From fba7b940194465ac7a8f0cdf793959fb5fbb8834 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Mon, 16 Jan 2006 11:48:01 +0000 Subject: [PATCH] Add fs_subsys to enable filesystems to use sysfs This creates an "fs" subdirectory in sysfs so that GFS2 (or any other filesystem, come to that) can make use of sysfs. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- include/linux/fs.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 552cedfa6064..eabc80d22bbc 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1293,6 +1293,9 @@ extern int vfs_statfs(struct super_block *, struct kstatfs *); #define FLOCK_VERIFY_READ 1 #define FLOCK_VERIFY_WRITE 2 +/* /sys/fs */ +extern struct subsystem fs_subsys; + extern int locks_mandatory_locked(struct inode *); extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t); -- cgit v1.2.3 From b3b94faa5fe5968827ba0640ee9fba4b3e7f736e Mon Sep 17 00:00:00 2001 From: David Teigland Date: Mon, 16 Jan 2006 16:50:04 +0000 Subject: [GFS2] The core of GFS2 This patch contains all the core files for GFS2. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/Kconfig | 46 + fs/gfs2/Makefile | 44 + fs/gfs2/acl.c | 312 ++++++ fs/gfs2/acl.h | 37 + fs/gfs2/bits.c | 178 +++ fs/gfs2/bits.h | 28 + fs/gfs2/bmap.c | 1206 +++++++++++++++++++++ fs/gfs2/bmap.h | 39 + fs/gfs2/daemon.c | 225 ++++ fs/gfs2/daemon.h | 20 + fs/gfs2/dir.c | 2157 +++++++++++++++++++++++++++++++++++++ fs/gfs2/dir.h | 51 + fs/gfs2/eaops.c | 185 ++++ fs/gfs2/eaops.h | 30 + fs/gfs2/eattr.c | 1620 ++++++++++++++++++++++++++++ fs/gfs2/eattr.h | 90 ++ fs/gfs2/format.h | 21 + fs/gfs2/gfs2.h | 62 ++ fs/gfs2/glock.c | 2513 +++++++++++++++++++++++++++++++++++++++++++ fs/gfs2/glock.h | 143 +++ fs/gfs2/glops.c | 487 +++++++++ fs/gfs2/glops.h | 23 + fs/gfs2/incore.h | 703 ++++++++++++ fs/gfs2/inode.c | 1805 +++++++++++++++++++++++++++++++ fs/gfs2/inode.h | 74 ++ fs/gfs2/jdata.c | 382 +++++++ fs/gfs2/jdata.h | 52 + fs/gfs2/lm.c | 235 ++++ fs/gfs2/lm.h | 42 + fs/gfs2/lm_interface.h | 295 +++++ fs/gfs2/locking.c | 192 ++++ fs/gfs2/log.c | 659 ++++++++++++ fs/gfs2/log.h | 68 ++ fs/gfs2/lops.c | 534 +++++++++ fs/gfs2/lops.h | 96 ++ fs/gfs2/lvb.c | 48 + fs/gfs2/lvb.h | 28 + fs/gfs2/main.c | 103 ++ fs/gfs2/meta_io.c | 876 +++++++++++++++ fs/gfs2/meta_io.h | 88 ++ fs/gfs2/mount.c | 211 ++++ fs/gfs2/mount.h | 15 + fs/gfs2/ondisk.c | 590 ++++++++++ fs/gfs2/ops_address.c | 515 +++++++++ fs/gfs2/ops_address.h | 15 + fs/gfs2/ops_dentry.c | 117 ++ fs/gfs2/ops_dentry.h | 15 + fs/gfs2/ops_export.c | 310 ++++++ fs/gfs2/ops_export.h | 15 + fs/gfs2/ops_file.c | 1597 +++++++++++++++++++++++++++ fs/gfs2/ops_file.h | 16 + fs/gfs2/ops_fstype.c | 879 +++++++++++++++ fs/gfs2/ops_fstype.h | 15 + fs/gfs2/ops_inode.c | 1265 ++++++++++++++++++++++ fs/gfs2/ops_inode.h | 18 + fs/gfs2/ops_super.c | 401 +++++++ fs/gfs2/ops_super.h | 15 + fs/gfs2/ops_vm.c | 199 ++++ fs/gfs2/ops_vm.h | 16 + fs/gfs2/page.c | 273 +++++ fs/gfs2/page.h | 23 + fs/gfs2/quota.c | 1238 +++++++++++++++++++++ fs/gfs2/quota.h | 34 + fs/gfs2/recovery.c | 570 ++++++++++ fs/gfs2/recovery.h | 32 + fs/gfs2/resize.c | 291 +++++ fs/gfs2/resize.h | 19 + fs/gfs2/rgrp.c | 1361 +++++++++++++++++++++++ fs/gfs2/rgrp.h | 62 ++ fs/gfs2/super.c | 944 ++++++++++++++++ fs/gfs2/super.h | 55 + fs/gfs2/sys.c | 640 +++++++++++ fs/gfs2/sys.h | 24 + fs/gfs2/trans.c | 214 ++++ fs/gfs2/trans.h | 40 + fs/gfs2/unlinked.c | 453 ++++++++ fs/gfs2/unlinked.h | 25 + fs/gfs2/util.c | 273 +++++ fs/gfs2/util.h | 180 ++++ include/linux/gfs2_ioctl.h | 32 + include/linux/gfs2_ondisk.h | 454 ++++++++ 81 files changed, 29258 insertions(+) create mode 100644 fs/gfs2/Kconfig create mode 100644 fs/gfs2/Makefile create mode 100644 fs/gfs2/acl.c create mode 100644 fs/gfs2/acl.h create mode 100644 fs/gfs2/bits.c create mode 100644 fs/gfs2/bits.h create mode 100644 fs/gfs2/bmap.c create mode 100644 fs/gfs2/bmap.h create mode 100644 fs/gfs2/daemon.c create mode 100644 fs/gfs2/daemon.h create mode 100644 fs/gfs2/dir.c create mode 100644 fs/gfs2/dir.h create mode 100644 fs/gfs2/eaops.c create mode 100644 fs/gfs2/eaops.h create mode 100644 fs/gfs2/eattr.c create mode 100644 fs/gfs2/eattr.h create mode 100644 fs/gfs2/format.h create mode 100644 fs/gfs2/gfs2.h create mode 100644 fs/gfs2/glock.c create mode 100644 fs/gfs2/glock.h create mode 100644 fs/gfs2/glops.c create mode 100644 fs/gfs2/glops.h create mode 100644 fs/gfs2/incore.h create mode 100644 fs/gfs2/inode.c create mode 100644 fs/gfs2/inode.h create mode 100644 fs/gfs2/jdata.c create mode 100644 fs/gfs2/jdata.h create mode 100644 fs/gfs2/lm.c create mode 100644 fs/gfs2/lm.h create mode 100644 fs/gfs2/lm_interface.h create mode 100644 fs/gfs2/locking.c create mode 100644 fs/gfs2/log.c create mode 100644 fs/gfs2/log.h create mode 100644 fs/gfs2/lops.c create mode 100644 fs/gfs2/lops.h create mode 100644 fs/gfs2/lvb.c create mode 100644 fs/gfs2/lvb.h create mode 100644 fs/gfs2/main.c create mode 100644 fs/gfs2/meta_io.c create mode 100644 fs/gfs2/meta_io.h create mode 100644 fs/gfs2/mount.c create mode 100644 fs/gfs2/mount.h create mode 100644 fs/gfs2/ondisk.c create mode 100644 fs/gfs2/ops_address.c create mode 100644 fs/gfs2/ops_address.h create mode 100644 fs/gfs2/ops_dentry.c create mode 100644 fs/gfs2/ops_dentry.h create mode 100644 fs/gfs2/ops_export.c create mode 100644 fs/gfs2/ops_export.h create mode 100644 fs/gfs2/ops_file.c create mode 100644 fs/gfs2/ops_file.h create mode 100644 fs/gfs2/ops_fstype.c create mode 100644 fs/gfs2/ops_fstype.h create mode 100644 fs/gfs2/ops_inode.c create mode 100644 fs/gfs2/ops_inode.h create mode 100644 fs/gfs2/ops_super.c create mode 100644 fs/gfs2/ops_super.h create mode 100644 fs/gfs2/ops_vm.c create mode 100644 fs/gfs2/ops_vm.h create mode 100644 fs/gfs2/page.c create mode 100644 fs/gfs2/page.h create mode 100644 fs/gfs2/quota.c create mode 100644 fs/gfs2/quota.h create mode 100644 fs/gfs2/recovery.c create mode 100644 fs/gfs2/recovery.h create mode 100644 fs/gfs2/resize.c create mode 100644 fs/gfs2/resize.h create mode 100644 fs/gfs2/rgrp.c create mode 100644 fs/gfs2/rgrp.h create mode 100644 fs/gfs2/super.c create mode 100644 fs/gfs2/super.h create mode 100644 fs/gfs2/sys.c create mode 100644 fs/gfs2/sys.h create mode 100644 fs/gfs2/trans.c create mode 100644 fs/gfs2/trans.h create mode 100644 fs/gfs2/unlinked.c create mode 100644 fs/gfs2/unlinked.h create mode 100644 fs/gfs2/util.c create mode 100644 fs/gfs2/util.h create mode 100644 include/linux/gfs2_ioctl.h create mode 100644 include/linux/gfs2_ondisk.h (limited to 'include/linux') diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig new file mode 100644 index 000000000000..17cb44bea1c0 --- /dev/null +++ b/fs/gfs2/Kconfig @@ -0,0 +1,46 @@ +config GFS2_FS + tristate "GFS2 file system support" + default m + depends on EXPERIMENTAL + select FS_POSIX_ACL + select SYSFS + help + A cluster filesystem. + + Allows a cluster of computers to simultaneously use a block device + that is shared between them (with FC, iSCSI, NBD, etc...). GFS reads + and writes to the block device like a local filesystem, but also uses + a lock module to allow the computers coordinate their I/O so + filesystem consistency is maintained. One of the nifty features of + GFS is perfect consistency -- changes made to the filesystem on one + machine show up immediately on all other machines in the cluster. + + To use the GFS2 filesystem, you will need to enable one or more of + the below locking modules. Documentation and utilities for GFS2 can + be found here: http://sources.redhat.com/cluster/gfs/ + +config GFS2_FS_LOCKING_NOLOCK + tristate "GFS2 \"nolock\" locking module" + depends on GFS2_FS + help + Single node locking module for GFS2. + + Use this module if you want to use GFS2 on a single node without + its clustering features. You can still take advantage of the + large file support, and upgrade to running a full cluster later on + if required. + + If you will only be using GFS2 in cluster mode, you do not need this + module. + +config GFS2_FS_LOCKING_DLM + tristate "GFS2 DLM locking module" + depends on GFS2_FS + select DLM + help + Multiple node locking module for GFS2 + + Most users of GFS2 will require this module. It provides the locking + interface between GFS2 and the DLM, which is required to use GFS2 + in a cluster environment. + diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile new file mode 100644 index 000000000000..b1bac4f199db --- /dev/null +++ b/fs/gfs2/Makefile @@ -0,0 +1,44 @@ +obj-$(CONFIG_GFS2_FS) += gfs2.o +gfs2-y := \ + acl.o \ + bits.o \ + bmap.o \ + daemon.o \ + dir.o \ + eaops.o \ + eattr.o \ + glock.o \ + glops.o \ + inode.o \ + jdata.o \ + lm.o \ + log.o \ + lops.o \ + locking.o \ + lvb.o \ + main.o \ + meta_io.o \ + mount.o \ + ondisk.o \ + ops_address.o \ + ops_dentry.o \ + ops_export.o \ + ops_file.o \ + ops_fstype.o \ + ops_inode.o \ + ops_super.o \ + ops_vm.o \ + page.o \ + quota.o \ + resize.o \ + recovery.o \ + rgrp.o \ + super.o \ + sys.o \ + trans.o \ + unlinked.o \ + util.o + +obj-$(CONFIG_GFS2_LOCKING_NOLOCK) += locking/nolock/ +obj-$(CONFIG_GFS2_LOCKING_DLM) += locking/dlm/ + diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c new file mode 100644 index 000000000000..33c465a2ab53 --- /dev/null +++ b/fs/gfs2/acl.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "acl.h" +#include "eaops.h" +#include "eattr.h" +#include "glock.h" +#include "inode.h" +#include "meta_io.h" +#include "trans.h" + +#define ACL_ACCESS 1 +#define ACL_DEFAULT 0 + +int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, + struct gfs2_ea_request *er, + int *remove, mode_t *mode) +{ + struct posix_acl *acl; + int error; + + error = gfs2_acl_validate_remove(ip, access); + if (error) + return error; + + if (!er->er_data) + return -EINVAL; + + acl = posix_acl_from_xattr(er->er_data, er->er_data_len); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (!acl) { + *remove = 1; + return 0; + } + + error = posix_acl_valid(acl); + if (error) + goto out; + + if (access) { + error = posix_acl_equiv_mode(acl, mode); + if (!error) + *remove = 1; + else if (error > 0) + error = 0; + } + + out: + posix_acl_release(acl); + + return error; +} + +int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) +{ + if (!ip->i_sbd->sd_args.ar_posix_acl) + return -EOPNOTSUPP; + if (current->fsuid != ip->i_di.di_uid && !capable(CAP_FOWNER)) + return -EPERM; + if (S_ISLNK(ip->i_di.di_mode)) + return -EOPNOTSUPP; + if (!access && !S_ISDIR(ip->i_di.di_mode)) + return -EACCES; + + return 0; +} + +static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, + struct gfs2_ea_location *el, char **data, unsigned int *len) +{ + struct gfs2_ea_request er; + struct gfs2_ea_location el_this; + int error; + + if (!ip->i_di.di_eattr) + return 0; + + memset(&er, 0, sizeof(struct gfs2_ea_request)); + if (access) { + er.er_name = GFS2_POSIX_ACL_ACCESS; + er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN; + } else { + er.er_name = GFS2_POSIX_ACL_DEFAULT; + er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; + } + er.er_type = GFS2_EATYPE_SYS; + + if (!el) + el = &el_this; + + error = gfs2_ea_find(ip, &er, el); + if (error) + return error; + if (!el->el_ea) + return 0; + if (!GFS2_EA_DATA_LEN(el->el_ea)) + goto out; + + er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea); + er.er_data = kmalloc(er.er_data_len, GFP_KERNEL); + error = -ENOMEM; + if (!er.er_data) + goto out; + + error = gfs2_ea_get_copy(ip, el, er.er_data); + if (error) + goto out_kfree; + + if (acl) { + *acl = posix_acl_from_xattr(er.er_data, er.er_data_len); + if (IS_ERR(*acl)) + error = PTR_ERR(*acl); + } + + out_kfree: + if (error || !data) + kfree(er.er_data); + else { + *data = er.er_data; + *len = er.er_data_len; + } + + out: + if (error || el == &el_this) + brelse(el->el_bh); + + return error; +} + +/** + * gfs2_check_acl_locked - Check an ACL to see if we're allowed to do something + * @inode: the file we want to do something to + * @mask: what we want to do + * + * Returns: errno + */ + +int gfs2_check_acl_locked(struct inode *inode, int mask) +{ + struct posix_acl *acl = NULL; + int error; + + error = acl_get(get_v2ip(inode), ACL_ACCESS, &acl, NULL, NULL, NULL); + if (error) + return error; + + if (acl) { + error = posix_acl_permission(inode, acl, mask); + posix_acl_release(acl); + return error; + } + + return -EAGAIN; +} + +int gfs2_check_acl(struct inode *inode, int mask) +{ + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_holder i_gh; + int error; + + error = gfs2_glock_nq_init(ip->i_gl, + LM_ST_SHARED, LM_FLAG_ANY, + &i_gh); + if (!error) { + error = gfs2_check_acl_locked(inode, mask); + gfs2_glock_dq_uninit(&i_gh); + } + + return error; +} + +static int munge_mode(struct gfs2_inode *ip, mode_t mode) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head *dibh; + int error; + + error = gfs2_trans_begin(sdp, RES_DINODE, 0); + if (error) + return error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + gfs2_assert_withdraw(sdp, + (ip->i_di.di_mode & S_IFMT) == (mode & S_IFMT)); + ip->i_di.di_mode = mode; + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs2_trans_end(sdp); + + return 0; +} + +int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct posix_acl *acl = NULL, *clone; + struct gfs2_ea_request er; + mode_t mode = ip->i_di.di_mode; + int error; + + if (!sdp->sd_args.ar_posix_acl) + return 0; + if (S_ISLNK(ip->i_di.di_mode)) + return 0; + + memset(&er, 0, sizeof(struct gfs2_ea_request)); + er.er_type = GFS2_EATYPE_SYS; + + error = acl_get(dip, ACL_DEFAULT, &acl, NULL, + &er.er_data, &er.er_data_len); + if (error) + return error; + if (!acl) { + mode &= ~current->fs->umask; + if (mode != ip->i_di.di_mode) + error = munge_mode(ip, mode); + return error; + } + + clone = posix_acl_clone(acl, GFP_KERNEL); + error = -ENOMEM; + if (!clone) + goto out; + posix_acl_release(acl); + acl = clone; + + if (S_ISDIR(ip->i_di.di_mode)) { + er.er_name = GFS2_POSIX_ACL_DEFAULT; + er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; + error = gfs2_system_eaops.eo_set(ip, &er); + if (error) + goto out; + } + + error = posix_acl_create_masq(acl, &mode); + if (error < 0) + goto out; + if (error > 0) { + er.er_name = GFS2_POSIX_ACL_ACCESS; + er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN; + posix_acl_to_xattr(acl, er.er_data, er.er_data_len); + er.er_mode = mode; + er.er_flags = GFS2_ERF_MODE; + error = gfs2_system_eaops.eo_set(ip, &er); + if (error) + goto out; + } else + munge_mode(ip, mode); + + out: + posix_acl_release(acl); + kfree(er.er_data); + return error; +} + +int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) +{ + struct posix_acl *acl = NULL, *clone; + struct gfs2_ea_location el; + char *data; + unsigned int len; + int error; + + error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len); + if (error) + return error; + if (!acl) + return gfs2_setattr_simple(ip, attr); + + clone = posix_acl_clone(acl, GFP_KERNEL); + error = -ENOMEM; + if (!clone) + goto out; + posix_acl_release(acl); + acl = clone; + + error = posix_acl_chmod_masq(acl, attr->ia_mode); + if (!error) { + posix_acl_to_xattr(acl, data, len); + error = gfs2_ea_acl_chmod(ip, &el, attr, data); + } + + out: + posix_acl_release(acl); + brelse(el.el_bh); + kfree(data); + + return error; +} + diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h new file mode 100644 index 000000000000..a174b4f6bcc2 --- /dev/null +++ b/fs/gfs2/acl.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __ACL_DOT_H__ +#define __ACL_DOT_H__ + +#define GFS2_POSIX_ACL_ACCESS "posix_acl_access" +#define GFS2_POSIX_ACL_ACCESS_LEN 16 +#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" +#define GFS2_POSIX_ACL_DEFAULT_LEN 17 + +#define GFS2_ACL_IS_ACCESS(name, len) \ + ((len) == GFS2_POSIX_ACL_ACCESS_LEN && \ + !memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len))) + +#define GFS2_ACL_IS_DEFAULT(name, len) \ + ((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \ + !memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len))) + +struct gfs2_ea_request; + +int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, + struct gfs2_ea_request *er, + int *remove, mode_t *mode); +int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access); +int gfs2_check_acl_locked(struct inode *inode, int mask); +int gfs2_check_acl(struct inode *inode, int mask); +int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip); +int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); + +#endif /* __ACL_DOT_H__ */ diff --git a/fs/gfs2/bits.c b/fs/gfs2/bits.c new file mode 100644 index 000000000000..57d420a86adf --- /dev/null +++ b/fs/gfs2/bits.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +/* + * These routines are used by the resource group routines (rgrp.c) + * to keep track of block allocation. Each block is represented by two + * bits. One bit indicates whether or not the block is used. (1=used, + * 0=free) The other bit indicates whether or not the block contains a + * dinode or not. (1=dinode, 0=not-dinode) So, each byte represents + * GFS2_NBBY (i.e. 4) blocks. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bits.h" + +static const char valid_change[16] = { + /* current */ + /* n */ 0, 1, 0, 1, + /* e */ 1, 0, 0, 0, + /* w */ 0, 0, 0, 0, + 1, 0, 0, 0 +}; + +/** + * gfs2_setbit - Set a bit in the bitmaps + * @buffer: the buffer that holds the bitmaps + * @buflen: the length (in bytes) of the buffer + * @block: the block to set + * @new_state: the new state of the block + * + */ + +void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, + unsigned int buflen, uint32_t block, unsigned char new_state) +{ + unsigned char *byte, *end, cur_state; + unsigned int bit; + + byte = buffer + (block / GFS2_NBBY); + bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE; + end = buffer + buflen; + + gfs2_assert(rgd->rd_sbd, byte < end); + + cur_state = (*byte >> bit) & GFS2_BIT_MASK; + + if (valid_change[new_state * 4 + cur_state]) { + *byte ^= cur_state << bit; + *byte |= new_state << bit; + } else + gfs2_consist_rgrpd(rgd); +} + +/** + * gfs2_testbit - test a bit in the bitmaps + * @buffer: the buffer that holds the bitmaps + * @buflen: the length (in bytes) of the buffer + * @block: the block to read + * + */ + +unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, + unsigned int buflen, uint32_t block) +{ + unsigned char *byte, *end, cur_state; + unsigned int bit; + + byte = buffer + (block / GFS2_NBBY); + bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE; + end = buffer + buflen; + + gfs2_assert(rgd->rd_sbd, byte < end); + + cur_state = (*byte >> bit) & GFS2_BIT_MASK; + + return cur_state; +} + +/** + * gfs2_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing + * a block in a given allocation state. + * @buffer: the buffer that holds the bitmaps + * @buflen: the length (in bytes) of the buffer + * @goal: start search at this block's bit-pair (within @buffer) + * @old_state: GFS2_BLKST_XXX the state of the block we're looking for; + * bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0) + * + * Scope of @goal and returned block number is only within this bitmap buffer, + * not entire rgrp or filesystem. @buffer will be offset from the actual + * beginning of a bitmap block buffer, skipping any header structures. + * + * Return: the block number (bitmap buffer scope) that was found + */ + +uint32_t gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, + unsigned int buflen, uint32_t goal, + unsigned char old_state) +{ + unsigned char *byte, *end, alloc; + uint32_t blk = goal; + unsigned int bit; + + byte = buffer + (goal / GFS2_NBBY); + bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; + end = buffer + buflen; + alloc = (old_state & 1) ? 0 : 0x55; + + while (byte < end) { + if ((*byte & 0x55) == alloc) { + blk += (8 - bit) >> 1; + + bit = 0; + byte++; + + continue; + } + + if (((*byte >> bit) & GFS2_BIT_MASK) == old_state) + return blk; + + bit += GFS2_BIT_SIZE; + if (bit >= 8) { + bit = 0; + byte++; + } + + blk++; + } + + return BFITNOENT; +} + +/** + * gfs2_bitcount - count the number of bits in a certain state + * @buffer: the buffer that holds the bitmaps + * @buflen: the length (in bytes) of the buffer + * @state: the state of the block we're looking for + * + * Returns: The number of bits + */ + +uint32_t gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer, + unsigned int buflen, unsigned char state) +{ + unsigned char *byte = buffer; + unsigned char *end = buffer + buflen; + unsigned char state1 = state << 2; + unsigned char state2 = state << 4; + unsigned char state3 = state << 6; + uint32_t count = 0; + + for (; byte < end; byte++) { + if (((*byte) & 0x03) == state) + count++; + if (((*byte) & 0x0C) == state1) + count++; + if (((*byte) & 0x30) == state2) + count++; + if (((*byte) & 0xC0) == state3) + count++; + } + + return count; +} + diff --git a/fs/gfs2/bits.h b/fs/gfs2/bits.h new file mode 100644 index 000000000000..36ccbdcb1eef --- /dev/null +++ b/fs/gfs2/bits.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __BITS_DOT_H__ +#define __BITS_DOT_H__ + +#define BFITNOENT 0xFFFFFFFF + +void gfs2_setbit(struct gfs2_rgrpd *rgd, + unsigned char *buffer, unsigned int buflen, + uint32_t block, unsigned char new_state); +unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, + unsigned char *buffer, unsigned int buflen, + uint32_t block); +uint32_t gfs2_bitfit(struct gfs2_rgrpd *rgd, + unsigned char *buffer, unsigned int buflen, + uint32_t goal, unsigned char old_state); +uint32_t gfs2_bitcount(struct gfs2_rgrpd *rgd, + unsigned char *buffer, unsigned int buflen, + unsigned char state); + +#endif /* __BITS_DOT_H__ */ diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c new file mode 100644 index 000000000000..4b4e295b3bf5 --- /dev/null +++ b/fs/gfs2/bmap.c @@ -0,0 +1,1206 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "glock.h" +#include "inode.h" +#include "jdata.h" +#include "meta_io.h" +#include "page.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" + +/* This doesn't need to be that large as max 64 bit pointers in a 4k + * block is 512, so __u16 is fine for that. It saves stack space to + * keep it small. + */ +struct metapath { + __u16 mp_list[GFS2_MAX_META_HEIGHT]; +}; + +typedef int (*block_call_t) (struct gfs2_inode *ip, struct buffer_head *dibh, + struct buffer_head *bh, uint64_t *top, + uint64_t *bottom, unsigned int height, + void *data); + +struct strip_mine { + int sm_first; + unsigned int sm_height; +}; + +/** + * @gfs2_unstuffer_sync - Synchronously unstuff a dinode + * @ip: + * @dibh: + * @block: + * @private: + * + * Cheat and use a metadata buffer instead of a data page. + * + * Returns: errno + */ + +int gfs2_unstuffer_sync(struct gfs2_inode *ip, struct buffer_head *dibh, + uint64_t block, void *private) +{ + struct buffer_head *bh; + int error; + + bh = gfs2_meta_new(ip->i_gl, block); + + gfs2_buffer_copy_tail(bh, 0, dibh, sizeof(struct gfs2_dinode)); + + set_buffer_dirty(bh); + error = sync_dirty_buffer(bh); + + brelse(bh); + + return error; +} + +/** + * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big + * @ip: The GFS2 inode to unstuff + * @unstuffer: the routine that handles unstuffing a non-zero length file + * @private: private data for the unstuffer + * + * This routine unstuffs a dinode and returns it to a "normal" state such + * that the height can be grown in the traditional way. + * + * Returns: errno + */ + +int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, + void *private) +{ + struct buffer_head *bh, *dibh; + uint64_t block = 0; + int journaled = gfs2_is_jdata(ip); + int error; + + down_write(&ip->i_rw_mutex); + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out; + + if (ip->i_di.di_size) { + /* Get a free block, fill it with the stuffed data, + and write it out to disk */ + + if (journaled) { + block = gfs2_alloc_meta(ip); + + error = gfs2_jdata_get_buffer(ip, block, 1, &bh); + if (error) + goto out_brelse; + gfs2_buffer_copy_tail(bh, + sizeof(struct gfs2_meta_header), + dibh, sizeof(struct gfs2_dinode)); + brelse(bh); + } else { + block = gfs2_alloc_data(ip); + + error = unstuffer(ip, dibh, block, private); + if (error) + goto out_brelse; + } + } + + /* Set up the pointer to the new block */ + + gfs2_trans_add_bh(ip->i_gl, dibh); + + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); + + if (ip->i_di.di_size) { + *(uint64_t *)(dibh->b_data + sizeof(struct gfs2_dinode)) = cpu_to_be64(block); + ip->i_di.di_blocks++; + } + + ip->i_di.di_height = 1; + + gfs2_dinode_out(&ip->i_di, dibh->b_data); + + out_brelse: + brelse(dibh); + + out: + up_write(&ip->i_rw_mutex); + + return error; +} + +/** + * calc_tree_height - Calculate the height of a metadata tree + * @ip: The GFS2 inode + * @size: The proposed size of the file + * + * Work out how tall a metadata tree needs to be in order to accommodate a + * file of a particular size. If size is less than the current size of + * the inode, then the current size of the inode is used instead of the + * supplied one. + * + * Returns: the height the tree should be + */ + +static unsigned int calc_tree_height(struct gfs2_inode *ip, uint64_t size) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + uint64_t *arr; + unsigned int max, height; + + if (ip->i_di.di_size > size) + size = ip->i_di.di_size; + + if (gfs2_is_jdata(ip)) { + arr = sdp->sd_jheightsize; + max = sdp->sd_max_jheight; + } else { + arr = sdp->sd_heightsize; + max = sdp->sd_max_height; + } + + for (height = 0; height < max; height++) + if (arr[height] >= size) + break; + + return height; +} + +/** + * build_height - Build a metadata tree of the requested height + * @ip: The GFS2 inode + * @height: The height to build to + * + * This routine makes sure that the metadata tree is tall enough to hold + * "size" bytes of data. + * + * Returns: errno + */ + +static int build_height(struct gfs2_inode *ip, int height) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head *bh, *dibh; + uint64_t block = 0, *bp; + unsigned int x; + int new_block; + int error; + + while (ip->i_di.di_height < height) { + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; + + new_block = 0; + bp = (uint64_t *)(dibh->b_data + sizeof(struct gfs2_dinode)); + for (x = 0; x < sdp->sd_diptrs; x++, bp++) + if (*bp) { + new_block = 1; + break; + } + + if (new_block) { + /* Get a new block, fill it with the old direct + pointers, and write it out */ + + block = gfs2_alloc_meta(ip); + + bh = gfs2_meta_new(ip->i_gl, block); + gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_metatype_set(bh, + GFS2_METATYPE_IN, + GFS2_FORMAT_IN); + gfs2_buffer_copy_tail(bh, + sizeof(struct gfs2_meta_header), + dibh, sizeof(struct gfs2_dinode)); + + brelse(bh); + } + + /* Set up the new direct pointer and write it out to disk */ + + gfs2_trans_add_bh(ip->i_gl, dibh); + + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); + + if (new_block) { + *(uint64_t *)(dibh->b_data + sizeof(struct gfs2_dinode)) = cpu_to_be64(block); + ip->i_di.di_blocks++; + } + + ip->i_di.di_height++; + + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + return 0; +} + +/** + * find_metapath - Find path through the metadata tree + * @ip: The inode pointer + * @mp: The metapath to return the result in + * @block: The disk block to look up + * + * This routine returns a struct metapath structure that defines a path + * through the metadata of inode "ip" to get to block "block". + * + * Example: + * Given: "ip" is a height 3 file, "offset" is 101342453, and this is a + * filesystem with a blocksize of 4096. + * + * find_metapath() would return a struct metapath structure set to: + * mp_offset = 101342453, mp_height = 3, mp_list[0] = 0, mp_list[1] = 48, + * and mp_list[2] = 165. + * + * That means that in order to get to the block containing the byte at + * offset 101342453, we would load the indirect block pointed to by pointer + * 0 in the dinode. We would then load the indirect block pointed to by + * pointer 48 in that indirect block. We would then load the data block + * pointed to by pointer 165 in that indirect block. + * + * ---------------------------------------- + * | Dinode | | + * | | 4| + * | |0 1 2 3 4 5 9| + * | | 6| + * ---------------------------------------- + * | + * | + * V + * ---------------------------------------- + * | Indirect Block | + * | 5| + * | 4 4 4 4 4 5 5 1| + * |0 5 6 7 8 9 0 1 2| + * ---------------------------------------- + * | + * | + * V + * ---------------------------------------- + * | Indirect Block | + * | 1 1 1 1 1 5| + * | 6 6 6 6 6 1| + * |0 3 4 5 6 7 2| + * ---------------------------------------- + * | + * | + * V + * ---------------------------------------- + * | Data block containing offset | + * | 101342453 | + * | | + * | | + * ---------------------------------------- + * + */ + +static void find_metapath(struct gfs2_inode *ip, uint64_t block, struct metapath *mp) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + uint64_t b = block; + unsigned int i; + + for (i = ip->i_di.di_height; i--;) + mp->mp_list[i] = (__u16)do_div(b, sdp->sd_inptrs); + +} + +/** + * metapointer - Return pointer to start of metadata in a buffer + * @bh: The buffer + * @height: The metadata height (0 = dinode) + * @mp: The metapath + * + * Return a pointer to the block number of the next height of the metadata + * tree given a buffer containing the pointer to the current height of the + * metadata tree. + */ + +static inline uint64_t *metapointer(struct buffer_head *bh, + unsigned int height, struct metapath *mp) +{ + unsigned int head_size = (height > 0) ? + sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); + + return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height]; +} + +/** + * lookup_block - Get the next metadata block in metadata tree + * @ip: The GFS2 inode + * @bh: Buffer containing the pointers to metadata blocks + * @height: The height of the tree (0 = dinode) + * @mp: The metapath + * @create: Non-zero if we may create a new meatdata block + * @new: Used to indicate if we did create a new metadata block + * @block: the returned disk block number + * + * Given a metatree, complete to a particular height, checks to see if the next + * height of the tree exists. If not the next height of the tree is created. + * The block number of the next height of the metadata tree is returned. + * + */ + +static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, + unsigned int height, struct metapath *mp, int create, + int *new, uint64_t *block) +{ + uint64_t *ptr = metapointer(bh, height, mp); + + if (*ptr) { + *block = be64_to_cpu(*ptr); + return; + } + + *block = 0; + + if (!create) + return; + + if (height == ip->i_di.di_height - 1 && + !gfs2_is_jdata(ip)) + *block = gfs2_alloc_data(ip); + else + *block = gfs2_alloc_meta(ip); + + gfs2_trans_add_bh(ip->i_gl, bh); + + *ptr = cpu_to_be64(*block); + ip->i_di.di_blocks++; + + *new = 1; +} + +/** + * gfs2_block_map - Map a block from an inode to a disk block + * @ip: The GFS2 inode + * @lblock: The logical block number + * @new: Value/Result argument (1 = may create/did create new blocks) + * @dblock: the disk block number of the start of an extent + * @extlen: the size of the extent + * + * Find the block number on the current device which corresponds to an + * inode's block. If the block had to be created, "new" will be set. + * + * Returns: errno + */ + +int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, + uint64_t *dblock, uint32_t *extlen) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head *bh; + struct metapath mp; + int create = *new; + unsigned int bsize; + unsigned int height; + unsigned int end_of_metadata; + unsigned int x; + int error = 0; + + *new = 0; + *dblock = 0; + if (extlen) + *extlen = 0; + + if (create) + down_write(&ip->i_rw_mutex); + else + down_read(&ip->i_rw_mutex); + + if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) + goto out; + + bsize = (gfs2_is_jdata(ip)) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; + + height = calc_tree_height(ip, (lblock + 1) * bsize); + if (ip->i_di.di_height < height) { + if (!create) + goto out; + + error = build_height(ip, height); + if (error) + goto out; + } + + find_metapath(ip, lblock, &mp); + end_of_metadata = ip->i_di.di_height - 1; + + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + goto out; + + for (x = 0; x < end_of_metadata; x++) { + lookup_block(ip, bh, x, &mp, create, new, dblock); + brelse(bh); + if (!*dblock) + goto out; + + error = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, &bh); + if (error) + goto out; + } + + lookup_block(ip, bh, end_of_metadata, &mp, create, new, dblock); + + if (extlen && *dblock) { + *extlen = 1; + + if (!*new) { + uint64_t tmp_dblock; + int tmp_new; + unsigned int nptrs; + + nptrs = (end_of_metadata) ? sdp->sd_inptrs : + sdp->sd_diptrs; + + while (++mp.mp_list[end_of_metadata] < nptrs) { + lookup_block(ip, bh, end_of_metadata, &mp, + 0, &tmp_new, &tmp_dblock); + + if (*dblock + *extlen != tmp_dblock) + break; + + (*extlen)++; + } + } + } + + brelse(bh); + + if (*new) { + error = gfs2_meta_inode_buffer(ip, &bh); + if (!error) { + gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_dinode_out(&ip->i_di, bh->b_data); + brelse(bh); + } + } + + out: + if (create) + up_write(&ip->i_rw_mutex); + else + up_read(&ip->i_rw_mutex); + + return error; +} + +/** + * recursive_scan - recursively scan through the end of a file + * @ip: the inode + * @dibh: the dinode buffer + * @mp: the path through the metadata to the point to start + * @height: the height the recursion is at + * @block: the indirect block to look at + * @first: 1 if this is the first block + * @bc: the call to make for each piece of metadata + * @data: data opaque to this function to pass to @bc + * + * When this is first called @height and @block should be zero and + * @first should be 1. + * + * Returns: errno + */ + +static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, + struct metapath *mp, unsigned int height, + uint64_t block, int first, block_call_t bc, + void *data) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head *bh = NULL; + uint64_t *top, *bottom; + uint64_t bn; + int error; + int mh_size = sizeof(struct gfs2_meta_header); + + if (!height) { + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + return error; + dibh = bh; + + top = (uint64_t *)(bh->b_data + sizeof(struct gfs2_dinode)) + + mp->mp_list[0]; + bottom = (uint64_t *)(bh->b_data + sizeof(struct gfs2_dinode)) + + sdp->sd_diptrs; + } else { + error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh); + if (error) + return error; + + top = (uint64_t *)(bh->b_data + mh_size) + + ((first) ? mp->mp_list[height] : 0); + + bottom = (uint64_t *)(bh->b_data + mh_size) + sdp->sd_inptrs; + } + + error = bc(ip, dibh, bh, top, bottom, height, data); + if (error) + goto out; + + if (height < ip->i_di.di_height - 1) + for (; top < bottom; top++, first = 0) { + if (!*top) + continue; + + bn = be64_to_cpu(*top); + + error = recursive_scan(ip, dibh, mp, height + 1, bn, + first, bc, data); + if (error) + break; + } + + out: + brelse(bh); + + return error; +} + +/** + * do_strip - Look for a layer a particular layer of the file and strip it off + * @ip: the inode + * @dibh: the dinode buffer + * @bh: A buffer of pointers + * @top: The first pointer in the buffer + * @bottom: One more than the last pointer + * @height: the height this buffer is at + * @data: a pointer to a struct strip_mine + * + * Returns: errno + */ + +static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, + struct buffer_head *bh, uint64_t *top, uint64_t *bottom, + unsigned int height, void *data) +{ + struct strip_mine *sm = (struct strip_mine *)data; + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_rgrp_list rlist; + uint64_t bn, bstart; + uint32_t blen; + uint64_t *p; + unsigned int rg_blocks = 0; + int metadata; + unsigned int revokes = 0; + int x; + int error; + + if (!*top) + sm->sm_first = 0; + + if (height != sm->sm_height) + return 0; + + if (sm->sm_first) { + top++; + sm->sm_first = 0; + } + + metadata = (height != ip->i_di.di_height - 1) || gfs2_is_jdata(ip); + if (metadata) + revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; + + error = gfs2_rindex_hold(sdp, &ip->i_alloc.al_ri_gh); + if (error) + return error; + + memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); + bstart = 0; + blen = 0; + + for (p = top; p < bottom; p++) { + if (!*p) + continue; + + bn = be64_to_cpu(*p); + + if (bstart + blen == bn) + blen++; + else { + if (bstart) + gfs2_rlist_add(sdp, &rlist, bstart); + + bstart = bn; + blen = 1; + } + } + + if (bstart) + gfs2_rlist_add(sdp, &rlist, bstart); + else + goto out; /* Nothing to do */ + + gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); + + for (x = 0; x < rlist.rl_rgrps; x++) { + struct gfs2_rgrpd *rgd; + rgd = get_gl2rgd(rlist.rl_ghs[x].gh_gl); + rg_blocks += rgd->rd_ri.ri_length; + } + + error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs); + if (error) + goto out_rlist; + + error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + + RES_INDIRECT + RES_STATFS + RES_QUOTA, + revokes); + if (error) + goto out_rg_gunlock; + + down_write(&ip->i_rw_mutex); + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_trans_add_bh(ip->i_gl, bh); + + bstart = 0; + blen = 0; + + for (p = top; p < bottom; p++) { + if (!*p) + continue; + + bn = be64_to_cpu(*p); + + if (bstart + blen == bn) + blen++; + else { + if (bstart) { + if (metadata) + gfs2_free_meta(ip, bstart, blen); + else + gfs2_free_data(ip, bstart, blen); + } + + bstart = bn; + blen = 1; + } + + *p = 0; + if (!ip->i_di.di_blocks) + gfs2_consist_inode(ip); + ip->i_di.di_blocks--; + } + if (bstart) { + if (metadata) + gfs2_free_meta(ip, bstart, blen); + else + gfs2_free_data(ip, bstart, blen); + } + + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + gfs2_dinode_out(&ip->i_di, dibh->b_data); + + up_write(&ip->i_rw_mutex); + + gfs2_trans_end(sdp); + + out_rg_gunlock: + gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); + + out_rlist: + gfs2_rlist_free(&rlist); + + out: + gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh); + + return error; +} + +/** + * do_grow - Make a file look bigger than it is + * @ip: the inode + * @size: the size to set the file to + * + * Called with an exclusive lock on @ip. + * + * Returns: errno + */ + +static int do_grow(struct gfs2_inode *ip, uint64_t size) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al; + struct buffer_head *dibh; + unsigned int h; + int error; + + al = gfs2_alloc_get(ip); + + error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto out_gunlock_q; + + al->al_requested = sdp->sd_max_height + RES_DATA; + + error = gfs2_inplace_reserve(ip); + if (error) + goto out_gunlock_q; + + error = gfs2_trans_begin(sdp, + sdp->sd_max_height + al->al_rgd->rd_ri.ri_length + + RES_JDATA + RES_DINODE + RES_STATFS + RES_QUOTA, 0); + if (error) + goto out_ipres; + + if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { + if (gfs2_is_stuffed(ip)) { + error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, + NULL); + if (error) + goto out_end_trans; + } + + h = calc_tree_height(ip, size); + if (ip->i_di.di_height < h) { + down_write(&ip->i_rw_mutex); + error = build_height(ip, h); + up_write(&ip->i_rw_mutex); + if (error) + goto out_end_trans; + } + } + + ip->i_di.di_size = size; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out_end_trans; + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + out_end_trans: + gfs2_trans_end(sdp); + + out_ipres: + gfs2_inplace_release(ip); + + out_gunlock_q: + gfs2_quota_unlock(ip); + + out: + gfs2_alloc_put(ip); + + return error; +} + +static int truncator_journaled(struct gfs2_inode *ip, uint64_t size) +{ + uint64_t lbn, dbn; + uint32_t off; + struct buffer_head *bh; + int new = 0; + int error; + + lbn = size; + off = do_div(lbn, ip->i_sbd->sd_jbsize); + + error = gfs2_block_map(ip, lbn, &new, &dbn, NULL); + if (error || !dbn) + return error; + + error = gfs2_jdata_get_buffer(ip, dbn, 0, &bh); + if (error) + return error; + + gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header) + off); + + brelse(bh); + + return 0; +} + +static int trunc_start(struct gfs2_inode *ip, uint64_t size, + gfs2_truncator_t truncator) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head *dibh; + int journaled = gfs2_is_jdata(ip); + int error; + + error = gfs2_trans_begin(sdp, + RES_DINODE + ((journaled) ? RES_JDATA : 0), 0); + if (error) + return error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out; + + if (gfs2_is_stuffed(ip)) { + ip->i_di.di_size = size; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size); + error = 1; + + } else { + if (journaled) { + uint64_t junk = size; + /* we're just interested in the modulus */ + if (do_div(junk, sdp->sd_jbsize)) + error = truncator_journaled(ip, size); + } else if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1)) + error = truncator(ip, size); + + if (!error) { + ip->i_di.di_size = size; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG; + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + } + } + + brelse(dibh); + + out: + gfs2_trans_end(sdp); + + return error; +} + +static int trunc_dealloc(struct gfs2_inode *ip, uint64_t size) +{ + unsigned int height = ip->i_di.di_height; + uint64_t lblock; + struct metapath mp; + int error; + + if (!size) + lblock = 0; + else if (gfs2_is_jdata(ip)) { + lblock = size - 1; + do_div(lblock, ip->i_sbd->sd_jbsize); + } else + lblock = (size - 1) >> ip->i_sbd->sd_sb.sb_bsize_shift; + + find_metapath(ip, lblock, &mp); + gfs2_alloc_get(ip); + + error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + while (height--) { + struct strip_mine sm; + sm.sm_first = !!size; + sm.sm_height = height; + + error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm); + if (error) + break; + } + + gfs2_quota_unhold(ip); + + out: + gfs2_alloc_put(ip); + return error; +} + +static int trunc_end(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head *dibh; + int error; + + error = gfs2_trans_begin(sdp, RES_DINODE, 0); + if (error) + return error; + + down_write(&ip->i_rw_mutex); + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out; + + if (!ip->i_di.di_size) { + ip->i_di.di_height = 0; + ip->i_di.di_goal_meta = + ip->i_di.di_goal_data = + ip->i_num.no_addr; + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); + } + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG; + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + out: + up_write(&ip->i_rw_mutex); + + gfs2_trans_end(sdp); + + return error; +} + +/** + * do_shrink - make a file smaller + * @ip: the inode + * @size: the size to make the file + * @truncator: function to truncate the last partial block + * + * Called with an exclusive lock on @ip. + * + * Returns: errno + */ + +static int do_shrink(struct gfs2_inode *ip, uint64_t size, + gfs2_truncator_t truncator) +{ + int error; + + error = trunc_start(ip, size, truncator); + if (error < 0) + return error; + if (error > 0) + return 0; + + error = trunc_dealloc(ip, size); + if (!error) + error = trunc_end(ip); + + return error; +} + +/** + * gfs2_truncatei - make a file a give size + * @ip: the inode + * @size: the size to make the file + * @truncator: function to truncate the last partial block + * + * The file size can grow, shrink, or stay the same size. + * + * Returns: errno + */ + +int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size, + gfs2_truncator_t truncator) +{ + int error; + + if (gfs2_assert_warn(ip->i_sbd, S_ISREG(ip->i_di.di_mode))) + return -EINVAL; + + if (size > ip->i_di.di_size) + error = do_grow(ip, size); + else + error = do_shrink(ip, size, truncator); + + return error; +} + +int gfs2_truncatei_resume(struct gfs2_inode *ip) +{ + int error; + error = trunc_dealloc(ip, ip->i_di.di_size); + if (!error) + error = trunc_end(ip); + return error; +} + +int gfs2_file_dealloc(struct gfs2_inode *ip) +{ + return trunc_dealloc(ip, 0); +} + +/** + * gfs2_write_calc_reserv - calculate number of blocks needed to write to a file + * @ip: the file + * @len: the number of bytes to be written to the file + * @data_blocks: returns the number of data blocks required + * @ind_blocks: returns the number of indirect blocks required + * + */ + +void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len, + unsigned int *data_blocks, unsigned int *ind_blocks) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + unsigned int tmp; + + if (gfs2_is_jdata(ip)) { + *data_blocks = DIV_RU(len, sdp->sd_jbsize) + 2; + *ind_blocks = 3 * (sdp->sd_max_jheight - 1); + } else { + *data_blocks = (len >> sdp->sd_sb.sb_bsize_shift) + 3; + *ind_blocks = 3 * (sdp->sd_max_height - 1); + } + + for (tmp = *data_blocks; tmp > sdp->sd_diptrs;) { + tmp = DIV_RU(tmp, sdp->sd_inptrs); + *ind_blocks += tmp; + } +} + +/** + * gfs2_write_alloc_required - figure out if a write will require an allocation + * @ip: the file being written to + * @offset: the offset to write to + * @len: the number of bytes being written + * @alloc_required: set to 1 if an alloc is required, 0 otherwise + * + * Returns: errno + */ + +int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset, + unsigned int len, int *alloc_required) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + uint64_t lblock, lblock_stop, dblock; + uint32_t extlen; + int new = 0; + int error = 0; + + *alloc_required = 0; + + if (!len) + return 0; + + if (gfs2_is_stuffed(ip)) { + if (offset + len > + sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) + *alloc_required = 1; + return 0; + } + + if (gfs2_is_jdata(ip)) { + unsigned int bsize = sdp->sd_jbsize; + lblock = offset; + do_div(lblock, bsize); + lblock_stop = offset + len + bsize - 1; + do_div(lblock_stop, bsize); + } else { + unsigned int shift = sdp->sd_sb.sb_bsize_shift; + lblock = offset >> shift; + lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift; + } + + for (; lblock < lblock_stop; lblock += extlen) { + error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); + if (error) + return error; + + if (!dblock) { + *alloc_required = 1; + return 0; + } + } + + return 0; +} + +/** + * do_gfm - Copy out the dinode/indirect blocks of a file + * @ip: the file + * @dibh: the dinode buffer + * @bh: the indirect buffer we're looking at + * @top: the first pointer in the block + * @bottom: one more than the last pointer in the block + * @height: the height the block is at + * @data: a pointer to a struct gfs2_user_buffer structure + * + * If this is a journaled file, copy out the data too. + * + * Returns: errno + */ + +static int do_gfm(struct gfs2_inode *ip, struct buffer_head *dibh, + struct buffer_head *bh, uint64_t *top, uint64_t *bottom, + unsigned int height, void *data) +{ + struct gfs2_user_buffer *ub = (struct gfs2_user_buffer *)data; + int error; + + error = gfs2_add_bh_to_ub(ub, bh); + if (error) + return error; + + if (!S_ISDIR(ip->i_di.di_mode) || + height + 1 != ip->i_di.di_height) + return 0; + + for (; top < bottom; top++) + if (*top) { + struct buffer_head *data_bh; + + error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*top), + DIO_START | DIO_WAIT, + &data_bh); + if (error) + return error; + + error = gfs2_add_bh_to_ub(ub, data_bh); + + brelse(data_bh); + + if (error) + return error; + } + + return 0; +} + +/** + * gfs2_get_file_meta - return all the metadata for a file + * @ip: the file + * @ub: the structure representing the meta + * + * Returns: errno + */ + +int gfs2_get_file_meta(struct gfs2_inode *ip, struct gfs2_user_buffer *ub) +{ + int error; + + if (gfs2_is_stuffed(ip)) { + struct buffer_head *dibh; + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + error = gfs2_add_bh_to_ub(ub, dibh); + brelse(dibh); + } + } else { + struct metapath mp; + find_metapath(ip, 0, &mp); + error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_gfm, ub); + } + + return error; +} + diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h new file mode 100644 index 000000000000..de16e44f049f --- /dev/null +++ b/fs/gfs2/bmap.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __BMAP_DOT_H__ +#define __BMAP_DOT_H__ + +typedef int (*gfs2_unstuffer_t) (struct gfs2_inode * ip, + struct buffer_head * dibh, uint64_t block, + void *private); +int gfs2_unstuffer_sync(struct gfs2_inode *ip, struct buffer_head *dibh, + uint64_t block, void *private); +int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, + void *private); + +int gfs2_block_map(struct gfs2_inode *ip, + uint64_t lblock, int *new, + uint64_t *dblock, uint32_t *extlen); + +typedef int (*gfs2_truncator_t) (struct gfs2_inode * ip, uint64_t size); +int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size, + gfs2_truncator_t truncator); +int gfs2_truncatei_resume(struct gfs2_inode *ip); +int gfs2_file_dealloc(struct gfs2_inode *ip); + +void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len, + unsigned int *data_blocks, + unsigned int *ind_blocks); +int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset, + unsigned int len, int *alloc_required); + +int gfs2_get_file_meta(struct gfs2_inode *ip, struct gfs2_user_buffer *ub); + +#endif /* __BMAP_DOT_H__ */ diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c new file mode 100644 index 000000000000..cff8d5368d21 --- /dev/null +++ b/fs/gfs2/daemon.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "daemon.h" +#include "glock.h" +#include "log.h" +#include "quota.h" +#include "recovery.h" +#include "super.h" +#include "unlinked.h" + +/* This uses schedule_timeout() instead of msleep() because it's good for + the daemons to wake up more often than the timeout when unmounting so + the user's unmount doesn't sit there forever. + + The kthread functions used to start these daemons block and flush signals. */ + +/** + * gfs2_scand - Look for cached glocks and inodes to toss from memory + * @sdp: Pointer to GFS2 superblock + * + * One of these daemons runs, finding candidates to add to sd_reclaim_list. + * See gfs2_glockd() + */ + +int gfs2_scand(void *data) +{ + struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + unsigned long t; + + while (!kthread_should_stop()) { + gfs2_scand_internal(sdp); + t = gfs2_tune_get(sdp, gt_scand_secs) * HZ; + schedule_timeout_interruptible(t); + } + + return 0; +} + +/** + * gfs2_glockd - Reclaim unused glock structures + * @sdp: Pointer to GFS2 superblock + * + * One or more of these daemons run, reclaiming glocks on sd_reclaim_list. + * Number of daemons can be set by user, with num_glockd mount option. + */ + +int gfs2_glockd(void *data) +{ + struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + DECLARE_WAITQUEUE(wait_chan, current); + + while (!kthread_should_stop()) { + while (atomic_read(&sdp->sd_reclaim_count)) + gfs2_reclaim_glock(sdp); + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&sdp->sd_reclaim_wq, &wait_chan); + if (!atomic_read(&sdp->sd_reclaim_count) && + !kthread_should_stop()) + schedule(); + remove_wait_queue(&sdp->sd_reclaim_wq, &wait_chan); + set_current_state(TASK_RUNNING); + } + + return 0; +} + +/** + * gfs2_recoverd - Recover dead machine's journals + * @sdp: Pointer to GFS2 superblock + * + */ + +int gfs2_recoverd(void *data) +{ + struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + unsigned long t; + + while (!kthread_should_stop()) { + gfs2_check_journals(sdp); + t = gfs2_tune_get(sdp, gt_recoverd_secs) * HZ; + schedule_timeout_interruptible(t); + } + + return 0; +} + +/** + * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks + * @sdp: Pointer to GFS2 superblock + * + * Also, periodically check to make sure that we're using the most recent + * journal index. + */ + +int gfs2_logd(void *data) +{ + struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + struct gfs2_holder ji_gh; + unsigned long t; + + while (!kthread_should_stop()) { + /* Advance the log tail */ + + t = sdp->sd_log_flush_time + + gfs2_tune_get(sdp, gt_log_flush_secs) * HZ; + + gfs2_ail1_empty(sdp, DIO_ALL); + + if (time_after_eq(jiffies, t)) { + gfs2_log_flush(sdp); + sdp->sd_log_flush_time = jiffies; + } + + /* Check for latest journal index */ + + t = sdp->sd_jindex_refresh_time + + gfs2_tune_get(sdp, gt_jindex_refresh_secs) * HZ; + + if (time_after_eq(jiffies, t)) { + if (!gfs2_jindex_hold(sdp, &ji_gh)) + gfs2_glock_dq_uninit(&ji_gh); + sdp->sd_jindex_refresh_time = jiffies; + } + + t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; + schedule_timeout_interruptible(t); + } + + return 0; +} + +/** + * gfs2_quotad - Write cached quota changes into the quota file + * @sdp: Pointer to GFS2 superblock + * + */ + +int gfs2_quotad(void *data) +{ + struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + unsigned long t; + int error; + + while (!kthread_should_stop()) { + /* Update the master statfs file */ + + t = sdp->sd_statfs_sync_time + + gfs2_tune_get(sdp, gt_statfs_quantum) * HZ; + + if (time_after_eq(jiffies, t)) { + error = gfs2_statfs_sync(sdp); + if (error && + error != -EROFS && + !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + fs_err(sdp, "quotad: (1) error=%d\n", error); + sdp->sd_statfs_sync_time = jiffies; + } + + /* Update quota file */ + + t = sdp->sd_quota_sync_time + + gfs2_tune_get(sdp, gt_quota_quantum) * HZ; + + if (time_after_eq(jiffies, t)) { + error = gfs2_quota_sync(sdp); + if (error && + error != -EROFS && + !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + fs_err(sdp, "quotad: (2) error=%d\n", error); + sdp->sd_quota_sync_time = jiffies; + } + + gfs2_quota_scan(sdp); + + t = gfs2_tune_get(sdp, gt_quotad_secs) * HZ; + schedule_timeout_interruptible(t); + } + + return 0; +} + +/** + * gfs2_inoded - Deallocate unlinked inodes + * @sdp: Pointer to GFS2 superblock + * + */ + +int gfs2_inoded(void *data) +{ + struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; + unsigned long t; + int error; + + while (!kthread_should_stop()) { + error = gfs2_unlinked_dealloc(sdp); + if (error && + error != -EROFS && + !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + fs_err(sdp, "inoded: error = %d\n", error); + + t = gfs2_tune_get(sdp, gt_inoded_secs) * HZ; + schedule_timeout_interruptible(t); + } + + return 0; +} + diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h new file mode 100644 index 000000000000..a27fdeda5fbb --- /dev/null +++ b/fs/gfs2/daemon.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __DAEMON_DOT_H__ +#define __DAEMON_DOT_H__ + +int gfs2_scand(void *data); +int gfs2_glockd(void *data); +int gfs2_recoverd(void *data); +int gfs2_logd(void *data); +int gfs2_quotad(void *data); +int gfs2_inoded(void *data); + +#endif /* __DAEMON_DOT_H__ */ diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c new file mode 100644 index 000000000000..6b1dc3dc3a2d --- /dev/null +++ b/fs/gfs2/dir.c @@ -0,0 +1,2157 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +/* +* Implements Extendible Hashing as described in: +* "Extendible Hashing" by Fagin, et al in +* __ACM Trans. on Database Systems__, Sept 1979. +* +* +* Here's the layout of dirents which is essentially the same as that of ext2 +* within a single block. The field de_name_len is the number of bytes +* actually required for the name (no null terminator). The field de_rec_len +* is the number of bytes allocated to the dirent. The offset of the next +* dirent in the block is (dirent + dirent->de_rec_len). When a dirent is +* deleted, the preceding dirent inherits its allocated space, ie +* prev->de_rec_len += deleted->de_rec_len. Since the next dirent is obtained +* by adding de_rec_len to the current dirent, this essentially causes the +* deleted dirent to get jumped over when iterating through all the dirents. +* +* When deleting the first dirent in a block, there is no previous dirent so +* the field de_ino is set to zero to designate it as deleted. When allocating +* a dirent, gfs2_dirent_alloc iterates through the dirents in a block. If the +* first dirent has (de_ino == 0) and de_rec_len is large enough, this first +* dirent is allocated. Otherwise it must go through all the 'used' dirents +* searching for one in which the amount of total space minus the amount of +* used space will provide enough space for the new dirent. +* +* There are two types of blocks in which dirents reside. In a stuffed dinode, +* the dirents begin at offset sizeof(struct gfs2_dinode) from the beginning of +* the block. In leaves, they begin at offset sizeof(struct gfs2_leaf) from the +* beginning of the leaf block. The dirents reside in leaves when +* +* dip->i_di.di_flags & GFS2_DIF_EXHASH is true +* +* Otherwise, the dirents are "linear", within a single stuffed dinode block. +* +* When the dirents are in leaves, the actual contents of the directory file are +* used as an array of 64-bit block pointers pointing to the leaf blocks. The +* dirents are NOT in the directory file itself. There can be more than one block +* pointer in the array that points to the same leaf. In fact, when a directory +* is first converted from linear to exhash, all of the pointers point to the +* same leaf. +* +* When a leaf is completely full, the size of the hash table can be +* doubled unless it is already at the maximum size which is hard coded into +* GFS2_DIR_MAX_DEPTH. After that, leaves are chained together in a linked list, +* but never before the maximum hash table size has been reached. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "dir.h" +#include "glock.h" +#include "inode.h" +#include "jdata.h" +#include "meta_io.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" + +#define IS_LEAF 1 /* Hashed (leaf) directory */ +#define IS_DINODE 2 /* Linear (stuffed dinode block) directory */ + +#if 1 +#define gfs2_disk_hash2offset(h) (((uint64_t)(h)) >> 1) +#define gfs2_dir_offset2hash(p) ((uint32_t)(((uint64_t)(p)) << 1)) +#else +#define gfs2_disk_hash2offset(h) (((uint64_t)(h))) +#define gfs2_dir_offset2hash(p) ((uint32_t)(((uint64_t)(p)))) +#endif + +typedef int (*leaf_call_t) (struct gfs2_inode *dip, + uint32_t index, uint32_t len, uint64_t leaf_no, + void *data); + +/** + * int gfs2_filecmp - Compare two filenames + * @file1: The first filename + * @file2: The second filename + * @len_of_file2: The length of the second file + * + * This routine compares two filenames and returns 1 if they are equal. + * + * Returns: 1 if the files are the same, otherwise 0. + */ + +int gfs2_filecmp(struct qstr *file1, char *file2, int len_of_file2) +{ + if (file1->len != len_of_file2) + return 0; + if (memcmp(file1->name, file2, file1->len)) + return 0; + return 1; +} + +/** + * dirent_first - Return the first dirent + * @dip: the directory + * @bh: The buffer + * @dent: Pointer to list of dirents + * + * return first dirent whether bh points to leaf or stuffed dinode + * + * Returns: IS_LEAF, IS_DINODE, or -errno + */ + +static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh, + struct gfs2_dirent **dent) +{ + struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data; + + if (be16_to_cpu(h->mh_type) == GFS2_METATYPE_LF) { + if (gfs2_meta_check(dip->i_sbd, bh)) + return -EIO; + *dent = (struct gfs2_dirent *)(bh->b_data + + sizeof(struct gfs2_leaf)); + return IS_LEAF; + } else { + if (gfs2_metatype_check(dip->i_sbd, bh, GFS2_METATYPE_DI)) + return -EIO; + *dent = (struct gfs2_dirent *)(bh->b_data + + sizeof(struct gfs2_dinode)); + return IS_DINODE; + } +} + +/** + * dirent_next - Next dirent + * @dip: the directory + * @bh: The buffer + * @dent: Pointer to list of dirents + * + * Returns: 0 on success, error code otherwise + */ + +static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, + struct gfs2_dirent **dent) +{ + struct gfs2_dirent *tmp, *cur; + char *bh_end; + uint32_t cur_rec_len; + + cur = *dent; + bh_end = bh->b_data + bh->b_size; + cur_rec_len = be32_to_cpu(cur->de_rec_len); + + if ((char *)cur + cur_rec_len >= bh_end) { + if ((char *)cur + cur_rec_len > bh_end) { + gfs2_consist_inode(dip); + return -EIO; + } + return -ENOENT; + } + + tmp = (struct gfs2_dirent *)((char *)cur + cur_rec_len); + + if ((char *)tmp + be32_to_cpu(tmp->de_rec_len) > bh_end) { + gfs2_consist_inode(dip); + return -EIO; + } + /* Only the first dent could ever have de_inum.no_addr == 0 */ + if (!tmp->de_inum.no_addr) { + gfs2_consist_inode(dip); + return -EIO; + } + + *dent = tmp; + + return 0; +} + +/** + * dirent_del - Delete a dirent + * @dip: The GFS2 inode + * @bh: The buffer + * @prev: The previous dirent + * @cur: The current dirent + * + */ + +static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, + struct gfs2_dirent *prev, struct gfs2_dirent *cur) +{ + uint32_t cur_rec_len, prev_rec_len; + + if (!cur->de_inum.no_addr) { + gfs2_consist_inode(dip); + return; + } + + gfs2_trans_add_bh(dip->i_gl, bh); + + /* If there is no prev entry, this is the first entry in the block. + The de_rec_len is already as big as it needs to be. Just zero + out the inode number and return. */ + + if (!prev) { + cur->de_inum.no_addr = 0; /* No endianess worries */ + return; + } + + /* Combine this dentry with the previous one. */ + + prev_rec_len = be32_to_cpu(prev->de_rec_len); + cur_rec_len = be32_to_cpu(cur->de_rec_len); + + if ((char *)prev + prev_rec_len != (char *)cur) + gfs2_consist_inode(dip); + if ((char *)cur + cur_rec_len > bh->b_data + bh->b_size) + gfs2_consist_inode(dip); + + prev_rec_len += cur_rec_len; + prev->de_rec_len = cpu_to_be32(prev_rec_len); +} + +/** + * gfs2_dirent_alloc - Allocate a directory entry + * @dip: The GFS2 inode + * @bh: The buffer + * @name_len: The length of the name + * @dent_out: Pointer to list of dirents + * + * Returns: 0 on success, error code otherwise + */ + +int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, + int name_len, struct gfs2_dirent **dent_out) +{ + struct gfs2_dirent *dent, *new; + unsigned int rec_len = GFS2_DIRENT_SIZE(name_len); + unsigned int entries = 0, offset = 0; + int type; + + type = dirent_first(dip, bh, &dent); + if (type < 0) + return type; + + if (type == IS_LEAF) { + struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data; + entries = be16_to_cpu(leaf->lf_entries); + offset = sizeof(struct gfs2_leaf); + } else { + struct gfs2_dinode *dinode = (struct gfs2_dinode *)bh->b_data; + entries = be32_to_cpu(dinode->di_entries); + offset = sizeof(struct gfs2_dinode); + } + + if (!entries) { + if (dent->de_inum.no_addr) { + gfs2_consist_inode(dip); + return -EIO; + } + + gfs2_trans_add_bh(dip->i_gl, bh); + + dent->de_rec_len = bh->b_size - offset; + dent->de_rec_len = cpu_to_be32(dent->de_rec_len); + dent->de_name_len = name_len; + + *dent_out = dent; + return 0; + } + + do { + uint32_t cur_rec_len, cur_name_len; + + cur_rec_len = be32_to_cpu(dent->de_rec_len); + cur_name_len = dent->de_name_len; + + if ((!dent->de_inum.no_addr && cur_rec_len >= rec_len) || + (cur_rec_len >= GFS2_DIRENT_SIZE(cur_name_len) + rec_len)) { + gfs2_trans_add_bh(dip->i_gl, bh); + + if (dent->de_inum.no_addr) { + new = (struct gfs2_dirent *)((char *)dent + + GFS2_DIRENT_SIZE(cur_name_len)); + memset(new, 0, sizeof(struct gfs2_dirent)); + + new->de_rec_len = cur_rec_len - GFS2_DIRENT_SIZE(cur_name_len); + new->de_rec_len = cpu_to_be32(new->de_rec_len); + new->de_name_len = name_len; + + dent->de_rec_len = cur_rec_len - be32_to_cpu(new->de_rec_len); + dent->de_rec_len = cpu_to_be32(dent->de_rec_len); + + *dent_out = new; + return 0; + } + + dent->de_name_len = name_len; + + *dent_out = dent; + return 0; + } + } while (dirent_next(dip, bh, &dent) == 0); + + return -ENOSPC; +} + +/** + * dirent_fits - See if we can fit a entry in this buffer + * @dip: The GFS2 inode + * @bh: The buffer + * @name_len: The length of the name + * + * Returns: 1 if it can fit, 0 otherwise + */ + +static int dirent_fits(struct gfs2_inode *dip, struct buffer_head *bh, + int name_len) +{ + struct gfs2_dirent *dent; + unsigned int rec_len = GFS2_DIRENT_SIZE(name_len); + unsigned int entries = 0; + int type; + + type = dirent_first(dip, bh, &dent); + if (type < 0) + return type; + + if (type == IS_LEAF) { + struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data; + entries = be16_to_cpu(leaf->lf_entries); + } else { + struct gfs2_dinode *dinode = (struct gfs2_dinode *)bh->b_data; + entries = be32_to_cpu(dinode->di_entries); + } + + if (!entries) + return 1; + + do { + uint32_t cur_rec_len, cur_name_len; + + cur_rec_len = be32_to_cpu(dent->de_rec_len); + cur_name_len = dent->de_name_len; + + if ((!dent->de_inum.no_addr && cur_rec_len >= rec_len) || + (cur_rec_len >= GFS2_DIRENT_SIZE(cur_name_len) + rec_len)) + return 1; + } while (dirent_next(dip, bh, &dent) == 0); + + return 0; +} + +static int leaf_search(struct gfs2_inode *dip, struct buffer_head *bh, + struct qstr *filename, struct gfs2_dirent **dent_out, + struct gfs2_dirent **dent_prev) +{ + uint32_t hash; + struct gfs2_dirent *dent, *prev = NULL; + unsigned int entries = 0; + int type; + + type = dirent_first(dip, bh, &dent); + if (type < 0) + return type; + + if (type == IS_LEAF) { + struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data; + entries = be16_to_cpu(leaf->lf_entries); + } else if (type == IS_DINODE) { + struct gfs2_dinode *dinode = (struct gfs2_dinode *)bh->b_data; + entries = be32_to_cpu(dinode->di_entries); + } + + hash = gfs2_disk_hash(filename->name, filename->len); + + do { + if (!dent->de_inum.no_addr) { + prev = dent; + continue; + } + + if (be32_to_cpu(dent->de_hash) == hash && + gfs2_filecmp(filename, (char *)(dent + 1), + dent->de_name_len)) { + *dent_out = dent; + if (dent_prev) + *dent_prev = prev; + + return 0; + } + + prev = dent; + } while (dirent_next(dip, bh, &dent) == 0); + + return -ENOENT; +} + +static int get_leaf(struct gfs2_inode *dip, uint64_t leaf_no, + struct buffer_head **bhp) +{ + int error; + + error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_START | DIO_WAIT, bhp); + if (!error && gfs2_metatype_check(dip->i_sbd, *bhp, GFS2_METATYPE_LF)) + error = -EIO; + + return error; +} + +/** + * get_leaf_nr - Get a leaf number associated with the index + * @dip: The GFS2 inode + * @index: + * @leaf_out: + * + * Returns: 0 on success, error code otherwise + */ + +static int get_leaf_nr(struct gfs2_inode *dip, uint32_t index, + uint64_t *leaf_out) +{ + uint64_t leaf_no; + int error; + + error = gfs2_jdata_read_mem(dip, (char *)&leaf_no, + index * sizeof(uint64_t), + sizeof(uint64_t)); + if (error != sizeof(uint64_t)) + return (error < 0) ? error : -EIO; + + *leaf_out = be64_to_cpu(leaf_no); + + return 0; +} + +static int get_first_leaf(struct gfs2_inode *dip, uint32_t index, + struct buffer_head **bh_out) +{ + uint64_t leaf_no; + int error; + + error = get_leaf_nr(dip, index, &leaf_no); + if (!error) + error = get_leaf(dip, leaf_no, bh_out); + + return error; +} + +static int get_next_leaf(struct gfs2_inode *dip, struct buffer_head *bh_in, + struct buffer_head **bh_out) +{ + struct gfs2_leaf *leaf; + int error; + + leaf = (struct gfs2_leaf *)bh_in->b_data; + + if (!leaf->lf_next) + error = -ENOENT; + else + error = get_leaf(dip, be64_to_cpu(leaf->lf_next), bh_out); + + return error; +} + +static int linked_leaf_search(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_dirent **dent_out, + struct gfs2_dirent **dent_prev, + struct buffer_head **bh_out) +{ + struct buffer_head *bh = NULL, *bh_next; + uint32_t hsize, index; + uint32_t hash; + int error; + + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs2_consist_inode(dip); + return -EIO; + } + + /* Figure out the address of the leaf node. */ + + hash = gfs2_disk_hash(filename->name, filename->len); + index = hash >> (32 - dip->i_di.di_depth); + + error = get_first_leaf(dip, index, &bh_next); + if (error) + return error; + + /* Find the entry */ + + do { + brelse(bh); + + bh = bh_next; + + error = leaf_search(dip, bh, filename, dent_out, dent_prev); + switch (error) { + case 0: + *bh_out = bh; + return 0; + + case -ENOENT: + break; + + default: + brelse(bh); + return error; + } + + error = get_next_leaf(dip, bh, &bh_next); + } + while (!error); + + brelse(bh); + + return error; +} + +/** + * dir_make_exhash - Convert a stuffed directory into an ExHash directory + * @dip: The GFS2 inode + * + * Returns: 0 on success, error code otherwise + */ + +static int dir_make_exhash(struct gfs2_inode *dip) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_dirent *dent; + struct buffer_head *bh, *dibh; + struct gfs2_leaf *leaf; + int y; + uint32_t x; + uint64_t *lp, bn; + int error; + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (error) + return error; + + /* Allocate a new block for the first leaf node */ + + bn = gfs2_alloc_meta(dip); + + /* Turn over a new leaf */ + + bh = gfs2_meta_new(dip->i_gl, bn); + gfs2_trans_add_bh(dip->i_gl, bh); + gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF); + gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); + + /* Fill in the leaf structure */ + + leaf = (struct gfs2_leaf *)bh->b_data; + + gfs2_assert(sdp, dip->i_di.di_entries < (1 << 16)); + + leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); + leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries); + + /* Copy dirents */ + + gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_leaf), dibh, + sizeof(struct gfs2_dinode)); + + /* Find last entry */ + + x = 0; + dirent_first(dip, bh, &dent); + + do { + if (!dent->de_inum.no_addr) + continue; + if (++x == dip->i_di.di_entries) + break; + } + while (dirent_next(dip, bh, &dent) == 0); + + /* Adjust the last dirent's record length + (Remember that dent still points to the last entry.) */ + + dent->de_rec_len = be32_to_cpu(dent->de_rec_len) + + sizeof(struct gfs2_dinode) - + sizeof(struct gfs2_leaf); + dent->de_rec_len = cpu_to_be32(dent->de_rec_len); + + brelse(bh); + + /* We're done with the new leaf block, now setup the new + hash table. */ + + gfs2_trans_add_bh(dip->i_gl, dibh); + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); + + lp = (uint64_t *)(dibh->b_data + sizeof(struct gfs2_dinode)); + + for (x = sdp->sd_hash_ptrs; x--; lp++) + *lp = cpu_to_be64(bn); + + dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2; + dip->i_di.di_blocks++; + dip->i_di.di_flags |= GFS2_DIF_EXHASH; + dip->i_di.di_payload_format = 0; + + for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; + dip->i_di.di_depth = y; + + gfs2_dinode_out(&dip->i_di, dibh->b_data); + + brelse(dibh); + + return 0; +} + +/** + * dir_split_leaf - Split a leaf block into two + * @dip: The GFS2 inode + * @index: + * @leaf_no: + * + * Returns: 0 on success, error code on failure + */ + +static int dir_split_leaf(struct gfs2_inode *dip, uint32_t index, + uint64_t leaf_no) +{ + struct buffer_head *nbh, *obh, *dibh; + struct gfs2_leaf *nleaf, *oleaf; + struct gfs2_dirent *dent, *prev = NULL, *next = NULL, *new; + uint32_t start, len, half_len, divider; + uint64_t bn, *lp; + uint32_t name_len; + int x, moved = 0; + int error; + + /* Allocate the new leaf block */ + + bn = gfs2_alloc_meta(dip); + + /* Get the new leaf block */ + + nbh = gfs2_meta_new(dip->i_gl, bn); + gfs2_trans_add_bh(dip->i_gl, nbh); + gfs2_metatype_set(nbh, GFS2_METATYPE_LF, GFS2_FORMAT_LF); + gfs2_buffer_clear_tail(nbh, sizeof(struct gfs2_meta_header)); + + nleaf = (struct gfs2_leaf *)nbh->b_data; + + nleaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); + + /* Get the old leaf block */ + + error = get_leaf(dip, leaf_no, &obh); + if (error) + goto fail; + + gfs2_trans_add_bh(dip->i_gl, obh); + + oleaf = (struct gfs2_leaf *)obh->b_data; + + /* Compute the start and len of leaf pointers in the hash table. */ + + len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth)); + half_len = len >> 1; + if (!half_len) { + gfs2_consist_inode(dip); + error = -EIO; + goto fail_brelse; + } + + start = (index & ~(len - 1)); + + /* Change the pointers. + Don't bother distinguishing stuffed from non-stuffed. + This code is complicated enough already. */ + + lp = kcalloc(half_len, sizeof(uint64_t), GFP_KERNEL | __GFP_NOFAIL); + + error = gfs2_jdata_read_mem(dip, (char *)lp, start * sizeof(uint64_t), + half_len * sizeof(uint64_t)); + if (error != half_len * sizeof(uint64_t)) { + if (error >= 0) + error = -EIO; + goto fail_lpfree; + } + + /* Change the pointers */ + + for (x = 0; x < half_len; x++) + lp[x] = cpu_to_be64(bn); + + error = gfs2_jdata_write_mem(dip, (char *)lp, start * sizeof(uint64_t), + half_len * sizeof(uint64_t)); + if (error != half_len * sizeof(uint64_t)) { + if (error >= 0) + error = -EIO; + goto fail_lpfree; + } + + kfree(lp); + + /* Compute the divider */ + + divider = (start + half_len) << (32 - dip->i_di.di_depth); + + /* Copy the entries */ + + dirent_first(dip, obh, &dent); + + do { + next = dent; + if (dirent_next(dip, obh, &next)) + next = NULL; + + if (dent->de_inum.no_addr && + be32_to_cpu(dent->de_hash) < divider) { + name_len = dent->de_name_len; + + gfs2_dirent_alloc(dip, nbh, name_len, &new); + + new->de_inum = dent->de_inum; /* No endian worries */ + new->de_hash = dent->de_hash; /* No endian worries */ + new->de_type = dent->de_type; /* No endian worries */ + memcpy((char *)(new + 1), (char *)(dent + 1), + name_len); + + nleaf->lf_entries = be16_to_cpu(nleaf->lf_entries)+1; + nleaf->lf_entries = cpu_to_be16(nleaf->lf_entries); + + dirent_del(dip, obh, prev, dent); + + if (!oleaf->lf_entries) + gfs2_consist_inode(dip); + oleaf->lf_entries = be16_to_cpu(oleaf->lf_entries)-1; + oleaf->lf_entries = cpu_to_be16(oleaf->lf_entries); + + if (!prev) + prev = dent; + + moved = 1; + } else + prev = dent; + + dent = next; + } + while (dent); + + /* If none of the entries got moved into the new leaf, + artificially fill in the first entry. */ + + if (!moved) { + gfs2_dirent_alloc(dip, nbh, 0, &new); + new->de_inum.no_addr = 0; + } + + oleaf->lf_depth = be16_to_cpu(oleaf->lf_depth) + 1; + oleaf->lf_depth = cpu_to_be16(oleaf->lf_depth); + nleaf->lf_depth = oleaf->lf_depth; + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (!gfs2_assert_withdraw(dip->i_sbd, !error)) { + dip->i_di.di_blocks++; + gfs2_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + } + + brelse(obh); + brelse(nbh); + + return error; + + fail_lpfree: + kfree(lp); + + fail_brelse: + brelse(obh); + + fail: + brelse(nbh); + return error; +} + +/** + * dir_double_exhash - Double size of ExHash table + * @dip: The GFS2 dinode + * + * Returns: 0 on success, error code on failure + */ + +static int dir_double_exhash(struct gfs2_inode *dip) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct buffer_head *dibh; + uint32_t hsize; + uint64_t *buf; + uint64_t *from, *to; + uint64_t block; + int x; + int error = 0; + + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs2_consist_inode(dip); + return -EIO; + } + + /* Allocate both the "from" and "to" buffers in one big chunk */ + + buf = kcalloc(3, sdp->sd_hash_bsize, GFP_KERNEL | __GFP_NOFAIL); + + for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) { + error = gfs2_jdata_read_mem(dip, (char *)buf, + block * sdp->sd_hash_bsize, + sdp->sd_hash_bsize); + if (error != sdp->sd_hash_bsize) { + if (error >= 0) + error = -EIO; + goto fail; + } + + from = buf; + to = (uint64_t *)((char *)buf + sdp->sd_hash_bsize); + + for (x = sdp->sd_hash_ptrs; x--; from++) { + *to++ = *from; /* No endianess worries */ + *to++ = *from; + } + + error = gfs2_jdata_write_mem(dip, + (char *)buf + sdp->sd_hash_bsize, + block * sdp->sd_sb.sb_bsize, + sdp->sd_sb.sb_bsize); + if (error != sdp->sd_sb.sb_bsize) { + if (error >= 0) + error = -EIO; + goto fail; + } + } + + kfree(buf); + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (!gfs2_assert_withdraw(sdp, !error)) { + dip->i_di.di_depth++; + gfs2_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + } + + return error; + + fail: + kfree(buf); + + return error; +} + +/** + * compare_dents - compare directory entries by hash value + * @a: first dent + * @b: second dent + * + * When comparing the hash entries of @a to @b: + * gt: returns 1 + * lt: returns -1 + * eq: returns 0 + */ + +static int compare_dents(const void *a, const void *b) +{ + struct gfs2_dirent *dent_a, *dent_b; + uint32_t hash_a, hash_b; + int ret = 0; + + dent_a = *(struct gfs2_dirent **)a; + hash_a = dent_a->de_hash; + hash_a = be32_to_cpu(hash_a); + + dent_b = *(struct gfs2_dirent **)b; + hash_b = dent_b->de_hash; + hash_b = be32_to_cpu(hash_b); + + if (hash_a > hash_b) + ret = 1; + else if (hash_a < hash_b) + ret = -1; + else { + unsigned int len_a = dent_a->de_name_len; + unsigned int len_b = dent_b->de_name_len; + + if (len_a > len_b) + ret = 1; + else if (len_a < len_b) + ret = -1; + else + ret = memcmp((char *)(dent_a + 1), + (char *)(dent_b + 1), + len_a); + } + + return ret; +} + +/** + * do_filldir_main - read out directory entries + * @dip: The GFS2 inode + * @offset: The offset in the file to read from + * @opaque: opaque data to pass to filldir + * @filldir: The function to pass entries to + * @darr: an array of struct gfs2_dirent pointers to read + * @entries: the number of entries in darr + * @copied: pointer to int that's non-zero if a entry has been copied out + * + * Jump through some hoops to make sure that if there are hash collsions, + * they are read out at the beginning of a buffer. We want to minimize + * the possibility that they will fall into different readdir buffers or + * that someone will want to seek to that location. + * + * Returns: errno, >0 on exception from filldir + */ + +static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, + void *opaque, gfs2_filldir_t filldir, + struct gfs2_dirent **darr, uint32_t entries, + int *copied) +{ + struct gfs2_dirent *dent, *dent_next; + struct gfs2_inum inum; + uint64_t off, off_next; + unsigned int x, y; + int run = 0; + int error = 0; + + sort(darr, entries, sizeof(struct gfs2_dirent *), compare_dents, NULL); + + dent_next = darr[0]; + off_next = be32_to_cpu(dent_next->de_hash); + off_next = gfs2_disk_hash2offset(off_next); + + for (x = 0, y = 1; x < entries; x++, y++) { + dent = dent_next; + off = off_next; + + if (y < entries) { + dent_next = darr[y]; + off_next = be32_to_cpu(dent_next->de_hash); + off_next = gfs2_disk_hash2offset(off_next); + + if (off < *offset) + continue; + *offset = off; + + if (off_next == off) { + if (*copied && !run) + return 1; + run = 1; + } else + run = 0; + } else { + if (off < *offset) + continue; + *offset = off; + } + + gfs2_inum_in(&inum, (char *)&dent->de_inum); + + error = filldir(opaque, (char *)(dent + 1), + dent->de_name_len, + off, &inum, + dent->de_type); + if (error) + return 1; + + *copied = 1; + } + + /* Increment the *offset by one, so the next time we come into the + do_filldir fxn, we get the next entry instead of the last one in the + current leaf */ + + (*offset)++; + + return 0; +} + +/** + * do_filldir_single - Read directory entries out of a single block + * @dip: The GFS2 inode + * @offset: The offset in the file to read from + * @opaque: opaque data to pass to filldir + * @filldir: The function to pass entries to + * @bh: the block + * @entries: the number of entries in the block + * @copied: pointer to int that's non-zero if a entry has been copied out + * + * Returns: errno, >0 on exception from filldir + */ + +static int do_filldir_single(struct gfs2_inode *dip, uint64_t *offset, + void *opaque, gfs2_filldir_t filldir, + struct buffer_head *bh, uint32_t entries, + int *copied) +{ + struct gfs2_dirent **darr; + struct gfs2_dirent *de; + unsigned int e = 0; + int error; + + if (!entries) + return 0; + + darr = kcalloc(entries, sizeof(struct gfs2_dirent *), GFP_KERNEL); + if (!darr) + return -ENOMEM; + + dirent_first(dip, bh, &de); + do { + if (!de->de_inum.no_addr) + continue; + if (e >= entries) { + gfs2_consist_inode(dip); + error = -EIO; + goto out; + } + darr[e++] = de; + } + while (dirent_next(dip, bh, &de) == 0); + + if (e != entries) { + gfs2_consist_inode(dip); + error = -EIO; + goto out; + } + + error = do_filldir_main(dip, offset, opaque, filldir, darr, + entries, copied); + + out: + kfree(darr); + + return error; +} + +/** + * do_filldir_multi - Read directory entries out of a linked leaf list + * @dip: The GFS2 inode + * @offset: The offset in the file to read from + * @opaque: opaque data to pass to filldir + * @filldir: The function to pass entries to + * @bh: the first leaf in the list + * @copied: pointer to int that's non-zero if a entry has been copied out + * + * Returns: errno, >0 on exception from filldir + */ + +static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset, + void *opaque, gfs2_filldir_t filldir, + struct buffer_head *bh, int *copied) +{ + struct buffer_head **larr = NULL; + struct gfs2_dirent **darr; + struct gfs2_leaf *leaf; + struct buffer_head *tmp_bh; + struct gfs2_dirent *de; + unsigned int entries, e = 0; + unsigned int leaves = 0, l = 0; + unsigned int x; + uint64_t ln; + int error = 0; + + /* Count leaves and entries */ + + leaf = (struct gfs2_leaf *)bh->b_data; + entries = be16_to_cpu(leaf->lf_entries); + ln = leaf->lf_next; + + while (ln) { + ln = be64_to_cpu(ln); + + error = get_leaf(dip, ln, &tmp_bh); + if (error) + return error; + + leaf = (struct gfs2_leaf *)tmp_bh->b_data; + if (leaf->lf_entries) { + entries += be16_to_cpu(leaf->lf_entries); + leaves++; + } + ln = leaf->lf_next; + + brelse(tmp_bh); + } + + if (!entries) + return 0; + + if (leaves) { + larr = kcalloc(leaves, sizeof(struct buffer_head *),GFP_KERNEL); + if (!larr) + return -ENOMEM; + } + + darr = kcalloc(entries, sizeof(struct gfs2_dirent *), GFP_KERNEL); + if (!darr) { + kfree(larr); + return -ENOMEM; + } + + leaf = (struct gfs2_leaf *)bh->b_data; + if (leaf->lf_entries) { + dirent_first(dip, bh, &de); + do { + if (!de->de_inum.no_addr) + continue; + if (e >= entries) { + gfs2_consist_inode(dip); + error = -EIO; + goto out; + } + darr[e++] = de; + } + while (dirent_next(dip, bh, &de) == 0); + } + ln = leaf->lf_next; + + while (ln) { + ln = be64_to_cpu(ln); + + error = get_leaf(dip, ln, &tmp_bh); + if (error) + goto out; + + leaf = (struct gfs2_leaf *)tmp_bh->b_data; + if (leaf->lf_entries) { + dirent_first(dip, tmp_bh, &de); + do { + if (!de->de_inum.no_addr) + continue; + if (e >= entries) { + gfs2_consist_inode(dip); + error = -EIO; + goto out; + } + darr[e++] = de; + } + while (dirent_next(dip, tmp_bh, &de) == 0); + + larr[l++] = tmp_bh; + + ln = leaf->lf_next; + } else { + ln = leaf->lf_next; + brelse(tmp_bh); + } + } + + if (gfs2_assert_withdraw(dip->i_sbd, l == leaves)) { + error = -EIO; + goto out; + } + if (e != entries) { + gfs2_consist_inode(dip); + error = -EIO; + goto out; + } + + error = do_filldir_main(dip, offset, opaque, filldir, darr, + entries, copied); + + out: + kfree(darr); + for (x = 0; x < l; x++) + brelse(larr[x]); + kfree(larr); + + return error; +} + +/** + * dir_e_search - Search exhash (leaf) dir for inode matching name + * @dip: The GFS2 inode + * @filename: Filename string + * @inode: If non-NULL, function fills with formal inode # and block address + * @type: If non-NULL, function fills with DT_... dinode type + * + * Returns: + */ + +static int dir_e_search(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int *type) +{ + struct buffer_head *bh; + struct gfs2_dirent *dent; + int error; + + error = linked_leaf_search(dip, filename, &dent, NULL, &bh); + if (error) + return error; + + if (inum) + gfs2_inum_in(inum, (char *)&dent->de_inum); + if (type) + *type = dent->de_type; + + brelse(bh); + + return 0; +} + +static int dir_e_add(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int type) +{ + struct buffer_head *bh, *nbh, *dibh; + struct gfs2_leaf *leaf, *nleaf; + struct gfs2_dirent *dent; + uint32_t hsize, index; + uint32_t hash; + uint64_t leaf_no, bn; + int error; + + restart: + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs2_consist_inode(dip); + return -EIO; + } + + /* Figure out the address of the leaf node. */ + + hash = gfs2_disk_hash(filename->name, filename->len); + index = hash >> (32 - dip->i_di.di_depth); + + error = get_leaf_nr(dip, index, &leaf_no); + if (error) + return error; + + /* Add entry to the leaf */ + + for (;;) { + error = get_leaf(dip, leaf_no, &bh); + if (error) + return error; + + leaf = (struct gfs2_leaf *)bh->b_data; + + if (gfs2_dirent_alloc(dip, bh, filename->len, &dent)) { + + if (be16_to_cpu(leaf->lf_depth) < dip->i_di.di_depth) { + /* Can we split the leaf? */ + + brelse(bh); + + error = dir_split_leaf(dip, index, leaf_no); + if (error) + return error; + + goto restart; + + } else if (dip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) { + /* Can we double the hash table? */ + + brelse(bh); + + error = dir_double_exhash(dip); + if (error) + return error; + + goto restart; + + } else if (leaf->lf_next) { + /* Can we try the next leaf in the list? */ + leaf_no = be64_to_cpu(leaf->lf_next); + brelse(bh); + continue; + + } else { + /* Create a new leaf and add it to the list. */ + + bn = gfs2_alloc_meta(dip); + + nbh = gfs2_meta_new(dip->i_gl, bn); + gfs2_trans_add_bh(dip->i_gl, nbh); + gfs2_metatype_set(nbh, + GFS2_METATYPE_LF, + GFS2_FORMAT_LF); + gfs2_buffer_clear_tail(nbh, + sizeof(struct gfs2_meta_header)); + + gfs2_trans_add_bh(dip->i_gl, bh); + leaf->lf_next = cpu_to_be64(bn); + + nleaf = (struct gfs2_leaf *)nbh->b_data; + nleaf->lf_depth = leaf->lf_depth; + nleaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); + + gfs2_dirent_alloc(dip, nbh, filename->len, + &dent); + + dip->i_di.di_blocks++; + + brelse(bh); + + bh = nbh; + leaf = nleaf; + } + } + + /* If the gfs2_dirent_alloc() succeeded, it pinned the "bh" */ + + gfs2_inum_out(inum, (char *)&dent->de_inum); + dent->de_hash = cpu_to_be32(hash); + dent->de_type = type; + memcpy((char *)(dent + 1), filename->name, filename->len); + + leaf->lf_entries = be16_to_cpu(leaf->lf_entries) + 1; + leaf->lf_entries = cpu_to_be16(leaf->lf_entries); + + brelse(bh); + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (error) + return error; + + dip->i_di.di_entries++; + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs2_trans_add_bh(dip->i_gl, dibh); + gfs2_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + + return 0; + } + + return -ENOENT; +} + +static int dir_e_del(struct gfs2_inode *dip, struct qstr *filename) +{ + struct buffer_head *bh, *dibh; + struct gfs2_dirent *dent, *prev; + struct gfs2_leaf *leaf; + unsigned int entries; + int error; + + error = linked_leaf_search(dip, filename, &dent, &prev, &bh); + if (error == -ENOENT) { + gfs2_consist_inode(dip); + return -EIO; + } + if (error) + return error; + + dirent_del(dip, bh, prev, dent); /* Pins bh */ + + leaf = (struct gfs2_leaf *)bh->b_data; + entries = be16_to_cpu(leaf->lf_entries); + if (!entries) + gfs2_consist_inode(dip); + entries--; + leaf->lf_entries = cpu_to_be16(entries); + + brelse(bh); + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (error) + return error; + + if (!dip->i_di.di_entries) + gfs2_consist_inode(dip); + dip->i_di.di_entries--; + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs2_trans_add_bh(dip->i_gl, dibh); + gfs2_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + + return 0; +} + +/** + * dir_e_read - Reads the entries from a directory into a filldir buffer + * @dip: dinode pointer + * @offset: the hash of the last entry read shifted to the right once + * @opaque: buffer for the filldir function to fill + * @filldir: points to the filldir function to use + * + * Returns: errno + */ + +static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, + gfs2_filldir_t filldir) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct buffer_head *bh; + struct gfs2_leaf leaf; + uint32_t hsize, len; + uint32_t ht_offset, lp_offset, ht_offset_cur = -1; + uint32_t hash, index; + uint64_t *lp; + int copied = 0; + int error = 0; + + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs2_consist_inode(dip); + return -EIO; + } + + hash = gfs2_dir_offset2hash(*offset); + index = hash >> (32 - dip->i_di.di_depth); + + lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); + if (!lp) + return -ENOMEM; + + while (index < hsize) { + lp_offset = index & (sdp->sd_hash_ptrs - 1); + ht_offset = index - lp_offset; + + if (ht_offset_cur != ht_offset) { + error = gfs2_jdata_read_mem(dip, (char *)lp, + ht_offset * sizeof(uint64_t), + sdp->sd_hash_bsize); + if (error != sdp->sd_hash_bsize) { + if (error >= 0) + error = -EIO; + goto out; + } + ht_offset_cur = ht_offset; + } + + error = get_leaf(dip, be64_to_cpu(lp[lp_offset]), &bh); + if (error) + goto out; + + gfs2_leaf_in(&leaf, bh->b_data); + + if (leaf.lf_next) + error = do_filldir_multi(dip, offset, opaque, filldir, + bh, &copied); + else + error = do_filldir_single(dip, offset, opaque, filldir, + bh, leaf.lf_entries, &copied); + + brelse(bh); + + if (error) { + if (error > 0) + error = 0; + goto out; + } + + len = 1 << (dip->i_di.di_depth - leaf.lf_depth); + index = (index & ~(len - 1)) + len; + } + + out: + kfree(lp); + + return error; +} + +static int dir_e_mvino(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int new_type) +{ + struct buffer_head *bh, *dibh; + struct gfs2_dirent *dent; + int error; + + error = linked_leaf_search(dip, filename, &dent, NULL, &bh); + if (error == -ENOENT) { + gfs2_consist_inode(dip); + return -EIO; + } + if (error) + return error; + + gfs2_trans_add_bh(dip->i_gl, bh); + + gfs2_inum_out(inum, (char *)&dent->de_inum); + dent->de_type = new_type; + + brelse(bh); + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (error) + return error; + + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs2_trans_add_bh(dip->i_gl, dibh); + gfs2_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + + return 0; +} + +/** + * dir_l_search - Search linear (stuffed dinode) dir for inode matching name + * @dip: The GFS2 inode + * @filename: Filename string + * @inode: If non-NULL, function fills with formal inode # and block address + * @type: If non-NULL, function fills with DT_... dinode type + * + * Returns: + */ + +static int dir_l_search(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int *type) +{ + struct buffer_head *dibh; + struct gfs2_dirent *dent; + int error; + + if (!gfs2_is_stuffed(dip)) { + gfs2_consist_inode(dip); + return -EIO; + } + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (error) + return error; + + error = leaf_search(dip, dibh, filename, &dent, NULL); + if (!error) { + if (inum) + gfs2_inum_in(inum, (char *)&dent->de_inum); + if (type) + *type = dent->de_type; + } + + brelse(dibh); + + return error; +} + +static int dir_l_add(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int type) +{ + struct buffer_head *dibh; + struct gfs2_dirent *dent; + int error; + + if (!gfs2_is_stuffed(dip)) { + gfs2_consist_inode(dip); + return -EIO; + } + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (error) + return error; + + if (gfs2_dirent_alloc(dip, dibh, filename->len, &dent)) { + brelse(dibh); + + error = dir_make_exhash(dip); + if (!error) + error = dir_e_add(dip, filename, inum, type); + + return error; + } + + /* gfs2_dirent_alloc() pins */ + + gfs2_inum_out(inum, (char *)&dent->de_inum); + dent->de_hash = gfs2_disk_hash(filename->name, filename->len); + dent->de_hash = cpu_to_be32(dent->de_hash); + dent->de_type = type; + memcpy((char *)(dent + 1), filename->name, filename->len); + + dip->i_di.di_entries++; + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs2_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + + return 0; +} + +static int dir_l_del(struct gfs2_inode *dip, struct qstr *filename) +{ + struct buffer_head *dibh; + struct gfs2_dirent *dent, *prev; + int error; + + if (!gfs2_is_stuffed(dip)) { + gfs2_consist_inode(dip); + return -EIO; + } + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (error) + return error; + + error = leaf_search(dip, dibh, filename, &dent, &prev); + if (error == -ENOENT) { + gfs2_consist_inode(dip); + error = -EIO; + goto out; + } + if (error) + goto out; + + dirent_del(dip, dibh, prev, dent); + + /* dirent_del() pins */ + + if (!dip->i_di.di_entries) + gfs2_consist_inode(dip); + dip->i_di.di_entries--; + + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs2_dinode_out(&dip->i_di, dibh->b_data); + + out: + brelse(dibh); + + return error; +} + +static int dir_l_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, + gfs2_filldir_t filldir) +{ + struct buffer_head *dibh; + int copied = 0; + int error; + + if (!gfs2_is_stuffed(dip)) { + gfs2_consist_inode(dip); + return -EIO; + } + + if (!dip->i_di.di_entries) + return 0; + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (error) + return error; + + error = do_filldir_single(dip, offset, + opaque, filldir, + dibh, dip->i_di.di_entries, + &copied); + if (error > 0) + error = 0; + + brelse(dibh); + + return error; +} + +static int dir_l_mvino(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int new_type) +{ + struct buffer_head *dibh; + struct gfs2_dirent *dent; + int error; + + if (!gfs2_is_stuffed(dip)) { + gfs2_consist_inode(dip); + return -EIO; + } + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (error) + return error; + + error = leaf_search(dip, dibh, filename, &dent, NULL); + if (error == -ENOENT) { + gfs2_consist_inode(dip); + error = -EIO; + goto out; + } + if (error) + goto out; + + gfs2_trans_add_bh(dip->i_gl, dibh); + + gfs2_inum_out(inum, (char *)&dent->de_inum); + dent->de_type = new_type; + + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs2_dinode_out(&dip->i_di, dibh->b_data); + + out: + brelse(dibh); + + return error; +} + +/** + * gfs2_dir_search - Search a directory + * @dip: The GFS2 inode + * @filename: + * @inode: + * + * This routine searches a directory for a file or another directory. + * Assumes a glock is held on dip. + * + * Returns: errno + */ + +int gfs2_dir_search(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int *type) +{ + int error; + + if (dip->i_di.di_flags & GFS2_DIF_EXHASH) + error = dir_e_search(dip, filename, inum, type); + else + error = dir_l_search(dip, filename, inum, type); + + return error; +} + +/** + * gfs2_dir_add - Add new filename into directory + * @dip: The GFS2 inode + * @filename: The new name + * @inode: The inode number of the entry + * @type: The type of the entry + * + * Returns: 0 on success, error code on failure + */ + +int gfs2_dir_add(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int type) +{ + int error; + + if (dip->i_di.di_flags & GFS2_DIF_EXHASH) + error = dir_e_add(dip, filename, inum, type); + else + error = dir_l_add(dip, filename, inum, type); + + return error; +} + +/** + * gfs2_dir_del - Delete a directory entry + * @dip: The GFS2 inode + * @filename: The filename + * + * Returns: 0 on success, error code on failure + */ + +int gfs2_dir_del(struct gfs2_inode *dip, struct qstr *filename) +{ + int error; + + if (dip->i_di.di_flags & GFS2_DIF_EXHASH) + error = dir_e_del(dip, filename); + else + error = dir_l_del(dip, filename); + + return error; +} + +int gfs2_dir_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, + gfs2_filldir_t filldir) +{ + int error; + + if (dip->i_di.di_flags & GFS2_DIF_EXHASH) + error = dir_e_read(dip, offset, opaque, filldir); + else + error = dir_l_read(dip, offset, opaque, filldir); + + return error; +} + +/** + * gfs2_dir_mvino - Change inode number of directory entry + * @dip: The GFS2 inode + * @filename: + * @new_inode: + * + * This routine changes the inode number of a directory entry. It's used + * by rename to change ".." when a directory is moved. + * Assumes a glock is held on dvp. + * + * Returns: errno + */ + +int gfs2_dir_mvino(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int new_type) +{ + int error; + + if (dip->i_di.di_flags & GFS2_DIF_EXHASH) + error = dir_e_mvino(dip, filename, inum, new_type); + else + error = dir_l_mvino(dip, filename, inum, new_type); + + return error; +} + +/** + * foreach_leaf - call a function for each leaf in a directory + * @dip: the directory + * @lc: the function to call for each each + * @data: private data to pass to it + * + * Returns: errno + */ + +static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct buffer_head *bh; + struct gfs2_leaf leaf; + uint32_t hsize, len; + uint32_t ht_offset, lp_offset, ht_offset_cur = -1; + uint32_t index = 0; + uint64_t *lp; + uint64_t leaf_no; + int error = 0; + + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs2_consist_inode(dip); + return -EIO; + } + + lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); + if (!lp) + return -ENOMEM; + + while (index < hsize) { + lp_offset = index & (sdp->sd_hash_ptrs - 1); + ht_offset = index - lp_offset; + + if (ht_offset_cur != ht_offset) { + error = gfs2_jdata_read_mem(dip, (char *)lp, + ht_offset * sizeof(uint64_t), + sdp->sd_hash_bsize); + if (error != sdp->sd_hash_bsize) { + if (error >= 0) + error = -EIO; + goto out; + } + ht_offset_cur = ht_offset; + } + + leaf_no = be64_to_cpu(lp[lp_offset]); + if (leaf_no) { + error = get_leaf(dip, leaf_no, &bh); + if (error) + goto out; + gfs2_leaf_in(&leaf, bh->b_data); + brelse(bh); + + len = 1 << (dip->i_di.di_depth - leaf.lf_depth); + + error = lc(dip, index, len, leaf_no, data); + if (error) + goto out; + + index = (index & ~(len - 1)) + len; + } else + index++; + } + + if (index != hsize) { + gfs2_consist_inode(dip); + error = -EIO; + } + + out: + kfree(lp); + + return error; +} + +/** + * leaf_dealloc - Deallocate a directory leaf + * @dip: the directory + * @index: the hash table offset in the directory + * @len: the number of pointers to this leaf + * @leaf_no: the leaf number + * @data: not used + * + * Returns: errno + */ + +static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, + uint64_t leaf_no, void *data) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_leaf tmp_leaf; + struct gfs2_rgrp_list rlist; + struct buffer_head *bh, *dibh; + uint64_t blk; + unsigned int rg_blocks = 0, l_blocks = 0; + char *ht; + unsigned int x, size = len * sizeof(uint64_t); + int error; + + memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); + + ht = kzalloc(size, GFP_KERNEL); + if (!ht) + return -ENOMEM; + + gfs2_alloc_get(dip); + + error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh); + if (error) + goto out_qs; + + /* Count the number of leaves */ + + for (blk = leaf_no; blk; blk = tmp_leaf.lf_next) { + error = get_leaf(dip, blk, &bh); + if (error) + goto out_rlist; + gfs2_leaf_in(&tmp_leaf, (bh)->b_data); + brelse(bh); + + gfs2_rlist_add(sdp, &rlist, blk); + l_blocks++; + } + + gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); + + for (x = 0; x < rlist.rl_rgrps; x++) { + struct gfs2_rgrpd *rgd; + rgd = get_gl2rgd(rlist.rl_ghs[x].gh_gl); + rg_blocks += rgd->rd_ri.ri_length; + } + + error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs); + if (error) + goto out_rlist; + + error = gfs2_trans_begin(sdp, + rg_blocks + (DIV_RU(size, sdp->sd_jbsize) + 1) + + RES_DINODE + RES_STATFS + RES_QUOTA, l_blocks); + if (error) + goto out_rg_gunlock; + + for (blk = leaf_no; blk; blk = tmp_leaf.lf_next) { + error = get_leaf(dip, blk, &bh); + if (error) + goto out_end_trans; + gfs2_leaf_in(&tmp_leaf, bh->b_data); + brelse(bh); + + gfs2_free_meta(dip, blk, 1); + + if (!dip->i_di.di_blocks) + gfs2_consist_inode(dip); + dip->i_di.di_blocks--; + } + + error = gfs2_jdata_write_mem(dip, ht, index * sizeof(uint64_t), size); + if (error != size) { + if (error >= 0) + error = -EIO; + goto out_end_trans; + } + + error = gfs2_meta_inode_buffer(dip, &dibh); + if (error) + goto out_end_trans; + + gfs2_trans_add_bh(dip->i_gl, dibh); + gfs2_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + + out_end_trans: + gfs2_trans_end(sdp); + + out_rg_gunlock: + gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); + + out_rlist: + gfs2_rlist_free(&rlist); + gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh); + + out_qs: + gfs2_quota_unhold(dip); + + out: + gfs2_alloc_put(dip); + kfree(ht); + + return error; +} + +/** + * gfs2_dir_exhash_dealloc - free all the leaf blocks in a directory + * @dip: the directory + * + * Dealloc all on-disk directory leaves to FREEMETA state + * Change on-disk inode type to "regular file" + * + * Returns: errno + */ + +int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct buffer_head *bh; + int error; + + /* Dealloc on-disk leaves to FREEMETA state */ + error = foreach_leaf(dip, leaf_dealloc, NULL); + if (error) + return error; + + /* Make this a regular file in case we crash. + (We don't want to free these blocks a second time.) */ + + error = gfs2_trans_begin(sdp, RES_DINODE, 0); + if (error) + return error; + + error = gfs2_meta_inode_buffer(dip, &bh); + if (!error) { + gfs2_trans_add_bh(dip->i_gl, bh); + ((struct gfs2_dinode *)bh->b_data)->di_mode = cpu_to_be32(S_IFREG); + brelse(bh); + } + + gfs2_trans_end(sdp); + + return error; +} + +/** + * gfs2_diradd_alloc_required - find if adding entry will require an allocation + * @ip: the file being written to + * @filname: the filename that's going to be added + * @alloc_required: set to 1 if an alloc is required, 0 otherwise + * + * Returns: errno + */ + +int gfs2_diradd_alloc_required(struct gfs2_inode *dip, struct qstr *filename, + int *alloc_required) +{ + struct buffer_head *bh = NULL, *bh_next; + uint32_t hsize, hash, index; + int error = 0; + + *alloc_required = 0; + + if (dip->i_di.di_flags & GFS2_DIF_EXHASH) { + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs2_consist_inode(dip); + return -EIO; + } + + hash = gfs2_disk_hash(filename->name, filename->len); + index = hash >> (32 - dip->i_di.di_depth); + + error = get_first_leaf(dip, index, &bh_next); + if (error) + return error; + + do { + brelse(bh); + + bh = bh_next; + + if (dirent_fits(dip, bh, filename->len)) + break; + + error = get_next_leaf(dip, bh, &bh_next); + if (error == -ENOENT) { + *alloc_required = 1; + error = 0; + break; + } + } + while (!error); + + brelse(bh); + } else { + error = gfs2_meta_inode_buffer(dip, &bh); + if (error) + return error; + + if (!dirent_fits(dip, bh, filename->len)) + *alloc_required = 1; + + brelse(bh); + } + + return error; +} + +/** + * do_gdm - copy out one leaf (or list of leaves) + * @dip: the directory + * @index: the hash table offset in the directory + * @len: the number of pointers to this leaf + * @leaf_no: the leaf number + * @data: a pointer to a struct gfs2_user_buffer structure + * + * Returns: errno + */ + +static int do_gdm(struct gfs2_inode *dip, uint32_t index, uint32_t len, + uint64_t leaf_no, void *data) +{ + struct gfs2_user_buffer *ub = (struct gfs2_user_buffer *)data; + struct gfs2_leaf leaf; + struct buffer_head *bh; + uint64_t blk; + int error = 0; + + for (blk = leaf_no; blk; blk = leaf.lf_next) { + error = get_leaf(dip, blk, &bh); + if (error) + break; + + gfs2_leaf_in(&leaf, bh->b_data); + + error = gfs2_add_bh_to_ub(ub, bh); + + brelse(bh); + + if (error) + break; + } + + return error; +} + +/** + * gfs2_get_dir_meta - return all the leaf blocks of a directory + * @dip: the directory + * @ub: the structure representing the meta + * + * Returns: errno + */ + +int gfs2_get_dir_meta(struct gfs2_inode *dip, struct gfs2_user_buffer *ub) +{ + return foreach_leaf(dip, do_gdm, ub); +} + diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h new file mode 100644 index 000000000000..79f77aab4264 --- /dev/null +++ b/fs/gfs2/dir.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __DIR_DOT_H__ +#define __DIR_DOT_H__ + +/** + * gfs2_filldir_t - Report a directory entry to the caller of gfs2_dir_read() + * @opaque: opaque data used by the function + * @name: the name of the directory entry + * @length: the length of the name + * @offset: the entry's offset in the directory + * @inum: the inode number the entry points to + * @type: the type of inode the entry points to + * + * Returns: 0 on success, 1 if buffer full + */ + +typedef int (*gfs2_filldir_t) (void *opaque, + const char *name, unsigned int length, + uint64_t offset, + struct gfs2_inum *inum, unsigned int type); + +int gfs2_filecmp(struct qstr *file1, char *file2, int len_of_file2); +int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, + int name_len, struct gfs2_dirent **dent_out); + +int gfs2_dir_search(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int *type); +int gfs2_dir_add(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *inum, unsigned int type); +int gfs2_dir_del(struct gfs2_inode *dip, struct qstr *filename); +int gfs2_dir_read(struct gfs2_inode *dip, uint64_t * offset, void *opaque, + gfs2_filldir_t filldir); +int gfs2_dir_mvino(struct gfs2_inode *dip, struct qstr *filename, + struct gfs2_inum *new_inum, unsigned int new_type); + +int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip); + +int gfs2_diradd_alloc_required(struct gfs2_inode *dip, struct qstr *filename, + int *alloc_required); + +int gfs2_get_dir_meta(struct gfs2_inode *ip, struct gfs2_user_buffer *ub); + +#endif /* __DIR_DOT_H__ */ diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c new file mode 100644 index 000000000000..2914731250c5 --- /dev/null +++ b/fs/gfs2/eaops.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "acl.h" +#include "eaops.h" +#include "eattr.h" + +/** + * gfs2_ea_name2type - get the type of the ea, and truncate type from the name + * @namep: ea name, possibly with type appended + * + * Returns: GFS2_EATYPE_XXX + */ + +unsigned int gfs2_ea_name2type(const char *name, char **truncated_name) +{ + unsigned int type; + + if (strncmp(name, "system.", 7) == 0) { + type = GFS2_EATYPE_SYS; + if (truncated_name) + *truncated_name = strchr(name, '.') + 1; + } else if (strncmp(name, "user.", 5) == 0) { + type = GFS2_EATYPE_USR; + if (truncated_name) + *truncated_name = strchr(name, '.') + 1; + } else { + type = GFS2_EATYPE_UNUSED; + if (truncated_name) + *truncated_name = NULL; + } + + return type; +} + +static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct inode *inode = ip->i_vnode; + int error = permission(inode, MAY_READ, NULL); + if (error) + return error; + + return gfs2_ea_get_i(ip, er); +} + +static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct inode *inode = ip->i_vnode; + + if (S_ISREG(inode->i_mode) || + (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) { + int error = permission(inode, MAY_WRITE, NULL); + if (error) + return error; + } else + return -EPERM; + + return gfs2_ea_set_i(ip, er); +} + +static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct inode *inode = ip->i_vnode; + + if (S_ISREG(inode->i_mode) || + (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) { + int error = permission(inode, MAY_WRITE, NULL); + if (error) + return error; + } else + return -EPERM; + + return gfs2_ea_remove_i(ip, er); +} + +static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) && + !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (ip->i_sbd->sd_args.ar_posix_acl == 0 && + (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) || + GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len))) + return -EOPNOTSUPP; + + + + return gfs2_ea_get_i(ip, er); +} + +static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + int remove = 0; + int error; + + if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { + if (!(er->er_flags & GFS2_ERF_MODE)) { + er->er_mode = ip->i_di.di_mode; + er->er_flags |= GFS2_ERF_MODE; + } + error = gfs2_acl_validate_set(ip, 1, er, + &remove, &er->er_mode); + if (error) + return error; + error = gfs2_ea_set_i(ip, er); + if (error) + return error; + if (remove) + gfs2_ea_remove_i(ip, er); + return 0; + + } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) { + error = gfs2_acl_validate_set(ip, 0, er, + &remove, NULL); + if (error) + return error; + if (!remove) + error = gfs2_ea_set_i(ip, er); + else { + error = gfs2_ea_remove_i(ip, er); + if (error == -ENODATA) + error = 0; + } + return error; + } + + return -EPERM; +} + +static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { + int error = gfs2_acl_validate_remove(ip, 1); + if (error) + return error; + + } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) { + int error = gfs2_acl_validate_remove(ip, 0); + if (error) + return error; + + } else + return -EPERM; + + return gfs2_ea_remove_i(ip, er); +} + +struct gfs2_eattr_operations gfs2_user_eaops = { + .eo_get = user_eo_get, + .eo_set = user_eo_set, + .eo_remove = user_eo_remove, + .eo_name = "user", +}; + +struct gfs2_eattr_operations gfs2_system_eaops = { + .eo_get = system_eo_get, + .eo_set = system_eo_set, + .eo_remove = system_eo_remove, + .eo_name = "system", +}; + +struct gfs2_eattr_operations *gfs2_ea_ops[] = { + NULL, + &gfs2_user_eaops, + &gfs2_system_eaops, +}; + diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h new file mode 100644 index 000000000000..f83c497eddca --- /dev/null +++ b/fs/gfs2/eaops.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __EAOPS_DOT_H__ +#define __EAOPS_DOT_H__ + +struct gfs2_ea_request; + +struct gfs2_eattr_operations { + int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er); + int (*eo_set) (struct gfs2_inode *ip, struct gfs2_ea_request *er); + int (*eo_remove) (struct gfs2_inode *ip, struct gfs2_ea_request *er); + char *eo_name; +}; + +unsigned int gfs2_ea_name2type(const char *name, char **truncated_name); + +extern struct gfs2_eattr_operations gfs2_user_eaops; +extern struct gfs2_eattr_operations gfs2_system_eaops; + +extern struct gfs2_eattr_operations *gfs2_ea_ops[]; + +#endif /* __EAOPS_DOT_H__ */ + diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c new file mode 100644 index 000000000000..63a5cf1e2472 --- /dev/null +++ b/fs/gfs2/eattr.c @@ -0,0 +1,1620 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "acl.h" +#include "eaops.h" +#include "eattr.h" +#include "glock.h" +#include "inode.h" +#include "meta_io.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" + +/** + * ea_calc_size - returns the acutal number of bytes the request will take up + * (not counting any unstuffed data blocks) + * @sdp: + * @er: + * @size: + * + * Returns: 1 if the EA should be stuffed + */ + +static int ea_calc_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er, + unsigned int *size) +{ + *size = GFS2_EAREQ_SIZE_STUFFED(er); + if (*size <= sdp->sd_jbsize) + return 1; + + *size = GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er); + + return 0; +} + +static int ea_check_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er) +{ + unsigned int size; + + if (er->er_data_len > GFS2_EA_MAX_DATA_LEN) + return -ERANGE; + + ea_calc_size(sdp, er, &size); + + /* This can only happen with 512 byte blocks */ + if (size > sdp->sd_jbsize) + return -ERANGE; + + return 0; +} + +typedef int (*ea_call_t) (struct gfs2_inode *ip, + struct buffer_head *bh, + struct gfs2_ea_header *ea, + struct gfs2_ea_header *prev, + void *private); + +static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh, + ea_call_t ea_call, void *data) +{ + struct gfs2_ea_header *ea, *prev = NULL; + int error = 0; + + if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_EA)) + return -EIO; + + for (ea = GFS2_EA_BH2FIRST(bh);; prev = ea, ea = GFS2_EA2NEXT(ea)) { + if (!GFS2_EA_REC_LEN(ea)) + goto fail; + if (!(bh->b_data <= (char *)ea && + (char *)GFS2_EA2NEXT(ea) <= + bh->b_data + bh->b_size)) + goto fail; + if (!GFS2_EATYPE_VALID(ea->ea_type)) + goto fail; + + error = ea_call(ip, bh, ea, prev, data); + if (error) + return error; + + if (GFS2_EA_IS_LAST(ea)) { + if ((char *)GFS2_EA2NEXT(ea) != + bh->b_data + bh->b_size) + goto fail; + break; + } + } + + return error; + + fail: + gfs2_consist_inode(ip); + return -EIO; +} + +static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) +{ + struct buffer_head *bh, *eabh; + uint64_t *eablk, *end; + int error; + + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, + DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT)) { + error = ea_foreach_i(ip, bh, ea_call, data); + goto out; + } + + if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_IN)) { + error = -EIO; + goto out; + } + + eablk = (uint64_t *)(bh->b_data + sizeof(struct gfs2_meta_header)); + end = eablk + ip->i_sbd->sd_inptrs; + + for (; eablk < end; eablk++) { + uint64_t bn; + + if (!*eablk) + break; + bn = be64_to_cpu(*eablk); + + error = gfs2_meta_read(ip->i_gl, bn, DIO_START | DIO_WAIT, + &eabh); + if (error) + break; + error = ea_foreach_i(ip, eabh, ea_call, data); + brelse(eabh); + if (error) + break; + } + out: + brelse(bh); + + return error; +} + +struct ea_find { + struct gfs2_ea_request *ef_er; + struct gfs2_ea_location *ef_el; +}; + +static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, + struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, + void *private) +{ + struct ea_find *ef = private; + struct gfs2_ea_request *er = ef->ef_er; + + if (ea->ea_type == GFS2_EATYPE_UNUSED) + return 0; + + if (ea->ea_type == er->er_type) { + if (ea->ea_name_len == er->er_name_len && + !memcmp(GFS2_EA2NAME(ea), er->er_name, ea->ea_name_len)) { + struct gfs2_ea_location *el = ef->ef_el; + get_bh(bh); + el->el_bh = bh; + el->el_ea = ea; + el->el_prev = prev; + return 1; + } + } + +#if 0 + else if ((ip->i_di.di_flags & GFS2_DIF_EA_PACKED) && + er->er_type == GFS2_EATYPE_SYS) + return 1; +#endif + + return 0; +} + +int gfs2_ea_find(struct gfs2_inode *ip, struct gfs2_ea_request *er, + struct gfs2_ea_location *el) +{ + struct ea_find ef; + int error; + + ef.ef_er = er; + ef.ef_el = el; + + memset(el, 0, sizeof(struct gfs2_ea_location)); + + error = ea_foreach(ip, ea_find_i, &ef); + if (error > 0) + return 0; + + return error; +} + +/** + * ea_dealloc_unstuffed - + * @ip: + * @bh: + * @ea: + * @prev: + * @private: + * + * Take advantage of the fact that all unstuffed blocks are + * allocated from the same RG. But watch, this may not always + * be true. + * + * Returns: errno + */ + +static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, + struct gfs2_ea_header *ea, + struct gfs2_ea_header *prev, void *private) +{ + int *leave = private; + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_rgrpd *rgd; + struct gfs2_holder rg_gh; + struct buffer_head *dibh; + uint64_t *dataptrs, bn = 0; + uint64_t bstart = 0; + unsigned int blen = 0; + unsigned int blks = 0; + unsigned int x; + int error; + + if (GFS2_EA_IS_STUFFED(ea)) + return 0; + + dataptrs = GFS2_EA2DATAPTRS(ea); + for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) + if (*dataptrs) { + blks++; + bn = be64_to_cpu(*dataptrs); + } + if (!blks) + return 0; + + rgd = gfs2_blk2rgrpd(sdp, bn); + if (!rgd) { + gfs2_consist_inode(ip); + return -EIO; + } + + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh); + if (error) + return error; + + error = gfs2_trans_begin(sdp, rgd->rd_ri.ri_length + + RES_DINODE + RES_EATTR + RES_STATFS + + RES_QUOTA, blks); + if (error) + goto out_gunlock; + + gfs2_trans_add_bh(ip->i_gl, bh); + + dataptrs = GFS2_EA2DATAPTRS(ea); + for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) { + if (!*dataptrs) + break; + bn = be64_to_cpu(*dataptrs); + + if (bstart + blen == bn) + blen++; + else { + if (bstart) + gfs2_free_meta(ip, bstart, blen); + bstart = bn; + blen = 1; + } + + *dataptrs = 0; + if (!ip->i_di.di_blocks) + gfs2_consist_inode(ip); + ip->i_di.di_blocks--; + } + if (bstart) + gfs2_free_meta(ip, bstart, blen); + + if (prev && !leave) { + uint32_t len; + + len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea); + prev->ea_rec_len = cpu_to_be32(len); + + if (GFS2_EA_IS_LAST(ea)) + prev->ea_flags |= GFS2_EAFLAG_LAST; + } else { + ea->ea_type = GFS2_EATYPE_UNUSED; + ea->ea_num_ptrs = 0; + } + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + ip->i_di.di_ctime = get_seconds(); + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs2_trans_end(sdp); + + out_gunlock: + gfs2_glock_dq_uninit(&rg_gh); + + return error; +} + +static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, + struct gfs2_ea_header *ea, + struct gfs2_ea_header *prev, int leave) +{ + struct gfs2_alloc *al; + int error; + + al = gfs2_alloc_get(ip); + + error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out_alloc; + + error = gfs2_rindex_hold(ip->i_sbd, &al->al_ri_gh); + if (error) + goto out_quota; + + error = ea_dealloc_unstuffed(ip, + bh, ea, prev, + (leave) ? &error : NULL); + + gfs2_glock_dq_uninit(&al->al_ri_gh); + + out_quota: + gfs2_quota_unhold(ip); + + out_alloc: + gfs2_alloc_put(ip); + + return error; +} + +/******************************************************************************/ + +static int gfs2_ea_repack_i(struct gfs2_inode *ip) +{ + return -EOPNOTSUPP; +} + +int gfs2_ea_repack(struct gfs2_inode *ip) +{ + struct gfs2_holder gh; + int error; + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + if (error) + return error; + + /* Some sort of permissions checking would be nice */ + + error = gfs2_ea_repack_i(ip); + + gfs2_glock_dq_uninit(&gh); + + return error; +} + +struct ea_list { + struct gfs2_ea_request *ei_er; + unsigned int ei_size; +}; + +static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, + struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, + void *private) +{ + struct ea_list *ei = private; + struct gfs2_ea_request *er = ei->ei_er; + unsigned int ea_size = GFS2_EA_STRLEN(ea); + + if (ea->ea_type == GFS2_EATYPE_UNUSED) + return 0; + + if (er->er_data_len) { + char *prefix; + unsigned int l; + char c = 0; + + if (ei->ei_size + ea_size > er->er_data_len) + return -ERANGE; + + if (ea->ea_type == GFS2_EATYPE_USR) { + prefix = "user."; + l = 5; + } else { + prefix = "system."; + l = 7; + } + + memcpy(er->er_data + ei->ei_size, + prefix, l); + memcpy(er->er_data + ei->ei_size + l, + GFS2_EA2NAME(ea), + ea->ea_name_len); + memcpy(er->er_data + ei->ei_size + + ea_size - 1, + &c, 1); + } + + ei->ei_size += ea_size; + + return 0; +} + +/** + * gfs2_ea_list - + * @ip: + * @er: + * + * Returns: actual size of data on success, -errno on error + */ + +int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct gfs2_holder i_gh; + int error; + + if (!er->er_data || !er->er_data_len) { + er->er_data = NULL; + er->er_data_len = 0; + } + + error = gfs2_glock_nq_init(ip->i_gl, + LM_ST_SHARED, LM_FLAG_ANY, + &i_gh); + if (error) + return error; + + if (ip->i_di.di_eattr) { + struct ea_list ei = { .ei_er = er, .ei_size = 0 }; + + error = ea_foreach(ip, ea_list_i, &ei); + if (!error) + error = ei.ei_size; + } + + gfs2_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * ea_get_unstuffed - actually copies the unstuffed data into the + * request buffer + * @ip: + * @ea: + * @data: + * + * Returns: errno + */ + +static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, + char *data) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head **bh; + unsigned int amount = GFS2_EA_DATA_LEN(ea); + unsigned int nptrs = DIV_RU(amount, sdp->sd_jbsize); + uint64_t *dataptrs = GFS2_EA2DATAPTRS(ea); + unsigned int x; + int error = 0; + + bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL); + if (!bh) + return -ENOMEM; + + for (x = 0; x < nptrs; x++) { + error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), + DIO_START, bh + x); + if (error) { + while (x--) + brelse(bh[x]); + goto out; + } + dataptrs++; + } + + for (x = 0; x < nptrs; x++) { + error = gfs2_meta_reread(sdp, bh[x], DIO_WAIT); + if (error) { + for (; x < nptrs; x++) + brelse(bh[x]); + goto out; + } + if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) { + for (; x < nptrs; x++) + brelse(bh[x]); + error = -EIO; + goto out; + } + + memcpy(data, + bh[x]->b_data + sizeof(struct gfs2_meta_header), + (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize); + + amount -= sdp->sd_jbsize; + data += sdp->sd_jbsize; + + brelse(bh[x]); + } + + out: + kfree(bh); + + return error; +} + +int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, + char *data) +{ + if (GFS2_EA_IS_STUFFED(el->el_ea)) { + memcpy(data, + GFS2_EA2DATA(el->el_ea), + GFS2_EA_DATA_LEN(el->el_ea)); + return 0; + } else + return ea_get_unstuffed(ip, el->el_ea, data); +} + +/** + * gfs2_ea_get_i - + * @ip: + * @er: + * + * Returns: actual size of data on success, -errno on error + */ + +int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct gfs2_ea_location el; + int error; + + if (!ip->i_di.di_eattr) + return -ENODATA; + + error = gfs2_ea_find(ip, er, &el); + if (error) + return error; + if (!el.el_ea) + return -ENODATA; + + if (er->er_data_len) { + if (GFS2_EA_DATA_LEN(el.el_ea) > er->er_data_len) + error = -ERANGE; + else + error = gfs2_ea_get_copy(ip, &el, er->er_data); + } + if (!error) + error = GFS2_EA_DATA_LEN(el.el_ea); + + brelse(el.el_bh); + + return error; +} + +/** + * gfs2_ea_get - + * @ip: + * @er: + * + * Returns: actual size of data on success, -errno on error + */ + +int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct gfs2_holder i_gh; + int error; + + if (!er->er_name_len || + er->er_name_len > GFS2_EA_MAX_NAME_LEN) + return -EINVAL; + if (!er->er_data || !er->er_data_len) { + er->er_data = NULL; + er->er_data_len = 0; + } + + error = gfs2_glock_nq_init(ip->i_gl, + LM_ST_SHARED, LM_FLAG_ANY, + &i_gh); + if (error) + return error; + + error = gfs2_ea_ops[er->er_type]->eo_get(ip, er); + + gfs2_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * ea_alloc_blk - allocates a new block for extended attributes. + * @ip: A pointer to the inode that's getting extended attributes + * @bhp: + * + * Returns: errno + */ + +static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_ea_header *ea; + uint64_t block; + + block = gfs2_alloc_meta(ip); + + *bhp = gfs2_meta_new(ip->i_gl, block); + gfs2_trans_add_bh(ip->i_gl, *bhp); + gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA); + gfs2_buffer_clear_tail(*bhp, sizeof(struct gfs2_meta_header)); + + ea = GFS2_EA_BH2FIRST(*bhp); + ea->ea_rec_len = cpu_to_be32(sdp->sd_jbsize); + ea->ea_type = GFS2_EATYPE_UNUSED; + ea->ea_flags = GFS2_EAFLAG_LAST; + ea->ea_num_ptrs = 0; + + ip->i_di.di_blocks++; + + return 0; +} + +/** + * ea_write - writes the request info to an ea, creating new blocks if + * necessary + * @ip: inode that is being modified + * @ea: the location of the new ea in a block + * @er: the write request + * + * Note: does not update ea_rec_len or the GFS2_EAFLAG_LAST bin of ea_flags + * + * returns : errno + */ + +static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, + struct gfs2_ea_request *er) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + + ea->ea_data_len = cpu_to_be32(er->er_data_len); + ea->ea_name_len = er->er_name_len; + ea->ea_type = er->er_type; + ea->__pad = 0; + + memcpy(GFS2_EA2NAME(ea), er->er_name, er->er_name_len); + + if (GFS2_EAREQ_SIZE_STUFFED(er) <= sdp->sd_jbsize) { + ea->ea_num_ptrs = 0; + memcpy(GFS2_EA2DATA(ea), er->er_data, er->er_data_len); + } else { + uint64_t *dataptr = GFS2_EA2DATAPTRS(ea); + const char *data = er->er_data; + unsigned int data_len = er->er_data_len; + unsigned int copy; + unsigned int x; + + ea->ea_num_ptrs = DIV_RU(er->er_data_len, sdp->sd_jbsize); + for (x = 0; x < ea->ea_num_ptrs; x++) { + struct buffer_head *bh; + uint64_t block; + int mh_size = sizeof(struct gfs2_meta_header); + + block = gfs2_alloc_meta(ip); + + bh = gfs2_meta_new(ip->i_gl, block); + gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED); + + ip->i_di.di_blocks++; + + copy = (data_len > sdp->sd_jbsize) ? sdp->sd_jbsize : + data_len; + memcpy(bh->b_data + mh_size, data, copy); + if (copy < sdp->sd_jbsize) + memset(bh->b_data + mh_size + copy, 0, + sdp->sd_jbsize - copy); + + *dataptr++ = cpu_to_be64((uint64_t)bh->b_blocknr); + data += copy; + data_len -= copy; + + brelse(bh); + } + + gfs2_assert_withdraw(sdp, !data_len); + } + + return 0; +} + +typedef int (*ea_skeleton_call_t) (struct gfs2_inode *ip, + struct gfs2_ea_request *er, + void *private); + +static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, + unsigned int blks, + ea_skeleton_call_t skeleton_call, + void *private) +{ + struct gfs2_alloc *al; + struct buffer_head *dibh; + int error; + + al = gfs2_alloc_get(ip); + + error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto out_gunlock_q; + + al->al_requested = blks; + + error = gfs2_inplace_reserve(ip); + if (error) + goto out_gunlock_q; + + error = gfs2_trans_begin(ip->i_sbd, + blks + al->al_rgd->rd_ri.ri_length + + RES_DINODE + RES_STATFS + RES_QUOTA, 0); + if (error) + goto out_ipres; + + error = skeleton_call(ip, er, private); + if (error) + goto out_end_trans; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + if (er->er_flags & GFS2_ERF_MODE) { + gfs2_assert_withdraw(ip->i_sbd, + (ip->i_di.di_mode & S_IFMT) == + (er->er_mode & S_IFMT)); + ip->i_di.di_mode = er->er_mode; + } + ip->i_di.di_ctime = get_seconds(); + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + out_end_trans: + gfs2_trans_end(ip->i_sbd); + + out_ipres: + gfs2_inplace_release(ip); + + out_gunlock_q: + gfs2_quota_unlock(ip); + + out: + gfs2_alloc_put(ip); + + return error; +} + +static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, + void *private) +{ + struct buffer_head *bh; + int error; + + error = ea_alloc_blk(ip, &bh); + if (error) + return error; + + ip->i_di.di_eattr = bh->b_blocknr; + error = ea_write(ip, GFS2_EA_BH2FIRST(bh), er); + + brelse(bh); + + return error; +} + +/** + * ea_init - initializes a new eattr block + * @ip: + * @er: + * + * Returns: errno + */ + +static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + unsigned int jbsize = ip->i_sbd->sd_jbsize; + unsigned int blks = 1; + + if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize) + blks += DIV_RU(er->er_data_len, jbsize); + + return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL); +} + +static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) +{ + uint32_t ea_size = GFS2_EA_SIZE(ea); + struct gfs2_ea_header *new = (struct gfs2_ea_header *)((char *)ea + ea_size); + uint32_t new_size = GFS2_EA_REC_LEN(ea) - ea_size; + int last = ea->ea_flags & GFS2_EAFLAG_LAST; + + ea->ea_rec_len = cpu_to_be32(ea_size); + ea->ea_flags ^= last; + + new->ea_rec_len = cpu_to_be32(new_size); + new->ea_flags = last; + + return new; +} + +static void ea_set_remove_stuffed(struct gfs2_inode *ip, + struct gfs2_ea_location *el) +{ + struct gfs2_ea_header *ea = el->el_ea; + struct gfs2_ea_header *prev = el->el_prev; + uint32_t len; + + gfs2_trans_add_bh(ip->i_gl, el->el_bh); + + if (!prev || !GFS2_EA_IS_STUFFED(ea)) { + ea->ea_type = GFS2_EATYPE_UNUSED; + return; + } else if (GFS2_EA2NEXT(prev) != ea) { + prev = GFS2_EA2NEXT(prev); + gfs2_assert_withdraw(ip->i_sbd, GFS2_EA2NEXT(prev) == ea); + } + + len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea); + prev->ea_rec_len = cpu_to_be32(len); + + if (GFS2_EA_IS_LAST(ea)) + prev->ea_flags |= GFS2_EAFLAG_LAST; +} + +struct ea_set { + int ea_split; + + struct gfs2_ea_request *es_er; + struct gfs2_ea_location *es_el; + + struct buffer_head *es_bh; + struct gfs2_ea_header *es_ea; +}; + +static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, + struct gfs2_ea_header *ea, struct ea_set *es) +{ + struct gfs2_ea_request *er = es->es_er; + struct buffer_head *dibh; + int error; + + error = gfs2_trans_begin(ip->i_sbd, RES_DINODE + 2 * RES_EATTR, 0); + if (error) + return error; + + gfs2_trans_add_bh(ip->i_gl, bh); + + if (es->ea_split) + ea = ea_split_ea(ea); + + ea_write(ip, ea, er); + + if (es->es_el) + ea_set_remove_stuffed(ip, es->es_el); + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out; + + if (er->er_flags & GFS2_ERF_MODE) { + gfs2_assert_withdraw(ip->i_sbd, + (ip->i_di.di_mode & S_IFMT) == (er->er_mode & S_IFMT)); + ip->i_di.di_mode = er->er_mode; + } + ip->i_di.di_ctime = get_seconds(); + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + out: + gfs2_trans_end(ip->i_sbd); + + return error; +} + +static int ea_set_simple_alloc(struct gfs2_inode *ip, + struct gfs2_ea_request *er, void *private) +{ + struct ea_set *es = private; + struct gfs2_ea_header *ea = es->es_ea; + int error; + + gfs2_trans_add_bh(ip->i_gl, es->es_bh); + + if (es->ea_split) + ea = ea_split_ea(ea); + + error = ea_write(ip, ea, er); + if (error) + return error; + + if (es->es_el) + ea_set_remove_stuffed(ip, es->es_el); + + return 0; +} + +static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, + struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, + void *private) +{ + struct ea_set *es = private; + unsigned int size; + int stuffed; + int error; + + stuffed = ea_calc_size(ip->i_sbd, es->es_er, &size); + + if (ea->ea_type == GFS2_EATYPE_UNUSED) { + if (GFS2_EA_REC_LEN(ea) < size) + return 0; + if (!GFS2_EA_IS_STUFFED(ea)) { + error = ea_remove_unstuffed(ip, bh, ea, prev, 1); + if (error) + return error; + } + es->ea_split = 0; + } else if (GFS2_EA_REC_LEN(ea) - GFS2_EA_SIZE(ea) >= size) + es->ea_split = 1; + else + return 0; + + if (stuffed) { + error = ea_set_simple_noalloc(ip, bh, ea, es); + if (error) + return error; + } else { + unsigned int blks; + + es->es_bh = bh; + es->es_ea = ea; + blks = 2 + DIV_RU(es->es_er->er_data_len, ip->i_sbd->sd_jbsize); + + error = ea_alloc_skeleton(ip, es->es_er, blks, + ea_set_simple_alloc, es); + if (error) + return error; + } + + return 1; +} + +static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, + void *private) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head *indbh, *newbh; + uint64_t *eablk; + int error; + int mh_size = sizeof(struct gfs2_meta_header); + + if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) { + uint64_t *end; + + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, + DIO_START | DIO_WAIT, &indbh); + if (error) + return error; + + if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) { + error = -EIO; + goto out; + } + + eablk = (uint64_t *)(indbh->b_data + mh_size); + end = eablk + sdp->sd_inptrs; + + for (; eablk < end; eablk++) + if (!*eablk) + break; + + if (eablk == end) { + error = -ENOSPC; + goto out; + } + + gfs2_trans_add_bh(ip->i_gl, indbh); + } else { + uint64_t blk; + + blk = gfs2_alloc_meta(ip); + + indbh = gfs2_meta_new(ip->i_gl, blk); + gfs2_trans_add_bh(ip->i_gl, indbh); + gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); + gfs2_buffer_clear_tail(indbh, mh_size); + + eablk = (uint64_t *)(indbh->b_data + mh_size); + *eablk = cpu_to_be64(ip->i_di.di_eattr); + ip->i_di.di_eattr = blk; + ip->i_di.di_flags |= GFS2_DIF_EA_INDIRECT; + ip->i_di.di_blocks++; + + eablk++; + } + + error = ea_alloc_blk(ip, &newbh); + if (error) + goto out; + + *eablk = cpu_to_be64((uint64_t)newbh->b_blocknr); + error = ea_write(ip, GFS2_EA_BH2FIRST(newbh), er); + brelse(newbh); + if (error) + goto out; + + if (private) + ea_set_remove_stuffed(ip, (struct gfs2_ea_location *)private); + + out: + brelse(indbh); + + return error; +} + +static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, + struct gfs2_ea_location *el) +{ + struct ea_set es; + unsigned int blks = 2; + int error; + + memset(&es, 0, sizeof(struct ea_set)); + es.es_er = er; + es.es_el = el; + + error = ea_foreach(ip, ea_set_simple, &es); + if (error > 0) + return 0; + if (error) + return error; + + if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT)) + blks++; + if (GFS2_EAREQ_SIZE_STUFFED(er) > ip->i_sbd->sd_jbsize) + blks += DIV_RU(er->er_data_len, ip->i_sbd->sd_jbsize); + + return ea_alloc_skeleton(ip, er, blks, ea_set_block, el); +} + +static int ea_set_remove_unstuffed(struct gfs2_inode *ip, + struct gfs2_ea_location *el) +{ + if (el->el_prev && GFS2_EA2NEXT(el->el_prev) != el->el_ea) { + el->el_prev = GFS2_EA2NEXT(el->el_prev); + gfs2_assert_withdraw(ip->i_sbd, + GFS2_EA2NEXT(el->el_prev) == el->el_ea); + } + + return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0); +} + +int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct gfs2_ea_location el; + int error; + + if (!ip->i_di.di_eattr) { + if (er->er_flags & XATTR_REPLACE) + return -ENODATA; + return ea_init(ip, er); + } + + error = gfs2_ea_find(ip, er, &el); + if (error) + return error; + + if (el.el_ea) { + if (ip->i_di.di_flags & GFS2_DIF_APPENDONLY) { + brelse(el.el_bh); + return -EPERM; + } + + error = -EEXIST; + if (!(er->er_flags & XATTR_CREATE)) { + int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); + error = ea_set_i(ip, er, &el); + if (!error && unstuffed) + ea_set_remove_unstuffed(ip, &el); + } + + brelse(el.el_bh); + } else { + error = -ENODATA; + if (!(er->er_flags & XATTR_REPLACE)) + error = ea_set_i(ip, er, NULL); + } + + return error; +} + +int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct gfs2_holder i_gh; + int error; + + if (!er->er_name_len || + er->er_name_len > GFS2_EA_MAX_NAME_LEN) + return -EINVAL; + if (!er->er_data || !er->er_data_len) { + er->er_data = NULL; + er->er_data_len = 0; + } + error = ea_check_size(ip->i_sbd, er); + if (error) + return error; + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + return error; + + if (IS_IMMUTABLE(ip->i_vnode)) + error = -EPERM; + else + error = gfs2_ea_ops[er->er_type]->eo_set(ip, er); + + gfs2_glock_dq_uninit(&i_gh); + + return error; +} + +static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) +{ + struct gfs2_ea_header *ea = el->el_ea; + struct gfs2_ea_header *prev = el->el_prev; + struct buffer_head *dibh; + int error; + + error = gfs2_trans_begin(ip->i_sbd, RES_DINODE + RES_EATTR, 0); + if (error) + return error; + + gfs2_trans_add_bh(ip->i_gl, el->el_bh); + + if (prev) { + uint32_t len; + + len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea); + prev->ea_rec_len = cpu_to_be32(len); + + if (GFS2_EA_IS_LAST(ea)) + prev->ea_flags |= GFS2_EAFLAG_LAST; + } else + ea->ea_type = GFS2_EATYPE_UNUSED; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + ip->i_di.di_ctime = get_seconds(); + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs2_trans_end(ip->i_sbd); + + return error; +} + +int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct gfs2_ea_location el; + int error; + + if (!ip->i_di.di_eattr) + return -ENODATA; + + error = gfs2_ea_find(ip, er, &el); + if (error) + return error; + if (!el.el_ea) + return -ENODATA; + + if (GFS2_EA_IS_STUFFED(el.el_ea)) + error = ea_remove_stuffed(ip, &el); + else + error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, + 0); + + brelse(el.el_bh); + + return error; +} + +/** + * gfs2_ea_remove - sets (or creates or replaces) an extended attribute + * @ip: pointer to the inode of the target file + * @er: request information + * + * Returns: errno + */ + +int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct gfs2_holder i_gh; + int error; + + if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) + return -EINVAL; + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + return error; + + if (IS_IMMUTABLE(ip->i_vnode) || IS_APPEND(ip->i_vnode)) + error = -EPERM; + else + error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er); + + gfs2_glock_dq_uninit(&i_gh); + + return error; +} + +static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, + struct gfs2_ea_header *ea, char *data) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head **bh; + unsigned int amount = GFS2_EA_DATA_LEN(ea); + unsigned int nptrs = DIV_RU(amount, sdp->sd_jbsize); + uint64_t *dataptrs = GFS2_EA2DATAPTRS(ea); + unsigned int x; + int error; + + bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL); + if (!bh) + return -ENOMEM; + + error = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0); + if (error) + goto out; + + for (x = 0; x < nptrs; x++) { + error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), + DIO_START, bh + x); + if (error) { + while (x--) + brelse(bh[x]); + goto fail; + } + dataptrs++; + } + + for (x = 0; x < nptrs; x++) { + error = gfs2_meta_reread(sdp, bh[x], DIO_WAIT); + if (error) { + for (; x < nptrs; x++) + brelse(bh[x]); + goto fail; + } + if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) { + for (; x < nptrs; x++) + brelse(bh[x]); + error = -EIO; + goto fail; + } + + gfs2_trans_add_bh(ip->i_gl, bh[x]); + + memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), + data, + (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize); + + amount -= sdp->sd_jbsize; + data += sdp->sd_jbsize; + + brelse(bh[x]); + } + + out: + kfree(bh); + + return error; + + fail: + gfs2_trans_end(sdp); + kfree(bh); + + return error; +} + +int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, + struct iattr *attr, char *data) +{ + struct buffer_head *dibh; + int error; + + if (GFS2_EA_IS_STUFFED(el->el_ea)) { + error = gfs2_trans_begin(ip->i_sbd, RES_DINODE + RES_EATTR, 0); + if (error) + return error; + + gfs2_trans_add_bh(ip->i_gl, el->el_bh); + memcpy(GFS2_EA2DATA(el->el_ea), + data, + GFS2_EA_DATA_LEN(el->el_ea)); + } else + error = ea_acl_chmod_unstuffed(ip, el->el_ea, data); + + if (error) + return error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + error = inode_setattr(ip->i_vnode, attr); + gfs2_assert_warn(ip->i_sbd, !error); + gfs2_inode_attr_out(ip); + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs2_trans_end(ip->i_sbd); + + return error; +} + +static int ea_dealloc_indirect(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_rgrp_list rlist; + struct buffer_head *indbh, *dibh; + uint64_t *eablk, *end; + unsigned int rg_blocks = 0; + uint64_t bstart = 0; + unsigned int blen = 0; + unsigned int blks = 0; + unsigned int x; + int error; + + memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); + + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, + DIO_START | DIO_WAIT, &indbh); + if (error) + return error; + + if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) { + error = -EIO; + goto out; + } + + eablk = (uint64_t *)(indbh->b_data + sizeof(struct gfs2_meta_header)); + end = eablk + sdp->sd_inptrs; + + for (; eablk < end; eablk++) { + uint64_t bn; + + if (!*eablk) + break; + bn = be64_to_cpu(*eablk); + + if (bstart + blen == bn) + blen++; + else { + if (bstart) + gfs2_rlist_add(sdp, &rlist, bstart); + bstart = bn; + blen = 1; + } + blks++; + } + if (bstart) + gfs2_rlist_add(sdp, &rlist, bstart); + else + goto out; + + gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); + + for (x = 0; x < rlist.rl_rgrps; x++) { + struct gfs2_rgrpd *rgd; + rgd = get_gl2rgd(rlist.rl_ghs[x].gh_gl); + rg_blocks += rgd->rd_ri.ri_length; + } + + error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs); + if (error) + goto out_rlist_free; + + error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + + RES_INDIRECT + RES_STATFS + + RES_QUOTA, blks); + if (error) + goto out_gunlock; + + gfs2_trans_add_bh(ip->i_gl, indbh); + + eablk = (uint64_t *)(indbh->b_data + sizeof(struct gfs2_meta_header)); + bstart = 0; + blen = 0; + + for (; eablk < end; eablk++) { + uint64_t bn; + + if (!*eablk) + break; + bn = be64_to_cpu(*eablk); + + if (bstart + blen == bn) + blen++; + else { + if (bstart) + gfs2_free_meta(ip, bstart, blen); + bstart = bn; + blen = 1; + } + + *eablk = 0; + if (!ip->i_di.di_blocks) + gfs2_consist_inode(ip); + ip->i_di.di_blocks--; + } + if (bstart) + gfs2_free_meta(ip, bstart, blen); + + ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs2_trans_end(sdp); + + out_gunlock: + gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); + + out_rlist_free: + gfs2_rlist_free(&rlist); + + out: + brelse(indbh); + + return error; +} + +static int ea_dealloc_block(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_rgrpd *rgd; + struct buffer_head *dibh; + int error; + + rgd = gfs2_blk2rgrpd(sdp, ip->i_di.di_eattr); + if (!rgd) { + gfs2_consist_inode(ip); + return -EIO; + } + + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, + &al->al_rgd_gh); + if (error) + return error; + + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_DINODE + + RES_STATFS + RES_QUOTA, 1); + if (error) + goto out_gunlock; + + gfs2_free_meta(ip, ip->i_di.di_eattr, 1); + + ip->i_di.di_eattr = 0; + if (!ip->i_di.di_blocks) + gfs2_consist_inode(ip); + ip->i_di.di_blocks--; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs2_trans_end(sdp); + + out_gunlock: + gfs2_glock_dq_uninit(&al->al_rgd_gh); + + return error; +} + +/** + * gfs2_ea_dealloc - deallocate the extended attribute fork + * @ip: the inode + * + * Returns: errno + */ + +int gfs2_ea_dealloc(struct gfs2_inode *ip) +{ + struct gfs2_alloc *al; + int error; + + al = gfs2_alloc_get(ip); + + error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out_alloc; + + error = gfs2_rindex_hold(ip->i_sbd, &al->al_ri_gh); + if (error) + goto out_quota; + + error = ea_foreach(ip, ea_dealloc_unstuffed, NULL); + if (error) + goto out_rindex; + + if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) { + error = ea_dealloc_indirect(ip); + if (error) + goto out_rindex; + } + + error = ea_dealloc_block(ip); + + out_rindex: + gfs2_glock_dq_uninit(&al->al_ri_gh); + + out_quota: + gfs2_quota_unhold(ip); + + out_alloc: + gfs2_alloc_put(ip); + + return error; +} + +/** + * gfs2_get_eattr_meta - return all the eattr blocks of a file + * @dip: the directory + * @ub: the structure representing the user buffer to copy to + * + * Returns: errno + */ + +int gfs2_get_eattr_meta(struct gfs2_inode *ip, struct gfs2_user_buffer *ub) +{ + struct buffer_head *bh; + int error; + + error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, + DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + gfs2_add_bh_to_ub(ub, bh); + + if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) { + struct buffer_head *eabh; + uint64_t *eablk, *end; + + if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_IN)) { + error = -EIO; + goto out; + } + + eablk = (uint64_t *)(bh->b_data + + sizeof(struct gfs2_meta_header)); + end = eablk + ip->i_sbd->sd_inptrs; + + for (; eablk < end; eablk++) { + uint64_t bn; + + if (!*eablk) + break; + bn = be64_to_cpu(*eablk); + + error = gfs2_meta_read(ip->i_gl, bn, + DIO_START | DIO_WAIT, &eabh); + if (error) + break; + gfs2_add_bh_to_ub(ub, eabh); + brelse(eabh); + if (error) + break; + } + } + + out: + brelse(bh); + + return error; +} + diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h new file mode 100644 index 000000000000..a64039295759 --- /dev/null +++ b/fs/gfs2/eattr.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __EATTR_DOT_H__ +#define __EATTR_DOT_H__ + +#define GFS2_EA_REC_LEN(ea) be32_to_cpu((ea)->ea_rec_len) +#define GFS2_EA_DATA_LEN(ea) be32_to_cpu((ea)->ea_data_len) + +#define GFS2_EA_SIZE(ea) \ +ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \ + ((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \ + (sizeof(uint64_t) * (ea)->ea_num_ptrs)), 8) + +#define GFS2_EA_STRLEN(ea) \ +((((ea)->ea_type == GFS2_EATYPE_USR) ? 5 : 7) + (ea)->ea_name_len + 1) + +#define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs) +#define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST) + +#define GFS2_EAREQ_SIZE_STUFFED(er) \ +ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8) + +#define GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er) \ +ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \ + sizeof(uint64_t) * DIV_RU((er)->er_data_len, (sdp)->sd_jbsize), 8) + +#define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1)) +#define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len) + +#define GFS2_EA2DATAPTRS(ea) \ +((uint64_t *)(GFS2_EA2NAME(ea) + ALIGN((ea)->ea_name_len, 8))) + +#define GFS2_EA2NEXT(ea) \ +((struct gfs2_ea_header *)((char *)(ea) + GFS2_EA_REC_LEN(ea))) + +#define GFS2_EA_BH2FIRST(bh) \ +((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header))) + +#define GFS2_ERF_MODE 0x80000000 + +struct gfs2_ea_request { + char *er_name; + char *er_data; + unsigned int er_name_len; + unsigned int er_data_len; + unsigned int er_type; /* GFS2_EATYPE_... */ + int er_flags; + mode_t er_mode; +}; + +struct gfs2_ea_location { + struct buffer_head *el_bh; + struct gfs2_ea_header *el_ea; + struct gfs2_ea_header *el_prev; +}; + +int gfs2_ea_repack(struct gfs2_inode *ip); + +int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); +int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); +int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); + +int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er); +int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er); +int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er); +int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er); + +int gfs2_ea_dealloc(struct gfs2_inode *ip); + +int gfs2_get_eattr_meta(struct gfs2_inode *ip, struct gfs2_user_buffer *ub); + +/* Exported to acl.c */ + +int gfs2_ea_find(struct gfs2_inode *ip, + struct gfs2_ea_request *er, + struct gfs2_ea_location *el); +int gfs2_ea_get_copy(struct gfs2_inode *ip, + struct gfs2_ea_location *el, + char *data); +int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, + struct iattr *attr, char *data); + +#endif /* __EATTR_DOT_H__ */ diff --git a/fs/gfs2/format.h b/fs/gfs2/format.h new file mode 100644 index 000000000000..c7bf32ce3eca --- /dev/null +++ b/fs/gfs2/format.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __FORMAT_DOT_H__ +#define __FORMAT_DOT_H__ + +static const uint32_t gfs2_old_fs_formats[] = { + 0 +}; + +static const uint32_t gfs2_old_multihost_formats[] = { + 0 +}; + +#endif /* __FORMAT_DOT_H__ */ diff --git a/fs/gfs2/gfs2.h b/fs/gfs2/gfs2.h new file mode 100644 index 000000000000..a5d118238466 --- /dev/null +++ b/fs/gfs2/gfs2.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __GFS2_DOT_H__ +#define __GFS2_DOT_H__ + +#include + +#include "lm_interface.h" +#include "lvb.h" +#include "incore.h" +#include "util.h" + +enum { + NO_CREATE = 0, + CREATE = 1, +}; + +enum { + NO_WAIT = 0, + WAIT = 1, +}; + +enum { + NO_FORCE = 0, + FORCE = 1, +}; + +/* Divide num by den. Round up if there is a remainder. */ +#define DIV_RU(num, den) (((num) + (den) - 1) / (den)) + +#define GFS2_FAST_NAME_SIZE 8 + +#define get_v2sdp(sb) ((struct gfs2_sbd *)(sb)->s_fs_info) +#define set_v2sdp(sb, sdp) (sb)->s_fs_info = (sdp) +#define get_v2ip(inode) ((struct gfs2_inode *)(inode)->u.generic_ip) +#define set_v2ip(inode, ip) (inode)->u.generic_ip = (ip) +#define get_v2fp(file) ((struct gfs2_file *)(file)->private_data) +#define set_v2fp(file, fp) (file)->private_data = (fp) +#define get_v2bd(bh) ((struct gfs2_bufdata *)(bh)->b_private) +#define set_v2bd(bh, bd) (bh)->b_private = (bd) +#define get_v2db(bh) ((struct gfs2_databuf *)(bh)->b_private) +#define set_v2db(bh, db) (bh)->b_private = (db) + +#define get_transaction ((struct gfs2_trans *)(current->journal_info)) +#define set_transaction(tr) (current->journal_info) = (tr) + +#define get_gl2ip(gl) ((struct gfs2_inode *)(gl)->gl_object) +#define set_gl2ip(gl, ip) (gl)->gl_object = (ip) +#define get_gl2rgd(gl) ((struct gfs2_rgrpd *)(gl)->gl_object) +#define set_gl2rgd(gl, rgd) (gl)->gl_object = (rgd) +#define get_gl2gl(gl) ((struct gfs2_glock *)(gl)->gl_object) +#define set_gl2gl(gl, gl2) (gl)->gl_object = (gl2) + +#endif /* __GFS2_DOT_H__ */ + diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c new file mode 100644 index 000000000000..321945fde12d --- /dev/null +++ b/fs/gfs2/glock.c @@ -0,0 +1,2513 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "lm.h" +#include "lops.h" +#include "meta_io.h" +#include "quota.h" +#include "super.h" + +/* Must be kept in sync with the beginning of struct gfs2_glock */ +struct glock_plug { + struct list_head gl_list; + unsigned long gl_flags; +}; + +struct greedy { + struct gfs2_holder gr_gh; + struct work_struct gr_work; +}; + +typedef void (*glock_examiner) (struct gfs2_glock * gl); + +/** + * relaxed_state_ok - is a requested lock compatible with the current lock mode? + * @actual: the current state of the lock + * @requested: the lock state that was requested by the caller + * @flags: the modifier flags passed in by the caller + * + * Returns: 1 if the locks are compatible, 0 otherwise + */ + +static inline int relaxed_state_ok(unsigned int actual, unsigned requested, + int flags) +{ + if (actual == requested) + return 1; + + if (flags & GL_EXACT) + return 0; + + if (actual == LM_ST_EXCLUSIVE && requested == LM_ST_SHARED) + return 1; + + if (actual != LM_ST_UNLOCKED && (flags & LM_FLAG_ANY)) + return 1; + + return 0; +} + +/** + * gl_hash() - Turn glock number into hash bucket number + * @lock: The glock number + * + * Returns: The number of the corresponding hash bucket + */ + +static unsigned int gl_hash(struct lm_lockname *name) +{ + unsigned int h; + + h = jhash(&name->ln_number, sizeof(uint64_t), 0); + h = jhash(&name->ln_type, sizeof(unsigned int), h); + h &= GFS2_GL_HASH_MASK; + + return h; +} + +/** + * glock_free() - Perform a few checks and then release struct gfs2_glock + * @gl: The glock to release + * + * Also calls lock module to release its internal structure for this glock. + * + */ + +static void glock_free(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct inode *aspace = gl->gl_aspace; + + gfs2_lm_put_lock(sdp, gl->gl_lock); + + if (aspace) + gfs2_aspace_put(aspace); + + kmem_cache_free(gfs2_glock_cachep, gl); + + atomic_dec(&sdp->sd_glock_count); +} + +/** + * gfs2_glock_hold() - increment reference count on glock + * @gl: The glock to hold + * + */ + +void gfs2_glock_hold(struct gfs2_glock *gl) +{ + kref_get(&gl->gl_ref); +} + +/* All work is done after the return from kref_put() so we + can release the write_lock before the free. */ + +static void kill_glock(struct kref *kref) +{ + struct gfs2_glock *gl = container_of(kref, struct gfs2_glock, gl_ref); + struct gfs2_sbd *sdp = gl->gl_sbd; + + gfs2_assert(sdp, gl->gl_state == LM_ST_UNLOCKED); + gfs2_assert(sdp, list_empty(&gl->gl_reclaim)); + gfs2_assert(sdp, list_empty(&gl->gl_holders)); + gfs2_assert(sdp, list_empty(&gl->gl_waiters1)); + gfs2_assert(sdp, list_empty(&gl->gl_waiters2)); + gfs2_assert(sdp, list_empty(&gl->gl_waiters3)); +} + +/** + * gfs2_glock_put() - Decrement reference count on glock + * @gl: The glock to put + * + */ + +int gfs2_glock_put(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_gl_hash_bucket *bucket = gl->gl_bucket; + int rv = 0; + + down(&sdp->sd_invalidate_inodes_mutex); + + write_lock(&bucket->hb_lock); + if (kref_put(&gl->gl_ref, kill_glock)) { + list_del_init(&gl->gl_list); + write_unlock(&bucket->hb_lock); + glock_free(gl); + rv = 1; + goto out; + } + write_unlock(&bucket->hb_lock); + out: + up(&sdp->sd_invalidate_inodes_mutex); + return rv; +} + +/** + * queue_empty - check to see if a glock's queue is empty + * @gl: the glock + * @head: the head of the queue to check + * + * This function protects the list in the event that a process already + * has a holder on the list and is adding a second holder for itself. + * The glmutex lock is what generally prevents processes from working + * on the same glock at once, but the special case of adding a second + * holder for yourself ("recursive" locking) doesn't involve locking + * glmutex, making the spin lock necessary. + * + * Returns: 1 if the queue is empty + */ + +static inline int queue_empty(struct gfs2_glock *gl, struct list_head *head) +{ + int empty; + spin_lock(&gl->gl_spin); + empty = list_empty(head); + spin_unlock(&gl->gl_spin); + return empty; +} + +/** + * search_bucket() - Find struct gfs2_glock by lock number + * @bucket: the bucket to search + * @name: The lock name + * + * Returns: NULL, or the struct gfs2_glock with the requested number + */ + +static struct gfs2_glock *search_bucket(struct gfs2_gl_hash_bucket *bucket, + struct lm_lockname *name) +{ + struct gfs2_glock *gl; + + list_for_each_entry(gl, &bucket->hb_list, gl_list) { + if (test_bit(GLF_PLUG, &gl->gl_flags)) + continue; + if (!lm_name_equal(&gl->gl_name, name)) + continue; + + kref_get(&gl->gl_ref); + + return gl; + } + + return NULL; +} + +/** + * gfs2_glock_find() - Find glock by lock number + * @sdp: The GFS2 superblock + * @name: The lock name + * + * Returns: NULL, or the struct gfs2_glock with the requested number + */ + +struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, + struct lm_lockname *name) +{ + struct gfs2_gl_hash_bucket *bucket = &sdp->sd_gl_hash[gl_hash(name)]; + struct gfs2_glock *gl; + + read_lock(&bucket->hb_lock); + gl = search_bucket(bucket, name); + read_unlock(&bucket->hb_lock); + + return gl; +} + +/** + * gfs2_glock_get() - Get a glock, or create one if one doesn't exist + * @sdp: The GFS2 superblock + * @number: the lock number + * @glops: The glock_operations to use + * @create: If 0, don't create the glock if it doesn't exist + * @glp: the glock is returned here + * + * This does not lock a glock, just finds/creates structures for one. + * + * Returns: errno + */ + +int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, + struct gfs2_glock_operations *glops, int create, + struct gfs2_glock **glp) +{ + struct lm_lockname name; + struct gfs2_glock *gl, *tmp; + struct gfs2_gl_hash_bucket *bucket; + int error; + + name.ln_number = number; + name.ln_type = glops->go_type; + bucket = &sdp->sd_gl_hash[gl_hash(&name)]; + + read_lock(&bucket->hb_lock); + gl = search_bucket(bucket, &name); + read_unlock(&bucket->hb_lock); + + if (gl || !create) { + *glp = gl; + return 0; + } + + gl = kmem_cache_alloc(gfs2_glock_cachep, GFP_KERNEL); + if (!gl) + return -ENOMEM; + + memset(gl, 0, sizeof(struct gfs2_glock)); + + INIT_LIST_HEAD(&gl->gl_list); + gl->gl_name = name; + kref_init(&gl->gl_ref); + + spin_lock_init(&gl->gl_spin); + + gl->gl_state = LM_ST_UNLOCKED; + INIT_LIST_HEAD(&gl->gl_holders); + INIT_LIST_HEAD(&gl->gl_waiters1); + INIT_LIST_HEAD(&gl->gl_waiters2); + INIT_LIST_HEAD(&gl->gl_waiters3); + + gl->gl_ops = glops; + + gl->gl_bucket = bucket; + INIT_LIST_HEAD(&gl->gl_reclaim); + + gl->gl_sbd = sdp; + + lops_init_le(&gl->gl_le, &gfs2_glock_lops); + INIT_LIST_HEAD(&gl->gl_ail_list); + + /* If this glock protects actual on-disk data or metadata blocks, + create a VFS inode to manage the pages/buffers holding them. */ + if (glops == &gfs2_inode_glops || + glops == &gfs2_rgrp_glops || + glops == &gfs2_meta_glops) { + gl->gl_aspace = gfs2_aspace_get(sdp); + if (!gl->gl_aspace) { + error = -ENOMEM; + goto fail; + } + } + + error = gfs2_lm_get_lock(sdp, &name, &gl->gl_lock); + if (error) + goto fail_aspace; + + atomic_inc(&sdp->sd_glock_count); + + write_lock(&bucket->hb_lock); + tmp = search_bucket(bucket, &name); + if (tmp) { + write_unlock(&bucket->hb_lock); + glock_free(gl); + gl = tmp; + } else { + list_add_tail(&gl->gl_list, &bucket->hb_list); + write_unlock(&bucket->hb_lock); + } + + *glp = gl; + + return 0; + + fail_aspace: + if (gl->gl_aspace) + gfs2_aspace_put(gl->gl_aspace); + + fail: + kmem_cache_free(gfs2_glock_cachep, gl); + + return error; +} + +/** + * gfs2_holder_init - initialize a struct gfs2_holder in the default way + * @gl: the glock + * @state: the state we're requesting + * @flags: the modifier flags + * @gh: the holder structure + * + */ + +void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, int flags, + struct gfs2_holder *gh) +{ + INIT_LIST_HEAD(&gh->gh_list); + gh->gh_gl = gl; + gh->gh_owner = (flags & GL_NEVER_RECURSE) ? NULL : current; + gh->gh_state = state; + gh->gh_flags = flags; + gh->gh_error = 0; + gh->gh_iflags = 0; + init_completion(&gh->gh_wait); + + if (gh->gh_state == LM_ST_EXCLUSIVE) + gh->gh_flags |= GL_LOCAL_EXCL; + + gfs2_glock_hold(gl); +} + +/** + * gfs2_holder_reinit - reinitialize a struct gfs2_holder so we can requeue it + * @state: the state we're requesting + * @flags: the modifier flags + * @gh: the holder structure + * + * Don't mess with the glock. + * + */ + +void gfs2_holder_reinit(unsigned int state, int flags, struct gfs2_holder *gh) +{ + gh->gh_state = state; + gh->gh_flags = flags; + if (gh->gh_state == LM_ST_EXCLUSIVE) + gh->gh_flags |= GL_LOCAL_EXCL; + + gh->gh_iflags &= 1 << HIF_ALLOCED; +} + +/** + * gfs2_holder_uninit - uninitialize a holder structure (drop glock reference) + * @gh: the holder structure + * + */ + +void gfs2_holder_uninit(struct gfs2_holder *gh) +{ + gfs2_glock_put(gh->gh_gl); + gh->gh_gl = NULL; +} + +/** + * gfs2_holder_get - get a struct gfs2_holder structure + * @gl: the glock + * @state: the state we're requesting + * @flags: the modifier flags + * @gfp_flags: __GFP_NOFAIL + * + * Figure out how big an impact this function has. Either: + * 1) Replace it with a cache of structures hanging off the struct gfs2_sbd + * 2) Leave it like it is + * + * Returns: the holder structure, NULL on ENOMEM + */ + +struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl, unsigned int state, + int flags, gfp_t gfp_flags) +{ + struct gfs2_holder *gh; + + gh = kmalloc(sizeof(struct gfs2_holder), gfp_flags); + if (!gh) + return NULL; + + gfs2_holder_init(gl, state, flags, gh); + set_bit(HIF_ALLOCED, &gh->gh_iflags); + + return gh; +} + +/** + * gfs2_holder_put - get rid of a struct gfs2_holder structure + * @gh: the holder structure + * + */ + +void gfs2_holder_put(struct gfs2_holder *gh) +{ + gfs2_holder_uninit(gh); + kfree(gh); +} + +/** + * handle_recurse - put other holder structures (marked recursive) + * into the holders list + * @gh: the holder structure + * + */ + +static void handle_recurse(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_holder *tmp_gh, *safe; + int found = 0; + + if (gfs2_assert_warn(sdp, gh->gh_owner)) + return; + + list_for_each_entry_safe(tmp_gh, safe, &gl->gl_waiters3, gh_list) { + if (tmp_gh->gh_owner != gh->gh_owner) + continue; + + gfs2_assert_warn(sdp, + test_bit(HIF_RECURSE, &tmp_gh->gh_iflags)); + + list_move_tail(&tmp_gh->gh_list, &gl->gl_holders); + tmp_gh->gh_error = 0; + set_bit(HIF_HOLDER, &tmp_gh->gh_iflags); + + complete(&tmp_gh->gh_wait); + + found = 1; + } + + gfs2_assert_warn(sdp, found); +} + +/** + * do_unrecurse - a recursive holder was just dropped of the waiters3 list + * @gh: the holder + * + * If there is only one other recursive holder, clear its HIF_RECURSE bit. + * If there is more than one, leave them alone. + * + */ + +static void do_unrecurse(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_holder *tmp_gh, *last_gh = NULL; + int found = 0; + + if (gfs2_assert_warn(sdp, gh->gh_owner)) + return; + + list_for_each_entry(tmp_gh, &gl->gl_waiters3, gh_list) { + if (tmp_gh->gh_owner != gh->gh_owner) + continue; + + gfs2_assert_warn(sdp, + test_bit(HIF_RECURSE, &tmp_gh->gh_iflags)); + + if (found) + return; + + found = 1; + last_gh = tmp_gh; + } + + if (!gfs2_assert_warn(sdp, found)) + clear_bit(HIF_RECURSE, &last_gh->gh_iflags); +} + +/** + * rq_mutex - process a mutex request in the queue + * @gh: the glock holder + * + * Returns: 1 if the queue is blocked + */ + +static int rq_mutex(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + + list_del_init(&gh->gh_list); + /* gh->gh_error never examined. */ + set_bit(GLF_LOCK, &gl->gl_flags); + complete(&gh->gh_wait); + + return 1; +} + +/** + * rq_promote - process a promote request in the queue + * @gh: the glock holder + * + * Acquire a new inter-node lock, or change a lock state to more restrictive. + * + * Returns: 1 if the queue is blocked + */ + +static int rq_promote(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_glock_operations *glops = gl->gl_ops; + int recurse; + + if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) { + if (list_empty(&gl->gl_holders)) { + gl->gl_req_gh = gh; + set_bit(GLF_LOCK, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + + if (atomic_read(&sdp->sd_reclaim_count) > + gfs2_tune_get(sdp, gt_reclaim_limit) && + !(gh->gh_flags & LM_FLAG_PRIORITY)) { + gfs2_reclaim_glock(sdp); + gfs2_reclaim_glock(sdp); + } + + glops->go_xmote_th(gl, gh->gh_state, + gh->gh_flags); + + spin_lock(&gl->gl_spin); + } + return 1; + } + + if (list_empty(&gl->gl_holders)) { + set_bit(HIF_FIRST, &gh->gh_iflags); + set_bit(GLF_LOCK, &gl->gl_flags); + recurse = 0; + } else { + struct gfs2_holder *next_gh; + if (gh->gh_flags & GL_LOCAL_EXCL) + return 1; + next_gh = list_entry(gl->gl_holders.next, struct gfs2_holder, + gh_list); + if (next_gh->gh_flags & GL_LOCAL_EXCL) + return 1; + recurse = test_bit(HIF_RECURSE, &gh->gh_iflags); + } + + list_move_tail(&gh->gh_list, &gl->gl_holders); + gh->gh_error = 0; + set_bit(HIF_HOLDER, &gh->gh_iflags); + + if (recurse) + handle_recurse(gh); + + complete(&gh->gh_wait); + + return 0; +} + +/** + * rq_demote - process a demote request in the queue + * @gh: the glock holder + * + * Returns: 1 if the queue is blocked + */ + +static int rq_demote(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_glock_operations *glops = gl->gl_ops; + + if (!list_empty(&gl->gl_holders)) + return 1; + + if (gl->gl_state == gh->gh_state || gl->gl_state == LM_ST_UNLOCKED) { + list_del_init(&gh->gh_list); + gh->gh_error = 0; + spin_unlock(&gl->gl_spin); + if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) + gfs2_holder_put(gh); + else + complete(&gh->gh_wait); + spin_lock(&gl->gl_spin); + } else { + gl->gl_req_gh = gh; + set_bit(GLF_LOCK, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + + if (gh->gh_state == LM_ST_UNLOCKED || + gl->gl_state != LM_ST_EXCLUSIVE) + glops->go_drop_th(gl); + else + glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags); + + spin_lock(&gl->gl_spin); + } + + return 0; +} + +/** + * rq_greedy - process a queued request to drop greedy status + * @gh: the glock holder + * + * Returns: 1 if the queue is blocked + */ + +static int rq_greedy(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + + list_del_init(&gh->gh_list); + /* gh->gh_error never examined. */ + clear_bit(GLF_GREEDY, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + + gfs2_holder_uninit(gh); + kfree(container_of(gh, struct greedy, gr_gh)); + + spin_lock(&gl->gl_spin); + + return 0; +} + +/** + * run_queue - process holder structures on a glock + * @gl: the glock + * + */ + +static void run_queue(struct gfs2_glock *gl) +{ + struct gfs2_holder *gh; + int blocked = 1; + + for (;;) { + if (test_bit(GLF_LOCK, &gl->gl_flags)) + break; + + if (!list_empty(&gl->gl_waiters1)) { + gh = list_entry(gl->gl_waiters1.next, + struct gfs2_holder, gh_list); + + if (test_bit(HIF_MUTEX, &gh->gh_iflags)) + blocked = rq_mutex(gh); + else + gfs2_assert_warn(gl->gl_sbd, 0); + + } else if (!list_empty(&gl->gl_waiters2) && + !test_bit(GLF_SKIP_WAITERS2, &gl->gl_flags)) { + gh = list_entry(gl->gl_waiters2.next, + struct gfs2_holder, gh_list); + + if (test_bit(HIF_DEMOTE, &gh->gh_iflags)) + blocked = rq_demote(gh); + else if (test_bit(HIF_GREEDY, &gh->gh_iflags)) + blocked = rq_greedy(gh); + else + gfs2_assert_warn(gl->gl_sbd, 0); + + } else if (!list_empty(&gl->gl_waiters3)) { + gh = list_entry(gl->gl_waiters3.next, + struct gfs2_holder, gh_list); + + if (test_bit(HIF_PROMOTE, &gh->gh_iflags)) + blocked = rq_promote(gh); + else + gfs2_assert_warn(gl->gl_sbd, 0); + + } else + break; + + if (blocked) + break; + } +} + +/** + * gfs2_glmutex_lock - acquire a local lock on a glock + * @gl: the glock + * + * Gives caller exclusive access to manipulate a glock structure. + */ + +void gfs2_glmutex_lock(struct gfs2_glock *gl) +{ + struct gfs2_holder gh; + + gfs2_holder_init(gl, 0, 0, &gh); + set_bit(HIF_MUTEX, &gh.gh_iflags); + + spin_lock(&gl->gl_spin); + if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) + list_add_tail(&gh.gh_list, &gl->gl_waiters1); + else + complete(&gh.gh_wait); + spin_unlock(&gl->gl_spin); + + wait_for_completion(&gh.gh_wait); + gfs2_holder_uninit(&gh); +} + +/** + * gfs2_glmutex_trylock - try to acquire a local lock on a glock + * @gl: the glock + * + * Returns: 1 if the glock is acquired + */ + +int gfs2_glmutex_trylock(struct gfs2_glock *gl) +{ + int acquired = 1; + + spin_lock(&gl->gl_spin); + if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) + acquired = 0; + spin_unlock(&gl->gl_spin); + + return acquired; +} + +/** + * gfs2_glmutex_unlock - release a local lock on a glock + * @gl: the glock + * + */ + +void gfs2_glmutex_unlock(struct gfs2_glock *gl) +{ + spin_lock(&gl->gl_spin); + clear_bit(GLF_LOCK, &gl->gl_flags); + run_queue(gl); + spin_unlock(&gl->gl_spin); +} + +/** + * handle_callback - add a demote request to a lock's queue + * @gl: the glock + * @state: the state the caller wants us to change to + * + */ + +static void handle_callback(struct gfs2_glock *gl, unsigned int state) +{ + struct gfs2_holder *gh, *new_gh = NULL; + + restart: + spin_lock(&gl->gl_spin); + + list_for_each_entry(gh, &gl->gl_waiters2, gh_list) { + if (test_bit(HIF_DEMOTE, &gh->gh_iflags) && + gl->gl_req_gh != gh) { + if (gh->gh_state != state) + gh->gh_state = LM_ST_UNLOCKED; + goto out; + } + } + + if (new_gh) { + list_add_tail(&new_gh->gh_list, &gl->gl_waiters2); + new_gh = NULL; + } else { + spin_unlock(&gl->gl_spin); + + new_gh = gfs2_holder_get(gl, state, + LM_FLAG_TRY | GL_NEVER_RECURSE, + GFP_KERNEL | __GFP_NOFAIL), + set_bit(HIF_DEMOTE, &new_gh->gh_iflags); + set_bit(HIF_DEALLOC, &new_gh->gh_iflags); + + goto restart; + } + + out: + spin_unlock(&gl->gl_spin); + + if (new_gh) + gfs2_holder_put(new_gh); +} + +/** + * state_change - record that the glock is now in a different state + * @gl: the glock + * @new_state the new state + * + */ + +static void state_change(struct gfs2_glock *gl, unsigned int new_state) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + int held1, held2; + + held1 = (gl->gl_state != LM_ST_UNLOCKED); + held2 = (new_state != LM_ST_UNLOCKED); + + if (held1 != held2) { + if (held2) { + atomic_inc(&sdp->sd_glock_held_count); + gfs2_glock_hold(gl); + } else { + atomic_dec(&sdp->sd_glock_held_count); + gfs2_glock_put(gl); + } + } + + gl->gl_state = new_state; +} + +/** + * xmote_bh - Called after the lock module is done acquiring a lock + * @gl: The glock in question + * @ret: the int returned from the lock module + * + */ + +static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_glock_operations *glops = gl->gl_ops; + struct gfs2_holder *gh = gl->gl_req_gh; + int prev_state = gl->gl_state; + int op_done = 1; + + gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC)); + + state_change(gl, ret & LM_OUT_ST_MASK); + + if (prev_state != LM_ST_UNLOCKED && !(ret & LM_OUT_CACHEABLE)) { + if (glops->go_inval) + glops->go_inval(gl, DIO_METADATA | DIO_DATA); + } else if (gl->gl_state == LM_ST_DEFERRED) { + /* We might not want to do this here. + Look at moving to the inode glops. */ + if (glops->go_inval) + glops->go_inval(gl, DIO_DATA); + } + + /* Deal with each possible exit condition */ + + if (!gh) + gl->gl_stamp = jiffies; + + else if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + gh->gh_error = -EIO; + if (test_bit(HIF_RECURSE, &gh->gh_iflags)) + do_unrecurse(gh); + spin_unlock(&gl->gl_spin); + + } else if (test_bit(HIF_DEMOTE, &gh->gh_iflags)) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + if (gl->gl_state == gh->gh_state || + gl->gl_state == LM_ST_UNLOCKED) + gh->gh_error = 0; + else { + if (gfs2_assert_warn(sdp, gh->gh_flags & + (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) == -1) + fs_warn(sdp, "ret = 0x%.8X\n", ret); + gh->gh_error = GLR_TRYFAILED; + } + spin_unlock(&gl->gl_spin); + + if (ret & LM_OUT_CANCELED) + handle_callback(gl, LM_ST_UNLOCKED); /* Lame */ + + } else if (ret & LM_OUT_CANCELED) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + gh->gh_error = GLR_CANCELED; + if (test_bit(HIF_RECURSE, &gh->gh_iflags)) + do_unrecurse(gh); + spin_unlock(&gl->gl_spin); + + } else if (relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) { + spin_lock(&gl->gl_spin); + list_move_tail(&gh->gh_list, &gl->gl_holders); + gh->gh_error = 0; + set_bit(HIF_HOLDER, &gh->gh_iflags); + spin_unlock(&gl->gl_spin); + + set_bit(HIF_FIRST, &gh->gh_iflags); + + op_done = 0; + + } else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + gh->gh_error = GLR_TRYFAILED; + if (test_bit(HIF_RECURSE, &gh->gh_iflags)) + do_unrecurse(gh); + spin_unlock(&gl->gl_spin); + + } else { + if (gfs2_assert_withdraw(sdp, 0) == -1) + fs_err(sdp, "ret = 0x%.8X\n", ret); + } + + if (glops->go_xmote_bh) + glops->go_xmote_bh(gl); + + if (op_done) { + spin_lock(&gl->gl_spin); + gl->gl_req_gh = NULL; + gl->gl_req_bh = NULL; + clear_bit(GLF_LOCK, &gl->gl_flags); + run_queue(gl); + spin_unlock(&gl->gl_spin); + } + + gfs2_glock_put(gl); + + if (gh) { + if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) + gfs2_holder_put(gh); + else + complete(&gh->gh_wait); + } +} + +/** + * gfs2_glock_xmote_th - Call into the lock module to acquire or change a glock + * @gl: The glock in question + * @state: the requested state + * @flags: modifier flags to the lock call + * + */ + +void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_glock_operations *glops = gl->gl_ops; + int lck_flags = flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB | + LM_FLAG_NOEXP | LM_FLAG_ANY | + LM_FLAG_PRIORITY); + unsigned int lck_ret; + + gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs2_assert_warn(sdp, state != LM_ST_UNLOCKED); + gfs2_assert_warn(sdp, state != gl->gl_state); + + if (gl->gl_state == LM_ST_EXCLUSIVE) { + if (glops->go_sync) + glops->go_sync(gl, + DIO_METADATA | DIO_DATA | DIO_RELEASE); + } + + gfs2_glock_hold(gl); + gl->gl_req_bh = xmote_bh; + + atomic_inc(&sdp->sd_lm_lock_calls); + + lck_ret = gfs2_lm_lock(sdp, gl->gl_lock, gl->gl_state, state, + lck_flags); + + if (gfs2_assert_withdraw(sdp, !(lck_ret & LM_OUT_ERROR))) + return; + + if (lck_ret & LM_OUT_ASYNC) + gfs2_assert_warn(sdp, lck_ret == LM_OUT_ASYNC); + else + xmote_bh(gl, lck_ret); +} + +/** + * drop_bh - Called after a lock module unlock completes + * @gl: the glock + * @ret: the return status + * + * Doesn't wake up the process waiting on the struct gfs2_holder (if any) + * Doesn't drop the reference on the glock the top half took out + * + */ + +static void drop_bh(struct gfs2_glock *gl, unsigned int ret) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_glock_operations *glops = gl->gl_ops; + struct gfs2_holder *gh = gl->gl_req_gh; + + clear_bit(GLF_PREFETCH, &gl->gl_flags); + + gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs2_assert_warn(sdp, !ret); + + state_change(gl, LM_ST_UNLOCKED); + + if (glops->go_inval) + glops->go_inval(gl, DIO_METADATA | DIO_DATA); + + if (gh) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + gh->gh_error = 0; + spin_unlock(&gl->gl_spin); + } + + if (glops->go_drop_bh) + glops->go_drop_bh(gl); + + spin_lock(&gl->gl_spin); + gl->gl_req_gh = NULL; + gl->gl_req_bh = NULL; + clear_bit(GLF_LOCK, &gl->gl_flags); + run_queue(gl); + spin_unlock(&gl->gl_spin); + + gfs2_glock_put(gl); + + if (gh) { + if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) + gfs2_holder_put(gh); + else + complete(&gh->gh_wait); + } +} + +/** + * gfs2_glock_drop_th - call into the lock module to unlock a lock + * @gl: the glock + * + */ + +void gfs2_glock_drop_th(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_glock_operations *glops = gl->gl_ops; + unsigned int ret; + + gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED); + + if (gl->gl_state == LM_ST_EXCLUSIVE) { + if (glops->go_sync) + glops->go_sync(gl, + DIO_METADATA | DIO_DATA | DIO_RELEASE); + } + + gfs2_glock_hold(gl); + gl->gl_req_bh = drop_bh; + + atomic_inc(&sdp->sd_lm_unlock_calls); + + ret = gfs2_lm_unlock(sdp, gl->gl_lock, gl->gl_state); + + if (gfs2_assert_withdraw(sdp, !(ret & LM_OUT_ERROR))) + return; + + if (!ret) + drop_bh(gl, ret); + else + gfs2_assert_warn(sdp, ret == LM_OUT_ASYNC); +} + +/** + * do_cancels - cancel requests for locks stuck waiting on an expire flag + * @gh: the LM_FLAG_PRIORITY holder waiting to acquire the lock + * + * Don't cancel GL_NOCANCEL requests. + */ + +static void do_cancels(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + + spin_lock(&gl->gl_spin); + + while (gl->gl_req_gh != gh && + !test_bit(HIF_HOLDER, &gh->gh_iflags) && + !list_empty(&gh->gh_list)) { + if (gl->gl_req_bh && + !(gl->gl_req_gh && + (gl->gl_req_gh->gh_flags & GL_NOCANCEL))) { + spin_unlock(&gl->gl_spin); + gfs2_lm_cancel(gl->gl_sbd, gl->gl_lock); + msleep(100); + spin_lock(&gl->gl_spin); + } else { + spin_unlock(&gl->gl_spin); + msleep(100); + spin_lock(&gl->gl_spin); + } + } + + spin_unlock(&gl->gl_spin); +} + +/** + * glock_wait_internal - wait on a glock acquisition + * @gh: the glock holder + * + * Returns: 0 on success + */ + +static int glock_wait_internal(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_glock_operations *glops = gl->gl_ops; + + if (test_bit(HIF_ABORTED, &gh->gh_iflags)) + return -EIO; + + if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) { + spin_lock(&gl->gl_spin); + if (gl->gl_req_gh != gh && + !test_bit(HIF_HOLDER, &gh->gh_iflags) && + !list_empty(&gh->gh_list)) { + list_del_init(&gh->gh_list); + gh->gh_error = GLR_TRYFAILED; + if (test_bit(HIF_RECURSE, &gh->gh_iflags)) + do_unrecurse(gh); + run_queue(gl); + spin_unlock(&gl->gl_spin); + return gh->gh_error; + } + spin_unlock(&gl->gl_spin); + } + + if (gh->gh_flags & LM_FLAG_PRIORITY) + do_cancels(gh); + + wait_for_completion(&gh->gh_wait); + + if (gh->gh_error) + return gh->gh_error; + + gfs2_assert_withdraw(sdp, test_bit(HIF_HOLDER, &gh->gh_iflags)); + gfs2_assert_withdraw(sdp, relaxed_state_ok(gl->gl_state, + gh->gh_state, + gh->gh_flags)); + + if (test_bit(HIF_FIRST, &gh->gh_iflags)) { + gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + + if (glops->go_lock) { + gh->gh_error = glops->go_lock(gh); + if (gh->gh_error) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + if (test_and_clear_bit(HIF_RECURSE, + &gh->gh_iflags)) + do_unrecurse(gh); + spin_unlock(&gl->gl_spin); + } + } + + spin_lock(&gl->gl_spin); + gl->gl_req_gh = NULL; + gl->gl_req_bh = NULL; + clear_bit(GLF_LOCK, &gl->gl_flags); + if (test_bit(HIF_RECURSE, &gh->gh_iflags)) + handle_recurse(gh); + run_queue(gl); + spin_unlock(&gl->gl_spin); + } + + return gh->gh_error; +} + +static inline struct gfs2_holder * +find_holder_by_owner(struct list_head *head, struct task_struct *owner) +{ + struct gfs2_holder *gh; + + list_for_each_entry(gh, head, gh_list) { + if (gh->gh_owner == owner) + return gh; + } + + return NULL; +} + +/** + * recurse_check - + * + * Make sure the new holder is compatible with the pre-existing one. + * + */ + +static int recurse_check(struct gfs2_holder *existing, struct gfs2_holder *new, + unsigned int state) +{ + struct gfs2_sbd *sdp = existing->gh_gl->gl_sbd; + + if (gfs2_assert_warn(sdp, (new->gh_flags & LM_FLAG_ANY) || + !(existing->gh_flags & LM_FLAG_ANY))) + goto fail; + + if (gfs2_assert_warn(sdp, (existing->gh_flags & GL_LOCAL_EXCL) || + !(new->gh_flags & GL_LOCAL_EXCL))) + goto fail; + + if (gfs2_assert_warn(sdp, relaxed_state_ok(state, new->gh_state, + new->gh_flags))) + goto fail; + + return 0; + + fail: + set_bit(HIF_ABORTED, &new->gh_iflags); + return -EINVAL; +} + +/** + * add_to_queue - Add a holder to the wait queue (but look for recursion) + * @gh: the holder structure to add + * + */ + +static void add_to_queue(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_holder *existing; + + if (!gh->gh_owner) + goto out; + + existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner); + if (existing) { + if (recurse_check(existing, gh, gl->gl_state)) + return; + + list_add_tail(&gh->gh_list, &gl->gl_holders); + set_bit(HIF_HOLDER, &gh->gh_iflags); + + gh->gh_error = 0; + complete(&gh->gh_wait); + + return; + } + + existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner); + if (existing) { + if (recurse_check(existing, gh, existing->gh_state)) + return; + + set_bit(HIF_RECURSE, &gh->gh_iflags); + set_bit(HIF_RECURSE, &existing->gh_iflags); + + list_add_tail(&gh->gh_list, &gl->gl_waiters3); + + return; + } + + out: + if (gh->gh_flags & LM_FLAG_PRIORITY) + list_add(&gh->gh_list, &gl->gl_waiters3); + else + list_add_tail(&gh->gh_list, &gl->gl_waiters3); +} + +/** + * gfs2_glock_nq - enqueue a struct gfs2_holder onto a glock (acquire a glock) + * @gh: the holder structure + * + * if (gh->gh_flags & GL_ASYNC), this never returns an error + * + * Returns: 0, GLR_TRYFAILED, or errno on failure + */ + +int gfs2_glock_nq(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_sbd *sdp = gl->gl_sbd; + int error = 0; + + atomic_inc(&sdp->sd_glock_nq_calls); + + restart: + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) { + set_bit(HIF_ABORTED, &gh->gh_iflags); + return -EIO; + } + + set_bit(HIF_PROMOTE, &gh->gh_iflags); + + spin_lock(&gl->gl_spin); + add_to_queue(gh); + run_queue(gl); + spin_unlock(&gl->gl_spin); + + if (!(gh->gh_flags & GL_ASYNC)) { + error = glock_wait_internal(gh); + if (error == GLR_CANCELED) { + msleep(1000); + goto restart; + } + } + + clear_bit(GLF_PREFETCH, &gl->gl_flags); + + return error; +} + +/** + * gfs2_glock_poll - poll to see if an async request has been completed + * @gh: the holder + * + * Returns: 1 if the request is ready to be gfs2_glock_wait()ed on + */ + +int gfs2_glock_poll(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + int ready = 0; + + spin_lock(&gl->gl_spin); + + if (test_bit(HIF_HOLDER, &gh->gh_iflags)) + ready = 1; + else if (list_empty(&gh->gh_list)) { + if (gh->gh_error == GLR_CANCELED) { + spin_unlock(&gl->gl_spin); + msleep(1000); + if (gfs2_glock_nq(gh)) + return 1; + return 0; + } else + ready = 1; + } + + spin_unlock(&gl->gl_spin); + + return ready; +} + +/** + * gfs2_glock_wait - wait for a lock acquisition that ended in a GLR_ASYNC + * @gh: the holder structure + * + * Returns: 0, GLR_TRYFAILED, or errno on failure + */ + +int gfs2_glock_wait(struct gfs2_holder *gh) +{ + int error; + + error = glock_wait_internal(gh); + if (error == GLR_CANCELED) { + msleep(1000); + gh->gh_flags &= ~GL_ASYNC; + error = gfs2_glock_nq(gh); + } + + return error; +} + +/** + * gfs2_glock_dq - dequeue a struct gfs2_holder from a glock (release a glock) + * @gh: the glock holder + * + */ + +void gfs2_glock_dq(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_glock_operations *glops = gl->gl_ops; + + atomic_inc(&sdp->sd_glock_dq_calls); + + if (gh->gh_flags & GL_SYNC) + set_bit(GLF_SYNC, &gl->gl_flags); + + if (gh->gh_flags & GL_NOCACHE) + handle_callback(gl, LM_ST_UNLOCKED); + + gfs2_glmutex_lock(gl); + + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + + if (list_empty(&gl->gl_holders)) { + spin_unlock(&gl->gl_spin); + + if (glops->go_unlock) + glops->go_unlock(gh); + + if (test_bit(GLF_SYNC, &gl->gl_flags)) { + if (glops->go_sync) + glops->go_sync(gl, DIO_METADATA | DIO_DATA); + } + + gl->gl_stamp = jiffies; + + spin_lock(&gl->gl_spin); + } + + clear_bit(GLF_LOCK, &gl->gl_flags); + run_queue(gl); + spin_unlock(&gl->gl_spin); +} + +/** + * gfs2_glock_prefetch - Try to prefetch a glock + * @gl: the glock + * @state: the state to prefetch in + * @flags: flags passed to go_xmote_th() + * + */ + +void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, int flags) +{ + struct gfs2_glock_operations *glops = gl->gl_ops; + + spin_lock(&gl->gl_spin); + + if (test_bit(GLF_LOCK, &gl->gl_flags) || + !list_empty(&gl->gl_holders) || + !list_empty(&gl->gl_waiters1) || + !list_empty(&gl->gl_waiters2) || + !list_empty(&gl->gl_waiters3) || + relaxed_state_ok(gl->gl_state, state, flags)) { + spin_unlock(&gl->gl_spin); + return; + } + + set_bit(GLF_PREFETCH, &gl->gl_flags); + set_bit(GLF_LOCK, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + + glops->go_xmote_th(gl, state, flags); + + atomic_inc(&gl->gl_sbd->sd_glock_prefetch_calls); +} + +/** + * gfs2_glock_force_drop - Force a glock to be uncached + * @gl: the glock + * + */ + +void gfs2_glock_force_drop(struct gfs2_glock *gl) +{ + struct gfs2_holder gh; + + gfs2_holder_init(gl, LM_ST_UNLOCKED, GL_NEVER_RECURSE, &gh); + set_bit(HIF_DEMOTE, &gh.gh_iflags); + + spin_lock(&gl->gl_spin); + list_add_tail(&gh.gh_list, &gl->gl_waiters2); + run_queue(gl); + spin_unlock(&gl->gl_spin); + + wait_for_completion(&gh.gh_wait); + gfs2_holder_uninit(&gh); +} + +static void greedy_work(void *data) +{ + struct greedy *gr = (struct greedy *)data; + struct gfs2_holder *gh = &gr->gr_gh; + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_glock_operations *glops = gl->gl_ops; + + clear_bit(GLF_SKIP_WAITERS2, &gl->gl_flags); + + if (glops->go_greedy) + glops->go_greedy(gl); + + spin_lock(&gl->gl_spin); + + if (list_empty(&gl->gl_waiters2)) { + clear_bit(GLF_GREEDY, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + gfs2_holder_uninit(gh); + kfree(gr); + } else { + gfs2_glock_hold(gl); + list_add_tail(&gh->gh_list, &gl->gl_waiters2); + run_queue(gl); + spin_unlock(&gl->gl_spin); + gfs2_glock_put(gl); + } +} + +/** + * gfs2_glock_be_greedy - + * @gl: + * @time: + * + * Returns: 0 if go_greedy will be called, 1 otherwise + */ + +int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time) +{ + struct greedy *gr; + struct gfs2_holder *gh; + + if (!time || + gl->gl_sbd->sd_args.ar_localcaching || + test_and_set_bit(GLF_GREEDY, &gl->gl_flags)) + return 1; + + gr = kmalloc(sizeof(struct greedy), GFP_KERNEL); + if (!gr) { + clear_bit(GLF_GREEDY, &gl->gl_flags); + return 1; + } + gh = &gr->gr_gh; + + gfs2_holder_init(gl, 0, GL_NEVER_RECURSE, gh); + set_bit(HIF_GREEDY, &gh->gh_iflags); + INIT_WORK(&gr->gr_work, greedy_work, gr); + + set_bit(GLF_SKIP_WAITERS2, &gl->gl_flags); + schedule_delayed_work(&gr->gr_work, time); + + return 0; +} + +/** + * gfs2_glock_nq_init - intialize a holder and enqueue it on a glock + * @gl: the glock + * @state: the state we're requesting + * @flags: the modifier flags + * @gh: the holder structure + * + * Returns: 0, GLR_*, or errno + */ + +int gfs2_glock_nq_init(struct gfs2_glock *gl, unsigned int state, int flags, + struct gfs2_holder *gh) +{ + int error; + + gfs2_holder_init(gl, state, flags, gh); + + error = gfs2_glock_nq(gh); + if (error) + gfs2_holder_uninit(gh); + + return error; +} + +/** + * gfs2_glock_dq_uninit - dequeue a holder from a glock and initialize it + * @gh: the holder structure + * + */ + +void gfs2_glock_dq_uninit(struct gfs2_holder *gh) +{ + gfs2_glock_dq(gh); + gfs2_holder_uninit(gh); +} + +/** + * gfs2_glock_nq_num - acquire a glock based on lock number + * @sdp: the filesystem + * @number: the lock number + * @glops: the glock operations for the type of glock + * @state: the state to acquire the glock in + * @flags: modifier flags for the aquisition + * @gh: the struct gfs2_holder + * + * Returns: errno + */ + +int gfs2_glock_nq_num(struct gfs2_sbd *sdp, uint64_t number, + struct gfs2_glock_operations *glops, unsigned int state, + int flags, struct gfs2_holder *gh) +{ + struct gfs2_glock *gl; + int error; + + error = gfs2_glock_get(sdp, number, glops, CREATE, &gl); + if (!error) { + error = gfs2_glock_nq_init(gl, state, flags, gh); + gfs2_glock_put(gl); + } + + return error; +} + +/** + * glock_compare - Compare two struct gfs2_glock structures for sorting + * @arg_a: the first structure + * @arg_b: the second structure + * + */ + +static int glock_compare(const void *arg_a, const void *arg_b) +{ + struct gfs2_holder *gh_a = *(struct gfs2_holder **)arg_a; + struct gfs2_holder *gh_b = *(struct gfs2_holder **)arg_b; + struct lm_lockname *a = &gh_a->gh_gl->gl_name; + struct lm_lockname *b = &gh_b->gh_gl->gl_name; + int ret = 0; + + if (a->ln_number > b->ln_number) + ret = 1; + else if (a->ln_number < b->ln_number) + ret = -1; + else { + if (gh_a->gh_state == LM_ST_SHARED && + gh_b->gh_state == LM_ST_EXCLUSIVE) + ret = 1; + else if (!(gh_a->gh_flags & GL_LOCAL_EXCL) && + (gh_b->gh_flags & GL_LOCAL_EXCL)) + ret = 1; + } + + return ret; +} + +/** + * nq_m_sync - synchonously acquire more than one glock in deadlock free order + * @num_gh: the number of structures + * @ghs: an array of struct gfs2_holder structures + * + * Returns: 0 on success (all glocks acquired), + * errno on failure (no glocks acquired) + */ + +static int nq_m_sync(unsigned int num_gh, struct gfs2_holder *ghs, + struct gfs2_holder **p) +{ + unsigned int x; + int error = 0; + + for (x = 0; x < num_gh; x++) + p[x] = &ghs[x]; + + sort(p, num_gh, sizeof(struct gfs2_holder *), glock_compare, NULL); + + for (x = 0; x < num_gh; x++) { + p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC); + + error = gfs2_glock_nq(p[x]); + if (error) { + while (x--) + gfs2_glock_dq(p[x]); + break; + } + } + + return error; +} + +/** + * gfs2_glock_nq_m - acquire multiple glocks + * @num_gh: the number of structures + * @ghs: an array of struct gfs2_holder structures + * + * Figure out how big an impact this function has. Either: + * 1) Replace this code with code that calls gfs2_glock_prefetch() + * 2) Forget async stuff and just call nq_m_sync() + * 3) Leave it like it is + * + * Returns: 0 on success (all glocks acquired), + * errno on failure (no glocks acquired) + */ + +int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs) +{ + int *e; + unsigned int x; + int borked = 0, serious = 0; + int error = 0; + + if (!num_gh) + return 0; + + if (num_gh == 1) { + ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC); + return gfs2_glock_nq(ghs); + } + + e = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL); + if (!e) + return -ENOMEM; + + for (x = 0; x < num_gh; x++) { + ghs[x].gh_flags |= LM_FLAG_TRY | GL_ASYNC; + error = gfs2_glock_nq(&ghs[x]); + if (error) { + borked = 1; + serious = error; + num_gh = x; + break; + } + } + + for (x = 0; x < num_gh; x++) { + error = e[x] = glock_wait_internal(&ghs[x]); + if (error) { + borked = 1; + if (error != GLR_TRYFAILED && error != GLR_CANCELED) + serious = error; + } + } + + if (!borked) { + kfree(e); + return 0; + } + + for (x = 0; x < num_gh; x++) + if (!e[x]) + gfs2_glock_dq(&ghs[x]); + + if (serious) + error = serious; + else { + for (x = 0; x < num_gh; x++) + gfs2_holder_reinit(ghs[x].gh_state, ghs[x].gh_flags, + &ghs[x]); + error = nq_m_sync(num_gh, ghs, (struct gfs2_holder **)e); + } + + kfree(e); + + return error; +} + +/** + * gfs2_glock_dq_m - release multiple glocks + * @num_gh: the number of structures + * @ghs: an array of struct gfs2_holder structures + * + */ + +void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs) +{ + unsigned int x; + + for (x = 0; x < num_gh; x++) + gfs2_glock_dq(&ghs[x]); +} + +/** + * gfs2_glock_dq_uninit_m - release multiple glocks + * @num_gh: the number of structures + * @ghs: an array of struct gfs2_holder structures + * + */ + +void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs) +{ + unsigned int x; + + for (x = 0; x < num_gh; x++) + gfs2_glock_dq_uninit(&ghs[x]); +} + +/** + * gfs2_glock_prefetch_num - prefetch a glock based on lock number + * @sdp: the filesystem + * @number: the lock number + * @glops: the glock operations for the type of glock + * @state: the state to acquire the glock in + * @flags: modifier flags for the aquisition + * + * Returns: errno + */ + +void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, uint64_t number, + struct gfs2_glock_operations *glops, + unsigned int state, int flags) +{ + struct gfs2_glock *gl; + int error; + + if (atomic_read(&sdp->sd_reclaim_count) < + gfs2_tune_get(sdp, gt_reclaim_limit)) { + error = gfs2_glock_get(sdp, number, glops, CREATE, &gl); + if (!error) { + gfs2_glock_prefetch(gl, state, flags); + gfs2_glock_put(gl); + } + } +} + +/** + * gfs2_lvb_hold - attach a LVB from a glock + * @gl: The glock in question + * + */ + +int gfs2_lvb_hold(struct gfs2_glock *gl) +{ + int error; + + gfs2_glmutex_lock(gl); + + if (!atomic_read(&gl->gl_lvb_count)) { + error = gfs2_lm_hold_lvb(gl->gl_sbd, gl->gl_lock, &gl->gl_lvb); + if (error) { + gfs2_glmutex_unlock(gl); + return error; + } + gfs2_glock_hold(gl); + } + atomic_inc(&gl->gl_lvb_count); + + gfs2_glmutex_unlock(gl); + + return 0; +} + +/** + * gfs2_lvb_unhold - detach a LVB from a glock + * @gl: The glock in question + * + */ + +void gfs2_lvb_unhold(struct gfs2_glock *gl) +{ + gfs2_glock_hold(gl); + gfs2_glmutex_lock(gl); + + gfs2_assert(gl->gl_sbd, atomic_read(&gl->gl_lvb_count) > 0); + if (atomic_dec_and_test(&gl->gl_lvb_count)) { + gfs2_lm_unhold_lvb(gl->gl_sbd, gl->gl_lock, gl->gl_lvb); + gl->gl_lvb = NULL; + gfs2_glock_put(gl); + } + + gfs2_glmutex_unlock(gl); + gfs2_glock_put(gl); +} + +void gfs2_lvb_sync(struct gfs2_glock *gl) +{ + gfs2_glmutex_lock(gl); + + gfs2_assert(gl->gl_sbd, atomic_read(&gl->gl_lvb_count)); + if (!gfs2_assert_warn(gl->gl_sbd, gfs2_glock_is_held_excl(gl))) + gfs2_lm_sync_lvb(gl->gl_sbd, gl->gl_lock, gl->gl_lvb); + + gfs2_glmutex_unlock(gl); +} + +static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, + unsigned int state) +{ + struct gfs2_glock *gl; + + gl = gfs2_glock_find(sdp, name); + if (!gl) + return; + + if (gl->gl_ops->go_callback) + gl->gl_ops->go_callback(gl, state); + handle_callback(gl, state); + + spin_lock(&gl->gl_spin); + run_queue(gl); + spin_unlock(&gl->gl_spin); + + gfs2_glock_put(gl); +} + +/** + * gfs2_glock_cb - Callback used by locking module + * @fsdata: Pointer to the superblock + * @type: Type of callback + * @data: Type dependent data pointer + * + * Called by the locking module when it wants to tell us something. + * Either we need to drop a lock, one of our ASYNC requests completed, or + * a journal from another client needs to be recovered. + */ + +void gfs2_glock_cb(lm_fsdata_t *fsdata, unsigned int type, void *data) +{ + struct gfs2_sbd *sdp = (struct gfs2_sbd *)fsdata; + + atomic_inc(&sdp->sd_lm_callbacks); + + switch (type) { + case LM_CB_NEED_E: + blocking_cb(sdp, (struct lm_lockname *)data, LM_ST_UNLOCKED); + return; + + case LM_CB_NEED_D: + blocking_cb(sdp, (struct lm_lockname *)data, LM_ST_DEFERRED); + return; + + case LM_CB_NEED_S: + blocking_cb(sdp, (struct lm_lockname *)data, LM_ST_SHARED); + return; + + case LM_CB_ASYNC: { + struct lm_async_cb *async = (struct lm_async_cb *)data; + struct gfs2_glock *gl; + + gl = gfs2_glock_find(sdp, &async->lc_name); + if (gfs2_assert_warn(sdp, gl)) + return; + if (!gfs2_assert_warn(sdp, gl->gl_req_bh)) + gl->gl_req_bh(gl, async->lc_ret); + gfs2_glock_put(gl); + + return; + } + + case LM_CB_NEED_RECOVERY: + gfs2_jdesc_make_dirty(sdp, *(unsigned int *)data); + if (sdp->sd_recoverd_process) + wake_up_process(sdp->sd_recoverd_process); + return; + + case LM_CB_DROPLOCKS: + gfs2_gl_hash_clear(sdp, NO_WAIT); + gfs2_quota_scan(sdp); + return; + + default: + gfs2_assert_warn(sdp, 0); + return; + } +} + +/** + * gfs2_try_toss_inode - try to remove a particular inode struct from cache + * sdp: the filesystem + * inum: the inode number + * + */ + +void gfs2_try_toss_inode(struct gfs2_sbd *sdp, struct gfs2_inum *inum) +{ + struct gfs2_glock *gl; + struct gfs2_inode *ip; + int error; + + error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_inode_glops, + NO_CREATE, &gl); + if (error || !gl) + return; + + if (!gfs2_glmutex_trylock(gl)) + goto out; + + ip = get_gl2ip(gl); + if (!ip) + goto out_unlock; + + if (atomic_read(&ip->i_count)) + goto out_unlock; + + gfs2_inode_destroy(ip); + + out_unlock: + gfs2_glmutex_unlock(gl); + + out: + gfs2_glock_put(gl); +} + +/** + * gfs2_iopen_go_callback - Try to kick the inode/vnode associated with an + * iopen glock from memory + * @io_gl: the iopen glock + * @state: the state into which the glock should be put + * + */ + +void gfs2_iopen_go_callback(struct gfs2_glock *io_gl, unsigned int state) +{ + struct gfs2_glock *i_gl; + + if (state != LM_ST_UNLOCKED) + return; + + spin_lock(&io_gl->gl_spin); + i_gl = get_gl2gl(io_gl); + if (i_gl) { + gfs2_glock_hold(i_gl); + spin_unlock(&io_gl->gl_spin); + } else { + spin_unlock(&io_gl->gl_spin); + return; + } + + if (gfs2_glmutex_trylock(i_gl)) { + struct gfs2_inode *ip = get_gl2ip(i_gl); + if (ip) { + gfs2_try_toss_vnode(ip); + gfs2_glmutex_unlock(i_gl); + gfs2_glock_schedule_for_reclaim(i_gl); + goto out; + } + gfs2_glmutex_unlock(i_gl); + } + + out: + gfs2_glock_put(i_gl); +} + +/** + * demote_ok - Check to see if it's ok to unlock a glock + * @gl: the glock + * + * Returns: 1 if it's ok + */ + +static int demote_ok(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_glock_operations *glops = gl->gl_ops; + int demote = 1; + + if (test_bit(GLF_STICKY, &gl->gl_flags)) + demote = 0; + else if (test_bit(GLF_PREFETCH, &gl->gl_flags)) + demote = time_after_eq(jiffies, + gl->gl_stamp + + gfs2_tune_get(sdp, gt_prefetch_secs) * HZ); + else if (glops->go_demote_ok) + demote = glops->go_demote_ok(gl); + + return demote; +} + +/** + * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list + * @gl: the glock + * + */ + +void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + + spin_lock(&sdp->sd_reclaim_lock); + if (list_empty(&gl->gl_reclaim)) { + gfs2_glock_hold(gl); + list_add(&gl->gl_reclaim, &sdp->sd_reclaim_list); + atomic_inc(&sdp->sd_reclaim_count); + } + spin_unlock(&sdp->sd_reclaim_lock); + + wake_up(&sdp->sd_reclaim_wq); +} + +/** + * gfs2_reclaim_glock - process the next glock on the filesystem's reclaim list + * @sdp: the filesystem + * + * Called from gfs2_glockd() glock reclaim daemon, or when promoting a + * different glock and we notice that there are a lot of glocks in the + * reclaim list. + * + */ + +void gfs2_reclaim_glock(struct gfs2_sbd *sdp) +{ + struct gfs2_glock *gl; + + spin_lock(&sdp->sd_reclaim_lock); + if (list_empty(&sdp->sd_reclaim_list)) { + spin_unlock(&sdp->sd_reclaim_lock); + return; + } + gl = list_entry(sdp->sd_reclaim_list.next, + struct gfs2_glock, gl_reclaim); + list_del_init(&gl->gl_reclaim); + spin_unlock(&sdp->sd_reclaim_lock); + + atomic_dec(&sdp->sd_reclaim_count); + atomic_inc(&sdp->sd_reclaimed); + + if (gfs2_glmutex_trylock(gl)) { + if (gl->gl_ops == &gfs2_inode_glops) { + struct gfs2_inode *ip = get_gl2ip(gl); + if (ip && !atomic_read(&ip->i_count)) + gfs2_inode_destroy(ip); + } + if (queue_empty(gl, &gl->gl_holders) && + gl->gl_state != LM_ST_UNLOCKED && + demote_ok(gl)) + handle_callback(gl, LM_ST_UNLOCKED); + gfs2_glmutex_unlock(gl); + } + + gfs2_glock_put(gl); +} + +/** + * examine_bucket - Call a function for glock in a hash bucket + * @examiner: the function + * @sdp: the filesystem + * @bucket: the bucket + * + * Returns: 1 if the bucket has entries + */ + +static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, + struct gfs2_gl_hash_bucket *bucket) +{ + struct glock_plug plug; + struct list_head *tmp; + struct gfs2_glock *gl; + int entries; + + /* Add "plug" to end of bucket list, work back up list from there */ + memset(&plug.gl_flags, 0, sizeof(unsigned long)); + set_bit(GLF_PLUG, &plug.gl_flags); + + write_lock(&bucket->hb_lock); + list_add(&plug.gl_list, &bucket->hb_list); + write_unlock(&bucket->hb_lock); + + for (;;) { + write_lock(&bucket->hb_lock); + + for (;;) { + tmp = plug.gl_list.next; + + if (tmp == &bucket->hb_list) { + list_del(&plug.gl_list); + entries = !list_empty(&bucket->hb_list); + write_unlock(&bucket->hb_lock); + return entries; + } + gl = list_entry(tmp, struct gfs2_glock, gl_list); + + /* Move plug up list */ + list_move(&plug.gl_list, &gl->gl_list); + + if (test_bit(GLF_PLUG, &gl->gl_flags)) + continue; + + /* examiner() must glock_put() */ + gfs2_glock_hold(gl); + + break; + } + + write_unlock(&bucket->hb_lock); + + examiner(gl); + } +} + +/** + * scan_glock - look at a glock and see if we can reclaim it + * @gl: the glock to look at + * + */ + +static void scan_glock(struct gfs2_glock *gl) +{ + if (gfs2_glmutex_trylock(gl)) { + if (gl->gl_ops == &gfs2_inode_glops) { + struct gfs2_inode *ip = get_gl2ip(gl); + if (ip && !atomic_read(&ip->i_count)) + goto out_schedule; + } + if (queue_empty(gl, &gl->gl_holders) && + gl->gl_state != LM_ST_UNLOCKED && + demote_ok(gl)) + goto out_schedule; + + gfs2_glmutex_unlock(gl); + } + + gfs2_glock_put(gl); + + return; + + out_schedule: + gfs2_glmutex_unlock(gl); + gfs2_glock_schedule_for_reclaim(gl); + gfs2_glock_put(gl); +} + +/** + * gfs2_scand_internal - Look for glocks and inodes to toss from memory + * @sdp: the filesystem + * + */ + +void gfs2_scand_internal(struct gfs2_sbd *sdp) +{ + unsigned int x; + + for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { + examine_bucket(scan_glock, sdp, &sdp->sd_gl_hash[x]); + cond_resched(); + } +} + +/** + * clear_glock - look at a glock and see if we can free it from glock cache + * @gl: the glock to look at + * + */ + +static void clear_glock(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + int released; + + spin_lock(&sdp->sd_reclaim_lock); + if (!list_empty(&gl->gl_reclaim)) { + list_del_init(&gl->gl_reclaim); + atomic_dec(&sdp->sd_reclaim_count); + released = gfs2_glock_put(gl); + gfs2_assert(sdp, !released); + } + spin_unlock(&sdp->sd_reclaim_lock); + + if (gfs2_glmutex_trylock(gl)) { + if (gl->gl_ops == &gfs2_inode_glops) { + struct gfs2_inode *ip = get_gl2ip(gl); + if (ip && !atomic_read(&ip->i_count)) + gfs2_inode_destroy(ip); + } + if (queue_empty(gl, &gl->gl_holders) && + gl->gl_state != LM_ST_UNLOCKED) + handle_callback(gl, LM_ST_UNLOCKED); + + gfs2_glmutex_unlock(gl); + } + + gfs2_glock_put(gl); +} + +/** + * gfs2_gl_hash_clear - Empty out the glock hash table + * @sdp: the filesystem + * @wait: wait until it's all gone + * + * Called when unmounting the filesystem, or when inter-node lock manager + * requests DROPLOCKS because it is running out of capacity. + */ + +void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) +{ + unsigned long t; + unsigned int x; + int cont; + + t = jiffies; + + for (;;) { + cont = 0; + + for (x = 0; x < GFS2_GL_HASH_SIZE; x++) + if (examine_bucket(clear_glock, sdp, + &sdp->sd_gl_hash[x])) + cont = 1; + + if (!wait || !cont) + break; + + if (time_after_eq(jiffies, + t + gfs2_tune_get(sdp, gt_stall_secs) * HZ)) { + fs_warn(sdp, "Unmount seems to be stalled. " + "Dumping lock state...\n"); + gfs2_dump_lockstate(sdp); + t = jiffies; + } + + /* invalidate_inodes() requires that the sb inodes list + not change, but an async completion callback for an + unlock can occur which does glock_put() which + can call iput() which will change the sb inodes list. + invalidate_inodes_mutex prevents glock_put()'s during + an invalidate_inodes() */ + + down(&sdp->sd_invalidate_inodes_mutex); + invalidate_inodes(sdp->sd_vfs); + up(&sdp->sd_invalidate_inodes_mutex); + yield(); + } +} + +/* + * Diagnostic routines to help debug distributed deadlock + */ + +/** + * dump_holder - print information about a glock holder + * @str: a string naming the type of holder + * @gh: the glock holder + * + * Returns: 0 on success, -ENOBUFS when we run out of space + */ + +static int dump_holder(char *str, struct gfs2_holder *gh) +{ + unsigned int x; + int error = -ENOBUFS; + + printk(" %s\n", str); + printk(" owner = %ld\n", + (gh->gh_owner) ? (long)gh->gh_owner->pid : -1); + printk(" gh_state = %u\n", gh->gh_state); + printk(" gh_flags ="); + for (x = 0; x < 32; x++) + if (gh->gh_flags & (1 << x)) + printk(" %u", x); + printk(" \n"); + printk(" error = %d\n", gh->gh_error); + printk(" gh_iflags ="); + for (x = 0; x < 32; x++) + if (test_bit(x, &gh->gh_iflags)) + printk(" %u", x); + printk(" \n"); + + error = 0; + + return error; +} + +/** + * dump_inode - print information about an inode + * @ip: the inode + * + * Returns: 0 on success, -ENOBUFS when we run out of space + */ + +static int dump_inode(struct gfs2_inode *ip) +{ + unsigned int x; + int error = -ENOBUFS; + + printk(" Inode:\n"); + printk(" num = %llu %llu\n", + ip->i_num.no_formal_ino, ip->i_num.no_addr); + printk(" type = %u\n", IF2DT(ip->i_di.di_mode)); + printk(" i_count = %d\n", atomic_read(&ip->i_count)); + printk(" i_flags ="); + for (x = 0; x < 32; x++) + if (test_bit(x, &ip->i_flags)) + printk(" %u", x); + printk(" \n"); + printk(" vnode = %s\n", (ip->i_vnode) ? "yes" : "no"); + + error = 0; + + return error; +} + +/** + * dump_glock - print information about a glock + * @gl: the glock + * @count: where we are in the buffer + * + * Returns: 0 on success, -ENOBUFS when we run out of space + */ + +static int dump_glock(struct gfs2_glock *gl) +{ + struct gfs2_holder *gh; + unsigned int x; + int error = -ENOBUFS; + + spin_lock(&gl->gl_spin); + + printk("Glock (%u, %llu)\n", + gl->gl_name.ln_type, + gl->gl_name.ln_number); + printk(" gl_flags ="); + for (x = 0; x < 32; x++) + if (test_bit(x, &gl->gl_flags)) + printk(" %u", x); + printk(" \n"); + printk(" gl_ref = %d\n", atomic_read(&gl->gl_ref.refcount)); + printk(" gl_state = %u\n", gl->gl_state); + printk(" req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no"); + printk(" req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no"); + printk(" lvb_count = %d\n", atomic_read(&gl->gl_lvb_count)); + printk(" object = %s\n", (gl->gl_object) ? "yes" : "no"); + printk(" le = %s\n", + (list_empty(&gl->gl_le.le_list)) ? "no" : "yes"); + printk(" reclaim = %s\n", + (list_empty(&gl->gl_reclaim)) ? "no" : "yes"); + if (gl->gl_aspace) + printk(" aspace = %lu\n", + gl->gl_aspace->i_mapping->nrpages); + else + printk(" aspace = no\n"); + printk(" ail = %d\n", atomic_read(&gl->gl_ail_count)); + if (gl->gl_req_gh) { + error = dump_holder("Request", gl->gl_req_gh); + if (error) + goto out; + } + list_for_each_entry(gh, &gl->gl_holders, gh_list) { + error = dump_holder("Holder", gh); + if (error) + goto out; + } + list_for_each_entry(gh, &gl->gl_waiters1, gh_list) { + error = dump_holder("Waiter1", gh); + if (error) + goto out; + } + list_for_each_entry(gh, &gl->gl_waiters2, gh_list) { + error = dump_holder("Waiter2", gh); + if (error) + goto out; + } + list_for_each_entry(gh, &gl->gl_waiters3, gh_list) { + error = dump_holder("Waiter3", gh); + if (error) + goto out; + } + if (gl->gl_ops == &gfs2_inode_glops && get_gl2ip(gl)) { + if (!test_bit(GLF_LOCK, &gl->gl_flags) && + list_empty(&gl->gl_holders)) { + error = dump_inode(get_gl2ip(gl)); + if (error) + goto out; + } else { + error = -ENOBUFS; + printk(" Inode: busy\n"); + } + } + + error = 0; + + out: + spin_unlock(&gl->gl_spin); + + return error; +} + +/** + * gfs2_dump_lockstate - print out the current lockstate + * @sdp: the filesystem + * @ub: the buffer to copy the information into + * + * If @ub is NULL, dump the lockstate to the console. + * + */ + +int gfs2_dump_lockstate(struct gfs2_sbd *sdp) +{ + struct gfs2_gl_hash_bucket *bucket; + struct gfs2_glock *gl; + unsigned int x; + int error = 0; + + for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { + bucket = &sdp->sd_gl_hash[x]; + + read_lock(&bucket->hb_lock); + + list_for_each_entry(gl, &bucket->hb_list, gl_list) { + if (test_bit(GLF_PLUG, &gl->gl_flags)) + continue; + + error = dump_glock(gl); + if (error) + break; + } + + read_unlock(&bucket->hb_lock); + + if (error) + break; + } + + + return error; +} + diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h new file mode 100644 index 000000000000..06847ebebdee --- /dev/null +++ b/fs/gfs2/glock.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __GLOCK_DOT_H__ +#define __GLOCK_DOT_H__ + +/* Flags for lock requests; used in gfs2_holder gh_flag field. + From lm_interface.h: +#define LM_FLAG_TRY 0x00000001 +#define LM_FLAG_TRY_1CB 0x00000002 +#define LM_FLAG_NOEXP 0x00000004 +#define LM_FLAG_ANY 0x00000008 +#define LM_FLAG_PRIORITY 0x00000010 */ + +#define GL_LOCAL_EXCL 0x00000020 +#define GL_ASYNC 0x00000040 +#define GL_EXACT 0x00000080 +#define GL_SKIP 0x00000100 +#define GL_ATIME 0x00000200 +#define GL_NOCACHE 0x00000400 +#define GL_SYNC 0x00000800 +#define GL_NOCANCEL 0x00001000 +#define GL_NEVER_RECURSE 0x00002000 + +#define GLR_TRYFAILED 13 +#define GLR_CANCELED 14 + +static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) +{ + struct gfs2_holder *gh; + int locked = 0; + + /* Look in glock's list of holders for one with current task as owner */ + spin_lock(&gl->gl_spin); + list_for_each_entry(gh, &gl->gl_holders, gh_list) { + if (gh->gh_owner == current) { + locked = 1; + break; + } + } + spin_unlock(&gl->gl_spin); + + return locked; +} + +static inline int gfs2_glock_is_held_excl(struct gfs2_glock *gl) +{ + return (gl->gl_state == LM_ST_EXCLUSIVE); +} + +static inline int gfs2_glock_is_held_dfrd(struct gfs2_glock *gl) +{ + return (gl->gl_state == LM_ST_DEFERRED); +} + +static inline int gfs2_glock_is_held_shrd(struct gfs2_glock *gl) +{ + return (gl->gl_state == LM_ST_SHARED); +} + +static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) +{ + int ret; + spin_lock(&gl->gl_spin); + ret = !list_empty(&gl->gl_waiters2) || !list_empty(&gl->gl_waiters3); + spin_unlock(&gl->gl_spin); + return ret; +} + +struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, + struct lm_lockname *name); +int gfs2_glock_get(struct gfs2_sbd *sdp, + uint64_t number, struct gfs2_glock_operations *glops, + int create, struct gfs2_glock **glp); +void gfs2_glock_hold(struct gfs2_glock *gl); +int gfs2_glock_put(struct gfs2_glock *gl); + +void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, int flags, + struct gfs2_holder *gh); +void gfs2_holder_reinit(unsigned int state, int flags, struct gfs2_holder *gh); +void gfs2_holder_uninit(struct gfs2_holder *gh); +struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl, unsigned int state, + int flags, gfp_t gfp_flags); +void gfs2_holder_put(struct gfs2_holder *gh); + +void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags); +void gfs2_glock_drop_th(struct gfs2_glock *gl); + +void gfs2_glmutex_lock(struct gfs2_glock *gl); +int gfs2_glmutex_trylock(struct gfs2_glock *gl); +void gfs2_glmutex_unlock(struct gfs2_glock *gl); + +int gfs2_glock_nq(struct gfs2_holder *gh); +int gfs2_glock_poll(struct gfs2_holder *gh); +int gfs2_glock_wait(struct gfs2_holder *gh); +void gfs2_glock_dq(struct gfs2_holder *gh); + +void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, int flags); +void gfs2_glock_force_drop(struct gfs2_glock *gl); + +int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time); + +int gfs2_glock_nq_init(struct gfs2_glock *gl, unsigned int state, int flags, + struct gfs2_holder *gh); +void gfs2_glock_dq_uninit(struct gfs2_holder *gh); +int gfs2_glock_nq_num(struct gfs2_sbd *sdp, + uint64_t number, struct gfs2_glock_operations *glops, + unsigned int state, int flags, struct gfs2_holder *gh); + +int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs); +void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs); +void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs); + +void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, uint64_t number, + struct gfs2_glock_operations *glops, + unsigned int state, int flags); + +/* Lock Value Block functions */ + +int gfs2_lvb_hold(struct gfs2_glock *gl); +void gfs2_lvb_unhold(struct gfs2_glock *gl); +void gfs2_lvb_sync(struct gfs2_glock *gl); + +void gfs2_glock_cb(lm_fsdata_t *fsdata, unsigned int type, void *data); + +void gfs2_try_toss_inode(struct gfs2_sbd *sdp, struct gfs2_inum *inum); +void gfs2_iopen_go_callback(struct gfs2_glock *gl, unsigned int state); + +void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl); +void gfs2_reclaim_glock(struct gfs2_sbd *sdp); + +void gfs2_scand_internal(struct gfs2_sbd *sdp); +void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait); + +int gfs2_dump_lockstate(struct gfs2_sbd *sdp); + +#endif /* __GLOCK_DOT_H__ */ diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c new file mode 100644 index 000000000000..127008146a57 --- /dev/null +++ b/fs/gfs2/glops.c @@ -0,0 +1,487 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "log.h" +#include "meta_io.h" +#include "page.h" +#include "recovery.h" +#include "rgrp.h" + +/** + * meta_go_sync - sync out the metadata for this glock + * @gl: the glock + * @flags: DIO_* + * + * Called when demoting or unlocking an EX glock. We must flush + * to disk all dirty buffers/pages relating to this glock, and must not + * not return to caller to demote/unlock the glock until I/O is complete. + */ + +static void meta_go_sync(struct gfs2_glock *gl, int flags) +{ + if (!(flags & DIO_METADATA)) + return; + + if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) { + gfs2_log_flush_glock(gl); + gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); + if (flags & DIO_RELEASE) + gfs2_ail_empty_gl(gl); + } + + clear_bit(GLF_SYNC, &gl->gl_flags); +} + +/** + * meta_go_inval - invalidate the metadata for this glock + * @gl: the glock + * @flags: + * + */ + +static void meta_go_inval(struct gfs2_glock *gl, int flags) +{ + if (!(flags & DIO_METADATA)) + return; + + gfs2_meta_inval(gl); + gl->gl_vn++; +} + +/** + * meta_go_demote_ok - Check to see if it's ok to unlock a glock + * @gl: the glock + * + * Returns: 1 if we have no cached data; ok to demote meta glock + */ + +static int meta_go_demote_ok(struct gfs2_glock *gl) +{ + return !gl->gl_aspace->i_mapping->nrpages; +} + +/** + * inode_go_xmote_th - promote/demote a glock + * @gl: the glock + * @state: the requested state + * @flags: + * + */ + +static void inode_go_xmote_th(struct gfs2_glock *gl, unsigned int state, + int flags) +{ + if (gl->gl_state != LM_ST_UNLOCKED) + gfs2_pte_inval(gl); + gfs2_glock_xmote_th(gl, state, flags); +} + +/** + * inode_go_xmote_bh - After promoting/demoting a glock + * @gl: the glock + * + */ + +static void inode_go_xmote_bh(struct gfs2_glock *gl) +{ + struct gfs2_holder *gh = gl->gl_req_gh; + struct buffer_head *bh; + int error; + + if (gl->gl_state != LM_ST_UNLOCKED && + (!gh || !(gh->gh_flags & GL_SKIP))) { + error = gfs2_meta_read(gl, gl->gl_name.ln_number, DIO_START, + &bh); + if (!error) + brelse(bh); + } +} + +/** + * inode_go_drop_th - unlock a glock + * @gl: the glock + * + * Invoked from rq_demote(). + * Another node needs the lock in EXCLUSIVE mode, or lock (unused for too long) + * is being purged from our node's glock cache; we're dropping lock. + */ + +static void inode_go_drop_th(struct gfs2_glock *gl) +{ + gfs2_pte_inval(gl); + gfs2_glock_drop_th(gl); +} + +/** + * inode_go_sync - Sync the dirty data and/or metadata for an inode glock + * @gl: the glock protecting the inode + * @flags: + * + */ + +static void inode_go_sync(struct gfs2_glock *gl, int flags) +{ + int meta = (flags & DIO_METADATA); + int data = (flags & DIO_DATA); + + if (test_bit(GLF_DIRTY, &gl->gl_flags)) { + if (meta && data) { + gfs2_page_sync(gl, flags | DIO_START); + gfs2_log_flush_glock(gl); + gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); + gfs2_page_sync(gl, flags | DIO_WAIT); + clear_bit(GLF_DIRTY, &gl->gl_flags); + } else if (meta) { + gfs2_log_flush_glock(gl); + gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); + } else if (data) + gfs2_page_sync(gl, flags | DIO_START | DIO_WAIT); + if (flags & DIO_RELEASE) + gfs2_ail_empty_gl(gl); + } + + clear_bit(GLF_SYNC, &gl->gl_flags); +} + +/** + * inode_go_inval - prepare a inode glock to be released + * @gl: the glock + * @flags: + * + */ + +static void inode_go_inval(struct gfs2_glock *gl, int flags) +{ + int meta = (flags & DIO_METADATA); + int data = (flags & DIO_DATA); + + if (meta) { + gfs2_meta_inval(gl); + gl->gl_vn++; + } + if (data) + gfs2_page_inval(gl); +} + +/** + * inode_go_demote_ok - Check to see if it's ok to unlock an inode glock + * @gl: the glock + * + * Returns: 1 if it's ok + */ + +static int inode_go_demote_ok(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + int demote = 0; + + if (!get_gl2ip(gl) && !gl->gl_aspace->i_mapping->nrpages) + demote = 1; + else if (!sdp->sd_args.ar_localcaching && + time_after_eq(jiffies, gl->gl_stamp + + gfs2_tune_get(sdp, gt_demote_secs) * HZ)) + demote = 1; + + return demote; +} + +/** + * inode_go_lock - operation done after an inode lock is locked by a process + * @gl: the glock + * @flags: + * + * Returns: errno + */ + +static int inode_go_lock(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_inode *ip = get_gl2ip(gl); + int error = 0; + + if (!ip) + return 0; + + if (ip->i_vn != gl->gl_vn) { + error = gfs2_inode_refresh(ip); + if (error) + return error; + gfs2_inode_attr_in(ip); + } + + if ((ip->i_di.di_flags & GFS2_DIF_TRUNC_IN_PROG) && + (gl->gl_state == LM_ST_EXCLUSIVE) && + (gh->gh_flags & GL_LOCAL_EXCL)) + error = gfs2_truncatei_resume(ip); + + return error; +} + +/** + * inode_go_unlock - operation done before an inode lock is unlocked by a + * process + * @gl: the glock + * @flags: + * + */ + +static void inode_go_unlock(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_inode *ip = get_gl2ip(gl); + + if (ip && test_bit(GLF_DIRTY, &gl->gl_flags)) + gfs2_inode_attr_in(ip); + + if (ip) + gfs2_meta_cache_flush(ip); +} + +/** + * inode_greedy - + * @gl: the glock + * + */ + +static void inode_greedy(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_inode *ip = get_gl2ip(gl); + unsigned int quantum = gfs2_tune_get(sdp, gt_greedy_quantum); + unsigned int max = gfs2_tune_get(sdp, gt_greedy_max); + unsigned int new_time; + + spin_lock(&ip->i_spin); + + if (time_after(ip->i_last_pfault + quantum, jiffies)) { + new_time = ip->i_greedy + quantum; + if (new_time > max) + new_time = max; + } else { + new_time = ip->i_greedy - quantum; + if (!new_time || new_time > max) + new_time = 1; + } + + ip->i_greedy = new_time; + + spin_unlock(&ip->i_spin); + + gfs2_inode_put(ip); +} + +/** + * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock + * @gl: the glock + * + * Returns: 1 if it's ok + */ + +static int rgrp_go_demote_ok(struct gfs2_glock *gl) +{ + return !gl->gl_aspace->i_mapping->nrpages; +} + +/** + * rgrp_go_lock - operation done after an rgrp lock is locked by + * a first holder on this node. + * @gl: the glock + * @flags: + * + * Returns: errno + */ + +static int rgrp_go_lock(struct gfs2_holder *gh) +{ + return gfs2_rgrp_bh_get(get_gl2rgd(gh->gh_gl)); +} + +/** + * rgrp_go_unlock - operation done before an rgrp lock is unlocked by + * a last holder on this node. + * @gl: the glock + * @flags: + * + */ + +static void rgrp_go_unlock(struct gfs2_holder *gh) +{ + gfs2_rgrp_bh_put(get_gl2rgd(gh->gh_gl)); +} + +/** + * trans_go_xmote_th - promote/demote the transaction glock + * @gl: the glock + * @state: the requested state + * @flags: + * + */ + +static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state, + int flags) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + + if (gl->gl_state != LM_ST_UNLOCKED && + test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { + gfs2_meta_syncfs(sdp); + gfs2_log_shutdown(sdp); + } + + gfs2_glock_xmote_th(gl, state, flags); +} + +/** + * trans_go_xmote_bh - After promoting/demoting the transaction glock + * @gl: the glock + * + */ + +static void trans_go_xmote_bh(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_glock *j_gl = sdp->sd_jdesc->jd_inode->i_gl; + struct gfs2_log_header head; + int error; + + if (gl->gl_state != LM_ST_UNLOCKED && + test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { + gfs2_meta_cache_flush(sdp->sd_jdesc->jd_inode); + j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA); + + error = gfs2_find_jhead(sdp->sd_jdesc, &head); + if (error) + gfs2_consist(sdp); + if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) + gfs2_consist(sdp); + + /* Initialize some head of the log stuff */ + if (!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) { + sdp->sd_log_sequence = head.lh_sequence + 1; + gfs2_log_pointers_init(sdp, head.lh_blkno); + } + } +} + +/** + * trans_go_drop_th - unlock the transaction glock + * @gl: the glock + * + * We want to sync the device even with localcaching. Remember + * that localcaching journal replay only marks buffers dirty. + */ + +static void trans_go_drop_th(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + + if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { + gfs2_meta_syncfs(sdp); + gfs2_log_shutdown(sdp); + } + + gfs2_glock_drop_th(gl); +} + +/** + * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock + * @gl: the glock + * + * Returns: 1 if it's ok + */ + +static int quota_go_demote_ok(struct gfs2_glock *gl) +{ + return !atomic_read(&gl->gl_lvb_count); +} + +struct gfs2_glock_operations gfs2_meta_glops = { + .go_xmote_th = gfs2_glock_xmote_th, + .go_drop_th = gfs2_glock_drop_th, + .go_sync = meta_go_sync, + .go_inval = meta_go_inval, + .go_demote_ok = meta_go_demote_ok, + .go_type = LM_TYPE_META +}; + +struct gfs2_glock_operations gfs2_inode_glops = { + .go_xmote_th = inode_go_xmote_th, + .go_xmote_bh = inode_go_xmote_bh, + .go_drop_th = inode_go_drop_th, + .go_sync = inode_go_sync, + .go_inval = inode_go_inval, + .go_demote_ok = inode_go_demote_ok, + .go_lock = inode_go_lock, + .go_unlock = inode_go_unlock, + .go_greedy = inode_greedy, + .go_type = LM_TYPE_INODE +}; + +struct gfs2_glock_operations gfs2_rgrp_glops = { + .go_xmote_th = gfs2_glock_xmote_th, + .go_drop_th = gfs2_glock_drop_th, + .go_sync = meta_go_sync, + .go_inval = meta_go_inval, + .go_demote_ok = rgrp_go_demote_ok, + .go_lock = rgrp_go_lock, + .go_unlock = rgrp_go_unlock, + .go_type = LM_TYPE_RGRP +}; + +struct gfs2_glock_operations gfs2_trans_glops = { + .go_xmote_th = trans_go_xmote_th, + .go_xmote_bh = trans_go_xmote_bh, + .go_drop_th = trans_go_drop_th, + .go_type = LM_TYPE_NONDISK +}; + +struct gfs2_glock_operations gfs2_iopen_glops = { + .go_xmote_th = gfs2_glock_xmote_th, + .go_drop_th = gfs2_glock_drop_th, + .go_callback = gfs2_iopen_go_callback, + .go_type = LM_TYPE_IOPEN +}; + +struct gfs2_glock_operations gfs2_flock_glops = { + .go_xmote_th = gfs2_glock_xmote_th, + .go_drop_th = gfs2_glock_drop_th, + .go_type = LM_TYPE_FLOCK +}; + +struct gfs2_glock_operations gfs2_nondisk_glops = { + .go_xmote_th = gfs2_glock_xmote_th, + .go_drop_th = gfs2_glock_drop_th, + .go_type = LM_TYPE_NONDISK +}; + +struct gfs2_glock_operations gfs2_quota_glops = { + .go_xmote_th = gfs2_glock_xmote_th, + .go_drop_th = gfs2_glock_drop_th, + .go_demote_ok = quota_go_demote_ok, + .go_type = LM_TYPE_QUOTA +}; + +struct gfs2_glock_operations gfs2_journal_glops = { + .go_xmote_th = gfs2_glock_xmote_th, + .go_drop_th = gfs2_glock_drop_th, + .go_type = LM_TYPE_JOURNAL +}; + diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h new file mode 100644 index 000000000000..94f2d264aa64 --- /dev/null +++ b/fs/gfs2/glops.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __GLOPS_DOT_H__ +#define __GLOPS_DOT_H__ + +extern struct gfs2_glock_operations gfs2_meta_glops; +extern struct gfs2_glock_operations gfs2_inode_glops; +extern struct gfs2_glock_operations gfs2_rgrp_glops; +extern struct gfs2_glock_operations gfs2_trans_glops; +extern struct gfs2_glock_operations gfs2_iopen_glops; +extern struct gfs2_glock_operations gfs2_flock_glops; +extern struct gfs2_glock_operations gfs2_nondisk_glops; +extern struct gfs2_glock_operations gfs2_quota_glops; +extern struct gfs2_glock_operations gfs2_journal_glops; + +#endif /* __GLOPS_DOT_H__ */ diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h new file mode 100644 index 000000000000..3ed0a7f26e45 --- /dev/null +++ b/fs/gfs2/incore.h @@ -0,0 +1,703 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __INCORE_DOT_H__ +#define __INCORE_DOT_H__ + +#define DIO_FORCE 0x00000001 +#define DIO_CLEAN 0x00000002 +#define DIO_DIRTY 0x00000004 +#define DIO_START 0x00000008 +#define DIO_WAIT 0x00000010 +#define DIO_METADATA 0x00000020 +#define DIO_DATA 0x00000040 +#define DIO_RELEASE 0x00000080 +#define DIO_ALL 0x00000100 + +struct gfs2_log_operations; +struct gfs2_log_element; +struct gfs2_bitmap; +struct gfs2_rgrpd; +struct gfs2_bufdata; +struct gfs2_databuf; +struct gfs2_glock_operations; +struct gfs2_holder; +struct gfs2_glock; +struct gfs2_alloc; +struct gfs2_inode; +struct gfs2_file; +struct gfs2_revoke; +struct gfs2_revoke_replay; +struct gfs2_unlinked; +struct gfs2_quota_data; +struct gfs2_log_buf; +struct gfs2_trans; +struct gfs2_ail; +struct gfs2_jdesc; +struct gfs2_args; +struct gfs2_tune; +struct gfs2_gl_hash_bucket; +struct gfs2_sbd; + +typedef void (*gfs2_glop_bh_t) (struct gfs2_glock *gl, unsigned int ret); + +/* + * Structure of operations that are associated with each + * type of element in the log. + */ + +struct gfs2_log_operations { + void (*lo_add) (struct gfs2_sbd *sdp, struct gfs2_log_element *le); + void (*lo_incore_commit) (struct gfs2_sbd *sdp, struct gfs2_trans *tr); + void (*lo_before_commit) (struct gfs2_sbd *sdp); + void (*lo_after_commit) (struct gfs2_sbd *sdp, struct gfs2_ail *ai); + void (*lo_before_scan) (struct gfs2_jdesc *jd, + struct gfs2_log_header *head, int pass); + int (*lo_scan_elements) (struct gfs2_jdesc *jd, unsigned int start, + struct gfs2_log_descriptor *ld, __be64 *ptr, + int pass); + void (*lo_after_scan) (struct gfs2_jdesc *jd, int error, int pass); + char *lo_name; +}; + +struct gfs2_log_element { + struct list_head le_list; + struct gfs2_log_operations *le_ops; +}; + +struct gfs2_bitmap { + struct buffer_head *bi_bh; + char *bi_clone; + uint32_t bi_offset; + uint32_t bi_start; + uint32_t bi_len; +}; + +struct gfs2_rgrpd { + struct list_head rd_list; /* Link with superblock */ + struct list_head rd_list_mru; + struct list_head rd_recent; /* Recently used rgrps */ + struct gfs2_glock *rd_gl; /* Glock for this rgrp */ + struct gfs2_rindex rd_ri; + struct gfs2_rgrp rd_rg; + uint64_t rd_rg_vn; + struct gfs2_bitmap *rd_bits; + unsigned int rd_bh_count; + struct semaphore rd_mutex; + uint32_t rd_free_clone; + struct gfs2_log_element rd_le; + uint32_t rd_last_alloc_data; + uint32_t rd_last_alloc_meta; + struct gfs2_sbd *rd_sbd; +}; + +enum gfs2_state_bits { + BH_Pinned = BH_PrivateStart, +}; + +BUFFER_FNS(Pinned, pinned) +TAS_BUFFER_FNS(Pinned, pinned) + +struct gfs2_bufdata { + struct buffer_head *bd_bh; + struct gfs2_glock *bd_gl; + + struct list_head bd_list_tr; + struct gfs2_log_element bd_le; + + struct gfs2_ail *bd_ail; + struct list_head bd_ail_st_list; + struct list_head bd_ail_gl_list; +}; + +struct gfs2_databuf { + struct gfs2_log_element db_le; + struct buffer_head *db_bh; +}; + +struct gfs2_glock_operations { + void (*go_xmote_th) (struct gfs2_glock * gl, unsigned int state, + int flags); + void (*go_xmote_bh) (struct gfs2_glock * gl); + void (*go_drop_th) (struct gfs2_glock * gl); + void (*go_drop_bh) (struct gfs2_glock * gl); + void (*go_sync) (struct gfs2_glock * gl, int flags); + void (*go_inval) (struct gfs2_glock * gl, int flags); + int (*go_demote_ok) (struct gfs2_glock * gl); + int (*go_lock) (struct gfs2_holder * gh); + void (*go_unlock) (struct gfs2_holder * gh); + void (*go_callback) (struct gfs2_glock * gl, unsigned int state); + void (*go_greedy) (struct gfs2_glock * gl); + int go_type; +}; + +enum { + /* Actions */ + HIF_MUTEX = 0, + HIF_PROMOTE = 1, + HIF_DEMOTE = 2, + HIF_GREEDY = 3, + + /* States */ + HIF_ALLOCED = 4, + HIF_DEALLOC = 5, + HIF_HOLDER = 6, + HIF_FIRST = 7, + HIF_RECURSE = 8, + HIF_ABORTED = 9, +}; + +struct gfs2_holder { + struct list_head gh_list; + + struct gfs2_glock *gh_gl; + struct task_struct *gh_owner; + unsigned int gh_state; + int gh_flags; + + int gh_error; + unsigned long gh_iflags; + struct completion gh_wait; +}; + +enum { + GLF_PLUG = 0, + GLF_LOCK = 1, + GLF_STICKY = 2, + GLF_PREFETCH = 3, + GLF_SYNC = 4, + GLF_DIRTY = 5, + GLF_SKIP_WAITERS2 = 6, + GLF_GREEDY = 7, +}; + +struct gfs2_glock { + struct list_head gl_list; + unsigned long gl_flags; /* GLF_... */ + struct lm_lockname gl_name; + struct kref gl_ref; + + spinlock_t gl_spin; + + unsigned int gl_state; + struct list_head gl_holders; + struct list_head gl_waiters1; /* HIF_MUTEX */ + struct list_head gl_waiters2; /* HIF_DEMOTE, HIF_GREEDY */ + struct list_head gl_waiters3; /* HIF_PROMOTE */ + + struct gfs2_glock_operations *gl_ops; + + struct gfs2_holder *gl_req_gh; + gfs2_glop_bh_t gl_req_bh; + + lm_lock_t *gl_lock; + char *gl_lvb; + atomic_t gl_lvb_count; + + uint64_t gl_vn; + unsigned long gl_stamp; + void *gl_object; + + struct gfs2_gl_hash_bucket *gl_bucket; + struct list_head gl_reclaim; + + struct gfs2_sbd *gl_sbd; + + struct inode *gl_aspace; + struct gfs2_log_element gl_le; + struct list_head gl_ail_list; + atomic_t gl_ail_count; +}; + +struct gfs2_alloc { + /* Quota stuff */ + + unsigned int al_qd_num; + struct gfs2_quota_data *al_qd[4]; + struct gfs2_holder al_qd_ghs[4]; + + /* Filled in by the caller to gfs2_inplace_reserve() */ + + uint32_t al_requested; + + /* Filled in by gfs2_inplace_reserve() */ + + char *al_file; + unsigned int al_line; + struct gfs2_holder al_ri_gh; + struct gfs2_holder al_rgd_gh; + struct gfs2_rgrpd *al_rgd; + + /* Filled in by gfs2_alloc_*() */ + + uint32_t al_alloced; +}; + +enum { + GIF_MIN_INIT = 0, + GIF_QD_LOCKED = 1, + GIF_PAGED = 2, + GIF_SW_PAGED = 3, +}; + +struct gfs2_inode { + struct gfs2_inum i_num; + + atomic_t i_count; + unsigned long i_flags; /* GIF_... */ + + uint64_t i_vn; + struct gfs2_dinode i_di; + + struct gfs2_glock *i_gl; + struct gfs2_sbd *i_sbd; + struct inode *i_vnode; + + struct gfs2_holder i_iopen_gh; + + struct gfs2_alloc i_alloc; + uint64_t i_last_rg_alloc; + + spinlock_t i_spin; + struct rw_semaphore i_rw_mutex; + + unsigned int i_greedy; + unsigned long i_last_pfault; + + struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT]; +}; + +enum { + GFF_DID_DIRECT_ALLOC = 0, +}; + +struct gfs2_file { + unsigned long f_flags; /* GFF_... */ + + struct semaphore f_fl_mutex; + struct gfs2_holder f_fl_gh; + + struct gfs2_inode *f_inode; + struct file *f_vfile; +}; + +struct gfs2_revoke { + struct gfs2_log_element rv_le; + uint64_t rv_blkno; +}; + +struct gfs2_revoke_replay { + struct list_head rr_list; + uint64_t rr_blkno; + unsigned int rr_where; +}; + +enum { + ULF_LOCKED = 0, +}; + +struct gfs2_unlinked { + struct list_head ul_list; + unsigned int ul_count; + struct gfs2_unlinked_tag ul_ut; + unsigned long ul_flags; /* ULF_... */ + unsigned int ul_slot; +}; + +enum { + QDF_USER = 0, + QDF_CHANGE = 1, + QDF_LOCKED = 2, +}; + +struct gfs2_quota_data { + struct list_head qd_list; + unsigned int qd_count; + + uint32_t qd_id; + unsigned long qd_flags; /* QDF_... */ + + int64_t qd_change; + int64_t qd_change_sync; + + unsigned int qd_slot; + unsigned int qd_slot_count; + + struct buffer_head *qd_bh; + struct gfs2_quota_change *qd_bh_qc; + unsigned int qd_bh_count; + + struct gfs2_glock *qd_gl; + struct gfs2_quota_lvb qd_qb; + + uint64_t qd_sync_gen; + unsigned long qd_last_warn; + unsigned long qd_last_touched; +}; + +struct gfs2_log_buf { + struct list_head lb_list; + struct buffer_head *lb_bh; + struct buffer_head *lb_real; +}; + +struct gfs2_trans { + char *tr_file; + unsigned int tr_line; + + unsigned int tr_blocks; + unsigned int tr_revokes; + unsigned int tr_reserved; + + struct gfs2_holder *tr_t_gh; + + int tr_touched; + + unsigned int tr_num_buf; + unsigned int tr_num_buf_new; + unsigned int tr_num_buf_rm; + struct list_head tr_list_buf; + + unsigned int tr_num_revoke; + unsigned int tr_num_revoke_rm; +}; + +struct gfs2_ail { + struct list_head ai_list; + + unsigned int ai_first; + struct list_head ai_ail1_list; + struct list_head ai_ail2_list; + + uint64_t ai_sync_gen; +}; + +struct gfs2_jdesc { + struct list_head jd_list; + + struct gfs2_inode *jd_inode; + unsigned int jd_jid; + int jd_dirty; + + unsigned int jd_blocks; +}; + +#define GFS2_GLOCKD_DEFAULT 1 +#define GFS2_GLOCKD_MAX 16 + +#define GFS2_QUOTA_DEFAULT GFS2_QUOTA_OFF +#define GFS2_QUOTA_OFF 0 +#define GFS2_QUOTA_ACCOUNT 1 +#define GFS2_QUOTA_ON 2 + +#define GFS2_DATA_DEFAULT GFS2_DATA_ORDERED +#define GFS2_DATA_WRITEBACK 1 +#define GFS2_DATA_ORDERED 2 + +struct gfs2_args { + char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */ + char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */ + char ar_hostdata[GFS2_LOCKNAME_LEN]; /* Host specific data */ + int ar_spectator; /* Don't get a journal because we're always RO */ + int ar_ignore_local_fs; /* Don't optimize even if local_fs is 1 */ + int ar_localflocks; /* Let the VFS do flock|fcntl locks for us */ + int ar_localcaching; /* Local-style caching (dangerous on multihost) */ + int ar_debug; /* Oops on errors instead of trying to be graceful */ + int ar_upgrade; /* Upgrade ondisk/multihost format */ + unsigned int ar_num_glockd; /* Number of glockd threads */ + int ar_posix_acl; /* Enable posix acls */ + int ar_quota; /* off/account/on */ + int ar_suiddir; /* suiddir support */ + int ar_data; /* ordered/writeback */ +}; + +struct gfs2_tune { + spinlock_t gt_spin; + + unsigned int gt_ilimit; + unsigned int gt_ilimit_tries; + unsigned int gt_ilimit_min; + unsigned int gt_demote_secs; /* Cache retention for unheld glock */ + unsigned int gt_incore_log_blocks; + unsigned int gt_log_flush_secs; + unsigned int gt_jindex_refresh_secs; /* Check for new journal index */ + + unsigned int gt_scand_secs; + unsigned int gt_recoverd_secs; + unsigned int gt_logd_secs; + unsigned int gt_quotad_secs; + unsigned int gt_inoded_secs; + + unsigned int gt_quota_simul_sync; /* Max quotavals to sync at once */ + unsigned int gt_quota_warn_period; /* Secs between quota warn msgs */ + unsigned int gt_quota_scale_num; /* Numerator */ + unsigned int gt_quota_scale_den; /* Denominator */ + unsigned int gt_quota_cache_secs; + unsigned int gt_quota_quantum; /* Secs between syncs to quota file */ + unsigned int gt_atime_quantum; /* Min secs between atime updates */ + unsigned int gt_new_files_jdata; + unsigned int gt_new_files_directio; + unsigned int gt_max_atomic_write; /* Split big writes into this size */ + unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */ + unsigned int gt_lockdump_size; + unsigned int gt_stall_secs; /* Detects trouble! */ + unsigned int gt_complain_secs; + unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */ + unsigned int gt_entries_per_readdir; + unsigned int gt_prefetch_secs; /* Usage window for prefetched glocks */ + unsigned int gt_greedy_default; + unsigned int gt_greedy_quantum; + unsigned int gt_greedy_max; + unsigned int gt_statfs_quantum; + unsigned int gt_statfs_slow; +}; + +struct gfs2_gl_hash_bucket { + rwlock_t hb_lock; + struct list_head hb_list; +}; + +enum { + SDF_JOURNAL_CHECKED = 0, + SDF_JOURNAL_LIVE = 1, + SDF_SHUTDOWN = 2, + SDF_NOATIME = 3, +}; + +#define GFS2_GL_HASH_SHIFT 13 +#define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT) +#define GFS2_GL_HASH_MASK (GFS2_GL_HASH_SIZE - 1) +#define GFS2_FSNAME_LEN 256 + +struct gfs2_sbd { + struct super_block *sd_vfs; + struct kobject sd_kobj; + unsigned long sd_flags; /* SDF_... */ + struct gfs2_sb sd_sb; + + /* Constants computed on mount */ + + uint32_t sd_fsb2bb; + uint32_t sd_fsb2bb_shift; + uint32_t sd_diptrs; /* Number of pointers in a dinode */ + uint32_t sd_inptrs; /* Number of pointers in a indirect block */ + uint32_t sd_jbsize; /* Size of a journaled data block */ + uint32_t sd_hash_bsize; /* sizeof(exhash block) */ + uint32_t sd_hash_bsize_shift; + uint32_t sd_hash_ptrs; /* Number of pointers in a hash block */ + uint32_t sd_ut_per_block; + uint32_t sd_qc_per_block; + uint32_t sd_max_dirres; /* Max blocks needed to add a directory entry */ + uint32_t sd_max_height; /* Max height of a file's metadata tree */ + uint64_t sd_heightsize[GFS2_MAX_META_HEIGHT]; + uint32_t sd_max_jheight; /* Max height of journaled file's meta tree */ + uint64_t sd_jheightsize[GFS2_MAX_META_HEIGHT]; + + struct gfs2_args sd_args; /* Mount arguments */ + struct gfs2_tune sd_tune; /* Filesystem tuning structure */ + + /* Lock Stuff */ + + struct lm_lockstruct sd_lockstruct; + struct gfs2_gl_hash_bucket sd_gl_hash[GFS2_GL_HASH_SIZE]; + struct list_head sd_reclaim_list; + spinlock_t sd_reclaim_lock; + wait_queue_head_t sd_reclaim_wq; + atomic_t sd_reclaim_count; + struct gfs2_holder sd_live_gh; + struct gfs2_glock *sd_rename_gl; + struct gfs2_glock *sd_trans_gl; + struct semaphore sd_invalidate_inodes_mutex; + + /* Inode Stuff */ + + struct gfs2_inode *sd_master_dir; + struct gfs2_inode *sd_jindex; + struct gfs2_inode *sd_inum_inode; + struct gfs2_inode *sd_statfs_inode; + struct gfs2_inode *sd_ir_inode; + struct gfs2_inode *sd_sc_inode; + struct gfs2_inode *sd_ut_inode; + struct gfs2_inode *sd_qc_inode; + struct gfs2_inode *sd_rindex; + struct gfs2_inode *sd_quota_inode; + struct gfs2_inode *sd_root_dir; + + /* Inum stuff */ + + struct semaphore sd_inum_mutex; + + /* StatFS stuff */ + + spinlock_t sd_statfs_spin; + struct semaphore sd_statfs_mutex; + struct gfs2_statfs_change sd_statfs_master; + struct gfs2_statfs_change sd_statfs_local; + unsigned long sd_statfs_sync_time; + + /* Resource group stuff */ + + uint64_t sd_rindex_vn; + spinlock_t sd_rindex_spin; + struct semaphore sd_rindex_mutex; + struct list_head sd_rindex_list; + struct list_head sd_rindex_mru_list; + struct list_head sd_rindex_recent_list; + struct gfs2_rgrpd *sd_rindex_forward; + unsigned int sd_rgrps; + + /* Journal index stuff */ + + struct list_head sd_jindex_list; + spinlock_t sd_jindex_spin; + struct semaphore sd_jindex_mutex; + unsigned int sd_journals; + unsigned long sd_jindex_refresh_time; + + struct gfs2_jdesc *sd_jdesc; + struct gfs2_holder sd_journal_gh; + struct gfs2_holder sd_jinode_gh; + + struct gfs2_holder sd_ir_gh; + struct gfs2_holder sd_sc_gh; + struct gfs2_holder sd_ut_gh; + struct gfs2_holder sd_qc_gh; + + /* Daemon stuff */ + + struct task_struct *sd_scand_process; + struct task_struct *sd_recoverd_process; + struct task_struct *sd_logd_process; + struct task_struct *sd_quotad_process; + struct task_struct *sd_inoded_process; + struct task_struct *sd_glockd_process[GFS2_GLOCKD_MAX]; + unsigned int sd_glockd_num; + + /* Unlinked inode stuff */ + + struct list_head sd_unlinked_list; + atomic_t sd_unlinked_count; + spinlock_t sd_unlinked_spin; + struct semaphore sd_unlinked_mutex; + + unsigned int sd_unlinked_slots; + unsigned int sd_unlinked_chunks; + unsigned char **sd_unlinked_bitmap; + + /* Quota stuff */ + + struct list_head sd_quota_list; + atomic_t sd_quota_count; + spinlock_t sd_quota_spin; + struct semaphore sd_quota_mutex; + + unsigned int sd_quota_slots; + unsigned int sd_quota_chunks; + unsigned char **sd_quota_bitmap; + + uint64_t sd_quota_sync_gen; + unsigned long sd_quota_sync_time; + + /* Log stuff */ + + spinlock_t sd_log_lock; + atomic_t sd_log_trans_count; + wait_queue_head_t sd_log_trans_wq; + atomic_t sd_log_flush_count; + wait_queue_head_t sd_log_flush_wq; + + unsigned int sd_log_blks_reserved; + unsigned int sd_log_commited_buf; + unsigned int sd_log_commited_revoke; + + unsigned int sd_log_num_gl; + unsigned int sd_log_num_buf; + unsigned int sd_log_num_revoke; + unsigned int sd_log_num_rg; + unsigned int sd_log_num_databuf; + struct list_head sd_log_le_gl; + struct list_head sd_log_le_buf; + struct list_head sd_log_le_revoke; + struct list_head sd_log_le_rg; + struct list_head sd_log_le_databuf; + + unsigned int sd_log_blks_free; + struct list_head sd_log_blks_list; + wait_queue_head_t sd_log_blks_wait; + + uint64_t sd_log_sequence; + unsigned int sd_log_head; + unsigned int sd_log_tail; + uint64_t sd_log_wraps; + int sd_log_idle; + + unsigned long sd_log_flush_time; + struct semaphore sd_log_flush_lock; + struct list_head sd_log_flush_list; + + unsigned int sd_log_flush_head; + uint64_t sd_log_flush_wrapped; + + struct list_head sd_ail1_list; + struct list_head sd_ail2_list; + uint64_t sd_ail_sync_gen; + + /* Replay stuff */ + + struct list_head sd_revoke_list; + unsigned int sd_replay_tail; + + unsigned int sd_found_blocks; + unsigned int sd_found_revokes; + unsigned int sd_replayed_blocks; + + /* For quiescing the filesystem */ + + struct gfs2_holder sd_freeze_gh; + struct semaphore sd_freeze_lock; + unsigned int sd_freeze_count; + + /* Counters */ + + atomic_t sd_glock_count; + atomic_t sd_glock_held_count; + atomic_t sd_inode_count; + atomic_t sd_bufdata_count; + + atomic_t sd_fh2dentry_misses; + atomic_t sd_reclaimed; + atomic_t sd_log_flush_incore; + atomic_t sd_log_flush_ondisk; + + atomic_t sd_glock_nq_calls; + atomic_t sd_glock_dq_calls; + atomic_t sd_glock_prefetch_calls; + atomic_t sd_lm_lock_calls; + atomic_t sd_lm_unlock_calls; + atomic_t sd_lm_callbacks; + + atomic_t sd_ops_address; + atomic_t sd_ops_dentry; + atomic_t sd_ops_export; + atomic_t sd_ops_file; + atomic_t sd_ops_inode; + atomic_t sd_ops_super; + atomic_t sd_ops_vm; + + char sd_fsname[GFS2_FSNAME_LEN]; + char sd_table_name[GFS2_FSNAME_LEN]; + char sd_proto_name[GFS2_FSNAME_LEN]; + + /* Debugging crud */ + + unsigned long sd_last_warning; +}; + +#endif /* __INCORE_DOT_H__ */ + diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c new file mode 100644 index 000000000000..73922dba5398 --- /dev/null +++ b/fs/gfs2/inode.c @@ -0,0 +1,1805 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "acl.h" +#include "bmap.h" +#include "dir.h" +#include "eattr.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "log.h" +#include "meta_io.h" +#include "ops_address.h" +#include "ops_file.h" +#include "ops_inode.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" +#include "unlinked.h" + +/** + * inode_attr_in - Copy attributes from the dinode into the VFS inode + * @ip: The GFS2 inode (with embedded disk inode data) + * @inode: The Linux VFS inode + * + */ + +static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode) +{ + inode->i_ino = ip->i_num.no_formal_ino; + + switch (ip->i_di.di_mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + inode->i_rdev = MKDEV(ip->i_di.di_major, ip->i_di.di_minor); + break; + default: + inode->i_rdev = 0; + break; + }; + + inode->i_mode = ip->i_di.di_mode; + inode->i_nlink = ip->i_di.di_nlink; + inode->i_uid = ip->i_di.di_uid; + inode->i_gid = ip->i_di.di_gid; + i_size_write(inode, ip->i_di.di_size); + inode->i_atime.tv_sec = ip->i_di.di_atime; + inode->i_mtime.tv_sec = ip->i_di.di_mtime; + inode->i_ctime.tv_sec = ip->i_di.di_ctime; + inode->i_atime.tv_nsec = 0; + inode->i_mtime.tv_nsec = 0; + inode->i_ctime.tv_nsec = 0; + inode->i_blksize = PAGE_SIZE; + inode->i_blocks = ip->i_di.di_blocks << + (ip->i_sbd->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT); + + if (ip->i_di.di_flags & GFS2_DIF_IMMUTABLE) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= ~S_IMMUTABLE; + + if (ip->i_di.di_flags & GFS2_DIF_APPENDONLY) + inode->i_flags |= S_APPEND; + else + inode->i_flags &= ~S_APPEND; +} + +/** + * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode + * @ip: The GFS2 inode (with embedded disk inode data) + * + */ + +void gfs2_inode_attr_in(struct gfs2_inode *ip) +{ + struct inode *inode; + + inode = gfs2_ip2v_lookup(ip); + if (inode) { + inode_attr_in(ip, inode); + iput(inode); + } +} + +/** + * gfs2_inode_attr_out - Copy attributes from VFS inode into the dinode + * @ip: The GFS2 inode + * + * Only copy out the attributes that we want the VFS layer + * to be able to modify. + */ + +void gfs2_inode_attr_out(struct gfs2_inode *ip) +{ + struct inode *inode = ip->i_vnode; + + gfs2_assert_withdraw(ip->i_sbd, + (ip->i_di.di_mode & S_IFMT) == (inode->i_mode & S_IFMT)); + ip->i_di.di_mode = inode->i_mode; + ip->i_di.di_uid = inode->i_uid; + ip->i_di.di_gid = inode->i_gid; + ip->i_di.di_atime = inode->i_atime.tv_sec; + ip->i_di.di_mtime = inode->i_mtime.tv_sec; + ip->i_di.di_ctime = inode->i_ctime.tv_sec; +} + +/** + * gfs2_ip2v_lookup - Get the struct inode for a struct gfs2_inode + * @ip: the struct gfs2_inode to get the struct inode for + * + * Returns: A VFS inode, or NULL if none + */ + +struct inode *gfs2_ip2v_lookup(struct gfs2_inode *ip) +{ + struct inode *inode = NULL; + + gfs2_assert_warn(ip->i_sbd, test_bit(GIF_MIN_INIT, &ip->i_flags)); + + spin_lock(&ip->i_spin); + if (ip->i_vnode) + inode = igrab(ip->i_vnode); + spin_unlock(&ip->i_spin); + + return inode; +} + +/** + * gfs2_ip2v - Get/Create a struct inode for a struct gfs2_inode + * @ip: the struct gfs2_inode to get the struct inode for + * + * Returns: A VFS inode, or NULL if no mem + */ + +struct inode *gfs2_ip2v(struct gfs2_inode *ip) +{ + struct inode *inode, *tmp; + + inode = gfs2_ip2v_lookup(ip); + if (inode) + return inode; + + tmp = new_inode(ip->i_sbd->sd_vfs); + if (!tmp) + return NULL; + + inode_attr_in(ip, tmp); + + if (S_ISREG(ip->i_di.di_mode)) { + tmp->i_op = &gfs2_file_iops; + tmp->i_fop = &gfs2_file_fops; + tmp->i_mapping->a_ops = &gfs2_file_aops; + } else if (S_ISDIR(ip->i_di.di_mode)) { + tmp->i_op = &gfs2_dir_iops; + tmp->i_fop = &gfs2_dir_fops; + } else if (S_ISLNK(ip->i_di.di_mode)) { + tmp->i_op = &gfs2_symlink_iops; + } else { + tmp->i_op = &gfs2_dev_iops; + init_special_inode(tmp, tmp->i_mode, tmp->i_rdev); + } + + set_v2ip(tmp, NULL); + + for (;;) { + spin_lock(&ip->i_spin); + if (!ip->i_vnode) + break; + inode = igrab(ip->i_vnode); + spin_unlock(&ip->i_spin); + + if (inode) { + iput(tmp); + return inode; + } + yield(); + } + + inode = tmp; + + gfs2_inode_hold(ip); + ip->i_vnode = inode; + set_v2ip(inode, ip); + + spin_unlock(&ip->i_spin); + + insert_inode_hash(inode); + + return inode; +} + +static int iget_test(struct inode *inode, void *opaque) +{ + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inum *inum = (struct gfs2_inum *)opaque; + + if (ip && ip->i_num.no_addr == inum->no_addr) + return 1; + + return 0; +} + +struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum) +{ + return ilookup5(sb, (unsigned long)inum->no_formal_ino, + iget_test, inum); +} + +void gfs2_inode_min_init(struct gfs2_inode *ip, unsigned int type) +{ + spin_lock(&ip->i_spin); + if (!test_and_set_bit(GIF_MIN_INIT, &ip->i_flags)) { + ip->i_di.di_nlink = 1; + ip->i_di.di_mode = DT2IF(type); + } + spin_unlock(&ip->i_spin); +} + +/** + * gfs2_inode_refresh - Refresh the incore copy of the dinode + * @ip: The GFS2 inode + * + * Returns: errno + */ + +int gfs2_inode_refresh(struct gfs2_inode *ip) +{ + struct buffer_head *dibh; + int error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; + + if (gfs2_metatype_check(ip->i_sbd, dibh, GFS2_METATYPE_DI)) { + brelse(dibh); + return -EIO; + } + + spin_lock(&ip->i_spin); + gfs2_dinode_in(&ip->i_di, dibh->b_data); + set_bit(GIF_MIN_INIT, &ip->i_flags); + spin_unlock(&ip->i_spin); + + brelse(dibh); + + if (ip->i_num.no_addr != ip->i_di.di_num.no_addr) { + if (gfs2_consist_inode(ip)) + gfs2_dinode_print(&ip->i_di); + return -EIO; + } + if (ip->i_num.no_formal_ino != ip->i_di.di_num.no_formal_ino) + return -ESTALE; + + ip->i_vn = ip->i_gl->gl_vn; + + return 0; +} + +/** + * inode_create - create a struct gfs2_inode + * @i_gl: The glock covering the inode + * @inum: The inode number + * @io_gl: the iopen glock to acquire/hold (using holder in new gfs2_inode) + * @io_state: the state the iopen glock should be acquired in + * @ipp: pointer to put the returned inode in + * + * Returns: errno + */ + +static int inode_create(struct gfs2_glock *i_gl, struct gfs2_inum *inum, + struct gfs2_glock *io_gl, unsigned int io_state, + struct gfs2_inode **ipp) +{ + struct gfs2_sbd *sdp = i_gl->gl_sbd; + struct gfs2_inode *ip; + int error = 0; + + ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL); + if (!ip) + return -ENOMEM; + memset(ip, 0, sizeof(struct gfs2_inode)); + + ip->i_num = *inum; + + atomic_set(&ip->i_count, 1); + + ip->i_vn = i_gl->gl_vn - 1; + + ip->i_gl = i_gl; + ip->i_sbd = sdp; + + spin_lock_init(&ip->i_spin); + init_rwsem(&ip->i_rw_mutex); + + ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default); + + error = gfs2_glock_nq_init(io_gl, + io_state, GL_LOCAL_EXCL | GL_EXACT, + &ip->i_iopen_gh); + if (error) + goto fail; + ip->i_iopen_gh.gh_owner = NULL; + + spin_lock(&io_gl->gl_spin); + gfs2_glock_hold(i_gl); + set_gl2gl(io_gl, i_gl); + spin_unlock(&io_gl->gl_spin); + + gfs2_glock_hold(i_gl); + set_gl2ip(i_gl, ip); + + atomic_inc(&sdp->sd_inode_count); + + *ipp = ip; + + return 0; + + fail: + gfs2_meta_cache_flush(ip); + kmem_cache_free(gfs2_inode_cachep, ip); + *ipp = NULL; + + return error; +} + +/** + * gfs2_inode_get - Create or get a reference on an inode + * @i_gl: The glock covering the inode + * @inum: The inode number + * @create: + * @ipp: pointer to put the returned inode in + * + * Returns: errno + */ + +int gfs2_inode_get(struct gfs2_glock *i_gl, struct gfs2_inum *inum, int create, + struct gfs2_inode **ipp) +{ + struct gfs2_sbd *sdp = i_gl->gl_sbd; + struct gfs2_glock *io_gl; + int error = 0; + + gfs2_glmutex_lock(i_gl); + + *ipp = get_gl2ip(i_gl); + if (*ipp) { + error = -ESTALE; + if ((*ipp)->i_num.no_formal_ino != inum->no_formal_ino) + goto out; + atomic_inc(&(*ipp)->i_count); + error = 0; + goto out; + } + + if (!create) + goto out; + + error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_iopen_glops, + CREATE, &io_gl); + if (!error) { + error = inode_create(i_gl, inum, io_gl, LM_ST_SHARED, ipp); + gfs2_glock_put(io_gl); + } + + out: + gfs2_glmutex_unlock(i_gl); + + return error; +} + +void gfs2_inode_hold(struct gfs2_inode *ip) +{ + gfs2_assert(ip->i_sbd, atomic_read(&ip->i_count) > 0); + atomic_inc(&ip->i_count); +} + +void gfs2_inode_put(struct gfs2_inode *ip) +{ + gfs2_assert(ip->i_sbd, atomic_read(&ip->i_count) > 0); + atomic_dec(&ip->i_count); +} + +void gfs2_inode_destroy(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_glock *io_gl = ip->i_iopen_gh.gh_gl; + struct gfs2_glock *i_gl = ip->i_gl; + + gfs2_assert_warn(sdp, !atomic_read(&ip->i_count)); + gfs2_assert(sdp, get_gl2gl(io_gl) == i_gl); + + spin_lock(&io_gl->gl_spin); + set_gl2gl(io_gl, NULL); + gfs2_glock_put(i_gl); + spin_unlock(&io_gl->gl_spin); + + gfs2_glock_dq_uninit(&ip->i_iopen_gh); + + gfs2_meta_cache_flush(ip); + kmem_cache_free(gfs2_inode_cachep, ip); + + set_gl2ip(i_gl, NULL); + gfs2_glock_put(i_gl); + + atomic_dec(&sdp->sd_inode_count); +} + +static int dinode_dealloc(struct gfs2_inode *ip, struct gfs2_unlinked *ul) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al; + struct gfs2_rgrpd *rgd; + int error; + + if (ip->i_di.di_blocks != 1) { + if (gfs2_consist_inode(ip)) + gfs2_dinode_print(&ip->i_di); + return -EIO; + } + + al = gfs2_alloc_get(ip); + + error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs2_rindex_hold(sdp, &al->al_ri_gh); + if (error) + goto out_qs; + + rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr); + if (!rgd) { + gfs2_consist_inode(ip); + error = -EIO; + goto out_rindex_relse; + } + + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, + &al->al_rgd_gh); + if (error) + goto out_rindex_relse; + + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_UNLINKED + + RES_STATFS + RES_QUOTA, 1); + if (error) + goto out_rg_gunlock; + + gfs2_trans_add_gl(ip->i_gl); + + gfs2_free_di(rgd, ip); + + error = gfs2_unlinked_ondisk_rm(sdp, ul); + + gfs2_trans_end(sdp); + clear_bit(GLF_STICKY, &ip->i_gl->gl_flags); + + out_rg_gunlock: + gfs2_glock_dq_uninit(&al->al_rgd_gh); + + out_rindex_relse: + gfs2_glock_dq_uninit(&al->al_ri_gh); + + out_qs: + gfs2_quota_unhold(ip); + + out: + gfs2_alloc_put(ip); + + return error; +} + +/** + * inode_dealloc - Deallocate all on-disk blocks for an inode (dinode) + * @sdp: the filesystem + * @inum: the inode number to deallocate + * @io_gh: a holder for the iopen glock for this inode + * + * Returns: errno + */ + +static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul, + struct gfs2_holder *io_gh) +{ + struct gfs2_inode *ip; + struct gfs2_holder i_gh; + int error; + + error = gfs2_glock_nq_num(sdp, + ul->ul_ut.ut_inum.no_addr, &gfs2_inode_glops, + LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + return error; + + /* We reacquire the iopen lock here to avoid a race with the NFS server + calling gfs2_read_inode() with the inode number of a inode we're in + the process of deallocating. And we can't keep our hold on the lock + from inode_dealloc_init() for deadlock reasons. */ + + gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY, io_gh); + error = gfs2_glock_nq(io_gh); + switch (error) { + case 0: + break; + case GLR_TRYFAILED: + error = 1; + default: + goto out; + } + + gfs2_assert_warn(sdp, !get_gl2ip(i_gh.gh_gl)); + error = inode_create(i_gh.gh_gl, &ul->ul_ut.ut_inum, io_gh->gh_gl, + LM_ST_EXCLUSIVE, &ip); + + gfs2_glock_dq(io_gh); + + if (error) + goto out; + + error = gfs2_inode_refresh(ip); + if (error) + goto out_iput; + + if (ip->i_di.di_nlink) { + if (gfs2_consist_inode(ip)) + gfs2_dinode_print(&ip->i_di); + error = -EIO; + goto out_iput; + } + + if (S_ISDIR(ip->i_di.di_mode) && + (ip->i_di.di_flags & GFS2_DIF_EXHASH)) { + error = gfs2_dir_exhash_dealloc(ip); + if (error) + goto out_iput; + } + + if (ip->i_di.di_eattr) { + error = gfs2_ea_dealloc(ip); + if (error) + goto out_iput; + } + + if (!gfs2_is_stuffed(ip)) { + error = gfs2_file_dealloc(ip); + if (error) + goto out_iput; + } + + error = dinode_dealloc(ip, ul); + if (error) + goto out_iput; + + out_iput: + gfs2_glmutex_lock(i_gh.gh_gl); + gfs2_inode_put(ip); + gfs2_inode_destroy(ip); + gfs2_glmutex_unlock(i_gh.gh_gl); + + out: + gfs2_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * try_inode_dealloc - Try to deallocate an inode and all its blocks + * @sdp: the filesystem + * + * Returns: 0 on success, -errno on error, 1 on busy (inode open) + */ + +static int try_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) +{ + struct gfs2_holder io_gh; + int error = 0; + + gfs2_try_toss_inode(sdp, &ul->ul_ut.ut_inum); + + error = gfs2_glock_nq_num(sdp, + ul->ul_ut.ut_inum.no_addr, &gfs2_iopen_glops, + LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB, &io_gh); + switch (error) { + case 0: + break; + case GLR_TRYFAILED: + return 1; + default: + return error; + } + + gfs2_glock_dq(&io_gh); + error = inode_dealloc(sdp, ul, &io_gh); + gfs2_holder_uninit(&io_gh); + + return error; +} + +static int inode_dealloc_uninit(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) +{ + struct gfs2_rgrpd *rgd; + struct gfs2_holder ri_gh, rgd_gh; + int error; + + error = gfs2_rindex_hold(sdp, &ri_gh); + if (error) + return error; + + rgd = gfs2_blk2rgrpd(sdp, ul->ul_ut.ut_inum.no_addr); + if (!rgd) { + gfs2_consist(sdp); + error = -EIO; + goto out; + } + + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rgd_gh); + if (error) + goto out; + + error = gfs2_trans_begin(sdp, + RES_RG_BIT + RES_UNLINKED + RES_STATFS, + 0); + if (error) + goto out_gunlock; + + gfs2_free_uninit_di(rgd, ul->ul_ut.ut_inum.no_addr); + gfs2_unlinked_ondisk_rm(sdp, ul); + + gfs2_trans_end(sdp); + + out_gunlock: + gfs2_glock_dq_uninit(&rgd_gh); + out: + gfs2_glock_dq_uninit(&ri_gh); + + return error; +} + +int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) +{ + if (ul->ul_ut.ut_flags & GFS2_UTF_UNINIT) + return inode_dealloc_uninit(sdp, ul); + else + return try_inode_dealloc(sdp, ul); +} + +/** + * gfs2_change_nlink - Change nlink count on inode + * @ip: The GFS2 inode + * @diff: The change in the nlink count required + * + * Returns: errno + */ + +int gfs2_change_nlink(struct gfs2_inode *ip, int diff) +{ + struct buffer_head *dibh; + uint32_t nlink; + int error; + + nlink = ip->i_di.di_nlink + diff; + + /* If we are reducing the nlink count, but the new value ends up being + bigger than the old one, we must have underflowed. */ + if (diff < 0 && nlink > ip->i_di.di_nlink) { + if (gfs2_consist_inode(ip)) + gfs2_dinode_print(&ip->i_di); + return -EIO; + } + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; + + ip->i_di.di_nlink = nlink; + ip->i_di.di_ctime = get_seconds(); + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + return 0; +} + +/** + * gfs2_lookupi - Look up a filename in a directory and return its inode + * @d_gh: An initialized holder for the directory glock + * @name: The name of the inode to look for + * @is_root: If 1, ignore the caller's permissions + * @i_gh: An uninitialized holder for the new inode glock + * + * There will always be a vnode (Linux VFS inode) for the d_gh inode unless + * @is_root is true. + * + * Returns: errno + */ + +int gfs2_lookupi(struct gfs2_inode *dip, struct qstr *name, int is_root, + struct gfs2_inode **ipp) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_holder d_gh; + struct gfs2_inum inum; + unsigned int type; + struct gfs2_glock *gl; + int error; + + if (!name->len || name->len > GFS2_FNAMESIZE) + return -ENAMETOOLONG; + + if (gfs2_filecmp(name, ".", 1) || + (gfs2_filecmp(name, "..", 2) && dip == sdp->sd_root_dir)) { + gfs2_inode_hold(dip); + *ipp = dip; + return 0; + } + + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); + if (error) + return error; + + if (!is_root) { + error = gfs2_repermission(dip->i_vnode, MAY_EXEC, NULL); + if (error) + goto out; + } + + error = gfs2_dir_search(dip, name, &inum, &type); + if (error) + goto out; + + error = gfs2_glock_get(sdp, inum.no_addr, &gfs2_inode_glops, + CREATE, &gl); + if (error) + goto out; + + error = gfs2_inode_get(gl, &inum, CREATE, ipp); + if (!error) + gfs2_inode_min_init(*ipp, type); + + gfs2_glock_put(gl); + + out: + gfs2_glock_dq_uninit(&d_gh); + + return error; +} + +static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) +{ + struct gfs2_inode *ip = sdp->sd_ir_inode; + struct buffer_head *bh; + struct gfs2_inum_range ir; + int error; + + error = gfs2_trans_begin(sdp, RES_DINODE, 0); + if (error) + return error; + down(&sdp->sd_inum_mutex); + + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) { + up(&sdp->sd_inum_mutex); + gfs2_trans_end(sdp); + return error; + } + + gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode)); + + if (ir.ir_length) { + *formal_ino = ir.ir_start++; + ir.ir_length--; + gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_inum_range_out(&ir, + bh->b_data + sizeof(struct gfs2_dinode)); + brelse(bh); + up(&sdp->sd_inum_mutex); + gfs2_trans_end(sdp); + return 0; + } + + brelse(bh); + + up(&sdp->sd_inum_mutex); + gfs2_trans_end(sdp); + + return 1; +} + +static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) +{ + struct gfs2_inode *ip = sdp->sd_ir_inode; + struct gfs2_inode *m_ip = sdp->sd_inum_inode; + struct gfs2_holder gh; + struct buffer_head *bh; + struct gfs2_inum_range ir; + int error; + + error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + if (error) + return error; + + error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0); + if (error) + goto out; + down(&sdp->sd_inum_mutex); + + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + goto out_end_trans; + + gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode)); + + if (!ir.ir_length) { + struct buffer_head *m_bh; + uint64_t x, y; + + error = gfs2_meta_inode_buffer(m_ip, &m_bh); + if (error) + goto out_brelse; + + x = *(uint64_t *)(m_bh->b_data + sizeof(struct gfs2_dinode)); + x = y = be64_to_cpu(x); + ir.ir_start = x; + ir.ir_length = GFS2_INUM_QUANTUM; + x += GFS2_INUM_QUANTUM; + if (x < y) + gfs2_consist_inode(m_ip); + x = cpu_to_be64(x); + gfs2_trans_add_bh(m_ip->i_gl, m_bh); + *(uint64_t *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = x; + + brelse(m_bh); + } + + *formal_ino = ir.ir_start++; + ir.ir_length--; + + gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode)); + + out_brelse: + brelse(bh); + + out_end_trans: + up(&sdp->sd_inum_mutex); + gfs2_trans_end(sdp); + + out: + gfs2_glock_dq_uninit(&gh); + + return error; +} + +static int pick_formal_ino(struct gfs2_sbd *sdp, uint64_t *inum) +{ + int error; + + error = pick_formal_ino_1(sdp, inum); + if (error <= 0) + return error; + + error = pick_formal_ino_2(sdp, inum); + + return error; +} + +/** + * create_ok - OK to create a new on-disk inode here? + * @dip: Directory in which dinode is to be created + * @name: Name of new dinode + * @mode: + * + * Returns: errno + */ + +static int create_ok(struct gfs2_inode *dip, struct qstr *name, + unsigned int mode) +{ + int error; + + error = gfs2_repermission(dip->i_vnode, MAY_WRITE | MAY_EXEC, NULL); + if (error) + return error; + + /* Don't create entries in an unlinked directory */ + if (!dip->i_di.di_nlink) + return -EPERM; + + error = gfs2_dir_search(dip, name, NULL, NULL); + switch (error) { + case -ENOENT: + error = 0; + break; + case 0: + return -EEXIST; + default: + return error; + } + + if (dip->i_di.di_entries == (uint32_t)-1) + return -EFBIG; + if (S_ISDIR(mode) && dip->i_di.di_nlink == (uint32_t)-1) + return -EMLINK; + + return 0; +} + +static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, + unsigned int *uid, unsigned int *gid) +{ + if (dip->i_sbd->sd_args.ar_suiddir && + (dip->i_di.di_mode & S_ISUID) && + dip->i_di.di_uid) { + if (S_ISDIR(*mode)) + *mode |= S_ISUID; + else if (dip->i_di.di_uid != current->fsuid) + *mode &= ~07111; + *uid = dip->i_di.di_uid; + } else + *uid = current->fsuid; + + if (dip->i_di.di_mode & S_ISGID) { + if (S_ISDIR(*mode)) + *mode |= S_ISGID; + *gid = dip->i_di.di_gid; + } else + *gid = current->fsgid; +} + +static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_unlinked *ul) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + int error; + + gfs2_alloc_get(dip); + + dip->i_alloc.al_requested = RES_DINODE; + error = gfs2_inplace_reserve(dip); + if (error) + goto out; + + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_UNLINKED + + RES_STATFS, 0); + if (error) + goto out_ipreserv; + + ul->ul_ut.ut_inum.no_addr = gfs2_alloc_di(dip); + + ul->ul_ut.ut_flags = GFS2_UTF_UNINIT; + error = gfs2_unlinked_ondisk_add(sdp, ul); + + gfs2_trans_end(sdp); + + out_ipreserv: + gfs2_inplace_release(dip); + + out: + gfs2_alloc_put(dip); + + return error; +} + +/** + * init_dinode - Fill in a new dinode structure + * @dip: the directory this inode is being created in + * @gl: The glock covering the new inode + * @inum: the inode number + * @mode: the file permissions + * @uid: + * @gid: + * + */ + +static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, + struct gfs2_inum *inum, unsigned int mode, + unsigned int uid, unsigned int gid) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_dinode di; + struct buffer_head *dibh; + + dibh = gfs2_meta_new(gl, inum->no_addr); + gfs2_trans_add_bh(gl, dibh); + gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI); + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); + + memset(&di, 0, sizeof(struct gfs2_dinode)); + gfs2_meta_header_in(&di.di_header, dibh->b_data); + di.di_num = *inum; + di.di_mode = mode; + di.di_uid = uid; + di.di_gid = gid; + di.di_blocks = 1; + di.di_atime = di.di_mtime = di.di_ctime = get_seconds(); + di.di_goal_meta = di.di_goal_data = inum->no_addr; + + if (S_ISREG(mode)) { + if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA) || + gfs2_tune_get(sdp, gt_new_files_jdata)) + di.di_flags |= GFS2_DIF_JDATA; + if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_DIRECTIO) || + gfs2_tune_get(sdp, gt_new_files_directio)) + di.di_flags |= GFS2_DIF_DIRECTIO; + } else if (S_ISDIR(mode)) { + di.di_flags |= (dip->i_di.di_flags & GFS2_DIF_INHERIT_DIRECTIO); + di.di_flags |= (dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA); + } + + gfs2_dinode_out(&di, dibh->b_data); + brelse(dibh); +} + +static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, + unsigned int mode, struct gfs2_unlinked *ul) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + unsigned int uid, gid; + int error; + + munge_mode_uid_gid(dip, &mode, &uid, &gid); + + gfs2_alloc_get(dip); + + error = gfs2_quota_lock(dip, uid, gid); + if (error) + goto out; + + error = gfs2_quota_check(dip, uid, gid); + if (error) + goto out_quota; + + error = gfs2_trans_begin(sdp, RES_DINODE + RES_UNLINKED + + RES_QUOTA, 0); + if (error) + goto out_quota; + + ul->ul_ut.ut_flags = 0; + error = gfs2_unlinked_ondisk_munge(sdp, ul); + + init_dinode(dip, gl, &ul->ul_ut.ut_inum, + mode, uid, gid); + + gfs2_quota_change(dip, +1, uid, gid); + + gfs2_trans_end(sdp); + + out_quota: + gfs2_quota_unlock(dip); + + out: + gfs2_alloc_put(dip); + + return error; +} + +static int link_dinode(struct gfs2_inode *dip, struct qstr *name, + struct gfs2_inode *ip, struct gfs2_unlinked *ul) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_alloc *al; + int alloc_required; + struct buffer_head *dibh; + int error; + + al = gfs2_alloc_get(dip); + + error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto fail; + + error = gfs2_diradd_alloc_required(dip, name, &alloc_required); + if (alloc_required) { + error = gfs2_quota_check(dip, dip->i_di.di_uid, + dip->i_di.di_gid); + if (error) + goto fail_quota_locks; + + al->al_requested = sdp->sd_max_dirres; + + error = gfs2_inplace_reserve(dip); + if (error) + goto fail_quota_locks; + + error = gfs2_trans_begin(sdp, + sdp->sd_max_dirres + + al->al_rgd->rd_ri.ri_length + + 2 * RES_DINODE + RES_UNLINKED + + RES_STATFS + RES_QUOTA, 0); + if (error) + goto fail_ipreserv; + } else { + error = gfs2_trans_begin(sdp, + RES_LEAF + + 2 * RES_DINODE + + RES_UNLINKED, 0); + if (error) + goto fail_quota_locks; + } + + error = gfs2_dir_add(dip, name, &ip->i_num, IF2DT(ip->i_di.di_mode)); + if (error) + goto fail_end_trans; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + ip->i_di.di_nlink = 1; + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + error = gfs2_unlinked_ondisk_rm(sdp, ul); + if (error) + goto fail_end_trans; + + return 0; + + fail_end_trans: + gfs2_trans_end(sdp); + + fail_ipreserv: + if (dip->i_alloc.al_rgd) + gfs2_inplace_release(dip); + + fail_quota_locks: + gfs2_quota_unlock(dip); + + fail: + gfs2_alloc_put(dip); + + return error; +} + +/** + * gfs2_createi - Create a new inode + * @ghs: An array of two holders + * @name: The name of the new file + * @mode: the permissions on the new inode + * + * @ghs[0] is an initialized holder for the directory + * @ghs[1] is the holder for the inode lock + * + * If the return value is 0, the glocks on both the directory and the new + * file are held. A transaction has been started and an inplace reservation + * is held, as well. + * + * Returns: errno + */ + +int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode) +{ + struct gfs2_inode *dip = get_gl2ip(ghs->gh_gl); + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_unlinked *ul; + struct gfs2_inode *ip; + int error; + + if (!name->len || name->len > GFS2_FNAMESIZE) + return -ENAMETOOLONG; + + error = gfs2_unlinked_get(sdp, &ul); + if (error) + return error; + + gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); + error = gfs2_glock_nq(ghs); + if (error) + goto fail; + + error = create_ok(dip, name, mode); + if (error) + goto fail_gunlock; + + error = pick_formal_ino(sdp, &ul->ul_ut.ut_inum.no_formal_ino); + if (error) + goto fail_gunlock; + + error = alloc_dinode(dip, ul); + if (error) + goto fail_gunlock; + + if (ul->ul_ut.ut_inum.no_addr < dip->i_num.no_addr) { + gfs2_glock_dq(ghs); + + error = gfs2_glock_nq_num(sdp, + ul->ul_ut.ut_inum.no_addr, + &gfs2_inode_glops, + LM_ST_EXCLUSIVE, GL_SKIP, + ghs + 1); + if (error) { + gfs2_unlinked_put(sdp, ul); + return error; + } + + gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); + error = gfs2_glock_nq(ghs); + if (error) { + gfs2_glock_dq_uninit(ghs + 1); + gfs2_unlinked_put(sdp, ul); + return error; + } + + error = create_ok(dip, name, mode); + if (error) + goto fail_gunlock2; + } else { + error = gfs2_glock_nq_num(sdp, + ul->ul_ut.ut_inum.no_addr, + &gfs2_inode_glops, + LM_ST_EXCLUSIVE, GL_SKIP, + ghs + 1); + if (error) + goto fail_gunlock; + } + + error = make_dinode(dip, ghs[1].gh_gl, mode, ul); + if (error) + goto fail_gunlock2; + + error = gfs2_inode_get(ghs[1].gh_gl, &ul->ul_ut.ut_inum, CREATE, &ip); + if (error) + goto fail_gunlock2; + + error = gfs2_inode_refresh(ip); + if (error) + goto fail_iput; + + error = gfs2_acl_create(dip, ip); + if (error) + goto fail_iput; + + error = link_dinode(dip, name, ip, ul); + if (error) + goto fail_iput; + + gfs2_unlinked_put(sdp, ul); + + return 0; + + fail_iput: + gfs2_inode_put(ip); + + fail_gunlock2: + gfs2_glock_dq_uninit(ghs + 1); + + fail_gunlock: + gfs2_glock_dq(ghs); + + fail: + gfs2_unlinked_put(sdp, ul); + + return error; +} + +/** + * gfs2_unlinki - Unlink a file + * @dip: The inode of the directory + * @name: The name of the file to be unlinked + * @ip: The inode of the file to be removed + * + * Assumes Glocks on both dip and ip are held. + * + * Returns: errno + */ + +int gfs2_unlinki(struct gfs2_inode *dip, struct qstr *name, + struct gfs2_inode *ip, struct gfs2_unlinked *ul) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + int error; + + error = gfs2_dir_del(dip, name); + if (error) + return error; + + error = gfs2_change_nlink(ip, -1); + if (error) + return error; + + /* If this inode is being unlinked from the directory structure, + we need to mark that in the log so that it isn't lost during + a crash. */ + + if (!ip->i_di.di_nlink) { + ul->ul_ut.ut_inum = ip->i_num; + error = gfs2_unlinked_ondisk_add(sdp, ul); + if (!error) + set_bit(GLF_STICKY, &ip->i_gl->gl_flags); + } + + return error; +} + +/** + * gfs2_rmdiri - Remove a directory + * @dip: The parent directory of the directory to be removed + * @name: The name of the directory to be removed + * @ip: The GFS2 inode of the directory to be removed + * + * Assumes Glocks on dip and ip are held + * + * Returns: errno + */ + +int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, + struct gfs2_inode *ip, struct gfs2_unlinked *ul) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct qstr dotname; + int error; + + if (ip->i_di.di_entries != 2) { + if (gfs2_consist_inode(ip)) + gfs2_dinode_print(&ip->i_di); + return -EIO; + } + + error = gfs2_dir_del(dip, name); + if (error) + return error; + + error = gfs2_change_nlink(dip, -1); + if (error) + return error; + + dotname.len = 1; + dotname.name = "."; + error = gfs2_dir_del(ip, &dotname); + if (error) + return error; + + dotname.len = 2; + dotname.name = ".."; + error = gfs2_dir_del(ip, &dotname); + if (error) + return error; + + error = gfs2_change_nlink(ip, -2); + if (error) + return error; + + /* This inode is being unlinked from the directory structure and + we need to mark that in the log so that it isn't lost during + a crash. */ + + ul->ul_ut.ut_inum = ip->i_num; + error = gfs2_unlinked_ondisk_add(sdp, ul); + if (!error) + set_bit(GLF_STICKY, &ip->i_gl->gl_flags); + + return error; +} + +/* + * gfs2_unlink_ok - check to see that a inode is still in a directory + * @dip: the directory + * @name: the name of the file + * @ip: the inode + * + * Assumes that the lock on (at least) @dip is held. + * + * Returns: 0 if the parent/child relationship is correct, errno if it isn't + */ + +int gfs2_unlink_ok(struct gfs2_inode *dip, struct qstr *name, + struct gfs2_inode *ip) +{ + struct gfs2_inum inum; + unsigned int type; + int error; + + if (IS_IMMUTABLE(ip->i_vnode) || IS_APPEND(ip->i_vnode)) + return -EPERM; + + if ((dip->i_di.di_mode & S_ISVTX) && + dip->i_di.di_uid != current->fsuid && + ip->i_di.di_uid != current->fsuid && + !capable(CAP_FOWNER)) + return -EPERM; + + if (IS_APPEND(dip->i_vnode)) + return -EPERM; + + error = gfs2_repermission(dip->i_vnode, MAY_WRITE | MAY_EXEC, NULL); + if (error) + return error; + + error = gfs2_dir_search(dip, name, &inum, &type); + if (error) + return error; + + if (!gfs2_inum_equal(&inum, &ip->i_num)) + return -ENOENT; + + if (IF2DT(ip->i_di.di_mode) != type) { + gfs2_consist_inode(dip); + return -EIO; + } + + return 0; +} + +/* + * gfs2_ok_to_move - check if it's ok to move a directory to another directory + * @this: move this + * @to: to here + * + * Follow @to back to the root and make sure we don't encounter @this + * Assumes we already hold the rename lock. + * + * Returns: errno + */ + +int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) +{ + struct gfs2_sbd *sdp = this->i_sbd; + struct gfs2_inode *tmp; + struct qstr dotdot; + int error = 0; + + memset(&dotdot, 0, sizeof(struct qstr)); + dotdot.name = ".."; + dotdot.len = 2; + + gfs2_inode_hold(to); + + for (;;) { + if (to == this) { + error = -EINVAL; + break; + } + if (to == sdp->sd_root_dir) { + error = 0; + break; + } + + error = gfs2_lookupi(to, &dotdot, 1, &tmp); + if (error) + break; + + gfs2_inode_put(to); + to = tmp; + } + + gfs2_inode_put(to); + + return error; +} + +/** + * gfs2_readlinki - return the contents of a symlink + * @ip: the symlink's inode + * @buf: a pointer to the buffer to be filled + * @len: a pointer to the length of @buf + * + * If @buf is too small, a piece of memory is kmalloc()ed and needs + * to be freed by the caller. + * + * Returns: errno + */ + +int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) +{ + struct gfs2_holder i_gh; + struct buffer_head *dibh; + unsigned int x; + int error; + + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh); + error = gfs2_glock_nq_atime(&i_gh); + if (error) { + gfs2_holder_uninit(&i_gh); + return error; + } + + if (!ip->i_di.di_size) { + gfs2_consist_inode(ip); + error = -EIO; + goto out; + } + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out; + + x = ip->i_di.di_size + 1; + if (x > *len) { + *buf = kmalloc(x, GFP_KERNEL); + if (!*buf) { + error = -ENOMEM; + goto out_brelse; + } + } + + memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x); + *len = x; + + out_brelse: + brelse(dibh); + + out: + gfs2_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs2_glock_nq_atime - Acquire a hold on an inode's glock, and + * conditionally update the inode's atime + * @gh: the holder to acquire + * + * Tests atime (access time) for gfs2_read, gfs2_readdir and gfs2_mmap + * Update if the difference between the current time and the inode's current + * atime is greater than an interval specified at mount. + * + * Returns: errno + */ + +int gfs2_glock_nq_atime(struct gfs2_holder *gh) +{ + struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_inode *ip = get_gl2ip(gl); + int64_t curtime, quantum = gfs2_tune_get(sdp, gt_atime_quantum); + unsigned int state; + int flags; + int error; + + if (gfs2_assert_warn(sdp, gh->gh_flags & GL_ATIME) || + gfs2_assert_warn(sdp, !(gh->gh_flags & GL_ASYNC)) || + gfs2_assert_warn(sdp, gl->gl_ops == &gfs2_inode_glops)) + return -EINVAL; + + state = gh->gh_state; + flags = gh->gh_flags; + + error = gfs2_glock_nq(gh); + if (error) + return error; + + if (test_bit(SDF_NOATIME, &sdp->sd_flags) || + (sdp->sd_vfs->s_flags & MS_RDONLY)) + return 0; + + curtime = get_seconds(); + if (curtime - ip->i_di.di_atime >= quantum) { + gfs2_glock_dq(gh); + gfs2_holder_reinit(LM_ST_EXCLUSIVE, + gh->gh_flags & ~LM_FLAG_ANY, + gh); + error = gfs2_glock_nq(gh); + if (error) + return error; + + /* Verify that atime hasn't been updated while we were + trying to get exclusive lock. */ + + curtime = get_seconds(); + if (curtime - ip->i_di.di_atime >= quantum) { + struct buffer_head *dibh; + + error = gfs2_trans_begin(sdp, RES_DINODE, 0); + if (error == -EROFS) + return 0; + if (error) + goto fail; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + ip->i_di.di_atime = curtime; + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + gfs2_trans_end(sdp); + } + + /* If someone else has asked for the glock, + unlock and let them have it. Then reacquire + in the original state. */ + if (gfs2_glock_is_blocking(gl)) { + gfs2_glock_dq(gh); + gfs2_holder_reinit(state, flags, gh); + return gfs2_glock_nq(gh); + } + } + + return 0; + + fail_end_trans: + gfs2_trans_end(sdp); + + fail: + gfs2_glock_dq(gh); + + return error; +} + +/** + * glock_compare_atime - Compare two struct gfs2_glock structures for sort + * @arg_a: the first structure + * @arg_b: the second structure + * + * Returns: 1 if A > B + * -1 if A < B + * 0 if A = B + */ + +static int glock_compare_atime(const void *arg_a, const void *arg_b) +{ + struct gfs2_holder *gh_a = *(struct gfs2_holder **)arg_a; + struct gfs2_holder *gh_b = *(struct gfs2_holder **)arg_b; + struct lm_lockname *a = &gh_a->gh_gl->gl_name; + struct lm_lockname *b = &gh_b->gh_gl->gl_name; + int ret = 0; + + if (a->ln_number > b->ln_number) + ret = 1; + else if (a->ln_number < b->ln_number) + ret = -1; + else { + if (gh_a->gh_state == LM_ST_SHARED && + gh_b->gh_state == LM_ST_EXCLUSIVE) + ret = 1; + else if (gh_a->gh_state == LM_ST_SHARED && + (gh_b->gh_flags & GL_ATIME)) + ret = 1; + } + + return ret; +} + +/** + * gfs2_glock_nq_m_atime - acquire multiple glocks where one may need an + * atime update + * @num_gh: the number of structures + * @ghs: an array of struct gfs2_holder structures + * + * Returns: 0 on success (all glocks acquired), + * errno on failure (no glocks acquired) + */ + +int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs) +{ + struct gfs2_holder **p; + unsigned int x; + int error = 0; + + if (!num_gh) + return 0; + + if (num_gh == 1) { + ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC); + if (ghs->gh_flags & GL_ATIME) + error = gfs2_glock_nq_atime(ghs); + else + error = gfs2_glock_nq(ghs); + return error; + } + + p = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL); + if (!p) + return -ENOMEM; + + for (x = 0; x < num_gh; x++) + p[x] = &ghs[x]; + + sort(p, num_gh, sizeof(struct gfs2_holder *), glock_compare_atime,NULL); + + for (x = 0; x < num_gh; x++) { + p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC); + + if (p[x]->gh_flags & GL_ATIME) + error = gfs2_glock_nq_atime(p[x]); + else + error = gfs2_glock_nq(p[x]); + + if (error) { + while (x--) + gfs2_glock_dq(p[x]); + break; + } + } + + kfree(p); + + return error; +} + +/** + * gfs2_try_toss_vnode - See if we can toss a vnode from memory + * @ip: the inode + * + * Returns: 1 if the vnode was tossed + */ + +void gfs2_try_toss_vnode(struct gfs2_inode *ip) +{ + struct inode *inode; + + inode = gfs2_ip2v_lookup(ip); + if (!inode) + return; + + d_prune_aliases(inode); + + if (S_ISDIR(ip->i_di.di_mode)) { + struct list_head *head = &inode->i_dentry; + struct dentry *d = NULL; + + spin_lock(&dcache_lock); + if (list_empty(head)) + spin_unlock(&dcache_lock); + else { + d = list_entry(head->next, struct dentry, d_alias); + dget_locked(d); + spin_unlock(&dcache_lock); + + if (have_submounts(d)) + dput(d); + else { + shrink_dcache_parent(d); + dput(d); + d_prune_aliases(inode); + } + } + } + + inode->i_nlink = 0; + iput(inode); +} + + +static int +__gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) +{ + struct buffer_head *dibh; + int error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + error = inode_setattr(ip->i_vnode, attr); + gfs2_assert_warn(ip->i_sbd, !error); + gfs2_inode_attr_out(ip); + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + return error; +} + +/** + * gfs2_setattr_simple - + * @ip: + * @attr: + * + * Called with a reference on the vnode. + * + * Returns: errno + */ + +int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) +{ + int error; + + if (get_transaction) + return __gfs2_setattr_simple(ip, attr); + + error = gfs2_trans_begin(ip->i_sbd, RES_DINODE, 0); + if (error) + return error; + + error = __gfs2_setattr_simple(ip, attr); + + gfs2_trans_end(ip->i_sbd); + + return error; +} + +int gfs2_repermission(struct inode *inode, int mask, struct nameidata *nd) +{ + return permission(inode, mask, nd); +} + diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h new file mode 100644 index 000000000000..4df7da51f715 --- /dev/null +++ b/fs/gfs2/inode.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __INODE_DOT_H__ +#define __INODE_DOT_H__ + +static inline int gfs2_is_stuffed(struct gfs2_inode *ip) +{ + return !ip->i_di.di_height; +} + +static inline int gfs2_is_jdata(struct gfs2_inode *ip) +{ + return ip->i_di.di_flags & GFS2_DIF_JDATA; +} + +void gfs2_inode_attr_in(struct gfs2_inode *ip); +void gfs2_inode_attr_out(struct gfs2_inode *ip); +struct inode *gfs2_ip2v_lookup(struct gfs2_inode *ip); +struct inode *gfs2_ip2v(struct gfs2_inode *ip); +struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum); + +void gfs2_inode_min_init(struct gfs2_inode *ip, unsigned int type); +int gfs2_inode_refresh(struct gfs2_inode *ip); + +int gfs2_inode_get(struct gfs2_glock *i_gl, + struct gfs2_inum *inum, int create, + struct gfs2_inode **ipp); +void gfs2_inode_hold(struct gfs2_inode *ip); +void gfs2_inode_put(struct gfs2_inode *ip); +void gfs2_inode_destroy(struct gfs2_inode *ip); + +int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); + +int gfs2_change_nlink(struct gfs2_inode *ip, int diff); +int gfs2_lookupi(struct gfs2_inode *dip, struct qstr *name, int is_root, + struct gfs2_inode **ipp); +int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode); +int gfs2_unlinki(struct gfs2_inode *dip, struct qstr *name, + struct gfs2_inode *ip, struct gfs2_unlinked *ul); +int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, + struct gfs2_inode *ip, struct gfs2_unlinked *ul); +int gfs2_unlink_ok(struct gfs2_inode *dip, struct qstr *name, + struct gfs2_inode *ip); +int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to); +int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len); + +int gfs2_glock_nq_atime(struct gfs2_holder *gh); +int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs); + +void gfs2_try_toss_vnode(struct gfs2_inode *ip); + +int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); + +int gfs2_repermission(struct inode *inode, int mask, struct nameidata *nd); + +static inline int gfs2_lookup_simple(struct gfs2_inode *dip, char *name, + struct gfs2_inode **ipp) +{ + struct qstr qstr; + memset(&qstr, 0, sizeof(struct qstr)); + qstr.name = name; + qstr.len = strlen(name); + return gfs2_lookupi(dip, &qstr, 1, ipp); +} + +#endif /* __INODE_DOT_H__ */ + diff --git a/fs/gfs2/jdata.c b/fs/gfs2/jdata.c new file mode 100644 index 000000000000..d4adbf171ed3 --- /dev/null +++ b/fs/gfs2/jdata.c @@ -0,0 +1,382 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "inode.h" +#include "jdata.h" +#include "meta_io.h" +#include "trans.h" + +int gfs2_jdata_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, + struct buffer_head **bhp) +{ + struct buffer_head *bh; + int error = 0; + + if (new) { + bh = gfs2_meta_new(ip->i_gl, block); + gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD); + gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); + } else { + error = gfs2_meta_read(ip->i_gl, block, + DIO_START | DIO_WAIT, &bh); + if (error) + return error; + if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_JD)) { + brelse(bh); + return -EIO; + } + } + + *bhp = bh; + + return 0; +} + +/** + * gfs2_copy2mem - Trivial copy function for gfs2_jdata_read() + * @bh: The buffer to copy from, or NULL meaning zero the buffer + * @buf: The buffer to copy/zero + * @offset: The offset in the buffer to copy from + * @size: The amount of data to copy/zero + * + * Returns: errno + */ + +int gfs2_copy2mem(struct buffer_head *bh, char **buf, unsigned int offset, + unsigned int size) +{ + if (bh) + memcpy(*buf, bh->b_data + offset, size); + else + memset(*buf, 0, size); + *buf += size; + return 0; +} + +/** + * gfs2_copy2user - Copy bytes to user space for gfs2_jdata_read() + * @bh: The buffer + * @buf: The destination of the data + * @offset: The offset into the buffer + * @size: The amount of data to copy + * + * Returns: errno + */ + +int gfs2_copy2user(struct buffer_head *bh, char **buf, unsigned int offset, + unsigned int size) +{ + int error; + + if (bh) + error = copy_to_user(*buf, bh->b_data + offset, size); + else + error = clear_user(*buf, size); + + if (error) + error = -EFAULT; + else + *buf += size; + + return error; +} + +static int jdata_read_stuffed(struct gfs2_inode *ip, char *buf, + unsigned int offset, unsigned int size, + read_copy_fn_t copy_fn) +{ + struct buffer_head *dibh; + int error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + error = copy_fn(dibh, &buf, + offset + sizeof(struct gfs2_dinode), size); + brelse(dibh); + } + + return (error) ? error : size; +} + +/** + * gfs2_jdata_read - Read a jdata file + * @ip: The GFS2 Inode + * @buf: The buffer to place result into + * @offset: File offset to begin jdata_readng from + * @size: Amount of data to transfer + * @copy_fn: Function to actually perform the copy + * + * The @copy_fn only copies a maximum of a single block at once so + * we are safe calling it with int arguments. It is done so that + * we don't needlessly put 64bit arguments on the stack and it + * also makes the code in the @copy_fn nicer too. + * + * Returns: The amount of data actually copied or the error + */ + +int gfs2_jdata_read(struct gfs2_inode *ip, char __user *buf, uint64_t offset, + unsigned int size, read_copy_fn_t copy_fn) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + uint64_t lblock, dblock; + uint32_t extlen = 0; + unsigned int o; + int copied = 0; + int error = 0; + + if (offset >= ip->i_di.di_size) + return 0; + + if ((offset + size) > ip->i_di.di_size) + size = ip->i_di.di_size - offset; + + if (!size) + return 0; + + if (gfs2_is_stuffed(ip)) + return jdata_read_stuffed(ip, buf, (unsigned int)offset, size, + copy_fn); + + if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) + return -EINVAL; + + lblock = offset; + o = do_div(lblock, sdp->sd_jbsize) + + sizeof(struct gfs2_meta_header); + + while (copied < size) { + unsigned int amount; + struct buffer_head *bh; + int new; + + amount = size - copied; + if (amount > sdp->sd_sb.sb_bsize - o) + amount = sdp->sd_sb.sb_bsize - o; + + if (!extlen) { + new = 0; + error = gfs2_block_map(ip, lblock, &new, + &dblock, &extlen); + if (error) + goto fail; + } + + if (extlen > 1) + gfs2_meta_ra(ip->i_gl, dblock, extlen); + + if (dblock) { + error = gfs2_jdata_get_buffer(ip, dblock, new, &bh); + if (error) + goto fail; + dblock++; + extlen--; + } else + bh = NULL; + + error = copy_fn(bh, &buf, o, amount); + brelse(bh); + if (error) + goto fail; + + copied += amount; + lblock++; + + o = sizeof(struct gfs2_meta_header); + } + + return copied; + + fail: + return (copied) ? copied : error; +} + +/** + * gfs2_copy_from_mem - Trivial copy function for gfs2_jdata_write() + * @bh: The buffer to copy to or clear + * @buf: The buffer to copy from + * @offset: The offset in the buffer to write to + * @size: The amount of data to write + * + * Returns: errno + */ + +int gfs2_copy_from_mem(struct gfs2_inode *ip, struct buffer_head *bh, + const char **buf, unsigned int offset, unsigned int size) +{ + gfs2_trans_add_bh(ip->i_gl, bh); + memcpy(bh->b_data + offset, *buf, size); + + *buf += size; + + return 0; +} + +/** + * gfs2_copy_from_user - Copy bytes from user space for gfs2_jdata_write() + * @bh: The buffer to copy to or clear + * @buf: The buffer to copy from + * @offset: The offset in the buffer to write to + * @size: The amount of data to write + * + * Returns: errno + */ + +int gfs2_copy_from_user(struct gfs2_inode *ip, struct buffer_head *bh, + const char __user **buf, unsigned int offset, unsigned int size) +{ + int error = 0; + + gfs2_trans_add_bh(ip->i_gl, bh); + if (copy_from_user(bh->b_data + offset, *buf, size)) + error = -EFAULT; + else + *buf += size; + + return error; +} + +static int jdata_write_stuffed(struct gfs2_inode *ip, char *buf, + unsigned int offset, unsigned int size, + write_copy_fn_t copy_fn) +{ + struct buffer_head *dibh; + int error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; + + error = copy_fn(ip, + dibh, &buf, + offset + sizeof(struct gfs2_dinode), size); + if (!error) { + if (ip->i_di.di_size < offset + size) + ip->i_di.di_size = offset + size; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + } + + brelse(dibh); + + return (error) ? error : size; +} + +/** + * gfs2_jdata_write - Write bytes to a file + * @ip: The GFS2 inode + * @buf: The buffer containing information to be written + * @offset: The file offset to start writing at + * @size: The amount of data to write + * @copy_fn: Function to do the actual copying + * + * Returns: The number of bytes correctly written or error code + */ + +int gfs2_jdata_write(struct gfs2_inode *ip, const char __user *buf, uint64_t offset, + unsigned int size, write_copy_fn_t copy_fn) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head *dibh; + uint64_t lblock, dblock; + uint32_t extlen = 0; + unsigned int o; + int copied = 0; + int error = 0; + + if (!size) + return 0; + + if (gfs2_is_stuffed(ip) && + offset + size <= sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) + return jdata_write_stuffed(ip, buf, (unsigned int)offset, size, + copy_fn); + + if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) + return -EINVAL; + + if (gfs2_is_stuffed(ip)) { + error = gfs2_unstuff_dinode(ip, NULL, NULL); + if (error) + return error; + } + + lblock = offset; + o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header); + + while (copied < size) { + unsigned int amount; + struct buffer_head *bh; + int new; + + amount = size - copied; + if (amount > sdp->sd_sb.sb_bsize - o) + amount = sdp->sd_sb.sb_bsize - o; + + if (!extlen) { + new = 1; + error = gfs2_block_map(ip, lblock, &new, + &dblock, &extlen); + if (error) + goto fail; + error = -EIO; + if (gfs2_assert_withdraw(sdp, dblock)) + goto fail; + } + + error = gfs2_jdata_get_buffer(ip, dblock, + (amount == sdp->sd_jbsize) ? 1 : new, + &bh); + if (error) + goto fail; + + error = copy_fn(ip, bh, &buf, o, amount); + brelse(bh); + if (error) + goto fail; + + copied += amount; + lblock++; + dblock++; + extlen--; + + o = sizeof(struct gfs2_meta_header); + } + + out: + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; + + if (ip->i_di.di_size < offset + copied) + ip->i_di.di_size = offset + copied; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + return copied; + + fail: + if (copied) + goto out; + return error; +} + diff --git a/fs/gfs2/jdata.h b/fs/gfs2/jdata.h new file mode 100644 index 000000000000..95e18fcb8f82 --- /dev/null +++ b/fs/gfs2/jdata.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __FILE_DOT_H__ +#define __FILE_DOT_H__ + +int gfs2_jdata_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, + struct buffer_head **bhp); + +typedef int (*read_copy_fn_t) (struct buffer_head *bh, char **buf, + unsigned int offset, unsigned int size); +typedef int (*write_copy_fn_t) (struct gfs2_inode *ip, + struct buffer_head *bh, const char **buf, + unsigned int offset, unsigned int size); + +int gfs2_copy2mem(struct buffer_head *bh, char **buf, + unsigned int offset, unsigned int size); +int gfs2_copy2user(struct buffer_head *bh, char __user **buf, + unsigned int offset, unsigned int size); +int gfs2_jdata_read(struct gfs2_inode *ip, char __user *buf, + uint64_t offset, unsigned int size, + read_copy_fn_t copy_fn); + +int gfs2_copy_from_mem(struct gfs2_inode *ip, + struct buffer_head *bh, const char **buf, + unsigned int offset, unsigned int size); +int gfs2_copy_from_user(struct gfs2_inode *ip, + struct buffer_head *bh, const char __user **buf, + unsigned int offset, unsigned int size); +int gfs2_jdata_write(struct gfs2_inode *ip, const char __user *buf, + uint64_t offset, unsigned int size, + write_copy_fn_t copy_fn); + +static inline int gfs2_jdata_read_mem(struct gfs2_inode *ip, char *buf, + uint64_t offset, unsigned int size) +{ + return gfs2_jdata_read(ip, (__force char __user *)buf, offset, size, gfs2_copy2mem); +} + +static inline int gfs2_jdata_write_mem(struct gfs2_inode *ip, const char *buf, + uint64_t offset, unsigned int size) +{ + return gfs2_jdata_write(ip, (__force const char __user *)buf, offset, size, gfs2_copy_from_mem); +} + +#endif /* __FILE_DOT_H__ */ diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c new file mode 100644 index 000000000000..cc7442261b2e --- /dev/null +++ b/fs/gfs2/lm.c @@ -0,0 +1,235 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "glock.h" +#include "lm.h" +#include "super.h" + +/** + * gfs2_lm_mount - mount a locking protocol + * @sdp: the filesystem + * @args: mount arguements + * @silent: if 1, don't complain if the FS isn't a GFS2 fs + * + * Returns: errno + */ + +int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) +{ + char *proto = sdp->sd_proto_name; + char *table = sdp->sd_table_name; + int flags = 0; + int error; + + if (sdp->sd_args.ar_spectator) + flags |= LM_MFLAG_SPECTATOR; + + fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table); + + error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata, + gfs2_glock_cb, sdp, + GFS2_MIN_LVB_SIZE, flags, + &sdp->sd_lockstruct, &sdp->sd_kobj); + if (error) { + fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n", + proto, table, sdp->sd_args.ar_hostdata); + goto out; + } + + if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lockspace) || + gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) || + gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >= + GFS2_MIN_LVB_SIZE)) { + gfs2_unmount_lockproto(&sdp->sd_lockstruct); + goto out; + } + + if (sdp->sd_args.ar_spectator) + snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table); + else + snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table, + sdp->sd_lockstruct.ls_jid); + + fs_info(sdp, "Joined cluster. Now mounting FS...\n"); + + if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) && + !sdp->sd_args.ar_ignore_local_fs) { + sdp->sd_args.ar_localflocks = 1; + sdp->sd_args.ar_localcaching = 1; + } + + out: + return error; +} + +void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_others_may_mount(sdp->sd_lockstruct.ls_lockspace); +} + +void gfs2_lm_unmount(struct gfs2_sbd *sdp) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + gfs2_unmount_lockproto(&sdp->sd_lockstruct); +} + +int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) +{ + va_list args; + + if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + return 0; + + va_start(args, fmt); + vprintk(fmt, args); + va_end(args); + + fs_err(sdp, "about to withdraw from the cluster\n"); + if (sdp->sd_args.ar_debug) + BUG(); + + fs_err(sdp, "waiting for outstanding I/O\n"); + + /* FIXME: suspend dm device so oustanding bio's complete + and all further io requests fail */ + + fs_err(sdp, "telling LM to withdraw\n"); + gfs2_withdraw_lockproto(&sdp->sd_lockstruct); + fs_err(sdp, "withdrawn\n"); + dump_stack(); + + return -1; +} + +int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name, + lm_lock_t **lockp) +{ + int error; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + else + error = sdp->sd_lockstruct.ls_ops->lm_get_lock(sdp->sd_lockstruct.ls_lockspace, name, lockp); + return error; +} + +void gfs2_lm_put_lock(struct gfs2_sbd *sdp, lm_lock_t *lock) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_put_lock(lock); +} + +unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, lm_lock_t *lock, + unsigned int cur_state, unsigned int req_state, + unsigned int flags) +{ + int ret; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + ret = 0; + else + ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, + cur_state, + req_state, flags); + return ret; +} + +unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, lm_lock_t *lock, + unsigned int cur_state) +{ + int ret; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + ret = 0; + else + ret = sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state); + return ret; +} + +void gfs2_lm_cancel(struct gfs2_sbd *sdp, lm_lock_t *lock) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_cancel(lock); +} + +int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char **lvbp) +{ + int error; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + else + error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp); + return error; +} + +void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(lock, lvb); +} + +void gfs2_lm_sync_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_sync_lvb(lock, lvb); +} + +int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + int error; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + else + error = sdp->sd_lockstruct.ls_ops->lm_plock_get( + sdp->sd_lockstruct.ls_lockspace, + name, file, fl); + return error; +} + +int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl) +{ + int error; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + else + error = sdp->sd_lockstruct.ls_ops->lm_plock( + sdp->sd_lockstruct.ls_lockspace, + name, file, cmd, fl); + return error; +} + +int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + int error; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + else + error = sdp->sd_lockstruct.ls_ops->lm_punlock( + sdp->sd_lockstruct.ls_lockspace, + name, file, fl); + return error; +} + +void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, + unsigned int message) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_recovery_done(sdp->sd_lockstruct.ls_lockspace, jid, message); +} + diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h new file mode 100644 index 000000000000..ec812424fdec --- /dev/null +++ b/fs/gfs2/lm.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __LM_DOT_H__ +#define __LM_DOT_H__ + +int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent); +void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp); +void gfs2_lm_unmount(struct gfs2_sbd *sdp); +int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) +__attribute__ ((format(printf, 2, 3))); +int gfs2_lm_get_lock(struct gfs2_sbd *sdp, + struct lm_lockname *name, lm_lock_t **lockp); +void gfs2_lm_put_lock(struct gfs2_sbd *sdp, lm_lock_t *lock); +unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, lm_lock_t *lock, + unsigned int cur_state, unsigned int req_state, + unsigned int flags); +unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, lm_lock_t *lock, + unsigned int cur_state); +void gfs2_lm_cancel(struct gfs2_sbd *sdp, lm_lock_t *lock); +int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char **lvbp); +void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb); +void gfs2_lm_sync_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb); +int gfs2_lm_plock_get(struct gfs2_sbd *sdp, + struct lm_lockname *name, + struct file *file, struct file_lock *fl); +int gfs2_lm_plock(struct gfs2_sbd *sdp, + struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl); +int gfs2_lm_punlock(struct gfs2_sbd *sdp, + struct lm_lockname *name, + struct file *file, struct file_lock *fl); +void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, + unsigned int jid, unsigned int message); + +#endif /* __LM_DOT_H__ */ diff --git a/fs/gfs2/lm_interface.h b/fs/gfs2/lm_interface.h new file mode 100644 index 000000000000..378432f17f27 --- /dev/null +++ b/fs/gfs2/lm_interface.h @@ -0,0 +1,295 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __LM_INTERFACE_DOT_H__ +#define __LM_INTERFACE_DOT_H__ + +/* + * Opaque handles represent the lock module's lockspace structure, the lock + * module's lock structures, and GFS's file system (superblock) structure. + */ + +typedef void lm_lockspace_t; +typedef void lm_lock_t; +typedef void lm_fsdata_t; + +typedef void (*lm_callback_t) (lm_fsdata_t *fsdata, unsigned int type, + void *data); + +/* + * lm_mount() flags + * + * LM_MFLAG_SPECTATOR + * GFS is asking to join the filesystem's lockspace, but it doesn't want to + * modify the filesystem. The lock module shouldn't assign a journal to the FS + * mount. It shouldn't send recovery callbacks to the FS mount. If the node + * dies or withdraws, all locks can be wiped immediately. + */ + +#define LM_MFLAG_SPECTATOR 0x00000001 + +/* + * lm_lockstruct flags + * + * LM_LSFLAG_LOCAL + * The lock_nolock module returns LM_LSFLAG_LOCAL to GFS, indicating that GFS + * can make single-node optimizations. + */ + +#define LM_LSFLAG_LOCAL 0x00000001 + +/* + * lm_lockname types + */ + +#define LM_TYPE_RESERVED 0x00 +#define LM_TYPE_NONDISK 0x01 +#define LM_TYPE_INODE 0x02 +#define LM_TYPE_RGRP 0x03 +#define LM_TYPE_META 0x04 +#define LM_TYPE_IOPEN 0x05 +#define LM_TYPE_FLOCK 0x06 +#define LM_TYPE_PLOCK 0x07 +#define LM_TYPE_QUOTA 0x08 +#define LM_TYPE_JOURNAL 0x09 + +/* + * lm_lock() states + * + * SHARED is compatible with SHARED, not with DEFERRED or EX. + * DEFERRED is compatible with DEFERRED, not with SHARED or EX. + */ + +#define LM_ST_UNLOCKED 0 +#define LM_ST_EXCLUSIVE 1 +#define LM_ST_DEFERRED 2 +#define LM_ST_SHARED 3 + +/* + * lm_lock() flags + * + * LM_FLAG_TRY + * Don't wait to acquire the lock if it can't be granted immediately. + * + * LM_FLAG_TRY_1CB + * Send one blocking callback if TRY is set and the lock is not granted. + * + * LM_FLAG_NOEXP + * GFS sets this flag on lock requests it makes while doing journal recovery. + * These special requests should not be blocked due to the recovery like + * ordinary locks would be. + * + * LM_FLAG_ANY + * A SHARED request may also be granted in DEFERRED, or a DEFERRED request may + * also be granted in SHARED. The preferred state is whichever is compatible + * with other granted locks, or the specified state if no other locks exist. + * + * LM_FLAG_PRIORITY + * Override fairness considerations. Suppose a lock is held in a shared state + * and there is a pending request for the deferred state. A shared lock + * request with the priority flag would be allowed to bypass the deferred + * request and directly join the other shared lock. A shared lock request + * without the priority flag might be forced to wait until the deferred + * requested had acquired and released the lock. + */ + +#define LM_FLAG_TRY 0x00000001 +#define LM_FLAG_TRY_1CB 0x00000002 +#define LM_FLAG_NOEXP 0x00000004 +#define LM_FLAG_ANY 0x00000008 +#define LM_FLAG_PRIORITY 0x00000010 + +/* + * lm_lock() and lm_async_cb return flags + * + * LM_OUT_ST_MASK + * Masks the lower two bits of lock state in the returned value. + * + * LM_OUT_CACHEABLE + * The lock hasn't been released so GFS can continue to cache data for it. + * + * LM_OUT_CANCELED + * The lock request was canceled. + * + * LM_OUT_ASYNC + * The result of the request will be returned in an LM_CB_ASYNC callback. + */ + +#define LM_OUT_ST_MASK 0x00000003 +#define LM_OUT_CACHEABLE 0x00000004 +#define LM_OUT_CANCELED 0x00000008 +#define LM_OUT_ASYNC 0x00000080 +#define LM_OUT_ERROR 0x00000100 + +/* + * lm_callback_t types + * + * LM_CB_NEED_E LM_CB_NEED_D LM_CB_NEED_S + * Blocking callback, a remote node is requesting the given lock in + * EXCLUSIVE, DEFERRED, or SHARED. + * + * LM_CB_NEED_RECOVERY + * The given journal needs to be recovered. + * + * LM_CB_DROPLOCKS + * Reduce the number of cached locks. + * + * LM_CB_ASYNC + * The given lock has been granted. + */ + +#define LM_CB_NEED_E 257 +#define LM_CB_NEED_D 258 +#define LM_CB_NEED_S 259 +#define LM_CB_NEED_RECOVERY 260 +#define LM_CB_DROPLOCKS 261 +#define LM_CB_ASYNC 262 + +/* + * lm_recovery_done() messages + */ + +#define LM_RD_GAVEUP 308 +#define LM_RD_SUCCESS 309 + + +struct lm_lockname { + uint64_t ln_number; + unsigned int ln_type; +}; + +#define lm_name_equal(name1, name2) \ + (((name1)->ln_number == (name2)->ln_number) && \ + ((name1)->ln_type == (name2)->ln_type)) \ + +struct lm_async_cb { + struct lm_lockname lc_name; + int lc_ret; +}; + +struct lm_lockstruct; + +struct lm_lockops { + char lm_proto_name[256]; + + /* + * Mount/Unmount + */ + + int (*lm_mount) (char *table_name, char *host_data, + lm_callback_t cb, lm_fsdata_t *fsdata, + unsigned int min_lvb_size, int flags, + struct lm_lockstruct *lockstruct, + struct kobject *fskobj); + + void (*lm_others_may_mount) (lm_lockspace_t *lockspace); + + void (*lm_unmount) (lm_lockspace_t *lockspace); + + void (*lm_withdraw) (lm_lockspace_t *lockspace); + + /* + * Lock oriented operations + */ + + int (*lm_get_lock) (lm_lockspace_t *lockspace, + struct lm_lockname *name, lm_lock_t **lockp); + + void (*lm_put_lock) (lm_lock_t *lock); + + unsigned int (*lm_lock) (lm_lock_t *lock, unsigned int cur_state, + unsigned int req_state, unsigned int flags); + + unsigned int (*lm_unlock) (lm_lock_t *lock, unsigned int cur_state); + + void (*lm_cancel) (lm_lock_t *lock); + + int (*lm_hold_lvb) (lm_lock_t *lock, char **lvbp); + void (*lm_unhold_lvb) (lm_lock_t *lock, char *lvb); + void (*lm_sync_lvb) (lm_lock_t *lock, char *lvb); + + /* + * Posix Lock oriented operations + */ + + int (*lm_plock_get) (lm_lockspace_t *lockspace, + struct lm_lockname *name, + struct file *file, struct file_lock *fl); + + int (*lm_plock) (lm_lockspace_t *lockspace, + struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl); + + int (*lm_punlock) (lm_lockspace_t *lockspace, + struct lm_lockname *name, + struct file *file, struct file_lock *fl); + + /* + * Client oriented operations + */ + + void (*lm_recovery_done) (lm_lockspace_t *lockspace, unsigned int jid, + unsigned int message); + + struct module *lm_owner; +}; + +/* + * lm_mount() return values + * + * ls_jid - the journal ID this node should use + * ls_first - this node is the first to mount the file system + * ls_lvb_size - size in bytes of lock value blocks + * ls_lockspace - lock module's context for this file system + * ls_ops - lock module's functions + * ls_flags - lock module features + */ + +struct lm_lockstruct { + unsigned int ls_jid; + unsigned int ls_first; + unsigned int ls_lvb_size; + lm_lockspace_t *ls_lockspace; + struct lm_lockops *ls_ops; + int ls_flags; +}; + +void __init gfs2_init_lmh(void); + +/* + * Lock module bottom interface. A lock module makes itself available to GFS + * with these functions. + * + * For the time being, we copy the gfs1 lock module bottom interface so the + * same lock modules can be used with both gfs1 and gfs2 (it won't be possible + * to load both gfs1 and gfs2 at once.) Eventually the lock modules will fork + * for gfs1/gfs2 and this API can change to the gfs2_ prefix. + */ + +int gfs_register_lockproto(struct lm_lockops *proto); + +void gfs_unregister_lockproto(struct lm_lockops *proto); + +/* + * Lock module top interface. GFS calls these functions when mounting or + * unmounting a file system. + */ + +int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, + lm_callback_t cb, lm_fsdata_t *fsdata, + unsigned int min_lvb_size, int flags, + struct lm_lockstruct *lockstruct, + struct kobject *fskobj); + +void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct); + +void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct); + +#endif /* __LM_INTERFACE_DOT_H__ */ + diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c new file mode 100644 index 000000000000..2d2f8fe53999 --- /dev/null +++ b/fs/gfs2/locking.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lm_interface.h" + +struct lmh_wrapper { + struct list_head lw_list; + struct lm_lockops *lw_ops; +}; + +/* List of registered low-level locking protocols. A file system selects one + of them by name at mount time, e.g. lock_nolock, lock_dlm. */ + +static struct list_head lmh_list; +static struct semaphore lmh_lock; + +/** + * gfs_register_lockproto - Register a low-level locking protocol + * @proto: the protocol definition + * + * Returns: 0 on success, -EXXX on failure + */ + +int gfs_register_lockproto(struct lm_lockops *proto) +{ + struct lmh_wrapper *lw; + + down(&lmh_lock); + + list_for_each_entry(lw, &lmh_list, lw_list) { + if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) { + up(&lmh_lock); + printk("GFS2: protocol %s already exists\n", + proto->lm_proto_name); + return -EEXIST; + } + } + + lw = kmalloc(sizeof(struct lmh_wrapper), GFP_KERNEL); + if (!lw) { + up(&lmh_lock); + return -ENOMEM; + } + memset(lw, 0, sizeof(struct lmh_wrapper)); + + lw->lw_ops = proto; + list_add(&lw->lw_list, &lmh_list); + + up(&lmh_lock); + + return 0; +} + +/** + * gfs_unregister_lockproto - Unregister a low-level locking protocol + * @proto: the protocol definition + * + */ + +void gfs_unregister_lockproto(struct lm_lockops *proto) +{ + struct lmh_wrapper *lw; + + down(&lmh_lock); + + list_for_each_entry(lw, &lmh_list, lw_list) { + if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) { + list_del(&lw->lw_list); + up(&lmh_lock); + kfree(lw); + return; + } + } + + up(&lmh_lock); + + printk("GFS2: can't unregister lock protocol %s\n", + proto->lm_proto_name); +} + +/** + * gfs2_mount_lockproto - Mount a lock protocol + * @proto_name - the name of the protocol + * @table_name - the name of the lock space + * @host_data - data specific to this host + * @cb - the callback to the code using the lock module + * @fsdata - data to pass back with the callback + * @min_lvb_size - the mininum LVB size that the caller can deal with + * @flags - LM_MFLAG_* + * @lockstruct - a structure returned describing the mount + * + * Returns: 0 on success, -EXXX on failure + */ + +int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, + lm_callback_t cb, lm_fsdata_t *fsdata, + unsigned int min_lvb_size, int flags, + struct lm_lockstruct *lockstruct, + struct kobject *fskobj) +{ + struct lmh_wrapper *lw = NULL; + int try = 0; + int error, found; + + retry: + down(&lmh_lock); + + found = 0; + list_for_each_entry(lw, &lmh_list, lw_list) { + if (!strcmp(lw->lw_ops->lm_proto_name, proto_name)) { + found = 1; + break; + } + } + + if (!found) { + if (!try && capable(CAP_SYS_MODULE)) { + try = 1; + up(&lmh_lock); + request_module(proto_name); + goto retry; + } + printk("GFS2: can't find protocol %s\n", proto_name); + error = -ENOENT; + goto out; + } + + if (!try_module_get(lw->lw_ops->lm_owner)) { + try = 0; + up(&lmh_lock); + msleep(1000); + goto retry; + } + + error = lw->lw_ops->lm_mount(table_name, host_data, cb, fsdata, + min_lvb_size, flags, lockstruct, fskobj); + if (error) + module_put(lw->lw_ops->lm_owner); + out: + up(&lmh_lock); + return error; +} + +void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct) +{ + down(&lmh_lock); + lockstruct->ls_ops->lm_unmount(lockstruct->ls_lockspace); + if (lockstruct->ls_ops->lm_owner) + module_put(lockstruct->ls_ops->lm_owner); + up(&lmh_lock); +} + +/** + * gfs2_withdraw_lockproto - abnormally unmount a lock module + * @lockstruct: the lockstruct passed into mount + * + */ + +void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct) +{ + down(&lmh_lock); + lockstruct->ls_ops->lm_withdraw(lockstruct->ls_lockspace); + if (lockstruct->ls_ops->lm_owner) + module_put(lockstruct->ls_ops->lm_owner); + up(&lmh_lock); +} + +void __init gfs2_init_lmh(void) +{ + init_MUTEX(&lmh_lock); + INIT_LIST_HEAD(&lmh_list); +} + +EXPORT_SYMBOL_GPL(gfs_register_lockproto); +EXPORT_SYMBOL_GPL(gfs_unregister_lockproto); + diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c new file mode 100644 index 000000000000..736d0d33dd1b --- /dev/null +++ b/fs/gfs2/log.c @@ -0,0 +1,659 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "glock.h" +#include "log.h" +#include "lops.h" +#include "meta_io.h" + +#define PULL 1 + +static inline int is_done(struct gfs2_sbd *sdp, atomic_t *a) +{ + int done; + gfs2_log_lock(sdp); + done = atomic_read(a) ? 0 : 1; + gfs2_log_unlock(sdp); + return done; +} + +static void do_lock_wait(struct gfs2_sbd *sdp, wait_queue_head_t *wq, + atomic_t *a) +{ + gfs2_log_unlock(sdp); + wait_event(*wq, is_done(sdp, a)); + gfs2_log_lock(sdp); +} + +static void lock_for_trans(struct gfs2_sbd *sdp) +{ + gfs2_log_lock(sdp); + do_lock_wait(sdp, &sdp->sd_log_trans_wq, &sdp->sd_log_flush_count); + atomic_inc(&sdp->sd_log_trans_count); + gfs2_log_unlock(sdp); +} + +static void unlock_from_trans(struct gfs2_sbd *sdp) +{ + gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_trans_count)); + if (atomic_dec_and_test(&sdp->sd_log_trans_count)) + wake_up(&sdp->sd_log_flush_wq); +} + +void gfs2_lock_for_flush(struct gfs2_sbd *sdp) +{ + gfs2_log_lock(sdp); + atomic_inc(&sdp->sd_log_flush_count); + do_lock_wait(sdp, &sdp->sd_log_flush_wq, &sdp->sd_log_trans_count); + gfs2_log_unlock(sdp); +} + +void gfs2_unlock_from_flush(struct gfs2_sbd *sdp) +{ + gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_flush_count)); + if (atomic_dec_and_test(&sdp->sd_log_flush_count)) + wake_up(&sdp->sd_log_trans_wq); +} + +/** + * gfs2_struct2blk - compute stuff + * @sdp: the filesystem + * @nstruct: the number of structures + * @ssize: the size of the structures + * + * Compute the number of log descriptor blocks needed to hold a certain number + * of structures of a certain size. + * + * Returns: the number of blocks needed (minimum is always 1) + */ + +unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, + unsigned int ssize) +{ + unsigned int blks; + unsigned int first, second; + + blks = 1; + first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / ssize; + + if (nstruct > first) { + second = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header)) / ssize; + blks += DIV_RU(nstruct - first, second); + } + + return blks; +} + +void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) +{ + struct list_head *head = &sdp->sd_ail1_list; + uint64_t sync_gen; + struct list_head *first, *tmp; + struct gfs2_ail *first_ai, *ai; + + gfs2_log_lock(sdp); + if (list_empty(head)) { + gfs2_log_unlock(sdp); + return; + } + sync_gen = sdp->sd_ail_sync_gen++; + + first = head->prev; + first_ai = list_entry(first, struct gfs2_ail, ai_list); + first_ai->ai_sync_gen = sync_gen; + gfs2_ail1_start_one(sdp, first_ai); + + if (flags & DIO_ALL) + first = NULL; + + for (;;) { + if (first && + (head->prev != first || + gfs2_ail1_empty_one(sdp, first_ai, 0))) + break; + + for (tmp = head->prev; tmp != head; tmp = tmp->prev) { + ai = list_entry(tmp, struct gfs2_ail, ai_list); + if (ai->ai_sync_gen >= sync_gen) + continue; + ai->ai_sync_gen = sync_gen; + gfs2_ail1_start_one(sdp, ai); + break; + } + + if (tmp == head) + break; + } + + gfs2_log_unlock(sdp); +} + +int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) +{ + struct gfs2_ail *ai, *s; + int ret; + + gfs2_log_lock(sdp); + + list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) { + if (gfs2_ail1_empty_one(sdp, ai, flags)) + list_move(&ai->ai_list, &sdp->sd_ail2_list); + else if (!(flags & DIO_ALL)) + break; + } + + ret = list_empty(&sdp->sd_ail1_list); + + gfs2_log_unlock(sdp); + + return ret; +} + +static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) +{ + struct gfs2_ail *ai, *safe; + unsigned int old_tail = sdp->sd_log_tail; + int wrap = (new_tail < old_tail); + int a, b, rm; + + gfs2_log_lock(sdp); + + list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) { + a = (old_tail <= ai->ai_first); + b = (ai->ai_first < new_tail); + rm = (wrap) ? (a || b) : (a && b); + if (!rm) + continue; + + gfs2_ail2_empty_one(sdp, ai); + list_del(&ai->ai_list); + gfs2_assert_warn(sdp, list_empty(&ai->ai_ail1_list)); + gfs2_assert_warn(sdp, list_empty(&ai->ai_ail2_list)); + kfree(ai); + } + + gfs2_log_unlock(sdp); +} + +/** + * gfs2_log_reserve - Make a log reservation + * @sdp: The GFS2 superblock + * @blks: The number of blocks to reserve + * + * Returns: errno + */ + +int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) +{ + LIST_HEAD(list); + unsigned int try = 0; + + if (gfs2_assert_warn(sdp, blks) || + gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks)) + return -EINVAL; + + for (;;) { + gfs2_log_lock(sdp); + + if (list_empty(&list)) { + list_add_tail(&list, &sdp->sd_log_blks_list); + while (sdp->sd_log_blks_list.next != &list) { + DECLARE_WAITQUEUE(__wait_chan, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&sdp->sd_log_blks_wait, + &__wait_chan); + gfs2_log_unlock(sdp); + schedule(); + gfs2_log_lock(sdp); + remove_wait_queue(&sdp->sd_log_blks_wait, + &__wait_chan); + set_current_state(TASK_RUNNING); + } + } + + /* Never give away the last block so we can + always pull the tail if we need to. */ + if (sdp->sd_log_blks_free > blks) { + sdp->sd_log_blks_free -= blks; + list_del(&list); + gfs2_log_unlock(sdp); + wake_up(&sdp->sd_log_blks_wait); + break; + } + + gfs2_log_unlock(sdp); + + gfs2_ail1_empty(sdp, 0); + gfs2_log_flush(sdp); + + if (try++) + gfs2_ail1_start(sdp, 0); + } + + lock_for_trans(sdp); + + return 0; +} + +/** + * gfs2_log_release - Release a given number of log blocks + * @sdp: The GFS2 superblock + * @blks: The number of blocks + * + */ + +void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) +{ + unlock_from_trans(sdp); + + gfs2_log_lock(sdp); + sdp->sd_log_blks_free += blks; + gfs2_assert_withdraw(sdp, + sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); + gfs2_log_unlock(sdp); +} + +static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) +{ + int new = 0; + uint64_t dbn; + int error; + + error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, &new, &dbn, NULL); + gfs2_assert_withdraw(sdp, !error && dbn); + + return dbn; +} + +/** + * log_distance - Compute distance between two journal blocks + * @sdp: The GFS2 superblock + * @newer: The most recent journal block of the pair + * @older: The older journal block of the pair + * + * Compute the distance (in the journal direction) between two + * blocks in the journal + * + * Returns: the distance in blocks + */ + +static inline unsigned int log_distance(struct gfs2_sbd *sdp, + unsigned int newer, + unsigned int older) +{ + int dist; + + dist = newer - older; + if (dist < 0) + dist += sdp->sd_jdesc->jd_blocks; + + return dist; +} + +static unsigned int current_tail(struct gfs2_sbd *sdp) +{ + struct gfs2_ail *ai; + unsigned int tail; + + gfs2_log_lock(sdp); + + if (list_empty(&sdp->sd_ail1_list)) + tail = sdp->sd_log_head; + else { + ai = list_entry(sdp->sd_ail1_list.prev, + struct gfs2_ail, ai_list); + tail = ai->ai_first; + } + + gfs2_log_unlock(sdp); + + return tail; +} + +static inline void log_incr_head(struct gfs2_sbd *sdp) +{ + if (sdp->sd_log_flush_head == sdp->sd_log_tail) + gfs2_assert_withdraw(sdp, + sdp->sd_log_flush_head == sdp->sd_log_head); + + if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { + sdp->sd_log_flush_head = 0; + sdp->sd_log_flush_wrapped = 1; + } +} + +/** + * gfs2_log_get_buf - Get and initialize a buffer to use for log control data + * @sdp: The GFS2 superblock + * + * Returns: the buffer_head + */ + +struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) +{ + uint64_t blkno = log_bmap(sdp, sdp->sd_log_flush_head); + struct gfs2_log_buf *lb; + struct buffer_head *bh; + + lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_KERNEL | __GFP_NOFAIL); + list_add(&lb->lb_list, &sdp->sd_log_flush_list); + + bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno); + lock_buffer(bh); + memset(bh->b_data, 0, bh->b_size); + set_buffer_uptodate(bh); + clear_buffer_dirty(bh); + unlock_buffer(bh); + + log_incr_head(sdp); + + return bh; +} + +/** + * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log + * @sdp: the filesystem + * @data: the data the buffer_head should point to + * + * Returns: the log buffer descriptor + */ + +struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, + struct buffer_head *real) +{ + uint64_t blkno = log_bmap(sdp, sdp->sd_log_flush_head); + struct gfs2_log_buf *lb; + struct buffer_head *bh; + + lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_KERNEL | __GFP_NOFAIL); + list_add(&lb->lb_list, &sdp->sd_log_flush_list); + lb->lb_real = real; + + bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); + atomic_set(&bh->b_count, 1); + bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate); + set_bh_page(bh, virt_to_page(real->b_data), + ((unsigned long)real->b_data) & (PAGE_SIZE - 1)); + bh->b_blocknr = blkno; + bh->b_size = sdp->sd_sb.sb_bsize; + bh->b_bdev = sdp->sd_vfs->s_bdev; + + log_incr_head(sdp); + + return bh; +} + +static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull) +{ + unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail); + + ail2_empty(sdp, new_tail); + + gfs2_log_lock(sdp); + sdp->sd_log_blks_free += dist - ((pull) ? 1 : 0); + gfs2_assert_withdraw(sdp, + sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); + gfs2_log_unlock(sdp); + + sdp->sd_log_tail = new_tail; +} + +/** + * log_write_header - Get and initialize a journal header buffer + * @sdp: The GFS2 superblock + * + * Returns: the initialized log buffer descriptor + */ + +static void log_write_header(struct gfs2_sbd *sdp, uint32_t flags, int pull) +{ + uint64_t blkno = log_bmap(sdp, sdp->sd_log_flush_head); + struct buffer_head *bh; + struct gfs2_log_header *lh; + unsigned int tail; + uint32_t hash; + + atomic_inc(&sdp->sd_log_flush_ondisk); + + bh = sb_getblk(sdp->sd_vfs, blkno); + lock_buffer(bh); + memset(bh->b_data, 0, bh->b_size); + set_buffer_uptodate(bh); + clear_buffer_dirty(bh); + unlock_buffer(bh); + + gfs2_ail1_empty(sdp, 0); + tail = current_tail(sdp); + + lh = (struct gfs2_log_header *)bh->b_data; + memset(lh, 0, sizeof(struct gfs2_log_header)); + lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + lh->lh_header.mh_type = cpu_to_be16(GFS2_METATYPE_LH); + lh->lh_header.mh_format = cpu_to_be16(GFS2_FORMAT_LH); + lh->lh_sequence = be64_to_cpu(sdp->sd_log_sequence++); + lh->lh_flags = be32_to_cpu(flags); + lh->lh_tail = be32_to_cpu(tail); + lh->lh_blkno = be32_to_cpu(sdp->sd_log_flush_head); + hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header)); + lh->lh_hash = cpu_to_be32(hash); + + set_buffer_dirty(bh); + if (sync_dirty_buffer(bh)) + gfs2_io_error_bh(sdp, bh); + brelse(bh); + + if (sdp->sd_log_tail != tail) + log_pull_tail(sdp, tail, pull); + else + gfs2_assert_withdraw(sdp, !pull); + + sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); + log_incr_head(sdp); +} + +static void log_flush_commit(struct gfs2_sbd *sdp) +{ + struct list_head *head = &sdp->sd_log_flush_list; + struct gfs2_log_buf *lb; + struct buffer_head *bh; + unsigned int d; + + d = log_distance(sdp, sdp->sd_log_flush_head, sdp->sd_log_head); + + gfs2_assert_withdraw(sdp, d + 1 == sdp->sd_log_blks_reserved); + + while (!list_empty(head)) { + lb = list_entry(head->next, struct gfs2_log_buf, lb_list); + list_del(&lb->lb_list); + bh = lb->lb_bh; + + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) + gfs2_io_error_bh(sdp, bh); + if (lb->lb_real) { + while (atomic_read(&bh->b_count) != 1) /* Grrrr... */ + schedule(); + free_buffer_head(bh); + } else + brelse(bh); + kfree(lb); + } + + log_write_header(sdp, 0, 0); +} + +/** + * gfs2_log_flush_i - flush incore transaction(s) + * @sdp: the filesystem + * @gl: The glock structure to flush. If NULL, flush the whole incore log + * + */ + +void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) +{ + struct gfs2_ail *ai; + + atomic_inc(&sdp->sd_log_flush_incore); + + ai = kzalloc(sizeof(struct gfs2_ail), GFP_KERNEL | __GFP_NOFAIL); + INIT_LIST_HEAD(&ai->ai_ail1_list); + INIT_LIST_HEAD(&ai->ai_ail2_list); + + gfs2_lock_for_flush(sdp); + down(&sdp->sd_log_flush_lock); + + gfs2_assert_withdraw(sdp, + sdp->sd_log_num_buf == sdp->sd_log_commited_buf); + gfs2_assert_withdraw(sdp, + sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke); + + if (gl && list_empty(&gl->gl_le.le_list)) { + up(&sdp->sd_log_flush_lock); + gfs2_unlock_from_flush(sdp); + kfree(ai); + return; + } + + sdp->sd_log_flush_head = sdp->sd_log_head; + sdp->sd_log_flush_wrapped = 0; + ai->ai_first = sdp->sd_log_flush_head; + + lops_before_commit(sdp); + if (!list_empty(&sdp->sd_log_flush_list)) + log_flush_commit(sdp); + else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle) + log_write_header(sdp, 0, PULL); + lops_after_commit(sdp, ai); + + sdp->sd_log_head = sdp->sd_log_flush_head; + if (sdp->sd_log_flush_wrapped) + sdp->sd_log_wraps++; + + sdp->sd_log_blks_reserved = + sdp->sd_log_commited_buf = + sdp->sd_log_commited_revoke = 0; + + gfs2_log_lock(sdp); + if (!list_empty(&ai->ai_ail1_list)) { + list_add(&ai->ai_list, &sdp->sd_ail1_list); + ai = NULL; + } + gfs2_log_unlock(sdp); + + up(&sdp->sd_log_flush_lock); + sdp->sd_vfs->s_dirt = 0; + gfs2_unlock_from_flush(sdp); + + kfree(ai); +} + +static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) +{ + unsigned int reserved = 1; + unsigned int old; + + gfs2_log_lock(sdp); + + sdp->sd_log_commited_buf += tr->tr_num_buf_new - tr->tr_num_buf_rm; + gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_buf) >= 0); + sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm; + gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0); + + if (sdp->sd_log_commited_buf) + reserved += 1 + sdp->sd_log_commited_buf + sdp->sd_log_commited_buf/503; + if (sdp->sd_log_commited_revoke) + reserved += gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke, + sizeof(uint64_t)); + + old = sdp->sd_log_blks_free; + sdp->sd_log_blks_free += tr->tr_reserved - + (reserved - sdp->sd_log_blks_reserved); + + gfs2_assert_withdraw(sdp, + sdp->sd_log_blks_free >= old); + gfs2_assert_withdraw(sdp, + sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); + + sdp->sd_log_blks_reserved = reserved; + + gfs2_log_unlock(sdp); +} + +/** + * gfs2_log_commit - Commit a transaction to the log + * @sdp: the filesystem + * @tr: the transaction + * + * Returns: errno + */ + +void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) +{ + log_refund(sdp, tr); + lops_incore_commit(sdp, tr); + + sdp->sd_vfs->s_dirt = 1; + unlock_from_trans(sdp); + + kfree(tr); + + gfs2_log_lock(sdp); + if (sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks)) { + gfs2_log_unlock(sdp); + gfs2_log_flush(sdp); + } else + gfs2_log_unlock(sdp); +} + +/** + * gfs2_log_shutdown - write a shutdown header into a journal + * @sdp: the filesystem + * + */ + +void gfs2_log_shutdown(struct gfs2_sbd *sdp) +{ + down(&sdp->sd_log_flush_lock); + + gfs2_assert_withdraw(sdp, !atomic_read(&sdp->sd_log_trans_count)); + gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); + gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); + gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); + gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); + gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); + gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); + gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list)); + + sdp->sd_log_flush_head = sdp->sd_log_head; + sdp->sd_log_flush_wrapped = 0; + + log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 0); + + gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free == + sdp->sd_jdesc->jd_blocks); + gfs2_assert_withdraw(sdp, sdp->sd_log_head == sdp->sd_log_tail); + gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail2_list)); + + sdp->sd_log_head = sdp->sd_log_flush_head; + if (sdp->sd_log_flush_wrapped) + sdp->sd_log_wraps++; + sdp->sd_log_tail = sdp->sd_log_head; + + up(&sdp->sd_log_flush_lock); +} + diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h new file mode 100644 index 000000000000..4413cda81154 --- /dev/null +++ b/fs/gfs2/log.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __LOG_DOT_H__ +#define __LOG_DOT_H__ + +/** + * gfs2_log_lock - acquire the right to mess with the log manager + * @sdp: the filesystem + * + */ + +static inline void gfs2_log_lock(struct gfs2_sbd *sdp) +{ + spin_lock(&sdp->sd_log_lock); +} + +/** + * gfs2_log_unlock - release the right to mess with the log manager + * @sdp: the filesystem + * + */ + +static inline void gfs2_log_unlock(struct gfs2_sbd *sdp) +{ + spin_unlock(&sdp->sd_log_lock); +} + +static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp, + unsigned int value) +{ + if (++value == sdp->sd_jdesc->jd_blocks) { + value = 0; + sdp->sd_log_wraps++; + } + sdp->sd_log_head = sdp->sd_log_tail = value; +} + +void gfs2_lock_for_flush(struct gfs2_sbd *sdp); +void gfs2_unlock_from_flush(struct gfs2_sbd *sdp); + +unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, + unsigned int ssize); + +void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags); +int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags); + +int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks); +void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks); + +struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp); +struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, + struct buffer_head *real); + +#define gfs2_log_flush(sdp) gfs2_log_flush_i((sdp), NULL) +#define gfs2_log_flush_glock(gl) gfs2_log_flush_i((gl)->gl_sbd, (gl)) +void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl); +void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); + +void gfs2_log_shutdown(struct gfs2_sbd *sdp); + +#endif /* __LOG_DOT_H__ */ diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c new file mode 100644 index 000000000000..d501e8224ed0 --- /dev/null +++ b/fs/gfs2/lops.c @@ -0,0 +1,534 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "glock.h" +#include "log.h" +#include "lops.h" +#include "meta_io.h" +#include "recovery.h" +#include "rgrp.h" +#include "trans.h" + +static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) +{ + struct gfs2_glock *gl; + + get_transaction->tr_touched = 1; + + if (!list_empty(&le->le_list)) + return; + + gl = container_of(le, struct gfs2_glock, gl_le); + if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl))) + return; + gfs2_glock_hold(gl); + set_bit(GLF_DIRTY, &gl->gl_flags); + + gfs2_log_lock(sdp); + sdp->sd_log_num_gl++; + list_add(&le->le_list, &sdp->sd_log_le_gl); + gfs2_log_unlock(sdp); +} + +static void glock_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) +{ + struct list_head *head = &sdp->sd_log_le_gl; + struct gfs2_glock *gl; + + while (!list_empty(head)) { + gl = list_entry(head->next, struct gfs2_glock, gl_le.le_list); + list_del_init(&gl->gl_le.le_list); + sdp->sd_log_num_gl--; + + gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)); + gfs2_glock_put(gl); + } + gfs2_assert_warn(sdp, !sdp->sd_log_num_gl); +} + +static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) +{ + struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); + struct gfs2_trans *tr; + + if (!list_empty(&bd->bd_list_tr)) + return; + + tr = get_transaction; + tr->tr_touched = 1; + tr->tr_num_buf++; + list_add(&bd->bd_list_tr, &tr->tr_list_buf); + + if (!list_empty(&le->le_list)) + return; + + gfs2_trans_add_gl(bd->bd_gl); + + gfs2_meta_check(sdp, bd->bd_bh); + gfs2_meta_pin(sdp, bd->bd_bh); + + gfs2_log_lock(sdp); + sdp->sd_log_num_buf++; + list_add(&le->le_list, &sdp->sd_log_le_buf); + gfs2_log_unlock(sdp); + + tr->tr_num_buf_new++; +} + +static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) +{ + struct list_head *head = &tr->tr_list_buf; + struct gfs2_bufdata *bd; + + while (!list_empty(head)) { + bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr); + list_del_init(&bd->bd_list_tr); + tr->tr_num_buf--; + } + gfs2_assert_warn(sdp, !tr->tr_num_buf); +} + +static void buf_lo_before_commit(struct gfs2_sbd *sdp) +{ + struct buffer_head *bh; + struct gfs2_log_descriptor *ld; + struct gfs2_bufdata *bd1 = NULL, *bd2; + unsigned int total = sdp->sd_log_num_buf; + unsigned int offset = sizeof(struct gfs2_log_descriptor); + unsigned int limit; + unsigned int num; + unsigned n; + __be64 *ptr; + + offset += (sizeof(__be64) - 1); + offset &= ~(sizeof(__be64) - 1); + limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64); + /* for 4k blocks, limit = 503 */ + + bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list); + while(total) { + num = total; + if (total > limit) + num = limit; + bh = gfs2_log_get_buf(sdp); + ld = (struct gfs2_log_descriptor *)bh->b_data; + ptr = (__be64 *)(bh->b_data + offset); + ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + ld->ld_header.mh_type = cpu_to_be16(GFS2_METATYPE_LD); + ld->ld_header.mh_format = cpu_to_be16(GFS2_FORMAT_LD); + ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_METADATA); + ld->ld_length = cpu_to_be32(num + 1); + ld->ld_data1 = cpu_to_be32(num); + ld->ld_data2 = cpu_to_be32(0); + memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); + + n = 0; + list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf, bd_le.le_list) { + *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr); + if (++n >= num) + break; + } + + set_buffer_dirty(bh); + ll_rw_block(WRITE, 1, &bh); + + n = 0; + list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf, bd_le.le_list) { + bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); + set_buffer_dirty(bh); + ll_rw_block(WRITE, 1, &bh); + if (++n >= num) + break; + } + + total -= num; + } +} + +static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) +{ + struct list_head *head = &sdp->sd_log_le_buf; + struct gfs2_bufdata *bd; + + while (!list_empty(head)) { + bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); + list_del_init(&bd->bd_le.le_list); + sdp->sd_log_num_buf--; + + gfs2_meta_unpin(sdp, bd->bd_bh, ai); + } + gfs2_assert_warn(sdp, !sdp->sd_log_num_buf); +} + +static void buf_lo_before_scan(struct gfs2_jdesc *jd, + struct gfs2_log_header *head, int pass) +{ + struct gfs2_sbd *sdp = jd->jd_inode->i_sbd; + + if (pass != 0) + return; + + sdp->sd_found_blocks = 0; + sdp->sd_replayed_blocks = 0; +} + +static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, + struct gfs2_log_descriptor *ld, __be64 *ptr, + int pass) +{ + struct gfs2_sbd *sdp = jd->jd_inode->i_sbd; + struct gfs2_glock *gl = jd->jd_inode->i_gl; + unsigned int blks = be32_to_cpu(ld->ld_data1); + struct buffer_head *bh_log, *bh_ip; + uint64_t blkno; + int error = 0; + + if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_METADATA) + return 0; + + gfs2_replay_incr_blk(sdp, &start); + + for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { + blkno = be64_to_cpu(*ptr++); + + sdp->sd_found_blocks++; + + if (gfs2_revoke_check(sdp, blkno, start)) + continue; + + error = gfs2_replay_read_block(jd, start, &bh_log); + if (error) + return error; + + bh_ip = gfs2_meta_new(gl, blkno); + memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size); + + if (gfs2_meta_check(sdp, bh_ip)) + error = -EIO; + else + mark_buffer_dirty(bh_ip); + + brelse(bh_log); + brelse(bh_ip); + + if (error) + break; + + sdp->sd_replayed_blocks++; + } + + return error; +} + +static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) +{ + struct gfs2_sbd *sdp = jd->jd_inode->i_sbd; + + if (error) { + gfs2_meta_sync(jd->jd_inode->i_gl, DIO_START | DIO_WAIT); + return; + } + if (pass != 1) + return; + + gfs2_meta_sync(jd->jd_inode->i_gl, DIO_START | DIO_WAIT); + + fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n", + jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); +} + +static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) +{ + struct gfs2_trans *tr; + + tr = get_transaction; + tr->tr_touched = 1; + tr->tr_num_revoke++; + + gfs2_log_lock(sdp); + sdp->sd_log_num_revoke++; + list_add(&le->le_list, &sdp->sd_log_le_revoke); + gfs2_log_unlock(sdp); +} + +static void revoke_lo_before_commit(struct gfs2_sbd *sdp) +{ + struct gfs2_log_descriptor *ld; + struct gfs2_meta_header *mh; + struct buffer_head *bh; + unsigned int offset; + struct list_head *head = &sdp->sd_log_le_revoke; + struct gfs2_revoke *rv; + + if (!sdp->sd_log_num_revoke) + return; + + bh = gfs2_log_get_buf(sdp); + ld = (struct gfs2_log_descriptor *)bh->b_data; + ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + ld->ld_header.mh_type = cpu_to_be16(GFS2_METATYPE_LD); + ld->ld_header.mh_format = cpu_to_be16(GFS2_FORMAT_LD); + ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_REVOKE); + ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke, sizeof(uint64_t))); + ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke); + ld->ld_data2 = cpu_to_be32(0); + memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); + offset = sizeof(struct gfs2_log_descriptor); + + while (!list_empty(head)) { + rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list); + list_del(&rv->rv_le.le_list); + sdp->sd_log_num_revoke--; + + if (offset + sizeof(uint64_t) > sdp->sd_sb.sb_bsize) { + set_buffer_dirty(bh); + ll_rw_block(WRITE, 1, &bh); + + bh = gfs2_log_get_buf(sdp); + mh = (struct gfs2_meta_header *)bh->b_data; + mh->mh_magic = cpu_to_be32(GFS2_MAGIC); + mh->mh_type = cpu_to_be16(GFS2_METATYPE_LB); + mh->mh_format = cpu_to_be16(GFS2_FORMAT_LB); + offset = sizeof(struct gfs2_meta_header); + } + + *(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno); + kfree(rv); + + offset += sizeof(uint64_t); + } + gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); + + set_buffer_dirty(bh); + ll_rw_block(WRITE, 1, &bh); +} + +static void revoke_lo_before_scan(struct gfs2_jdesc *jd, + struct gfs2_log_header *head, int pass) +{ + struct gfs2_sbd *sdp = jd->jd_inode->i_sbd; + + if (pass != 0) + return; + + sdp->sd_found_revokes = 0; + sdp->sd_replay_tail = head->lh_tail; +} + +static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, + struct gfs2_log_descriptor *ld, __be64 *ptr, + int pass) +{ + struct gfs2_sbd *sdp = jd->jd_inode->i_sbd; + unsigned int blks = be32_to_cpu(ld->ld_length); + unsigned int revokes = be32_to_cpu(ld->ld_data1); + struct buffer_head *bh; + unsigned int offset; + uint64_t blkno; + int first = 1; + int error; + + if (pass != 0 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_REVOKE) + return 0; + + offset = sizeof(struct gfs2_log_descriptor); + + for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { + error = gfs2_replay_read_block(jd, start, &bh); + if (error) + return error; + + if (!first) + gfs2_metatype_check(sdp, bh, GFS2_METATYPE_LB); + + while (offset + sizeof(uint64_t) <= sdp->sd_sb.sb_bsize) { + blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset)); + + error = gfs2_revoke_add(sdp, blkno, start); + if (error < 0) + return error; + else if (error) + sdp->sd_found_revokes++; + + if (!--revokes) + break; + offset += sizeof(uint64_t); + } + + brelse(bh); + offset = sizeof(struct gfs2_meta_header); + first = 0; + } + + return 0; +} + +static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) +{ + struct gfs2_sbd *sdp = jd->jd_inode->i_sbd; + + if (error) { + gfs2_revoke_clean(sdp); + return; + } + if (pass != 1) + return; + + fs_info(sdp, "jid=%u: Found %u revoke tags\n", + jd->jd_jid, sdp->sd_found_revokes); + + gfs2_revoke_clean(sdp); +} + +static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) +{ + struct gfs2_rgrpd *rgd; + + get_transaction->tr_touched = 1; + + if (!list_empty(&le->le_list)) + return; + + rgd = container_of(le, struct gfs2_rgrpd, rd_le); + gfs2_rgrp_bh_hold(rgd); + + gfs2_log_lock(sdp); + sdp->sd_log_num_rg++; + list_add(&le->le_list, &sdp->sd_log_le_rg); + gfs2_log_unlock(sdp); +} + +static void rg_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) +{ + struct list_head *head = &sdp->sd_log_le_rg; + struct gfs2_rgrpd *rgd; + + while (!list_empty(head)) { + rgd = list_entry(head->next, struct gfs2_rgrpd, rd_le.le_list); + list_del_init(&rgd->rd_le.le_list); + sdp->sd_log_num_rg--; + + gfs2_rgrp_repolish_clones(rgd); + gfs2_rgrp_bh_put(rgd); + } + gfs2_assert_warn(sdp, !sdp->sd_log_num_rg); +} + +static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) +{ + get_transaction->tr_touched = 1; + + gfs2_log_lock(sdp); + sdp->sd_log_num_databuf++; + list_add(&le->le_list, &sdp->sd_log_le_databuf); + gfs2_log_unlock(sdp); +} + +static void databuf_lo_before_commit(struct gfs2_sbd *sdp) +{ + struct list_head *head = &sdp->sd_log_le_databuf; + LIST_HEAD(started); + struct gfs2_databuf *db; + struct buffer_head *bh; + + while (!list_empty(head)) { + db = list_entry(head->prev, struct gfs2_databuf, db_le.le_list); + list_move(&db->db_le.le_list, &started); + + gfs2_log_lock(sdp); + bh = db->db_bh; + if (bh) { + get_bh(bh); + gfs2_log_unlock(sdp); + if (buffer_dirty(bh)) { + wait_on_buffer(bh); + ll_rw_block(WRITE, 1, &bh); + } + brelse(bh); + } else + gfs2_log_unlock(sdp); + } + + while (!list_empty(&started)) { + db = list_entry(started.next, struct gfs2_databuf, + db_le.le_list); + list_del(&db->db_le.le_list); + sdp->sd_log_num_databuf--; + + gfs2_log_lock(sdp); + bh = db->db_bh; + if (bh) { + set_v2db(bh, NULL); + gfs2_log_unlock(sdp); + wait_on_buffer(bh); + brelse(bh); + } else + gfs2_log_unlock(sdp); + + kfree(db); + } + + gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf); +} + +struct gfs2_log_operations gfs2_glock_lops = { + .lo_add = glock_lo_add, + .lo_after_commit = glock_lo_after_commit, + .lo_name = "glock" +}; + +struct gfs2_log_operations gfs2_buf_lops = { + .lo_add = buf_lo_add, + .lo_incore_commit = buf_lo_incore_commit, + .lo_before_commit = buf_lo_before_commit, + .lo_after_commit = buf_lo_after_commit, + .lo_before_scan = buf_lo_before_scan, + .lo_scan_elements = buf_lo_scan_elements, + .lo_after_scan = buf_lo_after_scan, + .lo_name = "buf" +}; + +struct gfs2_log_operations gfs2_revoke_lops = { + .lo_add = revoke_lo_add, + .lo_before_commit = revoke_lo_before_commit, + .lo_before_scan = revoke_lo_before_scan, + .lo_scan_elements = revoke_lo_scan_elements, + .lo_after_scan = revoke_lo_after_scan, + .lo_name = "revoke" +}; + +struct gfs2_log_operations gfs2_rg_lops = { + .lo_add = rg_lo_add, + .lo_after_commit = rg_lo_after_commit, + .lo_name = "rg" +}; + +struct gfs2_log_operations gfs2_databuf_lops = { + .lo_add = databuf_lo_add, + .lo_before_commit = databuf_lo_before_commit, + .lo_name = "databuf" +}; + +struct gfs2_log_operations *gfs2_log_ops[] = { + &gfs2_glock_lops, + &gfs2_buf_lops, + &gfs2_revoke_lops, + &gfs2_rg_lops, + &gfs2_databuf_lops, + NULL +}; + diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h new file mode 100644 index 000000000000..417f5aade4b1 --- /dev/null +++ b/fs/gfs2/lops.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __LOPS_DOT_H__ +#define __LOPS_DOT_H__ + +extern struct gfs2_log_operations gfs2_glock_lops; +extern struct gfs2_log_operations gfs2_buf_lops; +extern struct gfs2_log_operations gfs2_revoke_lops; +extern struct gfs2_log_operations gfs2_rg_lops; +extern struct gfs2_log_operations gfs2_databuf_lops; + +extern struct gfs2_log_operations *gfs2_log_ops[]; + +static inline void lops_init_le(struct gfs2_log_element *le, + struct gfs2_log_operations *lops) +{ + INIT_LIST_HEAD(&le->le_list); + le->le_ops = lops; +} + +static inline void lops_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) +{ + if (le->le_ops->lo_add) + le->le_ops->lo_add(sdp, le); +} + +static inline void lops_incore_commit(struct gfs2_sbd *sdp, + struct gfs2_trans *tr) +{ + int x; + for (x = 0; gfs2_log_ops[x]; x++) + if (gfs2_log_ops[x]->lo_incore_commit) + gfs2_log_ops[x]->lo_incore_commit(sdp, tr); +} + +static inline void lops_before_commit(struct gfs2_sbd *sdp) +{ + int x; + for (x = 0; gfs2_log_ops[x]; x++) + if (gfs2_log_ops[x]->lo_before_commit) + gfs2_log_ops[x]->lo_before_commit(sdp); +} + +static inline void lops_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) +{ + int x; + for (x = 0; gfs2_log_ops[x]; x++) + if (gfs2_log_ops[x]->lo_after_commit) + gfs2_log_ops[x]->lo_after_commit(sdp, ai); +} + +static inline void lops_before_scan(struct gfs2_jdesc *jd, + struct gfs2_log_header *head, + unsigned int pass) +{ + int x; + for (x = 0; gfs2_log_ops[x]; x++) + if (gfs2_log_ops[x]->lo_before_scan) + gfs2_log_ops[x]->lo_before_scan(jd, head, pass); +} + +static inline int lops_scan_elements(struct gfs2_jdesc *jd, unsigned int start, + struct gfs2_log_descriptor *ld, + __be64 *ptr, + unsigned int pass) +{ + int x, error; + for (x = 0; gfs2_log_ops[x]; x++) + if (gfs2_log_ops[x]->lo_scan_elements) { + error = gfs2_log_ops[x]->lo_scan_elements(jd, start, + ld, ptr, pass); + if (error) + return error; + } + + return 0; +} + +static inline void lops_after_scan(struct gfs2_jdesc *jd, int error, + unsigned int pass) +{ + int x; + for (x = 0; gfs2_log_ops[x]; x++) + if (gfs2_log_ops[x]->lo_before_scan) + gfs2_log_ops[x]->lo_after_scan(jd, error, pass); +} + +#endif /* __LOPS_DOT_H__ */ + diff --git a/fs/gfs2/lvb.c b/fs/gfs2/lvb.c new file mode 100644 index 000000000000..8af62568a3f4 --- /dev/null +++ b/fs/gfs2/lvb.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" + +#define pv(struct, member, fmt) printk(" "#member" = "fmt"\n", struct->member); + +void gfs2_quota_lvb_in(struct gfs2_quota_lvb *qb, char *lvb) +{ + struct gfs2_quota_lvb *str = (struct gfs2_quota_lvb *)lvb; + + qb->qb_magic = be32_to_cpu(str->qb_magic); + qb->qb_limit = be64_to_cpu(str->qb_limit); + qb->qb_warn = be64_to_cpu(str->qb_warn); + qb->qb_value = be64_to_cpu(str->qb_value); +} + +void gfs2_quota_lvb_out(struct gfs2_quota_lvb *qb, char *lvb) +{ + struct gfs2_quota_lvb *str = (struct gfs2_quota_lvb *)lvb; + + str->qb_magic = cpu_to_be32(qb->qb_magic); + str->qb_limit = cpu_to_be64(qb->qb_limit); + str->qb_warn = cpu_to_be64(qb->qb_warn); + str->qb_value = cpu_to_be64(qb->qb_value); +} + +void gfs2_quota_lvb_print(struct gfs2_quota_lvb *qb) +{ + pv(qb, qb_magic, "%u"); + pv(qb, qb_limit, "%llu"); + pv(qb, qb_warn, "%llu"); + pv(qb, qb_value, "%lld"); +} + diff --git a/fs/gfs2/lvb.h b/fs/gfs2/lvb.h new file mode 100644 index 000000000000..ca9732b2d9f4 --- /dev/null +++ b/fs/gfs2/lvb.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __LVB_DOT_H__ +#define __LVB_DOT_H__ + +#define GFS2_MIN_LVB_SIZE 32 + +struct gfs2_quota_lvb { + uint32_t qb_magic; + uint32_t __pad; + uint64_t qb_limit; /* Hard limit of # blocks to alloc */ + uint64_t qb_warn; /* Warn user when alloc is above this # */ + int64_t qb_value; /* Current # blocks allocated */ +}; + +void gfs2_quota_lvb_in(struct gfs2_quota_lvb *qb, char *lvb); +void gfs2_quota_lvb_out(struct gfs2_quota_lvb *qb, char *lvb); +void gfs2_quota_lvb_print(struct gfs2_quota_lvb *qb); + +#endif /* __LVB_DOT_H__ */ + diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c new file mode 100644 index 000000000000..0c60f2b10fdd --- /dev/null +++ b/fs/gfs2/main.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "ops_fstype.h" +#include "sys.h" + +/** + * init_gfs2_fs - Register GFS2 as a filesystem + * + * Returns: 0 on success, error code on failure + */ + +static int __init init_gfs2_fs(void) +{ + int error; + + gfs2_init_lmh(); + + error = gfs2_sys_init(); + if (error) + return error; + + error = -ENOMEM; + + gfs2_glock_cachep = kmem_cache_create("gfs2_glock", + sizeof(struct gfs2_glock), + 0, 0, NULL, NULL); + if (!gfs2_glock_cachep) + goto fail; + + gfs2_inode_cachep = kmem_cache_create("gfs2_inode", + sizeof(struct gfs2_inode), + 0, 0, NULL, NULL); + if (!gfs2_inode_cachep) + goto fail; + + gfs2_bufdata_cachep = kmem_cache_create("gfs2_bufdata", + sizeof(struct gfs2_bufdata), + 0, 0, NULL, NULL); + if (!gfs2_bufdata_cachep) + goto fail; + + error = register_filesystem(&gfs2_fs_type); + if (error) + goto fail; + + printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__); + + return 0; + + fail: + if (gfs2_bufdata_cachep) + kmem_cache_destroy(gfs2_bufdata_cachep); + + if (gfs2_inode_cachep) + kmem_cache_destroy(gfs2_inode_cachep); + + if (gfs2_glock_cachep) + kmem_cache_destroy(gfs2_glock_cachep); + + gfs2_sys_uninit(); + return error; +} + +/** + * exit_gfs2_fs - Unregister the file system + * + */ + +static void __exit exit_gfs2_fs(void) +{ + unregister_filesystem(&gfs2_fs_type); + + kmem_cache_destroy(gfs2_bufdata_cachep); + kmem_cache_destroy(gfs2_inode_cachep); + kmem_cache_destroy(gfs2_glock_cachep); + + gfs2_sys_uninit(); +} + +MODULE_DESCRIPTION("Global File System"); +MODULE_AUTHOR("Red Hat, Inc."); +MODULE_LICENSE("GPL"); + +module_init(init_gfs2_fs); +module_exit(exit_gfs2_fs); + diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c new file mode 100644 index 000000000000..177b0246d194 --- /dev/null +++ b/fs/gfs2/meta_io.c @@ -0,0 +1,876 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "log.h" +#include "lops.h" +#include "meta_io.h" +#include "rgrp.h" +#include "trans.h" + +#define buffer_busy(bh) \ +((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned))) +#define buffer_in_io(bh) \ +((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock))) + +static int aspace_get_block(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + gfs2_assert_warn(get_v2sdp(inode->i_sb), 0); + return -EOPNOTSUPP; +} + +static int gfs2_aspace_writepage(struct page *page, + struct writeback_control *wbc) +{ + return block_write_full_page(page, aspace_get_block, wbc); +} + +/** + * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. + * @bh: the buffer we're stuck on + * + */ + +static void stuck_releasepage(struct buffer_head *bh) +{ + struct gfs2_sbd *sdp = get_v2sdp(bh->b_page->mapping->host->i_sb); + struct gfs2_bufdata *bd = get_v2bd(bh); + struct gfs2_glock *gl; + + fs_warn(sdp, "stuck in gfs2_releasepage()\n"); + fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", + (uint64_t)bh->b_blocknr, atomic_read(&bh->b_count)); + fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); + fs_warn(sdp, "get_v2bd(bh) = %s\n", (bd) ? "!NULL" : "NULL"); + + if (!bd) + return; + + gl = bd->bd_gl; + + fs_warn(sdp, "gl = (%u, %llu)\n", + gl->gl_name.ln_type, gl->gl_name.ln_number); + + fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", + (list_empty(&bd->bd_list_tr)) ? "no" : "yes", + (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); + + if (gl->gl_ops == &gfs2_inode_glops) { + struct gfs2_inode *ip = get_gl2ip(gl); + unsigned int x; + + if (!ip) + return; + + fs_warn(sdp, "ip = %llu %llu\n", + ip->i_num.no_formal_ino, ip->i_num.no_addr); + fs_warn(sdp, "ip->i_count = %d, ip->i_vnode = %s\n", + atomic_read(&ip->i_count), + (ip->i_vnode) ? "!NULL" : "NULL"); + + for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) + fs_warn(sdp, "ip->i_cache[%u] = %s\n", + x, (ip->i_cache[x]) ? "!NULL" : "NULL"); + } +} + +/** + * gfs2_aspace_releasepage - free the metadata associated with a page + * @page: the page that's being released + * @gfp_mask: passed from Linux VFS, ignored by us + * + * Call try_to_free_buffers() if the buffers in this page can be + * released. + * + * Returns: 0 + */ + +static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask) +{ + struct inode *aspace = page->mapping->host; + struct gfs2_sbd *sdp = get_v2sdp(aspace->i_sb); + struct buffer_head *bh, *head; + struct gfs2_bufdata *bd; + unsigned long t; + + if (!page_has_buffers(page)) + goto out; + + head = bh = page_buffers(page); + do { + t = jiffies; + + while (atomic_read(&bh->b_count)) { + if (atomic_read(&aspace->i_writecount)) { + if (time_after_eq(jiffies, t + + gfs2_tune_get(sdp, gt_stall_secs) * HZ)) { + stuck_releasepage(bh); + t = jiffies; + } + + yield(); + continue; + } + + return 0; + } + + gfs2_assert_warn(sdp, !buffer_pinned(bh)); + + bd = get_v2bd(bh); + if (bd) { + gfs2_assert_warn(sdp, bd->bd_bh == bh); + gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); + gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); + gfs2_assert_warn(sdp, !bd->bd_ail); + kmem_cache_free(gfs2_bufdata_cachep, bd); + atomic_dec(&sdp->sd_bufdata_count); + set_v2bd(bh, NULL); + } + + bh = bh->b_this_page; + } + while (bh != head); + + out: + return try_to_free_buffers(page); +} + +static struct address_space_operations aspace_aops = { + .writepage = gfs2_aspace_writepage, + .releasepage = gfs2_aspace_releasepage, +}; + +/** + * gfs2_aspace_get - Create and initialize a struct inode structure + * @sdp: the filesystem the aspace is in + * + * Right now a struct inode is just a struct inode. Maybe Linux + * will supply a more lightweight address space construct (that works) + * in the future. + * + * Make sure pages/buffers in this aspace aren't in high memory. + * + * Returns: the aspace + */ + +struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp) +{ + struct inode *aspace; + + aspace = new_inode(sdp->sd_vfs); + if (aspace) { + mapping_set_gfp_mask(aspace->i_mapping, GFP_KERNEL); + aspace->i_mapping->a_ops = &aspace_aops; + aspace->i_size = ~0ULL; + set_v2ip(aspace, NULL); + insert_inode_hash(aspace); + } + + return aspace; +} + +void gfs2_aspace_put(struct inode *aspace) +{ + remove_inode_hash(aspace); + iput(aspace); +} + +/** + * gfs2_ail1_start_one - Start I/O on a part of the AIL + * @sdp: the filesystem + * @tr: the part of the AIL + * + */ + +void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) +{ + struct gfs2_bufdata *bd, *s; + struct buffer_head *bh; + int retry; + + do { + retry = 0; + + list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, + bd_ail_st_list) { + bh = bd->bd_bh; + + gfs2_assert(sdp, bd->bd_ail == ai); + + if (!buffer_busy(bh)) { + if (!buffer_uptodate(bh)) + gfs2_io_error_bh(sdp, bh); + list_move(&bd->bd_ail_st_list, + &ai->ai_ail2_list); + continue; + } + + if (!buffer_dirty(bh)) + continue; + + list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); + + gfs2_log_unlock(sdp); + wait_on_buffer(bh); + ll_rw_block(WRITE, 1, &bh); + gfs2_log_lock(sdp); + + retry = 1; + break; + } + } while (retry); +} + +/** + * gfs2_ail1_empty_one - Check whether or not a trans in the AIL has been synced + * @sdp: the filesystem + * @ai: the AIL entry + * + */ + +int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags) +{ + struct gfs2_bufdata *bd, *s; + struct buffer_head *bh; + + list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, + bd_ail_st_list) { + bh = bd->bd_bh; + + gfs2_assert(sdp, bd->bd_ail == ai); + + if (buffer_busy(bh)) { + if (flags & DIO_ALL) + continue; + else + break; + } + + if (!buffer_uptodate(bh)) + gfs2_io_error_bh(sdp, bh); + + list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); + } + + return list_empty(&ai->ai_ail1_list); +} + +/** + * gfs2_ail2_empty_one - Check whether or not a trans in the AIL has been synced + * @sdp: the filesystem + * @ai: the AIL entry + * + */ + +void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) +{ + struct list_head *head = &ai->ai_ail2_list; + struct gfs2_bufdata *bd; + + while (!list_empty(head)) { + bd = list_entry(head->prev, struct gfs2_bufdata, + bd_ail_st_list); + gfs2_assert(sdp, bd->bd_ail == ai); + bd->bd_ail = NULL; + list_del(&bd->bd_ail_st_list); + list_del(&bd->bd_ail_gl_list); + atomic_dec(&bd->bd_gl->gl_ail_count); + brelse(bd->bd_bh); + } +} + +/** + * ail_empty_gl - remove all buffers for a given lock from the AIL + * @gl: the glock + * + * None of the buffers should be dirty, locked, or pinned. + */ + +void gfs2_ail_empty_gl(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + unsigned int blocks; + struct list_head *head = &gl->gl_ail_list; + struct gfs2_bufdata *bd; + struct buffer_head *bh; + uint64_t blkno; + int error; + + blocks = atomic_read(&gl->gl_ail_count); + if (!blocks) + return; + + error = gfs2_trans_begin(sdp, 0, blocks); + if (gfs2_assert_withdraw(sdp, !error)) + return; + + gfs2_log_lock(sdp); + while (!list_empty(head)) { + bd = list_entry(head->next, struct gfs2_bufdata, + bd_ail_gl_list); + bh = bd->bd_bh; + blkno = bh->b_blocknr; + gfs2_assert_withdraw(sdp, !buffer_busy(bh)); + + bd->bd_ail = NULL; + list_del(&bd->bd_ail_st_list); + list_del(&bd->bd_ail_gl_list); + atomic_dec(&gl->gl_ail_count); + brelse(bh); + gfs2_log_unlock(sdp); + + gfs2_trans_add_revoke(sdp, blkno); + + gfs2_log_lock(sdp); + } + gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); + gfs2_log_unlock(sdp); + + gfs2_trans_end(sdp); + gfs2_log_flush(sdp); +} + +/** + * gfs2_meta_inval - Invalidate all buffers associated with a glock + * @gl: the glock + * + */ + +void gfs2_meta_inval(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct inode *aspace = gl->gl_aspace; + struct address_space *mapping = gl->gl_aspace->i_mapping; + + gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); + + atomic_inc(&aspace->i_writecount); + truncate_inode_pages(mapping, 0); + atomic_dec(&aspace->i_writecount); + + gfs2_assert_withdraw(sdp, !mapping->nrpages); +} + +/** + * gfs2_meta_sync - Sync all buffers associated with a glock + * @gl: The glock + * @flags: DIO_START | DIO_WAIT + * + */ + +void gfs2_meta_sync(struct gfs2_glock *gl, int flags) +{ + struct address_space *mapping = gl->gl_aspace->i_mapping; + int error = 0; + + if (flags & DIO_START) + filemap_fdatawrite(mapping); + if (!error && (flags & DIO_WAIT)) + error = filemap_fdatawait(mapping); + + if (error) + gfs2_io_error(gl->gl_sbd); +} + +/** + * getbuf - Get a buffer with a given address space + * @sdp: the filesystem + * @aspace: the address space + * @blkno: the block number (filesystem scope) + * @create: 1 if the buffer should be created + * + * Returns: the buffer + */ + +static struct buffer_head *getbuf(struct gfs2_sbd *sdp, struct inode *aspace, + uint64_t blkno, int create) +{ + struct page *page; + struct buffer_head *bh; + unsigned int shift; + unsigned long index; + unsigned int bufnum; + + shift = PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift; + index = blkno >> shift; /* convert block to page */ + bufnum = blkno - (index << shift); /* block buf index within page */ + + if (create) { + for (;;) { + page = grab_cache_page(aspace->i_mapping, index); + if (page) + break; + yield(); + } + } else { + page = find_lock_page(aspace->i_mapping, index); + if (!page) + return NULL; + } + + if (!page_has_buffers(page)) + create_empty_buffers(page, sdp->sd_sb.sb_bsize, 0); + + /* Locate header for our buffer within our page */ + for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page) + /* Do nothing */; + get_bh(bh); + + if (!buffer_mapped(bh)) + map_bh(bh, sdp->sd_vfs, blkno); + + unlock_page(page); + mark_page_accessed(page); + page_cache_release(page); + + return bh; +} + +static void meta_prep_new(struct buffer_head *bh) +{ + struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data; + + lock_buffer(bh); + clear_buffer_dirty(bh); + set_buffer_uptodate(bh); + unlock_buffer(bh); + + mh->mh_magic = cpu_to_be32(GFS2_MAGIC); +} + +/** + * gfs2_meta_new - Get a block + * @gl: The glock associated with this block + * @blkno: The block number + * + * Returns: The buffer + */ + +struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, uint64_t blkno) +{ + struct buffer_head *bh; + bh = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE); + meta_prep_new(bh); + return bh; +} + +/** + * gfs2_meta_read - Read a block from disk + * @gl: The glock covering the block + * @blkno: The block number + * @flags: flags to gfs2_dreread() + * @bhp: the place where the buffer is returned (NULL on failure) + * + * Returns: errno + */ + +int gfs2_meta_read(struct gfs2_glock *gl, uint64_t blkno, int flags, + struct buffer_head **bhp) +{ + int error; + + *bhp = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE); + error = gfs2_meta_reread(gl->gl_sbd, *bhp, flags); + if (error) + brelse(*bhp); + + return error; +} + +/** + * gfs2_meta_reread - Reread a block from disk + * @sdp: the filesystem + * @bh: The block to read + * @flags: Flags that control the read + * + * Returns: errno + */ + +int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags) +{ + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + return -EIO; + + if (flags & DIO_FORCE) + clear_buffer_uptodate(bh); + + if ((flags & DIO_START) && !buffer_uptodate(bh)) + ll_rw_block(READ, 1, &bh); + + if (flags & DIO_WAIT) { + wait_on_buffer(bh); + + if (!buffer_uptodate(bh)) { + struct gfs2_trans *tr = get_transaction; + if (tr && tr->tr_touched) + gfs2_io_error_bh(sdp, bh); + return -EIO; + } + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + return -EIO; + } + + return 0; +} + +/** + * gfs2_meta_attach_bufdata - attach a struct gfs2_bufdata structure to a buffer + * @gl: the glock the buffer belongs to + * @bh: The buffer to be attached to + * + */ + +void gfs2_meta_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh) +{ + struct gfs2_bufdata *bd; + + lock_page(bh->b_page); + + if (get_v2bd(bh)) { + unlock_page(bh->b_page); + return; + } + + bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_KERNEL | __GFP_NOFAIL), + atomic_inc(&gl->gl_sbd->sd_bufdata_count); + + memset(bd, 0, sizeof(struct gfs2_bufdata)); + + bd->bd_bh = bh; + bd->bd_gl = gl; + + INIT_LIST_HEAD(&bd->bd_list_tr); + lops_init_le(&bd->bd_le, &gfs2_buf_lops); + + set_v2bd(bh, bd); + + unlock_page(bh->b_page); +} + +/** + * gfs2_meta_pin - Pin a metadata buffer in memory + * @sdp: the filesystem the buffer belongs to + * @bh: The buffer to be pinned + * + */ + +void gfs2_meta_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) +{ + struct gfs2_bufdata *bd = get_v2bd(bh); + + gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); + + if (test_set_buffer_pinned(bh)) + gfs2_assert_withdraw(sdp, 0); + + wait_on_buffer(bh); + + /* If this buffer is in the AIL and it has already been written + to in-place disk block, remove it from the AIL. */ + + gfs2_log_lock(sdp); + if (bd->bd_ail && !buffer_in_io(bh)) + list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); + gfs2_log_unlock(sdp); + + clear_buffer_dirty(bh); + wait_on_buffer(bh); + + if (!buffer_uptodate(bh)) + gfs2_io_error_bh(sdp, bh); + + get_bh(bh); +} + +/** + * gfs2_meta_unpin - Unpin a buffer + * @sdp: the filesystem the buffer belongs to + * @bh: The buffer to unpin + * @ai: + * + */ + +void gfs2_meta_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, + struct gfs2_ail *ai) +{ + struct gfs2_bufdata *bd = get_v2bd(bh); + + gfs2_assert_withdraw(sdp, buffer_uptodate(bh)); + + if (!buffer_pinned(bh)) + gfs2_assert_withdraw(sdp, 0); + + mark_buffer_dirty(bh); + clear_buffer_pinned(bh); + + gfs2_log_lock(sdp); + if (bd->bd_ail) { + list_del(&bd->bd_ail_st_list); + brelse(bh); + } else { + struct gfs2_glock *gl = bd->bd_gl; + list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list); + atomic_inc(&gl->gl_ail_count); + } + bd->bd_ail = ai; + list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); + gfs2_log_unlock(sdp); +} + +/** + * gfs2_meta_wipe - make inode's buffers so they aren't dirty/pinned anymore + * @ip: the inode who owns the buffers + * @bstart: the first buffer in the run + * @blen: the number of buffers in the run + * + */ + +void gfs2_meta_wipe(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct inode *aspace = ip->i_gl->gl_aspace; + struct buffer_head *bh; + + while (blen) { + bh = getbuf(sdp, aspace, bstart, NO_CREATE); + if (bh) { + struct gfs2_bufdata *bd = get_v2bd(bh); + + if (test_clear_buffer_pinned(bh)) { + gfs2_log_lock(sdp); + list_del_init(&bd->bd_le.le_list); + gfs2_assert_warn(sdp, sdp->sd_log_num_buf); + sdp->sd_log_num_buf--; + gfs2_log_unlock(sdp); + get_transaction->tr_num_buf_rm++; + brelse(bh); + } + if (bd) { + gfs2_log_lock(sdp); + if (bd->bd_ail) { + uint64_t blkno = bh->b_blocknr; + bd->bd_ail = NULL; + list_del(&bd->bd_ail_st_list); + list_del(&bd->bd_ail_gl_list); + atomic_dec(&bd->bd_gl->gl_ail_count); + brelse(bh); + gfs2_log_unlock(sdp); + gfs2_trans_add_revoke(sdp, blkno); + } else + gfs2_log_unlock(sdp); + } + + lock_buffer(bh); + clear_buffer_dirty(bh); + clear_buffer_uptodate(bh); + unlock_buffer(bh); + + brelse(bh); + } + + bstart++; + blen--; + } +} + +/** + * gfs2_meta_cache_flush - get rid of any references on buffers for this inode + * @ip: The GFS2 inode + * + * This releases buffers that are in the most-recently-used array of + * blocks used for indirect block addressing for this inode. + */ + +void gfs2_meta_cache_flush(struct gfs2_inode *ip) +{ + struct buffer_head **bh_slot; + unsigned int x; + + spin_lock(&ip->i_spin); + + for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) { + bh_slot = &ip->i_cache[x]; + if (!*bh_slot) + break; + brelse(*bh_slot); + *bh_slot = NULL; + } + + spin_unlock(&ip->i_spin); +} + +/** + * gfs2_meta_indirect_buffer - Get a metadata buffer + * @ip: The GFS2 inode + * @height: The level of this buf in the metadata (indir addr) tree (if any) + * @num: The block number (device relative) of the buffer + * @new: Non-zero if we may create a new buffer + * @bhp: the buffer is returned here + * + * Try to use the gfs2_inode's MRU metadata tree cache. + * + * Returns: errno + */ + +int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t num, + int new, struct buffer_head **bhp) +{ + struct buffer_head *bh, **bh_slot = ip->i_cache + height; + int error; + + spin_lock(&ip->i_spin); + bh = *bh_slot; + if (bh) { + if (bh->b_blocknr == num) + get_bh(bh); + else + bh = NULL; + } + spin_unlock(&ip->i_spin); + + if (bh) { + if (new) + meta_prep_new(bh); + else { + error = gfs2_meta_reread(ip->i_sbd, bh, + DIO_START | DIO_WAIT); + if (error) { + brelse(bh); + return error; + } + } + } else { + if (new) + bh = gfs2_meta_new(ip->i_gl, num); + else { + error = gfs2_meta_read(ip->i_gl, num, + DIO_START | DIO_WAIT, &bh); + if (error) + return error; + } + + spin_lock(&ip->i_spin); + if (*bh_slot != bh) { + brelse(*bh_slot); + *bh_slot = bh; + get_bh(bh); + } + spin_unlock(&ip->i_spin); + } + + if (new) { + if (gfs2_assert_warn(ip->i_sbd, height)) { + brelse(bh); + return -EIO; + } + gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); + gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); + + } else if (gfs2_metatype_check(ip->i_sbd, bh, + (height) ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)) { + brelse(bh); + return -EIO; + } + + *bhp = bh; + + return 0; +} + +/** + * gfs2_meta_ra - start readahead on an extent of a file + * @gl: the glock the blocks belong to + * @dblock: the starting disk block + * @extlen: the number of blocks in the extent + * + */ + +void gfs2_meta_ra(struct gfs2_glock *gl, uint64_t dblock, uint32_t extlen) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct inode *aspace = gl->gl_aspace; + struct buffer_head *first_bh, *bh; + uint32_t max_ra = gfs2_tune_get(sdp, gt_max_readahead) >> sdp->sd_sb.sb_bsize_shift; + int error; + + if (!extlen || !max_ra) + return; + if (extlen > max_ra) + extlen = max_ra; + + first_bh = getbuf(sdp, aspace, dblock, CREATE); + + if (buffer_uptodate(first_bh)) + goto out; + if (!buffer_locked(first_bh)) { + error = gfs2_meta_reread(sdp, first_bh, DIO_START); + if (error) + goto out; + } + + dblock++; + extlen--; + + while (extlen) { + bh = getbuf(sdp, aspace, dblock, CREATE); + + if (!buffer_uptodate(bh) && !buffer_locked(bh)) { + error = gfs2_meta_reread(sdp, bh, DIO_START); + brelse(bh); + if (error) + goto out; + } else + brelse(bh); + + dblock++; + extlen--; + + if (buffer_uptodate(first_bh)) + break; + } + + out: + brelse(first_bh); +} + +/** + * gfs2_meta_syncfs - sync all the buffers in a filesystem + * @sdp: the filesystem + * + */ + +void gfs2_meta_syncfs(struct gfs2_sbd *sdp) +{ + gfs2_log_flush(sdp); + for (;;) { + gfs2_ail1_start(sdp, DIO_ALL); + if (gfs2_ail1_empty(sdp, DIO_ALL)) + break; + msleep(100); + } +} + diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h new file mode 100644 index 000000000000..5556df8cc6c9 --- /dev/null +++ b/fs/gfs2/meta_io.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __DIO_DOT_H__ +#define __DIO_DOT_H__ + +static inline void gfs2_buffer_clear(struct buffer_head *bh) +{ + memset(bh->b_data, 0, bh->b_size); +} + +static inline void gfs2_buffer_clear_tail(struct buffer_head *bh, int head) +{ + memset(bh->b_data + head, 0, bh->b_size - head); +} + +static inline void gfs2_buffer_clear_ends(struct buffer_head *bh, int offset, + int amount, int journaled) +{ + int z_off1 = (journaled) ? sizeof(struct gfs2_meta_header) : 0; + int z_len1 = offset - z_off1; + int z_off2 = offset + amount; + int z_len2 = (bh)->b_size - z_off2; + + if (z_len1) + memset(bh->b_data + z_off1, 0, z_len1); + + if (z_len2) + memset(bh->b_data + z_off2, 0, z_len2); +} + +static inline void gfs2_buffer_copy_tail(struct buffer_head *to_bh, + int to_head, + struct buffer_head *from_bh, + int from_head) +{ + memcpy(to_bh->b_data + to_head, + from_bh->b_data + from_head, + from_bh->b_size - from_head); + memset(to_bh->b_data + to_bh->b_size + to_head - from_head, + 0, + from_head - to_head); +} + +struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp); +void gfs2_aspace_put(struct inode *aspace); + +void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai); +int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags); +void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai); +void gfs2_ail_empty_gl(struct gfs2_glock *gl); + +void gfs2_meta_inval(struct gfs2_glock *gl); +void gfs2_meta_sync(struct gfs2_glock *gl, int flags); + +struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, uint64_t blkno); +int gfs2_meta_read(struct gfs2_glock *gl, uint64_t blkno, + int flags, struct buffer_head **bhp); +int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags); + +void gfs2_meta_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh); +void gfs2_meta_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); +void gfs2_meta_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, + struct gfs2_ail *ai); + +void gfs2_meta_wipe(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); + +void gfs2_meta_cache_flush(struct gfs2_inode *ip); +int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t num, + int new, struct buffer_head **bhp); + +static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip, + struct buffer_head **bhp) +{ + return gfs2_meta_indirect_buffer(ip, 0, ip->i_num.no_addr, 0, bhp); +} + +void gfs2_meta_ra(struct gfs2_glock *gl, uint64_t dblock, uint32_t extlen); +void gfs2_meta_syncfs(struct gfs2_sbd *sdp); + +#endif /* __DIO_DOT_H__ */ + diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c new file mode 100644 index 000000000000..3e42697aafc7 --- /dev/null +++ b/fs/gfs2/mount.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "mount.h" +#include "sys.h" + +/** + * gfs2_mount_args - Parse mount options + * @sdp: + * @data: + * + * Return: errno + */ + +int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount) +{ + struct gfs2_args *args = &sdp->sd_args; + char *data = data_arg; + char *options, *o, *v; + int error = 0; + + if (!remount) { + /* If someone preloaded options, use those instead */ + spin_lock(&gfs2_sys_margs_lock); + if (gfs2_sys_margs) { + data = gfs2_sys_margs; + gfs2_sys_margs = NULL; + } + spin_unlock(&gfs2_sys_margs_lock); + + /* Set some defaults */ + args->ar_num_glockd = GFS2_GLOCKD_DEFAULT; + args->ar_quota = GFS2_QUOTA_DEFAULT; + args->ar_data = GFS2_DATA_DEFAULT; + } + + /* Split the options into tokens with the "," character and + process them */ + + for (options = data; (o = strsep(&options, ",")); ) { + if (!*o) + continue; + + v = strchr(o, '='); + if (v) + *v++ = 0; + + if (!strcmp(o, "lockproto")) { + if (!v) + goto need_value; + if (remount && strcmp(v, args->ar_lockproto)) + goto cant_remount; + strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN); + args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0; + } + + else if (!strcmp(o, "locktable")) { + if (!v) + goto need_value; + if (remount && strcmp(v, args->ar_locktable)) + goto cant_remount; + strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN); + args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0; + } + + else if (!strcmp(o, "hostdata")) { + if (!v) + goto need_value; + if (remount && strcmp(v, args->ar_hostdata)) + goto cant_remount; + strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN); + args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0; + } + + else if (!strcmp(o, "spectator")) { + if (remount && !args->ar_spectator) + goto cant_remount; + args->ar_spectator = 1; + sdp->sd_vfs->s_flags |= MS_RDONLY; + } + + else if (!strcmp(o, "ignore_local_fs")) { + if (remount && !args->ar_ignore_local_fs) + goto cant_remount; + args->ar_ignore_local_fs = 1; + } + + else if (!strcmp(o, "localflocks")) { + if (remount && !args->ar_localflocks) + goto cant_remount; + args->ar_localflocks = 1; + } + + else if (!strcmp(o, "localcaching")) { + if (remount && !args->ar_localcaching) + goto cant_remount; + args->ar_localcaching = 1; + } + + else if (!strcmp(o, "debug")) + args->ar_debug = 1; + + else if (!strcmp(o, "nodebug")) + args->ar_debug = 0; + + else if (!strcmp(o, "upgrade")) { + if (remount && !args->ar_upgrade) + goto cant_remount; + args->ar_upgrade = 1; + } + + else if (!strcmp(o, "num_glockd")) { + unsigned int x; + if (!v) + goto need_value; + sscanf(v, "%u", &x); + if (remount && x != args->ar_num_glockd) + goto cant_remount; + if (!x || x > GFS2_GLOCKD_MAX) { + fs_info(sdp, "0 < num_glockd <= %u (not %u)\n", + GFS2_GLOCKD_MAX, x); + error = -EINVAL; + break; + } + args->ar_num_glockd = x; + } + + else if (!strcmp(o, "acl")) { + args->ar_posix_acl = 1; + sdp->sd_vfs->s_flags |= MS_POSIXACL; + } + + else if (!strcmp(o, "noacl")) { + args->ar_posix_acl = 0; + sdp->sd_vfs->s_flags &= ~MS_POSIXACL; + } + + else if (!strcmp(o, "quota")) { + if (!v) + goto need_value; + if (!strcmp(v, "off")) + args->ar_quota = GFS2_QUOTA_OFF; + else if (!strcmp(v, "account")) + args->ar_quota = GFS2_QUOTA_ACCOUNT; + else if (!strcmp(v, "on")) + args->ar_quota = GFS2_QUOTA_ON; + else { + fs_info(sdp, "invalid value for quota\n"); + error = -EINVAL; + break; + } + } + + else if (!strcmp(o, "suiddir")) + args->ar_suiddir = 1; + + else if (!strcmp(o, "nosuiddir")) + args->ar_suiddir = 0; + + else if (!strcmp(o, "data")) { + if (!v) + goto need_value; + if (!strcmp(v, "writeback")) + args->ar_data = GFS2_DATA_WRITEBACK; + else if (!strcmp(v, "ordered")) + args->ar_data = GFS2_DATA_ORDERED; + else { + fs_info(sdp, "invalid value for data\n"); + error = -EINVAL; + break; + } + } + + else { + fs_info(sdp, "unknown option: %s\n", o); + error = -EINVAL; + break; + } + } + + if (error) + fs_info(sdp, "invalid mount option(s)\n"); + + if (data != data_arg) + kfree(data); + + return error; + + need_value: + fs_info(sdp, "need value for option %s\n", o); + return -EINVAL; + + cant_remount: + fs_info(sdp, "can't remount with option %s\n", o); + return -EINVAL; +} + diff --git a/fs/gfs2/mount.h b/fs/gfs2/mount.h new file mode 100644 index 000000000000..bc8331cd7b2c --- /dev/null +++ b/fs/gfs2/mount.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __MOUNT_DOT_H__ +#define __MOUNT_DOT_H__ + +int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount); + +#endif /* __MOUNT_DOT_H__ */ diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c new file mode 100644 index 000000000000..2a1ef5aa7f0c --- /dev/null +++ b/fs/gfs2/ondisk.c @@ -0,0 +1,590 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include + +#define pv(struct, member, fmt) printk(" "#member" = "fmt"\n", struct->member); +#define pa(struct, member, count) print_array(#member, struct->member, count); + +/** + * print_array - Print out an array of bytes + * @title: what to print before the array + * @buf: the array + * @count: the number of bytes + * + */ + +static void print_array(char *title, char *buf, int count) +{ + int x; + + printk(" %s =\n", title); + for (x = 0; x < count; x++) { + printk("%.2X ", (unsigned char)buf[x]); + if (x % 16 == 15) + printk("\n"); + } + if (x % 16) + printk("\n"); +} + +/* + * gfs2_xxx_in - read in an xxx struct + * first arg: the cpu-order structure + * buf: the disk-order buffer + * + * gfs2_xxx_out - write out an xxx struct + * first arg: the cpu-order structure + * buf: the disk-order buffer + * + * gfs2_xxx_print - print out an xxx struct + * first arg: the cpu-order structure + */ + +void gfs2_inum_in(struct gfs2_inum *no, char *buf) +{ + struct gfs2_inum *str = (struct gfs2_inum *)buf; + + no->no_formal_ino = be64_to_cpu(str->no_formal_ino); + no->no_addr = be64_to_cpu(str->no_addr); +} + +void gfs2_inum_out(struct gfs2_inum *no, char *buf) +{ + struct gfs2_inum *str = (struct gfs2_inum *)buf; + + str->no_formal_ino = cpu_to_be64(no->no_formal_ino); + str->no_addr = cpu_to_be64(no->no_addr); +} + +void gfs2_inum_print(struct gfs2_inum *no) +{ + pv(no, no_formal_ino, "%llu"); + pv(no, no_addr, "%llu"); +} + +void gfs2_meta_header_in(struct gfs2_meta_header *mh, char *buf) +{ + struct gfs2_meta_header *str = (struct gfs2_meta_header *)buf; + + mh->mh_magic = be32_to_cpu(str->mh_magic); + mh->mh_type = be16_to_cpu(str->mh_type); + mh->mh_format = be16_to_cpu(str->mh_format); +} + +void gfs2_meta_header_out(struct gfs2_meta_header *mh, char *buf) +{ + struct gfs2_meta_header *str = (struct gfs2_meta_header *)buf; + + str->mh_magic = cpu_to_be32(mh->mh_magic); + str->mh_type = cpu_to_be16(mh->mh_type); + str->mh_format = cpu_to_be16(mh->mh_format); +} + +void gfs2_meta_header_print(struct gfs2_meta_header *mh) +{ + pv(mh, mh_magic, "0x%.8X"); + pv(mh, mh_type, "%u"); + pv(mh, mh_format, "%u"); +} + +void gfs2_sb_in(struct gfs2_sb *sb, char *buf) +{ + struct gfs2_sb *str = (struct gfs2_sb *)buf; + + gfs2_meta_header_in(&sb->sb_header, buf); + + sb->sb_fs_format = be32_to_cpu(str->sb_fs_format); + sb->sb_multihost_format = be32_to_cpu(str->sb_multihost_format); + sb->sb_bsize = be32_to_cpu(str->sb_bsize); + sb->sb_bsize_shift = be32_to_cpu(str->sb_bsize_shift); + + gfs2_inum_in(&sb->sb_master_dir, (char *)&str->sb_master_dir); + gfs2_inum_in(&sb->sb_root_dir, (char *)&str->sb_root_dir); + + memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN); + memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN); +} + +void gfs2_sb_out(struct gfs2_sb *sb, char *buf) +{ + struct gfs2_sb *str = (struct gfs2_sb *)buf; + + gfs2_meta_header_out(&sb->sb_header, buf); + + str->sb_fs_format = cpu_to_be32(sb->sb_fs_format); + str->sb_multihost_format = cpu_to_be32(sb->sb_multihost_format); + str->sb_bsize = cpu_to_be32(sb->sb_bsize); + str->sb_bsize_shift = cpu_to_be32(sb->sb_bsize_shift); + + gfs2_inum_out(&sb->sb_master_dir, (char *)&str->sb_master_dir); + gfs2_inum_out(&sb->sb_root_dir, (char *)&str->sb_root_dir); + + memcpy(str->sb_lockproto, sb->sb_lockproto, GFS2_LOCKNAME_LEN); + memcpy(str->sb_locktable, sb->sb_locktable, GFS2_LOCKNAME_LEN); +} + +void gfs2_sb_print(struct gfs2_sb *sb) +{ + gfs2_meta_header_print(&sb->sb_header); + + pv(sb, sb_fs_format, "%u"); + pv(sb, sb_multihost_format, "%u"); + + pv(sb, sb_bsize, "%u"); + pv(sb, sb_bsize_shift, "%u"); + + gfs2_inum_print(&sb->sb_master_dir); + + pv(sb, sb_lockproto, "%s"); + pv(sb, sb_locktable, "%s"); +} + +void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf) +{ + struct gfs2_rindex *str = (struct gfs2_rindex *)buf; + + ri->ri_addr = be64_to_cpu(str->ri_addr); + ri->ri_length = be32_to_cpu(str->ri_length); + ri->ri_data0 = be64_to_cpu(str->ri_data0); + ri->ri_data = be32_to_cpu(str->ri_data); + ri->ri_bitbytes = be32_to_cpu(str->ri_bitbytes); + +} + +void gfs2_rindex_out(struct gfs2_rindex *ri, char *buf) +{ + struct gfs2_rindex *str = (struct gfs2_rindex *)buf; + + str->ri_addr = cpu_to_be64(ri->ri_addr); + str->ri_length = cpu_to_be32(ri->ri_length); + str->__pad = 0; + + str->ri_data0 = cpu_to_be64(ri->ri_data0); + str->ri_data = cpu_to_be32(ri->ri_data); + str->ri_bitbytes = cpu_to_be32(ri->ri_bitbytes); + memset(str->ri_reserved, 0, sizeof(str->ri_reserved)); +} + +void gfs2_rindex_print(struct gfs2_rindex *ri) +{ + pv(ri, ri_addr, "%llu"); + pv(ri, ri_length, "%u"); + + pv(ri, ri_data0, "%llu"); + pv(ri, ri_data, "%u"); + + pv(ri, ri_bitbytes, "%u"); +} + +void gfs2_rgrp_in(struct gfs2_rgrp *rg, char *buf) +{ + struct gfs2_rgrp *str = (struct gfs2_rgrp *)buf; + + gfs2_meta_header_in(&rg->rg_header, buf); + rg->rg_flags = be32_to_cpu(str->rg_flags); + rg->rg_free = be32_to_cpu(str->rg_free); + rg->rg_dinodes = be32_to_cpu(str->rg_dinodes); +} + +void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf) +{ + struct gfs2_rgrp *str = (struct gfs2_rgrp *)buf; + + gfs2_meta_header_out(&rg->rg_header, buf); + str->rg_flags = cpu_to_be32(rg->rg_flags); + str->rg_free = cpu_to_be32(rg->rg_free); + str->rg_dinodes = cpu_to_be32(rg->rg_dinodes); + + memset(&str->rg_reserved, 0, sizeof(str->rg_reserved)); +} + +void gfs2_rgrp_print(struct gfs2_rgrp *rg) +{ + gfs2_meta_header_print(&rg->rg_header); + pv(rg, rg_flags, "%u"); + pv(rg, rg_free, "%u"); + pv(rg, rg_dinodes, "%u"); + + pa(rg, rg_reserved, 36); +} + +void gfs2_quota_in(struct gfs2_quota *qu, char *buf) +{ + struct gfs2_quota *str = (struct gfs2_quota *)buf; + + qu->qu_limit = be64_to_cpu(str->qu_limit); + qu->qu_warn = be64_to_cpu(str->qu_warn); + qu->qu_value = be64_to_cpu(str->qu_value); +} + +void gfs2_quota_out(struct gfs2_quota *qu, char *buf) +{ + struct gfs2_quota *str = (struct gfs2_quota *)buf; + + str->qu_limit = cpu_to_be64(qu->qu_limit); + str->qu_warn = cpu_to_be64(qu->qu_warn); + str->qu_value = cpu_to_be64(qu->qu_value); +} + +void gfs2_quota_print(struct gfs2_quota *qu) +{ + pv(qu, qu_limit, "%llu"); + pv(qu, qu_warn, "%llu"); + pv(qu, qu_value, "%lld"); +} + +void gfs2_dinode_in(struct gfs2_dinode *di, char *buf) +{ + struct gfs2_dinode *str = (struct gfs2_dinode *)buf; + + gfs2_meta_header_in(&di->di_header, buf); + gfs2_inum_in(&di->di_num, (char *)&str->di_num); + + di->di_mode = be32_to_cpu(str->di_mode); + di->di_uid = be32_to_cpu(str->di_uid); + di->di_gid = be32_to_cpu(str->di_gid); + di->di_nlink = be32_to_cpu(str->di_nlink); + di->di_size = be64_to_cpu(str->di_size); + di->di_blocks = be64_to_cpu(str->di_blocks); + di->di_atime = be64_to_cpu(str->di_atime); + di->di_mtime = be64_to_cpu(str->di_mtime); + di->di_ctime = be64_to_cpu(str->di_ctime); + di->di_major = be32_to_cpu(str->di_major); + di->di_minor = be32_to_cpu(str->di_minor); + + di->di_goal_meta = be64_to_cpu(str->di_goal_meta); + di->di_goal_data = be64_to_cpu(str->di_goal_data); + + di->di_flags = be32_to_cpu(str->di_flags); + di->di_payload_format = be32_to_cpu(str->di_payload_format); + di->di_height = be16_to_cpu(str->di_height); + + di->di_depth = be16_to_cpu(str->di_depth); + di->di_entries = be32_to_cpu(str->di_entries); + + di->di_eattr = be64_to_cpu(str->di_eattr); + +} + +void gfs2_dinode_out(struct gfs2_dinode *di, char *buf) +{ + struct gfs2_dinode *str = (struct gfs2_dinode *)buf; + + gfs2_meta_header_out(&di->di_header, buf); + gfs2_inum_out(&di->di_num, (char *)&str->di_num); + + str->di_mode = cpu_to_be32(di->di_mode); + str->di_uid = cpu_to_be32(di->di_uid); + str->di_gid = cpu_to_be32(di->di_gid); + str->di_nlink = cpu_to_be32(di->di_nlink); + str->di_size = cpu_to_be64(di->di_size); + str->di_blocks = cpu_to_be64(di->di_blocks); + str->di_atime = cpu_to_be64(di->di_atime); + str->di_mtime = cpu_to_be64(di->di_mtime); + str->di_ctime = cpu_to_be64(di->di_ctime); + str->di_major = cpu_to_be32(di->di_major); + str->di_minor = cpu_to_be32(di->di_minor); + + str->di_goal_meta = cpu_to_be64(di->di_goal_meta); + str->di_goal_data = cpu_to_be64(di->di_goal_data); + + str->di_flags = cpu_to_be32(di->di_flags); + str->di_payload_format = cpu_to_be32(di->di_payload_format); + str->di_height = cpu_to_be16(di->di_height); + + str->di_depth = cpu_to_be16(di->di_depth); + str->di_entries = cpu_to_be32(di->di_entries); + + str->di_eattr = cpu_to_be64(di->di_eattr); + +} + +void gfs2_dinode_print(struct gfs2_dinode *di) +{ + gfs2_meta_header_print(&di->di_header); + gfs2_inum_print(&di->di_num); + + pv(di, di_mode, "0%o"); + pv(di, di_uid, "%u"); + pv(di, di_gid, "%u"); + pv(di, di_nlink, "%u"); + pv(di, di_size, "%llu"); + pv(di, di_blocks, "%llu"); + pv(di, di_atime, "%lld"); + pv(di, di_mtime, "%lld"); + pv(di, di_ctime, "%lld"); + pv(di, di_major, "%u"); + pv(di, di_minor, "%u"); + + pv(di, di_goal_meta, "%llu"); + pv(di, di_goal_data, "%llu"); + + pv(di, di_flags, "0x%.8X"); + pv(di, di_payload_format, "%u"); + pv(di, di_height, "%u"); + + pv(di, di_depth, "%u"); + pv(di, di_entries, "%u"); + + pv(di, di_eattr, "%llu"); +} + +void gfs2_dirent_in(struct gfs2_dirent *de, char *buf) +{ + struct gfs2_dirent *str = (struct gfs2_dirent *)buf; + + gfs2_inum_in(&de->de_inum, buf); + de->de_hash = be32_to_cpu(str->de_hash); + de->de_rec_len = be32_to_cpu(str->de_rec_len); + de->de_name_len = str->de_name_len; + de->de_type = str->de_type; +} + +void gfs2_dirent_out(struct gfs2_dirent *de, char *buf) +{ + struct gfs2_dirent *str = (struct gfs2_dirent *)buf; + + gfs2_inum_out(&de->de_inum, buf); + str->de_hash = cpu_to_be32(de->de_hash); + str->de_rec_len = cpu_to_be32(de->de_rec_len); + str->de_name_len = de->de_name_len; + str->de_type = de->de_type; + str->__pad1 = 0; + str->__pad2 = 0; +} + +void gfs2_dirent_print(struct gfs2_dirent *de, char *name) +{ + char buf[GFS2_FNAMESIZE + 1]; + + gfs2_inum_print(&de->de_inum); + pv(de, de_hash, "0x%.8X"); + pv(de, de_rec_len, "%u"); + pv(de, de_name_len, "%u"); + pv(de, de_type, "%u"); + + memset(buf, 0, GFS2_FNAMESIZE + 1); + memcpy(buf, name, de->de_name_len); + printk(" name = %s\n", buf); +} + +void gfs2_leaf_in(struct gfs2_leaf *lf, char *buf) +{ + struct gfs2_leaf *str = (struct gfs2_leaf *)buf; + + gfs2_meta_header_in(&lf->lf_header, buf); + lf->lf_depth = be16_to_cpu(str->lf_depth); + lf->lf_entries = be16_to_cpu(str->lf_entries); + lf->lf_dirent_format = be32_to_cpu(str->lf_dirent_format); + lf->lf_next = be64_to_cpu(str->lf_next); +} + +void gfs2_leaf_out(struct gfs2_leaf *lf, char *buf) +{ + struct gfs2_leaf *str = (struct gfs2_leaf *)buf; + + gfs2_meta_header_out(&lf->lf_header, buf); + str->lf_depth = cpu_to_be16(lf->lf_depth); + str->lf_entries = cpu_to_be16(lf->lf_entries); + str->lf_dirent_format = cpu_to_be32(lf->lf_dirent_format); + str->lf_next = cpu_to_be64(lf->lf_next); + memset(&str->lf_reserved, 0, sizeof(str->lf_reserved)); +} + +void gfs2_leaf_print(struct gfs2_leaf *lf) +{ + gfs2_meta_header_print(&lf->lf_header); + pv(lf, lf_depth, "%u"); + pv(lf, lf_entries, "%u"); + pv(lf, lf_dirent_format, "%u"); + pv(lf, lf_next, "%llu"); + + pa(lf, lf_reserved, 32); +} + +void gfs2_ea_header_in(struct gfs2_ea_header *ea, char *buf) +{ + struct gfs2_ea_header *str = (struct gfs2_ea_header *)buf; + + ea->ea_rec_len = be32_to_cpu(str->ea_rec_len); + ea->ea_data_len = be32_to_cpu(str->ea_data_len); + ea->ea_name_len = str->ea_name_len; + ea->ea_type = str->ea_type; + ea->ea_flags = str->ea_flags; + ea->ea_num_ptrs = str->ea_num_ptrs; +} + +void gfs2_ea_header_out(struct gfs2_ea_header *ea, char *buf) +{ + struct gfs2_ea_header *str = (struct gfs2_ea_header *)buf; + + str->ea_rec_len = cpu_to_be32(ea->ea_rec_len); + str->ea_data_len = cpu_to_be32(ea->ea_data_len); + str->ea_name_len = ea->ea_name_len; + str->ea_type = ea->ea_type; + str->ea_flags = ea->ea_flags; + str->ea_num_ptrs = ea->ea_num_ptrs; + str->__pad = 0; +} + +void gfs2_ea_header_print(struct gfs2_ea_header *ea, char *name) +{ + char buf[GFS2_EA_MAX_NAME_LEN + 1]; + + pv(ea, ea_rec_len, "%u"); + pv(ea, ea_data_len, "%u"); + pv(ea, ea_name_len, "%u"); + pv(ea, ea_type, "%u"); + pv(ea, ea_flags, "%u"); + pv(ea, ea_num_ptrs, "%u"); + + memset(buf, 0, GFS2_EA_MAX_NAME_LEN + 1); + memcpy(buf, name, ea->ea_name_len); + printk(" name = %s\n", buf); +} + +void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf) +{ + struct gfs2_log_header *str = (struct gfs2_log_header *)buf; + + gfs2_meta_header_in(&lh->lh_header, buf); + lh->lh_sequence = be64_to_cpu(str->lh_sequence); + lh->lh_flags = be32_to_cpu(str->lh_flags); + lh->lh_tail = be32_to_cpu(str->lh_tail); + lh->lh_blkno = be32_to_cpu(str->lh_blkno); + lh->lh_hash = be32_to_cpu(str->lh_hash); +} + +void gfs2_log_header_print(struct gfs2_log_header *lh) +{ + gfs2_meta_header_print(&lh->lh_header); + pv(lh, lh_sequence, "%llu"); + pv(lh, lh_flags, "0x%.8X"); + pv(lh, lh_tail, "%u"); + pv(lh, lh_blkno, "%u"); + pv(lh, lh_hash, "0x%.8X"); +} + +void gfs2_log_descriptor_print(struct gfs2_log_descriptor *ld) +{ + gfs2_meta_header_print(&ld->ld_header); + pv(ld, ld_type, "%u"); + pv(ld, ld_length, "%u"); + pv(ld, ld_data1, "%u"); + pv(ld, ld_data2, "%u"); + + pa(ld, ld_reserved, 32); +} + +void gfs2_inum_range_in(struct gfs2_inum_range *ir, char *buf) +{ + struct gfs2_inum_range *str = (struct gfs2_inum_range *)buf; + + ir->ir_start = be64_to_cpu(str->ir_start); + ir->ir_length = be64_to_cpu(str->ir_length); +} + +void gfs2_inum_range_out(struct gfs2_inum_range *ir, char *buf) +{ + struct gfs2_inum_range *str = (struct gfs2_inum_range *)buf; + + str->ir_start = cpu_to_be64(ir->ir_start); + str->ir_length = cpu_to_be64(ir->ir_length); +} + +void gfs2_inum_range_print(struct gfs2_inum_range *ir) +{ + pv(ir, ir_start, "%llu"); + pv(ir, ir_length, "%llu"); +} + +void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, char *buf) +{ + struct gfs2_statfs_change *str = (struct gfs2_statfs_change *)buf; + + sc->sc_total = be64_to_cpu(str->sc_total); + sc->sc_free = be64_to_cpu(str->sc_free); + sc->sc_dinodes = be64_to_cpu(str->sc_dinodes); +} + +void gfs2_statfs_change_out(struct gfs2_statfs_change *sc, char *buf) +{ + struct gfs2_statfs_change *str = (struct gfs2_statfs_change *)buf; + + str->sc_total = cpu_to_be64(sc->sc_total); + str->sc_free = cpu_to_be64(sc->sc_free); + str->sc_dinodes = cpu_to_be64(sc->sc_dinodes); +} + +void gfs2_statfs_change_print(struct gfs2_statfs_change *sc) +{ + pv(sc, sc_total, "%lld"); + pv(sc, sc_free, "%lld"); + pv(sc, sc_dinodes, "%lld"); +} + +void gfs2_unlinked_tag_in(struct gfs2_unlinked_tag *ut, char *buf) +{ + struct gfs2_unlinked_tag *str = (struct gfs2_unlinked_tag *)buf; + + gfs2_inum_in(&ut->ut_inum, buf); + ut->ut_flags = be32_to_cpu(str->ut_flags); +} + +void gfs2_unlinked_tag_out(struct gfs2_unlinked_tag *ut, char *buf) +{ + struct gfs2_unlinked_tag *str = (struct gfs2_unlinked_tag *)buf; + + gfs2_inum_out(&ut->ut_inum, buf); + str->ut_flags = cpu_to_be32(ut->ut_flags); + str->__pad = 0; +} + +void gfs2_unlinked_tag_print(struct gfs2_unlinked_tag *ut) +{ + gfs2_inum_print(&ut->ut_inum); + pv(ut, ut_flags, "%u"); +} + +void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf) +{ + struct gfs2_quota_change *str = (struct gfs2_quota_change *)buf; + + qc->qc_change = be64_to_cpu(str->qc_change); + qc->qc_flags = be32_to_cpu(str->qc_flags); + qc->qc_id = be32_to_cpu(str->qc_id); +} + +void gfs2_quota_change_out(struct gfs2_quota_change *qc, char *buf) +{ + struct gfs2_quota_change *str = (struct gfs2_quota_change *)buf; + + str->qc_change = cpu_to_be64(qc->qc_change); + str->qc_flags = cpu_to_be32(qc->qc_flags); + str->qc_id = cpu_to_be32(qc->qc_id); +} + +void gfs2_quota_change_print(struct gfs2_quota_change *qc) +{ + pv(qc, qc_change, "%lld"); + pv(qc, qc_flags, "0x%.8X"); + pv(qc, qc_id, "%u"); +} + + + diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c new file mode 100644 index 000000000000..0aa5f140ddb1 --- /dev/null +++ b/fs/gfs2/ops_address.c @@ -0,0 +1,515 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "glock.h" +#include "inode.h" +#include "jdata.h" +#include "log.h" +#include "meta_io.h" +#include "ops_address.h" +#include "page.h" +#include "quota.h" +#include "trans.h" + +/** + * get_block - Fills in a buffer head with details about a block + * @inode: The inode + * @lblock: The block number to look up + * @bh_result: The buffer head to return the result in + * @create: Non-zero if we may add block to the file + * + * Returns: errno + */ + +static int get_block(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + struct gfs2_inode *ip = get_v2ip(inode); + int new = create; + uint64_t dblock; + int error; + + error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); + if (error) + return error; + + if (!dblock) + return 0; + + map_bh(bh_result, inode->i_sb, dblock); + if (new) + set_buffer_new(bh_result); + + return 0; +} + +/** + * get_block_noalloc - Fills in a buffer head with details about a block + * @inode: The inode + * @lblock: The block number to look up + * @bh_result: The buffer head to return the result in + * @create: Non-zero if we may add block to the file + * + * Returns: errno + */ + +static int get_block_noalloc(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + struct gfs2_inode *ip = get_v2ip(inode); + int new = 0; + uint64_t dblock; + int error; + + error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); + if (error) + return error; + + if (dblock) + map_bh(bh_result, inode->i_sb, dblock); + else if (gfs2_assert_withdraw(ip->i_sbd, !create)) + error = -EIO; + + return error; +} + +static int get_blocks(struct inode *inode, sector_t lblock, + unsigned long max_blocks, struct buffer_head *bh_result, + int create) +{ + struct gfs2_inode *ip = get_v2ip(inode); + int new = create; + uint64_t dblock; + uint32_t extlen; + int error; + + error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); + if (error) + return error; + + if (!dblock) + return 0; + + map_bh(bh_result, inode->i_sb, dblock); + if (new) + set_buffer_new(bh_result); + + if (extlen > max_blocks) + extlen = max_blocks; + bh_result->b_size = extlen << inode->i_blkbits; + + return 0; +} + +static int get_blocks_noalloc(struct inode *inode, sector_t lblock, + unsigned long max_blocks, + struct buffer_head *bh_result, int create) +{ + struct gfs2_inode *ip = get_v2ip(inode); + int new = 0; + uint64_t dblock; + uint32_t extlen; + int error; + + error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); + if (error) + return error; + + if (dblock) { + map_bh(bh_result, inode->i_sb, dblock); + if (extlen > max_blocks) + extlen = max_blocks; + bh_result->b_size = extlen << inode->i_blkbits; + } else if (gfs2_assert_withdraw(ip->i_sbd, !create)) + error = -EIO; + + return error; +} + +/** + * gfs2_writepage - Write complete page + * @page: Page to write + * + * Returns: errno + * + * Use Linux VFS block_write_full_page() to write one page, + * using GFS2's get_block_noalloc to find which blocks to write. + */ + +static int gfs2_writepage(struct page *page, struct writeback_control *wbc) +{ + struct gfs2_inode *ip = get_v2ip(page->mapping->host); + struct gfs2_sbd *sdp = ip->i_sbd; + int error; + + atomic_inc(&sdp->sd_ops_address); + + if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) { + unlock_page(page); + return -EIO; + } + if (get_transaction) { + redirty_page_for_writepage(wbc, page); + unlock_page(page); + return 0; + } + + error = block_write_full_page(page, get_block_noalloc, wbc); + + gfs2_meta_cache_flush(ip); + + return error; +} + +/** + * stuffed_readpage - Fill in a Linux page with stuffed file data + * @ip: the inode + * @page: the page + * + * Returns: errno + */ + +static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) +{ + struct buffer_head *dibh; + void *kaddr; + int error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; + + kaddr = kmap(page); + memcpy((char *)kaddr, + dibh->b_data + sizeof(struct gfs2_dinode), + ip->i_di.di_size); + memset((char *)kaddr + ip->i_di.di_size, + 0, + PAGE_CACHE_SIZE - ip->i_di.di_size); + kunmap(page); + + brelse(dibh); + + SetPageUptodate(page); + + return 0; +} + +static int zero_readpage(struct page *page) +{ + void *kaddr; + + kaddr = kmap(page); + memset(kaddr, 0, PAGE_CACHE_SIZE); + kunmap(page); + + SetPageUptodate(page); + unlock_page(page); + + return 0; +} + +/** + * jdata_readpage - readpage that goes through gfs2_jdata_read_mem() + * @ip: + * @page: The page to read + * + * Returns: errno + */ + +static int jdata_readpage(struct gfs2_inode *ip, struct page *page) +{ + void *kaddr; + int ret; + + kaddr = kmap(page); + + ret = gfs2_jdata_read_mem(ip, kaddr, + (uint64_t)page->index << PAGE_CACHE_SHIFT, + PAGE_CACHE_SIZE); + if (ret >= 0) { + if (ret < PAGE_CACHE_SIZE) + memset(kaddr + ret, 0, PAGE_CACHE_SIZE - ret); + SetPageUptodate(page); + ret = 0; + } + + kunmap(page); + + unlock_page(page); + + return ret; +} + +/** + * gfs2_readpage - readpage with locking + * @file: The file to read a page for + * @page: The page to read + * + * Returns: errno + */ + +static int gfs2_readpage(struct file *file, struct page *page) +{ + struct gfs2_inode *ip = get_v2ip(page->mapping->host); + struct gfs2_sbd *sdp = ip->i_sbd; + int error; + + atomic_inc(&sdp->sd_ops_address); + + if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl))) { + unlock_page(page); + return -EOPNOTSUPP; + } + + if (!gfs2_is_jdata(ip)) { + if (gfs2_is_stuffed(ip)) { + if (!page->index) { + error = stuffed_readpage(ip, page); + unlock_page(page); + } else + error = zero_readpage(page); + } else + error = block_read_full_page(page, get_block); + } else + error = jdata_readpage(ip, page); + + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + + return error; +} + +/** + * gfs2_prepare_write - Prepare to write a page to a file + * @file: The file to write to + * @page: The page which is to be prepared for writing + * @from: From (byte range within page) + * @to: To (byte range within page) + * + * Returns: errno + */ + +static int gfs2_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct gfs2_inode *ip = get_v2ip(page->mapping->host); + struct gfs2_sbd *sdp = ip->i_sbd; + int error = 0; + + atomic_inc(&sdp->sd_ops_address); + + if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl))) + return -EOPNOTSUPP; + + if (gfs2_is_stuffed(ip)) { + uint64_t file_size; + file_size = ((uint64_t)page->index << PAGE_CACHE_SHIFT) + to; + + if (file_size > sdp->sd_sb.sb_bsize - + sizeof(struct gfs2_dinode)) { + error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, + page); + if (!error) + error = block_prepare_write(page, from, to, + get_block); + } else if (!PageUptodate(page)) + error = stuffed_readpage(ip, page); + } else + error = block_prepare_write(page, from, to, get_block); + + return error; +} + +/** + * gfs2_commit_write - Commit write to a file + * @file: The file to write to + * @page: The page containing the data + * @from: From (byte range within page) + * @to: To (byte range within page) + * + * Returns: errno + */ + +static int gfs2_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct inode *inode = page->mapping->host; + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_sbd *sdp = ip->i_sbd; + int error; + + atomic_inc(&sdp->sd_ops_address); + + if (gfs2_is_stuffed(ip)) { + struct buffer_head *dibh; + uint64_t file_size; + void *kaddr; + + file_size = ((uint64_t)page->index << PAGE_CACHE_SHIFT) + to; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto fail; + + gfs2_trans_add_bh(ip->i_gl, dibh); + + kaddr = kmap(page); + memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from, + (char *)kaddr + from, + to - from); + kunmap(page); + + brelse(dibh); + + SetPageUptodate(page); + + if (inode->i_size < file_size) + i_size_write(inode, file_size); + } else { + if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) + gfs2_page_add_databufs(sdp, page, from, to); + error = generic_commit_write(file, page, from, to); + if (error) + goto fail; + } + + return 0; + + fail: + ClearPageUptodate(page); + + return error; +} + +/** + * gfs2_bmap - Block map function + * @mapping: Address space info + * @lblock: The block to map + * + * Returns: The disk address for the block or 0 on hole or error + */ + +static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) +{ + struct gfs2_inode *ip = get_v2ip(mapping->host); + struct gfs2_holder i_gh; + sector_t dblock = 0; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_address); + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + if (error) + return 0; + + if (!gfs2_is_stuffed(ip)) + dblock = generic_block_bmap(mapping, lblock, get_block); + + gfs2_glock_dq_uninit(&i_gh); + + return dblock; +} + +static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh) +{ + struct gfs2_databuf *db; + + gfs2_log_lock(sdp); + db = get_v2db(bh); + if (db) { + db->db_bh = NULL; + set_v2db(bh, NULL); + gfs2_log_unlock(sdp); + brelse(bh); + } else + gfs2_log_unlock(sdp); + + lock_buffer(bh); + clear_buffer_dirty(bh); + bh->b_bdev = NULL; + clear_buffer_mapped(bh); + clear_buffer_req(bh); + clear_buffer_new(bh); + clear_buffer_delay(bh); + unlock_buffer(bh); +} + +static int gfs2_invalidatepage(struct page *page, unsigned long offset) +{ + struct gfs2_sbd *sdp = get_v2sdp(page->mapping->host->i_sb); + struct buffer_head *head, *bh, *next; + unsigned int curr_off = 0; + int ret = 1; + + BUG_ON(!PageLocked(page)); + if (!page_has_buffers(page)) + return 1; + + bh = head = page_buffers(page); + do { + unsigned int next_off = curr_off + bh->b_size; + next = bh->b_this_page; + + if (offset <= curr_off) + discard_buffer(sdp, bh); + + curr_off = next_off; + bh = next; + } while (bh != head); + + if (!offset) + ret = try_to_release_page(page, 0); + + return ret; +} + +static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_sbd *sdp = ip->i_sbd; + get_blocks_t *gb = get_blocks; + + atomic_inc(&sdp->sd_ops_address); + + if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)) || + gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) + return -EINVAL; + + if (rw == WRITE && !get_transaction) + gb = get_blocks_noalloc; + + return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, gb, NULL); +} + +struct address_space_operations gfs2_file_aops = { + .writepage = gfs2_writepage, + .readpage = gfs2_readpage, + .sync_page = block_sync_page, + .prepare_write = gfs2_prepare_write, + .commit_write = gfs2_commit_write, + .bmap = gfs2_bmap, + .invalidatepage = gfs2_invalidatepage, + .direct_IO = gfs2_direct_IO, +}; + diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h new file mode 100644 index 000000000000..ced9ea0fdd31 --- /dev/null +++ b/fs/gfs2/ops_address.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __OPS_ADDRESS_DOT_H__ +#define __OPS_ADDRESS_DOT_H__ + +extern struct address_space_operations gfs2_file_aops; + +#endif /* __OPS_ADDRESS_DOT_H__ */ diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c new file mode 100644 index 000000000000..5c618611c11b --- /dev/null +++ b/fs/gfs2/ops_dentry.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "dir.h" +#include "glock.h" +#include "ops_dentry.h" + +/** + * gfs2_drevalidate - Check directory lookup consistency + * @dentry: the mapping to check + * @nd: + * + * Check to make sure the lookup necessary to arrive at this inode from its + * parent is still good. + * + * Returns: 1 if the dentry is ok, 0 if it isn't + */ + +static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) +{ + struct dentry *parent = dget_parent(dentry); + struct gfs2_inode *dip = get_v2ip(parent->d_inode); + struct gfs2_sbd *sdp = dip->i_sbd; + struct inode *inode; + struct gfs2_holder d_gh; + struct gfs2_inode *ip; + struct gfs2_inum inum; + unsigned int type; + int error; + + lock_kernel(); + + atomic_inc(&sdp->sd_ops_dentry); + + inode = dentry->d_inode; + if (inode && is_bad_inode(inode)) + goto invalid; + + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); + if (error) + goto fail; + + error = gfs2_dir_search(dip, &dentry->d_name, &inum, &type); + switch (error) { + case 0: + if (!inode) + goto invalid_gunlock; + break; + case -ENOENT: + if (!inode) + goto valid_gunlock; + goto invalid_gunlock; + default: + goto fail_gunlock; + } + + ip = get_v2ip(inode); + + if (!gfs2_inum_equal(&ip->i_num, &inum)) + goto invalid_gunlock; + + if (IF2DT(ip->i_di.di_mode) != type) { + gfs2_consist_inode(dip); + goto fail_gunlock; + } + + valid_gunlock: + gfs2_glock_dq_uninit(&d_gh); + + valid: + unlock_kernel(); + dput(parent); + return 1; + + invalid_gunlock: + gfs2_glock_dq_uninit(&d_gh); + + invalid: + if (inode && S_ISDIR(inode->i_mode)) { + if (have_submounts(dentry)) + goto valid; + shrink_dcache_parent(dentry); + } + d_drop(dentry); + + unlock_kernel(); + dput(parent); + return 0; + + fail_gunlock: + gfs2_glock_dq_uninit(&d_gh); + + fail: + unlock_kernel(); + dput(parent); + return 0; +} + +struct dentry_operations gfs2_dops = { + .d_revalidate = gfs2_drevalidate, +}; + diff --git a/fs/gfs2/ops_dentry.h b/fs/gfs2/ops_dentry.h new file mode 100644 index 000000000000..94e3ee170165 --- /dev/null +++ b/fs/gfs2/ops_dentry.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __OPS_DENTRY_DOT_H__ +#define __OPS_DENTRY_DOT_H__ + +extern struct dentry_operations gfs2_dops; + +#endif /* __OPS_DENTRY_DOT_H__ */ diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c new file mode 100644 index 000000000000..0ae3a0af192d --- /dev/null +++ b/fs/gfs2/ops_export.c @@ -0,0 +1,310 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "dir.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "ops_export.h" +#include "rgrp.h" + +static struct dentry *gfs2_decode_fh(struct super_block *sb, + __u32 *fh, + int fh_len, + int fh_type, + int (*acceptable)(void *context, + struct dentry *dentry), + void *context) +{ + struct gfs2_inum this, parent; + + atomic_inc(&get_v2sdp(sb)->sd_ops_export); + + if (fh_type != fh_len) + return NULL; + + memset(&parent, 0, sizeof(struct gfs2_inum)); + + switch (fh_type) { + case 8: + parent.no_formal_ino = ((uint64_t)be32_to_cpu(fh[4])) << 32; + parent.no_formal_ino |= be32_to_cpu(fh[5]); + parent.no_addr = ((uint64_t)be32_to_cpu(fh[6])) << 32; + parent.no_addr |= be32_to_cpu(fh[7]); + case 4: + this.no_formal_ino = ((uint64_t)be32_to_cpu(fh[0])) << 32; + this.no_formal_ino |= be32_to_cpu(fh[1]); + this.no_addr = ((uint64_t)be32_to_cpu(fh[2])) << 32; + this.no_addr |= be32_to_cpu(fh[3]); + break; + default: + return NULL; + } + + return gfs2_export_ops.find_exported_dentry(sb, &this, &parent, + acceptable, context); +} + +static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, + int connectable) +{ + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_sbd *sdp = ip->i_sbd; + + atomic_inc(&sdp->sd_ops_export); + + if (*len < 4 || (connectable && *len < 8)) + return 255; + + fh[0] = ip->i_num.no_formal_ino >> 32; + fh[0] = cpu_to_be32(fh[0]); + fh[1] = ip->i_num.no_formal_ino & 0xFFFFFFFF; + fh[1] = cpu_to_be32(fh[1]); + fh[2] = ip->i_num.no_addr >> 32; + fh[2] = cpu_to_be32(fh[2]); + fh[3] = ip->i_num.no_addr & 0xFFFFFFFF; + fh[3] = cpu_to_be32(fh[3]); + *len = 4; + + if (!connectable || ip == sdp->sd_root_dir) + return *len; + + spin_lock(&dentry->d_lock); + inode = dentry->d_parent->d_inode; + ip = get_v2ip(inode); + gfs2_inode_hold(ip); + spin_unlock(&dentry->d_lock); + + fh[4] = ip->i_num.no_formal_ino >> 32; + fh[4] = cpu_to_be32(fh[4]); + fh[5] = ip->i_num.no_formal_ino & 0xFFFFFFFF; + fh[5] = cpu_to_be32(fh[5]); + fh[6] = ip->i_num.no_addr >> 32; + fh[6] = cpu_to_be32(fh[6]); + fh[7] = ip->i_num.no_addr & 0xFFFFFFFF; + fh[7] = cpu_to_be32(fh[7]); + *len = 8; + + gfs2_inode_put(ip); + + return *len; +} + +struct get_name_filldir { + struct gfs2_inum inum; + char *name; +}; + +static int get_name_filldir(void *opaque, const char *name, unsigned int length, + uint64_t offset, struct gfs2_inum *inum, + unsigned int type) +{ + struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque; + + if (!gfs2_inum_equal(inum, &gnfd->inum)) + return 0; + + memcpy(gnfd->name, name, length); + gnfd->name[length] = 0; + + return 1; +} + +static int gfs2_get_name(struct dentry *parent, char *name, + struct dentry *child) +{ + struct inode *dir = parent->d_inode; + struct inode *inode = child->d_inode; + struct gfs2_inode *dip, *ip; + struct get_name_filldir gnfd; + struct gfs2_holder gh; + uint64_t offset = 0; + int error; + + if (!dir) + return -EINVAL; + + atomic_inc(&get_v2sdp(dir->i_sb)->sd_ops_export); + + if (!S_ISDIR(dir->i_mode) || !inode) + return -EINVAL; + + dip = get_v2ip(dir); + ip = get_v2ip(inode); + + *name = 0; + gnfd.inum = ip->i_num; + gnfd.name = name; + + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh); + if (error) + return error; + + error = gfs2_dir_read(dip, &offset, &gnfd, get_name_filldir); + + gfs2_glock_dq_uninit(&gh); + + if (!error && !*name) + error = -ENOENT; + + return error; +} + +static struct dentry *gfs2_get_parent(struct dentry *child) +{ + struct gfs2_inode *dip = get_v2ip(child->d_inode); + struct qstr dotdot = { .name = "..", .len = 2 }; + struct gfs2_inode *ip; + struct inode *inode; + struct dentry *dentry; + int error; + + atomic_inc(&dip->i_sbd->sd_ops_export); + + error = gfs2_lookupi(dip, &dotdot, 1, &ip); + if (error) + return ERR_PTR(error); + + inode = gfs2_ip2v(ip); + gfs2_inode_put(ip); + + if (!inode) + return ERR_PTR(-ENOMEM); + + dentry = d_alloc_anon(inode); + if (!dentry) { + iput(inode); + return ERR_PTR(-ENOMEM); + } + + return dentry; +} + +static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_p) +{ + struct gfs2_sbd *sdp = get_v2sdp(sb); + struct gfs2_inum *inum = (struct gfs2_inum *)inum_p; + struct gfs2_holder i_gh, ri_gh, rgd_gh; + struct gfs2_rgrpd *rgd; + struct gfs2_inode *ip; + struct inode *inode; + struct dentry *dentry; + int error; + + atomic_inc(&sdp->sd_ops_export); + + /* System files? */ + + inode = gfs2_iget(sb, inum); + if (inode) { + ip = get_v2ip(inode); + if (ip->i_num.no_formal_ino != inum->no_formal_ino) { + iput(inode); + return ERR_PTR(-ESTALE); + } + goto out_inode; + } + + error = gfs2_glock_nq_num(sdp, + inum->no_addr, &gfs2_inode_glops, + LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL, + &i_gh); + if (error) + return ERR_PTR(error); + + error = gfs2_inode_get(i_gh.gh_gl, inum, NO_CREATE, &ip); + if (error) + goto fail; + if (ip) + goto out_ip; + + error = gfs2_rindex_hold(sdp, &ri_gh); + if (error) + goto fail; + + error = -EINVAL; + rgd = gfs2_blk2rgrpd(sdp, inum->no_addr); + if (!rgd) + goto fail_rindex; + + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh); + if (error) + goto fail_rindex; + + error = -ESTALE; + if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE) + goto fail_rgd; + + gfs2_glock_dq_uninit(&rgd_gh); + gfs2_glock_dq_uninit(&ri_gh); + + error = gfs2_inode_get(i_gh.gh_gl, inum, CREATE, &ip); + if (error) + goto fail; + + error = gfs2_inode_refresh(ip); + if (error) { + gfs2_inode_put(ip); + goto fail; + } + + atomic_inc(&sdp->sd_fh2dentry_misses); + + out_ip: + error = -EIO; + if (ip->i_di.di_flags & GFS2_DIF_SYSTEM) { + gfs2_inode_put(ip); + goto fail; + } + + gfs2_glock_dq_uninit(&i_gh); + + inode = gfs2_ip2v(ip); + gfs2_inode_put(ip); + + if (!inode) + return ERR_PTR(-ENOMEM); + + out_inode: + dentry = d_alloc_anon(inode); + if (!dentry) { + iput(inode); + return ERR_PTR(-ENOMEM); + } + + return dentry; + + fail_rgd: + gfs2_glock_dq_uninit(&rgd_gh); + + fail_rindex: + gfs2_glock_dq_uninit(&ri_gh); + + fail: + gfs2_glock_dq_uninit(&i_gh); + return ERR_PTR(error); +} + +struct export_operations gfs2_export_ops = { + .decode_fh = gfs2_decode_fh, + .encode_fh = gfs2_encode_fh, + .get_name = gfs2_get_name, + .get_parent = gfs2_get_parent, + .get_dentry = gfs2_get_dentry, +}; + diff --git a/fs/gfs2/ops_export.h b/fs/gfs2/ops_export.h new file mode 100644 index 000000000000..2f342f3d8755 --- /dev/null +++ b/fs/gfs2/ops_export.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __OPS_EXPORT_DOT_H__ +#define __OPS_EXPORT_DOT_H__ + +extern struct export_operations gfs2_export_ops; + +#endif /* __OPS_EXPORT_DOT_H__ */ diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c new file mode 100644 index 000000000000..1e6f51b74f44 --- /dev/null +++ b/fs/gfs2/ops_file.c @@ -0,0 +1,1597 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "dir.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "jdata.h" +#include "lm.h" +#include "log.h" +#include "meta_io.h" +#include "ops_file.h" +#include "ops_vm.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" + +/* "bad" is for NFS support */ +struct filldir_bad_entry { + char *fbe_name; + unsigned int fbe_length; + uint64_t fbe_offset; + struct gfs2_inum fbe_inum; + unsigned int fbe_type; +}; + +struct filldir_bad { + struct gfs2_sbd *fdb_sbd; + + struct filldir_bad_entry *fdb_entry; + unsigned int fdb_entry_num; + unsigned int fdb_entry_off; + + char *fdb_name; + unsigned int fdb_name_size; + unsigned int fdb_name_off; +}; + +/* For regular, non-NFS */ +struct filldir_reg { + struct gfs2_sbd *fdr_sbd; + int fdr_prefetch; + + filldir_t fdr_filldir; + void *fdr_opaque; +}; + +typedef ssize_t(*do_rw_t) (struct file *file, + char __user *buf, + size_t size, loff_t *offset, + unsigned int num_gh, struct gfs2_holder *ghs); + +/** + * gfs2_llseek - seek to a location in a file + * @file: the file + * @offset: the offset + * @origin: Where to seek from (SEEK_SET, SEEK_CUR, or SEEK_END) + * + * SEEK_END requires the glock for the file because it references the + * file's size. + * + * Returns: The new offset, or errno + */ + +static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) +{ + struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_holder i_gh; + loff_t error; + + atomic_inc(&ip->i_sbd->sd_ops_file); + + if (origin == 2) { + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, + &i_gh); + if (!error) { + error = remote_llseek(file, offset, origin); + gfs2_glock_dq_uninit(&i_gh); + } + } else + error = remote_llseek(file, offset, origin); + + return error; +} + +static inline unsigned int vma2state(struct vm_area_struct *vma) +{ + if ((vma->vm_flags & (VM_MAYWRITE | VM_MAYSHARE)) == + (VM_MAYWRITE | VM_MAYSHARE)) + return LM_ST_EXCLUSIVE; + return LM_ST_SHARED; +} + +static ssize_t walk_vm_hard(struct file *file, const char __user *buf, size_t size, + loff_t *offset, do_rw_t operation) +{ + struct gfs2_holder *ghs; + unsigned int num_gh = 0; + ssize_t count; + struct super_block *sb = file->f_dentry->d_inode->i_sb; + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long start = (unsigned long)buf; + unsigned long end = start + size; + int dumping = (current->flags & PF_DUMPCORE); + unsigned int x = 0; + + for (vma = find_vma(mm, start); vma; vma = vma->vm_next) { + if (end <= vma->vm_start) + break; + if (vma->vm_file && + vma->vm_file->f_dentry->d_inode->i_sb == sb) { + num_gh++; + } + } + + ghs = kcalloc((num_gh + 1), sizeof(struct gfs2_holder), GFP_KERNEL); + if (!ghs) { + if (!dumping) + up_read(&mm->mmap_sem); + return -ENOMEM; + } + + for (vma = find_vma(mm, start); vma; vma = vma->vm_next) { + if (end <= vma->vm_start) + break; + if (vma->vm_file) { + struct inode *inode = vma->vm_file->f_dentry->d_inode; + if (inode->i_sb == sb) + gfs2_holder_init(get_v2ip(inode)->i_gl, + vma2state(vma), 0, &ghs[x++]); + } + } + + if (!dumping) + up_read(&mm->mmap_sem); + + gfs2_assert(get_v2sdp(sb), x == num_gh); + + count = operation(file, buf, size, offset, num_gh, ghs); + + while (num_gh--) + gfs2_holder_uninit(&ghs[num_gh]); + kfree(ghs); + + return count; +} + +/** + * walk_vm - Walk the vmas associated with a buffer for read or write. + * If any of them are gfs2, pass the gfs2 inode down to the read/write + * worker function so that locks can be acquired in the correct order. + * @file: The file to read/write from/to + * @buf: The buffer to copy to/from + * @size: The amount of data requested + * @offset: The current file offset + * @operation: The read or write worker function + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t walk_vm(struct file *file, const char __user *buf, size_t size, + loff_t *offset, do_rw_t operation) +{ + struct gfs2_holder gh; + + if (current->mm) { + struct super_block *sb = file->f_dentry->d_inode->i_sb; + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long start = (unsigned long)buf; + unsigned long end = start + size; + int dumping = (current->flags & PF_DUMPCORE); + + if (!dumping) + down_read(&mm->mmap_sem); + + for (vma = find_vma(mm, start); vma; vma = vma->vm_next) { + if (end <= vma->vm_start) + break; + if (vma->vm_file && + vma->vm_file->f_dentry->d_inode->i_sb == sb) + goto do_locks; + } + + if (!dumping) + up_read(&mm->mmap_sem); + } + + return operation(file, buf, size, offset, 0, &gh); + +do_locks: + return walk_vm_hard(file, buf, size, offset, operation); +} + +static ssize_t do_jdata_read(struct file *file, char __user *buf, size_t size, + loff_t *offset) +{ + struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + ssize_t count = 0; + + if (*offset < 0) + return -EINVAL; + if (!access_ok(VERIFY_WRITE, buf, size)) + return -EFAULT; + + if (!(file->f_flags & O_LARGEFILE)) { + if (*offset >= MAX_NON_LFS) + return -EFBIG; + if (*offset + size > MAX_NON_LFS) + size = MAX_NON_LFS - *offset; + } + + count = gfs2_jdata_read(ip, buf, *offset, size, gfs2_copy2user); + + if (count > 0) + *offset += count; + + return count; +} + +/** + * do_read_direct - Read bytes from a file + * @file: The file to read from + * @buf: The buffer to copy into + * @size: The amount of data requested + * @offset: The current file offset + * @num_gh: The number of other locks we need to do the read + * @ghs: the locks we need plus one for our lock + * + * Outputs: Offset - updated according to number of bytes read + * + * Returns: The number of bytes read, errno on failure + */ + +static ssize_t do_read_direct(struct file *file, char __user *buf, size_t size, + loff_t *offset, unsigned int num_gh, + struct gfs2_holder *ghs) +{ + struct inode *inode = file->f_mapping->host; + struct gfs2_inode *ip = get_v2ip(inode); + unsigned int state = LM_ST_DEFERRED; + int flags = 0; + unsigned int x; + ssize_t count = 0; + int error; + + for (x = 0; x < num_gh; x++) + if (ghs[x].gh_gl == ip->i_gl) { + state = LM_ST_SHARED; + flags |= GL_LOCAL_EXCL; + break; + } + + gfs2_holder_init(ip->i_gl, state, flags, &ghs[num_gh]); + + error = gfs2_glock_nq_m(num_gh + 1, ghs); + if (error) + goto out; + + error = -EINVAL; + if (gfs2_is_jdata(ip)) + goto out_gunlock; + + if (gfs2_is_stuffed(ip)) { + size_t mask = bdev_hardsect_size(inode->i_sb->s_bdev) - 1; + + if (((*offset) & mask) || (((unsigned long)buf) & mask)) + goto out_gunlock; + + count = do_jdata_read(file, buf, size & ~mask, offset); + } else + count = generic_file_read(file, buf, size, offset); + + error = 0; + + out_gunlock: + gfs2_glock_dq_m(num_gh + 1, ghs); + + out: + gfs2_holder_uninit(&ghs[num_gh]); + + return (count) ? count : error; +} + +/** + * do_read_buf - Read bytes from a file + * @file: The file to read from + * @buf: The buffer to copy into + * @size: The amount of data requested + * @offset: The current file offset + * @num_gh: The number of other locks we need to do the read + * @ghs: the locks we need plus one for our lock + * + * Outputs: Offset - updated according to number of bytes read + * + * Returns: The number of bytes read, errno on failure + */ + +static ssize_t do_read_buf(struct file *file, char __user *buf, size_t size, + loff_t *offset, unsigned int num_gh, + struct gfs2_holder *ghs) +{ + struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + ssize_t count = 0; + int error; + + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &ghs[num_gh]); + + error = gfs2_glock_nq_m_atime(num_gh + 1, ghs); + if (error) + goto out; + + if (gfs2_is_jdata(ip)) + count = do_jdata_read(file, buf, size, offset); + else + count = generic_file_read(file, buf, size, offset); + + gfs2_glock_dq_m(num_gh + 1, ghs); + + out: + gfs2_holder_uninit(&ghs[num_gh]); + + return (count) ? count : error; +} + +/** + * gfs2_read - Read bytes from a file + * @file: The file to read from + * @buf: The buffer to copy into + * @size: The amount of data requested + * @offset: The current file offset + * + * Outputs: Offset - updated according to number of bytes read + * + * Returns: The number of bytes read, errno on failure + */ + +static ssize_t gfs2_read(struct file *file, char __user *buf, size_t size, + loff_t *offset) +{ + atomic_inc(&get_v2sdp(file->f_mapping->host->i_sb)->sd_ops_file); + + if (file->f_flags & O_DIRECT) + return walk_vm(file, buf, size, offset, do_read_direct); + else + return walk_vm(file, buf, size, offset, do_read_buf); +} + +/** + * grope_mapping - feel up a mapping that needs to be written + * @buf: the start of the memory to be written + * @size: the size of the memory to be written + * + * We do this after acquiring the locks on the mapping, + * but before starting the write transaction. We need to make + * sure that we don't cause recursive transactions if blocks + * need to be allocated to the file backing the mapping. + * + * Returns: errno + */ + +static int grope_mapping(const char __user *buf, size_t size) +{ + const char __user *stop = buf + size; + char c; + + while (buf < stop) { + if (copy_from_user(&c, buf, 1)) + return -EFAULT; + buf += PAGE_CACHE_SIZE; + buf = (const char __user *)PAGE_ALIGN((unsigned long)buf); + } + + return 0; +} + +/** + * do_write_direct_alloc - Write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The current file offset + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t do_write_direct_alloc(struct file *file, const char __user *buf, size_t size, + loff_t *offset) +{ + struct inode *inode = file->f_mapping->host; + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = NULL; + struct iovec local_iov = { .iov_base = buf, .iov_len = size }; + struct buffer_head *dibh; + unsigned int data_blocks, ind_blocks; + ssize_t count; + int error; + + gfs2_write_calc_reserv(ip, size, &data_blocks, &ind_blocks); + + al = gfs2_alloc_get(ip); + + error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto fail; + + error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto fail_gunlock_q; + + al->al_requested = data_blocks + ind_blocks; + + error = gfs2_inplace_reserve(ip); + if (error) + goto fail_gunlock_q; + + error = gfs2_trans_begin(sdp, + al->al_rgd->rd_ri.ri_length + ind_blocks + + RES_DINODE + RES_STATFS + RES_QUOTA, 0); + if (error) + goto fail_ipres; + + if ((ip->i_di.di_mode & (S_ISUID | S_ISGID)) && !capable(CAP_FSETID)) { + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + ip->i_di.di_mode &= (ip->i_di.di_mode & S_IXGRP) ? + (~(S_ISUID | S_ISGID)) : (~S_ISUID); + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + if (gfs2_is_stuffed(ip)) { + error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_sync, NULL); + if (error) + goto fail_end_trans; + } + + count = generic_file_write_nolock(file, &local_iov, 1, offset); + if (count < 0) { + error = count; + goto fail_end_trans; + } + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + if (ip->i_di.di_size < inode->i_size) + ip->i_di.di_size = inode->i_size; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + gfs2_trans_end(sdp); + + if (file->f_flags & O_SYNC) + gfs2_log_flush_glock(ip->i_gl); + + gfs2_inplace_release(ip); + gfs2_quota_unlock(ip); + gfs2_alloc_put(ip); + + if (file->f_mapping->nrpages) { + error = filemap_fdatawrite(file->f_mapping); + if (!error) + error = filemap_fdatawait(file->f_mapping); + } + if (error) + return error; + + return count; + + fail_end_trans: + gfs2_trans_end(sdp); + + fail_ipres: + gfs2_inplace_release(ip); + + fail_gunlock_q: + gfs2_quota_unlock(ip); + + fail: + gfs2_alloc_put(ip); + + return error; +} + +/** + * do_write_direct - Write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The current file offset + * @num_gh: The number of other locks we need to do the read + * @gh: the locks we need plus one for our lock + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t do_write_direct(struct file *file, const char __user *buf, size_t size, + loff_t *offset, unsigned int num_gh, + struct gfs2_holder *ghs) +{ + struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_file *fp = get_v2fp(file); + unsigned int state = LM_ST_DEFERRED; + int alloc_required; + unsigned int x; + size_t s; + ssize_t count = 0; + int error; + + if (test_bit(GFF_DID_DIRECT_ALLOC, &fp->f_flags)) + state = LM_ST_EXCLUSIVE; + else + for (x = 0; x < num_gh; x++) + if (ghs[x].gh_gl == ip->i_gl) { + state = LM_ST_EXCLUSIVE; + break; + } + + restart: + gfs2_holder_init(ip->i_gl, state, 0, &ghs[num_gh]); + + error = gfs2_glock_nq_m(num_gh + 1, ghs); + if (error) + goto out; + + error = -EINVAL; + if (gfs2_is_jdata(ip)) + goto out_gunlock; + + if (num_gh) { + error = grope_mapping(buf, size); + if (error) + goto out_gunlock; + } + + if (file->f_flags & O_APPEND) + *offset = ip->i_di.di_size; + + if (!(file->f_flags & O_LARGEFILE)) { + error = -EFBIG; + if (*offset >= MAX_NON_LFS) + goto out_gunlock; + if (*offset + size > MAX_NON_LFS) + size = MAX_NON_LFS - *offset; + } + + if (gfs2_is_stuffed(ip) || + *offset + size > ip->i_di.di_size || + ((ip->i_di.di_mode & (S_ISUID | S_ISGID)) && !capable(CAP_FSETID))) + alloc_required = 1; + else { + error = gfs2_write_alloc_required(ip, *offset, size, + &alloc_required); + if (error) + goto out_gunlock; + } + + if (alloc_required && state != LM_ST_EXCLUSIVE) { + gfs2_glock_dq_m(num_gh + 1, ghs); + gfs2_holder_uninit(&ghs[num_gh]); + state = LM_ST_EXCLUSIVE; + goto restart; + } + + if (alloc_required) { + set_bit(GFF_DID_DIRECT_ALLOC, &fp->f_flags); + + /* split large writes into smaller atomic transactions */ + while (size) { + s = gfs2_tune_get(sdp, gt_max_atomic_write); + if (s > size) + s = size; + + error = do_write_direct_alloc(file, buf, s, offset); + if (error < 0) + goto out_gunlock; + + buf += error; + size -= error; + count += error; + } + } else { + struct iovec local_iov = { .iov_base = buf, .iov_len = size }; + struct gfs2_holder t_gh; + + clear_bit(GFF_DID_DIRECT_ALLOC, &fp->f_flags); + + error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, + GL_NEVER_RECURSE, &t_gh); + if (error) + goto out_gunlock; + + count = generic_file_write_nolock(file, &local_iov, 1, offset); + + gfs2_glock_dq_uninit(&t_gh); + } + + error = 0; + + out_gunlock: + gfs2_glock_dq_m(num_gh + 1, ghs); + + out: + gfs2_holder_uninit(&ghs[num_gh]); + + return (count) ? count : error; +} + +/** + * do_do_write_buf - Write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The current file offset + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t do_do_write_buf(struct file *file, const char __user *buf, size_t size, + loff_t *offset) +{ + struct inode *inode = file->f_mapping->host; + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = NULL; + struct buffer_head *dibh; + unsigned int data_blocks, ind_blocks; + int alloc_required, journaled; + ssize_t count; + int error; + + journaled = gfs2_is_jdata(ip); + + gfs2_write_calc_reserv(ip, size, &data_blocks, &ind_blocks); + + error = gfs2_write_alloc_required(ip, *offset, size, &alloc_required); + if (error) + return error; + + if (alloc_required) { + al = gfs2_alloc_get(ip); + + error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto fail; + + error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto fail_gunlock_q; + + al->al_requested = data_blocks + ind_blocks; + + error = gfs2_inplace_reserve(ip); + if (error) + goto fail_gunlock_q; + + error = gfs2_trans_begin(sdp, + al->al_rgd->rd_ri.ri_length + + ind_blocks + + ((journaled) ? data_blocks : 0) + + RES_DINODE + RES_STATFS + RES_QUOTA, + 0); + if (error) + goto fail_ipres; + } else { + error = gfs2_trans_begin(sdp, + ((journaled) ? data_blocks : 0) + + RES_DINODE, + 0); + if (error) + goto fail_ipres; + } + + if ((ip->i_di.di_mode & (S_ISUID | S_ISGID)) && !capable(CAP_FSETID)) { + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + ip->i_di.di_mode &= (ip->i_di.di_mode & S_IXGRP) ? + (~(S_ISUID | S_ISGID)) : (~S_ISUID); + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + if (journaled) { + count = gfs2_jdata_write(ip, buf, *offset, size, + gfs2_copy_from_user); + if (count < 0) { + error = count; + goto fail_end_trans; + } + + *offset += count; + } else { + struct iovec local_iov = { .iov_base = buf, .iov_len = size }; + + count = generic_file_write_nolock(file, &local_iov, 1, offset); + if (count < 0) { + error = count; + goto fail_end_trans; + } + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + if (ip->i_di.di_size < inode->i_size) + ip->i_di.di_size = inode->i_size; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs2_trans_end(sdp); + + if (file->f_flags & O_SYNC || IS_SYNC(inode)) { + gfs2_log_flush_glock(ip->i_gl); + error = filemap_fdatawrite(file->f_mapping); + if (error == 0) + error = filemap_fdatawait(file->f_mapping); + if (error) + goto fail_ipres; + } + + if (alloc_required) { + gfs2_assert_warn(sdp, count != size || + al->al_alloced); + gfs2_inplace_release(ip); + gfs2_quota_unlock(ip); + gfs2_alloc_put(ip); + } + + return count; + + fail_end_trans: + gfs2_trans_end(sdp); + + fail_ipres: + if (alloc_required) + gfs2_inplace_release(ip); + + fail_gunlock_q: + if (alloc_required) + gfs2_quota_unlock(ip); + + fail: + if (alloc_required) + gfs2_alloc_put(ip); + + return error; +} + +/** + * do_write_buf - Write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The current file offset + * @num_gh: The number of other locks we need to do the read + * @gh: the locks we need plus one for our lock + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t do_write_buf(struct file *file, const char __user *buf, size_t size, + loff_t *offset, unsigned int num_gh, + struct gfs2_holder *ghs) +{ + struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_sbd *sdp = ip->i_sbd; + size_t s; + ssize_t count = 0; + int error; + + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[num_gh]); + + error = gfs2_glock_nq_m(num_gh + 1, ghs); + if (error) + goto out; + + if (num_gh) { + error = grope_mapping(buf, size); + if (error) + goto out_gunlock; + } + + if (file->f_flags & O_APPEND) + *offset = ip->i_di.di_size; + + if (!(file->f_flags & O_LARGEFILE)) { + error = -EFBIG; + if (*offset >= MAX_NON_LFS) + goto out_gunlock; + if (*offset + size > MAX_NON_LFS) + size = MAX_NON_LFS - *offset; + } + + /* split large writes into smaller atomic transactions */ + while (size) { + s = gfs2_tune_get(sdp, gt_max_atomic_write); + if (s > size) + s = size; + + error = do_do_write_buf(file, buf, s, offset); + if (error < 0) + goto out_gunlock; + + buf += error; + size -= error; + count += error; + } + + error = 0; + + out_gunlock: + gfs2_glock_dq_m(num_gh + 1, ghs); + + out: + gfs2_holder_uninit(&ghs[num_gh]); + + return (count) ? count : error; +} + +/** + * gfs2_write - Write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The current file offset + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t gfs2_write(struct file *file, const char __user *buf, + size_t size, loff_t *offset) +{ + struct inode *inode = file->f_mapping->host; + ssize_t count; + + atomic_inc(&get_v2sdp(inode->i_sb)->sd_ops_file); + + if (*offset < 0) + return -EINVAL; + if (!access_ok(VERIFY_READ, buf, size)) + return -EFAULT; + + mutex_lock(&inode->i_mutex); + if (file->f_flags & O_DIRECT) + count = walk_vm(file, buf, size, offset, + do_write_direct); + else + count = walk_vm(file, buf, size, offset, do_write_buf); + mutex_unlock(&inode->i_mutex); + + return count; +} + +/** + * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() + * @opaque: opaque data used by the function + * @name: the name of the directory entry + * @length: the length of the name + * @offset: the entry's offset in the directory + * @inum: the inode number the entry points to + * @type: the type of inode the entry points to + * + * Returns: 0 on success, 1 if buffer full + */ + +static int filldir_reg_func(void *opaque, const char *name, unsigned int length, + uint64_t offset, struct gfs2_inum *inum, + unsigned int type) +{ + struct filldir_reg *fdr = (struct filldir_reg *)opaque; + struct gfs2_sbd *sdp = fdr->fdr_sbd; + int error; + + error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset, + inum->no_formal_ino, type); + if (error) + return 1; + + if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) { + gfs2_glock_prefetch_num(sdp, + inum->no_addr, &gfs2_inode_glops, + LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY); + gfs2_glock_prefetch_num(sdp, + inum->no_addr, &gfs2_iopen_glops, + LM_ST_SHARED, LM_FLAG_TRY); + } + + return 0; +} + +/** + * readdir_reg - Read directory entries from a directory + * @file: The directory to read from + * @dirent: Buffer for dirents + * @filldir: Function used to do the copying + * + * Returns: errno + */ + +static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) +{ + struct gfs2_inode *dip = get_v2ip(file->f_mapping->host); + struct filldir_reg fdr; + struct gfs2_holder d_gh; + uint64_t offset = file->f_pos; + int error; + + fdr.fdr_sbd = dip->i_sbd; + fdr.fdr_prefetch = 1; + fdr.fdr_filldir = filldir; + fdr.fdr_opaque = dirent; + + gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh); + error = gfs2_glock_nq_atime(&d_gh); + if (error) { + gfs2_holder_uninit(&d_gh); + return error; + } + + error = gfs2_dir_read(dip, &offset, &fdr, filldir_reg_func); + + gfs2_glock_dq_uninit(&d_gh); + + file->f_pos = offset; + + return error; +} + +/** + * filldir_bad_func - Report a directory entry to the caller of gfs2_dir_read() + * @opaque: opaque data used by the function + * @name: the name of the directory entry + * @length: the length of the name + * @offset: the entry's offset in the directory + * @inum: the inode number the entry points to + * @type: the type of inode the entry points to + * + * For supporting NFS. + * + * Returns: 0 on success, 1 if buffer full + */ + +static int filldir_bad_func(void *opaque, const char *name, unsigned int length, + uint64_t offset, struct gfs2_inum *inum, + unsigned int type) +{ + struct filldir_bad *fdb = (struct filldir_bad *)opaque; + struct gfs2_sbd *sdp = fdb->fdb_sbd; + struct filldir_bad_entry *fbe; + + if (fdb->fdb_entry_off == fdb->fdb_entry_num || + fdb->fdb_name_off + length > fdb->fdb_name_size) + return 1; + + fbe = &fdb->fdb_entry[fdb->fdb_entry_off]; + fbe->fbe_name = fdb->fdb_name + fdb->fdb_name_off; + memcpy(fbe->fbe_name, name, length); + fbe->fbe_length = length; + fbe->fbe_offset = offset; + fbe->fbe_inum = *inum; + fbe->fbe_type = type; + + fdb->fdb_entry_off++; + fdb->fdb_name_off += length; + + if (!(length == 1 && *name == '.')) { + gfs2_glock_prefetch_num(sdp, + inum->no_addr, &gfs2_inode_glops, + LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY); + gfs2_glock_prefetch_num(sdp, + inum->no_addr, &gfs2_iopen_glops, + LM_ST_SHARED, LM_FLAG_TRY); + } + + return 0; +} + +/** + * readdir_bad - Read directory entries from a directory + * @file: The directory to read from + * @dirent: Buffer for dirents + * @filldir: Function used to do the copying + * + * For supporting NFS. + * + * Returns: errno + */ + +static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) +{ + struct gfs2_inode *dip = get_v2ip(file->f_mapping->host); + struct gfs2_sbd *sdp = dip->i_sbd; + struct filldir_reg fdr; + unsigned int entries, size; + struct filldir_bad *fdb; + struct gfs2_holder d_gh; + uint64_t offset = file->f_pos; + unsigned int x; + struct filldir_bad_entry *fbe; + int error; + + entries = gfs2_tune_get(sdp, gt_entries_per_readdir); + size = sizeof(struct filldir_bad) + + entries * (sizeof(struct filldir_bad_entry) + GFS2_FAST_NAME_SIZE); + + fdb = kzalloc(size, GFP_KERNEL); + if (!fdb) + return -ENOMEM; + + fdb->fdb_sbd = sdp; + fdb->fdb_entry = (struct filldir_bad_entry *)(fdb + 1); + fdb->fdb_entry_num = entries; + fdb->fdb_name = ((char *)fdb) + sizeof(struct filldir_bad) + + entries * sizeof(struct filldir_bad_entry); + fdb->fdb_name_size = entries * GFS2_FAST_NAME_SIZE; + + gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh); + error = gfs2_glock_nq_atime(&d_gh); + if (error) { + gfs2_holder_uninit(&d_gh); + goto out; + } + + error = gfs2_dir_read(dip, &offset, fdb, filldir_bad_func); + + gfs2_glock_dq_uninit(&d_gh); + + fdr.fdr_sbd = sdp; + fdr.fdr_prefetch = 0; + fdr.fdr_filldir = filldir; + fdr.fdr_opaque = dirent; + + for (x = 0; x < fdb->fdb_entry_off; x++) { + fbe = &fdb->fdb_entry[x]; + + error = filldir_reg_func(&fdr, + fbe->fbe_name, fbe->fbe_length, + fbe->fbe_offset, + &fbe->fbe_inum, fbe->fbe_type); + if (error) { + file->f_pos = fbe->fbe_offset; + error = 0; + goto out; + } + } + + file->f_pos = offset; + + out: + kfree(fdb); + + return error; +} + +/** + * gfs2_readdir - Read directory entries from a directory + * @file: The directory to read from + * @dirent: Buffer for dirents + * @filldir: Function used to do the copying + * + * Returns: errno + */ + +static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + int error; + + atomic_inc(&get_v2sdp(file->f_mapping->host->i_sb)->sd_ops_file); + + if (strcmp(current->comm, "nfsd") != 0) + error = readdir_reg(file, dirent, filldir); + else + error = readdir_bad(file, dirent, filldir); + + return error; +} + +static int gfs2_ioctl_flags(struct gfs2_inode *ip, unsigned int cmd, unsigned long arg) +{ + unsigned int lmode = (cmd == GFS2_IOCTL_SETFLAGS) ? LM_ST_EXCLUSIVE : LM_ST_SHARED; + struct buffer_head *dibh; + struct gfs2_holder i_gh; + int error; + __u32 flags = 0, change; + + if (cmd == GFS2_IOCTL_SETFLAGS) { + error = get_user(flags, (__u32 __user *)arg); + if (error) + return -EFAULT; + } + + error = gfs2_glock_nq_init(ip->i_gl, lmode, 0, &i_gh); + if (error) + return error; + + if (cmd == GFS2_IOCTL_SETFLAGS) { + change = flags ^ ip->i_di.di_flags; + error = -EPERM; + if (change & (GFS2_DIF_IMMUTABLE|GFS2_DIF_APPENDONLY)) { + if (!capable(CAP_LINUX_IMMUTABLE)) + goto out; + } + error = -EINVAL; + if (flags & (GFS2_DIF_JDATA|GFS2_DIF_DIRECTIO)) { + if (!S_ISREG(ip->i_di.di_mode)) + goto out; + /* FIXME: Would be nice not to require the following test */ + if ((flags & GFS2_DIF_JDATA) && ip->i_di.di_size) + goto out; + } + if (flags & (GFS2_DIF_INHERIT_JDATA|GFS2_DIF_INHERIT_DIRECTIO)) { + if (!S_ISDIR(ip->i_di.di_mode)) + goto out; + } + + error = gfs2_trans_begin(ip->i_sbd, RES_DINODE, 0); + if (error) + goto out; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out_trans_end; + + ip->i_di.di_flags = flags; + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + + brelse(dibh); + +out_trans_end: + gfs2_trans_end(ip->i_sbd); + } else { + flags = ip->i_di.di_flags; + } +out: + gfs2_glock_dq_uninit(&i_gh); + if (cmd == GFS2_IOCTL_GETFLAGS) { + if (put_user(flags, (__u32 __user *)arg)) + return -EFAULT; + } + return error; +} + +/** + * gfs2_ioctl - do an ioctl on a file + * @inode: the inode + * @file: the file pointer + * @cmd: the ioctl command + * @arg: the argument + * + * Returns: errno + */ + +static int gfs2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct gfs2_inode *ip = get_v2ip(inode); + + atomic_inc(&ip->i_sbd->sd_ops_file); + + switch (cmd) { + case GFS2_IOCTL_IDENTIFY: { + unsigned int x = GFS2_MAGIC; + if (copy_to_user((unsigned int __user *)arg, &x, sizeof(unsigned int))) + return -EFAULT; + return 0; + + case GFS2_IOCTL_SETFLAGS: + case GFS2_IOCTL_GETFLAGS: + return gfs2_ioctl_flags(ip, cmd, arg); + } + + default: + return -ENOTTY; + } +} + +/** + * gfs2_mmap - + * @file: The file to map + * @vma: The VMA which described the mapping + * + * Returns: 0 or error code + */ + +static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_holder i_gh; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_file); + + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh); + error = gfs2_glock_nq_atime(&i_gh); + if (error) { + gfs2_holder_uninit(&i_gh); + return error; + } + + if (gfs2_is_jdata(ip)) { + if (vma->vm_flags & VM_MAYSHARE) + error = -EOPNOTSUPP; + else + vma->vm_ops = &gfs2_vm_ops_private; + } else { + /* This is VM_MAYWRITE instead of VM_WRITE because a call + to mprotect() can turn on VM_WRITE later. */ + + if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) == + (VM_MAYSHARE | VM_MAYWRITE)) + vma->vm_ops = &gfs2_vm_ops_sharewrite; + else + vma->vm_ops = &gfs2_vm_ops_private; + } + + gfs2_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs2_open - open a file + * @inode: the inode to open + * @file: the struct file for this opening + * + * Returns: errno + */ + +static int gfs2_open(struct inode *inode, struct file *file) +{ + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_holder i_gh; + struct gfs2_file *fp; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_file); + + fp = kzalloc(sizeof(struct gfs2_file), GFP_KERNEL); + if (!fp) + return -ENOMEM; + + init_MUTEX(&fp->f_fl_mutex); + + fp->f_inode = ip; + fp->f_vfile = file; + + gfs2_assert_warn(ip->i_sbd, !get_v2fp(file)); + set_v2fp(file, fp); + + if (S_ISREG(ip->i_di.di_mode)) { + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, + &i_gh); + if (error) + goto fail; + + if (!(file->f_flags & O_LARGEFILE) && + ip->i_di.di_size > MAX_NON_LFS) { + error = -EFBIG; + goto fail_gunlock; + } + + /* Listen to the Direct I/O flag */ + + if (ip->i_di.di_flags & GFS2_DIF_DIRECTIO) + file->f_flags |= O_DIRECT; + + /* Don't let the user open O_DIRECT on a jdata file */ + + if ((file->f_flags & O_DIRECT) && gfs2_is_jdata(ip)) { + error = -EINVAL; + goto fail_gunlock; + } + + gfs2_glock_dq_uninit(&i_gh); + } + + return 0; + + fail_gunlock: + gfs2_glock_dq_uninit(&i_gh); + + fail: + set_v2fp(file, NULL); + kfree(fp); + + return error; +} + +/** + * gfs2_close - called to close a struct file + * @inode: the inode the struct file belongs to + * @file: the struct file being closed + * + * Returns: errno + */ + +static int gfs2_close(struct inode *inode, struct file *file) +{ + struct gfs2_sbd *sdp = get_v2sdp(inode->i_sb); + struct gfs2_file *fp; + + atomic_inc(&sdp->sd_ops_file); + + fp = get_v2fp(file); + set_v2fp(file, NULL); + + if (gfs2_assert_warn(sdp, fp)) + return -EIO; + + kfree(fp); + + return 0; +} + +/** + * gfs2_fsync - sync the dirty data for a file (across the cluster) + * @file: the file that points to the dentry (we ignore this) + * @dentry: the dentry that points to the inode to sync + * + * Returns: errno + */ + +static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + + atomic_inc(&ip->i_sbd->sd_ops_file); + gfs2_log_flush_glock(ip->i_gl); + + return 0; +} + +/** + * gfs2_lock - acquire/release a posix lock on a file + * @file: the file pointer + * @cmd: either modify or retrieve lock state, possibly wait + * @fl: type and range of lock + * + * Returns: errno + */ + +static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) +{ + struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_sbd *sdp = ip->i_sbd; + struct lm_lockname name = + { .ln_number = ip->i_num.no_addr, + .ln_type = LM_TYPE_PLOCK }; + + atomic_inc(&sdp->sd_ops_file); + + if (!(fl->fl_flags & FL_POSIX)) + return -ENOLCK; + if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + return -ENOLCK; + + if (sdp->sd_args.ar_localflocks) { + if (IS_GETLK(cmd)) { + struct file_lock *tmp; + lock_kernel(); + tmp = posix_test_lock(file, fl); + fl->fl_type = F_UNLCK; + if (tmp) + memcpy(fl, tmp, sizeof(struct file_lock)); + unlock_kernel(); + return 0; + } else { + int error; + lock_kernel(); + error = posix_lock_file_wait(file, fl); + unlock_kernel(); + return error; + } + } + + if (IS_GETLK(cmd)) + return gfs2_lm_plock_get(sdp, &name, file, fl); + else if (fl->fl_type == F_UNLCK) + return gfs2_lm_punlock(sdp, &name, file, fl); + else + return gfs2_lm_plock(sdp, &name, file, cmd, fl); +} + +/** + * gfs2_sendfile - Send bytes to a file or socket + * @in_file: The file to read from + * @out_file: The file to write to + * @count: The amount of data + * @offset: The beginning file offset + * + * Outputs: offset - updated according to number of bytes read + * + * Returns: The number of bytes sent, errno on failure + */ + +static ssize_t gfs2_sendfile(struct file *in_file, loff_t *offset, size_t count, + read_actor_t actor, void *target) +{ + struct gfs2_inode *ip = get_v2ip(in_file->f_mapping->host); + struct gfs2_holder gh; + ssize_t retval; + + atomic_inc(&ip->i_sbd->sd_ops_file); + + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); + + retval = gfs2_glock_nq_atime(&gh); + if (retval) + goto out; + + if (gfs2_is_jdata(ip)) + retval = -EOPNOTSUPP; + else + retval = generic_file_sendfile(in_file, offset, count, actor, + target); + + gfs2_glock_dq(&gh); + + out: + gfs2_holder_uninit(&gh); + + return retval; +} + +static int do_flock(struct file *file, int cmd, struct file_lock *fl) +{ + struct gfs2_file *fp = get_v2fp(file); + struct gfs2_holder *fl_gh = &fp->f_fl_gh; + struct gfs2_inode *ip = fp->f_inode; + struct gfs2_glock *gl; + unsigned int state; + int flags; + int error = 0; + + state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED; + flags = ((IS_SETLKW(cmd)) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE; + + down(&fp->f_fl_mutex); + + gl = fl_gh->gh_gl; + if (gl) { + if (fl_gh->gh_state == state) + goto out; + gfs2_glock_hold(gl); + flock_lock_file_wait(file, + &(struct file_lock){.fl_type = F_UNLCK}); + gfs2_glock_dq_uninit(fl_gh); + } else { + error = gfs2_glock_get(ip->i_sbd, + ip->i_num.no_addr, &gfs2_flock_glops, + CREATE, &gl); + if (error) + goto out; + } + + gfs2_holder_init(gl, state, flags, fl_gh); + gfs2_glock_put(gl); + + error = gfs2_glock_nq(fl_gh); + if (error) { + gfs2_holder_uninit(fl_gh); + if (error == GLR_TRYFAILED) + error = -EAGAIN; + } else { + error = flock_lock_file_wait(file, fl); + gfs2_assert_warn(ip->i_sbd, !error); + } + + out: + up(&fp->f_fl_mutex); + + return error; +} + +static void do_unflock(struct file *file, struct file_lock *fl) +{ + struct gfs2_file *fp = get_v2fp(file); + struct gfs2_holder *fl_gh = &fp->f_fl_gh; + + down(&fp->f_fl_mutex); + flock_lock_file_wait(file, fl); + if (fl_gh->gh_gl) + gfs2_glock_dq_uninit(fl_gh); + up(&fp->f_fl_mutex); +} + +/** + * gfs2_flock - acquire/release a flock lock on a file + * @file: the file pointer + * @cmd: either modify or retrieve lock state, possibly wait + * @fl: type and range of lock + * + * Returns: errno + */ + +static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) +{ + struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_sbd *sdp = ip->i_sbd; + + atomic_inc(&ip->i_sbd->sd_ops_file); + + if (!(fl->fl_flags & FL_FLOCK)) + return -ENOLCK; + if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + return -ENOLCK; + + if (sdp->sd_args.ar_localflocks) + return flock_lock_file_wait(file, fl); + + if (fl->fl_type == F_UNLCK) { + do_unflock(file, fl); + return 0; + } else + return do_flock(file, cmd, fl); +} + +struct file_operations gfs2_file_fops = { + .llseek = gfs2_llseek, + .read = gfs2_read, + .write = gfs2_write, + .ioctl = gfs2_ioctl, + .mmap = gfs2_mmap, + .open = gfs2_open, + .release = gfs2_close, + .fsync = gfs2_fsync, + .lock = gfs2_lock, + .sendfile = gfs2_sendfile, + .flock = gfs2_flock, +}; + +struct file_operations gfs2_dir_fops = { + .readdir = gfs2_readdir, + .ioctl = gfs2_ioctl, + .open = gfs2_open, + .release = gfs2_close, + .fsync = gfs2_fsync, + .lock = gfs2_lock, + .flock = gfs2_flock, +}; + diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h new file mode 100644 index 000000000000..95123d7bbcdf --- /dev/null +++ b/fs/gfs2/ops_file.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __OPS_FILE_DOT_H__ +#define __OPS_FILE_DOT_H__ + +extern struct file_operations gfs2_file_fops; +extern struct file_operations gfs2_dir_fops; + +#endif /* __OPS_FILE_DOT_H__ */ diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c new file mode 100644 index 000000000000..c61a80c439a6 --- /dev/null +++ b/fs/gfs2/ops_fstype.c @@ -0,0 +1,879 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "daemon.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "lm.h" +#include "mount.h" +#include "ops_export.h" +#include "ops_fstype.h" +#include "ops_super.h" +#include "recovery.h" +#include "rgrp.h" +#include "super.h" +#include "unlinked.h" +#include "sys.h" + +#define DO 0 +#define UNDO 1 + +static struct gfs2_sbd *init_sbd(struct super_block *sb) +{ + struct gfs2_sbd *sdp; + unsigned int x; + + sdp = vmalloc(sizeof(struct gfs2_sbd)); + if (!sdp) + return NULL; + + memset(sdp, 0, sizeof(struct gfs2_sbd)); + + set_v2sdp(sb, sdp); + sdp->sd_vfs = sb; + + gfs2_tune_init(&sdp->sd_tune); + + for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { + sdp->sd_gl_hash[x].hb_lock = RW_LOCK_UNLOCKED; + INIT_LIST_HEAD(&sdp->sd_gl_hash[x].hb_list); + } + INIT_LIST_HEAD(&sdp->sd_reclaim_list); + spin_lock_init(&sdp->sd_reclaim_lock); + init_waitqueue_head(&sdp->sd_reclaim_wq); + init_MUTEX(&sdp->sd_invalidate_inodes_mutex); + + init_MUTEX(&sdp->sd_inum_mutex); + spin_lock_init(&sdp->sd_statfs_spin); + init_MUTEX(&sdp->sd_statfs_mutex); + + spin_lock_init(&sdp->sd_rindex_spin); + init_MUTEX(&sdp->sd_rindex_mutex); + INIT_LIST_HEAD(&sdp->sd_rindex_list); + INIT_LIST_HEAD(&sdp->sd_rindex_mru_list); + INIT_LIST_HEAD(&sdp->sd_rindex_recent_list); + + INIT_LIST_HEAD(&sdp->sd_jindex_list); + spin_lock_init(&sdp->sd_jindex_spin); + init_MUTEX(&sdp->sd_jindex_mutex); + + INIT_LIST_HEAD(&sdp->sd_unlinked_list); + spin_lock_init(&sdp->sd_unlinked_spin); + init_MUTEX(&sdp->sd_unlinked_mutex); + + INIT_LIST_HEAD(&sdp->sd_quota_list); + spin_lock_init(&sdp->sd_quota_spin); + init_MUTEX(&sdp->sd_quota_mutex); + + spin_lock_init(&sdp->sd_log_lock); + init_waitqueue_head(&sdp->sd_log_trans_wq); + init_waitqueue_head(&sdp->sd_log_flush_wq); + + INIT_LIST_HEAD(&sdp->sd_log_le_gl); + INIT_LIST_HEAD(&sdp->sd_log_le_buf); + INIT_LIST_HEAD(&sdp->sd_log_le_revoke); + INIT_LIST_HEAD(&sdp->sd_log_le_rg); + INIT_LIST_HEAD(&sdp->sd_log_le_databuf); + + INIT_LIST_HEAD(&sdp->sd_log_blks_list); + init_waitqueue_head(&sdp->sd_log_blks_wait); + + INIT_LIST_HEAD(&sdp->sd_ail1_list); + INIT_LIST_HEAD(&sdp->sd_ail2_list); + + init_MUTEX(&sdp->sd_log_flush_lock); + INIT_LIST_HEAD(&sdp->sd_log_flush_list); + + INIT_LIST_HEAD(&sdp->sd_revoke_list); + + init_MUTEX(&sdp->sd_freeze_lock); + + return sdp; +} + +static void init_vfs(struct gfs2_sbd *sdp) +{ + struct super_block *sb = sdp->sd_vfs; + + sb->s_magic = GFS2_MAGIC; + sb->s_op = &gfs2_super_ops; + sb->s_export_op = &gfs2_export_ops; + sb->s_maxbytes = MAX_LFS_FILESIZE; + + if (sb->s_flags & (MS_NOATIME | MS_NODIRATIME)) + set_bit(SDF_NOATIME, &sdp->sd_flags); + + /* Don't let the VFS update atimes. GFS2 handles this itself. */ + sb->s_flags |= MS_NOATIME | MS_NODIRATIME; + + /* Set up the buffer cache and fill in some fake block size values + to allow us to read-in the on-disk superblock. */ + sdp->sd_sb.sb_bsize = sb_min_blocksize(sb, GFS2_BASIC_BLOCK); + sdp->sd_sb.sb_bsize_shift = sb->s_blocksize_bits; + sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT; + sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; +} + +static int init_names(struct gfs2_sbd *sdp, int silent) +{ + struct gfs2_sb *sb = NULL; + char *proto, *table; + int error = 0; + + proto = sdp->sd_args.ar_lockproto; + table = sdp->sd_args.ar_locktable; + + /* Try to autodetect */ + + if (!proto[0] || !table[0]) { + struct buffer_head *bh; + bh = sb_getblk(sdp->sd_vfs, + GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift); + lock_buffer(bh); + clear_buffer_uptodate(bh); + clear_buffer_dirty(bh); + unlock_buffer(bh); + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + + if (!buffer_uptodate(bh)) { + brelse(bh); + return -EIO; + } + + sb = kmalloc(sizeof(struct gfs2_sb), GFP_KERNEL); + if (!sb) { + brelse(bh); + return -ENOMEM; + } + gfs2_sb_in(sb, bh->b_data); + brelse(bh); + + error = gfs2_check_sb(sdp, sb, silent); + if (error) + goto out; + + if (!proto[0]) + proto = sb->sb_lockproto; + if (!table[0]) + table = sb->sb_locktable; + } + + if (!table[0]) + table = sdp->sd_vfs->s_id; + + snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto); + snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table); + + out: + kfree(sb); + + return error; +} + +static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, + int undo) +{ + struct task_struct *p; + int error = 0; + + if (undo) + goto fail_trans; + + p = kthread_run(gfs2_scand, sdp, "gfs2_scand"); + error = IS_ERR(p); + if (error) { + fs_err(sdp, "can't start scand thread: %d\n", error); + return error; + } + sdp->sd_scand_process = p; + + for (sdp->sd_glockd_num = 0; + sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd; + sdp->sd_glockd_num++) { + p = kthread_run(gfs2_glockd, sdp, "gfs2_glockd"); + error = IS_ERR(p); + if (error) { + fs_err(sdp, "can't start glockd thread: %d\n", error); + goto fail; + } + sdp->sd_glockd_process[sdp->sd_glockd_num] = p; + } + + error = gfs2_glock_nq_num(sdp, + GFS2_MOUNT_LOCK, &gfs2_nondisk_glops, + LM_ST_EXCLUSIVE, LM_FLAG_NOEXP | GL_NOCACHE, + mount_gh); + if (error) { + fs_err(sdp, "can't acquire mount glock: %d\n", error); + goto fail; + } + + error = gfs2_glock_nq_num(sdp, + GFS2_LIVE_LOCK, &gfs2_nondisk_glops, + LM_ST_SHARED, + LM_FLAG_NOEXP | GL_EXACT | GL_NEVER_RECURSE, + &sdp->sd_live_gh); + if (error) { + fs_err(sdp, "can't acquire live glock: %d\n", error); + goto fail_mount; + } + + error = gfs2_glock_get(sdp, GFS2_RENAME_LOCK, &gfs2_nondisk_glops, + CREATE, &sdp->sd_rename_gl); + if (error) { + fs_err(sdp, "can't create rename glock: %d\n", error); + goto fail_live; + } + + error = gfs2_glock_get(sdp, GFS2_TRANS_LOCK, &gfs2_trans_glops, + CREATE, &sdp->sd_trans_gl); + if (error) { + fs_err(sdp, "can't create transaction glock: %d\n", error); + goto fail_rename; + } + set_bit(GLF_STICKY, &sdp->sd_trans_gl->gl_flags); + + return 0; + + fail_trans: + gfs2_glock_put(sdp->sd_trans_gl); + + fail_rename: + gfs2_glock_put(sdp->sd_rename_gl); + + fail_live: + gfs2_glock_dq_uninit(&sdp->sd_live_gh); + + fail_mount: + gfs2_glock_dq_uninit(mount_gh); + + fail: + while (sdp->sd_glockd_num--) + kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]); + + kthread_stop(sdp->sd_scand_process); + + return error; +} + +static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) +{ + struct super_block *sb = sdp->sd_vfs; + struct gfs2_holder sb_gh; + int error = 0; + + if (undo) { + gfs2_inode_put(sdp->sd_master_dir); + return 0; + } + + error = gfs2_glock_nq_num(sdp, + GFS2_SB_LOCK, &gfs2_meta_glops, + LM_ST_SHARED, 0, &sb_gh); + if (error) { + fs_err(sdp, "can't acquire superblock glock: %d\n", error); + return error; + } + + error = gfs2_read_sb(sdp, sb_gh.gh_gl, silent); + if (error) { + fs_err(sdp, "can't read superblock: %d\n", error); + goto out; + } + + /* Set up the buffer cache and SB for real */ + error = -EINVAL; + if (sdp->sd_sb.sb_bsize < bdev_hardsect_size(sb->s_bdev)) { + fs_err(sdp, "FS block size (%u) is too small for device " + "block size (%u)\n", + sdp->sd_sb.sb_bsize, bdev_hardsect_size(sb->s_bdev)); + goto out; + } + if (sdp->sd_sb.sb_bsize > PAGE_SIZE) { + fs_err(sdp, "FS block size (%u) is too big for machine " + "page size (%u)\n", + sdp->sd_sb.sb_bsize, (unsigned int)PAGE_SIZE); + goto out; + } + + /* Get rid of buffers from the original block size */ + sb_gh.gh_gl->gl_ops->go_inval(sb_gh.gh_gl, DIO_METADATA | DIO_DATA); + sb_gh.gh_gl->gl_aspace->i_blkbits = sdp->sd_sb.sb_bsize_shift; + + sb_set_blocksize(sb, sdp->sd_sb.sb_bsize); + + error = gfs2_lookup_master_dir(sdp); + if (error) + fs_err(sdp, "can't read in master directory: %d\n", error); + + out: + gfs2_glock_dq_uninit(&sb_gh); + + return error; +} + +static int init_journal(struct gfs2_sbd *sdp, int undo) +{ + struct gfs2_holder ji_gh; + struct task_struct *p; + int jindex = 1; + int error = 0; + + if (undo) { + jindex = 0; + goto fail_recoverd; + } + + error = gfs2_lookup_simple(sdp->sd_master_dir, "jindex", + &sdp->sd_jindex); + if (error) { + fs_err(sdp, "can't lookup journal index: %d\n", error); + return error; + } + set_bit(GLF_STICKY, &sdp->sd_jindex->i_gl->gl_flags); + + /* Load in the journal index special file */ + + error = gfs2_jindex_hold(sdp, &ji_gh); + if (error) { + fs_err(sdp, "can't read journal index: %d\n", error); + goto fail; + } + + error = -EINVAL; + if (!gfs2_jindex_size(sdp)) { + fs_err(sdp, "no journals!\n"); + goto fail_jindex; + } + + if (sdp->sd_args.ar_spectator) { + sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0); + sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks; + } else { + if (sdp->sd_lockstruct.ls_jid >= gfs2_jindex_size(sdp)) { + fs_err(sdp, "can't mount journal #%u\n", + sdp->sd_lockstruct.ls_jid); + fs_err(sdp, "there are only %u journals (0 - %u)\n", + gfs2_jindex_size(sdp), + gfs2_jindex_size(sdp) - 1); + goto fail_jindex; + } + sdp->sd_jdesc = gfs2_jdesc_find(sdp, sdp->sd_lockstruct.ls_jid); + + error = gfs2_glock_nq_num(sdp, + sdp->sd_lockstruct.ls_jid, + &gfs2_journal_glops, + LM_ST_EXCLUSIVE, LM_FLAG_NOEXP, + &sdp->sd_journal_gh); + if (error) { + fs_err(sdp, "can't acquire journal glock: %d\n", error); + goto fail_jindex; + } + + error = gfs2_glock_nq_init(sdp->sd_jdesc->jd_inode->i_gl, + LM_ST_SHARED, + LM_FLAG_NOEXP | GL_EXACT, + &sdp->sd_jinode_gh); + if (error) { + fs_err(sdp, "can't acquire journal inode glock: %d\n", + error); + goto fail_journal_gh; + } + + error = gfs2_jdesc_check(sdp->sd_jdesc); + if (error) { + fs_err(sdp, "my journal (%u) is bad: %d\n", + sdp->sd_jdesc->jd_jid, error); + goto fail_jinode_gh; + } + sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks; + } + + if (sdp->sd_lockstruct.ls_first) { + unsigned int x; + for (x = 0; x < sdp->sd_journals; x++) { + error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x), + WAIT); + if (error) { + fs_err(sdp, "error recovering journal %u: %d\n", + x, error); + goto fail_jinode_gh; + } + } + + gfs2_lm_others_may_mount(sdp); + } else if (!sdp->sd_args.ar_spectator) { + error = gfs2_recover_journal(sdp->sd_jdesc, WAIT); + if (error) { + fs_err(sdp, "error recovering my journal: %d\n", error); + goto fail_jinode_gh; + } + } + + set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags); + gfs2_glock_dq_uninit(&ji_gh); + jindex = 0; + + /* Disown my Journal glock */ + + sdp->sd_journal_gh.gh_owner = NULL; + sdp->sd_jinode_gh.gh_owner = NULL; + + p = kthread_run(gfs2_recoverd, sdp, "gfs2_recoverd"); + error = IS_ERR(p); + if (error) { + fs_err(sdp, "can't start recoverd thread: %d\n", error); + goto fail_jinode_gh; + } + sdp->sd_recoverd_process = p; + + return 0; + + fail_recoverd: + kthread_stop(sdp->sd_recoverd_process); + + fail_jinode_gh: + if (!sdp->sd_args.ar_spectator) + gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); + + fail_journal_gh: + if (!sdp->sd_args.ar_spectator) + gfs2_glock_dq_uninit(&sdp->sd_journal_gh); + + fail_jindex: + gfs2_jindex_free(sdp); + if (jindex) + gfs2_glock_dq_uninit(&ji_gh); + + fail: + gfs2_inode_put(sdp->sd_jindex); + + return error; +} + +int gfs2_lookup_root(struct gfs2_sbd *sdp) +{ + int error; + struct gfs2_glock *gl; + + error = gfs2_glock_get(sdp, sdp->sd_sb.sb_root_dir.no_addr, + &gfs2_inode_glops, CREATE, &gl); + if (!error) { + error = gfs2_inode_get(gl, &sdp->sd_sb.sb_root_dir, + CREATE, &sdp->sd_root_dir); + if (!error) + gfs2_inode_min_init(sdp->sd_root_dir, DT_DIR); + gfs2_glock_put(gl); + } + + return error; +} + + +static int init_inodes(struct gfs2_sbd *sdp, int undo) +{ + struct inode *inode; + struct dentry **dentry = &sdp->sd_vfs->s_root; + int error = 0; + + if (undo) + goto fail_dput; + + /* Read in the master inode number inode */ + error = gfs2_lookup_simple(sdp->sd_master_dir, "inum", + &sdp->sd_inum_inode); + if (error) { + fs_err(sdp, "can't read in inum inode: %d\n", error); + return error; + } + + /* Read in the master statfs inode */ + error = gfs2_lookup_simple(sdp->sd_master_dir, "statfs", + &sdp->sd_statfs_inode); + if (error) { + fs_err(sdp, "can't read in statfs inode: %d\n", error); + goto fail; + } + + /* Read in the resource index inode */ + error = gfs2_lookup_simple(sdp->sd_master_dir, "rindex", + &sdp->sd_rindex); + if (error) { + fs_err(sdp, "can't get resource index inode: %d\n", error); + goto fail_statfs; + } + set_bit(GLF_STICKY, &sdp->sd_rindex->i_gl->gl_flags); + sdp->sd_rindex_vn = sdp->sd_rindex->i_gl->gl_vn - 1; + + /* Read in the quota inode */ + error = gfs2_lookup_simple(sdp->sd_master_dir, "quota", + &sdp->sd_quota_inode); + if (error) { + fs_err(sdp, "can't get quota file inode: %d\n", error); + goto fail_rindex; + } + + /* Get the root inode */ + error = gfs2_lookup_root(sdp); + if (error) { + fs_err(sdp, "can't read in root inode: %d\n", error); + goto fail_qinode; + } + + /* Get the root inode/dentry */ + inode = gfs2_ip2v(sdp->sd_root_dir); + if (!inode) { + fs_err(sdp, "can't get root inode\n"); + error = -ENOMEM; + goto fail_rooti; + } + + *dentry = d_alloc_root(inode); + if (!*dentry) { + iput(inode); + fs_err(sdp, "can't get root dentry\n"); + error = -ENOMEM; + goto fail_rooti; + } + + return 0; + + fail_dput: + dput(*dentry); + *dentry = NULL; + + fail_rooti: + gfs2_inode_put(sdp->sd_root_dir); + + fail_qinode: + gfs2_inode_put(sdp->sd_quota_inode); + + fail_rindex: + gfs2_clear_rgrpd(sdp); + gfs2_inode_put(sdp->sd_rindex); + + fail_statfs: + gfs2_inode_put(sdp->sd_statfs_inode); + + fail: + gfs2_inode_put(sdp->sd_inum_inode); + + return error; +} + +static int init_per_node(struct gfs2_sbd *sdp, int undo) +{ + struct gfs2_inode *pn = NULL; + char buf[30]; + int error = 0; + + if (sdp->sd_args.ar_spectator) + return 0; + + if (undo) + goto fail_qc_gh; + + error = gfs2_lookup_simple(sdp->sd_master_dir, "per_node", &pn); + if (error) { + fs_err(sdp, "can't find per_node directory: %d\n", error); + return error; + } + + sprintf(buf, "inum_range%u", sdp->sd_jdesc->jd_jid); + error = gfs2_lookup_simple(pn, buf, &sdp->sd_ir_inode); + if (error) { + fs_err(sdp, "can't find local \"ir\" file: %d\n", error); + goto fail; + } + + sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid); + error = gfs2_lookup_simple(pn, buf, &sdp->sd_sc_inode); + if (error) { + fs_err(sdp, "can't find local \"sc\" file: %d\n", error); + goto fail_ir_i; + } + + sprintf(buf, "unlinked_tag%u", sdp->sd_jdesc->jd_jid); + error = gfs2_lookup_simple(pn, buf, &sdp->sd_ut_inode); + if (error) { + fs_err(sdp, "can't find local \"ut\" file: %d\n", error); + goto fail_sc_i; + } + + sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid); + error = gfs2_lookup_simple(pn, buf, &sdp->sd_qc_inode); + if (error) { + fs_err(sdp, "can't find local \"qc\" file: %d\n", error); + goto fail_ut_i; + } + + gfs2_inode_put(pn); + pn = NULL; + + error = gfs2_glock_nq_init(sdp->sd_ir_inode->i_gl, + LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, + &sdp->sd_ir_gh); + if (error) { + fs_err(sdp, "can't lock local \"ir\" file: %d\n", error); + goto fail_qc_i; + } + + error = gfs2_glock_nq_init(sdp->sd_sc_inode->i_gl, + LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, + &sdp->sd_sc_gh); + if (error) { + fs_err(sdp, "can't lock local \"sc\" file: %d\n", error); + goto fail_ir_gh; + } + + error = gfs2_glock_nq_init(sdp->sd_ut_inode->i_gl, + LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, + &sdp->sd_ut_gh); + if (error) { + fs_err(sdp, "can't lock local \"ut\" file: %d\n", error); + goto fail_sc_gh; + } + + error = gfs2_glock_nq_init(sdp->sd_qc_inode->i_gl, + LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, + &sdp->sd_qc_gh); + if (error) { + fs_err(sdp, "can't lock local \"qc\" file: %d\n", error); + goto fail_ut_gh; + } + + return 0; + + fail_qc_gh: + gfs2_glock_dq_uninit(&sdp->sd_qc_gh); + + fail_ut_gh: + gfs2_glock_dq_uninit(&sdp->sd_ut_gh); + + fail_sc_gh: + gfs2_glock_dq_uninit(&sdp->sd_sc_gh); + + fail_ir_gh: + gfs2_glock_dq_uninit(&sdp->sd_ir_gh); + + fail_qc_i: + gfs2_inode_put(sdp->sd_qc_inode); + + fail_ut_i: + gfs2_inode_put(sdp->sd_ut_inode); + + fail_sc_i: + gfs2_inode_put(sdp->sd_sc_inode); + + fail_ir_i: + gfs2_inode_put(sdp->sd_ir_inode); + + fail: + if (pn) + gfs2_inode_put(pn); + return error; +} + +static int init_threads(struct gfs2_sbd *sdp, int undo) +{ + struct task_struct *p; + int error = 0; + + if (undo) + goto fail_inoded; + + sdp->sd_log_flush_time = jiffies; + sdp->sd_jindex_refresh_time = jiffies; + + p = kthread_run(gfs2_logd, sdp, "gfs2_logd"); + error = IS_ERR(p); + if (error) { + fs_err(sdp, "can't start logd thread: %d\n", error); + return error; + } + sdp->sd_logd_process = p; + + sdp->sd_statfs_sync_time = jiffies; + sdp->sd_quota_sync_time = jiffies; + + p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad"); + error = IS_ERR(p); + if (error) { + fs_err(sdp, "can't start quotad thread: %d\n", error); + goto fail; + } + sdp->sd_quotad_process = p; + + p = kthread_run(gfs2_inoded, sdp, "gfs2_inoded"); + error = IS_ERR(p); + if (error) { + fs_err(sdp, "can't start inoded thread: %d\n", error); + goto fail_quotad; + } + sdp->sd_inoded_process = p; + + return 0; + + fail_inoded: + kthread_stop(sdp->sd_inoded_process); + + fail_quotad: + kthread_stop(sdp->sd_quotad_process); + + fail: + kthread_stop(sdp->sd_logd_process); + + return error; +} + +/** + * fill_super - Read in superblock + * @sb: The VFS superblock + * @data: Mount options + * @silent: Don't complain if it's not a GFS2 filesystem + * + * Returns: errno + */ + +static int fill_super(struct super_block *sb, void *data, int silent) +{ + struct gfs2_sbd *sdp; + struct gfs2_holder mount_gh; + int error; + + sdp = init_sbd(sb); + if (!sdp) { + printk("GFS2: can't alloc struct gfs2_sbd\n"); + return -ENOMEM; + } + + error = gfs2_mount_args(sdp, (char *)data, 0); + if (error) { + printk("GFS2: can't parse mount arguments\n"); + goto fail; + } + + init_vfs(sdp); + + error = init_names(sdp, silent); + if (error) + goto fail; + + error = gfs2_sys_fs_add(sdp); + if (error) + goto fail; + + error = gfs2_lm_mount(sdp, silent); + if (error) + goto fail_sys; + + error = init_locking(sdp, &mount_gh, DO); + if (error) + goto fail_lm; + + error = init_sb(sdp, silent, DO); + if (error) + goto fail_locking; + + error = init_journal(sdp, DO); + if (error) + goto fail_sb; + + error = init_inodes(sdp, DO); + if (error) + goto fail_journals; + + error = init_per_node(sdp, DO); + if (error) + goto fail_inodes; + + error = gfs2_statfs_init(sdp); + if (error) { + fs_err(sdp, "can't initialize statfs subsystem: %d\n", error); + goto fail_per_node; + } + + error = init_threads(sdp, DO); + if (error) + goto fail_per_node; + + if (!(sb->s_flags & MS_RDONLY)) { + error = gfs2_make_fs_rw(sdp); + if (error) { + fs_err(sdp, "can't make FS RW: %d\n", error); + goto fail_threads; + } + } + + gfs2_glock_dq_uninit(&mount_gh); + + return 0; + + fail_threads: + init_threads(sdp, UNDO); + + fail_per_node: + init_per_node(sdp, UNDO); + + fail_inodes: + init_inodes(sdp, UNDO); + + fail_journals: + init_journal(sdp, UNDO); + + fail_sb: + init_sb(sdp, 0, UNDO); + + fail_locking: + init_locking(sdp, &mount_gh, UNDO); + + fail_lm: + gfs2_gl_hash_clear(sdp, WAIT); + gfs2_lm_unmount(sdp); + while (invalidate_inodes(sb)) + yield(); + + fail_sys: + gfs2_sys_fs_del(sdp); + + fail: + vfree(sdp); + set_v2sdp(sb, NULL); + + return error; +} + +static struct super_block *gfs2_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, fill_super); +} + +struct file_system_type gfs2_fs_type = { + .name = "gfs2", + .fs_flags = FS_REQUIRES_DEV, + .get_sb = gfs2_get_sb, + .kill_sb = kill_block_super, + .owner = THIS_MODULE, +}; + diff --git a/fs/gfs2/ops_fstype.h b/fs/gfs2/ops_fstype.h new file mode 100644 index 000000000000..7008364e76ea --- /dev/null +++ b/fs/gfs2/ops_fstype.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __OPS_FSTYPE_DOT_H__ +#define __OPS_FSTYPE_DOT_H__ + +extern struct file_system_type gfs2_fs_type; + +#endif /* __OPS_FSTYPE_DOT_H__ */ diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c new file mode 100644 index 000000000000..d0f90b88380c --- /dev/null +++ b/fs/gfs2/ops_inode.c @@ -0,0 +1,1265 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "acl.h" +#include "bmap.h" +#include "dir.h" +#include "eaops.h" +#include "eattr.h" +#include "glock.h" +#include "inode.h" +#include "meta_io.h" +#include "ops_dentry.h" +#include "ops_inode.h" +#include "page.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" +#include "unlinked.h" + +/** + * gfs2_create - Create a file + * @dir: The directory in which to create the file + * @dentry: The dentry of the new file + * @mode: The mode of the new file + * + * Returns: errno + */ + +static int gfs2_create(struct inode *dir, struct dentry *dentry, + int mode, struct nameidata *nd) +{ + struct gfs2_inode *dip = get_v2ip(dir), *ip; + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_holder ghs[2]; + struct inode *inode; + int new = 1; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + gfs2_holder_init(dip->i_gl, 0, 0, ghs); + + for (;;) { + error = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode); + if (!error) { + ip = get_gl2ip(ghs[1].gh_gl); + gfs2_trans_end(sdp); + if (dip->i_alloc.al_rgd) + gfs2_inplace_release(dip); + gfs2_quota_unlock(dip); + gfs2_alloc_put(dip); + gfs2_glock_dq_uninit_m(2, ghs); + break; + } else if (error != -EEXIST || + (nd->intent.open.flags & O_EXCL)) { + gfs2_holder_uninit(ghs); + return error; + } + + error = gfs2_lookupi(dip, &dentry->d_name, 0, &ip); + if (!error) { + new = 0; + gfs2_holder_uninit(ghs); + break; + } else if (error != -ENOENT) { + gfs2_holder_uninit(ghs); + return error; + } + } + + inode = gfs2_ip2v(ip); + gfs2_inode_put(ip); + + if (!inode) + return -ENOMEM; + + d_instantiate(dentry, inode); + if (new) + mark_inode_dirty(inode); + + return 0; +} + +/** + * gfs2_lookup - Look up a filename in a directory and return its inode + * @dir: The directory inode + * @dentry: The dentry of the new inode + * @nd: passed from Linux VFS, ignored by us + * + * Called by the VFS layer. Lock dir and call gfs2_lookupi() + * + * Returns: errno + */ + +static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct gfs2_inode *dip = get_v2ip(dir), *ip; + struct gfs2_sbd *sdp = dip->i_sbd; + struct inode *inode = NULL; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + if (!sdp->sd_args.ar_localcaching) + dentry->d_op = &gfs2_dops; + + error = gfs2_lookupi(dip, &dentry->d_name, 0, &ip); + if (!error) { + inode = gfs2_ip2v(ip); + gfs2_inode_put(ip); + if (!inode) + return ERR_PTR(-ENOMEM); + + } else if (error != -ENOENT) + return ERR_PTR(error); + + if (inode) + return d_splice_alias(inode, dentry); + d_add(dentry, inode); + + return NULL; +} + +/** + * gfs2_link - Link to a file + * @old_dentry: The inode to link + * @dir: Add link to this directory + * @dentry: The name of the link + * + * Link the inode in "old_dentry" into the directory "dir" with the + * name in "dentry". + * + * Returns: errno + */ + +static int gfs2_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) +{ + struct gfs2_inode *dip = get_v2ip(dir); + struct gfs2_sbd *sdp = dip->i_sbd; + struct inode *inode = old_dentry->d_inode; + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_holder ghs[2]; + int alloc_required; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + if (S_ISDIR(ip->i_di.di_mode)) + return -EPERM; + + gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); + + error = gfs2_glock_nq_m(2, ghs); + if (error) + goto out; + + error = gfs2_repermission(dir, MAY_WRITE | MAY_EXEC, NULL); + if (error) + goto out_gunlock; + + error = gfs2_dir_search(dip, &dentry->d_name, NULL, NULL); + switch (error) { + case -ENOENT: + break; + case 0: + error = -EEXIST; + default: + goto out_gunlock; + } + + error = -EINVAL; + if (!dip->i_di.di_nlink) + goto out_gunlock; + error = -EFBIG; + if (dip->i_di.di_entries == (uint32_t)-1) + goto out_gunlock; + error = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + goto out_gunlock; + error = -EINVAL; + if (!ip->i_di.di_nlink) + goto out_gunlock; + error = -EMLINK; + if (ip->i_di.di_nlink == (uint32_t)-1) + goto out_gunlock; + + error = gfs2_diradd_alloc_required(dip, &dentry->d_name, + &alloc_required); + if (error) + goto out_gunlock; + + if (alloc_required) { + struct gfs2_alloc *al = gfs2_alloc_get(dip); + + error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out_alloc; + + error = gfs2_quota_check(dip, dip->i_di.di_uid, + dip->i_di.di_gid); + if (error) + goto out_gunlock_q; + + al->al_requested = sdp->sd_max_dirres; + + error = gfs2_inplace_reserve(dip); + if (error) + goto out_gunlock_q; + + error = gfs2_trans_begin(sdp, + sdp->sd_max_dirres + + al->al_rgd->rd_ri.ri_length + + 2 * RES_DINODE + RES_STATFS + + RES_QUOTA, 0); + if (error) + goto out_ipres; + } else { + error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0); + if (error) + goto out_ipres; + } + + error = gfs2_dir_add(dip, &dentry->d_name, &ip->i_num, + IF2DT(ip->i_di.di_mode)); + if (error) + goto out_end_trans; + + error = gfs2_change_nlink(ip, +1); + + out_end_trans: + gfs2_trans_end(sdp); + + out_ipres: + if (alloc_required) + gfs2_inplace_release(dip); + + out_gunlock_q: + if (alloc_required) + gfs2_quota_unlock(dip); + + out_alloc: + if (alloc_required) + gfs2_alloc_put(dip); + + out_gunlock: + gfs2_glock_dq_m(2, ghs); + + out: + gfs2_holder_uninit(ghs); + gfs2_holder_uninit(ghs + 1); + + if (!error) { + atomic_inc(&inode->i_count); + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + } + + return error; +} + +/** + * gfs2_unlink - Unlink a file + * @dir: The inode of the directory containing the file to unlink + * @dentry: The file itself + * + * Unlink a file. Call gfs2_unlinki() + * + * Returns: errno + */ + +static int gfs2_unlink(struct inode *dir, struct dentry *dentry) +{ + struct gfs2_inode *dip = get_v2ip(dir); + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + struct gfs2_unlinked *ul; + struct gfs2_holder ghs[2]; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + error = gfs2_unlinked_get(sdp, &ul); + if (error) + return error; + + gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); + + error = gfs2_glock_nq_m(2, ghs); + if (error) + goto out; + + error = gfs2_unlink_ok(dip, &dentry->d_name, ip); + if (error) + goto out_gunlock; + + error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF + + RES_UNLINKED, 0); + if (error) + goto out_gunlock; + + error = gfs2_unlinki(dip, &dentry->d_name, ip,ul); + + gfs2_trans_end(sdp); + + out_gunlock: + gfs2_glock_dq_m(2, ghs); + + out: + gfs2_holder_uninit(ghs); + gfs2_holder_uninit(ghs + 1); + + gfs2_unlinked_put(sdp, ul); + + return error; +} + +/** + * gfs2_symlink - Create a symlink + * @dir: The directory to create the symlink in + * @dentry: The dentry to put the symlink in + * @symname: The thing which the link points to + * + * Returns: errno + */ + +static int gfs2_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) +{ + struct gfs2_inode *dip = get_v2ip(dir), *ip; + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_holder ghs[2]; + struct inode *inode; + struct buffer_head *dibh; + int size; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + /* Must be stuffed with a null terminator for gfs2_follow_link() */ + size = strlen(symname); + if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1) + return -ENAMETOOLONG; + + gfs2_holder_init(dip->i_gl, 0, 0, ghs); + + error = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO); + if (error) { + gfs2_holder_uninit(ghs); + return error; + } + + ip = get_gl2ip(ghs[1].gh_gl); + + ip->i_di.di_size = size; + + error = gfs2_meta_inode_buffer(ip, &dibh); + + if (!gfs2_assert_withdraw(sdp, !error)) { + gfs2_dinode_out(&ip->i_di, dibh->b_data); + memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, + size); + brelse(dibh); + } + + gfs2_trans_end(sdp); + if (dip->i_alloc.al_rgd) + gfs2_inplace_release(dip); + gfs2_quota_unlock(dip); + gfs2_alloc_put(dip); + + gfs2_glock_dq_uninit_m(2, ghs); + + inode = gfs2_ip2v(ip); + gfs2_inode_put(ip); + + if (!inode) + return -ENOMEM; + + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + + return 0; +} + +/** + * gfs2_mkdir - Make a directory + * @dir: The parent directory of the new one + * @dentry: The dentry of the new directory + * @mode: The mode of the new directory + * + * Returns: errno + */ + +static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + struct gfs2_inode *dip = get_v2ip(dir), *ip; + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_holder ghs[2]; + struct inode *inode; + struct buffer_head *dibh; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + gfs2_holder_init(dip->i_gl, 0, 0, ghs); + + error = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode); + if (error) { + gfs2_holder_uninit(ghs); + return error; + } + + ip = get_gl2ip(ghs[1].gh_gl); + + ip->i_di.di_nlink = 2; + ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode); + ip->i_di.di_flags |= GFS2_DIF_JDATA; + ip->i_di.di_payload_format = GFS2_FORMAT_DE; + ip->i_di.di_entries = 2; + + error = gfs2_meta_inode_buffer(ip, &dibh); + + if (!gfs2_assert_withdraw(sdp, !error)) { + struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; + struct gfs2_dirent *dent; + + gfs2_dirent_alloc(ip, dibh, 1, &dent); + + dent->de_inum = di->di_num; /* already GFS2 endian */ + dent->de_hash = gfs2_disk_hash(".", 1); + dent->de_hash = cpu_to_be32(dent->de_hash); + dent->de_type = DT_DIR; + memcpy((char *) (dent + 1), ".", 1); + di->di_entries = cpu_to_be32(1); + + gfs2_dirent_alloc(ip, dibh, 2, &dent); + + gfs2_inum_out(&dip->i_num, (char *) &dent->de_inum); + dent->de_hash = gfs2_disk_hash("..", 2); + dent->de_hash = cpu_to_be32(dent->de_hash); + dent->de_type = DT_DIR; + memcpy((char *) (dent + 1), "..", 2); + + gfs2_dinode_out(&ip->i_di, (char *)di); + + brelse(dibh); + } + + error = gfs2_change_nlink(dip, +1); + gfs2_assert_withdraw(sdp, !error); /* dip already pinned */ + + gfs2_trans_end(sdp); + if (dip->i_alloc.al_rgd) + gfs2_inplace_release(dip); + gfs2_quota_unlock(dip); + gfs2_alloc_put(dip); + + gfs2_glock_dq_uninit_m(2, ghs); + + inode = gfs2_ip2v(ip); + gfs2_inode_put(ip); + + if (!inode) + return -ENOMEM; + + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + + return 0; +} + +/** + * gfs2_rmdir - Remove a directory + * @dir: The parent directory of the directory to be removed + * @dentry: The dentry of the directory to remove + * + * Remove a directory. Call gfs2_rmdiri() + * + * Returns: errno + */ + +static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct gfs2_inode *dip = get_v2ip(dir); + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + struct gfs2_unlinked *ul; + struct gfs2_holder ghs[2]; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + error = gfs2_unlinked_get(sdp, &ul); + if (error) + return error; + + gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); + + error = gfs2_glock_nq_m(2, ghs); + if (error) + goto out; + + error = gfs2_unlink_ok(dip, &dentry->d_name, ip); + if (error) + goto out_gunlock; + + if (ip->i_di.di_entries < 2) { + if (gfs2_consist_inode(ip)) + gfs2_dinode_print(&ip->i_di); + error = -EIO; + goto out_gunlock; + } + if (ip->i_di.di_entries > 2) { + error = -ENOTEMPTY; + goto out_gunlock; + } + + error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + + RES_UNLINKED, 0); + if (error) + goto out_gunlock; + + error = gfs2_rmdiri(dip, &dentry->d_name, ip, ul); + + gfs2_trans_end(sdp); + + out_gunlock: + gfs2_glock_dq_m(2, ghs); + + out: + gfs2_holder_uninit(ghs); + gfs2_holder_uninit(ghs + 1); + + gfs2_unlinked_put(sdp, ul); + + return error; +} + +/** + * gfs2_mknod - Make a special file + * @dir: The directory in which the special file will reside + * @dentry: The dentry of the special file + * @mode: The mode of the special file + * @rdev: The device specification of the special file + * + */ + +static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, + dev_t dev) +{ + struct gfs2_inode *dip = get_v2ip(dir), *ip; + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_holder ghs[2]; + struct inode *inode; + struct buffer_head *dibh; + uint32_t major = 0, minor = 0; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + switch (mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + major = MAJOR(dev); + minor = MINOR(dev); + break; + case S_IFIFO: + case S_IFSOCK: + break; + default: + return -EOPNOTSUPP; + }; + + gfs2_holder_init(dip->i_gl, 0, 0, ghs); + + error = gfs2_createi(ghs, &dentry->d_name, mode); + if (error) { + gfs2_holder_uninit(ghs); + return error; + } + + ip = get_gl2ip(ghs[1].gh_gl); + + ip->i_di.di_major = major; + ip->i_di.di_minor = minor; + + error = gfs2_meta_inode_buffer(ip, &dibh); + + if (!gfs2_assert_withdraw(sdp, !error)) { + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs2_trans_end(sdp); + if (dip->i_alloc.al_rgd) + gfs2_inplace_release(dip); + gfs2_quota_unlock(dip); + gfs2_alloc_put(dip); + + gfs2_glock_dq_uninit_m(2, ghs); + + inode = gfs2_ip2v(ip); + gfs2_inode_put(ip); + + if (!inode) + return -ENOMEM; + + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + + return 0; +} + +/** + * gfs2_rename - Rename a file + * @odir: Parent directory of old file name + * @odentry: The old dentry of the file + * @ndir: Parent directory of new file name + * @ndentry: The new dentry of the file + * + * Returns: errno + */ + +static int gfs2_rename(struct inode *odir, struct dentry *odentry, + struct inode *ndir, struct dentry *ndentry) +{ + struct gfs2_inode *odip = get_v2ip(odir); + struct gfs2_inode *ndip = get_v2ip(ndir); + struct gfs2_inode *ip = get_v2ip(odentry->d_inode); + struct gfs2_inode *nip = NULL; + struct gfs2_sbd *sdp = odip->i_sbd; + struct gfs2_unlinked *ul; + struct gfs2_holder ghs[4], r_gh; + unsigned int num_gh; + int dir_rename = 0; + int alloc_required; + unsigned int x; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + if (ndentry->d_inode) { + nip = get_v2ip(ndentry->d_inode); + if (ip == nip) + return 0; + } + + error = gfs2_unlinked_get(sdp, &ul); + if (error) + return error; + + /* Make sure we aren't trying to move a dirctory into it's subdir */ + + if (S_ISDIR(ip->i_di.di_mode) && odip != ndip) { + dir_rename = 1; + + error = gfs2_glock_nq_init(sdp->sd_rename_gl, + LM_ST_EXCLUSIVE, 0, + &r_gh); + if (error) + goto out; + + error = gfs2_ok_to_move(ip, ndip); + if (error) + goto out_gunlock_r; + } + + gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); + gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); + num_gh = 3; + + if (nip) + gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); + + error = gfs2_glock_nq_m(num_gh, ghs); + if (error) + goto out_uninit; + + /* Check out the old directory */ + + error = gfs2_unlink_ok(odip, &odentry->d_name, ip); + if (error) + goto out_gunlock; + + /* Check out the new directory */ + + if (nip) { + error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip); + if (error) + goto out_gunlock; + + if (S_ISDIR(nip->i_di.di_mode)) { + if (nip->i_di.di_entries < 2) { + if (gfs2_consist_inode(nip)) + gfs2_dinode_print(&nip->i_di); + error = -EIO; + goto out_gunlock; + } + if (nip->i_di.di_entries > 2) { + error = -ENOTEMPTY; + goto out_gunlock; + } + } + } else { + error = gfs2_repermission(ndir, MAY_WRITE | MAY_EXEC, NULL); + if (error) + goto out_gunlock; + + error = gfs2_dir_search(ndip, &ndentry->d_name, NULL, NULL); + switch (error) { + case -ENOENT: + error = 0; + break; + case 0: + error = -EEXIST; + default: + goto out_gunlock; + }; + + if (odip != ndip) { + if (!ndip->i_di.di_nlink) { + error = -EINVAL; + goto out_gunlock; + } + if (ndip->i_di.di_entries == (uint32_t)-1) { + error = -EFBIG; + goto out_gunlock; + } + if (S_ISDIR(ip->i_di.di_mode) && + ndip->i_di.di_nlink == (uint32_t)-1) { + error = -EMLINK; + goto out_gunlock; + } + } + } + + /* Check out the dir to be renamed */ + + if (dir_rename) { + error = gfs2_repermission(odentry->d_inode, MAY_WRITE, NULL); + if (error) + goto out_gunlock; + } + + error = gfs2_diradd_alloc_required(ndip, &ndentry->d_name, + &alloc_required); + if (error) + goto out_gunlock; + + if (alloc_required) { + struct gfs2_alloc *al = gfs2_alloc_get(ndip); + + error = gfs2_quota_lock(ndip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out_alloc; + + error = gfs2_quota_check(ndip, ndip->i_di.di_uid, + ndip->i_di.di_gid); + if (error) + goto out_gunlock_q; + + al->al_requested = sdp->sd_max_dirres; + + error = gfs2_inplace_reserve(ndip); + if (error) + goto out_gunlock_q; + + error = gfs2_trans_begin(sdp, + sdp->sd_max_dirres + + al->al_rgd->rd_ri.ri_length + + 4 * RES_DINODE + 4 * RES_LEAF + + RES_UNLINKED + RES_STATFS + + RES_QUOTA, 0); + if (error) + goto out_ipreserv; + } else { + error = gfs2_trans_begin(sdp, 4 * RES_DINODE + + 5 * RES_LEAF + + RES_UNLINKED, 0); + if (error) + goto out_gunlock; + } + + /* Remove the target file, if it exists */ + + if (nip) { + if (S_ISDIR(nip->i_di.di_mode)) + error = gfs2_rmdiri(ndip, &ndentry->d_name, nip, ul); + else + error = gfs2_unlinki(ndip, &ndentry->d_name, nip, ul); + if (error) + goto out_end_trans; + } + + if (dir_rename) { + struct qstr name; + name.len = 2; + name.name = ".."; + + error = gfs2_change_nlink(ndip, +1); + if (error) + goto out_end_trans; + error = gfs2_change_nlink(odip, -1); + if (error) + goto out_end_trans; + + error = gfs2_dir_mvino(ip, &name, &ndip->i_num, DT_DIR); + if (error) + goto out_end_trans; + } else { + struct buffer_head *dibh; + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out_end_trans; + ip->i_di.di_ctime = get_seconds(); + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + error = gfs2_dir_del(odip, &odentry->d_name); + if (error) + goto out_end_trans; + + error = gfs2_dir_add(ndip, &ndentry->d_name, &ip->i_num, + IF2DT(ip->i_di.di_mode)); + if (error) + goto out_end_trans; + + out_end_trans: + gfs2_trans_end(sdp); + + out_ipreserv: + if (alloc_required) + gfs2_inplace_release(ndip); + + out_gunlock_q: + if (alloc_required) + gfs2_quota_unlock(ndip); + + out_alloc: + if (alloc_required) + gfs2_alloc_put(ndip); + + out_gunlock: + gfs2_glock_dq_m(num_gh, ghs); + + out_uninit: + for (x = 0; x < num_gh; x++) + gfs2_holder_uninit(ghs + x); + + out_gunlock_r: + if (dir_rename) + gfs2_glock_dq_uninit(&r_gh); + + out: + gfs2_unlinked_put(sdp, ul); + + return error; +} + +/** + * gfs2_readlink - Read the value of a symlink + * @dentry: the symlink + * @buf: the buffer to read the symlink data into + * @size: the size of the buffer + * + * Returns: errno + */ + +static int gfs2_readlink(struct dentry *dentry, char __user *user_buf, + int user_size) +{ + struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + char array[GFS2_FAST_NAME_SIZE], *buf = array; + unsigned int len = GFS2_FAST_NAME_SIZE; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_inode); + + error = gfs2_readlinki(ip, &buf, &len); + if (error) + return error; + + if (user_size > len - 1) + user_size = len - 1; + + if (copy_to_user(user_buf, buf, user_size)) + error = -EFAULT; + else + error = user_size; + + if (buf != array) + kfree(buf); + + return error; +} + +/** + * gfs2_follow_link - Follow a symbolic link + * @dentry: The dentry of the link + * @nd: Data that we pass to vfs_follow_link() + * + * This can handle symlinks of any size. It is optimised for symlinks + * under GFS2_FAST_NAME_SIZE. + * + * Returns: 0 on success or error code + */ + +static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + char array[GFS2_FAST_NAME_SIZE], *buf = array; + unsigned int len = GFS2_FAST_NAME_SIZE; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_inode); + + error = gfs2_readlinki(ip, &buf, &len); + if (!error) { + error = vfs_follow_link(nd, buf); + if (buf != array) + kfree(buf); + } + + return ERR_PTR(error); +} + +/** + * gfs2_permission - + * @inode: + * @mask: + * @nd: passed from Linux VFS, ignored by us + * + * Returns: errno + */ + +static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_holder i_gh; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_inode); + + if (ip->i_vn == ip->i_gl->gl_vn) + return generic_permission(inode, mask, gfs2_check_acl); + + error = gfs2_glock_nq_init(ip->i_gl, + LM_ST_SHARED, LM_FLAG_ANY, + &i_gh); + if (!error) { + error = generic_permission(inode, mask, gfs2_check_acl_locked); + gfs2_glock_dq_uninit(&i_gh); + } + + return error; +} + +static int setattr_size(struct inode *inode, struct iattr *attr) +{ + struct gfs2_inode *ip = get_v2ip(inode); + int error; + + if (attr->ia_size != ip->i_di.di_size) { + error = vmtruncate(inode, attr->ia_size); + if (error) + return error; + } + + error = gfs2_truncatei(ip, attr->ia_size, gfs2_truncator_page); + if (error) + return error; + + return error; +} + +static int setattr_chown(struct inode *inode, struct iattr *attr) +{ + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_sbd *sdp = ip->i_sbd; + struct buffer_head *dibh; + uint32_t ouid, ogid, nuid, ngid; + int error; + + ouid = ip->i_di.di_uid; + ogid = ip->i_di.di_gid; + nuid = attr->ia_uid; + ngid = attr->ia_gid; + + if (!(attr->ia_valid & ATTR_UID) || ouid == nuid) + ouid = nuid = NO_QUOTA_CHANGE; + if (!(attr->ia_valid & ATTR_GID) || ogid == ngid) + ogid = ngid = NO_QUOTA_CHANGE; + + gfs2_alloc_get(ip); + + error = gfs2_quota_lock(ip, nuid, ngid); + if (error) + goto out_alloc; + + if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { + error = gfs2_quota_check(ip, nuid, ngid); + if (error) + goto out_gunlock_q; + } + + error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_QUOTA, 0); + if (error) + goto out_gunlock_q; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out_end_trans; + + error = inode_setattr(inode, attr); + gfs2_assert_warn(sdp, !error); + gfs2_inode_attr_out(ip); + + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { + gfs2_quota_change(ip, -ip->i_di.di_blocks, + ouid, ogid); + gfs2_quota_change(ip, ip->i_di.di_blocks, + nuid, ngid); + } + + out_end_trans: + gfs2_trans_end(sdp); + + out_gunlock_q: + gfs2_quota_unlock(ip); + + out_alloc: + gfs2_alloc_put(ip); + + return error; +} + +/** + * gfs2_setattr - Change attributes on an inode + * @dentry: The dentry which is changing + * @attr: The structure describing the change + * + * The VFS layer wants to change one or more of an inodes attributes. Write + * that change out to disk. + * + * Returns: errno + */ + +static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_holder i_gh; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_inode); + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + return error; + + error = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + goto out; + + error = inode_change_ok(inode, attr); + if (error) + goto out; + + if (attr->ia_valid & ATTR_SIZE) + error = setattr_size(inode, attr); + else if (attr->ia_valid & (ATTR_UID | ATTR_GID)) + error = setattr_chown(inode, attr); + else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode)) + error = gfs2_acl_chmod(ip, attr); + else + error = gfs2_setattr_simple(ip, attr); + + out: + gfs2_glock_dq_uninit(&i_gh); + + if (!error) + mark_inode_dirty(inode); + + return error; +} + +/** + * gfs2_getattr - Read out an inode's attributes + * @mnt: ? + * @dentry: The dentry to stat + * @stat: The inode's stats + * + * Returns: errno + */ + +static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_holder gh; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_inode); + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); + if (!error) { + generic_fillattr(inode, stat); + gfs2_glock_dq_uninit(&gh); + } + + return error; +} + +static int gfs2_setxattr(struct dentry *dentry, const char *name, + const void *data, size_t size, int flags) +{ + struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + struct gfs2_ea_request er; + + atomic_inc(&ip->i_sbd->sd_ops_inode); + + memset(&er, 0, sizeof(struct gfs2_ea_request)); + er.er_type = gfs2_ea_name2type(name, &er.er_name); + if (er.er_type == GFS2_EATYPE_UNUSED) + return -EOPNOTSUPP; + er.er_data = (char *)data; + er.er_name_len = strlen(er.er_name); + er.er_data_len = size; + er.er_flags = flags; + + gfs2_assert_warn(ip->i_sbd, !(er.er_flags & GFS2_ERF_MODE)); + + return gfs2_ea_set(ip, &er); +} + +static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, + void *data, size_t size) +{ + struct gfs2_ea_request er; + + atomic_inc(&get_v2sdp(dentry->d_inode->i_sb)->sd_ops_inode); + + memset(&er, 0, sizeof(struct gfs2_ea_request)); + er.er_type = gfs2_ea_name2type(name, &er.er_name); + if (er.er_type == GFS2_EATYPE_UNUSED) + return -EOPNOTSUPP; + er.er_data = data; + er.er_name_len = strlen(er.er_name); + er.er_data_len = size; + + return gfs2_ea_get(get_v2ip(dentry->d_inode), &er); +} + +static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + struct gfs2_ea_request er; + + atomic_inc(&get_v2sdp(dentry->d_inode->i_sb)->sd_ops_inode); + + memset(&er, 0, sizeof(struct gfs2_ea_request)); + er.er_data = (size) ? buffer : NULL; + er.er_data_len = size; + + return gfs2_ea_list(get_v2ip(dentry->d_inode), &er); +} + +static int gfs2_removexattr(struct dentry *dentry, const char *name) +{ + struct gfs2_ea_request er; + + atomic_inc(&get_v2sdp(dentry->d_inode->i_sb)->sd_ops_inode); + + memset(&er, 0, sizeof(struct gfs2_ea_request)); + er.er_type = gfs2_ea_name2type(name, &er.er_name); + if (er.er_type == GFS2_EATYPE_UNUSED) + return -EOPNOTSUPP; + er.er_name_len = strlen(er.er_name); + + return gfs2_ea_remove(get_v2ip(dentry->d_inode), &er); +} + +struct inode_operations gfs2_file_iops = { + .permission = gfs2_permission, + .setattr = gfs2_setattr, + .getattr = gfs2_getattr, + .setxattr = gfs2_setxattr, + .getxattr = gfs2_getxattr, + .listxattr = gfs2_listxattr, + .removexattr = gfs2_removexattr, +}; + +struct inode_operations gfs2_dev_iops = { + .permission = gfs2_permission, + .setattr = gfs2_setattr, + .getattr = gfs2_getattr, + .setxattr = gfs2_setxattr, + .getxattr = gfs2_getxattr, + .listxattr = gfs2_listxattr, + .removexattr = gfs2_removexattr, +}; + +struct inode_operations gfs2_dir_iops = { + .create = gfs2_create, + .lookup = gfs2_lookup, + .link = gfs2_link, + .unlink = gfs2_unlink, + .symlink = gfs2_symlink, + .mkdir = gfs2_mkdir, + .rmdir = gfs2_rmdir, + .mknod = gfs2_mknod, + .rename = gfs2_rename, + .permission = gfs2_permission, + .setattr = gfs2_setattr, + .getattr = gfs2_getattr, + .setxattr = gfs2_setxattr, + .getxattr = gfs2_getxattr, + .listxattr = gfs2_listxattr, + .removexattr = gfs2_removexattr, +}; + +struct inode_operations gfs2_symlink_iops = { + .readlink = gfs2_readlink, + .follow_link = gfs2_follow_link, + .permission = gfs2_permission, + .setattr = gfs2_setattr, + .getattr = gfs2_getattr, + .setxattr = gfs2_setxattr, + .getxattr = gfs2_getxattr, + .listxattr = gfs2_listxattr, + .removexattr = gfs2_removexattr, +}; + diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h new file mode 100644 index 000000000000..5fafd87c8d7b --- /dev/null +++ b/fs/gfs2/ops_inode.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __OPS_INODE_DOT_H__ +#define __OPS_INODE_DOT_H__ + +extern struct inode_operations gfs2_file_iops; +extern struct inode_operations gfs2_dir_iops; +extern struct inode_operations gfs2_symlink_iops; +extern struct inode_operations gfs2_dev_iops; + +#endif /* __OPS_INODE_DOT_H__ */ diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c new file mode 100644 index 000000000000..ca6a4d81bc26 --- /dev/null +++ b/fs/gfs2/ops_super.c @@ -0,0 +1,401 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "glock.h" +#include "inode.h" +#include "lm.h" +#include "log.h" +#include "mount.h" +#include "ops_super.h" +#include "page.h" +#include "quota.h" +#include "recovery.h" +#include "rgrp.h" +#include "super.h" +#include "sys.h" + +/** + * gfs2_write_inode - Make sure the inode is stable on the disk + * @inode: The inode + * @sync: synchronous write flag + * + * Returns: errno + */ + +static int gfs2_write_inode(struct inode *inode, int sync) +{ + struct gfs2_inode *ip = get_v2ip(inode); + + atomic_inc(&ip->i_sbd->sd_ops_super); + + if (current->flags & PF_MEMALLOC) + return 0; + if (ip && sync) + gfs2_log_flush_glock(ip->i_gl); + + return 0; +} + +/** + * gfs2_put_super - Unmount the filesystem + * @sb: The VFS superblock + * + */ + +static void gfs2_put_super(struct super_block *sb) +{ + struct gfs2_sbd *sdp = get_v2sdp(sb); + int error; + + if (!sdp) + return; + + atomic_inc(&sdp->sd_ops_super); + + /* Unfreeze the filesystem, if we need to */ + + down(&sdp->sd_freeze_lock); + if (sdp->sd_freeze_count) + gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); + up(&sdp->sd_freeze_lock); + + kthread_stop(sdp->sd_inoded_process); + kthread_stop(sdp->sd_quotad_process); + kthread_stop(sdp->sd_logd_process); + kthread_stop(sdp->sd_recoverd_process); + while (sdp->sd_glockd_num--) + kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]); + kthread_stop(sdp->sd_scand_process); + + if (!(sb->s_flags & MS_RDONLY)) { + error = gfs2_make_fs_ro(sdp); + if (error) + gfs2_io_error(sdp); + } + + /* At this point, we're through modifying the disk */ + + /* Release stuff */ + + gfs2_inode_put(sdp->sd_master_dir); + gfs2_inode_put(sdp->sd_jindex); + gfs2_inode_put(sdp->sd_inum_inode); + gfs2_inode_put(sdp->sd_statfs_inode); + gfs2_inode_put(sdp->sd_rindex); + gfs2_inode_put(sdp->sd_quota_inode); + gfs2_inode_put(sdp->sd_root_dir); + + gfs2_glock_put(sdp->sd_rename_gl); + gfs2_glock_put(sdp->sd_trans_gl); + + if (!sdp->sd_args.ar_spectator) { + gfs2_glock_dq_uninit(&sdp->sd_journal_gh); + gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); + gfs2_glock_dq_uninit(&sdp->sd_ir_gh); + gfs2_glock_dq_uninit(&sdp->sd_sc_gh); + gfs2_glock_dq_uninit(&sdp->sd_ut_gh); + gfs2_glock_dq_uninit(&sdp->sd_qc_gh); + gfs2_inode_put(sdp->sd_ir_inode); + gfs2_inode_put(sdp->sd_sc_inode); + gfs2_inode_put(sdp->sd_ut_inode); + gfs2_inode_put(sdp->sd_qc_inode); + } + + gfs2_glock_dq_uninit(&sdp->sd_live_gh); + + gfs2_clear_rgrpd(sdp); + gfs2_jindex_free(sdp); + + /* Take apart glock structures and buffer lists */ + gfs2_gl_hash_clear(sdp, WAIT); + + /* Unmount the locking protocol */ + gfs2_lm_unmount(sdp); + + /* At this point, we're through participating in the lockspace */ + + gfs2_sys_fs_del(sdp); + + /* Get rid of any extra inodes */ + while (invalidate_inodes(sb)) + yield(); + + vfree(sdp); + + set_v2sdp(sb, NULL); +} + +/** + * gfs2_write_super - disk commit all incore transactions + * @sb: the filesystem + * + * This function is called every time sync(2) is called. + * After this exits, all dirty buffers and synced. + */ + +static void gfs2_write_super(struct super_block *sb) +{ + struct gfs2_sbd *sdp = get_v2sdp(sb); + atomic_inc(&sdp->sd_ops_super); + gfs2_log_flush(sdp); +} + +/** + * gfs2_write_super_lockfs - prevent further writes to the filesystem + * @sb: the VFS structure for the filesystem + * + */ + +static void gfs2_write_super_lockfs(struct super_block *sb) +{ + struct gfs2_sbd *sdp = get_v2sdp(sb); + int error; + + atomic_inc(&sdp->sd_ops_super); + + for (;;) { + error = gfs2_freeze_fs(sdp); + if (!error) + break; + + switch (error) { + case -EBUSY: + fs_err(sdp, "waiting for recovery before freeze\n"); + break; + + default: + fs_err(sdp, "error freezing FS: %d\n", error); + break; + } + + fs_err(sdp, "retrying...\n"); + msleep(1000); + } +} + +/** + * gfs2_unlockfs - reallow writes to the filesystem + * @sb: the VFS structure for the filesystem + * + */ + +static void gfs2_unlockfs(struct super_block *sb) +{ + struct gfs2_sbd *sdp = get_v2sdp(sb); + + atomic_inc(&sdp->sd_ops_super); + gfs2_unfreeze_fs(sdp); +} + +/** + * gfs2_statfs - Gather and return stats about the filesystem + * @sb: The superblock + * @statfsbuf: The buffer + * + * Returns: 0 on success or error code + */ + +static int gfs2_statfs(struct super_block *sb, struct kstatfs *buf) +{ + struct gfs2_sbd *sdp = get_v2sdp(sb); + struct gfs2_statfs_change sc; + int error; + + atomic_inc(&sdp->sd_ops_super); + + if (gfs2_tune_get(sdp, gt_statfs_slow)) + error = gfs2_statfs_slow(sdp, &sc); + else + error = gfs2_statfs_i(sdp, &sc); + + if (error) + return error; + + memset(buf, 0, sizeof(struct kstatfs)); + + buf->f_type = GFS2_MAGIC; + buf->f_bsize = sdp->sd_sb.sb_bsize; + buf->f_blocks = sc.sc_total; + buf->f_bfree = sc.sc_free; + buf->f_bavail = sc.sc_free; + buf->f_files = sc.sc_dinodes + sc.sc_free; + buf->f_ffree = sc.sc_free; + buf->f_namelen = GFS2_FNAMESIZE; + + return 0; +} + +/** + * gfs2_remount_fs - called when the FS is remounted + * @sb: the filesystem + * @flags: the remount flags + * @data: extra data passed in (not used right now) + * + * Returns: errno + */ + +static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) +{ + struct gfs2_sbd *sdp = get_v2sdp(sb); + int error; + + atomic_inc(&sdp->sd_ops_super); + + error = gfs2_mount_args(sdp, data, 1); + if (error) + return error; + + if (sdp->sd_args.ar_spectator) + *flags |= MS_RDONLY; + else { + if (*flags & MS_RDONLY) { + if (!(sb->s_flags & MS_RDONLY)) + error = gfs2_make_fs_ro(sdp); + } else if (!(*flags & MS_RDONLY) && + (sb->s_flags & MS_RDONLY)) { + error = gfs2_make_fs_rw(sdp); + } + } + + if (*flags & (MS_NOATIME | MS_NODIRATIME)) + set_bit(SDF_NOATIME, &sdp->sd_flags); + else + clear_bit(SDF_NOATIME, &sdp->sd_flags); + + /* Don't let the VFS update atimes. GFS2 handles this itself. */ + *flags |= MS_NOATIME | MS_NODIRATIME; + + return error; +} + +/** + * gfs2_clear_inode - Deallocate an inode when VFS is done with it + * @inode: The VFS inode + * + */ + +static void gfs2_clear_inode(struct inode *inode) +{ + struct gfs2_inode *ip = get_v2ip(inode); + + atomic_inc(&get_v2sdp(inode->i_sb)->sd_ops_super); + + if (ip) { + spin_lock(&ip->i_spin); + ip->i_vnode = NULL; + set_v2ip(inode, NULL); + spin_unlock(&ip->i_spin); + + gfs2_glock_schedule_for_reclaim(ip->i_gl); + gfs2_inode_put(ip); + } +} + +/** + * gfs2_show_options - Show mount options for /proc/mounts + * @s: seq_file structure + * @mnt: vfsmount + * + * Returns: 0 on success or error code + */ + +static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) +{ + struct gfs2_sbd *sdp = get_v2sdp(mnt->mnt_sb); + struct gfs2_args *args = &sdp->sd_args; + + atomic_inc(&sdp->sd_ops_super); + + if (args->ar_lockproto[0]) + seq_printf(s, ",lockproto=%s", args->ar_lockproto); + if (args->ar_locktable[0]) + seq_printf(s, ",locktable=%s", args->ar_locktable); + if (args->ar_hostdata[0]) + seq_printf(s, ",hostdata=%s", args->ar_hostdata); + if (args->ar_spectator) + seq_printf(s, ",spectator"); + if (args->ar_ignore_local_fs) + seq_printf(s, ",ignore_local_fs"); + if (args->ar_localflocks) + seq_printf(s, ",localflocks"); + if (args->ar_localcaching) + seq_printf(s, ",localcaching"); + if (args->ar_debug) + seq_printf(s, ",debug"); + if (args->ar_upgrade) + seq_printf(s, ",upgrade"); + if (args->ar_num_glockd != GFS2_GLOCKD_DEFAULT) + seq_printf(s, ",num_glockd=%u", args->ar_num_glockd); + if (args->ar_posix_acl) + seq_printf(s, ",acl"); + if (args->ar_quota != GFS2_QUOTA_DEFAULT) { + char *state; + switch (args->ar_quota) { + case GFS2_QUOTA_OFF: + state = "off"; + break; + case GFS2_QUOTA_ACCOUNT: + state = "account"; + break; + case GFS2_QUOTA_ON: + state = "on"; + break; + default: + state = "unknown"; + break; + } + seq_printf(s, ",quota=%s", state); + } + if (args->ar_suiddir) + seq_printf(s, ",suiddir"); + if (args->ar_data != GFS2_DATA_DEFAULT) { + char *state; + switch (args->ar_data) { + case GFS2_DATA_WRITEBACK: + state = "writeback"; + break; + case GFS2_DATA_ORDERED: + state = "ordered"; + break; + default: + state = "unknown"; + break; + } + seq_printf(s, ",data=%s", state); + } + + return 0; +} + +struct super_operations gfs2_super_ops = { + .write_inode = gfs2_write_inode, + .put_super = gfs2_put_super, + .write_super = gfs2_write_super, + .write_super_lockfs = gfs2_write_super_lockfs, + .unlockfs = gfs2_unlockfs, + .statfs = gfs2_statfs, + .remount_fs = gfs2_remount_fs, + .clear_inode = gfs2_clear_inode, + .show_options = gfs2_show_options, +}; + diff --git a/fs/gfs2/ops_super.h b/fs/gfs2/ops_super.h new file mode 100644 index 000000000000..a41d208dc558 --- /dev/null +++ b/fs/gfs2/ops_super.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __OPS_SUPER_DOT_H__ +#define __OPS_SUPER_DOT_H__ + +extern struct super_operations gfs2_super_ops; + +#endif /* __OPS_SUPER_DOT_H__ */ diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c new file mode 100644 index 000000000000..a1b409ce75e1 --- /dev/null +++ b/fs/gfs2/ops_vm.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "glock.h" +#include "inode.h" +#include "ops_vm.h" +#include "page.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" + +static void pfault_be_greedy(struct gfs2_inode *ip) +{ + unsigned int time; + + spin_lock(&ip->i_spin); + time = ip->i_greedy; + ip->i_last_pfault = jiffies; + spin_unlock(&ip->i_spin); + + gfs2_inode_hold(ip); + if (gfs2_glock_be_greedy(ip->i_gl, time)) + gfs2_inode_put(ip); +} + +static struct page *gfs2_private_nopage(struct vm_area_struct *area, + unsigned long address, int *type) +{ + struct gfs2_inode *ip = get_v2ip(area->vm_file->f_mapping->host); + struct gfs2_holder i_gh; + struct page *result; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_vm); + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); + if (error) + return NULL; + + set_bit(GIF_PAGED, &ip->i_flags); + + result = filemap_nopage(area, address, type); + + if (result && result != NOPAGE_OOM) + pfault_be_greedy(ip); + + gfs2_glock_dq_uninit(&i_gh); + + return result; +} + +static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + unsigned long index = page->index; + uint64_t lblock = index << (PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift); + unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift; + struct gfs2_alloc *al; + unsigned int data_blocks, ind_blocks; + unsigned int x; + int error; + + al = gfs2_alloc_get(ip); + + error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto out_gunlock_q; + + gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, + &data_blocks, &ind_blocks); + + al->al_requested = data_blocks + ind_blocks; + + error = gfs2_inplace_reserve(ip); + if (error) + goto out_gunlock_q; + + error = gfs2_trans_begin(sdp, + al->al_rgd->rd_ri.ri_length + + ind_blocks + RES_DINODE + + RES_STATFS + RES_QUOTA, 0); + if (error) + goto out_ipres; + + if (gfs2_is_stuffed(ip)) { + error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, NULL); + if (error) + goto out_trans; + } + + for (x = 0; x < blocks; ) { + uint64_t dblock; + unsigned int extlen; + int new = 1; + + error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); + if (error) + goto out_trans; + + lblock += extlen; + x += extlen; + } + + gfs2_assert_warn(sdp, al->al_alloced); + + out_trans: + gfs2_trans_end(sdp); + + out_ipres: + gfs2_inplace_release(ip); + + out_gunlock_q: + gfs2_quota_unlock(ip); + + out: + gfs2_alloc_put(ip); + + return error; +} + +static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, + unsigned long address, int *type) +{ + struct gfs2_inode *ip = get_v2ip(area->vm_file->f_mapping->host); + struct gfs2_holder i_gh; + struct page *result = NULL; + unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff; + int alloc_required; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_vm); + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + return NULL; + + if (gfs2_is_jdata(ip)) + goto out; + + set_bit(GIF_PAGED, &ip->i_flags); + set_bit(GIF_SW_PAGED, &ip->i_flags); + + error = gfs2_write_alloc_required(ip, + (uint64_t)index << PAGE_CACHE_SHIFT, + PAGE_CACHE_SIZE, &alloc_required); + if (error) + goto out; + + result = filemap_nopage(area, address, type); + if (!result || result == NOPAGE_OOM) + goto out; + + if (alloc_required) { + error = alloc_page_backing(ip, result); + if (error) { + page_cache_release(result); + result = NULL; + goto out; + } + set_page_dirty(result); + } + + pfault_be_greedy(ip); + + out: + gfs2_glock_dq_uninit(&i_gh); + + return result; +} + +struct vm_operations_struct gfs2_vm_ops_private = { + .nopage = gfs2_private_nopage, +}; + +struct vm_operations_struct gfs2_vm_ops_sharewrite = { + .nopage = gfs2_sharewrite_nopage, +}; + diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h new file mode 100644 index 000000000000..54e3a8769cbb --- /dev/null +++ b/fs/gfs2/ops_vm.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __OPS_VM_DOT_H__ +#define __OPS_VM_DOT_H__ + +extern struct vm_operations_struct gfs2_vm_ops_private; +extern struct vm_operations_struct gfs2_vm_ops_sharewrite; + +#endif /* __OPS_VM_DOT_H__ */ diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c new file mode 100644 index 000000000000..05453c5a06f0 --- /dev/null +++ b/fs/gfs2/page.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "inode.h" +#include "page.h" +#include "trans.h" + +/** + * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock + * @gl: the glock + * + */ + +void gfs2_pte_inval(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip; + struct inode *inode; + + ip = get_gl2ip(gl); + if (!ip || !S_ISREG(ip->i_di.di_mode)) + return; + + if (!test_bit(GIF_PAGED, &ip->i_flags)) + return; + + inode = gfs2_ip2v_lookup(ip); + if (inode) { + unmap_shared_mapping_range(inode->i_mapping, 0, 0); + iput(inode); + + if (test_bit(GIF_SW_PAGED, &ip->i_flags)) + set_bit(GLF_DIRTY, &gl->gl_flags); + } + + clear_bit(GIF_SW_PAGED, &ip->i_flags); +} + +/** + * gfs2_page_inval - Invalidate all pages associated with a glock + * @gl: the glock + * + */ + +void gfs2_page_inval(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip; + struct inode *inode; + + ip = get_gl2ip(gl); + if (!ip || !S_ISREG(ip->i_di.di_mode)) + return; + + inode = gfs2_ip2v_lookup(ip); + if (inode) { + struct address_space *mapping = inode->i_mapping; + + truncate_inode_pages(mapping, 0); + gfs2_assert_withdraw(ip->i_sbd, !mapping->nrpages); + + iput(inode); + } + + clear_bit(GIF_PAGED, &ip->i_flags); +} + +/** + * gfs2_page_sync - Sync the data pages (not metadata) associated with a glock + * @gl: the glock + * @flags: DIO_START | DIO_WAIT + * + * Syncs data (not metadata) for a regular file. + * No-op for all other types. + */ + +void gfs2_page_sync(struct gfs2_glock *gl, int flags) +{ + struct gfs2_inode *ip; + struct inode *inode; + + ip = get_gl2ip(gl); + if (!ip || !S_ISREG(ip->i_di.di_mode)) + return; + + inode = gfs2_ip2v_lookup(ip); + if (inode) { + struct address_space *mapping = inode->i_mapping; + int error = 0; + + if (flags & DIO_START) + filemap_fdatawrite(mapping); + if (!error && (flags & DIO_WAIT)) + error = filemap_fdatawait(mapping); + + /* Put back any errors cleared by filemap_fdatawait() + so they can be caught by someone who can pass them + up to user space. */ + + if (error == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + else if (error) + set_bit(AS_EIO, &mapping->flags); + + iput(inode); + } +} + +/** + * gfs2_unstuffer_page - unstuff a stuffed inode into a block cached by a page + * @ip: the inode + * @dibh: the dinode buffer + * @block: the block number that was allocated + * @private: any locked page held by the caller process + * + * Returns: errno + */ + +int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, + uint64_t block, void *private) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct inode *inode = ip->i_vnode; + struct page *page = (struct page *)private; + struct buffer_head *bh; + int release = 0; + + if (!page || page->index) { + page = grab_cache_page(inode->i_mapping, 0); + if (!page) + return -ENOMEM; + release = 1; + } + + if (!PageUptodate(page)) { + void *kaddr = kmap(page); + + memcpy(kaddr, + dibh->b_data + sizeof(struct gfs2_dinode), + ip->i_di.di_size); + memset(kaddr + ip->i_di.di_size, + 0, + PAGE_CACHE_SIZE - ip->i_di.di_size); + kunmap(page); + + SetPageUptodate(page); + } + + if (!page_has_buffers(page)) + create_empty_buffers(page, 1 << inode->i_blkbits, + (1 << BH_Uptodate)); + + bh = page_buffers(page); + + if (!buffer_mapped(bh)) + map_bh(bh, inode->i_sb, block); + + set_buffer_uptodate(bh); + if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) + gfs2_trans_add_databuf(sdp, bh); + mark_buffer_dirty(bh); + + if (release) { + unlock_page(page); + page_cache_release(page); + } + + return 0; +} + +/** + * gfs2_truncator_page - truncate a partial data block in the page cache + * @ip: the inode + * @size: the size the file should be + * + * Returns: errno + */ + +int gfs2_truncator_page(struct gfs2_inode *ip, uint64_t size) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct inode *inode = ip->i_vnode; + struct page *page; + struct buffer_head *bh; + void *kaddr; + uint64_t lbn, dbn; + unsigned long index; + unsigned int offset; + unsigned int bufnum; + int new = 0; + int error; + + lbn = size >> inode->i_blkbits; + error = gfs2_block_map(ip, lbn, &new, &dbn, NULL); + if (error || !dbn) + return error; + + index = size >> PAGE_CACHE_SHIFT; + offset = size & (PAGE_CACHE_SIZE - 1); + bufnum = lbn - (index << (PAGE_CACHE_SHIFT - inode->i_blkbits)); + + page = read_cache_page(inode->i_mapping, index, + (filler_t *)inode->i_mapping->a_ops->readpage, + NULL); + if (IS_ERR(page)) + return PTR_ERR(page); + + lock_page(page); + + if (!PageUptodate(page) || PageError(page)) { + error = -EIO; + goto out; + } + + kaddr = kmap(page); + memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); + kunmap(page); + + if (!page_has_buffers(page)) + create_empty_buffers(page, 1 << inode->i_blkbits, + (1 << BH_Uptodate)); + + for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page) + /* Do nothing */; + + if (!buffer_mapped(bh)) + map_bh(bh, inode->i_sb, dbn); + + set_buffer_uptodate(bh); + if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) + gfs2_trans_add_databuf(sdp, bh); + mark_buffer_dirty(bh); + + out: + unlock_page(page); + page_cache_release(page); + + return error; +} + +void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page, + unsigned int from, unsigned int to) +{ + struct buffer_head *head = page_buffers(page); + unsigned int bsize = head->b_size; + struct buffer_head *bh; + unsigned int start, end; + + for (bh = head, start = 0; + bh != head || !start; + bh = bh->b_this_page, start = end) { + end = start + bsize; + if (end <= from || start >= to) + continue; + gfs2_trans_add_databuf(sdp, bh); + } +} + diff --git a/fs/gfs2/page.h b/fs/gfs2/page.h new file mode 100644 index 000000000000..7ad8c99ee0ef --- /dev/null +++ b/fs/gfs2/page.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __PAGE_DOT_H__ +#define __PAGE_DOT_H__ + +void gfs2_pte_inval(struct gfs2_glock *gl); +void gfs2_page_inval(struct gfs2_glock *gl); +void gfs2_page_sync(struct gfs2_glock *gl, int flags); + +int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, + uint64_t block, void *private); +int gfs2_truncator_page(struct gfs2_inode *ip, uint64_t size); +void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page, + unsigned int from, unsigned int to); + +#endif /* __PAGE_DOT_H__ */ diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c new file mode 100644 index 000000000000..a0320f22b57b --- /dev/null +++ b/fs/gfs2/quota.c @@ -0,0 +1,1238 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +/* + * Quota change tags are associated with each transaction that allocates or + * deallocates space. Those changes are accumulated locally to each node (in a + * per-node file) and then are periodically synced to the quota file. This + * avoids the bottleneck of constantly touching the quota file, but introduces + * fuzziness in the current usage value of IDs that are being used on different + * nodes in the cluster simultaneously. So, it is possible for a user on + * multiple nodes to overrun their quota, but that overrun is controlable. + * Since quota tags are part of transactions, there is no need to a quota check + * program to be run on node crashes or anything like that. + * + * There are couple of knobs that let the administrator manage the quota + * fuzziness. "quota_quantum" sets the maximum time a quota change can be + * sitting on one node before being synced to the quota file. (The default is + * 60 seconds.) Another knob, "quota_scale" controls how quickly the frequency + * of quota file syncs increases as the user moves closer to their limit. The + * more frequent the syncs, the more accurate the quota enforcement, but that + * means that there is more contention between the nodes for the quota file. + * The default value is one. This sets the maximum theoretical quota overrun + * (with infinite node with infinite bandwidth) to twice the user's limit. (In + * practice, the maximum overrun you see should be much less.) A "quota_scale" + * number greater than one makes quota syncs more frequent and reduces the + * maximum overrun. Numbers less than one (but greater than zero) make quota + * syncs less frequent. + * + * GFS quotas also use per-ID Lock Value Blocks (LVBs) to cache the contents of + * the quota file, so it is not being constantly read. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "glock.h" +#include "glops.h" +#include "jdata.h" +#include "log.h" +#include "meta_io.h" +#include "quota.h" +#include "rgrp.h" +#include "super.h" +#include "trans.h" + +#define QUOTA_USER 1 +#define QUOTA_GROUP 0 + +static uint64_t qd2offset(struct gfs2_quota_data *qd) +{ + uint64_t offset; + + offset = 2 * (uint64_t)qd->qd_id + !test_bit(QDF_USER, &qd->qd_flags); + offset *= sizeof(struct gfs2_quota); + + return offset; +} + +static int qd_alloc(struct gfs2_sbd *sdp, int user, uint32_t id, + struct gfs2_quota_data **qdp) +{ + struct gfs2_quota_data *qd; + int error; + + qd = kzalloc(sizeof(struct gfs2_quota_data), GFP_KERNEL); + if (!qd) + return -ENOMEM; + + qd->qd_count = 1; + qd->qd_id = id; + if (user) + set_bit(QDF_USER, &qd->qd_flags); + qd->qd_slot = -1; + + error = gfs2_glock_get(sdp, 2 * (uint64_t)id + !user, + &gfs2_quota_glops, CREATE, &qd->qd_gl); + if (error) + goto fail; + + error = gfs2_lvb_hold(qd->qd_gl); + gfs2_glock_put(qd->qd_gl); + if (error) + goto fail; + + *qdp = qd; + + return 0; + + fail: + kfree(qd); + return error; +} + +static int qd_get(struct gfs2_sbd *sdp, int user, uint32_t id, int create, + struct gfs2_quota_data **qdp) +{ + struct gfs2_quota_data *qd = NULL, *new_qd = NULL; + int error, found; + + *qdp = NULL; + + for (;;) { + found = 0; + spin_lock(&sdp->sd_quota_spin); + list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) { + if (qd->qd_id == id && + !test_bit(QDF_USER, &qd->qd_flags) == !user) { + qd->qd_count++; + found = 1; + break; + } + } + + if (!found) + qd = NULL; + + if (!qd && new_qd) { + qd = new_qd; + list_add(&qd->qd_list, &sdp->sd_quota_list); + atomic_inc(&sdp->sd_quota_count); + new_qd = NULL; + } + + spin_unlock(&sdp->sd_quota_spin); + + if (qd || !create) { + if (new_qd) { + gfs2_lvb_unhold(new_qd->qd_gl); + kfree(new_qd); + } + *qdp = qd; + return 0; + } + + error = qd_alloc(sdp, user, id, &new_qd); + if (error) + return error; + } +} + +static void qd_hold(struct gfs2_quota_data *qd) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + + spin_lock(&sdp->sd_quota_spin); + gfs2_assert(sdp, qd->qd_count); + qd->qd_count++; + spin_unlock(&sdp->sd_quota_spin); +} + +static void qd_put(struct gfs2_quota_data *qd) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + spin_lock(&sdp->sd_quota_spin); + gfs2_assert(sdp, qd->qd_count); + if (!--qd->qd_count) + qd->qd_last_touched = jiffies; + spin_unlock(&sdp->sd_quota_spin); +} + +static int slot_get(struct gfs2_quota_data *qd) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + unsigned int c, o = 0, b; + unsigned char byte = 0; + + spin_lock(&sdp->sd_quota_spin); + + if (qd->qd_slot_count++) { + spin_unlock(&sdp->sd_quota_spin); + return 0; + } + + for (c = 0; c < sdp->sd_quota_chunks; c++) + for (o = 0; o < PAGE_SIZE; o++) { + byte = sdp->sd_quota_bitmap[c][o]; + if (byte != 0xFF) + goto found; + } + + goto fail; + + found: + for (b = 0; b < 8; b++) + if (!(byte & (1 << b))) + break; + qd->qd_slot = c * (8 * PAGE_SIZE) + o * 8 + b; + + if (qd->qd_slot >= sdp->sd_quota_slots) + goto fail; + + sdp->sd_quota_bitmap[c][o] |= 1 << b; + + spin_unlock(&sdp->sd_quota_spin); + + return 0; + + fail: + qd->qd_slot_count--; + spin_unlock(&sdp->sd_quota_spin); + return -ENOSPC; +} + +static void slot_hold(struct gfs2_quota_data *qd) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + + spin_lock(&sdp->sd_quota_spin); + gfs2_assert(sdp, qd->qd_slot_count); + qd->qd_slot_count++; + spin_unlock(&sdp->sd_quota_spin); +} + +static void slot_put(struct gfs2_quota_data *qd) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + + spin_lock(&sdp->sd_quota_spin); + gfs2_assert(sdp, qd->qd_slot_count); + if (!--qd->qd_slot_count) { + gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, qd->qd_slot, 0); + qd->qd_slot = -1; + } + spin_unlock(&sdp->sd_quota_spin); +} + +static int bh_get(struct gfs2_quota_data *qd) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_inode *ip = sdp->sd_qc_inode; + unsigned int block, offset; + uint64_t dblock; + int new = 0; + struct buffer_head *bh; + int error; + + down(&sdp->sd_quota_mutex); + + if (qd->qd_bh_count++) { + up(&sdp->sd_quota_mutex); + return 0; + } + + block = qd->qd_slot / sdp->sd_qc_per_block; + offset = qd->qd_slot % sdp->sd_qc_per_block;; + + error = gfs2_block_map(ip, block, &new, &dblock, NULL); + if (error) + goto fail; + error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); + if (error) + goto fail; + error = -EIO; + if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC)) + goto fail_brelse; + + qd->qd_bh = bh; + qd->qd_bh_qc = (struct gfs2_quota_change *) + (bh->b_data + sizeof(struct gfs2_meta_header) + + offset * sizeof(struct gfs2_quota_change)); + + up(&sdp->sd_quota_mutex); + + return 0; + + fail_brelse: + brelse(bh); + + fail: + qd->qd_bh_count--; + up(&sdp->sd_quota_mutex); + return error; +} + +static void bh_put(struct gfs2_quota_data *qd) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + + down(&sdp->sd_quota_mutex); + gfs2_assert(sdp, qd->qd_bh_count); + if (!--qd->qd_bh_count) { + brelse(qd->qd_bh); + qd->qd_bh = NULL; + qd->qd_bh_qc = NULL; + } + up(&sdp->sd_quota_mutex); +} + +static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp) +{ + struct gfs2_quota_data *qd = NULL; + int error; + int found = 0; + + *qdp = NULL; + + if (sdp->sd_vfs->s_flags & MS_RDONLY) + return 0; + + spin_lock(&sdp->sd_quota_spin); + + list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) { + if (test_bit(QDF_LOCKED, &qd->qd_flags) || + !test_bit(QDF_CHANGE, &qd->qd_flags) || + qd->qd_sync_gen >= sdp->sd_quota_sync_gen) + continue; + + list_move_tail(&qd->qd_list, &sdp->sd_quota_list); + + set_bit(QDF_LOCKED, &qd->qd_flags); + gfs2_assert_warn(sdp, qd->qd_count); + qd->qd_count++; + qd->qd_change_sync = qd->qd_change; + gfs2_assert_warn(sdp, qd->qd_slot_count); + qd->qd_slot_count++; + found = 1; + + break; + } + + if (!found) + qd = NULL; + + spin_unlock(&sdp->sd_quota_spin); + + if (qd) { + gfs2_assert_warn(sdp, qd->qd_change_sync); + error = bh_get(qd); + if (error) { + clear_bit(QDF_LOCKED, &qd->qd_flags); + slot_put(qd); + qd_put(qd); + return error; + } + } + + *qdp = qd; + + return 0; +} + +static int qd_trylock(struct gfs2_quota_data *qd) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + + if (sdp->sd_vfs->s_flags & MS_RDONLY) + return 0; + + spin_lock(&sdp->sd_quota_spin); + + if (test_bit(QDF_LOCKED, &qd->qd_flags) || + !test_bit(QDF_CHANGE, &qd->qd_flags)) { + spin_unlock(&sdp->sd_quota_spin); + return 0; + } + + list_move_tail(&qd->qd_list, &sdp->sd_quota_list); + + set_bit(QDF_LOCKED, &qd->qd_flags); + gfs2_assert_warn(sdp, qd->qd_count); + qd->qd_count++; + qd->qd_change_sync = qd->qd_change; + gfs2_assert_warn(sdp, qd->qd_slot_count); + qd->qd_slot_count++; + + spin_unlock(&sdp->sd_quota_spin); + + gfs2_assert_warn(sdp, qd->qd_change_sync); + if (bh_get(qd)) { + clear_bit(QDF_LOCKED, &qd->qd_flags); + slot_put(qd); + qd_put(qd); + return 0; + } + + return 1; +} + +static void qd_unlock(struct gfs2_quota_data *qd) +{ + gfs2_assert_warn(qd->qd_gl->gl_sbd, test_bit(QDF_LOCKED, &qd->qd_flags)); + clear_bit(QDF_LOCKED, &qd->qd_flags); + bh_put(qd); + slot_put(qd); + qd_put(qd); +} + +static int qdsb_get(struct gfs2_sbd *sdp, int user, uint32_t id, int create, + struct gfs2_quota_data **qdp) +{ + int error; + + error = qd_get(sdp, user, id, create, qdp); + if (error) + return error; + + error = slot_get(*qdp); + if (error) + goto fail; + + error = bh_get(*qdp); + if (error) + goto fail_slot; + + return 0; + + fail_slot: + slot_put(*qdp); + + fail: + qd_put(*qdp); + return error; +} + +static void qdsb_put(struct gfs2_quota_data *qd) +{ + bh_put(qd); + slot_put(qd); + qd_put(qd); +} + +int gfs2_quota_hold(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_quota_data **qd = al->al_qd; + int error; + + if (gfs2_assert_warn(sdp, !al->al_qd_num) || + gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags))) + return -EIO; + + if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) + return 0; + + error = qdsb_get(sdp, QUOTA_USER, ip->i_di.di_uid, CREATE, qd); + if (error) + goto out; + al->al_qd_num++; + qd++; + + error = qdsb_get(sdp, QUOTA_GROUP, ip->i_di.di_gid, CREATE, qd); + if (error) + goto out; + al->al_qd_num++; + qd++; + + if (uid != NO_QUOTA_CHANGE && uid != ip->i_di.di_uid) { + error = qdsb_get(sdp, QUOTA_USER, uid, CREATE, qd); + if (error) + goto out; + al->al_qd_num++; + qd++; + } + + if (gid != NO_QUOTA_CHANGE && gid != ip->i_di.di_gid) { + error = qdsb_get(sdp, QUOTA_GROUP, gid, CREATE, qd); + if (error) + goto out; + al->al_qd_num++; + qd++; + } + + out: + if (error) + gfs2_quota_unhold(ip); + + return error; +} + +void gfs2_quota_unhold(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = &ip->i_alloc; + unsigned int x; + + gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)); + + for (x = 0; x < al->al_qd_num; x++) { + qdsb_put(al->al_qd[x]); + al->al_qd[x] = NULL; + } + al->al_qd_num = 0; +} + +static int sort_qd(const void *a, const void *b) +{ + struct gfs2_quota_data *qd_a = *(struct gfs2_quota_data **)a; + struct gfs2_quota_data *qd_b = *(struct gfs2_quota_data **)b; + int ret = 0; + + if (!test_bit(QDF_USER, &qd_a->qd_flags) != + !test_bit(QDF_USER, &qd_b->qd_flags)) { + if (test_bit(QDF_USER, &qd_a->qd_flags)) + ret = -1; + else + ret = 1; + } else { + if (qd_a->qd_id < qd_b->qd_id) + ret = -1; + else if (qd_a->qd_id > qd_b->qd_id) + ret = 1; + } + + return ret; +} + +static void do_qc(struct gfs2_quota_data *qd, int64_t change) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_inode *ip = sdp->sd_qc_inode; + struct gfs2_quota_change *qc = qd->qd_bh_qc; + int64_t x; + + down(&sdp->sd_quota_mutex); + gfs2_trans_add_bh(ip->i_gl, qd->qd_bh); + + if (!test_bit(QDF_CHANGE, &qd->qd_flags)) { + qc->qc_change = 0; + qc->qc_flags = 0; + if (test_bit(QDF_USER, &qd->qd_flags)) + qc->qc_flags = cpu_to_be32(GFS2_QCF_USER); + qc->qc_id = cpu_to_be32(qd->qd_id); + } + + x = qc->qc_change; + x = be64_to_cpu(x) + change; + qc->qc_change = cpu_to_be64(x); + + spin_lock(&sdp->sd_quota_spin); + qd->qd_change = x; + spin_unlock(&sdp->sd_quota_spin); + + if (!x) { + gfs2_assert_warn(sdp, test_bit(QDF_CHANGE, &qd->qd_flags)); + clear_bit(QDF_CHANGE, &qd->qd_flags); + qc->qc_flags = 0; + qc->qc_id = 0; + slot_put(qd); + qd_put(qd); + } else if (!test_and_set_bit(QDF_CHANGE, &qd->qd_flags)) { + qd_hold(qd); + slot_hold(qd); + } + + up(&sdp->sd_quota_mutex); +} + +static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) +{ + struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd; + struct gfs2_inode *ip = sdp->sd_quota_inode; + unsigned int data_blocks, ind_blocks; + struct gfs2_holder *ghs, i_gh; + unsigned int qx, x; + struct gfs2_quota_data *qd; + uint64_t offset; + unsigned int nalloc = 0; + struct gfs2_alloc *al = NULL; + int error; + + gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota), + &data_blocks, &ind_blocks); + + ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_KERNEL); + if (!ghs) + return -ENOMEM; + + sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL); + for (qx = 0; qx < num_qd; qx++) { + error = gfs2_glock_nq_init(qda[qx]->qd_gl, + LM_ST_EXCLUSIVE, + GL_NOCACHE, &ghs[qx]); + if (error) + goto out; + } + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + goto out; + + for (x = 0; x < num_qd; x++) { + int alloc_required; + + offset = qd2offset(qda[x]); + error = gfs2_write_alloc_required(ip, offset, + sizeof(struct gfs2_quota), + &alloc_required); + if (error) + goto out_gunlock; + if (alloc_required) + nalloc++; + } + + if (nalloc) { + al = gfs2_alloc_get(ip); + + al->al_requested = nalloc * (data_blocks + ind_blocks); + + error = gfs2_inplace_reserve(ip); + if (error) + goto out_alloc; + + error = gfs2_trans_begin(sdp, + al->al_rgd->rd_ri.ri_length + + num_qd * data_blocks + + nalloc * ind_blocks + + RES_DINODE + num_qd + + RES_STATFS, 0); + if (error) + goto out_ipres; + } else { + error = gfs2_trans_begin(sdp, + num_qd * data_blocks + + RES_DINODE + num_qd, 0); + if (error) + goto out_gunlock; + } + + for (x = 0; x < num_qd; x++) { + char buf[sizeof(struct gfs2_quota)]; + struct gfs2_quota q; + + qd = qda[x]; + offset = qd2offset(qd); + + /* The quota file may not be a multiple of + sizeof(struct gfs2_quota) bytes. */ + memset(buf, 0, sizeof(struct gfs2_quota)); + + error = gfs2_jdata_read_mem(ip, buf, offset, + sizeof(struct gfs2_quota)); + if (error < 0) + goto out_end_trans; + + gfs2_quota_in(&q, buf); + q.qu_value += qda[x]->qd_change_sync; + gfs2_quota_out(&q, buf); + + error = gfs2_jdata_write_mem(ip, buf, offset, + sizeof(struct gfs2_quota)); + if (error < 0) + goto out_end_trans; + else if (error != sizeof(struct gfs2_quota)) { + error = -EIO; + goto out_end_trans; + } + + do_qc(qd, -qd->qd_change_sync); + + memset(&qd->qd_qb, 0, sizeof(struct gfs2_quota_lvb)); + qd->qd_qb.qb_magic = GFS2_MAGIC; + qd->qd_qb.qb_limit = q.qu_limit; + qd->qd_qb.qb_warn = q.qu_warn; + qd->qd_qb.qb_value = q.qu_value; + + gfs2_quota_lvb_out(&qd->qd_qb, qd->qd_gl->gl_lvb); + } + + error = 0; + + out_end_trans: + gfs2_trans_end(sdp); + + out_ipres: + if (nalloc) + gfs2_inplace_release(ip); + + out_alloc: + if (nalloc) + gfs2_alloc_put(ip); + + out_gunlock: + gfs2_glock_dq_uninit(&i_gh); + + out: + while (qx--) + gfs2_glock_dq_uninit(&ghs[qx]); + kfree(ghs); + gfs2_log_flush_glock(ip->i_gl); + + return error; +} + +static int do_glock(struct gfs2_quota_data *qd, int force_refresh, + struct gfs2_holder *q_gh) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_holder i_gh; + struct gfs2_quota q; + char buf[sizeof(struct gfs2_quota)]; + int error; + + restart: + error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); + if (error) + return error; + + gfs2_quota_lvb_in(&qd->qd_qb, qd->qd_gl->gl_lvb); + + if (force_refresh || qd->qd_qb.qb_magic != GFS2_MAGIC) { + gfs2_glock_dq_uninit(q_gh); + error = gfs2_glock_nq_init(qd->qd_gl, + LM_ST_EXCLUSIVE, GL_NOCACHE, + q_gh); + if (error) + return error; + + error = gfs2_glock_nq_init(sdp->sd_quota_inode->i_gl, + LM_ST_SHARED, 0, + &i_gh); + if (error) + goto fail; + + memset(buf, 0, sizeof(struct gfs2_quota)); + + error = gfs2_jdata_read_mem(sdp->sd_quota_inode, buf, + qd2offset(qd), + sizeof(struct gfs2_quota)); + if (error < 0) + goto fail_gunlock; + + gfs2_glock_dq_uninit(&i_gh); + + gfs2_quota_in(&q, buf); + + memset(&qd->qd_qb, 0, sizeof(struct gfs2_quota_lvb)); + qd->qd_qb.qb_magic = GFS2_MAGIC; + qd->qd_qb.qb_limit = q.qu_limit; + qd->qd_qb.qb_warn = q.qu_warn; + qd->qd_qb.qb_value = q.qu_value; + + gfs2_quota_lvb_out(&qd->qd_qb, qd->qd_gl->gl_lvb); + + if (gfs2_glock_is_blocking(qd->qd_gl)) { + gfs2_glock_dq_uninit(q_gh); + force_refresh = 0; + goto restart; + } + } + + return 0; + + fail_gunlock: + gfs2_glock_dq_uninit(&i_gh); + + fail: + gfs2_glock_dq_uninit(q_gh); + + return error; +} + +int gfs2_quota_lock(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = &ip->i_alloc; + unsigned int x; + int error = 0; + + gfs2_quota_hold(ip, uid, gid); + + if (capable(CAP_SYS_RESOURCE) || + sdp->sd_args.ar_quota != GFS2_QUOTA_ON) + return 0; + + sort(al->al_qd, al->al_qd_num, sizeof(struct gfs2_quota_data *), + sort_qd, NULL); + + for (x = 0; x < al->al_qd_num; x++) { + error = do_glock(al->al_qd[x], NO_FORCE, &al->al_qd_ghs[x]); + if (error) + break; + } + + if (!error) + set_bit(GIF_QD_LOCKED, &ip->i_flags); + else { + while (x--) + gfs2_glock_dq_uninit(&al->al_qd_ghs[x]); + gfs2_quota_unhold(ip); + } + + return error; +} + +static int need_sync(struct gfs2_quota_data *qd) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_tune *gt = &sdp->sd_tune; + int64_t value; + unsigned int num, den; + int do_sync = 1; + + if (!qd->qd_qb.qb_limit) + return 0; + + spin_lock(&sdp->sd_quota_spin); + value = qd->qd_change; + spin_unlock(&sdp->sd_quota_spin); + + spin_lock(>->gt_spin); + num = gt->gt_quota_scale_num; + den = gt->gt_quota_scale_den; + spin_unlock(>->gt_spin); + + if (value < 0) + do_sync = 0; + else if (qd->qd_qb.qb_value >= (int64_t)qd->qd_qb.qb_limit) + do_sync = 0; + else { + value *= gfs2_jindex_size(sdp) * num; + do_div(value, den); + value += qd->qd_qb.qb_value; + if (value < (int64_t)qd->qd_qb.qb_limit) + do_sync = 0; + } + + return do_sync; +} + +void gfs2_quota_unlock(struct gfs2_inode *ip) +{ + struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_quota_data *qda[4]; + unsigned int count = 0; + unsigned int x; + + if (!test_and_clear_bit(GIF_QD_LOCKED, &ip->i_flags)) + goto out; + + for (x = 0; x < al->al_qd_num; x++) { + struct gfs2_quota_data *qd; + int sync; + + qd = al->al_qd[x]; + sync = need_sync(qd); + + gfs2_glock_dq_uninit(&al->al_qd_ghs[x]); + + if (sync && qd_trylock(qd)) + qda[count++] = qd; + } + + if (count) { + do_sync(count, qda); + for (x = 0; x < count; x++) + qd_unlock(qda[x]); + } + + out: + gfs2_quota_unhold(ip); +} + +#define MAX_LINE 256 + +static int print_message(struct gfs2_quota_data *qd, char *type) +{ + struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + char *line; + int len; + + line = kmalloc(MAX_LINE, GFP_KERNEL); + if (!line) + return -ENOMEM; + + len = snprintf(line, MAX_LINE-1, "GFS2: fsid=%s: quota %s for %s %u\r\n", + sdp->sd_fsname, type, + (test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group", + qd->qd_id); + line[MAX_LINE-1] = 0; + + if (current->signal) { /* Is this test still required? */ + tty_write_message(current->signal->tty, line); + } + + kfree(line); + + return 0; +} + +int gfs2_quota_check(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_quota_data *qd; + int64_t value; + unsigned int x; + int error = 0; + + if (!test_bit(GIF_QD_LOCKED, &ip->i_flags)) + return 0; + + if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON) + return 0; + + for (x = 0; x < al->al_qd_num; x++) { + qd = al->al_qd[x]; + + if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) || + (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags)))) + continue; + + value = qd->qd_qb.qb_value; + spin_lock(&sdp->sd_quota_spin); + value += qd->qd_change; + spin_unlock(&sdp->sd_quota_spin); + + if (qd->qd_qb.qb_limit && (int64_t)qd->qd_qb.qb_limit < value) { + print_message(qd, "exceeded"); + error = -EDQUOT; + break; + } else if (qd->qd_qb.qb_warn && + (int64_t)qd->qd_qb.qb_warn < value && + time_after_eq(jiffies, qd->qd_last_warn + + gfs2_tune_get(sdp, gt_quota_warn_period) * HZ)) { + error = print_message(qd, "warning"); + qd->qd_last_warn = jiffies; + } + } + + return error; +} + +void gfs2_quota_change(struct gfs2_inode *ip, int64_t change, + uint32_t uid, uint32_t gid) +{ + struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_quota_data *qd; + unsigned int x; + unsigned int found = 0; + + if (gfs2_assert_warn(ip->i_sbd, change)) + return; + if (ip->i_di.di_flags & GFS2_DIF_SYSTEM) + return; + + for (x = 0; x < al->al_qd_num; x++) { + qd = al->al_qd[x]; + + if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) || + (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) { + do_qc(qd, change); + found++; + } + } +} + +int gfs2_quota_sync(struct gfs2_sbd *sdp) +{ + struct gfs2_quota_data **qda; + unsigned int max_qd = gfs2_tune_get(sdp, gt_quota_simul_sync); + unsigned int num_qd; + unsigned int x; + int error = 0; + + sdp->sd_quota_sync_gen++; + + qda = kcalloc(max_qd, sizeof(struct gfs2_quota_data *), GFP_KERNEL); + if (!qda) + return -ENOMEM; + + do { + num_qd = 0; + + for (;;) { + error = qd_fish(sdp, qda + num_qd); + if (error || !qda[num_qd]) + break; + if (++num_qd == max_qd) + break; + } + + if (num_qd) { + if (!error) + error = do_sync(num_qd, qda); + if (!error) + for (x = 0; x < num_qd; x++) + qda[x]->qd_sync_gen = + sdp->sd_quota_sync_gen; + + for (x = 0; x < num_qd; x++) + qd_unlock(qda[x]); + } + } while (!error && num_qd == max_qd); + + kfree(qda); + + return error; +} + +int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, uint32_t id) +{ + struct gfs2_quota_data *qd; + struct gfs2_holder q_gh; + int error; + + error = qd_get(sdp, user, id, CREATE, &qd); + if (error) + return error; + + error = do_glock(qd, FORCE, &q_gh); + if (!error) + gfs2_glock_dq_uninit(&q_gh); + + qd_put(qd); + + return error; +} + +int gfs2_quota_read(struct gfs2_sbd *sdp, int user, uint32_t id, + struct gfs2_quota *q) +{ + struct gfs2_quota_data *qd; + struct gfs2_holder q_gh; + int error; + + if (((user) ? (id != current->fsuid) : (!in_group_p(id))) && + !capable(CAP_SYS_ADMIN)) + return -EACCES; + + error = qd_get(sdp, user, id, CREATE, &qd); + if (error) + return error; + + error = do_glock(qd, NO_FORCE, &q_gh); + if (error) + goto out; + + memset(q, 0, sizeof(struct gfs2_quota)); + q->qu_limit = qd->qd_qb.qb_limit; + q->qu_warn = qd->qd_qb.qb_warn; + q->qu_value = qd->qd_qb.qb_value; + + spin_lock(&sdp->sd_quota_spin); + q->qu_value += qd->qd_change; + spin_unlock(&sdp->sd_quota_spin); + + gfs2_glock_dq_uninit(&q_gh); + + out: + qd_put(qd); + + return error; +} + +int gfs2_quota_init(struct gfs2_sbd *sdp) +{ + struct gfs2_inode *ip = sdp->sd_qc_inode; + unsigned int blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; + unsigned int x, slot = 0; + unsigned int found = 0; + uint64_t dblock; + uint32_t extlen = 0; + int error; + + if (!ip->i_di.di_size || + ip->i_di.di_size > (64 << 20) || + ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1)) { + gfs2_consist_inode(ip); + return -EIO; + } + sdp->sd_quota_slots = blocks * sdp->sd_qc_per_block; + sdp->sd_quota_chunks = DIV_RU(sdp->sd_quota_slots, 8 * PAGE_SIZE); + + error = -ENOMEM; + + sdp->sd_quota_bitmap = kcalloc(sdp->sd_quota_chunks, + sizeof(unsigned char *), GFP_KERNEL); + if (!sdp->sd_quota_bitmap) + return error; + + for (x = 0; x < sdp->sd_quota_chunks; x++) { + sdp->sd_quota_bitmap[x] = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!sdp->sd_quota_bitmap[x]) + goto fail; + } + + for (x = 0; x < blocks; x++) { + struct buffer_head *bh; + unsigned int y; + + if (!extlen) { + int new = 0; + error = gfs2_block_map(ip, x, &new, &dblock, &extlen); + if (error) + goto fail; + } + gfs2_meta_ra(ip->i_gl, dblock, extlen); + error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, + &bh); + if (error) + goto fail; + error = -EIO; + if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC)) { + brelse(bh); + goto fail; + } + + for (y = 0; + y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots; + y++, slot++) { + struct gfs2_quota_change qc; + struct gfs2_quota_data *qd; + + gfs2_quota_change_in(&qc, bh->b_data + + sizeof(struct gfs2_meta_header) + + y * sizeof(struct gfs2_quota_change)); + if (!qc.qc_change) + continue; + + error = qd_alloc(sdp, (qc.qc_flags & GFS2_QCF_USER), + qc.qc_id, &qd); + if (error) { + brelse(bh); + goto fail; + } + + set_bit(QDF_CHANGE, &qd->qd_flags); + qd->qd_change = qc.qc_change; + qd->qd_slot = slot; + qd->qd_slot_count = 1; + qd->qd_last_touched = jiffies; + + spin_lock(&sdp->sd_quota_spin); + gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, slot, 1); + list_add(&qd->qd_list, &sdp->sd_quota_list); + atomic_inc(&sdp->sd_quota_count); + spin_unlock(&sdp->sd_quota_spin); + + found++; + } + + brelse(bh); + dblock++; + extlen--; + } + + if (found) + fs_info(sdp, "found %u quota changes\n", found); + + return 0; + + fail: + gfs2_quota_cleanup(sdp); + return error; +} + +void gfs2_quota_scan(struct gfs2_sbd *sdp) +{ + struct gfs2_quota_data *qd, *safe; + LIST_HEAD(dead); + + spin_lock(&sdp->sd_quota_spin); + list_for_each_entry_safe(qd, safe, &sdp->sd_quota_list, qd_list) { + if (!qd->qd_count && + time_after_eq(jiffies, qd->qd_last_touched + + gfs2_tune_get(sdp, gt_quota_cache_secs) * HZ)) { + list_move(&qd->qd_list, &dead); + gfs2_assert_warn(sdp, + atomic_read(&sdp->sd_quota_count) > 0); + atomic_dec(&sdp->sd_quota_count); + } + } + spin_unlock(&sdp->sd_quota_spin); + + while (!list_empty(&dead)) { + qd = list_entry(dead.next, struct gfs2_quota_data, qd_list); + list_del(&qd->qd_list); + + gfs2_assert_warn(sdp, !qd->qd_change); + gfs2_assert_warn(sdp, !qd->qd_slot_count); + gfs2_assert_warn(sdp, !qd->qd_bh_count); + + gfs2_lvb_unhold(qd->qd_gl); + kfree(qd); + } +} + +void gfs2_quota_cleanup(struct gfs2_sbd *sdp) +{ + struct list_head *head = &sdp->sd_quota_list; + struct gfs2_quota_data *qd; + unsigned int x; + + spin_lock(&sdp->sd_quota_spin); + while (!list_empty(head)) { + qd = list_entry(head->prev, struct gfs2_quota_data, qd_list); + + if (qd->qd_count > 1 || + (qd->qd_count && !test_bit(QDF_CHANGE, &qd->qd_flags))) { + list_move(&qd->qd_list, head); + spin_unlock(&sdp->sd_quota_spin); + schedule(); + spin_lock(&sdp->sd_quota_spin); + continue; + } + + list_del(&qd->qd_list); + atomic_dec(&sdp->sd_quota_count); + spin_unlock(&sdp->sd_quota_spin); + + if (!qd->qd_count) { + gfs2_assert_warn(sdp, !qd->qd_change); + gfs2_assert_warn(sdp, !qd->qd_slot_count); + } else + gfs2_assert_warn(sdp, qd->qd_slot_count == 1); + gfs2_assert_warn(sdp, !qd->qd_bh_count); + + gfs2_lvb_unhold(qd->qd_gl); + kfree(qd); + + spin_lock(&sdp->sd_quota_spin); + } + spin_unlock(&sdp->sd_quota_spin); + + gfs2_assert_warn(sdp, !atomic_read(&sdp->sd_quota_count)); + + if (sdp->sd_quota_bitmap) { + for (x = 0; x < sdp->sd_quota_chunks; x++) + kfree(sdp->sd_quota_bitmap[x]); + kfree(sdp->sd_quota_bitmap); + } +} + diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h new file mode 100644 index 000000000000..005529f6895d --- /dev/null +++ b/fs/gfs2/quota.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __QUOTA_DOT_H__ +#define __QUOTA_DOT_H__ + +#define NO_QUOTA_CHANGE ((uint32_t)-1) + +int gfs2_quota_hold(struct gfs2_inode *ip, uint32_t uid, uint32_t gid); +void gfs2_quota_unhold(struct gfs2_inode *ip); + +int gfs2_quota_lock(struct gfs2_inode *ip, uint32_t uid, uint32_t gid); +void gfs2_quota_unlock(struct gfs2_inode *ip); + +int gfs2_quota_check(struct gfs2_inode *ip, uint32_t uid, uint32_t gid); +void gfs2_quota_change(struct gfs2_inode *ip, int64_t change, + uint32_t uid, uint32_t gid); + +int gfs2_quota_sync(struct gfs2_sbd *sdp); +int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, uint32_t id); +int gfs2_quota_read(struct gfs2_sbd *sdp, int user, uint32_t id, + struct gfs2_quota *q); + +int gfs2_quota_init(struct gfs2_sbd *sdp); +void gfs2_quota_scan(struct gfs2_sbd *sdp); +void gfs2_quota_cleanup(struct gfs2_sbd *sdp); + +#endif /* __QUOTA_DOT_H__ */ diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c new file mode 100644 index 000000000000..15cd26fbcff9 --- /dev/null +++ b/fs/gfs2/recovery.c @@ -0,0 +1,570 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "glock.h" +#include "glops.h" +#include "lm.h" +#include "lops.h" +#include "meta_io.h" +#include "recovery.h" +#include "super.h" + +int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, + struct buffer_head **bh) +{ + struct gfs2_glock *gl = jd->jd_inode->i_gl; + int new = 0; + uint64_t dblock; + uint32_t extlen; + int error; + + error = gfs2_block_map(jd->jd_inode, blk, &new, &dblock, &extlen); + if (error) + return error; + if (!dblock) { + gfs2_consist_inode(jd->jd_inode); + return -EIO; + } + + gfs2_meta_ra(gl, dblock, extlen); + error = gfs2_meta_read(gl, dblock, DIO_START | DIO_WAIT, bh); + + return error; +} + +int gfs2_revoke_add(struct gfs2_sbd *sdp, uint64_t blkno, unsigned int where) +{ + struct list_head *head = &sdp->sd_revoke_list; + struct gfs2_revoke_replay *rr; + int found = 0; + + list_for_each_entry(rr, head, rr_list) { + if (rr->rr_blkno == blkno) { + found = 1; + break; + } + } + + if (found) { + rr->rr_where = where; + return 0; + } + + rr = kmalloc(sizeof(struct gfs2_revoke_replay), GFP_KERNEL); + if (!rr) + return -ENOMEM; + + rr->rr_blkno = blkno; + rr->rr_where = where; + list_add(&rr->rr_list, head); + + return 1; +} + +int gfs2_revoke_check(struct gfs2_sbd *sdp, uint64_t blkno, unsigned int where) +{ + struct gfs2_revoke_replay *rr; + int wrap, a, b, revoke; + int found = 0; + + list_for_each_entry(rr, &sdp->sd_revoke_list, rr_list) { + if (rr->rr_blkno == blkno) { + found = 1; + break; + } + } + + if (!found) + return 0; + + wrap = (rr->rr_where < sdp->sd_replay_tail); + a = (sdp->sd_replay_tail < where); + b = (where < rr->rr_where); + revoke = (wrap) ? (a || b) : (a && b); + + return revoke; +} + +void gfs2_revoke_clean(struct gfs2_sbd *sdp) +{ + struct list_head *head = &sdp->sd_revoke_list; + struct gfs2_revoke_replay *rr; + + while (!list_empty(head)) { + rr = list_entry(head->next, struct gfs2_revoke_replay, rr_list); + list_del(&rr->rr_list); + kfree(rr); + } +} + +/** + * get_log_header - read the log header for a given segment + * @jd: the journal + * @blk: the block to look at + * @lh: the log header to return + * + * Read the log header for a given segement in a given journal. Do a few + * sanity checks on it. + * + * Returns: 0 on success, + * 1 if the header was invalid or incomplete, + * errno on error + */ + +static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, + struct gfs2_log_header *head) +{ + struct buffer_head *bh; + struct gfs2_log_header lh; + uint32_t hash; + int error; + + error = gfs2_replay_read_block(jd, blk, &bh); + if (error) + return error; + + memcpy(&lh, bh->b_data, sizeof(struct gfs2_log_header)); + lh.lh_hash = 0; + hash = gfs2_disk_hash((char *)&lh, sizeof(struct gfs2_log_header)); + gfs2_log_header_in(&lh, bh->b_data); + + brelse(bh); + + if (lh.lh_header.mh_magic != GFS2_MAGIC || + lh.lh_header.mh_type != GFS2_METATYPE_LH || + lh.lh_blkno != blk || + lh.lh_hash != hash) + return 1; + + *head = lh; + + return 0; +} + +/** + * find_good_lh - find a good log header + * @jd: the journal + * @blk: the segment to start searching from + * @lh: the log header to fill in + * @forward: if true search forward in the log, else search backward + * + * Call get_log_header() to get a log header for a segment, but if the + * segment is bad, either scan forward or backward until we find a good one. + * + * Returns: errno + */ + +static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk, + struct gfs2_log_header *head) +{ + unsigned int orig_blk = *blk; + int error; + + for (;;) { + error = get_log_header(jd, *blk, head); + if (error <= 0) + return error; + + if (++*blk == jd->jd_blocks) + *blk = 0; + + if (*blk == orig_blk) { + gfs2_consist_inode(jd->jd_inode); + return -EIO; + } + } +} + +/** + * jhead_scan - make sure we've found the head of the log + * @jd: the journal + * @head: this is filled in with the log descriptor of the head + * + * At this point, seg and lh should be either the head of the log or just + * before. Scan forward until we find the head. + * + * Returns: errno + */ + +static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head) +{ + unsigned int blk = head->lh_blkno; + struct gfs2_log_header lh; + int error; + + for (;;) { + if (++blk == jd->jd_blocks) + blk = 0; + + error = get_log_header(jd, blk, &lh); + if (error < 0) + return error; + if (error == 1) + continue; + + if (lh.lh_sequence == head->lh_sequence) { + gfs2_consist_inode(jd->jd_inode); + return -EIO; + } + if (lh.lh_sequence < head->lh_sequence) + break; + + *head = lh; + } + + return 0; +} + +/** + * gfs2_find_jhead - find the head of a log + * @jd: the journal + * @head: the log descriptor for the head of the log is returned here + * + * Do a binary search of a journal and find the valid log entry with the + * highest sequence number. (i.e. the log head) + * + * Returns: errno + */ + +int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header *head) +{ + struct gfs2_log_header lh_1, lh_m; + uint32_t blk_1, blk_2, blk_m; + int error; + + blk_1 = 0; + blk_2 = jd->jd_blocks - 1; + + for (;;) { + blk_m = (blk_1 + blk_2) / 2; + + error = find_good_lh(jd, &blk_1, &lh_1); + if (error) + return error; + + error = find_good_lh(jd, &blk_m, &lh_m); + if (error) + return error; + + if (blk_1 == blk_m || blk_m == blk_2) + break; + + if (lh_1.lh_sequence <= lh_m.lh_sequence) + blk_1 = blk_m; + else + blk_2 = blk_m; + } + + error = jhead_scan(jd, &lh_1); + if (error) + return error; + + *head = lh_1; + + return error; +} + +/** + * foreach_descriptor - go through the active part of the log + * @jd: the journal + * @start: the first log header in the active region + * @end: the last log header (don't process the contents of this entry)) + * + * Call a given function once for every log descriptor in the active + * portion of the log. + * + * Returns: errno + */ + +static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, + unsigned int end, int pass) +{ + struct gfs2_sbd *sdp = jd->jd_inode->i_sbd; + struct buffer_head *bh; + struct gfs2_log_descriptor *ld; + int error = 0; + u32 length; + __be64 *ptr; + unsigned int offset = sizeof(struct gfs2_log_descriptor); + offset += (sizeof(__be64)-1); + offset &= ~(sizeof(__be64)-1); + + while (start != end) { + error = gfs2_replay_read_block(jd, start, &bh); + if (error) + return error; + if (gfs2_meta_check(sdp, bh)) { + brelse(bh); + return -EIO; + } + ld = (struct gfs2_log_descriptor *)bh->b_data; + length = be32_to_cpu(ld->ld_length); + + if (be16_to_cpu(ld->ld_header.mh_type) == GFS2_METATYPE_LH) { + struct gfs2_log_header lh; + error = get_log_header(jd, start, &lh); + if (!error) { + gfs2_replay_incr_blk(sdp, &start); + continue; + } + if (error == 1) { + gfs2_consist_inode(jd->jd_inode); + error = -EIO; + } + brelse(bh); + return error; + } else if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_LD)) { + brelse(bh); + return -EIO; + } + ptr = (__be64 *)(bh->b_data + offset); + error = lops_scan_elements(jd, start, ld, ptr, pass); + if (error) { + brelse(bh); + return error; + } + + while (length--) + gfs2_replay_incr_blk(sdp, &start); + + brelse(bh); + } + + return 0; +} + +/** + * clean_journal - mark a dirty journal as being clean + * @sdp: the filesystem + * @jd: the journal + * @gl: the journal's glock + * @head: the head journal to start from + * + * Returns: errno + */ + +static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) +{ + struct gfs2_inode *ip = jd->jd_inode; + struct gfs2_sbd *sdp = ip->i_sbd; + unsigned int lblock; + int new = 0; + uint64_t dblock; + struct gfs2_log_header *lh; + uint32_t hash; + struct buffer_head *bh; + int error; + + lblock = head->lh_blkno; + gfs2_replay_incr_blk(sdp, &lblock); + error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); + if (error) + return error; + if (!dblock) { + gfs2_consist_inode(ip); + return -EIO; + } + + bh = sb_getblk(sdp->sd_vfs, dblock); + lock_buffer(bh); + memset(bh->b_data, 0, bh->b_size); + set_buffer_uptodate(bh); + clear_buffer_dirty(bh); + unlock_buffer(bh); + + lh = (struct gfs2_log_header *)bh->b_data; + memset(lh, 0, sizeof(struct gfs2_log_header)); + lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + lh->lh_header.mh_type = cpu_to_be16(GFS2_METATYPE_LH); + lh->lh_header.mh_format = cpu_to_be16(GFS2_FORMAT_LH); + lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1); + lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT); + lh->lh_blkno = cpu_to_be32(lblock); + hash = gfs2_disk_hash((const char *)lh, sizeof(struct gfs2_log_header)); + lh->lh_hash = cpu_to_be32(hash); + + set_buffer_dirty(bh); + if (sync_dirty_buffer(bh)) + gfs2_io_error_bh(sdp, bh); + brelse(bh); + + return error; +} + +/** + * gfs2_recover_journal - recovery a given journal + * @jd: the struct gfs2_jdesc describing the journal + * @wait: Don't return until the journal is clean (or an error is encountered) + * + * Acquire the journal's lock, check to see if the journal is clean, and + * do recovery if necessary. + * + * Returns: errno + */ + +int gfs2_recover_journal(struct gfs2_jdesc *jd, int wait) +{ + struct gfs2_sbd *sdp = jd->jd_inode->i_sbd; + struct gfs2_log_header head; + struct gfs2_holder j_gh, ji_gh, t_gh; + unsigned long t; + int ro = 0; + unsigned int pass; + int error; + + fs_info(sdp, "jid=%u: Trying to acquire journal lock...\n", jd->jd_jid); + + /* Aquire the journal lock so we can do recovery */ + + error = gfs2_glock_nq_num(sdp, + jd->jd_jid, &gfs2_journal_glops, + LM_ST_EXCLUSIVE, + LM_FLAG_NOEXP | + ((wait) ? 0 : LM_FLAG_TRY) | + GL_NOCACHE, &j_gh); + switch (error) { + case 0: + break; + + case GLR_TRYFAILED: + fs_info(sdp, "jid=%u: Busy\n", jd->jd_jid); + error = 0; + + default: + goto fail; + }; + + error = gfs2_glock_nq_init(jd->jd_inode->i_gl, LM_ST_SHARED, + LM_FLAG_NOEXP, &ji_gh); + if (error) + goto fail_gunlock_j; + + fs_info(sdp, "jid=%u: Looking at journal...\n", jd->jd_jid); + + error = gfs2_jdesc_check(jd); + if (error) + goto fail_gunlock_ji; + + error = gfs2_find_jhead(jd, &head); + if (error) + goto fail_gunlock_ji; + + if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) { + fs_info(sdp, "jid=%u: Acquiring the transaction lock...\n", + jd->jd_jid); + + t = jiffies; + + /* Acquire a shared hold on the transaction lock */ + + error = gfs2_glock_nq_init(sdp->sd_trans_gl, + LM_ST_SHARED, + LM_FLAG_NOEXP | + LM_FLAG_PRIORITY | + GL_NEVER_RECURSE | + GL_NOCANCEL | + GL_NOCACHE, + &t_gh); + if (error) + goto fail_gunlock_ji; + + if (test_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags)) { + if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) + ro = 1; + } else { + if (sdp->sd_vfs->s_flags & MS_RDONLY) + ro = 1; + } + + if (ro) { + fs_warn(sdp, "jid=%u: Can't replay: read-only FS\n", + jd->jd_jid); + error = -EROFS; + goto fail_gunlock_tr; + } + + fs_info(sdp, "jid=%u: Replaying journal...\n", jd->jd_jid); + + for (pass = 0; pass < 2; pass++) { + lops_before_scan(jd, &head, pass); + error = foreach_descriptor(jd, head.lh_tail, + head.lh_blkno, pass); + lops_after_scan(jd, error, pass); + if (error) + goto fail_gunlock_tr; + } + + error = clean_journal(jd, &head); + if (error) + goto fail_gunlock_tr; + + gfs2_glock_dq_uninit(&t_gh); + + t = DIV_RU(jiffies - t, HZ); + + fs_info(sdp, "jid=%u: Journal replayed in %lus\n", + jd->jd_jid, t); + } + + gfs2_glock_dq_uninit(&ji_gh); + + gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS); + + gfs2_glock_dq_uninit(&j_gh); + + fs_info(sdp, "jid=%u: Done\n", jd->jd_jid); + + return 0; + + fail_gunlock_tr: + gfs2_glock_dq_uninit(&t_gh); + + fail_gunlock_ji: + gfs2_glock_dq_uninit(&ji_gh); + + fail_gunlock_j: + gfs2_glock_dq_uninit(&j_gh); + + fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done"); + + fail: + gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); + + return error; +} + +/** + * gfs2_check_journals - Recover any dirty journals + * @sdp: the filesystem + * + */ + +void gfs2_check_journals(struct gfs2_sbd *sdp) +{ + struct gfs2_jdesc *jd; + + for (;;) { + jd = gfs2_jdesc_find_dirty(sdp); + if (!jd) + break; + + if (jd != sdp->sd_jdesc) + gfs2_recover_journal(jd, NO_WAIT); + } +} + diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h new file mode 100644 index 000000000000..50d7eb57881c --- /dev/null +++ b/fs/gfs2/recovery.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __RECOVERY_DOT_H__ +#define __RECOVERY_DOT_H__ + +static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk) +{ + if (++*blk == sdp->sd_jdesc->jd_blocks) + *blk = 0; +} + +int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, + struct buffer_head **bh); + +int gfs2_revoke_add(struct gfs2_sbd *sdp, uint64_t blkno, unsigned int where); +int gfs2_revoke_check(struct gfs2_sbd *sdp, uint64_t blkno, unsigned int where); +void gfs2_revoke_clean(struct gfs2_sbd *sdp); + +int gfs2_find_jhead(struct gfs2_jdesc *jd, + struct gfs2_log_header *head); +int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, int wait); +void gfs2_check_journals(struct gfs2_sbd *sdp); + +#endif /* __RECOVERY_DOT_H__ */ + diff --git a/fs/gfs2/resize.c b/fs/gfs2/resize.c new file mode 100644 index 000000000000..67d26b99a73c --- /dev/null +++ b/fs/gfs2/resize.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "dir.h" +#include "glock.h" +#include "inode.h" +#include "jdata.h" +#include "meta_io.h" +#include "quota.h" +#include "resize.h" +#include "rgrp.h" +#include "super.h" +#include "trans.h" + +/* A single transaction needs to add the structs to rindex and make the + statfs change. */ + +int gfs2_resize_add_rgrps(struct gfs2_sbd *sdp, char __user *buf, + unsigned int size) +{ + unsigned int num = size / sizeof(struct gfs2_rindex); + struct gfs2_inode *ip = sdp->sd_rindex; + struct gfs2_alloc *al = NULL; + struct gfs2_holder i_gh; + unsigned int data_blocks, ind_blocks; + int alloc_required; + unsigned int x; + int error; + + gfs2_write_calc_reserv(ip, size, &data_blocks, &ind_blocks); + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, + LM_FLAG_PRIORITY | GL_SYNC, &i_gh); + if (error) + return error; + + if (!gfs2_is_jdata(ip)) { + gfs2_consist_inode(ip); + error = -EIO; + goto out; + } + + error = gfs2_write_alloc_required(ip, ip->i_di.di_size, size, + &alloc_required); + if (error) + goto out; + + if (alloc_required) { + al = gfs2_alloc_get(ip); + + al->al_requested = data_blocks + ind_blocks; + + error = gfs2_inplace_reserve(ip); + if (error) + goto out_alloc; + + error = gfs2_trans_begin(sdp, + al->al_rgd->rd_ri.ri_length + + data_blocks + ind_blocks + + RES_DINODE + RES_STATFS, 0); + if (error) + goto out_relse; + } else { + error = gfs2_trans_begin(sdp, data_blocks + + RES_DINODE + RES_STATFS, 0); + if (error) + goto out; + } + + for (x = 0; x < num; x++) { + struct gfs2_rindex ri; + char ri_buf[sizeof(struct gfs2_rindex)]; + + error = copy_from_user(&ri, buf, sizeof(struct gfs2_rindex)); + if (error) { + error = -EFAULT; + goto out_trans; + } + gfs2_rindex_out(&ri, ri_buf); + + error = gfs2_jdata_write_mem(ip, ri_buf, ip->i_di.di_size, + sizeof(struct gfs2_rindex)); + if (error < 0) + goto out_trans; + gfs2_assert_withdraw(sdp, error == sizeof(struct gfs2_rindex)); + error = 0; + + gfs2_statfs_change(sdp, ri.ri_data, ri.ri_data, 0); + + buf += sizeof(struct gfs2_rindex); + } + + out_trans: + gfs2_trans_end(sdp); + + out_relse: + if (alloc_required) + gfs2_inplace_release(ip); + + out_alloc: + if (alloc_required) + gfs2_alloc_put(ip); + + out: + ip->i_gl->gl_vn++; + gfs2_glock_dq_uninit(&i_gh); + + return error; +} + +static void drop_dentries(struct gfs2_inode *ip) +{ + struct inode *inode; + struct dentry *d; + + inode = gfs2_ip2v_lookup(ip); + if (!inode) + return; + + restart: + spin_lock(&dcache_lock); + list_for_each_entry(d, &inode->i_dentry, d_alias) { + if (d_unhashed(d)) + continue; + dget_locked(d); + __d_drop(d); + spin_unlock(&dcache_lock); + dput(d); + goto restart; + } + spin_unlock(&dcache_lock); + + iput(inode); +} + +/* This is called by an ioctl to rename an ordinary file that's represented + in the vfs to a hidden system file that isn't represented in the vfs. It's + used to add journals, along with the associated system files, to a fs. */ + +int gfs2_rename2system(struct gfs2_inode *ip, + struct gfs2_inode *old_dip, char *old_name, + struct gfs2_inode *new_dip, char *new_name) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_holder ghs[3]; + struct qstr old_qstr, new_qstr; + struct gfs2_inum inum; + int alloc_required; + struct buffer_head *dibh; + int error; + + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, ghs); + gfs2_holder_init(old_dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); + gfs2_holder_init(new_dip->i_gl, LM_ST_EXCLUSIVE, GL_SYNC, ghs + 2); + + error = gfs2_glock_nq_m(3, ghs); + if (error) + goto out; + + error = -EMLINK; + if (ip->i_di.di_nlink != 1) + goto out_gunlock; + error = -EINVAL; + if (!S_ISREG(ip->i_di.di_mode)) + goto out_gunlock; + + old_qstr.name = old_name; + old_qstr.len = strlen(old_name); + error = gfs2_dir_search(old_dip, &old_qstr, &inum, NULL); + switch (error) { + case 0: + break; + default: + goto out_gunlock; + } + + error = -EINVAL; + if (!gfs2_inum_equal(&inum, &ip->i_num)) + goto out_gunlock; + + new_qstr.name = new_name; + new_qstr.len = strlen(new_name); + error = gfs2_dir_search(new_dip, &new_qstr, NULL, NULL); + switch (error) { + case -ENOENT: + break; + case 0: + error = -EEXIST; + default: + goto out_gunlock; + } + + gfs2_alloc_get(ip); + + error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out_alloc; + + error = gfs2_diradd_alloc_required(new_dip, &new_qstr, &alloc_required); + if (error) + goto out_unhold; + + if (alloc_required) { + struct gfs2_alloc *al = gfs2_alloc_get(new_dip); + + al->al_requested = sdp->sd_max_dirres; + + error = gfs2_inplace_reserve(new_dip); + if (error) + goto out_alloc2; + + error = gfs2_trans_begin(sdp, + sdp->sd_max_dirres + + al->al_rgd->rd_ri.ri_length + + 3 * RES_DINODE + RES_LEAF + + RES_STATFS + RES_QUOTA, 0); + if (error) + goto out_ipreserv; + } else { + error = gfs2_trans_begin(sdp, + 3 * RES_DINODE + 2 * RES_LEAF + + RES_QUOTA, 0); + if (error) + goto out_unhold; + } + + error = gfs2_dir_del(old_dip, &old_qstr); + if (error) + goto out_trans; + + error = gfs2_dir_add(new_dip, &new_qstr, &ip->i_num, + IF2DT(ip->i_di.di_mode)); + if (error) + goto out_trans; + + gfs2_quota_change(ip, -ip->i_di.di_blocks, ip->i_di.di_uid, + ip->i_di.di_gid); + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out_trans; + ip->i_di.di_flags |= GFS2_DIF_SYSTEM; + gfs2_trans_add_bh(ip->i_gl, dibh); + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + drop_dentries(ip); + + out_trans: + gfs2_trans_end(sdp); + + out_ipreserv: + if (alloc_required) + gfs2_inplace_release(new_dip); + + out_alloc2: + if (alloc_required) + gfs2_alloc_put(new_dip); + + out_unhold: + gfs2_quota_unhold(ip); + + out_alloc: + gfs2_alloc_put(ip); + + out_gunlock: + gfs2_glock_dq_m(3, ghs); + + out: + gfs2_holder_uninit(ghs); + gfs2_holder_uninit(ghs + 1); + gfs2_holder_uninit(ghs + 2); + + return error; +} + diff --git a/fs/gfs2/resize.h b/fs/gfs2/resize.h new file mode 100644 index 000000000000..bb97f0501598 --- /dev/null +++ b/fs/gfs2/resize.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __RESIZE_DOT_H__ +#define __RESIZE_DOT_H__ + +int gfs2_resize_add_rgrps(struct gfs2_sbd *sdp, char __user *buf, + unsigned int size); +int gfs2_rename2system(struct gfs2_inode *ip, + struct gfs2_inode *old_dip, char *old_name, + struct gfs2_inode *new_dip, char *new_name); + +#endif /* __RESIZE_DOT_H__ */ diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c new file mode 100644 index 000000000000..8df6fba20fac --- /dev/null +++ b/fs/gfs2/rgrp.c @@ -0,0 +1,1361 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bits.h" +#include "glock.h" +#include "glops.h" +#include "jdata.h" +#include "lops.h" +#include "meta_io.h" +#include "quota.h" +#include "rgrp.h" +#include "super.h" +#include "trans.h" + +/** + * gfs2_rgrp_verify - Verify that a resource group is consistent + * @sdp: the filesystem + * @rgd: the rgrp + * + */ + +void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd) +{ + struct gfs2_sbd *sdp = rgd->rd_sbd; + struct gfs2_bitmap *bi = NULL; + uint32_t length = rgd->rd_ri.ri_length; + uint32_t count[4], tmp; + int buf, x; + + memset(count, 0, 4 * sizeof(uint32_t)); + + /* Count # blocks in each of 4 possible allocation states */ + for (buf = 0; buf < length; buf++) { + bi = rgd->rd_bits + buf; + for (x = 0; x < 4; x++) + count[x] += gfs2_bitcount(rgd, + bi->bi_bh->b_data + + bi->bi_offset, + bi->bi_len, x); + } + + if (count[0] != rgd->rd_rg.rg_free) { + if (gfs2_consist_rgrpd(rgd)) + fs_err(sdp, "free data mismatch: %u != %u\n", + count[0], rgd->rd_rg.rg_free); + return; + } + + tmp = rgd->rd_ri.ri_data - + rgd->rd_rg.rg_free - + rgd->rd_rg.rg_dinodes; + if (count[1] != tmp) { + if (gfs2_consist_rgrpd(rgd)) + fs_err(sdp, "used data mismatch: %u != %u\n", + count[1], tmp); + return; + } + + if (count[2]) { + if (gfs2_consist_rgrpd(rgd)) + fs_err(sdp, "free metadata mismatch: %u != 0\n", + count[2]); + return; + } + + if (count[3] != rgd->rd_rg.rg_dinodes) { + if (gfs2_consist_rgrpd(rgd)) + fs_err(sdp, "used metadata mismatch: %u != %u\n", + count[3], rgd->rd_rg.rg_dinodes); + return; + } +} + +static inline int rgrp_contains_block(struct gfs2_rindex *ri, uint64_t block) +{ + uint64_t first = ri->ri_data0; + uint64_t last = first + ri->ri_data; + return !!(first <= block && block < last); +} + +/** + * gfs2_blk2rgrpd - Find resource group for a given data/meta block number + * @sdp: The GFS2 superblock + * @n: The data block number + * + * Returns: The resource group, or NULL if not found + */ + +struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, uint64_t blk) +{ + struct gfs2_rgrpd *rgd; + + spin_lock(&sdp->sd_rindex_spin); + + list_for_each_entry(rgd, &sdp->sd_rindex_mru_list, rd_list_mru) { + if (rgrp_contains_block(&rgd->rd_ri, blk)) { + list_move(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list); + spin_unlock(&sdp->sd_rindex_spin); + return rgd; + } + } + + spin_unlock(&sdp->sd_rindex_spin); + + return NULL; +} + +/** + * gfs2_rgrpd_get_first - get the first Resource Group in the filesystem + * @sdp: The GFS2 superblock + * + * Returns: The first rgrp in the filesystem + */ + +struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp) +{ + gfs2_assert(sdp, !list_empty(&sdp->sd_rindex_list)); + return list_entry(sdp->sd_rindex_list.next, struct gfs2_rgrpd, rd_list); +} + +/** + * gfs2_rgrpd_get_next - get the next RG + * @rgd: A RG + * + * Returns: The next rgrp + */ + +struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd) +{ + if (rgd->rd_list.next == &rgd->rd_sbd->sd_rindex_list) + return NULL; + return list_entry(rgd->rd_list.next, struct gfs2_rgrpd, rd_list); +} + +static void clear_rgrpdi(struct gfs2_sbd *sdp) +{ + struct list_head *head; + struct gfs2_rgrpd *rgd; + struct gfs2_glock *gl; + + spin_lock(&sdp->sd_rindex_spin); + sdp->sd_rindex_forward = NULL; + head = &sdp->sd_rindex_recent_list; + while (!list_empty(head)) { + rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent); + list_del(&rgd->rd_recent); + } + spin_unlock(&sdp->sd_rindex_spin); + + head = &sdp->sd_rindex_list; + while (!list_empty(head)) { + rgd = list_entry(head->next, struct gfs2_rgrpd, rd_list); + gl = rgd->rd_gl; + + list_del(&rgd->rd_list); + list_del(&rgd->rd_list_mru); + + if (gl) { + set_gl2rgd(gl, NULL); + gfs2_glock_put(gl); + } + + kfree(rgd->rd_bits); + kfree(rgd); + } +} + +void gfs2_clear_rgrpd(struct gfs2_sbd *sdp) +{ + down(&sdp->sd_rindex_mutex); + clear_rgrpdi(sdp); + up(&sdp->sd_rindex_mutex); +} + +/** + * gfs2_compute_bitstructs - Compute the bitmap sizes + * @rgd: The resource group descriptor + * + * Calculates bitmap descriptors, one for each block that contains bitmap data + * + * Returns: errno + */ + +static int compute_bitstructs(struct gfs2_rgrpd *rgd) +{ + struct gfs2_sbd *sdp = rgd->rd_sbd; + struct gfs2_bitmap *bi; + uint32_t length = rgd->rd_ri.ri_length; /* # blocks in hdr & bitmap */ + uint32_t bytes_left, bytes; + int x; + + rgd->rd_bits = kcalloc(length, sizeof(struct gfs2_bitmap), GFP_KERNEL); + if (!rgd->rd_bits) + return -ENOMEM; + + bytes_left = rgd->rd_ri.ri_bitbytes; + + for (x = 0; x < length; x++) { + bi = rgd->rd_bits + x; + + /* small rgrp; bitmap stored completely in header block */ + if (length == 1) { + bytes = bytes_left; + bi->bi_offset = sizeof(struct gfs2_rgrp); + bi->bi_start = 0; + bi->bi_len = bytes; + /* header block */ + } else if (x == 0) { + bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_rgrp); + bi->bi_offset = sizeof(struct gfs2_rgrp); + bi->bi_start = 0; + bi->bi_len = bytes; + /* last block */ + } else if (x + 1 == length) { + bytes = bytes_left; + bi->bi_offset = sizeof(struct gfs2_meta_header); + bi->bi_start = rgd->rd_ri.ri_bitbytes - bytes_left; + bi->bi_len = bytes; + /* other blocks */ + } else { + bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header); + bi->bi_offset = sizeof(struct gfs2_meta_header); + bi->bi_start = rgd->rd_ri.ri_bitbytes - bytes_left; + bi->bi_len = bytes; + } + + bytes_left -= bytes; + } + + if (bytes_left) { + gfs2_consist_rgrpd(rgd); + return -EIO; + } + bi = rgd->rd_bits + (length - 1); + if ((bi->bi_start + bi->bi_len) * GFS2_NBBY != rgd->rd_ri.ri_data) { + if (gfs2_consist_rgrpd(rgd)) { + gfs2_rindex_print(&rgd->rd_ri); + fs_err(sdp, "start=%u len=%u offset=%u\n", + bi->bi_start, bi->bi_len, bi->bi_offset); + } + return -EIO; + } + + return 0; +} + +/** + * gfs2_ri_update - Pull in a new resource index from the disk + * @gl: The glock covering the rindex inode + * + * Returns: 0 on successful update, error code otherwise + */ + +static int gfs2_ri_update(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_rgrpd *rgd; + char buf[sizeof(struct gfs2_rindex)]; + uint64_t junk = ip->i_di.di_size; + int error; + + if (do_div(junk, sizeof(struct gfs2_rindex))) { + gfs2_consist_inode(ip); + return -EIO; + } + + clear_rgrpdi(sdp); + + for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) { + error = gfs2_jdata_read_mem(ip, buf, + sdp->sd_rgrps * + sizeof(struct gfs2_rindex), + sizeof(struct gfs2_rindex)); + if (!error) + break; + if (error != sizeof(struct gfs2_rindex)) { + if (error > 0) + error = -EIO; + goto fail; + } + + rgd = kzalloc(sizeof(struct gfs2_rgrpd), GFP_KERNEL); + error = -ENOMEM; + if (!rgd) + goto fail; + + init_MUTEX(&rgd->rd_mutex); + lops_init_le(&rgd->rd_le, &gfs2_rg_lops); + rgd->rd_sbd = sdp; + + list_add_tail(&rgd->rd_list, &sdp->sd_rindex_list); + list_add_tail(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list); + + gfs2_rindex_in(&rgd->rd_ri, buf); + + error = compute_bitstructs(rgd); + if (error) + goto fail; + + error = gfs2_glock_get(sdp, rgd->rd_ri.ri_addr, + &gfs2_rgrp_glops, CREATE, &rgd->rd_gl); + if (error) + goto fail; + + set_gl2rgd(rgd->rd_gl, rgd); + rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1; + } + + sdp->sd_rindex_vn = ip->i_gl->gl_vn; + + return 0; + + fail: + clear_rgrpdi(sdp); + + return error; +} + +/** + * gfs2_rindex_hold - Grab a lock on the rindex + * @sdp: The GFS2 superblock + * @ri_gh: the glock holder + * + * We grab a lock on the rindex inode to make sure that it doesn't + * change whilst we are performing an operation. We keep this lock + * for quite long periods of time compared to other locks. This + * doesn't matter, since it is shared and it is very, very rarely + * accessed in the exclusive mode (i.e. only when expanding the filesystem). + * + * This makes sure that we're using the latest copy of the resource index + * special file, which might have been updated if someone expanded the + * filesystem (via gfs2_grow utility), which adds new resource groups. + * + * Returns: 0 on success, error code otherwise + */ + +int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh) +{ + struct gfs2_inode *ip = sdp->sd_rindex; + struct gfs2_glock *gl = ip->i_gl; + int error; + + error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh); + if (error) + return error; + + /* Read new copy from disk if we don't have the latest */ + if (sdp->sd_rindex_vn != gl->gl_vn) { + down(&sdp->sd_rindex_mutex); + if (sdp->sd_rindex_vn != gl->gl_vn) { + error = gfs2_ri_update(ip); + if (error) + gfs2_glock_dq_uninit(ri_gh); + } + up(&sdp->sd_rindex_mutex); + } + + return error; +} + +/** + * gfs2_rgrp_bh_get - Read in a RG's header and bitmaps + * @rgd: the struct gfs2_rgrpd describing the RG to read in + * + * Read in all of a Resource Group's header and bitmap blocks. + * Caller must eventually call gfs2_rgrp_relse() to free the bitmaps. + * + * Returns: errno + */ + +int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) +{ + struct gfs2_sbd *sdp = rgd->rd_sbd; + struct gfs2_glock *gl = rgd->rd_gl; + unsigned int length = rgd->rd_ri.ri_length; + struct gfs2_bitmap *bi; + unsigned int x, y; + int error; + + down(&rgd->rd_mutex); + + spin_lock(&sdp->sd_rindex_spin); + if (rgd->rd_bh_count) { + rgd->rd_bh_count++; + spin_unlock(&sdp->sd_rindex_spin); + up(&rgd->rd_mutex); + return 0; + } + spin_unlock(&sdp->sd_rindex_spin); + + for (x = 0; x < length; x++) { + bi = rgd->rd_bits + x; + error = gfs2_meta_read(gl, rgd->rd_ri.ri_addr + x, DIO_START, + &bi->bi_bh); + if (error) + goto fail; + } + + for (y = length; y--;) { + bi = rgd->rd_bits + y; + error = gfs2_meta_reread(sdp, bi->bi_bh, DIO_WAIT); + if (error) + goto fail; + if (gfs2_metatype_check(sdp, bi->bi_bh, + (y) ? GFS2_METATYPE_RB : + GFS2_METATYPE_RG)) { + error = -EIO; + goto fail; + } + } + + if (rgd->rd_rg_vn != gl->gl_vn) { + gfs2_rgrp_in(&rgd->rd_rg, (rgd->rd_bits[0].bi_bh)->b_data); + rgd->rd_rg_vn = gl->gl_vn; + } + + spin_lock(&sdp->sd_rindex_spin); + rgd->rd_free_clone = rgd->rd_rg.rg_free; + rgd->rd_bh_count++; + spin_unlock(&sdp->sd_rindex_spin); + + up(&rgd->rd_mutex); + + return 0; + + fail: + while (x--) { + bi = rgd->rd_bits + x; + brelse(bi->bi_bh); + bi->bi_bh = NULL; + gfs2_assert_warn(sdp, !bi->bi_clone); + } + up(&rgd->rd_mutex); + + return error; +} + +void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd) +{ + struct gfs2_sbd *sdp = rgd->rd_sbd; + + spin_lock(&sdp->sd_rindex_spin); + gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count); + rgd->rd_bh_count++; + spin_unlock(&sdp->sd_rindex_spin); +} + +/** + * gfs2_rgrp_bh_put - Release RG bitmaps read in with gfs2_rgrp_bh_get() + * @rgd: the struct gfs2_rgrpd describing the RG to read in + * + */ + +void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd) +{ + struct gfs2_sbd *sdp = rgd->rd_sbd; + int x, length = rgd->rd_ri.ri_length; + + spin_lock(&sdp->sd_rindex_spin); + gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count); + if (--rgd->rd_bh_count) { + spin_unlock(&sdp->sd_rindex_spin); + return; + } + + for (x = 0; x < length; x++) { + struct gfs2_bitmap *bi = rgd->rd_bits + x; + kfree(bi->bi_clone); + bi->bi_clone = NULL; + brelse(bi->bi_bh); + bi->bi_bh = NULL; + } + + spin_unlock(&sdp->sd_rindex_spin); +} + +void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) +{ + struct gfs2_sbd *sdp = rgd->rd_sbd; + unsigned int length = rgd->rd_ri.ri_length; + unsigned int x; + + for (x = 0; x < length; x++) { + struct gfs2_bitmap *bi = rgd->rd_bits + x; + if (!bi->bi_clone) + continue; + memcpy(bi->bi_clone + bi->bi_offset, + bi->bi_bh->b_data + bi->bi_offset, + bi->bi_len); + } + + spin_lock(&sdp->sd_rindex_spin); + rgd->rd_free_clone = rgd->rd_rg.rg_free; + spin_unlock(&sdp->sd_rindex_spin); +} + +/** + * gfs2_alloc_get - get the struct gfs2_alloc structure for an inode + * @ip: the incore GFS2 inode structure + * + * Returns: the struct gfs2_alloc + */ + +struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip) +{ + struct gfs2_alloc *al = &ip->i_alloc; + + /* FIXME: Should assert that the correct locks are held here... */ + memset(al, 0, sizeof(*al)); + return al; +} + +/** + * gfs2_alloc_put - throw away the struct gfs2_alloc for an inode + * @ip: the inode + * + */ + +void gfs2_alloc_put(struct gfs2_inode *ip) +{ + return; +} + +/** + * try_rgrp_fit - See if a given reservation will fit in a given RG + * @rgd: the RG data + * @al: the struct gfs2_alloc structure describing the reservation + * + * If there's room for the requested blocks to be allocated from the RG: + * Sets the $al_reserved_data field in @al. + * Sets the $al_reserved_meta field in @al. + * Sets the $al_rgd field in @al. + * + * Returns: 1 on success (it fits), 0 on failure (it doesn't fit) + */ + +static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) +{ + struct gfs2_sbd *sdp = rgd->rd_sbd; + int ret = 0; + + spin_lock(&sdp->sd_rindex_spin); + if (rgd->rd_free_clone >= al->al_requested) { + al->al_rgd = rgd; + ret = 1; + } + spin_unlock(&sdp->sd_rindex_spin); + + return ret; +} + +/** + * recent_rgrp_first - get first RG from "recent" list + * @sdp: The GFS2 superblock + * @rglast: address of the rgrp used last + * + * Returns: The first rgrp in the recent list + */ + +static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp, + uint64_t rglast) +{ + struct gfs2_rgrpd *rgd = NULL; + + spin_lock(&sdp->sd_rindex_spin); + + if (list_empty(&sdp->sd_rindex_recent_list)) + goto out; + + if (!rglast) + goto first; + + list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) { + if (rgd->rd_ri.ri_addr == rglast) + goto out; + } + + first: + rgd = list_entry(sdp->sd_rindex_recent_list.next, struct gfs2_rgrpd, + rd_recent); + + out: + spin_unlock(&sdp->sd_rindex_spin); + + return rgd; +} + +/** + * recent_rgrp_next - get next RG from "recent" list + * @cur_rgd: current rgrp + * @remove: + * + * Returns: The next rgrp in the recent list + */ + +static struct gfs2_rgrpd *recent_rgrp_next(struct gfs2_rgrpd *cur_rgd, + int remove) +{ + struct gfs2_sbd *sdp = cur_rgd->rd_sbd; + struct list_head *head; + struct gfs2_rgrpd *rgd; + + spin_lock(&sdp->sd_rindex_spin); + + head = &sdp->sd_rindex_recent_list; + + list_for_each_entry(rgd, head, rd_recent) { + if (rgd == cur_rgd) { + if (cur_rgd->rd_recent.next != head) + rgd = list_entry(cur_rgd->rd_recent.next, + struct gfs2_rgrpd, rd_recent); + else + rgd = NULL; + + if (remove) + list_del(&cur_rgd->rd_recent); + + goto out; + } + } + + rgd = NULL; + if (!list_empty(head)) + rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent); + + out: + spin_unlock(&sdp->sd_rindex_spin); + + return rgd; +} + +/** + * recent_rgrp_add - add an RG to tail of "recent" list + * @new_rgd: The rgrp to add + * + */ + +static void recent_rgrp_add(struct gfs2_rgrpd *new_rgd) +{ + struct gfs2_sbd *sdp = new_rgd->rd_sbd; + struct gfs2_rgrpd *rgd; + unsigned int count = 0; + unsigned int max = sdp->sd_rgrps / gfs2_jindex_size(sdp); + + spin_lock(&sdp->sd_rindex_spin); + + list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) { + if (rgd == new_rgd) + goto out; + + if (++count >= max) + goto out; + } + list_add_tail(&new_rgd->rd_recent, &sdp->sd_rindex_recent_list); + + out: + spin_unlock(&sdp->sd_rindex_spin); +} + +/** + * forward_rgrp_get - get an rgrp to try next from full list + * @sdp: The GFS2 superblock + * + * Returns: The rgrp to try next + */ + +static struct gfs2_rgrpd *forward_rgrp_get(struct gfs2_sbd *sdp) +{ + struct gfs2_rgrpd *rgd; + unsigned int journals = gfs2_jindex_size(sdp); + unsigned int rg = 0, x; + + spin_lock(&sdp->sd_rindex_spin); + + rgd = sdp->sd_rindex_forward; + if (!rgd) { + if (sdp->sd_rgrps >= journals) + rg = sdp->sd_rgrps * sdp->sd_jdesc->jd_jid / journals; + + for (x = 0, rgd = gfs2_rgrpd_get_first(sdp); + x < rg; + x++, rgd = gfs2_rgrpd_get_next(rgd)) + /* Do Nothing */; + + sdp->sd_rindex_forward = rgd; + } + + spin_unlock(&sdp->sd_rindex_spin); + + return rgd; +} + +/** + * forward_rgrp_set - set the forward rgrp pointer + * @sdp: the filesystem + * @rgd: The new forward rgrp + * + */ + +static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd) +{ + spin_lock(&sdp->sd_rindex_spin); + sdp->sd_rindex_forward = rgd; + spin_unlock(&sdp->sd_rindex_spin); +} + +/** + * get_local_rgrp - Choose and lock a rgrp for allocation + * @ip: the inode to reserve space for + * @rgp: the chosen and locked rgrp + * + * Try to acquire rgrp in way which avoids contending with others. + * + * Returns: errno + */ + +static int get_local_rgrp(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_rgrpd *rgd, *begin = NULL; + struct gfs2_alloc *al = &ip->i_alloc; + int flags = LM_FLAG_TRY; + int skipped = 0; + int loops = 0; + int error; + + /* Try recently successful rgrps */ + + rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc); + + while (rgd) { + error = gfs2_glock_nq_init(rgd->rd_gl, + LM_ST_EXCLUSIVE, LM_FLAG_TRY, + &al->al_rgd_gh); + switch (error) { + case 0: + if (try_rgrp_fit(rgd, al)) + goto out; + gfs2_glock_dq_uninit(&al->al_rgd_gh); + rgd = recent_rgrp_next(rgd, 1); + break; + + case GLR_TRYFAILED: + rgd = recent_rgrp_next(rgd, 0); + break; + + default: + return error; + } + } + + /* Go through full list of rgrps */ + + begin = rgd = forward_rgrp_get(sdp); + + for (;;) { + error = gfs2_glock_nq_init(rgd->rd_gl, + LM_ST_EXCLUSIVE, flags, + &al->al_rgd_gh); + switch (error) { + case 0: + if (try_rgrp_fit(rgd, al)) + goto out; + gfs2_glock_dq_uninit(&al->al_rgd_gh); + break; + + case GLR_TRYFAILED: + skipped++; + break; + + default: + return error; + } + + rgd = gfs2_rgrpd_get_next(rgd); + if (!rgd) + rgd = gfs2_rgrpd_get_first(sdp); + + if (rgd == begin) { + if (++loops >= 2 || !skipped) + return -ENOSPC; + flags = 0; + } + } + + out: + ip->i_last_rg_alloc = rgd->rd_ri.ri_addr; + + if (begin) { + recent_rgrp_add(rgd); + rgd = gfs2_rgrpd_get_next(rgd); + if (!rgd) + rgd = gfs2_rgrpd_get_first(sdp); + forward_rgrp_set(sdp, rgd); + } + + return 0; +} + +/** + * gfs2_inplace_reserve_i - Reserve space in the filesystem + * @ip: the inode to reserve space for + * + * Returns: errno + */ + +int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = &ip->i_alloc; + int error; + + if (gfs2_assert_warn(sdp, al->al_requested)) + return -EINVAL; + + error = gfs2_rindex_hold(sdp, &al->al_ri_gh); + if (error) + return error; + + error = get_local_rgrp(ip); + if (error) { + gfs2_glock_dq_uninit(&al->al_ri_gh); + return error; + } + + al->al_file = file; + al->al_line = line; + + return 0; +} + +/** + * gfs2_inplace_release - release an inplace reservation + * @ip: the inode the reservation was taken out on + * + * Release a reservation made by gfs2_inplace_reserve(). + */ + +void gfs2_inplace_release(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = &ip->i_alloc; + + if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1) + fs_warn(sdp, "al_alloced = %u, al_requested = %u " + "al_file = %s, al_line = %u\n", + al->al_alloced, al->al_requested, al->al_file, + al->al_line); + + al->al_rgd = NULL; + gfs2_glock_dq_uninit(&al->al_rgd_gh); + gfs2_glock_dq_uninit(&al->al_ri_gh); +} + +/** + * gfs2_get_block_type - Check a block in a RG is of given type + * @rgd: the resource group holding the block + * @block: the block number + * + * Returns: The block type (GFS2_BLKST_*) + */ + +unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, uint64_t block) +{ + struct gfs2_bitmap *bi = NULL; + uint32_t length, rgrp_block, buf_block; + unsigned int buf; + unsigned char type; + + length = rgd->rd_ri.ri_length; + rgrp_block = block - rgd->rd_ri.ri_data0; + + for (buf = 0; buf < length; buf++) { + bi = rgd->rd_bits + buf; + if (rgrp_block < (bi->bi_start + bi->bi_len) * GFS2_NBBY) + break; + } + + gfs2_assert(rgd->rd_sbd, buf < length); + buf_block = rgrp_block - bi->bi_start * GFS2_NBBY; + + type = gfs2_testbit(rgd, + bi->bi_bh->b_data + bi->bi_offset, + bi->bi_len, buf_block); + + return type; +} + +/** + * rgblk_search - find a block in @old_state, change allocation + * state to @new_state + * @rgd: the resource group descriptor + * @goal: the goal block within the RG (start here to search for avail block) + * @old_state: GFS2_BLKST_XXX the before-allocation state to find + * @new_state: GFS2_BLKST_XXX the after-allocation block state + * + * Walk rgrp's bitmap to find bits that represent a block in @old_state. + * Add the found bitmap buffer to the transaction. + * Set the found bits to @new_state to change block's allocation state. + * + * This function never fails, because we wouldn't call it unless we + * know (from reservation results, etc.) that a block is available. + * + * Scope of @goal and returned block is just within rgrp, not the whole + * filesystem. + * + * Returns: the block number allocated + */ + +static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal, + unsigned char old_state, unsigned char new_state) +{ + struct gfs2_bitmap *bi = NULL; + uint32_t length = rgd->rd_ri.ri_length; + uint32_t blk = 0; + unsigned int buf, x; + + /* Find bitmap block that contains bits for goal block */ + for (buf = 0; buf < length; buf++) { + bi = rgd->rd_bits + buf; + if (goal < (bi->bi_start + bi->bi_len) * GFS2_NBBY) + break; + } + + gfs2_assert(rgd->rd_sbd, buf < length); + + /* Convert scope of "goal" from rgrp-wide to within found bit block */ + goal -= bi->bi_start * GFS2_NBBY; + + /* Search (up to entire) bitmap in this rgrp for allocatable block. + "x <= length", instead of "x < length", because we typically start + the search in the middle of a bit block, but if we can't find an + allocatable block anywhere else, we want to be able wrap around and + search in the first part of our first-searched bit block. */ + for (x = 0; x <= length; x++) { + if (bi->bi_clone) + blk = gfs2_bitfit(rgd, + bi->bi_clone + bi->bi_offset, + bi->bi_len, goal, old_state); + else + blk = gfs2_bitfit(rgd, + bi->bi_bh->b_data + bi->bi_offset, + bi->bi_len, goal, old_state); + if (blk != BFITNOENT) + break; + + /* Try next bitmap block (wrap back to rgrp header if at end) */ + buf = (buf + 1) % length; + bi = rgd->rd_bits + buf; + goal = 0; + } + + if (gfs2_assert_withdraw(rgd->rd_sbd, x <= length)) + blk = 0; + + gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh); + gfs2_setbit(rgd, + bi->bi_bh->b_data + bi->bi_offset, + bi->bi_len, blk, new_state); + if (bi->bi_clone) + gfs2_setbit(rgd, + bi->bi_clone + bi->bi_offset, + bi->bi_len, blk, new_state); + + return bi->bi_start * GFS2_NBBY + blk; +} + +/** + * rgblk_free - Change alloc state of given block(s) + * @sdp: the filesystem + * @bstart: the start of a run of blocks to free + * @blen: the length of the block run (all must lie within ONE RG!) + * @new_state: GFS2_BLKST_XXX the after-allocation block state + * + * Returns: Resource group containing the block(s) + */ + +static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, uint64_t bstart, + uint32_t blen, unsigned char new_state) +{ + struct gfs2_rgrpd *rgd; + struct gfs2_bitmap *bi = NULL; + uint32_t length, rgrp_blk, buf_blk; + unsigned int buf; + + rgd = gfs2_blk2rgrpd(sdp, bstart); + if (!rgd) { + if (gfs2_consist(sdp)) + fs_err(sdp, "block = %llu\n", bstart); + return NULL; + } + + length = rgd->rd_ri.ri_length; + + rgrp_blk = bstart - rgd->rd_ri.ri_data0; + + while (blen--) { + for (buf = 0; buf < length; buf++) { + bi = rgd->rd_bits + buf; + if (rgrp_blk < (bi->bi_start + bi->bi_len) * GFS2_NBBY) + break; + } + + gfs2_assert(rgd->rd_sbd, buf < length); + + buf_blk = rgrp_blk - bi->bi_start * GFS2_NBBY; + rgrp_blk++; + + if (!bi->bi_clone) { + bi->bi_clone = kmalloc(bi->bi_bh->b_size, + GFP_KERNEL | __GFP_NOFAIL); + memcpy(bi->bi_clone + bi->bi_offset, + bi->bi_bh->b_data + bi->bi_offset, + bi->bi_len); + } + gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh); + gfs2_setbit(rgd, + bi->bi_bh->b_data + bi->bi_offset, + bi->bi_len, buf_blk, new_state); + } + + return rgd; +} + +/** + * gfs2_alloc_data - Allocate a data block + * @ip: the inode to allocate the data block for + * + * Returns: the allocated block + */ + +uint64_t gfs2_alloc_data(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_rgrpd *rgd = al->al_rgd; + uint32_t goal, blk; + uint64_t block; + + if (rgrp_contains_block(&rgd->rd_ri, ip->i_di.di_goal_data)) + goal = ip->i_di.di_goal_data - rgd->rd_ri.ri_data0; + else + goal = rgd->rd_last_alloc_data; + + blk = rgblk_search(rgd, goal, + GFS2_BLKST_FREE, GFS2_BLKST_USED); + rgd->rd_last_alloc_data = blk; + + block = rgd->rd_ri.ri_data0 + blk; + ip->i_di.di_goal_data = block; + + gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); + rgd->rd_rg.rg_free--; + + gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh); + gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + + al->al_alloced++; + + gfs2_statfs_change(sdp, 0, -1, 0); + gfs2_quota_change(ip, +1, ip->i_di.di_uid, ip->i_di.di_gid); + + spin_lock(&sdp->sd_rindex_spin); + rgd->rd_free_clone--; + spin_unlock(&sdp->sd_rindex_spin); + + return block; +} + +/** + * gfs2_alloc_meta - Allocate a metadata block + * @ip: the inode to allocate the metadata block for + * + * Returns: the allocated block + */ + +uint64_t gfs2_alloc_meta(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_rgrpd *rgd = al->al_rgd; + uint32_t goal, blk; + uint64_t block; + + if (rgrp_contains_block(&rgd->rd_ri, ip->i_di.di_goal_meta)) + goal = ip->i_di.di_goal_meta - rgd->rd_ri.ri_data0; + else + goal = rgd->rd_last_alloc_meta; + + blk = rgblk_search(rgd, goal, + GFS2_BLKST_FREE, GFS2_BLKST_USED); + rgd->rd_last_alloc_meta = blk; + + block = rgd->rd_ri.ri_data0 + blk; + ip->i_di.di_goal_meta = block; + + gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); + rgd->rd_rg.rg_free--; + + gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh); + gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + + al->al_alloced++; + + gfs2_statfs_change(sdp, 0, -1, 0); + gfs2_quota_change(ip, +1, ip->i_di.di_uid, ip->i_di.di_gid); + gfs2_trans_add_unrevoke(sdp, block); + + spin_lock(&sdp->sd_rindex_spin); + rgd->rd_free_clone--; + spin_unlock(&sdp->sd_rindex_spin); + + return block; +} + +/** + * gfs2_alloc_di - Allocate a dinode + * @dip: the directory that the inode is going in + * + * Returns: the block allocated + */ + +uint64_t gfs2_alloc_di(struct gfs2_inode *dip) +{ + struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_alloc *al = &dip->i_alloc; + struct gfs2_rgrpd *rgd = al->al_rgd; + uint32_t blk; + uint64_t block; + + blk = rgblk_search(rgd, rgd->rd_last_alloc_meta, + GFS2_BLKST_FREE, GFS2_BLKST_DINODE); + + rgd->rd_last_alloc_meta = blk; + + block = rgd->rd_ri.ri_data0 + blk; + + gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); + rgd->rd_rg.rg_free--; + rgd->rd_rg.rg_dinodes++; + + gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh); + gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + + al->al_alloced++; + + gfs2_statfs_change(sdp, 0, -1, +1); + gfs2_trans_add_unrevoke(sdp, block); + + spin_lock(&sdp->sd_rindex_spin); + rgd->rd_free_clone--; + spin_unlock(&sdp->sd_rindex_spin); + + return block; +} + +/** + * gfs2_free_data - free a contiguous run of data block(s) + * @ip: the inode these blocks are being freed from + * @bstart: first block of a run of contiguous blocks + * @blen: the length of the block run + * + */ + +void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_rgrpd *rgd; + + rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE); + if (!rgd) + return; + + rgd->rd_rg.rg_free += blen; + + gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh); + gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + + gfs2_trans_add_rg(rgd); + + gfs2_statfs_change(sdp, 0, +blen, 0); + gfs2_quota_change(ip, -(int64_t)blen, + ip->i_di.di_uid, ip->i_di.di_gid); +} + +/** + * gfs2_free_meta - free a contiguous run of data block(s) + * @ip: the inode these blocks are being freed from + * @bstart: first block of a run of contiguous blocks + * @blen: the length of the block run + * + */ + +void gfs2_free_meta(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_rgrpd *rgd; + + rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE); + if (!rgd) + return; + + rgd->rd_rg.rg_free += blen; + + gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh); + gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + + gfs2_trans_add_rg(rgd); + + gfs2_statfs_change(sdp, 0, +blen, 0); + gfs2_quota_change(ip, -(int64_t)blen, + ip->i_di.di_uid, ip->i_di.di_gid); + gfs2_meta_wipe(ip, bstart, blen); +} + +void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, uint64_t blkno) +{ + struct gfs2_sbd *sdp = rgd->rd_sbd; + struct gfs2_rgrpd *tmp_rgd; + + tmp_rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_FREE); + if (!tmp_rgd) + return; + gfs2_assert_withdraw(sdp, rgd == tmp_rgd); + + if (!rgd->rd_rg.rg_dinodes) + gfs2_consist_rgrpd(rgd); + rgd->rd_rg.rg_dinodes--; + rgd->rd_rg.rg_free++; + + gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh); + gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + + gfs2_statfs_change(sdp, 0, +1, -1); + gfs2_trans_add_rg(rgd); +} + +/** + * gfs2_free_uninit_di - free a dinode block + * @rgd: the resource group that contains the dinode + * @ip: the inode + * + */ + +void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip) +{ + gfs2_free_uninit_di(rgd, ip->i_num.no_addr); + gfs2_quota_change(ip, -1, ip->i_di.di_uid, ip->i_di.di_gid); + gfs2_meta_wipe(ip, ip->i_num.no_addr, 1); +} + +/** + * gfs2_rlist_add - add a RG to a list of RGs + * @sdp: the filesystem + * @rlist: the list of resource groups + * @block: the block + * + * Figure out what RG a block belongs to and add that RG to the list + * + * FIXME: Don't use NOFAIL + * + */ + +void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, + uint64_t block) +{ + struct gfs2_rgrpd *rgd; + struct gfs2_rgrpd **tmp; + unsigned int new_space; + unsigned int x; + + if (gfs2_assert_warn(sdp, !rlist->rl_ghs)) + return; + + rgd = gfs2_blk2rgrpd(sdp, block); + if (!rgd) { + if (gfs2_consist(sdp)) + fs_err(sdp, "block = %llu\n", block); + return; + } + + for (x = 0; x < rlist->rl_rgrps; x++) + if (rlist->rl_rgd[x] == rgd) + return; + + if (rlist->rl_rgrps == rlist->rl_space) { + new_space = rlist->rl_space + 10; + + tmp = kcalloc(new_space, sizeof(struct gfs2_rgrpd *), + GFP_KERNEL | __GFP_NOFAIL); + + if (rlist->rl_rgd) { + memcpy(tmp, rlist->rl_rgd, + rlist->rl_space * sizeof(struct gfs2_rgrpd *)); + kfree(rlist->rl_rgd); + } + + rlist->rl_space = new_space; + rlist->rl_rgd = tmp; + } + + rlist->rl_rgd[rlist->rl_rgrps++] = rgd; +} + +/** + * gfs2_rlist_alloc - all RGs have been added to the rlist, now allocate + * and initialize an array of glock holders for them + * @rlist: the list of resource groups + * @state: the lock state to acquire the RG lock in + * @flags: the modifier flags for the holder structures + * + * FIXME: Don't use NOFAIL + * + */ + +void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state, + int flags) +{ + unsigned int x; + + rlist->rl_ghs = kcalloc(rlist->rl_rgrps, sizeof(struct gfs2_holder), + GFP_KERNEL | __GFP_NOFAIL); + for (x = 0; x < rlist->rl_rgrps; x++) + gfs2_holder_init(rlist->rl_rgd[x]->rd_gl, + state, flags, + &rlist->rl_ghs[x]); +} + +/** + * gfs2_rlist_free - free a resource group list + * @list: the list of resource groups + * + */ + +void gfs2_rlist_free(struct gfs2_rgrp_list *rlist) +{ + unsigned int x; + + kfree(rlist->rl_rgd); + + if (rlist->rl_ghs) { + for (x = 0; x < rlist->rl_rgrps; x++) + gfs2_holder_uninit(&rlist->rl_ghs[x]); + kfree(rlist->rl_ghs); + } +} + diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h new file mode 100644 index 000000000000..4c44a191b1c1 --- /dev/null +++ b/fs/gfs2/rgrp.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __RGRP_DOT_H__ +#define __RGRP_DOT_H__ + +void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd); + +struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, uint64_t blk); +struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp); +struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd); + +void gfs2_clear_rgrpd(struct gfs2_sbd *sdp); +int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh); + +int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd); +void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd); +void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd); + +void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd); + +struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); +void gfs2_alloc_put(struct gfs2_inode *ip); + +int gfs2_inplace_reserve_i(struct gfs2_inode *ip, + char *file, unsigned int line); +#define gfs2_inplace_reserve(ip) \ +gfs2_inplace_reserve_i((ip), __FILE__, __LINE__) + +void gfs2_inplace_release(struct gfs2_inode *ip); + +unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, uint64_t block); + +uint64_t gfs2_alloc_data(struct gfs2_inode *ip); +uint64_t gfs2_alloc_meta(struct gfs2_inode *ip); +uint64_t gfs2_alloc_di(struct gfs2_inode *ip); + +void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); +void gfs2_free_meta(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); +void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, uint64_t blkno); +void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); + +struct gfs2_rgrp_list { + unsigned int rl_rgrps; + unsigned int rl_space; + struct gfs2_rgrpd **rl_rgd; + struct gfs2_holder *rl_ghs; +}; + +void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, + uint64_t block); +void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state, + int flags); +void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); + +#endif /* __RGRP_DOT_H__ */ diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c new file mode 100644 index 000000000000..d37f203e133b --- /dev/null +++ b/fs/gfs2/super.c @@ -0,0 +1,944 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "dir.h" +#include "format.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "log.h" +#include "meta_io.h" +#include "quota.h" +#include "recovery.h" +#include "rgrp.h" +#include "super.h" +#include "trans.h" +#include "unlinked.h" + +/** + * gfs2_tune_init - Fill a gfs2_tune structure with default values + * @gt: tune + * + */ + +void gfs2_tune_init(struct gfs2_tune *gt) +{ + spin_lock_init(>->gt_spin); + + gt->gt_ilimit = 100; + gt->gt_ilimit_tries = 3; + gt->gt_ilimit_min = 1; + gt->gt_demote_secs = 300; + gt->gt_incore_log_blocks = 1024; + gt->gt_log_flush_secs = 60; + gt->gt_jindex_refresh_secs = 60; + gt->gt_scand_secs = 15; + gt->gt_recoverd_secs = 60; + gt->gt_logd_secs = 1; + gt->gt_quotad_secs = 5; + gt->gt_inoded_secs = 15; + gt->gt_quota_simul_sync = 64; + gt->gt_quota_warn_period = 10; + gt->gt_quota_scale_num = 1; + gt->gt_quota_scale_den = 1; + gt->gt_quota_cache_secs = 300; + gt->gt_quota_quantum = 60; + gt->gt_atime_quantum = 3600; + gt->gt_new_files_jdata = 0; + gt->gt_new_files_directio = 0; + gt->gt_max_atomic_write = 4 << 20; + gt->gt_max_readahead = 1 << 18; + gt->gt_lockdump_size = 131072; + gt->gt_stall_secs = 600; + gt->gt_complain_secs = 10; + gt->gt_reclaim_limit = 5000; + gt->gt_entries_per_readdir = 32; + gt->gt_prefetch_secs = 10; + gt->gt_greedy_default = HZ / 10; + gt->gt_greedy_quantum = HZ / 40; + gt->gt_greedy_max = HZ / 4; + gt->gt_statfs_quantum = 30; + gt->gt_statfs_slow = 0; +} + +/** + * gfs2_check_sb - Check superblock + * @sdp: the filesystem + * @sb: The superblock + * @silent: Don't print a message if the check fails + * + * Checks the version code of the FS is one that we understand how to + * read and that the sizes of the various on-disk structures have not + * changed. + */ + +int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent) +{ + unsigned int x; + + if (sb->sb_header.mh_magic != GFS2_MAGIC || + sb->sb_header.mh_type != GFS2_METATYPE_SB) { + if (!silent) + printk("GFS2: not a GFS2 filesystem\n"); + return -EINVAL; + } + + /* If format numbers match exactly, we're done. */ + + if (sb->sb_fs_format == GFS2_FORMAT_FS && + sb->sb_multihost_format == GFS2_FORMAT_MULTI) + return 0; + + if (sb->sb_fs_format != GFS2_FORMAT_FS) { + for (x = 0; gfs2_old_fs_formats[x]; x++) + if (gfs2_old_fs_formats[x] == sb->sb_fs_format) + break; + + if (!gfs2_old_fs_formats[x]) { + printk("GFS2: code version (%u, %u) is incompatible " + "with ondisk format (%u, %u)\n", + GFS2_FORMAT_FS, GFS2_FORMAT_MULTI, + sb->sb_fs_format, sb->sb_multihost_format); + printk("GFS2: I don't know how to upgrade this FS\n"); + return -EINVAL; + } + } + + if (sb->sb_multihost_format != GFS2_FORMAT_MULTI) { + for (x = 0; gfs2_old_multihost_formats[x]; x++) + if (gfs2_old_multihost_formats[x] == sb->sb_multihost_format) + break; + + if (!gfs2_old_multihost_formats[x]) { + printk("GFS2: code version (%u, %u) is incompatible " + "with ondisk format (%u, %u)\n", + GFS2_FORMAT_FS, GFS2_FORMAT_MULTI, + sb->sb_fs_format, sb->sb_multihost_format); + printk("GFS2: I don't know how to upgrade this FS\n"); + return -EINVAL; + } + } + + if (!sdp->sd_args.ar_upgrade) { + printk("GFS2: code version (%u, %u) is incompatible " + "with ondisk format (%u, %u)\n", + GFS2_FORMAT_FS, GFS2_FORMAT_MULTI, + sb->sb_fs_format, sb->sb_multihost_format); + printk("GFS2: Use the \"upgrade\" mount option to upgrade " + "the FS\n"); + printk("GFS2: See the manual for more details\n"); + return -EINVAL; + } + + return 0; +} + +/** + * gfs2_read_sb - Read super block + * @sdp: The GFS2 superblock + * @gl: the glock for the superblock (assumed to be held) + * @silent: Don't print message if mount fails + * + */ + +int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) +{ + struct buffer_head *bh; + uint32_t hash_blocks, ind_blocks, leaf_blocks; + uint32_t tmp_blocks; + unsigned int x; + int error; + + error = gfs2_meta_read(gl, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift, + DIO_FORCE | DIO_START | DIO_WAIT, &bh); + if (error) { + if (!silent) + fs_err(sdp, "can't read superblock\n"); + return error; + } + + gfs2_assert(sdp, sizeof(struct gfs2_sb) <= bh->b_size); + gfs2_sb_in(&sdp->sd_sb, bh->b_data); + brelse(bh); + + error = gfs2_check_sb(sdp, &sdp->sd_sb, silent); + if (error) + return error; + + sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift - + GFS2_BASIC_BLOCK_SHIFT; + sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; + sdp->sd_diptrs = (sdp->sd_sb.sb_bsize - + sizeof(struct gfs2_dinode)) / sizeof(uint64_t); + sdp->sd_inptrs = (sdp->sd_sb.sb_bsize - + sizeof(struct gfs2_meta_header)) / sizeof(uint64_t); + sdp->sd_jbsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header); + sdp->sd_hash_bsize = sdp->sd_sb.sb_bsize / 2; + sdp->sd_hash_bsize_shift = sdp->sd_sb.sb_bsize_shift - 1; + sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(uint64_t); + sdp->sd_ut_per_block = (sdp->sd_sb.sb_bsize - + sizeof(struct gfs2_meta_header)) / + sizeof(struct gfs2_unlinked_tag); + sdp->sd_qc_per_block = (sdp->sd_sb.sb_bsize - + sizeof(struct gfs2_meta_header)) / + sizeof(struct gfs2_quota_change); + + /* Compute maximum reservation required to add a entry to a directory */ + + hash_blocks = DIV_RU(sizeof(uint64_t) * (1 << GFS2_DIR_MAX_DEPTH), + sdp->sd_jbsize); + + ind_blocks = 0; + for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) { + tmp_blocks = DIV_RU(tmp_blocks, sdp->sd_inptrs); + ind_blocks += tmp_blocks; + } + + leaf_blocks = 2 + GFS2_DIR_MAX_DEPTH; + + sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks; + + sdp->sd_heightsize[0] = sdp->sd_sb.sb_bsize - + sizeof(struct gfs2_dinode); + sdp->sd_heightsize[1] = sdp->sd_sb.sb_bsize * sdp->sd_diptrs; + for (x = 2;; x++) { + uint64_t space, d; + uint32_t m; + + space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs; + d = space; + m = do_div(d, sdp->sd_inptrs); + + if (d != sdp->sd_heightsize[x - 1] || m) + break; + sdp->sd_heightsize[x] = space; + } + sdp->sd_max_height = x; + gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT); + + sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize - + sizeof(struct gfs2_dinode); + sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs; + for (x = 2;; x++) { + uint64_t space, d; + uint32_t m; + + space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs; + d = space; + m = do_div(d, sdp->sd_inptrs); + + if (d != sdp->sd_jheightsize[x - 1] || m) + break; + sdp->sd_jheightsize[x] = space; + } + sdp->sd_max_jheight = x; + gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT); + + return 0; +} + +int gfs2_do_upgrade(struct gfs2_sbd *sdp, struct gfs2_glock *sb_gl) +{ + return 0; +} + +/** + * gfs2_jindex_hold - Grab a lock on the jindex + * @sdp: The GFS2 superblock + * @ji_gh: the holder for the jindex glock + * + * This is very similar to the gfs2_rindex_hold() function, except that + * in general we hold the jindex lock for longer periods of time and + * we grab it far less frequently (in general) then the rgrp lock. + * + * Returns: errno + */ + +int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) +{ + struct gfs2_inode *dip = sdp->sd_jindex; + struct qstr name; + char buf[20]; + struct gfs2_jdesc *jd; + int error; + + name.name = buf; + + down(&sdp->sd_jindex_mutex); + + for (;;) { + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, + GL_LOCAL_EXCL, ji_gh); + if (error) + break; + + name.len = sprintf(buf, "journal%u", sdp->sd_journals); + + error = gfs2_dir_search(sdp->sd_jindex, &name, NULL, NULL); + if (error == -ENOENT) { + error = 0; + break; + } + + gfs2_glock_dq_uninit(ji_gh); + + if (error) + break; + + error = -ENOMEM; + jd = kzalloc(sizeof(struct gfs2_jdesc), GFP_KERNEL); + if (!jd) + break; + + error = gfs2_lookupi(dip, &name, 1, &jd->jd_inode); + if (error) { + kfree(jd); + break; + } + + spin_lock(&sdp->sd_jindex_spin); + jd->jd_jid = sdp->sd_journals++; + list_add_tail(&jd->jd_list, &sdp->sd_jindex_list); + spin_unlock(&sdp->sd_jindex_spin); + } + + up(&sdp->sd_jindex_mutex); + + return error; +} + +/** + * gfs2_jindex_free - Clear all the journal index information + * @sdp: The GFS2 superblock + * + */ + +void gfs2_jindex_free(struct gfs2_sbd *sdp) +{ + struct list_head list; + struct gfs2_jdesc *jd; + + spin_lock(&sdp->sd_jindex_spin); + list_add(&list, &sdp->sd_jindex_list); + list_del_init(&sdp->sd_jindex_list); + sdp->sd_journals = 0; + spin_unlock(&sdp->sd_jindex_spin); + + while (!list_empty(&list)) { + jd = list_entry(list.next, struct gfs2_jdesc, jd_list); + list_del(&jd->jd_list); + gfs2_inode_put(jd->jd_inode); + kfree(jd); + } +} + +static struct gfs2_jdesc *jdesc_find_i(struct list_head *head, unsigned int jid) +{ + struct gfs2_jdesc *jd; + int found = 0; + + list_for_each_entry(jd, head, jd_list) { + if (jd->jd_jid == jid) { + found = 1; + break; + } + } + + if (!found) + jd = NULL; + + return jd; +} + +struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid) +{ + struct gfs2_jdesc *jd; + + spin_lock(&sdp->sd_jindex_spin); + jd = jdesc_find_i(&sdp->sd_jindex_list, jid); + spin_unlock(&sdp->sd_jindex_spin); + + return jd; +} + +void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid) +{ + struct gfs2_jdesc *jd; + + spin_lock(&sdp->sd_jindex_spin); + jd = jdesc_find_i(&sdp->sd_jindex_list, jid); + if (jd) + jd->jd_dirty = 1; + spin_unlock(&sdp->sd_jindex_spin); +} + +struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp) +{ + struct gfs2_jdesc *jd; + int found = 0; + + spin_lock(&sdp->sd_jindex_spin); + + list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { + if (jd->jd_dirty) { + jd->jd_dirty = 0; + found = 1; + break; + } + } + spin_unlock(&sdp->sd_jindex_spin); + + if (!found) + jd = NULL; + + return jd; +} + +int gfs2_jdesc_check(struct gfs2_jdesc *jd) +{ + struct gfs2_inode *ip = jd->jd_inode; + struct gfs2_sbd *sdp = ip->i_sbd; + int ar; + int error; + + if (ip->i_di.di_size < (8 << 20) || + ip->i_di.di_size > (1 << 30) || + (ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1))) { + gfs2_consist_inode(ip); + return -EIO; + } + jd->jd_blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; + + error = gfs2_write_alloc_required(ip, + 0, ip->i_di.di_size, + &ar); + if (!error && ar) { + gfs2_consist_inode(ip); + error = -EIO; + } + + return error; +} + +int gfs2_lookup_master_dir(struct gfs2_sbd *sdp) +{ + struct gfs2_glock *gl; + int error; + + error = gfs2_glock_get(sdp, + sdp->sd_sb.sb_master_dir.no_addr, + &gfs2_inode_glops, CREATE, &gl); + if (!error) { + error = gfs2_inode_get(gl, &sdp->sd_sb.sb_master_dir, CREATE, + &sdp->sd_master_dir); + gfs2_glock_put(gl); + } + + return error; +} + +/** + * gfs2_make_fs_rw - Turn a Read-Only FS into a Read-Write one + * @sdp: the filesystem + * + * Returns: errno + */ + +int gfs2_make_fs_rw(struct gfs2_sbd *sdp) +{ + struct gfs2_glock *j_gl = sdp->sd_jdesc->jd_inode->i_gl; + struct gfs2_holder t_gh; + struct gfs2_log_header head; + int error; + + error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, + GL_LOCAL_EXCL | GL_NEVER_RECURSE, &t_gh); + if (error) + return error; + + gfs2_meta_cache_flush(sdp->sd_jdesc->jd_inode); + j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA); + + error = gfs2_find_jhead(sdp->sd_jdesc, &head); + if (error) + goto fail; + + if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) { + gfs2_consist(sdp); + error = -EIO; + goto fail; + } + + /* Initialize some head of the log stuff */ + sdp->sd_log_sequence = head.lh_sequence + 1; + gfs2_log_pointers_init(sdp, head.lh_blkno); + + error = gfs2_unlinked_init(sdp); + if (error) + goto fail; + error = gfs2_quota_init(sdp); + if (error) + goto fail_unlinked; + + set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); + + gfs2_glock_dq_uninit(&t_gh); + + return 0; + + fail_unlinked: + gfs2_unlinked_cleanup(sdp); + + fail: + t_gh.gh_flags |= GL_NOCACHE; + gfs2_glock_dq_uninit(&t_gh); + + return error; +} + +/** + * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one + * @sdp: the filesystem + * + * Returns: errno + */ + +int gfs2_make_fs_ro(struct gfs2_sbd *sdp) +{ + struct gfs2_holder t_gh; + int error; + + gfs2_unlinked_dealloc(sdp); + gfs2_quota_sync(sdp); + gfs2_statfs_sync(sdp); + + error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, + GL_LOCAL_EXCL | GL_NEVER_RECURSE | GL_NOCACHE, + &t_gh); + if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + return error; + + gfs2_meta_syncfs(sdp); + gfs2_log_shutdown(sdp); + + clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); + + if (t_gh.gh_gl) + gfs2_glock_dq_uninit(&t_gh); + + gfs2_unlinked_cleanup(sdp); + gfs2_quota_cleanup(sdp); + + return error; +} + +int gfs2_statfs_init(struct gfs2_sbd *sdp) +{ + struct gfs2_inode *m_ip = sdp->sd_statfs_inode; + struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; + struct gfs2_inode *l_ip = sdp->sd_sc_inode; + struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; + struct buffer_head *m_bh, *l_bh; + struct gfs2_holder gh; + int error; + + error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, + &gh); + if (error) + return error; + + error = gfs2_meta_inode_buffer(m_ip, &m_bh); + if (error) + goto out; + + if (sdp->sd_args.ar_spectator) { + spin_lock(&sdp->sd_statfs_spin); + gfs2_statfs_change_in(m_sc, m_bh->b_data + + sizeof(struct gfs2_dinode)); + spin_unlock(&sdp->sd_statfs_spin); + } else { + error = gfs2_meta_inode_buffer(l_ip, &l_bh); + if (error) + goto out_m_bh; + + spin_lock(&sdp->sd_statfs_spin); + gfs2_statfs_change_in(m_sc, m_bh->b_data + + sizeof(struct gfs2_dinode)); + gfs2_statfs_change_in(l_sc, l_bh->b_data + + sizeof(struct gfs2_dinode)); + spin_unlock(&sdp->sd_statfs_spin); + + brelse(l_bh); + } + + out_m_bh: + brelse(m_bh); + + out: + gfs2_glock_dq_uninit(&gh); + + return 0; +} + +void gfs2_statfs_change(struct gfs2_sbd *sdp, int64_t total, int64_t free, + int64_t dinodes) +{ + struct gfs2_inode *l_ip = sdp->sd_sc_inode; + struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; + struct buffer_head *l_bh; + int error; + + error = gfs2_meta_inode_buffer(l_ip, &l_bh); + if (error) + return; + + down(&sdp->sd_statfs_mutex); + gfs2_trans_add_bh(l_ip->i_gl, l_bh); + up(&sdp->sd_statfs_mutex); + + spin_lock(&sdp->sd_statfs_spin); + l_sc->sc_total += total; + l_sc->sc_free += free; + l_sc->sc_dinodes += dinodes; + gfs2_statfs_change_out(l_sc, l_bh->b_data + + sizeof(struct gfs2_dinode)); + spin_unlock(&sdp->sd_statfs_spin); + + brelse(l_bh); +} + +int gfs2_statfs_sync(struct gfs2_sbd *sdp) +{ + struct gfs2_inode *m_ip = sdp->sd_statfs_inode; + struct gfs2_inode *l_ip = sdp->sd_sc_inode; + struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; + struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; + struct gfs2_holder gh; + struct buffer_head *m_bh, *l_bh; + int error; + + error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, + &gh); + if (error) + return error; + + error = gfs2_meta_inode_buffer(m_ip, &m_bh); + if (error) + goto out; + + spin_lock(&sdp->sd_statfs_spin); + gfs2_statfs_change_in(m_sc, m_bh->b_data + + sizeof(struct gfs2_dinode)); + if (!l_sc->sc_total && !l_sc->sc_free && !l_sc->sc_dinodes) { + spin_unlock(&sdp->sd_statfs_spin); + goto out_bh; + } + spin_unlock(&sdp->sd_statfs_spin); + + error = gfs2_meta_inode_buffer(l_ip, &l_bh); + if (error) + goto out_bh; + + error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0); + if (error) + goto out_bh2; + + down(&sdp->sd_statfs_mutex); + gfs2_trans_add_bh(l_ip->i_gl, l_bh); + up(&sdp->sd_statfs_mutex); + + spin_lock(&sdp->sd_statfs_spin); + m_sc->sc_total += l_sc->sc_total; + m_sc->sc_free += l_sc->sc_free; + m_sc->sc_dinodes += l_sc->sc_dinodes; + memset(l_sc, 0, sizeof(struct gfs2_statfs_change)); + memset(l_bh->b_data + sizeof(struct gfs2_dinode), + 0, sizeof(struct gfs2_statfs_change)); + spin_unlock(&sdp->sd_statfs_spin); + + gfs2_trans_add_bh(m_ip->i_gl, m_bh); + gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); + + gfs2_trans_end(sdp); + + out_bh2: + brelse(l_bh); + + out_bh: + brelse(m_bh); + + out: + gfs2_glock_dq_uninit(&gh); + + return error; +} + +/** + * gfs2_statfs_i - Do a statfs + * @sdp: the filesystem + * @sg: the sg structure + * + * Returns: errno + */ + +int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc) +{ + struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; + struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; + + spin_lock(&sdp->sd_statfs_spin); + + *sc = *m_sc; + sc->sc_total += l_sc->sc_total; + sc->sc_free += l_sc->sc_free; + sc->sc_dinodes += l_sc->sc_dinodes; + + spin_unlock(&sdp->sd_statfs_spin); + + if (sc->sc_free < 0) + sc->sc_free = 0; + if (sc->sc_free > sc->sc_total) + sc->sc_free = sc->sc_total; + if (sc->sc_dinodes < 0) + sc->sc_dinodes = 0; + + return 0; +} + +/** + * statfs_fill - fill in the sg for a given RG + * @rgd: the RG + * @sc: the sc structure + * + * Returns: 0 on success, -ESTALE if the LVB is invalid + */ + +static int statfs_slow_fill(struct gfs2_rgrpd *rgd, + struct gfs2_statfs_change *sc) +{ + gfs2_rgrp_verify(rgd); + sc->sc_total += rgd->rd_ri.ri_data; + sc->sc_free += rgd->rd_rg.rg_free; + sc->sc_dinodes += rgd->rd_rg.rg_dinodes; + return 0; +} + +/** + * gfs2_statfs_slow - Stat a filesystem using asynchronous locking + * @sdp: the filesystem + * @sc: the sc info that will be returned + * + * Any error (other than a signal) will cause this routine to fall back + * to the synchronous version. + * + * FIXME: This really shouldn't busy wait like this. + * + * Returns: errno + */ + +int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc) +{ + struct gfs2_holder ri_gh; + struct gfs2_rgrpd *rgd_next; + struct gfs2_holder *gha, *gh; + unsigned int slots = 64; + unsigned int x; + int done; + int error = 0, err; + + memset(sc, 0, sizeof(struct gfs2_statfs_change)); + gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL); + if (!gha) + return -ENOMEM; + + error = gfs2_rindex_hold(sdp, &ri_gh); + if (error) + goto out; + + rgd_next = gfs2_rgrpd_get_first(sdp); + + for (;;) { + done = 1; + + for (x = 0; x < slots; x++) { + gh = gha + x; + + if (gh->gh_gl && gfs2_glock_poll(gh)) { + err = gfs2_glock_wait(gh); + if (err) { + gfs2_holder_uninit(gh); + error = err; + } else { + if (!error) + error = statfs_slow_fill(get_gl2rgd(gh->gh_gl), sc); + gfs2_glock_dq_uninit(gh); + } + } + + if (gh->gh_gl) + done = 0; + else if (rgd_next && !error) { + error = gfs2_glock_nq_init(rgd_next->rd_gl, + LM_ST_SHARED, + GL_ASYNC, + gh); + rgd_next = gfs2_rgrpd_get_next(rgd_next); + done = 0; + } + + if (signal_pending(current)) + error = -ERESTARTSYS; + } + + if (done) + break; + + yield(); + } + + gfs2_glock_dq_uninit(&ri_gh); + + out: + kfree(gha); + + return error; +} + +struct lfcc { + struct list_head list; + struct gfs2_holder gh; +}; + +/** + * gfs2_lock_fs_check_clean - Stop all writes to the FS and check that all + * journals are clean + * @sdp: the file system + * @state: the state to put the transaction lock into + * @t_gh: the hold on the transaction lock + * + * Returns: errno + */ + +int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_holder *t_gh) +{ + struct gfs2_holder ji_gh; + struct gfs2_jdesc *jd; + struct lfcc *lfcc; + LIST_HEAD(list); + struct gfs2_log_header lh; + int error; + + error = gfs2_jindex_hold(sdp, &ji_gh); + if (error) + return error; + + list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { + lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL); + if (!lfcc) { + error = -ENOMEM; + goto out; + } + error = gfs2_glock_nq_init(jd->jd_inode->i_gl, LM_ST_SHARED, 0, + &lfcc->gh); + if (error) { + kfree(lfcc); + goto out; + } + list_add(&lfcc->list, &list); + } + + error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_DEFERRED, + LM_FLAG_PRIORITY | GL_NEVER_RECURSE | GL_NOCACHE, + t_gh); + + list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { + error = gfs2_jdesc_check(jd); + if (error) + break; + error = gfs2_find_jhead(jd, &lh); + if (error) + break; + if (!(lh.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) { + error = -EBUSY; + break; + } + } + + if (error) + gfs2_glock_dq_uninit(t_gh); + + out: + while (!list_empty(&list)) { + lfcc = list_entry(list.next, struct lfcc, list); + list_del(&lfcc->list); + gfs2_glock_dq_uninit(&lfcc->gh); + kfree(lfcc); + } + gfs2_glock_dq_uninit(&ji_gh); + + return error; +} + +/** + * gfs2_freeze_fs - freezes the file system + * @sdp: the file system + * + * This function flushes data and meta data for all machines by + * aquiring the transaction log exclusively. All journals are + * ensured to be in a clean state as well. + * + * Returns: errno + */ + +int gfs2_freeze_fs(struct gfs2_sbd *sdp) +{ + int error = 0; + + down(&sdp->sd_freeze_lock); + + if (!sdp->sd_freeze_count++) { + error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh); + if (error) + sdp->sd_freeze_count--; + } + + up(&sdp->sd_freeze_lock); + + return error; +} + +/** + * gfs2_unfreeze_fs - unfreezes the file system + * @sdp: the file system + * + * This function allows the file system to proceed by unlocking + * the exclusively held transaction lock. Other GFS2 nodes are + * now free to acquire the lock shared and go on with their lives. + * + */ + +void gfs2_unfreeze_fs(struct gfs2_sbd *sdp) +{ + down(&sdp->sd_freeze_lock); + + if (sdp->sd_freeze_count && !--sdp->sd_freeze_count) + gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); + + up(&sdp->sd_freeze_lock); +} + diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h new file mode 100644 index 000000000000..cc1a3df1949a --- /dev/null +++ b/fs/gfs2/super.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __SUPER_DOT_H__ +#define __SUPER_DOT_H__ + +void gfs2_tune_init(struct gfs2_tune *gt); + +int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent); +int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent); +int gfs2_do_upgrade(struct gfs2_sbd *sdp, struct gfs2_glock *gl_sb); + +static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) +{ + unsigned int x; + spin_lock(&sdp->sd_jindex_spin); + x = sdp->sd_journals; + spin_unlock(&sdp->sd_jindex_spin); + return x; +} + +int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh); +void gfs2_jindex_free(struct gfs2_sbd *sdp); + +struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); +void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid); +struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp); +int gfs2_jdesc_check(struct gfs2_jdesc *jd); + +int gfs2_lookup_master_dir(struct gfs2_sbd *sdp); +int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename, + struct gfs2_inode **ipp); + +int gfs2_make_fs_rw(struct gfs2_sbd *sdp); +int gfs2_make_fs_ro(struct gfs2_sbd *sdp); + +int gfs2_statfs_init(struct gfs2_sbd *sdp); +void gfs2_statfs_change(struct gfs2_sbd *sdp, + int64_t total, int64_t free, int64_t dinodes); +int gfs2_statfs_sync(struct gfs2_sbd *sdp); +int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc); +int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc); + +int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_holder *t_gh); +int gfs2_freeze_fs(struct gfs2_sbd *sdp); +void gfs2_unfreeze_fs(struct gfs2_sbd *sdp); + +#endif /* __SUPER_DOT_H__ */ + diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c new file mode 100644 index 000000000000..75e9a3231b8f --- /dev/null +++ b/fs/gfs2/sys.c @@ -0,0 +1,640 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "lm.h" +#include "sys.h" +#include "super.h" +#include "glock.h" +#include "quota.h" + +char *gfs2_sys_margs; +spinlock_t gfs2_sys_margs_lock; + +static ssize_t id_show(struct gfs2_sbd *sdp, char *buf) +{ + return sprintf(buf, "%s\n", sdp->sd_vfs->s_id); +} + +static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf) +{ + return sprintf(buf, "%s\n", sdp->sd_fsname); +} + +static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf) +{ + unsigned int count; + + down(&sdp->sd_freeze_lock); + count = sdp->sd_freeze_count; + up(&sdp->sd_freeze_lock); + + return sprintf(buf, "%u\n", count); +} + +static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +{ + ssize_t ret = len; + int error = 0; + int n = simple_strtol(buf, NULL, 0); + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + switch (n) { + case 0: + gfs2_unfreeze_fs(sdp); + break; + case 1: + error = gfs2_freeze_fs(sdp); + break; + default: + ret = -EINVAL; + } + + if (error) + fs_warn(sdp, "freeze %d error %d", n, error); + + return ret; +} + +static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf) +{ + unsigned int b = test_bit(SDF_SHUTDOWN, &sdp->sd_flags); + return sprintf(buf, "%u\n", b); +} + +static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (simple_strtol(buf, NULL, 0) != 1) + return -EINVAL; + + gfs2_lm_withdraw(sdp, + "GFS2: fsid=%s: withdrawing from cluster at user's request\n", + sdp->sd_fsname); + return len; +} + +static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf, + size_t len) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (simple_strtol(buf, NULL, 0) != 1) + return -EINVAL; + + gfs2_statfs_sync(sdp); + return len; +} + +static ssize_t shrink_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (simple_strtol(buf, NULL, 0) != 1) + return -EINVAL; + + gfs2_gl_hash_clear(sdp, NO_WAIT); + return len; +} + +static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf, + size_t len) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (simple_strtol(buf, NULL, 0) != 1) + return -EINVAL; + + gfs2_quota_sync(sdp); + return len; +} + +static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf, + size_t len) +{ + uint32_t id; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + id = simple_strtoul(buf, NULL, 0); + + gfs2_quota_refresh(sdp, 1, id); + return len; +} + +static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, + size_t len) +{ + uint32_t id; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + id = simple_strtoul(buf, NULL, 0); + + gfs2_quota_refresh(sdp, 0, id); + return len; +} + +struct gfs2_attr { + struct attribute attr; + ssize_t (*show)(struct gfs2_sbd *, char *); + ssize_t (*store)(struct gfs2_sbd *, const char *, size_t); +}; + +#define GFS2_ATTR(name, mode, show, store) \ +static struct gfs2_attr gfs2_attr_##name = __ATTR(name, mode, show, store) + +GFS2_ATTR(id, 0444, id_show, NULL); +GFS2_ATTR(fsname, 0444, fsname_show, NULL); +GFS2_ATTR(freeze, 0644, freeze_show, freeze_store); +GFS2_ATTR(shrink, 0200, NULL, shrink_store); +GFS2_ATTR(withdraw, 0644, withdraw_show, withdraw_store); +GFS2_ATTR(statfs_sync, 0200, NULL, statfs_sync_store); +GFS2_ATTR(quota_sync, 0200, NULL, quota_sync_store); +GFS2_ATTR(quota_refresh_user, 0200, NULL, quota_refresh_user_store); +GFS2_ATTR(quota_refresh_group, 0200, NULL, quota_refresh_group_store); + +static struct attribute *gfs2_attrs[] = { + &gfs2_attr_id.attr, + &gfs2_attr_fsname.attr, + &gfs2_attr_freeze.attr, + &gfs2_attr_shrink.attr, + &gfs2_attr_withdraw.attr, + &gfs2_attr_statfs_sync.attr, + &gfs2_attr_quota_sync.attr, + &gfs2_attr_quota_refresh_user.attr, + &gfs2_attr_quota_refresh_group.attr, + NULL, +}; + +static ssize_t gfs2_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); + struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr); + return a->show ? a->show(sdp, buf) : 0; +} + +static ssize_t gfs2_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len) +{ + struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); + struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr); + return a->store ? a->store(sdp, buf, len) : len; +} + +static struct sysfs_ops gfs2_attr_ops = { + .show = gfs2_attr_show, + .store = gfs2_attr_store, +}; + +static struct kobj_type gfs2_ktype = { + .default_attrs = gfs2_attrs, + .sysfs_ops = &gfs2_attr_ops, +}; + +static struct kset gfs2_kset = { + .subsys = &fs_subsys, + .kobj = {.name = "gfs2",}, + .ktype = &gfs2_ktype, +}; + +/* + * display struct lm_lockstruct fields + */ + +struct lockstruct_attr { + struct attribute attr; + ssize_t (*show)(struct gfs2_sbd *, char *); +}; + +#define LOCKSTRUCT_ATTR(name, fmt) \ +static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \ +{ \ + return sprintf(buf, fmt, sdp->sd_lockstruct.ls_##name); \ +} \ +static struct lockstruct_attr lockstruct_attr_##name = __ATTR_RO(name) + +LOCKSTRUCT_ATTR(jid, "%u\n"); +LOCKSTRUCT_ATTR(first, "%u\n"); +LOCKSTRUCT_ATTR(lvb_size, "%u\n"); +LOCKSTRUCT_ATTR(flags, "%d\n"); + +static struct attribute *lockstruct_attrs[] = { + &lockstruct_attr_jid.attr, + &lockstruct_attr_first.attr, + &lockstruct_attr_lvb_size.attr, + &lockstruct_attr_flags.attr, + NULL +}; + +/* + * display struct gfs2_args fields + */ + +struct args_attr { + struct attribute attr; + ssize_t (*show)(struct gfs2_sbd *, char *); +}; + +#define ARGS_ATTR(name, fmt) \ +static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \ +{ \ + return sprintf(buf, fmt, sdp->sd_args.ar_##name); \ +} \ +static struct args_attr args_attr_##name = __ATTR_RO(name) + +ARGS_ATTR(lockproto, "%s\n"); +ARGS_ATTR(locktable, "%s\n"); +ARGS_ATTR(hostdata, "%s\n"); +ARGS_ATTR(spectator, "%d\n"); +ARGS_ATTR(ignore_local_fs, "%d\n"); +ARGS_ATTR(localcaching, "%d\n"); +ARGS_ATTR(localflocks, "%d\n"); +ARGS_ATTR(debug, "%d\n"); +ARGS_ATTR(upgrade, "%d\n"); +ARGS_ATTR(num_glockd, "%u\n"); +ARGS_ATTR(posix_acl, "%d\n"); +ARGS_ATTR(quota, "%u\n"); +ARGS_ATTR(suiddir, "%d\n"); +ARGS_ATTR(data, "%d\n"); + +/* one oddball doesn't fit the macro mold */ +static ssize_t noatime_show(struct gfs2_sbd *sdp, char *buf) +{ + return sprintf(buf, "%d\n", !!test_bit(SDF_NOATIME, &sdp->sd_flags)); +} +static struct args_attr args_attr_noatime = __ATTR_RO(noatime); + +static struct attribute *args_attrs[] = { + &args_attr_lockproto.attr, + &args_attr_locktable.attr, + &args_attr_hostdata.attr, + &args_attr_spectator.attr, + &args_attr_ignore_local_fs.attr, + &args_attr_localcaching.attr, + &args_attr_localflocks.attr, + &args_attr_debug.attr, + &args_attr_upgrade.attr, + &args_attr_num_glockd.attr, + &args_attr_posix_acl.attr, + &args_attr_quota.attr, + &args_attr_suiddir.attr, + &args_attr_data.attr, + &args_attr_noatime.attr, + NULL +}; + +/* + * display counters from superblock + */ + +struct counters_attr { + struct attribute attr; + ssize_t (*show)(struct gfs2_sbd *, char *); +}; + +#define COUNTERS_ATTR_GENERAL(name, fmt, val) \ +static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \ +{ \ + return sprintf(buf, fmt, val); \ +} \ +static struct counters_attr counters_attr_##name = __ATTR_RO(name) + +#define COUNTERS_ATTR_SIMPLE(name, fmt) \ + COUNTERS_ATTR_GENERAL(name, fmt, sdp->sd_##name) + +#define COUNTERS_ATTR_ATOMIC(name, fmt) \ + COUNTERS_ATTR_GENERAL(name, fmt, (unsigned int)atomic_read(&sdp->sd_##name)) + +COUNTERS_ATTR_ATOMIC(glock_count, "%u\n"); +COUNTERS_ATTR_ATOMIC(glock_held_count, "%u\n"); +COUNTERS_ATTR_ATOMIC(inode_count, "%u\n"); +COUNTERS_ATTR_ATOMIC(bufdata_count, "%u\n"); +COUNTERS_ATTR_ATOMIC(unlinked_count, "%u\n"); +COUNTERS_ATTR_ATOMIC(quota_count, "%u\n"); +COUNTERS_ATTR_SIMPLE(log_num_gl, "%u\n"); +COUNTERS_ATTR_SIMPLE(log_num_buf, "%u\n"); +COUNTERS_ATTR_SIMPLE(log_num_revoke, "%u\n"); +COUNTERS_ATTR_SIMPLE(log_num_rg, "%u\n"); +COUNTERS_ATTR_SIMPLE(log_num_databuf, "%u\n"); +COUNTERS_ATTR_SIMPLE(log_blks_free, "%u\n"); +COUNTERS_ATTR_GENERAL(jd_blocks, "%u\n", sdp->sd_jdesc->jd_blocks); +COUNTERS_ATTR_ATOMIC(reclaim_count, "%u\n"); +COUNTERS_ATTR_SIMPLE(log_wraps, "%llu\n"); +COUNTERS_ATTR_ATOMIC(fh2dentry_misses, "%u\n"); +COUNTERS_ATTR_ATOMIC(reclaimed, "%u\n"); +COUNTERS_ATTR_ATOMIC(log_flush_incore, "%u\n"); +COUNTERS_ATTR_ATOMIC(log_flush_ondisk, "%u\n"); +COUNTERS_ATTR_ATOMIC(glock_nq_calls, "%u\n"); +COUNTERS_ATTR_ATOMIC(glock_dq_calls, "%u\n"); +COUNTERS_ATTR_ATOMIC(glock_prefetch_calls, "%u\n"); +COUNTERS_ATTR_ATOMIC(lm_lock_calls, "%u\n"); +COUNTERS_ATTR_ATOMIC(lm_unlock_calls, "%u\n"); +COUNTERS_ATTR_ATOMIC(lm_callbacks, "%u\n"); +COUNTERS_ATTR_ATOMIC(ops_address, "%u\n"); +COUNTERS_ATTR_ATOMIC(ops_dentry, "%u\n"); +COUNTERS_ATTR_ATOMIC(ops_export, "%u\n"); +COUNTERS_ATTR_ATOMIC(ops_file, "%u\n"); +COUNTERS_ATTR_ATOMIC(ops_inode, "%u\n"); +COUNTERS_ATTR_ATOMIC(ops_super, "%u\n"); +COUNTERS_ATTR_ATOMIC(ops_vm, "%u\n"); + +static struct attribute *counters_attrs[] = { + &counters_attr_glock_count.attr, + &counters_attr_glock_held_count.attr, + &counters_attr_inode_count.attr, + &counters_attr_bufdata_count.attr, + &counters_attr_unlinked_count.attr, + &counters_attr_quota_count.attr, + &counters_attr_log_num_gl.attr, + &counters_attr_log_num_buf.attr, + &counters_attr_log_num_revoke.attr, + &counters_attr_log_num_rg.attr, + &counters_attr_log_num_databuf.attr, + &counters_attr_log_blks_free.attr, + &counters_attr_jd_blocks.attr, + &counters_attr_reclaim_count.attr, + &counters_attr_log_wraps.attr, + &counters_attr_fh2dentry_misses.attr, + &counters_attr_reclaimed.attr, + &counters_attr_log_flush_incore.attr, + &counters_attr_log_flush_ondisk.attr, + &counters_attr_glock_nq_calls.attr, + &counters_attr_glock_dq_calls.attr, + &counters_attr_glock_prefetch_calls.attr, + &counters_attr_lm_lock_calls.attr, + &counters_attr_lm_unlock_calls.attr, + &counters_attr_lm_callbacks.attr, + &counters_attr_ops_address.attr, + &counters_attr_ops_dentry.attr, + &counters_attr_ops_export.attr, + &counters_attr_ops_file.attr, + &counters_attr_ops_inode.attr, + &counters_attr_ops_super.attr, + &counters_attr_ops_vm.attr, + NULL +}; + +/* + * get and set struct gfs2_tune fields + */ + +static ssize_t quota_scale_show(struct gfs2_sbd *sdp, char *buf) +{ + return sprintf(buf, "%u %u\n", sdp->sd_tune.gt_quota_scale_num, + sdp->sd_tune.gt_quota_scale_den); +} + +static ssize_t quota_scale_store(struct gfs2_sbd *sdp, const char *buf, + size_t len) +{ + struct gfs2_tune *gt = &sdp->sd_tune; + unsigned int x, y; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (sscanf(buf, "%u %u", &x, &y) != 2 || !y) + return -EINVAL; + + spin_lock(>->gt_spin); + gt->gt_quota_scale_num = x; + gt->gt_quota_scale_den = y; + spin_unlock(>->gt_spin); + return len; +} + +static ssize_t tune_set(struct gfs2_sbd *sdp, unsigned int *field, + int check_zero, const char *buf, size_t len) +{ + struct gfs2_tune *gt = &sdp->sd_tune; + unsigned int x; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + x = simple_strtoul(buf, NULL, 0); + + if (check_zero && !x) + return -EINVAL; + + spin_lock(>->gt_spin); + *field = x; + spin_unlock(>->gt_spin); + return len; +} + +struct tune_attr { + struct attribute attr; + ssize_t (*show)(struct gfs2_sbd *, char *); + ssize_t (*store)(struct gfs2_sbd *, const char *, size_t); +}; + +#define TUNE_ATTR_3(name, show, store) \ +static struct tune_attr tune_attr_##name = __ATTR(name, 0644, show, store) + +#define TUNE_ATTR_2(name, store) \ +static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \ +{ \ + return sprintf(buf, "%u\n", sdp->sd_tune.gt_##name); \ +} \ +TUNE_ATTR_3(name, name##_show, store) + +#define TUNE_ATTR(name, check_zero) \ +static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\ +{ \ + return tune_set(sdp, &sdp->sd_tune.gt_##name, check_zero, buf, len); \ +} \ +TUNE_ATTR_2(name, name##_store) + +#define TUNE_ATTR_DAEMON(name, process) \ +static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\ +{ \ + ssize_t r = tune_set(sdp, &sdp->sd_tune.gt_##name, 1, buf, len); \ + wake_up_process(sdp->sd_##process); \ + return r; \ +} \ +TUNE_ATTR_2(name, name##_store) + +TUNE_ATTR(ilimit, 0); +TUNE_ATTR(ilimit_tries, 0); +TUNE_ATTR(ilimit_min, 0); +TUNE_ATTR(demote_secs, 0); +TUNE_ATTR(incore_log_blocks, 0); +TUNE_ATTR(log_flush_secs, 0); +TUNE_ATTR(jindex_refresh_secs, 0); +TUNE_ATTR(quota_warn_period, 0); +TUNE_ATTR(quota_quantum, 0); +TUNE_ATTR(atime_quantum, 0); +TUNE_ATTR(max_readahead, 0); +TUNE_ATTR(complain_secs, 0); +TUNE_ATTR(reclaim_limit, 0); +TUNE_ATTR(prefetch_secs, 0); +TUNE_ATTR(statfs_slow, 0); +TUNE_ATTR(new_files_jdata, 0); +TUNE_ATTR(new_files_directio, 0); +TUNE_ATTR(quota_simul_sync, 1); +TUNE_ATTR(quota_cache_secs, 1); +TUNE_ATTR(max_atomic_write, 1); +TUNE_ATTR(stall_secs, 1); +TUNE_ATTR(entries_per_readdir, 1); +TUNE_ATTR(greedy_default, 1); +TUNE_ATTR(greedy_quantum, 1); +TUNE_ATTR(greedy_max, 1); +TUNE_ATTR(statfs_quantum, 1); +TUNE_ATTR_DAEMON(scand_secs, scand_process); +TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process); +TUNE_ATTR_DAEMON(logd_secs, logd_process); +TUNE_ATTR_DAEMON(quotad_secs, quotad_process); +TUNE_ATTR_DAEMON(inoded_secs, inoded_process); +TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store); + +static struct attribute *tune_attrs[] = { + &tune_attr_ilimit.attr, + &tune_attr_ilimit_tries.attr, + &tune_attr_ilimit_min.attr, + &tune_attr_demote_secs.attr, + &tune_attr_incore_log_blocks.attr, + &tune_attr_log_flush_secs.attr, + &tune_attr_jindex_refresh_secs.attr, + &tune_attr_quota_warn_period.attr, + &tune_attr_quota_quantum.attr, + &tune_attr_atime_quantum.attr, + &tune_attr_max_readahead.attr, + &tune_attr_complain_secs.attr, + &tune_attr_reclaim_limit.attr, + &tune_attr_prefetch_secs.attr, + &tune_attr_statfs_slow.attr, + &tune_attr_quota_simul_sync.attr, + &tune_attr_quota_cache_secs.attr, + &tune_attr_max_atomic_write.attr, + &tune_attr_stall_secs.attr, + &tune_attr_entries_per_readdir.attr, + &tune_attr_greedy_default.attr, + &tune_attr_greedy_quantum.attr, + &tune_attr_greedy_max.attr, + &tune_attr_statfs_quantum.attr, + &tune_attr_scand_secs.attr, + &tune_attr_recoverd_secs.attr, + &tune_attr_logd_secs.attr, + &tune_attr_quotad_secs.attr, + &tune_attr_inoded_secs.attr, + &tune_attr_quota_scale.attr, + &tune_attr_new_files_jdata.attr, + &tune_attr_new_files_directio.attr, + NULL +}; + +static struct attribute_group lockstruct_group = { + .name = "lockstruct", + .attrs = lockstruct_attrs +}; + +static struct attribute_group counters_group = { + .name = "counters", + .attrs = counters_attrs +}; + +static struct attribute_group args_group = { + .name = "args", + .attrs = args_attrs +}; + +static struct attribute_group tune_group = { + .name = "tune", + .attrs = tune_attrs +}; + +int gfs2_sys_fs_add(struct gfs2_sbd *sdp) +{ + int error; + + sdp->sd_kobj.kset = &gfs2_kset; + sdp->sd_kobj.ktype = &gfs2_ktype; + + error = kobject_set_name(&sdp->sd_kobj, "%s", sdp->sd_table_name); + if (error) + goto fail; + + error = kobject_register(&sdp->sd_kobj); + if (error) + goto fail; + + error = sysfs_create_group(&sdp->sd_kobj, &lockstruct_group); + if (error) + goto fail_reg; + + error = sysfs_create_group(&sdp->sd_kobj, &counters_group); + if (error) + goto fail_lockstruct; + + error = sysfs_create_group(&sdp->sd_kobj, &args_group); + if (error) + goto fail_counters; + + error = sysfs_create_group(&sdp->sd_kobj, &tune_group); + if (error) + goto fail_args; + + return 0; + + fail_args: + sysfs_remove_group(&sdp->sd_kobj, &args_group); + fail_counters: + sysfs_remove_group(&sdp->sd_kobj, &counters_group); + fail_lockstruct: + sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group); + fail_reg: + kobject_unregister(&sdp->sd_kobj); + fail: + return error; +} + +void gfs2_sys_fs_del(struct gfs2_sbd *sdp) +{ + sysfs_remove_group(&sdp->sd_kobj, &tune_group); + sysfs_remove_group(&sdp->sd_kobj, &args_group); + sysfs_remove_group(&sdp->sd_kobj, &counters_group); + sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group); + kobject_unregister(&sdp->sd_kobj); +} + +int gfs2_sys_init(void) +{ + gfs2_sys_margs = NULL; + spin_lock_init(&gfs2_sys_margs_lock); + return kset_register(&gfs2_kset); +} + +void gfs2_sys_uninit(void) +{ + kfree(gfs2_sys_margs); + kset_unregister(&gfs2_kset); +} + diff --git a/fs/gfs2/sys.h b/fs/gfs2/sys.h new file mode 100644 index 000000000000..62c8ed89ab9c --- /dev/null +++ b/fs/gfs2/sys.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __SYS_DOT_H__ +#define __SYS_DOT_H__ + +/* Allow args to be passed to GFS2 when using an initial ram disk */ +extern char *gfs2_sys_margs; +extern spinlock_t gfs2_sys_margs_lock; + +int gfs2_sys_fs_add(struct gfs2_sbd *sdp); +void gfs2_sys_fs_del(struct gfs2_sbd *sdp); + +int gfs2_sys_init(void); +void gfs2_sys_uninit(void); + +#endif /* __SYS_DOT_H__ */ + diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c new file mode 100644 index 000000000000..afa5408c0008 --- /dev/null +++ b/fs/gfs2/trans.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "glock.h" +#include "log.h" +#include "lops.h" +#include "meta_io.h" +#include "trans.h" + +int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, + unsigned int revokes, char *file, unsigned int line) +{ + struct gfs2_trans *tr; + int error; + + if (gfs2_assert_warn(sdp, !get_transaction) || + gfs2_assert_warn(sdp, blocks || revokes)) { + fs_warn(sdp, "(%s, %u)\n", file, line); + return -EINVAL; + } + + tr = kzalloc(sizeof(struct gfs2_trans), GFP_KERNEL); + if (!tr) + return -ENOMEM; + + tr->tr_file = file; + tr->tr_line = line; + tr->tr_blocks = blocks; + tr->tr_revokes = revokes; + tr->tr_reserved = 1; + if (blocks) + tr->tr_reserved += 1 + blocks; + if (revokes) + tr->tr_reserved += gfs2_struct2blk(sdp, revokes, + sizeof(uint64_t)); + INIT_LIST_HEAD(&tr->tr_list_buf); + + error = -ENOMEM; + tr->tr_t_gh = gfs2_holder_get(sdp->sd_trans_gl, LM_ST_SHARED, + GL_NEVER_RECURSE, GFP_KERNEL); + if (!tr->tr_t_gh) + goto fail; + + error = gfs2_glock_nq(tr->tr_t_gh); + if (error) + goto fail_holder_put; + + if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { + tr->tr_t_gh->gh_flags |= GL_NOCACHE; + error = -EROFS; + goto fail_gunlock; + } + + error = gfs2_log_reserve(sdp, tr->tr_reserved); + if (error) + goto fail_gunlock; + + set_transaction(tr); + + return 0; + + fail_gunlock: + gfs2_glock_dq(tr->tr_t_gh); + + fail_holder_put: + gfs2_holder_put(tr->tr_t_gh); + + fail: + kfree(tr); + + return error; +} + +void gfs2_trans_end(struct gfs2_sbd *sdp) +{ + struct gfs2_trans *tr; + struct gfs2_holder *t_gh; + + tr = get_transaction; + set_transaction(NULL); + + if (gfs2_assert_warn(sdp, tr)) + return; + + t_gh = tr->tr_t_gh; + tr->tr_t_gh = NULL; + + if (!tr->tr_touched) { + gfs2_log_release(sdp, tr->tr_reserved); + kfree(tr); + + gfs2_glock_dq(t_gh); + gfs2_holder_put(t_gh); + + return; + } + + if (gfs2_assert_withdraw(sdp, tr->tr_num_buf <= tr->tr_blocks)) + fs_err(sdp, "tr_num_buf = %u, tr_blocks = %u " + "tr_file = %s, tr_line = %u\n", + tr->tr_num_buf, tr->tr_blocks, + tr->tr_file, tr->tr_line); + if (gfs2_assert_withdraw(sdp, tr->tr_num_revoke <= tr->tr_revokes)) + fs_err(sdp, "tr_num_revoke = %u, tr_revokes = %u " + "tr_file = %s, tr_line = %u\n", + tr->tr_num_revoke, tr->tr_revokes, + tr->tr_file, tr->tr_line); + + gfs2_log_commit(sdp, tr); + + gfs2_glock_dq(t_gh); + gfs2_holder_put(t_gh); + + if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS) + gfs2_log_flush(sdp); +} + +void gfs2_trans_add_gl(struct gfs2_glock *gl) +{ + lops_add(gl->gl_sbd, &gl->gl_le); +} + +/** + * gfs2_trans_add_bh - Add a to-be-modified buffer to the current transaction + * @gl: the glock the buffer belongs to + * @bh: The buffer to add + * + */ + +void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_bufdata *bd; + + bd = get_v2bd(bh); + if (bd) + gfs2_assert(sdp, bd->bd_gl == gl); + else { + gfs2_meta_attach_bufdata(gl, bh); + bd = get_v2bd(bh); + } + + lops_add(sdp, &bd->bd_le); +} + +void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, uint64_t blkno) +{ + struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke), + GFP_KERNEL | __GFP_NOFAIL); + lops_init_le(&rv->rv_le, &gfs2_revoke_lops); + rv->rv_blkno = blkno; + lops_add(sdp, &rv->rv_le); +} + +void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, uint64_t blkno) +{ + struct gfs2_revoke *rv; + int found = 0; + + gfs2_log_lock(sdp); + + list_for_each_entry(rv, &sdp->sd_log_le_revoke, rv_le.le_list) { + if (rv->rv_blkno == blkno) { + list_del(&rv->rv_le.le_list); + gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke); + sdp->sd_log_num_revoke--; + found = 1; + break; + } + } + + gfs2_log_unlock(sdp); + + if (found) { + kfree(rv); + get_transaction->tr_num_revoke_rm++; + } +} + +void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd) +{ + lops_add(rgd->rd_sbd, &rgd->rd_le); +} + +void gfs2_trans_add_databuf(struct gfs2_sbd *sdp, struct buffer_head *bh) +{ + struct gfs2_databuf *db; + + db = get_v2db(bh); + if (!db) { + db = kmalloc(sizeof(struct gfs2_databuf), + GFP_KERNEL | __GFP_NOFAIL); + lops_init_le(&db->db_le, &gfs2_databuf_lops); + get_bh(bh); + db->db_bh = bh; + set_v2db(bh, db); + lops_add(sdp, &db->db_le); + } +} + diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h new file mode 100644 index 000000000000..ac615e9e8521 --- /dev/null +++ b/fs/gfs2/trans.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __TRANS_DOT_H__ +#define __TRANS_DOT_H__ + +#define RES_DINODE 1 +#define RES_INDIRECT 1 +#define RES_JDATA 1 +#define RES_DATA 1 +#define RES_LEAF 1 +#define RES_RG_BIT 2 +#define RES_EATTR 1 +#define RES_UNLINKED 1 +#define RES_STATFS 1 +#define RES_QUOTA 2 + +#define gfs2_trans_begin(sdp, blocks, revokes) \ +gfs2_trans_begin_i((sdp), (blocks), (revokes), __FILE__, __LINE__) + +int gfs2_trans_begin_i(struct gfs2_sbd *sdp, + unsigned int blocks, unsigned int revokes, + char *file, unsigned int line); + +void gfs2_trans_end(struct gfs2_sbd *sdp); + +void gfs2_trans_add_gl(struct gfs2_glock *gl); +void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh); +void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, uint64_t blkno); +void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, uint64_t blkno); +void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd); +void gfs2_trans_add_databuf(struct gfs2_sbd *sdp, struct buffer_head *bh); + +#endif /* __TRANS_DOT_H__ */ diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c new file mode 100644 index 000000000000..4a993af58c1a --- /dev/null +++ b/fs/gfs2/unlinked.c @@ -0,0 +1,453 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "bmap.h" +#include "inode.h" +#include "meta_io.h" +#include "trans.h" +#include "unlinked.h" + +static int munge_ondisk(struct gfs2_sbd *sdp, unsigned int slot, + struct gfs2_unlinked_tag *ut) +{ + struct gfs2_inode *ip = sdp->sd_ut_inode; + unsigned int block, offset; + uint64_t dblock; + int new = 0; + struct buffer_head *bh; + int error; + + block = slot / sdp->sd_ut_per_block; + offset = slot % sdp->sd_ut_per_block; + + error = gfs2_block_map(ip, block, &new, &dblock, NULL); + if (error) + return error; + error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); + if (error) + return error; + if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_UT)) { + error = -EIO; + goto out; + } + + down(&sdp->sd_unlinked_mutex); + gfs2_trans_add_bh(ip->i_gl, bh); + gfs2_unlinked_tag_out(ut, bh->b_data + + sizeof(struct gfs2_meta_header) + + offset * sizeof(struct gfs2_unlinked_tag)); + up(&sdp->sd_unlinked_mutex); + + out: + brelse(bh); + + return error; +} + +static void ul_hash(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) +{ + spin_lock(&sdp->sd_unlinked_spin); + list_add(&ul->ul_list, &sdp->sd_unlinked_list); + gfs2_assert(sdp, ul->ul_count); + ul->ul_count++; + atomic_inc(&sdp->sd_unlinked_count); + spin_unlock(&sdp->sd_unlinked_spin); +} + +static void ul_unhash(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) +{ + spin_lock(&sdp->sd_unlinked_spin); + list_del_init(&ul->ul_list); + gfs2_assert(sdp, ul->ul_count > 1); + ul->ul_count--; + gfs2_assert_warn(sdp, atomic_read(&sdp->sd_unlinked_count) > 0); + atomic_dec(&sdp->sd_unlinked_count); + spin_unlock(&sdp->sd_unlinked_spin); +} + +static struct gfs2_unlinked *ul_fish(struct gfs2_sbd *sdp) +{ + struct list_head *head; + struct gfs2_unlinked *ul; + int found = 0; + + if (sdp->sd_vfs->s_flags & MS_RDONLY) + return NULL; + + spin_lock(&sdp->sd_unlinked_spin); + + head = &sdp->sd_unlinked_list; + + list_for_each_entry(ul, head, ul_list) { + if (test_bit(ULF_LOCKED, &ul->ul_flags)) + continue; + + list_move_tail(&ul->ul_list, head); + ul->ul_count++; + set_bit(ULF_LOCKED, &ul->ul_flags); + found = 1; + + break; + } + + if (!found) + ul = NULL; + + spin_unlock(&sdp->sd_unlinked_spin); + + return ul; +} + +/** + * enforce_limit - limit the number of inodes waiting to be deallocated + * @sdp: the filesystem + * + * Returns: errno + */ + +static void enforce_limit(struct gfs2_sbd *sdp) +{ + unsigned int tries = 0, min = 0; + int error; + + if (atomic_read(&sdp->sd_unlinked_count) >= + gfs2_tune_get(sdp, gt_ilimit)) { + tries = gfs2_tune_get(sdp, gt_ilimit_tries); + min = gfs2_tune_get(sdp, gt_ilimit_min); + } + + while (tries--) { + struct gfs2_unlinked *ul = ul_fish(sdp); + if (!ul) + break; + error = gfs2_inode_dealloc(sdp, ul); + gfs2_unlinked_put(sdp, ul); + + if (!error) { + if (!--min) + break; + } else if (error != 1) + break; + } +} + +static struct gfs2_unlinked *ul_alloc(struct gfs2_sbd *sdp) +{ + struct gfs2_unlinked *ul; + + ul = kzalloc(sizeof(struct gfs2_unlinked), GFP_KERNEL); + if (ul) { + INIT_LIST_HEAD(&ul->ul_list); + ul->ul_count = 1; + set_bit(ULF_LOCKED, &ul->ul_flags); + } + + return ul; +} + +int gfs2_unlinked_get(struct gfs2_sbd *sdp, struct gfs2_unlinked **ul) +{ + unsigned int c, o = 0, b; + unsigned char byte = 0; + + enforce_limit(sdp); + + *ul = ul_alloc(sdp); + if (!*ul) + return -ENOMEM; + + spin_lock(&sdp->sd_unlinked_spin); + + for (c = 0; c < sdp->sd_unlinked_chunks; c++) + for (o = 0; o < PAGE_SIZE; o++) { + byte = sdp->sd_unlinked_bitmap[c][o]; + if (byte != 0xFF) + goto found; + } + + goto fail; + + found: + for (b = 0; b < 8; b++) + if (!(byte & (1 << b))) + break; + (*ul)->ul_slot = c * (8 * PAGE_SIZE) + o * 8 + b; + + if ((*ul)->ul_slot >= sdp->sd_unlinked_slots) + goto fail; + + sdp->sd_unlinked_bitmap[c][o] |= 1 << b; + + spin_unlock(&sdp->sd_unlinked_spin); + + return 0; + + fail: + spin_unlock(&sdp->sd_unlinked_spin); + kfree(*ul); + return -ENOSPC; +} + +void gfs2_unlinked_put(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) +{ + gfs2_assert_warn(sdp, test_and_clear_bit(ULF_LOCKED, &ul->ul_flags)); + + spin_lock(&sdp->sd_unlinked_spin); + gfs2_assert(sdp, ul->ul_count); + ul->ul_count--; + if (!ul->ul_count) { + gfs2_icbit_munge(sdp, sdp->sd_unlinked_bitmap, ul->ul_slot, 0); + spin_unlock(&sdp->sd_unlinked_spin); + kfree(ul); + } else + spin_unlock(&sdp->sd_unlinked_spin); +} + +int gfs2_unlinked_ondisk_add(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) +{ + int error; + + gfs2_assert_warn(sdp, test_bit(ULF_LOCKED, &ul->ul_flags)); + gfs2_assert_warn(sdp, list_empty(&ul->ul_list)); + + error = munge_ondisk(sdp, ul->ul_slot, &ul->ul_ut); + if (!error) + ul_hash(sdp, ul); + + return error; +} + +int gfs2_unlinked_ondisk_munge(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) +{ + int error; + + gfs2_assert_warn(sdp, test_bit(ULF_LOCKED, &ul->ul_flags)); + gfs2_assert_warn(sdp, !list_empty(&ul->ul_list)); + + error = munge_ondisk(sdp, ul->ul_slot, &ul->ul_ut); + + return error; +} + +int gfs2_unlinked_ondisk_rm(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) +{ + struct gfs2_unlinked_tag ut; + int error; + + gfs2_assert_warn(sdp, test_bit(ULF_LOCKED, &ul->ul_flags)); + gfs2_assert_warn(sdp, !list_empty(&ul->ul_list)); + + memset(&ut, 0, sizeof(struct gfs2_unlinked_tag)); + + error = munge_ondisk(sdp, ul->ul_slot, &ut); + if (error) + return error; + + ul_unhash(sdp, ul); + + return 0; +} + +/** + * gfs2_unlinked_dealloc - Go through the list of inodes to be deallocated + * @sdp: the filesystem + * + * Returns: errno + */ + +int gfs2_unlinked_dealloc(struct gfs2_sbd *sdp) +{ + unsigned int hits, strikes; + int error; + + for (;;) { + hits = 0; + strikes = 0; + + for (;;) { + struct gfs2_unlinked *ul = ul_fish(sdp); + if (!ul) + return 0; + error = gfs2_inode_dealloc(sdp, ul); + gfs2_unlinked_put(sdp, ul); + + if (!error) { + hits++; + if (strikes) + strikes--; + } else if (error == 1) { + strikes++; + if (strikes >= + atomic_read(&sdp->sd_unlinked_count)) { + error = 0; + break; + } + } else + return error; + } + + if (!hits || kthread_should_stop()) + break; + + cond_resched(); + } + + return 0; +} + +int gfs2_unlinked_init(struct gfs2_sbd *sdp) +{ + struct gfs2_inode *ip = sdp->sd_ut_inode; + unsigned int blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; + unsigned int x, slot = 0; + unsigned int found = 0; + uint64_t dblock; + uint32_t extlen = 0; + int error; + + if (!ip->i_di.di_size || + ip->i_di.di_size > (64 << 20) || + ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1)) { + gfs2_consist_inode(ip); + return -EIO; + } + sdp->sd_unlinked_slots = blocks * sdp->sd_ut_per_block; + sdp->sd_unlinked_chunks = DIV_RU(sdp->sd_unlinked_slots, 8 * PAGE_SIZE); + + error = -ENOMEM; + + sdp->sd_unlinked_bitmap = kcalloc(sdp->sd_unlinked_chunks, + sizeof(unsigned char *), + GFP_KERNEL); + if (!sdp->sd_unlinked_bitmap) + return error; + + for (x = 0; x < sdp->sd_unlinked_chunks; x++) { + sdp->sd_unlinked_bitmap[x] = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!sdp->sd_unlinked_bitmap[x]) + goto fail; + } + + for (x = 0; x < blocks; x++) { + struct buffer_head *bh; + unsigned int y; + + if (!extlen) { + int new = 0; + error = gfs2_block_map(ip, x, &new, &dblock, &extlen); + if (error) + goto fail; + } + gfs2_meta_ra(ip->i_gl, dblock, extlen); + error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, + &bh); + if (error) + goto fail; + error = -EIO; + if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_UT)) { + brelse(bh); + goto fail; + } + + for (y = 0; + y < sdp->sd_ut_per_block && slot < sdp->sd_unlinked_slots; + y++, slot++) { + struct gfs2_unlinked_tag ut; + struct gfs2_unlinked *ul; + + gfs2_unlinked_tag_in(&ut, bh->b_data + + sizeof(struct gfs2_meta_header) + + y * sizeof(struct gfs2_unlinked_tag)); + if (!ut.ut_inum.no_addr) + continue; + + error = -ENOMEM; + ul = ul_alloc(sdp); + if (!ul) { + brelse(bh); + goto fail; + } + ul->ul_ut = ut; + ul->ul_slot = slot; + + spin_lock(&sdp->sd_unlinked_spin); + gfs2_icbit_munge(sdp, sdp->sd_unlinked_bitmap, slot, 1); + spin_unlock(&sdp->sd_unlinked_spin); + ul_hash(sdp, ul); + + gfs2_unlinked_put(sdp, ul); + found++; + } + + brelse(bh); + dblock++; + extlen--; + } + + if (found) + fs_info(sdp, "found %u unlinked inodes\n", found); + + return 0; + + fail: + gfs2_unlinked_cleanup(sdp); + return error; +} + +/** + * gfs2_unlinked_cleanup - get rid of any extra struct gfs2_unlinked structures + * @sdp: the filesystem + * + */ + +void gfs2_unlinked_cleanup(struct gfs2_sbd *sdp) +{ + struct list_head *head = &sdp->sd_unlinked_list; + struct gfs2_unlinked *ul; + unsigned int x; + + spin_lock(&sdp->sd_unlinked_spin); + while (!list_empty(head)) { + ul = list_entry(head->next, struct gfs2_unlinked, ul_list); + + if (ul->ul_count > 1) { + list_move_tail(&ul->ul_list, head); + spin_unlock(&sdp->sd_unlinked_spin); + schedule(); + spin_lock(&sdp->sd_unlinked_spin); + continue; + } + + list_del_init(&ul->ul_list); + atomic_dec(&sdp->sd_unlinked_count); + + gfs2_assert_warn(sdp, ul->ul_count == 1); + gfs2_assert_warn(sdp, !test_bit(ULF_LOCKED, &ul->ul_flags)); + kfree(ul); + } + spin_unlock(&sdp->sd_unlinked_spin); + + gfs2_assert_warn(sdp, !atomic_read(&sdp->sd_unlinked_count)); + + if (sdp->sd_unlinked_bitmap) { + for (x = 0; x < sdp->sd_unlinked_chunks; x++) + kfree(sdp->sd_unlinked_bitmap[x]); + kfree(sdp->sd_unlinked_bitmap); + } +} + diff --git a/fs/gfs2/unlinked.h b/fs/gfs2/unlinked.h new file mode 100644 index 000000000000..51e77f88d74f --- /dev/null +++ b/fs/gfs2/unlinked.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __UNLINKED_DOT_H__ +#define __UNLINKED_DOT_H__ + +int gfs2_unlinked_get(struct gfs2_sbd *sdp, struct gfs2_unlinked **ul); +void gfs2_unlinked_put(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); + +int gfs2_unlinked_ondisk_add(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); +int gfs2_unlinked_ondisk_munge(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); +int gfs2_unlinked_ondisk_rm(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); + +int gfs2_unlinked_dealloc(struct gfs2_sbd *sdp); + +int gfs2_unlinked_init(struct gfs2_sbd *sdp); +void gfs2_unlinked_cleanup(struct gfs2_sbd *sdp); + +#endif /* __UNLINKED_DOT_H__ */ diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c new file mode 100644 index 000000000000..74e2c62f2370 --- /dev/null +++ b/fs/gfs2/util.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "glock.h" +#include "lm.h" + +kmem_cache_t *gfs2_glock_cachep __read_mostly; +kmem_cache_t *gfs2_inode_cachep __read_mostly; +kmem_cache_t *gfs2_bufdata_cachep __read_mostly; + +uint32_t gfs2_disk_hash(const char *data, int len) +{ + return crc32_le(0xFFFFFFFF, data, len) ^ 0xFFFFFFFF; +} + +void gfs2_assert_i(struct gfs2_sbd *sdp) +{ + printk(KERN_EMERG "GFS2: fsid=%s: fatal assertion failed\n", + sdp->sd_fsname); +} + +/** + * gfs2_assert_withdraw_i - Cause the machine to withdraw if @assertion is false + * Returns: -1 if this call withdrew the machine, + * -2 if it was already withdrawn + */ + +int gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion, + const char *function, char *file, unsigned int line) +{ + int me; + me = gfs2_lm_withdraw(sdp, + "GFS2: fsid=%s: fatal: assertion \"%s\" failed\n" + "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", + sdp->sd_fsname, assertion, + sdp->sd_fsname, function, file, line); + return (me) ? -1 : -2; +} + +/** + * gfs2_assert_warn_i - Print a message to the console if @assertion is false + * Returns: -1 if we printed something + * -2 if we didn't + */ + +int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, + const char *function, char *file, unsigned int line) +{ + if (time_before(jiffies, + sdp->sd_last_warning + + gfs2_tune_get(sdp, gt_complain_secs) * HZ)) + return -2; + + printk(KERN_WARNING + "GFS2: fsid=%s: warning: assertion \"%s\" failed\n" + "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", + sdp->sd_fsname, assertion, + sdp->sd_fsname, function, file, line); + + if (sdp->sd_args.ar_debug) + BUG(); + + sdp->sd_last_warning = jiffies; + + return -1; +} + +/** + * gfs2_consist_i - Flag a filesystem consistency error and withdraw + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide, const char *function, + char *file, unsigned int line) +{ + int rv; + rv = gfs2_lm_withdraw(sdp, + "GFS2: fsid=%s: fatal: filesystem consistency error\n" + "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", + sdp->sd_fsname, + sdp->sd_fsname, function, file, line); + return rv; +} + +/** + * gfs2_consist_inode_i - Flag an inode consistency error and withdraw + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide, + const char *function, char *file, unsigned int line) +{ + struct gfs2_sbd *sdp = ip->i_sbd; + int rv; + rv = gfs2_lm_withdraw(sdp, + "GFS2: fsid=%s: fatal: filesystem consistency error\n" + "GFS2: fsid=%s: inode = %llu %llu\n" + "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", + sdp->sd_fsname, + sdp->sd_fsname, ip->i_num.no_formal_ino, ip->i_num.no_addr, + sdp->sd_fsname, function, file, line); + return rv; +} + +/** + * gfs2_consist_rgrpd_i - Flag a RG consistency error and withdraw + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide, + const char *function, char *file, unsigned int line) +{ + struct gfs2_sbd *sdp = rgd->rd_sbd; + int rv; + rv = gfs2_lm_withdraw(sdp, + "GFS2: fsid=%s: fatal: filesystem consistency error\n" + "GFS2: fsid=%s: RG = %llu\n" + "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", + sdp->sd_fsname, + sdp->sd_fsname, rgd->rd_ri.ri_addr, + sdp->sd_fsname, function, file, line); + return rv; +} + +/** + * gfs2_meta_check_ii - Flag a magic number consistency error and withdraw + * Returns: -1 if this call withdrew the machine, + * -2 if it was already withdrawn + */ + +int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, + const char *type, const char *function, char *file, + unsigned int line) +{ + int me; + me = gfs2_lm_withdraw(sdp, + "GFS2: fsid=%s: fatal: invalid metadata block\n" + "GFS2: fsid=%s: bh = %llu (%s)\n" + "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", + sdp->sd_fsname, + sdp->sd_fsname, (uint64_t)bh->b_blocknr, type, + sdp->sd_fsname, function, file, line); + return (me) ? -1 : -2; +} + +/** + * gfs2_metatype_check_ii - Flag a metadata type consistency error and withdraw + * Returns: -1 if this call withdrew the machine, + * -2 if it was already withdrawn + */ + +int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, + uint16_t type, uint16_t t, const char *function, + char *file, unsigned int line) +{ + int me; + me = gfs2_lm_withdraw(sdp, + "GFS2: fsid=%s: fatal: invalid metadata block\n" + "GFS2: fsid=%s: bh = %llu (type: exp=%u, found=%u)\n" + "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", + sdp->sd_fsname, + sdp->sd_fsname, (uint64_t)bh->b_blocknr, type, t, + sdp->sd_fsname, function, file, line); + return (me) ? -1 : -2; +} + +/** + * gfs2_io_error_i - Flag an I/O error and withdraw + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function, char *file, + unsigned int line) +{ + int rv; + rv = gfs2_lm_withdraw(sdp, + "GFS2: fsid=%s: fatal: I/O error\n" + "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", + sdp->sd_fsname, + sdp->sd_fsname, function, file, line); + return rv; +} + +/** + * gfs2_io_error_bh_i - Flag a buffer I/O error and withdraw + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, + const char *function, char *file, unsigned int line) +{ + int rv; + rv = gfs2_lm_withdraw(sdp, + "GFS2: fsid=%s: fatal: I/O error\n" + "GFS2: fsid=%s: block = %llu\n" + "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", + sdp->sd_fsname, + sdp->sd_fsname, (uint64_t)bh->b_blocknr, + sdp->sd_fsname, function, file, line); + return rv; +} + +/** + * gfs2_add_bh_to_ub - copy a buffer up to user space + * @ub: the structure representing where to copy + * @bh: the buffer + * + * Returns: errno + */ + +int gfs2_add_bh_to_ub(struct gfs2_user_buffer *ub, struct buffer_head *bh) +{ + uint64_t blkno = bh->b_blocknr; + + if (ub->ub_count + sizeof(uint64_t) + bh->b_size > ub->ub_size) + return -ENOMEM; + + if (copy_to_user(ub->ub_data + ub->ub_count, + &blkno, + sizeof(uint64_t))) + return -EFAULT; + ub->ub_count += sizeof(uint64_t); + + if (copy_to_user(ub->ub_data + ub->ub_count, + bh->b_data, + bh->b_size)) + return -EFAULT; + ub->ub_count += bh->b_size; + + return 0; +} + +void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap, + unsigned int bit, int new_value) +{ + unsigned int c, o, b = bit; + int old_value; + + c = b / (8 * PAGE_SIZE); + b %= 8 * PAGE_SIZE; + o = b / 8; + b %= 8; + + old_value = (bitmap[c][o] & (1 << b)); + gfs2_assert_withdraw(sdp, !old_value != !new_value); + + if (new_value) + bitmap[c][o] |= 1 << b; + else + bitmap[c][o] &= ~(1 << b); +} + diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h new file mode 100644 index 000000000000..21466fe9bf43 --- /dev/null +++ b/fs/gfs2/util.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __UTIL_DOT_H__ +#define __UTIL_DOT_H__ + +uint32_t gfs2_disk_hash(const char *data, int len); + + +#define fs_printk(level, fs, fmt, arg...) \ + printk(level "GFS2: fsid=%s: " fmt , (fs)->sd_fsname , ## arg) + +#define fs_info(fs, fmt, arg...) \ + fs_printk(KERN_INFO , fs , fmt , ## arg) + +#define fs_warn(fs, fmt, arg...) \ + fs_printk(KERN_WARNING , fs , fmt , ## arg) + +#define fs_err(fs, fmt, arg...) \ + fs_printk(KERN_ERR, fs , fmt , ## arg) + + +void gfs2_assert_i(struct gfs2_sbd *sdp); + +#define gfs2_assert(sdp, assertion) \ +do { \ + if (unlikely(!(assertion))) { \ + gfs2_assert_i(sdp); \ + BUG(); \ + } \ +} while (0) + + +int gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion, + const char *function, char *file, unsigned int line); + +#define gfs2_assert_withdraw(sdp, assertion) \ +((likely(assertion)) ? 0 : gfs2_assert_withdraw_i((sdp), #assertion, \ + __FUNCTION__, __FILE__, __LINE__)) + + +int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, + const char *function, char *file, unsigned int line); + +#define gfs2_assert_warn(sdp, assertion) \ +((likely(assertion)) ? 0 : gfs2_assert_warn_i((sdp), #assertion, \ + __FUNCTION__, __FILE__, __LINE__)) + + +int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide, + const char *function, char *file, unsigned int line); + +#define gfs2_consist(sdp) \ +gfs2_consist_i((sdp), 0, __FUNCTION__, __FILE__, __LINE__) + + +int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide, + const char *function, char *file, unsigned int line); + +#define gfs2_consist_inode(ip) \ +gfs2_consist_inode_i((ip), 0, __FUNCTION__, __FILE__, __LINE__) + + +int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide, + const char *function, char *file, unsigned int line); + +#define gfs2_consist_rgrpd(rgd) \ +gfs2_consist_rgrpd_i((rgd), 0, __FUNCTION__, __FILE__, __LINE__) + + +int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, + const char *type, const char *function, + char *file, unsigned int line); + +static inline int gfs2_meta_check_i(struct gfs2_sbd *sdp, + struct buffer_head *bh, + const char *function, + char *file, unsigned int line) +{ + struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data; + uint32_t magic = mh->mh_magic; + magic = be32_to_cpu(magic); + if (unlikely(magic != GFS2_MAGIC)) + return gfs2_meta_check_ii(sdp, bh, "magic number", function, + file, line); + return 0; +} + +#define gfs2_meta_check(sdp, bh) \ +gfs2_meta_check_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__) + + +int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, + uint16_t type, uint16_t t, + const char *function, + char *file, unsigned int line); + +static inline int gfs2_metatype_check_i(struct gfs2_sbd *sdp, + struct buffer_head *bh, + uint16_t type, + const char *function, + char *file, unsigned int line) +{ + struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data; + uint32_t magic = mh->mh_magic; + uint16_t t = mh->mh_type; + magic = be32_to_cpu(magic); + if (unlikely(magic != GFS2_MAGIC)) + return gfs2_meta_check_ii(sdp, bh, "magic number", function, + file, line); + t = be16_to_cpu(t); + if (unlikely(t != type)) + return gfs2_metatype_check_ii(sdp, bh, type, t, function, + file, line); + return 0; +} + +#define gfs2_metatype_check(sdp, bh, type) \ +gfs2_metatype_check_i((sdp), (bh), (type), __FUNCTION__, __FILE__, __LINE__) + +static inline void gfs2_metatype_set(struct buffer_head *bh, uint16_t type, + uint16_t format) +{ + struct gfs2_meta_header *mh; + mh = (struct gfs2_meta_header *)bh->b_data; + mh->mh_type = cpu_to_be16(type); + mh->mh_format = cpu_to_be16(format); +} + + +int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function, + char *file, unsigned int line); + +#define gfs2_io_error(sdp) \ +gfs2_io_error_i((sdp), __FUNCTION__, __FILE__, __LINE__); + + +int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, + const char *function, char *file, unsigned int line); + +#define gfs2_io_error_bh(sdp, bh) \ +gfs2_io_error_bh_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__); + + +extern kmem_cache_t *gfs2_glock_cachep; +extern kmem_cache_t *gfs2_inode_cachep; +extern kmem_cache_t *gfs2_bufdata_cachep; + +struct gfs2_user_buffer { + char __user *ub_data; + unsigned int ub_size; + unsigned int ub_count; +}; + +int gfs2_add_bh_to_ub(struct gfs2_user_buffer *ub, struct buffer_head *bh); + +static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt, + unsigned int *p) +{ + unsigned int x; + spin_lock(>->gt_spin); + x = *p; + spin_unlock(>->gt_spin); + return x; +} + +#define gfs2_tune_get(sdp, field) \ +gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field) + +void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap, + unsigned int bit, int new_value); + +#endif /* __UTIL_DOT_H__ */ + diff --git a/include/linux/gfs2_ioctl.h b/include/linux/gfs2_ioctl.h new file mode 100644 index 000000000000..dde9840b1c30 --- /dev/null +++ b/include/linux/gfs2_ioctl.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __GFS2_IOCTL_DOT_H__ +#define __GFS2_IOCTL_DOT_H__ + +#define _GFS2C_(x) (('G' << 16) | ('2' << 8) | (x)) + +/* Ioctls implemented */ + +#define GFS2_IOCTL_IDENTIFY _GFS2C_(1) +#define GFS2_IOCTL_SUPER _GFS2C_(2) +#define GFS2_IOCTL_SETFLAGS _GFS2C_(3) +#define GFS2_IOCTL_GETFLAGS _GFS2C_(4) + +struct gfs2_ioctl { + unsigned int gi_argc; + const char **gi_argv; + + char __user *gi_data; + unsigned int gi_size; + uint64_t gi_offset; +}; + +#endif /* ___GFS2_IOCTL_DOT_H__ */ + diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h new file mode 100644 index 000000000000..213d664d495d --- /dev/null +++ b/include/linux/gfs2_ondisk.h @@ -0,0 +1,454 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __GFS2_ONDISK_DOT_H__ +#define __GFS2_ONDISK_DOT_H__ + +#define GFS2_MAGIC 0x01161970 +#define GFS2_BASIC_BLOCK 512 +#define GFS2_BASIC_BLOCK_SHIFT 9 + +/* Lock numbers of the LM_TYPE_NONDISK type */ + +#define GFS2_MOUNT_LOCK 0 +#define GFS2_LIVE_LOCK 1 +#define GFS2_TRANS_LOCK 2 +#define GFS2_RENAME_LOCK 3 + +/* Format numbers for various metadata types */ + +#define GFS2_FORMAT_NONE 0 +#define GFS2_FORMAT_SB 100 +#define GFS2_FORMAT_RG 200 +#define GFS2_FORMAT_RB 300 +#define GFS2_FORMAT_DI 400 +#define GFS2_FORMAT_IN 500 +#define GFS2_FORMAT_LF 600 +#define GFS2_FORMAT_JD 700 +#define GFS2_FORMAT_LH 800 +#define GFS2_FORMAT_LD 900 +#define GFS2_FORMAT_LB 1000 +#define GFS2_FORMAT_EA 1100 +#define GFS2_FORMAT_ED 1200 +#define GFS2_FORMAT_UT 1300 +#define GFS2_FORMAT_QC 1400 +/* These are format numbers for entities contained in files */ +#define GFS2_FORMAT_RI 1500 +#define GFS2_FORMAT_DE 1600 +#define GFS2_FORMAT_QU 1700 +/* These are part of the superblock */ +#define GFS2_FORMAT_FS 1801 +#define GFS2_FORMAT_MULTI 1900 + +/* + * An on-disk inode number + */ + +#define gfs2_inum_equal(ino1, ino2) \ + (((ino1)->no_formal_ino == (ino2)->no_formal_ino) && \ + ((ino1)->no_addr == (ino2)->no_addr)) + +struct gfs2_inum { + __be64 no_formal_ino; + __be64 no_addr; +}; + +/* + * Generic metadata head structure + * Every inplace buffer logged in the journal must start with this. + */ + +#define GFS2_METATYPE_NONE 0 +#define GFS2_METATYPE_SB 1 +#define GFS2_METATYPE_RG 2 +#define GFS2_METATYPE_RB 3 +#define GFS2_METATYPE_DI 4 +#define GFS2_METATYPE_IN 5 +#define GFS2_METATYPE_LF 6 +#define GFS2_METATYPE_JD 7 +#define GFS2_METATYPE_LH 8 +#define GFS2_METATYPE_LD 9 +#define GFS2_METATYPE_LB 10 +#define GFS2_METATYPE_EA 11 +#define GFS2_METATYPE_ED 12 +#define GFS2_METATYPE_UT 13 +#define GFS2_METATYPE_QC 14 + +struct gfs2_meta_header { + __be32 mh_magic; + __be32 mh_type; + __be64 __pad0; /* Was generation number in gfs1 */ + __be32 mh_format; + __be32 __pad1; /* Was incarnation number in gfs1 */ +}; + +/* + * super-block structure + * + * It's probably good if SIZEOF_SB <= GFS2_BASIC_BLOCK (512 bytes) + * + * Order is important, need to be able to read old superblocks to do on-disk + * version upgrades. + */ + +/* Address of superblock in GFS2 basic blocks */ +#define GFS2_SB_ADDR 128 + +/* The lock number for the superblock (must be zero) */ +#define GFS2_SB_LOCK 0 + +/* Requirement: GFS2_LOCKNAME_LEN % 8 == 0 + Includes: the fencing zero at the end */ +#define GFS2_LOCKNAME_LEN 64 + +struct gfs2_sb { + struct gfs2_meta_header sb_header; + + __be32 sb_fs_format; + __be32 sb_multihost_format; + __u32 __pad0; /* Was superblock flags in gfs1 */ + + __be32 sb_bsize; + __be32 sb_bsize_shift; + __u32 __pad1; /* Was journal segment size in gfs1 */ + + struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ + struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */ + struct gfs2_inum sb_root_dir; + + char sb_lockproto[GFS2_LOCKNAME_LEN]; + char sb_locktable[GFS2_LOCKNAME_LEN]; + /* In gfs1, quota and license dinodes followed */ +}; + +/* + * resource index structure + */ + +struct gfs2_rindex { + __be64 ri_addr; /* grp block disk address */ + __be32 ri_length; /* length of rgrp header in fs blocks */ + __u32 __pad; + + __be64 ri_data0; /* first data location */ + __be32 ri_data; /* num of data blocks in rgrp */ + + __be32 ri_bitbytes; /* number of bytes in data bitmaps */ + + __u8 ri_reserved[64]; +}; + +/* + * resource group header structure + */ + +/* Number of blocks per byte in rgrp */ +#define GFS2_NBBY 4 +#define GFS2_BIT_SIZE 2 +#define GFS2_BIT_MASK 0x00000003 + +#define GFS2_BLKST_FREE 0 +#define GFS2_BLKST_USED 1 +#define GFS2_BLKST_INVALID 2 +#define GFS2_BLKST_DINODE 3 + +#define GFS2_RGF_JOURNAL 0x00000001 +#define GFS2_RGF_METAONLY 0x00000002 +#define GFS2_RGF_DATAONLY 0x00000004 +#define GFS2_RGF_NOALLOC 0x00000008 + +struct gfs2_rgrp { + struct gfs2_meta_header rg_header; + + __be32 rg_flags; + __be32 rg_free; + __be32 rg_dinodes; + + __u8 rg_reserved[92]; /* Several fields from gfs1 now reserved */ +}; + +/* + * quota structure + */ + +struct gfs2_quota { + __be64 qu_limit; + __be64 qu_warn; + __be64 qu_value; +}; + +/* + * dinode structure + */ + +#define GFS2_MAX_META_HEIGHT 10 +#define GFS2_DIR_MAX_DEPTH 17 + +#define DT2IF(dt) (((dt) << 12) & S_IFMT) +#define IF2DT(sif) (((sif) & S_IFMT) >> 12) + +/* Dinode flags */ +#define GFS2_DIF_JDATA 0x00000001 +#define GFS2_DIF_EXHASH 0x00000002 +#define GFS2_DIF_UNUSED 0x00000004 /* only in gfs1 */ +#define GFS2_DIF_EA_INDIRECT 0x00000008 +#define GFS2_DIF_DIRECTIO 0x00000010 +#define GFS2_DIF_IMMUTABLE 0x00000020 +#define GFS2_DIF_APPENDONLY 0x00000040 +#define GFS2_DIF_NOATIME 0x00000080 +#define GFS2_DIF_SYNC 0x00000100 +#define GFS2_DIF_SYSTEM 0x00000200 /* New in gfs2 */ +#define GFS2_DIF_TRUNC_IN_PROG 0x20000000 /* New in gfs2 */ +#define GFS2_DIF_INHERIT_DIRECTIO 0x40000000 +#define GFS2_DIF_INHERIT_JDATA 0x80000000 + +struct gfs2_dinode { + struct gfs2_meta_header di_header; + + struct gfs2_inum di_num; + + __be32 di_mode; /* mode of file */ + __be32 di_uid; /* owner's user id */ + __be32 di_gid; /* owner's group id */ + __be32 di_nlink; /* number of links to this file */ + __be64 di_size; /* number of bytes in file */ + __be64 di_blocks; /* number of blocks in file */ + __be64 di_atime; /* time last accessed */ + __be64 di_mtime; /* time last modified */ + __be64 di_ctime; /* time last changed */ + __be32 di_major; /* device major number */ + __be32 di_minor; /* device minor number */ + + /* This section varies from gfs1. Padding added to align with + * remainder of dinode + */ + __be64 di_goal_meta; /* rgrp to alloc from next */ + __be64 di_goal_data; /* data block goal */ + __u32 __pad[2]; + + __be32 di_flags; /* GFS2_DIF_... */ + __be32 di_payload_format; /* GFS2_FORMAT_... */ + __u16 __pad1; /* Was ditype in gfs1 */ + __be16 di_height; /* height of metadata */ + __u32 __pad2; /* Unused incarnation number from gfs1 */ + + /* These only apply to directories */ + __u16 __pad3; /* Padding */ + __be16 di_depth; /* Number of bits in the table */ + __be32 di_entries; /* The number of entries in the directory */ + + struct gfs2_inum __pad4; /* Unused even in current gfs1 */ + + __be64 di_eattr; /* extended attribute block number */ + + __u8 di_reserved[56]; +}; + +/* + * directory structure - many of these per directory file + */ + +#define GFS2_FNAMESIZE 255 +#define GFS2_DIRENT_SIZE(name_len) ((sizeof(struct gfs2_dirent) + (name_len) + 7) & ~7) + +struct gfs2_dirent { + struct gfs2_inum de_inum; + __be32 de_hash; + __be32 de_rec_len; + __u8 de_name_len; + __u8 de_type; + __u16 __pad1; + __u32 __pad2; +}; + +/* + * Header of leaf directory nodes + */ + +struct gfs2_leaf { + struct gfs2_meta_header lf_header; + + __be16 lf_depth; /* Depth of leaf */ + __be16 lf_entries; /* Number of dirents in leaf */ + __be32 lf_dirent_format; /* Format of the dirents */ + __be64 lf_next; /* Next leaf, if overflow */ + + __u8 lf_reserved[32]; +}; + +/* + * Extended attribute header format + */ + +#define GFS2_EA_MAX_NAME_LEN 255 +#define GFS2_EA_MAX_DATA_LEN 65536 + +#define GFS2_EATYPE_UNUSED 0 +#define GFS2_EATYPE_USR 1 +#define GFS2_EATYPE_SYS 2 + +#define GFS2_EATYPE_LAST 2 +#define GFS2_EATYPE_VALID(x) ((x) <= GFS2_EATYPE_LAST) + +#define GFS2_EAFLAG_LAST 0x01 /* last ea in block */ + +struct gfs2_ea_header { + __be32 ea_rec_len; + __be32 ea_data_len; + __u8 ea_name_len; /* no NULL pointer after the string */ + __u8 ea_type; /* GFS2_EATYPE_... */ + __u8 ea_flags; /* GFS2_EAFLAG_... */ + __u8 ea_num_ptrs; + __u32 __pad; +}; + +/* + * Log header structure + */ + +#define GFS2_LOG_HEAD_UNMOUNT 0x00000001 /* log is clean */ + +struct gfs2_log_header { + struct gfs2_meta_header lh_header; + + __be64 lh_sequence; /* Sequence number of this transaction */ + __be32 lh_flags; /* GFS2_LOG_HEAD_... */ + __be32 lh_tail; /* Block number of log tail */ + __be32 lh_blkno; + __be32 lh_hash; +}; + +/* + * Log type descriptor + */ + +#define GFS2_LOG_DESC_METADATA 300 +/* ld_data1 is the number of metadata blocks in the descriptor. + ld_data2 is unused. */ + +#define GFS2_LOG_DESC_REVOKE 301 +/* ld_data1 is the number of revoke blocks in the descriptor. + ld_data2 is unused. */ + +struct gfs2_log_descriptor { + struct gfs2_meta_header ld_header; + + __be32 ld_type; /* GFS2_LOG_DESC_... */ + __be32 ld_length; /* Number of buffers in this chunk */ + __be32 ld_data1; /* descriptor-specific field */ + __be32 ld_data2; /* descriptor-specific field */ + + __u8 ld_reserved[32]; +}; + +/* + * Inum Range + * Describe a range of formal inode numbers allocated to + * one machine to assign to inodes. + */ + +#define GFS2_INUM_QUANTUM 1048576 + +struct gfs2_inum_range { + __be64 ir_start; + __be64 ir_length; +}; + +/* + * Statfs change + * Describes an change to the pool of free and allocated + * blocks. + */ + +struct gfs2_statfs_change { + __be64 sc_total; + __be64 sc_free; + __be64 sc_dinodes; +}; + +/* + * Unlinked Tag + * Describes an allocated inode that isn't linked into + * the directory tree and might need to be deallocated. + */ + +#define GFS2_UTF_UNINIT 0x00000001 + +struct gfs2_unlinked_tag { + struct gfs2_inum ut_inum; + __be32 ut_flags; /* GFS2_UTF_... */ + __u32 __pad; +}; + +/* + * Quota change + * Describes an allocation change for a particular + * user or group. + */ + +#define GFS2_QCF_USER 0x00000001 + +struct gfs2_quota_change { + __be64 qc_change; + __be32 qc_flags; /* GFS2_QCF_... */ + __be32 qc_id; +}; + +/* Translation functions */ + +extern void gfs2_inum_in(struct gfs2_inum *no, char *buf); +extern void gfs2_inum_out(struct gfs2_inum *no, char *buf); +extern void gfs2_meta_header_in(struct gfs2_meta_header *mh, char *buf); +extern void gfs2_meta_header_out(struct gfs2_meta_header *mh, char *buf); +extern void gfs2_sb_in(struct gfs2_sb *sb, char *buf); +extern void gfs2_sb_out(struct gfs2_sb *sb, char *buf); +extern void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf); +extern void gfs2_rindex_out(struct gfs2_rindex *ri, char *buf); +extern void gfs2_rgrp_in(struct gfs2_rgrp *rg, char *buf); +extern void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf); +extern void gfs2_quota_in(struct gfs2_quota *qu, char *buf); +extern void gfs2_quota_out(struct gfs2_quota *qu, char *buf); +extern void gfs2_dinode_in(struct gfs2_dinode *di, char *buf); +extern void gfs2_dinode_out(struct gfs2_dinode *di, char *buf); +extern void gfs2_dirent_in(struct gfs2_dirent *de, char *buf); +extern void gfs2_dirent_out(struct gfs2_dirent *de, char *buf); +extern void gfs2_leaf_in(struct gfs2_leaf *lf, char *buf); +extern void gfs2_leaf_out(struct gfs2_leaf *lf, char *buf); +extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, char *buf); +extern void gfs2_ea_header_out(struct gfs2_ea_header *ea, char *buf); +extern void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf); +extern void gfs2_inum_range_in(struct gfs2_inum_range *ir, char *buf); +extern void gfs2_inum_range_out(struct gfs2_inum_range *ir, char *buf); +extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, char *buf); +extern void gfs2_statfs_change_out(struct gfs2_statfs_change *sc, char *buf); +extern void gfs2_unlinked_tag_in(struct gfs2_unlinked_tag *ut, char *buf); +extern void gfs2_unlinked_tag_out(struct gfs2_unlinked_tag *ut, char *buf); +extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf); +extern void gfs2_quota_change_out(struct gfs2_quota_change *qc, char *buf); + +/* Printing functions */ + +extern void gfs2_inum_print(struct gfs2_inum *no); +extern void gfs2_meta_header_print(struct gfs2_meta_header *mh); +extern void gfs2_sb_print(struct gfs2_sb *sb); +extern void gfs2_rindex_print(struct gfs2_rindex *ri); +extern void gfs2_rgrp_print(struct gfs2_rgrp *rg); +extern void gfs2_quota_print(struct gfs2_quota *qu); +extern void gfs2_dinode_print(struct gfs2_dinode *di); +extern void gfs2_dirent_print(struct gfs2_dirent *de, char *name); +extern void gfs2_leaf_print(struct gfs2_leaf *lf); +extern void gfs2_ea_header_print(struct gfs2_ea_header *ea, char *name); +extern void gfs2_log_header_print(struct gfs2_log_header *lh); +extern void gfs2_log_descriptor_print(struct gfs2_log_descriptor *ld); +extern void gfs2_inum_range_print(struct gfs2_inum_range *ir); +extern void gfs2_statfs_change_print(struct gfs2_statfs_change *sc); +extern void gfs2_unlinked_tag_print(struct gfs2_unlinked_tag *ut); +extern void gfs2_quota_change_print(struct gfs2_quota_change *qc); + +#endif /* __GFS2_ONDISK_DOT_H__ */ -- cgit v1.2.3 From 869d81df53ad28ce78fc92504b3365b8196a2fa1 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 17 Jan 2006 08:47:12 +0000 Subject: [GFS2] An update of the GFS2 lock modules This brings the lock modules uptodate and removes the stray .mod.c file which accidently got included in the last check in. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/Makefile | 2 +- fs/gfs2/locking/dlm/lock.c | 104 +++++------ fs/gfs2/locking/dlm/lock_dlm.h | 191 ++++++++++++++++++++ fs/gfs2/locking/dlm/main.c | 34 ++-- fs/gfs2/locking/dlm/mount.c | 189 ++++++++++---------- fs/gfs2/locking/dlm/plock.c | 297 +++++++++++++++++++++++++++++++ fs/gfs2/locking/dlm/sysfs.c | 203 ++++++--------------- fs/gfs2/locking/dlm/thread.c | 65 +++---- fs/gfs2/locking/nolock/lock_nolock.mod.c | 44 ----- fs/gfs2/locking/nolock/main.c | 113 ++---------- include/linux/lock_dlm_plock.h | 40 +++++ 11 files changed, 792 insertions(+), 490 deletions(-) create mode 100644 fs/gfs2/locking/dlm/lock_dlm.h create mode 100644 fs/gfs2/locking/dlm/plock.c delete mode 100644 fs/gfs2/locking/nolock/lock_nolock.mod.c create mode 100644 include/linux/lock_dlm_plock.h (limited to 'include/linux') diff --git a/fs/gfs2/locking/dlm/Makefile b/fs/gfs2/locking/dlm/Makefile index d3bca02f7b3e..a9733ff80371 100644 --- a/fs/gfs2/locking/dlm/Makefile +++ b/fs/gfs2/locking/dlm/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_GFS2_FS) += lock_dlm.o -lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o +lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o plock.o diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index daf59d504e29..d799865b64a4 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -1,15 +1,11 @@ -/****************************************************************************** -******************************************************************************* -** -** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. -** -** This copyrighted material is made available to anyone wishing to use, -** modify, copy, or redistribute it subject to the terms and conditions -** of the GNU General Public License v.2. -** -******************************************************************************* -******************************************************************************/ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ #include "lock_dlm.h" @@ -38,7 +34,7 @@ static inline void gdlm_bast(void *astarg, int mode) struct gdlm_ls *ls = lp->ls; if (!mode) { - printk("lock_dlm: bast mode zero %x,%"PRIx64"\n", + printk("lock_dlm: bast mode zero %x,%llx\n", lp->lockname.ln_type, lp->lockname.ln_number); return; } @@ -75,9 +71,9 @@ static int16_t make_mode(int16_t lmstate) return DLM_LOCK_CW; case LM_ST_SHARED: return DLM_LOCK_PR; - default: - GDLM_ASSERT(0, printk("unknown LM state %d\n", lmstate);); } + gdlm_assert(0, "unknown LM state %d", lmstate); + return -1; } /* convert dlm lock-mode to gfs lock-state */ @@ -94,9 +90,9 @@ int16_t gdlm_make_lmstate(int16_t dlmmode) return LM_ST_DEFERRED; case DLM_LOCK_PR: return LM_ST_SHARED; - default: - GDLM_ASSERT(0, printk("unknown DLM mode %d\n", dlmmode);); } + gdlm_assert(0, "unknown DLM mode %d", dlmmode); + return -1; } /* verify agreement with GFS on the current lock state, NB: DLM_LOCK_NL and @@ -106,7 +102,7 @@ static void check_cur_state(struct gdlm_lock *lp, unsigned int cur_state) { int16_t cur = make_mode(cur_state); if (lp->cur != DLM_LOCK_IV) - GDLM_ASSERT(lp->cur == cur, printk("%d, %d\n", lp->cur, cur);); + gdlm_assert(lp->cur == cur, "%d, %d", lp->cur, cur); } static inline unsigned int make_flags(struct gdlm_lock *lp, @@ -157,7 +153,7 @@ static inline unsigned int make_flags(struct gdlm_lock *lp, static inline void make_strname(struct lm_lockname *lockname, struct gdlm_strname *str) { - sprintf(str->name, "%8x%16"PRIx64, lockname->ln_type, + sprintf(str->name, "%8x%16llx", lockname->ln_type, lockname->ln_number); str->namelen = GDLM_STRNAME_BYTES; } @@ -167,11 +163,10 @@ int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name, { struct gdlm_lock *lp; - lp = kmalloc(sizeof(struct gdlm_lock), GFP_KERNEL); + lp = kzalloc(sizeof(struct gdlm_lock), GFP_KERNEL); if (!lp) return -ENOMEM; - memset(lp, 0, sizeof(struct gdlm_lock)); lp->lockname = *name; lp->ls = ls; lp->cur = DLM_LOCK_IV; @@ -202,7 +197,8 @@ void gdlm_delete_lp(struct gdlm_lock *lp) list_del_init(&lp->blist); if (!list_empty(&lp->delay_list)) list_del_init(&lp->delay_list); - GDLM_ASSERT(!list_empty(&lp->all_list),); + gdlm_assert(!list_empty(&lp->all_list), + "%x,%llx", lp->lockname.ln_type, lp->lockname.ln_number); list_del_init(&lp->all_list); ls->all_locks_count--; spin_unlock(&ls->async_lock); @@ -227,7 +223,7 @@ void gdlm_put_lock(lm_lock_t *lock) gdlm_delete_lp((struct gdlm_lock *) lock); } -void gdlm_do_lock(struct gdlm_lock *lp, struct dlm_range *range) +unsigned int gdlm_do_lock(struct gdlm_lock *lp, struct dlm_range *range) { struct gdlm_ls *ls = lp->ls; struct gdlm_strname str; @@ -242,7 +238,7 @@ void gdlm_do_lock(struct gdlm_lock *lp, struct dlm_range *range) if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) && !test_bit(LFL_NOBLOCK, &lp->flags) && lp->req != DLM_LOCK_NL) { gdlm_queue_delayed(lp); - return; + return LM_OUT_ASYNC; } /* @@ -256,7 +252,7 @@ void gdlm_do_lock(struct gdlm_lock *lp, struct dlm_range *range) set_bit(LFL_ACTIVE, &lp->flags); - log_debug("lk %x,%"PRIx64" id %x %d,%d %x", lp->lockname.ln_type, + log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type, lp->lockname.ln_number, lp->lksb.sb_lkid, lp->cur, lp->req, lp->lkf); @@ -270,15 +266,19 @@ void gdlm_do_lock(struct gdlm_lock *lp, struct dlm_range *range) error = 0; } - GDLM_ASSERT(!error, - printk("%s: num=%x,%"PRIx64" err=%d cur=%d req=%d lkf=%x\n", - ls->fsname, lp->lockname.ln_type, + if (error) { + log_debug("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x " + "flags=%lx", ls->fsname, lp->lockname.ln_type, lp->lockname.ln_number, error, lp->cur, lp->req, - lp->lkf);); + lp->lkf, lp->flags); + return LM_OUT_ERROR; + } + return LM_OUT_ASYNC; } -void gdlm_do_unlock(struct gdlm_lock *lp) +unsigned int gdlm_do_unlock(struct gdlm_lock *lp) { + struct gdlm_ls *ls = lp->ls; unsigned int lkf = 0; int error; @@ -288,16 +288,19 @@ void gdlm_do_unlock(struct gdlm_lock *lp) if (lp->lvb) lkf = DLM_LKF_VALBLK; - log_debug("un %x,%"PRIx64" %x %d %x", lp->lockname.ln_type, + log_debug("un %x,%llx %x %d %x", lp->lockname.ln_type, lp->lockname.ln_number, lp->lksb.sb_lkid, lp->cur, lkf); - error = dlm_unlock(lp->ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, - NULL, lp); + error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp); - GDLM_ASSERT(!error, - printk("%s: error=%d num=%x,%"PRIx64" lkf=%x flags=%lx\n", - lp->ls->fsname, error, lp->lockname.ln_type, - lp->lockname.ln_number, lkf, lp->flags);); + if (error) { + log_debug("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x " + "flags=%lx", ls->fsname, lp->lockname.ln_type, + lp->lockname.ln_number, error, lp->cur, lp->req, + lp->lkf, lp->flags); + return LM_OUT_ERROR; + } + return LM_OUT_ASYNC; } unsigned int gdlm_lock(lm_lock_t *lock, unsigned int cur_state, @@ -313,8 +316,7 @@ unsigned int gdlm_lock(lm_lock_t *lock, unsigned int cur_state, lp->req = make_mode(req_state); lp->lkf = make_flags(lp, flags, lp->cur, lp->req); - gdlm_do_lock(lp, NULL); - return LM_OUT_ASYNC; + return gdlm_do_lock(lp, NULL); } unsigned int gdlm_unlock(lm_lock_t *lock, unsigned int cur_state) @@ -324,8 +326,7 @@ unsigned int gdlm_unlock(lm_lock_t *lock, unsigned int cur_state) clear_bit(LFL_DLM_CANCEL, &lp->flags); if (lp->cur == DLM_LOCK_IV) return 0; - gdlm_do_unlock(lp); - return LM_OUT_ASYNC; + return gdlm_do_unlock(lp); } void gdlm_cancel(lm_lock_t *lock) @@ -337,8 +338,8 @@ void gdlm_cancel(lm_lock_t *lock) if (test_bit(LFL_DLM_CANCEL, &lp->flags)) return; - log_all("gdlm_cancel %x,%"PRIx64" flags %lx", - lp->lockname.ln_type, lp->lockname.ln_number, lp->flags); + log_info("gdlm_cancel %x,%llx flags %lx", + lp->lockname.ln_type, lp->lockname.ln_number, lp->flags); spin_lock(&ls->async_lock); if (!list_empty(&lp->delay_list)) { @@ -356,9 +357,9 @@ void gdlm_cancel(lm_lock_t *lock) if (!test_bit(LFL_ACTIVE, &lp->flags) || test_bit(LFL_DLM_UNLOCK, &lp->flags)) { - log_all("gdlm_cancel skip %x,%"PRIx64" flags %lx", - lp->lockname.ln_type, lp->lockname.ln_number, - lp->flags); + log_info("gdlm_cancel skip %x,%llx flags %lx", + lp->lockname.ln_type, lp->lockname.ln_number, + lp->flags); return; } @@ -370,8 +371,8 @@ void gdlm_cancel(lm_lock_t *lock) error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, DLM_LKF_CANCEL, NULL, lp); - log_all("gdlm_cancel rv %d %x,%"PRIx64" flags %lx", error, - lp->lockname.ln_type, lp->lockname.ln_number, lp->flags); + log_info("gdlm_cancel rv %d %x,%llx flags %lx", error, + lp->lockname.ln_type, lp->lockname.ln_number, lp->flags); if (error == -EBUSY) clear_bit(LFL_DLM_CANCEL, &lp->flags); @@ -381,12 +382,10 @@ int gdlm_add_lvb(struct gdlm_lock *lp) { char *lvb; - lvb = kmalloc(GDLM_LVB_SIZE, GFP_KERNEL); + lvb = kzalloc(GDLM_LVB_SIZE, GFP_KERNEL); if (!lvb) return -ENOMEM; - memset(lvb, 0, GDLM_LVB_SIZE); - lp->lksb.sb_lvbptr = lvb; lp->lvb = lvb; return 0; @@ -448,7 +447,8 @@ static void unhold_null_lock(struct gdlm_lock *lp) { struct gdlm_lock *lpn = lp->hold_null; - GDLM_ASSERT(lpn,); + gdlm_assert(lpn, "%x,%llx", + lp->lockname.ln_type, lp->lockname.ln_number); lpn->lksb.sb_lvbptr = NULL; lpn->lvb = NULL; set_bit(LFL_UNLOCK_DELETE, &lpn->flags); diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h new file mode 100644 index 000000000000..fa545f7872e8 --- /dev/null +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef LOCK_DLM_DOT_H +#define LOCK_DLM_DOT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../../lm_interface.h" + +/* + * Internally, we prefix things with gdlm_ and GDLM_ (for gfs-dlm) since a + * prefix of lock_dlm_ gets awkward. Externally, GFS refers to this module + * as "lock_dlm". + */ + +#define GDLM_STRNAME_BYTES 24 +#define GDLM_LVB_SIZE 32 +#define GDLM_DROP_COUNT 50000 +#define GDLM_DROP_PERIOD 60 +#define GDLM_NAME_LEN 128 + +/* GFS uses 12 bytes to identify a resource (32 bit type + 64 bit number). + We sprintf these numbers into a 24 byte string of hex values to make them + human-readable (to make debugging simpler.) */ + +struct gdlm_strname { + unsigned char name[GDLM_STRNAME_BYTES]; + unsigned short namelen; +}; + +enum { + DFL_BLOCK_LOCKS = 0, + DFL_SPECTATOR = 1, + DFL_WITHDRAW = 2, +}; + +struct gdlm_ls { + uint32_t id; + int jid; + int first; + int first_done; + unsigned long flags; + struct kobject kobj; + char clustername[GDLM_NAME_LEN]; + char fsname[GDLM_NAME_LEN]; + int fsflags; + dlm_lockspace_t *dlm_lockspace; + lm_callback_t fscb; + lm_fsdata_t *fsdata; + int recover_jid; + int recover_jid_done; + spinlock_t async_lock; + struct list_head complete; + struct list_head blocking; + struct list_head delayed; + struct list_head submit; + struct list_head all_locks; + uint32_t all_locks_count; + wait_queue_head_t wait_control; + struct task_struct *thread1; + struct task_struct *thread2; + wait_queue_head_t thread_wait; + unsigned long drop_time; + int drop_locks_count; + int drop_locks_period; +}; + +enum { + LFL_NOBLOCK = 0, + LFL_NOCACHE = 1, + LFL_DLM_UNLOCK = 2, + LFL_DLM_CANCEL = 3, + LFL_SYNC_LVB = 4, + LFL_FORCE_PROMOTE = 5, + LFL_REREQUEST = 6, + LFL_ACTIVE = 7, + LFL_INLOCK = 8, + LFL_CANCEL = 9, + LFL_NOBAST = 10, + LFL_HEADQUE = 11, + LFL_UNLOCK_DELETE = 12, +}; + +struct gdlm_lock { + struct gdlm_ls *ls; + struct lm_lockname lockname; + char *lvb; + struct dlm_lksb lksb; + + int16_t cur; + int16_t req; + int16_t prev_req; + uint32_t lkf; /* dlm flags DLM_LKF_ */ + unsigned long flags; /* lock_dlm flags LFL_ */ + + int bast_mode; /* protected by async_lock */ + struct completion ast_wait; + + struct list_head clist; /* complete */ + struct list_head blist; /* blocking */ + struct list_head delay_list; /* delayed */ + struct list_head all_list; /* all locks for the fs */ + struct gdlm_lock *hold_null; /* NL lock for hold_lvb */ +}; + +#define gdlm_assert(assertion, fmt, args...) \ +do { \ + if (unlikely(!(assertion))) { \ + printk(KERN_EMERG "lock_dlm: fatal assertion failed \"%s\"\n" \ + "lock_dlm: " fmt "\n", \ + #assertion, ##args); \ + BUG(); \ + } \ +} while (0) + +#define log_print(lev, fmt, arg...) printk(lev "lock_dlm: " fmt "\n" , ## arg) +#define log_info(fmt, arg...) log_print(KERN_INFO , fmt , ## arg) +#define log_error(fmt, arg...) log_print(KERN_ERR , fmt , ## arg) +#ifdef LOCK_DLM_LOG_DEBUG +#define log_debug(fmt, arg...) log_print(KERN_DEBUG , fmt , ## arg) +#else +#define log_debug(fmt, arg...) +#endif + +/* sysfs.c */ + +int gdlm_sysfs_init(void); +void gdlm_sysfs_exit(void); +int gdlm_kobject_setup(struct gdlm_ls *, struct kobject *); +void gdlm_kobject_release(struct gdlm_ls *); + +/* thread.c */ + +int gdlm_init_threads(struct gdlm_ls *); +void gdlm_release_threads(struct gdlm_ls *); + +/* lock.c */ + +int16_t gdlm_make_lmstate(int16_t); +void gdlm_queue_delayed(struct gdlm_lock *); +void gdlm_submit_delayed(struct gdlm_ls *); +int gdlm_release_all_locks(struct gdlm_ls *); +int gdlm_create_lp(struct gdlm_ls *, struct lm_lockname *, struct gdlm_lock **); +void gdlm_delete_lp(struct gdlm_lock *); +int gdlm_add_lvb(struct gdlm_lock *); +void gdlm_del_lvb(struct gdlm_lock *); +unsigned int gdlm_do_lock(struct gdlm_lock *, struct dlm_range *); +unsigned int gdlm_do_unlock(struct gdlm_lock *); + +int gdlm_get_lock(lm_lockspace_t *, struct lm_lockname *, lm_lock_t **); +void gdlm_put_lock(lm_lock_t *); +unsigned int gdlm_lock(lm_lock_t *, unsigned int, unsigned int, unsigned int); +unsigned int gdlm_unlock(lm_lock_t *, unsigned int); +void gdlm_cancel(lm_lock_t *); +int gdlm_hold_lvb(lm_lock_t *, char **); +void gdlm_unhold_lvb(lm_lock_t *, char *); +void gdlm_sync_lvb(lm_lock_t *, char *); + +/* plock.c */ + +int gdlm_plock_init(void); +void gdlm_plock_exit(void); +int gdlm_plock(lm_lockspace_t *, struct lm_lockname *, struct file *, int, + struct file_lock *); +int gdlm_plock_get(lm_lockspace_t *, struct lm_lockname *, struct file *, + struct file_lock *); +int gdlm_punlock(lm_lockspace_t *, struct lm_lockname *, struct file *, + struct file_lock *); +#endif + diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c index 3ced92ef1b19..2c13c916a352 100644 --- a/fs/gfs2/locking/dlm/main.c +++ b/fs/gfs2/locking/dlm/main.c @@ -1,15 +1,11 @@ -/****************************************************************************** -******************************************************************************* -** -** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. -** -** This copyrighted material is made available to anyone wishing to use, -** modify, copy, or redistribute it subject to the terms and conditions -** of the GNU General Public License v.2. -** -******************************************************************************* -******************************************************************************/ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ #include @@ -24,7 +20,7 @@ int __init init_lock_dlm(void) { int error; - error = lm_register_proto(&gdlm_ops); + error = gfs_register_lockproto(&gdlm_ops); if (error) { printk("lock_dlm: can't register protocol: %d\n", error); return error; @@ -32,7 +28,14 @@ int __init init_lock_dlm(void) error = gdlm_sysfs_init(); if (error) { - lm_unregister_proto(&gdlm_ops); + gfs_unregister_lockproto(&gdlm_ops); + return error; + } + + error = gdlm_plock_init(); + if (error) { + gdlm_sysfs_exit(); + gfs_unregister_lockproto(&gdlm_ops); return error; } @@ -45,8 +48,9 @@ int __init init_lock_dlm(void) void __exit exit_lock_dlm(void) { - lm_unregister_proto(&gdlm_ops); + gdlm_plock_exit(); gdlm_sysfs_exit(); + gfs_unregister_lockproto(&gdlm_ops); } module_init(init_lock_dlm); diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index 92b1789deb89..bfb224638f2d 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -1,15 +1,11 @@ -/****************************************************************************** -******************************************************************************* -** -** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. -** -** This copyrighted material is made available to anyone wishing to use, -** modify, copy, or redistribute it subject to the terms and conditions -** of the GNU General Public License v.2. -** -******************************************************************************* -******************************************************************************/ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ #include "lock_dlm.h" @@ -24,27 +20,21 @@ static struct gdlm_ls *init_gdlm(lm_callback_t cb, lm_fsdata_t *fsdata, struct gdlm_ls *ls; char buf[256], *p; - ls = kmalloc(sizeof(struct gdlm_ls), GFP_KERNEL); + ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL); if (!ls) return NULL; - memset(ls, 0, sizeof(struct gdlm_ls)); - ls->drop_locks_count = gdlm_drop_count; ls->drop_locks_period = gdlm_drop_period; - ls->fscb = cb; ls->fsdata = fsdata; ls->fsflags = flags; - spin_lock_init(&ls->async_lock); - INIT_LIST_HEAD(&ls->complete); INIT_LIST_HEAD(&ls->blocking); INIT_LIST_HEAD(&ls->delayed); INIT_LIST_HEAD(&ls->submit); INIT_LIST_HEAD(&ls->all_locks); - init_waitqueue_head(&ls->thread_wait); init_waitqueue_head(&ls->wait_control); ls->thread1 = NULL; @@ -57,23 +47,75 @@ static struct gdlm_ls *init_gdlm(lm_callback_t cb, lm_fsdata_t *fsdata, p = strstr(buf, ":"); if (!p) { - printk("lock_dlm: invalid table_name \"%s\"\n", table_name); + log_info("invalid table_name \"%s\"", table_name); kfree(ls); return NULL; } *p = '\0'; p++; - strncpy(ls->clustername, buf, 128); - strncpy(ls->fsname, p, 128); + strncpy(ls->clustername, buf, GDLM_NAME_LEN); + strncpy(ls->fsname, p, GDLM_NAME_LEN); return ls; } +static int make_args(struct gdlm_ls *ls, char *data_arg) +{ + char data[256]; + char *options, *x, *y; + int error = 0; + + memset(data, 0, 256); + strncpy(data, data_arg, 255); + + for (options = data; (x = strsep(&options, ":")); ) { + if (!*x) + continue; + + y = strchr(x, '='); + if (y) + *y++ = 0; + + if (!strcmp(x, "jid")) { + if (!y) { + log_error("need argument to jid"); + error = -EINVAL; + break; + } + sscanf(y, "%u", &ls->jid); + + } else if (!strcmp(x, "first")) { + if (!y) { + log_error("need argument to first"); + error = -EINVAL; + break; + } + sscanf(y, "%u", &ls->first); + + } else if (!strcmp(x, "id")) { + if (!y) { + log_error("need argument to id"); + error = -EINVAL; + break; + } + sscanf(y, "%u", &ls->id); + + } else { + log_error("unkonwn option: %s", x); + error = -EINVAL; + break; + } + } + + return error; +} + static int gdlm_mount(char *table_name, char *host_data, lm_callback_t cb, lm_fsdata_t *fsdata, unsigned int min_lvb_size, int flags, - struct lm_lockstruct *lockstruct) + struct lm_lockstruct *lockstruct, + struct kobject *fskobj) { struct gdlm_ls *ls; int error = -ENOMEM; @@ -92,30 +134,18 @@ static int gdlm_mount(char *table_name, char *host_data, error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname), &ls->dlm_lockspace, 0, GDLM_LVB_SIZE); if (error) { - printk("lock_dlm: dlm_new_lockspace error %d\n", error); + log_error("dlm_new_lockspace error %d", error); goto out_thread; } - error = gdlm_kobject_setup(ls); + error = gdlm_kobject_setup(ls, fskobj); if (error) goto out_dlm; - kobject_uevent(&ls->kobj, KOBJ_MOUNT, NULL); - /* Now we depend on userspace to notice the new mount, - join the appropriate group, and do a write to our sysfs - "mounted" or "terminate" file. Before the start, userspace - must set "jid" and "first". */ - - error = wait_event_interruptible(ls->wait_control, - test_bit(DFL_JOIN_DONE, &ls->flags)); + error = make_args(ls, host_data); if (error) goto out_sysfs; - if (test_bit(DFL_TERMINATE, &ls->flags)) { - error = -ERESTARTSYS; - goto out_sysfs; - } - lockstruct->ls_jid = ls->jid; lockstruct->ls_first = ls->first; lockstruct->ls_lockspace = ls; @@ -143,22 +173,19 @@ static void gdlm_unmount(lm_lockspace_t *lockspace) log_debug("unmount flags %lx", ls->flags); - if (test_bit(DFL_WITHDRAW, &ls->flags)) { - gdlm_kobject_release(ls); - goto out; - } - - kobject_uevent(&ls->kobj, KOBJ_UMOUNT, NULL); + /* FIXME: serialize unmount and withdraw in case they + happen at once. Also, if unmount follows withdraw, + wait for withdraw to finish. */ - wait_event_interruptible(ls->wait_control, - test_bit(DFL_LEAVE_DONE, &ls->flags)); + if (test_bit(DFL_WITHDRAW, &ls->flags)) + goto out; gdlm_kobject_release(ls); dlm_release_lockspace(ls->dlm_lockspace, 2); gdlm_release_threads(ls); rv = gdlm_release_all_locks(ls); if (rv) - log_all("lm_dlm_unmount: %d stray locks freed", rv); + log_info("gdlm_unmount: %d stray locks freed", rv); out: kfree(ls); } @@ -167,7 +194,7 @@ static void gdlm_recovery_done(lm_lockspace_t *lockspace, unsigned int jid, unsigned int message) { struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; - ls->recover_done = jid; + ls->recover_jid_done = jid; kobject_uevent(&ls->kobj, KOBJ_CHANGE, NULL); } @@ -178,12 +205,14 @@ static void gdlm_others_may_mount(lm_lockspace_t *lockspace) kobject_uevent(&ls->kobj, KOBJ_CHANGE, NULL); } +/* Userspace gets the offline uevent, blocks new gfs locks on + other mounters, and lets us know (sets WITHDRAW flag). Then, + userspace leaves the mount group while we leave the lockspace. */ + static void gdlm_withdraw(lm_lockspace_t *lockspace) { struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; - /* userspace suspends locking on all other members */ - kobject_uevent(&ls->kobj, KOBJ_OFFLINE, NULL); wait_event_interruptible(ls->wait_control, @@ -192,49 +221,27 @@ static void gdlm_withdraw(lm_lockspace_t *lockspace) dlm_release_lockspace(ls->dlm_lockspace, 2); gdlm_release_threads(ls); gdlm_release_all_locks(ls); - - kobject_uevent(&ls->kobj, KOBJ_UMOUNT, NULL); - - /* userspace leaves the mount group, we don't need to wait for - that to complete */ -} - -int gdlm_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, - struct file *file, struct file_lock *fl) -{ - return -ENOSYS; -} - -int gdlm_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, - struct file *file, struct file_lock *fl) -{ - return -ENOSYS; -} - -int gdlm_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, - struct file *file, int cmd, struct file_lock *fl) -{ - return -ENOSYS; + gdlm_kobject_release(ls); } struct lm_lockops gdlm_ops = { - lm_proto_name:"lock_dlm", - lm_mount:gdlm_mount, - lm_others_may_mount:gdlm_others_may_mount, - lm_unmount:gdlm_unmount, - lm_withdraw:gdlm_withdraw, - lm_get_lock:gdlm_get_lock, - lm_put_lock:gdlm_put_lock, - lm_lock:gdlm_lock, - lm_unlock:gdlm_unlock, - lm_plock:gdlm_plock, - lm_punlock:gdlm_punlock, - lm_plock_get:gdlm_plock_get, - lm_cancel:gdlm_cancel, - lm_hold_lvb:gdlm_hold_lvb, - lm_unhold_lvb:gdlm_unhold_lvb, - lm_sync_lvb:gdlm_sync_lvb, - lm_recovery_done:gdlm_recovery_done, - lm_owner:THIS_MODULE, + .lm_proto_name = "lock_dlm", + .lm_mount = gdlm_mount, + .lm_others_may_mount = gdlm_others_may_mount, + .lm_unmount = gdlm_unmount, + .lm_withdraw = gdlm_withdraw, + .lm_get_lock = gdlm_get_lock, + .lm_put_lock = gdlm_put_lock, + .lm_lock = gdlm_lock, + .lm_unlock = gdlm_unlock, + .lm_plock = gdlm_plock, + .lm_punlock = gdlm_punlock, + .lm_plock_get = gdlm_plock_get, + .lm_cancel = gdlm_cancel, + .lm_hold_lvb = gdlm_hold_lvb, + .lm_unhold_lvb = gdlm_unhold_lvb, + .lm_sync_lvb = gdlm_sync_lvb, + .lm_recovery_done = gdlm_recovery_done, + .lm_owner = THIS_MODULE, }; diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c new file mode 100644 index 000000000000..382847205bc1 --- /dev/null +++ b/fs/gfs2/locking/dlm/plock.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#include +#include + +#include "lock_dlm.h" + + +static spinlock_t ops_lock; +static struct list_head send_list; +static struct list_head recv_list; +static wait_queue_head_t send_wq; +static wait_queue_head_t recv_wq; + +struct plock_op { + struct list_head list; + int done; + struct gdlm_plock_info info; +}; + +static inline void set_version(struct gdlm_plock_info *info) +{ + info->version[0] = GDLM_PLOCK_VERSION_MAJOR; + info->version[1] = GDLM_PLOCK_VERSION_MINOR; + info->version[2] = GDLM_PLOCK_VERSION_PATCH; +} + +static int check_version(struct gdlm_plock_info *info) +{ + if ((GDLM_PLOCK_VERSION_MAJOR != info->version[0]) || + (GDLM_PLOCK_VERSION_MINOR < info->version[1])) { + log_error("plock device version mismatch: " + "kernel (%u.%u.%u), user (%u.%u.%u)", + GDLM_PLOCK_VERSION_MAJOR, + GDLM_PLOCK_VERSION_MINOR, + GDLM_PLOCK_VERSION_PATCH, + info->version[0], + info->version[1], + info->version[2]); + return -EINVAL; + } + return 0; +} + +static void send_op(struct plock_op *op) +{ + set_version(&op->info); + INIT_LIST_HEAD(&op->list); + spin_lock(&ops_lock); + list_add_tail(&op->list, &send_list); + spin_unlock(&ops_lock); + wake_up(&send_wq); +} + +int gdlm_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl) +{ + struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + struct plock_op *op; + int rv; + + op = kzalloc(sizeof(*op), GFP_KERNEL); + if (!op) + return -ENOMEM; + + op->info.optype = GDLM_PLOCK_OP_LOCK; + op->info.pid = (uint32_t) fl->fl_owner; + op->info.ex = (fl->fl_type == F_WRLCK); + op->info.wait = IS_SETLKW(cmd); + op->info.fsid = ls->id; + op->info.number = name->ln_number; + op->info.start = fl->fl_start; + op->info.end = fl->fl_end; + + send_op(op); + wait_event(recv_wq, (op->done != 0)); + + spin_lock(&ops_lock); + if (!list_empty(&op->list)) { + printk("plock op on list\n"); + list_del(&op->list); + } + spin_unlock(&ops_lock); + + rv = op->info.rv; + + if (!rv) { + if (posix_lock_file_wait(file, fl) < 0) + log_error("gdlm_plock: vfs lock error %x,%llx", + name->ln_type, name->ln_number); + } + + kfree(op); + return rv; +} + +int gdlm_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + struct plock_op *op; + int rv; + + op = kzalloc(sizeof(*op), GFP_KERNEL); + if (!op) + return -ENOMEM; + + if (posix_lock_file_wait(file, fl) < 0) + log_error("gdlm_punlock: vfs unlock error %x,%llx", + name->ln_type, name->ln_number); + + op->info.optype = GDLM_PLOCK_OP_UNLOCK; + op->info.pid = (uint32_t) fl->fl_owner; + op->info.fsid = ls->id; + op->info.number = name->ln_number; + op->info.start = fl->fl_start; + op->info.end = fl->fl_end; + + send_op(op); + wait_event(recv_wq, (op->done != 0)); + + spin_lock(&ops_lock); + if (!list_empty(&op->list)) { + printk("punlock op on list\n"); + list_del(&op->list); + } + spin_unlock(&ops_lock); + + rv = op->info.rv; + + kfree(op); + return rv; +} + +int gdlm_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + struct gdlm_ls *ls = (struct gdlm_ls *) lockspace; + struct plock_op *op; + int rv; + + op = kzalloc(sizeof(*op), GFP_KERNEL); + if (!op) + return -ENOMEM; + + op->info.optype = GDLM_PLOCK_OP_GET; + op->info.pid = (uint32_t) fl->fl_owner; + op->info.ex = (fl->fl_type == F_WRLCK); + op->info.fsid = ls->id; + op->info.number = name->ln_number; + op->info.start = fl->fl_start; + op->info.end = fl->fl_end; + + send_op(op); + wait_event(recv_wq, (op->done != 0)); + + spin_lock(&ops_lock); + if (!list_empty(&op->list)) { + printk("plock_get op on list\n"); + list_del(&op->list); + } + spin_unlock(&ops_lock); + + rv = op->info.rv; + + if (rv == 0) + fl->fl_type = F_UNLCK; + else if (rv > 0) { + fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK; + fl->fl_pid = op->info.pid; + fl->fl_start = op->info.start; + fl->fl_end = op->info.end; + } + + kfree(op); + return rv; +} + +/* a read copies out one plock request from the send list */ +static ssize_t dev_read(struct file *file, char __user *u, size_t count, + loff_t *ppos) +{ + struct gdlm_plock_info info; + struct plock_op *op = NULL; + + if (count < sizeof(info)) + return -EINVAL; + + spin_lock(&ops_lock); + if (!list_empty(&send_list)) { + op = list_entry(send_list.next, struct plock_op, list); + list_move(&op->list, &recv_list); + memcpy(&info, &op->info, sizeof(info)); + } + spin_unlock(&ops_lock); + + if (!op) + return -EAGAIN; + + if (copy_to_user(u, &info, sizeof(info))) + return -EFAULT; + return sizeof(info); +} + +/* a write copies in one plock result that should match a plock_op + on the recv list */ +static ssize_t dev_write(struct file *file, const char __user *u, size_t count, + loff_t *ppos) +{ + struct gdlm_plock_info info; + struct plock_op *op; + int found = 0; + + if (count != sizeof(info)) + return -EINVAL; + + if (copy_from_user(&info, u, sizeof(info))) + return -EFAULT; + + if (check_version(&info)) + return -EINVAL; + + spin_lock(&ops_lock); + list_for_each_entry(op, &recv_list, list) { + if (op->info.fsid == info.fsid && + op->info.number == info.number) { + list_del_init(&op->list); + found = 1; + op->done = 1; + memcpy(&op->info, &info, sizeof(info)); + break; + } + } + spin_unlock(&ops_lock); + + if (found) + wake_up(&recv_wq); + else + printk("gdlm dev_write no op %x %llx\n", info.fsid, + info.number); + return count; +} + +static unsigned int dev_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &send_wq, wait); + + spin_lock(&ops_lock); + if (!list_empty(&send_list)) { + spin_unlock(&ops_lock); + return POLLIN | POLLRDNORM; + } + spin_unlock(&ops_lock); + return 0; +} + +static struct file_operations dev_fops = { + .read = dev_read, + .write = dev_write, + .poll = dev_poll, + .owner = THIS_MODULE +}; + +static struct miscdevice plock_dev_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = GDLM_PLOCK_MISC_NAME, + .fops = &dev_fops +}; + +int gdlm_plock_init(void) +{ + int rv; + + spin_lock_init(&ops_lock); + INIT_LIST_HEAD(&send_list); + INIT_LIST_HEAD(&recv_list); + init_waitqueue_head(&send_wq); + init_waitqueue_head(&recv_wq); + + rv = misc_register(&plock_dev_misc); + if (rv) + printk("gdlm_plock_init: misc_register failed %d", rv); + return rv; +} + +void gdlm_plock_exit(void) +{ + if (misc_deregister(&plock_dev_misc) < 0) + printk("gdlm_plock_exit: misc_deregister failed"); +} + diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index 8964733f55e4..e1e5186c97c9 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -1,21 +1,25 @@ -/****************************************************************************** -******************************************************************************* -** -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. -** -** This copyrighted material is made available to anyone wishing to use, -** modify, copy, or redistribute it subject to the terms and conditions -** of the GNU General Public License v.2. -** -******************************************************************************* -******************************************************************************/ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ #include #include #include "lock_dlm.h" -static ssize_t gdlm_block_show(struct gdlm_ls *ls, char *buf) +extern struct lm_lockops gdlm_ops; + +static ssize_t proto_name_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%s\n", gdlm_ops.lm_proto_name); +} + +static ssize_t block_show(struct gdlm_ls *ls, char *buf) { ssize_t ret; int val = 0; @@ -26,7 +30,7 @@ static ssize_t gdlm_block_show(struct gdlm_ls *ls, char *buf) return ret; } -static ssize_t gdlm_block_store(struct gdlm_ls *ls, const char *buf, size_t len) +static ssize_t block_store(struct gdlm_ls *ls, const char *buf, size_t len) { ssize_t ret = len; int val; @@ -43,43 +47,7 @@ static ssize_t gdlm_block_store(struct gdlm_ls *ls, const char *buf, size_t len) return ret; } -static ssize_t gdlm_mounted_show(struct gdlm_ls *ls, char *buf) -{ - ssize_t ret; - int val = -2; - - if (test_bit(DFL_TERMINATE, &ls->flags)) - val = -1; - else if (test_bit(DFL_LEAVE_DONE, &ls->flags)) - val = 0; - else if (test_bit(DFL_JOIN_DONE, &ls->flags)) - val = 1; - ret = sprintf(buf, "%d\n", val); - return ret; -} - -static ssize_t gdlm_mounted_store(struct gdlm_ls *ls, const char *buf, size_t len) -{ - ssize_t ret = len; - int val; - - val = simple_strtol(buf, NULL, 0); - - if (val == 1) - set_bit(DFL_JOIN_DONE, &ls->flags); - else if (val == 0) - set_bit(DFL_LEAVE_DONE, &ls->flags); - else if (val == -1) { - set_bit(DFL_TERMINATE, &ls->flags); - set_bit(DFL_JOIN_DONE, &ls->flags); - set_bit(DFL_LEAVE_DONE, &ls->flags); - } else - ret = -EINVAL; - wake_up(&ls->wait_control); - return ret; -} - -static ssize_t gdlm_withdraw_show(struct gdlm_ls *ls, char *buf) +static ssize_t withdraw_show(struct gdlm_ls *ls, char *buf) { ssize_t ret; int val = 0; @@ -90,7 +58,7 @@ static ssize_t gdlm_withdraw_show(struct gdlm_ls *ls, char *buf) return ret; } -static ssize_t gdlm_withdraw_store(struct gdlm_ls *ls, const char *buf, size_t len) +static ssize_t withdraw_store(struct gdlm_ls *ls, const char *buf, size_t len) { ssize_t ret = len; int val; @@ -105,67 +73,41 @@ static ssize_t gdlm_withdraw_store(struct gdlm_ls *ls, const char *buf, size_t l return ret; } -static ssize_t gdlm_jid_show(struct gdlm_ls *ls, char *buf) -{ - return sprintf(buf, "%u\n", ls->jid); -} - -static ssize_t gdlm_jid_store(struct gdlm_ls *ls, const char *buf, size_t len) +static ssize_t id_show(struct gdlm_ls *ls, char *buf) { - ls->jid = simple_strtol(buf, NULL, 0); - return len; + return sprintf(buf, "%u\n", ls->id); } -static ssize_t gdlm_first_show(struct gdlm_ls *ls, char *buf) +static ssize_t jid_show(struct gdlm_ls *ls, char *buf) { - return sprintf(buf, "%u\n", ls->first); + return sprintf(buf, "%d\n", ls->jid); } -static ssize_t gdlm_first_store(struct gdlm_ls *ls, const char *buf, size_t len) +static ssize_t first_show(struct gdlm_ls *ls, char *buf) { - ls->first = simple_strtol(buf, NULL, 0); - return len; + return sprintf(buf, "%d\n", ls->first); } -static ssize_t gdlm_first_done_show(struct gdlm_ls *ls, char *buf) +static ssize_t first_done_show(struct gdlm_ls *ls, char *buf) { return sprintf(buf, "%d\n", ls->first_done); } -static ssize_t gdlm_recover_show(struct gdlm_ls *ls, char *buf) +static ssize_t recover_show(struct gdlm_ls *ls, char *buf) { - return sprintf(buf, "%u\n", ls->recover_jid); + return sprintf(buf, "%d\n", ls->recover_jid); } -static ssize_t gdlm_recover_store(struct gdlm_ls *ls, const char *buf, size_t len) +static ssize_t recover_store(struct gdlm_ls *ls, const char *buf, size_t len) { ls->recover_jid = simple_strtol(buf, NULL, 0); ls->fscb(ls->fsdata, LM_CB_NEED_RECOVERY, &ls->recover_jid); return len; } -static ssize_t gdlm_recover_done_show(struct gdlm_ls *ls, char *buf) -{ - ssize_t ret; - ret = sprintf(buf, "%d\n", ls->recover_done); - return ret; -} - -static ssize_t gdlm_cluster_show(struct gdlm_ls *ls, char *buf) -{ - ssize_t ret; - ret = sprintf(buf, "%s\n", ls->clustername); - return ret; -} - -static ssize_t gdlm_options_show(struct gdlm_ls *ls, char *buf) +static ssize_t recover_done_show(struct gdlm_ls *ls, char *buf) { - ssize_t ret = 0; - - if (ls->fsflags & LM_MFLAG_SPECTATOR) - ret += sprintf(buf, "spectator "); - - return ret; + return sprintf(buf, "%d\n", ls->recover_jid_done); } struct gdlm_attr { @@ -174,73 +116,29 @@ struct gdlm_attr { ssize_t (*store)(struct gdlm_ls *, const char *, size_t); }; -static struct gdlm_attr gdlm_attr_block = { - .attr = {.name = "block", .mode = S_IRUGO | S_IWUSR}, - .show = gdlm_block_show, - .store = gdlm_block_store -}; - -static struct gdlm_attr gdlm_attr_mounted = { - .attr = {.name = "mounted", .mode = S_IRUGO | S_IWUSR}, - .show = gdlm_mounted_show, - .store = gdlm_mounted_store -}; - -static struct gdlm_attr gdlm_attr_withdraw = { - .attr = {.name = "withdraw", .mode = S_IRUGO | S_IWUSR}, - .show = gdlm_withdraw_show, - .store = gdlm_withdraw_store -}; - -static struct gdlm_attr gdlm_attr_jid = { - .attr = {.name = "jid", .mode = S_IRUGO | S_IWUSR}, - .show = gdlm_jid_show, - .store = gdlm_jid_store -}; - -static struct gdlm_attr gdlm_attr_first = { - .attr = {.name = "first", .mode = S_IRUGO | S_IWUSR}, - .show = gdlm_first_show, - .store = gdlm_first_store -}; - -static struct gdlm_attr gdlm_attr_first_done = { - .attr = {.name = "first_done", .mode = S_IRUGO}, - .show = gdlm_first_done_show, -}; - -static struct gdlm_attr gdlm_attr_recover = { - .attr = {.name = "recover", .mode = S_IRUGO | S_IWUSR}, - .show = gdlm_recover_show, - .store = gdlm_recover_store -}; - -static struct gdlm_attr gdlm_attr_recover_done = { - .attr = {.name = "recover_done", .mode = S_IRUGO | S_IWUSR}, - .show = gdlm_recover_done_show, -}; - -static struct gdlm_attr gdlm_attr_cluster = { - .attr = {.name = "cluster", .mode = S_IRUGO | S_IWUSR}, - .show = gdlm_cluster_show, -}; +#define GDLM_ATTR(_name,_mode,_show,_store) \ +static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) -static struct gdlm_attr gdlm_attr_options = { - .attr = {.name = "options", .mode = S_IRUGO | S_IWUSR}, - .show = gdlm_options_show, -}; +GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); +GDLM_ATTR(block, 0644, block_show, block_store); +GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); +GDLM_ATTR(id, 0444, id_show, NULL); +GDLM_ATTR(jid, 0444, jid_show, NULL); +GDLM_ATTR(first, 0444, first_show, NULL); +GDLM_ATTR(first_done, 0444, first_done_show, NULL); +GDLM_ATTR(recover, 0644, recover_show, recover_store); +GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); static struct attribute *gdlm_attrs[] = { + &gdlm_attr_proto_name.attr, &gdlm_attr_block.attr, - &gdlm_attr_mounted.attr, &gdlm_attr_withdraw.attr, + &gdlm_attr_id.attr, &gdlm_attr_jid.attr, &gdlm_attr_first.attr, &gdlm_attr_first_done.attr, &gdlm_attr_recover.attr, &gdlm_attr_recover_done.attr, - &gdlm_attr_cluster.attr, - &gdlm_attr_options.attr, NULL, }; @@ -276,20 +174,25 @@ static struct kset gdlm_kset = { .ktype = &gdlm_ktype, }; -int gdlm_kobject_setup(struct gdlm_ls *ls) +int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj) { int error; - error = kobject_set_name(&ls->kobj, "%s", ls->fsname); - if (error) + error = kobject_set_name(&ls->kobj, "%s", "lock_module"); + if (error) { + log_error("can't set kobj name %d", error); return error; + } ls->kobj.kset = &gdlm_kset; ls->kobj.ktype = &gdlm_ktype; + ls->kobj.parent = fskobj; error = kobject_register(&ls->kobj); + if (error) + log_error("can't register kobj %d", error); - return 0; + return error; } void gdlm_kobject_release(struct gdlm_ls *ls) diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index 22bbe6d3a5ae..6fe669cd334b 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -1,15 +1,11 @@ -/****************************************************************************** -******************************************************************************* -** -** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. -** -** This copyrighted material is made available to anyone wishing to use, -** modify, copy, or redistribute it subject to the terms and conditions -** of the GNU General Public License v.2. -** -******************************************************************************* -******************************************************************************/ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ #include "lock_dlm.h" @@ -26,15 +22,10 @@ static void queue_submit(struct gdlm_lock *lp) wake_up(&ls->thread_wait); } -static void process_submit(struct gdlm_lock *lp) -{ - gdlm_do_lock(lp, NULL); -} - static void process_blocking(struct gdlm_lock *lp, int bast_mode) { struct gdlm_ls *ls = lp->ls; - unsigned int cb; + unsigned int cb = 0; switch (gdlm_make_lmstate(bast_mode)) { case LM_ST_EXCLUSIVE: @@ -47,7 +38,7 @@ static void process_blocking(struct gdlm_lock *lp, int bast_mode) cb = LM_CB_NEED_S; break; default: - GDLM_ASSERT(0, printk("unknown bast mode %u\n",lp->bast_mode);); + gdlm_assert(0, "unknown bast mode %u", lp->bast_mode); } ls->fscb(ls->fsdata, cb, &lp->lockname); @@ -62,9 +53,9 @@ static void process_complete(struct gdlm_lock *lp) memset(&acb, 0, sizeof(acb)); if (lp->lksb.sb_status == -DLM_ECANCEL) { - log_all("complete dlm cancel %x,%"PRIx64" flags %lx", - lp->lockname.ln_type, lp->lockname.ln_number, - lp->flags); + log_info("complete dlm cancel %x,%llx flags %lx", + lp->lockname.ln_type, lp->lockname.ln_number, + lp->flags); lp->req = lp->cur; acb.lc_ret |= LM_OUT_CANCELED; @@ -75,9 +66,9 @@ static void process_complete(struct gdlm_lock *lp) if (test_and_clear_bit(LFL_DLM_UNLOCK, &lp->flags)) { if (lp->lksb.sb_status != -DLM_EUNLOCK) { - log_all("unlock sb_status %d %x,%"PRIx64" flags %lx", - lp->lksb.sb_status, lp->lockname.ln_type, - lp->lockname.ln_number, lp->flags); + log_info("unlock sb_status %d %x,%llx flags %lx", + lp->lksb.sb_status, lp->lockname.ln_type, + lp->lockname.ln_number, lp->flags); return; } @@ -108,8 +99,8 @@ static void process_complete(struct gdlm_lock *lp) */ if (test_and_clear_bit(LFL_CANCEL, &lp->flags)) { - log_all("complete internal cancel %x,%"PRIx64"", - lp->lockname.ln_type, lp->lockname.ln_number); + log_info("complete internal cancel %x,%llx", + lp->lockname.ln_type, lp->lockname.ln_number); lp->req = lp->cur; acb.lc_ret |= LM_OUT_CANCELED; goto out; @@ -130,9 +121,9 @@ static void process_complete(struct gdlm_lock *lp) } /* this could only happen with cancels I think */ - log_all("ast sb_status %d %x,%"PRIx64" flags %lx", - lp->lksb.sb_status, lp->lockname.ln_type, - lp->lockname.ln_number, lp->flags); + log_info("ast sb_status %d %x,%llx flags %lx", + lp->lksb.sb_status, lp->lockname.ln_type, + lp->lockname.ln_number, lp->flags); return; } @@ -152,8 +143,10 @@ static void process_complete(struct gdlm_lock *lp) */ if (test_and_clear_bit(LFL_REREQUEST, &lp->flags)) { - GDLM_ASSERT(lp->req == DLM_LOCK_NL,); - GDLM_ASSERT(lp->prev_req > DLM_LOCK_NL,); + gdlm_assert(lp->req == DLM_LOCK_NL, "%x,%llx", + lp->lockname.ln_type, lp->lockname.ln_number); + gdlm_assert(lp->prev_req > DLM_LOCK_NL, "%x,%llx", + lp->lockname.ln_type, lp->lockname.ln_number); lp->cur = DLM_LOCK_NL; lp->req = lp->prev_req; @@ -189,7 +182,7 @@ static void process_complete(struct gdlm_lock *lp) lp->lkf |= DLM_LKF_CONVERT; lp->lkf &= ~DLM_LKF_CONVDEADLK; - log_debug("rereq %x,%"PRIx64" id %x %d,%d", + log_debug("rereq %x,%llx id %x %d,%d", lp->lockname.ln_type, lp->lockname.ln_number, lp->lksb.sb_lkid, lp->cur, lp->req); @@ -315,7 +308,7 @@ static int gdlm_thread(void *data) process_blocking(lp, blocking); else if (submit) - process_submit(lp); + gdlm_do_lock(lp, NULL); if (drop) ls->fscb(ls->fsdata, LM_CB_DROPLOCKS, NULL); @@ -334,7 +327,7 @@ int gdlm_init_threads(struct gdlm_ls *ls) p = kthread_run(gdlm_thread, ls, "lock_dlm1"); error = IS_ERR(p); if (error) { - log_all("can't start lock_dlm1 thread %d", error); + log_error("can't start lock_dlm1 thread %d", error); return error; } ls->thread1 = p; @@ -342,7 +335,7 @@ int gdlm_init_threads(struct gdlm_ls *ls) p = kthread_run(gdlm_thread, ls, "lock_dlm2"); error = IS_ERR(p); if (error) { - log_all("can't start lock_dlm2 thread %d", error); + log_error("can't start lock_dlm2 thread %d", error); kthread_stop(ls->thread1); return error; } diff --git a/fs/gfs2/locking/nolock/lock_nolock.mod.c b/fs/gfs2/locking/nolock/lock_nolock.mod.c deleted file mode 100644 index ae92522b2182..000000000000 --- a/fs/gfs2/locking/nolock/lock_nolock.mod.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include - -MODULE_INFO(vermagic, VERMAGIC_STRING); - -#undef unix -struct module __this_module -__attribute__((section(".gnu.linkonce.this_module"))) = { - .name = __stringify(KBUILD_MODNAME), - .init = init_module, -#ifdef CONFIG_MODULE_UNLOAD - .exit = cleanup_module, -#endif -}; - -static const struct modversion_info ____versions[] -__attribute_used__ -__attribute__((section("__versions"))) = { - { 0x316962fc, "struct_module" }, - { 0x5a34a45c, "__kmalloc" }, - { 0x724beef2, "malloc_sizes" }, - { 0x3fa03a97, "memset" }, - { 0xc16fe12d, "__memcpy" }, - { 0xdd132261, "printk" }, - { 0x859204af, "sscanf" }, - { 0x3656bf5a, "lock_kernel" }, - { 0x1e6d26a8, "strstr" }, - { 0x41ede9df, "lm_register_proto" }, - { 0xb1f975aa, "unlock_kernel" }, - { 0x87b0b01f, "posix_lock_file_wait" }, - { 0x75f29cfd, "kmem_cache_alloc" }, - { 0x69384280, "lm_unregister_proto" }, - { 0x37a0cba, "kfree" }, - { 0x5d16bfe6, "posix_test_lock" }, -}; - -static const char __module_depends[] -__attribute_used__ -__attribute__((section(".modinfo"))) = -"depends=gfs2"; - - -MODULE_INFO(srcversion, "123E446F965A386A0C017C4"); diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index d3919e471163..b716e336c073 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -1,15 +1,11 @@ -/****************************************************************************** -******************************************************************************* -** -** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. -** -** This copyrighted material is made available to anyone wishing to use, -** modify, copy, or redistribute it subject to the terms and conditions -** of the GNU General Public License v.2. -** -******************************************************************************* -******************************************************************************/ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ #include #include @@ -27,23 +23,11 @@ struct nolock_lockspace { struct lm_lockops nolock_ops; -/** - * nolock_mount - mount a nolock lockspace - * @table_name: the name of the space to mount - * @host_data: host specific data - * @cb: the callback - * @fsdata: - * @min_lvb_size: - * @flags: - * @lockstruct: the structure of crap to fill in - * - * Returns: 0 on success, -EXXX on failure - */ - static int nolock_mount(char *table_name, char *host_data, lm_callback_t cb, lm_fsdata_t *fsdata, unsigned int min_lvb_size, int flags, - struct lm_lockstruct *lockstruct) + struct lm_lockstruct *lockstruct, + struct kobject *fskobj) { char *c; unsigned int jid; @@ -77,34 +61,16 @@ static int nolock_mount(char *table_name, char *host_data, return 0; } -/** - * nolock_others_may_mount - unmount a lock space - * @lockspace: the lockspace to unmount - * - */ - static void nolock_others_may_mount(lm_lockspace_t *lockspace) { } -/** - * nolock_unmount - unmount a lock space - * @lockspace: the lockspace to unmount - * - */ - static void nolock_unmount(lm_lockspace_t *lockspace) { struct nolock_lockspace *nl = (struct nolock_lockspace *)lockspace; kfree(nl); } -/** - * nolock_withdraw - withdraw from a lock space - * @lockspace: the lockspace - * - */ - static void nolock_withdraw(lm_lockspace_t *lockspace) { } @@ -164,12 +130,6 @@ static unsigned int nolock_unlock(lm_lock_t *lock, unsigned int cur_state) return 0; } -/** - * nolock_cancel - cancel a request on a lock - * @lock: the lock to cancel request for - * - */ - static void nolock_cancel(lm_lock_t *lock) { } @@ -219,16 +179,6 @@ static void nolock_sync_lvb(lm_lock_t *lock, char *lvb) { } -/** - * nolock_plock_get - - * @lockspace: the lockspace - * @name: - * @file: - * @fl: - * - * Returns: errno - */ - static int nolock_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, struct file *file, struct file_lock *fl) { @@ -244,17 +194,6 @@ static int nolock_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name, return 0; } -/** - * nolock_plock - - * @lockspace: the lockspace - * @name: - * @file: - * @cmd: - * @fl: - * - * Returns: errno - */ - static int nolock_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, struct file *file, int cmd, struct file_lock *fl) { @@ -265,16 +204,6 @@ static int nolock_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, return error; } -/** - * nolock_punlock - - * @lockspace: the lockspace - * @name: - * @file: - * @fl: - * - * Returns: errno - */ - static int nolock_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, struct file *file, struct file_lock *fl) { @@ -285,13 +214,6 @@ static int nolock_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, return error; } -/** - * nolock_recovery_done - reset the expired locks for a given jid - * @lockspace: the lockspace - * @jid: the jid - * - */ - static void nolock_recovery_done(lm_lockspace_t *lockspace, unsigned int jid, unsigned int message) { @@ -318,17 +240,11 @@ struct lm_lockops nolock_ops = { .lm_owner = THIS_MODULE, }; -/** - * init_nolock - Initialize the nolock module - * - * Returns: 0 on success, -EXXX on failure - */ - int __init init_nolock(void) { int error; - error = lm_register_proto(&nolock_ops); + error = gfs_register_lockproto(&nolock_ops); if (error) { printk("lock_nolock: can't register protocol: %d\n", error); return error; @@ -338,14 +254,9 @@ int __init init_nolock(void) return 0; } -/** - * exit_nolock - cleanup the nolock module - * - */ - void __exit exit_nolock(void) { - lm_unregister_proto(&nolock_ops); + gfs_unregister_lockproto(&nolock_ops); } module_init(init_nolock); diff --git a/include/linux/lock_dlm_plock.h b/include/linux/lock_dlm_plock.h new file mode 100644 index 000000000000..007b07a178ab --- /dev/null +++ b/include/linux/lock_dlm_plock.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ + +#ifndef __LOCK_DLM_PLOCK_DOT_H__ +#define __LOCK_DLM_PLOCK_DOT_H__ + +#define GDLM_PLOCK_MISC_NAME "lock_dlm_plock" + +#define GDLM_PLOCK_VERSION_MAJOR 1 +#define GDLM_PLOCK_VERSION_MINOR 0 +#define GDLM_PLOCK_VERSION_PATCH 0 + +enum { + GDLM_PLOCK_OP_LOCK = 1, + GDLM_PLOCK_OP_UNLOCK, + GDLM_PLOCK_OP_GET, +}; + +struct gdlm_plock_info { + __u32 version[3]; + __u8 optype; + __u8 ex; + __u8 wait; + __u8 pad; + __u32 pid; + __s32 nodeid; + __s32 rv; + __u32 fsid; + __u64 number; + __u64 start; + __u64 end; +}; + +#endif + -- cgit v1.2.3 From cd1344fe322cd9d95b2c0f011d6766677cfcb29b Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 18 Jan 2006 08:53:38 +0000 Subject: [GFS2] Remove unused ioctls and unused structure Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- include/linux/gfs2_ioctl.h | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/gfs2_ioctl.h b/include/linux/gfs2_ioctl.h index dde9840b1c30..ca9632862833 100644 --- a/include/linux/gfs2_ioctl.h +++ b/include/linux/gfs2_ioctl.h @@ -14,19 +14,8 @@ /* Ioctls implemented */ -#define GFS2_IOCTL_IDENTIFY _GFS2C_(1) -#define GFS2_IOCTL_SUPER _GFS2C_(2) #define GFS2_IOCTL_SETFLAGS _GFS2C_(3) #define GFS2_IOCTL_GETFLAGS _GFS2C_(4) -struct gfs2_ioctl { - unsigned int gi_argc; - const char **gi_argv; - - char __user *gi_data; - unsigned int gi_size; - uint64_t gi_offset; -}; - #endif /* ___GFS2_IOCTL_DOT_H__ */ -- cgit v1.2.3 From e7fd41792fc0ee52a05fcaac87511f118328d147 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Wed, 18 Jan 2006 09:30:29 +0000 Subject: [DLM] The core of the DLM for GFS2/CLVM This is the core of the distributed lock manager which is required to use GFS2 as a cluster filesystem. It is also used by CLVM and can be used as a standalone lock manager independantly of either of these two projects. It implements VAX-style locking modes. Signed-off-by: David Teigland Signed-off-by: Steve Whitehouse --- fs/Kconfig | 1 + fs/Makefile | 1 + fs/dlm/Kconfig | 30 + fs/dlm/Makefile | 21 + fs/dlm/ast.c | 167 ++ fs/dlm/ast.h | 26 + fs/dlm/config.c | 787 ++++++++++ fs/dlm/config.h | 42 + fs/dlm/debug_fs.c | 310 ++++ fs/dlm/device.c | 1084 +++++++++++++ fs/dlm/dir.c | 423 ++++++ fs/dlm/dir.h | 30 + fs/dlm/dlm_internal.h | 518 +++++++ fs/dlm/lock.c | 3610 ++++++++++++++++++++++++++++++++++++++++++++ fs/dlm/lock.h | 50 + fs/dlm/lockspace.c | 666 ++++++++ fs/dlm/lockspace.h | 24 + fs/dlm/lowcomms.c | 1218 +++++++++++++++ fs/dlm/lowcomms.h | 25 + fs/dlm/lvb_table.h | 18 + fs/dlm/main.c | 89 ++ fs/dlm/member.c | 314 ++++ fs/dlm/member.h | 24 + fs/dlm/memory.c | 122 ++ fs/dlm/memory.h | 31 + fs/dlm/midcomms.c | 140 ++ fs/dlm/midcomms.h | 21 + fs/dlm/rcom.c | 460 ++++++ fs/dlm/rcom.h | 24 + fs/dlm/recover.c | 762 ++++++++++ fs/dlm/recover.h | 34 + fs/dlm/recoverd.c | 285 ++++ fs/dlm/recoverd.h | 24 + fs/dlm/requestqueue.c | 184 +++ fs/dlm/requestqueue.h | 22 + fs/dlm/util.c | 173 +++ fs/dlm/util.h | 22 + include/linux/dlm.h | 312 ++++ include/linux/dlm_device.h | 84 ++ 39 files changed, 12178 insertions(+) create mode 100644 fs/dlm/Kconfig create mode 100644 fs/dlm/Makefile create mode 100644 fs/dlm/ast.c create mode 100644 fs/dlm/ast.h create mode 100644 fs/dlm/config.c create mode 100644 fs/dlm/config.h create mode 100644 fs/dlm/debug_fs.c create mode 100644 fs/dlm/device.c create mode 100644 fs/dlm/dir.c create mode 100644 fs/dlm/dir.h create mode 100644 fs/dlm/dlm_internal.h create mode 100644 fs/dlm/lock.c create mode 100644 fs/dlm/lock.h create mode 100644 fs/dlm/lockspace.c create mode 100644 fs/dlm/lockspace.h create mode 100644 fs/dlm/lowcomms.c create mode 100644 fs/dlm/lowcomms.h create mode 100644 fs/dlm/lvb_table.h create mode 100644 fs/dlm/main.c create mode 100644 fs/dlm/member.c create mode 100644 fs/dlm/member.h create mode 100644 fs/dlm/memory.c create mode 100644 fs/dlm/memory.h create mode 100644 fs/dlm/midcomms.c create mode 100644 fs/dlm/midcomms.h create mode 100644 fs/dlm/rcom.c create mode 100644 fs/dlm/rcom.h create mode 100644 fs/dlm/recover.c create mode 100644 fs/dlm/recover.h create mode 100644 fs/dlm/recoverd.c create mode 100644 fs/dlm/recoverd.h create mode 100644 fs/dlm/requestqueue.c create mode 100644 fs/dlm/requestqueue.h create mode 100644 fs/dlm/util.c create mode 100644 fs/dlm/util.h create mode 100644 include/linux/dlm.h create mode 100644 include/linux/dlm_device.h (limited to 'include/linux') diff --git a/fs/Kconfig b/fs/Kconfig index bec8afa5704d..3a32f3f97e9b 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1831,6 +1831,7 @@ source "fs/partitions/Kconfig" endmenu source "fs/nls/Kconfig" +source "fs/dlm/Kconfig" endmenu diff --git a/fs/Makefile b/fs/Makefile index 0922727732c5..b298f4fdc6f2 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_SYSFS) += sysfs/ obj-y += devpts/ obj-$(CONFIG_PROFILING) += dcookies.o +obj-$(CONFIG_DLM) += dlm/ # Do not add any filesystems before this line obj-$(CONFIG_REISERFS_FS) += reiserfs/ diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig new file mode 100644 index 000000000000..d01f735e6e06 --- /dev/null +++ b/fs/dlm/Kconfig @@ -0,0 +1,30 @@ +menu "Distributed Lock Manager" + depends on INET && EXPERIMENTAL + +config DLM + tristate "Distributed Lock Manager (DLM)" + depends on SYSFS + depends on IPV6 || IPV6=n + select IP_SCTP + select CONFIGFS_FS + help + A general purpose distributed lock manager for kernel or userspace + applications. + +config DLM_DEVICE + tristate "DLM device for userspace access" + depends on DLM + help + This module creates a misc device through which the dlm lockspace + and locking functions become available to userspace applications + (usually through the libdlm library). + +config DLM_DEBUG + bool "DLM debugging" + depends on DLM + help + Under the debugfs mount point, the name of each lockspace will + appear as a file in the "dlm" directory. The output is the + list of resource and locks the local node knows about. + +endmenu diff --git a/fs/dlm/Makefile b/fs/dlm/Makefile new file mode 100644 index 000000000000..1e6232e7d8e5 --- /dev/null +++ b/fs/dlm/Makefile @@ -0,0 +1,21 @@ +obj-$(CONFIG_DLM) += dlm.o +obj-$(CONFIG_DLM_DEVICE) += dlm_device.o + +dlm-y := ast.o \ + config.o \ + dir.o \ + lock.o \ + lockspace.o \ + lowcomms.o \ + main.o \ + member.o \ + memory.o \ + midcomms.o \ + rcom.o \ + recover.o \ + recoverd.o \ + requestqueue.o \ + util.o +dlm-$(CONFIG_DLM_DEBUG) += debug_fs.o + +dlm_device-y := device.o diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c new file mode 100644 index 000000000000..2bd1c5e1a72c --- /dev/null +++ b/fs/dlm/ast.c @@ -0,0 +1,167 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "lock.h" +#include "ast.h" + +#define WAKE_ASTS 0 + +static struct list_head ast_queue; +static spinlock_t ast_queue_lock; +static struct task_struct * astd_task; +static unsigned long astd_wakeflags; +static struct semaphore astd_running; + + +void dlm_del_ast(struct dlm_lkb *lkb) +{ + spin_lock(&ast_queue_lock); + if (lkb->lkb_ast_type & (AST_COMP | AST_BAST)) + list_del(&lkb->lkb_astqueue); + spin_unlock(&ast_queue_lock); +} + +void dlm_add_ast(struct dlm_lkb *lkb, int type) +{ + spin_lock(&ast_queue_lock); + if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { + kref_get(&lkb->lkb_ref); + list_add_tail(&lkb->lkb_astqueue, &ast_queue); + } + lkb->lkb_ast_type |= type; + spin_unlock(&ast_queue_lock); + + set_bit(WAKE_ASTS, &astd_wakeflags); + wake_up_process(astd_task); +} + +static void process_asts(void) +{ + struct dlm_ls *ls = NULL; + struct dlm_rsb *r = NULL; + struct dlm_lkb *lkb; + void (*cast) (long param); + void (*bast) (long param, int mode); + int type = 0, found, bmode; + + for (;;) { + found = FALSE; + spin_lock(&ast_queue_lock); + list_for_each_entry(lkb, &ast_queue, lkb_astqueue) { + r = lkb->lkb_resource; + ls = r->res_ls; + + if (dlm_locking_stopped(ls)) + continue; + + list_del(&lkb->lkb_astqueue); + type = lkb->lkb_ast_type; + lkb->lkb_ast_type = 0; + found = TRUE; + break; + } + spin_unlock(&ast_queue_lock); + + if (!found) + break; + + cast = lkb->lkb_astaddr; + bast = lkb->lkb_bastaddr; + bmode = lkb->lkb_bastmode; + + if ((type & AST_COMP) && cast) + cast(lkb->lkb_astparam); + + /* FIXME: Is it safe to look at lkb_grmode here + without doing a lock_rsb() ? + Look at other checks in v1 to avoid basts. */ + + if ((type & AST_BAST) && bast) + if (!dlm_modes_compat(lkb->lkb_grmode, bmode)) + bast(lkb->lkb_astparam, bmode); + + /* this removes the reference added by dlm_add_ast + and may result in the lkb being freed */ + dlm_put_lkb(lkb); + + schedule(); + } +} + +static inline int no_asts(void) +{ + int ret; + + spin_lock(&ast_queue_lock); + ret = list_empty(&ast_queue); + spin_unlock(&ast_queue_lock); + return ret; +} + +static int dlm_astd(void *data) +{ + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + if (!test_bit(WAKE_ASTS, &astd_wakeflags)) + schedule(); + set_current_state(TASK_RUNNING); + + down(&astd_running); + if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags)) + process_asts(); + up(&astd_running); + } + return 0; +} + +void dlm_astd_wake(void) +{ + if (!no_asts()) { + set_bit(WAKE_ASTS, &astd_wakeflags); + wake_up_process(astd_task); + } +} + +int dlm_astd_start(void) +{ + struct task_struct *p; + int error = 0; + + INIT_LIST_HEAD(&ast_queue); + spin_lock_init(&ast_queue_lock); + init_MUTEX(&astd_running); + + p = kthread_run(dlm_astd, NULL, "dlm_astd"); + if (IS_ERR(p)) + error = PTR_ERR(p); + else + astd_task = p; + return error; +} + +void dlm_astd_stop(void) +{ + kthread_stop(astd_task); +} + +void dlm_astd_suspend(void) +{ + down(&astd_running); +} + +void dlm_astd_resume(void) +{ + up(&astd_running); +} + diff --git a/fs/dlm/ast.h b/fs/dlm/ast.h new file mode 100644 index 000000000000..6ee276c74c52 --- /dev/null +++ b/fs/dlm/ast.h @@ -0,0 +1,26 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __ASTD_DOT_H__ +#define __ASTD_DOT_H__ + +void dlm_add_ast(struct dlm_lkb *lkb, int type); +void dlm_del_ast(struct dlm_lkb *lkb); + +void dlm_astd_wake(void); +int dlm_astd_start(void); +void dlm_astd_stop(void); +void dlm_astd_suspend(void); +void dlm_astd_resume(void); + +#endif + diff --git a/fs/dlm/config.c b/fs/dlm/config.c new file mode 100644 index 000000000000..024ace9973a8 --- /dev/null +++ b/fs/dlm/config.c @@ -0,0 +1,787 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include +#include +#include +#include + +#include "config.h" + +/* + * /config/dlm//spaces//nodes//nodeid + * /config/dlm//spaces//nodes//weight + * /config/dlm//comms//nodeid + * /config/dlm//comms//local + * /config/dlm//comms//addr + * The level is useless, but I haven't figured out how to avoid it. + */ + +static struct config_group *space_list; +static struct config_group *comm_list; +static struct comm *local_comm; + +struct clusters; +struct cluster; +struct spaces; +struct space; +struct comms; +struct comm; +struct nodes; +struct node; + +static struct config_group *make_cluster(struct config_group *, const char *); +static void drop_cluster(struct config_group *, struct config_item *); +static void release_cluster(struct config_item *); +static struct config_group *make_space(struct config_group *, const char *); +static void drop_space(struct config_group *, struct config_item *); +static void release_space(struct config_item *); +static struct config_item *make_comm(struct config_group *, const char *); +static void drop_comm(struct config_group *, struct config_item *); +static void release_comm(struct config_item *); +static struct config_item *make_node(struct config_group *, const char *); +static void drop_node(struct config_group *, struct config_item *); +static void release_node(struct config_item *); + +static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, + char *buf); +static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a, + const char *buf, size_t len); +static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, + char *buf); +static ssize_t store_node(struct config_item *i, struct configfs_attribute *a, + const char *buf, size_t len); + +static ssize_t comm_nodeid_read(struct comm *cm, char *buf); +static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len); +static ssize_t comm_local_read(struct comm *cm, char *buf); +static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len); +static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len); +static ssize_t node_nodeid_read(struct node *nd, char *buf); +static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len); +static ssize_t node_weight_read(struct node *nd, char *buf); +static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len); + +enum { + COMM_ATTR_NODEID = 0, + COMM_ATTR_LOCAL, + COMM_ATTR_ADDR, +}; + +struct comm_attribute { + struct configfs_attribute attr; + ssize_t (*show)(struct comm *, char *); + ssize_t (*store)(struct comm *, const char *, size_t); +}; + +static struct comm_attribute comm_attr_nodeid = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "nodeid", + .ca_mode = S_IRUGO | S_IWUSR }, + .show = comm_nodeid_read, + .store = comm_nodeid_write, +}; + +static struct comm_attribute comm_attr_local = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "local", + .ca_mode = S_IRUGO | S_IWUSR }, + .show = comm_local_read, + .store = comm_local_write, +}; + +static struct comm_attribute comm_attr_addr = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "addr", + .ca_mode = S_IRUGO | S_IWUSR }, + .store = comm_addr_write, +}; + +static struct configfs_attribute *comm_attrs[] = { + [COMM_ATTR_NODEID] = &comm_attr_nodeid.attr, + [COMM_ATTR_LOCAL] = &comm_attr_local.attr, + [COMM_ATTR_ADDR] = &comm_attr_addr.attr, + NULL, +}; + +enum { + NODE_ATTR_NODEID = 0, + NODE_ATTR_WEIGHT, +}; + +struct node_attribute { + struct configfs_attribute attr; + ssize_t (*show)(struct node *, char *); + ssize_t (*store)(struct node *, const char *, size_t); +}; + +static struct node_attribute node_attr_nodeid = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "nodeid", + .ca_mode = S_IRUGO | S_IWUSR }, + .show = node_nodeid_read, + .store = node_nodeid_write, +}; + +static struct node_attribute node_attr_weight = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "weight", + .ca_mode = S_IRUGO | S_IWUSR }, + .show = node_weight_read, + .store = node_weight_write, +}; + +static struct configfs_attribute *node_attrs[] = { + [NODE_ATTR_NODEID] = &node_attr_nodeid.attr, + [NODE_ATTR_WEIGHT] = &node_attr_weight.attr, + NULL, +}; + +struct clusters { + struct configfs_subsystem subsys; +}; + +struct cluster { + struct config_group group; +}; + +struct spaces { + struct config_group ss_group; +}; + +struct space { + struct config_group group; + struct list_head members; + struct semaphore members_lock; + int members_count; +}; + +struct comms { + struct config_group cs_group; +}; + +struct comm { + struct config_item item; + int nodeid; + int local; + int addr_count; + struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT]; +}; + +struct nodes { + struct config_group ns_group; +}; + +struct node { + struct config_item item; + struct list_head list; /* space->members */ + int nodeid; + int weight; +}; + +static struct configfs_group_operations clusters_ops = { + .make_group = make_cluster, + .drop_item = drop_cluster, +}; + +static struct configfs_item_operations cluster_ops = { + .release = release_cluster, +}; + +static struct configfs_group_operations spaces_ops = { + .make_group = make_space, + .drop_item = drop_space, +}; + +static struct configfs_item_operations space_ops = { + .release = release_space, +}; + +static struct configfs_group_operations comms_ops = { + .make_item = make_comm, + .drop_item = drop_comm, +}; + +static struct configfs_item_operations comm_ops = { + .release = release_comm, + .show_attribute = show_comm, + .store_attribute = store_comm, +}; + +static struct configfs_group_operations nodes_ops = { + .make_item = make_node, + .drop_item = drop_node, +}; + +static struct configfs_item_operations node_ops = { + .release = release_node, + .show_attribute = show_node, + .store_attribute = store_node, +}; + +static struct config_item_type clusters_type = { + .ct_group_ops = &clusters_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_item_type cluster_type = { + .ct_item_ops = &cluster_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_item_type spaces_type = { + .ct_group_ops = &spaces_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_item_type space_type = { + .ct_item_ops = &space_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_item_type comms_type = { + .ct_group_ops = &comms_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_item_type comm_type = { + .ct_item_ops = &comm_ops, + .ct_attrs = comm_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_item_type nodes_type = { + .ct_group_ops = &nodes_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_item_type node_type = { + .ct_item_ops = &node_ops, + .ct_attrs = node_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct cluster *to_cluster(struct config_item *i) +{ + return i ? container_of(to_config_group(i), struct cluster, group):NULL; +} + +static struct space *to_space(struct config_item *i) +{ + return i ? container_of(to_config_group(i), struct space, group) : NULL; +} + +static struct comm *to_comm(struct config_item *i) +{ + return i ? container_of(i, struct comm, item) : NULL; +} + +static struct node *to_node(struct config_item *i) +{ + return i ? container_of(i, struct node, item) : NULL; +} + +static struct config_group *make_cluster(struct config_group *g, + const char *name) +{ + struct cluster *cl = NULL; + struct spaces *sps = NULL; + struct comms *cms = NULL; + void *gps = NULL; + + cl = kzalloc(sizeof(struct cluster), GFP_KERNEL); + gps = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL); + sps = kzalloc(sizeof(struct spaces), GFP_KERNEL); + cms = kzalloc(sizeof(struct comms), GFP_KERNEL); + + if (!cl || !gps || !sps || !cms) + goto fail; + + config_group_init_type_name(&cl->group, name, &cluster_type); + config_group_init_type_name(&sps->ss_group, "spaces", &spaces_type); + config_group_init_type_name(&cms->cs_group, "comms", &comms_type); + + cl->group.default_groups = gps; + cl->group.default_groups[0] = &sps->ss_group; + cl->group.default_groups[1] = &cms->cs_group; + cl->group.default_groups[2] = NULL; + + space_list = &sps->ss_group; + comm_list = &cms->cs_group; + return &cl->group; + + fail: + kfree(cl); + kfree(gps); + kfree(sps); + kfree(cms); + return NULL; +} + +static void drop_cluster(struct config_group *g, struct config_item *i) +{ + struct cluster *cl = to_cluster(i); + struct config_item *tmp; + int j; + + for (j = 0; cl->group.default_groups[j]; j++) { + tmp = &cl->group.default_groups[j]->cg_item; + cl->group.default_groups[j] = NULL; + config_item_put(tmp); + } + + space_list = NULL; + comm_list = NULL; + + config_item_put(i); +} + +static void release_cluster(struct config_item *i) +{ + struct cluster *cl = to_cluster(i); + kfree(cl->group.default_groups); + kfree(cl); +} + +static struct config_group *make_space(struct config_group *g, const char *name) +{ + struct space *sp = NULL; + struct nodes *nds = NULL; + void *gps = NULL; + + sp = kzalloc(sizeof(struct space), GFP_KERNEL); + gps = kcalloc(2, sizeof(struct config_group *), GFP_KERNEL); + nds = kzalloc(sizeof(struct nodes), GFP_KERNEL); + + if (!sp || !gps || !nds) + goto fail; + + config_group_init_type_name(&sp->group, name, &space_type); + config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type); + + sp->group.default_groups = gps; + sp->group.default_groups[0] = &nds->ns_group; + sp->group.default_groups[1] = NULL; + + INIT_LIST_HEAD(&sp->members); + init_MUTEX(&sp->members_lock); + sp->members_count = 0; + return &sp->group; + + fail: + kfree(sp); + kfree(gps); + kfree(nds); + return NULL; +} + +static void drop_space(struct config_group *g, struct config_item *i) +{ + struct space *sp = to_space(i); + struct config_item *tmp; + int j; + + /* assert list_empty(&sp->members) */ + + for (j = 0; sp->group.default_groups[j]; j++) { + tmp = &sp->group.default_groups[j]->cg_item; + sp->group.default_groups[j] = NULL; + config_item_put(tmp); + } + + config_item_put(i); +} + +static void release_space(struct config_item *i) +{ + struct space *sp = to_space(i); + kfree(sp->group.default_groups); + kfree(sp); +} + +static struct config_item *make_comm(struct config_group *g, const char *name) +{ + struct comm *cm; + + cm = kzalloc(sizeof(struct comm), GFP_KERNEL); + if (!cm) + return NULL; + + config_item_init_type_name(&cm->item, name, &comm_type); + cm->nodeid = -1; + cm->local = 0; + cm->addr_count = 0; + return &cm->item; +} + +static void drop_comm(struct config_group *g, struct config_item *i) +{ + struct comm *cm = to_comm(i); + if (local_comm == cm) + local_comm = NULL; + while (cm->addr_count--) + kfree(cm->addr[cm->addr_count]); + config_item_put(i); +} + +static void release_comm(struct config_item *i) +{ + struct comm *cm = to_comm(i); + kfree(cm); +} + +static struct config_item *make_node(struct config_group *g, const char *name) +{ + struct space *sp = to_space(g->cg_item.ci_parent); + struct node *nd; + + nd = kzalloc(sizeof(struct node), GFP_KERNEL); + if (!nd) + return NULL; + + config_item_init_type_name(&nd->item, name, &node_type); + nd->nodeid = -1; + nd->weight = 1; /* default weight of 1 if none is set */ + + down(&sp->members_lock); + list_add(&nd->list, &sp->members); + sp->members_count++; + up(&sp->members_lock); + + return &nd->item; +} + +static void drop_node(struct config_group *g, struct config_item *i) +{ + struct space *sp = to_space(g->cg_item.ci_parent); + struct node *nd = to_node(i); + + down(&sp->members_lock); + list_del(&nd->list); + sp->members_count--; + up(&sp->members_lock); + + config_item_put(i); +} + +static void release_node(struct config_item *i) +{ + struct node *nd = to_node(i); + kfree(nd); +} + +static struct clusters clusters_root = { + .subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "dlm", + .ci_type = &clusters_type, + }, + }, + }, +}; + +int dlm_config_init(void) +{ + config_group_init(&clusters_root.subsys.su_group); + init_MUTEX(&clusters_root.subsys.su_sem); + return configfs_register_subsystem(&clusters_root.subsys); +} + +void dlm_config_exit(void) +{ + configfs_unregister_subsystem(&clusters_root.subsys); +} + +/* + * Functions for user space to read/write attributes + */ + +static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, + char *buf) +{ + struct comm *cm = to_comm(i); + struct comm_attribute *cma = + container_of(a, struct comm_attribute, attr); + return cma->show ? cma->show(cm, buf) : 0; +} + +static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a, + const char *buf, size_t len) +{ + struct comm *cm = to_comm(i); + struct comm_attribute *cma = + container_of(a, struct comm_attribute, attr); + return cma->store ? cma->store(cm, buf, len) : -EINVAL; +} + +static ssize_t comm_nodeid_read(struct comm *cm, char *buf) +{ + return sprintf(buf, "%d\n", cm->nodeid); +} + +static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len) +{ + cm->nodeid = simple_strtol(buf, NULL, 0); + return len; +} + +static ssize_t comm_local_read(struct comm *cm, char *buf) +{ + return sprintf(buf, "%d\n", cm->local); +} + +static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len) +{ + cm->local= simple_strtol(buf, NULL, 0); + if (cm->local && !local_comm) + local_comm = cm; + return len; +} + +static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len) +{ + struct sockaddr_storage *addr; + + if (len != sizeof(struct sockaddr_storage)) + return -EINVAL; + + if (cm->addr_count >= DLM_MAX_ADDR_COUNT) + return -ENOSPC; + + addr = kzalloc(sizeof(*addr), GFP_KERNEL); + if (!addr) + return -ENOMEM; + + memcpy(addr, buf, len); + cm->addr[cm->addr_count++] = addr; + return len; +} + +static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, + char *buf) +{ + struct node *nd = to_node(i); + struct node_attribute *nda = + container_of(a, struct node_attribute, attr); + return nda->show ? nda->show(nd, buf) : 0; +} + +static ssize_t store_node(struct config_item *i, struct configfs_attribute *a, + const char *buf, size_t len) +{ + struct node *nd = to_node(i); + struct node_attribute *nda = + container_of(a, struct node_attribute, attr); + return nda->store ? nda->store(nd, buf, len) : -EINVAL; +} + +static ssize_t node_nodeid_read(struct node *nd, char *buf) +{ + return sprintf(buf, "%d\n", nd->nodeid); +} + +static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len) +{ + nd->nodeid = simple_strtol(buf, NULL, 0); + return len; +} + +static ssize_t node_weight_read(struct node *nd, char *buf) +{ + return sprintf(buf, "%d\n", nd->weight); +} + +static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len) +{ + nd->weight = simple_strtol(buf, NULL, 0); + return len; +} + +/* + * Functions for the dlm to get the info that's been configured + */ + +static struct space *get_space(char *name) +{ + if (!space_list) + return NULL; + return to_space(config_group_find_obj(space_list, name)); +} + +static void put_space(struct space *sp) +{ + config_item_put(&sp->group.cg_item); +} + +static struct comm *get_comm(int nodeid, struct sockaddr_storage *addr) +{ + struct config_item *i; + struct comm *cm = NULL; + int found = 0; + + if (!comm_list) + return NULL; + + down(&clusters_root.subsys.su_sem); + + list_for_each_entry(i, &comm_list->cg_children, ci_entry) { + cm = to_comm(i); + + if (nodeid) { + if (cm->nodeid != nodeid) + continue; + found = 1; + break; + } else { + if (!cm->addr_count || + memcmp(cm->addr[0], addr, sizeof(*addr))) + continue; + found = 1; + break; + } + } + up(&clusters_root.subsys.su_sem); + + if (found) + config_item_get(i); + else + cm = NULL; + return cm; +} + +static void put_comm(struct comm *cm) +{ + config_item_put(&cm->item); +} + +/* caller must free mem */ +int dlm_nodeid_list(char *lsname, int **ids_out) +{ + struct space *sp; + struct node *nd; + int i = 0, rv = 0; + int *ids; + + sp = get_space(lsname); + if (!sp) + return -EEXIST; + + down(&sp->members_lock); + if (!sp->members_count) { + rv = 0; + goto out; + } + + ids = kcalloc(sp->members_count, sizeof(int), GFP_KERNEL); + if (!ids) { + rv = -ENOMEM; + goto out; + } + + rv = sp->members_count; + list_for_each_entry(nd, &sp->members, list) + ids[i++] = nd->nodeid; + + if (rv != i) + printk("bad nodeid count %d %d\n", rv, i); + + *ids_out = ids; + out: + up(&sp->members_lock); + put_space(sp); + return rv; +} + +int dlm_node_weight(char *lsname, int nodeid) +{ + struct space *sp; + struct node *nd; + int w = -EEXIST; + + sp = get_space(lsname); + if (!sp) + goto out; + + down(&sp->members_lock); + list_for_each_entry(nd, &sp->members, list) { + if (nd->nodeid != nodeid) + continue; + w = nd->weight; + break; + } + up(&sp->members_lock); + put_space(sp); + out: + return w; +} + +int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr) +{ + struct comm *cm = get_comm(nodeid, NULL); + if (!cm) + return -EEXIST; + if (!cm->addr_count) + return -ENOENT; + memcpy(addr, cm->addr[0], sizeof(*addr)); + put_comm(cm); + return 0; +} + +int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid) +{ + struct comm *cm = get_comm(0, addr); + if (!cm) + return -EEXIST; + *nodeid = cm->nodeid; + put_comm(cm); + return 0; +} + +int dlm_our_nodeid(void) +{ + return local_comm ? local_comm->nodeid : 0; +} + +/* num 0 is first addr, num 1 is second addr */ +int dlm_our_addr(struct sockaddr_storage *addr, int num) +{ + if (!local_comm) + return -1; + if (num + 1 > local_comm->addr_count) + return -1; + memcpy(addr, local_comm->addr[num], sizeof(*addr)); + return 0; +} + +/* Config file defaults */ +#define DEFAULT_TCP_PORT 21064 +#define DEFAULT_BUFFER_SIZE 4096 +#define DEFAULT_RSBTBL_SIZE 256 +#define DEFAULT_LKBTBL_SIZE 1024 +#define DEFAULT_DIRTBL_SIZE 512 +#define DEFAULT_RECOVER_TIMER 5 +#define DEFAULT_TOSS_SECS 10 +#define DEFAULT_SCAN_SECS 5 + +struct dlm_config_info dlm_config = { + .tcp_port = DEFAULT_TCP_PORT, + .buffer_size = DEFAULT_BUFFER_SIZE, + .rsbtbl_size = DEFAULT_RSBTBL_SIZE, + .lkbtbl_size = DEFAULT_LKBTBL_SIZE, + .dirtbl_size = DEFAULT_DIRTBL_SIZE, + .recover_timer = DEFAULT_RECOVER_TIMER, + .toss_secs = DEFAULT_TOSS_SECS, + .scan_secs = DEFAULT_SCAN_SECS +}; + diff --git a/fs/dlm/config.h b/fs/dlm/config.h new file mode 100644 index 000000000000..9da7839958a9 --- /dev/null +++ b/fs/dlm/config.h @@ -0,0 +1,42 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __CONFIG_DOT_H__ +#define __CONFIG_DOT_H__ + +#define DLM_MAX_ADDR_COUNT 3 + +struct dlm_config_info { + int tcp_port; + int buffer_size; + int rsbtbl_size; + int lkbtbl_size; + int dirtbl_size; + int recover_timer; + int toss_secs; + int scan_secs; +}; + +extern struct dlm_config_info dlm_config; + +int dlm_config_init(void); +void dlm_config_exit(void); +int dlm_node_weight(char *lsname, int nodeid); +int dlm_nodeid_list(char *lsname, int **ids_out); +int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr); +int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid); +int dlm_our_nodeid(void); +int dlm_our_addr(struct sockaddr_storage *addr, int num); + +#endif /* __CONFIG_DOT_H__ */ + diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c new file mode 100644 index 000000000000..98b49a1ece47 --- /dev/null +++ b/fs/dlm/debug_fs.c @@ -0,0 +1,310 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include +#include +#include +#include +#include + +#include "dlm_internal.h" + + +static struct dentry *dlm_root; + +struct rsb_iter { + int entry; + struct dlm_ls *ls; + struct list_head *next; + struct dlm_rsb *rsb; +}; + +static char *print_lockmode(int mode) +{ + switch (mode) { + case DLM_LOCK_IV: + return "--"; + case DLM_LOCK_NL: + return "NL"; + case DLM_LOCK_CR: + return "CR"; + case DLM_LOCK_CW: + return "CW"; + case DLM_LOCK_PR: + return "PR"; + case DLM_LOCK_PW: + return "PW"; + case DLM_LOCK_EX: + return "EX"; + default: + return "??"; + } +} + +static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, + struct dlm_rsb *res) +{ + seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); + + if (lkb->lkb_status == DLM_LKSTS_CONVERT + || lkb->lkb_status == DLM_LKSTS_WAITING) + seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode)); + + if (lkb->lkb_range) { + /* FIXME: this warns on Alpha */ + if (lkb->lkb_status == DLM_LKSTS_CONVERT + || lkb->lkb_status == DLM_LKSTS_GRANTED) + seq_printf(s, " %" PRIx64 "-%" PRIx64, + lkb->lkb_range[GR_RANGE_START], + lkb->lkb_range[GR_RANGE_END]); + if (lkb->lkb_status == DLM_LKSTS_CONVERT + || lkb->lkb_status == DLM_LKSTS_WAITING) + seq_printf(s, " (%" PRIx64 "-%" PRIx64 ")", + lkb->lkb_range[RQ_RANGE_START], + lkb->lkb_range[RQ_RANGE_END]); + } + + if (lkb->lkb_nodeid) { + if (lkb->lkb_nodeid != res->res_nodeid) + seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid, + lkb->lkb_remid); + else + seq_printf(s, " Master: %08x", lkb->lkb_remid); + } + + if (lkb->lkb_wait_type) + seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); + + seq_printf(s, "\n"); +} + +static int print_resource(struct dlm_rsb *res, struct seq_file *s) +{ + struct dlm_lkb *lkb; + int i, lvblen = res->res_ls->ls_lvblen; + + seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length); + for (i = 0; i < res->res_length; i++) { + if (isprint(res->res_name[i])) + seq_printf(s, "%c", res->res_name[i]); + else + seq_printf(s, "%c", '.'); + } + if (res->res_nodeid > 0) + seq_printf(s, "\" \nLocal Copy, Master is node %d\n", + res->res_nodeid); + else if (res->res_nodeid == 0) + seq_printf(s, "\" \nMaster Copy\n"); + else if (res->res_nodeid == -1) + seq_printf(s, "\" \nLooking up master (lkid %x)\n", + res->res_first_lkid); + else + seq_printf(s, "\" \nInvalid master %d\n", res->res_nodeid); + + /* Print the LVB: */ + if (res->res_lvbptr) { + seq_printf(s, "LVB: "); + for (i = 0; i < lvblen; i++) { + if (i == lvblen / 2) + seq_printf(s, "\n "); + seq_printf(s, "%02x ", + (unsigned char) res->res_lvbptr[i]); + } + if (rsb_flag(res, RSB_VALNOTVALID)) + seq_printf(s, " (INVALID)"); + seq_printf(s, "\n"); + } + + /* Print the locks attached to this resource */ + seq_printf(s, "Granted Queue\n"); + list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) + print_lock(s, lkb, res); + + seq_printf(s, "Conversion Queue\n"); + list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) + print_lock(s, lkb, res); + + seq_printf(s, "Waiting Queue\n"); + list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) + print_lock(s, lkb, res); + + return 0; +} + +static int rsb_iter_next(struct rsb_iter *ri) +{ + struct dlm_ls *ls = ri->ls; + int i; + + if (!ri->next) { + top: + /* Find the next non-empty hash bucket */ + for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) { + read_lock(&ls->ls_rsbtbl[i].lock); + if (!list_empty(&ls->ls_rsbtbl[i].list)) { + ri->next = ls->ls_rsbtbl[i].list.next; + read_unlock(&ls->ls_rsbtbl[i].lock); + break; + } + read_unlock(&ls->ls_rsbtbl[i].lock); + } + ri->entry = i; + + if (ri->entry >= ls->ls_rsbtbl_size) + return 1; + } else { + i = ri->entry; + read_lock(&ls->ls_rsbtbl[i].lock); + ri->next = ri->next->next; + if (ri->next->next == ls->ls_rsbtbl[i].list.next) { + /* End of list - move to next bucket */ + ri->next = NULL; + ri->entry++; + read_unlock(&ls->ls_rsbtbl[i].lock); + goto top; + } + read_unlock(&ls->ls_rsbtbl[i].lock); + } + ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); + + return 0; +} + +static void rsb_iter_free(struct rsb_iter *ri) +{ + kfree(ri); +} + +static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls) +{ + struct rsb_iter *ri; + + ri = kmalloc(sizeof *ri, GFP_KERNEL); + if (!ri) + return NULL; + + ri->ls = ls; + ri->entry = 0; + ri->next = NULL; + + if (rsb_iter_next(ri)) { + rsb_iter_free(ri); + return NULL; + } + + return ri; +} + +static void *seq_start(struct seq_file *file, loff_t *pos) +{ + struct rsb_iter *ri; + loff_t n = *pos; + + ri = rsb_iter_init(file->private); + if (!ri) + return NULL; + + while (n--) { + if (rsb_iter_next(ri)) { + rsb_iter_free(ri); + return NULL; + } + } + + return ri; +} + +static void *seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) +{ + struct rsb_iter *ri = iter_ptr; + + (*pos)++; + + if (rsb_iter_next(ri)) { + rsb_iter_free(ri); + return NULL; + } + + return ri; +} + +static void seq_stop(struct seq_file *file, void *iter_ptr) +{ + /* nothing for now */ +} + +static int seq_show(struct seq_file *file, void *iter_ptr) +{ + struct rsb_iter *ri = iter_ptr; + + print_resource(ri->rsb, file); + + return 0; +} + +static struct seq_operations dlm_seq_ops = { + .start = seq_start, + .next = seq_next, + .stop = seq_stop, + .show = seq_show, +}; + +static int do_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int ret; + + ret = seq_open(file, &dlm_seq_ops); + if (ret) + return ret; + + seq = file->private_data; + seq->private = inode->u.generic_ip; + + return 0; +} + +static struct file_operations dlm_fops = { + .owner = THIS_MODULE, + .open = do_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +int dlm_create_debug_file(struct dlm_ls *ls) +{ + ls->ls_debug_dentry = debugfs_create_file(ls->ls_name, + S_IFREG | S_IRUGO, + dlm_root, + ls, + &dlm_fops); + return ls->ls_debug_dentry ? 0 : -ENOMEM; +} + +void dlm_delete_debug_file(struct dlm_ls *ls) +{ + if (ls->ls_debug_dentry) + debugfs_remove(ls->ls_debug_dentry); +} + +int dlm_register_debugfs(void) +{ + dlm_root = debugfs_create_dir("dlm", NULL); + return dlm_root ? 0 : -ENOMEM; +} + +void dlm_unregister_debugfs(void) +{ + debugfs_remove(dlm_root); +} + diff --git a/fs/dlm/device.c b/fs/dlm/device.c new file mode 100644 index 000000000000..a8bf600ed13d --- /dev/null +++ b/fs/dlm/device.c @@ -0,0 +1,1084 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +/* + * device.c + * + * This is the userland interface to the DLM. + * + * The locking is done via a misc char device (find the + * registered minor number in /proc/misc). + * + * User code should not use this interface directly but + * call the library routines in libdlm.a instead. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "lvb_table.h" + +static struct file_operations _dlm_fops; +static const char *name_prefix="dlm"; +static struct list_head user_ls_list; +static struct semaphore user_ls_lock; + +/* Lock infos are stored in here indexed by lock ID */ +static DEFINE_IDR(lockinfo_idr); +static rwlock_t lockinfo_lock; + +/* Flags in li_flags */ +#define LI_FLAG_COMPLETE 1 +#define LI_FLAG_FIRSTLOCK 2 +#define LI_FLAG_PERSISTENT 3 + +/* flags in ls_flags*/ +#define LS_FLAG_DELETED 1 +#define LS_FLAG_AUTOFREE 2 + + +#define LOCKINFO_MAGIC 0x53595324 + +struct lock_info { + uint32_t li_magic; + uint8_t li_cmd; + int8_t li_grmode; + int8_t li_rqmode; + struct dlm_lksb li_lksb; + wait_queue_head_t li_waitq; + unsigned long li_flags; + void __user *li_castparam; + void __user *li_castaddr; + void __user *li_bastparam; + void __user *li_bastaddr; + void __user *li_pend_bastparam; + void __user *li_pend_bastaddr; + struct list_head li_ownerqueue; + struct file_info *li_file; + struct dlm_lksb __user *li_user_lksb; + struct semaphore li_firstlock; +}; + +/* A queued AST no less */ +struct ast_info { + struct dlm_lock_result result; + struct list_head list; + uint32_t lvb_updated; + uint32_t progress; /* How much has been read */ +}; + +/* One of these per userland lockspace */ +struct user_ls { + void *ls_lockspace; + atomic_t ls_refcnt; + long ls_flags; + + /* Passed into misc_register() */ + struct miscdevice ls_miscinfo; + struct list_head ls_list; +}; + +/* misc_device info for the control device */ +static struct miscdevice ctl_device; + +/* + * Stuff we hang off the file struct. + * The first two are to cope with unlocking all the + * locks help by a process when it dies. + */ +struct file_info { + struct list_head fi_li_list; /* List of active lock_infos */ + spinlock_t fi_li_lock; + struct list_head fi_ast_list; /* Queue of ASTs to be delivered */ + spinlock_t fi_ast_lock; + wait_queue_head_t fi_wait; + struct user_ls *fi_ls; + atomic_t fi_refcnt; /* Number of users */ + unsigned long fi_flags; /* Bit 1 means the device is open */ +}; + + +/* get and put ops for file_info. + Actually I don't really like "get" and "put", but everyone + else seems to use them and I can't think of anything + nicer at the moment */ +static void get_file_info(struct file_info *f) +{ + atomic_inc(&f->fi_refcnt); +} + +static void put_file_info(struct file_info *f) +{ + if (atomic_dec_and_test(&f->fi_refcnt)) + kfree(f); +} + +static void release_lockinfo(struct lock_info *li) +{ + put_file_info(li->li_file); + + write_lock(&lockinfo_lock); + idr_remove(&lockinfo_idr, li->li_lksb.sb_lkid); + write_unlock(&lockinfo_lock); + + if (li->li_lksb.sb_lvbptr) + kfree(li->li_lksb.sb_lvbptr); + kfree(li); + + module_put(THIS_MODULE); +} + +static struct lock_info *get_lockinfo(uint32_t lockid) +{ + struct lock_info *li; + + read_lock(&lockinfo_lock); + li = idr_find(&lockinfo_idr, lockid); + read_unlock(&lockinfo_lock); + + return li; +} + +static int add_lockinfo(struct lock_info *li) +{ + int n; + int r; + int ret = -EINVAL; + + write_lock(&lockinfo_lock); + + if (idr_find(&lockinfo_idr, li->li_lksb.sb_lkid)) + goto out_up; + + ret = -ENOMEM; + r = idr_pre_get(&lockinfo_idr, GFP_KERNEL); + if (!r) + goto out_up; + + r = idr_get_new_above(&lockinfo_idr, li, li->li_lksb.sb_lkid, &n); + if (r) + goto out_up; + + if (n != li->li_lksb.sb_lkid) { + idr_remove(&lockinfo_idr, n); + goto out_up; + } + + ret = 0; + + out_up: + write_unlock(&lockinfo_lock); + + return ret; +} + + +static struct user_ls *__find_lockspace(int minor) +{ + struct user_ls *lsinfo; + + list_for_each_entry(lsinfo, &user_ls_list, ls_list) { + if (lsinfo->ls_miscinfo.minor == minor) + return lsinfo; + } + return NULL; +} + +/* Find a lockspace struct given the device minor number */ +static struct user_ls *find_lockspace(int minor) +{ + struct user_ls *lsinfo; + + down(&user_ls_lock); + lsinfo = __find_lockspace(minor); + up(&user_ls_lock); + + return lsinfo; +} + +static void add_lockspace_to_list(struct user_ls *lsinfo) +{ + down(&user_ls_lock); + list_add(&lsinfo->ls_list, &user_ls_list); + up(&user_ls_lock); +} + +/* Register a lockspace with the DLM and create a misc + device for userland to access it */ +static int register_lockspace(char *name, struct user_ls **ls, int flags) +{ + struct user_ls *newls; + int status; + int namelen; + + namelen = strlen(name)+strlen(name_prefix)+2; + + newls = kmalloc(sizeof(struct user_ls), GFP_KERNEL); + if (!newls) + return -ENOMEM; + memset(newls, 0, sizeof(struct user_ls)); + + newls->ls_miscinfo.name = kmalloc(namelen, GFP_KERNEL); + if (!newls->ls_miscinfo.name) { + kfree(newls); + return -ENOMEM; + } + + status = dlm_new_lockspace(name, strlen(name), &newls->ls_lockspace, 0, + DLM_USER_LVB_LEN); + if (status != 0) { + kfree(newls->ls_miscinfo.name); + kfree(newls); + return status; + } + + snprintf((char*)newls->ls_miscinfo.name, namelen, "%s_%s", + name_prefix, name); + + newls->ls_miscinfo.fops = &_dlm_fops; + newls->ls_miscinfo.minor = MISC_DYNAMIC_MINOR; + + status = misc_register(&newls->ls_miscinfo); + if (status) { + printk(KERN_ERR "dlm: misc register failed for %s\n", name); + dlm_release_lockspace(newls->ls_lockspace, 0); + kfree(newls->ls_miscinfo.name); + kfree(newls); + return status; + } + + if (flags & DLM_USER_LSFLG_AUTOFREE) + set_bit(LS_FLAG_AUTOFREE, &newls->ls_flags); + + add_lockspace_to_list(newls); + *ls = newls; + return 0; +} + +/* Called with the user_ls_lock semaphore held */ +static int unregister_lockspace(struct user_ls *lsinfo, int force) +{ + int status; + + status = dlm_release_lockspace(lsinfo->ls_lockspace, force); + if (status) + return status; + + status = misc_deregister(&lsinfo->ls_miscinfo); + if (status) + return status; + + list_del(&lsinfo->ls_list); + set_bit(LS_FLAG_DELETED, &lsinfo->ls_flags); + lsinfo->ls_lockspace = NULL; + if (atomic_read(&lsinfo->ls_refcnt) == 0) { + kfree(lsinfo->ls_miscinfo.name); + kfree(lsinfo); + } + + return 0; +} + +/* Add it to userland's AST queue */ +static void add_to_astqueue(struct lock_info *li, void *astaddr, void *astparam, + int lvb_updated) +{ + struct ast_info *ast = kmalloc(sizeof(struct ast_info), GFP_KERNEL); + if (!ast) + return; + + memset(ast, 0, sizeof(*ast)); + ast->result.user_astparam = astparam; + ast->result.user_astaddr = astaddr; + ast->result.user_lksb = li->li_user_lksb; + memcpy(&ast->result.lksb, &li->li_lksb, sizeof(struct dlm_lksb)); + ast->lvb_updated = lvb_updated; + + spin_lock(&li->li_file->fi_ast_lock); + list_add_tail(&ast->list, &li->li_file->fi_ast_list); + spin_unlock(&li->li_file->fi_ast_lock); + wake_up_interruptible(&li->li_file->fi_wait); +} + +static void bast_routine(void *param, int mode) +{ + struct lock_info *li = param; + + if (li && li->li_bastaddr) + add_to_astqueue(li, li->li_bastaddr, li->li_bastparam, 0); +} + +/* + * This is the kernel's AST routine. + * All lock, unlock & query operations complete here. + * The only syncronous ops are those done during device close. + */ +static void ast_routine(void *param) +{ + struct lock_info *li = param; + + /* Param may be NULL if a persistent lock is unlocked by someone else */ + if (!li) + return; + + /* If this is a succesful conversion then activate the blocking ast + * args from the conversion request */ + if (!test_bit(LI_FLAG_FIRSTLOCK, &li->li_flags) && + li->li_lksb.sb_status == 0) { + + li->li_bastparam = li->li_pend_bastparam; + li->li_bastaddr = li->li_pend_bastaddr; + li->li_pend_bastaddr = NULL; + } + + /* If it's an async request then post data to the user's AST queue. */ + if (li->li_castaddr) { + int lvb_updated = 0; + + /* See if the lvb has been updated */ + if (dlm_lvb_operations[li->li_grmode+1][li->li_rqmode+1] == 1) + lvb_updated = 1; + + if (li->li_lksb.sb_status == 0) + li->li_grmode = li->li_rqmode; + + /* Only queue AST if the device is still open */ + if (test_bit(1, &li->li_file->fi_flags)) + add_to_astqueue(li, li->li_castaddr, li->li_castparam, + lvb_updated); + + /* If it's a new lock operation that failed, then + * remove it from the owner queue and free the + * lock_info. + */ + if (test_and_clear_bit(LI_FLAG_FIRSTLOCK, &li->li_flags) && + li->li_lksb.sb_status != 0) { + + /* Wait till dlm_lock() has finished */ + down(&li->li_firstlock); + up(&li->li_firstlock); + + spin_lock(&li->li_file->fi_li_lock); + list_del(&li->li_ownerqueue); + spin_unlock(&li->li_file->fi_li_lock); + release_lockinfo(li); + return; + } + /* Free unlocks & queries */ + if (li->li_lksb.sb_status == -DLM_EUNLOCK || + li->li_cmd == DLM_USER_QUERY) { + release_lockinfo(li); + } + } else { + /* Synchronous request, just wake up the caller */ + set_bit(LI_FLAG_COMPLETE, &li->li_flags); + wake_up_interruptible(&li->li_waitq); + } +} + +/* + * Wait for the lock op to complete and return the status. + */ +static int wait_for_ast(struct lock_info *li) +{ + /* Wait for the AST routine to complete */ + set_task_state(current, TASK_INTERRUPTIBLE); + while (!test_bit(LI_FLAG_COMPLETE, &li->li_flags)) + schedule(); + + set_task_state(current, TASK_RUNNING); + + return li->li_lksb.sb_status; +} + + +/* Open on control device */ +static int dlm_ctl_open(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +/* Close on control device */ +static int dlm_ctl_close(struct inode *inode, struct file *file) +{ + return 0; +} + +/* Open on lockspace device */ +static int dlm_open(struct inode *inode, struct file *file) +{ + struct file_info *f; + struct user_ls *lsinfo; + + lsinfo = find_lockspace(iminor(inode)); + if (!lsinfo) + return -ENOENT; + + f = kmalloc(sizeof(struct file_info), GFP_KERNEL); + if (!f) + return -ENOMEM; + + atomic_inc(&lsinfo->ls_refcnt); + INIT_LIST_HEAD(&f->fi_li_list); + INIT_LIST_HEAD(&f->fi_ast_list); + spin_lock_init(&f->fi_li_lock); + spin_lock_init(&f->fi_ast_lock); + init_waitqueue_head(&f->fi_wait); + f->fi_ls = lsinfo; + f->fi_flags = 0; + get_file_info(f); + set_bit(1, &f->fi_flags); + + file->private_data = f; + + return 0; +} + +/* Check the user's version matches ours */ +static int check_version(struct dlm_write_request *req) +{ + if (req->version[0] != DLM_DEVICE_VERSION_MAJOR || + (req->version[0] == DLM_DEVICE_VERSION_MAJOR && + req->version[1] > DLM_DEVICE_VERSION_MINOR)) { + + printk(KERN_DEBUG "dlm: process %s (%d) version mismatch " + "user (%d.%d.%d) kernel (%d.%d.%d)\n", + current->comm, + current->pid, + req->version[0], + req->version[1], + req->version[2], + DLM_DEVICE_VERSION_MAJOR, + DLM_DEVICE_VERSION_MINOR, + DLM_DEVICE_VERSION_PATCH); + return -EINVAL; + } + return 0; +} + +/* Close on lockspace device */ +static int dlm_close(struct inode *inode, struct file *file) +{ + struct file_info *f = file->private_data; + struct lock_info li; + struct lock_info *old_li, *safe; + sigset_t tmpsig; + sigset_t allsigs; + struct user_ls *lsinfo; + DECLARE_WAITQUEUE(wq, current); + + lsinfo = find_lockspace(iminor(inode)); + if (!lsinfo) + return -ENOENT; + + /* Mark this closed so that ASTs will not be delivered any more */ + clear_bit(1, &f->fi_flags); + + /* Block signals while we are doing this */ + sigfillset(&allsigs); + sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); + + /* We use our own lock_info struct here, so that any + * outstanding "real" ASTs will be delivered with the + * corresponding "real" params, thus freeing the lock_info + * that belongs the lock. This catches the corner case where + * a lock is BUSY when we try to unlock it here + */ + memset(&li, 0, sizeof(li)); + clear_bit(LI_FLAG_COMPLETE, &li.li_flags); + init_waitqueue_head(&li.li_waitq); + add_wait_queue(&li.li_waitq, &wq); + + /* + * Free any outstanding locks, they are on the + * list in LIFO order so there should be no problems + * about unlocking parents before children. + */ + list_for_each_entry_safe(old_li, safe, &f->fi_li_list, li_ownerqueue) { + int status; + int flags = 0; + + /* Don't unlock persistent locks, just mark them orphaned */ + if (test_bit(LI_FLAG_PERSISTENT, &old_li->li_flags)) { + list_del(&old_li->li_ownerqueue); + + /* Update master copy */ + /* TODO: Check locking core updates the local and + remote ORPHAN flags */ + li.li_lksb.sb_lkid = old_li->li_lksb.sb_lkid; + status = dlm_lock(f->fi_ls->ls_lockspace, + old_li->li_grmode, &li.li_lksb, + DLM_LKF_CONVERT|DLM_LKF_ORPHAN, + NULL, 0, 0, ast_routine, NULL, + NULL, NULL); + if (status != 0) + printk("dlm: Error orphaning lock %x: %d\n", + old_li->li_lksb.sb_lkid, status); + + /* But tidy our references in it */ + release_lockinfo(old_li); + continue; + } + + clear_bit(LI_FLAG_COMPLETE, &li.li_flags); + + flags = DLM_LKF_FORCEUNLOCK; + if (old_li->li_grmode >= DLM_LOCK_PW) + flags |= DLM_LKF_IVVALBLK; + + status = dlm_unlock(f->fi_ls->ls_lockspace, + old_li->li_lksb.sb_lkid, flags, + &li.li_lksb, &li); + + /* Must wait for it to complete as the next lock could be its + * parent */ + if (status == 0) + wait_for_ast(&li); + + /* Unlock suceeded, free the lock_info struct. */ + if (status == 0) + release_lockinfo(old_li); + } + + remove_wait_queue(&li.li_waitq, &wq); + + /* + * If this is the last reference to the lockspace + * then free the struct. If it's an AUTOFREE lockspace + * then free the whole thing. + */ + down(&user_ls_lock); + if (atomic_dec_and_test(&lsinfo->ls_refcnt)) { + + if (lsinfo->ls_lockspace) { + if (test_bit(LS_FLAG_AUTOFREE, &lsinfo->ls_flags)) { + unregister_lockspace(lsinfo, 1); + } + } else { + kfree(lsinfo->ls_miscinfo.name); + kfree(lsinfo); + } + } + up(&user_ls_lock); + put_file_info(f); + + /* Restore signals */ + sigprocmask(SIG_SETMASK, &tmpsig, NULL); + recalc_sigpending(); + + return 0; +} + +static int do_user_create_lockspace(struct file_info *fi, uint8_t cmd, + struct dlm_lspace_params *kparams) +{ + int status; + struct user_ls *lsinfo; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + status = register_lockspace(kparams->name, &lsinfo, kparams->flags); + + /* If it succeeded then return the minor number */ + if (status == 0) + status = lsinfo->ls_miscinfo.minor; + + return status; +} + +static int do_user_remove_lockspace(struct file_info *fi, uint8_t cmd, + struct dlm_lspace_params *kparams) +{ + int status; + int force = 1; + struct user_ls *lsinfo; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + down(&user_ls_lock); + lsinfo = __find_lockspace(kparams->minor); + if (!lsinfo) { + up(&user_ls_lock); + return -EINVAL; + } + + if (kparams->flags & DLM_USER_LSFLG_FORCEFREE) + force = 2; + + status = unregister_lockspace(lsinfo, force); + up(&user_ls_lock); + + return status; +} + +/* Read call, might block if no ASTs are waiting. + * It will only ever return one message at a time, regardless + * of how many are pending. + */ +static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, + loff_t *ppos) +{ + struct file_info *fi = file->private_data; + struct ast_info *ast; + int data_size; + int offset; + DECLARE_WAITQUEUE(wait, current); + + if (count < sizeof(struct dlm_lock_result)) + return -EINVAL; + + spin_lock(&fi->fi_ast_lock); + if (list_empty(&fi->fi_ast_list)) { + + /* No waiting ASTs. + * Return EOF if the lockspace been deleted. + */ + if (test_bit(LS_FLAG_DELETED, &fi->fi_ls->ls_flags)) + return 0; + + if (file->f_flags & O_NONBLOCK) { + spin_unlock(&fi->fi_ast_lock); + return -EAGAIN; + } + + add_wait_queue(&fi->fi_wait, &wait); + + repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (list_empty(&fi->fi_ast_list) && + !signal_pending(current)) { + + spin_unlock(&fi->fi_ast_lock); + schedule(); + spin_lock(&fi->fi_ast_lock); + goto repeat; + } + + current->state = TASK_RUNNING; + remove_wait_queue(&fi->fi_wait, &wait); + + if (signal_pending(current)) { + spin_unlock(&fi->fi_ast_lock); + return -ERESTARTSYS; + } + } + + ast = list_entry(fi->fi_ast_list.next, struct ast_info, list); + list_del(&ast->list); + spin_unlock(&fi->fi_ast_lock); + + /* Work out the size of the returned data */ + data_size = sizeof(struct dlm_lock_result); + if (ast->lvb_updated && ast->result.lksb.sb_lvbptr) + data_size += DLM_USER_LVB_LEN; + + offset = sizeof(struct dlm_lock_result); + + /* Room for the extended data ? */ + if (count >= data_size) { + + if (ast->lvb_updated && ast->result.lksb.sb_lvbptr) { + if (copy_to_user(buffer+offset, + ast->result.lksb.sb_lvbptr, + DLM_USER_LVB_LEN)) + return -EFAULT; + ast->result.lvb_offset = offset; + offset += DLM_USER_LVB_LEN; + } + } + + ast->result.length = data_size; + /* Copy the header now it has all the offsets in it */ + if (copy_to_user(buffer, &ast->result, sizeof(struct dlm_lock_result))) + offset = -EFAULT; + + /* If we only returned a header and there's more to come then put it + back on the list */ + if (count < data_size) { + spin_lock(&fi->fi_ast_lock); + list_add(&ast->list, &fi->fi_ast_list); + spin_unlock(&fi->fi_ast_lock); + } else + kfree(ast); + return offset; +} + +static unsigned int dlm_poll(struct file *file, poll_table *wait) +{ + struct file_info *fi = file->private_data; + + poll_wait(file, &fi->fi_wait, wait); + + spin_lock(&fi->fi_ast_lock); + if (!list_empty(&fi->fi_ast_list)) { + spin_unlock(&fi->fi_ast_lock); + return POLLIN | POLLRDNORM; + } + + spin_unlock(&fi->fi_ast_lock); + return 0; +} + +static struct lock_info *allocate_lockinfo(struct file_info *fi, uint8_t cmd, + struct dlm_lock_params *kparams) +{ + struct lock_info *li; + + if (!try_module_get(THIS_MODULE)) + return NULL; + + li = kmalloc(sizeof(struct lock_info), GFP_KERNEL); + if (li) { + li->li_magic = LOCKINFO_MAGIC; + li->li_file = fi; + li->li_cmd = cmd; + li->li_flags = 0; + li->li_grmode = -1; + li->li_rqmode = -1; + li->li_pend_bastparam = NULL; + li->li_pend_bastaddr = NULL; + li->li_castaddr = NULL; + li->li_castparam = NULL; + li->li_lksb.sb_lvbptr = NULL; + li->li_bastaddr = kparams->bastaddr; + li->li_bastparam = kparams->bastparam; + + get_file_info(fi); + } + return li; +} + +static int do_user_lock(struct file_info *fi, uint8_t cmd, + struct dlm_lock_params *kparams) +{ + struct lock_info *li; + int status; + + /* + * Validate things that we need to have correct. + */ + if (!kparams->castaddr) + return -EINVAL; + + if (!kparams->lksb) + return -EINVAL; + + /* Persistent child locks are not available yet */ + if ((kparams->flags & DLM_LKF_PERSISTENT) && kparams->parent) + return -EINVAL; + + /* For conversions, there should already be a lockinfo struct, + unless we are adopting an orphaned persistent lock */ + if (kparams->flags & DLM_LKF_CONVERT) { + + li = get_lockinfo(kparams->lkid); + + /* If this is a persistent lock we will have to create a + lockinfo again */ + if (!li && DLM_LKF_PERSISTENT) { + li = allocate_lockinfo(fi, cmd, kparams); + + li->li_lksb.sb_lkid = kparams->lkid; + li->li_castaddr = kparams->castaddr; + li->li_castparam = kparams->castparam; + + /* OK, this isn;t exactly a FIRSTLOCK but it is the + first time we've used this lockinfo, and if things + fail we want rid of it */ + init_MUTEX_LOCKED(&li->li_firstlock); + set_bit(LI_FLAG_FIRSTLOCK, &li->li_flags); + add_lockinfo(li); + + /* TODO: do a query to get the current state ?? */ + } + if (!li) + return -EINVAL; + + if (li->li_magic != LOCKINFO_MAGIC) + return -EINVAL; + + /* For conversions don't overwrite the current blocking AST + info so that: + a) if a blocking AST fires before the conversion is queued + it runs the current handler + b) if the conversion is cancelled, the original blocking AST + declaration is active + The pend_ info is made active when the conversion + completes. + */ + li->li_pend_bastaddr = kparams->bastaddr; + li->li_pend_bastparam = kparams->bastparam; + } else { + li = allocate_lockinfo(fi, cmd, kparams); + if (!li) + return -ENOMEM; + + /* semaphore to allow us to complete our work before + the AST routine runs. In fact we only need (and use) this + when the initial lock fails */ + init_MUTEX_LOCKED(&li->li_firstlock); + set_bit(LI_FLAG_FIRSTLOCK, &li->li_flags); + } + + li->li_user_lksb = kparams->lksb; + li->li_castaddr = kparams->castaddr; + li->li_castparam = kparams->castparam; + li->li_lksb.sb_lkid = kparams->lkid; + li->li_rqmode = kparams->mode; + if (kparams->flags & DLM_LKF_PERSISTENT) + set_bit(LI_FLAG_PERSISTENT, &li->li_flags); + + /* Copy in the value block */ + if (kparams->flags & DLM_LKF_VALBLK) { + if (!li->li_lksb.sb_lvbptr) { + li->li_lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, + GFP_KERNEL); + if (!li->li_lksb.sb_lvbptr) { + status = -ENOMEM; + goto out_err; + } + } + + memcpy(li->li_lksb.sb_lvbptr, kparams->lvb, DLM_USER_LVB_LEN); + } + + /* Lock it ... */ + status = dlm_lock(fi->fi_ls->ls_lockspace, + kparams->mode, &li->li_lksb, + kparams->flags, + kparams->name, kparams->namelen, + kparams->parent, + ast_routine, + li, + (li->li_pend_bastaddr || li->li_bastaddr) ? + bast_routine : NULL, + kparams->range.ra_end ? &kparams->range : NULL); + if (status) + goto out_err; + + /* If it succeeded (this far) with a new lock then keep track of + it on the file's lockinfo list */ + if (!status && test_bit(LI_FLAG_FIRSTLOCK, &li->li_flags)) { + + spin_lock(&fi->fi_li_lock); + list_add(&li->li_ownerqueue, &fi->fi_li_list); + spin_unlock(&fi->fi_li_lock); + if (add_lockinfo(li)) + printk(KERN_WARNING "Add lockinfo failed\n"); + + up(&li->li_firstlock); + } + + /* Return the lockid as the user needs it /now/ */ + return li->li_lksb.sb_lkid; + + out_err: + if (test_bit(LI_FLAG_FIRSTLOCK, &li->li_flags)) + release_lockinfo(li); + return status; + +} + +static int do_user_unlock(struct file_info *fi, uint8_t cmd, + struct dlm_lock_params *kparams) +{ + struct lock_info *li; + int status; + int convert_cancel = 0; + + li = get_lockinfo(kparams->lkid); + if (!li) { + li = allocate_lockinfo(fi, cmd, kparams); + spin_lock(&fi->fi_li_lock); + list_add(&li->li_ownerqueue, &fi->fi_li_list); + spin_unlock(&fi->fi_li_lock); + } + if (!li) + return -ENOMEM; + + if (li->li_magic != LOCKINFO_MAGIC) + return -EINVAL; + + li->li_user_lksb = kparams->lksb; + li->li_castparam = kparams->castparam; + li->li_cmd = cmd; + + /* Cancelling a conversion doesn't remove the lock...*/ + if (kparams->flags & DLM_LKF_CANCEL && li->li_grmode != -1) + convert_cancel = 1; + + /* dlm_unlock() passes a 0 for castaddr which means don't overwrite + the existing li_castaddr as that's the completion routine for + unlocks. dlm_unlock_wait() specifies a new AST routine to be + executed when the unlock completes. */ + if (kparams->castaddr) + li->li_castaddr = kparams->castaddr; + + /* Use existing lksb & astparams */ + status = dlm_unlock(fi->fi_ls->ls_lockspace, + kparams->lkid, + kparams->flags, &li->li_lksb, li); + + if (!status && !convert_cancel) { + spin_lock(&fi->fi_li_lock); + list_del(&li->li_ownerqueue); + spin_unlock(&fi->fi_li_lock); + } + + return status; +} + +/* Write call, submit a locking request */ +static ssize_t dlm_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct file_info *fi = file->private_data; + struct dlm_write_request *kparams; + sigset_t tmpsig; + sigset_t allsigs; + int status; + + /* -1 because lock name is optional */ + if (count < sizeof(struct dlm_write_request)-1) + return -EINVAL; + + /* Has the lockspace been deleted */ + if (fi && test_bit(LS_FLAG_DELETED, &fi->fi_ls->ls_flags)) + return -ENOENT; + + kparams = kmalloc(count, GFP_KERNEL); + if (!kparams) + return -ENOMEM; + + status = -EFAULT; + /* Get the command info */ + if (copy_from_user(kparams, buffer, count)) + goto out_free; + + status = -EBADE; + if (check_version(kparams)) + goto out_free; + + /* Block signals while we are doing this */ + sigfillset(&allsigs); + sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); + + status = -EINVAL; + switch (kparams->cmd) + { + case DLM_USER_LOCK: + if (!fi) goto out_sig; + status = do_user_lock(fi, kparams->cmd, &kparams->i.lock); + break; + + case DLM_USER_UNLOCK: + if (!fi) goto out_sig; + status = do_user_unlock(fi, kparams->cmd, &kparams->i.lock); + break; + + case DLM_USER_CREATE_LOCKSPACE: + if (fi) goto out_sig; + status = do_user_create_lockspace(fi, kparams->cmd, + &kparams->i.lspace); + break; + + case DLM_USER_REMOVE_LOCKSPACE: + if (fi) goto out_sig; + status = do_user_remove_lockspace(fi, kparams->cmd, + &kparams->i.lspace); + break; + default: + printk("Unknown command passed to DLM device : %d\n", + kparams->cmd); + break; + } + + out_sig: + /* Restore signals */ + sigprocmask(SIG_SETMASK, &tmpsig, NULL); + recalc_sigpending(); + + out_free: + kfree(kparams); + if (status == 0) + return count; + else + return status; +} + +static struct file_operations _dlm_fops = { + .open = dlm_open, + .release = dlm_close, + .read = dlm_read, + .write = dlm_write, + .poll = dlm_poll, + .owner = THIS_MODULE, +}; + +static struct file_operations _dlm_ctl_fops = { + .open = dlm_ctl_open, + .release = dlm_ctl_close, + .write = dlm_write, + .owner = THIS_MODULE, +}; + +/* + * Create control device + */ +static int __init dlm_device_init(void) +{ + int r; + + INIT_LIST_HEAD(&user_ls_list); + init_MUTEX(&user_ls_lock); + rwlock_init(&lockinfo_lock); + + ctl_device.name = "dlm-control"; + ctl_device.fops = &_dlm_ctl_fops; + ctl_device.minor = MISC_DYNAMIC_MINOR; + + r = misc_register(&ctl_device); + if (r) { + printk(KERN_ERR "dlm: misc_register failed for control dev\n"); + return r; + } + + return 0; +} + +static void __exit dlm_device_exit(void) +{ + misc_deregister(&ctl_device); +} + +MODULE_DESCRIPTION("Distributed Lock Manager device interface"); +MODULE_AUTHOR("Red Hat, Inc."); +MODULE_LICENSE("GPL"); + +module_init(dlm_device_init); +module_exit(dlm_device_exit); diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c new file mode 100644 index 000000000000..0f1dde54bcd2 --- /dev/null +++ b/fs/dlm/dir.c @@ -0,0 +1,423 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "lockspace.h" +#include "member.h" +#include "lowcomms.h" +#include "rcom.h" +#include "config.h" +#include "memory.h" +#include "recover.h" +#include "util.h" +#include "lock.h" +#include "dir.h" + + +static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de) +{ + spin_lock(&ls->ls_recover_list_lock); + list_add(&de->list, &ls->ls_recover_list); + spin_unlock(&ls->ls_recover_list_lock); +} + +static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len) +{ + int found = FALSE; + struct dlm_direntry *de; + + spin_lock(&ls->ls_recover_list_lock); + list_for_each_entry(de, &ls->ls_recover_list, list) { + if (de->length == len) { + list_del(&de->list); + de->master_nodeid = 0; + memset(de->name, 0, len); + found = TRUE; + break; + } + } + spin_unlock(&ls->ls_recover_list_lock); + + if (!found) + de = allocate_direntry(ls, len); + return de; +} + +void dlm_clear_free_entries(struct dlm_ls *ls) +{ + struct dlm_direntry *de; + + spin_lock(&ls->ls_recover_list_lock); + while (!list_empty(&ls->ls_recover_list)) { + de = list_entry(ls->ls_recover_list.next, struct dlm_direntry, + list); + list_del(&de->list); + free_direntry(de); + } + spin_unlock(&ls->ls_recover_list_lock); +} + +/* + * We use the upper 16 bits of the hash value to select the directory node. + * Low bits are used for distribution of rsb's among hash buckets on each node. + * + * To give the exact range wanted (0 to num_nodes-1), we apply a modulus of + * num_nodes to the hash value. This value in the desired range is used as an + * offset into the sorted list of nodeid's to give the particular nodeid. + */ + +int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash) +{ + struct list_head *tmp; + struct dlm_member *memb = NULL; + uint32_t node, n = 0; + int nodeid; + + if (ls->ls_num_nodes == 1) { + nodeid = dlm_our_nodeid(); + goto out; + } + + if (ls->ls_node_array) { + node = (hash >> 16) % ls->ls_total_weight; + nodeid = ls->ls_node_array[node]; + goto out; + } + + /* make_member_array() failed to kmalloc ls_node_array... */ + + node = (hash >> 16) % ls->ls_num_nodes; + + list_for_each(tmp, &ls->ls_nodes) { + if (n++ != node) + continue; + memb = list_entry(tmp, struct dlm_member, list); + break; + } + + DLM_ASSERT(memb , printk("num_nodes=%u n=%u node=%u\n", + ls->ls_num_nodes, n, node);); + nodeid = memb->nodeid; + out: + return nodeid; +} + +int dlm_dir_nodeid(struct dlm_rsb *r) +{ + return dlm_hash2nodeid(r->res_ls, r->res_hash); +} + +static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len) +{ + uint32_t val; + + val = jhash(name, len, 0); + val &= (ls->ls_dirtbl_size - 1); + + return val; +} + +static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de) +{ + uint32_t bucket; + + bucket = dir_hash(ls, de->name, de->length); + list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); +} + +static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name, + int namelen, uint32_t bucket) +{ + struct dlm_direntry *de; + + list_for_each_entry(de, &ls->ls_dirtbl[bucket].list, list) { + if (de->length == namelen && !memcmp(name, de->name, namelen)) + goto out; + } + de = NULL; + out: + return de; +} + +void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen) +{ + struct dlm_direntry *de; + uint32_t bucket; + + bucket = dir_hash(ls, name, namelen); + + write_lock(&ls->ls_dirtbl[bucket].lock); + + de = search_bucket(ls, name, namelen, bucket); + + if (!de) { + log_error(ls, "remove fr %u none", nodeid); + goto out; + } + + if (de->master_nodeid != nodeid) { + log_error(ls, "remove fr %u ID %u", nodeid, de->master_nodeid); + goto out; + } + + list_del(&de->list); + free_direntry(de); + out: + write_unlock(&ls->ls_dirtbl[bucket].lock); +} + +void dlm_dir_clear(struct dlm_ls *ls) +{ + struct list_head *head; + struct dlm_direntry *de; + int i; + + DLM_ASSERT(list_empty(&ls->ls_recover_list), ); + + for (i = 0; i < ls->ls_dirtbl_size; i++) { + write_lock(&ls->ls_dirtbl[i].lock); + head = &ls->ls_dirtbl[i].list; + while (!list_empty(head)) { + de = list_entry(head->next, struct dlm_direntry, list); + list_del(&de->list); + put_free_de(ls, de); + } + write_unlock(&ls->ls_dirtbl[i].lock); + } +} + +int dlm_recover_directory(struct dlm_ls *ls) +{ + struct dlm_member *memb; + struct dlm_direntry *de; + char *b, *last_name = NULL; + int error = -ENOMEM, last_len, count = 0; + uint16_t namelen; + + log_debug(ls, "dlm_recover_directory"); + + if (dlm_no_directory(ls)) + goto out_status; + + dlm_dir_clear(ls); + + last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL); + if (!last_name) + goto out; + + list_for_each_entry(memb, &ls->ls_nodes, list) { + memset(last_name, 0, DLM_RESNAME_MAXLEN); + last_len = 0; + + for (;;) { + error = dlm_recovery_stopped(ls); + if (error) + goto out_free; + + error = dlm_rcom_names(ls, memb->nodeid, + last_name, last_len); + if (error) + goto out_free; + + schedule(); + + /* + * pick namelen/name pairs out of received buffer + */ + + b = ls->ls_recover_buf + sizeof(struct dlm_rcom); + + for (;;) { + memcpy(&namelen, b, sizeof(uint16_t)); + namelen = be16_to_cpu(namelen); + b += sizeof(uint16_t); + + /* namelen of 0xFFFFF marks end of names for + this node; namelen of 0 marks end of the + buffer */ + + if (namelen == 0xFFFF) + goto done; + if (!namelen) + break; + + error = -ENOMEM; + de = get_free_de(ls, namelen); + if (!de) + goto out_free; + + de->master_nodeid = memb->nodeid; + de->length = namelen; + last_len = namelen; + memcpy(de->name, b, namelen); + memcpy(last_name, b, namelen); + b += namelen; + + add_entry_to_hash(ls, de); + count++; + } + } + done: + ; + } + + out_status: + error = 0; + dlm_set_recover_status(ls, DLM_RS_DIR); + log_debug(ls, "dlm_recover_directory %d entries", count); + out_free: + kfree(last_name); + out: + dlm_clear_free_entries(ls); + return error; +} + +static int get_entry(struct dlm_ls *ls, int nodeid, char *name, + int namelen, int *r_nodeid) +{ + struct dlm_direntry *de, *tmp; + uint32_t bucket; + + bucket = dir_hash(ls, name, namelen); + + write_lock(&ls->ls_dirtbl[bucket].lock); + de = search_bucket(ls, name, namelen, bucket); + if (de) { + *r_nodeid = de->master_nodeid; + write_unlock(&ls->ls_dirtbl[bucket].lock); + if (*r_nodeid == nodeid) + return -EEXIST; + return 0; + } + + write_unlock(&ls->ls_dirtbl[bucket].lock); + + de = allocate_direntry(ls, namelen); + if (!de) + return -ENOMEM; + + de->master_nodeid = nodeid; + de->length = namelen; + memcpy(de->name, name, namelen); + + write_lock(&ls->ls_dirtbl[bucket].lock); + tmp = search_bucket(ls, name, namelen, bucket); + if (tmp) { + free_direntry(de); + de = tmp; + } else { + list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); + } + *r_nodeid = de->master_nodeid; + write_unlock(&ls->ls_dirtbl[bucket].lock); + return 0; +} + +int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen, + int *r_nodeid) +{ + return get_entry(ls, nodeid, name, namelen, r_nodeid); +} + +/* Copy the names of master rsb's into the buffer provided. + Only select names whose dir node is the given nodeid. */ + +void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, + char *outbuf, int outlen, int nodeid) +{ + struct list_head *list; + struct dlm_rsb *start_r = NULL, *r = NULL; + int offset = 0, start_namelen, error, dir_nodeid; + char *start_name; + uint16_t be_namelen; + + /* + * Find the rsb where we left off (or start again) + */ + + start_namelen = inlen; + start_name = inbuf; + + if (start_namelen > 1) { + /* + * We could also use a find_rsb_root() function here that + * searched the ls_root_list. + */ + error = dlm_find_rsb(ls, start_name, start_namelen, R_MASTER, + &start_r); + DLM_ASSERT(!error && start_r, + printk("error %d\n", error);); + DLM_ASSERT(!list_empty(&start_r->res_root_list), + dlm_print_rsb(start_r);); + dlm_put_rsb(start_r); + } + + /* + * Send rsb names for rsb's we're master of and whose directory node + * matches the requesting node. + */ + + down_read(&ls->ls_root_sem); + if (start_r) + list = start_r->res_root_list.next; + else + list = ls->ls_root_list.next; + + for (offset = 0; list != &ls->ls_root_list; list = list->next) { + r = list_entry(list, struct dlm_rsb, res_root_list); + if (r->res_nodeid) + continue; + + dir_nodeid = dlm_dir_nodeid(r); + if (dir_nodeid != nodeid) + continue; + + /* + * The block ends when we can't fit the following in the + * remaining buffer space: + * namelen (uint16_t) + + * name (r->res_length) + + * end-of-block record 0x0000 (uint16_t) + */ + + if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) { + /* Write end-of-block record */ + be_namelen = 0; + memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t)); + offset += sizeof(uint16_t); + goto out; + } + + be_namelen = cpu_to_be16(r->res_length); + memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t)); + offset += sizeof(uint16_t); + memcpy(outbuf + offset, r->res_name, r->res_length); + offset += r->res_length; + } + + /* + * If we've reached the end of the list (and there's room) write a + * terminating record. + */ + + if ((list == &ls->ls_root_list) && + (offset + sizeof(uint16_t) <= outlen)) { + be_namelen = 0xFFFF; + memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t)); + offset += sizeof(uint16_t); + } + + out: + up_read(&ls->ls_root_sem); +} + diff --git a/fs/dlm/dir.h b/fs/dlm/dir.h new file mode 100644 index 000000000000..0b0eb1267b6e --- /dev/null +++ b/fs/dlm/dir.h @@ -0,0 +1,30 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __DIR_DOT_H__ +#define __DIR_DOT_H__ + + +int dlm_dir_nodeid(struct dlm_rsb *rsb); +int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash); +void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int len); +void dlm_dir_clear(struct dlm_ls *ls); +void dlm_clear_free_entries(struct dlm_ls *ls); +int dlm_recover_directory(struct dlm_ls *ls); +int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen, + int *r_nodeid); +void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, + char *outbuf, int outlen, int nodeid); + +#endif /* __DIR_DOT_H__ */ + diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h new file mode 100644 index 000000000000..0020cd07baf7 --- /dev/null +++ b/fs/dlm/dlm_internal.h @@ -0,0 +1,518 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __DLM_INTERNAL_DOT_H__ +#define __DLM_INTERNAL_DOT_H__ + +/* + * This is the main header file to be included in each DLM source file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DLM_LOCKSPACE_LEN 64 + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#if (BITS_PER_LONG == 64) +#define PRIx64 "lx" +#else +#define PRIx64 "Lx" +#endif + +/* Size of the temp buffer midcomms allocates on the stack. + We try to make this large enough so most messages fit. + FIXME: should sctp make this unnecessary? */ + +#define DLM_INBUF_LEN 148 + +struct dlm_ls; +struct dlm_lkb; +struct dlm_rsb; +struct dlm_member; +struct dlm_lkbtable; +struct dlm_rsbtable; +struct dlm_dirtable; +struct dlm_direntry; +struct dlm_recover; +struct dlm_header; +struct dlm_message; +struct dlm_rcom; +struct dlm_mhandle; + +#define log_print(fmt, args...) \ + printk(KERN_ERR "dlm: "fmt"\n" , ##args) +#define log_error(ls, fmt, args...) \ + printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args) + +#ifdef DLM_LOG_DEBUG +#define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args) +#else +#define log_debug(ls, fmt, args...) +#endif + +#define DLM_ASSERT(x, do) \ +{ \ + if (!(x)) \ + { \ + printk(KERN_ERR "\nDLM: Assertion failed on line %d of file %s\n" \ + "DLM: assertion: \"%s\"\n" \ + "DLM: time = %lu\n", \ + __LINE__, __FILE__, #x, jiffies); \ + {do} \ + printk("\n"); \ + BUG(); \ + panic("DLM: Record message above and reboot.\n"); \ + } \ +} + + +struct dlm_direntry { + struct list_head list; + uint32_t master_nodeid; + uint16_t length; + char name[1]; +}; + +struct dlm_dirtable { + struct list_head list; + rwlock_t lock; +}; + +struct dlm_rsbtable { + struct list_head list; + struct list_head toss; + rwlock_t lock; +}; + +struct dlm_lkbtable { + struct list_head list; + rwlock_t lock; + uint16_t counter; +}; + +/* + * Lockspace member (per node in a ls) + */ + +struct dlm_member { + struct list_head list; + int nodeid; + int weight; +}; + +/* + * Save and manage recovery state for a lockspace. + */ + +struct dlm_recover { + struct list_head list; + int *nodeids; + int node_count; + uint64_t seq; +}; + +/* + * Pass input args to second stage locking function. + */ + +struct dlm_args { + uint32_t flags; + void *astaddr; + long astparam; + void *bastaddr; + int mode; + struct dlm_lksb *lksb; + struct dlm_range *range; +}; + + +/* + * Lock block + * + * A lock can be one of three types: + * + * local copy lock is mastered locally + * (lkb_nodeid is zero and DLM_LKF_MSTCPY is not set) + * process copy lock is mastered on a remote node + * (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is not set) + * master copy master node's copy of a lock owned by remote node + * (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is set) + * + * lkb_exflags: a copy of the most recent flags arg provided to dlm_lock or + * dlm_unlock. The dlm does not modify these or use any private flags in + * this field; it only contains DLM_LKF_ flags from dlm.h. These flags + * are sent as-is to the remote master when the lock is remote. + * + * lkb_flags: internal dlm flags (DLM_IFL_ prefix) from dlm_internal.h. + * Some internal flags are shared between the master and process nodes; + * these shared flags are kept in the lower two bytes. One of these + * flags set on the master copy will be propagated to the process copy + * and v.v. Other internal flags are private to the master or process + * node (e.g. DLM_IFL_MSTCPY). These are kept in the high two bytes. + * + * lkb_sbflags: status block flags. These flags are copied directly into + * the caller's lksb.sb_flags prior to the dlm_lock/dlm_unlock completion + * ast. All defined in dlm.h with DLM_SBF_ prefix. + * + * lkb_status: the lock status indicates which rsb queue the lock is + * on, grant, convert, or wait. DLM_LKSTS_ WAITING/GRANTED/CONVERT + * + * lkb_wait_type: the dlm message type (DLM_MSG_ prefix) for which a + * reply is needed. Only set when the lkb is on the lockspace waiters + * list awaiting a reply from a remote node. + * + * lkb_nodeid: when the lkb is a local copy, nodeid is 0; when the lkb + * is a master copy, nodeid specifies the remote lock holder, when the + * lkb is a process copy, the nodeid specifies the lock master. + */ + +/* lkb_ast_type */ + +#define AST_COMP 1 +#define AST_BAST 2 + +/* lkb_range[] */ + +#define GR_RANGE_START 0 +#define GR_RANGE_END 1 +#define RQ_RANGE_START 2 +#define RQ_RANGE_END 3 + +/* lkb_status */ + +#define DLM_LKSTS_WAITING 1 +#define DLM_LKSTS_GRANTED 2 +#define DLM_LKSTS_CONVERT 3 + +/* lkb_flags */ + +#define DLM_IFL_MSTCPY 0x00010000 +#define DLM_IFL_RESEND 0x00020000 +#define DLM_IFL_RANGE 0x00000001 + +struct dlm_lkb { + struct dlm_rsb *lkb_resource; /* the rsb */ + struct kref lkb_ref; + int lkb_nodeid; /* copied from rsb */ + int lkb_ownpid; /* pid of lock owner */ + uint32_t lkb_id; /* our lock ID */ + uint32_t lkb_remid; /* lock ID on remote partner */ + uint32_t lkb_exflags; /* external flags from caller */ + uint32_t lkb_sbflags; /* lksb flags */ + uint32_t lkb_flags; /* internal flags */ + uint32_t lkb_lvbseq; /* lvb sequence number */ + + int8_t lkb_status; /* granted, waiting, convert */ + int8_t lkb_rqmode; /* requested lock mode */ + int8_t lkb_grmode; /* granted lock mode */ + int8_t lkb_bastmode; /* requested mode */ + int8_t lkb_highbast; /* highest mode bast sent for */ + + int8_t lkb_wait_type; /* type of reply waiting for */ + int8_t lkb_ast_type; /* type of ast queued for */ + + struct list_head lkb_idtbl_list; /* lockspace lkbtbl */ + struct list_head lkb_statequeue; /* rsb g/c/w list */ + struct list_head lkb_rsb_lookup; /* waiting for rsb lookup */ + struct list_head lkb_wait_reply; /* waiting for remote reply */ + struct list_head lkb_astqueue; /* need ast to be sent */ + + uint64_t *lkb_range; /* array of gr/rq ranges */ + char *lkb_lvbptr; + struct dlm_lksb *lkb_lksb; /* caller's status block */ + void *lkb_astaddr; /* caller's ast function */ + void *lkb_bastaddr; /* caller's bast function */ + long lkb_astparam; /* caller's ast arg */ +}; + + +struct dlm_rsb { + struct dlm_ls *res_ls; /* the lockspace */ + struct kref res_ref; + struct semaphore res_sem; + unsigned long res_flags; + int res_length; /* length of rsb name */ + int res_nodeid; + uint32_t res_lvbseq; + uint32_t res_hash; + uint32_t res_bucket; /* rsbtbl */ + unsigned long res_toss_time; + uint32_t res_first_lkid; + struct list_head res_lookup; /* lkbs waiting on first */ + struct list_head res_hashchain; /* rsbtbl */ + struct list_head res_grantqueue; + struct list_head res_convertqueue; + struct list_head res_waitqueue; + + struct list_head res_root_list; /* used for recovery */ + struct list_head res_recover_list; /* used for recovery */ + int res_recover_locks_count; + + char *res_lvbptr; + char res_name[1]; +}; + +/* find_rsb() flags */ + +#define R_MASTER 1 /* only return rsb if it's a master */ +#define R_CREATE 2 /* create/add rsb if not found */ + +/* rsb_flags */ + +enum rsb_flags { + RSB_MASTER_UNCERTAIN, + RSB_VALNOTVALID, + RSB_VALNOTVALID_PREV, + RSB_NEW_MASTER, + RSB_NEW_MASTER2, + RSB_RECOVER_CONVERT, +}; + +static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag) +{ + __set_bit(flag, &r->res_flags); +} + +static inline void rsb_clear_flag(struct dlm_rsb *r, enum rsb_flags flag) +{ + __clear_bit(flag, &r->res_flags); +} + +static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag) +{ + return test_bit(flag, &r->res_flags); +} + + +/* dlm_header is first element of all structs sent between nodes */ + +#define DLM_HEADER_MAJOR 0x00020000 +#define DLM_HEADER_MINOR 0x00000001 + +#define DLM_MSG 1 +#define DLM_RCOM 2 + +struct dlm_header { + uint32_t h_version; + uint32_t h_lockspace; + uint32_t h_nodeid; /* nodeid of sender */ + uint16_t h_length; + uint8_t h_cmd; /* DLM_MSG, DLM_RCOM */ + uint8_t h_pad; +}; + + +#define DLM_MSG_REQUEST 1 +#define DLM_MSG_CONVERT 2 +#define DLM_MSG_UNLOCK 3 +#define DLM_MSG_CANCEL 4 +#define DLM_MSG_REQUEST_REPLY 5 +#define DLM_MSG_CONVERT_REPLY 6 +#define DLM_MSG_UNLOCK_REPLY 7 +#define DLM_MSG_CANCEL_REPLY 8 +#define DLM_MSG_GRANT 9 +#define DLM_MSG_BAST 10 +#define DLM_MSG_LOOKUP 11 +#define DLM_MSG_REMOVE 12 +#define DLM_MSG_LOOKUP_REPLY 13 + +struct dlm_message { + struct dlm_header m_header; + uint32_t m_type; /* DLM_MSG_ */ + uint32_t m_nodeid; + uint32_t m_pid; + uint32_t m_lkid; /* lkid on sender */ + uint32_t m_remid; /* lkid on receiver */ + uint32_t m_parent_lkid; + uint32_t m_parent_remid; + uint32_t m_exflags; + uint32_t m_sbflags; + uint32_t m_flags; + uint32_t m_lvbseq; + uint32_t m_hash; + int m_status; + int m_grmode; + int m_rqmode; + int m_bastmode; + int m_asts; + int m_result; /* 0 or -EXXX */ + uint64_t m_range[2]; + char m_extra[0]; /* name or lvb */ +}; + + +#define DLM_RS_NODES 0x00000001 +#define DLM_RS_NODES_ALL 0x00000002 +#define DLM_RS_DIR 0x00000004 +#define DLM_RS_DIR_ALL 0x00000008 +#define DLM_RS_LOCKS 0x00000010 +#define DLM_RS_LOCKS_ALL 0x00000020 +#define DLM_RS_DONE 0x00000040 +#define DLM_RS_DONE_ALL 0x00000080 + +#define DLM_RCOM_STATUS 1 +#define DLM_RCOM_NAMES 2 +#define DLM_RCOM_LOOKUP 3 +#define DLM_RCOM_LOCK 4 +#define DLM_RCOM_STATUS_REPLY 5 +#define DLM_RCOM_NAMES_REPLY 6 +#define DLM_RCOM_LOOKUP_REPLY 7 +#define DLM_RCOM_LOCK_REPLY 8 + +struct dlm_rcom { + struct dlm_header rc_header; + uint32_t rc_type; /* DLM_RCOM_ */ + int rc_result; /* multi-purpose */ + uint64_t rc_id; /* match reply with request */ + char rc_buf[0]; +}; + +struct rcom_config { + uint32_t rf_lvblen; + uint32_t rf_lsflags; + uint64_t rf_unused; +}; + +struct rcom_lock { + uint32_t rl_ownpid; + uint32_t rl_lkid; + uint32_t rl_remid; + uint32_t rl_parent_lkid; + uint32_t rl_parent_remid; + uint32_t rl_exflags; + uint32_t rl_flags; + uint32_t rl_lvbseq; + int rl_result; + int8_t rl_rqmode; + int8_t rl_grmode; + int8_t rl_status; + int8_t rl_asts; + uint16_t rl_wait_type; + uint16_t rl_namelen; + uint64_t rl_range[4]; + char rl_name[DLM_RESNAME_MAXLEN]; + char rl_lvb[0]; +}; + +struct dlm_ls { + struct list_head ls_list; /* list of lockspaces */ + uint32_t ls_global_id; /* global unique lockspace ID */ + uint32_t ls_exflags; + int ls_lvblen; + int ls_count; /* reference count */ + unsigned long ls_flags; /* LSFL_ */ + struct kobject ls_kobj; + + struct dlm_rsbtable *ls_rsbtbl; + uint32_t ls_rsbtbl_size; + + struct dlm_lkbtable *ls_lkbtbl; + uint32_t ls_lkbtbl_size; + + struct dlm_dirtable *ls_dirtbl; + uint32_t ls_dirtbl_size; + + struct semaphore ls_waiters_sem; + struct list_head ls_waiters; /* lkbs needing a reply */ + + struct list_head ls_nodes; /* current nodes in ls */ + struct list_head ls_nodes_gone; /* dead node list, recovery */ + int ls_num_nodes; /* number of nodes in ls */ + int ls_low_nodeid; + int ls_total_weight; + int *ls_node_array; + + struct dlm_rsb ls_stub_rsb; /* for returning errors */ + struct dlm_lkb ls_stub_lkb; /* for returning errors */ + struct dlm_message ls_stub_ms; /* for faking a reply */ + + struct dentry *ls_debug_dentry; /* debugfs */ + + wait_queue_head_t ls_uevent_wait; /* user part of join/leave */ + int ls_uevent_result; + + /* recovery related */ + + struct timer_list ls_timer; + struct task_struct *ls_recoverd_task; + struct semaphore ls_recoverd_active; + spinlock_t ls_recover_lock; + uint32_t ls_recover_status; /* DLM_RS_ */ + uint64_t ls_recover_seq; + struct dlm_recover *ls_recover_args; + struct rw_semaphore ls_in_recovery; /* block local requests */ + struct list_head ls_requestqueue;/* queue remote requests */ + struct semaphore ls_requestqueue_lock; + char *ls_recover_buf; + struct list_head ls_recover_list; + spinlock_t ls_recover_list_lock; + int ls_recover_list_count; + wait_queue_head_t ls_wait_general; + + struct list_head ls_root_list; /* root resources */ + struct rw_semaphore ls_root_sem; /* protect root_list */ + + int ls_namelen; + char ls_name[1]; +}; + +#define LSFL_WORK 0 +#define LSFL_RUNNING 1 +#define LSFL_RECOVERY_STOP 2 +#define LSFL_RCOM_READY 3 +#define LSFL_UEVENT_WAIT 4 + +static inline int dlm_locking_stopped(struct dlm_ls *ls) +{ + return !test_bit(LSFL_RUNNING, &ls->ls_flags); +} + +static inline int dlm_recovery_stopped(struct dlm_ls *ls) +{ + return test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags); +} + +static inline int dlm_no_directory(struct dlm_ls *ls) +{ + return (ls->ls_exflags & DLM_LSFL_NODIR) ? 1 : 0; +} + +#endif /* __DLM_INTERNAL_DOT_H__ */ + diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c new file mode 100644 index 000000000000..81efb361f95d --- /dev/null +++ b/fs/dlm/lock.c @@ -0,0 +1,3610 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +/* Central locking logic has four stages: + + dlm_lock() + dlm_unlock() + + request_lock(ls, lkb) + convert_lock(ls, lkb) + unlock_lock(ls, lkb) + cancel_lock(ls, lkb) + + _request_lock(r, lkb) + _convert_lock(r, lkb) + _unlock_lock(r, lkb) + _cancel_lock(r, lkb) + + do_request(r, lkb) + do_convert(r, lkb) + do_unlock(r, lkb) + do_cancel(r, lkb) + + Stage 1 (lock, unlock) is mainly about checking input args and + splitting into one of the four main operations: + + dlm_lock = request_lock + dlm_lock+CONVERT = convert_lock + dlm_unlock = unlock_lock + dlm_unlock+CANCEL = cancel_lock + + Stage 2, xxxx_lock(), just finds and locks the relevant rsb which is + provided to the next stage. + + Stage 3, _xxxx_lock(), determines if the operation is local or remote. + When remote, it calls send_xxxx(), when local it calls do_xxxx(). + + Stage 4, do_xxxx(), is the guts of the operation. It manipulates the + given rsb and lkb and queues callbacks. + + For remote operations, send_xxxx() results in the corresponding do_xxxx() + function being executed on the remote node. The connecting send/receive + calls on local (L) and remote (R) nodes: + + L: send_xxxx() -> R: receive_xxxx() + R: do_xxxx() + L: receive_xxxx_reply() <- R: send_xxxx_reply() +*/ + +#include "dlm_internal.h" +#include "memory.h" +#include "lowcomms.h" +#include "requestqueue.h" +#include "util.h" +#include "dir.h" +#include "member.h" +#include "lockspace.h" +#include "ast.h" +#include "lock.h" +#include "rcom.h" +#include "recover.h" +#include "lvb_table.h" +#include "config.h" + +static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb); +static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb); +static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb); +static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb); +static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb); +static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode); +static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb); +static int send_remove(struct dlm_rsb *r); +static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb); +static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, + struct dlm_message *ms); +static int receive_extralen(struct dlm_message *ms); + +/* + * Lock compatibilty matrix - thanks Steve + * UN = Unlocked state. Not really a state, used as a flag + * PD = Padding. Used to make the matrix a nice power of two in size + * Other states are the same as the VMS DLM. + * Usage: matrix[grmode+1][rqmode+1] (although m[rq+1][gr+1] is the same) + */ + +static const int __dlm_compat_matrix[8][8] = { + /* UN NL CR CW PR PW EX PD */ + {1, 1, 1, 1, 1, 1, 1, 0}, /* UN */ + {1, 1, 1, 1, 1, 1, 1, 0}, /* NL */ + {1, 1, 1, 1, 1, 1, 0, 0}, /* CR */ + {1, 1, 1, 1, 0, 0, 0, 0}, /* CW */ + {1, 1, 1, 0, 1, 0, 0, 0}, /* PR */ + {1, 1, 1, 0, 0, 0, 0, 0}, /* PW */ + {1, 1, 0, 0, 0, 0, 0, 0}, /* EX */ + {0, 0, 0, 0, 0, 0, 0, 0} /* PD */ +}; + +/* + * This defines the direction of transfer of LVB data. + * Granted mode is the row; requested mode is the column. + * Usage: matrix[grmode+1][rqmode+1] + * 1 = LVB is returned to the caller + * 0 = LVB is written to the resource + * -1 = nothing happens to the LVB + */ + +const int dlm_lvb_operations[8][8] = { + /* UN NL CR CW PR PW EX PD*/ + { -1, 1, 1, 1, 1, 1, 1, -1 }, /* UN */ + { -1, 1, 1, 1, 1, 1, 1, 0 }, /* NL */ + { -1, -1, 1, 1, 1, 1, 1, 0 }, /* CR */ + { -1, -1, -1, 1, 1, 1, 1, 0 }, /* CW */ + { -1, -1, -1, -1, 1, 1, 1, 0 }, /* PR */ + { -1, 0, 0, 0, 0, 0, 1, 0 }, /* PW */ + { -1, 0, 0, 0, 0, 0, 0, 0 }, /* EX */ + { -1, 0, 0, 0, 0, 0, 0, 0 } /* PD */ +}; +EXPORT_SYMBOL_GPL(dlm_lvb_operations); + +#define modes_compat(gr, rq) \ + __dlm_compat_matrix[(gr)->lkb_grmode + 1][(rq)->lkb_rqmode + 1] + +int dlm_modes_compat(int mode1, int mode2) +{ + return __dlm_compat_matrix[mode1 + 1][mode2 + 1]; +} + +/* + * Compatibility matrix for conversions with QUECVT set. + * Granted mode is the row; requested mode is the column. + * Usage: matrix[grmode+1][rqmode+1] + */ + +static const int __quecvt_compat_matrix[8][8] = { + /* UN NL CR CW PR PW EX PD */ + {0, 0, 0, 0, 0, 0, 0, 0}, /* UN */ + {0, 0, 1, 1, 1, 1, 1, 0}, /* NL */ + {0, 0, 0, 1, 1, 1, 1, 0}, /* CR */ + {0, 0, 0, 0, 1, 1, 1, 0}, /* CW */ + {0, 0, 0, 1, 0, 1, 1, 0}, /* PR */ + {0, 0, 0, 0, 0, 0, 1, 0}, /* PW */ + {0, 0, 0, 0, 0, 0, 0, 0}, /* EX */ + {0, 0, 0, 0, 0, 0, 0, 0} /* PD */ +}; + +static void dlm_print_lkb(struct dlm_lkb *lkb) +{ + printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n" + " status %d rqmode %d grmode %d wait_type %d ast_type %d\n", + lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags, + lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode, + lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type); +} + +void dlm_print_rsb(struct dlm_rsb *r) +{ + printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n", + r->res_nodeid, r->res_flags, r->res_first_lkid, + r->res_recover_locks_count, r->res_name); +} + +/* Threads cannot use the lockspace while it's being recovered */ + +static inline void lock_recovery(struct dlm_ls *ls) +{ + down_read(&ls->ls_in_recovery); +} + +static inline void unlock_recovery(struct dlm_ls *ls) +{ + up_read(&ls->ls_in_recovery); +} + +static inline int lock_recovery_try(struct dlm_ls *ls) +{ + return down_read_trylock(&ls->ls_in_recovery); +} + +static inline int can_be_queued(struct dlm_lkb *lkb) +{ + return !(lkb->lkb_exflags & DLM_LKF_NOQUEUE); +} + +static inline int force_blocking_asts(struct dlm_lkb *lkb) +{ + return (lkb->lkb_exflags & DLM_LKF_NOQUEUEBAST); +} + +static inline int is_demoted(struct dlm_lkb *lkb) +{ + return (lkb->lkb_sbflags & DLM_SBF_DEMOTED); +} + +static inline int is_remote(struct dlm_rsb *r) +{ + DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r);); + return !!r->res_nodeid; +} + +static inline int is_process_copy(struct dlm_lkb *lkb) +{ + return (lkb->lkb_nodeid && !(lkb->lkb_flags & DLM_IFL_MSTCPY)); +} + +static inline int is_master_copy(struct dlm_lkb *lkb) +{ + if (lkb->lkb_flags & DLM_IFL_MSTCPY) + DLM_ASSERT(lkb->lkb_nodeid, dlm_print_lkb(lkb);); + return (lkb->lkb_flags & DLM_IFL_MSTCPY) ? TRUE : FALSE; +} + +static inline int middle_conversion(struct dlm_lkb *lkb) +{ + if ((lkb->lkb_grmode==DLM_LOCK_PR && lkb->lkb_rqmode==DLM_LOCK_CW) || + (lkb->lkb_rqmode==DLM_LOCK_PR && lkb->lkb_grmode==DLM_LOCK_CW)) + return TRUE; + return FALSE; +} + +static inline int down_conversion(struct dlm_lkb *lkb) +{ + return (!middle_conversion(lkb) && lkb->lkb_rqmode < lkb->lkb_grmode); +} + +static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv) +{ + if (is_master_copy(lkb)) + return; + + DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb);); + + lkb->lkb_lksb->sb_status = rv; + lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags; + + dlm_add_ast(lkb, AST_COMP); +} + +static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode) +{ + if (is_master_copy(lkb)) + send_bast(r, lkb, rqmode); + else { + lkb->lkb_bastmode = rqmode; + dlm_add_ast(lkb, AST_BAST); + } +} + +/* + * Basic operations on rsb's and lkb's + */ + +static struct dlm_rsb *create_rsb(struct dlm_ls *ls, char *name, int len) +{ + struct dlm_rsb *r; + + r = allocate_rsb(ls, len); + if (!r) + return NULL; + + r->res_ls = ls; + r->res_length = len; + memcpy(r->res_name, name, len); + init_MUTEX(&r->res_sem); + + INIT_LIST_HEAD(&r->res_lookup); + INIT_LIST_HEAD(&r->res_grantqueue); + INIT_LIST_HEAD(&r->res_convertqueue); + INIT_LIST_HEAD(&r->res_waitqueue); + INIT_LIST_HEAD(&r->res_root_list); + INIT_LIST_HEAD(&r->res_recover_list); + + return r; +} + +static int search_rsb_list(struct list_head *head, char *name, int len, + unsigned int flags, struct dlm_rsb **r_ret) +{ + struct dlm_rsb *r; + int error = 0; + + list_for_each_entry(r, head, res_hashchain) { + if (len == r->res_length && !memcmp(name, r->res_name, len)) + goto found; + } + return -ENOENT; + + found: + if (r->res_nodeid && (flags & R_MASTER)) + error = -ENOTBLK; + *r_ret = r; + return error; +} + +static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b, + unsigned int flags, struct dlm_rsb **r_ret) +{ + struct dlm_rsb *r; + int error; + + error = search_rsb_list(&ls->ls_rsbtbl[b].list, name, len, flags, &r); + if (!error) { + kref_get(&r->res_ref); + goto out; + } + error = search_rsb_list(&ls->ls_rsbtbl[b].toss, name, len, flags, &r); + if (error) + goto out; + + list_move(&r->res_hashchain, &ls->ls_rsbtbl[b].list); + + if (dlm_no_directory(ls)) + goto out; + + if (r->res_nodeid == -1) { + rsb_clear_flag(r, RSB_MASTER_UNCERTAIN); + r->res_first_lkid = 0; + } else if (r->res_nodeid > 0) { + rsb_set_flag(r, RSB_MASTER_UNCERTAIN); + r->res_first_lkid = 0; + } else { + DLM_ASSERT(r->res_nodeid == 0, dlm_print_rsb(r);); + DLM_ASSERT(!rsb_flag(r, RSB_MASTER_UNCERTAIN),); + } + out: + *r_ret = r; + return error; +} + +static int search_rsb(struct dlm_ls *ls, char *name, int len, int b, + unsigned int flags, struct dlm_rsb **r_ret) +{ + int error; + write_lock(&ls->ls_rsbtbl[b].lock); + error = _search_rsb(ls, name, len, b, flags, r_ret); + write_unlock(&ls->ls_rsbtbl[b].lock); + return error; +} + +/* + * Find rsb in rsbtbl and potentially create/add one + * + * Delaying the release of rsb's has a similar benefit to applications keeping + * NL locks on an rsb, but without the guarantee that the cached master value + * will still be valid when the rsb is reused. Apps aren't always smart enough + * to keep NL locks on an rsb that they may lock again shortly; this can lead + * to excessive master lookups and removals if we don't delay the release. + * + * Searching for an rsb means looking through both the normal list and toss + * list. When found on the toss list the rsb is moved to the normal list with + * ref count of 1; when found on normal list the ref count is incremented. + */ + +static int find_rsb(struct dlm_ls *ls, char *name, int namelen, + unsigned int flags, struct dlm_rsb **r_ret) +{ + struct dlm_rsb *r, *tmp; + uint32_t hash, bucket; + int error = 0; + + if (dlm_no_directory(ls)) + flags |= R_CREATE; + + hash = jhash(name, namelen, 0); + bucket = hash & (ls->ls_rsbtbl_size - 1); + + error = search_rsb(ls, name, namelen, bucket, flags, &r); + if (!error) + goto out; + + if (error == -ENOENT && !(flags & R_CREATE)) + goto out; + + /* the rsb was found but wasn't a master copy */ + if (error == -ENOTBLK) + goto out; + + error = -ENOMEM; + r = create_rsb(ls, name, namelen); + if (!r) + goto out; + + r->res_hash = hash; + r->res_bucket = bucket; + r->res_nodeid = -1; + kref_init(&r->res_ref); + + /* With no directory, the master can be set immediately */ + if (dlm_no_directory(ls)) { + int nodeid = dlm_dir_nodeid(r); + if (nodeid == dlm_our_nodeid()) + nodeid = 0; + r->res_nodeid = nodeid; + } + + write_lock(&ls->ls_rsbtbl[bucket].lock); + error = _search_rsb(ls, name, namelen, bucket, 0, &tmp); + if (!error) { + write_unlock(&ls->ls_rsbtbl[bucket].lock); + free_rsb(r); + r = tmp; + goto out; + } + list_add(&r->res_hashchain, &ls->ls_rsbtbl[bucket].list); + write_unlock(&ls->ls_rsbtbl[bucket].lock); + error = 0; + out: + *r_ret = r; + return error; +} + +int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen, + unsigned int flags, struct dlm_rsb **r_ret) +{ + return find_rsb(ls, name, namelen, flags, r_ret); +} + +/* This is only called to add a reference when the code already holds + a valid reference to the rsb, so there's no need for locking. */ + +static inline void hold_rsb(struct dlm_rsb *r) +{ + kref_get(&r->res_ref); +} + +void dlm_hold_rsb(struct dlm_rsb *r) +{ + hold_rsb(r); +} + +static void toss_rsb(struct kref *kref) +{ + struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref); + struct dlm_ls *ls = r->res_ls; + + DLM_ASSERT(list_empty(&r->res_root_list), dlm_print_rsb(r);); + kref_init(&r->res_ref); + list_move(&r->res_hashchain, &ls->ls_rsbtbl[r->res_bucket].toss); + r->res_toss_time = jiffies; + if (r->res_lvbptr) { + free_lvb(r->res_lvbptr); + r->res_lvbptr = NULL; + } +} + +/* When all references to the rsb are gone it's transfered to + the tossed list for later disposal. */ + +static void put_rsb(struct dlm_rsb *r) +{ + struct dlm_ls *ls = r->res_ls; + uint32_t bucket = r->res_bucket; + + write_lock(&ls->ls_rsbtbl[bucket].lock); + kref_put(&r->res_ref, toss_rsb); + write_unlock(&ls->ls_rsbtbl[bucket].lock); +} + +void dlm_put_rsb(struct dlm_rsb *r) +{ + put_rsb(r); +} + +/* See comment for unhold_lkb */ + +static void unhold_rsb(struct dlm_rsb *r) +{ + int rv; + rv = kref_put(&r->res_ref, toss_rsb); + DLM_ASSERT(!rv, dlm_print_rsb(r);); +} + +static void kill_rsb(struct kref *kref) +{ + struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref); + + /* All work is done after the return from kref_put() so we + can release the write_lock before the remove and free. */ + + DLM_ASSERT(list_empty(&r->res_lookup),); + DLM_ASSERT(list_empty(&r->res_grantqueue),); + DLM_ASSERT(list_empty(&r->res_convertqueue),); + DLM_ASSERT(list_empty(&r->res_waitqueue),); + DLM_ASSERT(list_empty(&r->res_root_list),); + DLM_ASSERT(list_empty(&r->res_recover_list),); +} + +/* Attaching/detaching lkb's from rsb's is for rsb reference counting. + The rsb must exist as long as any lkb's for it do. */ + +static void attach_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + hold_rsb(r); + lkb->lkb_resource = r; +} + +static void detach_lkb(struct dlm_lkb *lkb) +{ + if (lkb->lkb_resource) { + put_rsb(lkb->lkb_resource); + lkb->lkb_resource = NULL; + } +} + +static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) +{ + struct dlm_lkb *lkb, *tmp; + uint32_t lkid = 0; + uint16_t bucket; + + lkb = allocate_lkb(ls); + if (!lkb) + return -ENOMEM; + + lkb->lkb_nodeid = -1; + lkb->lkb_grmode = DLM_LOCK_IV; + kref_init(&lkb->lkb_ref); + + get_random_bytes(&bucket, sizeof(bucket)); + bucket &= (ls->ls_lkbtbl_size - 1); + + write_lock(&ls->ls_lkbtbl[bucket].lock); + + /* counter can roll over so we must verify lkid is not in use */ + + while (lkid == 0) { + lkid = bucket | (ls->ls_lkbtbl[bucket].counter++ << 16); + + list_for_each_entry(tmp, &ls->ls_lkbtbl[bucket].list, + lkb_idtbl_list) { + if (tmp->lkb_id != lkid) + continue; + lkid = 0; + break; + } + } + + lkb->lkb_id = lkid; + list_add(&lkb->lkb_idtbl_list, &ls->ls_lkbtbl[bucket].list); + write_unlock(&ls->ls_lkbtbl[bucket].lock); + + *lkb_ret = lkb; + return 0; +} + +static struct dlm_lkb *__find_lkb(struct dlm_ls *ls, uint32_t lkid) +{ + uint16_t bucket = lkid & 0xFFFF; + struct dlm_lkb *lkb; + + list_for_each_entry(lkb, &ls->ls_lkbtbl[bucket].list, lkb_idtbl_list) { + if (lkb->lkb_id == lkid) + return lkb; + } + return NULL; +} + +static int find_lkb(struct dlm_ls *ls, uint32_t lkid, struct dlm_lkb **lkb_ret) +{ + struct dlm_lkb *lkb; + uint16_t bucket = lkid & 0xFFFF; + + if (bucket >= ls->ls_lkbtbl_size) + return -EBADSLT; + + read_lock(&ls->ls_lkbtbl[bucket].lock); + lkb = __find_lkb(ls, lkid); + if (lkb) + kref_get(&lkb->lkb_ref); + read_unlock(&ls->ls_lkbtbl[bucket].lock); + + *lkb_ret = lkb; + return lkb ? 0 : -ENOENT; +} + +static void kill_lkb(struct kref *kref) +{ + struct dlm_lkb *lkb = container_of(kref, struct dlm_lkb, lkb_ref); + + /* All work is done after the return from kref_put() so we + can release the write_lock before the detach_lkb */ + + DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb);); +} + +static int put_lkb(struct dlm_lkb *lkb) +{ + struct dlm_ls *ls = lkb->lkb_resource->res_ls; + uint16_t bucket = lkb->lkb_id & 0xFFFF; + + write_lock(&ls->ls_lkbtbl[bucket].lock); + if (kref_put(&lkb->lkb_ref, kill_lkb)) { + list_del(&lkb->lkb_idtbl_list); + write_unlock(&ls->ls_lkbtbl[bucket].lock); + + detach_lkb(lkb); + + /* for local/process lkbs, lvbptr points to caller's lksb */ + if (lkb->lkb_lvbptr && is_master_copy(lkb)) + free_lvb(lkb->lkb_lvbptr); + if (lkb->lkb_range) + free_range(lkb->lkb_range); + free_lkb(lkb); + return 1; + } else { + write_unlock(&ls->ls_lkbtbl[bucket].lock); + return 0; + } +} + +int dlm_put_lkb(struct dlm_lkb *lkb) +{ + return put_lkb(lkb); +} + +/* This is only called to add a reference when the code already holds + a valid reference to the lkb, so there's no need for locking. */ + +static inline void hold_lkb(struct dlm_lkb *lkb) +{ + kref_get(&lkb->lkb_ref); +} + +/* This is called when we need to remove a reference and are certain + it's not the last ref. e.g. del_lkb is always called between a + find_lkb/put_lkb and is always the inverse of a previous add_lkb. + put_lkb would work fine, but would involve unnecessary locking */ + +static inline void unhold_lkb(struct dlm_lkb *lkb) +{ + int rv; + rv = kref_put(&lkb->lkb_ref, kill_lkb); + DLM_ASSERT(!rv, dlm_print_lkb(lkb);); +} + +static void lkb_add_ordered(struct list_head *new, struct list_head *head, + int mode) +{ + struct dlm_lkb *lkb = NULL; + + list_for_each_entry(lkb, head, lkb_statequeue) + if (lkb->lkb_rqmode < mode) + break; + + if (!lkb) + list_add_tail(new, head); + else + __list_add(new, lkb->lkb_statequeue.prev, &lkb->lkb_statequeue); +} + +/* add/remove lkb to rsb's grant/convert/wait queue */ + +static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status) +{ + kref_get(&lkb->lkb_ref); + + DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb);); + + lkb->lkb_status = status; + + switch (status) { + case DLM_LKSTS_WAITING: + if (lkb->lkb_exflags & DLM_LKF_HEADQUE) + list_add(&lkb->lkb_statequeue, &r->res_waitqueue); + else + list_add_tail(&lkb->lkb_statequeue, &r->res_waitqueue); + break; + case DLM_LKSTS_GRANTED: + /* convention says granted locks kept in order of grmode */ + lkb_add_ordered(&lkb->lkb_statequeue, &r->res_grantqueue, + lkb->lkb_grmode); + break; + case DLM_LKSTS_CONVERT: + if (lkb->lkb_exflags & DLM_LKF_HEADQUE) + list_add(&lkb->lkb_statequeue, &r->res_convertqueue); + else + list_add_tail(&lkb->lkb_statequeue, + &r->res_convertqueue); + break; + default: + DLM_ASSERT(0, dlm_print_lkb(lkb); printk("sts=%d\n", status);); + } +} + +static void del_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + lkb->lkb_status = 0; + list_del(&lkb->lkb_statequeue); + unhold_lkb(lkb); +} + +static void move_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int sts) +{ + hold_lkb(lkb); + del_lkb(r, lkb); + add_lkb(r, lkb, sts); + unhold_lkb(lkb); +} + +/* add/remove lkb from global waiters list of lkb's waiting for + a reply from a remote node */ + +static void add_to_waiters(struct dlm_lkb *lkb, int mstype) +{ + struct dlm_ls *ls = lkb->lkb_resource->res_ls; + + down(&ls->ls_waiters_sem); + if (lkb->lkb_wait_type) { + log_print("add_to_waiters error %d", lkb->lkb_wait_type); + goto out; + } + lkb->lkb_wait_type = mstype; + kref_get(&lkb->lkb_ref); + list_add(&lkb->lkb_wait_reply, &ls->ls_waiters); + out: + up(&ls->ls_waiters_sem); +} + +static int _remove_from_waiters(struct dlm_lkb *lkb) +{ + int error = 0; + + if (!lkb->lkb_wait_type) { + log_print("remove_from_waiters error"); + error = -EINVAL; + goto out; + } + lkb->lkb_wait_type = 0; + list_del(&lkb->lkb_wait_reply); + unhold_lkb(lkb); + out: + return error; +} + +static int remove_from_waiters(struct dlm_lkb *lkb) +{ + struct dlm_ls *ls = lkb->lkb_resource->res_ls; + int error; + + down(&ls->ls_waiters_sem); + error = _remove_from_waiters(lkb); + up(&ls->ls_waiters_sem); + return error; +} + +static void dir_remove(struct dlm_rsb *r) +{ + int to_nodeid; + + if (dlm_no_directory(r->res_ls)) + return; + + to_nodeid = dlm_dir_nodeid(r); + if (to_nodeid != dlm_our_nodeid()) + send_remove(r); + else + dlm_dir_remove_entry(r->res_ls, to_nodeid, + r->res_name, r->res_length); +} + +/* FIXME: shouldn't this be able to exit as soon as one non-due rsb is + found since they are in order of newest to oldest? */ + +static int shrink_bucket(struct dlm_ls *ls, int b) +{ + struct dlm_rsb *r; + int count = 0, found; + + for (;;) { + found = FALSE; + write_lock(&ls->ls_rsbtbl[b].lock); + list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss, + res_hashchain) { + if (!time_after_eq(jiffies, r->res_toss_time + + dlm_config.toss_secs * HZ)) + continue; + found = TRUE; + break; + } + + if (!found) { + write_unlock(&ls->ls_rsbtbl[b].lock); + break; + } + + if (kref_put(&r->res_ref, kill_rsb)) { + list_del(&r->res_hashchain); + write_unlock(&ls->ls_rsbtbl[b].lock); + + if (is_master(r)) + dir_remove(r); + free_rsb(r); + count++; + } else { + write_unlock(&ls->ls_rsbtbl[b].lock); + log_error(ls, "tossed rsb in use %s", r->res_name); + } + } + + return count; +} + +void dlm_scan_rsbs(struct dlm_ls *ls) +{ + int i; + + if (dlm_locking_stopped(ls)) + return; + + for (i = 0; i < ls->ls_rsbtbl_size; i++) { + shrink_bucket(ls, i); + cond_resched(); + } +} + +/* lkb is master or local copy */ + +static void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + int b, len = r->res_ls->ls_lvblen; + + /* b=1 lvb returned to caller + b=0 lvb written to rsb or invalidated + b=-1 do nothing */ + + b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1]; + + if (b == 1) { + if (!lkb->lkb_lvbptr) + return; + + if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) + return; + + if (!r->res_lvbptr) + return; + + memcpy(lkb->lkb_lvbptr, r->res_lvbptr, len); + lkb->lkb_lvbseq = r->res_lvbseq; + + } else if (b == 0) { + if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) { + rsb_set_flag(r, RSB_VALNOTVALID); + return; + } + + if (!lkb->lkb_lvbptr) + return; + + if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) + return; + + if (!r->res_lvbptr) + r->res_lvbptr = allocate_lvb(r->res_ls); + + if (!r->res_lvbptr) + return; + + memcpy(r->res_lvbptr, lkb->lkb_lvbptr, len); + r->res_lvbseq++; + lkb->lkb_lvbseq = r->res_lvbseq; + rsb_clear_flag(r, RSB_VALNOTVALID); + } + + if (rsb_flag(r, RSB_VALNOTVALID)) + lkb->lkb_sbflags |= DLM_SBF_VALNOTVALID; +} + +static void set_lvb_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + if (lkb->lkb_grmode < DLM_LOCK_PW) + return; + + if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) { + rsb_set_flag(r, RSB_VALNOTVALID); + return; + } + + if (!lkb->lkb_lvbptr) + return; + + if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) + return; + + if (!r->res_lvbptr) + r->res_lvbptr = allocate_lvb(r->res_ls); + + if (!r->res_lvbptr) + return; + + memcpy(r->res_lvbptr, lkb->lkb_lvbptr, r->res_ls->ls_lvblen); + r->res_lvbseq++; + rsb_clear_flag(r, RSB_VALNOTVALID); +} + +/* lkb is process copy (pc) */ + +static void set_lvb_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb, + struct dlm_message *ms) +{ + int b; + + if (!lkb->lkb_lvbptr) + return; + + if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) + return; + + b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1]; + if (b == 1) { + int len = receive_extralen(ms); + memcpy(lkb->lkb_lvbptr, ms->m_extra, len); + lkb->lkb_lvbseq = ms->m_lvbseq; + } +} + +/* Manipulate lkb's on rsb's convert/granted/waiting queues + remove_lock -- used for unlock, removes lkb from granted + revert_lock -- used for cancel, moves lkb from convert to granted + grant_lock -- used for request and convert, adds lkb to granted or + moves lkb from convert or waiting to granted + + Each of these is used for master or local copy lkb's. There is + also a _pc() variation used to make the corresponding change on + a process copy (pc) lkb. */ + +static void _remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + del_lkb(r, lkb); + lkb->lkb_grmode = DLM_LOCK_IV; + /* this unhold undoes the original ref from create_lkb() + so this leads to the lkb being freed */ + unhold_lkb(lkb); +} + +static void remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + set_lvb_unlock(r, lkb); + _remove_lock(r, lkb); +} + +static void remove_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + _remove_lock(r, lkb); +} + +static void revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + lkb->lkb_rqmode = DLM_LOCK_IV; + + switch (lkb->lkb_status) { + case DLM_LKSTS_CONVERT: + move_lkb(r, lkb, DLM_LKSTS_GRANTED); + break; + case DLM_LKSTS_WAITING: + del_lkb(r, lkb); + lkb->lkb_grmode = DLM_LOCK_IV; + /* this unhold undoes the original ref from create_lkb() + so this leads to the lkb being freed */ + unhold_lkb(lkb); + break; + default: + log_print("invalid status for revert %d", lkb->lkb_status); + } +} + +static void revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + revert_lock(r, lkb); +} + +static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + if (lkb->lkb_grmode != lkb->lkb_rqmode) { + lkb->lkb_grmode = lkb->lkb_rqmode; + if (lkb->lkb_status) + move_lkb(r, lkb, DLM_LKSTS_GRANTED); + else + add_lkb(r, lkb, DLM_LKSTS_GRANTED); + } + + lkb->lkb_rqmode = DLM_LOCK_IV; + + if (lkb->lkb_range) { + lkb->lkb_range[GR_RANGE_START] = lkb->lkb_range[RQ_RANGE_START]; + lkb->lkb_range[GR_RANGE_END] = lkb->lkb_range[RQ_RANGE_END]; + } +} + +static void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + set_lvb_lock(r, lkb); + _grant_lock(r, lkb); + lkb->lkb_highbast = 0; +} + +static void grant_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb, + struct dlm_message *ms) +{ + set_lvb_lock_pc(r, lkb, ms); + _grant_lock(r, lkb); +} + +/* called by grant_pending_locks() which means an async grant message must + be sent to the requesting node in addition to granting the lock if the + lkb belongs to a remote node. */ + +static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + grant_lock(r, lkb); + if (is_master_copy(lkb)) + send_grant(r, lkb); + else + queue_cast(r, lkb, 0); +} + +static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head) +{ + struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb, + lkb_statequeue); + if (lkb->lkb_id == first->lkb_id) + return TRUE; + + return FALSE; +} + +/* Return 1 if the locks' ranges overlap. If the lkb has no range then it is + assumed to cover 0-ffffffff.ffffffff */ + +static inline int ranges_overlap(struct dlm_lkb *lkb1, struct dlm_lkb *lkb2) +{ + if (!lkb1->lkb_range || !lkb2->lkb_range) + return TRUE; + + if (lkb1->lkb_range[RQ_RANGE_END] < lkb2->lkb_range[GR_RANGE_START] || + lkb1->lkb_range[RQ_RANGE_START] > lkb2->lkb_range[GR_RANGE_END]) + return FALSE; + + return TRUE; +} + +/* Check if the given lkb conflicts with another lkb on the queue. */ + +static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb) +{ + struct dlm_lkb *this; + + list_for_each_entry(this, head, lkb_statequeue) { + if (this == lkb) + continue; + if (ranges_overlap(lkb, this) && !modes_compat(this, lkb)) + return TRUE; + } + return FALSE; +} + +/* + * "A conversion deadlock arises with a pair of lock requests in the converting + * queue for one resource. The granted mode of each lock blocks the requested + * mode of the other lock." + * + * Part 2: if the granted mode of lkb is preventing the first lkb in the + * convert queue from being granted, then demote lkb (set grmode to NL). + * This second form requires that we check for conv-deadlk even when + * now == 0 in _can_be_granted(). + * + * Example: + * Granted Queue: empty + * Convert Queue: NL->EX (first lock) + * PR->EX (second lock) + * + * The first lock can't be granted because of the granted mode of the second + * lock and the second lock can't be granted because it's not first in the + * list. We demote the granted mode of the second lock (the lkb passed to this + * function). + * + * After the resolution, the "grant pending" function needs to go back and try + * to grant locks on the convert queue again since the first lock can now be + * granted. + */ + +static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb) +{ + struct dlm_lkb *this, *first = NULL, *self = NULL; + + list_for_each_entry(this, &rsb->res_convertqueue, lkb_statequeue) { + if (!first) + first = this; + if (this == lkb) { + self = lkb; + continue; + } + + if (!ranges_overlap(lkb, this)) + continue; + + if (!modes_compat(this, lkb) && !modes_compat(lkb, this)) + return TRUE; + } + + /* if lkb is on the convert queue and is preventing the first + from being granted, then there's deadlock and we demote lkb. + multiple converting locks may need to do this before the first + converting lock can be granted. */ + + if (self && self != first) { + if (!modes_compat(lkb, first) && + !queue_conflict(&rsb->res_grantqueue, first)) + return TRUE; + } + + return FALSE; +} + +/* + * Return 1 if the lock can be granted, 0 otherwise. + * Also detect and resolve conversion deadlocks. + * + * lkb is the lock to be granted + * + * now is 1 if the function is being called in the context of the + * immediate request, it is 0 if called later, after the lock has been + * queued. + * + * References are from chapter 6 of "VAXcluster Principles" by Roy Davis + */ + +static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) +{ + int8_t conv = (lkb->lkb_grmode != DLM_LOCK_IV); + + /* + * 6-10: Version 5.4 introduced an option to address the phenomenon of + * a new request for a NL mode lock being blocked. + * + * 6-11: If the optional EXPEDITE flag is used with the new NL mode + * request, then it would be granted. In essence, the use of this flag + * tells the Lock Manager to expedite theis request by not considering + * what may be in the CONVERTING or WAITING queues... As of this + * writing, the EXPEDITE flag can be used only with new requests for NL + * mode locks. This flag is not valid for conversion requests. + * + * A shortcut. Earlier checks return an error if EXPEDITE is used in a + * conversion or used with a non-NL requested mode. We also know an + * EXPEDITE request is always granted immediately, so now must always + * be 1. The full condition to grant an expedite request: (now && + * !conv && lkb->rqmode == DLM_LOCK_NL && (flags & EXPEDITE)) can + * therefore be shortened to just checking the flag. + */ + + if (lkb->lkb_exflags & DLM_LKF_EXPEDITE) + return TRUE; + + /* + * A shortcut. Without this, !queue_conflict(grantqueue, lkb) would be + * added to the remaining conditions. + */ + + if (queue_conflict(&r->res_grantqueue, lkb)) + goto out; + + /* + * 6-3: By default, a conversion request is immediately granted if the + * requested mode is compatible with the modes of all other granted + * locks + */ + + if (queue_conflict(&r->res_convertqueue, lkb)) + goto out; + + /* + * 6-5: But the default algorithm for deciding whether to grant or + * queue conversion requests does not by itself guarantee that such + * requests are serviced on a "first come first serve" basis. This, in + * turn, can lead to a phenomenon known as "indefinate postponement". + * + * 6-7: This issue is dealt with by using the optional QUECVT flag with + * the system service employed to request a lock conversion. This flag + * forces certain conversion requests to be queued, even if they are + * compatible with the granted modes of other locks on the same + * resource. Thus, the use of this flag results in conversion requests + * being ordered on a "first come first servce" basis. + * + * DCT: This condition is all about new conversions being able to occur + * "in place" while the lock remains on the granted queue (assuming + * nothing else conflicts.) IOW if QUECVT isn't set, a conversion + * doesn't _have_ to go onto the convert queue where it's processed in + * order. The "now" variable is necessary to distinguish converts + * being received and processed for the first time now, because once a + * convert is moved to the conversion queue the condition below applies + * requiring fifo granting. + */ + + if (now && conv && !(lkb->lkb_exflags & DLM_LKF_QUECVT)) + return TRUE; + + /* + * When using range locks the NOORDER flag is set to avoid the standard + * vms rules on grant order. + */ + + if (lkb->lkb_exflags & DLM_LKF_NOORDER) + return TRUE; + + /* + * 6-3: Once in that queue [CONVERTING], a conversion request cannot be + * granted until all other conversion requests ahead of it are granted + * and/or canceled. + */ + + if (!now && conv && first_in_list(lkb, &r->res_convertqueue)) + return TRUE; + + /* + * 6-4: By default, a new request is immediately granted only if all + * three of the following conditions are satisfied when the request is + * issued: + * - The queue of ungranted conversion requests for the resource is + * empty. + * - The queue of ungranted new requests for the resource is empty. + * - The mode of the new request is compatible with the most + * restrictive mode of all granted locks on the resource. + */ + + if (now && !conv && list_empty(&r->res_convertqueue) && + list_empty(&r->res_waitqueue)) + return TRUE; + + /* + * 6-4: Once a lock request is in the queue of ungranted new requests, + * it cannot be granted until the queue of ungranted conversion + * requests is empty, all ungranted new requests ahead of it are + * granted and/or canceled, and it is compatible with the granted mode + * of the most restrictive lock granted on the resource. + */ + + if (!now && !conv && list_empty(&r->res_convertqueue) && + first_in_list(lkb, &r->res_waitqueue)) + return TRUE; + + out: + /* + * The following, enabled by CONVDEADLK, departs from VMS. + */ + + if (conv && (lkb->lkb_exflags & DLM_LKF_CONVDEADLK) && + conversion_deadlock_detect(r, lkb)) { + lkb->lkb_grmode = DLM_LOCK_NL; + lkb->lkb_sbflags |= DLM_SBF_DEMOTED; + } + + return FALSE; +} + +/* + * The ALTPR and ALTCW flags aren't traditional lock manager flags, but are a + * simple way to provide a big optimization to applications that can use them. + */ + +static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) +{ + uint32_t flags = lkb->lkb_exflags; + int rv; + int8_t alt = 0, rqmode = lkb->lkb_rqmode; + + rv = _can_be_granted(r, lkb, now); + if (rv) + goto out; + + if (lkb->lkb_sbflags & DLM_SBF_DEMOTED) + goto out; + + if (rqmode != DLM_LOCK_PR && flags & DLM_LKF_ALTPR) + alt = DLM_LOCK_PR; + else if (rqmode != DLM_LOCK_CW && flags & DLM_LKF_ALTCW) + alt = DLM_LOCK_CW; + + if (alt) { + lkb->lkb_rqmode = alt; + rv = _can_be_granted(r, lkb, now); + if (rv) + lkb->lkb_sbflags |= DLM_SBF_ALTMODE; + else + lkb->lkb_rqmode = rqmode; + } + out: + return rv; +} + +static int grant_pending_convert(struct dlm_rsb *r, int high) +{ + struct dlm_lkb *lkb, *s; + int hi, demoted, quit, grant_restart, demote_restart; + + quit = 0; + restart: + grant_restart = 0; + demote_restart = 0; + hi = DLM_LOCK_IV; + + list_for_each_entry_safe(lkb, s, &r->res_convertqueue, lkb_statequeue) { + demoted = is_demoted(lkb); + if (can_be_granted(r, lkb, FALSE)) { + grant_lock_pending(r, lkb); + grant_restart = 1; + } else { + hi = max_t(int, lkb->lkb_rqmode, hi); + if (!demoted && is_demoted(lkb)) + demote_restart = 1; + } + } + + if (grant_restart) + goto restart; + if (demote_restart && !quit) { + quit = 1; + goto restart; + } + + return max_t(int, high, hi); +} + +static int grant_pending_wait(struct dlm_rsb *r, int high) +{ + struct dlm_lkb *lkb, *s; + + list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) { + if (can_be_granted(r, lkb, FALSE)) + grant_lock_pending(r, lkb); + else + high = max_t(int, lkb->lkb_rqmode, high); + } + + return high; +} + +static void grant_pending_locks(struct dlm_rsb *r) +{ + struct dlm_lkb *lkb, *s; + int high = DLM_LOCK_IV; + + DLM_ASSERT(is_master(r), dlm_print_rsb(r);); + + high = grant_pending_convert(r, high); + high = grant_pending_wait(r, high); + + if (high == DLM_LOCK_IV) + return; + + /* + * If there are locks left on the wait/convert queue then send blocking + * ASTs to granted locks based on the largest requested mode (high) + * found above. This can generate spurious blocking ASTs for range + * locks. FIXME: highbast < high comparison not valid for PR/CW. + */ + + list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) { + if (lkb->lkb_bastaddr && (lkb->lkb_highbast < high) && + !__dlm_compat_matrix[lkb->lkb_grmode+1][high+1]) { + queue_bast(r, lkb, high); + lkb->lkb_highbast = high; + } + } +} + +static void send_bast_queue(struct dlm_rsb *r, struct list_head *head, + struct dlm_lkb *lkb) +{ + struct dlm_lkb *gr; + + list_for_each_entry(gr, head, lkb_statequeue) { + if (gr->lkb_bastaddr && + gr->lkb_highbast < lkb->lkb_rqmode && + ranges_overlap(lkb, gr) && !modes_compat(gr, lkb)) { + queue_bast(r, gr, lkb->lkb_rqmode); + gr->lkb_highbast = lkb->lkb_rqmode; + } + } +} + +static void send_blocking_asts(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + send_bast_queue(r, &r->res_grantqueue, lkb); +} + +static void send_blocking_asts_all(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + send_bast_queue(r, &r->res_grantqueue, lkb); + send_bast_queue(r, &r->res_convertqueue, lkb); +} + +/* set_master(r, lkb) -- set the master nodeid of a resource + + The purpose of this function is to set the nodeid field in the given + lkb using the nodeid field in the given rsb. If the rsb's nodeid is + known, it can just be copied to the lkb and the function will return + 0. If the rsb's nodeid is _not_ known, it needs to be looked up + before it can be copied to the lkb. + + When the rsb nodeid is being looked up remotely, the initial lkb + causing the lookup is kept on the ls_waiters list waiting for the + lookup reply. Other lkb's waiting for the same rsb lookup are kept + on the rsb's res_lookup list until the master is verified. + + Return values: + 0: nodeid is set in rsb/lkb and the caller should go ahead and use it + 1: the rsb master is not available and the lkb has been placed on + a wait queue +*/ + +static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + struct dlm_ls *ls = r->res_ls; + int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid(); + + if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) { + rsb_clear_flag(r, RSB_MASTER_UNCERTAIN); + r->res_first_lkid = lkb->lkb_id; + lkb->lkb_nodeid = r->res_nodeid; + return 0; + } + + if (r->res_first_lkid && r->res_first_lkid != lkb->lkb_id) { + list_add_tail(&lkb->lkb_rsb_lookup, &r->res_lookup); + return 1; + } + + if (r->res_nodeid == 0) { + lkb->lkb_nodeid = 0; + return 0; + } + + if (r->res_nodeid > 0) { + lkb->lkb_nodeid = r->res_nodeid; + return 0; + } + + DLM_ASSERT(r->res_nodeid == -1, dlm_print_rsb(r);); + + dir_nodeid = dlm_dir_nodeid(r); + + if (dir_nodeid != our_nodeid) { + r->res_first_lkid = lkb->lkb_id; + send_lookup(r, lkb); + return 1; + } + + for (;;) { + /* It's possible for dlm_scand to remove an old rsb for + this same resource from the toss list, us to create + a new one, look up the master locally, and find it + already exists just before dlm_scand does the + dir_remove() on the previous rsb. */ + + error = dlm_dir_lookup(ls, our_nodeid, r->res_name, + r->res_length, &ret_nodeid); + if (!error) + break; + log_debug(ls, "dir_lookup error %d %s", error, r->res_name); + schedule(); + } + + if (ret_nodeid == our_nodeid) { + r->res_first_lkid = 0; + r->res_nodeid = 0; + lkb->lkb_nodeid = 0; + } else { + r->res_first_lkid = lkb->lkb_id; + r->res_nodeid = ret_nodeid; + lkb->lkb_nodeid = ret_nodeid; + } + return 0; +} + +static void process_lookup_list(struct dlm_rsb *r) +{ + struct dlm_lkb *lkb, *safe; + + list_for_each_entry_safe(lkb, safe, &r->res_lookup, lkb_rsb_lookup) { + list_del(&lkb->lkb_rsb_lookup); + _request_lock(r, lkb); + schedule(); + } +} + +/* confirm_master -- confirm (or deny) an rsb's master nodeid */ + +static void confirm_master(struct dlm_rsb *r, int error) +{ + struct dlm_lkb *lkb; + + if (!r->res_first_lkid) + return; + + switch (error) { + case 0: + case -EINPROGRESS: + r->res_first_lkid = 0; + process_lookup_list(r); + break; + + case -EAGAIN: + /* the remote master didn't queue our NOQUEUE request; + make a waiting lkb the first_lkid */ + + r->res_first_lkid = 0; + + if (!list_empty(&r->res_lookup)) { + lkb = list_entry(r->res_lookup.next, struct dlm_lkb, + lkb_rsb_lookup); + list_del(&lkb->lkb_rsb_lookup); + r->res_first_lkid = lkb->lkb_id; + _request_lock(r, lkb); + } else + r->res_nodeid = -1; + break; + + default: + log_error(r->res_ls, "confirm_master unknown error %d", error); + } +} + +static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags, + int namelen, uint32_t parent_lkid, void *ast, + void *astarg, void *bast, struct dlm_range *range, + struct dlm_args *args) +{ + int rv = -EINVAL; + + /* check for invalid arg usage */ + + if (mode < 0 || mode > DLM_LOCK_EX) + goto out; + + if (!(flags & DLM_LKF_CONVERT) && (namelen > DLM_RESNAME_MAXLEN)) + goto out; + + if (flags & DLM_LKF_CANCEL) + goto out; + + if (flags & DLM_LKF_QUECVT && !(flags & DLM_LKF_CONVERT)) + goto out; + + if (flags & DLM_LKF_CONVDEADLK && !(flags & DLM_LKF_CONVERT)) + goto out; + + if (flags & DLM_LKF_CONVDEADLK && flags & DLM_LKF_NOQUEUE) + goto out; + + if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_CONVERT) + goto out; + + if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_QUECVT) + goto out; + + if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_NOQUEUE) + goto out; + + if (flags & DLM_LKF_EXPEDITE && mode != DLM_LOCK_NL) + goto out; + + if (!ast || !lksb) + goto out; + + if (flags & DLM_LKF_VALBLK && !lksb->sb_lvbptr) + goto out; + + /* parent/child locks not yet supported */ + if (parent_lkid) + goto out; + + if (flags & DLM_LKF_CONVERT && !lksb->sb_lkid) + goto out; + + /* these args will be copied to the lkb in validate_lock_args, + it cannot be done now because when converting locks, fields in + an active lkb cannot be modified before locking the rsb */ + + args->flags = flags; + args->astaddr = ast; + args->astparam = (long) astarg; + args->bastaddr = bast; + args->mode = mode; + args->lksb = lksb; + args->range = range; + rv = 0; + out: + return rv; +} + +static int set_unlock_args(uint32_t flags, void *astarg, struct dlm_args *args) +{ + if (flags & ~(DLM_LKF_CANCEL | DLM_LKF_VALBLK | DLM_LKF_IVVALBLK | + DLM_LKF_FORCEUNLOCK)) + return -EINVAL; + + args->flags = flags; + args->astparam = (long) astarg; + return 0; +} + +static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, + struct dlm_args *args) +{ + int rv = -EINVAL; + + if (args->flags & DLM_LKF_CONVERT) { + if (lkb->lkb_flags & DLM_IFL_MSTCPY) + goto out; + + if (args->flags & DLM_LKF_QUECVT && + !__quecvt_compat_matrix[lkb->lkb_grmode+1][args->mode+1]) + goto out; + + rv = -EBUSY; + if (lkb->lkb_status != DLM_LKSTS_GRANTED) + goto out; + + if (lkb->lkb_wait_type) + goto out; + } + + lkb->lkb_exflags = args->flags; + lkb->lkb_sbflags = 0; + lkb->lkb_astaddr = args->astaddr; + lkb->lkb_astparam = args->astparam; + lkb->lkb_bastaddr = args->bastaddr; + lkb->lkb_rqmode = args->mode; + lkb->lkb_lksb = args->lksb; + lkb->lkb_lvbptr = args->lksb->sb_lvbptr; + lkb->lkb_ownpid = (int) current->pid; + + rv = 0; + if (!args->range) + goto out; + + if (!lkb->lkb_range) { + rv = -ENOMEM; + lkb->lkb_range = allocate_range(ls); + if (!lkb->lkb_range) + goto out; + /* This is needed for conversions that contain ranges + where the original lock didn't but it's harmless for + new locks too. */ + lkb->lkb_range[GR_RANGE_START] = 0LL; + lkb->lkb_range[GR_RANGE_END] = 0xffffffffffffffffULL; + } + + lkb->lkb_range[RQ_RANGE_START] = args->range->ra_start; + lkb->lkb_range[RQ_RANGE_END] = args->range->ra_end; + lkb->lkb_flags |= DLM_IFL_RANGE; + rv = 0; + out: + return rv; +} + +static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args) +{ + int rv = -EINVAL; + + if (lkb->lkb_flags & DLM_IFL_MSTCPY) + goto out; + + if (args->flags & DLM_LKF_FORCEUNLOCK) + goto out_ok; + + if (args->flags & DLM_LKF_CANCEL && + lkb->lkb_status == DLM_LKSTS_GRANTED) + goto out; + + if (!(args->flags & DLM_LKF_CANCEL) && + lkb->lkb_status != DLM_LKSTS_GRANTED) + goto out; + + rv = -EBUSY; + if (lkb->lkb_wait_type) + goto out; + + out_ok: + lkb->lkb_exflags = args->flags; + lkb->lkb_sbflags = 0; + lkb->lkb_astparam = args->astparam; + + rv = 0; + out: + return rv; +} + +/* + * Four stage 4 varieties: + * do_request(), do_convert(), do_unlock(), do_cancel() + * These are called on the master node for the given lock and + * from the central locking logic. + */ + +static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + int error = 0; + + if (can_be_granted(r, lkb, TRUE)) { + grant_lock(r, lkb); + queue_cast(r, lkb, 0); + goto out; + } + + if (can_be_queued(lkb)) { + error = -EINPROGRESS; + add_lkb(r, lkb, DLM_LKSTS_WAITING); + send_blocking_asts(r, lkb); + goto out; + } + + error = -EAGAIN; + if (force_blocking_asts(lkb)) + send_blocking_asts_all(r, lkb); + queue_cast(r, lkb, -EAGAIN); + + out: + return error; +} + +static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + int error = 0; + + /* changing an existing lock may allow others to be granted */ + + if (can_be_granted(r, lkb, TRUE)) { + grant_lock(r, lkb); + queue_cast(r, lkb, 0); + grant_pending_locks(r); + goto out; + } + + if (can_be_queued(lkb)) { + if (is_demoted(lkb)) + grant_pending_locks(r); + error = -EINPROGRESS; + del_lkb(r, lkb); + add_lkb(r, lkb, DLM_LKSTS_CONVERT); + send_blocking_asts(r, lkb); + goto out; + } + + error = -EAGAIN; + if (force_blocking_asts(lkb)) + send_blocking_asts_all(r, lkb); + queue_cast(r, lkb, -EAGAIN); + + out: + return error; +} + +static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + remove_lock(r, lkb); + queue_cast(r, lkb, -DLM_EUNLOCK); + grant_pending_locks(r); + return -DLM_EUNLOCK; +} + +static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + revert_lock(r, lkb); + queue_cast(r, lkb, -DLM_ECANCEL); + grant_pending_locks(r); + return -DLM_ECANCEL; +} + +/* + * Four stage 3 varieties: + * _request_lock(), _convert_lock(), _unlock_lock(), _cancel_lock() + */ + +/* add a new lkb to a possibly new rsb, called by requesting process */ + +static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + int error; + + /* set_master: sets lkb nodeid from r */ + + error = set_master(r, lkb); + if (error < 0) + goto out; + if (error) { + error = 0; + goto out; + } + + if (is_remote(r)) + /* receive_request() calls do_request() on remote node */ + error = send_request(r, lkb); + else + error = do_request(r, lkb); + out: + return error; +} + +/* change some property of an existing lkb, e.g. mode, range */ + +static int _convert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + int error; + + if (is_remote(r)) + /* receive_convert() calls do_convert() on remote node */ + error = send_convert(r, lkb); + else + error = do_convert(r, lkb); + + return error; +} + +/* remove an existing lkb from the granted queue */ + +static int _unlock_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + int error; + + if (is_remote(r)) + /* receive_unlock() calls do_unlock() on remote node */ + error = send_unlock(r, lkb); + else + error = do_unlock(r, lkb); + + return error; +} + +/* remove an existing lkb from the convert or wait queue */ + +static int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + int error; + + if (is_remote(r)) + /* receive_cancel() calls do_cancel() on remote node */ + error = send_cancel(r, lkb); + else + error = do_cancel(r, lkb); + + return error; +} + +/* + * Four stage 2 varieties: + * request_lock(), convert_lock(), unlock_lock(), cancel_lock() + */ + +static int request_lock(struct dlm_ls *ls, struct dlm_lkb *lkb, char *name, + int len, struct dlm_args *args) +{ + struct dlm_rsb *r; + int error; + + error = validate_lock_args(ls, lkb, args); + if (error) + goto out; + + error = find_rsb(ls, name, len, R_CREATE, &r); + if (error) + goto out; + + lock_rsb(r); + + attach_lkb(r, lkb); + lkb->lkb_lksb->sb_lkid = lkb->lkb_id; + + error = _request_lock(r, lkb); + + unlock_rsb(r); + put_rsb(r); + + out: + return error; +} + +static int convert_lock(struct dlm_ls *ls, struct dlm_lkb *lkb, + struct dlm_args *args) +{ + struct dlm_rsb *r; + int error; + + r = lkb->lkb_resource; + + hold_rsb(r); + lock_rsb(r); + + error = validate_lock_args(ls, lkb, args); + if (error) + goto out; + + error = _convert_lock(r, lkb); + out: + unlock_rsb(r); + put_rsb(r); + return error; +} + +static int unlock_lock(struct dlm_ls *ls, struct dlm_lkb *lkb, + struct dlm_args *args) +{ + struct dlm_rsb *r; + int error; + + r = lkb->lkb_resource; + + hold_rsb(r); + lock_rsb(r); + + error = validate_unlock_args(lkb, args); + if (error) + goto out; + + error = _unlock_lock(r, lkb); + out: + unlock_rsb(r); + put_rsb(r); + return error; +} + +static int cancel_lock(struct dlm_ls *ls, struct dlm_lkb *lkb, + struct dlm_args *args) +{ + struct dlm_rsb *r; + int error; + + r = lkb->lkb_resource; + + hold_rsb(r); + lock_rsb(r); + + error = validate_unlock_args(lkb, args); + if (error) + goto out; + + error = _cancel_lock(r, lkb); + out: + unlock_rsb(r); + put_rsb(r); + return error; +} + +/* + * Two stage 1 varieties: dlm_lock() and dlm_unlock() + */ + +int dlm_lock(dlm_lockspace_t *lockspace, + int mode, + struct dlm_lksb *lksb, + uint32_t flags, + void *name, + unsigned int namelen, + uint32_t parent_lkid, + void (*ast) (void *astarg), + void *astarg, + void (*bast) (void *astarg, int mode), + struct dlm_range *range) +{ + struct dlm_ls *ls; + struct dlm_lkb *lkb; + struct dlm_args args; + int error, convert = flags & DLM_LKF_CONVERT; + + ls = dlm_find_lockspace_local(lockspace); + if (!ls) + return -EINVAL; + + lock_recovery(ls); + + if (convert) + error = find_lkb(ls, lksb->sb_lkid, &lkb); + else + error = create_lkb(ls, &lkb); + + if (error) + goto out; + + error = set_lock_args(mode, lksb, flags, namelen, parent_lkid, ast, + astarg, bast, range, &args); + if (error) + goto out_put; + + if (convert) + error = convert_lock(ls, lkb, &args); + else + error = request_lock(ls, lkb, name, namelen, &args); + + if (error == -EINPROGRESS) + error = 0; + out_put: + if (convert || error) + put_lkb(lkb); + if (error == -EAGAIN) + error = 0; + out: + unlock_recovery(ls); + dlm_put_lockspace(ls); + return error; +} + +int dlm_unlock(dlm_lockspace_t *lockspace, + uint32_t lkid, + uint32_t flags, + struct dlm_lksb *lksb, + void *astarg) +{ + struct dlm_ls *ls; + struct dlm_lkb *lkb; + struct dlm_args args; + int error; + + ls = dlm_find_lockspace_local(lockspace); + if (!ls) + return -EINVAL; + + lock_recovery(ls); + + error = find_lkb(ls, lkid, &lkb); + if (error) + goto out; + + error = set_unlock_args(flags, astarg, &args); + if (error) + goto out_put; + + if (flags & DLM_LKF_CANCEL) + error = cancel_lock(ls, lkb, &args); + else + error = unlock_lock(ls, lkb, &args); + + if (error == -DLM_EUNLOCK || error == -DLM_ECANCEL) + error = 0; + out_put: + put_lkb(lkb); + out: + unlock_recovery(ls); + dlm_put_lockspace(ls); + return error; +} + +/* + * send/receive routines for remote operations and replies + * + * send_args + * send_common + * send_request receive_request + * send_convert receive_convert + * send_unlock receive_unlock + * send_cancel receive_cancel + * send_grant receive_grant + * send_bast receive_bast + * send_lookup receive_lookup + * send_remove receive_remove + * + * send_common_reply + * receive_request_reply send_request_reply + * receive_convert_reply send_convert_reply + * receive_unlock_reply send_unlock_reply + * receive_cancel_reply send_cancel_reply + * receive_lookup_reply send_lookup_reply + */ + +static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb, + int to_nodeid, int mstype, + struct dlm_message **ms_ret, + struct dlm_mhandle **mh_ret) +{ + struct dlm_message *ms; + struct dlm_mhandle *mh; + char *mb; + int mb_len = sizeof(struct dlm_message); + + switch (mstype) { + case DLM_MSG_REQUEST: + case DLM_MSG_LOOKUP: + case DLM_MSG_REMOVE: + mb_len += r->res_length; + break; + case DLM_MSG_CONVERT: + case DLM_MSG_UNLOCK: + case DLM_MSG_REQUEST_REPLY: + case DLM_MSG_CONVERT_REPLY: + case DLM_MSG_GRANT: + if (lkb && lkb->lkb_lvbptr) + mb_len += r->res_ls->ls_lvblen; + break; + } + + /* get_buffer gives us a message handle (mh) that we need to + pass into lowcomms_commit and a message buffer (mb) that we + write our data into */ + + mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_KERNEL, &mb); + if (!mh) + return -ENOBUFS; + + memset(mb, 0, mb_len); + + ms = (struct dlm_message *) mb; + + ms->m_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR); + ms->m_header.h_lockspace = r->res_ls->ls_global_id; + ms->m_header.h_nodeid = dlm_our_nodeid(); + ms->m_header.h_length = mb_len; + ms->m_header.h_cmd = DLM_MSG; + + ms->m_type = mstype; + + *mh_ret = mh; + *ms_ret = ms; + return 0; +} + +/* further lowcomms enhancements or alternate implementations may make + the return value from this function useful at some point */ + +static int send_message(struct dlm_mhandle *mh, struct dlm_message *ms) +{ + dlm_message_out(ms); + dlm_lowcomms_commit_buffer(mh); + return 0; +} + +static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb, + struct dlm_message *ms) +{ + ms->m_nodeid = lkb->lkb_nodeid; + ms->m_pid = lkb->lkb_ownpid; + ms->m_lkid = lkb->lkb_id; + ms->m_remid = lkb->lkb_remid; + ms->m_exflags = lkb->lkb_exflags; + ms->m_sbflags = lkb->lkb_sbflags; + ms->m_flags = lkb->lkb_flags; + ms->m_lvbseq = lkb->lkb_lvbseq; + ms->m_status = lkb->lkb_status; + ms->m_grmode = lkb->lkb_grmode; + ms->m_rqmode = lkb->lkb_rqmode; + ms->m_hash = r->res_hash; + + /* m_result and m_bastmode are set from function args, + not from lkb fields */ + + if (lkb->lkb_bastaddr) + ms->m_asts |= AST_BAST; + if (lkb->lkb_astaddr) + ms->m_asts |= AST_COMP; + + if (lkb->lkb_range) { + ms->m_range[0] = lkb->lkb_range[RQ_RANGE_START]; + ms->m_range[1] = lkb->lkb_range[RQ_RANGE_END]; + } + + if (ms->m_type == DLM_MSG_REQUEST || ms->m_type == DLM_MSG_LOOKUP) + memcpy(ms->m_extra, r->res_name, r->res_length); + + else if (lkb->lkb_lvbptr) + memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen); + +} + +static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype) +{ + struct dlm_message *ms; + struct dlm_mhandle *mh; + int to_nodeid, error; + + add_to_waiters(lkb, mstype); + + to_nodeid = r->res_nodeid; + + error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh); + if (error) + goto fail; + + send_args(r, lkb, ms); + + error = send_message(mh, ms); + if (error) + goto fail; + return 0; + + fail: + remove_from_waiters(lkb); + return error; +} + +static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + return send_common(r, lkb, DLM_MSG_REQUEST); +} + +static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + int error; + + error = send_common(r, lkb, DLM_MSG_CONVERT); + + /* down conversions go without a reply from the master */ + if (!error && down_conversion(lkb)) { + remove_from_waiters(lkb); + r->res_ls->ls_stub_ms.m_result = 0; + __receive_convert_reply(r, lkb, &r->res_ls->ls_stub_ms); + } + + return error; +} + +/* FIXME: if this lkb is the only lock we hold on the rsb, then set + MASTER_UNCERTAIN to force the next request on the rsb to confirm + that the master is still correct. */ + +static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + return send_common(r, lkb, DLM_MSG_UNLOCK); +} + +static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + return send_common(r, lkb, DLM_MSG_CANCEL); +} + +static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + struct dlm_message *ms; + struct dlm_mhandle *mh; + int to_nodeid, error; + + to_nodeid = lkb->lkb_nodeid; + + error = create_message(r, lkb, to_nodeid, DLM_MSG_GRANT, &ms, &mh); + if (error) + goto out; + + send_args(r, lkb, ms); + + ms->m_result = 0; + + error = send_message(mh, ms); + out: + return error; +} + +static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode) +{ + struct dlm_message *ms; + struct dlm_mhandle *mh; + int to_nodeid, error; + + to_nodeid = lkb->lkb_nodeid; + + error = create_message(r, NULL, to_nodeid, DLM_MSG_BAST, &ms, &mh); + if (error) + goto out; + + send_args(r, lkb, ms); + + ms->m_bastmode = mode; + + error = send_message(mh, ms); + out: + return error; +} + +static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + struct dlm_message *ms; + struct dlm_mhandle *mh; + int to_nodeid, error; + + add_to_waiters(lkb, DLM_MSG_LOOKUP); + + to_nodeid = dlm_dir_nodeid(r); + + error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &ms, &mh); + if (error) + goto fail; + + send_args(r, lkb, ms); + + error = send_message(mh, ms); + if (error) + goto fail; + return 0; + + fail: + remove_from_waiters(lkb); + return error; +} + +static int send_remove(struct dlm_rsb *r) +{ + struct dlm_message *ms; + struct dlm_mhandle *mh; + int to_nodeid, error; + + to_nodeid = dlm_dir_nodeid(r); + + error = create_message(r, NULL, to_nodeid, DLM_MSG_REMOVE, &ms, &mh); + if (error) + goto out; + + memcpy(ms->m_extra, r->res_name, r->res_length); + ms->m_hash = r->res_hash; + + error = send_message(mh, ms); + out: + return error; +} + +static int send_common_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, + int mstype, int rv) +{ + struct dlm_message *ms; + struct dlm_mhandle *mh; + int to_nodeid, error; + + to_nodeid = lkb->lkb_nodeid; + + error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh); + if (error) + goto out; + + send_args(r, lkb, ms); + + ms->m_result = rv; + + error = send_message(mh, ms); + out: + return error; +} + +static int send_request_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv) +{ + return send_common_reply(r, lkb, DLM_MSG_REQUEST_REPLY, rv); +} + +static int send_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv) +{ + return send_common_reply(r, lkb, DLM_MSG_CONVERT_REPLY, rv); +} + +static int send_unlock_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv) +{ + return send_common_reply(r, lkb, DLM_MSG_UNLOCK_REPLY, rv); +} + +static int send_cancel_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv) +{ + return send_common_reply(r, lkb, DLM_MSG_CANCEL_REPLY, rv); +} + +static int send_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms_in, + int ret_nodeid, int rv) +{ + struct dlm_rsb *r = &ls->ls_stub_rsb; + struct dlm_message *ms; + struct dlm_mhandle *mh; + int error, nodeid = ms_in->m_header.h_nodeid; + + error = create_message(r, NULL, nodeid, DLM_MSG_LOOKUP_REPLY, &ms, &mh); + if (error) + goto out; + + ms->m_lkid = ms_in->m_lkid; + ms->m_result = rv; + ms->m_nodeid = ret_nodeid; + + error = send_message(mh, ms); + out: + return error; +} + +/* which args we save from a received message depends heavily on the type + of message, unlike the send side where we can safely send everything about + the lkb for any type of message */ + +static void receive_flags(struct dlm_lkb *lkb, struct dlm_message *ms) +{ + lkb->lkb_exflags = ms->m_exflags; + lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) | + (ms->m_flags & 0x0000FFFF); +} + +static void receive_flags_reply(struct dlm_lkb *lkb, struct dlm_message *ms) +{ + lkb->lkb_sbflags = ms->m_sbflags; + lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) | + (ms->m_flags & 0x0000FFFF); +} + +static int receive_extralen(struct dlm_message *ms) +{ + return (ms->m_header.h_length - sizeof(struct dlm_message)); +} + +static int receive_range(struct dlm_ls *ls, struct dlm_lkb *lkb, + struct dlm_message *ms) +{ + if (lkb->lkb_flags & DLM_IFL_RANGE) { + if (!lkb->lkb_range) + lkb->lkb_range = allocate_range(ls); + if (!lkb->lkb_range) + return -ENOMEM; + lkb->lkb_range[RQ_RANGE_START] = ms->m_range[0]; + lkb->lkb_range[RQ_RANGE_END] = ms->m_range[1]; + } + return 0; +} + +static int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb, + struct dlm_message *ms) +{ + int len; + + if (lkb->lkb_exflags & DLM_LKF_VALBLK) { + if (!lkb->lkb_lvbptr) + lkb->lkb_lvbptr = allocate_lvb(ls); + if (!lkb->lkb_lvbptr) + return -ENOMEM; + len = receive_extralen(ms); + memcpy(lkb->lkb_lvbptr, ms->m_extra, len); + } + return 0; +} + +static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb, + struct dlm_message *ms) +{ + lkb->lkb_nodeid = ms->m_header.h_nodeid; + lkb->lkb_ownpid = ms->m_pid; + lkb->lkb_remid = ms->m_lkid; + lkb->lkb_grmode = DLM_LOCK_IV; + lkb->lkb_rqmode = ms->m_rqmode; + lkb->lkb_bastaddr = (void *) (long) (ms->m_asts & AST_BAST); + lkb->lkb_astaddr = (void *) (long) (ms->m_asts & AST_COMP); + + DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb);); + + if (receive_range(ls, lkb, ms)) + return -ENOMEM; + + if (receive_lvb(ls, lkb, ms)) + return -ENOMEM; + + return 0; +} + +static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb, + struct dlm_message *ms) +{ + if (lkb->lkb_nodeid != ms->m_header.h_nodeid) { + log_error(ls, "convert_args nodeid %d %d lkid %x %x", + lkb->lkb_nodeid, ms->m_header.h_nodeid, + lkb->lkb_id, lkb->lkb_remid); + return -EINVAL; + } + + if (!is_master_copy(lkb)) + return -EINVAL; + + if (lkb->lkb_status != DLM_LKSTS_GRANTED) + return -EBUSY; + + if (receive_range(ls, lkb, ms)) + return -ENOMEM; + if (lkb->lkb_range) { + lkb->lkb_range[GR_RANGE_START] = 0LL; + lkb->lkb_range[GR_RANGE_END] = 0xffffffffffffffffULL; + } + + if (receive_lvb(ls, lkb, ms)) + return -ENOMEM; + + lkb->lkb_rqmode = ms->m_rqmode; + lkb->lkb_lvbseq = ms->m_lvbseq; + + return 0; +} + +static int receive_unlock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, + struct dlm_message *ms) +{ + if (!is_master_copy(lkb)) + return -EINVAL; + if (receive_lvb(ls, lkb, ms)) + return -ENOMEM; + return 0; +} + +/* We fill in the stub-lkb fields with the info that send_xxxx_reply() + uses to send a reply and that the remote end uses to process the reply. */ + +static void setup_stub_lkb(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb = &ls->ls_stub_lkb; + lkb->lkb_nodeid = ms->m_header.h_nodeid; + lkb->lkb_remid = ms->m_lkid; +} + +static void receive_request(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + struct dlm_rsb *r; + int error, namelen; + + error = create_lkb(ls, &lkb); + if (error) + goto fail; + + receive_flags(lkb, ms); + lkb->lkb_flags |= DLM_IFL_MSTCPY; + error = receive_request_args(ls, lkb, ms); + if (error) { + put_lkb(lkb); + goto fail; + } + + namelen = receive_extralen(ms); + + error = find_rsb(ls, ms->m_extra, namelen, R_MASTER, &r); + if (error) { + put_lkb(lkb); + goto fail; + } + + lock_rsb(r); + + attach_lkb(r, lkb); + error = do_request(r, lkb); + send_request_reply(r, lkb, error); + + unlock_rsb(r); + put_rsb(r); + + if (error == -EINPROGRESS) + error = 0; + if (error) + put_lkb(lkb); + return; + + fail: + setup_stub_lkb(ls, ms); + send_request_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error); +} + +static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + struct dlm_rsb *r; + int error, reply = TRUE; + + error = find_lkb(ls, ms->m_remid, &lkb); + if (error) + goto fail; + + r = lkb->lkb_resource; + + hold_rsb(r); + lock_rsb(r); + + receive_flags(lkb, ms); + error = receive_convert_args(ls, lkb, ms); + if (error) + goto out; + reply = !down_conversion(lkb); + + error = do_convert(r, lkb); + out: + if (reply) + send_convert_reply(r, lkb, error); + + unlock_rsb(r); + put_rsb(r); + put_lkb(lkb); + return; + + fail: + setup_stub_lkb(ls, ms); + send_convert_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error); +} + +static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + struct dlm_rsb *r; + int error; + + error = find_lkb(ls, ms->m_remid, &lkb); + if (error) + goto fail; + + r = lkb->lkb_resource; + + hold_rsb(r); + lock_rsb(r); + + receive_flags(lkb, ms); + error = receive_unlock_args(ls, lkb, ms); + if (error) + goto out; + + error = do_unlock(r, lkb); + out: + send_unlock_reply(r, lkb, error); + + unlock_rsb(r); + put_rsb(r); + put_lkb(lkb); + return; + + fail: + setup_stub_lkb(ls, ms); + send_unlock_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error); +} + +static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + struct dlm_rsb *r; + int error; + + error = find_lkb(ls, ms->m_remid, &lkb); + if (error) + goto fail; + + receive_flags(lkb, ms); + + r = lkb->lkb_resource; + + hold_rsb(r); + lock_rsb(r); + + error = do_cancel(r, lkb); + send_cancel_reply(r, lkb, error); + + unlock_rsb(r); + put_rsb(r); + put_lkb(lkb); + return; + + fail: + setup_stub_lkb(ls, ms); + send_cancel_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error); +} + +static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + struct dlm_rsb *r; + int error; + + error = find_lkb(ls, ms->m_remid, &lkb); + if (error) { + log_error(ls, "receive_grant no lkb"); + return; + } + DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); + + r = lkb->lkb_resource; + + hold_rsb(r); + lock_rsb(r); + + receive_flags_reply(lkb, ms); + grant_lock_pc(r, lkb, ms); + queue_cast(r, lkb, 0); + + unlock_rsb(r); + put_rsb(r); + put_lkb(lkb); +} + +static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + struct dlm_rsb *r; + int error; + + error = find_lkb(ls, ms->m_remid, &lkb); + if (error) { + log_error(ls, "receive_bast no lkb"); + return; + } + DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); + + r = lkb->lkb_resource; + + hold_rsb(r); + lock_rsb(r); + + queue_bast(r, lkb, ms->m_bastmode); + + unlock_rsb(r); + put_rsb(r); + put_lkb(lkb); +} + +static void receive_lookup(struct dlm_ls *ls, struct dlm_message *ms) +{ + int len, error, ret_nodeid, dir_nodeid, from_nodeid, our_nodeid; + + from_nodeid = ms->m_header.h_nodeid; + our_nodeid = dlm_our_nodeid(); + + len = receive_extralen(ms); + + dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash); + if (dir_nodeid != our_nodeid) { + log_error(ls, "lookup dir_nodeid %d from %d", + dir_nodeid, from_nodeid); + error = -EINVAL; + ret_nodeid = -1; + goto out; + } + + error = dlm_dir_lookup(ls, from_nodeid, ms->m_extra, len, &ret_nodeid); + + /* Optimization: we're master so treat lookup as a request */ + if (!error && ret_nodeid == our_nodeid) { + receive_request(ls, ms); + return; + } + out: + send_lookup_reply(ls, ms, ret_nodeid, error); +} + +static void receive_remove(struct dlm_ls *ls, struct dlm_message *ms) +{ + int len, dir_nodeid, from_nodeid; + + from_nodeid = ms->m_header.h_nodeid; + + len = receive_extralen(ms); + + dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash); + if (dir_nodeid != dlm_our_nodeid()) { + log_error(ls, "remove dir entry dir_nodeid %d from %d", + dir_nodeid, from_nodeid); + return; + } + + dlm_dir_remove_entry(ls, from_nodeid, ms->m_extra, len); +} + +static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + struct dlm_rsb *r; + int error, mstype; + + error = find_lkb(ls, ms->m_remid, &lkb); + if (error) { + log_error(ls, "receive_request_reply no lkb"); + return; + } + DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); + + mstype = lkb->lkb_wait_type; + error = remove_from_waiters(lkb); + if (error) { + log_error(ls, "receive_request_reply not on waiters"); + goto out; + } + + /* this is the value returned from do_request() on the master */ + error = ms->m_result; + + r = lkb->lkb_resource; + hold_rsb(r); + lock_rsb(r); + + /* Optimization: the dir node was also the master, so it took our + lookup as a request and sent request reply instead of lookup reply */ + if (mstype == DLM_MSG_LOOKUP) { + r->res_nodeid = ms->m_header.h_nodeid; + lkb->lkb_nodeid = r->res_nodeid; + } + + switch (error) { + case -EAGAIN: + /* request would block (be queued) on remote master; + the unhold undoes the original ref from create_lkb() + so it leads to the lkb being freed */ + queue_cast(r, lkb, -EAGAIN); + confirm_master(r, -EAGAIN); + unhold_lkb(lkb); + break; + + case -EINPROGRESS: + case 0: + /* request was queued or granted on remote master */ + receive_flags_reply(lkb, ms); + lkb->lkb_remid = ms->m_lkid; + if (error) + add_lkb(r, lkb, DLM_LKSTS_WAITING); + else { + grant_lock_pc(r, lkb, ms); + queue_cast(r, lkb, 0); + } + confirm_master(r, error); + break; + + case -ENOENT: + case -ENOTBLK: + /* find_rsb failed to find rsb or rsb wasn't master */ + r->res_nodeid = -1; + lkb->lkb_nodeid = -1; + _request_lock(r, lkb); + break; + + default: + log_error(ls, "receive_request_reply error %d", error); + } + + unlock_rsb(r); + put_rsb(r); + out: + put_lkb(lkb); +} + +static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, + struct dlm_message *ms) +{ + int error = ms->m_result; + + /* this is the value returned from do_convert() on the master */ + + switch (error) { + case -EAGAIN: + /* convert would block (be queued) on remote master */ + queue_cast(r, lkb, -EAGAIN); + break; + + case -EINPROGRESS: + /* convert was queued on remote master */ + del_lkb(r, lkb); + add_lkb(r, lkb, DLM_LKSTS_CONVERT); + break; + + case 0: + /* convert was granted on remote master */ + receive_flags_reply(lkb, ms); + grant_lock_pc(r, lkb, ms); + queue_cast(r, lkb, 0); + break; + + default: + log_error(r->res_ls, "receive_convert_reply error %d", error); + } +} + +static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms) +{ + struct dlm_rsb *r = lkb->lkb_resource; + + hold_rsb(r); + lock_rsb(r); + + __receive_convert_reply(r, lkb, ms); + + unlock_rsb(r); + put_rsb(r); +} + +static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + int error; + + error = find_lkb(ls, ms->m_remid, &lkb); + if (error) { + log_error(ls, "receive_convert_reply no lkb"); + return; + } + DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); + + error = remove_from_waiters(lkb); + if (error) { + log_error(ls, "receive_convert_reply not on waiters"); + goto out; + } + + _receive_convert_reply(lkb, ms); + out: + put_lkb(lkb); +} + +static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms) +{ + struct dlm_rsb *r = lkb->lkb_resource; + int error = ms->m_result; + + hold_rsb(r); + lock_rsb(r); + + /* this is the value returned from do_unlock() on the master */ + + switch (error) { + case -DLM_EUNLOCK: + receive_flags_reply(lkb, ms); + remove_lock_pc(r, lkb); + queue_cast(r, lkb, -DLM_EUNLOCK); + break; + default: + log_error(r->res_ls, "receive_unlock_reply error %d", error); + } + + unlock_rsb(r); + put_rsb(r); +} + +static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + int error; + + error = find_lkb(ls, ms->m_remid, &lkb); + if (error) { + log_error(ls, "receive_unlock_reply no lkb"); + return; + } + DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); + + error = remove_from_waiters(lkb); + if (error) { + log_error(ls, "receive_unlock_reply not on waiters"); + goto out; + } + + _receive_unlock_reply(lkb, ms); + out: + put_lkb(lkb); +} + +static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms) +{ + struct dlm_rsb *r = lkb->lkb_resource; + int error = ms->m_result; + + hold_rsb(r); + lock_rsb(r); + + /* this is the value returned from do_cancel() on the master */ + + switch (error) { + case -DLM_ECANCEL: + receive_flags_reply(lkb, ms); + revert_lock_pc(r, lkb); + queue_cast(r, lkb, -DLM_ECANCEL); + break; + default: + log_error(r->res_ls, "receive_cancel_reply error %d", error); + } + + unlock_rsb(r); + put_rsb(r); +} + +static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + int error; + + error = find_lkb(ls, ms->m_remid, &lkb); + if (error) { + log_error(ls, "receive_cancel_reply no lkb"); + return; + } + DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); + + error = remove_from_waiters(lkb); + if (error) { + log_error(ls, "receive_cancel_reply not on waiters"); + goto out; + } + + _receive_cancel_reply(lkb, ms); + out: + put_lkb(lkb); +} + +static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms) +{ + struct dlm_lkb *lkb; + struct dlm_rsb *r; + int error, ret_nodeid; + + error = find_lkb(ls, ms->m_lkid, &lkb); + if (error) { + log_error(ls, "receive_lookup_reply no lkb"); + return; + } + + error = remove_from_waiters(lkb); + if (error) { + log_error(ls, "receive_lookup_reply not on waiters"); + goto out; + } + + /* this is the value returned by dlm_dir_lookup on dir node + FIXME: will a non-zero error ever be returned? */ + error = ms->m_result; + + r = lkb->lkb_resource; + hold_rsb(r); + lock_rsb(r); + + ret_nodeid = ms->m_nodeid; + if (ret_nodeid == dlm_our_nodeid()) { + r->res_nodeid = 0; + ret_nodeid = 0; + r->res_first_lkid = 0; + } else { + /* set_master() will copy res_nodeid to lkb_nodeid */ + r->res_nodeid = ret_nodeid; + } + + _request_lock(r, lkb); + + if (!ret_nodeid) + process_lookup_list(r); + + unlock_rsb(r); + put_rsb(r); + out: + put_lkb(lkb); +} + +int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery) +{ + struct dlm_message *ms = (struct dlm_message *) hd; + struct dlm_ls *ls; + int error; + + if (!recovery) + dlm_message_in(ms); + + ls = dlm_find_lockspace_global(hd->h_lockspace); + if (!ls) { + log_print("drop message %d from %d for unknown lockspace %d", + ms->m_type, nodeid, hd->h_lockspace); + return -EINVAL; + } + + /* recovery may have just ended leaving a bunch of backed-up requests + in the requestqueue; wait while dlm_recoverd clears them */ + + if (!recovery) + dlm_wait_requestqueue(ls); + + /* recovery may have just started while there were a bunch of + in-flight requests -- save them in requestqueue to be processed + after recovery. we can't let dlm_recvd block on the recovery + lock. if dlm_recoverd is calling this function to clear the + requestqueue, it needs to be interrupted (-EINTR) if another + recovery operation is starting. */ + + while (1) { + if (dlm_locking_stopped(ls)) { + if (!recovery) + dlm_add_requestqueue(ls, nodeid, hd); + error = -EINTR; + goto out; + } + + if (lock_recovery_try(ls)) + break; + schedule(); + } + + switch (ms->m_type) { + + /* messages sent to a master node */ + + case DLM_MSG_REQUEST: + receive_request(ls, ms); + break; + + case DLM_MSG_CONVERT: + receive_convert(ls, ms); + break; + + case DLM_MSG_UNLOCK: + receive_unlock(ls, ms); + break; + + case DLM_MSG_CANCEL: + receive_cancel(ls, ms); + break; + + /* messages sent from a master node (replies to above) */ + + case DLM_MSG_REQUEST_REPLY: + receive_request_reply(ls, ms); + break; + + case DLM_MSG_CONVERT_REPLY: + receive_convert_reply(ls, ms); + break; + + case DLM_MSG_UNLOCK_REPLY: + receive_unlock_reply(ls, ms); + break; + + case DLM_MSG_CANCEL_REPLY: + receive_cancel_reply(ls, ms); + break; + + /* messages sent from a master node (only two types of async msg) */ + + case DLM_MSG_GRANT: + receive_grant(ls, ms); + break; + + case DLM_MSG_BAST: + receive_bast(ls, ms); + break; + + /* messages sent to a dir node */ + + case DLM_MSG_LOOKUP: + receive_lookup(ls, ms); + break; + + case DLM_MSG_REMOVE: + receive_remove(ls, ms); + break; + + /* messages sent from a dir node (remove has no reply) */ + + case DLM_MSG_LOOKUP_REPLY: + receive_lookup_reply(ls, ms); + break; + + default: + log_error(ls, "unknown message type %d", ms->m_type); + } + + unlock_recovery(ls); + out: + dlm_put_lockspace(ls); + dlm_astd_wake(); + return 0; +} + + +/* + * Recovery related + */ + +static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb) +{ + if (middle_conversion(lkb)) { + hold_lkb(lkb); + ls->ls_stub_ms.m_result = -EINPROGRESS; + _remove_from_waiters(lkb); + _receive_convert_reply(lkb, &ls->ls_stub_ms); + + /* Same special case as in receive_rcom_lock_args() */ + lkb->lkb_grmode = DLM_LOCK_IV; + rsb_set_flag(lkb->lkb_resource, RSB_RECOVER_CONVERT); + unhold_lkb(lkb); + + } else if (lkb->lkb_rqmode >= lkb->lkb_grmode) { + lkb->lkb_flags |= DLM_IFL_RESEND; + } + + /* lkb->lkb_rqmode < lkb->lkb_grmode shouldn't happen since down + conversions are async; there's no reply from the remote master */ +} + +/* A waiting lkb needs recovery if the master node has failed, or + the master node is changing (only when no directory is used) */ + +static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb) +{ + if (dlm_is_removed(ls, lkb->lkb_nodeid)) + return 1; + + if (!dlm_no_directory(ls)) + return 0; + + if (dlm_dir_nodeid(lkb->lkb_resource) != lkb->lkb_nodeid) + return 1; + + return 0; +} + +/* Recovery for locks that are waiting for replies from nodes that are now + gone. We can just complete unlocks and cancels by faking a reply from the + dead node. Requests and up-conversions we flag to be resent after + recovery. Down-conversions can just be completed with a fake reply like + unlocks. Conversions between PR and CW need special attention. */ + +void dlm_recover_waiters_pre(struct dlm_ls *ls) +{ + struct dlm_lkb *lkb, *safe; + + down(&ls->ls_waiters_sem); + + list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) { + log_debug(ls, "pre recover waiter lkid %x type %d flags %x", + lkb->lkb_id, lkb->lkb_wait_type, lkb->lkb_flags); + + /* all outstanding lookups, regardless of destination will be + resent after recovery is done */ + + if (lkb->lkb_wait_type == DLM_MSG_LOOKUP) { + lkb->lkb_flags |= DLM_IFL_RESEND; + continue; + } + + if (!waiter_needs_recovery(ls, lkb)) + continue; + + switch (lkb->lkb_wait_type) { + + case DLM_MSG_REQUEST: + lkb->lkb_flags |= DLM_IFL_RESEND; + break; + + case DLM_MSG_CONVERT: + recover_convert_waiter(ls, lkb); + break; + + case DLM_MSG_UNLOCK: + hold_lkb(lkb); + ls->ls_stub_ms.m_result = -DLM_EUNLOCK; + _remove_from_waiters(lkb); + _receive_unlock_reply(lkb, &ls->ls_stub_ms); + put_lkb(lkb); + break; + + case DLM_MSG_CANCEL: + hold_lkb(lkb); + ls->ls_stub_ms.m_result = -DLM_ECANCEL; + _remove_from_waiters(lkb); + _receive_cancel_reply(lkb, &ls->ls_stub_ms); + put_lkb(lkb); + break; + + default: + log_error(ls, "invalid lkb wait_type %d", + lkb->lkb_wait_type); + } + } + up(&ls->ls_waiters_sem); +} + +static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) +{ + struct dlm_lkb *lkb; + int rv = 0; + + down(&ls->ls_waiters_sem); + list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) { + if (lkb->lkb_flags & DLM_IFL_RESEND) { + rv = lkb->lkb_wait_type; + _remove_from_waiters(lkb); + lkb->lkb_flags &= ~DLM_IFL_RESEND; + break; + } + } + up(&ls->ls_waiters_sem); + + if (!rv) + lkb = NULL; + *lkb_ret = lkb; + return rv; +} + +/* Deal with lookups and lkb's marked RESEND from _pre. We may now be the + master or dir-node for r. Processing the lkb may result in it being placed + back on waiters. */ + +int dlm_recover_waiters_post(struct dlm_ls *ls) +{ + struct dlm_lkb *lkb; + struct dlm_rsb *r; + int error = 0, mstype; + + while (1) { + if (dlm_locking_stopped(ls)) { + log_debug(ls, "recover_waiters_post aborted"); + error = -EINTR; + break; + } + + mstype = remove_resend_waiter(ls, &lkb); + if (!mstype) + break; + + r = lkb->lkb_resource; + + log_debug(ls, "recover_waiters_post %x type %d flags %x %s", + lkb->lkb_id, mstype, lkb->lkb_flags, r->res_name); + + switch (mstype) { + + case DLM_MSG_LOOKUP: + hold_rsb(r); + lock_rsb(r); + _request_lock(r, lkb); + if (is_master(r)) + confirm_master(r, 0); + unlock_rsb(r); + put_rsb(r); + break; + + case DLM_MSG_REQUEST: + hold_rsb(r); + lock_rsb(r); + _request_lock(r, lkb); + unlock_rsb(r); + put_rsb(r); + break; + + case DLM_MSG_CONVERT: + hold_rsb(r); + lock_rsb(r); + _convert_lock(r, lkb); + unlock_rsb(r); + put_rsb(r); + break; + + default: + log_error(ls, "recover_waiters_post type %d", mstype); + } + } + + return error; +} + +static void purge_queue(struct dlm_rsb *r, struct list_head *queue, + int (*test)(struct dlm_ls *ls, struct dlm_lkb *lkb)) +{ + struct dlm_ls *ls = r->res_ls; + struct dlm_lkb *lkb, *safe; + + list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) { + if (test(ls, lkb)) { + del_lkb(r, lkb); + /* this put should free the lkb */ + if (!put_lkb(lkb)) + log_error(ls, "purged lkb not released"); + } + } +} + +static int purge_dead_test(struct dlm_ls *ls, struct dlm_lkb *lkb) +{ + return (is_master_copy(lkb) && dlm_is_removed(ls, lkb->lkb_nodeid)); +} + +static int purge_mstcpy_test(struct dlm_ls *ls, struct dlm_lkb *lkb) +{ + return is_master_copy(lkb); +} + +static void purge_dead_locks(struct dlm_rsb *r) +{ + purge_queue(r, &r->res_grantqueue, &purge_dead_test); + purge_queue(r, &r->res_convertqueue, &purge_dead_test); + purge_queue(r, &r->res_waitqueue, &purge_dead_test); +} + +void dlm_purge_mstcpy_locks(struct dlm_rsb *r) +{ + purge_queue(r, &r->res_grantqueue, &purge_mstcpy_test); + purge_queue(r, &r->res_convertqueue, &purge_mstcpy_test); + purge_queue(r, &r->res_waitqueue, &purge_mstcpy_test); +} + +/* Get rid of locks held by nodes that are gone. */ + +int dlm_purge_locks(struct dlm_ls *ls) +{ + struct dlm_rsb *r; + + log_debug(ls, "dlm_purge_locks"); + + down_write(&ls->ls_root_sem); + list_for_each_entry(r, &ls->ls_root_list, res_root_list) { + hold_rsb(r); + lock_rsb(r); + if (is_master(r)) + purge_dead_locks(r); + unlock_rsb(r); + unhold_rsb(r); + + schedule(); + } + up_write(&ls->ls_root_sem); + + return 0; +} + +int dlm_grant_after_purge(struct dlm_ls *ls) +{ + struct dlm_rsb *r; + int i; + + for (i = 0; i < ls->ls_rsbtbl_size; i++) { + read_lock(&ls->ls_rsbtbl[i].lock); + list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) { + hold_rsb(r); + lock_rsb(r); + if (is_master(r)) { + grant_pending_locks(r); + confirm_master(r, 0); + } + unlock_rsb(r); + put_rsb(r); + } + read_unlock(&ls->ls_rsbtbl[i].lock); + } + + return 0; +} + +static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid, + uint32_t remid) +{ + struct dlm_lkb *lkb; + + list_for_each_entry(lkb, head, lkb_statequeue) { + if (lkb->lkb_nodeid == nodeid && lkb->lkb_remid == remid) + return lkb; + } + return NULL; +} + +static struct dlm_lkb *search_remid(struct dlm_rsb *r, int nodeid, + uint32_t remid) +{ + struct dlm_lkb *lkb; + + lkb = search_remid_list(&r->res_grantqueue, nodeid, remid); + if (lkb) + return lkb; + lkb = search_remid_list(&r->res_convertqueue, nodeid, remid); + if (lkb) + return lkb; + lkb = search_remid_list(&r->res_waitqueue, nodeid, remid); + if (lkb) + return lkb; + return NULL; +} + +static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, + struct dlm_rsb *r, struct dlm_rcom *rc) +{ + struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf; + int lvblen; + + lkb->lkb_nodeid = rc->rc_header.h_nodeid; + lkb->lkb_ownpid = rl->rl_ownpid; + lkb->lkb_remid = rl->rl_lkid; + lkb->lkb_exflags = rl->rl_exflags; + lkb->lkb_flags = rl->rl_flags & 0x0000FFFF; + lkb->lkb_flags |= DLM_IFL_MSTCPY; + lkb->lkb_lvbseq = rl->rl_lvbseq; + lkb->lkb_rqmode = rl->rl_rqmode; + lkb->lkb_grmode = rl->rl_grmode; + /* don't set lkb_status because add_lkb wants to itself */ + + lkb->lkb_bastaddr = (void *) (long) (rl->rl_asts & AST_BAST); + lkb->lkb_astaddr = (void *) (long) (rl->rl_asts & AST_COMP); + + if (lkb->lkb_flags & DLM_IFL_RANGE) { + lkb->lkb_range = allocate_range(ls); + if (!lkb->lkb_range) + return -ENOMEM; + memcpy(lkb->lkb_range, rl->rl_range, 4*sizeof(uint64_t)); + } + + if (lkb->lkb_exflags & DLM_LKF_VALBLK) { + lkb->lkb_lvbptr = allocate_lvb(ls); + if (!lkb->lkb_lvbptr) + return -ENOMEM; + lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) - + sizeof(struct rcom_lock); + memcpy(lkb->lkb_lvbptr, rl->rl_lvb, lvblen); + } + + /* Conversions between PR and CW (middle modes) need special handling. + The real granted mode of these converting locks cannot be determined + until all locks have been rebuilt on the rsb (recover_conversion) */ + + if (rl->rl_wait_type == DLM_MSG_CONVERT && middle_conversion(lkb)) { + rl->rl_status = DLM_LKSTS_CONVERT; + lkb->lkb_grmode = DLM_LOCK_IV; + rsb_set_flag(r, RSB_RECOVER_CONVERT); + } + + return 0; +} + +/* This lkb may have been recovered in a previous aborted recovery so we need + to check if the rsb already has an lkb with the given remote nodeid/lkid. + If so we just send back a standard reply. If not, we create a new lkb with + the given values and send back our lkid. We send back our lkid by sending + back the rcom_lock struct we got but with the remid field filled in. */ + +int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc) +{ + struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf; + struct dlm_rsb *r; + struct dlm_lkb *lkb; + int error; + + if (rl->rl_parent_lkid) { + error = -EOPNOTSUPP; + goto out; + } + + error = find_rsb(ls, rl->rl_name, rl->rl_namelen, R_MASTER, &r); + if (error) + goto out; + + lock_rsb(r); + + lkb = search_remid(r, rc->rc_header.h_nodeid, rl->rl_lkid); + if (lkb) { + error = -EEXIST; + goto out_remid; + } + + error = create_lkb(ls, &lkb); + if (error) + goto out_unlock; + + error = receive_rcom_lock_args(ls, lkb, r, rc); + if (error) { + put_lkb(lkb); + goto out_unlock; + } + + attach_lkb(r, lkb); + add_lkb(r, lkb, rl->rl_status); + error = 0; + + out_remid: + /* this is the new value returned to the lock holder for + saving in its process-copy lkb */ + rl->rl_remid = lkb->lkb_id; + + out_unlock: + unlock_rsb(r); + put_rsb(r); + out: + if (error) + log_print("recover_master_copy %d %x", error, rl->rl_lkid); + rl->rl_result = error; + return error; +} + +int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc) +{ + struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf; + struct dlm_rsb *r; + struct dlm_lkb *lkb; + int error; + + error = find_lkb(ls, rl->rl_lkid, &lkb); + if (error) { + log_error(ls, "recover_process_copy no lkid %x", rl->rl_lkid); + return error; + } + + DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb);); + + error = rl->rl_result; + + r = lkb->lkb_resource; + hold_rsb(r); + lock_rsb(r); + + switch (error) { + case -EEXIST: + log_debug(ls, "master copy exists %x", lkb->lkb_id); + /* fall through */ + case 0: + lkb->lkb_remid = rl->rl_remid; + break; + default: + log_error(ls, "dlm_recover_process_copy unknown error %d %x", + error, lkb->lkb_id); + } + + /* an ack for dlm_recover_locks() which waits for replies from + all the locks it sends to new masters */ + dlm_recovered_lock(r); + + unlock_rsb(r); + put_rsb(r); + put_lkb(lkb); + + return 0; +} + diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h new file mode 100644 index 000000000000..9e6499f773da --- /dev/null +++ b/fs/dlm/lock.h @@ -0,0 +1,50 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __LOCK_DOT_H__ +#define __LOCK_DOT_H__ + +void dlm_print_rsb(struct dlm_rsb *r); +int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery); +int dlm_modes_compat(int mode1, int mode2); +int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen, + unsigned int flags, struct dlm_rsb **r_ret); +void dlm_put_rsb(struct dlm_rsb *r); +void dlm_hold_rsb(struct dlm_rsb *r); +int dlm_put_lkb(struct dlm_lkb *lkb); +void dlm_scan_rsbs(struct dlm_ls *ls); + +int dlm_purge_locks(struct dlm_ls *ls); +void dlm_purge_mstcpy_locks(struct dlm_rsb *r); +int dlm_grant_after_purge(struct dlm_ls *ls); +int dlm_recover_waiters_post(struct dlm_ls *ls); +void dlm_recover_waiters_pre(struct dlm_ls *ls); +int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc); +int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc); + +static inline int is_master(struct dlm_rsb *r) +{ + return !r->res_nodeid; +} + +static inline void lock_rsb(struct dlm_rsb *r) +{ + down(&r->res_sem); +} + +static inline void unlock_rsb(struct dlm_rsb *r) +{ + up(&r->res_sem); +} + +#endif + diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c new file mode 100644 index 000000000000..fee4659b6582 --- /dev/null +++ b/fs/dlm/lockspace.c @@ -0,0 +1,666 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "lockspace.h" +#include "member.h" +#include "recoverd.h" +#include "ast.h" +#include "dir.h" +#include "lowcomms.h" +#include "config.h" +#include "memory.h" +#include "lock.h" + +#ifdef CONFIG_DLM_DEBUG +int dlm_create_debug_file(struct dlm_ls *ls); +void dlm_delete_debug_file(struct dlm_ls *ls); +#else +static inline int dlm_create_debug_file(struct dlm_ls *ls) { return 0; } +static inline void dlm_delete_debug_file(struct dlm_ls *ls) { } +#endif + +static int ls_count; +static struct semaphore ls_lock; +static struct list_head lslist; +static spinlock_t lslist_lock; +static struct task_struct * scand_task; + + +static ssize_t dlm_control_store(struct dlm_ls *ls, const char *buf, size_t len) +{ + ssize_t ret = len; + int n = simple_strtol(buf, NULL, 0); + + switch (n) { + case 0: + dlm_ls_stop(ls); + break; + case 1: + dlm_ls_start(ls); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static ssize_t dlm_event_store(struct dlm_ls *ls, const char *buf, size_t len) +{ + ls->ls_uevent_result = simple_strtol(buf, NULL, 0); + set_bit(LSFL_UEVENT_WAIT, &ls->ls_flags); + wake_up(&ls->ls_uevent_wait); + return len; +} + +static ssize_t dlm_id_show(struct dlm_ls *ls, char *buf) +{ + return sprintf(buf, "%u\n", ls->ls_global_id); +} + +static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len) +{ + ls->ls_global_id = simple_strtoul(buf, NULL, 0); + return len; +} + +struct dlm_attr { + struct attribute attr; + ssize_t (*show)(struct dlm_ls *, char *); + ssize_t (*store)(struct dlm_ls *, const char *, size_t); +}; + +static struct dlm_attr dlm_attr_control = { + .attr = {.name = "control", .mode = S_IWUSR}, + .store = dlm_control_store +}; + +static struct dlm_attr dlm_attr_event = { + .attr = {.name = "event_done", .mode = S_IWUSR}, + .store = dlm_event_store +}; + +static struct dlm_attr dlm_attr_id = { + .attr = {.name = "id", .mode = S_IRUGO | S_IWUSR}, + .show = dlm_id_show, + .store = dlm_id_store +}; + +static struct attribute *dlm_attrs[] = { + &dlm_attr_control.attr, + &dlm_attr_event.attr, + &dlm_attr_id.attr, + NULL, +}; + +static ssize_t dlm_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj); + struct dlm_attr *a = container_of(attr, struct dlm_attr, attr); + return a->show ? a->show(ls, buf) : 0; +} + +static ssize_t dlm_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len) +{ + struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj); + struct dlm_attr *a = container_of(attr, struct dlm_attr, attr); + return a->store ? a->store(ls, buf, len) : len; +} + +static struct sysfs_ops dlm_attr_ops = { + .show = dlm_attr_show, + .store = dlm_attr_store, +}; + +static struct kobj_type dlm_ktype = { + .default_attrs = dlm_attrs, + .sysfs_ops = &dlm_attr_ops, +}; + +static struct kset dlm_kset = { + .subsys = &kernel_subsys, + .kobj = {.name = "dlm",}, + .ktype = &dlm_ktype, +}; + +static int kobject_setup(struct dlm_ls *ls) +{ + char lsname[DLM_LOCKSPACE_LEN]; + int error; + + memset(lsname, 0, DLM_LOCKSPACE_LEN); + snprintf(lsname, DLM_LOCKSPACE_LEN, "%s", ls->ls_name); + + error = kobject_set_name(&ls->ls_kobj, "%s", lsname); + if (error) + return error; + + ls->ls_kobj.kset = &dlm_kset; + ls->ls_kobj.ktype = &dlm_ktype; + return 0; +} + +static int do_uevent(struct dlm_ls *ls, int in) +{ + int error; + + if (in) + kobject_uevent(&ls->ls_kobj, KOBJ_ONLINE); + else + kobject_uevent(&ls->ls_kobj, KOBJ_OFFLINE); + + error = wait_event_interruptible(ls->ls_uevent_wait, + test_and_clear_bit(LSFL_UEVENT_WAIT, &ls->ls_flags)); + if (error) + goto out; + + error = ls->ls_uevent_result; + out: + return error; +} + + +int dlm_lockspace_init(void) +{ + int error; + + ls_count = 0; + init_MUTEX(&ls_lock); + INIT_LIST_HEAD(&lslist); + spin_lock_init(&lslist_lock); + + error = kset_register(&dlm_kset); + if (error) + printk("dlm_lockspace_init: cannot register kset %d\n", error); + return error; +} + +void dlm_lockspace_exit(void) +{ + kset_unregister(&dlm_kset); +} + +static int dlm_scand(void *data) +{ + struct dlm_ls *ls; + + while (!kthread_should_stop()) { + list_for_each_entry(ls, &lslist, ls_list) + dlm_scan_rsbs(ls); + schedule_timeout_interruptible(dlm_config.scan_secs * HZ); + } + return 0; +} + +static int dlm_scand_start(void) +{ + struct task_struct *p; + int error = 0; + + p = kthread_run(dlm_scand, NULL, "dlm_scand"); + if (IS_ERR(p)) + error = PTR_ERR(p); + else + scand_task = p; + return error; +} + +static void dlm_scand_stop(void) +{ + kthread_stop(scand_task); +} + +static struct dlm_ls *dlm_find_lockspace_name(char *name, int namelen) +{ + struct dlm_ls *ls; + + spin_lock(&lslist_lock); + + list_for_each_entry(ls, &lslist, ls_list) { + if (ls->ls_namelen == namelen && + memcmp(ls->ls_name, name, namelen) == 0) + goto out; + } + ls = NULL; + out: + spin_unlock(&lslist_lock); + return ls; +} + +struct dlm_ls *dlm_find_lockspace_global(uint32_t id) +{ + struct dlm_ls *ls; + + spin_lock(&lslist_lock); + + list_for_each_entry(ls, &lslist, ls_list) { + if (ls->ls_global_id == id) { + ls->ls_count++; + goto out; + } + } + ls = NULL; + out: + spin_unlock(&lslist_lock); + return ls; +} + +struct dlm_ls *dlm_find_lockspace_local(void *id) +{ + struct dlm_ls *ls = id; + + spin_lock(&lslist_lock); + ls->ls_count++; + spin_unlock(&lslist_lock); + return ls; +} + +void dlm_put_lockspace(struct dlm_ls *ls) +{ + spin_lock(&lslist_lock); + ls->ls_count--; + spin_unlock(&lslist_lock); +} + +static void remove_lockspace(struct dlm_ls *ls) +{ + for (;;) { + spin_lock(&lslist_lock); + if (ls->ls_count == 0) { + list_del(&ls->ls_list); + spin_unlock(&lslist_lock); + return; + } + spin_unlock(&lslist_lock); + ssleep(1); + } +} + +static int threads_start(void) +{ + int error; + + /* Thread which process lock requests for all lockspace's */ + error = dlm_astd_start(); + if (error) { + log_print("cannot start dlm_astd thread %d", error); + goto fail; + } + + error = dlm_scand_start(); + if (error) { + log_print("cannot start dlm_scand thread %d", error); + goto astd_fail; + } + + /* Thread for sending/receiving messages for all lockspace's */ + error = dlm_lowcomms_start(); + if (error) { + log_print("cannot start dlm lowcomms %d", error); + goto scand_fail; + } + + return 0; + + scand_fail: + dlm_scand_stop(); + astd_fail: + dlm_astd_stop(); + fail: + return error; +} + +static void threads_stop(void) +{ + dlm_scand_stop(); + dlm_lowcomms_stop(); + dlm_astd_stop(); +} + +static int new_lockspace(char *name, int namelen, void **lockspace, + uint32_t flags, int lvblen) +{ + struct dlm_ls *ls; + int i, size, error = -ENOMEM; + + if (namelen > DLM_LOCKSPACE_LEN) + return -EINVAL; + + if (!lvblen || (lvblen % 8)) + return -EINVAL; + + if (!try_module_get(THIS_MODULE)) + return -EINVAL; + + ls = dlm_find_lockspace_name(name, namelen); + if (ls) { + *lockspace = ls; + module_put(THIS_MODULE); + return -EEXIST; + } + + ls = kmalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); + if (!ls) + goto out; + memset(ls, 0, sizeof(struct dlm_ls) + namelen); + memcpy(ls->ls_name, name, namelen); + ls->ls_namelen = namelen; + ls->ls_exflags = flags; + ls->ls_lvblen = lvblen; + ls->ls_count = 0; + ls->ls_flags = 0; + + size = dlm_config.rsbtbl_size; + ls->ls_rsbtbl_size = size; + + ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL); + if (!ls->ls_rsbtbl) + goto out_lsfree; + for (i = 0; i < size; i++) { + INIT_LIST_HEAD(&ls->ls_rsbtbl[i].list); + INIT_LIST_HEAD(&ls->ls_rsbtbl[i].toss); + rwlock_init(&ls->ls_rsbtbl[i].lock); + } + + size = dlm_config.lkbtbl_size; + ls->ls_lkbtbl_size = size; + + ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL); + if (!ls->ls_lkbtbl) + goto out_rsbfree; + for (i = 0; i < size; i++) { + INIT_LIST_HEAD(&ls->ls_lkbtbl[i].list); + rwlock_init(&ls->ls_lkbtbl[i].lock); + ls->ls_lkbtbl[i].counter = 1; + } + + size = dlm_config.dirtbl_size; + ls->ls_dirtbl_size = size; + + ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL); + if (!ls->ls_dirtbl) + goto out_lkbfree; + for (i = 0; i < size; i++) { + INIT_LIST_HEAD(&ls->ls_dirtbl[i].list); + rwlock_init(&ls->ls_dirtbl[i].lock); + } + + INIT_LIST_HEAD(&ls->ls_waiters); + init_MUTEX(&ls->ls_waiters_sem); + + INIT_LIST_HEAD(&ls->ls_nodes); + INIT_LIST_HEAD(&ls->ls_nodes_gone); + ls->ls_num_nodes = 0; + ls->ls_low_nodeid = 0; + ls->ls_total_weight = 0; + ls->ls_node_array = NULL; + + memset(&ls->ls_stub_rsb, 0, sizeof(struct dlm_rsb)); + ls->ls_stub_rsb.res_ls = ls; + + ls->ls_debug_dentry = NULL; + + init_waitqueue_head(&ls->ls_uevent_wait); + ls->ls_uevent_result = 0; + + ls->ls_recoverd_task = NULL; + init_MUTEX(&ls->ls_recoverd_active); + spin_lock_init(&ls->ls_recover_lock); + ls->ls_recover_status = 0; + ls->ls_recover_seq = 0; + ls->ls_recover_args = NULL; + init_rwsem(&ls->ls_in_recovery); + INIT_LIST_HEAD(&ls->ls_requestqueue); + init_MUTEX(&ls->ls_requestqueue_lock); + + ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL); + if (!ls->ls_recover_buf) + goto out_dirfree; + + INIT_LIST_HEAD(&ls->ls_recover_list); + spin_lock_init(&ls->ls_recover_list_lock); + ls->ls_recover_list_count = 0; + init_waitqueue_head(&ls->ls_wait_general); + INIT_LIST_HEAD(&ls->ls_root_list); + init_rwsem(&ls->ls_root_sem); + + down_write(&ls->ls_in_recovery); + + error = dlm_recoverd_start(ls); + if (error) { + log_error(ls, "can't start dlm_recoverd %d", error); + goto out_rcomfree; + } + + spin_lock(&lslist_lock); + list_add(&ls->ls_list, &lslist); + spin_unlock(&lslist_lock); + + dlm_create_debug_file(ls); + + error = kobject_setup(ls); + if (error) + goto out_del; + + error = kobject_register(&ls->ls_kobj); + if (error) + goto out_del; + + error = do_uevent(ls, 1); + if (error) + goto out_unreg; + + *lockspace = ls; + return 0; + + out_unreg: + kobject_unregister(&ls->ls_kobj); + out_del: + dlm_delete_debug_file(ls); + spin_lock(&lslist_lock); + list_del(&ls->ls_list); + spin_unlock(&lslist_lock); + dlm_recoverd_stop(ls); + out_rcomfree: + kfree(ls->ls_recover_buf); + out_dirfree: + kfree(ls->ls_dirtbl); + out_lkbfree: + kfree(ls->ls_lkbtbl); + out_rsbfree: + kfree(ls->ls_rsbtbl); + out_lsfree: + kfree(ls); + out: + module_put(THIS_MODULE); + return error; +} + +int dlm_new_lockspace(char *name, int namelen, void **lockspace, + uint32_t flags, int lvblen) +{ + int error = 0; + + down(&ls_lock); + if (!ls_count) + error = threads_start(); + if (error) + goto out; + + error = new_lockspace(name, namelen, lockspace, flags, lvblen); + if (!error) + ls_count++; + out: + up(&ls_lock); + return error; +} + +/* Return 1 if the lockspace still has active remote locks, + * 2 if the lockspace still has active local locks. + */ +static int lockspace_busy(struct dlm_ls *ls) +{ + int i, lkb_found = 0; + struct dlm_lkb *lkb; + + /* NOTE: We check the lockidtbl here rather than the resource table. + This is because there may be LKBs queued as ASTs that have been + unlinked from their RSBs and are pending deletion once the AST has + been delivered */ + + for (i = 0; i < ls->ls_lkbtbl_size; i++) { + read_lock(&ls->ls_lkbtbl[i].lock); + if (!list_empty(&ls->ls_lkbtbl[i].list)) { + lkb_found = 1; + list_for_each_entry(lkb, &ls->ls_lkbtbl[i].list, + lkb_idtbl_list) { + if (!lkb->lkb_nodeid) { + read_unlock(&ls->ls_lkbtbl[i].lock); + return 2; + } + } + } + read_unlock(&ls->ls_lkbtbl[i].lock); + } + return lkb_found; +} + +static int release_lockspace(struct dlm_ls *ls, int force) +{ + struct dlm_lkb *lkb; + struct dlm_rsb *rsb; + struct list_head *head; + int i; + int busy = lockspace_busy(ls); + + if (busy > force) + return -EBUSY; + + if (force < 3) + do_uevent(ls, 0); + + dlm_recoverd_stop(ls); + + remove_lockspace(ls); + + dlm_delete_debug_file(ls); + + dlm_astd_suspend(); + + kfree(ls->ls_recover_buf); + + /* + * Free direntry structs. + */ + + dlm_dir_clear(ls); + kfree(ls->ls_dirtbl); + + /* + * Free all lkb's on lkbtbl[] lists. + */ + + for (i = 0; i < ls->ls_lkbtbl_size; i++) { + head = &ls->ls_lkbtbl[i].list; + while (!list_empty(head)) { + lkb = list_entry(head->next, struct dlm_lkb, + lkb_idtbl_list); + + list_del(&lkb->lkb_idtbl_list); + + dlm_del_ast(lkb); + + if (lkb->lkb_lvbptr && lkb->lkb_flags & DLM_IFL_MSTCPY) + free_lvb(lkb->lkb_lvbptr); + + free_lkb(lkb); + } + } + dlm_astd_resume(); + + kfree(ls->ls_lkbtbl); + + /* + * Free all rsb's on rsbtbl[] lists + */ + + for (i = 0; i < ls->ls_rsbtbl_size; i++) { + head = &ls->ls_rsbtbl[i].list; + while (!list_empty(head)) { + rsb = list_entry(head->next, struct dlm_rsb, + res_hashchain); + + list_del(&rsb->res_hashchain); + free_rsb(rsb); + } + + head = &ls->ls_rsbtbl[i].toss; + while (!list_empty(head)) { + rsb = list_entry(head->next, struct dlm_rsb, + res_hashchain); + list_del(&rsb->res_hashchain); + free_rsb(rsb); + } + } + + kfree(ls->ls_rsbtbl); + + /* + * Free structures on any other lists + */ + + kfree(ls->ls_recover_args); + dlm_clear_free_entries(ls); + dlm_clear_members(ls); + dlm_clear_members_gone(ls); + kfree(ls->ls_node_array); + kobject_unregister(&ls->ls_kobj); + kfree(ls); + + down(&ls_lock); + ls_count--; + if (!ls_count) + threads_stop(); + up(&ls_lock); + + module_put(THIS_MODULE); + return 0; +} + +/* + * Called when a system has released all its locks and is not going to use the + * lockspace any longer. We free everything we're managing for this lockspace. + * Remaining nodes will go through the recovery process as if we'd died. The + * lockspace must continue to function as usual, participating in recoveries, + * until this returns. + * + * Force has 4 possible values: + * 0 - don't destroy locksapce if it has any LKBs + * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs + * 2 - destroy lockspace regardless of LKBs + * 3 - destroy lockspace as part of a forced shutdown + */ + +int dlm_release_lockspace(void *lockspace, int force) +{ + struct dlm_ls *ls; + + ls = dlm_find_lockspace_local(lockspace); + if (!ls) + return -EINVAL; + dlm_put_lockspace(ls); + return release_lockspace(ls, force); +} + diff --git a/fs/dlm/lockspace.h b/fs/dlm/lockspace.h new file mode 100644 index 000000000000..17bd3ba863a9 --- /dev/null +++ b/fs/dlm/lockspace.h @@ -0,0 +1,24 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __LOCKSPACE_DOT_H__ +#define __LOCKSPACE_DOT_H__ + +int dlm_lockspace_init(void); +void dlm_lockspace_exit(void); +struct dlm_ls *dlm_find_lockspace_global(uint32_t id); +struct dlm_ls *dlm_find_lockspace_local(void *id); +void dlm_put_lockspace(struct dlm_ls *ls); + +#endif /* __LOCKSPACE_DOT_H__ */ + diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c new file mode 100644 index 000000000000..09b0124f7fc4 --- /dev/null +++ b/fs/dlm/lowcomms.c @@ -0,0 +1,1218 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +/* + * lowcomms.c + * + * This is the "low-level" comms layer. + * + * It is responsible for sending/receiving messages + * from other nodes in the cluster. + * + * Cluster nodes are referred to by their nodeids. nodeids are + * simply 32 bit numbers to the locking module - if they need to + * be expanded for the cluster infrastructure then that is it's + * responsibility. It is this layer's + * responsibility to resolve these into IP address or + * whatever it needs for inter-node communication. + * + * The comms level is two kernel threads that deal mainly with + * the receiving of messages from other nodes and passing them + * up to the mid-level comms layer (which understands the + * message format) for execution by the locking core, and + * a send thread which does all the setting up of connections + * to remote nodes and the sending of data. Threads are not allowed + * to send their own data because it may cause them to wait in times + * of high load. Also, this way, the sending thread can collect together + * messages bound for one node and send them in one block. + * + * I don't see any problem with the recv thread executing the locking + * code on behalf of remote processes as the locking code is + * short, efficient and never (well, hardly ever) waits. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dlm_internal.h" +#include "lowcomms.h" +#include "config.h" +#include "midcomms.h" + +static struct sockaddr_storage *local_addr[DLM_MAX_ADDR_COUNT]; +static int local_count; +static int local_nodeid; + +/* One of these per connected node */ + +#define NI_INIT_PENDING 1 +#define NI_WRITE_PENDING 2 + +struct nodeinfo { + spinlock_t lock; + sctp_assoc_t assoc_id; + unsigned long flags; + struct list_head write_list; /* nodes with pending writes */ + struct list_head writequeue; /* outgoing writequeue_entries */ + spinlock_t writequeue_lock; + int nodeid; +}; + +static DEFINE_IDR(nodeinfo_idr); +static struct rw_semaphore nodeinfo_lock; +static int max_nodeid; + +struct cbuf { + unsigned base; + unsigned len; + unsigned mask; +}; + +/* Just the one of these, now. But this struct keeps + the connection-specific variables together */ + +#define CF_READ_PENDING 1 + +struct connection { + struct socket *sock; + unsigned long flags; + struct page *rx_page; + atomic_t waiting_requests; + struct cbuf cb; + int eagain_flag; +}; + +/* An entry waiting to be sent */ + +struct writequeue_entry { + struct list_head list; + struct page *page; + int offset; + int len; + int end; + int users; + struct nodeinfo *ni; +}; + +#define CBUF_ADD(cb, n) do { (cb)->len += n; } while(0) +#define CBUF_EMPTY(cb) ((cb)->len == 0) +#define CBUF_MAY_ADD(cb, n) (((cb)->len + (n)) < ((cb)->mask + 1)) +#define CBUF_DATA(cb) (((cb)->base + (cb)->len) & (cb)->mask) + +#define CBUF_INIT(cb, size) \ +do { \ + (cb)->base = (cb)->len = 0; \ + (cb)->mask = ((size)-1); \ +} while(0) + +#define CBUF_EAT(cb, n) \ +do { \ + (cb)->len -= (n); \ + (cb)->base += (n); \ + (cb)->base &= (cb)->mask; \ +} while(0) + + +/* List of nodes which have writes pending */ +static struct list_head write_nodes; +static spinlock_t write_nodes_lock; + +/* Maximum number of incoming messages to process before + * doing a schedule() + */ +#define MAX_RX_MSG_COUNT 25 + +/* Manage daemons */ +static struct task_struct *recv_task; +static struct task_struct *send_task; +static wait_queue_head_t lowcomms_recv_wait; +static atomic_t accepting; + +/* The SCTP connection */ +static struct connection sctp_con; + + +static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr) +{ + struct sockaddr_storage addr; + int error; + + if (!local_count) + return -1; + + error = dlm_nodeid_to_addr(nodeid, &addr); + if (error) + return error; + + if (local_addr[0]->ss_family == AF_INET) { + struct sockaddr_in *in4 = (struct sockaddr_in *) &addr; + struct sockaddr_in *ret4 = (struct sockaddr_in *) retaddr; + ret4->sin_addr.s_addr = in4->sin_addr.s_addr; + } else { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &addr; + struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr; + memcpy(&ret6->sin6_addr, &in6->sin6_addr, + sizeof(in6->sin6_addr)); + } + + return 0; +} + +static struct nodeinfo *nodeid2nodeinfo(int nodeid, int alloc) +{ + struct nodeinfo *ni; + int r; + int n; + + down_read(&nodeinfo_lock); + ni = idr_find(&nodeinfo_idr, nodeid); + up_read(&nodeinfo_lock); + + if (!ni && alloc) { + down_write(&nodeinfo_lock); + + ni = idr_find(&nodeinfo_idr, nodeid); + if (ni) + goto out_up; + + r = idr_pre_get(&nodeinfo_idr, alloc); + if (!r) + goto out_up; + + ni = kmalloc(sizeof(struct nodeinfo), alloc); + if (!ni) + goto out_up; + + r = idr_get_new_above(&nodeinfo_idr, ni, nodeid, &n); + if (r) { + kfree(ni); + ni = NULL; + goto out_up; + } + if (n != nodeid) { + idr_remove(&nodeinfo_idr, n); + kfree(ni); + ni = NULL; + goto out_up; + } + memset(ni, 0, sizeof(struct nodeinfo)); + spin_lock_init(&ni->lock); + INIT_LIST_HEAD(&ni->writequeue); + spin_lock_init(&ni->writequeue_lock); + ni->nodeid = nodeid; + + if (nodeid > max_nodeid) + max_nodeid = nodeid; + out_up: + up_write(&nodeinfo_lock); + } + + return ni; +} + +/* Don't call this too often... */ +static struct nodeinfo *assoc2nodeinfo(sctp_assoc_t assoc) +{ + int i; + struct nodeinfo *ni; + + for (i=1; i<=max_nodeid; i++) { + ni = nodeid2nodeinfo(i, 0); + if (ni && ni->assoc_id == assoc) + return ni; + } + return NULL; +} + +/* Data or notification available on socket */ +static void lowcomms_data_ready(struct sock *sk, int count_unused) +{ + atomic_inc(&sctp_con.waiting_requests); + if (test_and_set_bit(CF_READ_PENDING, &sctp_con.flags)) + return; + + wake_up_interruptible(&lowcomms_recv_wait); +} + + +/* Add the port number to an IP6 or 4 sockaddr and return the address length. + Also padd out the struct with zeros to make comparisons meaningful */ + +static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port, + int *addr_len) +{ + struct sockaddr_in *local4_addr; + struct sockaddr_in6 *local6_addr; + + if (!local_count) + return; + + if (!port) { + if (local_addr[0]->ss_family == AF_INET) { + local4_addr = (struct sockaddr_in *)local_addr[0]; + port = be16_to_cpu(local4_addr->sin_port); + } else { + local6_addr = (struct sockaddr_in6 *)local_addr[0]; + port = be16_to_cpu(local6_addr->sin6_port); + } + } + + saddr->ss_family = local_addr[0]->ss_family; + if (local_addr[0]->ss_family == AF_INET) { + struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr; + in4_addr->sin_port = cpu_to_be16(port); + memset(&in4_addr->sin_zero, 0, sizeof(in4_addr->sin_zero)); + memset(in4_addr+1, 0, sizeof(struct sockaddr_storage) - + sizeof(struct sockaddr_in)); + *addr_len = sizeof(struct sockaddr_in); + } else { + struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr; + in6_addr->sin6_port = cpu_to_be16(port); + memset(in6_addr+1, 0, sizeof(struct sockaddr_storage) - + sizeof(struct sockaddr_in6)); + *addr_len = sizeof(struct sockaddr_in6); + } +} + +/* Close the connection and tidy up */ +static void close_connection(void) +{ + if (sctp_con.sock) { + sock_release(sctp_con.sock); + sctp_con.sock = NULL; + } + + if (sctp_con.rx_page) { + __free_page(sctp_con.rx_page); + sctp_con.rx_page = NULL; + } +} + +/* We only send shutdown messages to nodes that are not part of the cluster */ +static void send_shutdown(sctp_assoc_t associd) +{ + static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; + struct msghdr outmessage; + struct cmsghdr *cmsg; + struct sctp_sndrcvinfo *sinfo; + int ret; + + outmessage.msg_name = NULL; + outmessage.msg_namelen = 0; + outmessage.msg_control = outcmsg; + outmessage.msg_controllen = sizeof(outcmsg); + outmessage.msg_flags = MSG_EOR; + + cmsg = CMSG_FIRSTHDR(&outmessage); + cmsg->cmsg_level = IPPROTO_SCTP; + cmsg->cmsg_type = SCTP_SNDRCV; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); + outmessage.msg_controllen = cmsg->cmsg_len; + sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); + + sinfo->sinfo_flags |= MSG_EOF; + sinfo->sinfo_assoc_id = associd; + + ret = kernel_sendmsg(sctp_con.sock, &outmessage, NULL, 0, 0); + + if (ret != 0) + log_print("send EOF to node failed: %d", ret); +} + + +/* INIT failed but we don't know which node... + restart INIT on all pending nodes */ +static void init_failed(void) +{ + int i; + struct nodeinfo *ni; + + for (i=1; i<=max_nodeid; i++) { + ni = nodeid2nodeinfo(i, 0); + if (!ni) + continue; + + if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) { + ni->assoc_id = 0; + if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) { + spin_lock_bh(&write_nodes_lock); + list_add_tail(&ni->write_list, &write_nodes); + spin_unlock_bh(&write_nodes_lock); + } + } + } + wake_up_process(send_task); +} + +/* Something happened to an association */ +static void process_sctp_notification(struct msghdr *msg, char *buf) +{ + union sctp_notification *sn = (union sctp_notification *)buf; + + if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) { + switch (sn->sn_assoc_change.sac_state) { + + case SCTP_COMM_UP: + case SCTP_RESTART: + { + /* Check that the new node is in the lockspace */ + struct sctp_prim prim; + mm_segment_t fs; + int nodeid; + int prim_len, ret; + int addr_len; + struct nodeinfo *ni; + + /* This seems to happen when we received a connection + * too early... or something... anyway, it happens but + * we always seem to get a real message too, see + * receive_from_sock */ + + if ((int)sn->sn_assoc_change.sac_assoc_id <= 0) { + log_print("COMM_UP for invalid assoc ID %d", + (int)sn->sn_assoc_change.sac_assoc_id); + init_failed(); + return; + } + memset(&prim, 0, sizeof(struct sctp_prim)); + prim_len = sizeof(struct sctp_prim); + prim.ssp_assoc_id = sn->sn_assoc_change.sac_assoc_id; + + fs = get_fs(); + set_fs(get_ds()); + ret = sctp_con.sock->ops->getsockopt(sctp_con.sock, + IPPROTO_SCTP, SCTP_PRIMARY_ADDR, + (char*)&prim, &prim_len); + set_fs(fs); + if (ret < 0) { + struct nodeinfo *ni; + + log_print("getsockopt/sctp_primary_addr on " + "new assoc %d failed : %d", + (int)sn->sn_assoc_change.sac_assoc_id, ret); + + /* Retry INIT later */ + ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id); + if (ni) + clear_bit(NI_INIT_PENDING, &ni->flags); + return; + } + make_sockaddr(&prim.ssp_addr, 0, &addr_len); + if (dlm_addr_to_nodeid(&prim.ssp_addr, &nodeid)) { + log_print("reject connect from unknown addr"); + send_shutdown(prim.ssp_assoc_id); + return; + } + + ni = nodeid2nodeinfo(nodeid, GFP_KERNEL); + if (!ni) + return; + + /* Save the assoc ID */ + spin_lock(&ni->lock); + ni->assoc_id = sn->sn_assoc_change.sac_assoc_id; + spin_unlock(&ni->lock); + + log_print("got new/restarted association %d nodeid %d", + (int)sn->sn_assoc_change.sac_assoc_id, nodeid); + + /* Send any pending writes */ + clear_bit(NI_INIT_PENDING, &ni->flags); + if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) { + spin_lock_bh(&write_nodes_lock); + list_add_tail(&ni->write_list, &write_nodes); + spin_unlock_bh(&write_nodes_lock); + } + wake_up_process(send_task); + } + break; + + case SCTP_COMM_LOST: + case SCTP_SHUTDOWN_COMP: + { + struct nodeinfo *ni; + + ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id); + if (ni) { + spin_lock(&ni->lock); + ni->assoc_id = 0; + spin_unlock(&ni->lock); + } + } + break; + + /* We don't know which INIT failed, so clear the PENDING flags + * on them all. if assoc_id is zero then it will then try + * again */ + + case SCTP_CANT_STR_ASSOC: + { + log_print("Can't start SCTP association - retrying"); + init_failed(); + } + break; + + default: + log_print("unexpected SCTP assoc change id=%d state=%d", + (int)sn->sn_assoc_change.sac_assoc_id, + sn->sn_assoc_change.sac_state); + } + } +} + +/* Data received from remote end */ +static int receive_from_sock(void) +{ + int ret = 0; + struct msghdr msg; + struct kvec iov[2]; + unsigned len; + int r; + struct sctp_sndrcvinfo *sinfo; + struct cmsghdr *cmsg; + struct nodeinfo *ni; + + /* These two are marginally too big for stack allocation, but this + * function is (currently) only called by dlm_recvd so static should be + * OK. + */ + static struct sockaddr_storage msgname; + static char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; + + if (sctp_con.sock == NULL) + goto out; + + if (sctp_con.rx_page == NULL) { + /* + * This doesn't need to be atomic, but I think it should + * improve performance if it is. + */ + sctp_con.rx_page = alloc_page(GFP_ATOMIC); + if (sctp_con.rx_page == NULL) + goto out_resched; + CBUF_INIT(&sctp_con.cb, PAGE_CACHE_SIZE); + } + + memset(&incmsg, 0, sizeof(incmsg)); + memset(&msgname, 0, sizeof(msgname)); + + memset(incmsg, 0, sizeof(incmsg)); + msg.msg_name = &msgname; + msg.msg_namelen = sizeof(msgname); + msg.msg_flags = 0; + msg.msg_control = incmsg; + msg.msg_controllen = sizeof(incmsg); + + /* I don't see why this circular buffer stuff is necessary for SCTP + * which is a packet-based protocol, but the whole thing breaks under + * load without it! The overhead is minimal (and is in the TCP lowcomms + * anyway, of course) so I'll leave it in until I can figure out what's + * really happening. + */ + + /* + * iov[0] is the bit of the circular buffer between the current end + * point (cb.base + cb.len) and the end of the buffer. + */ + iov[0].iov_len = sctp_con.cb.base - CBUF_DATA(&sctp_con.cb); + iov[0].iov_base = page_address(sctp_con.rx_page) + + CBUF_DATA(&sctp_con.cb); + iov[1].iov_len = 0; + + /* + * iov[1] is the bit of the circular buffer between the start of the + * buffer and the start of the currently used section (cb.base) + */ + if (CBUF_DATA(&sctp_con.cb) >= sctp_con.cb.base) { + iov[0].iov_len = PAGE_CACHE_SIZE - CBUF_DATA(&sctp_con.cb); + iov[1].iov_len = sctp_con.cb.base; + iov[1].iov_base = page_address(sctp_con.rx_page); + msg.msg_iovlen = 2; + } + len = iov[0].iov_len + iov[1].iov_len; + + r = ret = kernel_recvmsg(sctp_con.sock, &msg, iov, 1, len, + MSG_NOSIGNAL | MSG_DONTWAIT); + if (ret <= 0) + goto out_close; + + msg.msg_control = incmsg; + msg.msg_controllen = sizeof(incmsg); + cmsg = CMSG_FIRSTHDR(&msg); + sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + + if (msg.msg_flags & MSG_NOTIFICATION) { + process_sctp_notification(&msg, page_address(sctp_con.rx_page)); + return 0; + } + + /* Is this a new association ? */ + ni = nodeid2nodeinfo(le32_to_cpu(sinfo->sinfo_ppid), GFP_KERNEL); + if (ni) { + ni->assoc_id = sinfo->sinfo_assoc_id; + if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) { + + if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) { + spin_lock_bh(&write_nodes_lock); + list_add_tail(&ni->write_list, &write_nodes); + spin_unlock_bh(&write_nodes_lock); + } + wake_up_process(send_task); + } + } + + /* INIT sends a message with length of 1 - ignore it */ + if (r == 1) + return 0; + + CBUF_ADD(&sctp_con.cb, ret); + ret = dlm_process_incoming_buffer(cpu_to_le32(sinfo->sinfo_ppid), + page_address(sctp_con.rx_page), + sctp_con.cb.base, sctp_con.cb.len, + PAGE_CACHE_SIZE); + if (ret < 0) + goto out_close; + CBUF_EAT(&sctp_con.cb, ret); + + out: + ret = 0; + goto out_ret; + + out_resched: + lowcomms_data_ready(sctp_con.sock->sk, 0); + ret = 0; + schedule(); + goto out_ret; + + out_close: + if (ret != -EAGAIN) + log_print("error reading from sctp socket: %d", ret); + out_ret: + return ret; +} + +/* Bind to an IP address. SCTP allows multiple address so it can do multi-homing */ +static int add_bind_addr(struct sockaddr_storage *addr, int addr_len, int num) +{ + mm_segment_t fs; + int result = 0; + + fs = get_fs(); + set_fs(get_ds()); + if (num == 1) + result = sctp_con.sock->ops->bind(sctp_con.sock, + (struct sockaddr *) addr, addr_len); + else + result = sctp_con.sock->ops->setsockopt(sctp_con.sock, SOL_SCTP, + SCTP_SOCKOPT_BINDX_ADD, (char *)addr, addr_len); + set_fs(fs); + + if (result < 0) + log_print("Can't bind to port %d addr number %d", + dlm_config.tcp_port, num); + + return result; +} + +static void init_local(void) +{ + struct sockaddr_storage sas, *addr; + int i; + + local_nodeid = dlm_our_nodeid(); + + for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) { + if (dlm_our_addr(&sas, i)) + break; + + addr = kmalloc(sizeof(*addr), GFP_KERNEL); + if (!addr) + break; + memcpy(addr, &sas, sizeof(*addr)); + local_addr[local_count++] = addr; + } +} + +/* Initialise SCTP socket and bind to all interfaces */ +static int init_sock(void) +{ + mm_segment_t fs; + struct socket *sock = NULL; + struct sockaddr_storage localaddr; + struct sctp_event_subscribe subscribe; + int result = -EINVAL, num = 1, i, addr_len; + + if (!local_count) { + init_local(); + if (!local_count) { + log_print("no local IP address has been set"); + goto out; + } + } + + result = sock_create_kern(local_addr[0]->ss_family, SOCK_SEQPACKET, + IPPROTO_SCTP, &sock); + if (result < 0) { + log_print("Can't create comms socket, check SCTP is loaded"); + goto out; + } + + /* Listen for events */ + memset(&subscribe, 0, sizeof(subscribe)); + subscribe.sctp_data_io_event = 1; + subscribe.sctp_association_event = 1; + subscribe.sctp_send_failure_event = 1; + subscribe.sctp_shutdown_event = 1; + subscribe.sctp_partial_delivery_event = 1; + + fs = get_fs(); + set_fs(get_ds()); + result = sock->ops->setsockopt(sock, SOL_SCTP, SCTP_EVENTS, + (char *)&subscribe, sizeof(subscribe)); + set_fs(fs); + + if (result < 0) { + log_print("Failed to set SCTP_EVENTS on socket: result=%d", + result); + goto create_delsock; + } + + /* Init con struct */ + sock->sk->sk_user_data = &sctp_con; + sctp_con.sock = sock; + sctp_con.sock->sk->sk_data_ready = lowcomms_data_ready; + + /* Bind to all interfaces. */ + for (i = 0; i < local_count; i++) { + memcpy(&localaddr, local_addr[i], sizeof(localaddr)); + make_sockaddr(&localaddr, dlm_config.tcp_port, &addr_len); + + result = add_bind_addr(&localaddr, addr_len, num); + if (result) + goto create_delsock; + ++num; + } + + result = sock->ops->listen(sock, 5); + if (result < 0) { + log_print("Can't set socket listening"); + goto create_delsock; + } + + return 0; + + create_delsock: + sock_release(sock); + sctp_con.sock = NULL; + out: + return result; +} + + +static struct writequeue_entry *new_writequeue_entry(int allocation) +{ + struct writequeue_entry *entry; + + entry = kmalloc(sizeof(struct writequeue_entry), allocation); + if (!entry) + return NULL; + + entry->page = alloc_page(allocation); + if (!entry->page) { + kfree(entry); + return NULL; + } + + entry->offset = 0; + entry->len = 0; + entry->end = 0; + entry->users = 0; + + return entry; +} + +void *dlm_lowcomms_get_buffer(int nodeid, int len, int allocation, char **ppc) +{ + struct writequeue_entry *e; + int offset = 0; + int users = 0; + struct nodeinfo *ni; + + if (!atomic_read(&accepting)) + return NULL; + + ni = nodeid2nodeinfo(nodeid, allocation); + if (!ni) + return NULL; + + spin_lock(&ni->writequeue_lock); + e = list_entry(ni->writequeue.prev, struct writequeue_entry, list); + if (((struct list_head *) e == &ni->writequeue) || + (PAGE_CACHE_SIZE - e->end < len)) { + e = NULL; + } else { + offset = e->end; + e->end += len; + users = e->users++; + } + spin_unlock(&ni->writequeue_lock); + + if (e) { + got_one: + if (users == 0) + kmap(e->page); + *ppc = page_address(e->page) + offset; + return e; + } + + e = new_writequeue_entry(allocation); + if (e) { + spin_lock(&ni->writequeue_lock); + offset = e->end; + e->end += len; + e->ni = ni; + users = e->users++; + list_add_tail(&e->list, &ni->writequeue); + spin_unlock(&ni->writequeue_lock); + goto got_one; + } + return NULL; +} + +void dlm_lowcomms_commit_buffer(void *arg) +{ + struct writequeue_entry *e = (struct writequeue_entry *) arg; + int users; + struct nodeinfo *ni = e->ni; + + if (!atomic_read(&accepting)) + return; + + spin_lock(&ni->writequeue_lock); + users = --e->users; + if (users) + goto out; + e->len = e->end - e->offset; + kunmap(e->page); + spin_unlock(&ni->writequeue_lock); + + if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) { + spin_lock_bh(&write_nodes_lock); + list_add_tail(&ni->write_list, &write_nodes); + spin_unlock_bh(&write_nodes_lock); + wake_up_process(send_task); + } + return; + + out: + spin_unlock(&ni->writequeue_lock); + return; +} + +static void free_entry(struct writequeue_entry *e) +{ + __free_page(e->page); + kfree(e); +} + +/* Initiate an SCTP association. In theory we could just use sendmsg() on + the first IP address and it should work, but this allows us to set up the + association before sending any valuable data that we can't afford to lose. + It also keeps the send path clean as it can now always use the association ID */ +static void initiate_association(int nodeid) +{ + struct sockaddr_storage rem_addr; + static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; + struct msghdr outmessage; + struct cmsghdr *cmsg; + struct sctp_sndrcvinfo *sinfo; + int ret; + int addrlen; + char buf[1]; + struct kvec iov[1]; + struct nodeinfo *ni; + + log_print("Initiating association with node %d", nodeid); + + ni = nodeid2nodeinfo(nodeid, GFP_KERNEL); + if (!ni) + return; + + if (nodeid_to_addr(nodeid, (struct sockaddr *)&rem_addr)) { + log_print("no address for nodeid %d", nodeid); + return; + } + + make_sockaddr(&rem_addr, dlm_config.tcp_port, &addrlen); + + outmessage.msg_name = &rem_addr; + outmessage.msg_namelen = addrlen; + outmessage.msg_control = outcmsg; + outmessage.msg_controllen = sizeof(outcmsg); + outmessage.msg_flags = MSG_EOR; + + iov[0].iov_base = buf; + iov[0].iov_len = 1; + + /* Real INIT messages seem to cause trouble. Just send a 1 byte message + we can afford to lose */ + cmsg = CMSG_FIRSTHDR(&outmessage); + cmsg->cmsg_level = IPPROTO_SCTP; + cmsg->cmsg_type = SCTP_SNDRCV; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); + sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); + sinfo->sinfo_ppid = cpu_to_le32(local_nodeid); + + outmessage.msg_controllen = cmsg->cmsg_len; + ret = kernel_sendmsg(sctp_con.sock, &outmessage, iov, 1, 1); + if (ret < 0) { + log_print("send INIT to node failed: %d", ret); + /* Try again later */ + clear_bit(NI_INIT_PENDING, &ni->flags); + } +} + +/* Send a message */ +static int send_to_sock(struct nodeinfo *ni) +{ + int ret = 0; + struct writequeue_entry *e; + int len, offset; + struct msghdr outmsg; + static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; + struct cmsghdr *cmsg; + struct sctp_sndrcvinfo *sinfo; + struct kvec iov; + + /* See if we need to init an association before we start + sending precious messages */ + spin_lock(&ni->lock); + if (!ni->assoc_id && !test_and_set_bit(NI_INIT_PENDING, &ni->flags)) { + spin_unlock(&ni->lock); + initiate_association(ni->nodeid); + return 0; + } + spin_unlock(&ni->lock); + + outmsg.msg_name = NULL; /* We use assoc_id */ + outmsg.msg_namelen = 0; + outmsg.msg_control = outcmsg; + outmsg.msg_controllen = sizeof(outcmsg); + outmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL | MSG_EOR; + + cmsg = CMSG_FIRSTHDR(&outmsg); + cmsg->cmsg_level = IPPROTO_SCTP; + cmsg->cmsg_type = SCTP_SNDRCV; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); + sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); + sinfo->sinfo_ppid = cpu_to_le32(local_nodeid); + sinfo->sinfo_assoc_id = ni->assoc_id; + outmsg.msg_controllen = cmsg->cmsg_len; + + spin_lock(&ni->writequeue_lock); + for (;;) { + if (list_empty(&ni->writequeue)) + break; + e = list_entry(ni->writequeue.next, struct writequeue_entry, + list); + kmap(e->page); + len = e->len; + offset = e->offset; + BUG_ON(len == 0 && e->users == 0); + spin_unlock(&ni->writequeue_lock); + + ret = 0; + if (len) { + iov.iov_base = page_address(e->page)+offset; + iov.iov_len = len; + + ret = kernel_sendmsg(sctp_con.sock, &outmsg, &iov, 1, + len); + if (ret == -EAGAIN) { + sctp_con.eagain_flag = 1; + goto out; + } else if (ret < 0) + goto send_error; + } else { + /* Don't starve people filling buffers */ + schedule(); + } + + spin_lock(&ni->writequeue_lock); + e->offset += ret; + e->len -= ret; + + if (e->len == 0 && e->users == 0) { + list_del(&e->list); + free_entry(e); + continue; + } + } + spin_unlock(&ni->writequeue_lock); + out: + return ret; + + send_error: + log_print("Error sending to node %d %d", ni->nodeid, ret); + spin_lock(&ni->lock); + if (!test_and_set_bit(NI_INIT_PENDING, &ni->flags)) { + ni->assoc_id = 0; + spin_unlock(&ni->lock); + initiate_association(ni->nodeid); + } else + spin_unlock(&ni->lock); + + return ret; +} + +/* Try to send any messages that are pending */ +static void process_output_queue(void) +{ + struct list_head *list; + struct list_head *temp; + + spin_lock_bh(&write_nodes_lock); + list_for_each_safe(list, temp, &write_nodes) { + struct nodeinfo *ni = + list_entry(list, struct nodeinfo, write_list); + clear_bit(NI_WRITE_PENDING, &ni->flags); + list_del(&ni->write_list); + + spin_unlock_bh(&write_nodes_lock); + + send_to_sock(ni); + spin_lock_bh(&write_nodes_lock); + } + spin_unlock_bh(&write_nodes_lock); +} + +/* Called after we've had -EAGAIN and been woken up */ +static void refill_write_queue(void) +{ + int i; + + for (i=1; i<=max_nodeid; i++) { + struct nodeinfo *ni = nodeid2nodeinfo(i, 0); + + if (ni) { + if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) { + spin_lock_bh(&write_nodes_lock); + list_add_tail(&ni->write_list, &write_nodes); + spin_unlock_bh(&write_nodes_lock); + } + } + } +} + +static void clean_one_writequeue(struct nodeinfo *ni) +{ + struct list_head *list; + struct list_head *temp; + + spin_lock(&ni->writequeue_lock); + list_for_each_safe(list, temp, &ni->writequeue) { + struct writequeue_entry *e = + list_entry(list, struct writequeue_entry, list); + list_del(&e->list); + free_entry(e); + } + spin_unlock(&ni->writequeue_lock); +} + +static void clean_writequeues(void) +{ + int i; + + for (i=1; i<=max_nodeid; i++) { + struct nodeinfo *ni = nodeid2nodeinfo(i, 0); + if (ni) + clean_one_writequeue(ni); + } +} + + +static void dealloc_nodeinfo(void) +{ + int i; + + for (i=1; i<=max_nodeid; i++) { + struct nodeinfo *ni = nodeid2nodeinfo(i, 0); + if (ni) { + idr_remove(&nodeinfo_idr, i); + kfree(ni); + } + } +} + +static int write_list_empty(void) +{ + int status; + + spin_lock_bh(&write_nodes_lock); + status = list_empty(&write_nodes); + spin_unlock_bh(&write_nodes_lock); + + return status; +} + +static int dlm_recvd(void *data) +{ + DECLARE_WAITQUEUE(wait, current); + + while (!kthread_should_stop()) { + int count = 0; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&lowcomms_recv_wait, &wait); + if (!test_bit(CF_READ_PENDING, &sctp_con.flags)) + schedule(); + remove_wait_queue(&lowcomms_recv_wait, &wait); + set_current_state(TASK_RUNNING); + + if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) { + int ret; + + do { + ret = receive_from_sock(); + + /* Don't starve out everyone else */ + if (++count >= MAX_RX_MSG_COUNT) { + schedule(); + count = 0; + } + } while (!kthread_should_stop() && ret >=0); + } + schedule(); + } + + return 0; +} + +static int dlm_sendd(void *data) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(sctp_con.sock->sk->sk_sleep, &wait); + + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + if (write_list_empty()) + schedule(); + set_current_state(TASK_RUNNING); + + if (sctp_con.eagain_flag) { + sctp_con.eagain_flag = 0; + refill_write_queue(); + } + process_output_queue(); + } + + remove_wait_queue(sctp_con.sock->sk->sk_sleep, &wait); + + return 0; +} + +static void daemons_stop(void) +{ + kthread_stop(recv_task); + kthread_stop(send_task); +} + +static int daemons_start(void) +{ + struct task_struct *p; + int error; + + p = kthread_run(dlm_recvd, NULL, "dlm_recvd"); + error = IS_ERR(p); + if (error) { + log_print("can't start dlm_recvd %d", error); + return error; + } + recv_task = p; + + p = kthread_run(dlm_sendd, NULL, "dlm_sendd"); + error = IS_ERR(p); + if (error) { + log_print("can't start dlm_sendd %d", error); + kthread_stop(recv_task); + return error; + } + send_task = p; + + return 0; +} + +/* + * This is quite likely to sleep... + */ +int dlm_lowcomms_start(void) +{ + int error; + + spin_lock_init(&write_nodes_lock); + INIT_LIST_HEAD(&write_nodes); + init_rwsem(&nodeinfo_lock); + + error = init_sock(); + if (error) + goto fail_sock; + error = daemons_start(); + if (error) + goto fail_sock; + atomic_set(&accepting, 1); + return 0; + + fail_sock: + close_connection(); + return error; +} + +/* Set all the activity flags to prevent any socket activity. */ + +void dlm_lowcomms_stop(void) +{ + atomic_set(&accepting, 0); + sctp_con.flags = 0x7; + daemons_stop(); + clean_writequeues(); + close_connection(); + dealloc_nodeinfo(); + max_nodeid = 0; +} + +int dlm_lowcomms_init(void) +{ + init_waitqueue_head(&lowcomms_recv_wait); + return 0; +} + +void dlm_lowcomms_exit(void) +{ + int i; + + for (i = 0; i < local_count; i++) + kfree(local_addr[i]); + local_count = 0; + local_nodeid = 0; +} + diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h new file mode 100644 index 000000000000..3af8035ff12f --- /dev/null +++ b/fs/dlm/lowcomms.h @@ -0,0 +1,25 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __LOWCOMMS_DOT_H__ +#define __LOWCOMMS_DOT_H__ + +int dlm_lowcomms_init(void); +void dlm_lowcomms_exit(void); +int dlm_lowcomms_start(void); +void dlm_lowcomms_stop(void); +void *dlm_lowcomms_get_buffer(int nodeid, int len, int allocation, char **ppc); +void dlm_lowcomms_commit_buffer(void *mh); + +#endif /* __LOWCOMMS_DOT_H__ */ + diff --git a/fs/dlm/lvb_table.h b/fs/dlm/lvb_table.h new file mode 100644 index 000000000000..cc3e92f3feef --- /dev/null +++ b/fs/dlm/lvb_table.h @@ -0,0 +1,18 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __LVB_TABLE_DOT_H__ +#define __LVB_TABLE_DOT_H__ + +extern const int dlm_lvb_operations[8][8]; + +#endif diff --git a/fs/dlm/main.c b/fs/dlm/main.c new file mode 100644 index 000000000000..81bf4cb22033 --- /dev/null +++ b/fs/dlm/main.c @@ -0,0 +1,89 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "lockspace.h" +#include "lock.h" +#include "memory.h" +#include "lowcomms.h" +#include "config.h" + +#ifdef CONFIG_DLM_DEBUG +int dlm_register_debugfs(void); +void dlm_unregister_debugfs(void); +#else +static inline int dlm_register_debugfs(void) { return 0; } +static inline void dlm_unregister_debugfs(void) { } +#endif + +static int __init init_dlm(void) +{ + int error; + + error = dlm_memory_init(); + if (error) + goto out; + + error = dlm_lockspace_init(); + if (error) + goto out_mem; + + error = dlm_config_init(); + if (error) + goto out_lockspace; + + error = dlm_register_debugfs(); + if (error) + goto out_config; + + error = dlm_lowcomms_init(); + if (error) + goto out_debug; + + printk("DLM (built %s %s) installed\n", __DATE__, __TIME__); + + return 0; + + out_debug: + dlm_unregister_debugfs(); + out_config: + dlm_config_exit(); + out_lockspace: + dlm_lockspace_exit(); + out_mem: + dlm_memory_exit(); + out: + return error; +} + +static void __exit exit_dlm(void) +{ + dlm_lowcomms_exit(); + dlm_config_exit(); + dlm_memory_exit(); + dlm_lockspace_exit(); + dlm_unregister_debugfs(); +} + +module_init(init_dlm); +module_exit(exit_dlm); + +MODULE_DESCRIPTION("Distributed Lock Manager"); +MODULE_AUTHOR("Red Hat, Inc."); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL_GPL(dlm_new_lockspace); +EXPORT_SYMBOL_GPL(dlm_release_lockspace); +EXPORT_SYMBOL_GPL(dlm_lock); +EXPORT_SYMBOL_GPL(dlm_unlock); + diff --git a/fs/dlm/member.c b/fs/dlm/member.c new file mode 100644 index 000000000000..439249b62a57 --- /dev/null +++ b/fs/dlm/member.c @@ -0,0 +1,314 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "lockspace.h" +#include "member.h" +#include "recoverd.h" +#include "recover.h" +#include "lowcomms.h" +#include "rcom.h" +#include "config.h" + +/* + * Following called by dlm_recoverd thread + */ + +static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new) +{ + struct dlm_member *memb = NULL; + struct list_head *tmp; + struct list_head *newlist = &new->list; + struct list_head *head = &ls->ls_nodes; + + list_for_each(tmp, head) { + memb = list_entry(tmp, struct dlm_member, list); + if (new->nodeid < memb->nodeid) + break; + } + + if (!memb) + list_add_tail(newlist, head); + else { + /* FIXME: can use list macro here */ + newlist->prev = tmp->prev; + newlist->next = tmp; + tmp->prev->next = newlist; + tmp->prev = newlist; + } +} + +static int dlm_add_member(struct dlm_ls *ls, int nodeid) +{ + struct dlm_member *memb; + int w; + + memb = kmalloc(sizeof(struct dlm_member), GFP_KERNEL); + if (!memb) + return -ENOMEM; + + w = dlm_node_weight(ls->ls_name, nodeid); + if (w < 0) + return w; + + memb->nodeid = nodeid; + memb->weight = w; + add_ordered_member(ls, memb); + ls->ls_num_nodes++; + return 0; +} + +static void dlm_remove_member(struct dlm_ls *ls, struct dlm_member *memb) +{ + list_move(&memb->list, &ls->ls_nodes_gone); + ls->ls_num_nodes--; +} + +static int dlm_is_member(struct dlm_ls *ls, int nodeid) +{ + struct dlm_member *memb; + + list_for_each_entry(memb, &ls->ls_nodes, list) { + if (memb->nodeid == nodeid) + return TRUE; + } + return FALSE; +} + +int dlm_is_removed(struct dlm_ls *ls, int nodeid) +{ + struct dlm_member *memb; + + list_for_each_entry(memb, &ls->ls_nodes_gone, list) { + if (memb->nodeid == nodeid) + return TRUE; + } + return FALSE; +} + +static void clear_memb_list(struct list_head *head) +{ + struct dlm_member *memb; + + while (!list_empty(head)) { + memb = list_entry(head->next, struct dlm_member, list); + list_del(&memb->list); + kfree(memb); + } +} + +void dlm_clear_members(struct dlm_ls *ls) +{ + clear_memb_list(&ls->ls_nodes); + ls->ls_num_nodes = 0; +} + +void dlm_clear_members_gone(struct dlm_ls *ls) +{ + clear_memb_list(&ls->ls_nodes_gone); +} + +static void make_member_array(struct dlm_ls *ls) +{ + struct dlm_member *memb; + int i, w, x = 0, total = 0, all_zero = 0, *array; + + kfree(ls->ls_node_array); + ls->ls_node_array = NULL; + + list_for_each_entry(memb, &ls->ls_nodes, list) { + if (memb->weight) + total += memb->weight; + } + + /* all nodes revert to weight of 1 if all have weight 0 */ + + if (!total) { + total = ls->ls_num_nodes; + all_zero = 1; + } + + ls->ls_total_weight = total; + + array = kmalloc(sizeof(int) * total, GFP_KERNEL); + if (!array) + return; + + list_for_each_entry(memb, &ls->ls_nodes, list) { + if (!all_zero && !memb->weight) + continue; + + if (all_zero) + w = 1; + else + w = memb->weight; + + DLM_ASSERT(x < total, printk("total %d x %d\n", total, x);); + + for (i = 0; i < w; i++) + array[x++] = memb->nodeid; + } + + ls->ls_node_array = array; +} + +/* send a status request to all members just to establish comms connections */ + +static void ping_members(struct dlm_ls *ls) +{ + struct dlm_member *memb; + list_for_each_entry(memb, &ls->ls_nodes, list) + dlm_rcom_status(ls, memb->nodeid); +} + +int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) +{ + struct dlm_member *memb, *safe; + int i, error, found, pos = 0, neg = 0, low = -1; + + /* move departed members from ls_nodes to ls_nodes_gone */ + + list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) { + found = FALSE; + for (i = 0; i < rv->node_count; i++) { + if (memb->nodeid == rv->nodeids[i]) { + found = TRUE; + break; + } + } + + if (!found) { + neg++; + dlm_remove_member(ls, memb); + log_debug(ls, "remove member %d", memb->nodeid); + } + } + + /* add new members to ls_nodes */ + + for (i = 0; i < rv->node_count; i++) { + if (dlm_is_member(ls, rv->nodeids[i])) + continue; + dlm_add_member(ls, rv->nodeids[i]); + pos++; + log_debug(ls, "add member %d", rv->nodeids[i]); + } + + list_for_each_entry(memb, &ls->ls_nodes, list) { + if (low == -1 || memb->nodeid < low) + low = memb->nodeid; + } + ls->ls_low_nodeid = low; + + make_member_array(ls); + dlm_set_recover_status(ls, DLM_RS_NODES); + *neg_out = neg; + + ping_members(ls); + + error = dlm_recover_members_wait(ls); + log_debug(ls, "total members %d", ls->ls_num_nodes); + return error; +} + +/* + * Following called from lockspace.c + */ + +int dlm_ls_stop(struct dlm_ls *ls) +{ + int new; + + /* + * A stop cancels any recovery that's in progress (see RECOVERY_STOP, + * dlm_recovery_stopped()) and prevents any new locks from being + * processed (see RUNNING, dlm_locking_stopped()). + */ + + spin_lock(&ls->ls_recover_lock); + set_bit(LSFL_RECOVERY_STOP, &ls->ls_flags); + new = test_and_clear_bit(LSFL_RUNNING, &ls->ls_flags); + ls->ls_recover_seq++; + spin_unlock(&ls->ls_recover_lock); + + /* + * This in_recovery lock does two things: + * + * 1) Keeps this function from returning until all threads are out + * of locking routines and locking is truely stopped. + * 2) Keeps any new requests from being processed until it's unlocked + * when recovery is complete. + */ + + if (new) + down_write(&ls->ls_in_recovery); + + /* + * The recoverd suspend/resume makes sure that dlm_recoverd (if + * running) has noticed the clearing of RUNNING above and quit + * processing the previous recovery. This will be true for all nodes + * before any nodes start the new recovery. + */ + + dlm_recoverd_suspend(ls); + ls->ls_recover_status = 0; + dlm_recoverd_resume(ls); + return 0; +} + +int dlm_ls_start(struct dlm_ls *ls) +{ + struct dlm_recover *rv = NULL, *rv_old; + int *ids = NULL; + int error, count; + + rv = kmalloc(sizeof(struct dlm_recover), GFP_KERNEL); + if (!rv) + return -ENOMEM; + memset(rv, 0, sizeof(struct dlm_recover)); + + error = count = dlm_nodeid_list(ls->ls_name, &ids); + if (error <= 0) + goto fail; + + spin_lock(&ls->ls_recover_lock); + + /* the lockspace needs to be stopped before it can be started */ + + if (!dlm_locking_stopped(ls)) { + spin_unlock(&ls->ls_recover_lock); + log_error(ls, "start ignored: lockspace running"); + error = -EINVAL; + goto fail; + } + + rv->nodeids = ids; + rv->node_count = count; + rv->seq = ++ls->ls_recover_seq; + rv_old = ls->ls_recover_args; + ls->ls_recover_args = rv; + spin_unlock(&ls->ls_recover_lock); + + if (rv_old) { + kfree(rv_old->nodeids); + kfree(rv_old); + } + + dlm_recoverd_kick(ls); + return 0; + + fail: + kfree(rv); + kfree(ids); + return error; +} + diff --git a/fs/dlm/member.h b/fs/dlm/member.h new file mode 100644 index 000000000000..927c08c19214 --- /dev/null +++ b/fs/dlm/member.h @@ -0,0 +1,24 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __MEMBER_DOT_H__ +#define __MEMBER_DOT_H__ + +int dlm_ls_stop(struct dlm_ls *ls); +int dlm_ls_start(struct dlm_ls *ls); +void dlm_clear_members(struct dlm_ls *ls); +void dlm_clear_members_gone(struct dlm_ls *ls); +int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv,int *neg_out); +int dlm_is_removed(struct dlm_ls *ls, int nodeid); + +#endif /* __MEMBER_DOT_H__ */ + diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c new file mode 100644 index 000000000000..0b9851d0bdb2 --- /dev/null +++ b/fs/dlm/memory.c @@ -0,0 +1,122 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "config.h" +#include "memory.h" + +static kmem_cache_t *lkb_cache; + + +int dlm_memory_init(void) +{ + int ret = 0; + + lkb_cache = kmem_cache_create("dlm_lkb", sizeof(struct dlm_lkb), + __alignof__(struct dlm_lkb), 0, NULL, NULL); + if (!lkb_cache) + ret = -ENOMEM; + return ret; +} + +void dlm_memory_exit(void) +{ + if (lkb_cache) + kmem_cache_destroy(lkb_cache); +} + +char *allocate_lvb(struct dlm_ls *ls) +{ + char *p; + + p = kmalloc(ls->ls_lvblen, GFP_KERNEL); + if (p) + memset(p, 0, ls->ls_lvblen); + return p; +} + +void free_lvb(char *p) +{ + kfree(p); +} + +uint64_t *allocate_range(struct dlm_ls *ls) +{ + int ralen = 4*sizeof(uint64_t); + uint64_t *p; + + p = kmalloc(ralen, GFP_KERNEL); + if (p) + memset(p, 0, ralen); + return p; +} + +void free_range(uint64_t *p) +{ + kfree(p); +} + +/* FIXME: have some minimal space built-in to rsb for the name and + kmalloc a separate name if needed, like dentries are done */ + +struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen) +{ + struct dlm_rsb *r; + + DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,); + + r = kmalloc(sizeof(*r) + namelen, GFP_KERNEL); + if (r) + memset(r, 0, sizeof(*r) + namelen); + return r; +} + +void free_rsb(struct dlm_rsb *r) +{ + if (r->res_lvbptr) + free_lvb(r->res_lvbptr); + kfree(r); +} + +struct dlm_lkb *allocate_lkb(struct dlm_ls *ls) +{ + struct dlm_lkb *lkb; + + lkb = kmem_cache_alloc(lkb_cache, GFP_KERNEL); + if (lkb) + memset(lkb, 0, sizeof(*lkb)); + return lkb; +} + +void free_lkb(struct dlm_lkb *lkb) +{ + kmem_cache_free(lkb_cache, lkb); +} + +struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen) +{ + struct dlm_direntry *de; + + DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,); + + de = kmalloc(sizeof(*de) + namelen, GFP_KERNEL); + if (de) + memset(de, 0, sizeof(*de) + namelen); + return de; +} + +void free_direntry(struct dlm_direntry *de) +{ + kfree(de); +} + diff --git a/fs/dlm/memory.h b/fs/dlm/memory.h new file mode 100644 index 000000000000..7b235132b0b4 --- /dev/null +++ b/fs/dlm/memory.h @@ -0,0 +1,31 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __MEMORY_DOT_H__ +#define __MEMORY_DOT_H__ + +int dlm_memory_init(void); +void dlm_memory_exit(void); +struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen); +void free_rsb(struct dlm_rsb *r); +struct dlm_lkb *allocate_lkb(struct dlm_ls *ls); +void free_lkb(struct dlm_lkb *l); +struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen); +void free_direntry(struct dlm_direntry *de); +char *allocate_lvb(struct dlm_ls *ls); +void free_lvb(char *l); +uint64_t *allocate_range(struct dlm_ls *ls); +void free_range(uint64_t *l); + +#endif /* __MEMORY_DOT_H__ */ + diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c new file mode 100644 index 000000000000..d96f9bbb407c --- /dev/null +++ b/fs/dlm/midcomms.c @@ -0,0 +1,140 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +/* + * midcomms.c + * + * This is the appallingly named "mid-level" comms layer. + * + * Its purpose is to take packets from the "real" comms layer, + * split them up into packets and pass them to the interested + * part of the locking mechanism. + * + * It also takes messages from the locking layer, formats them + * into packets and sends them to the comms layer. + */ + +#include "dlm_internal.h" +#include "lowcomms.h" +#include "config.h" +#include "rcom.h" +#include "lock.h" +#include "midcomms.h" + + +static void copy_from_cb(void *dst, const void *base, unsigned offset, + unsigned len, unsigned limit) +{ + unsigned copy = len; + + if ((copy + offset) > limit) + copy = limit - offset; + memcpy(dst, base + offset, copy); + len -= copy; + if (len) + memcpy(dst + copy, base, len); +} + +/* + * Called from the low-level comms layer to process a buffer of + * commands. + * + * Only complete messages are processed here, any "spare" bytes from + * the end of a buffer are saved and tacked onto the front of the next + * message that comes in. I doubt this will happen very often but we + * need to be able to cope with it and I don't want the task to be waiting + * for packets to come in when there is useful work to be done. + */ + +int dlm_process_incoming_buffer(int nodeid, const void *base, + unsigned offset, unsigned len, unsigned limit) +{ + unsigned char __tmp[DLM_INBUF_LEN]; + struct dlm_header *msg = (struct dlm_header *) __tmp; + int ret = 0; + int err = 0; + uint16_t msglen; + uint32_t lockspace; + + while (len > sizeof(struct dlm_header)) { + + /* Copy just the header to check the total length. The + message may wrap around the end of the buffer back to the + start, so we need to use a temp buffer and copy_from_cb. */ + + copy_from_cb(msg, base, offset, sizeof(struct dlm_header), + limit); + + msglen = le16_to_cpu(msg->h_length); + lockspace = msg->h_lockspace; + + err = -EINVAL; + if (msglen < sizeof(struct dlm_header)) + break; + err = -E2BIG; + if (msglen > dlm_config.buffer_size) { + log_print("message size %d from %d too big, buf len %d", + msglen, nodeid, len); + break; + } + err = 0; + + /* If only part of the full message is contained in this + buffer, then do nothing and wait for lowcomms to call + us again later with more data. We return 0 meaning + we've consumed none of the input buffer. */ + + if (msglen > len) + break; + + /* Allocate a larger temp buffer if the full message won't fit + in the buffer on the stack (which should work for most + ordinary messages). */ + + if (msglen > sizeof(__tmp) && + msg == (struct dlm_header *) __tmp) { + msg = kmalloc(dlm_config.buffer_size, GFP_KERNEL); + if (msg == NULL) + return ret; + } + + copy_from_cb(msg, base, offset, msglen, limit); + + BUG_ON(lockspace != msg->h_lockspace); + + ret += msglen; + offset += msglen; + offset &= (limit - 1); + len -= msglen; + + switch (msg->h_cmd) { + case DLM_MSG: + dlm_receive_message(msg, nodeid, FALSE); + break; + + case DLM_RCOM: + dlm_receive_rcom(msg, nodeid); + break; + + default: + log_print("unknown msg type %x from %u: %u %u %u %u", + msg->h_cmd, nodeid, msglen, len, offset, ret); + } + } + + if (msg != (struct dlm_header *) __tmp) + kfree(msg); + + return err ? err : ret; +} + diff --git a/fs/dlm/midcomms.h b/fs/dlm/midcomms.h new file mode 100644 index 000000000000..95852a5f111d --- /dev/null +++ b/fs/dlm/midcomms.h @@ -0,0 +1,21 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __MIDCOMMS_DOT_H__ +#define __MIDCOMMS_DOT_H__ + +int dlm_process_incoming_buffer(int nodeid, const void *base, unsigned offset, + unsigned len, unsigned limit); + +#endif /* __MIDCOMMS_DOT_H__ */ + diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c new file mode 100644 index 000000000000..4c5c08a8860e --- /dev/null +++ b/fs/dlm/rcom.c @@ -0,0 +1,460 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "lockspace.h" +#include "member.h" +#include "lowcomms.h" +#include "midcomms.h" +#include "rcom.h" +#include "recover.h" +#include "dir.h" +#include "config.h" +#include "memory.h" +#include "lock.h" +#include "util.h" + + +static int rcom_response(struct dlm_ls *ls) +{ + return test_bit(LSFL_RCOM_READY, &ls->ls_flags); +} + +static int create_rcom(struct dlm_ls *ls, int to_nodeid, int type, int len, + struct dlm_rcom **rc_ret, struct dlm_mhandle **mh_ret) +{ + struct dlm_rcom *rc; + struct dlm_mhandle *mh; + char *mb; + int mb_len = sizeof(struct dlm_rcom) + len; + + mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_KERNEL, &mb); + if (!mh) { + log_print("create_rcom to %d type %d len %d ENOBUFS", + to_nodeid, type, len); + return -ENOBUFS; + } + memset(mb, 0, mb_len); + + rc = (struct dlm_rcom *) mb; + + rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR); + rc->rc_header.h_lockspace = ls->ls_global_id; + rc->rc_header.h_nodeid = dlm_our_nodeid(); + rc->rc_header.h_length = mb_len; + rc->rc_header.h_cmd = DLM_RCOM; + + rc->rc_type = type; + + *mh_ret = mh; + *rc_ret = rc; + return 0; +} + +static void send_rcom(struct dlm_ls *ls, struct dlm_mhandle *mh, + struct dlm_rcom *rc) +{ + dlm_rcom_out(rc); + dlm_lowcomms_commit_buffer(mh); +} + +/* When replying to a status request, a node also sends back its + configuration values. The requesting node then checks that the remote + node is configured the same way as itself. */ + +static void make_config(struct dlm_ls *ls, struct rcom_config *rf) +{ + rf->rf_lvblen = ls->ls_lvblen; + rf->rf_lsflags = ls->ls_exflags; +} + +static int check_config(struct dlm_ls *ls, struct rcom_config *rf, int nodeid) +{ + if (rf->rf_lvblen != ls->ls_lvblen || + rf->rf_lsflags != ls->ls_exflags) { + log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x", + ls->ls_lvblen, ls->ls_exflags, + nodeid, rf->rf_lvblen, rf->rf_lsflags); + return -EINVAL; + } + return 0; +} + +int dlm_rcom_status(struct dlm_ls *ls, int nodeid) +{ + struct dlm_rcom *rc; + struct dlm_mhandle *mh; + int error = 0; + + memset(ls->ls_recover_buf, 0, dlm_config.buffer_size); + + if (nodeid == dlm_our_nodeid()) { + rc = (struct dlm_rcom *) ls->ls_recover_buf; + rc->rc_result = dlm_recover_status(ls); + goto out; + } + + error = create_rcom(ls, nodeid, DLM_RCOM_STATUS, 0, &rc, &mh); + if (error) + goto out; + + send_rcom(ls, mh, rc); + + error = dlm_wait_function(ls, &rcom_response); + clear_bit(LSFL_RCOM_READY, &ls->ls_flags); + if (error) + goto out; + + rc = (struct dlm_rcom *) ls->ls_recover_buf; + + if (rc->rc_result == -ESRCH) { + /* we pretend the remote lockspace exists with 0 status */ + log_debug(ls, "remote node %d not ready", nodeid); + rc->rc_result = 0; + } else + error = check_config(ls, (struct rcom_config *) rc->rc_buf, + nodeid); + /* the caller looks at rc_result for the remote recovery status */ + out: + return error; +} + +static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in) +{ + struct dlm_rcom *rc; + struct dlm_mhandle *mh; + int error, nodeid = rc_in->rc_header.h_nodeid; + + error = create_rcom(ls, nodeid, DLM_RCOM_STATUS_REPLY, + sizeof(struct rcom_config), &rc, &mh); + if (error) + return; + rc->rc_result = dlm_recover_status(ls); + make_config(ls, (struct rcom_config *) rc->rc_buf); + + send_rcom(ls, mh, rc); +} + +static void receive_rcom_status_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) +{ + memcpy(ls->ls_recover_buf, rc_in, rc_in->rc_header.h_length); + set_bit(LSFL_RCOM_READY, &ls->ls_flags); + wake_up(&ls->ls_wait_general); +} + +int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) +{ + struct dlm_rcom *rc; + struct dlm_mhandle *mh; + int error = 0, len = sizeof(struct dlm_rcom); + + memset(ls->ls_recover_buf, 0, dlm_config.buffer_size); + + if (nodeid == dlm_our_nodeid()) { + dlm_copy_master_names(ls, last_name, last_len, + ls->ls_recover_buf + len, + dlm_config.buffer_size - len, nodeid); + goto out; + } + + error = create_rcom(ls, nodeid, DLM_RCOM_NAMES, last_len, &rc, &mh); + if (error) + goto out; + memcpy(rc->rc_buf, last_name, last_len); + + send_rcom(ls, mh, rc); + + error = dlm_wait_function(ls, &rcom_response); + clear_bit(LSFL_RCOM_READY, &ls->ls_flags); + out: + return error; +} + +static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in) +{ + struct dlm_rcom *rc; + struct dlm_mhandle *mh; + int error, inlen, outlen; + int nodeid = rc_in->rc_header.h_nodeid; + uint32_t status = dlm_recover_status(ls); + + /* + * We can't run dlm_dir_rebuild_send (which uses ls_nodes) while + * dlm_recoverd is running ls_nodes_reconfig (which changes ls_nodes). + * It could only happen in rare cases where we get a late NAMES + * message from a previous instance of recovery. + */ + + if (!(status & DLM_RS_NODES)) { + log_debug(ls, "ignoring RCOM_NAMES from %u", nodeid); + return; + } + + nodeid = rc_in->rc_header.h_nodeid; + inlen = rc_in->rc_header.h_length - sizeof(struct dlm_rcom); + outlen = dlm_config.buffer_size - sizeof(struct dlm_rcom); + + error = create_rcom(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, &rc, &mh); + if (error) + return; + + dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen, + nodeid); + send_rcom(ls, mh, rc); +} + +static void receive_rcom_names_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) +{ + memcpy(ls->ls_recover_buf, rc_in, rc_in->rc_header.h_length); + set_bit(LSFL_RCOM_READY, &ls->ls_flags); + wake_up(&ls->ls_wait_general); +} + +int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid) +{ + struct dlm_rcom *rc; + struct dlm_mhandle *mh; + struct dlm_ls *ls = r->res_ls; + int error; + + error = create_rcom(ls, dir_nodeid, DLM_RCOM_LOOKUP, r->res_length, + &rc, &mh); + if (error) + goto out; + memcpy(rc->rc_buf, r->res_name, r->res_length); + rc->rc_id = (unsigned long) r; + + send_rcom(ls, mh, rc); + out: + return error; +} + +static void receive_rcom_lookup(struct dlm_ls *ls, struct dlm_rcom *rc_in) +{ + struct dlm_rcom *rc; + struct dlm_mhandle *mh; + int error, ret_nodeid, nodeid = rc_in->rc_header.h_nodeid; + int len = rc_in->rc_header.h_length - sizeof(struct dlm_rcom); + + error = create_rcom(ls, nodeid, DLM_RCOM_LOOKUP_REPLY, 0, &rc, &mh); + if (error) + return; + + error = dlm_dir_lookup(ls, nodeid, rc_in->rc_buf, len, &ret_nodeid); + if (error) + ret_nodeid = error; + rc->rc_result = ret_nodeid; + rc->rc_id = rc_in->rc_id; + + send_rcom(ls, mh, rc); +} + +static void receive_rcom_lookup_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) +{ + dlm_recover_master_reply(ls, rc_in); +} + +static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb, + struct rcom_lock *rl) +{ + memset(rl, 0, sizeof(*rl)); + + rl->rl_ownpid = lkb->lkb_ownpid; + rl->rl_lkid = lkb->lkb_id; + rl->rl_exflags = lkb->lkb_exflags; + rl->rl_flags = lkb->lkb_flags; + rl->rl_lvbseq = lkb->lkb_lvbseq; + rl->rl_rqmode = lkb->lkb_rqmode; + rl->rl_grmode = lkb->lkb_grmode; + rl->rl_status = lkb->lkb_status; + rl->rl_wait_type = lkb->lkb_wait_type; + + if (lkb->lkb_bastaddr) + rl->rl_asts |= AST_BAST; + if (lkb->lkb_astaddr) + rl->rl_asts |= AST_COMP; + + if (lkb->lkb_range) + memcpy(rl->rl_range, lkb->lkb_range, 4*sizeof(uint64_t)); + + rl->rl_namelen = r->res_length; + memcpy(rl->rl_name, r->res_name, r->res_length); + + /* FIXME: might we have an lvb without DLM_LKF_VALBLK set ? + If so, receive_rcom_lock_args() won't take this copy. */ + + if (lkb->lkb_lvbptr) + memcpy(rl->rl_lvb, lkb->lkb_lvbptr, r->res_ls->ls_lvblen); +} + +int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) +{ + struct dlm_ls *ls = r->res_ls; + struct dlm_rcom *rc; + struct dlm_mhandle *mh; + struct rcom_lock *rl; + int error, len = sizeof(struct rcom_lock); + + if (lkb->lkb_lvbptr) + len += ls->ls_lvblen; + + error = create_rcom(ls, r->res_nodeid, DLM_RCOM_LOCK, len, &rc, &mh); + if (error) + goto out; + + rl = (struct rcom_lock *) rc->rc_buf; + pack_rcom_lock(r, lkb, rl); + rc->rc_id = (unsigned long) r; + + send_rcom(ls, mh, rc); + out: + return error; +} + +static void receive_rcom_lock(struct dlm_ls *ls, struct dlm_rcom *rc_in) +{ + struct dlm_rcom *rc; + struct dlm_mhandle *mh; + int error, nodeid = rc_in->rc_header.h_nodeid; + + dlm_recover_master_copy(ls, rc_in); + + error = create_rcom(ls, nodeid, DLM_RCOM_LOCK_REPLY, + sizeof(struct rcom_lock), &rc, &mh); + if (error) + return; + + /* We send back the same rcom_lock struct we received, but + dlm_recover_master_copy() has filled in rl_remid and rl_result */ + + memcpy(rc->rc_buf, rc_in->rc_buf, sizeof(struct rcom_lock)); + rc->rc_id = rc_in->rc_id; + + send_rcom(ls, mh, rc); +} + +static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) +{ + uint32_t status = dlm_recover_status(ls); + + if (!(status & DLM_RS_DIR)) { + log_debug(ls, "ignoring RCOM_LOCK_REPLY from %u", + rc_in->rc_header.h_nodeid); + return; + } + + dlm_recover_process_copy(ls, rc_in); +} + +static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in) +{ + struct dlm_rcom *rc; + struct dlm_mhandle *mh; + char *mb; + int mb_len = sizeof(struct dlm_rcom); + + mh = dlm_lowcomms_get_buffer(nodeid, mb_len, GFP_KERNEL, &mb); + if (!mh) + return -ENOBUFS; + memset(mb, 0, mb_len); + + rc = (struct dlm_rcom *) mb; + + rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR); + rc->rc_header.h_lockspace = rc_in->rc_header.h_lockspace; + rc->rc_header.h_nodeid = dlm_our_nodeid(); + rc->rc_header.h_length = mb_len; + rc->rc_header.h_cmd = DLM_RCOM; + + rc->rc_type = DLM_RCOM_STATUS_REPLY; + rc->rc_result = -ESRCH; + + dlm_rcom_out(rc); + dlm_lowcomms_commit_buffer(mh); + + return 0; +} + +/* Called by dlm_recvd; corresponds to dlm_receive_message() but special + recovery-only comms are sent through here. */ + +void dlm_receive_rcom(struct dlm_header *hd, int nodeid) +{ + struct dlm_rcom *rc = (struct dlm_rcom *) hd; + struct dlm_ls *ls; + + dlm_rcom_in(rc); + + /* If the lockspace doesn't exist then still send a status message + back; it's possible that it just doesn't have its global_id yet. */ + + ls = dlm_find_lockspace_global(hd->h_lockspace); + if (!ls) { + log_print("lockspace %x from %d not found", + hd->h_lockspace, nodeid); + send_ls_not_ready(nodeid, rc); + return; + } + + if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) { + log_error(ls, "ignoring recovery message %x from %d", + rc->rc_type, nodeid); + goto out; + } + + if (nodeid != rc->rc_header.h_nodeid) { + log_error(ls, "bad rcom nodeid %d from %d", + rc->rc_header.h_nodeid, nodeid); + goto out; + } + + switch (rc->rc_type) { + case DLM_RCOM_STATUS: + receive_rcom_status(ls, rc); + break; + + case DLM_RCOM_NAMES: + receive_rcom_names(ls, rc); + break; + + case DLM_RCOM_LOOKUP: + receive_rcom_lookup(ls, rc); + break; + + case DLM_RCOM_LOCK: + receive_rcom_lock(ls, rc); + break; + + case DLM_RCOM_STATUS_REPLY: + receive_rcom_status_reply(ls, rc); + break; + + case DLM_RCOM_NAMES_REPLY: + receive_rcom_names_reply(ls, rc); + break; + + case DLM_RCOM_LOOKUP_REPLY: + receive_rcom_lookup_reply(ls, rc); + break; + + case DLM_RCOM_LOCK_REPLY: + receive_rcom_lock_reply(ls, rc); + break; + + default: + DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type);); + } + out: + dlm_put_lockspace(ls); +} + diff --git a/fs/dlm/rcom.h b/fs/dlm/rcom.h new file mode 100644 index 000000000000..d7984321ff41 --- /dev/null +++ b/fs/dlm/rcom.h @@ -0,0 +1,24 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __RCOM_DOT_H__ +#define __RCOM_DOT_H__ + +int dlm_rcom_status(struct dlm_ls *ls, int nodeid); +int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len); +int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid); +int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb); +void dlm_receive_rcom(struct dlm_header *hd, int nodeid); + +#endif + diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c new file mode 100644 index 000000000000..1712c97bc229 --- /dev/null +++ b/fs/dlm/recover.c @@ -0,0 +1,762 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "lockspace.h" +#include "dir.h" +#include "config.h" +#include "ast.h" +#include "memory.h" +#include "rcom.h" +#include "lock.h" +#include "lowcomms.h" +#include "member.h" +#include "recover.h" + + +/* + * Recovery waiting routines: these functions wait for a particular reply from + * a remote node, or for the remote node to report a certain status. They need + * to abort if the lockspace is stopped indicating a node has failed (perhaps + * the one being waited for). + */ + +/* + * Wait until given function returns non-zero or lockspace is stopped + * (LS_RECOVERY_STOP set due to failure of a node in ls_nodes). When another + * function thinks it could have completed the waited-on task, they should wake + * up ls_wait_general to get an immediate response rather than waiting for the + * timer to detect the result. A timer wakes us up periodically while waiting + * to see if we should abort due to a node failure. This should only be called + * by the dlm_recoverd thread. + */ + +static void dlm_wait_timer_fn(unsigned long data) +{ + struct dlm_ls *ls = (struct dlm_ls *) data; + mod_timer(&ls->ls_timer, jiffies + (dlm_config.recover_timer * HZ)); + wake_up(&ls->ls_wait_general); +} + +int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls)) +{ + int error = 0; + + init_timer(&ls->ls_timer); + ls->ls_timer.function = dlm_wait_timer_fn; + ls->ls_timer.data = (long) ls; + ls->ls_timer.expires = jiffies + (dlm_config.recover_timer * HZ); + add_timer(&ls->ls_timer); + + wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls)); + del_timer_sync(&ls->ls_timer); + + if (dlm_recovery_stopped(ls)) { + log_debug(ls, "dlm_wait_function aborted"); + error = -EINTR; + } + return error; +} + +/* + * An efficient way for all nodes to wait for all others to have a certain + * status. The node with the lowest nodeid polls all the others for their + * status (wait_status_all) and all the others poll the node with the low id + * for its accumulated result (wait_status_low). When all nodes have set + * status flag X, then status flag X_ALL will be set on the low nodeid. + */ + +uint32_t dlm_recover_status(struct dlm_ls *ls) +{ + uint32_t status; + spin_lock(&ls->ls_recover_lock); + status = ls->ls_recover_status; + spin_unlock(&ls->ls_recover_lock); + return status; +} + +void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status) +{ + spin_lock(&ls->ls_recover_lock); + ls->ls_recover_status |= status; + spin_unlock(&ls->ls_recover_lock); +} + +static int wait_status_all(struct dlm_ls *ls, uint32_t wait_status) +{ + struct dlm_rcom *rc = (struct dlm_rcom *) ls->ls_recover_buf; + struct dlm_member *memb; + int error = 0, delay; + + list_for_each_entry(memb, &ls->ls_nodes, list) { + delay = 0; + for (;;) { + if (dlm_recovery_stopped(ls)) { + error = -EINTR; + goto out; + } + + error = dlm_rcom_status(ls, memb->nodeid); + if (error) + goto out; + + if (rc->rc_result & wait_status) + break; + if (delay < 1000) + delay += 20; + msleep(delay); + } + } + out: + return error; +} + +static int wait_status_low(struct dlm_ls *ls, uint32_t wait_status) +{ + struct dlm_rcom *rc = (struct dlm_rcom *) ls->ls_recover_buf; + int error = 0, delay = 0, nodeid = ls->ls_low_nodeid; + + for (;;) { + if (dlm_recovery_stopped(ls)) { + error = -EINTR; + goto out; + } + + error = dlm_rcom_status(ls, nodeid); + if (error) + break; + + if (rc->rc_result & wait_status) + break; + if (delay < 1000) + delay += 20; + msleep(delay); + } + out: + return error; +} + +static int wait_status(struct dlm_ls *ls, uint32_t status) +{ + uint32_t status_all = status << 1; + int error; + + if (ls->ls_low_nodeid == dlm_our_nodeid()) { + error = wait_status_all(ls, status); + if (!error) + dlm_set_recover_status(ls, status_all); + } else + error = wait_status_low(ls, status_all); + + return error; +} + +int dlm_recover_members_wait(struct dlm_ls *ls) +{ + return wait_status(ls, DLM_RS_NODES); +} + +int dlm_recover_directory_wait(struct dlm_ls *ls) +{ + return wait_status(ls, DLM_RS_DIR); +} + +int dlm_recover_locks_wait(struct dlm_ls *ls) +{ + return wait_status(ls, DLM_RS_LOCKS); +} + +int dlm_recover_done_wait(struct dlm_ls *ls) +{ + return wait_status(ls, DLM_RS_DONE); +} + +/* + * The recover_list contains all the rsb's for which we've requested the new + * master nodeid. As replies are returned from the resource directories the + * rsb's are removed from the list. When the list is empty we're done. + * + * The recover_list is later similarly used for all rsb's for which we've sent + * new lkb's and need to receive new corresponding lkid's. + * + * We use the address of the rsb struct as a simple local identifier for the + * rsb so we can match an rcom reply with the rsb it was sent for. + */ + +static int recover_list_empty(struct dlm_ls *ls) +{ + int empty; + + spin_lock(&ls->ls_recover_list_lock); + empty = list_empty(&ls->ls_recover_list); + spin_unlock(&ls->ls_recover_list_lock); + + return empty; +} + +static void recover_list_add(struct dlm_rsb *r) +{ + struct dlm_ls *ls = r->res_ls; + + spin_lock(&ls->ls_recover_list_lock); + if (list_empty(&r->res_recover_list)) { + list_add_tail(&r->res_recover_list, &ls->ls_recover_list); + ls->ls_recover_list_count++; + dlm_hold_rsb(r); + } + spin_unlock(&ls->ls_recover_list_lock); +} + +static void recover_list_del(struct dlm_rsb *r) +{ + struct dlm_ls *ls = r->res_ls; + + spin_lock(&ls->ls_recover_list_lock); + list_del_init(&r->res_recover_list); + ls->ls_recover_list_count--; + spin_unlock(&ls->ls_recover_list_lock); + + dlm_put_rsb(r); +} + +static struct dlm_rsb *recover_list_find(struct dlm_ls *ls, uint64_t id) +{ + struct dlm_rsb *r = NULL; + + spin_lock(&ls->ls_recover_list_lock); + + list_for_each_entry(r, &ls->ls_recover_list, res_recover_list) { + if (id == (unsigned long) r) + goto out; + } + r = NULL; + out: + spin_unlock(&ls->ls_recover_list_lock); + return r; +} + +static void recover_list_clear(struct dlm_ls *ls) +{ + struct dlm_rsb *r, *s; + + spin_lock(&ls->ls_recover_list_lock); + list_for_each_entry_safe(r, s, &ls->ls_recover_list, res_recover_list) { + list_del_init(&r->res_recover_list); + dlm_put_rsb(r); + ls->ls_recover_list_count--; + } + + if (ls->ls_recover_list_count != 0) { + log_error(ls, "warning: recover_list_count %d", + ls->ls_recover_list_count); + ls->ls_recover_list_count = 0; + } + spin_unlock(&ls->ls_recover_list_lock); +} + + +/* Master recovery: find new master node for rsb's that were + mastered on nodes that have been removed. + + dlm_recover_masters + recover_master + dlm_send_rcom_lookup -> receive_rcom_lookup + dlm_dir_lookup + receive_rcom_lookup_reply <- + dlm_recover_master_reply + set_new_master + set_master_lkbs + set_lock_master +*/ + +/* + * Set the lock master for all LKBs in a lock queue + * If we are the new master of the rsb, we may have received new + * MSTCPY locks from other nodes already which we need to ignore + * when setting the new nodeid. + */ + +static void set_lock_master(struct list_head *queue, int nodeid) +{ + struct dlm_lkb *lkb; + + list_for_each_entry(lkb, queue, lkb_statequeue) + if (!(lkb->lkb_flags & DLM_IFL_MSTCPY)) + lkb->lkb_nodeid = nodeid; +} + +static void set_master_lkbs(struct dlm_rsb *r) +{ + set_lock_master(&r->res_grantqueue, r->res_nodeid); + set_lock_master(&r->res_convertqueue, r->res_nodeid); + set_lock_master(&r->res_waitqueue, r->res_nodeid); +} + +/* + * Propogate the new master nodeid to locks + * The NEW_MASTER flag tells dlm_recover_locks() which rsb's to consider. + * The NEW_MASTER2 flag tells recover_lvb() which rsb's to consider. + */ + +static void set_new_master(struct dlm_rsb *r, int nodeid) +{ + lock_rsb(r); + r->res_nodeid = nodeid; + set_master_lkbs(r); + rsb_set_flag(r, RSB_NEW_MASTER); + rsb_set_flag(r, RSB_NEW_MASTER2); + unlock_rsb(r); +} + +/* + * We do async lookups on rsb's that need new masters. The rsb's + * waiting for a lookup reply are kept on the recover_list. + */ + +static int recover_master(struct dlm_rsb *r) +{ + struct dlm_ls *ls = r->res_ls; + int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid(); + + dir_nodeid = dlm_dir_nodeid(r); + + if (dir_nodeid == our_nodeid) { + error = dlm_dir_lookup(ls, our_nodeid, r->res_name, + r->res_length, &ret_nodeid); + if (error) + log_error(ls, "recover dir lookup error %d", error); + + if (ret_nodeid == our_nodeid) + ret_nodeid = 0; + set_new_master(r, ret_nodeid); + } else { + recover_list_add(r); + error = dlm_send_rcom_lookup(r, dir_nodeid); + } + + return error; +} + +/* + * When not using a directory, most resource names will hash to a new static + * master nodeid and the resource will need to be remastered. + */ + +static int recover_master_static(struct dlm_rsb *r) +{ + int master = dlm_dir_nodeid(r); + + if (master == dlm_our_nodeid()) + master = 0; + + if (r->res_nodeid != master) { + if (is_master(r)) + dlm_purge_mstcpy_locks(r); + set_new_master(r, master); + return 1; + } + return 0; +} + +/* + * Go through local root resources and for each rsb which has a master which + * has departed, get the new master nodeid from the directory. The dir will + * assign mastery to the first node to look up the new master. That means + * we'll discover in this lookup if we're the new master of any rsb's. + * + * We fire off all the dir lookup requests individually and asynchronously to + * the correct dir node. + */ + +int dlm_recover_masters(struct dlm_ls *ls) +{ + struct dlm_rsb *r; + int error = 0, count = 0; + + log_debug(ls, "dlm_recover_masters"); + + down_read(&ls->ls_root_sem); + list_for_each_entry(r, &ls->ls_root_list, res_root_list) { + if (dlm_recovery_stopped(ls)) { + up_read(&ls->ls_root_sem); + error = -EINTR; + goto out; + } + + if (dlm_no_directory(ls)) + count += recover_master_static(r); + else if (!is_master(r) && dlm_is_removed(ls, r->res_nodeid)) { + recover_master(r); + count++; + } + + schedule(); + } + up_read(&ls->ls_root_sem); + + log_debug(ls, "dlm_recover_masters %d resources", count); + + error = dlm_wait_function(ls, &recover_list_empty); + out: + if (error) + recover_list_clear(ls); + return error; +} + +int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc) +{ + struct dlm_rsb *r; + int nodeid; + + r = recover_list_find(ls, rc->rc_id); + if (!r) { + log_error(ls, "dlm_recover_master_reply no id %"PRIx64"", + rc->rc_id); + goto out; + } + + nodeid = rc->rc_result; + if (nodeid == dlm_our_nodeid()) + nodeid = 0; + + set_new_master(r, nodeid); + recover_list_del(r); + + if (recover_list_empty(ls)) + wake_up(&ls->ls_wait_general); + out: + return 0; +} + + +/* Lock recovery: rebuild the process-copy locks we hold on a + remastered rsb on the new rsb master. + + dlm_recover_locks + recover_locks + recover_locks_queue + dlm_send_rcom_lock -> receive_rcom_lock + dlm_recover_master_copy + receive_rcom_lock_reply <- + dlm_recover_process_copy +*/ + + +/* + * keep a count of the number of lkb's we send to the new master; when we get + * an equal number of replies then recovery for the rsb is done + */ + +static int recover_locks_queue(struct dlm_rsb *r, struct list_head *head) +{ + struct dlm_lkb *lkb; + int error = 0; + + list_for_each_entry(lkb, head, lkb_statequeue) { + error = dlm_send_rcom_lock(r, lkb); + if (error) + break; + r->res_recover_locks_count++; + } + + return error; +} + +static int all_queues_empty(struct dlm_rsb *r) +{ + if (!list_empty(&r->res_grantqueue) || + !list_empty(&r->res_convertqueue) || + !list_empty(&r->res_waitqueue)) + return FALSE; + return TRUE; +} + +static int recover_locks(struct dlm_rsb *r) +{ + int error = 0; + + lock_rsb(r); + if (all_queues_empty(r)) + goto out; + + DLM_ASSERT(!r->res_recover_locks_count, dlm_print_rsb(r);); + + error = recover_locks_queue(r, &r->res_grantqueue); + if (error) + goto out; + error = recover_locks_queue(r, &r->res_convertqueue); + if (error) + goto out; + error = recover_locks_queue(r, &r->res_waitqueue); + if (error) + goto out; + + if (r->res_recover_locks_count) + recover_list_add(r); + else + rsb_clear_flag(r, RSB_NEW_MASTER); + out: + unlock_rsb(r); + return error; +} + +int dlm_recover_locks(struct dlm_ls *ls) +{ + struct dlm_rsb *r; + int error, count = 0; + + log_debug(ls, "dlm_recover_locks"); + + down_read(&ls->ls_root_sem); + list_for_each_entry(r, &ls->ls_root_list, res_root_list) { + if (is_master(r)) { + rsb_clear_flag(r, RSB_NEW_MASTER); + continue; + } + + if (!rsb_flag(r, RSB_NEW_MASTER)) + continue; + + if (dlm_recovery_stopped(ls)) { + error = -EINTR; + up_read(&ls->ls_root_sem); + goto out; + } + + error = recover_locks(r); + if (error) { + up_read(&ls->ls_root_sem); + goto out; + } + + count += r->res_recover_locks_count; + } + up_read(&ls->ls_root_sem); + + log_debug(ls, "dlm_recover_locks %d locks", count); + + error = dlm_wait_function(ls, &recover_list_empty); + out: + if (error) + recover_list_clear(ls); + else + dlm_set_recover_status(ls, DLM_RS_LOCKS); + return error; +} + +void dlm_recovered_lock(struct dlm_rsb *r) +{ + DLM_ASSERT(rsb_flag(r, RSB_NEW_MASTER), dlm_print_rsb(r);); + + r->res_recover_locks_count--; + if (!r->res_recover_locks_count) { + rsb_clear_flag(r, RSB_NEW_MASTER); + recover_list_del(r); + } + + if (recover_list_empty(r->res_ls)) + wake_up(&r->res_ls->ls_wait_general); +} + +/* + * The lvb needs to be recovered on all master rsb's. This includes setting + * the VALNOTVALID flag if necessary, and determining the correct lvb contents + * based on the lvb's of the locks held on the rsb. + * + * RSB_VALNOTVALID is set if there are only NL/CR locks on the rsb. If it + * was already set prior to recovery, it's not cleared, regardless of locks. + * + * The LVB contents are only considered for changing when this is a new master + * of the rsb (NEW_MASTER2). Then, the rsb's lvb is taken from any lkb with + * mode > CR. If no lkb's exist with mode above CR, the lvb contents are taken + * from the lkb with the largest lvb sequence number. + */ + +static void recover_lvb(struct dlm_rsb *r) +{ + struct dlm_lkb *lkb, *high_lkb = NULL; + uint32_t high_seq = 0; + int lock_lvb_exists = FALSE; + int big_lock_exists = FALSE; + int lvblen = r->res_ls->ls_lvblen; + + list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) { + if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) + continue; + + lock_lvb_exists = TRUE; + + if (lkb->lkb_grmode > DLM_LOCK_CR) { + big_lock_exists = TRUE; + goto setflag; + } + + if (((int)lkb->lkb_lvbseq - (int)high_seq) >= 0) { + high_lkb = lkb; + high_seq = lkb->lkb_lvbseq; + } + } + + list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) { + if (!(lkb->lkb_exflags & DLM_LKF_VALBLK)) + continue; + + lock_lvb_exists = TRUE; + + if (lkb->lkb_grmode > DLM_LOCK_CR) { + big_lock_exists = TRUE; + goto setflag; + } + + if (((int)lkb->lkb_lvbseq - (int)high_seq) >= 0) { + high_lkb = lkb; + high_seq = lkb->lkb_lvbseq; + } + } + + setflag: + if (!lock_lvb_exists) + goto out; + + if (!big_lock_exists) + rsb_set_flag(r, RSB_VALNOTVALID); + + /* don't mess with the lvb unless we're the new master */ + if (!rsb_flag(r, RSB_NEW_MASTER2)) + goto out; + + if (!r->res_lvbptr) { + r->res_lvbptr = allocate_lvb(r->res_ls); + if (!r->res_lvbptr) + goto out; + } + + if (big_lock_exists) { + r->res_lvbseq = lkb->lkb_lvbseq; + memcpy(r->res_lvbptr, lkb->lkb_lvbptr, lvblen); + } else if (high_lkb) { + r->res_lvbseq = high_lkb->lkb_lvbseq; + memcpy(r->res_lvbptr, high_lkb->lkb_lvbptr, lvblen); + } else { + r->res_lvbseq = 0; + memset(r->res_lvbptr, 0, lvblen); + } + out: + return; +} + +/* All master rsb's flagged RECOVER_CONVERT need to be looked at. The locks + converting PR->CW or CW->PR need to have their lkb_grmode set. */ + +static void recover_conversion(struct dlm_rsb *r) +{ + struct dlm_lkb *lkb; + int grmode = -1; + + list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) { + if (lkb->lkb_grmode == DLM_LOCK_PR || + lkb->lkb_grmode == DLM_LOCK_CW) { + grmode = lkb->lkb_grmode; + break; + } + } + + list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) { + if (lkb->lkb_grmode != DLM_LOCK_IV) + continue; + if (grmode == -1) + lkb->lkb_grmode = lkb->lkb_rqmode; + else + lkb->lkb_grmode = grmode; + } +} + +void dlm_recover_rsbs(struct dlm_ls *ls) +{ + struct dlm_rsb *r; + int count = 0; + + log_debug(ls, "dlm_recover_rsbs"); + + down_read(&ls->ls_root_sem); + list_for_each_entry(r, &ls->ls_root_list, res_root_list) { + lock_rsb(r); + if (is_master(r)) { + if (rsb_flag(r, RSB_RECOVER_CONVERT)) + recover_conversion(r); + recover_lvb(r); + count++; + } + rsb_clear_flag(r, RSB_RECOVER_CONVERT); + unlock_rsb(r); + } + up_read(&ls->ls_root_sem); + + log_debug(ls, "dlm_recover_rsbs %d rsbs", count); +} + +/* Create a single list of all root rsb's to be used during recovery */ + +int dlm_create_root_list(struct dlm_ls *ls) +{ + struct dlm_rsb *r; + int i, error = 0; + + down_write(&ls->ls_root_sem); + if (!list_empty(&ls->ls_root_list)) { + log_error(ls, "root list not empty"); + error = -EINVAL; + goto out; + } + + for (i = 0; i < ls->ls_rsbtbl_size; i++) { + read_lock(&ls->ls_rsbtbl[i].lock); + list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) { + list_add(&r->res_root_list, &ls->ls_root_list); + dlm_hold_rsb(r); + } + read_unlock(&ls->ls_rsbtbl[i].lock); + } + out: + up_write(&ls->ls_root_sem); + return error; +} + +void dlm_release_root_list(struct dlm_ls *ls) +{ + struct dlm_rsb *r, *safe; + + down_write(&ls->ls_root_sem); + list_for_each_entry_safe(r, safe, &ls->ls_root_list, res_root_list) { + list_del_init(&r->res_root_list); + dlm_put_rsb(r); + } + up_write(&ls->ls_root_sem); +} + +void dlm_clear_toss_list(struct dlm_ls *ls) +{ + struct dlm_rsb *r, *safe; + int i; + + for (i = 0; i < ls->ls_rsbtbl_size; i++) { + write_lock(&ls->ls_rsbtbl[i].lock); + list_for_each_entry_safe(r, safe, &ls->ls_rsbtbl[i].toss, + res_hashchain) { + list_del(&r->res_hashchain); + free_rsb(r); + } + write_unlock(&ls->ls_rsbtbl[i].lock); + } +} + diff --git a/fs/dlm/recover.h b/fs/dlm/recover.h new file mode 100644 index 000000000000..ebd0363f1e08 --- /dev/null +++ b/fs/dlm/recover.h @@ -0,0 +1,34 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __RECOVER_DOT_H__ +#define __RECOVER_DOT_H__ + +int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls)); +uint32_t dlm_recover_status(struct dlm_ls *ls); +void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status); +int dlm_recover_members_wait(struct dlm_ls *ls); +int dlm_recover_directory_wait(struct dlm_ls *ls); +int dlm_recover_locks_wait(struct dlm_ls *ls); +int dlm_recover_done_wait(struct dlm_ls *ls); +int dlm_recover_masters(struct dlm_ls *ls); +int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc); +int dlm_recover_locks(struct dlm_ls *ls); +void dlm_recovered_lock(struct dlm_rsb *r); +int dlm_create_root_list(struct dlm_ls *ls); +void dlm_release_root_list(struct dlm_ls *ls); +void dlm_clear_toss_list(struct dlm_ls *ls); +void dlm_recover_rsbs(struct dlm_ls *ls); + +#endif /* __RECOVER_DOT_H__ */ + diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c new file mode 100644 index 000000000000..06e4f7cab6e7 --- /dev/null +++ b/fs/dlm/recoverd.c @@ -0,0 +1,285 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "lockspace.h" +#include "member.h" +#include "dir.h" +#include "ast.h" +#include "recover.h" +#include "lowcomms.h" +#include "lock.h" +#include "requestqueue.h" +#include "recoverd.h" + + +/* If the start for which we're re-enabling locking (seq) has been superseded + by a newer stop (ls_recover_seq), we need to leave locking disabled. */ + +static int enable_locking(struct dlm_ls *ls, uint64_t seq) +{ + int error = -EINTR; + + spin_lock(&ls->ls_recover_lock); + if (ls->ls_recover_seq == seq) { + set_bit(LSFL_RUNNING, &ls->ls_flags); + up_write(&ls->ls_in_recovery); + error = 0; + } + spin_unlock(&ls->ls_recover_lock); + return error; +} + +static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) +{ + unsigned long start; + int error, neg = 0; + + log_debug(ls, "recover %"PRIx64"", rv->seq); + + down(&ls->ls_recoverd_active); + + /* + * Suspending and resuming dlm_astd ensures that no lkb's from this ls + * will be processed by dlm_astd during recovery. + */ + + dlm_astd_suspend(); + dlm_astd_resume(); + + /* + * This list of root rsb's will be the basis of most of the recovery + * routines. + */ + + dlm_create_root_list(ls); + + /* + * Free all the tossed rsb's so we don't have to recover them. + */ + + dlm_clear_toss_list(ls); + + /* + * Add or remove nodes from the lockspace's ls_nodes list. + * Also waits for all nodes to complete dlm_recover_members. + */ + + error = dlm_recover_members(ls, rv, &neg); + if (error) { + log_error(ls, "recover_members failed %d", error); + goto fail; + } + start = jiffies; + + /* + * Rebuild our own share of the directory by collecting from all other + * nodes their master rsb names that hash to us. + */ + + error = dlm_recover_directory(ls); + if (error) { + log_error(ls, "recover_directory failed %d", error); + goto fail; + } + + /* + * Purge directory-related requests that are saved in requestqueue. + * All dir requests from before recovery are invalid now due to the dir + * rebuild and will be resent by the requesting nodes. + */ + + dlm_purge_requestqueue(ls); + + /* + * Wait for all nodes to complete directory rebuild. + */ + + error = dlm_recover_directory_wait(ls); + if (error) { + log_error(ls, "recover_directory_wait failed %d", error); + goto fail; + } + + /* + * We may have outstanding operations that are waiting for a reply from + * a failed node. Mark these to be resent after recovery. Unlock and + * cancel ops can just be completed. + */ + + dlm_recover_waiters_pre(ls); + + error = dlm_recovery_stopped(ls); + if (error) + goto fail; + + if (neg || dlm_no_directory(ls)) { + /* + * Clear lkb's for departed nodes. + */ + + dlm_purge_locks(ls); + + /* + * Get new master nodeid's for rsb's that were mastered on + * departed nodes. + */ + + error = dlm_recover_masters(ls); + if (error) { + log_error(ls, "recover_masters failed %d", error); + goto fail; + } + + /* + * Send our locks on remastered rsb's to the new masters. + */ + + error = dlm_recover_locks(ls); + if (error) { + log_error(ls, "recover_locks failed %d", error); + goto fail; + } + + error = dlm_recover_locks_wait(ls); + if (error) { + log_error(ls, "recover_locks_wait failed %d", error); + goto fail; + } + + /* + * Finalize state in master rsb's now that all locks can be + * checked. This includes conversion resolution and lvb + * settings. + */ + + dlm_recover_rsbs(ls); + } + + dlm_release_root_list(ls); + + dlm_set_recover_status(ls, DLM_RS_DONE); + error = dlm_recover_done_wait(ls); + if (error) { + log_error(ls, "recover_done_wait failed %d", error); + goto fail; + } + + dlm_clear_members_gone(ls); + + error = enable_locking(ls, rv->seq); + if (error) { + log_error(ls, "enable_locking failed %d", error); + goto fail; + } + + error = dlm_process_requestqueue(ls); + if (error) { + log_error(ls, "process_requestqueue failed %d", error); + goto fail; + } + + error = dlm_recover_waiters_post(ls); + if (error) { + log_error(ls, "recover_waiters_post failed %d", error); + goto fail; + } + + dlm_grant_after_purge(ls); + + dlm_astd_wake(); + + log_debug(ls, "recover %"PRIx64" done: %u ms", rv->seq, + jiffies_to_msecs(jiffies - start)); + up(&ls->ls_recoverd_active); + + return 0; + + fail: + dlm_release_root_list(ls); + log_debug(ls, "recover %"PRIx64" error %d", rv->seq, error); + up(&ls->ls_recoverd_active); + return error; +} + +static void do_ls_recovery(struct dlm_ls *ls) +{ + struct dlm_recover *rv = NULL; + + spin_lock(&ls->ls_recover_lock); + rv = ls->ls_recover_args; + ls->ls_recover_args = NULL; + clear_bit(LSFL_RECOVERY_STOP, &ls->ls_flags); + spin_unlock(&ls->ls_recover_lock); + + if (rv) { + ls_recover(ls, rv); + kfree(rv->nodeids); + kfree(rv); + } +} + +static int dlm_recoverd(void *arg) +{ + struct dlm_ls *ls; + + ls = dlm_find_lockspace_local(arg); + + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + if (!test_bit(LSFL_WORK, &ls->ls_flags)) + schedule(); + set_current_state(TASK_RUNNING); + + if (test_and_clear_bit(LSFL_WORK, &ls->ls_flags)) + do_ls_recovery(ls); + } + + dlm_put_lockspace(ls); + return 0; +} + +void dlm_recoverd_kick(struct dlm_ls *ls) +{ + set_bit(LSFL_WORK, &ls->ls_flags); + wake_up_process(ls->ls_recoverd_task); +} + +int dlm_recoverd_start(struct dlm_ls *ls) +{ + struct task_struct *p; + int error = 0; + + p = kthread_run(dlm_recoverd, ls, "dlm_recoverd"); + if (IS_ERR(p)) + error = PTR_ERR(p); + else + ls->ls_recoverd_task = p; + return error; +} + +void dlm_recoverd_stop(struct dlm_ls *ls) +{ + kthread_stop(ls->ls_recoverd_task); +} + +void dlm_recoverd_suspend(struct dlm_ls *ls) +{ + down(&ls->ls_recoverd_active); +} + +void dlm_recoverd_resume(struct dlm_ls *ls) +{ + up(&ls->ls_recoverd_active); +} + diff --git a/fs/dlm/recoverd.h b/fs/dlm/recoverd.h new file mode 100644 index 000000000000..866657c5d69d --- /dev/null +++ b/fs/dlm/recoverd.h @@ -0,0 +1,24 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __RECOVERD_DOT_H__ +#define __RECOVERD_DOT_H__ + +void dlm_recoverd_kick(struct dlm_ls *ls); +void dlm_recoverd_stop(struct dlm_ls *ls); +int dlm_recoverd_start(struct dlm_ls *ls); +void dlm_recoverd_suspend(struct dlm_ls *ls); +void dlm_recoverd_resume(struct dlm_ls *ls); + +#endif /* __RECOVERD_DOT_H__ */ + diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c new file mode 100644 index 000000000000..36afe99e4f93 --- /dev/null +++ b/fs/dlm/requestqueue.c @@ -0,0 +1,184 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "member.h" +#include "lock.h" +#include "dir.h" +#include "config.h" +#include "requestqueue.h" + +struct rq_entry { + struct list_head list; + int nodeid; + char request[1]; +}; + +/* + * Requests received while the lockspace is in recovery get added to the + * request queue and processed when recovery is complete. This happens when + * the lockspace is suspended on some nodes before it is on others, or the + * lockspace is enabled on some while still suspended on others. + */ + +void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd) +{ + struct rq_entry *e; + int length = hd->h_length; + + if (dlm_is_removed(ls, nodeid)) + return; + + e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL); + if (!e) { + log_print("dlm_add_requestqueue: out of memory\n"); + return; + } + + e->nodeid = nodeid; + memcpy(e->request, hd, length); + + down(&ls->ls_requestqueue_lock); + list_add_tail(&e->list, &ls->ls_requestqueue); + up(&ls->ls_requestqueue_lock); +} + +int dlm_process_requestqueue(struct dlm_ls *ls) +{ + struct rq_entry *e; + struct dlm_header *hd; + int error = 0; + + down(&ls->ls_requestqueue_lock); + + for (;;) { + if (list_empty(&ls->ls_requestqueue)) { + up(&ls->ls_requestqueue_lock); + error = 0; + break; + } + e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list); + up(&ls->ls_requestqueue_lock); + + hd = (struct dlm_header *) e->request; + error = dlm_receive_message(hd, e->nodeid, TRUE); + + if (error == -EINTR) { + /* entry is left on requestqueue */ + log_debug(ls, "process_requestqueue abort eintr"); + break; + } + + down(&ls->ls_requestqueue_lock); + list_del(&e->list); + kfree(e); + + if (dlm_locking_stopped(ls)) { + log_debug(ls, "process_requestqueue abort running"); + up(&ls->ls_requestqueue_lock); + error = -EINTR; + break; + } + schedule(); + } + + return error; +} + +/* + * After recovery is done, locking is resumed and dlm_recoverd takes all the + * saved requests and processes them as they would have been by dlm_recvd. At + * the same time, dlm_recvd will start receiving new requests from remote + * nodes. We want to delay dlm_recvd processing new requests until + * dlm_recoverd has finished processing the old saved requests. + */ + +void dlm_wait_requestqueue(struct dlm_ls *ls) +{ + for (;;) { + down(&ls->ls_requestqueue_lock); + if (list_empty(&ls->ls_requestqueue)) + break; + if (dlm_locking_stopped(ls)) + break; + up(&ls->ls_requestqueue_lock); + schedule(); + } + up(&ls->ls_requestqueue_lock); +} + +static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid) +{ + uint32_t type = ms->m_type; + + if (dlm_is_removed(ls, nodeid)) + return 1; + + /* directory operations are always purged because the directory is + always rebuilt during recovery and the lookups resent */ + + if (type == DLM_MSG_REMOVE || + type == DLM_MSG_LOOKUP || + type == DLM_MSG_LOOKUP_REPLY) + return 1; + + if (!dlm_no_directory(ls)) + return 0; + + /* with no directory, the master is likely to change as a part of + recovery; requests to/from the defunct master need to be purged */ + + switch (type) { + case DLM_MSG_REQUEST: + case DLM_MSG_CONVERT: + case DLM_MSG_UNLOCK: + case DLM_MSG_CANCEL: + /* we're no longer the master of this resource, the sender + will resend to the new master (see waiter_needs_recovery) */ + + if (dlm_hash2nodeid(ls, ms->m_hash) != dlm_our_nodeid()) + return 1; + break; + + case DLM_MSG_REQUEST_REPLY: + case DLM_MSG_CONVERT_REPLY: + case DLM_MSG_UNLOCK_REPLY: + case DLM_MSG_CANCEL_REPLY: + case DLM_MSG_GRANT: + /* this reply is from the former master of the resource, + we'll resend to the new master if needed */ + + if (dlm_hash2nodeid(ls, ms->m_hash) != nodeid) + return 1; + break; + } + + return 0; +} + +void dlm_purge_requestqueue(struct dlm_ls *ls) +{ + struct dlm_message *ms; + struct rq_entry *e, *safe; + + down(&ls->ls_requestqueue_lock); + list_for_each_entry_safe(e, safe, &ls->ls_requestqueue, list) { + ms = (struct dlm_message *) e->request; + + if (purge_request(ls, ms, e->nodeid)) { + list_del(&e->list); + kfree(e); + } + } + up(&ls->ls_requestqueue_lock); +} + diff --git a/fs/dlm/requestqueue.h b/fs/dlm/requestqueue.h new file mode 100644 index 000000000000..349f0d292d95 --- /dev/null +++ b/fs/dlm/requestqueue.h @@ -0,0 +1,22 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __REQUESTQUEUE_DOT_H__ +#define __REQUESTQUEUE_DOT_H__ + +void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd); +int dlm_process_requestqueue(struct dlm_ls *ls); +void dlm_wait_requestqueue(struct dlm_ls *ls); +void dlm_purge_requestqueue(struct dlm_ls *ls); + +#endif + diff --git a/fs/dlm/util.c b/fs/dlm/util.c new file mode 100644 index 000000000000..826d122edf55 --- /dev/null +++ b/fs/dlm/util.c @@ -0,0 +1,173 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#include "dlm_internal.h" +#include "rcom.h" +#include "util.h" + +static void header_out(struct dlm_header *hd) +{ + hd->h_version = cpu_to_le32(hd->h_version); + hd->h_lockspace = cpu_to_le32(hd->h_lockspace); + hd->h_nodeid = cpu_to_le32(hd->h_nodeid); + hd->h_length = cpu_to_le16(hd->h_length); +} + +static void header_in(struct dlm_header *hd) +{ + hd->h_version = le32_to_cpu(hd->h_version); + hd->h_lockspace = le32_to_cpu(hd->h_lockspace); + hd->h_nodeid = le32_to_cpu(hd->h_nodeid); + hd->h_length = le16_to_cpu(hd->h_length); +} + +void dlm_message_out(struct dlm_message *ms) +{ + struct dlm_header *hd = (struct dlm_header *) ms; + + header_out(hd); + + ms->m_type = cpu_to_le32(ms->m_type); + ms->m_nodeid = cpu_to_le32(ms->m_nodeid); + ms->m_pid = cpu_to_le32(ms->m_pid); + ms->m_lkid = cpu_to_le32(ms->m_lkid); + ms->m_remid = cpu_to_le32(ms->m_remid); + ms->m_parent_lkid = cpu_to_le32(ms->m_parent_lkid); + ms->m_parent_remid = cpu_to_le32(ms->m_parent_remid); + ms->m_exflags = cpu_to_le32(ms->m_exflags); + ms->m_sbflags = cpu_to_le32(ms->m_sbflags); + ms->m_flags = cpu_to_le32(ms->m_flags); + ms->m_lvbseq = cpu_to_le32(ms->m_lvbseq); + ms->m_hash = cpu_to_le32(ms->m_hash); + ms->m_status = cpu_to_le32(ms->m_status); + ms->m_grmode = cpu_to_le32(ms->m_grmode); + ms->m_rqmode = cpu_to_le32(ms->m_rqmode); + ms->m_bastmode = cpu_to_le32(ms->m_bastmode); + ms->m_asts = cpu_to_le32(ms->m_asts); + ms->m_result = cpu_to_le32(ms->m_result); + ms->m_range[0] = cpu_to_le64(ms->m_range[0]); + ms->m_range[1] = cpu_to_le64(ms->m_range[1]); +} + +void dlm_message_in(struct dlm_message *ms) +{ + struct dlm_header *hd = (struct dlm_header *) ms; + + header_in(hd); + + ms->m_type = le32_to_cpu(ms->m_type); + ms->m_nodeid = le32_to_cpu(ms->m_nodeid); + ms->m_pid = le32_to_cpu(ms->m_pid); + ms->m_lkid = le32_to_cpu(ms->m_lkid); + ms->m_remid = le32_to_cpu(ms->m_remid); + ms->m_parent_lkid = le32_to_cpu(ms->m_parent_lkid); + ms->m_parent_remid = le32_to_cpu(ms->m_parent_remid); + ms->m_exflags = le32_to_cpu(ms->m_exflags); + ms->m_sbflags = le32_to_cpu(ms->m_sbflags); + ms->m_flags = le32_to_cpu(ms->m_flags); + ms->m_lvbseq = le32_to_cpu(ms->m_lvbseq); + ms->m_hash = le32_to_cpu(ms->m_hash); + ms->m_status = le32_to_cpu(ms->m_status); + ms->m_grmode = le32_to_cpu(ms->m_grmode); + ms->m_rqmode = le32_to_cpu(ms->m_rqmode); + ms->m_bastmode = le32_to_cpu(ms->m_bastmode); + ms->m_asts = le32_to_cpu(ms->m_asts); + ms->m_result = le32_to_cpu(ms->m_result); + ms->m_range[0] = le64_to_cpu(ms->m_range[0]); + ms->m_range[1] = le64_to_cpu(ms->m_range[1]); +} + +static void rcom_lock_out(struct rcom_lock *rl) +{ + rl->rl_ownpid = cpu_to_le32(rl->rl_ownpid); + rl->rl_lkid = cpu_to_le32(rl->rl_lkid); + rl->rl_remid = cpu_to_le32(rl->rl_remid); + rl->rl_parent_lkid = cpu_to_le32(rl->rl_parent_lkid); + rl->rl_parent_remid = cpu_to_le32(rl->rl_parent_remid); + rl->rl_exflags = cpu_to_le32(rl->rl_exflags); + rl->rl_flags = cpu_to_le32(rl->rl_flags); + rl->rl_lvbseq = cpu_to_le32(rl->rl_lvbseq); + rl->rl_result = cpu_to_le32(rl->rl_result); + rl->rl_wait_type = cpu_to_le16(rl->rl_wait_type); + rl->rl_namelen = cpu_to_le16(rl->rl_namelen); + rl->rl_range[0] = cpu_to_le64(rl->rl_range[0]); + rl->rl_range[1] = cpu_to_le64(rl->rl_range[1]); + rl->rl_range[2] = cpu_to_le64(rl->rl_range[2]); + rl->rl_range[3] = cpu_to_le64(rl->rl_range[3]); +} + +static void rcom_lock_in(struct rcom_lock *rl) +{ + rl->rl_ownpid = le32_to_cpu(rl->rl_ownpid); + rl->rl_lkid = le32_to_cpu(rl->rl_lkid); + rl->rl_remid = le32_to_cpu(rl->rl_remid); + rl->rl_parent_lkid = le32_to_cpu(rl->rl_parent_lkid); + rl->rl_parent_remid = le32_to_cpu(rl->rl_parent_remid); + rl->rl_exflags = le32_to_cpu(rl->rl_exflags); + rl->rl_flags = le32_to_cpu(rl->rl_flags); + rl->rl_lvbseq = le32_to_cpu(rl->rl_lvbseq); + rl->rl_result = le32_to_cpu(rl->rl_result); + rl->rl_wait_type = le16_to_cpu(rl->rl_wait_type); + rl->rl_namelen = le16_to_cpu(rl->rl_namelen); + rl->rl_range[0] = le64_to_cpu(rl->rl_range[0]); + rl->rl_range[1] = le64_to_cpu(rl->rl_range[1]); + rl->rl_range[2] = le64_to_cpu(rl->rl_range[2]); + rl->rl_range[3] = le64_to_cpu(rl->rl_range[3]); +} + +static void rcom_config_out(struct rcom_config *rf) +{ + rf->rf_lvblen = cpu_to_le32(rf->rf_lvblen); + rf->rf_lsflags = cpu_to_le32(rf->rf_lsflags); +} + +static void rcom_config_in(struct rcom_config *rf) +{ + rf->rf_lvblen = le32_to_cpu(rf->rf_lvblen); + rf->rf_lsflags = le32_to_cpu(rf->rf_lsflags); +} + +void dlm_rcom_out(struct dlm_rcom *rc) +{ + struct dlm_header *hd = (struct dlm_header *) rc; + int type = rc->rc_type; + + header_out(hd); + + rc->rc_type = cpu_to_le32(rc->rc_type); + rc->rc_result = cpu_to_le32(rc->rc_result); + rc->rc_id = cpu_to_le64(rc->rc_id); + + if (type == DLM_RCOM_LOCK) + rcom_lock_out((struct rcom_lock *) rc->rc_buf); + + else if (type == DLM_RCOM_STATUS_REPLY) + rcom_config_out((struct rcom_config *) rc->rc_buf); +} + +void dlm_rcom_in(struct dlm_rcom *rc) +{ + struct dlm_header *hd = (struct dlm_header *) rc; + + header_in(hd); + + rc->rc_type = le32_to_cpu(rc->rc_type); + rc->rc_result = le32_to_cpu(rc->rc_result); + rc->rc_id = le64_to_cpu(rc->rc_id); + + if (rc->rc_type == DLM_RCOM_LOCK) + rcom_lock_in((struct rcom_lock *) rc->rc_buf); + + else if (rc->rc_type == DLM_RCOM_STATUS_REPLY) + rcom_config_in((struct rcom_config *) rc->rc_buf); +} + diff --git a/fs/dlm/util.h b/fs/dlm/util.h new file mode 100644 index 000000000000..2b25915161c0 --- /dev/null +++ b/fs/dlm/util.h @@ -0,0 +1,22 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __UTIL_DOT_H__ +#define __UTIL_DOT_H__ + +void dlm_message_out(struct dlm_message *ms); +void dlm_message_in(struct dlm_message *ms); +void dlm_rcom_out(struct dlm_rcom *rc); +void dlm_rcom_in(struct dlm_rcom *rc); + +#endif + diff --git a/include/linux/dlm.h b/include/linux/dlm.h new file mode 100644 index 000000000000..dd324ba44d80 --- /dev/null +++ b/include/linux/dlm.h @@ -0,0 +1,312 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +#ifndef __DLM_DOT_H__ +#define __DLM_DOT_H__ + +/* + * Interface to Distributed Lock Manager (DLM) + * routines and structures to use DLM lockspaces + */ + +/* + * Lock Modes + */ + +#define DLM_LOCK_IV -1 /* invalid */ +#define DLM_LOCK_NL 0 /* null */ +#define DLM_LOCK_CR 1 /* concurrent read */ +#define DLM_LOCK_CW 2 /* concurrent write */ +#define DLM_LOCK_PR 3 /* protected read */ +#define DLM_LOCK_PW 4 /* protected write */ +#define DLM_LOCK_EX 5 /* exclusive */ + +/* + * Maximum size in bytes of a dlm_lock name + */ + +#define DLM_RESNAME_MAXLEN 64 + +/* + * Flags to dlm_lock + * + * DLM_LKF_NOQUEUE + * + * Do not queue the lock request on the wait queue if it cannot be granted + * immediately. If the lock cannot be granted because of this flag, DLM will + * either return -EAGAIN from the dlm_lock call or will return 0 from + * dlm_lock and -EAGAIN in the lock status block when the AST is executed. + * + * DLM_LKF_CANCEL + * + * Used to cancel a pending lock request or conversion. A converting lock is + * returned to its previously granted mode. + * + * DLM_LKF_CONVERT + * + * Indicates a lock conversion request. For conversions the name and namelen + * are ignored and the lock ID in the LKSB is used to identify the lock. + * + * DLM_LKF_VALBLK + * + * Requests DLM to return the current contents of the lock value block in the + * lock status block. When this flag is set in a lock conversion from PW or EX + * modes, DLM assigns the value specified in the lock status block to the lock + * value block of the lock resource. The LVB is a DLM_LVB_LEN size array + * containing application-specific information. + * + * DLM_LKF_QUECVT + * + * Force a conversion request to be queued, even if it is compatible with + * the granted modes of other locks on the same resource. + * + * DLM_LKF_IVVALBLK + * + * Invalidate the lock value block. + * + * DLM_LKF_CONVDEADLK + * + * Allows the dlm to resolve conversion deadlocks internally by demoting the + * granted mode of a converting lock to NL. The DLM_SBF_DEMOTED flag is + * returned for a conversion that's been effected by this. + * + * DLM_LKF_PERSISTENT + * + * Only relevant to locks originating in userspace. A persistent lock will not + * be removed if the process holding the lock exits. + * + * DLM_LKF_NODLKWT + * DLM_LKF_NODLCKBLK + * + * net yet implemented + * + * DLM_LKF_EXPEDITE + * + * Used only with new requests for NL mode locks. Tells the lock manager + * to grant the lock, ignoring other locks in convert and wait queues. + * + * DLM_LKF_NOQUEUEBAST + * + * Send blocking AST's before returning -EAGAIN to the caller. It is only + * used along with the NOQUEUE flag. Blocking AST's are not sent for failed + * NOQUEUE requests otherwise. + * + * DLM_LKF_HEADQUE + * + * Add a lock to the head of the convert or wait queue rather than the tail. + * + * DLM_LKF_NOORDER + * + * Disregard the standard grant order rules and grant a lock as soon as it + * is compatible with other granted locks. + * + * DLM_LKF_ORPHAN + * + * not yet implemented + * + * DLM_LKF_ALTPR + * + * If the requested mode cannot be granted immediately, try to grant the lock + * in PR mode instead. If this alternate mode is granted instead of the + * requested mode, DLM_SBF_ALTMODE is returned in the lksb. + * + * DLM_LKF_ALTCW + * + * The same as ALTPR, but the alternate mode is CW. + * + * DLM_LKF_FORCEUNLOCK + * + * Unlock the lock even if it is converting or waiting or has sublocks. + * Only really for use by the userland device.c code. + * + */ + +#define DLM_LKF_NOQUEUE 0x00000001 +#define DLM_LKF_CANCEL 0x00000002 +#define DLM_LKF_CONVERT 0x00000004 +#define DLM_LKF_VALBLK 0x00000008 +#define DLM_LKF_QUECVT 0x00000010 +#define DLM_LKF_IVVALBLK 0x00000020 +#define DLM_LKF_CONVDEADLK 0x00000040 +#define DLM_LKF_PERSISTENT 0x00000080 +#define DLM_LKF_NODLCKWT 0x00000100 +#define DLM_LKF_NODLCKBLK 0x00000200 +#define DLM_LKF_EXPEDITE 0x00000400 +#define DLM_LKF_NOQUEUEBAST 0x00000800 +#define DLM_LKF_HEADQUE 0x00001000 +#define DLM_LKF_NOORDER 0x00002000 +#define DLM_LKF_ORPHAN 0x00004000 +#define DLM_LKF_ALTPR 0x00008000 +#define DLM_LKF_ALTCW 0x00010000 +#define DLM_LKF_FORCEUNLOCK 0x00020000 + +/* + * Some return codes that are not in errno.h + */ + +#define DLM_ECANCEL 0x10001 +#define DLM_EUNLOCK 0x10002 + +typedef void dlm_lockspace_t; + +/* + * Lock range structure + */ + +struct dlm_range { + uint64_t ra_start; + uint64_t ra_end; +}; + +/* + * Lock status block + * + * Use this structure to specify the contents of the lock value block. For a + * conversion request, this structure is used to specify the lock ID of the + * lock. DLM writes the status of the lock request and the lock ID assigned + * to the request in the lock status block. + * + * sb_lkid: the returned lock ID. It is set on new (non-conversion) requests. + * It is available when dlm_lock returns. + * + * sb_lvbptr: saves or returns the contents of the lock's LVB according to rules + * shown for the DLM_LKF_VALBLK flag. + * + * sb_flags: DLM_SBF_DEMOTED is returned if in the process of promoting a lock, + * it was first demoted to NL to avoid conversion deadlock. + * DLM_SBF_VALNOTVALID is returned if the resource's LVB is marked invalid. + * + * sb_status: the returned status of the lock request set prior to AST + * execution. Possible return values: + * + * 0 if lock request was successful + * -EAGAIN if request would block and is flagged DLM_LKF_NOQUEUE + * -ENOMEM if there is no memory to process request + * -EINVAL if there are invalid parameters + * -DLM_EUNLOCK if unlock request was successful + * -DLM_ECANCEL if a cancel completed successfully + */ + +#define DLM_SBF_DEMOTED 0x01 +#define DLM_SBF_VALNOTVALID 0x02 +#define DLM_SBF_ALTMODE 0x04 + +struct dlm_lksb { + int sb_status; + uint32_t sb_lkid; + char sb_flags; + char * sb_lvbptr; +}; + + +#ifdef __KERNEL__ + +#define DLM_LSFL_NODIR 0x00000001 + +/* + * dlm_new_lockspace + * + * Starts a lockspace with the given name. If the named lockspace exists in + * the cluster, the calling node joins it. + */ + +int dlm_new_lockspace(char *name, int namelen, dlm_lockspace_t **lockspace, + uint32_t flags, int lvblen); + +/* + * dlm_release_lockspace + * + * Stop a lockspace. + */ + +int dlm_release_lockspace(dlm_lockspace_t *lockspace, int force); + +/* + * dlm_lock + * + * Make an asyncronous request to acquire or convert a lock on a named + * resource. + * + * lockspace: context for the request + * mode: the requested mode of the lock (DLM_LOCK_) + * lksb: lock status block for input and async return values + * flags: input flags (DLM_LKF_) + * name: name of the resource to lock, can be binary + * namelen: the length in bytes of the resource name (MAX_RESNAME_LEN) + * parent: the lock ID of a parent lock or 0 if none + * lockast: function DLM executes when it completes processing the request + * astarg: argument passed to lockast and bast functions + * bast: function DLM executes when this lock later blocks another request + * + * Returns: + * 0 if request is successfully queued for processing + * -EINVAL if any input parameters are invalid + * -EAGAIN if request would block and is flagged DLM_LKF_NOQUEUE + * -ENOMEM if there is no memory to process request + * -ENOTCONN if there is a communication error + * + * If the call to dlm_lock returns an error then the operation has failed and + * the AST routine will not be called. If dlm_lock returns 0 it is still + * possible that the lock operation will fail. The AST routine will be called + * when the locking is complete and the status is returned in the lksb. + * + * If the AST routines or parameter are passed to a conversion operation then + * they will overwrite those values that were passed to a previous dlm_lock + * call. + * + * AST routines should not block (at least not for long), but may make + * any locking calls they please. + */ + +int dlm_lock(dlm_lockspace_t *lockspace, + int mode, + struct dlm_lksb *lksb, + uint32_t flags, + void *name, + unsigned int namelen, + uint32_t parent_lkid, + void (*lockast) (void *astarg), + void *astarg, + void (*bast) (void *astarg, int mode), + struct dlm_range *range); + +/* + * dlm_unlock + * + * Asynchronously release a lock on a resource. The AST routine is called + * when the resource is successfully unlocked. + * + * lockspace: context for the request + * lkid: the lock ID as returned in the lksb + * flags: input flags (DLM_LKF_) + * lksb: if NULL the lksb parameter passed to last lock request is used + * astarg: the arg used with the completion ast for the unlock + * + * Returns: + * 0 if request is successfully queued for processing + * -EINVAL if any input parameters are invalid + * -ENOTEMPTY if the lock still has sublocks + * -EBUSY if the lock is waiting for a remote lock operation + * -ENOTCONN if there is a communication error + */ + +int dlm_unlock(dlm_lockspace_t *lockspace, + uint32_t lkid, + uint32_t flags, + struct dlm_lksb *lksb, + void *astarg); + +#endif /* __KERNEL__ */ + +#endif /* __DLM_DOT_H__ */ + diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h new file mode 100644 index 000000000000..5e17d295544b --- /dev/null +++ b/include/linux/dlm_device.h @@ -0,0 +1,84 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +/* This is the device interface for dlm, most users will use a library + * interface. + */ + +#define DLM_USER_LVB_LEN 32 + +/* Version of the device interface */ +#define DLM_DEVICE_VERSION_MAJOR 3 +#define DLM_DEVICE_VERSION_MINOR 0 +#define DLM_DEVICE_VERSION_PATCH 0 + +/* struct passed to the lock write */ +struct dlm_lock_params { + __u8 mode; + __u16 flags; + __u32 lkid; + __u32 parent; + struct dlm_range range; + __u8 namelen; + void __user *castparam; + void __user *castaddr; + void __user *bastparam; + void __user *bastaddr; + struct dlm_lksb __user *lksb; + char lvb[DLM_USER_LVB_LEN]; + char name[1]; +}; + +struct dlm_lspace_params { + __u32 flags; + __u32 minor; + char name[1]; +}; + +struct dlm_write_request { + __u32 version[3]; + __u8 cmd; + + union { + struct dlm_lock_params lock; + struct dlm_lspace_params lspace; + } i; +}; + +/* struct read from the "device" fd, + consists mainly of userspace pointers for the library to use */ +struct dlm_lock_result { + __u32 length; + void __user * user_astaddr; + void __user * user_astparam; + struct dlm_lksb __user * user_lksb; + struct dlm_lksb lksb; + __u8 bast_mode; + /* Offsets may be zero if no data is present */ + __u32 lvb_offset; +}; + +/* Commands passed to the device */ +#define DLM_USER_LOCK 1 +#define DLM_USER_UNLOCK 2 +#define DLM_USER_QUERY 3 +#define DLM_USER_CREATE_LOCKSPACE 4 +#define DLM_USER_REMOVE_LOCKSPACE 5 + +/* Arbitrary length restriction */ +#define MAX_LS_NAME_LEN 64 + +/* Lockspace flags */ +#define DLM_USER_LSFLG_AUTOFREE 1 +#define DLM_USER_LSFLG_FORCEFREE 2 + -- cgit v1.2.3 From 3bd7662c4de28522d4709ab5a56033e3c33e1d4a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Jan 2006 10:40:17 +0000 Subject: [GFS2] Remove unused code from ondisk.c/gfs2_ondisk.h Removal of unused conversion functions from ondisk.c and gfs2_ondisk.h Signed-off-by: Steven Whitehouse --- fs/gfs2/ondisk.c | 63 --------------------------------------------- include/linux/gfs2_ondisk.h | 5 ---- 2 files changed, 68 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 2a1ef5aa7f0c..0d54e082e62b 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -120,24 +120,6 @@ void gfs2_sb_in(struct gfs2_sb *sb, char *buf) memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN); } -void gfs2_sb_out(struct gfs2_sb *sb, char *buf) -{ - struct gfs2_sb *str = (struct gfs2_sb *)buf; - - gfs2_meta_header_out(&sb->sb_header, buf); - - str->sb_fs_format = cpu_to_be32(sb->sb_fs_format); - str->sb_multihost_format = cpu_to_be32(sb->sb_multihost_format); - str->sb_bsize = cpu_to_be32(sb->sb_bsize); - str->sb_bsize_shift = cpu_to_be32(sb->sb_bsize_shift); - - gfs2_inum_out(&sb->sb_master_dir, (char *)&str->sb_master_dir); - gfs2_inum_out(&sb->sb_root_dir, (char *)&str->sb_root_dir); - - memcpy(str->sb_lockproto, sb->sb_lockproto, GFS2_LOCKNAME_LEN); - memcpy(str->sb_locktable, sb->sb_locktable, GFS2_LOCKNAME_LEN); -} - void gfs2_sb_print(struct gfs2_sb *sb) { gfs2_meta_header_print(&sb->sb_header); @@ -344,30 +326,6 @@ void gfs2_dinode_print(struct gfs2_dinode *di) pv(di, di_eattr, "%llu"); } -void gfs2_dirent_in(struct gfs2_dirent *de, char *buf) -{ - struct gfs2_dirent *str = (struct gfs2_dirent *)buf; - - gfs2_inum_in(&de->de_inum, buf); - de->de_hash = be32_to_cpu(str->de_hash); - de->de_rec_len = be32_to_cpu(str->de_rec_len); - de->de_name_len = str->de_name_len; - de->de_type = str->de_type; -} - -void gfs2_dirent_out(struct gfs2_dirent *de, char *buf) -{ - struct gfs2_dirent *str = (struct gfs2_dirent *)buf; - - gfs2_inum_out(&de->de_inum, buf); - str->de_hash = cpu_to_be32(de->de_hash); - str->de_rec_len = cpu_to_be32(de->de_rec_len); - str->de_name_len = de->de_name_len; - str->de_type = de->de_type; - str->__pad1 = 0; - str->__pad2 = 0; -} - void gfs2_dirent_print(struct gfs2_dirent *de, char *name) { char buf[GFS2_FNAMESIZE + 1]; @@ -394,18 +352,6 @@ void gfs2_leaf_in(struct gfs2_leaf *lf, char *buf) lf->lf_next = be64_to_cpu(str->lf_next); } -void gfs2_leaf_out(struct gfs2_leaf *lf, char *buf) -{ - struct gfs2_leaf *str = (struct gfs2_leaf *)buf; - - gfs2_meta_header_out(&lf->lf_header, buf); - str->lf_depth = cpu_to_be16(lf->lf_depth); - str->lf_entries = cpu_to_be16(lf->lf_entries); - str->lf_dirent_format = cpu_to_be32(lf->lf_dirent_format); - str->lf_next = cpu_to_be64(lf->lf_next); - memset(&str->lf_reserved, 0, sizeof(str->lf_reserved)); -} - void gfs2_leaf_print(struct gfs2_leaf *lf) { gfs2_meta_header_print(&lf->lf_header); @@ -570,15 +516,6 @@ void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf) qc->qc_id = be32_to_cpu(str->qc_id); } -void gfs2_quota_change_out(struct gfs2_quota_change *qc, char *buf) -{ - struct gfs2_quota_change *str = (struct gfs2_quota_change *)buf; - - str->qc_change = cpu_to_be64(qc->qc_change); - str->qc_flags = cpu_to_be32(qc->qc_flags); - str->qc_id = cpu_to_be32(qc->qc_id); -} - void gfs2_quota_change_print(struct gfs2_quota_change *qc) { pv(qc, qc_change, "%lld"); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 213d664d495d..8354b9c4f408 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -407,7 +407,6 @@ extern void gfs2_inum_out(struct gfs2_inum *no, char *buf); extern void gfs2_meta_header_in(struct gfs2_meta_header *mh, char *buf); extern void gfs2_meta_header_out(struct gfs2_meta_header *mh, char *buf); extern void gfs2_sb_in(struct gfs2_sb *sb, char *buf); -extern void gfs2_sb_out(struct gfs2_sb *sb, char *buf); extern void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf); extern void gfs2_rindex_out(struct gfs2_rindex *ri, char *buf); extern void gfs2_rgrp_in(struct gfs2_rgrp *rg, char *buf); @@ -416,10 +415,7 @@ extern void gfs2_quota_in(struct gfs2_quota *qu, char *buf); extern void gfs2_quota_out(struct gfs2_quota *qu, char *buf); extern void gfs2_dinode_in(struct gfs2_dinode *di, char *buf); extern void gfs2_dinode_out(struct gfs2_dinode *di, char *buf); -extern void gfs2_dirent_in(struct gfs2_dirent *de, char *buf); -extern void gfs2_dirent_out(struct gfs2_dirent *de, char *buf); extern void gfs2_leaf_in(struct gfs2_leaf *lf, char *buf); -extern void gfs2_leaf_out(struct gfs2_leaf *lf, char *buf); extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, char *buf); extern void gfs2_ea_header_out(struct gfs2_ea_header *ea, char *buf); extern void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf); @@ -430,7 +426,6 @@ extern void gfs2_statfs_change_out(struct gfs2_statfs_change *sc, char *buf); extern void gfs2_unlinked_tag_in(struct gfs2_unlinked_tag *ut, char *buf); extern void gfs2_unlinked_tag_out(struct gfs2_unlinked_tag *ut, char *buf); extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf); -extern void gfs2_quota_change_out(struct gfs2_quota_change *qc, char *buf); /* Printing functions */ -- cgit v1.2.3 From b96ca4fa4e3b510d528a093a5bac0befbc2ba46d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 18 Jan 2006 10:57:10 +0000 Subject: [GFS2] Update init_dinode() to reduce stack usage We no longer allocate a dinode on the stack in init_dinode() and we no longer use gfs2_dinode_out (eliminating one copy) and gfs2_meta_header_in (eliminating another copy). The meta_header_in fucntion is now no longer referenced from outside gfs2_ondisk.c, so make it static. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 45 +++++++++++++++++++++++++++++---------------- fs/gfs2/ondisk.c | 4 ++-- include/linux/gfs2_ondisk.h | 2 -- 3 files changed, 31 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 73922dba5398..aa5311ef7ba7 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -993,37 +993,50 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, unsigned int uid, unsigned int gid) { struct gfs2_sbd *sdp = dip->i_sbd; - struct gfs2_dinode di; + struct gfs2_dinode *di; struct buffer_head *dibh; dibh = gfs2_meta_new(gl, inum->no_addr); gfs2_trans_add_bh(gl, dibh); gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); - - memset(&di, 0, sizeof(struct gfs2_dinode)); - gfs2_meta_header_in(&di.di_header, dibh->b_data); - di.di_num = *inum; - di.di_mode = mode; - di.di_uid = uid; - di.di_gid = gid; - di.di_blocks = 1; - di.di_atime = di.di_mtime = di.di_ctime = get_seconds(); - di.di_goal_meta = di.di_goal_data = inum->no_addr; + di = (struct gfs2_dinode *)dibh->b_data; + + di->di_num = *inum; + di->di_mode = cpu_to_be32(mode); + di->di_uid = cpu_to_be32(uid); + di->di_gid = cpu_to_be32(gid); + di->di_nlink = cpu_to_be32(0); + di->di_size = cpu_to_be64(0); + di->di_blocks = cpu_to_be64(1); + di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds()); + di->di_major = di->di_minor = cpu_to_be32(0); + di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); + di->__pad[0] = di->__pad[1] = 0; + di->di_flags = cpu_to_be32(0); if (S_ISREG(mode)) { if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA) || gfs2_tune_get(sdp, gt_new_files_jdata)) - di.di_flags |= GFS2_DIF_JDATA; + di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_DIRECTIO) || gfs2_tune_get(sdp, gt_new_files_directio)) - di.di_flags |= GFS2_DIF_DIRECTIO; + di->di_flags |= cpu_to_be32(GFS2_DIF_DIRECTIO); } else if (S_ISDIR(mode)) { - di.di_flags |= (dip->i_di.di_flags & GFS2_DIF_INHERIT_DIRECTIO); - di.di_flags |= (dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA); + di->di_flags |= cpu_to_be32(dip->i_di.di_flags & GFS2_DIF_INHERIT_DIRECTIO); + di->di_flags |= cpu_to_be32(dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA); } - gfs2_dinode_out(&di, dibh->b_data); + di->__pad1 = 0; + di->di_height = cpu_to_be32(0); + di->__pad2 = 0; + di->__pad3 = 0; + di->di_depth = cpu_to_be16(0); + di->di_entries = cpu_to_be32(0); + memset(&di->__pad4, 0, sizeof(di->__pad4)); + di->di_eattr = cpu_to_be64(0); + memset(&di->di_reserved, 0, sizeof(di->di_reserved)); + brelse(dibh); } diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 0d54e082e62b..854b5049b8d5 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -77,7 +77,7 @@ void gfs2_inum_print(struct gfs2_inum *no) pv(no, no_addr, "%llu"); } -void gfs2_meta_header_in(struct gfs2_meta_header *mh, char *buf) +static void gfs2_meta_header_in(struct gfs2_meta_header *mh, char *buf) { struct gfs2_meta_header *str = (struct gfs2_meta_header *)buf; @@ -86,7 +86,7 @@ void gfs2_meta_header_in(struct gfs2_meta_header *mh, char *buf) mh->mh_format = be16_to_cpu(str->mh_format); } -void gfs2_meta_header_out(struct gfs2_meta_header *mh, char *buf) +static void gfs2_meta_header_out(struct gfs2_meta_header *mh, char *buf) { struct gfs2_meta_header *str = (struct gfs2_meta_header *)buf; diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 8354b9c4f408..f1302e2616da 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -404,8 +404,6 @@ struct gfs2_quota_change { extern void gfs2_inum_in(struct gfs2_inum *no, char *buf); extern void gfs2_inum_out(struct gfs2_inum *no, char *buf); -extern void gfs2_meta_header_in(struct gfs2_meta_header *mh, char *buf); -extern void gfs2_meta_header_out(struct gfs2_meta_header *mh, char *buf); extern void gfs2_sb_in(struct gfs2_sb *sb, char *buf); extern void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf); extern void gfs2_rindex_out(struct gfs2_rindex *ri, char *buf); -- cgit v1.2.3 From 8ca05c60de49c3bb523a435abc216b6b6eeb1067 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 24 Jan 2006 10:03:04 +0000 Subject: [GFS2] Update ioctl() numbering to use official numbers. This patch adds us into the official ioctl-number.txt registry and updates GFS2 accordingly. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- Documentation/ioctl-number.txt | 1 + include/linux/gfs2_ioctl.h | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt index aa7ba00ec082..7d5ce496f39f 100644 --- a/Documentation/ioctl-number.txt +++ b/Documentation/ioctl-number.txt @@ -126,6 +126,7 @@ Code Seq# Include File Comments 'e' 00-1F linux/video_encoder.h conflict! 'e' 00-1F net/irda/irtty.h conflict! 'f' 00-1F linux/ext2_fs.h +'g' 00-1F linux/gfs2_ioctl.h 'h' 00-7F Charon filesystem 'i' 00-3F linux/i2o.h diff --git a/include/linux/gfs2_ioctl.h b/include/linux/gfs2_ioctl.h index ca9632862833..fb7c0cf72c56 100644 --- a/include/linux/gfs2_ioctl.h +++ b/include/linux/gfs2_ioctl.h @@ -10,12 +10,8 @@ #ifndef __GFS2_IOCTL_DOT_H__ #define __GFS2_IOCTL_DOT_H__ -#define _GFS2C_(x) (('G' << 16) | ('2' << 8) | (x)) - -/* Ioctls implemented */ - -#define GFS2_IOCTL_SETFLAGS _GFS2C_(3) -#define GFS2_IOCTL_GETFLAGS _GFS2C_(4) +#define GFS2_IOCTL_SETFLAGS _IOW('g', 3, long) +#define GFS2_IOCTL_GETFLAGS _IOR('g', 4, long) #endif /* ___GFS2_IOCTL_DOT_H__ */ -- cgit v1.2.3 From 18ec7d5c3f434aed9661ed10a9e1f48cdeb4981d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 8 Feb 2006 11:50:51 +0000 Subject: [GFS2] Make journaled data files identical to normal files on disk This is a very large patch, with a few still to be resolved issues so you might want to check out the previous head of the tree since this is known to be unstable. Fixes for the various bugs will be forthcoming shortly. This patch removes the special data format which has been used up till now for journaled data files. Directories still retain the old format so that they will remain on disk compatible with earlier releases. As a result you can now do the following with journaled data files: 1) mmap them 2) export them over NFS 3) convert to/from normal files whenever you want to (the zero length restriction is gone) In addition the level at which GFS' locking is done has changed for all files (since they all now use the page cache) such that the locking is done at the page cache level rather than the level of the fs operations. This should mean that things like loopback mounts and other things which touch the page cache directly should now work. Current known issues: 1. There is a lock mode inversion problem related to the resource group hold function which needs to be resolved. 2. Any significant amount of I/O causes an oops with an offset of hex 320 (NULL pointer dereference) which appears to be related to a journaled data buffer appearing on a list where it shouldn't be. 3. Direct I/O writes are disabled for the time being (will reappear later) 4. There is probably a deadlock between the page lock and GFS' locks under certain combinations of mmap and fs operation I/O. 5. Issue relating to ref counting on internally used inodes causes a hang on umount (discovered before this patch, and not fixed by it) 6. One part of the directory metadata is different from GFS1 and will need to be resolved before next release. Signed-off-by: Steven Whitehouse --- fs/gfs2/Makefile | 1 - fs/gfs2/bmap.c | 59 +-- fs/gfs2/dir.c | 4 +- fs/gfs2/dir.h | 2 + fs/gfs2/inode.h | 7 +- fs/gfs2/jdata.c | 389 ------------------ fs/gfs2/jdata.h | 52 --- fs/gfs2/log.c | 4 +- fs/gfs2/lops.c | 280 +++++++++++-- fs/gfs2/meta_io.c | 16 +- fs/gfs2/ops_address.c | 260 +++++++----- fs/gfs2/ops_file.c | 967 ++++++++------------------------------------ fs/gfs2/ops_vm.c | 3 - fs/gfs2/page.c | 10 +- fs/gfs2/quota.c | 114 ++++-- fs/gfs2/trans.c | 19 +- fs/gfs2/trans.h | 1 - fs/gfs2/util.c | 3 + include/linux/gfs2_ondisk.h | 7 + 19 files changed, 721 insertions(+), 1477 deletions(-) delete mode 100644 fs/gfs2/jdata.c delete mode 100644 fs/gfs2/jdata.h (limited to 'include/linux') diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 4e87b8661af0..88f927948113 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -10,7 +10,6 @@ gfs2-y := \ glock.o \ glops.o \ inode.o \ - jdata.o \ lm.o \ log.o \ lops.o \ diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index bd194f645c52..4efcd8a39e98 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -18,12 +18,12 @@ #include "bmap.h" #include "glock.h" #include "inode.h" -#include "jdata.h" #include "meta_io.h" #include "page.h" #include "quota.h" #include "rgrp.h" #include "trans.h" +#include "dir.h" /* This doesn't need to be that large as max 64 bit pointers in a 4k * block is 512, so __u16 is fine for that. It saves stack space to @@ -90,7 +90,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, { struct buffer_head *bh, *dibh; uint64_t block = 0; - int journaled = gfs2_is_jdata(ip); + int isdir = gfs2_is_dir(ip); int error; down_write(&ip->i_rw_mutex); @@ -103,10 +103,10 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, /* Get a free block, fill it with the stuffed data, and write it out to disk */ - if (journaled) { + if (isdir) { block = gfs2_alloc_meta(ip); - error = gfs2_jdata_get_buffer(ip, block, 1, &bh); + error = gfs2_dir_get_buffer(ip, block, 1, &bh); if (error) goto out_brelse; gfs2_buffer_copy_tail(bh, @@ -168,7 +168,7 @@ static unsigned int calc_tree_height(struct gfs2_inode *ip, uint64_t size) if (ip->i_di.di_size > size) size = ip->i_di.di_size; - if (gfs2_is_jdata(ip)) { + if (gfs2_is_dir(ip)) { arr = sdp->sd_jheightsize; max = sdp->sd_max_jheight; } else { @@ -377,7 +377,7 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, return; if (height == ip->i_di.di_height - 1 && - !gfs2_is_jdata(ip)) + !gfs2_is_dir(ip)) *block = gfs2_alloc_data(ip); else *block = gfs2_alloc_meta(ip); @@ -430,7 +430,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) goto out; - bsize = (gfs2_is_jdata(ip)) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; + bsize = (gfs2_is_dir(ip)) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; height = calc_tree_height(ip, (lblock + 1) * bsize); if (ip->i_di.di_height < height) { @@ -618,7 +618,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, sm->sm_first = 0; } - metadata = (height != ip->i_di.di_height - 1) || gfs2_is_jdata(ip); + metadata = (height != ip->i_di.di_height - 1); if (metadata) revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; @@ -814,33 +814,6 @@ static int do_grow(struct gfs2_inode *ip, uint64_t size) return error; } -static int truncator_journaled(struct gfs2_inode *ip, uint64_t size) -{ - uint64_t lbn, dbn; - uint32_t off; - struct buffer_head *bh; - int new = 0; - int error; - - lbn = size; - off = do_div(lbn, ip->i_sbd->sd_jbsize); - - error = gfs2_block_map(ip, lbn, &new, &dbn, NULL); - if (error || !dbn) - return error; - - error = gfs2_jdata_get_buffer(ip, dbn, 0, &bh); - if (error) - return error; - - gfs2_trans_add_bh(ip->i_gl, bh, 1); - gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header) + off); - - brelse(bh); - - return 0; -} - static int trunc_start(struct gfs2_inode *ip, uint64_t size) { struct gfs2_sbd *sdp = ip->i_sbd; @@ -866,12 +839,7 @@ static int trunc_start(struct gfs2_inode *ip, uint64_t size) error = 1; } else { - if (journaled) { - uint64_t junk = size; - /* we're just interested in the modulus */ - if (do_div(junk, sdp->sd_jbsize)) - error = truncator_journaled(ip, size); - } else if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1)) + if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1)) error = gfs2_block_truncate_page(ip->i_vnode->i_mapping); if (!error) { @@ -900,10 +868,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, uint64_t size) if (!size) lblock = 0; - else if (gfs2_is_jdata(ip)) { - lblock = size - 1; - do_div(lblock, ip->i_sbd->sd_jbsize); - } else + else lblock = (size - 1) >> ip->i_sbd->sd_sb.sb_bsize_shift; find_metapath(ip, lblock, &mp); @@ -1051,7 +1016,7 @@ void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len, struct gfs2_sbd *sdp = ip->i_sbd; unsigned int tmp; - if (gfs2_is_jdata(ip)) { + if (gfs2_is_dir(ip)) { *data_blocks = DIV_RU(len, sdp->sd_jbsize) + 2; *ind_blocks = 3 * (sdp->sd_max_jheight - 1); } else { @@ -1096,7 +1061,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset, return 0; } - if (gfs2_is_jdata(ip)) { + if (gfs2_is_dir(ip)) { unsigned int bsize = sdp->sd_jbsize; lblock = offset; do_div(lblock, bsize); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index ada283a0f5f3..c77e18048d98 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -86,8 +86,8 @@ typedef int (*leaf_call_t) (struct gfs2_inode *dip, uint32_t index, uint32_t len, uint64_t leaf_no, void *data); -static int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, - struct buffer_head **bhp) +int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, + struct buffer_head **bhp) { struct buffer_head *bh; int error = 0; diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index ff6d1c597ee9..5b01497b3ab3 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -45,5 +45,7 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip); int gfs2_diradd_alloc_required(struct gfs2_inode *dip, struct qstr *filename, int *alloc_required); +int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, + struct buffer_head **bhp); #endif /* __DIR_DOT_H__ */ diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index e42ae38d6778..214975c6bb22 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -20,6 +20,11 @@ static inline int gfs2_is_jdata(struct gfs2_inode *ip) return ip->i_di.di_flags & GFS2_DIF_JDATA; } +static inline int gfs2_is_dir(struct gfs2_inode *ip) +{ + return S_ISDIR(ip->i_di.di_mode); +} + void gfs2_inode_attr_in(struct gfs2_inode *ip); void gfs2_inode_attr_out(struct gfs2_inode *ip); struct inode *gfs2_ip2v_lookup(struct gfs2_inode *ip); @@ -72,9 +77,9 @@ static inline int gfs2_lookup_simple(struct inode *dip, char *name, err = gfs2_lookupi(get_v2ip(dip), &qstr, 1, &ip); if (err == 0) { *ipp = gfs2_ip2v(ip); + gfs2_inode_put(ip); if (*ipp == NULL) err = -ENOMEM; - gfs2_inode_put(ip); } return err; } diff --git a/fs/gfs2/jdata.c b/fs/gfs2/jdata.c deleted file mode 100644 index e43eaf133f10..000000000000 --- a/fs/gfs2/jdata.c +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License v.2. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "gfs2.h" -#include "bmap.h" -#include "inode.h" -#include "jdata.h" -#include "meta_io.h" -#include "trans.h" - -int gfs2_internal_read(struct gfs2_inode *ip, - struct file_ra_state *ra_state, - char *buf, loff_t *pos, unsigned size) -{ - return gfs2_jdata_read_mem(ip, buf, *pos, size); -} - -int gfs2_jdata_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, - struct buffer_head **bhp) -{ - struct buffer_head *bh; - int error = 0; - - if (new) { - bh = gfs2_meta_new(ip->i_gl, block); - gfs2_trans_add_bh(ip->i_gl, bh, 1); - gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD); - gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); - } else { - error = gfs2_meta_read(ip->i_gl, block, - DIO_START | DIO_WAIT, &bh); - if (error) - return error; - if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_JD)) { - brelse(bh); - return -EIO; - } - } - - *bhp = bh; - - return 0; -} - -/** - * gfs2_copy2mem - Trivial copy function for gfs2_jdata_read() - * @bh: The buffer to copy from, or NULL meaning zero the buffer - * @buf: The buffer to copy/zero - * @offset: The offset in the buffer to copy from - * @size: The amount of data to copy/zero - * - * Returns: errno - */ - -int gfs2_copy2mem(struct buffer_head *bh, char **buf, unsigned int offset, - unsigned int size) -{ - if (bh) - memcpy(*buf, bh->b_data + offset, size); - else - memset(*buf, 0, size); - *buf += size; - return 0; -} - -/** - * gfs2_copy2user - Copy bytes to user space for gfs2_jdata_read() - * @bh: The buffer - * @buf: The destination of the data - * @offset: The offset into the buffer - * @size: The amount of data to copy - * - * Returns: errno - */ - -int gfs2_copy2user(struct buffer_head *bh, char **buf, unsigned int offset, - unsigned int size) -{ - int error; - - if (bh) - error = copy_to_user(*buf, bh->b_data + offset, size); - else - error = clear_user(*buf, size); - - if (error) - error = -EFAULT; - else - *buf += size; - - return error; -} - -static int jdata_read_stuffed(struct gfs2_inode *ip, char *buf, - unsigned int offset, unsigned int size, - read_copy_fn_t copy_fn) -{ - struct buffer_head *dibh; - int error; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (!error) { - error = copy_fn(dibh, &buf, - offset + sizeof(struct gfs2_dinode), size); - brelse(dibh); - } - - return (error) ? error : size; -} - -/** - * gfs2_jdata_read - Read a jdata file - * @ip: The GFS2 Inode - * @buf: The buffer to place result into - * @offset: File offset to begin jdata_readng from - * @size: Amount of data to transfer - * @copy_fn: Function to actually perform the copy - * - * The @copy_fn only copies a maximum of a single block at once so - * we are safe calling it with int arguments. It is done so that - * we don't needlessly put 64bit arguments on the stack and it - * also makes the code in the @copy_fn nicer too. - * - * Returns: The amount of data actually copied or the error - */ - -int gfs2_jdata_read(struct gfs2_inode *ip, char __user *buf, uint64_t offset, - unsigned int size, read_copy_fn_t copy_fn) -{ - struct gfs2_sbd *sdp = ip->i_sbd; - uint64_t lblock, dblock; - uint32_t extlen = 0; - unsigned int o; - int copied = 0; - int error = 0; - - if (offset >= ip->i_di.di_size) - return 0; - - if ((offset + size) > ip->i_di.di_size) - size = ip->i_di.di_size - offset; - - if (!size) - return 0; - - if (gfs2_is_stuffed(ip)) - return jdata_read_stuffed(ip, buf, (unsigned int)offset, size, - copy_fn); - - if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) - return -EINVAL; - - lblock = offset; - o = do_div(lblock, sdp->sd_jbsize) + - sizeof(struct gfs2_meta_header); - - while (copied < size) { - unsigned int amount; - struct buffer_head *bh; - int new; - - amount = size - copied; - if (amount > sdp->sd_sb.sb_bsize - o) - amount = sdp->sd_sb.sb_bsize - o; - - if (!extlen) { - new = 0; - error = gfs2_block_map(ip, lblock, &new, - &dblock, &extlen); - if (error) - goto fail; - } - - if (extlen > 1) - gfs2_meta_ra(ip->i_gl, dblock, extlen); - - if (dblock) { - error = gfs2_jdata_get_buffer(ip, dblock, new, &bh); - if (error) - goto fail; - dblock++; - extlen--; - } else - bh = NULL; - - error = copy_fn(bh, &buf, o, amount); - brelse(bh); - if (error) - goto fail; - - copied += amount; - lblock++; - - o = sizeof(struct gfs2_meta_header); - } - - return copied; - - fail: - return (copied) ? copied : error; -} - -/** - * gfs2_copy_from_mem - Trivial copy function for gfs2_jdata_write() - * @bh: The buffer to copy to or clear - * @buf: The buffer to copy from - * @offset: The offset in the buffer to write to - * @size: The amount of data to write - * - * Returns: errno - */ - -int gfs2_copy_from_mem(struct gfs2_inode *ip, struct buffer_head *bh, - const char **buf, unsigned int offset, unsigned int size) -{ - gfs2_trans_add_bh(ip->i_gl, bh, 1); - memcpy(bh->b_data + offset, *buf, size); - - *buf += size; - - return 0; -} - -/** - * gfs2_copy_from_user - Copy bytes from user space for gfs2_jdata_write() - * @bh: The buffer to copy to or clear - * @buf: The buffer to copy from - * @offset: The offset in the buffer to write to - * @size: The amount of data to write - * - * Returns: errno - */ - -int gfs2_copy_from_user(struct gfs2_inode *ip, struct buffer_head *bh, - const char __user **buf, unsigned int offset, unsigned int size) -{ - int error = 0; - - gfs2_trans_add_bh(ip->i_gl, bh, 1); - if (copy_from_user(bh->b_data + offset, *buf, size)) - error = -EFAULT; - else - *buf += size; - - return error; -} - -static int jdata_write_stuffed(struct gfs2_inode *ip, char *buf, - unsigned int offset, unsigned int size, - write_copy_fn_t copy_fn) -{ - struct buffer_head *dibh; - int error; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - return error; - - error = copy_fn(ip, - dibh, &buf, - offset + sizeof(struct gfs2_dinode), size); - if (!error) { - if (ip->i_di.di_size < offset + size) - ip->i_di.di_size = offset + size; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); - gfs2_dinode_out(&ip->i_di, dibh->b_data); - } - - brelse(dibh); - - return (error) ? error : size; -} - -/** - * gfs2_jdata_write - Write bytes to a file - * @ip: The GFS2 inode - * @buf: The buffer containing information to be written - * @offset: The file offset to start writing at - * @size: The amount of data to write - * @copy_fn: Function to do the actual copying - * - * Returns: The number of bytes correctly written or error code - */ - -int gfs2_jdata_write(struct gfs2_inode *ip, const char __user *buf, uint64_t offset, - unsigned int size, write_copy_fn_t copy_fn) -{ - struct gfs2_sbd *sdp = ip->i_sbd; - struct buffer_head *dibh; - uint64_t lblock, dblock; - uint32_t extlen = 0; - unsigned int o; - int copied = 0; - int error = 0; - - if (!size) - return 0; - - if (gfs2_is_stuffed(ip) && - offset + size <= sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) - return jdata_write_stuffed(ip, buf, (unsigned int)offset, size, - copy_fn); - - if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) - return -EINVAL; - - if (gfs2_is_stuffed(ip)) { - error = gfs2_unstuff_dinode(ip, NULL, NULL); - if (error) - return error; - } - - lblock = offset; - o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header); - - while (copied < size) { - unsigned int amount; - struct buffer_head *bh; - int new; - - amount = size - copied; - if (amount > sdp->sd_sb.sb_bsize - o) - amount = sdp->sd_sb.sb_bsize - o; - - if (!extlen) { - new = 1; - error = gfs2_block_map(ip, lblock, &new, - &dblock, &extlen); - if (error) - goto fail; - error = -EIO; - if (gfs2_assert_withdraw(sdp, dblock)) - goto fail; - } - - error = gfs2_jdata_get_buffer(ip, dblock, - (amount == sdp->sd_jbsize) ? 1 : new, - &bh); - if (error) - goto fail; - - error = copy_fn(ip, bh, &buf, o, amount); - brelse(bh); - if (error) - goto fail; - - copied += amount; - lblock++; - dblock++; - extlen--; - - o = sizeof(struct gfs2_meta_header); - } - - out: - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - return error; - - if (ip->i_di.di_size < offset + copied) - ip->i_di.di_size = offset + copied; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); - brelse(dibh); - - return copied; - - fail: - if (copied) - goto out; - return error; -} - diff --git a/fs/gfs2/jdata.h b/fs/gfs2/jdata.h deleted file mode 100644 index 95e18fcb8f82..000000000000 --- a/fs/gfs2/jdata.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License v.2. - */ - -#ifndef __FILE_DOT_H__ -#define __FILE_DOT_H__ - -int gfs2_jdata_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, - struct buffer_head **bhp); - -typedef int (*read_copy_fn_t) (struct buffer_head *bh, char **buf, - unsigned int offset, unsigned int size); -typedef int (*write_copy_fn_t) (struct gfs2_inode *ip, - struct buffer_head *bh, const char **buf, - unsigned int offset, unsigned int size); - -int gfs2_copy2mem(struct buffer_head *bh, char **buf, - unsigned int offset, unsigned int size); -int gfs2_copy2user(struct buffer_head *bh, char __user **buf, - unsigned int offset, unsigned int size); -int gfs2_jdata_read(struct gfs2_inode *ip, char __user *buf, - uint64_t offset, unsigned int size, - read_copy_fn_t copy_fn); - -int gfs2_copy_from_mem(struct gfs2_inode *ip, - struct buffer_head *bh, const char **buf, - unsigned int offset, unsigned int size); -int gfs2_copy_from_user(struct gfs2_inode *ip, - struct buffer_head *bh, const char __user **buf, - unsigned int offset, unsigned int size); -int gfs2_jdata_write(struct gfs2_inode *ip, const char __user *buf, - uint64_t offset, unsigned int size, - write_copy_fn_t copy_fn); - -static inline int gfs2_jdata_read_mem(struct gfs2_inode *ip, char *buf, - uint64_t offset, unsigned int size) -{ - return gfs2_jdata_read(ip, (__force char __user *)buf, offset, size, gfs2_copy2mem); -} - -static inline int gfs2_jdata_write_mem(struct gfs2_inode *ip, const char *buf, - uint64_t offset, unsigned int size) -{ - return gfs2_jdata_write(ip, (__force const char __user *)buf, offset, size, gfs2_copy_from_mem); -} - -#endif /* __FILE_DOT_H__ */ diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index f6d00130f96f..9b4484d366ca 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -387,8 +387,7 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); atomic_set(&bh->b_count, 1); bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate); - set_bh_page(bh, virt_to_page(real->b_data), - ((unsigned long)real->b_data) & (PAGE_SIZE - 1)); + set_bh_page(bh, real->b_page, bh_offset(real)); bh->b_blocknr = blkno; bh->b_size = sdp->sd_sb.sb_bsize; bh->b_bdev = sdp->sd_vfs->s_bdev; @@ -634,6 +633,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); + gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index a065f7667238..dd41863810d7 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -428,49 +428,188 @@ static void rg_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) gfs2_assert_warn(sdp, !sdp->sd_log_num_rg); } +/** + * databuf_lo_add - Add a databuf to the transaction. + * + * This is used in two distinct cases: + * i) In ordered write mode + * We put the data buffer on a list so that we can ensure that its + * synced to disk at the right time + * ii) In journaled data mode + * We need to journal the data block in the same way as metadata in + * the functions above. The difference is that here we have a tag + * which is two __be64's being the block number (as per meta data) + * and a flag which says whether the data block needs escaping or + * not. This means we need a new log entry for each 251 or so data + * blocks, which isn't an enormous overhead but twice as much as + * for normal metadata blocks. + */ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { - get_transaction->tr_touched = 1; + struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); + struct gfs2_trans *tr = get_transaction; + struct address_space *mapping = bd->bd_bh->b_page->mapping; + struct gfs2_inode *ip = get_v2ip(mapping->host); + tr->tr_touched = 1; + if (!list_empty(&bd->bd_list_tr) && + (ip->i_di.di_flags & GFS2_DIF_JDATA)) { + tr->tr_num_buf++; + gfs2_trans_add_gl(bd->bd_gl); + list_add(&bd->bd_list_tr, &tr->tr_list_buf); + gfs2_pin(sdp, bd->bd_bh); + } else { + clear_buffer_pinned(bd->bd_bh); + } gfs2_log_lock(sdp); + if (ip->i_di.di_flags & GFS2_DIF_JDATA) + sdp->sd_log_num_jdata++; sdp->sd_log_num_databuf++; list_add(&le->le_list, &sdp->sd_log_le_databuf); gfs2_log_unlock(sdp); } +static int gfs2_check_magic(struct buffer_head *bh) +{ + struct page *page = bh->b_page; + void *kaddr; + __be32 *ptr; + int rv = 0; + + kaddr = kmap_atomic(page, KM_USER0); + ptr = kaddr + bh_offset(bh); + if (*ptr == cpu_to_be32(GFS2_MAGIC)) + rv = 1; + kunmap_atomic(page, KM_USER0); + + return rv; +} + +/** + * databuf_lo_before_commit - Scan the data buffers, writing as we go + * + * Here we scan through the lists of buffers and make the assumption + * that any buffer thats been pinned is being journaled, and that + * any unpinned buffer is an ordered write data buffer and therefore + * will be written back rather than journaled. + */ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) { - struct list_head *head = &sdp->sd_log_le_databuf; LIST_HEAD(started); - struct gfs2_bufdata *bd; - struct buffer_head *bh; + struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt; + struct buffer_head *bh = NULL; + unsigned int offset = sizeof(struct gfs2_log_descriptor); + struct gfs2_log_descriptor *ld; + unsigned int limit; + unsigned int total_dbuf = sdp->sd_log_num_databuf; + unsigned int total_jdata = sdp->sd_log_num_jdata; + unsigned int num, n; + __be64 *ptr; - while (!list_empty(head)) { - bd = list_entry(head->prev, struct gfs2_bufdata, bd_le.le_list); - list_move(&bd->bd_le.le_list, &started); + offset += (2*sizeof(__be64) - 1); + offset &= ~(2*sizeof(__be64) - 1); + limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64); - gfs2_log_lock(sdp); - bh = bd->bd_bh; + /* printk(KERN_INFO "totals: jdata=%u dbuf=%u\n", total_jdata, total_dbuf); */ + /* + * Start writing ordered buffers, write journaled buffers + * into the log along with a header + */ + bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf, bd_le.le_list); + while(total_dbuf) { + num = total_jdata; + if (num > limit) + num = limit; + n = 0; + list_for_each_entry_safe_continue(bd1, bdt, &sdp->sd_log_le_databuf, bd_le.le_list) { + gfs2_log_lock(sdp); + /* An ordered write buffer */ + if (bd1->bd_bh && !buffer_pinned(bd1->bd_bh)) { + list_move(&bd1->bd_le.le_list, &started); + if (bd1 == bd2) { + bd2 = NULL; + bd2 = list_prepare_entry(bd2, &sdp->sd_log_le_databuf, bd_le.le_list); + } + total_dbuf--; + if (bd1->bd_bh) { + get_bh(bd1->bd_bh); + gfs2_log_unlock(sdp); + if (buffer_dirty(bd1->bd_bh)) { + wait_on_buffer(bd1->bd_bh); + ll_rw_block(WRITE, 1, &bd1->bd_bh); + } + brelse(bd1->bd_bh); + continue; + } + gfs2_log_unlock(sdp); + continue; + } else if (bd1->bd_bh) { /* A journaled buffer */ + int magic; + gfs2_log_unlock(sdp); + /* printk(KERN_INFO "journaled buffer\n"); */ + if (!bh) { + bh = gfs2_log_get_buf(sdp); + ld = (struct gfs2_log_descriptor *)bh->b_data; + ptr = (__be64 *)(bh->b_data + offset); + ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + ld->ld_header.mh_type = cpu_to_be16(GFS2_METATYPE_LD); + ld->ld_header.mh_format = cpu_to_be16(GFS2_FORMAT_LD); + ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_JDATA); + ld->ld_length = cpu_to_be32(num + 1); + ld->ld_data1 = cpu_to_be32(num); + ld->ld_data2 = cpu_to_be32(0); + memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); + } + magic = gfs2_check_magic(bd1->bd_bh); + *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr); + *ptr++ = cpu_to_be64((__u64)magic); + clear_buffer_escaped(bd1->bd_bh); + if (unlikely(magic != 0)) + set_buffer_escaped(bd1->bd_bh); + if (n++ > num) + break; + } + } if (bh) { - get_bh(bh); - gfs2_log_unlock(sdp); - if (buffer_dirty(bh)) { - wait_on_buffer(bh); - ll_rw_block(WRITE, 1, &bh); + set_buffer_dirty(bh); + ll_rw_block(WRITE, 1, &bh); + bh = NULL; + } + n = 0; + /* printk(KERN_INFO "totals2: jdata=%u dbuf=%u\n", total_jdata, total_dbuf); */ + list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf, bd_le.le_list) { + if (!bd2->bd_bh) + continue; + /* copy buffer if it needs escaping */ + if (unlikely(buffer_escaped(bd2->bd_bh))) { + void *kaddr; + struct page *page = bd2->bd_bh->b_page; + bh = gfs2_log_get_buf(sdp); + kaddr = kmap_atomic(page, KM_USER0); + memcpy(bh->b_data, kaddr + bh_offset(bd2->bd_bh), sdp->sd_sb.sb_bsize); + kunmap_atomic(page, KM_USER0); + *(__be32 *)bh->b_data = 0; + } else { + bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); } - brelse(bh); - } else - gfs2_log_unlock(sdp); + set_buffer_dirty(bh); + ll_rw_block(WRITE, 1, &bh); + if (++n >= num) + break; + } + bh = NULL; + total_dbuf -= num; + total_jdata -= num; } - + /* printk(KERN_INFO "wait on ordered data buffers\n"); */ + /* Wait on all ordered buffers */ while (!list_empty(&started)) { - bd = list_entry(started.next, struct gfs2_bufdata, - bd_le.le_list); - list_del(&bd->bd_le.le_list); + bd1 = list_entry(started.next, struct gfs2_bufdata, bd_le.le_list); + list_del(&bd1->bd_le.le_list); sdp->sd_log_num_databuf--; gfs2_log_lock(sdp); - bh = bd->bd_bh; + bh = bd1->bd_bh; if (bh) { set_v2bd(bh, NULL); gfs2_log_unlock(sdp); @@ -479,12 +618,103 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) } else gfs2_log_unlock(sdp); - kfree(bd); + kfree(bd1); } + /* printk(KERN_INFO "sd_log_num_databuf %u sd_log_num_jdata %u\n", sdp->sd_log_num_databuf, sdp->sd_log_num_jdata); */ + /* We've removed all the ordered write bufs here, so only jdata left */ + gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata); +} + +static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, + struct gfs2_log_descriptor *ld, + __be64 *ptr, int pass) +{ + struct gfs2_sbd *sdp = jd->jd_inode->i_sbd; + struct gfs2_glock *gl = jd->jd_inode->i_gl; + unsigned int blks = be32_to_cpu(ld->ld_data1); + struct buffer_head *bh_log, *bh_ip; + uint64_t blkno; + uint64_t esc; + int error = 0; + + if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_JDATA) + return 0; + + gfs2_replay_incr_blk(sdp, &start); + for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { + blkno = be64_to_cpu(*ptr++); + esc = be64_to_cpu(*ptr++); + + sdp->sd_found_blocks++; + + if (gfs2_revoke_check(sdp, blkno, start)) + continue; + + error = gfs2_replay_read_block(jd, start, &bh_log); + if (error) + return error; + + bh_ip = gfs2_meta_new(gl, blkno); + memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size); + + /* Unescape */ + if (esc) { + __be32 *eptr = (__be32 *)bh_ip->b_data; + *eptr = cpu_to_be32(GFS2_MAGIC); + } + mark_buffer_dirty(bh_ip); + + brelse(bh_log); + brelse(bh_ip); + if (error) + break; + + sdp->sd_replayed_blocks++; + } + + return error; +} + +/* FIXME: sort out accounting for log blocks etc. */ + +static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) +{ + struct gfs2_sbd *sdp = jd->jd_inode->i_sbd; + + if (error) { + gfs2_meta_sync(jd->jd_inode->i_gl, DIO_START | DIO_WAIT); + return; + } + if (pass != 1) + return; + + /* data sync? */ + gfs2_meta_sync(jd->jd_inode->i_gl, DIO_START | DIO_WAIT); + + fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n", + jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); +} + +static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) +{ + struct list_head *head = &sdp->sd_log_le_databuf; + struct gfs2_bufdata *bd; + + while (!list_empty(head)) { + bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); + list_del_init(&bd->bd_le.le_list); + sdp->sd_log_num_databuf--; + sdp->sd_log_num_jdata--; + gfs2_unpin(sdp, bd->bd_bh, ai); + brelse(bd->bd_bh); + kfree(bd); + } gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf); + gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata); } + struct gfs2_log_operations gfs2_glock_lops = { .lo_add = glock_lo_add, .lo_after_commit = glock_lo_after_commit, @@ -519,7 +749,11 @@ struct gfs2_log_operations gfs2_rg_lops = { struct gfs2_log_operations gfs2_databuf_lops = { .lo_add = databuf_lo_add, + .lo_incore_commit = buf_lo_incore_commit, .lo_before_commit = databuf_lo_before_commit, + .lo_after_commit = databuf_lo_after_commit, + .lo_scan_elements = databuf_lo_scan_elements, + .lo_after_scan = databuf_lo_after_scan, .lo_name = "databuf" }; diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index b6bd2ebfc2cc..ef58d43b67ee 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -547,10 +547,12 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta { struct gfs2_bufdata *bd; - lock_page(bh->b_page); + if (meta) + lock_page(bh->b_page); if (get_v2bd(bh)) { - unlock_page(bh->b_page); + if (meta) + unlock_page(bh->b_page); return; } @@ -563,14 +565,16 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta bd->bd_gl = gl; INIT_LIST_HEAD(&bd->bd_list_tr); - if (meta) + if (meta) { lops_init_le(&bd->bd_le, &gfs2_buf_lops); - else + } else { lops_init_le(&bd->bd_le, &gfs2_databuf_lops); - + get_bh(bh); + } set_v2bd(bh, bd); - unlock_page(bh->b_page); + if (meta) + unlock_page(bh->b_page); } /** diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index d611b2ad2e97..b14357e89421 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -20,13 +20,13 @@ #include "bmap.h" #include "glock.h" #include "inode.h" -#include "jdata.h" #include "log.h" #include "meta_io.h" #include "ops_address.h" #include "page.h" #include "quota.h" #include "trans.h" +#include "rgrp.h" /** * gfs2_get_block - Fills in a buffer head with details about a block @@ -149,33 +149,55 @@ static int get_blocks_noalloc(struct inode *inode, sector_t lblock, * * Returns: errno * - * Use Linux VFS block_write_full_page() to write one page, - * using GFS2's get_block_noalloc to find which blocks to write. + * Some of this is copied from block_write_full_page() although we still + * call it to do most of the work. */ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) { + struct inode *inode = page->mapping->host; struct gfs2_inode *ip = get_v2ip(page->mapping->host); struct gfs2_sbd *sdp = ip->i_sbd; + loff_t i_size = i_size_read(inode); + pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; + unsigned offset; int error; + int done_trans = 0; atomic_inc(&sdp->sd_ops_address); - if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) { unlock_page(page); return -EIO; } - if (get_transaction) { - redirty_page_for_writepage(wbc, page); + if (get_transaction) + goto out_ignore; + + /* Is the page fully outside i_size? (truncate in progress) */ + offset = i_size & (PAGE_CACHE_SIZE-1); + if (page->index >= end_index+1 || !offset) { + page->mapping->a_ops->invalidatepage(page, 0); unlock_page(page); - return 0; + return 0; /* don't care */ } - error = block_write_full_page(page, get_block_noalloc, wbc); + if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) { + error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0); + if (error) + goto out_ignore; + gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1); + done_trans = 1; + } + error = block_write_full_page(page, get_block_noalloc, wbc); + if (done_trans) + gfs2_trans_end(sdp); gfs2_meta_cache_flush(ip); - return error; + +out_ignore: + redirty_page_for_writepage(wbc, page); + unlock_page(page); + return 0; } /** @@ -226,41 +248,10 @@ static int zero_readpage(struct page *page) return 0; } -/** - * jdata_readpage - readpage that goes through gfs2_jdata_read_mem() - * @ip: - * @page: The page to read - * - * Returns: errno - */ - -static int jdata_readpage(struct gfs2_inode *ip, struct page *page) -{ - void *kaddr; - int ret; - - kaddr = kmap(page); - - ret = gfs2_jdata_read_mem(ip, kaddr, - (uint64_t)page->index << PAGE_CACHE_SHIFT, - PAGE_CACHE_SIZE); - if (ret >= 0) { - if (ret < PAGE_CACHE_SIZE) - memset(kaddr + ret, 0, PAGE_CACHE_SIZE - ret); - SetPageUptodate(page); - ret = 0; - } - - kunmap(page); - - unlock_page(page); - - return ret; -} - /** * gfs2_readpage - readpage with locking - * @file: The file to read a page for + * @file: The file to read a page for. N.B. This may be NULL if we are + * reading an internal file. * @page: The page to read * * Returns: errno @@ -270,31 +261,35 @@ static int gfs2_readpage(struct file *file, struct page *page) { struct gfs2_inode *ip = get_v2ip(page->mapping->host); struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_holder gh; int error; atomic_inc(&sdp->sd_ops_address); - if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl))) { - unlock_page(page); - return -EOPNOTSUPP; - } + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); + error = gfs2_glock_nq_m_atime(1, &gh); + if (error) + goto out_unlock; - if (!gfs2_is_jdata(ip)) { - if (gfs2_is_stuffed(ip)) { - if (!page->index) { - error = stuffed_readpage(ip, page); - unlock_page(page); - } else - error = zero_readpage(page); + if (gfs2_is_stuffed(ip)) { + if (!page->index) { + error = stuffed_readpage(ip, page); + unlock_page(page); } else - error = mpage_readpage(page, gfs2_get_block); + error = zero_readpage(page); } else - error = jdata_readpage(ip, page); + error = mpage_readpage(page, gfs2_get_block); if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) error = -EIO; + gfs2_glock_dq_m(1, &gh); + gfs2_holder_uninit(&gh); +out: return error; +out_unlock: + unlock_page(page); + goto out; } /** @@ -312,28 +307,82 @@ static int gfs2_prepare_write(struct file *file, struct page *page, { struct gfs2_inode *ip = get_v2ip(page->mapping->host); struct gfs2_sbd *sdp = ip->i_sbd; + unsigned int data_blocks, ind_blocks, rblocks; + int alloc_required; int error = 0; + loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + from; + loff_t end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + struct gfs2_alloc *al; atomic_inc(&sdp->sd_ops_address); - if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl))) - return -EOPNOTSUPP; + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &ip->i_gh); + error = gfs2_glock_nq_m_atime(1, &ip->i_gh); + if (error) + goto out_uninit; - if (gfs2_is_stuffed(ip)) { - uint64_t file_size; - file_size = ((uint64_t)page->index << PAGE_CACHE_SHIFT) + to; + gfs2_write_calc_reserv(ip, to - from, &data_blocks, &ind_blocks); + + error = gfs2_write_alloc_required(ip, pos, from - to, &alloc_required); + if (error) + goto out_unlock; - if (file_size > sdp->sd_sb.sb_bsize - - sizeof(struct gfs2_dinode)) { - error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, - page); - if (!error) - error = block_prepare_write(page, from, to, - gfs2_get_block); - } else if (!PageUptodate(page)) + + if (alloc_required) { + al = gfs2_alloc_get(ip); + + error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out_alloc_put; + + error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto out_qunlock; + + al->al_requested = data_blocks + ind_blocks; + error = gfs2_inplace_reserve(ip); + if (error) + goto out_qunlock; + } + + rblocks = RES_DINODE + ind_blocks; + if (gfs2_is_jdata(ip)) + rblocks += data_blocks ? data_blocks : 1; + if (ind_blocks || data_blocks) + rblocks += RES_STATFS + RES_QUOTA; + + error = gfs2_trans_begin(sdp, rblocks, 0); + if (error) + goto out; + + if (gfs2_is_stuffed(ip)) { + if (end > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { + error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, page); + if (error) + goto out; + } else if (!PageUptodate(page)) { error = stuffed_readpage(ip, page); - } else - error = block_prepare_write(page, from, to, gfs2_get_block); + goto out; + } + } + + error = block_prepare_write(page, from, to, gfs2_get_block); + +out: + if (error) { + gfs2_trans_end(sdp); + if (alloc_required) { + gfs2_inplace_release(ip); +out_qunlock: + gfs2_quota_unlock(ip); +out_alloc_put: + gfs2_alloc_put(ip); + } +out_unlock: + gfs2_glock_dq_m(1, &ip->i_gh); +out_uninit: + gfs2_holder_uninit(&ip->i_gh); + } return error; } @@ -354,48 +403,73 @@ static int gfs2_commit_write(struct file *file, struct page *page, struct inode *inode = page->mapping->host; struct gfs2_inode *ip = get_v2ip(inode); struct gfs2_sbd *sdp = ip->i_sbd; - int error; + int error = -EOPNOTSUPP; + struct buffer_head *dibh; + struct gfs2_alloc *al = &ip->i_alloc;; atomic_inc(&sdp->sd_ops_address); + + if (gfs2_assert_withdraw(sdp, gfs2_glock_is_locked_by_me(ip->i_gl))) + goto fail_nounlock; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto fail_endtrans; + + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + if (gfs2_is_stuffed(ip)) { - struct buffer_head *dibh; uint64_t file_size; void *kaddr; file_size = ((uint64_t)page->index << PAGE_CACHE_SHIFT) + to; - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto fail; - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - - kaddr = kmap(page); + kaddr = kmap_atomic(page, KM_USER0); memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from, - (char *)kaddr + from, - to - from); - kunmap(page); - - brelse(dibh); + (char *)kaddr + from, to - from); + kunmap_atomic(page, KM_USER0); SetPageUptodate(page); if (inode->i_size < file_size) i_size_write(inode, file_size); } else { - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) + if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) gfs2_page_add_databufs(ip, page, from, to); error = generic_commit_write(file, page, from, to); if (error) goto fail; } + if (ip->i_di.di_size < inode->i_size) + ip->i_di.di_size = inode->i_size; + + gfs2_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + gfs2_trans_end(sdp); + if (al->al_requested) { + gfs2_inplace_release(ip); + gfs2_quota_unlock(ip); + gfs2_alloc_put(ip); + } + gfs2_glock_dq_m(1, &ip->i_gh); + gfs2_holder_uninit(&ip->i_gh); return 0; - fail: +fail: + brelse(dibh); +fail_endtrans: + gfs2_trans_end(sdp); + if (al->al_requested) { + gfs2_inplace_release(ip); + gfs2_quota_unlock(ip); + gfs2_alloc_put(ip); + } + gfs2_glock_dq_m(1, &ip->i_gh); + gfs2_holder_uninit(&ip->i_gh); +fail_nounlock: ClearPageUptodate(page); - return error; } @@ -492,12 +566,16 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *io atomic_inc(&sdp->sd_ops_address); - if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)) || - gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) + if (gfs2_is_jdata(ip)) return -EINVAL; - if (rw == WRITE && !get_transaction) - gb = get_blocks_noalloc; + if (rw == WRITE) { + return -EOPNOTSUPP; /* for now */ + } else { + if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)) || + gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) + return -EINVAL; + } return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, gb, NULL); diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 0f356fc4690c..56820b39a993 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -27,7 +28,6 @@ #include "glock.h" #include "glops.h" #include "inode.h" -#include "jdata.h" #include "lm.h" #include "log.h" #include "meta_io.h" @@ -67,10 +67,37 @@ struct filldir_reg { void *fdr_opaque; }; -typedef ssize_t(*do_rw_t) (struct file *file, - char __user *buf, - size_t size, loff_t *offset, - unsigned int num_gh, struct gfs2_holder *ghs); +static int gfs2_read_actor(read_descriptor_t *desc, struct page *page, + unsigned long offset, unsigned long size) +{ + char *kaddr; + unsigned long count = desc->count; + + if (size > count) + size = count; + + kaddr = kmap(page); + memcpy(desc->arg.buf, kaddr + offset, size); + kunmap(page); + + desc->count = count - size; + desc->written += size; + desc->arg.buf += size; + return size; +} + +int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, + char *buf, loff_t *pos, unsigned size) +{ + struct inode *inode = ip->i_vnode; + read_descriptor_t desc; + desc.written = 0; + desc.arg.buf = buf; + desc.count = size; + desc.error = 0; + do_generic_mapping_read(inode->i_mapping, ra_state, NULL, pos, &desc, gfs2_read_actor); + return desc.written ? desc.written : desc.error; +} /** * gfs2_llseek - seek to a location in a file @@ -105,247 +132,114 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) return error; } -static inline unsigned int vma2state(struct vm_area_struct *vma) -{ - if ((vma->vm_flags & (VM_MAYWRITE | VM_MAYSHARE)) == - (VM_MAYWRITE | VM_MAYSHARE)) - return LM_ST_EXCLUSIVE; - return LM_ST_SHARED; -} -static ssize_t walk_vm_hard(struct file *file, const char __user *buf, size_t size, - loff_t *offset, do_rw_t operation) +static ssize_t gfs2_direct_IO_read(struct kiocb *iocb, const struct iovec *iov, + loff_t offset, unsigned long nr_segs) { - struct gfs2_holder *ghs; - unsigned int num_gh = 0; - ssize_t count; - struct super_block *sb = file->f_dentry->d_inode->i_sb; - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long start = (unsigned long)buf; - unsigned long end = start + size; - int dumping = (current->flags & PF_DUMPCORE); - unsigned int x = 0; - - for (vma = find_vma(mm, start); vma; vma = vma->vm_next) { - if (end <= vma->vm_start) - break; - if (vma->vm_file && - vma->vm_file->f_dentry->d_inode->i_sb == sb) { - num_gh++; - } - } - - ghs = kcalloc((num_gh + 1), sizeof(struct gfs2_holder), GFP_KERNEL); - if (!ghs) { - if (!dumping) - up_read(&mm->mmap_sem); - return -ENOMEM; - } + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + ssize_t retval; - for (vma = find_vma(mm, start); vma; vma = vma->vm_next) { - if (end <= vma->vm_start) - break; - if (vma->vm_file) { - struct inode *inode = vma->vm_file->f_dentry->d_inode; - if (inode->i_sb == sb) - gfs2_holder_init(get_v2ip(inode)->i_gl, - vma2state(vma), 0, &ghs[x++]); - } + retval = filemap_write_and_wait(mapping); + if (retval == 0) { + retval = mapping->a_ops->direct_IO(READ, iocb, iov, offset, + nr_segs); } - - if (!dumping) - up_read(&mm->mmap_sem); - - gfs2_assert(get_v2sdp(sb), x == num_gh); - - count = operation(file, buf, size, offset, num_gh, ghs); - - while (num_gh--) - gfs2_holder_uninit(&ghs[num_gh]); - kfree(ghs); - - return count; + return retval; } /** - * walk_vm - Walk the vmas associated with a buffer for read or write. - * If any of them are gfs2, pass the gfs2 inode down to the read/write - * worker function so that locks can be acquired in the correct order. - * @file: The file to read/write from/to - * @buf: The buffer to copy to/from - * @size: The amount of data requested - * @offset: The current file offset - * @operation: The read or write worker function - * - * Outputs: Offset - updated according to number of bytes written - * - * Returns: The number of bytes written, errno on failure + * __gfs2_file_aio_read - The main GFS2 read function + * + * N.B. This is almost, but not quite the same as __generic_file_aio_read() + * the important subtle different being that inode->i_size isn't valid + * unless we are holding a lock, and we do this _only_ on the O_DIRECT + * path since otherwise locking is done entirely at the page cache + * layer. */ - -static ssize_t walk_vm(struct file *file, const char __user *buf, size_t size, - loff_t *offset, do_rw_t operation) +static ssize_t __gfs2_file_aio_read(struct kiocb *iocb, + const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) { + struct file *filp = iocb->ki_filp; + struct gfs2_inode *ip = get_v2ip(filp->f_mapping->host); struct gfs2_holder gh; - - if (current->mm) { - struct super_block *sb = file->f_dentry->d_inode->i_sb; - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long start = (unsigned long)buf; - unsigned long end = start + size; - int dumping = (current->flags & PF_DUMPCORE); - - if (!dumping) - down_read(&mm->mmap_sem); - - for (vma = find_vma(mm, start); vma; vma = vma->vm_next) { - if (end <= vma->vm_start) - break; - if (vma->vm_file && - vma->vm_file->f_dentry->d_inode->i_sb == sb) - goto do_locks; - } - - if (!dumping) - up_read(&mm->mmap_sem); - } - - return operation(file, buf, size, offset, 0, &gh); - -do_locks: - return walk_vm_hard(file, buf, size, offset, operation); -} - -static ssize_t do_jdata_read(struct file *file, char __user *buf, size_t size, - loff_t *offset) -{ - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); - ssize_t count = 0; - - if (*offset < 0) + ssize_t retval; + unsigned long seg; + size_t count; + + count = 0; + for (seg = 0; seg < nr_segs; seg++) { + const struct iovec *iv = &iov[seg]; + + /* + * If any segment has a negative length, or the cumulative + * length ever wraps negative then return -EINVAL. + */ + count += iv->iov_len; + if (unlikely((ssize_t)(count|iv->iov_len) < 0)) return -EINVAL; - if (!access_ok(VERIFY_WRITE, buf, size)) + if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len)) + continue; + if (seg == 0) return -EFAULT; + nr_segs = seg; + count -= iv->iov_len; /* This segment is no good */ + break; + } + + /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ + if (filp->f_flags & O_DIRECT) { + loff_t pos = *ppos, size; + struct address_space *mapping; + struct inode *inode; + + mapping = filp->f_mapping; + inode = mapping->host; + retval = 0; + if (!count) + goto out; /* skip atime */ + + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); + retval = gfs2_glock_nq_m_atime(1, &gh); + if (retval) + goto out; - if (!(file->f_flags & O_LARGEFILE)) { - if (*offset >= MAX_NON_LFS) - return -EFBIG; - if (*offset + size > MAX_NON_LFS) - size = MAX_NON_LFS - *offset; - } - - count = gfs2_jdata_read(ip, buf, *offset, size, gfs2_copy2user); - - if (count > 0) - *offset += count; - - return count; -} - -/** - * do_read_direct - Read bytes from a file - * @file: The file to read from - * @buf: The buffer to copy into - * @size: The amount of data requested - * @offset: The current file offset - * @num_gh: The number of other locks we need to do the read - * @ghs: the locks we need plus one for our lock - * - * Outputs: Offset - updated according to number of bytes read - * - * Returns: The number of bytes read, errno on failure - */ - -static ssize_t do_read_direct(struct file *file, char __user *buf, size_t size, - loff_t *offset, unsigned int num_gh, - struct gfs2_holder *ghs) -{ - struct inode *inode = file->f_mapping->host; - struct gfs2_inode *ip = get_v2ip(inode); - unsigned int state = LM_ST_DEFERRED; - int flags = 0; - unsigned int x; - ssize_t count = 0; - int error; - - for (x = 0; x < num_gh; x++) - if (ghs[x].gh_gl == ip->i_gl) { - state = LM_ST_SHARED; - flags |= GL_LOCAL_EXCL; - break; + size = i_size_read(inode); + if (pos < size) { + retval = gfs2_direct_IO_read(iocb, iov, pos, nr_segs); + if (retval > 0 && !is_sync_kiocb(iocb)) + retval = -EIOCBQUEUED; + if (retval > 0) + *ppos = pos + retval; } - - gfs2_holder_init(ip->i_gl, state, flags, &ghs[num_gh]); - - error = gfs2_glock_nq_m(num_gh + 1, ghs); - if (error) + file_accessed(filp); + gfs2_glock_dq_m(1, &gh); + gfs2_holder_uninit(&gh); goto out; + } - error = -EINVAL; - if (gfs2_is_jdata(ip)) - goto out_gunlock; - - if (gfs2_is_stuffed(ip)) { - size_t mask = bdev_hardsect_size(inode->i_sb->s_bdev) - 1; - - if (((*offset) & mask) || (((unsigned long)buf) & mask)) - goto out_gunlock; - - count = do_jdata_read(file, buf, size & ~mask, offset); - } else - count = generic_file_read(file, buf, size, offset); - - error = 0; - - out_gunlock: - gfs2_glock_dq_m(num_gh + 1, ghs); - - out: - gfs2_holder_uninit(&ghs[num_gh]); - - return (count) ? count : error; -} - -/** - * do_read_buf - Read bytes from a file - * @file: The file to read from - * @buf: The buffer to copy into - * @size: The amount of data requested - * @offset: The current file offset - * @num_gh: The number of other locks we need to do the read - * @ghs: the locks we need plus one for our lock - * - * Outputs: Offset - updated according to number of bytes read - * - * Returns: The number of bytes read, errno on failure - */ - -static ssize_t do_read_buf(struct file *file, char __user *buf, size_t size, - loff_t *offset, unsigned int num_gh, - struct gfs2_holder *ghs) -{ - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); - ssize_t count = 0; - int error; - - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &ghs[num_gh]); - - error = gfs2_glock_nq_m_atime(num_gh + 1, ghs); - if (error) - goto out; - - if (gfs2_is_jdata(ip)) - count = do_jdata_read(file, buf, size, offset); - else - count = generic_file_read(file, buf, size, offset); - - gfs2_glock_dq_m(num_gh + 1, ghs); - - out: - gfs2_holder_uninit(&ghs[num_gh]); - - return (count) ? count : error; + retval = 0; + if (count) { + for (seg = 0; seg < nr_segs; seg++) { + read_descriptor_t desc; + + desc.written = 0; + desc.arg.buf = iov[seg].iov_base; + desc.count = iov[seg].iov_len; + if (desc.count == 0) + continue; + desc.error = 0; + do_generic_file_read(filp,ppos,&desc,file_read_actor); + retval += desc.written; + if (desc.error) { + retval = retval ?: desc.error; + break; + } + } + } +out: + return retval; } /** @@ -360,550 +254,49 @@ static ssize_t do_read_buf(struct file *file, char __user *buf, size_t size, * Returns: The number of bytes read, errno on failure */ -static ssize_t gfs2_read(struct file *file, char __user *buf, size_t size, +static ssize_t gfs2_read(struct file *filp, char __user *buf, size_t size, loff_t *offset) { - atomic_inc(&get_v2sdp(file->f_mapping->host->i_sb)->sd_ops_file); - - if (file->f_flags & O_DIRECT) - return walk_vm(file, buf, size, offset, do_read_direct); - else - return walk_vm(file, buf, size, offset, do_read_buf); -} - -/** - * grope_mapping - feel up a mapping that needs to be written - * @buf: the start of the memory to be written - * @size: the size of the memory to be written - * - * We do this after acquiring the locks on the mapping, - * but before starting the write transaction. We need to make - * sure that we don't cause recursive transactions if blocks - * need to be allocated to the file backing the mapping. - * - * Returns: errno - */ - -static int grope_mapping(const char __user *buf, size_t size) -{ - const char __user *stop = buf + size; - char c; - - while (buf < stop) { - if (copy_from_user(&c, buf, 1)) - return -EFAULT; - buf += PAGE_CACHE_SIZE; - buf = (const char __user *)PAGE_ALIGN((unsigned long)buf); - } - - return 0; -} - -/** - * do_write_direct_alloc - Write bytes to a file - * @file: The file to write to - * @buf: The buffer to copy from - * @size: The amount of data requested - * @offset: The current file offset - * - * Outputs: Offset - updated according to number of bytes written - * - * Returns: The number of bytes written, errno on failure - */ - -static ssize_t do_write_direct_alloc(struct file *file, const char __user *buf, size_t size, - loff_t *offset) -{ - struct inode *inode = file->f_mapping->host; - struct gfs2_inode *ip = get_v2ip(inode); - struct gfs2_sbd *sdp = ip->i_sbd; - struct gfs2_alloc *al = NULL; struct iovec local_iov = { .iov_base = buf, .iov_len = size }; - struct buffer_head *dibh; - unsigned int data_blocks, ind_blocks; - ssize_t count; - int error; - - gfs2_write_calc_reserv(ip, size, &data_blocks, &ind_blocks); - - al = gfs2_alloc_get(ip); - - error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); - if (error) - goto fail; - - error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); - if (error) - goto fail_gunlock_q; - - al->al_requested = data_blocks + ind_blocks; - - error = gfs2_inplace_reserve(ip); - if (error) - goto fail_gunlock_q; - - error = gfs2_trans_begin(sdp, - al->al_rgd->rd_ri.ri_length + ind_blocks + - RES_DINODE + RES_STATFS + RES_QUOTA, 0); - if (error) - goto fail_ipres; - - if ((ip->i_di.di_mode & (S_ISUID | S_ISGID)) && !capable(CAP_FSETID)) { - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto fail_end_trans; - - ip->i_di.di_mode &= (ip->i_di.di_mode & S_IXGRP) ? - (~(S_ISUID | S_ISGID)) : (~S_ISUID); - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); - brelse(dibh); - } - - if (gfs2_is_stuffed(ip)) { - error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_sync, NULL); - if (error) - goto fail_end_trans; - } - - count = generic_file_write_nolock(file, &local_iov, 1, offset); - if (count < 0) { - error = count; - goto fail_end_trans; - } - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto fail_end_trans; - - if (ip->i_di.di_size < inode->i_size) - ip->i_di.di_size = inode->i_size; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); - brelse(dibh); - - gfs2_trans_end(sdp); + struct kiocb kiocb; + ssize_t ret; - if (file->f_flags & O_SYNC) - gfs2_log_flush_glock(ip->i_gl); - - gfs2_inplace_release(ip); - gfs2_quota_unlock(ip); - gfs2_alloc_put(ip); - - if (file->f_mapping->nrpages) { - error = filemap_fdatawrite(file->f_mapping); - if (!error) - error = filemap_fdatawait(file->f_mapping); - } - if (error) - return error; - - return count; - - fail_end_trans: - gfs2_trans_end(sdp); - - fail_ipres: - gfs2_inplace_release(ip); - - fail_gunlock_q: - gfs2_quota_unlock(ip); - - fail: - gfs2_alloc_put(ip); + atomic_inc(&get_v2sdp(filp->f_mapping->host->i_sb)->sd_ops_file); - return error; -} - -/** - * do_write_direct - Write bytes to a file - * @file: The file to write to - * @buf: The buffer to copy from - * @size: The amount of data requested - * @offset: The current file offset - * @num_gh: The number of other locks we need to do the read - * @gh: the locks we need plus one for our lock - * - * Outputs: Offset - updated according to number of bytes written - * - * Returns: The number of bytes written, errno on failure - */ - -static ssize_t do_write_direct(struct file *file, const char __user *buf, size_t size, - loff_t *offset, unsigned int num_gh, - struct gfs2_holder *ghs) -{ - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); - struct gfs2_sbd *sdp = ip->i_sbd; - struct gfs2_file *fp = get_v2fp(file); - unsigned int state = LM_ST_DEFERRED; - int alloc_required; - unsigned int x; - size_t s; - ssize_t count = 0; - int error; - - if (test_bit(GFF_DID_DIRECT_ALLOC, &fp->f_flags)) - state = LM_ST_EXCLUSIVE; - else - for (x = 0; x < num_gh; x++) - if (ghs[x].gh_gl == ip->i_gl) { - state = LM_ST_EXCLUSIVE; - break; - } - - restart: - gfs2_holder_init(ip->i_gl, state, 0, &ghs[num_gh]); - - error = gfs2_glock_nq_m(num_gh + 1, ghs); - if (error) - goto out; - - error = -EINVAL; - if (gfs2_is_jdata(ip)) - goto out_gunlock; - - if (num_gh) { - error = grope_mapping(buf, size); - if (error) - goto out_gunlock; - } - - if (file->f_flags & O_APPEND) - *offset = ip->i_di.di_size; - - if (!(file->f_flags & O_LARGEFILE)) { - error = -EFBIG; - if (*offset >= MAX_NON_LFS) - goto out_gunlock; - if (*offset + size > MAX_NON_LFS) - size = MAX_NON_LFS - *offset; - } - - if (gfs2_is_stuffed(ip) || - *offset + size > ip->i_di.di_size || - ((ip->i_di.di_mode & (S_ISUID | S_ISGID)) && !capable(CAP_FSETID))) - alloc_required = 1; - else { - error = gfs2_write_alloc_required(ip, *offset, size, - &alloc_required); - if (error) - goto out_gunlock; - } - - if (alloc_required && state != LM_ST_EXCLUSIVE) { - gfs2_glock_dq_m(num_gh + 1, ghs); - gfs2_holder_uninit(&ghs[num_gh]); - state = LM_ST_EXCLUSIVE; - goto restart; - } - - if (alloc_required) { - set_bit(GFF_DID_DIRECT_ALLOC, &fp->f_flags); - - /* split large writes into smaller atomic transactions */ - while (size) { - s = gfs2_tune_get(sdp, gt_max_atomic_write); - if (s > size) - s = size; - - error = do_write_direct_alloc(file, buf, s, offset); - if (error < 0) - goto out_gunlock; - - buf += error; - size -= error; - count += error; - } - } else { - struct iovec local_iov = { .iov_base = buf, .iov_len = size }; - struct gfs2_holder t_gh; - - clear_bit(GFF_DID_DIRECT_ALLOC, &fp->f_flags); - - error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, - GL_NEVER_RECURSE, &t_gh); - if (error) - goto out_gunlock; - - count = generic_file_write_nolock(file, &local_iov, 1, offset); - - gfs2_glock_dq_uninit(&t_gh); - } - - error = 0; - - out_gunlock: - gfs2_glock_dq_m(num_gh + 1, ghs); - - out: - gfs2_holder_uninit(&ghs[num_gh]); - - return (count) ? count : error; + init_sync_kiocb(&kiocb, filp); + ret = __gfs2_file_aio_read(&kiocb, &local_iov, 1, offset); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&kiocb); + return ret; } -/** - * do_do_write_buf - Write bytes to a file - * @file: The file to write to - * @buf: The buffer to copy from - * @size: The amount of data requested - * @offset: The current file offset - * - * Outputs: Offset - updated according to number of bytes written - * - * Returns: The number of bytes written, errno on failure - */ - -static ssize_t do_do_write_buf(struct file *file, const char __user *buf, size_t size, - loff_t *offset) +static ssize_t gfs2_file_readv(struct file *filp, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) { - struct inode *inode = file->f_mapping->host; - struct gfs2_inode *ip = get_v2ip(inode); - struct gfs2_sbd *sdp = ip->i_sbd; - struct gfs2_alloc *al = NULL; - struct buffer_head *dibh; - unsigned int data_blocks, ind_blocks; - int alloc_required, journaled; - ssize_t count; - int error; - - journaled = gfs2_is_jdata(ip); - - gfs2_write_calc_reserv(ip, size, &data_blocks, &ind_blocks); - - error = gfs2_write_alloc_required(ip, *offset, size, &alloc_required); - if (error) - return error; - - if (alloc_required) { - al = gfs2_alloc_get(ip); - - error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); - if (error) - goto fail; - - error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); - if (error) - goto fail_gunlock_q; - - al->al_requested = data_blocks + ind_blocks; - - error = gfs2_inplace_reserve(ip); - if (error) - goto fail_gunlock_q; - - error = gfs2_trans_begin(sdp, - al->al_rgd->rd_ri.ri_length + - ind_blocks + - ((journaled) ? data_blocks : 0) + - RES_DINODE + RES_STATFS + RES_QUOTA, - 0); - if (error) - goto fail_ipres; - } else { - error = gfs2_trans_begin(sdp, - ((journaled) ? data_blocks : 0) + - RES_DINODE, - 0); - if (error) - goto fail_ipres; - } - - if ((ip->i_di.di_mode & (S_ISUID | S_ISGID)) && !capable(CAP_FSETID)) { - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto fail_end_trans; - - ip->i_di.di_mode &= (ip->i_di.di_mode & S_IXGRP) ? - (~(S_ISUID | S_ISGID)) : (~S_ISUID); - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); - brelse(dibh); - } + struct kiocb kiocb; + ssize_t ret; - if (journaled) { - count = gfs2_jdata_write(ip, buf, *offset, size, - gfs2_copy_from_user); - if (count < 0) { - error = count; - goto fail_end_trans; - } - - *offset += count; - } else { - struct iovec local_iov = { .iov_base = buf, .iov_len = size }; - - count = generic_file_write_nolock(file, &local_iov, 1, offset); - if (count < 0) { - error = count; - goto fail_end_trans; - } - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto fail_end_trans; - - if (ip->i_di.di_size < inode->i_size) - ip->i_di.di_size = inode->i_size; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); - brelse(dibh); - } - - gfs2_trans_end(sdp); - - if (file->f_flags & O_SYNC || IS_SYNC(inode)) { - gfs2_log_flush_glock(ip->i_gl); - error = filemap_fdatawrite(file->f_mapping); - if (error == 0) - error = filemap_fdatawait(file->f_mapping); - if (error) - goto fail_ipres; - } - - if (alloc_required) { - gfs2_assert_warn(sdp, count != size || - al->al_alloced); - gfs2_inplace_release(ip); - gfs2_quota_unlock(ip); - gfs2_alloc_put(ip); - } - - return count; - - fail_end_trans: - gfs2_trans_end(sdp); - - fail_ipres: - if (alloc_required) - gfs2_inplace_release(ip); - - fail_gunlock_q: - if (alloc_required) - gfs2_quota_unlock(ip); + atomic_inc(&get_v2sdp(filp->f_mapping->host->i_sb)->sd_ops_file); - fail: - if (alloc_required) - gfs2_alloc_put(ip); - - return error; + init_sync_kiocb(&kiocb, filp); + ret = __gfs2_file_aio_read(&kiocb, iov, nr_segs, ppos); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&kiocb); + return ret; } -/** - * do_write_buf - Write bytes to a file - * @file: The file to write to - * @buf: The buffer to copy from - * @size: The amount of data requested - * @offset: The current file offset - * @num_gh: The number of other locks we need to do the read - * @gh: the locks we need plus one for our lock - * - * Outputs: Offset - updated according to number of bytes written - * - * Returns: The number of bytes written, errno on failure - */ - -static ssize_t do_write_buf(struct file *file, const char __user *buf, size_t size, - loff_t *offset, unsigned int num_gh, - struct gfs2_holder *ghs) +static ssize_t gfs2_file_aio_read(struct kiocb *iocb, char __user *buf, + size_t count, loff_t pos) { - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); - struct gfs2_sbd *sdp = ip->i_sbd; - size_t s; - ssize_t count = 0; - int error; - - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[num_gh]); - - error = gfs2_glock_nq_m(num_gh + 1, ghs); - if (error) - goto out; - - if (num_gh) { - error = grope_mapping(buf, size); - if (error) - goto out_gunlock; - } - - if (file->f_flags & O_APPEND) - *offset = ip->i_di.di_size; - - if (!(file->f_flags & O_LARGEFILE)) { - error = -EFBIG; - if (*offset >= MAX_NON_LFS) - goto out_gunlock; - if (*offset + size > MAX_NON_LFS) - size = MAX_NON_LFS - *offset; - } - - /* split large writes into smaller atomic transactions */ - while (size) { - s = gfs2_tune_get(sdp, gt_max_atomic_write); - if (s > size) - s = size; - - error = do_do_write_buf(file, buf, s, offset); - if (error < 0) - goto out_gunlock; - - buf += error; - size -= error; - count += error; - } - - error = 0; + struct file *filp = iocb->ki_filp; + struct iovec local_iov = { .iov_base = buf, .iov_len = count }; - out_gunlock: - gfs2_glock_dq_m(num_gh + 1, ghs); + atomic_inc(&get_v2sdp(filp->f_mapping->host->i_sb)->sd_ops_file); - out: - gfs2_holder_uninit(&ghs[num_gh]); - - return (count) ? count : error; + BUG_ON(iocb->ki_pos != pos); + return __gfs2_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); } -/** - * gfs2_write - Write bytes to a file - * @file: The file to write to - * @buf: The buffer to copy from - * @size: The amount of data requested - * @offset: The current file offset - * - * Outputs: Offset - updated according to number of bytes written - * - * Returns: The number of bytes written, errno on failure - */ - -static ssize_t gfs2_write(struct file *file, const char __user *buf, - size_t size, loff_t *offset) -{ - struct inode *inode = file->f_mapping->host; - ssize_t count; - - atomic_inc(&get_v2sdp(inode->i_sb)->sd_ops_file); - - if (*offset < 0) - return -EINVAL; - if (!access_ok(VERIFY_READ, buf, size)) - return -EFAULT; - - mutex_lock(&inode->i_mutex); - if (file->f_flags & O_DIRECT) - count = walk_vm(file, buf, size, offset, - do_write_direct); - else - count = walk_vm(file, buf, size, offset, do_write_buf); - mutex_unlock(&inode->i_mutex); - - return count; -} /** * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() @@ -1158,9 +551,6 @@ static int gfs2_ioctl_flags(struct gfs2_inode *ip, unsigned int cmd, unsigned lo if (flags & (GFS2_DIF_JDATA|GFS2_DIF_DIRECTIO)) { if (!S_ISREG(ip->i_di.di_mode)) goto out; - /* FIXME: Would be nice not to require the following test */ - if ((flags & GFS2_DIF_JDATA) && ip->i_di.di_size) - goto out; } if (flags & (GFS2_DIF_INHERIT_JDATA|GFS2_DIF_INHERIT_DIRECTIO)) { if (!S_ISDIR(ip->i_di.di_mode)) @@ -1246,21 +636,14 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) return error; } - if (gfs2_is_jdata(ip)) { - if (vma->vm_flags & VM_MAYSHARE) - error = -EOPNOTSUPP; - else - vma->vm_ops = &gfs2_vm_ops_private; - } else { - /* This is VM_MAYWRITE instead of VM_WRITE because a call - to mprotect() can turn on VM_WRITE later. */ - - if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) == - (VM_MAYSHARE | VM_MAYWRITE)) - vma->vm_ops = &gfs2_vm_ops_sharewrite; - else - vma->vm_ops = &gfs2_vm_ops_private; - } + /* This is VM_MAYWRITE instead of VM_WRITE because a call + to mprotect() can turn on VM_WRITE later. */ + + if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) == + (VM_MAYSHARE | VM_MAYWRITE)) + vma->vm_ops = &gfs2_vm_ops_sharewrite; + else + vma->vm_ops = &gfs2_vm_ops_private; gfs2_glock_dq_uninit(&i_gh); @@ -1313,13 +696,6 @@ static int gfs2_open(struct inode *inode, struct file *file) if (ip->i_di.di_flags & GFS2_DIF_DIRECTIO) file->f_flags |= O_DIRECT; - /* Don't let the user open O_DIRECT on a jdata file */ - - if ((file->f_flags & O_DIRECT) && gfs2_is_jdata(ip)) { - error = -EINVAL; - goto fail_gunlock; - } - gfs2_glock_dq_uninit(&i_gh); } @@ -1446,29 +822,10 @@ static ssize_t gfs2_sendfile(struct file *in_file, loff_t *offset, size_t count, read_actor_t actor, void *target) { struct gfs2_inode *ip = get_v2ip(in_file->f_mapping->host); - struct gfs2_holder gh; - ssize_t retval; atomic_inc(&ip->i_sbd->sd_ops_file); - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); - - retval = gfs2_glock_nq_atime(&gh); - if (retval) - goto out; - - if (gfs2_is_jdata(ip)) - retval = -EOPNOTSUPP; - else - retval = generic_file_sendfile(in_file, offset, count, actor, - target); - - gfs2_glock_dq(&gh); - - out: - gfs2_holder_uninit(&gh); - - return retval; + return generic_file_sendfile(in_file, offset, count, actor, target); } static int do_flock(struct file *file, int cmd, struct file_lock *fl) @@ -1567,7 +924,11 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) struct file_operations gfs2_file_fops = { .llseek = gfs2_llseek, .read = gfs2_read, - .write = gfs2_write, + .readv = gfs2_file_readv, + .aio_read = gfs2_file_aio_read, + .write = generic_file_write, + .writev = generic_file_writev, + .aio_write = generic_file_aio_write, .ioctl = gfs2_ioctl, .mmap = gfs2_mmap, .open = gfs2_open, diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index a1b409ce75e1..8f77bb7896bd 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -155,9 +155,6 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, if (error) return NULL; - if (gfs2_is_jdata(ip)) - goto out; - set_bit(GIF_PAGED, &ip->i_flags); set_bit(GIF_SW_PAGED, &ip->i_flags); diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c index ea31bceac4f2..3542aa6b01c4 100644 --- a/fs/gfs2/page.c +++ b/fs/gfs2/page.c @@ -172,8 +172,8 @@ int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, map_bh(bh, inode->i_sb, block); set_buffer_uptodate(bh); - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) - gfs2_trans_add_databuf(sdp, bh); + if ((sdp->sd_args.ar_data == GFS2_DATA_ORDERED) || gfs2_is_jdata(ip)) + gfs2_trans_add_bh(ip->i_gl, bh, 0); mark_buffer_dirty(bh); if (release) { @@ -245,8 +245,8 @@ int gfs2_block_truncate_page(struct address_space *mapping) goto unlock; } - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED/* || gfs2_is_jdata(ip)*/) - gfs2_trans_add_databuf(sdp, bh); + if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) + gfs2_trans_add_bh(ip->i_gl, bh, 0); kaddr = kmap_atomic(page, KM_USER0); memset(kaddr + offset, 0, length); @@ -273,7 +273,7 @@ void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, end = start + bsize; if (end <= from || start >= to) continue; - gfs2_trans_add_databuf(ip->i_sbd, bh); + gfs2_trans_add_bh(ip->i_gl, bh, 0); } } diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 69e8f4e92e57..138fdf559a9a 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -43,20 +43,22 @@ #include #include #include +#include #include #include "gfs2.h" #include "bmap.h" #include "glock.h" #include "glops.h" -#include "jdata.h" #include "log.h" #include "meta_io.h" #include "quota.h" #include "rgrp.h" #include "super.h" #include "trans.h" +#include "inode.h" #include "ops_file.h" +#include "ops_address.h" #define QUOTA_USER 1 #define QUOTA_GROUP 0 @@ -561,6 +563,81 @@ static void do_qc(struct gfs2_quota_data *qd, int64_t change) up(&sdp->sd_quota_mutex); } +/** + * gfs2_adjust_quota + * + * This function was mostly borrowed from gfs2_block_truncate_page which was + * in turn mostly borrowed from ext3 + */ +static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, + int64_t change, struct gfs2_quota_data *qd) +{ + struct inode *inode = gfs2_ip2v(ip); + struct address_space *mapping = inode->i_mapping; + unsigned long index = loc >> PAGE_CACHE_SHIFT; + unsigned offset = loc & (PAGE_CACHE_SHIFT - 1); + unsigned blocksize, iblock, pos; + struct buffer_head *bh; + struct page *page; + void *kaddr; + __be64 *ptr; + u64 value; + int err = -EIO; + + page = grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + + blocksize = inode->i_sb->s_blocksize; + iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); + + if (!page_has_buffers(page)) + create_empty_buffers(page, blocksize, 0); + + bh = page_buffers(page); + pos = blocksize; + while (offset >= pos) { + bh = bh->b_this_page; + iblock++; + pos += blocksize; + } + + if (!buffer_mapped(bh)) { + gfs2_get_block(inode, iblock, bh, 1); + if (!buffer_mapped(bh)) + goto unlock; + } + + if (PageUptodate(page)) + set_buffer_uptodate(bh); + + if (!buffer_uptodate(bh)) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) + goto unlock; + } + + gfs2_trans_add_bh(ip->i_gl, bh, 0); + + kaddr = kmap_atomic(page, KM_USER0); + ptr = (__be64 *)(kaddr + offset); + value = *ptr = cpu_to_be64(be64_to_cpu(*ptr) + change); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + err = 0; + qd->qd_qb.qb_magic = cpu_to_be32(GFS2_MAGIC); +#if 0 + qd->qd_qb.qb_limit = cpu_to_be64(q.qu_limit); + qd->qd_qb.qb_warn = cpu_to_be64(q.qu_warn); +#endif + qd->qd_qb.qb_value = cpu_to_be64(value); +unlock: + unlock_page(page); + page_cache_release(page); + return err; +} + static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) { struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd; @@ -635,43 +712,14 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) file_ra_state_init(&ra_state, ip->i_vnode->i_mapping); for (x = 0; x < num_qd; x++) { - char buf[sizeof(struct gfs2_quota)]; - struct gfs2_quota q; - qd = qda[x]; offset = qd2offset(qd); - - /* The quota file may not be a multiple of - sizeof(struct gfs2_quota) bytes. */ - memset(buf, 0, sizeof(struct gfs2_quota)); - - error = gfs2_internal_read(ip, &ra_state, buf, &offset, - sizeof(struct gfs2_quota)); - if (error < 0) + error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync, + (struct gfs2_quota_data *)qd->qd_gl->gl_lvb); + if (error) goto out_end_trans; - gfs2_quota_in(&q, buf); - q.qu_value += qda[x]->qd_change_sync; - gfs2_quota_out(&q, buf); - - error = gfs2_jdata_write_mem(ip, buf, offset, - sizeof(struct gfs2_quota)); - if (error < 0) - goto out_end_trans; - else if (error != sizeof(struct gfs2_quota)) { - error = -EIO; - goto out_end_trans; - } - do_qc(qd, -qd->qd_change_sync); - - memset(&qd->qd_qb, 0, sizeof(struct gfs2_quota_lvb)); - qd->qd_qb.qb_magic = GFS2_MAGIC; - qd->qd_qb.qb_limit = q.qu_limit; - qd->qd_qb.qb_warn = q.qu_warn; - qd->qd_qb.qb_value = q.qu_value; - - gfs2_quota_lvb_out(&qd->qd_qb, qd->qd_gl->gl_lvb); } error = 0; diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index b014591fa4a4..104e664fa182 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -154,14 +154,13 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta) gfs2_attach_bufdata(gl, bh, meta); bd = get_v2bd(bh); } - lops_add(sdp, &bd->bd_le); } void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, uint64_t blkno) { struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke), - GFP_KERNEL | __GFP_NOFAIL); + GFP_NOFS | __GFP_NOFAIL); lops_init_le(&rv->rv_le, &gfs2_revoke_lops); rv->rv_blkno = blkno; lops_add(sdp, &rv->rv_le); @@ -197,19 +196,3 @@ void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd) lops_add(rgd->rd_sbd, &rgd->rd_le); } -void gfs2_trans_add_databuf(struct gfs2_sbd *sdp, struct buffer_head *bh) -{ - struct gfs2_bufdata *bd; - - bd = get_v2bd(bh); - if (!bd) { - bd = kmalloc(sizeof(struct gfs2_bufdata), - GFP_NOFS | __GFP_NOFAIL); - lops_init_le(&bd->bd_le, &gfs2_databuf_lops); - get_bh(bh); - bd->bd_bh = bh; - set_v2bd(bh, bd); - lops_add(sdp, &bd->bd_le); - } -} - diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index 5a7da1e853c9..f7f3e2a3d590 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -35,6 +35,5 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta); void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, uint64_t blkno); void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, uint64_t blkno); void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd); -void gfs2_trans_add_databuf(struct gfs2_sbd *sdp, struct buffer_head *bh); #endif /* __TRANS_DOT_H__ */ diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index ad49153c33d1..4fb1704aac10 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -50,6 +50,7 @@ int gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion, "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", sdp->sd_fsname, assertion, sdp->sd_fsname, function, file, line); + dump_stack(); return (me) ? -1 : -2; } @@ -75,6 +76,8 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, if (sdp->sd_args.ar_debug) BUG(); + else + dump_stack(); sdp->sd_last_warning = jiffies; diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index f1302e2616da..99d7ae4f6b7e 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -336,6 +336,10 @@ struct gfs2_log_header { /* ld_data1 is the number of revoke blocks in the descriptor. ld_data2 is unused. */ +#define GFS2_LOG_DESC_JDATA 302 +/* ld_data1 is the number of data blocks in the descriptor. + ld_data2 is unused. */ + struct gfs2_log_descriptor { struct gfs2_meta_header ld_header; @@ -400,6 +404,7 @@ struct gfs2_quota_change { __be32 qc_id; }; +#ifdef __KERNEL__ /* Translation functions */ extern void gfs2_inum_in(struct gfs2_inum *no, char *buf); @@ -444,4 +449,6 @@ extern void gfs2_statfs_change_print(struct gfs2_statfs_change *sc); extern void gfs2_unlinked_tag_print(struct gfs2_unlinked_tag *ut); extern void gfs2_quota_change_print(struct gfs2_quota_change *qc); +#endif /* __KERNEL__ */ + #endif /* __GFS2_ONDISK_DOT_H__ */ -- cgit v1.2.3 From fc69d0d336214219abb521d8ff060f786d7f369e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 13 Feb 2006 16:21:47 +0000 Subject: [GFS2] Change ondisk format (hopefully for the last time) There were one or two fields in structures which didn't get changed last time back to their gfs1 sizes and alignments. One or two constants have also changed back to their original values which were missed the first time. Its possible that indirect pointer blocks might need to change. If they don't we'll have to rewrite them all on upgrade due to a change in the amount of padding that they use. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 36 +++++++++++++++++++----------------- include/linux/gfs2_ondisk.h | 42 +++++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 38 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index c77e18048d98..c32f7b3de662 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -397,11 +397,11 @@ static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, { struct gfs2_dirent *tmp, *cur; char *bh_end; - uint32_t cur_rec_len; + uint16_t cur_rec_len; cur = *dent; bh_end = bh->b_data + bh->b_size; - cur_rec_len = be32_to_cpu(cur->de_rec_len); + cur_rec_len = be16_to_cpu(cur->de_rec_len); if ((char *)cur + cur_rec_len >= bh_end) { if ((char *)cur + cur_rec_len > bh_end) { @@ -413,7 +413,7 @@ static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, tmp = (struct gfs2_dirent *)((char *)cur + cur_rec_len); - if ((char *)tmp + be32_to_cpu(tmp->de_rec_len) > bh_end) { + if ((char *)tmp + be16_to_cpu(tmp->de_rec_len) > bh_end) { gfs2_consist_inode(dip); return -EIO; } @@ -440,7 +440,7 @@ static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, struct gfs2_dirent *prev, struct gfs2_dirent *cur) { - uint32_t cur_rec_len, prev_rec_len; + uint16_t cur_rec_len, prev_rec_len; if (!cur->de_inum.no_addr) { gfs2_consist_inode(dip); @@ -460,8 +460,8 @@ static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, /* Combine this dentry with the previous one. */ - prev_rec_len = be32_to_cpu(prev->de_rec_len); - cur_rec_len = be32_to_cpu(cur->de_rec_len); + prev_rec_len = be16_to_cpu(prev->de_rec_len); + cur_rec_len = be16_to_cpu(cur->de_rec_len); if ((char *)prev + prev_rec_len != (char *)cur) gfs2_consist_inode(dip); @@ -469,7 +469,7 @@ static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, gfs2_consist_inode(dip); prev_rec_len += cur_rec_len; - prev->de_rec_len = cpu_to_be32(prev_rec_len); + prev->de_rec_len = cpu_to_be16(prev_rec_len); } /** @@ -513,7 +513,7 @@ int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, gfs2_trans_add_bh(dip->i_gl, bh, 1); dent->de_rec_len = bh->b_size - offset; - dent->de_rec_len = cpu_to_be32(dent->de_rec_len); + dent->de_rec_len = cpu_to_be16(dent->de_rec_len); dent->de_name_len = name_len; *dent_out = dent; @@ -521,9 +521,10 @@ int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, } do { - uint32_t cur_rec_len, cur_name_len; + uint16_t cur_rec_len; + uint32_t cur_name_len; - cur_rec_len = be32_to_cpu(dent->de_rec_len); + cur_rec_len = be16_to_cpu(dent->de_rec_len); cur_name_len = dent->de_name_len; if ((!dent->de_inum.no_addr && cur_rec_len >= rec_len) || @@ -536,11 +537,11 @@ int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, memset(new, 0, sizeof(struct gfs2_dirent)); new->de_rec_len = cur_rec_len - GFS2_DIRENT_SIZE(cur_name_len); - new->de_rec_len = cpu_to_be32(new->de_rec_len); + new->de_rec_len = cpu_to_be16(new->de_rec_len); new->de_name_len = name_len; - dent->de_rec_len = cur_rec_len - be32_to_cpu(new->de_rec_len); - dent->de_rec_len = cpu_to_be32(dent->de_rec_len); + dent->de_rec_len = cur_rec_len - be16_to_cpu(new->de_rec_len); + dent->de_rec_len = cpu_to_be16(dent->de_rec_len); *dent_out = new; return 0; @@ -589,9 +590,10 @@ static int dirent_fits(struct gfs2_inode *dip, struct buffer_head *bh, return 1; do { - uint32_t cur_rec_len, cur_name_len; + uint16_t cur_rec_len; + uint32_t cur_name_len; - cur_rec_len = be32_to_cpu(dent->de_rec_len); + cur_rec_len = be16_to_cpu(dent->de_rec_len); cur_name_len = dent->de_name_len; if ((!dent->de_inum.no_addr && cur_rec_len >= rec_len) || @@ -832,10 +834,10 @@ static int dir_make_exhash(struct gfs2_inode *dip) /* Adjust the last dirent's record length (Remember that dent still points to the last entry.) */ - dent->de_rec_len = be32_to_cpu(dent->de_rec_len) + + dent->de_rec_len = be16_to_cpu(dent->de_rec_len) + sizeof(struct gfs2_dinode) - sizeof(struct gfs2_leaf); - dent->de_rec_len = cpu_to_be32(dent->de_rec_len); + dent->de_rec_len = cpu_to_be16(dent->de_rec_len); brelse(bh); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 99d7ae4f6b7e..ec432e0c208d 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -1,11 +1,11 @@ /* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License v.2. - */ +* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +* +* This copyrighted material is made available to anyone wishing to use, +* modify, copy, or redistribute it subject to the terms and conditions +* of the GNU General Public License v.2. +*/ #ifndef __GFS2_ONDISK_DOT_H__ #define __GFS2_ONDISK_DOT_H__ @@ -34,14 +34,14 @@ #define GFS2_FORMAT_LH 800 #define GFS2_FORMAT_LD 900 #define GFS2_FORMAT_LB 1000 -#define GFS2_FORMAT_EA 1100 -#define GFS2_FORMAT_ED 1200 +#define GFS2_FORMAT_EA 1600 +#define GFS2_FORMAT_ED 1700 #define GFS2_FORMAT_UT 1300 #define GFS2_FORMAT_QC 1400 /* These are format numbers for entities contained in files */ -#define GFS2_FORMAT_RI 1500 -#define GFS2_FORMAT_DE 1600 -#define GFS2_FORMAT_QU 1700 +#define GFS2_FORMAT_RI 1100 +#define GFS2_FORMAT_DE 1200 +#define GFS2_FORMAT_QU 1500 /* These are part of the superblock */ #define GFS2_FORMAT_FS 1801 #define GFS2_FORMAT_MULTI 1900 @@ -74,9 +74,9 @@ struct gfs2_inum { #define GFS2_METATYPE_JD 7 #define GFS2_METATYPE_LH 8 #define GFS2_METATYPE_LD 9 -#define GFS2_METATYPE_LB 10 -#define GFS2_METATYPE_EA 11 -#define GFS2_METATYPE_ED 12 +#define GFS2_METATYPE_LB 12 +#define GFS2_METATYPE_EA 10 +#define GFS2_METATYPE_ED 11 #define GFS2_METATYPE_UT 13 #define GFS2_METATYPE_QC 14 @@ -181,6 +181,7 @@ struct gfs2_quota { __be64 qu_limit; __be64 qu_warn; __be64 qu_value; + __u8 qu_reserved[64]; }; /* @@ -260,11 +261,10 @@ struct gfs2_dinode { struct gfs2_dirent { struct gfs2_inum de_inum; __be32 de_hash; - __be32 de_rec_len; - __u8 de_name_len; - __u8 de_type; - __u16 __pad1; - __u32 __pad2; + __be16 de_rec_len; + __be16 de_name_len; + __be16 de_type; + __u8 __pad[14]; }; /* @@ -279,7 +279,7 @@ struct gfs2_leaf { __be32 lf_dirent_format; /* Format of the dirents */ __be64 lf_next; /* Next leaf, if overflow */ - __u8 lf_reserved[32]; + __u8 lf_reserved[64]; }; /* -- cgit v1.2.3 From 3bcd3687f895f178fa8480a7bcc47a363817354a Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 23 Feb 2006 09:56:38 +0000 Subject: [DLM] Remove range locks from the DLM This patch removes support for range locking from the DLM Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/debug_fs.c | 14 ------ fs/dlm/device.c | 6 +-- fs/dlm/dlm_internal.h | 12 ------ fs/dlm/lock.c | 103 ++++----------------------------------------- fs/dlm/memory.c | 16 ------- fs/dlm/memory.h | 2 - fs/dlm/rcom.c | 3 -- fs/dlm/util.c | 12 ------ include/linux/dlm.h | 12 +----- include/linux/dlm_device.h | 3 +- 10 files changed, 13 insertions(+), 170 deletions(-) (limited to 'include/linux') diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 5080bbffd586..49deca845dba 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -59,20 +59,6 @@ static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, || lkb->lkb_status == DLM_LKSTS_WAITING) seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode)); - if (lkb->lkb_range) { - /* FIXME: this warns on Alpha */ - if (lkb->lkb_status == DLM_LKSTS_CONVERT - || lkb->lkb_status == DLM_LKSTS_GRANTED) - seq_printf(s, " %llx-%llx", - lkb->lkb_range[GR_RANGE_START], - lkb->lkb_range[GR_RANGE_END]); - if (lkb->lkb_status == DLM_LKSTS_CONVERT - || lkb->lkb_status == DLM_LKSTS_WAITING) - seq_printf(s, " (%llx-%llx)", - lkb->lkb_range[RQ_RANGE_START], - lkb->lkb_range[RQ_RANGE_END]); - } - if (lkb->lkb_nodeid) { if (lkb->lkb_nodeid != res->res_nodeid) seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid, diff --git a/fs/dlm/device.c b/fs/dlm/device.c index 899d4f92a4d7..99d8b6b07fba 100644 --- a/fs/dlm/device.c +++ b/fs/dlm/device.c @@ -532,8 +532,7 @@ static int dlm_close(struct inode *inode, struct file *file) status = dlm_lock(f->fi_ls->ls_lockspace, old_li->li_grmode, &li.li_lksb, DLM_LKF_CONVERT|DLM_LKF_ORPHAN, - NULL, 0, 0, ast_routine, NULL, - NULL, NULL); + NULL, 0, 0, ast_routine, NULL, NULL); if (status != 0) printk("dlm: Error orphaning lock %x: %d\n", old_li->li_lksb.sb_lkid, status); @@ -878,8 +877,7 @@ static int do_user_lock(struct file_info *fi, uint8_t cmd, ast_routine, li, (li->li_pend_bastaddr || li->li_bastaddr) ? - bast_routine : NULL, - kparams->range.ra_end ? &kparams->range : NULL); + bast_routine : NULL); if (status) goto out_err; diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 16f20cfd9197..c3299020c8f3 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -146,7 +146,6 @@ struct dlm_args { void *bastaddr; int mode; struct dlm_lksb *lksb; - struct dlm_range *range; }; @@ -195,13 +194,6 @@ struct dlm_args { #define AST_COMP 1 #define AST_BAST 2 -/* lkb_range[] */ - -#define GR_RANGE_START 0 -#define GR_RANGE_END 1 -#define RQ_RANGE_START 2 -#define RQ_RANGE_END 3 - /* lkb_status */ #define DLM_LKSTS_WAITING 1 @@ -212,7 +204,6 @@ struct dlm_args { #define DLM_IFL_MSTCPY 0x00010000 #define DLM_IFL_RESEND 0x00020000 -#define DLM_IFL_RANGE 0x00000001 struct dlm_lkb { struct dlm_rsb *lkb_resource; /* the rsb */ @@ -241,7 +232,6 @@ struct dlm_lkb { struct list_head lkb_wait_reply; /* waiting for remote reply */ struct list_head lkb_astqueue; /* need ast to be sent */ - uint64_t *lkb_range; /* array of gr/rq ranges */ char *lkb_lvbptr; struct dlm_lksb *lkb_lksb; /* caller's status block */ void *lkb_astaddr; /* caller's ast function */ @@ -360,7 +350,6 @@ struct dlm_message { int m_bastmode; int m_asts; int m_result; /* 0 or -EXXX */ - uint64_t m_range[2]; char m_extra[0]; /* name or lvb */ }; @@ -413,7 +402,6 @@ struct rcom_lock { int8_t rl_asts; uint16_t rl_wait_type; uint16_t rl_namelen; - uint64_t rl_range[4]; char rl_name[DLM_RESNAME_MAXLEN]; char rl_lvb[0]; }; diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 29d3b95dbb63..80487703d582 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -606,8 +606,6 @@ static int put_lkb(struct dlm_lkb *lkb) /* for local/process lkbs, lvbptr points to caller's lksb */ if (lkb->lkb_lvbptr && is_master_copy(lkb)) free_lvb(lkb->lkb_lvbptr); - if (lkb->lkb_range) - free_range(lkb->lkb_range); free_lkb(lkb); return 1; } else { @@ -988,11 +986,6 @@ static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) } lkb->lkb_rqmode = DLM_LOCK_IV; - - if (lkb->lkb_range) { - lkb->lkb_range[GR_RANGE_START] = lkb->lkb_range[RQ_RANGE_START]; - lkb->lkb_range[GR_RANGE_END] = lkb->lkb_range[RQ_RANGE_END]; - } } static void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) @@ -1032,21 +1025,6 @@ static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head) return 0; } -/* Return 1 if the locks' ranges overlap. If the lkb has no range then it is - assumed to cover 0-ffffffff.ffffffff */ - -static inline int ranges_overlap(struct dlm_lkb *lkb1, struct dlm_lkb *lkb2) -{ - if (!lkb1->lkb_range || !lkb2->lkb_range) - return 1; - - if (lkb1->lkb_range[RQ_RANGE_END] < lkb2->lkb_range[GR_RANGE_START] || - lkb1->lkb_range[RQ_RANGE_START] > lkb2->lkb_range[GR_RANGE_END]) - return 0; - - return 1; -} - /* Check if the given lkb conflicts with another lkb on the queue. */ static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb) @@ -1056,7 +1034,7 @@ static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb) list_for_each_entry(this, head, lkb_statequeue) { if (this == lkb) continue; - if (ranges_overlap(lkb, this) && !modes_compat(this, lkb)) + if (!modes_compat(this, lkb)) return 1; } return 0; @@ -1099,9 +1077,6 @@ static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb) continue; } - if (!ranges_overlap(lkb, this)) - continue; - if (!modes_compat(this, lkb) && !modes_compat(lkb, this)) return 1; } @@ -1203,8 +1178,8 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now) return 1; /* - * When using range locks the NOORDER flag is set to avoid the standard - * vms rules on grant order. + * The NOORDER flag is set to avoid the standard vms rules on grant + * order. */ if (lkb->lkb_exflags & DLM_LKF_NOORDER) @@ -1358,8 +1333,7 @@ static void grant_pending_locks(struct dlm_rsb *r) /* * If there are locks left on the wait/convert queue then send blocking * ASTs to granted locks based on the largest requested mode (high) - * found above. This can generate spurious blocking ASTs for range - * locks. FIXME: highbast < high comparison not valid for PR/CW. + * found above. FIXME: highbast < high comparison not valid for PR/CW. */ list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) { @@ -1379,7 +1353,7 @@ static void send_bast_queue(struct dlm_rsb *r, struct list_head *head, list_for_each_entry(gr, head, lkb_statequeue) { if (gr->lkb_bastaddr && gr->lkb_highbast < lkb->lkb_rqmode && - ranges_overlap(lkb, gr) && !modes_compat(gr, lkb)) { + !modes_compat(gr, lkb)) { queue_bast(r, gr, lkb->lkb_rqmode); gr->lkb_highbast = lkb->lkb_rqmode; } @@ -1530,8 +1504,7 @@ static void confirm_master(struct dlm_rsb *r, int error) static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags, int namelen, uint32_t parent_lkid, void *ast, - void *astarg, void *bast, struct dlm_range *range, - struct dlm_args *args) + void *astarg, void *bast, struct dlm_args *args) { int rv = -EINVAL; @@ -1590,7 +1563,6 @@ static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags, args->bastaddr = bast; args->mode = mode; args->lksb = lksb; - args->range = range; rv = 0; out: return rv; @@ -1637,26 +1609,6 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, lkb->lkb_lksb = args->lksb; lkb->lkb_lvbptr = args->lksb->sb_lvbptr; lkb->lkb_ownpid = (int) current->pid; - - rv = 0; - if (!args->range) - goto out; - - if (!lkb->lkb_range) { - rv = -ENOMEM; - lkb->lkb_range = allocate_range(ls); - if (!lkb->lkb_range) - goto out; - /* This is needed for conversions that contain ranges - where the original lock didn't but it's harmless for - new locks too. */ - lkb->lkb_range[GR_RANGE_START] = 0LL; - lkb->lkb_range[GR_RANGE_END] = 0xffffffffffffffffULL; - } - - lkb->lkb_range[RQ_RANGE_START] = args->range->ra_start; - lkb->lkb_range[RQ_RANGE_END] = args->range->ra_end; - lkb->lkb_flags |= DLM_IFL_RANGE; rv = 0; out: return rv; @@ -1805,7 +1757,7 @@ static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) return error; } -/* change some property of an existing lkb, e.g. mode, range */ +/* change some property of an existing lkb, e.g. mode */ static int _convert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) { @@ -1962,8 +1914,7 @@ int dlm_lock(dlm_lockspace_t *lockspace, uint32_t parent_lkid, void (*ast) (void *astarg), void *astarg, - void (*bast) (void *astarg, int mode), - struct dlm_range *range) + void (*bast) (void *astarg, int mode)) { struct dlm_ls *ls; struct dlm_lkb *lkb; @@ -1985,7 +1936,7 @@ int dlm_lock(dlm_lockspace_t *lockspace, goto out; error = set_lock_args(mode, lksb, flags, namelen, parent_lkid, ast, - astarg, bast, range, &args); + astarg, bast, &args); if (error) goto out_put; @@ -2154,11 +2105,6 @@ static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb, if (lkb->lkb_astaddr) ms->m_asts |= AST_COMP; - if (lkb->lkb_range) { - ms->m_range[0] = lkb->lkb_range[RQ_RANGE_START]; - ms->m_range[1] = lkb->lkb_range[RQ_RANGE_END]; - } - if (ms->m_type == DLM_MSG_REQUEST || ms->m_type == DLM_MSG_LOOKUP) memcpy(ms->m_extra, r->res_name, r->res_length); @@ -2402,20 +2348,6 @@ static int receive_extralen(struct dlm_message *ms) return (ms->m_header.h_length - sizeof(struct dlm_message)); } -static int receive_range(struct dlm_ls *ls, struct dlm_lkb *lkb, - struct dlm_message *ms) -{ - if (lkb->lkb_flags & DLM_IFL_RANGE) { - if (!lkb->lkb_range) - lkb->lkb_range = allocate_range(ls); - if (!lkb->lkb_range) - return -ENOMEM; - lkb->lkb_range[RQ_RANGE_START] = ms->m_range[0]; - lkb->lkb_range[RQ_RANGE_END] = ms->m_range[1]; - } - return 0; -} - static int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb, struct dlm_message *ms) { @@ -2445,9 +2377,6 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb, DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb);); - if (receive_range(ls, lkb, ms)) - return -ENOMEM; - if (receive_lvb(ls, lkb, ms)) return -ENOMEM; @@ -2470,13 +2399,6 @@ static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb, if (lkb->lkb_status != DLM_LKSTS_GRANTED) return -EBUSY; - if (receive_range(ls, lkb, ms)) - return -ENOMEM; - if (lkb->lkb_range) { - lkb->lkb_range[GR_RANGE_START] = 0LL; - lkb->lkb_range[GR_RANGE_END] = 0xffffffffffffffffULL; - } - if (receive_lvb(ls, lkb, ms)) return -ENOMEM; @@ -3476,13 +3398,6 @@ static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, lkb->lkb_bastaddr = (void *) (long) (rl->rl_asts & AST_BAST); lkb->lkb_astaddr = (void *) (long) (rl->rl_asts & AST_COMP); - if (lkb->lkb_flags & DLM_IFL_RANGE) { - lkb->lkb_range = allocate_range(ls); - if (!lkb->lkb_range) - return -ENOMEM; - memcpy(lkb->lkb_range, rl->rl_range, 4*sizeof(uint64_t)); - } - if (lkb->lkb_exflags & DLM_LKF_VALBLK) { lkb->lkb_lvbptr = allocate_lvb(ls); if (!lkb->lkb_lvbptr) diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c index 0b9851d0bdb2..f7cf4589fae8 100644 --- a/fs/dlm/memory.c +++ b/fs/dlm/memory.c @@ -50,22 +50,6 @@ void free_lvb(char *p) kfree(p); } -uint64_t *allocate_range(struct dlm_ls *ls) -{ - int ralen = 4*sizeof(uint64_t); - uint64_t *p; - - p = kmalloc(ralen, GFP_KERNEL); - if (p) - memset(p, 0, ralen); - return p; -} - -void free_range(uint64_t *p) -{ - kfree(p); -} - /* FIXME: have some minimal space built-in to rsb for the name and kmalloc a separate name if needed, like dentries are done */ diff --git a/fs/dlm/memory.h b/fs/dlm/memory.h index 7b235132b0b4..6ead158ccc5c 100644 --- a/fs/dlm/memory.h +++ b/fs/dlm/memory.h @@ -24,8 +24,6 @@ struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen); void free_direntry(struct dlm_direntry *de); char *allocate_lvb(struct dlm_ls *ls); void free_lvb(char *l); -uint64_t *allocate_range(struct dlm_ls *ls); -void free_range(uint64_t *l); #endif /* __MEMORY_DOT_H__ */ diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 4c5c08a8860e..55fbe313340e 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -284,9 +284,6 @@ static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb, if (lkb->lkb_astaddr) rl->rl_asts |= AST_COMP; - if (lkb->lkb_range) - memcpy(rl->rl_range, lkb->lkb_range, 4*sizeof(uint64_t)); - rl->rl_namelen = r->res_length; memcpy(rl->rl_name, r->res_name, r->res_length); diff --git a/fs/dlm/util.c b/fs/dlm/util.c index 826d122edf55..767197db9944 100644 --- a/fs/dlm/util.c +++ b/fs/dlm/util.c @@ -54,8 +54,6 @@ void dlm_message_out(struct dlm_message *ms) ms->m_bastmode = cpu_to_le32(ms->m_bastmode); ms->m_asts = cpu_to_le32(ms->m_asts); ms->m_result = cpu_to_le32(ms->m_result); - ms->m_range[0] = cpu_to_le64(ms->m_range[0]); - ms->m_range[1] = cpu_to_le64(ms->m_range[1]); } void dlm_message_in(struct dlm_message *ms) @@ -82,8 +80,6 @@ void dlm_message_in(struct dlm_message *ms) ms->m_bastmode = le32_to_cpu(ms->m_bastmode); ms->m_asts = le32_to_cpu(ms->m_asts); ms->m_result = le32_to_cpu(ms->m_result); - ms->m_range[0] = le64_to_cpu(ms->m_range[0]); - ms->m_range[1] = le64_to_cpu(ms->m_range[1]); } static void rcom_lock_out(struct rcom_lock *rl) @@ -99,10 +95,6 @@ static void rcom_lock_out(struct rcom_lock *rl) rl->rl_result = cpu_to_le32(rl->rl_result); rl->rl_wait_type = cpu_to_le16(rl->rl_wait_type); rl->rl_namelen = cpu_to_le16(rl->rl_namelen); - rl->rl_range[0] = cpu_to_le64(rl->rl_range[0]); - rl->rl_range[1] = cpu_to_le64(rl->rl_range[1]); - rl->rl_range[2] = cpu_to_le64(rl->rl_range[2]); - rl->rl_range[3] = cpu_to_le64(rl->rl_range[3]); } static void rcom_lock_in(struct rcom_lock *rl) @@ -118,10 +110,6 @@ static void rcom_lock_in(struct rcom_lock *rl) rl->rl_result = le32_to_cpu(rl->rl_result); rl->rl_wait_type = le16_to_cpu(rl->rl_wait_type); rl->rl_namelen = le16_to_cpu(rl->rl_namelen); - rl->rl_range[0] = le64_to_cpu(rl->rl_range[0]); - rl->rl_range[1] = le64_to_cpu(rl->rl_range[1]); - rl->rl_range[2] = le64_to_cpu(rl->rl_range[2]); - rl->rl_range[3] = le64_to_cpu(rl->rl_range[3]); } static void rcom_config_out(struct rcom_config *rf) diff --git a/include/linux/dlm.h b/include/linux/dlm.h index dd324ba44d80..1b1dcb9a40bb 100644 --- a/include/linux/dlm.h +++ b/include/linux/dlm.h @@ -159,15 +159,6 @@ typedef void dlm_lockspace_t; -/* - * Lock range structure - */ - -struct dlm_range { - uint64_t ra_start; - uint64_t ra_end; -}; - /* * Lock status block * @@ -277,8 +268,7 @@ int dlm_lock(dlm_lockspace_t *lockspace, uint32_t parent_lkid, void (*lockast) (void *astarg), void *astarg, - void (*bast) (void *astarg, int mode), - struct dlm_range *range); + void (*bast) (void *astarg, int mode)); /* * dlm_unlock diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h index 5e17d295544b..f8ba1981aa96 100644 --- a/include/linux/dlm_device.h +++ b/include/linux/dlm_device.h @@ -18,7 +18,7 @@ #define DLM_USER_LVB_LEN 32 /* Version of the device interface */ -#define DLM_DEVICE_VERSION_MAJOR 3 +#define DLM_DEVICE_VERSION_MAJOR 4 #define DLM_DEVICE_VERSION_MINOR 0 #define DLM_DEVICE_VERSION_PATCH 0 @@ -28,7 +28,6 @@ struct dlm_lock_params { __u16 flags; __u32 lkid; __u32 parent; - struct dlm_range range; __u8 namelen; void __user *castparam; void __user *castaddr; -- cgit v1.2.3 From 5c676f6d359b0404d53f542f02e1359583cb2895 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 27 Feb 2006 17:23:27 -0500 Subject: [GFS2] Macros removal in gfs2.h As suggested by Pekka Enberg . The DIV_RU macro is renamed DIV_ROUND_UP and and moved to kernel.h The other macros are gone from gfs2.h as (although not requested by Pekka Enberg) are a number of included header file which are now included individually. The inode number comparison function is now an inline function. The DT2IF and IF2DT may be addressed in a future patch. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 8 ++++-- fs/gfs2/bits.c | 4 +++ fs/gfs2/bmap.c | 10 +++++--- fs/gfs2/daemon.c | 4 +++ fs/gfs2/dir.c | 8 ++++-- fs/gfs2/eaops.c | 4 +++ fs/gfs2/eattr.c | 19 +++++++++----- fs/gfs2/eattr.h | 2 +- fs/gfs2/gfs2.h | 29 --------------------- fs/gfs2/glock.c | 20 +++++++++------ fs/gfs2/glops.c | 21 +++++++++------ fs/gfs2/incore.h | 8 ++++++ fs/gfs2/inode.c | 38 ++++++++++++++------------- fs/gfs2/lm.c | 5 ++++ fs/gfs2/log.c | 8 ++++-- fs/gfs2/lops.c | 56 +++++++++++++++++++++++++--------------- fs/gfs2/lvb.c | 4 +++ fs/gfs2/lvb.h | 8 ------ fs/gfs2/main.c | 4 +++ fs/gfs2/meta_io.c | 37 +++++++++++++++------------ fs/gfs2/mount.c | 4 +++ fs/gfs2/ops_address.c | 34 ++++++++++++++----------- fs/gfs2/ops_dentry.c | 8 ++++-- fs/gfs2/ops_export.c | 17 ++++++++----- fs/gfs2/ops_file.c | 40 ++++++++++++++++------------- fs/gfs2/ops_fstype.c | 35 +++++++++++++++++-------- fs/gfs2/ops_inode.c | 62 ++++++++++++++++++++++++--------------------- fs/gfs2/ops_super.c | 26 +++++++++++-------- fs/gfs2/ops_vm.c | 8 ++++-- fs/gfs2/page.c | 12 ++++++--- fs/gfs2/quota.c | 20 ++++++++++----- fs/gfs2/recovery.c | 29 +++++++++++++-------- fs/gfs2/rgrp.c | 10 +++++--- fs/gfs2/super.c | 36 ++++++++++++++++---------- fs/gfs2/sys.c | 4 +++ fs/gfs2/trans.c | 19 +++++++++----- fs/gfs2/unlinked.c | 11 +++++--- fs/gfs2/util.c | 4 +++ include/linux/gfs2_ondisk.h | 11 +++++--- include/linux/kernel.h | 1 + 40 files changed, 416 insertions(+), 272 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 9482a677ea47..e9d05fe94357 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -15,8 +15,11 @@ #include #include #include +#include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "acl.h" #include "eaops.h" #include "eattr.h" @@ -24,6 +27,7 @@ #include "inode.h" #include "meta_io.h" #include "trans.h" +#include "util.h" #define ACL_ACCESS 1 #define ACL_DEFAULT 0 @@ -157,7 +161,7 @@ int gfs2_check_acl_locked(struct inode *inode, int mask) struct posix_acl *acl = NULL; int error; - error = acl_get(get_v2ip(inode), ACL_ACCESS, &acl, NULL, NULL, NULL); + error = acl_get(inode->u.generic_ip, ACL_ACCESS, &acl, NULL, NULL, NULL); if (error) return error; @@ -172,7 +176,7 @@ int gfs2_check_acl_locked(struct inode *inode, int mask) int gfs2_check_acl(struct inode *inode, int mask) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_holder i_gh; int error; diff --git a/fs/gfs2/bits.c b/fs/gfs2/bits.c index 57d420a86adf..49585e3de095 100644 --- a/fs/gfs2/bits.c +++ b/fs/gfs2/bits.c @@ -21,10 +21,14 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bits.h" +#include "util.h" static const char valid_change[16] = { /* current */ diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index e132d8a41008..cd5e4d863ce2 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -12,9 +12,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "glock.h" #include "inode.h" @@ -24,6 +27,7 @@ #include "rgrp.h" #include "trans.h" #include "dir.h" +#include "util.h" /* This doesn't need to be that large as max 64 bit pointers in a 4k * block is 512, so __u16 is fine for that. It saves stack space to @@ -660,7 +664,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd; - rgd = get_gl2rgd(rlist.rl_ghs[x].gh_gl); + rgd = rlist.rl_ghs[x].gh_gl->gl_object; rg_blocks += rgd->rd_ri.ri_length; } @@ -1021,7 +1025,7 @@ void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len, unsigned int tmp; if (gfs2_is_dir(ip)) { - *data_blocks = DIV_RU(len, sdp->sd_jbsize) + 2; + *data_blocks = DIV_ROUND_UP(len, sdp->sd_jbsize) + 2; *ind_blocks = 3 * (sdp->sd_max_jheight - 1); } else { *data_blocks = (len >> sdp->sd_sb.sb_bsize_shift) + 3; @@ -1029,7 +1033,7 @@ void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len, } for (tmp = *data_blocks; tmp > sdp->sd_diptrs;) { - tmp = DIV_RU(tmp, sdp->sd_inptrs); + tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs); *ind_blocks += tmp; } } diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index cff8d5368d21..94317dc7e42c 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -14,9 +14,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "daemon.h" #include "glock.h" #include "log.h" @@ -24,6 +27,7 @@ #include "recovery.h" #include "super.h" #include "unlinked.h" +#include "util.h" /* This uses schedule_timeout() instead of msleep() because it's good for the daemons to wake up more often than the timeout when unmounting so diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 56683788a6cf..37f70ca558cc 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -59,9 +59,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "dir.h" #include "glock.h" #include "inode.h" @@ -70,6 +73,7 @@ #include "rgrp.h" #include "trans.h" #include "bmap.h" +#include "util.h" #define IS_LEAF 1 /* Hashed (leaf) directory */ #define IS_DINODE 2 /* Linear (stuffed dinode block) directory */ @@ -2196,7 +2200,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd; - rgd = get_gl2rgd(rlist.rl_ghs[x].gh_gl); + rgd = rlist.rl_ghs[x].gh_gl->gl_object; rg_blocks += rgd->rd_ri.ri_length; } @@ -2205,7 +2209,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, goto out_rlist; error = gfs2_trans_begin(sdp, - rg_blocks + (DIV_RU(size, sdp->sd_jbsize) + 1) + + rg_blocks + (DIV_ROUND_UP(size, sdp->sd_jbsize) + 1) + RES_DINODE + RES_STATFS + RES_QUOTA, l_blocks); if (error) goto out_rg_gunlock; diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 2914731250c5..4b9f6cff7a34 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -13,13 +13,17 @@ #include #include #include +#include #include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "acl.h" #include "eaops.h" #include "eattr.h" +#include "util.h" /** * gfs2_ea_name2type - get the type of the ea, and truncate type from the name diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 146995d9cd65..8219d471f06c 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -13,10 +13,13 @@ #include #include #include +#include #include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "acl.h" #include "eaops.h" #include "eattr.h" @@ -26,6 +29,7 @@ #include "quota.h" #include "rgrp.h" #include "trans.h" +#include "util.h" /** * ea_calc_size - returns the acutal number of bytes the request will take up @@ -478,7 +482,7 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, struct gfs2_sbd *sdp = ip->i_sbd; struct buffer_head **bh; unsigned int amount = GFS2_EA_DATA_LEN(ea); - unsigned int nptrs = DIV_RU(amount, sdp->sd_jbsize); + unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize); uint64_t *dataptrs = GFS2_EA2DATAPTRS(ea); unsigned int x; int error = 0; @@ -676,7 +680,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, unsigned int copy; unsigned int x; - ea->ea_num_ptrs = DIV_RU(er->er_data_len, sdp->sd_jbsize); + ea->ea_num_ptrs = DIV_ROUND_UP(er->er_data_len, sdp->sd_jbsize); for (x = 0; x < ea->ea_num_ptrs; x++) { struct buffer_head *bh; uint64_t block; @@ -810,7 +814,7 @@ static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er) unsigned int blks = 1; if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize) - blks += DIV_RU(er->er_data_len, jbsize); + blks += DIV_ROUND_UP(er->er_data_len, jbsize); return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL); } @@ -962,7 +966,8 @@ static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, es->es_bh = bh; es->es_ea = ea; - blks = 2 + DIV_RU(es->es_er->er_data_len, ip->i_sbd->sd_jbsize); + blks = 2 + DIV_ROUND_UP(es->es_er->er_data_len, + ip->i_sbd->sd_jbsize); error = ea_alloc_skeleton(ip, es->es_er, blks, ea_set_simple_alloc, es); @@ -1066,7 +1071,7 @@ static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT)) blks++; if (GFS2_EAREQ_SIZE_STUFFED(er) > ip->i_sbd->sd_jbsize) - blks += DIV_RU(er->er_data_len, ip->i_sbd->sd_jbsize); + blks += DIV_ROUND_UP(er->er_data_len, ip->i_sbd->sd_jbsize); return ea_alloc_skeleton(ip, er, blks, ea_set_block, el); } @@ -1250,7 +1255,7 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, struct gfs2_sbd *sdp = ip->i_sbd; struct buffer_head **bh; unsigned int amount = GFS2_EA_DATA_LEN(ea); - unsigned int nptrs = DIV_RU(amount, sdp->sd_jbsize); + unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize); uint64_t *dataptrs = GFS2_EA2DATAPTRS(ea); unsigned int x; int error; @@ -1402,7 +1407,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd; - rgd = get_gl2rgd(rlist.rl_ghs[x].gh_gl); + rgd = rlist.rl_ghs[x].gh_gl->gl_object; rg_blocks += rgd->rd_ri.ri_length; } diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h index e5a42abf68a3..2b4152b1fcbe 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/eattr.h @@ -29,7 +29,7 @@ ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8) #define GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er) \ ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \ - sizeof(uint64_t) * DIV_RU((er)->er_data_len, (sdp)->sd_jbsize), 8) + sizeof(uint64_t) * DIV_ROUND_UP((er)->er_data_len, (sdp)->sd_jbsize), 8) #define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1)) #define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len) diff --git a/fs/gfs2/gfs2.h b/fs/gfs2/gfs2.h index 6c53d080675c..57175f70e2bd 100644 --- a/fs/gfs2/gfs2.h +++ b/fs/gfs2/gfs2.h @@ -10,13 +10,6 @@ #ifndef __GFS2_DOT_H__ #define __GFS2_DOT_H__ -#include - -#include "lm_interface.h" -#include "lvb.h" -#include "incore.h" -#include "util.h" - enum { NO_CREATE = 0, CREATE = 1, @@ -32,29 +25,7 @@ enum { FORCE = 1, }; -/* Divide num by den. Round up if there is a remainder. */ -#define DIV_RU(num, den) (((num) + (den) - 1) / (den)) - #define GFS2_FAST_NAME_SIZE 8 -#define get_v2sdp(sb) ((struct gfs2_sbd *)(sb)->s_fs_info) -#define set_v2sdp(sb, sdp) (sb)->s_fs_info = (sdp) -#define get_v2ip(inode) ((struct gfs2_inode *)(inode)->u.generic_ip) -#define set_v2ip(inode, ip) (inode)->u.generic_ip = (ip) -#define get_v2fp(file) ((struct gfs2_file *)(file)->private_data) -#define set_v2fp(file, fp) (file)->private_data = (fp) -#define get_v2bd(bh) ((struct gfs2_bufdata *)(bh)->b_private) -#define set_v2bd(bh, bd) (bh)->b_private = (bd) - -#define get_transaction ((struct gfs2_trans *)(current->journal_info)) -#define set_transaction(tr) (current->journal_info) = (tr) - -#define get_gl2ip(gl) ((struct gfs2_inode *)(gl)->gl_object) -#define set_gl2ip(gl, ip) (gl)->gl_object = (ip) -#define get_gl2rgd(gl) ((struct gfs2_rgrpd *)(gl)->gl_object) -#define set_gl2rgd(gl, rgd) (gl)->gl_object = (rgd) -#define get_gl2gl(gl) ((struct gfs2_glock *)(gl)->gl_object) -#define set_gl2gl(gl, gl2) (gl)->gl_object = (gl2) - #endif /* __GFS2_DOT_H__ */ diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index f30fde91d14a..81b06812b329 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -16,10 +16,13 @@ #include #include #include +#include #include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "glock.h" #include "glops.h" #include "inode.h" @@ -28,6 +31,7 @@ #include "meta_io.h" #include "quota.h" #include "super.h" +#include "util.h" /* Must be kept in sync with the beginning of struct gfs2_glock */ struct glock_plug { @@ -1962,7 +1966,7 @@ void gfs2_try_toss_inode(struct gfs2_sbd *sdp, struct gfs2_inum *inum) if (!gfs2_glmutex_trylock(gl)) goto out; - ip = get_gl2ip(gl); + ip = gl->gl_object; if (!ip) goto out_unlock; @@ -1994,7 +1998,7 @@ void gfs2_iopen_go_callback(struct gfs2_glock *io_gl, unsigned int state) return; spin_lock(&io_gl->gl_spin); - i_gl = get_gl2gl(io_gl); + i_gl = io_gl->gl_object; if (i_gl) { gfs2_glock_hold(i_gl); spin_unlock(&io_gl->gl_spin); @@ -2004,7 +2008,7 @@ void gfs2_iopen_go_callback(struct gfs2_glock *io_gl, unsigned int state) } if (gfs2_glmutex_trylock(i_gl)) { - struct gfs2_inode *ip = get_gl2ip(i_gl); + struct gfs2_inode *ip = i_gl->gl_object; if (ip) { gfs2_try_toss_vnode(ip); gfs2_glmutex_unlock(i_gl); @@ -2093,7 +2097,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp) if (gfs2_glmutex_trylock(gl)) { if (gl->gl_ops == &gfs2_inode_glops) { - struct gfs2_inode *ip = get_gl2ip(gl); + struct gfs2_inode *ip = gl->gl_object; if (ip && !atomic_read(&ip->i_count)) gfs2_inode_destroy(ip); } @@ -2174,7 +2178,7 @@ static void scan_glock(struct gfs2_glock *gl) { if (gfs2_glmutex_trylock(gl)) { if (gl->gl_ops == &gfs2_inode_glops) { - struct gfs2_inode *ip = get_gl2ip(gl); + struct gfs2_inode *ip = gl->gl_object; if (ip && !atomic_read(&ip->i_count)) goto out_schedule; } @@ -2234,7 +2238,7 @@ static void clear_glock(struct gfs2_glock *gl) if (gfs2_glmutex_trylock(gl)) { if (gl->gl_ops == &gfs2_inode_glops) { - struct gfs2_inode *ip = get_gl2ip(gl); + struct gfs2_inode *ip = gl->gl_object; if (ip && !atomic_read(&ip->i_count)) gfs2_inode_destroy(ip); } @@ -2430,10 +2434,10 @@ static int dump_glock(struct gfs2_glock *gl) if (error) goto out; } - if (gl->gl_ops == &gfs2_inode_glops && get_gl2ip(gl)) { + if (gl->gl_ops == &gfs2_inode_glops && gl->gl_object) { if (!test_bit(GLF_LOCK, &gl->gl_flags) && list_empty(&gl->gl_holders)) { - error = dump_inode(get_gl2ip(gl)); + error = dump_inode(gl->gl_object); if (error) goto out; } else { diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 27374306ecde..d9334eb72df8 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -12,9 +12,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "glock.h" #include "glops.h" @@ -24,6 +27,7 @@ #include "page.h" #include "recovery.h" #include "rgrp.h" +#include "util.h" /** * meta_go_sync - sync out the metadata for this glock @@ -193,7 +197,7 @@ static int inode_go_demote_ok(struct gfs2_glock *gl) struct gfs2_sbd *sdp = gl->gl_sbd; int demote = 0; - if (!get_gl2ip(gl) && !gl->gl_aspace->i_mapping->nrpages) + if (!gl->gl_object && !gl->gl_aspace->i_mapping->nrpages) demote = 1; else if (!sdp->sd_args.ar_localcaching && time_after_eq(jiffies, gl->gl_stamp + @@ -214,7 +218,7 @@ static int inode_go_demote_ok(struct gfs2_glock *gl) static int inode_go_lock(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_inode *ip = get_gl2ip(gl); + struct gfs2_inode *ip = gl->gl_object; int error = 0; if (!ip) @@ -246,7 +250,7 @@ static int inode_go_lock(struct gfs2_holder *gh) static void inode_go_unlock(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_inode *ip = get_gl2ip(gl); + struct gfs2_inode *ip = gl->gl_object; if (ip && test_bit(GLF_DIRTY, &gl->gl_flags)) gfs2_inode_attr_in(ip); @@ -264,7 +268,7 @@ static void inode_go_unlock(struct gfs2_holder *gh) static void inode_greedy(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_sbd; - struct gfs2_inode *ip = get_gl2ip(gl); + struct gfs2_inode *ip = gl->gl_object; unsigned int quantum = gfs2_tune_get(sdp, gt_greedy_quantum); unsigned int max = gfs2_tune_get(sdp, gt_greedy_max); unsigned int new_time; @@ -311,7 +315,7 @@ static int rgrp_go_demote_ok(struct gfs2_glock *gl) static int rgrp_go_lock(struct gfs2_holder *gh) { - return gfs2_rgrp_bh_get(get_gl2rgd(gh->gh_gl)); + return gfs2_rgrp_bh_get(gh->gh_gl->gl_object); } /** @@ -324,7 +328,7 @@ static int rgrp_go_lock(struct gfs2_holder *gh) static void rgrp_go_unlock(struct gfs2_holder *gh) { - gfs2_rgrp_bh_put(get_gl2rgd(gh->gh_gl)); + gfs2_rgrp_bh_put(gh->gh_gl->gl_object); } /** @@ -358,13 +362,14 @@ static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state, static void trans_go_xmote_bh(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_sbd; - struct gfs2_glock *j_gl = get_v2ip(sdp->sd_jdesc->jd_inode)->i_gl; + struct gfs2_inode *ip = sdp->sd_jdesc->jd_inode->u.generic_ip; + struct gfs2_glock *j_gl = ip->i_gl; struct gfs2_log_header head; int error; if (gl->gl_state != LM_ST_UNLOCKED && test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { - gfs2_meta_cache_flush(get_v2ip(sdp->sd_jdesc->jd_inode)); + gfs2_meta_cache_flush(sdp->sd_jdesc->jd_inode->u.generic_ip); j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA); error = gfs2_find_jhead(sdp->sd_jdesc, &head); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 0e550e8e5be3..2443e9aad598 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -313,6 +313,14 @@ enum { QDF_LOCKED = 2, }; +struct gfs2_quota_lvb { + uint32_t qb_magic; + uint32_t __pad; + uint64_t qb_limit; /* Hard limit of # blocks to alloc */ + uint64_t qb_warn; /* Warn user when alloc is above this # */ + int64_t qb_value; /* Current # blocks allocated */ +}; + struct gfs2_quota_data { struct list_head qd_list; unsigned int qd_count; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 51ecdb8503b0..ea9e996f3673 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -14,9 +14,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "acl.h" #include "bmap.h" #include "dir.h" @@ -33,6 +36,7 @@ #include "rgrp.h" #include "trans.h" #include "unlinked.h" +#include "util.h" /** * inode_attr_in - Copy attributes from the dinode into the VFS inode @@ -176,7 +180,7 @@ struct inode *gfs2_ip2v(struct gfs2_inode *ip) init_special_inode(tmp, tmp->i_mode, tmp->i_rdev); } - set_v2ip(tmp, NULL); + tmp->u.generic_ip = NULL; for (;;) { spin_lock(&ip->i_spin); @@ -196,7 +200,7 @@ struct inode *gfs2_ip2v(struct gfs2_inode *ip) gfs2_inode_hold(ip); ip->i_vnode = inode; - set_v2ip(inode, ip); + inode->u.generic_ip = ip; spin_unlock(&ip->i_spin); @@ -207,7 +211,7 @@ struct inode *gfs2_ip2v(struct gfs2_inode *ip) static int iget_test(struct inode *inode, void *opaque) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_inum *inum = (struct gfs2_inum *)opaque; if (ip && ip->i_num.no_addr == inum->no_addr) @@ -320,11 +324,11 @@ static int inode_create(struct gfs2_glock *i_gl, struct gfs2_inum *inum, spin_lock(&io_gl->gl_spin); gfs2_glock_hold(i_gl); - set_gl2gl(io_gl, i_gl); + io_gl->gl_object = i_gl; spin_unlock(&io_gl->gl_spin); gfs2_glock_hold(i_gl); - set_gl2ip(i_gl, ip); + i_gl->gl_object = ip; atomic_inc(&sdp->sd_inode_count); @@ -359,7 +363,7 @@ int gfs2_inode_get(struct gfs2_glock *i_gl, struct gfs2_inum *inum, int create, gfs2_glmutex_lock(i_gl); - *ipp = get_gl2ip(i_gl); + *ipp = i_gl->gl_object; if (*ipp) { error = -ESTALE; if ((*ipp)->i_num.no_formal_ino != inum->no_formal_ino) @@ -404,10 +408,10 @@ void gfs2_inode_destroy(struct gfs2_inode *ip) struct gfs2_glock *i_gl = ip->i_gl; gfs2_assert_warn(sdp, !atomic_read(&ip->i_count)); - gfs2_assert(sdp, get_gl2gl(io_gl) == i_gl); + gfs2_assert(sdp, io_gl->gl_object == i_gl); spin_lock(&io_gl->gl_spin); - set_gl2gl(io_gl, NULL); + io_gl->gl_object = NULL; gfs2_glock_put(i_gl); spin_unlock(&io_gl->gl_spin); @@ -416,7 +420,7 @@ void gfs2_inode_destroy(struct gfs2_inode *ip) gfs2_meta_cache_flush(ip); kmem_cache_free(gfs2_inode_cachep, ip); - set_gl2ip(i_gl, NULL); + i_gl->gl_object = NULL; gfs2_glock_put(i_gl); atomic_dec(&sdp->sd_inode_count); @@ -524,7 +528,7 @@ static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul, goto out; } - gfs2_assert_warn(sdp, !get_gl2ip(i_gh.gh_gl)); + gfs2_assert_warn(sdp, !i_gh.gh_gl->gl_object); error = inode_create(i_gh.gh_gl, &ul->ul_ut.ut_inum, io_gh->gh_gl, LM_ST_EXCLUSIVE, &ip); @@ -715,7 +719,7 @@ int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, struct inode **inodep) { struct gfs2_inode *ipp; - struct gfs2_inode *dip = get_v2ip(dir); + struct gfs2_inode *dip = dir->u.generic_ip; struct gfs2_sbd *sdp = dip->i_sbd; struct gfs2_holder d_gh; struct gfs2_inum inum; @@ -774,7 +778,7 @@ done: static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) { - struct gfs2_inode *ip = get_v2ip(sdp->sd_ir_inode); + struct gfs2_inode *ip = sdp->sd_ir_inode->u.generic_ip; struct buffer_head *bh; struct gfs2_inum_range ir; int error; @@ -815,8 +819,8 @@ static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) { - struct gfs2_inode *ip = get_v2ip(sdp->sd_ir_inode); - struct gfs2_inode *m_ip = get_v2ip(sdp->sd_inum_inode); + struct gfs2_inode *ip = sdp->sd_ir_inode->u.generic_ip; + struct gfs2_inode *m_ip = sdp->sd_inum_inode->u.generic_ip; struct gfs2_holder gh; struct buffer_head *bh; struct gfs2_inum_range ir; @@ -1194,7 +1198,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode) { struct inode *inode; - struct gfs2_inode *dip = get_gl2ip(ghs->gh_gl); + struct gfs2_inode *dip = ghs->gh_gl->gl_object; struct gfs2_sbd *sdp = dip->i_sbd; struct gfs2_unlinked *ul; struct gfs2_inode *ip; @@ -1570,7 +1574,7 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; struct gfs2_sbd *sdp = gl->gl_sbd; - struct gfs2_inode *ip = get_gl2ip(gl); + struct gfs2_inode *ip = gl->gl_object; int64_t curtime, quantum = gfs2_tune_get(sdp, gt_atime_quantum); unsigned int state; int flags; @@ -1817,7 +1821,7 @@ int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) { int error; - if (get_transaction) + if (current->journal_info) return __gfs2_setattr_simple(ip, attr); error = gfs2_trans_begin(ip->i_sbd, RES_DINODE, 0); diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index 3df8fa00442d..5b3c56d2df2f 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -13,12 +13,17 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "glock.h" #include "lm.h" #include "super.h" +#include "util.h" +#include "lvb.h" /** * gfs2_lm_mount - mount a locking protocol diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 0e31d46edd4d..32a41a274bf8 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -12,14 +12,18 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "glock.h" #include "log.h" #include "lops.h" #include "meta_io.h" +#include "util.h" #define PULL 1 @@ -80,7 +84,7 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, if (nstruct > first) { second = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header)) / ssize; - blks += DIV_RU(nstruct - first, second); + blks += DIV_ROUND_UP(nstruct - first, second); } return blks; @@ -257,7 +261,7 @@ static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) uint64_t dbn; int error; - error = gfs2_block_map(get_v2ip(sdp->sd_jdesc->jd_inode), + error = gfs2_block_map(sdp->sd_jdesc->jd_inode->u.generic_ip, lbn, &new, &dbn, NULL); gfs2_assert_withdraw(sdp, !error && dbn); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 4bd89c0781e7..430161a05a21 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -12,9 +12,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "glock.h" #include "log.h" #include "lops.h" @@ -22,12 +25,14 @@ #include "recovery.h" #include "rgrp.h" #include "trans.h" +#include "util.h" static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { struct gfs2_glock *gl; + struct gfs2_trans *tr = current->journal_info; - get_transaction->tr_touched = 1; + tr->tr_touched = 1; if (!list_empty(&le->le_list)) return; @@ -68,7 +73,7 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) if (!list_empty(&bd->bd_list_tr)) return; - tr = get_transaction; + tr = current->journal_info; tr->tr_touched = 1; tr->tr_num_buf++; list_add(&bd->bd_list_tr, &tr->tr_list_buf); @@ -179,7 +184,8 @@ static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) static void buf_lo_before_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head, int pass) { - struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; if (pass != 0) return; @@ -192,8 +198,9 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, struct gfs2_log_descriptor *ld, __be64 *ptr, int pass) { - struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; - struct gfs2_glock *gl = get_v2ip(jd->jd_inode)->i_gl; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_glock *gl = ip->i_gl; unsigned int blks = be32_to_cpu(ld->ld_data1); struct buffer_head *bh_log, *bh_ip; uint64_t blkno; @@ -238,17 +245,18 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) { - struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; if (error) { - gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, + gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); return; } if (pass != 1) return; - gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n", jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); @@ -258,7 +266,7 @@ static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { struct gfs2_trans *tr; - tr = get_transaction; + tr = current->journal_info; tr->tr_touched = 1; tr->tr_num_revoke++; @@ -324,7 +332,8 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) static void revoke_lo_before_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head, int pass) { - struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; if (pass != 0) return; @@ -337,7 +346,8 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, struct gfs2_log_descriptor *ld, __be64 *ptr, int pass) { - struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; unsigned int blks = be32_to_cpu(ld->ld_length); unsigned int revokes = be32_to_cpu(ld->ld_data1); struct buffer_head *bh; @@ -383,7 +393,8 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) { - struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; if (error) { gfs2_revoke_clean(sdp); @@ -401,8 +412,9 @@ static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { struct gfs2_rgrpd *rgd; + struct gfs2_trans *tr = current->journal_info; - get_transaction->tr_touched = 1; + tr->tr_touched = 1; if (!list_empty(&le->le_list)) return; @@ -451,9 +463,9 @@ static void rg_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); - struct gfs2_trans *tr = get_transaction; + struct gfs2_trans *tr = current->journal_info; struct address_space *mapping = bd->bd_bh->b_page->mapping; - struct gfs2_inode *ip = get_v2ip(mapping->host); + struct gfs2_inode *ip = mapping->host->u.generic_ip; tr->tr_touched = 1; if (!list_empty(&bd->bd_list_tr) && @@ -633,7 +645,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) bh = bd1->bd_bh; if (bh) { - set_v2bd(bh, NULL); + bh->b_private = NULL; gfs2_log_unlock(sdp); wait_on_buffer(bh); brelse(bh); @@ -651,8 +663,9 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, struct gfs2_log_descriptor *ld, __be64 *ptr, int pass) { - struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; - struct gfs2_glock *gl = get_v2ip(jd->jd_inode)->i_gl; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_glock *gl = ip->i_gl; unsigned int blks = be32_to_cpu(ld->ld_data1); struct buffer_head *bh_log, *bh_ip; uint64_t blkno; @@ -701,10 +714,11 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) { - struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; if (error) { - gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, + gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); return; } @@ -712,7 +726,7 @@ static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) return; /* data sync? */ - gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, DIO_START | DIO_WAIT); + gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT); fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n", jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); diff --git a/fs/gfs2/lvb.c b/fs/gfs2/lvb.c index ca959ebb80c1..63b815dad8e7 100644 --- a/fs/gfs2/lvb.c +++ b/fs/gfs2/lvb.c @@ -12,9 +12,13 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" +#include "lvb.h" #define pv(struct, member, fmt) printk(KERN_INFO " "#member" = "fmt"\n", \ struct->member); diff --git a/fs/gfs2/lvb.h b/fs/gfs2/lvb.h index ca9732b2d9f4..1b9eb69b9534 100644 --- a/fs/gfs2/lvb.h +++ b/fs/gfs2/lvb.h @@ -12,14 +12,6 @@ #define GFS2_MIN_LVB_SIZE 32 -struct gfs2_quota_lvb { - uint32_t qb_magic; - uint32_t __pad; - uint64_t qb_limit; /* Hard limit of # blocks to alloc */ - uint64_t qb_warn; /* Warn user when alloc is above this # */ - int64_t qb_value; /* Current # blocks allocated */ -}; - void gfs2_quota_lvb_in(struct gfs2_quota_lvb *qb, char *lvb); void gfs2_quota_lvb_out(struct gfs2_quota_lvb *qb, char *lvb); void gfs2_quota_lvb_print(struct gfs2_quota_lvb *qb); diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 0c60f2b10fdd..c54177790318 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -14,11 +14,15 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "ops_fstype.h" #include "sys.h" +#include "util.h" /** * init_gfs2_fs - Register GFS2 as a filesystem diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 53f33fa899f9..b85fa2464666 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -17,9 +17,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "glock.h" #include "glops.h" #include "inode.h" @@ -28,6 +31,7 @@ #include "meta_io.h" #include "rgrp.h" #include "trans.h" +#include "util.h" #define buffer_busy(bh) \ ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned))) @@ -37,7 +41,7 @@ static int aspace_get_block(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - gfs2_assert_warn(get_v2sdp(inode->i_sb), 0); + gfs2_assert_warn(inode->i_sb->s_fs_info, 0); return -EOPNOTSUPP; } @@ -55,15 +59,15 @@ static int gfs2_aspace_writepage(struct page *page, static void stuck_releasepage(struct buffer_head *bh) { - struct gfs2_sbd *sdp = get_v2sdp(bh->b_page->mapping->host->i_sb); - struct gfs2_bufdata *bd = get_v2bd(bh); + struct gfs2_sbd *sdp = bh->b_page->mapping->host->i_sb->s_fs_info; + struct gfs2_bufdata *bd = bh->b_private; struct gfs2_glock *gl; fs_warn(sdp, "stuck in gfs2_releasepage()\n"); fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", (uint64_t)bh->b_blocknr, atomic_read(&bh->b_count)); fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); - fs_warn(sdp, "get_v2bd(bh) = %s\n", (bd) ? "!NULL" : "NULL"); + fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL"); if (!bd) return; @@ -78,7 +82,7 @@ static void stuck_releasepage(struct buffer_head *bh) (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); if (gl->gl_ops == &gfs2_inode_glops) { - struct gfs2_inode *ip = get_gl2ip(gl); + struct gfs2_inode *ip = gl->gl_object; unsigned int x; if (!ip) @@ -110,7 +114,7 @@ static void stuck_releasepage(struct buffer_head *bh) static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask) { struct inode *aspace = page->mapping->host; - struct gfs2_sbd *sdp = get_v2sdp(aspace->i_sb); + struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; struct buffer_head *bh, *head; struct gfs2_bufdata *bd; unsigned long t; @@ -139,14 +143,14 @@ static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask) gfs2_assert_warn(sdp, !buffer_pinned(bh)); - bd = get_v2bd(bh); + bd = bh->b_private; if (bd) { gfs2_assert_warn(sdp, bd->bd_bh == bh); gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); gfs2_assert_warn(sdp, !bd->bd_ail); kmem_cache_free(gfs2_bufdata_cachep, bd); - set_v2bd(bh, NULL); + bh->b_private = NULL; } bh = bh->b_this_page; @@ -184,7 +188,7 @@ struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp) mapping_set_gfp_mask(aspace->i_mapping, GFP_KERNEL); aspace->i_mapping->a_ops = &aspace_aops; aspace->i_size = ~0ULL; - set_v2ip(aspace, NULL); + aspace->u.generic_ip = NULL; insert_inode_hash(aspace); } @@ -523,7 +527,7 @@ int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags) wait_on_buffer(bh); if (!buffer_uptodate(bh)) { - struct gfs2_trans *tr = get_transaction; + struct gfs2_trans *tr = current->journal_info; if (tr && tr->tr_touched) gfs2_io_error_bh(sdp, bh); return -EIO; @@ -550,7 +554,7 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, if (meta) lock_page(bh->b_page); - if (get_v2bd(bh)) { + if (bh->b_private) { if (meta) unlock_page(bh->b_page); return; @@ -569,7 +573,7 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, lops_init_le(&bd->bd_le, &gfs2_databuf_lops); get_bh(bh); } - set_v2bd(bh, bd); + bh->b_private = bd; if (meta) unlock_page(bh->b_page); @@ -584,7 +588,7 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) { - struct gfs2_bufdata *bd = get_v2bd(bh); + struct gfs2_bufdata *bd = bh->b_private; gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); @@ -621,7 +625,7 @@ void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, struct gfs2_ail *ai) { - struct gfs2_bufdata *bd = get_v2bd(bh); + struct gfs2_bufdata *bd = bh->b_private; gfs2_assert_withdraw(sdp, buffer_uptodate(bh)); @@ -662,15 +666,16 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) while (blen) { bh = getbuf(sdp, aspace, bstart, NO_CREATE); if (bh) { - struct gfs2_bufdata *bd = get_v2bd(bh); + struct gfs2_bufdata *bd = bh->b_private; if (test_clear_buffer_pinned(bh)) { + struct gfs2_trans *tr = current->journal_info; gfs2_log_lock(sdp); list_del_init(&bd->bd_le.le_list); gfs2_assert_warn(sdp, sdp->sd_log_num_buf); sdp->sd_log_num_buf--; gfs2_log_unlock(sdp); - get_transaction->tr_num_buf_rm++; + tr->tr_num_buf_rm++; brelse(bh); } if (bd) { diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index 3e42697aafc7..e90ea7d32f9e 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -12,11 +12,15 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "mount.h" #include "sys.h" +#include "util.h" /** * gfs2_mount_args - Parse mount options diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 89a8b8fad2e7..01aa4a9b48c3 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -15,9 +15,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "glock.h" #include "inode.h" @@ -29,6 +32,7 @@ #include "trans.h" #include "rgrp.h" #include "ops_file.h" +#include "util.h" /** * gfs2_get_block - Fills in a buffer head with details about a block @@ -43,7 +47,7 @@ int gfs2_get_block(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; int new = create; uint64_t dblock; int error; @@ -75,7 +79,7 @@ int gfs2_get_block(struct inode *inode, sector_t lblock, static int get_block_noalloc(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; int new = 0; uint64_t dblock; int error; @@ -96,7 +100,7 @@ static int get_blocks(struct inode *inode, sector_t lblock, unsigned long max_blocks, struct buffer_head *bh_result, int create) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; int new = create; uint64_t dblock; uint32_t extlen; @@ -124,7 +128,7 @@ static int get_blocks_noalloc(struct inode *inode, sector_t lblock, unsigned long max_blocks, struct buffer_head *bh_result, int create) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; int new = 0; uint64_t dblock; uint32_t extlen; @@ -158,7 +162,7 @@ static int get_blocks_noalloc(struct inode *inode, sector_t lblock, static int gfs2_writepage(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; - struct gfs2_inode *ip = get_v2ip(page->mapping->host); + struct gfs2_inode *ip = page->mapping->host->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; loff_t i_size = i_size_read(inode); pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; @@ -170,7 +174,7 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) unlock_page(page); return -EIO; } - if (get_transaction) + if (current->journal_info) goto out_ignore; /* Is the page fully outside i_size? (truncate in progress) */ @@ -259,7 +263,7 @@ static int zero_readpage(struct page *page) static int gfs2_readpage(struct file *file, struct page *page) { - struct gfs2_inode *ip = get_v2ip(page->mapping->host); + struct gfs2_inode *ip = page->mapping->host->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; struct gfs2_holder gh; int error; @@ -307,7 +311,7 @@ out_unlock: static int gfs2_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { - struct gfs2_inode *ip = get_v2ip(page->mapping->host); + struct gfs2_inode *ip = page->mapping->host->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; unsigned int data_blocks, ind_blocks, rblocks; int alloc_required; @@ -402,7 +406,7 @@ static int gfs2_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { struct inode *inode = page->mapping->host; - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; int error = -EOPNOTSUPP; struct buffer_head *dibh; @@ -482,7 +486,7 @@ fail_nounlock: static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) { - struct gfs2_inode *ip = get_v2ip(mapping->host); + struct gfs2_inode *ip = mapping->host->u.generic_ip; struct gfs2_holder i_gh; sector_t dblock = 0; int error; @@ -504,10 +508,10 @@ static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh) struct gfs2_bufdata *bd; gfs2_log_lock(sdp); - bd = get_v2bd(bh); + bd = bh->b_private; if (bd) { bd->bd_bh = NULL; - set_v2bd(bh, NULL); + bh->b_private = NULL; gfs2_log_unlock(sdp); brelse(bh); } else @@ -525,7 +529,7 @@ static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh) static int gfs2_invalidatepage(struct page *page, unsigned long offset) { - struct gfs2_sbd *sdp = get_v2sdp(page->mapping->host->i_sb); + struct gfs2_sbd *sdp = page->mapping->host->i_sb->s_fs_info; struct buffer_head *head, *bh, *next; unsigned int curr_off = 0; int ret = 1; @@ -557,7 +561,7 @@ static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_holder gh; int rv; @@ -604,7 +608,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; if (rw == WRITE) diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index b020ad8f180b..7f6139288519 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -13,12 +13,16 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "dir.h" #include "glock.h" #include "ops_dentry.h" +#include "util.h" /** * gfs2_drevalidate - Check directory lookup consistency @@ -34,7 +38,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) { struct dentry *parent = dget_parent(dentry); - struct gfs2_inode *dip = get_v2ip(parent->d_inode); + struct gfs2_inode *dip = parent->d_inode->u.generic_ip; struct inode *inode; struct gfs2_holder d_gh; struct gfs2_inode *ip; @@ -66,7 +70,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) goto fail_gunlock; } - ip = get_v2ip(inode); + ip = inode->u.generic_ip; if (!gfs2_inum_equal(&ip->i_num, &inum)) goto invalid_gunlock; diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 60d006402553..d149584cff30 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -12,9 +12,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "dir.h" #include "glock.h" #include "glops.h" @@ -61,7 +64,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, int connectable) { struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; if (*len < 4 || (connectable && *len < 8)) @@ -77,12 +80,12 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, fh[3] = cpu_to_be32(fh[3]); *len = 4; - if (!connectable || ip == get_v2ip(sdp->sd_root_dir)) + if (!connectable || ip == sdp->sd_root_dir->u.generic_ip) return *len; spin_lock(&dentry->d_lock); inode = dentry->d_parent->d_inode; - ip = get_v2ip(inode); + ip = inode->u.generic_ip; gfs2_inode_hold(ip); spin_unlock(&dentry->d_lock); @@ -138,8 +141,8 @@ static int gfs2_get_name(struct dentry *parent, char *name, if (!S_ISDIR(dir->i_mode) || !inode) return -EINVAL; - dip = get_v2ip(dir); - ip = get_v2ip(inode); + dip = dir->u.generic_ip; + ip = inode->u.generic_ip; *name = 0; gnfd.inum = ip->i_num; @@ -181,7 +184,7 @@ static struct dentry *gfs2_get_parent(struct dentry *child) static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_p) { - struct gfs2_sbd *sdp = get_v2sdp(sb); + struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_inum *inum = (struct gfs2_inum *)inum_p; struct gfs2_holder i_gh, ri_gh, rgd_gh; struct gfs2_rgrpd *rgd; @@ -194,7 +197,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_p) inode = gfs2_iget(sb, inum); if (inode) { - ip = get_v2ip(inode); + ip = inode->u.generic_ip; if (ip->i_num.no_formal_ino != inum->no_formal_ino) { iput(inode); return ERR_PTR(-ESTALE); diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index e6ae2551b0cb..d30c6db46241 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -19,10 +19,13 @@ #include #include #include +#include #include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "dir.h" #include "glock.h" @@ -36,6 +39,7 @@ #include "quota.h" #include "rgrp.h" #include "trans.h" +#include "util.h" /* "bad" is for NFS support */ struct filldir_bad_entry { @@ -125,7 +129,7 @@ int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) { - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_inode *ip = file->f_mapping->host->u.generic_ip; struct gfs2_holder i_gh; loff_t error; @@ -172,7 +176,7 @@ static ssize_t __gfs2_file_aio_read(struct kiocb *iocb, unsigned long nr_segs, loff_t *ppos) { struct file *filp = iocb->ki_filp; - struct gfs2_inode *ip = get_v2ip(filp->f_mapping->host); + struct gfs2_inode *ip = filp->f_mapping->host->u.generic_ip; struct gfs2_holder gh; ssize_t retval; unsigned long seg; @@ -354,7 +358,7 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) { - struct gfs2_inode *dip = get_v2ip(file->f_mapping->host); + struct gfs2_inode *dip = file->f_mapping->host->u.generic_ip; struct filldir_reg fdr; struct gfs2_holder d_gh; uint64_t offset = file->f_pos; @@ -443,7 +447,7 @@ static int filldir_bad_func(void *opaque, const char *name, unsigned int length, static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) { - struct gfs2_inode *dip = get_v2ip(file->f_mapping->host); + struct gfs2_inode *dip = file->f_mapping->host->u.generic_ip; struct gfs2_sbd *sdp = dip->i_sbd; struct filldir_reg fdr; unsigned int entries, size; @@ -608,7 +612,7 @@ out: static int gfs2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; switch (cmd) { case GFS2_IOCTL_SETFLAGS: @@ -630,7 +634,7 @@ static int gfs2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) { - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_inode *ip = file->f_mapping->host->u.generic_ip; struct gfs2_holder i_gh; int error; @@ -665,7 +669,7 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) static int gfs2_open(struct inode *inode, struct file *file) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_holder i_gh; struct gfs2_file *fp; int error; @@ -679,8 +683,8 @@ static int gfs2_open(struct inode *inode, struct file *file) fp->f_inode = ip; fp->f_vfile = file; - gfs2_assert_warn(ip->i_sbd, !get_v2fp(file)); - set_v2fp(file, fp); + gfs2_assert_warn(ip->i_sbd, !file->private_data); + file->private_data = fp; if (S_ISREG(ip->i_di.di_mode)) { error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, @@ -708,7 +712,7 @@ static int gfs2_open(struct inode *inode, struct file *file) gfs2_glock_dq_uninit(&i_gh); fail: - set_v2fp(file, NULL); + file->private_data = NULL; kfree(fp); return error; @@ -724,11 +728,11 @@ static int gfs2_open(struct inode *inode, struct file *file) static int gfs2_close(struct inode *inode, struct file *file) { - struct gfs2_sbd *sdp = get_v2sdp(inode->i_sb); + struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; struct gfs2_file *fp; - fp = get_v2fp(file); - set_v2fp(file, NULL); + fp = file->private_data; + file->private_data = NULL; if (gfs2_assert_warn(sdp, fp)) return -EIO; @@ -748,7 +752,7 @@ static int gfs2_close(struct inode *inode, struct file *file) static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync) { - struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; gfs2_log_flush_glock(ip->i_gl); @@ -766,7 +770,7 @@ static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync) static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) { - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_inode *ip = file->f_mapping->host->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; struct lm_lockname name = { .ln_number = ip->i_num.no_addr, @@ -824,7 +828,7 @@ static ssize_t gfs2_sendfile(struct file *in_file, loff_t *offset, size_t count, static int do_flock(struct file *file, int cmd, struct file_lock *fl) { - struct gfs2_file *fp = get_v2fp(file); + struct gfs2_file *fp = file->private_data; struct gfs2_holder *fl_gh = &fp->f_fl_gh; struct gfs2_inode *ip = fp->f_inode; struct gfs2_glock *gl; @@ -874,7 +878,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) static void do_unflock(struct file *file, struct file_lock *fl) { - struct gfs2_file *fp = get_v2fp(file); + struct gfs2_file *fp = file->private_data; struct gfs2_holder *fl_gh = &fp->f_fl_gh; mutex_lock(&fp->f_fl_mutex); @@ -895,7 +899,7 @@ static void do_unflock(struct file *file, struct file_lock *fl) static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) { - struct gfs2_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs2_inode *ip = file->f_mapping->host->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; if (!(fl->fl_flags & FL_FLOCK)) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 535f020f1e0c..4c4115f9d960 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -15,9 +15,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "daemon.h" #include "glock.h" #include "glops.h" @@ -32,6 +35,7 @@ #include "super.h" #include "unlinked.h" #include "sys.h" +#include "util.h" #define DO 0 #define UNDO 1 @@ -47,7 +51,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) memset(sdp, 0, sizeof(struct gfs2_sbd)); - set_v2sdp(sb, sdp); + sb->s_fs_info = sdp; sdp->sd_vfs = sb; gfs2_tune_init(&sdp->sd_tune); @@ -382,6 +386,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) { struct gfs2_holder ji_gh; struct task_struct *p; + struct gfs2_inode *ip; int jindex = 1; int error = 0; @@ -396,7 +401,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) fs_err(sdp, "can't lookup journal index: %d\n", error); return error; } - set_bit(GLF_STICKY, &get_v2ip(sdp->sd_jindex)->i_gl->gl_flags); + ip = sdp->sd_jindex->u.generic_ip; + set_bit(GLF_STICKY, &ip->i_gl->gl_flags); /* Load in the journal index special file */ @@ -436,8 +442,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) goto fail_jindex; } - error = gfs2_glock_nq_init( - get_v2ip(sdp->sd_jdesc->jd_inode)->i_gl, + ip = sdp->sd_jdesc->jd_inode->u.generic_ip; + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_NOEXP | GL_EXACT, &sdp->sd_jinode_gh); @@ -522,6 +528,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) static int init_inodes(struct gfs2_sbd *sdp, int undo) { int error = 0; + struct gfs2_inode *ip; if (undo) goto fail_qinode; @@ -560,8 +567,9 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) fs_err(sdp, "can't get resource index inode: %d\n", error); goto fail_statfs; } - set_bit(GLF_STICKY, &get_v2ip(sdp->sd_rindex)->i_gl->gl_flags); - sdp->sd_rindex_vn = get_v2ip(sdp->sd_rindex)->i_gl->gl_vn - 1; + ip = sdp->sd_rindex->u.generic_ip; + set_bit(GLF_STICKY, &ip->i_gl->gl_flags); + sdp->sd_rindex_vn = ip->i_gl->gl_vn - 1; /* Read in the quota inode */ error = gfs2_lookup_simple(sdp->sd_master_dir, "quota", @@ -597,6 +605,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) struct inode *pn = NULL; char buf[30]; int error = 0; + struct gfs2_inode *ip; if (sdp->sd_args.ar_spectator) return 0; @@ -641,7 +650,8 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) iput(pn); pn = NULL; - error = gfs2_glock_nq_init(get_v2ip(sdp->sd_ir_inode)->i_gl, + ip = sdp->sd_ir_inode->u.generic_ip; + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, &sdp->sd_ir_gh); if (error) { @@ -649,7 +659,8 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) goto fail_qc_i; } - error = gfs2_glock_nq_init(get_v2ip(sdp->sd_sc_inode)->i_gl, + ip = sdp->sd_sc_inode->u.generic_ip; + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, &sdp->sd_sc_gh); if (error) { @@ -657,7 +668,8 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) goto fail_ir_gh; } - error = gfs2_glock_nq_init(get_v2ip(sdp->sd_ut_inode)->i_gl, + ip = sdp->sd_ut_inode->u.generic_ip; + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, &sdp->sd_ut_gh); if (error) { @@ -665,7 +677,8 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) goto fail_sc_gh; } - error = gfs2_glock_nq_init(get_v2ip(sdp->sd_qc_inode)->i_gl, + ip = sdp->sd_qc_inode->u.generic_ip; + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_NEVER_RECURSE, &sdp->sd_qc_gh); if (error) { @@ -862,7 +875,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) fail: vfree(sdp); - set_v2sdp(sb, NULL); + sb->s_fs_info = NULL; return error; } diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 9971a30eb78e..7633a8584b0d 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -17,10 +17,13 @@ #include #include #include +#include #include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "acl.h" #include "bmap.h" #include "dir.h" @@ -36,6 +39,7 @@ #include "rgrp.h" #include "trans.h" #include "unlinked.h" +#include "util.h" /** * gfs2_create - Create a file @@ -49,7 +53,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { - struct gfs2_inode *dip = get_v2ip(dir); + struct gfs2_inode *dip = dir->u.generic_ip; struct gfs2_sbd *sdp = dip->i_sbd; struct gfs2_holder ghs[2]; struct inode *inode; @@ -106,7 +110,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - struct gfs2_inode *dip = get_v2ip(dir); + struct gfs2_inode *dip = dir->u.generic_ip; struct gfs2_sbd *sdp = dip->i_sbd; struct inode *inode = NULL; int error; @@ -140,10 +144,10 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, static int gfs2_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct gfs2_inode *dip = get_v2ip(dir); + struct gfs2_inode *dip = dir->u.generic_ip; struct gfs2_sbd *sdp = dip->i_sbd; struct inode *inode = old_dentry->d_inode; - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_holder ghs[2]; int alloc_required; int error; @@ -274,9 +278,9 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, static int gfs2_unlink(struct inode *dir, struct dentry *dentry) { - struct gfs2_inode *dip = get_v2ip(dir); + struct gfs2_inode *dip = dir->u.generic_ip; struct gfs2_sbd *sdp = dip->i_sbd; - struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; struct gfs2_unlinked *ul; struct gfs2_holder ghs[2]; int error; @@ -329,7 +333,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) static int gfs2_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { - struct gfs2_inode *dip = get_v2ip(dir), *ip; + struct gfs2_inode *dip = dir->u.generic_ip, *ip; struct gfs2_sbd *sdp = dip->i_sbd; struct gfs2_holder ghs[2]; struct inode *inode; @@ -350,7 +354,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, return PTR_ERR(inode); } - ip = get_gl2ip(ghs[1].gh_gl); + ip = ghs[1].gh_gl->gl_object; ip->i_di.di_size = size; @@ -388,7 +392,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) { - struct gfs2_inode *dip = get_v2ip(dir), *ip; + struct gfs2_inode *dip = dir->u.generic_ip, *ip; struct gfs2_sbd *sdp = dip->i_sbd; struct gfs2_holder ghs[2]; struct inode *inode; @@ -403,7 +407,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) return PTR_ERR(inode); } - ip = get_gl2ip(ghs[1].gh_gl); + ip = ghs[1].gh_gl->gl_object; ip->i_di.di_nlink = 2; ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode); @@ -468,9 +472,9 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) { - struct gfs2_inode *dip = get_v2ip(dir); + struct gfs2_inode *dip = dir->u.generic_ip; struct gfs2_sbd *sdp = dip->i_sbd; - struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; struct gfs2_unlinked *ul; struct gfs2_holder ghs[2]; int error; @@ -534,7 +538,7 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { - struct gfs2_inode *dip = get_v2ip(dir), *ip; + struct gfs2_inode *dip = dir->u.generic_ip, *ip; struct gfs2_sbd *sdp = dip->i_sbd; struct gfs2_holder ghs[2]; struct inode *inode; @@ -563,7 +567,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, return PTR_ERR(inode); } - ip = get_gl2ip(ghs[1].gh_gl); + ip = ghs[1].gh_gl->gl_object; ip->i_di.di_major = major; ip->i_di.di_minor = minor; @@ -602,9 +606,9 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, static int gfs2_rename(struct inode *odir, struct dentry *odentry, struct inode *ndir, struct dentry *ndentry) { - struct gfs2_inode *odip = get_v2ip(odir); - struct gfs2_inode *ndip = get_v2ip(ndir); - struct gfs2_inode *ip = get_v2ip(odentry->d_inode); + struct gfs2_inode *odip = odir->u.generic_ip; + struct gfs2_inode *ndip = ndir->u.generic_ip; + struct gfs2_inode *ip = odentry->d_inode->u.generic_ip; struct gfs2_inode *nip = NULL; struct gfs2_sbd *sdp = odip->i_sbd; struct gfs2_unlinked *ul; @@ -616,7 +620,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, int error; if (ndentry->d_inode) { - nip = get_v2ip(ndentry->d_inode); + nip = ndentry->d_inode->u.generic_ip; if (ip == nip) return 0; } @@ -848,7 +852,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, static int gfs2_readlink(struct dentry *dentry, char __user *user_buf, int user_size) { - struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; @@ -884,7 +888,7 @@ static int gfs2_readlink(struct dentry *dentry, char __user *user_buf, static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; @@ -910,7 +914,7 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_holder i_gh; int error; @@ -930,7 +934,7 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) static int setattr_size(struct inode *inode, struct iattr *attr) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; int error; if (attr->ia_size != ip->i_di.di_size) { @@ -948,7 +952,7 @@ static int setattr_size(struct inode *inode, struct iattr *attr) static int setattr_chown(struct inode *inode, struct iattr *attr) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; struct buffer_head *dibh; uint32_t ouid, ogid, nuid, ngid; @@ -1025,7 +1029,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_holder i_gh; int error; @@ -1072,7 +1076,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_holder gh; int error; @@ -1088,7 +1092,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, static int gfs2_setxattr(struct dentry *dentry, const char *name, const void *data, size_t size, int flags) { - struct gfs2_inode *ip = get_v2ip(dentry->d_inode); + struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; struct gfs2_ea_request er; memset(&er, 0, sizeof(struct gfs2_ea_request)); @@ -1118,7 +1122,7 @@ static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, er.er_name_len = strlen(er.er_name); er.er_data_len = size; - return gfs2_ea_get(get_v2ip(dentry->d_inode), &er); + return gfs2_ea_get(dentry->d_inode->u.generic_ip, &er); } static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) @@ -1129,7 +1133,7 @@ static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) er.er_data = (size) ? buffer : NULL; er.er_data_len = size; - return gfs2_ea_list(get_v2ip(dentry->d_inode), &er); + return gfs2_ea_list(dentry->d_inode->u.generic_ip, &er); } static int gfs2_removexattr(struct dentry *dentry, const char *name) @@ -1142,7 +1146,7 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name) return -EOPNOTSUPP; er.er_name_len = strlen(er.er_name); - return gfs2_ea_remove(get_v2ip(dentry->d_inode), &er); + return gfs2_ea_remove(dentry->d_inode->u.generic_ip, &er); } struct inode_operations gfs2_file_iops = { diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 48a94522406e..10f70ee12161 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -18,9 +18,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "glock.h" #include "inode.h" #include "lm.h" @@ -33,6 +36,7 @@ #include "rgrp.h" #include "super.h" #include "sys.h" +#include "util.h" /** * gfs2_write_inode - Make sure the inode is stable on the disk @@ -44,7 +48,7 @@ static int gfs2_write_inode(struct inode *inode, int sync) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; if (current->flags & PF_MEMALLOC) return 0; @@ -62,7 +66,7 @@ static int gfs2_write_inode(struct inode *inode, int sync) static void gfs2_put_super(struct super_block *sb) { - struct gfs2_sbd *sdp = get_v2sdp(sb); + struct gfs2_sbd *sdp = sb->s_fs_info; int error; if (!sdp) @@ -138,7 +142,7 @@ static void gfs2_put_super(struct super_block *sb) vfree(sdp); - set_v2sdp(sb, NULL); + sb->s_fs_info = NULL; } /** @@ -151,7 +155,7 @@ static void gfs2_put_super(struct super_block *sb) static void gfs2_write_super(struct super_block *sb) { - struct gfs2_sbd *sdp = get_v2sdp(sb); + struct gfs2_sbd *sdp = sb->s_fs_info; gfs2_log_flush(sdp); } @@ -163,7 +167,7 @@ static void gfs2_write_super(struct super_block *sb) static void gfs2_write_super_lockfs(struct super_block *sb) { - struct gfs2_sbd *sdp = get_v2sdp(sb); + struct gfs2_sbd *sdp = sb->s_fs_info; int error; for (;;) { @@ -194,7 +198,7 @@ static void gfs2_write_super_lockfs(struct super_block *sb) static void gfs2_unlockfs(struct super_block *sb) { - struct gfs2_sbd *sdp = get_v2sdp(sb); + struct gfs2_sbd *sdp = sb->s_fs_info; gfs2_unfreeze_fs(sdp); } @@ -208,7 +212,7 @@ static void gfs2_unlockfs(struct super_block *sb) static int gfs2_statfs(struct super_block *sb, struct kstatfs *buf) { - struct gfs2_sbd *sdp = get_v2sdp(sb); + struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_statfs_change sc; int error; @@ -245,7 +249,7 @@ static int gfs2_statfs(struct super_block *sb, struct kstatfs *buf) static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) { - struct gfs2_sbd *sdp = get_v2sdp(sb); + struct gfs2_sbd *sdp = sb->s_fs_info; int error; error = gfs2_mount_args(sdp, data, 1); @@ -283,12 +287,12 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) static void gfs2_clear_inode(struct inode *inode) { - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; if (ip) { spin_lock(&ip->i_spin); ip->i_vnode = NULL; - set_v2ip(inode, NULL); + inode->u.generic_ip = NULL; spin_unlock(&ip->i_spin); gfs2_glock_schedule_for_reclaim(ip->i_gl); @@ -306,7 +310,7 @@ static void gfs2_clear_inode(struct inode *inode) static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) { - struct gfs2_sbd *sdp = get_v2sdp(mnt->mnt_sb); + struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info; struct gfs2_args *args = &sdp->sd_args; if (args->ar_lockproto[0]) diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index bfeb920dccee..dbc57071e7bb 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -14,9 +14,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "glock.h" #include "inode.h" @@ -25,6 +28,7 @@ #include "quota.h" #include "rgrp.h" #include "trans.h" +#include "util.h" static void pfault_be_greedy(struct gfs2_inode *ip) { @@ -43,7 +47,7 @@ static void pfault_be_greedy(struct gfs2_inode *ip) static struct page *gfs2_private_nopage(struct vm_area_struct *area, unsigned long address, int *type) { - struct gfs2_inode *ip = get_v2ip(area->vm_file->f_mapping->host); + struct gfs2_inode *ip = area->vm_file->f_mapping->host->u.generic_ip; struct gfs2_holder i_gh; struct page *result; int error; @@ -141,7 +145,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, unsigned long address, int *type) { - struct gfs2_inode *ip = get_v2ip(area->vm_file->f_mapping->host); + struct gfs2_inode *ip = area->vm_file->f_mapping->host->u.generic_ip; struct gfs2_holder i_gh; struct page *result = NULL; unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c index 3542aa6b01c4..a2c9e93c7c39 100644 --- a/fs/gfs2/page.c +++ b/fs/gfs2/page.c @@ -14,14 +14,18 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "inode.h" #include "page.h" #include "trans.h" #include "ops_address.h" +#include "util.h" /** * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock @@ -34,7 +38,7 @@ void gfs2_pte_inval(struct gfs2_glock *gl) struct gfs2_inode *ip; struct inode *inode; - ip = get_gl2ip(gl); + ip = gl->gl_object; if (!ip || !S_ISREG(ip->i_di.di_mode)) return; @@ -64,7 +68,7 @@ void gfs2_page_inval(struct gfs2_glock *gl) struct gfs2_inode *ip; struct inode *inode; - ip = get_gl2ip(gl); + ip = gl->gl_object; if (!ip || !S_ISREG(ip->i_di.di_mode)) return; @@ -95,7 +99,7 @@ void gfs2_page_sync(struct gfs2_glock *gl, int flags) struct gfs2_inode *ip; struct inode *inode; - ip = get_gl2ip(gl); + ip = gl->gl_object; if (!ip || !S_ISREG(ip->i_di.di_mode)) return; @@ -192,7 +196,7 @@ int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, int gfs2_block_truncate_page(struct address_space *mapping) { struct inode *inode = mapping->host; - struct gfs2_inode *ip = get_v2ip(inode); + struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; loff_t from = inode->i_size; unsigned long index = from >> PAGE_CACHE_SHIFT; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 40c7cf87eb44..c57b5cf1d583 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -44,13 +44,17 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "glock.h" #include "glops.h" #include "log.h" +#include "lvb.h" #include "meta_io.h" #include "quota.h" #include "rgrp.h" @@ -59,6 +63,7 @@ #include "inode.h" #include "ops_file.h" #include "ops_address.h" +#include "util.h" #define QUOTA_USER 1 #define QUOTA_GROUP 0 @@ -244,7 +249,7 @@ static void slot_put(struct gfs2_quota_data *qd) static int bh_get(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - struct gfs2_inode *ip = get_v2ip(sdp->sd_qc_inode); + struct gfs2_inode *ip = sdp->sd_qc_inode->u.generic_ip; unsigned int block, offset; uint64_t dblock; int new = 0; @@ -526,7 +531,7 @@ static int sort_qd(const void *a, const void *b) static void do_qc(struct gfs2_quota_data *qd, int64_t change) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - struct gfs2_inode *ip = get_v2ip(sdp->sd_qc_inode); + struct gfs2_inode *ip = sdp->sd_qc_inode->u.generic_ip; struct gfs2_quota_change *qc = qd->qd_bh_qc; int64_t x; @@ -642,7 +647,7 @@ unlock: static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) { struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd; - struct gfs2_inode *ip = get_v2ip(sdp->sd_quota_inode); + struct gfs2_inode *ip = sdp->sd_quota_inode->u.generic_ip; unsigned int data_blocks, ind_blocks; struct file_ra_state ra_state; struct gfs2_holder *ghs, i_gh; @@ -753,6 +758,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, struct gfs2_holder *q_gh) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_inode *ip = sdp->sd_quota_inode->u.generic_ip; struct gfs2_holder i_gh; struct gfs2_quota q; char buf[sizeof(struct gfs2_quota)]; @@ -776,7 +782,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, if (error) return error; - error = gfs2_glock_nq_init(get_v2ip(sdp->sd_quota_inode)->i_gl, + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); if (error) @@ -784,7 +790,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, memset(buf, 0, sizeof(struct gfs2_quota)); pos = qd2offset(qd); - error = gfs2_internal_read(get_v2ip(sdp->sd_quota_inode), + error = gfs2_internal_read(ip, &ra_state, buf, &pos, sizeof(struct gfs2_quota)); @@ -1118,7 +1124,7 @@ int gfs2_quota_read(struct gfs2_sbd *sdp, int user, uint32_t id, int gfs2_quota_init(struct gfs2_sbd *sdp) { - struct gfs2_inode *ip = get_v2ip(sdp->sd_qc_inode); + struct gfs2_inode *ip = sdp->sd_qc_inode->u.generic_ip; unsigned int blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; unsigned int x, slot = 0; unsigned int found = 0; @@ -1133,7 +1139,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) return -EIO; } sdp->sd_quota_slots = blocks * sdp->sd_qc_per_block; - sdp->sd_quota_chunks = DIV_RU(sdp->sd_quota_slots, 8 * PAGE_SIZE); + sdp->sd_quota_chunks = DIV_ROUND_UP(sdp->sd_quota_slots, 8 * PAGE_SIZE); error = -ENOMEM; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index e5f2b284fa54..2df450e2f433 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -12,9 +12,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "glock.h" #include "glops.h" @@ -23,22 +26,24 @@ #include "meta_io.h" #include "recovery.h" #include "super.h" +#include "util.h" int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, struct buffer_head **bh) { - struct gfs2_glock *gl = get_v2ip(jd->jd_inode)->i_gl; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_glock *gl = ip->i_gl; int new = 0; uint64_t dblock; uint32_t extlen; int error; - error = gfs2_block_map(get_v2ip(jd->jd_inode), blk, &new, &dblock, + error = gfs2_block_map(ip, blk, &new, &dblock, &extlen); if (error) return error; if (!dblock) { - gfs2_consist_inode(get_v2ip(jd->jd_inode)); + gfs2_consist_inode(ip); return -EIO; } @@ -185,7 +190,7 @@ static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk, *blk = 0; if (*blk == orig_blk) { - gfs2_consist_inode(get_v2ip(jd->jd_inode)); + gfs2_consist_inode(jd->jd_inode->u.generic_ip); return -EIO; } } @@ -219,7 +224,7 @@ static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head) continue; if (lh.lh_sequence == head->lh_sequence) { - gfs2_consist_inode(get_v2ip(jd->jd_inode)); + gfs2_consist_inode(jd->jd_inode->u.generic_ip); return -EIO; } if (lh.lh_sequence < head->lh_sequence) @@ -295,7 +300,8 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header *head) static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, unsigned int end, int pass) { - struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; struct buffer_head *bh; struct gfs2_log_descriptor *ld; int error = 0; @@ -324,7 +330,7 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, continue; } if (error == 1) { - gfs2_consist_inode(get_v2ip(jd->jd_inode)); + gfs2_consist_inode(jd->jd_inode->u.generic_ip); error = -EIO; } brelse(bh); @@ -361,7 +367,7 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) { - struct gfs2_inode *ip = get_v2ip(jd->jd_inode); + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; unsigned int lblock; int new = 0; @@ -420,7 +426,8 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) int gfs2_recover_journal(struct gfs2_jdesc *jd, int wait) { - struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd; + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_sbd *sdp = ip->i_sbd; struct gfs2_log_header head; struct gfs2_holder j_gh, ji_gh, t_gh; unsigned long t; @@ -450,7 +457,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd, int wait) goto fail; }; - error = gfs2_glock_nq_init(get_v2ip(jd->jd_inode)->i_gl, LM_ST_SHARED, + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_NOEXP, &ji_gh); if (error) goto fail_gunlock_j; @@ -516,7 +523,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd, int wait) gfs2_glock_dq_uninit(&t_gh); - t = DIV_RU(jiffies - t, HZ); + t = DIV_ROUND_UP(jiffies - t, HZ); fs_info(sdp, "jid=%u: Journal replayed in %lus\n", jd->jd_jid, t); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 9525b176f502..4ae559694396 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -13,9 +13,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bits.h" #include "glock.h" #include "glops.h" @@ -26,6 +29,7 @@ #include "super.h" #include "trans.h" #include "ops_file.h" +#include "util.h" /** * gfs2_rgrp_verify - Verify that a resource group is consistent @@ -171,7 +175,7 @@ static void clear_rgrpdi(struct gfs2_sbd *sdp) list_del(&rgd->rd_list_mru); if (gl) { - set_gl2rgd(gl, NULL); + gl->gl_object = NULL; gfs2_glock_put(gl); } @@ -320,7 +324,7 @@ static int gfs2_ri_update(struct gfs2_inode *ip) if (error) goto fail; - set_gl2rgd(rgd->rd_gl, rgd); + rgd->rd_gl->gl_object = rgd; rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1; } @@ -354,7 +358,7 @@ static int gfs2_ri_update(struct gfs2_inode *ip) int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh) { - struct gfs2_inode *ip = get_v2ip(sdp->sd_rindex); + struct gfs2_inode *ip = sdp->sd_rindex->u.generic_ip; struct gfs2_glock *gl = ip->i_gl; int error; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 2c1c6aa1c077..9ccf0b9c5980 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -12,9 +12,12 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "dir.h" #include "format.h" @@ -29,6 +32,7 @@ #include "super.h" #include "trans.h" #include "unlinked.h" +#include "util.h" /** * gfs2_tune_init - Fill a gfs2_tune structure with default values @@ -207,12 +211,12 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) /* Compute maximum reservation required to add a entry to a directory */ - hash_blocks = DIV_RU(sizeof(uint64_t) * (1 << GFS2_DIR_MAX_DEPTH), + hash_blocks = DIV_ROUND_UP(sizeof(uint64_t) * (1 << GFS2_DIR_MAX_DEPTH), sdp->sd_jbsize); ind_blocks = 0; for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) { - tmp_blocks = DIV_RU(tmp_blocks, sdp->sd_inptrs); + tmp_blocks = DIV_ROUND_UP(tmp_blocks, sdp->sd_inptrs); ind_blocks += tmp_blocks; } @@ -278,7 +282,7 @@ int gfs2_do_upgrade(struct gfs2_sbd *sdp, struct gfs2_glock *sb_gl) int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) { - struct gfs2_inode *dip = get_v2ip(sdp->sd_jindex); + struct gfs2_inode *dip = sdp->sd_jindex->u.generic_ip; struct qstr name; char buf[20]; struct gfs2_jdesc *jd; @@ -296,7 +300,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) name.len = sprintf(buf, "journal%u", sdp->sd_journals); - error = gfs2_dir_search(get_v2ip(sdp->sd_jindex), + error = gfs2_dir_search(sdp->sd_jindex->u.generic_ip, &name, NULL, NULL); if (error == -ENOENT) { error = 0; @@ -419,7 +423,7 @@ struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp) int gfs2_jdesc_check(struct gfs2_jdesc *jd) { - struct gfs2_inode *ip = get_v2ip(jd->jd_inode); + struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; struct gfs2_sbd *sdp = ip->i_sbd; int ar; int error; @@ -471,7 +475,8 @@ int gfs2_lookup_master_dir(struct gfs2_sbd *sdp) int gfs2_make_fs_rw(struct gfs2_sbd *sdp) { - struct gfs2_glock *j_gl = get_v2ip(sdp->sd_jdesc->jd_inode)->i_gl; + struct gfs2_inode *ip = sdp->sd_jdesc->jd_inode->u.generic_ip; + struct gfs2_glock *j_gl = ip->i_gl; struct gfs2_holder t_gh; struct gfs2_log_header head; int error; @@ -481,7 +486,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) if (error) return error; - gfs2_meta_cache_flush(get_v2ip(sdp->sd_jdesc->jd_inode)); + gfs2_meta_cache_flush(ip); j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA); error = gfs2_find_jhead(sdp->sd_jdesc, &head); @@ -559,9 +564,9 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp) int gfs2_statfs_init(struct gfs2_sbd *sdp) { - struct gfs2_inode *m_ip = get_v2ip(sdp->sd_statfs_inode); + struct gfs2_inode *m_ip = sdp->sd_statfs_inode->u.generic_ip; struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; - struct gfs2_inode *l_ip = get_v2ip(sdp->sd_sc_inode); + struct gfs2_inode *l_ip = sdp->sd_sc_inode->u.generic_ip; struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; struct buffer_head *m_bh, *l_bh; struct gfs2_holder gh; @@ -608,7 +613,7 @@ int gfs2_statfs_init(struct gfs2_sbd *sdp) void gfs2_statfs_change(struct gfs2_sbd *sdp, int64_t total, int64_t free, int64_t dinodes) { - struct gfs2_inode *l_ip = get_v2ip(sdp->sd_sc_inode); + struct gfs2_inode *l_ip = sdp->sd_sc_inode->u.generic_ip; struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; struct buffer_head *l_bh; int error; @@ -634,8 +639,8 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, int64_t total, int64_t free, int gfs2_statfs_sync(struct gfs2_sbd *sdp) { - struct gfs2_inode *m_ip = get_v2ip(sdp->sd_statfs_inode); - struct gfs2_inode *l_ip = get_v2ip(sdp->sd_sc_inode); + struct gfs2_inode *m_ip = sdp->sd_statfs_inode->u.generic_ip; + struct gfs2_inode *l_ip = sdp->sd_sc_inode->u.generic_ip; struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; struct gfs2_holder gh; @@ -795,7 +800,8 @@ int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc) error = err; } else { if (!error) - error = statfs_slow_fill(get_gl2rgd(gh->gh_gl), sc); + error = statfs_slow_fill( + gh->gh_gl->gl_object, sc); gfs2_glock_dq_uninit(gh); } } @@ -846,6 +852,7 @@ struct lfcc { int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_holder *t_gh) { + struct gfs2_inode *ip; struct gfs2_holder ji_gh; struct gfs2_jdesc *jd; struct lfcc *lfcc; @@ -863,7 +870,8 @@ int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_holder *t_gh) error = -ENOMEM; goto out; } - error = gfs2_glock_nq_init(get_v2ip(jd->jd_inode)->i_gl, + ip = jd->jd_inode->u.generic_ip; + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &lfcc->gh); if (error) { diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index f87df8ec041e..f05ba8f69132 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -14,15 +14,19 @@ #include #include #include +#include #include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "lm.h" #include "sys.h" #include "super.h" #include "glock.h" #include "quota.h" +#include "util.h" char *gfs2_sys_margs; spinlock_t gfs2_sys_margs_lock; diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 0a0ea70eac4c..2cce68aec134 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -12,14 +12,18 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "glock.h" #include "log.h" #include "lops.h" #include "meta_io.h" #include "trans.h" +#include "util.h" int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, unsigned int revokes, char *file, unsigned int line) @@ -27,7 +31,7 @@ int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, struct gfs2_trans *tr; int error; - if (gfs2_assert_warn(sdp, !get_transaction) || + if (gfs2_assert_warn(sdp, !current->journal_info) || gfs2_assert_warn(sdp, blocks || revokes)) { fs_warn(sdp, "(%s, %u)\n", file, line); return -EINVAL; @@ -69,7 +73,7 @@ int gfs2_trans_begin_i(struct gfs2_sbd *sdp, unsigned int blocks, if (error) goto fail_gunlock; - set_transaction(tr); + current->journal_info = tr; return 0; @@ -90,8 +94,8 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) struct gfs2_trans *tr; struct gfs2_holder *t_gh; - tr = get_transaction; - set_transaction(NULL); + tr = current->journal_info; + current->journal_info = NULL; if (gfs2_assert_warn(sdp, tr)) return; @@ -147,12 +151,12 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta) struct gfs2_sbd *sdp = gl->gl_sbd; struct gfs2_bufdata *bd; - bd = get_v2bd(bh); + bd = bh->b_private; if (bd) gfs2_assert(sdp, bd->bd_gl == gl); else { gfs2_attach_bufdata(gl, bh, meta); - bd = get_v2bd(bh); + bd = bh->b_private; } lops_add(sdp, &bd->bd_le); } @@ -186,8 +190,9 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, uint64_t blkno) gfs2_log_unlock(sdp); if (found) { + struct gfs2_trans *tr = current->journal_info; kfree(rv); - get_transaction->tr_num_revoke_rm++; + tr->tr_num_revoke_rm++; } } diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c index e92a3a11815b..24b91c23bc2d 100644 --- a/fs/gfs2/unlinked.c +++ b/fs/gfs2/unlinked.c @@ -13,19 +13,23 @@ #include #include #include +#include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "bmap.h" #include "inode.h" #include "meta_io.h" #include "trans.h" #include "unlinked.h" +#include "util.h" static int munge_ondisk(struct gfs2_sbd *sdp, unsigned int slot, struct gfs2_unlinked_tag *ut) { - struct gfs2_inode *ip = get_v2ip(sdp->sd_ut_inode); + struct gfs2_inode *ip = sdp->sd_ut_inode->u.generic_ip; unsigned int block, offset; uint64_t dblock; int new = 0; @@ -312,7 +316,7 @@ int gfs2_unlinked_dealloc(struct gfs2_sbd *sdp) int gfs2_unlinked_init(struct gfs2_sbd *sdp) { - struct gfs2_inode *ip = get_v2ip(sdp->sd_ut_inode); + struct gfs2_inode *ip = sdp->sd_ut_inode->u.generic_ip; unsigned int blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; unsigned int x, slot = 0; unsigned int found = 0; @@ -327,7 +331,8 @@ int gfs2_unlinked_init(struct gfs2_sbd *sdp) return -EIO; } sdp->sd_unlinked_slots = blocks * sdp->sd_ut_per_block; - sdp->sd_unlinked_chunks = DIV_RU(sdp->sd_unlinked_slots, 8 * PAGE_SIZE); + sdp->sd_unlinked_chunks = DIV_ROUND_UP(sdp->sd_unlinked_slots, + 8 * PAGE_SIZE); error = -ENOMEM; diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 4fb1704aac10..8b22fa91bd14 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -13,12 +13,16 @@ #include #include #include +#include #include #include #include "gfs2.h" +#include "lm_interface.h" +#include "incore.h" #include "glock.h" #include "lm.h" +#include "util.h" kmem_cache_t *gfs2_glock_cachep __read_mostly; kmem_cache_t *gfs2_inode_cachep __read_mostly; diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index ec432e0c208d..8d4f0445df47 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -50,15 +50,18 @@ * An on-disk inode number */ -#define gfs2_inum_equal(ino1, ino2) \ - (((ino1)->no_formal_ino == (ino2)->no_formal_ino) && \ - ((ino1)->no_addr == (ino2)->no_addr)) - struct gfs2_inum { __be64 no_formal_ino; __be64 no_addr; }; +static inline int gfs2_inum_equal(const struct gfs2_inum *ino1, + const struct gfs2_inum *ino2) +{ + return ino1->no_formal_ino == ino2->no_formal_ino && + ino1->no_addr == ino2->no_addr; +} + /* * Generic metadata head structure * Every inplace buffer logged in the journal must start with this. diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3b507bf05d09..f789278a625a 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -29,6 +29,7 @@ extern const char linux_banner[]; #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define ALIGN(x,a) (((x)+(a)-1)&~((a)-1)) +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #define KERN_EMERG "<0>" /* system is unusable */ #define KERN_ALERT "<1>" /* action must be taken immediately */ -- cgit v1.2.3 From c752666c17f870fa8ae9f16804dd457e9e6daaec Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 20 Mar 2006 12:30:04 -0500 Subject: [GFS2] Fix bug in directory code and tidy up Due to a typo, the dir leaf split operation was (for the first split in a directory) writing the new hash vaules at the wrong offset. This is now fixed. Also some other tidy ups are included: - We use GFS2's hash function for dentries (see ops_dentry.c) so that we don't have to keep recalculating the hash values. - A lot of common code is eliminated between the various directory lookup routines. - Better error checking on directory lookup (previously different routines checked for different errors) - The leaf split operation has a couple of redundant operations removed from it, so it should be faster. There is still further scope for further clean ups in the directory code, and readdir in particular could do with slimming down a bit. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 1390 +++++++++++++++++-------------------------- fs/gfs2/dir.h | 39 +- fs/gfs2/inode.c | 63 +- fs/gfs2/inode.h | 16 +- fs/gfs2/ondisk.c | 13 +- fs/gfs2/ops_dentry.c | 21 +- fs/gfs2/ops_export.c | 13 +- fs/gfs2/ops_fstype.c | 56 +- fs/gfs2/ops_inode.c | 72 ++- fs/gfs2/super.c | 11 +- include/linux/gfs2_ondisk.h | 3 +- 11 files changed, 698 insertions(+), 999 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 37f70ca558cc..f31f163da1a1 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -130,7 +130,7 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, return error; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - memcpy(dibh->b_data + offset + sizeof(struct gfs2_inode), buf, size); + memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size); if (ip->i_di.di_size < offset + size) ip->i_di.di_size = offset + size; ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); @@ -177,7 +177,7 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, if (gfs2_is_stuffed(ip)) { error = gfs2_unstuff_dinode(ip, NULL, NULL); if (error) - return error; + return error; } lblock = offset; @@ -244,7 +244,7 @@ fail: } static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, - unsigned int offset, unsigned int size) + unsigned int offset, unsigned int size) { struct buffer_head *dibh; int error; @@ -343,26 +343,159 @@ fail: return (copied) ? copied : error; } -/** - * int gfs2_filecmp - Compare two filenames - * @file1: The first filename - * @file2: The second filename - * @len_of_file2: The length of the second file - * - * This routine compares two filenames and returns 1 if they are equal. - * - * Returns: 1 if the files are the same, otherwise 0. +typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, + const struct qstr *name); + +static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, + const struct qstr *name, int ret) +{ + if (dent->de_inum.no_addr != 0 && + be32_to_cpu(dent->de_hash) == name->hash && + be16_to_cpu(dent->de_name_len) == name->len && + memcmp((char *)(dent+1), name->name, name->len) == 0) + return ret; + return 0; +} + +static int gfs2_dirent_find(const struct gfs2_dirent *dent, + const struct qstr *name) +{ + return __gfs2_dirent_find(dent, name, 1); +} + +static int gfs2_dirent_prev(const struct gfs2_dirent *dent, + const struct qstr *name) +{ + return __gfs2_dirent_find(dent, name, 2); +} + +/* + * name->name holds ptr to start of block. + * name->len holds size of block. */ +static int gfs2_dirent_last(const struct gfs2_dirent *dent, + const struct qstr *name) +{ + const char *start = name->name; + const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len); + if (name->len == (end - start)) + return 1; + return 0; +} -int gfs2_filecmp(struct qstr *file1, char *file2, int len_of_file2) +static int gfs2_dirent_find_space(const struct gfs2_dirent *dent, + const struct qstr *name) { - if (file1->len != len_of_file2) - return 0; - if (memcmp(file1->name, file2, file1->len)) - return 0; - return 1; + unsigned required = GFS2_DIRENT_SIZE(name->len); + unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len)); + unsigned totlen = be16_to_cpu(dent->de_rec_len); + + if ((totlen - actual) >= required) + return 1; + return 0; +} + +/* + * Other possible things to check: + * - Inode located within filesystem size (and on valid block) + * - Valid directory entry type + * Not sure how heavy-weight we want to make this... could also check + * hash is correct for example, but that would take a lot of extra time. + * For now the most important thing is to check that the various sizes + * are correct. + */ +static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset, + unsigned int size, unsigned int len, int first) +{ + const char *msg = "gfs2_dirent too small"; + if (unlikely(size < sizeof(struct gfs2_dirent))) + goto error; + msg = "gfs2_dirent misaligned"; + if (unlikely(offset & 0x7)) + goto error; + msg = "gfs2_dirent points beyond end of block"; + if (unlikely(offset + size > len)) + goto error; + msg = "zero inode number"; + if (unlikely(!first && !dent->de_inum.no_addr)) + goto error; + msg = "name length is greater than space in dirent"; + if (dent->de_inum.no_addr && + unlikely(sizeof(struct gfs2_dirent)+be16_to_cpu(dent->de_name_len) > + size)) + goto error; + return 0; +error: + printk(KERN_WARNING "gfs2_check_dirent: %s (%s)\n", msg, + first ? "first in block" : "not first in block"); + return -EIO; } +static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, + void *buf, + unsigned int len, gfs2_dscan_t scan, + const struct qstr *name) +{ + struct gfs2_meta_header *h = buf; + struct gfs2_dirent *dent, *prev; + unsigned offset; + unsigned size; + int ret = 0; + + BUG_ON(buf == NULL); + BUG_ON(name == NULL); + + switch(be16_to_cpu(h->mh_type)) { + case GFS2_METATYPE_LF: + offset = sizeof(struct gfs2_leaf); + break; + case GFS2_METATYPE_DI: + offset = sizeof(struct gfs2_dinode); + break; + default: + goto wrong_type; + } + + prev = NULL; + dent = (struct gfs2_dirent *)(buf + offset); + size = be16_to_cpu(dent->de_rec_len); + if (gfs2_check_dirent(dent, offset, size, len, 1)) + goto consist_inode; + do { + ret = scan(dent, name); + if (ret) + break; + offset += size; + if (offset == len) + break; + prev = dent; + dent = (struct gfs2_dirent *)(buf + offset); + size = be16_to_cpu(dent->de_rec_len); + if (gfs2_check_dirent(dent, offset, size, len, 0)) + goto consist_inode; + } while(1); + + switch(ret) { + case 0: + return NULL; + case 1: + return dent; + case 2: + return prev ? prev : dent; + default: + BUG_ON(ret > 0); + return ERR_PTR(ret); + } + +wrong_type: + printk(KERN_WARNING "gfs2_scan_dirent: %p wrong block type %u\n", scan, + be16_to_cpu(h->mh_type)); +consist_inode: + gfs2_consist_inode(inode->u.generic_ip); + return ERR_PTR(-EIO); +} + + /** * dirent_first - Return the first dirent * @dip: the directory @@ -489,180 +622,39 @@ static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, prev->de_rec_len = cpu_to_be16(prev_rec_len); } -/** - * gfs2_dirent_alloc - Allocate a directory entry - * @dip: The GFS2 inode - * @bh: The buffer - * @name_len: The length of the name - * @dent_out: Pointer to list of dirents - * - * Returns: 0 on success, error code otherwise +/* + * Takes a dent from which to grab space as an argument. Returns the + * newly created dent. */ - -int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, - int name_len, struct gfs2_dirent **dent_out) +struct gfs2_dirent *gfs2_init_dirent(struct inode *inode, + struct gfs2_dirent *dent, + const struct qstr *name, + struct buffer_head *bh) { - struct gfs2_dirent *dent, *new; - unsigned int rec_len = GFS2_DIRENT_SIZE(name_len); - unsigned int entries = 0, offset = 0; - int type; - - type = dirent_first(dip, bh, &dent); - if (type < 0) - return type; - - if (type == IS_LEAF) { - struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data; - entries = be16_to_cpu(leaf->lf_entries); - offset = sizeof(struct gfs2_leaf); - } else { - struct gfs2_dinode *dinode = (struct gfs2_dinode *)bh->b_data; - entries = be32_to_cpu(dinode->di_entries); - offset = sizeof(struct gfs2_dinode); - } - - if (!entries) { - if (dent->de_inum.no_addr) { - gfs2_consist_inode(dip); - return -EIO; - } - - gfs2_trans_add_bh(dip->i_gl, bh, 1); - - dent->de_rec_len = cpu_to_be16(bh->b_size - offset); - dent->de_name_len = cpu_to_be16(name_len); - - *dent_out = dent; - return 0; - } - - do { - uint16_t cur_rec_len; - uint16_t cur_name_len; - - cur_rec_len = be16_to_cpu(dent->de_rec_len); - cur_name_len = be16_to_cpu(dent->de_name_len); - - if ((!dent->de_inum.no_addr && cur_rec_len >= rec_len) || - (cur_rec_len >= GFS2_DIRENT_SIZE(cur_name_len) + rec_len)) { - gfs2_trans_add_bh(dip->i_gl, bh, 1); - - if (dent->de_inum.no_addr) { - new = (struct gfs2_dirent *)((char *)dent + - GFS2_DIRENT_SIZE(cur_name_len)); - memset(new, 0, sizeof(struct gfs2_dirent)); - - new->de_rec_len = cpu_to_be16(cur_rec_len - - GFS2_DIRENT_SIZE(cur_name_len)); - new->de_name_len = cpu_to_be16(name_len); - - dent->de_rec_len = cpu_to_be16(cur_rec_len - - be16_to_cpu(new->de_rec_len)); - - *dent_out = new; - return 0; - } - - dent->de_name_len = cpu_to_be16(name_len); - - *dent_out = dent; - return 0; - } - } while (dirent_next(dip, bh, &dent) == 0); - - return -ENOSPC; + struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_dirent *ndent; + unsigned offset = 0, totlen; + + if (dent->de_inum.no_addr) + offset = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len)); + totlen = be16_to_cpu(dent->de_rec_len); + BUG_ON(offset + name->len > totlen); + gfs2_trans_add_bh(ip->i_gl, bh, 1); + ndent = (struct gfs2_dirent *)((char *)dent + offset); + dent->de_rec_len = cpu_to_be16(offset); + gfs2_qstr2dirent(name, totlen - offset, ndent); + return ndent; } -/** - * dirent_fits - See if we can fit a entry in this buffer - * @dip: The GFS2 inode - * @bh: The buffer - * @name_len: The length of the name - * - * Returns: 1 if it can fit, 0 otherwise - */ - -static int dirent_fits(struct gfs2_inode *dip, struct buffer_head *bh, - int name_len) +static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode, + struct buffer_head *bh, + const struct qstr *name) { struct gfs2_dirent *dent; - unsigned int rec_len = GFS2_DIRENT_SIZE(name_len); - unsigned int entries = 0; - int type; - - type = dirent_first(dip, bh, &dent); - if (type < 0) - return type; - - if (type == IS_LEAF) { - struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data; - entries = be16_to_cpu(leaf->lf_entries); - } else { - struct gfs2_dinode *dinode = (struct gfs2_dinode *)bh->b_data; - entries = be32_to_cpu(dinode->di_entries); - } - - if (!entries) - return 1; - - do { - uint16_t cur_rec_len; - uint32_t cur_name_len; - - cur_rec_len = be16_to_cpu(dent->de_rec_len); - cur_name_len = be16_to_cpu(dent->de_name_len); - - if ((!dent->de_inum.no_addr && cur_rec_len >= rec_len) || - (cur_rec_len >= GFS2_DIRENT_SIZE(cur_name_len) + rec_len)) - return 1; - } while (dirent_next(dip, bh, &dent) == 0); - - return 0; -} - -static int leaf_search(struct gfs2_inode *dip, struct buffer_head *bh, - struct qstr *filename, struct gfs2_dirent **dent_out, - struct gfs2_dirent **dent_prev) -{ - uint32_t hash; - struct gfs2_dirent *dent, *prev = NULL; - unsigned int entries = 0; - int type; - - type = dirent_first(dip, bh, &dent); - if (type < 0) - return type; - - if (type == IS_LEAF) { - struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data; - entries = be16_to_cpu(leaf->lf_entries); - } else if (type == IS_DINODE) { - struct gfs2_dinode *dinode = (struct gfs2_dinode *)bh->b_data; - entries = be32_to_cpu(dinode->di_entries); - } - - hash = gfs2_disk_hash(filename->name, filename->len); - - do { - if (!dent->de_inum.no_addr) { - prev = dent; - continue; - } - - if (be32_to_cpu(dent->de_hash) == hash && - gfs2_filecmp(filename, (char *)(dent + 1), - be16_to_cpu(dent->de_name_len))) { - *dent_out = dent; - if (dent_prev) - *dent_prev = prev; - - return 0; - } - - prev = dent; - } while (dirent_next(dip, bh, &dent) == 0); - - return -ENOENT; + dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, gfs2_dirent_find_space, name); + if (!dent || IS_ERR(dent)) + return dent; + return gfs2_init_dirent(inode, dent, name, bh); } static int get_leaf(struct gfs2_inode *dip, uint64_t leaf_no, @@ -716,75 +708,81 @@ static int get_first_leaf(struct gfs2_inode *dip, uint32_t index, return error; } -static int get_next_leaf(struct gfs2_inode *dip, struct buffer_head *bh_in, - struct buffer_head **bh_out) -{ - struct gfs2_leaf *leaf; - int error; - - leaf = (struct gfs2_leaf *)bh_in->b_data; - - if (!leaf->lf_next) - error = -ENOENT; - else - error = get_leaf(dip, be64_to_cpu(leaf->lf_next), bh_out); - - return error; -} - -static int linked_leaf_search(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_dirent **dent_out, - struct gfs2_dirent **dent_prev, - struct buffer_head **bh_out) +static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, + const struct qstr *name, + gfs2_dscan_t scan, + struct buffer_head **pbh) { - struct buffer_head *bh = NULL, *bh_next; - uint32_t hsize, index; - uint32_t hash; + struct buffer_head *bh; + struct gfs2_dirent *dent; + struct gfs2_inode *ip = inode->u.generic_ip; int error; - hsize = 1 << dip->i_di.di_depth; - if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { - gfs2_consist_inode(dip); - return -EIO; - } - - /* Figure out the address of the leaf node. */ - - hash = gfs2_disk_hash(filename->name, filename->len); - index = hash >> (32 - dip->i_di.di_depth); - - error = get_first_leaf(dip, index, &bh_next); - if (error) - return error; - - /* Find the entry */ - - do { - brelse(bh); - - bh = bh_next; - - error = leaf_search(dip, bh, filename, dent_out, dent_prev); - switch (error) { - case 0: - *bh_out = bh; - return 0; - - case -ENOENT: - break; + if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { + struct gfs2_leaf *leaf; + unsigned hsize = 1 << ip->i_di.di_depth; + unsigned index; + u64 ln; + if (hsize * sizeof(u64) != ip->i_di.di_size) { + gfs2_consist_inode(ip); + return ERR_PTR(-EIO); + } - default: + index = name->hash >> (32 - ip->i_di.di_depth); + error = get_first_leaf(ip, index, &bh); + if (error) + return ERR_PTR(error); + do { + dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, + scan, name); + if (dent) + goto got_dent; + leaf = (struct gfs2_leaf *)bh->b_data; + ln = be64_to_cpu(leaf->lf_next); brelse(bh); - return error; - } + if (!ln) + break; + error = get_leaf(ip, ln, &bh); + } while(!error); - error = get_next_leaf(dip, bh, &bh_next); + return error ? ERR_PTR(error) : NULL; } - while (!error); - brelse(bh); + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + return ERR_PTR(error); + dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name); +got_dent: + *pbh = bh; + return dent; +} - return error; +static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth) +{ + struct gfs2_inode *ip = inode->u.generic_ip; + u64 bn = gfs2_alloc_meta(ip); + struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); + struct gfs2_leaf *leaf; + struct gfs2_dirent *dent; + if (!bh) + return NULL; + gfs2_trans_add_bh(ip->i_gl, bh, 1); + gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF); + leaf = (struct gfs2_leaf *)bh->b_data; + leaf->lf_depth = cpu_to_be16(depth); + leaf->lf_entries = cpu_to_be16(0); + leaf->lf_dirent_format = cpu_to_be16(GFS2_FORMAT_DE); + leaf->lf_next = cpu_to_be64(0); + memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved)); + dent = (struct gfs2_dirent *)(leaf+1); + dent->de_inum.no_formal_ino = cpu_to_be64(0); + dent->de_inum.no_addr = cpu_to_be64(0); + dent->de_hash = cpu_to_be32(0); + dent->de_rec_len = cpu_to_be16(bh->b_size - sizeof(struct gfs2_leaf)); + dent->de_name_len = cpu_to_be16(0); + dent->de_type = cpu_to_be16(0); + *pbh = bh; + return leaf; } /** @@ -794,10 +792,12 @@ static int linked_leaf_search(struct gfs2_inode *dip, struct qstr *filename, * Returns: 0 on success, error code otherwise */ -static int dir_make_exhash(struct gfs2_inode *dip) +static int dir_make_exhash(struct inode *inode) { + struct gfs2_inode *dip = inode->u.generic_ip; struct gfs2_sbd *sdp = dip->i_sbd; struct gfs2_dirent *dent; + struct qstr args; struct buffer_head *bh, *dibh; struct gfs2_leaf *leaf; int y; @@ -809,24 +809,14 @@ static int dir_make_exhash(struct gfs2_inode *dip) if (error) return error; - /* Allocate a new block for the first leaf node */ - - bn = gfs2_alloc_meta(dip); - /* Turn over a new leaf */ - bh = gfs2_meta_new(dip->i_gl, bn); - gfs2_trans_add_bh(dip->i_gl, bh, 1); - gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF); - gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); - - /* Fill in the leaf structure */ - - leaf = (struct gfs2_leaf *)bh->b_data; + leaf = new_leaf(inode, &bh, 0); + if (!leaf) + return -ENOSPC; + bn = bh->b_blocknr; gfs2_assert(sdp, dip->i_di.di_entries < (1 << 16)); - - leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries); /* Copy dirents */ @@ -837,15 +827,21 @@ static int dir_make_exhash(struct gfs2_inode *dip) /* Find last entry */ x = 0; - dirent_first(dip, bh, &dent); - - do { - if (!dent->de_inum.no_addr) - continue; - if (++x == dip->i_di.di_entries) - break; + args.len = bh->b_size - sizeof(struct gfs2_dinode) + + sizeof(struct gfs2_leaf); + args.name = bh->b_data; + dent = gfs2_dirent_scan(dip->i_vnode, bh->b_data, bh->b_size, + gfs2_dirent_last, &args); + if (!dent) { + brelse(bh); + brelse(dibh); + return -EIO; + } + if (IS_ERR(dent)) { + brelse(bh); + brelse(dibh); + return PTR_ERR(dent); } - while (dirent_next(dip, bh, &dent) == 0); /* Adjust the last dirent's record length (Remember that dent still points to the last entry.) */ @@ -891,45 +887,39 @@ static int dir_make_exhash(struct gfs2_inode *dip) * Returns: 0 on success, error code on failure */ -static int dir_split_leaf(struct gfs2_inode *dip, uint32_t index, - uint64_t leaf_no) +static int dir_split_leaf(struct inode *inode, const struct qstr *name) { + struct gfs2_inode *dip = inode->u.generic_ip; struct buffer_head *nbh, *obh, *dibh; struct gfs2_leaf *nleaf, *oleaf; struct gfs2_dirent *dent, *prev = NULL, *next = NULL, *new; uint32_t start, len, half_len, divider; - uint64_t bn, *lp; - uint32_t name_len; + uint64_t bn, *lp, leaf_no; + uint32_t index; int x, moved = 0; int error; - /* Allocate the new leaf block */ - - bn = gfs2_alloc_meta(dip); - - /* Get the new leaf block */ - - nbh = gfs2_meta_new(dip->i_gl, bn); - gfs2_trans_add_bh(dip->i_gl, nbh, 1); - gfs2_metatype_set(nbh, GFS2_METATYPE_LF, GFS2_FORMAT_LF); - gfs2_buffer_clear_tail(nbh, sizeof(struct gfs2_meta_header)); - - nleaf = (struct gfs2_leaf *)nbh->b_data; - - nleaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); + index = name->hash >> (32 - dip->i_di.di_depth); + error = get_leaf_nr(dip, index, &leaf_no); + if (error) + return error; /* Get the old leaf block */ - error = get_leaf(dip, leaf_no, &obh); if (error) goto fail; gfs2_trans_add_bh(dip->i_gl, obh, 1); - oleaf = (struct gfs2_leaf *)obh->b_data; - /* Compute the start and len of leaf pointers in the hash table. */ + nleaf = new_leaf(inode, &nbh, be16_to_cpu(oleaf->lf_depth) + 1); + if (!nleaf) { + brelse(obh); + return -ENOSPC; + } + bn = nbh->b_blocknr; + /* Compute the start and len of leaf pointers in the hash table. */ len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth)); half_len = len >> 1; if (!half_len) { @@ -943,19 +933,8 @@ static int dir_split_leaf(struct gfs2_inode *dip, uint32_t index, /* Change the pointers. Don't bother distinguishing stuffed from non-stuffed. This code is complicated enough already. */ - - lp = kcalloc(half_len, sizeof(uint64_t), GFP_KERNEL | __GFP_NOFAIL); - - error = gfs2_dir_read_data(dip, (char *)lp, start * sizeof(uint64_t), - half_len * sizeof(uint64_t)); - if (error != half_len * sizeof(uint64_t)) { - if (error >= 0) - error = -EIO; - goto fail_lpfree; - } - + lp = kmalloc(half_len * sizeof(uint64_t), GFP_NOFS | __GFP_NOFAIL); /* Change the pointers */ - for (x = 0; x < half_len; x++) lp[x] = cpu_to_be64(bn); @@ -970,11 +949,9 @@ static int dir_split_leaf(struct gfs2_inode *dip, uint32_t index, kfree(lp); /* Compute the divider */ - divider = (start + half_len) << (32 - dip->i_di.di_depth); /* Copy the entries */ - dirent_first(dip, obh, &dent); do { @@ -984,48 +961,37 @@ static int dir_split_leaf(struct gfs2_inode *dip, uint32_t index, if (dent->de_inum.no_addr && be32_to_cpu(dent->de_hash) < divider) { - name_len = be16_to_cpu(dent->de_name_len); - - gfs2_dirent_alloc(dip, nbh, name_len, &new); + struct qstr str; + str.name = (char*)(dent+1); + str.len = be16_to_cpu(dent->de_name_len); + str.hash = be32_to_cpu(dent->de_hash); + new = gfs2_dirent_alloc(dip->i_vnode, nbh, &str); + if (IS_ERR(new)) { + error = PTR_ERR(new); + break; + } new->de_inum = dent->de_inum; /* No endian worries */ - new->de_hash = dent->de_hash; /* No endian worries */ new->de_type = dent->de_type; /* No endian worries */ - memcpy((char *)(new + 1), (char *)(dent + 1), - name_len); - - nleaf->lf_entries = be16_to_cpu(nleaf->lf_entries)+1; - nleaf->lf_entries = cpu_to_be16(nleaf->lf_entries); + nleaf->lf_entries = cpu_to_be16(be16_to_cpu(nleaf->lf_entries)+1); dirent_del(dip, obh, prev, dent); if (!oleaf->lf_entries) gfs2_consist_inode(dip); - oleaf->lf_entries = be16_to_cpu(oleaf->lf_entries)-1; - oleaf->lf_entries = cpu_to_be16(oleaf->lf_entries); + oleaf->lf_entries = cpu_to_be16(be16_to_cpu(oleaf->lf_entries)-1); if (!prev) prev = dent; moved = 1; - } else + } else { prev = dent; - + } dent = next; - } - while (dent); - - /* If none of the entries got moved into the new leaf, - artificially fill in the first entry. */ - - if (!moved) { - gfs2_dirent_alloc(dip, nbh, 0, &new); - new->de_inum.no_addr = 0; - } + } while (dent); - oleaf->lf_depth = be16_to_cpu(oleaf->lf_depth) + 1; - oleaf->lf_depth = cpu_to_be16(oleaf->lf_depth); - nleaf->lf_depth = oleaf->lf_depth; + oleaf->lf_depth = nleaf->lf_depth; error = gfs2_meta_inode_buffer(dip, &dibh); if (!gfs2_assert_withdraw(dip->i_sbd, !error)) { @@ -1142,12 +1108,10 @@ static int compare_dents(const void *a, const void *b) int ret = 0; dent_a = *(struct gfs2_dirent **)a; - hash_a = dent_a->de_hash; - hash_a = be32_to_cpu(hash_a); + hash_a = be32_to_cpu(dent_a->de_hash); dent_b = *(struct gfs2_dirent **)b; - hash_b = dent_b->de_hash; - hash_b = be32_to_cpu(hash_b); + hash_b = be32_to_cpu(dent_b->de_hash); if (hash_a > hash_b) ret = 1; @@ -1292,8 +1256,7 @@ static int do_filldir_single(struct gfs2_inode *dip, uint64_t *offset, goto out; } darr[e++] = de; - } - while (dirent_next(dip, bh, &de) == 0); + } while (dirent_next(dip, bh, &de) == 0); if (e != entries) { gfs2_consist_inode(dip); @@ -1341,11 +1304,9 @@ static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset, leaf = (struct gfs2_leaf *)bh->b_data; entries = be16_to_cpu(leaf->lf_entries); - ln = leaf->lf_next; + ln = be64_to_cpu(leaf->lf_next); while (ln) { - ln = be64_to_cpu(ln); - error = get_leaf(dip, ln, &tmp_bh); if (error) return error; @@ -1355,7 +1316,7 @@ static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset, entries += be16_to_cpu(leaf->lf_entries); leaves++; } - ln = leaf->lf_next; + ln = be64_to_cpu(leaf->lf_next); brelse(tmp_bh); } @@ -1387,14 +1348,11 @@ static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset, goto out; } darr[e++] = de; - } - while (dirent_next(dip, bh, &de) == 0); + } while (dirent_next(dip, bh, &de) == 0); } - ln = leaf->lf_next; + ln = be64_to_cpu(leaf->lf_next); while (ln) { - ln = be64_to_cpu(ln); - error = get_leaf(dip, ln, &tmp_bh); if (error) goto out; @@ -1411,14 +1369,13 @@ static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset, goto out; } darr[e++] = de; - } - while (dirent_next(dip, tmp_bh, &de) == 0); + } while (dirent_next(dip, tmp_bh, &de) == 0); larr[l++] = tmp_bh; - ln = leaf->lf_next; + ln = be64_to_cpu(leaf->lf_next); } else { - ln = leaf->lf_next; + ln = be64_to_cpu(leaf->lf_next); brelse(tmp_bh); } } @@ -1446,228 +1403,27 @@ static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset, } /** - * dir_e_search - Search exhash (leaf) dir for inode matching name - * @dip: The GFS2 inode - * @filename: Filename string - * @inode: If non-NULL, function fills with formal inode # and block address - * @type: If non-NULL, function fills with DT_... dinode type + * dir_e_read - Reads the entries from a directory into a filldir buffer + * @dip: dinode pointer + * @offset: the hash of the last entry read shifted to the right once + * @opaque: buffer for the filldir function to fill + * @filldir: points to the filldir function to use * - * Returns: + * Returns: errno */ -static int dir_e_search(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_inum *inum, unsigned int *type) +static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, + gfs2_filldir_t filldir) { + struct gfs2_sbd *sdp = dip->i_sbd; struct buffer_head *bh; - struct gfs2_dirent *dent; - int error; - - error = linked_leaf_search(dip, filename, &dent, NULL, &bh); - if (error) - return error; - - if (inum) - gfs2_inum_in(inum, (char *)&dent->de_inum); - if (type) - *type = be16_to_cpu(dent->de_type); - - brelse(bh); - - return 0; -} - -static int dir_e_add(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_inum *inum, unsigned int type) -{ - struct buffer_head *bh, *nbh, *dibh; - struct gfs2_leaf *leaf, *nleaf; - struct gfs2_dirent *dent; - uint32_t hsize, index; - uint32_t hash; - uint64_t leaf_no, bn; - int error; - - restart: - hsize = 1 << dip->i_di.di_depth; - if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { - gfs2_consist_inode(dip); - return -EIO; - } - - /* Figure out the address of the leaf node. */ - - hash = gfs2_disk_hash(filename->name, filename->len); - index = hash >> (32 - dip->i_di.di_depth); - - error = get_leaf_nr(dip, index, &leaf_no); - if (error) - return error; - - /* Add entry to the leaf */ - - for (;;) { - error = get_leaf(dip, leaf_no, &bh); - if (error) - return error; - - leaf = (struct gfs2_leaf *)bh->b_data; - - if (gfs2_dirent_alloc(dip, bh, filename->len, &dent)) { - - if (be16_to_cpu(leaf->lf_depth) < dip->i_di.di_depth) { - /* Can we split the leaf? */ - - brelse(bh); - - error = dir_split_leaf(dip, index, leaf_no); - if (error) - return error; - - goto restart; - - } else if (dip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) { - /* Can we double the hash table? */ - - brelse(bh); - - error = dir_double_exhash(dip); - if (error) - return error; - - goto restart; - - } else if (leaf->lf_next) { - /* Can we try the next leaf in the list? */ - leaf_no = be64_to_cpu(leaf->lf_next); - brelse(bh); - continue; - - } else { - /* Create a new leaf and add it to the list. */ - - bn = gfs2_alloc_meta(dip); - - nbh = gfs2_meta_new(dip->i_gl, bn); - gfs2_trans_add_bh(dip->i_gl, nbh, 1); - gfs2_metatype_set(nbh, - GFS2_METATYPE_LF, - GFS2_FORMAT_LF); - gfs2_buffer_clear_tail(nbh, - sizeof(struct gfs2_meta_header)); - - gfs2_trans_add_bh(dip->i_gl, bh, 1); - leaf->lf_next = cpu_to_be64(bn); - - nleaf = (struct gfs2_leaf *)nbh->b_data; - nleaf->lf_depth = leaf->lf_depth; - nleaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); - - gfs2_dirent_alloc(dip, nbh, filename->len, - &dent); - - dip->i_di.di_blocks++; - - brelse(bh); - - bh = nbh; - leaf = nleaf; - } - } - - /* If the gfs2_dirent_alloc() succeeded, it pinned the "bh" */ - - gfs2_inum_out(inum, (char *)&dent->de_inum); - dent->de_hash = cpu_to_be32(hash); - dent->de_type = cpu_to_be16(type); - memcpy((char *)(dent + 1), filename->name, filename->len); - - leaf->lf_entries = be16_to_cpu(leaf->lf_entries) + 1; - leaf->lf_entries = cpu_to_be16(leaf->lf_entries); - - brelse(bh); - - error = gfs2_meta_inode_buffer(dip, &dibh); - if (error) - return error; - - dip->i_di.di_entries++; - dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - - gfs2_trans_add_bh(dip->i_gl, dibh, 1); - gfs2_dinode_out(&dip->i_di, dibh->b_data); - brelse(dibh); - - return 0; - } - - return -ENOENT; -} - -static int dir_e_del(struct gfs2_inode *dip, struct qstr *filename) -{ - struct buffer_head *bh, *dibh; - struct gfs2_dirent *dent, *prev; - struct gfs2_leaf *leaf; - unsigned int entries; - int error; - - error = linked_leaf_search(dip, filename, &dent, &prev, &bh); - if (error == -ENOENT) { - gfs2_consist_inode(dip); - return -EIO; - } - if (error) - return error; - - dirent_del(dip, bh, prev, dent); /* Pins bh */ - - leaf = (struct gfs2_leaf *)bh->b_data; - entries = be16_to_cpu(leaf->lf_entries); - if (!entries) - gfs2_consist_inode(dip); - entries--; - leaf->lf_entries = cpu_to_be16(entries); - - brelse(bh); - - error = gfs2_meta_inode_buffer(dip, &dibh); - if (error) - return error; - - if (!dip->i_di.di_entries) - gfs2_consist_inode(dip); - dip->i_di.di_entries--; - dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - - gfs2_trans_add_bh(dip->i_gl, dibh, 1); - gfs2_dinode_out(&dip->i_di, dibh->b_data); - brelse(dibh); - - return 0; -} - -/** - * dir_e_read - Reads the entries from a directory into a filldir buffer - * @dip: dinode pointer - * @offset: the hash of the last entry read shifted to the right once - * @opaque: buffer for the filldir function to fill - * @filldir: points to the filldir function to use - * - * Returns: errno - */ - -static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, - gfs2_filldir_t filldir) -{ - struct gfs2_sbd *sdp = dip->i_sbd; - struct buffer_head *bh; - struct gfs2_leaf leaf; - uint32_t hsize, len; - uint32_t ht_offset, lp_offset, ht_offset_cur = -1; - uint32_t hash, index; - uint64_t *lp; - int copied = 0; - int error = 0; + struct gfs2_leaf *leaf; + uint32_t hsize, len; + uint32_t ht_offset, lp_offset, ht_offset_cur = -1; + uint32_t hash, index; + uint64_t *lp; + int copied = 0; + int error = 0; hsize = 1 << dip->i_di.di_depth; if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { @@ -1702,14 +1458,15 @@ static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, if (error) goto out; - gfs2_leaf_in(&leaf, bh->b_data); - - if (leaf.lf_next) + leaf = (struct gfs2_leaf *)bh->b_data; + if (leaf->lf_next) error = do_filldir_multi(dip, offset, opaque, filldir, bh, &copied); else error = do_filldir_single(dip, offset, opaque, filldir, - bh, leaf.lf_entries, &copied); + bh, + be16_to_cpu(leaf->lf_entries), + &copied); brelse(bh); @@ -1719,7 +1476,7 @@ static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, goto out; } - len = 1 << (dip->i_di.di_depth - leaf.lf_depth); + len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth)); index = (index & ~(len - 1)) + len; } @@ -1729,165 +1486,6 @@ static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, return error; } -static int dir_e_mvino(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_inum *inum, unsigned int new_type) -{ - struct buffer_head *bh, *dibh; - struct gfs2_dirent *dent; - int error; - - error = linked_leaf_search(dip, filename, &dent, NULL, &bh); - if (error == -ENOENT) { - gfs2_consist_inode(dip); - return -EIO; - } - if (error) - return error; - - gfs2_trans_add_bh(dip->i_gl, bh, 1); - - gfs2_inum_out(inum, (char *)&dent->de_inum); - dent->de_type = cpu_to_be16(new_type); - - brelse(bh); - - error = gfs2_meta_inode_buffer(dip, &dibh); - if (error) - return error; - - dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - - gfs2_trans_add_bh(dip->i_gl, dibh, 1); - gfs2_dinode_out(&dip->i_di, dibh->b_data); - brelse(dibh); - - return 0; -} - -/** - * dir_l_search - Search linear (stuffed dinode) dir for inode matching name - * @dip: The GFS2 inode - * @filename: Filename string - * @inode: If non-NULL, function fills with formal inode # and block address - * @type: If non-NULL, function fills with DT_... dinode type - * - * Returns: - */ - -static int dir_l_search(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_inum *inum, unsigned int *type) -{ - struct buffer_head *dibh; - struct gfs2_dirent *dent; - int error; - - if (!gfs2_is_stuffed(dip)) { - gfs2_consist_inode(dip); - return -EIO; - } - - error = gfs2_meta_inode_buffer(dip, &dibh); - if (error) - return error; - - error = leaf_search(dip, dibh, filename, &dent, NULL); - if (!error) { - if (inum) - gfs2_inum_in(inum, (char *)&dent->de_inum); - if (type) - *type = be16_to_cpu(dent->de_type); - } - - brelse(dibh); - - return error; -} - -static int dir_l_add(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_inum *inum, unsigned int type) -{ - struct buffer_head *dibh; - struct gfs2_dirent *dent; - int error; - - if (!gfs2_is_stuffed(dip)) { - gfs2_consist_inode(dip); - return -EIO; - } - - error = gfs2_meta_inode_buffer(dip, &dibh); - if (error) - return error; - - if (gfs2_dirent_alloc(dip, dibh, filename->len, &dent)) { - brelse(dibh); - - error = dir_make_exhash(dip); - if (!error) - error = dir_e_add(dip, filename, inum, type); - - return error; - } - - /* gfs2_dirent_alloc() pins */ - - gfs2_inum_out(inum, (char *)&dent->de_inum); - dent->de_hash = gfs2_disk_hash(filename->name, filename->len); - dent->de_hash = cpu_to_be32(dent->de_hash); - dent->de_type = cpu_to_be16(type); - memcpy((char *)(dent + 1), filename->name, filename->len); - - dip->i_di.di_entries++; - dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - - gfs2_dinode_out(&dip->i_di, dibh->b_data); - brelse(dibh); - - return 0; -} - -static int dir_l_del(struct gfs2_inode *dip, struct qstr *filename) -{ - struct buffer_head *dibh; - struct gfs2_dirent *dent, *prev; - int error; - - if (!gfs2_is_stuffed(dip)) { - gfs2_consist_inode(dip); - return -EIO; - } - - error = gfs2_meta_inode_buffer(dip, &dibh); - if (error) - return error; - - error = leaf_search(dip, dibh, filename, &dent, &prev); - if (error == -ENOENT) { - gfs2_consist_inode(dip); - error = -EIO; - goto out; - } - if (error) - goto out; - - dirent_del(dip, dibh, prev, dent); - - /* dirent_del() pins */ - - if (!dip->i_di.di_entries) - gfs2_consist_inode(dip); - dip->i_di.di_entries--; - - dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - - gfs2_dinode_out(&dip->i_di, dibh->b_data); - - out: - brelse(dibh); - - return error; -} - static int dir_l_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, gfs2_filldir_t filldir) { @@ -1919,46 +1517,6 @@ static int dir_l_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, return error; } -static int dir_l_mvino(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_inum *inum, unsigned int new_type) -{ - struct buffer_head *dibh; - struct gfs2_dirent *dent; - int error; - - if (!gfs2_is_stuffed(dip)) { - gfs2_consist_inode(dip); - return -EIO; - } - - error = gfs2_meta_inode_buffer(dip, &dibh); - if (error) - return error; - - error = leaf_search(dip, dibh, filename, &dent, NULL); - if (error == -ENOENT) { - gfs2_consist_inode(dip); - error = -EIO; - goto out; - } - if (error) - goto out; - - gfs2_trans_add_bh(dip->i_gl, dibh, 1); - - gfs2_inum_out(inum, (char *)&dent->de_inum); - dent->de_type = cpu_to_be16(new_type); - - dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - - gfs2_dinode_out(&dip->i_di, dibh->b_data); - - out: - brelse(dibh); - - return error; -} - /** * gfs2_dir_search - Search a directory * @dip: The GFS2 inode @@ -1971,17 +1529,69 @@ static int dir_l_mvino(struct gfs2_inode *dip, struct qstr *filename, * Returns: errno */ -int gfs2_dir_search(struct gfs2_inode *dip, struct qstr *filename, +int gfs2_dir_search(struct inode *dir, const struct qstr *name, struct gfs2_inum *inum, unsigned int *type) { + struct buffer_head *bh; + struct gfs2_dirent *dent; + + dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh); + if (dent) { + if (IS_ERR(dent)) + return PTR_ERR(dent); + if (inum) + gfs2_inum_in(inum, (char *)&dent->de_inum); + if (type) + *type = be16_to_cpu(dent->de_type); + brelse(bh); + return 0; + } + return -ENOENT; +} + +static int dir_new_leaf(struct inode *inode, const struct qstr *name) +{ + struct buffer_head *bh, *obh; + struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_leaf *leaf, *oleaf; int error; + u32 index; + u64 bn; - if (dip->i_di.di_flags & GFS2_DIF_EXHASH) - error = dir_e_search(dip, filename, inum, type); - else - error = dir_l_search(dip, filename, inum, type); + index = name->hash >> (32 - ip->i_di.di_depth); + error = get_first_leaf(ip, index, &obh); + if (error) + return error; + do { + oleaf = (struct gfs2_leaf *)obh->b_data; + bn = be64_to_cpu(oleaf->lf_next); + if (!bn) + break; + brelse(obh); + error = get_leaf(ip, bn, &obh); + if (error) + return error; + } while(1); - return error; + gfs2_trans_add_bh(ip->i_gl, obh, 1); + + leaf = new_leaf(inode, &bh, be16_to_cpu(oleaf->lf_depth)); + if (!leaf) { + brelse(obh); + return -ENOSPC; + } + oleaf->lf_next = cpu_to_be64(bn); + brelse(bh); + brelse(obh); + + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + return error; + gfs2_trans_add_bh(ip->i_gl, bh, 1); + ip->i_di.di_blocks++; + gfs2_dinode_out(&ip->i_di, bh->b_data); + brelse(bh); + return 0; } /** @@ -1994,19 +1604,70 @@ int gfs2_dir_search(struct gfs2_inode *dip, struct qstr *filename, * Returns: 0 on success, error code on failure */ -int gfs2_dir_add(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_inum *inum, unsigned int type) +int gfs2_dir_add(struct inode *inode, const struct qstr *name, + const struct gfs2_inum *inum, unsigned type) { + struct gfs2_inode *ip = inode->u.generic_ip; + struct buffer_head *bh; + struct gfs2_dirent *dent; + struct gfs2_leaf *leaf; int error; - if (dip->i_di.di_flags & GFS2_DIF_EXHASH) - error = dir_e_add(dip, filename, inum, type); - else - error = dir_l_add(dip, filename, inum, type); - + while(1) { + dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, + &bh); + if (dent) { + if (IS_ERR(dent)) + return PTR_ERR(dent); + dent = gfs2_init_dirent(inode, dent, name, bh); + gfs2_inum_out(inum, (char *)&dent->de_inum); + dent->de_type = cpu_to_be16(type); + if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { + leaf = (struct gfs2_leaf *)bh->b_data; + leaf->lf_entries = cpu_to_be16(be16_to_cpu(leaf->lf_entries) + 1); + } + brelse(bh); + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + break; + gfs2_trans_add_bh(ip->i_gl, bh, 1); + ip->i_di.di_entries++; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + gfs2_dinode_out(&ip->i_di, bh->b_data); + brelse(bh); + error = 0; + break; + } + if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH)) { + error = dir_make_exhash(inode); + if (error) + break; + continue; + } + error = dir_split_leaf(inode, name); + if (error == 0) + continue; + if (error != -ENOSPC) + break; + if (ip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) { + error = dir_double_exhash(ip); + if (error) + break; + error = dir_split_leaf(inode, name); + if (error) + break; + continue; + } + error = dir_new_leaf(inode, name); + if (!error) + continue; + error = -ENOSPC; + break; + } return error; } + /** * gfs2_dir_del - Delete a directory entry * @dip: The GFS2 inode @@ -2015,14 +1676,50 @@ int gfs2_dir_add(struct gfs2_inode *dip, struct qstr *filename, * Returns: 0 on success, error code on failure */ -int gfs2_dir_del(struct gfs2_inode *dip, struct qstr *filename) +int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) { + struct gfs2_dirent *dent, *prev = NULL; + struct buffer_head *bh; int error; - if (dip->i_di.di_flags & GFS2_DIF_EXHASH) - error = dir_e_del(dip, filename); - else - error = dir_l_del(dip, filename); + /* Returns _either_ the entry (if its first in block) or the + previous entry otherwise */ + dent = gfs2_dirent_search(dip->i_vnode, name, gfs2_dirent_prev, &bh); + if (!dent) { + gfs2_consist_inode(dip); + return -EIO; + } + if (IS_ERR(dent)) { + gfs2_consist_inode(dip); + return PTR_ERR(dent); + } + /* If not first in block, adjust pointers accordingly */ + if (gfs2_dirent_find(dent, name) == 0) { + prev = dent; + dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len)); + } + + dirent_del(dip, bh, prev, dent); + if (dip->i_di.di_flags & GFS2_DIF_EXHASH) { + struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data; + u16 entries = be16_to_cpu(leaf->lf_entries); + if (!entries) + gfs2_consist_inode(dip); + leaf->lf_entries = cpu_to_be16(--entries); + brelse(bh); + } + + error = gfs2_meta_inode_buffer(dip, &bh); + if (error) + return error; + + if (!dip->i_di.di_entries) + gfs2_consist_inode(dip); + gfs2_trans_add_bh(dip->i_gl, bh, 1); + dip->i_di.di_entries--; + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + gfs2_dinode_out(&dip->i_di, bh->b_data); + brelse(bh); return error; } @@ -2053,17 +1750,37 @@ int gfs2_dir_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, * Returns: errno */ -int gfs2_dir_mvino(struct gfs2_inode *dip, struct qstr *filename, +int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, struct gfs2_inum *inum, unsigned int new_type) { + struct buffer_head *bh; + struct gfs2_dirent *dent; int error; - if (dip->i_di.di_flags & GFS2_DIF_EXHASH) - error = dir_e_mvino(dip, filename, inum, new_type); - else - error = dir_l_mvino(dip, filename, inum, new_type); + dent = gfs2_dirent_search(dip->i_vnode, filename, gfs2_dirent_find, &bh); + if (!dent) { + gfs2_consist_inode(dip); + return -EIO; + } + if (IS_ERR(dent)) + return PTR_ERR(dent); - return error; + gfs2_trans_add_bh(dip->i_gl, bh, 1); + gfs2_inum_out(inum, (char *)&dent->de_inum); + dent->de_type = cpu_to_be16(new_type); + + if (dip->i_di.di_flags & GFS2_DIF_EXHASH) { + brelse(bh); + error = gfs2_meta_inode_buffer(dip, &bh); + if (error) + return error; + gfs2_trans_add_bh(dip->i_gl, bh, 1); + } + + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + gfs2_dinode_out(&dip->i_di, bh->b_data); + brelse(bh); + return 0; } /** @@ -2079,7 +1796,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) { struct gfs2_sbd *sdp = dip->i_sbd; struct buffer_head *bh; - struct gfs2_leaf leaf; + struct gfs2_leaf *leaf; uint32_t hsize, len; uint32_t ht_offset, lp_offset, ht_offset_cur = -1; uint32_t index = 0; @@ -2118,10 +1835,10 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) error = get_leaf(dip, leaf_no, &bh); if (error) goto out; - gfs2_leaf_in(&leaf, bh->b_data); + leaf = (struct gfs2_leaf *)bh->b_data; brelse(bh); - len = 1 << (dip->i_di.di_depth - leaf.lf_depth); + len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth)); error = lc(dip, index, len, leaf_no, data); if (error) @@ -2158,10 +1875,10 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, uint64_t leaf_no, void *data) { struct gfs2_sbd *sdp = dip->i_sbd; - struct gfs2_leaf tmp_leaf; + struct gfs2_leaf *tmp_leaf; struct gfs2_rgrp_list rlist; struct buffer_head *bh, *dibh; - uint64_t blk; + uint64_t blk, nblk; unsigned int rg_blocks = 0, l_blocks = 0; char *ht; unsigned int x, size = len * sizeof(uint64_t); @@ -2185,11 +1902,12 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, /* Count the number of leaves */ - for (blk = leaf_no; blk; blk = tmp_leaf.lf_next) { + for (blk = leaf_no; blk; blk = nblk) { error = get_leaf(dip, blk, &bh); if (error) goto out_rlist; - gfs2_leaf_in(&tmp_leaf, (bh)->b_data); + tmp_leaf = (struct gfs2_leaf *)bh->b_data; + nblk = be64_to_cpu(tmp_leaf->lf_next); brelse(bh); gfs2_rlist_add(sdp, &rlist, blk); @@ -2214,11 +1932,12 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, if (error) goto out_rg_gunlock; - for (blk = leaf_no; blk; blk = tmp_leaf.lf_next) { + for (blk = leaf_no; blk; blk = nblk) { error = get_leaf(dip, blk, &bh); if (error) goto out_end_trans; - gfs2_leaf_in(&tmp_leaf, bh->b_data); + tmp_leaf = (struct gfs2_leaf *)bh->b_data; + nblk = be64_to_cpu(tmp_leaf->lf_next); brelse(bh); gfs2_free_meta(dip, blk, 1); @@ -2308,63 +2027,22 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) * gfs2_diradd_alloc_required - find if adding entry will require an allocation * @ip: the file being written to * @filname: the filename that's going to be added - * @alloc_required: set to 1 if an alloc is required, 0 otherwise * - * Returns: errno + * Returns: 1 if alloc required, 0 if not, -ve on error */ -int gfs2_diradd_alloc_required(struct gfs2_inode *dip, struct qstr *filename, - int *alloc_required) +int gfs2_diradd_alloc_required(struct inode *inode, + const struct qstr *name) { - struct buffer_head *bh = NULL, *bh_next; - uint32_t hsize, hash, index; - int error = 0; - - *alloc_required = 0; - - if (dip->i_di.di_flags & GFS2_DIF_EXHASH) { - hsize = 1 << dip->i_di.di_depth; - if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { - gfs2_consist_inode(dip); - return -EIO; - } - - hash = gfs2_disk_hash(filename->name, filename->len); - index = hash >> (32 - dip->i_di.di_depth); - - error = get_first_leaf(dip, index, &bh_next); - if (error) - return error; - - do { - brelse(bh); - - bh = bh_next; - - if (dirent_fits(dip, bh, filename->len)) - break; - - error = get_next_leaf(dip, bh, &bh_next); - if (error == -ENOENT) { - *alloc_required = 1; - error = 0; - break; - } - } - while (!error); - - brelse(bh); - } else { - error = gfs2_meta_inode_buffer(dip, &bh); - if (error) - return error; - - if (!dirent_fits(dip, bh, filename->len)) - *alloc_required = 1; - - brelse(bh); - } + struct gfs2_dirent *dent; + struct buffer_head *bh; - return error; + dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh); + if (!dent) + return 1; + if (IS_ERR(dent)) + return PTR_ERR(dent); + brelse(bh); + return 0; } diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index 5b01497b3ab3..8fd4dc0f700e 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -27,25 +27,34 @@ typedef int (*gfs2_filldir_t) (void *opaque, uint64_t offset, struct gfs2_inum *inum, unsigned int type); -int gfs2_filecmp(struct qstr *file1, char *file2, int len_of_file2); -int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh, - int name_len, struct gfs2_dirent **dent_out); - -int gfs2_dir_search(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_inum *inum, unsigned int *type); -int gfs2_dir_add(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_inum *inum, unsigned int type); -int gfs2_dir_del(struct gfs2_inode *dip, struct qstr *filename); +int gfs2_dir_search(struct inode *dir, const struct qstr *filename, + struct gfs2_inum *inum, unsigned int *type); +int gfs2_dir_add(struct inode *inode, const struct qstr *filename, + const struct gfs2_inum *inum, unsigned int type); +int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename); int gfs2_dir_read(struct gfs2_inode *dip, uint64_t * offset, void *opaque, - gfs2_filldir_t filldir); -int gfs2_dir_mvino(struct gfs2_inode *dip, struct qstr *filename, - struct gfs2_inum *new_inum, unsigned int new_type); + gfs2_filldir_t filldir); +int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, + struct gfs2_inum *new_inum, unsigned int new_type); int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip); -int gfs2_diradd_alloc_required(struct gfs2_inode *dip, struct qstr *filename, - int *alloc_required); +int gfs2_diradd_alloc_required(struct inode *dir, + const struct qstr *filename); int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, - struct buffer_head **bhp); + struct buffer_head **bhp); + +/* N.B. This probably ought to take inum & type as args as well */ +static inline void gfs2_qstr2dirent(const struct qstr *name, u16 reclen, struct gfs2_dirent *dent) +{ + dent->de_inum.no_addr = cpu_to_be64(0); + dent->de_inum.no_formal_ino = cpu_to_be64(0); + dent->de_hash = cpu_to_be32(name->hash); + dent->de_rec_len = cpu_to_be16(reclen); + dent->de_name_len = cpu_to_be16(name->len); + dent->de_type = cpu_to_be16(0); + memset(dent->__pad, 0, sizeof(dent->__pad)); + memcpy((char*)(dent+1), name->name, name->len); +} #endif /* __DIR_DOT_H__ */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index cd1de61bff2f..d403d51d5b0f 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -228,12 +228,10 @@ struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum) void gfs2_inode_min_init(struct gfs2_inode *ip, unsigned int type) { - spin_lock(&ip->i_spin); if (!test_and_set_bit(GIF_MIN_INIT, &ip->i_flags)) { ip->i_di.di_nlink = 1; ip->i_di.di_mode = DT2IF(type); } - spin_unlock(&ip->i_spin); } /** @@ -257,10 +255,8 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) return -EIO; } - spin_lock(&ip->i_spin); gfs2_dinode_in(&ip->i_di, dibh->b_data); set_bit(GIF_MIN_INIT, &ip->i_flags); - spin_unlock(&ip->i_spin); brelse(dibh); @@ -702,6 +698,16 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) return 0; } +struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) +{ + struct qstr qstr; + qstr.name = name; + qstr.len = strlen(name); + qstr.hash = gfs2_disk_hash(qstr.name, qstr.len); + return gfs2_lookupi(dip, &qstr, 1, NULL); +} + + /** * gfs2_lookupi - Look up a filename in a directory and return its inode * @d_gh: An initialized holder for the directory glock @@ -715,8 +721,9 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) * Returns: errno */ -int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, - struct inode **inodep) +struct inode *gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, + struct nameidata *nd) + { struct super_block *sb = dir->i_sb; struct gfs2_inode *ipp; @@ -727,14 +734,14 @@ int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, unsigned int type; struct gfs2_glock *gl; int error = 0; - - *inodep = NULL; + struct inode *inode = NULL; if (!name->len || name->len > GFS2_FNAMESIZE) - return -ENAMETOOLONG; + return ERR_PTR(-ENAMETOOLONG); - if (gfs2_filecmp(name, ".", 1) || - (gfs2_filecmp(name, "..", 2) && dir == sb->s_root->d_inode)) { + if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) || + (name->len == 2 && memcmp(name->name, "..", 2) == 0 && + dir == sb->s_root->d_inode)) { gfs2_inode_hold(dip); ipp = dip; goto done; @@ -742,7 +749,7 @@ int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); if (error) - return error; + return ERR_PTR(error); if (!is_root) { error = gfs2_repermission(dip->i_vnode, MAY_EXEC, NULL); @@ -750,7 +757,7 @@ int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, goto out; } - error = gfs2_dir_search(dip, name, &inum, &type); + error = gfs2_dir_search(dir, name, &inum, &type); if (error) goto out; @@ -768,13 +775,16 @@ int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, out: gfs2_glock_dq_uninit(&d_gh); done: + if (error == -ENOENT) + return NULL; if (error == 0) { - *inodep = gfs2_ip2v(ipp); - if (!*inodep) - error = -ENOMEM; + inode = gfs2_ip2v(ipp); gfs2_inode_put(ipp); + if (!inode) + return ERR_PTR(-ENOMEM); + return inode; } - return error; + return ERR_PTR(error); } static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) @@ -918,7 +928,7 @@ static int create_ok(struct gfs2_inode *dip, struct qstr *name, if (!dip->i_di.di_nlink) return -EPERM; - error = gfs2_dir_search(dip, name, NULL, NULL); + error = gfs2_dir_search(dip->i_vnode, name, NULL, NULL); switch (error) { case -ENOENT: error = 0; @@ -1116,7 +1126,9 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, if (error) goto fail; - error = gfs2_diradd_alloc_required(dip, name, &alloc_required); + error = alloc_required = gfs2_diradd_alloc_required(dip->i_vnode, name); + if (alloc_required < 0) + goto fail; if (alloc_required) { error = gfs2_quota_check(dip, dip->i_di.di_uid, dip->i_di.di_gid); @@ -1145,7 +1157,7 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, goto fail_quota_locks; } - error = gfs2_dir_add(dip, name, &ip->i_num, IF2DT(ip->i_di.di_mode)); + error = gfs2_dir_add(dip->i_vnode, name, &ip->i_num, IF2DT(ip->i_di.di_mode)); if (error) goto fail_end_trans; @@ -1379,12 +1391,14 @@ int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, dotname.len = 1; dotname.name = "."; + dotname.hash = gfs2_disk_hash(dotname.name, dotname.len); error = gfs2_dir_del(ip, &dotname); if (error) return error; dotname.len = 2; dotname.name = ".."; + dotname.hash = gfs2_disk_hash(dotname.name, dotname.len); error = gfs2_dir_del(ip, &dotname); if (error) return error; @@ -1439,7 +1453,7 @@ int gfs2_unlink_ok(struct gfs2_inode *dip, struct qstr *name, if (error) return error; - error = gfs2_dir_search(dip, name, &inum, &type); + error = gfs2_dir_search(dip->i_vnode, name, &inum, &type); if (error) return error; @@ -1476,6 +1490,7 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) memset(&dotdot, 0, sizeof(struct qstr)); dotdot.name = ".."; dotdot.len = 2; + dotdot.hash = gfs2_disk_hash(dotdot.name, dotdot.len); igrab(dir); @@ -1489,9 +1504,11 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) break; } - error = gfs2_lookupi(dir, &dotdot, 1, &tmp); - if (error) + tmp = gfs2_lookupi(dir, &dotdot, 1, NULL); + if (IS_ERR(tmp)) { + error = PTR_ERR(tmp); break; + } iput(dir); dir = tmp; diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index c3fa6cfce169..0dd2a26626ec 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -44,8 +44,8 @@ void gfs2_inode_destroy(struct gfs2_inode *ip); int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); int gfs2_change_nlink(struct gfs2_inode *ip, int diff); -int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, - struct inode **ipp); +struct inode *gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, + struct nameidata *nd); struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode); int gfs2_unlinki(struct gfs2_inode *dip, struct qstr *name, @@ -66,17 +66,7 @@ int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); int gfs2_repermission(struct inode *inode, int mask, struct nameidata *nd); -static inline int gfs2_lookup_simple(struct inode *dip, char *name, - struct inode **ipp) -{ - struct qstr qstr; - int err; - memset(&qstr, 0, sizeof(struct qstr)); - qstr.name = name; - qstr.len = strlen(name); - err = gfs2_lookupi(dip, &qstr, 1, ipp); - return err; -} +struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); #endif /* __INODE_DOT_H__ */ diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 5a0bdc22a1f4..3be060f1cbe7 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -64,7 +64,7 @@ void gfs2_inum_in(struct gfs2_inum *no, char *buf) no->no_addr = be64_to_cpu(str->no_addr); } -void gfs2_inum_out(struct gfs2_inum *no, char *buf) +void gfs2_inum_out(const struct gfs2_inum *no, char *buf) { struct gfs2_inum *str = (struct gfs2_inum *)buf; @@ -342,17 +342,6 @@ void gfs2_dirent_print(struct gfs2_dirent *de, char *name) printk(KERN_INFO " name = %s\n", buf); } -void gfs2_leaf_in(struct gfs2_leaf *lf, char *buf) -{ - struct gfs2_leaf *str = (struct gfs2_leaf *)buf; - - gfs2_meta_header_in(&lf->lf_header, buf); - lf->lf_depth = be16_to_cpu(str->lf_depth); - lf->lf_entries = be16_to_cpu(str->lf_entries); - lf->lf_dirent_format = be32_to_cpu(str->lf_dirent_format); - lf->lf_next = be64_to_cpu(str->lf_next); -} - void gfs2_leaf_print(struct gfs2_leaf *lf) { gfs2_meta_header_print(&lf->lf_header); diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index 7f6139288519..b54608f9df50 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -38,25 +38,26 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) { struct dentry *parent = dget_parent(dentry); + struct gfs2_sbd *sdp = parent->d_inode->i_sb->s_fs_info; struct gfs2_inode *dip = parent->d_inode->u.generic_ip; - struct inode *inode; + struct inode *inode = dentry->d_inode; struct gfs2_holder d_gh; struct gfs2_inode *ip; struct gfs2_inum inum; unsigned int type; int error; - lock_kernel(); - - inode = dentry->d_inode; if (inode && is_bad_inode(inode)) goto invalid; + if (sdp->sd_args.ar_localcaching) + goto valid; + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); if (error) goto fail; - error = gfs2_dir_search(dip, &dentry->d_name, &inum, &type); + error = gfs2_dir_search(parent->d_inode, &dentry->d_name, &inum, &type); switch (error) { case 0: if (!inode) @@ -84,7 +85,6 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) gfs2_glock_dq_uninit(&d_gh); valid: - unlock_kernel(); dput(parent); return 1; @@ -99,7 +99,6 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) } d_drop(dentry); - unlock_kernel(); dput(parent); return 0; @@ -107,12 +106,18 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) gfs2_glock_dq_uninit(&d_gh); fail: - unlock_kernel(); dput(parent); return 0; } +static int gfs2_dhash(struct dentry *dentry, struct qstr *str) +{ + str->hash = gfs2_disk_hash(str->name, str->len); + return 0; +} + struct dentry_operations gfs2_dops = { .d_revalidate = gfs2_drevalidate, + .d_hash = gfs2_dhash, }; diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index a346943363c6..b27bce74a795 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -24,6 +24,7 @@ #include "inode.h" #include "ops_export.h" #include "rgrp.h" +#include "util.h" static struct dentry *gfs2_decode_fh(struct super_block *sb, __u32 *fh, @@ -167,11 +168,15 @@ static struct dentry *gfs2_get_parent(struct dentry *child) struct qstr dotdot = { .name = "..", .len = 2 }; struct inode *inode; struct dentry *dentry; - int error; - error = gfs2_lookupi(child->d_inode, &dotdot, 1, &inode); - if (error) - return ERR_PTR(error); + dotdot.hash = gfs2_disk_hash(dotdot.name, dotdot.len); + + inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL); + + if (!inode) + return ERR_PTR(-ENOENT); + if (IS_ERR(inode)) + return ERR_PTR(PTR_ERR(inode)); dentry = d_alloc_anon(inode); if (!dentry) { diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 8d6d94143561..8d2c557b3ff4 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -379,11 +379,10 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) goto fail_recoverd; } - error = gfs2_lookup_simple(sdp->sd_master_dir, "jindex", - &sdp->sd_jindex); - if (error) { + sdp->sd_jindex = gfs2_lookup_simple(sdp->sd_master_dir, "jindex"); + if (IS_ERR(sdp->sd_jindex)) { fs_err(sdp, "can't lookup journal index: %d\n", error); - return error; + return PTR_ERR(sdp->sd_jindex); } ip = sdp->sd_jindex->u.generic_ip; set_bit(GLF_STICKY, &ip->i_gl->gl_flags); @@ -531,26 +530,26 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) goto fail_master; /* Read in the master inode number inode */ - error = gfs2_lookup_simple(sdp->sd_master_dir, "inum", - &sdp->sd_inum_inode); - if (error) { + sdp->sd_inum_inode = gfs2_lookup_simple(sdp->sd_master_dir, "inum"); + if (IS_ERR(sdp->sd_inum_inode)) { + error = PTR_ERR(sdp->sd_inum_inode); fs_err(sdp, "can't read in inum inode: %d\n", error); goto fail_journal; } /* Read in the master statfs inode */ - error = gfs2_lookup_simple(sdp->sd_master_dir, "statfs", - &sdp->sd_statfs_inode); - if (error) { + sdp->sd_statfs_inode = gfs2_lookup_simple(sdp->sd_master_dir, "statfs"); + if (IS_ERR(sdp->sd_statfs_inode)) { + error = PTR_ERR(sdp->sd_statfs_inode); fs_err(sdp, "can't read in statfs inode: %d\n", error); goto fail_inum; } /* Read in the resource index inode */ - error = gfs2_lookup_simple(sdp->sd_master_dir, "rindex", - &sdp->sd_rindex); - if (error) { + sdp->sd_rindex = gfs2_lookup_simple(sdp->sd_master_dir, "rindex"); + if (IS_ERR(sdp->sd_rindex)) { + error = PTR_ERR(sdp->sd_rindex); fs_err(sdp, "can't get resource index inode: %d\n", error); goto fail_statfs; } @@ -559,9 +558,9 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) sdp->sd_rindex_vn = ip->i_gl->gl_vn - 1; /* Read in the quota inode */ - error = gfs2_lookup_simple(sdp->sd_master_dir, "quota", - &sdp->sd_quota_inode); - if (error) { + sdp->sd_quota_inode = gfs2_lookup_simple(sdp->sd_master_dir, "quota"); + if (IS_ERR(sdp->sd_quota_inode)) { + error = PTR_ERR(sdp->sd_quota_inode); fs_err(sdp, "can't get quota file inode: %d\n", error); goto fail_rindex; } @@ -600,36 +599,41 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) if (undo) goto fail_qc_gh; - error = gfs2_lookup_simple(sdp->sd_master_dir, "per_node", &pn); - if (error) { + pn = gfs2_lookup_simple(sdp->sd_master_dir, "per_node"); + if (IS_ERR(pn)) { + error = PTR_ERR(pn); fs_err(sdp, "can't find per_node directory: %d\n", error); return error; } sprintf(buf, "inum_range%u", sdp->sd_jdesc->jd_jid); - error = gfs2_lookup_simple(pn, buf, &sdp->sd_ir_inode); - if (error) { + sdp->sd_ir_inode = gfs2_lookup_simple(pn, buf); + if (IS_ERR(sdp->sd_ir_inode)) { + error = PTR_ERR(sdp->sd_ir_inode); fs_err(sdp, "can't find local \"ir\" file: %d\n", error); goto fail; } sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid); - error = gfs2_lookup_simple(pn, buf, &sdp->sd_sc_inode); - if (error) { + sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf); + if (IS_ERR(sdp->sd_sc_inode)) { + error = PTR_ERR(sdp->sd_sc_inode); fs_err(sdp, "can't find local \"sc\" file: %d\n", error); goto fail_ir_i; } sprintf(buf, "unlinked_tag%u", sdp->sd_jdesc->jd_jid); - error = gfs2_lookup_simple(pn, buf, &sdp->sd_ut_inode); - if (error) { + sdp->sd_ut_inode = gfs2_lookup_simple(pn, buf); + if (IS_ERR(sdp->sd_ut_inode)) { + error = PTR_ERR(sdp->sd_ut_inode); fs_err(sdp, "can't find local \"ut\" file: %d\n", error); goto fail_sc_i; } sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid); - error = gfs2_lookup_simple(pn, buf, &sdp->sd_qc_inode); - if (error) { + sdp->sd_qc_inode = gfs2_lookup_simple(pn, buf); + if (IS_ERR(sdp->sd_qc_inode)) { + error = PTR_ERR(sdp->sd_qc_inode); fs_err(sdp, "can't find local \"qc\" file: %d\n", error); goto fail_ut_i; } diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 7633a8584b0d..e8ab9d254b76 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -58,7 +58,6 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, struct gfs2_holder ghs[2]; struct inode *inode; int new = 1; - int error; gfs2_holder_init(dip->i_gl, 0, 0, ghs); @@ -78,14 +77,16 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, return PTR_ERR(inode); } - error = gfs2_lookupi(dir, &dentry->d_name, 0, &inode); - if (!error) { - new = 0; - gfs2_holder_uninit(ghs); - break; - } else if (error != -ENOENT) { - gfs2_holder_uninit(ghs); - return error; + inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd); + if (inode) { + if (!IS_ERR(inode)) { + new = 0; + gfs2_holder_uninit(ghs); + break; + } else { + gfs2_holder_uninit(ghs); + return PTR_ERR(inode); + } } } @@ -110,17 +111,13 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - struct gfs2_inode *dip = dir->u.generic_ip; - struct gfs2_sbd *sdp = dip->i_sbd; struct inode *inode = NULL; - int error; - if (!sdp->sd_args.ar_localcaching) - dentry->d_op = &gfs2_dops; + dentry->d_op = &gfs2_dops; - error = gfs2_lookupi(dir, &dentry->d_name, 0, &inode); - if (error && error != -ENOENT) - return ERR_PTR(error); + inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd); + if (inode && IS_ERR(inode)) + return ERR_PTR(PTR_ERR(inode)); if (inode) return d_splice_alias(inode, dentry); @@ -166,7 +163,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (error) goto out_gunlock; - error = gfs2_dir_search(dip, &dentry->d_name, NULL, NULL); + error = gfs2_dir_search(dir, &dentry->d_name, NULL, NULL); switch (error) { case -ENOENT: break; @@ -192,10 +189,10 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (ip->i_di.di_nlink == (uint32_t)-1) goto out_gunlock; - error = gfs2_diradd_alloc_required(dip, &dentry->d_name, - &alloc_required); - if (error) + alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name); + if (error < 0) goto out_gunlock; + error = 0; if (alloc_required) { struct gfs2_alloc *al = gfs2_alloc_get(dip); @@ -228,7 +225,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, goto out_ipres; } - error = gfs2_dir_add(dip, &dentry->d_name, &ip->i_num, + error = gfs2_dir_add(dir, &dentry->d_name, &ip->i_num, IF2DT(ip->i_di.di_mode)); if (error) goto out_end_trans; @@ -419,24 +416,24 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (!gfs2_assert_withdraw(sdp, !error)) { struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; - struct gfs2_dirent *dent; - - gfs2_dirent_alloc(ip, dibh, 1, &dent); + struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1); + struct qstr str = { .name = ".", .len = 1 }; + str.hash = gfs2_disk_hash(str.name, str.len); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent); dent->de_inum = di->di_num; /* already GFS2 endian */ - dent->de_hash = gfs2_disk_hash(".", 1); - dent->de_hash = cpu_to_be32(dent->de_hash); dent->de_type = DT_DIR; - memcpy((char *) (dent + 1), ".", 1); di->di_entries = cpu_to_be32(1); - gfs2_dirent_alloc(ip, dibh, 2, &dent); + str.name = ".."; + str.len = 2; + str.hash = gfs2_disk_hash(str.name, str.len); + dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1)); + gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent); gfs2_inum_out(&dip->i_num, (char *) &dent->de_inum); - dent->de_hash = gfs2_disk_hash("..", 2); - dent->de_hash = cpu_to_be32(dent->de_hash); dent->de_type = DT_DIR; - memcpy((char *) (dent + 1), "..", 2); gfs2_dinode_out(&ip->i_di, (char *)di); @@ -687,7 +684,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (error) goto out_gunlock; - error = gfs2_dir_search(ndip, &ndentry->d_name, NULL, NULL); + error = gfs2_dir_search(ndir, &ndentry->d_name, NULL, NULL); switch (error) { case -ENOENT: error = 0; @@ -723,10 +720,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, goto out_gunlock; } - error = gfs2_diradd_alloc_required(ndip, &ndentry->d_name, - &alloc_required); - if (error) + alloc_required = error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name); + if (error < 0) goto out_gunlock; + error = 0; if (alloc_required) { struct gfs2_alloc *al = gfs2_alloc_get(ndip); @@ -777,6 +774,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, struct qstr name; name.len = 2; name.name = ".."; + name.hash = gfs2_disk_hash(name.name, name.len); error = gfs2_change_nlink(ndip, +1); if (error) @@ -803,7 +801,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (error) goto out_end_trans; - error = gfs2_dir_add(ndip, &ndentry->d_name, &ip->i_num, + error = gfs2_dir_add(ndir, &ndentry->d_name, &ip->i_num, IF2DT(ip->i_di.di_mode)); if (error) goto out_end_trans; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index fff5a96f4152..71cca7629403 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -299,8 +299,9 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) break; name.len = sprintf(buf, "journal%u", sdp->sd_journals); + name.hash = gfs2_disk_hash(name.name, name.len); - error = gfs2_dir_search(sdp->sd_jindex->u.generic_ip, + error = gfs2_dir_search(sdp->sd_jindex, &name, NULL, NULL); if (error == -ENOENT) { error = 0; @@ -317,8 +318,12 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) if (!jd) break; - error = gfs2_lookupi(sdp->sd_jindex, &name, 1, &jd->jd_inode); - if (error) { + jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL); + if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { + if (!jd->jd_inode) + error = -ENOENT; + else + error = PTR_ERR(jd->jd_inode); kfree(jd); break; } diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 8d4f0445df47..a5fb4f99aa45 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -411,7 +411,7 @@ struct gfs2_quota_change { /* Translation functions */ extern void gfs2_inum_in(struct gfs2_inum *no, char *buf); -extern void gfs2_inum_out(struct gfs2_inum *no, char *buf); +extern void gfs2_inum_out(const struct gfs2_inum *no, char *buf); extern void gfs2_sb_in(struct gfs2_sb *sb, char *buf); extern void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf); extern void gfs2_rindex_out(struct gfs2_rindex *ri, char *buf); @@ -421,7 +421,6 @@ extern void gfs2_quota_in(struct gfs2_quota *qu, char *buf); extern void gfs2_quota_out(struct gfs2_quota *qu, char *buf); extern void gfs2_dinode_in(struct gfs2_dinode *di, char *buf); extern void gfs2_dinode_out(struct gfs2_dinode *di, char *buf); -extern void gfs2_leaf_in(struct gfs2_leaf *lf, char *buf); extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, char *buf); extern void gfs2_ea_header_out(struct gfs2_ea_header *ea, char *buf); extern void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf); -- cgit v1.2.3 From 94aabbd99370f738da4f6cb4ea0b94cd9024002f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 21 Mar 2006 11:29:00 -0500 Subject: [GFS2] Remove ioctl support The various flags on inodes will in future be set and queried via the extended attributes interface, so this interface is no longer required. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 95 ---------------------------------------------- include/linux/gfs2_ioctl.h | 17 --------- 2 files changed, 112 deletions(-) delete mode 100644 include/linux/gfs2_ioctl.h (limited to 'include/linux') diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index d30c6db46241..6333a14cf77a 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -532,98 +531,6 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) return error; } -static int gfs2_ioctl_flags(struct gfs2_inode *ip, unsigned int cmd, - unsigned long arg) -{ - unsigned int lmode = (cmd == GFS2_IOCTL_SETFLAGS) ? - LM_ST_EXCLUSIVE : LM_ST_SHARED; - struct buffer_head *dibh; - struct gfs2_holder i_gh; - int error; - __u32 flags = 0, change; - - if (cmd == GFS2_IOCTL_SETFLAGS) { - error = get_user(flags, (__u32 __user *)arg); - if (error) - return -EFAULT; - } - - error = gfs2_glock_nq_init(ip->i_gl, lmode, 0, &i_gh); - if (error) - return error; - - if (cmd == GFS2_IOCTL_SETFLAGS) { - change = flags ^ ip->i_di.di_flags; - error = -EPERM; - if (change & (GFS2_DIF_IMMUTABLE|GFS2_DIF_APPENDONLY)) { - if (!capable(CAP_LINUX_IMMUTABLE)) - goto out; - } - error = -EINVAL; - if (flags & (GFS2_DIF_JDATA|GFS2_DIF_DIRECTIO)) { - if (!S_ISREG(ip->i_di.di_mode)) - goto out; - } - if (flags & - (GFS2_DIF_INHERIT_JDATA|GFS2_DIF_INHERIT_DIRECTIO)) { - if (!S_ISDIR(ip->i_di.di_mode)) - goto out; - } - - error = gfs2_trans_begin(ip->i_sbd, RES_DINODE, 0); - if (error) - goto out; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto out_trans_end; - - ip->i_di.di_flags = flags; - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); - - brelse(dibh); - -out_trans_end: - gfs2_trans_end(ip->i_sbd); - } else { - flags = ip->i_di.di_flags; - } -out: - gfs2_glock_dq_uninit(&i_gh); - if (cmd == GFS2_IOCTL_GETFLAGS) { - if (put_user(flags, (__u32 __user *)arg)) - return -EFAULT; - } - return error; -} - -/** - * gfs2_ioctl - do an ioctl on a file - * @inode: the inode - * @file: the file pointer - * @cmd: the ioctl command - * @arg: the argument - * - * Returns: errno - */ - -static int gfs2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct gfs2_inode *ip = inode->u.generic_ip; - - switch (cmd) { - case GFS2_IOCTL_SETFLAGS: - case GFS2_IOCTL_GETFLAGS: - return gfs2_ioctl_flags(ip, cmd, arg); - - default: - return -ENOTTY; - } -} - /** * gfs2_mmap - * @file: The file to map @@ -925,7 +832,6 @@ struct file_operations gfs2_file_fops = { .write = generic_file_write, .writev = generic_file_writev, .aio_write = generic_file_aio_write, - .ioctl = gfs2_ioctl, .mmap = gfs2_mmap, .open = gfs2_open, .release = gfs2_close, @@ -937,7 +843,6 @@ struct file_operations gfs2_file_fops = { struct file_operations gfs2_dir_fops = { .readdir = gfs2_readdir, - .ioctl = gfs2_ioctl, .open = gfs2_open, .release = gfs2_close, .fsync = gfs2_fsync, diff --git a/include/linux/gfs2_ioctl.h b/include/linux/gfs2_ioctl.h deleted file mode 100644 index fb7c0cf72c56..000000000000 --- a/include/linux/gfs2_ioctl.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License v.2. - */ - -#ifndef __GFS2_IOCTL_DOT_H__ -#define __GFS2_IOCTL_DOT_H__ - -#define GFS2_IOCTL_SETFLAGS _IOW('g', 3, long) -#define GFS2_IOCTL_GETFLAGS _IOR('g', 4, long) - -#endif /* ___GFS2_IOCTL_DOT_H__ */ - -- cgit v1.2.3 From 7ea9ea832212c4a755650f7c7cc1ff0b63292a41 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 31 Mar 2006 15:01:28 -0500 Subject: [GFS2] Update ioctl() to new interface This is designed as a fs independent way to set flags on a particular inode. The values of the ioctl() and flags are designed to be identical to the ext2/3 values. Assuming that this plan is acceptable to people in general, the plan is to then move other fs across to using the same set of #defines, etc. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 138 ++++++++++++-------------------------------- include/linux/gfs2_ondisk.h | 16 +++++ include/linux/iflags.h | 104 +++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 102 deletions(-) create mode 100644 include/linux/iflags.h (limited to 'include/linux') diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index ac8e1238cb6f..db4484a3efcc 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -536,110 +537,44 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) return error; } -const struct gfs2_flag_eattr { - u32 flag; - u32 ext2; -} gfs2_flag_eattrs[] = { - { - .flag = GFS2_DIF_IMMUTABLE, - .ext2 = EXT2_IMMUTABLE_FL, - }, { - .flag = GFS2_DIF_APPENDONLY, - .ext2 = EXT2_APPEND_FL, - }, { - .flag = GFS2_DIF_JDATA, - .ext2 = EXT2_JOURNAL_DATA_FL, - }, { - .flag = GFS2_DIF_EXHASH, - .ext2 = EXT2_INDEX_FL, - }, { - .flag = GFS2_DIF_EA_INDIRECT, - }, { - .flag = GFS2_DIF_DIRECTIO, - }, { - .flag = GFS2_DIF_NOATIME, - .ext2 = EXT2_NOATIME_FL, - }, { - .flag = GFS2_DIF_SYNC, - .ext2 = EXT2_SYNC_FL, - }, { - .flag = GFS2_DIF_SYSTEM, - }, { - .flag = GFS2_DIF_TRUNC_IN_PROG, - }, { - .flag = GFS2_DIF_INHERIT_JDATA, - }, { - .flag = GFS2_DIF_INHERIT_DIRECTIO, - }, { - }, +static const u32 iflags_to_gfs2[32] = { + [iflag_Sync] = GFS2_DIF_SYNC, + [iflag_Immutable] = GFS2_DIF_IMMUTABLE, + [iflag_Append] = GFS2_DIF_APPENDONLY, + [iflag_NoAtime] = GFS2_DIF_NOATIME, + [iflag_Index] = GFS2_DIF_EXHASH, + [iflag_JournalData] = GFS2_DIF_JDATA, + [iflag_DirectIO] = GFS2_DIF_DIRECTIO, + [iflag_InheritDirectIO] = GFS2_DIF_INHERIT_DIRECTIO, + [iflag_InheritJdata] = GFS2_DIF_INHERIT_JDATA, }; -static const struct gfs2_flag_eattr *get_by_ext2(u32 ext2) -{ - const struct gfs2_flag_eattr *p = gfs2_flag_eattrs; - for(; p->flag; p++) { - if (ext2 == p->ext2) - return p; - } - return NULL; -} - -static const struct gfs2_flag_eattr *get_by_gfs2(u32 gfs2) -{ - const struct gfs2_flag_eattr *p = gfs2_flag_eattrs; - for(; p->flag; p++) { - if (gfs2 == p->flag) - return p; - } - return NULL; -} - -static u32 gfs2_flags_to_ext2(u32 gfs2) -{ - const struct gfs2_flag_eattr *ea; - u32 ext2 = 0; - u32 mask = 1; - - for(; mask != 0; mask <<=1) { - if (mask & gfs2) { - ea = get_by_gfs2(mask); - if (ea) - ext2 |= ea->ext2; - } - } - return ext2; -} - -static int gfs2_flags_from_ext2(u32 *gfs2, u32 ext2) -{ - const struct gfs2_flag_eattr *ea; - u32 mask = 1; - - for(; mask != 0; mask <<= 1) { - if (mask & ext2) { - ea = get_by_ext2(mask); - if (ea == NULL) - return -EINVAL; - *gfs2 |= ea->flag; - } - } - return 0; -} +static const u32 gfs2_to_iflags[32] = { + [gfs2fl_Sync] = IFLAG_SYNC, + [gfs2fl_Immutable] = IFLAG_IMMUTABLE, + [gfs2fl_AppendOnly] = IFLAG_APPEND, + [gfs2fl_NoAtime] = IFLAG_NOATIME, + [gfs2fl_ExHash] = IFLAG_INDEX, + [gfs2fl_Jdata] = IFLAG_JOURNAL_DATA, + [gfs2fl_Directio] = IFLAG_DIRECTIO, + [gfs2fl_InheritDirectio] = IFLAG_INHERITDIRECTIO, + [gfs2fl_InheritJdata] = IFLAG_INHERITJDATA, +}; -static int get_ext2_flags(struct inode *inode, u32 __user *ptr) +static int gfs2_get_flags(struct inode *inode, u32 __user *ptr) { struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_holder gh; int error; - u32 ext2; + u32 iflags; gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); error = gfs2_glock_nq_m_atime(1, &gh); if (error) return error; - ext2 = gfs2_flags_to_ext2(ip->i_di.di_flags); - if (put_user(ext2, ptr)) + iflags = iflags_cvt(gfs2_to_iflags, ip->i_di.di_flags); + if (put_user(iflags, ptr)) error = -EFAULT; gfs2_glock_dq_m(1, &gh); @@ -665,7 +600,7 @@ static int get_ext2_flags(struct inode *inode, u32 __user *ptr) * @mask: Indicates which flags are valid * */ -static int gfs2_set_flags(struct inode *inode, u32 flags, u32 mask) +static int do_gfs2_set_flags(struct inode *inode, u32 flags, u32 mask) { struct gfs2_inode *ip = inode->u.generic_ip; struct buffer_head *bh; @@ -717,24 +652,23 @@ out: return error; } -static int set_ext2_flags(struct inode *inode, u32 __user *ptr) +static int gfs2_set_flags(struct inode *inode, u32 __user *ptr) { - u32 ext2, gfs2; - if (get_user(ext2, ptr)) + u32 iflags, gfsflags; + if (get_user(iflags, ptr)) return -EFAULT; - if (gfs2_flags_from_ext2(&gfs2, ext2)) - return -EINVAL; - return gfs2_set_flags(inode, gfs2, ~0); + gfsflags = iflags_cvt(iflags_to_gfs2, iflags); + return do_gfs2_set_flags(inode, gfsflags, ~0); } int gfs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd) { - case EXT2_IOC_GETFLAGS: - return get_ext2_flags(inode, (u32 __user *)arg); - case EXT2_IOC_SETFLAGS: - return set_ext2_flags(inode, (u32 __user *)arg); + case IFLAGS_GET_IOC: + return gfs2_get_flags(inode, (u32 __user *)arg); + case IFLAGS_SET_IOC: + return gfs2_set_flags(inode, (u32 __user *)arg); } return -ENOTTY; } diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index a5fb4f99aa45..3ab40917383f 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -197,6 +197,22 @@ struct gfs2_quota { #define DT2IF(dt) (((dt) << 12) & S_IFMT) #define IF2DT(sif) (((sif) & S_IFMT) >> 12) +enum { + gfs2fl_Jdata = 0, + gfs2fl_ExHash = 1, + gfs2fl_Unused = 2, + gfs2fl_EaIndirect = 3, + gfs2fl_Directio = 4, + gfs2fl_Immutable = 5, + gfs2fl_AppendOnly = 6, + gfs2fl_NoAtime = 7, + gfs2fl_Sync = 8, + gfs2fl_System = 9, + gfs2fl_TruncInProg = 29, + gfs2fl_InheritDirectio = 30, + gfs2fl_InheritJdata = 31, +}; + /* Dinode flags */ #define GFS2_DIF_JDATA 0x00000001 #define GFS2_DIF_EXHASH 0x00000002 diff --git a/include/linux/iflags.h b/include/linux/iflags.h new file mode 100644 index 000000000000..1b4d9ef5d62b --- /dev/null +++ b/include/linux/iflags.h @@ -0,0 +1,104 @@ +#ifndef _LINUX_IFLAGS_H +#define _LINUX_IFLAGS_H + +/* + * A universal set of inode flags. + * + * Originally taken from ext2/3 with additions for other filesystems. + * Filesystems supporting this interface should interoperate with + * the lsattr and chattr command line tools. + * + * This interface is supported in whole or in part by: + * ext2 + * ext3 + * xfs + * jfs + * gfs2 + * + */ + +#define IFLAGS_GET_IOC _IOR('f', 1, long) +#define IFLAGS_SET_IOC _IOW('f', 2, long) + +/* + * These values are provided for use as indices of an array + * for use with the iflags_cvt function below + */ +enum { + iflag_SecureRm = 0, /* Secure deletion */ + iflag_Unrm = 1, /* Undelete */ + iflag_Compress = 2, /* Compress file */ + iflag_Sync = 3, /* Synchronous updates */ + iflag_Immutable = 4, /* Immutable */ + iflag_Append = 5, /* Append */ + iflag_NoDump = 6, /* Don't dump file */ + iflag_NoAtime = 7, /* No atime updates */ + /* Reserved for compression usage */ + iflag_Dirty = 8, + iflag_ComprBlk = 9, /* One or more compressed clusters */ + iflag_NoComp = 10, /* Don't compress */ + iflag_Ecompr = 11, /* Compression error */ + /* End of compression flags */ + iflag_Btree = 12, /* btree format dir */ + iflag_Index = 12, /* hash-indexed directory */ + iflag_Imagic = 13, /* AFS directory */ + iflag_JournalData = 14, /* file data should be journaled */ + iflag_NoTail = 15, /* file tail should not be merged */ + iflag_DirSync = 16, /* dirsync behaviour */ + iflag_TopDir = 17, /* Top of directory hierarchies */ + iflag_DirectIO = 18, /* Always use direct I/O on this file */ + iflag_InheritDirectIO = 19, /* Set DirectIO on new files in dir */ + iflag_InheritJdata = 20, /* Set JournalData on create in dir */ + iflag_Reserved = 31 /* reserved for ext2/3 lib */ +}; + +#define __IFL(x) (1<<(iflag_##x)) +#define IFLAG_SECRM __IFL(SecureRm) /* 0x00000001 */ +#define IFLAG_UNRM __IFL(Unrm) /* 0x00000002 */ +#define IFLAG_COMPR __IFL(Compr) /* 0x00000004 */ +#define IFLAG_SYNC __IFL(Sync) /* 0x00000008 */ +#define IFLAG_IMMUTABLE __IFL(Immutable) /* 0x00000010 */ +#define IFLAG_APPEND __IFL(Append) /* 0x00000020 */ +#define IFLAG_NODUMP __IFL(NoDump) /* 0x00000040 */ +#define IFLAG_NOATIME __IFL(NoAtime) /* 0x00000080 */ +#define IFLAG_DIRTY __IFL(Dirty) /* 0x00000100 */ +#define IFLAG_COMPRBLK __IFL(ComprBlk) /* 0x00000200 */ +#define IFLAG_NOCOMP __IFL(NoComp) /* 0x00000400 */ +#define IFLAG_ECOMPR __IFL(Ecompr) /* 0x00000800 */ +#define IFLAG_BTREE __IFL(Btree) /* 0x00001000 */ +#define IFLAG_INDEX __IFL(Index) /* 0x00001000 */ +#define IFLAG_IMAGIC __IFL(Imagic) /* 0x00002000 */ +#define IFLAG_JOURNAL_DATA __IFL(JournalData) /* 0x00004000 */ +#define IFLAG_NOTAIL __IFL(NoTail) /* 0x00008000 */ +#define IFLAG_DIRSYNC __IFL(DirSync) /* 0x00010000 */ +#define IFLAG_TOPDIR __IFL(TopDir) /* 0x00020000 */ +#define IFLAG_DIRECTIO __IFL(DirectIO) /* 0x00040000 */ +#define IFLAG_INHERITDIRECTIO __IFL(InheritDirectIO) /* 0x00080000 */ +#define IFLAG_INHERITJDATA __IFL(InheritJdata) /* 0x00100000 */ +#define IFLAG_RESERVED __IFL(Reserved) /* 0x80000000 */ + +#ifdef __KERNEL__ +/** + * iflags_cvt + * @table: A table of 32 u32 flags + * @val: a 32 bit value to convert + * + * This function can be used to convert between IFLAGS values and + * the filesystem's own flags values. + * + * Returns: the converted flags + */ +static inline u32 iflags_cvt(const u32 *table, u32 val) +{ + u32 res = 0; + while(val) { + if (val & 1) + res |= *table; + table++; + val >>= 1; + } + return res; +} +#endif /* __KERNEL__ */ + +#endif /* _LINUX_IFLAGS_H */ -- cgit v1.2.3 From 4bcf7091f9da595016f9d1175aa1bea8e736566f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 25 Apr 2006 13:20:27 -0400 Subject: [GFS2] Remove inherited flags from exported flags. We don't need the inherited flags since this action can be implied by setting the flags on directories where they wouldn't otherwise make sense. It reduces the number of extra flags by two. Also updated the list of flags to take account of one extra ext2/3 flag. Cc: Andreas Dilger Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 23 +++++++++-------------- include/linux/iflags.h | 10 ++++------ 2 files changed, 13 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 3fb1a29f88a6..c2dbc300a50c 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -545,8 +545,6 @@ static const u32 iflags_to_gfs2[32] = { [iflag_Index] = GFS2_DIF_EXHASH, [iflag_JournalData] = GFS2_DIF_JDATA, [iflag_DirectIO] = GFS2_DIF_DIRECTIO, - [iflag_InheritDirectIO] = GFS2_DIF_INHERIT_DIRECTIO, - [iflag_InheritJdata] = GFS2_DIF_INHERIT_JDATA, }; static const u32 gfs2_to_iflags[32] = { @@ -557,8 +555,8 @@ static const u32 gfs2_to_iflags[32] = { [gfs2fl_ExHash] = IFLAG_INDEX, [gfs2fl_Jdata] = IFLAG_JOURNAL_DATA, [gfs2fl_Directio] = IFLAG_DIRECTIO, - [gfs2fl_InheritDirectio] = IFLAG_INHERITDIRECTIO, - [gfs2fl_InheritJdata] = IFLAG_INHERITJDATA, + [gfs2fl_InheritDirectio] = IFLAG_DIRECTIO, + [gfs2fl_InheritJdata] = IFLAG_JOURNAL_DATA, }; static int gfs2_get_flags(struct file *filp, u32 __user *ptr) @@ -621,20 +619,17 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) if ((new_flags ^ flags) == 0) goto out; + if (S_ISDIR(inode->i_mode)) { + if ((new_flags ^ flags) & GFS2_DIF_JDATA) + new_flags ^= (GFS2_DIF_JDATA|GFS2_DIF_INHERIT_JDATA); + if ((new_flags ^ flags) & GFS2_DIF_DIRECTIO) + new_flags ^= (GFS2_DIF_DIRECTIO|GFS2_DIF_INHERIT_DIRECTIO); + } + error = -EINVAL; if ((new_flags ^ flags) & ~GFS2_FLAGS_USER_SET) goto out; - if (S_ISDIR(inode->i_mode)) { - if ((new_flags ^ flags) & (GFS2_DIF_JDATA | GFS2_DIF_DIRECTIO)) - goto out; - } else if (S_ISREG(inode->i_mode)) { - if ((new_flags ^ flags) & (GFS2_DIF_INHERIT_DIRECTIO| - GFS2_DIF_INHERIT_JDATA)) - goto out; - } else - goto out; - error = -EPERM; if (IS_IMMUTABLE(inode) && (new_flags & GFS2_DIF_IMMUTABLE)) goto out; diff --git a/include/linux/iflags.h b/include/linux/iflags.h index 1b4d9ef5d62b..5b27102dfeaf 100644 --- a/include/linux/iflags.h +++ b/include/linux/iflags.h @@ -46,9 +46,8 @@ enum { iflag_NoTail = 15, /* file tail should not be merged */ iflag_DirSync = 16, /* dirsync behaviour */ iflag_TopDir = 17, /* Top of directory hierarchies */ - iflag_DirectIO = 18, /* Always use direct I/O on this file */ - iflag_InheritDirectIO = 19, /* Set DirectIO on new files in dir */ - iflag_InheritJdata = 20, /* Set JournalData on create in dir */ + iflag_Extent = 19, /* Extents */ + iflag_DirectIO = 20, /* Always use direct I/O on this file */ iflag_Reserved = 31 /* reserved for ext2/3 lib */ }; @@ -72,9 +71,8 @@ enum { #define IFLAG_NOTAIL __IFL(NoTail) /* 0x00008000 */ #define IFLAG_DIRSYNC __IFL(DirSync) /* 0x00010000 */ #define IFLAG_TOPDIR __IFL(TopDir) /* 0x00020000 */ -#define IFLAG_DIRECTIO __IFL(DirectIO) /* 0x00040000 */ -#define IFLAG_INHERITDIRECTIO __IFL(InheritDirectIO) /* 0x00080000 */ -#define IFLAG_INHERITJDATA __IFL(InheritJdata) /* 0x00100000 */ +#define IFLAG_EXTENT __IFL(Extent) /* 0x00080000 */ +#define IFLAG_DIRECTIO __IFL(DirectIO) /* 0x00100000 */ #define IFLAG_RESERVED __IFL(Reserved) /* 0x80000000 */ #ifdef __KERNEL__ -- cgit v1.2.3 From 08bc2dbc7327e89b9d5b9c8ef9401d1df2622fca Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 28 Apr 2006 10:59:12 -0400 Subject: [GFS2] [-mm patch] fs/gfs2/: possible cleanups This patch contains the following possible cleanups: - make needlessly global code static - #if 0 unused functions - remove the following global function that was both unused and unimplemented: - super.c: gfs2_do_upgrade() Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 3 ++- fs/gfs2/bmap.h | 2 -- fs/gfs2/dir.c | 8 ++++---- fs/gfs2/eaops.c | 2 +- fs/gfs2/eaops.h | 1 - fs/gfs2/eattr.c | 3 +++ fs/gfs2/eattr.h | 2 -- fs/gfs2/glock.c | 25 ++++++++++++++++--------- fs/gfs2/glock.h | 12 ------------ fs/gfs2/lm.c | 2 ++ fs/gfs2/lm.h | 1 - fs/gfs2/locking/dlm/lock.c | 10 +++++----- fs/gfs2/locking/dlm/lock_dlm.h | 4 ---- fs/gfs2/locking/dlm/main.c | 4 ++-- fs/gfs2/locking/nolock/main.c | 8 ++++---- fs/gfs2/lvb.c | 2 ++ fs/gfs2/lvb.h | 1 - fs/gfs2/ondisk.c | 38 ++++++++++++++++++++++++++++++++++---- fs/gfs2/quota.c | 2 ++ fs/gfs2/quota.h | 2 -- fs/gfs2/super.c | 8 ++------ fs/gfs2/super.h | 2 -- include/linux/gfs2_ondisk.h | 14 -------------- 23 files changed, 79 insertions(+), 77 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 68bc3be09c98..f570d8caef68 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -59,7 +59,7 @@ struct strip_mine { * * Returns: errno */ - +#if 0 int gfs2_unstuffer_sync(struct gfs2_inode *ip, struct buffer_head *dibh, uint64_t block, void *private) { @@ -77,6 +77,7 @@ int gfs2_unstuffer_sync(struct gfs2_inode *ip, struct buffer_head *dibh, return error; } +#endif /* 0 */ /** * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index ee9ec8d7515c..23fb6589d5e3 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -13,8 +13,6 @@ typedef int (*gfs2_unstuffer_t) (struct gfs2_inode * ip, struct buffer_head * dibh, uint64_t block, void *private); -int gfs2_unstuffer_sync(struct gfs2_inode *ip, struct buffer_head *dibh, - uint64_t block, void *private); int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, void *private); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index ffc1beff6703..0404783f39b3 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -669,10 +669,10 @@ static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, * Takes a dent from which to grab space as an argument. Returns the * newly created dent. */ -struct gfs2_dirent *gfs2_init_dirent(struct inode *inode, - struct gfs2_dirent *dent, - const struct qstr *name, - struct buffer_head *bh) +static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode, + struct gfs2_dirent *dent, + const struct qstr *name, + struct buffer_head *bh) { struct gfs2_inode *ip = inode->u.generic_ip; struct gfs2_dirent *ndent; diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 4b9f6cff7a34..1b376eceb6af 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -167,7 +167,7 @@ static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) return gfs2_ea_remove_i(ip, er); } -struct gfs2_eattr_operations gfs2_user_eaops = { +static struct gfs2_eattr_operations gfs2_user_eaops = { .eo_get = user_eo_get, .eo_set = user_eo_set, .eo_remove = user_eo_remove, diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h index f83c497eddca..30ec6a09bfd0 100644 --- a/fs/gfs2/eaops.h +++ b/fs/gfs2/eaops.h @@ -21,7 +21,6 @@ struct gfs2_eattr_operations { unsigned int gfs2_ea_name2type(const char *name, char **truncated_name); -extern struct gfs2_eattr_operations gfs2_user_eaops; extern struct gfs2_eattr_operations gfs2_system_eaops; extern struct gfs2_eattr_operations *gfs2_ea_ops[]; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 8219d471f06c..d3316cab2be4 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -358,6 +358,7 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, return error; } +#if 0 static int gfs2_ea_repack_i(struct gfs2_inode *ip) { @@ -382,6 +383,8 @@ int gfs2_ea_repack(struct gfs2_inode *ip) return error; } +#endif /* 0 */ + struct ea_list { struct gfs2_ea_request *ei_er; unsigned int ei_size; diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h index 2b4152b1fcbe..ffd56686225b 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/eattr.h @@ -61,8 +61,6 @@ struct gfs2_ea_location { struct gfs2_ea_header *el_prev; }; -int gfs2_ea_repack(struct gfs2_inode *ip); - int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index f82ecc0cc8fb..0a5a0e87b0a6 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -47,6 +47,8 @@ struct greedy { typedef void (*glock_examiner) (struct gfs2_glock * gl); +static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); + /** * relaxed_state_ok - is a requested lock compatible with the current lock mode? * @actual: the current state of the lock @@ -228,8 +230,8 @@ static struct gfs2_glock *search_bucket(struct gfs2_gl_hash_bucket *bucket, * Returns: NULL, or the struct gfs2_glock with the requested number */ -struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, - struct lm_lockname *name) +static struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, + struct lm_lockname *name) { struct gfs2_gl_hash_bucket *bucket = &sdp->sd_gl_hash[gl_hash(name)]; struct gfs2_glock *gl; @@ -421,8 +423,9 @@ void gfs2_holder_uninit(struct gfs2_holder *gh) * Returns: the holder structure, NULL on ENOMEM */ -struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl, unsigned int state, - int flags, gfp_t gfp_flags) +static struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl, + unsigned int state, + int flags, gfp_t gfp_flags) { struct gfs2_holder *gh; @@ -442,7 +445,7 @@ struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl, unsigned int state, * */ -void gfs2_holder_put(struct gfs2_holder *gh) +static void gfs2_holder_put(struct gfs2_holder *gh) { gfs2_holder_uninit(gh); kfree(gh); @@ -674,7 +677,7 @@ void gfs2_glmutex_lock(struct gfs2_glock *gl) * Returns: 1 if the glock is acquired */ -int gfs2_glmutex_trylock(struct gfs2_glock *gl) +static int gfs2_glmutex_trylock(struct gfs2_glock *gl) { int acquired = 1; @@ -1301,7 +1304,8 @@ void gfs2_glock_dq(struct gfs2_holder *gh) * */ -void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, int flags) +static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, + int flags) { struct gfs2_glock_operations *glops = gl->gl_ops; @@ -1329,7 +1333,7 @@ void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, int flags) * @gl: the glock * */ - +#if 0 void gfs2_glock_force_drop(struct gfs2_glock *gl) { struct gfs2_holder gh; @@ -1345,6 +1349,7 @@ void gfs2_glock_force_drop(struct gfs2_glock *gl) wait_for_completion(&gh.gh_wait); gfs2_holder_uninit(&gh); } +#endif /* 0 */ static void greedy_work(void *data) { @@ -1697,6 +1702,7 @@ void gfs2_lvb_unhold(struct gfs2_glock *gl) gfs2_glock_put(gl); } +#if 0 void gfs2_lvb_sync(struct gfs2_glock *gl) { gfs2_glmutex_lock(gl); @@ -1707,6 +1713,7 @@ void gfs2_lvb_sync(struct gfs2_glock *gl) gfs2_glmutex_unlock(gl); } +#endif /* 0 */ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, unsigned int state) @@ -2307,7 +2314,7 @@ static int dump_glock(struct gfs2_glock *gl) * */ -int gfs2_dump_lockstate(struct gfs2_sbd *sdp) +static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) { struct gfs2_gl_hash_bucket *bucket; struct gfs2_glock *gl; diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 6f9c88ed5383..a36b26585fb8 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -73,8 +73,6 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) return ret; } -struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp, - struct lm_lockname *name); int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number, struct gfs2_glock_operations *glops, int create, struct gfs2_glock **glp); @@ -85,15 +83,11 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *gh); void gfs2_holder_uninit(struct gfs2_holder *gh); -struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl, unsigned int state, - int flags, gfp_t gfp_flags); -void gfs2_holder_put(struct gfs2_holder *gh); void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags); void gfs2_glock_drop_th(struct gfs2_glock *gl); void gfs2_glmutex_lock(struct gfs2_glock *gl); -int gfs2_glmutex_trylock(struct gfs2_glock *gl); void gfs2_glmutex_unlock(struct gfs2_glock *gl); int gfs2_glock_nq(struct gfs2_holder *gh); @@ -101,9 +95,6 @@ int gfs2_glock_poll(struct gfs2_holder *gh); int gfs2_glock_wait(struct gfs2_holder *gh); void gfs2_glock_dq(struct gfs2_holder *gh); -void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, int flags); -void gfs2_glock_force_drop(struct gfs2_glock *gl); - int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time); void gfs2_glock_dq_uninit(struct gfs2_holder *gh); @@ -148,7 +139,6 @@ static inline int gfs2_glock_nq_init(struct gfs2_glock *gl, int gfs2_lvb_hold(struct gfs2_glock *gl); void gfs2_lvb_unhold(struct gfs2_glock *gl); -void gfs2_lvb_sync(struct gfs2_glock *gl); void gfs2_glock_cb(lm_fsdata_t *fsdata, unsigned int type, void *data); @@ -161,6 +151,4 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp); void gfs2_scand_internal(struct gfs2_sbd *sdp); void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait); -int gfs2_dump_lockstate(struct gfs2_sbd *sdp); - #endif /* __GLOCK_DOT_H__ */ diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index 5b3c56d2df2f..06a785e9b582 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -188,11 +188,13 @@ void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb) sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(lock, lvb); } +#if 0 void gfs2_lm_sync_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb) { if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) sdp->sd_lockstruct.ls_ops->lm_sync_lvb(lock, lvb); } +#endif /* 0 */ int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name, struct file *file, struct file_lock *fl) diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h index ec812424fdec..4ee5c34434bc 100644 --- a/fs/gfs2/lm.h +++ b/fs/gfs2/lm.h @@ -26,7 +26,6 @@ unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, lm_lock_t *lock, void gfs2_lm_cancel(struct gfs2_sbd *sdp, lm_lock_t *lock); int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char **lvbp); void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb); -void gfs2_lm_sync_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb); int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name, struct file *file, struct file_lock *fl); diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c index a309b799dff1..3b0dfd7ae26e 100644 --- a/fs/gfs2/locking/dlm/lock.c +++ b/fs/gfs2/locking/dlm/lock.c @@ -158,8 +158,8 @@ static inline void make_strname(struct lm_lockname *lockname, str->namelen = GDLM_STRNAME_BYTES; } -int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name, - struct gdlm_lock **lpp) +static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name, + struct gdlm_lock **lpp) { struct gdlm_lock *lp; @@ -276,7 +276,7 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp) return LM_OUT_ASYNC; } -unsigned int gdlm_do_unlock(struct gdlm_lock *lp) +static unsigned int gdlm_do_unlock(struct gdlm_lock *lp) { struct gdlm_ls *ls = lp->ls; unsigned int lkf = 0; @@ -378,7 +378,7 @@ void gdlm_cancel(lm_lock_t *lock) clear_bit(LFL_DLM_CANCEL, &lp->flags); } -int gdlm_add_lvb(struct gdlm_lock *lp) +static int gdlm_add_lvb(struct gdlm_lock *lp) { char *lvb; @@ -391,7 +391,7 @@ int gdlm_add_lvb(struct gdlm_lock *lp) return 0; } -void gdlm_del_lvb(struct gdlm_lock *lp) +static void gdlm_del_lvb(struct gdlm_lock *lp) { kfree(lp->lvb); lp->lvb = NULL; diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index e6c1e4786fec..530c2f542584 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -162,12 +162,8 @@ int16_t gdlm_make_lmstate(int16_t); void gdlm_queue_delayed(struct gdlm_lock *); void gdlm_submit_delayed(struct gdlm_ls *); int gdlm_release_all_locks(struct gdlm_ls *); -int gdlm_create_lp(struct gdlm_ls *, struct lm_lockname *, struct gdlm_lock **); void gdlm_delete_lp(struct gdlm_lock *); -int gdlm_add_lvb(struct gdlm_lock *); -void gdlm_del_lvb(struct gdlm_lock *); unsigned int gdlm_do_lock(struct gdlm_lock *); -unsigned int gdlm_do_unlock(struct gdlm_lock *); int gdlm_get_lock(lm_lockspace_t *, struct lm_lockname *, lm_lock_t **); void gdlm_put_lock(lm_lock_t *); diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c index 3c9adf18fd9c..89728c91665f 100644 --- a/fs/gfs2/locking/dlm/main.c +++ b/fs/gfs2/locking/dlm/main.c @@ -16,7 +16,7 @@ extern int gdlm_drop_period; extern struct lm_lockops gdlm_ops; -int __init init_lock_dlm(void) +static int __init init_lock_dlm(void) { int error; @@ -48,7 +48,7 @@ int __init init_lock_dlm(void) return 0; } -void __exit exit_lock_dlm(void) +static void __exit exit_lock_dlm(void) { gdlm_plock_exit(); gdlm_sysfs_exit(); diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index ecd37371eba5..97ffac5cdefb 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -21,7 +21,7 @@ struct nolock_lockspace { unsigned int nl_lvb_size; }; -struct lm_lockops nolock_ops; +static struct lm_lockops nolock_ops; static int nolock_mount(char *table_name, char *host_data, lm_callback_t cb, lm_fsdata_t *fsdata, @@ -208,7 +208,7 @@ static void nolock_recovery_done(lm_lockspace_t *lockspace, unsigned int jid, { } -struct lm_lockops nolock_ops = { +static struct lm_lockops nolock_ops = { .lm_proto_name = "lock_nolock", .lm_mount = nolock_mount, .lm_others_may_mount = nolock_others_may_mount, @@ -229,7 +229,7 @@ struct lm_lockops nolock_ops = { .lm_owner = THIS_MODULE, }; -int __init init_nolock(void) +static int __init init_nolock(void) { int error; @@ -245,7 +245,7 @@ int __init init_nolock(void) return 0; } -void __exit exit_nolock(void) +static void __exit exit_nolock(void) { gfs_unregister_lockproto(&nolock_ops); } diff --git a/fs/gfs2/lvb.c b/fs/gfs2/lvb.c index 63b815dad8e7..9d72872c6f73 100644 --- a/fs/gfs2/lvb.c +++ b/fs/gfs2/lvb.c @@ -43,6 +43,7 @@ void gfs2_quota_lvb_out(struct gfs2_quota_lvb *qb, char *lvb) str->qb_value = cpu_to_be64(qb->qb_value); } +#if 0 void gfs2_quota_lvb_print(struct gfs2_quota_lvb *qb) { pv(qb, qb_magic, "%u"); @@ -50,4 +51,5 @@ void gfs2_quota_lvb_print(struct gfs2_quota_lvb *qb) pv(qb, qb_warn, "%llu"); pv(qb, qb_value, "%lld"); } +#endif /* 0 */ diff --git a/fs/gfs2/lvb.h b/fs/gfs2/lvb.h index 1b9eb69b9534..3c4c17405e9a 100644 --- a/fs/gfs2/lvb.h +++ b/fs/gfs2/lvb.h @@ -14,7 +14,6 @@ void gfs2_quota_lvb_in(struct gfs2_quota_lvb *qb, char *lvb); void gfs2_quota_lvb_out(struct gfs2_quota_lvb *qb, char *lvb); -void gfs2_quota_lvb_print(struct gfs2_quota_lvb *qb); #endif /* __LVB_DOT_H__ */ diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index acfc944ce13e..b11e659bdd9e 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -28,7 +28,7 @@ * @count: the number of bytes * */ - +#if 0 static void print_array(char *title, char *buf, int count) { int x; @@ -42,6 +42,7 @@ static void print_array(char *title, char *buf, int count) if (x % 16) printk("\n"); } +#endif /* 0 */ /* * gfs2_xxx_in - read in an xxx struct @@ -72,7 +73,7 @@ void gfs2_inum_out(const struct gfs2_inum *no, char *buf) str->no_addr = cpu_to_be64(no->no_addr); } -void gfs2_inum_print(struct gfs2_inum *no) +static void gfs2_inum_print(struct gfs2_inum *no) { pv(no, no_formal_ino, "%llu"); pv(no, no_addr, "%llu"); @@ -96,7 +97,7 @@ static void gfs2_meta_header_out(struct gfs2_meta_header *mh, char *buf) str->mh_format = cpu_to_be32(mh->mh_format); } -void gfs2_meta_header_print(struct gfs2_meta_header *mh) +static void gfs2_meta_header_print(struct gfs2_meta_header *mh) { pv(mh, mh_magic, "0x%.8X"); pv(mh, mh_type, "%u"); @@ -121,6 +122,7 @@ void gfs2_sb_in(struct gfs2_sb *sb, char *buf) memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN); } +#if 0 void gfs2_sb_print(struct gfs2_sb *sb) { gfs2_meta_header_print(&sb->sb_header); @@ -136,6 +138,7 @@ void gfs2_sb_print(struct gfs2_sb *sb) pv(sb, sb_lockproto, "%s"); pv(sb, sb_locktable, "%s"); } +#endif /* 0 */ void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf) { @@ -149,6 +152,7 @@ void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf) } +#if 0 void gfs2_rindex_out(struct gfs2_rindex *ri, char *buf) { struct gfs2_rindex *str = (struct gfs2_rindex *)buf; @@ -163,6 +167,8 @@ void gfs2_rindex_out(struct gfs2_rindex *ri, char *buf) memset(str->ri_reserved, 0, sizeof(str->ri_reserved)); } +#endif /* 0 */ + void gfs2_rindex_print(struct gfs2_rindex *ri) { pv(ri, ri_addr, "%llu"); @@ -196,6 +202,7 @@ void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf) memset(&str->rg_reserved, 0, sizeof(str->rg_reserved)); } +#if 0 void gfs2_rgrp_print(struct gfs2_rgrp *rg) { gfs2_meta_header_print(&rg->rg_header); @@ -205,6 +212,7 @@ void gfs2_rgrp_print(struct gfs2_rgrp *rg) pa(rg, rg_reserved, 36); } +#endif /* 0 */ void gfs2_quota_in(struct gfs2_quota *qu, char *buf) { @@ -215,6 +223,8 @@ void gfs2_quota_in(struct gfs2_quota *qu, char *buf) qu->qu_value = be64_to_cpu(str->qu_value); } +#if 0 + void gfs2_quota_out(struct gfs2_quota *qu, char *buf) { struct gfs2_quota *str = (struct gfs2_quota *)buf; @@ -231,6 +241,8 @@ void gfs2_quota_print(struct gfs2_quota *qu) pv(qu, qu_value, "%lld"); } +#endif /* 0 */ + void gfs2_dinode_in(struct gfs2_dinode *di, char *buf) { struct gfs2_dinode *str = (struct gfs2_dinode *)buf; @@ -327,6 +339,8 @@ void gfs2_dinode_print(struct gfs2_dinode *di) pv(di, di_eattr, "%llu"); } +#if 0 + void gfs2_dirent_print(struct gfs2_dirent *de, char *name) { char buf[GFS2_FNAMESIZE + 1]; @@ -394,6 +408,8 @@ void gfs2_ea_header_print(struct gfs2_ea_header *ea, char *name) printk(KERN_INFO " name = %s\n", buf); } +#endif /* 0 */ + void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf) { struct gfs2_log_header *str = (struct gfs2_log_header *)buf; @@ -406,6 +422,8 @@ void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf) lh->lh_hash = be32_to_cpu(str->lh_hash); } +#if 0 + void gfs2_log_header_print(struct gfs2_log_header *lh) { gfs2_meta_header_print(&lh->lh_header); @@ -427,6 +445,8 @@ void gfs2_log_descriptor_print(struct gfs2_log_descriptor *ld) pa(ld, ld_reserved, 32); } +#endif /* 0 */ + void gfs2_inum_range_in(struct gfs2_inum_range *ir, char *buf) { struct gfs2_inum_range *str = (struct gfs2_inum_range *)buf; @@ -443,11 +463,13 @@ void gfs2_inum_range_out(struct gfs2_inum_range *ir, char *buf) str->ir_length = cpu_to_be64(ir->ir_length); } +#if 0 void gfs2_inum_range_print(struct gfs2_inum_range *ir) { pv(ir, ir_start, "%llu"); pv(ir, ir_length, "%llu"); } +#endif /* 0 */ void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, char *buf) { @@ -467,12 +489,14 @@ void gfs2_statfs_change_out(struct gfs2_statfs_change *sc, char *buf) str->sc_dinodes = cpu_to_be64(sc->sc_dinodes); } +#if 0 void gfs2_statfs_change_print(struct gfs2_statfs_change *sc) { pv(sc, sc_total, "%lld"); pv(sc, sc_free, "%lld"); pv(sc, sc_dinodes, "%lld"); } +#endif /* 0 */ void gfs2_unlinked_tag_in(struct gfs2_unlinked_tag *ut, char *buf) { @@ -491,12 +515,16 @@ void gfs2_unlinked_tag_out(struct gfs2_unlinked_tag *ut, char *buf) str->__pad = 0; } +#if 0 + void gfs2_unlinked_tag_print(struct gfs2_unlinked_tag *ut) { gfs2_inum_print(&ut->ut_inum); pv(ut, ut_flags, "%u"); } +#endif /* 0 */ + void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf) { struct gfs2_quota_change *str = (struct gfs2_quota_change *)buf; @@ -506,6 +534,8 @@ void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf) qc->qc_id = be32_to_cpu(str->qc_id); } +#if 0 + void gfs2_quota_change_print(struct gfs2_quota_change *qc) { pv(qc, qc_change, "%lld"); @@ -513,5 +543,5 @@ void gfs2_quota_change_print(struct gfs2_quota_change *qc) pv(qc, qc_id, "%u"); } - +#endif /* 0 */ diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 90e32a3dc50d..942c4c8b9f56 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1086,6 +1086,7 @@ int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, uint32_t id) return error; } +#if 0 int gfs2_quota_read(struct gfs2_sbd *sdp, int user, uint32_t id, struct gfs2_quota *q) { @@ -1121,6 +1122,7 @@ int gfs2_quota_read(struct gfs2_sbd *sdp, int user, uint32_t id, return error; } +#endif /* 0 */ int gfs2_quota_init(struct gfs2_sbd *sdp) { diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index 005529f6895d..1baeeb23d232 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -24,8 +24,6 @@ void gfs2_quota_change(struct gfs2_inode *ip, int64_t change, int gfs2_quota_sync(struct gfs2_sbd *sdp); int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, uint32_t id); -int gfs2_quota_read(struct gfs2_sbd *sdp, int user, uint32_t id, - struct gfs2_quota *q); int gfs2_quota_init(struct gfs2_sbd *sdp); void gfs2_quota_scan(struct gfs2_sbd *sdp); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f0dbd2d7aadc..75a8def8d0bc 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -264,11 +264,6 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) return 0; } -int gfs2_do_upgrade(struct gfs2_sbd *sdp, struct gfs2_glock *sb_gl) -{ - return 0; -} - /** * gfs2_jindex_hold - Grab a lock on the jindex * @sdp: The GFS2 superblock @@ -837,7 +832,8 @@ struct lfcc { * Returns: errno */ -int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_holder *t_gh) +static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, + struct gfs2_holder *t_gh) { struct gfs2_inode *ip; struct gfs2_holder ji_gh; diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 6abb7b5c8828..175afdde43bb 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -14,7 +14,6 @@ void gfs2_tune_init(struct gfs2_tune *gt); int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent); int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent); -int gfs2_do_upgrade(struct gfs2_sbd *sdp, struct gfs2_glock *gl_sb); static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) { @@ -46,7 +45,6 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp); int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc); int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc); -int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_holder *t_gh); int gfs2_freeze_fs(struct gfs2_sbd *sdp); void gfs2_unfreeze_fs(struct gfs2_sbd *sdp); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 3ab40917383f..4356e3864643 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -450,22 +450,8 @@ extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf); /* Printing functions */ -extern void gfs2_inum_print(struct gfs2_inum *no); -extern void gfs2_meta_header_print(struct gfs2_meta_header *mh); -extern void gfs2_sb_print(struct gfs2_sb *sb); extern void gfs2_rindex_print(struct gfs2_rindex *ri); -extern void gfs2_rgrp_print(struct gfs2_rgrp *rg); -extern void gfs2_quota_print(struct gfs2_quota *qu); extern void gfs2_dinode_print(struct gfs2_dinode *di); -extern void gfs2_dirent_print(struct gfs2_dirent *de, char *name); -extern void gfs2_leaf_print(struct gfs2_leaf *lf); -extern void gfs2_ea_header_print(struct gfs2_ea_header *ea, char *name); -extern void gfs2_log_header_print(struct gfs2_log_header *lh); -extern void gfs2_log_descriptor_print(struct gfs2_log_descriptor *ld); -extern void gfs2_inum_range_print(struct gfs2_inum_range *ir); -extern void gfs2_statfs_change_print(struct gfs2_statfs_change *sc); -extern void gfs2_unlinked_tag_print(struct gfs2_unlinked_tag *ut); -extern void gfs2_quota_change_print(struct gfs2_quota_change *qc); #endif /* __KERNEL__ */ -- cgit v1.2.3 From 639b6d79b8c20cce4079fb035640c65456324d1c Mon Sep 17 00:00:00 2001 From: Ryan O'Hara Date: Mon, 22 May 2006 10:08:35 -0400 Subject: [GFS2] selinux support This adds support to GFS2 for selinux extended attributes. There is a known bug in gfs2_ea_get() which is believed to be independant of this patch. Further patches will follow once that bug is fixed in order to make GFS2 use as much of the generic eattr infrastructure as possible. Signed-off-by: Ryan O'Hara Signed-off-by: Steven Whitehouse --- fs/gfs2/eaops.c | 41 +++++++++++++++++++++++++++++++++++++++++ fs/gfs2/eaops.h | 2 ++ fs/gfs2/eattr.c | 15 ++++++++++++--- fs/gfs2/eattr.h | 17 ++++++++++++++--- include/linux/gfs2_ondisk.h | 3 ++- 5 files changed, 71 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 85c1dbace88b..2243b44ecb07 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -43,6 +43,10 @@ unsigned int gfs2_ea_name2type(const char *name, char **truncated_name) type = GFS2_EATYPE_USR; if (truncated_name) *truncated_name = strchr(name, '.') + 1; + } else if (strncmp(name, "security.", 9) == 0) { + type = GFS2_EATYPE_SECURITY; + if (truncated_name) + *truncated_name = strchr(name, '.') + 1; } else { type = GFS2_EATYPE_UNUSED; if (truncated_name) @@ -166,6 +170,36 @@ static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) return gfs2_ea_remove_i(ip, er); } +static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct inode *inode = ip->i_vnode; + int error = permission(inode, MAY_READ, NULL); + if (error) + return error; + + return gfs2_ea_get_i(ip, er); +} + +static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct inode *inode = ip->i_vnode; + int error = permission(inode, MAY_WRITE, NULL); + if (error) + return error; + + return gfs2_ea_set_i(ip, er); +} + +static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) +{ + struct inode *inode = ip->i_vnode; + int error = permission(inode, MAY_WRITE, NULL); + if (error) + return error; + + return gfs2_ea_remove_i(ip, er); +} + static struct gfs2_eattr_operations gfs2_user_eaops = { .eo_get = user_eo_get, .eo_set = user_eo_set, @@ -180,6 +214,13 @@ struct gfs2_eattr_operations gfs2_system_eaops = { .eo_name = "system", }; +struct gfs2_eattr_operations gfs2_security_eaops = { + .eo_get = security_eo_get, + .eo_set = security_eo_set, + .eo_remove = security_eo_remove, + .eo_name = "security", +}; + struct gfs2_eattr_operations *gfs2_ea_ops[] = { NULL, &gfs2_user_eaops, diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h index 3dece17e3116..965a235c96e8 100644 --- a/fs/gfs2/eaops.h +++ b/fs/gfs2/eaops.h @@ -23,6 +23,8 @@ unsigned int gfs2_ea_name2type(const char *name, char **truncated_name); extern struct gfs2_eattr_operations gfs2_system_eaops; +extern struct gfs2_eattr_operations gfs2_security_eaops; + extern struct gfs2_eattr_operations *gfs2_ea_ops[]; #endif /* __EAOPS_DOT_H__ */ diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index f5169a42a919..187fba1c4678 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -368,7 +368,7 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, { struct ea_list *ei = private; struct gfs2_ea_request *er = ei->ei_er; - unsigned int ea_size = GFS2_EA_STRLEN(ea); + unsigned int ea_size = gfs2_ea_strlen(ea); if (ea->ea_type == GFS2_EATYPE_UNUSED) return 0; @@ -381,12 +381,21 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, if (ei->ei_size + ea_size > er->er_data_len) return -ERANGE; - if (ea->ea_type == GFS2_EATYPE_USR) { + switch (ea->ea_type) { + case GFS2_EATYPE_USR: prefix = "user."; l = 5; - } else { + break; + case GFS2_EATYPE_SYS: prefix = "system."; l = 7; + break; + case GFS2_EATYPE_SECURITY: + prefix = "security."; + l = 9; + break; + default: + break; } memcpy(er->er_data + ei->ei_size, diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h index 19fb1dc4ddc4..ae199692e51d 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/eattr.h @@ -18,9 +18,6 @@ ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \ ((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \ (sizeof(uint64_t) * (ea)->ea_num_ptrs)), 8) -#define GFS2_EA_STRLEN(ea) \ -((((ea)->ea_type == GFS2_EATYPE_USR) ? 5 : 7) + (ea)->ea_name_len + 1) - #define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs) #define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST) @@ -83,4 +80,18 @@ int gfs2_ea_get_copy(struct gfs2_inode *ip, int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, struct iattr *attr, char *data); +static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea) +{ + switch (ea->ea_type) { + case GFS2_EATYPE_USR: + return (5 + (ea->ea_name_len + 1)); + case GFS2_EATYPE_SYS: + return (7 + (ea->ea_name_len + 1)); + case GFS2_EATYPE_SECURITY: + return (9 + (ea->ea_name_len + 1)); + default: + return (0); + } +} + #endif /* __EATTR_DOT_H__ */ diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 4356e3864643..3893aac4e3ae 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -311,8 +311,9 @@ struct gfs2_leaf { #define GFS2_EATYPE_UNUSED 0 #define GFS2_EATYPE_USR 1 #define GFS2_EATYPE_SYS 2 +#define GFS2_EATYPE_SECURITY 3 -#define GFS2_EATYPE_LAST 2 +#define GFS2_EATYPE_LAST 3 #define GFS2_EATYPE_VALID(x) ((x) <= GFS2_EATYPE_LAST) #define GFS2_EAFLAG_LAST 0x01 /* last ea in block */ -- cgit v1.2.3 From 22da645fd6675b7abc55cf937ddf6132f343e5b9 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Fri, 9 Jun 2006 16:14:20 -0400 Subject: [DLM] compat patch Here's a patch which add 32/64 bit compat to the DLM IOs and tidies the structures for alignment. As it causes an ABI change I had few qualms about adding the extra flag for "is64bit" as it simply uses a byte that would have been padding. Cc: David Woodhouse Signed-off-by: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/device.c | 166 ++++++++++++++++++++++++++++++++++++++++++--- include/linux/dlm_device.h | 11 +-- 2 files changed, 163 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/fs/dlm/device.c b/fs/dlm/device.c index 49a20d549216..47798fe46d72 100644 --- a/fs/dlm/device.c +++ b/fs/dlm/device.c @@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -59,6 +59,9 @@ static rwlock_t lockinfo_lock; #define LS_FLAG_DELETED 1 #define LS_FLAG_AUTOFREE 2 +/* flags in ls_flags*/ +#define FI_FLAG_OPEN 1 +#define FI_FLAG_COMPAT 2 #define LOCKINFO_MAGIC 0x53595324 @@ -117,9 +120,110 @@ struct file_info { wait_queue_head_t fi_wait; struct user_ls *fi_ls; atomic_t fi_refcnt; /* Number of users */ - unsigned long fi_flags; /* Bit 1 means the device is open */ + unsigned long fi_flags; +}; + +#ifdef CONFIG_COMPAT + +struct dlm_lock_params32 { + __u8 mode; + __u8 namelen; + __u16 flags; + __u32 lkid; + __u32 parent; + + __u32 castparam; + __u32 castaddr; + __u32 bastparam; + __u32 bastaddr; + __u32 lksb; + + char lvb[DLM_USER_LVB_LEN]; + char name[0]; }; +struct dlm_write_request32 { + __u32 version[3]; + __u8 cmd; + __u8 is64bit; + __u8 unused[2]; + + union { + struct dlm_lock_params32 lock; + struct dlm_lspace_params lspace; + } i; +}; + +struct dlm_lksb32 { + __u32 sb_status; + __u32 sb_lkid; + __u8 sb_flags; + __u32 sb_lvbptr; +}; + +struct dlm_lock_result32 { + __u32 length; + __u32 user_astaddr; + __u32 user_astparam; + __u32 user_lksb; + struct dlm_lksb32 lksb; + __u8 bast_mode; + __u8 unused[3]; + /* Offsets may be zero if no data is present */ + __u32 lvb_offset; +}; + + +static void compat_input(struct dlm_write_request *kparams, struct dlm_write_request32 *k32params) +{ + + kparams->version[0] = k32params->version[0]; + kparams->version[1] = k32params->version[1]; + kparams->version[2] = k32params->version[2]; + + kparams->cmd = k32params->cmd; + kparams->is64bit = k32params->is64bit; + if (kparams->cmd == DLM_USER_CREATE_LOCKSPACE || + kparams->cmd == DLM_USER_REMOVE_LOCKSPACE) { + + kparams->i.lspace.flags = k32params->i.lspace.flags; + kparams->i.lspace.minor = k32params->i.lspace.minor; + strcpy(kparams->i.lspace.name, k32params->i.lspace.name); + } + else { + kparams->i.lock.mode = k32params->i.lock.mode; + kparams->i.lock.namelen = k32params->i.lock.namelen; + kparams->i.lock.flags = k32params->i.lock.flags; + kparams->i.lock.lkid = k32params->i.lock.lkid; + kparams->i.lock.parent = k32params->i.lock.parent; + kparams->i.lock.castparam = (void *)(long)k32params->i.lock.castparam; + kparams->i.lock.castaddr = (void *)(long)k32params->i.lock.castaddr; + kparams->i.lock.bastparam = (void *)(long)k32params->i.lock.bastparam; + kparams->i.lock.bastaddr = (void *)(long)k32params->i.lock.bastaddr; + kparams->i.lock.lksb = (void *)(long)k32params->i.lock.lksb; + memcpy(kparams->i.lock.lvb, k32params->i.lock.lvb, DLM_USER_LVB_LEN); + memcpy(kparams->i.lock.name, k32params->i.lock.name, kparams->i.lock.namelen); + } +} + +void compat_output(struct dlm_lock_result *res, struct dlm_lock_result32 *res32) +{ + res32->length = res->length - (sizeof(struct dlm_lock_result) - sizeof(struct dlm_lock_result32)); + res32->user_astaddr = (__u32)(long)res->user_astaddr; + res32->user_astparam = (__u32)(long)res->user_astparam; + res32->user_lksb = (__u32)(long)res->user_lksb; + res32->bast_mode = res->bast_mode; + + res32->lvb_offset = res->lvb_offset; + res32->length = res->length; + + res32->lksb.sb_status = res->lksb.sb_status; + res32->lksb.sb_flags = res->lksb.sb_flags; + res32->lksb.sb_lkid = res->lksb.sb_lkid; + res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr; +} +#endif + /* get and put ops for file_info. Actually I don't really like "get" and "put", but everyone @@ -364,7 +468,7 @@ static void ast_routine(void *param) li->li_grmode = li->li_rqmode; /* Only queue AST if the device is still open */ - if (test_bit(1, &li->li_file->fi_flags)) + if (test_bit(FI_FLAG_OPEN, &li->li_file->fi_flags)) add_to_astqueue(li, li->li_castaddr, li->li_castparam, lvb_updated); @@ -449,7 +553,7 @@ static int dlm_open(struct inode *inode, struct file *file) f->fi_ls = lsinfo; f->fi_flags = 0; get_file_info(f); - set_bit(1, &f->fi_flags); + set_bit(FI_FLAG_OPEN, &f->fi_flags); file->private_data = f; @@ -494,7 +598,7 @@ static int dlm_close(struct inode *inode, struct file *file) return -ENOENT; /* Mark this closed so that ASTs will not be delivered any more */ - clear_bit(1, &f->fi_flags); + clear_bit(FI_FLAG_OPEN, &f->fi_flags); /* Block signals while we are doing this */ sigfillset(&allsigs); @@ -643,11 +747,18 @@ static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, { struct file_info *fi = file->private_data; struct ast_info *ast; + void *data; int data_size; + int struct_size; int offset; DECLARE_WAITQUEUE(wait, current); +#ifdef CONFIG_COMPAT + struct dlm_lock_result32 result32; + if (count < sizeof(struct dlm_lock_result32)) +#else if (count < sizeof(struct dlm_lock_result)) +#endif return -EINVAL; spin_lock(&fi->fi_ast_lock); @@ -691,11 +802,21 @@ static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, spin_unlock(&fi->fi_ast_lock); /* Work out the size of the returned data */ - data_size = sizeof(struct dlm_lock_result); +#ifdef CONFIG_COMPAT + if (test_bit(FI_FLAG_COMPAT, &fi->fi_flags)) { + data_size = struct_size = sizeof(struct dlm_lock_result32); + data = &result32; + } + else +#endif + { + data_size = struct_size = sizeof(struct dlm_lock_result); + data = &ast->result; + } if (ast->lvb_updated && ast->result.lksb.sb_lvbptr) data_size += DLM_USER_LVB_LEN; - offset = sizeof(struct dlm_lock_result); + offset = struct_size; /* Room for the extended data ? */ if (count >= data_size) { @@ -711,8 +832,13 @@ static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, } ast->result.length = data_size; + +#ifdef CONFIG_COMPAT + compat_output(&ast->result, &result32); +#endif + /* Copy the header now it has all the offsets in it */ - if (copy_to_user(buffer, &ast->result, sizeof(struct dlm_lock_result))) + if (copy_to_user(buffer, data, struct_size)) offset = -EFAULT; /* If we only returned a header and there's more to come then put it @@ -970,8 +1096,14 @@ static ssize_t dlm_write(struct file *file, const char __user *buffer, sigset_t allsigs; int status; - /* -1 because lock name is optional */ - if (count < sizeof(struct dlm_write_request)-1) +#ifdef CONFIG_COMPAT + if (count < sizeof(struct dlm_write_request32)) +#else + if (count < sizeof(struct dlm_write_request)) +#endif + return -EINVAL; + + if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN) return -EINVAL; /* Has the lockspace been deleted */ @@ -991,6 +1123,20 @@ static ssize_t dlm_write(struct file *file, const char __user *buffer, if (check_version(kparams)) goto out_free; +#ifdef CONFIG_COMPAT + if (!kparams->is64bit) { + struct dlm_write_request32 *k32params = (struct dlm_write_request32 *)kparams; + kparams = kmalloc(count + (sizeof(struct dlm_write_request) - sizeof(struct dlm_write_request32)), GFP_KERNEL); + if (!kparams) + return -ENOMEM; + + if (fi) + set_bit(FI_FLAG_COMPAT, &fi->fi_flags); + compat_input(kparams, k32params); + kfree(k32params); + } +#endif + /* Block signals while we are doing this */ sigfillset(&allsigs); sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h index f8ba1981aa96..2a2dd189b9fd 100644 --- a/include/linux/dlm_device.h +++ b/include/linux/dlm_device.h @@ -18,35 +18,37 @@ #define DLM_USER_LVB_LEN 32 /* Version of the device interface */ -#define DLM_DEVICE_VERSION_MAJOR 4 +#define DLM_DEVICE_VERSION_MAJOR 5 #define DLM_DEVICE_VERSION_MINOR 0 #define DLM_DEVICE_VERSION_PATCH 0 /* struct passed to the lock write */ struct dlm_lock_params { __u8 mode; + __u8 namelen; __u16 flags; __u32 lkid; __u32 parent; - __u8 namelen; void __user *castparam; void __user *castaddr; void __user *bastparam; void __user *bastaddr; struct dlm_lksb __user *lksb; char lvb[DLM_USER_LVB_LEN]; - char name[1]; + char name[0]; }; struct dlm_lspace_params { __u32 flags; __u32 minor; - char name[1]; + char name[0]; }; struct dlm_write_request { __u32 version[3]; __u8 cmd; + __u8 is64bit; + __u8 unused[2]; union { struct dlm_lock_params lock; @@ -63,6 +65,7 @@ struct dlm_lock_result { struct dlm_lksb __user * user_lksb; struct dlm_lksb lksb; __u8 bast_mode; + __u8 unused[3]; /* Offsets may be zero if no data is present */ __u32 lvb_offset; }; -- cgit v1.2.3 From feaa7bba026c181ce071d5a4884f7f9dd26207a1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 14 Jun 2006 15:32:57 -0400 Subject: [GFS2] Fix unlinked file handling This patch fixes the way we have been dealing with unlinked, but still open files. It removes all limits (other than memory for inodes, as per every other filesystem) on numbers of these which we can support on GFS2. It also means that (like other fs) its the responsibility of the last process to close the file to deallocate the storage, rather than the person who did the unlinking. Note that with GFS2, those two events might take place on different nodes. Also there are a number of other changes: o We use the Linux inode subsystem as it was intended to be used, wrt allocating GFS2 inodes o The Linux inode cache is now the point which we use for local enforcement of only holding one copy of the inode in core at once (previous to this we used the glock layer). o We no longer use the unlinked "special" file. We just ignore it completely. This makes unlinking more efficient. o We now use the 4th block allocation state. The previously unused state is used to track unlinked but still open inodes. o gfs2_inoded is no longer needed o Several fields are now no longer needed (and removed) from the in core struct gfs2_inode o Several fields are no longer needed (and removed) from the in core superblock There are a number of future possible optimisations and clean ups which have been made possible by this patch. Signed-off-by: Steven Whitehouse --- fs/gfs2/Makefile | 2 +- fs/gfs2/acl.c | 10 +- fs/gfs2/bmap.c | 44 +-- fs/gfs2/daemon.c | 27 -- fs/gfs2/daemon.h | 1 - fs/gfs2/dir.c | 66 ++-- fs/gfs2/eaops.c | 14 +- fs/gfs2/eattr.c | 70 ++-- fs/gfs2/glock.c | 102 ++---- fs/gfs2/glock.h | 5 +- fs/gfs2/glops.c | 9 +- fs/gfs2/incore.h | 48 +-- fs/gfs2/inode.c | 809 ++++++++++---------------------------------- fs/gfs2/inode.h | 32 +- fs/gfs2/log.c | 3 + fs/gfs2/lops.c | 30 +- fs/gfs2/main.c | 2 - fs/gfs2/meta_io.c | 12 +- fs/gfs2/ondisk.c | 17 - fs/gfs2/ops_address.c | 31 +- fs/gfs2/ops_dentry.c | 6 +- fs/gfs2/ops_export.c | 60 ++-- fs/gfs2/ops_file.c | 42 +-- fs/gfs2/ops_fstype.c | 103 ++---- fs/gfs2/ops_inode.c | 168 ++++----- fs/gfs2/ops_super.c | 112 ++++-- fs/gfs2/ops_vm.c | 12 +- fs/gfs2/page.c | 64 ++-- fs/gfs2/quota.c | 28 +- fs/gfs2/recovery.c | 23 +- fs/gfs2/rgrp.c | 118 ++++--- fs/gfs2/rgrp.h | 1 + fs/gfs2/super.c | 45 +-- fs/gfs2/sys.c | 2 - fs/gfs2/trans.h | 1 - fs/gfs2/unlinked.c | 459 ------------------------- fs/gfs2/unlinked.h | 25 -- fs/gfs2/util.c | 2 +- include/linux/gfs2_ondisk.h | 34 +- 39 files changed, 746 insertions(+), 1893 deletions(-) delete mode 100644 fs/gfs2/unlinked.c delete mode 100644 fs/gfs2/unlinked.h (limited to 'include/linux') diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 9974201aa16c..0b7977623b80 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -3,7 +3,7 @@ gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \ glops.o inode.o lm.o log.o lops.o locking.o lvb.o main.o meta_io.o \ mount.o ondisk.o ops_address.o ops_dentry.o ops_export.o ops_file.o \ ops_fstype.o ops_inode.o ops_super.o ops_vm.o page.o quota.o \ - recovery.o rgrp.o super.o sys.o trans.o unlinked.o util.o + recovery.o rgrp.o super.o sys.o trans.o util.o obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/ obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += locking/dlm/ diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 343dbe3e87bb..9ef4cf2c03db 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -73,7 +73,7 @@ int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) { - if (!ip->i_sbd->sd_args.ar_posix_acl) + if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl) return -EOPNOTSUPP; if (current->fsuid != ip->i_di.di_uid && !capable(CAP_FOWNER)) return -EPERM; @@ -160,7 +160,7 @@ int gfs2_check_acl_locked(struct inode *inode, int mask) struct posix_acl *acl = NULL; int error; - error = acl_get(inode->u.generic_ip, ACL_ACCESS, &acl, NULL, NULL, NULL); + error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL); if (error) return error; @@ -175,7 +175,7 @@ int gfs2_check_acl_locked(struct inode *inode, int mask) int gfs2_check_acl(struct inode *inode, int mask) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder i_gh; int error; @@ -192,7 +192,7 @@ int gfs2_check_acl(struct inode *inode, int mask) static int munge_mode(struct gfs2_inode *ip, mode_t mode) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *dibh; int error; @@ -217,7 +217,7 @@ static int munge_mode(struct gfs2_inode *ip, mode_t mode) int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct posix_acl *acl = NULL, *clone; struct gfs2_ea_request er; mode_t mode = ip->i_di.di_mode; diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 41abd3f4fc73..98fa07c2b710 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -136,7 +136,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, static unsigned int calc_tree_height(struct gfs2_inode *ip, uint64_t size) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); uint64_t *arr; unsigned int max, height; @@ -169,7 +169,7 @@ static unsigned int calc_tree_height(struct gfs2_inode *ip, uint64_t size) static int build_height(struct inode *inode, unsigned height) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); unsigned new_height = height - ip->i_di.di_height; struct buffer_head *dibh; struct buffer_head *blocks[GFS2_MAX_META_HEIGHT]; @@ -283,7 +283,7 @@ static int build_height(struct inode *inode, unsigned height) static void find_metapath(struct gfs2_inode *ip, uint64_t block, struct metapath *mp) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); uint64_t b = block; unsigned int i; @@ -382,8 +382,8 @@ static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock, int *boundary, struct metapath *mp) { - struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); struct buffer_head *bh; int create = *new; unsigned int bsize; @@ -446,7 +446,7 @@ out: static inline void bmap_lock(struct inode *inode, int create) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); if (create) down_write(&ip->i_rw_mutex); else @@ -455,7 +455,7 @@ static inline void bmap_lock(struct inode *inode, int create) static inline void bmap_unlock(struct inode *inode, int create) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); if (create) up_write(&ip->i_rw_mutex); else @@ -481,8 +481,8 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int * int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) { - struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); struct metapath mp; struct buffer_head *bh; int boundary; @@ -541,7 +541,7 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, uint64_t block, int first, block_call_t bc, void *data) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *bh = NULL; uint64_t *top, *bottom; uint64_t bn; @@ -609,8 +609,8 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, struct buffer_head *bh, uint64_t *top, uint64_t *bottom, unsigned int height, void *data) { - struct strip_mine *sm = (struct strip_mine *)data; - struct gfs2_sbd *sdp = ip->i_sbd; + struct strip_mine *sm = data; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrp_list rlist; uint64_t bn, bstart; uint32_t blen; @@ -756,7 +756,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, static int do_grow(struct gfs2_inode *ip, uint64_t size) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al; struct buffer_head *dibh; unsigned int h; @@ -795,7 +795,7 @@ static int do_grow(struct gfs2_inode *ip, uint64_t size) h = calc_tree_height(ip, size); if (ip->i_di.di_height < h) { down_write(&ip->i_rw_mutex); - error = build_height(ip->i_vnode, h); + error = build_height(&ip->i_inode, h); up_write(&ip->i_rw_mutex); if (error) goto out_end_trans; @@ -830,7 +830,7 @@ static int do_grow(struct gfs2_inode *ip, uint64_t size) static int trunc_start(struct gfs2_inode *ip, uint64_t size) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *dibh; int journaled = gfs2_is_jdata(ip); int error; @@ -854,7 +854,7 @@ static int trunc_start(struct gfs2_inode *ip, uint64_t size) } else { if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1)) - error = gfs2_block_truncate_page(ip->i_vnode->i_mapping); + error = gfs2_block_truncate_page(ip->i_inode.i_mapping); if (!error) { ip->i_di.di_size = size; @@ -883,7 +883,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, uint64_t size) if (!size) lblock = 0; else - lblock = (size - 1) >> ip->i_sbd->sd_sb.sb_bsize_shift; + lblock = (size - 1) >> GFS2_SB(&ip->i_inode)->sd_sb.sb_bsize_shift; find_metapath(ip, lblock, &mp); gfs2_alloc_get(ip); @@ -911,7 +911,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, uint64_t size) static int trunc_end(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *dibh; int error; @@ -990,7 +990,7 @@ int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size) { int error; - if (gfs2_assert_warn(ip->i_sbd, S_ISREG(ip->i_di.di_mode))) + if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_di.di_mode))) return -EINVAL; if (size > ip->i_di.di_size) @@ -1027,7 +1027,7 @@ int gfs2_file_dealloc(struct gfs2_inode *ip) void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len, unsigned int *data_blocks, unsigned int *ind_blocks) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); unsigned int tmp; if (gfs2_is_dir(ip)) { @@ -1057,7 +1057,7 @@ void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len, int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset, unsigned int len, int *alloc_required) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); uint64_t lblock, lblock_stop, dblock; uint32_t extlen; int new = 0; @@ -1088,7 +1088,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset, } for (; lblock < lblock_stop; lblock += extlen) { - error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen); + error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); if (error) return error; diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index 9e7b9f296786..1453605c8f32 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -25,7 +25,6 @@ #include "quota.h" #include "recovery.h" #include "super.h" -#include "unlinked.h" #include "util.h" /* This uses schedule_timeout() instead of msleep() because it's good for @@ -195,29 +194,3 @@ int gfs2_quotad(void *data) return 0; } -/** - * gfs2_inoded - Deallocate unlinked inodes - * @sdp: Pointer to GFS2 superblock - * - */ - -int gfs2_inoded(void *data) -{ - struct gfs2_sbd *sdp = data; - unsigned long t; - int error; - - while (!kthread_should_stop()) { - error = gfs2_unlinked_dealloc(sdp); - if (error && - error != -EROFS && - !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) - fs_err(sdp, "inoded: error = %d\n", error); - - t = gfs2_tune_get(sdp, gt_inoded_secs) * HZ; - schedule_timeout_interruptible(t); - } - - return 0; -} - diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h index aa68e7a1b0b7..aa93eb6f668e 100644 --- a/fs/gfs2/daemon.h +++ b/fs/gfs2/daemon.h @@ -15,6 +15,5 @@ int gfs2_glockd(void *data); int gfs2_recoverd(void *data); int gfs2_logd(void *data); int gfs2_quotad(void *data); -int gfs2_inoded(void *data); #endif /* __DAEMON_DOT_H__ */ diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 6918a58261e2..b0353884dd7d 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -113,7 +113,7 @@ static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, uint64_t block, error = gfs2_meta_read(ip->i_gl, block, DIO_START | DIO_WAIT, &bh); if (error) return error; - if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_JD)) { + if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) { brelse(bh); return -EIO; } @@ -158,7 +158,7 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, uint64_t offset, unsigned int size) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *dibh; uint64_t lblock, dblock; uint32_t extlen = 0; @@ -197,7 +197,7 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, if (!extlen) { new = 1; - error = gfs2_extent_map(ip->i_vnode, lblock, &new, + error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); if (error) goto fail; @@ -277,7 +277,7 @@ static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, uint64_t offset, unsigned int size) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); uint64_t lblock, dblock; uint32_t extlen = 0; unsigned int o; @@ -314,7 +314,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, if (!extlen) { new = 0; - error = gfs2_extent_map(ip->i_vnode, lblock, &new, + error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); if (error) goto fail; @@ -534,7 +534,7 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, } consist_inode: - gfs2_consist_inode(inode->u.generic_ip); + gfs2_consist_inode(GFS2_I(inode)); return ERR_PTR(-EIO); } @@ -556,13 +556,13 @@ static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh, struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data; if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) { - if (gfs2_meta_check(dip->i_sbd, bh)) + if (gfs2_meta_check(GFS2_SB(&dip->i_inode), bh)) return -EIO; *dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_leaf)); return IS_LEAF; } else { - if (gfs2_metatype_check(dip->i_sbd, bh, GFS2_METATYPE_DI)) + if (gfs2_metatype_check(GFS2_SB(&dip->i_inode), bh, GFS2_METATYPE_DI)) return -EIO; *dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_dinode)); @@ -674,7 +674,7 @@ static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode, const struct qstr *name, struct buffer_head *bh) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_dirent *ndent; unsigned offset = 0, totlen; @@ -707,8 +707,10 @@ static int get_leaf(struct gfs2_inode *dip, uint64_t leaf_no, int error; error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_START | DIO_WAIT, bhp); - if (!error && gfs2_metatype_check(dip->i_sbd, *bhp, GFS2_METATYPE_LF)) + if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) { + /* printk(KERN_INFO "block num=%llu\n", leaf_no); */ error = -EIO; + } return error; } @@ -759,7 +761,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, { struct buffer_head *bh; struct gfs2_dirent *dent; - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); int error; if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { @@ -771,7 +773,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, gfs2_consist_inode(ip); return ERR_PTR(-EIO); } - + index = name->hash >> (32 - ip->i_di.di_depth); error = get_first_leaf(ip, index, &bh); if (error) @@ -786,12 +788,14 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, brelse(bh); if (!ln) break; + error = get_leaf(ip, ln, &bh); } while(!error); return error ? ERR_PTR(error) : NULL; } + error = gfs2_meta_inode_buffer(ip, &bh); if (error) return ERR_PTR(error); @@ -807,7 +811,7 @@ got_dent: static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); u64 bn = gfs2_alloc_meta(ip); struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); struct gfs2_leaf *leaf; @@ -815,6 +819,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, struct qstr name = { .name = "", .len = 0, .hash = 0 }; if (!bh) return NULL; + gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF); leaf = (struct gfs2_leaf *)bh->b_data; @@ -838,8 +843,8 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, static int dir_make_exhash(struct inode *inode) { - struct gfs2_inode *dip = inode->u.generic_ip; - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *dip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_dirent *dent; struct qstr args; struct buffer_head *bh, *dibh; @@ -874,7 +879,7 @@ static int dir_make_exhash(struct inode *inode) args.len = bh->b_size - sizeof(struct gfs2_dinode) + sizeof(struct gfs2_leaf); args.name = bh->b_data; - dent = gfs2_dirent_scan(dip->i_vnode, bh->b_data, bh->b_size, + dent = gfs2_dirent_scan(&dip->i_inode, bh->b_data, bh->b_size, gfs2_dirent_last, &args, NULL); if (!dent) { brelse(bh); @@ -933,7 +938,7 @@ static int dir_make_exhash(struct inode *inode) static int dir_split_leaf(struct inode *inode, const struct qstr *name) { - struct gfs2_inode *dip = inode->u.generic_ip; + struct gfs2_inode *dip = GFS2_I(inode); struct buffer_head *nbh, *obh, *dibh; struct gfs2_leaf *nleaf, *oleaf; struct gfs2_dirent *dent, *prev = NULL, *next = NULL, *new; @@ -1044,7 +1049,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) oleaf->lf_depth = nleaf->lf_depth; error = gfs2_meta_inode_buffer(dip, &dibh); - if (!gfs2_assert_withdraw(dip->i_sbd, !error)) { + if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) { dip->i_di.di_blocks++; gfs2_dinode_out(&dip->i_di, dibh->b_data); brelse(dibh); @@ -1073,7 +1078,7 @@ fail_brelse: static int dir_double_exhash(struct gfs2_inode *dip) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct buffer_head *dibh; uint32_t hsize; uint64_t *buf; @@ -1268,7 +1273,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, gfs2_filldir_t filldir, int *copied, unsigned *depth, u64 leaf_no) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct buffer_head *bh; struct gfs2_leaf *lf; unsigned entries = 0; @@ -1348,8 +1353,8 @@ out: static int dir_e_read(struct inode *inode, uint64_t *offset, void *opaque, gfs2_filldir_t filldir) { - struct gfs2_inode *dip = inode->u.generic_ip; - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *dip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); uint32_t hsize, len = 0; uint32_t ht_offset, lp_offset, ht_offset_cur = -1; uint32_t hash, index; @@ -1407,7 +1412,7 @@ out: int gfs2_dir_read(struct inode *inode, uint64_t *offset, void *opaque, gfs2_filldir_t filldir) { - struct gfs2_inode *dip = inode->u.generic_ip; + struct gfs2_inode *dip = GFS2_I(inode); struct dirent_gather g; const struct gfs2_dirent **darr, *dent; struct buffer_head *dibh; @@ -1490,7 +1495,7 @@ int gfs2_dir_search(struct inode *dir, const struct qstr *name, static int dir_new_leaf(struct inode *inode, const struct qstr *name) { struct buffer_head *bh, *obh; - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_leaf *leaf, *oleaf; int error; u32 index; @@ -1545,7 +1550,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) int gfs2_dir_add(struct inode *inode, const struct qstr *name, const struct gfs2_inum *inum, unsigned type) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct buffer_head *bh; struct gfs2_dirent *dent; struct gfs2_leaf *leaf; @@ -1623,7 +1628,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) /* Returns _either_ the entry (if its first in block) or the previous entry otherwise */ - dent = gfs2_dirent_search(dip->i_vnode, name, gfs2_dirent_prev, &bh); + dent = gfs2_dirent_search(&dip->i_inode, name, gfs2_dirent_prev, &bh); if (!dent) { gfs2_consist_inode(dip); return -EIO; @@ -1659,6 +1664,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); gfs2_dinode_out(&dip->i_di, bh->b_data); brelse(bh); + mark_inode_dirty(&dip->i_inode); return error; } @@ -1683,7 +1689,7 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, struct gfs2_dirent *dent; int error; - dent = gfs2_dirent_search(dip->i_vnode, filename, gfs2_dirent_find, &bh); + dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh); if (!dent) { gfs2_consist_inode(dip); return -EIO; @@ -1720,7 +1726,7 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct buffer_head *bh; struct gfs2_leaf *leaf; uint32_t hsize, len; @@ -1800,7 +1806,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, uint64_t leaf_no, void *data) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_leaf *tmp_leaf; struct gfs2_rgrp_list rlist; struct buffer_head *bh, *dibh; @@ -1920,7 +1926,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct buffer_head *bh; int error; diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 1c5ac3160b3b..b7e6a37cab6e 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -58,7 +58,7 @@ unsigned int gfs2_ea_name2type(const char *name, char **truncated_name) static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) { - struct inode *inode = ip->i_vnode; + struct inode *inode = &ip->i_inode; int error = permission(inode, MAY_READ, NULL); if (error) return error; @@ -68,7 +68,7 @@ static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) { - struct inode *inode = ip->i_vnode; + struct inode *inode = &ip->i_inode; if (S_ISREG(inode->i_mode) || (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) { @@ -83,7 +83,7 @@ static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) { - struct inode *inode = ip->i_vnode; + struct inode *inode = &ip->i_inode; if (S_ISREG(inode->i_mode) || (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) { @@ -103,7 +103,7 @@ static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) !capable(CAP_SYS_ADMIN)) return -EPERM; - if (ip->i_sbd->sd_args.ar_posix_acl == 0 && + if (GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl == 0 && (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) || GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len))) return -EOPNOTSUPP; @@ -172,7 +172,7 @@ static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) { - struct inode *inode = ip->i_vnode; + struct inode *inode = &ip->i_inode; int error = permission(inode, MAY_READ, NULL); if (error) return error; @@ -182,7 +182,7 @@ static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) { - struct inode *inode = ip->i_vnode; + struct inode *inode = &ip->i_inode; int error = permission(inode, MAY_WRITE, NULL); if (error) return error; @@ -192,7 +192,7 @@ static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) { - struct inode *inode = ip->i_vnode; + struct inode *inode = &ip->i_inode; int error = permission(inode, MAY_WRITE, NULL); if (error) return error; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 2e114c075707..96736932260f 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -80,7 +80,7 @@ static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh, struct gfs2_ea_header *ea, *prev = NULL; int error = 0; - if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_EA)) + if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_EA)) return -EIO; for (ea = GFS2_EA_BH2FIRST(bh);; prev = ea, ea = GFS2_EA2NEXT(ea)) { @@ -128,13 +128,13 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) goto out; } - if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_IN)) { + if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_IN)) { error = -EIO; goto out; } eablk = (uint64_t *)(bh->b_data + sizeof(struct gfs2_meta_header)); - end = eablk + ip->i_sbd->sd_inptrs; + end = eablk + GFS2_SB(&ip->i_inode)->sd_inptrs; for (; eablk < end; eablk++) { uint64_t bn; @@ -232,7 +232,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, struct gfs2_ea_header *prev, void *private) { int *leave = private; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrpd *rgd; struct gfs2_holder rg_gh; struct buffer_head *dibh; @@ -338,7 +338,7 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, if (error) goto out_alloc; - error = gfs2_rindex_hold(ip->i_sbd, &al->al_ri_gh); + error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh); if (error) goto out_quota; @@ -459,7 +459,7 @@ int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, char *data) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head **bh; unsigned int amount = GFS2_EA_DATA_LEN(ea); unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize); @@ -604,7 +604,7 @@ int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_ea_header *ea; uint64_t block; @@ -641,7 +641,7 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, struct gfs2_ea_request *er) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); ea->ea_data_len = cpu_to_be32(er->er_data_len); ea->ea_name_len = er->er_name_len; @@ -723,7 +723,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, if (error) goto out_gunlock_q; - error = gfs2_trans_begin(ip->i_sbd, + error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), blks + al->al_rgd->rd_ri.ri_length + RES_DINODE + RES_STATFS + RES_QUOTA, 0); if (error) @@ -736,7 +736,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { if (er->er_flags & GFS2_ERF_MODE) { - gfs2_assert_withdraw(ip->i_sbd, + gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), (ip->i_di.di_mode & S_IFMT) == (er->er_mode & S_IFMT)); ip->i_di.di_mode = er->er_mode; @@ -748,7 +748,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, } out_end_trans: - gfs2_trans_end(ip->i_sbd); + gfs2_trans_end(GFS2_SB(&ip->i_inode)); out_ipres: gfs2_inplace_release(ip); @@ -790,7 +790,7 @@ static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er) { - unsigned int jbsize = ip->i_sbd->sd_jbsize; + unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; unsigned int blks = 1; if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize) @@ -830,7 +830,7 @@ static void ea_set_remove_stuffed(struct gfs2_inode *ip, return; } else if (GFS2_EA2NEXT(prev) != ea) { prev = GFS2_EA2NEXT(prev); - gfs2_assert_withdraw(ip->i_sbd, GFS2_EA2NEXT(prev) == ea); + gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), GFS2_EA2NEXT(prev) == ea); } len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea); @@ -857,7 +857,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, struct buffer_head *dibh; int error; - error = gfs2_trans_begin(ip->i_sbd, RES_DINODE + 2 * RES_EATTR, 0); + error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + 2 * RES_EATTR, 0); if (error) return error; @@ -876,7 +876,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, goto out; if (er->er_flags & GFS2_ERF_MODE) { - gfs2_assert_withdraw(ip->i_sbd, + gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), (ip->i_di.di_mode & S_IFMT) == (er->er_mode & S_IFMT)); ip->i_di.di_mode = er->er_mode; } @@ -885,7 +885,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); out: - gfs2_trans_end(ip->i_sbd); + gfs2_trans_end(GFS2_SB(&ip->i_inode)); return error; } @@ -921,7 +921,7 @@ static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, int stuffed; int error; - stuffed = ea_calc_size(ip->i_sbd, es->es_er, &size); + stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er, &size); if (ea->ea_type == GFS2_EATYPE_UNUSED) { if (GFS2_EA_REC_LEN(ea) < size) @@ -947,7 +947,7 @@ static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, es->es_bh = bh; es->es_ea = ea; blks = 2 + DIV_ROUND_UP(es->es_er->er_data_len, - ip->i_sbd->sd_jbsize); + GFS2_SB(&ip->i_inode)->sd_jbsize); error = ea_alloc_skeleton(ip, es->es_er, blks, ea_set_simple_alloc, es); @@ -961,7 +961,7 @@ static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, void *private) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *indbh, *newbh; uint64_t *eablk; int error; @@ -1050,8 +1050,8 @@ static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT)) blks++; - if (GFS2_EAREQ_SIZE_STUFFED(er) > ip->i_sbd->sd_jbsize) - blks += DIV_ROUND_UP(er->er_data_len, ip->i_sbd->sd_jbsize); + if (GFS2_EAREQ_SIZE_STUFFED(er) > GFS2_SB(&ip->i_inode)->sd_jbsize) + blks += DIV_ROUND_UP(er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); return ea_alloc_skeleton(ip, er, blks, ea_set_block, el); } @@ -1061,7 +1061,7 @@ static int ea_set_remove_unstuffed(struct gfs2_inode *ip, { if (el->el_prev && GFS2_EA2NEXT(el->el_prev) != el->el_ea) { el->el_prev = GFS2_EA2NEXT(el->el_prev); - gfs2_assert_withdraw(ip->i_sbd, + gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), GFS2_EA2NEXT(el->el_prev) == el->el_ea); } @@ -1119,7 +1119,7 @@ int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) er->er_data = NULL; er->er_data_len = 0; } - error = ea_check_size(ip->i_sbd, er); + error = ea_check_size(GFS2_SB(&ip->i_inode), er); if (error) return error; @@ -1127,7 +1127,7 @@ int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) if (error) return error; - if (IS_IMMUTABLE(ip->i_vnode)) + if (IS_IMMUTABLE(&ip->i_inode)) error = -EPERM; else error = gfs2_ea_ops[er->er_type]->eo_set(ip, er); @@ -1144,7 +1144,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) struct buffer_head *dibh; int error; - error = gfs2_trans_begin(ip->i_sbd, RES_DINODE + RES_EATTR, 0); + error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0); if (error) return error; @@ -1169,7 +1169,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) brelse(dibh); } - gfs2_trans_end(ip->i_sbd); + gfs2_trans_end(GFS2_SB(&ip->i_inode)); return error; } @@ -1219,7 +1219,7 @@ int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) if (error) return error; - if (IS_IMMUTABLE(ip->i_vnode) || IS_APPEND(ip->i_vnode)) + if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) error = -EPERM; else error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er); @@ -1232,7 +1232,7 @@ int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, char *data) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head **bh; unsigned int amount = GFS2_EA_DATA_LEN(ea); unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize); @@ -1304,7 +1304,7 @@ int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, int error; if (GFS2_EA_IS_STUFFED(el->el_ea)) { - error = gfs2_trans_begin(ip->i_sbd, RES_DINODE + RES_EATTR, 0); + error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0); if (error) return error; @@ -1320,22 +1320,22 @@ int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { - error = inode_setattr(ip->i_vnode, attr); - gfs2_assert_warn(ip->i_sbd, !error); + error = inode_setattr(&ip->i_inode, attr); + gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); gfs2_inode_attr_out(ip); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); } - gfs2_trans_end(ip->i_sbd); + gfs2_trans_end(GFS2_SB(&ip->i_inode)); return error; } static int ea_dealloc_indirect(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrp_list rlist; struct buffer_head *indbh, *dibh; uint64_t *eablk, *end; @@ -1456,7 +1456,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) static int ea_dealloc_block(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_rgrpd *rgd; struct buffer_head *dibh; @@ -1518,7 +1518,7 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip) if (error) goto out_alloc; - error = gfs2_rindex_hold(ip->i_sbd, &al->al_ri_gh); + error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh); if (error) goto out_quota; diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 0603a6de52c9..35bac90878a5 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -654,7 +654,7 @@ static void run_queue(struct gfs2_glock *gl) * Gives caller exclusive access to manipulate a glock structure. */ -void gfs2_glmutex_lock(struct gfs2_glock *gl) +static void gfs2_glmutex_lock(struct gfs2_glock *gl) { struct gfs2_holder gh; @@ -704,7 +704,7 @@ static int gfs2_glmutex_trylock(struct gfs2_glock *gl) * */ -void gfs2_glmutex_unlock(struct gfs2_glock *gl) +static void gfs2_glmutex_unlock(struct gfs2_glock *gl) { spin_lock(&gl->gl_spin); clear_bit(GLF_LOCK, &gl->gl_flags); @@ -726,7 +726,7 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state) { struct gfs2_holder *gh, *new_gh = NULL; - restart: +restart: spin_lock(&gl->gl_spin); list_for_each_entry(gh, &gl->gl_waiters2, gh_list) { @@ -752,13 +752,27 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state) goto restart; } - out: +out: spin_unlock(&gl->gl_spin); if (new_gh) gfs2_holder_put(new_gh); } +void gfs2_glock_inode_squish(struct inode *inode) +{ + struct gfs2_holder gh; + struct gfs2_glock *gl = GFS2_I(inode)->i_gl; + gfs2_holder_init(gl, LM_ST_UNLOCKED, 0, &gh); + set_bit(HIF_DEMOTE, &gh.gh_iflags); + spin_lock(&gl->gl_spin); + gfs2_assert(inode->i_sb->s_fs_info, list_empty(&gl->gl_holders)); + list_add_tail(&gh.gh_list, &gl->gl_waiters2); + run_queue(gl); + spin_unlock(&gl->gl_spin); + gfs2_holder_uninit(&gh); +} + /** * state_change - record that the glock is now in a different state * @gl: the glock @@ -1383,8 +1397,7 @@ int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time) struct greedy *gr; struct gfs2_holder *gh; - if (!time || - gl->gl_sbd->sd_args.ar_localcaching || + if (!time || gl->gl_sbd->sd_args.ar_localcaching || test_and_set_bit(GLF_GREEDY, &gl->gl_flags)) return 1; @@ -1784,43 +1797,6 @@ void gfs2_glock_cb(lm_fsdata_t *fsdata, unsigned int type, void *data) } } -/** - * gfs2_try_toss_inode - try to remove a particular inode struct from cache - * sdp: the filesystem - * inum: the inode number - * - */ - -void gfs2_try_toss_inode(struct gfs2_sbd *sdp, struct gfs2_inum *inum) -{ - struct gfs2_glock *gl; - struct gfs2_inode *ip; - int error; - - error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_inode_glops, - NO_CREATE, &gl); - if (error || !gl) - return; - - if (!gfs2_glmutex_trylock(gl)) - goto out; - - ip = gl->gl_object; - if (!ip) - goto out_unlock; - - if (atomic_read(&ip->i_count)) - goto out_unlock; - - gfs2_inode_destroy(ip, 1); - - out_unlock: - gfs2_glmutex_unlock(gl); - - out: - gfs2_glock_put(gl); -} - /** * gfs2_iopen_go_callback - Try to kick the inode/vnode associated with an * iopen glock from memory @@ -1831,34 +1807,10 @@ void gfs2_try_toss_inode(struct gfs2_sbd *sdp, struct gfs2_inum *inum) void gfs2_iopen_go_callback(struct gfs2_glock *io_gl, unsigned int state) { - struct gfs2_glock *i_gl; if (state != LM_ST_UNLOCKED) return; - - spin_lock(&io_gl->gl_spin); - i_gl = io_gl->gl_object; - if (i_gl) { - gfs2_glock_hold(i_gl); - spin_unlock(&io_gl->gl_spin); - } else { - spin_unlock(&io_gl->gl_spin); - return; - } - - if (gfs2_glmutex_trylock(i_gl)) { - struct gfs2_inode *ip = i_gl->gl_object; - if (ip) { - gfs2_try_toss_vnode(ip); - gfs2_glmutex_unlock(i_gl); - gfs2_glock_schedule_for_reclaim(i_gl); - goto out; - } - gfs2_glmutex_unlock(i_gl); - } - - out: - gfs2_glock_put(i_gl); + /* FIXME: remove this? */ } /** @@ -1935,11 +1887,6 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp) atomic_inc(&sdp->sd_reclaimed); if (gfs2_glmutex_trylock(gl)) { - if (gl->gl_ops == &gfs2_inode_glops) { - struct gfs2_inode *ip = gl->gl_object; - if (ip && !atomic_read(&ip->i_count)) - gfs2_inode_destroy(ip, 1); - } if (queue_empty(gl, &gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl)) @@ -2018,7 +1965,7 @@ static void scan_glock(struct gfs2_glock *gl) if (gfs2_glmutex_trylock(gl)) { if (gl->gl_ops == &gfs2_inode_glops) { struct gfs2_inode *ip = gl->gl_object; - if (ip && !atomic_read(&ip->i_count)) + if (ip) goto out_schedule; } if (queue_empty(gl, &gl->gl_holders) && @@ -2078,11 +2025,6 @@ static void clear_glock(struct gfs2_glock *gl) } if (gfs2_glmutex_trylock(gl)) { - if (gl->gl_ops == &gfs2_inode_glops) { - struct gfs2_inode *ip = gl->gl_object; - if (ip && !atomic_read(&ip->i_count)) - gfs2_inode_destroy(ip, 1); - } if (queue_empty(gl, &gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED) handle_callback(gl, LM_ST_UNLOCKED); @@ -2199,13 +2141,11 @@ static int dump_inode(struct gfs2_inode *ip) (unsigned long long)ip->i_num.no_formal_ino, (unsigned long long)ip->i_num.no_addr); printk(KERN_INFO " type = %u\n", IF2DT(ip->i_di.di_mode)); - printk(KERN_INFO " i_count = %d\n", atomic_read(&ip->i_count)); printk(KERN_INFO " i_flags ="); for (x = 0; x < 32; x++) if (test_bit(x, &ip->i_flags)) printk(" %u", x); printk(" \n"); - printk(KERN_INFO " vnode = %s\n", (ip->i_vnode) ? "yes" : "no"); error = 0; diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 2e0a2ba92aa0..fdf58db44ae3 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -88,9 +88,6 @@ void gfs2_holder_uninit(struct gfs2_holder *gh); void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags); void gfs2_glock_drop_th(struct gfs2_glock *gl); -void gfs2_glmutex_lock(struct gfs2_glock *gl); -void gfs2_glmutex_unlock(struct gfs2_glock *gl); - int gfs2_glock_nq(struct gfs2_holder *gh); int gfs2_glock_poll(struct gfs2_holder *gh); int gfs2_glock_wait(struct gfs2_holder *gh); @@ -110,6 +107,7 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs); void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, uint64_t number, struct gfs2_glock_operations *glops, unsigned int state, int flags); +void gfs2_glock_inode_squish(struct inode *inode); /** * gfs2_glock_nq_init - intialize a holder and enqueue it on a glock @@ -143,7 +141,6 @@ void gfs2_lvb_unhold(struct gfs2_glock *gl); void gfs2_glock_cb(lm_fsdata_t *fsdata, unsigned int type, void *data); -void gfs2_try_toss_inode(struct gfs2_sbd *sdp, struct gfs2_inum *inum); void gfs2_iopen_go_callback(struct gfs2_glock *gl, unsigned int state); void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl); diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index e262f22f744e..013bf5f1552f 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -129,6 +129,7 @@ static void inode_go_xmote_bh(struct gfs2_glock *gl) static void inode_go_drop_th(struct gfs2_glock *gl) { + printk(KERN_INFO "drop th %p\n", gl->gl_object); gfs2_pte_inval(gl); gfs2_glock_drop_th(gl); } @@ -147,6 +148,7 @@ static void inode_go_sync(struct gfs2_glock *gl, int flags) if (test_bit(GLF_DIRTY, &gl->gl_flags)) { if (meta && data) { + printk(KERN_INFO "sync all\n"); gfs2_page_sync(gl, flags | DIO_START); gfs2_log_flush(gl->gl_sbd, gl); gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT); @@ -224,6 +226,7 @@ static int inode_go_lock(struct gfs2_holder *gh) return 0; if (ip->i_vn != gl->gl_vn) { + printk(KERN_INFO "refresh inode %p\n", &ip->i_inode); error = gfs2_inode_refresh(ip); if (error) return error; @@ -288,7 +291,7 @@ static void inode_greedy(struct gfs2_glock *gl) spin_unlock(&ip->i_spin); - gfs2_inode_put(ip); + iput(&ip->i_inode); } /** @@ -361,14 +364,14 @@ static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state, static void trans_go_xmote_bh(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_sbd; - struct gfs2_inode *ip = sdp->sd_jdesc->jd_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode); struct gfs2_glock *j_gl = ip->i_gl; struct gfs2_log_header head; int error; if (gl->gl_state != LM_ST_UNLOCKED && test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { - gfs2_meta_cache_flush(sdp->sd_jdesc->jd_inode->u.generic_ip); + gfs2_meta_cache_flush(GFS2_I(sdp->sd_jdesc->jd_inode)); j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA); error = gfs2_find_jhead(sdp->sd_jdesc, &head); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 8caefec88854..9a67a5954126 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -33,7 +33,6 @@ struct gfs2_inode; struct gfs2_file; struct gfs2_revoke; struct gfs2_revoke_replay; -struct gfs2_unlinked; struct gfs2_quota_data; struct gfs2_log_buf; struct gfs2_trans; @@ -245,16 +244,12 @@ struct gfs2_inode { struct inode i_inode; struct gfs2_inum i_num; - atomic_t i_count; unsigned long i_flags; /* GIF_... */ uint64_t i_vn; - struct gfs2_dinode i_di; - - struct gfs2_glock *i_gl; - struct gfs2_sbd *i_sbd; - struct inode *i_vnode; + struct gfs2_dinode i_di; /* To be replaced by ref to block */ + struct gfs2_glock *i_gl; /* Move into i_gh? */ struct gfs2_holder i_iopen_gh; struct gfs2_holder i_gh; /* for prepare/commit_write only */ struct gfs2_alloc i_alloc; @@ -262,18 +257,27 @@ struct gfs2_inode { spinlock_t i_spin; struct rw_semaphore i_rw_mutex; - unsigned int i_greedy; unsigned long i_last_pfault; struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT]; }; +/* + * Since i_inode is the first element of struct gfs2_inode, + * this is effectively a cast. + */ static inline struct gfs2_inode *GFS2_I(struct inode *inode) { return container_of(inode, struct gfs2_inode, i_inode); } +/* To be removed? */ +static inline struct gfs2_sbd *GFS2_SB(struct inode *inode) +{ + return inode->i_sb->s_fs_info; +} + enum { GFF_DID_DIRECT_ALLOC = 0, }; @@ -295,18 +299,6 @@ struct gfs2_revoke_replay { unsigned int rr_where; }; -enum { - ULF_LOCKED = 0, -}; - -struct gfs2_unlinked { - struct list_head ul_list; - unsigned int ul_count; - struct gfs2_unlinked_tag ul_ut; - unsigned long ul_flags; /* ULF_... */ - unsigned int ul_slot; -}; - enum { QDF_USER = 0, QDF_CHANGE = 1, @@ -436,7 +428,6 @@ struct gfs2_tune { unsigned int gt_recoverd_secs; unsigned int gt_logd_secs; unsigned int gt_quotad_secs; - unsigned int gt_inoded_secs; unsigned int gt_quota_simul_sync; /* Max quotavals to sync at once */ unsigned int gt_quota_warn_period; /* Secs between quota warn msgs */ @@ -495,7 +486,6 @@ struct gfs2_sbd { uint32_t sd_hash_bsize; /* sizeof(exhash block) */ uint32_t sd_hash_bsize_shift; uint32_t sd_hash_ptrs; /* Number of pointers in a hash block */ - uint32_t sd_ut_per_block; uint32_t sd_qc_per_block; uint32_t sd_max_dirres; /* Max blocks needed to add a directory entry */ uint32_t sd_max_height; /* Max height of a file's metadata tree */ @@ -527,7 +517,6 @@ struct gfs2_sbd { struct inode *sd_statfs_inode; struct inode *sd_ir_inode; struct inode *sd_sc_inode; - struct inode *sd_ut_inode; struct inode *sd_qc_inode; struct inode *sd_rindex; struct inode *sd_quota_inode; @@ -569,7 +558,6 @@ struct gfs2_sbd { struct gfs2_holder sd_ir_gh; struct gfs2_holder sd_sc_gh; - struct gfs2_holder sd_ut_gh; struct gfs2_holder sd_qc_gh; /* Daemon stuff */ @@ -578,21 +566,9 @@ struct gfs2_sbd { struct task_struct *sd_recoverd_process; struct task_struct *sd_logd_process; struct task_struct *sd_quotad_process; - struct task_struct *sd_inoded_process; struct task_struct *sd_glockd_process[GFS2_GLOCKD_MAX]; unsigned int sd_glockd_num; - /* Unlinked inode stuff */ - - struct list_head sd_unlinked_list; - atomic_t sd_unlinked_count; - spinlock_t sd_unlinked_spin; - struct mutex sd_unlinked_mutex; - - unsigned int sd_unlinked_slots; - unsigned int sd_unlinked_chunks; - unsigned char **sd_unlinked_bitmap; - /* Quota stuff */ struct list_head sd_quota_list; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index c2c7d2b63a57..4e9c42119aed 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -35,7 +35,6 @@ #include "quota.h" #include "rgrp.h" #include "trans.h" -#include "unlinked.h" #include "util.h" /** @@ -72,7 +71,7 @@ static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode) inode->i_ctime.tv_nsec = 0; inode->i_blksize = PAGE_SIZE; inode->i_blocks = ip->i_di.di_blocks << - (ip->i_sbd->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT); + (GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT); if (ip->i_di.di_flags & GFS2_DIF_IMMUTABLE) inode->i_flags |= S_IMMUTABLE; @@ -93,13 +92,8 @@ static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode) void gfs2_inode_attr_in(struct gfs2_inode *ip) { - struct inode *inode; - - inode = gfs2_ip2v_lookup(ip); - if (inode) { - inode_attr_in(ip, inode); - iput(inode); - } + struct inode *inode = &ip->i_inode; + inode_attr_in(ip, inode); } /** @@ -112,9 +106,9 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) void gfs2_inode_attr_out(struct gfs2_inode *ip) { - struct inode *inode = ip->i_vnode; + struct inode *inode = &ip->i_inode; - gfs2_assert_withdraw(ip->i_sbd, + gfs2_assert_withdraw(GFS2_SB(inode), (ip->i_di.di_mode & S_IFMT) == (inode->i_mode & S_IFMT)); ip->i_di.di_mode = inode->i_mode; ip->i_di.di_uid = inode->i_uid; @@ -124,114 +118,100 @@ void gfs2_inode_attr_out(struct gfs2_inode *ip) ip->i_di.di_ctime = inode->i_ctime.tv_sec; } -/** - * gfs2_ip2v_lookup - Get the struct inode for a struct gfs2_inode - * @ip: the struct gfs2_inode to get the struct inode for - * - * Returns: A VFS inode, or NULL if none - */ +static int iget_test(struct inode *inode, void *opaque) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_inum *inum = opaque; + + if (ip && ip->i_num.no_addr == inum->no_addr) + return 1; -struct inode *gfs2_ip2v_lookup(struct gfs2_inode *ip) + return 0; +} + +static int iget_set(struct inode *inode, void *opaque) { - struct inode *inode = NULL; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_inum *inum = opaque; - gfs2_assert_warn(ip->i_sbd, test_bit(GIF_MIN_INIT, &ip->i_flags)); + ip->i_num = *inum; + return 0; +} - spin_lock(&ip->i_spin); - if (ip->i_vnode) - inode = igrab(ip->i_vnode); - spin_unlock(&ip->i_spin); +struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum *inum) +{ + return ilookup5(sb, (unsigned long)inum->no_formal_ino, + iget_test, inum); +} - return inode; +static struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum) +{ + return iget5_locked(sb, (unsigned long)inum->no_formal_ino, + iget_test, iget_set, inum); } /** - * gfs2_ip2v - Get/Create a struct inode for a struct gfs2_inode - * @ip: the struct gfs2_inode to get the struct inode for + * gfs2_inode_lookup - Lookup an inode + * @sb: The super block + * @inum: The inode number + * @type: The type of the inode * - * Returns: A VFS inode, or NULL if no mem + * Returns: A VFS inode, or an error */ -struct inode *gfs2_ip2v(struct gfs2_inode *ip) +struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, unsigned int type) { - struct inode *inode, *tmp; - - inode = gfs2_ip2v_lookup(ip); - if (inode) - return inode; - - tmp = new_inode(ip->i_sbd->sd_vfs); - if (!tmp) - return NULL; - - inode_attr_in(ip, tmp); - - if (S_ISREG(ip->i_di.di_mode)) { - tmp->i_op = &gfs2_file_iops; - tmp->i_fop = &gfs2_file_fops; - tmp->i_mapping->a_ops = &gfs2_file_aops; - } else if (S_ISDIR(ip->i_di.di_mode)) { - tmp->i_op = &gfs2_dir_iops; - tmp->i_fop = &gfs2_dir_fops; - } else if (S_ISLNK(ip->i_di.di_mode)) { - tmp->i_op = &gfs2_symlink_iops; - } else { - tmp->i_op = &gfs2_dev_iops; - init_special_inode(tmp, tmp->i_mode, tmp->i_rdev); - } - - tmp->u.generic_ip = NULL; - - for (;;) { - spin_lock(&ip->i_spin); - if (!ip->i_vnode) - break; - inode = igrab(ip->i_vnode); - spin_unlock(&ip->i_spin); + struct inode *inode = gfs2_iget(sb, inum); + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_glock *io_gl; + int error; - if (inode) { - iput(tmp); - return inode; + if (inode->i_state & I_NEW) { + struct gfs2_sbd *sdp = GFS2_SB(inode); + umode_t mode = DT2IF(type); + inode->u.generic_ip = ip; + inode->i_mode = mode; + + if (S_ISREG(mode)) { + inode->i_op = &gfs2_file_iops; + inode->i_fop = &gfs2_file_fops; + inode->i_mapping->a_ops = &gfs2_file_aops; + } else if (S_ISDIR(mode)) { + inode->i_op = &gfs2_dir_iops; + inode->i_fop = &gfs2_dir_fops; + } else if (S_ISLNK(mode)) { + inode->i_op = &gfs2_symlink_iops; + } else { + inode->i_op = &gfs2_dev_iops; } - yield(); - } - inode = tmp; + error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); + if (unlikely(error)) + goto fail; + ip->i_gl->gl_object = ip; - gfs2_inode_hold(ip); - ip->i_vnode = inode; - inode->u.generic_ip = ip; + error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_iopen_glops, CREATE, &io_gl); + if (unlikely(error)) + goto fail_put; - spin_unlock(&ip->i_spin); + ip->i_vn = ip->i_gl->gl_vn - 1; + error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); + if (unlikely(error)) + goto fail_iopen; - insert_inode_hash(inode); + gfs2_glock_put(io_gl); + unlock_new_inode(inode); + } return inode; -} - -static int iget_test(struct inode *inode, void *opaque) -{ - struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_inum *inum = (struct gfs2_inum *)opaque; - - if (ip && ip->i_num.no_addr == inum->no_addr) - return 1; - - return 0; -} - -struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum) -{ - return ilookup5(sb, (unsigned long)inum->no_formal_ino, - iget_test, inum); -} - -void gfs2_inode_min_init(struct gfs2_inode *ip, unsigned int type) -{ - if (!test_and_set_bit(GIF_MIN_INIT, &ip->i_flags)) { - ip->i_di.di_nlink = 1; - ip->i_di.di_mode = DT2IF(type); - } +fail_iopen: + gfs2_glock_put(io_gl); +fail_put: + ip->i_gl->gl_object = NULL; + gfs2_glock_put(ip->i_gl); +fail: + iput(inode); + return ERR_PTR(error); } /** @@ -250,7 +230,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) if (error) return error; - if (gfs2_metatype_check(ip->i_sbd, dibh, GFS2_METATYPE_DI)) { + if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), dibh, GFS2_METATYPE_DI)) { brelse(dibh); return -EIO; } @@ -273,151 +253,9 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) return 0; } -/** - * inode_create - create a struct gfs2_inode - * @i_gl: The glock covering the inode - * @inum: The inode number - * @io_gl: the iopen glock to acquire/hold (using holder in new gfs2_inode) - * @io_state: the state the iopen glock should be acquired in - * @ipp: pointer to put the returned inode in - * - * Returns: errno - */ - -static int inode_create(struct gfs2_glock *i_gl, const struct gfs2_inum *inum, - struct gfs2_glock *io_gl, unsigned int io_state, - struct gfs2_inode **ipp, int need_lock) +int gfs2_dinode_dealloc(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = i_gl->gl_sbd; - struct gfs2_inode *ip; - int error = 0; - - ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL); - if (!ip) - return -ENOMEM; - memset(ip, 0, sizeof(struct gfs2_inode)); - ip->i_num = *inum; - atomic_set(&ip->i_count, 1); - ip->i_vn = i_gl->gl_vn - 1; - ip->i_gl = i_gl; - ip->i_sbd = sdp; - spin_lock_init(&ip->i_spin); - init_rwsem(&ip->i_rw_mutex); - ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default); - - if (need_lock) { - error = gfs2_glock_nq_init(io_gl, - io_state, GL_LOCAL_EXCL | GL_EXACT, - &ip->i_iopen_gh); - if (error) - goto fail; - - spin_lock(&io_gl->gl_spin); - gfs2_glock_hold(i_gl); - io_gl->gl_object = i_gl; - spin_unlock(&io_gl->gl_spin); - } - - gfs2_glock_hold(i_gl); - i_gl->gl_object = ip; - atomic_inc(&sdp->sd_inode_count); - *ipp = ip; - return 0; - -fail: - gfs2_meta_cache_flush(ip); - kmem_cache_free(gfs2_inode_cachep, ip); - *ipp = NULL; - return error; -} - -/** - * gfs2_inode_get - Create or get a reference on an inode - * @i_gl: The glock covering the inode - * @inum: The inode number - * @create: - * @ipp: pointer to put the returned inode in - * - * Returns: errno - */ - -int gfs2_inode_get(struct gfs2_glock *i_gl, const struct gfs2_inum *inum, - int create, struct gfs2_inode **ipp) -{ - struct gfs2_sbd *sdp = i_gl->gl_sbd; - struct gfs2_glock *io_gl; - int error = 0; - - gfs2_glmutex_lock(i_gl); - - *ipp = i_gl->gl_object; - if (*ipp) { - error = -ESTALE; - if ((*ipp)->i_num.no_formal_ino != inum->no_formal_ino) - goto out; - atomic_inc(&(*ipp)->i_count); - error = 0; - goto out; - } - - if (!create) - goto out; - - error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_iopen_glops, - CREATE, &io_gl); - if (!error) { - error = inode_create(i_gl, inum, io_gl, LM_ST_SHARED, ipp, 1); - gfs2_glock_put(io_gl); - } - - out: - gfs2_glmutex_unlock(i_gl); - - return error; -} - -void gfs2_inode_hold(struct gfs2_inode *ip) -{ - gfs2_assert(ip->i_sbd, atomic_read(&ip->i_count) > 0); - atomic_inc(&ip->i_count); -} - -void gfs2_inode_put(struct gfs2_inode *ip) -{ - gfs2_assert(ip->i_sbd, atomic_read(&ip->i_count) > 0); - atomic_dec(&ip->i_count); -} - -void gfs2_inode_destroy(struct gfs2_inode *ip, int unlock) -{ - struct gfs2_sbd *sdp = ip->i_sbd; - struct gfs2_glock *i_gl = ip->i_gl; - - gfs2_assert_warn(sdp, !atomic_read(&ip->i_count)); - if (unlock) { - struct gfs2_glock *io_gl = ip->i_iopen_gh.gh_gl; - gfs2_assert(sdp, io_gl->gl_object == i_gl); - - spin_lock(&io_gl->gl_spin); - io_gl->gl_object = NULL; - spin_unlock(&io_gl->gl_spin); - gfs2_glock_put(i_gl); - - gfs2_glock_dq_uninit(&ip->i_iopen_gh); - } - - gfs2_meta_cache_flush(ip); - kmem_cache_free(gfs2_inode_cachep, ip); - - i_gl->gl_object = NULL; - gfs2_glock_put(i_gl); - - atomic_dec(&sdp->sd_inode_count); -} - -static int dinode_dealloc(struct gfs2_inode *ip, struct gfs2_unlinked *ul) -{ - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al; struct gfs2_rgrpd *rgd; int error; @@ -450,7 +288,7 @@ static int dinode_dealloc(struct gfs2_inode *ip, struct gfs2_unlinked *ul) if (error) goto out_rindex_relse; - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_UNLINKED + + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1); if (error) goto out_rg_gunlock; @@ -459,191 +297,20 @@ static int dinode_dealloc(struct gfs2_inode *ip, struct gfs2_unlinked *ul) gfs2_free_di(rgd, ip); - error = gfs2_unlinked_ondisk_rm(sdp, ul); - gfs2_trans_end(sdp); clear_bit(GLF_STICKY, &ip->i_gl->gl_flags); - out_rg_gunlock: +out_rg_gunlock: gfs2_glock_dq_uninit(&al->al_rgd_gh); - - out_rindex_relse: +out_rindex_relse: gfs2_glock_dq_uninit(&al->al_ri_gh); - - out_qs: +out_qs: gfs2_quota_unhold(ip); - - out: - gfs2_alloc_put(ip); - - return error; -} - -/** - * inode_dealloc - Deallocate all on-disk blocks for an inode (dinode) - * @sdp: the filesystem - * @inum: the inode number to deallocate - * @io_gh: a holder for the iopen glock for this inode - * - * N.B. When we enter this we already hold the iopen glock and getting - * the glock for the inode means that we are grabbing the locks in the - * "wrong" order so we must only so a try lock operation and fail if we - * don't get the lock. Thats ok, since if we fail it means someone else - * is using the inode still and thus we shouldn't be deallocating it - * anyway. - * - * Returns: errno - */ - -static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul, - struct gfs2_holder *io_gh) -{ - struct gfs2_inode *ip; - struct gfs2_holder i_gh; - int error; - - error = gfs2_glock_nq_num(sdp, ul->ul_ut.ut_inum.no_addr, - &gfs2_inode_glops, LM_ST_EXCLUSIVE, - LM_FLAG_TRY_1CB|GL_DUMP, &i_gh); - switch(error) { - case 0: - break; - case GLR_TRYFAILED: - return 1; /* or back off and relock in different order? */ - default: - return error; - } - - gfs2_assert_warn(sdp, !i_gh.gh_gl->gl_object); - error = inode_create(i_gh.gh_gl, &ul->ul_ut.ut_inum, io_gh->gh_gl, - LM_ST_EXCLUSIVE, &ip, 0); - - if (error) - goto out; - - error = gfs2_inode_refresh(ip); - if (error) - goto out_iput; - - if (ip->i_di.di_nlink) { - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); - error = -EIO; - goto out_iput; - } - - if (S_ISDIR(ip->i_di.di_mode) && - (ip->i_di.di_flags & GFS2_DIF_EXHASH)) { - error = gfs2_dir_exhash_dealloc(ip); - if (error) - goto out_iput; - } - - if (ip->i_di.di_eattr) { - error = gfs2_ea_dealloc(ip); - if (error) - goto out_iput; - } - - if (!gfs2_is_stuffed(ip)) { - error = gfs2_file_dealloc(ip); - if (error) - goto out_iput; - } - - error = dinode_dealloc(ip, ul); - if (error) - goto out_iput; - -out_iput: - gfs2_glmutex_lock(i_gh.gh_gl); - gfs2_inode_put(ip); - gfs2_inode_destroy(ip, 0); - gfs2_glmutex_unlock(i_gh.gh_gl); - out: - gfs2_glock_dq_uninit(&i_gh); - - return error; -} - -/** - * try_inode_dealloc - Try to deallocate an inode and all its blocks - * @sdp: the filesystem - * - * Returns: 0 on success, -errno on error, 1 on busy (inode open) - */ - -static int try_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - int error = 0; - struct gfs2_holder iogh; - - gfs2_try_toss_inode(sdp, &ul->ul_ut.ut_inum); - error = gfs2_glock_nq_num(sdp, ul->ul_ut.ut_inum.no_addr, - &gfs2_iopen_glops, LM_ST_EXCLUSIVE, - LM_FLAG_TRY_1CB, &iogh); - switch (error) { - case 0: - break; - case GLR_TRYFAILED: - return 1; - default: - return error; - } - - error = inode_dealloc(sdp, ul, &iogh); - gfs2_glock_dq_uninit(&iogh); - - return error; -} - -static int inode_dealloc_uninit(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - struct gfs2_rgrpd *rgd; - struct gfs2_holder ri_gh, rgd_gh; - int error; - - error = gfs2_rindex_hold(sdp, &ri_gh); - if (error) - return error; - - rgd = gfs2_blk2rgrpd(sdp, ul->ul_ut.ut_inum.no_addr); - if (!rgd) { - gfs2_consist(sdp); - error = -EIO; - goto out; - } - - error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rgd_gh); - if (error) - goto out; - - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_UNLINKED + RES_STATFS, 0); - if (error) - goto out_gunlock; - - gfs2_free_uninit_di(rgd, ul->ul_ut.ut_inum.no_addr); - gfs2_unlinked_ondisk_rm(sdp, ul); - - gfs2_trans_end(sdp); - - out_gunlock: - gfs2_glock_dq_uninit(&rgd_gh); - out: - gfs2_glock_dq_uninit(&ri_gh); - + gfs2_alloc_put(ip); return error; } -int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - if (ul->ul_ut.ut_flags & GFS2_UTF_UNINIT) - return inode_dealloc_uninit(sdp, ul); - else - return try_inode_dealloc(sdp, ul); -} - /** * gfs2_change_nlink - Change nlink count on inode * @ip: The GFS2 inode @@ -654,6 +321,7 @@ int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) int gfs2_change_nlink(struct gfs2_inode *ip, int diff) { + struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info; struct buffer_head *dibh; uint32_t nlink; int error; @@ -678,8 +346,30 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); + mark_inode_dirty(&ip->i_inode); - return 0; + if (ip->i_di.di_nlink == 0) { + struct gfs2_rgrpd *rgd; + struct gfs2_holder ri_gh, rg_gh; + + error = gfs2_rindex_hold(sdp, &ri_gh); + if (error) + goto out; + error = -EIO; + rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr); + if (!rgd) + goto out_norgrp; + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh); + if (error) + goto out_norgrp; + + gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */ + gfs2_glock_dq_uninit(&rg_gh); +out_norgrp: + gfs2_glock_dq_uninit(&ri_gh); + } +out: + return error; } struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) @@ -703,18 +393,15 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) * Returns: errno */ -struct inode *gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, - struct nameidata *nd) +struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, + int is_root, struct nameidata *nd) { struct super_block *sb = dir->i_sb; - struct gfs2_inode *ipp; - struct gfs2_inode *dip = dir->u.generic_ip; - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_holder d_gh; struct gfs2_inum inum; unsigned int type; - struct gfs2_glock *gl; int error = 0; struct inode *inode = NULL; @@ -742,34 +429,18 @@ struct inode *gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, if (error) goto out; - error = gfs2_glock_get(sdp, inum.no_addr, &gfs2_inode_glops, - CREATE, &gl); - if (error) - goto out; - - error = gfs2_inode_get(gl, &inum, CREATE, &ipp); - if (!error) - gfs2_inode_min_init(ipp, type); - - gfs2_glock_put(gl); + inode = gfs2_inode_lookup(sb, &inum, type); out: gfs2_glock_dq_uninit(&d_gh); if (error == -ENOENT) return NULL; - if (error == 0) { - inode = gfs2_ip2v(ipp); - gfs2_inode_put(ipp); - if (!inode) - return ERR_PTR(-ENOMEM); - return inode; - } - return ERR_PTR(error); + return inode; } static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) { - struct gfs2_inode *ip = sdp->sd_ir_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode); struct buffer_head *bh; struct gfs2_inum_range ir; int error; @@ -810,8 +481,8 @@ static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) { - struct gfs2_inode *ip = sdp->sd_ir_inode->u.generic_ip; - struct gfs2_inode *m_ip = sdp->sd_inum_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode); + struct gfs2_inode *m_ip = GFS2_I(sdp->sd_inum_inode); struct gfs2_holder gh; struct buffer_head *bh; struct gfs2_inum_range ir; @@ -895,12 +566,12 @@ static int pick_formal_ino(struct gfs2_sbd *sdp, uint64_t *inum) * Returns: errno */ -static int create_ok(struct gfs2_inode *dip, struct qstr *name, +static int create_ok(struct gfs2_inode *dip, const struct qstr *name, unsigned int mode) { int error; - error = gfs2_repermission(dip->i_vnode, MAY_WRITE | MAY_EXEC, NULL); + error = gfs2_repermission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL); if (error) return error; @@ -908,7 +579,7 @@ static int create_ok(struct gfs2_inode *dip, struct qstr *name, if (!dip->i_di.di_nlink) return -EPERM; - error = gfs2_dir_search(dip->i_vnode, name, NULL, NULL); + error = gfs2_dir_search(&dip->i_inode, name, NULL, NULL); switch (error) { case -ENOENT: error = 0; @@ -930,7 +601,7 @@ static int create_ok(struct gfs2_inode *dip, struct qstr *name, static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, unsigned int *uid, unsigned int *gid) { - if (dip->i_sbd->sd_args.ar_suiddir && + if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir && (dip->i_di.di_mode & S_ISUID) && dip->i_di.di_uid) { if (S_ISDIR(*mode)) @@ -949,9 +620,9 @@ static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, *gid = current->fsgid; } -static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_unlinked *ul) +static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); int error; gfs2_alloc_get(dip); @@ -961,15 +632,11 @@ static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_unlinked *ul) if (error) goto out; - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_UNLINKED + - RES_STATFS, 0); + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS, 0); if (error) goto out_ipreserv; - ul->ul_ut.ut_inum.no_addr = gfs2_alloc_di(dip); - - ul->ul_ut.ut_flags = GFS2_UTF_UNINIT; - error = gfs2_unlinked_ondisk_add(sdp, ul); + inum->no_addr = gfs2_alloc_di(dip); gfs2_trans_end(sdp); @@ -997,7 +664,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, struct gfs2_inum *inum, unsigned int mode, unsigned int uid, unsigned int gid) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_dinode *di; struct buffer_head *dibh; @@ -1049,9 +716,9 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, } static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - unsigned int mode, struct gfs2_unlinked *ul) + unsigned int mode, struct gfs2_inum *inum) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); unsigned int uid, gid; int error; @@ -1066,28 +733,25 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, if (error) goto out_quota; - error = gfs2_trans_begin(sdp, RES_DINODE + RES_UNLINKED + RES_QUOTA, 0); + error = gfs2_trans_begin(sdp, RES_DINODE + RES_QUOTA, 0); if (error) goto out_quota; - ul->ul_ut.ut_flags = 0; - error = gfs2_unlinked_ondisk_munge(sdp, ul); - init_dinode(dip, gl, &ul->ul_ut.ut_inum, mode, uid, gid); + init_dinode(dip, gl, inum, mode, uid, gid); gfs2_quota_change(dip, +1, uid, gid); gfs2_trans_end(sdp); - out_quota: +out_quota: gfs2_quota_unlock(dip); - - out: +out: gfs2_alloc_put(dip); return error; } -static int link_dinode(struct gfs2_inode *dip, struct qstr *name, - struct gfs2_inode *ip, struct gfs2_unlinked *ul) +static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, + struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_alloc *al; int alloc_required; struct buffer_head *dibh; @@ -1099,7 +763,7 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, if (error) goto fail; - error = alloc_required = gfs2_diradd_alloc_required(dip->i_vnode, name); + error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name); if (alloc_required < 0) goto fail; if (alloc_required) { @@ -1116,20 +780,17 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + al->al_rgd->rd_ri.ri_length + - 2 * RES_DINODE + RES_UNLINKED + + 2 * RES_DINODE + RES_STATFS + RES_QUOTA, 0); if (error) goto fail_ipreserv; } else { - error = gfs2_trans_begin(sdp, - RES_LEAF + - 2 * RES_DINODE + - RES_UNLINKED, 0); + error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0); if (error) goto fail_quota_locks; } - error = gfs2_dir_add(dip->i_vnode, name, &ip->i_num, IF2DT(ip->i_di.di_mode)); + error = gfs2_dir_add(&dip->i_inode, name, &ip->i_num, IF2DT(ip->i_di.di_mode)); if (error) goto fail_end_trans; @@ -1140,11 +801,6 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(&ip->i_di, dibh->b_data); brelse(dibh); - - error = gfs2_unlinked_ondisk_rm(sdp, ul); - if (error) - goto fail_end_trans; - return 0; fail_end_trans: @@ -1178,23 +834,19 @@ fail: * Returns: An inode */ -struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, +struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, unsigned int mode) { struct inode *inode; struct gfs2_inode *dip = ghs->gh_gl->gl_object; - struct gfs2_sbd *sdp = dip->i_sbd; - struct gfs2_unlinked *ul; - struct gfs2_inode *ip; + struct inode *dir = &dip->i_inode; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + struct gfs2_inum inum; int error; if (!name->len || name->len > GFS2_FNAMESIZE) return ERR_PTR(-ENAMETOOLONG); - error = gfs2_unlinked_get(sdp, &ul); - if (error) - return ERR_PTR(error); - gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); error = gfs2_glock_nq(ghs); if (error) @@ -1204,22 +856,21 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, if (error) goto fail_gunlock; - error = pick_formal_ino(sdp, &ul->ul_ut.ut_inum.no_formal_ino); + error = pick_formal_ino(sdp, &inum.no_formal_ino); if (error) goto fail_gunlock; - error = alloc_dinode(dip, ul); + error = alloc_dinode(dip, &inum); if (error) goto fail_gunlock; - if (ul->ul_ut.ut_inum.no_addr < dip->i_num.no_addr) { + if (inum.no_addr < dip->i_num.no_addr) { gfs2_glock_dq(ghs); - error = gfs2_glock_nq_num(sdp, ul->ul_ut.ut_inum.no_addr, + error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); if (error) { - gfs2_unlinked_put(sdp, ul); return ERR_PTR(error); } @@ -1227,7 +878,6 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, error = gfs2_glock_nq(ghs); if (error) { gfs2_glock_dq_uninit(ghs + 1); - gfs2_unlinked_put(sdp, ul); return ERR_PTR(error); } @@ -1235,94 +885,47 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, if (error) goto fail_gunlock2; } else { - error = gfs2_glock_nq_num(sdp, ul->ul_ut.ut_inum.no_addr, + error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); if (error) goto fail_gunlock; } - error = make_dinode(dip, ghs[1].gh_gl, mode, ul); + error = make_dinode(dip, ghs[1].gh_gl, mode, &inum); if (error) goto fail_gunlock2; - error = gfs2_inode_get(ghs[1].gh_gl, &ul->ul_ut.ut_inum, CREATE, &ip); - if (error) + inode = gfs2_inode_lookup(dir->i_sb, &inum, IF2DT(mode)); + if (IS_ERR(inode)) goto fail_gunlock2; - error = gfs2_inode_refresh(ip); + error = gfs2_inode_refresh(GFS2_I(inode)); if (error) goto fail_iput; - error = gfs2_acl_create(dip, ip); + error = gfs2_acl_create(dip, GFS2_I(inode)); if (error) goto fail_iput; - error = link_dinode(dip, name, ip, ul); + error = link_dinode(dip, name, GFS2_I(inode)); if (error) goto fail_iput; - gfs2_unlinked_put(sdp, ul); - - inode = gfs2_ip2v(ip); - gfs2_inode_put(ip); if (!inode) return ERR_PTR(-ENOMEM); return inode; fail_iput: - gfs2_inode_put(ip); - + iput(inode); fail_gunlock2: gfs2_glock_dq_uninit(ghs + 1); - fail_gunlock: gfs2_glock_dq(ghs); - fail: - gfs2_unlinked_put(sdp, ul); return ERR_PTR(error); } -/** - * gfs2_unlinki - Unlink a file - * @dip: The inode of the directory - * @name: The name of the file to be unlinked - * @ip: The inode of the file to be removed - * - * Assumes Glocks on both dip and ip are held. - * - * Returns: errno - */ - -int gfs2_unlinki(struct gfs2_inode *dip, struct qstr *name, - struct gfs2_inode *ip, struct gfs2_unlinked *ul) -{ - struct gfs2_sbd *sdp = dip->i_sbd; - int error; - - error = gfs2_dir_del(dip, name); - if (error) - return error; - - error = gfs2_change_nlink(ip, -1); - if (error) - return error; - - /* If this inode is being unlinked from the directory structure, - we need to mark that in the log so that it isn't lost during - a crash. */ - - if (!ip->i_di.di_nlink) { - ul->ul_ut.ut_inum = ip->i_num; - error = gfs2_unlinked_ondisk_add(sdp, ul); - if (!error) - set_bit(GLF_STICKY, &ip->i_gl->gl_flags); - } - - return error; -} - /** * gfs2_rmdiri - Remove a directory * @dip: The parent directory of the directory to be removed @@ -1334,10 +937,9 @@ int gfs2_unlinki(struct gfs2_inode *dip, struct qstr *name, * Returns: errno */ -int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, - struct gfs2_inode *ip, struct gfs2_unlinked *ul) +int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, + struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = dip->i_sbd; struct qstr dotname; int error; @@ -1360,9 +962,7 @@ int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, if (error) return error; - dotname.len = 2; - dotname.name = ".."; - dotname.hash = gfs2_disk_hash(dotname.name, dotname.len); + gfs2_str2qstr(&dotname, ".."); error = gfs2_dir_del(ip, &dotname); if (error) return error; @@ -1371,15 +971,6 @@ int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, if (error) return error; - /* This inode is being unlinked from the directory structure and - we need to mark that in the log so that it isn't lost during - a crash. */ - - ul->ul_ut.ut_inum = ip->i_num; - error = gfs2_unlinked_ondisk_add(sdp, ul); - if (!error) - set_bit(GLF_STICKY, &ip->i_gl->gl_flags); - return error; } @@ -1394,30 +985,29 @@ int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, * Returns: 0 if the parent/child relationship is correct, errno if it isn't */ -int gfs2_unlink_ok(struct gfs2_inode *dip, struct qstr *name, +int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, struct gfs2_inode *ip) { struct gfs2_inum inum; unsigned int type; int error; - if (IS_IMMUTABLE(ip->i_vnode) || IS_APPEND(ip->i_vnode)) + if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) return -EPERM; if ((dip->i_di.di_mode & S_ISVTX) && dip->i_di.di_uid != current->fsuid && - ip->i_di.di_uid != current->fsuid && - !capable(CAP_FOWNER)) + ip->i_di.di_uid != current->fsuid && !capable(CAP_FOWNER)) return -EPERM; - if (IS_APPEND(dip->i_vnode)) + if (IS_APPEND(&dip->i_inode)) return -EPERM; - error = gfs2_repermission(dip->i_vnode, MAY_WRITE | MAY_EXEC, NULL); + error = gfs2_repermission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL); if (error) return error; - error = gfs2_dir_search(dip->i_vnode, name, &inum, &type); + error = gfs2_dir_search(&dip->i_inode, name, &inum, &type); if (error) return error; @@ -1445,7 +1035,7 @@ int gfs2_unlink_ok(struct gfs2_inode *dip, struct qstr *name, int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) { - struct inode *dir = to->i_vnode; + struct inode *dir = &to->i_inode; struct super_block *sb = dir->i_sb; struct inode *tmp; struct qstr dotdot; @@ -1456,7 +1046,7 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) igrab(dir); for (;;) { - if (dir == this->i_vnode) { + if (dir == &this->i_inode) { error = -EINVAL; break; } @@ -1528,12 +1118,10 @@ int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x); *len = x; - out_brelse: +out_brelse: brelse(dibh); - - out: +out: gfs2_glock_dq_uninit(&i_gh); - return error; } @@ -1622,12 +1210,10 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh) return 0; - fail_end_trans: +fail_end_trans: gfs2_trans_end(sdp); - - fail: +fail: gfs2_glock_dq(gh); - return error; } @@ -1722,49 +1308,6 @@ int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs) return error; } -/** - * gfs2_try_toss_vnode - See if we can toss a vnode from memory - * @ip: the inode - * - * Returns: 1 if the vnode was tossed - */ - -void gfs2_try_toss_vnode(struct gfs2_inode *ip) -{ - struct inode *inode; - - inode = gfs2_ip2v_lookup(ip); - if (!inode) - return; - - d_prune_aliases(inode); - - if (S_ISDIR(ip->i_di.di_mode)) { - struct list_head *head = &inode->i_dentry; - struct dentry *d = NULL; - - spin_lock(&dcache_lock); - if (list_empty(head)) - spin_unlock(&dcache_lock); - else { - d = list_entry(head->next, struct dentry, d_alias); - dget_locked(d); - spin_unlock(&dcache_lock); - - if (have_submounts(d)) - dput(d); - else { - shrink_dcache_parent(d); - dput(d); - d_prune_aliases(inode); - } - } - } - - inode->i_nlink = 0; - iput(inode); -} - static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) @@ -1774,8 +1317,8 @@ __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { - error = inode_setattr(ip->i_vnode, attr); - gfs2_assert_warn(ip->i_sbd, !error); + error = inode_setattr(&ip->i_inode, attr); + gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); gfs2_inode_attr_out(ip); gfs2_trans_add_bh(ip->i_gl, dibh, 1); @@ -1802,13 +1345,13 @@ int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) if (current->journal_info) return __gfs2_setattr_simple(ip, attr); - error = gfs2_trans_begin(ip->i_sbd, RES_DINODE, 0); + error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0); if (error) return error; error = __gfs2_setattr_simple(ip, attr); - gfs2_trans_end(ip->i_sbd); + gfs2_trans_end(GFS2_SB(&ip->i_inode)); return error; } diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 5ef21317b2f6..30cfcc10beb2 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -27,32 +27,20 @@ static inline int gfs2_is_dir(struct gfs2_inode *ip) void gfs2_inode_attr_in(struct gfs2_inode *ip); void gfs2_inode_attr_out(struct gfs2_inode *ip); -struct inode *gfs2_ip2v_lookup(struct gfs2_inode *ip); -struct inode *gfs2_ip2v(struct gfs2_inode *ip); -struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum); +struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, unsigned type); +struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum *inum); -void gfs2_inode_min_init(struct gfs2_inode *ip, unsigned int type); int gfs2_inode_refresh(struct gfs2_inode *ip); -int gfs2_inode_get(struct gfs2_glock *i_gl, - const struct gfs2_inum *inum, int create, - struct gfs2_inode **ipp); -void gfs2_inode_hold(struct gfs2_inode *ip); -void gfs2_inode_put(struct gfs2_inode *ip); -void gfs2_inode_destroy(struct gfs2_inode *ip, int unlock); - -int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); - +int gfs2_dinode_dealloc(struct gfs2_inode *inode); int gfs2_change_nlink(struct gfs2_inode *ip, int diff); -struct inode *gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, - struct nameidata *nd); -struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, +struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, + int is_root, struct nameidata *nd); +struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, unsigned int mode); -int gfs2_unlinki(struct gfs2_inode *dip, struct qstr *name, - struct gfs2_inode *ip, struct gfs2_unlinked *ul); -int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, - struct gfs2_inode *ip, struct gfs2_unlinked *ul); -int gfs2_unlink_ok(struct gfs2_inode *dip, struct qstr *name, +int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, + struct gfs2_inode *ip); +int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, struct gfs2_inode *ip); int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to); int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len); @@ -60,8 +48,6 @@ int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len); int gfs2_glock_nq_atime(struct gfs2_holder *gh); int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs); -void gfs2_try_toss_vnode(struct gfs2_inode *ip); - int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); int gfs2_repermission(struct inode *inode, int mask, struct nameidata *nd); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 2a8b4b71dd1f..483d4fa987f6 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -213,6 +213,9 @@ static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) int bdy; error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, &new, &dbn, &bdy); + if (!(!error && dbn)) { + printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, dbn, lbn); + } gfs2_assert_withdraw(sdp, !error && dbn); return dbn; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index e4c75a74df5b..a76f1a778920 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -184,8 +184,7 @@ static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) static void buf_lo_before_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head, int pass) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (pass != 0) return; @@ -198,8 +197,8 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, struct gfs2_log_descriptor *ld, __be64 *ptr, int pass) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct gfs2_glock *gl = ip->i_gl; unsigned int blks = be32_to_cpu(ld->ld_data1); struct buffer_head *bh_log, *bh_ip; @@ -245,8 +244,8 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (error) { gfs2_meta_sync(ip->i_gl, @@ -332,8 +331,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) static void revoke_lo_before_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head, int pass) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (pass != 0) return; @@ -346,8 +344,7 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, struct gfs2_log_descriptor *ld, __be64 *ptr, int pass) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); unsigned int blks = be32_to_cpu(ld->ld_length); unsigned int revokes = be32_to_cpu(ld->ld_data1); struct buffer_head *bh; @@ -393,8 +390,7 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (error) { gfs2_revoke_clean(sdp); @@ -465,7 +461,7 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); struct gfs2_trans *tr = current->journal_info; struct address_space *mapping = bd->bd_bh->b_page->mapping; - struct gfs2_inode *ip = mapping->host->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(mapping->host); tr->tr_touched = 1; if (!list_empty(&bd->bd_list_tr) && @@ -665,8 +661,8 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, struct gfs2_log_descriptor *ld, __be64 *ptr, int pass) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct gfs2_glock *gl = ip->i_gl; unsigned int blks = be32_to_cpu(ld->ld_data1); struct buffer_head *bh_log, *bh_ip; @@ -716,8 +712,8 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); if (error) { gfs2_meta_sync(ip->i_gl, diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index b24d0b40d965..c112943ee8c1 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -29,8 +29,6 @@ static void gfs2_init_inode_once(void *foo, kmem_cache_t *cachep, unsigned long if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { inode_init_once(&ip->i_inode); - atomic_set(&ip->i_count, 0); - ip->i_vnode = &ip->i_inode; spin_lock_init(&ip->i_spin); init_rwsem(&ip->i_rw_mutex); memset(ip->i_cache, 0, sizeof(ip->i_cache)); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index c78517225f61..2523d42a02de 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -91,9 +91,6 @@ static void stuck_releasepage(struct buffer_head *bh) fs_warn(sdp, "ip = %llu %llu\n", (unsigned long long)ip->i_num.no_formal_ino, (unsigned long long)ip->i_num.no_addr); - fs_warn(sdp, "ip->i_count = %d, ip->i_vnode = %s\n", - atomic_read(&ip->i_count), - (ip->i_vnode) ? "!NULL" : "NULL"); for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) fs_warn(sdp, "ip->i_cache[%u] = %s\n", @@ -567,7 +564,6 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL), memset(bd, 0, sizeof(struct gfs2_bufdata)); - bd->bd_bh = bh; bd->bd_gl = gl; @@ -664,7 +660,7 @@ void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, void gfs2_meta_wipe(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct inode *aspace = ip->i_gl->gl_aspace; struct buffer_head *bh; @@ -770,7 +766,7 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t num, if (new) meta_prep_new(bh); else { - error = gfs2_meta_reread(ip->i_sbd, bh, + error = gfs2_meta_reread(GFS2_SB(&ip->i_inode), bh, DIO_START | DIO_WAIT); if (error) { brelse(bh); @@ -797,7 +793,7 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t num, } if (new) { - if (gfs2_assert_warn(ip->i_sbd, height)) { + if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), height)) { brelse(bh); return -EIO; } @@ -805,7 +801,7 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t num, gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); - } else if (gfs2_metatype_check(ip->i_sbd, bh, + } else if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, (height) ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)) { brelse(bh); return -EIO; diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index be5c86e5787e..09154ad7b270 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -293,23 +293,6 @@ void gfs2_statfs_change_out(struct gfs2_statfs_change *sc, char *buf) str->sc_dinodes = cpu_to_be64(sc->sc_dinodes); } -void gfs2_unlinked_tag_in(struct gfs2_unlinked_tag *ut, char *buf) -{ - struct gfs2_unlinked_tag *str = (struct gfs2_unlinked_tag *)buf; - - gfs2_inum_in(&ut->ut_inum, buf); - ut->ut_flags = be32_to_cpu(str->ut_flags); -} - -void gfs2_unlinked_tag_out(struct gfs2_unlinked_tag *ut, char *buf) -{ - struct gfs2_unlinked_tag *str = (struct gfs2_unlinked_tag *)buf; - - gfs2_inum_out(&ut->ut_inum, buf); - str->ut_flags = cpu_to_be32(ut->ut_flags); - str->__pad = 0; -} - void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf) { struct gfs2_quota_change *str = (struct gfs2_quota_change *)buf; diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 16d3ebd32092..207363aed112 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -81,7 +81,6 @@ int gfs2_get_block(struct inode *inode, sector_t lblock, static int get_block_noalloc(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - struct gfs2_inode *ip = inode->u.generic_ip; int new = 0; uint64_t dblock; int error; @@ -93,7 +92,7 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock, if (dblock) map_bh(bh_result, inode->i_sb, dblock); - else if (gfs2_assert_withdraw(ip->i_sbd, !create)) + else if (gfs2_assert_withdraw(GFS2_SB(inode), !create)) error = -EIO; if (boundary) set_buffer_boundary(bh_result); @@ -114,8 +113,8 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock, static int gfs2_writepage(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; - struct gfs2_inode *ip = page->mapping->host->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(page->mapping->host); + struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); loff_t i_size = i_size_read(inode); pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; unsigned offset; @@ -216,8 +215,8 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) static int gfs2_readpage(struct file *file, struct page *page) { - struct gfs2_inode *ip = page->mapping->host->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(page->mapping->host); + struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); struct gfs2_holder gh; int error; @@ -271,8 +270,8 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { struct inode *inode = mapping->host; - struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_holder gh; unsigned page_idx; int ret; @@ -345,8 +344,8 @@ out_unlock: static int gfs2_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { - struct gfs2_inode *ip = page->mapping->host->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(page->mapping->host); + struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); unsigned int data_blocks, ind_blocks, rblocks; int alloc_required; int error = 0; @@ -440,8 +439,8 @@ static int gfs2_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { struct inode *inode = page->mapping->host; - struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); int error = -EOPNOTSUPP; struct buffer_head *dibh; struct gfs2_alloc *al = &ip->i_alloc;; @@ -520,7 +519,7 @@ fail_nounlock: static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) { - struct gfs2_inode *ip = mapping->host->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(mapping->host); struct gfs2_holder i_gh; sector_t dblock = 0; int error; @@ -594,7 +593,7 @@ static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int rv; @@ -641,8 +640,8 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); if (rw == WRITE) return gfs2_direct_IO_write(iocb, iov, offset, nr_segs); diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index fef415e2068e..fd55979ec428 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -38,8 +38,8 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) { struct dentry *parent = dget_parent(dentry); - struct gfs2_sbd *sdp = parent->d_inode->i_sb->s_fs_info; - struct gfs2_inode *dip = parent->d_inode->u.generic_ip; + struct gfs2_sbd *sdp = GFS2_SB(parent->d_inode); + struct gfs2_inode *dip = GFS2_I(parent->d_inode); struct inode *inode = dentry->d_inode; struct gfs2_holder d_gh; struct gfs2_inode *ip; @@ -71,7 +71,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) goto fail_gunlock; } - ip = inode->u.generic_ip; + ip = GFS2_I(inode); if (!gfs2_inum_equal(&ip->i_num, &inum)) goto invalid_gunlock; diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index a376ead7d0cd..eacc1c092f91 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -66,7 +66,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, { struct inode *inode = dentry->d_inode; struct super_block *sb = inode->i_sb; - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); if (*len < 4 || (connectable && *len < 8)) return 255; @@ -86,8 +86,8 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, spin_lock(&dentry->d_lock); inode = dentry->d_parent->d_inode; - ip = inode->u.generic_ip; - gfs2_inode_hold(ip); + ip = GFS2_I(inode); + igrab(inode); spin_unlock(&dentry->d_lock); fh[4] = ip->i_num.no_formal_ino >> 32; @@ -100,7 +100,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, fh[7] = cpu_to_be32(fh[7]); *len = 8; - gfs2_inode_put(ip); + iput(inode); return *len; } @@ -142,8 +142,8 @@ static int gfs2_get_name(struct dentry *parent, char *name, if (!S_ISDIR(dir->i_mode) || !inode) return -EINVAL; - dip = dir->u.generic_ip; - ip = inode->u.generic_ip; + dip = GFS2_I(dir); + ip = GFS2_I(inode); *name = 0; gnfd.inum = ip->i_num; @@ -189,39 +189,30 @@ static struct dentry *gfs2_get_parent(struct dentry *child) static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_p) { struct gfs2_sbd *sdp = sb->s_fs_info; - struct gfs2_inum *inum = (struct gfs2_inum *)inum_p; + struct gfs2_inum *inum = inum_p; struct gfs2_holder i_gh, ri_gh, rgd_gh; struct gfs2_rgrpd *rgd; - struct gfs2_inode *ip; struct inode *inode; struct dentry *dentry; int error; /* System files? */ - inode = gfs2_iget(sb, inum); + inode = gfs2_ilookup(sb, inum); if (inode) { - ip = inode->u.generic_ip; - if (ip->i_num.no_formal_ino != inum->no_formal_ino) { + if (GFS2_I(inode)->i_num.no_formal_ino != inum->no_formal_ino) { iput(inode); return ERR_PTR(-ESTALE); } goto out_inode; } - error = gfs2_glock_nq_num(sdp, - inum->no_addr, &gfs2_inode_glops, + error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops, LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL, &i_gh); if (error) return ERR_PTR(error); - error = gfs2_inode_get(i_gh.gh_gl, inum, NO_CREATE, &ip); - if (error) - goto fail; - if (ip) - goto out_ip; - error = gfs2_rindex_hold(sdp, &ri_gh); if (error) goto fail; @@ -242,32 +233,29 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_p) gfs2_glock_dq_uninit(&rgd_gh); gfs2_glock_dq_uninit(&ri_gh); - error = gfs2_inode_get(i_gh.gh_gl, inum, CREATE, &ip); - if (error) + inode = gfs2_inode_lookup(sb, inum, DT_UNKNOWN); + if (!inode) + goto fail; + if (IS_ERR(inode)) { + error = PTR_ERR(inode); goto fail; + } - error = gfs2_inode_refresh(ip); + error = gfs2_inode_refresh(GFS2_I(inode)); if (error) { - gfs2_inode_put(ip); + iput(inode); goto fail; } - out_ip: error = -EIO; - if (ip->i_di.di_flags & GFS2_DIF_SYSTEM) { - gfs2_inode_put(ip); + if (GFS2_I(inode)->i_di.di_flags & GFS2_DIF_SYSTEM) { + iput(inode); goto fail; } gfs2_glock_dq_uninit(&i_gh); - inode = gfs2_ip2v(ip); - gfs2_inode_put(ip); - - if (!inode) - return ERR_PTR(-ENOMEM); - - out_inode: +out_inode: dentry = d_alloc_anon(inode); if (!dentry) { iput(inode); @@ -276,13 +264,13 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_p) return dentry; - fail_rgd: +fail_rgd: gfs2_glock_dq_uninit(&rgd_gh); - fail_rindex: +fail_rindex: gfs2_glock_dq_uninit(&ri_gh); - fail: +fail: gfs2_glock_dq_uninit(&i_gh); return ERR_PTR(error); } diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 1e8f602c1e50..222f3be3e06e 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -105,7 +105,7 @@ static int gfs2_read_actor(read_descriptor_t *desc, struct page *page, int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, char *buf, loff_t *pos, unsigned size) { - struct inode *inode = ip->i_vnode; + struct inode *inode = &ip->i_inode; read_descriptor_t desc; desc.written = 0; desc.arg.buf = buf; @@ -131,7 +131,7 @@ int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) { - struct gfs2_inode *ip = file->f_mapping->host->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); struct gfs2_holder i_gh; loff_t error; @@ -178,7 +178,7 @@ static ssize_t __gfs2_file_aio_read(struct kiocb *iocb, unsigned long nr_segs, loff_t *ppos) { struct file *filp = iocb->ki_filp; - struct gfs2_inode *ip = filp->f_mapping->host->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(filp->f_mapping->host); struct gfs2_holder gh; ssize_t retval; unsigned long seg; @@ -361,13 +361,13 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) { struct inode *dir = file->f_mapping->host; - struct gfs2_inode *dip = dir->u.generic_ip; + struct gfs2_inode *dip = GFS2_I(dir); struct filldir_reg fdr; struct gfs2_holder d_gh; uint64_t offset = file->f_pos; int error; - fdr.fdr_sbd = dip->i_sbd; + fdr.fdr_sbd = GFS2_SB(dir); fdr.fdr_prefetch = 1; fdr.fdr_filldir = filldir; fdr.fdr_opaque = dirent; @@ -451,8 +451,8 @@ static int filldir_bad_func(void *opaque, const char *name, unsigned int length, static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) { struct inode *dir = file->f_mapping->host; - struct gfs2_inode *dip = dir->u.generic_ip; - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_sbd *sdp = GFS2_SB(dir); struct filldir_reg fdr; unsigned int entries, size; struct filldir_bad *fdb; @@ -561,7 +561,7 @@ static const u32 gfs2_to_iflags[32] = { static int gfs2_get_flags(struct file *filp, u32 __user *ptr) { struct inode *inode = filp->f_dentry->d_inode; - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int error; u32 iflags; @@ -601,8 +601,8 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr) static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) { struct inode *inode = filp->f_dentry->d_inode; - struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); struct buffer_head *bh; struct gfs2_holder gh; int error; @@ -693,7 +693,7 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) { - struct gfs2_inode *ip = file->f_mapping->host->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); struct gfs2_holder i_gh; int error; @@ -728,7 +728,7 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) static int gfs2_open(struct inode *inode, struct file *file) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder i_gh; struct gfs2_file *fp; int error; @@ -739,7 +739,7 @@ static int gfs2_open(struct inode *inode, struct file *file) mutex_init(&fp->f_fl_mutex); - gfs2_assert_warn(ip->i_sbd, !file->private_data); + gfs2_assert_warn(GFS2_SB(inode), !file->private_data); file->private_data = fp; if (S_ISREG(ip->i_di.di_mode)) { @@ -808,7 +808,7 @@ static int gfs2_close(struct inode *inode, struct file *file) static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync) { - struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(dentry->d_inode); gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); @@ -826,8 +826,8 @@ static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync) static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) { - struct gfs2_inode *ip = file->f_mapping->host->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); + struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host); struct lm_lockname name = { .ln_number = ip->i_num.no_addr, .ln_type = LM_TYPE_PLOCK }; @@ -881,7 +881,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) { struct gfs2_file *fp = file->private_data; struct gfs2_holder *fl_gh = &fp->f_fl_gh; - struct gfs2_inode *ip = file->f_dentry->d_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(file->f_dentry->d_inode); struct gfs2_glock *gl; unsigned int state; int flags; @@ -901,7 +901,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) &(struct file_lock){.fl_type = F_UNLCK}); gfs2_glock_dq_uninit(fl_gh); } else { - error = gfs2_glock_get(ip->i_sbd, + error = gfs2_glock_get(GFS2_SB(&ip->i_inode), ip->i_num.no_addr, &gfs2_flock_glops, CREATE, &gl); if (error) @@ -918,7 +918,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) error = -EAGAIN; } else { error = flock_lock_file_wait(file, fl); - gfs2_assert_warn(ip->i_sbd, !error); + gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); } out: @@ -950,8 +950,8 @@ static void do_unflock(struct file *file, struct file_lock *fl) static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) { - struct gfs2_inode *ip = file->f_mapping->host->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); + struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host); if (!(fl->fl_flags & FL_FLOCK)) return -ENOLCK; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index a45982045509..b68eb6b4a4c1 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -32,7 +32,6 @@ #include "recovery.h" #include "rgrp.h" #include "super.h" -#include "unlinked.h" #include "sys.h" #include "util.h" @@ -80,10 +79,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) spin_lock_init(&sdp->sd_jindex_spin); mutex_init(&sdp->sd_jindex_mutex); - INIT_LIST_HEAD(&sdp->sd_unlinked_list); - spin_lock_init(&sdp->sd_unlinked_spin); - mutex_init(&sdp->sd_unlinked_mutex); - INIT_LIST_HEAD(&sdp->sd_quota_list); spin_lock_init(&sdp->sd_quota_spin); mutex_init(&sdp->sd_quota_mutex); @@ -248,19 +243,19 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, return 0; - fail_trans: +fail_trans: gfs2_glock_put(sdp->sd_trans_gl); - fail_rename: +fail_rename: gfs2_glock_put(sdp->sd_rename_gl); - fail_live: +fail_live: gfs2_glock_dq_uninit(&sdp->sd_live_gh); - fail_mount: +fail_mount: gfs2_glock_dq_uninit(mount_gh); - fail: +fail: while (sdp->sd_glockd_num--) kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]); @@ -269,28 +264,10 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, return error; } -static struct inode *gfs2_lookup_root(struct gfs2_sbd *sdp, - const struct gfs2_inum *inum) +static struct inode *gfs2_lookup_root(struct super_block *sb, + struct gfs2_inum *inum) { - int error; - struct gfs2_glock *gl; - struct gfs2_inode *ip; - struct inode *inode; - - error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_inode_glops, - CREATE, &gl); - if (!error) { - error = gfs2_inode_get(gl, inum, CREATE, &ip); - if (!error) { - gfs2_inode_min_init(ip, DT_DIR); - inode = gfs2_ip2v(ip); - gfs2_inode_put(ip); - gfs2_glock_put(gl); - return inode; - } - gfs2_glock_put(gl); - } - return ERR_PTR(error); + return gfs2_inode_lookup(sb, inum, DT_DIR); } static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) @@ -305,8 +282,7 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) return 0; } - error = gfs2_glock_nq_num(sdp, - GFS2_SB_LOCK, &gfs2_meta_glops, + error = gfs2_glock_nq_num(sdp, GFS2_SB_LOCK, &gfs2_meta_glops, LM_ST_SHARED, 0, &sb_gh); if (error) { fs_err(sdp, "can't acquire superblock glock: %d\n", error); @@ -345,7 +321,7 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) inum = &sdp->sd_sb.sb_root_dir; if (sb->s_type == &gfs2meta_fs_type) inum = &sdp->sd_sb.sb_master_dir; - inode = gfs2_lookup_root(sdp, inum); + inode = gfs2_lookup_root(sb, inum); if (IS_ERR(inode)) { error = PTR_ERR(inode); fs_err(sdp, "can't read in root inode: %d\n", error); @@ -382,7 +358,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) fs_err(sdp, "can't lookup journal index: %d\n", error); return PTR_ERR(sdp->sd_jindex); } - ip = sdp->sd_jindex->u.generic_ip; + ip = GFS2_I(sdp->sd_jindex); set_bit(GLF_STICKY, &ip->i_gl->gl_flags); /* Load in the journal index special file */ @@ -413,8 +389,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) } sdp->sd_jdesc = gfs2_jdesc_find(sdp, sdp->sd_lockstruct.ls_jid); - error = gfs2_glock_nq_num(sdp, - sdp->sd_lockstruct.ls_jid, + error = gfs2_glock_nq_num(sdp, sdp->sd_lockstruct.ls_jid, &gfs2_journal_glops, LM_ST_EXCLUSIVE, LM_FLAG_NOEXP, &sdp->sd_journal_gh); @@ -423,9 +398,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) goto fail_jindex; } - ip = sdp->sd_jdesc->jd_inode->u.generic_ip; - error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_SHARED, + ip = GFS2_I(sdp->sd_jdesc->jd_inode); + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_NOEXP | GL_EXACT, &sdp->sd_jinode_gh); if (error) { @@ -509,7 +483,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) if (undo) goto fail_qinode; - inode = gfs2_lookup_root(sdp, &sdp->sd_sb.sb_master_dir); + inode = gfs2_lookup_root(sdp->sd_vfs, &sdp->sd_sb.sb_master_dir); if (IS_ERR(inode)) { error = PTR_ERR(inode); fs_err(sdp, "can't read in master directory: %d\n", error); @@ -545,7 +519,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) fs_err(sdp, "can't get resource index inode: %d\n", error); goto fail_statfs; } - ip = sdp->sd_rindex->u.generic_ip; + ip = GFS2_I(sdp->sd_rindex); set_bit(GLF_STICKY, &ip->i_gl->gl_flags); sdp->sd_rindex_vn = ip->i_gl->gl_vn - 1; @@ -614,14 +588,6 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) goto fail_ir_i; } - sprintf(buf, "unlinked_tag%u", sdp->sd_jdesc->jd_jid); - sdp->sd_ut_inode = gfs2_lookup_simple(pn, buf); - if (IS_ERR(sdp->sd_ut_inode)) { - error = PTR_ERR(sdp->sd_ut_inode); - fs_err(sdp, "can't find local \"ut\" file: %d\n", error); - goto fail_sc_i; - } - sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid); sdp->sd_qc_inode = gfs2_lookup_simple(pn, buf); if (IS_ERR(sdp->sd_qc_inode)) { @@ -633,7 +599,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) iput(pn); pn = NULL; - ip = sdp->sd_ir_inode->u.generic_ip; + ip = GFS2_I(sdp->sd_ir_inode); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &sdp->sd_ir_gh); @@ -642,7 +608,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) goto fail_qc_i; } - ip = sdp->sd_sc_inode->u.generic_ip; + ip = GFS2_I(sdp->sd_sc_inode); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &sdp->sd_sc_gh); @@ -651,16 +617,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) goto fail_ir_gh; } - ip = sdp->sd_ut_inode->u.generic_ip; - error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_EXCLUSIVE, 0, - &sdp->sd_ut_gh); - if (error) { - fs_err(sdp, "can't lock local \"ut\" file: %d\n", error); - goto fail_sc_gh; - } - - ip = sdp->sd_qc_inode->u.generic_ip; + ip = GFS2_I(sdp->sd_qc_inode); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &sdp->sd_qc_gh); @@ -675,9 +632,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) gfs2_glock_dq_uninit(&sdp->sd_qc_gh); fail_ut_gh: - gfs2_glock_dq_uninit(&sdp->sd_ut_gh); - fail_sc_gh: gfs2_glock_dq_uninit(&sdp->sd_sc_gh); fail_ir_gh: @@ -687,9 +642,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) iput(sdp->sd_qc_inode); fail_ut_i: - iput(sdp->sd_ut_inode); - fail_sc_i: iput(sdp->sd_sc_inode); fail_ir_i: @@ -707,7 +660,7 @@ static int init_threads(struct gfs2_sbd *sdp, int undo) int error = 0; if (undo) - goto fail_inoded; + goto fail_quotad; sdp->sd_log_flush_time = jiffies; sdp->sd_jindex_refresh_time = jiffies; @@ -731,25 +684,13 @@ static int init_threads(struct gfs2_sbd *sdp, int undo) } sdp->sd_quotad_process = p; - p = kthread_run(gfs2_inoded, sdp, "gfs2_inoded"); - error = IS_ERR(p); - if (error) { - fs_err(sdp, "can't start inoded thread: %d\n", error); - goto fail_quotad; - } - sdp->sd_inoded_process = p; - return 0; - fail_inoded: - kthread_stop(sdp->sd_inoded_process); - fail_quotad: +fail_quotad: kthread_stop(sdp->sd_quotad_process); - - fail: +fail: kthread_stop(sdp->sd_logd_process); - return error; } diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 0c06f92368f2..f678f6b62afd 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -38,7 +38,6 @@ #include "quota.h" #include "rgrp.h" #include "trans.h" -#include "unlinked.h" #include "util.h" /** @@ -53,8 +52,8 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { - struct gfs2_inode *dip = dir->u.generic_ip; - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_holder ghs[2]; struct inode *inode; int new = 1; @@ -141,10 +140,10 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, static int gfs2_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct gfs2_inode *dip = dir->u.generic_ip; - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_sbd *sdp = GFS2_SB(dir); struct inode *inode = old_dentry->d_inode; - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder ghs[2]; int alloc_required; int error; @@ -231,30 +230,29 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, error = gfs2_change_nlink(ip, +1); - out_end_trans: +out_end_trans: gfs2_trans_end(sdp); - out_ipres: +out_ipres: if (alloc_required) gfs2_inplace_release(dip); - out_gunlock_q: +out_gunlock_q: if (alloc_required) gfs2_quota_unlock(dip); - out_alloc: +out_alloc: if (alloc_required) gfs2_alloc_put(dip); - out_gunlock: +out_gunlock: gfs2_glock_dq_m(2, ghs); - out: +out: gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs + 1); if (!error) { - atomic_inc(&inode->i_count); d_instantiate(dentry, inode); mark_inode_dirty(inode); } @@ -274,17 +272,12 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, static int gfs2_unlink(struct inode *dir, struct dentry *dentry) { - struct gfs2_inode *dip = dir->u.generic_ip; - struct gfs2_sbd *sdp = dip->i_sbd; - struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; - struct gfs2_unlinked *ul; + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_sbd *sdp = GFS2_SB(dir); + struct gfs2_inode *ip = GFS2_I(dentry->d_inode); struct gfs2_holder ghs[2]; int error; - error = gfs2_unlinked_get(sdp, &ul); - if (error) - return error; - gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); @@ -296,24 +289,23 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) if (error) goto out_gunlock; - error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF + - RES_UNLINKED, 0); + error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); if (error) goto out_gunlock; - error = gfs2_unlinki(dip, &dentry->d_name, ip, ul); + error = gfs2_dir_del(dip, &dentry->d_name); + if (error) + goto out_end_trans; - gfs2_trans_end(sdp); + error = gfs2_change_nlink(ip, -1); - out_gunlock: +out_end_trans: + gfs2_trans_end(sdp); +out_gunlock: gfs2_glock_dq_m(2, ghs); - - out: +out: gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs + 1); - - gfs2_unlinked_put(sdp, ul); - return error; } @@ -329,8 +321,8 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) static int gfs2_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { - struct gfs2_inode *dip = dir->u.generic_ip, *ip; - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *dip = GFS2_I(dir), *ip; + struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_holder ghs[2]; struct inode *inode; struct buffer_head *dibh; @@ -388,8 +380,8 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) { - struct gfs2_inode *dip = dir->u.generic_ip, *ip; - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *dip = GFS2_I(dir), *ip; + struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_holder ghs[2]; struct inode *inode; struct buffer_head *dibh; @@ -466,17 +458,12 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) { - struct gfs2_inode *dip = dir->u.generic_ip; - struct gfs2_sbd *sdp = dip->i_sbd; - struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; - struct gfs2_unlinked *ul; + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_sbd *sdp = GFS2_SB(dir); + struct gfs2_inode *ip = GFS2_I(dentry->d_inode); struct gfs2_holder ghs[2]; int error; - error = gfs2_unlinked_get(sdp, &ul); - if (error) - return error; - gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); @@ -499,12 +486,11 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) goto out_gunlock; } - error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + - RES_UNLINKED, 0); + error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT, 0); if (error) goto out_gunlock; - error = gfs2_rmdiri(dip, &dentry->d_name, ip, ul); + error = gfs2_rmdiri(dip, &dentry->d_name, ip); gfs2_trans_end(sdp); @@ -515,8 +501,6 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs + 1); - gfs2_unlinked_put(sdp, ul); - return error; } @@ -532,8 +516,8 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { - struct gfs2_inode *dip = dir->u.generic_ip, *ip; - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *dip = GFS2_I(dir), *ip; + struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_holder ghs[2]; struct inode *inode; struct buffer_head *dibh; @@ -600,12 +584,11 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, static int gfs2_rename(struct inode *odir, struct dentry *odentry, struct inode *ndir, struct dentry *ndentry) { - struct gfs2_inode *odip = odir->u.generic_ip; - struct gfs2_inode *ndip = ndir->u.generic_ip; - struct gfs2_inode *ip = odentry->d_inode->u.generic_ip; + struct gfs2_inode *odip = GFS2_I(odir); + struct gfs2_inode *ndip = GFS2_I(ndir); + struct gfs2_inode *ip = GFS2_I(odentry->d_inode); struct gfs2_inode *nip = NULL; - struct gfs2_sbd *sdp = odip->i_sbd; - struct gfs2_unlinked *ul; + struct gfs2_sbd *sdp = GFS2_SB(odir); struct gfs2_holder ghs[4], r_gh; unsigned int num_gh; int dir_rename = 0; @@ -614,15 +597,11 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, int error; if (ndentry->d_inode) { - nip = ndentry->d_inode->u.generic_ip; + nip = GFS2_I(ndentry->d_inode); if (ip == nip) return 0; } - error = gfs2_unlinked_get(sdp, &ul); - if (error) - return error; - /* Make sure we aren't trying to move a dirctory into it's subdir */ if (S_ISDIR(ip->i_di.di_mode) && odip != ndip) { @@ -743,14 +722,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + al->al_rgd->rd_ri.ri_length + 4 * RES_DINODE + 4 * RES_LEAF + - RES_UNLINKED + RES_STATFS + - RES_QUOTA, 0); + RES_STATFS + RES_QUOTA, 0); if (error) goto out_ipreserv; } else { error = gfs2_trans_begin(sdp, 4 * RES_DINODE + - 5 * RES_LEAF + - RES_UNLINKED, 0); + 5 * RES_LEAF, 0); if (error) goto out_gunlock; } @@ -759,9 +736,13 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (nip) { if (S_ISDIR(nip->i_di.di_mode)) - error = gfs2_rmdiri(ndip, &ndentry->d_name, nip, ul); - else - error = gfs2_unlinki(ndip, &ndentry->d_name, nip, ul); + error = gfs2_rmdiri(ndip, &ndentry->d_name, nip); + else { + error = gfs2_dir_del(ndip, &ndentry->d_name); + if (error) + goto out_end_trans; + error = gfs2_change_nlink(nip, -1); + } if (error) goto out_end_trans; } @@ -800,35 +781,26 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (error) goto out_end_trans; - out_end_trans: +out_end_trans: gfs2_trans_end(sdp); - - out_ipreserv: +out_ipreserv: if (alloc_required) gfs2_inplace_release(ndip); - - out_gunlock_q: +out_gunlock_q: if (alloc_required) gfs2_quota_unlock(ndip); - - out_alloc: +out_alloc: if (alloc_required) gfs2_alloc_put(ndip); - - out_gunlock: +out_gunlock: gfs2_glock_dq_m(num_gh, ghs); - - out_uninit: +out_uninit: for (x = 0; x < num_gh; x++) gfs2_holder_uninit(ghs + x); - - out_gunlock_r: +out_gunlock_r: if (dir_rename) gfs2_glock_dq_uninit(&r_gh); - - out: - gfs2_unlinked_put(sdp, ul); - +out: return error; } @@ -844,7 +816,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, static int gfs2_readlink(struct dentry *dentry, char __user *user_buf, int user_size) { - struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(dentry->d_inode); char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; @@ -880,7 +852,7 @@ static int gfs2_readlink(struct dentry *dentry, char __user *user_buf, static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(dentry->d_inode); char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; @@ -906,7 +878,7 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder i_gh; int error; @@ -926,7 +898,7 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) static int setattr_size(struct inode *inode, struct iattr *attr) { - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); int error; if (attr->ia_size != ip->i_di.di_size) { @@ -944,8 +916,8 @@ static int setattr_size(struct inode *inode, struct iattr *attr) static int setattr_chown(struct inode *inode, struct iattr *attr) { - struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); struct buffer_head *dibh; uint32_t ouid, ogid, nuid, ngid; int error; @@ -1021,7 +993,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder i_gh; int error; @@ -1068,7 +1040,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int error; @@ -1084,7 +1056,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, static int gfs2_setxattr(struct dentry *dentry, const char *name, const void *data, size_t size, int flags) { - struct gfs2_inode *ip = dentry->d_inode->u.generic_ip; + struct inode *inode = dentry->d_inode; struct gfs2_ea_request er; memset(&er, 0, sizeof(struct gfs2_ea_request)); @@ -1096,9 +1068,9 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name, er.er_data_len = size; er.er_flags = flags; - gfs2_assert_warn(ip->i_sbd, !(er.er_flags & GFS2_ERF_MODE)); + gfs2_assert_warn(GFS2_SB(inode), !(er.er_flags & GFS2_ERF_MODE)); - return gfs2_ea_set(ip, &er); + return gfs2_ea_set(GFS2_I(inode), &er); } static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, @@ -1114,7 +1086,7 @@ static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, er.er_name_len = strlen(er.er_name); er.er_data_len = size; - return gfs2_ea_get(dentry->d_inode->u.generic_ip, &er); + return gfs2_ea_get(GFS2_I(dentry->d_inode), &er); } static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) @@ -1125,7 +1097,7 @@ static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) er.er_data = (size) ? buffer : NULL; er.er_data_len = size; - return gfs2_ea_list(dentry->d_inode->u.generic_ip, &er); + return gfs2_ea_list(GFS2_I(dentry->d_inode), &er); } static int gfs2_removexattr(struct dentry *dentry, const char *name) @@ -1138,7 +1110,7 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name) return -EOPNOTSUPP; er.er_name_len = strlen(er.er_name); - return gfs2_ea_remove(dentry->d_inode->u.generic_ip, &er); + return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er); } struct inode_operations gfs2_file_iops = { diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 1c17acc946f9..317d497f8f88 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "gfs2.h" #include "lm_interface.h" @@ -36,6 +37,10 @@ #include "super.h" #include "sys.h" #include "util.h" +#include "trans.h" +#include "dir.h" +#include "eattr.h" +#include "bmap.h" /** * gfs2_write_inode - Make sure the inode is stable on the disk @@ -47,12 +52,15 @@ static int gfs2_write_inode(struct inode *inode, int sync) { - struct gfs2_inode *ip = inode->u.generic_ip; - - if (current->flags & PF_MEMALLOC) - return 0; - if (ip && sync) - gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); + struct gfs2_inode *ip = GFS2_I(inode); + + /* Check this is a "normal" inode */ + if (inode->u.generic_ip) { + if (current->flags & PF_MEMALLOC) + return 0; + if (sync) + gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); + } return 0; } @@ -78,7 +86,6 @@ static void gfs2_put_super(struct super_block *sb) gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); mutex_unlock(&sdp->sd_freeze_lock); - kthread_stop(sdp->sd_inoded_process); kthread_stop(sdp->sd_quotad_process); kthread_stop(sdp->sd_logd_process); kthread_stop(sdp->sd_recoverd_process); @@ -110,11 +117,9 @@ static void gfs2_put_super(struct super_block *sb) gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); gfs2_glock_dq_uninit(&sdp->sd_ir_gh); gfs2_glock_dq_uninit(&sdp->sd_sc_gh); - gfs2_glock_dq_uninit(&sdp->sd_ut_gh); gfs2_glock_dq_uninit(&sdp->sd_qc_gh); iput(sdp->sd_ir_inode); iput(sdp->sd_sc_inode); - iput(sdp->sd_ut_inode); iput(sdp->sd_qc_inode); } @@ -274,16 +279,20 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) static void gfs2_clear_inode(struct inode *inode) { - struct gfs2_inode *ip = inode->u.generic_ip; - - if (ip) { - spin_lock(&ip->i_spin); - ip->i_vnode = NULL; - inode->u.generic_ip = NULL; - spin_unlock(&ip->i_spin); - + /* This tells us its a "real" inode and not one which only + * serves to contain an address space (see rgrp.c, meta_io.c) + * which therefore doesn't have its own glocks. + */ + if (inode->u.generic_ip) { + struct gfs2_inode *ip = GFS2_I(inode); + gfs2_glock_inode_squish(inode); + gfs2_assert(inode->i_sb->s_fs_info, ip->i_gl->gl_state == LM_ST_UNLOCKED); + ip->i_gl->gl_object = NULL; gfs2_glock_schedule_for_reclaim(ip->i_gl); - gfs2_inode_put(ip); + gfs2_glock_put(ip->i_gl); + ip->i_gl = NULL; + if (ip->i_iopen_gh.gh_gl) + gfs2_glock_dq_uninit(&ip->i_iopen_gh); } } @@ -361,6 +370,70 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) return 0; } +/* + * We have to (at the moment) hold the inodes main lock to cover + * the gap between unlocking the shared lock on the iopen lock and + * taking the exclusive lock. I'd rather do a shared -> exclusive + * conversion on the iopen lock, but we can change that later. This + * is safe, just less efficient. + */ +static void gfs2_delete_inode(struct inode *inode) +{ + struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_holder gh; + int error; + + if (!inode->u.generic_ip) + goto out; + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &gh); + if (unlikely(error)) { + gfs2_glock_dq_uninit(&ip->i_iopen_gh); + goto out; + } + + gfs2_glock_dq(&ip->i_iopen_gh); + gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); + error = gfs2_glock_nq(&ip->i_iopen_gh); + if (error) + goto out_uninit; + + if (S_ISDIR(ip->i_di.di_mode) && + (ip->i_di.di_flags & GFS2_DIF_EXHASH)) { + error = gfs2_dir_exhash_dealloc(ip); + if (error) + goto out_unlock; + } + + if (ip->i_di.di_eattr) { + error = gfs2_ea_dealloc(ip); + if (error) + goto out_unlock; + } + + if (!gfs2_is_stuffed(ip)) { + error = gfs2_file_dealloc(ip); + if (error) + goto out_unlock; + } + + error = gfs2_dinode_dealloc(ip); + +out_unlock: + gfs2_glock_dq(&ip->i_iopen_gh); +out_uninit: + gfs2_holder_uninit(&ip->i_iopen_gh); + gfs2_glock_dq_uninit(&gh); + if (error) + fs_warn(sdp, "gfs2_delete_inode: %d\n", error); +out: + truncate_inode_pages(&inode->i_data, 0); + clear_inode(inode); +} + + + static struct inode *gfs2_alloc_inode(struct super_block *sb) { struct gfs2_sbd *sdp = sb->s_fs_info; @@ -370,8 +443,6 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb) if (ip) { ip->i_flags = 0; ip->i_gl = NULL; - ip->i_sbd = sdp; - ip->i_vnode = &ip->i_inode; ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default); ip->i_last_pfault = jiffies; } @@ -387,6 +458,7 @@ struct super_operations gfs2_super_ops = { .alloc_inode = gfs2_alloc_inode, .destroy_inode = gfs2_destroy_inode, .write_inode = gfs2_write_inode, + .delete_inode = gfs2_delete_inode, .put_super = gfs2_put_super, .write_super = gfs2_write_super, .write_super_lockfs = gfs2_write_super_lockfs, diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 263c1fb7bbaf..08709f19ea98 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -38,15 +38,15 @@ static void pfault_be_greedy(struct gfs2_inode *ip) ip->i_last_pfault = jiffies; spin_unlock(&ip->i_spin); - gfs2_inode_hold(ip); + igrab(&ip->i_inode); if (gfs2_glock_be_greedy(ip->i_gl, time)) - gfs2_inode_put(ip); + iput(&ip->i_inode); } static struct page *gfs2_private_nopage(struct vm_area_struct *area, unsigned long address, int *type) { - struct gfs2_inode *ip = area->vm_file->f_mapping->host->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host); struct gfs2_holder i_gh; struct page *result; int error; @@ -69,7 +69,7 @@ static struct page *gfs2_private_nopage(struct vm_area_struct *area, static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); unsigned long index = page->index; uint64_t lblock = index << (PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift); @@ -114,7 +114,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) unsigned int extlen; int new = 1; - error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen); + error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); if (error) goto out_trans; @@ -142,7 +142,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, unsigned long address, int *type) { - struct gfs2_inode *ip = area->vm_file->f_mapping->host->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host); struct gfs2_holder i_gh; struct page *result = NULL; unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c index cd93644c7d70..a8165a693b56 100644 --- a/fs/gfs2/page.c +++ b/fs/gfs2/page.c @@ -38,20 +38,17 @@ void gfs2_pte_inval(struct gfs2_glock *gl) struct inode *inode; ip = gl->gl_object; + inode = &ip->i_inode; if (!ip || !S_ISREG(ip->i_di.di_mode)) return; if (!test_bit(GIF_PAGED, &ip->i_flags)) return; - inode = gfs2_ip2v_lookup(ip); - if (inode) { - unmap_shared_mapping_range(inode->i_mapping, 0, 0); - iput(inode); + unmap_shared_mapping_range(inode->i_mapping, 0, 0); - if (test_bit(GIF_SW_PAGED, &ip->i_flags)) - set_bit(GLF_DIRTY, &gl->gl_flags); - } + if (test_bit(GIF_SW_PAGED, &ip->i_flags)) + set_bit(GLF_DIRTY, &gl->gl_flags); clear_bit(GIF_SW_PAGED, &ip->i_flags); } @@ -68,19 +65,12 @@ void gfs2_page_inval(struct gfs2_glock *gl) struct inode *inode; ip = gl->gl_object; + inode = &ip->i_inode; if (!ip || !S_ISREG(ip->i_di.di_mode)) return; - inode = gfs2_ip2v_lookup(ip); - if (inode) { - struct address_space *mapping = inode->i_mapping; - - truncate_inode_pages(mapping, 0); - gfs2_assert_withdraw(ip->i_sbd, !mapping->nrpages); - - iput(inode); - } - + truncate_inode_pages(inode->i_mapping, 0); + gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), !inode->i_mapping->nrpages); clear_bit(GIF_PAGED, &ip->i_flags); } @@ -97,32 +87,30 @@ void gfs2_page_sync(struct gfs2_glock *gl, int flags) { struct gfs2_inode *ip; struct inode *inode; + struct address_space *mapping; + int error = 0; ip = gl->gl_object; + inode = &ip->i_inode; if (!ip || !S_ISREG(ip->i_di.di_mode)) return; - inode = gfs2_ip2v_lookup(ip); - if (inode) { - struct address_space *mapping = inode->i_mapping; - int error = 0; + mapping = inode->i_mapping; - if (flags & DIO_START) - filemap_fdatawrite(mapping); - if (!error && (flags & DIO_WAIT)) - error = filemap_fdatawait(mapping); + if (flags & DIO_START) + filemap_fdatawrite(mapping); + if (!error && (flags & DIO_WAIT)) + error = filemap_fdatawait(mapping); - /* Put back any errors cleared by filemap_fdatawait() - so they can be caught by someone who can pass them - up to user space. */ + /* Put back any errors cleared by filemap_fdatawait() + so they can be caught by someone who can pass them + up to user space. */ - if (error == -ENOSPC) - set_bit(AS_ENOSPC, &mapping->flags); - else if (error) - set_bit(AS_EIO, &mapping->flags); + if (error == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + else if (error) + set_bit(AS_EIO, &mapping->flags); - iput(inode); - } } /** @@ -138,8 +126,8 @@ void gfs2_page_sync(struct gfs2_glock *gl, int flags) int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, uint64_t block, void *private) { - struct gfs2_sbd *sdp = ip->i_sbd; - struct inode *inode = ip->i_vnode; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct inode *inode = &ip->i_inode; struct page *page = (struct page *)private; struct buffer_head *bh; int release = 0; @@ -193,8 +181,8 @@ int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, int gfs2_block_truncate_page(struct address_space *mapping) { struct inode *inode = mapping->host; - struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); loff_t from = inode->i_size; unsigned long index = from >> PAGE_CACHE_SHIFT; unsigned offset = from & (PAGE_CACHE_SIZE-1); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index f752b0184690..d3cd5171d7c7 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -248,7 +248,7 @@ static void slot_put(struct gfs2_quota_data *qd) static int bh_get(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - struct gfs2_inode *ip = sdp->sd_qc_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); unsigned int block, offset; uint64_t dblock; int new = 0; @@ -266,7 +266,7 @@ static int bh_get(struct gfs2_quota_data *qd) block = qd->qd_slot / sdp->sd_qc_per_block; offset = qd->qd_slot % sdp->sd_qc_per_block;; - error = gfs2_block_map(ip->i_vnode, block, &new, &dblock, &boundary); + error = gfs2_block_map(&ip->i_inode, block, &new, &dblock, &boundary); if (error) goto fail; error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); @@ -444,7 +444,7 @@ static void qdsb_put(struct gfs2_quota_data *qd) int gfs2_quota_hold(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_quota_data **qd = al->al_qd; int error; @@ -493,7 +493,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) void gfs2_quota_unhold(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; unsigned int x; @@ -531,7 +531,7 @@ static int sort_qd(const void *a, const void *b) static void do_qc(struct gfs2_quota_data *qd, int64_t change) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - struct gfs2_inode *ip = sdp->sd_qc_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); struct gfs2_quota_change *qc = qd->qd_bh_qc; int64_t x; @@ -578,7 +578,7 @@ static void do_qc(struct gfs2_quota_data *qd, int64_t change) static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, int64_t change, struct gfs2_quota_data *qd) { - struct inode *inode = ip->i_vnode; + struct inode *inode = &ip->i_inode; struct address_space *mapping = inode->i_mapping; unsigned long index = loc >> PAGE_CACHE_SHIFT; unsigned offset = loc & (PAGE_CACHE_SHIFT - 1); @@ -647,7 +647,7 @@ unlock: static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) { struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd; - struct gfs2_inode *ip = sdp->sd_quota_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); unsigned int data_blocks, ind_blocks; struct file_ra_state ra_state; struct gfs2_holder *ghs, i_gh; @@ -716,7 +716,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) goto out_gunlock; } - file_ra_state_init(&ra_state, ip->i_vnode->i_mapping); + file_ra_state_init(&ra_state, ip->i_inode.i_mapping); for (x = 0; x < num_qd; x++) { qd = qda[x]; offset = qd2offset(qd); @@ -758,7 +758,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, struct gfs2_holder *q_gh) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - struct gfs2_inode *ip = sdp->sd_quota_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); struct gfs2_holder i_gh; struct gfs2_quota q; char buf[sizeof(struct gfs2_quota)]; @@ -829,7 +829,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, int gfs2_quota_lock(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; unsigned int x; int error = 0; @@ -958,7 +958,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type) int gfs2_quota_check(struct gfs2_inode *ip, uint32_t uid, uint32_t gid) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_quota_data *qd; int64_t value; @@ -1008,7 +1008,7 @@ void gfs2_quota_change(struct gfs2_inode *ip, int64_t change, unsigned int x; unsigned int found = 0; - if (gfs2_assert_warn(ip->i_sbd, change)) + if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change)) return; if (ip->i_di.di_flags & GFS2_DIF_SYSTEM) return; @@ -1126,7 +1126,7 @@ int gfs2_quota_read(struct gfs2_sbd *sdp, int user, uint32_t id, int gfs2_quota_init(struct gfs2_sbd *sdp) { - struct gfs2_inode *ip = sdp->sd_qc_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); unsigned int blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; unsigned int x, slot = 0; unsigned int found = 0; @@ -1162,7 +1162,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) if (!extlen) { int new = 0; - error = gfs2_extent_map(ip->i_vnode, x, &new, &dblock, &extlen); + error = gfs2_extent_map(&ip->i_inode, x, &new, &dblock, &extlen); if (error) goto fail; } diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index c504ac1b831d..7aabc03e4abd 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -32,14 +32,14 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, struct buffer_head **bh) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); struct gfs2_glock *gl = ip->i_gl; int new = 0; uint64_t dblock; uint32_t extlen; int error; - error = gfs2_extent_map(ip->i_vnode, blk, &new, &dblock, &extlen); + error = gfs2_extent_map(&ip->i_inode, blk, &new, &dblock, &extlen); if (error) return error; if (!dblock) { @@ -190,7 +190,7 @@ static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk, *blk = 0; if (*blk == orig_blk) { - gfs2_consist_inode(jd->jd_inode->u.generic_ip); + gfs2_consist_inode(GFS2_I(jd->jd_inode)); return -EIO; } } @@ -224,7 +224,7 @@ static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head) continue; if (lh.lh_sequence == head->lh_sequence) { - gfs2_consist_inode(jd->jd_inode->u.generic_ip); + gfs2_consist_inode(GFS2_I(jd->jd_inode)); return -EIO; } if (lh.lh_sequence < head->lh_sequence) @@ -300,8 +300,7 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header *head) static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, unsigned int end, int pass) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct buffer_head *bh; struct gfs2_log_descriptor *ld; int error = 0; @@ -330,7 +329,7 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, continue; } if (error == 1) { - gfs2_consist_inode(jd->jd_inode->u.generic_ip); + gfs2_consist_inode(GFS2_I(jd->jd_inode)); error = -EIO; } brelse(bh); @@ -367,8 +366,8 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); unsigned int lblock; int new = 0; uint64_t dblock; @@ -380,7 +379,7 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) lblock = head->lh_blkno; gfs2_replay_incr_blk(sdp, &lblock); - error = gfs2_block_map(ip->i_vnode, lblock, &new, &dblock, &boundary); + error = gfs2_block_map(&ip->i_inode, lblock, &new, &dblock, &boundary); if (error) return error; if (!dblock) { @@ -426,8 +425,8 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) int gfs2_recover_journal(struct gfs2_jdesc *jd) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct gfs2_log_header head; struct gfs2_holder j_gh, ji_gh, t_gh; unsigned long t; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 691e6f3ce43b..75df79eb50ba 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -34,17 +34,19 @@ /* * These routines are used by the resource group routines (rgrp.c) * to keep track of block allocation. Each block is represented by two - * bits. One bit indicates whether or not the block is used. (1=used, - * 0=free) The other bit indicates whether or not the block contains a - * dinode or not. (1=dinode, 0=not-dinode) So, each byte represents - * GFS2_NBBY (i.e. 4) blocks. + * bits. So, each byte represents GFS2_NBBY (i.e. 4) blocks. + * + * 0 = Free + * 1 = Used (not metadata) + * 2 = Unlinked (still in use) inode + * 3 = Used (metadata) */ static const char valid_change[16] = { /* current */ - /* n */ 0, 1, 0, 1, + /* n */ 0, 1, 1, 1, /* e */ 1, 0, 0, 0, - /* w */ 0, 0, 0, 0, + /* w */ 0, 0, 0, 1, 1, 0, 0, 0 }; @@ -228,26 +230,27 @@ void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd) tmp = rgd->rd_ri.ri_data - rgd->rd_rg.rg_free - rgd->rd_rg.rg_dinodes; - if (count[1] != tmp) { + if (count[1] + count[2] != tmp) { if (gfs2_consist_rgrpd(rgd)) fs_err(sdp, "used data mismatch: %u != %u\n", count[1], tmp); return; } - if (count[2]) { + if (count[3] != rgd->rd_rg.rg_dinodes) { if (gfs2_consist_rgrpd(rgd)) - fs_err(sdp, "free metadata mismatch: %u != 0\n", - count[2]); + fs_err(sdp, "used metadata mismatch: %u != %u\n", + count[3], rgd->rd_rg.rg_dinodes); return; } - if (count[3] != rgd->rd_rg.rg_dinodes) { + if (count[2] > count[3]) { if (gfs2_consist_rgrpd(rgd)) - fs_err(sdp, "used metadata mismatch: %u != %u\n", - count[3], rgd->rd_rg.rg_dinodes); + fs_err(sdp, "unlinked inodes > inodes: %u\n", + count[2]); return; } + } static inline int rgrp_contains_block(struct gfs2_rindex *ri, uint64_t block) @@ -368,6 +371,9 @@ static int compute_bitstructs(struct gfs2_rgrpd *rgd) uint32_t bytes_left, bytes; int x; + if (!length) + return -EINVAL; + rgd->rd_bits = kcalloc(length, sizeof(struct gfs2_bitmap), GFP_KERNEL); if (!rgd->rd_bits) return -ENOMEM; @@ -433,14 +439,16 @@ static int compute_bitstructs(struct gfs2_rgrpd *rgd) static int gfs2_ri_update(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = ip->i_sbd; - struct inode *inode = ip->i_vnode; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct inode *inode = &ip->i_inode; struct gfs2_rgrpd *rgd; char buf[sizeof(struct gfs2_rindex)]; struct file_ra_state ra_state; uint64_t junk = ip->i_di.di_size; int error; + printk(KERN_INFO "gfs2_ri_update inode=%p\n", inode); + if (do_div(junk, sizeof(struct gfs2_rindex))) { gfs2_consist_inode(ip); return -EIO; @@ -448,9 +456,12 @@ static int gfs2_ri_update(struct gfs2_inode *ip) clear_rgrpdi(sdp); + printk(KERN_INFO "rgrps cleared\n"); + file_ra_state_init(&ra_state, inode->i_mapping); for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) { loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex); + printk(KERN_INFO "reading rgrp %d\n", sdp->sd_rgrps); error = gfs2_internal_read(ip, &ra_state, buf, &pos, sizeof(struct gfs2_rindex)); if (!error) @@ -474,13 +485,15 @@ static int gfs2_ri_update(struct gfs2_inode *ip) list_add_tail(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list); gfs2_rindex_in(&rgd->rd_ri, buf); - + printk(KERN_INFO "compute bitstructs\n"); error = compute_bitstructs(rgd); if (error) goto fail; + printk(KERN_INFO "gfs2_glock_get\n"); error = gfs2_glock_get(sdp, rgd->rd_ri.ri_addr, &gfs2_rgrp_glops, CREATE, &rgd->rd_gl); + printk(KERN_INFO "gfs2_glock_got one\n"); if (error) goto fail; @@ -488,13 +501,14 @@ static int gfs2_ri_update(struct gfs2_inode *ip) rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1; } + printk(KERN_INFO "ok, finished\n"); sdp->sd_rindex_vn = ip->i_gl->gl_vn; - return 0; - fail: +fail: + printk(KERN_INFO "fail\n"); clear_rgrpdi(sdp); - + printk(KERN_INFO "cleared rgrps\n"); return error; } @@ -518,7 +532,7 @@ static int gfs2_ri_update(struct gfs2_inode *ip) int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh) { - struct gfs2_inode *ip = sdp->sd_rindex->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex); struct gfs2_glock *gl = ip->i_gl; int error; @@ -583,8 +597,7 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) error = gfs2_meta_reread(sdp, bi->bi_bh, DIO_WAIT); if (error) goto fail; - if (gfs2_metatype_check(sdp, bi->bi_bh, - (y) ? GFS2_METATYPE_RB : + if (gfs2_metatype_check(sdp, bi->bi_bh, y ? GFS2_METATYPE_RB : GFS2_METATYPE_RG)) { error = -EIO; goto fail; @@ -605,7 +618,7 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) return 0; - fail: +fail: while (x--) { bi = rgd->rd_bits + x; brelse(bi->bi_bh); @@ -667,8 +680,7 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) if (!bi->bi_clone) continue; memcpy(bi->bi_clone + bi->bi_offset, - bi->bi_bh->b_data + bi->bi_offset, - bi->bi_len); + bi->bi_bh->b_data + bi->bi_offset, bi->bi_len); } spin_lock(&sdp->sd_rindex_spin); @@ -757,13 +769,11 @@ static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp, goto out; } - first: +first: rgd = list_entry(sdp->sd_rindex_recent_list.next, struct gfs2_rgrpd, rd_recent); - - out: +out: spin_unlock(&sdp->sd_rindex_spin); - return rgd; } @@ -805,9 +815,8 @@ static struct gfs2_rgrpd *recent_rgrp_next(struct gfs2_rgrpd *cur_rgd, if (!list_empty(head)) rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent); - out: +out: spin_unlock(&sdp->sd_rindex_spin); - return rgd; } @@ -835,7 +844,7 @@ static void recent_rgrp_add(struct gfs2_rgrpd *new_rgd) } list_add_tail(&new_rgd->rd_recent, &sdp->sd_rindex_recent_list); - out: +out: spin_unlock(&sdp->sd_rindex_spin); } @@ -898,7 +907,7 @@ static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd) static int get_local_rgrp(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrpd *rgd, *begin = NULL; struct gfs2_alloc *al = &ip->i_alloc; int flags = LM_FLAG_TRY; @@ -965,7 +974,7 @@ static int get_local_rgrp(struct gfs2_inode *ip) } } - out: +out: ip->i_last_rg_alloc = rgd->rd_ri.ri_addr; if (begin) { @@ -988,7 +997,7 @@ static int get_local_rgrp(struct gfs2_inode *ip) int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; int error; @@ -1020,7 +1029,7 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) void gfs2_inplace_release(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1) @@ -1061,8 +1070,7 @@ unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, uint64_t block) gfs2_assert(rgd->rd_sbd, buf < length); buf_block = rgrp_block - bi->bi_start * GFS2_NBBY; - type = gfs2_testbit(rgd, - bi->bi_bh->b_data + bi->bi_offset, + type = gfs2_testbit(rgd, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len, buf_block); return type; @@ -1210,7 +1218,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, uint64_t bstart, uint64_t gfs2_alloc_data(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_rgrpd *rgd = al->al_rgd; uint32_t goal, blk; @@ -1254,7 +1262,7 @@ uint64_t gfs2_alloc_data(struct gfs2_inode *ip) uint64_t gfs2_alloc_meta(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_rgrpd *rgd = al->al_rgd; uint32_t goal, blk; @@ -1299,7 +1307,7 @@ uint64_t gfs2_alloc_meta(struct gfs2_inode *ip) uint64_t gfs2_alloc_di(struct gfs2_inode *dip) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_alloc *al = &dip->i_alloc; struct gfs2_rgrpd *rgd = al->al_rgd; uint32_t blk; @@ -1341,7 +1349,7 @@ uint64_t gfs2_alloc_di(struct gfs2_inode *dip) void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrpd *rgd; rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE); @@ -1370,7 +1378,7 @@ void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) void gfs2_free_meta(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrpd *rgd; rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE); @@ -1385,11 +1393,25 @@ void gfs2_free_meta(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) gfs2_trans_add_rg(rgd); gfs2_statfs_change(sdp, 0, +blen, 0); - gfs2_quota_change(ip, -(int64_t)blen, - ip->i_di.di_uid, ip->i_di.di_gid); + gfs2_quota_change(ip, -(int64_t)blen, ip->i_di.di_uid, ip->i_di.di_gid); gfs2_meta_wipe(ip, bstart, blen); } +void gfs2_unlink_di(struct inode *inode) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + struct gfs2_rgrpd *rgd; + u64 blkno = ip->i_num.no_addr; + + rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_UNLINKED); + if (!rgd) + return; + gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); + gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); + gfs2_trans_add_rg(rgd); +} + void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, uint64_t blkno) { struct gfs2_sbd *sdp = rgd->rd_sbd; @@ -1412,12 +1434,6 @@ void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, uint64_t blkno) gfs2_trans_add_rg(rgd); } -/** - * gfs2_free_uninit_di - free a dinode block - * @rgd: the resource group that contains the dinode - * @ip: the inode - * - */ void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip) { diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index d2db3719cc0f..e86a532cc159 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -45,6 +45,7 @@ void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); void gfs2_free_meta(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, uint64_t blkno); void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); +void gfs2_unlink_di(struct inode *inode); struct gfs2_rgrp_list { unsigned int rl_rgrps; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index a943a505bc5a..f2d287660cc9 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -31,7 +31,6 @@ #include "rgrp.h" #include "super.h" #include "trans.h" -#include "unlinked.h" #include "util.h" /** @@ -55,7 +54,6 @@ void gfs2_tune_init(struct gfs2_tune *gt) gt->gt_recoverd_secs = 60; gt->gt_logd_secs = 1; gt->gt_quotad_secs = 5; - gt->gt_inoded_secs = 15; gt->gt_quota_simul_sync = 64; gt->gt_quota_warn_period = 10; gt->gt_quota_scale_num = 1; @@ -202,9 +200,6 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) sdp->sd_hash_bsize = sdp->sd_sb.sb_bsize / 2; sdp->sd_hash_bsize_shift = sdp->sd_sb.sb_bsize_shift - 1; sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(uint64_t); - sdp->sd_ut_per_block = (sdp->sd_sb.sb_bsize - - sizeof(struct gfs2_meta_header)) / - sizeof(struct gfs2_unlinked_tag); sdp->sd_qc_per_block = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header)) / sizeof(struct gfs2_quota_change); @@ -277,7 +272,7 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) { - struct gfs2_inode *dip = sdp->sd_jindex->u.generic_ip; + struct gfs2_inode *dip = GFS2_I(sdp->sd_jindex); struct qstr name; char buf[20]; struct gfs2_jdesc *jd; @@ -296,8 +291,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) name.len = sprintf(buf, "journal%u", sdp->sd_journals); name.hash = gfs2_disk_hash(name.name, name.len); - error = gfs2_dir_search(sdp->sd_jindex, - &name, NULL, NULL); + error = gfs2_dir_search(sdp->sd_jindex, &name, NULL, NULL); if (error == -ENOENT) { error = 0; break; @@ -423,22 +417,19 @@ struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp) int gfs2_jdesc_check(struct gfs2_jdesc *jd) { - struct gfs2_inode *ip = jd->jd_inode->u.generic_ip; - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); int ar; int error; - if (ip->i_di.di_size < (8 << 20) || - ip->i_di.di_size > (1 << 30) || + if (ip->i_di.di_size < (8 << 20) || ip->i_di.di_size > (1 << 30) || (ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1))) { gfs2_consist_inode(ip); return -EIO; } jd->jd_blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; - error = gfs2_write_alloc_required(ip, - 0, ip->i_di.di_size, - &ar); + error = gfs2_write_alloc_required(ip, 0, ip->i_di.di_size, &ar); if (!error && ar) { gfs2_consist_inode(ip); error = -EIO; @@ -456,7 +447,7 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd) int gfs2_make_fs_rw(struct gfs2_sbd *sdp) { - struct gfs2_inode *ip = sdp->sd_jdesc->jd_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode); struct gfs2_glock *j_gl = ip->i_gl; struct gfs2_holder t_gh; struct gfs2_log_header head; @@ -484,9 +475,6 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) sdp->sd_log_sequence = head.lh_sequence + 1; gfs2_log_pointers_init(sdp, head.lh_blkno); - error = gfs2_unlinked_init(sdp); - if (error) - goto fail; error = gfs2_quota_init(sdp); if (error) goto fail_unlinked; @@ -498,7 +486,6 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) return 0; fail_unlinked: - gfs2_unlinked_cleanup(sdp); fail: t_gh.gh_flags |= GL_NOCACHE; @@ -519,7 +506,6 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp) struct gfs2_holder t_gh; int error; - gfs2_unlinked_dealloc(sdp); gfs2_quota_sync(sdp); gfs2_statfs_sync(sdp); @@ -537,7 +523,6 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp) if (t_gh.gh_gl) gfs2_glock_dq_uninit(&t_gh); - gfs2_unlinked_cleanup(sdp); gfs2_quota_cleanup(sdp); return error; @@ -545,9 +530,9 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp) int gfs2_statfs_init(struct gfs2_sbd *sdp) { - struct gfs2_inode *m_ip = sdp->sd_statfs_inode->u.generic_ip; + struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; - struct gfs2_inode *l_ip = sdp->sd_sc_inode->u.generic_ip; + struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; struct buffer_head *m_bh, *l_bh; struct gfs2_holder gh; @@ -594,7 +579,7 @@ int gfs2_statfs_init(struct gfs2_sbd *sdp) void gfs2_statfs_change(struct gfs2_sbd *sdp, int64_t total, int64_t free, int64_t dinodes) { - struct gfs2_inode *l_ip = sdp->sd_sc_inode->u.generic_ip; + struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; struct buffer_head *l_bh; int error; @@ -620,8 +605,8 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, int64_t total, int64_t free, int gfs2_statfs_sync(struct gfs2_sbd *sdp) { - struct gfs2_inode *m_ip = sdp->sd_statfs_inode->u.generic_ip; - struct gfs2_inode *l_ip = sdp->sd_sc_inode->u.generic_ip; + struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); + struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; struct gfs2_holder gh; @@ -852,10 +837,8 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, error = -ENOMEM; goto out; } - ip = jd->jd_inode->u.generic_ip; - error = gfs2_glock_nq_init(ip->i_gl, - LM_ST_SHARED, 0, - &lfcc->gh); + ip = GFS2_I(jd->jd_inode); + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &lfcc->gh); if (error) { kfree(lfcc); goto out; diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index d32a2c54daee..3c4cb4558905 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -453,7 +453,6 @@ TUNE_ATTR_DAEMON(scand_secs, scand_process); TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process); TUNE_ATTR_DAEMON(logd_secs, logd_process); TUNE_ATTR_DAEMON(quotad_secs, quotad_process); -TUNE_ATTR_DAEMON(inoded_secs, inoded_process); TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store); static struct attribute *tune_attrs[] = { @@ -485,7 +484,6 @@ static struct attribute *tune_attrs[] = { &tune_attr_recoverd_secs.attr, &tune_attr_logd_secs.attr, &tune_attr_quotad_secs.attr, - &tune_attr_inoded_secs.attr, &tune_attr_quota_scale.attr, &tune_attr_new_files_jdata.attr, &tune_attr_new_files_directio.attr, diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index 60ef163dd9bb..fbef3f5a99e3 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -17,7 +17,6 @@ #define RES_LEAF 1 #define RES_RG_BIT 2 #define RES_EATTR 1 -#define RES_UNLINKED 1 #define RES_STATFS 1 #define RES_QUOTA 2 diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c deleted file mode 100644 index b92d73002055..000000000000 --- a/fs/gfs2/unlinked.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License v.2. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "gfs2.h" -#include "lm_interface.h" -#include "incore.h" -#include "bmap.h" -#include "inode.h" -#include "meta_io.h" -#include "trans.h" -#include "unlinked.h" -#include "util.h" - -static int munge_ondisk(struct gfs2_sbd *sdp, unsigned int slot, - struct gfs2_unlinked_tag *ut) -{ - struct gfs2_inode *ip = sdp->sd_ut_inode->u.generic_ip; - unsigned int block, offset; - uint64_t dblock; - int new = 0; - struct buffer_head *bh; - int error; - int boundary; - - block = slot / sdp->sd_ut_per_block; - offset = slot % sdp->sd_ut_per_block; - - error = gfs2_block_map(ip->i_vnode, block, &new, &dblock, &boundary); - if (error) - return error; - error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); - if (error) - return error; - if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_UT)) { - error = -EIO; - goto out; - } - - mutex_lock(&sdp->sd_unlinked_mutex); - gfs2_trans_add_bh(ip->i_gl, bh, 1); - gfs2_unlinked_tag_out(ut, bh->b_data + - sizeof(struct gfs2_meta_header) + - offset * sizeof(struct gfs2_unlinked_tag)); - mutex_unlock(&sdp->sd_unlinked_mutex); - - out: - brelse(bh); - - return error; -} - -static void ul_hash(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - spin_lock(&sdp->sd_unlinked_spin); - list_add(&ul->ul_list, &sdp->sd_unlinked_list); - gfs2_assert(sdp, ul->ul_count); - ul->ul_count++; - atomic_inc(&sdp->sd_unlinked_count); - spin_unlock(&sdp->sd_unlinked_spin); -} - -static void ul_unhash(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - spin_lock(&sdp->sd_unlinked_spin); - list_del_init(&ul->ul_list); - gfs2_assert(sdp, ul->ul_count > 1); - ul->ul_count--; - gfs2_assert_warn(sdp, atomic_read(&sdp->sd_unlinked_count) > 0); - atomic_dec(&sdp->sd_unlinked_count); - spin_unlock(&sdp->sd_unlinked_spin); -} - -static struct gfs2_unlinked *ul_fish(struct gfs2_sbd *sdp) -{ - struct list_head *head; - struct gfs2_unlinked *ul; - int found = 0; - - if (sdp->sd_vfs->s_flags & MS_RDONLY) - return NULL; - - spin_lock(&sdp->sd_unlinked_spin); - - head = &sdp->sd_unlinked_list; - - list_for_each_entry(ul, head, ul_list) { - if (test_bit(ULF_LOCKED, &ul->ul_flags)) - continue; - - list_move_tail(&ul->ul_list, head); - ul->ul_count++; - set_bit(ULF_LOCKED, &ul->ul_flags); - found = 1; - - break; - } - - if (!found) - ul = NULL; - - spin_unlock(&sdp->sd_unlinked_spin); - - return ul; -} - -/** - * enforce_limit - limit the number of inodes waiting to be deallocated - * @sdp: the filesystem - * - * Returns: errno - */ - -static void enforce_limit(struct gfs2_sbd *sdp) -{ - unsigned int tries = 0, min = 0; - int error; - - if (atomic_read(&sdp->sd_unlinked_count) < - gfs2_tune_get(sdp, gt_ilimit)) - return; - - tries = gfs2_tune_get(sdp, gt_ilimit_tries); - min = gfs2_tune_get(sdp, gt_ilimit_min); - - while (tries--) { - struct gfs2_unlinked *ul = ul_fish(sdp); - if (!ul) - break; - error = gfs2_inode_dealloc(sdp, ul); - gfs2_unlinked_put(sdp, ul); - - if (!error) { - if (!--min) - break; - } else if (error != 1) - break; - } -} - -static struct gfs2_unlinked *ul_alloc(struct gfs2_sbd *sdp) -{ - struct gfs2_unlinked *ul; - - ul = kzalloc(sizeof(struct gfs2_unlinked), GFP_KERNEL); - if (ul) { - INIT_LIST_HEAD(&ul->ul_list); - ul->ul_count = 1; - set_bit(ULF_LOCKED, &ul->ul_flags); - } - - return ul; -} - -int gfs2_unlinked_get(struct gfs2_sbd *sdp, struct gfs2_unlinked **ul) -{ - unsigned int c, o = 0, b; - unsigned char byte = 0; - - enforce_limit(sdp); - - *ul = ul_alloc(sdp); - if (!*ul) - return -ENOMEM; - - spin_lock(&sdp->sd_unlinked_spin); - - for (c = 0; c < sdp->sd_unlinked_chunks; c++) - for (o = 0; o < PAGE_SIZE; o++) { - byte = sdp->sd_unlinked_bitmap[c][o]; - if (byte != 0xFF) - goto found; - } - - goto fail; - -found: - for (b = 0; b < 8; b++) - if (!(byte & (1 << b))) - break; - (*ul)->ul_slot = c * (8 * PAGE_SIZE) + o * 8 + b; - - if ((*ul)->ul_slot >= sdp->sd_unlinked_slots) - goto fail; - - sdp->sd_unlinked_bitmap[c][o] |= 1 << b; - - spin_unlock(&sdp->sd_unlinked_spin); - - return 0; - -fail: - spin_unlock(&sdp->sd_unlinked_spin); - kfree(*ul); - return -ENOSPC; -} - -void gfs2_unlinked_put(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - gfs2_assert_warn(sdp, test_and_clear_bit(ULF_LOCKED, &ul->ul_flags)); - - spin_lock(&sdp->sd_unlinked_spin); - gfs2_assert(sdp, ul->ul_count); - ul->ul_count--; - if (!ul->ul_count) { - gfs2_icbit_munge(sdp, sdp->sd_unlinked_bitmap, ul->ul_slot, 0); - spin_unlock(&sdp->sd_unlinked_spin); - kfree(ul); - } else - spin_unlock(&sdp->sd_unlinked_spin); -} - -int gfs2_unlinked_ondisk_add(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - int error; - - gfs2_assert_warn(sdp, test_bit(ULF_LOCKED, &ul->ul_flags)); - gfs2_assert_warn(sdp, list_empty(&ul->ul_list)); - - error = munge_ondisk(sdp, ul->ul_slot, &ul->ul_ut); - if (!error) - ul_hash(sdp, ul); - - return error; -} - -int gfs2_unlinked_ondisk_munge(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - int error; - - gfs2_assert_warn(sdp, test_bit(ULF_LOCKED, &ul->ul_flags)); - gfs2_assert_warn(sdp, !list_empty(&ul->ul_list)); - - error = munge_ondisk(sdp, ul->ul_slot, &ul->ul_ut); - - return error; -} - -int gfs2_unlinked_ondisk_rm(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - struct gfs2_unlinked_tag ut; - int error; - - gfs2_assert_warn(sdp, test_bit(ULF_LOCKED, &ul->ul_flags)); - gfs2_assert_warn(sdp, !list_empty(&ul->ul_list)); - - memset(&ut, 0, sizeof(struct gfs2_unlinked_tag)); - - error = munge_ondisk(sdp, ul->ul_slot, &ut); - if (error) - return error; - - ul_unhash(sdp, ul); - - return 0; -} - -/** - * gfs2_unlinked_dealloc - Go through the list of inodes to be deallocated - * @sdp: the filesystem - * - * Returns: errno - */ - -int gfs2_unlinked_dealloc(struct gfs2_sbd *sdp) -{ - unsigned int hits, strikes; - int error; - - for (;;) { - hits = 0; - strikes = 0; - - for (;;) { - struct gfs2_unlinked *ul = ul_fish(sdp); - if (!ul) - return 0; - error = gfs2_inode_dealloc(sdp, ul); - gfs2_unlinked_put(sdp, ul); - - if (!error) { - hits++; - if (strikes) - strikes--; - } else if (error == 1) { - strikes++; - if (strikes >= - atomic_read(&sdp->sd_unlinked_count)) { - error = 0; - break; - } - } else - return error; - } - - if (!hits || kthread_should_stop()) - break; - - cond_resched(); - } - - return 0; -} - -int gfs2_unlinked_init(struct gfs2_sbd *sdp) -{ - struct gfs2_inode *ip = sdp->sd_ut_inode->u.generic_ip; - unsigned int blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; - unsigned int x, slot = 0; - unsigned int found = 0; - uint64_t dblock; - uint32_t extlen = 0; - int error; - - if (!ip->i_di.di_size || - ip->i_di.di_size > (64 << 20) || - ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1)) { - gfs2_consist_inode(ip); - return -EIO; - } - sdp->sd_unlinked_slots = blocks * sdp->sd_ut_per_block; - sdp->sd_unlinked_chunks = DIV_ROUND_UP(sdp->sd_unlinked_slots, - 8 * PAGE_SIZE); - - error = -ENOMEM; - - sdp->sd_unlinked_bitmap = kcalloc(sdp->sd_unlinked_chunks, - sizeof(unsigned char *), - GFP_KERNEL); - if (!sdp->sd_unlinked_bitmap) - return error; - - for (x = 0; x < sdp->sd_unlinked_chunks; x++) { - sdp->sd_unlinked_bitmap[x] = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!sdp->sd_unlinked_bitmap[x]) - goto fail; - } - - for (x = 0; x < blocks; x++) { - struct buffer_head *bh; - unsigned int y; - - if (!extlen) { - int new = 0; - error = gfs2_extent_map(ip->i_vnode, x, &new, &dblock, &extlen); - if (error) - goto fail; - } - gfs2_meta_ra(ip->i_gl, dblock, extlen); - error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, - &bh); - if (error) - goto fail; - error = -EIO; - if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_UT)) { - brelse(bh); - goto fail; - } - - for (y = 0; - y < sdp->sd_ut_per_block && slot < sdp->sd_unlinked_slots; - y++, slot++) { - struct gfs2_unlinked_tag ut; - struct gfs2_unlinked *ul; - - gfs2_unlinked_tag_in(&ut, bh->b_data + - sizeof(struct gfs2_meta_header) + - y * sizeof(struct gfs2_unlinked_tag)); - if (!ut.ut_inum.no_addr) - continue; - - error = -ENOMEM; - ul = ul_alloc(sdp); - if (!ul) { - brelse(bh); - goto fail; - } - ul->ul_ut = ut; - ul->ul_slot = slot; - - spin_lock(&sdp->sd_unlinked_spin); - gfs2_icbit_munge(sdp, sdp->sd_unlinked_bitmap, slot, 1); - spin_unlock(&sdp->sd_unlinked_spin); - ul_hash(sdp, ul); - - gfs2_unlinked_put(sdp, ul); - found++; - } - - brelse(bh); - dblock++; - extlen--; - } - - if (found) - fs_info(sdp, "found %u unlinked inodes\n", found); - - return 0; - -fail: - gfs2_unlinked_cleanup(sdp); - return error; -} - -/** - * gfs2_unlinked_cleanup - get rid of any extra struct gfs2_unlinked structures - * @sdp: the filesystem - * - */ - -void gfs2_unlinked_cleanup(struct gfs2_sbd *sdp) -{ - struct list_head *head = &sdp->sd_unlinked_list; - struct gfs2_unlinked *ul; - unsigned int x; - - spin_lock(&sdp->sd_unlinked_spin); - while (!list_empty(head)) { - ul = list_entry(head->next, struct gfs2_unlinked, ul_list); - - if (ul->ul_count > 1) { - list_move_tail(&ul->ul_list, head); - spin_unlock(&sdp->sd_unlinked_spin); - schedule(); - spin_lock(&sdp->sd_unlinked_spin); - continue; - } - - list_del_init(&ul->ul_list); - atomic_dec(&sdp->sd_unlinked_count); - - gfs2_assert_warn(sdp, ul->ul_count == 1); - gfs2_assert_warn(sdp, !test_bit(ULF_LOCKED, &ul->ul_flags)); - kfree(ul); - } - spin_unlock(&sdp->sd_unlinked_spin); - - gfs2_assert_warn(sdp, !atomic_read(&sdp->sd_unlinked_count)); - - if (sdp->sd_unlinked_bitmap) { - for (x = 0; x < sdp->sd_unlinked_chunks; x++) - kfree(sdp->sd_unlinked_bitmap[x]); - kfree(sdp->sd_unlinked_bitmap); - } -} - diff --git a/fs/gfs2/unlinked.h b/fs/gfs2/unlinked.h deleted file mode 100644 index 159cf5ffe47e..000000000000 --- a/fs/gfs2/unlinked.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License v.2. - */ - -#ifndef __UNLINKED_DOT_H__ -#define __UNLINKED_DOT_H__ - -int gfs2_unlinked_get(struct gfs2_sbd *sdp, struct gfs2_unlinked **ul); -void gfs2_unlinked_put(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); - -int gfs2_unlinked_ondisk_add(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); -int gfs2_unlinked_ondisk_munge(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); -int gfs2_unlinked_ondisk_rm(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul); - -int gfs2_unlinked_dealloc(struct gfs2_sbd *sdp); - -int gfs2_unlinked_init(struct gfs2_sbd *sdp); -void gfs2_unlinked_cleanup(struct gfs2_sbd *sdp); - -#endif /* __UNLINKED_DOT_H__ */ diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 88974e9824f7..39e67b1ec70a 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -109,7 +109,7 @@ int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide, const char *function, int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide, const char *function, char *file, unsigned int line) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); int rv; rv = gfs2_lm_withdraw(sdp, "GFS2: fsid=%s: fatal: filesystem consistency error\n" diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 3893aac4e3ae..1181da831939 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -1,11 +1,11 @@ /* -* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. -* -* This copyrighted material is made available to anyone wishing to use, -* modify, copy, or redistribute it subject to the terms and conditions -* of the GNU General Public License v.2. -*/ + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + */ #ifndef __GFS2_ONDISK_DOT_H__ #define __GFS2_ONDISK_DOT_H__ @@ -36,7 +36,6 @@ #define GFS2_FORMAT_LB 1000 #define GFS2_FORMAT_EA 1600 #define GFS2_FORMAT_ED 1700 -#define GFS2_FORMAT_UT 1300 #define GFS2_FORMAT_QC 1400 /* These are format numbers for entities contained in files */ #define GFS2_FORMAT_RI 1100 @@ -80,7 +79,6 @@ static inline int gfs2_inum_equal(const struct gfs2_inum *ino1, #define GFS2_METATYPE_LB 12 #define GFS2_METATYPE_EA 10 #define GFS2_METATYPE_ED 11 -#define GFS2_METATYPE_UT 13 #define GFS2_METATYPE_QC 14 struct gfs2_meta_header { @@ -158,7 +156,7 @@ struct gfs2_rindex { #define GFS2_BLKST_FREE 0 #define GFS2_BLKST_USED 1 -#define GFS2_BLKST_INVALID 2 +#define GFS2_BLKST_UNLINKED 2 #define GFS2_BLKST_DINODE 3 #define GFS2_RGF_JOURNAL 0x00000001 @@ -396,20 +394,6 @@ struct gfs2_statfs_change { __be64 sc_dinodes; }; -/* - * Unlinked Tag - * Describes an allocated inode that isn't linked into - * the directory tree and might need to be deallocated. - */ - -#define GFS2_UTF_UNINIT 0x00000001 - -struct gfs2_unlinked_tag { - struct gfs2_inum ut_inum; - __be32 ut_flags; /* GFS2_UTF_... */ - __u32 __pad; -}; - /* * Quota change * Describes an allocation change for a particular @@ -445,8 +429,6 @@ extern void gfs2_inum_range_in(struct gfs2_inum_range *ir, char *buf); extern void gfs2_inum_range_out(struct gfs2_inum_range *ir, char *buf); extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, char *buf); extern void gfs2_statfs_change_out(struct gfs2_statfs_change *sc, char *buf); -extern void gfs2_unlinked_tag_in(struct gfs2_unlinked_tag *ut, char *buf); -extern void gfs2_unlinked_tag_out(struct gfs2_unlinked_tag *ut, char *buf); extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf); /* Printing functions */ -- cgit v1.2.3 From c37bb26654bb8981ea237076e333eb37d4aa2dc6 Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 20 Jun 2006 14:55:55 -0400 Subject: intelfb: add preliminary i2c support [01/07] i2c: add intelfb bit algorithm id Adds the intelfb bit algorithm id to i2c-id.h. Signed-off-by: Dennis Munsie --- include/linux/i2c-id.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index c8b81f419fd8..cce6074dd754 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -189,6 +189,7 @@ #define I2C_HW_B_RADEON 0x01001e /* radeon framebuffer driver */ #define I2C_HW_B_EM28XX 0x01001f /* em28xx video capture cards */ #define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */ +#define I2C_HW_B_INTELFB 0x010021 /* intel framebuffer driver */ /* --- PCF 8584 based algorithms */ #define I2C_HW_P_LP 0x020000 /* Parallel port interface */ -- cgit v1.2.3 From 3864caea2ed2b43bfc92e5cfbe001abe3f002a06 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 5 Jul 2006 11:17:36 -0400 Subject: [GFS2] Kbuild update to install correct headers Now that the headers_instakll target is in Linus' kernel, this update ensures that the correct GFS2/DLM headers are installed. Signed-off-by: Steven Whitehouse --- include/linux/Kbuild | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 2b8a7d68fae3..2121cde187d8 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -8,7 +8,7 @@ header-y += affs_fs.h affs_hardblocks.h aio_abi.h a.out.h arcfb.h \ atmppp.h atmsap.h atmsvc.h atm_zatm.h auto_fs4.h auxvec.h \ awe_voice.h ax25.h b1lli.h baycom.h bfs_fs.h blkpg.h \ bpqether.h cdk.h chio.h coda_psdev.h coff.h comstats.h \ - consolemap.h cycx_cfm.h dm-ioctl.h dn.h dqblk_v1.h \ + consolemap.h cycx_cfm.h dlm_device.h dm-ioctl.h dn.h dqblk_v1.h \ dqblk_v2.h dqblk_xfs.h efs_fs_sb.h elf-fdpic.h elf.h elf-em.h \ fadvise.h fd.h fdreg.h ftape-header-segment.h ftape-vendors.h \ fuse.h futex.h genetlink.h gen_stats.h gigaset_dev.h hdsmart.h \ @@ -18,28 +18,29 @@ header-y += affs_fs.h affs_hardblocks.h aio_abi.h a.out.h arcfb.h \ if_plip.h if_ppp.h if_slip.h if_strip.h if_tunnel.h in6.h \ in_route.h ioctl.h ip.h ipmi_msgdefs.h ip_mp_alg.h ipsec.h \ ipx.h irda.h isdn_divertif.h iso_fs.h ite_gpio.h ixjuser.h \ - jffs2.h keyctl.h limits.h major.h matroxfb.h meye.h minix_fs.h \ - mmtimer.h mqueue.h mtio.h ncp_no.h netfilter_arp.h netrom.h \ - nfs2.h nfs4_mount.h nfs_mount.h openprom_fs.h param.h \ - pci_ids.h pci_regs.h personality.h pfkeyv2.h pg.h pkt_cls.h \ - pkt_sched.h posix_types.h ppdev.h prctl.h ps2esdi.h qic117.h \ - qnxtypes.h quotaio_v1.h quotaio_v2.h radeonfb.h raw.h \ - resource.h rose.h sctp.h smbno.h snmp.h sockios.h som.h \ - sound.h stddef.h synclink.h telephony.h termios.h ticable.h \ - times.h tiocl.h tipc.h toshiba.h ultrasound.h un.h utime.h \ - utsname.h video_decoder.h video_encoder.h videotext.h vt.h \ - wavefront.h wireless.h xattr.h x25.h zorro_ids.h + jffs2.h keyctl.h limits.h lock_dlm_plock.h major.h matroxfb.h \ + meye.h minix_fs.h mmtimer.h mqueue.h mtio.h ncp_no.h \ + netfilter_arp.h netrom.h nfs2.h nfs4_mount.h nfs_mount.h \ + openprom_fs.h param.h pci_ids.h pci_regs.h personality.h \ + pfkeyv2.h pg.h pkt_cls.h pkt_sched.h posix_types.h ppdev.h \ + prctl.h ps2esdi.h qic117.h qnxtypes.h quotaio_v1.h quotaio_v2.h \ + radeonfb.h raw.h resource.h rose.h sctp.h smbno.h snmp.h \ + sockios.h som.h sound.h stddef.h synclink.h telephony.h \ + termios.h ticable.h times.h tiocl.h tipc.h toshiba.h \ + ultrasound.h un.h utime.h utsname.h video_decoder.h \ + video_encoder.h videotext.h vt.h wavefront.h wireless.h xattr.h \ + x25.h zorro_ids.h unifdef-y += acct.h adb.h adfs_fs.h agpgart.h apm_bios.h atalk.h \ atmarp.h atmdev.h atm.h atm_tcp.h audit.h auto_fs.h binfmts.h \ capability.h capi.h cciss_ioctl.h cdrom.h cm4000_cs.h \ cn_proc.h coda.h connector.h cramfs_fs.h cuda.h cyclades.h \ - dccp.h dirent.h divert.h elfcore.h errno.h errqueue.h \ + dccp.h dirent.h divert.h dlm.h elfcore.h errno.h errqueue.h \ ethtool.h eventpoll.h ext2_fs.h ext3_fs.h fb.h fcntl.h \ filter.h flat.h fs.h ftape.h gameport.h generic_serial.h \ - genhd.h hayesesp.h hdlcdrv.h hdlc.h hdreg.h hiddev.h hpet.h \ - i2c.h i2o-dev.h icmpv6.h if_bridge.h if_ec.h \ - if_eql.h if_ether.h if_frad.h if_ltalk.h if_pppox.h \ + genhd.h gfs2_ondisk.h hayesesp.h hdlcdrv.h hdlc.h hdreg.h \ + hiddev.h hpet.h i2c.h i2o-dev.h icmpv6.h iflags.h if_bridge.h \ + if_ec.h if_eql.h if_ether.h if_frad.h if_ltalk.h if_pppox.h \ if_shaper.h if_tr.h if_tun.h if_vlan.h if_wanpipe.h igmp.h \ inet_diag.h in.h inotify.h input.h ipc.h ipmi.h ipv6.h \ ipv6_route.h isdn.h isdnif.h isdn_ppp.h isicom.h jbd.h \ -- cgit v1.2.3 From 4340fe62531f7d1dafb6f5359ffe0378bdb0db80 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 11 Jul 2006 09:46:33 -0400 Subject: [GFS2] Add generation number This adds a generation number for the eventual use of NFS to the ondisk inode. Its backward compatible with the current code since it doesn't really matter what the generation number is to start with, and indeed since its set to zero, due to it being taken from padding in both the inode and rgrp header, it should be fine. The eventual plan is to use this rather than no_formal_ino in the NFS filehandles. At that point no_formal_ino will be unused. At the same time we also add a releasepages call back to the "normal" address space for gfs2 inodes. Also I've removed a one-linrer function thats not required any more. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 46 ++++++++---------- fs/gfs2/meta_io.c | 112 +------------------------------------------- fs/gfs2/ondisk.c | 6 ++- fs/gfs2/ops_address.c | 111 +++++++++++++++++++++++++++++++++++++++++++ fs/gfs2/ops_address.h | 1 + fs/gfs2/ops_file.c | 2 +- fs/gfs2/rgrp.c | 12 ++--- fs/gfs2/rgrp.h | 6 +-- include/linux/gfs2_ondisk.h | 6 ++- 9 files changed, 153 insertions(+), 149 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index f4c48395208a..22ca3b5ddaea 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -38,15 +38,17 @@ #include "util.h" /** - * inode_attr_in - Copy attributes from the dinode into the VFS inode + * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode * @ip: The GFS2 inode (with embedded disk inode data) * @inode: The Linux VFS inode * */ -static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode) +void gfs2_inode_attr_in(struct gfs2_inode *ip) { - inode->i_ino = ip->i_num.no_formal_ino; + struct inode *inode = &ip->i_inode; + + inode->i_ino = ip->i_num.no_addr; switch (ip->i_di.di_mode & S_IFMT) { case S_IFBLK: @@ -84,18 +86,6 @@ static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode) inode->i_flags &= ~S_APPEND; } -/** - * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode - * @ip: The GFS2 inode (with embedded disk inode data) - * - */ - -void gfs2_inode_attr_in(struct gfs2_inode *ip) -{ - struct inode *inode = &ip->i_inode; - inode_attr_in(ip, inode); -} - /** * gfs2_inode_attr_out - Copy attributes from VFS inode into the dinode * @ip: The GFS2 inode @@ -621,7 +611,8 @@ static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, *gid = current->fsgid; } -static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum) +static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum, + u64 *generation) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); int error; @@ -637,14 +628,14 @@ static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum) if (error) goto out_ipreserv; - inum->no_addr = gfs2_alloc_di(dip); + inum->no_addr = gfs2_alloc_di(dip, generation); gfs2_trans_end(sdp); - out_ipreserv: +out_ipreserv: gfs2_inplace_release(dip); - out: +out: gfs2_alloc_put(dip); return error; @@ -662,8 +653,9 @@ static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum) */ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - struct gfs2_inum *inum, unsigned int mode, - unsigned int uid, unsigned int gid) + const struct gfs2_inum *inum, unsigned int mode, + unsigned int uid, unsigned int gid, + const u64 *generation) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_dinode *di; @@ -686,7 +678,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds()); di->di_major = di->di_minor = cpu_to_be32(0); di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); - di->__pad[0] = di->__pad[1] = 0; + di->di_generation = cpu_to_be64(*generation); di->di_flags = cpu_to_be32(0); if (S_ISREG(mode)) { @@ -717,7 +709,8 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, } static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - unsigned int mode, struct gfs2_inum *inum) + unsigned int mode, const struct gfs2_inum *inum, + const u64 *generation) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); unsigned int uid, gid; @@ -738,7 +731,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, if (error) goto out_quota; - init_dinode(dip, gl, inum, mode, uid, gid); + init_dinode(dip, gl, inum, mode, uid, gid, generation); gfs2_quota_change(dip, +1, uid, gid); gfs2_trans_end(sdp); @@ -844,6 +837,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_inum inum; int error; + u64 generation; if (!name->len || name->len > GFS2_FNAMESIZE) return ERR_PTR(-ENAMETOOLONG); @@ -861,7 +855,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, if (error) goto fail_gunlock; - error = alloc_dinode(dip, &inum); + error = alloc_dinode(dip, &inum, &generation); if (error) goto fail_gunlock; @@ -893,7 +887,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, goto fail_gunlock; } - error = make_dinode(dip, ghs[1].gh_gl, mode, &inum); + error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation); if (error) goto fail_gunlock2; diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index ddcd4dc1081d..cad44fd70d67 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -31,6 +31,7 @@ #include "rgrp.h" #include "trans.h" #include "util.h" +#include "ops_address.h" #define buffer_busy(bh) \ ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned))) @@ -50,118 +51,9 @@ static int gfs2_aspace_writepage(struct page *page, return block_write_full_page(page, aspace_get_block, wbc); } -/** - * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. - * @bh: the buffer we're stuck on - * - */ - -static void stuck_releasepage(struct buffer_head *bh) -{ - struct inode *inode = bh->b_page->mapping->host; - struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; - struct gfs2_bufdata *bd = bh->b_private; - struct gfs2_glock *gl; - - fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); - fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", - (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count)); - fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); - fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL"); - - if (!bd) - return; - - gl = bd->bd_gl; - - fs_warn(sdp, "gl = (%u, %llu)\n", - gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); - - fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", - (list_empty(&bd->bd_list_tr)) ? "no" : "yes", - (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); - - if (gl->gl_ops == &gfs2_inode_glops) { - struct gfs2_inode *ip = gl->gl_object; - unsigned int x; - - if (!ip) - return; - - fs_warn(sdp, "ip = %llu %llu\n", - (unsigned long long)ip->i_num.no_formal_ino, - (unsigned long long)ip->i_num.no_addr); - - for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) - fs_warn(sdp, "ip->i_cache[%u] = %s\n", - x, (ip->i_cache[x]) ? "!NULL" : "NULL"); - } -} - -/** - * gfs2_aspace_releasepage - free the metadata associated with a page - * @page: the page that's being released - * @gfp_mask: passed from Linux VFS, ignored by us - * - * Call try_to_free_buffers() if the buffers in this page can be - * released. - * - * Returns: 0 - */ - -static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask) -{ - struct inode *aspace = page->mapping->host; - struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; - struct buffer_head *bh, *head; - struct gfs2_bufdata *bd; - unsigned long t; - - if (!page_has_buffers(page)) - goto out; - - head = bh = page_buffers(page); - do { - t = jiffies; - - while (atomic_read(&bh->b_count)) { - if (atomic_read(&aspace->i_writecount)) { - if (time_after_eq(jiffies, t + - gfs2_tune_get(sdp, gt_stall_secs) * HZ)) { - stuck_releasepage(bh); - t = jiffies; - } - - yield(); - continue; - } - - return 0; - } - - gfs2_assert_warn(sdp, !buffer_pinned(bh)); - - bd = bh->b_private; - if (bd) { - gfs2_assert_warn(sdp, bd->bd_bh == bh); - gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); - gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); - gfs2_assert_warn(sdp, !bd->bd_ail); - kmem_cache_free(gfs2_bufdata_cachep, bd); - bh->b_private = NULL; - } - - bh = bh->b_this_page; - } - while (bh != head); - - out: - return try_to_free_buffers(page); -} - static const struct address_space_operations aspace_aops = { .writepage = gfs2_aspace_writepage, - .releasepage = gfs2_aspace_releasepage, + .releasepage = gfs2_releasepage, }; /** diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 09154ad7b270..39c7f0345fc6 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -128,6 +128,7 @@ void gfs2_rgrp_in(struct gfs2_rgrp *rg, char *buf) rg->rg_flags = be32_to_cpu(str->rg_flags); rg->rg_free = be32_to_cpu(str->rg_free); rg->rg_dinodes = be32_to_cpu(str->rg_dinodes); + rg->rg_igeneration = be64_to_cpu(str->rg_igeneration); } void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf) @@ -138,7 +139,8 @@ void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf) str->rg_flags = cpu_to_be32(rg->rg_flags); str->rg_free = cpu_to_be32(rg->rg_free); str->rg_dinodes = cpu_to_be32(rg->rg_dinodes); - + str->__pad = cpu_to_be32(0); + str->rg_igeneration = cpu_to_be64(rg->rg_igeneration); memset(&str->rg_reserved, 0, sizeof(str->rg_reserved)); } @@ -172,6 +174,7 @@ void gfs2_dinode_in(struct gfs2_dinode *di, char *buf) di->di_goal_meta = be64_to_cpu(str->di_goal_meta); di->di_goal_data = be64_to_cpu(str->di_goal_data); + di->di_generation = be64_to_cpu(str->di_generation); di->di_flags = be32_to_cpu(str->di_flags); di->di_payload_format = be32_to_cpu(str->di_payload_format); @@ -205,6 +208,7 @@ void gfs2_dinode_out(struct gfs2_dinode *di, char *buf) str->di_goal_meta = cpu_to_be64(di->di_goal_meta); str->di_goal_data = cpu_to_be64(di->di_goal_data); + str->di_generation = cpu_to_be64(di->di_generation); str->di_flags = cpu_to_be32(di->di_flags); str->di_payload_format = cpu_to_be32(di->di_payload_format); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 2c4ec5cf21ff..031270ad55e2 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -33,6 +33,7 @@ #include "rgrp.h" #include "ops_file.h" #include "util.h" +#include "glops.h" /** * gfs2_get_block - Fills in a buffer head with details about a block @@ -659,6 +660,115 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, return ret; } +/** + * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. + * @bh: the buffer we're stuck on + * + */ + +static void stuck_releasepage(struct buffer_head *bh) +{ + struct inode *inode = bh->b_page->mapping->host; + struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; + struct gfs2_bufdata *bd = bh->b_private; + struct gfs2_glock *gl; + + fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); + fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", + (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count)); + fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); + fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL"); + + if (!bd) + return; + + gl = bd->bd_gl; + + fs_warn(sdp, "gl = (%u, %llu)\n", + gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); + + fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", + (list_empty(&bd->bd_list_tr)) ? "no" : "yes", + (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); + + if (gl->gl_ops == &gfs2_inode_glops) { + struct gfs2_inode *ip = gl->gl_object; + unsigned int x; + + if (!ip) + return; + + fs_warn(sdp, "ip = %llu %llu\n", + (unsigned long long)ip->i_num.no_formal_ino, + (unsigned long long)ip->i_num.no_addr); + + for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) + fs_warn(sdp, "ip->i_cache[%u] = %s\n", + x, (ip->i_cache[x]) ? "!NULL" : "NULL"); + } +} + +/** + * gfs2_aspace_releasepage - free the metadata associated with a page + * @page: the page that's being released + * @gfp_mask: passed from Linux VFS, ignored by us + * + * Call try_to_free_buffers() if the buffers in this page can be + * released. + * + * Returns: 0 + */ + +int gfs2_releasepage(struct page *page, gfp_t gfp_mask) +{ + struct inode *aspace = page->mapping->host; + struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; + struct buffer_head *bh, *head; + struct gfs2_bufdata *bd; + unsigned long t; + + if (!page_has_buffers(page)) + goto out; + + head = bh = page_buffers(page); + do { + t = jiffies; + + while (atomic_read(&bh->b_count)) { + if (atomic_read(&aspace->i_writecount)) { + if (time_after_eq(jiffies, t + + gfs2_tune_get(sdp, gt_stall_secs) * HZ)) { + stuck_releasepage(bh); + t = jiffies; + } + + yield(); + continue; + } + + return 0; + } + + gfs2_assert_warn(sdp, !buffer_pinned(bh)); + + bd = bh->b_private; + if (bd) { + gfs2_assert_warn(sdp, bd->bd_bh == bh); + gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); + gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); + gfs2_assert_warn(sdp, !bd->bd_ail); + kmem_cache_free(gfs2_bufdata_cachep, bd); + bh->b_private = NULL; + } + + bh = bh->b_this_page; + } + while (bh != head); + + out: + return try_to_free_buffers(page); +} + const struct address_space_operations gfs2_file_aops = { .writepage = gfs2_writepage, .readpage = gfs2_readpage, @@ -668,6 +778,7 @@ const struct address_space_operations gfs2_file_aops = { .commit_write = gfs2_commit_write, .bmap = gfs2_bmap, .invalidatepage = gfs2_invalidatepage, + .releasepage = gfs2_releasepage, .direct_IO = gfs2_direct_IO, }; diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h index a7ef3bf36f3e..dfc3dda6de11 100644 --- a/fs/gfs2/ops_address.h +++ b/fs/gfs2/ops_address.h @@ -13,5 +13,6 @@ extern const struct address_space_operations gfs2_file_aops; extern int gfs2_get_block(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create); +extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask); #endif /* __OPS_ADDRESS_DOT_H__ */ diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index c8e2c98700a7..26f1d3249b0f 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -333,7 +333,7 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, int error; error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset, - inum->no_formal_ino, type); + inum->no_addr, type); if (error) return 1; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 14c1f88bfb5d..65eea0b88bf7 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1205,7 +1205,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, uint64_t bstart, * Returns: the allocated block */ -uint64_t gfs2_alloc_data(struct gfs2_inode *ip) +u64 gfs2_alloc_data(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; @@ -1249,7 +1249,7 @@ uint64_t gfs2_alloc_data(struct gfs2_inode *ip) * Returns: the allocated block */ -uint64_t gfs2_alloc_meta(struct gfs2_inode *ip) +u64 gfs2_alloc_meta(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; @@ -1294,13 +1294,13 @@ uint64_t gfs2_alloc_meta(struct gfs2_inode *ip) * Returns: the block allocated */ -uint64_t gfs2_alloc_di(struct gfs2_inode *dip) +u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_alloc *al = &dip->i_alloc; struct gfs2_rgrpd *rgd = al->al_rgd; - uint32_t blk; - uint64_t block; + u32 blk; + u64 block; blk = rgblk_search(rgd, rgd->rd_last_alloc_meta, GFS2_BLKST_FREE, GFS2_BLKST_DINODE); @@ -1312,7 +1312,7 @@ uint64_t gfs2_alloc_di(struct gfs2_inode *dip) gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); rgd->rd_rg.rg_free--; rgd->rd_rg.rg_dinodes++; - + *generation = rgd->rd_rg.rg_igeneration++; gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 9c42d2252ddd..14600944d184 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -37,9 +37,9 @@ void gfs2_inplace_release(struct gfs2_inode *ip); unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, uint64_t block); -uint64_t gfs2_alloc_data(struct gfs2_inode *ip); -uint64_t gfs2_alloc_meta(struct gfs2_inode *ip); -uint64_t gfs2_alloc_di(struct gfs2_inode *ip); +u64 gfs2_alloc_data(struct gfs2_inode *ip); +u64 gfs2_alloc_meta(struct gfs2_inode *ip); +u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation); void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); void gfs2_free_meta(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 1181da831939..3ebd8743ce8c 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -170,8 +170,10 @@ struct gfs2_rgrp { __be32 rg_flags; __be32 rg_free; __be32 rg_dinodes; + __be32 __pad; + __be64 rg_igeneration; - __u8 rg_reserved[92]; /* Several fields from gfs1 now reserved */ + __u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */ }; /* @@ -248,7 +250,7 @@ struct gfs2_dinode { */ __be64 di_goal_meta; /* rgrp to alloc from next */ __be64 di_goal_data; /* data block goal */ - __u32 __pad[2]; + __be64 di_generation; /* generation number for NFS */ __be32 di_flags; /* GFS2_DIF_... */ __be32 di_payload_format; /* GFS2_FORMAT_... */ -- cgit v1.2.3 From 509ca1a9383601fdc5612d3d3ba5b981f6eb6c8b Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 19 Jul 2006 01:40:22 -0400 Subject: Input: implement new force feedback interface Implement a new force feedback interface, in which all non-driver-specific operations are separated to a common module. This includes handling effect type validations, locking, etc. The effects are now file descriptor specific instead of the previous strange half-process half-fd specific behaviour. The effect memory of devices is not emptied if the root user opens and closes the device while another user is using effects. This is a minor change and most likely no force feedback aware programs are affected by this negatively. Otherwise the userspace interface is left unaltered. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/Makefile | 2 +- drivers/input/evdev.c | 32 ++--- drivers/input/ff-core.c | 367 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/input/input.c | 6 + include/linux/input.h | 61 ++++++++ 5 files changed, 450 insertions(+), 18 deletions(-) create mode 100644 drivers/input/ff-core.c (limited to 'include/linux') diff --git a/drivers/input/Makefile b/drivers/input/Makefile index e539a309df8a..abdc9d435705 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -5,7 +5,7 @@ # Each configuration option enables a list of files. obj-$(CONFIG_INPUT) += input-core.o -input-core-objs := input.o +input-core-objs := input.o ff-core.o obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 4bf48188cc91..12c7ab876c34 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -391,8 +391,10 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, struct evdev *evdev = list->evdev; struct input_dev *dev = evdev->handle.dev; struct input_absinfo abs; + struct ff_effect effect; int __user *ip = (int __user *)p; int i, t, u, v; + int error; if (!evdev->exist) return -ENODEV; @@ -460,27 +462,22 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, return 0; case EVIOCSFF: - if (dev->upload_effect) { - struct ff_effect effect; - int err; - - if (copy_from_user(&effect, p, sizeof(effect))) - return -EFAULT; - err = dev->upload_effect(dev, &effect); - if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) - return -EFAULT; - return err; - } else - return -ENOSYS; + if (copy_from_user(&effect, p, sizeof(effect))) + return -EFAULT; - case EVIOCRMFF: - if (!dev->erase_effect) - return -ENOSYS; + error = input_ff_upload(dev, &effect, file); - return dev->erase_effect(dev, (int)(unsigned long) p); + if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) + return -EFAULT; + + return error; + + case EVIOCRMFF: + return input_ff_erase(dev, (int)(unsigned long) p, file); case EVIOCGEFFECTS: - if (put_user(dev->ff_effects_max, ip)) + i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0; + if (put_user(i, ip)) return -EFAULT; return 0; @@ -669,6 +666,7 @@ static void evdev_disconnect(struct input_handle *handle) evdev->exist = 0; if (evdev->open) { + input_flush_device(handle, NULL); input_close_device(handle); wake_up_interruptible(&evdev->wait); list_for_each_entry(list, &evdev->list, node) diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c new file mode 100644 index 000000000000..35656cadc914 --- /dev/null +++ b/drivers/input/ff-core.c @@ -0,0 +1,367 @@ +/* + * Force feedback support for Linux input subsystem + * + * Copyright (c) 2006 Anssi Hannula + * Copyright (c) 2006 Dmitry Torokhov + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* #define DEBUG */ + +#define debug(format, arg...) pr_debug("ff-core: " format "\n", ## arg) + +#include +#include +#include + +/* + * Check that the effect_id is a valid effect and whether the user + * is the owner + */ +static int check_effect_access(struct ff_device *ff, int effect_id, + struct file *file) +{ + if (effect_id < 0 || effect_id >= ff->max_effects || + !ff->effect_owners[effect_id]) + return -EINVAL; + + if (file && ff->effect_owners[effect_id] != file) + return -EACCES; + + return 0; +} + +/* + * Checks whether 2 effects can be combined together + */ +static inline int check_effects_compatible(struct ff_effect *e1, + struct ff_effect *e2) +{ + return e1->type == e2->type && + (e1->type != FF_PERIODIC || + e1->u.periodic.waveform == e2->u.periodic.waveform); +} + +/* + * Convert an effect into compatible one + */ +static int compat_effect(struct ff_device *ff, struct ff_effect *effect) +{ + int magnitude; + + switch (effect->type) { + case FF_RUMBLE: + if (!test_bit(FF_PERIODIC, ff->ffbit)) + return -EINVAL; + + /* + * calculate manginude of sine wave as average of rumble's + * 2/3 of strong magnitude and 1/3 of weak magnitude + */ + magnitude = effect->u.rumble.strong_magnitude / 3 + + effect->u.rumble.weak_magnitude / 6; + + effect->type = FF_PERIODIC; + effect->u.periodic.waveform = FF_SINE; + effect->u.periodic.period = 50; + effect->u.periodic.magnitude = max(magnitude, 0x7fff); + effect->u.periodic.offset = 0; + effect->u.periodic.phase = 0; + effect->u.periodic.envelope.attack_length = 0; + effect->u.periodic.envelope.attack_level = 0; + effect->u.periodic.envelope.fade_length = 0; + effect->u.periodic.envelope.fade_level = 0; + + return 0; + + default: + /* Let driver handle conversion */ + return 0; + } +} + +/** + * input_ff_upload() - upload effect into force-feedback device + * @dev: input device + * @effect: effect to be uploaded + * @file: owner of the effect + */ +int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, + struct file *file) +{ + struct ff_device *ff = dev->ff; + struct ff_effect *old; + int ret = 0; + int id; + + if (!test_bit(EV_FF, dev->evbit)) + return -ENOSYS; + + if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX || + !test_bit(effect->type, dev->ffbit)) { + debug("invalid or not supported effect type in upload"); + return -EINVAL; + } + + if (effect->type == FF_PERIODIC && + (effect->u.periodic.waveform < FF_WAVEFORM_MIN || + effect->u.periodic.waveform > FF_WAVEFORM_MAX || + !test_bit(effect->u.periodic.waveform, dev->ffbit))) { + debug("invalid or not supported wave form in upload"); + return -EINVAL; + } + + if (!test_bit(effect->type, ff->ffbit)) { + ret = compat_effect(ff, effect); + if (ret) + return ret; + } + + mutex_lock(&ff->mutex); + + if (effect->id == -1) { + for (id = 0; id < ff->max_effects; id++) + if (!ff->effect_owners[id]) + break; + + if (id >= ff->max_effects) { + ret = -ENOSPC; + goto out; + } + + effect->id = id; + old = NULL; + + } else { + id = effect->id; + + ret = check_effect_access(ff, id, file); + if (ret) + goto out; + + old = &ff->effects[id]; + + if (!check_effects_compatible(effect, old)) { + ret = -EINVAL; + goto out; + } + } + + ret = ff->upload(dev, effect, old); + if (ret) + goto out; + + ff->effects[id] = *effect; + ff->effect_owners[id] = file; + + out: + mutex_unlock(&ff->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(input_ff_upload); + +/* + * Erases the effect if the requester is also the effect owner. The mutex + * should already be locked before calling this function. + */ +static int erase_effect(struct input_dev *dev, int effect_id, + struct file *file) +{ + struct ff_device *ff = dev->ff; + int error; + + error = check_effect_access(ff, effect_id, file); + if (error) + return error; + + ff->playback(dev, effect_id, 0); + + if (ff->erase) { + error = ff->erase(dev, effect_id); + if (error) + return error; + } + + ff->effect_owners[effect_id] = NULL; + + return 0; +} + +/** + * input_ff_erase - erase an effect from device + * @dev: input device to erase effect from + * @effect_id: id of the ffect to be erased + * @file: purported owner of the request + * + * This function erases a force-feedback effect from specified device. + * The effect will only be erased if it was uploaded through the same + * file handle that is requesting erase. + */ +int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file) +{ + struct ff_device *ff = dev->ff; + int ret; + + if (!test_bit(EV_FF, dev->evbit)) + return -ENOSYS; + + mutex_lock(&ff->mutex); + ret = erase_effect(dev, effect_id, file); + mutex_unlock(&ff->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(input_ff_erase); + +/* + * flush_effects - erase all effects owned by a file handle + */ +static int flush_effects(struct input_dev *dev, struct file *file) +{ + struct ff_device *ff = dev->ff; + int i; + + debug("flushing now"); + + mutex_lock(&ff->mutex); + + for (i = 0; i < ff->max_effects; i++) + erase_effect(dev, i, file); + + mutex_unlock(&ff->mutex); + + return 0; +} + +/** + * input_ff_event() - generic handler for force-feedback events + * @dev: input device to send the effect to + * @type: event type (anything but EV_FF is ignored) + * @code: event code + * @value: event value + */ +int input_ff_event(struct input_dev *dev, unsigned int type, + unsigned int code, int value) +{ + struct ff_device *ff = dev->ff; + + if (type != EV_FF) + return 0; + + mutex_lock(&ff->mutex); + + switch (code) { + case FF_GAIN: + if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff) + break; + + ff->set_gain(dev, value); + break; + + case FF_AUTOCENTER: + if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffff) + break; + + ff->set_autocenter(dev, value); + break; + + default: + ff->playback(dev, code, value); + break; + } + + mutex_unlock(&ff->mutex); + return 0; +} +EXPORT_SYMBOL_GPL(input_ff_event); + +/** + * input_ff_create() - create force-feedback device + * @dev: input device supporting force-feedback + * @max_effects: maximum number of effects supported by the device + * + * This function allocates all necessary memory for a force feedback + * portion of an input device and installs all default handlers. + * @dev->ffbit should be already set up before calling this function. + * Once ff device is created you need to setup its upload, erase, + * playback and other handlers before registering input device + */ +int input_ff_create(struct input_dev *dev, int max_effects) +{ + struct ff_device *ff; + int i; + + if (!max_effects) { + printk(KERN_ERR + "ff-core: cannot allocate device without any effects\n"); + return -EINVAL; + } + + ff = kzalloc(sizeof(struct ff_device) + + max_effects * sizeof(struct file *), GFP_KERNEL); + if (!ff) + return -ENOMEM; + + ff->effects = kcalloc(max_effects, sizeof(struct ff_effect), + GFP_KERNEL); + if (!ff->effects) { + kfree(ff); + return -ENOMEM; + } + + ff->max_effects = max_effects; + mutex_init(&ff->mutex); + + dev->ff = ff; + dev->flush = flush_effects; + dev->event = input_ff_event; + set_bit(EV_FF, dev->evbit); + + /* Copy "true" bits into ff device bitmap */ + for (i = 0; i <= FF_MAX; i++) + if (test_bit(i, dev->ffbit)) + set_bit(i, ff->ffbit); + + /* we can emulate RUMBLE with periodic effects */ + if (test_bit(FF_PERIODIC, ff->ffbit)) + set_bit(FF_RUMBLE, dev->ffbit); + + return 0; +} +EXPORT_SYMBOL_GPL(input_ff_create); + +/** + * input_ff_free() - frees force feedback portion of input device + * @dev: input device supporintg force feedback + * + * This function is only needed in error path as input core will + * automatically free force feedback structures when device is + * destroyed. + */ +void input_ff_destroy(struct input_dev *dev) +{ + clear_bit(EV_FF, dev->evbit); + if (dev->ff) { + if (dev->ff->destroy) + dev->ff->destroy(dev->ff); + kfree(dev->ff->private); + kfree(dev->ff); + dev->ff = NULL; + } +} +EXPORT_SYMBOL_GPL(input_ff_destroy); diff --git a/drivers/input/input.c b/drivers/input/input.c index 9cb4b9a54f01..1fc0517e9428 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -176,6 +176,10 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in break; case EV_FF: + + if (value < 0) + return; + if (dev->event) dev->event(dev, type, code, value); break; @@ -762,7 +766,9 @@ static void input_dev_release(struct class_device *class_dev) { struct input_dev *dev = to_input_dev(class_dev); + input_ff_destroy(dev); kfree(dev); + module_put(THIS_MODULE); } diff --git a/include/linux/input.h b/include/linux/input.h index b3253ab72ff7..81c6ea5afedb 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -784,6 +784,9 @@ struct ff_effect { #define FF_INERTIA 0x56 #define FF_RAMP 0x57 +#define FF_EFFECT_MIN FF_RUMBLE +#define FF_EFFECT_MAX FF_RAMP + /* * Force feedback periodic effect types */ @@ -795,6 +798,9 @@ struct ff_effect { #define FF_SAW_DOWN 0x5c #define FF_CUSTOM 0x5d +#define FF_WAVEFORM_MIN FF_SQUARE +#define FF_WAVEFORM_MAX FF_CUSTOM + /* * Set ff device properties */ @@ -870,6 +876,8 @@ struct input_dev { unsigned int keycodesize; void *keycode; + struct ff_device *ff; + unsigned int repeat_key; struct timer_list timer; @@ -1108,5 +1116,58 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min extern struct class input_class; +/** + * struct ff_device - force-feedback part of an input device + * @upload: Called to upload an new effect into device + * @erase: Called to erase an effect from device + * @playback: Called to request device to start playing specified effect + * @set_gain: Called to set specified gain + * @set_autocenter: Called to auto-center device + * @destroy: called by input core when parent input device is being + * destroyed + * @private: driver-specific data, will be freed automatically + * @ffbit: bitmap of force feedback capabilities truly supported by + * device (not emulated like ones in input_dev->ffbit) + * @mutex: mutex for serializing access to the device + * @max_effects: maximum number of effects supported by device + * @effects: pointer to an array of effects currently loaded into device + * @effect_owners: array of effect owners; when file handle owning + * an effect gets closed the effcet is automatically erased + * + * Every force-feedback device must implement upload() and playback() + * methods; erase() is optional. set_gain() and set_autocenter() need + * only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER + * bits. + */ +struct ff_device { + int (*upload)(struct input_dev *dev, struct ff_effect *effect, + struct ff_effect *old); + int (*erase)(struct input_dev *dev, int effect_id); + + int (*playback)(struct input_dev *dev, int effect_id, int value); + void (*set_gain)(struct input_dev *dev, u16 gain); + void (*set_autocenter)(struct input_dev *dev, u16 magnitude); + + void (*destroy)(struct ff_device *); + + void *private; + + unsigned long ffbit[NBITS(FF_MAX)]; + + struct mutex mutex; + + int max_effects; + struct ff_effect *effects; + struct file *effect_owners[]; +}; + +int input_ff_create(struct input_dev *dev, int max_effects); +void input_ff_destroy(struct input_dev *dev); + +int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); + +int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file); +int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file); + #endif #endif -- cgit v1.2.3 From 7d928a2b14eede1f333db7b7b684c57f7fa7f456 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 19 Jul 2006 01:40:30 -0400 Subject: Input: unified force feedback support for memoryless devices Consolidate core implementing memoryless devices in one module; added support for gain and envelopes and periodic => rumble conversion. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/Kconfig | 14 ++ drivers/input/Makefile | 2 + drivers/input/ff-memless.c | 515 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/input.h | 3 + 4 files changed, 534 insertions(+) create mode 100644 drivers/input/ff-memless.c (limited to 'include/linux') diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 58223b5d842a..96232313b1b9 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -24,6 +24,20 @@ config INPUT if INPUT +config INPUT_FF_MEMLESS + tristate "Support for memoryless force-feedback devices" + default n + ---help--- + Say Y here if you have memoryless force-feedback input device + such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual + Power 2, or similar. You will also need to enable hardware-specific + driver. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called ff-memless. + comment "Userland interfaces" config INPUT_MOUSEDEV diff --git a/drivers/input/Makefile b/drivers/input/Makefile index abdc9d435705..a005b1df5f1a 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_INPUT) += input-core.o input-core-objs := input.o ff-core.o +obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o + obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_EVDEV) += evdev.o diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c new file mode 100644 index 000000000000..cd8b7297e6df --- /dev/null +++ b/drivers/input/ff-memless.c @@ -0,0 +1,515 @@ +/* + * Force feedback support for memoryless devices + * + * Copyright (c) 2006 Anssi Hannula + * Copyright (c) 2006 Dmitry Torokhov + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* #define DEBUG */ + +#define debug(format, arg...) pr_debug("ff-memless: " format "\n", ## arg) + +#include +#include +#include +#include +#include + +#include "fixp-arith.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Anssi Hannula "); +MODULE_DESCRIPTION("Force feedback support for memoryless devices"); + +/* Number of effects handled with memoryless devices */ +#define FF_MEMLESS_EFFECTS 16 + +/* Envelope update interval in ms */ +#define FF_ENVELOPE_INTERVAL 50 + +#define FF_EFFECT_STARTED 0 +#define FF_EFFECT_PLAYING 1 +#define FF_EFFECT_ABORTING 2 + +struct ml_effect_state { + struct ff_effect *effect; + unsigned long flags; /* effect state (STARTED, PLAYING, etc) */ + int count; /* loop count of the effect */ + unsigned long play_at; /* start time */ + unsigned long stop_at; /* stop time */ + unsigned long adj_at; /* last time the effect was sent */ +}; + +struct ml_device { + void *private; + struct ml_effect_state states[FF_MEMLESS_EFFECTS]; + int gain; + struct timer_list timer; + spinlock_t timer_lock; + struct input_dev *dev; + + int (*play_effect)(struct input_dev *dev, void *data, + struct ff_effect *effect); +}; + +static const struct ff_envelope *get_envelope(const struct ff_effect *effect) +{ + static const struct ff_envelope empty_envelope; + + switch (effect->type) { + case FF_PERIODIC: + return &effect->u.periodic.envelope; + case FF_CONSTANT: + return &effect->u.constant.envelope; + default: + return &empty_envelope; + } +} + +/* + * Check for the next time envelope requires an update on memoryless devices + */ +static unsigned long calculate_next_time(struct ml_effect_state *state) +{ + const struct ff_envelope *envelope = get_envelope(state->effect); + unsigned long attack_stop, fade_start, next_fade; + + if (envelope->attack_length) { + attack_stop = state->play_at + + msecs_to_jiffies(envelope->attack_length); + if (time_before(state->adj_at, attack_stop)) + return state->adj_at + + msecs_to_jiffies(FF_ENVELOPE_INTERVAL); + } + + if (state->effect->replay.length) { + if (envelope->fade_length) { + /* check when fading should start */ + fade_start = state->stop_at - + msecs_to_jiffies(envelope->fade_length); + + if (time_before(state->adj_at, fade_start)) + return fade_start; + + /* already fading, advance to next checkpoint */ + next_fade = state->adj_at + + msecs_to_jiffies(FF_ENVELOPE_INTERVAL); + if (time_before(next_fade, state->stop_at)) + return next_fade; + } + + return state->stop_at; + } + + return state->play_at; +} + +static void ml_schedule_timer(struct ml_device *ml) +{ + struct ml_effect_state *state; + unsigned long now = jiffies; + unsigned long earliest = 0; + unsigned long next_at; + int events = 0; + int i; + + debug("calculating next timer"); + + for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { + + state = &ml->states[i]; + + if (!test_bit(FF_EFFECT_STARTED, &state->flags)) + continue; + + if (test_bit(FF_EFFECT_PLAYING, &state->flags)) + next_at = calculate_next_time(state); + else + next_at = state->play_at; + + if (time_before_eq(now, next_at) && + (++events == 1 || time_before(next_at, earliest))) + earliest = next_at; + } + + if (!events) { + debug("no actions"); + del_timer(&ml->timer); + } else { + debug("timer set"); + mod_timer(&ml->timer, earliest); + } +} + +/* + * Apply an envelope to a value + */ +static int apply_envelope(struct ml_effect_state *state, int value, + struct ff_envelope *envelope) +{ + struct ff_effect *effect = state->effect; + unsigned long now = jiffies; + int time_from_level; + int time_of_envelope; + int envelope_level; + int difference; + + if (envelope->attack_length && + time_before(now, + state->play_at + msecs_to_jiffies(envelope->attack_length))) { + debug("value = 0x%x, attack_level = 0x%x", value, + envelope->attack_level); + time_from_level = jiffies_to_msecs(now - state->play_at); + time_of_envelope = envelope->attack_length; + envelope_level = min_t(__s16, envelope->attack_level, 0x7fff); + + } else if (envelope->fade_length && effect->replay.length && + time_after(now, + state->stop_at - msecs_to_jiffies(envelope->fade_length)) && + time_before(now, state->stop_at)) { + time_from_level = jiffies_to_msecs(state->stop_at - now); + time_of_envelope = envelope->fade_length; + envelope_level = min_t(__s16, envelope->fade_level, 0x7fff); + } else + return value; + + difference = abs(value) - envelope_level; + + debug("difference = %d", difference); + debug("time_from_level = 0x%x", time_from_level); + debug("time_of_envelope = 0x%x", time_of_envelope); + + difference = difference * time_from_level / time_of_envelope; + + debug("difference = %d", difference); + + return value < 0 ? + -(difference + envelope_level) : (difference + envelope_level); +} + +/* + * Return the type the effect has to be converted into (memless devices) + */ +static int get_compatible_type(struct ff_device *ff, int effect_type) +{ + + if (test_bit(effect_type, ff->ffbit)) + return effect_type; + + if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit)) + return FF_RUMBLE; + + printk(KERN_ERR + "ff-memless: invalid type in get_compatible_type()\n"); + + return 0; +} + +/* + * Combine two effects and apply gain. + */ +static void ml_combine_effects(struct ff_effect *effect, + struct ml_effect_state *state, + int gain) +{ + struct ff_effect *new = state->effect; + unsigned int strong, weak, i; + int x, y; + fixp_t level; + + switch (new->type) { + case FF_CONSTANT: + i = new->direction * 360 / 0xffff; + level = fixp_new16(apply_envelope(state, + new->u.constant.level, + &new->u.constant.envelope)); + x = fixp_mult(fixp_sin(i), level) * gain / 0xffff; + y = fixp_mult(-fixp_cos(i), level) * gain / 0xffff; + /* + * here we abuse ff_ramp to hold x and y of constant force + * If in future any driver wants something else than x and y + * in s8, this should be changed to something more generic + */ + effect->u.ramp.start_level = + max(min(effect->u.ramp.start_level + x, 0x7f), -0x80); + effect->u.ramp.end_level = + max(min(effect->u.ramp.end_level + y, 0x7f), -0x80); + break; + + case FF_RUMBLE: + strong = new->u.rumble.strong_magnitude * gain / 0xffff; + weak = new->u.rumble.weak_magnitude * gain / 0xffff; + effect->u.rumble.strong_magnitude = + min(strong + effect->u.rumble.strong_magnitude, + 0xffffU); + effect->u.rumble.weak_magnitude = + min(weak + effect->u.rumble.weak_magnitude, 0xffffU); + break; + + case FF_PERIODIC: + i = apply_envelope(state, abs(new->u.periodic.magnitude), + &new->u.periodic.envelope); + + /* here we also scale it 0x7fff => 0xffff */ + i = i * gain / 0x7fff; + + effect->u.rumble.strong_magnitude = + min(i + effect->u.rumble.strong_magnitude, 0xffffU); + effect->u.rumble.weak_magnitude = + min(i + effect->u.rumble.weak_magnitude, 0xffffU); + break; + + default: + printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n"); + break; + } + +} + + +/* + * Because memoryless devices have only one effect per effect type active + * at one time we have to combine multiple effects into one + */ +static int ml_get_combo_effect(struct ml_device *ml, + unsigned long *effect_handled, + struct ff_effect *combo_effect) +{ + struct ff_effect *effect; + struct ml_effect_state *state; + int effect_type; + int i; + + memset(combo_effect, 0, sizeof(struct ff_effect)); + + for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { + if (__test_and_set_bit(i, effect_handled)) + continue; + + state = &ml->states[i]; + effect = state->effect; + + if (!test_bit(FF_EFFECT_STARTED, &state->flags)) + continue; + + if (time_before(jiffies, state->play_at)) + continue; + + /* + * here we have started effects that are either + * currently playing (and may need be aborted) + * or need to start playing. + */ + effect_type = get_compatible_type(ml->dev->ff, effect->type); + if (combo_effect->type != effect_type) { + if (combo_effect->type != 0) { + __clear_bit(i, effect_handled); + continue; + } + combo_effect->type = effect_type; + } + + if (__test_and_clear_bit(FF_EFFECT_ABORTING, &state->flags)) { + __clear_bit(FF_EFFECT_PLAYING, &state->flags); + __clear_bit(FF_EFFECT_STARTED, &state->flags); + } else if (effect->replay.length && + time_after_eq(jiffies, state->stop_at)) { + + __clear_bit(FF_EFFECT_PLAYING, &state->flags); + + if (--state->count <= 0) { + __clear_bit(FF_EFFECT_STARTED, &state->flags); + } else { + state->play_at = jiffies + + msecs_to_jiffies(effect->replay.delay); + state->stop_at = state->play_at + + msecs_to_jiffies(effect->replay.length); + } + } else { + __set_bit(FF_EFFECT_PLAYING, &state->flags); + state->adj_at = jiffies; + ml_combine_effects(combo_effect, state, ml->gain); + } + } + + return combo_effect->type != 0; +} + +static void ml_play_effects(struct ml_device *ml) +{ + struct ff_effect effect; + DECLARE_BITMAP(handled_bm, FF_MEMLESS_EFFECTS); + + memset(handled_bm, 0, sizeof(handled_bm)); + + while (ml_get_combo_effect(ml, handled_bm, &effect)) + ml->play_effect(ml->dev, ml->private, &effect); + + ml_schedule_timer(ml); +} + +static void ml_effect_timer(unsigned long timer_data) +{ + struct input_dev *dev = (struct input_dev *)timer_data; + struct ml_device *ml = dev->ff->private; + + debug("timer: updating effects"); + + spin_lock(&ml->timer_lock); + ml_play_effects(ml); + spin_unlock(&ml->timer_lock); +} + +static void ml_ff_set_gain(struct input_dev *dev, u16 gain) +{ + struct ml_device *ml = dev->ff->private; + int i; + + spin_lock_bh(&ml->timer_lock); + + ml->gain = gain; + + for (i = 0; i < FF_MEMLESS_EFFECTS; i++) + __clear_bit(FF_EFFECT_PLAYING, &ml->states[i].flags); + + ml_play_effects(ml); + + spin_unlock_bh(&ml->timer_lock); +} + +static int ml_ff_playback(struct input_dev *dev, int effect_id, int value) +{ + struct ml_device *ml = dev->ff->private; + struct ml_effect_state *state = &ml->states[effect_id]; + + spin_lock_bh(&ml->timer_lock); + + if (value > 0) { + debug("initiated play"); + + __set_bit(FF_EFFECT_STARTED, &state->flags); + state->count = value; + state->play_at = jiffies + + msecs_to_jiffies(state->effect->replay.delay); + state->stop_at = state->play_at + + msecs_to_jiffies(state->effect->replay.length); + state->adj_at = state->play_at; + + ml_schedule_timer(ml); + + } else { + debug("initiated stop"); + + if (test_bit(FF_EFFECT_PLAYING, &state->flags)) + __set_bit(FF_EFFECT_ABORTING, &state->flags); + else + __clear_bit(FF_EFFECT_STARTED, &state->flags); + + ml_play_effects(ml); + } + + spin_unlock_bh(&ml->timer_lock); + + return 0; +} + +static int ml_ff_upload(struct input_dev *dev, + struct ff_effect *effect, struct ff_effect *old) +{ + struct ml_device *ml = dev->ff->private; + struct ml_effect_state *state = &ml->states[effect->id]; + + spin_lock_bh(&ml->timer_lock); + + if (test_bit(FF_EFFECT_STARTED, &state->flags)) { + __clear_bit(FF_EFFECT_PLAYING, &state->flags); + state->play_at = jiffies + + msecs_to_jiffies(state->effect->replay.delay); + state->stop_at = state->play_at + + msecs_to_jiffies(state->effect->replay.length); + state->adj_at = state->play_at; + ml_schedule_timer(ml); + } + + spin_unlock_bh(&ml->timer_lock); + + return 0; +} + +static void ml_ff_destroy(struct ff_device *ff) +{ + struct ml_device *ml = ff->private; + + kfree(ml->private); +} + +/** + * input_ff_create_memless() - create memoryless FF device + * @dev: input device supporting force-feedback + * @data: driver-specific data to be passed into @play_effect + * @play_effect: driver-specific method for playing FF effect + */ +int input_ff_create_memless(struct input_dev *dev, void *data, + int (*play_effect)(struct input_dev *, void *, struct ff_effect *)) +{ + struct ml_device *ml; + struct ff_device *ff; + int error; + int i; + + ml = kzalloc(sizeof(struct ml_device), GFP_KERNEL); + if (!ml) + return -ENOMEM; + + ml->dev = dev; + ml->private = data; + ml->play_effect = play_effect; + ml->gain = 0xffff; + spin_lock_init(&ml->timer_lock); + setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev); + + set_bit(FF_GAIN, dev->ffbit); + + error = input_ff_create(dev, FF_MEMLESS_EFFECTS); + if (error) { + kfree(ml); + return error; + } + + ff = dev->ff; + ff->private = ml; + ff->upload = ml_ff_upload; + ff->playback = ml_ff_playback; + ff->set_gain = ml_ff_set_gain; + ff->destroy = ml_ff_destroy; + + /* we can emulate periodic effects with RUMBLE */ + if (test_bit(FF_RUMBLE, ff->ffbit)) { + set_bit(FF_PERIODIC, dev->ffbit); + set_bit(FF_SINE, dev->ffbit); + set_bit(FF_TRIANGLE, dev->ffbit); + set_bit(FF_SQUARE, dev->ffbit); + } + + for (i = 0; i < FF_MEMLESS_EFFECTS; i++) + ml->states[i].effect = &ff->effects[i]; + + return 0; +} +EXPORT_SYMBOL_GPL(input_ff_create_memless); diff --git a/include/linux/input.h b/include/linux/input.h index 81c6ea5afedb..d8b0c5610c04 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1169,5 +1169,8 @@ int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file); int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file); +int input_ff_create_memless(struct input_dev *dev, void *data, + int (*play_effect)(struct input_dev *, void *, struct ff_effect *)); + #endif #endif -- cgit v1.2.3 From ff462551235d8d7d843a005950bc90924fcedede Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 19 Jul 2006 01:41:09 -0400 Subject: Input: uinput - switch to the new FF interface The userspace interface of the force feedback part is changed and documentation in uinput.h is updated accordingly. MODULE_VERSION is also incremented to reflect the revision. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 67 ++++++++++++++++++++++++++++++++++----------- include/linux/uinput.h | 35 +++++++++++++++-------- 2 files changed, 74 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index d723e9ad7c41..9516439b7c78 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -20,6 +20,9 @@ * Author: Aristeu Sergio Rozanski Filho * * Changes/Revisions: + * 0.3 09/04/2006 (Anssi Hannula ) + * - updated ff support for the changes in kernel interface + * - added MODULE_VERSION * 0.2 16/10/2004 (Micah Dowty ) * - added force feedback support * - added UI_SET_PHYS @@ -107,18 +110,31 @@ static int uinput_request_submit(struct input_dev *dev, struct uinput_request *r return request->retval; } -static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) +static void uinput_dev_set_gain(struct input_dev *dev, u16 gain) +{ + uinput_dev_event(dev, EV_FF, FF_GAIN, gain); +} + +static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude) +{ + uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude); +} + +static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) +{ + return uinput_dev_event(dev, EV_FF, effect_id, value); +} + +static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) { struct uinput_request request; int retval; - if (!test_bit(EV_FF, dev->evbit)) - return -ENOSYS; - request.id = -1; init_completion(&request.done); request.code = UI_FF_UPLOAD; - request.u.effect = effect; + request.u.upload.effect = effect; + request.u.upload.old = old; retval = uinput_request_reserve_slot(dev->private, &request); if (!retval) @@ -168,6 +184,7 @@ static void uinput_destroy_device(struct uinput_device *udev) static int uinput_create_device(struct uinput_device *udev) { + struct input_dev *dev = udev->dev; int error; if (udev->state != UIST_SETUP_COMPLETE) { @@ -175,15 +192,29 @@ static int uinput_create_device(struct uinput_device *udev) return -EINVAL; } - error = input_register_device(udev->dev); - if (error) { - uinput_destroy_device(udev); - return error; + if (udev->ff_effects_max) { + error = input_ff_create(dev, udev->ff_effects_max); + if (error) + goto fail1; + + dev->ff->upload = uinput_dev_upload_effect; + dev->ff->erase = uinput_dev_erase_effect; + dev->ff->playback = uinput_dev_playback; + dev->ff->set_gain = uinput_dev_set_gain; + dev->ff->set_autocenter = uinput_dev_set_autocenter; } + error = input_register_device(udev->dev); + if (error) + goto fail2; + udev->state = UIST_CREATED; return 0; + + fail2: input_ff_destroy(dev); + fail1: uinput_destroy_device(udev); + return error; } static int uinput_open(struct inode *inode, struct file *file) @@ -243,8 +274,6 @@ static int uinput_allocate_device(struct uinput_device *udev) return -ENOMEM; udev->dev->event = uinput_dev_event; - udev->dev->upload_effect = uinput_dev_upload_effect; - udev->dev->erase_effect = uinput_dev_erase_effect; udev->dev->private = udev; return 0; @@ -278,6 +307,8 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu goto exit; } + udev->ff_effects_max = user_dev->ff_effects_max; + size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; if (!size) { retval = -EINVAL; @@ -296,7 +327,6 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu dev->id.vendor = user_dev->id.vendor; dev->id.product = user_dev->id.product; dev->id.version = user_dev->id.version; - dev->ff_effects_max = user_dev->ff_effects_max; size = sizeof(int) * (ABS_MAX + 1); memcpy(dev->absmax, user_dev->absmax, size); @@ -525,12 +555,17 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { + if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { retval = -EINVAL; break; } ff_up.retval = 0; - memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect)); + memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect)); + if (req->u.upload.old) + memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect)); + else + memset(&ff_up.old, 0, sizeof(struct ff_effect)); + if (copy_to_user(p, &ff_up, sizeof(ff_up))) { retval = -EFAULT; break; @@ -561,12 +596,11 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { + if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { retval = -EINVAL; break; } req->retval = ff_up.retval; - memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); uinput_request_done(udev, req); break; @@ -622,6 +656,7 @@ static void __exit uinput_exit(void) MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); MODULE_DESCRIPTION("User level driver support for input subsystem"); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.3"); module_init(uinput_init); module_exit(uinput_exit); diff --git a/include/linux/uinput.h b/include/linux/uinput.h index 7168302f9844..1fd61eeed664 100644 --- a/include/linux/uinput.h +++ b/include/linux/uinput.h @@ -22,12 +22,18 @@ * Author: Aristeu Sergio Rozanski Filho * * Changes/Revisions: + * 0.3 24/05/2006 (Anssi Hannula ) + * - update ff support for the changes in kernel interface + * - add UINPUT_VERSION * 0.2 16/10/2004 (Micah Dowty ) * - added force feedback support * - added UI_SET_PHYS * 0.1 20/06/2002 * - first public version */ + +#define UINPUT_VERSION 3 + #ifdef __KERNEL__ #define UINPUT_MINOR 223 #define UINPUT_NAME "uinput" @@ -45,7 +51,10 @@ struct uinput_request { union { int effect_id; - struct ff_effect* effect; + struct { + struct ff_effect *effect; + struct ff_effect *old; + } upload; } u; }; @@ -58,6 +67,7 @@ struct uinput_device { unsigned char head; unsigned char tail; struct input_event buff[UINPUT_BUFFER_SIZE]; + int ff_effects_max; struct uinput_request *requests[UINPUT_NUM_REQUESTS]; wait_queue_head_t requests_waitq; @@ -69,6 +79,7 @@ struct uinput_ff_upload { int request_id; int retval; struct ff_effect effect; + struct ff_effect old; }; struct uinput_ff_erase { @@ -98,33 +109,33 @@ struct uinput_ff_erase { #define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase) #define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase) -/* To write a force-feedback-capable driver, the upload_effect +/* + * To write a force-feedback-capable driver, the upload_effect * and erase_effect callbacks in input_dev must be implemented. * The uinput driver will generate a fake input event when one of * these callbacks are invoked. The userspace code then uses * ioctls to retrieve additional parameters and send the return code. * The callback blocks until this return code is sent. * - * The described callback mechanism is only used if EV_FF is set. - * Otherwise, default implementations of upload_effect and erase_effect - * are used. + * The described callback mechanism is only used if ff_effects_max + * is set. * * To implement upload_effect(): - * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_UPLOAD. + * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD. * A request ID will be given in 'value'. * 2. Allocate a uinput_ff_upload struct, fill in request_id with * the 'value' from the EV_UINPUT event. * 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the * uinput_ff_upload struct. It will be filled in with the - * ff_effect passed to upload_effect(). - * 4. Perform the effect upload, and place the modified ff_effect - * and a return code back into the uinput_ff_upload struct. + * ff_effects passed to upload_effect(). + * 4. Perform the effect upload, and place a return code back into + the uinput_ff_upload struct. * 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the * uinput_ff_upload_effect struct. This will complete execution * of our upload_effect() handler. * * To implement erase_effect(): - * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_ERASE. + * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE. * A request ID will be given in 'value'. * 2. Allocate a uinput_ff_erase struct, fill in request_id with * the 'value' from the EV_UINPUT event. @@ -133,13 +144,13 @@ struct uinput_ff_erase { * effect ID passed to erase_effect(). * 4. Perform the effect erasure, and place a return code back * into the uinput_ff_erase struct. - * and a return code back into the uinput_ff_erase struct. * 5. Issue a UI_END_FF_ERASE ioctl, also giving it the * uinput_ff_erase_effect struct. This will complete execution * of our erase_effect() handler. */ -/* This is the new event type, used only by uinput. +/* + * This is the new event type, used only by uinput. * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value' * is the unique request ID. This number was picked * arbitrarily, above EV_MAX (since the input system -- cgit v1.2.3 From 1f734cb461e1f029d751deb15c8d9f8137fb2ca7 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 19 Jul 2006 01:44:08 -0400 Subject: Input: drop remnants of the old force-feedback interface Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/input.h b/include/linux/input.h index d8b0c5610c04..4405d0283549 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -870,7 +870,6 @@ struct input_dev { unsigned long sndbit[NBITS(SND_MAX)]; unsigned long ffbit[NBITS(FF_MAX)]; unsigned long swbit[NBITS(SW_MAX)]; - int ff_effects_max; unsigned int keycodemax; unsigned int keycodesize; @@ -903,8 +902,6 @@ struct input_dev { void (*close)(struct input_dev *dev); int (*flush)(struct input_dev *dev, struct file *file); int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); - int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); - int (*erase_effect)(struct input_dev *dev, int effect_id); struct input_handle *grab; @@ -1078,11 +1075,6 @@ static inline void input_report_abs(struct input_dev *dev, unsigned int code, in input_event(dev, EV_ABS, code, value); } -static inline void input_report_ff(struct input_dev *dev, unsigned int code, int value) -{ - input_event(dev, EV_FF, code, value); -} - static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value) { input_event(dev, EV_FF_STATUS, code, value); -- cgit v1.2.3 From 8b8277a17477de38d8df6783e8221aed55bab300 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 19 Jul 2006 01:44:22 -0400 Subject: Input: update the force feedback documentation Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- Documentation/input/ff.txt | 112 ++++++++++++++--------------- include/linux/input.h | 175 +++++++++++++++++++++++++++++++-------------- 2 files changed, 174 insertions(+), 113 deletions(-) (limited to 'include/linux') diff --git a/Documentation/input/ff.txt b/Documentation/input/ff.txt index c7e10eaff203..c53b1c11aa40 100644 --- a/Documentation/input/ff.txt +++ b/Documentation/input/ff.txt @@ -1,67 +1,37 @@ Force feedback for Linux. By Johann Deneux on 2001/04/22. +Updated by Anssi Hannula on 2006/04/09. You may redistribute this file. Please remember to include shape.fig and interactive.fig as well. ---------------------------------------------------------------------------- -0. Introduction +1. Introduction ~~~~~~~~~~~~~~~ This document describes how to use force feedback devices under Linux. The goal is not to support these devices as if they were simple input-only devices (as it is already the case), but to really enable the rendering of force effects. -At the moment, only I-Force devices are supported, and not officially. That -means I had to find out how the protocol works on my own. Of course, the -information I managed to grasp is far from being complete, and I can not -guarranty that this driver will work for you. -This document only describes the force feedback part of the driver for I-Force -devices. Please read joystick.txt before reading further this document. +This document only describes the force feedback part of the Linux input +interface. Please read joystick.txt and input.txt before reading further this +document. 2. Instructions to the user ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Here are instructions on how to compile and use the driver. In fact, this -driver is the normal iforce, input and evdev drivers written by Vojtech -Pavlik, plus additions to support force feedback. +To enable force feedback, you have to: + +1. have your kernel configured with evdev and a driver that supports your + device. +2. make sure evdev module is loaded and /dev/input/event* device files are + created. Before you start, let me WARN you that some devices shake violently during the initialisation phase. This happens for example with my "AVB Top Shot Pegasus". To stop this annoying behaviour, move you joystick to its limits. Anyway, you -should keep a hand on your device, in order to avoid it to brake down if +should keep a hand on your device, in order to avoid it to break down if something goes wrong. -At the kernel's compilation: - - Enable IForce/Serial - - Enable Event interface - -Compile the modules, install them. - -You also need inputattach. - -You then need to insert the modules into the following order: -% modprobe joydev -% modprobe serport # Only for serial -% modprobe iforce -% modprobe evdev -% ./inputattach -ifor $2 & # Only for serial -If you are using USB, you don't need the inputattach step. - -Please check that you have all the /dev/input entries needed: -cd /dev -rm js* -mkdir input -mknod input/js0 c 13 0 -mknod input/js1 c 13 1 -mknod input/js2 c 13 2 -mknod input/js3 c 13 3 -ln -s input/js0 js0 -ln -s input/js1 js1 -ln -s input/js2 js2 -ln -s input/js3 js3 - -mknod input/event0 c 13 64 -mknod input/event1 c 13 65 -mknod input/event2 c 13 66 -mknod input/event3 c 13 67 +If you have a serial iforce device, you need to start inputattach. See +joystick.txt for details. 2.1 Does it work ? ~~~~~~~~~~~~~~~~~~ @@ -70,9 +40,9 @@ There is an utility called fftest that will allow you to test the driver. 3. Instructions to the developper ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - All interactions are done using the event API. That is, you can use ioctl() +All interactions are done using the event API. That is, you can use ioctl() and write() on /dev/input/eventXX. - This information is subject to change. +This information is subject to change. 3.1 Querying device capabilities ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -86,18 +56,29 @@ int ioctl(int file_descriptor, int request, unsigned long *features); Returns the features supported by the device. features is a bitfield with the following bits: -- FF_X has an X axis (usually joysticks) -- FF_Y has an Y axis (usually joysticks) -- FF_WHEEL has a wheel (usually sterring wheels) - FF_CONSTANT can render constant force effects -- FF_PERIODIC can render periodic effects (sine, triangle, square...) +- FF_PERIODIC can render periodic effects with the following waveforms: + - FF_SQUARE square waveform + - FF_TRIANGLE triangle waveform + - FF_SINE sine waveform + - FF_SAW_UP sawtooth up waveform + - FF_SAW_DOWN sawtooth down waveform + - FF_CUSTOM custom waveform - FF_RAMP can render ramp effects - FF_SPRING can simulate the presence of a spring -- FF_FRICTION can simulate friction +- FF_FRICTION can simulate friction - FF_DAMPER can simulate damper effects -- FF_RUMBLE rumble effects (normally the only effect supported by rumble - pads) +- FF_RUMBLE rumble effects - FF_INERTIA can simulate inertia +- FF_GAIN gain is adjustable +- FF_AUTOCENTER autocenter is adjustable + +Note: In most cases you should use FF_PERIODIC instead of FF_RUMBLE. All + devices that support FF_RUMBLE support FF_PERIODIC (square, triangle, + sine) and the other way around. + +Note: The exact syntax FF_CUSTOM is undefined for the time being as no driver + supports it yet. int ioctl(int fd, EVIOCGEFFECTS, int *n); @@ -108,7 +89,7 @@ Returns the number of effects the device can keep in its memory. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #include #include - + int ioctl(int file_descriptor, int request, struct ff_effect *effect); "request" must be EVIOCSFF. @@ -120,6 +101,9 @@ to the unique id assigned by the driver. This data is required for performing some operations (removing an effect, controlling the playback). This if field must be set to -1 by the user in order to tell the driver to allocate a new effect. + +Effects are file descriptor specific. + See for a description of the ff_effect struct. You should also find help in a few sketches, contained in files shape.fig and interactive.fig. You need xfig to visualize these files. @@ -128,8 +112,8 @@ You need xfig to visualize these files. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int ioctl(int fd, EVIOCRMFF, effect.id); -This makes room for new effects in the device's memory. Please note this won't -stop the effect if it was playing. +This makes room for new effects in the device's memory. Note that this also +stops the effect if it was playing. 3.4 Controlling the playback of effects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -149,22 +133,21 @@ Control of playing is done with write(). Below is an example: play.type = EV_FF; play.code = effect.id; play.value = 3; - + write(fd, (const void*) &play, sizeof(play)); ... /* Stop an effect */ stop.type = EV_FF; stop.code = effect.id; stop.value = 0; - + write(fd, (const void*) &play, sizeof(stop)); 3.5 Setting the gain ~~~~~~~~~~~~~~~~~~~~ Not all devices have the same strength. Therefore, users should set a gain factor depending on how strong they want effects to be. This setting is -persistent across access to the driver, so you should not care about it if -you are writing games, as another utility probably already set this for you. +persistent across access to the driver. /* Set the gain of the device int gain; /* between 0 and 100 */ @@ -204,11 +187,14 @@ type of device, not all parameters can be dynamically updated. For example, the direction of an effect cannot be updated with iforce devices. In this case, the driver stops the effect, up-load it, and restart it. +Therefore it is recommended to dynamically change direction while the effect +is playing only when it is ok to restart the effect with a replay count of 1. 3.8 Information about the status of effects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Every time the status of an effect is changed, an event is sent. The values and meanings of the fields of the event are as follows: + struct input_event { /* When the status of the effect changed */ struct timeval time; @@ -225,3 +211,9 @@ struct input_event { FF_STATUS_STOPPED The effect stopped playing FF_STATUS_PLAYING The effect started to play + +NOTE: Status feedback is only supported by iforce driver. If you have + a really good reason to use this, please contact + linux-joystick@atrey.karlin.mff.cuni.cz or anssi.hannula@gmail.com + so that support for it can be added to the rest of the drivers. + diff --git a/include/linux/input.h b/include/linux/input.h index 4405d0283549..a7a1f55a5eed 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -667,98 +667,167 @@ struct input_absinfo { /* * Structures used in ioctls to upload effects to a device - * The first structures are not passed directly by using ioctls. - * They are sub-structures of the actually sent structure (called ff_effect) + * They are pieces of a bigger structure (called ff_effect) */ +/* + * All duration values are expressed in ms. Values above 32767 ms (0x7fff) + * should not be used and have unspecified results. + */ + +/** + * struct ff_replay - defines scheduling of the effect + * @length: duration of the effect + * @delay: delay before effect should start playing + */ struct ff_replay { - __u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */ - __u16 delay; /* Time to wait before to start playing an effect */ + __u16 length; + __u16 delay; }; +/** + * struct ff_trigger - defines what triggers the effect + * @button: number of the button triggering the effect + * @interval: controls how soon the effect can be re-triggered + */ struct ff_trigger { - __u16 button; /* Number of button triggering an effect */ - __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */ + __u16 button; + __u16 interval; }; +/** + * struct ff_envelope - generic effect envelope + * @attack_length: duration of the attack (ms) + * @attack_level: level at the beginning of the attack + * @fade_length: duration of fade (ms) + * @fade_level: level at the end of fade + * + * The @attack_level and @fade_level are absolute values; when applying + * envelope force-feedback core will convert to positive/negative + * value based on polarity of the default level of the effect. + * Valid range for the attack and fade levels is 0x0000 - 0x7fff + */ struct ff_envelope { - __u16 attack_length; /* Duration of attack (ms) */ - __u16 attack_level; /* Level at beginning of attack */ - __u16 fade_length; /* Duration of fade (ms) */ - __u16 fade_level; /* Level at end of fade */ + __u16 attack_length; + __u16 attack_level; + __u16 fade_length; + __u16 fade_level; }; -/* FF_CONSTANT */ +/** + * struct ff_constant_effect - defines parameters of a constant effect + * @level: strength of the effect; may be negative + * @envelope: envelope data + */ struct ff_constant_effect { - __s16 level; /* Strength of effect. Negative values are OK */ + __s16 level; struct ff_envelope envelope; }; -/* FF_RAMP */ +/** + * struct ff_ramp_effect - defines parameters of a ramp effect + * @start_level: beginning strength of the effect; may be negative + * @end_level: final strength of the effect; may be negative + * @envelope: envelope data + */ struct ff_ramp_effect { __s16 start_level; __s16 end_level; struct ff_envelope envelope; }; -/* FF_SPRING of FF_FRICTION */ +/** + * struct ff_condition_effect - defines a spring or friction effect + * @right_saturation: maximum level when joystick moved all way to the right + * @left_saturation: same for the left side + * @right_coeff: controls how fast the force grows when the joystick moves + * to the right + * @left_coeff: same for the left side + * @deadband: size of the dead zone, where no force is produced + * @center: position of the dead zone + */ struct ff_condition_effect { - __u16 right_saturation; /* Max level when joystick is on the right */ - __u16 left_saturation; /* Max level when joystick in on the left */ + __u16 right_saturation; + __u16 left_saturation; - __s16 right_coeff; /* Indicates how fast the force grows when the - joystick moves to the right */ - __s16 left_coeff; /* Same for left side */ - - __u16 deadband; /* Size of area where no force is produced */ - __s16 center; /* Position of dead zone */ + __s16 right_coeff; + __s16 left_coeff; + __u16 deadband; + __s16 center; }; -/* FF_PERIODIC */ +/** + * struct ff_periodic_effect - defines parameters of a periodic effect + * @waveform: kind of the effect (wave) + * @period: period of the wave (ms) + * @magnitude: peak value + * @offset: mean value of the wave (roughly) + * @phase: 'horizontal' shift + * @envelope: envelope data + * @custom_len: number of samples (FF_CUSTOM only) + * @custom_data: buffer of samples (FF_CUSTOM only) + * + * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, + * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined + * for the time being as no driver supports it yet. + * + * Note: the data pointed by custom_data is copied by the driver. + * You can therefore dispose of the memory after the upload/update. + */ struct ff_periodic_effect { - __u16 waveform; /* Kind of wave (sine, square...) */ - __u16 period; /* in ms */ - __s16 magnitude; /* Peak value */ - __s16 offset; /* Mean value of wave (roughly) */ - __u16 phase; /* 'Horizontal' shift */ + __u16 waveform; + __u16 period; + __s16 magnitude; + __s16 offset; + __u16 phase; struct ff_envelope envelope; -/* Only used if waveform == FF_CUSTOM */ - __u32 custom_len; /* Number of samples */ - __s16 *custom_data; /* Buffer of samples */ -/* Note: the data pointed by custom_data is copied by the driver. You can - * therefore dispose of the memory after the upload/update */ + __u32 custom_len; + __s16 *custom_data; }; -/* FF_RUMBLE */ -/* Some rumble pads have two motors of different weight. - strong_magnitude represents the magnitude of the vibration generated - by the heavy motor. -*/ +/** + * struct ff_rumble_effect - defines parameters of a periodic effect + * @strong_magnitude: magnitude of the heavy motor + * @weak_magnitude: magnitude of the light one + * + * Some rumble pads have two motors of different weight. Strong_magnitude + * represents the magnitude of the vibration generated by the heavy one. + */ struct ff_rumble_effect { - __u16 strong_magnitude; /* Magnitude of the heavy motor */ - __u16 weak_magnitude; /* Magnitude of the light one */ + __u16 strong_magnitude; + __u16 weak_magnitude; }; -/* - * Structure sent through ioctl from the application to the driver +/** + * struct ff_effect - defines force feedback effect + * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING, + * FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM) + * @id: an unique id assigned to an effect + * @direction: direction of the effect + * @trigger: trigger conditions (struct ff_trigger) + * @replay: scheduling of the effect (struct ff_replay) + * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect, + * ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further + * defining effect parameters + * + * This structure is sent through ioctl from the application to the driver. + * To create a new effect aplication should set its @id to -1; the kernel + * will return assigned @id which can later be used to update or delete + * this effect. + * + * Direction of the effect is encoded as follows: + * 0 deg -> 0x0000 (down) + * 90 deg -> 0x4000 (left) + * 180 deg -> 0x8000 (up) + * 270 deg -> 0xC000 (right) */ struct ff_effect { __u16 type; -/* Following field denotes the unique id assigned to an effect. - * If user sets if to -1, a new effect is created, and its id is returned in the same field - * Else, the user sets it to the effect id it wants to update. - */ __s16 id; - - __u16 direction; /* Direction. 0 deg -> 0x0000 (down) - 90 deg -> 0x4000 (left) - 180 deg -> 0x8000 (up) - 270 deg -> 0xC000 (right) - */ - + __u16 direction; struct ff_trigger trigger; struct ff_replay replay; -- cgit v1.2.3 From de9b75d31e81e87685d8cc70052a003c654f1e8e Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 28 Jul 2006 14:00:20 -0500 Subject: [GFS2] add plock owner We need to use fl_owner instead of fl_pid to track the owner of a posix lock. Pass the owner value out to user space where cluster plocks are managed. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/plock.c | 2 ++ include/linux/lock_dlm_plock.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 6adfb2d4fd8c..e5b11f0688f6 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -77,6 +77,7 @@ int gdlm_plock(lm_lockspace_t *lockspace, struct lm_lockname *name, op->info.number = name->ln_number; op->info.start = fl->fl_start; op->info.end = fl->fl_end; + op->info.owner = (__u64)(long) fl->fl_owner; send_op(op); wait_event(recv_wq, (op->done != 0)); @@ -122,6 +123,7 @@ int gdlm_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name, op->info.number = name->ln_number; op->info.start = fl->fl_start; op->info.end = fl->fl_end; + op->info.owner = (__u64)(long) fl->fl_owner; send_op(op); wait_event(recv_wq, (op->done != 0)); diff --git a/include/linux/lock_dlm_plock.h b/include/linux/lock_dlm_plock.h index 007b07a178ab..fc3415113973 100644 --- a/include/linux/lock_dlm_plock.h +++ b/include/linux/lock_dlm_plock.h @@ -12,7 +12,7 @@ #define GDLM_PLOCK_MISC_NAME "lock_dlm_plock" #define GDLM_PLOCK_VERSION_MAJOR 1 -#define GDLM_PLOCK_VERSION_MINOR 0 +#define GDLM_PLOCK_VERSION_MINOR 1 #define GDLM_PLOCK_VERSION_PATCH 0 enum { @@ -34,6 +34,7 @@ struct gdlm_plock_info { __u64 number; __u64 start; __u64 end; + __u64 owner; }; #endif -- cgit v1.2.3 From ee4799997950e81437ef9055a4b104099e3272c4 Mon Sep 17 00:00:00 2001 From: Rick Koch Date: Sat, 5 Aug 2006 00:32:18 -0400 Subject: Input: add driver for Penmount serial touchscreens Signed-off-by: Rick Koch Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 +++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/penmount.c | 185 +++++++++++++++++++++++++++++++++++ include/linux/serio.h | 1 + 4 files changed, 199 insertions(+) create mode 100644 drivers/input/touchscreen/penmount.c (limited to 'include/linux') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index b1b14f8d4dd6..fa038126d508 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -108,4 +108,16 @@ config TOUCHSCREEN_HP600 To compile this driver as a module, choose M here: the module will be called hp680_ts_input. +config TOUCHSCREEN_PENMOUNT + tristate "Penmount serial touchscreen" + select SERIO + help + Say Y here if you have a Penmount serial touchscreen connected to + your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called penmount. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 5e5557c43121..72e7be8097a4 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o +obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c new file mode 100644 index 000000000000..f7370109d43e --- /dev/null +++ b/drivers/input/touchscreen/penmount.c @@ -0,0 +1,185 @@ +/* + * Penmount serial touchscreen driver + * + * Copyright (c) 2006 Rick Koch + * + * Based on ELO driver (drivers/input/touchscreen/elo.c) + * Copyright (c) 2004 Vojtech Pavlik + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Penmount serial touchscreen driver" + +MODULE_AUTHOR("Rick Koch "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define PM_MAX_LENGTH 5 + +/* + * Per-touchscreen data. + */ + +struct pm { + struct input_dev *dev; + struct serio *serio; + int idx; + unsigned char data[PM_MAX_LENGTH]; + char phys[32]; +}; + +static irqreturn_t pm_interrupt(struct serio *serio, + unsigned char data, unsigned int flags, struct pt_regs *regs) +{ + struct pm *pm = serio_get_drvdata(serio); + struct input_dev *dev = pm->dev; + + pm->data[pm->idx] = data; + + if (pm->data[0] & 0x80) { + if (PM_MAX_LENGTH == ++pm->idx) { + input_regs(dev, regs); + input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]); + input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]); + input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); + input_sync(dev); + pm->idx = 0; + } + } + + return IRQ_HANDLED; +} + +/* + * pm_disconnect() is the opposite of pm_connect() + */ + +static void pm_disconnect(struct serio *serio) +{ + struct pm *pm = serio_get_drvdata(serio); + + input_get_device(pm->dev); + input_unregister_device(pm->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(pm->dev); + kfree(pm); +} + +/* + * pm_connect() is the routine that is called when someone adds a + * new serio device that supports Gunze protocol and registers it as + * an input device. + */ + +static int pm_connect(struct serio *serio, struct serio_driver *drv) +{ + struct pm *pm; + struct input_dev *input_dev; + int err; + + pm = kzalloc(sizeof(struct pm), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!pm || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + pm->serio = serio; + pm->dev = input_dev; + snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); + + input_dev->private = pm; + input_dev->name = "Penmount Serial TouchScreen"; + input_dev->phys = pm->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_PENMOUNT; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0); + input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0); + + serio_set_drvdata(serio, pm); + + err = serio_open(serio, drv); + if (err) + goto fail2; + + err = input_register_device(pm->dev); + if (err) + goto fail3; + + return 0; + + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(pm); + return err; +} + +/* + * The serio driver structure. + */ + +static struct serio_device_id pm_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_PENMOUNT, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, pm_serio_ids); + +static struct serio_driver pm_drv = { + .driver = { + .name = "penmountlpc", + }, + .description = DRIVER_DESC, + .id_table = pm_serio_ids, + .interrupt = pm_interrupt, + .connect = pm_connect, + .disconnect = pm_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +static int __init pm_init(void) +{ + serio_register_driver(&pm_drv); + return 0; +} + +static void __exit pm_exit(void) +{ + serio_unregister_driver(&pm_drv); +} + +module_init(pm_init); +module_exit(pm_exit); diff --git a/include/linux/serio.h b/include/linux/serio.h index 6348e8330897..ad546a0205c6 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -217,5 +217,6 @@ static inline void serio_unpin_driver(struct serio *serio) #define SERIO_LKKBD 0x28 #define SERIO_ELO 0x29 #define SERIO_MICROTOUCH 0x30 +#define SERIO_PENMOUNT 0x31 #endif -- cgit v1.2.3 From 4003dff41e65ad338a60dde90019bffcb5531fb6 Mon Sep 17 00:00:00 2001 From: Rick Koch Date: Sat, 5 Aug 2006 00:32:24 -0400 Subject: Input: add driver for Touchright serial touchscreens Signed-off-by: Rick Koch Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 ++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/touchright.c | 196 +++++++++++++++++++++++++++++++++ include/linux/serio.h | 1 + 4 files changed, 210 insertions(+) create mode 100644 drivers/input/touchscreen/touchright.c (limited to 'include/linux') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index fa038126d508..216db1229376 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -120,4 +120,16 @@ config TOUCHSCREEN_PENMOUNT To compile this driver as a module, choose M here: the module will be called penmount. +config TOUCHSCREEN_TOUCHRIGHT + tristate "Touchright serial touchscreen" + select SERIO + help + Say Y here if you have a Touchright serial touchscreen connected to + your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called touchright. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 72e7be8097a4..deda25e36807 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o +obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c new file mode 100644 index 000000000000..1c89fa538651 --- /dev/null +++ b/drivers/input/touchscreen/touchright.c @@ -0,0 +1,196 @@ +/* + * Touchright serial touchscreen driver + * + * Copyright (c) 2006 Rick Koch + * + * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c) + * Copyright (c) 2004 Vojtech Pavlik + * and Dan Streetman + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Touchright serial touchscreen driver" + +MODULE_AUTHOR("Rick Koch "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define TR_FORMAT_TOUCH_BIT 0x01 +#define TR_FORMAT_STATUS_BYTE 0x40 +#define TR_FORMAT_STATUS_MASK ~TR_FORMAT_TOUCH_BIT + +#define TR_LENGTH 5 + +#define TR_MIN_XC 0 +#define TR_MAX_XC 0x1ff +#define TR_MIN_YC 0 +#define TR_MAX_YC 0x1ff + +/* + * Per-touchscreen data. + */ + +struct tr { + struct input_dev *dev; + struct serio *serio; + int idx; + unsigned char data[TR_LENGTH]; + char phys[32]; +}; + +static irqreturn_t tr_interrupt(struct serio *serio, + unsigned char data, unsigned int flags, struct pt_regs *regs) +{ + struct tr *tr = serio_get_drvdata(serio); + struct input_dev *dev = tr->dev; + + tr->data[tr->idx] = data; + + if ((tr->data[0] & TR_FORMAT_STATUS_MASK) == TR_FORMAT_STATUS_BYTE) { + if (++tr->idx == TR_LENGTH) { + input_regs(dev, regs); + input_report_abs(dev, ABS_X, + (tr->data[1] << 5) | (tr->data[2] >> 1)); + input_report_abs(dev, ABS_Y, + (tr->data[3] << 5) | (tr->data[4] >> 1)); + input_report_key(dev, BTN_TOUCH, + tr->data[0] & TR_FORMAT_TOUCH_BIT); + input_sync(dev); + tr->idx = 0; + } + } + + return IRQ_HANDLED; +} + +/* + * tr_disconnect() is the opposite of tr_connect() + */ + +static void tr_disconnect(struct serio *serio) +{ + struct tr *tr = serio_get_drvdata(serio); + + input_get_device(tr->dev); + input_unregister_device(tr->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(tr->dev); + kfree(tr); +} + +/* + * tr_connect() is the routine that is called when someone adds a + * new serio device that supports the Touchright protocol and registers it as + * an input device. + */ + +static int tr_connect(struct serio *serio, struct serio_driver *drv) +{ + struct tr *tr; + struct input_dev *input_dev; + int err; + + tr = kzalloc(sizeof(struct tr), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!tr || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + tr->serio = serio; + tr->dev = input_dev; + snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys); + + input_dev->private = tr; + input_dev->name = "Touchright Serial TouchScreen"; + input_dev->phys = tr->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_TOUCHRIGHT; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0); + input_set_abs_params(tr->dev, ABS_Y, TR_MIN_YC, TR_MAX_YC, 0, 0); + + serio_set_drvdata(serio, tr); + + err = serio_open(serio, drv); + if (err) + goto fail2; + + err = input_register_device(tr->dev); + if (err) + goto fail3; + + return 0; + + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(tr); + return err; +} + +/* + * The serio driver structure. + */ + +static struct serio_device_id tr_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_TOUCHRIGHT, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, tr_serio_ids); + +static struct serio_driver tr_drv = { + .driver = { + .name = "touchright", + }, + .description = DRIVER_DESC, + .id_table = tr_serio_ids, + .interrupt = tr_interrupt, + .connect = tr_connect, + .disconnect = tr_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +static int __init tr_init(void) +{ + serio_register_driver(&tr_drv); + return 0; +} + +static void __exit tr_exit(void) +{ + serio_unregister_driver(&tr_drv); +} + +module_init(tr_init); +module_exit(tr_exit); diff --git a/include/linux/serio.h b/include/linux/serio.h index ad546a0205c6..152606413158 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -218,5 +218,6 @@ static inline void serio_unpin_driver(struct serio *serio) #define SERIO_ELO 0x29 #define SERIO_MICROTOUCH 0x30 #define SERIO_PENMOUNT 0x31 +#define SERIO_TOUCHRIGHT 0x32 #endif -- cgit v1.2.3 From 11ea3173d5f2de71d037ef58ac43395795fed2bc Mon Sep 17 00:00:00 2001 From: Rick Koch Date: Sat, 5 Aug 2006 00:32:30 -0400 Subject: Input: add driver for Touchwin serial touchscreens Signed-off-by: Rick Koch Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 +++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/touchwin.c | 203 +++++++++++++++++++++++++++++++++++ include/linux/serio.h | 1 + 4 files changed, 217 insertions(+) create mode 100644 drivers/input/touchscreen/touchwin.c (limited to 'include/linux') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 216db1229376..9418bbe47072 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -132,4 +132,16 @@ config TOUCHSCREEN_TOUCHRIGHT To compile this driver as a module, choose M here: the module will be called touchright. +config TOUCHSCREEN_TOUCHWIN + tristate "Touchwin serial touchscreen" + select SERIO + help + Say Y here if you have a Touchwin serial touchscreen connected to + your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called touchwin. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index deda25e36807..1abb8f10d608 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o +obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c new file mode 100644 index 000000000000..a7b4c755958e --- /dev/null +++ b/drivers/input/touchscreen/touchwin.c @@ -0,0 +1,203 @@ +/* + * Touchwindow serial touchscreen driver + * + * Copyright (c) 2006 Rick Koch + * + * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c) + * Copyright (c) 2004 Vojtech Pavlik + * and Dan Streetman + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +/* + * 2005/02/19 Rick Koch: + * The Touchwindow I used is made by Edmark Corp. and + * constantly outputs a stream of 0's unless it is touched. + * It then outputs 3 bytes: X, Y, and a copy of Y. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Touchwindow serial touchscreen driver" + +MODULE_AUTHOR("Rick Koch "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define TW_LENGTH 3 + +#define TW_MIN_XC 0 +#define TW_MAX_XC 0xff +#define TW_MIN_YC 0 +#define TW_MAX_YC 0xff + +/* + * Per-touchscreen data. + */ + +struct tw { + struct input_dev *dev; + struct serio *serio; + int idx; + int touched; + unsigned char data[TW_LENGTH]; + char phys[32]; +}; + +static irqreturn_t tw_interrupt(struct serio *serio, + unsigned char data, unsigned int flags, struct pt_regs *regs) +{ + struct tw *tw = serio_get_drvdata(serio); + struct input_dev *dev = tw->dev; + + if (data) { /* touch */ + tw->touched = 1; + tw->data[tw->idx++] = data; + /* verify length and that the two Y's are the same */ + if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) { + input_regs(dev, regs); + input_report_abs(dev, ABS_X, tw->data[0]); + input_report_abs(dev, ABS_Y, tw->data[1]); + input_report_key(dev, BTN_TOUCH, 1); + input_sync(dev); + tw->idx = 0; + } + } else if (tw->touched) { /* untouch */ + input_report_key(dev, BTN_TOUCH, 0); + input_sync(dev); + tw->idx = 0; + tw->touched = 0; + } + + return IRQ_HANDLED; +} + +/* + * tw_disconnect() is the opposite of tw_connect() + */ + +static void tw_disconnect(struct serio *serio) +{ + struct tw *tw = serio_get_drvdata(serio); + + input_get_device(tw->dev); + input_unregister_device(tw->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(tw->dev); + kfree(tw); +} + +/* + * tw_connect() is the routine that is called when someone adds a + * new serio device that supports the Touchwin protocol and registers it as + * an input device. + */ + +static int tw_connect(struct serio *serio, struct serio_driver *drv) +{ + struct tw *tw; + struct input_dev *input_dev; + int err; + + tw = kzalloc(sizeof(struct tw), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!tw || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + tw->serio = serio; + tw->dev = input_dev; + snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys); + + input_dev->private = tw; + input_dev->name = "Touchwindow Serial TouchScreen"; + input_dev->phys = tw->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_TOUCHWIN; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0); + input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0); + + serio_set_drvdata(serio, tw); + + err = serio_open(serio, drv); + if (err) + goto fail2; + + err = input_register_device(tw->dev); + if (err) + goto fail3; + + return 0; + + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(tw); + return err; +} + +/* + * The serio driver structure. + */ + +static struct serio_device_id tw_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_TOUCHWIN, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, tw_serio_ids); + +static struct serio_driver tw_drv = { + .driver = { + .name = "touchwin", + }, + .description = DRIVER_DESC, + .id_table = tw_serio_ids, + .interrupt = tw_interrupt, + .connect = tw_connect, + .disconnect = tw_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +static int __init tw_init(void) +{ + serio_register_driver(&tw_drv); + return 0; +} + +static void __exit tw_exit(void) +{ + serio_unregister_driver(&tw_drv); +} + +module_init(tw_init); +module_exit(tw_exit); diff --git a/include/linux/serio.h b/include/linux/serio.h index 152606413158..c9069310b6ac 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -219,5 +219,6 @@ static inline void serio_unpin_driver(struct serio *serio) #define SERIO_MICROTOUCH 0x30 #define SERIO_PENMOUNT 0x31 #define SERIO_TOUCHRIGHT 0x32 +#define SERIO_TOUCHWIN 0x33 #endif -- cgit v1.2.3 From 38c60ef228596c8e331437ea9287ce035706b107 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 4 Sep 2006 14:48:37 -0400 Subject: [GFS2] Use const in endian conversion routines Use const in endian conversion and printing of on-disk structures. Cc: Jan Engelhardt Signed-off-by: Steven Whitehouse --- fs/gfs2/ondisk.c | 78 ++++++++++++++++++++++----------------------- include/linux/gfs2_ondisk.h | 42 ++++++++++++------------ 2 files changed, 60 insertions(+), 60 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 03881f9870f7..1025960b0e6e 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -32,56 +32,56 @@ * first arg: the cpu-order structure */ -void gfs2_inum_in(struct gfs2_inum *no, char *buf) +void gfs2_inum_in(struct gfs2_inum *no, const void *buf) { - struct gfs2_inum *str = (struct gfs2_inum *)buf; + const struct gfs2_inum *str = buf; no->no_formal_ino = be64_to_cpu(str->no_formal_ino); no->no_addr = be64_to_cpu(str->no_addr); } -void gfs2_inum_out(const struct gfs2_inum *no, char *buf) +void gfs2_inum_out(const struct gfs2_inum *no, void *buf) { - struct gfs2_inum *str = (struct gfs2_inum *)buf; + struct gfs2_inum *str = buf; str->no_formal_ino = cpu_to_be64(no->no_formal_ino); str->no_addr = cpu_to_be64(no->no_addr); } -static void gfs2_inum_print(struct gfs2_inum *no) +static void gfs2_inum_print(const struct gfs2_inum *no) { printk(KERN_INFO " no_formal_ino = %llu\n", (unsigned long long)no->no_formal_ino); printk(KERN_INFO " no_addr = %llu\n", (unsigned long long)no->no_addr); } -static void gfs2_meta_header_in(struct gfs2_meta_header *mh, char *buf) +static void gfs2_meta_header_in(struct gfs2_meta_header *mh, const void *buf) { - struct gfs2_meta_header *str = (struct gfs2_meta_header *)buf; + const struct gfs2_meta_header *str = buf; mh->mh_magic = be32_to_cpu(str->mh_magic); mh->mh_type = be32_to_cpu(str->mh_type); mh->mh_format = be32_to_cpu(str->mh_format); } -static void gfs2_meta_header_out(struct gfs2_meta_header *mh, char *buf) +static void gfs2_meta_header_out(const struct gfs2_meta_header *mh, void *buf) { - struct gfs2_meta_header *str = (struct gfs2_meta_header *)buf; + struct gfs2_meta_header *str = buf; str->mh_magic = cpu_to_be32(mh->mh_magic); str->mh_type = cpu_to_be32(mh->mh_type); str->mh_format = cpu_to_be32(mh->mh_format); } -static void gfs2_meta_header_print(struct gfs2_meta_header *mh) +static void gfs2_meta_header_print(const struct gfs2_meta_header *mh) { pv(mh, mh_magic, "0x%.8X"); pv(mh, mh_type, "%u"); pv(mh, mh_format, "%u"); } -void gfs2_sb_in(struct gfs2_sb *sb, char *buf) +void gfs2_sb_in(struct gfs2_sb *sb, const void *buf) { - struct gfs2_sb *str = (struct gfs2_sb *)buf; + const struct gfs2_sb *str = buf; gfs2_meta_header_in(&sb->sb_header, buf); @@ -97,9 +97,9 @@ void gfs2_sb_in(struct gfs2_sb *sb, char *buf) memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN); } -void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf) +void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf) { - struct gfs2_rindex *str = (struct gfs2_rindex *)buf; + const struct gfs2_rindex *str = buf; ri->ri_addr = be64_to_cpu(str->ri_addr); ri->ri_length = be32_to_cpu(str->ri_length); @@ -109,7 +109,7 @@ void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf) } -void gfs2_rindex_print(struct gfs2_rindex *ri) +void gfs2_rindex_print(const struct gfs2_rindex *ri) { printk(KERN_INFO " ri_addr = %llu\n", (unsigned long long)ri->ri_addr); pv(ri, ri_length, "%u"); @@ -120,9 +120,9 @@ void gfs2_rindex_print(struct gfs2_rindex *ri) pv(ri, ri_bitbytes, "%u"); } -void gfs2_rgrp_in(struct gfs2_rgrp *rg, char *buf) +void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf) { - struct gfs2_rgrp *str = (struct gfs2_rgrp *)buf; + const struct gfs2_rgrp *str = buf; gfs2_meta_header_in(&rg->rg_header, buf); rg->rg_flags = be32_to_cpu(str->rg_flags); @@ -131,9 +131,9 @@ void gfs2_rgrp_in(struct gfs2_rgrp *rg, char *buf) rg->rg_igeneration = be64_to_cpu(str->rg_igeneration); } -void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf) +void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf) { - struct gfs2_rgrp *str = (struct gfs2_rgrp *)buf; + struct gfs2_rgrp *str = buf; gfs2_meta_header_out(&rg->rg_header, buf); str->rg_flags = cpu_to_be32(rg->rg_flags); @@ -144,21 +144,21 @@ void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf) memset(&str->rg_reserved, 0, sizeof(str->rg_reserved)); } -void gfs2_quota_in(struct gfs2_quota *qu, char *buf) +void gfs2_quota_in(struct gfs2_quota *qu, const void *buf) { - struct gfs2_quota *str = (struct gfs2_quota *)buf; + const struct gfs2_quota *str = buf; qu->qu_limit = be64_to_cpu(str->qu_limit); qu->qu_warn = be64_to_cpu(str->qu_warn); qu->qu_value = be64_to_cpu(str->qu_value); } -void gfs2_dinode_in(struct gfs2_dinode *di, char *buf) +void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf) { - struct gfs2_dinode *str = (struct gfs2_dinode *)buf; + const struct gfs2_dinode *str = buf; gfs2_meta_header_in(&di->di_header, buf); - gfs2_inum_in(&di->di_num, (char *)&str->di_num); + gfs2_inum_in(&di->di_num, &str->di_num); di->di_mode = be32_to_cpu(str->di_mode); di->di_uid = be32_to_cpu(str->di_uid); @@ -187,9 +187,9 @@ void gfs2_dinode_in(struct gfs2_dinode *di, char *buf) } -void gfs2_dinode_out(struct gfs2_dinode *di, char *buf) +void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf) { - struct gfs2_dinode *str = (struct gfs2_dinode *)buf; + struct gfs2_dinode *str = buf; gfs2_meta_header_out(&di->di_header, buf); gfs2_inum_out(&di->di_num, (char *)&str->di_num); @@ -221,7 +221,7 @@ void gfs2_dinode_out(struct gfs2_dinode *di, char *buf) } -void gfs2_dinode_print(struct gfs2_dinode *di) +void gfs2_dinode_print(const struct gfs2_dinode *di) { gfs2_meta_header_print(&di->di_header); gfs2_inum_print(&di->di_num); @@ -251,9 +251,9 @@ void gfs2_dinode_print(struct gfs2_dinode *di) printk(KERN_INFO " di_eattr = %llu\n", (unsigned long long)di->di_eattr); } -void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf) +void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf) { - struct gfs2_log_header *str = (struct gfs2_log_header *)buf; + const struct gfs2_log_header *str = buf; gfs2_meta_header_in(&lh->lh_header, buf); lh->lh_sequence = be64_to_cpu(str->lh_sequence); @@ -263,43 +263,43 @@ void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf) lh->lh_hash = be32_to_cpu(str->lh_hash); } -void gfs2_inum_range_in(struct gfs2_inum_range *ir, char *buf) +void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf) { - struct gfs2_inum_range *str = (struct gfs2_inum_range *)buf; + const struct gfs2_inum_range *str = buf; ir->ir_start = be64_to_cpu(str->ir_start); ir->ir_length = be64_to_cpu(str->ir_length); } -void gfs2_inum_range_out(struct gfs2_inum_range *ir, char *buf) +void gfs2_inum_range_out(const struct gfs2_inum_range *ir, void *buf) { - struct gfs2_inum_range *str = (struct gfs2_inum_range *)buf; + struct gfs2_inum_range *str = buf; str->ir_start = cpu_to_be64(ir->ir_start); str->ir_length = cpu_to_be64(ir->ir_length); } -void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, char *buf) +void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf) { - struct gfs2_statfs_change *str = (struct gfs2_statfs_change *)buf; + const struct gfs2_statfs_change *str = buf; sc->sc_total = be64_to_cpu(str->sc_total); sc->sc_free = be64_to_cpu(str->sc_free); sc->sc_dinodes = be64_to_cpu(str->sc_dinodes); } -void gfs2_statfs_change_out(struct gfs2_statfs_change *sc, char *buf) +void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf) { - struct gfs2_statfs_change *str = (struct gfs2_statfs_change *)buf; + struct gfs2_statfs_change *str = buf; str->sc_total = cpu_to_be64(sc->sc_total); str->sc_free = cpu_to_be64(sc->sc_free); str->sc_dinodes = cpu_to_be64(sc->sc_dinodes); } -void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf) +void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf) { - struct gfs2_quota_change *str = (struct gfs2_quota_change *)buf; + const struct gfs2_quota_change *str = buf; qc->qc_change = be64_to_cpu(str->qc_change); qc->qc_flags = be32_to_cpu(str->qc_flags); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 3ebd8743ce8c..a7ae7c177cac 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -413,30 +413,30 @@ struct gfs2_quota_change { #ifdef __KERNEL__ /* Translation functions */ -extern void gfs2_inum_in(struct gfs2_inum *no, char *buf); -extern void gfs2_inum_out(const struct gfs2_inum *no, char *buf); -extern void gfs2_sb_in(struct gfs2_sb *sb, char *buf); -extern void gfs2_rindex_in(struct gfs2_rindex *ri, char *buf); -extern void gfs2_rindex_out(struct gfs2_rindex *ri, char *buf); -extern void gfs2_rgrp_in(struct gfs2_rgrp *rg, char *buf); -extern void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf); -extern void gfs2_quota_in(struct gfs2_quota *qu, char *buf); -extern void gfs2_quota_out(struct gfs2_quota *qu, char *buf); -extern void gfs2_dinode_in(struct gfs2_dinode *di, char *buf); -extern void gfs2_dinode_out(struct gfs2_dinode *di, char *buf); -extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, char *buf); -extern void gfs2_ea_header_out(struct gfs2_ea_header *ea, char *buf); -extern void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf); -extern void gfs2_inum_range_in(struct gfs2_inum_range *ir, char *buf); -extern void gfs2_inum_range_out(struct gfs2_inum_range *ir, char *buf); -extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, char *buf); -extern void gfs2_statfs_change_out(struct gfs2_statfs_change *sc, char *buf); -extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, char *buf); +extern void gfs2_inum_in(struct gfs2_inum *no, const void *buf); +extern void gfs2_inum_out(const struct gfs2_inum *no, void *buf); +extern void gfs2_sb_in(struct gfs2_sb *sb, const void *buf); +extern void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf); +extern void gfs2_rindex_out(const struct gfs2_rindex *ri, void *buf); +extern void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf); +extern void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf); +extern void gfs2_quota_in(struct gfs2_quota *qu, const void *buf); +extern void gfs2_quota_out(const struct gfs2_quota *qu, void *buf); +extern void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf); +extern void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf); +extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf); +extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf); +extern void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf); +extern void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf); +extern void gfs2_inum_range_out(const struct gfs2_inum_range *ir, void *buf); +extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf); +extern void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf); +extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf); /* Printing functions */ -extern void gfs2_rindex_print(struct gfs2_rindex *ri); -extern void gfs2_dinode_print(struct gfs2_dinode *di); +extern void gfs2_rindex_print(const struct gfs2_rindex *ri); +extern void gfs2_dinode_print(const struct gfs2_dinode *di); #endif /* __KERNEL__ */ -- cgit v1.2.3 From 9807879bfdc0c2b5106b4b378f5475c6a333d853 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 14 Sep 2006 01:31:27 -0400 Subject: Input: atkbd - support Microsoft Natural Elite Pro keyboards Microsoft Natural Elite Pro keyboard produces unisual response to the GET ID command - single byte 0xaa (normally keyboards produce 2-byte response). Fail GET ID command so atkbd gets a change to do alternate probe. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 4 +--- drivers/input/serio/libps2.c | 18 ++++++++++++++++-- include/linux/libps2.h | 1 + 3 files changed, 18 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index ce1f10e8984b..9874072cf9d6 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -635,9 +635,7 @@ static int atkbd_probe(struct atkbd *atkbd) return 0; } - if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */ - param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */ - param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */ + if (!ps2_is_keyboard_id(param[0])) return -1; atkbd->id = (param[0] << 8) | param[1]; diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index ed202f2f251a..e0a2297a9d21 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -35,6 +35,7 @@ EXPORT_SYMBOL(ps2_schedule_command); EXPORT_SYMBOL(ps2_handle_ack); EXPORT_SYMBOL(ps2_handle_response); EXPORT_SYMBOL(ps2_cmd_aborted); +EXPORT_SYMBOL(ps2_is_keyboard_id); /* Work structure to schedule execution of a command */ struct ps2work { @@ -102,9 +103,9 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout) * known keyboard IDs. */ -static inline int ps2_is_keyboard_id(char id_byte) +int ps2_is_keyboard_id(char id_byte) { - static char keyboard_ids[] = { + const static char keyboard_ids[] = { 0xab, /* Regular keyboards */ 0xac, /* NCD Sun keyboard */ 0x2b, /* Trust keyboard, translated */ @@ -138,6 +139,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) break; case PS2_CMD_GETID: + /* + * Microsoft Natural Elite keyboard responds to + * the GET ID command as it were a mouse, with + * a single byte. Fail the command so atkbd will + * use alternative probe to detect it. + */ + if (ps2dev->cmdbuf[1] == 0xaa) { + serio_pause_rx(ps2dev->serio); + ps2dev->flags = 0; + serio_continue_rx(ps2dev->serio); + timeout = 0; + } + /* * If device behind the port is not a keyboard there * won't be 2nd byte of ID response. diff --git a/include/linux/libps2.h b/include/linux/libps2.h index 08a450a9dbf7..f6f301e2b0f5 100644 --- a/include/linux/libps2.h +++ b/include/linux/libps2.h @@ -47,5 +47,6 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); void ps2_cmd_aborted(struct ps2dev *ps2dev); +int ps2_is_keyboard_id(char id); #endif /* _LIBPS2_H */ -- cgit v1.2.3 From 66e66118837ed95a299328437c2d9fb4b5137352 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 14 Sep 2006 01:31:59 -0400 Subject: Input: constify input core Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 4 ++-- drivers/input/evbug.c | 8 +++++--- drivers/input/evdev.c | 7 ++++--- drivers/input/input.c | 7 ++++--- drivers/input/joydev.c | 9 +++++---- drivers/input/mousedev.c | 7 ++++--- drivers/input/power.c | 4 ++-- drivers/input/tsdev.c | 8 +++----- include/linux/input.h | 10 +++++----- 9 files changed, 34 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 30a745428a09..797480768b4e 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1285,7 +1285,7 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, */ static struct input_handle *kbd_connect(struct input_handler *handler, struct input_dev *dev, - struct input_device_id *id) + const struct input_device_id *id) { struct input_handle *handle; int i; @@ -1334,7 +1334,7 @@ static void kbd_start(struct input_handle *handle) tasklet_enable(&keyboard_tasklet); } -static struct input_device_id kbd_ids[] = { +static const struct input_device_id kbd_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT(EV_KEY) }, diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index 07358fb51b82..1d8ce7a1ec30 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -42,10 +42,12 @@ static char evbug_name[] = "evbug"; static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { - printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value); + printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", + handle->dev->phys, type, code, value); } -static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct input_handle *handle; @@ -72,7 +74,7 @@ static void evbug_disconnect(struct input_handle *handle) kfree(handle); } -static struct input_device_id evbug_ids[] = { +static const struct input_device_id evbug_ids[] = { { .driver_info = 1 }, /* Matches all devices */ { }, /* Terminating zero entry */ }; diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 12c7ab876c34..154e423167b9 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -601,7 +601,7 @@ static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned lon } #endif -static struct file_operations evdev_fops = { +static const struct file_operations evdev_fops = { .owner = THIS_MODULE, .read = evdev_read, .write = evdev_write, @@ -616,7 +616,8 @@ static struct file_operations evdev_fops = { .flush = evdev_flush }; -static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct evdev *evdev; struct class_device *cdev; @@ -675,7 +676,7 @@ static void evdev_disconnect(struct input_handle *handle) evdev_free(evdev); } -static struct input_device_id evdev_ids[] = { +static const struct input_device_id evdev_ids[] = { { .driver_info = 1 }, /* Matches all devices */ { }, /* Terminating zero entry */ }; diff --git a/drivers/input/input.c b/drivers/input/input.c index 1c71dd6fe5cd..4954c790ccb1 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -313,7 +313,8 @@ static void input_link_handle(struct input_handle *handle) if (i != NBITS(max)) \ continue; -static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev) +static const struct input_device_id *input_match_device(const struct input_device_id *id, + struct input_dev *dev) { int i; @@ -935,7 +936,7 @@ int input_register_device(struct input_dev *dev) static atomic_t input_no = ATOMIC_INIT(0); struct input_handle *handle; struct input_handler *handler; - struct input_device_id *id; + const struct input_device_id *id; const char *path; int error; @@ -1050,7 +1051,7 @@ void input_register_handler(struct input_handler *handler) { struct input_dev *dev; struct input_handle *handle; - struct input_device_id *id; + const struct input_device_id *id; if (!handler) return; diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index d67157513bf7..033e3aac92a3 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -451,7 +451,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd } } -static struct file_operations joydev_fops = { +static const struct file_operations joydev_fops = { .owner = THIS_MODULE, .read = joydev_read, .write = joydev_write, @@ -465,7 +465,8 @@ static struct file_operations joydev_fops = { .fasync = joydev_fasync, }; -static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct joydev *joydev; struct class_device *cdev; @@ -562,7 +563,7 @@ static void joydev_disconnect(struct input_handle *handle) joydev_free(joydev); } -static struct input_device_id joydev_blacklist[] = { +static const struct input_device_id joydev_blacklist[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, .evbit = { BIT(EV_KEY) }, @@ -571,7 +572,7 @@ static struct input_device_id joydev_blacklist[] = { { } /* Terminating entry */ }; -static struct input_device_id joydev_ids[] = { +static const struct input_device_id joydev_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, .evbit = { BIT(EV_ABS) }, diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 1f851acab30d..cd02f1b62b66 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -614,7 +614,7 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait) (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); } -static struct file_operations mousedev_fops = { +static const struct file_operations mousedev_fops = { .owner = THIS_MODULE, .read = mousedev_read, .write = mousedev_write, @@ -624,7 +624,8 @@ static struct file_operations mousedev_fops = { .fasync = mousedev_fasync, }; -static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct mousedev *mousedev; struct class_device *cdev; @@ -688,7 +689,7 @@ static void mousedev_disconnect(struct input_handle *handle) } } -static struct input_device_id mousedev_ids[] = { +static const struct input_device_id mousedev_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, diff --git a/drivers/input/power.c b/drivers/input/power.c index 51a519e24b6d..75d018759cd5 100644 --- a/drivers/input/power.c +++ b/drivers/input/power.c @@ -98,7 +98,7 @@ static void power_event(struct input_handle *handle, unsigned int type, static struct input_handle *power_connect(struct input_handler *handler, struct input_dev *dev, - struct input_device_id *id) + const struct input_device_id *id) { struct input_handle *handle; @@ -120,7 +120,7 @@ static void power_disconnect(struct input_handle *handle) kfree(handle); } -static struct input_device_id power_ids[] = { +static const struct input_device_id power_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, .evbit = { BIT(EV_KEY) }, diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 00e3929c6288..162ee08223a9 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -135,8 +135,6 @@ struct tsdev_list { #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) -static struct input_handler tsdev_handler; - static struct tsdev *tsdev_table[TSDEV_MINORS/2]; static int tsdev_fasync(int fd, struct file *file, int on) @@ -263,7 +261,7 @@ static int tsdev_ioctl(struct inode *inode, struct file *file, return retval; } -static struct file_operations tsdev_fops = { +static const struct file_operations tsdev_fops = { .owner = THIS_MODULE, .open = tsdev_open, .release = tsdev_release, @@ -370,7 +368,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, static struct input_handle *tsdev_connect(struct input_handler *handler, struct input_dev *dev, - struct input_device_id *id) + const struct input_device_id *id) { struct tsdev *tsdev; struct class_device *cdev; @@ -443,7 +441,7 @@ static void tsdev_disconnect(struct input_handle *handle) tsdev_free(tsdev); } -static struct input_device_id tsdev_ids[] = { +static const struct input_device_id tsdev_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, diff --git a/include/linux/input.h b/include/linux/input.h index a7a1f55a5eed..300036b7755a 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1059,16 +1059,16 @@ struct input_handler { void *private; void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); - struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id); + struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle); const struct file_operations *fops; int minor; - char *name; + const char *name; - struct input_device_id *id_table; - struct input_device_id *blacklist; + const struct input_device_id *id_table; + const struct input_device_id *blacklist; struct list_head h_list; struct list_head node; @@ -1079,7 +1079,7 @@ struct input_handle { void *private; int open; - char *name; + const char *name; struct input_dev *dev; struct input_handler *handler; -- cgit v1.2.3 From 68c2a1607cd6dd12427c9566b39756e92708713c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 14 Sep 2006 01:32:28 -0400 Subject: Input: remove cruft that was needed for transition to sysfs Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 10 ---------- include/linux/input.h | 9 --------- 2 files changed, 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/input.c b/drivers/input/input.c index f2c85a60a0dc..c3448364cc73 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -906,7 +906,6 @@ struct input_dev *input_allocate_device(void) dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); if (dev) { - dev->dynalloc = 1; dev->cdev.class = &input_class; class_device_initialize(&dev->cdev); mutex_init(&dev->mutex); @@ -942,13 +941,6 @@ int input_register_device(struct input_dev *dev) const char *path; int error; - if (!dev->dynalloc) { - printk(KERN_WARNING "input: device %s is statically allocated, will not register\n" - "Please convert to input_allocate_device() or contact dtor_core@ameritech.net\n", - dev->name ? dev->name : ""); - return -EINVAL; - } - set_bit(EV_SYN, dev->evbit); /* @@ -964,10 +956,8 @@ int input_register_device(struct input_dev *dev) dev->rep[REP_PERIOD] = 33; } - INIT_LIST_HEAD(&dev->h_list); list_add_tail(&dev->node, &input_dev_list); - dev->cdev.class = &input_class; snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); diff --git a/include/linux/input.h b/include/linux/input.h index 300036b7755a..155b2bc96842 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -978,9 +978,6 @@ struct input_dev { unsigned int users; struct class_device cdev; - struct device *dev; /* will be removed soon */ - - int dynalloc; /* temporarily */ struct list_head h_list; struct list_head node; @@ -1093,12 +1090,6 @@ struct input_handle { #define to_handle(n) container_of(n,struct input_handle,d_node) #define to_handle_h(n) container_of(n,struct input_handle,h_node) -static inline void init_input_dev(struct input_dev *dev) -{ - INIT_LIST_HEAD(&dev->h_list); - INIT_LIST_HEAD(&dev->node); -} - struct input_dev *input_allocate_device(void); void input_free_device(struct input_dev *dev); -- cgit v1.2.3 From 4263cf0fac28122c8381b6f4f9441a43cd93c81f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 14 Sep 2006 01:32:39 -0400 Subject: Input: make input_register_handler() return error codes Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 5 ++++- drivers/input/evbug.c | 3 +-- drivers/input/evdev.c | 3 +-- drivers/input/input.c | 12 +++++++----- drivers/input/joydev.c | 3 +-- drivers/input/mousedev.c | 21 +++++++++++++++++---- drivers/input/power.c | 3 +-- drivers/input/tsdev.c | 4 +--- include/linux/input.h | 2 +- 9 files changed, 34 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 797480768b4e..bf2339c869ea 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1362,6 +1362,7 @@ static struct input_handler kbd_handler = { int __init kbd_init(void) { int i; + int error; for (i = 0; i < MAX_NR_CONSOLES; i++) { kbd_table[i].ledflagstate = KBD_DEFLEDS; @@ -1373,7 +1374,9 @@ int __init kbd_init(void) kbd_table[i].kbdmode = VC_XLATE; } - input_register_handler(&kbd_handler); + error = input_register_handler(&kbd_handler); + if (error) + return error; tasklet_enable(&keyboard_tasklet); tasklet_schedule(&keyboard_tasklet); diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index 1d8ce7a1ec30..5a9653c3128a 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -91,8 +91,7 @@ static struct input_handler evbug_handler = { static int __init evbug_init(void) { - input_register_handler(&evbug_handler); - return 0; + return input_register_handler(&evbug_handler); } static void __exit evbug_exit(void) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 154e423167b9..6439f378f6cc 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -695,8 +695,7 @@ static struct input_handler evdev_handler = { static int __init evdev_init(void) { - input_register_handler(&evdev_handler); - return 0; + return input_register_handler(&evdev_handler); } static void __exit evdev_exit(void) diff --git a/drivers/input/input.c b/drivers/input/input.c index c3448364cc73..1c8c8a5bc4a9 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1037,19 +1037,20 @@ void input_unregister_device(struct input_dev *dev) } EXPORT_SYMBOL(input_unregister_device); -void input_register_handler(struct input_handler *handler) +int input_register_handler(struct input_handler *handler) { struct input_dev *dev; struct input_handle *handle; const struct input_device_id *id; - if (!handler) - return; - INIT_LIST_HEAD(&handler->h_list); - if (handler->fops != NULL) + if (handler->fops != NULL) { + if (input_table[handler->minor >> 5]) + return -EBUSY; + input_table[handler->minor >> 5] = handler; + } list_add_tail(&handler->node, &input_handler_list); @@ -1063,6 +1064,7 @@ void input_register_handler(struct input_handler *handler) } input_wakeup_procfs_readers(); + return 0; } EXPORT_SYMBOL(input_register_handler); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 033e3aac92a3..9f3529ad3fda 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -606,8 +606,7 @@ static struct input_handler joydev_handler = { static int __init joydev_init(void) { - input_register_handler(&joydev_handler); - return 0; + return input_register_handler(&joydev_handler); } static void __exit joydev_exit(void) diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index cd02f1b62b66..a22a74a2a3dc 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -738,7 +738,12 @@ static int psaux_registered; static int __init mousedev_init(void) { - input_register_handler(&mousedev_handler); + struct class_device *cdev; + int error; + + error = input_register_handler(&mousedev_handler); + if (error) + return error; memset(&mousedev_mix, 0, sizeof(struct mousedev)); INIT_LIST_HEAD(&mousedev_mix.list); @@ -747,12 +752,20 @@ static int __init mousedev_init(void) mousedev_mix.exist = 1; mousedev_mix.minor = MOUSEDEV_MIX; - class_device_create(&input_class, NULL, + cdev = class_device_create(&input_class, NULL, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); + if (IS_ERR(cdev)) { + input_unregister_handler(&mousedev_handler); + return PTR_ERR(cdev); + } #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX - if (!(psaux_registered = !misc_register(&psaux_mouse))) - printk(KERN_WARNING "mice: could not misc_register the device\n"); + error = misc_register(&psaux_mouse); + if (error) + printk(KERN_WARNING "mice: could not register psaux device, " + "error: %d\n", error); + else + psaux_registered = 1; #endif printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); diff --git a/drivers/input/power.c b/drivers/input/power.c index 75d018759cd5..ee82464a2fa7 100644 --- a/drivers/input/power.c +++ b/drivers/input/power.c @@ -150,8 +150,7 @@ static struct input_handler power_handler = { static int __init power_init(void) { - input_register_handler(&power_handler); - return 0; + return input_register_handler(&power_handler); } static void __exit power_exit(void) diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 162ee08223a9..a730c461227f 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -479,9 +479,7 @@ static struct input_handler tsdev_handler = { static int __init tsdev_init(void) { - input_register_handler(&tsdev_handler); - printk(KERN_INFO "ts: Compaq touchscreen protocol output\n"); - return 0; + return input_register_handler(&tsdev_handler); } static void __exit tsdev_exit(void) diff --git a/include/linux/input.h b/include/linux/input.h index 155b2bc96842..7025432350fa 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1106,7 +1106,7 @@ static inline void input_put_device(struct input_dev *dev) int input_register_device(struct input_dev *); void input_unregister_device(struct input_dev *); -void input_register_handler(struct input_handler *); +int input_register_handler(struct input_handler *); void input_unregister_handler(struct input_handler *); int input_grab_device(struct input_handle *); -- cgit v1.2.3 From 132919ba80ad207755fe271277bfefff865a54fe Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 27 Aug 2006 13:56:52 +0100 Subject: [MMC] Remove data->blksz_bits member data->blksz_bits is unused now - remove it. Signed-off-by: Russell King --- drivers/mmc/mmc.c | 1 - drivers/mmc/mmc_block.c | 1 - include/linux/mmc/mmc.h | 1 - 3 files changed, 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 74eaaee66de0..5b9caa7978d3 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -996,7 +996,6 @@ static void mmc_read_scrs(struct mmc_host *host) mmc_set_data_timeout(&data, card, 0); - data.blksz_bits = 3; data.blksz = 1 << 3; data.blocks = 1; data.flags = MMC_DATA_READ; diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index a0e0dad1b419..f3a99dd8df8f 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -172,7 +172,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.cmd.arg = req->sector << 9; brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - brq.data.blksz_bits = md->block_bits; brq.data.blksz = 1 << md->block_bits; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); brq.stop.opcode = MMC_STOP_TRANSMISSION; diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 627e2c08ce41..a3594dfd6963 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -68,7 +68,6 @@ struct mmc_command { struct mmc_data { unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */ unsigned int timeout_clks; /* data timeout (in clocks) */ - unsigned int blksz_bits; /* data block size */ unsigned int blksz; /* data block size */ unsigned int blocks; /* number of blocks */ unsigned int error; /* data error */ -- cgit v1.2.3 From db53f28b3a6d9338cca1b7e917dc063ac99e1871 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 30 Aug 2006 15:14:56 +0100 Subject: [MMC] Add multi block-write capability Add a capability flag for drivers to set when they can perform multi- block transfers to cards _and_ correctly report the number of bytes transferred should an error occur. The last point is very important - if a driver reports more bytes than were actually accepted by the card and an error occurs, there is the possibility for data loss. Pierre Ossman provided the patch for wbsd and sdhci. Signed-off-by: Pierre Ossman Signed-off-by: Russell King --- drivers/mmc/mmc_block.c | 27 ++++++++++++++++++++------- drivers/mmc/mmci.c | 1 + drivers/mmc/sdhci.c | 2 +- drivers/mmc/wbsd.c | 2 +- include/linux/mmc/host.h | 1 + 5 files changed, 24 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index f3a99dd8df8f..8d18b87bfd34 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -165,6 +166,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) do { struct mmc_blk_request brq; struct mmc_command cmd; + u32 readcmd, writecmd; memset(&brq, 0, sizeof(struct mmc_blk_request)); brq.mrq.cmd = &brq.cmd; @@ -180,20 +182,31 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); - if (rq_data_dir(req) == READ) { - brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK; - brq.data.flags |= MMC_DATA_READ; - } else { - brq.cmd.opcode = MMC_WRITE_BLOCK; - brq.data.flags |= MMC_DATA_WRITE; + /* + * If the host doesn't support multiple block writes, force + * block writes to single block. + */ + if (rq_data_dir(req) != READ && + !(card->host->caps & MMC_CAP_MULTIWRITE)) brq.data.blocks = 1; - } if (brq.data.blocks > 1) { brq.data.flags |= MMC_DATA_MULTI; brq.mrq.stop = &brq.stop; + readcmd = MMC_READ_MULTIPLE_BLOCK; + writecmd = MMC_WRITE_MULTIPLE_BLOCK; } else { brq.mrq.stop = NULL; + readcmd = MMC_READ_SINGLE_BLOCK; + writecmd = MMC_WRITE_BLOCK; + } + + if (rq_data_dir(req) == READ) { + brq.cmd.opcode = readcmd; + brq.data.flags |= MMC_DATA_READ; + } else { + brq.cmd.opcode = writecmd; + brq.data.flags |= MMC_DATA_WRITE; } brq.data.sg = mq->sg; diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 8419489e7744..2b5a0cc9ea56 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -509,6 +509,7 @@ static int mmci_probe(struct amba_device *dev, void *id) mmc->f_min = (host->mclk + 511) / 512; mmc->f_max = min(host->mclk, fmax); mmc->ocr_avail = plat->ocr_mask; + mmc->caps = MMC_CAP_MULTIWRITE; /* * We can do SGIO diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 4e21b3b9d330..dea4edd1c434 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -1262,7 +1262,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) mmc->ops = &sdhci_ops; mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; - mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; mmc->ocr_avail = 0; if (caps & SDHCI_CAN_VDD_330) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index c351c6d1a18a..4a6617d9a49f 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1323,7 +1323,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev) mmc->f_min = 375000; mmc->f_max = 24000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; spin_lock_init(&host->lock); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index ba095aebedff..b282ec9bba08 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -85,6 +85,7 @@ struct mmc_host { unsigned long caps; /* Host capabilities */ #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */ +#define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ -- cgit v1.2.3 From 9a87fdded5742a9d14780e5dfd9c940d7862e0ec Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Tue, 19 Sep 2006 01:59:49 -0400 Subject: Input: add new BUS_VIRTUAL bus type BUS_VIRTUAL can be used when creating virtual devices using uinput driver. Note that when uinput is used to drive a real piece of hardware "real" bus type (such as BUS_USB, BUS_BLUETOOTH) should be specified. Signed-off-by: Michael Hanselmann Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/input.h b/include/linux/input.h index 7025432350fa..22a361040547 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -645,6 +645,7 @@ struct input_absinfo { #define BUS_USB 0x03 #define BUS_HIL 0x04 #define BUS_BLUETOOTH 0x05 +#define BUS_VIRTUAL 0x06 #define BUS_ISA 0x10 #define BUS_I8042 0x11 -- cgit v1.2.3 From 90da11514562020ea7d697982f912ac949adc317 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Sep 2006 01:59:55 -0400 Subject: Input: add KEY_BLUETOOTH and KEY_WLAN definitions Some laptops have separate "rfkill" buttons for disabling/enabling Bluetooth and WLAN. Signed-off-by: Lennart Poettering Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/input.h b/include/linux/input.h index 22a361040547..5770105471dd 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -349,6 +349,9 @@ struct input_absinfo { #define KEY_BATTERY 236 +#define KEY_BLUETOOTH 237 +#define KEY_WLAN 238 + #define KEY_UNKNOWN 240 #define BTN_MISC 0x100 -- cgit v1.2.3 From 7d308590ae60d1f038a54a94e78a385c5c163452 Mon Sep 17 00:00:00 2001 From: Fabio Massimo Di Nitto Date: Tue, 19 Sep 2006 07:56:29 +0200 Subject: [GFS2] Export lm_interface to kernel headers lm_interface.h has a few out of the tree clients such as GFS1 and userland tools. Right now, these clients keeps a copy of the file in their build tree that can go out of sync. Move lm_interface.h to include/linux, export it to userland and clean up fs/gfs2 to use the new location. Signed-off-by: Fabio M. Di Nitto Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 2 +- fs/gfs2/bmap.c | 2 +- fs/gfs2/daemon.c | 2 +- fs/gfs2/dir.c | 2 +- fs/gfs2/eaops.c | 2 +- fs/gfs2/eattr.c | 2 +- fs/gfs2/glock.c | 2 +- fs/gfs2/glops.c | 2 +- fs/gfs2/inode.c | 2 +- fs/gfs2/lm.c | 2 +- fs/gfs2/lm_interface.h | 273 ----------------------------------------- fs/gfs2/locking.c | 3 +- fs/gfs2/locking/dlm/lock_dlm.h | 2 +- fs/gfs2/locking/nolock/main.c | 3 +- fs/gfs2/log.c | 2 +- fs/gfs2/lops.c | 2 +- fs/gfs2/main.c | 2 +- fs/gfs2/meta_io.c | 2 +- fs/gfs2/mount.c | 2 +- fs/gfs2/ops_address.c | 2 +- fs/gfs2/ops_dentry.c | 2 +- fs/gfs2/ops_export.c | 2 +- fs/gfs2/ops_file.c | 2 +- fs/gfs2/ops_fstype.c | 2 +- fs/gfs2/ops_inode.c | 2 +- fs/gfs2/ops_super.c | 2 +- fs/gfs2/ops_vm.c | 2 +- fs/gfs2/quota.c | 2 +- fs/gfs2/recovery.c | 2 +- fs/gfs2/rgrp.c | 2 +- fs/gfs2/super.c | 2 +- fs/gfs2/sys.c | 2 +- fs/gfs2/trans.c | 2 +- fs/gfs2/util.c | 2 +- include/linux/Kbuild | 6 +- include/linux/lm_interface.h | 273 +++++++++++++++++++++++++++++++++++++++++ 36 files changed, 309 insertions(+), 311 deletions(-) delete mode 100644 fs/gfs2/lm_interface.h create mode 100644 include/linux/lm_interface.h (limited to 'include/linux') diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index d846b5ad1d87..3123fc071233 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -15,9 +15,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "acl.h" #include "eaops.h" diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index bd5bc887ef9b..19b9bfc10349 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -14,9 +14,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "bmap.h" #include "glock.h" diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index a2a07c41845d..a9908cd78cd9 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -15,9 +15,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "daemon.h" #include "glock.h" diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index f3dbda216caf..739028688270 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -61,9 +61,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "dir.h" #include "glock.h" diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index adb898ceaa18..1a7877fe7393 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -14,10 +14,10 @@ #include #include #include +#include #include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "acl.h" #include "eaops.h" diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index d7b92fba6998..698942ec7c99 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -14,10 +14,10 @@ #include #include #include +#include #include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "acl.h" #include "eaops.h" diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 64a1676e5f48..f98694e7d668 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -18,10 +18,10 @@ #include #include #include +#include #include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "glock.h" #include "glops.h" diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index d3aef74ea5d4..9c046dbf4729 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -13,9 +13,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "bmap.h" #include "glock.h" diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 0d010f0654d9..b9e4bcb3bf1e 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -16,9 +16,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "acl.h" #include "bmap.h" diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index 4e23aa5ef75d..2109fc4791d4 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -14,9 +14,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "glock.h" #include "lm.h" diff --git a/fs/gfs2/lm_interface.h b/fs/gfs2/lm_interface.h deleted file mode 100644 index 1418fdc9ac02..000000000000 --- a/fs/gfs2/lm_interface.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#ifndef __LM_INTERFACE_DOT_H__ -#define __LM_INTERFACE_DOT_H__ - - -typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); - -/* - * lm_mount() flags - * - * LM_MFLAG_SPECTATOR - * GFS is asking to join the filesystem's lockspace, but it doesn't want to - * modify the filesystem. The lock module shouldn't assign a journal to the FS - * mount. It shouldn't send recovery callbacks to the FS mount. If the node - * dies or withdraws, all locks can be wiped immediately. - */ - -#define LM_MFLAG_SPECTATOR 0x00000001 - -/* - * lm_lockstruct flags - * - * LM_LSFLAG_LOCAL - * The lock_nolock module returns LM_LSFLAG_LOCAL to GFS, indicating that GFS - * can make single-node optimizations. - */ - -#define LM_LSFLAG_LOCAL 0x00000001 - -/* - * lm_lockname types - */ - -#define LM_TYPE_RESERVED 0x00 -#define LM_TYPE_NONDISK 0x01 -#define LM_TYPE_INODE 0x02 -#define LM_TYPE_RGRP 0x03 -#define LM_TYPE_META 0x04 -#define LM_TYPE_IOPEN 0x05 -#define LM_TYPE_FLOCK 0x06 -#define LM_TYPE_PLOCK 0x07 -#define LM_TYPE_QUOTA 0x08 -#define LM_TYPE_JOURNAL 0x09 - -/* - * lm_lock() states - * - * SHARED is compatible with SHARED, not with DEFERRED or EX. - * DEFERRED is compatible with DEFERRED, not with SHARED or EX. - */ - -#define LM_ST_UNLOCKED 0 -#define LM_ST_EXCLUSIVE 1 -#define LM_ST_DEFERRED 2 -#define LM_ST_SHARED 3 - -/* - * lm_lock() flags - * - * LM_FLAG_TRY - * Don't wait to acquire the lock if it can't be granted immediately. - * - * LM_FLAG_TRY_1CB - * Send one blocking callback if TRY is set and the lock is not granted. - * - * LM_FLAG_NOEXP - * GFS sets this flag on lock requests it makes while doing journal recovery. - * These special requests should not be blocked due to the recovery like - * ordinary locks would be. - * - * LM_FLAG_ANY - * A SHARED request may also be granted in DEFERRED, or a DEFERRED request may - * also be granted in SHARED. The preferred state is whichever is compatible - * with other granted locks, or the specified state if no other locks exist. - * - * LM_FLAG_PRIORITY - * Override fairness considerations. Suppose a lock is held in a shared state - * and there is a pending request for the deferred state. A shared lock - * request with the priority flag would be allowed to bypass the deferred - * request and directly join the other shared lock. A shared lock request - * without the priority flag might be forced to wait until the deferred - * requested had acquired and released the lock. - */ - -#define LM_FLAG_TRY 0x00000001 -#define LM_FLAG_TRY_1CB 0x00000002 -#define LM_FLAG_NOEXP 0x00000004 -#define LM_FLAG_ANY 0x00000008 -#define LM_FLAG_PRIORITY 0x00000010 - -/* - * lm_lock() and lm_async_cb return flags - * - * LM_OUT_ST_MASK - * Masks the lower two bits of lock state in the returned value. - * - * LM_OUT_CACHEABLE - * The lock hasn't been released so GFS can continue to cache data for it. - * - * LM_OUT_CANCELED - * The lock request was canceled. - * - * LM_OUT_ASYNC - * The result of the request will be returned in an LM_CB_ASYNC callback. - */ - -#define LM_OUT_ST_MASK 0x00000003 -#define LM_OUT_CACHEABLE 0x00000004 -#define LM_OUT_CANCELED 0x00000008 -#define LM_OUT_ASYNC 0x00000080 -#define LM_OUT_ERROR 0x00000100 - -/* - * lm_callback_t types - * - * LM_CB_NEED_E LM_CB_NEED_D LM_CB_NEED_S - * Blocking callback, a remote node is requesting the given lock in - * EXCLUSIVE, DEFERRED, or SHARED. - * - * LM_CB_NEED_RECOVERY - * The given journal needs to be recovered. - * - * LM_CB_DROPLOCKS - * Reduce the number of cached locks. - * - * LM_CB_ASYNC - * The given lock has been granted. - */ - -#define LM_CB_NEED_E 257 -#define LM_CB_NEED_D 258 -#define LM_CB_NEED_S 259 -#define LM_CB_NEED_RECOVERY 260 -#define LM_CB_DROPLOCKS 261 -#define LM_CB_ASYNC 262 - -/* - * lm_recovery_done() messages - */ - -#define LM_RD_GAVEUP 308 -#define LM_RD_SUCCESS 309 - - -struct lm_lockname { - u64 ln_number; - unsigned int ln_type; -}; - -#define lm_name_equal(name1, name2) \ - (((name1)->ln_number == (name2)->ln_number) && \ - ((name1)->ln_type == (name2)->ln_type)) \ - -struct lm_async_cb { - struct lm_lockname lc_name; - int lc_ret; -}; - -struct lm_lockstruct; - -struct lm_lockops { - const char *lm_proto_name; - - /* - * Mount/Unmount - */ - - int (*lm_mount) (char *table_name, char *host_data, - lm_callback_t cb, void *cb_data, - unsigned int min_lvb_size, int flags, - struct lm_lockstruct *lockstruct, - struct kobject *fskobj); - - void (*lm_others_may_mount) (void *lockspace); - - void (*lm_unmount) (void *lockspace); - - void (*lm_withdraw) (void *lockspace); - - /* - * Lock oriented operations - */ - - int (*lm_get_lock) (void *lockspace, struct lm_lockname *name, void **lockp); - - void (*lm_put_lock) (void *lock); - - unsigned int (*lm_lock) (void *lock, unsigned int cur_state, - unsigned int req_state, unsigned int flags); - - unsigned int (*lm_unlock) (void *lock, unsigned int cur_state); - - void (*lm_cancel) (void *lock); - - int (*lm_hold_lvb) (void *lock, char **lvbp); - void (*lm_unhold_lvb) (void *lock, char *lvb); - - /* - * Posix Lock oriented operations - */ - - int (*lm_plock_get) (void *lockspace, struct lm_lockname *name, - struct file *file, struct file_lock *fl); - - int (*lm_plock) (void *lockspace, struct lm_lockname *name, - struct file *file, int cmd, struct file_lock *fl); - - int (*lm_punlock) (void *lockspace, struct lm_lockname *name, - struct file *file, struct file_lock *fl); - - /* - * Client oriented operations - */ - - void (*lm_recovery_done) (void *lockspace, unsigned int jid, - unsigned int message); - - struct module *lm_owner; -}; - -/* - * lm_mount() return values - * - * ls_jid - the journal ID this node should use - * ls_first - this node is the first to mount the file system - * ls_lvb_size - size in bytes of lock value blocks - * ls_lockspace - lock module's context for this file system - * ls_ops - lock module's functions - * ls_flags - lock module features - */ - -struct lm_lockstruct { - unsigned int ls_jid; - unsigned int ls_first; - unsigned int ls_lvb_size; - void *ls_lockspace; - const struct lm_lockops *ls_ops; - int ls_flags; -}; - -/* - * Lock module bottom interface. A lock module makes itself available to GFS - * with these functions. - */ - -int gfs2_register_lockproto(const struct lm_lockops *proto); -void gfs2_unregister_lockproto(const struct lm_lockops *proto); - -/* - * Lock module top interface. GFS calls these functions when mounting or - * unmounting a file system. - */ - -int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, - lm_callback_t cb, void *cb_data, - unsigned int min_lvb_size, int flags, - struct lm_lockstruct *lockstruct, - struct kobject *fskobj); - -void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct); - -void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct); - -#endif /* __LM_INTERFACE_DOT_H__ */ - diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c index 65eca48b2eae..663fee728783 100644 --- a/fs/gfs2/locking.c +++ b/fs/gfs2/locking.c @@ -16,8 +16,7 @@ #include #include #include - -#include "lm_interface.h" +#include struct lmh_wrapper { struct list_head lw_list; diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index 3a45c020d01e..33af707a4d3f 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -26,7 +26,7 @@ #include #include -#include "../../lm_interface.h" +#include /* * Internally, we prefix things with gdlm_ and GDLM_ (for gfs-dlm) since a diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index 7b263fc6c273..acfbc941f319 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -14,8 +14,7 @@ #include #include #include - -#include "../../lm_interface.h" +#include struct nolock_lockspace { unsigned int nl_lvb_size; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index ab341cd0a76a..08b80b263ade 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -14,9 +14,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "bmap.h" #include "glock.h" diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index f8f6d4b56a01..e44d245d51d4 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -13,9 +13,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "glock.h" #include "log.h" diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index d2867988cc34..7903be735fe9 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -15,10 +15,10 @@ #include #include #include +#include #include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "ops_fstype.h" #include "sys.h" diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 6af3521339fc..a5630ec6c045 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -18,9 +18,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "glock.h" #include "glops.h" diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index 257c4a179dc6..ef3092e29607 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -13,9 +13,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "mount.h" #include "sys.h" diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 7cd53d118c89..91ec8080eeb2 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -17,9 +17,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "bmap.h" #include "glock.h" diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index fa6ceffc7d82..00041b1b8025 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -15,9 +15,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "dir.h" #include "glock.h" diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 470e8829e7f4..86127d93bd35 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -14,9 +14,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "dir.h" #include "glock.h" diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index b551074a3c98..80f3ff0bba7b 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -22,10 +22,10 @@ #include #include #include +#include #include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "bmap.h" #include "dir.h" diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index e8b7a1ae163b..e32a6b242e0c 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -17,9 +17,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "daemon.h" #include "glock.h" diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 2f38313b4bd5..bb2ef6a86533 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -19,10 +19,10 @@ #include #include #include +#include #include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "acl.h" #include "bmap.h" diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 975e93b7992e..f9538849c418 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -19,9 +19,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "glock.h" #include "inode.h" diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 3b3463144126..5453d2947ab3 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -15,9 +15,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "bmap.h" #include "glock.h" diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index bc9ad058d20e..c5eb6c646177 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -44,9 +44,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "bmap.h" #include "glock.h" diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 130e9fbf9692..518f9128137e 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -14,9 +14,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "bmap.h" #include "glock.h" diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 7a5ab817ad9c..113b4ace6893 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -14,9 +14,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "glock.h" #include "glops.h" diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f1d07d987c7b..fe207a3e206e 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -15,9 +15,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "bmap.h" #include "dir.h" diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index c9b23084918f..0e0ec988f731 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -15,10 +15,10 @@ #include #include #include +#include #include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "lm.h" #include "sys.h" diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index acf840160d5f..f8dabf8446bb 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -14,9 +14,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "glock.h" #include "log.h" diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index d72eb8addc7a..196c604faadc 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -14,10 +14,10 @@ #include #include #include +#include #include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "glock.h" #include "lm.h" diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 2121cde187d8..d8e720f9c21a 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -45,9 +45,9 @@ unifdef-y += acct.h adb.h adfs_fs.h agpgart.h apm_bios.h atalk.h \ inet_diag.h in.h inotify.h input.h ipc.h ipmi.h ipv6.h \ ipv6_route.h isdn.h isdnif.h isdn_ppp.h isicom.h jbd.h \ joystick.h kdev_t.h kd.h kernelcapi.h kernel.h keyboard.h \ - llc.h loop.h lp.h mempolicy.h mii.h mman.h mroute.h msdos_fs.h \ - msg.h nbd.h ncp_fs.h ncp.h ncp_mount.h netdevice.h \ - netfilter_bridge.h netfilter_decnet.h netfilter.h \ + llc.h lm_interface.h loop.h lp.h mempolicy.h mii.h mman.h \ + mroute.h msdos_fs.h msg.h nbd.h ncp_fs.h ncp.h ncp_mount.h \ + netdevice.h netfilter_bridge.h netfilter_decnet.h netfilter.h \ netfilter_ipv4.h netfilter_ipv6.h netfilter_logging.h net.h \ netlink.h nfs3.h nfs4.h nfsacl.h nfs_fs.h nfs.h nfs_idmap.h \ n_r3964.h nubus.h nvram.h parport.h patchkey.h pci.h pktcdvd.h \ diff --git a/include/linux/lm_interface.h b/include/linux/lm_interface.h new file mode 100644 index 000000000000..1418fdc9ac02 --- /dev/null +++ b/include/linux/lm_interface.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#ifndef __LM_INTERFACE_DOT_H__ +#define __LM_INTERFACE_DOT_H__ + + +typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); + +/* + * lm_mount() flags + * + * LM_MFLAG_SPECTATOR + * GFS is asking to join the filesystem's lockspace, but it doesn't want to + * modify the filesystem. The lock module shouldn't assign a journal to the FS + * mount. It shouldn't send recovery callbacks to the FS mount. If the node + * dies or withdraws, all locks can be wiped immediately. + */ + +#define LM_MFLAG_SPECTATOR 0x00000001 + +/* + * lm_lockstruct flags + * + * LM_LSFLAG_LOCAL + * The lock_nolock module returns LM_LSFLAG_LOCAL to GFS, indicating that GFS + * can make single-node optimizations. + */ + +#define LM_LSFLAG_LOCAL 0x00000001 + +/* + * lm_lockname types + */ + +#define LM_TYPE_RESERVED 0x00 +#define LM_TYPE_NONDISK 0x01 +#define LM_TYPE_INODE 0x02 +#define LM_TYPE_RGRP 0x03 +#define LM_TYPE_META 0x04 +#define LM_TYPE_IOPEN 0x05 +#define LM_TYPE_FLOCK 0x06 +#define LM_TYPE_PLOCK 0x07 +#define LM_TYPE_QUOTA 0x08 +#define LM_TYPE_JOURNAL 0x09 + +/* + * lm_lock() states + * + * SHARED is compatible with SHARED, not with DEFERRED or EX. + * DEFERRED is compatible with DEFERRED, not with SHARED or EX. + */ + +#define LM_ST_UNLOCKED 0 +#define LM_ST_EXCLUSIVE 1 +#define LM_ST_DEFERRED 2 +#define LM_ST_SHARED 3 + +/* + * lm_lock() flags + * + * LM_FLAG_TRY + * Don't wait to acquire the lock if it can't be granted immediately. + * + * LM_FLAG_TRY_1CB + * Send one blocking callback if TRY is set and the lock is not granted. + * + * LM_FLAG_NOEXP + * GFS sets this flag on lock requests it makes while doing journal recovery. + * These special requests should not be blocked due to the recovery like + * ordinary locks would be. + * + * LM_FLAG_ANY + * A SHARED request may also be granted in DEFERRED, or a DEFERRED request may + * also be granted in SHARED. The preferred state is whichever is compatible + * with other granted locks, or the specified state if no other locks exist. + * + * LM_FLAG_PRIORITY + * Override fairness considerations. Suppose a lock is held in a shared state + * and there is a pending request for the deferred state. A shared lock + * request with the priority flag would be allowed to bypass the deferred + * request and directly join the other shared lock. A shared lock request + * without the priority flag might be forced to wait until the deferred + * requested had acquired and released the lock. + */ + +#define LM_FLAG_TRY 0x00000001 +#define LM_FLAG_TRY_1CB 0x00000002 +#define LM_FLAG_NOEXP 0x00000004 +#define LM_FLAG_ANY 0x00000008 +#define LM_FLAG_PRIORITY 0x00000010 + +/* + * lm_lock() and lm_async_cb return flags + * + * LM_OUT_ST_MASK + * Masks the lower two bits of lock state in the returned value. + * + * LM_OUT_CACHEABLE + * The lock hasn't been released so GFS can continue to cache data for it. + * + * LM_OUT_CANCELED + * The lock request was canceled. + * + * LM_OUT_ASYNC + * The result of the request will be returned in an LM_CB_ASYNC callback. + */ + +#define LM_OUT_ST_MASK 0x00000003 +#define LM_OUT_CACHEABLE 0x00000004 +#define LM_OUT_CANCELED 0x00000008 +#define LM_OUT_ASYNC 0x00000080 +#define LM_OUT_ERROR 0x00000100 + +/* + * lm_callback_t types + * + * LM_CB_NEED_E LM_CB_NEED_D LM_CB_NEED_S + * Blocking callback, a remote node is requesting the given lock in + * EXCLUSIVE, DEFERRED, or SHARED. + * + * LM_CB_NEED_RECOVERY + * The given journal needs to be recovered. + * + * LM_CB_DROPLOCKS + * Reduce the number of cached locks. + * + * LM_CB_ASYNC + * The given lock has been granted. + */ + +#define LM_CB_NEED_E 257 +#define LM_CB_NEED_D 258 +#define LM_CB_NEED_S 259 +#define LM_CB_NEED_RECOVERY 260 +#define LM_CB_DROPLOCKS 261 +#define LM_CB_ASYNC 262 + +/* + * lm_recovery_done() messages + */ + +#define LM_RD_GAVEUP 308 +#define LM_RD_SUCCESS 309 + + +struct lm_lockname { + u64 ln_number; + unsigned int ln_type; +}; + +#define lm_name_equal(name1, name2) \ + (((name1)->ln_number == (name2)->ln_number) && \ + ((name1)->ln_type == (name2)->ln_type)) \ + +struct lm_async_cb { + struct lm_lockname lc_name; + int lc_ret; +}; + +struct lm_lockstruct; + +struct lm_lockops { + const char *lm_proto_name; + + /* + * Mount/Unmount + */ + + int (*lm_mount) (char *table_name, char *host_data, + lm_callback_t cb, void *cb_data, + unsigned int min_lvb_size, int flags, + struct lm_lockstruct *lockstruct, + struct kobject *fskobj); + + void (*lm_others_may_mount) (void *lockspace); + + void (*lm_unmount) (void *lockspace); + + void (*lm_withdraw) (void *lockspace); + + /* + * Lock oriented operations + */ + + int (*lm_get_lock) (void *lockspace, struct lm_lockname *name, void **lockp); + + void (*lm_put_lock) (void *lock); + + unsigned int (*lm_lock) (void *lock, unsigned int cur_state, + unsigned int req_state, unsigned int flags); + + unsigned int (*lm_unlock) (void *lock, unsigned int cur_state); + + void (*lm_cancel) (void *lock); + + int (*lm_hold_lvb) (void *lock, char **lvbp); + void (*lm_unhold_lvb) (void *lock, char *lvb); + + /* + * Posix Lock oriented operations + */ + + int (*lm_plock_get) (void *lockspace, struct lm_lockname *name, + struct file *file, struct file_lock *fl); + + int (*lm_plock) (void *lockspace, struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl); + + int (*lm_punlock) (void *lockspace, struct lm_lockname *name, + struct file *file, struct file_lock *fl); + + /* + * Client oriented operations + */ + + void (*lm_recovery_done) (void *lockspace, unsigned int jid, + unsigned int message); + + struct module *lm_owner; +}; + +/* + * lm_mount() return values + * + * ls_jid - the journal ID this node should use + * ls_first - this node is the first to mount the file system + * ls_lvb_size - size in bytes of lock value blocks + * ls_lockspace - lock module's context for this file system + * ls_ops - lock module's functions + * ls_flags - lock module features + */ + +struct lm_lockstruct { + unsigned int ls_jid; + unsigned int ls_first; + unsigned int ls_lvb_size; + void *ls_lockspace; + const struct lm_lockops *ls_ops; + int ls_flags; +}; + +/* + * Lock module bottom interface. A lock module makes itself available to GFS + * with these functions. + */ + +int gfs2_register_lockproto(const struct lm_lockops *proto); +void gfs2_unregister_lockproto(const struct lm_lockops *proto); + +/* + * Lock module top interface. GFS calls these functions when mounting or + * unmounting a file system. + */ + +int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, + lm_callback_t cb, void *cb_data, + unsigned int min_lvb_size, int flags, + struct lm_lockstruct *lockstruct, + struct kobject *fskobj); + +void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct); + +void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct); + +#endif /* __LM_INTERFACE_DOT_H__ */ + -- cgit v1.2.3 From d3465c921f79cfef0a4a8ceeeef9a3721bbbb57d Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Thu, 21 Sep 2006 22:38:05 +0400 Subject: POWERPC: overhaul with cpm2_map mechanism Incorporating the new way of cpm2 immr access, introduced in the previous patch, into CPM2 peripheral devices (fs_enet and cpm_uart). Both ppc and powerpc approved working( real actions taken in powerpc only, ppc just has a wrapper to keep init stuff consistent). Signed-off-by: Vitaly Bordug --- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 109 ++++++++++++++++-------------- arch/powerpc/sysdev/cpm2_common.c | 90 ++++++++++++++++++++++++ arch/powerpc/sysdev/fsl_soc.c | 7 ++ arch/ppc/platforms/mpc8272ads_setup.c | 8 +-- arch/ppc/platforms/mpc866ads_setup.c | 8 +-- arch/ppc/platforms/mpc885ads_setup.c | 10 +-- drivers/net/fs_enet/fs_enet-main.c | 2 +- drivers/serial/cpm_uart/cpm_uart_core.c | 4 +- include/asm-ppc/cpm2.h | 53 +++++++++++++++ include/linux/fs_enet_pd.h | 10 +-- include/linux/fs_uart_pd.h | 4 +- 11 files changed, 235 insertions(+), 70 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 7ebfe74bde40..28070e7ae507 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -33,6 +33,7 @@ #include "mpc85xx.h" #ifdef CONFIG_CPM2 +#include #include #include #include @@ -146,70 +147,81 @@ void __init mpc85xx_ads_pic_init(void) * Setup the architecture */ #ifdef CONFIG_CPM2 -static void init_fcc_ioports(void) +void init_fcc_ioports(struct fs_platform_info *fpi) { - struct immap *immap; - struct io_port *io; + struct io_port *io = cpm2_map(im_ioport); + int fcc_no = fs_get_fcc_index(fpi->fs_no); + int target; u32 tempval; - immap = cpm2_immr; - - io = &immap->im_ioport; - /* FCC2/3 are on the ports B/C. */ - tempval = in_be32(&io->iop_pdirb); - tempval &= ~PB2_DIRB0; - tempval |= PB2_DIRB1; - out_be32(&io->iop_pdirb, tempval); - - tempval = in_be32(&io->iop_psorb); - tempval &= ~PB2_PSORB0; - tempval |= PB2_PSORB1; - out_be32(&io->iop_psorb, tempval); - - tempval = in_be32(&io->iop_pparb); - tempval |= (PB2_DIRB0 | PB2_DIRB1); - out_be32(&io->iop_pparb, tempval); - - tempval = in_be32(&io->iop_pdirb); - tempval &= ~PB3_DIRB0; - tempval |= PB3_DIRB1; - out_be32(&io->iop_pdirb, tempval); - - tempval = in_be32(&io->iop_psorb); - tempval &= ~PB3_PSORB0; - tempval |= PB3_PSORB1; - out_be32(&io->iop_psorb, tempval); - - tempval = in_be32(&io->iop_pparb); - tempval |= (PB3_DIRB0 | PB3_DIRB1); - out_be32(&io->iop_pparb, tempval); - - tempval = in_be32(&io->iop_pdirc); - tempval |= PC3_DIRC1; - out_be32(&io->iop_pdirc, tempval); - - tempval = in_be32(&io->iop_pparc); - tempval |= PC3_DIRC1; - out_be32(&io->iop_pparc, tempval); + switch(fcc_no) { + case 1: + tempval = in_be32(&io->iop_pdirb); + tempval &= ~PB2_DIRB0; + tempval |= PB2_DIRB1; + out_be32(&io->iop_pdirb, tempval); + + tempval = in_be32(&io->iop_psorb); + tempval &= ~PB2_PSORB0; + tempval |= PB2_PSORB1; + out_be32(&io->iop_psorb, tempval); + + tempval = in_be32(&io->iop_pparb); + tempval |= (PB2_DIRB0 | PB2_DIRB1); + out_be32(&io->iop_pparb, tempval); + + target = CPM_CLK_FCC2; + break; + case 2: + tempval = in_be32(&io->iop_pdirb); + tempval &= ~PB3_DIRB0; + tempval |= PB3_DIRB1; + out_be32(&io->iop_pdirb, tempval); + + tempval = in_be32(&io->iop_psorb); + tempval &= ~PB3_PSORB0; + tempval |= PB3_PSORB1; + out_be32(&io->iop_psorb, tempval); + + tempval = in_be32(&io->iop_pparb); + tempval |= (PB3_DIRB0 | PB3_DIRB1); + out_be32(&io->iop_pparb, tempval); + + tempval = in_be32(&io->iop_pdirc); + tempval |= PC3_DIRC1; + out_be32(&io->iop_pdirc, tempval); + + tempval = in_be32(&io->iop_pparc); + tempval |= PC3_DIRC1; + out_be32(&io->iop_pparc, tempval); + + target = CPM_CLK_FCC3; + break; + default: + printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n"); + return; + } /* Port C has clocks...... */ tempval = in_be32(&io->iop_psorc); - tempval &= ~(CLK_TRX); + tempval &= ~(PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8)); out_be32(&io->iop_psorc, tempval); tempval = in_be32(&io->iop_pdirc); - tempval &= ~(CLK_TRX); + tempval &= ~(PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8)); out_be32(&io->iop_pdirc, tempval); tempval = in_be32(&io->iop_pparc); - tempval |= (CLK_TRX); + tempval |= (PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8)); out_be32(&io->iop_pparc, tempval); + cpm2_unmap(io); + /* Configure Serial Interface clock routing. - * First, clear all FCC bits to zero, + * First, clear FCC bits to zero, * then set the ones we want. */ - immap->im_cpmux.cmx_fcr &= ~(CPMUX_CLK_MASK); - immap->im_cpmux.cmx_fcr |= CPMUX_CLK_ROUTE; + cpm2_clk_setup(target, fpi->clk_rx, CPM_CLK_RX); + cpm2_clk_setup(target, fpi->clk_tx, CPM_CLK_TX); } #endif @@ -237,7 +249,6 @@ static void __init mpc85xx_ads_setup_arch(void) #ifdef CONFIG_CPM2 cpm2_reset(); - init_fcc_ioports(); #endif #ifdef CONFIG_PCI diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c index 73376f9c1560..ec265995d5d8 100644 --- a/arch/powerpc/sysdev/cpm2_common.c +++ b/arch/powerpc/sysdev/cpm2_common.c @@ -130,6 +130,96 @@ cpm2_fastbrg(uint brg, uint rate, int div16) cpm2_unmap(bp); } +int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) +{ + int ret = 0; + int shift; + int i, bits = 0; + cpmux_t *im_cpmux; + u32 *reg; + u32 mask = 7; + u8 clk_map [24][3] = { + {CPM_CLK_FCC1, CPM_BRG5, 0}, + {CPM_CLK_FCC1, CPM_BRG6, 1}, + {CPM_CLK_FCC1, CPM_BRG7, 2}, + {CPM_CLK_FCC1, CPM_BRG8, 3}, + {CPM_CLK_FCC1, CPM_CLK9, 4}, + {CPM_CLK_FCC1, CPM_CLK10, 5}, + {CPM_CLK_FCC1, CPM_CLK11, 6}, + {CPM_CLK_FCC1, CPM_CLK12, 7}, + {CPM_CLK_FCC2, CPM_BRG5, 0}, + {CPM_CLK_FCC2, CPM_BRG6, 1}, + {CPM_CLK_FCC2, CPM_BRG7, 2}, + {CPM_CLK_FCC2, CPM_BRG8, 3}, + {CPM_CLK_FCC2, CPM_CLK13, 4}, + {CPM_CLK_FCC2, CPM_CLK14, 5}, + {CPM_CLK_FCC2, CPM_CLK15, 6}, + {CPM_CLK_FCC2, CPM_CLK16, 7}, + {CPM_CLK_FCC3, CPM_BRG5, 0}, + {CPM_CLK_FCC3, CPM_BRG6, 1}, + {CPM_CLK_FCC3, CPM_BRG7, 2}, + {CPM_CLK_FCC3, CPM_BRG8, 3}, + {CPM_CLK_FCC3, CPM_CLK13, 4}, + {CPM_CLK_FCC3, CPM_CLK14, 5}, + {CPM_CLK_FCC3, CPM_CLK15, 6}, + {CPM_CLK_FCC3, CPM_CLK16, 7} + }; + + im_cpmux = cpm2_map(im_cpmux); + + switch (target) { + case CPM_CLK_SCC1: + reg = &im_cpmux->cmx_scr; + shift = 24; + case CPM_CLK_SCC2: + reg = &im_cpmux->cmx_scr; + shift = 16; + break; + case CPM_CLK_SCC3: + reg = &im_cpmux->cmx_scr; + shift = 8; + break; + case CPM_CLK_SCC4: + reg = &im_cpmux->cmx_scr; + shift = 0; + break; + case CPM_CLK_FCC1: + reg = &im_cpmux->cmx_fcr; + shift = 24; + break; + case CPM_CLK_FCC2: + reg = &im_cpmux->cmx_fcr; + shift = 16; + break; + case CPM_CLK_FCC3: + reg = &im_cpmux->cmx_fcr; + shift = 8; + break; + default: + printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n"); + return -EINVAL; + } + + if (mode == CPM_CLK_RX) + shift +=3; + + for (i=0; i<24; i++) { + if (clk_map[i][0] == target && clk_map[i][1] == clock) { + bits = clk_map[i][2]; + break; + } + } + if (i == sizeof(clk_map)/3) + ret = -EINVAL; + + bits <<= shift; + mask <<= shift; + out_be32(reg, (in_be32(reg) & ~mask) | bits); + + cpm2_unmap(im_cpmux); + return ret; +} + /* * dpalloc / dpfree bits. */ diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 0b8a03cc3042..4e72bb983636 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -36,6 +36,7 @@ #include #include +extern void init_fcc_ioports(struct fs_platform_info*); static phys_addr_t immrbase = -1; phys_addr_t get_immrbase(void) @@ -630,6 +631,9 @@ static int __init fs_enet_of_init(void) goto unreg; } + fs_enet_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL)); + fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL)); + if (strstr(model, "FCC")) { int fcc_index = fs_get_fcc_index(*id); @@ -646,6 +650,7 @@ static int __init fs_enet_of_init(void) snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x", (u32)res.start, fs_enet_data.phy_addr); fs_enet_data.bus_id = (char*)&bus_id[(*id)]; + fs_enet_data.init_ioports = init_fcc_ioports; } of_node_put(phy); @@ -717,6 +722,8 @@ static int __init cpm_uart_of_init(void) cpm_uart_data.tx_buf_size = 32; cpm_uart_data.rx_num_fifo = 4; cpm_uart_data.rx_buf_size = 32; + cpm_uart_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL)); + cpm_uart_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL)); ret = platform_device_add_data(cpm_uart_dev, &cpm_uart_data, diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c index 2a35fe2b9b96..d5d36c372c8e 100644 --- a/arch/ppc/platforms/mpc8272ads_setup.c +++ b/arch/ppc/platforms/mpc8272ads_setup.c @@ -103,7 +103,7 @@ static struct fs_platform_info mpc82xx_enet_pdata[] = { }, }; -static void init_fcc1_ioports(void) +static void init_fcc1_ioports(struct fs_platform_info*) { struct io_port *io; u32 tempval; @@ -144,7 +144,7 @@ static void init_fcc1_ioports(void) iounmap(immap); } -static void init_fcc2_ioports(void) +static void init_fcc2_ioports(struct fs_platform_info*) { cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t)); u32 *bcsr = ioremap(BCSR_ADDR+12, sizeof(u32)); @@ -229,7 +229,7 @@ static void mpc8272ads_fixup_uart_pdata(struct platform_device *pdev, } } -static void init_scc1_uart_ioports(void) +static void init_scc1_uart_ioports(struct fs_uart_platform_info*) { cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t)); @@ -246,7 +246,7 @@ static void init_scc1_uart_ioports(void) iounmap(immap); } -static void init_scc4_uart_ioports(void) +static void init_scc4_uart_ioports(struct fs_uart_platform_info*) { cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t)); diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c index e12cece4c9fd..5f130dca3770 100644 --- a/arch/ppc/platforms/mpc866ads_setup.c +++ b/arch/ppc/platforms/mpc866ads_setup.c @@ -137,7 +137,7 @@ void __init board_init(void) iounmap(bcsr_io); } -static void setup_fec1_ioports(void) +static void setup_fec1_ioports(struct fs_platform_info*) { immap_t *immap = (immap_t *) IMAP_ADDR; @@ -145,7 +145,7 @@ static void setup_fec1_ioports(void) setbits16(&immap->im_ioport.iop_pddir, 0x1fff); } -static void setup_scc1_ioports(void) +static void setup_scc1_ioports(struct fs_platform_info*) { immap_t *immap = (immap_t *) IMAP_ADDR; unsigned *bcsr_io; @@ -194,7 +194,7 @@ static void setup_scc1_ioports(void) } -static void setup_smc1_ioports(void) +static void setup_smc1_ioports(struct fs_uart_platform_info*) { immap_t *immap = (immap_t *) IMAP_ADDR; unsigned *bcsr_io; @@ -216,7 +216,7 @@ static void setup_smc1_ioports(void) } -static void setup_smc2_ioports(void) +static void setup_smc2_ioports(struct fs_uart_platform_info*) { immap_t *immap = (immap_t *) IMAP_ADDR; unsigned *bcsr_io; diff --git a/arch/ppc/platforms/mpc885ads_setup.c b/arch/ppc/platforms/mpc885ads_setup.c index 5dfa4e6c2af0..bf388ed04d46 100644 --- a/arch/ppc/platforms/mpc885ads_setup.c +++ b/arch/ppc/platforms/mpc885ads_setup.c @@ -161,7 +161,7 @@ void __init board_init(void) #endif } -static void setup_fec1_ioports(void) +static void setup_fec1_ioports(struct fs_platform_info*) { immap_t *immap = (immap_t *) IMAP_ADDR; @@ -181,7 +181,7 @@ static void setup_fec1_ioports(void) clrbits32(&immap->im_cpm.cp_cptr, 0x00000100); } -static void setup_fec2_ioports(void) +static void setup_fec2_ioports(struct fs_platform_info*) { immap_t *immap = (immap_t *) IMAP_ADDR; @@ -193,7 +193,7 @@ static void setup_fec2_ioports(void) clrbits32(&immap->im_cpm.cp_cptr, 0x00000080); } -static void setup_scc3_ioports(void) +static void setup_scc3_ioports(struct fs_platform_info*) { immap_t *immap = (immap_t *) IMAP_ADDR; unsigned *bcsr_io; @@ -315,7 +315,7 @@ static void __init mpc885ads_fixup_scc_enet_pdata(struct platform_device *pdev, mpc885ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1); } -static void setup_smc1_ioports(void) +static void setup_smc1_ioports(struct fs_uart_platform_info*) { immap_t *immap = (immap_t *) IMAP_ADDR; unsigned *bcsr_io; @@ -335,7 +335,7 @@ static void setup_smc1_ioports(void) clrbits16(&immap->im_cpm.cp_pbodr, iobits); } -static void setup_smc2_ioports(void) +static void setup_smc2_ioports(struct fs_uart_platform_info*) { immap_t *immap = (immap_t *) IMAP_ADDR; unsigned *bcsr_io; diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index df62506a1787..f358ee61d9b9 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -971,7 +971,7 @@ static struct net_device *fs_init_instance(struct device *dev, dev_set_drvdata(dev, ndev); fep->fpi = fpi; if (fpi->init_ioports) - fpi->init_ioports(); + fpi->init_ioports((struct fs_platform_info *)fpi); #ifdef CONFIG_FS_ENET_HAS_FEC if (fs_get_fec_index(fpi->fs_no) >= 0) diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index dfa06b644957..24613a68f5cc 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -1180,7 +1180,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) pdata = pdev->dev.platform_data; if (pdata) if (pdata->init_ioports) - pdata->init_ioports(); + pdata->init_ioports(pdata); cpm_uart_drv_get_platform_data(pdev, 1); } @@ -1269,7 +1269,7 @@ static int cpm_uart_drv_probe(struct device *dev) return ret; if (pdata->init_ioports) - pdata->init_ioports(); + pdata->init_ioports(pdata); ret = uart_add_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h index bd6623aed383..220cc2debe08 100644 --- a/include/asm-ppc/cpm2.h +++ b/include/asm-ppc/cpm2.h @@ -1196,5 +1196,58 @@ typedef struct im_idma { #define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1) #define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2) +/* Clocks and GRG's */ + +enum cpm_clk_dir { + CPM_CLK_RX, + CPM_CLK_TX, + CPM_CLK_RTX +}; + +enum cpm_clk_target { + CPM_CLK_SCC1, + CPM_CLK_SCC2, + CPM_CLK_SCC3, + CPM_CLK_SCC4, + CPM_CLK_FCC1, + CPM_CLK_FCC2, + CPM_CLK_FCC3 +}; + +enum cpm_clk { + CPM_CLK_NONE = 0, + CPM_BRG1, /* Baud Rate Generator 1 */ + CPM_BRG2, /* Baud Rate Generator 2 */ + CPM_BRG3, /* Baud Rate Generator 3 */ + CPM_BRG4, /* Baud Rate Generator 4 */ + CPM_BRG5, /* Baud Rate Generator 5 */ + CPM_BRG6, /* Baud Rate Generator 6 */ + CPM_BRG7, /* Baud Rate Generator 7 */ + CPM_BRG8, /* Baud Rate Generator 8 */ + CPM_CLK1, /* Clock 1 */ + CPM_CLK2, /* Clock 2 */ + CPM_CLK3, /* Clock 3 */ + CPM_CLK4, /* Clock 4 */ + CPM_CLK5, /* Clock 5 */ + CPM_CLK6, /* Clock 6 */ + CPM_CLK7, /* Clock 7 */ + CPM_CLK8, /* Clock 8 */ + CPM_CLK9, /* Clock 9 */ + CPM_CLK10, /* Clock 10 */ + CPM_CLK11, /* Clock 11 */ + CPM_CLK12, /* Clock 12 */ + CPM_CLK13, /* Clock 13 */ + CPM_CLK14, /* Clock 14 */ + CPM_CLK15, /* Clock 15 */ + CPM_CLK16, /* Clock 16 */ + CPM_CLK17, /* Clock 17 */ + CPM_CLK18, /* Clock 18 */ + CPM_CLK19, /* Clock 19 */ + CPM_CLK20, /* Clock 20 */ + CPM_CLK_DUMMY +}; + +extern int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode); + #endif /* __CPM2__ */ #endif /* __KERNEL__ */ diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h index 74ed35a00a94..932223550aca 100644 --- a/include/linux/fs_enet_pd.h +++ b/include/linux/fs_enet_pd.h @@ -87,18 +87,20 @@ struct fs_mii_bb_platform_info { }; struct fs_platform_info { - - void(*init_ioports)(void); + + void(*init_ioports)(struct fs_platform_info *); /* device specific information */ int fs_no; /* controller index */ u32 cp_page; /* CPM page */ u32 cp_block; /* CPM sblock */ - + u32 clk_trx; /* some stuff for pins & mux configuration*/ + u32 clk_rx; + u32 clk_tx; u32 clk_route; u32 clk_mask; - + u32 mem_offset; u32 dpram_offset; u32 fcc_regs_c; diff --git a/include/linux/fs_uart_pd.h b/include/linux/fs_uart_pd.h index f5975126b712..a99a020f95c2 100644 --- a/include/linux/fs_uart_pd.h +++ b/include/linux/fs_uart_pd.h @@ -46,7 +46,7 @@ static inline int fs_uart_id_fsid2smc(int id) } struct fs_uart_platform_info { - void(*init_ioports)(void); + void(*init_ioports)(struct fs_uart_platform_info *); /* device specific information */ int fs_no; /* controller index */ u32 uart_clk; @@ -55,6 +55,8 @@ struct fs_uart_platform_info { u8 rx_num_fifo; u8 rx_buf_size; u8 brg; + u8 clk_rx; + u8 clk_tx; }; #endif -- cgit v1.2.3 From 611a15afcdaacec6efba984c7eb089b853564bdf Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Thu, 21 Sep 2006 22:38:05 +0400 Subject: POWERPC: Bring the fs_no calculation to the relevant SoC enumeration The fs_no mean used to be fs_enet driver driven, hence it was an enumeration across all the possible fs_enet "users" in the SoC. Now, with QE on the pipeline, and to make DTS descriptions more clear, fs_no features relevant SoC part number, with additional field to describe the SoC type. Another reason for that is now not only fs_enet is going to utilize those stuff. There might be UART, HLDC, and even USB, so to prevent confusion and be ready for upcoming OF_device transfer, fs_enet and cpm_uart drivers were updated in that concern, as well as the relevant DTS. Signed-off-by: Vitaly Bordug --- arch/powerpc/boot/dts/mpc8560ads.dts | 8 +++---- arch/powerpc/sysdev/fsl_soc.c | 8 ++++++- drivers/net/fs_enet/fs_enet-main.c | 3 ++- drivers/serial/cpm_uart/cpm_uart_core.c | 9 +++++--- include/linux/fs_enet_pd.h | 37 +++++++++++++++++++++++++++++++++ include/linux/fs_uart_pd.h | 10 +++++++++ 6 files changed, 66 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index ba5c943a6fe9..2b168486aeba 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts @@ -244,7 +244,7 @@ device_type = "serial"; compatible = "cpm_uart"; model = "SCC"; - device-id = <2>; + device-id = <1>; reg = <91a00 20 88000 100>; clock-setup = <00ffffff 0>; rx-clock = <1>; @@ -258,7 +258,7 @@ device_type = "serial"; compatible = "cpm_uart"; model = "SCC"; - device-id = <3>; + device-id = <2>; reg = <91a20 20 88100 100>; clock-setup = ; rx-clock = <2>; @@ -272,7 +272,7 @@ device_type = "network"; compatible = "fs_enet"; model = "FCC"; - device-id = <3>; + device-id = <2>; reg = <91320 20 88500 100 913a0 30>; mac-address = [ 00 00 0C 00 02 FD ]; clock-setup = ; @@ -287,7 +287,7 @@ device_type = "network"; compatible = "fs_enet"; model = "FCC"; - device-id = <4>; + device-id = <3>; reg = <91340 20 88600 100 913d0 30>; mac-address = [ 00 00 0C 00 03 FD ]; clock-setup = ; diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 4e72bb983636..022ed275ea68 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -622,6 +622,7 @@ static int __init fs_enet_of_init(void) id = get_property(np, "device-id", NULL); fs_enet_data.fs_no = *id; + strcpy(fs_enet_data.fs_type, model); mdio = of_get_parent(phy); ret = of_address_to_resource(mdio, 0, &res); @@ -635,7 +636,7 @@ static int __init fs_enet_of_init(void) fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL)); if (strstr(model, "FCC")) { - int fcc_index = fs_get_fcc_index(*id); + int fcc_index = *id - 1; fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0); fs_enet_data.rx_ring = 32; @@ -688,6 +689,7 @@ static int __init cpm_uart_of_init(void) struct resource r[3]; struct fs_uart_platform_info cpm_uart_data; const int *id; + const char *model; memset(r, 0, sizeof(r)); memset(&cpm_uart_data, 0, sizeof(cpm_uart_data)); @@ -716,6 +718,10 @@ static int __init cpm_uart_of_init(void) id = get_property(np, "device-id", NULL); cpm_uart_data.fs_no = *id; + + model = (char*)get_property(np, "model", NULL); + strcpy(cpm_uart_data.fs_type, model); + cpm_uart_data.uart_clk = ppc_proc_freq; cpm_uart_data.tx_num_fifo = 4; diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index f358ee61d9b9..3e2a3a20d50a 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -944,12 +944,13 @@ extern int fs_mii_connect(struct net_device *dev); extern void fs_mii_disconnect(struct net_device *dev); static struct net_device *fs_init_instance(struct device *dev, - const struct fs_platform_info *fpi) + struct fs_platform_info *fpi) { struct net_device *ndev = NULL; struct fs_enet_private *fep = NULL; int privsize, i, r, err = 0, registered = 0; + fpi->fs_no = fs_get_id(fpi); /* guard */ if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX) return ERR_PTR(-EINVAL); diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index 24613a68f5cc..a0d6136deb9b 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -1023,15 +1023,17 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con) { struct resource *r; struct fs_uart_platform_info *pdata = pdev->dev.platform_data; - int idx = pdata->fs_no; /* It is UART_SMCx or UART_SCCx index */ + int idx; /* It is UART_SMCx or UART_SCCx index */ struct uart_cpm_port *pinfo; int line; u32 mem, pram; + idx = pdata->fs_no = fs_uart_get_id(pdata); + line = cpm_uart_id2nr(idx); if(line < 0) { printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx); - return -1; + return -EINVAL; } pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx]; @@ -1263,11 +1265,12 @@ static int cpm_uart_drv_probe(struct device *dev) } pdata = pdev->dev.platform_data; - pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no)); if ((ret = cpm_uart_drv_get_platform_data(pdev, 0))) return ret; + pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no)); + if (pdata->init_ioports) pdata->init_ioports(pdata); diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h index 932223550aca..543cd3cd9e77 100644 --- a/include/linux/fs_enet_pd.h +++ b/include/linux/fs_enet_pd.h @@ -55,6 +55,30 @@ static inline int fs_get_scc_index(enum fs_id id) return -1; } +static inline int fs_fec_index2id(int index) +{ + int id = fsid_fec1 + index - 1; + if (id >= fsid_fec1 && id <= fsid_fec2) + return id; + return FS_MAX_INDEX; + } + +static inline int fs_fcc_index2id(int index) +{ + int id = fsid_fcc1 + index - 1; + if (id >= fsid_fcc1 && id <= fsid_fcc3) + return id; + return FS_MAX_INDEX; +} + +static inline int fs_scc_index2id(int index) +{ + int id = fsid_scc1 + index - 1; + if (id >= fsid_scc1 && id <= fsid_scc4) + return id; + return FS_MAX_INDEX; +} + enum fs_mii_method { fsmii_fixed, fsmii_fec, @@ -91,6 +115,7 @@ struct fs_platform_info { void(*init_ioports)(struct fs_platform_info *); /* device specific information */ int fs_no; /* controller index */ + char fs_type[4]; /* controller type */ u32 cp_page; /* CPM page */ u32 cp_block; /* CPM sblock */ @@ -126,4 +151,16 @@ struct fs_mii_fec_platform_info { u32 irq[32]; u32 mii_speed; }; + +static inline int fs_get_id(struct fs_platform_info *fpi) +{ + if(strstr(fpi->fs_type, "SCC")) + return fs_scc_index2id(fpi->fs_no); + if(strstr(fpi->fs_type, "FCC")) + return fs_fcc_index2id(fpi->fs_no); + if(strstr(fpi->fs_type, "FEC")) + return fs_fec_index2id(fpi->fs_no); + return fpi->fs_no; +} + #endif diff --git a/include/linux/fs_uart_pd.h b/include/linux/fs_uart_pd.h index a99a020f95c2..809bb9ffc788 100644 --- a/include/linux/fs_uart_pd.h +++ b/include/linux/fs_uart_pd.h @@ -49,6 +49,7 @@ struct fs_uart_platform_info { void(*init_ioports)(struct fs_uart_platform_info *); /* device specific information */ int fs_no; /* controller index */ + char fs_type[4]; /* controller type */ u32 uart_clk; u8 tx_num_fifo; u8 tx_buf_size; @@ -59,4 +60,13 @@ struct fs_uart_platform_info { u8 clk_tx; }; +static inline int fs_uart_get_id(struct fs_uart_platform_info *fpi) +{ + if(strstr(fpi->fs_type, "SMC")) + return fs_uart_id_smc2fsid(fpi->fs_no); + if(strstr(fpi->fs_type, "SCC")) + return fs_uart_id_scc2fsid(fpi->fs_no); + return fpi->fs_no; +} + #endif -- cgit v1.2.3 From 42431acbac43eb47c774c29d370f5c59136805bf Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 24 Sep 2006 10:44:09 +0100 Subject: [MMC] MMC_CAP_BYTEBLOCK flag for non-log2 block sizes capable hosts Some MMC hosts can only handle log2 block sizes. Unfortunately, the MMC password support needs to be able to send non-log2 block sizes. Provide a capability so that the MMC password support can decide whether it should use this support or not. The unfortunate side effect of this host limitation is that any MMC card protected by a password which is not a log2 block size can not be accessed on a host which only allows a log2 block size. This change just adds the flag. The MMC password support code needs updating to use it (if and when it is finally submitted.) Signed-off-by: Russell King --- drivers/mmc/at91_mci.c | 1 + drivers/mmc/imxmmc.c | 2 +- drivers/mmc/omap.c | 7 ++++--- drivers/mmc/sdhci.c | 2 +- drivers/mmc/wbsd.c | 2 +- include/linux/mmc/host.h | 1 + 6 files changed, 9 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index 6b7638b84290..d34b7d9d92ed 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -822,6 +822,7 @@ static int at91_mci_probe(struct platform_device *pdev) mmc->f_min = 375000; mmc->f_max = 25000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + mmc->caps = MMC_CAP_BYTEBLOCK; host = mmc_priv(mmc); host->mmc = mmc; diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index fb6565b98f32..1b79dd271aae 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -956,7 +956,7 @@ static int imxmci_probe(struct platform_device *pdev) mmc->f_min = 150000; mmc->f_max = CLK_RATE/2; mmc->ocr_avail = MMC_VDD_32_33; - mmc->caps |= MMC_CAP_4_BIT_DATA; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK; /* MMC core transfer sizes tunable parameters */ mmc->max_hw_segs = 64; diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c index ddf06b32c159..52c9e52e6b78 100644 --- a/drivers/mmc/omap.c +++ b/drivers/mmc/omap.c @@ -1034,13 +1034,14 @@ static int __init mmc_omap_probe(struct platform_device *pdev) host->irq = pdev->resource[1].start; host->base = (void __iomem*)IO_ADDRESS(r->start); - if (minfo->wire4) - mmc->caps |= MMC_CAP_4_BIT_DATA; - mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; mmc->f_max = 24000000; mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; + mmc->caps = MMC_CAP_BYTEBLOCK; + + if (minfo->wire4) + mmc->caps |= MMC_CAP_4_BIT_DATA; /* Use scatterlist DMA to reduce per-transfer costs. * NOTE max_seg_size assumption that small blocks aren't diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index dea4edd1c434..fdfc3838dd79 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -1262,7 +1262,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) mmc->ops = &sdhci_ops; mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK; mmc->ocr_avail = 0; if (caps & SDHCI_CAN_VDD_330) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 4a6617d9a49f..6435a6822ad3 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1323,7 +1323,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev) mmc->f_min = 375000; mmc->f_max = 24000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK; spin_lock_init(&host->lock); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index b282ec9bba08..587264a58d56 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -86,6 +86,7 @@ struct mmc_host { #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */ #define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */ +#define MMC_CAP_BYTEBLOCK (1 << 2) /* Can do non-log2 block sizes */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ -- cgit v1.2.3 From 3b85c3211ebde263a86c8cd3c7277fdd2e440310 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 25 Sep 2006 17:06:53 +0100 Subject: [MTD NAND] Split nand_scan() into two parts; allow board driver to intervene Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 90 ++++++++++++++++++++++++++++++++------------ include/linux/mtd/nand.h | 5 +++ 2 files changed, 70 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 8da8862d0548..492ff9d1a35c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2289,40 +2289,22 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, return type; } -/* module_text_address() isn't exported, and it's mostly a pointless - test if this is a module _anyway_ -- they'd have to try _really_ hard - to call us from in-kernel code if the core NAND support is modular. */ -#ifdef MODULE -#define caller_is_module() (1) -#else -#define caller_is_module() \ - module_text_address((unsigned long)__builtin_return_address(0)) -#endif - /** - * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for + * nand_scan_ident - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: Number of chips to scan for * - * This fills out all the uninitialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. - * The mtd->owner field must be set to the module of the caller + * This is the first phase of the normal nand_scan() function. It + * reads the flash ID and sets up MTD fields accordingly. * + * The mtd->owner field must be set to the module of the caller. */ -int nand_scan(struct mtd_info *mtd, int maxchips) +int nand_scan_ident(struct mtd_info *mtd, int maxchips) { int i, busw, nand_maf_id; struct nand_chip *chip = mtd->priv; struct nand_flash_dev *type; - /* Many callers got this wrong, so check for it for a while... */ - if (!mtd->owner && caller_is_module()) { - printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n"); - BUG(); - } - /* Get buswidth to select the correct functions */ busw = chip->options & NAND_BUSWIDTH_16; /* Set the default functions */ @@ -2354,6 +2336,24 @@ int nand_scan(struct mtd_info *mtd, int maxchips) chip->numchips = i; mtd->size = i * chip->chipsize; + return 0; +} + + +/** + * nand_scan_tail - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: Number of chips to scan for + * + * This is the second phase of the normal nand_scan() function. It + * fills out all the uninitialized function pointers with the defaults + * and scans for a bad block table if appropriate. + */ +int nand_scan_tail(struct mtd_info *mtd) +{ + int i; + struct nand_chip *chip = mtd->priv; + /* Preset the internal oob write buffer */ memset(chip->buffers.oobwbuf, 0xff, mtd->oobsize); @@ -2504,6 +2504,44 @@ int nand_scan(struct mtd_info *mtd, int maxchips) return chip->scan_bbt(mtd); } +/* module_text_address() isn't exported, and it's mostly a pointless + test if this is a module _anyway_ -- they'd have to try _really_ hard + to call us from in-kernel code if the core NAND support is modular. */ +#ifdef MODULE +#define caller_is_module() (1) +#else +#define caller_is_module() \ + module_text_address((unsigned long)__builtin_return_address(0)) +#endif + +/** + * nand_scan - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: Number of chips to scan for + * + * This fills out all the uninitialized function pointers + * with the defaults. + * The flash ID is read and the mtd/chip structures are + * filled with the appropriate values. + * The mtd->owner field must be set to the module of the caller + * + */ +int nand_scan(struct mtd_info *mtd, int maxchips) +{ + int ret; + + /* Many callers got this wrong, so check for it for a while... */ + if (!mtd->owner && caller_is_module()) { + printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n"); + BUG(); + } + + ret = nand_scan_ident(mtd, maxchips); + if (!ret) + ret = nand_scan_tail(mtd); + return ret; +} + /** * nand_release - [NAND Interface] Free resources held by the NAND device * @mtd: MTD device structure @@ -2524,6 +2562,8 @@ void nand_release(struct mtd_info *mtd) } EXPORT_SYMBOL_GPL(nand_scan); +EXPORT_SYMBOL_GPL(nand_scan_ident); +EXPORT_SYMBOL_GPL(nand_scan_tail); EXPORT_SYMBOL_GPL(nand_release); static int __init nand_base_init(void) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 0b4cd2fa64aa..88d690d79d77 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -27,6 +27,11 @@ struct mtd_info; /* Scan and identify a NAND device */ extern int nand_scan (struct mtd_info *mtd, int max_chips); +/* Separate phases of nand_scan(), allowing board driver to intervene + * and override command or ECC setup according to flash type */ +extern int nand_scan_ident(struct mtd_info *mtd, int max_chips); +extern int nand_scan_tail(struct mtd_info *mtd); + /* Free resources held by the NAND device */ extern void nand_release (struct mtd_info *mtd); -- cgit v1.2.3 From 4bf63fcb83dc761853f69a77b15e47712689020b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 25 Sep 2006 17:08:04 +0100 Subject: [MTD NAND] Allocate chip->buffers separately to allow it to be overridden In particular, the board driver might need it to be DMAable. Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 35 +++++++++++++++++++++-------------- drivers/mtd/nand/nand_bbt.c | 2 +- include/linux/mtd/nand.h | 6 ++++-- 3 files changed, 26 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 492ff9d1a35c..e1e81a9543e8 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -767,8 +767,8 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers.ecccalc; - uint8_t *ecc_code = chip->buffers.ecccode; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; int *eccpos = chip->ecc.layout->eccpos; nand_read_page_raw(mtd, chip, buf); @@ -809,8 +809,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers.ecccalc; - uint8_t *ecc_code = chip->buffers.ecccode; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; int *eccpos = chip->ecc.layout->eccpos; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { @@ -971,7 +971,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, page = realpage & chip->pagemask; col = (int)(from & (mtd->writesize - 1)); - chip->oob_poi = chip->buffers.oobrbuf; + chip->oob_poi = chip->buffers->oobrbuf; buf = ops->datbuf; oob = ops->oobbuf; @@ -982,7 +982,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Is the current page in the buffer ? */ if (realpage != chip->pagebuf || oob) { - bufpoi = aligned ? buf : chip->buffers.databuf; + bufpoi = aligned ? buf : chip->buffers->databuf; if (likely(sndcmd)) { chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); @@ -997,7 +997,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Transfer not aligned data */ if (!aligned) { chip->pagebuf = realpage; - memcpy(buf, chip->buffers.databuf + col, bytes); + memcpy(buf, chip->buffers->databuf + col, bytes); } buf += bytes; @@ -1024,7 +1024,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, nand_wait_ready(mtd); } } else { - memcpy(buf, chip->buffers.databuf + col, bytes); + memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; } @@ -1267,7 +1267,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, realpage = (int)(from >> chip->page_shift); page = realpage & chip->pagemask; - chip->oob_poi = chip->buffers.oobrbuf; + chip->oob_poi = chip->buffers->oobrbuf; while(1) { sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); @@ -1392,7 +1392,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers.ecccalc; + uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; int *eccpos = chip->ecc.layout->eccpos; @@ -1418,7 +1418,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers.ecccalc; + uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; int *eccpos = chip->ecc.layout->eccpos; @@ -1628,7 +1628,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, (chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; - chip->oob_poi = chip->buffers.oobwbuf; + chip->oob_poi = chip->buffers->oobwbuf; while(1) { int cached = writelen > bytes && page != blockmask; @@ -1746,7 +1746,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, if (page == chip->pagebuf) chip->pagebuf = -1; - chip->oob_poi = chip->buffers.oobwbuf; + chip->oob_poi = chip->buffers->oobwbuf; memset(chip->oob_poi, 0xff, mtd->oobsize); nand_fill_oob(chip, ops->oobbuf, ops); status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); @@ -2354,8 +2354,13 @@ int nand_scan_tail(struct mtd_info *mtd) int i; struct nand_chip *chip = mtd->priv; + if (!(chip->options & NAND_OWN_BUFFERS)) + chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); + if (!chip->buffers) + return -ENOMEM; + /* Preset the internal oob write buffer */ - memset(chip->buffers.oobwbuf, 0xff, mtd->oobsize); + memset(chip->buffers->oobwbuf, 0xff, mtd->oobsize); /* * If no default placement scheme is given, select an appropriate one @@ -2559,6 +2564,8 @@ void nand_release(struct mtd_info *mtd) /* Free bad block table memory */ kfree(chip->bbt); + if (!(chip->options & NAND_OWN_BUFFERS)) + kfree(chip->buffers); } EXPORT_SYMBOL_GPL(nand_scan); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index a612c4ea8194..9402653eb09b 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -759,7 +759,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b struct nand_chip *this = mtd->priv; bd->options &= ~NAND_BBT_SCANEMPTY; - return create_bbt(mtd, this->buffers.databuf, bd, -1); + return create_bbt(mtd, this->buffers->databuf, bd, -1); } /** diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 88d690d79d77..cd4fe9ae8622 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -183,7 +183,9 @@ typedef enum { #define NAND_USE_FLASH_BBT 0x00010000 /* This option skips the bbt scan during initialization. */ #define NAND_SKIP_BBTSCAN 0x00020000 - +/* This option is defined if the board driver allocates its own buffers + (e.g. because it needs them DMA-coherent */ +#define NAND_OWN_BUFFERS 0x00040000 /* Options set by nand scan */ /* Nand scan has allocated controller struct */ #define NAND_CONTROLLER_ALLOC 0x80000000 @@ -385,7 +387,7 @@ struct nand_chip { struct nand_ecclayout *ecclayout; struct nand_ecc_ctrl ecc; - struct nand_buffers buffers; + struct nand_buffers *buffers; struct nand_hw_control hwcontrol; struct mtd_oob_ops ops; -- cgit v1.2.3 From 956e944c7690ea994757a8cbedbb6241e1d9138f Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 25 Sep 2006 17:12:39 +0100 Subject: [MTD NAND] Allow override of page read and write functions. - allow high-level nand_write_page() function to be overridden - likewise low-level write_page_raw() and read_page_raw() functions - Clean up the abuse of chip->ecc.{write,read}_page() with MTD_OOB_RAW Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 44 +++++++++++++++++++++----------------------- include/linux/mtd/nand.h | 11 +++++++++++ 2 files changed, 32 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e1e81a9543e8..baece61169f4 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -990,7 +990,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, } /* Now read the page into the buffer */ - ret = chip->ecc.read_page(mtd, chip, bufpoi); + if (unlikely(ops->mode == MTD_OOB_RAW)) + ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); + else + ret = chip->ecc.read_page(mtd, chip, bufpoi); if (ret < 0) break; @@ -1323,8 +1326,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, static int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf) = NULL; struct nand_chip *chip = mtd->priv; int ret = -ENOTSUPP; @@ -1342,12 +1343,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, switch(ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: - break; - case MTD_OOB_RAW: - /* Replace the read_page algorithm temporary */ - read_page = chip->ecc.read_page; - chip->ecc.read_page = nand_read_page_raw; break; default: @@ -1359,8 +1355,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, else ret = nand_do_read_ops(mtd, from, ops); - if (unlikely(ops->mode == MTD_OOB_RAW)) - chip->ecc.read_page = read_page; out: nand_release_device(mtd); return ret; @@ -1479,7 +1473,7 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, } /** - * nand_write_page - [INTERNAL] write one page + * nand_write_page - [REPLACEABLE] write one page * @mtd: MTD device structure * @chip: NAND chip descriptor * @buf: the data to write @@ -1487,13 +1481,16 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, * @cached: cached programming */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int page, int cached) + const uint8_t *buf, int page, int cached, int raw) { int status; chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - chip->ecc.write_page(mtd, chip, buf); + if (unlikely(raw)) + chip->ecc.write_page_raw(mtd, chip, buf); + else + chip->ecc.write_page(mtd, chip, buf); /* * Cached progamming disabled for now, Not sure if its worth the @@ -1636,7 +1633,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (unlikely(oob)) oob = nand_fill_oob(chip, oob, ops); - ret = nand_write_page(mtd, chip, buf, page, cached); + ret = chip->write_page(mtd, chip, buf, page, cached, + (ops->mode == MTD_OOB_RAW)); if (ret) break; @@ -1769,8 +1767,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { - void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) = NULL; struct nand_chip *chip = mtd->priv; int ret = -ENOTSUPP; @@ -1788,12 +1784,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, switch(ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: - break; - case MTD_OOB_RAW: - /* Replace the write_page algorithm temporary */ - write_page = chip->ecc.write_page; - chip->ecc.write_page = nand_write_page_raw; break; default: @@ -1805,8 +1796,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, else ret = nand_do_write_ops(mtd, to, ops); - if (unlikely(ops->mode == MTD_OOB_RAW)) - chip->ecc.write_page = write_page; out: nand_release_device(mtd); return ret; @@ -2383,10 +2372,18 @@ int nand_scan_tail(struct mtd_info *mtd) } } + if (!chip->write_page) + chip->write_page = nand_write_page; + /* * check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */ + if (!chip->ecc.read_page_raw) + chip->ecc.read_page_raw = nand_read_page_raw; + if (!chip->ecc.write_page_raw) + chip->ecc.write_page_raw = nand_write_page_raw; + switch (chip->ecc.mode) { case NAND_ECC_HW: /* Use standard hwecc read page function ? */ @@ -2444,6 +2441,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.size = mtd->writesize; chip->ecc.bytes = 0; break; + default: printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index cd4fe9ae8622..2bcbcc896835 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -235,6 +235,8 @@ struct nand_hw_control { * be provided if an hardware ECC is available * @calculate: function for ecc calculation or readback from ecc hardware * @correct: function for ecc correction, matching to ecc generator (sw/hw) + * @read_page_raw: function to read a raw page without ECC + * @write_page_raw: function to write a raw page without ECC * @read_page: function to read a page according to the ecc generator requirements * @write_page: function to write a page according to the ecc generator requirements * @read_oob: function to read chip OOB data @@ -256,6 +258,12 @@ struct nand_ecc_ctrl { int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc); + int (*read_page_raw)(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf); + void (*write_page_raw)(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf); int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf); @@ -344,6 +352,7 @@ struct nand_buffers { * @priv: [OPTIONAL] pointer to private chip date * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks * (determine if errors are correctable) + * @write_page [REPLACEABLE] High-level page write function */ struct nand_chip { @@ -366,6 +375,8 @@ struct nand_chip { void (*erase_cmd)(struct mtd_info *mtd, int page); int (*scan_bbt)(struct mtd_info *mtd); int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); + int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int page, int cached, int raw); int chip_delay; unsigned int options; -- cgit v1.2.3 From baef186519c69b11cf7e48c26e75feb1e6173baa Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 8 Sep 2006 16:04:05 -0400 Subject: [PATCH] WE-21 support (core API) This is version 21 of the Wireless Extensions. Changelog : o finishes migrating the ESSID API (remove the +1) o netdev->get_wireless_stats is no more o long/short retry This is a redacted version of a patch originally submitted by Jean Tourrilhes. I removed most of the additions, in order to minimize future support requirements for nl80211 (or other WE successor). CC: Jean Tourrilhes Signed-off-by: John W. Linville --- include/linux/netdevice.h | 1 - include/linux/wireless.h | 24 ++++++++++++++--- net/core/net-sysfs.c | 5 +--- net/core/wireless.c | 67 +++++++++++++++++++++++++++++------------------ 4 files changed, 62 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 43289127b458..ac4f50213bc3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -334,7 +334,6 @@ struct net_device struct net_device_stats* (*get_stats)(struct net_device *dev); - struct iw_statistics* (*get_wireless_stats)(struct net_device *dev); /* List of functions to handle Wireless Extensions (instead of ioctl). * See for details. Jean II */ diff --git a/include/linux/wireless.h b/include/linux/wireless.h index 13588564b42b..a50a0130fd9e 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -1,7 +1,7 @@ /* * This file define a set of standard wireless extensions * - * Version : 20 17.2.06 + * Version : 21 14.3.06 * * Authors : Jean Tourrilhes - HPL - * Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved. @@ -69,9 +69,14 @@ /***************************** INCLUDES *****************************/ +/* This header is used in user-space, therefore need to be sanitised + * for that purpose. Those includes are usually not compatible with glibc. + * To know which includes to use in user-space, check iwlib.h. */ +#ifdef __KERNEL__ #include /* for "caddr_t" et al */ #include /* for "struct sockaddr" et al */ #include /* for IFNAMSIZ and co... */ +#endif /* __KERNEL__ */ /***************************** VERSION *****************************/ /* @@ -80,7 +85,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 20 +#define WIRELESS_EXT 21 /* * Changes : @@ -208,6 +213,14 @@ * V19 to V20 * ---------- * - RtNetlink requests support (SET/GET) + * + * V20 to V21 + * ---------- + * - Remove (struct net_device *)->get_wireless_stats() + * - Change length in ESSID and NICK to strlen() instead of strlen()+1 + * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers + * - Power/Retry relative values no longer * 100000 + * - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI */ /**************************** CONSTANTS ****************************/ @@ -448,6 +461,7 @@ #define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ #define IW_QUAL_LEVEL_INVALID 0x20 #define IW_QUAL_NOISE_INVALID 0x40 +#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */ #define IW_QUAL_ALL_INVALID 0x70 /* Frequency flags */ @@ -500,10 +514,12 @@ #define IW_RETRY_TYPE 0xF000 /* Type of parameter */ #define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ #define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ -#define IW_RETRY_MODIFIER 0x000F /* Modify a parameter */ +#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */ #define IW_RETRY_MIN 0x0001 /* Value is a minimum */ #define IW_RETRY_MAX 0x0002 /* Value is a maximum */ #define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ +#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */ +#define IW_RETRY_LONG 0x0020 /* Value is for long packets */ /* Scanning request flags */ #define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ @@ -1017,7 +1033,7 @@ struct iw_range /* Note : this frequency list doesn't need to fit channel numbers, * because each entry contain its channel index */ - __u32 enc_capa; /* IW_ENC_CAPA_* bit field */ + __u32 enc_capa; /* IW_ENC_CAPA_* bit field */ }; /* diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 13472762b18b..f47f319bb7dc 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -344,8 +344,6 @@ static ssize_t wireless_show(struct class_device *cd, char *buf, if(dev->wireless_handlers && dev->wireless_handlers->get_wireless_stats) iw = dev->wireless_handlers->get_wireless_stats(dev); - else if (dev->get_wireless_stats) - iw = dev->get_wireless_stats(dev); if (iw != NULL) ret = (*format)(iw, buf); } @@ -465,8 +463,7 @@ int netdev_register_sysfs(struct net_device *net) *groups++ = &netstat_group; #ifdef WIRELESS_EXT - if (net->get_wireless_stats - || (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)) + if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats) *groups++ = &wireless_group; #endif diff --git a/net/core/wireless.c b/net/core/wireless.c index 3168fca312f7..ffff0da46c6e 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c @@ -68,6 +68,14 @@ * * v8 - 17.02.06 - Jean II * o RtNetlink requests support (SET/GET) + * + * v8b - 03.08.06 - Herbert Xu + * o Fix Wireless Event locking issues. + * + * v9 - 14.3.06 - Jean II + * o Change length in ESSID and NICK to strlen() instead of strlen()+1 + * o Make standard_ioctl_num and standard_event_num unsigned + * o Remove (struct net_device *)->get_wireless_stats() */ /***************************** INCLUDES *****************************/ @@ -234,24 +242,24 @@ static const struct iw_ioctl_description standard_ioctl[] = { [SIOCSIWESSID - SIOCIWFIRST] = { .header_type = IW_HEADER_TYPE_POINT, .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE + 1, + .max_tokens = IW_ESSID_MAX_SIZE, .flags = IW_DESCR_FLAG_EVENT, }, [SIOCGIWESSID - SIOCIWFIRST] = { .header_type = IW_HEADER_TYPE_POINT, .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE + 1, + .max_tokens = IW_ESSID_MAX_SIZE, .flags = IW_DESCR_FLAG_DUMP, }, [SIOCSIWNICKN - SIOCIWFIRST] = { .header_type = IW_HEADER_TYPE_POINT, .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE + 1, + .max_tokens = IW_ESSID_MAX_SIZE, }, [SIOCGIWNICKN - SIOCIWFIRST] = { .header_type = IW_HEADER_TYPE_POINT, .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE + 1, + .max_tokens = IW_ESSID_MAX_SIZE, }, [SIOCSIWRATE - SIOCIWFIRST] = { .header_type = IW_HEADER_TYPE_PARAM, @@ -338,8 +346,8 @@ static const struct iw_ioctl_description standard_ioctl[] = { .max_tokens = sizeof(struct iw_pmksa), }, }; -static const int standard_ioctl_num = (sizeof(standard_ioctl) / - sizeof(struct iw_ioctl_description)); +static const unsigned standard_ioctl_num = (sizeof(standard_ioctl) / + sizeof(struct iw_ioctl_description)); /* * Meta-data about all the additional standard Wireless Extension events @@ -389,8 +397,8 @@ static const struct iw_ioctl_description standard_event[] = { .max_tokens = sizeof(struct iw_pmkid_cand), }, }; -static const int standard_event_num = (sizeof(standard_event) / - sizeof(struct iw_ioctl_description)); +static const unsigned standard_event_num = (sizeof(standard_event) / + sizeof(struct iw_ioctl_description)); /* Size (in bytes) of the various private data types */ static const char iw_priv_type_size[] = { @@ -465,17 +473,6 @@ static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) (dev->wireless_handlers->get_wireless_stats != NULL)) return dev->wireless_handlers->get_wireless_stats(dev); - /* Old location, field to be removed in next WE */ - if(dev->get_wireless_stats) { - static int printed_message; - - if (!printed_message++) - printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n", - dev->name); - - return dev->get_wireless_stats(dev); - } - /* Not found */ return (struct iw_statistics *) NULL; } @@ -1843,8 +1840,33 @@ int wireless_rtnetlink_set(struct net_device * dev, */ #ifdef WE_EVENT_RTNETLINK +/* ---------------------------------------------------------------- */ +/* + * Locking... + * ---------- + * + * Thanks to Herbert Xu for fixing + * the locking issue in here and implementing this code ! + * + * The issue : wireless_send_event() is often called in interrupt context, + * while the Netlink layer can never be called in interrupt context. + * The fully formed RtNetlink events are queued, and then a tasklet is run + * to feed those to Netlink. + * The skb_queue is interrupt safe, and its lock is not held while calling + * Netlink, so there is no possibility of dealock. + * Jean II + */ + static struct sk_buff_head wireless_nlevent_queue; +static int __init wireless_nlevent_init(void) +{ + skb_queue_head_init(&wireless_nlevent_queue); + return 0; +} + +subsys_initcall(wireless_nlevent_init); + static void wireless_nlevent_process(unsigned long data) { struct sk_buff *skb; @@ -1921,13 +1943,6 @@ static inline void rtmsg_iwinfo(struct net_device * dev, tasklet_schedule(&wireless_nlevent_tasklet); } -static int __init wireless_nlevent_init(void) -{ - skb_queue_head_init(&wireless_nlevent_queue); - return 0; -} - -subsys_initcall(wireless_nlevent_init); #endif /* WE_EVENT_RTNETLINK */ /* ---------------------------------------------------------------- */ -- cgit v1.2.3 From b77d95c78fb0ec330cd53e0d297ffa4fd2975e32 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 25 Sep 2006 21:58:50 +0100 Subject: [MTD NAND] Provide prototype for newly-exported nand_wait_ready() Signed-off-by: David Woodhouse --- include/linux/mtd/nand.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 2bcbcc896835..70420bbae82b 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -35,6 +35,9 @@ extern int nand_scan_tail(struct mtd_info *mtd); /* Free resources held by the NAND device */ extern void nand_release (struct mtd_info *mtd); +/* Internal helper for board drivers which need to override command function */ +extern void nand_wait_ready(struct mtd_info *mtd); + /* The maximum number of NAND chips in an array */ #define NAND_MAX_CHIPS 8 -- cgit v1.2.3 From 0b680e753724d31a9c45f059d1aad29df54584a1 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Fri, 22 Sep 2006 21:54:10 -0700 Subject: [PATCH] bonding: Add priv_flag to avoid event mishandling Add priv_flag to specifically identify bonding-involved devices. Needed because IFF_MASTER is an unreliable identifier (vlan interfaces above bonding will inherit IFF_MASTER). Misidentification of devices would cause notifier events for other devices to be erroneously processed by bonding, causing various havoc. Bug discovered by Martin Papik ; this patch is modified from his original. Signed-off-by: Martin Papik Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 7 ++++++- include/linux/if.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d2f460b0dbab..9e5a533a1622 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1371,6 +1371,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } new_slave->dev = slave_dev; + slave_dev->priv_flags |= IFF_BONDING; if ((bond->params.mode == BOND_MODE_TLB) || (bond->params.mode == BOND_MODE_ALB)) { @@ -1784,7 +1785,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) dev_set_mac_address(slave_dev, &addr); slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | - IFF_SLAVE_INACTIVE); + IFF_SLAVE_INACTIVE | IFF_BONDING); kfree(slave); @@ -3216,6 +3217,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v (event_dev ? event_dev->name : "None"), event); + if (!(event_dev->priv_flags & IFF_BONDING)) + return NOTIFY_DONE; + if (event_dev->flags & IFF_MASTER) { dprintk("IFF_MASTER\n"); return bond_master_netdev_event(event, event_dev); @@ -4185,6 +4189,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) /* Initialize the device options */ bond_dev->tx_queue_len = 0; bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; + bond_dev->priv_flags |= IFF_BONDING; /* At first, we block adding VLANs. That's the only way to * prevent problems that occur when adding VLANs over an diff --git a/include/linux/if.h b/include/linux/if.h index cd080d765324..a023ec1274fe 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -59,6 +59,7 @@ #define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */ #define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */ #define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */ +#define IFF_BONDING 0x20 /* bonding master or slave */ #define IF_GET_IFACE 0x0001 /* for querying only */ #define IF_GET_PROTO 0x0002 -- cgit v1.2.3 From f5b2b966f032f22d3a289045a5afd4afa09f09c6 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Fri, 22 Sep 2006 21:54:53 -0700 Subject: [PATCH] bonding: Validate probe replies in ARP monitor Add logic to check ARP request / reply packets used for ARP monitor link integrity checking. The current method simply examines the slave device to see if it has sent and received traffic; this can be fooled by extraneous traffic. For example, if multiple hosts running bonding are behind a common switch, the probe traffic from the multiple instances of bonding will update the tx/rx times on each other's slave devices. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- Documentation/networking/bonding.txt | 59 ++++++++++++ drivers/net/bonding/bond_main.c | 182 +++++++++++++++++++++++++++++++++-- drivers/net/bonding/bond_sysfs.c | 54 +++++++++++ drivers/net/bonding/bonding.h | 32 +++++- include/linux/if.h | 1 + include/linux/netdevice.h | 7 +- 6 files changed, 325 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index afac780445cd..dc942eaf490f 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -192,6 +192,17 @@ or, for backwards compatibility, the option value. E.g., arp_interval Specifies the ARP link monitoring frequency in milliseconds. + + The ARP monitor works by periodically checking the slave + devices to determine whether they have sent or received + traffic recently (the precise criteria depends upon the + bonding mode, and the state of the slave). Regular traffic is + generated via ARP probes issued for the addresses specified by + the arp_ip_target option. + + This behavior can be modified by the arp_validate option, + below. + If ARP monitoring is used in an etherchannel compatible mode (modes 0 and 2), the switch should be configured in a mode that evenly distributes packets across all links. If the @@ -213,6 +224,54 @@ arp_ip_target maximum number of targets that can be specified is 16. The default value is no IP addresses. +arp_validate + + Specifies whether or not ARP probes and replies should be + validated in the active-backup mode. This causes the ARP + monitor to examine the incoming ARP requests and replies, and + only consider a slave to be up if it is receiving the + appropriate ARP traffic. + + Possible values are: + + none or 0 + + No validation is performed. This is the default. + + active or 1 + + Validation is performed only for the active slave. + + backup or 2 + + Validation is performed only for backup slaves. + + all or 3 + + Validation is performed for all slaves. + + For the active slave, the validation checks ARP replies to + confirm that they were generated by an arp_ip_target. Since + backup slaves do not typically receive these replies, the + validation performed for backup slaves is on the ARP request + sent out via the active slave. It is possible that some + switch or network configurations may result in situations + wherein the backup slaves do not receive the ARP requests; in + such a situation, validation of backup slaves must be + disabled. + + This option is useful in network configurations in which + multiple bonding hosts are concurrently issuing ARPs to one or + more targets beyond a common switch. Should the link between + the switch and target fail (but not the switch itself), the + probe traffic generated by the multiple bonding instances will + fool the standard ARP monitor into considering the links as + still up. Use of the arp_validate option can resolve this, as + the ARP monitor will only consider ARP requests and replies + associated with its own instance of bonding. + + This option was added in bonding version 3.1.0. + downdelay Specifies the time, in milliseconds, to wait before disabling diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index bafe62f7c9b7..fd521b05db83 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -96,6 +96,7 @@ static char *lacp_rate = NULL; static char *xmit_hash_policy = NULL; static int arp_interval = BOND_LINK_ARP_INTERV; static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; +static char *arp_validate = NULL; struct bond_params bonding_defaults; module_param(max_bonds, int, 0); @@ -127,6 +128,8 @@ module_param(arp_interval, int, 0); MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); module_param_array(arp_ip_target, charp, NULL, 0); MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); +module_param(arp_validate, charp, 0); +MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); /*----------------------------- Global variables ----------------------------*/ @@ -170,6 +173,14 @@ struct bond_parm_tbl xmit_hashtype_tbl[] = { { NULL, -1}, }; +struct bond_parm_tbl arp_validate_tbl[] = { +{ "none", BOND_ARP_VALIDATE_NONE}, +{ "active", BOND_ARP_VALIDATE_ACTIVE}, +{ "backup", BOND_ARP_VALIDATE_BACKUP}, +{ "all", BOND_ARP_VALIDATE_ALL}, +{ NULL, -1}, +}; + /*-------------------------- Forward declarations ---------------------------*/ static void bond_send_gratuitous_arp(struct bonding *bond); @@ -1424,6 +1435,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_compute_features(bond); + new_slave->last_arp_rx = jiffies; + if (bond->params.miimon && !bond->params.use_carrier) { link_reporting = bond_check_dev_link(bond, slave_dev, 1); @@ -1785,7 +1798,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) dev_set_mac_address(slave_dev, &addr); slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | - IFF_SLAVE_INACTIVE | IFF_BONDING); + IFF_SLAVE_INACTIVE | IFF_BONDING | + IFF_SLAVE_NEEDARP); kfree(slave); @@ -2298,6 +2312,25 @@ static int bond_has_ip(struct bonding *bond) return 0; } +static int bond_has_this_ip(struct bonding *bond, u32 ip) +{ + struct vlan_entry *vlan, *vlan_next; + + if (ip == bond->master_ip) + return 1; + + if (list_empty(&bond->vlan_list)) + return 0; + + list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, + vlan_list) { + if (ip == vlan->vlan_ip) + return 1; + } + + return 0; +} + /* * We go to the (large) trouble of VLAN tagging ARP frames because * switches in VLAN mode (especially if ports are configured as @@ -2436,6 +2469,93 @@ static void bond_send_gratuitous_arp(struct bonding *bond) } } +static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip) +{ + int i; + u32 *targets = bond->params.arp_targets; + + targets = bond->params.arp_targets; + for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { + dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] " + "%u.%u.%u.%u bhti(tip) %d\n", + NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]), + bond_has_this_ip(bond, tip)); + if (sip == targets[i]) { + if (bond_has_this_ip(bond, tip)) + slave->last_arp_rx = jiffies; + return; + } + } +} + +static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) +{ + struct arphdr *arp; + struct slave *slave; + struct bonding *bond; + unsigned char *arp_ptr; + u32 sip, tip; + + if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) + goto out; + + bond = dev->priv; + read_lock(&bond->lock); + + dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n", + bond->dev->name, skb->dev ? skb->dev->name : "NULL", + orig_dev ? orig_dev->name : "NULL"); + + slave = bond_get_slave_by_dev(bond, orig_dev); + if (!slave || !slave_do_arp_validate(bond, slave)) + goto out_unlock; + + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ + if (!pskb_may_pull(skb, (sizeof(struct arphdr) + + (2 * dev->addr_len) + + (2 * sizeof(u32))))) + goto out_unlock; + + arp = skb->nh.arph; + if (arp->ar_hln != dev->addr_len || + skb->pkt_type == PACKET_OTHERHOST || + skb->pkt_type == PACKET_LOOPBACK || + arp->ar_hrd != htons(ARPHRD_ETHER) || + arp->ar_pro != htons(ETH_P_IP) || + arp->ar_pln != 4) + goto out_unlock; + + arp_ptr = (unsigned char *)(arp + 1); + arp_ptr += dev->addr_len; + memcpy(&sip, arp_ptr, 4); + arp_ptr += 4 + dev->addr_len; + memcpy(&tip, arp_ptr, 4); + + dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u" + " tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name, + slave->state, bond->params.arp_validate, + slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip)); + + /* + * Backup slaves won't see the ARP reply, but do come through + * here for each ARP probe (so we swap the sip/tip to validate + * the probe). In a "redundant switch, common router" type of + * configuration, the ARP probe will (hopefully) travel from + * the active, through one switch, the router, then the other + * switch before reaching the backup. + */ + if (slave->state == BOND_STATE_ACTIVE) + bond_validate_arp(bond, slave, sip, tip); + else + bond_validate_arp(bond, slave, tip, sip); + +out_unlock: + read_unlock(&bond->lock); +out: + dev_kfree_skb(skb); + return NET_RX_SUCCESS; +} + /* * this function is called regularly to monitor each slave's link * ensuring that traffic is being sent and received when arp monitoring @@ -2600,7 +2720,8 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) */ bond_for_each_slave(bond, slave, i) { if (slave->link != BOND_LINK_UP) { - if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) { + if ((jiffies - slave_last_rx(bond, slave)) <= + delta_in_ticks) { slave->link = BOND_LINK_UP; @@ -2645,7 +2766,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) if ((slave != bond->curr_active_slave) && (!bond->current_arp_slave) && - (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && + (((jiffies - slave_last_rx(bond, slave)) >= 3*delta_in_ticks) && bond_has_ip(bond))) { /* a backup slave has gone down; three times * the delta allows the current slave to be @@ -2692,7 +2813,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) * if it is up and needs to take over as the curr_active_slave */ if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + (((jiffies - slave_last_rx(bond, slave)) >= (2*delta_in_ticks)) && bond_has_ip(bond))) && ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { @@ -3315,6 +3436,21 @@ static void bond_unregister_lacpdu(struct bonding *bond) dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); } +void bond_register_arp(struct bonding *bond) +{ + struct packet_type *pt = &bond->arp_mon_pt; + + pt->type = htons(ETH_P_ARP); + pt->dev = NULL; /*bond->dev;XXX*/ + pt->func = bond_arp_rcv; + dev_add_pack(pt); +} + +void bond_unregister_arp(struct bonding *bond) +{ + dev_remove_pack(&bond->arp_mon_pt); +} + /*---------------------------- Hashing Policies -----------------------------*/ /* @@ -3401,6 +3537,9 @@ static int bond_open(struct net_device *bond_dev) } else { arp_timer->function = (void *)&bond_loadbalance_arp_mon; } + if (bond->params.arp_validate) + bond_register_arp(bond); + add_timer(arp_timer); } @@ -3428,6 +3567,9 @@ static int bond_close(struct net_device *bond_dev) bond_unregister_lacpdu(bond); } + if (bond->params.arp_validate) + bond_unregister_arp(bond); + write_lock_bh(&bond->lock); @@ -4281,6 +4423,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) static int bond_check_params(struct bond_params *params) { + int arp_validate_value; + /* * Convert string parameters. */ @@ -4484,6 +4628,29 @@ static int bond_check_params(struct bond_params *params) arp_interval = 0; } + if (arp_validate) { + if (bond_mode != BOND_MODE_ACTIVEBACKUP) { + printk(KERN_ERR DRV_NAME + ": arp_validate only supported in active-backup mode\n"); + return -EINVAL; + } + if (!arp_interval) { + printk(KERN_ERR DRV_NAME + ": arp_validate requires arp_interval\n"); + return -EINVAL; + } + + arp_validate_value = bond_parse_parm(arp_validate, + arp_validate_tbl); + if (arp_validate_value == -1) { + printk(KERN_ERR DRV_NAME + ": Error: invalid arp_validate \"%s\"\n", + arp_validate == NULL ? "NULL" : arp_validate); + return -EINVAL; + } + } else + arp_validate_value = 0; + if (miimon) { printk(KERN_INFO DRV_NAME ": MII link monitoring set to %d ms\n", @@ -4492,8 +4659,10 @@ static int bond_check_params(struct bond_params *params) int i; printk(KERN_INFO DRV_NAME - ": ARP monitoring set to %d ms with %d target(s):", - arp_interval, arp_ip_count); + ": ARP monitoring set to %d ms, validate %s, with %d target(s):", + arp_interval, + arp_validate_tbl[arp_validate_value].modename, + arp_ip_count); for (i = 0; i < arp_ip_count; i++) printk (" %s", arp_ip_target[i]); @@ -4527,6 +4696,7 @@ static int bond_check_params(struct bond_params *params) params->xmit_policy = xmit_hashtype; params->miimon = miimon; params->arp_interval = arp_interval; + params->arp_validate = arp_validate_value; params->updelay = updelay; params->downdelay = downdelay; params->use_carrier = use_carrier; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 15b6a29bb4d4..ced9ed8f995a 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -51,6 +51,7 @@ extern struct bond_params bonding_defaults; extern struct bond_parm_tbl bond_mode_tbl[]; extern struct bond_parm_tbl bond_lacp_tbl[]; extern struct bond_parm_tbl xmit_hashtype_tbl[]; +extern struct bond_parm_tbl arp_validate_tbl[]; static int expected_refcount = -1; static struct class *netdev_class; @@ -502,6 +503,53 @@ out: } static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); +/* + * Show and set arp_validate. + */ +static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf) +{ + struct bonding *bond = to_bond(cd); + + return sprintf(buf, "%s %d\n", + arp_validate_tbl[bond->params.arp_validate].modename, + bond->params.arp_validate) + 1; +} + +static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count) +{ + int new_value; + struct bonding *bond = to_bond(cd); + + new_value = bond_parse_parm((char *)buf, arp_validate_tbl); + if (new_value < 0) { + printk(KERN_ERR DRV_NAME + ": %s: Ignoring invalid arp_validate value %s\n", + bond->dev->name, buf); + return -EINVAL; + } + if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) { + printk(KERN_ERR DRV_NAME + ": %s: arp_validate only supported in active-backup mode.\n", + bond->dev->name); + return -EINVAL; + } + printk(KERN_INFO DRV_NAME ": %s: setting arp_validate to %s (%d).\n", + bond->dev->name, arp_validate_tbl[new_value].modename, + new_value); + + if (!bond->params.arp_validate && new_value) { + bond_register_arp(bond); + } else if (bond->params.arp_validate && !new_value) { + bond_unregister_arp(bond); + } + + bond->params.arp_validate = new_value; + + return count; +} + +static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); + /* * Show and set the arp timer interval. There are two tricky bits * here. First, if ARP monitoring is activated, then we must disable @@ -914,6 +962,11 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si "ARP monitoring. Disabling ARP monitoring...\n", bond->dev->name); bond->params.arp_interval = 0; + if (bond->params.arp_validate) { + bond_unregister_arp(bond); + bond->params.arp_validate = + BOND_ARP_VALIDATE_NONE; + } /* Kill ARP timer, else it brings bond's link down */ if (bond->mii_timer.function) { printk(KERN_INFO DRV_NAME @@ -1273,6 +1326,7 @@ static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, N static struct attribute *per_bond_attrs[] = { &class_device_attr_slaves.attr, &class_device_attr_mode.attr, + &class_device_attr_arp_validate.attr, &class_device_attr_arp_interval.attr, &class_device_attr_arp_ip_target.attr, &class_device_attr_downdelay.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 17caafe58247..db16fee40a5f 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.0.3" -#define DRV_RELDATE "March 23, 2006" +#define DRV_VERSION "3.1.0-test" +#define DRV_RELDATE "September 9, 2006" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -126,6 +126,7 @@ struct bond_params { int xmit_policy; int miimon; int arp_interval; + int arp_validate; int use_carrier; int updelay; int downdelay; @@ -151,6 +152,7 @@ struct slave { struct slave *prev; int delay; u32 jiffies; + u32 last_arp_rx; s8 link; /* one of BOND_LINK_XXXX */ s8 state; /* one of BOND_STATE_XXXX */ u32 original_flags; @@ -198,6 +200,7 @@ struct bonding { struct bond_params params; struct list_head vlan_list; struct vlan_group *vlgrp; + struct packet_type arp_mon_pt; }; /** @@ -228,6 +231,25 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) return (struct bonding *)slave->dev->master->priv; } +#define BOND_ARP_VALIDATE_NONE 0 +#define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE) +#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP) +#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \ + BOND_ARP_VALIDATE_BACKUP) + +extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave) +{ + return bond->params.arp_validate & (1 << slave->state); +} + +extern inline u32 slave_last_rx(struct bonding *bond, struct slave *slave) +{ + if (slave_do_arp_validate(bond, slave)) + return slave->last_arp_rx; + + return slave->dev->last_rx; +} + static inline void bond_set_slave_inactive_flags(struct slave *slave) { struct bonding *bond = slave->dev->master->priv; @@ -235,12 +257,14 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave) bond->params.mode != BOND_MODE_ALB) slave->state = BOND_STATE_BACKUP; slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; + if (slave_do_arp_validate(bond, slave)) + slave->dev->priv_flags |= IFF_SLAVE_NEEDARP; } static inline void bond_set_slave_active_flags(struct slave *slave) { slave->state = BOND_STATE_ACTIVE; - slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE; + slave->dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_SLAVE_NEEDARP); } static inline void bond_set_master_3ad_flags(struct bonding *bond) @@ -284,6 +308,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl); const char *bond_mode_name(int mode); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); +void bond_register_arp(struct bonding *); +void bond_unregister_arp(struct bonding *); #endif /* _LINUX_BONDING_H */ diff --git a/include/linux/if.h b/include/linux/if.h index a023ec1274fe..8018c2e22c0c 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -60,6 +60,7 @@ #define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */ #define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */ #define IFF_BONDING 0x20 /* bonding master or slave */ +#define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */ #define IF_GET_IFACE 0x0001 /* for querying only */ #define IF_GET_PROTO 0x0002 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 43289127b458..afd80eff2725 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1016,7 +1016,8 @@ static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) } /* On bonding slaves other than the currently active slave, suppress - * duplicates except for 802.3ad ETH_P_SLOW and alb non-mcast/bcast. + * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and + * ARP on active-backup slaves with arp_validate enabled. */ static inline int skb_bond_should_drop(struct sk_buff *skb) { @@ -1025,6 +1026,10 @@ static inline int skb_bond_should_drop(struct sk_buff *skb) if (master && (dev->priv_flags & IFF_SLAVE_INACTIVE)) { + if ((dev->priv_flags & IFF_SLAVE_NEEDARP) && + skb->protocol == __constant_htons(ETH_P_ARP)) + return 0; + if (master->priv_flags & IFF_MASTER_ALB) { if (skb->pkt_type != PACKET_BROADCAST && skb->pkt_type != PACKET_MULTICAST) -- cgit v1.2.3 From 1739adea321788e380794c1072c810d445090bca Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 26 Aug 2006 03:05:17 -0300 Subject: V4L/DVB (4545): Add missing v4l2_buf_type to struct v4l2_sliced_vbi_cap. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index e3715d774197..d5746d470c73 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -1135,7 +1135,8 @@ struct v4l2_sliced_vbi_cap (equals frame lines 313-336 for 625 line video standards, 263-286 for 525 line standards) */ __u16 service_lines[2][24]; - __u32 reserved[4]; /* must be 0 */ + enum v4l2_buf_type type; + __u32 reserved[3]; /* must be 0 */ }; struct v4l2_sliced_vbi_data -- cgit v1.2.3 From 616b8b639e6491cfa63f79238a5c6fbee383eb09 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 1 Sep 2006 18:36:48 -0300 Subject: V4L/DVB (4585): VIDIOC_G_SLICED_VBI_CAP now accepts a v4l2_buf_type, make it IOWR The VIDIOC_G_SLICED_VBI_CAP needs to receive the v4l2_buf_type field before it can return a result. Hence this ioctl must be IOWR, not IOR. Since this ioctl is still marked experimental we can make this change. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index d5746d470c73..44c59da26ed2 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -1243,7 +1243,7 @@ struct v4l2_streamparm #define VIDIOC_G_PRIORITY _IOR ('V', 67, enum v4l2_priority) #define VIDIOC_S_PRIORITY _IOW ('V', 68, enum v4l2_priority) #if 1 -#define VIDIOC_G_SLICED_VBI_CAP _IOR ('V', 69, struct v4l2_sliced_vbi_cap) +#define VIDIOC_G_SLICED_VBI_CAP _IOWR ('V', 69, struct v4l2_sliced_vbi_cap) #endif #define VIDIOC_LOG_STATUS _IO ('V', 70) #define VIDIOC_G_EXT_CTRLS _IOWR ('V', 71, struct v4l2_ext_controls) -- cgit v1.2.3 From 28b79ff9661b22e4c41c0d00d4ab8503e810f13d Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Tue, 26 Sep 2006 09:45:28 +0000 Subject: [MTD ONENAND] Check OneNAND lock scheme & all block unlock command support OneNAND lock scheme depends on density and process of chip. Some OneNAND chips support all block unlock Signed-off-by: Kyungmin Park Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 137 ++++++++++++++++++++++++++++++++----- include/linux/mtd/onenand.h | 6 +- include/linux/mtd/onenand_regs.h | 4 +- 3 files changed, 125 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 09aefe2164aa..8ed68b28afe3 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1,7 +1,7 @@ /* * linux/drivers/mtd/onenand/onenand_base.c * - * Copyright (C) 2005 Samsung Electronics + * Copyright (C) 2005-2006 Samsung Electronics * Kyungmin Park * * This program is free software; you can redistribute it and/or modify @@ -199,6 +199,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le case ONENAND_CMD_UNLOCK: case ONENAND_CMD_LOCK: case ONENAND_CMD_LOCK_TIGHT: + case ONENAND_CMD_UNLOCK_ALL: block = -1; page = -1; break; @@ -1211,11 +1212,11 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) end = len >> this->erase_shift; /* Continuous lock scheme */ - if (this->options & ONENAND_CONT_LOCK) { + if (this->options & ONENAND_HAS_CONT_LOCK) { /* Set start block address */ this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS); /* Set end block address */ - this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); + this->write_word(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); /* Write unlock command */ this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); @@ -1236,7 +1237,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) } /* Block lock scheme */ - for (block = start; block < end; block++) { + for (block = start; block < start + end; block++) { /* Set block address */ value = onenand_block_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); @@ -1265,6 +1266,79 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) return 0; } +/** + * onenand_check_lock_status - [OneNAND Interface] Check lock status + * @param this onenand chip data structure + * + * Check lock status + */ +static void onenand_check_lock_status(struct onenand_chip *this) +{ + unsigned int value, block, status; + unsigned int end; + + end = this->chipsize >> this->erase_shift; + for (block = 0; block < end; block++) { + /* Set block address */ + value = onenand_block_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); + /* Select DataRAM for DDP */ + value = onenand_bufferram_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); + /* Set start block address */ + this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); + + /* Check lock status */ + status = this->read_word(this->base + ONENAND_REG_WP_STATUS); + if (!(status & ONENAND_WP_US)) + printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); + } +} + +/** + * onenand_unlock_all - [OneNAND Interface] unlock all blocks + * @param mtd MTD device structure + * + * Unlock all blocks + */ +static int onenand_unlock_all(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + + if (this->options & ONENAND_HAS_UNLOCK_ALL) { + /* Write unlock command */ + this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0); + + /* There's no return value */ + this->wait(mtd, FL_UNLOCKING); + + /* Sanity check */ + while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) + & ONENAND_CTRL_ONGO) + continue; + + /* Workaround for all block unlock in DDP */ + if (this->device_id & ONENAND_DEVICE_IS_DDP) { + loff_t ofs; + size_t len; + + /* 1st block on another chip */ + ofs = this->chipsize >> 1; + len = 1 << this->erase_shift; + + onenand_unlock(mtd, ofs, len); + } + + onenand_check_lock_status(this); + + return 0; + } + + mtd->unlock(mtd, 0x0, this->chipsize); + + return 0; +} + #ifdef CONFIG_MTD_ONENAND_OTP /* Interal OTP operation */ @@ -1563,13 +1637,44 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, } #endif /* CONFIG_MTD_ONENAND_OTP */ +/** + * onenand_lock_scheme - Check and set OneNAND lock scheme + * @param mtd MTD data structure + * + * Check and set OneNAND lock scheme + */ +static void onenand_lock_scheme(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + unsigned int density, process; + + /* Lock scheme depends on density and process */ + density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT; + process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; + + /* Lock scheme */ + if (density >= ONENAND_DEVICE_DENSITY_1Gb) { + /* A-Die has all block unlock */ + if (process) { + printk(KERN_DEBUG "Chip support all block unlock\n"); + this->options |= ONENAND_HAS_UNLOCK_ALL; + } + } else { + /* Some OneNAND has continues lock scheme */ + if (!process) { + printk(KERN_DEBUG "Lock scheme is Continues Lock\n"); + this->options |= ONENAND_HAS_CONT_LOCK; + } + } +} + /** * onenand_print_device_info - Print device ID * @param device device ID * * Print device ID */ -static void onenand_print_device_info(int device) +static void onenand_print_device_info(int device, int version) { int vcc, demuxed, ddp, density; @@ -1583,6 +1688,7 @@ static void onenand_print_device_info(int device) (16 << density), vcc ? "2.65/3.3" : "1.8", device); + printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version); } static const struct onenand_manufacturers onenand_manuf_ids[] = { @@ -1625,8 +1731,7 @@ static int onenand_check_maf(int manuf) static int onenand_probe(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; - int bram_maf_id, bram_dev_id, maf_id, dev_id; - int version_id; + int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id; int density; int syscfg; @@ -1657,14 +1762,16 @@ static int onenand_probe(struct mtd_info *mtd) /* Read manufacturer and device IDs from Register */ maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); + ver_id= this->read_word(this->base + ONENAND_REG_VERSION_ID); /* Check OneNAND device */ if (maf_id != bram_maf_id || dev_id != bram_dev_id) return -ENXIO; /* Flash device information */ - onenand_print_device_info(dev_id); + onenand_print_device_info(dev_id, ver_id); this->device_id = dev_id; + this->version_id = ver_id; density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; this->chipsize = (16 << density) << 20; @@ -1687,16 +1794,8 @@ static int onenand_probe(struct mtd_info *mtd) mtd->size = this->chipsize; - /* Version ID */ - version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); - printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id); - - /* Lock scheme */ - if (density <= ONENAND_DEVICE_DENSITY_512Mb && - !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) { - printk(KERN_INFO "Lock scheme is Continues Lock\n"); - this->options |= ONENAND_CONT_LOCK; - } + /* Check OneNAND lock scheme */ + onenand_lock_scheme(mtd); return 0; } @@ -1832,7 +1931,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->owner = THIS_MODULE; /* Unlock whole block */ - mtd->unlock(mtd, 0x0, this->chipsize); + onenand_unlock_all(mtd); return this->scan_bbt(mtd); } diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index 1f4972155249..6f045b586e76 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -1,7 +1,7 @@ /* * linux/include/linux/mtd/onenand.h * - * Copyright (C) 2005 Samsung Electronics + * Copyright (C) 2005-2006 Samsung Electronics * Kyungmin Park * * This program is free software; you can redistribute it and/or modify @@ -96,6 +96,7 @@ struct onenand_chip { void __iomem *base; unsigned int chipsize; unsigned int device_id; + unsigned int version_id; unsigned int density_mask; unsigned int options; @@ -149,7 +150,8 @@ struct onenand_chip { /* * Options bits */ -#define ONENAND_CONT_LOCK (0x0001) +#define ONENAND_HAS_CONT_LOCK (0x0001) +#define ONENAND_HAS_UNLOCK_ALL (0x0002) #define ONENAND_PAGEBUF_ALLOC (0x1000) /* diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h index 4a72818d2545..9e409fe6ded6 100644 --- a/include/linux/mtd/onenand_regs.h +++ b/include/linux/mtd/onenand_regs.h @@ -3,7 +3,7 @@ * * OneNAND Register header file * - * Copyright (C) 2005 Samsung Electronics + * Copyright (C) 2005-2006 Samsung Electronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -72,6 +72,7 @@ #define ONENAND_DEVICE_VCC_MASK (0x3) #define ONENAND_DEVICE_DENSITY_512Mb (0x002) +#define ONENAND_DEVICE_DENSITY_1Gb (0x003) /* * Version ID Register F002h (R) @@ -110,6 +111,7 @@ #define ONENAND_CMD_UNLOCK (0x23) #define ONENAND_CMD_LOCK (0x2A) #define ONENAND_CMD_LOCK_TIGHT (0x2C) +#define ONENAND_CMD_UNLOCK_ALL (0x27) #define ONENAND_CMD_ERASE (0x94) #define ONENAND_CMD_RESET (0xF0) #define ONENAND_CMD_OTP_ACCESS (0x65) -- cgit v1.2.3 From 5e96f59f9b20373014abd5e30fba4805c5d4f53f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 26 Sep 2006 17:14:02 -0400 Subject: [GFS2] Remove (extra) fs_subsys declaration This is already in Linus' tree, so we don't need to add another one. Signed-off-by: Steven Whitehouse --- include/linux/fs.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 48f982100f5a..1d3e601ece73 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1377,9 +1377,6 @@ extern struct subsystem fs_subsys; #define FLOCK_VERIFY_READ 1 #define FLOCK_VERIFY_WRITE 2 -/* /sys/fs */ -extern struct subsystem fs_subsys; - extern int locks_mandatory_locked(struct inode *); extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t); -- cgit v1.2.3 From eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfb Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Tue, 26 Sep 2006 23:23:45 +0200 Subject: [PATCH] Modularize generic HDLC This patch enables building of individual WAN protocol support routines (parts of generic HDLC) as separate modules. All protocol-private definitions are moved from hdlc.h file to protocol drivers. User-space interface and interface between generic HDLC and underlying low-level HDLC drivers are unchanged. Signed-off-by: Krzysztof Halasa Signed-off-by: Jeff Garzik --- drivers/net/wan/Kconfig | 12 +- drivers/net/wan/Makefile | 19 +- drivers/net/wan/hdlc.c | 368 ++++++++++++++++++++++++++++++++++++++ drivers/net/wan/hdlc_cisco.c | 198 ++++++++++++++------- drivers/net/wan/hdlc_fr.c | 389 +++++++++++++++++++++++++---------------- drivers/net/wan/hdlc_generic.c | 339 ----------------------------------- drivers/net/wan/hdlc_ppp.c | 77 ++++++-- drivers/net/wan/hdlc_raw.c | 50 +++++- drivers/net/wan/hdlc_raw_eth.c | 49 +++++- drivers/net/wan/hdlc_x25.c | 54 ++++-- include/linux/hdlc.h | 201 +++++---------------- include/linux/hdlc/ioctl.h | 33 ++++ 12 files changed, 1012 insertions(+), 777 deletions(-) create mode 100644 drivers/net/wan/hdlc.c delete mode 100644 drivers/net/wan/hdlc_generic.c (limited to 'include/linux') diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 54b8e492ef97..58b7efbb0750 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -154,7 +154,7 @@ config HDLC If unsure, say N. config HDLC_RAW - bool "Raw HDLC support" + tristate "Raw HDLC support" depends on HDLC help Generic HDLC driver supporting raw HDLC over WAN connections. @@ -162,7 +162,7 @@ config HDLC_RAW If unsure, say N. config HDLC_RAW_ETH - bool "Raw HDLC Ethernet device support" + tristate "Raw HDLC Ethernet device support" depends on HDLC help Generic HDLC driver supporting raw HDLC Ethernet device emulation @@ -173,7 +173,7 @@ config HDLC_RAW_ETH If unsure, say N. config HDLC_CISCO - bool "Cisco HDLC support" + tristate "Cisco HDLC support" depends on HDLC help Generic HDLC driver supporting Cisco HDLC over WAN connections. @@ -181,7 +181,7 @@ config HDLC_CISCO If unsure, say N. config HDLC_FR - bool "Frame Relay support" + tristate "Frame Relay support" depends on HDLC help Generic HDLC driver supporting Frame Relay over WAN connections. @@ -189,7 +189,7 @@ config HDLC_FR If unsure, say N. config HDLC_PPP - bool "Synchronous Point-to-Point Protocol (PPP) support" + tristate "Synchronous Point-to-Point Protocol (PPP) support" depends on HDLC help Generic HDLC driver supporting PPP over WAN connections. @@ -197,7 +197,7 @@ config HDLC_PPP If unsure, say N. config HDLC_X25 - bool "X.25 protocol support" + tristate "X.25 protocol support" depends on HDLC && (LAPB=m && HDLC=m || LAPB=y) help Generic HDLC driver supporting X.25 over WAN connections. diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 316ca6869d5e..83ec2c87ba3f 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -9,14 +9,13 @@ cyclomx-y := cycx_main.o cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o cyclomx-objs := $(cyclomx-y) -hdlc-y := hdlc_generic.o -hdlc-$(CONFIG_HDLC_RAW) += hdlc_raw.o -hdlc-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o -hdlc-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o -hdlc-$(CONFIG_HDLC_FR) += hdlc_fr.o -hdlc-$(CONFIG_HDLC_PPP) += hdlc_ppp.o -hdlc-$(CONFIG_HDLC_X25) += hdlc_x25.o -hdlc-objs := $(hdlc-y) +obj-$(CONFIG_HDLC) += hdlc.o +obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o +obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o +obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o +obj-$(CONFIG_HDLC_FR) += hdlc_fr.o +obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o +obj-$(CONFIG_HDLC_X25) += hdlc_x25.o pc300-y := pc300_drv.o pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o @@ -38,10 +37,6 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_SBNI) += sbni.o obj-$(CONFIG_PC300) += pc300.o -obj-$(CONFIG_HDLC) += hdlc.o -ifeq ($(CONFIG_HDLC_PPP),y) - obj-$(CONFIG_HDLC) += syncppp.o -endif obj-$(CONFIG_N2) += n2.o obj-$(CONFIG_C101) += c101.o obj-$(CONFIG_WANXL) += wanxl.o diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c new file mode 100644 index 000000000000..db354e0edbe5 --- /dev/null +++ b/drivers/net/wan/hdlc.c @@ -0,0 +1,368 @@ +/* + * Generic HDLC support routines for Linux + * + * Copyright (C) 1999 - 2006 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * Currently supported: + * * raw IP-in-HDLC + * * Cisco HDLC + * * Frame Relay with ANSI or CCITT LMI (both user and network side) + * * PPP + * * X.25 + * + * Use sethdlc utility to set line parameters, protocol and PVCs + * + * How does it work: + * - proto->open(), close(), start(), stop() calls are serialized. + * The order is: open, [ start, stop ... ] close ... + * - proto->start() and stop() are called with spin_lock_irq held. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char* version = "HDLC support module revision 1.20"; + +#undef DEBUG_LINK + +static struct hdlc_proto *first_proto = NULL; + + +static int hdlc_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + + + +static struct net_device_stats *hdlc_get_stats(struct net_device *dev) +{ + return hdlc_stats(dev); +} + + + +static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *p, struct net_device *orig_dev) +{ + struct hdlc_device_desc *desc = dev_to_desc(dev); + if (desc->netif_rx) + return desc->netif_rx(skb); + + desc->stats.rx_dropped++; /* Shouldn't happen */ + dev_kfree_skb(skb); + return NET_RX_DROP; +} + + + +static inline void hdlc_proto_start(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + if (hdlc->proto->start) + return hdlc->proto->start(dev); +} + + + +static inline void hdlc_proto_stop(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + if (hdlc->proto->stop) + return hdlc->proto->stop(dev); +} + + + +static int hdlc_device_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + hdlc_device *hdlc; + unsigned long flags; + int on; + + if (dev->get_stats != hdlc_get_stats) + return NOTIFY_DONE; /* not an HDLC device */ + + if (event != NETDEV_CHANGE) + return NOTIFY_DONE; /* Only interrested in carrier changes */ + + on = netif_carrier_ok(dev); + +#ifdef DEBUG_LINK + printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n", + dev->name, on); +#endif + + hdlc = dev_to_hdlc(dev); + spin_lock_irqsave(&hdlc->state_lock, flags); + + if (hdlc->carrier == on) + goto carrier_exit; /* no change in DCD line level */ + + hdlc->carrier = on; + + if (!hdlc->open) + goto carrier_exit; + + if (hdlc->carrier) { + printk(KERN_INFO "%s: Carrier detected\n", dev->name); + hdlc_proto_start(dev); + } else { + printk(KERN_INFO "%s: Carrier lost\n", dev->name); + hdlc_proto_stop(dev); + } + +carrier_exit: + spin_unlock_irqrestore(&hdlc->state_lock, flags); + return NOTIFY_DONE; +} + + + +/* Must be called by hardware driver when HDLC device is being opened */ +int hdlc_open(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); +#ifdef DEBUG_LINK + printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name, + hdlc->carrier, hdlc->open); +#endif + + if (hdlc->proto == NULL) + return -ENOSYS; /* no protocol attached */ + + if (hdlc->proto->open) { + int result = hdlc->proto->open(dev); + if (result) + return result; + } + + spin_lock_irq(&hdlc->state_lock); + + if (hdlc->carrier) { + printk(KERN_INFO "%s: Carrier detected\n", dev->name); + hdlc_proto_start(dev); + } else + printk(KERN_INFO "%s: No carrier\n", dev->name); + + hdlc->open = 1; + + spin_unlock_irq(&hdlc->state_lock); + return 0; +} + + + +/* Must be called by hardware driver when HDLC device is being closed */ +void hdlc_close(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); +#ifdef DEBUG_LINK + printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name, + hdlc->carrier, hdlc->open); +#endif + + spin_lock_irq(&hdlc->state_lock); + + hdlc->open = 0; + if (hdlc->carrier) + hdlc_proto_stop(dev); + + spin_unlock_irq(&hdlc->state_lock); + + if (hdlc->proto->close) + hdlc->proto->close(dev); +} + + + +int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct hdlc_proto *proto = first_proto; + int result; + + if (cmd != SIOCWANDEV) + return -EINVAL; + + if (dev_to_hdlc(dev)->proto) { + result = dev_to_hdlc(dev)->proto->ioctl(dev, ifr); + if (result != -EINVAL) + return result; + } + + /* Not handled by currently attached protocol (if any) */ + + while (proto) { + if ((result = proto->ioctl(dev, ifr)) != -EINVAL) + return result; + proto = proto->next; + } + return -EINVAL; +} + +void hdlc_setup(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + dev->get_stats = hdlc_get_stats; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + + dev->type = ARPHRD_RAWHDLC; + dev->hard_header_len = 16; + + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + + hdlc->carrier = 1; + hdlc->open = 0; + spin_lock_init(&hdlc->state_lock); +} + +struct net_device *alloc_hdlcdev(void *priv) +{ + struct net_device *dev; + dev = alloc_netdev(sizeof(struct hdlc_device_desc) + + sizeof(hdlc_device), "hdlc%d", hdlc_setup); + if (dev) + dev_to_hdlc(dev)->priv = priv; + return dev; +} + +void unregister_hdlc_device(struct net_device *dev) +{ + rtnl_lock(); + unregister_netdevice(dev); + detach_hdlc_protocol(dev); + rtnl_unlock(); +} + + + +int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto, + int (*rx)(struct sk_buff *skb), size_t size) +{ + detach_hdlc_protocol(dev); + + if (!try_module_get(proto->module)) + return -ENOSYS; + + if (size) + if ((dev_to_hdlc(dev)->state = kmalloc(size, + GFP_KERNEL)) == NULL) { + printk(KERN_WARNING "Memory squeeze on" + " hdlc_proto_attach()\n"); + module_put(proto->module); + return -ENOBUFS; + } + dev_to_hdlc(dev)->proto = proto; + dev_to_desc(dev)->netif_rx = rx; + return 0; +} + + +void detach_hdlc_protocol(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + if (hdlc->proto) { + if (hdlc->proto->detach) + hdlc->proto->detach(dev); + module_put(hdlc->proto->module); + hdlc->proto = NULL; + } + kfree(hdlc->state); + hdlc->state = NULL; +} + + +void register_hdlc_protocol(struct hdlc_proto *proto) +{ + proto->next = first_proto; + first_proto = proto; +} + + +void unregister_hdlc_protocol(struct hdlc_proto *proto) +{ + struct hdlc_proto **p = &first_proto; + while (*p) { + if (*p == proto) { + *p = proto->next; + return; + } + p = &((*p)->next); + } +} + + + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("HDLC support module"); +MODULE_LICENSE("GPL v2"); + +EXPORT_SYMBOL(hdlc_open); +EXPORT_SYMBOL(hdlc_close); +EXPORT_SYMBOL(hdlc_ioctl); +EXPORT_SYMBOL(hdlc_setup); +EXPORT_SYMBOL(alloc_hdlcdev); +EXPORT_SYMBOL(unregister_hdlc_device); +EXPORT_SYMBOL(register_hdlc_protocol); +EXPORT_SYMBOL(unregister_hdlc_protocol); +EXPORT_SYMBOL(attach_hdlc_protocol); +EXPORT_SYMBOL(detach_hdlc_protocol); + +static struct packet_type hdlc_packet_type = { + .type = __constant_htons(ETH_P_HDLC), + .func = hdlc_rcv, +}; + + +static struct notifier_block hdlc_notifier = { + .notifier_call = hdlc_device_event, +}; + + +static int __init hdlc_module_init(void) +{ + int result; + + printk(KERN_INFO "%s\n", version); + if ((result = register_netdevice_notifier(&hdlc_notifier)) != 0) + return result; + dev_add_pack(&hdlc_packet_type); + return 0; +} + + + +static void __exit hdlc_module_exit(void) +{ + dev_remove_pack(&hdlc_packet_type); + unregister_netdevice_notifier(&hdlc_notifier); +} + + +module_init(hdlc_module_init); +module_exit(hdlc_module_exit); diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index f289daba0c7b..7ec2b2f9b7ee 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * Cisco HDLC support * - * Copyright (C) 2000 - 2003 Krzysztof Halasa + * Copyright (C) 2000 - 2006 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -34,17 +34,56 @@ #define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ +struct hdlc_header { + u8 address; + u8 control; + u16 protocol; +}__attribute__ ((packed)); + + +struct cisco_packet { + u32 type; /* code */ + u32 par1; + u32 par2; + u16 rel; /* reliability */ + u32 time; +}__attribute__ ((packed)); +#define CISCO_PACKET_LEN 18 +#define CISCO_BIG_PACKET_LEN 20 + + +struct cisco_state { + cisco_proto settings; + + struct timer_list timer; + unsigned long last_poll; + int up; + int request_sent; + u32 txseq; /* TX sequence number */ + u32 rxseq; /* RX sequence number */ +}; + + +static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr); + + +static inline struct cisco_state * state(hdlc_device *hdlc) +{ + return(struct cisco_state *)(hdlc->state); +} + + static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, u16 type, void *daddr, void *saddr, unsigned int len) { - hdlc_header *data; + struct hdlc_header *data; #ifdef DEBUG_HARD_HEADER printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); #endif - skb_push(skb, sizeof(hdlc_header)); - data = (hdlc_header*)skb->data; + skb_push(skb, sizeof(struct hdlc_header)); + data = (struct hdlc_header*)skb->data; if (type == CISCO_KEEPALIVE) data->address = CISCO_MULTICAST; else @@ -52,7 +91,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, data->control = 0; data->protocol = htons(type); - return sizeof(hdlc_header); + return sizeof(struct hdlc_header); } @@ -61,9 +100,10 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, u32 par1, u32 par2) { struct sk_buff *skb; - cisco_packet *data; + struct cisco_packet *data; - skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet)); + skb = dev_alloc_skb(sizeof(struct hdlc_header) + + sizeof(struct cisco_packet)); if (!skb) { printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n", @@ -72,7 +112,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, } skb_reserve(skb, 4); cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); - data = (cisco_packet*)(skb->data + 4); + data = (struct cisco_packet*)(skb->data + 4); data->type = htonl(type); data->par1 = htonl(par1); @@ -81,7 +121,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, /* we will need do_div here if 1000 % HZ != 0 */ data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ)); - skb_put(skb, sizeof(cisco_packet)); + skb_put(skb, sizeof(struct cisco_packet)); skb->priority = TC_PRIO_CONTROL; skb->dev = dev; skb->nh.raw = skb->data; @@ -93,9 +133,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev) { - hdlc_header *data = (hdlc_header*)skb->data; + struct hdlc_header *data = (struct hdlc_header*)skb->data; - if (skb->len < sizeof(hdlc_header)) + if (skb->len < sizeof(struct hdlc_header)) return __constant_htons(ETH_P_HDLC); if (data->address != CISCO_MULTICAST && @@ -106,7 +146,7 @@ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev) case __constant_htons(ETH_P_IP): case __constant_htons(ETH_P_IPX): case __constant_htons(ETH_P_IPV6): - skb_pull(skb, sizeof(hdlc_header)); + skb_pull(skb, sizeof(struct hdlc_header)); return data->protocol; default: return __constant_htons(ETH_P_HDLC); @@ -118,12 +158,12 @@ static int cisco_rx(struct sk_buff *skb) { struct net_device *dev = skb->dev; hdlc_device *hdlc = dev_to_hdlc(dev); - hdlc_header *data = (hdlc_header*)skb->data; - cisco_packet *cisco_data; + struct hdlc_header *data = (struct hdlc_header*)skb->data; + struct cisco_packet *cisco_data; struct in_device *in_dev; u32 addr, mask; - if (skb->len < sizeof(hdlc_header)) + if (skb->len < sizeof(struct hdlc_header)) goto rx_error; if (data->address != CISCO_MULTICAST && @@ -137,15 +177,17 @@ static int cisco_rx(struct sk_buff *skb) return NET_RX_SUCCESS; case CISCO_KEEPALIVE: - if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN && - skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) { - printk(KERN_INFO "%s: Invalid length of Cisco " - "control packet (%d bytes)\n", - dev->name, skb->len); + if ((skb->len != sizeof(struct hdlc_header) + + CISCO_PACKET_LEN) && + (skb->len != sizeof(struct hdlc_header) + + CISCO_BIG_PACKET_LEN)) { + printk(KERN_INFO "%s: Invalid length of Cisco control" + " packet (%d bytes)\n", dev->name, skb->len); goto rx_error; } - cisco_data = (cisco_packet*)(skb->data + sizeof(hdlc_header)); + cisco_data = (struct cisco_packet*)(skb->data + sizeof + (struct hdlc_header)); switch(ntohl (cisco_data->type)) { case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ @@ -178,11 +220,11 @@ static int cisco_rx(struct sk_buff *skb) goto rx_error; case CISCO_KEEPALIVE_REQ: - hdlc->state.cisco.rxseq = ntohl(cisco_data->par1); - if (hdlc->state.cisco.request_sent && - ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) { - hdlc->state.cisco.last_poll = jiffies; - if (!hdlc->state.cisco.up) { + state(hdlc)->rxseq = ntohl(cisco_data->par1); + if (state(hdlc)->request_sent && + ntohl(cisco_data->par2) == state(hdlc)->txseq) { + state(hdlc)->last_poll = jiffies; + if (!state(hdlc)->up) { u32 sec, min, hrs, days; sec = ntohl(cisco_data->time) / 1000; min = sec / 60; sec -= min * 60; @@ -193,7 +235,7 @@ static int cisco_rx(struct sk_buff *skb) dev->name, days, hrs, min, sec); netif_dormant_off(dev); - hdlc->state.cisco.up = 1; + state(hdlc)->up = 1; } } @@ -208,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb) return NET_RX_DROP; rx_error: - hdlc->stats.rx_errors++; /* Mark error */ + dev_to_desc(dev)->stats.rx_errors++; /* Mark error */ dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -220,23 +262,22 @@ static void cisco_timer(unsigned long arg) struct net_device *dev = (struct net_device *)arg; hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->state.cisco.up && - time_after(jiffies, hdlc->state.cisco.last_poll + - hdlc->state.cisco.settings.timeout * HZ)) { - hdlc->state.cisco.up = 0; + if (state(hdlc)->up && + time_after(jiffies, state(hdlc)->last_poll + + state(hdlc)->settings.timeout * HZ)) { + state(hdlc)->up = 0; printk(KERN_INFO "%s: Link down\n", dev->name); netif_dormant_on(dev); } - cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, - ++hdlc->state.cisco.txseq, - hdlc->state.cisco.rxseq); - hdlc->state.cisco.request_sent = 1; - hdlc->state.cisco.timer.expires = jiffies + - hdlc->state.cisco.settings.interval * HZ; - hdlc->state.cisco.timer.function = cisco_timer; - hdlc->state.cisco.timer.data = arg; - add_timer(&hdlc->state.cisco.timer); + cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq, + state(hdlc)->rxseq); + state(hdlc)->request_sent = 1; + state(hdlc)->timer.expires = jiffies + + state(hdlc)->settings.interval * HZ; + state(hdlc)->timer.function = cisco_timer; + state(hdlc)->timer.data = arg; + add_timer(&state(hdlc)->timer); } @@ -244,15 +285,15 @@ static void cisco_timer(unsigned long arg) static void cisco_start(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - hdlc->state.cisco.up = 0; - hdlc->state.cisco.request_sent = 0; - hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0; - - init_timer(&hdlc->state.cisco.timer); - hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/ - hdlc->state.cisco.timer.function = cisco_timer; - hdlc->state.cisco.timer.data = (unsigned long)dev; - add_timer(&hdlc->state.cisco.timer); + state(hdlc)->up = 0; + state(hdlc)->request_sent = 0; + state(hdlc)->txseq = state(hdlc)->rxseq = 0; + + init_timer(&state(hdlc)->timer); + state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/ + state(hdlc)->timer.function = cisco_timer; + state(hdlc)->timer.data = (unsigned long)dev; + add_timer(&state(hdlc)->timer); } @@ -260,15 +301,24 @@ static void cisco_start(struct net_device *dev) static void cisco_stop(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - del_timer_sync(&hdlc->state.cisco.timer); + del_timer_sync(&state(hdlc)->timer); netif_dormant_on(dev); - hdlc->state.cisco.up = 0; - hdlc->state.cisco.request_sent = 0; + state(hdlc)->up = 0; + state(hdlc)->request_sent = 0; } -int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) +static struct hdlc_proto proto = { + .start = cisco_start, + .stop = cisco_stop, + .type_trans = cisco_type_trans, + .ioctl = cisco_ioctl, + .module = THIS_MODULE, +}; + + +static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) { cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco; const size_t size = sizeof(cisco_proto); @@ -278,12 +328,14 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_CISCO; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } - if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size)) + if (copy_to_user(cisco_s, &state(hdlc)->settings, size)) return -EFAULT; return 0; @@ -302,19 +354,15 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); - if (result) return result; - hdlc_proto_detach(hdlc); - memcpy(&hdlc->state.cisco.settings, &new_settings, size); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); + result = attach_hdlc_protocol(dev, &proto, cisco_rx, + sizeof(struct cisco_state)); + if (result) + return result; - hdlc->proto.start = cisco_start; - hdlc->proto.stop = cisco_stop; - hdlc->proto.netif_rx = cisco_rx; - hdlc->proto.type_trans = cisco_type_trans; - hdlc->proto.id = IF_PROTO_CISCO; + memcpy(&state(hdlc)->settings, &new_settings, size); dev->hard_start_xmit = hdlc->xmit; dev->hard_header = cisco_hard_header; dev->hard_header_cache = NULL; @@ -327,3 +375,25 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("Cisco HDLC protocol support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 7bb737bbdeb9..b45ab680d2d6 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * Frame Relay support * - * Copyright (C) 1999 - 2005 Krzysztof Halasa + * Copyright (C) 1999 - 2006 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -52,6 +52,8 @@ #undef DEBUG_PKT #undef DEBUG_ECN #undef DEBUG_LINK +#undef DEBUG_PROTO +#undef DEBUG_PVC #define FR_UI 0x03 #define FR_PAD 0x00 @@ -115,13 +117,53 @@ typedef struct { }__attribute__ ((packed)) fr_hdr; +typedef struct pvc_device_struct { + struct net_device *frad; + struct net_device *main; + struct net_device *ether; /* bridged Ethernet interface */ + struct pvc_device_struct *next; /* Sorted in ascending DLCI order */ + int dlci; + int open_count; + + struct { + unsigned int new: 1; + unsigned int active: 1; + unsigned int exist: 1; + unsigned int deleted: 1; + unsigned int fecn: 1; + unsigned int becn: 1; + unsigned int bandwidth; /* Cisco LMI reporting only */ + }state; +}pvc_device; + + +struct frad_state { + fr_proto settings; + pvc_device *first_pvc; + int dce_pvc_count; + + struct timer_list timer; + unsigned long last_poll; + int reliable; + int dce_changed; + int request; + int fullrep_sent; + u32 last_errors; /* last errors bit list */ + u8 n391cnt; + u8 txseq; /* TX sequence number */ + u8 rxseq; /* RX sequence number */ +}; + + +static int fr_ioctl(struct net_device *dev, struct ifreq *ifr); + + static inline u16 q922_to_dlci(u8 *hdr) { return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4); } - static inline void dlci_to_q922(u8 *hdr, u16 dlci) { hdr[0] = (dlci >> 2) & 0xFC; @@ -129,10 +171,21 @@ static inline void dlci_to_q922(u8 *hdr, u16 dlci) } +static inline struct frad_state * state(hdlc_device *hdlc) +{ + return(struct frad_state *)(hdlc->state); +} + + +static __inline__ pvc_device* dev_to_pvc(struct net_device *dev) +{ + return dev->priv; +} + static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) { - pvc_device *pvc = hdlc->state.fr.first_pvc; + pvc_device *pvc = state(hdlc)->first_pvc; while (pvc) { if (pvc->dlci == dlci) @@ -146,10 +199,10 @@ static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) } -static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci) +static pvc_device* add_pvc(struct net_device *dev, u16 dlci) { hdlc_device *hdlc = dev_to_hdlc(dev); - pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc; + pvc_device *pvc, **pvc_p = &state(hdlc)->first_pvc; while (*pvc_p) { if ((*pvc_p)->dlci == dlci) @@ -160,12 +213,15 @@ static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci) } pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC); +#ifdef DEBUG_PVC + printk(KERN_DEBUG "add_pvc: allocated pvc %p, frad %p\n", pvc, dev); +#endif if (!pvc) return NULL; memset(pvc, 0, sizeof(pvc_device)); pvc->dlci = dlci; - pvc->master = dev; + pvc->frad = dev; pvc->next = *pvc_p; /* Put it in the chain */ *pvc_p = pvc; return pvc; @@ -174,7 +230,7 @@ static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci) static inline int pvc_is_used(pvc_device *pvc) { - return pvc->main != NULL || pvc->ether != NULL; + return pvc->main || pvc->ether; } @@ -200,11 +256,14 @@ static inline void pvc_carrier(int on, pvc_device *pvc) static inline void delete_unused_pvcs(hdlc_device *hdlc) { - pvc_device **pvc_p = &hdlc->state.fr.first_pvc; + pvc_device **pvc_p = &state(hdlc)->first_pvc; while (*pvc_p) { if (!pvc_is_used(*pvc_p)) { pvc_device *pvc = *pvc_p; +#ifdef DEBUG_PVC + printk(KERN_DEBUG "freeing unused pvc: %p\n", pvc); +#endif *pvc_p = pvc->next; kfree(pvc); continue; @@ -295,16 +354,16 @@ static int pvc_open(struct net_device *dev) { pvc_device *pvc = dev_to_pvc(dev); - if ((pvc->master->flags & IFF_UP) == 0) - return -EIO; /* Master must be UP in order to activate PVC */ + if ((pvc->frad->flags & IFF_UP) == 0) + return -EIO; /* Frad must be UP in order to activate PVC */ if (pvc->open_count++ == 0) { - hdlc_device *hdlc = dev_to_hdlc(pvc->master); - if (hdlc->state.fr.settings.lmi == LMI_NONE) - pvc->state.active = netif_carrier_ok(pvc->master); + hdlc_device *hdlc = dev_to_hdlc(pvc->frad); + if (state(hdlc)->settings.lmi == LMI_NONE) + pvc->state.active = netif_carrier_ok(pvc->frad); pvc_carrier(pvc->state.active, pvc); - hdlc->state.fr.dce_changed = 1; + state(hdlc)->dce_changed = 1; } return 0; } @@ -316,12 +375,12 @@ static int pvc_close(struct net_device *dev) pvc_device *pvc = dev_to_pvc(dev); if (--pvc->open_count == 0) { - hdlc_device *hdlc = dev_to_hdlc(pvc->master); - if (hdlc->state.fr.settings.lmi == LMI_NONE) + hdlc_device *hdlc = dev_to_hdlc(pvc->frad); + if (state(hdlc)->settings.lmi == LMI_NONE) pvc->state.active = 0; - if (hdlc->state.fr.settings.dce) { - hdlc->state.fr.dce_changed = 1; + if (state(hdlc)->settings.dce) { + state(hdlc)->dce_changed = 1; pvc->state.active = 0; } } @@ -348,7 +407,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } info.dlci = pvc->dlci; - memcpy(info.master, pvc->master->name, IFNAMSIZ); + memcpy(info.master, pvc->frad->name, IFNAMSIZ); if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info, &info, sizeof(info))) return -EFAULT; @@ -361,7 +420,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static inline struct net_device_stats *pvc_get_stats(struct net_device *dev) { - return netdev_priv(dev); + return &dev_to_desc(dev)->stats; } @@ -393,7 +452,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_packets++; if (pvc->state.fecn) /* TX Congestion counter */ stats->tx_compressed++; - skb->dev = pvc->master; + skb->dev = pvc->frad; dev_queue_xmit(skb); return 0; } @@ -419,7 +478,7 @@ static int pvc_change_mtu(struct net_device *dev, int new_mtu) static inline void fr_log_dlci_active(pvc_device *pvc) { printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n", - pvc->master->name, + pvc->frad->name, pvc->dlci, pvc->main ? pvc->main->name : "", pvc->main && pvc->ether ? " " : "", @@ -438,21 +497,20 @@ static inline u8 fr_lmi_nextseq(u8 x) } - static void fr_lmi_send(struct net_device *dev, int fullrep) { hdlc_device *hdlc = dev_to_hdlc(dev); struct sk_buff *skb; - pvc_device *pvc = hdlc->state.fr.first_pvc; - int lmi = hdlc->state.fr.settings.lmi; - int dce = hdlc->state.fr.settings.dce; + pvc_device *pvc = state(hdlc)->first_pvc; + int lmi = state(hdlc)->settings.lmi; + int dce = state(hdlc)->settings.dce; int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH; int stat_len = (lmi == LMI_CISCO) ? 6 : 3; u8 *data; int i = 0; if (dce && fullrep) { - len += hdlc->state.fr.dce_pvc_count * (2 + stat_len); + len += state(hdlc)->dce_pvc_count * (2 + stat_len); if (len > HDLC_MAX_MRU) { printk(KERN_WARNING "%s: Too many PVCs while sending " "LMI full report\n", dev->name); @@ -486,8 +544,9 @@ static void fr_lmi_send(struct net_device *dev, int fullrep) data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE; data[i++] = LMI_INTEG_LEN; - data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq); - data[i++] = hdlc->state.fr.rxseq; + data[i++] = state(hdlc)->txseq = + fr_lmi_nextseq(state(hdlc)->txseq); + data[i++] = state(hdlc)->rxseq; if (dce && fullrep) { while (pvc) { @@ -496,7 +555,7 @@ static void fr_lmi_send(struct net_device *dev, int fullrep) data[i++] = stat_len; /* LMI start/restart */ - if (hdlc->state.fr.reliable && !pvc->state.exist) { + if (state(hdlc)->reliable && !pvc->state.exist) { pvc->state.exist = pvc->state.new = 1; fr_log_dlci_active(pvc); } @@ -541,15 +600,15 @@ static void fr_lmi_send(struct net_device *dev, int fullrep) static void fr_set_link_state(int reliable, struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - pvc_device *pvc = hdlc->state.fr.first_pvc; + pvc_device *pvc = state(hdlc)->first_pvc; - hdlc->state.fr.reliable = reliable; + state(hdlc)->reliable = reliable; if (reliable) { netif_dormant_off(dev); - hdlc->state.fr.n391cnt = 0; /* Request full status */ - hdlc->state.fr.dce_changed = 1; + state(hdlc)->n391cnt = 0; /* Request full status */ + state(hdlc)->dce_changed = 1; - if (hdlc->state.fr.settings.lmi == LMI_NONE) { + if (state(hdlc)->settings.lmi == LMI_NONE) { while (pvc) { /* Activate all PVCs */ pvc_carrier(1, pvc); pvc->state.exist = pvc->state.active = 1; @@ -563,7 +622,7 @@ static void fr_set_link_state(int reliable, struct net_device *dev) pvc_carrier(0, pvc); pvc->state.exist = pvc->state.active = 0; pvc->state.new = 0; - if (!hdlc->state.fr.settings.dce) + if (!state(hdlc)->settings.dce) pvc->state.bandwidth = 0; pvc = pvc->next; } @@ -571,7 +630,6 @@ static void fr_set_link_state(int reliable, struct net_device *dev) } - static void fr_timer(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; @@ -579,62 +637,61 @@ static void fr_timer(unsigned long arg) int i, cnt = 0, reliable; u32 list; - if (hdlc->state.fr.settings.dce) { - reliable = hdlc->state.fr.request && - time_before(jiffies, hdlc->state.fr.last_poll + - hdlc->state.fr.settings.t392 * HZ); - hdlc->state.fr.request = 0; + if (state(hdlc)->settings.dce) { + reliable = state(hdlc)->request && + time_before(jiffies, state(hdlc)->last_poll + + state(hdlc)->settings.t392 * HZ); + state(hdlc)->request = 0; } else { - hdlc->state.fr.last_errors <<= 1; /* Shift the list */ - if (hdlc->state.fr.request) { - if (hdlc->state.fr.reliable) + state(hdlc)->last_errors <<= 1; /* Shift the list */ + if (state(hdlc)->request) { + if (state(hdlc)->reliable) printk(KERN_INFO "%s: No LMI status reply " "received\n", dev->name); - hdlc->state.fr.last_errors |= 1; + state(hdlc)->last_errors |= 1; } - list = hdlc->state.fr.last_errors; - for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1) + list = state(hdlc)->last_errors; + for (i = 0; i < state(hdlc)->settings.n393; i++, list >>= 1) cnt += (list & 1); /* errors count */ - reliable = (cnt < hdlc->state.fr.settings.n392); + reliable = (cnt < state(hdlc)->settings.n392); } - if (hdlc->state.fr.reliable != reliable) { + if (state(hdlc)->reliable != reliable) { printk(KERN_INFO "%s: Link %sreliable\n", dev->name, reliable ? "" : "un"); fr_set_link_state(reliable, dev); } - if (hdlc->state.fr.settings.dce) - hdlc->state.fr.timer.expires = jiffies + - hdlc->state.fr.settings.t392 * HZ; + if (state(hdlc)->settings.dce) + state(hdlc)->timer.expires = jiffies + + state(hdlc)->settings.t392 * HZ; else { - if (hdlc->state.fr.n391cnt) - hdlc->state.fr.n391cnt--; + if (state(hdlc)->n391cnt) + state(hdlc)->n391cnt--; - fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0); + fr_lmi_send(dev, state(hdlc)->n391cnt == 0); - hdlc->state.fr.last_poll = jiffies; - hdlc->state.fr.request = 1; - hdlc->state.fr.timer.expires = jiffies + - hdlc->state.fr.settings.t391 * HZ; + state(hdlc)->last_poll = jiffies; + state(hdlc)->request = 1; + state(hdlc)->timer.expires = jiffies + + state(hdlc)->settings.t391 * HZ; } - hdlc->state.fr.timer.function = fr_timer; - hdlc->state.fr.timer.data = arg; - add_timer(&hdlc->state.fr.timer); + state(hdlc)->timer.function = fr_timer; + state(hdlc)->timer.data = arg; + add_timer(&state(hdlc)->timer); } - static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) { hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc; u8 rxseq, txseq; - int lmi = hdlc->state.fr.settings.lmi; - int dce = hdlc->state.fr.settings.dce; + int lmi = state(hdlc)->settings.lmi; + int dce = state(hdlc)->settings.dce; int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i; if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH : @@ -645,8 +702,8 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI : NLPID_CCITT_ANSI_LMI)) { - printk(KERN_INFO "%s: Received non-LMI frame with LMI" - " DLCI\n", dev->name); + printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n", + dev->name); return 1; } @@ -706,53 +763,53 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) } i++; - hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */ + state(hdlc)->rxseq = skb->data[i++]; /* TX sequence from peer */ rxseq = skb->data[i++]; /* Should confirm our sequence */ - txseq = hdlc->state.fr.txseq; + txseq = state(hdlc)->txseq; if (dce) - hdlc->state.fr.last_poll = jiffies; + state(hdlc)->last_poll = jiffies; error = 0; - if (!hdlc->state.fr.reliable) + if (!state(hdlc)->reliable) error = 1; - if (rxseq == 0 || rxseq != txseq) { - hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */ + if (rxseq == 0 || rxseq != txseq) { /* Ask for full report next time */ + state(hdlc)->n391cnt = 0; error = 1; } if (dce) { - if (hdlc->state.fr.fullrep_sent && !error) { + if (state(hdlc)->fullrep_sent && !error) { /* Stop sending full report - the last one has been confirmed by DTE */ - hdlc->state.fr.fullrep_sent = 0; - pvc = hdlc->state.fr.first_pvc; + state(hdlc)->fullrep_sent = 0; + pvc = state(hdlc)->first_pvc; while (pvc) { if (pvc->state.new) { pvc->state.new = 0; /* Tell DTE that new PVC is now active */ - hdlc->state.fr.dce_changed = 1; + state(hdlc)->dce_changed = 1; } pvc = pvc->next; } } - if (hdlc->state.fr.dce_changed) { + if (state(hdlc)->dce_changed) { reptype = LMI_FULLREP; - hdlc->state.fr.fullrep_sent = 1; - hdlc->state.fr.dce_changed = 0; + state(hdlc)->fullrep_sent = 1; + state(hdlc)->dce_changed = 0; } - hdlc->state.fr.request = 1; /* got request */ + state(hdlc)->request = 1; /* got request */ fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0); return 0; } /* DTE */ - hdlc->state.fr.request = 0; /* got response, no request pending */ + state(hdlc)->request = 0; /* got response, no request pending */ if (error) return 0; @@ -760,7 +817,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) if (reptype != LMI_FULLREP) return 0; - pvc = hdlc->state.fr.first_pvc; + pvc = state(hdlc)->first_pvc; while (pvc) { pvc->state.deleted = 1; @@ -827,7 +884,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) i += stat_len; } - pvc = hdlc->state.fr.first_pvc; + pvc = state(hdlc)->first_pvc; while (pvc) { if (pvc->state.deleted && pvc->state.exist) { @@ -841,17 +898,16 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) } /* Next full report after N391 polls */ - hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391; + state(hdlc)->n391cnt = state(hdlc)->settings.n391; return 0; } - static int fr_rx(struct sk_buff *skb) { - struct net_device *ndev = skb->dev; - hdlc_device *hdlc = dev_to_hdlc(ndev); + struct net_device *frad = skb->dev; + hdlc_device *hdlc = dev_to_hdlc(frad); fr_hdr *fh = (fr_hdr*)skb->data; u8 *data = skb->data; u16 dlci; @@ -864,11 +920,11 @@ static int fr_rx(struct sk_buff *skb) dlci = q922_to_dlci(skb->data); if ((dlci == LMI_CCITT_ANSI_DLCI && - (hdlc->state.fr.settings.lmi == LMI_ANSI || - hdlc->state.fr.settings.lmi == LMI_CCITT)) || + (state(hdlc)->settings.lmi == LMI_ANSI || + state(hdlc)->settings.lmi == LMI_CCITT)) || (dlci == LMI_CISCO_DLCI && - hdlc->state.fr.settings.lmi == LMI_CISCO)) { - if (fr_lmi_recv(ndev, skb)) + state(hdlc)->settings.lmi == LMI_CISCO)) { + if (fr_lmi_recv(frad, skb)) goto rx_error; dev_kfree_skb_any(skb); return NET_RX_SUCCESS; @@ -878,7 +934,7 @@ static int fr_rx(struct sk_buff *skb) if (!pvc) { #ifdef DEBUG_PKT printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", - ndev->name, dlci); + frad->name, dlci); #endif dev_kfree_skb_any(skb); return NET_RX_DROP; @@ -886,7 +942,7 @@ static int fr_rx(struct sk_buff *skb) if (pvc->state.fecn != fh->fecn) { #ifdef DEBUG_ECN - printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", ndev->name, + printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", frad->name, dlci, fh->fecn ? "N" : "FF"); #endif pvc->state.fecn ^= 1; @@ -894,7 +950,7 @@ static int fr_rx(struct sk_buff *skb) if (pvc->state.becn != fh->becn) { #ifdef DEBUG_ECN - printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", ndev->name, + printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", frad->name, dlci, fh->becn ? "N" : "FF"); #endif pvc->state.becn ^= 1; @@ -902,7 +958,7 @@ static int fr_rx(struct sk_buff *skb) if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - hdlc->stats.rx_dropped++; + dev_to_desc(frad)->stats.rx_dropped++; return NET_RX_DROP; } @@ -938,13 +994,13 @@ static int fr_rx(struct sk_buff *skb) default: printk(KERN_INFO "%s: Unsupported protocol, OUI=%x " - "PID=%x\n", ndev->name, oui, pid); + "PID=%x\n", frad->name, oui, pid); dev_kfree_skb_any(skb); return NET_RX_DROP; } } else { printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x " - "length = %i\n", ndev->name, data[3], skb->len); + "length = %i\n", frad->name, data[3], skb->len); dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -964,7 +1020,7 @@ static int fr_rx(struct sk_buff *skb) } rx_error: - hdlc->stats.rx_errors++; /* Mark error */ + dev_to_desc(frad)->stats.rx_errors++; /* Mark error */ dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -977,44 +1033,42 @@ static void fr_start(struct net_device *dev) #ifdef DEBUG_LINK printk(KERN_DEBUG "fr_start\n"); #endif - if (hdlc->state.fr.settings.lmi != LMI_NONE) { - hdlc->state.fr.reliable = 0; - hdlc->state.fr.dce_changed = 1; - hdlc->state.fr.request = 0; - hdlc->state.fr.fullrep_sent = 0; - hdlc->state.fr.last_errors = 0xFFFFFFFF; - hdlc->state.fr.n391cnt = 0; - hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0; - - init_timer(&hdlc->state.fr.timer); + if (state(hdlc)->settings.lmi != LMI_NONE) { + state(hdlc)->reliable = 0; + state(hdlc)->dce_changed = 1; + state(hdlc)->request = 0; + state(hdlc)->fullrep_sent = 0; + state(hdlc)->last_errors = 0xFFFFFFFF; + state(hdlc)->n391cnt = 0; + state(hdlc)->txseq = state(hdlc)->rxseq = 0; + + init_timer(&state(hdlc)->timer); /* First poll after 1 s */ - hdlc->state.fr.timer.expires = jiffies + HZ; - hdlc->state.fr.timer.function = fr_timer; - hdlc->state.fr.timer.data = (unsigned long)dev; - add_timer(&hdlc->state.fr.timer); + state(hdlc)->timer.expires = jiffies + HZ; + state(hdlc)->timer.function = fr_timer; + state(hdlc)->timer.data = (unsigned long)dev; + add_timer(&state(hdlc)->timer); } else fr_set_link_state(1, dev); } - static void fr_stop(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK printk(KERN_DEBUG "fr_stop\n"); #endif - if (hdlc->state.fr.settings.lmi != LMI_NONE) - del_timer_sync(&hdlc->state.fr.timer); + if (state(hdlc)->settings.lmi != LMI_NONE) + del_timer_sync(&state(hdlc)->timer); fr_set_link_state(0, dev); } - static void fr_close(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - pvc_device *pvc = hdlc->state.fr.first_pvc; + pvc_device *pvc = state(hdlc)->first_pvc; while (pvc) { /* Shutdown all PVCs for this FRAD */ if (pvc->main) @@ -1025,7 +1079,8 @@ static void fr_close(struct net_device *dev) } } -static void dlci_setup(struct net_device *dev) + +static void pvc_setup(struct net_device *dev) { dev->type = ARPHRD_DLCI; dev->flags = IFF_POINTOPOINT; @@ -1033,9 +1088,9 @@ static void dlci_setup(struct net_device *dev) dev->addr_len = 2; } -static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type) +static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) { - hdlc_device *hdlc = dev_to_hdlc(master); + hdlc_device *hdlc = dev_to_hdlc(frad); pvc_device *pvc = NULL; struct net_device *dev; int result, used; @@ -1044,9 +1099,9 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type) if (type == ARPHRD_ETHER) prefix = "pvceth%d"; - if ((pvc = add_pvc(master, dlci)) == NULL) { + if ((pvc = add_pvc(frad, dlci)) == NULL) { printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n", - master->name); + frad->name); return -ENOBUFS; } @@ -1060,11 +1115,11 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type) "pvceth%d", ether_setup); else dev = alloc_netdev(sizeof(struct net_device_stats), - "pvc%d", dlci_setup); + "pvc%d", pvc_setup); if (!dev) { printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n", - master->name); + frad->name); delete_unused_pvcs(hdlc); return -ENOBUFS; } @@ -1102,8 +1157,8 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type) dev->destructor = free_netdev; *get_dev_p(pvc, type) = dev; if (!used) { - hdlc->state.fr.dce_changed = 1; - hdlc->state.fr.dce_pvc_count++; + state(hdlc)->dce_changed = 1; + state(hdlc)->dce_pvc_count++; } return 0; } @@ -1128,8 +1183,8 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) *get_dev_p(pvc, type) = NULL; if (!pvc_is_used(pvc)) { - hdlc->state.fr.dce_pvc_count--; - hdlc->state.fr.dce_changed = 1; + state(hdlc)->dce_pvc_count--; + state(hdlc)->dce_changed = 1; } delete_unused_pvcs(hdlc); return 0; @@ -1137,14 +1192,13 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) -static void fr_destroy(hdlc_device *hdlc) +static void fr_destroy(struct net_device *frad) { - pvc_device *pvc; - - pvc = hdlc->state.fr.first_pvc; - hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */ - hdlc->state.fr.dce_pvc_count = 0; - hdlc->state.fr.dce_changed = 1; + hdlc_device *hdlc = dev_to_hdlc(frad); + pvc_device *pvc = state(hdlc)->first_pvc; + state(hdlc)->first_pvc = NULL; /* All PVCs destroyed */ + state(hdlc)->dce_pvc_count = 0; + state(hdlc)->dce_changed = 1; while (pvc) { pvc_device *next = pvc->next; @@ -1161,8 +1215,17 @@ static void fr_destroy(hdlc_device *hdlc) } +static struct hdlc_proto proto = { + .close = fr_close, + .start = fr_start, + .stop = fr_stop, + .detach = fr_destroy, + .ioctl = fr_ioctl, + .module = THIS_MODULE, +}; + -int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) +static int fr_ioctl(struct net_device *dev, struct ifreq *ifr) { fr_proto __user *fr_s = ifr->ifr_settings.ifs_ifsu.fr; const size_t size = sizeof(fr_proto); @@ -1173,12 +1236,14 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */ + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_FR; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } - if (copy_to_user(fr_s, &hdlc->state.fr.settings, size)) + if (copy_to_user(fr_s, &state(hdlc)->settings, size)) return -EFAULT; return 0; @@ -1213,20 +1278,16 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - if (hdlc->proto.id != IF_PROTO_FR) { - hdlc_proto_detach(hdlc); - hdlc->state.fr.first_pvc = NULL; - hdlc->state.fr.dce_pvc_count = 0; + if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */ + result = attach_hdlc_protocol(dev, &proto, fr_rx, + sizeof(struct frad_state)); + if (result) + return result; + state(hdlc)->first_pvc = NULL; + state(hdlc)->dce_pvc_count = 0; } - memcpy(&hdlc->state.fr.settings, &new_settings, size); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - - hdlc->proto.close = fr_close; - hdlc->proto.start = fr_start; - hdlc->proto.stop = fr_stop; - hdlc->proto.detach = fr_destroy; - hdlc->proto.netif_rx = fr_rx; - hdlc->proto.id = IF_PROTO_FR; + memcpy(&state(hdlc)->settings, &new_settings, size); + dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_FRAD; @@ -1238,6 +1299,9 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) case IF_PROTO_FR_DEL_PVC: case IF_PROTO_FR_ADD_ETH_PVC: case IF_PROTO_FR_DEL_ETH_PVC: + if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */ + return -EINVAL; + if(!capable(CAP_NET_ADMIN)) return -EPERM; @@ -1263,3 +1327,24 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("Frame-Relay protocol support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c deleted file mode 100644 index 04ca1f7b6424..000000000000 --- a/drivers/net/wan/hdlc_generic.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Generic HDLC support routines for Linux - * - * Copyright (C) 1999 - 2005 Krzysztof Halasa - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * Currently supported: - * * raw IP-in-HDLC - * * Cisco HDLC - * * Frame Relay with ANSI or CCITT LMI (both user and network side) - * * PPP - * * X.25 - * - * Use sethdlc utility to set line parameters, protocol and PVCs - * - * How does it work: - * - proto.open(), close(), start(), stop() calls are serialized. - * The order is: open, [ start, stop ... ] close ... - * - proto.start() and stop() are called with spin_lock_irq held. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -static const char* version = "HDLC support module revision 1.19"; - -#undef DEBUG_LINK - - -static int hdlc_change_mtu(struct net_device *dev, int new_mtu) -{ - if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) - return -EINVAL; - dev->mtu = new_mtu; - return 0; -} - - - -static struct net_device_stats *hdlc_get_stats(struct net_device *dev) -{ - return hdlc_stats(dev); -} - - - -static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *p, struct net_device *orig_dev) -{ - hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->proto.netif_rx) - return hdlc->proto.netif_rx(skb); - - hdlc->stats.rx_dropped++; /* Shouldn't happen */ - dev_kfree_skb(skb); - return NET_RX_DROP; -} - - - -static inline void hdlc_proto_start(struct net_device *dev) -{ - hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->proto.start) - return hdlc->proto.start(dev); -} - - - -static inline void hdlc_proto_stop(struct net_device *dev) -{ - hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->proto.stop) - return hdlc->proto.stop(dev); -} - - - -static int hdlc_device_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct net_device *dev = ptr; - hdlc_device *hdlc; - unsigned long flags; - int on; - - if (dev->get_stats != hdlc_get_stats) - return NOTIFY_DONE; /* not an HDLC device */ - - if (event != NETDEV_CHANGE) - return NOTIFY_DONE; /* Only interrested in carrier changes */ - - on = netif_carrier_ok(dev); - -#ifdef DEBUG_LINK - printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n", - dev->name, on); -#endif - - hdlc = dev_to_hdlc(dev); - spin_lock_irqsave(&hdlc->state_lock, flags); - - if (hdlc->carrier == on) - goto carrier_exit; /* no change in DCD line level */ - - hdlc->carrier = on; - - if (!hdlc->open) - goto carrier_exit; - - if (hdlc->carrier) { - printk(KERN_INFO "%s: Carrier detected\n", dev->name); - hdlc_proto_start(dev); - } else { - printk(KERN_INFO "%s: Carrier lost\n", dev->name); - hdlc_proto_stop(dev); - } - -carrier_exit: - spin_unlock_irqrestore(&hdlc->state_lock, flags); - return NOTIFY_DONE; -} - - - -/* Must be called by hardware driver when HDLC device is being opened */ -int hdlc_open(struct net_device *dev) -{ - hdlc_device *hdlc = dev_to_hdlc(dev); -#ifdef DEBUG_LINK - printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n", - hdlc->carrier, hdlc->open); -#endif - - if (hdlc->proto.id == -1) - return -ENOSYS; /* no protocol attached */ - - if (hdlc->proto.open) { - int result = hdlc->proto.open(dev); - if (result) - return result; - } - - spin_lock_irq(&hdlc->state_lock); - - if (hdlc->carrier) { - printk(KERN_INFO "%s: Carrier detected\n", dev->name); - hdlc_proto_start(dev); - } else - printk(KERN_INFO "%s: No carrier\n", dev->name); - - hdlc->open = 1; - - spin_unlock_irq(&hdlc->state_lock); - return 0; -} - - - -/* Must be called by hardware driver when HDLC device is being closed */ -void hdlc_close(struct net_device *dev) -{ - hdlc_device *hdlc = dev_to_hdlc(dev); -#ifdef DEBUG_LINK - printk(KERN_DEBUG "hdlc_close() carrier %i open %i\n", - hdlc->carrier, hdlc->open); -#endif - - spin_lock_irq(&hdlc->state_lock); - - hdlc->open = 0; - if (hdlc->carrier) - hdlc_proto_stop(dev); - - spin_unlock_irq(&hdlc->state_lock); - - if (hdlc->proto.close) - hdlc->proto.close(dev); -} - - - -#ifndef CONFIG_HDLC_RAW -#define hdlc_raw_ioctl(dev, ifr) -ENOSYS -#endif - -#ifndef CONFIG_HDLC_RAW_ETH -#define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS -#endif - -#ifndef CONFIG_HDLC_PPP -#define hdlc_ppp_ioctl(dev, ifr) -ENOSYS -#endif - -#ifndef CONFIG_HDLC_CISCO -#define hdlc_cisco_ioctl(dev, ifr) -ENOSYS -#endif - -#ifndef CONFIG_HDLC_FR -#define hdlc_fr_ioctl(dev, ifr) -ENOSYS -#endif - -#ifndef CONFIG_HDLC_X25 -#define hdlc_x25_ioctl(dev, ifr) -ENOSYS -#endif - - -int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - hdlc_device *hdlc = dev_to_hdlc(dev); - unsigned int proto; - - if (cmd != SIOCWANDEV) - return -EINVAL; - - switch(ifr->ifr_settings.type) { - case IF_PROTO_HDLC: - case IF_PROTO_HDLC_ETH: - case IF_PROTO_PPP: - case IF_PROTO_CISCO: - case IF_PROTO_FR: - case IF_PROTO_X25: - proto = ifr->ifr_settings.type; - break; - - default: - proto = hdlc->proto.id; - } - - switch(proto) { - case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr); - case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr); - case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr); - case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr); - case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr); - case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr); - default: return -EINVAL; - } -} - -void hdlc_setup(struct net_device *dev) -{ - hdlc_device *hdlc = dev_to_hdlc(dev); - - dev->get_stats = hdlc_get_stats; - dev->change_mtu = hdlc_change_mtu; - dev->mtu = HDLC_MAX_MTU; - - dev->type = ARPHRD_RAWHDLC; - dev->hard_header_len = 16; - - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - - hdlc->proto.id = -1; - hdlc->proto.detach = NULL; - hdlc->carrier = 1; - hdlc->open = 0; - spin_lock_init(&hdlc->state_lock); -} - -struct net_device *alloc_hdlcdev(void *priv) -{ - struct net_device *dev; - dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup); - if (dev) - dev_to_hdlc(dev)->priv = priv; - return dev; -} - -void unregister_hdlc_device(struct net_device *dev) -{ - rtnl_lock(); - hdlc_proto_detach(dev_to_hdlc(dev)); - unregister_netdevice(dev); - rtnl_unlock(); -} - - - -MODULE_AUTHOR("Krzysztof Halasa "); -MODULE_DESCRIPTION("HDLC support module"); -MODULE_LICENSE("GPL v2"); - -EXPORT_SYMBOL(hdlc_open); -EXPORT_SYMBOL(hdlc_close); -EXPORT_SYMBOL(hdlc_ioctl); -EXPORT_SYMBOL(hdlc_setup); -EXPORT_SYMBOL(alloc_hdlcdev); -EXPORT_SYMBOL(unregister_hdlc_device); - -static struct packet_type hdlc_packet_type = { - .type = __constant_htons(ETH_P_HDLC), - .func = hdlc_rcv, -}; - - -static struct notifier_block hdlc_notifier = { - .notifier_call = hdlc_device_event, -}; - - -static int __init hdlc_module_init(void) -{ - int result; - - printk(KERN_INFO "%s\n", version); - if ((result = register_netdevice_notifier(&hdlc_notifier)) != 0) - return result; - dev_add_pack(&hdlc_packet_type); - return 0; -} - - - -static void __exit hdlc_module_exit(void) -{ - dev_remove_pack(&hdlc_packet_type); - unregister_netdevice_notifier(&hdlc_notifier); -} - - -module_init(hdlc_module_init); -module_exit(hdlc_module_exit); diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index fbaab5bf71eb..e9f717070fde 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * Point-to-point protocol support * - * Copyright (C) 1999 - 2003 Krzysztof Halasa + * Copyright (C) 1999 - 2006 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -22,6 +22,21 @@ #include #include #include +#include + +struct ppp_state { + struct ppp_device pppdev; + struct ppp_device *syncppp_ptr; + int (*old_change_mtu)(struct net_device *dev, int new_mtu); +}; + +static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr); + + +static inline struct ppp_state* state(hdlc_device *hdlc) +{ + return(struct ppp_state *)(hdlc->state); +} static int ppp_open(struct net_device *dev) @@ -30,16 +45,16 @@ static int ppp_open(struct net_device *dev) void *old_ioctl; int result; - dev->priv = &hdlc->state.ppp.syncppp_ptr; - hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev; - hdlc->state.ppp.pppdev.dev = dev; + dev->priv = &state(hdlc)->syncppp_ptr; + state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev; + state(hdlc)->pppdev.dev = dev; old_ioctl = dev->do_ioctl; - hdlc->state.ppp.old_change_mtu = dev->change_mtu; - sppp_attach(&hdlc->state.ppp.pppdev); + state(hdlc)->old_change_mtu = dev->change_mtu; + sppp_attach(&state(hdlc)->pppdev); /* sppp_attach nukes them. We don't need syncppp's ioctl */ dev->do_ioctl = old_ioctl; - hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO; + state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO; dev->type = ARPHRD_PPP; result = sppp_open(dev); if (result) { @@ -59,7 +74,7 @@ static void ppp_close(struct net_device *dev) sppp_close(dev); sppp_detach(dev); dev->rebuild_header = NULL; - dev->change_mtu = hdlc->state.ppp.old_change_mtu; + dev->change_mtu = state(hdlc)->old_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->hard_header_len = 16; } @@ -73,13 +88,24 @@ static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev) -int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) +static struct hdlc_proto proto = { + .open = ppp_open, + .close = ppp_close, + .type_trans = ppp_type_trans, + .ioctl = ppp_ioctl, + .module = THIS_MODULE, +}; + + +static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) { hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_PPP; return 0; /* return protocol only, no settable parameters */ @@ -96,13 +122,10 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - hdlc_proto_detach(hdlc); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - - hdlc->proto.open = ppp_open; - hdlc->proto.close = ppp_close; - hdlc->proto.type_trans = ppp_type_trans; - hdlc->proto.id = IF_PROTO_PPP; + result = attach_hdlc_protocol(dev, &proto, NULL, + sizeof(struct ppp_state)); + if (result) + return result; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_PPP; @@ -113,3 +136,25 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("PPP protocol support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c index f15aa6ba77f1..fe3cae5c6b9d 100644 --- a/drivers/net/wan/hdlc_raw.c +++ b/drivers/net/wan/hdlc_raw.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * HDLC support * - * Copyright (C) 1999 - 2003 Krzysztof Halasa + * Copyright (C) 1999 - 2006 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -24,6 +24,8 @@ #include +static int raw_ioctl(struct net_device *dev, struct ifreq *ifr); + static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev) { return __constant_htons(ETH_P_IP); @@ -31,7 +33,14 @@ static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev) -int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) +static struct hdlc_proto proto = { + .type_trans = raw_type_trans, + .ioctl = raw_ioctl, + .module = THIS_MODULE, +}; + + +static int raw_ioctl(struct net_device *dev, struct ifreq *ifr) { raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; const size_t size = sizeof(raw_hdlc_proto); @@ -41,12 +50,14 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_HDLC; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } - if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size)) + if (copy_to_user(raw_s, hdlc->state, size)) return -EFAULT; return 0; @@ -71,12 +82,11 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - hdlc_proto_detach(hdlc); - memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - - hdlc->proto.type_trans = raw_type_trans; - hdlc->proto.id = IF_PROTO_HDLC; + result = attach_hdlc_protocol(dev, &proto, NULL, + sizeof(raw_hdlc_proto)); + if (result) + return result; + memcpy(hdlc->state, &new_settings, size); dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_RAWHDLC; @@ -88,3 +98,25 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("Raw HDLC protocol support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index d1884987f94e..1a69a9aaa9b9 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * HDLC Ethernet emulation support * - * Copyright (C) 2002-2003 Krzysztof Halasa + * Copyright (C) 2002-2006 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -25,6 +25,7 @@ #include #include +static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr); static int eth_tx(struct sk_buff *skb, struct net_device *dev) { @@ -44,7 +45,14 @@ static int eth_tx(struct sk_buff *skb, struct net_device *dev) } -int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) +static struct hdlc_proto proto = { + .type_trans = eth_type_trans, + .ioctl = raw_eth_ioctl, + .module = THIS_MODULE, +}; + + +static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) { raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; const size_t size = sizeof(raw_hdlc_proto); @@ -56,12 +64,14 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_HDLC_ETH; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } - if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size)) + if (copy_to_user(raw_s, hdlc->state, size)) return -EFAULT; return 0; @@ -86,12 +96,11 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - hdlc_proto_detach(hdlc); - memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - - hdlc->proto.type_trans = eth_type_trans; - hdlc->proto.id = IF_PROTO_HDLC_ETH; + result = attach_hdlc_protocol(dev, &proto, NULL, + sizeof(raw_hdlc_proto)); + if (result) + return result; + memcpy(hdlc->state, &new_settings, size); dev->hard_start_xmit = eth_tx; old_ch_mtu = dev->change_mtu; old_qlen = dev->tx_queue_len; @@ -106,3 +115,25 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index a867fb411f89..e4bb9f8ad433 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * X.25 support * - * Copyright (C) 1999 - 2003 Krzysztof Halasa + * Copyright (C) 1999 - 2006 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -25,6 +25,8 @@ #include +static int x25_ioctl(struct net_device *dev, struct ifreq *ifr); + /* These functions are callbacks called by LAPB layer */ static void x25_connect_disconnect(struct net_device *dev, int reason, int code) @@ -162,30 +164,39 @@ static void x25_close(struct net_device *dev) static int x25_rx(struct sk_buff *skb) { - hdlc_device *hdlc = dev_to_hdlc(skb->dev); + struct hdlc_device_desc *desc = dev_to_desc(skb->dev); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - hdlc->stats.rx_dropped++; + desc->stats.rx_dropped++; return NET_RX_DROP; } if (lapb_data_received(skb->dev, skb) == LAPB_OK) return NET_RX_SUCCESS; - hdlc->stats.rx_errors++; + desc->stats.rx_errors++; dev_kfree_skb_any(skb); return NET_RX_DROP; } +static struct hdlc_proto proto = { + .open = x25_open, + .close = x25_close, + .ioctl = x25_ioctl, + .module = THIS_MODULE, +}; + -int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) +static int x25_ioctl(struct net_device *dev, struct ifreq *ifr) { hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: + if (dev_to_hdlc(dev)->proto != &proto) + return -EINVAL; ifr->ifr_settings.type = IF_PROTO_X25; return 0; /* return protocol only, no settable parameters */ @@ -200,14 +211,9 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - hdlc_proto_detach(hdlc); - memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - - hdlc->proto.open = x25_open; - hdlc->proto.close = x25_close; - hdlc->proto.netif_rx = x25_rx; - hdlc->proto.type_trans = NULL; - hdlc->proto.id = IF_PROTO_X25; + if ((result = attach_hdlc_protocol(dev, &proto, + x25_rx, 0)) != 0) + return result; dev->hard_start_xmit = x25_xmit; dev->hard_header = NULL; dev->type = ARPHRD_X25; @@ -218,3 +224,25 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) return -EINVAL; } + + +static int __init mod_init(void) +{ + register_hdlc_protocol(&proto); + return 0; +} + + + +static void __exit mod_exit(void) +{ + unregister_hdlc_protocol(&proto); +} + + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("X.25 protocol support for generic HDLC"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h index d5ebbb29aeae..d4b333938f73 100644 --- a/include/linux/hdlc.h +++ b/include/linux/hdlc.h @@ -11,95 +11,46 @@ #ifndef __HDLC_H #define __HDLC_H -#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */ - -#define CLOCK_DEFAULT 0 /* Default setting */ -#define CLOCK_EXT 1 /* External TX and RX clock - DTE */ -#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */ -#define CLOCK_TXINT 3 /* Internal TX and external RX clock */ -#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */ - - -#define ENCODING_DEFAULT 0 /* Default setting */ -#define ENCODING_NRZ 1 -#define ENCODING_NRZI 2 -#define ENCODING_FM_MARK 3 -#define ENCODING_FM_SPACE 4 -#define ENCODING_MANCHESTER 5 - - -#define PARITY_DEFAULT 0 /* Default setting */ -#define PARITY_NONE 1 /* No parity */ -#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */ -#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */ -#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */ -#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */ -#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */ -#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */ - -#define LMI_DEFAULT 0 /* Default setting */ -#define LMI_NONE 1 /* No LMI, all PVCs are static */ -#define LMI_ANSI 2 /* ANSI Annex D */ -#define LMI_CCITT 3 /* ITU-T Annex A */ -#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */ #define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ +#if 0 #define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */ +#else +#define HDLC_MAX_MRU 1600 /* as required for FR network */ +#endif #ifdef __KERNEL__ #include #include -#include #include -typedef struct { /* Used in Cisco and PPP mode */ - u8 address; - u8 control; - u16 protocol; -}__attribute__ ((packed)) hdlc_header; - - - -typedef struct { - u32 type; /* code */ - u32 par1; - u32 par2; - u16 rel; /* reliability */ - u32 time; -}__attribute__ ((packed)) cisco_packet; -#define CISCO_PACKET_LEN 18 -#define CISCO_BIG_PACKET_LEN 20 - - - -typedef struct pvc_device_struct { - struct net_device *master; - struct net_device *main; - struct net_device *ether; /* bridged Ethernet interface */ - struct pvc_device_struct *next; /* Sorted in ascending DLCI order */ - int dlci; - int open_count; - - struct { - unsigned int new: 1; - unsigned int active: 1; - unsigned int exist: 1; - unsigned int deleted: 1; - unsigned int fecn: 1; - unsigned int becn: 1; - unsigned int bandwidth; /* Cisco LMI reporting only */ - }state; -}pvc_device; - - - -typedef struct hdlc_device_struct { - /* To be initialized by hardware driver */ +/* Used by all network devices here, pointed to by netdev_priv(dev) */ +struct hdlc_device_desc { + int (*netif_rx)(struct sk_buff *skb); struct net_device_stats stats; - +}; + +/* This structure is a private property of HDLC protocols. + Hardware drivers have no interest here */ + +struct hdlc_proto { + int (*open)(struct net_device *dev); + void (*close)(struct net_device *dev); + void (*start)(struct net_device *dev); /* if open & DCD */ + void (*stop)(struct net_device *dev); /* if open & !DCD */ + void (*detach)(struct net_device *dev); + int (*ioctl)(struct net_device *dev, struct ifreq *ifr); + unsigned short (*type_trans)(struct sk_buff *skb, + struct net_device *dev); + struct module *module; + struct hdlc_proto *next; /* next protocol in the list */ +}; + + +typedef struct hdlc_device { /* used by HDLC layer to take control over HDLC device from hw driver*/ int (*attach)(struct net_device *dev, unsigned short encoding, unsigned short parity); @@ -107,82 +58,18 @@ typedef struct hdlc_device_struct { /* hardware driver must handle this instead of dev->hard_start_xmit */ int (*xmit)(struct sk_buff *skb, struct net_device *dev); - /* Things below are for HDLC layer internal use only */ - struct { - int (*open)(struct net_device *dev); - void (*close)(struct net_device *dev); - - /* if open & DCD */ - void (*start)(struct net_device *dev); - /* if open & !DCD */ - void (*stop)(struct net_device *dev); - - void (*detach)(struct hdlc_device_struct *hdlc); - int (*netif_rx)(struct sk_buff *skb); - unsigned short (*type_trans)(struct sk_buff *skb, - struct net_device *dev); - int id; /* IF_PROTO_HDLC/CISCO/FR/etc. */ - }proto; - + const struct hdlc_proto *proto; int carrier; int open; spinlock_t state_lock; - - union { - struct { - fr_proto settings; - pvc_device *first_pvc; - int dce_pvc_count; - - struct timer_list timer; - unsigned long last_poll; - int reliable; - int dce_changed; - int request; - int fullrep_sent; - u32 last_errors; /* last errors bit list */ - u8 n391cnt; - u8 txseq; /* TX sequence number */ - u8 rxseq; /* RX sequence number */ - }fr; - - struct { - cisco_proto settings; - - struct timer_list timer; - unsigned long last_poll; - int up; - int request_sent; - u32 txseq; /* TX sequence number */ - u32 rxseq; /* RX sequence number */ - }cisco; - - struct { - raw_hdlc_proto settings; - }raw_hdlc; - - struct { - struct ppp_device pppdev; - struct ppp_device *syncppp_ptr; - int (*old_change_mtu)(struct net_device *dev, - int new_mtu); - }ppp; - }state; + void *state; void *priv; }hdlc_device; -int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr); -int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr); -int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr); -int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr); -int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr); -int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr); - - -/* Exported from hdlc.o */ +/* Exported from hdlc module */ /* Called by hardware driver when a user requests HDLC service */ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); @@ -191,17 +78,21 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); #define register_hdlc_device(dev) register_netdev(dev) void unregister_hdlc_device(struct net_device *dev); + +void register_hdlc_protocol(struct hdlc_proto *proto); +void unregister_hdlc_protocol(struct hdlc_proto *proto); + struct net_device *alloc_hdlcdev(void *priv); -static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev) + +static __inline__ struct hdlc_device_desc* dev_to_desc(struct net_device *dev) { return netdev_priv(dev); } - -static __inline__ pvc_device* dev_to_pvc(struct net_device *dev) +static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev) { - return (pvc_device*)dev->priv; + return netdev_priv(dev) + sizeof(struct hdlc_device_desc); } @@ -225,18 +116,14 @@ int hdlc_open(struct net_device *dev); /* Must be called by hardware driver when HDLC device is being closed */ void hdlc_close(struct net_device *dev); +int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto, + int (*rx)(struct sk_buff *skb), size_t size); /* May be used by hardware driver to gain control over HDLC device */ -static __inline__ void hdlc_proto_detach(hdlc_device *hdlc) -{ - if (hdlc->proto.detach) - hdlc->proto.detach(hdlc); - hdlc->proto.detach = NULL; -} - +void detach_hdlc_protocol(struct net_device *dev); static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev) { - return &dev_to_hdlc(dev)->stats; + return &dev_to_desc(dev)->stats; } @@ -248,8 +135,8 @@ static __inline__ __be16 hdlc_type_trans(struct sk_buff *skb, skb->mac.raw = skb->data; skb->dev = dev; - if (hdlc->proto.type_trans) - return hdlc->proto.type_trans(skb, dev); + if (hdlc->proto->type_trans) + return hdlc->proto->type_trans(skb, dev); else return htons(ETH_P_HDLC); } diff --git a/include/linux/hdlc/ioctl.h b/include/linux/hdlc/ioctl.h index 78430ba3ea69..583972364357 100644 --- a/include/linux/hdlc/ioctl.h +++ b/include/linux/hdlc/ioctl.h @@ -1,6 +1,39 @@ #ifndef __HDLC_IOCTL_H__ #define __HDLC_IOCTL_H__ + +#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */ + +#define CLOCK_DEFAULT 0 /* Default setting */ +#define CLOCK_EXT 1 /* External TX and RX clock - DTE */ +#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */ +#define CLOCK_TXINT 3 /* Internal TX and external RX clock */ +#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */ + + +#define ENCODING_DEFAULT 0 /* Default setting */ +#define ENCODING_NRZ 1 +#define ENCODING_NRZI 2 +#define ENCODING_FM_MARK 3 +#define ENCODING_FM_SPACE 4 +#define ENCODING_MANCHESTER 5 + + +#define PARITY_DEFAULT 0 /* Default setting */ +#define PARITY_NONE 1 /* No parity */ +#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */ +#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */ +#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */ +#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */ +#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */ +#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */ + +#define LMI_DEFAULT 0 /* Default setting */ +#define LMI_NONE 1 /* No LMI, all PVCs are static */ +#define LMI_ANSI 2 /* ANSI Annex D */ +#define LMI_CCITT 3 /* ITU-T Annex A */ +#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */ + typedef struct { unsigned int clock_rate; /* bits per second */ unsigned int clock_type; /* internal, external, TX-internal etc. */ -- cgit v1.2.3 From 51c3711704b66986373408cbc0540abea43d2380 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 13 Aug 2006 23:33:16 +0200 Subject: i2c-algo-sibyte: Merge into i2c-sibyte i2c-algo-sibyte: Merge into i2c-sibyte Merge i2c-algo-sibyte into i2c-sibyte, as this is a complete, hardware-dependent SMBus implementation and not a reusable algorithm. Perform some basic coding style cleanups while we're here (mainly space-based indentation replaced by tabulations.) Signed-off-by: Jean Delvare Cc: Ralf Baechle Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/algos/Kconfig | 6 -- drivers/i2c/algos/Makefile | 1 - drivers/i2c/algos/i2c-algo-sibyte.c | 186 ------------------------------------ drivers/i2c/busses/i2c-sibyte.c | 158 +++++++++++++++++++++++++++++- include/linux/i2c-algo-sibyte.h | 33 ------- 5 files changed, 155 insertions(+), 229 deletions(-) delete mode 100644 drivers/i2c/algos/i2c-algo-sibyte.c delete mode 100644 include/linux/i2c-algo-sibyte.h (limited to 'include/linux') diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig index 30408015d231..c034820615bb 100644 --- a/drivers/i2c/algos/Kconfig +++ b/drivers/i2c/algos/Kconfig @@ -53,12 +53,6 @@ config I2C_ALGO8XX tristate "MPC8xx CPM I2C interface" depends on 8xx && I2C -config I2C_ALGO_SIBYTE - tristate "SiByte SMBus interface" - depends on SIBYTE_SB1xxx_SOC && I2C - help - Supports the SiByte SOC on-chip I2C interfaces (2 channels). - config I2C_ALGO_SGI tristate "I2C SGI interfaces" depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS) diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile index 867fe1f67401..208be04a3dbd 100644 --- a/drivers/i2c/algos/Makefile +++ b/drivers/i2c/algos/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o -obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o ifeq ($(CONFIG_I2C_DEBUG_ALGO),y) diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c deleted file mode 100644 index 16d666fa16f3..000000000000 --- a/drivers/i2c/algos/i2c-algo-sibyte.c +++ /dev/null @@ -1,186 +0,0 @@ -/* ------------------------------------------------------------------------- */ -/* i2c-algo-sibyte.c i2c driver algorithms for bit-shift adapters */ -/* ------------------------------------------------------------------------- */ -/* Copyright (C) 2001,2002,2003 Broadcom Corporation - Copyright (C) 1995-2000 Simon G. Vogl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* ------------------------------------------------------------------------- */ - -/* With some changes from Kyösti Mälkki and even - Frodo Looijaard . */ - -/* Ported for SiByte SOCs by Broadcom Corporation. */ - -#include -#include -#include - -#include -#include -#include - -#include -#include - -/* ----- global defines ----------------------------------------------- */ -#define SMB_CSR(a,r) ((long)(a->reg_base + r)) - -/* ----- global variables --------------------------------------------- */ - -/* module parameters: - */ -static int bit_scan; /* have a look at what's hanging 'round */ - - -static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) -{ - struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; - int data_bytes = 0; - int error; - - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) - ; - - switch (size) { - case I2C_SMBUS_QUICK: - csr_out32((V_SMB_ADDR(addr) | (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | - V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START)); - break; - case I2C_SMBUS_BYTE: - if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE), - SMB_CSR(adap, R_SMB_START)); - data_bytes = 1; - } else { - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE), - SMB_CSR(adap, R_SMB_START)); - } - break; - case I2C_SMBUS_BYTE_DATA: - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); - if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE), - SMB_CSR(adap, R_SMB_START)); - data_bytes = 1; - } else { - csr_out32(V_SMB_LB(data->byte), SMB_CSR(adap, R_SMB_DATA)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), - SMB_CSR(adap, R_SMB_START)); - } - break; - case I2C_SMBUS_WORD_DATA: - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); - if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE), - SMB_CSR(adap, R_SMB_START)); - data_bytes = 2; - } else { - csr_out32(V_SMB_LB(data->word & 0xff), SMB_CSR(adap, R_SMB_DATA)); - csr_out32(V_SMB_MB(data->word >> 8), SMB_CSR(adap, R_SMB_DATA)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), - SMB_CSR(adap, R_SMB_START)); - } - break; - default: - return -1; /* XXXKW better error code? */ - } - - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) - ; - - error = csr_in32(SMB_CSR(adap, R_SMB_STATUS)); - if (error & M_SMB_ERROR) { - /* Clear error bit by writing a 1 */ - csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS)); - return -1; /* XXXKW better error code? */ - } - - if (data_bytes == 1) - data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff; - if (data_bytes == 2) - data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff; - - return 0; -} - -static u32 bit_func(struct i2c_adapter *adap) -{ - return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA); -} - - -/* -----exported algorithm data: ------------------------------------- */ - -static struct i2c_algorithm i2c_sibyte_algo = { - .smbus_xfer = smbus_xfer, - .functionality = bit_func, -}; - -/* - * registering functions to load algorithms at runtime - */ -int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) -{ - int i; - struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; - - /* register new adapter to i2c module... */ - i2c_adap->algo = &i2c_sibyte_algo; - - /* Set the frequency to 100 kHz */ - csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ)); - csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL)); - - /* scan bus */ - if (bit_scan) { - union i2c_smbus_data data; - int rc; - printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n", - i2c_adap->name); - for (i = 0x00; i < 0x7f; i++) { - /* XXXKW is this a realistic probe? */ - rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0, - I2C_SMBUS_BYTE_DATA, &data); - if (!rc) { - printk("(%02x)",i); - } else - printk("."); - } - printk("\n"); - } - - return i2c_add_adapter(i2c_adap); -} - - -int i2c_sibyte_del_bus(struct i2c_adapter *adap) -{ - return i2c_del_adapter(adap); -} - - -EXPORT_SYMBOL(i2c_sibyte_add_bus); -EXPORT_SYMBOL(i2c_sibyte_del_bus); - -MODULE_AUTHOR("Kip Walker, Broadcom Corp."); -MODULE_DESCRIPTION("SiByte I2C-Bus algorithm"); -module_param(bit_scan, int, 0); -MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus"); -MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index fa503ed9f86d..f516eb7a23f7 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2004 Steven J. Hill * Copyright (C) 2001,2002,2003 Broadcom Corporation + * Copyright (C) 1995-2000 Simon G. Vogl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -17,11 +18,162 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include -#include +#include +#include +#include #include #include + +struct i2c_algo_sibyte_data { + void *data; /* private data */ + int bus; /* which bus */ + void *reg_base; /* CSR base */ +}; + +/* ----- global defines ----------------------------------------------- */ +#define SMB_CSR(a,r) ((long)(a->reg_base + r)) + +/* ----- global variables --------------------------------------------- */ + +/* module parameters: + */ +static int bit_scan; /* have a look at what's hanging 'round */ +module_param(bit_scan, int, 0); +MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus"); + + +static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data * data) +{ + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + int data_bytes = 0; + int error; + + while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) + ; + + switch (size) { + case I2C_SMBUS_QUICK: + csr_out32((V_SMB_ADDR(addr) | + (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | + V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START)); + break; + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_READ) { + csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE), + SMB_CSR(adap, R_SMB_START)); + data_bytes = 1; + } else { + csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); + csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE), + SMB_CSR(adap, R_SMB_START)); + } + break; + case I2C_SMBUS_BYTE_DATA: + csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); + if (read_write == I2C_SMBUS_READ) { + csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE), + SMB_CSR(adap, R_SMB_START)); + data_bytes = 1; + } else { + csr_out32(V_SMB_LB(data->byte), + SMB_CSR(adap, R_SMB_DATA)); + csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), + SMB_CSR(adap, R_SMB_START)); + } + break; + case I2C_SMBUS_WORD_DATA: + csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); + if (read_write == I2C_SMBUS_READ) { + csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE), + SMB_CSR(adap, R_SMB_START)); + data_bytes = 2; + } else { + csr_out32(V_SMB_LB(data->word & 0xff), + SMB_CSR(adap, R_SMB_DATA)); + csr_out32(V_SMB_MB(data->word >> 8), + SMB_CSR(adap, R_SMB_DATA)); + csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), + SMB_CSR(adap, R_SMB_START)); + } + break; + default: + return -1; /* XXXKW better error code? */ + } + + while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) + ; + + error = csr_in32(SMB_CSR(adap, R_SMB_STATUS)); + if (error & M_SMB_ERROR) { + /* Clear error bit by writing a 1 */ + csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS)); + return -1; /* XXXKW better error code? */ + } + + if (data_bytes == 1) + data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff; + if (data_bytes == 2) + data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff; + + return 0; +} + +static u32 bit_func(struct i2c_adapter *adap) +{ + return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA); +} + + +/* -----exported algorithm data: ------------------------------------- */ + +static struct i2c_algorithm i2c_sibyte_algo = { + .smbus_xfer = smbus_xfer, + .functionality = bit_func, +}; + +/* + * registering functions to load algorithms at runtime + */ +int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) +{ + int i; + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + + /* register new adapter to i2c module... */ + i2c_adap->algo = &i2c_sibyte_algo; + + /* Set the frequency to 100 kHz */ + csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ)); + csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL)); + + /* scan bus */ + if (bit_scan) { + union i2c_smbus_data data; + int rc; + printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n", + i2c_adap->name); + for (i = 0x00; i < 0x7f; i++) { + /* XXXKW is this a realistic probe? */ + rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE_DATA, &data); + if (!rc) { + printk("(%02x)",i); + } else + printk("."); + } + printk("\n"); + } + + return i2c_add_adapter(i2c_adap); +} + + static struct i2c_algo_sibyte_data sibyte_board_data[2] = { { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) }, { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) } @@ -58,8 +210,8 @@ static int __init i2c_sibyte_init(void) static void __exit i2c_sibyte_exit(void) { - i2c_sibyte_del_bus(&sibyte_board_adapter[0]); - i2c_sibyte_del_bus(&sibyte_board_adapter[1]); + i2c_del_bus(&sibyte_board_adapter[0]); + i2c_del_bus(&sibyte_board_adapter[1]); } module_init(i2c_sibyte_init); diff --git a/include/linux/i2c-algo-sibyte.h b/include/linux/i2c-algo-sibyte.h deleted file mode 100644 index 03914ded8614..000000000000 --- a/include/linux/i2c-algo-sibyte.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2001,2002,2003 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef I2C_ALGO_SIBYTE_H -#define I2C_ALGO_SIBYTE_H 1 - -#include - -struct i2c_algo_sibyte_data { - void *data; /* private data */ - int bus; /* which bus */ - void *reg_base; /* CSR base */ -}; - -int i2c_sibyte_add_bus(struct i2c_adapter *, int speed); -int i2c_sibyte_del_bus(struct i2c_adapter *); - -#endif /* I2C_ALGO_SIBYTE_H */ -- cgit v1.2.3 From a0d9c63d3640bd4fc90a408e8334754ef44bcf48 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 27 Aug 2006 11:46:49 +0200 Subject: i2c-algo-bit: Discard the mdelay data struct member i2c-algo-bit: Discard the mdelay data struct member The i2c_algo_bit_data structure has an mdelay member, which is not used by the algorithm code (the code has always been ifdef'd out.) Let's discard it to save some code and memory. Signed-off-by: Jean Delvare Acked-by: Mauro Carvalho Chehab Cc: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/acorn/char/i2c.c | 1 - drivers/i2c/algos/i2c-algo-bit.c | 4 ---- drivers/i2c/busses/i2c-hydra.c | 1 - drivers/i2c/busses/i2c-i810.c | 2 -- drivers/i2c/busses/i2c-ixp2000.c | 1 - drivers/i2c/busses/i2c-ixp4xx.c | 1 - drivers/i2c/busses/i2c-parport-light.c | 1 - drivers/i2c/busses/i2c-parport.c | 1 - drivers/i2c/busses/i2c-prosavage.c | 1 - drivers/i2c/busses/i2c-savage4.c | 1 - drivers/i2c/busses/i2c-via.c | 1 - drivers/i2c/busses/i2c-voodoo3.c | 2 -- drivers/i2c/busses/scx200_i2c.c | 12 ++++++------ drivers/ieee1394/pcilynx.c | 1 - drivers/media/video/bt8xx/bttv-i2c.c | 1 - drivers/media/video/cx88/cx88-i2c.c | 1 - drivers/media/video/cx88/cx88-vp3054-i2c.c | 1 - drivers/media/video/zoran_card.c | 1 - drivers/video/i810/i810-i2c.c | 1 - drivers/video/matrox/i2c-matroxfb.c | 1 - drivers/video/savage/savagefb-i2c.c | 1 - include/linux/i2c-algo-bit.h | 1 - 22 files changed, 6 insertions(+), 32 deletions(-) (limited to 'include/linux') diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c index c26c08b36829..bdb9c8b78ed8 100644 --- a/drivers/acorn/char/i2c.c +++ b/drivers/acorn/char/i2c.c @@ -308,7 +308,6 @@ static struct i2c_algo_bit_data ioc_data = { .getsda = ioc_getsda, .getscl = ioc_getscl, .udelay = 80, - .mdelay = 80, .timeout = 100 }; diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index ab230c033f99..761df16838b4 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -354,10 +354,6 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) return (retval<0)? retval : -EFAULT; /* got a better one ?? */ } -#if 0 - /* from asm/delay.h */ - __delay(adap->mdelay * (loops_per_sec / 1000) ); -#endif } return wrcount; } diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index e0cb3b0f92fa..457d48a0ab9d 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -99,7 +99,6 @@ static struct i2c_algo_bit_data hydra_bit_data = { .getsda = hydra_bit_getsda, .getscl = hydra_bit_getscl, .udelay = 5, - .mdelay = 5, .timeout = HZ }; diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index 748be30f2bae..b66fb6bb1870 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -166,7 +166,6 @@ static struct i2c_algo_bit_data i810_i2c_bit_data = { .getsda = bit_i810i2c_getsda, .getscl = bit_i810i2c_getscl, .udelay = CYCLE_DELAY, - .mdelay = CYCLE_DELAY, .timeout = TIMEOUT, }; @@ -182,7 +181,6 @@ static struct i2c_algo_bit_data i810_ddc_bit_data = { .getsda = bit_i810ddc_getsda, .getscl = bit_i810ddc_getscl, .udelay = CYCLE_DELAY, - .mdelay = CYCLE_DELAY, .timeout = TIMEOUT, }; diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index cd6f45d186ab..dd3f4cd3aa68 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -114,7 +114,6 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev) drv_data->algo_data.getsda = ixp2000_bit_getsda; drv_data->algo_data.getscl = ixp2000_bit_getscl; drv_data->algo_data.udelay = 6; - drv_data->algo_data.mdelay = 6; drv_data->algo_data.timeout = 100; drv_data->adapter.id = I2C_HW_B_IXP2000, diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 2ed07112d683..ab573254a8aa 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -122,7 +122,6 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev) drv_data->algo_data.getsda = ixp4xx_bit_getsda; drv_data->algo_data.getscl = ixp4xx_bit_getscl; drv_data->algo_data.udelay = 10; - drv_data->algo_data.mdelay = 10; drv_data->algo_data.timeout = 100; drv_data->adapter.id = I2C_HW_B_IXP4XX; diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index e09ebbb2f9f0..5eb2bd294fd9 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -103,7 +103,6 @@ static struct i2c_algo_bit_data parport_algo_data = { .getsda = parport_getsda, .getscl = parport_getscl, .udelay = 50, - .mdelay = 50, .timeout = HZ, }; diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 934bd55bae15..48a829431c7b 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -138,7 +138,6 @@ static struct i2c_algo_bit_data parport_algo_data = { .getsda = parport_getsda, .getscl = parport_getscl, .udelay = 60, - .mdelay = 60, .timeout = HZ, }; diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 9479525892e3..7745e21874a8 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c @@ -180,7 +180,6 @@ static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iom p->algo.getsda = bit_s3via_getsda; p->algo.getscl = bit_s3via_getscl; p->algo.udelay = CYCLE_DELAY; - p->algo.mdelay = CYCLE_DELAY; p->algo.timeout = TIMEOUT; p->algo.data = p; p->mmvga = mmvga; diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 0c8518298e4d..209f47ea1750 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c @@ -140,7 +140,6 @@ static struct i2c_algo_bit_data sav_i2c_bit_data = { .getsda = bit_savi2c_getsda, .getscl = bit_savi2c_getscl, .udelay = CYCLE_DELAY, - .mdelay = CYCLE_DELAY, .timeout = TIMEOUT }; diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 484bbacfce6b..910e200ad500 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -81,7 +81,6 @@ static struct i2c_algo_bit_data bit_data = { .getsda = bit_via_getsda, .getscl = bit_via_getscl, .udelay = 5, - .mdelay = 5, .timeout = HZ }; diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index b675773b0cc1..6c8d25183382 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -160,7 +160,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = { .getsda = bit_vooi2c_getsda, .getscl = bit_vooi2c_getscl, .udelay = CYCLE_DELAY, - .mdelay = CYCLE_DELAY, .timeout = TIMEOUT }; @@ -177,7 +176,6 @@ static struct i2c_algo_bit_data voo_ddc_bit_data = { .getsda = bit_vooddc_getsda, .getscl = bit_vooddc_getscl, .udelay = CYCLE_DELAY, - .mdelay = CYCLE_DELAY, .timeout = TIMEOUT }; diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c index cb3ef5ac99fd..8b65a5cf8251 100644 --- a/drivers/i2c/busses/scx200_i2c.c +++ b/drivers/i2c/busses/scx200_i2c.c @@ -71,12 +71,12 @@ static int scx200_i2c_getsda(void *data) */ static struct i2c_algo_bit_data scx200_i2c_data = { - NULL, - scx200_i2c_setsda, - scx200_i2c_setscl, - scx200_i2c_getsda, - scx200_i2c_getscl, - 10, 10, 100, /* waits, timeout */ + .setsda = scx200_i2c_setsda, + .setscl = scx200_i2c_setscl, + .getsda = scx200_i2c_getsda, + .getscl = scx200_i2c_getscl, + .udelay = 10, + .timeout = 100, }; static struct i2c_adapter scx200_i2c_ops = { diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index e6f41238f5e8..b4f146f2c951 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -137,7 +137,6 @@ static struct i2c_algo_bit_data bit_data = { .getsda = bit_getsda, .getscl = bit_getscl, .udelay = 5, - .mdelay = 5, .timeout = 100, }; diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index 4b562b386fcf..0dfbcc85ebb9 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -100,7 +100,6 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { .getsda = bttv_bit_getsda, .getscl = bttv_bit_getscl, .udelay = 16, - .mdelay = 10, .timeout = 200, }; diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 70663805cc30..7bea34714861 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -155,7 +155,6 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = { .getsda = cx8800_bit_getsda, .getscl = cx8800_bit_getscl, .udelay = 16, - .mdelay = 10, .timeout = 200, }; diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index 751a754a45e9..2b4f1970c7df 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -100,7 +100,6 @@ static struct i2c_algo_bit_data vp3054_i2c_algo_template = { .getsda = vp3054_bit_getsda, .getscl = vp3054_bit_getscl, .udelay = 16, - .mdelay = 10, .timeout = 200, }; diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index f2249ed25273..29f59c36f001 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -820,7 +820,6 @@ static struct i2c_algo_bit_data zoran_i2c_bit_data_template = { .getsda = zoran_i2c_getsda, .getscl = zoran_i2c_getscl, .udelay = 10, - .mdelay = 0, .timeout = 100, }; diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c index c1f7b49975dd..7d06b38e80a0 100644 --- a/drivers/video/i810/i810-i2c.c +++ b/drivers/video/i810/i810-i2c.c @@ -98,7 +98,6 @@ static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name) chan->algo.getsda = i810i2c_getsda; chan->algo.getscl = i810i2c_getscl; chan->algo.udelay = 10; - chan->algo.mdelay = 10; chan->algo.timeout = (HZ/2); chan->algo.data = chan; diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c index 9842042d2af5..795c1a99a680 100644 --- a/drivers/video/matrox/i2c-matroxfb.c +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -100,7 +100,6 @@ static struct i2c_algo_bit_data matrox_i2c_algo_template = .getsda = matroxfb_gpio_getsda, .getscl = matroxfb_gpio_getscl, .udelay = 10, - .mdelay = 10, .timeout = 100, }; diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index e83befd16d63..d7d810dbf0bd 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -148,7 +148,6 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan, chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = &chan->par->pcidev->dev; chan->algo.udelay = 40; - chan->algo.mdelay = 5; chan->algo.timeout = 20; chan->algo.data = chan; diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h index c0e7fab28ce3..c8f8df25c7e0 100644 --- a/include/linux/i2c-algo-bit.h +++ b/include/linux/i2c-algo-bit.h @@ -40,7 +40,6 @@ struct i2c_algo_bit_data { /* local settings */ int udelay; /* half-clock-cycle time in microsecs */ /* i.e. clock is (500 / udelay) KHz */ - int mdelay; /* in millisecs, unused */ int timeout; /* in jiffies */ }; -- cgit v1.2.3 From 9b4ccb86b4abe644ffd218720da2f942b6a20fc2 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 3 Sep 2006 22:22:50 +0200 Subject: i2c-algo-pcf: Discard the mdelay data struct member i2c-algo-pcf: Discard the mdelay data struct member Just as i2c-algo-bit, i2c-algo-pcf has an unused mdelay struct member, which we can get rid of to spare some code and memory. Signed-off-by: Adrian Bunk Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-elektor.c | 1 - include/linux/i2c-algo-pcf.h | 1 - 2 files changed, 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 59f8308c2356..caa8e5c8bfbb 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -196,7 +196,6 @@ static struct i2c_algo_pcf_data pcf_isa_data = { .getclock = pcf_isa_getclock, .waitforpin = pcf_isa_waitforpin, .udelay = 10, - .mdelay = 10, .timeout = 100, }; diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h index 18b0adf57a3d..9908f3fc4839 100644 --- a/include/linux/i2c-algo-pcf.h +++ b/include/linux/i2c-algo-pcf.h @@ -35,7 +35,6 @@ struct i2c_algo_pcf_data { /* local settings */ int udelay; - int mdelay; int timeout; }; -- cgit v1.2.3 From af71ff690b92894f66ccede27f731150dc10d80d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 3 Sep 2006 22:37:11 +0200 Subject: i2c: Let drivers constify i2c_algorithm data i2c: Let drivers constify i2c_algorithm data Let drivers constify I2C algorithm method operations tables, moving them from ".data" to ".rodata". Signed-off-by: David Brownell Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/i2c.h b/include/linux/i2c.h index eb0628a7ecc6..23ad1ee42a4c 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -220,7 +220,7 @@ struct i2c_adapter { struct module *owner; unsigned int id; unsigned int class; - struct i2c_algorithm *algo;/* the algorithm to access the bus */ + const struct i2c_algorithm *algo; /* the algorithm to access the bus */ void *algo_data; /* --- administration stuff. */ -- cgit v1.2.3 From 6d3aae9d74221b00e2cbf50a353527e5a71a58ba Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 3 Sep 2006 22:41:08 +0200 Subject: i2c: Drop unimplemented slave functions i2c: Drop unimplemented slave functions Drop the function declarations for slave mode support of i2c adapters. This was never implemented, and by the time it is I bet we will want something different anyway. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c.h | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 23ad1ee42a4c..9b5d04768c2c 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -64,14 +64,6 @@ extern int i2c_master_recv(struct i2c_client *,char* ,int); */ extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); -/* - * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor. - * This is not tested/implemented yet and will change in the future. - */ -extern int i2c_slave_send(struct i2c_client *,char*,int); -extern int i2c_slave_recv(struct i2c_client *,char*,int); - - /* This is the very generalized SMBus access routine. You probably do not want to use this, though; one of the functions below may be much easier, @@ -201,10 +193,6 @@ struct i2c_algorithm { unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data); - /* --- these optional/future use for some adapter types.*/ - int (*slave_send)(struct i2c_adapter *,char*,int); - int (*slave_recv)(struct i2c_adapter *,char*,int); - /* --- ioctl like call to set div. parameters. */ int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long); -- cgit v1.2.3 From 46ff34633ed09f36ebc4b5c40ac37e592172df74 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Thu, 31 Aug 2006 01:55:24 -0400 Subject: MSI: Rename PCI_CAP_ID_HT_IRQCONF into PCI_CAP_ID_HT 0x08 is the HT capability, while PCI_CAP_ID_HT_IRQCONF would be the subtype 0x80 that mpic_scan_ht_pic() uses. Rename PCI_CAP_ID_HT_IRQCONF into PCI_CAP_ID_HT. And by the way, use it in the ipath driver instead of defining its own HT_CAPABILITY_ID. Signed-off-by: Brice Goglin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/sysdev/mpic.c | 2 +- drivers/infiniband/hw/ipath/ipath_iba6110.c | 5 ++--- include/linux/pci_regs.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index b604926401f5..723972bb5bd9 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -339,7 +339,7 @@ static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); - if (id == PCI_CAP_ID_HT_IRQCONF) { + if (id == PCI_CAP_ID_HT) { id = readb(devbase + pos + 3); if (id == 0x80) break; diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index bf2455a6d562..5c9b509e40e4 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -742,7 +742,6 @@ static int ipath_setup_ht_reset(struct ipath_devdata *dd) return 0; } -#define HT_CAPABILITY_ID 0x08 /* HT capabilities not defined in kernel */ #define HT_INTR_DISC_CONFIG 0x80 /* HT interrupt and discovery cap */ #define HT_INTR_REG_INDEX 2 /* intconfig requires indirect accesses */ @@ -973,7 +972,7 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd, * do this early, before we ever enable errors or hardware errors, * mostly to avoid causing the chip to enter freeze mode. */ - pos = pci_find_capability(pdev, HT_CAPABILITY_ID); + pos = pci_find_capability(pdev, PCI_CAP_ID_HT); if (!pos) { ipath_dev_err(dd, "Couldn't find HyperTransport " "capability; no interrupts\n"); @@ -996,7 +995,7 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd, else if (cap_type == HT_INTR_DISC_CONFIG) ihandler = set_int_handler(dd, pdev, pos); } while ((pos = pci_find_next_capability(pdev, pos, - HT_CAPABILITY_ID))); + PCI_CAP_ID_HT))); if (!ihandler) { ipath_dev_err(dd, "Couldn't find interrupt handler in " diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 96930cb5927c..7d0e26cba420 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -196,7 +196,7 @@ #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ -#define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */ +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ #define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */ #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ -- cgit v1.2.3 From 6397c75cbc4d7dbc3d07278b57c82a47dafb21b5 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Thu, 31 Aug 2006 01:55:32 -0400 Subject: MSI: Blacklist PCI-E chipsets depending on Hypertransport MSI capability Introduce msi_ht_cap_enabled() to check the MSI capability in the Hypertransport configuration space. It is used in a generic quirk quirk_msi_ht_cap() to check whether MSI is enabled on hypertransport chipset, and a nVidia specific quirk quirk_nvidia_ck804_msi_ht_cap() where two 2 HT MSI mappings have to be checked. Both quirks set the PCI_BUS_FLAGS_NO_MSI bus flag when MSI is disabled. Signed-off-by: Brice Goglin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 1 + 2 files changed, 60 insertions(+) (limited to 'include/linux') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 8385b815ecb1..08cd86a6dd66 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1703,6 +1703,65 @@ static void __devinit quirk_disable_msi(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi); + +/* Go through the list of Hypertransport capabilities and + * return 1 if a HT MSI capability is found and enabled */ +static int __devinit msi_ht_cap_enabled(struct pci_dev *dev) +{ + u8 pos; + int ttl; + for (pos = pci_find_capability(dev, PCI_CAP_ID_HT), ttl = 48; + pos && ttl; + pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT), ttl--) { + u32 cap_hdr; + /* MSI mapping section according to Hypertransport spec */ + if (pci_read_config_dword(dev, pos, &cap_hdr) == 0 + && (cap_hdr & 0xf8000000) == 0xa8000000 /* MSI mapping */) { + printk(KERN_INFO "PCI: Found HT MSI mapping on %s with capability %s\n", + pci_name(dev), cap_hdr & 0x10000 ? "enabled" : "disabled"); + return (cap_hdr & 0x10000) != 0; /* MSI mapping cap enabled */ + } + } + return 0; +} + +/* Check the hypertransport MSI mapping to know whether MSI is enabled or not */ +static void __devinit quirk_msi_ht_cap(struct pci_dev *dev) +{ + if (dev->subordinate && !msi_ht_cap_enabled(dev)) { + printk(KERN_WARNING "PCI: MSI quirk detected. " + "MSI disabled on chipset %s.\n", + pci_name(dev)); + dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE, + quirk_msi_ht_cap); + +/* The nVidia CK804 chipset may have 2 HT MSI mappings. + * MSI are supported if the MSI capability set in any of these mappings. + */ +static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) +{ + struct pci_dev *pdev; + + if (!dev->subordinate) + return; + + /* check HT MSI cap on this chipset and the root one. + * a single one having MSI is enough to be sure that MSI are supported. + */ + pdev = pci_find_slot(dev->bus->number, 0); + if (dev->subordinate && !msi_ht_cap_enabled(dev) + && !msi_ht_cap_enabled(pdev)) { + printk(KERN_WARNING "PCI: MSI quirk detected. " + "MSI disabled on chipset %s.\n", + pci_name(dev)); + dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, + quirk_nvidia_ck804_msi_ht_cap); #endif /* CONFIG_PCI_MSI */ EXPORT_SYMBOL(pcie_mch_quirk); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6a1e09834559..b9e263adebab 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1411,6 +1411,7 @@ #define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009 #define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017 #define PCI_DEVICE_ID_SERVERWORKS_EPB 0x0103 +#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132 #define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 #define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 #define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203 -- cgit v1.2.3 From 6c2b374d74857e892080ee726184ec1d15e7d4e4 Mon Sep 17 00:00:00 2001 From: "Zhang, Yanmin" Date: Mon, 31 Jul 2006 15:21:33 +0800 Subject: PCI-Express AER implemetation: AER core and aerdriver Patch 3 implements the core part of PCI-Express AER and aerdrv port service driver. When a root port service device is probed, the aerdrv will call request_irq to register irq handler for AER error interrupt. When a device sends an PCI-Express error message to the root port, the root port will trigger an interrupt, by either MSI or IO-APIC, then kernel would run the irq handler. The handler collects root error status register and schedules a work. The work will call the core part to process the error based on its type (Correctable/non-fatal/fatal). As for Correctable errors, the patch chooses to just clear the correctable error status register of the device. As for the non-fatal error, the patch follows generic PCI error handler rules to call the error callback functions of the endpoint's driver. If the device is a bridge, the patch chooses to broadcast the error to downstream devices. As for the fatal error, the patch resets the pci-express link and follows generic PCI error handler rules to call the error callback functions of the endpoint's driver. If the device is a bridge, the patch chooses to broadcast the error to downstream devices. Signed-off-by: Zhang Yanmin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/Kconfig | 1 + drivers/pci/pcie/Makefile | 3 + drivers/pci/pcie/aer/Kconfig | 12 + drivers/pci/pcie/aer/Makefile | 8 + drivers/pci/pcie/aer/aerdrv.c | 346 +++++++++++++++ drivers/pci/pcie/aer/aerdrv.h | 125 ++++++ drivers/pci/pcie/aer/aerdrv_acpi.c | 68 +++ drivers/pci/pcie/aer/aerdrv_core.c | 757 +++++++++++++++++++++++++++++++++ drivers/pci/pcie/aer/aerdrv_errprint.c | 248 +++++++++++ include/linux/aer.h | 24 ++ include/linux/pcieport_if.h | 6 + 11 files changed, 1598 insertions(+) create mode 100644 drivers/pci/pcie/aer/Kconfig create mode 100644 drivers/pci/pcie/aer/Makefile create mode 100644 drivers/pci/pcie/aer/aerdrv.c create mode 100644 drivers/pci/pcie/aer/aerdrv.h create mode 100644 drivers/pci/pcie/aer/aerdrv_acpi.c create mode 100644 drivers/pci/pcie/aer/aerdrv_core.c create mode 100644 drivers/pci/pcie/aer/aerdrv_errprint.c create mode 100644 include/linux/aer.h (limited to 'include/linux') diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 1012db8b8b2c..0ad92a8ad8b1 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -34,3 +34,4 @@ config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE When in doubt, say N. +source "drivers/pci/pcie/aer/Kconfig" diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index 984fa87283e3..e00fb99acf44 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile @@ -5,3 +5,6 @@ pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o + +# Build PCI Express AER if needed +obj-$(CONFIG_PCIEAER) += aer/ diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig new file mode 100644 index 000000000000..3f37a60a6438 --- /dev/null +++ b/drivers/pci/pcie/aer/Kconfig @@ -0,0 +1,12 @@ +# +# PCI Express Root Port Device AER Configuration +# + +config PCIEAER + boolean "Root Port Advanced Error Reporting support" + depends on PCIEPORTBUS && ACPI + default y + help + This enables PCI Express Root Port Advanced Error Reporting + (AER) driver support. Error reporting messages sent to Root + Port will be handled by PCI Express AER driver. diff --git a/drivers/pci/pcie/aer/Makefile b/drivers/pci/pcie/aer/Makefile new file mode 100644 index 000000000000..15a4f40d520b --- /dev/null +++ b/drivers/pci/pcie/aer/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for PCI-Express Root Port Advanced Error Reporting Driver +# + +obj-$(CONFIG_PCIEAER) += aerdriver.o + +aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o aerdrv_acpi.o + diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c new file mode 100644 index 000000000000..0d4ac027d53e --- /dev/null +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -0,0 +1,346 @@ +/* + * drivers/pci/pcie/aer/aerdrv.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * This file implements the AER root port service driver. The driver will + * register an irq handler. When root port triggers an AER interrupt, the irq + * handler will collect root port status and schedule a work. + * + * Copyright (C) 2006 Intel Corp. + * Tom Long Nguyen (tom.l.nguyen@intel.com) + * Zhang Yanmin (yanmin.zhang@intel.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aerdrv.h" + +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0" +#define DRIVER_AUTHOR "tom.l.nguyen@intel.com" +#define DRIVER_DESC "Root Port Advanced Error Reporting Driver" +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +static int __devinit aer_probe (struct pcie_device *dev, + const struct pcie_port_service_id *id ); +static void aer_remove(struct pcie_device *dev); +static int aer_suspend(struct pcie_device *dev, pm_message_t state) +{return 0;} +static int aer_resume(struct pcie_device *dev) {return 0;} +static pci_ers_result_t aer_error_detected(struct pci_dev *dev, + enum pci_channel_state error); +static void aer_error_resume(struct pci_dev *dev); +static pci_ers_result_t aer_root_reset(struct pci_dev *dev); + +/* + * PCI Express bus's AER Root service driver data structure + */ +static struct pcie_port_service_id aer_id[] = { + { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .port_type = PCIE_RC_PORT, + .service_type = PCIE_PORT_SERVICE_AER, + }, + { /* end: all zeroes */ } +}; + +static struct pci_error_handlers aer_error_handlers = { + .error_detected = aer_error_detected, + .resume = aer_error_resume, +}; + +static struct pcie_port_service_driver aerdrv = { + .name = "aer", + .id_table = &aer_id[0], + + .probe = aer_probe, + .remove = aer_remove, + + .suspend = aer_suspend, + .resume = aer_resume, + + .err_handler = &aer_error_handlers, + + .reset_link = aer_root_reset, +}; + +/** + * aer_irq - Root Port's ISR + * @irq: IRQ assigned to Root Port + * @context: pointer to Root Port data structure + * @r: pointer struct pt_regs + * + * Invoked when Root Port detects AER messages. + **/ +static irqreturn_t aer_irq(int irq, void *context, struct pt_regs * r) +{ + unsigned int status, id; + struct pcie_device *pdev = (struct pcie_device *)context; + struct aer_rpc *rpc = get_service_data(pdev); + int next_prod_idx; + unsigned long flags; + int pos; + + pos = pci_find_aer_capability(pdev->port); + /* + * Must lock access to Root Error Status Reg, Root Error ID Reg, + * and Root error producer/consumer index + */ + spin_lock_irqsave(&rpc->e_lock, flags); + + /* Read error status */ + pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status); + if (!(status & ROOT_ERR_STATUS_MASKS)) { + spin_unlock_irqrestore(&rpc->e_lock, flags); + return IRQ_NONE; + } + + /* Read error source and clear error status */ + pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_COR_SRC, &id); + pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status); + + /* Store error source for later DPC handler */ + next_prod_idx = rpc->prod_idx + 1; + if (next_prod_idx == AER_ERROR_SOURCES_MAX) + next_prod_idx = 0; + if (next_prod_idx == rpc->cons_idx) { + /* + * Error Storm Condition - possibly the same error occurred. + * Drop the error. + */ + spin_unlock_irqrestore(&rpc->e_lock, flags); + return IRQ_HANDLED; + } + rpc->e_sources[rpc->prod_idx].status = status; + rpc->e_sources[rpc->prod_idx].id = id; + rpc->prod_idx = next_prod_idx; + spin_unlock_irqrestore(&rpc->e_lock, flags); + + /* Invoke DPC handler */ + schedule_work(&rpc->dpc_handler); + + return IRQ_HANDLED; +} + +/** + * aer_alloc_rpc - allocate Root Port data structure + * @dev: pointer to the pcie_dev data structure + * + * Invoked when Root Port's AER service is loaded. + **/ +static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev) +{ + struct aer_rpc *rpc; + + if (!(rpc = (struct aer_rpc *)kmalloc(sizeof(struct aer_rpc), + GFP_KERNEL))) + return NULL; + + memset(rpc, 0, sizeof(struct aer_rpc)); + /* + * Initialize Root lock access, e_lock, to Root Error Status Reg, + * Root Error ID Reg, and Root error producer/consumer index. + */ + rpc->e_lock = SPIN_LOCK_UNLOCKED; + + rpc->rpd = dev; + INIT_WORK(&rpc->dpc_handler, aer_isr, (void *)dev); + rpc->prod_idx = rpc->cons_idx = 0; + mutex_init(&rpc->rpc_mutex); + init_waitqueue_head(&rpc->wait_release); + + /* Use PCIE bus function to store rpc into PCIE device */ + set_service_data(dev, rpc); + + return rpc; +} + +/** + * aer_remove - clean up resources + * @dev: pointer to the pcie_dev data structure + * + * Invoked when PCI Express bus unloads or AER probe fails. + **/ +static void aer_remove(struct pcie_device *dev) +{ + struct aer_rpc *rpc = get_service_data(dev); + + if (rpc) { + /* If register interrupt service, it must be free. */ + if (rpc->isr) + free_irq(dev->irq, dev); + + wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx); + + aer_delete_rootport(rpc); + set_service_data(dev, NULL); + } +} + +/** + * aer_probe - initialize resources + * @dev: pointer to the pcie_dev data structure + * @id: pointer to the service id data structure + * + * Invoked when PCI Express bus loads AER service driver. + **/ +static int __devinit aer_probe (struct pcie_device *dev, + const struct pcie_port_service_id *id ) +{ + int status; + struct aer_rpc *rpc; + struct device *device = &dev->device; + + /* Init */ + if ((status = aer_init(dev))) + return status; + + /* Alloc rpc data structure */ + if (!(rpc = aer_alloc_rpc(dev))) { + printk(KERN_DEBUG "%s: Alloc rpc fails on PCIE device[%s]\n", + __FUNCTION__, device->bus_id); + aer_remove(dev); + return -ENOMEM; + } + + /* Request IRQ ISR */ + if ((status = request_irq(dev->irq, aer_irq, SA_SHIRQ, "aerdrv", + dev))) { + printk(KERN_DEBUG "%s: Request ISR fails on PCIE device[%s]\n", + __FUNCTION__, device->bus_id); + aer_remove(dev); + return status; + } + + rpc->isr = 1; + + aer_enable_rootport(rpc); + + return status; +} + +/** + * aer_root_reset - reset link on Root Port + * @dev: pointer to Root Port's pci_dev data structure + * + * Invoked by Port Bus driver when performing link reset at Root Port. + **/ +static pci_ers_result_t aer_root_reset(struct pci_dev *dev) +{ + u16 p2p_ctrl; + u32 status; + int pos; + + pos = pci_find_aer_capability(dev); + + /* Disable Root's interrupt in response to error messages */ + pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0); + + /* Assert Secondary Bus Reset */ + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl); + p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET; + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); + + /* De-assert Secondary Bus Reset */ + p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET; + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); + + /* + * System software must wait for at least 100ms from the end + * of a reset of one or more device before it is permitted + * to issue Configuration Requests to those devices. + */ + msleep(200); + printk(KERN_DEBUG "Complete link reset at Root[%s]\n", dev->dev.bus_id); + + /* Enable Root Port's interrupt in response to error messages */ + pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status); + pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status); + pci_write_config_dword(dev, + pos + PCI_ERR_ROOT_COMMAND, + ROOT_PORT_INTR_ON_MESG_MASK); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * aer_error_detected - update severity status + * @dev: pointer to Root Port's pci_dev data structure + * @error: error severity being notified by port bus + * + * Invoked by Port Bus driver during error recovery. + **/ +static pci_ers_result_t aer_error_detected(struct pci_dev *dev, + enum pci_channel_state error) +{ + /* Root Port has no impact. Always recovers. */ + return PCI_ERS_RESULT_CAN_RECOVER; +} + +/** + * aer_error_resume - clean up corresponding error status bits + * @dev: pointer to Root Port's pci_dev data structure + * + * Invoked by Port Bus driver during nonfatal recovery. + **/ +static void aer_error_resume(struct pci_dev *dev) +{ + int pos; + u32 status, mask; + u16 reg16; + + /* Clean up Root device status */ + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16); + pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16); + + /* Clean AER Root Error Status */ + pos = pci_find_aer_capability(dev); + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); + if (dev->error_state == pci_channel_io_normal) + status &= ~mask; /* Clear corresponding nonfatal bits */ + else + status &= mask; /* Clear corresponding fatal bits */ + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); +} + +/** + * aer_service_init - register AER root service driver + * + * Invoked when AER root service driver is loaded. + **/ +static int __init aer_service_init(void) +{ + return pcie_port_service_register(&aerdrv); +} + +/** + * aer_service_exit - unregister AER root service driver + * + * Invoked when AER root service driver is unloaded. + **/ +static void __exit aer_service_exit(void) +{ + pcie_port_service_unregister(&aerdrv); +} + +module_init(aer_service_init); +module_exit(aer_service_exit); diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h new file mode 100644 index 000000000000..daf0cad88fc8 --- /dev/null +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2006 Intel Corp. + * Tom Long Nguyen (tom.l.nguyen@intel.com) + * Zhang Yanmin (yanmin.zhang@intel.com) + * + */ + +#ifndef _AERDRV_H_ +#define _AERDRV_H_ + +#include +#include + +#define AER_NONFATAL 0 +#define AER_FATAL 1 +#define AER_CORRECTABLE 2 +#define AER_UNCORRECTABLE 4 +#define AER_ERROR_MASK 0x001fffff +#define AER_ERROR(d) (d & AER_ERROR_MASK) + +#define OSC_METHOD_RUN_SUCCESS 0 +#define OSC_METHOD_NOT_SUPPORTED 1 +#define OSC_METHOD_RUN_FAILURE 2 + +/* Root Error Status Register Bits */ +#define ROOT_ERR_STATUS_MASKS 0x0f + +#define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \ + PCI_EXP_RTCTL_SENFEE| \ + PCI_EXP_RTCTL_SEFEE) +#define ROOT_PORT_INTR_ON_MESG_MASK (PCI_ERR_ROOT_CMD_COR_EN| \ + PCI_ERR_ROOT_CMD_NONFATAL_EN| \ + PCI_ERR_ROOT_CMD_FATAL_EN) +#define ERR_COR_ID(d) (d & 0xffff) +#define ERR_UNCOR_ID(d) (d >> 16) + +#define AER_SUCCESS 0 +#define AER_UNSUCCESS 1 +#define AER_ERROR_SOURCES_MAX 100 + +#define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \ + PCI_ERR_UNC_ECRC| \ + PCI_ERR_UNC_UNSUP| \ + PCI_ERR_UNC_COMP_ABORT| \ + PCI_ERR_UNC_UNX_COMP| \ + PCI_ERR_UNC_MALF_TLP) + +/* AER Error Info Flags */ +#define AER_TLP_HEADER_VALID_FLAG 0x00000001 +#define AER_MULTI_ERROR_VALID_FLAG 0x00000002 + +#define ERR_CORRECTABLE_ERROR_MASK 0x000031c1 +#define ERR_UNCORRECTABLE_ERROR_MASK 0x001ff010 + +struct header_log_regs { + unsigned int dw0; + unsigned int dw1; + unsigned int dw2; + unsigned int dw3; +}; + +struct aer_err_info { + int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */ + int flags; + unsigned int status; /* COR/UNCOR Error Status */ + struct header_log_regs tlp; /* TLP Header */ +}; + +struct aer_err_source { + unsigned int status; + unsigned int id; +}; + +struct aer_rpc { + struct pcie_device *rpd; /* Root Port device */ + struct work_struct dpc_handler; + struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX]; + unsigned short prod_idx; /* Error Producer Index */ + unsigned short cons_idx; /* Error Consumer Index */ + int isr; + spinlock_t e_lock; /* + * Lock access to Error Status/ID Regs + * and error producer/consumer index + */ + struct mutex rpc_mutex; /* + * only one thread could do + * recovery on the same + * root port hierachy + */ + wait_queue_head_t wait_release; +}; + +struct aer_broadcast_data { + enum pci_channel_state state; + enum pci_ers_result result; +}; + +static inline pci_ers_result_t merge_result(enum pci_ers_result orig, + enum pci_ers_result new) +{ + switch (orig) { + case PCI_ERS_RESULT_CAN_RECOVER: + case PCI_ERS_RESULT_RECOVERED: + orig = new; + break; + case PCI_ERS_RESULT_DISCONNECT: + if (new == PCI_ERS_RESULT_NEED_RESET) + orig = new; + break; + default: + break; + } + + return orig; +} + +extern struct bus_type pcie_port_bus_type; +extern void aer_enable_rootport(struct aer_rpc *rpc); +extern void aer_delete_rootport(struct aer_rpc *rpc); +extern int aer_init(struct pcie_device *dev); +extern void aer_isr(void *context); +extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); +extern int aer_osc_setup(struct pci_dev *dev); + +#endif //_AERDRV_H_ diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c new file mode 100644 index 000000000000..fa68e89ebec9 --- /dev/null +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -0,0 +1,68 @@ +/* + * Access ACPI _OSC method + * + * Copyright (C) 2006 Intel Corp. + * Tom Long Nguyen (tom.l.nguyen@intel.com) + * Zhang Yanmin (yanmin.zhang@intel.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aerdrv.h" + +/** + * aer_osc_setup - run ACPI _OSC method + * + * Return: + * Zero if success. Nonzero for otherwise. + * + * Invoked when PCIE bus loads AER service driver. To avoid conflict with + * BIOS AER support requires BIOS to yield AER control to OS native driver. + **/ +int aer_osc_setup(struct pci_dev *dev) +{ + int retval = OSC_METHOD_RUN_SUCCESS; + acpi_status status; + acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); + struct pci_dev *pdev = dev; + struct pci_bus *parent; + + while (!handle) { + if (!pdev || !pdev->bus->parent) + break; + parent = pdev->bus->parent; + if (!parent->self) + /* Parent must be a host bridge */ + handle = acpi_get_pci_rootbridge_handle( + pci_domain_nr(parent), + parent->number); + else + handle = DEVICE_ACPI_HANDLE( + &(parent->self->dev)); + pdev = parent->self; + } + + if (!handle) + return OSC_METHOD_NOT_SUPPORTED; + + pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT); + status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL | + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); + if (ACPI_FAILURE(status)) { + if (status == AE_SUPPORT) + retval = OSC_METHOD_NOT_SUPPORTED; + else + retval = OSC_METHOD_RUN_FAILURE; + } + + return retval; +} + diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c new file mode 100644 index 000000000000..5591043acea7 --- /dev/null +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -0,0 +1,757 @@ +/* + * drivers/pci/pcie/aer/aerdrv_core.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * This file implements the core part of PCI-Express AER. When an pci-express + * error is delivered, an error message will be collected and printed to + * console, then, an error recovery procedure will be executed by following + * the pci error recovery rules. + * + * Copyright (C) 2006 Intel Corp. + * Tom Long Nguyen (tom.l.nguyen@intel.com) + * Zhang Yanmin (yanmin.zhang@intel.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aerdrv.h" + +static int forceload; +module_param(forceload, bool, 0); + +#define PCI_CFG_SPACE_SIZE (0x100) +int pci_find_aer_capability(struct pci_dev *dev) +{ + int pos; + u32 reg32 = 0; + + /* Check if it's a pci-express device */ + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) + return 0; + + /* Check if it supports pci-express AER */ + pos = PCI_CFG_SPACE_SIZE; + while (pos) { + if (pci_read_config_dword(dev, pos, ®32)) + return 0; + + /* some broken boards return ~0 */ + if (reg32 == 0xffffffff) + return 0; + + if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR) + break; + + pos = reg32 >> 20; + } + + return pos; +} + +int pci_enable_pcie_error_reporting(struct pci_dev *dev) +{ + u16 reg16 = 0; + int pos; + + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) + return -EIO; + + pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, ®16); + reg16 = reg16 | + PCI_EXP_DEVCTL_CERE | + PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | + PCI_EXP_DEVCTL_URRE; + pci_write_config_word(dev, pos+PCI_EXP_DEVCTL, + reg16); + return 0; +} + +int pci_disable_pcie_error_reporting(struct pci_dev *dev) +{ + u16 reg16 = 0; + int pos; + + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) + return -EIO; + + pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, ®16); + reg16 = reg16 & ~(PCI_EXP_DEVCTL_CERE | + PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | + PCI_EXP_DEVCTL_URRE); + pci_write_config_word(dev, pos+PCI_EXP_DEVCTL, + reg16); + return 0; +} + +int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) +{ + int pos; + u32 status, mask; + + pos = pci_find_aer_capability(dev); + if (!pos) + return -EIO; + + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); + if (dev->error_state == pci_channel_io_normal) + status &= ~mask; /* Clear corresponding nonfatal bits */ + else + status &= mask; /* Clear corresponding fatal bits */ + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); + + return 0; +} + +static int find_device_iter(struct device *device, void *data) +{ + struct pci_dev *dev; + u16 id = *(unsigned long *)data; + u8 secondary, subordinate, d_bus = id >> 8; + + if (device->bus == &pci_bus_type) { + dev = to_pci_dev(device); + if (id == ((dev->bus->number << 8) | dev->devfn)) { + /* + * Device ID match + */ + *(unsigned long*)data = (unsigned long)device; + return 1; + } + + /* + * If device is P2P, check if it is an upstream? + */ + if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(dev, PCI_SECONDARY_BUS, + &secondary); + pci_read_config_byte(dev, PCI_SUBORDINATE_BUS, + &subordinate); + if (d_bus >= secondary && d_bus <= subordinate) { + *(unsigned long*)data = (unsigned long)device; + return 1; + } + } + } + + return 0; +} + +/** + * find_source_device - search through device hierarchy for source device + * @p_dev: pointer to Root Port pci_dev data structure + * @id: device ID of agent who sends an error message to this Root Port + * + * Invoked when error is detected at the Root Port. + **/ +static struct device* find_source_device(struct pci_dev *parent, u16 id) +{ + struct pci_dev *dev = parent; + struct device *device; + unsigned long device_addr; + int status; + + /* Is Root Port an agent that sends error message? */ + if (id == ((dev->bus->number << 8) | dev->devfn)) + return &dev->dev; + + do { + device_addr = id; + if ((status = device_for_each_child(&dev->dev, + &device_addr, find_device_iter))) { + device = (struct device*)device_addr; + dev = to_pci_dev(device); + if (id == ((dev->bus->number << 8) | dev->devfn)) + return device; + } + }while (status); + + return NULL; +} + +static void report_error_detected(struct pci_dev *dev, void *data) +{ + pci_ers_result_t vote; + struct pci_error_handlers *err_handler; + struct aer_broadcast_data *result_data; + result_data = (struct aer_broadcast_data *) data; + + dev->error_state = result_data->state; + + if (!dev->driver || + !dev->driver->err_handler || + !dev->driver->err_handler->error_detected) { + if (result_data->state == pci_channel_io_frozen && + !(dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) { + /* + * In case of fatal recovery, if one of down- + * stream device has no driver. We might be + * unable to recover because a later insmod + * of a driver for this device is unaware of + * its hw state. + */ + printk(KERN_DEBUG "Device ID[%s] has %s\n", + dev->dev.bus_id, (dev->driver) ? + "no AER-aware driver" : "no driver"); + } + return; + } + + err_handler = dev->driver->err_handler; + vote = err_handler->error_detected(dev, result_data->state); + result_data->result = merge_result(result_data->result, vote); + return; +} + +static void report_mmio_enabled(struct pci_dev *dev, void *data) +{ + pci_ers_result_t vote; + struct pci_error_handlers *err_handler; + struct aer_broadcast_data *result_data; + result_data = (struct aer_broadcast_data *) data; + + if (!dev->driver || + !dev->driver->err_handler || + !dev->driver->err_handler->mmio_enabled) + return; + + err_handler = dev->driver->err_handler; + vote = err_handler->mmio_enabled(dev); + result_data->result = merge_result(result_data->result, vote); + return; +} + +static void report_slot_reset(struct pci_dev *dev, void *data) +{ + pci_ers_result_t vote; + struct pci_error_handlers *err_handler; + struct aer_broadcast_data *result_data; + result_data = (struct aer_broadcast_data *) data; + + if (!dev->driver || + !dev->driver->err_handler || + !dev->driver->err_handler->slot_reset) + return; + + err_handler = dev->driver->err_handler; + vote = err_handler->slot_reset(dev); + result_data->result = merge_result(result_data->result, vote); + return; +} + +static void report_resume(struct pci_dev *dev, void *data) +{ + struct pci_error_handlers *err_handler; + + dev->error_state = pci_channel_io_normal; + + if (!dev->driver || + !dev->driver->err_handler || + !dev->driver->err_handler->slot_reset) + return; + + err_handler = dev->driver->err_handler; + err_handler->resume(dev); + return; +} + +/** + * broadcast_error_message - handle message broadcast to downstream drivers + * @device: pointer to from where in a hierarchy message is broadcasted down + * @api: callback to be broadcasted + * @state: error state + * + * Invoked during error recovery process. Once being invoked, the content + * of error severity will be broadcasted to all downstream drivers in a + * hierarchy in question. + **/ +static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, + enum pci_channel_state state, + char *error_mesg, + void (*cb)(struct pci_dev *, void *)) +{ + struct aer_broadcast_data result_data; + + printk(KERN_DEBUG "Broadcast %s message\n", error_mesg); + result_data.state = state; + if (cb == report_error_detected) + result_data.result = PCI_ERS_RESULT_CAN_RECOVER; + else + result_data.result = PCI_ERS_RESULT_RECOVERED; + + if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) { + /* + * If the error is reported by a bridge, we think this error + * is related to the downstream link of the bridge, so we + * do error recovery on all subordinates of the bridge instead + * of the bridge and clear the error status of the bridge. + */ + if (cb == report_error_detected) + dev->error_state = state; + pci_walk_bus(dev->subordinate, cb, &result_data); + if (cb == report_resume) { + pci_cleanup_aer_uncorrect_error_status(dev); + dev->error_state = pci_channel_io_normal; + } + } + else { + /* + * If the error is reported by an end point, we think this + * error is related to the upstream link of the end point. + */ + pci_walk_bus(dev->bus, cb, &result_data); + } + + return result_data.result; +} + +struct find_aer_service_data { + struct pcie_port_service_driver *aer_driver; + int is_downstream; +}; + +static int find_aer_service_iter(struct device *device, void *data) +{ + struct device_driver *driver; + struct pcie_port_service_driver *service_driver; + struct pcie_device *pcie_dev; + struct find_aer_service_data *result; + + result = (struct find_aer_service_data *) data; + + if (device->bus == &pcie_port_bus_type) { + pcie_dev = to_pcie_device(device); + if (pcie_dev->id.port_type == PCIE_SW_DOWNSTREAM_PORT) + result->is_downstream = 1; + + driver = device->driver; + if (driver) { + service_driver = to_service_driver(driver); + if (service_driver->id_table->service_type == + PCIE_PORT_SERVICE_AER) { + result->aer_driver = service_driver; + return 1; + } + } + } + + return 0; +} + +static void find_aer_service(struct pci_dev *dev, + struct find_aer_service_data *data) +{ + device_for_each_child(&dev->dev, data, find_aer_service_iter); +} + +static pci_ers_result_t reset_link(struct pcie_device *aerdev, + struct pci_dev *dev) +{ + struct pci_dev *udev; + pci_ers_result_t status; + struct find_aer_service_data data; + + if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) + udev = dev; + else + udev= dev->bus->self; + + data.is_downstream = 0; + data.aer_driver = NULL; + find_aer_service(udev, &data); + + /* + * Use the aer driver of the error agent firstly. + * If it hasn't the aer driver, use the root port's + */ + if (!data.aer_driver || !data.aer_driver->reset_link) { + if (data.is_downstream && + aerdev->device.driver && + to_service_driver(aerdev->device.driver)->reset_link) { + data.aer_driver = + to_service_driver(aerdev->device.driver); + } else { + printk(KERN_DEBUG "No link-reset support to Device ID" + "[%s]\n", + dev->dev.bus_id); + return PCI_ERS_RESULT_DISCONNECT; + } + } + + status = data.aer_driver->reset_link(udev); + if (status != PCI_ERS_RESULT_RECOVERED) { + printk(KERN_DEBUG "Link reset at upstream Device ID" + "[%s] failed\n", + udev->dev.bus_id); + return PCI_ERS_RESULT_DISCONNECT; + } + + return status; +} + +/** + * do_recovery - handle nonfatal/fatal error recovery process + * @aerdev: pointer to a pcie_device data structure of root port + * @dev: pointer to a pci_dev data structure of agent detecting an error + * @severity: error severity type + * + * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast + * error detected message to all downstream drivers within a hierarchy in + * question and return the returned code. + **/ +static pci_ers_result_t do_recovery(struct pcie_device *aerdev, + struct pci_dev *dev, + int severity) +{ + pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED; + enum pci_channel_state state; + + if (severity == AER_FATAL) + state = pci_channel_io_frozen; + else + state = pci_channel_io_normal; + + status = broadcast_error_message(dev, + state, + "error_detected", + report_error_detected); + + if (severity == AER_FATAL) { + result = reset_link(aerdev, dev); + if (result != PCI_ERS_RESULT_RECOVERED) { + /* TODO: Should panic here? */ + return result; + } + } + + if (status == PCI_ERS_RESULT_CAN_RECOVER) + status = broadcast_error_message(dev, + state, + "mmio_enabled", + report_mmio_enabled); + + if (status == PCI_ERS_RESULT_NEED_RESET) { + /* + * TODO: Should call platform-specific + * functions to reset slot before calling + * drivers' slot_reset callbacks? + */ + status = broadcast_error_message(dev, + state, + "slot_reset", + report_slot_reset); + } + + if (status == PCI_ERS_RESULT_RECOVERED) + broadcast_error_message(dev, + state, + "resume", + report_resume); + + return status; +} + +/** + * handle_error_source - handle logging error into an event log + * @aerdev: pointer to pcie_device data structure of the root port + * @dev: pointer to pci_dev data structure of error source device + * @info: comprehensive error information + * + * Invoked when an error being detected by Root Port. + **/ +static void handle_error_source(struct pcie_device * aerdev, + struct pci_dev *dev, + struct aer_err_info info) +{ + pci_ers_result_t status = 0; + int pos; + + if (info.severity == AER_CORRECTABLE) { + /* + * Correctable error does not need software intevention. + * No need to go through error recovery process. + */ + pos = pci_find_aer_capability(dev); + if (pos) + pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, + info.status); + } else { + status = do_recovery(aerdev, dev, info.severity); + if (status == PCI_ERS_RESULT_RECOVERED) { + printk(KERN_DEBUG "AER driver successfully recovered\n"); + } else { + /* TODO: Should kernel panic here? */ + printk(KERN_DEBUG "AER driver didn't recover\n"); + } + } +} + +/** + * aer_enable_rootport - enable Root Port's interrupts when receiving messages + * @rpc: pointer to a Root Port data structure + * + * Invoked when PCIE bus loads AER service driver. + **/ +void aer_enable_rootport(struct aer_rpc *rpc) +{ + struct pci_dev *pdev = rpc->rpd->port; + int pos, aer_pos; + u16 reg16; + u32 reg32; + + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + /* Clear PCIE Capability's Device Status */ + pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, ®16); + pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16); + + /* Disable system error generation in response to error messages */ + pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, ®16); + reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK); + pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16); + + aer_pos = pci_find_aer_capability(pdev); + /* Clear error status */ + pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, ®32); + pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32); + pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, ®32); + pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32); + pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, ®32); + pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32); + + /* Enable Root Port device reporting error itself */ + pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, ®16); + reg16 = reg16 | + PCI_EXP_DEVCTL_CERE | + PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | + PCI_EXP_DEVCTL_URRE; + pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL, + reg16); + + /* Enable Root Port's interrupt in response to error messages */ + pci_write_config_dword(pdev, + aer_pos + PCI_ERR_ROOT_COMMAND, + ROOT_PORT_INTR_ON_MESG_MASK); +} + +/** + * disable_root_aer - disable Root Port's interrupts when receiving messages + * @rpc: pointer to a Root Port data structure + * + * Invoked when PCIE bus unloads AER service driver. + **/ +static void disable_root_aer(struct aer_rpc *rpc) +{ + struct pci_dev *pdev = rpc->rpd->port; + u32 reg32; + int pos; + + pos = pci_find_aer_capability(pdev); + /* Disable Root's interrupt in response to error messages */ + pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0); + + /* Clear Root's error status reg */ + pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, ®32); + pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32); +} + +/** + * get_e_source - retrieve an error source + * @rpc: pointer to the root port which holds an error + * + * Invoked by DPC handler to consume an error. + **/ +static struct aer_err_source* get_e_source(struct aer_rpc *rpc) +{ + struct aer_err_source *e_source; + unsigned long flags; + + /* Lock access to Root error producer/consumer index */ + spin_lock_irqsave(&rpc->e_lock, flags); + if (rpc->prod_idx == rpc->cons_idx) { + spin_unlock_irqrestore(&rpc->e_lock, flags); + return NULL; + } + e_source = &rpc->e_sources[rpc->cons_idx]; + rpc->cons_idx++; + if (rpc->cons_idx == AER_ERROR_SOURCES_MAX) + rpc->cons_idx = 0; + spin_unlock_irqrestore(&rpc->e_lock, flags); + + return e_source; +} + +static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) +{ + int pos; + + pos = pci_find_aer_capability(dev); + + /* The device might not support AER */ + if (!pos) + return AER_SUCCESS; + + if (info->severity == AER_CORRECTABLE) { + pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, + &info->status); + if (!(info->status & ERR_CORRECTABLE_ERROR_MASK)) + return AER_UNSUCCESS; + } else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE || + info->severity == AER_NONFATAL) { + + /* Link is still healthy for IO reads */ + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, + &info->status); + if (!(info->status & ERR_UNCORRECTABLE_ERROR_MASK)) + return AER_UNSUCCESS; + + if (info->status & AER_LOG_TLP_MASKS) { + info->flags |= AER_TLP_HEADER_VALID_FLAG; + pci_read_config_dword(dev, + pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0); + pci_read_config_dword(dev, + pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1); + pci_read_config_dword(dev, + pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2); + pci_read_config_dword(dev, + pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3); + } + } + + return AER_SUCCESS; +} + +/** + * aer_isr_one_error - consume an error detected by root port + * @p_device: pointer to error root port service device + * @e_src: pointer to an error source + **/ +static void aer_isr_one_error(struct pcie_device *p_device, + struct aer_err_source *e_src) +{ + struct device *s_device; + struct aer_err_info e_info = {0, 0, 0,}; + int i; + u16 id; + + /* + * There is a possibility that both correctable error and + * uncorrectable error being logged. Report correctable error first. + */ + for (i = 1; i & ROOT_ERR_STATUS_MASKS ; i <<= 2) { + if (i > 4) + break; + if (!(e_src->status & i)) + continue; + + /* Init comprehensive error information */ + if (i & PCI_ERR_ROOT_COR_RCV) { + id = ERR_COR_ID(e_src->id); + e_info.severity = AER_CORRECTABLE; + } else { + id = ERR_UNCOR_ID(e_src->id); + e_info.severity = ((e_src->status >> 6) & 1); + } + if (e_src->status & + (PCI_ERR_ROOT_MULTI_COR_RCV | + PCI_ERR_ROOT_MULTI_UNCOR_RCV)) + e_info.flags |= AER_MULTI_ERROR_VALID_FLAG; + if (!(s_device = find_source_device(p_device->port, id))) { + printk(KERN_DEBUG "%s->can't find device of ID%04x\n", + __FUNCTION__, id); + continue; + } + if (get_device_error_info(to_pci_dev(s_device), &e_info) == + AER_SUCCESS) { + aer_print_error(to_pci_dev(s_device), &e_info); + handle_error_source(p_device, + to_pci_dev(s_device), + e_info); + } + } +} + +/** + * aer_isr - consume errors detected by root port + * @context: pointer to a private data of pcie device + * + * Invoked, as DPC, when root port records new detected error + **/ +void aer_isr(void *context) +{ + struct pcie_device *p_device = (struct pcie_device *) context; + struct aer_rpc *rpc = get_service_data(p_device); + struct aer_err_source *e_src; + + mutex_lock(&rpc->rpc_mutex); + e_src = get_e_source(rpc); + while (e_src) { + aer_isr_one_error(p_device, e_src); + e_src = get_e_source(rpc); + } + mutex_unlock(&rpc->rpc_mutex); + + wake_up(&rpc->wait_release); +} + +/** + * aer_delete_rootport - disable root port aer and delete service data + * @rpc: pointer to a root port device being deleted + * + * Invoked when AER service unloaded on a specific Root Port + **/ +void aer_delete_rootport(struct aer_rpc *rpc) +{ + /* Disable root port AER itself */ + disable_root_aer(rpc); + + kfree(rpc); +} + +/** + * aer_init - provide AER initialization + * @dev: pointer to AER pcie device + * + * Invoked when AER service driver is loaded. + **/ +int aer_init(struct pcie_device *dev) +{ + int status; + + /* Run _OSC Method */ + status = aer_osc_setup(dev->port); + + if(status != OSC_METHOD_RUN_SUCCESS) { + printk(KERN_DEBUG "%s: AER service init fails - %s\n", + __FUNCTION__, + (status == OSC_METHOD_NOT_SUPPORTED) ? + "No ACPI _OSC support" : "Run ACPI _OSC fails"); + + if (!forceload) + return status; + } + + return AER_SUCCESS; +} + +EXPORT_SYMBOL_GPL(pci_find_aer_capability); +EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting); +EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); +EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); + diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c new file mode 100644 index 000000000000..3933d4f30e8c --- /dev/null +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c @@ -0,0 +1,248 @@ +/* + * drivers/pci/pcie/aer/aerdrv_errprint.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Format error messages and print them to console. + * + * Copyright (C) 2006 Intel Corp. + * Tom Long Nguyen (tom.l.nguyen@intel.com) + * Zhang Yanmin (yanmin.zhang@intel.com) + * + */ + +#include +#include +#include +#include +#include +#include + +#include "aerdrv.h" + +#define AER_AGENT_RECEIVER 0 +#define AER_AGENT_REQUESTER 1 +#define AER_AGENT_COMPLETER 2 +#define AER_AGENT_TRANSMITTER 3 + +#define AER_AGENT_REQUESTER_MASK (PCI_ERR_UNC_COMP_TIME| \ + PCI_ERR_UNC_UNSUP) + +#define AER_AGENT_COMPLETER_MASK PCI_ERR_UNC_COMP_ABORT + +#define AER_AGENT_TRANSMITTER_MASK(t, e) (e & (PCI_ERR_COR_REP_ROLL| \ + ((t == AER_CORRECTABLE) ? PCI_ERR_COR_REP_TIMER: 0))) + +#define AER_GET_AGENT(t, e) \ + ((e & AER_AGENT_COMPLETER_MASK) ? AER_AGENT_COMPLETER : \ + (e & AER_AGENT_REQUESTER_MASK) ? AER_AGENT_REQUESTER : \ + (AER_AGENT_TRANSMITTER_MASK(t, e)) ? AER_AGENT_TRANSMITTER : \ + AER_AGENT_RECEIVER) + +#define AER_PHYSICAL_LAYER_ERROR_MASK PCI_ERR_COR_RCVR +#define AER_DATA_LINK_LAYER_ERROR_MASK(t, e) \ + (PCI_ERR_UNC_DLP| \ + PCI_ERR_COR_BAD_TLP| \ + PCI_ERR_COR_BAD_DLLP| \ + PCI_ERR_COR_REP_ROLL| \ + ((t == AER_CORRECTABLE) ? \ + PCI_ERR_COR_REP_TIMER: 0)) + +#define AER_PHYSICAL_LAYER_ERROR 0 +#define AER_DATA_LINK_LAYER_ERROR 1 +#define AER_TRANSACTION_LAYER_ERROR 2 + +#define AER_GET_LAYER_ERROR(t, e) \ + ((e & AER_PHYSICAL_LAYER_ERROR_MASK) ? \ + AER_PHYSICAL_LAYER_ERROR : \ + (e & AER_DATA_LINK_LAYER_ERROR_MASK(t, e)) ? \ + AER_DATA_LINK_LAYER_ERROR : \ + AER_TRANSACTION_LAYER_ERROR) + +/* + * AER error strings + */ +static char* aer_error_severity_string[] = { + "Uncorrected (Non-Fatal)", + "Uncorrected (Fatal)", + "Corrected" +}; + +static char* aer_error_layer[] = { + "Physical Layer", + "Data Link Layer", + "Transaction Layer" +}; +static char* aer_correctable_error_string[] = { + "Receiver Error ", /* Bit Position 0 */ + NULL, + NULL, + NULL, + NULL, + NULL, + "Bad TLP ", /* Bit Position 6 */ + "Bad DLLP ", /* Bit Position 7 */ + "RELAY_NUM Rollover ", /* Bit Position 8 */ + NULL, + NULL, + NULL, + "Replay Timer Timeout ", /* Bit Position 12 */ + "Advisory Non-Fatal ", /* Bit Position 13 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +static char* aer_uncorrectable_error_string[] = { + NULL, + NULL, + NULL, + NULL, + "Data Link Protocol ", /* Bit Position 4 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "Poisoned TLP ", /* Bit Position 12 */ + "Flow Control Protocol ", /* Bit Position 13 */ + "Completion Timeout ", /* Bit Position 14 */ + "Completer Abort ", /* Bit Position 15 */ + "Unexpected Completion ", /* Bit Position 16 */ + "Receiver Overflow ", /* Bit Position 17 */ + "Malformed TLP ", /* Bit Position 18 */ + "ECRC ", /* Bit Position 19 */ + "Unsupported Request ", /* Bit Position 20 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +static char* aer_agent_string[] = { + "Receiver ID", + "Requester ID", + "Completer ID", + "Transmitter ID" +}; + +static char * aer_get_error_source_name(int severity, + unsigned int status, + char errmsg_buff[]) +{ + int i; + char * errmsg = NULL; + + for (i = 0; i < 32; i++) { + if (!(status & (1 << i))) + continue; + + if (severity == AER_CORRECTABLE) + errmsg = aer_correctable_error_string[i]; + else + errmsg = aer_uncorrectable_error_string[i]; + + if (!errmsg) { + sprintf(errmsg_buff, "Unknown Error Bit %2d ", i); + errmsg = errmsg_buff; + } + + break; + } + + return errmsg; +} + +static DEFINE_SPINLOCK(logbuf_lock); +static char errmsg_buff[100]; +void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) +{ + char * errmsg; + int err_layer, agent; + char * loglevel; + + if (info->severity == AER_CORRECTABLE) + loglevel = KERN_WARNING; + else + loglevel = KERN_ERR; + + printk("%s+------ PCI-Express Device Error ------+\n", loglevel); + printk("%sError Severity\t\t: %s\n", loglevel, + aer_error_severity_string[info->severity]); + + if ( info->status == 0) { + printk("%sPCIE Bus Error type\t: (Unaccessible)\n", loglevel); + printk("%sUnaccessible Received\t: %s\n", loglevel, + info->flags & AER_MULTI_ERROR_VALID_FLAG ? + "Multiple" : "First"); + printk("%sUnregistered Agent ID\t: %04x\n", loglevel, + (dev->bus->number << 8) | dev->devfn); + } else { + err_layer = AER_GET_LAYER_ERROR(info->severity, info->status); + printk("%sPCIE Bus Error type\t: %s\n", loglevel, + aer_error_layer[err_layer]); + + spin_lock(&logbuf_lock); + errmsg = aer_get_error_source_name(info->severity, + info->status, + errmsg_buff); + printk("%s%s\t: %s\n", loglevel, errmsg, + info->flags & AER_MULTI_ERROR_VALID_FLAG ? + "Multiple" : "First"); + spin_unlock(&logbuf_lock); + + agent = AER_GET_AGENT(info->severity, info->status); + printk("%s%s\t\t: %04x\n", loglevel, + aer_agent_string[agent], + (dev->bus->number << 8) | dev->devfn); + + printk("%sVendorID=%04xh, DeviceID=%04xh," + " Bus=%02xh, Device=%02xh, Function=%02xh\n", + loglevel, + dev->vendor, + dev->device, + dev->bus->number, + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + + if (info->flags & AER_TLP_HEADER_VALID_FLAG) { + unsigned char *tlp = (unsigned char *) &info->tlp; + printk("%sTLB Header:\n", loglevel); + printk("%s%02x%02x%02x%02x %02x%02x%02x%02x" + " %02x%02x%02x%02x %02x%02x%02x%02x\n", + loglevel, + *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, + *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), + *(tlp + 11), *(tlp + 10), *(tlp + 9), + *(tlp + 8), *(tlp + 15), *(tlp + 14), + *(tlp + 13), *(tlp + 12)); + } + } +} + diff --git a/include/linux/aer.h b/include/linux/aer.h new file mode 100644 index 000000000000..402e178b38eb --- /dev/null +++ b/include/linux/aer.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2006 Intel Corp. + * Tom Long Nguyen (tom.l.nguyen@intel.com) + * Zhang Yanmin (yanmin.zhang@intel.com) + */ + +#ifndef _AER_H_ +#define _AER_H_ + +#if defined(CONFIG_PCIEAER) +/* pci-e port driver needs this function to enable aer */ +extern int pci_enable_pcie_error_reporting(struct pci_dev *dev); +extern int pci_find_aer_capability(struct pci_dev *dev); +extern int pci_disable_pcie_error_reporting(struct pci_dev *dev); +extern int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev); +#else +#define pci_enable_pcie_error_reporting(dev) do { } while (0) +#define pci_find_aer_capability(dev) do { } while (0) +#define pci_disable_pcie_error_reporting(dev) do { } while (0) +#define pci_cleanup_aer_uncorrect_error_status(dev) do { } while (0) +#endif + +#endif //_AER_H_ + diff --git a/include/linux/pcieport_if.h b/include/linux/pcieport_if.h index b44e01a70914..6cd91e3f9820 100644 --- a/include/linux/pcieport_if.h +++ b/include/linux/pcieport_if.h @@ -62,6 +62,12 @@ struct pcie_port_service_driver { int (*suspend) (struct pcie_device *dev, pm_message_t state); int (*resume) (struct pcie_device *dev); + /* Service Error Recovery Handler */ + struct pci_error_handlers *err_handler; + + /* Link Reset Capability - AER service driver specific */ + pci_ers_result_t (*reset_link) (struct pci_dev *dev); + const struct pcie_port_service_id *id_table; struct device_driver driver; }; -- cgit v1.2.3 From b19441af185559118e8247382ea4f2f76ebffc6d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 28 Aug 2006 11:43:25 -0700 Subject: PCI: fix __must_check warnings Signed-off-by: Greg Kroah-Hartman --- drivers/pci/bus.c | 22 ++++++-- drivers/pci/hotplug/fakephp.c | 18 ++++-- drivers/pci/pci-driver.c | 5 +- drivers/pci/pci-sysfs.c | 112 ++++++++++++++++++++++++------------- drivers/pci/pcie/aer/aerdrv_core.c | 3 +- drivers/pci/pcie/portdrv_core.c | 6 +- drivers/pci/pcie/portdrv_pci.c | 16 ++++-- drivers/pci/probe.c | 16 +++++- include/linux/pci.h | 2 +- 9 files changed, 138 insertions(+), 62 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 5f7db9d2436e..aadaa3c8096b 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -77,9 +77,12 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, * This adds a single pci device to the global * device list and adds sysfs and procfs entries */ -void __devinit pci_bus_add_device(struct pci_dev *dev) +int __devinit pci_bus_add_device(struct pci_dev *dev) { - device_add(&dev->dev); + int retval; + retval = device_add(&dev->dev); + if (retval) + return retval; down_write(&pci_bus_sem); list_add_tail(&dev->global_list, &pci_devices); @@ -87,6 +90,7 @@ void __devinit pci_bus_add_device(struct pci_dev *dev) pci_proc_attach_device(dev); pci_create_sysfs_dev_files(dev); + return 0; } /** @@ -104,6 +108,7 @@ void __devinit pci_bus_add_device(struct pci_dev *dev) void __devinit pci_bus_add_devices(struct pci_bus *bus) { struct pci_dev *dev; + int retval; list_for_each_entry(dev, &bus->devices, bus_list) { /* @@ -112,7 +117,9 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) */ if (!list_empty(&dev->global_list)) continue; - pci_bus_add_device(dev); + retval = pci_bus_add_device(dev); + if (retval) + dev_err(&dev->dev, "Error adding device, continuing\n"); } list_for_each_entry(dev, &bus->devices, bus_list) { @@ -129,10 +136,13 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) list_add_tail(&dev->subordinate->node, &dev->bus->children); up_write(&pci_bus_sem); - } + } pci_bus_add_devices(dev->subordinate); - - sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge"); + retval = sysfs_create_link(&dev->subordinate->class_dev.kobj, + &dev->dev.kobj, "bridge"); + if (retval) + dev_err(&dev->dev, "Error creating sysfs " + "bridge symlink, continuing...\n"); } } } diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index dd2b762777c4..05a4f0f90186 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -176,7 +176,9 @@ static void pci_rescan_slot(struct pci_dev *temp) struct pci_bus *bus = temp->bus; struct pci_dev *dev; int func; + int retval; u8 hdr_type; + if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) { temp->hdr_type = hdr_type & 0x7f; if (!pci_find_slot(bus->number, temp->devfn)) { @@ -185,8 +187,12 @@ static void pci_rescan_slot(struct pci_dev *temp) dbg("New device on %s function %x:%x\n", bus->name, temp->devfn >> 3, temp->devfn & 7); - pci_bus_add_device(dev); - add_slot(dev); + retval = pci_bus_add_device(dev); + if (retval) + dev_err(&dev->dev, "error adding " + "device, continuing.\n"); + else + add_slot(dev); } } /* multifunction device? */ @@ -205,8 +211,12 @@ static void pci_rescan_slot(struct pci_dev *temp) dbg("New device on %s function %x:%x\n", bus->name, temp->devfn >> 3, temp->devfn & 7); - pci_bus_add_device(dev); - add_slot(dev); + retval = pci_bus_add_device(dev); + if (retval) + dev_err(&dev->dev, "error adding " + "device, continuing.\n"); + else + add_slot(dev); } } } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d8ace1f90dd2..309629e03bae 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -56,6 +56,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) subdevice=PCI_ANY_ID, class=0, class_mask=0; unsigned long driver_data=0; int fields=0; + int retval = 0; fields = sscanf(buf, "%x %x %x %x %x %x %lux", &vendor, &device, &subvendor, &subdevice, @@ -82,10 +83,12 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) spin_unlock(&pdrv->dynids.lock); if (get_driver(&pdrv->driver)) { - driver_attach(&pdrv->driver); + retval = driver_attach(&pdrv->driver); put_driver(&pdrv->driver); } + if (retval) + return retval; return count; } static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 010e01c4bd43..a1d2e979b17f 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -117,6 +117,7 @@ is_enabled_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); + int retval = 0; /* this can crash the machine when done on the "wrong" device */ if (!capable(CAP_SYS_ADMIN)) @@ -126,8 +127,10 @@ is_enabled_store(struct device *dev, struct device_attribute *attr, pci_disable_device(pdev); if (*buf == '1') - pci_enable_device(pdev); + retval = pci_enable_device(pdev); + if (retval) + return retval; return count; } @@ -425,16 +428,39 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, return pci_mmap_page_range(pdev, vma, mmap_type, 0); } +/** + * pci_remove_resource_files - cleanup resource files + * @dev: dev to cleanup + * + * If we created resource files for @dev, remove them from sysfs and + * free their resources. + */ +static void +pci_remove_resource_files(struct pci_dev *pdev) +{ + int i; + + for (i = 0; i < PCI_ROM_RESOURCE; i++) { + struct bin_attribute *res_attr; + + res_attr = pdev->res_attr[i]; + if (res_attr) { + sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); + kfree(res_attr); + } + } +} + /** * pci_create_resource_files - create resource files in sysfs for @dev * @dev: dev in question * * Walk the resources in @dev creating files for each resource available. */ -static void -pci_create_resource_files(struct pci_dev *pdev) +static int pci_create_resource_files(struct pci_dev *pdev) { int i; + int retval; /* Expose the PCI resources from this device as files */ for (i = 0; i < PCI_ROM_RESOURCE; i++) { @@ -457,35 +483,19 @@ pci_create_resource_files(struct pci_dev *pdev) res_attr->size = pci_resource_len(pdev, i); res_attr->mmap = pci_mmap_resource; res_attr->private = &pdev->resource[i]; - sysfs_create_bin_file(&pdev->dev.kobj, res_attr); - } - } -} - -/** - * pci_remove_resource_files - cleanup resource files - * @dev: dev to cleanup - * - * If we created resource files for @dev, remove them from sysfs and - * free their resources. - */ -static void -pci_remove_resource_files(struct pci_dev *pdev) -{ - int i; - - for (i = 0; i < PCI_ROM_RESOURCE; i++) { - struct bin_attribute *res_attr; - - res_attr = pdev->res_attr[i]; - if (res_attr) { - sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); - kfree(res_attr); + retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); + if (retval) { + pci_remove_resource_files(pdev); + return retval; + } + } else { + return -ENOMEM; } } + return 0; } #else /* !HAVE_PCI_MMAP */ -static inline void pci_create_resource_files(struct pci_dev *dev) { return; } +static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; } static inline void pci_remove_resource_files(struct pci_dev *dev) { return; } #endif /* HAVE_PCI_MMAP */ @@ -570,22 +580,27 @@ static struct bin_attribute pcie_config_attr = { .write = pci_write_config, }; -int pci_create_sysfs_dev_files (struct pci_dev *pdev) +int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) { + struct bin_attribute *rom_attr = NULL; + int retval; + if (!sysfs_initialized) return -EACCES; if (pdev->cfg_size < 4096) - sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); + retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); else - sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); + retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); + if (retval) + goto err; - pci_create_resource_files(pdev); + retval = pci_create_resource_files(pdev); + if (retval) + goto err_bin_file; /* If the device has a ROM, try to expose it in sysfs. */ if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { - struct bin_attribute *rom_attr; - rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); if (rom_attr) { pdev->rom_attr = rom_attr; @@ -595,13 +610,28 @@ int pci_create_sysfs_dev_files (struct pci_dev *pdev) rom_attr->attr.owner = THIS_MODULE; rom_attr->read = pci_read_rom; rom_attr->write = pci_write_rom; - sysfs_create_bin_file(&pdev->dev.kobj, rom_attr); + retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr); + if (retval) + goto err_rom; + } else { + retval = -ENOMEM; + goto err_bin_file; } } /* add platform-specific attributes */ pcibios_add_platform_entries(pdev); - + return 0; + +err_rom: + kfree(rom_attr); +err_bin_file: + if (pdev->cfg_size < 4096) + sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); + else + sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); +err: + return retval; } /** @@ -630,10 +660,14 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) static int __init pci_sysfs_init(void) { struct pci_dev *pdev = NULL; - + int retval; + sysfs_initialized = 1; - for_each_pci_dev(pdev) - pci_create_sysfs_dev_files(pdev); + for_each_pci_dev(pdev) { + retval = pci_create_sysfs_dev_files(pdev); + if (retval) + return retval; + } return 0; } diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 5591043acea7..1c7e660d6535 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -357,7 +357,8 @@ static int find_aer_service_iter(struct device *device, void *data) static void find_aer_service(struct pci_dev *dev, struct find_aer_service_data *data) { - device_for_each_child(&dev->dev, data, find_aer_service_iter); + int retval; + retval = device_for_each_child(&dev->dev, data, find_aer_service_iter); } static pci_ers_result_t reset_link(struct pcie_device *aerdev, diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index cf9e810b4bf8..bd6615b4d40e 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -340,8 +340,7 @@ static int suspend_iter(struct device *dev, void *data) int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state) { - device_for_each_child(&dev->dev, &state, suspend_iter); - return 0; + return device_for_each_child(&dev->dev, &state, suspend_iter); } static int resume_iter(struct device *dev, void *data) @@ -359,8 +358,7 @@ static int resume_iter(struct device *dev, void *data) int pcie_port_device_resume(struct pci_dev *dev) { - device_for_each_child(&dev->dev, NULL, resume_iter); - return 0; + return device_for_each_child(&dev->dev, NULL, resume_iter); } #endif diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index e4a2429986f0..037690e08f5f 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -147,8 +147,10 @@ static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, { struct aer_broadcast_data result_data = {error, PCI_ERS_RESULT_CAN_RECOVER}; + int retval; - device_for_each_child(&dev->dev, &result_data, error_detected_iter); + /* can not fail */ + retval = device_for_each_child(&dev->dev, &result_data, error_detected_iter); return result_data.result; } @@ -181,8 +183,10 @@ static int mmio_enabled_iter(struct device *device, void *data) static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev) { pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; + int retval; - device_for_each_child(&dev->dev, &status, mmio_enabled_iter); + /* get true return value from &status */ + retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter); return status; } @@ -214,6 +218,7 @@ static int slot_reset_iter(struct device *device, void *data) static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) { pci_ers_result_t status; + int retval; /* If fatal, restore cfg space for possible link reset at upstream */ if (dev->error_state == pci_channel_io_frozen) { @@ -221,7 +226,8 @@ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) pci_enable_pcie_error_reporting(dev); } - device_for_each_child(&dev->dev, &status, slot_reset_iter); + /* get true return value from &status */ + retval = device_for_each_child(&dev->dev, &status, slot_reset_iter); return status; } @@ -248,7 +254,9 @@ static int resume_iter(struct device *device, void *data) static void pcie_portdrv_err_resume(struct pci_dev *dev) { - device_for_each_child(&dev->dev, NULL, resume_iter); + int retval; + /* nothing to do with error value, if it ever happens */ + retval = device_for_each_child(&dev->dev, NULL, resume_iter); } /* diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c5a58d1c6c1c..a3b0a5eb5054 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -339,6 +339,7 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) { struct pci_bus *child; int i; + int retval; /* * Allocate a new bus, and inherit stuff from the parent.. @@ -356,8 +357,13 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) child->class_dev.class = &pcibus_class; sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr); - class_device_register(&child->class_dev); - class_device_create_file(&child->class_dev, &class_device_attr_cpuaffinity); + retval = class_device_register(&child->class_dev); + if (retval) + goto error_register; + retval = class_device_create_file(&child->class_dev, + &class_device_attr_cpuaffinity); + if (retval) + goto error_file_create; /* * Set up the primary, secondary and subordinate @@ -375,6 +381,12 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) bridge->subordinate = child; return child; + +error_file_create: + class_device_unregister(&child->class_dev); +error_register: + kfree(child); + return NULL; } struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) diff --git a/include/linux/pci.h b/include/linux/pci.h index 3ec72551ac31..c9bb7bee52c7 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -431,7 +431,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn); struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn); void pci_device_add(struct pci_dev *dev, struct pci_bus *bus); unsigned int pci_scan_child_bus(struct pci_bus *bus); -void pci_bus_add_device(struct pci_dev *dev); +int __must_check pci_bus_add_device(struct pci_dev *dev); void pci_read_bridge_bases(struct pci_bus *child); struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res); int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge); -- cgit v1.2.3 From 50b0075520a0acba9cabab5203bbce918b966d9a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 16 Aug 2006 17:42:18 +0100 Subject: PCI: Multiprobe sanitizer There are numerous drivers that can use multithreaded probing but having some kind of global flag as the way to control this makes migration to threaded probing hard and since it enables it everywhere and is almost as likely to cause serious pain as holding a clog dance in a minefield. If we have a pci_driver multithread_probe flag to inherit you can turn it on for one driver at a time. From playing so far however I think we need a different model at the device layer which serializes until the called probe function says "ok you can start another one now". That would need some kind of flag and semaphore plus a helper function. Anyway in the absence of that this is a starting point to usefully play with this stuff Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 6 +++++- include/linux/pci.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 309629e03bae..b1c0c707d96c 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -421,7 +421,11 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner) drv->driver.bus = &pci_bus_type; drv->driver.owner = owner; drv->driver.kobj.ktype = &pci_driver_kobj_type; - drv->driver.multithread_probe = pci_multithread_probe; + + if (pci_multithread_probe) + drv->driver.multithread_probe = pci_multithread_probe; + else + drv->driver.multithread_probe = drv->multithread_probe; spin_lock_init(&drv->dynids.lock); INIT_LIST_HEAD(&drv->dynids.list); diff --git a/include/linux/pci.h b/include/linux/pci.h index c9bb7bee52c7..549d8410974b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -356,6 +356,8 @@ struct pci_driver { struct pci_error_handlers *err_handler; struct device_driver driver; struct pci_dynids dynids; + + int multithread_probe; }; #define to_pci_driver(drv) container_of(drv,struct pci_driver, driver) -- cgit v1.2.3 From 24f8aa9b464b73e0553f092b747770940ee0ea54 Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Tue, 12 Sep 2006 10:16:36 -0700 Subject: PCI: add pci_stop_bus_device This patch adds pci_stop_bus_device() which stops a PCI device (detach the driver, remove from the global list and so on) and any children. This is needed for ACPI based PCI-to-PCI bridge hot-remove, and it will be also needed for ACPI based PCI root bridge hot-remove. Signed-off-by: Kenji Kaneshige Signed-off-by: MUNEDA Takahiro Signed-off-by: Satoru Takeuchi Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/remove.c | 37 ++++++++++++++++++++++++++++++++++++- include/linux/pci.h | 1 + 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 99ffbd478b29..430281b2e921 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -16,8 +16,11 @@ static void pci_free_resources(struct pci_dev *dev) } } -static void pci_destroy_dev(struct pci_dev *dev) +static void pci_stop_dev(struct pci_dev *dev) { + if (!dev->global_list.next) + return; + if (!list_empty(&dev->global_list)) { pci_proc_detach_device(dev); pci_remove_sysfs_dev_files(dev); @@ -27,6 +30,11 @@ static void pci_destroy_dev(struct pci_dev *dev) dev->global_list.next = dev->global_list.prev = NULL; up_write(&pci_bus_sem); } +} + +static void pci_destroy_dev(struct pci_dev *dev) +{ + pci_stop_dev(dev); /* Remove the device from the device lists, and prevent any further * list accesses from this device */ @@ -119,5 +127,32 @@ void pci_remove_behind_bridge(struct pci_dev *dev) } } +static void pci_stop_bus_devices(struct pci_bus *bus) +{ + struct list_head *l, *n; + + list_for_each_safe(l, n, &bus->devices) { + struct pci_dev *dev = pci_dev_b(l); + pci_stop_bus_device(dev); + } +} + +/** + * pci_stop_bus_device - stop a PCI device and any children + * @dev: the device to stop + * + * Stop a PCI device (detach the driver, remove from the global list + * and so on). This also stop any subordinate buses and children in a + * depth-first manner. + */ +void pci_stop_bus_device(struct pci_dev *dev) +{ + if (dev->subordinate) + pci_stop_bus_devices(dev->subordinate); + + pci_stop_dev(dev); +} + EXPORT_SYMBOL(pci_remove_bus_device); EXPORT_SYMBOL(pci_remove_behind_bridge); +EXPORT_SYMBOL_GPL(pci_stop_bus_device); diff --git a/include/linux/pci.h b/include/linux/pci.h index 549d8410974b..5c3a4176eb64 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -441,6 +441,7 @@ extern struct pci_dev *pci_dev_get(struct pci_dev *dev); extern void pci_dev_put(struct pci_dev *dev); extern void pci_remove_bus(struct pci_bus *b); extern void pci_remove_bus_device(struct pci_dev *dev); +extern void pci_stop_bus_device(struct pci_dev *dev); void pci_setup_cardbus(struct pci_bus *bus); /* Generic PCI functions exported to card drivers */ -- cgit v1.2.3 From d48f1de2d8170814fb64effa320848410c466f95 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 20 Sep 2006 20:56:02 +0100 Subject: [MIPS] Remove EV96100 as previously announced. Signed-off-by: Ralf Baechle --- Documentation/feature-removal-schedule.txt | 8 - Documentation/kernel-parameters.txt | 2 - arch/mips/Kconfig | 24 - arch/mips/Makefile | 7 - arch/mips/configs/atlas_defconfig | 1 - arch/mips/configs/bigsur_defconfig | 1 - arch/mips/configs/capcella_defconfig | 1 - arch/mips/configs/cobalt_defconfig | 1 - arch/mips/configs/db1000_defconfig | 1 - arch/mips/configs/db1100_defconfig | 1 - arch/mips/configs/db1200_defconfig | 1 - arch/mips/configs/db1500_defconfig | 1 - arch/mips/configs/db1550_defconfig | 1 - arch/mips/configs/ddb5477_defconfig | 1 - arch/mips/configs/decstation_defconfig | 1 - arch/mips/configs/e55_defconfig | 1 - arch/mips/configs/emma2rh_defconfig | 1 - arch/mips/configs/ev64120_defconfig | 1 - arch/mips/configs/ev96100_defconfig | 850 --------------------------- arch/mips/configs/excite_defconfig | 1 - arch/mips/configs/ip22_defconfig | 1 - arch/mips/configs/ip27_defconfig | 1 - arch/mips/configs/ip32_defconfig | 1 - arch/mips/configs/it8172_defconfig | 1 - arch/mips/configs/ivr_defconfig | 1 - arch/mips/configs/jaguar-atx_defconfig | 1 - arch/mips/configs/jmr3927_defconfig | 1 - arch/mips/configs/lasat200_defconfig | 1 - arch/mips/configs/malta_defconfig | 1 - arch/mips/configs/mipssim_defconfig | 1 - arch/mips/configs/mpc30x_defconfig | 1 - arch/mips/configs/ocelot_3_defconfig | 1 - arch/mips/configs/ocelot_c_defconfig | 1 - arch/mips/configs/ocelot_defconfig | 1 - arch/mips/configs/ocelot_g_defconfig | 1 - arch/mips/configs/pb1100_defconfig | 1 - arch/mips/configs/pb1500_defconfig | 1 - arch/mips/configs/pb1550_defconfig | 1 - arch/mips/configs/pnx8550-jbs_defconfig | 1 - arch/mips/configs/pnx8550-v2pci_defconfig | 1 - arch/mips/configs/qemu_defconfig | 1 - arch/mips/configs/rbhma4500_defconfig | 1 - arch/mips/configs/rm200_defconfig | 1 - arch/mips/configs/sb1250-swarm_defconfig | 1 - arch/mips/configs/sead_defconfig | 1 - arch/mips/configs/tb0226_defconfig | 1 - arch/mips/configs/tb0229_defconfig | 1 - arch/mips/configs/tb0287_defconfig | 1 - arch/mips/configs/workpad_defconfig | 1 - arch/mips/configs/wrppmc_defconfig | 1 - arch/mips/configs/yosemite_defconfig | 1 - arch/mips/defconfig | 1 - arch/mips/galileo-boards/ev96100/Makefile | 9 - arch/mips/galileo-boards/ev96100/init.c | 173 ------ arch/mips/galileo-boards/ev96100/irq.c | 77 --- arch/mips/galileo-boards/ev96100/puts.c | 138 ----- arch/mips/galileo-boards/ev96100/reset.c | 70 --- arch/mips/galileo-boards/ev96100/setup.c | 159 ----- arch/mips/galileo-boards/ev96100/time.c | 88 --- arch/mips/pci/Makefile | 2 - arch/mips/pci/fixup-ev96100.c | 48 -- arch/mips/pci/ops-gt96100.c | 169 ------ arch/mips/pci/pci-ev96100.c | 63 -- include/asm-mips/bootinfo.h | 3 +- include/asm-mips/galileo-boards/gt96100.h | 427 -------------- include/asm-mips/mach-ev96100/mach-gt64120.h | 46 -- include/asm-mips/serial.h | 4 +- include/linux/pci_ids.h | 3 - 68 files changed, 3 insertions(+), 2414 deletions(-) delete mode 100644 arch/mips/configs/ev96100_defconfig delete mode 100644 arch/mips/galileo-boards/ev96100/Makefile delete mode 100644 arch/mips/galileo-boards/ev96100/init.c delete mode 100644 arch/mips/galileo-boards/ev96100/irq.c delete mode 100644 arch/mips/galileo-boards/ev96100/puts.c delete mode 100644 arch/mips/galileo-boards/ev96100/reset.c delete mode 100644 arch/mips/galileo-boards/ev96100/setup.c delete mode 100644 arch/mips/galileo-boards/ev96100/time.c delete mode 100644 arch/mips/pci/fixup-ev96100.c delete mode 100644 arch/mips/pci/ops-gt96100.c delete mode 100644 arch/mips/pci/pci-ev96100.c delete mode 100644 include/asm-mips/galileo-boards/gt96100.h delete mode 100644 include/asm-mips/mach-ev96100/mach-gt64120.h (limited to 'include/linux') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 611acc32fdf5..bf56b20652b0 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -217,14 +217,6 @@ Who: Nick Piggin --------------------------- -What: Support for the MIPS EV96100 evaluation board -When: September 2006 -Why: Does no longer build since at least November 15, 2003, apparently - no userbase left. -Who: Ralf Baechle - ---------------------------- - What: Support for the Momentum / PMC-Sierra Jaguar ATX evaluation board When: September 2006 Why: Does no longer build since quite some time, and was never popular, diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index c918cc3f65fb..255ec535bba8 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -573,8 +573,6 @@ running once the system is up. gscd= [HW,CD] Format: - gt96100eth= [NET] MIPS GT96100 Advanced Communication Controller - gus= [HW,OSS] Format: ,,, diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 235208d658ff..30750c54bdf5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -203,26 +203,6 @@ config MIPS_EV64120 . Say Y here if you wish to build a kernel for this platform. -config MIPS_EV96100 - bool "Galileo EV96100 Evaluation board (EXPERIMENTAL)" - depends on EXPERIMENTAL - select DMA_NONCOHERENT - select HW_HAS_PCI - select IRQ_CPU - select MIPS_GT96100 - select RM7000_CPU_SCACHE - select SWAP_IO_SPACE - select SYS_HAS_CPU_R5000 - select SYS_HAS_CPU_RM7000 - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL - select SYS_SUPPORTS_BIG_ENDIAN - help - This is an evaluation board based on the Galileo GT-96100 LAN/WAN - communications controllers containing a MIPS R5000 compatible core - running at 83MHz. Their website is . Say Y - here if you wish to build a kernel for this platform. - config MIPS_IVR bool "Globespan IVR board" select DMA_NONCOHERENT @@ -1069,10 +1049,6 @@ config AU1X00_USB_DEVICE depends on MIPS_PB1500 || MIPS_PB1100 || MIPS_PB1000 default n -config MIPS_GT96100 - bool - select MIPS_GT64120 - config IT8172_CIR bool depends on MIPS_ITE8172 || MIPS_IVR diff --git a/arch/mips/Makefile b/arch/mips/Makefile index f4227d24227d..e521826b4234 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -279,13 +279,6 @@ core-$(CONFIG_MIPS_EV64120) += arch/mips/gt64120/common/ cflags-$(CONFIG_MIPS_EV64120) += -Iinclude/asm-mips/mach-ev64120 load-$(CONFIG_MIPS_EV64120) += 0xffffffff80100000 -# -# Galileo EV96100 Board -# -core-$(CONFIG_MIPS_EV96100) += arch/mips/galileo-boards/ev96100/ -cflags-$(CONFIG_MIPS_EV96100) += -Iinclude/asm-mips/mach-ev96100 -load-$(CONFIG_MIPS_EV96100) += 0xffffffff80100000 - # # Wind River PPMC Board (4KC + GT64120) # diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig index 54274065e9a5..2774ba9606b7 100644 --- a/arch/mips/configs/atlas_defconfig +++ b/arch/mips/configs/atlas_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 887fd959482a..e12a475dcbf4 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig index a01344f3a4c2..bfade9abb767 100644 --- a/arch/mips/configs/capcella_defconfig +++ b/arch/mips/configs/capcella_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig index c95682445a28..78db2a8a711b 100644 --- a/arch/mips/configs/cobalt_defconfig +++ b/arch/mips/configs/cobalt_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y CONFIG_MIPS_COBALT=y # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig index c2f33d3af62c..93cca1585bc3 100644 --- a/arch/mips/configs/db1000_defconfig +++ b/arch/mips/configs/db1000_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS_DB1000=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig index 8c44d16ae9a2..ffd99252a837 100644 --- a/arch/mips/configs/db1100_defconfig +++ b/arch/mips/configs/db1100_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS_DB1100=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig index c13768e75ac5..63eac5e89b9c 100644 --- a/arch/mips/configs/db1200_defconfig +++ b/arch/mips/configs/db1200_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS_DB1200=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig index 8aea73fae7fb..25a095f7dc4e 100644 --- a/arch/mips/configs/db1500_defconfig +++ b/arch/mips/configs/db1500_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS_DB1500=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig index 90ccb7359630..dda469c842b3 100644 --- a/arch/mips/configs/db1550_defconfig +++ b/arch/mips/configs/db1550_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS_DB1550=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ddb5477_defconfig b/arch/mips/configs/ddb5477_defconfig index b598cf08f156..fcd3dd19bc74 100644 --- a/arch/mips/configs/ddb5477_defconfig +++ b/arch/mips/configs/ddb5477_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig index 597150b14077..8683e0df12e0 100644 --- a/arch/mips/configs/decstation_defconfig +++ b/arch/mips/configs/decstation_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set CONFIG_MACH_DECSTATION=y # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig index d9a0d0eb0683..4ace61c95778 100644 --- a/arch/mips/configs/e55_defconfig +++ b/arch/mips/configs/e55_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/emma2rh_defconfig b/arch/mips/configs/emma2rh_defconfig index 375b2ac24a49..5847c916c130 100644 --- a/arch/mips/configs/emma2rh_defconfig +++ b/arch/mips/configs/emma2rh_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ev64120_defconfig b/arch/mips/configs/ev64120_defconfig index b0afc118bd5c..bc4c4f125c48 100644 --- a/arch/mips/configs/ev64120_defconfig +++ b/arch/mips/configs/ev64120_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set CONFIG_MIPS_EV64120=y -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ev96100_defconfig b/arch/mips/configs/ev96100_defconfig deleted file mode 100644 index 0bdc10f11610..000000000000 --- a/arch/mips/configs/ev96100_defconfig +++ /dev/null @@ -1,850 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:04:05 2006 -# -CONFIG_MIPS=y - -# -# Machine selection -# -# CONFIG_MIPS_MTX1 is not set -# CONFIG_MIPS_BOSPORUS is not set -# CONFIG_MIPS_PB1000 is not set -# CONFIG_MIPS_PB1100 is not set -# CONFIG_MIPS_PB1500 is not set -# CONFIG_MIPS_PB1550 is not set -# CONFIG_MIPS_PB1200 is not set -# CONFIG_MIPS_DB1000 is not set -# CONFIG_MIPS_DB1100 is not set -# CONFIG_MIPS_DB1500 is not set -# CONFIG_MIPS_DB1550 is not set -# CONFIG_MIPS_DB1200 is not set -# CONFIG_MIPS_MIRAGE is not set -# CONFIG_BASLER_EXCITE is not set -# CONFIG_MIPS_COBALT is not set -# CONFIG_MACH_DECSTATION is not set -# CONFIG_MIPS_EV64120 is not set -CONFIG_MIPS_EV96100=y -# CONFIG_MIPS_IVR is not set -# CONFIG_MIPS_ITE8172 is not set -# CONFIG_MACH_JAZZ is not set -# CONFIG_LASAT is not set -# CONFIG_MIPS_ATLAS is not set -# CONFIG_MIPS_MALTA is not set -# CONFIG_MIPS_SEAD is not set -# CONFIG_WR_PPMC is not set -# CONFIG_MIPS_SIM is not set -# CONFIG_MOMENCO_JAGUAR_ATX is not set -# CONFIG_MOMENCO_OCELOT is not set -# CONFIG_MOMENCO_OCELOT_3 is not set -# CONFIG_MOMENCO_OCELOT_C is not set -# CONFIG_MOMENCO_OCELOT_G is not set -# CONFIG_MIPS_XXS1500 is not set -# CONFIG_PNX8550_V2PCI is not set -# CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5477 is not set -# CONFIG_MACH_VR41XX is not set -# CONFIG_PMC_YOSEMITE is not set -# CONFIG_QEMU is not set -# CONFIG_MARKEINS is not set -# CONFIG_SGI_IP22 is not set -# CONFIG_SGI_IP27 is not set -# CONFIG_SGI_IP32 is not set -# CONFIG_SIBYTE_BIGSUR is not set -# CONFIG_SIBYTE_SWARM is not set -# CONFIG_SIBYTE_SENTOSA is not set -# CONFIG_SIBYTE_RHONE is not set -# CONFIG_SIBYTE_CARMEL is not set -# CONFIG_SIBYTE_PTSWARM is not set -# CONFIG_SIBYTE_LITTLESUR is not set -# CONFIG_SIBYTE_CRHINE is not set -# CONFIG_SIBYTE_CRHONE is not set -# CONFIG_SNI_RM200_PCI is not set -# CONFIG_TOSHIBA_JMR3927 is not set -# CONFIG_TOSHIBA_RBTX4927 is not set -# CONFIG_TOSHIBA_RBTX4938 is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_GENERIC_FIND_NEXT_BIT=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -CONFIG_DMA_NONCOHERENT=y -CONFIG_DMA_NEED_PCI_MAP_STATE=y -CONFIG_CPU_BIG_ENDIAN=y -# CONFIG_CPU_LITTLE_ENDIAN is not set -CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y -CONFIG_IRQ_CPU=y -CONFIG_MIPS_GT64120=y -CONFIG_SWAP_IO_SPACE=y -CONFIG_MIPS_GT96100=y -CONFIG_MIPS_L1_CACHE_SHIFT=5 - -# -# CPU selection -# -# CONFIG_CPU_MIPS32_R1 is not set -# CONFIG_CPU_MIPS32_R2 is not set -# CONFIG_CPU_MIPS64_R1 is not set -# CONFIG_CPU_MIPS64_R2 is not set -# CONFIG_CPU_R3000 is not set -# CONFIG_CPU_TX39XX is not set -# CONFIG_CPU_VR41XX is not set -# CONFIG_CPU_R4300 is not set -# CONFIG_CPU_R4X00 is not set -# CONFIG_CPU_TX49XX is not set -# CONFIG_CPU_R5000 is not set -# CONFIG_CPU_R5432 is not set -# CONFIG_CPU_R6000 is not set -# CONFIG_CPU_NEVADA is not set -# CONFIG_CPU_R8000 is not set -# CONFIG_CPU_R10000 is not set -CONFIG_CPU_RM7000=y -# CONFIG_CPU_RM9000 is not set -# CONFIG_CPU_SB1 is not set -CONFIG_SYS_HAS_CPU_R5000=y -CONFIG_SYS_HAS_CPU_RM7000=y -CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y - -# -# Kernel type -# -CONFIG_32BIT=y -# CONFIG_64BIT is not set -CONFIG_PAGE_SIZE_4KB=y -# CONFIG_PAGE_SIZE_8KB is not set -# CONFIG_PAGE_SIZE_16KB is not set -# CONFIG_PAGE_SIZE_64KB is not set -CONFIG_BOARD_SCACHE=y -CONFIG_RM7000_CPU_SCACHE=y -CONFIG_CPU_HAS_PREFETCH=y -CONFIG_MIPS_MT_DISABLED=y -# CONFIG_MIPS_MT_SMTC is not set -# CONFIG_MIPS_MT_SMP is not set -# CONFIG_MIPS_VPE_LOADER is not set -# CONFIG_64BIT_PHYS_ADDR is not set -CONFIG_CPU_HAS_LLSC=y -CONFIG_CPU_HAS_SYNC=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_CPU_SUPPORTS_HIGHMEM=y -CONFIG_ARCH_FLATMEM_ENABLE=y -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -# CONFIG_SPARSEMEM_STATIC is not set -CONFIG_SPLIT_PTLOCK_CPUS=4 -# CONFIG_RESOURCES_64BIT is not set -# CONFIG_HZ_48 is not set -# CONFIG_HZ_100 is not set -# CONFIG_HZ_128 is not set -# CONFIG_HZ_250 is not set -# CONFIG_HZ_256 is not set -CONFIG_HZ_1000=y -# CONFIG_HZ_1024 is not set -CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -CONFIG_HZ=1000 -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# -CONFIG_LOCALVERSION="" -CONFIG_LOCALVERSION_AUTO=y -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -# CONFIG_POSIX_MQUEUE is not set -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set -CONFIG_RELAY=y -CONFIG_INITRAMFS_SOURCE="" -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_EXTRA_PASS is not set -# CONFIG_HOTPLUG is not set -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -CONFIG_BASE_FULL=y -CONFIG_RT_MUTEXES=y -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_SHMEM=y -CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_MODVERSIONS=y -CONFIG_MODULE_SRCVERSION_ALL=y -# CONFIG_KMOD is not set - -# -# Block layer -# -# CONFIG_LBD is not set -# CONFIG_BLK_DEV_IO_TRACE is not set -# CONFIG_LSF is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_DEFAULT_AS=y -# CONFIG_DEFAULT_DEADLINE is not set -# CONFIG_DEFAULT_CFQ is not set -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="anticipatory" - -# -# Bus options (PCI, PCMCIA, EISA, ISA, TC) -# -CONFIG_HW_HAS_PCI=y -# CONFIG_PCI is not set -CONFIG_MMU=y - -# -# PCCARD (PCMCIA/CardBus) support -# -# CONFIG_PCCARD is not set - -# -# PCI Hotplug Support -# - -# -# Executable file formats -# -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -CONFIG_TRAD_SIGNALS=y - -# -# Networking -# -CONFIG_NET=y - -# -# Networking options -# -# CONFIG_NETDEBUG is not set -# CONFIG_PACKET is not set -CONFIG_UNIX=y -CONFIG_XFRM=y -CONFIG_XFRM_USER=m -CONFIG_NET_KEY=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_FIB_HASH=y -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_XFRM_TUNNEL is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_INET_XFRM_MODE_TRANSPORT=m -CONFIG_INET_XFRM_MODE_TUNNEL=m -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y -# CONFIG_IPV6 is not set -# CONFIG_INET6_XFRM_TUNNEL is not set -# CONFIG_INET6_TUNNEL is not set -CONFIG_NETWORK_SECMARK=y -# CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# -# CONFIG_TIPC is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -CONFIG_IEEE80211=m -# CONFIG_IEEE80211_DEBUG is not set -CONFIG_IEEE80211_CRYPT_WEP=m -CONFIG_IEEE80211_CRYPT_CCMP=m -CONFIG_IEEE80211_SOFTMAC=m -# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set -CONFIG_WIRELESS_EXT=y - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set -# CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# -CONFIG_CONNECTOR=m - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Plug and Play support -# - -# -# Block devices -# -# CONFIG_BLK_DEV_COW_COMMON is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set -CONFIG_CDROM_PKTCDVD=m -CONFIG_CDROM_PKTCDVD_BUFFERS=8 -# CONFIG_CDROM_PKTCDVD_WCACHE is not set -CONFIG_ATA_OVER_ETH=m - -# -# ATA/ATAPI/MFM/RLL support -# -# CONFIG_IDE is not set - -# -# SCSI device support -# -CONFIG_RAID_ATTRS=m -# CONFIG_SCSI is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set - -# -# PHY device support -# -CONFIG_PHYLIB=m - -# -# MII PHY device drivers -# -CONFIG_MARVELL_PHY=m -CONFIG_DAVICOM_PHY=m -CONFIG_QSEMI_PHY=m -CONFIG_LXT_PHY=m -CONFIG_CICADA_PHY=m -CONFIG_VITESSE_PHY=m -CONFIG_SMSC_PHY=m - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_MII is not set -CONFIG_MIPS_GT96100ETH=y -# CONFIG_DM9000 is not set - -# -# Ethernet (1000 Mbit) -# - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Telephony Support -# -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_LIBPS2 is not set -CONFIG_SERIO_RAW=m -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -CONFIG_VT_HW_CONSOLE_BINDING=y -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=4 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# -# CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# SPI support -# -# CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# -# CONFIG_W1 is not set - -# -# Hardware Monitoring support -# -# CONFIG_HWMON is not set -# CONFIG_HWMON_VID is not set - -# -# Misc devices -# - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# Graphics support -# -# CONFIG_FIRMWARE_EDID is not set -# CONFIG_FB is not set - -# -# Console display driver support -# -# CONFIG_VGA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB_ARCH_HAS_HCD is not set -# CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USB_ARCH_HAS_EHCI is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_MMC is not set - -# -# LED devices -# -# CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# -# Real Time Clock -# -# CONFIG_RTC_CLASS is not set - -# -# DMA Engine support -# -# CONFIG_DMA_ENGINE is not set - -# -# DMA Clients -# - -# -# DMA Devices -# - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT2_FS_XIP is not set -# CONFIG_EXT3_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set -# CONFIG_XFS_FS is not set -# CONFIG_OCFS2_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_INOTIFY=y -CONFIG_INOTIFY_USER=y -# CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -CONFIG_FUSE_FS=m - -# -# CD-ROM/DVD Filesystems -# -# CONFIG_ISO9660_FS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_SYSFS=y -# CONFIG_TMPFS is not set -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y -# CONFIG_CONFIGFS_FS is not set - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set -# CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set -CONFIG_ROOT_NFS=y -CONFIG_LOCKD=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y -# CONFIG_RPCSEC_GSS_KRB5 is not set -# CONFIG_RPCSEC_GSS_SPKM3 is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_CIFS_DEBUG2 is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# -# CONFIG_NLS is not set - -# -# Profiling support -# -# CONFIG_PROFILING is not set - -# -# Kernel hacking -# -# CONFIG_PRINTK_TIME is not set -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_DEBUG_FS is not set -CONFIG_CROSSCOMPILE=y -CONFIG_CMDLINE="" - -# -# Security options -# -CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -CONFIG_CRYPTO=y -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m -CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_SHA256=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_DES=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_AES=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_ARC4=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_DEFLATE=m -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_CRC32C=m -# CONFIG_CRYPTO_TEST is not set - -# -# Hardware crypto devices -# - -# -# Library routines -# -# CONFIG_CRC_CCITT is not set -CONFIG_CRC16=m -CONFIG_CRC32=m -CONFIG_LIBCRC32C=m -CONFIG_ZLIB_INFLATE=m -CONFIG_ZLIB_DEFLATE=m -CONFIG_PLIST=y diff --git a/arch/mips/configs/excite_defconfig b/arch/mips/configs/excite_defconfig index 045ebd089893..eb87cbbfd037 100644 --- a/arch/mips/configs/excite_defconfig +++ b/arch/mips/configs/excite_defconfig @@ -26,7 +26,6 @@ CONFIG_BASLER_EXCITE=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index ef16d1fb5071..9f22d13e729d 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 4bf1ee7f5f00..414a649dff8a 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig index f83dc09c3ca9..dec2ba6ba03f 100644 --- a/arch/mips/configs/ip32_defconfig +++ b/arch/mips/configs/ip32_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/it8172_defconfig b/arch/mips/configs/it8172_defconfig index a91d72a9ca86..37f9dd7187b1 100644 --- a/arch/mips/configs/it8172_defconfig +++ b/arch/mips/configs/it8172_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set CONFIG_MIPS_ITE8172=y # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ivr_defconfig b/arch/mips/configs/ivr_defconfig index cebc67212d06..18874a4c24fe 100644 --- a/arch/mips/configs/ivr_defconfig +++ b/arch/mips/configs/ivr_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set CONFIG_MIPS_IVR=y # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig index 5d9eb11aba3d..9b529857f802 100644 --- a/arch/mips/configs/jaguar-atx_defconfig +++ b/arch/mips/configs/jaguar-atx_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig index be45a9044d06..fded3f73815f 100644 --- a/arch/mips/configs/jmr3927_defconfig +++ b/arch/mips/configs/jmr3927_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig index 64dc9f45a19c..0354bfa18b39 100644 --- a/arch/mips/configs/lasat200_defconfig +++ b/arch/mips/configs/lasat200_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 2690baf15a85..b21ca470273a 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig index c298979c18ae..adbeeadddb8f 100644 --- a/arch/mips/configs/mipssim_defconfig +++ b/arch/mips/configs/mipssim_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig index 4405d127a941..79fd544fcb2a 100644 --- a/arch/mips/configs/mpc30x_defconfig +++ b/arch/mips/configs/mpc30x_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig index ec5758f22676..4d87da2b99fd 100644 --- a/arch/mips/configs/ocelot_3_defconfig +++ b/arch/mips/configs/ocelot_3_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig index 0d33d87de1a1..ce7c26475328 100644 --- a/arch/mips/configs/ocelot_c_defconfig +++ b/arch/mips/configs/ocelot_c_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ocelot_defconfig b/arch/mips/configs/ocelot_defconfig index 4b999102715e..3da2a43d1608 100644 --- a/arch/mips/configs/ocelot_defconfig +++ b/arch/mips/configs/ocelot_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig index 827b344f6010..3a3e5ff4a3ef 100644 --- a/arch/mips/configs/ocelot_g_defconfig +++ b/arch/mips/configs/ocelot_g_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig index 9ed60fef69e0..1a16e92900cb 100644 --- a/arch/mips/configs/pb1100_defconfig +++ b/arch/mips/configs/pb1100_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS_PB1100=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig index 6774254b1be6..9ea8edea6f29 100644 --- a/arch/mips/configs/pb1500_defconfig +++ b/arch/mips/configs/pb1500_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS_PB1500=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig index 1afe5bf6e765..c4a158976f8f 100644 --- a/arch/mips/configs/pb1550_defconfig +++ b/arch/mips/configs/pb1550_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS_PB1550=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index ac616c82d348..1cbf270c301c 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig index a8eb51bae3f3..bec30b15b9bd 100644 --- a/arch/mips/configs/pnx8550-v2pci_defconfig +++ b/arch/mips/configs/pnx8550-v2pci_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/qemu_defconfig b/arch/mips/configs/qemu_defconfig index 6a63a113b7ea..daa40c8ff694 100644 --- a/arch/mips/configs/qemu_defconfig +++ b/arch/mips/configs/qemu_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig index 6779f449bd2d..2f5650227ba3 100644 --- a/arch/mips/configs/rbhma4500_defconfig +++ b/arch/mips/configs/rbhma4500_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index b7826d3a2b77..f26b338333ac 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig index 625c1c619b6b..9041f095f96f 100644 --- a/arch/mips/configs/sb1250-swarm_defconfig +++ b/arch/mips/configs/sb1250-swarm_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/sead_defconfig b/arch/mips/configs/sead_defconfig index 4401b602118f..02abb2f1bfaf 100644 --- a/arch/mips/configs/sead_defconfig +++ b/arch/mips/configs/sead_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig index 2ba4e25e8c34..ca3d0c4ba15b 100644 --- a/arch/mips/configs/tb0226_defconfig +++ b/arch/mips/configs/tb0226_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig index fc8a407c1add..4e2009ace278 100644 --- a/arch/mips/configs/tb0229_defconfig +++ b/arch/mips/configs/tb0229_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig index effcb63b81a3..535a813d01a9 100644 --- a/arch/mips/configs/tb0287_defconfig +++ b/arch/mips/configs/tb0287_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig index 8f66ad71cb7e..3a3ef20b21cc 100644 --- a/arch/mips/configs/workpad_defconfig +++ b/arch/mips/configs/workpad_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig index 3e4b16b39827..e6b1dea55842 100644 --- a/arch/mips/configs/wrppmc_defconfig +++ b/arch/mips/configs/wrppmc_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig index 3a68d8a25b66..06a072b77b1c 100644 --- a/arch/mips/configs/yosemite_defconfig +++ b/arch/mips/configs/yosemite_defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/defconfig b/arch/mips/defconfig index fff6fcc96212..d620c463a78b 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -25,7 +25,6 @@ CONFIG_MIPS=y # CONFIG_MIPS_COBALT is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MACH_JAZZ is not set diff --git a/arch/mips/galileo-boards/ev96100/Makefile b/arch/mips/galileo-boards/ev96100/Makefile deleted file mode 100644 index cd868ec78cbc..000000000000 --- a/arch/mips/galileo-boards/ev96100/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Copyright 2000 MontaVista Software Inc. -# Author: MontaVista Software, Inc. -# ppopov@mvista.com or source@mvista.com -# -# Makefile for the Galileo EV96100 board. -# - -obj-y += init.o irq.o puts.o reset.o time.o setup.o diff --git a/arch/mips/galileo-boards/ev96100/init.c b/arch/mips/galileo-boards/ev96100/init.c deleted file mode 100644 index a01fe9b36f2c..000000000000 --- a/arch/mips/galileo-boards/ev96100/init.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This file was derived from Carsten Langgaard's - * arch/mips/mips-boards/generic/generic.c - * - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -/* Environment variable */ - -typedef struct { - char *name; - char *val; -} t_env_var; - -int prom_argc; -char **prom_argv, **prom_envp; - -int init_debug = 0; - -char * __init prom_getcmdline(void) -{ - return &(arcs_cmdline[0]); -} - -unsigned long __init prom_free_prom_memory(void) -{ - return 0; -} - -void __init prom_init_cmdline(void) -{ - char *cp; - int actr; - - actr = 1; /* Always ignore argv[0] */ - - cp = &(arcs_cmdline[0]); - while(actr < prom_argc) { - strcpy(cp, prom_argv[actr]); - cp += strlen(prom_argv[actr]); - *cp++ = ' '; - actr++; - } - if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ - --cp; - *cp = '\0'; -} - -char *prom_getenv(char *envname) -{ - /* - * Return a pointer to the given environment variable. - */ - - t_env_var *env = (t_env_var *) prom_envp; - int i; - - i = strlen(envname); - - while (env->name) { - if (strncmp(envname, env->name, i) == 0) { - return (env->val); - } - env++; - } - return (NULL); -} - -static inline unsigned char str2hexnum(unsigned char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - return 0; /* foo */ -} - -static inline void str2eaddr(unsigned char *ea, unsigned char *str) -{ - int i; - - for (i = 0; i < 6; i++) { - unsigned char num; - - if ((*str == '.') || (*str == ':')) - str++; - num = str2hexnum(*str++) << 4; - num |= (str2hexnum(*str++)); - ea[i] = num; - } -} - -int get_ethernet_addr(char *ethernet_addr) -{ - char *ethaddr_str; - - ethaddr_str = prom_getenv("ethaddr"); - if (!ethaddr_str) { - printk("ethaddr not set in boot prom\n"); - return -1; - } - str2eaddr(ethernet_addr, ethaddr_str); - - if (init_debug > 1) { - int i; - printk("get_ethernet_addr: "); - for (i = 0; i < 5; i++) - printk("%02x:", - (unsigned char) *(ethernet_addr + i)); - printk("%02x\n", *(ethernet_addr + i)); - } - - return 0; -} - -const char *get_system_type(void) -{ - return "Galileo EV96100"; -} - -void __init prom_init(void) -{ - volatile unsigned char *uart; - char ppbuf[8]; - - prom_argc = fw_arg0; - prom_argv = (char **) fw_arg1; - prom_envp = (char **) fw_arg2; - - mips_machgroup = MACH_GROUP_GALILEO; - mips_machtype = MACH_EV96100; - - prom_init_cmdline(); - - /* 32 MB upgradable */ - add_memory_region(0, 32 << 20, BOOT_MEM_RAM); -} diff --git a/arch/mips/galileo-boards/ev96100/irq.c b/arch/mips/galileo-boards/ev96100/irq.c deleted file mode 100644 index ee5d6720f23b..000000000000 --- a/arch/mips/galileo-boards/ev96100/irq.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This file was derived from Carsten Langgaard's - * arch/mips/mips-boards/atlas/atlas_int.c. - * - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static inline unsigned int ffz8(unsigned int word) -{ - unsigned long k; - - k = 7; - if (word & 0x0fUL) { k -= 4; word <<= 4; } - if (word & 0x30UL) { k -= 2; word <<= 2; } - if (word & 0x40UL) { k -= 1; } - - return k; -} - -extern void mips_timer_interrupt(struct pt_regs *regs); - -asmlinkage void ev96100_cpu_irq(unsigned int pending, struct pt_regs *regs) -{ - do_IRQ(ffz8(pending >> 8), regs); -} - -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) -{ - unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; - - if (pending & CAUSEF_IP7) - mips_timer_interrupt(regs); - else if (pending) - ev96100_cpu_irq(pending, regs); - else - spurious_interrupt(regs); -} - -void __init arch_init_irq(void) -{ - mips_cpu_irq_init(0); -} diff --git a/arch/mips/galileo-boards/ev96100/puts.c b/arch/mips/galileo-boards/ev96100/puts.c deleted file mode 100644 index 49dc6d137b9c..000000000000 --- a/arch/mips/galileo-boards/ev96100/puts.c +++ /dev/null @@ -1,138 +0,0 @@ - -/* - * Debug routines which directly access the uart. - */ - -#include -#include - - -//#define SERIAL_BASE EV96100_UART0_REGS_BASE -#define SERIAL_BASE 0xBD000020 -#define NS16550_BASE SERIAL_BASE - -#define SERA_CMD 0x0D -#define SERA_DATA 0x08 -//#define SERB_CMD 0x05 -#define SERB_CMD 20 -#define SERB_DATA 0x00 -#define TX_BUSY 0x20 - -#define TIMEOUT 0xffff -#undef SLOW_DOWN - -static const char digits[16] = "0123456789abcdef"; -static volatile unsigned char *const com1 = (unsigned char *) SERIAL_BASE; - - -#ifdef SLOW_DOWN -static inline void slow_down() -{ - int k; - for (k = 0; k < 10000; k++); -} -#else -#define slow_down() -#endif - -void putch(const unsigned char c) -{ - unsigned char ch; - int i = 0; - - do { - ch = com1[SERB_CMD]; - slow_down(); - i++; - if (i > TIMEOUT) { - break; - } - } while (0 == (ch & TX_BUSY)); - com1[SERB_DATA] = c; -} - -void putchar(const unsigned char c) -{ - unsigned char ch; - int i = 0; - - do { - ch = com1[SERB_CMD]; - slow_down(); - i++; - if (i > TIMEOUT) { - break; - } - } while (0 == (ch & TX_BUSY)); - com1[SERB_DATA] = c; -} - -void puts(unsigned char *cp) -{ - unsigned char ch; - int i = 0; - - while (*cp) { - do { - ch = com1[SERB_CMD]; - slow_down(); - i++; - if (i > TIMEOUT) { - break; - } - } while (0 == (ch & TX_BUSY)); - com1[SERB_DATA] = *cp++; - } - putch('\r'); - putch('\n'); -} - -void fputs(unsigned char *cp) -{ - unsigned char ch; - int i = 0; - - while (*cp) { - - do { - ch = com1[SERB_CMD]; - slow_down(); - i++; - if (i > TIMEOUT) { - break; - } - } while (0 == (ch & TX_BUSY)); - com1[SERB_DATA] = *cp++; - } -} - - -void put64(uint64_t ul) -{ - int cnt; - unsigned ch; - - cnt = 16; /* 16 nibbles in a 64 bit long */ - putch('0'); - putch('x'); - do { - cnt--; - ch = (unsigned char) (ul >> cnt * 4) & 0x0F; - putch(digits[ch]); - } while (cnt > 0); -} - -void put32(unsigned u) -{ - int cnt; - unsigned ch; - - cnt = 8; /* 8 nibbles in a 32 bit long */ - putch('0'); - putch('x'); - do { - cnt--; - ch = (unsigned char) (u >> cnt * 4) & 0x0F; - putch(digits[ch]); - } while (cnt > 0); -} diff --git a/arch/mips/galileo-boards/ev96100/reset.c b/arch/mips/galileo-boards/ev96100/reset.c deleted file mode 100644 index 5ef9b7f896e6..000000000000 --- a/arch/mips/galileo-boards/ev96100/reset.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * Galileo EV96100 reset routines. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This file was derived from Carsten Langgaard's - * arch/mips/mips-boards/generic/reset.c - * - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -static void mips_machine_restart(char *command); -static void mips_machine_halt(void); - -static void mips_machine_restart(char *command) -{ - set_c0_status(ST0_BEV | ST0_ERL); - change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); - flush_cache_all(); - write_c0_wired(0); - __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); - while (1); -} - -static void mips_machine_halt(void) -{ - printk(KERN_NOTICE "You can safely turn off the power\n"); - while (1) - __asm__(".set\tmips3\n\t" - "wait\n\t" - ".set\tmips0"); -} - -void mips_reboot_setup(void) -{ - _machine_restart = mips_machine_restart; - _machine_halt = mips_machine_halt; -} diff --git a/arch/mips/galileo-boards/ev96100/setup.c b/arch/mips/galileo-boards/ev96100/setup.c deleted file mode 100644 index 639ad5562c63..000000000000 --- a/arch/mips/galileo-boards/ev96100/setup.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * Galileo EV96100 setup. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This file was derived from Carsten Langgaard's - * arch/mips/mips-boards/atlas/atlas_setup.c. - * - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -extern char *__init prom_getcmdline(void); - -extern void mips_reboot_setup(void); - -unsigned char mac_0_1[12]; - -void __init plat_mem_setup(void) -{ - unsigned int config = read_c0_config(); - unsigned int status = read_c0_status(); - unsigned int info = read_c0_info(); - u32 tmp; - - char *argptr; - - clear_c0_status(ST0_FR); - - if (config & 0x8) - printk("Secondary cache is enabled\n"); - else - printk("Secondary cache is disabled\n"); - - if (status & (1 << 27)) - printk("User-mode cache ops enabled\n"); - else - printk("User-mode cache ops disabled\n"); - - printk("CP0 info reg: %x\n", (unsigned) info); - if (info & (1 << 28)) - printk("burst mode Scache RAMS\n"); - else - printk("pipelined Scache RAMS\n"); - - if (info & 0x1) - printk("Atomic Enable is set\n"); - - argptr = prom_getcmdline(); -#ifdef CONFIG_SERIAL_CONSOLE - if (strstr(argptr, "console=") == NULL) { - argptr = prom_getcmdline(); - strcat(argptr, " console=ttyS0,115200"); - } -#endif - - mips_reboot_setup(); - - set_io_port_base(KSEG1); - ioport_resource.start = GT_PCI_IO_BASE; - ioport_resource.end = GT_PCI_IO_BASE + 0x01ffffff; - -#ifdef CONFIG_BLK_DEV_INITRD - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); -#endif - - - /* - * Setup GT controller master bit so we can do config cycles - */ - - /* Clear cause register bits */ - GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | - GT_INTRCAUSE_TARABORT0_BIT)); - /* Setup address */ - GT_WRITE(GT_PCI0_CFGADDR_OFS, - (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | - (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | - ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | - GT_PCI0_CFGADDR_CONFIGEN_BIT); - - udelay(2); - tmp = GT_READ(GT_PCI0_CFGDATA_OFS); - - tmp |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_SERR); - GT_WRITE(GT_PCI0_CFGADDR_OFS, - (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | - (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | - ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | - GT_PCI0_CFGADDR_CONFIGEN_BIT); - udelay(2); - GT_WRITE(GT_PCI0_CFGDATA_OFS, tmp); - - /* Setup address */ - GT_WRITE(GT_PCI0_CFGADDR_OFS, - (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | - (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | - ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | - GT_PCI0_CFGADDR_CONFIGEN_BIT); - - udelay(2); - tmp = GT_READ(GT_PCI0_CFGDATA_OFS); -} - -unsigned short get_gt_devid(void) -{ - u32 gt_devid; - - /* Figure out if this is a gt96100 or gt96100A */ - GT_WRITE(GT_PCI0_CFGADDR_OFS, - (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | - (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | - ((PCI_VENDOR_ID / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | - GT_PCI0_CFGADDR_CONFIGEN_BIT); - - udelay(4); - gt_devid = GT_READ(GT_PCI0_CFGDATA_OFS); - - return gt_devid >> 16; -} diff --git a/arch/mips/galileo-boards/ev96100/time.c b/arch/mips/galileo-boards/ev96100/time.c deleted file mode 100644 index 8cbe8426491a..000000000000 --- a/arch/mips/galileo-boards/ev96100/time.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * Galileo EV96100 rtc routines. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This file was derived from Carsten Langgaard's - * arch/mips/mips-boards/atlas/atlas_rtc.c. - * - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) - -extern volatile unsigned long wall_jiffies; -unsigned long missed_heart_beats = 0; - -static unsigned long r4k_offset; /* Amount to increment compare reg each time */ -static unsigned long r4k_cur; /* What counter should be at next timer irq */ - -static inline void ack_r4ktimer(unsigned long newval) -{ - write_c0_compare(newval); -} - -/* - * There are a lot of conceptually broken versions of the MIPS timer interrupt - * handler floating around. This one is rather different, but the algorithm - * is probably more robust. - */ -void mips_timer_interrupt(struct pt_regs *regs) -{ - int irq = 7; /* FIX ME */ - - if (r4k_offset == 0) { - goto null; - } - - do { - kstat_this_cpu.irqs[irq]++; - do_timer(regs); -#ifndef CONFIG_SMP - update_process_times(user_mode(regs)); -#endif - r4k_cur += r4k_offset; - ack_r4ktimer(r4k_cur); - - } while (((unsigned long)read_c0_count() - - r4k_cur) < 0x7fffffff); - return; - -null: - ack_r4ktimer(0); -} diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 368d3d896165..edefa97b2330 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_ITE_BOARD_GEN) += ops-it8172.o obj-$(CONFIG_MIPS_BONITO64) += ops-bonito64.o obj-$(CONFIG_MIPS_GT64111) += ops-gt64111.o obj-$(CONFIG_MIPS_GT64120) += ops-gt64120.o -obj-$(CONFIG_MIPS_GT96100) += ops-gt96100.o obj-$(CONFIG_PCI_MARVELL) += ops-marvell.o obj-$(CONFIG_MIPS_MSC) += ops-msc.o obj-$(CONFIG_MIPS_NILE4) += ops-nile4.o @@ -29,7 +28,6 @@ obj-$(CONFIG_LASAT) += pci-lasat.o obj-$(CONFIG_MIPS_ATLAS) += fixup-atlas.o obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o obj-$(CONFIG_MIPS_EV64120) += fixup-ev64120.o -obj-$(CONFIG_MIPS_EV96100) += fixup-ev96100.o pci-ev96100.o obj-$(CONFIG_MIPS_ITE8172) += fixup-ite8172g.o obj-$(CONFIG_MIPS_IVR) += fixup-ivr.o obj-$(CONFIG_SOC_AU1500) += fixup-au1000.o ops-au1000.o diff --git a/arch/mips/pci/fixup-ev96100.c b/arch/mips/pci/fixup-ev96100.c deleted file mode 100644 index e2bc977b6d58..000000000000 --- a/arch/mips/pci/fixup-ev96100.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * EV96100 Board specific pci fixups. - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include - -static char irq_tab_ev96100[][5] __initdata = { - [8] = { 0, 5, 5, 5, 5 }, - [9] = { 0, 2, 2, 2, 2 } -}; - -int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - return irq_tab_ev96100[slot][pin]; -} - -/* Do platform specific device initialization at pci_enable_device() time */ -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - return 0; -} diff --git a/arch/mips/pci/ops-gt96100.c b/arch/mips/pci/ops-gt96100.c deleted file mode 100644 index 9e4ea6627e21..000000000000 --- a/arch/mips/pci/ops-gt96100.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * Galileo EV96100 board specific pci support. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This file was derived from Carsten Langgaard's - * arch/mips/mips-boards/generic/pci.c - * - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include - -#include -#include -#include - -#define PCI_ACCESS_READ 0 -#define PCI_ACCESS_WRITE 1 - -static int static gt96100_config_access(unsigned char access_type, - struct pci_bus *bus, unsigned int devfn, int where, u32 * data) -{ - unsigned char bus = bus->number; - u32 intr; - - /* - * Because of a bug in the galileo (for slot 31). - */ - if (bus == 0 && devfn >= PCI_DEVFN(31, 0)) - return PCIBIOS_DEVICE_NOT_FOUND; - - /* Clear cause register bits */ - GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | - GT_INTRCAUSE_TARABORT0_BIT)); - - /* Setup address */ - GT_WRITE(GT_PCI0_CFGADDR_OFS, - (bus << GT_PCI0_CFGADDR_BUSNUM_SHF) | - (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | - ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | - GT_PCI0_CFGADDR_CONFIGEN_BIT); - udelay(2); - - - if (access_type == PCI_ACCESS_WRITE) { - if (devfn != 0) - *data = le32_to_cpu(*data); - GT_WRITE(GT_PCI0_CFGDATA_OFS, *data); - } else { - *data = GT_READ(GT_PCI0_CFGDATA_OFS); - if (devfn != 0) - *data = le32_to_cpu(*data); - } - - udelay(2); - - /* Check for master or target abort */ - intr = GT_READ(GT_INTRCAUSE_OFS); - - if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) { - /* Error occured */ - - /* Clear bits */ - GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | - GT_INTRCAUSE_TARABORT0_BIT)); - return -1; - } - return 0; -} - -/* - * We can't address 8 and 16 bit words directly. Instead we have to - * read/write a 32bit word and mask/modify the data we actually want. - */ -static int gt96100_pcibios_read(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 * val) -{ - u32 data = 0; - - if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) - return PCIBIOS_DEVICE_NOT_FOUND; - - switch (size) { - case 1: - *val = (data >> ((where & 3) << 3)) & 0xff; - break; - - case 2: - *val = (data >> ((where & 3) << 3)) & 0xffff; - break; - - case 4: - *val = data; - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int gt96100_pcibios_write(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - u32 data = 0; - - switch (size) { - case 1: - if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) - return -1; - - data = (data & ~(0xff << ((where & 3) << 3))) | - (val << ((where & 3) << 3)); - - if (gt96100_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) - return -1; - - return PCIBIOS_SUCCESSFUL; - - case 2: - if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) - return -1; - - data = (data & ~(0xffff << ((where & 3) << 3))) | - (val << ((where & 3) << 3)); - - if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &data)) - return -1; - - - return PCIBIOS_SUCCESSFUL; - - case 4: - if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &val)) - return -1; - - return PCIBIOS_SUCCESSFUL; - } -} - -struct pci_ops gt96100_pci_ops = { - .read = gt96100_pcibios_read, - .write = gt96100_pcibios_write -}; diff --git a/arch/mips/pci/pci-ev96100.c b/arch/mips/pci/pci-ev96100.c deleted file mode 100644 index f9457ea00def..000000000000 --- a/arch/mips/pci/pci-ev96100.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include - -static struct resource pci_io_resource = { - .name = "io pci IO space", - .start = 0x10000000, - .end = 0x11ffffff, - .flags = IORESOURCE_IO -}; - -static struct resource pci_mem_resource = { - .name = "ext pci memory space", - .start = 0x12000000, - .end = 0x13ffffff, - .flags = IORESOURCE_MEM -}; - -extern struct pci_ops gt96100_pci_ops; - -struct pci_controller ev96100_controller = { - .pci_ops = >96100_pci_ops, - .io_resource = &pci_io_resource, - .mem_resource = &pci_mem_resource, -}; - -static void ev96100_pci_init(void) -{ - register_pci_controller(&ev96100_controller); -} - -arch_initcall(ev96100_pci_init); diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index 3b745e76f429..78c35ec46362 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -112,8 +112,7 @@ * Valid machtype for group GALILEO */ #define MACH_GROUP_GALILEO 11 /* Galileo Eval Boards */ -#define MACH_EV96100 0 /* EV96100 */ -#define MACH_EV64120A 1 /* EV64120A */ +#define MACH_EV64120A 0 /* EV64120A */ /* * Valid machtype for group MOMENCO diff --git a/include/asm-mips/galileo-boards/gt96100.h b/include/asm-mips/galileo-boards/gt96100.h deleted file mode 100644 index aabd1b629c19..000000000000 --- a/include/asm-mips/galileo-boards/gt96100.h +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * stevel@mvista.com or source@mvista.com - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Register offsets of the MIPS GT96100 Advanced Communication Controller. - */ -#ifndef _GT96100_H -#define _GT96100_H - -/* - * Galileo GT96100 internal register base. - */ -#define MIPS_GT96100_BASE (KSEG1ADDR(0x14000000)) - -#define GT96100_WRITE(ofs, data) \ - *(volatile u32 *)(MIPS_GT96100_BASE+ofs) = cpu_to_le32(data) -#define GT96100_READ(ofs) \ - le32_to_cpu(*(volatile u32 *)(MIPS_GT96100_BASE+ofs)) - -#define GT96100_ETH_IO_SIZE 0x4000 - -/************************************************************************ - * Register offset addresses follow - ************************************************************************/ - -/* CPU Interface Control Registers */ -#define GT96100_CPU_INTERF_CONFIG 0x000000 - -/* Ethernet Ports */ -#define GT96100_ETH_PHY_ADDR_REG 0x080800 -#define GT96100_ETH_SMI_REG 0x080810 -/* - These are offsets to port 0 registers. Add GT96100_ETH_IO_SIZE to - get offsets to port 1 registers. -*/ -#define GT96100_ETH_PORT_CONFIG 0x084800 -#define GT96100_ETH_PORT_CONFIG_EXT 0x084808 -#define GT96100_ETH_PORT_COMM 0x084810 -#define GT96100_ETH_PORT_STATUS 0x084818 -#define GT96100_ETH_SER_PARAM 0x084820 -#define GT96100_ETH_HASH_TBL_PTR 0x084828 -#define GT96100_ETH_FLOW_CNTRL_SRC_ADDR_L 0x084830 -#define GT96100_ETH_FLOW_CNTRL_SRC_ADDR_H 0x084838 -#define GT96100_ETH_SDMA_CONFIG 0x084840 -#define GT96100_ETH_SDMA_COMM 0x084848 -#define GT96100_ETH_INT_CAUSE 0x084850 -#define GT96100_ETH_INT_MASK 0x084858 -#define GT96100_ETH_1ST_RX_DESC_PTR0 0x084880 -#define GT96100_ETH_1ST_RX_DESC_PTR1 0x084884 -#define GT96100_ETH_1ST_RX_DESC_PTR2 0x084888 -#define GT96100_ETH_1ST_RX_DESC_PTR3 0x08488C -#define GT96100_ETH_CURR_RX_DESC_PTR0 0x0848A0 -#define GT96100_ETH_CURR_RX_DESC_PTR1 0x0848A4 -#define GT96100_ETH_CURR_RX_DESC_PTR2 0x0848A8 -#define GT96100_ETH_CURR_RX_DESC_PTR3 0x0848AC -#define GT96100_ETH_CURR_TX_DESC_PTR0 0x0848E0 -#define GT96100_ETH_CURR_TX_DESC_PTR1 0x0848E4 -#define GT96100_ETH_MIB_COUNT_BASE 0x085800 - -/* SDMAs */ -#define GT96100_SDMA_GROUP_CONFIG 0x101AF0 -/* SDMA Group 0 */ -#define GT96100_SDMA_G0_CHAN0_CONFIG 0x000900 -#define GT96100_SDMA_G0_CHAN0_COMM 0x000908 -#define GT96100_SDMA_G0_CHAN0_RX_DESC_BASE 0x008900 -#define GT96100_SDMA_G0_CHAN0_CURR_RX_DESC_PTR 0x008910 -#define GT96100_SDMA_G0_CHAN0_TX_DESC_BASE 0x00C900 -#define GT96100_SDMA_G0_CHAN0_CURR_TX_DESC_PTR 0x00C910 -#define GT96100_SDMA_G0_CHAN0_1ST_TX_DESC_PTR 0x00C914 -#define GT96100_SDMA_G0_CHAN1_CONFIG 0x010900 -#define GT96100_SDMA_G0_CHAN1_COMM 0x010908 -#define GT96100_SDMA_G0_CHAN1_RX_DESC_BASE 0x018900 -#define GT96100_SDMA_G0_CHAN1_CURR_RX_DESC_PTR 0x018910 -#define GT96100_SDMA_G0_CHAN1_TX_DESC_BASE 0x01C900 -#define GT96100_SDMA_G0_CHAN1_CURR_TX_DESC_PTR 0x01C910 -#define GT96100_SDMA_G0_CHAN1_1ST_TX_DESC_PTR 0x01C914 -#define GT96100_SDMA_G0_CHAN2_CONFIG 0x020900 -#define GT96100_SDMA_G0_CHAN2_COMM 0x020908 -#define GT96100_SDMA_G0_CHAN2_RX_DESC_BASE 0x028900 -#define GT96100_SDMA_G0_CHAN2_CURR_RX_DESC_PTR 0x028910 -#define GT96100_SDMA_G0_CHAN2_TX_DESC_BASE 0x02C900 -#define GT96100_SDMA_G0_CHAN2_CURR_TX_DESC_PTR 0x02C910 -#define GT96100_SDMA_G0_CHAN2_1ST_TX_DESC_PTR 0x02C914 -#define GT96100_SDMA_G0_CHAN3_CONFIG 0x030900 -#define GT96100_SDMA_G0_CHAN3_COMM 0x030908 -#define GT96100_SDMA_G0_CHAN3_RX_DESC_BASE 0x038900 -#define GT96100_SDMA_G0_CHAN3_CURR_RX_DESC_PTR 0x038910 -#define GT96100_SDMA_G0_CHAN3_TX_DESC_BASE 0x03C900 -#define GT96100_SDMA_G0_CHAN3_CURR_TX_DESC_PTR 0x03C910 -#define GT96100_SDMA_G0_CHAN3_1ST_TX_DESC_PTR 0x03C914 -#define GT96100_SDMA_G0_CHAN4_CONFIG 0x040900 -#define GT96100_SDMA_G0_CHAN4_COMM 0x040908 -#define GT96100_SDMA_G0_CHAN4_RX_DESC_BASE 0x048900 -#define GT96100_SDMA_G0_CHAN4_CURR_RX_DESC_PTR 0x048910 -#define GT96100_SDMA_G0_CHAN4_TX_DESC_BASE 0x04C900 -#define GT96100_SDMA_G0_CHAN4_CURR_TX_DESC_PTR 0x04C910 -#define GT96100_SDMA_G0_CHAN4_1ST_TX_DESC_PTR 0x04C914 -#define GT96100_SDMA_G0_CHAN5_CONFIG 0x050900 -#define GT96100_SDMA_G0_CHAN5_COMM 0x050908 -#define GT96100_SDMA_G0_CHAN5_RX_DESC_BASE 0x058900 -#define GT96100_SDMA_G0_CHAN5_CURR_RX_DESC_PTR 0x058910 -#define GT96100_SDMA_G0_CHAN5_TX_DESC_BASE 0x05C900 -#define GT96100_SDMA_G0_CHAN5_CURR_TX_DESC_PTR 0x05C910 -#define GT96100_SDMA_G0_CHAN5_1ST_TX_DESC_PTR 0x05C914 -#define GT96100_SDMA_G0_CHAN6_CONFIG 0x060900 -#define GT96100_SDMA_G0_CHAN6_COMM 0x060908 -#define GT96100_SDMA_G0_CHAN6_RX_DESC_BASE 0x068900 -#define GT96100_SDMA_G0_CHAN6_CURR_RX_DESC_PTR 0x068910 -#define GT96100_SDMA_G0_CHAN6_TX_DESC_BASE 0x06C900 -#define GT96100_SDMA_G0_CHAN6_CURR_TX_DESC_PTR 0x06C910 -#define GT96100_SDMA_G0_CHAN6_1ST_TX_DESC_PTR 0x06C914 -#define GT96100_SDMA_G0_CHAN7_CONFIG 0x070900 -#define GT96100_SDMA_G0_CHAN7_COMM 0x070908 -#define GT96100_SDMA_G0_CHAN7_RX_DESC_BASE 0x078900 -#define GT96100_SDMA_G0_CHAN7_CURR_RX_DESC_PTR 0x078910 -#define GT96100_SDMA_G0_CHAN7_TX_DESC_BASE 0x07C900 -#define GT96100_SDMA_G0_CHAN7_CURR_TX_DESC_PTR 0x07C910 -#define GT96100_SDMA_G0_CHAN7_1ST_TX_DESC_PTR 0x07C914 -/* SDMA Group 1 */ -#define GT96100_SDMA_G1_CHAN0_CONFIG 0x100900 -#define GT96100_SDMA_G1_CHAN0_COMM 0x100908 -#define GT96100_SDMA_G1_CHAN0_RX_DESC_BASE 0x108900 -#define GT96100_SDMA_G1_CHAN0_CURR_RX_DESC_PTR 0x108910 -#define GT96100_SDMA_G1_CHAN0_TX_DESC_BASE 0x10C900 -#define GT96100_SDMA_G1_CHAN0_CURR_TX_DESC_PTR 0x10C910 -#define GT96100_SDMA_G1_CHAN0_1ST_TX_DESC_PTR 0x10C914 -#define GT96100_SDMA_G1_CHAN1_CONFIG 0x110900 -#define GT96100_SDMA_G1_CHAN1_COMM 0x110908 -#define GT96100_SDMA_G1_CHAN1_RX_DESC_BASE 0x118900 -#define GT96100_SDMA_G1_CHAN1_CURR_RX_DESC_PTR 0x118910 -#define GT96100_SDMA_G1_CHAN1_TX_DESC_BASE 0x11C900 -#define GT96100_SDMA_G1_CHAN1_CURR_TX_DESC_PTR 0x11C910 -#define GT96100_SDMA_G1_CHAN1_1ST_TX_DESC_PTR 0x11C914 -#define GT96100_SDMA_G1_CHAN2_CONFIG 0x120900 -#define GT96100_SDMA_G1_CHAN2_COMM 0x120908 -#define GT96100_SDMA_G1_CHAN2_RX_DESC_BASE 0x128900 -#define GT96100_SDMA_G1_CHAN2_CURR_RX_DESC_PTR 0x128910 -#define GT96100_SDMA_G1_CHAN2_TX_DESC_BASE 0x12C900 -#define GT96100_SDMA_G1_CHAN2_CURR_TX_DESC_PTR 0x12C910 -#define GT96100_SDMA_G1_CHAN2_1ST_TX_DESC_PTR 0x12C914 -#define GT96100_SDMA_G1_CHAN3_CONFIG 0x130900 -#define GT96100_SDMA_G1_CHAN3_COMM 0x130908 -#define GT96100_SDMA_G1_CHAN3_RX_DESC_BASE 0x138900 -#define GT96100_SDMA_G1_CHAN3_CURR_RX_DESC_PTR 0x138910 -#define GT96100_SDMA_G1_CHAN3_TX_DESC_BASE 0x13C900 -#define GT96100_SDMA_G1_CHAN3_CURR_TX_DESC_PTR 0x13C910 -#define GT96100_SDMA_G1_CHAN3_1ST_TX_DESC_PTR 0x13C914 -#define GT96100_SDMA_G1_CHAN4_CONFIG 0x140900 -#define GT96100_SDMA_G1_CHAN4_COMM 0x140908 -#define GT96100_SDMA_G1_CHAN4_RX_DESC_BASE 0x148900 -#define GT96100_SDMA_G1_CHAN4_CURR_RX_DESC_PTR 0x148910 -#define GT96100_SDMA_G1_CHAN4_TX_DESC_BASE 0x14C900 -#define GT96100_SDMA_G1_CHAN4_CURR_TX_DESC_PTR 0x14C910 -#define GT96100_SDMA_G1_CHAN4_1ST_TX_DESC_PTR 0x14C914 -#define GT96100_SDMA_G1_CHAN5_CONFIG 0x150900 -#define GT96100_SDMA_G1_CHAN5_COMM 0x150908 -#define GT96100_SDMA_G1_CHAN5_RX_DESC_BASE 0x158900 -#define GT96100_SDMA_G1_CHAN5_CURR_RX_DESC_PTR 0x158910 -#define GT96100_SDMA_G1_CHAN5_TX_DESC_BASE 0x15C900 -#define GT96100_SDMA_G1_CHAN5_CURR_TX_DESC_PTR 0x15C910 -#define GT96100_SDMA_G1_CHAN5_1ST_TX_DESC_PTR 0x15C914 -#define GT96100_SDMA_G1_CHAN6_CONFIG 0x160900 -#define GT96100_SDMA_G1_CHAN6_COMM 0x160908 -#define GT96100_SDMA_G1_CHAN6_RX_DESC_BASE 0x168900 -#define GT96100_SDMA_G1_CHAN6_CURR_RX_DESC_PTR 0x168910 -#define GT96100_SDMA_G1_CHAN6_TX_DESC_BASE 0x16C900 -#define GT96100_SDMA_G1_CHAN6_CURR_TX_DESC_PTR 0x16C910 -#define GT96100_SDMA_G1_CHAN6_1ST_TX_DESC_PTR 0x16C914 -#define GT96100_SDMA_G1_CHAN7_CONFIG 0x170900 -#define GT96100_SDMA_G1_CHAN7_COMM 0x170908 -#define GT96100_SDMA_G1_CHAN7_RX_DESC_BASE 0x178900 -#define GT96100_SDMA_G1_CHAN7_CURR_RX_DESC_PTR 0x178910 -#define GT96100_SDMA_G1_CHAN7_TX_DESC_BASE 0x17C900 -#define GT96100_SDMA_G1_CHAN7_CURR_TX_DESC_PTR 0x17C910 -#define GT96100_SDMA_G1_CHAN7_1ST_TX_DESC_PTR 0x17C914 -/* MPSCs */ -#define GT96100_MPSC0_MAIN_CONFIG_LOW 0x000A00 -#define GT96100_MPSC0_MAIN_CONFIG_HIGH 0x000A04 -#define GT96100_MPSC0_PROTOCOL_CONFIG 0x000A08 -#define GT96100_MPSC_CHAN0_REG1 0x000A0C -#define GT96100_MPSC_CHAN0_REG2 0x000A10 -#define GT96100_MPSC_CHAN0_REG3 0x000A14 -#define GT96100_MPSC_CHAN0_REG4 0x000A18 -#define GT96100_MPSC_CHAN0_REG5 0x000A1C -#define GT96100_MPSC_CHAN0_REG6 0x000A20 -#define GT96100_MPSC_CHAN0_REG7 0x000A24 -#define GT96100_MPSC_CHAN0_REG8 0x000A28 -#define GT96100_MPSC_CHAN0_REG9 0x000A2C -#define GT96100_MPSC_CHAN0_REG10 0x000A30 -#define GT96100_MPSC_CHAN0_REG11 0x000A34 -#define GT96100_MPSC1_MAIN_CONFIG_LOW 0x008A00 -#define GT96100_MPSC1_MAIN_CONFIG_HIGH 0x008A04 -#define GT96100_MPSC1_PROTOCOL_CONFIG 0x008A08 -#define GT96100_MPSC_CHAN1_REG1 0x008A0C -#define GT96100_MPSC_CHAN1_REG2 0x008A10 -#define GT96100_MPSC_CHAN1_REG3 0x008A14 -#define GT96100_MPSC_CHAN1_REG4 0x008A18 -#define GT96100_MPSC_CHAN1_REG5 0x008A1C -#define GT96100_MPSC_CHAN1_REG6 0x008A20 -#define GT96100_MPSC_CHAN1_REG7 0x008A24 -#define GT96100_MPSC_CHAN1_REG8 0x008A28 -#define GT96100_MPSC_CHAN1_REG9 0x008A2C -#define GT96100_MPSC_CHAN1_REG10 0x008A30 -#define GT96100_MPSC_CHAN1_REG11 0x008A34 -#define GT96100_MPSC2_MAIN_CONFIG_LOW 0x010A00 -#define GT96100_MPSC2_MAIN_CONFIG_HIGH 0x010A04 -#define GT96100_MPSC2_PROTOCOL_CONFIG 0x010A08 -#define GT96100_MPSC_CHAN2_REG1 0x010A0C -#define GT96100_MPSC_CHAN2_REG2 0x010A10 -#define GT96100_MPSC_CHAN2_REG3 0x010A14 -#define GT96100_MPSC_CHAN2_REG4 0x010A18 -#define GT96100_MPSC_CHAN2_REG5 0x010A1C -#define GT96100_MPSC_CHAN2_REG6 0x010A20 -#define GT96100_MPSC_CHAN2_REG7 0x010A24 -#define GT96100_MPSC_CHAN2_REG8 0x010A28 -#define GT96100_MPSC_CHAN2_REG9 0x010A2C -#define GT96100_MPSC_CHAN2_REG10 0x010A30 -#define GT96100_MPSC_CHAN2_REG11 0x010A34 -#define GT96100_MPSC3_MAIN_CONFIG_LOW 0x018A00 -#define GT96100_MPSC3_MAIN_CONFIG_HIGH 0x018A04 -#define GT96100_MPSC3_PROTOCOL_CONFIG 0x018A08 -#define GT96100_MPSC_CHAN3_REG1 0x018A0C -#define GT96100_MPSC_CHAN3_REG2 0x018A10 -#define GT96100_MPSC_CHAN3_REG3 0x018A14 -#define GT96100_MPSC_CHAN3_REG4 0x018A18 -#define GT96100_MPSC_CHAN3_REG5 0x018A1C -#define GT96100_MPSC_CHAN3_REG6 0x018A20 -#define GT96100_MPSC_CHAN3_REG7 0x018A24 -#define GT96100_MPSC_CHAN3_REG8 0x018A28 -#define GT96100_MPSC_CHAN3_REG9 0x018A2C -#define GT96100_MPSC_CHAN3_REG10 0x018A30 -#define GT96100_MPSC_CHAN3_REG11 0x018A34 -#define GT96100_MPSC4_MAIN_CONFIG_LOW 0x020A00 -#define GT96100_MPSC4_MAIN_CONFIG_HIGH 0x020A04 -#define GT96100_MPSC4_PROTOCOL_CONFIG 0x020A08 -#define GT96100_MPSC_CHAN4_REG1 0x020A0C -#define GT96100_MPSC_CHAN4_REG2 0x020A10 -#define GT96100_MPSC_CHAN4_REG3 0x020A14 -#define GT96100_MPSC_CHAN4_REG4 0x020A18 -#define GT96100_MPSC_CHAN4_REG5 0x020A1C -#define GT96100_MPSC_CHAN4_REG6 0x020A20 -#define GT96100_MPSC_CHAN4_REG7 0x020A24 -#define GT96100_MPSC_CHAN4_REG8 0x020A28 -#define GT96100_MPSC_CHAN4_REG9 0x020A2C -#define GT96100_MPSC_CHAN4_REG10 0x020A30 -#define GT96100_MPSC_CHAN4_REG11 0x020A34 -#define GT96100_MPSC5_MAIN_CONFIG_LOW 0x028A00 -#define GT96100_MPSC5_MAIN_CONFIG_HIGH 0x028A04 -#define GT96100_MPSC5_PROTOCOL_CONFIG 0x028A08 -#define GT96100_MPSC_CHAN5_REG1 0x028A0C -#define GT96100_MPSC_CHAN5_REG2 0x028A10 -#define GT96100_MPSC_CHAN5_REG3 0x028A14 -#define GT96100_MPSC_CHAN5_REG4 0x028A18 -#define GT96100_MPSC_CHAN5_REG5 0x028A1C -#define GT96100_MPSC_CHAN5_REG6 0x028A20 -#define GT96100_MPSC_CHAN5_REG7 0x028A24 -#define GT96100_MPSC_CHAN5_REG8 0x028A28 -#define GT96100_MPSC_CHAN5_REG9 0x028A2C -#define GT96100_MPSC_CHAN5_REG10 0x028A30 -#define GT96100_MPSC_CHAN5_REG11 0x028A34 -#define GT96100_MPSC6_MAIN_CONFIG_LOW 0x030A00 -#define GT96100_MPSC6_MAIN_CONFIG_HIGH 0x030A04 -#define GT96100_MPSC6_PROTOCOL_CONFIG 0x030A08 -#define GT96100_MPSC_CHAN6_REG1 0x030A0C -#define GT96100_MPSC_CHAN6_REG2 0x030A10 -#define GT96100_MPSC_CHAN6_REG3 0x030A14 -#define GT96100_MPSC_CHAN6_REG4 0x030A18 -#define GT96100_MPSC_CHAN6_REG5 0x030A1C -#define GT96100_MPSC_CHAN6_REG6 0x030A20 -#define GT96100_MPSC_CHAN6_REG7 0x030A24 -#define GT96100_MPSC_CHAN6_REG8 0x030A28 -#define GT96100_MPSC_CHAN6_REG9 0x030A2C -#define GT96100_MPSC_CHAN6_REG10 0x030A30 -#define GT96100_MPSC_CHAN6_REG11 0x030A34 -#define GT96100_MPSC7_MAIN_CONFIG_LOW 0x038A00 -#define GT96100_MPSC7_MAIN_CONFIG_HIGH 0x038A04 -#define GT96100_MPSC7_PROTOCOL_CONFIG 0x038A08 -#define GT96100_MPSC_CHAN7_REG1 0x038A0C -#define GT96100_MPSC_CHAN7_REG2 0x038A10 -#define GT96100_MPSC_CHAN7_REG3 0x038A14 -#define GT96100_MPSC_CHAN7_REG4 0x038A18 -#define GT96100_MPSC_CHAN7_REG5 0x038A1C -#define GT96100_MPSC_CHAN7_REG6 0x038A20 -#define GT96100_MPSC_CHAN7_REG7 0x038A24 -#define GT96100_MPSC_CHAN7_REG8 0x038A28 -#define GT96100_MPSC_CHAN7_REG9 0x038A2C -#define GT96100_MPSC_CHAN7_REG10 0x038A30 -#define GT96100_MPSC_CHAN7_REG11 0x038A34 -/* FlexTDMs */ -/* TDPR0 - Transmit Dual Port RAM. block size 0xff */ -#define GT96100_FXTDM0_TDPR0_BLK0_BASE 0x000B00 -#define GT96100_FXTDM0_TDPR0_BLK1_BASE 0x001B00 -#define GT96100_FXTDM0_TDPR0_BLK2_BASE 0x002B00 -#define GT96100_FXTDM0_TDPR0_BLK3_BASE 0x003B00 -/* RDPR0 - Receive Dual Port RAM. block size 0xff */ -#define GT96100_FXTDM0_RDPR0_BLK0_BASE 0x004B00 -#define GT96100_FXTDM0_RDPR0_BLK1_BASE 0x005B00 -#define GT96100_FXTDM0_RDPR0_BLK2_BASE 0x006B00 -#define GT96100_FXTDM0_RDPR0_BLK3_BASE 0x007B00 -#define GT96100_FXTDM0_TX_READ_PTR 0x008B00 -#define GT96100_FXTDM0_RX_READ_PTR 0x008B04 -#define GT96100_FXTDM0_CONFIG 0x008B08 -#define GT96100_FXTDM0_AUX_CHANA_TX 0x008B0C -#define GT96100_FXTDM0_AUX_CHANA_RX 0x008B10 -#define GT96100_FXTDM0_AUX_CHANB_TX 0x008B14 -#define GT96100_FXTDM0_AUX_CHANB_RX 0x008B18 -#define GT96100_FXTDM1_TDPR1_BLK0_BASE 0x010B00 -#define GT96100_FXTDM1_TDPR1_BLK1_BASE 0x011B00 -#define GT96100_FXTDM1_TDPR1_BLK2_BASE 0x012B00 -#define GT96100_FXTDM1_TDPR1_BLK3_BASE 0x013B00 -#define GT96100_FXTDM1_RDPR1_BLK0_BASE 0x014B00 -#define GT96100_FXTDM1_RDPR1_BLK1_BASE 0x015B00 -#define GT96100_FXTDM1_RDPR1_BLK2_BASE 0x016B00 -#define GT96100_FXTDM1_RDPR1_BLK3_BASE 0x017B00 -#define GT96100_FXTDM1_TX_READ_PTR 0x018B00 -#define GT96100_FXTDM1_RX_READ_PTR 0x018B04 -#define GT96100_FXTDM1_CONFIG 0x018B08 -#define GT96100_FXTDM1_AUX_CHANA_TX 0x018B0C -#define GT96100_FXTDM1_AUX_CHANA_RX 0x018B10 -#define GT96100_FLTDM1_AUX_CHANB_TX 0x018B14 -#define GT96100_FLTDM1_AUX_CHANB_RX 0x018B18 -#define GT96100_FLTDM2_TDPR2_BLK0_BASE 0x020B00 -#define GT96100_FLTDM2_TDPR2_BLK1_BASE 0x021B00 -#define GT96100_FLTDM2_TDPR2_BLK2_BASE 0x022B00 -#define GT96100_FLTDM2_TDPR2_BLK3_BASE 0x023B00 -#define GT96100_FLTDM2_RDPR2_BLK0_BASE 0x024B00 -#define GT96100_FLTDM2_RDPR2_BLK1_BASE 0x025B00 -#define GT96100_FLTDM2_RDPR2_BLK2_BASE 0x026B00 -#define GT96100_FLTDM2_RDPR2_BLK3_BASE 0x027B00 -#define GT96100_FLTDM2_TX_READ_PTR 0x028B00 -#define GT96100_FLTDM2_RX_READ_PTR 0x028B04 -#define GT96100_FLTDM2_CONFIG 0x028B08 -#define GT96100_FLTDM2_AUX_CHANA_TX 0x028B0C -#define GT96100_FLTDM2_AUX_CHANA_RX 0x028B10 -#define GT96100_FLTDM2_AUX_CHANB_TX 0x028B14 -#define GT96100_FLTDM2_AUX_CHANB_RX 0x028B18 -#define GT96100_FLTDM3_TDPR3_BLK0_BASE 0x030B00 -#define GT96100_FLTDM3_TDPR3_BLK1_BASE 0x031B00 -#define GT96100_FLTDM3_TDPR3_BLK2_BASE 0x032B00 -#define GT96100_FLTDM3_TDPR3_BLK3_BASE 0x033B00 -#define GT96100_FXTDM3_RDPR3_BLK0_BASE 0x034B00 -#define GT96100_FXTDM3_RDPR3_BLK1_BASE 0x035B00 -#define GT96100_FXTDM3_RDPR3_BLK2_BASE 0x036B00 -#define GT96100_FXTDM3_RDPR3_BLK3_BASE 0x037B00 -#define GT96100_FXTDM3_TX_READ_PTR 0x038B00 -#define GT96100_FXTDM3_RX_READ_PTR 0x038B04 -#define GT96100_FXTDM3_CONFIG 0x038B08 -#define GT96100_FXTDM3_AUX_CHANA_TX 0x038B0C -#define GT96100_FXTDM3_AUX_CHANA_RX 0x038B10 -#define GT96100_FXTDM3_AUX_CHANB_TX 0x038B14 -#define GT96100_FXTDM3_AUX_CHANB_RX 0x038B18 -/* Baud Rate Generators */ -#define GT96100_BRG0_CONFIG 0x102A00 -#define GT96100_BRG0_BAUD_TUNE 0x102A04 -#define GT96100_BRG1_CONFIG 0x102A08 -#define GT96100_BRG1_BAUD_TUNE 0x102A0C -#define GT96100_BRG2_CONFIG 0x102A10 -#define GT96100_BRG2_BAUD_TUNE 0x102A14 -#define GT96100_BRG3_CONFIG 0x102A18 -#define GT96100_BRG3_BAUD_TUNE 0x102A1C -#define GT96100_BRG4_CONFIG 0x102A20 -#define GT96100_BRG4_BAUD_TUNE 0x102A24 -#define GT96100_BRG5_CONFIG 0x102A28 -#define GT96100_BRG5_BAUD_TUNE 0x102A2C -#define GT96100_BRG6_CONFIG 0x102A30 -#define GT96100_BRG6_BAUD_TUNE 0x102A34 -#define GT96100_BRG7_CONFIG 0x102A38 -#define GT96100_BRG7_BAUD_TUNE 0x102A3C -/* Routing Registers */ -#define GT96100_ROUTE_MAIN 0x101A00 -#define GT96100_ROUTE_RX_CLOCK 0x101A10 -#define GT96100_ROUTE_TX_CLOCK 0x101A20 -/* General Purpose Ports */ -#define GT96100_GPP_CONFIG0 0x100A00 -#define GT96100_GPP_CONFIG1 0x100A04 -#define GT96100_GPP_CONFIG2 0x100A08 -#define GT96100_GPP_CONFIG3 0x100A0C -#define GT96100_GPP_IO0 0x100A20 -#define GT96100_GPP_IO1 0x100A24 -#define GT96100_GPP_IO2 0x100A28 -#define GT96100_GPP_IO3 0x100A2C -#define GT96100_GPP_DATA0 0x100A40 -#define GT96100_GPP_DATA1 0x100A44 -#define GT96100_GPP_DATA2 0x100A48 -#define GT96100_GPP_DATA3 0x100A4C -#define GT96100_GPP_LEVEL0 0x100A60 -#define GT96100_GPP_LEVEL1 0x100A64 -#define GT96100_GPP_LEVEL2 0x100A68 -#define GT96100_GPP_LEVEL3 0x100A6C -/* Watchdog */ -#define GT96100_WD_CONFIG 0x101A80 -#define GT96100_WD_VALUE 0x101A84 -/* Communication Unit Arbiter */ -#define GT96100_COMM_UNIT_ARBTR_CONFIG 0x101AC0 -/* PCI Arbiters */ -#define GT96100_PCI0_ARBTR_CONFIG 0x101AE0 -#define GT96100_PCI1_ARBTR_CONFIG 0x101AE4 -/* CIU Arbiter */ -#define GT96100_CIU_ARBITER_CONFIG 0x101AC0 -/* Interrupt Controller */ -#define GT96100_MAIN_CAUSE 0x000C18 -#define GT96100_INT0_MAIN_MASK 0x000C1C -#define GT96100_INT1_MAIN_MASK 0x000C24 -#define GT96100_HIGH_CAUSE 0x000C98 -#define GT96100_INT0_HIGH_MASK 0x000C9C -#define GT96100_INT1_HIGH_MASK 0x000CA4 -#define GT96100_INT0_SELECT 0x000C70 -#define GT96100_INT1_SELECT 0x000C74 -#define GT96100_SERIAL_CAUSE 0x103A00 -#define GT96100_SERINT0_MASK 0x103A80 -#define GT96100_SERINT1_MASK 0x103A88 - -#endif /* _GT96100_H */ diff --git a/include/asm-mips/mach-ev96100/mach-gt64120.h b/include/asm-mips/mach-ev96100/mach-gt64120.h deleted file mode 100644 index 0ef1e6c25acf..000000000000 --- a/include/asm-mips/mach-ev96100/mach-gt64120.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This is a direct copy of the ev96100.h file, with a global - * search and replace. The numbers are the same. - * - * The reason I'm duplicating this is so that the 64120/96100 - * defines won't be confusing in the source code. - */ -#ifndef _ASM_GT64120_EV96100_GT64120_DEP_H -#define _ASM_GT64120_EV96100_GT64120_DEP_H - -/* - * GT96100 config space base address - */ -#define GT64120_BASE (KSEG1ADDR(0x14000000)) - -/* - * PCI Bus allocation - * - * (Guessing ...) - */ -#define GT_PCI_MEM_BASE 0x12000000UL -#define GT_PCI_MEM_SIZE 0x02000000UL -#define GT_PCI_IO_BASE 0x10000000UL -#define GT_PCI_IO_SIZE 0x02000000UL -#define GT_ISA_IO_BASE PCI_IO_BASE - -/* - * Duart I/O ports. - */ -#define EV96100_COM1_BASE_ADDR (0xBD000000 + 0x20) -#define EV96100_COM2_BASE_ADDR (0xBD000000 + 0x00) - - -/* - * EV96100 interrupt controller register base. - */ -#define EV96100_ICTRL_REGS_BASE (KSEG1ADDR(0x1f000000)) - -/* - * EV96100 UART register base. - */ -#define EV96100_UART0_REGS_BASE EV96100_COM1_BASE_ADDR -#define EV96100_UART1_REGS_BASE EV96100_COM2_BASE_ADDR -#define EV96100_BASE_BAUD ( 3686400 / 16 ) - -#endif /* _ASM_GT64120_EV96100_GT64120_DEP_H */ diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h index 584bd9c0ab2e..035637c67e7c 100644 --- a/include/asm-mips/serial.h +++ b/include/asm-mips/serial.h @@ -52,9 +52,9 @@ #endif /* - * Both Galileo boards have the same UART mappings. + * Galileo EV64120 evaluation board */ -#if defined (CONFIG_MIPS_EV96100) || defined (CONFIG_MIPS_EV64120) +#ifdef CONFIG_MIPS_EV64120 #include #include #define EV96100_SERIAL_PORT_DEFNS \ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6a1e09834559..5c1c698a92ac 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1482,9 +1482,6 @@ #define PCI_DEVICE_ID_MARVELL_GT64260 0x6430 #define PCI_DEVICE_ID_MARVELL_MV64360 0x6460 #define PCI_DEVICE_ID_MARVELL_MV64460 0x6480 -#define PCI_DEVICE_ID_MARVELL_GT96100 0x9652 -#define PCI_DEVICE_ID_MARVELL_GT96100A 0x9653 - #define PCI_VENDOR_ID_V3 0x11b0 #define PCI_DEVICE_ID_V3_V960 0x0001 -- cgit v1.2.3 From ae6ddcc5f24d6b06ae9231dc128904750a4155e0 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 27 Sep 2006 01:49:27 -0700 Subject: [PATCH] ext3 and jbd cleanup: remove whitespace Remove whitespace from ext3 and jbd, before we clone ext4. Signed-off-by: Mingming Cao Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/balloc.c | 16 +++--- fs/ext3/bitmap.c | 2 +- fs/ext3/dir.c | 14 +++--- fs/ext3/file.c | 2 +- fs/ext3/fsync.c | 6 +-- fs/ext3/hash.c | 6 +-- fs/ext3/ialloc.c | 48 +++++++++--------- fs/ext3/inode.c | 64 ++++++++++++------------ fs/ext3/namei.c | 28 +++++------ fs/ext3/super.c | 24 ++++----- fs/jbd/checkpoint.c | 30 +++++------ fs/jbd/journal.c | 56 ++++++++++----------- fs/jbd/recovery.c | 54 ++++++++++---------- fs/jbd/revoke.c | 70 +++++++++++++------------- fs/jbd/transaction.c | 128 +++++++++++++++++++++++------------------------ include/linux/ext3_jbd.h | 10 ++-- include/linux/jbd.h | 56 ++++++++++----------- 17 files changed, 307 insertions(+), 307 deletions(-) (limited to 'include/linux') diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 063d994bda0b..e6b983707008 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -74,7 +74,7 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, } /* - * Read the bitmap for a given block_group, reading into the specified + * Read the bitmap for a given block_group, reading into the specified * slot in the superblock's bitmap cache. * * Return buffer_head on success or NULL in case of failure. @@ -419,8 +419,8 @@ do_more: } /* @@@ This prevents newly-allocated data from being * freed and then reallocated within the same - * transaction. - * + * transaction. + * * Ideally we would want to allow that to happen, but to * do so requires making journal_forget() capable of * revoking the queued write of a data block, which @@ -433,7 +433,7 @@ do_more: * safe not to set the allocation bit in the committed * bitmap, because we know that there is no outstanding * activity on the buffer any more and so it is safe to - * reallocate it. + * reallocate it. */ BUFFER_TRACE(bitmap_bh, "set in b_committed_data"); J_ASSERT_BH(bitmap_bh, @@ -518,7 +518,7 @@ void ext3_free_blocks(handle_t *handle, struct inode *inode, * data would allow the old block to be overwritten before the * transaction committed (because we force data to disk before commit). * This would lead to corruption if we crashed between overwriting the - * data and committing the delete. + * data and committing the delete. * * @@@ We may want to make this allocation behaviour conditional on * data-writes at some point, and disable it for metadata allocations or @@ -584,7 +584,7 @@ find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, if (start > 0) { /* - * The goal was occupied; search forward for a free + * The goal was occupied; search forward for a free * block within the next XX blocks. * * end_goal is more or less random, but it has to be @@ -1194,7 +1194,7 @@ int ext3_should_retry_alloc(struct super_block *sb, int *retries) /* * ext3_new_block uses a goal block to assist allocation. If the goal is * free, or there is a free block within 32 blocks of the goal, that block - * is allocated. Otherwise a forward search is made for a free block; within + * is allocated. Otherwise a forward search is made for a free block; within * each block group the search first looks for an entire free byte in the block * bitmap, and then for any free bit if that fails. * This function also updates quota and i_blocks field. @@ -1303,7 +1303,7 @@ retry_alloc: smp_rmb(); /* - * Now search the rest of the groups. We assume that + * Now search the rest of the groups. We assume that * i and gdp correctly point to the last group visited. */ for (bgi = 0; bgi < ngroups; bgi++) { diff --git a/fs/ext3/bitmap.c b/fs/ext3/bitmap.c index ce4f82b9e528..b9176eed98d1 100644 --- a/fs/ext3/bitmap.c +++ b/fs/ext3/bitmap.c @@ -20,7 +20,7 @@ unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars) unsigned int i; unsigned long sum = 0; - if (!map) + if (!map) return (0); for (i = 0; i < numchars; i++) sum += nibblemap[map->b_data[i] & 0xf] + diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index fbb0d4ed07d4..6f9e5a523c87 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -59,7 +59,7 @@ static unsigned char get_dtype(struct super_block *sb, int filetype) return (ext3_filetype_table[filetype]); } - + int ext3_check_dir_entry (const char * function, struct inode * dir, struct ext3_dir_entry_2 * de, @@ -162,7 +162,7 @@ revalidate: * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { - de = (struct ext3_dir_entry_2 *) + de = (struct ext3_dir_entry_2 *) (bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this @@ -181,7 +181,7 @@ revalidate: filp->f_version = inode->i_version; } - while (!error && filp->f_pos < inode->i_size + while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ext3_dir_entry_2 *) (bh->b_data + offset); if (!ext3_check_dir_entry ("ext3_readdir", inode, de, @@ -229,7 +229,7 @@ out: /* * These functions convert from the major/minor hash to an f_pos * value. - * + * * Currently we only use major hash numer. This is unfortunate, but * on 32-bit machines, the same VFS interface is used for lseek and * llseek, so if we use the 64 bit offset, then the 32-bit versions of @@ -250,7 +250,7 @@ out: struct fname { __u32 hash; __u32 minor_hash; - struct rb_node rb_hash; + struct rb_node rb_hash; struct fname *next; __u32 inode; __u8 name_len; @@ -410,7 +410,7 @@ static int call_filldir(struct file * filp, void * dirent, curr_pos = hash2pos(fname->hash, fname->minor_hash); while (fname) { error = filldir(dirent, fname->name, - fname->name_len, curr_pos, + fname->name_len, curr_pos, fname->inode, get_dtype(sb, fname->file_type)); if (error) { @@ -465,7 +465,7 @@ static int ext3_dx_readdir(struct file * filp, /* * Fill the rbtree if we have no more entries, * or the inode has changed since we last read in the - * cached entries. + * cached entries. */ if ((!info->curr_node) || (filp->f_version != inode->i_version)) { diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 1efefb630ea9..994efd189f4e 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -100,7 +100,7 @@ ext3_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t force_commit: err = ext3_force_commit(inode->i_sb); - if (err) + if (err) return err; return ret; } diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c index 49382a208e05..dd1fd3c0fc05 100644 --- a/fs/ext3/fsync.c +++ b/fs/ext3/fsync.c @@ -8,14 +8,14 @@ * Universite Pierre et Marie Curie (Paris VI) * from * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds - * + * * ext3fs fsync primitive * * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 - * + * * Removed unnecessary code duplication for little endian machines - * and excessive __inline__s. + * and excessive __inline__s. * Andi Kleen, 1997 * * Major simplications and cleanup - we only need to do the metadata, because diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c index 5a2d1235ead0..7fa637cd322a 100644 --- a/fs/ext3/hash.c +++ b/fs/ext3/hash.c @@ -4,7 +4,7 @@ * Copyright (C) 2002 by Theodore Ts'o * * This file is released under the GPL v2. - * + * * This file may be redistributed under the terms of the GNU Public * License. */ @@ -80,11 +80,11 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) * Returns the hash of a filename. If len is 0 and name is NULL, then * this function can be used to test whether or not a hash version is * supported. - * + * * The seed is an 4 longword (32 bits) "secret" which can be used to * uniquify a hash. If the seed is all zero's, then some default seed * may be used. - * + * * A particular hash version specifies whether or not the seed is * represented, and whether or not the returned hash is 32 bits or 64 * bits. 32 bit hashes will return 0 for the minor hash. diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 36546ed36a14..5e288368499b 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -216,7 +216,7 @@ static int find_group_dir(struct super_block *sb, struct inode *parent) continue; if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) continue; - if (!best_desc || + if (!best_desc || (le16_to_cpu(desc->bg_free_blocks_count) > le16_to_cpu(best_desc->bg_free_blocks_count))) { best_group = group; @@ -226,30 +226,30 @@ static int find_group_dir(struct super_block *sb, struct inode *parent) return best_group; } -/* - * Orlov's allocator for directories. - * +/* + * Orlov's allocator for directories. + * * We always try to spread first-level directories. * - * If there are blockgroups with both free inodes and free blocks counts - * not worse than average we return one with smallest directory count. - * Otherwise we simply return a random group. - * - * For the rest rules look so: - * - * It's OK to put directory into a group unless - * it has too many directories already (max_dirs) or - * it has too few free inodes left (min_inodes) or - * it has too few free blocks left (min_blocks) or - * it's already running too large debt (max_debt). - * Parent's group is prefered, if it doesn't satisfy these - * conditions we search cyclically through the rest. If none - * of the groups look good we just look for a group with more - * free inodes than average (starting at parent's group). - * - * Debt is incremented each time we allocate a directory and decremented - * when we allocate an inode, within 0--255. - */ + * If there are blockgroups with both free inodes and free blocks counts + * not worse than average we return one with smallest directory count. + * Otherwise we simply return a random group. + * + * For the rest rules look so: + * + * It's OK to put directory into a group unless + * it has too many directories already (max_dirs) or + * it has too few free inodes left (min_inodes) or + * it has too few free blocks left (min_blocks) or + * it's already running too large debt (max_debt). + * Parent's group is prefered, if it doesn't satisfy these + * conditions we search cyclically through the rest. If none + * of the groups look good we just look for a group with more + * free inodes than average (starting at parent's group). + * + * Debt is incremented each time we allocate a directory and decremented + * when we allocate an inode, within 0--255. + */ #define INODE_COST 64 #define BLOCK_COST 256 @@ -454,7 +454,7 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) group = find_group_dir(sb, dir); else group = find_group_orlov(sb, dir); - } else + } else group = find_group_other(sb, dir); err = -ENOSPC; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 84be02e93652..473d206b1d7e 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -55,7 +55,7 @@ static int ext3_inode_is_fast_symlink(struct inode *inode) /* * The ext3 forget function must perform a revoke if we are freeing data * which has been journaled. Metadata (eg. indirect blocks) must be - * revoked in all cases. + * revoked in all cases. * * "bh" may be NULL: a metadata block may have been freed from memory * but there may still be a record of it in the journal, and that record @@ -105,7 +105,7 @@ int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode, * Work out how many blocks we need to proceed with the next chunk of a * truncate transaction. */ -static unsigned long blocks_for_truncate(struct inode *inode) +static unsigned long blocks_for_truncate(struct inode *inode) { unsigned long needed; @@ -122,13 +122,13 @@ static unsigned long blocks_for_truncate(struct inode *inode) /* But we need to bound the transaction so we don't overflow the * journal. */ - if (needed > EXT3_MAX_TRANS_DATA) + if (needed > EXT3_MAX_TRANS_DATA) needed = EXT3_MAX_TRANS_DATA; return EXT3_DATA_TRANS_BLOCKS(inode->i_sb) + needed; } -/* +/* * Truncate transactions can be complex and absolutely huge. So we need to * be able to restart the transaction at a conventient checkpoint to make * sure we don't overflow the journal. @@ -136,9 +136,9 @@ static unsigned long blocks_for_truncate(struct inode *inode) * start_transaction gets us a new handle for a truncate transaction, * and extend_transaction tries to extend the existing one a bit. If * extend fails, we need to propagate the failure up and restart the - * transaction in the top-level truncate loop. --sct + * transaction in the top-level truncate loop. --sct */ -static handle_t *start_transaction(struct inode *inode) +static handle_t *start_transaction(struct inode *inode) { handle_t *result; @@ -215,12 +215,12 @@ void ext3_delete_inode (struct inode * inode) ext3_orphan_del(handle, inode); EXT3_I(inode)->i_dtime = get_seconds(); - /* + /* * One subtle ordering requirement: if anything has gone wrong * (transaction abort, IO errors, whatever), then we can still * do these next steps (the fs will already have been marked as * having errors), but we can't free the inode if the mark_dirty - * fails. + * fails. */ if (ext3_mark_inode_dirty(handle, inode)) /* If that failed, just do the required in-core inode clear. */ @@ -398,7 +398,7 @@ no_block: * + if there is a block to the left of our position - allocate near it. * + if pointer will live in indirect block - allocate near that block. * + if pointer will live in inode - allocate in the same - * cylinder group. + * cylinder group. * * In the latter case we colour the starting block by the callers PID to * prevent it from clashing with concurrent allocations for a different inode @@ -744,7 +744,7 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, jbd_debug(5, "splicing indirect only\n"); BUFFER_TRACE(where->bh, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, where->bh); - if (err) + if (err) goto err_out; } else { /* @@ -1137,7 +1137,7 @@ static int walk_page_buffers( handle_t *handle, * So what we do is to rely on the fact that journal_stop/journal_start * will _not_ run commit under these circumstances because handle->h_ref * is elevated. We'll still have enough credits for the tiny quotafile - * write. + * write. */ static int do_journal_get_write_access(handle_t *handle, struct buffer_head *bh) @@ -1282,7 +1282,7 @@ static int ext3_journalled_commit_write(struct file *file, if (inode->i_size > EXT3_I(inode)->i_disksize) { EXT3_I(inode)->i_disksize = inode->i_size; ret2 = ext3_mark_inode_dirty(handle, inode); - if (!ret) + if (!ret) ret = ret2; } ret2 = ext3_journal_stop(handle); @@ -1291,7 +1291,7 @@ static int ext3_journalled_commit_write(struct file *file, return ret; } -/* +/* * bmap() is special. It gets used by applications such as lilo and by * the swapper to find the on-disk block of a specific piece of data. * @@ -1300,10 +1300,10 @@ static int ext3_journalled_commit_write(struct file *file, * filesystem and enables swap, then they may get a nasty shock when the * data getting swapped to that swapfile suddenly gets overwritten by * the original zero's written out previously to the journal and - * awaiting writeback in the kernel's buffer cache. + * awaiting writeback in the kernel's buffer cache. * * So, if we see any bmap calls here on a modified, data-journaled file, - * take extra steps to flush any blocks which might be in the cache. + * take extra steps to flush any blocks which might be in the cache. */ static sector_t ext3_bmap(struct address_space *mapping, sector_t block) { @@ -1312,16 +1312,16 @@ static sector_t ext3_bmap(struct address_space *mapping, sector_t block) int err; if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) { - /* + /* * This is a REALLY heavyweight approach, but the use of * bmap on dirty files is expected to be extremely rare: * only if we run lilo or swapon on a freshly made file - * do we expect this to happen. + * do we expect this to happen. * * (bmap requires CAP_SYS_RAWIO so this does not * represent an unprivileged user DOS attack --- we'd be * in trouble if mortal users could trigger this path at - * will.) + * will.) * * NB. EXT3_STATE_JDATA is not set on files other than * regular files. If somebody wants to bmap a directory @@ -1457,7 +1457,7 @@ static int ext3_ordered_writepage(struct page *page, */ /* - * And attach them to the current transaction. But only if + * And attach them to the current transaction. But only if * block_write_full_page() succeeded. Otherwise they are unmapped, * and generally junk. */ @@ -1644,7 +1644,7 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, } } - ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, ext3_get_block, NULL); @@ -2025,7 +2025,7 @@ static void ext3_free_data(handle_t *handle, struct inode *inode, __le32 *first, __le32 *last) { ext3_fsblk_t block_to_free = 0; /* Starting block # of a run */ - unsigned long count = 0; /* Number of blocks in the run */ + unsigned long count = 0; /* Number of blocks in the run */ __le32 *block_to_free_p = NULL; /* Pointer into inode/ind corresponding to block_to_free */ @@ -2054,7 +2054,7 @@ static void ext3_free_data(handle_t *handle, struct inode *inode, } else if (nr == block_to_free + count) { count++; } else { - ext3_clear_blocks(handle, inode, this_bh, + ext3_clear_blocks(handle, inode, this_bh, block_to_free, count, block_to_free_p, p); block_to_free = nr; @@ -2184,7 +2184,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, *p = 0; BUFFER_TRACE(parent_bh, "call ext3_journal_dirty_metadata"); - ext3_journal_dirty_metadata(handle, + ext3_journal_dirty_metadata(handle, parent_bh); } } @@ -2704,7 +2704,7 @@ void ext3_read_inode(struct inode * inode) if (raw_inode->i_block[0]) init_special_inode(inode, inode->i_mode, old_decode_dev(le32_to_cpu(raw_inode->i_block[0]))); - else + else init_special_inode(inode, inode->i_mode, new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); } @@ -2724,8 +2724,8 @@ bad_inode: * * The caller must have write access to iloc->bh. */ -static int ext3_do_update_inode(handle_t *handle, - struct inode *inode, +static int ext3_do_update_inode(handle_t *handle, + struct inode *inode, struct ext3_iloc *iloc) { struct ext3_inode *raw_inode = ext3_raw_inode(iloc); @@ -2900,7 +2900,7 @@ int ext3_write_inode(struct inode *inode, int wait) * commit will leave the blocks being flushed in an unused state on * disk. (On recovery, the inode will get truncated and the blocks will * be freed, so we have a strong guarantee that no future commit will - * leave these blocks visible to the user.) + * leave these blocks visible to the user.) * * Called with inode->sem down. */ @@ -3043,13 +3043,13 @@ int ext3_mark_iloc_dirty(handle_t *handle, return err; } -/* +/* * On success, We end up with an outstanding reference count against - * iloc->bh. This _must_ be cleaned up later. + * iloc->bh. This _must_ be cleaned up later. */ int -ext3_reserve_inode_write(handle_t *handle, struct inode *inode, +ext3_reserve_inode_write(handle_t *handle, struct inode *inode, struct ext3_iloc *iloc) { int err = 0; @@ -3139,7 +3139,7 @@ out: } #if 0 -/* +/* * Bind an inode's backing buffer_head into this transaction, to prevent * it from being flushed to disk early. Unlike * ext3_reserve_inode_write, this leaves behind no bh reference and @@ -3157,7 +3157,7 @@ static int ext3_pin_inode(handle_t *handle, struct inode *inode) BUFFER_TRACE(iloc.bh, "get_write_access"); err = journal_get_write_access(handle, iloc.bh); if (!err) - err = ext3_journal_dirty_metadata(handle, + err = ext3_journal_dirty_metadata(handle, iloc.bh); brelse(iloc.bh); } diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 2aa7101b27cd..4123f5261bcd 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -76,7 +76,7 @@ static struct buffer_head *ext3_append(handle_t *handle, #ifdef DX_DEBUG #define dxtrace(command) command #else -#define dxtrace(command) +#define dxtrace(command) #endif struct fake_dirent @@ -169,7 +169,7 @@ static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size); static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block); static int ext3_htree_next_block(struct inode *dir, __u32 hash, struct dx_frame *frame, - struct dx_frame *frames, + struct dx_frame *frames, __u32 *start_hash); static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, struct ext3_dir_entry_2 **res_dir, int *err); @@ -250,7 +250,7 @@ static void dx_show_index (char * label, struct dx_entry *entries) } struct stats -{ +{ unsigned names; unsigned space; unsigned bcount; @@ -464,7 +464,7 @@ static void dx_release (struct dx_frame *frames) */ static int ext3_htree_next_block(struct inode *dir, __u32 hash, struct dx_frame *frame, - struct dx_frame *frames, + struct dx_frame *frames, __u32 *start_hash) { struct dx_frame *p; @@ -632,7 +632,7 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, } count += ret; hashval = ~0; - ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS, + ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS, frame, frames, &hashval); *next_hash = hashval; if (ret < 0) { @@ -649,7 +649,7 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, break; } dx_release(frames); - dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n", + dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n", count, *next_hash)); return count; errout: @@ -1050,7 +1050,7 @@ struct dentry *ext3_get_parent(struct dentry *child) parent = ERR_PTR(-ENOMEM); } return parent; -} +} #define S_SHIFT 12 static unsigned char ext3_type_by_mode[S_IFMT >> S_SHIFT] = { @@ -1198,7 +1198,7 @@ errout: * add_dirent_to_buf will attempt search the directory block for * space. It will return -ENOSPC if no space is available, and -EIO * and -EEXIST if directory entry already exists. - * + * * NOTE! bh is NOT released in the case where ENOSPC is returned. In * all other cases bh is released. */ @@ -1572,7 +1572,7 @@ cleanup: * ext3_delete_entry deletes a directory entry by merging it with the * previous entry */ -static int ext3_delete_entry (handle_t *handle, +static int ext3_delete_entry (handle_t *handle, struct inode * dir, struct ext3_dir_entry_2 * de_del, struct buffer_head * bh) @@ -1643,12 +1643,12 @@ static int ext3_add_nondir(handle_t *handle, * is so far negative - it has no inode. * * If the create succeeds, we fill in the inode information - * with d_instantiate(). + * with d_instantiate(). */ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd) { - handle_t *handle; + handle_t *handle; struct inode * inode; int err, retries = 0; @@ -1813,7 +1813,7 @@ static int empty_dir (struct inode * inode) de1 = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); if (le32_to_cpu(de->inode) != inode->i_ino || - !le32_to_cpu(de1->inode) || + !le32_to_cpu(de1->inode) || strcmp (".", de->name) || strcmp ("..", de1->name)) { ext3_warning (inode->i_sb, "empty_dir", @@ -1883,7 +1883,7 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode) * being truncated, or files being unlinked. */ /* @@@ FIXME: Observation from aviro: - * I think I can trigger J_ASSERT in ext3_orphan_add(). We block + * I think I can trigger J_ASSERT in ext3_orphan_add(). We block * here (on lock_super()), so race with ext3_link() which might bump * ->i_nlink. For, say it, character device. Not a regular file, * not a directory, not a symlink and ->i_nlink > 0. @@ -2393,4 +2393,4 @@ struct inode_operations ext3_special_inode_operations = { .removexattr = generic_removexattr, #endif .permission = ext3_permission, -}; +}; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 3559086eee5f..4b95bfe4c8f7 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -62,13 +62,13 @@ 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. * * The only special thing we need to do here is to make sure that all * journal_end calls result in the superblock being marked dirty, so * that sync() will call the filesystem's write_super callback if - * appropriate. + * appropriate. */ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks) { @@ -90,11 +90,11 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks) return journal_start(journal, nblocks); } -/* +/* * The only special thing we need to do here is to make sure that all * journal_stop calls result in the superblock being marked dirty, so * that sync() will call the filesystem's write_super callback if - * appropriate. + * appropriate. */ int __ext3_journal_stop(const char *where, handle_t *handle) { @@ -369,7 +369,7 @@ static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi) { struct list_head *l; - printk(KERN_ERR "sb orphan head is %d\n", + printk(KERN_ERR "sb orphan head is %d\n", le32_to_cpu(sbi->s_es->s_last_orphan)); printk(KERN_ERR "sb_info orphan list:\n"); @@ -378,7 +378,7 @@ static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi) printk(KERN_ERR " " "inode %s:%ld at %p: mode %o, nlink %d, next %d\n", inode->i_sb->s_id, inode->i_ino, inode, - inode->i_mode, inode->i_nlink, + inode->i_mode, inode->i_nlink, NEXT_ORPHAN(inode)); } } @@ -475,7 +475,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) inode_init_once(&ei->vfs_inode); } } - + static int init_inodecache(void) { ext3_inode_cachep = kmem_cache_create("ext3_inode_cache", @@ -1483,7 +1483,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) || EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) || EXT3_HAS_INCOMPAT_FEATURE(sb, ~0U))) - printk(KERN_WARNING + printk(KERN_WARNING "EXT3-fs warning: feature flags set on rev 0 fs, " "running e2fsck is recommended\n"); /* @@ -1509,7 +1509,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) if (blocksize < EXT3_MIN_BLOCK_SIZE || blocksize > EXT3_MAX_BLOCK_SIZE) { - printk(KERN_ERR + printk(KERN_ERR "EXT3-fs: Unsupported filesystem blocksize %d on %s.\n", blocksize, sb->s_id); goto failed_mount; @@ -1533,14 +1533,14 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; bh = sb_bread(sb, logic_sb_block); if (!bh) { - printk(KERN_ERR + printk(KERN_ERR "EXT3-fs: Can't read superblock on 2nd try.\n"); goto failed_mount; } es = (struct ext3_super_block *)(((char *)bh->b_data) + offset); sbi->s_es = es; if (es->s_magic != cpu_to_le16(EXT3_SUPER_MAGIC)) { - printk (KERN_ERR + printk (KERN_ERR "EXT3-fs: Magic mismatch, very weird !\n"); goto failed_mount; } @@ -1820,7 +1820,7 @@ out_fail: /* * Setup any per-fs journal parameters now. We'll do this both on * initial mount, once the journal has been initialised but before we've - * done any recovery; and again on any subsequent remount. + * done any recovery; and again on any subsequent remount. */ static void ext3_init_journal_params(struct super_block *sb, journal_t *journal) { diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index d0685596e5a6..961ada28db5e 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -1,6 +1,6 @@ /* * linux/fs/checkpoint.c - * + * * Written by Stephen C. Tweedie , 1999 * * Copyright 1999 Red Hat Software --- All Rights Reserved @@ -9,8 +9,8 @@ * the terms of the GNU General Public License, version 2, or at your * option, any later version, incorporated herein by reference. * - * Checkpoint routines for the generic filesystem journaling code. - * Part of the ext2fs journaling system. + * Checkpoint routines for the generic filesystem journaling code. + * Part of the ext2fs journaling system. * * Checkpointing is the process of ensuring that a section of the log is * committed fully to disk, so that that portion of the log can be @@ -226,7 +226,7 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) * Try to flush one buffer from the checkpoint list to disk. * * Return 1 if something happened which requires us to abort the current - * scan of the checkpoint list. + * scan of the checkpoint list. * * Called with j_list_lock held and drops it if 1 is returned * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it @@ -270,7 +270,7 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh, * possibly block, while still holding the journal lock. * We cannot afford to let the transaction logic start * messing around with this buffer before we write it to - * disk, as that would break recoverability. + * disk, as that would break recoverability. */ BUFFER_TRACE(bh, "queue"); get_bh(bh); @@ -293,7 +293,7 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh, * Perform an actual checkpoint. We take the first transaction on the * list of transactions to be checkpointed and send all its buffers * to disk. We submit larger chunks of data at once. - * + * * The journal should be locked before calling this function. */ int log_do_checkpoint(journal_t *journal) @@ -304,10 +304,10 @@ int log_do_checkpoint(journal_t *journal) jbd_debug(1, "Start checkpoint\n"); - /* + /* * First thing: if there are any transactions in the log which * don't need checkpointing, just eliminate them from the - * journal straight away. + * journal straight away. */ result = cleanup_journal_tail(journal); jbd_debug(1, "cleanup_journal_tail returned %d\n", result); @@ -385,9 +385,9 @@ out: * we have already got rid of any since the last update of the log tail * in the journal superblock. If so, we can instantly roll the * superblock forward to remove those transactions from the log. - * + * * Return <0 on error, 0 on success, 1 if there was nothing to clean up. - * + * * Called with the journal lock held. * * This is the only part of the journaling code which really needs to be @@ -404,8 +404,8 @@ int cleanup_journal_tail(journal_t *journal) unsigned long blocknr, freed; /* OK, work out the oldest transaction remaining in the log, and - * the log block it starts at. - * + * the log block it starts at. + * * If the log is now empty, we need to work out which is the * next transaction ID we will write, and where it will * start. */ @@ -558,7 +558,7 @@ out: return ret; } -/* +/* * journal_remove_checkpoint: called after a buffer has been committed * to disk (either by being write-back flushed to disk, or being * committed to the log). @@ -636,7 +636,7 @@ out: * Called with the journal locked. * Called with j_list_lock held. */ -void __journal_insert_checkpoint(struct journal_head *jh, +void __journal_insert_checkpoint(struct journal_head *jh, transaction_t *transaction) { JBUFFER_TRACE(jh, "entry"); @@ -658,7 +658,7 @@ void __journal_insert_checkpoint(struct journal_head *jh, /* * We've finished with this transaction structure: adios... - * + * * The transaction must have no links except for the checkpoint by this * point. * diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index f66724ce443a..87c5a6d00805 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -578,7 +578,7 @@ int journal_next_log_block(journal_t *journal, unsigned long *retp) * this is a no-op. If needed, we can use j_blk_offset - everything is * ready. */ -int journal_bmap(journal_t *journal, unsigned long blocknr, +int journal_bmap(journal_t *journal, unsigned long blocknr, unsigned long *retp) { int err = 0; @@ -699,10 +699,10 @@ fail: * @len: Lenght of the journal in blocks. * @blocksize: blocksize of journalling device * @returns: a newly created journal_t * - * + * * journal_init_dev creates a journal which maps a fixed contiguous * range of blocks on an arbitrary block device. - * + * */ journal_t * journal_init_dev(struct block_device *bdev, struct block_device *fs_dev, @@ -739,11 +739,11 @@ journal_t * journal_init_dev(struct block_device *bdev, return journal; } - -/** + +/** * journal_t * journal_init_inode () - creates a journal which maps to a inode. * @inode: An inode to create the journal in - * + * * journal_init_inode creates a journal which maps an on-disk inode as * the journal. The inode must exist already, must support bmap() and * must have all data blocks preallocated. @@ -763,7 +763,7 @@ journal_t * journal_init_inode (struct inode *inode) journal->j_inode = inode; jbd_debug(1, "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n", - journal, inode->i_sb->s_id, inode->i_ino, + journal, inode->i_sb->s_id, inode->i_ino, (long long) inode->i_size, inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize); @@ -798,10 +798,10 @@ journal_t * journal_init_inode (struct inode *inode) return journal; } -/* +/* * If the journal init or create aborts, we need to mark the journal * superblock as being NULL to prevent the journal destroy from writing - * back a bogus superblock. + * back a bogus superblock. */ static void journal_fail_superblock (journal_t *journal) { @@ -844,13 +844,13 @@ static int journal_reset(journal_t *journal) return 0; } -/** +/** * int journal_create() - Initialise the new journal file * @journal: Journal to create. This structure must have been initialised - * + * * Given a journal_t structure which tells us which disk blocks we can * use, create a new journal superblock and initialise all of the - * journal fields from scratch. + * journal fields from scratch. **/ int journal_create(journal_t *journal) { @@ -915,7 +915,7 @@ int journal_create(journal_t *journal) return journal_reset(journal); } -/** +/** * void journal_update_superblock() - Update journal sb on disk. * @journal: The journal to update. * @wait: Set to '0' if you don't want to wait for IO completion. @@ -939,7 +939,7 @@ void journal_update_superblock(journal_t *journal, int wait) journal->j_transaction_sequence) { jbd_debug(1,"JBD: Skipping superblock update on recovered sb " "(start %ld, seq %d, errno %d)\n", - journal->j_tail, journal->j_tail_sequence, + journal->j_tail, journal->j_tail_sequence, journal->j_errno); goto out; } @@ -1062,7 +1062,7 @@ static int load_superblock(journal_t *journal) /** * int journal_load() - Read journal from disk. * @journal: Journal to act on. - * + * * Given a journal_t structure which tells us which disk blocks contain * a journal, read the journal from disk to initialise the in-memory * structures. @@ -1172,9 +1172,9 @@ void journal_destroy(journal_t *journal) * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount * @incompat: bitmask of incompatible features - * + * * Check whether the journal uses all of a given set of - * features. Return true (non-zero) if it does. + * features. Return true (non-zero) if it does. **/ int journal_check_used_features (journal_t *journal, unsigned long compat, @@ -1203,7 +1203,7 @@ int journal_check_used_features (journal_t *journal, unsigned long compat, * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount * @incompat: bitmask of incompatible features - * + * * Check whether the journaling code supports the use of * all of a given set of features on this journal. Return true * (non-zero) if it can. */ @@ -1241,7 +1241,7 @@ int journal_check_available_features (journal_t *journal, unsigned long compat, * @incompat: bitmask of incompatible features * * Mark a given journal feature as present on the - * superblock. Returns true if the requested features could be set. + * superblock. Returns true if the requested features could be set. * */ @@ -1327,7 +1327,7 @@ static int journal_convert_superblock_v1(journal_t *journal, /** * int journal_flush () - Flush journal * @journal: Journal to act on. - * + * * Flush all data for a given journal to disk and empty the journal. * Filesystems can use this when remounting readonly to ensure that * recovery does not need to happen on remount. @@ -1394,7 +1394,7 @@ int journal_flush(journal_t *journal) * int journal_wipe() - Wipe journal contents * @journal: Journal to act on. * @write: flag (see below) - * + * * Wipe out all of the contents of a journal, safely. This will produce * a warning if the journal contains any valid recovery information. * Must be called between journal_init_*() and journal_load(). @@ -1449,7 +1449,7 @@ static const char *journal_dev_name(journal_t *journal, char *buffer) /* * Journal abort has very specific semantics, which we describe - * for journal abort. + * for journal abort. * * Two internal function, which provide abort to te jbd layer * itself are here. @@ -1504,7 +1504,7 @@ static void __journal_abort_soft (journal_t *journal, int errno) * Perform a complete, immediate shutdown of the ENTIRE * journal (not of a single transaction). This operation cannot be * undone without closing and reopening the journal. - * + * * The journal_abort function is intended to support higher level error * recovery mechanisms such as the ext2/ext3 remount-readonly error * mode. @@ -1538,7 +1538,7 @@ static void __journal_abort_soft (journal_t *journal, int errno) * supply an errno; a null errno implies that absolutely no further * writes are done to the journal (unless there are any already in * progress). - * + * */ void journal_abort(journal_t *journal, int errno) @@ -1546,7 +1546,7 @@ void journal_abort(journal_t *journal, int errno) __journal_abort_soft(journal, errno); } -/** +/** * int journal_errno () - returns the journal's error state. * @journal: journal to examine. * @@ -1570,7 +1570,7 @@ int journal_errno(journal_t *journal) return err; } -/** +/** * int journal_clear_err () - clears the journal's error state * @journal: journal to act on. * @@ -1590,7 +1590,7 @@ int journal_clear_err(journal_t *journal) return err; } -/** +/** * void journal_ack_err() - Ack journal err. * @journal: journal to act on. * @@ -1612,7 +1612,7 @@ int journal_blocks_per_page(struct inode *inode) /* * Simple support for retrying memory allocations. Introduced to help to - * debug different VM deadlock avoidance strategies. + * debug different VM deadlock avoidance strategies. */ void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry) { diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index de5bafb4e853..73bb64806ed3 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -1,6 +1,6 @@ /* * linux/fs/recovery.c - * + * * Written by Stephen C. Tweedie , 1999 * * Copyright 1999-2000 Red Hat Software --- All Rights Reserved @@ -10,7 +10,7 @@ * option, any later version, incorporated herein by reference. * * Journal recovery routines for the generic filesystem journaling code; - * part of the ext2fs journaling system. + * part of the ext2fs journaling system. */ #ifndef __KERNEL__ @@ -25,9 +25,9 @@ /* * Maintain information about the progress of the recovery job, so that - * the different passes can carry information between them. + * the different passes can carry information between them. */ -struct recovery_info +struct recovery_info { tid_t start_transaction; tid_t end_transaction; @@ -116,7 +116,7 @@ static int do_readahead(journal_t *journal, unsigned int start) err = 0; failed: - if (nbufs) + if (nbufs) journal_brelse_array(bufs, nbufs); return err; } @@ -128,7 +128,7 @@ failed: * Read a block from the journal */ -static int jread(struct buffer_head **bhp, journal_t *journal, +static int jread(struct buffer_head **bhp, journal_t *journal, unsigned int offset) { int err; @@ -212,14 +212,14 @@ do { \ /** * journal_recover - recovers a on-disk journal * @journal: the journal to recover - * + * * The primary function for recovering the log contents when mounting a - * journaled device. + * journaled device. * * Recovery is done in three passes. In the first pass, we look for the * end of the log. In the second, we assemble the list of revoke * blocks. In the third and final pass, we replay any un-revoked blocks - * in the log. + * in the log. */ int journal_recover(journal_t *journal) { @@ -231,10 +231,10 @@ int journal_recover(journal_t *journal) memset(&info, 0, sizeof(info)); sb = journal->j_superblock; - /* + /* * The journal superblock's s_start field (the current log head) * is always zero if, and only if, the journal was cleanly - * unmounted. + * unmounted. */ if (!sb->s_start) { @@ -253,7 +253,7 @@ int journal_recover(journal_t *journal) jbd_debug(0, "JBD: recovery, exit status %d, " "recovered transactions %u to %u\n", err, info.start_transaction, info.end_transaction); - jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n", + jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n", info.nr_replays, info.nr_revoke_hits, info.nr_revokes); /* Restart the log at the next transaction ID, thus invalidating @@ -268,15 +268,15 @@ int journal_recover(journal_t *journal) /** * journal_skip_recovery - Start journal and wipe exiting records * @journal: journal to startup - * + * * Locate any valid recovery information from the journal and set up the * journal structures in memory to ignore it (presumably because the - * caller has evidence that it is out of date). + * caller has evidence that it is out of date). * This function does'nt appear to be exorted.. * * We perform one pass over the journal to allow us to tell the user how * much recovery information is being erased, and to let us initialise - * the journal transaction sequence numbers to the next unused ID. + * the journal transaction sequence numbers to the next unused ID. */ int journal_skip_recovery(journal_t *journal) { @@ -297,7 +297,7 @@ int journal_skip_recovery(journal_t *journal) #ifdef CONFIG_JBD_DEBUG int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence); #endif - jbd_debug(0, + jbd_debug(0, "JBD: ignoring %d transaction%s from the journal.\n", dropped, (dropped == 1) ? "" : "s"); journal->j_transaction_sequence = ++info.end_transaction; @@ -324,10 +324,10 @@ static int do_one_pass(journal_t *journal, MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t)) / sizeof(journal_block_tag_t)); - /* + /* * First thing is to establish what we expect to find in the log * (in terms of transaction IDs), and where (in terms of log - * block offsets): query the superblock. + * block offsets): query the superblock. */ sb = journal->j_superblock; @@ -344,7 +344,7 @@ static int do_one_pass(journal_t *journal, * Now we walk through the log, transaction by transaction, * making sure that each transaction has a commit block in the * expected place. Each complete transaction gets replayed back - * into the main filesystem. + * into the main filesystem. */ while (1) { @@ -379,8 +379,8 @@ static int do_one_pass(journal_t *journal, next_log_block++; wrap(journal, next_log_block); - /* What kind of buffer is it? - * + /* What kind of buffer is it? + * * If it is a descriptor block, check that it has the * expected sequence number. Otherwise, we're all done * here. */ @@ -394,7 +394,7 @@ static int do_one_pass(journal_t *journal, blocktype = be32_to_cpu(tmp->h_blocktype); sequence = be32_to_cpu(tmp->h_sequence); - jbd_debug(3, "Found magic %d, sequence %d\n", + jbd_debug(3, "Found magic %d, sequence %d\n", blocktype, sequence); if (sequence != next_commit_ID) { @@ -438,7 +438,7 @@ static int do_one_pass(journal_t *journal, /* Recover what we can, but * report failure at the end. */ success = err; - printk (KERN_ERR + printk (KERN_ERR "JBD: IO error %d recovering " "block %ld in log\n", err, io_block); @@ -452,7 +452,7 @@ static int do_one_pass(journal_t *journal, * revoked, then we're all done * here. */ if (journal_test_revoke - (journal, blocknr, + (journal, blocknr, next_commit_ID)) { brelse(obh); ++info->nr_revoke_hits; @@ -465,7 +465,7 @@ static int do_one_pass(journal_t *journal, blocknr, journal->j_blocksize); if (nbh == NULL) { - printk(KERN_ERR + printk(KERN_ERR "JBD: Out of memory " "during recovery.\n"); err = -ENOMEM; @@ -537,7 +537,7 @@ static int do_one_pass(journal_t *journal, } done: - /* + /* * We broke out of the log scan loop: either we came to the * known end of the log or we found an unexpected block in the * log. If the latter happened, then we know that the "current" @@ -567,7 +567,7 @@ static int do_one_pass(journal_t *journal, /* Scan a revoke record, marking all blocks mentioned as revoked. */ -static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, +static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, tid_t sequence, struct recovery_info *info) { journal_revoke_header_t *header; diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index a56144183462..c532429d8d9b 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -1,6 +1,6 @@ /* * linux/fs/revoke.c - * + * * Written by Stephen C. Tweedie , 2000 * * Copyright 2000 Red Hat corp --- All Rights Reserved @@ -15,10 +15,10 @@ * Revoke is the mechanism used to prevent old log records for deleted * metadata from being replayed on top of newer data using the same * blocks. The revoke mechanism is used in two separate places: - * + * * + Commit: during commit we write the entire list of the current * transaction's revoked blocks to the journal - * + * * + Recovery: during recovery we record the transaction ID of all * revoked blocks. If there are multiple revoke records in the log * for a single block, only the last one counts, and if there is a log @@ -29,7 +29,7 @@ * single transaction: * * Block is revoked and then journaled: - * The desired end result is the journaling of the new block, so we + * The desired end result is the journaling of the new block, so we * cancel the revoke before the transaction commits. * * Block is journaled and then revoked: @@ -41,7 +41,7 @@ * transaction must have happened after the block was journaled and so * the revoke must take precedence. * - * Block is revoked and then written as data: + * Block is revoked and then written as data: * The data write is allowed to succeed, but the revoke is _not_ * cancelled. We still need to prevent old log records from * overwriting the new data. We don't even need to clear the revoke @@ -54,7 +54,7 @@ * buffer has not been revoked, and cancel_revoke * need do nothing. * RevokeValid set, Revoked set: - * buffer has been revoked. + * buffer has been revoked. */ #ifndef __KERNEL__ @@ -77,7 +77,7 @@ static kmem_cache_t *revoke_table_cache; journal replay, this involves recording the transaction ID of the last transaction to revoke this block. */ -struct jbd_revoke_record_s +struct jbd_revoke_record_s { struct list_head hash; tid_t sequence; /* Used for recovery only */ @@ -90,8 +90,8 @@ struct jbd_revoke_table_s { /* It is conceivable that we might want a larger hash table * for recovery. Must be a power of two. */ - int hash_size; - int hash_shift; + int hash_size; + int hash_shift; struct list_head *hash_table; }; @@ -301,22 +301,22 @@ void journal_destroy_revoke(journal_t *journal) #ifdef __KERNEL__ -/* +/* * journal_revoke: revoke a given buffer_head from the journal. This * prevents the block from being replayed during recovery if we take a * crash after this current transaction commits. Any subsequent * metadata writes of the buffer in this transaction cancel the - * revoke. + * revoke. * * Note that this call may block --- it is up to the caller to make * sure that there are no further calls to journal_write_metadata * before the revoke is complete. In ext3, this implies calling the * revoke before clearing the block bitmap when we are deleting - * metadata. + * metadata. * * Revoke performs a journal_forget on any buffer_head passed in as a * parameter, but does _not_ forget the buffer_head if the bh was only - * found implicitly. + * found implicitly. * * bh_in may not be a journalled buffer - it may have come off * the hash tables without an attached journal_head. @@ -325,7 +325,7 @@ void journal_destroy_revoke(journal_t *journal) * by one. */ -int journal_revoke(handle_t *handle, unsigned long blocknr, +int journal_revoke(handle_t *handle, unsigned long blocknr, struct buffer_head *bh_in) { struct buffer_head *bh = NULL; @@ -487,7 +487,7 @@ void journal_switch_revoke_table(journal_t *journal) else journal->j_revoke = journal->j_revoke_table[0]; - for (i = 0; i < journal->j_revoke->hash_size; i++) + for (i = 0; i < journal->j_revoke->hash_size; i++) INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]); } @@ -498,7 +498,7 @@ void journal_switch_revoke_table(journal_t *journal) * Called with the journal lock held. */ -void journal_write_revoke_records(journal_t *journal, +void journal_write_revoke_records(journal_t *journal, transaction_t *transaction) { struct journal_head *descriptor; @@ -507,7 +507,7 @@ void journal_write_revoke_records(journal_t *journal, struct list_head *hash_list; int i, offset, count; - descriptor = NULL; + descriptor = NULL; offset = 0; count = 0; @@ -519,10 +519,10 @@ void journal_write_revoke_records(journal_t *journal, hash_list = &revoke->hash_table[i]; while (!list_empty(hash_list)) { - record = (struct jbd_revoke_record_s *) + record = (struct jbd_revoke_record_s *) hash_list->next; write_one_revoke_record(journal, transaction, - &descriptor, &offset, + &descriptor, &offset, record); count++; list_del(&record->hash); @@ -534,14 +534,14 @@ void journal_write_revoke_records(journal_t *journal, jbd_debug(1, "Wrote %d revoke records\n", count); } -/* +/* * Write out one revoke record. We need to create a new descriptor - * block if the old one is full or if we have not already created one. + * block if the old one is full or if we have not already created one. */ -static void write_one_revoke_record(journal_t *journal, +static void write_one_revoke_record(journal_t *journal, transaction_t *transaction, - struct journal_head **descriptorp, + struct journal_head **descriptorp, int *offsetp, struct jbd_revoke_record_s *record) { @@ -584,21 +584,21 @@ static void write_one_revoke_record(journal_t *journal, *descriptorp = descriptor; } - * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) = + * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) = cpu_to_be32(record->blocknr); offset += 4; *offsetp = offset; } -/* +/* * Flush a revoke descriptor out to the journal. If we are aborting, * this is a noop; otherwise we are generating a buffer which needs to * be waited for during commit, so it has to go onto the appropriate * journal buffer list. */ -static void flush_descriptor(journal_t *journal, - struct journal_head *descriptor, +static void flush_descriptor(journal_t *journal, + struct journal_head *descriptor, int offset) { journal_revoke_header_t *header; @@ -618,7 +618,7 @@ static void flush_descriptor(journal_t *journal, } #endif -/* +/* * Revoke support for recovery. * * Recovery needs to be able to: @@ -629,7 +629,7 @@ static void flush_descriptor(journal_t *journal, * check whether a given block in a given transaction should be replayed * (ie. has not been revoked by a revoke record in that or a subsequent * transaction) - * + * * empty the revoke table after recovery. */ @@ -637,11 +637,11 @@ static void flush_descriptor(journal_t *journal, * First, setting revoke records. We create a new revoke record for * every block ever revoked in the log as we scan it for recovery, and * we update the existing records if we find multiple revokes for a - * single block. + * single block. */ -int journal_set_revoke(journal_t *journal, - unsigned long blocknr, +int journal_set_revoke(journal_t *journal, + unsigned long blocknr, tid_t sequence) { struct jbd_revoke_record_s *record; @@ -653,18 +653,18 @@ int journal_set_revoke(journal_t *journal, if (tid_gt(sequence, record->sequence)) record->sequence = sequence; return 0; - } + } return insert_revoke_hash(journal, blocknr, sequence); } -/* +/* * Test revoke records. For a given block referenced in the log, has * that block been revoked? A revoke record with a given transaction * sequence number revokes all blocks in that transaction and earlier * ones, but later transactions still need replayed. */ -int journal_test_revoke(journal_t *journal, +int journal_test_revoke(journal_t *journal, unsigned long blocknr, tid_t sequence) { diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index f5169a96260e..bf7fd7117817 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1,6 +1,6 @@ /* * linux/fs/transaction.c - * + * * Written by Stephen C. Tweedie , 1998 * * Copyright 1998 Red Hat corp --- All Rights Reserved @@ -10,7 +10,7 @@ * option, any later version, incorporated herein by reference. * * Generic filesystem transaction handling code; part of the ext2fs - * journaling system. + * journaling system. * * This file manages transactions (compound commits managed by the * journaling code) and handles (individual atomic operations by the @@ -74,7 +74,7 @@ get_transaction(journal_t *journal, transaction_t *transaction) * start_this_handle: Given a handle, deal with any locking or stalling * needed to make sure that there is enough journal space for the handle * to begin. Attach the handle to a transaction and set up the - * transaction's buffer credits. + * transaction's buffer credits. */ static int start_this_handle(journal_t *journal, handle_t *handle) @@ -117,7 +117,7 @@ repeat_locked: if (is_journal_aborted(journal) || (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) { spin_unlock(&journal->j_state_lock); - ret = -EROFS; + ret = -EROFS; goto out; } @@ -182,7 +182,7 @@ repeat_locked: goto repeat; } - /* + /* * The commit code assumes that it can get enough log space * without forcing a checkpoint. This is *critical* for * correctness: a checkpoint of a buffer which is also @@ -191,7 +191,7 @@ repeat_locked: * * We must therefore ensure the necessary space in the journal * *before* starting to dirty potentially checkpointed buffers - * in the new transaction. + * in the new transaction. * * The worst part is, any transaction currently committing can * reduce the free space arbitrarily. Be careful to account for @@ -246,13 +246,13 @@ static handle_t *new_handle(int nblocks) } /** - * handle_t *journal_start() - Obtain a new handle. + * handle_t *journal_start() - Obtain a new handle. * @journal: Journal to start transaction on. * @nblocks: number of block buffer we might modify * * We make sure that the transaction can guarantee at least nblocks of * modified buffers in the log. We block until the log can guarantee - * that much space. + * that much space. * * This function is visible to journal users (like ext3fs), so is not * called with the journal already locked. @@ -292,11 +292,11 @@ handle_t *journal_start(journal_t *journal, int nblocks) * int journal_extend() - extend buffer credits. * @handle: handle to 'extend' * @nblocks: nr blocks to try to extend by. - * + * * Some transactions, such as large extends and truncates, can be done * atomically all at once or in several stages. The operation requests * a credit for a number of buffer modications in advance, but can - * extend its credit if it needs more. + * extend its credit if it needs more. * * journal_extend tries to give the running handle more buffer credits. * It does not guarantee that allocation - this is a best-effort only. @@ -363,7 +363,7 @@ out: * int journal_restart() - restart a handle . * @handle: handle to restart * @nblocks: nr credits requested - * + * * Restart a handle for a multi-transaction filesystem * operation. * @@ -462,7 +462,7 @@ void journal_lock_updates(journal_t *journal) /** * void journal_unlock_updates (journal_t* journal) - release barrier * @journal: Journal to release the barrier on. - * + * * Release a transaction barrier obtained with journal_lock_updates(). * * Should be called without the journal lock held. @@ -547,8 +547,8 @@ repeat: jbd_lock_bh_state(bh); /* We now hold the buffer lock so it is safe to query the buffer - * state. Is the buffer dirty? - * + * state. Is the buffer dirty? + * * If so, there are two possibilities. The buffer may be * non-journaled, and undergoing a quite legitimate writeback. * Otherwise, it is journaled, and we don't expect dirty buffers @@ -566,7 +566,7 @@ repeat: */ if (jh->b_transaction) { J_ASSERT_JH(jh, - jh->b_transaction == transaction || + jh->b_transaction == transaction || jh->b_transaction == journal->j_committing_transaction); if (jh->b_next_transaction) @@ -653,7 +653,7 @@ repeat: * buffer had better remain locked during the kmalloc, * but that should be true --- we hold the journal lock * still and the buffer is already on the BUF_JOURNAL - * list so won't be flushed. + * list so won't be flushed. * * Subtle point, though: if this is a get_undo_access, * then we will be relying on the frozen_data to contain @@ -765,8 +765,8 @@ int journal_get_write_access(handle_t *handle, struct buffer_head *bh) * manually rather than reading off disk), then we need to keep the * buffer_head locked until it has been completely filled with new * data. In this case, we should be able to make the assertion that - * the bh is not already part of an existing transaction. - * + * the bh is not already part of an existing transaction. + * * The buffer should already be locked by the caller by this point. * There is no lock ranking violation: it was a newly created, * unlocked buffer beforehand. */ @@ -778,7 +778,7 @@ int journal_get_write_access(handle_t *handle, struct buffer_head *bh) * * Call this if you create a new bh. */ -int journal_get_create_access(handle_t *handle, struct buffer_head *bh) +int journal_get_create_access(handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -847,13 +847,13 @@ out: * do not reuse freed space until the deallocation has been committed, * since if we overwrote that space we would make the delete * un-rewindable in case of a crash. - * + * * To deal with that, journal_get_undo_access requests write access to a * buffer for parts of non-rewindable operations such as delete * operations on the bitmaps. The journaling code must keep a copy of * the buffer's contents prior to the undo_access call until such time * as we know that the buffer has definitely been committed to disk. - * + * * We never need to know which transaction the committed data is part * of, buffers touched here are guaranteed to be dirtied later and so * will be committed to a new transaction in due course, at which point @@ -911,13 +911,13 @@ out: return err; } -/** +/** * int journal_dirty_data() - mark a buffer as containing dirty data which * needs to be flushed before we can commit the - * current transaction. + * current transaction. * @handle: transaction * @bh: bufferhead to mark - * + * * The buffer is placed on the transaction's data list and is marked as * belonging to the transaction. * @@ -946,15 +946,15 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh) /* * What if the buffer is already part of a running transaction? - * + * * There are two cases: * 1) It is part of the current running transaction. Refile it, * just in case we have allocated it as metadata, deallocated - * it, then reallocated it as data. + * it, then reallocated it as data. * 2) It is part of the previous, still-committing transaction. * If all we want to do is to guarantee that the buffer will be * written to disk before this new transaction commits, then - * being sure that the *previous* transaction has this same + * being sure that the *previous* transaction has this same * property is sufficient for us! Just leave it on its old * transaction. * @@ -1076,18 +1076,18 @@ no_journal: return 0; } -/** +/** * int journal_dirty_metadata() - mark a buffer as containing dirty metadata * @handle: transaction to add buffer to. - * @bh: buffer to mark - * + * @bh: buffer to mark + * * mark dirty metadata which needs to be journaled as part of the current * transaction. * * The buffer is placed on the transaction's metadata list and is marked - * as belonging to the transaction. + * as belonging to the transaction. * - * Returns error number or 0 on success. + * Returns error number or 0 on success. * * Special care needs to be taken if the buffer already belongs to the * current committing transaction (in which case we should have frozen @@ -1135,11 +1135,11 @@ int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) set_buffer_jbddirty(bh); - /* + /* * Metadata already on the current transaction list doesn't * need to be filed. Metadata on another transaction's list must * be committing, and will be refiled once the commit completes: - * leave it alone for now. + * leave it alone for now. */ if (jh->b_transaction != transaction) { JBUFFER_TRACE(jh, "already on other transaction"); @@ -1165,7 +1165,7 @@ out: return 0; } -/* +/* * journal_release_buffer: undo a get_write_access without any buffer * updates, if the update decided in the end that it didn't need access. * @@ -1176,20 +1176,20 @@ journal_release_buffer(handle_t *handle, struct buffer_head *bh) BUFFER_TRACE(bh, "entry"); } -/** +/** * void journal_forget() - bforget() for potentially-journaled buffers. * @handle: transaction handle * @bh: bh to 'forget' * * We can only do the bforget if there are no commits pending against the * buffer. If the buffer is dirty in the current running transaction we - * can safely unlink it. + * can safely unlink it. * * bh may not be a journalled buffer at all - it may be a non-JBD * buffer which came off the hashtable. Check for this. * * Decrements bh->b_count by one. - * + * * Allow this call even if the handle has aborted --- it may be part of * the caller's cleanup after an abort. */ @@ -1237,7 +1237,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh) drop_reserve = 1; - /* + /* * We are no longer going to journal this buffer. * However, the commit of this transaction is still * important to the buffer: the delete that we are now @@ -1246,7 +1246,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh) * * So, if we have a checkpoint on the buffer, we should * now refile the buffer on our BJ_Forget list so that - * we know to remove the checkpoint after we commit. + * we know to remove the checkpoint after we commit. */ if (jh->b_cp_transaction) { @@ -1264,7 +1264,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh) } } } else if (jh->b_transaction) { - J_ASSERT_JH(jh, (jh->b_transaction == + J_ASSERT_JH(jh, (jh->b_transaction == journal->j_committing_transaction)); /* However, if the buffer is still owned by a prior * (committing) transaction, we can't drop it yet... */ @@ -1294,7 +1294,7 @@ drop: /** * int journal_stop() - complete a transaction * @handle: tranaction to complete. - * + * * All done for a particular handle. * * There is not much action needed here. We just return any remaining @@ -1303,7 +1303,7 @@ drop: * filesystem is marked for synchronous update. * * journal_stop itself will not usually return an error, but it may - * do so in unusual circumstances. In particular, expect it to + * do so in unusual circumstances. In particular, expect it to * return -EIO if a journal_abort has been executed since the * transaction began. */ @@ -1388,7 +1388,7 @@ int journal_stop(handle_t *handle) /* * Special case: JFS_SYNC synchronous updates require us - * to wait for the commit to complete. + * to wait for the commit to complete. */ if (handle->h_sync && !(current->flags & PF_MEMALLOC)) err = log_wait_commit(journal, tid); @@ -1439,7 +1439,7 @@ int journal_force_commit(journal_t *journal) * jbd_lock_bh_state(jh2bh(jh)) is held. */ -static inline void +static inline void __blist_add_buffer(struct journal_head **list, struct journal_head *jh) { if (!*list) { @@ -1454,7 +1454,7 @@ __blist_add_buffer(struct journal_head **list, struct journal_head *jh) } } -/* +/* * Remove a buffer from a transaction list, given the transaction's list * head pointer. * @@ -1475,7 +1475,7 @@ __blist_del_buffer(struct journal_head **list, struct journal_head *jh) jh->b_tnext->b_tprev = jh->b_tprev; } -/* +/* * Remove a buffer from the appropriate transaction list. * * Note that this function can *change* the value of @@ -1595,17 +1595,17 @@ out: } -/** +/** * int journal_try_to_free_buffers() - try to free page buffers. * @journal: journal for operation * @page: to try and free * @unused_gfp_mask: unused * - * + * * For all the buffers on this page, * if they are fully written out ordered data, move them onto BUF_CLEAN * so try_to_free_buffers() can reap them. - * + * * This function returns non-zero if we wish try_to_free_buffers() * to be called. We do this if the page is releasable by try_to_free_buffers(). * We also do it if the page has locked or dirty buffers and the caller wants @@ -1629,7 +1629,7 @@ out: * cannot happen because we never reallocate freed data as metadata * while the data is part of a transaction. Yes? */ -int journal_try_to_free_buffers(journal_t *journal, +int journal_try_to_free_buffers(journal_t *journal, struct page *page, gfp_t unused_gfp_mask) { struct buffer_head *head; @@ -1697,7 +1697,7 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) } /* - * journal_invalidatepage + * journal_invalidatepage * * This code is tricky. It has a number of cases to deal with. * @@ -1705,15 +1705,15 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) * * i_size must be updated on disk before we start calling invalidatepage on the * data. - * + * * This is done in ext3 by defining an ext3_setattr method which * updates i_size before truncate gets going. By maintaining this * invariant, we can be sure that it is safe to throw away any buffers * attached to the current transaction: once the transaction commits, * we know that the data will not be needed. - * + * * Note however that we can *not* throw away data belonging to the - * previous, committing transaction! + * previous, committing transaction! * * Any disk blocks which *are* part of the previous, committing * transaction (and which therefore cannot be discarded immediately) are @@ -1732,7 +1732,7 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) * don't make guarantees about the order in which data hits disk --- in * particular we don't guarantee that new dirty data is flushed before * transaction commit --- so it is always safe just to discard data - * immediately in that mode. --sct + * immediately in that mode. --sct */ /* @@ -1876,9 +1876,9 @@ zap_buffer_unlocked: return may_free; } -/** +/** * void journal_invalidatepage() - * @journal: journal to use for flush... + * @journal: journal to use for flush... * @page: page to flush * @offset: length of page to invalidate. * @@ -1886,7 +1886,7 @@ zap_buffer_unlocked: * */ void journal_invalidatepage(journal_t *journal, - struct page *page, + struct page *page, unsigned long offset) { struct buffer_head *head, *bh, *next; @@ -1924,8 +1924,8 @@ void journal_invalidatepage(journal_t *journal, } } -/* - * File a buffer on the given transaction list. +/* + * File a buffer on the given transaction list. */ void __journal_file_buffer(struct journal_head *jh, transaction_t *transaction, int jlist) @@ -1948,7 +1948,7 @@ void __journal_file_buffer(struct journal_head *jh, * with __jbd_unexpected_dirty_buffer()'s handling of dirty * state. */ - if (jlist == BJ_Metadata || jlist == BJ_Reserved || + if (jlist == BJ_Metadata || jlist == BJ_Reserved || jlist == BJ_Shadow || jlist == BJ_Forget) { if (test_clear_buffer_dirty(bh) || test_clear_buffer_jbddirty(bh)) @@ -2008,7 +2008,7 @@ void journal_file_buffer(struct journal_head *jh, jbd_unlock_bh_state(jh2bh(jh)); } -/* +/* * Remove a buffer from its current buffer list in preparation for * dropping it from its current transaction entirely. If the buffer has * already started to be used by a subsequent transaction, refile the @@ -2060,7 +2060,7 @@ void __journal_refile_buffer(struct journal_head *jh) * to the caller to remove the journal_head if necessary. For the * unlocked journal_refile_buffer call, the caller isn't going to be * doing anything else to the buffer so we need to do the cleanup - * ourselves to avoid a jh leak. + * ourselves to avoid a jh leak. * * *** The journal_head may be freed by this call! *** */ diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h index c8307c02dd07..ce0e6109aff0 100644 --- a/include/linux/ext3_jbd.h +++ b/include/linux/ext3_jbd.h @@ -23,7 +23,7 @@ /* Define the number of blocks we need to account to a transaction to * modify one block of data. - * + * * We may have to touch one inode, one bitmap buffer, up to three * indirection blocks, the group and superblock summaries, and the data * block to complete the transaction. */ @@ -88,16 +88,16 @@ #endif int -ext3_mark_iloc_dirty(handle_t *handle, +ext3_mark_iloc_dirty(handle_t *handle, struct inode *inode, struct ext3_iloc *iloc); -/* +/* * On success, We end up with an outstanding reference count against - * iloc->bh. This _must_ be cleaned up later. + * iloc->bh. This _must_ be cleaned up later. */ -int ext3_reserve_inode_write(handle_t *handle, struct inode *inode, +int ext3_reserve_inode_write(handle_t *handle, struct inode *inode, struct ext3_iloc *iloc); int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode); diff --git a/include/linux/jbd.h b/include/linux/jbd.h index a04c154c5207..7d847931ee5a 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -1,6 +1,6 @@ /* * linux/include/linux/jbd.h - * + * * Written by Stephen C. Tweedie * * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved @@ -97,8 +97,8 @@ extern void jbd_slab_free(void *ptr, size_t size); * number of outstanding buffers possible at any time. When the * operation completes, any buffer credits not used are credited back to * the transaction, so that at all times we know how many buffers the - * outstanding updates on a transaction might possibly touch. - * + * outstanding updates on a transaction might possibly touch. + * * This is an opaque datatype. **/ typedef struct handle_s handle_t; /* Atomic operation type */ @@ -108,7 +108,7 @@ typedef struct handle_s handle_t; /* Atomic operation type */ * typedef journal_t - The journal_t maintains all of the journaling state information for a single filesystem. * * journal_t is linked to from the fs superblock structure. - * + * * We use the journal_t to keep track of all outstanding transaction * activity on the filesystem, and to manage the state of the log * writing process. @@ -128,7 +128,7 @@ typedef struct journal_s journal_t; /* Journal control structure */ * On-disk structures */ -/* +/* * Descriptor block types: */ @@ -149,8 +149,8 @@ typedef struct journal_header_s } journal_header_t; -/* - * The block tag: used to describe a single buffer in the journal +/* + * The block tag: used to describe a single buffer in the journal */ typedef struct journal_block_tag_s { @@ -158,9 +158,9 @@ typedef struct journal_block_tag_s __be32 t_flags; /* See below */ } journal_block_tag_t; -/* +/* * The revoke descriptor: used on disk to describe a series of blocks to - * be revoked from the log + * be revoked from the log */ typedef struct journal_revoke_header_s { @@ -374,10 +374,10 @@ struct jbd_revoke_table_s; **/ /* Docbook can't yet cope with the bit fields, but will leave the documentation - * in so it can be fixed later. + * in so it can be fixed later. */ -struct handle_s +struct handle_s { /* Which compound transaction is this update a part of? */ transaction_t *h_transaction; @@ -435,7 +435,7 @@ struct handle_s * */ -struct transaction_s +struct transaction_s { /* Pointer to the journal for this transaction. [no locking] */ journal_t *t_journal; @@ -455,7 +455,7 @@ struct transaction_s T_RUNDOWN, T_FLUSH, T_COMMIT, - T_FINISHED + T_FINISHED } t_state; /* @@ -569,7 +569,7 @@ struct transaction_s * journal_t. * @j_flags: General journaling state flags * @j_errno: Is there an outstanding uncleared error on the journal (from a - * prior abort)? + * prior abort)? * @j_sb_buffer: First part of superblock buffer * @j_superblock: Second part of superblock buffer * @j_format_version: Version of the superblock format @@ -583,7 +583,7 @@ struct transaction_s * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction * to start committing, or for a barrier lock to be released * @j_wait_logspace: Wait queue for waiting for checkpointing to complete - * @j_wait_done_commit: Wait queue for waiting for commit to complete + * @j_wait_done_commit: Wait queue for waiting for commit to complete * @j_wait_checkpoint: Wait queue to trigger checkpointing * @j_wait_commit: Wait queue to trigger commit * @j_wait_updates: Wait queue to wait for updates to complete @@ -592,7 +592,7 @@ struct transaction_s * @j_tail: Journal tail - identifies the oldest still-used block in the * journal. * @j_free: Journal free - how many free blocks are there in the journal? - * @j_first: The block number of the first usable block + * @j_first: The block number of the first usable block * @j_last: The block number one beyond the last usable block * @j_dev: Device where we store the journal * @j_blocksize: blocksize for the location where we store the journal. @@ -604,12 +604,12 @@ struct transaction_s * @j_list_lock: Protects the buffer lists and internal buffer state. * @j_inode: Optional inode where we store the journal. If present, all journal * block numbers are mapped into this inode via bmap(). - * @j_tail_sequence: Sequence number of the oldest transaction in the log + * @j_tail_sequence: Sequence number of the oldest transaction in the log * @j_transaction_sequence: Sequence number of the next transaction to grant * @j_commit_sequence: Sequence number of the most recently committed * transaction * @j_commit_request: Sequence number of the most recent transaction wanting - * commit + * commit * @j_uuid: Uuid of client object. * @j_task: Pointer to the current commit thread for this journal * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a @@ -823,8 +823,8 @@ struct journal_s void *j_private; }; -/* - * Journal flag definitions +/* + * Journal flag definitions */ #define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */ #define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */ @@ -833,7 +833,7 @@ struct journal_s #define JFS_LOADED 0x010 /* The journal superblock has been loaded */ #define JFS_BARRIER 0x020 /* Use IDE barriers */ -/* +/* * Function declarations for the journaling transaction and buffer * management */ @@ -862,7 +862,7 @@ int __journal_remove_checkpoint(struct journal_head *); void __journal_insert_checkpoint(struct journal_head *, transaction_t *); /* Buffer IO */ -extern int +extern int journal_write_metadata_buffer(transaction_t *transaction, struct journal_head *jh_in, struct journal_head **jh_out, @@ -890,7 +890,7 @@ static inline handle_t *journal_current_handle(void) /* The journaling code user interface: * * Create and destroy handles - * Register buffer modifications against the current transaction. + * Register buffer modifications against the current transaction. */ extern handle_t *journal_start(journal_t *, int nblocks); @@ -917,11 +917,11 @@ extern journal_t * journal_init_dev(struct block_device *bdev, int start, int len, int bsize); extern journal_t * journal_init_inode (struct inode *); extern int journal_update_format (journal_t *); -extern int journal_check_used_features +extern int journal_check_used_features (journal_t *, unsigned long, unsigned long, unsigned long); -extern int journal_check_available_features +extern int journal_check_available_features (journal_t *, unsigned long, unsigned long, unsigned long); -extern int journal_set_features +extern int journal_set_features (journal_t *, unsigned long, unsigned long, unsigned long); extern int journal_create (journal_t *); extern int journal_load (journal_t *journal); @@ -1015,7 +1015,7 @@ do { \ * bit, when set, indicates that we have had a fatal error somewhere, * either inside the journaling layer or indicated to us by the client * (eg. ext3), and that we and should not commit any further - * transactions. + * transactions. */ static inline int is_journal_aborted(journal_t *journal) @@ -1082,7 +1082,7 @@ static inline int jbd_space_needed(journal_t *journal) #define BJ_Reserved 7 /* Buffer is reserved for access by journal */ #define BJ_Locked 8 /* Locked for I/O during commit */ #define BJ_Types 9 - + extern int jbd_blocks_per_page(struct inode *inode); #ifdef __KERNEL__ -- cgit v1.2.3 From 37ed322290eb6d5cf2ab33915793ed4219eae1d6 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Wed, 27 Sep 2006 01:49:31 -0700 Subject: [PATCH] JBD: 16T fixes These are a few places I've found in jbd that look like they may not be 16T-safe, or consistent with the use of unsigned longs for block containers. Problems here would be somewhat hard to hit, would require journal blocks past the 8T boundary, which would not be terribly common. Still, should fix. (some of these have come from the ext4 work on jbd as well). I think there's one more possibility that the wrap() function may not be safe IF your last block in the journal butts right up against the 232 block boundary, but that seems like a VERY remote possibility, and I'm not worrying about it at this point. Signed-off-by: Eric Sandeen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd/journal.c | 6 +++--- include/linux/jbd.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 2613fca92740..88d970e09ce6 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -271,7 +271,7 @@ static void journal_kill_thread(journal_t *journal) int journal_write_metadata_buffer(transaction_t *transaction, struct journal_head *jh_in, struct journal_head **jh_out, - int blocknr) + unsigned long blocknr) { int need_copy_out = 0; int done_copy_out = 0; @@ -696,7 +696,7 @@ fail: * @bdev: Block device on which to create the journal * @fs_dev: Device which hold journalled filesystem for this journal. * @start: Block nr Start of journal. - * @len: Lenght of the journal in blocks. + * @len: Length of the journal in blocks. * @blocksize: blocksize of journalling device * @returns: a newly created journal_t * * @@ -820,7 +820,7 @@ static void journal_fail_superblock (journal_t *journal) static int journal_reset(journal_t *journal) { journal_superblock_t *sb = journal->j_superblock; - unsigned int first, last; + unsigned long first, last; first = be32_to_cpu(sb->s_first); last = be32_to_cpu(sb->s_maxlen); diff --git a/include/linux/jbd.h b/include/linux/jbd.h index 7d847931ee5a..dc262624efa5 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -732,7 +732,7 @@ struct journal_s */ struct block_device *j_dev; int j_blocksize; - unsigned int j_blk_offset; + unsigned long j_blk_offset; /* * Device which holds the client fs. For internal journal this will be @@ -866,7 +866,7 @@ extern int journal_write_metadata_buffer(transaction_t *transaction, struct journal_head *jh_in, struct journal_head **jh_out, - int blocknr); + unsigned long blocknr); /* Transaction locking */ extern void __wait_on_journal (journal_t *); -- cgit v1.2.3 From e9ad5620bfb901df8a7a2603c88689ededeecaf1 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 27 Sep 2006 01:49:35 -0700 Subject: [PATCH] ext3: More whitespace cleanups More white space cleanups in preparation of cloning ext4 from ext3. Removing spaces that precede a tab. Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/acl.c | 2 +- fs/ext3/balloc.c | 32 ++++++++++++++++---------------- fs/ext3/dir.c | 2 +- fs/ext3/hash.c | 2 +- fs/ext3/inode.c | 8 ++++---- fs/ext3/namei.c | 18 +++++++++--------- fs/ext3/super.c | 6 +++--- fs/jbd/checkpoint.c | 2 +- fs/jbd/journal.c | 2 +- fs/jbd/recovery.c | 2 +- fs/jbd/transaction.c | 6 +++--- include/linux/ext3_fs.h | 2 +- include/linux/ext3_fs_i.h | 2 +- include/linux/jbd.h | 10 +++++----- 14 files changed, 48 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 0d21d558b87a..92bf78221429 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -258,7 +258,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, default: return -EINVAL; } - if (acl) { + if (acl) { value = ext3_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index f1897feb18f4..c19be8fc3e51 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -40,7 +40,7 @@ /** * ext3_get_group_desc() -- load group descriptor from disk - * @sb: super block + * @sb: super block * @block_group: given block group * @bh: pointer to the buffer head to store the block * group descriptor @@ -355,7 +355,7 @@ void ext3_init_block_alloc_info(struct inode *inode) rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - /* + /* * if filesystem is mounted with NORESERVATION, the goal * reservation window size is set to zero to indicate * block reservation is off @@ -681,7 +681,7 @@ bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, jbd_lock_bh_state(bh); if (jh->b_committed_data) start = ext3_find_next_zero_bit(jh->b_committed_data, - maxblocks, next); + maxblocks, next); jbd_unlock_bh_state(bh); } return -1; @@ -790,10 +790,10 @@ claim_block(spinlock_t *lock, ext3_grpblk_t block, struct buffer_head *bh) * and at last, allocate the blocks by claiming the found free bit as allocated. * * To set the range of this allocation: - * if there is a reservation window, only try to allocate block(s) from the + * if there is a reservation window, only try to allocate block(s) from the * file's own reservation window; * Otherwise, the allocation range starts from the give goal block, ends at - * the block group's last block. + * the block group's last block. * * If we failed to allocate the desired block then we may end up crossing to a * new bitmap. In that case we must release write access to the old one via @@ -880,12 +880,12 @@ fail_access: } /** - * find_next_reservable_window(): + * find_next_reservable_window(): * find a reservable space within the given range. * It does not allocate the reservation window for now: * alloc_new_reservation() will do the work later. * - * @search_head: the head of the searching list; + * @search_head: the head of the searching list; * This is not necessarily the list head of the whole filesystem * * We have both head and start_block to assist the search @@ -893,12 +893,12 @@ fail_access: * but we will shift to the place where start_block is, * then start from there, when looking for a reservable space. * - * @size: the target new reservation window size + * @size: the target new reservation window size * - * @group_first_block: the first block we consider to start + * @group_first_block: the first block we consider to start * the real search from * - * @last_block: + * @last_block: * the maximum block number that our goal reservable space * could start from. This is normally the last block in this * group. The search will end when we found the start of next @@ -906,10 +906,10 @@ fail_access: * This could handle the cross boundary reservation window * request. * - * basically we search from the given range, rather than the whole - * reservation double linked list, (start_block, last_block) - * to find a free region that is of my size and has not - * been reserved. + * basically we search from the given range, rather than the whole + * reservation double linked list, (start_block, last_block) + * to find a free region that is of my size and has not + * been reserved. * */ static int find_next_reservable_window( @@ -962,7 +962,7 @@ static int find_next_reservable_window( /* * Found a reserveable space big enough. We could * have a reservation across the group boundary here - */ + */ break; } } @@ -998,7 +998,7 @@ static int find_next_reservable_window( } /** - * alloc_new_reservation()--allocate a new reservation window + * alloc_new_reservation()--allocate a new reservation window * * To make a new reservation, we search part of the filesystem * reservation list (the list that inside the group). We try to diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 6f9e5a523c87..4d97f437cd48 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -67,7 +67,7 @@ int ext3_check_dir_entry (const char * function, struct inode * dir, unsigned long offset) { const char * error_msg = NULL; - const int rlen = le16_to_cpu(de->rec_len); + const int rlen = le16_to_cpu(de->rec_len); if (rlen < EXT3_DIR_REC_LEN(1)) error_msg = "rec_len is smaller than minimal"; diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c index 7fa637cd322a..deeb27b5ba83 100644 --- a/fs/ext3/hash.c +++ b/fs/ext3/hash.c @@ -95,7 +95,7 @@ int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) __u32 minor_hash = 0; const char *p; int i; - __u32 in[8], buf[4]; + __u32 in[8], buf[4]; /* Initialize the default seed for the hash checksum functions */ buf[0] = 0x67452301; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 56665fab027d..c9fc15f8b609 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -13,11 +13,11 @@ * Copyright (C) 1991, 1992 Linus Torvalds * * Goal-directed block allocation by Stephen Tweedie - * (sct@redhat.com), 1993, 1998 + * (sct@redhat.com), 1993, 1998 * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 * 64-bit file support on 64-bit platforms by Jakub Jelinek - * (jj@sunsite.ms.mff.cuni.cz) + * (jj@sunsite.ms.mff.cuni.cz) * * Assorted race fixes, rewrite of ext3_get_block() by Al Viro, 2000 */ @@ -470,7 +470,7 @@ static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block, * ext3_blks_to_allocate: Look up the block map and count the number * of direct blocks need to be allocated for the given branch. * - * @branch: chain of indirect blocks + * @branch: chain of indirect blocks * @k: number of blocks need for indirect blocks * @blks: number of data blocks to be mapped. * @blocks_to_boundary: the offset in the indirect block @@ -1098,7 +1098,7 @@ static int walk_page_buffers( handle_t *handle, for ( bh = head, block_start = 0; ret == 0 && (bh != head || !block_start); - block_start = block_end, bh = next) + block_start = block_end, bh = next) { next = bh->b_this_page; block_end = block_start + blocksize; diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 70dc5206ebfa..85d132c37ee0 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -15,13 +15,13 @@ * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 * Directory entry file type support and forward compatibility hooks - * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998 + * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998 * Hash Tree Directory indexing (c) - * Daniel Phillips, 2001 + * Daniel Phillips, 2001 * Hash Tree Directory indexing porting - * Christopher Li, 2002 + * Christopher Li, 2002 * Hash Tree Directory indexing cleanup - * Theodore Ts'o, 2002 + * Theodore Ts'o, 2002 */ #include @@ -278,7 +278,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_ent ((char *) de - base)); } space += EXT3_DIR_REC_LEN(de->name_len); - names++; + names++; } de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); } @@ -1688,7 +1688,7 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry, retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -1816,7 +1816,7 @@ static int empty_dir (struct inode * inode) !le32_to_cpu(de1->inode) || strcmp (".", de->name) || strcmp ("..", de1->name)) { - ext3_warning (inode->i_sb, "empty_dir", + ext3_warning (inode->i_sb, "empty_dir", "bad directory (dir #%lu) - no `.' or `..'", inode->i_ino); brelse (bh); @@ -2129,7 +2129,7 @@ static int ext3_symlink (struct inode * dir, retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 + + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 + 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -2227,7 +2227,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, DQUOT_INIT(new_dentry->d_inode); handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); if (IS_ERR(handle)) return PTR_ERR(handle); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 4b526b496102..0544325d9d7e 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -734,8 +734,8 @@ static match_table_t tokens = { static ext3_fsblk_t get_sb_block(void **data) { - ext3_fsblk_t sb_block; - char *options = (char *) *data; + ext3_fsblk_t sb_block; + char *options = (char *) *data; if (!options || strncmp(options, "sb=", 3) != 0) return 1; /* Default location */ @@ -2740,7 +2740,7 @@ static int __init init_ext3_fs(void) out: destroy_inodecache(); out1: - exit_ext3_xattr(); + exit_ext3_xattr(); return err; } diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 961ada28db5e..0208cc7ac5d0 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -480,7 +480,7 @@ static int journal_clean_one_cp_list(struct journal_head *jh, int *released) if (!jh) return 0; - last_jh = jh->b_cpprev; + last_jh = jh->b_cpprev; do { jh = next_jh; next_jh = jh->b_cpnext; diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 88d970e09ce6..b571209d6a1e 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -181,7 +181,7 @@ loop: transaction->t_expires)) should_sleep = 0; if (journal->j_flags & JFS_UNMOUNT) - should_sleep = 0; + should_sleep = 0; if (should_sleep) { spin_unlock(&journal->j_state_lock); schedule(); diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index 73bb64806ed3..445eed6ce5dc 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -314,7 +314,7 @@ static int do_one_pass(journal_t *journal, unsigned long next_log_block; int err, success = 0; journal_superblock_t * sb; - journal_header_t * tmp; + journal_header_t * tmp; struct buffer_head * bh; unsigned int sequence; int blocktype; diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index bf7fd7117817..e1b3c8af4d17 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -580,7 +580,7 @@ repeat: */ JBUFFER_TRACE(jh, "Unexpected dirty buffer"); jbd_unexpected_dirty_buffer(jh); - } + } unlock_buffer(bh); @@ -1373,7 +1373,7 @@ int journal_stop(handle_t *handle) if (handle->h_sync || transaction->t_outstanding_credits > journal->j_max_transaction_buffers || - time_after_eq(jiffies, transaction->t_expires)) { + time_after_eq(jiffies, transaction->t_expires)) { /* Do this even for aborted journals: an abort still * completes the commit thread, it just doesn't write * anything to disk. */ @@ -1908,7 +1908,7 @@ void journal_invalidatepage(journal_t *journal, next = bh->b_this_page; if (offset <= curr_off) { - /* This block is wholly outside the truncation point */ + /* This block is wholly outside the truncation point */ lock_buffer(bh); may_free &= journal_unmap_buffer(journal, bh); unlock_buffer(bh); diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index 0eed918b3816..369c67502346 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -473,7 +473,7 @@ struct ext3_super_block { __u8 s_reserved_char_pad; __u16 s_reserved_word_pad; __le32 s_default_mount_opts; - __le32 s_first_meta_bg; /* First metablock block group */ + __le32 s_first_meta_bg; /* First metablock block group */ __u32 s_reserved[190]; /* Padding to the end of the block */ }; diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h index 2f18b9511f21..4395e5206746 100644 --- a/include/linux/ext3_fs_i.h +++ b/include/linux/ext3_fs_i.h @@ -35,7 +35,7 @@ struct ext3_reserve_window { }; struct ext3_reserve_window_node { - struct rb_node rsv_node; + struct rb_node rsv_node; __u32 rsv_goal_size; __u32 rsv_alloc_hit; struct ext3_reserve_window rsv_window; diff --git a/include/linux/jbd.h b/include/linux/jbd.h index dc262624efa5..a6d9daa38c6d 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -64,7 +64,7 @@ extern int journal_enable_debug; if ((n) <= journal_enable_debug) { \ printk (KERN_DEBUG "(%s, %d): %s: ", \ __FILE__, __LINE__, __FUNCTION__); \ - printk (f, ## a); \ + printk (f, ## a); \ } \ } while (0) #else @@ -201,9 +201,9 @@ typedef struct journal_superblock_s /* 0x0024 */ /* Remaining fields are only valid in a version-2 superblock */ - __be32 s_feature_compat; /* compatible feature set */ - __be32 s_feature_incompat; /* incompatible feature set */ - __be32 s_feature_ro_compat; /* readonly-compatible feature set */ + __be32 s_feature_compat; /* compatible feature set */ + __be32 s_feature_incompat; /* incompatible feature set */ + __be32 s_feature_ro_compat; /* readonly-compatible feature set */ /* 0x0030 */ __u8 s_uuid[16]; /* 128-bit uuid for journal */ @@ -699,7 +699,7 @@ struct journal_s wait_queue_head_t j_wait_updates; /* Semaphore for locking against concurrent checkpoints */ - struct mutex j_checkpoint_mutex; + struct mutex j_checkpoint_mutex; /* * Journal head: identifies the first unused block in the journal. -- cgit v1.2.3 From a4e4de36dc446b2193bdc8ebb96a96e44b69dd94 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 27 Sep 2006 01:49:36 -0700 Subject: [PATCH] ext3: Fix sparse warnings Fixing up some endian-ness warnings in preparation to clone ext4 from ext3. Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/resize.c | 21 +++++++++++---------- fs/ext3/super.c | 4 +--- fs/jbd/journal.c | 2 +- include/linux/ext3_fs.h | 2 +- 4 files changed, 14 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 5e1337fd878a..e186f7fb698b 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -336,7 +336,7 @@ static int verify_reserved_gdb(struct super_block *sb, unsigned five = 5; unsigned seven = 7; unsigned grp; - __u32 *p = (__u32 *)primary->b_data; + __le32 *p = (__le32 *)primary->b_data; int gdbackups = 0; while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) { @@ -380,7 +380,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, struct buffer_head *dind; int gdbackups; struct ext3_iloc iloc; - __u32 *data; + __le32 *data; int err; if (test_opt(sb, DEBUG)) @@ -417,7 +417,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, goto exit_bh; } - data = (__u32 *)dind->b_data; + data = (__le32 *)dind->b_data; if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) { ext3_warning(sb, __FUNCTION__, "new group %u GDT block "E3FSBLK" not reserved", @@ -519,7 +519,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, struct buffer_head *dind; struct ext3_iloc iloc; ext3_fsblk_t blk; - __u32 *data, *end; + __le32 *data, *end; int gdbackups = 0; int res, i; int err; @@ -536,8 +536,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, } blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count; - data = (__u32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count; - end = (__u32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb); + data = (__le32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count; + end = (__le32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb); /* Get each reserved primary GDT block and verify it holds backups */ for (res = 0; res < reserved_gdb; res++, blk++) { @@ -545,7 +545,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, ext3_warning(sb, __FUNCTION__, "reserved block "E3FSBLK " not at offset %ld", - blk, (long)(data - (__u32 *)dind->b_data)); + blk, + (long)(data - (__le32 *)dind->b_data)); err = -EINVAL; goto exit_bh; } @@ -560,7 +561,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, goto exit_bh; } if (++data >= end) - data = (__u32 *)dind->b_data; + data = (__le32 *)dind->b_data; } for (i = 0; i < reserved_gdb; i++) { @@ -584,7 +585,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, blk = input->group * EXT3_BLOCKS_PER_GROUP(sb); for (i = 0; i < reserved_gdb; i++) { int err2; - data = (__u32 *)primary[i]->b_data; + data = (__le32 *)primary[i]->b_data; /* printk("reserving backup %lu[%u] = %lu\n", primary[i]->b_blocknr, gdbackups, blk + primary[i]->b_blocknr); */ @@ -689,7 +690,7 @@ exit_err: "can't update backup for group %d (err %d), " "forcing fsck on next reboot", group, err); sbi->s_mount_state &= ~EXT3_VALID_FS; - sbi->s_es->s_state &= ~cpu_to_le16(EXT3_VALID_FS); + sbi->s_es->s_state &= cpu_to_le16(~EXT3_VALID_FS); mark_buffer_dirty(sbi->s_sbh); } } diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 0544325d9d7e..10985017765b 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2348,10 +2348,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) */ ext3_clear_journal_err(sb, es); sbi->s_mount_state = le16_to_cpu(es->s_state); - if ((ret = ext3_group_extend(sb, es, n_blocks_count))) { - err = ret; + if ((err = ext3_group_extend(sb, es, n_blocks_count))) goto restore_opts; - } if (!ext3_setup_super (sb, es, 0)) sb->s_flags &= ~MS_RDONLY; } diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index b571209d6a1e..2fc66c3e6681 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1094,7 +1094,7 @@ int journal_load(journal_t *journal) /* * Create a slab for this blocksize */ - err = journal_create_jbd_slab(cpu_to_be32(sb->s_blocksize)); + err = journal_create_jbd_slab(be32_to_cpu(sb->s_blocksize)); if (err) return err; diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index 369c67502346..cc08f56750da 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -460,7 +460,7 @@ struct ext3_super_block { */ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ - __u16 s_reserved_gdt_blocks; /* Per group desc for online growth */ + __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */ /* * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. */ -- cgit v1.2.3 From 133d205a18b7a4d8cb52959c5310f6664277cf61 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 27 Sep 2006 01:49:41 -0700 Subject: [PATCH] Make kmem_cache_destroy() return void un-, de-, -free, -destroy, -exit, etc functions should in general return void. Also, There is very little, say, filesystem driver code can do upon failed kmem_cache_destroy(). If it will be decided to BUG in this case, BUG should be put in generic code, instead. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 4 ++-- mm/slab.c | 6 ++---- mm/slob.c | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index 66d6eb78d1c6..a96fd9310d55 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -60,7 +60,7 @@ extern void __init kmem_cache_init(void); extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long, void (*)(void *, kmem_cache_t *, unsigned long), void (*)(void *, kmem_cache_t *, unsigned long)); -extern int kmem_cache_destroy(kmem_cache_t *); +extern void kmem_cache_destroy(kmem_cache_t *); extern int kmem_cache_shrink(kmem_cache_t *); extern void *kmem_cache_alloc(kmem_cache_t *, gfp_t); extern void *kmem_cache_zalloc(struct kmem_cache *, gfp_t); @@ -249,7 +249,7 @@ struct kmem_cache *kmem_cache_create(const char *c, size_t, size_t, unsigned long, void (*)(void *, struct kmem_cache *, unsigned long), void (*)(void *, struct kmem_cache *, unsigned long)); -int kmem_cache_destroy(struct kmem_cache *c); +void kmem_cache_destroy(struct kmem_cache *c); void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags); void *kmem_cache_zalloc(struct kmem_cache *, gfp_t); void kmem_cache_free(struct kmem_cache *c, void *b); diff --git a/mm/slab.c b/mm/slab.c index 7a48eb1a60c8..c52ebf9c4462 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2442,7 +2442,6 @@ EXPORT_SYMBOL(kmem_cache_shrink); * @cachep: the cache to destroy * * Remove a struct kmem_cache object from the slab cache. - * Returns 0 on success. * * It is expected this function will be called by a module when it is * unloaded. This will remove the cache completely, and avoid a duplicate @@ -2454,7 +2453,7 @@ EXPORT_SYMBOL(kmem_cache_shrink); * The caller must guarantee that noone will allocate memory from the cache * during the kmem_cache_destroy(). */ -int kmem_cache_destroy(struct kmem_cache *cachep) +void kmem_cache_destroy(struct kmem_cache *cachep) { BUG_ON(!cachep || in_interrupt()); @@ -2475,7 +2474,7 @@ int kmem_cache_destroy(struct kmem_cache *cachep) list_add(&cachep->next, &cache_chain); mutex_unlock(&cache_chain_mutex); unlock_cpu_hotplug(); - return 1; + return; } if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) @@ -2483,7 +2482,6 @@ int kmem_cache_destroy(struct kmem_cache *cachep) __kmem_cache_destroy(cachep); unlock_cpu_hotplug(); - return 0; } EXPORT_SYMBOL(kmem_cache_destroy); diff --git a/mm/slob.c b/mm/slob.c index 20188627347c..542394184a58 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -270,10 +270,9 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, } EXPORT_SYMBOL(kmem_cache_create); -int kmem_cache_destroy(struct kmem_cache *c) +void kmem_cache_destroy(struct kmem_cache *c) { slob_free(c, sizeof(struct kmem_cache)); - return 0; } EXPORT_SYMBOL(kmem_cache_destroy); -- cgit v1.2.3 From c713216deebd95d2b0ab38fef8bb2361c0180c2d Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 27 Sep 2006 01:49:43 -0700 Subject: [PATCH] Introduce mechanism for registering active regions of memory At a basic level, architectures define structures to record where active ranges of page frames are located. Once located, the code to calculate zone sizes and holes in each architecture is very similar. Some of this zone and hole sizing code is difficult to read for no good reason. This set of patches eliminates the similar-looking architecture-specific code. The patches introduce a mechanism where architectures register where the active ranges of page frames are with add_active_range(). When all areas have been discovered, free_area_init_nodes() is called to initialise the pgdat and zones. The zone sizes and holes are then calculated in an architecture independent manner. Patch 1 introduces the mechanism for registering and initialising PFN ranges Patch 2 changes ppc to use the mechanism - 139 arch-specific LOC removed Patch 3 changes x86 to use the mechanism - 136 arch-specific LOC removed Patch 4 changes x86_64 to use the mechanism - 74 arch-specific LOC removed Patch 5 changes ia64 to use the mechanism - 52 arch-specific LOC removed Patch 6 accounts for mem_map as a memory hole as the pages are not reclaimable. It adjusts the watermarks slightly Tony Luck has successfully tested for ia64 on Itanium with tiger_defconfig, gensparse_defconfig and defconfig. Bob Picco has also tested and debugged on IA64. Jack Steiner successfully boot tested on a mammoth SGI IA64-based machine. These were on patches against 2.6.17-rc1 and release 3 of these patches but there have been no ia64-changes since release 3. There are differences in the zone sizes for x86_64 as the arch-specific code for x86_64 accounts the kernel image and the starting mem_maps as memory holes but the architecture-independent code accounts the memory as present. The big benefit of this set of patches is a sizable reduction of architecture-specific code, some of which is very hairy. There should be a greater reduction when other architectures use the same mechanisms for zone and hole sizing but I lack the hardware to test on. Additional credit; Dave Hansen for the initial suggestion and comments on early patches Andy Whitcroft for reviewing early versions and catching numerous errors Tony Luck for testing and debugging on IA64 Bob Picco for fixing bugs related to pfn registration, reviewing a number of patch revisions, providing a number of suggestions on future direction and testing heavily Jack Steiner and Robin Holt for testing on IA64 and clarifying issues related to memory holes Yasunori for testing on IA64 Andi Kleen for reviewing and feeding back about x86_64 Christian Kujau for providing valuable information related to ACPI problems on x86_64 and testing potential fixes This patch: Define the structure to represent an active range of page frames within a node in an architecture independent manner. Architectures are expected to register active ranges of PFNs using add_active_range(nid, start_pfn, end_pfn) and call free_area_init_nodes() passing the PFNs of the end of each zone. Signed-off-by: Mel Gorman Signed-off-by: Bob Picco Cc: Dave Hansen Cc: Andy Whitcroft Cc: Andi Kleen Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: "Keith Mannthey" Cc: "Luck, Tony" Cc: KAMEZAWA Hiroyuki Cc: Yasunori Goto Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 47 +++++ include/linux/mmzone.h | 10 +- mm/page_alloc.c | 552 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 584 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index 856f0ee7e84a..c0402da7cce0 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -937,6 +937,53 @@ extern void free_area_init(unsigned long * zones_size); extern void free_area_init_node(int nid, pg_data_t *pgdat, unsigned long * zones_size, unsigned long zone_start_pfn, unsigned long *zholes_size); +#ifdef CONFIG_ARCH_POPULATES_NODE_MAP +/* + * With CONFIG_ARCH_POPULATES_NODE_MAP set, an architecture may initialise its + * zones, allocate the backing mem_map and account for memory holes in a more + * architecture independent manner. This is a substitute for creating the + * zone_sizes[] and zholes_size[] arrays and passing them to + * free_area_init_node() + * + * An architecture is expected to register range of page frames backed by + * physical memory with add_active_range() before calling + * free_area_init_nodes() passing in the PFN each zone ends at. At a basic + * usage, an architecture is expected to do something like + * + * unsigned long max_zone_pfns[MAX_NR_ZONES] = {max_dma, max_normal_pfn, + * max_highmem_pfn}; + * for_each_valid_physical_page_range() + * add_active_range(node_id, start_pfn, end_pfn) + * free_area_init_nodes(max_zone_pfns); + * + * If the architecture guarantees that there are no holes in the ranges + * registered with add_active_range(), free_bootmem_active_regions() + * will call free_bootmem_node() for each registered physical page range. + * Similarly sparse_memory_present_with_active_regions() calls + * memory_present() for each range when SPARSEMEM is enabled. + * + * See mm/page_alloc.c for more information on each function exposed by + * CONFIG_ARCH_POPULATES_NODE_MAP + */ +extern void free_area_init_nodes(unsigned long *max_zone_pfn); +extern void add_active_range(unsigned int nid, unsigned long start_pfn, + unsigned long end_pfn); +extern void shrink_active_range(unsigned int nid, unsigned long old_end_pfn, + unsigned long new_end_pfn); +extern void remove_all_active_ranges(void); +extern unsigned long absent_pages_in_range(unsigned long start_pfn, + unsigned long end_pfn); +extern void get_pfn_range_for_nid(unsigned int nid, + unsigned long *start_pfn, unsigned long *end_pfn); +extern unsigned long find_min_pfn_with_active_regions(void); +extern unsigned long find_max_pfn_with_active_regions(void); +extern void free_bootmem_with_active_regions(int nid, + unsigned long max_low_pfn); +extern void sparse_memory_present_with_active_regions(int nid); +#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID +extern int early_pfn_to_nid(unsigned long pfn); +#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */ +#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ extern void memmap_init_zone(unsigned long, int, unsigned long, unsigned long); extern void setup_per_zone_pages_min(void); extern void mem_init(void); diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 3693f1a52788..7fa1cbe9fa7a 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -305,6 +305,13 @@ struct zonelist { struct zone *zones[MAX_NUMNODES * MAX_NR_ZONES + 1]; // NULL delimited }; +#ifdef CONFIG_ARCH_POPULATES_NODE_MAP +struct node_active_region { + unsigned long start_pfn; + unsigned long end_pfn; + int nid; +}; +#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ /* * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM @@ -518,7 +525,8 @@ extern struct zone *next_zone(struct zone *zone); #endif -#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID +#if !defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) && \ + !defined(CONFIG_ARCH_POPULATES_NODE_MAP) #define early_pfn_to_nid(nid) (0UL) #endif diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 9810f0a60db7..26c9939857fa 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include @@ -103,6 +105,33 @@ int min_free_kbytes = 1024; unsigned long __meminitdata nr_kernel_pages; unsigned long __meminitdata nr_all_pages; +#ifdef CONFIG_ARCH_POPULATES_NODE_MAP + /* + * MAX_ACTIVE_REGIONS determines the maxmimum number of distinct + * ranges of memory (RAM) that may be registered with add_active_range(). + * Ranges passed to add_active_range() will be merged if possible + * so the number of times add_active_range() can be called is + * related to the number of nodes and the number of holes + */ + #ifdef CONFIG_MAX_ACTIVE_REGIONS + /* Allow an architecture to set MAX_ACTIVE_REGIONS to save memory */ + #define MAX_ACTIVE_REGIONS CONFIG_MAX_ACTIVE_REGIONS + #else + #if MAX_NUMNODES >= 32 + /* If there can be many nodes, allow up to 50 holes per node */ + #define MAX_ACTIVE_REGIONS (MAX_NUMNODES*50) + #else + /* By default, allow up to 256 distinct regions */ + #define MAX_ACTIVE_REGIONS 256 + #endif + #endif + + struct node_active_region __initdata early_node_map[MAX_ACTIVE_REGIONS]; + int __initdata nr_nodemap_entries; + unsigned long __initdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES]; + unsigned long __initdata arch_zone_highest_possible_pfn[MAX_NR_ZONES]; +#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ + #ifdef CONFIG_DEBUG_VM static int page_outside_zone_boundaries(struct zone *zone, struct page *page) { @@ -1642,25 +1671,6 @@ static inline unsigned long wait_table_bits(unsigned long size) #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) -static void __init calculate_zone_totalpages(struct pglist_data *pgdat, - unsigned long *zones_size, unsigned long *zholes_size) -{ - unsigned long realtotalpages, totalpages = 0; - enum zone_type i; - - for (i = 0; i < MAX_NR_ZONES; i++) - totalpages += zones_size[i]; - pgdat->node_spanned_pages = totalpages; - - realtotalpages = totalpages; - if (zholes_size) - for (i = 0; i < MAX_NR_ZONES; i++) - realtotalpages -= zholes_size[i]; - pgdat->node_present_pages = realtotalpages; - printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages); -} - - /* * Initially all pages are reserved - free ones are freed * up by free_all_bootmem() once the early boot process is @@ -1977,6 +1987,272 @@ __meminit int init_currently_empty_zone(struct zone *zone, return 0; } +#ifdef CONFIG_ARCH_POPULATES_NODE_MAP +/* + * Basic iterator support. Return the first range of PFNs for a node + * Note: nid == MAX_NUMNODES returns first region regardless of node + */ +static int __init first_active_region_index_in_nid(int nid) +{ + int i; + + for (i = 0; i < nr_nodemap_entries; i++) + if (nid == MAX_NUMNODES || early_node_map[i].nid == nid) + return i; + + return -1; +} + +/* + * Basic iterator support. Return the next active range of PFNs for a node + * Note: nid == MAX_NUMNODES returns next region regardles of node + */ +static int __init next_active_region_index_in_nid(int index, int nid) +{ + for (index = index + 1; index < nr_nodemap_entries; index++) + if (nid == MAX_NUMNODES || early_node_map[index].nid == nid) + return index; + + return -1; +} + +#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID +/* + * Required by SPARSEMEM. Given a PFN, return what node the PFN is on. + * Architectures may implement their own version but if add_active_range() + * was used and there are no special requirements, this is a convenient + * alternative + */ +int __init early_pfn_to_nid(unsigned long pfn) +{ + int i; + + for (i = 0; i < nr_nodemap_entries; i++) { + unsigned long start_pfn = early_node_map[i].start_pfn; + unsigned long end_pfn = early_node_map[i].end_pfn; + + if (start_pfn <= pfn && pfn < end_pfn) + return early_node_map[i].nid; + } + + return 0; +} +#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */ + +/* Basic iterator support to walk early_node_map[] */ +#define for_each_active_range_index_in_nid(i, nid) \ + for (i = first_active_region_index_in_nid(nid); i != -1; \ + i = next_active_region_index_in_nid(i, nid)) + +/** + * free_bootmem_with_active_regions - Call free_bootmem_node for each active range + * @nid: The node to free memory on. If MAX_NUMNODES, all nodes are freed + * @max_low_pfn: The highest PFN that till be passed to free_bootmem_node + * + * If an architecture guarantees that all ranges registered with + * add_active_ranges() contain no holes and may be freed, this + * this function may be used instead of calling free_bootmem() manually. + */ +void __init free_bootmem_with_active_regions(int nid, + unsigned long max_low_pfn) +{ + int i; + + for_each_active_range_index_in_nid(i, nid) { + unsigned long size_pages = 0; + unsigned long end_pfn = early_node_map[i].end_pfn; + + if (early_node_map[i].start_pfn >= max_low_pfn) + continue; + + if (end_pfn > max_low_pfn) + end_pfn = max_low_pfn; + + size_pages = end_pfn - early_node_map[i].start_pfn; + free_bootmem_node(NODE_DATA(early_node_map[i].nid), + PFN_PHYS(early_node_map[i].start_pfn), + size_pages << PAGE_SHIFT); + } +} + +/** + * sparse_memory_present_with_active_regions - Call memory_present for each active range + * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used + * + * If an architecture guarantees that all ranges registered with + * add_active_ranges() contain no holes and may be freed, this + * this function may be used instead of calling memory_present() manually. + */ +void __init sparse_memory_present_with_active_regions(int nid) +{ + int i; + + for_each_active_range_index_in_nid(i, nid) + memory_present(early_node_map[i].nid, + early_node_map[i].start_pfn, + early_node_map[i].end_pfn); +} + +/** + * get_pfn_range_for_nid - Return the start and end page frames for a node + * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned + * @start_pfn: Passed by reference. On return, it will have the node start_pfn + * @end_pfn: Passed by reference. On return, it will have the node end_pfn + * + * It returns the start and end page frame of a node based on information + * provided by an arch calling add_active_range(). If called for a node + * with no available memory, a warning is printed and the start and end + * PFNs will be 0 + */ +void __init get_pfn_range_for_nid(unsigned int nid, + unsigned long *start_pfn, unsigned long *end_pfn) +{ + int i; + *start_pfn = -1UL; + *end_pfn = 0; + + for_each_active_range_index_in_nid(i, nid) { + *start_pfn = min(*start_pfn, early_node_map[i].start_pfn); + *end_pfn = max(*end_pfn, early_node_map[i].end_pfn); + } + + if (*start_pfn == -1UL) { + printk(KERN_WARNING "Node %u active with no memory\n", nid); + *start_pfn = 0; + } +} + +/* + * Return the number of pages a zone spans in a node, including holes + * present_pages = zone_spanned_pages_in_node() - zone_absent_pages_in_node() + */ +unsigned long __init zone_spanned_pages_in_node(int nid, + unsigned long zone_type, + unsigned long *ignored) +{ + unsigned long node_start_pfn, node_end_pfn; + unsigned long zone_start_pfn, zone_end_pfn; + + /* Get the start and end of the node and zone */ + get_pfn_range_for_nid(nid, &node_start_pfn, &node_end_pfn); + zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type]; + zone_end_pfn = arch_zone_highest_possible_pfn[zone_type]; + + /* Check that this node has pages within the zone's required range */ + if (zone_end_pfn < node_start_pfn || zone_start_pfn > node_end_pfn) + return 0; + + /* Move the zone boundaries inside the node if necessary */ + zone_end_pfn = min(zone_end_pfn, node_end_pfn); + zone_start_pfn = max(zone_start_pfn, node_start_pfn); + + /* Return the spanned pages */ + return zone_end_pfn - zone_start_pfn; +} + +/* + * Return the number of holes in a range on a node. If nid is MAX_NUMNODES, + * then all holes in the requested range will be accounted for + */ +unsigned long __init __absent_pages_in_range(int nid, + unsigned long range_start_pfn, + unsigned long range_end_pfn) +{ + int i = 0; + unsigned long prev_end_pfn = 0, hole_pages = 0; + unsigned long start_pfn; + + /* Find the end_pfn of the first active range of pfns in the node */ + i = first_active_region_index_in_nid(nid); + if (i == -1) + return 0; + + prev_end_pfn = early_node_map[i].start_pfn; + + /* Find all holes for the zone within the node */ + for (; i != -1; i = next_active_region_index_in_nid(i, nid)) { + + /* No need to continue if prev_end_pfn is outside the zone */ + if (prev_end_pfn >= range_end_pfn) + break; + + /* Make sure the end of the zone is not within the hole */ + start_pfn = min(early_node_map[i].start_pfn, range_end_pfn); + prev_end_pfn = max(prev_end_pfn, range_start_pfn); + + /* Update the hole size cound and move on */ + if (start_pfn > range_start_pfn) { + BUG_ON(prev_end_pfn > start_pfn); + hole_pages += start_pfn - prev_end_pfn; + } + prev_end_pfn = early_node_map[i].end_pfn; + } + + return hole_pages; +} + +/** + * absent_pages_in_range - Return number of page frames in holes within a range + * @start_pfn: The start PFN to start searching for holes + * @end_pfn: The end PFN to stop searching for holes + * + * It returns the number of pages frames in memory holes within a range + */ +unsigned long __init absent_pages_in_range(unsigned long start_pfn, + unsigned long end_pfn) +{ + return __absent_pages_in_range(MAX_NUMNODES, start_pfn, end_pfn); +} + +/* Return the number of page frames in holes in a zone on a node */ +unsigned long __init zone_absent_pages_in_node(int nid, + unsigned long zone_type, + unsigned long *ignored) +{ + return __absent_pages_in_range(nid, + arch_zone_lowest_possible_pfn[zone_type], + arch_zone_highest_possible_pfn[zone_type]); +} +#else +static inline unsigned long zone_spanned_pages_in_node(int nid, + unsigned long zone_type, + unsigned long *zones_size) +{ + return zones_size[zone_type]; +} + +static inline unsigned long zone_absent_pages_in_node(int nid, + unsigned long zone_type, + unsigned long *zholes_size) +{ + if (!zholes_size) + return 0; + + return zholes_size[zone_type]; +} +#endif + +static void __init calculate_node_totalpages(struct pglist_data *pgdat, + unsigned long *zones_size, unsigned long *zholes_size) +{ + unsigned long realtotalpages, totalpages = 0; + enum zone_type i; + + for (i = 0; i < MAX_NR_ZONES; i++) + totalpages += zone_spanned_pages_in_node(pgdat->node_id, i, + zones_size); + pgdat->node_spanned_pages = totalpages; + + realtotalpages = totalpages; + for (i = 0; i < MAX_NR_ZONES; i++) + realtotalpages -= + zone_absent_pages_in_node(pgdat->node_id, i, + zholes_size); + pgdat->node_present_pages = realtotalpages; + printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id, + realtotalpages); +} + /* * Set up the zone data structures: * - mark all pages reserved @@ -2000,9 +2276,9 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat, struct zone *zone = pgdat->node_zones + j; unsigned long size, realsize; - realsize = size = zones_size[j]; - if (zholes_size) - realsize -= zholes_size[j]; + size = zone_spanned_pages_in_node(nid, j, zones_size); + realsize = size - zone_absent_pages_in_node(nid, j, + zholes_size); if (!is_highmem_idx(j)) nr_kernel_pages += realsize; @@ -2073,8 +2349,13 @@ static void __init alloc_node_mem_map(struct pglist_data *pgdat) /* * With no DISCONTIG, the global mem_map is just set as node 0's */ - if (pgdat == NODE_DATA(0)) + if (pgdat == NODE_DATA(0)) { mem_map = NODE_DATA(0)->node_mem_map; +#ifdef CONFIG_ARCH_POPULATES_NODE_MAP + if (page_to_pfn(mem_map) != pgdat->node_start_pfn) + mem_map -= pgdat->node_start_pfn; +#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ + } #endif #endif /* CONFIG_FLAT_NODE_MEM_MAP */ } @@ -2085,13 +2366,236 @@ void __meminit free_area_init_node(int nid, struct pglist_data *pgdat, { pgdat->node_id = nid; pgdat->node_start_pfn = node_start_pfn; - calculate_zone_totalpages(pgdat, zones_size, zholes_size); + calculate_node_totalpages(pgdat, zones_size, zholes_size); alloc_node_mem_map(pgdat); free_area_init_core(pgdat, zones_size, zholes_size); } +#ifdef CONFIG_ARCH_POPULATES_NODE_MAP +/** + * add_active_range - Register a range of PFNs backed by physical memory + * @nid: The node ID the range resides on + * @start_pfn: The start PFN of the available physical memory + * @end_pfn: The end PFN of the available physical memory + * + * These ranges are stored in an early_node_map[] and later used by + * free_area_init_nodes() to calculate zone sizes and holes. If the + * range spans a memory hole, it is up to the architecture to ensure + * the memory is not freed by the bootmem allocator. If possible + * the range being registered will be merged with existing ranges. + */ +void __init add_active_range(unsigned int nid, unsigned long start_pfn, + unsigned long end_pfn) +{ + int i; + + printk(KERN_DEBUG "Entering add_active_range(%d, %lu, %lu) " + "%d entries of %d used\n", + nid, start_pfn, end_pfn, + nr_nodemap_entries, MAX_ACTIVE_REGIONS); + + /* Merge with existing active regions if possible */ + for (i = 0; i < nr_nodemap_entries; i++) { + if (early_node_map[i].nid != nid) + continue; + + /* Skip if an existing region covers this new one */ + if (start_pfn >= early_node_map[i].start_pfn && + end_pfn <= early_node_map[i].end_pfn) + return; + + /* Merge forward if suitable */ + if (start_pfn <= early_node_map[i].end_pfn && + end_pfn > early_node_map[i].end_pfn) { + early_node_map[i].end_pfn = end_pfn; + return; + } + + /* Merge backward if suitable */ + if (start_pfn < early_node_map[i].end_pfn && + end_pfn >= early_node_map[i].start_pfn) { + early_node_map[i].start_pfn = start_pfn; + return; + } + } + + /* Check that early_node_map is large enough */ + if (i >= MAX_ACTIVE_REGIONS) { + printk(KERN_CRIT "More than %d memory regions, truncating\n", + MAX_ACTIVE_REGIONS); + return; + } + + early_node_map[i].nid = nid; + early_node_map[i].start_pfn = start_pfn; + early_node_map[i].end_pfn = end_pfn; + nr_nodemap_entries = i + 1; +} + +/** + * shrink_active_range - Shrink an existing registered range of PFNs + * @nid: The node id the range is on that should be shrunk + * @old_end_pfn: The old end PFN of the range + * @new_end_pfn: The new PFN of the range + * + * i386 with NUMA use alloc_remap() to store a node_mem_map on a local node. + * The map is kept at the end physical page range that has already been + * registered with add_active_range(). This function allows an arch to shrink + * an existing registered range. + */ +void __init shrink_active_range(unsigned int nid, unsigned long old_end_pfn, + unsigned long new_end_pfn) +{ + int i; + + /* Find the old active region end and shrink */ + for_each_active_range_index_in_nid(i, nid) + if (early_node_map[i].end_pfn == old_end_pfn) { + early_node_map[i].end_pfn = new_end_pfn; + break; + } +} + +/** + * remove_all_active_ranges - Remove all currently registered regions + * During discovery, it may be found that a table like SRAT is invalid + * and an alternative discovery method must be used. This function removes + * all currently registered regions. + */ +void __init remove_all_active_ranges() +{ + memset(early_node_map, 0, sizeof(early_node_map)); + nr_nodemap_entries = 0; +} + +/* Compare two active node_active_regions */ +static int __init cmp_node_active_region(const void *a, const void *b) +{ + struct node_active_region *arange = (struct node_active_region *)a; + struct node_active_region *brange = (struct node_active_region *)b; + + /* Done this way to avoid overflows */ + if (arange->start_pfn > brange->start_pfn) + return 1; + if (arange->start_pfn < brange->start_pfn) + return -1; + + return 0; +} + +/* sort the node_map by start_pfn */ +static void __init sort_node_map(void) +{ + sort(early_node_map, (size_t)nr_nodemap_entries, + sizeof(struct node_active_region), + cmp_node_active_region, NULL); +} + +/* Find the lowest pfn for a node. This depends on a sorted early_node_map */ +unsigned long __init find_min_pfn_for_node(unsigned long nid) +{ + int i; + + /* Assuming a sorted map, the first range found has the starting pfn */ + for_each_active_range_index_in_nid(i, nid) + return early_node_map[i].start_pfn; + + printk(KERN_WARNING "Could not find start_pfn for node %lu\n", nid); + return 0; +} + +/** + * find_min_pfn_with_active_regions - Find the minimum PFN registered + * + * It returns the minimum PFN based on information provided via + * add_active_range() + */ +unsigned long __init find_min_pfn_with_active_regions(void) +{ + return find_min_pfn_for_node(MAX_NUMNODES); +} + +/** + * find_max_pfn_with_active_regions - Find the maximum PFN registered + * + * It returns the maximum PFN based on information provided via + * add_active_range() + */ +unsigned long __init find_max_pfn_with_active_regions(void) +{ + int i; + unsigned long max_pfn = 0; + + for (i = 0; i < nr_nodemap_entries; i++) + max_pfn = max(max_pfn, early_node_map[i].end_pfn); + + return max_pfn; +} + +/** + * free_area_init_nodes - Initialise all pg_data_t and zone data + * @arch_max_dma_pfn: The maximum PFN usable for ZONE_DMA + * @arch_max_dma32_pfn: The maximum PFN usable for ZONE_DMA32 + * @arch_max_low_pfn: The maximum PFN usable for ZONE_NORMAL + * @arch_max_high_pfn: The maximum PFN usable for ZONE_HIGHMEM + * + * This will call free_area_init_node() for each active node in the system. + * Using the page ranges provided by add_active_range(), the size of each + * zone in each node and their holes is calculated. If the maximum PFN + * between two adjacent zones match, it is assumed that the zone is empty. + * For example, if arch_max_dma_pfn == arch_max_dma32_pfn, it is assumed + * that arch_max_dma32_pfn has no pages. It is also assumed that a zone + * starts where the previous one ended. For example, ZONE_DMA32 starts + * at arch_max_dma_pfn. + */ +void __init free_area_init_nodes(unsigned long *max_zone_pfn) +{ + unsigned long nid; + enum zone_type i; + + /* Record where the zone boundaries are */ + memset(arch_zone_lowest_possible_pfn, 0, + sizeof(arch_zone_lowest_possible_pfn)); + memset(arch_zone_highest_possible_pfn, 0, + sizeof(arch_zone_highest_possible_pfn)); + arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions(); + arch_zone_highest_possible_pfn[0] = max_zone_pfn[0]; + for (i = 1; i < MAX_NR_ZONES; i++) { + arch_zone_lowest_possible_pfn[i] = + arch_zone_highest_possible_pfn[i-1]; + arch_zone_highest_possible_pfn[i] = + max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]); + } + + /* Regions in the early_node_map can be in any order */ + sort_node_map(); + + /* Print out the zone ranges */ + printk("Zone PFN ranges:\n"); + for (i = 0; i < MAX_NR_ZONES; i++) + printk(" %-8s %8lu -> %8lu\n", + zone_names[i], + arch_zone_lowest_possible_pfn[i], + arch_zone_highest_possible_pfn[i]); + + /* Print out the early_node_map[] */ + printk("early_node_map[%d] active PFN ranges\n", nr_nodemap_entries); + for (i = 0; i < nr_nodemap_entries; i++) + printk(" %3d: %8lu -> %8lu\n", early_node_map[i].nid, + early_node_map[i].start_pfn, + early_node_map[i].end_pfn); + + /* Initialise every node */ + for_each_online_node(nid) { + pg_data_t *pgdat = NODE_DATA(nid); + free_area_init_node(nid, pgdat, NULL, + find_min_pfn_for_node(nid), NULL); + } +} +#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ + #ifndef CONFIG_NEED_MULTIPLE_NODES static bootmem_data_t contig_bootmem_data; struct pglist_data contig_page_data = { .bdata = &contig_bootmem_data }; -- cgit v1.2.3 From 0e0b864e069c52a7b3e4a7da56e29b03a012fd75 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 27 Sep 2006 01:49:56 -0700 Subject: [PATCH] Account for memmap and optionally the kernel image as holes The x86_64 code accounted for memmap and some portions of the the DMA zone as holes. This was because those areas would never be reclaimed and accounting for them as memory affects min watermarks. This patch will account for the memmap as a memory hole. Architectures may optionally use set_dma_reserve() if they wish to account for a portion of memory in ZONE_DMA as a hole. Signed-off-by: Mel Gorman Cc: Dave Hansen Cc: Andy Whitcroft Cc: Andi Kleen Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: "Keith Mannthey" Cc: "Luck, Tony" Cc: KAMEZAWA Hiroyuki Cc: Yasunori Goto Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/mm/init.c | 4 +++- include/linux/mm.h | 1 + mm/page_alloc.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 47928399e38a..3e16fe08150e 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -655,8 +655,10 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len) #else reserve_bootmem(phys, len); #endif - if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) + if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) { dma_reserve += len / PAGE_SIZE; + set_dma_reserve(dma_reserve); + } } int kern_addr_valid(unsigned long addr) diff --git a/include/linux/mm.h b/include/linux/mm.h index c0402da7cce0..22936e1fcdf2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -984,6 +984,7 @@ extern void sparse_memory_present_with_active_regions(int nid); extern int early_pfn_to_nid(unsigned long pfn); #endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */ #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ +extern void set_dma_reserve(unsigned long new_dma_reserve); extern void memmap_init_zone(unsigned long, int, unsigned long, unsigned long); extern void setup_per_zone_pages_min(void); extern void mem_init(void); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 26c9939857fa..8d9a1eb9fbba 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -104,6 +104,7 @@ int min_free_kbytes = 1024; unsigned long __meminitdata nr_kernel_pages; unsigned long __meminitdata nr_all_pages; +static unsigned long __initdata dma_reserve; #ifdef CONFIG_ARCH_POPULATES_NODE_MAP /* @@ -2213,6 +2214,20 @@ unsigned long __init zone_absent_pages_in_node(int nid, arch_zone_lowest_possible_pfn[zone_type], arch_zone_highest_possible_pfn[zone_type]); } + +/* Return the zone index a PFN is in */ +int memmap_zone_idx(struct page *lmem_map) +{ + int i; + unsigned long phys_addr = virt_to_phys(lmem_map); + unsigned long pfn = phys_addr >> PAGE_SHIFT; + + for (i = 0; i < MAX_NR_ZONES; i++) + if (pfn < arch_zone_highest_possible_pfn[i]) + break; + + return i; +} #else static inline unsigned long zone_spanned_pages_in_node(int nid, unsigned long zone_type, @@ -2230,6 +2245,11 @@ static inline unsigned long zone_absent_pages_in_node(int nid, return zholes_size[zone_type]; } + +static inline int memmap_zone_idx(struct page *lmem_map) +{ + return MAX_NR_ZONES; +} #endif static void __init calculate_node_totalpages(struct pglist_data *pgdat, @@ -2274,12 +2294,35 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat, for (j = 0; j < MAX_NR_ZONES; j++) { struct zone *zone = pgdat->node_zones + j; - unsigned long size, realsize; + unsigned long size, realsize, memmap_pages; size = zone_spanned_pages_in_node(nid, j, zones_size); realsize = size - zone_absent_pages_in_node(nid, j, zholes_size); + /* + * Adjust realsize so that it accounts for how much memory + * is used by this zone for memmap. This affects the watermark + * and per-cpu initialisations + */ + memmap_pages = (size * sizeof(struct page)) >> PAGE_SHIFT; + if (realsize >= memmap_pages) { + realsize -= memmap_pages; + printk(KERN_DEBUG + " %s zone: %lu pages used for memmap\n", + zone_names[j], memmap_pages); + } else + printk(KERN_WARNING + " %s zone: %lu pages exceeds realsize %lu\n", + zone_names[j], memmap_pages, realsize); + + /* Account for reserved DMA pages */ + if (j == ZONE_DMA && realsize > dma_reserve) { + realsize -= dma_reserve; + printk(KERN_DEBUG " DMA zone: %lu pages reserved\n", + dma_reserve); + } + if (!is_highmem_idx(j)) nr_kernel_pages += realsize; nr_all_pages += realsize; @@ -2596,6 +2639,21 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn) } #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ +/** + * set_dma_reserve - Account the specified number of pages reserved in ZONE_DMA + * @new_dma_reserve - The number of pages to mark reserved + * + * The per-cpu batchsize and zone watermarks are determined by present_pages. + * In the DMA zone, a significant percentage may be consumed by kernel image + * and other unfreeable allocations which can skew the watermarks badly. This + * function may optionally be used to account for unfreeable pages in + * ZONE_DMA. The effect will be lower watermarks and smaller per-cpu batchsize + */ +void __init set_dma_reserve(unsigned long new_dma_reserve) +{ + dma_reserve = new_dma_reserve; +} + #ifndef CONFIG_NEED_MULTIPLE_NODES static bootmem_data_t contig_bootmem_data; struct pglist_data contig_page_data = { .bdata = &contig_bootmem_data }; -- cgit v1.2.3 From fb01439c5b778d5974a488c5d4fe85e6d0e18a68 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 27 Sep 2006 01:49:59 -0700 Subject: [PATCH] Allow an arch to expand node boundaries Arch-independent zone-sizing determines the size of a node (pgdat->node_spanned_pages) based on the physical memory that was registered by the architecture. However, when CONFIG_MEMORY_HOTPLUG_RESERVE is set, the architecture expects that the spanned_pages will be much larger and that mem_map will be allocated that is used lated on memory hot-add. This patch allows an architecture that sets CONFIG_MEMORY_HOTPLUG_RESERVE to call push_node_boundaries() which will set the node beginning and end to at *least* the requested boundary. Cc: Dave Hansen Cc: Andy Whitcroft Cc: Andi Kleen Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: "Keith Mannthey" Cc: "Luck, Tony" Cc: KAMEZAWA Hiroyuki Cc: Yasunori Goto Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/mm/srat.c | 2 ++ include/linux/mm.h | 2 ++ mm/page_alloc.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) (limited to 'include/linux') diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index db1b2e11cf8f..f8c04d6935c9 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -324,6 +324,8 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) nd->start, nd->end); e820_register_active_regions(node, nd->start >> PAGE_SHIFT, nd->end >> PAGE_SHIFT); + push_node_boundaries(node, nd->start >> PAGE_SHIFT, + nd->end >> PAGE_SHIFT); #ifdef RESERVE_HOTADD if (ma->flags.hot_pluggable && reserve_hotadd(node, start, end) < 0) { diff --git a/include/linux/mm.h b/include/linux/mm.h index 22936e1fcdf2..9d046db31e76 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -970,6 +970,8 @@ extern void add_active_range(unsigned int nid, unsigned long start_pfn, unsigned long end_pfn); extern void shrink_active_range(unsigned int nid, unsigned long old_end_pfn, unsigned long new_end_pfn); +extern void push_node_boundaries(unsigned int nid, unsigned long start_pfn, + unsigned long end_pfn); extern void remove_all_active_ranges(void); extern unsigned long absent_pages_in_range(unsigned long start_pfn, unsigned long end_pfn); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 75133e1dc4b1..acbf58f8a1b7 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -131,6 +131,10 @@ static unsigned long __initdata dma_reserve; int __initdata nr_nodemap_entries; unsigned long __initdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES]; unsigned long __initdata arch_zone_highest_possible_pfn[MAX_NR_ZONES]; +#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE + unsigned long __initdata node_boundary_start_pfn[MAX_NUMNODES]; + unsigned long __initdata node_boundary_end_pfn[MAX_NUMNODES]; +#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */ #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ #ifdef CONFIG_DEBUG_VM @@ -2094,6 +2098,62 @@ void __init sparse_memory_present_with_active_regions(int nid) early_node_map[i].end_pfn); } +/** + * push_node_boundaries - Push node boundaries to at least the requested boundary + * @nid: The nid of the node to push the boundary for + * @start_pfn: The start pfn of the node + * @end_pfn: The end pfn of the node + * + * In reserve-based hot-add, mem_map is allocated that is unused until hotadd + * time. Specifically, on x86_64, SRAT will report ranges that can potentially + * be hotplugged even though no physical memory exists. This function allows + * an arch to push out the node boundaries so mem_map is allocated that can + * be used later. + */ +#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE +void __init push_node_boundaries(unsigned int nid, + unsigned long start_pfn, unsigned long end_pfn) +{ + printk(KERN_DEBUG "Entering push_node_boundaries(%u, %lu, %lu)\n", + nid, start_pfn, end_pfn); + + /* Initialise the boundary for this node if necessary */ + if (node_boundary_end_pfn[nid] == 0) + node_boundary_start_pfn[nid] = -1UL; + + /* Update the boundaries */ + if (node_boundary_start_pfn[nid] > start_pfn) + node_boundary_start_pfn[nid] = start_pfn; + if (node_boundary_end_pfn[nid] < end_pfn) + node_boundary_end_pfn[nid] = end_pfn; +} + +/* If necessary, push the node boundary out for reserve hotadd */ +static void __init account_node_boundary(unsigned int nid, + unsigned long *start_pfn, unsigned long *end_pfn) +{ + printk(KERN_DEBUG "Entering account_node_boundary(%u, %lu, %lu)\n", + nid, *start_pfn, *end_pfn); + + /* Return if boundary information has not been provided */ + if (node_boundary_end_pfn[nid] == 0) + return; + + /* Check the boundaries and update if necessary */ + if (node_boundary_start_pfn[nid] < *start_pfn) + *start_pfn = node_boundary_start_pfn[nid]; + if (node_boundary_end_pfn[nid] > *end_pfn) + *end_pfn = node_boundary_end_pfn[nid]; +} +#else +void __init push_node_boundaries(unsigned int nid, + unsigned long start_pfn, unsigned long end_pfn) {} + +static void __init account_node_boundary(unsigned int nid, + unsigned long *start_pfn, unsigned long *end_pfn) {} +#endif + + /** * get_pfn_range_for_nid - Return the start and end page frames for a node * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned @@ -2121,6 +2181,9 @@ void __init get_pfn_range_for_nid(unsigned int nid, printk(KERN_WARNING "Node %u active with no memory\n", nid); *start_pfn = 0; } + + /* Push the node boundaries out if requested */ + account_node_boundary(nid, start_pfn, end_pfn); } /* @@ -2527,6 +2590,10 @@ void __init remove_all_active_ranges() { memset(early_node_map, 0, sizeof(early_node_map)); nr_nodemap_entries = 0; +#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE + memset(node_boundary_start_pfn, 0, sizeof(node_boundary_start_pfn)); + memset(node_boundary_end_pfn, 0, sizeof(node_boundary_end_pfn)); +#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */ } /* Compare two active node_active_regions */ -- cgit v1.2.3 From e129b5c23c2b471d47f1c5d2b8b193fc2034af43 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 27 Sep 2006 01:50:00 -0700 Subject: [PATCH] vm: add per-zone writeout counter The VM is supposed to minimise the number of pages which get written off the LRU (for IO scheduling efficiency, and for high reclaim-success rates). But we don't actually have a clear way of showing how true this is. So add `nr_vmscan_write' to /proc/vmstat and /proc/zoneinfo - the number of pages which have been written by the vm scanner in this zone and globally. Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 1 + mm/vmscan.c | 3 ++- mm/vmstat.c | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 7fa1cbe9fa7a..1b0680cd84d2 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -58,6 +58,7 @@ enum zone_stat_item { NR_WRITEBACK, NR_UNSTABLE_NFS, /* NFS unstable pages */ NR_BOUNCE, + NR_VMSCAN_WRITE, #ifdef CONFIG_NUMA NUMA_HIT, /* allocated in intended node */ NUMA_MISS, /* allocated in non intended node */ diff --git a/mm/vmscan.c b/mm/vmscan.c index 87779dda4ec6..87d340999ce8 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -370,7 +371,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping) /* synchronous write or broken a_ops? */ ClearPageReclaim(page); } - + inc_zone_page_state(page, NR_VMSCAN_WRITE); return PAGE_SUCCESS; } diff --git a/mm/vmstat.c b/mm/vmstat.c index 490d8c1a0ded..69c657132e1f 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -465,6 +465,7 @@ static char *vmstat_text[] = { "nr_writeback", "nr_unstable", "nr_bounce", + "nr_vmscan_write", #ifdef CONFIG_NUMA "numa_hit", -- cgit v1.2.3 From 5b99cd0effaf846240a15441aec459a592577eaf Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 27 Sep 2006 01:50:01 -0700 Subject: [PATCH] own header file for struct page This moves the definition of struct page from mm.h to its own header file page-struct.h. This is a prereq to fix SetPageUptodate which is broken on s390: #define SetPageUptodate(_page) do { struct page *__page = (_page); if (!test_and_set_bit(PG_uptodate, &__page->flags)) page_test_and_clear_dirty(_page); } while (0) _page gets used twice in this macro which can cause subtle bugs. Using __page for the page_test_and_clear_dirty call doesn't work since it causes yet another problem with the page_test_and_clear_dirty macro as well. In order to avoid all these problems caused by macros it seems to be a good idea to get rid of them and convert them to static inline functions. Because of header file include order it's necessary to have a seperate header file for the struct page definition. Cc: Martin Schwidefsky Signed-off-by: Heiko Carstens Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 62 +------------------------------------------- include/linux/mm_types.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/mmzone.h | 5 ++++ 3 files changed, 73 insertions(+), 61 deletions(-) create mode 100644 include/linux/mm_types.h (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index 9d046db31e76..7477fb59c4f2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -16,6 +16,7 @@ #include #include #include +#include struct mempolicy; struct anon_vma; @@ -215,62 +216,6 @@ struct vm_operations_struct { struct mmu_gather; struct inode; -/* - * Each physical page in the system has a struct page associated with - * it to keep track of whatever it is we are using the page for at the - * moment. Note that we have no way to track which tasks are using - * a page, though if it is a pagecache page, rmap structures can tell us - * who is mapping it. - */ -struct page { - unsigned long flags; /* Atomic flags, some possibly - * updated asynchronously */ - atomic_t _count; /* Usage count, see below. */ - atomic_t _mapcount; /* Count of ptes mapped in mms, - * to show when page is mapped - * & limit reverse map searches. - */ - union { - struct { - unsigned long private; /* Mapping-private opaque data: - * usually used for buffer_heads - * if PagePrivate set; used for - * swp_entry_t if PageSwapCache; - * indicates order in the buddy - * system if PG_buddy is set. - */ - struct address_space *mapping; /* If low bit clear, points to - * inode address_space, or NULL. - * If page mapped as anonymous - * memory, low bit is set, and - * it points to anon_vma object: - * see PAGE_MAPPING_ANON below. - */ - }; -#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS - spinlock_t ptl; -#endif - }; - pgoff_t index; /* Our offset within mapping. */ - struct list_head lru; /* Pageout list, eg. active_list - * protected by zone->lru_lock ! - */ - /* - * On machines where all RAM is mapped into kernel address space, - * we can simply calculate the virtual address. On machines with - * highmem some memory is mapped into kernel virtual memory - * dynamically, so we need a place to store that address. - * Note that this field could be 16 bits on x86 ... ;) - * - * Architectures with slow multiplication can define - * WANT_PAGE_VIRTUAL in asm/page.h - */ -#if defined(WANT_PAGE_VIRTUAL) - void *virtual; /* Kernel virtual address (NULL if - not kmapped, ie. highmem) */ -#endif /* WANT_PAGE_VIRTUAL */ -}; - #define page_private(page) ((page)->private) #define set_page_private(page, v) ((page)->private = (v)) @@ -546,11 +491,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone, */ #include -#ifndef CONFIG_DISCONTIGMEM -/* The array of struct pages - for discontigmem use pgdat->lmem_map */ -extern struct page *mem_map; -#endif - static __always_inline void *lowmem_page_address(struct page *page) { return __va(page_to_pfn(page) << PAGE_SHIFT); diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h new file mode 100644 index 000000000000..c3852fd4a1cc --- /dev/null +++ b/include/linux/mm_types.h @@ -0,0 +1,67 @@ +#ifndef _LINUX_MM_TYPES_H +#define _LINUX_MM_TYPES_H + +#include +#include +#include +#include + +struct address_space; + +/* + * Each physical page in the system has a struct page associated with + * it to keep track of whatever it is we are using the page for at the + * moment. Note that we have no way to track which tasks are using + * a page, though if it is a pagecache page, rmap structures can tell us + * who is mapping it. + */ +struct page { + unsigned long flags; /* Atomic flags, some possibly + * updated asynchronously */ + atomic_t _count; /* Usage count, see below. */ + atomic_t _mapcount; /* Count of ptes mapped in mms, + * to show when page is mapped + * & limit reverse map searches. + */ + union { + struct { + unsigned long private; /* Mapping-private opaque data: + * usually used for buffer_heads + * if PagePrivate set; used for + * swp_entry_t if PageSwapCache; + * indicates order in the buddy + * system if PG_buddy is set. + */ + struct address_space *mapping; /* If low bit clear, points to + * inode address_space, or NULL. + * If page mapped as anonymous + * memory, low bit is set, and + * it points to anon_vma object: + * see PAGE_MAPPING_ANON below. + */ + }; +#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS + spinlock_t ptl; +#endif + }; + pgoff_t index; /* Our offset within mapping. */ + struct list_head lru; /* Pageout list, eg. active_list + * protected by zone->lru_lock ! + */ + /* + * On machines where all RAM is mapped into kernel address space, + * we can simply calculate the virtual address. On machines with + * highmem some memory is mapped into kernel virtual memory + * dynamically, so we need a place to store that address. + * Note that this field could be 16 bits on x86 ... ;) + * + * Architectures with slow multiplication can define + * WANT_PAGE_VIRTUAL in asm/page.h + */ +#if defined(WANT_PAGE_VIRTUAL) + void *virtual; /* Kernel virtual address (NULL if + not kmapped, ie. highmem) */ +#endif /* WANT_PAGE_VIRTUAL */ +}; + +#endif /* _LINUX_MM_TYPES_H */ diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 1b0680cd84d2..562cf7a8f3ee 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -314,6 +314,11 @@ struct node_active_region { }; #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ +#ifndef CONFIG_DISCONTIGMEM +/* The array of struct pages - for discontigmem use pgdat->lmem_map */ +extern struct page *mem_map; +#endif + /* * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM * (mostly NUMA machines?) to denote a higher-level memory zone than the -- cgit v1.2.3 From 08e0f6a9705376732fd3bc9bf8ba97a6b5211eb1 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 27 Sep 2006 01:50:06 -0700 Subject: [PATCH] Add NUMA_BUILD definition in kernel.h to avoid #ifdef CONFIG_NUMA The NUMA_BUILD constant is always available and will be set to 1 on NUMA_BUILDs. That way checks valid only under CONFIG_NUMA can easily be done without #ifdef CONFIG_NUMA F.e. if (NUMA_BUILD && ) { ... } [akpm: not a thing we'd normally do, but CONFIG_NUMA is special: it is causing ifdef explosion in core kernel, so let's see if this is a comfortable way in whcih to control that] Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 7 +++++++ mm/page_alloc.c | 12 +++++------- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 4fa373bb18ac..4d00988dad03 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -350,4 +350,11 @@ struct sysinfo { /* Trap pasters of __FUNCTION__ at compile-time */ #define __FUNCTION__ (__func__) +/* This helps us to avoid #ifdef CONFIG_NUMA */ +#ifdef CONFIG_NUMA +#define NUMA_BUILD 1 +#else +#define NUMA_BUILD 0 +#endif + #endif diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 8a6418b0d2c5..4c76188b1681 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -942,7 +942,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, */ do { zone = *z; - if (unlikely((gfp_mask & __GFP_THISNODE) && + if (unlikely(NUMA_BUILD && (gfp_mask & __GFP_THISNODE) && zone->zone_pgdat != zonelist->zones[0]->zone_pgdat)) break; if ((alloc_flags & ALLOC_CPUSET) && @@ -1256,14 +1256,12 @@ unsigned int nr_free_pagecache_pages(void) { return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER)); } -#ifdef CONFIG_NUMA -static void show_node(struct zone *zone) + +static inline void show_node(struct zone *zone) { - printk("Node %ld ", zone_to_nid(zone)); + if (NUMA_BUILD) + printk("Node %ld ", zone_to_nid(zone)); } -#else -#define show_node(zone) do { } while (0) -#endif void si_meminfo(struct sysinfo *val) { -- cgit v1.2.3 From 77f700dab4c05f8ee17584ec869672796d7bcb87 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 27 Sep 2006 01:50:07 -0700 Subject: [PATCH] Disable GFP_THISNODE in the non-NUMA case GFP_THISNODE must be set to 0 in the non numa case otherwise we disable retry and warnings for failing allocations in the SMP and UP case. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/gfp.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 8b34aabfe4c6..bf2b6bc3f6fd 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -67,7 +67,12 @@ struct vm_area_struct; #define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \ __GFP_HIGHMEM) +#ifdef CONFIG_NUMA #define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY) +#else +#define GFP_THISNODE 0 +#endif + /* Flag - indicates that the buffer will be suitable for DMA. Ignored on some platforms, used as appropriate on others */ -- cgit v1.2.3 From d5f541ed6e31518508c688912e7464facf253c87 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 27 Sep 2006 01:50:08 -0700 Subject: [PATCH] Add node to zone for the NUMA case Add the node in order to optimize zone_to_nid. Signed-off-by: Christoph Lameter Acked-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 6 +++++- include/linux/mmzone.h | 1 + mm/page_alloc.c | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index 7477fb59c4f2..8e433bbc6e7e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -446,7 +446,11 @@ static inline struct zone *page_zone(struct page *page) static inline unsigned long zone_to_nid(struct zone *zone) { - return zone->zone_pgdat->node_id; +#ifdef CONFIG_NUMA + return zone->node; +#else + return 0; +#endif } static inline unsigned long page_to_nid(struct page *page) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 562cf7a8f3ee..59855b8718a0 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -168,6 +168,7 @@ struct zone { unsigned long lowmem_reserve[MAX_NR_ZONES]; #ifdef CONFIG_NUMA + int node; /* * zone reclaim becomes active if more unmapped pages exist. */ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 4c76188b1681..d0432e44f77d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2405,6 +2405,7 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat, zone->spanned_pages = size; zone->present_pages = realsize; #ifdef CONFIG_NUMA + zone->node = nid; zone->min_unmapped_pages = (realsize*sysctl_min_unmapped_ratio) / 100; zone->min_slab_pages = (realsize * sysctl_min_slab_ratio) / 100; -- cgit v1.2.3 From f4b81804a2d1ab341a4613089dc31ecce0800ed8 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 27 Sep 2006 01:50:10 -0700 Subject: [PATCH] do_no_pfn() Implement do_no_pfn() for handling mapping of memory without a struct page backing it. This avoids creating fake page table entries for regions which are not backed by real memory. This feature is used by the MSPEC driver and other users, where it is highly undesirable to have a struct page sitting behind the page (for instance if the page is accessed in cached mode via the struct page in parallel to the the driver accessing it uncached, which can result in data corruption on some architectures, such as ia64). This version uses specific NOPFN_{SIGBUS,OOM} return values, rather than expect all negative pfn values would be an error. It also bugs on cow mappings as this would not work with the VM. [akpm@osdl.org: micro-optimise] Signed-off-by: Jes Sorensen Cc: Hugh Dickins Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 7 ++++++ mm/memory.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index 8e433bbc6e7e..22165cb18906 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -199,6 +199,7 @@ struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type); + unsigned long (*nopfn)(struct vm_area_struct * area, unsigned long address); int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock); /* notification that a previously read-only page is about to become @@ -593,6 +594,12 @@ static inline int page_mapped(struct page *page) #define NOPAGE_SIGBUS (NULL) #define NOPAGE_OOM ((struct page *) (-1)) +/* + * Error return values for the *_nopfn functions + */ +#define NOPFN_SIGBUS ((unsigned long) -1) +#define NOPFN_OOM ((unsigned long) -2) + /* * Different kinds of faults, as returned by handle_mm_fault(). * Used to decide whether a process gets delivered SIGBUS or diff --git a/mm/memory.c b/mm/memory.c index 92a3ebd8d795..f2ef1dcfff77 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2255,6 +2255,54 @@ oom: return VM_FAULT_OOM; } +/* + * do_no_pfn() tries to create a new page mapping for a page without + * a struct_page backing it + * + * As this is called only for pages that do not currently exist, we + * do not need to flush old virtual caches or the TLB. + * + * We enter with non-exclusive mmap_sem (to exclude vma changes, + * but allow concurrent faults), and pte mapped but not yet locked. + * We return with mmap_sem still held, but pte unmapped and unlocked. + * + * It is expected that the ->nopfn handler always returns the same pfn + * for a given virtual mapping. + * + * Mark this `noinline' to prevent it from bloating the main pagefault code. + */ +static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long address, pte_t *page_table, pmd_t *pmd, + int write_access) +{ + spinlock_t *ptl; + pte_t entry; + unsigned long pfn; + int ret = VM_FAULT_MINOR; + + pte_unmap(page_table); + BUG_ON(!(vma->vm_flags & VM_PFNMAP)); + BUG_ON(is_cow_mapping(vma->vm_flags)); + + pfn = vma->vm_ops->nopfn(vma, address & PAGE_MASK); + if (pfn == NOPFN_OOM) + return VM_FAULT_OOM; + if (pfn == NOPFN_SIGBUS) + return VM_FAULT_SIGBUS; + + page_table = pte_offset_map_lock(mm, pmd, address, &ptl); + + /* Only go through if we didn't race with anybody else... */ + if (pte_none(*page_table)) { + entry = pfn_pte(pfn, vma->vm_page_prot); + if (write_access) + entry = maybe_mkwrite(pte_mkdirty(entry), vma); + set_pte_at(mm, address, page_table, entry); + } + pte_unmap_unlock(page_table, ptl); + return ret; +} + /* * Fault of a previously existing named mapping. Repopulate the pte * from the encoded file_pte if possible. This enables swappable @@ -2317,11 +2365,17 @@ static inline int handle_pte_fault(struct mm_struct *mm, old_entry = entry = *pte; if (!pte_present(entry)) { if (pte_none(entry)) { - if (!vma->vm_ops || !vma->vm_ops->nopage) - return do_anonymous_page(mm, vma, address, - pte, pmd, write_access); - return do_no_page(mm, vma, address, - pte, pmd, write_access); + if (vma->vm_ops) { + if (vma->vm_ops->nopage) + return do_no_page(mm, vma, address, + pte, pmd, + write_access); + if (unlikely(vma->vm_ops->nopfn)) + return do_no_pfn(mm, vma, address, pte, + pmd, write_access); + } + return do_anonymous_page(mm, vma, address, + pte, pmd, write_access); } if (pte_file(entry)) return do_file_page(mm, vma, address, -- cgit v1.2.3 From d24afc57d51b1be41f95521e81399061fa5875a6 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Wed, 27 Sep 2006 01:50:13 -0700 Subject: [PATCH] Mark __remove_vm_area() static The function is exported but not used from anywhere else. It's also marked as "not for driver use" so noone out there should really care. Signed-off-by: Rolf Eike Beer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmalloc.h | 1 - mm/vmalloc.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index dee88c6b6fa7..ce5f1482e6be 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -62,7 +62,6 @@ extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, extern struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int node); extern struct vm_struct *remove_vm_area(void *addr); -extern struct vm_struct *__remove_vm_area(void *addr); extern int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages); extern void unmap_vm_area(struct vm_struct *area); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 659ec634856a..1ac191ce5641 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -272,7 +272,7 @@ static struct vm_struct *__find_vm_area(void *addr) } /* Caller must hold vmlist_lock */ -struct vm_struct *__remove_vm_area(void *addr) +static struct vm_struct *__remove_vm_area(void *addr) { struct vm_struct **p, *tmp; -- cgit v1.2.3 From 5da6185bca064e35aa73a7c1f27488d2b96434f4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 27 Sep 2006 01:50:16 -0700 Subject: [PATCH] NOMMU: Set BDI capabilities for /dev/mem and /dev/kmem Set the backing device info capabilities for /dev/mem and /dev/kmem to permit direct sharing under no-MMU conditions and full mapping capabilities under MMU conditions. Make the BDI used by these available to all directly mappable character devices. Also comment the capabilities for /dev/zero. [akpm@osdl.org: ifdef reductions] Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/mem.c | 39 +++++++++++++++++++++++++++++++++++++++ fs/char_dev.c | 20 ++++++++++++++++++++ include/linux/cdev.h | 2 ++ 3 files changed, 61 insertions(+) (limited to 'include/linux') diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 917b20402664..4ac70ec697f0 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -238,6 +238,32 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, } #endif +#ifndef CONFIG_MMU +static unsigned long get_unmapped_area_mem(struct file *file, + unsigned long addr, + unsigned long len, + unsigned long pgoff, + unsigned long flags) +{ + if (!valid_mmap_phys_addr_range(pgoff, len)) + return (unsigned long) -EINVAL; + return pgoff; +} + +/* can't do an in-place private mapping if there's no MMU */ +static inline int private_mapping_ok(struct vm_area_struct *vma) +{ + return vma->vm_flags & VM_MAYSHARE; +} +#else +#define get_unmapped_area_mem NULL + +static inline int private_mapping_ok(struct vm_area_struct *vma) +{ + return 1; +} +#endif + static int mmap_mem(struct file * file, struct vm_area_struct * vma) { size_t size = vma->vm_end - vma->vm_start; @@ -245,6 +271,9 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) return -EINVAL; + if (!private_mapping_ok(vma)) + return -ENOSYS; + vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, size, vma->vm_page_prot); @@ -782,6 +811,7 @@ static const struct file_operations mem_fops = { .write = write_mem, .mmap = mmap_mem, .open = open_mem, + .get_unmapped_area = get_unmapped_area_mem, }; static const struct file_operations kmem_fops = { @@ -790,6 +820,7 @@ static const struct file_operations kmem_fops = { .write = write_kmem, .mmap = mmap_kmem, .open = open_kmem, + .get_unmapped_area = get_unmapped_area_mem, }; static const struct file_operations null_fops = { @@ -815,6 +846,10 @@ static const struct file_operations zero_fops = { .mmap = mmap_zero, }; +/* + * capabilities for /dev/zero + * - permits private mappings, "copies" are taken of the source of zeros + */ static struct backing_dev_info zero_bdi = { .capabilities = BDI_CAP_MAP_COPY, }; @@ -862,9 +897,13 @@ static int memory_open(struct inode * inode, struct file * filp) switch (iminor(inode)) { case 1: filp->f_op = &mem_fops; + filp->f_mapping->backing_dev_info = + &directly_mappable_cdev_bdi; break; case 2: filp->f_op = &kmem_fops; + filp->f_mapping->backing_dev_info = + &directly_mappable_cdev_bdi; break; case 3: filp->f_op = &null_fops; diff --git a/fs/char_dev.c b/fs/char_dev.c index 3483d3cf8087..0009346d827f 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -19,11 +19,30 @@ #include #include #include +#include #ifdef CONFIG_KMOD #include #endif +/* + * capabilities for /dev/mem, /dev/kmem and similar directly mappable character + * devices + * - permits shared-mmap for read, write and/or exec + * - does not permit private mmap in NOMMU mode (can't do COW) + * - no readahead or I/O queue unplugging required + */ +struct backing_dev_info directly_mappable_cdev_bdi = { + .capabilities = ( +#ifdef CONFIG_MMU + /* permit private copies of the data to be taken */ + BDI_CAP_MAP_COPY | +#endif + /* permit direct mmap, for read, write or exec */ + BDI_CAP_MAP_DIRECT | + BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP), +}; + static struct kobj_map *cdev_map; static DEFINE_MUTEX(chrdevs_lock); @@ -461,3 +480,4 @@ EXPORT_SYMBOL(cdev_del); EXPORT_SYMBOL(cdev_add); EXPORT_SYMBOL(register_chrdev); EXPORT_SYMBOL(unregister_chrdev); +EXPORT_SYMBOL(directly_mappable_cdev_bdi); diff --git a/include/linux/cdev.h b/include/linux/cdev.h index 2216638962d2..ee5f53f2ca15 100644 --- a/include/linux/cdev.h +++ b/include/linux/cdev.h @@ -23,5 +23,7 @@ void cdev_del(struct cdev *); void cd_forget(struct inode *); +extern struct backing_dev_info directly_mappable_cdev_bdi; + #endif #endif -- cgit v1.2.3 From dbf8685c8e21404e3a8ed244bd0219d3c4b89101 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 27 Sep 2006 01:50:19 -0700 Subject: [PATCH] NOMMU: Implement /proc/pid/maps for NOMMU Implement /proc/pid/maps for NOMMU by reading the vm_area_list attached to current->mm->context.vmlist. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/nommu-mmap.txt | 3 ++ fs/proc/internal.h | 1 + fs/proc/nommu.c | 20 ++++++++---- fs/proc/task_nommu.c | 74 +++++++++++++++++++++++++++++++++++--------- include/linux/proc_fs.h | 2 ++ 5 files changed, 80 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/Documentation/nommu-mmap.txt b/Documentation/nommu-mmap.txt index b88ebe4d808c..83f4b083d57e 100644 --- a/Documentation/nommu-mmap.txt +++ b/Documentation/nommu-mmap.txt @@ -116,6 +116,9 @@ FURTHER NOTES ON NO-MMU MMAP (*) A list of all the mappings on the system is visible through /proc/maps in no-MMU mode. + (*) A list of all the mappings in use by a process is visible through + /proc//maps in no-MMU mode. + (*) Supplying MAP_FIXED or a requesting a particular mapping address will result in an error. diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 146a434ba944..987c773dbb20 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -28,6 +28,7 @@ do { \ (vmi)->largest_chunk = 0; \ } while(0) +extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *); #endif extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f); diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index cff10ab1af63..d7dbdf9e0f49 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c @@ -33,19 +33,15 @@ #include "internal.h" /* - * display a list of all the VMAs the kernel knows about - * - nommu kernals have a single flat list + * display a single VMA to a sequenced file */ -static int nommu_vma_list_show(struct seq_file *m, void *v) +int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) { - struct vm_area_struct *vma; unsigned long ino = 0; struct file *file; dev_t dev = 0; int flags, len; - vma = rb_entry((struct rb_node *) v, struct vm_area_struct, vm_rb); - flags = vma->vm_flags; file = vma->vm_file; @@ -78,6 +74,18 @@ static int nommu_vma_list_show(struct seq_file *m, void *v) return 0; } +/* + * display a list of all the VMAs the kernel knows about + * - nommu kernals have a single flat list + */ +static int nommu_vma_list_show(struct seq_file *m, void *v) +{ + struct vm_area_struct *vma; + + vma = rb_entry((struct rb_node *) v, struct vm_area_struct, vm_rb); + return nommu_vma_show(m, vma); +} + static void *nommu_vma_list_start(struct seq_file *m, loff_t *_pos) { struct rb_node *_rb; diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 4616ed50ffcd..091aa8e48e02 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -138,25 +138,63 @@ out: } /* - * Albert D. Cahalan suggested to fake entries for the traditional - * sections here. This might be worth investigating. + * display mapping lines for a particular process's /proc/pid/maps */ -static int show_map(struct seq_file *m, void *v) +static int show_map(struct seq_file *m, void *_vml) { - return 0; + struct vm_list_struct *vml = _vml; + return nommu_vma_show(m, vml->vma); } + static void *m_start(struct seq_file *m, loff_t *pos) { + struct proc_maps_private *priv = m->private; + struct vm_list_struct *vml; + struct mm_struct *mm; + loff_t n = *pos; + + /* pin the task and mm whilst we play with them */ + priv->task = get_pid_task(priv->pid, PIDTYPE_PID); + if (!priv->task) + return NULL; + + mm = get_task_mm(priv->task); + if (!mm) { + put_task_struct(priv->task); + priv->task = NULL; + return NULL; + } + + down_read(&mm->mmap_sem); + + /* start from the Nth VMA */ + for (vml = mm->context.vmlist; vml; vml = vml->next) + if (n-- == 0) + return vml; return NULL; } -static void m_stop(struct seq_file *m, void *v) + +static void m_stop(struct seq_file *m, void *_vml) { + struct proc_maps_private *priv = m->private; + + if (priv->task) { + struct mm_struct *mm = priv->task->mm; + up_read(&mm->mmap_sem); + mmput(mm); + put_task_struct(priv->task); + } } -static void *m_next(struct seq_file *m, void *v, loff_t *pos) + +static void *m_next(struct seq_file *m, void *_vml, loff_t *pos) { - return NULL; + struct vm_list_struct *vml = _vml; + + (*pos)++; + return vml ? vml->next : NULL; } -static struct seq_operations proc_pid_maps_op = { + +static struct seq_operations proc_pid_maps_ops = { .start = m_start, .next = m_next, .stop = m_stop, @@ -165,11 +203,19 @@ static struct seq_operations proc_pid_maps_op = { static int maps_open(struct inode *inode, struct file *file) { - int ret; - ret = seq_open(file, &proc_pid_maps_op); - if (!ret) { - struct seq_file *m = file->private_data; - m->private = NULL; + struct proc_maps_private *priv; + int ret = -ENOMEM; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (priv) { + priv->pid = proc_pid(inode); + ret = seq_open(file, &proc_pid_maps_ops); + if (!ret) { + struct seq_file *m = file->private_data; + m->private = priv; + } else { + kfree(priv); + } } return ret; } @@ -178,6 +224,6 @@ struct file_operations proc_maps_operations = { .open = maps_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_private, }; diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 3435ca38dd14..57f70bc8b24b 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -268,7 +268,9 @@ static inline struct proc_dir_entry *PDE(const struct inode *inode) struct proc_maps_private { struct pid *pid; struct task_struct *task; +#ifdef CONFIG_MMU struct vm_area_struct *tail_vma; +#endif }; #endif /* _LINUX_PROC_FS_H */ -- cgit v1.2.3 From f269fdd1829acc5e53bf57b145003e5733133f2b Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 27 Sep 2006 01:50:23 -0700 Subject: [PATCH] NOMMU: move the fallback arch_vma_name() to a sensible place Move the fallback arch_vma_name() to a sensible place (kernel/signal.c). Currently it's in fs/proc/task_mmu.c, a file that is dependent on both CONFIG_PROC_FS and CONFIG_MMU being enabled, but it's used from kernel/signal.c from where it is called unconditionally. [akpm@osdl.org: build fix] Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 5 ----- include/linux/mm.h | 2 +- kernel/signal.c | 5 +++++ 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 0a163a4f7764..6b769afac55a 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -122,11 +122,6 @@ struct mem_size_stats unsigned long private_dirty; }; -__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma) -{ - return NULL; -} - static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss) { struct proc_maps_private *priv = m->private; diff --git a/include/linux/mm.h b/include/linux/mm.h index 22165cb18906..7b703b6d4358 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1131,7 +1131,7 @@ void drop_slab(void); extern int randomize_va_space; #endif -const char *arch_vma_name(struct vm_area_struct *vma); +__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma); #endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */ diff --git a/kernel/signal.c b/kernel/signal.c index bfdb5686fa3e..05853a7337e3 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2577,6 +2577,11 @@ asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) } #endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */ +__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma) +{ + return NULL; +} + void __init signals_init(void) { sigqueue_cachep = -- cgit v1.2.3 From 7e96287ddc4f42081e18248b6167041c0908004c Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Wed, 27 Sep 2006 01:50:44 -0700 Subject: [PATCH] kdump: introduce "reset_devices" command line option Resetting the devices during driver initialization can be a costly operation in terms of time (especially scsi devices). This option can be used by drivers to know that user forcibly wants the devices to be reset during initialization. This option can be useful while kernel is booting in unreliable environment. For ex. during kdump boot where devices are in unknown random state and BIOS execution has been skipped. Signed-off-by: Vivek Goyal Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 3 +++ include/linux/init.h | 1 + init/main.c | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+) (limited to 'include/linux') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 255ec535bba8..54983246930d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1370,6 +1370,9 @@ running once the system is up. Reserves a hole at the top of the kernel virtual address space. + reset_devices [KNL] Force drivers to reset the underlying device + during initialization. + resume= [SWSUSP] Specify the partition device for software suspend diff --git a/include/linux/init.h b/include/linux/init.h index 6667785dd1ff..e92b1455d7af 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -68,6 +68,7 @@ extern initcall_t __security_initcall_start[], __security_initcall_end[]; /* Defined in init/main.c */ extern char saved_command_line[]; +extern unsigned int reset_devices; /* used by init/main.c */ extern void setup_arch(char **); diff --git a/init/main.c b/init/main.c index 913e48d658ee..0766e69712b2 100644 --- a/init/main.c +++ b/init/main.c @@ -127,6 +127,18 @@ static char *ramdisk_execute_command; /* Setup configured maximum number of CPUs to activate */ static unsigned int max_cpus = NR_CPUS; +/* + * If set, this is an indication to the drivers that reset the underlying + * device before going ahead with the initialization otherwise driver might + * rely on the BIOS and skip the reset operation. + * + * This is useful if kernel is booting in an unreliable environment. + * For ex. kdump situaiton where previous kernel has crashed, BIOS has been + * skipped and devices will be in unknown state. + */ +unsigned int reset_devices; +EXPORT_SYMBOL(reset_devices); + /* * Setup routine for controlling SMP activation * @@ -153,6 +165,14 @@ static int __init maxcpus(char *str) __setup("maxcpus=", maxcpus); +static int __init set_reset_devices(char *str) +{ + reset_devices = 1; + return 1; +} + +__setup("reset_devices", set_reset_devices); + static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; static const char *panic_later, *panic_param; -- cgit v1.2.3 From 8e18e2941c53416aa219708e7dcad21fb4bd6794 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 27 Sep 2006 01:50:46 -0700 Subject: [PATCH] inode_diet: Replace inode.u.generic_ip with inode.i_private The following patches reduce the size of the VFS inode structure by 28 bytes on a UP x86. (It would be more on an x86_64 system). This is a 10% reduction in the inode size on a UP kernel that is configured in a production mode (i.e., with no spinlock or other debugging functions enabled; if you want to save memory taken up by in-core inodes, the first thing you should do is disable the debugging options; they are responsible for a huge amount of bloat in the VFS inode structure). This patch: The filesystem or device-specific pointer in the inode is inside a union, which is pretty pointless given that all 30+ users of this field have been using the void pointer. Get rid of the union and rename it to i_private, with a comment to explain who is allowed to use the void pointer. This is just a cleanup, but it allows us to reuse the union 'u' for something something where the union will actually be used. [judith@osdl.org: powerpc build fix] Signed-off-by: "Theodore Ts'o" Signed-off-by: Judith Lebzelter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/platforms/cell/spufs/inode.c | 2 +- arch/powerpc/platforms/pseries/hvCall_inst.c | 2 +- arch/s390/hypfs/inode.c | 6 ++--- arch/s390/kernel/debug.c | 2 +- block/blktrace.c | 2 +- drivers/i2c/chips/tps65010.c | 2 +- drivers/infiniband/hw/ipath/ipath_fs.c | 12 ++++----- drivers/infiniband/ulp/ipoib/ipoib_fs.c | 4 +-- drivers/misc/ibmasm/ibmasmfs.c | 16 ++++++------ drivers/net/irda/vlsi_ir.h | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 2 +- drivers/oprofile/oprofilefs.c | 10 ++++---- drivers/pci/hotplug/cpqphp_sysfs.c | 2 +- drivers/usb/core/devio.c | 2 +- drivers/usb/core/inode.c | 6 ++--- drivers/usb/gadget/inode.c | 6 ++--- drivers/usb/host/isp116x-hcd.c | 2 +- drivers/usb/host/uhci-debug.c | 2 +- drivers/usb/mon/mon_stat.c | 2 +- drivers/usb/mon/mon_text.c | 4 +-- fs/autofs/inode.c | 2 +- fs/autofs/symlink.c | 2 +- fs/binfmt_misc.c | 8 +++--- fs/debugfs/file.c | 4 +-- fs/debugfs/inode.c | 4 +-- fs/devpts/inode.c | 4 +-- fs/freevxfs/vxfs.h | 2 +- fs/freevxfs/vxfs_inode.c | 4 +-- fs/fuse/control.c | 6 ++--- fs/inode.c | 2 +- fs/jffs/inode-v23.c | 34 +++++++++++++------------- fs/libfs.c | 2 +- fs/ocfs2/dlmglue.c | 2 +- include/linux/fs.h | 4 +-- kernel/relay.c | 2 +- security/inode.c | 8 +++--- 36 files changed, 88 insertions(+), 90 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 7b4572805db9..b837f12a84ae 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -120,7 +120,7 @@ spufs_new_file(struct super_block *sb, struct dentry *dentry, ret = 0; inode->i_op = &spufs_file_iops; inode->i_fop = fops; - inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); + inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); d_add(dentry, inode); out: return ret; diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index 641e6511cf06..446e17d162a5 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c @@ -85,7 +85,7 @@ static int hcall_inst_seq_open(struct inode *inode, struct file *file) rc = seq_open(file, &hcall_inst_seq_ops); seq = file->private_data; - seq->private = file->f_dentry->d_inode->u.generic_ip; + seq->private = file->f_dentry->d_inode->i_private; return rc; } diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index bdade5f2e325..8735024d235b 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -104,13 +104,13 @@ static struct inode *hypfs_make_inode(struct super_block *sb, int mode) static void hypfs_drop_inode(struct inode *inode) { - kfree(inode->u.generic_ip); + kfree(inode->i_private); generic_delete_inode(inode); } static int hypfs_open(struct inode *inode, struct file *filp) { - char *data = filp->f_dentry->d_inode->u.generic_ip; + char *data = filp->f_dentry->d_inode->i_private; struct hypfs_sb_info *fs_info; if (filp->f_mode & FMODE_WRITE) { @@ -352,7 +352,7 @@ static struct dentry *hypfs_create_file(struct super_block *sb, parent->d_inode->i_nlink++; } else BUG(); - inode->u.generic_ip = data; + inode->i_private = data; d_instantiate(dentry, inode); dget(dentry); return dentry; diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 7ba20922a535..43f3d0c7e132 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -603,7 +603,7 @@ debug_open(struct inode *inode, struct file *file) debug_info_t *debug_info, *debug_info_snapshot; down(&debug_lock); - debug_info = (struct debug_info*)file->f_dentry->d_inode->u.generic_ip; + debug_info = file->f_dentry->d_inode->i_private; /* find debug view */ for (i = 0; i < DEBUG_MAX_VIEWS; i++) { if (!debug_info->views[i]) diff --git a/block/blktrace.c b/block/blktrace.c index 265f7a830619..2b4ef2b89b8d 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -217,7 +217,7 @@ static int blk_trace_remove(request_queue_t *q) static int blk_dropped_open(struct inode *inode, struct file *filp) { - filp->private_data = inode->u.generic_ip; + filp->private_data = inode->i_private; return 0; } diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index 0be6fd6a267d..6a7578217177 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -305,7 +305,7 @@ static int dbg_show(struct seq_file *s, void *_) static int dbg_tps_open(struct inode *inode, struct file *file) { - return single_open(file, dbg_show, inode->u.generic_ip); + return single_open(file, dbg_show, inode->i_private); } static struct file_operations debug_fops = { diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index a5eb30a06a5c..055cdd089b28 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -64,7 +64,7 @@ static int ipathfs_mknod(struct inode *dir, struct dentry *dentry, inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->u.generic_ip = data; + inode->i_private = data; if ((mode & S_IFMT) == S_IFDIR) { inode->i_op = &simple_dir_inode_operations; inode->i_nlink++; @@ -119,7 +119,7 @@ static ssize_t atomic_counters_read(struct file *file, char __user *buf, u16 i; struct ipath_devdata *dd; - dd = file->f_dentry->d_inode->u.generic_ip; + dd = file->f_dentry->d_inode->i_private; for (i = 0; i < NUM_COUNTERS; i++) counters[i] = ipath_snap_cntr(dd, i); @@ -139,7 +139,7 @@ static ssize_t atomic_node_info_read(struct file *file, char __user *buf, struct ipath_devdata *dd; u64 guid; - dd = file->f_dentry->d_inode->u.generic_ip; + dd = file->f_dentry->d_inode->i_private; guid = be64_to_cpu(dd->ipath_guid); @@ -178,7 +178,7 @@ static ssize_t atomic_port_info_read(struct file *file, char __user *buf, u32 tmp, tmp2; struct ipath_devdata *dd; - dd = file->f_dentry->d_inode->u.generic_ip; + dd = file->f_dentry->d_inode->i_private; /* so we only initialize non-zero fields. */ memset(portinfo, 0, sizeof portinfo); @@ -325,7 +325,7 @@ static ssize_t flash_read(struct file *file, char __user *buf, goto bail; } - dd = file->f_dentry->d_inode->u.generic_ip; + dd = file->f_dentry->d_inode->i_private; if (ipath_eeprom_read(dd, pos, tmp, count)) { ipath_dev_err(dd, "failed to read from flash\n"); ret = -ENXIO; @@ -381,7 +381,7 @@ static ssize_t flash_write(struct file *file, const char __user *buf, goto bail_tmp; } - dd = file->f_dentry->d_inode->u.generic_ip; + dd = file->f_dentry->d_inode->i_private; if (ipath_eeprom_write(dd, pos, tmp, count)) { ret = -ENXIO; ipath_dev_err(dd, "failed to write to flash\n"); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c index 5dde380e8dbe..f1cb83688b31 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c @@ -141,7 +141,7 @@ static int ipoib_mcg_open(struct inode *inode, struct file *file) return ret; seq = file->private_data; - seq->private = inode->u.generic_ip; + seq->private = inode->i_private; return 0; } @@ -247,7 +247,7 @@ static int ipoib_path_open(struct inode *inode, struct file *file) return ret; seq = file->private_data; - seq->private = inode->u.generic_ip; + seq->private = inode->i_private; return 0; } diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 4a35caff5d02..0e909b617226 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -175,7 +175,7 @@ static struct dentry *ibmasmfs_create_file (struct super_block *sb, } inode->i_fop = fops; - inode->u.generic_ip = data; + inode->i_private = data; d_add(dentry, inode); return dentry; @@ -244,7 +244,7 @@ static int command_file_open(struct inode *inode, struct file *file) { struct ibmasmfs_command_data *command_data; - if (!inode->u.generic_ip) + if (!inode->i_private) return -ENODEV; command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL); @@ -252,7 +252,7 @@ static int command_file_open(struct inode *inode, struct file *file) return -ENOMEM; command_data->command = NULL; - command_data->sp = inode->u.generic_ip; + command_data->sp = inode->i_private; file->private_data = command_data; return 0; } @@ -351,10 +351,10 @@ static int event_file_open(struct inode *inode, struct file *file) struct ibmasmfs_event_data *event_data; struct service_processor *sp; - if (!inode->u.generic_ip) + if (!inode->i_private) return -ENODEV; - sp = inode->u.generic_ip; + sp = inode->i_private; event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL); if (!event_data) @@ -439,14 +439,14 @@ static int r_heartbeat_file_open(struct inode *inode, struct file *file) { struct ibmasmfs_heartbeat_data *rhbeat; - if (!inode->u.generic_ip) + if (!inode->i_private) return -ENODEV; rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL); if (!rhbeat) return -ENOMEM; - rhbeat->sp = (struct service_processor *)inode->u.generic_ip; + rhbeat->sp = inode->i_private; rhbeat->active = 0; ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat); file->private_data = rhbeat; @@ -508,7 +508,7 @@ static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf, static int remote_settings_file_open(struct inode *inode, struct file *file) { - file->private_data = inode->u.generic_ip; + file->private_data = inode->i_private; return 0; } diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index a82a4ba8de4f..c37f0bc4c7f9 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -58,7 +58,7 @@ typedef void irqreturn_t; /* PDE() introduced in 2.5.4 */ #ifdef CONFIG_PROC_FS -#define PDE(inode) ((inode)->u.generic_ip) +#define PDE(inode) ((inode)->i_private) #endif /* irda crc16 calculation exported in 2.5.42 */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index 923275ea0789..b9df06a06ea9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -54,7 +54,7 @@ static ssize_t write_file_dummy(struct file *file, const char __user *buf, static int open_file_generic(struct inode *inode, struct file *file) { - file->private_data = inode->u.generic_ip; + file->private_data = inode->i_private; return 0; } diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 71c2da277d6e..deb37354785b 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -110,8 +110,8 @@ static ssize_t ulong_write_file(struct file * file, char const __user * buf, siz static int default_open(struct inode * inode, struct file * filp) { - if (inode->u.generic_ip) - filp->private_data = inode->u.generic_ip; + if (inode->i_private) + filp->private_data = inode->i_private; return 0; } @@ -158,7 +158,7 @@ int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root, if (!d) return -EFAULT; - d->d_inode->u.generic_ip = val; + d->d_inode->i_private = val; return 0; } @@ -171,7 +171,7 @@ int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root, if (!d) return -EFAULT; - d->d_inode->u.generic_ip = val; + d->d_inode->i_private = val; return 0; } @@ -197,7 +197,7 @@ int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root, if (!d) return -EFAULT; - d->d_inode->u.generic_ip = val; + d->d_inode->i_private = val; return 0; } diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 8b3da007e859..5bab666cd67e 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -140,7 +140,7 @@ struct ctrl_dbg { static int open(struct inode *inode, struct file *file) { - struct controller *ctrl = inode->u.generic_ip; + struct controller *ctrl = inode->i_private; struct ctrl_dbg *dbg; int retval = -ENOMEM; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 218621b9958e..32e03000420c 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -555,7 +555,7 @@ static int usbdev_open(struct inode *inode, struct file *file) if (imajor(inode) == USB_DEVICE_MAJOR) dev = usbdev_lookup_minor(iminor(inode)); if (!dev) - dev = inode->u.generic_ip; + dev = inode->i_private; if (!dev) { kfree(ps); goto out; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 3182c2224ba2..482f253085e5 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -402,8 +402,8 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) static int default_open (struct inode *inode, struct file *file) { - if (inode->u.generic_ip) - file->private_data = inode->u.generic_ip; + if (inode->i_private) + file->private_data = inode->i_private; return 0; } @@ -509,7 +509,7 @@ static struct dentry *fs_create_file (const char *name, mode_t mode, } else { if (dentry->d_inode) { if (data) - dentry->d_inode->u.generic_ip = data; + dentry->d_inode->i_private = data; if (fops) dentry->d_inode->i_fop = fops; dentry->d_inode->i_uid = uid; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 3bdc5e3ba234..ffaa8c1afad8 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -844,7 +844,7 @@ fail1: static int ep_open (struct inode *inode, struct file *fd) { - struct ep_data *data = inode->u.generic_ip; + struct ep_data *data = inode->i_private; int value = -EBUSY; if (down_interruptible (&data->lock) != 0) @@ -1909,7 +1909,7 @@ fail: static int dev_open (struct inode *inode, struct file *fd) { - struct dev_data *dev = inode->u.generic_ip; + struct dev_data *dev = inode->i_private; int value = -EBUSY; if (dev->state == STATE_DEV_DISABLED) { @@ -1970,7 +1970,7 @@ gadgetfs_make_inode (struct super_block *sb, inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->u.generic_ip = data; + inode->i_private = data; inode->i_fop = fops; } return inode; diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5147ed4a6662..8c6b38a0b5bb 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1204,7 +1204,7 @@ static int isp116x_show_dbg(struct seq_file *s, void *unused) static int isp116x_open_seq(struct inode *inode, struct file *file) { - return single_open(file, isp116x_show_dbg, inode->u.generic_ip); + return single_open(file, isp116x_show_dbg, inode->i_private); } static struct file_operations isp116x_debug_fops = { diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index dc286a48cafd..d1372cb27f33 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -428,7 +428,7 @@ struct uhci_debug { static int uhci_debug_open(struct inode *inode, struct file *file) { - struct uhci_hcd *uhci = inode->u.generic_ip; + struct uhci_hcd *uhci = inode->i_private; struct uhci_debug *up; int ret = -ENOMEM; unsigned long flags; diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c index 1fe01d994a79..86ad2b381c4b 100644 --- a/drivers/usb/mon/mon_stat.c +++ b/drivers/usb/mon/mon_stat.c @@ -28,7 +28,7 @@ static int mon_stat_open(struct inode *inode, struct file *file) if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL) return -ENOMEM; - mbus = inode->u.generic_ip; + mbus = inode->i_private; sp->slen = snprintf(sp->str, STAT_BUF_SIZE, "nreaders %d events %u text_lost %u\n", diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index f961a770cee2..2fd39b4fa166 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -238,7 +238,7 @@ static int mon_text_open(struct inode *inode, struct file *file) int rc; mutex_lock(&mon_lock); - mbus = inode->u.generic_ip; + mbus = inode->i_private; ubus = mbus->u_bus; rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL); @@ -401,7 +401,7 @@ static int mon_text_release(struct inode *inode, struct file *file) struct mon_event_text *ep; mutex_lock(&mon_lock); - mbus = inode->u.generic_ip; + mbus = inode->i_private; if (mbus->nreaders <= 0) { printk(KERN_ERR TAG ": consistency error on close\n"); diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index c81d6b8c2828..d39d2acd9b38 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -241,7 +241,7 @@ static void autofs_read_inode(struct inode *inode) inode->i_op = &autofs_symlink_inode_operations; sl = &sbi->symlink[n]; - inode->u.generic_ip = sl; + inode->i_private = sl; inode->i_mode = S_IFLNK | S_IRWXUGO; inode->i_mtime.tv_sec = inode->i_ctime.tv_sec = sl->mtime; inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0; diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c index 52e8772b066e..c74f2eb65775 100644 --- a/fs/autofs/symlink.c +++ b/fs/autofs/symlink.c @@ -15,7 +15,7 @@ /* Nothing to release.. */ static void *autofs_follow_link(struct dentry *dentry, struct nameidata *nd) { - char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data; + char *s=((struct autofs_symlink *)dentry->d_inode->i_private)->data; nd_set_link(nd, s); return NULL; } diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 34ebbc191e46..6759b9839ce8 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -517,7 +517,7 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode) static void bm_clear_inode(struct inode *inode) { - kfree(inode->u.generic_ip); + kfree(inode->i_private); } static void kill_node(Node *e) @@ -545,7 +545,7 @@ static void kill_node(Node *e) static ssize_t bm_entry_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) { - Node *e = file->f_dentry->d_inode->u.generic_ip; + Node *e = file->f_dentry->d_inode->i_private; loff_t pos = *ppos; ssize_t res; char *page; @@ -579,7 +579,7 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct dentry *root; - Node *e = file->f_dentry->d_inode->u.generic_ip; + Node *e = file->f_dentry->d_inode->i_private; int res = parse_command(buffer, count); switch (res) { @@ -646,7 +646,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer, } e->dentry = dget(dentry); - inode->u.generic_ip = e; + inode->i_private = e; inode->i_fop = &bm_entry_operations; d_instantiate(dentry, inode); diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index e4b430552c88..bf3901ab1744 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -32,8 +32,8 @@ static ssize_t default_write_file(struct file *file, const char __user *buf, static int default_open(struct inode *inode, struct file *file) { - if (inode->u.generic_ip) - file->private_data = inode->u.generic_ip; + if (inode->i_private) + file->private_data = inode->i_private; return 0; } diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 3ca268d2e5a2..717f4821ed02 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -168,7 +168,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, * directory dentry if set. If this paramater is NULL, then the * file will be created in the root of the debugfs filesystem. * @data: a pointer to something that the caller will want to get to later - * on. The inode.u.generic_ip pointer will point to this value on + * on. The inode.i_private pointer will point to this value on * the open() call. * @fops: a pointer to a struct file_operations that should be used for * this file. @@ -209,7 +209,7 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode, if (dentry->d_inode) { if (data) - dentry->d_inode->u.generic_ip = data; + dentry->d_inode->i_private = data; if (fops) dentry->d_inode->i_fop = fops; } diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index f7aef5bb584a..5bf06a10dddf 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -177,7 +177,7 @@ int devpts_pty_new(struct tty_struct *tty) inode->i_gid = config.setgid ? config.gid : current->fsgid; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; init_special_inode(inode, S_IFCHR|config.mode, device); - inode->u.generic_ip = tty; + inode->i_private = tty; dentry = get_node(number); if (!IS_ERR(dentry) && !dentry->d_inode) @@ -196,7 +196,7 @@ struct tty_struct *devpts_get_tty(int number) tty = NULL; if (!IS_ERR(dentry)) { if (dentry->d_inode) - tty = dentry->d_inode->u.generic_ip; + tty = dentry->d_inode->i_private; dput(dentry); } diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h index d35979a58743..c8a92652612a 100644 --- a/fs/freevxfs/vxfs.h +++ b/fs/freevxfs/vxfs.h @@ -252,7 +252,7 @@ enum { * Get filesystem private data from VFS inode. */ #define VXFS_INO(ip) \ - ((struct vxfs_inode_info *)(ip)->u.generic_ip) + ((struct vxfs_inode_info *)(ip)->i_private) /* * Get filesystem private data from VFS superblock. diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index ca6a39714771..32a82ed108e4 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c @@ -243,7 +243,7 @@ vxfs_iinit(struct inode *ip, struct vxfs_inode_info *vip) ip->i_blocks = vip->vii_blocks; ip->i_generation = vip->vii_gen; - ip->u.generic_ip = (void *)vip; + ip->i_private = vip; } @@ -338,5 +338,5 @@ vxfs_read_inode(struct inode *ip) void vxfs_clear_inode(struct inode *ip) { - kmem_cache_free(vxfs_inode_cachep, ip->u.generic_ip); + kmem_cache_free(vxfs_inode_cachep, ip->i_private); } diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 46fe60b2da23..79ec1f23d4d2 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -23,7 +23,7 @@ static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file) { struct fuse_conn *fc; mutex_lock(&fuse_mutex); - fc = file->f_dentry->d_inode->u.generic_ip; + fc = file->f_dentry->d_inode->i_private; if (fc) fc = fuse_conn_get(fc); mutex_unlock(&fuse_mutex); @@ -98,7 +98,7 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, inode->i_op = iop; inode->i_fop = fop; inode->i_nlink = nlink; - inode->u.generic_ip = fc; + inode->i_private = fc; d_add(dentry, inode); return dentry; } @@ -150,7 +150,7 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc) for (i = fc->ctl_ndents - 1; i >= 0; i--) { struct dentry *dentry = fc->ctl_dentry[i]; - dentry->d_inode->u.generic_ip = NULL; + dentry->d_inode->i_private = NULL; d_drop(dentry); dput(dentry); } diff --git a/fs/inode.c b/fs/inode.c index 0bf9f0444a96..77e254792025 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -163,7 +163,7 @@ static struct inode *alloc_inode(struct super_block *sb) bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; mapping->backing_dev_info = bdi; } - memset(&inode->u, 0, sizeof(inode->u)); + inode->i_private = 0; inode->i_mapping = mapping; } return inode; diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index b59553d28d13..7358ef87f16b 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -369,7 +369,7 @@ jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode, f = jffs_find_file(c, raw_inode->ino); - inode->u.generic_ip = (void *)f; + inode->i_private = (void *)f; insert_inode_hash(inode); return inode; @@ -442,7 +442,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, }); result = -ENOTDIR; - if (!(old_dir_f = (struct jffs_file *)old_dir->u.generic_ip)) { + if (!(old_dir_f = old_dir->i_private)) { D(printk("jffs_rename(): Old dir invalid.\n")); goto jffs_rename_end; } @@ -456,7 +456,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, /* Find the new directory. */ result = -ENOTDIR; - if (!(new_dir_f = (struct jffs_file *)new_dir->u.generic_ip)) { + if (!(new_dir_f = new_dir->i_private)) { D(printk("jffs_rename(): New dir invalid.\n")); goto jffs_rename_end; } @@ -593,7 +593,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir) } else { ddino = ((struct jffs_file *) - inode->u.generic_ip)->pino; + inode->i_private)->pino; } D3(printk("jffs_readdir(): \"..\" %u\n", ddino)); if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0) { @@ -604,7 +604,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir) } filp->f_pos++; } - f = ((struct jffs_file *)inode->u.generic_ip)->children; + f = ((struct jffs_file *)inode->i_private)->children; j = 2; while(f && (f->deleted || j++ < filp->f_pos )) { @@ -668,7 +668,7 @@ jffs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) } r = -EACCES; - if (!(d = (struct jffs_file *)dir->u.generic_ip)) { + if (!(d = (struct jffs_file *)dir->i_private)) { D(printk("jffs_lookup(): No such inode! (%lu)\n", dir->i_ino)); goto jffs_lookup_end; @@ -739,7 +739,7 @@ jffs_do_readpage_nolock(struct file *file, struct page *page) unsigned long read_len; int result; struct inode *inode = (struct inode*)page->mapping->host; - struct jffs_file *f = (struct jffs_file *)inode->u.generic_ip; + struct jffs_file *f = (struct jffs_file *)inode->i_private; struct jffs_control *c = (struct jffs_control *)inode->i_sb->s_fs_info; int r; loff_t offset; @@ -828,7 +828,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) }); lock_kernel(); - dir_f = (struct jffs_file *)dir->u.generic_ip; + dir_f = dir->i_private; ASSERT(if (!dir_f) { printk(KERN_ERR "jffs_mkdir(): No reference to a " @@ -972,7 +972,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type) kfree(_name); }); - dir_f = (struct jffs_file *) dir->u.generic_ip; + dir_f = dir->i_private; c = dir_f->c; result = -ENOENT; @@ -1082,7 +1082,7 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) if (!old_valid_dev(rdev)) return -EINVAL; lock_kernel(); - dir_f = (struct jffs_file *)dir->u.generic_ip; + dir_f = dir->i_private; c = dir_f->c; D3(printk (KERN_NOTICE "mknod(): down biglock\n")); @@ -1186,7 +1186,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) kfree(_symname); }); - dir_f = (struct jffs_file *)dir->u.generic_ip; + dir_f = dir->i_private; ASSERT(if (!dir_f) { printk(KERN_ERR "jffs_symlink(): No reference to a " "jffs_file struct in inode.\n"); @@ -1289,7 +1289,7 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode, kfree(s); }); - dir_f = (struct jffs_file *)dir->u.generic_ip; + dir_f = dir->i_private; ASSERT(if (!dir_f) { printk(KERN_ERR "jffs_create(): No reference to a " "jffs_file struct in inode.\n"); @@ -1403,9 +1403,9 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, goto out_isem; } - if (!(f = (struct jffs_file *)inode->u.generic_ip)) { - D(printk("jffs_file_write(): inode->u.generic_ip = 0x%p\n", - inode->u.generic_ip)); + if (!(f = inode->i_private)) { + D(printk("jffs_file_write(): inode->i_private = 0x%p\n", + inode->i_private)); goto out_isem; } @@ -1693,7 +1693,7 @@ jffs_read_inode(struct inode *inode) mutex_unlock(&c->fmc->biglock); return; } - inode->u.generic_ip = (void *)f; + inode->i_private = f; inode->i_mode = f->mode; inode->i_nlink = f->nlink; inode->i_uid = f->uid; @@ -1748,7 +1748,7 @@ jffs_delete_inode(struct inode *inode) lock_kernel(); inode->i_size = 0; inode->i_blocks = 0; - inode->u.generic_ip = NULL; + inode->i_private = NULL; clear_inode(inode); if (inode->i_nlink == 0) { c = (struct jffs_control *) inode->i_sb->s_fs_info; diff --git a/fs/libfs.c b/fs/libfs.c index ac02ea602c3d..2751793beeaa 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -547,7 +547,7 @@ int simple_attr_open(struct inode *inode, struct file *file, attr->get = get; attr->set = set; - attr->data = inode->u.generic_ip; + attr->data = inode->i_private; attr->fmt = fmt; mutex_init(&attr->mutex); diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index de887063dcfc..8801e41afe80 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -2052,7 +2052,7 @@ static int ocfs2_dlm_debug_open(struct inode *inode, struct file *file) mlog_errno(ret); goto out; } - osb = (struct ocfs2_super *) inode->u.generic_ip; + osb = inode->i_private; ocfs2_get_dlm_debug(osb->osb_dlm_debug); priv->p_dlm_debug = osb->osb_dlm_debug; INIT_LIST_HEAD(&priv->p_iter_res.l_debug_list); diff --git a/include/linux/fs.h b/include/linux/fs.h index 1d3e601ece73..4f77ec9c3353 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -554,9 +554,7 @@ struct inode { atomic_t i_writecount; void *i_security; - union { - void *generic_ip; - } u; + void *i_private; /* fs or device private pointer */ #ifdef __NEED_I_SIZE_ORDERED seqcount_t i_size_seqcount; #endif diff --git a/kernel/relay.c b/kernel/relay.c index 33345e73485c..85786ff2a4f9 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -669,7 +669,7 @@ EXPORT_SYMBOL_GPL(relay_flush); */ static int relay_file_open(struct inode *inode, struct file *filp) { - struct rchan_buf *buf = inode->u.generic_ip; + struct rchan_buf *buf = inode->i_private; kref_get(&buf->kref); filp->private_data = buf; diff --git a/security/inode.c b/security/inode.c index 47eb63480dac..176aacea8ca4 100644 --- a/security/inode.c +++ b/security/inode.c @@ -44,8 +44,8 @@ static ssize_t default_write_file(struct file *file, const char __user *buf, static int default_open(struct inode *inode, struct file *file) { - if (inode->u.generic_ip) - file->private_data = inode->u.generic_ip; + if (inode->i_private) + file->private_data = inode->i_private; return 0; } @@ -194,7 +194,7 @@ static int create_by_name(const char *name, mode_t mode, * directory dentry if set. If this paramater is NULL, then the * file will be created in the root of the securityfs filesystem. * @data: a pointer to something that the caller will want to get to later - * on. The inode.u.generic_ip pointer will point to this value on + * on. The inode.i_private pointer will point to this value on * the open() call. * @fops: a pointer to a struct file_operations that should be used for * this file. @@ -240,7 +240,7 @@ struct dentry *securityfs_create_file(const char *name, mode_t mode, if (fops) dentry->d_inode->i_fop = fops; if (data) - dentry->d_inode->u.generic_ip = data; + dentry->d_inode->i_private = data; } exit: return dentry; -- cgit v1.2.3 From 4c1541680f8d189d21dd07b053bc12996574646e Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 27 Sep 2006 01:50:47 -0700 Subject: [PATCH] inode-diet: Move i_pipe into a union Move the i_pipe pointer into a union that will be shared with i_bdev and i_cdev. Signed-off-by: "Theodore Ts'o" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 4f77ec9c3353..ca695fc8d69c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -528,9 +528,10 @@ struct inode { #ifdef CONFIG_QUOTA struct dquot *i_dquot[MAXQUOTAS]; #endif - /* These three should probably be a union */ struct list_head i_devices; - struct pipe_inode_info *i_pipe; + union { + struct pipe_inode_info *i_pipe; + }; struct block_device *i_bdev; struct cdev *i_cdev; int i_cindex; -- cgit v1.2.3 From eaf796e7ef6014f208c409b2b14fddcfaafe7e3a Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 27 Sep 2006 01:50:48 -0700 Subject: [PATCH] inode-diet: Move i_bdev into a union Move the i_bdev pointer in struct inode into a union. Signed-off-by: "Theodore Ts'o" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/inode.c | 2 +- include/linux/fs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/inode.c b/fs/inode.c index 77e254792025..41b462232f7f 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -254,7 +254,7 @@ void clear_inode(struct inode *inode) DQUOT_DROP(inode); if (inode->i_sb && inode->i_sb->s_op->clear_inode) inode->i_sb->s_op->clear_inode(inode); - if (inode->i_bdev) + if (S_ISBLK(inode->i_mode) && inode->i_bdev) bd_forget(inode); if (inode->i_cdev) cd_forget(inode); diff --git a/include/linux/fs.h b/include/linux/fs.h index ca695fc8d69c..98ff684a5b1c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -531,8 +531,8 @@ struct inode { struct list_head i_devices; union { struct pipe_inode_info *i_pipe; + struct block_device *i_bdev; }; - struct block_device *i_bdev; struct cdev *i_cdev; int i_cindex; -- cgit v1.2.3 From 577c4eb09d1034d0739e3135fd2cff50588024be Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 27 Sep 2006 01:50:49 -0700 Subject: [PATCH] inode-diet: Move i_cdev into a union Move the i_cdev pointer in struct inode into a union. Signed-off-by: "Theodore Ts'o" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/file_table.c | 2 +- fs/inode.c | 2 +- include/linux/fs.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/fs/file_table.c b/fs/file_table.c index 0131ba06e1ee..bc35a40417d7 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -169,7 +169,7 @@ void fastcall __fput(struct file *file) if (file->f_op && file->f_op->release) file->f_op->release(inode, file); security_file_free(file); - if (unlikely(inode->i_cdev != NULL)) + if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) cdev_put(inode->i_cdev); fops_put(file->f_op); if (file->f_mode & FMODE_WRITE) diff --git a/fs/inode.c b/fs/inode.c index 41b462232f7f..f5c04dd9ae8a 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -256,7 +256,7 @@ void clear_inode(struct inode *inode) inode->i_sb->s_op->clear_inode(inode); if (S_ISBLK(inode->i_mode) && inode->i_bdev) bd_forget(inode); - if (inode->i_cdev) + if (S_ISCHR(inode->i_mode) && inode->i_cdev) cd_forget(inode); inode->i_state = I_CLEAR; } diff --git a/include/linux/fs.h b/include/linux/fs.h index 98ff684a5b1c..192e69bb55b5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -532,8 +532,8 @@ struct inode { union { struct pipe_inode_info *i_pipe; struct block_device *i_bdev; + struct cdev *i_cdev; }; - struct cdev *i_cdev; int i_cindex; __u32 i_generation; -- cgit v1.2.3 From ba52de123d454b57369f291348266d86f4b35070 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 27 Sep 2006 01:50:49 -0700 Subject: [PATCH] inode-diet: Eliminate i_blksize from the inode structure This eliminates the i_blksize field from struct inode. Filesystems that want to provide a per-inode st_blksize can do so by providing their own getattr routine instead of using the generic_fillattr() function. Note that some filesystems were providing pretty much random (and incorrect) values for i_blksize. [bunk@stusta.de: cleanup] [akpm@osdl.org: generic_fillattr() fix] Signed-off-by: "Theodore Ts'o" Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/platforms/cell/spufs/inode.c | 1 - arch/s390/hypfs/inode.c | 1 - drivers/block/loop.c | 7 +++++-- drivers/infiniband/hw/ipath/ipath_fs.c | 1 - drivers/isdn/capi/capifs.c | 2 -- drivers/misc/ibmasm/ibmasmfs.c | 1 - drivers/oprofile/oprofilefs.c | 1 - drivers/usb/core/inode.c | 1 - drivers/usb/gadget/inode.c | 1 - fs/9p/vfs_inode.c | 4 +--- fs/adfs/inode.c | 1 - fs/afs/inode.c | 1 - fs/autofs/inode.c | 1 - fs/autofs4/inode.c | 1 - fs/befs/linuxvfs.c | 1 - fs/bfs/dir.c | 2 +- fs/bfs/inode.c | 1 - fs/binfmt_misc.c | 1 - fs/cifs/cifsfs.c | 1 - fs/cifs/readdir.c | 5 ++--- fs/coda/coda_linux.c | 2 -- fs/configfs/inode.c | 1 - fs/cramfs/inode.c | 1 - fs/debugfs/inode.c | 1 - fs/devpts/inode.c | 2 -- fs/eventpoll.c | 1 - fs/ext2/ialloc.c | 1 - fs/ext2/inode.c | 1 - fs/ext3/ialloc.c | 1 - fs/ext3/inode.c | 3 --- fs/fat/inode.c | 3 --- fs/freevxfs/vxfs_inode.c | 1 - fs/fuse/inode.c | 1 - fs/hfs/inode.c | 2 -- fs/hfsplus/inode.c | 2 -- fs/hostfs/hostfs_kern.c | 1 - fs/hpfs/inode.c | 1 - fs/hppfs/hppfs_kern.c | 1 - fs/hugetlbfs/inode.c | 1 - fs/isofs/inode.c | 3 +-- fs/jffs/inode-v23.c | 2 -- fs/jffs2/fs.c | 2 -- fs/jfs/jfs_extent.c | 2 +- fs/jfs/jfs_imap.c | 1 - fs/jfs/jfs_inode.c | 1 - fs/jfs/jfs_metapage.c | 2 +- fs/libfs.c | 2 -- fs/minix/bitmap.c | 2 +- fs/minix/inode.c | 4 ++-- fs/ncpfs/inode.c | 1 - fs/nfs/inode.c | 4 ---- fs/ntfs/inode.c | 4 ---- fs/ntfs/mft.c | 5 ----- fs/ocfs2/dlm/dlmfs.c | 2 -- fs/ocfs2/inode.c | 4 ---- fs/pipe.c | 1 - fs/qnx4/inode.c | 1 - fs/ramfs/inode.c | 1 - fs/reiserfs/inode.c | 4 ---- fs/smbfs/inode.c | 2 -- fs/smbfs/proc.c | 1 - fs/stat.c | 3 ++- fs/sysfs/inode.c | 1 - fs/sysv/ialloc.c | 2 +- fs/sysv/inode.c | 2 +- fs/udf/ialloc.c | 1 - fs/udf/inode.c | 2 -- fs/ufs/ialloc.c | 1 - fs/ufs/inode.c | 1 - fs/xfs/linux-2.6/xfs_super.c | 1 - fs/xfs/linux-2.6/xfs_vnode.c | 1 - include/linux/fs.h | 1 - include/linux/nfsd/nfsfh.h | 10 ++-------- include/linux/smb.h | 1 - ipc/mqueue.c | 1 - kernel/cpuset.c | 1 - mm/shmem.c | 1 - net/sunrpc/rpc_pipe.c | 1 - security/inode.c | 1 - security/selinux/selinuxfs.c | 1 - 80 files changed, 21 insertions(+), 125 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index b837f12a84ae..3950ddccb2c8 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -82,7 +82,6 @@ spufs_new_inode(struct super_block *sb, int mode) inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; out: diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 8735024d235b..813fc21358f9 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -91,7 +91,6 @@ static struct inode *hypfs_make_inode(struct super_block *sb, int mode) ret->i_mode = mode; ret->i_uid = hypfs_info->uid; ret->i_gid = hypfs_info->gid; - ret->i_blksize = PAGE_CACHE_SIZE; ret->i_blocks = 0; ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; if (mode & S_IFDIR) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 7b3b94ddddcc..c774121684d7 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -662,7 +662,8 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p) mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask); lo->lo_backing_file = file; - lo->lo_blocksize = mapping->host->i_blksize; + lo->lo_blocksize = S_ISBLK(mapping->host->i_mode) ? + mapping->host->i_bdev->bd_block_size : PAGE_SIZE; lo->old_gfp_mask = mapping_gfp_mask(mapping); mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); complete(&p->wait); @@ -794,7 +795,9 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write) lo_flags |= LO_FLAGS_READ_ONLY; - lo_blocksize = inode->i_blksize; + lo_blocksize = S_ISBLK(inode->i_mode) ? + inode->i_bdev->bd_block_size : PAGE_SIZE; + error = 0; } else { goto out_putf; diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 055cdd089b28..c8a8af0fe471 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -61,7 +61,6 @@ static int ipathfs_mknod(struct inode *dir, struct dentry *dentry, inode->i_mode = mode; inode->i_uid = 0; inode->i_gid = 0; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_private = data; diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 9ea6bd0ddc35..2dd1b57b0ba4 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -104,7 +104,6 @@ capifs_fill_super(struct super_block *s, void *data, int silent) inode->i_ino = 1; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_blocks = 0; - inode->i_blksize = 1024; inode->i_uid = inode->i_gid = 0; inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; inode->i_op = &simple_dir_inode_operations; @@ -149,7 +148,6 @@ void capifs_new_ncci(unsigned int number, dev_t device) if (!inode) return; inode->i_ino = number+2; - inode->i_blksize = 1024; inode->i_uid = config.setuid ? config.uid : current->fsuid; inode->i_gid = config.setgid ? config.gid : current->fsgid; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 0e909b617226..b99dc507de2e 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -147,7 +147,6 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode) if (ret) { ret->i_mode = mode; ret->i_uid = ret->i_gid = 0; - ret->i_blksize = PAGE_CACHE_SIZE; ret->i_blocks = 0; ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; } diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index deb37354785b..5756401fb15b 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -31,7 +31,6 @@ static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode) inode->i_mode = mode; inode->i_uid = 0; inode->i_gid = 0; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; } diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 482f253085e5..58b4b1012120 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -249,7 +249,6 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index ffaa8c1afad8..2a7162d89799 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1966,7 +1966,6 @@ gadgetfs_make_inode (struct super_block *sb, inode->i_mode = mode; inode->i_uid = default_uid; inode->i_gid = default_gid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index eae50c9d6dc4..7a7ec2d1d2f4 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -204,7 +204,6 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = sb->s_blocksize; inode->i_blocks = 0; inode->i_rdev = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; @@ -950,9 +949,8 @@ v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, inode->i_size = stat->length; - inode->i_blksize = sb->s_blocksize; inode->i_blocks = - (inode->i_size + inode->i_blksize - 1) >> sb->s_blocksize_bits; + (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; } /** diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index 534f3eecc985..7e7a04be1278 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c @@ -269,7 +269,6 @@ adfs_iget(struct super_block *sb, struct object_info *obj) inode->i_ino = obj->file_id; inode->i_size = obj->size; inode->i_nlink = 2; - inode->i_blksize = PAGE_SIZE; inode->i_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 4ebb30a50ed5..6f37754906c2 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -72,7 +72,6 @@ static int afs_inode_map_status(struct afs_vnode *vnode) inode->i_ctime.tv_sec = vnode->status.mtime_server; inode->i_ctime.tv_nsec = 0; inode->i_atime = inode->i_mtime = inode->i_ctime; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_version = vnode->fid.unique; inode->i_mapping->a_ops = &afs_fs_aops; diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index d39d2acd9b38..2c9759baad61 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -216,7 +216,6 @@ static void autofs_read_inode(struct inode *inode) inode->i_nlink = 2; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_blocks = 0; - inode->i_blksize = 1024; if ( ino == AUTOFS_ROOT_INO ) { inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 11a6a9ae51b7..800ce876caec 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -447,7 +447,6 @@ struct inode *autofs4_get_inode(struct super_block *sb, inode->i_uid = 0; inode->i_gid = 0; } - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index f6676fbe9484..57020c7a7e65 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -365,7 +365,6 @@ befs_read_inode(struct inode *inode) inode->i_mtime.tv_nsec = 0; /* lower 16 bits are not a time */ inode->i_ctime = inode->i_mtime; inode->i_atime = inode->i_mtime; - inode->i_blksize = befs_sb->block_size; befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num); befs_ino->i_parent = fsrun_to_cpu(sb, raw_inode->parent); diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 26fad9621738..dcf04cb13283 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c @@ -102,7 +102,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode, inode->i_uid = current->fsuid; inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; - inode->i_blocks = inode->i_blksize = 0; + inode->i_blocks = 0; inode->i_op = &bfs_file_inops; inode->i_fop = &bfs_file_operations; inode->i_mapping->a_ops = &bfs_aops; diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 8fc2e8e49dbe..ed27ffb3459e 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -76,7 +76,6 @@ static void bfs_read_inode(struct inode * inode) inode->i_size = BFS_FILESIZE(di); inode->i_blocks = BFS_FILEBLOCKS(di); if (inode->i_size || inode->i_blocks) dprintf("Registered inode with %lld size, %ld blocks\n", inode->i_size, inode->i_blocks); - inode->i_blksize = PAGE_SIZE; inode->i_atime.tv_sec = le32_to_cpu(di->i_atime); inode->i_mtime.tv_sec = le32_to_cpu(di->i_mtime); inode->i_ctime.tv_sec = le32_to_cpu(di->i_ctime); diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 6759b9839ce8..66ba137f8661 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -507,7 +507,6 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode) inode->i_mode = mode; inode->i_uid = 0; inode->i_gid = 0; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 4197a5043f13..22bcf4d7e7ae 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -253,7 +253,6 @@ cifs_alloc_inode(struct super_block *sb) file data or metadata */ cifs_inode->clientCanCacheRead = FALSE; cifs_inode->clientCanCacheAll = FALSE; - cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; INIT_LIST_HEAD(&cifs_inode->openFileList); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 9aeb58a7d369..b27b34537bf2 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -216,10 +216,9 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, if (allocation_size < end_of_file) cFYI(1, ("May be sparse file, allocation less than file size")); - cFYI(1, ("File Size %ld and blocks %llu and blocksize %ld", + cFYI(1, ("File Size %ld and blocks %llu", (unsigned long)tmp_inode->i_size, - (unsigned long long)tmp_inode->i_blocks, - tmp_inode->i_blksize)); + (unsigned long long)tmp_inode->i_blocks)); if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, ("File inode")); tmp_inode->i_op = &cifs_file_inode_ops; diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c index 5597080cb811..95a54253c047 100644 --- a/fs/coda/coda_linux.c +++ b/fs/coda/coda_linux.c @@ -110,8 +110,6 @@ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr) inode->i_nlink = attr->va_nlink; if (attr->va_size != -1) inode->i_size = attr->va_size; - if (attr->va_blocksize != -1) - inode->i_blksize = attr->va_blocksize; if (attr->va_size != -1) inode->i_blocks = (attr->va_size + 511) >> 9; if (attr->va_atime.tv_sec != -1) diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 5047e6a7581e..fb18917954a9 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -135,7 +135,6 @@ struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd) { struct inode * inode = new_inode(configfs_sb); if (inode) { - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_mapping->a_ops = &configfs_aops; inode->i_mapping->backing_dev_info = &configfs_backing_dev_info; diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index d09b6777c41a..ad96b6990715 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -73,7 +73,6 @@ static int cramfs_iget5_set(struct inode *inode, void *opaque) inode->i_uid = cramfs_inode->uid; inode->i_size = cramfs_inode->size; inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_gid = cramfs_inode->gid; /* Struct copy intentional */ inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 717f4821ed02..269e649e6dc6 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -40,7 +40,6 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d inode->i_mode = mode; inode->i_uid = 0; inode->i_gid = 0; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 5bf06a10dddf..5f7b5a6025bf 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -113,7 +113,6 @@ devpts_fill_super(struct super_block *s, void *data, int silent) inode->i_ino = 1; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_blocks = 0; - inode->i_blksize = 1024; inode->i_uid = inode->i_gid = 0; inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; inode->i_op = &simple_dir_inode_operations; @@ -172,7 +171,6 @@ int devpts_pty_new(struct tty_struct *tty) return -ENOMEM; inode->i_ino = number+2; - inode->i_blksize = 1024; inode->i_uid = config.setuid ? config.uid : current->fsuid; inode->i_gid = config.setgid ? config.gid : current->fsgid; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 3a3567433b92..8d544334bcd2 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1590,7 +1590,6 @@ static struct inode *ep_eventpoll_inode(void) inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_blksize = PAGE_SIZE; return inode; eexit_1: diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 695f69ccf908..2cb545bf0f3c 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -574,7 +574,6 @@ got: inode->i_mode = mode; inode->i_ino = ino; - inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; memset(ei->i_data, 0, sizeof(ei->i_data)); diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index fb4d3220eb8d..dd4e14c221e0 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1094,7 +1094,6 @@ void ext2_read_inode (struct inode * inode) brelse (bh); goto bad_inode; } - inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); ei->i_flags = le32_to_cpu(raw_inode->i_flags); ei->i_faddr = le32_to_cpu(raw_inode->i_faddr); diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 1e4ded8aa3cd..e45dbd651736 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -559,7 +559,6 @@ got: inode->i_ino = ino; /* This is the optimal IO size (for stat), not the fs block size */ - inode->i_blksize = PAGE_SIZE; inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index c9fc15f8b609..dcf4f1dd108b 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -2632,9 +2632,6 @@ void ext3_read_inode(struct inode * inode) * recovery code: that's fine, we're about to complete * the process of deleting those. */ } - inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size - * (for stat), not the fs block - * size */ inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); ei->i_flags = le32_to_cpu(raw_inode->i_flags); #ifdef EXT3_FRAGMENTS diff --git a/fs/fat/inode.c b/fs/fat/inode.c index e1035a590664..ab96ae823753 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -370,8 +370,6 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) inode->i_flags |= S_IMMUTABLE; } MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED; - /* this is as close to the truth as we can get ... */ - inode->i_blksize = sbi->cluster_size; inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) & ~((loff_t)sbi->cluster_size - 1)) >> 9; inode->i_mtime.tv_sec = @@ -1131,7 +1129,6 @@ static int fat_read_root(struct inode *inode) MSDOS_I(inode)->i_start = 0; inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry); } - inode->i_blksize = sbi->cluster_size; inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) & ~((loff_t)sbi->cluster_size - 1)) >> 9; MSDOS_I(inode)->i_logstart = 0; diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index 32a82ed108e4..4786d51ad3bd 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c @@ -239,7 +239,6 @@ vxfs_iinit(struct inode *ip, struct vxfs_inode_info *vip) ip->i_ctime.tv_nsec = 0; ip->i_mtime.tv_nsec = 0; - ip->i_blksize = PAGE_SIZE; ip->i_blocks = vip->vii_blocks; ip->i_generation = vip->vii_gen; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 7d25092262ae..cb7cadb0b790 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -118,7 +118,6 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) inode->i_uid = attr->uid; inode->i_gid = attr->gid; i_size_write(inode, attr->size); - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = attr->blocks; inode->i_atime.tv_sec = attr->atime; inode->i_atime.tv_nsec = attr->atimensec; diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 315cf44a90b2..d05641c35fc9 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -154,7 +154,6 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode) inode->i_gid = current->fsgid; inode->i_nlink = 1; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; - inode->i_blksize = HFS_SB(sb)->alloc_blksz; HFS_I(inode)->flags = 0; HFS_I(inode)->rsrc_inode = NULL; HFS_I(inode)->fs_blocks = 0; @@ -284,7 +283,6 @@ static int hfs_read_inode(struct inode *inode, void *data) inode->i_uid = hsb->s_uid; inode->i_gid = hsb->s_gid; inode->i_nlink = 1; - inode->i_blksize = HFS_SB(inode->i_sb)->alloc_blksz; if (idata->key) HFS_I(inode)->cat_key = *idata->key; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 924ecdef8091..0eb1a6092668 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -304,7 +304,6 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode) inode->i_gid = current->fsgid; inode->i_nlink = 1; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; - inode->i_blksize = HFSPLUS_SB(sb).alloc_blksz; INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); init_MUTEX(&HFSPLUS_I(inode).extents_lock); atomic_set(&HFSPLUS_I(inode).opencnt, 0); @@ -407,7 +406,6 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset); HFSPLUS_I(inode).dev = 0; - inode->i_blksize = HFSPLUS_SB(inode->i_sb).alloc_blksz; if (type == HFSPLUS_FOLDER) { struct hfsplus_cat_folder *folder = &entry.folder; diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index b82e3d9c8790..322e876c35ed 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -156,7 +156,6 @@ static int read_name(struct inode *ino, char *name) ino->i_mode = i_mode; ino->i_nlink = i_nlink; ino->i_size = i_size; - ino->i_blksize = i_blksize; ino->i_blocks = i_blocks; return(0); } diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 56f2c338c4d9..bcf6ee36e065 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -17,7 +17,6 @@ void hpfs_init_inode(struct inode *i) i->i_gid = hpfs_sb(sb)->sb_gid; i->i_mode = hpfs_sb(sb)->sb_mode; hpfs_inode->i_conv = hpfs_sb(sb)->sb_conv; - i->i_blksize = 512; i->i_size = -1; i->i_blocks = -1; diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c index 3a9bdf58166f..dcb6d2e988b8 100644 --- a/fs/hppfs/hppfs_kern.c +++ b/fs/hppfs/hppfs_kern.c @@ -152,7 +152,6 @@ static void hppfs_read_inode(struct inode *ino) ino->i_mode = proc_ino->i_mode; ino->i_nlink = proc_ino->i_nlink; ino->i_size = proc_ino->i_size; - ino->i_blksize = proc_ino->i_blksize; ino->i_blocks = proc_ino->i_blocks; } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index c3920c96dadf..e025a31b4c64 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -357,7 +357,6 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, inode->i_mode = mode; inode->i_uid = uid; inode->i_gid = gid; - inode->i_blksize = HPAGE_SIZE; inode->i_blocks = 0; inode->i_mapping->a_ops = &hugetlbfs_aops; inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 10e47897bac7..4527692f432b 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -1235,7 +1235,7 @@ static void isofs_read_inode(struct inode *inode) } inode->i_uid = sbi->s_uid; inode->i_gid = sbi->s_gid; - inode->i_blocks = inode->i_blksize = 0; + inode->i_blocks = 0; ei->i_format_parm[0] = 0; ei->i_format_parm[1] = 0; @@ -1291,7 +1291,6 @@ static void isofs_read_inode(struct inode *inode) isonum_711 (de->ext_attr_length)); /* Set the number of blocks for stat() - should be done before RR */ - inode->i_blksize = PAGE_CACHE_SIZE; /* For stat() only */ inode->i_blocks = (inode->i_size + 511) >> 9; /* diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 7358ef87f16b..f5cf9c93e243 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -364,7 +364,6 @@ jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode, inode->i_ctime.tv_nsec = 0; inode->i_mtime.tv_nsec = 0; inode->i_atime.tv_nsec = 0; - inode->i_blksize = PAGE_SIZE; inode->i_blocks = (inode->i_size + 511) >> 9; f = jffs_find_file(c, raw_inode->ino); @@ -1706,7 +1705,6 @@ jffs_read_inode(struct inode *inode) inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0; - inode->i_blksize = PAGE_SIZE; inode->i_blocks = (inode->i_size + 511) >> 9; if (S_ISREG(inode->i_mode)) { inode->i_op = &jffs_file_inode_operations; diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 4780f82825d6..72d9909d95ff 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -263,7 +263,6 @@ void jffs2_read_inode (struct inode *inode) inode->i_nlink = f->inocache->nlink; - inode->i_blksize = PAGE_SIZE; inode->i_blocks = (inode->i_size + 511) >> 9; switch (inode->i_mode & S_IFMT) { @@ -449,7 +448,6 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime)); - inode->i_blksize = PAGE_SIZE; inode->i_blocks = 0; inode->i_size = 0; diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index 4d52593a5fc6..4c74f0944f7e 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c @@ -468,7 +468,7 @@ int extRecord(struct inode *ip, xad_t * xp) int extFill(struct inode *ip, xad_t * xp) { int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage; - s64 blkno = offsetXAD(xp) >> ip->i_blksize; + s64 blkno = offsetXAD(xp) >> ip->i_blkbits; // assert(ISSPARSE(ip)); diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index ccbe60aff83d..369d7f39c040 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -3115,7 +3115,6 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) ip->i_mtime.tv_nsec = le32_to_cpu(dip->di_mtime.tv_nsec); ip->i_ctime.tv_sec = le32_to_cpu(dip->di_ctime.tv_sec); ip->i_ctime.tv_nsec = le32_to_cpu(dip->di_ctime.tv_nsec); - ip->i_blksize = ip->i_sb->s_blocksize; ip->i_blocks = LBLK2PBLK(ip->i_sb, le64_to_cpu(dip->di_nblocks)); ip->i_generation = le32_to_cpu(dip->di_gen); diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c index 495df402916d..bffaca9ae3a2 100644 --- a/fs/jfs/jfs_inode.c +++ b/fs/jfs/jfs_inode.c @@ -115,7 +115,6 @@ struct inode *ialloc(struct inode *parent, umode_t mode) } jfs_inode->mode2 |= mode; - inode->i_blksize = sb->s_blocksize; inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; jfs_inode->otime = inode->i_ctime.tv_sec; diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index e1e0a6e6ebdf..f5afc129d6b1 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -257,7 +257,7 @@ static sector_t metapage_get_blocks(struct inode *inode, sector_t lblock, int rc = 0; int xflag; s64 xaddr; - sector_t file_blocks = (inode->i_size + inode->i_blksize - 1) >> + sector_t file_blocks = (inode->i_size + inode->i_sb->s_blocksize - 1) >> inode->i_blkbits; if (lblock >= file_blocks) diff --git a/fs/libfs.c b/fs/libfs.c index 2751793beeaa..8db5afb7b0a7 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -383,7 +383,6 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files return -ENOMEM; inode->i_mode = S_IFDIR | 0755; inode->i_uid = inode->i_gid = 0; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_op = &simple_dir_inode_operations; @@ -405,7 +404,6 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files goto out; inode->i_mode = S_IFREG | files->mode; inode->i_uid = inode->i_gid = 0; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_fop = files->ops; diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c index 4a6abc49418e..df6b1075b549 100644 --- a/fs/minix/bitmap.c +++ b/fs/minix/bitmap.c @@ -254,7 +254,7 @@ struct inode * minix_new_inode(const struct inode * dir, int * error) inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; inode->i_ino = j; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; - inode->i_blocks = inode->i_blksize = 0; + inode->i_blocks = 0; memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u)); insert_inode_hash(inode); mark_inode_dirty(inode); diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 826b9d830650..c11a4b9fb863 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -396,7 +396,7 @@ static void V1_minix_read_inode(struct inode * inode) inode->i_mtime.tv_nsec = 0; inode->i_atime.tv_nsec = 0; inode->i_ctime.tv_nsec = 0; - inode->i_blocks = inode->i_blksize = 0; + inode->i_blocks = 0; for (i = 0; i < 9; i++) minix_inode->u.i1_data[i] = raw_inode->i_zone[i]; minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0])); @@ -429,7 +429,7 @@ static void V2_minix_read_inode(struct inode * inode) inode->i_mtime.tv_nsec = 0; inode->i_atime.tv_nsec = 0; inode->i_ctime.tv_nsec = 0; - inode->i_blocks = inode->i_blksize = 0; + inode->i_blocks = 0; for (i = 0; i < 10; i++) minix_inode->u.i2_data[i] = raw_inode->i_zone[i]; minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0])); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 8244710e97dd..42e3bef270c9 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -223,7 +223,6 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) inode->i_nlink = 1; inode->i_uid = server->m.uid; inode->i_gid = server->m.gid; - inode->i_blksize = NCP_BLOCK_SIZE; ncp_update_dates(inode, &nwinfo->i); ncp_update_inode(inode, nwinfo); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 931f52a19579..bc9376ca86cd 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -277,10 +277,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) * report the blocks in 512byte units */ inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); - inode->i_blksize = inode->i_sb->s_blocksize; } else { inode->i_blocks = fattr->du.nfs2.blocks; - inode->i_blksize = fattr->du.nfs2.blocksize; } nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo_timestamp = jiffies; @@ -969,10 +967,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) * report the blocks in 512byte units */ inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); - inode->i_blksize = inode->i_sb->s_blocksize; } else { inode->i_blocks = fattr->du.nfs2.blocks; - inode->i_blksize = fattr->du.nfs2.blocksize; } if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 31852121b3f5..933dbd89c2a4 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -556,8 +556,6 @@ static int ntfs_read_locked_inode(struct inode *vi) /* Setup the generic vfs inode parts now. */ - /* This is the optimal IO size (for stat), not the fs block size. */ - vi->i_blksize = PAGE_CACHE_SIZE; /* * This is for checking whether an inode has changed w.r.t. a file so * that the file can be updated if necessary (compare with f_version). @@ -1234,7 +1232,6 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) base_ni = NTFS_I(base_vi); /* Just mirror the values from the base inode. */ - vi->i_blksize = base_vi->i_blksize; vi->i_version = base_vi->i_version; vi->i_uid = base_vi->i_uid; vi->i_gid = base_vi->i_gid; @@ -1504,7 +1501,6 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) ni = NTFS_I(vi); base_ni = NTFS_I(base_vi); /* Just mirror the values from the base inode. */ - vi->i_blksize = base_vi->i_blksize; vi->i_version = base_vi->i_version; vi->i_uid = base_vi->i_uid; vi->i_gid = base_vi->i_gid; diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 578fb3d5e803..584260fd6848 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -2637,11 +2637,6 @@ mft_rec_already_initialized: goto undo_mftbmp_alloc; } vi->i_ino = bit; - /* - * This is the optimal IO size (for stat), not the fs block - * size. - */ - vi->i_blksize = PAGE_CACHE_SIZE; /* * This is for checking whether an inode has changed w.r.t. a * file so that the file can be updated if necessary (compare diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index 0ff0898a0b9c..0368c6402182 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c @@ -335,7 +335,6 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb) inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; @@ -362,7 +361,6 @@ static struct inode *dlmfs_get_inode(struct inode *parent, inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 69d3db569166..16e8e74dc966 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -269,7 +269,6 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, inode->i_mode = le16_to_cpu(fe->i_mode); inode->i_uid = le32_to_cpu(fe->i_uid); inode->i_gid = le32_to_cpu(fe->i_gid); - inode->i_blksize = (u32)osb->s_clustersize; /* Fast symlinks will have i_size but no allocated clusters. */ if (S_ISLNK(inode->i_mode) && !fe->i_clusters) @@ -1258,8 +1257,6 @@ leave: void ocfs2_refresh_inode(struct inode *inode, struct ocfs2_dinode *fe) { - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - spin_lock(&OCFS2_I(inode)->ip_lock); OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters); @@ -1270,7 +1267,6 @@ void ocfs2_refresh_inode(struct inode *inode, inode->i_uid = le32_to_cpu(fe->i_uid); inode->i_gid = le32_to_cpu(fe->i_gid); inode->i_mode = le16_to_cpu(fe->i_mode); - inode->i_blksize = (u32) osb->s_clustersize; if (S_ISLNK(inode->i_mode) && le32_to_cpu(fe->i_clusters) == 0) inode->i_blocks = 0; else diff --git a/fs/pipe.c b/fs/pipe.c index 20352573e025..f3b6f71e9d0b 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -879,7 +879,6 @@ static struct inode * get_pipe_inode(void) inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_blksize = PAGE_SIZE; return inode; diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index fddbd61c68d0..5a41db2a218d 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -496,7 +496,6 @@ static void qnx4_read_inode(struct inode *inode) inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->di_ctime); inode->i_ctime.tv_nsec = 0; inode->i_blocks = le32_to_cpu(raw_inode->di_first_xtnt.xtnt_size); - inode->i_blksize = QNX4_DIR_ENTRY_SIZE; memcpy(qnx4_inode, raw_inode, QNX4_DIR_ENTRY_SIZE); if (S_ISREG(inode->i_mode)) { diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index b9677335cc8d..bc0e51662424 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -58,7 +58,6 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev) inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_mapping->a_ops = &ramfs_aops; inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info; diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 52f1e2136546..8810fda0da46 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -17,8 +17,6 @@ #include #include -extern int reiserfs_default_io_size; /* default io size devuned in super.c */ - static int reiserfs_commit_write(struct file *f, struct page *page, unsigned from, unsigned to); static int reiserfs_prepare_write(struct file *f, struct page *page, @@ -1122,7 +1120,6 @@ static void init_inode(struct inode *inode, struct path *path) ih = PATH_PITEM_HEAD(path); copy_key(INODE_PKEY(inode), &(ih->ih_key)); - inode->i_blksize = reiserfs_default_io_size; INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list)); REISERFS_I(inode)->i_flags = 0; @@ -1877,7 +1874,6 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, } // these do not go to on-disk stat data inode->i_ino = le32_to_cpu(ih.ih_key.k_objectid); - inode->i_blksize = reiserfs_default_io_size; // store in in-core inode the key of stat data and version all // object items will have (directory items will have old offset diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 92cf60aa6121..2c122ee83adb 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -166,7 +166,6 @@ smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr) fattr->f_mtime = inode->i_mtime; fattr->f_ctime = inode->i_ctime; fattr->f_atime = inode->i_atime; - fattr->f_blksize= inode->i_blksize; fattr->f_blocks = inode->i_blocks; fattr->attr = SMB_I(inode)->attr; @@ -200,7 +199,6 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr) inode->i_uid = fattr->f_uid; inode->i_gid = fattr->f_gid; inode->i_ctime = fattr->f_ctime; - inode->i_blksize= fattr->f_blksize; inode->i_blocks = fattr->f_blocks; inode->i_size = fattr->f_size; inode->i_mtime = fattr->f_mtime; diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index c3495059889d..40e174db9872 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -1826,7 +1826,6 @@ smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr) fattr->f_nlink = 1; fattr->f_uid = server->mnt->uid; fattr->f_gid = server->mnt->gid; - fattr->f_blksize = SMB_ST_BLKSIZE; fattr->f_unix = 0; } diff --git a/fs/stat.c b/fs/stat.c index 3a44dcf97da2..60a31d5e5966 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -32,7 +33,7 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) stat->ctime = inode->i_ctime; stat->size = i_size_read(inode); stat->blocks = inode->i_blocks; - stat->blksize = inode->i_blksize; + stat->blksize = (1 << inode->i_blkbits); } EXPORT_SYMBOL(generic_fillattr); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index fd7cd5f843d2..e79e38d52c00 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -125,7 +125,6 @@ struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd) { struct inode * inode = new_inode(sysfs_sb); if (inode) { - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c index 9b585d1081c0..115ab0d6f4bc 100644 --- a/fs/sysv/ialloc.c +++ b/fs/sysv/ialloc.c @@ -170,7 +170,7 @@ struct inode * sysv_new_inode(const struct inode * dir, mode_t mode) inode->i_uid = current->fsuid; inode->i_ino = fs16_to_cpu(sbi, ino); inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; - inode->i_blocks = inode->i_blksize = 0; + inode->i_blocks = 0; memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data)); SYSV_I(inode)->i_dir_start_lookup = 0; insert_inode_hash(inode); diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 58b2d22142ba..d63c5e48b050 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -201,7 +201,7 @@ static void sysv_read_inode(struct inode *inode) inode->i_ctime.tv_nsec = 0; inode->i_atime.tv_nsec = 0; inode->i_mtime.tv_nsec = 0; - inode->i_blocks = inode->i_blksize = 0; + inode->i_blocks = 0; si = SYSV_I(inode); for (block = 0; block < 10+1+1+1; block++) diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index d1d38238ce65..8206983f2ebf 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c @@ -121,7 +121,6 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err) UDF_I_LOCATION(inode).logicalBlockNum = block; UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum; inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0); - inode->i_blksize = PAGE_SIZE; inode->i_blocks = 0; UDF_I_LENEATTR(inode) = 0; UDF_I_LENALLOC(inode) = 0; diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 605f5111b6d8..b223b32db991 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -916,8 +916,6 @@ __udf_read_inode(struct inode *inode) * i_nlink = 1 * i_op = NULL; */ - inode->i_blksize = PAGE_SIZE; - bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident); if (!bh) diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index 9501dcd3b213..2ad1259c6eca 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -255,7 +255,6 @@ cg_found: inode->i_gid = current->fsgid; inode->i_ino = cg * uspi->s_ipg + bit; - inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; ufsi->i_flags = UFS_I(dir)->i_flags; diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 30c6e8a9446c..ee1eaa6f4ec2 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -741,7 +741,6 @@ void ufs_read_inode(struct inode * inode) ufs1_read_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino)); } - inode->i_blksize = PAGE_SIZE;/*This is the optimal IO size (for stat)*/ inode->i_version++; ufsi->i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift; diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 4754f342a5d3..9df9ed37d219 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -171,7 +171,6 @@ xfs_revalidate_inode( break; } - inode->i_blksize = xfs_preferred_iosize(mp); inode->i_generation = ip->i_d.di_gen; i_size_write(inode, ip->i_d.di_size); inode->i_blocks = diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index 6628d96b6fd6..553fa731ade5 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c @@ -122,7 +122,6 @@ vn_revalidate_core( inode->i_blocks = vap->va_nblocks; inode->i_mtime = vap->va_mtime; inode->i_ctime = vap->va_ctime; - inode->i_blksize = vap->va_blocksize; if (vap->va_xflags & XFS_XFLAG_IMMUTABLE) inode->i_flags |= S_IMMUTABLE; else diff --git a/include/linux/fs.h b/include/linux/fs.h index 192e69bb55b5..8f74dfbb2edd 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -512,7 +512,6 @@ struct inode { struct timespec i_mtime; struct timespec i_ctime; unsigned int i_blkbits; - unsigned long i_blksize; unsigned long i_version; blkcnt_t i_blocks; unsigned short i_bytes; diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index f9edcd2ff3c8..31a3cb617ce0 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -269,14 +269,8 @@ fill_post_wcc(struct svc_fh *fhp) fhp->fh_post_uid = inode->i_uid; fhp->fh_post_gid = inode->i_gid; fhp->fh_post_size = inode->i_size; - if (inode->i_blksize) { - fhp->fh_post_blksize = inode->i_blksize; - fhp->fh_post_blocks = inode->i_blocks; - } else { - fhp->fh_post_blksize = BLOCK_SIZE; - /* how much do we care for accuracy with MinixFS? */ - fhp->fh_post_blocks = (inode->i_size+511) >> 9; - } + fhp->fh_post_blksize = BLOCK_SIZE; + fhp->fh_post_blocks = inode->i_blocks; fhp->fh_post_rdev[0] = htonl((u32)imajor(inode)); fhp->fh_post_rdev[1] = htonl((u32)iminor(inode)); fhp->fh_post_atime = inode->i_atime; diff --git a/include/linux/smb.h b/include/linux/smb.h index 6df3b1501559..f098dff93f6b 100644 --- a/include/linux/smb.h +++ b/include/linux/smb.h @@ -89,7 +89,6 @@ struct smb_fattr { struct timespec f_atime; struct timespec f_mtime; struct timespec f_ctime; - unsigned long f_blksize; unsigned long f_blocks; int f_unix; }; diff --git a/ipc/mqueue.c b/ipc/mqueue.c index f8381f0660b2..840f8a6fb85f 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -115,7 +115,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME; diff --git a/kernel/cpuset.c b/kernel/cpuset.c index cff41511269f..1b32c2c04c15 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -289,7 +289,6 @@ static struct inode *cpuset_new_inode(mode_t mode) inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_mapping->backing_dev_info = &cpuset_backing_dev_info; diff --git a/mm/shmem.c b/mm/shmem.c index 0a8e29cf87e0..eda907c3a86a 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1351,7 +1351,6 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_mapping->a_ops = &shmem_aops; inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index f65bea74734d..700c6e061a04 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -488,7 +488,6 @@ rpc_get_inode(struct super_block *sb, int mode) return NULL; inode->i_mode = mode; inode->i_uid = inode->i_gid = 0; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch(mode & S_IFMT) { diff --git a/security/inode.c b/security/inode.c index 176aacea8ca4..49ee51529396 100644 --- a/security/inode.c +++ b/security/inode.c @@ -64,7 +64,6 @@ static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev) inode->i_mode = mode; inode->i_uid = 0; inode->i_gid = 0; - inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 00534c302ba2..bab7b386cb8d 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -771,7 +771,6 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode) if (ret) { ret->i_mode = mode; ret->i_uid = ret->i_gid = 0; - ret->i_blksize = PAGE_CACHE_SIZE; ret->i_blocks = 0; ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; } -- cgit v1.2.3 From ebba5f9fcb882306bef7175dee987342ec6fcf2f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 27 Sep 2006 01:50:55 -0700 Subject: [PATCH] consistently use MAX_ERRNO in __syscall_return Consistently use MAX_ERRNO when checking for errors in __syscall_return(). [ralf@linux-mips.org: build fix] Signed-off-by: Randy Dunlap Signed-off-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-arm/unistd.h | 3 ++- include/asm-arm26/unistd.h | 3 ++- include/asm-frv/unistd.h | 3 ++- include/asm-h8300/unistd.h | 6 +++--- include/asm-i386/unistd.h | 5 +++-- include/asm-m32r/unistd.h | 5 +++-- include/asm-m68k/unistd.h | 5 +++-- include/asm-m68knommu/unistd.h | 5 +++-- include/asm-s390/unistd.h | 4 +++- include/asm-sh/unistd.h | 7 +++++-- include/asm-sh64/unistd.h | 6 ++++-- include/asm-v850/unistd.h | 5 +++-- include/asm-x86_64/unistd.h | 5 +++-- include/linux/err.h | 4 ++++ 14 files changed, 43 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index 1e891f860ef3..2ab4078334bf 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -377,6 +377,7 @@ #endif #ifdef __KERNEL__ +#include #include #define __sys2(x) #x @@ -396,7 +397,7 @@ #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-129)) { \ + if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \ errno = -(res); \ res = -1; \ } \ diff --git a/include/asm-arm26/unistd.h b/include/asm-arm26/unistd.h index 70eb6d91cfd0..c6d2436c9d34 100644 --- a/include/asm-arm26/unistd.h +++ b/include/asm-arm26/unistd.h @@ -311,6 +311,7 @@ #define __ARM_NR_usr26 (__ARM_NR_BASE+3) #ifdef __KERNEL__ +#include #include #define __sys2(x) #x @@ -322,7 +323,7 @@ #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + if ((unsigned long)(res) >= (unsigned long)-MAX_ERRNO) { \ errno = -(res); \ res = -1; \ } \ diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h index b80dbd839475..d104d1b91d39 100644 --- a/include/asm-frv/unistd.h +++ b/include/asm-frv/unistd.h @@ -320,6 +320,7 @@ #ifdef __KERNEL__ #define NR_syscalls 310 +#include /* * process the return value of a syscall, consigning it to one of two possible fates @@ -329,7 +330,7 @@ #define __syscall_return(type, res) \ do { \ unsigned long __sr2 = (res); \ - if (__builtin_expect(__sr2 >= (unsigned long)(-4095), 0)) { \ + if (__builtin_expect(__sr2 >= (unsigned long)(-MAX_ERRNO), 0)) { \ errno = (-__sr2); \ __sr2 = ~0UL; \ } \ diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h index 226dd596c2da..a2dd90462d80 100644 --- a/include/asm-h8300/unistd.h +++ b/include/asm-h8300/unistd.h @@ -295,14 +295,14 @@ #ifdef __KERNEL__ #define NR_syscalls 289 +#include - -/* user-visible error numbers are in the range -1 - -122: see +/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see */ #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \ /* avoid using res which is declared to be in register d0; \ errno might expand to a function call and clobber it. */ \ int __err = -(res); \ diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 565d0897b205..bd9987087adc 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -328,14 +328,15 @@ #ifdef __KERNEL__ #define NR_syscalls 319 +#include /* - * user-visible error numbers are in the range -1 - -128: see + * user-visible error numbers are in the range -1 - -MAX_ERRNO: see * */ #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-(128 + 1))) { \ + if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \ errno = -(res); \ res = -1; \ } \ diff --git a/include/asm-m32r/unistd.h b/include/asm-m32r/unistd.h index 89f376e6229f..5c6a9ac6cf1a 100644 --- a/include/asm-m32r/unistd.h +++ b/include/asm-m32r/unistd.h @@ -296,8 +296,9 @@ #ifdef __KERNEL__ #define NR_syscalls 285 +#include -/* user-visible error numbers are in the range -1 - -124: see +/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see * */ @@ -305,7 +306,7 @@ #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-(124 + 1))) { \ + if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \ /* Avoid using "res" which is declared to be in register r0; \ errno might expand to a function call and clobber it. */ \ int __err = -(res); \ diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h index 7c0b6296b45c..751632b904db 100644 --- a/include/asm-m68k/unistd.h +++ b/include/asm-m68k/unistd.h @@ -288,13 +288,14 @@ #ifdef __KERNEL__ #define NR_syscalls 282 +#include -/* user-visible error numbers are in the range -1 - -124: see +/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see */ #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \ /* avoid using res which is declared to be in register d0; \ errno might expand to a function call and clobber it. */ \ int __err = -(res); \ diff --git a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h index 1b2abdf281e1..21fdc37c5c2c 100644 --- a/include/asm-m68knommu/unistd.h +++ b/include/asm-m68knommu/unistd.h @@ -289,13 +289,14 @@ #ifdef __KERNEL__ #define NR_syscalls 282 +#include -/* user-visible error numbers are in the range -1 - -122: see +/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see */ #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \ /* avoid using res which is declared to be in register d0; \ errno might expand to a function call and clobber it. */ \ int __err = -(res); \ diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index 02b942d85c37..d49c54cb5505 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -342,9 +342,11 @@ #ifdef __KERNEL__ +#include + #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-4095)) {\ + if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \ errno = -(res); \ res = -1; \ } \ diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h index 76b5430cb458..da127d7901af 100644 --- a/include/asm-sh/unistd.h +++ b/include/asm-sh/unistd.h @@ -306,11 +306,14 @@ #ifdef __KERNEL__ -/* user-visible error numbers are in the range -1 - -124: see */ +#include + +/* user-visible error numbers are in the range -1 - -MAX_ERRNO: + * see */ #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-124)) { \ + if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \ /* Avoid using "res" which is declared to be in register r0; \ errno might expand to a function call and clobber it. */ \ int __err = -(res); \ diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h index 9a1590fffc15..c113566bef33 100644 --- a/include/asm-sh64/unistd.h +++ b/include/asm-sh64/unistd.h @@ -347,8 +347,10 @@ #ifdef __KERNEL__ #define NR_syscalls 321 +#include -/* user-visible error numbers are in the range -1 - -125: see */ +/* user-visible error numbers are in the range -1 - -MAX_ERRNO: + * see */ #define __syscall_return(type, res) \ do { \ @@ -358,7 +360,7 @@ do { \ ** life easier in the system call epilogue (see entry.S) \ */ \ register unsigned long __sr2 __asm__ ("r2") = res; \ - if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \ errno = -(res); \ __sr2 = -1; \ } \ diff --git a/include/asm-v850/unistd.h b/include/asm-v850/unistd.h index bcb44bfe577a..552b7c873a57 100644 --- a/include/asm-v850/unistd.h +++ b/include/asm-v850/unistd.h @@ -238,12 +238,13 @@ #ifdef __KERNEL__ #include +#include #define __syscall_return(type, res) \ do { \ - /* user-visible error numbers are in the range -1 - -124: \ + /* user-visible error numbers are in the range -1 - -MAX_ERRNO: \ see */ \ - if (__builtin_expect ((unsigned long)(res) >= (unsigned long)(-125), 0)) { \ + if (__builtin_expect ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO), 0)) { \ errno = -(res); \ res = -1; \ } \ diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index eeb98c168e98..6137146516d3 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -623,16 +623,17 @@ __SYSCALL(__NR_move_pages, sys_move_pages) #ifdef __KERNEL__ #define __NR_syscall_max __NR_move_pages +#include #ifndef __NO_STUBS -/* user-visible error numbers are in the range -1 - -4095 */ +/* user-visible error numbers are in the range -1 - -MAX_ERRNO */ #define __syscall_clobber "r11","rcx","memory" #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-127)) { \ + if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \ errno = -(res); \ res = -1; \ } \ diff --git a/include/linux/err.h b/include/linux/err.h index cd3b367f7445..1ab1d44f8d3b 100644 --- a/include/linux/err.h +++ b/include/linux/err.h @@ -15,6 +15,8 @@ */ #define MAX_ERRNO 4095 +#ifndef __ASSEMBLY__ + #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) static inline void *ERR_PTR(long error) @@ -32,4 +34,6 @@ static inline long IS_ERR(const void *ptr) return IS_ERR_VALUE((unsigned long)ptr); } +#endif + #endif /* _LINUX_ERR_H */ -- cgit v1.2.3 From 07563c711fbc25389e58ab9c9f0b9de2fce56760 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Wed, 27 Sep 2006 01:50:56 -0700 Subject: [PATCH] EISA bus MODALIAS attributes support Add modalias attribute support for the almost forgotten now EISA bus and (at least some) EISA-aware modules. The modalias entry looks like (for an 3c509 NIC): eisa:sTCM5093 and the in-module alias like: eisa:sTCM5093* The patch moves struct eisa_device_id declaration from include/linux/eisa.h to include/linux/mod_devicetable.h (so that the former now #includes the latter), adds proper MODULE_DEVICE_TABLE(eisa, ...) statements for all drivers with EISA IDs I found (some drivers already have that DEVICE_TABLE declared), and adds recognision of __mod_eisa_device_table to scripts/mod/file2alias.c so that proper modules.alias will be generated. There's no support for /lib/modules/$kver/modules.eisamap, as it's not used by any existing tools, and because with in-kernel modalias mechanism those maps are obsolete anyway. The rationale for this patch is: a) to make EISA bus to act as other busses with modalias support, to unify driver loading b) to foget about EISA finally - with this patch, kernel (who still supports EISA) will be the only one who knows how to choose the necessary drivers for this bus ;) [akpm@osdl.org: fix the kbuild bit] Signed-off-by: Michael Tokarev Cc: Rusty Russell Cc: Randy Dunlap Acked-the-net-bits-by: Jeff Garzik Acked-the-tulip-bit-by: Valerie Henson Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/eisa/eisa-bus.c | 23 +++++++++++++++++++++++ drivers/net/3c509.c | 1 + drivers/net/3c59x.c | 1 + drivers/net/ne3210.c | 1 + drivers/net/tulip/de4x5.c | 1 + drivers/scsi/aha1740.c | 1 + drivers/scsi/aic7xxx/aic7770_osm.c | 3 ++- drivers/scsi/sim710.c | 1 + include/linux/eisa.h | 8 +------- include/linux/mod_devicetable.h | 12 ++++++++++++ scripts/mod/file2alias.c | 12 ++++++++++++ 11 files changed, 56 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index 6078e2f58817..3a365e159d89 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -128,9 +128,23 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv) return 0; } +static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct eisa_device *edev = to_eisa_device(dev); + int i = 0; + int length = 0; + + add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, + "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); + envp[i] = NULL; + return 0; +} + struct bus_type eisa_bus_type = { .name = "eisa", .match = eisa_bus_match, + .uevent = eisa_bus_uevent, }; int eisa_driver_register (struct eisa_driver *edrv) @@ -160,6 +174,14 @@ static ssize_t eisa_show_state (struct device *dev, struct device_attribute *att static DEVICE_ATTR(enabled, S_IRUGO, eisa_show_state, NULL); +static ssize_t eisa_show_modalias (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct eisa_device *edev = to_eisa_device (dev); + return sprintf (buf, EISA_DEVICE_MODALIAS_FMT "\n", edev->id.sig); +} + +static DEVICE_ATTR(modalias, S_IRUGO, eisa_show_modalias, NULL); + static int __init eisa_init_device (struct eisa_root_device *root, struct eisa_device *edev, int slot) @@ -209,6 +231,7 @@ static int __init eisa_register_device (struct eisa_device *edev) device_create_file (&edev->dev, &dev_attr_signature); device_create_file (&edev->dev, &dev_attr_enabled); + device_create_file (&edev->dev, &dev_attr_modalias); return 0; } diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 59c33925be62..b936373ab2a5 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -225,6 +225,7 @@ static struct eisa_device_id el3_eisa_ids[] = { { "TCM5095" }, { "" } }; +MODULE_DEVICE_TABLE(eisa, el3_eisa_ids); static int el3_eisa_probe (struct device *device); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index af301f09d674..df42e28cc80f 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -851,6 +851,7 @@ static struct eisa_device_id vortex_eisa_ids[] = { { "TCM5970", CH_3C597 }, { "" } }; +MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids); static int vortex_eisa_probe(struct device *device); static int vortex_eisa_remove(struct device *device); diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 0fa8e4d22769..d66328975425 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -343,6 +343,7 @@ static struct eisa_device_id ne3210_ids[] = { { "NVL1801" }, { "" }, }; +MODULE_DEVICE_TABLE(eisa, ne3210_ids); static struct eisa_driver ne3210_eisa_driver = { .id_table = ne3210_ids, diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index e661d0a9cc64..fb5fa7d68888 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -2114,6 +2114,7 @@ static struct eisa_device_id de4x5_eisa_ids[] = { { "DEC4250", 0 }, /* 0 is the board name index... */ { "" } }; +MODULE_DEVICE_TABLE(eisa, de4x5_eisa_ids); static struct eisa_driver de4x5_eisa_driver = { .id_table = de4x5_eisa_ids, diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index 0e4a7ebe300a..6b35ed8301e0 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -681,6 +681,7 @@ static struct eisa_device_id aha1740_ids[] = { { "ADP0400" }, /* 1744 */ { "" } }; +MODULE_DEVICE_TABLE(eisa, aha1740_ids); static struct eisa_driver aha1740_driver = { .id_table = aha1740_ids, diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c index 867cbe23579b..1ac119733bac 100644 --- a/drivers/scsi/aic7xxx/aic7770_osm.c +++ b/drivers/scsi/aic7xxx/aic7770_osm.c @@ -132,7 +132,8 @@ static struct eisa_device_id aic7770_ids[] = { { "ADP7770", 5 }, /* AIC7770 generic */ { "" } }; - +MODULE_DEVICE_TABLE(eisa, aic7770_ids); + static struct eisa_driver aic7770_driver = { .id_table = aic7770_ids, .driver = { diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index b27e85428daa..551baccec523 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -282,6 +282,7 @@ static struct eisa_device_id sim710_eisa_ids[] = { { "HWP0C80" }, { "" } }; +MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids); static __init int sim710_eisa_probe(struct device *dev) diff --git a/include/linux/eisa.h b/include/linux/eisa.h index 4079242dced8..1ff7c1392525 100644 --- a/include/linux/eisa.h +++ b/include/linux/eisa.h @@ -3,8 +3,8 @@ #include #include +#include -#define EISA_SIG_LEN 8 #define EISA_MAX_SLOTS 8 #define EISA_MAX_RESOURCES 4 @@ -27,12 +27,6 @@ #define EISA_CONFIG_ENABLED 1 #define EISA_CONFIG_FORCED 2 -/* The EISA signature, in ASCII form, null terminated */ -struct eisa_device_id { - char sig[EISA_SIG_LEN]; - unsigned long driver_data; -}; - /* There is not much we can say about an EISA device, apart from * signature, slot number, and base address. dma_mask is set by * default to parent device mask..*/ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index f7ca0b09075d..e0c393cc7240 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -308,4 +308,16 @@ struct input_device_id { kernel_ulong_t driver_info; }; +/* EISA */ + +#define EISA_SIG_LEN 8 + +/* The EISA signature, in ASCII form, null terminated */ +struct eisa_device_id { + char sig[EISA_SIG_LEN]; + kernel_ulong_t driver_data; +}; + +#define EISA_DEVICE_MODALIAS_FMT "eisa:s%s" + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index de76da80443f..f61c9ccef6aa 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -444,6 +444,14 @@ static int do_input_entry(const char *filename, struct input_device_id *id, return 1; } +static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa, + char *alias) +{ + if (eisa->sig[0]) + sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", eisa->sig); + return 1; +} + /* Ignore any prefix, eg. v850 prepends _ */ static inline int sym_is(const char *symbol, const char *name) { @@ -547,6 +555,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct input_device_id), "input", do_input_entry, mod); + else if (sym_is(symname, "__mod_eisa_device_table")) + do_table(symval, sym->st_size, + sizeof(struct eisa_device_id), "eisa", + do_eisa_entry, mod); } /* Now add out buffered information to the generated C source */ -- cgit v1.2.3 From c18258c6f0848f97e85287f6271c511a092bb784 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 27 Sep 2006 01:51:06 -0700 Subject: [PATCH] pid: Implement transfer_pid and use it to simplify de_thread In de_thread we move pids from one process to another, a rather ugly case. The function transfer_pid makes it clear what we are doing, and makes the action atomic. This is useful we ever want to atomically traverse the process group and session lists, in a rcu safe manner. Even if the atomic properties this change should be a win as transfer_pid should be less code to execute than executing both attach_pid and detach_pid, and this should make de_thread slightly smaller as only a single function call needs to be emitted. The only downside is that the code might be slower to execute as the odds are against transfer_pid being in cache. Signed-off-by: Eric W. Biederman Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/exec.c | 11 ++++------- include/linux/pid.h | 2 ++ kernel/pid.c | 9 +++++++++ 3 files changed, 15 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/fs/exec.c b/fs/exec.c index 54135df2a966..b7aa3d6422d6 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -696,23 +696,20 @@ static int de_thread(struct task_struct *tsk) */ /* Become a process group leader with the old leader's pid. - * Note: The old leader also uses thispid until release_task + * The old leader becomes a thread of the this thread group. + * Note: The old leader also uses this pid until release_task * is called. Odd but simple and correct. */ detach_pid(current, PIDTYPE_PID); current->pid = leader->pid; attach_pid(current, PIDTYPE_PID, current->pid); - attach_pid(current, PIDTYPE_PGID, current->signal->pgrp); - attach_pid(current, PIDTYPE_SID, current->signal->session); + transfer_pid(leader, current, PIDTYPE_PGID); + transfer_pid(leader, current, PIDTYPE_SID); list_replace_rcu(&leader->tasks, ¤t->tasks); current->group_leader = current; leader->group_leader = current; - /* Reduce leader to a thread */ - detach_pid(leader, PIDTYPE_PGID); - detach_pid(leader, PIDTYPE_SID); - current->exit_signal = SIGCHLD; BUG_ON(leader->exit_state != EXIT_ZOMBIE); diff --git a/include/linux/pid.h b/include/linux/pid.h index 29960b03bef7..93da7e2d9f30 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -76,6 +76,8 @@ extern int FASTCALL(attach_pid(struct task_struct *task, enum pid_type type, int nr)); extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type)); +extern void FASTCALL(transfer_pid(struct task_struct *old, + struct task_struct *new, enum pid_type)); /* * look up a PID in the hash table. Must be called with the tasklist_lock diff --git a/kernel/pid.c b/kernel/pid.c index 93e212f20671..6db82b68e2f8 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -252,6 +252,15 @@ void fastcall detach_pid(struct task_struct *task, enum pid_type type) free_pid(pid); } +/* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */ +void fastcall transfer_pid(struct task_struct *old, struct task_struct *new, + enum pid_type type) +{ + new->pids[type].pid = old->pids[type].pid; + hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node); + old->pids[type].pid = NULL; +} + struct task_struct * fastcall pid_task(struct pid *pid, enum pid_type type) { struct task_struct *result = NULL; -- cgit v1.2.3 From 66f37509fc7191df468a8d183374f48b13bacb73 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 27 Sep 2006 01:51:13 -0700 Subject: [PATCH] fs/nfs/: make code static Signed-off-by: Adrian Bunk Acked-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/namespace.c | 12 +++++++++--- include/linux/nfs_fs.h | 4 ---- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 77b00684894d..60408646176b 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -26,6 +26,11 @@ LIST_HEAD(nfs_automount_list); static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list); int nfs_mountpoint_expiry_timeout = 500 * HZ; +static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, + const struct dentry *dentry, + struct nfs_fh *fh, + struct nfs_fattr *fattr); + /* * nfs_path - reconstruct the path given an arbitrary dentry * @base - arbitrary string to prepend to the path @@ -209,9 +214,10 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, * @fattr - attributes for new root inode * */ -struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, - const struct dentry *dentry, struct nfs_fh *fh, - struct nfs_fattr *fattr) +static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, + const struct dentry *dentry, + struct nfs_fh *fh, + struct nfs_fattr *fattr) { struct nfs_clone_mount mountdata = { .sb = mnt_parent->mnt_sb, diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 36f5bcf513b0..98c9b9f667a5 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -315,10 +315,6 @@ extern void nfs_end_data_update(struct inode *); extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); extern void put_nfs_open_context(struct nfs_open_context *ctx); extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode); -extern struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, - const struct dentry *dentry, - struct nfs_fh *fh, - struct nfs_fattr *fattr); /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ extern u32 root_nfs_parse_addr(char *name); /*__init*/ -- cgit v1.2.3 From 1b79e5513d52e8533a08af35a3595dad80c74d1f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 27 Sep 2006 01:51:14 -0700 Subject: [PATCH] add probe_kernel_address() Add a version of __get_user() which is safe to call inside mmap_sem. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/uaccess.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'include/linux') diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index 391e7ed1eb3f..a48d7f11c7be 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -19,4 +19,26 @@ static inline unsigned long __copy_from_user_nocache(void *to, #endif /* ARCH_HAS_NOCACHE_UACCESS */ +/** + * probe_kernel_address(): safely attempt to read from a location + * @addr: address to read from - its type is type typeof(retval)* + * @retval: read into this variable + * + * Safely read from address @addr into variable @revtal. If a kernel fault + * happens, handle that and return -EFAULT. + * We ensure that the __get_user() is executed in atomic context so that + * do_page_fault() doesn't attempt to take mmap_sem. This makes + * probe_kernel_address() suitable for use within regions where the caller + * already holds mmap_sem, or other locks which nest inside mmap_sem. + */ +#define probe_kernel_address(addr, retval) \ + ({ \ + long ret; \ + \ + inc_preempt_count(); \ + ret = __get_user(retval, addr); \ + dec_preempt_count(); \ + ret; \ + }) + #endif /* __LINUX_UACCESS_H__ */ -- cgit v1.2.3 From 3a16f7b4a75d68364c3278523f51ac141a12758a Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 29 Jun 2006 12:27:23 -0700 Subject: USB: move to Move to . Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-omap/usb.c | 2 +- drivers/i2c/chips/isp1301_omap.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/host/ohci-hcd.c | 2 +- include/linux/usb/otg.h | 131 +++++++++++++++++++++++++++++++++++++++ include/linux/usb_otg.h | 131 --------------------------------------- 6 files changed, 135 insertions(+), 135 deletions(-) create mode 100644 include/linux/usb/otg.h delete mode 100644 include/linux/usb_otg.h (limited to 'include/linux') diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c index 9b815327b6a5..7e8096809be2 100644 --- a/arch/arm/plat-omap/usb.c +++ b/arch/arm/plat-omap/usb.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index f92505b94c61..182f04953466 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 2de9748ee673..81f0389fcc94 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index cbf38ae5ae76..7c3d8c60a60f 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -88,7 +88,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h new file mode 100644 index 000000000000..9897f7a818c5 --- /dev/null +++ b/include/linux/usb/otg.h @@ -0,0 +1,131 @@ +// include/linux/usb/otg.h + +/* + * These APIs may be used between USB controllers. USB device drivers + * (for either host or peripheral roles) don't use these calls; they + * continue to use just usb_device and usb_gadget. + */ + + +/* OTG defines lots of enumeration states before device reset */ +enum usb_otg_state { + OTG_STATE_UNDEFINED = 0, + + /* single-role peripheral, and dual-role default-b */ + OTG_STATE_B_IDLE, + OTG_STATE_B_SRP_INIT, + OTG_STATE_B_PERIPHERAL, + + /* extra dual-role default-b states */ + OTG_STATE_B_WAIT_ACON, + OTG_STATE_B_HOST, + + /* dual-role default-a */ + OTG_STATE_A_IDLE, + OTG_STATE_A_WAIT_VRISE, + OTG_STATE_A_WAIT_BCON, + OTG_STATE_A_HOST, + OTG_STATE_A_SUSPEND, + OTG_STATE_A_PERIPHERAL, + OTG_STATE_A_WAIT_VFALL, + OTG_STATE_A_VBUS_ERR, +}; + +/* + * the otg driver needs to interact with both device side and host side + * usb controllers. it decides which controller is active at a given + * moment, using the transceiver, ID signal, HNP and sometimes static + * configuration information (including "board isn't wired for otg"). + */ +struct otg_transceiver { + struct device *dev; + const char *label; + + u8 default_a; + enum usb_otg_state state; + + struct usb_bus *host; + struct usb_gadget *gadget; + + /* to pass extra port status to the root hub */ + u16 port_status; + u16 port_change; + + /* bind/unbind the host controller */ + int (*set_host)(struct otg_transceiver *otg, + struct usb_bus *host); + + /* bind/unbind the peripheral controller */ + int (*set_peripheral)(struct otg_transceiver *otg, + struct usb_gadget *gadget); + + /* effective for B devices, ignored for A-peripheral */ + int (*set_power)(struct otg_transceiver *otg, + unsigned mA); + + /* for non-OTG B devices: set transceiver into suspend mode */ + int (*set_suspend)(struct otg_transceiver *otg, + int suspend); + + /* for B devices only: start session with A-Host */ + int (*start_srp)(struct otg_transceiver *otg); + + /* start or continue HNP role switch */ + int (*start_hnp)(struct otg_transceiver *otg); + +}; + + +/* for board-specific init logic */ +extern int otg_set_transceiver(struct otg_transceiver *); + + +/* for usb host and peripheral controller drivers */ +extern struct otg_transceiver *otg_get_transceiver(void); + +static inline int +otg_start_hnp(struct otg_transceiver *otg) +{ + return otg->start_hnp(otg); +} + + +/* for HCDs */ +static inline int +otg_set_host(struct otg_transceiver *otg, struct usb_bus *host) +{ + return otg->set_host(otg, host); +} + + +/* for usb peripheral controller drivers */ +static inline int +otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph) +{ + return otg->set_peripheral(otg, periph); +} + +static inline int +otg_set_power(struct otg_transceiver *otg, unsigned mA) +{ + return otg->set_power(otg, mA); +} + +static inline int +otg_set_suspend(struct otg_transceiver *otg, int suspend) +{ + if (otg->set_suspend != NULL) + return otg->set_suspend(otg, suspend); + else + return 0; +} + +static inline int +otg_start_srp(struct otg_transceiver *otg) +{ + return otg->start_srp(otg); +} + + +/* for OTG controller drivers (and maybe other stuff) */ +extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num); diff --git a/include/linux/usb_otg.h b/include/linux/usb_otg.h deleted file mode 100644 index f827f6e203c2..000000000000 --- a/include/linux/usb_otg.h +++ /dev/null @@ -1,131 +0,0 @@ -// include/linux/usb_otg.h - -/* - * These APIs may be used between USB controllers. USB device drivers - * (for either host or peripheral roles) don't use these calls; they - * continue to use just usb_device and usb_gadget. - */ - - -/* OTG defines lots of enumeration states before device reset */ -enum usb_otg_state { - OTG_STATE_UNDEFINED = 0, - - /* single-role peripheral, and dual-role default-b */ - OTG_STATE_B_IDLE, - OTG_STATE_B_SRP_INIT, - OTG_STATE_B_PERIPHERAL, - - /* extra dual-role default-b states */ - OTG_STATE_B_WAIT_ACON, - OTG_STATE_B_HOST, - - /* dual-role default-a */ - OTG_STATE_A_IDLE, - OTG_STATE_A_WAIT_VRISE, - OTG_STATE_A_WAIT_BCON, - OTG_STATE_A_HOST, - OTG_STATE_A_SUSPEND, - OTG_STATE_A_PERIPHERAL, - OTG_STATE_A_WAIT_VFALL, - OTG_STATE_A_VBUS_ERR, -}; - -/* - * the otg driver needs to interact with both device side and host side - * usb controllers. it decides which controller is active at a given - * moment, using the transceiver, ID signal, HNP and sometimes static - * configuration information (including "board isn't wired for otg"). - */ -struct otg_transceiver { - struct device *dev; - const char *label; - - u8 default_a; - enum usb_otg_state state; - - struct usb_bus *host; - struct usb_gadget *gadget; - - /* to pass extra port status to the root hub */ - u16 port_status; - u16 port_change; - - /* bind/unbind the host controller */ - int (*set_host)(struct otg_transceiver *otg, - struct usb_bus *host); - - /* bind/unbind the peripheral controller */ - int (*set_peripheral)(struct otg_transceiver *otg, - struct usb_gadget *gadget); - - /* effective for B devices, ignored for A-peripheral */ - int (*set_power)(struct otg_transceiver *otg, - unsigned mA); - - /* for non-OTG B devices: set transceiver into suspend mode */ - int (*set_suspend)(struct otg_transceiver *otg, - int suspend); - - /* for B devices only: start session with A-Host */ - int (*start_srp)(struct otg_transceiver *otg); - - /* start or continue HNP role switch */ - int (*start_hnp)(struct otg_transceiver *otg); - -}; - - -/* for board-specific init logic */ -extern int otg_set_transceiver(struct otg_transceiver *); - - -/* for usb host and peripheral controller drivers */ -extern struct otg_transceiver *otg_get_transceiver(void); - -static inline int -otg_start_hnp(struct otg_transceiver *otg) -{ - return otg->start_hnp(otg); -} - - -/* for HCDs */ -static inline int -otg_set_host(struct otg_transceiver *otg, struct usb_bus *host) -{ - return otg->set_host(otg, host); -} - - -/* for usb peripheral controller drivers */ -static inline int -otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph) -{ - return otg->set_peripheral(otg, periph); -} - -static inline int -otg_set_power(struct otg_transceiver *otg, unsigned mA) -{ - return otg->set_power(otg, mA); -} - -static inline int -otg_set_suspend(struct otg_transceiver *otg, int suspend) -{ - if (otg->set_suspend != NULL) - return otg->set_suspend(otg, suspend); - else - return 0; -} - -static inline int -otg_start_srp(struct otg_transceiver *otg) -{ - return otg->start_srp(otg); -} - - -/* for OTG controller drivers (and maybe other stuff) */ -extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num); -- cgit v1.2.3 From 8bb54ab573ecd1b4fe2ed66416a8d99a86e65316 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 1 Jul 2006 22:08:49 -0400 Subject: usbcore: add usb_device_driver definition This patch (as732) adds a usb_device_driver structure, for representing drivers that manage an entire USB device as opposed to just an interface. Support routines like usb_register_device_driver, usb_deregister_device_driver, usb_probe_device, and usb_unbind_device are also added. Unlike an earlier version of this patch, the new code is type-safe. To accomplish this, the existing struct driver embedded in struct usb_driver had to be wrapped in an intermediate wrapper. This enables the core to tell at runtime whether a particular struct driver belongs to a device driver or to an interface driver. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 219 +++++++++++++++++++++++++++++++++------------ drivers/usb/core/generic.c | 17 +--- drivers/usb/core/usb.c | 15 ++-- drivers/usb/core/usb.h | 20 ++++- include/linux/usb.h | 58 ++++++++++-- 5 files changed, 245 insertions(+), 84 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 8dcf2cd0c569..0d4b5dcee3ab 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -84,7 +84,7 @@ static int usb_create_newid_file(struct usb_driver *usb_drv) goto exit; if (usb_drv->probe != NULL) - error = sysfs_create_file(&usb_drv->driver.kobj, + error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj, &driver_attr_new_id.attr); exit: return error; @@ -96,7 +96,7 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv) return; if (usb_drv->probe != NULL) - sysfs_remove_file(&usb_drv->driver.kobj, + sysfs_remove_file(&usb_drv->drvwrap.driver.kobj, &driver_attr_new_id.attr); } @@ -143,18 +143,55 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in } -/* called from driver core with usb_bus_type.subsys writelock */ +/* called from driver core with dev locked */ +static int usb_probe_device(struct device *dev) +{ + struct usb_device_driver *udriver = to_usb_device_driver(dev->driver); + struct usb_device *udev; + int error = -ENODEV; + + dev_dbg(dev, "%s\n", __FUNCTION__); + + if (!is_usb_device(dev)) /* Sanity check */ + return error; + + udev = to_usb_device(dev); + + /* FIXME: resume a suspended device */ + if (udev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + + /* TODO: Add real matching code */ + + error = udriver->probe(udev); + return error; +} + +/* called from driver core with dev locked */ +static int usb_unbind_device(struct device *dev) +{ + struct usb_device_driver *udriver = to_usb_device_driver(dev->driver); + + udriver->disconnect(to_usb_device(dev)); + return 0; +} + + +/* called from driver core with dev locked */ static int usb_probe_interface(struct device *dev) { - struct usb_interface * intf = to_usb_interface(dev); - struct usb_driver * driver = to_usb_driver(dev->driver); + struct usb_driver *driver = to_usb_driver(dev->driver); + struct usb_interface *intf; const struct usb_device_id *id; int error = -ENODEV; dev_dbg(dev, "%s\n", __FUNCTION__); - if (!driver->probe) + if (is_usb_device(dev)) /* Sanity check */ return error; + + intf = to_usb_interface(dev); + /* FIXME we'd much prefer to just resume it ... */ if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; @@ -182,19 +219,18 @@ static int usb_probe_interface(struct device *dev) return error; } -/* called from driver core with usb_bus_type.subsys writelock */ +/* called from driver core with dev locked */ static int usb_unbind_interface(struct device *dev) { + struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf = to_usb_interface(dev); - struct usb_driver *driver = to_usb_driver(intf->dev.driver); intf->condition = USB_INTERFACE_UNBINDING; /* release all urbs for this interface */ usb_disable_interface(interface_to_usbdev(intf), intf); - if (driver && driver->disconnect) - driver->disconnect(intf); + driver->disconnect(intf); /* reset other interface state */ usb_set_interface(interface_to_usbdev(intf), @@ -235,7 +271,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (dev->driver) return -EBUSY; - dev->driver = &driver->driver; + dev->driver = &driver->drvwrap.driver; usb_set_intfdata(iface, priv); iface->condition = USB_INTERFACE_BOUND; mark_active(iface); @@ -270,7 +306,7 @@ void usb_driver_release_interface(struct usb_driver *driver, struct device *dev = &iface->dev; /* this should never happen, don't release something that's not ours */ - if (!dev->driver || dev->driver != &driver->driver) + if (!dev->driver || dev->driver != &driver->drvwrap.driver) return; /* don't release from within disconnect() */ @@ -433,24 +469,37 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_match_id); int usb_device_match(struct device *dev, struct device_driver *drv) { - struct usb_interface *intf; - struct usb_driver *usb_drv; - const struct usb_device_id *id; - - /* check for generic driver, which we don't match any device with */ - if (drv == &usb_generic_driver) - return 0; + /* devices and interfaces are handled separately */ + if (is_usb_device(dev)) { - intf = to_usb_interface(dev); - usb_drv = to_usb_driver(drv); + /* interface drivers never match devices */ + if (!is_usb_device_driver(drv)) + return 0; - id = usb_match_id(intf, usb_drv->id_table); - if (id) + /* TODO: Add real matching code */ return 1; - id = usb_match_dynamic_id(intf, usb_drv); - if (id) - return 1; + } else { + struct usb_interface *intf; + struct usb_driver *usb_drv; + const struct usb_device_id *id; + + /* device drivers never match interfaces */ + if (is_usb_device_driver(drv)) + return 0; + + intf = to_usb_interface(dev); + usb_drv = to_usb_driver(drv); + + id = usb_match_id(intf, usb_drv->id_table); + if (id) + return 1; + + id = usb_match_dynamic_id(intf, usb_drv); + if (id) + return 1; + } + return 0; } @@ -481,14 +530,13 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, /* driver is often null here; dev_dbg() would oops */ pr_debug ("usb %s: uevent\n", dev->bus_id); - /* Must check driver_data here, as on remove driver is always NULL */ - if ((dev->driver == &usb_generic_driver) || - (dev->driver_data == &usb_generic_driver_data)) + if (is_usb_device(dev)) return 0; - - intf = to_usb_interface(dev); - usb_dev = interface_to_usbdev (intf); - alt = intf->cur_altsetting; + else { + intf = to_usb_interface(dev); + usb_dev = interface_to_usbdev(intf); + alt = intf->cur_altsetting; + } if (usb_dev->devnum < 0) { pr_debug ("usb %s: already deleted?\n", dev->bus_id); @@ -569,13 +617,71 @@ static int usb_uevent(struct device *dev, char **envp, #endif /* CONFIG_HOTPLUG */ /** - * usb_register_driver - register a USB driver - * @new_driver: USB operations for the driver + * usb_register_device_driver - register a USB device (not interface) driver + * @new_udriver: USB operations for the device driver * @owner: module owner of this driver. * - * Registers a USB driver with the USB core. The list of unattached - * interfaces will be rescanned whenever a new driver is added, allowing - * the new driver to attach to any recognized devices. + * Registers a USB device driver with the USB core. The list of + * unattached devices will be rescanned whenever a new driver is + * added, allowing the new driver to attach to any recognized devices. + * Returns a negative error code on failure and 0 on success. + */ +int usb_register_device_driver(struct usb_device_driver *new_udriver, + struct module *owner) +{ + int retval = 0; + + if (usb_disabled()) + return -ENODEV; + + new_udriver->drvwrap.for_devices = 1; + new_udriver->drvwrap.driver.name = (char *) new_udriver->name; + new_udriver->drvwrap.driver.bus = &usb_bus_type; + new_udriver->drvwrap.driver.probe = usb_probe_device; + new_udriver->drvwrap.driver.remove = usb_unbind_device; + new_udriver->drvwrap.driver.owner = owner; + + retval = driver_register(&new_udriver->drvwrap.driver); + + if (!retval) { + pr_info("%s: registered new device driver %s\n", + usbcore_name, new_udriver->name); + usbfs_update_special(); + } else { + printk(KERN_ERR "%s: error %d registering device " + " driver %s\n", + usbcore_name, retval, new_udriver->name); + } + + return retval; +} +EXPORT_SYMBOL_GPL(usb_register_device_driver); + +/** + * usb_deregister_device_driver - unregister a USB device (not interface) driver + * @udriver: USB operations of the device driver to unregister + * Context: must be able to sleep + * + * Unlinks the specified driver from the internal USB driver list. + */ +void usb_deregister_device_driver(struct usb_device_driver *udriver) +{ + pr_info("%s: deregistering device driver %s\n", + usbcore_name, udriver->name); + + driver_unregister(&udriver->drvwrap.driver); + usbfs_update_special(); +} +EXPORT_SYMBOL_GPL(usb_deregister_device_driver); + +/** + * usb_register_driver - register a USB interface driver + * @new_driver: USB operations for the interface driver + * @owner: module owner of this driver. + * + * Registers a USB interface driver with the USB core. The list of + * unattached interfaces will be rescanned whenever a new driver is + * added, allowing the new driver to attach to any recognized interfaces. * Returns a negative error code on failure and 0 on success. * * NOTE: if you want your driver to use the USB major number, you must call @@ -589,23 +695,25 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner) if (usb_disabled()) return -ENODEV; - new_driver->driver.name = (char *)new_driver->name; - new_driver->driver.bus = &usb_bus_type; - new_driver->driver.probe = usb_probe_interface; - new_driver->driver.remove = usb_unbind_interface; - new_driver->driver.owner = owner; + new_driver->drvwrap.for_devices = 0; + new_driver->drvwrap.driver.name = (char *) new_driver->name; + new_driver->drvwrap.driver.bus = &usb_bus_type; + new_driver->drvwrap.driver.probe = usb_probe_interface; + new_driver->drvwrap.driver.remove = usb_unbind_interface; + new_driver->drvwrap.driver.owner = owner; spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list); - retval = driver_register(&new_driver->driver); + retval = driver_register(&new_driver->drvwrap.driver); if (!retval) { - pr_info("%s: registered new driver %s\n", + pr_info("%s: registered new interface driver %s\n", usbcore_name, new_driver->name); usbfs_update_special(); usb_create_newid_file(new_driver); } else { - printk(KERN_ERR "%s: error %d registering driver %s\n", + printk(KERN_ERR "%s: error %d registering interface " + " driver %s\n", usbcore_name, retval, new_driver->name); } @@ -614,8 +722,8 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner) EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver); /** - * usb_deregister - unregister a USB driver - * @driver: USB operations of the driver to unregister + * usb_deregister - unregister a USB interface driver + * @driver: USB operations of the interface driver to unregister * Context: must be able to sleep * * Unlinks the specified driver from the internal USB driver list. @@ -626,11 +734,12 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver); */ void usb_deregister(struct usb_driver *driver) { - pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name); + pr_info("%s: deregistering interface driver %s\n", + usbcore_name, driver->name); usb_remove_newid_file(driver); usb_free_dynids(driver); - driver_unregister(&driver->driver); + driver_unregister(&driver->drvwrap.driver); usbfs_update_special(); } @@ -655,7 +764,7 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message) * marked for FREEZE as soon as their children are already idled. * But those semantics are useless, so we equate the two (sigh). */ - if (dev->driver == &usb_generic_driver) { + if (is_usb_device(dev)) { if (dev->power.power_state.event == message.event) return 0; /* we need to rule out bogus requests through sysfs */ @@ -665,8 +774,7 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message) return usb_port_suspend(to_usb_device(dev)); } - if ((dev->driver == NULL) || - (dev->driver_data == &usb_generic_driver_data)) + if (dev->driver == NULL) return 0; intf = to_usb_interface(dev); @@ -705,15 +813,14 @@ static int usb_generic_resume(struct device *dev) dev->power.power_state.event = PM_EVENT_ON; /* devices resume through their hubs */ - if (dev->driver == &usb_generic_driver) { + if (is_usb_device(dev)) { udev = to_usb_device(dev); if (udev->state == USB_STATE_NOTATTACHED) return 0; return usb_port_resume(udev); } - if ((dev->driver == NULL) || - (dev->driver_data == &usb_generic_driver_data)) { + if (dev->driver == NULL) { dev->power.power_state.event = PM_EVENT_FREEZE; return 0; } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 7bab9769b34f..fa6f34a12b4b 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -21,14 +21,12 @@ #include #include "usb.h" -static int generic_probe(struct device *dev) +static int generic_probe(struct usb_device *udev) { return 0; } -static int generic_remove(struct device *dev) +static void generic_disconnect(struct usb_device *udev) { - struct usb_device *udev = to_usb_device(dev); - /* if this is only an unbind, not a physical disconnect, then * unconfigure the device */ if (udev->state == USB_STATE_CONFIGURED) @@ -37,17 +35,10 @@ static int generic_remove(struct device *dev) /* in case the call failed or the device was suspended */ if (udev->state >= USB_STATE_CONFIGURED) usb_disable_device(udev, 0); - return 0; } -struct device_driver usb_generic_driver = { - .owner = THIS_MODULE, +struct usb_device_driver usb_generic_driver = { .name = "usb", - .bus = &usb_bus_type, .probe = generic_probe, - .remove = generic_remove, + .disconnect = generic_disconnect, }; - -/* Fun hack to determine if the struct device is a - * usb device or a usb interface. */ -int usb_generic_driver_data; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0b8c67bcde60..6dfbc284369b 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -123,7 +123,7 @@ static int __find_interface(struct device * dev, void * data) struct usb_interface *intf; /* can't look at usb devices, only interfaces */ - if (dev->driver == &usb_generic_driver) + if (is_usb_device(dev)) return 0; intf = to_usb_interface(dev); @@ -149,7 +149,8 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) argb.minor = minor; argb.interface = NULL; - driver_for_each_device(&drv->driver, NULL, &argb, __find_interface); + driver_for_each_device(&drv->drvwrap.driver, NULL, &argb, + __find_interface); return argb.interface; } @@ -204,11 +205,13 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) device_initialize(&dev->dev); dev->dev.bus = &usb_bus_type; dev->dev.dma_mask = bus->controller->dma_mask; - dev->dev.driver_data = &usb_generic_driver_data; - dev->dev.driver = &usb_generic_driver; + dev->dev.driver = &usb_generic_driver.drvwrap.driver; dev->dev.release = usb_release_dev; dev->state = USB_STATE_ATTACHED; + /* This magic assignment distinguishes devices from interfaces */ + dev->dev.platform_data = &usb_generic_driver; + INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; @@ -838,7 +841,7 @@ static int __init usb_init(void) retval = usb_hub_init(); if (retval) goto hub_init_failed; - retval = driver_register(&usb_generic_driver); + retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); if (!retval) goto out; @@ -868,7 +871,7 @@ static void __exit usb_exit(void) if (nousb) return; - driver_unregister(&usb_generic_driver); + usb_deregister_device_driver(&usb_generic_driver); usb_major_cleanup(); usbfs_cleanup(); usb_deregister(&usbfs_driver); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 82d397a6f773..1d25ccac7832 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -34,8 +34,24 @@ extern int usb_port_suspend(struct usb_device *dev); extern int usb_port_resume(struct usb_device *dev); extern struct bus_type usb_bus_type; -extern struct device_driver usb_generic_driver; -extern int usb_generic_driver_data; +extern struct usb_device_driver usb_generic_driver; + +/* Here's how we tell apart devices and interfaces. Luckily there's + * no such thing as a platform USB device, so we can steal the use + * of the platform_data field. */ + +static inline int is_usb_device(struct device *dev) +{ + return dev->platform_data == &usb_generic_driver; +} + +/* Do the same for device drivers and interface drivers. */ + +static inline int is_usb_device_driver(struct device_driver *drv) +{ + return container_of(drv, struct usbdrv_wrap, driver)-> + for_devices; +} /* Interfaces and their "power state" are owned by usbcore */ diff --git a/include/linux/usb.h b/include/linux/usb.h index d2bd0c8e0154..b4ccce6d0982 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -540,7 +540,17 @@ struct usb_dynids { }; /** - * struct usb_driver - identifies USB driver to usbcore + * struct usbdrv_wrap - wrapper for driver-model structure + * @driver: The driver-model core driver structure. + * @for_devices: Non-zero for device drivers, 0 for interface drivers. + */ +struct usbdrv_wrap { + struct device_driver driver; + int for_devices; +}; + +/** + * struct usb_driver - identifies USB interface driver to usbcore * @name: The driver name should be unique among USB drivers, * and should normally be the same as the module name. * @probe: Called to see if the driver is willing to manage a particular @@ -567,12 +577,12 @@ struct usb_dynids { * or your driver's probe function will never get called. * @dynids: used internally to hold the list of dynamically added device * ids for this driver. - * @driver: the driver model core driver structure. + * @drvwrap: Driver-model core structure wrapper. * @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be * added to this driver by preventing the sysfs file from being created. * - * USB drivers must provide a name, probe() and disconnect() methods, - * and an id_table. Other driver fields are optional. + * USB interface drivers must provide a name, probe() and disconnect() + * methods, and an id_table. Other driver fields are optional. * * The id_table is used in hotplugging. It holds a set of descriptors, * and specialized data may be associated with each entry. That table @@ -606,10 +616,40 @@ struct usb_driver { const struct usb_device_id *id_table; struct usb_dynids dynids; - struct device_driver driver; + struct usbdrv_wrap drvwrap; unsigned int no_dynamic_id:1; }; -#define to_usb_driver(d) container_of(d, struct usb_driver, driver) +#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver) + +/** + * struct usb_device_driver - identifies USB device driver to usbcore + * @name: The driver name should be unique among USB drivers, + * and should normally be the same as the module name. + * @probe: Called to see if the driver is willing to manage a particular + * device. If it is, probe returns zero and uses dev_set_drvdata() + * to associate driver-specific data with the device. If unwilling + * to manage the device, return a negative errno value. + * @disconnect: Called when the device is no longer accessible, usually + * because it has been (or is being) disconnected or the driver's + * module is being unloaded. + * @suspend: Called when the device is going to be suspended by the system. + * @resume: Called when the device is being resumed by the system. + * @drvwrap: Driver-model core structure wrapper. + * + * USB drivers must provide all the fields listed above except drvwrap. + */ +struct usb_device_driver { + const char *name; + + int (*probe) (struct usb_device *udev); + void (*disconnect) (struct usb_device *udev); + + int (*suspend) (struct usb_device *udev, pm_message_t message); + int (*resume) (struct usb_device *udev); + struct usbdrv_wrap drvwrap; +}; +#define to_usb_device_driver(d) container_of(d, struct usb_device_driver, \ + drvwrap.driver) extern struct bus_type usb_bus_type; @@ -633,13 +673,17 @@ struct usb_class_driver { * use these in module_init()/module_exit() * and don't forget MODULE_DEVICE_TABLE(usb, ...) */ -int usb_register_driver(struct usb_driver *, struct module *); +extern int usb_register_driver(struct usb_driver *, struct module *); static inline int usb_register(struct usb_driver *driver) { return usb_register_driver(driver, THIS_MODULE); } extern void usb_deregister(struct usb_driver *); +extern int usb_register_device_driver(struct usb_device_driver *, + struct module *); +extern void usb_deregister_device_driver(struct usb_device_driver *); + extern int usb_register_dev(struct usb_interface *intf, struct usb_class_driver *class_driver); extern void usb_deregister_dev(struct usb_interface *intf, -- cgit v1.2.3 From 4d064c080265a41324d108fccc26b72106d43db3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 1 Jul 2006 22:11:44 -0400 Subject: usbcore: track whether interfaces are suspended Currently we rely on intf->dev.power.power_state.event for tracking whether intf is suspended. This is not a reliable technique because that value is owned by the PM core, not by usbcore. This patch (as718b) adds a new flag so that we can accurately tell which interfaces are suspended and which aren't. At first one might think these flags aren't needed, since interfaces will be suspended along with their devices. It turns out there are a couple of intermediate situations where that's not quite true, such as while processing a remote-wakeup request. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.h | 6 +++--- include/linux/usb.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index cc42972b6bb0..74df0db954c9 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -59,17 +59,17 @@ static inline int is_usb_device_driver(struct device_driver *drv) static inline void mark_active(struct usb_interface *f) { - f->dev.power.power_state.event = PM_EVENT_ON; + f->is_active = 1; } static inline void mark_quiesced(struct usb_interface *f) { - f->dev.power.power_state.event = PM_EVENT_FREEZE; + f->is_active = 0; } static inline int is_active(struct usb_interface *f) { - return f->dev.power.power_state.event == PM_EVENT_ON; + return f->is_active; } diff --git a/include/linux/usb.h b/include/linux/usb.h index b4ccce6d0982..e22f4b386605 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -102,6 +102,7 @@ enum usb_interface_condition { * number from the USB core by calling usb_register_dev(). * @condition: binding state of the interface: not bound, binding * (in probe()), bound to a driver, or unbinding (in disconnect()) + * @is_active: flag set when the interface is bound and not suspended. * @dev: driver model's view of this device * @class_dev: driver model's class view of this device. * @@ -142,6 +143,8 @@ struct usb_interface { int minor; /* minor number this interface is * bound to */ enum usb_interface_condition condition; /* state of binding */ + unsigned is_active:1; /* the interface is not suspended */ + struct device dev; /* interface specific device info */ struct class_device *class_dev; }; -- cgit v1.2.3 From f2ebf92c9e1930a8f79b7eb49a32122931929014 Mon Sep 17 00:00:00 2001 From: Ben Williamson Date: Tue, 1 Aug 2006 11:28:16 +1000 Subject: USB: gmidi: New USB MIDI Gadget class driver. This driver is glue between the USB gadget interface and the ALSA MIDI interface. It allows us to appear as a MIDI Streaming device to a host system on the other end of a USB cable. This includes linux/usb/audio.h and linux/usb/midi.h containing definitions from the relevant USB specifications for USB audio and USB MIDI devices. The following changes have been made since the first RFC posting: * Bug fixes to endpoint handling. * Workaround for USB_REQ_SET_CONFIGURATION handling, not understood yet. * Added SND and SND_RAWMIDI dependencies in Kconfig. * Moved usb_audio.h and usb_midi.h to usb/*.h * Added module parameters for ALSA card index and id. * Added module parameters for USB descriptor IDs and strings. * Removed some unneeded stuff inherited from zero.c, more to go. * Provide DECLARE_* macros for the variable-length structs. * Use kmalloc instead of usb_ep_alloc_buffer. * Limit source to 80 columns. * Return actual error code instead of -ENOMEM in a few places. Signed-off-by: Ben Williamson Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 14 + drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/gmidi.c | 1337 +++++++++++++++++++++++++++++++++++++++++++ include/linux/usb/audio.h | 53 ++ include/linux/usb/midi.h | 112 ++++ 5 files changed, 1518 insertions(+) create mode 100644 drivers/usb/gadget/gmidi.c create mode 100644 include/linux/usb/audio.h create mode 100644 include/linux/usb/midi.h (limited to 'include/linux') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 1a32d96774b4..4301e96c417b 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -404,6 +404,20 @@ config USB_G_SERIAL which includes instructions and a "driver info file" needed to make MS-Windows work with this driver. +config USB_MIDI_GADGET + tristate "MIDI Gadget (EXPERIMENTAL)" + depends on SND && EXPERIMENTAL + select SND_RAWMIDI + help + The MIDI Gadget acts as a USB Audio device, with one MIDI + input and one MIDI output. These MIDI jacks appear as + a sound "card" in the ALSA sound system. Other MIDI + connections can then be made on the gadget system, using + ALSA's aconnect utility etc. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_midi". + # put drivers that need isochronous transfer support (for audio # or video class gadget drivers), or specific hardware, here. diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 5a28e61392ec..e71e086a1cfa 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o g_zero-objs := zero.o usbstring.o config.o epautoconf.o g_ether-objs := ether.o usbstring.o config.o epautoconf.o g_serial-objs := serial.o usbstring.o config.o epautoconf.o +g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o usbstring.o config.o \ epautoconf.o @@ -28,4 +29,5 @@ obj-$(CONFIG_USB_ETH) += g_ether.o obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o obj-$(CONFIG_USB_G_SERIAL) += g_serial.o +obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c new file mode 100644 index 000000000000..b68cecd57411 --- /dev/null +++ b/drivers/usb/gadget/gmidi.c @@ -0,0 +1,1337 @@ +/* + * gmidi.c -- USB MIDI Gadget Driver + * + * Copyright (C) 2006 Thumtronics Pty Ltd. + * Developed for Thumtronics by Grey Innovation + * Ben Williamson + * + * This software is distributed under the terms of the GNU General Public + * License ("GPL") version 2, as published by the Free Software Foundation. + * + * This code is based in part on: + * + * Gadget Zero driver, Copyright (C) 2003-2004 David Brownell. + * USB Audio driver, Copyright (C) 2002 by Takashi Iwai. + * USB MIDI driver, Copyright (C) 2002-2005 Clemens Ladisch. + * + * Refer to the USB Device Class Definition for MIDI Devices: + * http://www.usb.org/developers/devclass_docs/midi10.pdf + */ + +#define DEBUG 1 +// #define VERBOSE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "gadget_chips.h" + +MODULE_AUTHOR("Ben Williamson"); +MODULE_LICENSE("GPL v2"); + +#define DRIVER_VERSION "25 Jul 2006" + +static const char shortname[] = "g_midi"; +static const char longname[] = "MIDI Gadget"; + +static int index = SNDRV_DEFAULT_IDX1; +static char *id = SNDRV_DEFAULT_STR1; + +module_param(index, int, 0444); +MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter."); +module_param(id, charp, 0444); +MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter."); + +/* Some systems will want different product identifers published in the + * device descriptor, either numbers or strings or both. These string + * parameters are in UTF-8 (superset of ASCII's 7 bit characters). + */ + +static ushort idVendor; +module_param(idVendor, ushort, S_IRUGO); +MODULE_PARM_DESC(idVendor, "USB Vendor ID"); + +static ushort idProduct; +module_param(idProduct, ushort, S_IRUGO); +MODULE_PARM_DESC(idProduct, "USB Product ID"); + +static ushort bcdDevice; +module_param(bcdDevice, ushort, S_IRUGO); +MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); + +static char *iManufacturer; +module_param(iManufacturer, charp, S_IRUGO); +MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); + +static char *iProduct; +module_param(iProduct, charp, S_IRUGO); +MODULE_PARM_DESC(iProduct, "USB Product string"); + +static char *iSerialNumber; +module_param(iSerialNumber, charp, S_IRUGO); +MODULE_PARM_DESC(iSerialNumber, "SerialNumber"); + +/* + * this version autoconfigures as much as possible, + * which is reasonable for most "bulk-only" drivers. + */ +static const char *EP_IN_NAME; +static const char *EP_OUT_NAME; + + +/* big enough to hold our biggest descriptor */ +#define USB_BUFSIZ 256 + + +/* This is a gadget, and the IN/OUT naming is from the host's perspective. + USB -> OUT endpoint -> rawmidi + USB <- IN endpoint <- rawmidi */ +struct gmidi_in_port { + struct gmidi_device* dev; + int active; + uint8_t cable; /* cable number << 4 */ + uint8_t state; +#define STATE_UNKNOWN 0 +#define STATE_1PARAM 1 +#define STATE_2PARAM_1 2 +#define STATE_2PARAM_2 3 +#define STATE_SYSEX_0 4 +#define STATE_SYSEX_1 5 +#define STATE_SYSEX_2 6 + uint8_t data[2]; +}; + +struct gmidi_device { + spinlock_t lock; + struct usb_gadget *gadget; + struct usb_request *req; /* for control responses */ + u8 config; + struct usb_ep *in_ep, *out_ep; + struct snd_card *card; + struct snd_rawmidi *rmidi; + struct snd_rawmidi_substream *in_substream; + struct snd_rawmidi_substream *out_substream; + + /* For the moment we only support one port in + each direction, but in_port is kept as a + separate struct so we can have more later. */ + struct gmidi_in_port in_port; + unsigned long out_triggered; + struct tasklet_struct tasklet; +}; + +static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req); + + +#define xprintk(d,level,fmt,args...) \ + dev_printk(level , &(d)->gadget->dev , fmt , ## args) + +#ifdef DEBUG +#define DBG(dev,fmt,args...) \ + xprintk(dev , KERN_DEBUG , fmt , ## args) +#else +#define DBG(dev,fmt,args...) \ + do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE +#define VDBG DBG +#else +#define VDBG(dev,fmt,args...) \ + do { } while (0) +#endif /* VERBOSE */ + +#define ERROR(dev,fmt,args...) \ + xprintk(dev , KERN_ERR , fmt , ## args) +#define WARN(dev,fmt,args...) \ + xprintk(dev , KERN_WARNING , fmt , ## args) +#define INFO(dev,fmt,args...) \ + xprintk(dev , KERN_INFO , fmt , ## args) + + +static unsigned buflen = 256; +static unsigned qlen = 32; + +module_param(buflen, uint, S_IRUGO); +module_param(qlen, uint, S_IRUGO); + + +/* Thanks to Grey Innovation for donating this product ID. + * + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ +#define DRIVER_VENDOR_NUM 0x17b3 /* Grey Innovation */ +#define DRIVER_PRODUCT_NUM 0x0004 /* Linux-USB "MIDI Gadget" */ + + +/* + * DESCRIPTORS ... most are static, but strings and (full) + * configuration descriptors are built on demand. + */ + +#define STRING_MANUFACTURER 25 +#define STRING_PRODUCT 42 +#define STRING_SERIAL 101 +#define STRING_MIDI_GADGET 250 + +/* We only have the one configuration, it's number 1. */ +#define GMIDI_CONFIG 1 + +/* We have two interfaces- AudioControl and MIDIStreaming */ +#define GMIDI_AC_INTERFACE 0 +#define GMIDI_MS_INTERFACE 1 +#define GMIDI_NUM_INTERFACES 2 + +DECLARE_USB_AC_HEADER_DESCRIPTOR(1); +DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); +DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1); + +/* B.1 Device Descriptor */ +static struct usb_device_descriptor device_desc = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM), + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .bNumConfigurations = 1, +}; + +/* B.2 Configuration Descriptor */ +static struct usb_config_descriptor config_desc = { + .bLength = USB_DT_CONFIG_SIZE, + .bDescriptorType = USB_DT_CONFIG, + /* compute wTotalLength on the fly */ + .bNumInterfaces = GMIDI_NUM_INTERFACES, + .bConfigurationValue = GMIDI_CONFIG, + .iConfiguration = STRING_MIDI_GADGET, + /* + * FIXME: When embedding this driver in a device, + * these need to be set to reflect the actual + * power properties of the device. Is it selfpowered? + */ + .bmAttributes = USB_CONFIG_ATT_ONE, + .bMaxPower = 1, +}; + +/* B.3.1 Standard AC Interface Descriptor */ +static const struct usb_interface_descriptor ac_interface_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = GMIDI_AC_INTERFACE, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, + .iInterface = STRING_MIDI_GADGET, +}; + +/* B.3.2 Class-Specific AC Interface Descriptor */ +static const struct usb_ac_header_descriptor_1 ac_header_desc = { + .bLength = USB_DT_AC_HEADER_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_HEADER, + .bcdADC = __constant_cpu_to_le16(0x0100), + .wTotalLength = USB_DT_AC_HEADER_SIZE(1), + .bInCollection = 1, + .baInterfaceNr = { + [0] = GMIDI_MS_INTERFACE, + } +}; + +/* B.4.1 Standard MS Interface Descriptor */ +static const struct usb_interface_descriptor ms_interface_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = GMIDI_MS_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING, + .iInterface = STRING_MIDI_GADGET, +}; + +/* B.4.2 Class-Specific MS Interface Descriptor */ +static const struct usb_ms_header_descriptor ms_header_desc = { + .bLength = USB_DT_MS_HEADER_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_HEADER, + .bcdMSC = __constant_cpu_to_le16(0x0100), + .wTotalLength = USB_DT_MS_HEADER_SIZE + + 2*USB_DT_MIDI_IN_SIZE + + 2*USB_DT_MIDI_OUT_SIZE(1), +}; + +#define JACK_IN_EMB 1 +#define JACK_IN_EXT 2 +#define JACK_OUT_EMB 3 +#define JACK_OUT_EXT 4 + +/* B.4.3 MIDI IN Jack Descriptors */ +static const struct usb_midi_in_jack_descriptor jack_in_emb_desc = { + .bLength = USB_DT_MIDI_IN_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_MIDI_IN_JACK, + .bJackType = USB_MS_EMBEDDED, + .bJackID = JACK_IN_EMB, +}; + +static const struct usb_midi_in_jack_descriptor jack_in_ext_desc = { + .bLength = USB_DT_MIDI_IN_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_MIDI_IN_JACK, + .bJackType = USB_MS_EXTERNAL, + .bJackID = JACK_IN_EXT, +}; + +/* B.4.4 MIDI OUT Jack Descriptors */ +static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = { + .bLength = USB_DT_MIDI_OUT_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK, + .bJackType = USB_MS_EMBEDDED, + .bJackID = JACK_OUT_EMB, + .bNrInputPins = 1, + .pins = { + [0] = { + .baSourceID = JACK_IN_EXT, + .baSourcePin = 1, + } + } +}; + +static const struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc = { + .bLength = USB_DT_MIDI_OUT_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK, + .bJackType = USB_MS_EXTERNAL, + .bJackID = JACK_OUT_EXT, + .bNrInputPins = 1, + .pins = { + [0] = { + .baSourceID = JACK_IN_EMB, + .baSourcePin = 1, + } + } +}; + +/* B.5.1 Standard Bulk OUT Endpoint Descriptor */ +static struct usb_endpoint_descriptor bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */ +static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = { + .bLength = USB_DT_MS_ENDPOINT_SIZE(1), + .bDescriptorType = USB_DT_CS_ENDPOINT, + .bDescriptorSubtype = USB_MS_GENERAL, + .bNumEmbMIDIJack = 1, + .baAssocJackID = { + [0] = JACK_IN_EMB, + } +}; + +/* B.6.1 Standard Bulk IN Endpoint Descriptor */ +static struct usb_endpoint_descriptor bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */ +static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = { + .bLength = USB_DT_MS_ENDPOINT_SIZE(1), + .bDescriptorType = USB_DT_CS_ENDPOINT, + .bDescriptorSubtype = USB_MS_GENERAL, + .bNumEmbMIDIJack = 1, + .baAssocJackID = { + [0] = JACK_OUT_EMB, + } +}; + +static const struct usb_descriptor_header *gmidi_function [] = { + (struct usb_descriptor_header *)&ac_interface_desc, + (struct usb_descriptor_header *)&ac_header_desc, + (struct usb_descriptor_header *)&ms_interface_desc, + + (struct usb_descriptor_header *)&ms_header_desc, + (struct usb_descriptor_header *)&jack_in_emb_desc, + (struct usb_descriptor_header *)&jack_in_ext_desc, + (struct usb_descriptor_header *)&jack_out_emb_desc, + (struct usb_descriptor_header *)&jack_out_ext_desc, + /* If you add more jacks, update ms_header_desc.wTotalLength */ + + (struct usb_descriptor_header *)&bulk_out_desc, + (struct usb_descriptor_header *)&ms_out_desc, + (struct usb_descriptor_header *)&bulk_in_desc, + (struct usb_descriptor_header *)&ms_in_desc, + NULL, +}; + +static char manufacturer[50]; +static char product_desc[40] = "MIDI Gadget"; +static char serial_number[20]; + +/* static strings, in UTF-8 */ +static struct usb_string strings [] = { + { STRING_MANUFACTURER, manufacturer, }, + { STRING_PRODUCT, product_desc, }, + { STRING_SERIAL, serial_number, }, + { STRING_MIDI_GADGET, longname, }, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab = { + .language = 0x0409, /* en-us */ + .strings = strings, +}; + +static int config_buf(struct usb_gadget *gadget, + u8 *buf, u8 type, unsigned index) +{ + int len; + + /* only one configuration */ + if (index != 0) { + return -EINVAL; + } + len = usb_gadget_config_buf(&config_desc, + buf, USB_BUFSIZ, gmidi_function); + if (len < 0) { + return len; + } + ((struct usb_config_descriptor *)buf)->bDescriptorType = type; + return len; +} + +static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (req) { + req->length = length; + req->buf = kmalloc(length, GFP_ATOMIC); + if (!req->buf) { + usb_ep_free_request(ep, req); + req = NULL; + } + } + return req; +} + +static void free_ep_req(struct usb_ep *ep, struct usb_request *req) +{ + kfree(req->buf); + usb_ep_free_request(ep, req); +} + +static const uint8_t gmidi_cin_length[] = { + 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1 +}; + +/* + * Receives a chunk of MIDI data. + */ +static void gmidi_read_data(struct usb_ep *ep, int cable, + uint8_t* data, int length) +{ + struct gmidi_device *dev = ep->driver_data; + /* cable is ignored, because for now we only have one. */ + + if (!dev->out_substream) { + /* Nobody is listening - throw it on the floor. */ + return; + } + if (!test_bit(dev->out_substream->number, &dev->out_triggered)) { + return; + } + snd_rawmidi_receive(dev->out_substream, data, length); +} + +static void gmidi_handle_out_data(struct usb_ep *ep, struct usb_request *req) +{ + unsigned i; + u8 *buf = req->buf; + + for (i = 0; i + 3 < req->actual; i += 4) { + if (buf[i] != 0) { + int cable = buf[i] >> 4; + int length = gmidi_cin_length[buf[i] & 0x0f]; + gmidi_read_data(ep, cable, &buf[i + 1], length); + } + } +} + +static void gmidi_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct gmidi_device *dev = ep->driver_data; + int status = req->status; + + switch (status) { + case 0: /* normal completion */ + if (ep == dev->out_ep) { + /* we received stuff. + req is queued again, below */ + gmidi_handle_out_data(ep, req); + } else if (ep == dev->in_ep) { + /* our transmit completed. + see if there's more to go. + gmidi_transmit eats req, don't queue it again. */ + gmidi_transmit(dev, req); + return; + } + break; + + /* this endpoint is normally active while we're configured */ + case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNRESET: /* request dequeued */ + case -ESHUTDOWN: /* disconnect from host */ + VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status, + req->actual, req->length); + if (ep == dev->out_ep) { + gmidi_handle_out_data(ep, req); + } + free_ep_req(ep, req); + return; + + case -EOVERFLOW: /* buffer overrun on read means that + * we didn't provide a big enough + * buffer. + */ + default: + DBG(dev, "%s complete --> %d, %d/%d\n", ep->name, + status, req->actual, req->length); + break; + case -EREMOTEIO: /* short read */ + break; + } + + status = usb_ep_queue(ep, req, GFP_ATOMIC); + if (status) { + ERROR(dev, "kill %s: resubmit %d bytes --> %d\n", + ep->name, req->length, status); + usb_ep_set_halt(ep); + /* FIXME recover later ... somehow */ + } +} + +static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags) +{ + int err = 0; + struct usb_request *req; + struct usb_ep* ep; + unsigned i; + + err = usb_ep_enable(dev->in_ep, &bulk_in_desc); + if (err) { + ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err); + goto fail; + } + dev->in_ep->driver_data = dev; + + err = usb_ep_enable(dev->out_ep, &bulk_out_desc); + if (err) { + ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err); + goto fail; + } + dev->out_ep->driver_data = dev; + + /* allocate a bunch of read buffers and queue them all at once. */ + ep = dev->out_ep; + for (i = 0; i < qlen && err == 0; i++) { + req = alloc_ep_req(ep, buflen); + if (req) { + req->complete = gmidi_complete; + err = usb_ep_queue(ep, req, GFP_ATOMIC); + if (err) { + DBG(dev, "%s queue req: %d\n", ep->name, err); + } + } else { + err = -ENOMEM; + } + } +fail: + /* caller is responsible for cleanup on error */ + return err; +} + + +static void gmidi_reset_config(struct gmidi_device *dev) +{ + if (dev->config == 0) { + return; + } + + DBG(dev, "reset config\n"); + + /* just disable endpoints, forcing completion of pending i/o. + * all our completion handlers free their requests in this case. + */ + usb_ep_disable(dev->in_ep); + usb_ep_disable(dev->out_ep); + dev->config = 0; +} + +/* change our operational config. this code must agree with the code + * that returns config descriptors, and altsetting code. + * + * it's also responsible for power management interactions. some + * configurations might not work with our current power sources. + * + * note that some device controller hardware will constrain what this + * code can do, perhaps by disallowing more than one configuration or + * by limiting configuration choices (like the pxa2xx). + */ +static int +gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) +{ + int result = 0; + struct usb_gadget *gadget = dev->gadget; + +#if 0 + /* FIXME */ + /* Hacking this bit out fixes a bug where on receipt of two + USB_REQ_SET_CONFIGURATION messages, we end up with no + buffered OUT requests waiting for data. This is clearly + hiding a bug elsewhere, because if the config didn't + change then we really shouldn't do anything. */ + /* Having said that, when we do "change" from config 1 + to config 1, we at least gmidi_reset_config() which + clears out any requests on endpoints, so it's not like + we leak or anything. */ + if (number == dev->config) { + return 0; + } +#endif + + if (gadget_is_sa1100(gadget) && dev->config) { + /* tx fifo is full, but we can't clear it...*/ + INFO(dev, "can't change configurations\n"); + return -ESPIPE; + } + gmidi_reset_config(dev); + + switch (number) { + case GMIDI_CONFIG: + result = set_gmidi_config(dev, gfp_flags); + break; + default: + result = -EINVAL; + /* FALL THROUGH */ + case 0: + return result; + } + + if (!result && (!dev->in_ep || !dev->out_ep)) { + result = -ENODEV; + } + if (result) { + gmidi_reset_config(dev); + } else { + char *speed; + + switch (gadget->speed) { + case USB_SPEED_LOW: speed = "low"; break; + case USB_SPEED_FULL: speed = "full"; break; + case USB_SPEED_HIGH: speed = "high"; break; + default: speed = "?"; break; + } + + dev->config = number; + INFO(dev, "%s speed\n", speed); + } + return result; +} + + +static void gmidi_setup_complete(struct usb_ep *ep, struct usb_request *req) +{ + if (req->status || req->actual != req->length) { + DBG((struct gmidi_device *) ep->driver_data, + "setup complete --> %d, %d/%d\n", + req->status, req->actual, req->length); + } +} + +/* + * The setup() callback implements all the ep0 functionality that's + * not handled lower down, in hardware or the hardware driver (like + * device and endpoint feature flags, and their status). It's all + * housekeeping for the gadget function we're implementing. Most of + * the work is in config-specific setup. + */ +static int gmidi_setup(struct usb_gadget *gadget, + const struct usb_ctrlrequest *ctrl) +{ + struct gmidi_device *dev = get_gadget_data(gadget); + struct usb_request *req = dev->req; + int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + + /* usually this stores reply data in the pre-allocated ep0 buffer, + * but config change events will reconfigure hardware. + */ + req->zero = 0; + switch (ctrl->bRequest) { + + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != USB_DIR_IN) { + goto unknown; + } + switch (w_value >> 8) { + + case USB_DT_DEVICE: + value = min(w_length, (u16) sizeof(device_desc)); + memcpy(req->buf, &device_desc, value); + break; + case USB_DT_CONFIG: + value = config_buf(gadget, req->buf, + w_value >> 8, + w_value & 0xff); + if (value >= 0) { + value = min(w_length, (u16)value); + } + break; + + case USB_DT_STRING: + /* wIndex == language code. + * this driver only handles one language, you can + * add string tables for other languages, using + * any UTF-8 characters + */ + value = usb_gadget_get_string(&stringtab, + w_value & 0xff, req->buf); + if (value >= 0) { + value = min(w_length, (u16)value); + } + break; + } + break; + + /* currently two configs, two speeds */ + case USB_REQ_SET_CONFIGURATION: + if (ctrl->bRequestType != 0) { + goto unknown; + } + if (gadget->a_hnp_support) { + DBG(dev, "HNP available\n"); + } else if (gadget->a_alt_hnp_support) { + DBG(dev, "HNP needs a different root port\n"); + } else { + VDBG(dev, "HNP inactive\n"); + } + spin_lock(&dev->lock); + value = gmidi_set_config(dev, w_value, GFP_ATOMIC); + spin_unlock(&dev->lock); + break; + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != USB_DIR_IN) { + goto unknown; + } + *(u8 *)req->buf = dev->config; + value = min(w_length, (u16)1); + break; + + /* until we add altsetting support, or other interfaces, + * only 0/0 are possible. pxa2xx only supports 0/0 (poorly) + * and already killed pending endpoint I/O. + */ + case USB_REQ_SET_INTERFACE: + if (ctrl->bRequestType != USB_RECIP_INTERFACE) { + goto unknown; + } + spin_lock(&dev->lock); + if (dev->config && w_index < GMIDI_NUM_INTERFACES + && w_value == 0) + { + u8 config = dev->config; + + /* resets interface configuration, forgets about + * previous transaction state (queued bufs, etc) + * and re-inits endpoint state (toggle etc) + * no response queued, just zero status == success. + * if we had more than one interface we couldn't + * use this "reset the config" shortcut. + */ + gmidi_reset_config(dev); + gmidi_set_config(dev, config, GFP_ATOMIC); + value = 0; + } + spin_unlock(&dev->lock); + break; + case USB_REQ_GET_INTERFACE: + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) { + goto unknown; + } + if (!dev->config) { + break; + } + if (w_index >= GMIDI_NUM_INTERFACES) { + value = -EDOM; + break; + } + *(u8 *)req->buf = 0; + value = min(w_length, (u16)1); + break; + + default: +unknown: + VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + } + + /* respond with data transfer before status phase? */ + if (value >= 0) { + req->length = value; + req->zero = value < w_length; + value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DBG(dev, "ep_queue --> %d\n", value); + req->status = 0; + gmidi_setup_complete(gadget->ep0, req); + } + } + + /* device either stalls (value < 0) or reports success */ + return value; +} + +static void gmidi_disconnect(struct usb_gadget *gadget) +{ + struct gmidi_device *dev = get_gadget_data(gadget); + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + gmidi_reset_config(dev); + + /* a more significant application might have some non-usb + * activities to quiesce here, saving resources like power + * or pushing the notification up a network stack. + */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* next we may get setup() calls to enumerate new connections; + * or an unbind() during shutdown (including removing module). + */ +} + +static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget) +{ + struct gmidi_device *dev = get_gadget_data(gadget); + struct snd_card* card; + + DBG(dev, "unbind\n"); + + card = dev->card; + dev->card = NULL; + if (card) { + snd_card_free(card); + } + + /* we've already been disconnected ... no i/o is active */ + if (dev->req) { + dev->req->length = USB_BUFSIZ; + free_ep_req(gadget->ep0, dev->req); + } + kfree(dev); + set_gadget_data(gadget, NULL); +} + +static int gmidi_snd_free(struct snd_device *device) +{ + return 0; +} + +static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, + uint8_t p1, uint8_t p2, uint8_t p3) +{ + unsigned length = req->length; + + uint8_t* buf = (uint8_t*)req->buf + length; + buf[0] = p0; + buf[1] = p1; + buf[2] = p2; + buf[3] = p3; + req->length = length + 4; +} + +/* + * Converts MIDI commands to USB MIDI packets. + */ +static void gmidi_transmit_byte(struct usb_request* req, + struct gmidi_in_port* port, uint8_t b) +{ + uint8_t p0 = port->cable; + + if (b >= 0xf8) { + gmidi_transmit_packet(req, p0 | 0x0f, b, 0, 0); + } else if (b >= 0xf0) { + switch (b) { + case 0xf0: + port->data[0] = b; + port->state = STATE_SYSEX_1; + break; + case 0xf1: + case 0xf3: + port->data[0] = b; + port->state = STATE_1PARAM; + break; + case 0xf2: + port->data[0] = b; + port->state = STATE_2PARAM_1; + break; + case 0xf4: + case 0xf5: + port->state = STATE_UNKNOWN; + break; + case 0xf6: + gmidi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0); + port->state = STATE_UNKNOWN; + break; + case 0xf7: + switch (port->state) { + case STATE_SYSEX_0: + gmidi_transmit_packet(req, + p0 | 0x05, 0xf7, 0, 0); + break; + case STATE_SYSEX_1: + gmidi_transmit_packet(req, + p0 | 0x06, port->data[0], 0xf7, 0); + break; + case STATE_SYSEX_2: + gmidi_transmit_packet(req, + p0 | 0x07, port->data[0], + port->data[1], 0xf7); + break; + } + port->state = STATE_UNKNOWN; + break; + } + } else if (b >= 0x80) { + port->data[0] = b; + if (b >= 0xc0 && b <= 0xdf) + port->state = STATE_1PARAM; + else + port->state = STATE_2PARAM_1; + } else { /* b < 0x80 */ + switch (port->state) { + case STATE_1PARAM: + if (port->data[0] < 0xf0) { + p0 |= port->data[0] >> 4; + } else { + p0 |= 0x02; + port->state = STATE_UNKNOWN; + } + gmidi_transmit_packet(req, p0, port->data[0], b, 0); + break; + case STATE_2PARAM_1: + port->data[1] = b; + port->state = STATE_2PARAM_2; + break; + case STATE_2PARAM_2: + if (port->data[0] < 0xf0) { + p0 |= port->data[0] >> 4; + port->state = STATE_2PARAM_1; + } else { + p0 |= 0x03; + port->state = STATE_UNKNOWN; + } + gmidi_transmit_packet(req, + p0, port->data[0], port->data[1], b); + break; + case STATE_SYSEX_0: + port->data[0] = b; + port->state = STATE_SYSEX_1; + break; + case STATE_SYSEX_1: + port->data[1] = b; + port->state = STATE_SYSEX_2; + break; + case STATE_SYSEX_2: + gmidi_transmit_packet(req, + p0 | 0x04, port->data[0], port->data[1], b); + port->state = STATE_SYSEX_0; + break; + } + } +} + +static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) +{ + struct usb_ep* ep = dev->in_ep; + struct gmidi_in_port* port = &dev->in_port; + + if (!ep) { + return; + } + if (!req) { + req = alloc_ep_req(ep, buflen); + } + if (!req) { + ERROR(dev, "gmidi_transmit: alloc_ep_request failed\n"); + return; + } + req->length = 0; + req->complete = gmidi_complete; + + if (port->active) { + while (req->length + 3 < buflen) { + uint8_t b; + if (snd_rawmidi_transmit(dev->in_substream, &b, 1) + != 1) + { + port->active = 0; + break; + } + gmidi_transmit_byte(req, port, b); + } + } + if (req->length > 0) { + usb_ep_queue(ep, req, GFP_ATOMIC); + } else { + free_ep_req(ep, req); + } +} + +static void gmidi_in_tasklet(unsigned long data) +{ + struct gmidi_device* dev = (struct gmidi_device*)data; + + gmidi_transmit(dev, NULL); +} + +static int gmidi_in_open(struct snd_rawmidi_substream *substream) +{ + struct gmidi_device* dev = substream->rmidi->private_data; + + VDBG(dev, "gmidi_in_open\n"); + dev->in_substream = substream; + dev->in_port.state = STATE_UNKNOWN; + return 0; +} + +static int gmidi_in_close(struct snd_rawmidi_substream *substream) +{ + VDBG(dev, "gmidi_in_close\n"); + return 0; +} + +static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) +{ + struct gmidi_device* dev = substream->rmidi->private_data; + + VDBG(dev, "gmidi_in_trigger %d\n", up); + dev->in_port.active = up; + if (up) { + tasklet_hi_schedule(&dev->tasklet); + } +} + +static int gmidi_out_open(struct snd_rawmidi_substream *substream) +{ + struct gmidi_device* dev = substream->rmidi->private_data; + + VDBG(dev, "gmidi_out_open\n"); + dev->out_substream = substream; + return 0; +} + +static int gmidi_out_close(struct snd_rawmidi_substream *substream) +{ + VDBG(dev, "gmidi_out_close\n"); + return 0; +} + +static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up) +{ + struct gmidi_device* dev = substream->rmidi->private_data; + + VDBG(dev, "gmidi_out_trigger %d\n", up); + if (up) { + set_bit(substream->number, &dev->out_triggered); + } else { + clear_bit(substream->number, &dev->out_triggered); + } +} + +static struct snd_rawmidi_ops gmidi_in_ops = { + .open = gmidi_in_open, + .close = gmidi_in_close, + .trigger = gmidi_in_trigger, +}; + +static struct snd_rawmidi_ops gmidi_out_ops = { + .open = gmidi_out_open, + .close = gmidi_out_close, + .trigger = gmidi_out_trigger +}; + +/* register as a sound "card" */ +static int gmidi_register_card(struct gmidi_device *dev) +{ + struct snd_card *card; + struct snd_rawmidi *rmidi; + int err; + int out_ports = 1; + int in_ports = 1; + static struct snd_device_ops ops = { + .dev_free = gmidi_snd_free, + }; + + card = snd_card_new(index, id, THIS_MODULE, 0); + if (!card) { + ERROR(dev, "snd_card_new failed\n"); + err = -ENOMEM; + goto fail; + } + dev->card = card; + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, dev, &ops); + if (err < 0) { + ERROR(dev, "snd_device_new failed: error %d\n", err); + goto fail; + } + + strcpy(card->driver, longname); + strcpy(card->longname, longname); + strcpy(card->shortname, shortname); + + /* Set up rawmidi */ + dev->in_port.dev = dev; + dev->in_port.active = 0; + snd_component_add(card, "MIDI"); + err = snd_rawmidi_new(card, "USB MIDI Gadget", 0, + out_ports, in_ports, &rmidi); + if (err < 0) { + ERROR(dev, "snd_rawmidi_new failed: error %d\n", err); + goto fail; + } + dev->rmidi = rmidi; + strcpy(rmidi->name, card->shortname); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + rmidi->private_data = dev; + + /* Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT. + It's an upside-down world being a gadget. */ + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops); + + snd_card_set_dev(card, &dev->gadget->dev); + + /* register it - we're ready to go */ + err = snd_card_register(card); + if (err < 0) { + ERROR(dev, "snd_card_register failed\n"); + goto fail; + } + + VDBG(dev, "gmidi_register_card finished ok\n"); + return 0; + +fail: + if (dev->card) { + snd_card_free(dev->card); + dev->card = NULL; + } + return err; +} + +/* + * Creates an output endpoint, and initializes output ports. + */ +static int __devinit gmidi_bind(struct usb_gadget *gadget) +{ + struct gmidi_device *dev; + struct usb_ep *in_ep, *out_ep; + int gcnum, err = 0; + + /* support optional vendor/distro customization */ + if (idVendor) { + if (!idProduct) { + printk(KERN_ERR "idVendor needs idProduct!\n"); + return -ENODEV; + } + device_desc.idVendor = cpu_to_le16(idVendor); + device_desc.idProduct = cpu_to_le16(idProduct); + if (bcdDevice) { + device_desc.bcdDevice = cpu_to_le16(bcdDevice); + } + } + if (iManufacturer) { + strlcpy(manufacturer, iManufacturer, sizeof(manufacturer)); + } else { + snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", + system_utsname.sysname, system_utsname.release, + gadget->name); + } + if (iProduct) { + strlcpy(product_desc, iProduct, sizeof(product_desc)); + } + if (iSerialNumber) { + device_desc.iSerialNumber = STRING_SERIAL, + strlcpy(serial_number, iSerialNumber, sizeof(serial_number)); + } + + /* Bulk-only drivers like this one SHOULD be able to + * autoconfigure on any sane usb controller driver, + * but there may also be important quirks to address. + */ + usb_ep_autoconfig_reset(gadget); + in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc); + if (!in_ep) { +autoconf_fail: + printk(KERN_ERR "%s: can't autoconfigure on %s\n", + shortname, gadget->name); + return -ENODEV; + } + EP_IN_NAME = in_ep->name; + in_ep->driver_data = in_ep; /* claim */ + + out_ep = usb_ep_autoconfig(gadget, &bulk_out_desc); + if (!out_ep) { + goto autoconf_fail; + } + EP_OUT_NAME = out_ep->name; + out_ep->driver_data = out_ep; /* claim */ + + gcnum = usb_gadget_controller_number(gadget); + if (gcnum >= 0) { + device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); + } else { + /* gmidi is so simple (no altsettings) that + * it SHOULD NOT have problems with bulk-capable hardware. + * so warn about unrecognized controllers, don't panic. + */ + printk(KERN_WARNING "%s: controller '%s' not recognized\n", + shortname, gadget->name); + device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); + } + + + /* ok, we made sense of the hardware ... */ + dev = kzalloc(sizeof(*dev), SLAB_KERNEL); + if (!dev) { + return -ENOMEM; + } + spin_lock_init(&dev->lock); + dev->gadget = gadget; + dev->in_ep = in_ep; + dev->out_ep = out_ep; + set_gadget_data(gadget, dev); + tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev); + + /* preallocate control response and buffer */ + dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); + if (!dev->req) { + err = -ENOMEM; + goto fail; + } + dev->req->buf = usb_ep_alloc_buffer(gadget->ep0, USB_BUFSIZ, + &dev->req->dma, GFP_KERNEL); + if (!dev->req->buf) { + err = -ENOMEM; + goto fail; + } + + dev->req->complete = gmidi_setup_complete; + + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + + gadget->ep0->driver_data = dev; + + INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname); + INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, + EP_OUT_NAME, EP_IN_NAME); + + /* register as an ALSA sound card */ + err = gmidi_register_card(dev); + if (err < 0) { + goto fail; + } + + VDBG(dev, "gmidi_bind finished ok\n"); + return 0; + +fail: + gmidi_unbind(gadget); + return err; +} + + +static void gmidi_suspend(struct usb_gadget *gadget) +{ + struct gmidi_device *dev = get_gadget_data(gadget); + + if (gadget->speed == USB_SPEED_UNKNOWN) { + return; + } + + DBG(dev, "suspend\n"); +} + +static void gmidi_resume(struct usb_gadget *gadget) +{ + struct gmidi_device *dev = get_gadget_data(gadget); + + DBG(dev, "resume\n"); +} + + +static struct usb_gadget_driver gmidi_driver = { + .speed = USB_SPEED_FULL, + .function = (char *)longname, + .bind = gmidi_bind, + .unbind = __exit_p(gmidi_unbind), + + .setup = gmidi_setup, + .disconnect = gmidi_disconnect, + + .suspend = gmidi_suspend, + .resume = gmidi_resume, + + .driver = { + .name = (char *)shortname, + .owner = THIS_MODULE, + }, +}; + +static int __init gmidi_init(void) +{ + return usb_gadget_register_driver(&gmidi_driver); +} +module_init(gmidi_init); + +static void __exit gmidi_cleanup(void) +{ + usb_gadget_unregister_driver(&gmidi_driver); +} +module_exit(gmidi_cleanup); + diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h new file mode 100644 index 000000000000..6bd235994dc2 --- /dev/null +++ b/include/linux/usb/audio.h @@ -0,0 +1,53 @@ +/* + * -- USB Audio definitions. + * + * Copyright (C) 2006 Thumtronics Pty Ltd. + * Developed for Thumtronics by Grey Innovation + * Ben Williamson + * + * This software is distributed under the terms of the GNU General Public + * License ("GPL") version 2, as published by the Free Software Foundation. + * + * This file holds USB constants and structures defined + * by the USB Device Class Definition for Audio Devices. + * Comments below reference relevant sections of that document: + * + * http://www.usb.org/developers/devclass_docs/audio10.pdf + */ + +#ifndef __LINUX_USB_AUDIO_H +#define __LINUX_USB_AUDIO_H + +#include + +/* A.2 Audio Interface Subclass Codes */ +#define USB_SUBCLASS_AUDIOCONTROL 0x01 +#define USB_SUBCLASS_AUDIOSTREAMING 0x02 +#define USB_SUBCLASS_MIDISTREAMING 0x03 + +/* 4.3.2 Class-Specific AC Interface Descriptor */ +struct usb_ac_header_descriptor { + __u8 bLength; // 8+n + __u8 bDescriptorType; // USB_DT_CS_INTERFACE + __u8 bDescriptorSubtype; // USB_MS_HEADER + __le16 bcdADC; // 0x0100 + __le16 wTotalLength; // includes Unit and Terminal desc. + __u8 bInCollection; // n + __u8 baInterfaceNr[]; // [n] +} __attribute__ ((packed)); + +#define USB_DT_AC_HEADER_SIZE(n) (8+(n)) + +/* As above, but more useful for defining your own descriptors: */ +#define DECLARE_USB_AC_HEADER_DESCRIPTOR(n) \ +struct usb_ac_header_descriptor_##n { \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubtype; \ + __le16 bcdADC; \ + __le16 wTotalLength; \ + __u8 bInCollection; \ + __u8 baInterfaceNr[n]; \ +} __attribute__ ((packed)) + +#endif diff --git a/include/linux/usb/midi.h b/include/linux/usb/midi.h new file mode 100644 index 000000000000..11a97d5ffd34 --- /dev/null +++ b/include/linux/usb/midi.h @@ -0,0 +1,112 @@ +/* + * -- USB MIDI definitions. + * + * Copyright (C) 2006 Thumtronics Pty Ltd. + * Developed for Thumtronics by Grey Innovation + * Ben Williamson + * + * This software is distributed under the terms of the GNU General Public + * License ("GPL") version 2, as published by the Free Software Foundation. + * + * This file holds USB constants and structures defined + * by the USB Device Class Definition for MIDI Devices. + * Comments below reference relevant sections of that document: + * + * http://www.usb.org/developers/devclass_docs/midi10.pdf + */ + +#ifndef __LINUX_USB_MIDI_H +#define __LINUX_USB_MIDI_H + +#include + +/* A.1 MS Class-Specific Interface Descriptor Subtypes */ +#define USB_MS_HEADER 0x01 +#define USB_MS_MIDI_IN_JACK 0x02 +#define USB_MS_MIDI_OUT_JACK 0x03 +#define USB_MS_ELEMENT 0x04 + +/* A.2 MS Class-Specific Endpoint Descriptor Subtypes */ +#define USB_MS_GENERAL 0x01 + +/* A.3 MS MIDI IN and OUT Jack Types */ +#define USB_MS_EMBEDDED 0x01 +#define USB_MS_EXTERNAL 0x02 + +/* 6.1.2.1 Class-Specific MS Interface Header Descriptor */ +struct usb_ms_header_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubtype; + __le16 bcdMSC; + __le16 wTotalLength; +} __attribute__ ((packed)); + +#define USB_DT_MS_HEADER_SIZE 7 + +/* 6.1.2.2 MIDI IN Jack Descriptor */ +struct usb_midi_in_jack_descriptor { + __u8 bLength; + __u8 bDescriptorType; // USB_DT_CS_INTERFACE + __u8 bDescriptorSubtype; // USB_MS_MIDI_IN_JACK + __u8 bJackType; // USB_MS_EMBEDDED/EXTERNAL + __u8 bJackID; + __u8 iJack; +} __attribute__ ((packed)); + +#define USB_DT_MIDI_IN_SIZE 6 + +struct usb_midi_source_pin { + __u8 baSourceID; + __u8 baSourcePin; +} __attribute__ ((packed)); + +/* 6.1.2.3 MIDI OUT Jack Descriptor */ +struct usb_midi_out_jack_descriptor { + __u8 bLength; + __u8 bDescriptorType; // USB_DT_CS_INTERFACE + __u8 bDescriptorSubtype; // USB_MS_MIDI_OUT_JACK + __u8 bJackType; // USB_MS_EMBEDDED/EXTERNAL + __u8 bJackID; + __u8 bNrInputPins; // p + struct usb_midi_source_pin pins[]; // [p] + /*__u8 iJack; -- ommitted due to variable-sized pins[] */ +} __attribute__ ((packed)); + +#define USB_DT_MIDI_OUT_SIZE(p) (7 + 2 * (p)) + +/* As above, but more useful for defining your own descriptors: */ +#define DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(p) \ +struct usb_midi_out_jack_descriptor_##p { \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubtype; \ + __u8 bJackType; \ + __u8 bJackID; \ + __u8 bNrInputPins; \ + struct usb_midi_source_pin pins[p]; \ + __u8 iJack; \ +} __attribute__ ((packed)) + +/* 6.2.2 Class-Specific MS Bulk Data Endpoint Descriptor */ +struct usb_ms_endpoint_descriptor { + __u8 bLength; // 4+n + __u8 bDescriptorType; // USB_DT_CS_ENDPOINT + __u8 bDescriptorSubtype; // USB_MS_GENERAL + __u8 bNumEmbMIDIJack; // n + __u8 baAssocJackID[]; // [n] +} __attribute__ ((packed)); + +#define USB_DT_MS_ENDPOINT_SIZE(n) (4 + (n)) + +/* As above, but more useful for defining your own descriptors: */ +#define DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(n) \ +struct usb_ms_endpoint_descriptor_##n { \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubtype; \ + __u8 bNumEmbMIDIJack; \ + __u8 baAssocJackID[n]; \ +} __attribute__ ((packed)) + +#endif -- cgit v1.2.3 From 3d5b2510f6e361e2203e163c03b93d0026de5629 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 30 Jul 2006 18:43:43 +0200 Subject: USB: making the kernel -Wshadow clean - USB & completion include/linux/usb.h causes a lot of -Wshadow warnings - fix them. include/linux/usb.h:901: warning: declaration of 'complete' shadows a global declaration include/linux/completion.h:52: warning: shadowed declaration is here include/linux/usb.h:932: warning: declaration of 'complete' shadows a global declaration include/linux/completion.h:52: warning: shadowed declaration is here include/linux/usb.h:967: warning: declaration of 'complete' shadows a global declaration include/linux/completion.h:52: warning: shadowed declaration is here Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- include/linux/usb.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/usb.h b/include/linux/usb.h index e22f4b386605..3d5cfa731680 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -932,7 +932,7 @@ struct urb * @setup_packet: pointer to the setup_packet buffer * @transfer_buffer: pointer to the transfer buffer * @buffer_length: length of the transfer buffer - * @complete: pointer to the usb_complete_t function + * @complete_fn: pointer to the usb_complete_t function * @context: what to set the urb context to. * * Initializes a control urb with the proper information needed to submit @@ -944,7 +944,7 @@ static inline void usb_fill_control_urb (struct urb *urb, unsigned char *setup_packet, void *transfer_buffer, int buffer_length, - usb_complete_t complete, + usb_complete_t complete_fn, void *context) { spin_lock_init(&urb->lock); @@ -953,7 +953,7 @@ static inline void usb_fill_control_urb (struct urb *urb, urb->setup_packet = setup_packet; urb->transfer_buffer = transfer_buffer; urb->transfer_buffer_length = buffer_length; - urb->complete = complete; + urb->complete = complete_fn; urb->context = context; } @@ -964,7 +964,7 @@ static inline void usb_fill_control_urb (struct urb *urb, * @pipe: the endpoint pipe * @transfer_buffer: pointer to the transfer buffer * @buffer_length: length of the transfer buffer - * @complete: pointer to the usb_complete_t function + * @complete_fn: pointer to the usb_complete_t function * @context: what to set the urb context to. * * Initializes a bulk urb with the proper information needed to submit it @@ -975,7 +975,7 @@ static inline void usb_fill_bulk_urb (struct urb *urb, unsigned int pipe, void *transfer_buffer, int buffer_length, - usb_complete_t complete, + usb_complete_t complete_fn, void *context) { spin_lock_init(&urb->lock); @@ -983,7 +983,7 @@ static inline void usb_fill_bulk_urb (struct urb *urb, urb->pipe = pipe; urb->transfer_buffer = transfer_buffer; urb->transfer_buffer_length = buffer_length; - urb->complete = complete; + urb->complete = complete_fn; urb->context = context; } @@ -994,7 +994,7 @@ static inline void usb_fill_bulk_urb (struct urb *urb, * @pipe: the endpoint pipe * @transfer_buffer: pointer to the transfer buffer * @buffer_length: length of the transfer buffer - * @complete: pointer to the usb_complete_t function + * @complete_fn: pointer to the usb_complete_t function * @context: what to set the urb context to. * @interval: what to set the urb interval to, encoded like * the endpoint descriptor's bInterval value. @@ -1010,7 +1010,7 @@ static inline void usb_fill_int_urb (struct urb *urb, unsigned int pipe, void *transfer_buffer, int buffer_length, - usb_complete_t complete, + usb_complete_t complete_fn, void *context, int interval) { @@ -1019,7 +1019,7 @@ static inline void usb_fill_int_urb (struct urb *urb, urb->pipe = pipe; urb->transfer_buffer = transfer_buffer; urb->transfer_buffer_length = buffer_length; - urb->complete = complete; + urb->complete = complete_fn; urb->context = context; if (dev->speed == USB_SPEED_HIGH) urb->interval = 1 << (interval - 1); -- cgit v1.2.3 From b7cfaaaf86571732c7728e95a2231a860385463c Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Wed, 27 Sep 2006 11:58:53 -0700 Subject: USB: New functions to check endpoints info. These functions makes USB driver's code simpler when dealing with endpoints by avoiding them from accessing the endpoint's descriptor structure directly when they only need to know the endpoint's transfer type and/or direction. Please, read each functions' documentation in order to know how to use them. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/usb.h | 14 +++++ 2 files changed, 158 insertions(+) (limited to 'include/linux') diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 9ebfc0fe819d..82837d45b484 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -482,6 +482,138 @@ int usb_get_current_frame_number(struct usb_device *dev) return dev->bus->op->get_frame_number (dev); } +/** + * usb_endpoint_dir_in - check if the endpoint has IN direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type IN, otherwise it returns false. + */ +int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); +} + +/** + * usb_endpoint_dir_out - check if the endpoint has OUT direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type OUT, otherwise it returns false. + */ +int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); +} + +/** + * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type bulk, otherwise it returns false. + */ +int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK); +} + +/** + * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type interrupt, otherwise it returns + * false. + */ +int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT); +} + +/** + * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type isochronous, otherwise it returns + * false. + */ +int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_ISOC); +} + +/** + * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and IN direction, + * otherwise it returns false. + */ +int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and OUT direction, + * otherwise it returns false. + */ +int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd)); +} + +/** + * usb_endpoint_is_int_in - check if the endpoint is interrupt IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and IN direction, + * otherwise it returns false. + */ +int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and OUT direction, + * otherwise it returns false. + */ +int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd)); +} + +/** + * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and IN direction, + * otherwise it returns false. + */ +int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and OUT direction, + * otherwise it returns false. + */ +int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd)); +} + /*-------------------------------------------------------------------*/ /* * __usb_get_extra_descriptor() finds a descriptor of specific type in the @@ -909,6 +1041,18 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor); EXPORT_SYMBOL(usb_find_device); EXPORT_SYMBOL(usb_get_current_frame_number); +EXPORT_SYMBOL_GPL(usb_endpoint_dir_in); +EXPORT_SYMBOL_GPL(usb_endpoint_dir_out); +EXPORT_SYMBOL_GPL(usb_endpoint_xfer_bulk); +EXPORT_SYMBOL_GPL(usb_endpoint_xfer_int); +EXPORT_SYMBOL_GPL(usb_endpoint_xfer_isoc); +EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_in); +EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_out); +EXPORT_SYMBOL_GPL(usb_endpoint_is_int_in); +EXPORT_SYMBOL_GPL(usb_endpoint_is_int_out); +EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_in); +EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_out); + EXPORT_SYMBOL (usb_buffer_alloc); EXPORT_SYMBOL (usb_buffer_free); diff --git a/include/linux/usb.h b/include/linux/usb.h index 3d5cfa731680..f807479ef65b 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -467,6 +467,20 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, /*-------------------------------------------------------------------------*/ +extern int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd); +extern int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd); +extern int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd); +extern int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd); +extern int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd); +extern int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd); +extern int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd); +extern int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd); +extern int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd); +extern int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd); +extern int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd); + +/*-------------------------------------------------------------------------*/ + #define USB_DEVICE_ID_MATCH_DEVICE \ (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT) #define USB_DEVICE_ID_MATCH_DEV_RANGE \ -- cgit v1.2.3 From dfe0d3ba20e860d0b9a16c4c6524180b8f93be05 Mon Sep 17 00:00:00 2001 From: Matthew Dharm Date: Sun, 13 Aug 2006 17:30:14 -0700 Subject: USB Storage: add rio karma eject support This changeset from Keith Bennett (via Bob Copeland) moves the Karma initializer to its own file and adds trapping of the START_STOP command to enable eject of the device. Signed-off-by: Keith Bennett Signed-off-by: Bob Copeland Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/Kconfig | 12 +++ drivers/usb/storage/Makefile | 1 + drivers/usb/storage/initializers.c | 73 ----------------- drivers/usb/storage/initializers.h | 1 - drivers/usb/storage/karma.c | 155 +++++++++++++++++++++++++++++++++++++ drivers/usb/storage/karma.h | 7 ++ drivers/usb/storage/unusual_devs.h | 2 +- drivers/usb/storage/usb.c | 11 +++ include/linux/usb_usual.h | 3 + 9 files changed, 190 insertions(+), 75 deletions(-) create mode 100644 drivers/usb/storage/karma.c create mode 100644 drivers/usb/storage/karma.h (limited to 'include/linux') diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index be9eec225743..86e48c42d6af 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -135,6 +135,18 @@ config USB_STORAGE_ONETOUCH this input in any keybinding software. (e.g. gnome's keyboard short- cuts) +config USB_STORAGE_KARMA + bool "Support for Rio Karma music player" + depends on USB_STORAGE + help + Say Y here to include additional code to support the Rio Karma + USB interface. + + This code places the Rio Karma into mass storage mode, enabling + it to be mounted as an ordinary filesystem. Performing an eject + on the resulting scsi device node returns the Karma to normal + operation. + config USB_LIBUSUAL bool "The shared table of common (or usual) storage devices" depends on USB diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile index 8cbba22508a4..023969b4385b 100644 --- a/drivers/usb/storage/Makefile +++ b/drivers/usb/storage/Makefile @@ -20,6 +20,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA) += alauda.o usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o +usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ initializers.o $(usb-storage-obj-y) diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index ab173b30076e..5b06f9240d05 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -45,12 +45,6 @@ #include "debug.h" #include "transport.h" -#define RIO_MSC 0x08 -#define RIOP_INIT "RIOP\x00\x01\x08" -#define RIOP_INIT_LEN 7 -#define RIO_SEND_LEN 40 -#define RIO_RECV_LEN 0x200 - /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target * mode */ int usb_stor_euscsi_init(struct us_data *us) @@ -97,70 +91,3 @@ int usb_stor_ucr61s2b_init(struct us_data *us) return (res ? -1 : 0); } - -/* Place the Rio Karma into mass storage mode. - * - * The initialization begins by sending 40 bytes starting - * RIOP\x00\x01\x08\x00, which the device will ack with a 512-byte - * packet with the high four bits set and everything else null. - * - * Next, we send RIOP\x80\x00\x08\x00. Each time, a 512 byte response - * must be read, but we must loop until byte 5 in the response is 0x08, - * indicating success. */ -int rio_karma_init(struct us_data *us) -{ - int result, partial; - char *recv; - unsigned long timeout; - - // us->iobuf is big enough to hold cmd but not receive - if (!(recv = kmalloc(RIO_RECV_LEN, GFP_KERNEL))) - goto die_nomem; - - US_DEBUGP("Initializing Karma...\n"); - - memset(us->iobuf, 0, RIO_SEND_LEN); - memcpy(us->iobuf, RIOP_INIT, RIOP_INIT_LEN); - - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - us->iobuf, RIO_SEND_LEN, &partial); - if (result != USB_STOR_XFER_GOOD) - goto die; - - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - recv, RIO_RECV_LEN, &partial); - if (result != USB_STOR_XFER_GOOD) - goto die; - - us->iobuf[4] = 0x80; - us->iobuf[5] = 0; - timeout = jiffies + msecs_to_jiffies(3000); - for (;;) { - US_DEBUGP("Sending init command\n"); - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - us->iobuf, RIO_SEND_LEN, &partial); - if (result != USB_STOR_XFER_GOOD) - goto die; - - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - recv, RIO_RECV_LEN, &partial); - if (result != USB_STOR_XFER_GOOD) - goto die; - - if (recv[5] == RIO_MSC) - break; - if (time_after(jiffies, timeout)) - goto die; - msleep(10); - } - US_DEBUGP("Karma initialized.\n"); - kfree(recv); - return 0; - -die: - kfree(recv); -die_nomem: - US_DEBUGP("Could not initialize karma.\n"); - return USB_STOR_TRANSPORT_FAILED; -} - diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index 927f7781080f..e2967a4d48a2 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -47,4 +47,3 @@ int usb_stor_euscsi_init(struct us_data *us); /* This function is required to activate all four slots on the UCR-61S2B * flash reader */ int usb_stor_ucr61s2b_init(struct us_data *us); -int rio_karma_init(struct us_data *us); diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c new file mode 100644 index 000000000000..0d79ae5683f7 --- /dev/null +++ b/drivers/usb/storage/karma.c @@ -0,0 +1,155 @@ +/* Driver for Rio Karma + * + * (c) 2006 Bob Copeland + * (c) 2006 Keith Bennett + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include "usb.h" +#include "transport.h" +#include "debug.h" +#include "karma.h" + +#define RIO_PREFIX "RIOP\x00" +#define RIO_PREFIX_LEN 5 +#define RIO_SEND_LEN 40 +#define RIO_RECV_LEN 0x200 + +#define RIO_ENTER_STORAGE 0x1 +#define RIO_LEAVE_STORAGE 0x2 +#define RIO_RESET 0xC + +extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data *); + +struct karma_data { + int in_storage; + char *recv; +}; + +/* + * Send commands to Rio Karma. + * + * For each command we send 40 bytes starting 'RIOP\0' followed by + * the command number and a sequence number, which the device will ack + * with a 512-byte packet with the high four bits set and everything + * else null. Then we send 'RIOP\x80' followed by a zero and the + * sequence number, until byte 5 in the response repeats the sequence + * number. + */ +static int rio_karma_send_command(char cmd, struct us_data *us) +{ + int result, partial; + unsigned long timeout; + static unsigned char seq = 1; + struct karma_data *data = (struct karma_data *) us->extra; + + US_DEBUGP("karma: sending command %04x\n", cmd); + memset(us->iobuf, 0, RIO_SEND_LEN); + memcpy(us->iobuf, RIO_PREFIX, RIO_PREFIX_LEN); + us->iobuf[5] = cmd; + us->iobuf[6] = seq; + + timeout = jiffies + msecs_to_jiffies(6000); + for (;;) { + result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + us->iobuf, RIO_SEND_LEN, &partial); + if (result != USB_STOR_XFER_GOOD) + goto err; + + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data->recv, RIO_RECV_LEN, &partial); + if (result != USB_STOR_XFER_GOOD) + goto err; + + if (data->recv[5] == seq) + break; + + if (time_after(jiffies, timeout)) + goto err; + + us->iobuf[4] = 0x80; + us->iobuf[5] = 0; + msleep(50); + } + + seq++; + if (seq == 0) + seq = 1; + + US_DEBUGP("karma: sent command %04x\n", cmd); + return 0; +err: + US_DEBUGP("karma: command %04x failed\n", cmd); + return USB_STOR_TRANSPORT_FAILED; +} + +/* + * Trap START_STOP and READ_10 to leave/re-enter storage mode. + * Everything else is propagated to the normal bulk layer. + */ +int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us) +{ + int ret; + struct karma_data *data = (struct karma_data *) us->extra; + + if (srb->cmnd[0] == READ_10 && !data->in_storage) { + ret = rio_karma_send_command(RIO_ENTER_STORAGE, us); + if (ret) + return ret; + + data->in_storage = 1; + return usb_stor_Bulk_transport(srb, us); + } else if (srb->cmnd[0] == START_STOP) { + ret = rio_karma_send_command(RIO_LEAVE_STORAGE, us); + if (ret) + return ret; + + data->in_storage = 0; + return rio_karma_send_command(RIO_RESET, us); + } + return usb_stor_Bulk_transport(srb, us); +} + +static void rio_karma_destructor(void *extra) +{ + struct karma_data *data = (struct karma_data *) extra; + kfree(data->recv); +} + +int rio_karma_init(struct us_data *us) +{ + int ret = 0; + struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO); + if (!data) + goto out; + + data->recv = kmalloc(RIO_RECV_LEN, GFP_NOIO); + if (!data->recv) { + kfree(data); + goto out; + } + + us->extra = data; + us->extra_destructor = rio_karma_destructor; + ret = rio_karma_send_command(RIO_ENTER_STORAGE, us); + data->in_storage = (ret == 0); +out: + return ret; +} diff --git a/drivers/usb/storage/karma.h b/drivers/usb/storage/karma.h new file mode 100644 index 000000000000..8a60972af8c5 --- /dev/null +++ b/drivers/usb/storage/karma.h @@ -0,0 +1,7 @@ +#ifndef _KARMA_USB_H +#define _KARMA_USB_H + +extern int rio_karma_init(struct us_data *us); +extern int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us); + +#endif diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index fa49357289c4..1f11c9d44eaa 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -221,7 +221,7 @@ UNUSUAL_DEV( 0x0457, 0x0151, 0x0100, 0x0100, UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101, "Rio", "Rio Karma", - US_SC_SCSI, US_PR_BULK, rio_karma_init, 0), + US_SC_SCSI, US_PR_KARMA, rio_karma_init, 0), /* Patch submitted by Philipp Friedrich */ UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100, diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 8d7bdcb5924d..b8d6031b0975 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -98,6 +98,9 @@ #ifdef CONFIG_USB_STORAGE_ALAUDA #include "alauda.h" #endif +#ifdef CONFIG_USB_STORAGE_KARMA +#include "karma.h" +#endif /* Some informational data */ MODULE_AUTHOR("Matthew Dharm "); @@ -646,6 +649,14 @@ static int get_transport(struct us_data *us) break; #endif +#ifdef CONFIG_USB_STORAGE_KARMA + case US_PR_KARMA: + us->transport_name = "Rio Karma/Bulk"; + us->transport = rio_karma_transport; + us->transport_reset = usb_stor_Bulk_reset; + break; +#endif + default: return -EIO; } diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h index e7fc5fed5b98..2ae76fe52ff7 100644 --- a/include/linux/usb_usual.h +++ b/include/linux/usb_usual.h @@ -108,6 +108,9 @@ enum { US_DO_ALL_FLAGS }; #ifdef CONFIG_USB_STORAGE_ALAUDA #define US_PR_ALAUDA 0xf4 /* Alauda chipsets */ #endif +#ifdef CONFIG_USB_STORAGE_KARMA +#define US_PR_KARMA 0xf5 /* Rio Karma */ +#endif #define US_PR_DEVICE 0xff /* Use device's value */ -- cgit v1.2.3 From 095bc335360a51623dd8571839bbf465851a7f4b Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Sat, 26 Aug 2006 23:48:11 -0300 Subject: USB core: Use const where possible. This patch marks some USB core's functions parameters as const. This improves the design (we're saying to the caller that its parameter is not going to be modified) and may help in compiler's optimisation work. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 21 +++++++++++---------- drivers/usb/core/usb.h | 4 ++-- include/linux/usb.h | 18 +++++++++--------- 3 files changed, 22 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 82837d45b484..4eb98eb3804f 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -67,7 +67,8 @@ static int nousb; /* Disable USB when built into kernel image */ * Don't call this function unless you are bound to one of the interfaces * on this device or you have locked the device! */ -struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) +struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, + unsigned ifnum) { struct usb_host_config *config = dev->actconfig; int i; @@ -100,8 +101,8 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) * Don't call this function unless you are bound to the intf interface * or you have locked the device! */ -struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf, - unsigned int altnum) +struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf, + unsigned int altnum) { int i; @@ -356,7 +357,7 @@ void usb_put_intf(struct usb_interface *intf) * case the driver already owns the device lock.) */ int usb_lock_device_for_reset(struct usb_device *udev, - struct usb_interface *iface) + const struct usb_interface *iface) { unsigned long jiffies_expire = jiffies + HZ; @@ -852,8 +853,8 @@ void usb_buffer_unmap (struct urb *urb) * * Reverse the effect of this call with usb_buffer_unmap_sg(). */ -int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int nents) +int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int nents) { struct usb_bus *bus; struct device *controller; @@ -887,8 +888,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, * Use this when you are re-using a scatterlist's data buffers for * another USB request. */ -void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int n_hw_ents) +void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; struct device *controller; @@ -913,8 +914,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, * * Reverses the effect of usb_buffer_map_sg(). */ -void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int n_hw_ents) +void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; struct device *controller; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 6096ead2758c..67da6d0b316f 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -53,7 +53,7 @@ extern struct usb_device_driver usb_generic_driver; * no such thing as a platform USB device, so we can steal the use * of the platform_data field. */ -static inline int is_usb_device(struct device *dev) +static inline int is_usb_device(const struct device *dev) { return dev->platform_data == &usb_generic_driver; } @@ -78,7 +78,7 @@ static inline void mark_quiesced(struct usb_interface *f) f->is_active = 0; } -static inline int is_active(struct usb_interface *f) +static inline int is_active(const struct usb_interface *f) { return f->is_active; } diff --git a/include/linux/usb.h b/include/linux/usb.h index f807479ef65b..26d8a5f36896 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -387,7 +387,7 @@ extern void usb_put_dev(struct usb_device *dev); #define usb_unlock_device(udev) up(&(udev)->dev.sem) #define usb_trylock_device(udev) down_trylock(&(udev)->dev.sem) extern int usb_lock_device_for_reset(struct usb_device *udev, - struct usb_interface *iface); + const struct usb_interface *iface); /* USB port reset for device reinitialization */ extern int usb_reset_device(struct usb_device *dev); @@ -426,10 +426,10 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface, extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor); -extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, +extern struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, unsigned ifnum); extern struct usb_host_interface *usb_altnum_to_altsetting( - struct usb_interface *intf, unsigned int altnum); + const struct usb_interface *intf, unsigned int altnum); /** @@ -1064,14 +1064,14 @@ void usb_buffer_unmap (struct urb *urb); #endif struct scatterlist; -int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int nents); +int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int nents); #if 0 -void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int n_hw_ents); +void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents); #endif -void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int n_hw_ents); +void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents); /*-------------------------------------------------------------------* * SYNCHRONOUS CALL SUPPORT * -- cgit v1.2.3 From 088dc270e1da03744d977cbd9edd4311af142348 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 21 Aug 2006 12:08:19 -0400 Subject: usbcore: help drivers to change device configs It's generally a bad idea for USB interface drivers to try to change a device's configuration, and usbcore doesn't provide any way for them to do it. However in a few exceptional circumstances it can make sense. This patch (as767) adds a roundabout mechanism to help drivers that may need it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/usb.h | 3 +++ 2 files changed, 62 insertions(+) (limited to 'include/linux') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 49cfd7928a1c..333b22c68aa4 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1493,6 +1493,65 @@ free_interfaces: return 0; } +struct set_config_request { + struct usb_device *udev; + int config; + struct work_struct work; +}; + +/* Worker routine for usb_driver_set_configuration() */ +static void driver_set_config_work(void *_req) +{ + struct set_config_request *req = _req; + + usb_lock_device(req->udev); + usb_set_configuration(req->udev, req->config); + usb_unlock_device(req->udev); + usb_put_dev(req->udev); + kfree(req); +} + +/** + * usb_driver_set_configuration - Provide a way for drivers to change device configurations + * @udev: the device whose configuration is being updated + * @config: the configuration being chosen. + * Context: In process context, must be able to sleep + * + * Device interface drivers are not allowed to change device configurations. + * This is because changing configurations will destroy the interface the + * driver is bound to and create new ones; it would be like a floppy-disk + * driver telling the computer to replace the floppy-disk drive with a + * tape drive! + * + * Still, in certain specialized circumstances the need may arise. This + * routine gets around the normal restrictions by using a work thread to + * submit the change-config request. + * + * Returns 0 if the request was succesfully queued, error code otherwise. + * The caller has no way to know whether the queued request will eventually + * succeed. + */ +int usb_driver_set_configuration(struct usb_device *udev, int config) +{ + struct set_config_request *req; + + req = kmalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + req->udev = udev; + req->config = config; + INIT_WORK(&req->work, driver_set_config_work, req); + + usb_get_dev(udev); + if (!schedule_work(&req->work)) { + usb_put_dev(udev); + kfree(req); + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL_GPL(usb_driver_set_configuration); + // synchronous request completion model EXPORT_SYMBOL(usb_control_msg); EXPORT_SYMBOL(usb_bulk_msg); diff --git a/include/linux/usb.h b/include/linux/usb.h index 26d8a5f36896..f104efa04d79 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1099,6 +1099,9 @@ extern int usb_clear_halt(struct usb_device *dev, int pipe); extern int usb_reset_configuration(struct usb_device *dev); extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); +/* this request isn't really synchronous, but it belongs with the others */ +extern int usb_driver_set_configuration(struct usb_device *udev, int config); + /* * timeouts, in milliseconds, used for sending/receiving control messages * they typically complete within a few frames (msec) after they're issued -- cgit v1.2.3 From a6d2bb9ff919b4685bd684620ec7a1ffa8bf2349 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 11:27:36 -0400 Subject: USB: remove struct usb_operations All of the currently-supported USB host controller drivers use the HCD bus-glue framework. As part of the program for flattening out the glue layer, this patch (as769) removes the usb_operations structure. All function calls now go directly to the HCD routines (slightly renamed to remain within the "usb_" namespace). The patch also removes usb_alloc_bus(), because it's not useful in the HCD framework and it wasn't referenced anywhere. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 49 +++++----------------------------------------- drivers/usb/core/hcd.h | 32 +++++++----------------------- drivers/usb/core/message.c | 4 ++-- drivers/usb/core/urb.c | 13 +++++------- drivers/usb/core/usb.c | 10 +++++----- include/linux/usb.h | 4 ---- 6 files changed, 24 insertions(+), 88 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index ea20a3a5a9b9..2102c4deec1e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -731,30 +731,6 @@ static void usb_bus_init (struct usb_bus *bus) kref_init(&bus->kref); } -/** - * usb_alloc_bus - creates a new USB host controller structure - * @op: pointer to a struct usb_operations that this bus structure should use - * Context: !in_interrupt() - * - * Creates a USB host controller bus structure with the specified - * usb_operations and initializes all the necessary internal objects. - * - * If no memory is available, NULL is returned. - * - * The caller should call usb_put_bus() when it is finished with the structure. - */ -struct usb_bus *usb_alloc_bus (struct usb_operations *op) -{ - struct usb_bus *bus; - - bus = kzalloc (sizeof *bus, GFP_KERNEL); - if (!bus) - return NULL; - usb_bus_init (bus); - bus->op = op; - return bus; -} - /*-------------------------------------------------------------------------*/ /** @@ -1102,7 +1078,7 @@ static void urb_unlink (struct urb *urb) * expects usb_submit_urb() to have sanity checked and conditioned all * inputs in the urb */ -static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags) +int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; struct usb_hcd *hcd = urb->dev->bus->hcpriv; @@ -1211,7 +1187,7 @@ done: /*-------------------------------------------------------------------------*/ /* called in any context */ -static int hcd_get_frame_number (struct usb_device *udev) +int usb_hcd_get_frame_number (struct usb_device *udev) { struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; if (!HC_IS_RUNNING (hcd->state)) @@ -1253,7 +1229,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) * caller guarantees urb won't be recycled till both unlink() * and the urb's completion function return */ -static int hcd_unlink_urb (struct urb *urb, int status) +int usb_hcd_unlink_urb (struct urb *urb, int status) { struct usb_host_endpoint *ep; struct usb_hcd *hcd = NULL; @@ -1351,8 +1327,8 @@ done: * example: a qh stored in ep->hcpriv, holding state related to endpoint * type, maxpacket size, toggle, halt status, and scheduling. */ -static void -hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep) +void usb_hcd_endpoint_disable (struct usb_device *udev, + struct usb_host_endpoint *ep) { struct usb_hcd *hcd; struct urb *urb; @@ -1589,20 +1565,6 @@ EXPORT_SYMBOL (usb_bus_start_enum); /*-------------------------------------------------------------------------*/ -/* - * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue) - */ -static struct usb_operations usb_hcd_operations = { - .get_frame_number = hcd_get_frame_number, - .submit_urb = hcd_submit_urb, - .unlink_urb = hcd_unlink_urb, - .buffer_alloc = hcd_buffer_alloc, - .buffer_free = hcd_buffer_free, - .disable = hcd_endpoint_disable, -}; - -/*-------------------------------------------------------------------------*/ - /** * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB @@ -1744,7 +1706,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, dev_set_drvdata(dev, hcd); usb_bus_init(&hcd->self); - hcd->self.op = &usb_hcd_operations; hcd->self.hcpriv = hcd; hcd->self.release = &hcd_release; hcd->self.controller = dev; diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index fc71a08a1af4..83e229914797 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -139,28 +139,6 @@ struct hcd_timeout { /* timeouts we allocate */ /*-------------------------------------------------------------------------*/ -/* - * FIXME usb_operations should vanish or become hc_driver, - * when usb_bus and usb_hcd become the same thing. - */ - -struct usb_operations { - int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb *urb, gfp_t mem_flags); - int (*unlink_urb) (struct urb *urb, int status); - - /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ - void *(*buffer_alloc)(struct usb_bus *bus, size_t size, - gfp_t mem_flags, - dma_addr_t *dma); - void (*buffer_free)(struct usb_bus *bus, size_t size, - void *addr, dma_addr_t dma); - - void (*disable)(struct usb_device *udev, - struct usb_host_endpoint *ep); -}; - -/* each driver provides one of these, and hardware init support */ struct pt_regs; @@ -222,7 +200,13 @@ struct hc_driver { /* Needed only if port-change IRQs are level-triggered */ }; -extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); +extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); +extern int usb_hcd_unlink_urb (struct urb *urb, int status); +extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, + struct pt_regs *regs); +extern void usb_hcd_endpoint_disable (struct usb_device *udev, + struct usb_host_endpoint *ep); +extern int usb_hcd_get_frame_number (struct usb_device *udev); extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name); @@ -361,8 +345,6 @@ extern long usb_calc_bus_time (int speed, int is_input, /*-------------------------------------------------------------------------*/ -extern struct usb_bus *usb_alloc_bus (struct usb_operations *); - extern void usb_set_device_state(struct usb_device *udev, enum usb_device_state new_state); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 333b22c68aa4..1580c81a0db7 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -984,8 +984,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) ep = dev->ep_in[epnum]; dev->ep_in[epnum] = NULL; } - if (ep && dev->bus && dev->bus->op && dev->bus->op->disable) - dev->bus->op->disable(dev, ep); + if (ep && dev->bus) + usb_hcd_endpoint_disable(dev, ep); } /** diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 9864988377c7..576919927f53 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -221,7 +221,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { int pipe, temp, max; struct usb_device *dev; - struct usb_operations *op; int is_out; if (!urb || urb->hcpriv || !urb->complete) @@ -233,8 +232,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (dev->bus->controller->power.power_state.event != PM_EVENT_ON || dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; - if (!(op = dev->bus->op) || !op->submit_urb) - return -ENODEV; urb->status = -EINPROGRESS; urb->actual_length = 0; @@ -376,7 +373,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) urb->interval = temp; } - return op->submit_urb (urb, mem_flags); + return usb_hcd_submit_urb (urb, mem_flags); } /*-------------------------------------------------------------------*/ @@ -440,9 +437,9 @@ int usb_unlink_urb(struct urb *urb) { if (!urb) return -EINVAL; - if (!(urb->dev && urb->dev->bus && urb->dev->bus->op)) + if (!(urb->dev && urb->dev->bus)) return -ENODEV; - return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET); + return usb_hcd_unlink_urb(urb, -ECONNRESET); } /** @@ -468,13 +465,13 @@ int usb_unlink_urb(struct urb *urb) void usb_kill_urb(struct urb *urb) { might_sleep(); - if (!(urb && urb->dev && urb->dev->bus && urb->dev->bus->op)) + if (!(urb && urb->dev && urb->dev->bus)) return; spin_lock_irq(&urb->lock); ++urb->reject; spin_unlock_irq(&urb->lock); - urb->dev->bus->op->unlink_urb(urb, -ENOENT); + usb_hcd_unlink_urb(urb, -ENOENT); wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); spin_lock_irq(&urb->lock); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4eb98eb3804f..7ab9d29215f8 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -480,7 +480,7 @@ exit: */ int usb_get_current_frame_number(struct usb_device *dev) { - return dev->bus->op->get_frame_number (dev); + return usb_hcd_get_frame_number (dev); } /** @@ -677,9 +677,9 @@ void *usb_buffer_alloc ( dma_addr_t *dma ) { - if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc) + if (!dev || !dev->bus) return NULL; - return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma); + return hcd_buffer_alloc (dev->bus, size, mem_flags, dma); } /** @@ -700,11 +700,11 @@ void usb_buffer_free ( dma_addr_t dma ) { - if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free) + if (!dev || !dev->bus) return; if (!addr) return; - dev->bus->op->buffer_free (dev->bus, size, addr, dma); + hcd_buffer_free (dev->bus, size, addr, dma); } /** diff --git a/include/linux/usb.h b/include/linux/usb.h index f104efa04d79..4709033f8fa7 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -257,8 +257,6 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, /* ----------------------------------------------------------------------- */ -struct usb_operations; - /* USB device number allocation bitmap */ struct usb_devmap { unsigned long devicemap[128 / (8*sizeof(unsigned long))]; @@ -279,7 +277,6 @@ struct usb_bus { * round-robin allocation */ struct usb_devmap devmap; /* device address allocation map */ - struct usb_operations *op; /* Operations (specific to the HC) */ struct usb_device *root_hub; /* Root hub */ struct list_head bus_list; /* list of busses */ void *hcpriv; /* Host Controller private data */ @@ -1051,7 +1048,6 @@ extern int usb_submit_urb(struct urb *urb, gfp_t mem_flags); extern int usb_unlink_urb(struct urb *urb); extern void usb_kill_urb(struct urb *urb); -#define HAVE_USB_BUFFERS void *usb_buffer_alloc (struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); void usb_buffer_free (struct usb_device *dev, size_t size, -- cgit v1.2.3 From dd990f16a39d4e615c0b70a0ab50b79b32bfb16d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 11:29:56 -0400 Subject: usbcore: Add flag for whether a host controller uses DMA This patch (as770b) introduces a new field to usb_bus: a flag indicating whether or not the host controller uses DMA. This serves to encapsulate the computation. It also means we will have only one spot to update if the DMA API changes. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 8 +++++--- include/linux/usb.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 2102c4deec1e..0cc14206920a 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1152,7 +1152,7 @@ doit: /* lower level hcd code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (hcd->self.controller->dma_mask) { + if (hcd->self.uses_dma) { if (usb_pipecontrol (urb->pipe) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( @@ -1585,8 +1585,9 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs at_root_hub = (urb->dev == hcd->self.root_hub); urb_unlink (urb); - /* lower level hcd code should use *_dma exclusively */ - if (hcd->self.controller->dma_mask && !at_root_hub) { + /* lower level hcd code should use *_dma exclusively if the + * host controller does DMA */ + if (hcd->self.uses_dma && !at_root_hub) { if (usb_pipecontrol (urb->pipe) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) dma_unmap_single (hcd->self.controller, urb->setup_dma, @@ -1710,6 +1711,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, hcd->self.release = &hcd_release; hcd->self.controller = dev; hcd->self.bus_name = bus_name; + hcd->self.uses_dma = (dev->dma_mask != NULL); init_timer(&hcd->rh_timer); hcd->rh_timer.function = rh_timer_func; diff --git a/include/linux/usb.h b/include/linux/usb.h index 4709033f8fa7..09661759621f 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -269,6 +269,7 @@ struct usb_bus { struct device *controller; /* host/master side hardware */ int busnum; /* Bus number (in order of reg) */ char *bus_name; /* stable id (PCI slot_name etc) */ + u8 uses_dma; /* Does the host controller use DMA? */ u8 otg_port; /* 0, or number of OTG/HNP port */ unsigned is_b_host:1; /* true during some HNP roleswitches */ unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */ -- cgit v1.2.3 From 1720058343fa43a1a25bfad9e62ea06e7e9743b6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 11:32:52 -0400 Subject: usbcore: trim down usb_bus structure As part of the ongoing program to flatten out the HCD bus-glue layer, this patch (as771b) eliminates the hcpriv, release, and kref fields from struct usb_bus. hcpriv and release were not being used for anything worthwhile, and kref has been moved into the enclosing usb_hcd structure. Along with those changes, the patch gets rid of usb_bus_get and usb_bus_put, replacing them with usb_get_hcd and usb_put_hcd. The one interesting aspect is that the dev_set_drvdata call was removed from usb_put_hcd, where it clearly doesn't belong. This means the driver private data won't get reset to NULL. It shouldn't cause any problems, since the private data is undefined when no driver is bound. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/buffer.c | 4 +-- drivers/usb/core/hcd.c | 67 +++++++++++++++--------------------------- drivers/usb/core/hcd.h | 13 ++++---- drivers/usb/core/usb.c | 5 ++-- drivers/usb/gadget/dummy_hcd.c | 8 ++--- drivers/usb/host/ehci-dbg.c | 6 ++-- drivers/usb/host/ohci-dbg.c | 6 ++-- drivers/usb/mon/mon_main.c | 6 ++-- include/linux/usb.h | 3 -- 9 files changed, 44 insertions(+), 74 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index f4f4ef0f377a..840442a25b61 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -104,7 +104,7 @@ void *hcd_buffer_alloc ( dma_addr_t *dma ) { - struct usb_hcd *hcd = bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(bus); int i; /* some USB hosts just use PIO */ @@ -127,7 +127,7 @@ void hcd_buffer_free ( dma_addr_t dma ) { - struct usb_hcd *hcd = bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(bus); int i; if (!addr) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 0cc14206920a..9dfc812de034 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -664,31 +664,6 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) /*-------------------------------------------------------------------------*/ -/* exported only within usbcore */ -struct usb_bus *usb_bus_get(struct usb_bus *bus) -{ - if (bus) - kref_get(&bus->kref); - return bus; -} - -static void usb_host_release(struct kref *kref) -{ - struct usb_bus *bus = container_of(kref, struct usb_bus, kref); - - if (bus->release) - bus->release(bus); -} - -/* exported only within usbcore */ -void usb_bus_put(struct usb_bus *bus) -{ - if (bus) - kref_put(&bus->kref, usb_host_release); -} - -/*-------------------------------------------------------------------------*/ - static struct class *usb_host_class; int usb_host_init(void) @@ -720,15 +695,12 @@ static void usb_bus_init (struct usb_bus *bus) bus->devnum_next = 1; bus->root_hub = NULL; - bus->hcpriv = NULL; bus->busnum = -1; bus->bandwidth_allocated = 0; bus->bandwidth_int_reqs = 0; bus->bandwidth_isoc_reqs = 0; INIT_LIST_HEAD (&bus->bus_list); - - kref_init(&bus->kref); } /*-------------------------------------------------------------------------*/ @@ -1081,7 +1053,7 @@ static void urb_unlink (struct urb *urb) int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; - struct usb_hcd *hcd = urb->dev->bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); struct usb_host_endpoint *ep; unsigned long flags; @@ -1189,7 +1161,8 @@ done: /* called in any context */ int usb_hcd_get_frame_number (struct usb_device *udev) { - struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + if (!HC_IS_RUNNING (hcd->state)) return -ESHUTDOWN; return hcd->driver->get_frame_number (hcd); @@ -1262,7 +1235,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) spin_lock (&hcd_data_lock); sys = &urb->dev->dev; - hcd = urb->dev->bus->hcpriv; + hcd = bus_to_hcd(urb->dev->bus); if (hcd == NULL) { retval = -ENODEV; goto done; @@ -1333,7 +1306,7 @@ void usb_hcd_endpoint_disable (struct usb_device *udev, struct usb_hcd *hcd; struct urb *urb; - hcd = udev->bus->hcpriv; + hcd = bus_to_hcd(udev->bus); WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT && udev->state != USB_STATE_NOTATTACHED); @@ -1673,14 +1646,6 @@ EXPORT_SYMBOL_GPL (usb_hc_died); /*-------------------------------------------------------------------------*/ -static void hcd_release (struct usb_bus *bus) -{ - struct usb_hcd *hcd; - - hcd = container_of(bus, struct usb_hcd, self); - kfree(hcd); -} - /** * usb_create_hcd - create and initialize an HCD structure * @driver: HC driver that will use this hcd @@ -1705,10 +1670,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, return NULL; } dev_set_drvdata(dev, hcd); + kref_init(&hcd->kref); usb_bus_init(&hcd->self); - hcd->self.hcpriv = hcd; - hcd->self.release = &hcd_release; hcd->self.controller = dev; hcd->self.bus_name = bus_name; hcd->self.uses_dma = (dev->dma_mask != NULL); @@ -1725,10 +1689,25 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, } EXPORT_SYMBOL (usb_create_hcd); +static void hcd_release (struct kref *kref) +{ + struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); + + kfree(hcd); +} + +struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd) +{ + if (hcd) + kref_get (&hcd->kref); + return hcd; +} +EXPORT_SYMBOL (usb_get_hcd); + void usb_put_hcd (struct usb_hcd *hcd) { - dev_set_drvdata(hcd->self.controller, NULL); - usb_bus_put(&hcd->self); + if (hcd) + kref_put (&hcd->kref, hcd_release); } EXPORT_SYMBOL (usb_put_hcd); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 83e229914797..7a2bcba2ae61 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -55,12 +55,13 @@ /*-------------------------------------------------------------------------*/ -struct usb_hcd { /* usb_bus.hcpriv points to this */ +struct usb_hcd { /* * housekeeping */ struct usb_bus self; /* hcd is-a bus */ + struct kref kref; /* reference counter */ const char *product_desc; /* product/vendor string */ char irq_descr[24]; /* driver + bus # */ @@ -129,8 +130,10 @@ static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd) return &hcd->self; } - -// urb.hcpriv is really hardware-specific +static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus) +{ + return container_of(bus, struct usb_hcd, self); +} struct hcd_timeout { /* timeouts we allocate */ struct list_head timeout_list; @@ -210,6 +213,7 @@ extern int usb_hcd_get_frame_number (struct usb_device *udev); extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name); +extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd); extern void usb_put_hcd (struct usb_hcd *hcd); extern int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags); @@ -356,9 +360,6 @@ extern struct list_head usb_bus_list; extern struct mutex usb_bus_list_lock; extern wait_queue_head_t usb_kill_urb_queue; -extern struct usb_bus *usb_bus_get (struct usb_bus *bus); -extern void usb_bus_put (struct usb_bus *bus); - extern void usb_enable_root_hub_irq (struct usb_bus *bus); extern int usb_find_interface_driver (struct usb_device *dev, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7ab9d29215f8..b0c0a993338f 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -169,7 +169,7 @@ static void usb_release_dev(struct device *dev) udev = to_usb_device(dev); usb_destroy_configuration(udev); - usb_bus_put(udev->bus); + usb_put_hcd(bus_to_hcd(udev->bus)); kfree(udev->product); kfree(udev->manufacturer); kfree(udev->serial); @@ -197,8 +197,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) if (!dev) return NULL; - bus = usb_bus_get(bus); - if (!bus) { + if (!usb_get_hcd(bus_to_hcd(bus))) { kfree(dev); return NULL; } diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 7d1c22c34957..fdab97a27c08 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -889,11 +889,9 @@ EXPORT_SYMBOL (net2280_set_fifo_mode); static void dummy_gadget_release (struct device *dev) { -#if 0 /* usb_bus_put isn't EXPORTed! */ struct dummy *dum = gadget_dev_to_dummy (dev); - usb_bus_put (&dummy_to_hcd (dum)->self); -#endif + usb_put_hcd (dummy_to_hcd (dum)); } static int dummy_udc_probe (struct platform_device *pdev) @@ -915,9 +913,7 @@ static int dummy_udc_probe (struct platform_device *pdev) if (rc < 0) return rc; -#if 0 /* usb_bus_get isn't EXPORTed! */ - usb_bus_get (&dummy_to_hcd (dum)->self); -#endif + usb_get_hcd (dummy_to_hcd (dum)); platform_set_drvdata (pdev, dum); device_create_file (&dum->gadget.dev, &dev_attr_function); diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 65ac9fef3a7c..215ce6d06394 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -451,7 +451,7 @@ show_async (struct class_device *class_dev, char *buf) *buf = 0; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ehci = hcd_to_ehci (hcd); next = buf; size = PAGE_SIZE; @@ -497,7 +497,7 @@ show_periodic (struct class_device *class_dev, char *buf) seen_count = 0; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ehci = hcd_to_ehci (hcd); next = buf; size = PAGE_SIZE; @@ -634,7 +634,7 @@ show_registers (struct class_device *class_dev, char *buf) static char label [] = ""; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ehci = hcd_to_ehci (hcd); next = buf; size = PAGE_SIZE; diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index da52609a9290..534d07dcb824 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -477,7 +477,7 @@ show_async (struct class_device *class_dev, char *buf) unsigned long flags; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); /* display control and bulk lists together, for simplicity */ @@ -510,7 +510,7 @@ show_periodic (struct class_device *class_dev, char *buf) seen_count = 0; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); next = buf; size = PAGE_SIZE; @@ -607,7 +607,7 @@ show_registers (struct class_device *class_dev, char *buf) u32 rdata; bus = class_get_devdata(class_dev); - hcd = bus->hcpriv; + hcd = bus_to_hcd(bus); ohci = hcd_to_ohci(hcd); regs = ohci->regs; next = buf; diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 275a66f83058..e0ed36cdfd8b 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -265,7 +265,6 @@ static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus) ubus->mon_bus = NULL; mbus->u_bus = NULL; mb(); - // usb_bus_put(ubus); } /* @@ -297,10 +296,9 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus) INIT_LIST_HEAD(&mbus->r_list); /* - * This usb_bus_get here is superfluous, because we receive - * a notification if usb_bus is about to be removed. + * We don't need to take a reference to ubus, because we receive + * a notification if the bus is about to be removed. */ - // usb_bus_get(ubus); mbus->u_bus = ubus; ubus->mon_bus = mbus; diff --git a/include/linux/usb.h b/include/linux/usb.h index 09661759621f..c66303285a45 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -280,7 +280,6 @@ struct usb_bus { struct usb_devmap devmap; /* device address allocation map */ struct usb_device *root_hub; /* Root hub */ struct list_head bus_list; /* list of busses */ - void *hcpriv; /* Host Controller private data */ int bandwidth_allocated; /* on this bus: how much of the time * reserved for periodic (intr/iso) @@ -295,8 +294,6 @@ struct usb_bus { struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ struct class_device *class_dev; /* class device for this bus */ - struct kref kref; /* reference counting for this bus */ - void (*release)(struct usb_bus *bus); #if defined(CONFIG_USB_MON) struct mon_bus *mon_bus; /* non-null when associated */ -- cgit v1.2.3 From b6956ffa595db97656d5901ca8fec77ef272d41a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 15:46:48 -0400 Subject: usbcore: store each usb_device's level in the tree This patch (as778) adds a field to struct usb_device to store the device's level in the USB tree. In itself this number isn't really important. But the overhead is very low, and in a later patch it will be used for preventing bogus warnings from the lockdep checker. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 1 + include/linux/usb.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include/linux') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f5adce049b35..78e910b2046c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2414,6 +2414,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, usb_set_device_state(udev, USB_STATE_POWERED); udev->speed = USB_SPEED_UNKNOWN; udev->bus_mA = hub->mA_per_port; + udev->level = hdev->level + 1; /* set the address */ choose_address(udev); diff --git a/include/linux/usb.h b/include/linux/usb.h index c66303285a45..df5c93eb3ce9 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -348,6 +348,7 @@ struct usb_device { unsigned short bus_mA; /* Current available from the bus */ u8 portnum; /* Parent port number (origin 1) */ + u8 level; /* Number of USB hub ancestors */ int have_langid; /* whether string_langid is valid */ int string_langid; /* language ID for strings */ -- cgit v1.2.3 From 645daaab0b6adc35c1838df2a82f9d729fdb1767 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 15:47:02 -0400 Subject: usbcore: add autosuspend/autoresume infrastructure This patch (as739) adds the basic infrastructure for USB autosuspend and autoresume. The main features are: PM usage counters added to struct usb_device and struct usb_interface, indicating whether it's okay to autosuspend them or they are currently in use. Flag added to usb_device indicating whether the current suspend/resume operation originated from outside or as an autosuspend/autoresume. Flag added to usb_driver indicating whether the driver supports autosuspend. If not, no device bound to the driver will be autosuspended. Mutex added to usb_device for protecting PM operations. Unlike the device semaphore, the locking rule for the pm_mutex is that you must acquire the locks going _up_ the device tree. New routines handling autosuspend/autoresume requests for interfaces and devices. Suspend and resume requests are propagated up the device tree (but not outside the USB subsystem). work_struct added to usb_device, for carrying out delayed autosuspend requests. Autoresume added (and autosuspend prevented) during probe and disconnect. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 419 ++++++++++++++++++++++++++++++++++++++++++---- drivers/usb/core/hub.c | 49 ++++-- drivers/usb/core/usb.c | 23 +++ drivers/usb/core/usb.h | 14 ++ include/linux/usb.h | 33 ++++ 5 files changed, 493 insertions(+), 45 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index a5d11461f5a9..2b2000ac05ab 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -157,12 +157,13 @@ static int usb_probe_device(struct device *dev) udev = to_usb_device(dev); - /* FIXME: resume a suspended device */ - if (udev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; - /* TODO: Add real matching code */ + /* The device should always appear to be in use + * unless the driver suports autosuspend. + */ + udev->pm_usage_cnt = !(udriver->supports_autosuspend); + error = udriver->probe(udev); return error; } @@ -182,6 +183,7 @@ static int usb_probe_interface(struct device *dev) { struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf; + struct usb_device *udev; const struct usb_device_id *id; int error = -ENODEV; @@ -191,10 +193,7 @@ static int usb_probe_interface(struct device *dev) return error; intf = to_usb_interface(dev); - - /* FIXME we'd much prefer to just resume it ... */ - if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; + udev = interface_to_usbdev(intf); id = usb_match_id(intf, driver->id_table); if (!id) @@ -202,18 +201,31 @@ static int usb_probe_interface(struct device *dev) if (id) { dev_dbg(dev, "%s - got id\n", __FUNCTION__); + error = usb_autoresume_device(udev, 1); + if (error) + return error; + /* Interface "power state" doesn't correspond to any hardware * state whatsoever. We use it to record when it's bound to * a driver that may start I/0: it's not frozen/quiesced. */ mark_active(intf); intf->condition = USB_INTERFACE_BINDING; + + /* The interface should always appear to be in use + * unless the driver suports autosuspend. + */ + intf->pm_usage_cnt = !(driver->supports_autosuspend); + error = driver->probe(intf, id); if (error) { mark_quiesced(intf); + intf->needs_remote_wakeup = 0; intf->condition = USB_INTERFACE_UNBOUND; } else intf->condition = USB_INTERFACE_BOUND; + + usb_autosuspend_device(udev, 1); } return error; @@ -224,9 +236,15 @@ static int usb_unbind_interface(struct device *dev) { struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev; + int error; intf->condition = USB_INTERFACE_UNBINDING; + /* Autoresume for set_interface call below */ + udev = interface_to_usbdev(intf); + error = usb_autoresume_device(udev, 1); + /* release all urbs for this interface */ usb_disable_interface(interface_to_usbdev(intf), intf); @@ -237,8 +255,13 @@ static int usb_unbind_interface(struct device *dev) intf->altsetting[0].desc.bInterfaceNumber, 0); usb_set_intfdata(intf, NULL); + intf->condition = USB_INTERFACE_UNBOUND; mark_quiesced(intf); + intf->needs_remote_wakeup = 0; + + if (!error) + usb_autosuspend_device(udev, 1); return 0; } @@ -267,14 +290,19 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv) { struct device *dev = &iface->dev; + struct usb_device *udev = interface_to_usbdev(iface); if (dev->driver) return -EBUSY; dev->driver = &driver->drvwrap.driver; usb_set_intfdata(iface, priv); + + mutex_lock_nested(&udev->pm_mutex, udev->level); iface->condition = USB_INTERFACE_BOUND; mark_active(iface); + iface->pm_usage_cnt = !(driver->supports_autosuspend); + mutex_unlock(&udev->pm_mutex); /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() @@ -304,6 +332,7 @@ void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface) { struct device *dev = &iface->dev; + struct usb_device *udev = interface_to_usbdev(iface); /* this should never happen, don't release something that's not ours */ if (!dev->driver || dev->driver != &driver->drvwrap.driver) @@ -321,8 +350,12 @@ void usb_driver_release_interface(struct usb_driver *driver, dev->driver = NULL; usb_set_intfdata(iface, NULL); + + mutex_lock_nested(&udev->pm_mutex, udev->level); iface->condition = USB_INTERFACE_UNBOUND; mark_quiesced(iface); + iface->needs_remote_wakeup = 0; + mutex_unlock(&udev->pm_mutex); } EXPORT_SYMBOL(usb_driver_release_interface); @@ -751,7 +784,7 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); #ifdef CONFIG_PM -/* Caller has locked udev */ +/* Caller has locked udev->pm_mutex */ static int suspend_device(struct usb_device *udev, pm_message_t msg) { struct usb_device_driver *udriver; @@ -763,6 +796,7 @@ static int suspend_device(struct usb_device *udev, pm_message_t msg) /* For devices that don't have a driver, we do a standard suspend. */ if (udev->dev.driver == NULL) { + udev->do_remote_wakeup = 0; status = usb_port_suspend(udev); goto done; } @@ -771,12 +805,13 @@ static int suspend_device(struct usb_device *udev, pm_message_t msg) status = udriver->suspend(udev, msg); done: + // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); if (status == 0) udev->dev.power.power_state.event = msg.event; return status; } -/* Caller has locked udev */ +/* Caller has locked udev->pm_mutex */ static int resume_device(struct usb_device *udev) { struct usb_device_driver *udriver; @@ -796,12 +831,13 @@ static int resume_device(struct usb_device *udev) status = udriver->resume(udev); done: + // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); if (status == 0) udev->dev.power.power_state.event = PM_EVENT_ON; return status; } -/* Caller has locked intf's usb_device */ +/* Caller has locked intf's usb_device's pm_mutex */ static int suspend_interface(struct usb_interface *intf, pm_message_t msg) { struct usb_driver *driver; @@ -812,31 +848,33 @@ static int suspend_interface(struct usb_interface *intf, pm_message_t msg) !is_active(intf)) goto done; - if (intf->dev.driver == NULL) /* This can't happen */ + if (intf->condition == USB_INTERFACE_UNBOUND) /* This can't happen */ goto done; driver = to_usb_driver(intf->dev.driver); if (driver->suspend && driver->resume) { status = driver->suspend(intf, msg); - if (status) + if (status == 0) + mark_quiesced(intf); + else if (!interface_to_usbdev(intf)->auto_pm) dev_err(&intf->dev, "%s error %d\n", "suspend", status); - else - mark_quiesced(intf); } else { // FIXME else if there's no suspend method, disconnect... + // Not possible if auto_pm is set... dev_warn(&intf->dev, "no suspend for driver %s?\n", driver->name); mark_quiesced(intf); } done: + // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); if (status == 0) intf->dev.power.power_state.event = msg.event; return status; } -/* Caller has locked intf's usb_device */ +/* Caller has locked intf's usb_device's pm_mutex */ static int resume_interface(struct usb_interface *intf) { struct usb_driver *driver; @@ -846,8 +884,12 @@ static int resume_interface(struct usb_interface *intf) is_active(intf)) goto done; + /* Don't let autoresume interfere with unbinding */ + if (intf->condition == USB_INTERFACE_UNBINDING) + goto done; + /* Can't resume it if it doesn't have a driver. */ - if (intf->dev.driver == NULL) { + if (intf->condition == USB_INTERFACE_UNBOUND) { status = -ENOTCONN; goto done; } @@ -867,18 +909,88 @@ static int resume_interface(struct usb_interface *intf) } done: + // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); if (status == 0) intf->dev.power.power_state.event = PM_EVENT_ON; return status; } -/* Caller has locked udev */ +/** + * usb_suspend_both - suspend a USB device and its interfaces + * @udev: the usb_device to suspend + * @msg: Power Management message describing this state transition + * + * This is the central routine for suspending USB devices. It calls the + * suspend methods for all the interface drivers in @udev and then calls + * the suspend method for @udev itself. If an error occurs at any stage, + * all the interfaces which were suspended are resumed so that they remain + * in the same state as the device. + * + * If an autosuspend is in progress (@udev->auto_pm is set), the routine + * checks first to make sure that neither the device itself or any of its + * active interfaces is in use (pm_usage_cnt is greater than 0). If they + * are, the autosuspend fails. + * + * If the suspend succeeds, the routine recursively queues an autosuspend + * request for @udev's parent device, thereby propagating the change up + * the device tree. If all of the parent's children are now suspended, + * the parent will autosuspend in turn. + * + * The suspend method calls are subject to mutual exclusion under control + * of @udev's pm_mutex. Many of these calls are also under the protection + * of @udev's device lock (including all requests originating outside the + * USB subsystem), but autosuspend requests generated by a child device or + * interface driver may not be. Usbcore will insure that the method calls + * do not arrive during bind, unbind, or reset operations. However, drivers + * must be prepared to handle suspend calls arriving at unpredictable times. + * The only way to block such calls is to do an autoresume (preventing + * autosuspends) while holding @udev's device lock (preventing outside + * suspends). + * + * The caller must hold @udev->pm_mutex. + * + * This routine can run only in process context. + */ int usb_suspend_both(struct usb_device *udev, pm_message_t msg) { int status = 0; int i = 0; struct usb_interface *intf; + struct usb_device *parent = udev->parent; + + cancel_delayed_work(&udev->autosuspend); + if (udev->state == USB_STATE_NOTATTACHED) + return 0; + if (udev->state == USB_STATE_SUSPENDED) + return 0; + udev->do_remote_wakeup = device_may_wakeup(&udev->dev); + + /* For autosuspend, fail fast if anything is in use. + * Also fail if any interfaces require remote wakeup but it + * isn't available. */ + if (udev->auto_pm) { + if (udev->pm_usage_cnt > 0) + return -EBUSY; + if (udev->actconfig) { + for (; i < udev->actconfig->desc.bNumInterfaces; i++) { + intf = udev->actconfig->interface[i]; + if (!is_active(intf)) + continue; + if (intf->pm_usage_cnt > 0) + return -EBUSY; + if (intf->needs_remote_wakeup && + !udev->do_remote_wakeup) { + dev_dbg(&udev->dev, + "remote wakeup needed for autosuspend\n"); + return -EOPNOTSUPP; + } + } + i = 0; + } + } + + /* Suspend all the interfaces and then udev itself */ if (udev->actconfig) { for (; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; @@ -896,40 +1008,282 @@ int usb_suspend_both(struct usb_device *udev, pm_message_t msg) intf = udev->actconfig->interface[i]; resume_interface(intf); } - } + + /* If the suspend succeeded, propagate it up the tree */ + } else if (parent) + usb_autosuspend_device(parent, 0); + + // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); return status; } -/* Caller has locked udev */ +/** + * usb_resume_both - resume a USB device and its interfaces + * @udev: the usb_device to resume + * + * This is the central routine for resuming USB devices. It calls the + * the resume method for @udev and then calls the resume methods for all + * the interface drivers in @udev. + * + * Before starting the resume, the routine calls itself recursively for + * the parent device of @udev, thereby propagating the change up the device + * tree and assuring that @udev will be able to resume. If the parent is + * unable to resume successfully, the routine fails. + * + * The resume method calls are subject to mutual exclusion under control + * of @udev's pm_mutex. Many of these calls are also under the protection + * of @udev's device lock (including all requests originating outside the + * USB subsystem), but autoresume requests generated by a child device or + * interface driver may not be. Usbcore will insure that the method calls + * do not arrive during bind, unbind, or reset operations. However, drivers + * must be prepared to handle resume calls arriving at unpredictable times. + * The only way to block such calls is to do an autoresume (preventing + * other autoresumes) while holding @udev's device lock (preventing outside + * resumes). + * + * The caller must hold @udev->pm_mutex. + * + * This routine can run only in process context. + */ int usb_resume_both(struct usb_device *udev) { - int status; + int status = 0; int i; struct usb_interface *intf; + struct usb_device *parent = udev->parent; + + cancel_delayed_work(&udev->autosuspend); + if (udev->state == USB_STATE_NOTATTACHED) + return -ENODEV; - /* Can't resume if the parent is suspended */ - if (udev->parent && udev->parent->state == USB_STATE_SUSPENDED) { - dev_warn(&udev->dev, "can't resume; parent is suspended\n"); - return -EHOSTUNREACH; + /* Propagate the resume up the tree, if necessary */ + if (udev->state == USB_STATE_SUSPENDED) { + if (parent) { + mutex_lock_nested(&parent->pm_mutex, parent->level); + parent->auto_pm = 1; + status = usb_resume_both(parent); + } else { + + /* We can't progagate beyond the USB subsystem, + * so if a root hub's controller is suspended + * then we're stuck. */ + if (udev->dev.parent->power.power_state.event != + PM_EVENT_ON) + status = -EHOSTUNREACH; + } + if (status == 0 && udev->state == USB_STATE_SUSPENDED) + status = resume_device(udev); + if (parent) + mutex_unlock(&parent->pm_mutex); } - status = resume_device(udev); + /* Now the parent won't suspend until we are finished */ + if (status == 0 && udev->actconfig) { for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; resume_interface(intf); } } + + // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); + return status; +} + +#ifdef CONFIG_USB_SUSPEND + +/** + * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces + * @udev - the usb_device to autosuspend + * @dec_usage_cnt - flag to decrement @udev's PM-usage counter + * + * This routine should be called when a core subsystem is finished using + * @udev and wants to allow it to autosuspend. Examples would be when + * @udev's device file in usbfs is closed or after a configuration change. + * + * @dec_usage_cnt should be 1 if the subsystem previously incremented + * @udev's usage counter (such as by passing 1 to usb_autoresume_device); + * otherwise it should be 0. + * + * If the usage counter for @udev or any of its active interfaces is greater + * than 0, the autosuspend request will not be queued. (If an interface + * driver does not support autosuspend then its usage counter is permanently + * positive.) Likewise, if an interface driver requires remote-wakeup + * capability during autosuspend but remote wakeup is disabled, the + * autosuspend will fail. + * + * Often the caller will hold @udev's device lock, but this is not + * necessary. + * + * This routine can run only in process context. + */ +void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt) +{ + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->pm_usage_cnt -= dec_usage_cnt; + if (udev->pm_usage_cnt <= 0) + schedule_delayed_work(&udev->autosuspend, + USB_AUTOSUSPEND_DELAY); + mutex_unlock(&udev->pm_mutex); + // dev_dbg(&udev->dev, "%s: cnt %d\n", + // __FUNCTION__, udev->pm_usage_cnt); +} + +/** + * usb_autoresume_device - immediately autoresume a USB device and its interfaces + * @udev - the usb_device to autoresume + * @inc_usage_cnt - flag to increment @udev's PM-usage counter + * + * This routine should be called when a core subsystem wants to use @udev + * and needs to guarantee that it is not suspended. In addition, the + * caller can prevent @udev from being autosuspended subsequently. (Note + * that this will not prevent suspend events originating in the PM core.) + * Examples would be when @udev's device file in usbfs is opened (autosuspend + * should be prevented until the file is closed) or when a remote-wakeup + * request is received (later autosuspends should not be prevented). + * + * @inc_usage_cnt should be 1 to increment @udev's usage counter and prevent + * autosuspends. This prevention will persist until the usage counter is + * decremented again (such as by passing 1 to usb_autosuspend_device). + * Otherwise @inc_usage_cnt should be 0 to leave the usage counter unchanged. + * Regardless, if the autoresume fails then the usage counter is not + * incremented. + * + * Often the caller will hold @udev's device lock, but this is not + * necessary (and attempting it might cause deadlock). + * + * This routine can run only in process context. + */ +int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt) +{ + int status; + + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->pm_usage_cnt += inc_usage_cnt; + udev->auto_pm = 1; + status = usb_resume_both(udev); + if (status != 0) + udev->pm_usage_cnt -= inc_usage_cnt; + mutex_unlock(&udev->pm_mutex); + // dev_dbg(&udev->dev, "%s: status %d cnt %d\n", + // __FUNCTION__, status, udev->pm_usage_cnt); + return status; +} + +/** + * usb_autopm_put_interface - decrement a USB interface's PM-usage counter + * @intf - the usb_interface whose counter should be decremented + * + * This routine should be called by an interface driver when it is + * finished using @intf and wants to allow it to autosuspend. A typical + * example would be a character-device driver when its device file is + * closed. + * + * The routine decrements @intf's usage counter. When the counter reaches + * 0, a delayed autosuspend request for @intf's device is queued. When + * the delay expires, if @intf->pm_usage_cnt is still <= 0 along with all + * the other usage counters for the sibling interfaces and @intf's + * usb_device, the device and all its interfaces will be autosuspended. + * + * Note that @intf->pm_usage_cnt is owned by the interface driver. The + * core will not change its value other than the increment and decrement + * in usb_autopm_get_interface and usb_autopm_put_interface. The driver + * may use this simple counter-oriented discipline or may set the value + * any way it likes. + * + * If the driver has set @intf->needs_remote_wakeup then autosuspend will + * take place only if the device's remote-wakeup facility is enabled. + * + * Suspend method calls queued by this routine can arrive at any time + * while @intf is resumed and its usage counter is equal to 0. They are + * not protected by the usb_device's lock but only by its pm_mutex. + * Drivers must provide their own synchronization. + * + * This routine can run only in process context. + */ +void usb_autopm_put_interface(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + + mutex_lock_nested(&udev->pm_mutex, udev->level); + if (intf->condition != USB_INTERFACE_UNBOUND) { + if (--intf->pm_usage_cnt <= 0) + schedule_delayed_work(&udev->autosuspend, + USB_AUTOSUSPEND_DELAY); + } + mutex_unlock(&udev->pm_mutex); + // dev_dbg(&intf->dev, "%s: cnt %d\n", + // __FUNCTION__, intf->pm_usage_cnt); +} +EXPORT_SYMBOL_GPL(usb_autopm_put_interface); + +/** + * usb_autopm_get_interface - increment a USB interface's PM-usage counter + * @intf - the usb_interface whose counter should be incremented + * + * This routine should be called by an interface driver when it wants to + * use @intf and needs to guarantee that it is not suspended. In addition, + * the routine prevents @intf from being autosuspended subsequently. (Note + * that this will not prevent suspend events originating in the PM core.) + * This prevention will persist until usb_autopm_put_interface() is called + * or @intf is unbound. A typical example would be a character-device + * driver when its device file is opened. + * + * The routine increments @intf's usage counter. So long as the counter + * is greater than 0, autosuspend will not be allowed for @intf or its + * usb_device. When the driver is finished using @intf it should call + * usb_autopm_put_interface() to decrement the usage counter and queue + * a delayed autosuspend request (if the counter is <= 0). + * + * Note that @intf->pm_usage_cnt is owned by the interface driver. The + * core will not change its value other than the increment and decrement + * in usb_autopm_get_interface and usb_autopm_put_interface. The driver + * may use this simple counter-oriented discipline or may set the value + * any way it likes. + * + * Resume method calls generated by this routine can arrive at any time + * while @intf is suspended. They are not protected by the usb_device's + * lock but only by its pm_mutex. Drivers must provide their own + * synchronization. + * + * This routine can run only in process context. + */ +int usb_autopm_get_interface(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + int status; + + mutex_lock_nested(&udev->pm_mutex, udev->level); + if (intf->condition == USB_INTERFACE_UNBOUND) + status = -ENODEV; + else { + ++intf->pm_usage_cnt; + udev->auto_pm = 1; + status = usb_resume_both(udev); + if (status != 0) + --intf->pm_usage_cnt; + } + mutex_unlock(&udev->pm_mutex); + // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", + // __FUNCTION__, status, intf->pm_usage_cnt); return status; } +EXPORT_SYMBOL_GPL(usb_autopm_get_interface); + +#endif /* CONFIG_USB_SUSPEND */ static int usb_suspend(struct device *dev, pm_message_t message) { int status; - if (is_usb_device(dev)) - status = usb_suspend_both(to_usb_device(dev), message); - else + if (is_usb_device(dev)) { + struct usb_device *udev = to_usb_device(dev); + + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->auto_pm = 0; + status = usb_suspend_both(udev, message); + mutex_unlock(&udev->pm_mutex); + } else status = 0; return status; } @@ -939,7 +1293,12 @@ static int usb_resume(struct device *dev) int status; if (is_usb_device(dev)) { - status = usb_resume_both(to_usb_device(dev)); + struct usb_device *udev = to_usb_device(dev); + + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->auto_pm = 0; + status = usb_resume_both(udev); + mutex_unlock(&udev->pm_mutex); /* Rebind drivers that had no suspend method? */ } else diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 78e910b2046c..dee812bc6c43 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1017,19 +1017,22 @@ void usb_set_device_state(struct usb_device *udev, if (udev->state == USB_STATE_NOTATTACHED) ; /* do nothing */ else if (new_state != USB_STATE_NOTATTACHED) { - udev->state = new_state; /* root hub wakeup capabilities are managed out-of-band * and may involve silicon errata ... ignore them here. */ if (udev->parent) { - if (new_state == USB_STATE_CONFIGURED) + if (udev->state == USB_STATE_SUSPENDED + || new_state == USB_STATE_SUSPENDED) + ; /* No change to wakeup settings */ + else if (new_state == USB_STATE_CONFIGURED) device_init_wakeup(&udev->dev, (udev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_WAKEUP)); - else if (new_state != USB_STATE_SUSPENDED) + else device_init_wakeup(&udev->dev, 0); } + udev->state = new_state; } else recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); @@ -1507,7 +1510,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, * NOTE: OTG devices may issue remote wakeup (or SRP) even when * we don't explicitly enable it here. */ - if (device_may_wakeup(&udev->dev)) { + if (udev->do_remote_wakeup) { status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, USB_DEVICE_REMOTE_WAKEUP, 0, @@ -1533,7 +1536,8 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, USB_CTRL_SET_TIMEOUT); } else { /* device has up to 10 msec to fully suspend */ - dev_dbg(&udev->dev, "usb suspend\n"); + dev_dbg(&udev->dev, "usb %ssuspend\n", + udev->auto_pm ? "auto-" : ""); usb_set_device_state(udev, USB_STATE_SUSPENDED); msleep(10); } @@ -1573,7 +1577,8 @@ static int __usb_port_suspend (struct usb_device *udev, int port1) status = hub_port_suspend(hdev_to_hub(udev->parent), port1, udev); else { - dev_dbg(&udev->dev, "usb suspend\n"); + dev_dbg(&udev->dev, "usb %ssuspend\n", + udev->auto_pm ? "auto-" : ""); usb_set_device_state(udev, USB_STATE_SUSPENDED); } return status; @@ -1687,7 +1692,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) /* drive resume for at least 20 msec */ if (udev) - dev_dbg(&udev->dev, "RESUME\n"); + dev_dbg(&udev->dev, "usb %sresume\n", + udev->auto_pm ? "auto-" : ""); msleep(25); #define LIVE_FLAGS ( USB_PORT_STAT_POWER \ @@ -1754,8 +1760,11 @@ int usb_port_resume(struct usb_device *udev) // NOTE this fails if parent is also suspended... status = hub_port_resume(hdev_to_hub(udev->parent), udev->portnum, udev); - } else + } else { + dev_dbg(&udev->dev, "usb %sresume\n", + udev->auto_pm ? "auto-" : ""); status = finish_port_resume(udev); + } if (status < 0) dev_dbg(&udev->dev, "can't resume, status %d\n", status); return status; @@ -1765,19 +1774,23 @@ static int remote_wakeup(struct usb_device *udev) { int status = 0; - /* don't repeat RESUME sequence if this device - * was already woken up by some other task - */ + /* All this just to avoid sending a port-resume message + * to the parent hub! */ + usb_lock_device(udev); + mutex_lock_nested(&udev->pm_mutex, udev->level); if (udev->state == USB_STATE_SUSPENDED) { - dev_dbg(&udev->dev, "RESUME (wakeup)\n"); + dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); /* TRSMRCY = 10 msec */ msleep(10); status = finish_port_resume(udev); + if (status == 0) + udev->dev.power.power_state.event = PM_EVENT_ON; } + mutex_unlock(&udev->pm_mutex); if (status == 0) - usb_resume_both(udev); + usb_autoresume_device(udev, 0); usb_unlock_device(udev); return status; } @@ -1834,7 +1847,9 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) == PM_EVENT_ON #endif ) { - dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); + if (!hdev->auto_pm) + dev_dbg(&intf->dev, "port %d nyet suspended\n", + port1); return -EBUSY; } } @@ -2587,7 +2602,7 @@ static void hub_events(void) * stub "device" node was never suspended. */ if (i) - usb_resume_both(hdev); + usb_autoresume_device(hdev, 0); /* If this is an inactive or suspended hub, do nothing */ if (hub->quiescing) @@ -2993,6 +3008,9 @@ int usb_reset_composite_device(struct usb_device *udev, return -EINVAL; } + /* Prevent autosuspend during the reset */ + usb_autoresume_device(udev, 1); + if (iface && iface->condition != USB_INTERFACE_BINDING) iface = NULL; @@ -3034,6 +3052,7 @@ int usb_reset_composite_device(struct usb_device *udev, } } + usb_autosuspend_device(udev, 1); return ret; } EXPORT_SYMBOL(usb_reset_composite_device); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index b0c0a993338f..6b029cdb8671 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -168,6 +168,10 @@ static void usb_release_dev(struct device *dev) udev = to_usb_device(dev); +#ifdef CONFIG_PM + cancel_delayed_work(&udev->autosuspend); + flush_scheduled_work(); +#endif usb_destroy_configuration(udev); usb_put_hcd(bus_to_hcd(udev->bus)); kfree(udev->product); @@ -176,6 +180,21 @@ static void usb_release_dev(struct device *dev) kfree(udev); } +#ifdef CONFIG_PM + +/* usb_autosuspend_work - callback routine to autosuspend a USB device */ +static void usb_autosuspend_work(void *_udev) +{ + struct usb_device *udev = _udev; + + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->auto_pm = 1; + usb_suspend_both(udev, PMSG_SUSPEND); + mutex_unlock(&udev->pm_mutex); +} + +#endif + /** * usb_alloc_dev - usb device constructor (usbcore-internal) * @parent: hub to which device is connected; null to allocate a root hub @@ -251,6 +270,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->parent = parent; INIT_LIST_HEAD(&dev->filelist); +#ifdef CONFIG_PM + mutex_init(&dev->pm_mutex); + INIT_WORK(&dev->autosuspend, usb_autosuspend_work, dev); +#endif return dev; } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 5162cb370215..10688ad73c6d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -49,6 +49,20 @@ static inline int usb_resume_both(struct usb_device *udev) #endif +#ifdef CONFIG_USB_SUSPEND + +#define USB_AUTOSUSPEND_DELAY (HZ*2) + +extern void usb_autosuspend_device(struct usb_device *udev, int dec_busy_cnt); +extern int usb_autoresume_device(struct usb_device *udev, int inc_busy_cnt); + +#else + +#define usb_autosuspend_device(udev, dec_busy_cnt) do {} while (0) +#define usb_autoresume_device(udev, inc_busy_cnt) 0 + +#endif + extern struct bus_type usb_bus_type; extern struct usb_device_driver usb_generic_driver; diff --git a/include/linux/usb.h b/include/linux/usb.h index df5c93eb3ce9..0da15b0b02be 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -19,6 +19,7 @@ #include /* for struct file_operations */ #include /* for struct completion */ #include /* for current && schedule_timeout */ +#include /* for struct mutex */ struct usb_device; struct usb_driver; @@ -103,8 +104,12 @@ enum usb_interface_condition { * @condition: binding state of the interface: not bound, binding * (in probe()), bound to a driver, or unbinding (in disconnect()) * @is_active: flag set when the interface is bound and not suspended. + * @needs_remote_wakeup: flag set when the driver requires remote-wakeup + * capability during autosuspend. * @dev: driver model's view of this device * @class_dev: driver model's class view of this device. + * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not + * allowed unless the counter is 0. * * USB device drivers attach to interfaces on a physical device. Each * interface encapsulates a single high level function, such as feeding @@ -144,9 +149,11 @@ struct usb_interface { * bound to */ enum usb_interface_condition condition; /* state of binding */ unsigned is_active:1; /* the interface is not suspended */ + unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ struct device dev; /* interface specific device info */ struct class_device *class_dev; + int pm_usage_cnt; /* usage counter for autosuspend */ }; #define to_usb_interface(d) container_of(d, struct usb_interface, dev) #define interface_to_usbdev(intf) \ @@ -372,6 +379,15 @@ struct usb_device { int maxchild; /* Number of ports if hub */ struct usb_device *children[USB_MAXCHILDREN]; + +#ifdef CONFIG_PM + struct work_struct autosuspend; /* for delayed autosuspends */ + struct mutex pm_mutex; /* protects PM operations */ + int pm_usage_cnt; /* usage counter for autosuspend */ + + unsigned auto_pm:1; /* autosuspend/resume in progress */ + unsigned do_remote_wakeup:1; /* remote wakeup should be enabled */ +#endif }; #define to_usb_device(d) container_of(d, struct usb_device, dev) @@ -392,6 +408,17 @@ extern int usb_reset_composite_device(struct usb_device *dev, extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); +/* USB autosuspend and autoresume */ +#ifdef CONFIG_USB_SUSPEND +extern int usb_autopm_get_interface(struct usb_interface *intf); +extern void usb_autopm_put_interface(struct usb_interface *intf); + +#else +#define usb_autopm_get_interface(intf) 0 +#define usb_autopm_put_interface(intf) do {} while (0) +#endif + + /*-------------------------------------------------------------------------*/ /* for drivers using iso endpoints */ @@ -593,6 +620,8 @@ struct usbdrv_wrap { * @drvwrap: Driver-model core structure wrapper. * @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be * added to this driver by preventing the sysfs file from being created. + * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend + * for interfaces bound to this driver. * * USB interface drivers must provide a name, probe() and disconnect() * methods, and an id_table. Other driver fields are optional. @@ -631,6 +660,7 @@ struct usb_driver { struct usb_dynids dynids; struct usbdrv_wrap drvwrap; unsigned int no_dynamic_id:1; + unsigned int supports_autosuspend:1; }; #define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver) @@ -648,6 +678,8 @@ struct usb_driver { * @suspend: Called when the device is going to be suspended by the system. * @resume: Called when the device is being resumed by the system. * @drvwrap: Driver-model core structure wrapper. + * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend + * for devices bound to this driver. * * USB drivers must provide all the fields listed above except drvwrap. */ @@ -660,6 +692,7 @@ struct usb_device_driver { int (*suspend) (struct usb_device *udev, pm_message_t message); int (*resume) (struct usb_device *udev); struct usbdrv_wrap drvwrap; + unsigned int supports_autosuspend:1; }; #define to_usb_device_driver(d) container_of(d, struct usb_device_driver, \ drvwrap.driver) -- cgit v1.2.3 From 54bb3a94b192be09feb85993b664ff118d6433d0 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 27 Sep 2006 22:20:11 -0400 Subject: [libata] Use new PCI_VDEVICE() macro to dramatically shorten ID lists Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 90 ++++++++++++++++------------------------------ drivers/ata/pdc_adma.c | 3 +- drivers/ata/sata_nv.c | 50 ++++++++++---------------- drivers/ata/sata_promise.c | 55 ++++++++++------------------ drivers/ata/sata_sil.c | 15 ++++---- drivers/ata/sata_sil24.c | 11 +++--- drivers/ata/sata_sis.c | 6 ++-- drivers/ata/sata_sx4.c | 4 +-- drivers/ata/sata_uli.c | 7 ++-- include/linux/libata.h | 4 +++ 10 files changed, 95 insertions(+), 150 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 1aabc81d82f1..54e1f38ce301 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -299,76 +299,46 @@ static const struct ata_port_info ahci_port_info[] = { static const struct pci_device_id ahci_pci_tbl[] = { /* Intel */ - { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH6 */ - { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH6M */ - { PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH7 */ - { PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH7M */ - { PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH7R */ - { PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ULi M5288 */ - { PCI_VENDOR_ID_INTEL, 0x2681, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ESB2 */ - { PCI_VENDOR_ID_INTEL, 0x2682, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ESB2 */ - { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ESB2 */ - { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH7-M DH */ - { PCI_VENDOR_ID_INTEL, 0x2821, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH8 */ - { PCI_VENDOR_ID_INTEL, 0x2822, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH8 */ - { PCI_VENDOR_ID_INTEL, 0x2824, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH8 */ - { PCI_VENDOR_ID_INTEL, 0x2829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH8M */ - { PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */ + { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */ + { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */ + { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */ + { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */ + { PCI_VDEVICE(AL, 0x5288), board_ahci }, /* ULi M5288 */ + { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */ + { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ + { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ + { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ + { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ /* JMicron */ - { 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* JMicron JMB360 */ - { 0x197b, 0x2361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* JMicron JMB361 */ - { 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* JMicron JMB363 */ - { 0x197b, 0x2365, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* JMicron JMB365 */ - { 0x197b, 0x2366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* JMicron JMB366 */ + { PCI_VDEVICE(JMICRON, 0x2360), board_ahci }, /* JMicron JMB360 */ + { PCI_VDEVICE(JMICRON, 0x2361), board_ahci }, /* JMicron JMB361 */ + { PCI_VDEVICE(JMICRON, 0x2363), board_ahci }, /* JMicron JMB363 */ + { PCI_VDEVICE(JMICRON, 0x2365), board_ahci }, /* JMicron JMB365 */ + { PCI_VDEVICE(JMICRON, 0x2366), board_ahci }, /* JMicron JMB366 */ /* ATI */ - { PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ATI SB600 non-raid */ - { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* ATI SB600 raid */ + { PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */ + { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */ /* VIA */ - { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci_vt8251 }, /* VIA VT8251 */ + { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ /* NVIDIA */ - { PCI_VENDOR_ID_NVIDIA, 0x044c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* MCP65 */ - { PCI_VENDOR_ID_NVIDIA, 0x044d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* MCP65 */ - { PCI_VENDOR_ID_NVIDIA, 0x044e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* MCP65 */ - { PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */ /* SiS */ - { PCI_VENDOR_ID_SI, 0x1184, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* SiS 966 */ - { PCI_VENDOR_ID_SI, 0x1185, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* SiS 966 */ - { PCI_VENDOR_ID_SI, 0x0186, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, /* SiS 968 */ + { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ + { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ + { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ { } /* terminate list */ }; diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 0e23ecb77bc2..81f3d219e70e 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -192,8 +192,7 @@ static struct ata_port_info adma_port_info[] = { }; static const struct pci_device_id adma_ata_pci_tbl[] = { - { PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_1841_idx }, + { PCI_VDEVICE(PDC, 0x1841), board_1841_idx }, { } /* terminate list */ }; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 8cd730fe5dd3..bbf29595a008 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -106,38 +106,24 @@ enum nv_host_type }; static const struct pci_device_id nv_pci_tbl[] = { - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, - { PCI_VENDOR_ID_NVIDIA, 0x045c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, - { PCI_VENDOR_ID_NVIDIA, 0x045d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, - { PCI_VENDOR_ID_NVIDIA, 0x045e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, - { PCI_VENDOR_ID_NVIDIA, 0x045f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), NFORCE2 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), NFORCE3 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), NFORCE3 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA), CK804 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC }, + { PCI_VDEVICE(NVIDIA, 0x045c), GENERIC }, + { PCI_VDEVICE(NVIDIA, 0x045d), GENERIC }, + { PCI_VDEVICE(NVIDIA, 0x045e), GENERIC }, + { PCI_VDEVICE(NVIDIA, 0x045f), GENERIC }, { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC }, diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index d627812ea73d..15c9437710fc 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -234,48 +234,31 @@ static const struct ata_port_info pdc_port_info[] = { }; static const struct pci_device_id pdc_ata_pci_tbl[] = { - { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, - { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, - { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, - { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, - { PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, - { PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, - { PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2057x }, - { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2057x }, - { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_2037x }, - - { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_20319 }, - { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_20319 }, - { PCI_VENDOR_ID_PROMISE, 0x3515, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_20319 }, - { PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_20319 }, - { PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_20319 }, - { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_40518 }, - - { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_20619 }, + { PCI_VDEVICE(PROMISE, 0x3371), board_2037x }, + { PCI_VDEVICE(PROMISE, 0x3570), board_2037x }, + { PCI_VDEVICE(PROMISE, 0x3571), board_2037x }, + { PCI_VDEVICE(PROMISE, 0x3373), board_2037x }, + { PCI_VDEVICE(PROMISE, 0x3375), board_2037x }, + { PCI_VDEVICE(PROMISE, 0x3376), board_2037x }, + { PCI_VDEVICE(PROMISE, 0x3574), board_2057x }, + { PCI_VDEVICE(PROMISE, 0x3d75), board_2057x }, + { PCI_VDEVICE(PROMISE, 0x3d73), board_2037x }, + + { PCI_VDEVICE(PROMISE, 0x3318), board_20319 }, + { PCI_VDEVICE(PROMISE, 0x3319), board_20319 }, + { PCI_VDEVICE(PROMISE, 0x3515), board_20319 }, + { PCI_VDEVICE(PROMISE, 0x3519), board_20319 }, + { PCI_VDEVICE(PROMISE, 0x3d17), board_20319 }, + { PCI_VDEVICE(PROMISE, 0x3d18), board_40518 }, + + { PCI_VDEVICE(PROMISE, 0x6629), board_20619 }, /* TODO: remove all associated board_20771 code, as it completely * duplicates board_2037x code, unless reason for separation can be * divined. */ #if 0 - { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_20771 }, + { PCI_VDEVICE(PROMISE, 0x3570), board_20771 }, #endif { } /* terminate list */ diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index c63dbabc0cd9..3d9fa1cc834d 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -123,13 +123,14 @@ static void sil_thaw(struct ata_port *ap); static const struct pci_device_id sil_pci_tbl[] = { - { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, - { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, - { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 }, - { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 }, - { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, - { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq }, - { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq }, + { PCI_VDEVICE(CMD, 0x3112), sil_3112 }, + { PCI_VDEVICE(CMD, 0x0240), sil_3112 }, + { PCI_VDEVICE(CMD, 0x3512), sil_3512 }, + { PCI_VDEVICE(CMD, 0x3114), sil_3114 }, + { PCI_VDEVICE(ATI, 0x436e), sil_3112 }, + { PCI_VDEVICE(ATI, 0x4379), sil_3112_no_sata_irq }, + { PCI_VDEVICE(ATI, 0x437a), sil_3112_no_sata_irq }, + { } /* terminate list */ }; diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 39cb07baebae..a951f40c2f21 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -344,11 +344,12 @@ static int sil24_pci_device_resume(struct pci_dev *pdev); #endif static const struct pci_device_id sil24_pci_tbl[] = { - { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, - { 0x8086, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, - { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 }, - { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 }, - { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 }, + { PCI_VDEVICE(CMD, 0x3124), BID_SIL3124 }, + { PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 }, + { PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 }, + { PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 }, + { PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 }, + { } /* terminate list */ }; diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 18d49fff8dc4..8e8dc3f22152 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -67,9 +67,9 @@ static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg); static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static const struct pci_device_id sis_pci_tbl[] = { - { PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, - { PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, - { PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, + { PCI_VDEVICE(SI, 0x180), sis_180 }, + { PCI_VDEVICE(SI, 0x181), sis_180 }, + { PCI_VDEVICE(SI, 0x182), sis_180 }, { } /* terminate list */ }; diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 091867e10ea3..2b3d44bf495f 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -230,8 +230,8 @@ static const struct ata_port_info pdc_port_info[] = { }; static const struct pci_device_id pdc_sata_pci_tbl[] = { - { PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_20621 }, + { PCI_VDEVICE(PROMISE, 0x6622), board_20621 }, + { } /* terminate list */ }; diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index dd76f37be182..c2e6b7e59f05 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -61,9 +61,10 @@ static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg); static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static const struct pci_device_id uli_pci_tbl[] = { - { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 }, - { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 }, - { PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 }, + { PCI_VDEVICE(AL, 0x5289), uli_5289 }, + { PCI_VDEVICE(AL, 0x5287), uli_5287 }, + { PCI_VDEVICE(AL, 0x5281), uli_5281 }, + { } /* terminate list */ }; diff --git a/include/linux/libata.h b/include/linux/libata.h index d6a3d4b345fc..df44b09fbae8 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -109,6 +109,10 @@ static inline u32 ata_msg_init(int dval, int default_msg_enable_bits) #define ATA_TAG_POISON 0xfafbfcfdU /* move to PCI layer? */ +#define PCI_VDEVICE(vendor, device) \ + PCI_VENDOR_ID_##vendor, (device), \ + PCI_ANY_ID, PCI_ANY_ID, 0, 0 + static inline struct device *pci_dev_to_dev(struct pci_dev *pdev) { return &pdev->dev; -- cgit v1.2.3 From 29fa06c1292f473ae51a84f55c8fe22179bc1080 Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Mon, 28 Aug 2006 14:40:17 +0200 Subject: hwmon: New driver k8temp Add support for the temperature sensor(s) found in AMD K8 CPUs. Signed-off-by: Rudolf Marek Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/k8temp.c | 292 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 1 + 4 files changed, 304 insertions(+) create mode 100644 drivers/hwmon/k8temp.c (limited to 'include/linux') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 78c237f8fa0a..d9f86e9d405b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -94,6 +94,16 @@ config SENSORS_ADM9240 This driver can also be built as a module. If so, the module will be called adm9240. +config SENSORS_K8TEMP + tristate "AMD K8 processor sensor" + depends on HWMON && X86 && PCI && EXPERIMENTAL + help + If you say yes here you get support for the temperature + sensor(s) inside your AMD K8 CPU. + + This driver can also be built as a module. If so, the module + will be called k8temp. + config SENSORS_ASB100 tristate "Asus ASB100 Bach" depends on HWMON && I2C && EXPERIMENTAL diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 31415843a91a..aab4c1063059 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o obj-$(CONFIG_SENSORS_IT87) += it87.o +obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o obj-$(CONFIG_SENSORS_LM63) += lm63.o obj-$(CONFIG_SENSORS_LM70) += lm70.o obj-$(CONFIG_SENSORS_LM75) += lm75.o diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c new file mode 100644 index 000000000000..50162ffa8832 --- /dev/null +++ b/drivers/hwmon/k8temp.c @@ -0,0 +1,292 @@ +/* + * k8temp.c - Linux kernel module for hardware monitoring + * + * Copyright (C) 2006 Rudolf Marek + * + * Inspired from the w83785 and amd756 drivers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000) +#define REG_TEMP 0xe4 +#define SEL_PLACE 0x40 +#define SEL_CORE 0x04 + +struct k8temp_data { + struct class_device *class_dev; + struct mutex update_lock; + const char *name; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */ + u32 temp[2][2]; /* core, place */ +}; + +static struct k8temp_data *k8temp_update_device(struct device *dev) +{ + struct k8temp_data *data = dev_get_drvdata(dev); + struct pci_dev *pdev = to_pci_dev(dev); + u8 tmp; + + mutex_lock(&data->update_lock); + + if (!data->valid + || time_after(jiffies, data->last_updated + HZ)) { + pci_read_config_byte(pdev, REG_TEMP, &tmp); + tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ + pci_write_config_byte(pdev, REG_TEMP, tmp); + pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]); + + if (data->sensorsp & SEL_PLACE) { + tmp |= SEL_PLACE; /* Select sensor 1, core0 */ + pci_write_config_byte(pdev, REG_TEMP, tmp); + pci_read_config_dword(pdev, REG_TEMP, + &data->temp[0][1]); + } + + if (data->sensorsp & SEL_CORE) { + tmp &= ~SEL_PLACE; /* Select sensor 0, core1 */ + tmp |= SEL_CORE; + pci_write_config_byte(pdev, REG_TEMP, tmp); + pci_read_config_dword(pdev, REG_TEMP, + &data->temp[1][0]); + + if (data->sensorsp & SEL_PLACE) { + tmp |= SEL_PLACE; /* Select sensor 1, core1 */ + pci_write_config_byte(pdev, REG_TEMP, tmp); + pci_read_config_dword(pdev, REG_TEMP, + &data->temp[1][1]); + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + return data; +} + +/* + * Sysfs stuff + */ + +static ssize_t show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct k8temp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->name); +} + + +static ssize_t show_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute_2 *attr = + to_sensor_dev_attr_2(devattr); + int core = attr->nr; + int place = attr->index; + struct k8temp_data *data = k8temp_update_device(dev); + + return sprintf(buf, "%d\n", + TEMP_FROM_REG(data->temp[core][place])); +} + +/* core, place */ + +static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1); +static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0); +static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1); +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + +static struct pci_device_id k8temp_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, + { 0 }, +}; + +static int __devinit k8temp_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int err; + u8 scfg; + u32 temp; + struct k8temp_data *data; + u32 cpuid = cpuid_eax(1); + + /* this feature should be available since SH-C0 core */ + if ((cpuid == 0xf40) || (cpuid == 0xf50) || (cpuid == 0xf51)) { + err = -ENODEV; + goto exit; + } + + if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + pci_read_config_byte(pdev, REG_TEMP, &scfg); + scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ + pci_write_config_byte(pdev, REG_TEMP, scfg); + pci_read_config_byte(pdev, REG_TEMP, &scfg); + + if (scfg & (SEL_PLACE | SEL_CORE)) { + dev_err(&pdev->dev, "Configuration bit(s) stuck at 1!\n"); + err = -ENODEV; + goto exit_free; + } + + scfg |= (SEL_PLACE | SEL_CORE); + pci_write_config_byte(pdev, REG_TEMP, scfg); + + /* now we know if we can change core and/or sensor */ + pci_read_config_byte(pdev, REG_TEMP, &data->sensorsp); + + if (data->sensorsp & SEL_PLACE) { + scfg &= ~SEL_CORE; /* Select sensor 1, core0 */ + pci_write_config_byte(pdev, REG_TEMP, scfg); + pci_read_config_dword(pdev, REG_TEMP, &temp); + scfg |= SEL_CORE; /* prepare for next selection */ + if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */ + data->sensorsp &= ~SEL_PLACE; + } + + if (data->sensorsp & SEL_CORE) { + scfg &= ~SEL_PLACE; /* Select sensor 0, core1 */ + pci_write_config_byte(pdev, REG_TEMP, scfg); + pci_read_config_dword(pdev, REG_TEMP, &temp); + if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */ + data->sensorsp &= ~SEL_CORE; + } + + data->name = "k8temp"; + mutex_init(&data->update_lock); + dev_set_drvdata(&pdev->dev, data); + + /* Register sysfs hooks */ + err = device_create_file(&pdev->dev, + &sensor_dev_attr_temp1_input.dev_attr); + if (err) + goto exit_remove; + + /* sensor can be changed and reports something */ + if (data->sensorsp & SEL_PLACE) { + err = device_create_file(&pdev->dev, + &sensor_dev_attr_temp2_input.dev_attr); + if (err) + goto exit_remove; + } + + /* core can be changed and reports something */ + if (data->sensorsp & SEL_CORE) { + err = device_create_file(&pdev->dev, + &sensor_dev_attr_temp3_input.dev_attr); + if (err) + goto exit_remove; + if (data->sensorsp & SEL_PLACE) + err = device_create_file(&pdev->dev, + &sensor_dev_attr_temp4_input. + dev_attr); + if (err) + goto exit_remove; + } + + err = device_create_file(&pdev->dev, &dev_attr_name); + if (err) + goto exit_remove; + + data->class_dev = hwmon_device_register(&pdev->dev); + + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp3_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp4_input.dev_attr); + device_remove_file(&pdev->dev, &dev_attr_name); +exit_free: + dev_set_drvdata(&pdev->dev, NULL); + kfree(data); +exit: + return err; +} + +static void __devexit k8temp_remove(struct pci_dev *pdev) +{ + struct k8temp_data *data = dev_get_drvdata(&pdev->dev); + + hwmon_device_unregister(data->class_dev); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp3_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp4_input.dev_attr); + device_remove_file(&pdev->dev, &dev_attr_name); + dev_set_drvdata(&pdev->dev, NULL); + kfree(data); +} + +static struct pci_driver k8temp_driver = { + .name = "k8temp", + .id_table = k8temp_ids, + .probe = k8temp_probe, + .remove = __devexit_p(k8temp_remove), +}; + +static int __init k8temp_init(void) +{ + return pci_register_driver(&k8temp_driver); +} + +static void __exit k8temp_exit(void) +{ + pci_unregister_driver(&k8temp_driver); +} + +MODULE_AUTHOR("Rudolf Marek "); +MODULE_DESCRIPTION("AMD K8 core temperature monitor"); +MODULE_LICENSE("GPL"); + +module_init(k8temp_init) +module_exit(k8temp_exit) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ab032ceafa84..61db1907f06f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -479,6 +479,7 @@ #define PCI_VENDOR_ID_AMD 0x1022 #define PCI_DEVICE_ID_AMD_K8_NB 0x1100 +#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103 #define PCI_DEVICE_ID_AMD_LANCE 0x2000 #define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 #define PCI_DEVICE_ID_AMD_SCSI 0x2020 -- cgit v1.2.3 From e0318ebff4d96131bb3524308b845f642e64df81 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 26 Sep 2006 14:50:20 -0400 Subject: USB: fix autosuspend when CONFIG_PM isn't set This patch (as791b) fixes things up to avoid compiler warnings or errors when CONFIG_USB_SUSPEND or CONFIG_PM isn't set. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 42 +++++++++++++++++++++--------------------- drivers/usb/core/hub.c | 4 ++-- drivers/usb/core/usb.c | 4 ++-- drivers/usb/core/usb.h | 18 +++++++++++++++++- include/linux/usb.h | 2 +- 5 files changed, 43 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ee18d187ca17..113e484c763e 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -303,11 +303,11 @@ int usb_driver_claim_interface(struct usb_driver *driver, dev->driver = &driver->drvwrap.driver; usb_set_intfdata(iface, priv); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); iface->condition = USB_INTERFACE_BOUND; mark_active(iface); iface->pm_usage_cnt = !(driver->supports_autosuspend); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() @@ -356,11 +356,11 @@ void usb_driver_release_interface(struct usb_driver *driver, dev->driver = NULL; usb_set_intfdata(iface, NULL); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); iface->condition = USB_INTERFACE_UNBOUND; mark_quiesced(iface); iface->needs_remote_wakeup = 0; - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); } EXPORT_SYMBOL(usb_driver_release_interface); @@ -789,7 +789,7 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); #ifdef CONFIG_PM -/* Caller has locked udev->pm_mutex */ +/* Caller has locked udev's pm_mutex */ static int suspend_device(struct usb_device *udev, pm_message_t msg) { struct usb_device_driver *udriver; @@ -816,7 +816,7 @@ done: return status; } -/* Caller has locked udev->pm_mutex */ +/* Caller has locked udev's pm_mutex */ static int resume_device(struct usb_device *udev) { struct usb_device_driver *udriver; @@ -842,7 +842,7 @@ done: return status; } -/* Caller has locked intf's usb_device's pm_mutex */ +/* Caller has locked intf's usb_device's pm mutex */ static int suspend_interface(struct usb_interface *intf, pm_message_t msg) { struct usb_driver *driver; @@ -1064,7 +1064,7 @@ int usb_resume_both(struct usb_device *udev) /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { if (parent) { - mutex_lock_nested(&parent->pm_mutex, parent->level); + usb_pm_lock(parent); parent->auto_pm = 1; status = usb_resume_both(parent); } else { @@ -1079,7 +1079,7 @@ int usb_resume_both(struct usb_device *udev) if (status == 0) status = resume_device(udev); if (parent) - mutex_unlock(&parent->pm_mutex); + usb_pm_unlock(parent); } else { /* Needed only for setting udev->dev.power.power_state.event @@ -1129,12 +1129,12 @@ int usb_resume_both(struct usb_device *udev) */ void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt) { - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->pm_usage_cnt -= dec_usage_cnt; if (udev->pm_usage_cnt <= 0) queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, USB_AUTOSUSPEND_DELAY); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&udev->dev, "%s: cnt %d\n", // __FUNCTION__, udev->pm_usage_cnt); } @@ -1168,13 +1168,13 @@ int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt) { int status; - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->pm_usage_cnt += inc_usage_cnt; udev->auto_pm = 1; status = usb_resume_both(udev); if (status != 0) udev->pm_usage_cnt -= inc_usage_cnt; - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&udev->dev, "%s: status %d cnt %d\n", // __FUNCTION__, status, udev->pm_usage_cnt); return status; @@ -1215,13 +1215,13 @@ void usb_autopm_put_interface(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); if (intf->condition != USB_INTERFACE_UNBOUND && --intf->pm_usage_cnt <= 0) { queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, USB_AUTOSUSPEND_DELAY); } - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&intf->dev, "%s: cnt %d\n", // __FUNCTION__, intf->pm_usage_cnt); } @@ -1263,7 +1263,7 @@ int usb_autopm_get_interface(struct usb_interface *intf) struct usb_device *udev = interface_to_usbdev(intf); int status; - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); if (intf->condition == USB_INTERFACE_UNBOUND) status = -ENODEV; else { @@ -1273,7 +1273,7 @@ int usb_autopm_get_interface(struct usb_interface *intf) if (status != 0) --intf->pm_usage_cnt; } - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", // __FUNCTION__, status, intf->pm_usage_cnt); return status; @@ -1289,10 +1289,10 @@ static int usb_suspend(struct device *dev, pm_message_t message) if (is_usb_device(dev)) { struct usb_device *udev = to_usb_device(dev); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->auto_pm = 0; status = usb_suspend_both(udev, message); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); } else status = 0; return status; @@ -1305,10 +1305,10 @@ static int usb_resume(struct device *dev) if (is_usb_device(dev)) { struct usb_device *udev = to_usb_device(dev); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->auto_pm = 0; status = usb_resume_both(udev); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); /* Rebind drivers that had no suspend method? */ } else diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2a8cb3c2b19c..7676690a0386 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1779,7 +1779,7 @@ static int remote_wakeup(struct usb_device *udev) * to the parent hub! */ usb_lock_device(udev); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); if (udev->state == USB_STATE_SUSPENDED) { dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); /* TRSMRCY = 10 msec */ @@ -1788,7 +1788,7 @@ static int remote_wakeup(struct usb_device *udev) if (status == 0) udev->dev.power.power_state.event = PM_EVENT_ON; } - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); if (status == 0) usb_autoresume_device(udev, 0); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 239f8e5d247f..e4df9edf1bc0 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -214,10 +214,10 @@ static void usb_autosuspend_work(void *_udev) { struct usb_device *udev = _udev; - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->auto_pm = 1; usb_suspend_both(udev, PMSG_SUSPEND); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); } #else diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index fb6eb41c374f..f69df137ec0e 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -36,6 +36,16 @@ extern int usb_resume_both(struct usb_device *udev); extern int usb_port_suspend(struct usb_device *dev); extern int usb_port_resume(struct usb_device *dev); +static inline void usb_pm_lock(struct usb_device *udev) +{ + mutex_lock_nested(&udev->pm_mutex, udev->level); +} + +static inline void usb_pm_unlock(struct usb_device *udev) +{ + mutex_unlock(&udev->pm_mutex); +} + #else #define usb_suspend_both(udev, msg) 0 @@ -45,6 +55,8 @@ static inline int usb_resume_both(struct usb_device *udev) } #define usb_port_suspend(dev) 0 #define usb_port_resume(dev) 0 +static inline void usb_pm_lock(struct usb_device *udev) {} +static inline void usb_pm_unlock(struct usb_device *udev) {} #endif @@ -58,7 +70,11 @@ extern int usb_autoresume_device(struct usb_device *udev, int inc_busy_cnt); #else #define usb_autosuspend_device(udev, dec_busy_cnt) do {} while (0) -#define usb_autoresume_device(udev, inc_busy_cnt) 0 +static inline int usb_autoresume_device(struct usb_device *udev, + int inc_busy_cnt) +{ + return 0; +} #endif diff --git a/include/linux/usb.h b/include/linux/usb.h index 0da15b0b02be..190cc1b78fe2 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -380,10 +380,10 @@ struct usb_device { int maxchild; /* Number of ports if hub */ struct usb_device *children[USB_MAXCHILDREN]; + int pm_usage_cnt; /* usage counter for autosuspend */ #ifdef CONFIG_PM struct work_struct autosuspend; /* for delayed autosuspends */ struct mutex pm_mutex; /* protects PM operations */ - int pm_usage_cnt; /* usage counter for autosuspend */ unsigned auto_pm:1; /* autosuspend/resume in progress */ unsigned do_remote_wakeup:1; /* remote wakeup should be enabled */ -- cgit v1.2.3 From 2a50f28c326d20ab4556be1b867ecddf6aefbb88 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Sep 2006 21:22:08 -0700 Subject: [ATALK]: endianness annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- drivers/net/appletalk/ipddp.c | 5 +-- include/linux/atalk.h | 40 +--------------------- net/appletalk/ddp.c | 79 +++++++++++++++---------------------------- 3 files changed, 30 insertions(+), 94 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 7f7dd450226a..b98592a8bac8 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -145,9 +145,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) /* Create the Extended DDP header */ ddp = (struct ddpehdr *)skb->data; - ddp->deh_len = skb->len; - ddp->deh_hops = 1; - ddp->deh_pad = 0; + ddp->deh_len_hops = htons(skb->len + (1<<10)); ddp->deh_sum = 0; /* @@ -170,7 +168,6 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) ddp->deh_sport = 72; *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ - *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */ skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ diff --git a/include/linux/atalk.h b/include/linux/atalk.h index 6ba3aa8a81f4..75b8baca08f3 100644 --- a/include/linux/atalk.h +++ b/include/linux/atalk.h @@ -88,15 +88,7 @@ static inline struct atalk_sock *at_sk(struct sock *sk) #include struct ddpehdr { -#ifdef __LITTLE_ENDIAN_BITFIELD - __u16 deh_len:10, - deh_hops:4, - deh_pad:2; -#else - __u16 deh_pad:2, - deh_hops:4, - deh_len:10; -#endif + __be16 deh_len_hops; /* lower 10 bits are length, next 4 - hops */ __be16 deh_sum; __be16 deh_dnet; __be16 deh_snet; @@ -112,36 +104,6 @@ static __inline__ struct ddpehdr *ddp_hdr(struct sk_buff *skb) return (struct ddpehdr *)skb->h.raw; } -/* - * Don't drop the struct into the struct above. You'll get some - * surprise padding. - */ -struct ddpebits { -#ifdef __LITTLE_ENDIAN_BITFIELD - __u16 deh_len:10, - deh_hops:4, - deh_pad:2; -#else - __u16 deh_pad:2, - deh_hops:4, - deh_len:10; -#endif -}; - -/* Short form header */ -struct ddpshdr { -#ifdef __LITTLE_ENDIAN_BITFIELD - __u16 dsh_len:10, - dsh_pad:6; -#else - __u16 dsh_pad:6, - dsh_len:10; -#endif - __u8 dsh_dport; - __u8 dsh_sport; - /* And netatalk apps expect to stick the type in themselves */ -}; - /* AppleTalk AARP headers */ struct elapaarp { __be16 hw_type; diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 96dc6bb52d14..708e2e0371af 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1002,7 +1002,7 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset, return sum; } -static unsigned short atalk_checksum(const struct sk_buff *skb, int len) +static __be16 atalk_checksum(const struct sk_buff *skb, int len) { unsigned long sum; @@ -1010,7 +1010,7 @@ static unsigned short atalk_checksum(const struct sk_buff *skb, int len) sum = atalk_sum_skb(skb, 4, len-4, 0); /* Use 0xFFFF for 0. 0 itself means none */ - return sum ? htons((unsigned short)sum) : 0xFFFF; + return sum ? htons((unsigned short)sum) : htons(0xFFFF); } static struct proto ddp_proto = { @@ -1289,7 +1289,7 @@ static int handle_ip_over_ddp(struct sk_buff *skb) #endif static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, - struct ddpehdr *ddp, struct ddpebits *ddphv, + struct ddpehdr *ddp, __u16 len_hops, int origlen) { struct atalk_route *rt; @@ -1317,10 +1317,12 @@ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, /* Route the packet */ rt = atrtr_find(&ta); - if (!rt || ddphv->deh_hops == DDP_MAXHOPS) + /* increment hops count */ + len_hops += 1 << 10; + if (!rt || !(len_hops & (15 << 10))) goto free_it; + /* FIXME: use skb->cb to be able to use shared skbs */ - ddphv->deh_hops++; /* * Route goes through another gateway, so set the target to the @@ -1335,11 +1337,10 @@ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, /* Fix up skb->len field */ skb_trim(skb, min_t(unsigned int, origlen, (rt->dev->hard_header_len + - ddp_dl->header_length + ddphv->deh_len))); + ddp_dl->header_length + (len_hops & 1023)))); - /* Mend the byte order */ /* FIXME: use skb->cb to be able to use shared skbs */ - *((__u16 *)ddp) = ntohs(*((__u16 *)ddphv)); + ddp->deh_len_hops = htons(len_hops); /* * Send the buffer onwards @@ -1394,7 +1395,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct atalk_iface *atif; struct sockaddr_at tosat; int origlen; - struct ddpebits ddphv; + __u16 len_hops; /* Don't mangle buffer if shared */ if (!(skb = skb_share_check(skb, GFP_ATOMIC))) @@ -1406,16 +1407,11 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, ddp = ddp_hdr(skb); - /* - * Fix up the length field [Ok this is horrible but otherwise - * I end up with unions of bit fields and messy bit field order - * compiler/endian dependencies..] - */ - *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp)); + len_hops = ntohs(ddp->deh_len_hops); /* Trim buffer in case of stray trailing data */ origlen = skb->len; - skb_trim(skb, min_t(unsigned int, skb->len, ddphv.deh_len)); + skb_trim(skb, min_t(unsigned int, skb->len, len_hops & 1023)); /* * Size check to see if ddp->deh_len was crap @@ -1430,7 +1426,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, * valid for net byte orders all over the networking code... */ if (ddp->deh_sum && - atalk_checksum(skb, ddphv.deh_len) != ddp->deh_sum) + atalk_checksum(skb, len_hops & 1023) != ddp->deh_sum) /* Not a valid AppleTalk frame - dustbin time */ goto freeit; @@ -1444,7 +1440,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, /* Not ours, so we route the packet via the correct * AppleTalk iface */ - atalk_route_packet(skb, dev, ddp, &ddphv, origlen); + atalk_route_packet(skb, dev, ddp, len_hops, origlen); goto out; } @@ -1489,7 +1485,7 @@ static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, /* Find our address */ struct atalk_addr *ap = atalk_find_dev_addr(dev); - if (!ap || skb->len < sizeof(struct ddpshdr)) + if (!ap || skb->len < sizeof(__be16) || skb->len > 1023) goto freeit; /* Don't mangle buffer if shared */ @@ -1519,11 +1515,8 @@ static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, /* * Not sure about this bit... */ - ddp->deh_len = skb->len; - ddp->deh_hops = DDP_MAXHOPS; /* Non routable, so force a drop - if we slip up later */ - /* Mend the byte order */ - *((__u16 *)ddp) = htons(*((__u16 *)ddp)); + /* Non routable, so force a drop if we slip up later */ + ddp->deh_len_hops = htons(skb->len + (DDP_MAXHOPS << 10)); } skb->h.raw = skb->data; @@ -1622,16 +1615,7 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk); ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr)); - ddp->deh_pad = 0; - ddp->deh_hops = 0; - ddp->deh_len = len + sizeof(*ddp); - /* - * Fix up the length field [Ok this is horrible but otherwise - * I end up with unions of bit fields and messy bit field order - * compiler/endian dependencies.. - */ - *((__u16 *)ddp) = ntohs(*((__u16 *)ddp)); - + ddp->deh_len_hops = htons(len + sizeof(*ddp)); ddp->deh_dnet = usat->sat_addr.s_net; ddp->deh_snet = at->src_net; ddp->deh_dnode = usat->sat_addr.s_node; @@ -1712,8 +1696,8 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name; struct ddpehdr *ddp; int copied = 0; + int offset = 0; int err = 0; - struct ddpebits ddphv; struct sk_buff *skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err); if (!skb) @@ -1721,25 +1705,18 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr /* FIXME: use skb->cb to be able to use shared skbs */ ddp = ddp_hdr(skb); - *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp)); + copied = ntohs(ddp->deh_len_hops) & 1023; - if (sk->sk_type == SOCK_RAW) { - copied = ddphv.deh_len; - if (copied > size) { - copied = size; - msg->msg_flags |= MSG_TRUNC; - } + if (sk->sk_type != SOCK_RAW) { + offset = sizeof(*ddp); + copied -= offset; + } - err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - } else { - copied = ddphv.deh_len - sizeof(*ddp); - if (copied > size) { - copied = size; - msg->msg_flags |= MSG_TRUNC; - } - err = skb_copy_datagram_iovec(skb, sizeof(*ddp), - msg->msg_iov, copied); + if (copied > size) { + copied = size; + msg->msg_flags |= MSG_TRUNC; } + err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied); if (!err) { if (sat) { -- cgit v1.2.3 From 0ac0760a57a6b1eb75c21a590e578be5dfc2f88b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Sep 2006 21:23:16 -0700 Subject: [TR]: endiannness annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/trdevice.h | 2 +- net/802/tr.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/trdevice.h b/include/linux/trdevice.h index 99e02ef54c47..bfc84a7aecc5 100644 --- a/include/linux/trdevice.h +++ b/include/linux/trdevice.h @@ -28,7 +28,7 @@ #include #ifdef __KERNEL__ -extern unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev); +extern __be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev); extern void tr_source_route(struct sk_buff *skb, struct trh_hdr *trh, struct net_device *dev); extern struct net_device *alloc_trdev(int sizeof_priv); diff --git a/net/802/tr.c b/net/802/tr.c index d7d8f40c4fed..829deb41ce81 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -164,7 +164,7 @@ static int tr_rebuild_header(struct sk_buff *skb) */ if(trllc->ethertype != htons(ETH_P_IP)) { - printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(trllc->ethertype)); + printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n", ntohs(trllc->ethertype)); return 0; } @@ -186,7 +186,7 @@ static int tr_rebuild_header(struct sk_buff *skb) * it via SNAP. */ -unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev) +__be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev) { struct trh_hdr *trh=(struct trh_hdr *)skb->data; @@ -229,15 +229,15 @@ unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev) */ if (trllc->dsap == EXTENDED_SAP && - (trllc->ethertype == ntohs(ETH_P_IP) || - trllc->ethertype == ntohs(ETH_P_IPV6) || - trllc->ethertype == ntohs(ETH_P_ARP))) + (trllc->ethertype == htons(ETH_P_IP) || + trllc->ethertype == htons(ETH_P_IPV6) || + trllc->ethertype == htons(ETH_P_ARP))) { skb_pull(skb, sizeof(struct trllc)); return trllc->ethertype; } - return ntohs(ETH_P_TR_802_2); + return htons(ETH_P_TR_802_2); } /* -- cgit v1.2.3 From 046d033148e6936ee2466d38214cf0743a210f39 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Sep 2006 21:24:24 -0700 Subject: [IPV4]: headers endianness Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/ip.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ip.h b/include/linux/ip.h index 2f4600146f83..6b25d36fc54c 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -96,7 +96,7 @@ struct iphdr { __be16 frag_off; __u8 ttl; __u8 protocol; - __u16 check; + __be16 check; __be32 saddr; __be32 daddr; /*The options start here. */ @@ -105,22 +105,22 @@ struct iphdr { struct ip_auth_hdr { __u8 nexthdr; __u8 hdrlen; /* This one is measured in 32 bit units! */ - __u16 reserved; - __u32 spi; - __u32 seq_no; /* Sequence number */ + __be16 reserved; + __be32 spi; + __be32 seq_no; /* Sequence number */ __u8 auth_data[0]; /* Variable len but >=4. Mind the 64 bit alignment! */ }; struct ip_esp_hdr { - __u32 spi; - __u32 seq_no; /* Sequence number */ + __be32 spi; + __be32 seq_no; /* Sequence number */ __u8 enc_data[0]; /* Variable len but >=8. Mind the 64 bit alignment! */ }; struct ip_comp_hdr { __u8 nexthdr; __u8 flags; - __u16 cpi; + __be16 cpi; }; #endif /* _LINUX_IP_H */ -- cgit v1.2.3 From a61ced5d1c2e773620d7855ea2009d770c10a6e6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Sep 2006 21:27:54 -0700 Subject: [IPV4]: inet_select_addr() annotations argument and return value are net-endian. Annotated function and inferred net-endian variables in callers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 2 +- net/ipv4/arp.c | 4 ++-- net/ipv4/devinet.c | 4 ++-- net/ipv4/icmp.c | 2 +- net/ipv4/ipvs/ip_vs_sync.c | 2 +- net/ipv4/netfilter/ipt_MASQUERADE.c | 2 +- net/ipv4/route.c | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 92297ff24e85..40d07d0b896b 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -110,7 +110,7 @@ extern int devinet_ioctl(unsigned int cmd, void __user *); extern void devinet_init(void); extern struct in_device *inetdev_init(struct net_device *dev); extern struct in_device *inetdev_by_index(int); -extern u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope); +extern __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); extern u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope); extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask); extern void inet_forward_change(void); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 48e1ccb2ff55..db72339c21e1 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -330,10 +330,10 @@ static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb) static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) { - u32 saddr = 0; + __be32 saddr = 0; u8 *dst_ha = NULL; struct net_device *dev = neigh->dev; - u32 target = *(u32*)neigh->primary_key; + __be32 target = *(__be32*)neigh->primary_key; int probes = atomic_read(&neigh->probes); struct in_device *in_dev = in_dev_get(dev); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 8e8d1f17d77a..bffbbecef455 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -876,9 +876,9 @@ out: return done; } -u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) +__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) { - u32 addr = 0; + __be32 addr = 0; struct in_device *in_dev; rcu_read_lock(); diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index c2ad07e48ab4..fd39685241c1 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -437,7 +437,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) struct icmp_bxm icmp_param; struct rtable *rt = (struct rtable *)skb_in->dst; struct ipcm_cookie ipc; - u32 saddr; + __be32 saddr; u8 tos; if (!rt) diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c index 1bca714bda3d..0c8d20da6139 100644 --- a/net/ipv4/ipvs/ip_vs_sync.c +++ b/net/ipv4/ipvs/ip_vs_sync.c @@ -464,7 +464,7 @@ join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname) static int bind_mcastif_addr(struct socket *sock, char *ifname) { struct net_device *dev; - u32 addr; + __be32 addr; struct sockaddr_in sin; if ((dev = __dev_get_by_name(ifname)) == NULL) diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index bc65168a3437..3dbfcfac8a84 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -70,7 +70,7 @@ masquerade_target(struct sk_buff **pskb, const struct ip_nat_multi_range_compat *mr; struct ip_nat_range newrange; struct rtable *rt; - u_int32_t newsrc; + __be32 newsrc; IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 32fcb77295f0..9d8fbf1e5bc3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1532,7 +1532,7 @@ static int ip_rt_bug(struct sk_buff *skb) void ip_rt_get_source(u8 *addr, struct rtable *rt) { - u32 src; + __be32 src; struct fib_result res; if (rt->fl.iif == 0) @@ -1603,7 +1603,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, { unsigned hash; struct rtable *rth; - u32 spec_dst; + __be32 spec_dst; struct in_device *in_dev = in_dev_get(dev); u32 itag = 0; -- cgit v1.2.3 From a60c4923da795c74db9ff61a60e2f1df5754e4ce Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Sep 2006 21:28:34 -0700 Subject: [IPV4]: ip_check_mc() annotations annotated arguments Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/igmp.h | 2 +- net/ipv4/igmp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 899c3d4776f3..8e7eedb3a574 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -197,7 +197,7 @@ struct ip_mc_list #define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value) #define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value) -extern int ip_check_mc(struct in_device *dev, u32 mc_addr, u32 src_addr, u16 proto); +extern int ip_check_mc(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u16 proto); extern int igmp_rcv(struct sk_buff *); extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr); extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr); diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 58be8227b0cb..d8068c483781 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2216,7 +2216,7 @@ void ip_mc_drop_socket(struct sock *sk) rtnl_unlock(); } -int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto) +int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 proto) { struct ip_mc_list *im; struct ip_sf_list *psf; -- cgit v1.2.3 From ff428d72c59b35e4ba34bc1b487e707648010fe3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Sep 2006 22:13:35 -0700 Subject: [IPV4]: inet_addr_onlink() annotated Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 2 +- net/ipv4/devinet.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 40d07d0b896b..5ae09372c144 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -105,7 +105,7 @@ extern int register_inetaddr_notifier(struct notifier_block *nb); extern int unregister_inetaddr_notifier(struct notifier_block *nb); extern struct net_device *ip_dev_find(u32 addr); -extern int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b); +extern int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b); extern int devinet_ioctl(unsigned int cmd, void __user *); extern void devinet_init(void); extern struct in_device *inetdev_init(struct net_device *dev); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index bffbbecef455..5988584f6a6d 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -224,7 +224,7 @@ static void inetdev_destroy(struct in_device *in_dev) call_rcu(&in_dev->rcu_head, in_dev_rcu_put); } -int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) +int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b) { rcu_read_lock(); for_primary_ifa(in_dev) { -- cgit v1.2.3 From a144ea4b7a13087081ab5402fa9ad0bcfd249e67 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Sep 2006 18:00:55 -0700 Subject: [IPV4]: annotate struct in_ifaddr ifa_local, ifa_address, ifa_mask, ifa_broadcast and ifa_anycast are net-endian. Annotated them and variables that are inferred to be net-endian. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- arch/ia64/hp/sim/simeth.c | 4 ++-- arch/um/drivers/net_kern.c | 2 +- arch/xtensa/platform-iss/network.c | 2 +- drivers/isdn/i4l/isdn_net.c | 4 ++-- drivers/net/bonding/bond_main.c | 2 +- drivers/net/wan/hdlc_cisco.c | 2 +- drivers/net/wan/syncppp.c | 2 +- drivers/net/wireless/strip.c | 4 ++-- include/linux/inetdevice.h | 10 +++++----- net/ipv4/devinet.c | 4 ++-- net/ipv4/fib_frontend.c | 12 ++++++------ net/ipv4/icmp.c | 2 +- net/ipv4/netfilter/ip_conntrack_netbios_ns.c | 2 +- net/ipv4/netfilter/ipt_REDIRECT.c | 2 +- 14 files changed, 27 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index b5195be62818..e1a1b11473e2 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -320,7 +320,7 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) } printk(KERN_INFO "simeth_device_event: %s ipaddr=0x%x\n", - dev->name, htonl(ifa->ifa_local)); + dev->name, ntohl(ifa->ifa_local)); /* * XXX Fix me @@ -331,7 +331,7 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) local = dev->priv; /* now do it for real */ r = event == NETDEV_UP ? - netdev_attach(local->simfd, dev->irq, htonl(ifa->ifa_local)): + netdev_attach(local->simfd, dev->irq, ntohl(ifa->ifa_local)): netdev_detach(local->simfd); printk(KERN_INFO "simeth: netdev_attach/detach: event=%s ->%d\n", diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 664c2e2fb820..bd1178fa4e9a 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -825,7 +825,7 @@ int dev_netmask(void *d, void *m) struct net_device *dev = d; struct in_device *ip = dev->ip_ptr; struct in_ifaddr *in; - __u32 *mask_out = m; + __be32 *mask_out = m; if(ip == NULL) return(1); diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c index d96164e602fe..15d64414bd60 100644 --- a/arch/xtensa/platform-iss/network.c +++ b/arch/xtensa/platform-iss/network.c @@ -201,7 +201,7 @@ static void dev_ip_addr(void *d, char *buf, char *bin_buf) struct net_device *dev = d; struct in_device *ip = dev->ip_ptr; struct in_ifaddr *in; - u32 addr; + __be32 addr; if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) { printk(KERN_WARNING "Device not assigned an IP address!\n"); diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 43da8ae1b2ad..1f8d6ae66b41 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1614,8 +1614,8 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp) struct sk_buff *skb; unsigned char *p; struct in_device *in_dev = NULL; - u32 addr = 0; /* local ipv4 address */ - u32 mask = 0; /* local netmask */ + __be32 addr = 0; /* local ipv4 address */ + __be32 mask = 0; /* local netmask */ if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) { /* take primary(first) address of interface */ diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 0fb5f653d3ce..c0bbddae4ec4 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2252,7 +2252,7 @@ static u32 bond_glean_dev_ip(struct net_device *dev) { struct in_device *idev; struct in_ifaddr *ifa; - u32 addr = 0; + __be32 addr = 0; if (!dev) return 0; diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 7ec2b2f9b7ee..b0bc5ddcf1b1 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -161,7 +161,7 @@ static int cisco_rx(struct sk_buff *skb) struct hdlc_header *data = (struct hdlc_header*)skb->data; struct cisco_packet *cisco_data; struct in_device *in_dev; - u32 addr, mask; + __be32 addr, mask; if (skb->len < sizeof(struct hdlc_header)) goto rx_error; diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index c13b459a0137..d1173089f334 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -763,7 +763,7 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) { struct in_device *in_dev; struct in_ifaddr *ifa; - u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ + __be32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ #ifdef CONFIG_INET rcu_read_lock(); if ((in_dev = __in_dev_get_rcu(dev)) != NULL) diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index ccaf28e8db0a..337c692f6fd6 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1342,7 +1342,7 @@ static unsigned char *strip_make_packet(unsigned char *buffer, * 'broadcast hub' radio (First byte of address being 0xFF means broadcast) */ if (haddr.c[0] == 0xFF) { - u32 brd = 0; + __be32 brd = 0; struct in_device *in_dev; rcu_read_lock(); @@ -1406,7 +1406,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) int doreset = (long) jiffies - strip_info->watchdog_doreset >= 0; int doprobe = (long) jiffies - strip_info->watchdog_doprobe >= 0 && !doreset; - u32 addr, brd; + __be32 addr, brd; /* * 1. If we have a packet, encapsulate it and put it in the buffer diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 5ae09372c144..54b32e8b8f65 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -90,11 +90,11 @@ struct in_ifaddr struct in_ifaddr *ifa_next; struct in_device *ifa_dev; struct rcu_head rcu_head; - u32 ifa_local; - u32 ifa_address; - u32 ifa_mask; - u32 ifa_broadcast; - u32 ifa_anycast; + __be32 ifa_local; + __be32 ifa_address; + __be32 ifa_mask; + __be32 ifa_broadcast; + __be32 ifa_anycast; unsigned char ifa_scope; unsigned char ifa_flags; unsigned char ifa_prefixlen; diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5988584f6a6d..a0a7780e7515 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -805,7 +805,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg) break; ret = 0; if (ifa->ifa_mask != sin->sin_addr.s_addr) { - u32 old_mask = ifa->ifa_mask; + __be32 old_mask = ifa->ifa_mask; inet_del_ifa(in_dev, ifap, 0); ifa->ifa_mask = sin->sin_addr.s_addr; ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask); @@ -931,7 +931,7 @@ static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst, u32 local, int scope) { int same = 0; - u32 addr = 0; + __be32 addr = 0; for_ifa(in_dev) { if (!addr && diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 7f5217907e5a..62ee71ee6bc9 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -667,9 +667,9 @@ void fib_add_ifaddr(struct in_ifaddr *ifa) struct in_device *in_dev = ifa->ifa_dev; struct net_device *dev = in_dev->dev; struct in_ifaddr *prim = ifa; - u32 mask = ifa->ifa_mask; - u32 addr = ifa->ifa_local; - u32 prefix = ifa->ifa_address&mask; + __be32 mask = ifa->ifa_mask; + __be32 addr = ifa->ifa_local; + __be32 prefix = ifa->ifa_address&mask; if (ifa->ifa_flags&IFA_F_SECONDARY) { prim = inet_ifa_byprefix(in_dev, prefix, mask); @@ -685,7 +685,7 @@ void fib_add_ifaddr(struct in_ifaddr *ifa) return; /* Add broadcast address, if it is explicitly assigned. */ - if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF) + if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF)) fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) && @@ -707,8 +707,8 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) struct net_device *dev = in_dev->dev; struct in_ifaddr *ifa1; struct in_ifaddr *prim = ifa; - u32 brd = ifa->ifa_address|~ifa->ifa_mask; - u32 any = ifa->ifa_address&ifa->ifa_mask; + __be32 brd = ifa->ifa_address|~ifa->ifa_mask; + __be32 any = ifa->ifa_address&ifa->ifa_mask; #define LOCAL_OK 1 #define BRD_OK 2 #define BRD0_OK 4 diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index fd39685241c1..428f1c91ec45 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -895,7 +895,7 @@ static void icmp_address_reply(struct sk_buff *skb) if (in_dev->ifa_list && IN_DEV_LOG_MARTIANS(in_dev) && IN_DEV_FORWARD(in_dev)) { - u32 _mask, *mp; + __be32 _mask, *mp; mp = skb_header_pointer(skb, 0, sizeof(_mask), &_mask); BUG_ON(mp == NULL); diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c index 3d0b438783db..4adec47aae32 100644 --- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c +++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c @@ -48,7 +48,7 @@ static int help(struct sk_buff **pskb, struct iphdr *iph = (*pskb)->nh.iph; struct rtable *rt = (struct rtable *)(*pskb)->dst; struct in_device *in_dev; - u_int32_t mask = 0; + __be32 mask = 0; /* we're only interested in locally generated packets */ if ((*pskb)->sk == NULL) diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c index f03d43671c6d..c0dcfe9d610c 100644 --- a/net/ipv4/netfilter/ipt_REDIRECT.c +++ b/net/ipv4/netfilter/ipt_REDIRECT.c @@ -61,7 +61,7 @@ redirect_target(struct sk_buff **pskb, { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; - u_int32_t newdst; + __be32 newdst; const struct ip_nat_multi_range_compat *mr = targinfo; struct ip_nat_range newrange; -- cgit v1.2.3 From 60cad5da5791ceb0beefe9a79b570cca45791f50 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Sep 2006 22:17:09 -0700 Subject: [IPV4]: annotate inetdev.h helpers inet_confirm_addr(), inet_ifa_byprefix(), ip_dev_find(), inet_make_mask() and inet_ifa_match() annotated, along with inferred net-endian variables Signed-off-by: Al Viro Signed-off-by: David S. Miller --- drivers/infiniband/core/addr.c | 4 ++-- include/linux/inetdevice.h | 10 +++++----- net/ipv4/devinet.c | 12 ++++++------ net/ipv4/fib_frontend.c | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 9cbf09e2052f..60d3fbdd216c 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -86,7 +86,7 @@ EXPORT_SYMBOL(rdma_copy_addr); int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) { struct net_device *dev; - u32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr; + __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr; int ret; dev = ip_dev_find(ip); @@ -239,7 +239,7 @@ static int addr_resolve_local(struct sockaddr_in *src_in, { struct net_device *dev; u32 src_ip = src_in->sin_addr.s_addr; - u32 dst_ip = dst_in->sin_addr.s_addr; + __be32 dst_ip = dst_in->sin_addr.s_addr; int ret; dev = ip_dev_find(dst_ip); diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 54b32e8b8f65..5a0ab04627bc 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -104,18 +104,18 @@ struct in_ifaddr extern int register_inetaddr_notifier(struct notifier_block *nb); extern int unregister_inetaddr_notifier(struct notifier_block *nb); -extern struct net_device *ip_dev_find(u32 addr); +extern struct net_device *ip_dev_find(__be32 addr); extern int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b); extern int devinet_ioctl(unsigned int cmd, void __user *); extern void devinet_init(void); extern struct in_device *inetdev_init(struct net_device *dev); extern struct in_device *inetdev_by_index(int); extern __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); -extern u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope); -extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask); +extern __be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope); +extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, __be32 mask); extern void inet_forward_change(void); -static __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa) +static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa) { return !((addr^ifa->ifa_address)&ifa->ifa_mask); } @@ -183,7 +183,7 @@ static inline void in_dev_put(struct in_device *idev) #endif /* __KERNEL__ */ -static __inline__ __u32 inet_make_mask(int logmask) +static __inline__ __be32 inet_make_mask(int logmask) { if (logmask) return htonl(~((1<<(32-logmask))-1)); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index afba56222fb5..7602c79a389b 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -429,8 +429,8 @@ struct in_device *inetdev_by_index(int ifindex) /* Called only from RTNL semaphored context. No locks. */ -struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, - u32 mask) +struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, + __be32 mask) { ASSERT_RTNL(); @@ -927,8 +927,8 @@ out: return addr; } -static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst, - u32 local, int scope) +static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, + __be32 local, int scope) { int same = 0; __be32 addr = 0; @@ -971,9 +971,9 @@ static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst, * - local: address, 0=autoselect the local address * - scope: maximum allowed scope value for the local address */ -u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope) +__be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope) { - u32 addr = 0; + __be32 addr = 0; struct in_device *in_dev; if (dev) { diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 62ee71ee6bc9..c0bd2f122da2 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -122,7 +122,7 @@ static void fib_flush(void) * Find the first device with a given source address. */ -struct net_device * ip_dev_find(u32 addr) +struct net_device * ip_dev_find(__be32 addr) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; struct fib_result res; -- cgit v1.2.3 From 7699431301b189fca7ccbb64fe54e5a5170f8497 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 26 Sep 2006 22:28:46 -0700 Subject: [SUNRPC]: svc_{get,put}nl() * add svc_getnl(): Take network-endian value from buffer, convert to host-endian and return it. * add svc_putnl(): Take host-endian value, convert to network-endian and put it into a buffer. * annotate svc_getu32()/svc_putu32() as dealing with network-endian. * convert to svc_getnl(), svc_putnl(). [AV: in large part it's a carved-up Alexey's patch] Signed-off-by: Alexey Dobriyan Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/sunrpc/svc.h | 31 +++++++++++++++++------ net/sunrpc/auth_gss/svcauth_gss.c | 52 +++++++++++++++++++-------------------- net/sunrpc/svc.c | 44 ++++++++++++++++----------------- net/sunrpc/svcauth.c | 2 +- net/sunrpc/svcauth_unix.c | 22 ++++++++--------- 5 files changed, 84 insertions(+), 67 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 7b27c09b5604..5df1d319f5d5 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -78,28 +78,45 @@ struct svc_serv { */ #define RPCSVC_MAXPAGES ((RPCSVC_MAXPAYLOAD+PAGE_SIZE-1)/PAGE_SIZE + 2) -static inline u32 svc_getu32(struct kvec *iov) +static inline u32 svc_getnl(struct kvec *iov) { - u32 val, *vp; + __be32 val, *vp; vp = iov->iov_base; val = *vp++; iov->iov_base = (void*)vp; - iov->iov_len -= sizeof(u32); + iov->iov_len -= sizeof(__be32); + return ntohl(val); +} + +static inline void svc_putnl(struct kvec *iov, u32 val) +{ + __be32 *vp = iov->iov_base + iov->iov_len; + *vp = htonl(val); + iov->iov_len += sizeof(__be32); +} + +static inline __be32 svc_getu32(struct kvec *iov) +{ + __be32 val, *vp; + vp = iov->iov_base; + val = *vp++; + iov->iov_base = (void*)vp; + iov->iov_len -= sizeof(__be32); return val; } static inline void svc_ungetu32(struct kvec *iov) { - u32 *vp = (u32 *)iov->iov_base; + __be32 *vp = (__be32 *)iov->iov_base; iov->iov_base = (void *)(vp - 1); iov->iov_len += sizeof(*vp); } -static inline void svc_putu32(struct kvec *iov, u32 val) +static inline void svc_putu32(struct kvec *iov, __be32 val) { - u32 *vp = iov->iov_base + iov->iov_len; + __be32 *vp = iov->iov_base + iov->iov_len; *vp = val; - iov->iov_len += sizeof(u32); + iov->iov_len += sizeof(__be32); } diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 94217ec9e2dd..cd3d77ca3a31 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -607,7 +607,7 @@ svc_safe_getnetobj(struct kvec *argv, struct xdr_netobj *o) if (argv->iov_len < 4) return -1; - o->len = ntohl(svc_getu32(argv)); + o->len = svc_getnl(argv); l = round_up_to_quad(o->len); if (argv->iov_len < l) return -1; @@ -624,7 +624,7 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o) if (resv->iov_len + 4 > PAGE_SIZE) return -1; - svc_putu32(resv, htonl(o->len)); + svc_putnl(resv, o->len); p = resv->iov_base + resv->iov_len; resv->iov_len += round_up_to_quad(o->len); if (resv->iov_len > PAGE_SIZE) @@ -657,7 +657,7 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, *authp = rpc_autherr_badverf; if (argv->iov_len < 4) return SVC_DENIED; - flavor = ntohl(svc_getu32(argv)); + flavor = svc_getnl(argv); if (flavor != RPC_AUTH_GSS) return SVC_DENIED; if (svc_safe_getnetobj(argv, &checksum)) @@ -689,7 +689,7 @@ gss_write_null_verf(struct svc_rqst *rqstp) { u32 *p; - svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_NULL)); + svc_putnl(rqstp->rq_res.head, RPC_AUTH_NULL); p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len; /* don't really need to check if head->iov_len > PAGE_SIZE ... */ *p++ = 0; @@ -708,7 +708,7 @@ gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq) u32 *p; struct kvec iov; - svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_GSS)); + svc_putnl(rqstp->rq_res.head, RPC_AUTH_GSS); xdr_seq = htonl(seq); iov.iov_base = &xdr_seq; @@ -805,7 +805,7 @@ unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx) struct xdr_netobj mic; struct xdr_buf integ_buf; - integ_len = ntohl(svc_getu32(&buf->head[0])); + integ_len = svc_getnl(&buf->head[0]); if (integ_len & 3) goto out; if (integ_len > buf->len) @@ -825,7 +825,7 @@ unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx) maj_stat = gss_verify_mic(ctx, &integ_buf, &mic); if (maj_stat != GSS_S_COMPLETE) goto out; - if (ntohl(svc_getu32(&buf->head[0])) != seq) + if (svc_getnl(&buf->head[0]) != seq) goto out; stat = 0; out: @@ -857,7 +857,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs rqstp->rq_sendfile_ok = 0; - priv_len = ntohl(svc_getu32(&buf->head[0])); + priv_len = svc_getnl(&buf->head[0]); if (rqstp->rq_deferred) { /* Already decrypted last time through! The sequence number * check at out_seq is unnecessary but harmless: */ @@ -895,7 +895,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs if (maj_stat != GSS_S_COMPLETE) return -EINVAL; out_seq: - if (ntohl(svc_getu32(&buf->head[0])) != seq) + if (svc_getnl(&buf->head[0]) != seq) return -EINVAL; return 0; } @@ -985,12 +985,12 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) if (argv->iov_len < 5 * 4) goto auth_err; - crlen = ntohl(svc_getu32(argv)); - if (ntohl(svc_getu32(argv)) != RPC_GSS_VERSION) + crlen = svc_getnl(argv); + if (svc_getnl(argv) != RPC_GSS_VERSION) goto auth_err; - gc->gc_proc = ntohl(svc_getu32(argv)); - gc->gc_seq = ntohl(svc_getu32(argv)); - gc->gc_svc = ntohl(svc_getu32(argv)); + gc->gc_proc = svc_getnl(argv); + gc->gc_seq = svc_getnl(argv); + gc->gc_svc = svc_getnl(argv); if (svc_safe_getnetobj(argv, &gc->gc_ctx)) goto auth_err; if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4) @@ -1016,9 +1016,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) case RPC_GSS_PROC_CONTINUE_INIT: if (argv->iov_len < 2 * 4) goto auth_err; - if (ntohl(svc_getu32(argv)) != RPC_AUTH_NULL) + if (svc_getnl(argv) != RPC_AUTH_NULL) goto auth_err; - if (ntohl(svc_getu32(argv)) != 0) + if (svc_getnl(argv) != 0) goto auth_err; break; case RPC_GSS_PROC_DATA: @@ -1076,14 +1076,14 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) goto drop; if (resv->iov_len + 4 > PAGE_SIZE) goto drop; - svc_putu32(resv, rpc_success); + svc_putnl(resv, RPC_SUCCESS); if (svc_safe_putnetobj(resv, &rsip->out_handle)) goto drop; if (resv->iov_len + 3 * 4 > PAGE_SIZE) goto drop; - svc_putu32(resv, htonl(rsip->major_status)); - svc_putu32(resv, htonl(rsip->minor_status)); - svc_putu32(resv, htonl(GSS_SEQ_WIN)); + svc_putnl(resv, rsip->major_status); + svc_putnl(resv, rsip->minor_status); + svc_putnl(resv, GSS_SEQ_WIN); if (svc_safe_putnetobj(resv, &rsip->out_token)) goto drop; rqstp->rq_client = NULL; @@ -1093,7 +1093,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) set_bit(CACHE_NEGATIVE, &rsci->h.flags); if (resv->iov_len + 4 > PAGE_SIZE) goto drop; - svc_putu32(resv, rpc_success); + svc_putnl(resv, RPC_SUCCESS); goto complete; case RPC_GSS_PROC_DATA: *authp = rpcsec_gsserr_ctxproblem; @@ -1111,8 +1111,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) goto auth_err; /* placeholders for length and seq. number: */ svcdata->body_start = resv->iov_base + resv->iov_len; - svc_putu32(resv, 0); - svc_putu32(resv, 0); + svc_putnl(resv, 0); + svc_putnl(resv, 0); break; case RPC_GSS_SVC_PRIVACY: if (unwrap_priv_data(rqstp, &rqstp->rq_arg, @@ -1120,8 +1120,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) goto auth_err; /* placeholders for length and seq. number: */ svcdata->body_start = resv->iov_base + resv->iov_len; - svc_putu32(resv, 0); - svc_putu32(resv, 0); + svc_putnl(resv, 0); + svc_putnl(resv, 0); break; default: goto auth_err; @@ -1199,7 +1199,7 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp) mic.data = (u8 *)resv->iov_base + resv->iov_len + 4; if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic)) goto out_err; - svc_putu32(resv, htonl(mic.len)); + svc_putnl(resv, mic.len); memset(mic.data + mic.len, 0, round_up_to_quad(mic.len) - mic.len); resv->iov_len += XDR_QUADLEN(mic.len) << 2; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index b76a227dd3ad..6589e1ad47fa 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -284,16 +284,16 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) rqstp->rq_sendfile_ok = 1; /* tcp needs a space for the record length... */ if (rqstp->rq_prot == IPPROTO_TCP) - svc_putu32(resv, 0); + svc_putnl(resv, 0); rqstp->rq_xid = svc_getu32(argv); svc_putu32(resv, rqstp->rq_xid); - dir = ntohl(svc_getu32(argv)); - vers = ntohl(svc_getu32(argv)); + dir = svc_getnl(argv); + vers = svc_getnl(argv); /* First words of reply: */ - svc_putu32(resv, xdr_one); /* REPLY */ + svc_putnl(resv, 1); /* REPLY */ if (dir != 0) /* direction != CALL */ goto err_bad_dir; @@ -303,11 +303,11 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) /* Save position in case we later decide to reject: */ accept_statp = resv->iov_base + resv->iov_len; - svc_putu32(resv, xdr_zero); /* ACCEPT */ + svc_putnl(resv, 0); /* ACCEPT */ - rqstp->rq_prog = prog = ntohl(svc_getu32(argv)); /* program number */ - rqstp->rq_vers = vers = ntohl(svc_getu32(argv)); /* version number */ - rqstp->rq_proc = proc = ntohl(svc_getu32(argv)); /* procedure number */ + rqstp->rq_prog = prog = svc_getnl(argv); /* program number */ + rqstp->rq_vers = vers = svc_getnl(argv); /* version number */ + rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */ progp = serv->sv_program; @@ -361,7 +361,7 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) /* Build the reply header. */ statp = resv->iov_base +resv->iov_len; - svc_putu32(resv, rpc_success); /* RPC_SUCCESS */ + svc_putnl(resv, RPC_SUCCESS); /* Bump per-procedure stats counter */ procp->pc_count++; @@ -439,10 +439,10 @@ err_bad_dir: err_bad_rpc: serv->sv_stats->rpcbadfmt++; - svc_putu32(resv, xdr_one); /* REJECT */ - svc_putu32(resv, xdr_zero); /* RPC_MISMATCH */ - svc_putu32(resv, xdr_two); /* Only RPCv2 supported */ - svc_putu32(resv, xdr_two); + svc_putnl(resv, 1); /* REJECT */ + svc_putnl(resv, 0); /* RPC_MISMATCH */ + svc_putnl(resv, 2); /* Only RPCv2 supported */ + svc_putnl(resv, 2); goto sendit; err_bad_auth: @@ -450,15 +450,15 @@ err_bad_auth: serv->sv_stats->rpcbadauth++; /* Restore write pointer to location of accept status: */ xdr_ressize_check(rqstp, accept_statp); - svc_putu32(resv, xdr_one); /* REJECT */ - svc_putu32(resv, xdr_one); /* AUTH_ERROR */ - svc_putu32(resv, auth_stat); /* status */ + svc_putnl(resv, 1); /* REJECT */ + svc_putnl(resv, 1); /* AUTH_ERROR */ + svc_putnl(resv, ntohl(auth_stat)); /* status */ goto sendit; err_bad_prog: dprintk("svc: unknown program %d\n", prog); serv->sv_stats->rpcbadfmt++; - svc_putu32(resv, rpc_prog_unavail); + svc_putnl(resv, RPC_PROG_UNAVAIL); goto sendit; err_bad_vers: @@ -466,9 +466,9 @@ err_bad_vers: printk("svc: unknown version (%d)\n", vers); #endif serv->sv_stats->rpcbadfmt++; - svc_putu32(resv, rpc_prog_mismatch); - svc_putu32(resv, htonl(progp->pg_lovers)); - svc_putu32(resv, htonl(progp->pg_hivers)); + svc_putnl(resv, RPC_PROG_MISMATCH); + svc_putnl(resv, progp->pg_lovers); + svc_putnl(resv, progp->pg_hivers); goto sendit; err_bad_proc: @@ -476,7 +476,7 @@ err_bad_proc: printk("svc: unknown procedure (%d)\n", proc); #endif serv->sv_stats->rpcbadfmt++; - svc_putu32(resv, rpc_proc_unavail); + svc_putnl(resv, RPC_PROC_UNAVAIL); goto sendit; err_garbage: @@ -486,6 +486,6 @@ err_garbage: rpc_stat = rpc_garbage_args; err_bad: serv->sv_stats->rpcbadfmt++; - svc_putu32(resv, rpc_stat); + svc_putnl(resv, ntohl(rpc_stat)); goto sendit; } diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index 5b28c6176806..3f4d1f622de8 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c @@ -42,7 +42,7 @@ svc_authenticate(struct svc_rqst *rqstp, u32 *authp) *authp = rpc_auth_ok; - flavor = ntohl(svc_getu32(&rqstp->rq_arg.head[0])); + flavor = svc_getnl(&rqstp->rq_arg.head[0]); dprintk("svc: svc_authenticate (%d)\n", flavor); diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 7e5707e2d6b6..27f443b44af8 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -427,7 +427,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp) *authp = rpc_autherr_badcred; return SVC_DENIED; } - if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) { + if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { dprintk("svc: bad null verf\n"); *authp = rpc_autherr_badverf; return SVC_DENIED; @@ -441,8 +441,8 @@ svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp) return SVC_DROP; /* kmalloc failure - client must retry */ /* Put NULL verifier */ - svc_putu32(resv, RPC_AUTH_NULL); - svc_putu32(resv, 0); + svc_putnl(resv, RPC_AUTH_NULL); + svc_putnl(resv, 0); return SVC_OK; } @@ -488,31 +488,31 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp) svc_getu32(argv); /* length */ svc_getu32(argv); /* time stamp */ - slen = XDR_QUADLEN(ntohl(svc_getu32(argv))); /* machname length */ + slen = XDR_QUADLEN(svc_getnl(argv)); /* machname length */ if (slen > 64 || (len -= (slen + 3)*4) < 0) goto badcred; argv->iov_base = (void*)((u32*)argv->iov_base + slen); /* skip machname */ argv->iov_len -= slen*4; - cred->cr_uid = ntohl(svc_getu32(argv)); /* uid */ - cred->cr_gid = ntohl(svc_getu32(argv)); /* gid */ - slen = ntohl(svc_getu32(argv)); /* gids length */ + cred->cr_uid = svc_getnl(argv); /* uid */ + cred->cr_gid = svc_getnl(argv); /* gid */ + slen = svc_getnl(argv); /* gids length */ if (slen > 16 || (len -= (slen + 2)*4) < 0) goto badcred; cred->cr_group_info = groups_alloc(slen); if (cred->cr_group_info == NULL) return SVC_DROP; for (i = 0; i < slen; i++) - GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv)); + GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv); - if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) { + if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { *authp = rpc_autherr_badverf; return SVC_DENIED; } /* Put NULL verifier */ - svc_putu32(resv, RPC_AUTH_NULL); - svc_putu32(resv, 0); + svc_putnl(resv, RPC_AUTH_NULL); + svc_putnl(resv, 0); return SVC_OK; -- cgit v1.2.3 From d8ed029d6000ba2e2908d9286409e4833c091b4c Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 26 Sep 2006 22:29:38 -0700 Subject: [SUNRPC]: trivial endianness annotations pure s/u32/__be32/ [AV: large part based on Alexey's patches] Signed-off-by: Alexey Dobriyan Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/sunrpc/auth.h | 16 +++++------ include/linux/sunrpc/msg_prot.h | 2 +- include/linux/sunrpc/svc.h | 14 +++++----- include/linux/sunrpc/svcauth.h | 4 +-- include/linux/sunrpc/xdr.h | 38 +++++++++++++------------- include/linux/sunrpc/xprt.h | 12 ++++----- net/sunrpc/auth.c | 12 ++++----- net/sunrpc/auth_gss/auth_gss.c | 33 ++++++++++++----------- net/sunrpc/auth_gss/gss_krb5_seal.c | 2 +- net/sunrpc/auth_gss/gss_krb5_wrap.c | 4 +-- net/sunrpc/auth_gss/svcauth_gss.c | 24 ++++++++--------- net/sunrpc/auth_null.c | 8 +++--- net/sunrpc/auth_unix.c | 10 +++---- net/sunrpc/clnt.c | 23 ++++++++-------- net/sunrpc/pmap_clnt.c | 6 ++--- net/sunrpc/svc.c | 8 +++--- net/sunrpc/svcauth.c | 2 +- net/sunrpc/svcauth_unix.c | 8 +++--- net/sunrpc/svcsock.c | 2 +- net/sunrpc/xdr.c | 54 ++++++++++++++++++------------------- net/sunrpc/xprt.c | 4 +-- net/sunrpc/xprtsock.c | 3 ++- 22 files changed, 146 insertions(+), 143 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index a6de332e57d4..862c0d8c8381 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -109,13 +109,13 @@ struct rpc_credops { void (*crdestroy)(struct rpc_cred *); int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); - u32 * (*crmarshal)(struct rpc_task *, u32 *); + __be32 * (*crmarshal)(struct rpc_task *, __be32 *); int (*crrefresh)(struct rpc_task *); - u32 * (*crvalidate)(struct rpc_task *, u32 *); + __be32 * (*crvalidate)(struct rpc_task *, __be32 *); int (*crwrap_req)(struct rpc_task *, kxdrproc_t, - void *, u32 *, void *); + void *, __be32 *, void *); int (*crunwrap_resp)(struct rpc_task *, kxdrproc_t, - void *, u32 *, void *); + void *, __be32 *, void *); }; extern struct rpc_authops authunix_ops; @@ -134,10 +134,10 @@ struct rpc_cred * rpcauth_bindcred(struct rpc_task *); void rpcauth_holdcred(struct rpc_task *); void put_rpccred(struct rpc_cred *); void rpcauth_unbindcred(struct rpc_task *); -u32 * rpcauth_marshcred(struct rpc_task *, u32 *); -u32 * rpcauth_checkverf(struct rpc_task *, u32 *); -int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, u32 *data, void *obj); -int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, u32 *data, void *obj); +__be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); +__be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); +int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj); +int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, __be32 *data, void *obj); int rpcauth_refreshcred(struct rpc_task *); void rpcauth_invalcred(struct rpc_task *); int rpcauth_uptodatecred(struct rpc_task *); diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h index f43f237360ae..d9f5934ac9fe 100644 --- a/include/linux/sunrpc/msg_prot.h +++ b/include/linux/sunrpc/msg_prot.h @@ -95,7 +95,7 @@ enum rpc_auth_stat { * 2GB. */ -typedef u32 rpc_fraghdr; +typedef __be32 rpc_fraghdr; #define RPC_LAST_STREAM_FRAGMENT (1U << 31) #define RPC_FRAGMENT_SIZE_MASK (~RPC_LAST_STREAM_FRAGMENT) diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 5df1d319f5d5..73140ee5c638 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -147,7 +147,7 @@ struct svc_rqst { short rq_arghi; /* pages available in argument page list */ short rq_resused; /* pages used for result */ - u32 rq_xid; /* transmission id */ + __be32 rq_xid; /* transmission id */ u32 rq_prog; /* program number */ u32 rq_vers; /* program version */ u32 rq_proc; /* procedure number */ @@ -156,7 +156,7 @@ struct svc_rqst { rq_secure : 1; /* secure port */ - __u32 rq_daddr; /* dest addr of request - reply from here */ + __be32 rq_daddr; /* dest addr of request - reply from here */ void * rq_argp; /* decoded arguments */ void * rq_resp; /* xdr'd results */ @@ -186,7 +186,7 @@ struct svc_rqst { * Check buffer bounds after decoding arguments */ static inline int -xdr_argsize_check(struct svc_rqst *rqstp, u32 *p) +xdr_argsize_check(struct svc_rqst *rqstp, __be32 *p) { char *cp = (char *)p; struct kvec *vec = &rqstp->rq_arg.head[0]; @@ -195,7 +195,7 @@ xdr_argsize_check(struct svc_rqst *rqstp, u32 *p) } static inline int -xdr_ressize_check(struct svc_rqst *rqstp, u32 *p) +xdr_ressize_check(struct svc_rqst *rqstp, __be32 *p) { struct kvec *vec = &rqstp->rq_res.head[0]; char *cp = (char*)p; @@ -266,10 +266,10 @@ struct svc_deferred_req { u32 prot; /* protocol (UDP or TCP) */ struct sockaddr_in addr; struct svc_sock *svsk; /* where reply must go */ - u32 daddr; /* where reply must come from */ + __be32 daddr; /* where reply must come from */ struct cache_deferred_req handle; int argslen; - u32 args[0]; + __be32 args[0]; }; /* @@ -301,7 +301,7 @@ struct svc_version { * A return value of 0 means drop the request. * vs_dispatch == NULL means use default dispatcher. */ - int (*vs_dispatch)(struct svc_rqst *, u32 *); + int (*vs_dispatch)(struct svc_rqst *, __be32 *); }; /* diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index 2fe2087edd66..a6601650deeb 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h @@ -95,7 +95,7 @@ struct auth_ops { char * name; struct module *owner; int flavour; - int (*accept)(struct svc_rqst *rq, u32 *authp); + int (*accept)(struct svc_rqst *rq, __be32 *authp); int (*release)(struct svc_rqst *rq); void (*domain_release)(struct auth_domain *); int (*set_client)(struct svc_rqst *rq); @@ -112,7 +112,7 @@ struct auth_ops { #define SVC_COMPLETE 9 -extern int svc_authenticate(struct svc_rqst *rqstp, u32 *authp); +extern int svc_authenticate(struct svc_rqst *rqstp, __be32 *authp); extern int svc_authorise(struct svc_rqst *rqstp); extern int svc_set_client(struct svc_rqst *rqstp); extern int svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops); diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index e6d3d349506c..953723b09bc6 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -32,7 +32,7 @@ struct xdr_netobj { * side) or svc_rqst pointer (server side). * Encode functions always assume there's enough room in the buffer. */ -typedef int (*kxdrproc_t)(void *rqstp, u32 *data, void *obj); +typedef int (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj); /* * Basic structure for transmission/reception of a client XDR message. @@ -88,19 +88,19 @@ struct xdr_buf { /* * Miscellaneous XDR helper functions */ -u32 * xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int len); -u32 * xdr_encode_opaque(u32 *p, const void *ptr, unsigned int len); -u32 * xdr_encode_string(u32 *p, const char *s); -u32 * xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen); -u32 * xdr_encode_netobj(u32 *p, const struct xdr_netobj *); -u32 * xdr_decode_netobj(u32 *p, struct xdr_netobj *); +__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len); +__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len); +__be32 *xdr_encode_string(__be32 *p, const char *s); +__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen); +__be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *); +__be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *); void xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int, unsigned int); void xdr_inline_pages(struct xdr_buf *, unsigned int, struct page **, unsigned int, unsigned int); -static inline u32 *xdr_encode_array(u32 *p, const void *s, unsigned int len) +static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len) { return xdr_encode_opaque(p, s, len); } @@ -108,16 +108,16 @@ static inline u32 *xdr_encode_array(u32 *p, const void *s, unsigned int len) /* * Decode 64bit quantities (NFSv3 support) */ -static inline u32 * -xdr_encode_hyper(u32 *p, __u64 val) +static inline __be32 * +xdr_encode_hyper(__be32 *p, __u64 val) { *p++ = htonl(val >> 32); *p++ = htonl(val & 0xFFFFFFFF); return p; } -static inline u32 * -xdr_decode_hyper(u32 *p, __u64 *valp) +static inline __be32 * +xdr_decode_hyper(__be32 *p, __u64 *valp) { *valp = ((__u64) ntohl(*p++)) << 32; *valp |= ntohl(*p++); @@ -128,7 +128,7 @@ xdr_decode_hyper(u32 *p, __u64 *valp) * Adjust kvec to reflect end of xdr'ed data (RPC client XDR) */ static inline int -xdr_adjust_iovec(struct kvec *iov, u32 *p) +xdr_adjust_iovec(struct kvec *iov, __be32 *p) { return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base); } @@ -180,19 +180,19 @@ extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base, * Provide some simple tools for XDR buffer overflow-checking etc. */ struct xdr_stream { - uint32_t *p; /* start of available buffer */ + __be32 *p; /* start of available buffer */ struct xdr_buf *buf; /* XDR buffer to read/write */ - uint32_t *end; /* end of available buffer space */ + __be32 *end; /* end of available buffer space */ struct kvec *iov; /* pointer to the current kvec */ }; -extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p); -extern uint32_t *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); +extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p); +extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base, unsigned int len); -extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p); -extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes); +extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p); +extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes); extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len); extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len); diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index bdeba8538c71..6cf626580752 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -79,7 +79,7 @@ struct rpc_rqst { * This is the private part */ struct rpc_task * rq_task; /* RPC task data */ - __u32 rq_xid; /* request XID */ + __be32 rq_xid; /* request XID */ int rq_cong; /* has incremented xprt->cong */ int rq_received; /* receive completed */ u32 rq_seqno; /* gss seq no. used on req. */ @@ -171,9 +171,9 @@ struct rpc_xprt { /* * State of TCP reply receive stuff */ - u32 tcp_recm, /* Fragment header */ - tcp_xid, /* Current XID */ - tcp_reclen, /* fragment length */ + __be32 tcp_recm, /* Fragment header */ + tcp_xid; /* Current XID */ + u32 tcp_reclen, /* fragment length */ tcp_offset; /* fragment offset */ unsigned long tcp_copied, /* copied to request */ tcp_flags; @@ -253,7 +253,7 @@ void xprt_release(struct rpc_task *task); struct rpc_xprt * xprt_get(struct rpc_xprt *xprt); void xprt_put(struct rpc_xprt *xprt); -static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p) +static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p) { return p + xprt->tsh_size; } @@ -268,7 +268,7 @@ void xprt_wait_for_buffer_space(struct rpc_task *task); void xprt_write_space(struct rpc_xprt *xprt); void xprt_update_rtt(struct rpc_task *task); void xprt_adjust_cwnd(struct rpc_task *task, int result); -struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid); +struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid); void xprt_complete_rqst(struct rpc_task *task, int copied); void xprt_release_rqst_cong(struct rpc_task *task); void xprt_disconnect(struct rpc_xprt *xprt); diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 55163af3dcaf..993ff1a5d945 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -331,8 +331,8 @@ rpcauth_unbindcred(struct rpc_task *task) task->tk_msg.rpc_cred = NULL; } -u32 * -rpcauth_marshcred(struct rpc_task *task, u32 *p) +__be32 * +rpcauth_marshcred(struct rpc_task *task, __be32 *p) { struct rpc_cred *cred = task->tk_msg.rpc_cred; @@ -342,8 +342,8 @@ rpcauth_marshcred(struct rpc_task *task, u32 *p) return cred->cr_ops->crmarshal(task, p); } -u32 * -rpcauth_checkverf(struct rpc_task *task, u32 *p) +__be32 * +rpcauth_checkverf(struct rpc_task *task, __be32 *p) { struct rpc_cred *cred = task->tk_msg.rpc_cred; @@ -355,7 +355,7 @@ rpcauth_checkverf(struct rpc_task *task, u32 *p) int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, - u32 *data, void *obj) + __be32 *data, void *obj) { struct rpc_cred *cred = task->tk_msg.rpc_cred; @@ -369,7 +369,7 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, - u32 *data, void *obj) + __be32 *data, void *obj) { struct rpc_cred *cred = task->tk_msg.rpc_cred; diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 6eed3e166ba3..a6ed2d22a6e6 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -826,14 +826,14 @@ out: * Marshal credentials. * Maybe we should keep a cached credential for performance reasons. */ -static u32 * -gss_marshal(struct rpc_task *task, u32 *p) +static __be32 * +gss_marshal(struct rpc_task *task, __be32 *p) { struct rpc_cred *cred = task->tk_msg.rpc_cred; struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); - u32 *cred_len; + __be32 *cred_len; struct rpc_rqst *req = task->tk_rqstp; u32 maj_stat = 0; struct xdr_netobj mic; @@ -894,12 +894,12 @@ gss_refresh(struct rpc_task *task) return 0; } -static u32 * -gss_validate(struct rpc_task *task, u32 *p) +static __be32 * +gss_validate(struct rpc_task *task, __be32 *p) { struct rpc_cred *cred = task->tk_msg.rpc_cred; struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); - u32 seq; + __be32 seq; struct kvec iov; struct xdr_buf verf_buf; struct xdr_netobj mic; @@ -940,13 +940,14 @@ out_bad: static inline int gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, - kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj) + kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj) { struct xdr_buf *snd_buf = &rqstp->rq_snd_buf; struct xdr_buf integ_buf; - u32 *integ_len = NULL; + __be32 *integ_len = NULL; struct xdr_netobj mic; - u32 offset, *q; + u32 offset; + __be32 *q; struct kvec *iov; u32 maj_stat = 0; int status = -EIO; @@ -1032,13 +1033,13 @@ out: static inline int gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, - kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj) + kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj) { struct xdr_buf *snd_buf = &rqstp->rq_snd_buf; u32 offset; u32 maj_stat; int status; - u32 *opaque_len; + __be32 *opaque_len; struct page **inpages; int first; int pad; @@ -1095,7 +1096,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, static int gss_wrap_req(struct rpc_task *task, - kxdrproc_t encode, void *rqstp, u32 *p, void *obj) + kxdrproc_t encode, void *rqstp, __be32 *p, void *obj) { struct rpc_cred *cred = task->tk_msg.rpc_cred; struct gss_cred *gss_cred = container_of(cred, struct gss_cred, @@ -1132,7 +1133,7 @@ out: static inline int gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, - struct rpc_rqst *rqstp, u32 **p) + struct rpc_rqst *rqstp, __be32 **p) { struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; struct xdr_buf integ_buf; @@ -1169,7 +1170,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, static inline int gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, - struct rpc_rqst *rqstp, u32 **p) + struct rpc_rqst *rqstp, __be32 **p) { struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; u32 offset; @@ -1198,13 +1199,13 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, static int gss_unwrap_resp(struct rpc_task *task, - kxdrproc_t decode, void *rqstp, u32 *p, void *obj) + kxdrproc_t decode, void *rqstp, __be32 *p, void *obj) { struct rpc_cred *cred = task->tk_msg.rpc_cred; struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); - u32 *savedp = p; + __be32 *savedp = p; struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head; int savedlen = head->iov_len; int status = -EIO; diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 2f312164d6d5..08601ee4cd73 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -115,7 +115,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, krb5_hdr = ptr - 2; msg_start = krb5_hdr + 24; - *(u16 *)(krb5_hdr + 2) = htons(ctx->signalg); + *(__be16 *)(krb5_hdr + 2) = htons(ctx->signalg); memset(krb5_hdr + 4, 0xff, 4); if (make_checksum(checksum_type, krb5_hdr, 8, text, 0, &md5cksum)) diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index f179415d0c38..cc45c1605f80 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -177,9 +177,9 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, msg_start = krb5_hdr + 24; /* XXXJBF: */ BUG_ON(buf->head[0].iov_base + offset + headlen != msg_start + blocksize); - *(u16 *)(krb5_hdr + 2) = htons(kctx->signalg); + *(__be16 *)(krb5_hdr + 2) = htons(kctx->signalg); memset(krb5_hdr + 4, 0xff, 4); - *(u16 *)(krb5_hdr + 4) = htons(kctx->sealalg); + *(__be16 *)(krb5_hdr + 4) = htons(kctx->sealalg); make_confounder(msg_start, blocksize); diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index cd3d77ca3a31..a2587e8eef7b 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -640,7 +640,7 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o) */ static int gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, - u32 *rpcstart, struct rpc_gss_wire_cred *gc, u32 *authp) + __be32 *rpcstart, struct rpc_gss_wire_cred *gc, __be32 *authp) { struct gss_ctx *ctx_id = rsci->mechctx; struct xdr_buf rpchdr; @@ -687,7 +687,7 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, static int gss_write_null_verf(struct svc_rqst *rqstp) { - u32 *p; + __be32 *p; svc_putnl(rqstp->rq_res.head, RPC_AUTH_NULL); p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len; @@ -701,11 +701,11 @@ gss_write_null_verf(struct svc_rqst *rqstp) static int gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq) { - u32 xdr_seq; + __be32 xdr_seq; u32 maj_stat; struct xdr_buf verf_data; struct xdr_netobj mic; - u32 *p; + __be32 *p; struct kvec iov; svc_putnl(rqstp->rq_res.head, RPC_AUTH_GSS); @@ -782,7 +782,7 @@ EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor); static inline int read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) { - u32 raw; + __be32 raw; int status; status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj)); @@ -905,7 +905,7 @@ struct gss_svc_data { struct rpc_gss_wire_cred clcred; /* pointer to the beginning of the procedure-specific results, * which may be encrypted/checksummed in svcauth_gss_release: */ - u32 *body_start; + __be32 *body_start; struct rsc *rsci; }; @@ -946,7 +946,7 @@ gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip) * response here and return SVC_COMPLETE. */ static int -svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) +svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) { struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *resv = &rqstp->rq_res.head[0]; @@ -956,8 +956,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) struct rpc_gss_wire_cred *gc; struct rsc *rsci = NULL; struct rsi *rsip, rsikey; - u32 *rpcstart; - u32 *reject_stat = resv->iov_base + resv->iov_len; + __be32 *rpcstart; + __be32 *reject_stat = resv->iov_base + resv->iov_len; int ret; dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n",argv->iov_len); @@ -1156,7 +1156,7 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp) struct xdr_buf integ_buf; struct xdr_netobj mic; struct kvec *resv; - u32 *p; + __be32 *p; int integ_offset, integ_len; int stat = -EINVAL; @@ -1219,7 +1219,7 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp) struct rpc_gss_wire_cred *gc = &gsd->clcred; struct xdr_buf *resbuf = &rqstp->rq_res; struct page **inpages = NULL; - u32 *p; + __be32 *p; int offset, *len; int pad; @@ -1264,7 +1264,7 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp) return -ENOMEM; *len = htonl(resbuf->len - offset); pad = 3 - ((resbuf->len - offset - 1)&3); - p = (u32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len); + p = (__be32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len); memset(p, 0, pad); resbuf->tail[0].iov_len += pad; resbuf->len += pad; diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index 2eccffa96ba1..3be257dc32b2 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c @@ -60,8 +60,8 @@ nul_match(struct auth_cred *acred, struct rpc_cred *cred, int taskflags) /* * Marshal credential. */ -static u32 * -nul_marshal(struct rpc_task *task, u32 *p) +static __be32 * +nul_marshal(struct rpc_task *task, __be32 *p) { *p++ = htonl(RPC_AUTH_NULL); *p++ = 0; @@ -81,8 +81,8 @@ nul_refresh(struct rpc_task *task) return 0; } -static u32 * -nul_validate(struct rpc_task *task, u32 *p) +static __be32 * +nul_validate(struct rpc_task *task, __be32 *p) { rpc_authflavor_t flavor; u32 size; diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index 74c7406a1054..f7f990c9afe2 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -137,12 +137,12 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) * Marshal credentials. * Maybe we should keep a cached credential for performance reasons. */ -static u32 * -unx_marshal(struct rpc_task *task, u32 *p) +static __be32 * +unx_marshal(struct rpc_task *task, __be32 *p) { struct rpc_clnt *clnt = task->tk_client; struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred; - u32 *base, *hold; + __be32 *base, *hold; int i; *p++ = htonl(RPC_AUTH_UNIX); @@ -178,8 +178,8 @@ unx_refresh(struct rpc_task *task) return 0; } -static u32 * -unx_validate(struct rpc_task *task, u32 *p) +static __be32 * +unx_validate(struct rpc_task *task, __be32 *p) { rpc_authflavor_t flavor; u32 size; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 084a0ad5c64e..124ff0ceb55b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -60,8 +60,8 @@ static void call_refreshresult(struct rpc_task *task); static void call_timeout(struct rpc_task *task); static void call_connect(struct rpc_task *task); static void call_connect_status(struct rpc_task *task); -static u32 * call_header(struct rpc_task *task); -static u32 * call_verify(struct rpc_task *task); +static __be32 * call_header(struct rpc_task *task); +static __be32 * call_verify(struct rpc_task *task); static int @@ -782,7 +782,7 @@ call_encode(struct rpc_task *task) struct xdr_buf *rcvbuf = &req->rq_rcv_buf; unsigned int bufsiz; kxdrproc_t encode; - u32 *p; + __be32 *p; dprintk("RPC: %4d call_encode (status %d)\n", task->tk_pid, task->tk_status); @@ -1100,7 +1100,7 @@ call_decode(struct rpc_task *task) struct rpc_clnt *clnt = task->tk_client; struct rpc_rqst *req = task->tk_rqstp; kxdrproc_t decode = task->tk_msg.rpc_proc->p_decode; - u32 *p; + __be32 *p; dprintk("RPC: %4d call_decode (status %d)\n", task->tk_pid, task->tk_status); @@ -1197,12 +1197,12 @@ call_refreshresult(struct rpc_task *task) /* * Call header serialization */ -static u32 * +static __be32 * call_header(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; struct rpc_rqst *req = task->tk_rqstp; - u32 *p = req->rq_svec[0].iov_base; + __be32 *p = req->rq_svec[0].iov_base; /* FIXME: check buffer size? */ @@ -1221,12 +1221,13 @@ call_header(struct rpc_task *task) /* * Reply header verification */ -static u32 * +static __be32 * call_verify(struct rpc_task *task) { struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0]; int len = task->tk_rqstp->rq_rcv_buf.len >> 2; - u32 *p = iov->iov_base, n; + __be32 *p = iov->iov_base; + u32 n; int error = -EACCES; if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) { @@ -1303,7 +1304,7 @@ call_verify(struct rpc_task *task) printk(KERN_WARNING "call_verify: auth check failed\n"); goto out_garbage; /* bad verifier, retry */ } - len = p - (u32 *)iov->iov_base - 1; + len = p - (__be32 *)iov->iov_base - 1; if (len < 0) goto out_overflow; switch ((n = ntohl(*p++))) { @@ -1358,12 +1359,12 @@ out_overflow: goto out_garbage; } -static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj) +static int rpcproc_encode_null(void *rqstp, __be32 *data, void *obj) { return 0; } -static int rpcproc_decode_null(void *rqstp, u32 *data, void *obj) +static int rpcproc_decode_null(void *rqstp, __be32 *data, void *obj) { return 0; } diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index c04609d3476a..919d5ba7ca0a 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -300,7 +300,7 @@ static struct rpc_clnt *pmap_create(char *hostname, struct sockaddr_in *srvaddr, /* * XDR encode/decode functions for PMAP */ -static int xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct portmap_args *map) +static int xdr_encode_mapping(struct rpc_rqst *req, __be32 *p, struct portmap_args *map) { dprintk("RPC: xdr_encode_mapping(%u, %u, %u, %u)\n", map->pm_prog, map->pm_vers, map->pm_prot, map->pm_port); @@ -313,13 +313,13 @@ static int xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct portmap_args return 0; } -static int xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp) +static int xdr_decode_port(struct rpc_rqst *req, __be32 *p, unsigned short *portp) { *portp = (unsigned short) ntohl(*p++); return 0; } -static int xdr_decode_bool(struct rpc_rqst *req, u32 *p, unsigned int *boolp) +static int xdr_decode_bool(struct rpc_rqst *req, __be32 *p, unsigned int *boolp) { *boolp = (unsigned int) ntohl(*p++); return 0; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 6589e1ad47fa..44b8d9d4c18a 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -256,11 +256,11 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) struct kvec * argv = &rqstp->rq_arg.head[0]; struct kvec * resv = &rqstp->rq_res.head[0]; kxdrproc_t xdr; - u32 *statp; - u32 dir, prog, vers, proc, - auth_stat, rpc_stat; + __be32 *statp; + u32 dir, prog, vers, proc; + __be32 auth_stat, rpc_stat; int auth_res; - u32 *accept_statp; + __be32 *accept_statp; rpc_stat = rpc_success; diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index 3f4d1f622de8..8f2320aded5c 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c @@ -35,7 +35,7 @@ static struct auth_ops *authtab[RPC_AUTH_MAXFLAVOR] = { }; int -svc_authenticate(struct svc_rqst *rqstp, u32 *authp) +svc_authenticate(struct svc_rqst *rqstp, __be32 *authp) { rpc_authflavor_t flavor; struct auth_ops *aops; diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 27f443b44af8..f98229fb5e10 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -145,7 +145,7 @@ static void ip_map_request(struct cache_detail *cd, { char text_addr[20]; struct ip_map *im = container_of(h, struct ip_map, h); - __u32 addr = im->m_addr.s_addr; + __be32 addr = im->m_addr.s_addr; snprintf(text_addr, 20, "%u.%u.%u.%u", ntohl(addr) >> 24 & 0xff, @@ -410,7 +410,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) } static int -svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp) +svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) { struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *resv = &rqstp->rq_res.head[0]; @@ -472,7 +472,7 @@ struct auth_ops svcauth_null = { static int -svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp) +svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) { struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *resv = &rqstp->rq_res.head[0]; @@ -491,7 +491,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp) slen = XDR_QUADLEN(svc_getnl(argv)); /* machname length */ if (slen > 64 || (len -= (slen + 3)*4) < 0) goto badcred; - argv->iov_base = (void*)((u32*)argv->iov_base + slen); /* skip machname */ + argv->iov_base = (void*)((__be32*)argv->iov_base + slen); /* skip machname */ argv->iov_len -= slen*4; cred->cr_uid = svc_getnl(argv); /* uid */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 953aff89bcac..f09f7487051f 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1030,7 +1030,7 @@ svc_tcp_sendto(struct svc_rqst *rqstp) { struct xdr_buf *xbufp = &rqstp->rq_res; int sent; - u32 reclen; + __be32 reclen; /* Set up the first element of the reply kvec. * Any other kvecs that may be in use have been taken diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 6ac45103a272..9022eb8b37ed 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -18,8 +18,8 @@ /* * XDR functions for basic NFS types */ -u32 * -xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj) +__be32 * +xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj) { unsigned int quadlen = XDR_QUADLEN(obj->len); @@ -29,8 +29,8 @@ xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj) return p + XDR_QUADLEN(obj->len); } -u32 * -xdr_decode_netobj(u32 *p, struct xdr_netobj *obj) +__be32 * +xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj) { unsigned int len; @@ -55,7 +55,7 @@ xdr_decode_netobj(u32 *p, struct xdr_netobj *obj) * Returns the updated current XDR buffer position * */ -u32 *xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int nbytes) +__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int nbytes) { if (likely(nbytes != 0)) { unsigned int quadlen = XDR_QUADLEN(nbytes); @@ -79,21 +79,21 @@ EXPORT_SYMBOL(xdr_encode_opaque_fixed); * * Returns the updated current XDR buffer position */ -u32 *xdr_encode_opaque(u32 *p, const void *ptr, unsigned int nbytes) +__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int nbytes) { *p++ = htonl(nbytes); return xdr_encode_opaque_fixed(p, ptr, nbytes); } EXPORT_SYMBOL(xdr_encode_opaque); -u32 * -xdr_encode_string(u32 *p, const char *string) +__be32 * +xdr_encode_string(__be32 *p, const char *string) { return xdr_encode_array(p, string, strlen(string)); } -u32 * -xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen) +__be32 * +xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen) { unsigned int len; @@ -432,7 +432,7 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len) * of the buffer length, and takes care of adjusting the kvec * length for us. */ -void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) +void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p) { struct kvec *iov = buf->head; int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len; @@ -440,8 +440,8 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) BUG_ON(scratch_len < 0); xdr->buf = buf; xdr->iov = iov; - xdr->p = (uint32_t *)((char *)iov->iov_base + iov->iov_len); - xdr->end = (uint32_t *)((char *)iov->iov_base + scratch_len); + xdr->p = (__be32 *)((char *)iov->iov_base + iov->iov_len); + xdr->end = (__be32 *)((char *)iov->iov_base + scratch_len); BUG_ON(iov->iov_len > scratch_len); if (p != xdr->p && p != NULL) { @@ -465,10 +465,10 @@ EXPORT_SYMBOL(xdr_init_encode); * bytes of data. If so, update the total xdr_buf length, and * adjust the length of the current kvec. */ -uint32_t * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes) +__be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes) { - uint32_t *p = xdr->p; - uint32_t *q; + __be32 *p = xdr->p; + __be32 *q; /* align nbytes on the next 32-bit boundary */ nbytes += 3; @@ -524,7 +524,7 @@ EXPORT_SYMBOL(xdr_write_pages); * @buf: pointer to XDR buffer from which to decode data * @p: current pointer inside XDR buffer */ -void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) +void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p) { struct kvec *iov = buf->head; unsigned int len = iov->iov_len; @@ -534,7 +534,7 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) xdr->buf = buf; xdr->iov = iov; xdr->p = p; - xdr->end = (uint32_t *)((char *)iov->iov_base + len); + xdr->end = (__be32 *)((char *)iov->iov_base + len); } EXPORT_SYMBOL(xdr_init_decode); @@ -548,10 +548,10 @@ EXPORT_SYMBOL(xdr_init_decode); * If so return the current pointer, then update the current * pointer position. */ -uint32_t * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) +__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) { - uint32_t *p = xdr->p; - uint32_t *q = p + XDR_QUADLEN(nbytes); + __be32 *p = xdr->p; + __be32 *q = p + XDR_QUADLEN(nbytes); if (unlikely(q > xdr->end || q < p)) return NULL; @@ -599,8 +599,8 @@ void xdr_read_pages(struct xdr_stream *xdr, unsigned int len) * Position current pointer at beginning of tail, and * set remaining message length. */ - xdr->p = (uint32_t *)((char *)iov->iov_base + padding); - xdr->end = (uint32_t *)((char *)iov->iov_base + end); + xdr->p = (__be32 *)((char *)iov->iov_base + padding); + xdr->end = (__be32 *)((char *)iov->iov_base + end); } EXPORT_SYMBOL(xdr_read_pages); @@ -624,8 +624,8 @@ void xdr_enter_page(struct xdr_stream *xdr, unsigned int len) */ if (len > PAGE_CACHE_SIZE - xdr->buf->page_base) len = PAGE_CACHE_SIZE - xdr->buf->page_base; - xdr->p = (uint32_t *)(kaddr + xdr->buf->page_base); - xdr->end = (uint32_t *)((char *)xdr->p + len); + xdr->p = (__be32 *)(kaddr + xdr->buf->page_base); + xdr->end = (__be32 *)((char *)xdr->p + len); } EXPORT_SYMBOL(xdr_enter_page); @@ -743,7 +743,7 @@ out: int xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj) { - u32 raw; + __be32 raw; int status; status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj)); @@ -756,7 +756,7 @@ xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj) int xdr_encode_word(struct xdr_buf *buf, int base, u32 obj) { - u32 raw = htonl(obj); + __be32 raw = htonl(obj); return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj)); } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 1f786f68729d..80857470dc11 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -594,7 +594,7 @@ static void xprt_connect_status(struct rpc_task *task) * @xid: RPC XID of incoming reply * */ -struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) +struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid) { struct list_head *pos; @@ -801,7 +801,7 @@ void xprt_reserve(struct rpc_task *task) spin_unlock(&xprt->reserve_lock); } -static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt) +static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt) { return xprt->xid++; } diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 9b62923a9c06..28100e019225 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -548,7 +548,8 @@ static void xs_udp_data_ready(struct sock *sk, int len) struct rpc_rqst *rovr; struct sk_buff *skb; int err, repsize, copied; - u32 _xid, *xp; + u32 _xid; + __be32 *xp; read_lock(&sk->sk_callback_lock); dprintk("RPC: xs_udp_data_ready...\n"); -- cgit v1.2.3 From 126a336822a6594662f5898f1ddf33e6d048fcc7 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 27 Sep 2006 16:03:07 -0700 Subject: [TG3]: Add 5722 and 5756 support. Add IDs to support 5722 and 5756. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 +++ drivers/net/tg3.h | 4 +++- include/linux/pci_ids.h | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 14e964524969..d443b7372325 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -173,6 +173,7 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5722)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M)}, @@ -187,6 +188,7 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5756)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M)}, @@ -11273,6 +11275,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5780: return "5780"; case PHY_ID_BCM5755: return "5755"; case PHY_ID_BCM5787: return "5787"; + case PHY_ID_BCM5756: return "5722/5756"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index f7462c2ccc0a..feed13dc8719 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2282,6 +2282,7 @@ struct tg3 { #define PHY_ID_BCM5780 0x60008350 #define PHY_ID_BCM5755 0xbc050cc0 #define PHY_ID_BCM5787 0xbc050ce0 +#define PHY_ID_BCM5756 0xbc050ed0 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff #define PHY_ID_REV_MASK 0x0000000f @@ -2308,7 +2309,8 @@ struct tg3 { (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \ (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \ - (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \ + (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 61db1907f06f..ea3140d226e6 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1904,6 +1904,7 @@ #define PCI_DEVICE_ID_TIGON3_5705_2 0x1654 #define PCI_DEVICE_ID_TIGON3_5720 0x1658 #define PCI_DEVICE_ID_TIGON3_5721 0x1659 +#define PCI_DEVICE_ID_TIGON3_5722 0x165a #define PCI_DEVICE_ID_TIGON3_5705M 0x165d #define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e #define PCI_DEVICE_ID_TIGON3_5714 0x1668 @@ -1913,6 +1914,7 @@ #define PCI_DEVICE_ID_TIGON3_5705F 0x166e #define PCI_DEVICE_ID_TIGON3_5754M 0x1672 #define PCI_DEVICE_ID_TIGON3_5755M 0x1673 +#define PCI_DEVICE_ID_TIGON3_5756 0x1674 #define PCI_DEVICE_ID_TIGON3_5750 0x1676 #define PCI_DEVICE_ID_TIGON3_5751 0x1677 #define PCI_DEVICE_ID_TIGON3_5715 0x1678 -- cgit v1.2.3 From b5d3772ccbe0bc5ac8ffbb5356b74ca698aee28c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 27 Sep 2006 16:06:21 -0700 Subject: [TG3]: Add basic 5906 support. Add support for the new 5709 device. This is a new 10/100 Mbps chip. The mailbox access and firmware interface are quite different from all other tg3 chips. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 126 +++++++++++++++++++++++++++++++++++++++++++----- drivers/net/tg3.h | 28 +++++++++-- include/linux/pci_ids.h | 2 + 3 files changed, 141 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index eafca2a0dd00..2b062d776511 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -199,6 +199,8 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -426,6 +428,16 @@ static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val) readl(mbox); } +static u32 tg3_read32_mbox_5906(struct tg3 *tp, u32 off) +{ + return (readl(tp->regs + off + GRCMBOX_BASE)); +} + +static void tg3_write32_mbox_5906(struct tg3 *tp, u32 off, u32 val) +{ + writel(val, tp->regs + off + GRCMBOX_BASE); +} + #define tw32_mailbox(reg, val) tp->write32_mbox(tp, reg, val) #define tw32_mailbox_f(reg, val) tw32_mailbox_flush(tp, (reg), (val)) #define tw32_rx_mbox(reg, val) tp->write32_rx_mbox(tp, reg, val) @@ -441,6 +453,10 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) { unsigned long flags; + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) && + (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) + return; + spin_lock_irqsave(&tp->indirect_lock, flags); if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); @@ -462,6 +478,12 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) { unsigned long flags; + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) && + (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) { + *val = 0; + return; + } + spin_lock_irqsave(&tp->indirect_lock, flags); if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); @@ -491,6 +513,9 @@ static inline void tg3_cond_int(struct tg3 *tp) if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && (tp->hw_status->status & SD_STATUS_UPDATED)) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); + else + tw32(HOSTCC_MODE, tp->coalesce_mode | + (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); } static void tg3_enable_ints(struct tg3 *tp) @@ -656,6 +681,10 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) unsigned int loops; int ret; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 && + (reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL)) + return 0; + if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { tw32_f(MAC_MI_MODE, (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); @@ -1207,7 +1236,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tg3_setup_phy(tp, 0); } - if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + u32 val; + + val = tr32(GRC_VCPU_EXT_CTRL); + tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_DISABLE_WOL); + } else if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { int i; u32 val; @@ -4667,6 +4701,15 @@ static int tg3_poll_fw(struct tg3 *tp) int i; u32 val; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + for (i = 0; i < 400; i++) { + if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE) + return 0; + udelay(10); + } + return -ENODEV; + } + /* Wait for firmware initialization to complete. */ for (i = 0; i < 100000; i++) { tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val); @@ -4735,6 +4778,12 @@ static int tg3_chip_reset(struct tg3 *tp) } } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + tw32(VCPU_STATUS, tr32(VCPU_STATUS) | VCPU_STATUS_DRV_RESET); + tw32(GRC_VCPU_EXT_CTRL, + tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU); + } + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) val |= GRC_MISC_CFG_KEEP_GPHY_POWER; tw32(GRC_MISC_CFG, val); @@ -5066,6 +5115,12 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset) BUG_ON(offset == TX_CPU_BASE && (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + u32 val = tr32(GRC_VCPU_EXT_CTRL); + + tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU); + return 0; + } if (offset == RX_CPU_BASE) { for (i = 0; i < 10000; i++) { tw32(offset + CPU_STATE, 0xffffffff); @@ -6070,6 +6125,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) val = 1; else if (val > tp->rx_std_max_post) val = tp->rx_std_max_post; + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1) + tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2); + + if (val > (TG3_RX_INTERNAL_RING_SZ_5906 / 2)) + val = TG3_RX_INTERNAL_RING_SZ_5906 / 2; + } tw32(RCVBDI_STD_THRESH, val); @@ -6984,9 +7046,10 @@ static int tg3_open(struct net_device *dev) if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) { - u32 val = tr32(0x7c04); + u32 val = tr32(PCIE_TRANSACTION_CFG); - tw32(0x7c04, val | (1 << 29)); + tw32(PCIE_TRANSACTION_CFG, + val | PCIE_TRANS_CFG_1SHOT_MSI); } } } @@ -7941,7 +8004,8 @@ static int tg3_set_tso(struct net_device *dev, u32 value) return -EINVAL; return 0; } - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) { + if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) { if (value) dev->features |= NETIF_F_TSO6; else @@ -9257,6 +9321,13 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) } } +static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp) +{ + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; +} + /* Chips other than 5700/5701 use the NVRAM for fetching info. */ static void __devinit tg3_nvram_init(struct tg3 *tp) { @@ -9293,6 +9364,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_5755_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) tg3_get_5787_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + tg3_get_5906_nvram_info(tp); else tg3_get_nvram_info(tp); @@ -9766,6 +9839,12 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) /* Assume an onboard device by default. */ tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM)) + tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; + return; + } + tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg, led_cfg; @@ -10097,7 +10176,10 @@ static void __devinit tg3_read_partno(struct tg3 *tp) } out_not_found: - strcpy(tp->board_part_number, "none"); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + strcpy(tp->board_part_number, "BCM95906"); + else + strcpy(tp->board_part_number, "none"); } static void __devinit tg3_read_fw_ver(struct tg3 *tp) @@ -10299,6 +10381,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -10308,7 +10391,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; } else { @@ -10325,7 +10409,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0) @@ -10455,6 +10540,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_cmd &= ~PCI_COMMAND_MEMORY; pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + tp->read32_mbox = tg3_read32_mbox_5906; + tp->write32_mbox = tg3_write32_mbox_5906; + tp->write32_tx_mbox = tg3_write32_mbox_5906; + tp->write32_rx_mbox = tg3_write32_mbox_5906; + } if (tp->write32 == tg3_write_indirect_reg32 || ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && @@ -10526,6 +10617,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) && (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) && (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) || (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED; @@ -10539,7 +10631,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; - else + else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; } @@ -10629,7 +10721,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) || (tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM && (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F || - tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F))) + tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->tg3_flags |= TG3_FLAG_10_100_ONLY; err = tg3_phy_probe(tp); @@ -10680,7 +10773,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * straddle the 4GB address boundary in some cases. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->dev->hard_start_xmit = tg3_start_xmit; else tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug; @@ -10761,6 +10855,8 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) else tg3_nvram_unlock(tp); } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + mac_offset = 0x10; /* First try to get it from MAC address mailbox. */ tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi); @@ -11244,6 +11340,12 @@ static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) DEFAULT_MB_MACRX_LOW_WATER_5705; tp->bufmgr_config.mbuf_high_water = DEFAULT_MB_HIGH_WATER_5705; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + tp->bufmgr_config.mbuf_mac_rx_low_water = + DEFAULT_MB_MACRX_LOW_WATER_5906; + tp->bufmgr_config.mbuf_high_water = + DEFAULT_MB_HIGH_WATER_5906; + } tp->bufmgr_config.mbuf_read_dma_low_water_jumbo = DEFAULT_MB_RDMA_LOW_WATER_JUMBO_5780; @@ -11288,6 +11390,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5755: return "5755"; case PHY_ID_BCM5787: return "5787"; case PHY_ID_BCM5756: return "5722/5756"; + case PHY_ID_BCM5906: return "5906"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; @@ -11590,7 +11693,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, */ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { dev->features |= NETIF_F_TSO; - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) + if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) dev->features |= NETIF_F_TSO6; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index feed13dc8719..2f5e00c96016 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -24,6 +24,8 @@ #define RX_COPY_THRESHOLD 256 +#define TG3_RX_INTERNAL_RING_SZ_5906 32 + #define RX_STD_MAX_SIZE 1536 #define RX_STD_MAX_SIZE_5705 512 #define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */ @@ -129,6 +131,7 @@ #define CHIPREV_ID_5752_A0_HW 0x5000 #define CHIPREV_ID_5752_A0 0x6000 #define CHIPREV_ID_5752_A1 0x6001 +#define CHIPREV_ID_5906_A1 0xc001 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -141,6 +144,7 @@ #define ASIC_REV_5714 0x09 #define ASIC_REV_5755 0x0a #define ASIC_REV_5787 0x0b +#define ASIC_REV_5906 0x0c #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -646,7 +650,8 @@ #define SNDDATAI_SCTRL_FORCE_ZERO 0x00000010 #define SNDDATAI_STATSENAB 0x00000c0c #define SNDDATAI_STATSINCMASK 0x00000c10 -/* 0xc14 --> 0xc80 unused */ +#define ISO_PKT_TX 0x00000c20 +/* 0xc24 --> 0xc80 unused */ #define SNDDATAI_COS_CNT_0 0x00000c80 #define SNDDATAI_COS_CNT_1 0x00000c84 #define SNDDATAI_COS_CNT_2 0x00000c88 @@ -997,11 +1002,13 @@ #define BUFMGR_MB_MACRX_LOW_WATER 0x00004414 #define DEFAULT_MB_MACRX_LOW_WATER 0x00000020 #define DEFAULT_MB_MACRX_LOW_WATER_5705 0x00000010 +#define DEFAULT_MB_MACRX_LOW_WATER_5906 0x00000004 #define DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098 #define DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780 0x0000004b #define BUFMGR_MB_HIGH_WATER 0x00004418 #define DEFAULT_MB_HIGH_WATER 0x00000060 #define DEFAULT_MB_HIGH_WATER_5705 0x00000060 +#define DEFAULT_MB_HIGH_WATER_5906 0x00000010 #define DEFAULT_MB_HIGH_WATER_JUMBO 0x0000017c #define DEFAULT_MB_HIGH_WATER_JUMBO_5780 0x00000096 #define BUFMGR_RX_MB_ALLOC_REQ 0x0000441c @@ -1138,7 +1145,12 @@ #define TX_CPU_STATE 0x00005404 #define TX_CPU_PGMCTR 0x0000541c +#define VCPU_STATUS 0x00005100 +#define VCPU_STATUS_INIT_DONE 0x04000000 +#define VCPU_STATUS_DRV_RESET 0x08000000 + /* Mailboxes */ +#define GRCMBOX_BASE 0x00005600 #define GRCMBOX_INTERRUPT_0 0x00005800 /* 64-bit */ #define GRCMBOX_INTERRUPT_1 0x00005808 /* 64-bit */ #define GRCMBOX_INTERRUPT_2 0x00005810 /* 64-bit */ @@ -1398,7 +1410,10 @@ #define GRC_EEPROM_CTRL 0x00006840 #define GRC_MDI_CTRL 0x00006844 #define GRC_SEEPROM_DELAY 0x00006848 -/* 0x684c --> 0x6c00 unused */ +/* 0x684c --> 0x6890 unused */ +#define GRC_VCPU_EXT_CTRL 0x00006890 +#define GRC_VCPU_EXT_CTRL_HALT_CPU 0x00400000 +#define GRC_VCPU_EXT_CTRL_DISABLE_WOL 0x20000000 #define GRC_FASTBOOT_PC 0x00006894 /* 5752, 5755, 5787 */ /* 0x6c00 --> 0x7000 unused */ @@ -1485,7 +1500,11 @@ #define NVRAM_WRITE1 0x00007028 /* 0x702c --> 0x7400 unused */ -/* 0x7400 --> 0x8000 unused */ +/* 0x7400 --> 0x7c00 unused */ +#define PCIE_TRANSACTION_CFG 0x00007c04 +#define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000 +#define PCIE_TRANS_CFG_LOM 0x00000020 + #define TG3_EEPROM_MAGIC 0x669955aa @@ -2283,6 +2302,7 @@ struct tg3 { #define PHY_ID_BCM5755 0xbc050cc0 #define PHY_ID_BCM5787 0xbc050ce0 #define PHY_ID_BCM5756 0xbc050ed0 +#define PHY_ID_BCM5906 0xdc00ac40 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff #define PHY_ID_REV_MASK 0x0000000f @@ -2310,7 +2330,7 @@ struct tg3 { (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \ (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \ - (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ea3140d226e6..b7e85ff045ea 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1944,6 +1944,8 @@ #define PCI_DEVICE_ID_TIGON3_5901 0x170d #define PCI_DEVICE_ID_BCM4401B1 0x170c #define PCI_DEVICE_ID_TIGON3_5901_2 0x170e +#define PCI_DEVICE_ID_TIGON3_5906 0x1712 +#define PCI_DEVICE_ID_TIGON3_5906M 0x1713 #define PCI_DEVICE_ID_BCM4401 0x4401 #define PCI_DEVICE_ID_BCM4401B0 0x4402 -- cgit v1.2.3 From 00a5020cd51febbb3166ff7a09a2901c47ba251a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:29:47 -0700 Subject: [IPV4]: annotate ipv4 address fields in struct ip_msfilter and struct ip_mreq_source Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/in.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/in.h b/include/linux/in.h index bcaca8399aed..d79fc75fa7c2 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -123,17 +123,17 @@ struct ip_mreqn }; struct ip_mreq_source { - __u32 imr_multiaddr; - __u32 imr_interface; - __u32 imr_sourceaddr; + __be32 imr_multiaddr; + __be32 imr_interface; + __be32 imr_sourceaddr; }; struct ip_msfilter { - __u32 imsf_multiaddr; - __u32 imsf_interface; + __be32 imsf_multiaddr; + __be32 imsf_interface; __u32 imsf_fmode; __u32 imsf_numsrc; - __u32 imsf_slist[1]; + __be32 imsf_slist[1]; }; #define IP_MSFILTER_SIZE(numsrc) \ -- cgit v1.2.3 From 8f935bbd7c6c66796c2403aefdab74bb48045bf6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:30:07 -0700 Subject: [IPV4]: ip_mc_{inc,dec}_group() annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/igmp.h | 4 ++-- net/ipv4/igmp.c | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 8e7eedb3a574..dd49ba9065ae 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -215,7 +215,7 @@ extern void ip_mc_init_dev(struct in_device *); extern void ip_mc_destroy_dev(struct in_device *); extern void ip_mc_up(struct in_device *); extern void ip_mc_down(struct in_device *); -extern void ip_mc_dec_group(struct in_device *in_dev, u32 addr); -extern void ip_mc_inc_group(struct in_device *in_dev, u32 addr); +extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr); +extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr); #endif #endif diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d8068c483781..a2e733a82de2 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -144,8 +144,8 @@ static int sf_setstate(struct ip_mc_list *pmc); static void sf_markstate(struct ip_mc_list *pmc); #endif static void ip_mc_clear_src(struct ip_mc_list *pmc); -static int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode, - int sfcount, __u32 *psfsrc, int delta); +static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, + int sfcount, __be32 *psfsrc, int delta); static void ip_ma_put(struct ip_mc_list *im) { @@ -1193,7 +1193,7 @@ static void igmp_group_added(struct ip_mc_list *im) * A socket has joined a multicast group on device dev. */ -void ip_mc_inc_group(struct in_device *in_dev, u32 addr) +void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) { struct ip_mc_list *im; @@ -1252,7 +1252,7 @@ out: * A socket has left a multicast group on device dev */ -void ip_mc_dec_group(struct in_device *in_dev, u32 addr) +void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) { struct ip_mc_list *i, **ip; @@ -1402,7 +1402,7 @@ int sysctl_igmp_max_msf __read_mostly = IP_MAX_MSF; static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode, - __u32 *psfsrc) + __be32 *psfsrc) { struct ip_sf_list *psf, *psf_prev; int rv = 0; @@ -1450,8 +1450,8 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode, #define igmp_ifc_event(x) do { } while (0) #endif -static int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode, - int sfcount, __u32 *psfsrc, int delta) +static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode, + int sfcount, __be32 *psfsrc, int delta) { struct ip_mc_list *pmc; int changerec = 0; @@ -1517,7 +1517,7 @@ out_unlock: * Add multicast single-source filter to the interface list */ static int ip_mc_add1_src(struct ip_mc_list *pmc, int sfmode, - __u32 *psfsrc, int delta) + __be32 *psfsrc, int delta) { struct ip_sf_list *psf, *psf_prev; @@ -1623,8 +1623,8 @@ static int sf_setstate(struct ip_mc_list *pmc) /* * Add multicast source filter list to the interface list */ -static int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode, - int sfcount, __u32 *psfsrc, int delta) +static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, + int sfcount, __be32 *psfsrc, int delta) { struct ip_mc_list *pmc; int isexclude; @@ -1717,7 +1717,7 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc) int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) { int err; - u32 addr = imr->imr_multiaddr.s_addr; + __be32 addr = imr->imr_multiaddr.s_addr; struct ip_mc_socklist *iml=NULL, *i; struct in_device *in_dev; struct inet_sock *inet = inet_sk(sk); @@ -1791,7 +1791,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) struct inet_sock *inet = inet_sk(sk); struct ip_mc_socklist *iml, **imlp; struct in_device *in_dev; - u32 group = imr->imr_multiaddr.s_addr; + __be32 group = imr->imr_multiaddr.s_addr; u32 ifindex; int ret = -EADDRNOTAVAIL; -- cgit v1.2.3 From 942bf921e922560c05fde6afb00ddedf6224c608 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:30:28 -0700 Subject: [IPV4]: IGMP on-the-wire data is net-endian Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/igmp.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index dd49ba9065ae..fd207d9b2733 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -30,8 +30,8 @@ struct igmphdr { __u8 type; __u8 code; /* For newer IGMP */ - __u16 csum; - __u32 group; + __be16 csum; + __be32 group; }; /* V3 group record types [grec_type] */ @@ -45,25 +45,25 @@ struct igmphdr struct igmpv3_grec { __u8 grec_type; __u8 grec_auxwords; - __u16 grec_nsrcs; - __u32 grec_mca; - __u32 grec_src[0]; + __be16 grec_nsrcs; + __be32 grec_mca; + __be32 grec_src[0]; }; struct igmpv3_report { __u8 type; __u8 resv1; - __u16 csum; - __u16 resv2; - __u16 ngrec; + __be16 csum; + __be16 resv2; + __be16 ngrec; struct igmpv3_grec grec[0]; }; struct igmpv3_query { __u8 type; __u8 code; - __u16 csum; - __u32 group; + __be16 csum; + __be32 group; #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 qrv:3, suppress:1, @@ -76,8 +76,8 @@ struct igmpv3_query { #error "Please fix " #endif __u8 qqic; - __u16 nsrcs; - __u32 srcs[0]; + __be16 nsrcs; + __be32 srcs[0]; }; #define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */ -- cgit v1.2.3 From ea4d9e7220d32348cc9742ba6d27de5165262664 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:30:52 -0700 Subject: [IPV4]: struct ip_sf_list and struct ip_sf_socklist annotated Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/igmp.h | 4 ++-- net/ipv4/igmp.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index fd207d9b2733..4e9f3fe77cf9 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -136,7 +136,7 @@ struct ip_sf_socklist { unsigned int sl_max; unsigned int sl_count; - __u32 sl_addr[0]; + __be32 sl_addr[0]; }; #define IP_SFLSIZE(count) (sizeof(struct ip_sf_socklist) + \ @@ -159,7 +159,7 @@ struct ip_mc_socklist struct ip_sf_list { struct ip_sf_list *sf_next; - __u32 sf_inaddr; + __be32 sf_inaddr; unsigned long sf_count[2]; /* include/exclude counts */ unsigned char sf_gsresp; /* include in g & s response? */ unsigned char sf_oldin; /* change state */ diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a2e733a82de2..f6ca51a2dcc2 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -426,7 +426,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, first = 1; psf_prev = NULL; for (psf=*psf_list; psf; psf=psf_next) { - u32 *psrc; + __be32 *psrc; psf_next = psf->sf_next; @@ -455,7 +455,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, skb = add_grhead(skb, pmc, type, &pgr); first = 0; } - psrc = (u32 *)skb_put(skb, sizeof(u32)); + psrc = (__be32 *)skb_put(skb, sizeof(u32)); *psrc = psf->sf_inaddr; scount++; stotal++; if ((type == IGMPV3_ALLOW_NEW_SOURCES || @@ -748,7 +748,7 @@ static void igmp_timer_expire(unsigned long data) } /* mark EXCLUDE-mode sources */ -static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs) +static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs) { struct ip_sf_list *psf; int i, scount; @@ -775,7 +775,7 @@ static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs) return 1; } -static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs) +static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs) { struct ip_sf_list *psf; int i, scount; -- cgit v1.2.3 From c0cda068aac3481d40795b115e4fd36f7d386e3a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:31:10 -0700 Subject: [IPV4]: ip_mc_sf_allow() annotated ip_mc_sf_allow() expects addresses to be passed net-endian. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/igmp.h | 2 +- net/ipv4/igmp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 4e9f3fe77cf9..7514cceb4fe3 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -209,7 +209,7 @@ extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, struct ip_msfilter __user *optval, int __user *optlen); extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, struct group_filter __user *optval, int __user *optlen); -extern int ip_mc_sf_allow(struct sock *sk, u32 local, u32 rmt, int dif); +extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif); extern void ip_mr_init(void); extern void ip_mc_init_dev(struct in_device *); extern void ip_mc_destroy_dev(struct in_device *); diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index f6ca51a2dcc2..a2c7b2b1b3fb 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2156,7 +2156,7 @@ done: /* * check if a multicast source filter allows delivery for a given */ -int ip_mc_sf_allow(struct sock *sk, u32 loc_addr, u32 rmt_addr, int dif) +int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) { struct inet_sock *inet = inet_sk(sk); struct ip_mc_socklist *pmc; -- cgit v1.2.3 From 63007727e0bb09e8d906f73d36a09b9fac0d5893 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:31:32 -0700 Subject: [IPV4]: trivial igmp annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/igmp.h | 2 +- net/ipv4/igmp.c | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 7514cceb4fe3..03f43e2893a4 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -140,7 +140,7 @@ struct ip_sf_socklist }; #define IP_SFLSIZE(count) (sizeof(struct ip_sf_socklist) + \ - (count) * sizeof(__u32)) + (count) * sizeof(__be32)) #define IP_SFBLOCK 10 /* allocate this many at once */ diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a2c7b2b1b3fb..6eee71647b7c 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -138,7 +138,7 @@ time_before(jiffies, (in_dev)->mr_v2_seen))) static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im); -static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr); +static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr); static void igmpv3_clear_delrec(struct in_device *in_dev); static int sf_setstate(struct ip_mc_list *pmc); static void sf_markstate(struct ip_mc_list *pmc); @@ -439,7 +439,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, if (isquery) psf->sf_gsresp = 0; - if (AVAILABLE(skb) < sizeof(u32) + + if (AVAILABLE(skb) < sizeof(__be32) + first*sizeof(struct igmpv3_grec)) { if (truncate && !first) break; /* truncate these */ @@ -455,7 +455,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, skb = add_grhead(skb, pmc, type, &pgr); first = 0; } - psrc = (__be32 *)skb_put(skb, sizeof(u32)); + psrc = (__be32 *)skb_put(skb, sizeof(__be32)); *psrc = psf->sf_inaddr; scount++; stotal++; if ((type == IGMPV3_ALLOW_NEW_SOURCES || @@ -630,8 +630,8 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, struct igmphdr *ih; struct rtable *rt; struct net_device *dev = in_dev->dev; - u32 group = pmc ? pmc->multiaddr : 0; - u32 dst; + __be32 group = pmc ? pmc->multiaddr : 0; + __be32 dst; if (type == IGMPV3_HOST_MEMBERSHIP_REPORT) return igmpv3_send_report(in_dev, pmc); @@ -803,7 +803,7 @@ static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs) return 1; } -static void igmp_heard_report(struct in_device *in_dev, u32 group) +static void igmp_heard_report(struct in_device *in_dev, __be32 group) { struct ip_mc_list *im; @@ -828,7 +828,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, struct igmphdr *ih = skb->h.igmph; struct igmpv3_query *ih3 = (struct igmpv3_query *)ih; struct ip_mc_list *im; - u32 group = ih->group; + __be32 group = ih->group; int max_delay; int mark = 0; @@ -862,7 +862,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, ih3 = (struct igmpv3_query *) skb->h.raw; if (ih3->nsrcs) { if (!pskb_may_pull(skb, sizeof(struct igmpv3_query) - + ntohs(ih3->nsrcs)*sizeof(__u32))) + + ntohs(ih3->nsrcs)*sizeof(__be32))) return; ih3 = (struct igmpv3_query *) skb->h.raw; } @@ -985,7 +985,7 @@ drop: * Add a filter to a device */ -static void ip_mc_filter_add(struct in_device *in_dev, u32 addr) +static void ip_mc_filter_add(struct in_device *in_dev, __be32 addr) { char buf[MAX_ADDR_LEN]; struct net_device *dev = in_dev->dev; @@ -1005,7 +1005,7 @@ static void ip_mc_filter_add(struct in_device *in_dev, u32 addr) * Remove a filter from a device */ -static void ip_mc_filter_del(struct in_device *in_dev, u32 addr) +static void ip_mc_filter_del(struct in_device *in_dev, __be32 addr) { char buf[MAX_ADDR_LEN]; struct net_device *dev = in_dev->dev; @@ -1055,7 +1055,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im) spin_unlock_bh(&in_dev->mc_tomb_lock); } -static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr) +static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr) { struct ip_mc_list *pmc, *pmc_prev; struct ip_sf_list *psf, *psf_next; @@ -1829,7 +1829,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct { int err; struct ip_mreqn imr; - u32 addr = mreqs->imr_multiaddr; + __be32 addr = mreqs->imr_multiaddr; struct ip_mc_socklist *pmc; struct in_device *in_dev = NULL; struct inet_sock *inet = inet_sk(sk); @@ -1883,7 +1883,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct rv = !0; for (i=0; isl_count; i++) { rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr, - sizeof(__u32)); + sizeof(__be32)); if (rv == 0) break; } @@ -1935,7 +1935,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct rv = 1; /* > 0 for insert logic below if sl_count is 0 */ for (i=0; isl_count; i++) { rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr, - sizeof(__u32)); + sizeof(__be32)); if (rv == 0) break; } @@ -1960,7 +1960,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) { int err = 0; struct ip_mreqn imr; - u32 addr = msf->imsf_multiaddr; + __be32 addr = msf->imsf_multiaddr; struct ip_mc_socklist *pmc; struct in_device *in_dev; struct inet_sock *inet = inet_sk(sk); @@ -2044,7 +2044,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, { int err, len, count, copycount; struct ip_mreqn imr; - u32 addr = msf->imsf_multiaddr; + __be32 addr = msf->imsf_multiaddr; struct ip_mc_socklist *pmc; struct in_device *in_dev; struct inet_sock *inet = inet_sk(sk); @@ -2103,7 +2103,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, { int err, i, count, copycount; struct sockaddr_in *psin; - u32 addr; + __be32 addr; struct ip_mc_socklist *pmc; struct inet_sock *inet = inet_sk(sk); struct ip_sf_socklist *psl; -- cgit v1.2.3 From 46a97324a5ebdc1e343a0223d993e79551adab0f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:31:51 -0700 Subject: [IPV4]: TCP headers annotated Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/tcp.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 8ebf497907f8..543f06371840 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -21,10 +21,10 @@ #include struct tcphdr { - __u16 source; - __u16 dest; - __u32 seq; - __u32 ack_seq; + __be16 source; + __be16 dest; + __be32 seq; + __be32 ack_seq; #if defined(__LITTLE_ENDIAN_BITFIELD) __u16 res1:4, doff:4, @@ -50,9 +50,9 @@ struct tcphdr { #else #error "Adjust your defines" #endif - __u16 window; - __u16 check; - __u16 urg_ptr; + __be16 window; + __be16 check; + __be16 urg_ptr; }; /* @@ -62,7 +62,7 @@ struct tcphdr { */ union tcp_word_hdr { struct tcphdr hdr; - __u32 words[5]; + __be32 words[5]; }; #define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3]) -- cgit v1.2.3 From 269bd27e66037a7932cee6d6aa7ef7defd0bfe38 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:32:28 -0700 Subject: [TCP]: struct tcp_sack_block annotations Some of the instances of tcp_sack_block are host-endian, some - net-endian. Define struct tcp_sack_block_wire identical to struct tcp_sack_block with u32 replaced with __be32; annotate uses of tcp_sack_block replacing net-endian ones with tcp_sack_block_wire. Change is obviously safe since for cc(1) __be32 is typedefed to u32. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/tcp.h | 5 +++++ net/ipv4/netfilter/ip_nat_helper.c | 2 +- net/ipv4/tcp_input.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 543f06371840..9632aa866de4 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -166,6 +166,11 @@ struct tcp_info #include /* This defines a selective acknowledgement block. */ +struct tcp_sack_block_wire { + __be32 start_seq; + __be32 end_seq; +}; + struct tcp_sack_block { __u32 start_seq; __u32 end_seq; diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index 7f6a75984f6c..e9c5187ea5b2 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c @@ -283,7 +283,7 @@ sack_adjust(struct sk_buff *skb, struct ip_nat_seq *natseq) { while (sackoff < sackend) { - struct tcp_sack_block *sack; + struct tcp_sack_block_wire *sack; u_int32_t new_start_seq, new_end_seq; sack = (void *)skb->data + sackoff; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b3def0df14fb..46984ffd73cd 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -935,7 +935,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ const struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); unsigned char *ptr = ack_skb->h.raw + TCP_SKB_CB(ack_skb)->sacked; - struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2); + struct tcp_sack_block_wire *sp = (struct tcp_sack_block_wire *)(ptr+2); int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; int reord = tp->packets_out; int prior_fackets; -- cgit v1.2.3 From dddc93c05d7dba60b44866486502c155e96ab915 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:32:46 -0700 Subject: [TCP]: struct tcp_sock .pred_flags is net-endian Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/tcp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 9632aa866de4..0e058a2d1c6d 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -216,7 +216,7 @@ struct tcp_sock { * Header prediction flags * 0x5?10 << 16 + snd_wnd in net byte order */ - __u32 pred_flags; + __be32 pred_flags; /* * RFC793 variables by their proper names. This means you can -- cgit v1.2.3 From b406313c733156c8eea7d9c1891476f400914367 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:34:02 -0700 Subject: [NET]: struct sock_exterr_skb annotations ->port is net-endian Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/errqueue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/errqueue.h b/include/linux/errqueue.h index 408118a07763..92f8d4fab32b 100644 --- a/include/linux/errqueue.h +++ b/include/linux/errqueue.h @@ -38,7 +38,7 @@ struct sock_exterr_skb } header; struct sock_extended_err ee; u16 addr_offset; - u16 port; + __be16 port; }; #endif -- cgit v1.2.3 From bd6d610a14f2ed896b76dfb61fbdec829e44b8d3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:35:47 -0700 Subject: [IPV4]: ARP header annotated Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/if_arp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index a8b1a2071838..7f5714214ee3 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -130,11 +130,11 @@ struct arpreq_old { struct arphdr { - unsigned short ar_hrd; /* format of hardware address */ - unsigned short ar_pro; /* format of protocol address */ + __be16 ar_hrd; /* format of hardware address */ + __be16 ar_pro; /* format of protocol address */ unsigned char ar_hln; /* length of hardware address */ unsigned char ar_pln; /* length of protocol address */ - unsigned short ar_op; /* ARP opcode (command) */ + __be16 ar_op; /* ARP opcode (command) */ #if 0 /* -- cgit v1.2.3 From 4e7e0c7592cafe5453e5b2f115fc0065d11b3d44 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:37:19 -0700 Subject: [IPV4]: UDP header annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/udp.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/udp.h b/include/linux/udp.h index 90223f057d50..014b41d1e308 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -20,10 +20,10 @@ #include struct udphdr { - __u16 source; - __u16 dest; - __u16 len; - __u16 check; + __be16 source; + __be16 dest; + __be16 len; + __be16 check; }; /* UDP socket options */ -- cgit v1.2.3 From b1dd39ac963040c2d282ab8026b9c9aa9306ea06 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:38:13 -0700 Subject: [IPV4]: ICMP header annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/icmp.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/icmp.h b/include/linux/icmp.h index f0b571f1060b..878cfe4e587f 100644 --- a/include/linux/icmp.h +++ b/include/linux/icmp.h @@ -68,16 +68,16 @@ struct icmphdr { __u8 type; __u8 code; - __u16 checksum; + __be16 checksum; union { struct { - __u16 id; - __u16 sequence; + __be16 id; + __be16 sequence; } echo; - __u32 gateway; + __be32 gateway; struct { - __u16 __unused; - __u16 mtu; + __be16 __unused; + __be16 mtu; } frag; } un; }; -- cgit v1.2.3 From 1b620154273d5cc57690e0d199282c6bb9e56974 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:39:09 -0700 Subject: [IPV4]: PIMv2 header annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/mroute.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mroute.h b/include/linux/mroute.h index e05d54a90743..c7dd4c11f667 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -213,8 +213,8 @@ struct pimreghdr { __u8 type; __u8 reserved; - __u16 csum; - __u32 flags; + __be16 csum; + __be32 flags; }; extern int pim_rcv_v1(struct sk_buff *); -- cgit v1.2.3 From 114c7844f34c1608aec20ae7ff85cec471ac90ae Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:39:29 -0700 Subject: [IPV4]: mroute annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/mroute.h | 10 +++++----- net/ipv4/ipmr.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mroute.h b/include/linux/mroute.h index c7dd4c11f667..7da2cee8e132 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -142,7 +142,7 @@ struct vif_device unsigned long rate_limit; /* Traffic shaping (NI) */ unsigned char threshold; /* TTL threshold */ unsigned short flags; /* Control flags */ - __u32 local,remote; /* Addresses(remote for tunnels)*/ + __be32 local,remote; /* Addresses(remote for tunnels)*/ int link; /* Physical interface index */ }; @@ -151,8 +151,8 @@ struct vif_device struct mfc_cache { struct mfc_cache *next; /* Next entry on cache line */ - __u32 mfc_mcastgrp; /* Group the entry belongs to */ - __u32 mfc_origin; /* Source of packet */ + __be32 mfc_mcastgrp; /* Group the entry belongs to */ + __be32 mfc_origin; /* Source of packet */ vifi_t mfc_parent; /* Source interface */ int mfc_flags; /* Flags on line */ @@ -179,9 +179,9 @@ struct mfc_cache #define MFC_LINES 64 #ifdef __BIG_ENDIAN -#define MFC_HASH(a,b) ((((a)>>24)^((b)>>26))&(MFC_LINES-1)) +#define MFC_HASH(a,b) (((((__force u32)(__be32)a)>>24)^(((__force u32)(__be32)b)>>26))&(MFC_LINES-1)) #else -#define MFC_HASH(a,b) (((a)^((b)>>2))&(MFC_LINES-1)) +#define MFC_HASH(a,b) ((((__force u32)(__be32)a)^(((__force u32)(__be32)b)>>2))&(MFC_LINES-1)) #endif #endif diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index ba49588da242..97cfa97c8abb 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -462,7 +462,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock) return 0; } -static struct mfc_cache *ipmr_cache_find(__u32 origin, __u32 mcastgrp) +static struct mfc_cache *ipmr_cache_find(__be32 origin, __be32 mcastgrp) { int line=MFC_HASH(mcastgrp,origin); struct mfc_cache *c; @@ -1097,7 +1097,7 @@ static struct notifier_block ip_mr_notifier={ * important for multicast video. */ -static void ip_encap(struct sk_buff *skb, u32 saddr, u32 daddr) +static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr) { struct iphdr *iph = (struct iphdr *)skb_push(skb,sizeof(struct iphdr)); -- cgit v1.2.3 From 4f765d842fa6e6fe15d555b247b640118d65b4dd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:43:07 -0700 Subject: [IPV4]: INET_MATCH() annotations INET_MATCH() and friends depend on an interesting set of kludges: * there's a pair of adjacent fields in struct inet_sock - __be16 dport followed by __u16 num. We want to search by pair, so we combine the keys into a single 32bit value and compare with 32bit value read from &...->dport. * on 64bit targets we combine comparisons with pair of adjacent __be32 fields in the same way. Make sure that we don't mix those values with anything else and that pairs we form them from have correct types. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/ipv6.h | 2 +- include/net/inet_hashtables.h | 36 +++++++++++++++++++++++++----------- net/ipv4/inet_hashtables.c | 2 +- net/ipv6/inet6_hashtables.c | 8 ++++---- 4 files changed, 31 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index caca57df0d7d..6dc07ee7702e 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -461,7 +461,7 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk) #define INET6_MATCH(__sk, __hash, __saddr, __daddr, __ports, __dif)\ (((__sk)->sk_hash == (__hash)) && \ - ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ + ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ ((__sk)->sk_family == AF_INET6) && \ ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \ ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \ diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index b4491c9e2a5a..fb0c09c7090c 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -283,31 +283,45 @@ static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo, } /* Socket demux engine toys. */ +/* What happens here is ugly; there's a pair of adjacent fields in + struct inet_sock; __be16 dport followed by __u16 num. We want to + search by pair, so we combine the keys into a single 32bit value + and compare with 32bit value read from &...->dport. Let's at least + make sure that it's not mixed with anything else... + On 64bit targets we combine comparisons with pair of adjacent __be32 + fields in the same way. +*/ +typedef __u32 __bitwise __portpair; #ifdef __BIG_ENDIAN #define INET_COMBINED_PORTS(__sport, __dport) \ - (((__u32)(__sport) << 16) | (__u32)(__dport)) + ((__force __portpair)(((__force __u32)(__be16)(__sport) << 16) | (__u32)(__dport))) #else /* __LITTLE_ENDIAN */ #define INET_COMBINED_PORTS(__sport, __dport) \ - (((__u32)(__dport) << 16) | (__u32)(__sport)) + ((__force __portpair)(((__u32)(__dport) << 16) | (__force __u32)(__be16)(__sport))) #endif #if (BITS_PER_LONG == 64) +typedef __u64 __bitwise __addrpair; #ifdef __BIG_ENDIAN #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ - const __u64 __name = (((__u64)(__saddr)) << 32) | ((__u64)(__daddr)); + const __addrpair __name = (__force __addrpair) ( \ + (((__force __u64)(__be32)(__saddr)) << 32) | \ + ((__force __u64)(__be32)(__daddr))); #else /* __LITTLE_ENDIAN */ #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ - const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr)); + const __addrpair __name = (__force __addrpair) ( \ + (((__force __u64)(__be32)(__daddr)) << 32) | \ + ((__force __u64)(__be32)(__saddr))); #endif /* __BIG_ENDIAN */ #define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ (((__sk)->sk_hash == (__hash)) && \ - ((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ - ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ + ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ + ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ (((__sk)->sk_hash == (__hash)) && \ - ((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ - ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ + ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ + ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #else /* 32-bit arch */ #define INET_ADDR_COOKIE(__name, __saddr, __daddr) @@ -315,13 +329,13 @@ static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo, (((__sk)->sk_hash == (__hash)) && \ (inet_sk(__sk)->daddr == (__saddr)) && \ (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ - ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ + ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET_TW_MATCH(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ (((__sk)->sk_hash == (__hash)) && \ (inet_twsk(__sk)->tw_daddr == (__saddr)) && \ (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ - ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ + ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #endif /* 64-bit arch */ @@ -338,7 +352,7 @@ static inline struct sock * const int dif) { INET_ADDR_COOKIE(acookie, saddr, daddr) - const __u32 ports = INET_COMBINED_PORTS(sport, hnum); + const __portpair ports = INET_COMBINED_PORTS(sport, hnum); struct sock *sk; const struct hlist_node *node; /* Optimize here for direct hit, only listening connections can diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index fb296c9a7f3f..729d1eb39483 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -201,7 +201,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, u32 saddr = inet->daddr; int dif = sk->sk_bound_dev_if; INET_ADDR_COOKIE(acookie, saddr, daddr) - const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport); + const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport); struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); struct sock *sk2; diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index d2f3fc990bfa..8accd1fbeeda 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -64,7 +64,7 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo, { struct sock *sk; const struct hlist_node *node; - const __u32 ports = INET_COMBINED_PORTS(sport, hnum); + const __portpair ports = INET_COMBINED_PORTS(sport, hnum); /* Optimize here for direct hit, only listening connections can * have wildcards anyways. */ @@ -82,7 +82,7 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo, sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { const struct inet_timewait_sock *tw = inet_twsk(sk); - if(*((__u32 *)&(tw->tw_dport)) == ports && + if(*((__portpair *)&(tw->tw_dport)) == ports && sk->sk_family == PF_INET6) { const struct inet6_timewait_sock *tw6 = inet6_twsk(sk); @@ -171,7 +171,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, const struct in6_addr *daddr = &np->rcv_saddr; const struct in6_addr *saddr = &np->daddr; const int dif = sk->sk_bound_dev_if; - const u32 ports = INET_COMBINED_PORTS(inet->dport, lport); + const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); const unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport); struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); @@ -188,7 +188,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, tw = inet_twsk(sk2); - if(*((__u32 *)&(tw->tw_dport)) == ports && + if(*((__portpair *)&(tw->tw_dport)) == ports && sk2->sk_family == PF_INET6 && ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && -- cgit v1.2.3 From 9f8552996d969f56039ec88128cf5ad35b12f141 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:44:30 -0700 Subject: [IPV4]: inet_diag annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/inet_diag.h | 10 +++++----- net/ipv4/inet_diag.c | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index a4606e5810e5..6e8bc548635a 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -9,10 +9,10 @@ /* Socket identity */ struct inet_diag_sockid { - __u16 idiag_sport; - __u16 idiag_dport; - __u32 idiag_src[4]; - __u32 idiag_dst[4]; + __be16 idiag_sport; + __be16 idiag_dport; + __be32 idiag_src[4]; + __be32 idiag_dst[4]; __u32 idiag_if; __u32 idiag_cookie[2]; #define INET_DIAG_NOCOOKIE (~0U) @@ -67,7 +67,7 @@ struct inet_diag_hostcond { __u8 family; __u8 prefix_len; int port; - __u32 addr[0]; + __be32 addr[0]; }; /* Base info structure. It contains socket identity (addrs/ports/cookie) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 492858e6faf0..77761ac4f7bb 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -36,8 +36,8 @@ static const struct inet_diag_handler **inet_diag_table; struct inet_diag_entry { - u32 *saddr; - u32 *daddr; + __be32 *saddr; + __be32 *daddr; u16 sport; u16 dport; u16 family; @@ -294,7 +294,7 @@ out: return err; } -static int bitstring_match(const u32 *a1, const u32 *a2, int bits) +static int bitstring_match(const __be32 *a1, const __be32 *a2, int bits) { int words = bits >> 5; @@ -305,8 +305,8 @@ static int bitstring_match(const u32 *a1, const u32 *a2, int bits) return 0; } if (bits) { - __u32 w1, w2; - __u32 mask; + __be32 w1, w2; + __be32 mask; w1 = a1[words]; w2 = a2[words]; @@ -352,7 +352,7 @@ static int inet_diag_bc_run(const void *bc, int len, case INET_DIAG_BC_S_COND: case INET_DIAG_BC_D_COND: { struct inet_diag_hostcond *cond; - u32 *addr; + __be32 *addr; cond = (struct inet_diag_hostcond *)(op + 1); if (cond->port != -1 && -- cgit v1.2.3 From 48818f822d2b2e16f4bf4d1ed1185e7d2146dc34 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:44:54 -0700 Subject: [IPV6]: struct in6_addr annotations in6_addr elements are net-endian Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/in6.h | 4 ++-- include/net/ipv6.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/in6.h b/include/linux/in6.h index d776829b443f..348ecd4a36fe 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -32,8 +32,8 @@ struct in6_addr union { __u8 u6_addr8[16]; - __u16 u6_addr16[8]; - __u32 u6_addr32[4]; + __be16 u6_addr16[8]; + __be32 u6_addr32[4]; } in6_u; #define s6_addr in6_u.u6_addr8 #define s6_addr16 in6_u.u6_addr16 diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 72bf47b2a4e0..8223c4410b4b 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -318,8 +318,8 @@ static inline void ipv6_addr_prefix(struct in6_addr *pfx, #ifndef __HAVE_ARCH_ADDR_SET static inline void ipv6_addr_set(struct in6_addr *addr, - __u32 w1, __u32 w2, - __u32 w3, __u32 w4) + __be32 w1, __be32 w2, + __be32 w3, __be32 w4) { addr->s6_addr32[0] = w1; addr->s6_addr32[1] = w2; @@ -337,7 +337,7 @@ static inline int ipv6_addr_equal(const struct in6_addr *a1, a1->s6_addr32[3] == a2->s6_addr32[3]); } -static inline int __ipv6_prefix_equal(const u32 *a1, const u32 *a2, +static inline int __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2, unsigned int prefixlen) { unsigned pdw, pbi; -- cgit v1.2.3 From 43505077df075545e9b28b7c6ea12d82b3caf036 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:45:11 -0700 Subject: [IPV6]: IPv6 headers annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/ipv6.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 6dc07ee7702e..4f435c59de06 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -99,22 +99,22 @@ struct ipv6_destopt_hao { struct ipv6_auth_hdr { __u8 nexthdr; __u8 hdrlen; /* This one is measured in 32 bit units! */ - __u16 reserved; - __u32 spi; - __u32 seq_no; /* Sequence number */ + __be16 reserved; + __be32 spi; + __be32 seq_no; /* Sequence number */ __u8 auth_data[0]; /* Length variable but >=4. Mind the 64 bit alignment! */ }; struct ipv6_esp_hdr { - __u32 spi; - __u32 seq_no; /* Sequence number */ + __be32 spi; + __be32 seq_no; /* Sequence number */ __u8 enc_data[0]; /* Length variable but >=8. Mind the 64 bit alignment! */ }; struct ipv6_comp_hdr { __u8 nexthdr; __u8 flags; - __u16 cpi; + __be16 cpi; }; /* @@ -136,7 +136,7 @@ struct ipv6hdr { #endif __u8 flow_lbl[3]; - __u16 payload_len; + __be16 payload_len; __u8 nexthdr; __u8 hop_limit; -- cgit v1.2.3 From e2e38e819bd03e9674c102aaa2c9dc8151a3c3d0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:45:27 -0700 Subject: [IPV6]: sin6_port is net-endian Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/in6.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/in6.h b/include/linux/in6.h index 348ecd4a36fe..9be6a4756f0b 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -53,7 +53,7 @@ extern const struct in6_addr in6addr_loopback; struct sockaddr_in6 { unsigned short int sin6_family; /* AF_INET6 */ - __u16 sin6_port; /* Transport layer port # */ + __be16 sin6_port; /* Transport layer port # */ __u32 sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ __u32 sin6_scope_id; /* scope id (new in RFC2553) */ -- cgit v1.2.3 From 8f83f23e6db8b9a9fe787d02f73489224668c4e2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:46:11 -0700 Subject: [XFRM]: ports in struct xfrm_selector annotated Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/xfrm.h | 8 ++++---- net/ipv4/xfrm4_state.c | 4 ++-- net/ipv6/xfrm6_state.c | 4 ++-- net/key/af_key.c | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 14ecd19f4cdc..3aae9b9ce79b 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -49,10 +49,10 @@ struct xfrm_selector { xfrm_address_t daddr; xfrm_address_t saddr; - __u16 dport; - __u16 dport_mask; - __u16 sport; - __u16 sport_mask; + __be16 dport; + __be16 dport_mask; + __be16 sport; + __be16 sport_mask; __u16 family; __u8 prefixlen_d; __u8 prefixlen_s; diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index fe2034494d08..3cc3df0c6ece 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c @@ -29,9 +29,9 @@ __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, x->sel.daddr.a4 = fl->fl4_dst; x->sel.saddr.a4 = fl->fl4_src; x->sel.dport = xfrm_flowi_dport(fl); - x->sel.dport_mask = ~0; + x->sel.dport_mask = htons(0xffff); x->sel.sport = xfrm_flowi_sport(fl); - x->sel.sport_mask = ~0; + x->sel.sport_mask = htons(0xffff); x->sel.prefixlen_d = 32; x->sel.prefixlen_s = 32; x->sel.proto = fl->proto; diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index 711bfafb2472..9ddaa9d41539 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c @@ -29,9 +29,9 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst); ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src); x->sel.dport = xfrm_flowi_dport(fl); - x->sel.dport_mask = ~0; + x->sel.dport_mask = htons(0xffff); x->sel.sport = xfrm_flowi_sport(fl); - x->sel.sport_mask = ~0; + x->sel.sport_mask = htons(0xffff); x->sel.prefixlen_d = 128; x->sel.prefixlen_s = 128; x->sel.proto = fl->proto; diff --git a/net/key/af_key.c b/net/key/af_key.c index 83b443ddc72f..ff98e70b0931 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2140,7 +2140,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port; if (xp->selector.sport) - xp->selector.sport_mask = ~0; + xp->selector.sport_mask = htons(0xffff); sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr); @@ -2153,7 +2153,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h xp->selector.dport = ((struct sockaddr_in *)(sa+1))->sin_port; if (xp->selector.dport) - xp->selector.dport_mask = ~0; + xp->selector.dport_mask = htons(0xffff); sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; if (sec_ctx != NULL) { @@ -2243,7 +2243,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port; if (sel.sport) - sel.sport_mask = ~0; + sel.sport_mask = htons(0xffff); sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); @@ -2251,7 +2251,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port; if (sel.dport) - sel.dport_mask = ~0; + sel.dport_mask = htons(0xffff); sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; memset(&tmp, 0, sizeof(struct xfrm_policy)); -- cgit v1.2.3 From 737b5761dfc609b5be4163deb2cf09226f56bcbc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:46:48 -0700 Subject: [XFRM]: xfrm_address_t annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/xfrm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 3aae9b9ce79b..4b321842d65f 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -12,8 +12,8 @@ */ typedef union { - __u32 a4; - __u32 a6[4]; + __be32 a4; + __be32 a6[4]; } xfrm_address_t; /* Ident of a specific xfrm_state. It is used on input to lookup -- cgit v1.2.3 From e037c39bf965ca66fde902e191d849a90de278fe Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:47:40 -0700 Subject: [XFRM]: struct xfrm_id annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/xfrm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 4b321842d65f..c894267ff5dd 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -23,7 +23,7 @@ typedef union struct xfrm_id { xfrm_address_t daddr; - __u32 spi; + __be32 spi; __u8 proto; }; -- cgit v1.2.3 From 9916ecb0a6f52f1475fa2f71845227d3c75fb40c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Sep 2006 18:48:48 -0700 Subject: [XFRM]: struct xfrm_usersa_id annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/xfrm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index c894267ff5dd..430afd058269 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -281,7 +281,7 @@ struct xfrm_usersa_info { struct xfrm_usersa_id { xfrm_address_t daddr; - __u32 spi; + __be32 spi; __u16 family; __u8 proto; }; -- cgit v1.2.3 From cbde1668e4f08e0a150207646010bc65e1e2a42b Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 27 Sep 2006 22:40:19 -0700 Subject: [NET]: Move netlink interface bits to linux/if_link.h. Moving netlink interface bits to linux/if.h is rather troublesome for applications including both linux/if.h (which was changed to be included from linux/rtnetlink.h automatically) and net/if.h. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/linux/if.h | 130 -------------------------------------------- include/linux/if_link.h | 136 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/rtnetlink.h | 2 +- 3 files changed, 137 insertions(+), 131 deletions(-) create mode 100644 include/linux/if_link.h (limited to 'include/linux') diff --git a/include/linux/if.h b/include/linux/if.h index 8018c2e22c0c..32bf419351f1 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -214,134 +214,4 @@ struct ifconf #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures */ -/* The struct should be in sync with struct net_device_stats */ -struct rtnl_link_stats -{ - __u32 rx_packets; /* total packets received */ - __u32 tx_packets; /* total packets transmitted */ - __u32 rx_bytes; /* total bytes received */ - __u32 tx_bytes; /* total bytes transmitted */ - __u32 rx_errors; /* bad packets received */ - __u32 tx_errors; /* packet transmit problems */ - __u32 rx_dropped; /* no space in linux buffers */ - __u32 tx_dropped; /* no space available in linux */ - __u32 multicast; /* multicast packets received */ - __u32 collisions; - - /* detailed rx_errors: */ - __u32 rx_length_errors; - __u32 rx_over_errors; /* receiver ring buff overflow */ - __u32 rx_crc_errors; /* recved pkt with crc error */ - __u32 rx_frame_errors; /* recv'd frame alignment error */ - __u32 rx_fifo_errors; /* recv'r fifo overrun */ - __u32 rx_missed_errors; /* receiver missed packet */ - - /* detailed tx_errors */ - __u32 tx_aborted_errors; - __u32 tx_carrier_errors; - __u32 tx_fifo_errors; - __u32 tx_heartbeat_errors; - __u32 tx_window_errors; - - /* for cslip etc */ - __u32 rx_compressed; - __u32 tx_compressed; -}; - -/* The struct should be in sync with struct ifmap */ -struct rtnl_link_ifmap -{ - __u64 mem_start; - __u64 mem_end; - __u64 base_addr; - __u16 irq; - __u8 dma; - __u8 port; -}; - -enum -{ - IFLA_UNSPEC, - IFLA_ADDRESS, - IFLA_BROADCAST, - IFLA_IFNAME, - IFLA_MTU, - IFLA_LINK, - IFLA_QDISC, - IFLA_STATS, - IFLA_COST, -#define IFLA_COST IFLA_COST - IFLA_PRIORITY, -#define IFLA_PRIORITY IFLA_PRIORITY - IFLA_MASTER, -#define IFLA_MASTER IFLA_MASTER - IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ -#define IFLA_WIRELESS IFLA_WIRELESS - IFLA_PROTINFO, /* Protocol specific information for a link */ -#define IFLA_PROTINFO IFLA_PROTINFO - IFLA_TXQLEN, -#define IFLA_TXQLEN IFLA_TXQLEN - IFLA_MAP, -#define IFLA_MAP IFLA_MAP - IFLA_WEIGHT, -#define IFLA_WEIGHT IFLA_WEIGHT - IFLA_OPERSTATE, - IFLA_LINKMODE, - __IFLA_MAX -}; - - -#define IFLA_MAX (__IFLA_MAX - 1) - -/* ifi_flags. - - IFF_* flags. - - The only change is: - IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are - more not changeable by user. They describe link media - characteristics and set by device driver. - - Comments: - - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid - - If neither of these three flags are set; - the interface is NBMA. - - - IFF_MULTICAST does not mean anything special: - multicasts can be used on all not-NBMA links. - IFF_MULTICAST means that this media uses special encapsulation - for multicast frames. Apparently, all IFF_POINTOPOINT and - IFF_BROADCAST devices are able to use multicasts too. - */ - -/* IFLA_LINK. - For usual devices it is equal ifi_index. - If it is a "virtual interface" (f.e. tunnel), ifi_link - can point to real physical interface (f.e. for bandwidth calculations), - or maybe 0, what means, that real media is unknown (usual - for IPIP tunnels, when route to endpoint is allowed to change) - */ - -/* Subtype attributes for IFLA_PROTINFO */ -enum -{ - IFLA_INET6_UNSPEC, - IFLA_INET6_FLAGS, /* link flags */ - IFLA_INET6_CONF, /* sysctl parameters */ - IFLA_INET6_STATS, /* statistics */ - IFLA_INET6_MCAST, /* MC things. What of them? */ - IFLA_INET6_CACHEINFO, /* time values and max reasm size */ - __IFLA_INET6_MAX -}; - -#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) - -struct ifla_cacheinfo -{ - __u32 max_reasm_len; - __u32 tstamp; /* ipv6InterfaceTable updated timestamp */ - __u32 reachable_time; - __u32 retrans_time; -}; - #endif /* _LINUX_IF_H */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h new file mode 100644 index 000000000000..e963a077e6f5 --- /dev/null +++ b/include/linux/if_link.h @@ -0,0 +1,136 @@ +#ifndef _LINUX_IF_LINK_H +#define _LINUX_IF_LINK_H + +#include + +/* The struct should be in sync with struct net_device_stats */ +struct rtnl_link_stats +{ + __u32 rx_packets; /* total packets received */ + __u32 tx_packets; /* total packets transmitted */ + __u32 rx_bytes; /* total bytes received */ + __u32 tx_bytes; /* total bytes transmitted */ + __u32 rx_errors; /* bad packets received */ + __u32 tx_errors; /* packet transmit problems */ + __u32 rx_dropped; /* no space in linux buffers */ + __u32 tx_dropped; /* no space available in linux */ + __u32 multicast; /* multicast packets received */ + __u32 collisions; + + /* detailed rx_errors: */ + __u32 rx_length_errors; + __u32 rx_over_errors; /* receiver ring buff overflow */ + __u32 rx_crc_errors; /* recved pkt with crc error */ + __u32 rx_frame_errors; /* recv'd frame alignment error */ + __u32 rx_fifo_errors; /* recv'r fifo overrun */ + __u32 rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + __u32 tx_aborted_errors; + __u32 tx_carrier_errors; + __u32 tx_fifo_errors; + __u32 tx_heartbeat_errors; + __u32 tx_window_errors; + + /* for cslip etc */ + __u32 rx_compressed; + __u32 tx_compressed; +}; + +/* The struct should be in sync with struct ifmap */ +struct rtnl_link_ifmap +{ + __u64 mem_start; + __u64 mem_end; + __u64 base_addr; + __u16 irq; + __u8 dma; + __u8 port; +}; + +enum +{ + IFLA_UNSPEC, + IFLA_ADDRESS, + IFLA_BROADCAST, + IFLA_IFNAME, + IFLA_MTU, + IFLA_LINK, + IFLA_QDISC, + IFLA_STATS, + IFLA_COST, +#define IFLA_COST IFLA_COST + IFLA_PRIORITY, +#define IFLA_PRIORITY IFLA_PRIORITY + IFLA_MASTER, +#define IFLA_MASTER IFLA_MASTER + IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ +#define IFLA_WIRELESS IFLA_WIRELESS + IFLA_PROTINFO, /* Protocol specific information for a link */ +#define IFLA_PROTINFO IFLA_PROTINFO + IFLA_TXQLEN, +#define IFLA_TXQLEN IFLA_TXQLEN + IFLA_MAP, +#define IFLA_MAP IFLA_MAP + IFLA_WEIGHT, +#define IFLA_WEIGHT IFLA_WEIGHT + IFLA_OPERSTATE, + IFLA_LINKMODE, + __IFLA_MAX +}; + + +#define IFLA_MAX (__IFLA_MAX - 1) + +/* ifi_flags. + + IFF_* flags. + + The only change is: + IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are + more not changeable by user. They describe link media + characteristics and set by device driver. + + Comments: + - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid + - If neither of these three flags are set; + the interface is NBMA. + + - IFF_MULTICAST does not mean anything special: + multicasts can be used on all not-NBMA links. + IFF_MULTICAST means that this media uses special encapsulation + for multicast frames. Apparently, all IFF_POINTOPOINT and + IFF_BROADCAST devices are able to use multicasts too. + */ + +/* IFLA_LINK. + For usual devices it is equal ifi_index. + If it is a "virtual interface" (f.e. tunnel), ifi_link + can point to real physical interface (f.e. for bandwidth calculations), + or maybe 0, what means, that real media is unknown (usual + for IPIP tunnels, when route to endpoint is allowed to change) + */ + +/* Subtype attributes for IFLA_PROTINFO */ +enum +{ + IFLA_INET6_UNSPEC, + IFLA_INET6_FLAGS, /* link flags */ + IFLA_INET6_CONF, /* sysctl parameters */ + IFLA_INET6_STATS, /* statistics */ + IFLA_INET6_MCAST, /* MC things. What of them? */ + IFLA_INET6_CACHEINFO, /* time values and max reasm size */ + __IFLA_INET6_MAX +}; + +#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) + +struct ifla_cacheinfo +{ + __u32 max_reasm_len; + __u32 tstamp; /* ipv6InterfaceTable updated timestamp */ + __u32 reachable_time; + __u32 retrans_time; +}; + +#endif /* _LINUX_IF_LINK_H */ diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 9c92dc8b9a08..3a18addaed4c 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -2,7 +2,7 @@ #define __LINUX_RTNETLINK_H #include -#include +#include /**** * Routing/neighbour discovery messages. -- cgit v1.2.3 From b854d0d218688b30ccea70521d6ea5f3f56d4e12 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 27 Sep 2006 22:43:05 -0700 Subject: [NET] KBUILD: Add missing entries for new net headers. Add the following for userspace export by the 'headers_include' make target: linux/fib_rules.h, linux/if_addr.h, linux/if_link.h, linux/neighbour.h. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/linux/Kbuild | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 1df2ac30a4d2..f7a52e19b4be 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -58,6 +58,7 @@ header-y += elf-em.h header-y += fadvise.h header-y += fd.h header-y += fdreg.h +header-y += fib_rules.h header-y += ftape-header-segment.h header-y += ftape-vendors.h header-y += fuse.h @@ -70,6 +71,7 @@ header-y += hysdn_if.h header-y += i2c-dev.h header-y += i8k.h header-y += icmp.h +header-y += if_addr.h header-y += if_arcnet.h header-y += if_arp.h header-y += if_bonding.h @@ -79,6 +81,7 @@ header-y += if_fddi.h header-y += if.h header-y += if_hippi.h header-y += if_infiniband.h +header-y += if_link.h header-y += if_packet.h header-y += if_plip.h header-y += if_ppp.h @@ -110,6 +113,7 @@ header-y += mmtimer.h header-y += mqueue.h header-y += mtio.h header-y += ncp_no.h +header-y += neighbour.h header-y += netfilter_arp.h header-y += netrom.h header-y += nfs2.h -- cgit v1.2.3 From d77072ecfb6d28287d5e2a61d60d87a3a444ac97 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Sep 2006 14:20:34 -0700 Subject: [NET]: Annotate dst_ops protocol Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- include/net/dst.h | 2 +- net/core/neighbour.c | 2 +- net/ethernet/eth.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 13d6d4eb8b3a..9264139bd8df 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -187,7 +187,7 @@ struct hh_cache { struct hh_cache *hh_next; /* Next entry */ atomic_t hh_refcnt; /* number of users */ - unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP + __be16 hh_type; /* protocol identifier, f.e ETH_P_IP * NOTE: For VLANs, this will be the * encapuslated type. --BLG */ diff --git a/include/net/dst.h b/include/net/dst.h index a8d825f90305..e156e38e4ac3 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -84,7 +84,7 @@ struct dst_entry struct dst_ops { unsigned short family; - unsigned short protocol; + __be16 protocol; unsigned gc_thresh; int (*gc)(void); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index b6c69e1463e8..8ce8c471d868 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1079,7 +1079,7 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl, } static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, - u16 protocol) + __be16 protocol) { struct hh_cache *hh; struct net_device *dev = dst->dev; diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 43863933f27f..4bd78c8cfb26 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -223,7 +223,7 @@ static int eth_header_parse(struct sk_buff *skb, unsigned char *haddr) */ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) { - unsigned short type = hh->hh_type; + __be16 type = hh->hh_type; struct ethhdr *eth; struct net_device *dev = neigh->dev; -- cgit v1.2.3 From 59b8bfd8fd608821e5addc9f4682c7f2424afd8c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Sep 2006 14:21:07 -0700 Subject: [NETFILTER]: netfilter misc annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_arp/arp_tables.h | 6 +++--- include/linux/netfilter_ipv4/ip_queue.h | 2 +- net/ipv4/netfilter.c | 4 ++-- net/ipv4/netfilter/arp_tables.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 149e87c9ab13..44e39b61d9e7 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -46,11 +46,11 @@ struct arpt_arp { struct arpt_devaddr_info tgt_devaddr; /* ARP operation code. */ - u_int16_t arpop, arpop_mask; + __be16 arpop, arpop_mask; /* ARP hardware address and protocol address format. */ - u_int16_t arhrd, arhrd_mask; - u_int16_t arpro, arpro_mask; + __be16 arhrd, arhrd_mask; + __be16 arpro, arpro_mask; /* The protocol address length is only accepted if it is 4 * so there is no use in offering a way to do filtering on it. diff --git a/include/linux/netfilter_ipv4/ip_queue.h b/include/linux/netfilter_ipv4/ip_queue.h index aa08d68c4841..a03507f465f8 100644 --- a/include/linux/netfilter_ipv4/ip_queue.h +++ b/include/linux/netfilter_ipv4/ip_queue.h @@ -26,7 +26,7 @@ typedef struct ipq_packet_msg { unsigned int hook; /* Netfilter hook we rode in on */ char indev_name[IFNAMSIZ]; /* Name of incoming interface */ char outdev_name[IFNAMSIZ]; /* Name of outgoing interface */ - unsigned short hw_protocol; /* Hardware protocol (network order) */ + __be16 hw_protocol; /* Hardware protocol (network order) */ unsigned short hw_type; /* Hardware type */ unsigned char hw_addrlen; /* Hardware address length */ unsigned char hw_addr[8]; /* Hardware address */ diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index f88347de21a9..5ac15379a0cf 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -128,8 +128,8 @@ EXPORT_SYMBOL(ip_nat_decode_session); */ struct ip_rt_info { - u_int32_t daddr; - u_int32_t saddr; + __be32 daddr; + __be32 saddr; u_int8_t tos; }; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 85f0d73ebfb4..17e1a687ab45 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -80,7 +80,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr, { char *arpptr = (char *)(arphdr + 1); char *src_devaddr, *tgt_devaddr; - u32 src_ipaddr, tgt_ipaddr; + __be32 src_ipaddr, tgt_ipaddr; int i, ret; #define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg)) -- cgit v1.2.3 From cdcb71bf964e02e0a22007f5d90ead7bede3b85b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Sep 2006 14:21:37 -0700 Subject: [NETFILTER]: conntrack annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack.h | 2 +- include/linux/netfilter_ipv4/ip_conntrack_tuple.h | 16 ++--- net/ipv4/netfilter/ip_conntrack_amanda.c | 6 +- net/ipv4/netfilter/ip_conntrack_core.c | 12 ++-- net/ipv4/netfilter/ip_conntrack_ftp.c | 6 +- net/ipv4/netfilter/ip_conntrack_helper_pptp.c | 4 +- net/ipv4/netfilter/ip_conntrack_irc.c | 5 +- net/ipv4/netfilter/ip_conntrack_netbios_ns.c | 10 +-- net/ipv4/netfilter/ip_conntrack_netlink.c | 82 +++++++++++------------ net/ipv4/netfilter/ip_conntrack_proto_icmp.c | 4 +- net/ipv4/netfilter/ip_conntrack_proto_sctp.c | 2 +- net/ipv4/netfilter/ip_conntrack_proto_tcp.c | 6 +- net/ipv4/netfilter/ip_conntrack_sip.c | 16 ++--- net/ipv4/netfilter/ip_conntrack_tftp.c | 8 +-- 14 files changed, 90 insertions(+), 89 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 51dbec1892c8..64e868034c4a 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -157,7 +157,7 @@ struct ip_conntrack_expect unsigned int flags; #ifdef CONFIG_IP_NF_NAT_NEEDED - u_int32_t saved_ip; + __be32 saved_ip; /* This is the original per-proto part, used to map the * expected connection the way the recipient expects. */ union ip_conntrack_manip_proto saved_proto; diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h index 2fdabdb4c0ef..c228bde74c33 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h @@ -23,13 +23,13 @@ union ip_conntrack_manip_proto __be16 port; } tcp; struct { - u_int16_t port; + __be16 port; } udp; struct { - u_int16_t id; + __be16 id; } icmp; struct { - u_int16_t port; + __be16 port; } sctp; struct { __be16 key; /* key is 32bit, pptp only uses 16 */ @@ -39,7 +39,7 @@ union ip_conntrack_manip_proto /* The manipulable part of the tuple. */ struct ip_conntrack_manip { - u_int32_t ip; + __be32 ip; union ip_conntrack_manip_proto u; }; @@ -50,22 +50,22 @@ struct ip_conntrack_tuple /* These are the parts of the tuple which are fixed. */ struct { - u_int32_t ip; + __be32 ip; union { /* Add other protocols here. */ u_int16_t all; struct { - u_int16_t port; + __be16 port; } tcp; struct { - u_int16_t port; + __be16 port; } udp; struct { u_int8_t type, code; } icmp; struct { - u_int16_t port; + __be16 port; } sctp; struct { __be16 key; /* key is 32bit, diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index 0a7bd7f04061..6c7383a8e42b 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c @@ -155,11 +155,11 @@ static int help(struct sk_buff **pskb, exp->tuple.dst.protonum = IPPROTO_TCP; exp->tuple.dst.u.tcp.port = htons(port); - exp->mask.src.ip = 0xFFFFFFFF; + exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; - exp->mask.dst.ip = 0xFFFFFFFF; + exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.protonum = 0xFF; - exp->mask.dst.u.tcp.port = 0xFFFF; + exp->mask.dst.u.tcp.port = htons(0xFFFF); if (ip_nat_amanda_hook) ret = ip_nat_amanda_hook(pskb, ctinfo, off - dataoff, diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index c432b3163609..143c4668538b 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -149,8 +149,8 @@ static unsigned int ip_conntrack_hash_rnd; static u_int32_t __hash_conntrack(const struct ip_conntrack_tuple *tuple, unsigned int size, unsigned int rnd) { - return (jhash_3words(tuple->src.ip, - (tuple->dst.ip ^ tuple->dst.protonum), + return (jhash_3words((__force u32)tuple->src.ip, + ((__force u32)tuple->dst.ip ^ tuple->dst.protonum), (tuple->src.u.all | (tuple->dst.u.all << 16)), rnd) % size); } @@ -1169,9 +1169,9 @@ void __ip_ct_refresh_acct(struct ip_conntrack *ct, int ip_ct_port_tuple_to_nfattr(struct sk_buff *skb, const struct ip_conntrack_tuple *tuple) { - NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t), + NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(__be16), &tuple->src.u.tcp.port); - NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(u_int16_t), + NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(__be16), &tuple->dst.u.tcp.port); return 0; @@ -1186,9 +1186,9 @@ int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[], return -EINVAL; t->src.u.tcp.port = - *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]); + *(__be16 *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]); t->dst.u.tcp.port = - *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]); + *(__be16 *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]); return 0; } diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index 1d18c863f064..93dcf960662f 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c @@ -425,8 +425,8 @@ static int help(struct sk_buff **pskb, exp->tuple.src.u.tcp.port = 0; /* Don't care. */ exp->tuple.dst.protonum = IPPROTO_TCP; exp->mask = ((struct ip_conntrack_tuple) - { { 0xFFFFFFFF, { 0 } }, - { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }}); + { { htonl(0xFFFFFFFF), { 0 } }, + { htonl(0xFFFFFFFF), { .tcp = { htons(0xFFFF) } }, 0xFF }}); exp->expectfn = NULL; exp->flags = 0; @@ -488,7 +488,7 @@ static int __init ip_conntrack_ftp_init(void) for (i = 0; i < ports_c; i++) { ftp[i].tuple.src.u.tcp.port = htons(ports[i]); ftp[i].tuple.dst.protonum = IPPROTO_TCP; - ftp[i].mask.src.u.tcp.port = 0xFFFF; + ftp[i].mask.src.u.tcp.port = htons(0xFFFF); ftp[i].mask.dst.protonum = 0xFF; ftp[i].max_expected = 1; ftp[i].timeout = 5 * 60; /* 5 minutes */ diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c index fb0aee691721..a2af5e0c7f99 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c @@ -242,10 +242,10 @@ exp_gre(struct ip_conntrack *ct, exp_orig->tuple.dst.u.gre.key = callid; exp_orig->tuple.dst.protonum = IPPROTO_GRE; - exp_orig->mask.src.ip = 0xffffffff; + exp_orig->mask.src.ip = htonl(0xffffffff); exp_orig->mask.src.u.all = 0; exp_orig->mask.dst.u.gre.key = htons(0xffff); - exp_orig->mask.dst.ip = 0xffffffff; + exp_orig->mask.dst.ip = htonl(0xffffffff); exp_orig->mask.dst.protonum = 0xff; exp_orig->master = ct; diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index 44889075f3b2..75f7c3db1619 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c @@ -218,7 +218,8 @@ static int help(struct sk_buff **pskb, IPPROTO_TCP }}); exp->mask = ((struct ip_conntrack_tuple) { { 0, { 0 } }, - { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }}); + { htonl(0xFFFFFFFF), + { .tcp = { htons(0xFFFF) } }, 0xFF }}); exp->expectfn = NULL; exp->flags = 0; if (ip_nat_irc_hook) @@ -266,7 +267,7 @@ static int __init ip_conntrack_irc_init(void) hlpr = &irc_helpers[i]; hlpr->tuple.src.u.tcp.port = htons(ports[i]); hlpr->tuple.dst.protonum = IPPROTO_TCP; - hlpr->mask.src.u.tcp.port = 0xFFFF; + hlpr->mask.src.u.tcp.port = htons(0xFFFF); hlpr->mask.dst.protonum = 0xFF; hlpr->max_expected = max_dcc_channels; hlpr->timeout = dcc_timeout; diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c index 4adec47aae32..a1d6a89f64aa 100644 --- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c +++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c @@ -78,12 +78,12 @@ static int help(struct sk_buff **pskb, goto out; exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; - exp->tuple.src.u.udp.port = ntohs(NMBD_PORT); + exp->tuple.src.u.udp.port = htons(NMBD_PORT); exp->mask.src.ip = mask; - exp->mask.src.u.udp.port = 0xFFFF; - exp->mask.dst.ip = 0xFFFFFFFF; - exp->mask.dst.u.udp.port = 0xFFFF; + exp->mask.src.u.udp.port = htons(0xFFFF); + exp->mask.dst.ip = htonl(0xFFFFFFFF); + exp->mask.dst.u.udp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; exp->expectfn = NULL; @@ -115,7 +115,7 @@ static struct ip_conntrack_helper helper = { .src = { .u = { .udp = { - .port = 0xFFFF, + .port = __constant_htons(0xFFFF), } } }, diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 52eddea27e93..53b6dffea6c2 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -78,8 +78,8 @@ ctnetlink_dump_tuples_ip(struct sk_buff *skb, { struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); - NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip); - NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip); + NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(__be32), &tuple->src.ip); + NFA_PUT(skb, CTA_IP_V4_DST, sizeof(__be32), &tuple->dst.ip); NFA_NEST_END(skb, nest_parms); @@ -110,7 +110,7 @@ ctnetlink_dump_tuples(struct sk_buff *skb, static inline int ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct) { - u_int32_t status = htonl((u_int32_t) ct->status); + __be32 status = htonl((u_int32_t) ct->status); NFA_PUT(skb, CTA_STATUS, sizeof(status), &status); return 0; @@ -122,7 +122,7 @@ static inline int ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct) { long timeout_l = ct->timeout.expires - jiffies; - u_int32_t timeout; + __be32 timeout; if (timeout_l < 0) timeout = 0; @@ -192,13 +192,13 @@ ctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct, { enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; struct nfattr *nest_count = NFA_NEST(skb, type); - u_int32_t tmp; + __be32 tmp; tmp = htonl(ct->counters[dir].packets); - NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp); + NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(__be32), &tmp); tmp = htonl(ct->counters[dir].bytes); - NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp); + NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(__be32), &tmp); NFA_NEST_END(skb, nest_count); @@ -215,9 +215,9 @@ nfattr_failure: static inline int ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct) { - u_int32_t mark = htonl(ct->mark); + __be32 mark = htonl(ct->mark); - NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark); + NFA_PUT(skb, CTA_MARK, sizeof(__be32), &mark); return 0; nfattr_failure: @@ -230,8 +230,8 @@ nfattr_failure: static inline int ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct) { - u_int32_t id = htonl(ct->id); - NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id); + __be32 id = htonl(ct->id); + NFA_PUT(skb, CTA_ID, sizeof(__be32), &id); return 0; nfattr_failure: @@ -241,9 +241,9 @@ nfattr_failure: static inline int ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct) { - u_int32_t use = htonl(atomic_read(&ct->ct_general.use)); + __be32 use = htonl(atomic_read(&ct->ct_general.use)); - NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); + NFA_PUT(skb, CTA_USE, sizeof(__be32), &use); return 0; nfattr_failure: @@ -457,8 +457,8 @@ out: } static const size_t cta_min_ip[CTA_IP_MAX] = { - [CTA_IP_V4_SRC-1] = sizeof(u_int32_t), - [CTA_IP_V4_DST-1] = sizeof(u_int32_t), + [CTA_IP_V4_SRC-1] = sizeof(__be32), + [CTA_IP_V4_DST-1] = sizeof(__be32), }; static inline int @@ -475,11 +475,11 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple) if (!tb[CTA_IP_V4_SRC-1]) return -EINVAL; - tuple->src.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); + tuple->src.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); if (!tb[CTA_IP_V4_DST-1]) return -EINVAL; - tuple->dst.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]); + tuple->dst.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]); DEBUGP("leaving\n"); @@ -602,8 +602,8 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr, } static const size_t cta_min_nat[CTA_NAT_MAX] = { - [CTA_NAT_MINIP-1] = sizeof(u_int32_t), - [CTA_NAT_MAXIP-1] = sizeof(u_int32_t), + [CTA_NAT_MINIP-1] = sizeof(__be32), + [CTA_NAT_MAXIP-1] = sizeof(__be32), }; static inline int @@ -623,12 +623,12 @@ ctnetlink_parse_nat(struct nfattr *nat, return -EINVAL; if (tb[CTA_NAT_MINIP-1]) - range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]); + range->min_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MINIP-1]); if (!tb[CTA_NAT_MAXIP-1]) range->max_ip = range->min_ip; else - range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); + range->max_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); if (range->min_ip) range->flags |= IP_NAT_RANGE_MAP_IPS; @@ -663,11 +663,11 @@ ctnetlink_parse_help(struct nfattr *attr, char **helper_name) } static const size_t cta_min[CTA_MAX] = { - [CTA_STATUS-1] = sizeof(u_int32_t), - [CTA_TIMEOUT-1] = sizeof(u_int32_t), - [CTA_MARK-1] = sizeof(u_int32_t), - [CTA_USE-1] = sizeof(u_int32_t), - [CTA_ID-1] = sizeof(u_int32_t) + [CTA_STATUS-1] = sizeof(__be32), + [CTA_TIMEOUT-1] = sizeof(__be32), + [CTA_MARK-1] = sizeof(__be32), + [CTA_USE-1] = sizeof(__be32), + [CTA_ID-1] = sizeof(__be32) }; static int @@ -706,7 +706,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, ct = tuplehash_to_ctrack(h); if (cda[CTA_ID-1]) { - u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1])); + u_int32_t id = ntohl(*(__be32 *)NFA_DATA(cda[CTA_ID-1])); if (ct->id != id) { ip_conntrack_put(ct); return -ENOENT; @@ -808,7 +808,7 @@ static inline int ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[]) { unsigned long d; - unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1])); + unsigned status = ntohl(*(__be32 *)NFA_DATA(cda[CTA_STATUS-1])); d = ct->status ^ status; if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) @@ -903,7 +903,7 @@ ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[]) static inline int ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[]) { - u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); + u_int32_t timeout = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1])); if (!del_timer(&ct->timeout)) return -ETIME; @@ -966,7 +966,7 @@ ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[]) #if defined(CONFIG_IP_NF_CONNTRACK_MARK) if (cda[CTA_MARK-1]) - ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); + ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); #endif DEBUGP("all done\n"); @@ -989,7 +989,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[], if (!cda[CTA_TIMEOUT-1]) goto err; - ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); + ct->timeout.expires = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1])); ct->timeout.expires = jiffies + ct->timeout.expires * HZ; ct->status |= IPS_CONFIRMED; @@ -1006,7 +1006,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[], #if defined(CONFIG_IP_NF_CONNTRACK_MARK) if (cda[CTA_MARK-1]) - ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); + ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); #endif ct->helper = ip_conntrack_helper_find_get(rtuple); @@ -1138,8 +1138,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, const struct ip_conntrack_expect *exp) { struct ip_conntrack *master = exp->master; - u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ); - u_int32_t id = htonl(exp->id); + __be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ); + __be32 id = htonl(exp->id); if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) goto nfattr_failure; @@ -1150,8 +1150,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, CTA_EXPECT_MASTER) < 0) goto nfattr_failure; - NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout); - NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id); + NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(__be32), &timeout); + NFA_PUT(skb, CTA_EXPECT_ID, sizeof(__be32), &id); return 0; @@ -1272,8 +1272,8 @@ out: } static const size_t cta_min_exp[CTA_EXPECT_MAX] = { - [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t), - [CTA_EXPECT_ID-1] = sizeof(u_int32_t) + [CTA_EXPECT_TIMEOUT-1] = sizeof(__be32), + [CTA_EXPECT_ID-1] = sizeof(__be32) }; static int @@ -1321,7 +1321,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, return -ENOENT; if (cda[CTA_EXPECT_ID-1]) { - u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]); + __be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]); if (exp->id != ntohl(id)) { ip_conntrack_expect_put(exp); return -ENOENT; @@ -1375,8 +1375,8 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return -ENOENT; if (cda[CTA_EXPECT_ID-1]) { - u_int32_t id = - *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]); + __be32 id = + *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]); if (exp->id != ntohl(id)) { ip_conntrack_expect_put(exp); return -ENOENT; diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c index 09c40ebe3345..295b6fa340db 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c @@ -261,7 +261,7 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, static int icmp_tuple_to_nfattr(struct sk_buff *skb, const struct ip_conntrack_tuple *t) { - NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t), + NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(__be16), &t->src.u.icmp.id); NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t), &t->dst.u.icmp.type); @@ -287,7 +287,7 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[], tuple->dst.u.icmp.code = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]); tuple->src.u.icmp.id = - *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); + *(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); if (tuple->dst.u.icmp.type >= sizeof(invmap) || !invmap[tuple->dst.u.icmp.type]) diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c index b908a4842e18..2443322e4128 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c @@ -210,7 +210,7 @@ static int sctp_print_conntrack(struct seq_file *s, for (offset = skb->nh.iph->ihl * 4 + sizeof(sctp_sctphdr_t), count = 0; \ offset < skb->len && \ (sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch)); \ - offset += (htons(sch->length) + 3) & ~3, count++) + offset += (ntohs(sch->length) + 3) & ~3, count++) /* Some validity checks to make sure the chunks are fine */ static int do_basic_checks(struct ip_conntrack *conntrack, diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index 03ae9a04cb37..06e4e8a6dd9f 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -519,8 +519,8 @@ static void tcp_sack(const struct sk_buff *skb, /* Fast path for timestamp-only option */ if (length == TCPOLEN_TSTAMP_ALIGNED*4 - && *(__u32 *)ptr == - __constant_ntohl((TCPOPT_NOP << 24) + && *(__be32 *)ptr == + __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) @@ -551,7 +551,7 @@ static void tcp_sack(const struct sk_buff *skb, for (i = 0; i < (opsize - TCPOLEN_SACK_BASE); i += TCPOLEN_SACK_PERBLOCK) { - tmp = ntohl(*((u_int32_t *)(ptr+i)+1)); + tmp = ntohl(*((__be32 *)(ptr+i)+1)); if (after(tmp, *sack)) *sack = tmp; diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index 2893e9c74850..f4f75995a9e4 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -193,7 +193,7 @@ static int skp_digits_len(const char *dptr, const char *limit, int *shift) /* Simple ipaddr parser.. */ static int parse_ipaddr(const char *cp, const char **endp, - u_int32_t *ipaddr, const char *limit) + __be32 *ipaddr, const char *limit) { unsigned long int val; int i, digit = 0; @@ -227,7 +227,7 @@ static int parse_ipaddr(const char *cp, const char **endp, static int epaddr_len(const char *dptr, const char *limit, int *shift) { const char *aux = dptr; - u_int32_t ip; + __be32 ip; if (parse_ipaddr(dptr, &dptr, &ip, limit) < 0) { DEBUGP("ip: %s parse failed.!\n", dptr); @@ -302,7 +302,7 @@ int ct_sip_get_info(const char *dptr, size_t dlen, static int set_expected_rtp(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, - u_int32_t ipaddr, u_int16_t port, + __be32 ipaddr, u_int16_t port, const char *dptr) { struct ip_conntrack_expect *exp; @@ -319,10 +319,10 @@ static int set_expected_rtp(struct sk_buff **pskb, exp->tuple.dst.u.udp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_UDP; - exp->mask.src.ip = 0xFFFFFFFF; + exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.udp.port = 0; - exp->mask.dst.ip = 0xFFFFFFFF; - exp->mask.dst.u.udp.port = 0xFFFF; + exp->mask.dst.ip = htonl(0xFFFFFFFF); + exp->mask.dst.u.udp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; exp->expectfn = NULL; @@ -349,7 +349,7 @@ static int sip_help(struct sk_buff **pskb, const char *dptr; int ret = NF_ACCEPT; int matchoff, matchlen; - u_int32_t ipaddr; + __be32 ipaddr; u_int16_t port; /* No Data ? */ @@ -439,7 +439,7 @@ static int __init init(void) sip[i].tuple.dst.protonum = IPPROTO_UDP; sip[i].tuple.src.u.udp.port = htons(ports[i]); - sip[i].mask.src.u.udp.port = 0xFFFF; + sip[i].mask.src.u.udp.port = htons(0xFFFF); sip[i].mask.dst.protonum = 0xFF; sip[i].max_expected = 2; sip[i].timeout = 3 * 60; /* 3 minutes */ diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c index 7e33d3bed5e3..fe0b634dd377 100644 --- a/net/ipv4/netfilter/ip_conntrack_tftp.c +++ b/net/ipv4/netfilter/ip_conntrack_tftp.c @@ -70,10 +70,10 @@ static int tftp_help(struct sk_buff **pskb, return NF_DROP; exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; - exp->mask.src.ip = 0xffffffff; + exp->mask.src.ip = htonl(0xffffffff); exp->mask.src.u.udp.port = 0; - exp->mask.dst.ip = 0xffffffff; - exp->mask.dst.u.udp.port = 0xffff; + exp->mask.dst.ip = htonl(0xffffffff); + exp->mask.dst.u.udp.port = htons(0xffff); exp->mask.dst.protonum = 0xff; exp->expectfn = NULL; exp->flags = 0; @@ -129,7 +129,7 @@ static int __init ip_conntrack_tftp_init(void) tftp[i].tuple.dst.protonum = IPPROTO_UDP; tftp[i].tuple.src.u.udp.port = htons(ports[i]); tftp[i].mask.dst.protonum = 0xFF; - tftp[i].mask.src.u.udp.port = 0xFFFF; + tftp[i].mask.src.u.udp.port = htons(0xFFFF); tftp[i].max_expected = 1; tftp[i].timeout = 5 * 60; /* 5 minutes */ tftp[i].me = THIS_MODULE; -- cgit v1.2.3 From a76b11dd25957287af12ce6855be6d7fd415b3a9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Sep 2006 14:22:02 -0700 Subject: [NETFILTER]: NAT annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_nat.h | 2 +- net/ipv4/netfilter/ip_nat_core.c | 14 ++++++------- net/ipv4/netfilter/ip_nat_ftp.c | 10 ++++----- net/ipv4/netfilter/ip_nat_helper.c | 37 +++++++++++++++------------------ net/ipv4/netfilter/ip_nat_helper_pptp.c | 2 +- net/ipv4/netfilter/ip_nat_proto_icmp.c | 2 +- net/ipv4/netfilter/ip_nat_proto_tcp.c | 10 ++++----- net/ipv4/netfilter/ip_nat_proto_udp.c | 10 ++++----- net/ipv4/netfilter/ip_nat_rule.c | 6 +++--- net/ipv4/netfilter/ip_nat_sip.c | 8 +++---- net/ipv4/netfilter/ip_nat_snmp_basic.c | 2 +- net/ipv4/netfilter/ip_nat_standalone.c | 2 +- 12 files changed, 51 insertions(+), 54 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h index 98f8407e4cb5..bdf553620ca1 100644 --- a/include/linux/netfilter_ipv4/ip_nat.h +++ b/include/linux/netfilter_ipv4/ip_nat.h @@ -33,7 +33,7 @@ struct ip_nat_range unsigned int flags; /* Inclusive: network order. */ - u_int32_t min_ip, max_ip; + __be32 min_ip, max_ip; /* Inclusive: network order */ union ip_conntrack_manip_proto min, max; diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 71f3e09cbc84..4b6260a97408 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -82,7 +82,7 @@ static inline unsigned int hash_by_src(const struct ip_conntrack_tuple *tuple) { /* Original src, to ensure we map it consistently if poss. */ - return jhash_3words(tuple->src.ip, tuple->src.u.all, + return jhash_3words((__force u32)tuple->src.ip, tuple->src.u.all, tuple->dst.protonum, 0) % ip_nat_htable_size; } @@ -190,7 +190,7 @@ find_best_ips_proto(struct ip_conntrack_tuple *tuple, const struct ip_conntrack *conntrack, enum ip_nat_manip_type maniptype) { - u_int32_t *var_ipp; + __be32 *var_ipp; /* Host order */ u_int32_t minip, maxip, j; @@ -217,7 +217,7 @@ find_best_ips_proto(struct ip_conntrack_tuple *tuple, * like this), even across reboots. */ minip = ntohl(range->min_ip); maxip = ntohl(range->max_ip); - j = jhash_2words(tuple->src.ip, tuple->dst.ip, 0); + j = jhash_2words((__force u32)tuple->src.ip, (__force u32)tuple->dst.ip, 0); *var_ipp = htonl(minip + j % (maxip - minip + 1)); } @@ -534,9 +534,9 @@ int ip_nat_port_range_to_nfattr(struct sk_buff *skb, const struct ip_nat_range *range) { - NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(u_int16_t), + NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), &range->min.tcp.port); - NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(u_int16_t), + NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), &range->max.tcp.port); return 0; @@ -555,7 +555,7 @@ ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range) if (tb[CTA_PROTONAT_PORT_MIN-1]) { ret = 1; range->min.tcp.port = - *(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); + *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); } if (!tb[CTA_PROTONAT_PORT_MAX-1]) { @@ -564,7 +564,7 @@ ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range) } else { ret = 1; range->max.tcp.port = - *(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); + *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); } return ret; diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c index 3328fc5c5f50..a71c233d8112 100644 --- a/net/ipv4/netfilter/ip_nat_ftp.c +++ b/net/ipv4/netfilter/ip_nat_ftp.c @@ -34,7 +34,7 @@ MODULE_DESCRIPTION("ftp NAT helper"); static int mangle_rfc959_packet(struct sk_buff **pskb, - u_int32_t newip, + __be32 newip, u_int16_t port, unsigned int matchoff, unsigned int matchlen, @@ -57,7 +57,7 @@ mangle_rfc959_packet(struct sk_buff **pskb, /* |1|132.235.1.2|6275| */ static int mangle_eprt_packet(struct sk_buff **pskb, - u_int32_t newip, + __be32 newip, u_int16_t port, unsigned int matchoff, unsigned int matchlen, @@ -79,7 +79,7 @@ mangle_eprt_packet(struct sk_buff **pskb, /* |1|132.235.1.2|6275| */ static int mangle_epsv_packet(struct sk_buff **pskb, - u_int32_t newip, + __be32 newip, u_int16_t port, unsigned int matchoff, unsigned int matchlen, @@ -98,7 +98,7 @@ mangle_epsv_packet(struct sk_buff **pskb, matchlen, buffer, strlen(buffer)); } -static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t, +static int (*mangle[])(struct sk_buff **, __be32, u_int16_t, unsigned int, unsigned int, struct ip_conntrack *, @@ -120,7 +120,7 @@ static unsigned int ip_nat_ftp(struct sk_buff **pskb, struct ip_conntrack_expect *exp, u32 *seq) { - u_int32_t newip; + __be32 newip; u_int16_t port; int dir = CTINFO2DIR(ctinfo); struct ip_conntrack *ct = exp->master; diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index e9c5187ea5b2..3bf858480558 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c @@ -189,7 +189,7 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb, datalen, 0)); } else tcph->check = nf_proto_csum_update(*pskb, - htons(oldlen) ^ 0xFFFF, + htons(oldlen) ^ htons(0xFFFF), htons(datalen), tcph->check, 1); @@ -267,7 +267,7 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb, udph->check = -1; } else udph->check = nf_proto_csum_update(*pskb, - htons(oldlen) ^ 0xFFFF, + htons(oldlen) ^ htons(0xFFFF), htons(datalen), udph->check, 1); return 1; @@ -284,26 +284,24 @@ sack_adjust(struct sk_buff *skb, { while (sackoff < sackend) { struct tcp_sack_block_wire *sack; - u_int32_t new_start_seq, new_end_seq; + __be32 new_start_seq, new_end_seq; sack = (void *)skb->data + sackoff; if (after(ntohl(sack->start_seq) - natseq->offset_before, natseq->correction_pos)) - new_start_seq = ntohl(sack->start_seq) - - natseq->offset_after; + new_start_seq = htonl(ntohl(sack->start_seq) + - natseq->offset_after); else - new_start_seq = ntohl(sack->start_seq) - - natseq->offset_before; - new_start_seq = htonl(new_start_seq); + new_start_seq = htonl(ntohl(sack->start_seq) + - natseq->offset_before); if (after(ntohl(sack->end_seq) - natseq->offset_before, natseq->correction_pos)) - new_end_seq = ntohl(sack->end_seq) - - natseq->offset_after; + new_end_seq = htonl(ntohl(sack->end_seq) + - natseq->offset_after); else - new_end_seq = ntohl(sack->end_seq) - - natseq->offset_before; - new_end_seq = htonl(new_end_seq); + new_end_seq = htonl(ntohl(sack->end_seq) + - natseq->offset_before); DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", ntohl(sack->start_seq), new_start_seq, @@ -375,7 +373,8 @@ ip_nat_seq_adjust(struct sk_buff **pskb, enum ip_conntrack_info ctinfo) { struct tcphdr *tcph; - int dir, newseq, newack; + int dir; + __be32 newseq, newack; struct ip_nat_seq *this_way, *other_way; dir = CTINFO2DIR(ctinfo); @@ -388,17 +387,15 @@ ip_nat_seq_adjust(struct sk_buff **pskb, tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; if (after(ntohl(tcph->seq), this_way->correction_pos)) - newseq = ntohl(tcph->seq) + this_way->offset_after; + newseq = htonl(ntohl(tcph->seq) + this_way->offset_after); else - newseq = ntohl(tcph->seq) + this_way->offset_before; - newseq = htonl(newseq); + newseq = htonl(ntohl(tcph->seq) + this_way->offset_before); if (after(ntohl(tcph->ack_seq) - other_way->offset_before, other_way->correction_pos)) - newack = ntohl(tcph->ack_seq) - other_way->offset_after; + newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after); else - newack = ntohl(tcph->ack_seq) - other_way->offset_before; - newack = htonl(newack); + newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq, tcph->check, 0); diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c index 2ff578807123..329fdcd7d702 100644 --- a/net/ipv4/netfilter/ip_nat_helper_pptp.c +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c @@ -51,7 +51,7 @@ #define IP_NAT_PPTP_VERSION "3.0" -#define REQ_CID(req, off) (*(u_int16_t *)((char *)(req) + (off))) +#define REQ_CID(req, off) (*(__be16 *)((char *)(req) + (off))) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c index ec50cc295317..3f6efc13ac74 100644 --- a/net/ipv4/netfilter/ip_nat_proto_icmp.c +++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c @@ -67,7 +67,7 @@ icmp_manip_pkt(struct sk_buff **pskb, hdr = (struct icmphdr *)((*pskb)->data + hdroff); hdr->checksum = nf_proto_csum_update(*pskb, - hdr->un.echo.id ^ 0xFFFF, + hdr->un.echo.id ^ htons(0xFFFF), tuple->src.u.icmp.id, hdr->checksum, 0); hdr->un.echo.id = tuple->src.u.icmp.id; diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c index 72a6307bd2db..12deb13b93b1 100644 --- a/net/ipv4/netfilter/ip_nat_proto_tcp.c +++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c @@ -24,7 +24,7 @@ tcp_in_range(const struct ip_conntrack_tuple *tuple, const union ip_conntrack_manip_proto *min, const union ip_conntrack_manip_proto *max) { - u_int16_t port; + __be16 port; if (maniptype == IP_NAT_MANIP_SRC) port = tuple->src.u.tcp.port; @@ -42,7 +42,7 @@ tcp_unique_tuple(struct ip_conntrack_tuple *tuple, const struct ip_conntrack *conntrack) { static u_int16_t port; - u_int16_t *portptr; + __be16 *portptr; unsigned int range_size, min, i; if (maniptype == IP_NAT_MANIP_SRC) @@ -93,8 +93,8 @@ tcp_manip_pkt(struct sk_buff **pskb, struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); struct tcphdr *hdr; unsigned int hdroff = iphdroff + iph->ihl*4; - u32 oldip, newip; - u16 *portptr, newport, oldport; + __be32 oldip, newip; + __be16 *portptr, newport, oldport; int hdrsize = 8; /* TCP connection tracking guarantees this much */ /* this could be a inner header returned in icmp packet; in such @@ -130,7 +130,7 @@ tcp_manip_pkt(struct sk_buff **pskb, return 1; hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1); - hdr->check = nf_proto_csum_update(*pskb, oldport ^ 0xFFFF, newport, + hdr->check = nf_proto_csum_update(*pskb, oldport ^ htons(0xFFFF), newport, hdr->check, 0); return 1; } diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c index 5da196ae758c..4bbec7730d18 100644 --- a/net/ipv4/netfilter/ip_nat_proto_udp.c +++ b/net/ipv4/netfilter/ip_nat_proto_udp.c @@ -24,7 +24,7 @@ udp_in_range(const struct ip_conntrack_tuple *tuple, const union ip_conntrack_manip_proto *min, const union ip_conntrack_manip_proto *max) { - u_int16_t port; + __be16 port; if (maniptype == IP_NAT_MANIP_SRC) port = tuple->src.u.udp.port; @@ -42,7 +42,7 @@ udp_unique_tuple(struct ip_conntrack_tuple *tuple, const struct ip_conntrack *conntrack) { static u_int16_t port; - u_int16_t *portptr; + __be16 *portptr; unsigned int range_size, min, i; if (maniptype == IP_NAT_MANIP_SRC) @@ -91,8 +91,8 @@ udp_manip_pkt(struct sk_buff **pskb, struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); struct udphdr *hdr; unsigned int hdroff = iphdroff + iph->ihl*4; - u32 oldip, newip; - u16 *portptr, newport; + __be32 oldip, newip; + __be16 *portptr, newport; if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) return 0; @@ -118,7 +118,7 @@ udp_manip_pkt(struct sk_buff **pskb, hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1); hdr->check = nf_proto_csum_update(*pskb, - *portptr ^ 0xFFFF, newport, + *portptr ^ htons(0xFFFF), newport, hdr->check, 0); if (!hdr->check) hdr->check = -1; diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c index 7b703839aa58..a176aa3031e0 100644 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ b/net/ipv4/netfilter/ip_nat_rule.c @@ -119,7 +119,7 @@ static unsigned int ipt_snat_target(struct sk_buff **pskb, } /* Before 2.6.11 we did implicit source NAT if required. Warn about change. */ -static void warn_if_extra_mangle(u32 dstip, u32 srcip) +static void warn_if_extra_mangle(__be32 dstip, __be32 srcip) { static int warned = 0; struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } }; @@ -205,7 +205,7 @@ alloc_null_binding(struct ip_conntrack *conntrack, per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). Use reply in case it's already been mangled (eg local packet). */ - u_int32_t ip + __be32 ip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); @@ -222,7 +222,7 @@ alloc_null_binding_confirmed(struct ip_conntrack *conntrack, struct ip_nat_info *info, unsigned int hooknum) { - u_int32_t ip + __be32 ip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index 6ffba63adca2..71fc2730a007 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -60,8 +60,8 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; unsigned int bufflen, dataoff; - u_int32_t ip; - u_int16_t port; + __be32 ip; + __be16 port; dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); @@ -159,7 +159,7 @@ static int mangle_content_len(struct sk_buff **pskb, static unsigned int mangle_sdp(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct ip_conntrack *ct, - u_int32_t newip, u_int16_t port, + __be32 newip, u_int16_t port, const char *dptr) { char buffer[sizeof("nnn.nnn.nnn.nnn")]; @@ -195,7 +195,7 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb, { struct ip_conntrack *ct = exp->master; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - u_int32_t newip; + __be32 newip; u_int16_t port; DEBUGP("ip_nat_sdp():\n"); diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index 18b7fbdccb61..168f45fa1898 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -1211,7 +1211,7 @@ static int snmp_translate(struct ip_conntrack *ct, struct sk_buff **pskb) { struct iphdr *iph = (*pskb)->nh.iph; - struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl); + struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl); u_int16_t udplen = ntohs(udph->len); u_int16_t paylen = udplen - sizeof(struct udphdr); int dir = CTINFO2DIR(ctinfo); diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 9c577db62047..021395b67463 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -191,7 +191,7 @@ ip_nat_in(unsigned int hooknum, int (*okfn)(struct sk_buff *)) { unsigned int ret; - u_int32_t daddr = (*pskb)->nh.iph->daddr; + __be32 daddr = (*pskb)->nh.iph->daddr; ret = ip_nat_fn(hooknum, pskb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN -- cgit v1.2.3 From 6a19d61472d0802a24493c0d200e88f99ad39cd8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Sep 2006 14:22:24 -0700 Subject: [NETFILTER]: ipt annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ipt_iprange.h | 2 +- net/ipv4/netfilter/ipt_CLUSTERIP.c | 14 +++++++------- net/ipv4/netfilter/ipt_ECN.c | 12 ++++++------ net/ipv4/netfilter/ipt_NETMAP.c | 2 +- net/ipv4/netfilter/ipt_REJECT.c | 4 ++-- net/ipv4/netfilter/ipt_SAME.c | 3 ++- net/ipv4/netfilter/ipt_TCPMSS.c | 17 +++++++++-------- net/ipv4/netfilter/ipt_TOS.c | 4 ++-- net/ipv4/netfilter/ipt_TTL.c | 4 ++-- net/ipv4/netfilter/ipt_hashlimit.c | 16 +++++++++------- net/ipv4/netfilter/ipt_recent.c | 15 +++++++-------- net/ipv4/netfilter/iptable_mangle.c | 2 +- 12 files changed, 49 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ipt_iprange.h b/include/linux/netfilter_ipv4/ipt_iprange.h index 3ecb3bd63676..34ab0fb736e2 100644 --- a/include/linux/netfilter_ipv4/ipt_iprange.h +++ b/include/linux/netfilter_ipv4/ipt_iprange.h @@ -8,7 +8,7 @@ struct ipt_iprange { /* Inclusive: network order. */ - u_int32_t min_ip, max_ip; + __be32 min_ip, max_ip; }; struct ipt_iprange_info diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 41589665fc5d..7a29d6e7baa7 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -52,7 +52,7 @@ struct clusterip_config { atomic_t entries; /* number of entries/rules * referencing us */ - u_int32_t clusterip; /* the IP address */ + __be32 clusterip; /* the IP address */ u_int8_t clustermac[ETH_ALEN]; /* the MAC address */ struct net_device *dev; /* device */ u_int16_t num_total_nodes; /* total number of nodes */ @@ -119,7 +119,7 @@ clusterip_config_entry_put(struct clusterip_config *c) } static struct clusterip_config * -__clusterip_config_find(u_int32_t clusterip) +__clusterip_config_find(__be32 clusterip) { struct list_head *pos; @@ -136,7 +136,7 @@ __clusterip_config_find(u_int32_t clusterip) } static inline struct clusterip_config * -clusterip_config_find_get(u_int32_t clusterip, int entry) +clusterip_config_find_get(__be32 clusterip, int entry) { struct clusterip_config *c; @@ -166,7 +166,7 @@ clusterip_config_init_nodelist(struct clusterip_config *c, } static struct clusterip_config * -clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, +clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip, struct net_device *dev) { struct clusterip_config *c; @@ -387,7 +387,7 @@ checkentry(const char *tablename, return 0; } - if (e->ip.dmsk.s_addr != 0xffffffff + if (e->ip.dmsk.s_addr != htonl(0xffffffff) || e->ip.dst.s_addr == 0) { printk(KERN_ERR "CLUSTERIP: Please specify destination IP\n"); return 0; @@ -476,9 +476,9 @@ static struct ipt_target clusterip_tgt = { /* hardcoded for 48bit ethernet and 32bit ipv4 addresses */ struct arp_payload { u_int8_t src_hw[ETH_ALEN]; - u_int32_t src_ip; + __be32 src_ip; u_int8_t dst_hw[ETH_ALEN]; - u_int32_t dst_ip; + __be32 dst_ip; } __attribute__ ((packed)); #ifdef CLUSTERIP_DEBUG diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 23f9c7ebe7eb..12a818a2462f 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -28,7 +28,7 @@ static inline int set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) { struct iphdr *iph = (*pskb)->nh.iph; - u_int16_t oldtos; + __be16 oldtos; if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { if (!skb_make_writable(pskb, sizeof(struct iphdr))) @@ -37,7 +37,7 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) oldtos = iph->tos; iph->tos &= ~IPT_ECN_IP_MASK; iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK); - iph->check = nf_csum_update(oldtos ^ 0xFFFF, iph->tos, + iph->check = nf_csum_update(oldtos ^ htons(0xFFFF), iph->tos, iph->check); } return 1; @@ -48,7 +48,7 @@ static inline int set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) { struct tcphdr _tcph, *tcph; - u_int16_t oldval; + __be16 oldval; /* Not enought header? */ tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, @@ -66,15 +66,15 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) return 0; tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4; - oldval = ((u_int16_t *)tcph)[6]; + oldval = ((__be16 *)tcph)[6]; if (einfo->operation & IPT_ECN_OP_SET_ECE) tcph->ece = einfo->proto.tcp.ece; if (einfo->operation & IPT_ECN_OP_SET_CWR) tcph->cwr = einfo->proto.tcp.cwr; tcph->check = nf_proto_csum_update((*pskb), - oldval ^ 0xFFFF, - ((u_int16_t *)tcph)[6], + oldval ^ htons(0xFFFF), + ((__be16 *)tcph)[6], tcph->check, 0); return 1; } diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c index beb2914225ff..58a88f227108 100644 --- a/net/ipv4/netfilter/ipt_NETMAP.c +++ b/net/ipv4/netfilter/ipt_NETMAP.c @@ -58,7 +58,7 @@ target(struct sk_buff **pskb, { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; - u_int32_t new_ip, netmask; + __be32 new_ip, netmask; const struct ip_nat_multi_range_compat *mr = targinfo; struct ip_nat_range newrange; diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index b81821edd893..fd0c05efed8a 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -104,8 +104,8 @@ static void send_reset(struct sk_buff *oldskb, int hook) struct iphdr *iph = oldskb->nh.iph; struct tcphdr _otcph, *oth, *tcph; struct rtable *rt; - u_int16_t tmp_port; - u_int32_t tmp_addr; + __be16 tmp_port; + __be32 tmp_addr; int needs_ack; int hh_len; diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c index efbcb1198832..b38b13328d73 100644 --- a/net/ipv4/netfilter/ipt_SAME.c +++ b/net/ipv4/netfilter/ipt_SAME.c @@ -135,7 +135,8 @@ same_target(struct sk_buff **pskb, { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; - u_int32_t tmpip, aindex, new_ip; + u_int32_t tmpip, aindex; + __be32 new_ip; const struct ipt_same_info *same = targinfo; struct ip_nat_range newrange; const struct ip_conntrack_tuple *t; diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c index 4246c4321e5b..108b6b76311f 100644 --- a/net/ipv4/netfilter/ipt_TCPMSS.c +++ b/net/ipv4/netfilter/ipt_TCPMSS.c @@ -42,7 +42,8 @@ ipt_tcpmss_target(struct sk_buff **pskb, const struct ipt_tcpmss_info *tcpmssinfo = targinfo; struct tcphdr *tcph; struct iphdr *iph; - u_int16_t tcplen, newtotlen, oldval, newmss; + u_int16_t tcplen, newmss; + __be16 newtotlen, oldval; unsigned int i; u_int8_t *opt; @@ -97,7 +98,7 @@ ipt_tcpmss_target(struct sk_buff **pskb, opt[i+3] = (newmss & 0x00ff); tcph->check = nf_proto_csum_update(*pskb, - htons(oldmss)^0xFFFF, + htons(oldmss)^htons(0xFFFF), htons(newmss), tcph->check, 0); return IPT_CONTINUE; @@ -126,7 +127,7 @@ ipt_tcpmss_target(struct sk_buff **pskb, memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); tcph->check = nf_proto_csum_update(*pskb, - htons(tcplen) ^ 0xFFFF, + htons(tcplen) ^ htons(0xFFFF), htons(tcplen + TCPOLEN_MSS), tcph->check, 1); opt[0] = TCPOPT_MSS; @@ -134,18 +135,18 @@ ipt_tcpmss_target(struct sk_buff **pskb, opt[2] = (newmss & 0xff00) >> 8; opt[3] = (newmss & 0x00ff); - tcph->check = nf_proto_csum_update(*pskb, ~0, *((u_int32_t *)opt), + tcph->check = nf_proto_csum_update(*pskb, htonl(~0), *((__be32 *)opt), tcph->check, 0); - oldval = ((u_int16_t *)tcph)[6]; + oldval = ((__be16 *)tcph)[6]; tcph->doff += TCPOLEN_MSS/4; tcph->check = nf_proto_csum_update(*pskb, - oldval ^ 0xFFFF, - ((u_int16_t *)tcph)[6], + oldval ^ htons(0xFFFF), + ((__be16 *)tcph)[6], tcph->check, 0); newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS); - iph->check = nf_csum_update(iph->tot_len ^ 0xFFFF, + iph->check = nf_csum_update(iph->tot_len ^ htons(0xFFFF), newtotlen, iph->check); iph->tot_len = newtotlen; return IPT_CONTINUE; diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c index 471a4c438b0a..6b8b14ccc3d3 100644 --- a/net/ipv4/netfilter/ipt_TOS.c +++ b/net/ipv4/netfilter/ipt_TOS.c @@ -30,7 +30,7 @@ target(struct sk_buff **pskb, { const struct ipt_tos_target_info *tosinfo = targinfo; struct iphdr *iph = (*pskb)->nh.iph; - u_int16_t oldtos; + __be16 oldtos; if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { if (!skb_make_writable(pskb, sizeof(struct iphdr))) @@ -38,7 +38,7 @@ target(struct sk_buff **pskb, iph = (*pskb)->nh.iph; oldtos = iph->tos; iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; - iph->check = nf_csum_update(oldtos ^ 0xFFFF, iph->tos, + iph->check = nf_csum_update(oldtos ^ htons(0xFFFF), iph->tos, iph->check); } return IPT_CONTINUE; diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c index 96e79cc6d0f2..ac9517d62af0 100644 --- a/net/ipv4/netfilter/ipt_TTL.c +++ b/net/ipv4/netfilter/ipt_TTL.c @@ -54,8 +54,8 @@ ipt_ttl_target(struct sk_buff **pskb, } if (new_ttl != iph->ttl) { - iph->check = nf_csum_update(ntohs((iph->ttl << 8)) ^ 0xFFFF, - ntohs(new_ttl << 8), + iph->check = nf_csum_update(htons((iph->ttl << 8)) ^ htons(0xFFFF), + htons(new_ttl << 8), iph->check); iph->ttl = new_ttl; } diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c index 4f73a61aa3dd..33ccdbf8e794 100644 --- a/net/ipv4/netfilter/ipt_hashlimit.c +++ b/net/ipv4/netfilter/ipt_hashlimit.c @@ -50,11 +50,11 @@ static struct file_operations dl_file_ops; /* hash table crap */ struct dsthash_dst { - u_int32_t src_ip; - u_int32_t dst_ip; + __be32 src_ip; + __be32 dst_ip; /* ports have to be consecutive !!! */ - u_int16_t src_port; - u_int16_t dst_port; + __be16 src_port; + __be16 dst_port; }; struct dsthash_ent { @@ -106,8 +106,10 @@ static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b) static inline u_int32_t hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst) { - return (jhash_3words(dst->dst_ip, (dst->dst_port<<16 | dst->src_port), - dst->src_ip, ht->rnd) % ht->cfg.size); + return (jhash_3words((__force u32)dst->dst_ip, + ((__force u32)dst->dst_port<<16 | + (__force u32)dst->src_port), + (__force u32)dst->src_ip, ht->rnd) % ht->cfg.size); } static inline struct dsthash_ent * @@ -406,7 +408,7 @@ hashlimit_match(const struct sk_buff *skb, dst.src_ip = skb->nh.iph->saddr; if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT ||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) { - u_int16_t _ports[2], *ports; + __be16 _ports[2], *ports; switch (skb->nh.iph->protocol) { case IPPROTO_TCP: diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index 32ae8d7ac506..126db44e71a8 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c @@ -50,11 +50,10 @@ MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/ipt_recent/* files"); MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/ipt_recent/* files"); MODULE_PARM_DESC(ip_list_gid,"owning group of /proc/net/ipt_recent/* files"); - struct recent_entry { struct list_head list; struct list_head lru_list; - u_int32_t addr; + __be32 addr; u_int8_t ttl; u_int8_t index; u_int16_t nstamps; @@ -85,17 +84,17 @@ static struct file_operations recent_fops; static u_int32_t hash_rnd; static int hash_rnd_initted; -static unsigned int recent_entry_hash(u_int32_t addr) +static unsigned int recent_entry_hash(__be32 addr) { if (!hash_rnd_initted) { get_random_bytes(&hash_rnd, 4); hash_rnd_initted = 1; } - return jhash_1word(addr, hash_rnd) & (ip_list_hash_size - 1); + return jhash_1word((__force u32)addr, hash_rnd) & (ip_list_hash_size - 1); } static struct recent_entry * -recent_entry_lookup(const struct recent_table *table, u_int32_t addr, u_int8_t ttl) +recent_entry_lookup(const struct recent_table *table, __be32 addr, u_int8_t ttl) { struct recent_entry *e; unsigned int h; @@ -116,7 +115,7 @@ static void recent_entry_remove(struct recent_table *t, struct recent_entry *e) } static struct recent_entry * -recent_entry_init(struct recent_table *t, u_int32_t addr, u_int8_t ttl) +recent_entry_init(struct recent_table *t, __be32 addr, u_int8_t ttl) { struct recent_entry *e; @@ -178,7 +177,7 @@ ipt_recent_match(const struct sk_buff *skb, const struct ipt_recent_info *info = matchinfo; struct recent_table *t; struct recent_entry *e; - u_int32_t addr; + __be32 addr; u_int8_t ttl; int ret = info->invert; @@ -406,7 +405,7 @@ static ssize_t recent_proc_write(struct file *file, const char __user *input, struct recent_table *t = pde->data; struct recent_entry *e; char buf[sizeof("+255.255.255.255")], *c = buf; - u_int32_t addr; + __be32 addr; int add; if (size > sizeof(buf)) diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 79336cb42527..e62ea2bb9c0a 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -131,7 +131,7 @@ ipt_local_hook(unsigned int hook, { unsigned int ret; u_int8_t tos; - u_int32_t saddr, daddr; + __be32 saddr, daddr; unsigned long nfmark; /* root is playing with raw sockets. */ -- cgit v1.2.3 From d4263cde88d3fee2af0aac8836bb785cdb6b06c0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Sep 2006 14:22:51 -0700 Subject: [NETFILTER]: h323 annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack_h323.h | 6 +- net/ipv4/netfilter/ip_conntrack_helper_h323.c | 84 ++++++++++++------------ net/ipv4/netfilter/ip_nat_helper_h323.c | 16 ++--- 3 files changed, 53 insertions(+), 53 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h index 3cbff7379002..943cc6a4871d 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h @@ -30,7 +30,7 @@ struct ip_ct_h323_master { struct ip_conntrack_expect; extern int get_h225_addr(unsigned char *data, TransportAddress * addr, - u_int32_t * ip, u_int16_t * port); + __be32 * ip, u_int16_t * port); extern void ip_conntrack_h245_expect(struct ip_conntrack *new, struct ip_conntrack_expect *this); extern void ip_conntrack_q931_expect(struct ip_conntrack *new, @@ -38,11 +38,11 @@ extern void ip_conntrack_q931_expect(struct ip_conntrack *new, extern int (*set_h245_addr_hook) (struct sk_buff ** pskb, unsigned char **data, int dataoff, H245_TransportAddress * addr, - u_int32_t ip, u_int16_t port); + __be32 ip, u_int16_t port); extern int (*set_h225_addr_hook) (struct sk_buff ** pskb, unsigned char **data, int dataoff, TransportAddress * addr, - u_int32_t ip, u_int16_t port); + __be32 ip, u_int16_t port); extern int (*set_sig_addr_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, enum ip_conntrack_info ctinfo, diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index 9a39e2969712..7b7441202bfd 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -49,11 +49,11 @@ MODULE_PARM_DESC(callforward_filter, "only create call forwarding expectations " int (*set_h245_addr_hook) (struct sk_buff ** pskb, unsigned char **data, int dataoff, H245_TransportAddress * addr, - u_int32_t ip, u_int16_t port); + __be32 ip, u_int16_t port); int (*set_h225_addr_hook) (struct sk_buff ** pskb, unsigned char **data, int dataoff, TransportAddress * addr, - u_int32_t ip, u_int16_t port); + __be32 ip, u_int16_t port); int (*set_sig_addr_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, enum ip_conntrack_info ctinfo, @@ -209,7 +209,7 @@ static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct, /****************************************************************************/ static int get_h245_addr(unsigned char *data, H245_TransportAddress * addr, - u_int32_t * ip, u_int16_t * port) + __be32 * ip, u_int16_t * port) { unsigned char *p; @@ -232,7 +232,7 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, { int dir = CTINFO2DIR(ctinfo); int ret = 0; - u_int32_t ip; + __be32 ip; u_int16_t port; u_int16_t rtp_port; struct ip_conntrack_expect *rtp_exp; @@ -254,10 +254,10 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, rtp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; rtp_exp->tuple.dst.u.udp.port = htons(rtp_port); rtp_exp->tuple.dst.protonum = IPPROTO_UDP; - rtp_exp->mask.src.ip = 0xFFFFFFFF; + rtp_exp->mask.src.ip = htonl(0xFFFFFFFF); rtp_exp->mask.src.u.udp.port = 0; - rtp_exp->mask.dst.ip = 0xFFFFFFFF; - rtp_exp->mask.dst.u.udp.port = 0xFFFF; + rtp_exp->mask.dst.ip = htonl(0xFFFFFFFF); + rtp_exp->mask.dst.u.udp.port = htons(0xFFFF); rtp_exp->mask.dst.protonum = 0xFF; rtp_exp->flags = 0; @@ -271,10 +271,10 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, rtcp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; rtcp_exp->tuple.dst.u.udp.port = htons(rtp_port + 1); rtcp_exp->tuple.dst.protonum = IPPROTO_UDP; - rtcp_exp->mask.src.ip = 0xFFFFFFFF; + rtcp_exp->mask.src.ip = htonl(0xFFFFFFFF); rtcp_exp->mask.src.u.udp.port = 0; - rtcp_exp->mask.dst.ip = 0xFFFFFFFF; - rtcp_exp->mask.dst.u.udp.port = 0xFFFF; + rtcp_exp->mask.dst.ip = htonl(0xFFFFFFFF); + rtcp_exp->mask.dst.u.udp.port = htons(0xFFFF); rtcp_exp->mask.dst.protonum = 0xFF; rtcp_exp->flags = 0; @@ -325,7 +325,7 @@ static int expect_t120(struct sk_buff **pskb, { int dir = CTINFO2DIR(ctinfo); int ret = 0; - u_int32_t ip; + __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp = NULL; @@ -342,10 +342,10 @@ static int expect_t120(struct sk_buff **pskb, exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; - exp->mask.src.ip = 0xFFFFFFFF; + exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; - exp->mask.dst.ip = 0xFFFFFFFF; - exp->mask.dst.u.tcp.port = 0xFFFF; + exp->mask.dst.ip = htonl(0xFFFFFFFF); + exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */ @@ -626,7 +626,7 @@ void ip_conntrack_h245_expect(struct ip_conntrack *new, /****************************************************************************/ int get_h225_addr(unsigned char *data, TransportAddress * addr, - u_int32_t * ip, u_int16_t * port) + __be32 * ip, u_int16_t * port) { unsigned char *p; @@ -648,7 +648,7 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct, { int dir = CTINFO2DIR(ctinfo); int ret = 0; - u_int32_t ip; + __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp = NULL; @@ -665,10 +665,10 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct, exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; - exp->mask.src.ip = 0xFFFFFFFF; + exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; - exp->mask.dst.ip = 0xFFFFFFFF; - exp->mask.dst.u.tcp.port = 0xFFFF; + exp->mask.dst.ip = htonl(0xFFFFFFFF); + exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; exp->flags = 0; @@ -709,7 +709,7 @@ static int expect_callforwarding(struct sk_buff **pskb, { int dir = CTINFO2DIR(ctinfo); int ret = 0; - u_int32_t ip; + __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp = NULL; @@ -751,10 +751,10 @@ static int expect_callforwarding(struct sk_buff **pskb, exp->tuple.dst.ip = ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; - exp->mask.src.ip = 0xFFFFFFFF; + exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; - exp->mask.dst.ip = 0xFFFFFFFF; - exp->mask.dst.u.tcp.port = 0xFFFF; + exp->mask.dst.ip = htonl(0xFFFFFFFF); + exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; exp->flags = 0; @@ -791,7 +791,7 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, int dir = CTINFO2DIR(ctinfo); int ret; int i; - u_int32_t ip; + __be32 ip; u_int16_t port; DEBUGP("ip_ct_q931: Setup\n"); @@ -1188,7 +1188,7 @@ static unsigned char *get_udp_data(struct sk_buff **pskb, int *datalen) /****************************************************************************/ static struct ip_conntrack_expect *find_expect(struct ip_conntrack *ct, - u_int32_t ip, u_int16_t port) + __be32 ip, u_int16_t port) { struct ip_conntrack_expect *exp; struct ip_conntrack_tuple tuple; @@ -1228,7 +1228,7 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct, int dir = CTINFO2DIR(ctinfo); int ret = 0; int i; - u_int32_t ip; + __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp; @@ -1251,10 +1251,10 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct, exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; - exp->mask.src.ip = gkrouted_only ? 0xFFFFFFFF : 0; + exp->mask.src.ip = gkrouted_only ? htonl(0xFFFFFFFF) : 0; exp->mask.src.u.tcp.port = 0; - exp->mask.dst.ip = 0xFFFFFFFF; - exp->mask.dst.u.tcp.port = 0xFFFF; + exp->mask.dst.ip = htonl(0xFFFFFFFF); + exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */ @@ -1307,7 +1307,7 @@ static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct, { int dir = CTINFO2DIR(ctinfo); int ret = 0; - u_int32_t ip; + __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp; @@ -1333,10 +1333,10 @@ static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct, exp->tuple.dst.ip = ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_UDP; - exp->mask.src.ip = 0xFFFFFFFF; + exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; - exp->mask.dst.ip = 0xFFFFFFFF; - exp->mask.dst.u.tcp.port = 0xFFFF; + exp->mask.dst.ip = htonl(0xFFFFFFFF); + exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; exp->flags = 0; exp->expectfn = ip_conntrack_ras_expect; @@ -1477,7 +1477,7 @@ static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct, { struct ip_ct_h323_master *info = &ct->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); - u_int32_t ip; + __be32 ip; u_int16_t port; DEBUGP("ip_ct_ras: ARQ\n"); @@ -1513,7 +1513,7 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct, { int dir = CTINFO2DIR(ctinfo); int ret = 0; - u_int32_t ip; + __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp; @@ -1538,10 +1538,10 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct, exp->tuple.dst.ip = ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; - exp->mask.src.ip = 0xFFFFFFFF; + exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; - exp->mask.dst.ip = 0xFFFFFFFF; - exp->mask.dst.u.tcp.port = 0xFFFF; + exp->mask.dst.ip = htonl(0xFFFFFFFF); + exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; exp->flags = IP_CT_EXPECT_PERMANENT; exp->expectfn = ip_conntrack_q931_expect; @@ -1581,7 +1581,7 @@ static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct, { int dir = CTINFO2DIR(ctinfo); int ret = 0; - u_int32_t ip; + __be32 ip; u_int16_t port; struct ip_conntrack_expect *exp = NULL; @@ -1598,10 +1598,10 @@ static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct, exp->tuple.dst.ip = ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; - exp->mask.src.ip = 0xFFFFFFFF; + exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; - exp->mask.dst.ip = 0xFFFFFFFF; - exp->mask.dst.u.tcp.port = 0xFFFF; + exp->mask.dst.ip = htonl(0xFFFFFFFF); + exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; exp->flags = IP_CT_EXPECT_PERMANENT; exp->expectfn = ip_conntrack_q931_expect; diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c index 419b878fb467..4a7d34466ee2 100644 --- a/net/ipv4/netfilter/ip_nat_helper_h323.c +++ b/net/ipv4/netfilter/ip_nat_helper_h323.c @@ -32,13 +32,13 @@ /****************************************************************************/ static int set_addr(struct sk_buff **pskb, unsigned char **data, int dataoff, - unsigned int addroff, u_int32_t ip, u_int16_t port) + unsigned int addroff, __be32 ip, u_int16_t port) { enum ip_conntrack_info ctinfo; struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo); struct { - u_int32_t ip; - u_int16_t port; + __be32 ip; + __be16 port; } __attribute__ ((__packed__)) buf; struct tcphdr _tcph, *th; @@ -86,7 +86,7 @@ static int set_addr(struct sk_buff **pskb, static int set_h225_addr(struct sk_buff **pskb, unsigned char **data, int dataoff, TransportAddress * addr, - u_int32_t ip, u_int16_t port) + __be32 ip, u_int16_t port) { return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port); } @@ -95,7 +95,7 @@ static int set_h225_addr(struct sk_buff **pskb, static int set_h245_addr(struct sk_buff **pskb, unsigned char **data, int dataoff, H245_TransportAddress * addr, - u_int32_t ip, u_int16_t port) + __be32 ip, u_int16_t port) { return set_addr(pskb, data, dataoff, addr->unicastAddress.iPAddress.network, ip, port); @@ -110,7 +110,7 @@ static int set_sig_addr(struct sk_buff **pskb, struct ip_conntrack *ct, struct ip_ct_h323_master *info = &ct->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); int i; - u_int32_t ip; + __be32 ip; u_int16_t port; for (i = 0; i < count; i++) { @@ -164,7 +164,7 @@ static int set_ras_addr(struct sk_buff **pskb, struct ip_conntrack *ct, { int dir = CTINFO2DIR(ctinfo); int i; - u_int32_t ip; + __be32 ip; u_int16_t port; for (i = 0; i < count; i++) { @@ -433,7 +433,7 @@ static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct, struct ip_ct_h323_master *info = &ct->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); u_int16_t nated_port = port; - u_int32_t ip; + __be32 ip; /* Set expectations for NAT */ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; -- cgit v1.2.3 From 32f50cdee666333168b5203c7864bede159f789e Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Thu, 28 Sep 2006 14:51:47 -0700 Subject: [NetLabel]: add audit support for configuration changes This patch adds audit support to NetLabel, including six new audit message types shown below. #define AUDIT_MAC_UNLBL_ACCEPT 1406 #define AUDIT_MAC_UNLBL_DENY 1407 #define AUDIT_MAC_CIPSOV4_ADD 1408 #define AUDIT_MAC_CIPSOV4_DEL 1409 #define AUDIT_MAC_MAP_ADD 1410 #define AUDIT_MAC_MAP_DEL 1411 Signed-off-by: Paul Moore Acked-by: James Morris Signed-off-by: David S. Miller --- include/linux/audit.h | 6 +++ include/net/cipso_ipv4.h | 5 ++- include/net/netlabel.h | 2 +- net/ipv4/cipso_ipv4.c | 8 +++- net/netlabel/netlabel_cipso_v4.c | 43 +++++++++++++----- net/netlabel/netlabel_domainhash.c | 54 +++++++++++++++++++--- net/netlabel/netlabel_domainhash.h | 6 +-- net/netlabel/netlabel_mgmt.c | 14 +++--- net/netlabel/netlabel_unlabeled.c | 36 ++++++++++++--- net/netlabel/netlabel_user.c | 91 ++++++++++++++++++++++++++++++++++++++ net/netlabel/netlabel_user.h | 6 +++ 11 files changed, 235 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/include/linux/audit.h b/include/linux/audit.h index 40a6c26294ae..42719d07612a 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -95,6 +95,12 @@ #define AUDIT_MAC_POLICY_LOAD 1403 /* Policy file load */ #define AUDIT_MAC_STATUS 1404 /* Changed enforcing,permissive,off */ #define AUDIT_MAC_CONFIG_CHANGE 1405 /* Changes to booleans */ +#define AUDIT_MAC_UNLBL_ACCEPT 1406 /* NetLabel: allow unlabeled traffic */ +#define AUDIT_MAC_UNLBL_DENY 1407 /* NetLabel: deny unlabeled traffic */ +#define AUDIT_MAC_CIPSOV4_ADD 1408 /* NetLabel: add CIPSOv4 DOI entry */ +#define AUDIT_MAC_CIPSOV4_DEL 1409 /* NetLabel: del CIPSOv4 DOI entry */ +#define AUDIT_MAC_MAP_ADD 1410 /* NetLabel: add LSM domain mapping */ +#define AUDIT_MAC_MAP_DEL 1411 /* NetLabel: del LSM domain mapping */ #define AUDIT_FIRST_KERN_ANOM_MSG 1700 #define AUDIT_LAST_KERN_ANOM_MSG 1799 diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index 2d72496c2029..5d6ae1b2b196 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h @@ -128,7 +128,9 @@ extern int cipso_v4_rbm_strictvalid; #ifdef CONFIG_NETLABEL int cipso_v4_doi_add(struct cipso_v4_doi *doi_def); -int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head)); +int cipso_v4_doi_remove(u32 doi, + u32 audit_secid, + void (*callback) (struct rcu_head * head)); struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); int cipso_v4_doi_walk(u32 *skip_cnt, int (*callback) (struct cipso_v4_doi *doi_def, void *arg), @@ -143,6 +145,7 @@ static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) } static inline int cipso_v4_doi_remove(u32 doi, + u32 audit_secid, void (*callback) (struct rcu_head * head)) { return 0; diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 6692430063fd..190bfdbbdba6 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h @@ -96,7 +96,7 @@ struct netlbl_dom_map; /* Domain mapping operations */ -int netlbl_domhsh_remove(const char *domain); +int netlbl_domhsh_remove(const char *domain, u32 audit_secid); /* LSM security attributes */ struct netlbl_lsm_cache { diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index e6ce0b3ba62a..c4e469ff842d 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -474,6 +474,7 @@ doi_add_failure_rlock: /** * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine * @doi: the DOI value + * @audit_secid: the LSM secid to use in the audit message * @callback: the DOI cleanup/free callback * * Description: @@ -483,7 +484,9 @@ doi_add_failure_rlock: * success and negative values on failure. * */ -int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head)) +int cipso_v4_doi_remove(u32 doi, + u32 audit_secid, + void (*callback) (struct rcu_head * head)) { struct cipso_v4_doi *doi_def; struct cipso_v4_domhsh_entry *dom_iter; @@ -502,7 +505,8 @@ int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head)) spin_unlock(&cipso_v4_doi_list_lock); list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list) if (dom_iter->valid) - netlbl_domhsh_remove(dom_iter->domain); + netlbl_domhsh_remove(dom_iter->domain, + audit_secid); cipso_v4_cache_invalidate(); rcu_read_unlock(); diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index 4125a55f469f..09986ca962a6 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -162,8 +163,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) int nla_a_rem; int nla_b_rem; - if (!info->attrs[NLBL_CIPSOV4_A_DOI] || - !info->attrs[NLBL_CIPSOV4_A_TAGLST] || + if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] || !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST]) return -EINVAL; @@ -344,8 +344,7 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info) int ret_val; struct cipso_v4_doi *doi_def = NULL; - if (!info->attrs[NLBL_CIPSOV4_A_DOI] || - !info->attrs[NLBL_CIPSOV4_A_TAGLST]) + if (!info->attrs[NLBL_CIPSOV4_A_TAGLST]) return -EINVAL; doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); @@ -381,21 +380,35 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) { int ret_val = -EINVAL; - u32 map_type; + u32 type; + u32 doi; + const char *type_str = "(unknown)"; + struct audit_buffer *audit_buf; - if (!info->attrs[NLBL_CIPSOV4_A_MTYPE]) + if (!info->attrs[NLBL_CIPSOV4_A_DOI] || + !info->attrs[NLBL_CIPSOV4_A_MTYPE]) return -EINVAL; - map_type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); - switch (map_type) { + type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); + switch (type) { case CIPSO_V4_MAP_STD: + type_str = "std"; ret_val = netlbl_cipsov4_add_std(info); break; case CIPSO_V4_MAP_PASS: + type_str = "pass"; ret_val = netlbl_cipsov4_add_pass(info); break; } + if (ret_val == 0) { + doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); + audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, + NETLINK_CB(skb).sid); + audit_log_format(audit_buf, " doi=%u type=%s", doi, type_str); + audit_log_end(audit_buf); + } + return ret_val; } @@ -653,11 +666,21 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) { int ret_val = -EINVAL; - u32 doi; + u32 doi = 0; + struct audit_buffer *audit_buf; if (info->attrs[NLBL_CIPSOV4_A_DOI]) { doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); - ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free); + ret_val = cipso_v4_doi_remove(doi, + NETLINK_CB(skb).sid, + netlbl_cipsov4_doi_free); + } + + if (ret_val == 0) { + audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, + NETLINK_CB(skb).sid); + audit_log_format(audit_buf, " doi=%u", doi); + audit_log_end(audit_buf); } return ret_val; diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index f56d7a8ac7b7..d64e2ae3b129 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c @@ -35,12 +35,14 @@ #include #include #include +#include #include #include #include #include "netlabel_mgmt.h" #include "netlabel_domainhash.h" +#include "netlabel_user.h" struct netlbl_domhsh_tbl { struct list_head *tbl; @@ -186,6 +188,7 @@ int netlbl_domhsh_init(u32 size) /** * netlbl_domhsh_add - Adds a entry to the domain hash table * @entry: the entry to add + * @audit_secid: the LSM secid to use in the audit message * * Description: * Adds a new entry to the domain hash table and handles any updates to the @@ -193,10 +196,12 @@ int netlbl_domhsh_init(u32 size) * negative on failure. * */ -int netlbl_domhsh_add(struct netlbl_dom_map *entry) +int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid) { int ret_val; u32 bkt; + struct audit_buffer *audit_buf; + char *audit_domain; switch (entry->type) { case NETLBL_NLTYPE_UNLABELED: @@ -236,6 +241,26 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry) spin_unlock(&netlbl_domhsh_def_lock); } else ret_val = -EINVAL; + if (ret_val == 0) { + if (entry->domain != NULL) + audit_domain = entry->domain; + else + audit_domain = "(default)"; + audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, + audit_secid); + audit_log_format(audit_buf, " domain=%s", audit_domain); + switch (entry->type) { + case NETLBL_NLTYPE_UNLABELED: + audit_log_format(audit_buf, " protocol=unlbl"); + break; + case NETLBL_NLTYPE_CIPSOV4: + audit_log_format(audit_buf, + " protocol=cipsov4 doi=%u", + entry->type_def.cipsov4->doi); + break; + } + audit_log_end(audit_buf); + } rcu_read_unlock(); if (ret_val != 0) { @@ -254,6 +279,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry) /** * netlbl_domhsh_add_default - Adds the default entry to the domain hash table * @entry: the entry to add + * @audit_secid: the LSM secid to use in the audit message * * Description: * Adds a new default entry to the domain hash table and handles any updates @@ -261,14 +287,15 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry) * negative on failure. * */ -int netlbl_domhsh_add_default(struct netlbl_dom_map *entry) +int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, u32 audit_secid) { - return netlbl_domhsh_add(entry); + return netlbl_domhsh_add(entry, audit_secid); } /** * netlbl_domhsh_remove - Removes an entry from the domain hash table * @domain: the domain to remove + * @audit_secid: the LSM secid to use in the audit message * * Description: * Removes an entry from the domain hash table and handles any updates to the @@ -276,10 +303,12 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry) * negative on failure. * */ -int netlbl_domhsh_remove(const char *domain) +int netlbl_domhsh_remove(const char *domain, u32 audit_secid) { int ret_val = -ENOENT; struct netlbl_dom_map *entry; + struct audit_buffer *audit_buf; + char *audit_domain; rcu_read_lock(); if (domain != NULL) @@ -316,8 +345,18 @@ int netlbl_domhsh_remove(const char *domain) ret_val = -ENOENT; spin_unlock(&netlbl_domhsh_def_lock); } - if (ret_val == 0) + if (ret_val == 0) { + if (entry->domain != NULL) + audit_domain = entry->domain; + else + audit_domain = "(default)"; + audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, + audit_secid); + audit_log_format(audit_buf, " domain=%s", audit_domain); + audit_log_end(audit_buf); + call_rcu(&entry->rcu, netlbl_domhsh_free_entry); + } remove_return: rcu_read_unlock(); @@ -326,6 +365,7 @@ remove_return: /** * netlbl_domhsh_remove_default - Removes the default entry from the table + * @audit_secid: the LSM secid to use in the audit message * * Description: * Removes/resets the default entry for the domain hash table and handles any @@ -333,9 +373,9 @@ remove_return: * success, non-zero on failure. * */ -int netlbl_domhsh_remove_default(void) +int netlbl_domhsh_remove_default(u32 audit_secid) { - return netlbl_domhsh_remove(NULL); + return netlbl_domhsh_remove(NULL, audit_secid); } /** diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h index 02af72a7877c..d50f13cacdca 100644 --- a/net/netlabel/netlabel_domainhash.h +++ b/net/netlabel/netlabel_domainhash.h @@ -57,9 +57,9 @@ struct netlbl_dom_map { int netlbl_domhsh_init(u32 size); /* Manipulate the domain hash table */ -int netlbl_domhsh_add(struct netlbl_dom_map *entry); -int netlbl_domhsh_add_default(struct netlbl_dom_map *entry); -int netlbl_domhsh_remove_default(void); +int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid); +int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, u32 audit_secid); +int netlbl_domhsh_remove_default(u32 audit_secid); struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); int netlbl_domhsh_walk(u32 *skip_bkt, u32 *skip_chain, diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 8626c9f678eb..0ac314f18ad1 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -108,7 +108,7 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) switch (entry->type) { case NETLBL_NLTYPE_UNLABELED: - ret_val = netlbl_domhsh_add(entry); + ret_val = netlbl_domhsh_add(entry, NETLINK_CB(skb).sid); break; case NETLBL_NLTYPE_CIPSOV4: if (!info->attrs[NLBL_MGMT_A_CV4DOI]) @@ -125,7 +125,7 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) rcu_read_unlock(); goto add_failure; } - ret_val = netlbl_domhsh_add(entry); + ret_val = netlbl_domhsh_add(entry, NETLINK_CB(skb).sid); rcu_read_unlock(); break; default: @@ -161,7 +161,7 @@ static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) return -EINVAL; domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); - return netlbl_domhsh_remove(domain); + return netlbl_domhsh_remove(domain, NETLINK_CB(skb).sid); } /** @@ -277,7 +277,8 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) switch (entry->type) { case NETLBL_NLTYPE_UNLABELED: - ret_val = netlbl_domhsh_add_default(entry); + ret_val = netlbl_domhsh_add_default(entry, + NETLINK_CB(skb).sid); break; case NETLBL_NLTYPE_CIPSOV4: if (!info->attrs[NLBL_MGMT_A_CV4DOI]) @@ -294,7 +295,8 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) rcu_read_unlock(); goto adddef_failure; } - ret_val = netlbl_domhsh_add_default(entry); + ret_val = netlbl_domhsh_add_default(entry, + NETLINK_CB(skb).sid); rcu_read_unlock(); break; default: @@ -322,7 +324,7 @@ adddef_failure: */ static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) { - return netlbl_domhsh_remove_default(); + return netlbl_domhsh_remove_default(NETLINK_CB(skb).sid); } /** diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 440f5c4e1e2d..ab36675fee8c 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -63,6 +63,27 @@ static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, }; +/* + * Helper Functions + */ + +/** + * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag + * @value: desired value + * @audit_secid: the LSM secid to use in the audit message + * + * Description: + * Set the value of the unlabeled accept flag to @value. + * + */ +static void netlbl_unlabel_acceptflg_set(u8 value, u32 audit_secid) +{ + atomic_set(&netlabel_unlabel_accept_flg, value); + netlbl_audit_nomsg((value ? + AUDIT_MAC_UNLBL_ACCEPT : AUDIT_MAC_UNLBL_DENY), + audit_secid); +} + /* * NetLabel Command Handlers */ @@ -79,18 +100,18 @@ static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { */ static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info) { - int ret_val = -EINVAL; u8 value; if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) { value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]); if (value == 1 || value == 0) { - atomic_set(&netlabel_unlabel_accept_flg, value); - ret_val = 0; + netlbl_unlabel_acceptflg_set(value, + NETLINK_CB(skb).sid); + return 0; } } - return ret_val; + return -EINVAL; } /** @@ -229,16 +250,19 @@ int netlbl_unlabel_defconf(void) { int ret_val; struct netlbl_dom_map *entry; + u32 secid; + + security_task_getsecid(current, &secid); entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (entry == NULL) return -ENOMEM; entry->type = NETLBL_NLTYPE_UNLABELED; - ret_val = netlbl_domhsh_add_default(entry); + ret_val = netlbl_domhsh_add_default(entry, secid); if (ret_val != 0) return ret_val; - atomic_set(&netlabel_unlabel_accept_flg, 1); + netlbl_unlabel_acceptflg_set(1, secid); return 0; } diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c index eeb7d768d2bb..c2343af584cb 100644 --- a/net/netlabel/netlabel_user.c +++ b/net/netlabel/netlabel_user.c @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -74,3 +77,91 @@ int netlbl_netlink_init(void) return 0; } + +/* + * NetLabel Audit Functions + */ + +/** + * netlbl_audit_start_common - Start an audit message + * @type: audit message type + * @secid: LSM context ID + * + * Description: + * Start an audit message using the type specified in @type and fill the audit + * message with some fields common to all NetLabel audit messages. Returns + * a pointer to the audit buffer on success, NULL on failure. + * + */ +struct audit_buffer *netlbl_audit_start_common(int type, u32 secid) +{ + struct audit_context *audit_ctx = current->audit_context; + struct audit_buffer *audit_buf; + uid_t audit_loginuid; + const char *audit_tty; + char audit_comm[sizeof(current->comm)]; + struct vm_area_struct *vma; + char *secctx; + u32 secctx_len; + + audit_buf = audit_log_start(audit_ctx, GFP_ATOMIC, type); + if (audit_buf == NULL) + return NULL; + + audit_loginuid = audit_get_loginuid(audit_ctx); + if (current->signal && + current->signal->tty && + current->signal->tty->name) + audit_tty = current->signal->tty->name; + else + audit_tty = "(none)"; + get_task_comm(audit_comm, current); + + audit_log_format(audit_buf, + "netlabel: auid=%u uid=%u tty=%s pid=%d", + audit_loginuid, + current->uid, + audit_tty, + current->pid); + audit_log_format(audit_buf, " comm="); + audit_log_untrustedstring(audit_buf, audit_comm); + if (current->mm) { + down_read(¤t->mm->mmap_sem); + vma = current->mm->mmap; + while (vma) { + if ((vma->vm_flags & VM_EXECUTABLE) && + vma->vm_file) { + audit_log_d_path(audit_buf, + " exe=", + vma->vm_file->f_dentry, + vma->vm_file->f_vfsmnt); + break; + } + vma = vma->vm_next; + } + up_read(¤t->mm->mmap_sem); + } + + if (secid != 0 && + security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) + audit_log_format(audit_buf, " subj=%s", secctx); + + return audit_buf; +} + +/** + * netlbl_audit_nomsg - Send an audit message without additional text + * @type: audit message type + * @secid: LSM context ID + * + * Description: + * Send an audit message with only the common NetLabel audit fields. + * + */ +void netlbl_audit_nomsg(int type, u32 secid) +{ + struct audit_buffer *audit_buf; + + audit_buf = netlbl_audit_start_common(type, secid); + audit_log_end(audit_buf); +} diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h index 3f9386b917df..ab840acfc964 100644 --- a/net/netlabel/netlabel_user.h +++ b/net/netlabel/netlabel_user.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -75,4 +76,9 @@ static inline void *netlbl_netlink_hdr_put(struct sk_buff *skb, int netlbl_netlink_init(void); +/* NetLabel Audit Functions */ + +struct audit_buffer *netlbl_audit_start_common(int type, u32 secid); +void netlbl_audit_nomsg(int type, u32 secid); + #endif -- cgit v1.2.3 From 0891a8d706d6e6838a926b6dec42f95581747d0e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 29 Sep 2006 01:58:34 -0700 Subject: [PATCH] __percpu_alloc_mask() has to be __always_inline in UP case ... or we'll end up with cpu_online_map being evaluated on UP. In modules. cpumask.h is very careful to avoid that, and for a very good reason. So should we... PS: yes, it really triggers (on alpha). Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/percpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/percpu.h b/include/linux/percpu.h index 3835a9642f13..46ec72fa2c84 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -74,7 +74,7 @@ static inline int __percpu_populate_mask(void *__pdata, size_t size, gfp_t gfp, return 0; } -static inline void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask) +static __always_inline void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask) { return kzalloc(size, gfp); } -- cgit v1.2.3 From e04da1dfd9041e306cb33d1b40b6005c23c5b325 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 29 Sep 2006 01:58:35 -0700 Subject: [PATCH] sys_getcpu() prototype annotated Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/syscalls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 3f0f716225ec..2d1c3d5c83ac 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -597,6 +597,6 @@ asmlinkage long sys_get_robust_list(int pid, size_t __user *len_ptr); asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len); -asmlinkage long sys_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *cache); +asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); #endif -- cgit v1.2.3 From f71b2f10f56802075d67c5710cd9f1816382d720 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Fri, 29 Sep 2006 01:58:39 -0700 Subject: [PATCH] JBD: Make journal_brelse_array() static It's always good to make symbols static when we can, and this also eliminates the need to rename the function in jbd2 Suggested by Eric Sandeen. Signed-off-by: Dave Kleikamp Cc: Eric Sandeen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd/recovery.c | 2 +- include/linux/jbd.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index 445eed6ce5dc..11563fe2a52b 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -46,7 +46,7 @@ static int scan_revoke_records(journal_t *, struct buffer_head *, #ifdef __KERNEL__ /* Release readahead buffers after use */ -void journal_brelse_array(struct buffer_head *b[], int n) +static void journal_brelse_array(struct buffer_head *b[], int n) { while (--n >= 0) brelse (b[n]); diff --git a/include/linux/jbd.h b/include/linux/jbd.h index a6d9daa38c6d..fe89444b1c6f 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -977,7 +977,6 @@ extern void journal_write_revoke_records(journal_t *, transaction_t *); extern int journal_set_revoke(journal_t *, unsigned long, tid_t); extern int journal_test_revoke(journal_t *, unsigned long, tid_t); extern void journal_clear_revoke(journal_t *); -extern void journal_brelse_array(struct buffer_head *b[], int n); extern void journal_switch_revoke_table(journal_t *journal); /* -- cgit v1.2.3 From 2dcea57ae19275451a756a2d5bf96b329487b0e0 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 29 Sep 2006 01:58:41 -0700 Subject: [PATCH] convert s390 page handling macros to functions Convert s390 page handling macros to functions. In particular this fixes a problem with s390's SetPageUptodate macro which uses its input parameter twice which again can cause subtle bugs. [akpm@osdl.org: build fix] Cc: Martin Schwidefsky Signed-off-by: Heiko Carstens Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/s390/appldata/appldata_base.c | 2 +- include/asm-s390/pgtable.h | 84 ++++++++++++++++++-------------------- include/linux/page-flags.h | 11 +++-- 3 files changed, 46 insertions(+), 51 deletions(-) (limited to 'include/linux') diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 9a8f6ff21652..2b1e6c9a6e0e 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 83425cdefc91..ecdff13b2505 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -31,9 +31,9 @@ * the S390 page table tree. */ #ifndef __ASSEMBLY__ +#include #include #include -#include struct vm_area_struct; /* forward declaration (include/linux/mm.h) */ struct mm_struct; @@ -597,31 +597,31 @@ ptep_establish(struct vm_area_struct *vma, * should therefore only be called if it is not mapped in any * address space. */ -#define page_test_and_clear_dirty(_page) \ -({ \ - struct page *__page = (_page); \ - unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT); \ - int __skey = page_get_storage_key(__physpage); \ - if (__skey & _PAGE_CHANGED) \ - page_set_storage_key(__physpage, __skey & ~_PAGE_CHANGED);\ - (__skey & _PAGE_CHANGED); \ -}) +static inline int page_test_and_clear_dirty(struct page *page) +{ + unsigned long physpage = __pa((page - mem_map) << PAGE_SHIFT); + int skey = page_get_storage_key(physpage); + + if (skey & _PAGE_CHANGED) + page_set_storage_key(physpage, skey & ~_PAGE_CHANGED); + return skey & _PAGE_CHANGED; +} /* * Test and clear referenced bit in storage key. */ -#define page_test_and_clear_young(page) \ -({ \ - struct page *__page = (page); \ - unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT);\ - int __ccode; \ - asm volatile( \ - " rrbe 0,%1\n" \ - " ipm %0\n" \ - " srl %0,28\n" \ - : "=d" (__ccode) : "a" (__physpage) : "cc"); \ - (__ccode & 2); \ -}) +static inline int page_test_and_clear_young(struct page *page) +{ + unsigned long physpage = __pa((page - mem_map) << PAGE_SHIFT); + int ccode; + + asm volatile ( + "rrbe 0,%1\n" + "ipm %0\n" + "srl %0,28\n" + : "=d" (ccode) : "a" (physpage) : "cc" ); + return ccode & 2; +} /* * Conversion functions: convert a page and protection to a page entry, @@ -634,32 +634,28 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) return __pte; } -#define mk_pte(pg, pgprot) \ -({ \ - struct page *__page = (pg); \ - pgprot_t __pgprot = (pgprot); \ - unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT); \ - pte_t __pte = mk_pte_phys(__physpage, __pgprot); \ - __pte; \ -}) +static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) +{ + unsigned long physpage = __pa((page - mem_map) << PAGE_SHIFT); -#define pfn_pte(pfn, pgprot) \ -({ \ - pgprot_t __pgprot = (pgprot); \ - unsigned long __physpage = __pa((pfn) << PAGE_SHIFT); \ - pte_t __pte = mk_pte_phys(__physpage, __pgprot); \ - __pte; \ -}) + return mk_pte_phys(physpage, pgprot); +} + +static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot) +{ + unsigned long physpage = __pa((pfn) << PAGE_SHIFT); + + return mk_pte_phys(physpage, pgprot); +} #ifdef __s390x__ -#define pfn_pmd(pfn, pgprot) \ -({ \ - pgprot_t __pgprot = (pgprot); \ - unsigned long __physpage = __pa((pfn) << PAGE_SHIFT); \ - pmd_t __pmd = __pmd(__physpage + pgprot_val(__pgprot)); \ - __pmd; \ -}) +static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot) +{ + unsigned long physpage = __pa((pfn) << PAGE_SHIFT); + + return __pmd(physpage + pgprot_val(pgprot)); +} #endif /* __s390x__ */ diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 9d7921dd50f0..4830a3bedfb2 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -128,12 +128,11 @@ #define PageUptodate(page) test_bit(PG_uptodate, &(page)->flags) #ifdef CONFIG_S390 -#define SetPageUptodate(_page) \ - do { \ - struct page *__page = (_page); \ - if (!test_and_set_bit(PG_uptodate, &__page->flags)) \ - page_test_and_clear_dirty(_page); \ - } while (0) +static inline void SetPageUptodate(struct page *page) +{ + if (!test_and_set_bit(PG_uptodate, &page->flags)) + page_test_and_clear_dirty(page); +} #else #define SetPageUptodate(page) set_bit(PG_uptodate, &(page)->flags) #endif -- cgit v1.2.3 From 199a9afc3dbe98c35326f1d3907ab94dae953a6e Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 29 Sep 2006 01:59:00 -0700 Subject: [PATCH] Debug variants of linked list macros Signed-off-by: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/list.h | 15 ++++++++++ lib/Kconfig.debug | 9 ++++++ lib/Makefile | 1 + lib/list_debug.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 lib/list_debug.c (limited to 'include/linux') diff --git a/include/linux/list.h b/include/linux/list.h index 65a5b5ceda49..a9c90287c0ff 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -39,6 +39,7 @@ static inline void INIT_LIST_HEAD(struct list_head *list) * This is only for internal list manipulation where we know * the prev/next entries already! */ +#ifndef CONFIG_DEBUG_LIST static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) @@ -48,6 +49,11 @@ static inline void __list_add(struct list_head *new, new->prev = prev; prev->next = new; } +#else +extern void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next); +#endif /** * list_add - add a new entry @@ -57,10 +63,15 @@ static inline void __list_add(struct list_head *new, * Insert a new entry after the specified head. * This is good for implementing stacks. */ +#ifndef CONFIG_DEBUG_LIST static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } +#else +extern void list_add(struct list_head *new, struct list_head *head); +#endif + /** * list_add_tail - add a new entry @@ -153,12 +164,16 @@ static inline void __list_del(struct list_head * prev, struct list_head * next) * Note: list_empty on entry does not return true after this, the entry is * in an undefined state. */ +#ifndef CONFIG_DEBUG_LIST static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } +#else +extern void list_del(struct list_head *entry); +#endif /** * list_del_rcu - deletes entry from list without re-initialization diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index b0f5ca72599f..f9ae75cc0145 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -320,6 +320,15 @@ config DEBUG_VM If unsure, say N. +config DEBUG_LIST + bool "Debug linked list manipulation" + depends on DEBUG_KERNEL + help + Enable this to turn on extended checks in the linked-list + walking routines. + + If unsure, say N. + config FRAME_POINTER bool "Compile the kernel with frame pointers" depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32 || SUPERH) diff --git a/lib/Makefile b/lib/Makefile index ef1d37afbbb6..402762fead70 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -28,6 +28,7 @@ lib-$(CONFIG_GENERIC_HWEIGHT) += hweight.o obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o obj-$(CONFIG_PLIST) += plist.o obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o +obj-$(CONFIG_DEBUG_LIST) += list_debug.o ifneq ($(CONFIG_HAVE_DEC_LOCK),y) lib-y += dec_and_lock.o diff --git a/lib/list_debug.c b/lib/list_debug.c new file mode 100644 index 000000000000..1aae85cef92c --- /dev/null +++ b/lib/list_debug.c @@ -0,0 +1,77 @@ +/* + * Copyright 2006, Red Hat, Inc., Dave Jones + * Released under the General Public License (GPL). + * + * This file contains the linked list implementations for + * DEBUG_LIST. + */ + +#include +#include + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ + +void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + if (unlikely(next->prev != prev)) { + printk(KERN_ERR "list_add corruption. next->prev should be %p, but was %p\n", + prev, next->prev); + BUG(); + } + if (unlikely(prev->next != next)) { + printk(KERN_ERR "list_add corruption. prev->next should be %p, but was %p\n", + next, prev->next); + BUG(); + } + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} +EXPORT_SYMBOL(__list_add); + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} +EXPORT_SYMBOL(list_add); + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +void list_del(struct list_head *entry) +{ + if (unlikely(entry->prev->next != entry)) { + printk(KERN_ERR "list_del corruption. prev->next should be %p, but was %p\n", + entry, entry->prev->next); + BUG(); + } + if (unlikely(entry->next->prev != entry)) { + printk(KERN_ERR "list_del corruption. next->prev should be %p, but was %p\n", + entry, entry->next->prev); + BUG(); + } + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} +EXPORT_SYMBOL(list_del); + -- cgit v1.2.3 From 9938406ab6b2558d60c0c7200cc8e12f1ea7104a Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Fri, 29 Sep 2006 01:59:03 -0700 Subject: [PATCH] Make touch_nmi_watchdog imply touch_softlockup_watchdog on all archs touch_nmi_watchdog() calls touch_softlockup_watchdog() on both architectures that implement it (i386 and x86_64). On other architectures it does nothing at all. touch_nmi_watchdog() should imply touch_softlockup_watchdog() on all architectures. Suggested by Andi Kleen. [heiko.carstens@de.ibm.com: s390 fix] Signed-off-by: Michal Schmidt Cc: Andi Kleen Cc: Martin Schwidefsky Signed-off-by: Heiko Carstens Cc: Michal Schmidt Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-s390/irq.h | 3 --- include/linux/nmi.h | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/asm-s390/irq.h b/include/asm-s390/irq.h index bd1a721f7aa2..7da991a858f8 100644 --- a/include/asm-s390/irq.h +++ b/include/asm-s390/irq.h @@ -19,8 +19,5 @@ enum interruption_class { NR_IRQS, }; -#define touch_nmi_watchdog() do { } while(0) - #endif /* __KERNEL__ */ #endif - diff --git a/include/linux/nmi.h b/include/linux/nmi.h index c8f4d2f627d7..e16904e28c3a 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -4,6 +4,7 @@ #ifndef LINUX_NMI_H #define LINUX_NMI_H +#include #include /** @@ -16,7 +17,7 @@ #ifdef ARCH_HAS_NMI_WATCHDOG extern void touch_nmi_watchdog(void); #else -# define touch_nmi_watchdog() do { } while(0) +# define touch_nmi_watchdog() touch_softlockup_watchdog() #endif #endif -- cgit v1.2.3 From 58012cd788443b9d144bd7c72260a84b6b30f45d Mon Sep 17 00:00:00 2001 From: Chris Boot Date: Fri, 29 Sep 2006 01:59:07 -0700 Subject: [PATCH] scx200_gpio export cleanups Use EXPORT_SYMBOL_GPL for new symbols, and declare the struct in the header file for access by other modules. Signed-off-by: Chris Boot Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/scx200_gpio.c | 2 +- include/linux/scx200_gpio.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index b1f88c66b2b5..99e5272e3c53 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c @@ -44,7 +44,7 @@ struct nsc_gpio_ops scx200_gpio_ops = { .gpio_change = scx200_gpio_change, .gpio_current = scx200_gpio_current }; -EXPORT_SYMBOL(scx200_gpio_ops); +EXPORT_SYMBOL_GPL(scx200_gpio_ops); static int scx200_gpio_open(struct inode *inode, struct file *file) { diff --git a/include/linux/scx200_gpio.h b/include/linux/scx200_gpio.h index 90dd069cc145..1a82d30c4b17 100644 --- a/include/linux/scx200_gpio.h +++ b/include/linux/scx200_gpio.h @@ -4,6 +4,7 @@ u32 scx200_gpio_configure(unsigned index, u32 set, u32 clear); extern unsigned scx200_gpio_base; extern long scx200_gpio_shadow[2]; +extern struct nsc_gpio_ops scx200_gpio_ops; #define scx200_gpio_present() (scx200_gpio_base!=0) -- cgit v1.2.3 From 6c9979185c7ef4feeb7f8d29be032b8f032a1838 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Fri, 29 Sep 2006 01:59:11 -0700 Subject: [PATCH] kthread: convert loop.c to kthread Convert loop.c from the deprecated kernel_thread to kthread. This patch simplifies the code quite a bit and passes similar testing to the previous submission on both emulated x86 and s390. Changes since last submission: switched to using a rather simple loop based on wait_event_interruptible. Signed-off-by: Serge E. Hallyn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/loop.c | 69 ++++++++++++++++++---------------------------------- include/linux/loop.h | 5 ++-- 2 files changed, 26 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index c774121684d7..e87b88731adc 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -72,6 +72,7 @@ #include #include #include +#include #include @@ -522,15 +523,12 @@ static int loop_make_request(request_queue_t *q, struct bio *old_bio) goto out; if (unlikely(rw == WRITE && (lo->lo_flags & LO_FLAGS_READ_ONLY))) goto out; - lo->lo_pending++; loop_add_bio(lo, old_bio); + wake_up(&lo->lo_event); spin_unlock_irq(&lo->lo_lock); - complete(&lo->lo_bh_done); return 0; out: - if (lo->lo_pending == 0) - complete(&lo->lo_bh_done); spin_unlock_irq(&lo->lo_lock); bio_io_error(old_bio, old_bio->bi_size); return 0; @@ -570,14 +568,18 @@ static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio) * to avoid blocking in our make_request_fn. it also does loop decrypting * on reads for block backed loop, as that is too heavy to do from * b_end_io context where irqs may be disabled. + * + * Loop explanation: loop_clr_fd() sets lo_state to Lo_rundown before + * calling kthread_stop(). Therefore once kthread_should_stop() is + * true, make_request will not place any more requests. Therefore + * once kthread_should_stop() is true and lo_bio is NULL, we are + * done with the loop. */ static int loop_thread(void *data) { struct loop_device *lo = data; struct bio *bio; - daemonize("loop%d", lo->lo_number); - /* * loop can be used in an encrypted device, * hence, it mustn't be stopped at all @@ -587,47 +589,21 @@ static int loop_thread(void *data) set_user_nice(current, -20); - lo->lo_state = Lo_bound; - lo->lo_pending = 1; - - /* - * complete it, we are running - */ - complete(&lo->lo_done); + while (!kthread_should_stop() || lo->lo_bio) { - for (;;) { - int pending; + wait_event_interruptible(lo->lo_event, + lo->lo_bio || kthread_should_stop()); - if (wait_for_completion_interruptible(&lo->lo_bh_done)) + if (!lo->lo_bio) continue; - spin_lock_irq(&lo->lo_lock); - - /* - * could be completed because of tear-down, not pending work - */ - if (unlikely(!lo->lo_pending)) { - spin_unlock_irq(&lo->lo_lock); - break; - } - bio = loop_get_bio(lo); - lo->lo_pending--; - pending = lo->lo_pending; spin_unlock_irq(&lo->lo_lock); BUG_ON(!bio); loop_handle_bio(lo, bio); - - /* - * upped both for pending work and tear-down, lo_pending - * will hit zero then - */ - if (unlikely(!pending)) - break; } - complete(&lo->lo_done); return 0; } @@ -840,10 +816,15 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, set_blocksize(bdev, lo_blocksize); - error = kernel_thread(loop_thread, lo, CLONE_KERNEL); - if (error < 0) + lo->lo_thread = kthread_create(loop_thread, lo, "loop%d", + lo->lo_number); + if (IS_ERR(lo->lo_thread)) { + error = PTR_ERR(lo->lo_thread); + lo->lo_thread = NULL; goto out_putf; - wait_for_completion(&lo->lo_done); + } + lo->lo_state = Lo_bound; + wake_up_process(lo->lo_thread); return 0; out_putf: @@ -907,12 +888,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) spin_lock_irq(&lo->lo_lock); lo->lo_state = Lo_rundown; - lo->lo_pending--; - if (!lo->lo_pending) - complete(&lo->lo_bh_done); spin_unlock_irq(&lo->lo_lock); - wait_for_completion(&lo->lo_done); + kthread_stop(lo->lo_thread); lo->lo_backing_file = NULL; @@ -925,6 +903,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) lo->lo_sizelimit = 0; lo->lo_encrypt_key_size = 0; lo->lo_flags = 0; + lo->lo_thread = NULL; memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); memset(lo->lo_file_name, 0, LO_NAME_SIZE); @@ -1287,9 +1266,9 @@ static int __init loop_init(void) if (!lo->lo_queue) goto out_mem4; mutex_init(&lo->lo_ctl_mutex); - init_completion(&lo->lo_done); - init_completion(&lo->lo_bh_done); lo->lo_number = i; + lo->lo_thread = NULL; + init_waitqueue_head(&lo->lo_event); spin_lock_init(&lo->lo_lock); disk->major = LOOP_MAJOR; disk->first_minor = i; diff --git a/include/linux/loop.h b/include/linux/loop.h index e76c7611d6cc..191a595055f0 100644 --- a/include/linux/loop.h +++ b/include/linux/loop.h @@ -59,10 +59,9 @@ struct loop_device { struct bio *lo_bio; struct bio *lo_biotail; int lo_state; - struct completion lo_done; - struct completion lo_bh_done; struct mutex lo_ctl_mutex; - int lo_pending; + struct task_struct *lo_thread; + wait_queue_head_t lo_event; request_queue_t *lo_queue; }; -- cgit v1.2.3 From db0b0ead60815155c791e8f479ee4777e7946369 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 29 Sep 2006 01:59:28 -0700 Subject: [PATCH] lockdep: don't pull in includes when lockdep disabled Do not pull in various includes through lockdep.h if lockdep is disabled. Signed-off-by: Michael S. Tsirkin Cc: Ingo Molnar Cc: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/lockdep.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index c040a8c969aa..1314ca0f29be 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -8,13 +8,13 @@ #ifndef __LINUX_LOCKDEP_H #define __LINUX_LOCKDEP_H +#ifdef CONFIG_LOCKDEP + #include #include #include #include -#ifdef CONFIG_LOCKDEP - /* * Lock-class usage-state bits: */ -- cgit v1.2.3 From 650a898342b3fa21c392c06a2b7010fa19823efa Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 29 Sep 2006 01:59:35 -0700 Subject: [PATCH] vfs: define new lookup flag for chdir In the "operation does permission checking" model used by fuse, chdir permission is not checked, since there's no chdir method. For this case set a lookup flag, which will be passed to ->permission(), so fuse can distinguish it from permission checks for other operations. Signed-off-by: Miklos Szeredi Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fuse/dir.c | 2 +- fs/open.c | 3 ++- include/linux/namei.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 409ce6a7cca4..f85b2a282f13 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -776,7 +776,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) return -EACCES; - if (nd && (nd->flags & LOOKUP_ACCESS)) + if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) return fuse_access(inode, mask); return 0; } diff --git a/fs/open.c b/fs/open.c index 303f06d2a7b9..1574d8fe4909 100644 --- a/fs/open.c +++ b/fs/open.c @@ -546,7 +546,8 @@ asmlinkage long sys_chdir(const char __user * filename) struct nameidata nd; int error; - error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd); + error = __user_walk(filename, + LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd); if (error) goto out; diff --git a/include/linux/namei.h b/include/linux/namei.h index 45511a5918d3..c6470ba00668 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -54,6 +54,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_OPEN (0x0100) #define LOOKUP_CREATE (0x0200) #define LOOKUP_ACCESS (0x0400) +#define LOOKUP_CHDIR (0x0800) extern int FASTCALL(__user_walk(const char __user *, unsigned, struct nameidata *)); extern int FASTCALL(__user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *)); -- cgit v1.2.3 From 2e0c1f6ce7b816f63fea2af3e5e2cb20c66430e9 Mon Sep 17 00:00:00 2001 From: Shem Multinymous Date: Fri, 29 Sep 2006 01:59:37 -0700 Subject: [PATCH] DMI: Decode and save OEM String information This teaches dmi_decode() how to decode and save OEM Strings (type 11) DMI information, which is currently discarded silently. Existing code using DMI is not affected. Follows the "System Management BIOS (SMBIOS) Specification" (http://www.dmtf.org/standards/smbios), and also the userspace dmidecode.c code. OEM Strings are the only safe way to identify some hardware, e.g., the ThinkPad embedded controller used by the soon-to-be-submitted tp_smapi driver. This will also let us eliminate the long whitelist in the mainline hdaps driver (in a future patch). Signed-off-by: Shem Multinymous Cc: Bjorn Helgaas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/firmware/dmi_scan.c | 23 +++++++++++++++++++++++ include/linux/dmi.h | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index b9e3886d9e16..b8b596d5778d 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -123,6 +123,26 @@ static void __init dmi_save_devices(struct dmi_header *dm) dev->type = *d++ & 0x7f; dev->name = dmi_string(dm, *d); dev->device_data = NULL; + list_add(&dev->list, &dmi_devices); + } +} + +static void __init dmi_save_oem_strings_devices(struct dmi_header *dm) +{ + int i, count = *(u8 *)(dm + 1); + struct dmi_device *dev; + + for (i = 1; i <= count; i++) { + dev = dmi_alloc(sizeof(*dev)); + if (!dev) { + printk(KERN_ERR + "dmi_save_oem_strings_devices: out of memory.\n"); + break; + } + + dev->type = DMI_DEV_TYPE_OEM_STRING; + dev->name = dmi_string(dm, i); + dev->device_data = NULL; list_add(&dev->list, &dmi_devices); } @@ -181,6 +201,9 @@ static void __init dmi_decode(struct dmi_header *dm) case 10: /* Onboard Devices Information */ dmi_save_devices(dm); break; + case 11: /* OEM Strings */ + dmi_save_oem_strings_devices(dm); + break; case 38: /* IPMI Device Information */ dmi_save_ipmi_device(dm); } diff --git a/include/linux/dmi.h b/include/linux/dmi.h index b2cd2071d432..38dc403be70b 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -27,7 +27,8 @@ enum dmi_device_type { DMI_DEV_TYPE_ETHERNET, DMI_DEV_TYPE_TOKENRING, DMI_DEV_TYPE_SOUND, - DMI_DEV_TYPE_IPMI = -1 + DMI_DEV_TYPE_IPMI = -1, + DMI_DEV_TYPE_OEM_STRING = -2 }; struct dmi_header { -- cgit v1.2.3 From 402749ea2538be9ddad981a990739b93a0178bc6 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Fri, 29 Sep 2006 01:59:37 -0700 Subject: [PATCH] Remove unused tty_struct field Unused: tty_struct.max_flip_cnt $ git grep max_flip_cnt include/linux/tty.h: int max_flip_cnt; $ Cc: Paul Fulghum Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/tty.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/tty.h b/include/linux/tty.h index 04827ca65781..d1dec3d0c814 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -190,7 +190,6 @@ struct tty_struct { struct tty_struct *link; struct fasync_struct *fasync; struct tty_bufhead buf; - int max_flip_cnt; int alt_speed; /* For magic substitution of 38400 bps */ wait_queue_head_t write_wait; wait_queue_head_t read_wait; -- cgit v1.2.3 From 3d5b6fccc4b900cc4267692f015ea500bad4c6bf Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 29 Sep 2006 01:59:40 -0700 Subject: [PATCH] task_struct: ifdef Missed'em V IPC ipc/sem.c only. $ agrep sysvsem -w -n ipc/sem.c:912: undo_list = current->sysvsem.undo_list; ipc/sem.c:932: undo_list = current->sysvsem.undo_list; ipc/sem.c:954: undo_list = current->sysvsem.undo_list; ipc/sem.c:963: current->sysvsem.undo_list = undo_list; ipc/sem.c:1247: tsk->sysvsem.undo_list = undo_list; ipc/sem.c:1249: tsk->sysvsem.undo_list = NULL; ipc/sem.c:1271: undo_list = tsk->sysvsem.undo_list; include/linux/sched.h:876: struct sysv_sem sysvsem; Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 9d4aa7f95bc8..27122575d902 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -886,8 +886,10 @@ struct task_struct { - initialized normally by flush_old_exec */ /* file system info */ int link_count, total_link_count; +#ifdef CONFIG_SYSVIPC /* ipc stuff */ struct sysv_sem sysvsem; +#endif /* CPU-specific state of this task */ struct thread_struct thread; /* filesystem information */ -- cgit v1.2.3 From 6c5c934153513dc72e2d6464f39e8ef1f27c0a3e Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 29 Sep 2006 01:59:40 -0700 Subject: [PATCH] ifdef blktrace debugging fields Signed-off-by: Alexey Dobriyan Acked-by: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- block/blktrace.c | 6 ++++-- block/ll_rw_blk.c | 3 +-- include/linux/blkdev.h | 4 ++-- include/linux/sched.h | 3 ++- kernel/fork.c | 2 ++ 5 files changed, 11 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/block/blktrace.c b/block/blktrace.c index 2b4ef2b89b8d..8ff33441d8a2 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -450,8 +450,10 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg) **/ void blk_trace_shutdown(request_queue_t *q) { - blk_trace_startstop(q, 0); - blk_trace_remove(q); + if (q->blk_trace) { + blk_trace_startstop(q, 0); + blk_trace_remove(q); + } } /* diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 9c3a06bcb7ba..51dc0edf76e0 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1847,8 +1847,7 @@ static void blk_release_queue(struct kobject *kobj) if (q->queue_tags) __blk_queue_free_tags(q); - if (q->blk_trace) - blk_trace_shutdown(q); + blk_trace_shutdown(q); kmem_cache_free(requestq_cachep, q); } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c773ee545ebd..cfde8b3ee919 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -417,9 +417,9 @@ struct request_queue unsigned int sg_timeout; unsigned int sg_reserved_size; int node; - +#ifdef CONFIG_BLK_DEV_IO_TRACE struct blk_trace *blk_trace; - +#endif /* * reserved for flush operations */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 27122575d902..3696f2f7126d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -784,8 +784,9 @@ struct task_struct { struct prio_array *array; unsigned short ioprio; +#ifdef CONFIG_BLK_DEV_IO_TRACE unsigned int btrace_seq; - +#endif unsigned long sleep_avg; unsigned long long timestamp, last_ran; unsigned long long sched_time; /* sched_clock time spent running */ diff --git a/kernel/fork.c b/kernel/fork.c index 802b1cf0e63f..bca6ce6d3ded 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -183,7 +183,9 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) /* One for us, one for whoever does the "release_task()" (usually parent) */ atomic_set(&tsk->usage,2); atomic_set(&tsk->fs_excl, 0); +#ifdef CONFIG_BLK_DEV_IO_TRACE tsk->btrace_seq = 0; +#endif tsk->splice_pipe = NULL; return tsk; } -- cgit v1.2.3 From d6bd3a39f7c6ebad49c261c3d458df974c880758 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Fri, 29 Sep 2006 01:59:48 -0700 Subject: [PATCH] Move valid_dma_direction() from x86_64 to generic code As suggested by Muli Ben-Yehuda this function is moved to generic code as may be useful for all archs. [akpm@osdl.org: fix] Signed-off-by: Rolf Eike Beer Cc: Muli Ben-Yehuda Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/pci-swiotlb.c | 3 ++- drivers/net/fec_8xx/fec_main.c | 2 +- drivers/net/fs_enet/fs_enet.h | 3 +-- include/asm-x86_64/dma-mapping.h | 7 ------- include/linux/dma-mapping.h | 7 +++++++ 5 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c index 6a55f87ba97f..697f0aa794b9 100644 --- a/arch/x86_64/kernel/pci-swiotlb.c +++ b/arch/x86_64/kernel/pci-swiotlb.c @@ -3,7 +3,8 @@ #include #include #include -#include +#include + #include #include #include diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c index 22ac2df1aeb0..e17a1449ee10 100644 --- a/drivers/net/fec_8xx/fec_main.c +++ b/drivers/net/fec_8xx/fec_main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #include #include -#include #include "fec_8xx.h" diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 95022c005f75..92590d8fc24b 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -6,11 +6,10 @@ #include #include #include +#include #include -#include - #ifdef CONFIG_CPM1 #include diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h index b6da83dcc7a6..10174b110a5c 100644 --- a/include/asm-x86_64/dma-mapping.h +++ b/include/asm-x86_64/dma-mapping.h @@ -55,13 +55,6 @@ extern dma_addr_t bad_dma_address; extern struct dma_mapping_ops* dma_ops; extern int iommu_merge; -static inline int valid_dma_direction(int dma_direction) -{ - return ((dma_direction == DMA_BIDIRECTIONAL) || - (dma_direction == DMA_TO_DEVICE) || - (dma_direction == DMA_FROM_DEVICE)); -} - static inline int dma_mapping_error(dma_addr_t dma_addr) { if (dma_ops->mapping_error) diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 635690cf3e3d..ff203c465fed 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -24,6 +24,13 @@ enum dma_data_direction { #define DMA_28BIT_MASK 0x000000000fffffffULL #define DMA_24BIT_MASK 0x0000000000ffffffULL +static inline int valid_dma_direction(int dma_direction) +{ + return ((dma_direction == DMA_BIDIRECTIONAL) || + (dma_direction == DMA_TO_DEVICE) || + (dma_direction == DMA_FROM_DEVICE)); +} + #include /* Backwards compat, remove in 2.7.x */ -- cgit v1.2.3 From 0e51a720b9d9ea5ebf0fda39108919c6626bffa3 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 29 Sep 2006 01:59:56 -0700 Subject: [PATCH] ifdef ->quota_read, ->quota_write All suppliers of ->quota_read, ->quota_write (I've found ext2, ext3, UFS, reiserfs) already have them properly ifdeffed. All callers of ->quota_read, ->quota_write are under CONFIG_QUOTA umbrella, so... Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 8f74dfbb2edd..4caec6cebc42 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1143,9 +1143,10 @@ struct super_operations { int (*show_options)(struct seq_file *, struct vfsmount *); int (*show_stats)(struct seq_file *, struct vfsmount *); - +#ifdef CONFIG_QUOTA ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); +#endif }; /* Inode state bits. Protected by inode_lock. */ -- cgit v1.2.3 From 068fbb315dd1e9dd3418aac39a9cfeabe39c16a6 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 29 Sep 2006 01:59:58 -0700 Subject: [PATCH] reiserfs: ifdef xattr_sem Shrink reiserfs inode by 12 bytes for xattr non-users (me). -reiser_inode_cache 356 11 +reiser_inode_cache 344 11 Signed-off-by: Alexey Dobriyan Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/inode.c | 4 ++-- include/linux/reiserfs_fs_i.h | 2 ++ include/linux/reiserfs_xattr.h | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 8810fda0da46..78f23f406932 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1129,7 +1129,7 @@ static void init_inode(struct inode *inode, struct path *path) REISERFS_I(inode)->i_jl = NULL; REISERFS_I(inode)->i_acl_access = NULL; REISERFS_I(inode)->i_acl_default = NULL; - init_rwsem(&REISERFS_I(inode)->xattr_sem); + reiserfs_init_xattr_rwsem(inode); if (stat_data_v1(ih)) { struct stat_data_v1 *sd = @@ -1836,7 +1836,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); REISERFS_I(inode)->i_acl_access = NULL; REISERFS_I(inode)->i_acl_default = NULL; - init_rwsem(&REISERFS_I(inode)->xattr_sem); + reiserfs_init_xattr_rwsem(inode); if (old_format_only(sb)) make_le_item_head(&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET, diff --git a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h index 149be8d9a0c9..711e7e7cafa5 100644 --- a/include/linux/reiserfs_fs_i.h +++ b/include/linux/reiserfs_fs_i.h @@ -55,7 +55,9 @@ struct reiserfs_inode_info { struct posix_acl *i_acl_access; struct posix_acl *i_acl_default; +#ifdef CONFIG_REISERFS_FS_XATTR struct rw_semaphore xattr_sem; +#endif struct inode vfs_inode; }; diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h index 5e961035c725..966c35851b2e 100644 --- a/include/linux/reiserfs_xattr.h +++ b/include/linux/reiserfs_xattr.h @@ -97,6 +97,11 @@ static inline void reiserfs_mark_inode_private(struct inode *inode) inode->i_flags |= S_PRIVATE; } +static inline void reiserfs_init_xattr_rwsem(struct inode *inode) +{ + init_rwsem(&REISERFS_I(inode)->xattr_sem); +} + #else #define is_reiserfs_priv_object(inode) 0 @@ -129,6 +134,9 @@ static inline int reiserfs_xattr_init(struct super_block *sb, int mount_flags) sb->s_flags = (sb->s_flags & ~MS_POSIXACL); /* to be sure */ return 0; }; +static inline void reiserfs_init_xattr_rwsem(struct inode *inode) +{ +} #endif #endif /* __KERNEL__ */ -- cgit v1.2.3 From cfe14677f286c9be5d683b88214def8f4b8a6f24 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 29 Sep 2006 02:00:00 -0700 Subject: [PATCH] reiserfs: ifdef ACL stuff from inode Shrink reiserfs inode more (by 8 bytes) for ACL non-users: -reiser_inode_cache 344 11 +reiser_inode_cache 336 11 Signed-off-by: Alexey Dobriyan Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/inode.c | 10 ++++++---- fs/reiserfs/super.c | 6 ++++++ include/linux/reiserfs_acl.h | 17 +++++++++++++++++ include/linux/reiserfs_fs_i.h | 3 ++- 4 files changed, 31 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 78f23f406932..7e5a2f5ebeb0 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1127,8 +1127,8 @@ static void init_inode(struct inode *inode, struct path *path) REISERFS_I(inode)->i_prealloc_count = 0; REISERFS_I(inode)->i_trans_id = 0; REISERFS_I(inode)->i_jl = NULL; - REISERFS_I(inode)->i_acl_access = NULL; - REISERFS_I(inode)->i_acl_default = NULL; + reiserfs_init_acl_access(inode); + reiserfs_init_acl_default(inode); reiserfs_init_xattr_rwsem(inode); if (stat_data_v1(ih)) { @@ -1834,8 +1834,8 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, REISERFS_I(inode)->i_attrs = REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); - REISERFS_I(inode)->i_acl_access = NULL; - REISERFS_I(inode)->i_acl_default = NULL; + reiserfs_init_acl_access(inode); + reiserfs_init_acl_default(inode); reiserfs_init_xattr_rwsem(inode); if (old_format_only(sb)) @@ -1974,11 +1974,13 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, * iput doesn't deadlock in reiserfs_delete_xattrs. The locking * code really needs to be reworked, but this will take care of it * for now. -jeffm */ +#ifdef CONFIG_REISERFS_FS_POSIX_ACL if (REISERFS_I(dir)->i_acl_default && !IS_ERR(REISERFS_I(dir)->i_acl_default)) { reiserfs_write_unlock_xattrs(dir->i_sb); iput(inode); reiserfs_write_lock_xattrs(dir->i_sb); } else +#endif iput(inode); return err; } diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index b40d4d64d598..80fc3b32802f 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -510,8 +510,10 @@ static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) SLAB_CTOR_CONSTRUCTOR) { INIT_LIST_HEAD(&ei->i_prealloc_list); inode_init_once(&ei->vfs_inode); +#ifdef CONFIG_REISERFS_FS_POSIX_ACL ei->i_acl_access = NULL; ei->i_acl_default = NULL; +#endif } } @@ -560,6 +562,7 @@ static void reiserfs_dirty_inode(struct inode *inode) reiserfs_write_unlock(inode->i_sb); } +#ifdef CONFIG_REISERFS_FS_POSIX_ACL static void reiserfs_clear_inode(struct inode *inode) { struct posix_acl *acl; @@ -574,6 +577,9 @@ static void reiserfs_clear_inode(struct inode *inode) posix_acl_release(acl); REISERFS_I(inode)->i_acl_default = NULL; } +#else +#define reiserfs_clear_inode NULL +#endif #ifdef CONFIG_QUOTA static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, diff --git a/include/linux/reiserfs_acl.h b/include/linux/reiserfs_acl.h index 806ec5b06707..fe00f781a622 100644 --- a/include/linux/reiserfs_acl.h +++ b/include/linux/reiserfs_acl.h @@ -56,6 +56,16 @@ extern int reiserfs_xattr_posix_acl_init(void) __init; extern int reiserfs_xattr_posix_acl_exit(void); extern struct reiserfs_xattr_handler posix_acl_default_handler; extern struct reiserfs_xattr_handler posix_acl_access_handler; + +static inline void reiserfs_init_acl_access(struct inode *inode) +{ + REISERFS_I(inode)->i_acl_access = NULL; +} + +static inline void reiserfs_init_acl_default(struct inode *inode) +{ + REISERFS_I(inode)->i_acl_default = NULL; +} #else #define reiserfs_cache_default_acl(inode) 0 @@ -87,4 +97,11 @@ reiserfs_inherit_default_acl(const struct inode *dir, struct dentry *dentry, return 0; } +static inline void reiserfs_init_acl_access(struct inode *inode) +{ +} + +static inline void reiserfs_init_acl_default(struct inode *inode) +{ +} #endif diff --git a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h index 711e7e7cafa5..5b3b297aa2c5 100644 --- a/include/linux/reiserfs_fs_i.h +++ b/include/linux/reiserfs_fs_i.h @@ -52,9 +52,10 @@ struct reiserfs_inode_info { ** flushed */ unsigned long i_trans_id; struct reiserfs_journal_list *i_jl; - +#ifdef CONFIG_REISERFS_FS_POSIX_ACL struct posix_acl *i_acl_access; struct posix_acl *i_acl_default; +#endif #ifdef CONFIG_REISERFS_FS_XATTR struct rw_semaphore xattr_sem; #endif -- cgit v1.2.3 From 50462062a02226a698a211d5bd535376c89b8603 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 29 Sep 2006 02:00:01 -0700 Subject: [PATCH] fs.h: ifdef security fields [assuming BSD security levels are deleted] The only user of i_security, f_security, s_security fields is SELinux, however, quite a few security modules are trying to get into kernel. So, wrap them under CONFIG_SECURITY. Adding config option for each security field is likely an overkill. Following Stephen Smalley's suggestion, i_security initialization is moved to security_inode_alloc() to not clutter core code with ifdefs and make alloc_inode() codepath tiny little bit smaller and faster. The user of (highly greppable) struct fown_struct::security field is still to be found. I've checked every "fown_struct" and every "f_owner" occurence. Additionally it's removal doesn't break i386 allmodconfig build. struct inode, struct file, struct super_block, struct fown_struct become smaller. P.S. Combined with two reiserfs inode shrinking patches sent to linux-fsdevel, I can finally suck 12 reiserfs inodes into one page. /proc/slabinfo -ext2_inode_cache 388 10 +ext2_inode_cache 384 10 -inode_cache 280 14 +inode_cache 276 14 -proc_inode_cache 296 13 +proc_inode_cache 292 13 -reiser_inode_cache 336 11 +reiser_inode_cache 332 12 <= -shmem_inode_cache 372 10 +shmem_inode_cache 368 10 Signed-off-by: Alexey Dobriyan Cc: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/inode.c | 1 - include/linux/fs.h | 8 ++++++-- include/linux/security.h | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/fs/inode.c b/fs/inode.c index f5c04dd9ae8a..abf77471e6c4 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -133,7 +133,6 @@ static struct inode *alloc_inode(struct super_block *sb) inode->i_bdev = NULL; inode->i_cdev = NULL; inode->i_rdev = 0; - inode->i_security = NULL; inode->dirtied_when = 0; if (security_inode_alloc(inode)) { if (inode->i_sb->s_op->destroy_inode) diff --git a/include/linux/fs.h b/include/linux/fs.h index 4caec6cebc42..6eafbe309483 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -553,7 +553,9 @@ struct inode { unsigned int i_flags; atomic_t i_writecount; +#ifdef CONFIG_SECURITY void *i_security; +#endif void *i_private; /* fs or device private pointer */ #ifdef __NEED_I_SIZE_ORDERED seqcount_t i_size_seqcount; @@ -645,7 +647,6 @@ struct fown_struct { rwlock_t lock; /* protects pid, uid, euid fields */ int pid; /* pid or -pgrp where SIGIO should be sent */ uid_t uid, euid; /* uid/euid of process setting the owner */ - void *security; int signum; /* posix.1b rt signal to be delivered on IO */ }; @@ -688,8 +689,9 @@ struct file { struct file_ra_state f_ra; unsigned long f_version; +#ifdef CONFIG_SECURITY void *f_security; - +#endif /* needed for tty driver, and maybe others */ void *private_data; @@ -877,7 +879,9 @@ struct super_block { int s_syncing; int s_need_sync_fs; atomic_t s_active; +#ifdef CONFIG_SECURITY void *s_security; +#endif struct xattr_handler **s_xattr; struct list_head s_inodes; /* all inodes */ diff --git a/include/linux/security.h b/include/linux/security.h index 9f56fb8a4a6c..9b5fea81f55e 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1595,6 +1595,7 @@ static inline void security_sb_post_pivotroot (struct nameidata *old_nd, static inline int security_inode_alloc (struct inode *inode) { + inode->i_security = NULL; return security_ops->inode_alloc_security (inode); } -- cgit v1.2.3 From ae78bf9c4f5fde3c67e2829505f195d7347ce3e4 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Fri, 29 Sep 2006 02:00:03 -0700 Subject: [PATCH] add -o flush for fat Fat is commonly used on removable media. Mounting with -o flush tells the FS to write things to disk as quickly as possible. It is like -o sync, but much faster (and not as safe). Signed-off-by: Chris Mason Cc: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/file.c | 13 +++++++++++ fs/fat/inode.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++-- fs/msdos/namei.c | 11 ++++++++- include/linux/msdos_fs.h | 3 +++ 4 files changed, 83 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/fs/fat/file.c b/fs/fat/file.c index 1ee25232e6af..d50fc47169c1 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -13,6 +13,7 @@ #include #include #include +#include int fat_generic_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) @@ -112,6 +113,16 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp, } } +static int fat_file_release(struct inode *inode, struct file *filp) +{ + if ((filp->f_mode & FMODE_WRITE) && + MSDOS_SB(inode->i_sb)->options.flush) { + fat_flush_inodes(inode->i_sb, inode, NULL); + blk_congestion_wait(WRITE, HZ/10); + } + return 0; +} + const struct file_operations fat_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, @@ -121,6 +132,7 @@ const struct file_operations fat_file_operations = { .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, + .release = fat_file_release, .ioctl = fat_generic_ioctl, .fsync = file_fsync, .sendfile = generic_file_sendfile, @@ -289,6 +301,7 @@ void fat_truncate(struct inode *inode) lock_kernel(); fat_free(inode, nr_clusters); unlock_kernel(); + fat_flush_inodes(inode->i_sb, inode, NULL); } struct inode_operations fat_file_inode_operations = { diff --git a/fs/fat/inode.c b/fs/fat/inode.c index ab96ae823753..045738032a83 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #ifndef CONFIG_FAT_DEFAULT_IOCHARSET @@ -853,7 +854,7 @@ enum { Opt_charset, Opt_shortname_lower, Opt_shortname_win95, Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, - Opt_obsolate, Opt_err, + Opt_obsolate, Opt_flush, Opt_err, }; static match_table_t fat_tokens = { @@ -885,7 +886,8 @@ static match_table_t fat_tokens = { {Opt_obsolate, "cvf_format=%20s"}, {Opt_obsolate, "cvf_options=%100s"}, {Opt_obsolate, "posix"}, - {Opt_err, NULL} + {Opt_flush, "flush"}, + {Opt_err, NULL}, }; static match_table_t msdos_tokens = { {Opt_nodots, "nodots"}, @@ -1026,6 +1028,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, return 0; opts->codepage = option; break; + case Opt_flush: + opts->flush = 1; + break; /* msdos specific */ case Opt_dots: @@ -1425,6 +1430,56 @@ out_fail: EXPORT_SYMBOL_GPL(fat_fill_super); +/* + * helper function for fat_flush_inodes. This writes both the inode + * and the file data blocks, waiting for in flight data blocks before + * the start of the call. It does not wait for any io started + * during the call + */ +static int writeback_inode(struct inode *inode) +{ + + int ret; + struct address_space *mapping = inode->i_mapping; + struct writeback_control wbc = { + .sync_mode = WB_SYNC_NONE, + .nr_to_write = 0, + }; + /* if we used WB_SYNC_ALL, sync_inode waits for the io for the + * inode to finish. So WB_SYNC_NONE is sent down to sync_inode + * and filemap_fdatawrite is used for the data blocks + */ + ret = sync_inode(inode, &wbc); + if (!ret) + ret = filemap_fdatawrite(mapping); + return ret; +} + +/* + * write data and metadata corresponding to i1 and i2. The io is + * started but we do not wait for any of it to finish. + * + * filemap_flush is used for the block device, so if there is a dirty + * page for a block already in flight, we will not wait and start the + * io over again + */ +int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2) +{ + int ret = 0; + if (!MSDOS_SB(sb)->options.flush) + return 0; + if (i1) + ret = writeback_inode(i1); + if (!ret && i2) + ret = writeback_inode(i2); + if (!ret && sb) { + struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; + ret = filemap_flush(mapping); + } + return ret; +} +EXPORT_SYMBOL_GPL(fat_flush_inodes); + static int __init init_fat_fs(void) { int err; diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 9e44158a7540..d220165d4918 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -280,7 +280,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { struct super_block *sb = dir->i_sb; - struct inode *inode; + struct inode *inode = NULL; struct fat_slot_info sinfo; struct timespec ts; unsigned char msdos_name[MSDOS_NAME]; @@ -316,6 +316,8 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode, d_instantiate(dentry, inode); out: unlock_kernel(); + if (!err) + err = fat_flush_inodes(sb, dir, inode); return err; } @@ -348,6 +350,8 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) fat_detach(inode); out: unlock_kernel(); + if (!err) + err = fat_flush_inodes(inode->i_sb, dir, inode); return err; } @@ -401,6 +405,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode) d_instantiate(dentry, inode); unlock_kernel(); + fat_flush_inodes(sb, dir, inode); return 0; out_free: @@ -430,6 +435,8 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry) fat_detach(inode); out: unlock_kernel(); + if (!err) + err = fat_flush_inodes(inode->i_sb, dir, inode); return err; } @@ -635,6 +642,8 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry, new_dir, new_msdos_name, new_dentry, is_hid); out: unlock_kernel(); + if (!err) + err = fat_flush_inodes(old_dir->i_sb, old_dir, new_dir); return err; } diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index bae62d62dc3e..ce6c85815cbd 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -204,6 +204,7 @@ struct fat_mount_options { unicode_xlate:1, /* create escape sequences for unhandled Unicode */ numtail:1, /* Does first alias have a numeric '~1' type tail? */ atari:1, /* Use Atari GEMDOS variation of MS-DOS fs */ + flush:1, /* write things quickly */ nocase:1; /* Does this need case conversion? 0=need case conversion*/ }; @@ -412,6 +413,8 @@ extern int fat_sync_inode(struct inode *inode); extern int fat_fill_super(struct super_block *sb, void *data, int silent, struct inode_operations *fs_dir_inode_ops, int isvfat); +extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, + struct inode *i2); /* fat/misc.c */ extern void fat_fs_panic(struct super_block *s, const char *fmt, ...); extern void fat_clusters_flush(struct super_block *sb); -- cgit v1.2.3 From ca9bda00b4aafc42cd3d1b9d32934463e2993b4c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 29 Sep 2006 02:00:03 -0700 Subject: [PATCH] tty locking on resize The current kernel serializes console resizes but does not serialize the resize against the tty structure updates. This means that while two parallel resizes cannot mess up the console you can get incorrect results reported. Secondly while doing this I added vc_lock_resize() to lock and resize the console. This leaves all knowledge of the console_sem in the vt/console driver and kicks it out of the tty layer, which is good Thirdly while doing this I decided I couldn't stand "disallocate" any longer so I switched it to "deallocate". Signed-off-by: Alan Cox Cc: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/selection.c | 2 +- drivers/char/tty_io.c | 29 +++++++++++++++-------------- drivers/char/vt.c | 12 +++++++++++- drivers/char/vt_ioctl.c | 17 +++++++---------- include/linux/vt_kern.h | 3 ++- 5 files changed, 36 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/selection.c b/drivers/char/selection.c index 71093a9fc462..74cff839c857 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) */ -struct vc_data *sel_cons; /* must not be disallocated */ +struct vc_data *sel_cons; /* must not be deallocated */ static volatile int sel_start = -1; /* cleared by clear_selection */ static int sel_end; static int sel_buffer_lth; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index eb881cfa53e0..2a1e95b0f282 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2770,12 +2770,11 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) * actually has driver level meaning and triggers a VC resize. * * Locking: - * The console_sem is used to ensure we do not try and resize - * the console twice at once. - * FIXME: Two racing size sets may leave the console and kernel - * parameters disagreeing. Is this exploitable ? - * FIXME: Random values racing a window size get is wrong - * should lock here against that + * Called function use the console_sem is used to ensure we do + * not try and resize the console twice at once. + * The tty->termios_sem is used to ensure we don't double + * resize and get confused. Lock order - tty->termios.sem before + * console sem */ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, @@ -2785,17 +2784,17 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) return -EFAULT; + + down(&tty->termios_sem); if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) - return 0; + goto done; + #ifdef CONFIG_VT if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { - int rc; - - acquire_console_sem(); - rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row); - release_console_sem(); - if (rc) - return -ENXIO; + if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row)) { + up(&tty->termios_sem); + return -ENXIO; + } } #endif if (tty->pgrp > 0) @@ -2804,6 +2803,8 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, kill_pg(real_tty->pgrp, SIGWINCH, 1); tty->winsize = tmp_ws; real_tty->winsize = tmp_ws; +done: + up(&tty->termios_sem); return 0; } diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 0fca83ededff..b49f03375439 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -885,8 +885,17 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) return err; } +int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) +{ + int rc; + + acquire_console_sem(); + rc = vc_resize(vc, cols, lines); + release_console_sem(); + return rc; +} -void vc_disallocate(unsigned int currcons) +void vc_deallocate(unsigned int currcons) { WARN_CONSOLE_UNLOCKED(); @@ -3790,6 +3799,7 @@ EXPORT_SYMBOL(default_blu); EXPORT_SYMBOL(update_region); EXPORT_SYMBOL(redraw_screen); EXPORT_SYMBOL(vc_resize); +EXPORT_SYMBOL(vc_lock_resize); EXPORT_SYMBOL(fg_console); EXPORT_SYMBOL(console_blank_hook); EXPORT_SYMBOL(console_blanked); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index a5628a8b6620..a53e382cc107 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -96,7 +96,7 @@ do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_str if (!perm) return -EPERM; if (!i && v == K_NOSUCHMAP) { - /* disallocate map */ + /* deallocate map */ key_map = key_maps[s]; if (s && key_map) { key_maps[s] = NULL; @@ -819,20 +819,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (arg > MAX_NR_CONSOLES) return -ENXIO; if (arg == 0) { - /* disallocate all unused consoles, but leave 0 */ + /* deallocate all unused consoles, but leave 0 */ acquire_console_sem(); for (i=1; iv_rows) || get_user(cc, &vtsizes->v_cols)) return -EFAULT; - for (i = 0; i < MAX_NR_CONSOLES; i++) { - acquire_console_sem(); - vc_resize(vc_cons[i].d, cc, ll); - release_console_sem(); - } + for (i = 0; i < MAX_NR_CONSOLES; i++) + vc_lock_resize(vc_cons[i].d, cc, ll); return 0; } diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 918a29763aea..1009d3fe1fc2 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -33,7 +33,8 @@ extern int fg_console, last_console, want_console; int vc_allocate(unsigned int console); int vc_cons_allocated(unsigned int console); int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); -void vc_disallocate(unsigned int console); +int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); +void vc_deallocate(unsigned int console); void reset_palette(struct vc_data *vc); void do_blank_screen(int entering_gfx); void do_unblank_screen(int leaving_gfx); -- cgit v1.2.3 From 3b9b8ab65d8eed784b9164d03807cb2bda7b5cd6 Mon Sep 17 00:00:00 2001 From: Kirill Korotaev Date: Fri, 29 Sep 2006 02:00:05 -0700 Subject: [PATCH] Fix unserialized task->files changing Fixed race on put_files_struct on exec with proc. Restoring files on current on error path may lead to proc having a pointer to already kfree-d files_struct. ->files changing at exit.c and khtread.c are safe as exit_files() makes all things under lock. Found during OpenVZ stress testing. [akpm@osdl.org: add export] Signed-off-by: Pavel Emelianov Signed-off-by: Kirill Korotaev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_elf.c | 6 ++---- fs/binfmt_misc.c | 6 ++---- fs/exec.c | 3 +-- include/linux/file.h | 1 + kernel/exit.c | 12 ++++++++++++ 5 files changed, 18 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index dfd8cfb7fb5d..bb43da5cde5c 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1038,10 +1038,8 @@ out_free_interp: out_free_file: sys_close(elf_exec_fileno); out_free_fh: - if (files) { - put_files_struct(current->files); - current->files = files; - } + if (files) + reset_files_struct(current, files); out_free_ph: kfree(elf_phdata); goto out; diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 66ba137f8661..1713c48fef54 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -215,10 +215,8 @@ _error: bprm->interp_flags = 0; bprm->interp_data = 0; _unshare: - if (files) { - put_files_struct(current->files); - current->files = files; - } + if (files) + reset_files_struct(current, files); goto _ret; } diff --git a/fs/exec.c b/fs/exec.c index 97df6e0aeaee..a8efe35176b0 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -898,8 +898,7 @@ int flush_old_exec(struct linux_binprm * bprm) return 0; mmap_failed: - put_files_struct(current->files); - current->files = files; + reset_files_struct(current, files); out: return retval; } diff --git a/include/linux/file.h b/include/linux/file.h index 9f7c2513866f..74183e6f7f45 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -112,5 +112,6 @@ struct task_struct; struct files_struct *get_files_struct(struct task_struct *); void FASTCALL(put_files_struct(struct files_struct *fs)); +void reset_files_struct(struct task_struct *, struct files_struct *); #endif /* __LINUX_FILE_H */ diff --git a/kernel/exit.c b/kernel/exit.c index d891883420f7..4b6fb054b25d 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -487,6 +487,18 @@ void fastcall put_files_struct(struct files_struct *files) EXPORT_SYMBOL(put_files_struct); +void reset_files_struct(struct task_struct *tsk, struct files_struct *files) +{ + struct files_struct *old; + + old = tsk->files; + task_lock(tsk); + tsk->files = files; + task_unlock(tsk); + put_files_struct(old); +} +EXPORT_SYMBOL(reset_files_struct); + static inline void __exit_files(struct task_struct *tsk) { struct files_struct * files = tsk->files; -- cgit v1.2.3 From f400e198b2ed26ce55b22a1412ded0896e7516ac Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Fri, 29 Sep 2006 02:00:07 -0700 Subject: [PATCH] pidspace: is_init() This is an updated version of Eric Biederman's is_init() patch. (http://lkml.org/lkml/2006/2/6/280). It applies cleanly to 2.6.18-rc3 and replaces a few more instances of ->pid == 1 with is_init(). Further, is_init() checks pid and thus removes dependency on Eric's other patches for now. Eric's original description: There are a lot of places in the kernel where we test for init because we give it special properties. Most significantly init must not die. This results in code all over the kernel test ->pid == 1. Introduce is_init to capture this case. With multiple pid spaces for all of the cases affected we are looking for only the first process on the system, not some other process that has pid == 1. Signed-off-by: Eric W. Biederman Signed-off-by: Sukadev Bhattiprolu Cc: Dave Hansen Cc: Serge Hallyn Cc: Cedric Le Goater Cc: Acked-by: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/mm/fault.c | 2 +- arch/arm/mm/fault.c | 2 +- arch/arm26/mm/fault.c | 2 +- arch/i386/lib/usercopy.c | 2 +- arch/i386/mm/fault.c | 2 +- arch/ia64/mm/fault.c | 2 +- arch/m32r/mm/fault.c | 2 +- arch/m68k/mm/fault.c | 2 +- arch/mips/mm/fault.c | 2 +- arch/powerpc/mm/fault.c | 2 +- arch/powerpc/platforms/pseries/ras.c | 2 +- arch/ppc/kernel/traps.c | 2 +- arch/ppc/mm/fault.c | 2 +- arch/s390/mm/fault.c | 2 +- arch/sh/mm/fault.c | 2 +- arch/sh64/mm/fault.c | 6 +++--- arch/um/kernel/trap.c | 2 +- arch/x86_64/mm/fault.c | 4 ++-- arch/xtensa/mm/fault.c | 2 +- drivers/char/sysrq.c | 2 +- include/linux/sched.h | 10 ++++++++++ kernel/capability.c | 2 +- kernel/cpuset.c | 2 +- kernel/exit.c | 2 +- kernel/kexec.c | 2 +- kernel/ptrace.c | 1 + kernel/sysctl.c | 2 +- mm/oom_kill.c | 2 +- security/commoncap.c | 2 +- 29 files changed, 41 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index 622dabd84680..8871529a34e2 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -193,7 +193,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr, /* We ran out of memory, or some other thing happened to us that made us unable to handle the page fault gracefully. */ out_of_memory: - if (current->pid == 1) { + if (is_init(current)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index a5b33ff3924e..5e658a874498 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -198,7 +198,7 @@ survive: return fault; } - if (tsk->pid != 1) + if (!is_init(tsk)) goto out; /* diff --git a/arch/arm26/mm/fault.c b/arch/arm26/mm/fault.c index a7c4cc922095..a1f6d8a9cc32 100644 --- a/arch/arm26/mm/fault.c +++ b/arch/arm26/mm/fault.c @@ -185,7 +185,7 @@ survive: } fault = -3; /* out of memory */ - if (tsk->pid != 1) + if (!is_init(tsk)) goto out; /* diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index efc7e7d5f4d0..08502fc6d0cb 100644 --- a/arch/i386/lib/usercopy.c +++ b/arch/i386/lib/usercopy.c @@ -739,7 +739,7 @@ survive: retval = get_user_pages(current, current->mm, (unsigned long )to, 1, 1, 0, &pg, NULL); - if (retval == -ENOMEM && current->pid == 1) { + if (retval == -ENOMEM && is_init(current)) { up_read(¤t->mm->mmap_sem); blk_congestion_wait(WRITE, HZ/50); goto survive; diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 50d8617391dd..2581575786c1 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -589,7 +589,7 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - if (tsk->pid == 1) { + if (is_init(tsk)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index d8b1b4ac7f26..59f3ab937615 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -280,7 +280,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re out_of_memory: up_read(&mm->mmap_sem); - if (current->pid == 1) { + if (is_init(current)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c index dc18a33eefef..8d5f551b5754 100644 --- a/arch/m32r/mm/fault.c +++ b/arch/m32r/mm/fault.c @@ -299,7 +299,7 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - if (tsk->pid == 1) { + if (is_init(tsk)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index 5e2d87c10c87..911f2ce3f53e 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c @@ -181,7 +181,7 @@ good_area: */ out_of_memory: up_read(&mm->mmap_sem); - if (current->pid == 1) { + if (is_init(current)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index a4f8c45c4e8e..8423d8590779 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -171,7 +171,7 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - if (tsk->pid == 1) { + if (is_init(tsk)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 77953f41d754..e8fa50624b70 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -386,7 +386,7 @@ bad_area_nosemaphore: */ out_of_memory: up_read(&mm->mmap_sem); - if (current->pid == 1) { + if (is_init(current)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 903115d67fdc..311ed1993fc0 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -337,7 +337,7 @@ static int recover_mce(struct pt_regs *regs, struct rtas_error_log * err) err->disposition == RTAS_DISP_NOT_RECOVERED && err->target == RTAS_TARGET_MEMORY && err->type == RTAS_TYPE_ECC_UNCORR && - !(current->pid == 0 || current->pid == 1)) { + !(current->pid == 0 || is_init(current))) { /* Kill off a user process with an ECC error */ printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n", current->pid); diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index d7a433049b48..aafc8e8893d1 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -119,7 +119,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) * generate the same exception over and over again and we get * nowhere. Better to kill it and let the kernel panic. */ - if (current->pid == 1) { + if (is_init(current)) { __sighandler_t handler; spin_lock_irq(¤t->sighand->siglock); diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index bc776beb3136..465f451f3bc3 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -291,7 +291,7 @@ bad_area: */ out_of_memory: up_read(&mm->mmap_sem); - if (current->pid == 1) { + if (is_init(current)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index f2b9a84dc2bf..9c3c19fe62fc 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -353,7 +353,7 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - if (tsk->pid == 1) { + if (is_init(tsk)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 507f28914706..68663b8f99ae 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -149,7 +149,7 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - if (current->pid == 1) { + if (is_init(current)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/sh64/mm/fault.c b/arch/sh64/mm/fault.c index f08d0eaf6497..8e2f6c28b739 100644 --- a/arch/sh64/mm/fault.c +++ b/arch/sh64/mm/fault.c @@ -277,7 +277,7 @@ bad_area: show_regs(regs); #endif } - if (tsk->pid == 1) { + if (is_init(tsk)) { panic("INIT had user mode bad_area\n"); } tsk->thread.address = address; @@ -319,14 +319,14 @@ no_context: * us unable to handle the page fault gracefully. */ out_of_memory: - if (current->pid == 1) { + if (is_init(current)) { panic("INIT out of memory\n"); yield(); goto survive; } printk("fault:Out of memory\n"); up_read(&mm->mmap_sem); - if (current->pid == 1) { + if (is_init(current)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 61a23fff4395..c7b195c7e51f 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -120,7 +120,7 @@ out_nosemaphore: * us unable to handle the page fault gracefully. */ out_of_memory: - if (current->pid == 1) { + if (is_init(current)) { up_read(&mm->mmap_sem); yield(); down_read(&mm->mmap_sem); diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 9ba54cc2b5f6..3751b4788e28 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -244,7 +244,7 @@ static int is_errata93(struct pt_regs *regs, unsigned long address) int unhandled_signal(struct task_struct *tsk, int sig) { - if (tsk->pid == 1) + if (is_init(tsk)) return 1; if (tsk->ptrace & PT_PTRACED) return 0; @@ -580,7 +580,7 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - if (current->pid == 1) { + if (is_init(current)) { yield(); goto again; } diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c index a945a33e85a1..dd0dbec2e57e 100644 --- a/arch/xtensa/mm/fault.c +++ b/arch/xtensa/mm/fault.c @@ -144,7 +144,7 @@ bad_area: */ out_of_memory: up_read(&mm->mmap_sem); - if (current->pid == 1) { + if (is_init(current)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index ee3ca8f1768e..0ad6cb081db4 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -208,7 +208,7 @@ static void send_sig_all(int sig) struct task_struct *p; for_each_process(p) { - if (p->mm && p->pid != 1) + if (p->mm && !is_init(p)) /* Not swapper, init nor kernel thread */ force_sig(sig, p); } diff --git a/include/linux/sched.h b/include/linux/sched.h index 3696f2f7126d..ed2af8671589 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1033,6 +1033,16 @@ static inline int pid_alive(struct task_struct *p) return p->pids[PIDTYPE_PID].pid != NULL; } +/** + * is_init - check if a task structure is the first user space + * task the kernel created. + * @p: Task structure to be checked. + */ +static inline int is_init(struct task_struct *tsk) +{ + return tsk->pid == 1; +} + extern void free_task(struct task_struct *tsk); #define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0) diff --git a/kernel/capability.c b/kernel/capability.c index c7685ad00a97..edb845a6e84a 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -133,7 +133,7 @@ static inline int cap_set_all(kernel_cap_t *effective, int found = 0; do_each_thread(g, target) { - if (target == current || target->pid == 1) + if (target == current || is_init(target)) continue; found = 1; if (security_capset_check(target, effective, inheritable, diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 1b32c2c04c15..584bb4e6c042 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -240,7 +240,7 @@ static struct super_block *cpuset_sb; * A cpuset can only be deleted if both its 'count' of using tasks * is zero, and its list of 'children' cpusets is empty. Since all * tasks in the system use _some_ cpuset, and since there is always at - * least one task in the system (init, pid == 1), therefore, top_cpuset + * least one task in the system (init), therefore, top_cpuset * always has either children cpusets and/or using tasks. So we don't * need a special hack to ensure that top_cpuset cannot be deleted. * diff --git a/kernel/exit.c b/kernel/exit.c index 4b6fb054b25d..9961192d6055 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -219,7 +219,7 @@ static int will_become_orphaned_pgrp(int pgrp, struct task_struct *ignored_task) do_each_task_pid(pgrp, PIDTYPE_PGID, p) { if (p == ignored_task || p->exit_state - || p->real_parent->pid == 1) + || is_init(p->real_parent)) continue; if (process_group(p->real_parent) != pgrp && p->real_parent->signal->session == p->signal->session) { diff --git a/kernel/kexec.c b/kernel/kexec.c index 50087ecf337e..37cad75cf494 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -40,7 +40,7 @@ struct resource crashk_res = { int kexec_should_crash(struct task_struct *p) { - if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops) + if (in_interrupt() || !p->pid || is_init(p) || panic_on_oops) return 1; return 0; } diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 8aad0331d82e..4d50e06fd745 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -440,6 +440,7 @@ struct task_struct *ptrace_get_task_struct(pid_t pid) child = find_task_by_pid(pid); if (child) get_task_struct(child); + read_unlock(&tasklist_lock); if (!child) return ERR_PTR(-ESRCH); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8bfa7d117c54..9535a3839930 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1915,7 +1915,7 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, return -EPERM; } - op = (current->pid == 1) ? OP_SET : OP_AND; + op = is_init(current) ? OP_SET : OP_AND; return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, do_proc_dointvec_bset_conv,&op); } diff --git a/mm/oom_kill.c b/mm/oom_kill.c index bada3d03119f..f3dd79c1c367 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -255,7 +255,7 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) */ static void __oom_kill_task(struct task_struct *p, const char *message) { - if (p->pid == 1) { + if (is_init(p)) { WARN_ON(1); printk(KERN_WARNING "tried to kill init!\n"); return; diff --git a/security/commoncap.c b/security/commoncap.c index f50fc298cf80..5a5ef5ca7ea9 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -169,7 +169,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) /* For init, we want to retain the capabilities set * in the init_task struct. Thus we skip the usual * capability rules */ - if (current->pid != 1) { + if (!is_init(current)) { current->cap_permitted = new_permitted; current->cap_effective = cap_intersect (new_permitted, bprm->cap_effective); -- cgit v1.2.3 From 3ca212b813299899d2968aa0a24a797c3746f5ec Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 29 Sep 2006 02:00:14 -0700 Subject: [PATCH] Remove another config.h After the asm/ uses of #include this one is the next biggest source of noise. Signed-off-by: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmstat.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h index 176c7f797339..c89df55f6e03 100644 --- a/include/linux/vmstat.h +++ b/include/linux/vmstat.h @@ -3,7 +3,6 @@ #include #include -#include #include #include -- cgit v1.2.3 From af410fc13d95f079910fc3dca7496590c3275967 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 29 Sep 2006 02:00:14 -0700 Subject: [PATCH] make leds.h include relevant headers Make it possible to include linux/leds.h without first including list.h and spinlock.h. Signed-off-by: Johannes Berg Acked-by: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/leds.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/leds.h b/include/linux/leds.h index dc23c7c639f3..88afceffb7cb 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -12,6 +12,9 @@ #ifndef __LINUX_LEDS_H_INCLUDED #define __LINUX_LEDS_H_INCLUDED +#include +#include + struct device; struct class_device; /* -- cgit v1.2.3 From 1711ef3866b0360e102327389fe4b76c849bbe83 Mon Sep 17 00:00:00 2001 From: Toyo Abe Date: Fri, 29 Sep 2006 02:00:28 -0700 Subject: [PATCH] posix-timers: Fix clock_nanosleep() doesn't return the remaining time in compatibility mode The clock_nanosleep() function does not return the time remaining when the sleep is interrupted by a signal. This patch creates a new call out, compat_clock_nanosleep_restart(), which handles returning the remaining time after a sleep is interrupted. This patch revives clock_nanosleep_restart(). It is now accessed via the new call out. The compat_clock_nanosleep_restart() is used for compatibility access. Since this is implemented in compatibility mode the normal path is virtually unaffected - no real performance impact. Signed-off-by: Toyo Abe Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Roland McGrath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/hrtimer.h | 1 + include/linux/posix-timers.h | 4 ++++ kernel/compat.c | 33 +++++++++++++++++++++++++++++++++ kernel/hrtimer.c | 20 ++++++++++---------- kernel/posix-cpu-timers.c | 17 ++++++++++++----- kernel/posix-timers.c | 21 +++++++++++++++++++++ 6 files changed, 81 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 4fc379de6c2f..fca93025ab51 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -138,6 +138,7 @@ extern long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, const enum hrtimer_mode mode, const clockid_t clockid); +extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *tsk); diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 95572c434bc9..a7dd38f30ade 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -72,6 +72,7 @@ struct k_clock { int (*timer_create) (struct k_itimer *timer); int (*nsleep) (const clockid_t which_clock, int flags, struct timespec *, struct timespec __user *); + long (*nsleep_restart) (struct restart_block *restart_block); int (*timer_set) (struct k_itimer * timr, int flags, struct itimerspec * new_setting, struct itimerspec * old_setting); @@ -97,6 +98,7 @@ int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *ts); int posix_cpu_timer_create(struct k_itimer *timer); int posix_cpu_nsleep(const clockid_t which_clock, int flags, struct timespec *rqtp, struct timespec __user *rmtp); +long posix_cpu_nsleep_restart(struct restart_block *restart_block); int posix_cpu_timer_set(struct k_itimer *timer, int flags, struct itimerspec *new, struct itimerspec *old); int posix_cpu_timer_del(struct k_itimer *timer); @@ -111,4 +113,6 @@ void posix_cpu_timers_exit_group(struct task_struct *task); void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, cputime_t *newval, cputime_t *oldval); +long clock_nanosleep_restart(struct restart_block *restart_block); + #endif diff --git a/kernel/compat.c b/kernel/compat.c index 126dee9530aa..75573e5d27b0 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -601,6 +602,30 @@ long compat_sys_clock_getres(clockid_t which_clock, return err; } +static long compat_clock_nanosleep_restart(struct restart_block *restart) +{ + long err; + mm_segment_t oldfs; + struct timespec tu; + struct compat_timespec *rmtp = (struct compat_timespec *)(restart->arg1); + + restart->arg1 = (unsigned long) &tu; + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = clock_nanosleep_restart(restart); + set_fs(oldfs); + + if ((err == -ERESTART_RESTARTBLOCK) && rmtp && + put_compat_timespec(&tu, rmtp)) + return -EFAULT; + + if (err == -ERESTART_RESTARTBLOCK) { + restart->fn = compat_clock_nanosleep_restart; + restart->arg1 = (unsigned long) rmtp; + } + return err; +} + long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, struct compat_timespec __user *rqtp, struct compat_timespec __user *rmtp) @@ -608,6 +633,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, long err; mm_segment_t oldfs; struct timespec in, out; + struct restart_block *restart; if (get_compat_timespec(&in, rqtp)) return -EFAULT; @@ -618,9 +644,16 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, (struct timespec __user *) &in, (struct timespec __user *) &out); set_fs(oldfs); + if ((err == -ERESTART_RESTARTBLOCK) && rmtp && put_compat_timespec(&out, rmtp)) return -EFAULT; + + if (err == -ERESTART_RESTARTBLOCK) { + restart = ¤t_thread_info()->restart_block; + restart->fn = compat_clock_nanosleep_restart; + restart->arg1 = (unsigned long) rmtp; + } return err; } diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 21c38a7e666b..d0ba190dfeb6 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -693,7 +693,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod return t->task == NULL; } -static long __sched nanosleep_restart(struct restart_block *restart) +long __sched hrtimer_nanosleep_restart(struct restart_block *restart) { struct hrtimer_sleeper t; struct timespec __user *rmtp; @@ -702,13 +702,13 @@ static long __sched nanosleep_restart(struct restart_block *restart) restart->fn = do_no_restart_syscall; - hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS); - t.timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0; + hrtimer_init(&t.timer, restart->arg0, HRTIMER_ABS); + t.timer.expires.tv64 = ((u64)restart->arg3 << 32) | (u64) restart->arg2; if (do_nanosleep(&t, HRTIMER_ABS)) return 0; - rmtp = (struct timespec __user *) restart->arg2; + rmtp = (struct timespec __user *) restart->arg1; if (rmtp) { time = ktime_sub(t.timer.expires, t.timer.base->get_time()); if (time.tv64 <= 0) @@ -718,7 +718,7 @@ static long __sched nanosleep_restart(struct restart_block *restart) return -EFAULT; } - restart->fn = nanosleep_restart; + restart->fn = hrtimer_nanosleep_restart; /* The other values in restart are already filled in */ return -ERESTART_RESTARTBLOCK; @@ -751,11 +751,11 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, } restart = ¤t_thread_info()->restart_block; - restart->fn = nanosleep_restart; - restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF; - restart->arg1 = t.timer.expires.tv64 >> 32; - restart->arg2 = (unsigned long) rmtp; - restart->arg3 = (unsigned long) t.timer.base->index; + restart->fn = hrtimer_nanosleep_restart; + restart->arg0 = (unsigned long) t.timer.base->index; + restart->arg1 = (unsigned long) rmtp; + restart->arg2 = t.timer.expires.tv64 & 0xFFFFFFFF; + restart->arg3 = t.timer.expires.tv64 >> 32; return -ERESTART_RESTARTBLOCK; } diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index d38d9ec3276c..5667fef89dd1 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -1393,8 +1393,6 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx, } } -static long posix_cpu_clock_nanosleep_restart(struct restart_block *); - int posix_cpu_nsleep(const clockid_t which_clock, int flags, struct timespec *rqtp, struct timespec __user *rmtp) { @@ -1471,7 +1469,7 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags, copy_to_user(rmtp, &it.it_value, sizeof *rmtp)) return -EFAULT; - restart_block->fn = posix_cpu_clock_nanosleep_restart; + restart_block->fn = posix_cpu_nsleep_restart; /* Caller already set restart_block->arg1 */ restart_block->arg0 = which_clock; restart_block->arg1 = (unsigned long) rmtp; @@ -1484,8 +1482,7 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags, return error; } -static long -posix_cpu_clock_nanosleep_restart(struct restart_block *restart_block) +long posix_cpu_nsleep_restart(struct restart_block *restart_block) { clockid_t which_clock = restart_block->arg0; struct timespec __user *rmtp; @@ -1524,6 +1521,10 @@ static int process_cpu_nsleep(const clockid_t which_clock, int flags, { return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp); } +static long process_cpu_nsleep_restart(struct restart_block *restart_block) +{ + return -EINVAL; +} static int thread_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp) { @@ -1544,6 +1545,10 @@ static int thread_cpu_nsleep(const clockid_t which_clock, int flags, { return -EINVAL; } +static long thread_cpu_nsleep_restart(struct restart_block *restart_block) +{ + return -EINVAL; +} static __init int init_posix_cpu_timers(void) { @@ -1553,6 +1558,7 @@ static __init int init_posix_cpu_timers(void) .clock_set = do_posix_clock_nosettime, .timer_create = process_cpu_timer_create, .nsleep = process_cpu_nsleep, + .nsleep_restart = process_cpu_nsleep_restart, }; struct k_clock thread = { .clock_getres = thread_cpu_clock_getres, @@ -1560,6 +1566,7 @@ static __init int init_posix_cpu_timers(void) .clock_set = do_posix_clock_nosettime, .timer_create = thread_cpu_timer_create, .nsleep = thread_cpu_nsleep, + .nsleep_restart = thread_cpu_nsleep_restart, }; register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process); diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index ac6dc8744429..e5ebcc1ec3a0 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c @@ -973,3 +973,24 @@ sys_clock_nanosleep(const clockid_t which_clock, int flags, return CLOCK_DISPATCH(which_clock, nsleep, (which_clock, flags, &t, rmtp)); } + +/* + * nanosleep_restart for monotonic and realtime clocks + */ +static int common_nsleep_restart(struct restart_block *restart_block) +{ + return hrtimer_nanosleep_restart(restart_block); +} + +/* + * This will restart clock_nanosleep. This is required only by + * compat_clock_nanosleep_restart for now. + */ +long +clock_nanosleep_restart(struct restart_block *restart_block) +{ + clockid_t which_clock = restart_block->arg0; + + return CLOCK_DISPATCH(which_clock, nsleep_restart, + (restart_block)); +} -- cgit v1.2.3 From 3171a0305d62e6627a24bff35af4f997e4988a80 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Fri, 29 Sep 2006 02:00:32 -0700 Subject: [PATCH] simplify update_times (avoid jiffies/jiffies_64 aliasing problem) Pass ticks to do_timer() and update_times(), and adjust x86_64 and s390 timer interrupt handler with this change. Currently update_times() calculates ticks by "jiffies - wall_jiffies", but callers of do_timer() should know how many ticks to update. Passing ticks get rid of this redundant calculation. Also there are another redundancy pointed out by Martin Schwidefsky. This cleanup make a barrier added by 5aee405c662ca644980c184774277fc6d0769a84 needless. So this patch removes it. As a bonus, this cleanup make wall_jiffies can be removed easily, since now wall_jiffies is always synced with jiffies. (This patch does not really remove wall_jiffies. It would be another cleanup patch) Signed-off-by: Atsushi Nemoto Cc: Martin Schwidefsky Cc: "Eric W. Biederman" Cc: Thomas Gleixner Cc: Ingo Molnar Cc: john stultz Cc: Andi Kleen Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Richard Henderson Cc: Ivan Kokshaysky Acked-by: Russell King Cc: Ian Molton Cc: Mikael Starvik Acked-by: David Howells Cc: Yoshinori Sato Cc: Hirokazu Takata Acked-by: Ralf Baechle Cc: Kyle McMartin Cc: Heiko Carstens Cc: Martin Schwidefsky Cc: Paul Mundt Cc: Kazumoto Kojima Cc: Richard Curnow Cc: William Lee Irwin III Cc: "David S. Miller" Cc: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Cc: Miles Bader Cc: Chris Zankel Acked-by: "Luck, Tony" Cc: Geert Uytterhoeven Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/time.c | 2 +- arch/arm/kernel/time.c | 2 +- arch/arm26/kernel/time.c | 2 +- arch/avr32/kernel/time.c | 2 +- arch/cris/arch-v10/kernel/time.c | 2 +- arch/cris/arch-v32/kernel/time.c | 2 +- arch/frv/kernel/time.c | 2 +- arch/h8300/kernel/time.c | 2 +- arch/ia64/kernel/time.c | 2 +- arch/m32r/kernel/time.c | 2 +- arch/m68k/kernel/time.c | 2 +- arch/m68k/sun3/sun3ints.c | 2 +- arch/m68knommu/kernel/time.c | 2 +- arch/mips/au1000/common/time.c | 6 +++--- arch/mips/gt64120/common/time.c | 2 +- arch/mips/kernel/time.c | 2 +- arch/mips/momentum/ocelot_g/gt-irq.c | 2 +- arch/mips/sgi-ip27/ip27-timer.c | 2 +- arch/parisc/kernel/time.c | 2 +- arch/powerpc/kernel/time.c | 2 +- arch/ppc/kernel/time.c | 2 +- arch/s390/kernel/time.c | 9 ++++----- arch/sh/kernel/time.c | 2 +- arch/sh64/kernel/time.c | 2 +- arch/sparc/kernel/pcic.c | 2 +- arch/sparc/kernel/time.c | 2 +- arch/sparc64/kernel/time.c | 4 ++-- arch/um/kernel/time.c | 2 +- arch/v850/kernel/time.c | 2 +- arch/x86_64/kernel/time.c | 8 ++++---- arch/xtensa/kernel/time.c | 2 +- include/asm-arm/arch-clps711x/time.h | 2 +- include/asm-arm/arch-l7200/time.h | 2 +- include/asm-i386/mach-default/do_timer.h | 2 +- include/asm-i386/mach-visws/do_timer.h | 2 +- include/asm-i386/mach-voyager/do_timer.h | 2 +- include/linux/sched.h | 2 +- kernel/timer.c | 19 ++++++------------- 38 files changed, 52 insertions(+), 60 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index b191cc759737..7c1e44420a78 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -132,7 +132,7 @@ irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs) nticks = delta >> FIX_SHIFT; while (nticks > 0) { - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index d4dceb5f06e9..f7d5165796ef 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -337,7 +337,7 @@ void timer_tick(struct pt_regs *regs) profile_tick(CPU_PROFILING, regs); do_leds(); do_set_rtc(); - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/arm26/kernel/time.c b/arch/arm26/kernel/time.c index db63d75d0715..80adbd005fc5 100644 --- a/arch/arm26/kernel/time.c +++ b/arch/arm26/kernel/time.c @@ -194,7 +194,7 @@ EXPORT_SYMBOL(do_settimeofday); static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c index b0e6b5855a38..3e56b9f4358a 100644 --- a/arch/avr32/kernel/time.c +++ b/arch/avr32/kernel/time.c @@ -148,7 +148,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * Call the generic timer interrupt handler */ write_seqlock(&xtime_lock); - do_timer(regs); + do_timer(1); write_sequnlock(&xtime_lock); /* diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c index 9c22b76e129a..ebacf1457d91 100644 --- a/arch/cris/arch-v10/kernel/time.c +++ b/arch/cris/arch-v10/kernel/time.c @@ -227,7 +227,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* call the real timer interrupt handler */ - do_timer(regs); + do_timer(1); cris_do_profile(regs); /* Save profiling information */ diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c index 50f3f93293d6..be0a01657d4f 100644 --- a/arch/cris/arch-v32/kernel/time.c +++ b/arch/cris/arch-v32/kernel/time.c @@ -219,7 +219,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; /* call the real timer interrupt handler */ - do_timer(regs); + do_timer(1); /* * If we have an externally synchronized Linux clock, then update diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c index 3d0284bccb94..7e55884135ed 100644 --- a/arch/frv/kernel/time.c +++ b/arch/frv/kernel/time.c @@ -70,7 +70,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) */ write_seqlock(&xtime_lock); - do_timer(regs); + do_timer(1); update_process_times(user_mode(regs)); profile_tick(CPU_PROFILING, regs); diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c index 688a5100604c..e569d17b4ae6 100644 --- a/arch/h8300/kernel/time.c +++ b/arch/h8300/kernel/time.c @@ -41,7 +41,7 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs) /* may need to kick the hardware timer */ platform_timer_eoi(); - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 6928ef0d64d8..16262687a103 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -78,7 +78,7 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) * xtime_lock. */ write_seqlock(&xtime_lock); - do_timer(regs); + do_timer(1); local_cpu_data->itm_next = new_itm; write_sequnlock(&xtime_lock); } else diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c index ded0be07a476..7a896893cd28 100644 --- a/arch/m32r/kernel/time.c +++ b/arch/m32r/kernel/time.c @@ -202,7 +202,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) #ifndef CONFIG_SMP profile_tick(CPU_PROFILING, regs); #endif - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index 98e4b1adfa29..1072e4946a4a 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -40,7 +40,7 @@ static inline int set_rtc_mmss(unsigned long nowtime) */ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) { - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c index f18b9d3ef16d..dc4ea7e074a6 100644 --- a/arch/m68k/sun3/sun3ints.c +++ b/arch/m68k/sun3/sun3ints.c @@ -65,7 +65,7 @@ static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp) #ifdef CONFIG_SUN3 intersil_clear(); #endif - do_timer(fp); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(fp)); #endif diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c index 1db987272220..db1e1ce0a349 100644 --- a/arch/m68knommu/kernel/time.c +++ b/arch/m68knommu/kernel/time.c @@ -51,7 +51,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) write_seqlock(&xtime_lock); - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index 7fbea1bf7b48..0a067f3113a5 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -96,7 +96,7 @@ void mips_timer_interrupt(struct pt_regs *regs) timerlo = count; kstat_this_cpu.irqs[irq]++; - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif @@ -137,7 +137,7 @@ irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs) } while (time_elapsed > 0) { - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif @@ -156,7 +156,7 @@ irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs) if (jiffie_drift >= 999) { jiffie_drift -= 999; - do_timer(regs); /* increment jiffies by one */ + do_timer(1); /* increment jiffies by one */ #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/mips/gt64120/common/time.c b/arch/mips/gt64120/common/time.c index d837b26fbe51..7feca49350d1 100644 --- a/arch/mips/gt64120/common/time.c +++ b/arch/mips/gt64120/common/time.c @@ -34,7 +34,7 @@ static void gt64120_irq(int irq, void *dev_id, struct pt_regs *regs) if (irq_src & 0x00000800) { /* Check for timer interrupt */ handled = 1; irq_src &= ~0x00000800; - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 170cb67f4ede..6ab8d975a974 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -434,7 +434,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* * call the generic timer interrupt handling */ - do_timer(regs); + do_timer(1); /* * If we have an externally synchronized Linux clock, then update diff --git a/arch/mips/momentum/ocelot_g/gt-irq.c b/arch/mips/momentum/ocelot_g/gt-irq.c index 9fb2493fff02..6cd87cf0195a 100644 --- a/arch/mips/momentum/ocelot_g/gt-irq.c +++ b/arch/mips/momentum/ocelot_g/gt-irq.c @@ -133,7 +133,7 @@ static irqreturn_t gt64240_p0int_irq(int irq, void *dev, struct pt_regs *regs) MV_WRITE(TIMER_COUNTER_0_3_INTERRUPT_CAUSE, 0x0); /* handle the timer call */ - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index b029ba79c27a..c62a3a9ef867 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -111,7 +111,7 @@ again: kstat_this_cpu.irqs[irq]++; /* kstat only for bootcpu? */ if (cpu == 0) - do_timer(regs); + do_timer(1); update_process_times(user_mode(regs)); diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 5facc9bff4ef..700df10924dd 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -79,7 +79,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) #endif if (cpu == 0) { write_seqlock(&xtime_lock); - do_timer(regs); + do_timer(1); write_sequnlock(&xtime_lock); } } diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 7a3c3f791ade..71f71da98e7d 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -693,7 +693,7 @@ void timer_interrupt(struct pt_regs * regs) tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy; if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) { tb_last_jiffy = tb_next_jiffy; - do_timer(regs); + do_timer(1); timer_recalc_offset(tb_last_jiffy); timer_check_rtc(); } diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index 6ab8cc7226ab..1e1f31554767 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -153,7 +153,7 @@ void timer_interrupt(struct pt_regs * regs) /* We are in an interrupt, no need to save/restore flags */ write_seqlock(&xtime_lock); tb_last_stamp = jiffy_stamp; - do_timer(regs); + do_timer(1); /* * update the rtc when needed, this should be performed on the diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 1981c6199fa2..abab42e9f5f8 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -166,7 +166,7 @@ EXPORT_SYMBOL(do_settimeofday); void account_ticks(struct pt_regs *regs) { __u64 tmp; - __u32 ticks, xticks; + __u32 ticks; /* Calculate how many ticks have passed. */ if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) { @@ -204,6 +204,7 @@ 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 = __div(tmp, CLK_TICKS_PER_JIFFY); @@ -212,13 +213,11 @@ void account_ticks(struct pt_regs *regs) xticks = 1; xtime_cc += CLK_TICKS_PER_JIFFY; } - while (xticks--) - do_timer(regs); + do_timer(xticks); } write_sequnlock(&xtime_lock); #else - for (xticks = ticks; xticks > 0; xticks--) - do_timer(regs); + do_timer(ticks); #endif #ifdef CONFIG_VIRT_CPU_ACCOUNTING diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 149d9713eddf..f664a196c4f5 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -117,7 +117,7 @@ static long last_rtc_update; */ void handle_timer_tick(struct pt_regs *regs) { - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c index b8162e59030e..3b61e06f9d72 100644 --- a/arch/sh64/kernel/time.c +++ b/arch/sh64/kernel/time.c @@ -298,7 +298,7 @@ static inline void do_timer_interrupt(int irq, struct pt_regs *regs) asm ("getcon cr62, %0" : "=r" (current_ctc)); ctc_last_interrupt = (unsigned long) current_ctc; - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index bfd31aac2df3..e19b1bad9bc5 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -712,7 +712,7 @@ static irqreturn_t pcic_timer_handler (int irq, void *h, struct pt_regs *regs) { write_seqlock(&xtime_lock); /* Dummy, to show that we remember */ pcic_clear_clock_irq(); - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 845081b01267..6f84fa1b58e5 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -128,7 +128,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) #endif clear_clock_irq(); - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index b0b4feeec098..ca1193482f07 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -465,7 +465,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) profile_tick(CPU_PROFILING, regs); update_process_times(user_mode(regs)); #endif - do_timer(regs); + do_timer(1); /* Guarantee that the following sequences execute * uninterrupted. @@ -496,7 +496,7 @@ void timer_tick_interrupt(struct pt_regs *regs) { write_seqlock(&xtime_lock); - do_timer(regs); + do_timer(1); timer_check_rtc(); diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 820affbf3e16..a92965f8f9cd 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -93,7 +93,7 @@ irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) write_seqlock_irqsave(&xtime_lock, flags); - do_timer(regs); + do_timer(1); nsecs = get_time(); xtime.tv_sec = nsecs / NSEC_PER_SEC; diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c index a0b46695f186..f4d1a4d3cdc2 100644 --- a/arch/v850/kernel/time.c +++ b/arch/v850/kernel/time.c @@ -51,7 +51,7 @@ static irqreturn_t timer_interrupt (int irq, void *dummy, struct pt_regs *regs) if (mach_tick) mach_tick (); - do_timer (regs); + do_timer (1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 1c255ee76e7c..7ea3bf2a858c 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -415,16 +415,16 @@ void main_timer_handler(struct pt_regs *regs) (((long) offset << US_SCALE) / vxtime.tsc_quot) - 1; } - if (lost > 0) { + if (lost > 0) handle_lost_ticks(lost, regs); - jiffies += lost; - } + else + lost = 0; /* * Do the timer stuff. */ - do_timer(regs); + do_timer(lost + 1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index 412ab32de391..241db201f40e 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c @@ -175,7 +175,7 @@ again: last_ccount_stamp = next; next += CCOUNT_PER_JIFFY; - do_timer (regs); /* Linux handler in kernel/timer.c */ + do_timer (1); /* Linux handler in kernel/timer.c */ if (ntp_synced() && xtime.tv_sec - last_rtc_update >= 659 && diff --git a/include/asm-arm/arch-clps711x/time.h b/include/asm-arm/arch-clps711x/time.h index 9cb27cd4e6ae..0e4a3901d3b3 100644 --- a/include/asm-arm/arch-clps711x/time.h +++ b/include/asm-arm/arch-clps711x/time.h @@ -29,7 +29,7 @@ static irqreturn_t p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { do_leds(); - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/include/asm-arm/arch-l7200/time.h b/include/asm-arm/arch-l7200/time.h index 7b98b533e63a..c69cb508735f 100644 --- a/include/asm-arm/arch-l7200/time.h +++ b/include/asm-arm/arch-l7200/time.h @@ -45,7 +45,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif diff --git a/include/asm-i386/mach-default/do_timer.h b/include/asm-i386/mach-default/do_timer.h index 6312c3e79814..4182c347ef85 100644 --- a/include/asm-i386/mach-default/do_timer.h +++ b/include/asm-i386/mach-default/do_timer.h @@ -16,7 +16,7 @@ static inline void do_timer_interrupt_hook(struct pt_regs *regs) { - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode_vm(regs)); #endif diff --git a/include/asm-i386/mach-visws/do_timer.h b/include/asm-i386/mach-visws/do_timer.h index 95568e6ca91c..8db618c5a72b 100644 --- a/include/asm-i386/mach-visws/do_timer.h +++ b/include/asm-i386/mach-visws/do_timer.h @@ -9,7 +9,7 @@ static inline void do_timer_interrupt_hook(struct pt_regs *regs) /* Clear the interrupt */ co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR); - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode_vm(regs)); #endif diff --git a/include/asm-i386/mach-voyager/do_timer.h b/include/asm-i386/mach-voyager/do_timer.h index eaf518098981..099fe9f5c1b2 100644 --- a/include/asm-i386/mach-voyager/do_timer.h +++ b/include/asm-i386/mach-voyager/do_timer.h @@ -3,7 +3,7 @@ static inline void do_timer_interrupt_hook(struct pt_regs *regs) { - do_timer(regs); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode_vm(regs)); #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index ed2af8671589..503dea61ff99 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1206,7 +1206,7 @@ extern void switch_uid(struct user_struct *); #include -extern void do_timer(struct pt_regs *); +extern void do_timer(unsigned long ticks); extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state)); extern int FASTCALL(wake_up_process(struct task_struct * tsk)); diff --git a/kernel/timer.c b/kernel/timer.c index a2cb1ecb1b28..4f55622b0d38 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1222,10 +1222,8 @@ static inline void calc_load(unsigned long ticks) unsigned long active_tasks; /* fixed-point */ static int count = LOAD_FREQ; - count -= ticks; - if (count < 0) { - count += LOAD_FREQ; - active_tasks = count_active_tasks(); + active_tasks = count_active_tasks(); + for (count -= ticks; count < 0; count += LOAD_FREQ) { CALC_LOAD(avenrun[0], EXP_1, active_tasks); CALC_LOAD(avenrun[1], EXP_5, active_tasks); CALC_LOAD(avenrun[2], EXP_15, active_tasks); @@ -1270,11 +1268,8 @@ void run_local_timers(void) * Called by the timer interrupt. xtime_lock must already be taken * by the timer IRQ! */ -static inline void update_times(void) +static inline void update_times(unsigned long ticks) { - unsigned long ticks; - - ticks = jiffies - wall_jiffies; wall_jiffies += ticks; update_wall_time(); calc_load(ticks); @@ -1286,12 +1281,10 @@ static inline void update_times(void) * jiffies is defined in the linker script... */ -void do_timer(struct pt_regs *regs) +void do_timer(unsigned long ticks) { - jiffies_64++; - /* prevent loading jiffies before storing new jiffies_64 value. */ - barrier(); - update_times(); + jiffies_64 += ticks; + update_times(ticks); } #ifdef __ARCH_WANT_SYS_ALARM -- cgit v1.2.3 From 5785c95baede8459d70c4aa0f7becb6e8b5fde4b Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 29 Sep 2006 02:00:43 -0700 Subject: [PATCH] tty: make termios_sem a mutex [akpm@osdl.org: fix] Cc: Alan Cox Cc: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 23 ++++++++++++----------- drivers/char/tty_ioctl.c | 17 +++++++++-------- include/linux/tty.h | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index b4f37c65b95c..142427c6e8f3 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -618,9 +618,9 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); static void tty_set_termios_ldisc(struct tty_struct *tty, int num) { - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); tty->termios->c_line = num; - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); } /* @@ -1338,9 +1338,9 @@ static void do_tty_hangup(void *data) */ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); *tty->termios = tty->driver->init_termios; - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); } /* Defer ldisc switch */ @@ -2750,9 +2750,9 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) { int err; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); err = copy_to_user(arg, &tty->winsize, sizeof(*arg)); - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); return err ? -EFAULT: 0; } @@ -2782,14 +2782,15 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) return -EFAULT; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) goto done; #ifdef CONFIG_VT if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { - if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row)) { - up(&tty->termios_sem); + if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, + tmp_ws.ws_row)) { + mutex_unlock(&tty->termios_mutex); return -ENXIO; } } @@ -2801,7 +2802,7 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, tty->winsize = tmp_ws; real_tty->winsize = tmp_ws; done: - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); return 0; } @@ -3576,7 +3577,7 @@ static void initialize_tty_struct(struct tty_struct *tty) tty_buffer_init(tty); INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); init_MUTEX(&tty->buf.pty_sem); - init_MUTEX(&tty->termios_sem); + mutex_init(&tty->termios_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 4ad47d321bd4..4d540619ac84 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -131,7 +132,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios /* FIXME: we need to decide on some locking/ordering semantics for the set_termios notification eventually */ - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); @@ -176,7 +177,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios (ld->set_termios)(tty, &old_termios); tty_ldisc_deref(ld); } - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); } /** @@ -284,13 +285,13 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) { struct sgttyb tmp; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); tmp.sg_ispeed = 0; tmp.sg_ospeed = 0; tmp.sg_erase = tty->termios->c_cc[VERASE]; tmp.sg_kill = tty->termios->c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -345,12 +346,12 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) return -EFAULT; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); termios = *tty->termios; termios.c_cc[VERASE] = tmp.sg_erase; termios.c_cc[VKILL] = tmp.sg_kill; set_sgflags(&termios, tmp.sg_flags); - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); change_termios(tty, &termios); return 0; } @@ -592,11 +593,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, case TIOCSSOFTCAR: if (get_user(arg, (unsigned int __user *) arg)) return -EFAULT; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); return 0; default: return -ENOIOCTLCMD; diff --git a/include/linux/tty.h b/include/linux/tty.h index d1dec3d0c814..ea4c2605f8da 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -174,7 +174,7 @@ struct tty_struct { struct tty_driver *driver; int index; struct tty_ldisc ldisc; - struct semaphore termios_sem; + struct mutex termios_mutex; struct termios *termios, *termios_locked; char name[64]; int pgrp; -- cgit v1.2.3 From 416bc51292f977b43b010c6dd937522b90062390 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Fri, 29 Sep 2006 02:00:45 -0700 Subject: [PATCH] Use decimal for PTRACE_ATTACH and PTRACE_DETACH. It is sure confusing that linux/ptrace.h has: #define PTRACE_SINGLESTEP 9 #define PTRACE_ATTACH 0x10 #define PTRACE_DETACH 0x11 #define PTRACE_SYSCALL 24 All the low-numbered constants are in decimal, but the last two in hex. It sure makes it likely that someone will look at this and think that 9, 10, 11 are used, and that 16 and 17 are not used. How about we use the same notation for all the numbers [0,24] in the same short list? Signed-off-by: Roland McGrath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/ptrace.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 8b2749a259dc..eeb1976ef7bf 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -16,8 +16,8 @@ #define PTRACE_KILL 8 #define PTRACE_SINGLESTEP 9 -#define PTRACE_ATTACH 0x10 -#define PTRACE_DETACH 0x11 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 #define PTRACE_SYSCALL 24 -- cgit v1.2.3 From 57a6f51c4281aa3119975473c70dce0480d322bd Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 29 Sep 2006 02:00:49 -0700 Subject: [PATCH] introduce is_rt_policy() helper Imho, makes the code a bit easier to read. Signed-off-by: Oleg Nesterov Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Steven Rostedt Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 4 ++-- kernel/sched.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 503dea61ff99..fbc69cc3923d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -504,8 +504,8 @@ struct signal_struct { #define rt_prio(prio) unlikely((prio) < MAX_RT_PRIO) #define rt_task(p) rt_prio((p)->prio) #define batch_task(p) (unlikely((p)->policy == SCHED_BATCH)) -#define has_rt_policy(p) \ - unlikely((p)->policy != SCHED_NORMAL && (p)->policy != SCHED_BATCH) +#define is_rt_policy(p) ((p) != SCHED_NORMAL && (p) != SCHED_BATCH) +#define has_rt_policy(p) unlikely(is_rt_policy((p)->policy)) /* * Some day this will be a full-fledged user tracking system.. diff --git a/kernel/sched.c b/kernel/sched.c index f9b3c6a414f1..c3c718aea618 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4109,8 +4109,7 @@ recheck: (p->mm && param->sched_priority > MAX_USER_RT_PRIO-1) || (!p->mm && param->sched_priority > MAX_RT_PRIO-1)) return -EINVAL; - if ((policy == SCHED_NORMAL || policy == SCHED_BATCH) - != (param->sched_priority == 0)) + if (is_rt_policy(policy) != (param->sched_priority != 0)) return -EINVAL; /* @@ -4134,7 +4133,7 @@ recheck: !rlim_rtprio) return -EPERM; /* can't increase priority */ - if ((policy != SCHED_NORMAL && policy != SCHED_BATCH) && + if (is_rt_policy(policy) && param->sched_priority > p->rt_priority && param->sched_priority > rlim_rtprio) return -EPERM; -- cgit v1.2.3 From 9f50b93f066f8dc339de9b0eb78a22a75e6c8f8f Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 29 Sep 2006 02:00:59 -0700 Subject: [PATCH] Make spinlock/rwlock annotations more accurate by using parameters, not types The lock annotations used on spinlocks and rwlocks currently use __{acquires,releases}(spinlock_t) and __{acquires,releases}(rwlock_t), respectively. This loses the information of which lock actually got acquired or released, and assumes a different type for the parameter of __acquires and __releases than the rest of the kernel. While the current implementations of __acquires and __releases throw away their argument, this will not always remain the case. Change this to use the lock parameter instead, to preserve this information and increase consistency in usage of __acquires and __releases. Signed-off-by: Josh Triplett Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/spinlock_api_smp.h | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h index b2c4f8299464..8828b8155e9c 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -19,41 +19,41 @@ int in_lock_functions(unsigned long addr); #define assert_spin_locked(x) BUG_ON(!spin_is_locked(x)) -void __lockfunc _spin_lock(spinlock_t *lock) __acquires(spinlock_t); +void __lockfunc _spin_lock(spinlock_t *lock) __acquires(lock); void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass) - __acquires(spinlock_t); -void __lockfunc _read_lock(rwlock_t *lock) __acquires(rwlock_t); -void __lockfunc _write_lock(rwlock_t *lock) __acquires(rwlock_t); -void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(spinlock_t); -void __lockfunc _read_lock_bh(rwlock_t *lock) __acquires(rwlock_t); -void __lockfunc _write_lock_bh(rwlock_t *lock) __acquires(rwlock_t); -void __lockfunc _spin_lock_irq(spinlock_t *lock) __acquires(spinlock_t); -void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(rwlock_t); -void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(rwlock_t); + __acquires(lock); +void __lockfunc _read_lock(rwlock_t *lock) __acquires(lock); +void __lockfunc _write_lock(rwlock_t *lock) __acquires(lock); +void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(lock); +void __lockfunc _read_lock_bh(rwlock_t *lock) __acquires(lock); +void __lockfunc _write_lock_bh(rwlock_t *lock) __acquires(lock); +void __lockfunc _spin_lock_irq(spinlock_t *lock) __acquires(lock); +void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(lock); +void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(lock); unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) - __acquires(spinlock_t); + __acquires(lock); unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) - __acquires(rwlock_t); + __acquires(lock); unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) - __acquires(rwlock_t); + __acquires(lock); int __lockfunc _spin_trylock(spinlock_t *lock); int __lockfunc _read_trylock(rwlock_t *lock); int __lockfunc _write_trylock(rwlock_t *lock); int __lockfunc _spin_trylock_bh(spinlock_t *lock); -void __lockfunc _spin_unlock(spinlock_t *lock) __releases(spinlock_t); -void __lockfunc _read_unlock(rwlock_t *lock) __releases(rwlock_t); -void __lockfunc _write_unlock(rwlock_t *lock) __releases(rwlock_t); -void __lockfunc _spin_unlock_bh(spinlock_t *lock) __releases(spinlock_t); -void __lockfunc _read_unlock_bh(rwlock_t *lock) __releases(rwlock_t); -void __lockfunc _write_unlock_bh(rwlock_t *lock) __releases(rwlock_t); -void __lockfunc _spin_unlock_irq(spinlock_t *lock) __releases(spinlock_t); -void __lockfunc _read_unlock_irq(rwlock_t *lock) __releases(rwlock_t); -void __lockfunc _write_unlock_irq(rwlock_t *lock) __releases(rwlock_t); +void __lockfunc _spin_unlock(spinlock_t *lock) __releases(lock); +void __lockfunc _read_unlock(rwlock_t *lock) __releases(lock); +void __lockfunc _write_unlock(rwlock_t *lock) __releases(lock); +void __lockfunc _spin_unlock_bh(spinlock_t *lock) __releases(lock); +void __lockfunc _read_unlock_bh(rwlock_t *lock) __releases(lock); +void __lockfunc _write_unlock_bh(rwlock_t *lock) __releases(lock); +void __lockfunc _spin_unlock_irq(spinlock_t *lock) __releases(lock); +void __lockfunc _read_unlock_irq(rwlock_t *lock) __releases(lock); +void __lockfunc _write_unlock_irq(rwlock_t *lock) __releases(lock); void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) - __releases(spinlock_t); + __releases(lock); void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) - __releases(rwlock_t); + __releases(lock); void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) - __releases(rwlock_t); + __releases(lock); #endif /* __LINUX_SPINLOCK_API_SMP_H */ -- cgit v1.2.3 From 303912e2a32aa73785b4c4dee15466d944a38a46 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 29 Sep 2006 02:01:00 -0700 Subject: [PATCH] Replace _spin_trylock with spin_trylock in the IRQ variants to use __cond_lock spin_trylock_irq and spin_trylock_irqsave use _spin_trylock, which does not use the __cond_lock wrapper annotation and thus does not affect the lock context; change them to use spin_trylock instead, which does use __cond_lock. Signed-off-by: Josh Triplett Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/spinlock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 31473db92d3b..456e74f0e129 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -241,14 +241,14 @@ do { \ #define spin_trylock_irq(lock) \ ({ \ local_irq_disable(); \ - _spin_trylock(lock) ? \ + spin_trylock(lock) ? \ 1 : ({ local_irq_enable(); 0; }); \ }) #define spin_trylock_irqsave(lock, flags) \ ({ \ local_irq_save(flags); \ - _spin_trylock(lock) ? \ + spin_trylock(lock) ? \ 1 : ({ local_irq_restore(flags); 0; }); \ }) -- cgit v1.2.3 From dcc8e559ee5ae03fa6bdb8611d76d86d0083e793 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 29 Sep 2006 02:01:03 -0700 Subject: [PATCH] Pass a lock expression to __cond_lock, like __acquire and __release Currently, __acquire and __release take a lock expression, but __cond_lock takes only a condition, not the lock acquired if the expression evaluates to true. Change __cond_lock to accept a lock expression, and change all the callers to pass in a lock expression. Signed-off-by: Josh Triplett Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/compiler.h | 4 ++-- include/linux/spinlock.h | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 060b96112ec6..0780de440220 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -14,7 +14,7 @@ # define __releases(x) __attribute__((context(1,0))) # define __acquire(x) __context__(1) # define __release(x) __context__(-1) -# define __cond_lock(x) ((x) ? ({ __context__(1); 1; }) : 0) +# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) extern void __chk_user_ptr(void __user *); extern void __chk_io_ptr(void __iomem *); #else @@ -31,7 +31,7 @@ extern void __chk_io_ptr(void __iomem *); # define __releases(x) # define __acquire(x) (void)0 # define __release(x) (void)0 -# define __cond_lock(x) (x) +# define __cond_lock(x,c) (c) #endif #ifdef __KERNEL__ diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 456e74f0e129..b800d2d68b32 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -167,9 +167,9 @@ do { \ * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various * methods are defined as nops in the case they are not required. */ -#define spin_trylock(lock) __cond_lock(_spin_trylock(lock)) -#define read_trylock(lock) __cond_lock(_read_trylock(lock)) -#define write_trylock(lock) __cond_lock(_write_trylock(lock)) +#define spin_trylock(lock) __cond_lock(lock, _spin_trylock(lock)) +#define read_trylock(lock) __cond_lock(lock, _read_trylock(lock)) +#define write_trylock(lock) __cond_lock(lock, _write_trylock(lock)) #define spin_lock(lock) _spin_lock(lock) @@ -236,7 +236,7 @@ do { \ _write_unlock_irqrestore(lock, flags) #define write_unlock_bh(lock) _write_unlock_bh(lock) -#define spin_trylock_bh(lock) __cond_lock(_spin_trylock_bh(lock)) +#define spin_trylock_bh(lock) __cond_lock(lock, _spin_trylock_bh(lock)) #define spin_trylock_irq(lock) \ ({ \ @@ -264,7 +264,7 @@ do { \ */ extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); #define atomic_dec_and_lock(atomic, lock) \ - __cond_lock(_atomic_dec_and_lock(atomic, lock)) + __cond_lock(lock, _atomic_dec_and_lock(atomic, lock)) /** * spin_can_lock - would spin_trylock() succeed? -- cgit v1.2.3 From 368bdb3d616fa352971f45b423ae6344715e620b Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 29 Sep 2006 02:01:05 -0700 Subject: [PATCH] cramfs: make cramfs_uncompress_exit() return void It always returns 0, so relying on it is useless. The only caller isn't checking return value. In general, un-, de-, -free functions should return void. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/cramfs/uncompress.c | 3 +-- include/linux/cramfs_fs.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c index 8def89f2c438..fc3ccb74626f 100644 --- a/fs/cramfs/uncompress.c +++ b/fs/cramfs/uncompress.c @@ -68,11 +68,10 @@ int cramfs_uncompress_init(void) return 0; } -int cramfs_uncompress_exit(void) +void cramfs_uncompress_exit(void) { if (!--initialized) { zlib_inflateEnd(&stream); vfree(stream.workspace); } - return 0; } diff --git a/include/linux/cramfs_fs.h b/include/linux/cramfs_fs.h index a41f38428c37..1dba681e428d 100644 --- a/include/linux/cramfs_fs.h +++ b/include/linux/cramfs_fs.h @@ -87,6 +87,6 @@ struct cramfs_super { /* Uncompression interfaces to the underlying zlib */ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen); int cramfs_uncompress_init(void); -int cramfs_uncompress_exit(void); +void cramfs_uncompress_exit(void); #endif -- cgit v1.2.3 From e8106b941ceab68cc5ff713df7b1276484554584 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 29 Sep 2006 02:01:08 -0700 Subject: [PATCH] lockdep: core, add enable/disable_irq_irqsave/irqrestore() APIs Introduce the disable_irq_nosync_lockdep_irqsave() and enable_irq_lockdep_irqrestore() APIs. These are needed for NE2000; basically NE2000 calls disable_irq and enable_irq as locking against the IRQ handler, but both in cases where interrupts are on and off. This means that lockdep needs to track the old state of the virtual irq flags on disable_irq, and restore these at enable_irq time. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/8390.c | 6 +++--- include/linux/interrupt.h | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 5b6b05ed8f3c..9d34056147ad 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -299,7 +299,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) * Slow phase with lock held. */ - disable_irq_nosync_lockdep(dev->irq); + disable_irq_nosync_lockdep_irqsave(dev->irq, &flags); spin_lock(&ei_local->page_lock); @@ -338,7 +338,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock(&ei_local->page_lock); - enable_irq_lockdep(dev->irq); + enable_irq_lockdep_irqrestore(dev->irq, &flags); ei_local->stat.tx_errors++; return 1; } @@ -379,7 +379,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock(&ei_local->page_lock); - enable_irq_lockdep(dev->irq); + enable_irq_lockdep_irqrestore(dev->irq, &flags); dev_kfree_skb (skb); ei_local->stat.tx_bytes += send_length; diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index d5afee95fd43..1f97e3d92639 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -123,6 +123,14 @@ static inline void disable_irq_nosync_lockdep(unsigned int irq) #endif } +static inline void disable_irq_nosync_lockdep_irqsave(unsigned int irq, unsigned long *flags) +{ + disable_irq_nosync(irq); +#ifdef CONFIG_LOCKDEP + local_irq_save(*flags); +#endif +} + static inline void disable_irq_lockdep(unsigned int irq) { disable_irq(irq); @@ -139,6 +147,14 @@ static inline void enable_irq_lockdep(unsigned int irq) enable_irq(irq); } +static inline void enable_irq_lockdep_irqrestore(unsigned int irq, unsigned long *flags) +{ +#ifdef CONFIG_LOCKDEP + local_irq_restore(*flags); +#endif + enable_irq(irq); +} + /* IRQ wakeup (PM) control: */ extern int set_irq_wake(unsigned int irq, unsigned int on); -- cgit v1.2.3 From 55a101f8f71a3d3dbda7b5c77083ffe47552f831 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 29 Sep 2006 02:01:10 -0700 Subject: [PATCH] kill PF_DEAD flag After the previous change (->flags & PF_DEAD) <=> (->state == EXIT_DEAD), we don't need PF_DEAD any longer. Signed-off-by: Oleg Nesterov Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 - kernel/exit.c | 6 ++---- kernel/sched.c | 16 ++++++++-------- mm/oom_kill.c | 4 ++-- 4 files changed, 12 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index fbc69cc3923d..9763de334f09 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1061,7 +1061,6 @@ static inline void put_task_struct(struct task_struct *t) /* Not implemented yet, only for 486*/ #define PF_STARTING 0x00000002 /* being created */ #define PF_EXITING 0x00000004 /* getting shut down */ -#define PF_DEAD 0x00000008 /* Dead */ #define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ #define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ #define PF_DUMPCORE 0x00000200 /* dumped core */ diff --git a/kernel/exit.c b/kernel/exit.c index 3d759c98fb11..9dd5f1336da2 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -953,10 +953,8 @@ fastcall NORET_TYPE void do_exit(long code) if (tsk->splice_pipe) __free_pipe_info(tsk->splice_pipe); - /* PF_DEAD causes final put_task_struct after we schedule. */ preempt_disable(); - BUG_ON(tsk->flags & PF_DEAD); - tsk->flags |= PF_DEAD; + /* causes final put_task_struct in finish_task_switch(). */ tsk->state = EXIT_DEAD; schedule(); @@ -972,7 +970,7 @@ NORET_TYPE void complete_and_exit(struct completion *comp, long code) { if (comp) complete(comp); - + do_exit(code); } diff --git a/kernel/sched.c b/kernel/sched.c index e1646b044b69..a9405d7cc6ab 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1755,27 +1755,27 @@ static inline void finish_task_switch(struct rq *rq, struct task_struct *prev) __releases(rq->lock) { struct mm_struct *mm = rq->prev_mm; - unsigned long prev_task_flags; + long prev_state; rq->prev_mm = NULL; /* * A task struct has one reference for the use as "current". - * If a task dies, then it sets EXIT_ZOMBIE in tsk->exit_state and - * calls schedule one last time. The schedule call will never return, - * and the scheduled task must drop that reference. - * The test for EXIT_ZOMBIE must occur while the runqueue locks are + * If a task dies, then it sets EXIT_DEAD in tsk->state and calls + * schedule one last time. The schedule call will never return, and + * the scheduled task must drop that reference. + * The test for EXIT_DEAD must occur while the runqueue locks are * still held, otherwise prev could be scheduled on another cpu, die * there before we look at prev->state, and then the reference would * be dropped twice. * Manfred Spraul */ - prev_task_flags = prev->flags; + prev_state = prev->state; finish_arch_switch(prev); finish_lock_switch(rq, prev); if (mm) mmdrop(mm); - if (unlikely(prev_task_flags & PF_DEAD)) { + if (unlikely(prev_state == EXIT_DEAD)) { /* * Remove function-return probe instances associated with this * task and put them back on the free list. @@ -5153,7 +5153,7 @@ static void migrate_dead(unsigned int dead_cpu, struct task_struct *p) BUG_ON(p->exit_state != EXIT_ZOMBIE && p->exit_state != EXIT_DEAD); /* Cannot have done final schedule yet: would have vanished. */ - BUG_ON(p->flags & PF_DEAD); + BUG_ON(p->state == EXIT_DEAD); get_task_struct(p); diff --git a/mm/oom_kill.c b/mm/oom_kill.c index f3dd79c1c367..202f186a753a 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -226,8 +226,8 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) releasing = test_tsk_thread_flag(p, TIF_MEMDIE) || p->flags & PF_EXITING; if (releasing) { - /* PF_DEAD tasks have already released their mm */ - if (p->flags & PF_DEAD) + /* TASK_DEAD tasks have already released their mm */ + if (p->state == EXIT_DEAD) continue; if (p->flags & PF_EXITING && p == current) { chosen = p; -- cgit v1.2.3 From c394cc9fbb367f87faa2228ec2eabacd2d4701c6 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 29 Sep 2006 02:01:11 -0700 Subject: [PATCH] introduce TASK_DEAD state I am not sure about this patch, I am asking Ingo to take a decision. task_struct->state == EXIT_DEAD is a very special case, to avoid a confusion it makes sense to introduce a new state, TASK_DEAD, while EXIT_DEAD should live only in ->exit_state as documented in sched.h. Note that this state is not visible to user-space, get_task_state() masks off unsuitable states. Signed-off-by: Oleg Nesterov Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 + kernel/exit.c | 2 +- kernel/sched.c | 8 ++++---- mm/oom_kill.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 9763de334f09..a06fc89cf6e5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -148,6 +148,7 @@ extern unsigned long weighted_cpuload(const int cpu); #define EXIT_DEAD 32 /* in tsk->state again */ #define TASK_NONINTERACTIVE 64 +#define TASK_DEAD 128 #define __set_task_state(tsk, state_value) \ do { (tsk)->state = (state_value); } while (0) diff --git a/kernel/exit.c b/kernel/exit.c index 9dd5f1336da2..2e4c13cba95a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -955,7 +955,7 @@ fastcall NORET_TYPE void do_exit(long code) preempt_disable(); /* causes final put_task_struct in finish_task_switch(). */ - tsk->state = EXIT_DEAD; + tsk->state = TASK_DEAD; schedule(); BUG(); diff --git a/kernel/sched.c b/kernel/sched.c index a9405d7cc6ab..74f169ac0773 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1761,10 +1761,10 @@ static inline void finish_task_switch(struct rq *rq, struct task_struct *prev) /* * A task struct has one reference for the use as "current". - * If a task dies, then it sets EXIT_DEAD in tsk->state and calls + * If a task dies, then it sets TASK_DEAD in tsk->state and calls * schedule one last time. The schedule call will never return, and * the scheduled task must drop that reference. - * The test for EXIT_DEAD must occur while the runqueue locks are + * The test for TASK_DEAD must occur while the runqueue locks are * still held, otherwise prev could be scheduled on another cpu, die * there before we look at prev->state, and then the reference would * be dropped twice. @@ -1775,7 +1775,7 @@ static inline void finish_task_switch(struct rq *rq, struct task_struct *prev) finish_lock_switch(rq, prev); if (mm) mmdrop(mm); - if (unlikely(prev_state == EXIT_DEAD)) { + if (unlikely(prev_state == TASK_DEAD)) { /* * Remove function-return probe instances associated with this * task and put them back on the free list. @@ -5153,7 +5153,7 @@ static void migrate_dead(unsigned int dead_cpu, struct task_struct *p) BUG_ON(p->exit_state != EXIT_ZOMBIE && p->exit_state != EXIT_DEAD); /* Cannot have done final schedule yet: would have vanished. */ - BUG_ON(p->state == EXIT_DEAD); + BUG_ON(p->state == TASK_DEAD); get_task_struct(p); diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 202f186a753a..21f0a7e8e514 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -227,7 +227,7 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) p->flags & PF_EXITING; if (releasing) { /* TASK_DEAD tasks have already released their mm */ - if (p->state == EXIT_DEAD) + if (p->state == TASK_DEAD) continue; if (p->flags & PF_EXITING && p == current) { chosen = p; -- cgit v1.2.3 From 38837fc75acb7fa9b0e111b0241fe4fe76c5d4b3 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Fri, 29 Sep 2006 02:01:16 -0700 Subject: [PATCH] cpuset: top_cpuset tracks hotplug changes to node_online_map Change the list of memory nodes allowed to tasks in the top (root) nodeset to dynamically track what cpus are online, using a call to a cpuset hook from the memory hotplug code. Make this top cpus file read-only. On systems that have cpusets configured in their kernel, but that aren't actively using cpusets (for some distros, this covers the majority of systems) all tasks end up in the top cpuset. If that system does support memory hotplug, then these tasks cannot make use of memory nodes that are added after system boot, because the memory nodes are not allowed in the top cpuset. This is a surprising regression over earlier kernels that didn't have cpusets enabled. One key motivation for this change is to remain consistent with the behaviour for the top_cpuset's 'cpus', which is also read-only, and which automatically tracks the cpu_online_map. This change also has the minor benefit that it fixes a long standing, little noticed, minor bug in cpusets. The cpuset performance tweak to short circuit the cpuset_zone_allowed() check on systems with just a single cpuset (see 'number_of_cpusets', in linux/cpuset.h) meant that simply changing the 'mems' of the top_cpuset had no affect, even though the change (the write system call) appeared to succeed. With the following change, that write to the 'mems' file fails -EACCES, and the 'mems' file stubbornly refuses to be changed via user space writes. Thus no one should be mislead into thinking they've changed the top_cpusets's 'mems' when in affect they haven't. In order to keep the behaviour of cpusets consistent between systems actively making use of them and systems not using them, this patch changes the behaviour of the 'mems' file in the top (root) cpuset, making it read only, and making it automatically track the value of node_online_map. Thus tasks in the top cpuset will have automatic use of hot plugged memory nodes allowed by their cpuset. [akpm@osdl.org: build fix] [bunk@stusta.de: build fix] Signed-off-by: Paul Jackson Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cpusets.txt | 10 +++++----- include/linux/cpuset.h | 4 ++++ kernel/cpuset.c | 28 +++++++++++++++++++++++++--- mm/memory_hotplug.c | 3 +++ 4 files changed, 37 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt index 76b44290c154..842f0d1ab216 100644 --- a/Documentation/cpusets.txt +++ b/Documentation/cpusets.txt @@ -217,11 +217,11 @@ exclusive cpuset. Also, the use of a Linux virtual file system (vfs) to represent the cpuset hierarchy provides for a familiar permission and name space for cpusets, with a minimum of additional kernel code. -The cpus file in the root (top_cpuset) cpuset is read-only. -It automatically tracks the value of cpu_online_map, using a CPU -hotplug notifier. If and when memory nodes can be hotplugged, -we expect to make the mems file in the root cpuset read-only -as well, and have it track the value of node_online_map. +The cpus and mems files in the root (top_cpuset) cpuset are +read-only. The cpus file automatically tracks the value of +cpu_online_map using a CPU hotplug notifier, and the mems file +automatically tracks the value of node_online_map using the +cpuset_track_online_nodes() hook. 1.4 What are exclusive cpusets ? diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 9354722a9217..4d8adf663681 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -63,6 +63,8 @@ static inline int cpuset_do_slab_mem_spread(void) return current->flags & PF_SPREAD_SLAB; } +extern void cpuset_track_online_nodes(void); + #else /* !CONFIG_CPUSETS */ static inline int cpuset_init_early(void) { return 0; } @@ -126,6 +128,8 @@ static inline int cpuset_do_slab_mem_spread(void) return 0; } +static inline void cpuset_track_online_nodes(void) {} + #endif /* !CONFIG_CPUSETS */ #endif /* _LINUX_CPUSET_H */ diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 584bb4e6c042..794af5024c2f 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -912,6 +912,10 @@ static int update_nodemask(struct cpuset *cs, char *buf) int fudge; int retval; + /* top_cpuset.mems_allowed tracks node_online_map; it's read-only */ + if (cs == &top_cpuset) + return -EACCES; + trialcs = *cs; retval = nodelist_parse(buf, trialcs.mems_allowed); if (retval < 0) @@ -2042,9 +2046,8 @@ out: * (of no affect) on systems that are actively using CPU hotplug * but making no active use of cpusets. * - * This handles CPU hotplug (cpuhp) events. If someday Memory - * Nodes can be hotplugged (dynamically changing node_online_map) - * then we should handle that too, perhaps in a similar way. + * This routine ensures that top_cpuset.cpus_allowed tracks + * cpu_online_map on each CPU hotplug (cpuhp) event. */ #ifdef CONFIG_HOTPLUG_CPU @@ -2063,6 +2066,25 @@ static int cpuset_handle_cpuhp(struct notifier_block *nb, } #endif +/* + * Keep top_cpuset.mems_allowed tracking node_online_map. + * Call this routine anytime after you change node_online_map. + * See also the previous routine cpuset_handle_cpuhp(). + */ + +#ifdef CONFIG_MEMORY_HOTPLUG +void cpuset_track_online_nodes() +{ + mutex_lock(&manage_mutex); + mutex_lock(&callback_mutex); + + top_cpuset.mems_allowed = node_online_map; + + mutex_unlock(&callback_mutex); + mutex_unlock(&manage_mutex); +} +#endif + /** * cpuset_init_smp - initialize cpus_allowed * diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index c37319542b70..9576ed920c0a 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -283,6 +284,8 @@ int add_memory(int nid, u64 start, u64 size) /* we online node here. we can't roll back from here. */ node_set_online(nid); + cpuset_track_online_nodes(); + if (new_pgdat) { ret = register_one_node(nid); /* -- cgit v1.2.3 From 2d1d43f6a43b703587e759145f69467e7c6553a7 Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Fri, 29 Sep 2006 02:01:25 -0700 Subject: [PATCH] call mm/page-writeback.c:set_ratelimit() when new pages are hot-added ratelimit_pages in page-writeback.c is recalculated (in set_ratelimit()) every time a CPU is hot-added/removed. But this value is not recalculated when new pages are hot-added. This patch fixes that problem by calling set_ratelimit() when new pages are hot-added. [akpm@osdl.org: cleanups] Signed-off-by: Chandra Seetharaman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/writeback.h | 1 + mm/memory_hotplug.c | 2 ++ mm/page-writeback.c | 6 +++--- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 56a23a0e7f2e..9d4074ecd0cd 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -117,6 +117,7 @@ int sync_page_range(struct inode *inode, struct address_space *mapping, int sync_page_range_nolock(struct inode *inode, struct address_space *mapping, loff_t pos, loff_t count); void set_page_dirty_balance(struct page *page); +void writeback_set_ratelimit(void); /* pdflush.c */ extern int nr_pdflush_threads; /* Global so it can be exported to sysctl diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 9576ed920c0a..2053bb165a21 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -192,6 +193,7 @@ int online_pages(unsigned long pfn, unsigned long nr_pages) if (need_zonelists_rebuild) build_all_zonelists(); vm_total_pages = nr_free_pagecache_pages(); + writeback_set_ratelimit(); return 0; } diff --git a/mm/page-writeback.c b/mm/page-writeback.c index efd2705e4986..488b7088557c 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -501,7 +501,7 @@ void laptop_sync_completion(void) * will write six megabyte chunks, max. */ -static void set_ratelimit(void) +void writeback_set_ratelimit(void) { ratelimit_pages = vm_total_pages / (num_online_cpus() * 32); if (ratelimit_pages < 16) @@ -513,7 +513,7 @@ static void set_ratelimit(void) static int __cpuinit ratelimit_handler(struct notifier_block *self, unsigned long u, void *v) { - set_ratelimit(); + writeback_set_ratelimit(); return 0; } @@ -546,7 +546,7 @@ void __init page_writeback_init(void) vm_dirty_ratio = 1; } mod_timer(&wb_timer, jiffies + dirty_writeback_interval); - set_ratelimit(); + writeback_set_ratelimit(); register_cpu_notifier(&ratelimit_nb); } -- cgit v1.2.3 From 04b1db9fd7eea63c9663072feece616ea41b0a79 Mon Sep 17 00:00:00 2001 From: "Ian S. Nelson" Date: Fri, 29 Sep 2006 02:01:31 -0700 Subject: [PATCH] /sys/modules: allow full length section names I've been using systemtap for some debugging and I noticed that it can't probe a lot of modules. Turns out it's kind of silly, the sections section of /sys/module is limited to 32byte filenames and many of the actual sections are a a bit longer than that. [akpm@osdl.org: rewrite to use dymanic allocation] Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- CREDITS | 3 ++- include/linux/module.h | 4 ++-- kernel/module.c | 26 ++++++++++++++++++++------ 3 files changed, 24 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/CREDITS b/CREDITS index 8feb2bb49e35..66e82466dde8 100644 --- a/CREDITS +++ b/CREDITS @@ -2478,7 +2478,8 @@ S: Derbyshire DE4 3RL S: United Kingdom N: Ian S. Nelson -E: ian.nelson@echostar.com +E: nelsonis@earthlink.net +P: 1024D/00D3D983 3EFD 7B86 B888 D7E2 29B6 9E97 576F 1B97 00D3 D983 D: Minor mmap and ide hacks S: 1370 Atlantis Ave. S: Lafayette CO, 80026 diff --git a/include/linux/module.h b/include/linux/module.h index d4486cc2e7fe..2c599175c583 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -232,17 +232,17 @@ enum module_state }; /* Similar stuff for section attributes. */ -#define MODULE_SECT_NAME_LEN 32 struct module_sect_attr { struct module_attribute mattr; - char name[MODULE_SECT_NAME_LEN]; + char *name; unsigned long address; }; struct module_sect_attrs { struct attribute_group grp; + int nsections; struct module_sect_attr attrs[0]; }; diff --git a/kernel/module.c b/kernel/module.c index b7fe6e840963..05625d5dc758 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -933,6 +933,15 @@ static ssize_t module_sect_show(struct module_attribute *mattr, return sprintf(buf, "0x%lx\n", sattr->address); } +static void free_sect_attrs(struct module_sect_attrs *sect_attrs) +{ + int section; + + for (section = 0; section < sect_attrs->nsections; section++) + kfree(sect_attrs->attrs[section].name); + kfree(sect_attrs); +} + static void add_sect_attrs(struct module *mod, unsigned int nsect, char *secstrings, Elf_Shdr *sechdrs) { @@ -949,21 +958,26 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, + nloaded * sizeof(sect_attrs->attrs[0]), sizeof(sect_attrs->grp.attrs[0])); size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]); - if (! (sect_attrs = kmalloc(size[0] + size[1], GFP_KERNEL))) + sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL); + if (sect_attrs == NULL) return; /* Setup section attributes. */ sect_attrs->grp.name = "sections"; sect_attrs->grp.attrs = (void *)sect_attrs + size[0]; + sect_attrs->nsections = 0; sattr = §_attrs->attrs[0]; gattr = §_attrs->grp.attrs[0]; for (i = 0; i < nsect; i++) { if (! (sechdrs[i].sh_flags & SHF_ALLOC)) continue; sattr->address = sechdrs[i].sh_addr; - strlcpy(sattr->name, secstrings + sechdrs[i].sh_name, - MODULE_SECT_NAME_LEN); + sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, + GFP_KERNEL); + if (sattr->name == NULL) + goto out; + sect_attrs->nsections++; sattr->mattr.show = module_sect_show; sattr->mattr.store = NULL; sattr->mattr.attr.name = sattr->name; @@ -979,7 +993,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, mod->sect_attrs = sect_attrs; return; out: - kfree(sect_attrs); + free_sect_attrs(sect_attrs); } static void remove_sect_attrs(struct module *mod) @@ -989,13 +1003,13 @@ static void remove_sect_attrs(struct module *mod) &mod->sect_attrs->grp); /* We are positive that no one is using any sect attrs * at this point. Deallocate immediately. */ - kfree(mod->sect_attrs); + free_sect_attrs(mod->sect_attrs); mod->sect_attrs = NULL; } } - #else + static inline void add_sect_attrs(struct module *mod, unsigned int nsect, char *sectstrings, Elf_Shdr *sechdrs) { -- cgit v1.2.3 From f0c8bd164e1a0585d7e46896553136b4f488bd19 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 29 Sep 2006 02:01:34 -0700 Subject: [PATCH] Generic infrastructure for acls The patches solve the following problem: We want to grant access to devices based on who is logged in from where, etc. This includes switching back and forth between multiple user sessions, etc. Using ACLs to define device access for logged-in users gives us all the flexibility we need in order to fully solve the problem. Device special files nowadays usually live on tmpfs, hence tmpfs ACLs. Different distros have come up with solutions that solve the problem to different degrees: SUSE uses a resource manager which tracks login sessions and sets ACLs on device inodes as appropriate. RedHat uses pam_console, which changes the primary file ownership to the logged-in user. Others use a set of groups that users must be in in order to be granted the appropriate accesses. The freedesktop.org project plans to implement a combination of a console-tracker and a HAL-device-list based solution to grant access to devices to users, and more distros will likely follow this approach. These patches have first been posted here on 2 February 2005, and again on 8 January 2006. We have been shipping them in SLES9 and SLES10 with no problems reported. The previous submission is archived here: http://lkml.org/lkml/2006/1/8/229 http://lkml.org/lkml/2006/1/8/230 http://lkml.org/lkml/2006/1/8/231 This patch: Add some infrastructure for access control lists on in-memory filesystems such as tmpfs. Signed-off-by: Andreas Gruenbacher Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/Kconfig | 4 + fs/Makefile | 1 + fs/generic_acl.c | 197 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/generic_acl.h | 36 ++++++++ 4 files changed, 238 insertions(+) create mode 100644 fs/generic_acl.c create mode 100644 include/linux/generic_acl.h (limited to 'include/linux') diff --git a/fs/Kconfig b/fs/Kconfig index d311198bba43..deb9eec9f6ee 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1940,6 +1940,10 @@ config 9P_FS If unsure, say N. +config GENERIC_ACL + bool + select FS_POSIX_ACL + endmenu menu "Partition Types" diff --git a/fs/Makefile b/fs/Makefile index 89135428a539..46b8cfe497b2 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o obj-$(CONFIG_FS_MBCACHE) += mbcache.o obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o obj-$(CONFIG_NFS_COMMON) += nfs_common/ +obj-$(CONFIG_GENERIC_ACL) += generic_acl.o obj-$(CONFIG_QUOTA) += dquot.o obj-$(CONFIG_QFMT_V1) += quota_v1.o diff --git a/fs/generic_acl.c b/fs/generic_acl.c new file mode 100644 index 000000000000..9ccb78947171 --- /dev/null +++ b/fs/generic_acl.c @@ -0,0 +1,197 @@ +/* + * fs/generic_acl.c + * + * (C) 2005 Andreas Gruenbacher + * + * This file is released under the GPL. + */ + +#include +#include +#include + +/** + * generic_acl_list - Generic xattr_handler->list() operation + * @ops: Filesystem specific getacl and setacl callbacks + */ +size_t +generic_acl_list(struct inode *inode, struct generic_acl_operations *ops, + int type, char *list, size_t list_size) +{ + struct posix_acl *acl; + const char *name; + size_t size; + + acl = ops->getacl(inode, type); + if (!acl) + return 0; + posix_acl_release(acl); + + switch(type) { + case ACL_TYPE_ACCESS: + name = POSIX_ACL_XATTR_ACCESS; + break; + + case ACL_TYPE_DEFAULT: + name = POSIX_ACL_XATTR_DEFAULT; + break; + + default: + return 0; + } + size = strlen(name) + 1; + if (list && size <= list_size) + memcpy(list, name, size); + return size; +} + +/** + * generic_acl_get - Generic xattr_handler->get() operation + * @ops: Filesystem specific getacl and setacl callbacks + */ +int +generic_acl_get(struct inode *inode, struct generic_acl_operations *ops, + int type, void *buffer, size_t size) +{ + struct posix_acl *acl; + int error; + + acl = ops->getacl(inode, type); + if (!acl) + return -ENODATA; + error = posix_acl_to_xattr(acl, buffer, size); + posix_acl_release(acl); + + return error; +} + +/** + * generic_acl_set - Generic xattr_handler->set() operation + * @ops: Filesystem specific getacl and setacl callbacks + */ +int +generic_acl_set(struct inode *inode, struct generic_acl_operations *ops, + int type, const void *value, size_t size) +{ + struct posix_acl *acl = NULL; + int error; + + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) + return -EPERM; + if (value) { + acl = posix_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + } + if (acl) { + mode_t mode; + + error = posix_acl_valid(acl); + if (error) + goto failed; + switch(type) { + case ACL_TYPE_ACCESS: + mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); + if (error < 0) + goto failed; + inode->i_mode = mode; + if (error == 0) { + posix_acl_release(acl); + acl = NULL; + } + break; + + case ACL_TYPE_DEFAULT: + if (!S_ISDIR(inode->i_mode)) { + error = -EINVAL; + goto failed; + } + break; + } + } + ops->setacl(inode, type, acl); + error = 0; +failed: + posix_acl_release(acl); + return error; +} + +/** + * generic_acl_init - Take care of acl inheritance at @inode create time + * @ops: Filesystem specific getacl and setacl callbacks + * + * Files created inside a directory with a default ACL inherit the + * directory's default ACL. + */ +int +generic_acl_init(struct inode *inode, struct inode *dir, + struct generic_acl_operations *ops) +{ + struct posix_acl *acl = NULL; + mode_t mode = inode->i_mode; + int error; + + inode->i_mode = mode & ~current->fs->umask; + if (!S_ISLNK(inode->i_mode)) + acl = ops->getacl(dir, ACL_TYPE_DEFAULT); + if (acl) { + struct posix_acl *clone; + + if (S_ISDIR(inode->i_mode)) { + clone = posix_acl_clone(acl, GFP_KERNEL); + error = -ENOMEM; + if (!clone) + goto cleanup; + ops->setacl(inode, ACL_TYPE_DEFAULT, clone); + posix_acl_release(clone); + } + clone = posix_acl_clone(acl, GFP_KERNEL); + error = -ENOMEM; + if (!clone) + goto cleanup; + error = posix_acl_create_masq(clone, &mode); + if (error >= 0) { + inode->i_mode = mode; + if (error > 0) + ops->setacl(inode, ACL_TYPE_ACCESS, clone); + } + posix_acl_release(clone); + } + error = 0; + +cleanup: + posix_acl_release(acl); + return error; +} + +/** + * generic_acl_chmod - change the access acl of @inode upon chmod() + * @ops: FIlesystem specific getacl and setacl callbacks + * + * A chmod also changes the permissions of the owner, group/mask, and + * other ACL entries. + */ +int +generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops) +{ + struct posix_acl *acl, *clone; + int error = 0; + + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + acl = ops->getacl(inode, ACL_TYPE_ACCESS); + if (acl) { + clone = posix_acl_clone(acl, GFP_KERNEL); + posix_acl_release(acl); + if (!clone) + return -ENOMEM; + error = posix_acl_chmod_masq(clone, inode->i_mode); + if (!error) + ops->setacl(inode, ACL_TYPE_ACCESS, clone); + posix_acl_release(clone); + } + return error; +} diff --git a/include/linux/generic_acl.h b/include/linux/generic_acl.h new file mode 100644 index 000000000000..80764f40be75 --- /dev/null +++ b/include/linux/generic_acl.h @@ -0,0 +1,36 @@ +/* + * fs/generic_acl.c + * + * (C) 2005 Andreas Gruenbacher + * + * This file is released under the GPL. + */ + +#ifndef GENERIC_ACL_H +#define GENERIC_ACL_H + +#include +#include + +/** + * struct generic_acl_operations - filesystem operations + * + * Filesystems must make these operations available to the generic + * operations. + */ +struct generic_acl_operations { + struct posix_acl *(*getacl)(struct inode *, int); + void (*setacl)(struct inode *, int, struct posix_acl *); +}; + +size_t generic_acl_list(struct inode *, struct generic_acl_operations *, int, + char *, size_t); +int generic_acl_get(struct inode *, struct generic_acl_operations *, int, + void *, size_t); +int generic_acl_set(struct inode *, struct generic_acl_operations *, int, + const void *, size_t); +int generic_acl_init(struct inode *, struct inode *, + struct generic_acl_operations *); +int generic_acl_chmod(struct inode *, struct generic_acl_operations *); + +#endif -- cgit v1.2.3 From 39f0247d3823e4e0bf8f6838a10362864b1e1053 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 29 Sep 2006 02:01:35 -0700 Subject: [PATCH] Access Control Lists for tmpfs Add access control lists for tmpfs. Signed-off-by: Andreas Gruenbacher Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/Kconfig | 13 ++++ include/linux/shmem_fs.h | 24 ++++++ mm/Makefile | 1 + mm/shmem.c | 99 +++++++++++++++++++++++- mm/shmem_acl.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 332 insertions(+), 2 deletions(-) create mode 100644 mm/shmem_acl.c (limited to 'include/linux') diff --git a/fs/Kconfig b/fs/Kconfig index deb9eec9f6ee..4fd9efac29ab 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -881,6 +881,19 @@ config TMPFS See for details. +config TMPFS_POSIX_ACL + bool "Tmpfs POSIX Access Control Lists" + depends on TMPFS + select GENERIC_ACL + help + POSIX Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the POSIX ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N. + config HUGETLBFS bool "HugeTLB file system support" depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index c057f0b32318..f3c51899117f 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -19,6 +19,10 @@ struct shmem_inode_info { swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */ struct list_head swaplist; /* chain of maybes on swap */ struct inode vfs_inode; +#ifdef CONFIG_TMPFS_POSIX_ACL + struct posix_acl *i_acl; + struct posix_acl *i_default_acl; +#endif }; struct shmem_sb_info { @@ -36,4 +40,24 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode) return container_of(inode, struct shmem_inode_info, vfs_inode); } +#ifdef CONFIG_TMPFS_POSIX_ACL +int shmem_permission(struct inode *, int, struct nameidata *); +int shmem_acl_init(struct inode *, struct inode *); +void shmem_acl_destroy_inode(struct inode *); + +extern struct xattr_handler shmem_xattr_acl_access_handler; +extern struct xattr_handler shmem_xattr_acl_default_handler; + +extern struct generic_acl_operations shmem_acl_ops; + +#else +static inline int shmem_acl_init(struct inode *inode, struct inode *dir) +{ + return 0; +} +static inline void shmem_acl_destroy_inode(struct inode *inode) +{ +} +#endif /* CONFIG_TMPFS_POSIX_ACL */ + #endif diff --git a/mm/Makefile b/mm/Makefile index 60c56c0b5e10..6200c6d6afd2 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_HUGETLBFS) += hugetlb.o obj-$(CONFIG_NUMA) += mempolicy.o obj-$(CONFIG_SPARSEMEM) += sparse.o obj-$(CONFIG_SHMEM) += shmem.o +obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o obj-$(CONFIG_SLOB) += slob.o obj-$(CONFIG_SLAB) += slab.o diff --git a/mm/shmem.c b/mm/shmem.c index eda907c3a86a..b96de69f236b 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -177,6 +179,7 @@ static const struct address_space_operations shmem_aops; static struct file_operations shmem_file_operations; static struct inode_operations shmem_inode_operations; static struct inode_operations shmem_dir_inode_operations; +static struct inode_operations shmem_special_inode_operations; static struct vm_operations_struct shmem_vm_ops; static struct backing_dev_info shmem_backing_dev_info __read_mostly = { @@ -637,7 +640,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) struct page *page = NULL; int error; - if (attr->ia_valid & ATTR_SIZE) { + if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { if (attr->ia_size < inode->i_size) { /* * If truncating down to a partial page, then @@ -670,6 +673,10 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) error = inode_change_ok(inode, attr); if (!error) error = inode_setattr(inode, attr); +#ifdef CONFIG_TMPFS_POSIX_ACL + if (!error && (attr->ia_valid & ATTR_MODE)) + error = generic_acl_chmod(inode, &shmem_acl_ops); +#endif if (page) page_cache_release(page); return error; @@ -1362,6 +1369,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) switch (mode & S_IFMT) { default: + inode->i_op = &shmem_special_inode_operations; init_special_inode(inode, mode, dev); break; case S_IFREG: @@ -1682,7 +1690,11 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) iput(inode); return error; } - error = 0; + } + error = shmem_acl_init(inode, dir); + if (error) { + iput(inode); + return error; } if (dir->i_mode & S_ISGID) { inode->i_gid = dir->i_gid; @@ -1897,6 +1909,53 @@ static struct inode_operations shmem_symlink_inode_operations = { .put_link = shmem_put_link, }; +#ifdef CONFIG_TMPFS_POSIX_ACL +/** + * Superblocks without xattr inode operations will get security.* xattr + * support from the VFS "for free". As soon as we have any other xattrs + * like ACLs, we also need to implement the security.* handlers at + * filesystem level, though. + */ + +static size_t shmem_xattr_security_list(struct inode *inode, char *list, + size_t list_len, const char *name, + size_t name_len) +{ + return security_inode_listsecurity(inode, list, list_len); +} + +static int shmem_xattr_security_get(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return security_inode_getsecurity(inode, name, buffer, size, + -EOPNOTSUPP); +} + +static int shmem_xattr_security_set(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return security_inode_setsecurity(inode, name, value, size, flags); +} + +struct xattr_handler shmem_xattr_security_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .list = shmem_xattr_security_list, + .get = shmem_xattr_security_get, + .set = shmem_xattr_security_set, +}; + +static struct xattr_handler *shmem_xattr_handlers[] = { + &shmem_xattr_acl_access_handler, + &shmem_xattr_acl_default_handler, + &shmem_xattr_security_handler, + NULL +}; +#endif + static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes, int *policy, nodemask_t *policy_nodes) @@ -2094,6 +2153,10 @@ static int shmem_fill_super(struct super_block *sb, sb->s_magic = TMPFS_MAGIC; sb->s_op = &shmem_ops; sb->s_time_gran = 1; +#ifdef CONFIG_TMPFS_POSIX_ACL + sb->s_xattr = shmem_xattr_handlers; + sb->s_flags |= MS_POSIXACL; +#endif inode = shmem_get_inode(sb, S_IFDIR | mode, 0); if (!inode) @@ -2130,6 +2193,7 @@ static void shmem_destroy_inode(struct inode *inode) /* only struct inode is valid if it's an inline symlink */ mpol_free_shared_policy(&SHMEM_I(inode)->policy); } + shmem_acl_destroy_inode(inode); kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); } @@ -2141,6 +2205,10 @@ static void init_once(void *foo, struct kmem_cache *cachep, if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { inode_init_once(&p->vfs_inode); +#ifdef CONFIG_TMPFS_POSIX_ACL + p->i_acl = NULL; + p->i_default_acl = NULL; +#endif } } @@ -2184,6 +2252,14 @@ static struct inode_operations shmem_inode_operations = { .truncate = shmem_truncate, .setattr = shmem_notify_change, .truncate_range = shmem_truncate_range, +#ifdef CONFIG_TMPFS_POSIX_ACL + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = generic_listxattr, + .removexattr = generic_removexattr, + .permission = shmem_permission, +#endif + }; static struct inode_operations shmem_dir_inode_operations = { @@ -2198,6 +2274,25 @@ static struct inode_operations shmem_dir_inode_operations = { .mknod = shmem_mknod, .rename = shmem_rename, #endif +#ifdef CONFIG_TMPFS_POSIX_ACL + .setattr = shmem_notify_change, + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = generic_listxattr, + .removexattr = generic_removexattr, + .permission = shmem_permission, +#endif +}; + +static struct inode_operations shmem_special_inode_operations = { +#ifdef CONFIG_TMPFS_POSIX_ACL + .setattr = shmem_notify_change, + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = generic_listxattr, + .removexattr = generic_removexattr, + .permission = shmem_permission, +#endif }; static struct super_operations shmem_ops = { diff --git a/mm/shmem_acl.c b/mm/shmem_acl.c new file mode 100644 index 000000000000..c946bf468718 --- /dev/null +++ b/mm/shmem_acl.c @@ -0,0 +1,197 @@ +/* + * mm/shmem_acl.c + * + * (C) 2005 Andreas Gruenbacher + * + * This file is released under the GPL. + */ + +#include +#include +#include +#include + +/** + * shmem_get_acl - generic_acl_operations->getacl() operation + */ +static struct posix_acl * +shmem_get_acl(struct inode *inode, int type) +{ + struct posix_acl *acl = NULL; + + spin_lock(&inode->i_lock); + switch(type) { + case ACL_TYPE_ACCESS: + acl = posix_acl_dup(SHMEM_I(inode)->i_acl); + break; + + case ACL_TYPE_DEFAULT: + acl = posix_acl_dup(SHMEM_I(inode)->i_default_acl); + break; + } + spin_unlock(&inode->i_lock); + + return acl; +} + +/** + * shmem_get_acl - generic_acl_operations->setacl() operation + */ +static void +shmem_set_acl(struct inode *inode, int type, struct posix_acl *acl) +{ + struct posix_acl *free = NULL; + + spin_lock(&inode->i_lock); + switch(type) { + case ACL_TYPE_ACCESS: + free = SHMEM_I(inode)->i_acl; + SHMEM_I(inode)->i_acl = posix_acl_dup(acl); + break; + + case ACL_TYPE_DEFAULT: + free = SHMEM_I(inode)->i_default_acl; + SHMEM_I(inode)->i_default_acl = posix_acl_dup(acl); + break; + } + spin_unlock(&inode->i_lock); + posix_acl_release(free); +} + +struct generic_acl_operations shmem_acl_ops = { + .getacl = shmem_get_acl, + .setacl = shmem_set_acl, +}; + +/** + * shmem_list_acl_access, shmem_get_acl_access, shmem_set_acl_access, + * shmem_xattr_acl_access_handler - plumbing code to implement the + * system.posix_acl_access xattr using the generic acl functions. + */ + +static size_t +shmem_list_acl_access(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) +{ + return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, + list, list_size); +} + +static int +shmem_get_acl_access(struct inode *inode, const char *name, void *buffer, + size_t size) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, buffer, + size); +} + +static int +shmem_set_acl_access(struct inode *inode, const char *name, const void *value, + size_t size, int flags) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, value, + size); +} + +struct xattr_handler shmem_xattr_acl_access_handler = { + .prefix = POSIX_ACL_XATTR_ACCESS, + .list = shmem_list_acl_access, + .get = shmem_get_acl_access, + .set = shmem_set_acl_access, +}; + +/** + * shmem_list_acl_default, shmem_get_acl_default, shmem_set_acl_default, + * shmem_xattr_acl_default_handler - plumbing code to implement the + * system.posix_acl_default xattr using the generic acl functions. + */ + +static size_t +shmem_list_acl_default(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) +{ + return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, + list, list_size); +} + +static int +shmem_get_acl_default(struct inode *inode, const char *name, void *buffer, + size_t size) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, buffer, + size); +} + +static int +shmem_set_acl_default(struct inode *inode, const char *name, const void *value, + size_t size, int flags) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, value, + size); +} + +struct xattr_handler shmem_xattr_acl_default_handler = { + .prefix = POSIX_ACL_XATTR_DEFAULT, + .list = shmem_list_acl_default, + .get = shmem_get_acl_default, + .set = shmem_set_acl_default, +}; + +/** + * shmem_acl_init - Inizialize the acl(s) of a new inode + */ +int +shmem_acl_init(struct inode *inode, struct inode *dir) +{ + return generic_acl_init(inode, dir, &shmem_acl_ops); +} + +/** + * shmem_acl_destroy_inode - destroy acls hanging off the in-memory inode + * + * This is done before destroying the actual inode. + */ + +void +shmem_acl_destroy_inode(struct inode *inode) +{ + if (SHMEM_I(inode)->i_acl) + posix_acl_release(SHMEM_I(inode)->i_acl); + SHMEM_I(inode)->i_acl = NULL; + if (SHMEM_I(inode)->i_default_acl) + posix_acl_release(SHMEM_I(inode)->i_default_acl); + SHMEM_I(inode)->i_default_acl = NULL; +} + +/** + * shmem_check_acl - check_acl() callback for generic_permission() + */ +static int +shmem_check_acl(struct inode *inode, int mask) +{ + struct posix_acl *acl = shmem_get_acl(inode, ACL_TYPE_ACCESS); + + if (acl) { + int error = posix_acl_permission(inode, acl, mask); + posix_acl_release(acl); + return error; + } + return -EAGAIN; +} + +/** + * shmem_permission - permission() inode operation + */ +int +shmem_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + return generic_permission(inode, mask, shmem_check_acl); +} -- cgit v1.2.3 From 34596dc9e59d7bece16fe5aba08116b49465da26 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 30 Sep 2006 01:47:55 +0200 Subject: [PATCH] Define vsyscall cache as blob to make clearer that user space shouldn't use it Signed-off-by: Andi Kleen --- arch/x86_64/kernel/vsyscall.c | 8 ++++---- include/linux/getcpu.h | 12 +++++++----- kernel/sys.c | 8 ++++---- 3 files changed, 15 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index ac48c3857ddb..07c086382059 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -155,8 +155,8 @@ vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) We do this here because otherwise user space would do it on its own in a likely inferior way (no access to jiffies). If you don't like it pass NULL. */ - if (tcache && tcache->t0 == (j = __jiffies)) { - p = tcache->t1; + if (tcache && tcache->blob[0] == (j = __jiffies)) { + p = tcache->blob[1]; } else if (__vgetcpu_mode == VGETCPU_RDTSCP) { /* Load per CPU data from RDTSCP */ rdtscp(dummy, dummy, p); @@ -165,8 +165,8 @@ vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG)); } if (tcache) { - tcache->t0 = j; - tcache->t1 = p; + tcache->blob[0] = j; + tcache->blob[1] = p; } if (cpu) *cpu = p & 0xfff; diff --git a/include/linux/getcpu.h b/include/linux/getcpu.h index 031ed3780e45..c7372d7a97be 100644 --- a/include/linux/getcpu.h +++ b/include/linux/getcpu.h @@ -1,16 +1,18 @@ #ifndef _LINUX_GETCPU_H #define _LINUX_GETCPU_H 1 -/* Cache for getcpu() to speed it up. Results might be upto a jiffie +/* Cache for getcpu() to speed it up. Results might be a short time out of date, but will be faster. + User programs should not refer to the contents of this structure. - It is only a cache for vgetcpu(). It might change in future kernels. + I repeat they should not refer to it. If they do they will break + in future kernels. + + It is only a private cache for vgetcpu(). It will change in future kernels. The user program must store this information per thread (__thread) If you want 100% accurate information pass NULL instead. */ struct getcpu_cache { - unsigned long t0; - unsigned long t1; - unsigned long res[4]; + unsigned long blob[128 / sizeof(long)]; }; #endif diff --git a/kernel/sys.c b/kernel/sys.c index 8647061c084a..b88806c66244 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2083,12 +2083,12 @@ asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep, * padding */ unsigned long t0, t1; - get_user(t0, &cache->t0); - get_user(t1, &cache->t1); + get_user(t0, &cache->blob[0]); + get_user(t1, &cache->blob[1]); t0++; t1++; - put_user(t0, &cache->t0); - put_user(t1, &cache->t1); + put_user(t0, &cache->blob[0]); + put_user(t1, &cache->blob[1]); } return err ? -EFAULT : 0; } -- cgit v1.2.3 From 95d4e6be25a68cd9fbe8c0d356b585504d8db1c7 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 29 Sep 2006 17:05:05 -0700 Subject: [NetLabel]: audit fixups due to delayed feedback Fix some issues Steve Grubb had with the way NetLabel was using the audit subsystem. This should make NetLabel more consistent with other kernel generated audit messages specifying configuration changes. Signed-off-by: Paul Moore Acked-by: Steve Grubb Signed-off-by: David S. Miller --- include/linux/audit.h | 11 +++-- include/net/cipso_ipv4.h | 4 +- include/net/netlabel.h | 8 +++- net/ipv4/cipso_ipv4.c | 4 +- net/netlabel/netlabel_cipso_v4.c | 48 +++++++++++++--------- net/netlabel/netlabel_domainhash.c | 82 ++++++++++++++++++++------------------ net/netlabel/netlabel_domainhash.h | 8 ++-- net/netlabel/netlabel_mgmt.c | 27 +++++++++---- net/netlabel/netlabel_unlabeled.c | 34 +++++++++++----- net/netlabel/netlabel_user.c | 66 ++++-------------------------- net/netlabel/netlabel_user.h | 16 +++++++- 11 files changed, 157 insertions(+), 151 deletions(-) (limited to 'include/linux') diff --git a/include/linux/audit.h b/include/linux/audit.h index 42719d07612a..c3aa09751814 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -95,12 +95,11 @@ #define AUDIT_MAC_POLICY_LOAD 1403 /* Policy file load */ #define AUDIT_MAC_STATUS 1404 /* Changed enforcing,permissive,off */ #define AUDIT_MAC_CONFIG_CHANGE 1405 /* Changes to booleans */ -#define AUDIT_MAC_UNLBL_ACCEPT 1406 /* NetLabel: allow unlabeled traffic */ -#define AUDIT_MAC_UNLBL_DENY 1407 /* NetLabel: deny unlabeled traffic */ -#define AUDIT_MAC_CIPSOV4_ADD 1408 /* NetLabel: add CIPSOv4 DOI entry */ -#define AUDIT_MAC_CIPSOV4_DEL 1409 /* NetLabel: del CIPSOv4 DOI entry */ -#define AUDIT_MAC_MAP_ADD 1410 /* NetLabel: add LSM domain mapping */ -#define AUDIT_MAC_MAP_DEL 1411 /* NetLabel: del LSM domain mapping */ +#define AUDIT_MAC_UNLBL_ALLOW 1406 /* NetLabel: allow unlabeled traffic */ +#define AUDIT_MAC_CIPSOV4_ADD 1407 /* NetLabel: add CIPSOv4 DOI entry */ +#define AUDIT_MAC_CIPSOV4_DEL 1408 /* NetLabel: del CIPSOv4 DOI entry */ +#define AUDIT_MAC_MAP_ADD 1409 /* NetLabel: add LSM domain mapping */ +#define AUDIT_MAC_MAP_DEL 1410 /* NetLabel: del LSM domain mapping */ #define AUDIT_FIRST_KERN_ANOM_MSG 1700 #define AUDIT_LAST_KERN_ANOM_MSG 1799 diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index 5d6ae1b2b196..718b4d9c891f 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h @@ -129,7 +129,7 @@ extern int cipso_v4_rbm_strictvalid; #ifdef CONFIG_NETLABEL int cipso_v4_doi_add(struct cipso_v4_doi *doi_def); int cipso_v4_doi_remove(u32 doi, - u32 audit_secid, + struct netlbl_audit *audit_info, void (*callback) (struct rcu_head * head)); struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); int cipso_v4_doi_walk(u32 *skip_cnt, @@ -145,7 +145,7 @@ static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) } static inline int cipso_v4_doi_remove(u32 doi, - u32 audit_secid, + struct netlbl_audit *audit_info, void (*callback) (struct rcu_head * head)) { return 0; diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 190bfdbbdba6..c63a58058e21 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h @@ -92,11 +92,17 @@ * */ +/* NetLabel audit information */ +struct netlbl_audit { + u32 secid; + uid_t loginuid; +}; + /* Domain mapping definition struct */ struct netlbl_dom_map; /* Domain mapping operations */ -int netlbl_domhsh_remove(const char *domain, u32 audit_secid); +int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); /* LSM security attributes */ struct netlbl_lsm_cache { diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index c4e469ff842d..a8e2e879a647 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -485,7 +485,7 @@ doi_add_failure_rlock: * */ int cipso_v4_doi_remove(u32 doi, - u32 audit_secid, + struct netlbl_audit *audit_info, void (*callback) (struct rcu_head * head)) { struct cipso_v4_doi *doi_def; @@ -506,7 +506,7 @@ int cipso_v4_doi_remove(u32 doi, list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list) if (dom_iter->valid) netlbl_domhsh_remove(dom_iter->domain, - audit_secid); + audit_info); cipso_v4_cache_invalidate(); rcu_read_unlock(); diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index 09986ca962a6..a6ce1d6d5c59 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -384,11 +384,15 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) u32 doi; const char *type_str = "(unknown)"; struct audit_buffer *audit_buf; + struct netlbl_audit audit_info; if (!info->attrs[NLBL_CIPSOV4_A_DOI] || !info->attrs[NLBL_CIPSOV4_A_MTYPE]) return -EINVAL; + doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); + netlbl_netlink_auditinfo(skb, &audit_info); + type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); switch (type) { case CIPSO_V4_MAP_STD: @@ -401,13 +405,14 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) break; } - if (ret_val == 0) { - doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); - audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, - NETLINK_CB(skb).sid); - audit_log_format(audit_buf, " doi=%u type=%s", doi, type_str); - audit_log_end(audit_buf); - } + audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, + &audit_info); + audit_log_format(audit_buf, + " cipso_doi=%u cipso_type=%s res=%u", + doi, + type_str, + ret_val == 0 ? 1 : 0); + audit_log_end(audit_buf); return ret_val; } @@ -668,20 +673,25 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) int ret_val = -EINVAL; u32 doi = 0; struct audit_buffer *audit_buf; + struct netlbl_audit audit_info; - if (info->attrs[NLBL_CIPSOV4_A_DOI]) { - doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); - ret_val = cipso_v4_doi_remove(doi, - NETLINK_CB(skb).sid, - netlbl_cipsov4_doi_free); - } + if (!info->attrs[NLBL_CIPSOV4_A_DOI]) + return -EINVAL; - if (ret_val == 0) { - audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, - NETLINK_CB(skb).sid); - audit_log_format(audit_buf, " doi=%u", doi); - audit_log_end(audit_buf); - } + doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); + netlbl_netlink_auditinfo(skb, &audit_info); + + ret_val = cipso_v4_doi_remove(doi, + &audit_info, + netlbl_cipsov4_doi_free); + + audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, + &audit_info); + audit_log_format(audit_buf, + " cipso_doi=%u res=%u", + doi, + ret_val == 0 ? 1 : 0); + audit_log_end(audit_buf); return ret_val; } diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index d64e2ae3b129..af4371d3b459 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c @@ -188,7 +188,7 @@ int netlbl_domhsh_init(u32 size) /** * netlbl_domhsh_add - Adds a entry to the domain hash table * @entry: the entry to add - * @audit_secid: the LSM secid to use in the audit message + * @audit_info: NetLabel audit information * * Description: * Adds a new entry to the domain hash table and handles any updates to the @@ -196,7 +196,8 @@ int netlbl_domhsh_init(u32 size) * negative on failure. * */ -int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid) +int netlbl_domhsh_add(struct netlbl_dom_map *entry, + struct netlbl_audit *audit_info) { int ret_val; u32 bkt; @@ -241,26 +242,26 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid) spin_unlock(&netlbl_domhsh_def_lock); } else ret_val = -EINVAL; - if (ret_val == 0) { - if (entry->domain != NULL) - audit_domain = entry->domain; - else - audit_domain = "(default)"; - audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, - audit_secid); - audit_log_format(audit_buf, " domain=%s", audit_domain); - switch (entry->type) { - case NETLBL_NLTYPE_UNLABELED: - audit_log_format(audit_buf, " protocol=unlbl"); - break; - case NETLBL_NLTYPE_CIPSOV4: - audit_log_format(audit_buf, - " protocol=cipsov4 doi=%u", - entry->type_def.cipsov4->doi); - break; - } - audit_log_end(audit_buf); + + if (entry->domain != NULL) + audit_domain = entry->domain; + else + audit_domain = "(default)"; + audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); + audit_log_format(audit_buf, " nlbl_domain=%s", audit_domain); + switch (entry->type) { + case NETLBL_NLTYPE_UNLABELED: + audit_log_format(audit_buf, " nlbl_protocol=unlbl"); + break; + case NETLBL_NLTYPE_CIPSOV4: + audit_log_format(audit_buf, + " nlbl_protocol=cipsov4 cipso_doi=%u", + entry->type_def.cipsov4->doi); + break; } + audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0); + audit_log_end(audit_buf); + rcu_read_unlock(); if (ret_val != 0) { @@ -279,7 +280,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid) /** * netlbl_domhsh_add_default - Adds the default entry to the domain hash table * @entry: the entry to add - * @audit_secid: the LSM secid to use in the audit message + * @audit_info: NetLabel audit information * * Description: * Adds a new default entry to the domain hash table and handles any updates @@ -287,15 +288,16 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid) * negative on failure. * */ -int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, u32 audit_secid) +int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, + struct netlbl_audit *audit_info) { - return netlbl_domhsh_add(entry, audit_secid); + return netlbl_domhsh_add(entry, audit_info); } /** * netlbl_domhsh_remove - Removes an entry from the domain hash table * @domain: the domain to remove - * @audit_secid: the LSM secid to use in the audit message + * @audit_info: NetLabel audit information * * Description: * Removes an entry from the domain hash table and handles any updates to the @@ -303,7 +305,7 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, u32 audit_secid) * negative on failure. * */ -int netlbl_domhsh_remove(const char *domain, u32 audit_secid) +int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) { int ret_val = -ENOENT; struct netlbl_dom_map *entry; @@ -345,18 +347,20 @@ int netlbl_domhsh_remove(const char *domain, u32 audit_secid) ret_val = -ENOENT; spin_unlock(&netlbl_domhsh_def_lock); } - if (ret_val == 0) { - if (entry->domain != NULL) - audit_domain = entry->domain; - else - audit_domain = "(default)"; - audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, - audit_secid); - audit_log_format(audit_buf, " domain=%s", audit_domain); - audit_log_end(audit_buf); + if (entry->domain != NULL) + audit_domain = entry->domain; + else + audit_domain = "(default)"; + audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); + audit_log_format(audit_buf, + " nlbl_domain=%s res=%u", + audit_domain, + ret_val == 0 ? 1 : 0); + audit_log_end(audit_buf); + + if (ret_val == 0) call_rcu(&entry->rcu, netlbl_domhsh_free_entry); - } remove_return: rcu_read_unlock(); @@ -365,7 +369,7 @@ remove_return: /** * netlbl_domhsh_remove_default - Removes the default entry from the table - * @audit_secid: the LSM secid to use in the audit message + * @audit_info: NetLabel audit information * * Description: * Removes/resets the default entry for the domain hash table and handles any @@ -373,9 +377,9 @@ remove_return: * success, non-zero on failure. * */ -int netlbl_domhsh_remove_default(u32 audit_secid) +int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info) { - return netlbl_domhsh_remove(NULL, audit_secid); + return netlbl_domhsh_remove(NULL, audit_info); } /** diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h index d50f13cacdca..3689956c3436 100644 --- a/net/netlabel/netlabel_domainhash.h +++ b/net/netlabel/netlabel_domainhash.h @@ -57,9 +57,11 @@ struct netlbl_dom_map { int netlbl_domhsh_init(u32 size); /* Manipulate the domain hash table */ -int netlbl_domhsh_add(struct netlbl_dom_map *entry, u32 audit_secid); -int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, u32 audit_secid); -int netlbl_domhsh_remove_default(u32 audit_secid); +int netlbl_domhsh_add(struct netlbl_dom_map *entry, + struct netlbl_audit *audit_info); +int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, + struct netlbl_audit *audit_info); +int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); int netlbl_domhsh_walk(u32 *skip_bkt, u32 *skip_chain, diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 0ac314f18ad1..53c9079ad2c3 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -87,11 +87,14 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) struct netlbl_dom_map *entry = NULL; size_t tmp_size; u32 tmp_val; + struct netlbl_audit audit_info; if (!info->attrs[NLBL_MGMT_A_DOMAIN] || !info->attrs[NLBL_MGMT_A_PROTOCOL]) goto add_failure; + netlbl_netlink_auditinfo(skb, &audit_info); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (entry == NULL) { ret_val = -ENOMEM; @@ -108,7 +111,7 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) switch (entry->type) { case NETLBL_NLTYPE_UNLABELED: - ret_val = netlbl_domhsh_add(entry, NETLINK_CB(skb).sid); + ret_val = netlbl_domhsh_add(entry, &audit_info); break; case NETLBL_NLTYPE_CIPSOV4: if (!info->attrs[NLBL_MGMT_A_CV4DOI]) @@ -125,7 +128,7 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) rcu_read_unlock(); goto add_failure; } - ret_val = netlbl_domhsh_add(entry, NETLINK_CB(skb).sid); + ret_val = netlbl_domhsh_add(entry, &audit_info); rcu_read_unlock(); break; default: @@ -156,12 +159,15 @@ add_failure: static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) { char *domain; + struct netlbl_audit audit_info; if (!info->attrs[NLBL_MGMT_A_DOMAIN]) return -EINVAL; + netlbl_netlink_auditinfo(skb, &audit_info); + domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); - return netlbl_domhsh_remove(domain, NETLINK_CB(skb).sid); + return netlbl_domhsh_remove(domain, &audit_info); } /** @@ -264,10 +270,13 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) int ret_val = -EINVAL; struct netlbl_dom_map *entry = NULL; u32 tmp_val; + struct netlbl_audit audit_info; if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) goto adddef_failure; + netlbl_netlink_auditinfo(skb, &audit_info); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (entry == NULL) { ret_val = -ENOMEM; @@ -277,8 +286,7 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) switch (entry->type) { case NETLBL_NLTYPE_UNLABELED: - ret_val = netlbl_domhsh_add_default(entry, - NETLINK_CB(skb).sid); + ret_val = netlbl_domhsh_add_default(entry, &audit_info); break; case NETLBL_NLTYPE_CIPSOV4: if (!info->attrs[NLBL_MGMT_A_CV4DOI]) @@ -295,8 +303,7 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) rcu_read_unlock(); goto adddef_failure; } - ret_val = netlbl_domhsh_add_default(entry, - NETLINK_CB(skb).sid); + ret_val = netlbl_domhsh_add_default(entry, &audit_info); rcu_read_unlock(); break; default: @@ -324,7 +331,11 @@ adddef_failure: */ static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) { - return netlbl_domhsh_remove_default(NETLINK_CB(skb).sid); + struct netlbl_audit audit_info; + + netlbl_netlink_auditinfo(skb, &audit_info); + + return netlbl_domhsh_remove_default(&audit_info); } /** diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index ab36675fee8c..1833ad233b39 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -70,18 +70,25 @@ static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { /** * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag * @value: desired value - * @audit_secid: the LSM secid to use in the audit message + * @audit_info: NetLabel audit information * * Description: * Set the value of the unlabeled accept flag to @value. * */ -static void netlbl_unlabel_acceptflg_set(u8 value, u32 audit_secid) +static void netlbl_unlabel_acceptflg_set(u8 value, + struct netlbl_audit *audit_info) { + struct audit_buffer *audit_buf; + u8 old_val; + + old_val = atomic_read(&netlabel_unlabel_accept_flg); atomic_set(&netlabel_unlabel_accept_flg, value); - netlbl_audit_nomsg((value ? - AUDIT_MAC_UNLBL_ACCEPT : AUDIT_MAC_UNLBL_DENY), - audit_secid); + + audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW, + audit_info); + audit_log_format(audit_buf, " unlbl_accept=%u old=%u", value, old_val); + audit_log_end(audit_buf); } /* @@ -101,12 +108,13 @@ static void netlbl_unlabel_acceptflg_set(u8 value, u32 audit_secid) static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info) { u8 value; + struct netlbl_audit audit_info; if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) { value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]); if (value == 1 || value == 0) { - netlbl_unlabel_acceptflg_set(value, - NETLINK_CB(skb).sid); + netlbl_netlink_auditinfo(skb, &audit_info); + netlbl_unlabel_acceptflg_set(value, &audit_info); return 0; } } @@ -250,19 +258,23 @@ int netlbl_unlabel_defconf(void) { int ret_val; struct netlbl_dom_map *entry; - u32 secid; + struct netlbl_audit audit_info; - security_task_getsecid(current, &secid); + /* Only the kernel is allowed to call this function and the only time + * it is called is at bootup before the audit subsystem is reporting + * messages so don't worry to much about these values. */ + security_task_getsecid(current, &audit_info.secid); + audit_info.loginuid = 0; entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (entry == NULL) return -ENOMEM; entry->type = NETLBL_NLTYPE_UNLABELED; - ret_val = netlbl_domhsh_add_default(entry, secid); + ret_val = netlbl_domhsh_add_default(entry, &audit_info); if (ret_val != 0) return ret_val; - netlbl_unlabel_acceptflg_set(1, secid); + netlbl_unlabel_acceptflg_set(1, &audit_info); return 0; } diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c index c2343af584cb..98a416381e61 100644 --- a/net/netlabel/netlabel_user.c +++ b/net/netlabel/netlabel_user.c @@ -85,7 +85,7 @@ int netlbl_netlink_init(void) /** * netlbl_audit_start_common - Start an audit message * @type: audit message type - * @secid: LSM context ID + * @audit_info: NetLabel audit information * * Description: * Start an audit message using the type specified in @type and fill the audit @@ -93,14 +93,11 @@ int netlbl_netlink_init(void) * a pointer to the audit buffer on success, NULL on failure. * */ -struct audit_buffer *netlbl_audit_start_common(int type, u32 secid) +struct audit_buffer *netlbl_audit_start_common(int type, + struct netlbl_audit *audit_info) { struct audit_context *audit_ctx = current->audit_context; struct audit_buffer *audit_buf; - uid_t audit_loginuid; - const char *audit_tty; - char audit_comm[sizeof(current->comm)]; - struct vm_area_struct *vma; char *secctx; u32 secctx_len; @@ -108,60 +105,13 @@ struct audit_buffer *netlbl_audit_start_common(int type, u32 secid) if (audit_buf == NULL) return NULL; - audit_loginuid = audit_get_loginuid(audit_ctx); - if (current->signal && - current->signal->tty && - current->signal->tty->name) - audit_tty = current->signal->tty->name; - else - audit_tty = "(none)"; - get_task_comm(audit_comm, current); + audit_log_format(audit_buf, "netlabel: auid=%u", audit_info->loginuid); - audit_log_format(audit_buf, - "netlabel: auid=%u uid=%u tty=%s pid=%d", - audit_loginuid, - current->uid, - audit_tty, - current->pid); - audit_log_format(audit_buf, " comm="); - audit_log_untrustedstring(audit_buf, audit_comm); - if (current->mm) { - down_read(¤t->mm->mmap_sem); - vma = current->mm->mmap; - while (vma) { - if ((vma->vm_flags & VM_EXECUTABLE) && - vma->vm_file) { - audit_log_d_path(audit_buf, - " exe=", - vma->vm_file->f_dentry, - vma->vm_file->f_vfsmnt); - break; - } - vma = vma->vm_next; - } - up_read(¤t->mm->mmap_sem); - } - - if (secid != 0 && - security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) + if (audit_info->secid != 0 && + security_secid_to_secctx(audit_info->secid, + &secctx, + &secctx_len) == 0) audit_log_format(audit_buf, " subj=%s", secctx); return audit_buf; } - -/** - * netlbl_audit_nomsg - Send an audit message without additional text - * @type: audit message type - * @secid: LSM context ID - * - * Description: - * Send an audit message with only the common NetLabel audit fields. - * - */ -void netlbl_audit_nomsg(int type, u32 secid) -{ - struct audit_buffer *audit_buf; - - audit_buf = netlbl_audit_start_common(type, secid); - audit_log_end(audit_buf); -} diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h index ab840acfc964..47967ef32964 100644 --- a/net/netlabel/netlabel_user.h +++ b/net/netlabel/netlabel_user.h @@ -72,13 +72,25 @@ static inline void *netlbl_netlink_hdr_put(struct sk_buff *skb, NETLBL_PROTO_VERSION); } +/** + * netlbl_netlink_auditinfo - Fetch the audit information from a NETLINK msg + * @skb: the packet + * @audit_info: NetLabel audit information + */ +static inline void netlbl_netlink_auditinfo(struct sk_buff *skb, + struct netlbl_audit *audit_info) +{ + audit_info->secid = NETLINK_CB(skb).sid; + audit_info->loginuid = NETLINK_CB(skb).loginuid; +} + /* NetLabel NETLINK I/O functions */ int netlbl_netlink_init(void); /* NetLabel Audit Functions */ -struct audit_buffer *netlbl_audit_start_common(int type, u32 secid); -void netlbl_audit_nomsg(int type, u32 secid); +struct audit_buffer *netlbl_audit_start_common(int type, + struct netlbl_audit *audit_info); #endif -- cgit v1.2.3 From f9317a40c4e09e20ef01601fc9f5de9e6acb5b96 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 29 Sep 2006 17:06:23 -0700 Subject: [BNX2]: Disable MSI on 5706 if AMD 8132 bridge is present. MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes with byte enables disabled on the unused 32-bit word. This is legal but causes problems on the AMD 8132 which will eventually stop responding after a while. Without this patch, the MSI test done by the driver during open will pass, but MSI will eventually stop working after a few MSIs are written by the device. AMD believes this incompatibility is unique to the 5706, and prefers to locally disable MSI rather than globally disabling it using pci_msi_quirk. Update version to 1.4.45. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 32 ++++++++++++++++++++++++++++++-- include/linux/pci_ids.h | 1 + 2 files changed, 31 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 7fcf015021ec..6b4edb63c4c4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.4.44" -#define DRV_MODULE_RELDATE "August 10, 2006" +#define DRV_MODULE_VERSION "1.4.45" +#define DRV_MODULE_RELDATE "September 29, 2006" #define RUN_AT(x) (jiffies + (x)) @@ -5805,6 +5805,34 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->cmd_ticks_int = bp->cmd_ticks; } + /* Disable MSI on 5706 if AMD 8132 bridge is found. + * + * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes + * with byte enables disabled on the unused 32-bit word. This is legal + * but causes problems on the AMD 8132 which will eventually stop + * responding after a while. + * + * AMD believes this incompatibility is unique to the 5706, and + * prefers to locally disable MSI rather than globally disabling it + * using pci_msi_quirk. + */ + if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) { + struct pci_dev *amd_8132 = NULL; + + while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_8132_BRIDGE, + amd_8132))) { + u8 rev; + + pci_read_config_byte(amd_8132, PCI_REVISION_ID, &rev); + if (rev >= 0x10 && rev <= 0x13) { + disable_msi = 1; + pci_dev_put(amd_8132); + break; + } + } + } + bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL; bp->req_line_speed = 0; if (bp->phy_flags & PHY_SERDES_FLAG) { diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index b7e85ff045ea..c9ffbc3843d5 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -507,6 +507,7 @@ #define PCI_DEVICE_ID_AMD_8151_0 0x7454 #define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450 #define PCI_DEVICE_ID_AMD_8131_APIC 0x7451 +#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458 #define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090 #define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091 #define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093 -- cgit v1.2.3 From 1c9d3e72a7164c590437f2ab6c2c4f6da91f1703 Mon Sep 17 00:00:00 2001 From: Chas Williams Date: Fri, 29 Sep 2006 17:13:24 -0700 Subject: [ATM]: [lec] header indent, comment and whitespace cleanup Signed-off-by: Chas Williams Signed-off-by: David S. Miller --- include/linux/atmlec.h | 119 ++++++++++++++++++---------------- net/atm/lec.h | 172 +++++++++++++++++++++++++++---------------------- net/atm/lec_arpc.h | 148 ++++++++++++++++++++++-------------------- 3 files changed, 235 insertions(+), 204 deletions(-) (limited to 'include/linux') diff --git a/include/linux/atmlec.h b/include/linux/atmlec.h index f267f2442766..6f5a1bab8f50 100644 --- a/include/linux/atmlec.h +++ b/include/linux/atmlec.h @@ -1,9 +1,7 @@ /* - * - * ATM Lan Emulation Daemon vs. driver interface - * - * mkiiskila@yahoo.com + * ATM Lan Emulation Daemon driver interface * + * Marko Kiiskila */ #ifndef _ATMLEC_H_ @@ -13,76 +11,87 @@ #include #include #include + /* ATM lec daemon control socket */ -#define ATMLEC_CTRL _IO('a',ATMIOC_LANE) -#define ATMLEC_DATA _IO('a',ATMIOC_LANE+1) -#define ATMLEC_MCAST _IO('a',ATMIOC_LANE+2) +#define ATMLEC_CTRL _IO('a', ATMIOC_LANE) +#define ATMLEC_DATA _IO('a', ATMIOC_LANE+1) +#define ATMLEC_MCAST _IO('a', ATMIOC_LANE+2) /* Maximum number of LEC interfaces (tweakable) */ #define MAX_LEC_ITF 48 -/* From the total of MAX_LEC_ITF, last NUM_TR_DEVS are reserved for Token Ring. +/* + * From the total of MAX_LEC_ITF, last NUM_TR_DEVS are reserved for Token Ring. * E.g. if MAX_LEC_ITF = 48 and NUM_TR_DEVS = 8, then lec0-lec39 are for * Ethernet ELANs and lec40-lec47 are for Token Ring ELANS. */ #define NUM_TR_DEVS 8 -typedef enum { - l_set_mac_addr, l_del_mac_addr, - l_svc_setup, - l_addr_delete, l_topology_change, - l_flush_complete, l_arp_update, - l_narp_req, /* LANE2 mandates the use of this */ - l_config, l_flush_tran_id, - l_set_lecid, l_arp_xmt, - l_rdesc_arp_xmt, - l_associate_req, - l_should_bridge /* should we bridge this MAC? */ +typedef enum { + l_set_mac_addr, + l_del_mac_addr, + l_svc_setup, + l_addr_delete, + l_topology_change, + l_flush_complete, + l_arp_update, + l_narp_req, /* LANE2 mandates the use of this */ + l_config, + l_flush_tran_id, + l_set_lecid, + l_arp_xmt, + l_rdesc_arp_xmt, + l_associate_req, + l_should_bridge /* should we bridge this MAC? */ } atmlec_msg_type; #define ATMLEC_MSG_TYPE_MAX l_should_bridge struct atmlec_config_msg { - unsigned int maximum_unknown_frame_count; - unsigned int max_unknown_frame_time; - unsigned short max_retry_count; - unsigned int aging_time; - unsigned int forward_delay_time; - unsigned int arp_response_time; - unsigned int flush_timeout; - unsigned int path_switching_delay; - unsigned int lane_version; /* LANE2: 1 for LANEv1, 2 for LANEv2 */ - int mtu; - int is_proxy; + unsigned int maximum_unknown_frame_count; + unsigned int max_unknown_frame_time; + unsigned short max_retry_count; + unsigned int aging_time; + unsigned int forward_delay_time; + unsigned int arp_response_time; + unsigned int flush_timeout; + unsigned int path_switching_delay; + unsigned int lane_version; /* LANE2: 1 for LANEv1, 2 for LANEv2 */ + int mtu; + int is_proxy; }; - + struct atmlec_msg { - atmlec_msg_type type; - int sizeoftlvs; /* LANE2: if != 0, tlvs follow */ - union { - struct { - unsigned char mac_addr[ETH_ALEN]; - unsigned char atm_addr[ATM_ESA_LEN]; - unsigned int flag;/* Topology_change flag, - remoteflag, permanent flag, - lecid, transaction id */ - unsigned int targetless_le_arp; /* LANE2 */ - unsigned int no_source_le_narp; /* LANE2 */ - } normal; - struct atmlec_config_msg config; - struct { - uint16_t lec_id; /* requestor lec_id */ - uint32_t tran_id; /* transaction id */ - unsigned char mac_addr[ETH_ALEN]; /* dst mac addr */ - unsigned char atm_addr[ATM_ESA_LEN]; /* reqestor ATM addr */ - } proxy; - /* For mapping LE_ARP requests to responses. Filled by */ - } content; /* zeppelin, returned by kernel. Used only when proxying */ + atmlec_msg_type type; + int sizeoftlvs; /* LANE2: if != 0, tlvs follow */ + union { + struct { + unsigned char mac_addr[ETH_ALEN]; + unsigned char atm_addr[ATM_ESA_LEN]; + unsigned int flag; /* + * Topology_change flag, + * remoteflag, permanent flag, + * lecid, transaction id + */ + unsigned int targetless_le_arp; /* LANE2 */ + unsigned int no_source_le_narp; /* LANE2 */ + } normal; + struct atmlec_config_msg config; + struct { + uint16_t lec_id; /* requestor lec_id */ + uint32_t tran_id; /* transaction id */ + unsigned char mac_addr[ETH_ALEN]; /* dst mac addr */ + unsigned char atm_addr[ATM_ESA_LEN]; /* reqestor ATM addr */ + } proxy; /* + * For mapping LE_ARP requests to responses. Filled by + * zeppelin, returned by kernel. Used only when proxying + */ + } content; } __ATM_API_ALIGN; struct atmlec_ioc { - int dev_num; - unsigned char atm_addr[ATM_ESA_LEN]; - unsigned char receive; /* 1= receive vcc, 0 = send vcc */ + int dev_num; + unsigned char atm_addr[ATM_ESA_LEN]; + unsigned char receive; /* 1= receive vcc, 0 = send vcc */ }; #endif /* _ATMLEC_H_ */ diff --git a/net/atm/lec.h b/net/atm/lec.h index c22a8bfa1f81..c700472f64df 100644 --- a/net/atm/lec.h +++ b/net/atm/lec.h @@ -1,14 +1,13 @@ /* - * * Lan Emulation client header file * - * Marko Kiiskila mkiiskila@yahoo.com - * + * Marko Kiiskila */ #ifndef _LEC_H_ #define _LEC_H_ +#include #include #include #include @@ -16,18 +15,18 @@ #define LEC_HEADER_LEN 16 struct lecdatahdr_8023 { - unsigned short le_header; - unsigned char h_dest[ETH_ALEN]; - unsigned char h_source[ETH_ALEN]; - unsigned short h_type; + unsigned short le_header; + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; + unsigned short h_type; }; struct lecdatahdr_8025 { - unsigned short le_header; - unsigned char ac_pad; - unsigned char fc; - unsigned char h_dest[ETH_ALEN]; - unsigned char h_source[ETH_ALEN]; + unsigned short le_header; + unsigned char ac_pad; + unsigned char fc; + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; }; #define LEC_MINIMUM_8023_SIZE 62 @@ -44,17 +43,18 @@ struct lecdatahdr_8025 { * */ struct lane2_ops { - int (*resolve)(struct net_device *dev, u8 *dst_mac, int force, - u8 **tlvs, u32 *sizeoftlvs); - int (*associate_req)(struct net_device *dev, u8 *lan_dst, - u8 *tlvs, u32 sizeoftlvs); - void (*associate_indicator)(struct net_device *dev, u8 *mac_addr, - u8 *tlvs, u32 sizeoftlvs); + int (*resolve) (struct net_device *dev, u8 *dst_mac, int force, + u8 **tlvs, u32 *sizeoftlvs); + int (*associate_req) (struct net_device *dev, u8 *lan_dst, + u8 *tlvs, u32 sizeoftlvs); + void (*associate_indicator) (struct net_device *dev, u8 *mac_addr, + u8 *tlvs, u32 sizeoftlvs); }; /* * ATM LAN Emulation supports both LLC & Dix Ethernet EtherType * frames. + * * 1. Dix Ethernet EtherType frames encoded by placing EtherType * field in h_type field. Data follows immediatelly after header. * 2. LLC Data frames whose total length, including LLC field and data, @@ -70,72 +70,88 @@ struct lane2_ops { #define LEC_ARP_TABLE_SIZE 16 struct lec_priv { - struct net_device_stats stats; - unsigned short lecid; /* Lecid of this client */ - struct lec_arp_table *lec_arp_empty_ones; - /* Used for storing VCC's that don't have a MAC address attached yet */ - struct lec_arp_table *lec_arp_tables[LEC_ARP_TABLE_SIZE]; - /* Actual LE ARP table */ - struct lec_arp_table *lec_no_forward; - /* Used for storing VCC's (and forward packets from) which are to - age out by not using them to forward packets. - This is because to some LE clients there will be 2 VCCs. Only - one of them gets used. */ - struct lec_arp_table *mcast_fwds; - /* With LANEv2 it is possible that BUS (or a special multicast server) - establishes multiple Multicast Forward VCCs to us. This list - collects all those VCCs. LANEv1 client has only one item in this - list. These entries are not aged out. */ - spinlock_t lec_arp_lock; - struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ - struct atm_vcc *lecd; - struct timer_list lec_arp_timer; - /* C10 */ - unsigned int maximum_unknown_frame_count; -/* Within the period of time defined by this variable, the client will send - no more than C10 frames to BUS for a given unicast destination. (C11) */ - unsigned long max_unknown_frame_time; -/* If no traffic has been sent in this vcc for this period of time, - vcc will be torn down (C12)*/ - unsigned long vcc_timeout_period; -/* An LE Client MUST not retry an LE_ARP_REQUEST for a - given frame's LAN Destination more than maximum retry count times, - after the first LEC_ARP_REQUEST (C13)*/ - unsigned short max_retry_count; -/* Max time the client will maintain an entry in its arp cache in - absence of a verification of that relationship (C17)*/ - unsigned long aging_time; -/* Max time the client will maintain an entry in cache when - topology change flag is true (C18) */ - unsigned long forward_delay_time; -/* Topology change flag (C19)*/ - int topology_change; -/* Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE - cycle to take (C20)*/ - unsigned long arp_response_time; -/* Time limit ot wait to receive an LE_FLUSH_RESPONSE after the - LE_FLUSH_REQUEST has been sent before taking recover action. (C21)*/ - unsigned long flush_timeout; -/* The time since sending a frame to the bus after which the - LE Client may assume that the frame has been either discarded or - delivered to the recipient (C22) */ - unsigned long path_switching_delay; + struct net_device_stats stats; + unsigned short lecid; /* Lecid of this client */ + struct lec_arp_table *lec_arp_empty_ones; + /* Used for storing VCC's that don't have a MAC address attached yet */ + struct lec_arp_table *lec_arp_tables[LEC_ARP_TABLE_SIZE]; + /* Actual LE ARP table */ + struct lec_arp_table *lec_no_forward; + /* + * Used for storing VCC's (and forward packets from) which are to + * age out by not using them to forward packets. + * This is because to some LE clients there will be 2 VCCs. Only + * one of them gets used. + */ + struct lec_arp_table *mcast_fwds; + /* + * With LANEv2 it is possible that BUS (or a special multicast server) + * establishes multiple Multicast Forward VCCs to us. This list + * collects all those VCCs. LANEv1 client has only one item in this + * list. These entries are not aged out. + */ + spinlock_t lec_arp_lock; + struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ + struct atm_vcc *lecd; + struct timer_list lec_arp_timer; /* C10 */ + unsigned int maximum_unknown_frame_count; + /* + * Within the period of time defined by this variable, the client will send + * no more than C10 frames to BUS for a given unicast destination. (C11) + */ + unsigned long max_unknown_frame_time; + /* + * If no traffic has been sent in this vcc for this period of time, + * vcc will be torn down (C12) + */ + unsigned long vcc_timeout_period; + /* + * An LE Client MUST not retry an LE_ARP_REQUEST for a + * given frame's LAN Destination more than maximum retry count times, + * after the first LEC_ARP_REQUEST (C13) + */ + unsigned short max_retry_count; + /* + * Max time the client will maintain an entry in its arp cache in + * absence of a verification of that relationship (C17) + */ + unsigned long aging_time; + /* + * Max time the client will maintain an entry in cache when + * topology change flag is true (C18) + */ + unsigned long forward_delay_time; /* Topology change flag (C19) */ + int topology_change; + /* + * Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE + * cycle to take (C20) + */ + unsigned long arp_response_time; + /* + * Time limit ot wait to receive an LE_FLUSH_RESPONSE after the + * LE_FLUSH_REQUEST has been sent before taking recover action. (C21) + */ + unsigned long flush_timeout; + /* The time since sending a frame to the bus after which the + * LE Client may assume that the frame has been either discarded or + * delivered to the recipient (C22) + */ + unsigned long path_switching_delay; - u8 *tlvs; /* LANE2: TLVs are new */ - u32 sizeoftlvs; /* The size of the tlv array in bytes */ - int lane_version; /* LANE2 */ - int itfnum; /* e.g. 2 for lec2, 5 for lec5 */ - struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */ - int is_proxy; /* bridge between ATM and Ethernet */ - int is_trdev; /* Device type, 0 = Ethernet, 1 = TokenRing */ + u8 *tlvs; /* LANE2: TLVs are new */ + u32 sizeoftlvs; /* The size of the tlv array in bytes */ + int lane_version; /* LANE2 */ + int itfnum; /* e.g. 2 for lec2, 5 for lec5 */ + struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */ + int is_proxy; /* bridge between ATM and Ethernet */ + int is_trdev; /* Device type, 0 = Ethernet, 1 = TokenRing */ }; struct lec_vcc_priv { - void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); + void (*old_pop) (struct atm_vcc *vcc, struct sk_buff *skb); int xoff; }; #define LEC_VCC_PRIV(vcc) ((struct lec_vcc_priv *)((vcc)->user_back)) -#endif /* _LEC_H_ */ - +#endif /* _LEC_H_ */ diff --git a/net/atm/lec_arpc.h b/net/atm/lec_arpc.h index 397448094648..0230ca148c77 100644 --- a/net/atm/lec_arpc.h +++ b/net/atm/lec_arpc.h @@ -1,92 +1,98 @@ /* * Lec arp cache - * Marko Kiiskila mkiiskila@yahoo.com * + * Marko Kiiskila */ -#ifndef _LEC_ARP_H -#define _LEC_ARP_H +#ifndef _LEC_ARP_H_ +#define _LEC_ARP_H_ #include #include #include #include struct lec_arp_table { - struct lec_arp_table *next; /* Linked entry list */ - unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */ - unsigned char mac_addr[ETH_ALEN]; /* Mac address */ - int is_rdesc; /* Mac address is a route descriptor */ - struct atm_vcc *vcc; /* Vcc this entry is attached */ - struct atm_vcc *recv_vcc; /* Vcc we receive data from */ - void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); - /* Push that leads to daemon */ - void (*old_recv_push)(struct atm_vcc *vcc, struct sk_buff *skb); - /* Push that leads to daemon */ - void (*old_close)(struct atm_vcc *vcc); - /* We want to see when this - * vcc gets closed */ - unsigned long last_used; /* For expiry */ - unsigned long timestamp; /* Used for various timestamping - * things: - * 1. FLUSH started - * (status=ESI_FLUSH_PENDING) - * 2. Counting to - * max_unknown_frame_time - * (status=ESI_ARP_PENDING|| - * status=ESI_VC_PENDING) - */ - unsigned char no_tries; /* No of times arp retry has been - tried */ - unsigned char status; /* Status of this entry */ - unsigned short flags; /* Flags for this entry */ - unsigned short packets_flooded; /* Data packets flooded */ - unsigned long flush_tran_id; /* Transaction id in flush protocol */ - struct timer_list timer; /* Arping timer */ - struct lec_priv *priv; /* Pointer back */ + struct lec_arp_table *next; /* Linked entry list */ + unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */ + unsigned char mac_addr[ETH_ALEN]; /* Mac address */ + int is_rdesc; /* Mac address is a route descriptor */ + struct atm_vcc *vcc; /* Vcc this entry is attached */ + struct atm_vcc *recv_vcc; /* Vcc we receive data from */ - u8 *tlvs; /* LANE2: Each MAC address can have TLVs */ - u32 sizeoftlvs; /* associated with it. sizeoftlvs tells the */ - /* the length of the tlvs array */ - struct sk_buff_head tx_wait; /* wait queue for outgoing packets */ + void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb); + /* Push that leads to daemon */ + + void (*old_recv_push) (struct atm_vcc *vcc, struct sk_buff *skb); + /* Push that leads to daemon */ + + void (*old_close) (struct atm_vcc *vcc); + /* We want to see when this vcc gets closed */ + + unsigned long last_used; /* For expiry */ + unsigned long timestamp; /* Used for various timestamping things: + * 1. FLUSH started + * (status=ESI_FLUSH_PENDING) + * 2. Counting to + * max_unknown_frame_time + * (status=ESI_ARP_PENDING|| + * status=ESI_VC_PENDING) + */ + unsigned char no_tries; /* No of times arp retry has been tried */ + unsigned char status; /* Status of this entry */ + unsigned short flags; /* Flags for this entry */ + unsigned short packets_flooded; /* Data packets flooded */ + unsigned long flush_tran_id; /* Transaction id in flush protocol */ + struct timer_list timer; /* Arping timer */ + struct lec_priv *priv; /* Pointer back */ + u8 *tlvs; + u32 sizeoftlvs; /* + * LANE2: Each MAC address can have TLVs + * associated with it. sizeoftlvs tells the + * the length of the tlvs array + */ + struct sk_buff_head tx_wait; /* wait queue for outgoing packets */ }; -struct tlv { /* LANE2: Template tlv struct for accessing */ - /* the tlvs in the lec_arp_table->tlvs array*/ - u32 type; - u8 length; - u8 value[255]; +/* + * LANE2: Template tlv struct for accessing + * the tlvs in the lec_arp_table->tlvs array + */ +struct tlv { + u32 type; + u8 length; + u8 value[255]; }; /* Status fields */ -#define ESI_UNKNOWN 0 /* - * Next packet sent to this mac address - * causes ARP-request to be sent - */ -#define ESI_ARP_PENDING 1 /* - * There is no ATM address associated with this - * 48-bit address. The LE-ARP protocol is in - * progress. - */ -#define ESI_VC_PENDING 2 /* - * There is a valid ATM address associated with - * this 48-bit address but there is no VC set - * up to that ATM address. The signaling - * protocol is in process. - */ -#define ESI_FLUSH_PENDING 4 /* - * The LEC has been notified of the FLUSH_START - * status and it is assumed that the flush - * protocol is in process. - */ -#define ESI_FORWARD_DIRECT 5 /* - * Either the Path Switching Delay (C22) has - * elapsed or the LEC has notified the Mapping - * that the flush protocol has completed. In - * either case, it is safe to forward packets - * to this address via the data direct VC. - */ +#define ESI_UNKNOWN 0 /* + * Next packet sent to this mac address + * causes ARP-request to be sent + */ +#define ESI_ARP_PENDING 1 /* + * There is no ATM address associated with this + * 48-bit address. The LE-ARP protocol is in + * progress. + */ +#define ESI_VC_PENDING 2 /* + * There is a valid ATM address associated with + * this 48-bit address but there is no VC set + * up to that ATM address. The signaling + * protocol is in process. + */ +#define ESI_FLUSH_PENDING 4 /* + * The LEC has been notified of the FLUSH_START + * status and it is assumed that the flush + * protocol is in process. + */ +#define ESI_FORWARD_DIRECT 5 /* + * Either the Path Switching Delay (C22) has + * elapsed or the LEC has notified the Mapping + * that the flush protocol has completed. In + * either case, it is safe to forward packets + * to this address via the data direct VC. + */ /* Flag values */ #define LEC_REMOTE_FLAG 0x0001 #define LEC_PERMANENT_FLAG 0x0002 -#endif +#endif /* _LEC_ARP_H_ */ -- cgit v1.2.3 From e5c9e081e9c980fa785cd9002c25a251cf3f090e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 30 Sep 2006 19:44:39 +0900 Subject: [PATCH] libata: cosmetic changes to constants Cosmetic changes to ATA_DFLAG_* constants for soon-to-follow NCQ-off patch. Signed-off-by: Jeff Garzik --- include/linux/libata.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index df44b09fbae8..e54a5fd6a41e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -142,8 +142,8 @@ enum { ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */ ATA_DFLAG_CFG_MASK = (1 << 8) - 1, - ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ - ATA_DFLAG_SUSPENDED = (1 << 9), /* device suspended */ + ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */ + ATA_DFLAG_SUSPENDED = (1 << 10), /* device suspended */ ATA_DFLAG_INIT_MASK = (1 << 16) - 1, ATA_DFLAG_DETACH = (1 << 16), -- cgit v1.2.3 From 360f654e7cda850034f3f6252a7a7cff3fa77356 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 30 Sep 2006 19:45:00 +0900 Subject: [PATCH] libata: turn off NCQ if queue depth is adjusted to 1 Turn off NCQ if queue depth is adjusted to 1. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 12 +++++++++++- include/linux/libata.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index b4a0246506ef..b0d0cc41f3e8 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -889,6 +889,7 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) { struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev; + unsigned long flags; int max_depth; if (queue_depth < 1) @@ -904,6 +905,14 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) queue_depth = max_depth; scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth); + + spin_lock_irqsave(ap->lock, flags); + if (queue_depth > 1) + dev->flags &= ~ATA_DFLAG_NCQ_OFF; + else + dev->flags |= ATA_DFLAG_NCQ_OFF; + spin_unlock_irqrestore(ap->lock, flags); + return queue_depth; } @@ -1293,7 +1302,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm */ goto nothing_to_do; - if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) { + if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF | + ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) { /* yay, NCQ */ if (!lba_48_ok(block, n_block)) goto out_of_range; diff --git a/include/linux/libata.h b/include/linux/libata.h index e54a5fd6a41e..d1af1dbeaeb4 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -143,6 +143,7 @@ enum { ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */ + ATA_DFLAG_NCQ_OFF = (1 << 9), /* devied limited to non-NCQ mode */ ATA_DFLAG_SUSPENDED = (1 << 10), /* device suspended */ ATA_DFLAG_INIT_MASK = (1 << 16) - 1, -- cgit v1.2.3 From 4aff5e2333c9a1609662f2091f55c3f6fffdad36 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 10 Aug 2006 08:44:47 +0200 Subject: [PATCH] Split struct request ->flags into two parts Right now ->flags is a bit of a mess: some are request types, and others are just modifiers. Clean this up by splitting it into ->cmd_type and ->cmd_flags. This allows introduction of generic Linux block message types, useful for sending generic Linux commands to block devices. Signed-off-by: Jens Axboe --- block/as-iosched.c | 2 +- block/elevator.c | 26 +++--- block/ll_rw_blk.c | 101 ++++++++-------------- block/scsi_ioctl.c | 6 +- drivers/block/floppy.c | 4 +- drivers/block/nbd.c | 8 +- drivers/block/paride/pd.c | 2 +- drivers/block/pktcdvd.c | 6 +- drivers/block/xd.c | 2 +- drivers/cdrom/cdrom.c | 2 +- drivers/cdrom/cdu31a.c | 4 +- drivers/ide/ide-cd.c | 69 +++++++-------- drivers/ide/ide-disk.c | 5 +- drivers/ide/ide-dma.c | 2 +- drivers/ide/ide-floppy.c | 14 ++-- drivers/ide/ide-io.c | 36 ++++---- drivers/ide/ide-lib.c | 5 +- drivers/ide/ide-tape.c | 8 +- drivers/ide/ide-taskfile.c | 8 +- drivers/ide/ide.c | 4 +- drivers/ide/legacy/hd.c | 2 +- drivers/md/dm-emc.c | 3 +- drivers/message/i2o/i2o_block.c | 7 +- drivers/mmc/mmc_queue.c | 6 +- drivers/mtd/mtd_blkdevs.c | 2 +- drivers/s390/block/dasd_diag.c | 2 +- drivers/s390/block/dasd_eckd.c | 2 +- drivers/s390/block/dasd_fba.c | 2 +- drivers/scsi/aic7xxx_old.c | 4 +- drivers/scsi/ide-scsi.c | 14 ++-- drivers/scsi/pluto.c | 6 +- drivers/scsi/scsi_lib.c | 37 +++++---- drivers/scsi/sd.c | 5 +- drivers/scsi/sun3_NCR5380.c | 2 +- drivers/scsi/sun3_scsi.c | 2 +- drivers/scsi/sun3_scsi_vme.c | 2 +- include/linux/blkdev.h | 180 ++++++++++++++++++++++------------------ include/linux/blktrace_api.h | 2 +- include/scsi/scsi_tcq.h | 2 +- 39 files changed, 295 insertions(+), 301 deletions(-) (limited to 'include/linux') diff --git a/block/as-iosched.c b/block/as-iosched.c index 5da56d48fbd3..ad1cc4077819 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -1335,7 +1335,7 @@ static void as_add_request(request_queue_t *q, struct request *rq) arq->state = AS_RQ_NEW; if (rq_data_dir(arq->request) == READ - || (arq->request->flags & REQ_RW_SYNC)) + || (arq->request->cmd_flags & REQ_RW_SYNC)) arq->is_sync = 1; else arq->is_sync = 0; diff --git a/block/elevator.c b/block/elevator.c index 9b72dc7c8a5c..4ac97b642042 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -242,7 +242,7 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) list_for_each_prev(entry, &q->queue_head) { struct request *pos = list_entry_rq(entry); - if (pos->flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED)) + if (pos->cmd_flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED)) break; if (rq->sector >= boundary) { if (pos->sector < boundary) @@ -313,7 +313,7 @@ void elv_requeue_request(request_queue_t *q, struct request *rq) e->ops->elevator_deactivate_req_fn(q, rq); } - rq->flags &= ~REQ_STARTED; + rq->cmd_flags &= ~REQ_STARTED; elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE); } @@ -344,13 +344,13 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) switch (where) { case ELEVATOR_INSERT_FRONT: - rq->flags |= REQ_SOFTBARRIER; + rq->cmd_flags |= REQ_SOFTBARRIER; list_add(&rq->queuelist, &q->queue_head); break; case ELEVATOR_INSERT_BACK: - rq->flags |= REQ_SOFTBARRIER; + rq->cmd_flags |= REQ_SOFTBARRIER; elv_drain_elevator(q); list_add_tail(&rq->queuelist, &q->queue_head); /* @@ -369,7 +369,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) case ELEVATOR_INSERT_SORT: BUG_ON(!blk_fs_request(rq)); - rq->flags |= REQ_SORTED; + rq->cmd_flags |= REQ_SORTED; q->nr_sorted++; if (q->last_merge == NULL && rq_mergeable(rq)) q->last_merge = rq; @@ -387,7 +387,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) * insertion; otherwise, requests should be requeued * in ordseq order. */ - rq->flags |= REQ_SOFTBARRIER; + rq->cmd_flags |= REQ_SOFTBARRIER; if (q->ordseq == 0) { list_add(&rq->queuelist, &q->queue_head); @@ -429,9 +429,9 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, int plug) { if (q->ordcolor) - rq->flags |= REQ_ORDERED_COLOR; + rq->cmd_flags |= REQ_ORDERED_COLOR; - if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) { + if (rq->cmd_flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) { /* * toggle ordered color */ @@ -452,7 +452,7 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, q->end_sector = rq_end_sector(rq); q->boundary_rq = rq; } - } else if (!(rq->flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT) + } else if (!(rq->cmd_flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT) where = ELEVATOR_INSERT_BACK; if (plug) @@ -493,7 +493,7 @@ struct request *elv_next_request(request_queue_t *q) int ret; while ((rq = __elv_next_request(q)) != NULL) { - if (!(rq->flags & REQ_STARTED)) { + if (!(rq->cmd_flags & REQ_STARTED)) { elevator_t *e = q->elevator; /* @@ -510,7 +510,7 @@ struct request *elv_next_request(request_queue_t *q) * it, a request that has been delayed should * not be passed by new incoming requests */ - rq->flags |= REQ_STARTED; + rq->cmd_flags |= REQ_STARTED; blk_add_trace_rq(q, rq, BLK_TA_ISSUE); } @@ -519,7 +519,7 @@ struct request *elv_next_request(request_queue_t *q) q->boundary_rq = NULL; } - if ((rq->flags & REQ_DONTPREP) || !q->prep_rq_fn) + if ((rq->cmd_flags & REQ_DONTPREP) || !q->prep_rq_fn) break; ret = q->prep_rq_fn(q, rq); @@ -541,7 +541,7 @@ struct request *elv_next_request(request_queue_t *q) nr_bytes = rq->data_len; blkdev_dequeue_request(rq); - rq->flags |= REQ_QUIET; + rq->cmd_flags |= REQ_QUIET; end_that_request_chunk(rq, 0, nr_bytes); end_that_request_last(rq, 0); } else { diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 51dc0edf76e0..9b91bb70c5ed 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -382,8 +382,8 @@ unsigned blk_ordered_req_seq(struct request *rq) if (rq == &q->post_flush_rq) return QUEUE_ORDSEQ_POSTFLUSH; - if ((rq->flags & REQ_ORDERED_COLOR) == - (q->orig_bar_rq->flags & REQ_ORDERED_COLOR)) + if ((rq->cmd_flags & REQ_ORDERED_COLOR) == + (q->orig_bar_rq->cmd_flags & REQ_ORDERED_COLOR)) return QUEUE_ORDSEQ_DRAIN; else return QUEUE_ORDSEQ_DONE; @@ -446,8 +446,8 @@ static void queue_flush(request_queue_t *q, unsigned which) end_io = post_flush_end_io; } + rq->cmd_flags = REQ_HARDBARRIER; rq_init(q, rq); - rq->flags = REQ_HARDBARRIER; rq->elevator_private = NULL; rq->rq_disk = q->bar_rq.rq_disk; rq->rl = NULL; @@ -471,9 +471,11 @@ static inline struct request *start_ordered(request_queue_t *q, blkdev_dequeue_request(rq); q->orig_bar_rq = rq; rq = &q->bar_rq; + rq->cmd_flags = 0; rq_init(q, rq); - rq->flags = bio_data_dir(q->orig_bar_rq->bio); - rq->flags |= q->ordered & QUEUE_ORDERED_FUA ? REQ_FUA : 0; + if (bio_data_dir(q->orig_bar_rq->bio) == WRITE) + rq->cmd_flags |= REQ_RW; + rq->cmd_flags |= q->ordered & QUEUE_ORDERED_FUA ? REQ_FUA : 0; rq->elevator_private = NULL; rq->rl = NULL; init_request_from_bio(rq, q->orig_bar_rq->bio); @@ -1124,7 +1126,7 @@ void blk_queue_end_tag(request_queue_t *q, struct request *rq) } list_del_init(&rq->queuelist); - rq->flags &= ~REQ_QUEUED; + rq->cmd_flags &= ~REQ_QUEUED; rq->tag = -1; if (unlikely(bqt->tag_index[tag] == NULL)) @@ -1160,7 +1162,7 @@ int blk_queue_start_tag(request_queue_t *q, struct request *rq) struct blk_queue_tag *bqt = q->queue_tags; int tag; - if (unlikely((rq->flags & REQ_QUEUED))) { + if (unlikely((rq->cmd_flags & REQ_QUEUED))) { printk(KERN_ERR "%s: request %p for device [%s] already tagged %d", __FUNCTION__, rq, @@ -1174,7 +1176,7 @@ int blk_queue_start_tag(request_queue_t *q, struct request *rq) __set_bit(tag, bqt->tag_map); - rq->flags |= REQ_QUEUED; + rq->cmd_flags |= REQ_QUEUED; rq->tag = tag; bqt->tag_index[tag] = rq; blkdev_dequeue_request(rq); @@ -1210,65 +1212,31 @@ void blk_queue_invalidate_tags(request_queue_t *q) printk(KERN_ERR "%s: bad tag found on list\n", __FUNCTION__); list_del_init(&rq->queuelist); - rq->flags &= ~REQ_QUEUED; + rq->cmd_flags &= ~REQ_QUEUED; } else blk_queue_end_tag(q, rq); - rq->flags &= ~REQ_STARTED; + rq->cmd_flags &= ~REQ_STARTED; __elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 0); } } EXPORT_SYMBOL(blk_queue_invalidate_tags); -static const char * const rq_flags[] = { - "REQ_RW", - "REQ_FAILFAST", - "REQ_SORTED", - "REQ_SOFTBARRIER", - "REQ_HARDBARRIER", - "REQ_FUA", - "REQ_CMD", - "REQ_NOMERGE", - "REQ_STARTED", - "REQ_DONTPREP", - "REQ_QUEUED", - "REQ_ELVPRIV", - "REQ_PC", - "REQ_BLOCK_PC", - "REQ_SENSE", - "REQ_FAILED", - "REQ_QUIET", - "REQ_SPECIAL", - "REQ_DRIVE_CMD", - "REQ_DRIVE_TASK", - "REQ_DRIVE_TASKFILE", - "REQ_PREEMPT", - "REQ_PM_SUSPEND", - "REQ_PM_RESUME", - "REQ_PM_SHUTDOWN", - "REQ_ORDERED_COLOR", -}; - void blk_dump_rq_flags(struct request *rq, char *msg) { int bit; - printk("%s: dev %s: flags = ", msg, - rq->rq_disk ? rq->rq_disk->disk_name : "?"); - bit = 0; - do { - if (rq->flags & (1 << bit)) - printk("%s ", rq_flags[bit]); - bit++; - } while (bit < __REQ_NR_BITS); + printk("%s: dev %s: type=%x, flags=%x\n", msg, + rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type, + rq->cmd_flags); printk("\nsector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector, rq->nr_sectors, rq->current_nr_sectors); printk("bio %p, biotail %p, buffer %p, data %p, len %u\n", rq->bio, rq->biotail, rq->buffer, rq->data, rq->data_len); - if (rq->flags & (REQ_BLOCK_PC | REQ_PC)) { + if (blk_pc_request(rq)) { printk("cdb: "); for (bit = 0; bit < sizeof(rq->cmd); bit++) printk("%02x ", rq->cmd[bit]); @@ -1441,7 +1409,7 @@ static inline int ll_new_mergeable(request_queue_t *q, int nr_phys_segs = bio_phys_segments(q, bio); if (req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) { - req->flags |= REQ_NOMERGE; + req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; return 0; @@ -1464,7 +1432,7 @@ static inline int ll_new_hw_segment(request_queue_t *q, if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments || req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) { - req->flags |= REQ_NOMERGE; + req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; return 0; @@ -1491,7 +1459,7 @@ static int ll_back_merge_fn(request_queue_t *q, struct request *req, max_sectors = q->max_sectors; if (req->nr_sectors + bio_sectors(bio) > max_sectors) { - req->flags |= REQ_NOMERGE; + req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; return 0; @@ -1530,7 +1498,7 @@ static int ll_front_merge_fn(request_queue_t *q, struct request *req, if (req->nr_sectors + bio_sectors(bio) > max_sectors) { - req->flags |= REQ_NOMERGE; + req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; return 0; @@ -2029,7 +1997,7 @@ EXPORT_SYMBOL(blk_get_queue); static inline void blk_free_request(request_queue_t *q, struct request *rq) { - if (rq->flags & REQ_ELVPRIV) + if (rq->cmd_flags & REQ_ELVPRIV) elv_put_request(q, rq); mempool_free(rq, q->rq.rq_pool); } @@ -2044,17 +2012,17 @@ blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, return NULL; /* - * first three bits are identical in rq->flags and bio->bi_rw, + * first three bits are identical in rq->cmd_flags and bio->bi_rw, * see bio.h and blkdev.h */ - rq->flags = rw; + rq->cmd_flags = rw; if (priv) { if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) { mempool_free(rq, q->rq.rq_pool); return NULL; } - rq->flags |= REQ_ELVPRIV; + rq->cmd_flags |= REQ_ELVPRIV; } return rq; @@ -2351,7 +2319,8 @@ void blk_insert_request(request_queue_t *q, struct request *rq, * must not attempt merges on this) and that it acts as a soft * barrier */ - rq->flags |= REQ_SPECIAL | REQ_SOFTBARRIER; + rq->cmd_type = REQ_TYPE_SPECIAL; + rq->cmd_flags |= REQ_SOFTBARRIER; rq->special = data; @@ -2558,7 +2527,7 @@ void blk_execute_rq_nowait(request_queue_t *q, struct gendisk *bd_disk, int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; rq->rq_disk = bd_disk; - rq->flags |= REQ_NOMERGE; + rq->cmd_flags |= REQ_NOMERGE; rq->end_io = done; WARN_ON(irqs_disabled()); spin_lock_irq(q->queue_lock); @@ -2728,7 +2697,7 @@ void __blk_put_request(request_queue_t *q, struct request *req) */ if (rl) { int rw = rq_data_dir(req); - int priv = req->flags & REQ_ELVPRIV; + int priv = req->cmd_flags & REQ_ELVPRIV; BUG_ON(!list_empty(&req->queuelist)); @@ -2890,22 +2859,22 @@ static inline int attempt_front_merge(request_queue_t *q, struct request *rq) static void init_request_from_bio(struct request *req, struct bio *bio) { - req->flags |= REQ_CMD; + req->cmd_type = REQ_TYPE_FS; /* * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST) */ if (bio_rw_ahead(bio) || bio_failfast(bio)) - req->flags |= REQ_FAILFAST; + req->cmd_flags |= REQ_FAILFAST; /* * REQ_BARRIER implies no merging, but lets make it explicit */ if (unlikely(bio_barrier(bio))) - req->flags |= (REQ_HARDBARRIER | REQ_NOMERGE); + req->cmd_flags |= (REQ_HARDBARRIER | REQ_NOMERGE); if (bio_sync(bio)) - req->flags |= REQ_RW_SYNC; + req->cmd_flags |= REQ_RW_SYNC; req->errors = 0; req->hard_sector = req->sector = bio->bi_sector; @@ -3306,7 +3275,7 @@ static int __end_that_request_first(struct request *req, int uptodate, req->errors = 0; if (!uptodate) { - if (blk_fs_request(req) && !(req->flags & REQ_QUIET)) + if (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET)) printk("end_request: I/O error, dev %s, sector %llu\n", req->rq_disk ? req->rq_disk->disk_name : "?", (unsigned long long)req->sector); @@ -3569,8 +3538,8 @@ EXPORT_SYMBOL(end_request); void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio) { - /* first two bits are identical in rq->flags and bio->bi_rw */ - rq->flags |= (bio->bi_rw & 3); + /* first two bits are identical in rq->cmd_flags and bio->bi_rw */ + rq->cmd_flags |= (bio->bi_rw & 3); rq->nr_phys_segments = bio_phys_segments(q, bio); rq->nr_hw_segments = bio_hw_segments(q, bio); diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index b33eda26e205..2dc326421a24 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -294,7 +294,7 @@ static int sg_io(struct file *file, request_queue_t *q, rq->sense = sense; rq->sense_len = 0; - rq->flags |= REQ_BLOCK_PC; + rq->cmd_type = REQ_TYPE_BLOCK_PC; bio = rq->bio; /* @@ -470,7 +470,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q, memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; - rq->flags |= REQ_BLOCK_PC; + rq->cmd_type = REQ_TYPE_BLOCK_PC; blk_execute_rq(q, disk, rq, 0); @@ -502,7 +502,7 @@ static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int c int err; rq = blk_get_request(q, WRITE, __GFP_WAIT); - rq->flags |= REQ_BLOCK_PC; + rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->data = NULL; rq->data_len = 0; rq->timeout = BLK_DEFAULT_TIMEOUT; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index ad1d7065a1b2..629c5769d994 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2991,8 +2991,8 @@ static void do_fd_request(request_queue_t * q) if (usage_count == 0) { printk("warning: usage count=0, current_req=%p exiting\n", current_req); - printk("sect=%ld flags=%lx\n", (long)current_req->sector, - current_req->flags); + printk("sect=%ld type=%x flags=%x\n", (long)current_req->sector, + current_req->cmd_type, current_req->cmd_flags); return; } if (test_bit(0, &fdc_busy)) { diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index bdbade9a5cf5..9d1035e8d9d8 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -407,10 +407,10 @@ static void do_nbd_request(request_queue_t * q) struct nbd_device *lo; blkdev_dequeue_request(req); - dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%lx)\n", - req->rq_disk->disk_name, req, req->flags); + dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n", + req->rq_disk->disk_name, req, req->cmd_type); - if (!(req->flags & REQ_CMD)) + if (!blk_fs_request(req)) goto error_out; lo = req->rq_disk->private_data; @@ -489,7 +489,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, switch (cmd) { case NBD_DISCONNECT: printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); - sreq.flags = REQ_SPECIAL; + sreq.cmd_type = REQ_TYPE_SPECIAL; nbd_cmd(&sreq) = NBD_CMD_DISC; /* * Set these to sane values in case server implementation diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 2403721f9db1..12ff1a274d91 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -437,7 +437,7 @@ static char *pd_buf; /* buffer for request in progress */ static enum action do_pd_io_start(void) { - if (pd_req->flags & REQ_SPECIAL) { + if (blk_special_request(pd_req)) { phase = pd_special; return pd_special(); } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 451b996bba91..42891d2b054e 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -365,16 +365,16 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq->sense = sense; memset(sense, 0, sizeof(sense)); rq->sense_len = 0; - rq->flags |= REQ_BLOCK_PC | REQ_HARDBARRIER; + rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->cmd_flags |= REQ_HARDBARRIER; if (cgc->quiet) - rq->flags |= REQ_QUIET; + rq->cmd_flags |= REQ_QUIET; memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); if (sizeof(rq->cmd) > CDROM_PACKET_SIZE) memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE); rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); rq->ref_count++; - rq->flags |= REQ_NOMERGE; rq->waiting = &wait; rq->end_io = blk_end_sync_rq; elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); diff --git a/drivers/block/xd.c b/drivers/block/xd.c index e828e4cbd3e1..ebf3025721d1 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -313,7 +313,7 @@ static void do_xd_request (request_queue_t * q) int res = 0; int retry; - if (!(req->flags & REQ_CMD)) { + if (!blk_fs_request(req)) { end_request(req, 0); continue; } diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index d239cf8b20bd..b38c84a7a8e3 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2129,7 +2129,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, rq->cmd[9] = 0xf8; rq->cmd_len = 12; - rq->flags |= REQ_BLOCK_PC; + rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = 60 * HZ; bio = rq->bio; diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index 37bdb0163f0d..ccd91c1a84bd 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -1338,8 +1338,10 @@ static void do_cdu31a_request(request_queue_t * q) } /* WTF??? */ - if (!(req->flags & REQ_CMD)) + if (!blk_fs_request(req)) { + end_request(req, 0); continue; + } if (rq_data_dir(req) == WRITE) { end_request(req, 0); continue; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 654d4cd09847..69bbb6206a00 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -372,7 +372,7 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq, { int log = 0; - if (!sense || !rq || (rq->flags & REQ_QUIET)) + if (!sense || !rq || (rq->cmd_flags & REQ_QUIET)) return 0; switch (sense->sense_key) { @@ -597,7 +597,7 @@ static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq) struct cdrom_info *cd = drive->driver_data; ide_init_drive_cmd(rq); - rq->flags = REQ_PC; + rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->rq_disk = cd->disk; } @@ -617,7 +617,7 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, rq->cmd[0] = GPCMD_REQUEST_SENSE; rq->cmd[4] = rq->data_len = 18; - rq->flags = REQ_SENSE; + rq->cmd_type = REQ_TYPE_SENSE; /* NOTE! Save the failed command in "rq->buffer" */ rq->buffer = (void *) failed_command; @@ -630,10 +630,10 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate) struct request *rq = HWGROUP(drive)->rq; int nsectors = rq->hard_cur_sectors; - if ((rq->flags & REQ_SENSE) && uptodate) { + if (blk_sense_request(rq) && uptodate) { /* - * For REQ_SENSE, "rq->buffer" points to the original failed - * request + * For REQ_TYPE_SENSE, "rq->buffer" points to the original + * failed request */ struct request *failed = (struct request *) rq->buffer; struct cdrom_info *info = drive->driver_data; @@ -706,17 +706,17 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) return 1; } - if (rq->flags & REQ_SENSE) { + if (blk_sense_request(rq)) { /* We got an error trying to get sense info from the drive (probably while trying to recover from a former error). Just give up. */ - rq->flags |= REQ_FAILED; + rq->cmd_flags |= REQ_FAILED; cdrom_end_request(drive, 0); ide_error(drive, "request sense failure", stat); return 1; - } else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) { + } else if (blk_pc_request(rq)) { /* All other functions, except for READ. */ unsigned long flags; @@ -724,7 +724,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) * if we have an error, pass back CHECK_CONDITION as the * scsi status byte */ - if ((rq->flags & REQ_BLOCK_PC) && !rq->errors) + if (!rq->errors) rq->errors = SAM_STAT_CHECK_CONDITION; /* Check for tray open. */ @@ -735,12 +735,12 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) cdrom_saw_media_change (drive); /*printk("%s: media changed\n",drive->name);*/ return 0; - } else if (!(rq->flags & REQ_QUIET)) { + } else if (!(rq->cmd_flags & REQ_QUIET)) { /* Otherwise, print an error. */ ide_dump_status(drive, "packet command error", stat); } - rq->flags |= REQ_FAILED; + rq->cmd_flags |= REQ_FAILED; /* * instead of playing games with moving completions around, @@ -881,7 +881,7 @@ static int cdrom_timer_expiry(ide_drive_t *drive) wait = ATAPI_WAIT_PC; break; default: - if (!(rq->flags & REQ_QUIET)) + if (!(rq->cmd_flags & REQ_QUIET)) printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n", rq->cmd[0]); wait = 0; break; @@ -1124,7 +1124,7 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive) if (rq->current_nr_sectors > 0) { printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n", drive->name, rq->current_nr_sectors); - rq->flags |= REQ_FAILED; + rq->cmd_flags |= REQ_FAILED; cdrom_end_request(drive, 0); } else cdrom_end_request(drive, 1); @@ -1456,7 +1456,7 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive) printk ("%s: cdrom_pc_intr: data underrun %d\n", drive->name, pc->buflen); */ - rq->flags |= REQ_FAILED; + rq->cmd_flags |= REQ_FAILED; cdrom_end_request(drive, 0); } return ide_stopped; @@ -1509,7 +1509,7 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive) rq->data += thislen; rq->data_len -= thislen; - if (rq->flags & REQ_SENSE) + if (blk_sense_request(rq)) rq->sense_len += thislen; } else { confused: @@ -1517,7 +1517,7 @@ confused: "appears confused (ireason = 0x%02x). " "Trying to recover by ending request.\n", drive->name, ireason); - rq->flags |= REQ_FAILED; + rq->cmd_flags |= REQ_FAILED; cdrom_end_request(drive, 0); return ide_stopped; } @@ -1546,7 +1546,7 @@ static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive) struct cdrom_info *info = drive->driver_data; info->dma = 0; - rq->flags &= ~REQ_FAILED; + rq->cmd_flags &= ~REQ_FAILED; len = rq->data_len; /* Start sending the command to the drive. */ @@ -1558,7 +1558,7 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq) { struct request_sense sense; int retries = 10; - unsigned int flags = rq->flags; + unsigned int flags = rq->cmd_flags; if (rq->sense == NULL) rq->sense = &sense; @@ -1567,14 +1567,14 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq) do { int error; unsigned long time = jiffies; - rq->flags = flags; + rq->cmd_flags = flags; error = ide_do_drive_cmd(drive, rq, ide_wait); time = jiffies - time; /* FIXME: we should probably abort/retry or something * in case of failure */ - if (rq->flags & REQ_FAILED) { + if (rq->cmd_flags & REQ_FAILED) { /* The request failed. Retry if it was due to a unit attention status (usually means media was changed). */ @@ -1596,10 +1596,10 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq) } /* End of retry loop. */ - } while ((rq->flags & REQ_FAILED) && retries >= 0); + } while ((rq->cmd_flags & REQ_FAILED) && retries >= 0); /* Return an error if the command failed. */ - return (rq->flags & REQ_FAILED) ? -EIO : 0; + return (rq->cmd_flags & REQ_FAILED) ? -EIO : 0; } /* @@ -1963,7 +1963,7 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) { struct cdrom_info *info = drive->driver_data; - rq->flags |= REQ_QUIET; + rq->cmd_flags |= REQ_QUIET; info->dma = 0; @@ -2023,11 +2023,11 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block) } info->last_block = block; return action; - } else if (rq->flags & (REQ_PC | REQ_SENSE)) { + } else if (rq->cmd_type == REQ_TYPE_SENSE) { return cdrom_do_packet_command(drive); - } else if (rq->flags & REQ_BLOCK_PC) { + } else if (blk_pc_request(rq)) { return cdrom_do_block_pc(drive, rq); - } else if (rq->flags & REQ_SPECIAL) { + } else if (blk_special_request(rq)) { /* * right now this can only be a reset... */ @@ -2105,7 +2105,7 @@ static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense) req.sense = sense; req.cmd[0] = GPCMD_TEST_UNIT_READY; - req.flags |= REQ_QUIET; + req.cmd_flags |= REQ_QUIET; #if ! STANDARD_ATAPI /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to @@ -2207,7 +2207,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, req.cmd[0] = GPCMD_READ_CDVD_CAPACITY; req.data = (char *)&capbuf; req.data_len = sizeof(capbuf); - req.flags |= REQ_QUIET; + req.cmd_flags |= REQ_QUIET; stat = cdrom_queue_packet_command(drive, &req); if (stat == 0) { @@ -2230,7 +2230,7 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag, req.sense = sense; req.data = buf; req.data_len = buflen; - req.flags |= REQ_QUIET; + req.cmd_flags |= REQ_QUIET; req.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; req.cmd[6] = trackno; req.cmd[7] = (buflen >> 8); @@ -2531,7 +2531,7 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi, req.timeout = cgc->timeout; if (cgc->quiet) - req.flags |= REQ_QUIET; + req.cmd_flags |= REQ_QUIET; req.sense = cgc->sense; cgc->stat = cdrom_queue_packet_command(drive, &req); @@ -2629,7 +2629,8 @@ int ide_cdrom_reset (struct cdrom_device_info *cdi) int ret; cdrom_prepare_request(drive, &req); - req.flags = REQ_SPECIAL | REQ_QUIET; + req.cmd_type = REQ_TYPE_SPECIAL; + req.cmd_flags = REQ_QUIET; ret = ide_do_drive_cmd(drive, &req, ide_wait); /* @@ -3116,9 +3117,9 @@ static int ide_cdrom_prep_pc(struct request *rq) static int ide_cdrom_prep_fn(request_queue_t *q, struct request *rq) { - if (rq->flags & REQ_CMD) + if (blk_fs_request(rq)) return ide_cdrom_prep_fs(q, rq); - else if (rq->flags & REQ_BLOCK_PC) + else if (blk_pc_request(rq)) return ide_cdrom_prep_pc(rq); return 0; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 7cf3eb023521..0a05a377d66a 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -699,7 +699,8 @@ static void idedisk_prepare_flush(request_queue_t *q, struct request *rq) rq->cmd[0] = WIN_FLUSH_CACHE; - rq->flags |= REQ_DRIVE_TASK; + rq->cmd_type = REQ_TYPE_ATA_TASK; + rq->cmd_flags |= REQ_SOFTBARRIER; rq->buffer = rq->cmd; } @@ -740,7 +741,7 @@ static int set_multcount(ide_drive_t *drive, int arg) if (drive->special.b.set_multmode) return -EBUSY; ide_init_drive_cmd (&rq); - rq.flags = REQ_DRIVE_CMD; + rq.cmd_type = REQ_TYPE_ATA_CMD; drive->mult_req = arg; drive->special.b.set_multmode = 1; (void) ide_do_drive_cmd (drive, &rq, ide_wait); diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 7c3a13e1cf64..c3546fe9af63 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -205,7 +205,7 @@ int ide_build_sglist(ide_drive_t *drive, struct request *rq) ide_hwif_t *hwif = HWIF(drive); struct scatterlist *sg = hwif->sg_table; - BUG_ON((rq->flags & REQ_DRIVE_TASKFILE) && rq->nr_sectors > 256); + BUG_ON((rq->cmd_type == REQ_TYPE_ATA_TASKFILE) && rq->nr_sectors > 256); ide_map_sg(drive, rq); diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index adbe9f76a505..0edc32204915 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -588,7 +588,7 @@ static int idefloppy_do_end_request(ide_drive_t *drive, int uptodate, int nsecs) /* Why does this happen? */ if (!rq) return 0; - if (!(rq->flags & REQ_SPECIAL)) { //if (!IDEFLOPPY_RQ_CMD (rq->cmd)) { + if (!blk_special_request(rq)) { /* our real local end request function */ ide_end_request(drive, uptodate, nsecs); return 0; @@ -689,7 +689,7 @@ static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struc ide_init_drive_cmd(rq); rq->buffer = (char *) pc; - rq->flags = REQ_SPECIAL; //rq->cmd = IDEFLOPPY_PC_RQ; + rq->cmd_type = REQ_TYPE_SPECIAL; rq->rq_disk = floppy->disk; (void) ide_do_drive_cmd(drive, rq, ide_preempt); } @@ -1250,7 +1250,7 @@ static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t pc->callback = &idefloppy_rw_callback; pc->rq = rq; pc->b_count = cmd == READ ? 0 : rq->bio->bi_size; - if (rq->flags & REQ_RW) + if (rq->cmd_flags & REQ_RW) set_bit(PC_WRITING, &pc->flags); pc->buffer = NULL; pc->request_transfer = pc->buffer_size = blocks * floppy->block_size; @@ -1303,7 +1303,7 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request idefloppy_do_end_request(drive, 0, 0); return ide_stopped; } - if (rq->flags & REQ_CMD) { + if (blk_fs_request(rq)) { if (((long)rq->sector % floppy->bs_factor) || (rq->nr_sectors % floppy->bs_factor)) { printk("%s: unsupported r/w request size\n", @@ -1313,9 +1313,9 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request } pc = idefloppy_next_pc_storage(drive); idefloppy_create_rw_cmd(floppy, pc, rq, block); - } else if (rq->flags & REQ_SPECIAL) { + } else if (blk_special_request(rq)) { pc = (idefloppy_pc_t *) rq->buffer; - } else if (rq->flags & REQ_BLOCK_PC) { + } else if (blk_pc_request(rq)) { pc = idefloppy_next_pc_storage(drive); if (idefloppy_blockpc_cmd(floppy, pc, rq)) { idefloppy_do_end_request(drive, 0, 0); @@ -1343,7 +1343,7 @@ static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc) ide_init_drive_cmd (&rq); rq.buffer = (char *) pc; - rq.flags = REQ_SPECIAL; // rq.cmd = IDEFLOPPY_PC_RQ; + rq.cmd_type = REQ_TYPE_SPECIAL; rq.rq_disk = floppy->disk; return ide_do_drive_cmd(drive, &rq, ide_wait); diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index fb6795236e76..3436b1f104eb 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -59,7 +59,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq, { int ret = 1; - BUG_ON(!(rq->flags & REQ_STARTED)); + BUG_ON(!blk_rq_started(rq)); /* * if failfast is set on a request, override number of sectors and @@ -244,7 +244,7 @@ int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq, spin_lock_irqsave(&ide_lock, flags); - BUG_ON(!(rq->flags & REQ_STARTED)); + BUG_ON(!blk_rq_started(rq)); /* * if failfast is set on a request, override number of sectors and @@ -366,7 +366,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) rq = HWGROUP(drive)->rq; spin_unlock_irqrestore(&ide_lock, flags); - if (rq->flags & REQ_DRIVE_CMD) { + if (rq->cmd_type == REQ_TYPE_ATA_CMD) { u8 *args = (u8 *) rq->buffer; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); @@ -376,7 +376,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) args[1] = err; args[2] = hwif->INB(IDE_NSECTOR_REG); } - } else if (rq->flags & REQ_DRIVE_TASK) { + } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) { u8 *args = (u8 *) rq->buffer; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); @@ -390,7 +390,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) args[5] = hwif->INB(IDE_HCYL_REG); args[6] = hwif->INB(IDE_SELECT_REG); } - } else if (rq->flags & REQ_DRIVE_TASKFILE) { + } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *args = (ide_task_t *) rq->special; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); @@ -587,7 +587,7 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat) return ide_stopped; /* retry only "normal" I/O: */ - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) { + if (!blk_fs_request(rq)) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; @@ -638,7 +638,7 @@ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg) return ide_stopped; /* retry only "normal" I/O: */ - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) { + if (!blk_fs_request(rq)) { rq->errors = 1; ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; @@ -808,7 +808,7 @@ void ide_map_sg(ide_drive_t *drive, struct request *rq) if (hwif->sg_mapped) /* needed by ide-scsi */ return; - if ((rq->flags & REQ_DRIVE_TASKFILE) == 0) { + if (rq->cmd_type != REQ_TYPE_ATA_TASKFILE) { hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg); } else { sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE); @@ -844,7 +844,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) { ide_hwif_t *hwif = HWIF(drive); - if (rq->flags & REQ_DRIVE_TASKFILE) { + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *args = rq->special; if (!args) @@ -866,7 +866,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, if (args->tf_out_flags.all != 0) return flagged_taskfile(drive, args); return do_rw_taskfile(drive, args); - } else if (rq->flags & REQ_DRIVE_TASK) { + } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) { u8 *args = rq->buffer; u8 sel; @@ -892,7 +892,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, hwif->OUTB(sel, IDE_SELECT_REG); ide_cmd(drive, args[0], args[2], &drive_cmd_intr); return ide_started; - } else if (rq->flags & REQ_DRIVE_CMD) { + } else if (rq->cmd_type == REQ_TYPE_ATA_CMD) { u8 *args = rq->buffer; if (!args) @@ -980,7 +980,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) ide_startstop_t startstop; sector_t block; - BUG_ON(!(rq->flags & REQ_STARTED)); + BUG_ON(!blk_rq_started(rq)); #ifdef DEBUG printk("%s: start_request: current=0x%08lx\n", @@ -1013,9 +1013,9 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) if (!drive->special.all) { ide_driver_t *drv; - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) - return execute_drive_cmd(drive, rq); - else if (rq->flags & REQ_DRIVE_TASKFILE) + if (rq->cmd_type == REQ_TYPE_ATA_CMD || + rq->cmd_type == REQ_TYPE_ATA_TASK || + rq->cmd_type == REQ_TYPE_ATA_TASKFILE) return execute_drive_cmd(drive, rq); else if (blk_pm_request(rq)) { struct request_pm_state *pm = rq->end_io_data; @@ -1264,7 +1264,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) * We count how many times we loop here to make sure we service * all drives in the hwgroup without looping for ever */ - if (drive->blocked && !blk_pm_request(rq) && !(rq->flags & REQ_PREEMPT)) { + if (drive->blocked && !blk_pm_request(rq) && !(rq->cmd_flags & REQ_PREEMPT)) { drive = drive->next ? drive->next : hwgroup->drive; if (loops++ < 4 && !blk_queue_plugged(drive->queue)) goto again; @@ -1670,7 +1670,7 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs) void ide_init_drive_cmd (struct request *rq) { memset(rq, 0, sizeof(*rq)); - rq->flags = REQ_DRIVE_CMD; + rq->cmd_type = REQ_TYPE_ATA_CMD; rq->ref_count = 1; } @@ -1727,7 +1727,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio hwgroup->rq = NULL; if (action == ide_preempt || action == ide_head_wait) { where = ELEVATOR_INSERT_FRONT; - rq->flags |= REQ_PREEMPT; + rq->cmd_flags |= REQ_PREEMPT; } __elv_add_request(drive->queue, rq, where, 0); ide_do_request(hwgroup, IDE_NO_IRQ); diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 1feff23487d4..850ef63cc986 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -456,13 +456,14 @@ static void ide_dump_opcode(ide_drive_t *drive) spin_unlock(&ide_lock); if (!rq) return; - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { + if (rq->cmd_type == REQ_TYPE_ATA_CMD || + rq->cmd_type == REQ_TYPE_ATA_TASK) { char *args = rq->buffer; if (args) { opcode = args[0]; found = 1; } - } else if (rq->flags & REQ_DRIVE_TASKFILE) { + } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *args = rq->special; if (args) { task_struct_t *tf = (task_struct_t *) args->tfRegister; diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 7067ab997927..643e4b9ac651 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -1776,7 +1776,7 @@ static void idetape_create_request_sense_cmd (idetape_pc_t *pc) static void idetape_init_rq(struct request *rq, u8 cmd) { memset(rq, 0, sizeof(*rq)); - rq->flags = REQ_SPECIAL; + rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd[0] = cmd; } @@ -2433,12 +2433,12 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, rq->sector, rq->nr_sectors, rq->current_nr_sectors); #endif /* IDETAPE_DEBUG_LOG */ - if ((rq->flags & REQ_SPECIAL) == 0) { + if (!blk_special_request(rq)) { /* * We do not support buffer cache originated requests. */ printk(KERN_NOTICE "ide-tape: %s: Unsupported request in " - "request queue (%ld)\n", drive->name, rq->flags); + "request queue (%d)\n", drive->name, rq->cmd_type); ide_end_request(drive, 0, 0); return ide_stopped; } @@ -2768,7 +2768,7 @@ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_BUGS - if (rq == NULL || (rq->flags & REQ_SPECIAL) == 0) { + if (rq == NULL || !blk_special_request(rq)) { printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n"); return; } diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 97a9244312fc..1d0470c1f957 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -363,7 +363,7 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) { - if (rq->flags & REQ_DRIVE_TASKFILE) { + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *task = rq->special; if (task->tf_out_flags.all) { @@ -474,7 +474,7 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long struct request rq; memset(&rq, 0, sizeof(rq)); - rq.flags = REQ_DRIVE_TASKFILE; + rq.cmd_type = REQ_TYPE_ATA_TASKFILE; rq.buffer = buf; /* @@ -499,7 +499,7 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors; if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) - rq.flags |= REQ_RW; + rq.cmd_flags |= REQ_RW; } rq.special = args; @@ -737,7 +737,7 @@ static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf) struct request rq; ide_init_drive_cmd(&rq); - rq.flags = REQ_DRIVE_TASK; + rq.cmd_type = REQ_TYPE_ATA_TASK; rq.buffer = buf; return ide_do_drive_cmd(drive, &rq, ide_wait); } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 9c8468de1a75..9384a3fdde6c 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1217,7 +1217,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); - rq.flags = REQ_PM_SUSPEND; + rq.cmd_type = REQ_TYPE_PM_SUSPEND; rq.special = &args; rq.end_io_data = &rqpm; rqpm.pm_step = ide_pm_state_start_suspend; @@ -1238,7 +1238,7 @@ static int generic_ide_resume(struct device *dev) memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); - rq.flags = REQ_PM_RESUME; + rq.cmd_type = REQ_TYPE_PM_RESUME; rq.special = &args; rq.end_io_data = &rqpm; rqpm.pm_step = ide_pm_state_start_resume; diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c index aebecd8f51cc..4ab931145673 100644 --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c @@ -626,7 +626,7 @@ repeat: req->rq_disk->disk_name, (req->cmd == READ)?"read":"writ", cyl, head, sec, nsect, req->buffer); #endif - if (req->flags & REQ_CMD) { + if (blk_fs_request(req)) { switch (rq_data_dir(req)) { case READ: hd_out(disk,nsect,sec,head,cyl,WIN_READ,&read_intr); diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index 2a374ccb30dd..2b2d45d7baaa 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c @@ -126,7 +126,8 @@ static struct request *get_failover_req(struct emc_handler *h, memset(&rq->cmd, 0, BLK_MAX_CDB); rq->timeout = EMC_FAILOVER_TIMEOUT; - rq->flags |= (REQ_BLOCK_PC | REQ_FAILFAST | REQ_NOMERGE); + rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; return rq; } diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 1ddc2fb429d5..eaba81bf2eca 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -390,9 +390,9 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req) } /* request is already processed by us, so return */ - if (req->flags & REQ_SPECIAL) { + if (blk_special_request(req)) { osm_debug("REQ_SPECIAL already set!\n"); - req->flags |= REQ_DONTPREP; + req->cmd_flags |= REQ_DONTPREP; return BLKPREP_OK; } @@ -411,7 +411,8 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req) ireq = req->special; /* do not come back here */ - req->flags |= REQ_DONTPREP | REQ_SPECIAL; + req->cmd_type = REQ_TYPE_SPECIAL; + req->cmd_flags |= REQ_DONTPREP; return BLKPREP_OK; }; diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c index 74f8cdeeff0f..4ccdd82b680f 100644 --- a/drivers/mmc/mmc_queue.c +++ b/drivers/mmc/mmc_queue.c @@ -28,7 +28,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) struct mmc_queue *mq = q->queuedata; int ret = BLKPREP_KILL; - if (req->flags & REQ_SPECIAL) { + if (blk_special_request(req)) { /* * Special commands already have the command * blocks already setup in req->special. @@ -36,7 +36,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) BUG_ON(!req->special); ret = BLKPREP_OK; - } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { + } else if (blk_fs_request(req) || blk_pc_request(req)) { /* * Block I/O requests need translating according * to the protocol. @@ -50,7 +50,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) } if (ret == BLKPREP_OK) - req->flags |= REQ_DONTPREP; + req->cmd_flags |= REQ_DONTPREP; return ret; } diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 458d3c8ae1ee..6baf5fe14230 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -46,7 +46,7 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, nsect = req->current_nr_sectors; buf = req->buffer; - if (!(req->flags & REQ_CMD)) + if (!blk_fs_request(req)) return 0; if (block + nsect > get_capacity(req->rq_disk)) diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 9d051e5687ea..222a8a71a5e8 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -529,7 +529,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) } cqr->retries = DIAG_MAX_RETRIES; cqr->buildclk = get_clock(); - if (req->flags & REQ_FAILFAST) + if (req->cmd_flags & REQ_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->device = device; cqr->expires = DIAG_TIMEOUT; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index b7a7fac3f7c3..5ecea3e4fdef 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1266,7 +1266,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) recid++; } } - if (req->flags & REQ_FAILFAST) + if (req->cmd_flags & REQ_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->device = device; cqr->expires = 5 * 60 * HZ; /* 5 minutes */ diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index e85015be109b..80926c548228 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -344,7 +344,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) recid++; } } - if (req->flags & REQ_FAILFAST) + if (req->cmd_flags & REQ_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->device = device; cqr->expires = 5 * 60 * HZ; /* 5 minutes */ diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 5dcef48d414f..10353379a074 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -2862,7 +2862,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) aic_dev->r_total++; ptr = aic_dev->r_bins; } - if(cmd->device->simple_tags && cmd->request->flags & REQ_HARDBARRIER) + if(cmd->device->simple_tags && cmd->request->cmd_flags & REQ_HARDBARRIER) { aic_dev->barrier_total++; if(scb->tag_action == MSG_ORDERED_Q_TAG) @@ -10158,7 +10158,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd, /* We always force TEST_UNIT_READY to untagged */ if (cmd->cmnd[0] != TEST_UNIT_READY && sdptr->simple_tags) { - if (req->flags & REQ_HARDBARRIER) + if (req->cmd_flags & REQ_HARDBARRIER) { if(sdptr->ordered_tags) { diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 94d1de55607f..65b19695ebe2 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -344,7 +344,7 @@ static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_co pc->buffer = buf; pc->c[0] = REQUEST_SENSE; pc->c[4] = pc->request_transfer = pc->buffer_size = SCSI_SENSE_BUFFERSIZE; - rq->flags = REQ_SENSE; + rq->cmd_type = REQ_TYPE_SENSE; pc->timeout = jiffies + WAIT_READY; /* NOTE! Save the failed packet command in "rq->buffer" */ rq->buffer = (void *) failed_command->special; @@ -398,12 +398,12 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) int errors = rq->errors; unsigned long flags; - if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) { + if (!blk_special_request(rq) && !blk_sense_request(rq)) { ide_end_request(drive, uptodate, nrsecs); return 0; } ide_end_drive_cmd (drive, 0, 0); - if (rq->flags & REQ_SENSE) { + if (blk_sense_request(rq)) { idescsi_pc_t *opc = (idescsi_pc_t *) rq->buffer; if (log) { printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number); @@ -712,7 +712,7 @@ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *r printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); #endif /* IDESCSI_DEBUG_LOG */ - if (rq->flags & (REQ_SPECIAL|REQ_SENSE)) { + if (blk_sense_request(rq) || blk_special_request(rq)) { return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->special); } blk_dump_rq_flags(rq, "ide-scsi: unsup command"); @@ -938,7 +938,7 @@ static int idescsi_queue (struct scsi_cmnd *cmd, ide_init_drive_cmd (rq); rq->special = (char *) pc; - rq->flags = REQ_SPECIAL; + rq->cmd_type = REQ_TYPE_SPECIAL; spin_unlock_irq(host->host_lock); rq->rq_disk = scsi->disk; (void) ide_do_drive_cmd (drive, rq, ide_end); @@ -992,7 +992,7 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd) */ printk (KERN_ERR "ide-scsi: cmd aborted!\n"); - if (scsi->pc->rq->flags & REQ_SENSE) + if (blk_sense_request(scsi->pc->rq)) kfree(scsi->pc->buffer); kfree(scsi->pc->rq); kfree(scsi->pc); @@ -1042,7 +1042,7 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd) /* kill current request */ blkdev_dequeue_request(req); end_that_request_last(req, 0); - if (req->flags & REQ_SENSE) + if (blk_sense_request(req)) kfree(scsi->pc->buffer); kfree(scsi->pc); scsi->pc = NULL; diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c index 0bd9c60e6455..aa60a5f1fbc3 100644 --- a/drivers/scsi/pluto.c +++ b/drivers/scsi/pluto.c @@ -67,7 +67,6 @@ static void __init pluto_detect_done(Scsi_Cmnd *SCpnt) static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt) { - SCpnt->request->rq_status = RQ_SCSI_DONE; PLND(("Detect done %08lx\n", (long)SCpnt)) if (atomic_dec_and_test (&fcss)) up(&fc_sem); @@ -166,7 +165,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt) SCpnt->cmd_len = COMMAND_SIZE(INQUIRY); - SCpnt->request->rq_status = RQ_SCSI_BUSY; + SCpnt->request->cmd_flags &= ~REQ_STARTED; SCpnt->done = pluto_detect_done; SCpnt->request_bufflen = 256; @@ -178,7 +177,8 @@ int __init pluto_detect(struct scsi_host_template *tpnt) for (retry = 0; retry < 5; retry++) { for (i = 0; i < fcscount; i++) { if (!fcs[i].fc) break; - if (fcs[i].cmd.request->rq_status != RQ_SCSI_DONE) { + if (!(fcs[i].cmd.request->cmd_flags & REQ_STARTED)) { + fcs[i].cmd.request->cmd_flags |= REQ_STARTED; disable_irq(fcs[i].fc->irq); PLND(("queuecommand %d %d\n", retry, i)) fcp_scsi_queuecommand (&(fcs[i].cmd), diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index d6743b959a72..71084728eb42 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -82,7 +82,7 @@ static void scsi_unprep_request(struct request *req) { struct scsi_cmnd *cmd = req->special; - req->flags &= ~REQ_DONTPREP; + req->cmd_flags &= ~REQ_DONTPREP; req->special = NULL; scsi_put_command(cmd); @@ -196,7 +196,8 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, req->sense_len = 0; req->retries = retries; req->timeout = timeout; - req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL | REQ_QUIET; + req->cmd_type = REQ_TYPE_BLOCK_PC; + req->cmd_flags |= flags | REQ_QUIET | REQ_PREEMPT; /* * head injection *required* here otherwise quiesce won't work @@ -397,7 +398,8 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, req = blk_get_request(sdev->request_queue, write, gfp); if (!req) goto free_sense; - req->flags |= REQ_BLOCK_PC | REQ_QUIET; + req->cmd_type = REQ_TYPE_BLOCK_PC; + req->cmd_flags |= REQ_QUIET; if (use_sg) err = scsi_req_map_sg(req, buffer, use_sg, bufflen, gfp); @@ -933,7 +935,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) break; } } - if (!(req->flags & REQ_QUIET)) { + if (!(req->cmd_flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, "Device not ready: "); scsi_print_sense_hdr("", &sshdr); @@ -941,7 +943,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) scsi_end_request(cmd, 0, this_count, 1); return; case VOLUME_OVERFLOW: - if (!(req->flags & REQ_QUIET)) { + if (!(req->cmd_flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, "Volume overflow, CDB: "); __scsi_print_command(cmd->cmnd); @@ -963,7 +965,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) return; } if (result) { - if (!(req->flags & REQ_QUIET)) { + if (!(req->cmd_flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, "SCSI error: return code = 0x%08x\n", result); @@ -995,7 +997,7 @@ static int scsi_init_io(struct scsi_cmnd *cmd) /* * if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer */ - if ((req->flags & REQ_BLOCK_PC) && !req->bio) { + if (blk_pc_request(req) && !req->bio) { cmd->request_bufflen = req->data_len; cmd->request_buffer = req->data; req->buffer = req->data; @@ -1139,13 +1141,12 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) * these two cases differently. We differentiate by looking * at request->cmd, as this tells us the real story. */ - if (req->flags & REQ_SPECIAL && req->special) { + if (blk_special_request(req) && req->special) cmd = req->special; - } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { - - if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) { - if(specials_only == SDEV_QUIESCE || - specials_only == SDEV_BLOCK) + else if (blk_pc_request(req) || blk_fs_request(req)) { + if (unlikely(specials_only) && !(req->cmd_flags & REQ_PREEMPT)){ + if (specials_only == SDEV_QUIESCE || + specials_only == SDEV_BLOCK) goto defer; sdev_printk(KERN_ERR, sdev, @@ -1153,7 +1154,6 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) goto kill; } - /* * Now try and find a command block that we can use. */ @@ -1184,7 +1184,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) * lock. We hope REQ_STARTED prevents anything untoward from * happening now. */ - if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { + if (blk_fs_request(req) || blk_pc_request(req)) { int ret; /* @@ -1216,7 +1216,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) /* * Initialize the actual SCSI command for this request. */ - if (req->flags & REQ_BLOCK_PC) { + if (blk_pc_request(req)) { scsi_setup_blk_pc_cmnd(cmd); } else if (req->rq_disk) { struct scsi_driver *drv; @@ -1233,7 +1233,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) /* * The request is now prepped, no need to come back here */ - req->flags |= REQ_DONTPREP; + req->cmd_flags |= REQ_DONTPREP; return BLKPREP_OK; defer: @@ -1454,8 +1454,9 @@ static void scsi_request_fn(struct request_queue *q) if (unlikely(cmd == NULL)) { printk(KERN_CRIT "impossible request in %s.\n" "please mail a stack trace to " - "linux-scsi@vger.kernel.org", + "linux-scsi@vger.kernel.org\n", __FUNCTION__); + blk_dump_rq_flags(req, "foo"); BUG(); } spin_lock(shost->host_lock); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 638cff41d436..10bc99c911fa 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -443,8 +443,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) SCpnt->cmnd[0] = READ_6; SCpnt->sc_data_direction = DMA_FROM_DEVICE; } else { - printk(KERN_ERR "sd: Unknown command %lx\n", rq->flags); -/* overkill panic("Unknown sd command %lx\n", rq->flags); */ + printk(KERN_ERR "sd: Unknown command %x\n", rq->cmd_flags); return 0; } @@ -840,7 +839,7 @@ static int sd_issue_flush(struct device *dev, sector_t *error_sector) static void sd_prepare_flush(request_queue_t *q, struct request *rq) { memset(rq->cmd, 0, sizeof(rq->cmd)); - rq->flags |= REQ_BLOCK_PC; + rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = SD_TIMEOUT; rq->cmd[0] = SYNCHRONIZE_CACHE; rq->cmd_len = 10; diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index 2f8073b73bf3..7f9bcef6adfa 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -2017,7 +2017,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done != cmd)) { - if(cmd->request->flags & REQ_CMD) { + if(blk_fs_request(cmd->request)) { sun3scsi_dma_setup(d, count, rq_data_dir(cmd->request)); sun3_dma_setup_done = cmd; diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 837173415d4c..44a99aeb8180 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -524,7 +524,7 @@ static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance) static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd, int write_flag) { - if(cmd->request->flags & REQ_CMD) + if(blk_fs_request(cmd->request)) return wanted; else return 0; diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index 008a82ab8521..f5742b84b27a 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -458,7 +458,7 @@ static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance) static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd, int write_flag) { - if(cmd->request->flags & REQ_CMD) + if(blk_fs_request(cmd->request)) return wanted; else return 0; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index cfde8b3ee919..b2a412cf468f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -120,6 +120,86 @@ struct request_list { wait_queue_head_t wait[2]; }; +/* + * request command types + */ +enum rq_cmd_type_bits { + REQ_TYPE_FS = 1, /* fs request */ + REQ_TYPE_BLOCK_PC, /* scsi command */ + REQ_TYPE_SENSE, /* sense request */ + REQ_TYPE_PM_SUSPEND, /* suspend request */ + REQ_TYPE_PM_RESUME, /* resume request */ + REQ_TYPE_PM_SHUTDOWN, /* shutdown request */ + REQ_TYPE_FLUSH, /* flush request */ + REQ_TYPE_SPECIAL, /* driver defined type */ + REQ_TYPE_LINUX_BLOCK, /* generic block layer message */ + /* + * for ATA/ATAPI devices. this really doesn't belong here, ide should + * use REQ_TYPE_SPECIAL and use rq->cmd[0] with the range of driver + * private REQ_LB opcodes to differentiate what type of request this is + */ + REQ_TYPE_ATA_CMD, + REQ_TYPE_ATA_TASK, + REQ_TYPE_ATA_TASKFILE, +}; + +/* + * For request of type REQ_TYPE_LINUX_BLOCK, rq->cmd[0] is the opcode being + * sent down (similar to how REQ_TYPE_BLOCK_PC means that ->cmd[] holds a + * SCSI cdb. + * + * 0x00 -> 0x3f are driver private, to be used for whatever purpose they need, + * typically to differentiate REQ_TYPE_SPECIAL requests. + * + */ +enum { + /* + * just examples for now + */ + REQ_LB_OP_EJECT = 0x40, /* eject request */ + REQ_LB_OP_FLUSH = 0x41, /* flush device */ +}; + +/* + * request type modified bits. first three bits match BIO_RW* bits, important + */ +enum rq_flag_bits { + __REQ_RW, /* not set, read. set, write */ + __REQ_FAILFAST, /* no low level driver retries */ + __REQ_SORTED, /* elevator knows about this request */ + __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */ + __REQ_HARDBARRIER, /* may not be passed by drive either */ + __REQ_FUA, /* forced unit access */ + __REQ_NOMERGE, /* don't touch this for merging */ + __REQ_STARTED, /* drive already may have started this one */ + __REQ_DONTPREP, /* don't call prep for this one */ + __REQ_QUEUED, /* uses queueing */ + __REQ_ELVPRIV, /* elevator private data attached */ + __REQ_FAILED, /* set if the request failed */ + __REQ_QUIET, /* don't worry about errors */ + __REQ_PREEMPT, /* set for "ide_preempt" requests */ + __REQ_ORDERED_COLOR, /* is before or after barrier */ + __REQ_RW_SYNC, /* request is sync (O_DIRECT) */ + __REQ_NR_BITS, /* stops here */ +}; + +#define REQ_RW (1 << __REQ_RW) +#define REQ_FAILFAST (1 << __REQ_FAILFAST) +#define REQ_SORTED (1 << __REQ_SORTED) +#define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER) +#define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER) +#define REQ_FUA (1 << __REQ_FUA) +#define REQ_NOMERGE (1 << __REQ_NOMERGE) +#define REQ_STARTED (1 << __REQ_STARTED) +#define REQ_DONTPREP (1 << __REQ_DONTPREP) +#define REQ_QUEUED (1 << __REQ_QUEUED) +#define REQ_ELVPRIV (1 << __REQ_ELVPRIV) +#define REQ_FAILED (1 << __REQ_FAILED) +#define REQ_QUIET (1 << __REQ_QUIET) +#define REQ_PREEMPT (1 << __REQ_PREEMPT) +#define REQ_ORDERED_COLOR (1 << __REQ_ORDERED_COLOR) +#define REQ_RW_SYNC (1 << __REQ_RW_SYNC) + #define BLK_MAX_CDB 16 /* @@ -129,7 +209,8 @@ struct request { struct list_head queuelist; struct list_head donelist; - unsigned long flags; /* see REQ_ bits below */ + unsigned int cmd_flags; + enum rq_cmd_type_bits cmd_type; /* Maintain bio traversal state for part by part I/O submission. * hard_* are block layer internals, no driver should touch them! @@ -202,73 +283,7 @@ struct request { }; /* - * first three bits match BIO_RW* bits, important - */ -enum rq_flag_bits { - __REQ_RW, /* not set, read. set, write */ - __REQ_FAILFAST, /* no low level driver retries */ - __REQ_SORTED, /* elevator knows about this request */ - __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */ - __REQ_HARDBARRIER, /* may not be passed by drive either */ - __REQ_FUA, /* forced unit access */ - __REQ_CMD, /* is a regular fs rw request */ - __REQ_NOMERGE, /* don't touch this for merging */ - __REQ_STARTED, /* drive already may have started this one */ - __REQ_DONTPREP, /* don't call prep for this one */ - __REQ_QUEUED, /* uses queueing */ - __REQ_ELVPRIV, /* elevator private data attached */ - /* - * for ATA/ATAPI devices - */ - __REQ_PC, /* packet command (special) */ - __REQ_BLOCK_PC, /* queued down pc from block layer */ - __REQ_SENSE, /* sense retrival */ - - __REQ_FAILED, /* set if the request failed */ - __REQ_QUIET, /* don't worry about errors */ - __REQ_SPECIAL, /* driver suplied command */ - __REQ_DRIVE_CMD, - __REQ_DRIVE_TASK, - __REQ_DRIVE_TASKFILE, - __REQ_PREEMPT, /* set for "ide_preempt" requests */ - __REQ_PM_SUSPEND, /* suspend request */ - __REQ_PM_RESUME, /* resume request */ - __REQ_PM_SHUTDOWN, /* shutdown request */ - __REQ_ORDERED_COLOR, /* is before or after barrier */ - __REQ_RW_SYNC, /* request is sync (O_DIRECT) */ - __REQ_NR_BITS, /* stops here */ -}; - -#define REQ_RW (1 << __REQ_RW) -#define REQ_FAILFAST (1 << __REQ_FAILFAST) -#define REQ_SORTED (1 << __REQ_SORTED) -#define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER) -#define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER) -#define REQ_FUA (1 << __REQ_FUA) -#define REQ_CMD (1 << __REQ_CMD) -#define REQ_NOMERGE (1 << __REQ_NOMERGE) -#define REQ_STARTED (1 << __REQ_STARTED) -#define REQ_DONTPREP (1 << __REQ_DONTPREP) -#define REQ_QUEUED (1 << __REQ_QUEUED) -#define REQ_ELVPRIV (1 << __REQ_ELVPRIV) -#define REQ_PC (1 << __REQ_PC) -#define REQ_BLOCK_PC (1 << __REQ_BLOCK_PC) -#define REQ_SENSE (1 << __REQ_SENSE) -#define REQ_FAILED (1 << __REQ_FAILED) -#define REQ_QUIET (1 << __REQ_QUIET) -#define REQ_SPECIAL (1 << __REQ_SPECIAL) -#define REQ_DRIVE_CMD (1 << __REQ_DRIVE_CMD) -#define REQ_DRIVE_TASK (1 << __REQ_DRIVE_TASK) -#define REQ_DRIVE_TASKFILE (1 << __REQ_DRIVE_TASKFILE) -#define REQ_PREEMPT (1 << __REQ_PREEMPT) -#define REQ_PM_SUSPEND (1 << __REQ_PM_SUSPEND) -#define REQ_PM_RESUME (1 << __REQ_PM_RESUME) -#define REQ_PM_SHUTDOWN (1 << __REQ_PM_SHUTDOWN) -#define REQ_ORDERED_COLOR (1 << __REQ_ORDERED_COLOR) -#define REQ_RW_SYNC (1 << __REQ_RW_SYNC) - -/* - * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME + * State information carried for REQ_TYPE_PM_SUSPEND and REQ_TYPE_PM_RESUME * requests. Some step values could eventually be made generic. */ struct request_pm_state @@ -490,25 +505,28 @@ enum { #define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) #define blk_queue_flushing(q) ((q)->ordseq) -#define blk_fs_request(rq) ((rq)->flags & REQ_CMD) -#define blk_pc_request(rq) ((rq)->flags & REQ_BLOCK_PC) -#define blk_noretry_request(rq) ((rq)->flags & REQ_FAILFAST) -#define blk_rq_started(rq) ((rq)->flags & REQ_STARTED) +#define blk_fs_request(rq) ((rq)->cmd_type == REQ_TYPE_FS) +#define blk_pc_request(rq) ((rq)->cmd_type == REQ_TYPE_BLOCK_PC) +#define blk_special_request(rq) ((rq)->cmd_type == REQ_TYPE_SPECIAL) +#define blk_sense_request(rq) ((rq)->cmd_type == REQ_TYPE_SENSE) + +#define blk_noretry_request(rq) ((rq)->cmd_flags & REQ_FAILFAST) +#define blk_rq_started(rq) ((rq)->cmd_flags & REQ_STARTED) #define blk_account_rq(rq) (blk_rq_started(rq) && blk_fs_request(rq)) -#define blk_pm_suspend_request(rq) ((rq)->flags & REQ_PM_SUSPEND) -#define blk_pm_resume_request(rq) ((rq)->flags & REQ_PM_RESUME) +#define blk_pm_suspend_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_SUSPEND) +#define blk_pm_resume_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_RESUME) #define blk_pm_request(rq) \ - ((rq)->flags & (REQ_PM_SUSPEND | REQ_PM_RESUME)) + (blk_pm_suspend_request(rq) || blk_pm_resume_request(rq)) -#define blk_sorted_rq(rq) ((rq)->flags & REQ_SORTED) -#define blk_barrier_rq(rq) ((rq)->flags & REQ_HARDBARRIER) -#define blk_fua_rq(rq) ((rq)->flags & REQ_FUA) +#define blk_sorted_rq(rq) ((rq)->cmd_flags & REQ_SORTED) +#define blk_barrier_rq(rq) ((rq)->cmd_flags & REQ_HARDBARRIER) +#define blk_fua_rq(rq) ((rq)->cmd_flags & REQ_FUA) #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) -#define rq_data_dir(rq) ((rq)->flags & 1) +#define rq_data_dir(rq) ((rq)->cmd_flags & 1) static inline int blk_queue_full(struct request_queue *q, int rw) { @@ -541,7 +559,7 @@ static inline void blk_clear_queue_full(struct request_queue *q, int rw) #define RQ_NOMERGE_FLAGS \ (REQ_NOMERGE | REQ_STARTED | REQ_HARDBARRIER | REQ_SOFTBARRIER) #define rq_mergeable(rq) \ - (!((rq)->flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq))) + (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq))) /* * noop, requests are automagically marked as active/inactive by I/O @@ -737,7 +755,7 @@ extern void blk_put_queue(request_queue_t *); */ #define blk_queue_tag_depth(q) ((q)->queue_tags->busy) #define blk_queue_tag_queue(q) ((q)->queue_tags->busy < (q)->queue_tags->max_depth) -#define blk_rq_tagged(rq) ((rq)->flags & REQ_QUEUED) +#define blk_rq_tagged(rq) ((rq)->cmd_flags & REQ_QUEUED) extern int blk_queue_start_tag(request_queue_t *, struct request *); extern struct request *blk_queue_find_tag(request_queue_t *, int); extern void blk_queue_end_tag(request_queue_t *, struct request *); diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index 7520cc1ff9e2..ea48eb1b3fd3 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -148,7 +148,7 @@ static inline void blk_add_trace_rq(struct request_queue *q, struct request *rq, u32 what) { struct blk_trace *bt = q->blk_trace; - int rw = rq->flags & 0x03; + int rw = rq->cmd_flags & 0x03; if (likely(!bt)) return; diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h index d04d05adfa9b..bbf66219b769 100644 --- a/include/scsi/scsi_tcq.h +++ b/include/scsi/scsi_tcq.h @@ -100,7 +100,7 @@ static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg) struct scsi_device *sdev = cmd->device; if (blk_rq_tagged(req)) { - if (sdev->ordered_tags && req->flags & REQ_HARDBARRIER) + if (sdev->ordered_tags && req->cmd_flags & REQ_HARDBARRIER) *msg++ = MSG_ORDERED_TAG; else *msg++ = MSG_SIMPLE_TAG; -- cgit v1.2.3 From 9817064b68fef7e4580c6df1ea597e106b9ff88b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Jul 2006 09:23:08 +0200 Subject: [PATCH] elevator: move the backmerging logic into the elevator core Right now, every IO scheduler implements its own backmerging (except for noop, which does no merging). That results in duplicated code for essentially the same operation, which is never a good thing. This patch moves the backmerging out of the io schedulers and into the elevator core. We save 1.6kb of text and as a bonus get backmerging for noop as well. Win-win! Signed-off-by: Jens Axboe --- block/as-iosched.c | 139 +------------------------------------------- block/cfq-iosched.c | 86 +-------------------------- block/deadline-iosched.c | 128 +---------------------------------------- block/elevator.c | 147 ++++++++++++++++++++++++++++++++++++++++++----- block/ll_rw_blk.c | 2 + include/linux/blkdev.h | 17 +----- include/linux/elevator.h | 2 + 7 files changed, 146 insertions(+), 375 deletions(-) (limited to 'include/linux') diff --git a/block/as-iosched.c b/block/as-iosched.c index ad1cc4077819..6db494333c3a 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -95,7 +94,6 @@ struct as_data { struct as_rq *next_arq[2]; /* next in sort order */ sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */ - struct hlist_head *hash; /* request hash */ unsigned long exit_prob; /* probability a task will exit while being waited on */ @@ -161,11 +159,6 @@ struct as_rq { struct io_context *io_context; /* The submitting task */ - /* - * request hash, key is the ending offset (for back merge lookup) - */ - struct hlist_node hash; - /* * expire fifo */ @@ -272,77 +265,6 @@ static void as_put_io_context(struct as_rq *arq) put_io_context(arq->io_context); } -/* - * the back merge hash support functions - */ -static const int as_hash_shift = 6; -#define AS_HASH_BLOCK(sec) ((sec) >> 3) -#define AS_HASH_FN(sec) (hash_long(AS_HASH_BLOCK((sec)), as_hash_shift)) -#define AS_HASH_ENTRIES (1 << as_hash_shift) -#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) - -static inline void __as_del_arq_hash(struct as_rq *arq) -{ - hlist_del_init(&arq->hash); -} - -static inline void as_del_arq_hash(struct as_rq *arq) -{ - if (!hlist_unhashed(&arq->hash)) - __as_del_arq_hash(arq); -} - -static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq) -{ - struct request *rq = arq->request; - - BUG_ON(!hlist_unhashed(&arq->hash)); - - hlist_add_head(&arq->hash, &ad->hash[AS_HASH_FN(rq_hash_key(rq))]); -} - -/* - * move hot entry to front of chain - */ -static inline void as_hot_arq_hash(struct as_data *ad, struct as_rq *arq) -{ - struct request *rq = arq->request; - struct hlist_head *head = &ad->hash[AS_HASH_FN(rq_hash_key(rq))]; - - if (hlist_unhashed(&arq->hash)) { - WARN_ON(1); - return; - } - - if (&arq->hash != head->first) { - hlist_del(&arq->hash); - hlist_add_head(&arq->hash, head); - } -} - -static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset) -{ - struct hlist_head *hash_list = &ad->hash[AS_HASH_FN(offset)]; - struct hlist_node *entry, *next; - struct as_rq *arq; - - hlist_for_each_entry_safe(arq, entry, next, hash_list, hash) { - struct request *__rq = arq->request; - - BUG_ON(hlist_unhashed(&arq->hash)); - - if (!rq_mergeable(__rq)) { - as_del_arq_hash(arq); - continue; - } - - if (rq_hash_key(__rq) == offset) - return __rq; - } - - return NULL; -} - /* * rb tree support functions */ @@ -1060,7 +982,6 @@ static void as_remove_queued_request(request_queue_t *q, struct request *rq) ad->next_arq[data_dir] = as_find_next_arq(ad, arq); list_del_init(&arq->fifo); - as_del_arq_hash(arq); as_del_arq_rb(ad, arq); } @@ -1349,8 +1270,6 @@ static void as_add_request(request_queue_t *q, struct request *rq) } as_add_arq_rb(ad, arq); - if (rq_mergeable(arq->request)) - as_add_arq_hash(ad, arq); /* * set expire time (only used for reads) and add to fifo list @@ -1428,42 +1347,17 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio) struct as_data *ad = q->elevator->elevator_data; sector_t rb_key = bio->bi_sector + bio_sectors(bio); struct request *__rq; - int ret; - - /* - * see if the merge hash can satisfy a back merge - */ - __rq = as_find_arq_hash(ad, bio->bi_sector); - if (__rq) { - BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector); - - if (elv_rq_merge_ok(__rq, bio)) { - ret = ELEVATOR_BACK_MERGE; - goto out; - } - } /* * check for front merge */ __rq = as_find_arq_rb(ad, rb_key, bio_data_dir(bio)); - if (__rq) { - BUG_ON(rb_key != rq_rb_key(__rq)); - - if (elv_rq_merge_ok(__rq, bio)) { - ret = ELEVATOR_FRONT_MERGE; - goto out; - } + if (__rq && elv_rq_merge_ok(__rq, bio)) { + *req = __rq; + return ELEVATOR_FRONT_MERGE; } return ELEVATOR_NO_MERGE; -out: - if (ret) { - if (rq_mergeable(__rq)) - as_hot_arq_hash(ad, RQ_DATA(__rq)); - } - *req = __rq; - return ret; } static void as_merged_request(request_queue_t *q, struct request *req) @@ -1471,12 +1365,6 @@ static void as_merged_request(request_queue_t *q, struct request *req) struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = RQ_DATA(req); - /* - * hash always needs to be repositioned, key is end sector - */ - as_del_arq_hash(arq); - as_add_arq_hash(ad, arq); - /* * if the merge was a front merge, we need to reposition request */ @@ -1501,13 +1389,6 @@ static void as_merged_requests(request_queue_t *q, struct request *req, BUG_ON(!arq); BUG_ON(!anext); - /* - * reposition arq (this is the merged request) in hash, and in rbtree - * in case of a front merge - */ - as_del_arq_hash(arq); - as_add_arq_hash(ad, arq); - if (rq_rb_key(req) != arq->rb_key) { as_del_arq_rb(ad, arq); as_add_arq_rb(ad, arq); @@ -1591,7 +1472,6 @@ static int as_set_request(request_queue_t *q, struct request *rq, arq->request = rq; arq->state = AS_RQ_PRESCHED; arq->io_context = NULL; - INIT_HLIST_NODE(&arq->hash); INIT_LIST_HEAD(&arq->fifo); rq->elevator_private = arq; return 0; @@ -1628,7 +1508,6 @@ static void as_exit_queue(elevator_t *e) mempool_destroy(ad->arq_pool); put_io_context(ad->io_context); - kfree(ad->hash); kfree(ad); } @@ -1639,7 +1518,6 @@ static void as_exit_queue(elevator_t *e) static void *as_init_queue(request_queue_t *q, elevator_t *e) { struct as_data *ad; - int i; if (!arq_pool) return NULL; @@ -1651,17 +1529,9 @@ static void *as_init_queue(request_queue_t *q, elevator_t *e) ad->q = q; /* Identify what queue the data belongs to */ - ad->hash = kmalloc_node(sizeof(struct hlist_head)*AS_HASH_ENTRIES, - GFP_KERNEL, q->node); - if (!ad->hash) { - kfree(ad); - return NULL; - } - ad->arq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, arq_pool, q->node); if (!ad->arq_pool) { - kfree(ad->hash); kfree(ad); return NULL; } @@ -1672,9 +1542,6 @@ static void *as_init_queue(request_queue_t *q, elevator_t *e) init_timer(&ad->antic_timer); INIT_WORK(&ad->antic_work, as_work_handler, q); - for (i = 0; i < AS_HASH_ENTRIES; i++) - INIT_HLIST_HEAD(&ad->hash[i]); - INIT_LIST_HEAD(&ad->fifo_list[REQ_SYNC]); INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]); ad->sort_list[REQ_SYNC] = RB_ROOT; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3a3aee08ec5f..1b803c0c90f1 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -41,16 +41,6 @@ static DEFINE_SPINLOCK(cfq_exit_lock); #define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT) #define list_entry_qhash(entry) hlist_entry((entry), struct cfq_queue, cfq_hash) -/* - * for the hash of crq inside the cfqq - */ -#define CFQ_MHASH_SHIFT 6 -#define CFQ_MHASH_BLOCK(sec) ((sec) >> 3) -#define CFQ_MHASH_ENTRIES (1 << CFQ_MHASH_SHIFT) -#define CFQ_MHASH_FN(sec) hash_long(CFQ_MHASH_BLOCK(sec), CFQ_MHASH_SHIFT) -#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) -#define list_entry_hash(ptr) hlist_entry((ptr), struct cfq_rq, hash) - #define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list) #define list_entry_fifo(ptr) list_entry((ptr), struct request, queuelist) @@ -112,11 +102,6 @@ struct cfq_data { */ struct hlist_head *cfq_hash; - /* - * global crq hash for all queues - */ - struct hlist_head *crq_hash; - mempool_t *crq_pool; int rq_in_driver; @@ -203,7 +188,6 @@ struct cfq_rq { struct rb_node rb_node; sector_t rb_key; struct request *request; - struct hlist_node hash; struct cfq_queue *cfq_queue; struct cfq_io_context *io_context; @@ -271,42 +255,6 @@ static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsi static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *); static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask); -/* - * lots of deadline iosched dupes, can be abstracted later... - */ -static inline void cfq_del_crq_hash(struct cfq_rq *crq) -{ - hlist_del_init(&crq->hash); -} - -static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq) -{ - const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request)); - - hlist_add_head(&crq->hash, &cfqd->crq_hash[hash_idx]); -} - -static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset) -{ - struct hlist_head *hash_list = &cfqd->crq_hash[CFQ_MHASH_FN(offset)]; - struct hlist_node *entry, *next; - - hlist_for_each_safe(entry, next, hash_list) { - struct cfq_rq *crq = list_entry_hash(entry); - struct request *__rq = crq->request; - - if (!rq_mergeable(__rq)) { - cfq_del_crq_hash(crq); - continue; - } - - if (rq_hash_key(__rq) == offset) - return __rq; - } - - return NULL; -} - /* * scheduler run of queue, if there are requests pending and no one in the * driver that will restart queueing @@ -677,7 +625,6 @@ static void cfq_remove_request(struct request *rq) list_del_init(&rq->queuelist); cfq_del_crq_rb(crq); - cfq_del_crq_hash(crq); } static int @@ -685,34 +632,20 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) { struct cfq_data *cfqd = q->elevator->elevator_data; struct request *__rq; - int ret; - - __rq = cfq_find_rq_hash(cfqd, bio->bi_sector); - if (__rq && elv_rq_merge_ok(__rq, bio)) { - ret = ELEVATOR_BACK_MERGE; - goto out; - } __rq = cfq_find_rq_fmerge(cfqd, bio); if (__rq && elv_rq_merge_ok(__rq, bio)) { - ret = ELEVATOR_FRONT_MERGE; - goto out; + *req = __rq; + return ELEVATOR_FRONT_MERGE; } return ELEVATOR_NO_MERGE; -out: - *req = __rq; - return ret; } static void cfq_merged_request(request_queue_t *q, struct request *req) { - struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_rq *crq = RQ_DATA(req); - cfq_del_crq_hash(crq); - cfq_add_crq_hash(cfqd, crq); - if (rq_rb_key(req) != crq->rb_key) { struct cfq_queue *cfqq = crq->cfq_queue; @@ -1825,9 +1758,6 @@ static void cfq_insert_request(request_queue_t *q, struct request *rq) list_add_tail(&rq->queuelist, &cfqq->fifo); - if (rq_mergeable(rq)) - cfq_add_crq_hash(cfqd, crq); - cfq_crq_enqueued(cfqd, cfqq, crq); } @@ -2055,7 +1985,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, RB_CLEAR_NODE(&crq->rb_node); crq->rb_key = 0; crq->request = rq; - INIT_HLIST_NODE(&crq->hash); crq->cfq_queue = cfqq; crq->io_context = cic; @@ -2221,7 +2150,6 @@ static void cfq_exit_queue(elevator_t *e) cfq_shutdown_timer_wq(cfqd); mempool_destroy(cfqd->crq_pool); - kfree(cfqd->crq_hash); kfree(cfqd->cfq_hash); kfree(cfqd); } @@ -2246,20 +2174,14 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e) INIT_LIST_HEAD(&cfqd->empty_list); INIT_LIST_HEAD(&cfqd->cic_list); - cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL); - if (!cfqd->crq_hash) - goto out_crqhash; - cfqd->cfq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL); if (!cfqd->cfq_hash) - goto out_cfqhash; + goto out_crqhash; cfqd->crq_pool = mempool_create_slab_pool(BLKDEV_MIN_RQ, crq_pool); if (!cfqd->crq_pool) goto out_crqpool; - for (i = 0; i < CFQ_MHASH_ENTRIES; i++) - INIT_HLIST_HEAD(&cfqd->crq_hash[i]); for (i = 0; i < CFQ_QHASH_ENTRIES; i++) INIT_HLIST_HEAD(&cfqd->cfq_hash[i]); @@ -2289,8 +2211,6 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e) return cfqd; out_crqpool: kfree(cfqd->cfq_hash); -out_cfqhash: - kfree(cfqd->crq_hash); out_crqhash: kfree(cfqd); return NULL; diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index c7ca9f0b6498..b66e820f544d 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c @@ -12,7 +12,6 @@ #include #include #include -#include #include /* @@ -24,13 +23,6 @@ static const int writes_starved = 2; /* max times reads can starve a write */ static const int fifo_batch = 16; /* # of sequential requests treated as one by the above parameters. For throughput. */ -static const int deadline_hash_shift = 5; -#define DL_HASH_BLOCK(sec) ((sec) >> 3) -#define DL_HASH_FN(sec) (hash_long(DL_HASH_BLOCK((sec)), deadline_hash_shift)) -#define DL_HASH_ENTRIES (1 << deadline_hash_shift) -#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) -#define ON_HASH(drq) (!hlist_unhashed(&(drq)->hash)) - struct deadline_data { /* * run time data @@ -46,7 +38,6 @@ struct deadline_data { * next in sort order. read, write or both are NULL */ struct deadline_rq *next_drq[2]; - struct hlist_head *hash; /* request hash */ unsigned int batching; /* number of sequential requests made */ sector_t last_sector; /* head position */ unsigned int starved; /* times reads have starved writes */ @@ -74,11 +65,6 @@ struct deadline_rq { struct request *request; - /* - * request hash, key is the ending offset (for back merge lookup) - */ - struct hlist_node hash; - /* * expire fifo */ @@ -92,69 +78,6 @@ static kmem_cache_t *drq_pool; #define RQ_DATA(rq) ((struct deadline_rq *) (rq)->elevator_private) -/* - * the back merge hash support functions - */ -static inline void __deadline_del_drq_hash(struct deadline_rq *drq) -{ - hlist_del_init(&drq->hash); -} - -static inline void deadline_del_drq_hash(struct deadline_rq *drq) -{ - if (ON_HASH(drq)) - __deadline_del_drq_hash(drq); -} - -static inline void -deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq) -{ - struct request *rq = drq->request; - - BUG_ON(ON_HASH(drq)); - - hlist_add_head(&drq->hash, &dd->hash[DL_HASH_FN(rq_hash_key(rq))]); -} - -/* - * move hot entry to front of chain - */ -static inline void -deadline_hot_drq_hash(struct deadline_data *dd, struct deadline_rq *drq) -{ - struct request *rq = drq->request; - struct hlist_head *head = &dd->hash[DL_HASH_FN(rq_hash_key(rq))]; - - if (ON_HASH(drq) && &drq->hash != head->first) { - hlist_del(&drq->hash); - hlist_add_head(&drq->hash, head); - } -} - -static struct request * -deadline_find_drq_hash(struct deadline_data *dd, sector_t offset) -{ - struct hlist_head *hash_list = &dd->hash[DL_HASH_FN(offset)]; - struct hlist_node *entry, *next; - struct deadline_rq *drq; - - hlist_for_each_entry_safe(drq, entry, next, hash_list, hash) { - struct request *__rq = drq->request; - - BUG_ON(!ON_HASH(drq)); - - if (!rq_mergeable(__rq)) { - __deadline_del_drq_hash(drq); - continue; - } - - if (rq_hash_key(__rq) == offset) - return __rq; - } - - return NULL; -} - /* * rb tree support functions */ @@ -267,22 +190,19 @@ deadline_add_request(struct request_queue *q, struct request *rq) { struct deadline_data *dd = q->elevator->elevator_data; struct deadline_rq *drq = RQ_DATA(rq); - const int data_dir = rq_data_dir(drq->request); deadline_add_drq_rb(dd, drq); + /* * set expire time (only used for reads) and add to fifo list */ drq->expires = jiffies + dd->fifo_expire[data_dir]; list_add_tail(&drq->fifo, &dd->fifo_list[data_dir]); - - if (rq_mergeable(rq)) - deadline_add_drq_hash(dd, drq); } /* - * remove rq from rbtree, fifo, and hash + * remove rq from rbtree and fifo. */ static void deadline_remove_request(request_queue_t *q, struct request *rq) { @@ -291,7 +211,6 @@ static void deadline_remove_request(request_queue_t *q, struct request *rq) list_del_init(&drq->fifo); deadline_del_drq_rb(dd, drq); - deadline_del_drq_hash(drq); } static int @@ -301,19 +220,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) struct request *__rq; int ret; - /* - * see if the merge hash can satisfy a back merge - */ - __rq = deadline_find_drq_hash(dd, bio->bi_sector); - if (__rq) { - BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector); - - if (elv_rq_merge_ok(__rq, bio)) { - ret = ELEVATOR_BACK_MERGE; - goto out; - } - } - /* * check for front merge */ @@ -333,8 +239,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; out: - if (ret) - deadline_hot_drq_hash(dd, RQ_DATA(__rq)); *req = __rq; return ret; } @@ -344,12 +248,6 @@ static void deadline_merged_request(request_queue_t *q, struct request *req) struct deadline_data *dd = q->elevator->elevator_data; struct deadline_rq *drq = RQ_DATA(req); - /* - * hash always needs to be repositioned, key is end sector - */ - deadline_del_drq_hash(drq); - deadline_add_drq_hash(dd, drq); - /* * if the merge was a front merge, we need to reposition request */ @@ -370,13 +268,6 @@ deadline_merged_requests(request_queue_t *q, struct request *req, BUG_ON(!drq); BUG_ON(!dnext); - /* - * reposition drq (this is the merged request) in hash, and in rbtree - * in case of a front merge - */ - deadline_del_drq_hash(drq); - deadline_add_drq_hash(dd, drq); - if (rq_rb_key(req) != drq->rb_key) { deadline_del_drq_rb(dd, drq); deadline_add_drq_rb(dd, drq); @@ -594,7 +485,6 @@ static void deadline_exit_queue(elevator_t *e) BUG_ON(!list_empty(&dd->fifo_list[WRITE])); mempool_destroy(dd->drq_pool); - kfree(dd->hash); kfree(dd); } @@ -605,7 +495,6 @@ static void deadline_exit_queue(elevator_t *e) static void *deadline_init_queue(request_queue_t *q, elevator_t *e) { struct deadline_data *dd; - int i; if (!drq_pool) return NULL; @@ -615,24 +504,13 @@ static void *deadline_init_queue(request_queue_t *q, elevator_t *e) return NULL; memset(dd, 0, sizeof(*dd)); - dd->hash = kmalloc_node(sizeof(struct hlist_head)*DL_HASH_ENTRIES, - GFP_KERNEL, q->node); - if (!dd->hash) { - kfree(dd); - return NULL; - } - dd->drq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, drq_pool, q->node); if (!dd->drq_pool) { - kfree(dd->hash); kfree(dd); return NULL; } - for (i = 0; i < DL_HASH_ENTRIES; i++) - INIT_HLIST_HEAD(&dd->hash[i]); - INIT_LIST_HEAD(&dd->fifo_list[READ]); INIT_LIST_HEAD(&dd->fifo_list[WRITE]); dd->sort_list[READ] = RB_ROOT; @@ -667,8 +545,6 @@ deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio, RB_CLEAR_NODE(&drq->rb_node); drq->request = rq; - INIT_HLIST_NODE(&drq->hash); - INIT_LIST_HEAD(&drq->fifo); rq->elevator_private = drq; diff --git a/block/elevator.c b/block/elevator.c index 4ac97b642042..cff1102dac9d 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -33,12 +33,23 @@ #include #include #include +#include #include static DEFINE_SPINLOCK(elv_list_lock); static LIST_HEAD(elv_list); +/* + * Merge hash stuff. + */ +static const int elv_hash_shift = 6; +#define ELV_HASH_BLOCK(sec) ((sec) >> 3) +#define ELV_HASH_FN(sec) (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift)) +#define ELV_HASH_ENTRIES (1 << elv_hash_shift) +#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) +#define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash)) + /* * can we safely merge with this request? */ @@ -153,25 +164,41 @@ static struct kobj_type elv_ktype; static elevator_t *elevator_alloc(struct elevator_type *e) { - elevator_t *eq = kmalloc(sizeof(elevator_t), GFP_KERNEL); - if (eq) { - memset(eq, 0, sizeof(*eq)); - eq->ops = &e->ops; - eq->elevator_type = e; - kobject_init(&eq->kobj); - snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched"); - eq->kobj.ktype = &elv_ktype; - mutex_init(&eq->sysfs_lock); - } else { - elevator_put(e); - } + elevator_t *eq; + int i; + + eq = kmalloc(sizeof(elevator_t), GFP_KERNEL); + if (unlikely(!eq)) + goto err; + + memset(eq, 0, sizeof(*eq)); + eq->ops = &e->ops; + eq->elevator_type = e; + kobject_init(&eq->kobj); + snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched"); + eq->kobj.ktype = &elv_ktype; + mutex_init(&eq->sysfs_lock); + + eq->hash = kmalloc(sizeof(struct hlist_head) * ELV_HASH_ENTRIES, GFP_KERNEL); + if (!eq->hash) + goto err; + + for (i = 0; i < ELV_HASH_ENTRIES; i++) + INIT_HLIST_HEAD(&eq->hash[i]); + return eq; +err: + kfree(eq); + elevator_put(e); + return NULL; } static void elevator_release(struct kobject *kobj) { elevator_t *e = container_of(kobj, elevator_t, kobj); + elevator_put(e->elevator_type); + kfree(e->hash); kfree(e); } @@ -223,6 +250,53 @@ void elevator_exit(elevator_t *e) kobject_put(&e->kobj); } +static inline void __elv_rqhash_del(struct request *rq) +{ + hlist_del_init(&rq->hash); +} + +static void elv_rqhash_del(request_queue_t *q, struct request *rq) +{ + if (ELV_ON_HASH(rq)) + __elv_rqhash_del(rq); +} + +static void elv_rqhash_add(request_queue_t *q, struct request *rq) +{ + elevator_t *e = q->elevator; + + BUG_ON(ELV_ON_HASH(rq)); + hlist_add_head(&rq->hash, &e->hash[ELV_HASH_FN(rq_hash_key(rq))]); +} + +static void elv_rqhash_reposition(request_queue_t *q, struct request *rq) +{ + __elv_rqhash_del(rq); + elv_rqhash_add(q, rq); +} + +static struct request *elv_rqhash_find(request_queue_t *q, sector_t offset) +{ + elevator_t *e = q->elevator; + struct hlist_head *hash_list = &e->hash[ELV_HASH_FN(offset)]; + struct hlist_node *entry, *next; + struct request *rq; + + hlist_for_each_entry_safe(rq, entry, next, hash_list, hash) { + BUG_ON(!ELV_ON_HASH(rq)); + + if (unlikely(!rq_mergeable(rq))) { + __elv_rqhash_del(rq); + continue; + } + + if (rq_hash_key(rq) == offset) + return rq; + } + + return NULL; +} + /* * Insert rq into dispatch queue of q. Queue lock must be held on * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be @@ -235,6 +309,9 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) if (q->last_merge == rq) q->last_merge = NULL; + + elv_rqhash_del(q, rq); + q->nr_sorted--; boundary = q->end_sector; @@ -258,11 +335,32 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) list_add(&rq->queuelist, entry); } +/* + * This should be in elevator.h, but that requires pulling in rq and q + */ +void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) +{ + if (q->last_merge == rq) + q->last_merge = NULL; + + elv_rqhash_del(q, rq); + + q->nr_sorted--; + + q->end_sector = rq_end_sector(rq); + q->boundary_rq = rq; + list_add_tail(&rq->queuelist, &q->queue_head); +} + int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) { elevator_t *e = q->elevator; + struct request *__rq; int ret; + /* + * First try one-hit cache. + */ if (q->last_merge) { ret = elv_try_merge(q->last_merge, bio); if (ret != ELEVATOR_NO_MERGE) { @@ -271,6 +369,15 @@ int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) } } + /* + * See if our hash lookup can find a potential backmerge. + */ + __rq = elv_rqhash_find(q, bio->bi_sector); + if (__rq && elv_rq_merge_ok(__rq, bio)) { + *req = __rq; + return ELEVATOR_BACK_MERGE; + } + if (e->ops->elevator_merge_fn) return e->ops->elevator_merge_fn(q, req, bio); @@ -284,6 +391,8 @@ void elv_merged_request(request_queue_t *q, struct request *rq) if (e->ops->elevator_merged_fn) e->ops->elevator_merged_fn(q, rq); + elv_rqhash_reposition(q, rq); + q->last_merge = rq; } @@ -294,8 +403,11 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, if (e->ops->elevator_merge_req_fn) e->ops->elevator_merge_req_fn(q, rq, next); - q->nr_sorted--; + elv_rqhash_reposition(q, rq); + elv_rqhash_del(q, next); + + q->nr_sorted--; q->last_merge = rq; } @@ -371,8 +483,12 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) BUG_ON(!blk_fs_request(rq)); rq->cmd_flags |= REQ_SORTED; q->nr_sorted++; - if (q->last_merge == NULL && rq_mergeable(rq)) - q->last_merge = rq; + if (rq_mergeable(rq)) { + elv_rqhash_add(q, rq); + if (!q->last_merge) + q->last_merge = rq; + } + /* * Some ioscheds (cfq) run q->request_fn directly, so * rq cannot be accessed after calling @@ -557,6 +673,7 @@ struct request *elv_next_request(request_queue_t *q) void elv_dequeue_request(request_queue_t *q, struct request *rq) { BUG_ON(list_empty(&rq->queuelist)); + BUG_ON(ELV_ON_HASH(rq)); list_del_init(&rq->queuelist); diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 9b91bb70c5ed..9cbf7b550c78 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -281,6 +281,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq) { INIT_LIST_HEAD(&rq->queuelist); INIT_LIST_HEAD(&rq->donelist); + INIT_HLIST_NODE(&rq->hash); rq->errors = 0; rq->rq_status = RQ_ACTIVE; @@ -2700,6 +2701,7 @@ void __blk_put_request(request_queue_t *q, struct request *req) int priv = req->cmd_flags & REQ_ELVPRIV; BUG_ON(!list_empty(&req->queuelist)); + BUG_ON(!hlist_unhashed(&req->hash)); blk_free_request(q, req); freed_request(q, rw, priv); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index b2a412cf468f..8f5486964671 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -229,6 +229,8 @@ struct request { struct bio *bio; struct bio *biotail; + struct hlist_node hash; /* merge hash */ + void *elevator_private; void *completion_data; @@ -696,21 +698,6 @@ static inline void blkdev_dequeue_request(struct request *req) elv_dequeue_request(req->q, req); } -/* - * This should be in elevator.h, but that requires pulling in rq and q - */ -static inline void elv_dispatch_add_tail(struct request_queue *q, - struct request *rq) -{ - if (q->last_merge == rq) - q->last_merge = NULL; - q->nr_sorted--; - - q->end_sector = rq_end_sector(rq); - q->boundary_rq = rq; - list_add_tail(&rq->queuelist, &q->queue_head); -} - /* * Access functions for manipulating queue properties */ diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 1713ace808bf..2c270e90b33e 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -82,12 +82,14 @@ struct elevator_queue struct kobject kobj; struct elevator_type *elevator_type; struct mutex sysfs_lock; + struct hlist_head *hash; }; /* * block elevator interface */ extern void elv_dispatch_sort(request_queue_t *, struct request *); +extern void elv_dispatch_add_tail(request_queue_t *, struct request *); extern void elv_add_request(request_queue_t *, struct request *, int, int); extern void __elv_add_request(request_queue_t *, struct request *, int, int); extern void elv_insert(request_queue_t *, struct request *, int); -- cgit v1.2.3 From 10fd48f2376db52f08bf0420d2c4f580e39269e1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 11 Jul 2006 21:15:52 +0200 Subject: [PATCH] rbtree: fixed reversed RB_EMPTY_NODE and rb_next/prev The conditions got reserved. Also make rb_next() and rb_prev() check for the empty condition. Signed-off-by: Jens Axboe --- block/as-iosched.c | 4 ++-- include/linux/rbtree.h | 2 +- lib/rbtree.c | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/block/as-iosched.c b/block/as-iosched.c index 6db494333c3a..9d0f15a54c64 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -336,7 +336,7 @@ static void as_add_arq_rb(struct as_data *ad, struct as_rq *arq) static inline void as_del_arq_rb(struct as_data *ad, struct as_rq *arq) { - if (!RB_EMPTY_NODE(&arq->rb_node)) { + if (RB_EMPTY_NODE(&arq->rb_node)) { WARN_ON(1); return; } @@ -1039,7 +1039,7 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) struct request *rq = arq->request; const int data_dir = arq->is_sync; - BUG_ON(!RB_EMPTY_NODE(&arq->rb_node)); + BUG_ON(RB_EMPTY_NODE(&arq->rb_node)); as_antic_stop(ad); ad->antic_status = ANTIC_OFF; diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index 8d5382e62c08..344bc3495ddb 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h @@ -133,7 +133,7 @@ static inline void rb_set_color(struct rb_node *rb, int color) #define rb_entry(ptr, type, member) container_of(ptr, type, member) #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) -#define RB_EMPTY_NODE(node) (rb_parent(node) != node) +#define RB_EMPTY_NODE(node) (rb_parent(node) == node) #define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) extern void rb_insert_color(struct rb_node *, struct rb_root *); diff --git a/lib/rbtree.c b/lib/rbtree.c index 1e55ba1c2edf..48499c2d88cc 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c @@ -322,6 +322,9 @@ struct rb_node *rb_next(struct rb_node *node) { struct rb_node *parent; + if (rb_parent(node) == node) + return NULL; + /* If we have a right-hand child, go down and then left as far as we can. */ if (node->rb_right) { @@ -348,6 +351,9 @@ struct rb_node *rb_prev(struct rb_node *node) { struct rb_node *parent; + if (rb_parent(node) == node) + return NULL; + /* If we have a left-hand child, go down and then right as far as we can. */ if (node->rb_left) { -- cgit v1.2.3 From 2e662b65f05d550b6799ed6bfa9963b82279e6b7 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 13 Jul 2006 11:55:04 +0200 Subject: [PATCH] elevator: abstract out the rbtree sort handling The rbtree sort/lookup/reposition logic is mostly duplicated in cfq/deadline/as, so move it to the elevator core. The io schedulers still provide the actual rb root, as we don't want to impose any sort of specific handling on the schedulers. Introduce the helpers and rb_node in struct request to help migrate the IO schedulers. Signed-off-by: Jens Axboe --- block/elevator.c | 123 +++++++++++++++++++++++++++++++++++++++++------ block/ll_rw_blk.c | 7 +-- include/linux/blkdev.h | 1 + include/linux/elevator.h | 18 ++++++- 4 files changed, 130 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/block/elevator.c b/block/elevator.c index cff1102dac9d..cbbc36ba016a 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -239,6 +239,8 @@ int elevator_init(request_queue_t *q, char *name) return ret; } +EXPORT_SYMBOL(elevator_init); + void elevator_exit(elevator_t *e) { mutex_lock(&e->sysfs_lock); @@ -250,6 +252,8 @@ void elevator_exit(elevator_t *e) kobject_put(&e->kobj); } +EXPORT_SYMBOL(elevator_exit); + static inline void __elv_rqhash_del(struct request *rq) { hlist_del_init(&rq->hash); @@ -297,10 +301,69 @@ static struct request *elv_rqhash_find(request_queue_t *q, sector_t offset) return NULL; } +/* + * RB-tree support functions for inserting/lookup/removal of requests + * in a sorted RB tree. + */ +struct request *elv_rb_add(struct rb_root *root, struct request *rq) +{ + struct rb_node **p = &root->rb_node; + struct rb_node *parent = NULL; + struct request *__rq; + + while (*p) { + parent = *p; + __rq = rb_entry(parent, struct request, rb_node); + + if (rq->sector < __rq->sector) + p = &(*p)->rb_left; + else if (rq->sector > __rq->sector) + p = &(*p)->rb_right; + else + return __rq; + } + + rb_link_node(&rq->rb_node, parent, p); + rb_insert_color(&rq->rb_node, root); + return NULL; +} + +EXPORT_SYMBOL(elv_rb_add); + +void elv_rb_del(struct rb_root *root, struct request *rq) +{ + BUG_ON(RB_EMPTY_NODE(&rq->rb_node)); + rb_erase(&rq->rb_node, root); + RB_CLEAR_NODE(&rq->rb_node); +} + +EXPORT_SYMBOL(elv_rb_del); + +struct request *elv_rb_find(struct rb_root *root, sector_t sector) +{ + struct rb_node *n = root->rb_node; + struct request *rq; + + while (n) { + rq = rb_entry(n, struct request, rb_node); + + if (sector < rq->sector) + n = n->rb_left; + else if (sector > rq->sector) + n = n->rb_right; + else + return rq; + } + + return NULL; +} + +EXPORT_SYMBOL(elv_rb_find); + /* * Insert rq into dispatch queue of q. Queue lock must be held on - * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be - * appended to the dispatch queue. To be used by specific elevators. + * entry. rq is sort insted into the dispatch queue. To be used by + * specific elevators. */ void elv_dispatch_sort(request_queue_t *q, struct request *rq) { @@ -335,8 +398,12 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) list_add(&rq->queuelist, entry); } +EXPORT_SYMBOL(elv_dispatch_sort); + /* - * This should be in elevator.h, but that requires pulling in rq and q + * Insert rq into dispatch queue of q. Queue lock must be held on + * entry. rq is added to the back of the dispatch queue. To be used by + * specific elevators. */ void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) { @@ -352,6 +419,8 @@ void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) list_add_tail(&rq->queuelist, &q->queue_head); } +EXPORT_SYMBOL(elv_dispatch_add_tail); + int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) { elevator_t *e = q->elevator; @@ -384,14 +453,15 @@ int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; } -void elv_merged_request(request_queue_t *q, struct request *rq) +void elv_merged_request(request_queue_t *q, struct request *rq, int type) { elevator_t *e = q->elevator; if (e->ops->elevator_merged_fn) - e->ops->elevator_merged_fn(q, rq); + e->ops->elevator_merged_fn(q, rq, type); - elv_rqhash_reposition(q, rq); + if (type == ELEVATOR_BACK_MERGE) + elv_rqhash_reposition(q, rq); q->last_merge = rq; } @@ -577,6 +647,8 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, elv_insert(q, rq, where); } +EXPORT_SYMBOL(__elv_add_request); + void elv_add_request(request_queue_t *q, struct request *rq, int where, int plug) { @@ -587,6 +659,8 @@ void elv_add_request(request_queue_t *q, struct request *rq, int where, spin_unlock_irqrestore(q->queue_lock, flags); } +EXPORT_SYMBOL(elv_add_request); + static inline struct request *__elv_next_request(request_queue_t *q) { struct request *rq; @@ -670,6 +744,8 @@ struct request *elv_next_request(request_queue_t *q) return rq; } +EXPORT_SYMBOL(elv_next_request); + void elv_dequeue_request(request_queue_t *q, struct request *rq) { BUG_ON(list_empty(&rq->queuelist)); @@ -686,6 +762,8 @@ void elv_dequeue_request(request_queue_t *q, struct request *rq) q->in_flight++; } +EXPORT_SYMBOL(elv_dequeue_request); + int elv_queue_empty(request_queue_t *q) { elevator_t *e = q->elevator; @@ -699,6 +777,8 @@ int elv_queue_empty(request_queue_t *q) return 1; } +EXPORT_SYMBOL(elv_queue_empty); + struct request *elv_latter_request(request_queue_t *q, struct request *rq) { elevator_t *e = q->elevator; @@ -1025,11 +1105,26 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) return len; } -EXPORT_SYMBOL(elv_dispatch_sort); -EXPORT_SYMBOL(elv_add_request); -EXPORT_SYMBOL(__elv_add_request); -EXPORT_SYMBOL(elv_next_request); -EXPORT_SYMBOL(elv_dequeue_request); -EXPORT_SYMBOL(elv_queue_empty); -EXPORT_SYMBOL(elevator_exit); -EXPORT_SYMBOL(elevator_init); +struct request *elv_rb_former_request(request_queue_t *q, struct request *rq) +{ + struct rb_node *rbprev = rb_prev(&rq->rb_node); + + if (rbprev) + return rb_entry_rq(rbprev); + + return NULL; +} + +EXPORT_SYMBOL(elv_rb_former_request); + +struct request *elv_rb_latter_request(request_queue_t *q, struct request *rq) +{ + struct rb_node *rbnext = rb_next(&rq->rb_node); + + if (rbnext) + return rb_entry_rq(rbnext); + + return NULL; +} + +EXPORT_SYMBOL(elv_rb_latter_request); diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 9cbf7b550c78..d388486e98bb 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -281,11 +281,12 @@ static inline void rq_init(request_queue_t *q, struct request *rq) { INIT_LIST_HEAD(&rq->queuelist); INIT_LIST_HEAD(&rq->donelist); - INIT_HLIST_NODE(&rq->hash); rq->errors = 0; rq->rq_status = RQ_ACTIVE; rq->bio = rq->biotail = NULL; + INIT_HLIST_NODE(&rq->hash); + RB_CLEAR_NODE(&rq->rb_node); rq->ioprio = 0; rq->buffer = NULL; rq->ref_count = 1; @@ -2943,7 +2944,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) req->ioprio = ioprio_best(req->ioprio, prio); drive_stat_acct(req, nr_sectors, 0); if (!attempt_back_merge(q, req)) - elv_merged_request(q, req); + elv_merged_request(q, req, el_ret); goto out; case ELEVATOR_FRONT_MERGE: @@ -2970,7 +2971,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) req->ioprio = ioprio_best(req->ioprio, prio); drive_stat_acct(req, nr_sectors, 0); if (!attempt_front_merge(q, req)) - elv_merged_request(q, req); + elv_merged_request(q, req, el_ret); goto out; /* ELV_NO_MERGE: elevator says don't/can't merge. */ diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 8f5486964671..a905c4934a55 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -230,6 +230,7 @@ struct request { struct bio *biotail; struct hlist_node hash; /* merge hash */ + struct rb_node rb_node; /* sort/lookup */ void *elevator_private; void *completion_data; diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 2c270e90b33e..95b2a04b969c 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -6,7 +6,7 @@ typedef int (elevator_merge_fn) (request_queue_t *, struct request **, typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *); -typedef void (elevator_merged_fn) (request_queue_t *, struct request *); +typedef void (elevator_merged_fn) (request_queue_t *, struct request *, int); typedef int (elevator_dispatch_fn) (request_queue_t *, int); @@ -96,7 +96,7 @@ extern void elv_insert(request_queue_t *, struct request *, int); extern int elv_merge(request_queue_t *, struct request **, struct bio *); extern void elv_merge_requests(request_queue_t *, struct request *, struct request *); -extern void elv_merged_request(request_queue_t *, struct request *); +extern void elv_merged_request(request_queue_t *, struct request *, int); extern void elv_dequeue_request(request_queue_t *, struct request *); extern void elv_requeue_request(request_queue_t *, struct request *); extern int elv_queue_empty(request_queue_t *); @@ -126,6 +126,19 @@ extern int elevator_init(request_queue_t *, char *); extern void elevator_exit(elevator_t *); extern int elv_rq_merge_ok(struct request *, struct bio *); +/* + * Helper functions. + */ +extern struct request *elv_rb_former_request(request_queue_t *, struct request *); +extern struct request *elv_rb_latter_request(request_queue_t *, struct request *); + +/* + * rb support functions. + */ +extern struct request *elv_rb_add(struct rb_root *, struct request *); +extern void elv_rb_del(struct rb_root *, struct request *); +extern struct request *elv_rb_find(struct rb_root *, sector_t); + /* * Return values from elevator merger */ @@ -151,5 +164,6 @@ enum { }; #define rq_end_sector(rq) ((rq)->sector + (rq)->nr_sectors) +#define rb_entry_rq(node) rb_entry((node), struct request, rb_node) #endif -- cgit v1.2.3 From 1fbfdfcddff4df188b24d9d05271a76a85064583 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 11 Jul 2006 21:49:15 +0200 Subject: [PATCH] elevator: introduce a way to reuse rq for internal FIFO handling The io schedulers can use this instead of having to allocate space for it themselves. Signed-off-by: Jens Axboe --- include/linux/elevator.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include/linux') diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 95b2a04b969c..0e7b1a733919 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -166,4 +166,16 @@ enum { #define rq_end_sector(rq) ((rq)->sector + (rq)->nr_sectors) #define rb_entry_rq(node) rb_entry((node), struct request, rb_node) +/* + * Hack to reuse the donelist list_head as the fifo time holder while + * the request is in the io scheduler. Saves an unsigned long in rq. + */ +#define rq_fifo_time(rq) ((unsigned long) (rq)->donelist.next) +#define rq_set_fifo_time(rq,exp) ((rq)->donelist.next = (void *) (exp)) +#define rq_entry_fifo(ptr) list_entry((ptr), struct request, queuelist) +#define rq_fifo_clear(rq) do { \ + list_del_init(&(rq)->queuelist); \ + INIT_LIST_HEAD(&(rq)->donelist); \ + } while (0) + #endif -- cgit v1.2.3 From 9e2585a8a23f3a42f815b2a638725d85a921cd65 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Jul 2006 09:26:13 +0200 Subject: [PATCH] as-iosched: remove arq->is_sync member We can track this in struct request. Signed-off-by: Jens Axboe Signed-off-by: Nick Piggin --- block/as-iosched.c | 36 ++++++++++++++---------------------- include/linux/blkdev.h | 5 +++++ 2 files changed, 19 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/block/as-iosched.c b/block/as-iosched.c index c2665467950e..dca0b0563ca0 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -151,7 +151,6 @@ struct as_rq { struct io_context *io_context; /* The submitting task */ - unsigned int is_sync; enum arq_state state; }; @@ -241,7 +240,7 @@ static void as_put_io_context(struct as_rq *arq) aic = arq->io_context->aic; - if (arq->is_sync == REQ_SYNC && aic) { + if (rq_is_sync(arq->request) && aic) { spin_lock(&aic->lock); set_bit(AS_TASK_IORUNNING, &aic->state); aic->last_end_request = jiffies; @@ -254,14 +253,13 @@ static void as_put_io_context(struct as_rq *arq) /* * rb tree support functions */ -#define ARQ_RB_ROOT(ad, arq) (&(ad)->sort_list[(arq)->is_sync]) +#define RQ_RB_ROOT(ad, rq) (&(ad)->sort_list[rq_is_sync((rq))]) static void as_add_arq_rb(struct as_data *ad, struct request *rq) { - struct as_rq *arq = RQ_DATA(rq); struct request *alias; - while ((unlikely(alias = elv_rb_add(ARQ_RB_ROOT(ad, arq), rq)))) { + while ((unlikely(alias = elv_rb_add(RQ_RB_ROOT(ad, rq), rq)))) { as_move_to_dispatch(ad, RQ_DATA(alias)); as_antic_stop(ad); } @@ -269,7 +267,7 @@ static void as_add_arq_rb(struct as_data *ad, struct request *rq) static inline void as_del_arq_rb(struct as_data *ad, struct request *rq) { - elv_rb_del(ARQ_RB_ROOT(ad, RQ_DATA(rq)), rq); + elv_rb_del(RQ_RB_ROOT(ad, rq), rq); } /* @@ -300,13 +298,13 @@ as_choose_req(struct as_data *ad, struct as_rq *arq1, struct as_rq *arq2) if (arq2 == NULL) return arq1; - data_dir = arq1->is_sync; + data_dir = rq_is_sync(arq1->request); last = ad->last_sector[data_dir]; s1 = arq1->request->sector; s2 = arq2->request->sector; - BUG_ON(data_dir != arq2->is_sync); + BUG_ON(data_dir != rq_is_sync(arq2->request)); /* * Strict one way elevator _except_ in the case where we allow @@ -377,7 +375,7 @@ static struct as_rq *as_find_next_arq(struct as_data *ad, struct as_rq *arq) if (rbnext) next = RQ_DATA(rb_entry_rq(rbnext)); else { - const int data_dir = arq->is_sync; + const int data_dir = rq_is_sync(last); rbnext = rb_first(&ad->sort_list[data_dir]); if (rbnext && rbnext != &last->rb_node) @@ -538,8 +536,7 @@ static void as_update_seekdist(struct as_data *ad, struct as_io_context *aic, static void as_update_iohist(struct as_data *ad, struct as_io_context *aic, struct request *rq) { - struct as_rq *arq = RQ_DATA(rq); - int data_dir = arq->is_sync; + int data_dir = rq_is_sync(rq); unsigned long thinktime = 0; sector_t seek_dist; @@ -674,7 +671,7 @@ static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq) return 1; } - if (arq && arq->is_sync == REQ_SYNC && as_close_req(ad, aic, arq)) { + if (arq && rq_is_sync(arq->request) && as_close_req(ad, aic, arq)) { /* * Found a close request that is not one of ours. * @@ -758,7 +755,7 @@ static int as_can_anticipate(struct as_data *ad, struct as_rq *arq) */ static void as_update_arq(struct as_data *ad, struct as_rq *arq) { - const int data_dir = arq->is_sync; + const int data_dir = rq_is_sync(arq->request); /* keep the next_arq cache up to date */ ad->next_arq[data_dir] = as_choose_req(ad, arq, ad->next_arq[data_dir]); @@ -835,7 +832,7 @@ static void as_completed_request(request_queue_t *q, struct request *rq) * actually serviced. This should help devices with big TCQ windows * and writeback caches */ - if (ad->new_batch && ad->batch_data_dir == arq->is_sync) { + if (ad->new_batch && ad->batch_data_dir == rq_is_sync(rq)) { update_write_batch(ad); ad->current_batch_expires = jiffies + ad->batch_expire[REQ_SYNC]; @@ -868,7 +865,7 @@ out: static void as_remove_queued_request(request_queue_t *q, struct request *rq) { struct as_rq *arq = RQ_DATA(rq); - const int data_dir = arq->is_sync; + const int data_dir = rq_is_sync(rq); struct as_data *ad = q->elevator->elevator_data; WARN_ON(arq->state != AS_RQ_QUEUED); @@ -941,7 +938,7 @@ static inline int as_batch_expired(struct as_data *ad) static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) { struct request *rq = arq->request; - const int data_dir = arq->is_sync; + const int data_dir = rq_is_sync(rq); BUG_ON(RB_EMPTY_NODE(&rq->rb_node)); @@ -1158,12 +1155,7 @@ static void as_add_request(request_queue_t *q, struct request *rq) arq->state = AS_RQ_NEW; - if (rq_data_dir(arq->request) == READ - || (arq->request->cmd_flags & REQ_RW_SYNC)) - arq->is_sync = 1; - else - arq->is_sync = 0; - data_dir = arq->is_sync; + data_dir = rq_is_sync(rq); arq->io_context = as_get_io_context(); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index a905c4934a55..55ef6efe3eb5 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -531,6 +531,11 @@ enum { #define rq_data_dir(rq) ((rq)->cmd_flags & 1) +/* + * We regard a request as sync, if it's a READ or a SYNC write. + */ +#define rq_is_sync(rq) (rq_data_dir((rq)) == READ || (rq)->cmd_flags & REQ_RW_SYNC) + static inline int blk_queue_full(struct request_queue *q, int rw) { if (rw == READ) -- cgit v1.2.3 From ff7d145fd911266ae42af7552edc32681c01addb Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 12 Jul 2006 14:04:37 +0200 Subject: [PATCH] Add one more pointer to struct request for IO scheduler usage Then we have enough room in the request to get rid of the dynamic allocations in CFQ/AS. Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include/linux') diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 55ef6efe3eb5..d2dc17151f6c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -232,7 +232,13 @@ struct request { struct hlist_node hash; /* merge hash */ struct rb_node rb_node; /* sort/lookup */ + /* + * two pointers are available for the IO schedulers, if they need + * more they have to dynamically allocate it. + */ void *elevator_private; + void *elevator_private2; + void *completion_data; int rq_status; /* should split this into a few status bits */ -- cgit v1.2.3 From c00895ab2f08df7044e58ee01c38bf0a661ea0eb Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sat, 30 Sep 2006 20:29:12 +0200 Subject: [PATCH] Remove ->waiting member from struct request As the comments indicates in blkdev.h, we can fold it into ->end_io_data usage as that is really what ->waiting is. Fixup the users of blk_end_sync_rq(). Signed-off-by: Jens Axboe --- block/elevator.c | 3 +-- block/ll_rw_blk.c | 13 ++++++------- drivers/block/DAC960.c | 2 +- drivers/block/paride/pd.c | 3 +-- drivers/block/pktcdvd.c | 2 +- drivers/ide/ide-io.c | 13 ++++++------- drivers/ide/ide-tape.c | 2 +- drivers/ide/ide.c | 4 ++-- include/linux/blkdev.h | 3 +-- 9 files changed, 20 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/block/elevator.c b/block/elevator.c index cbbc36ba016a..924b81b08f86 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -67,8 +67,7 @@ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio) /* * same device and no special stuff set, merge is ok */ - if (rq->rq_disk == bio->bi_bdev->bd_disk && - !rq->waiting && !rq->special) + if (rq->rq_disk == bio->bi_bdev->bd_disk && !rq->special) return 1; return 0; diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index d388486e98bb..3b6aad2affd8 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -291,7 +291,6 @@ static inline void rq_init(request_queue_t *q, struct request *rq) rq->buffer = NULL; rq->ref_count = 1; rq->q = q; - rq->waiting = NULL; rq->special = NULL; rq->data_len = 0; rq->data = NULL; @@ -451,6 +450,7 @@ static void queue_flush(request_queue_t *q, unsigned which) rq->cmd_flags = REQ_HARDBARRIER; rq_init(q, rq); rq->elevator_private = NULL; + rq->elevator_private2 = NULL; rq->rq_disk = q->bar_rq.rq_disk; rq->rl = NULL; rq->end_io = end_io; @@ -479,6 +479,7 @@ static inline struct request *start_ordered(request_queue_t *q, rq->cmd_flags |= REQ_RW; rq->cmd_flags |= q->ordered & QUEUE_ORDERED_FUA ? REQ_FUA : 0; rq->elevator_private = NULL; + rq->elevator_private2 = NULL; rq->rl = NULL; init_request_from_bio(rq, q->orig_bar_rq->bio); rq->end_io = bar_end_io; @@ -2569,10 +2570,9 @@ int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk, rq->sense_len = 0; } - rq->waiting = &wait; + rq->end_io_data = &wait; blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq); wait_for_completion(&wait); - rq->waiting = NULL; if (rq->errors) err = -EIO; @@ -2736,9 +2736,9 @@ EXPORT_SYMBOL(blk_put_request); */ void blk_end_sync_rq(struct request *rq, int error) { - struct completion *waiting = rq->waiting; + struct completion *waiting = rq->end_io_data; - rq->waiting = NULL; + rq->end_io_data = NULL; __blk_put_request(rq->q, rq); /* @@ -2801,7 +2801,7 @@ static int attempt_merge(request_queue_t *q, struct request *req, if (rq_data_dir(req) != rq_data_dir(next) || req->rq_disk != next->rq_disk - || next->waiting || next->special) + || next->special) return 0; /* @@ -2886,7 +2886,6 @@ static void init_request_from_bio(struct request *req, struct bio *bio) req->nr_phys_segments = bio_phys_segments(req->q, bio); req->nr_hw_segments = bio_hw_segments(req->q, bio); req->buffer = bio_data(bio); /* see ->buffer comment above */ - req->waiting = NULL; req->bio = req->biotail = bio; req->ioprio = bio_prio(bio); req->rq_disk = bio->bi_bdev->bd_disk; diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index a360215dbce7..2568640430fb 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -3331,7 +3331,7 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_ Command->DmaDirection = PCI_DMA_TODEVICE; Command->CommandType = DAC960_WriteCommand; } - Command->Completion = Request->waiting; + Command->Completion = Request->end_io_data; Command->LogicalDriveNumber = (long)Request->rq_disk->private_data; Command->BlockNumber = Request->sector; Command->BlockCount = Request->nr_sectors; diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 12ff1a274d91..500d2ebb41e4 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -722,11 +722,10 @@ static int pd_special_command(struct pd_unit *disk, rq.rq_status = RQ_ACTIVE; rq.rq_disk = disk->gd; rq.ref_count = 1; - rq.waiting = &wait; + rq.end_io_data = &wait; rq.end_io = blk_end_sync_rq; blk_insert_request(disk->gd->queue, &rq, 0, func); wait_for_completion(&wait); - rq.waiting = NULL; if (rq.errors) err = -EIO; blk_put_request(&rq); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 42891d2b054e..888d1aceeeff 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -375,7 +375,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); rq->ref_count++; - rq->waiting = &wait; + rq->end_io_data = &wait; rq->end_io = blk_end_sync_rq; elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); generic_unplug_device(q); diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 3436b1f104eb..a3ffb04436bd 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -141,7 +141,7 @@ enum { static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error) { - struct request_pm_state *pm = rq->end_io_data; + struct request_pm_state *pm = rq->data; if (drive->media != ide_disk) return; @@ -164,7 +164,7 @@ static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 s static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) { - struct request_pm_state *pm = rq->end_io_data; + struct request_pm_state *pm = rq->data; ide_task_t *args = rq->special; memset(args, 0, sizeof(*args)); @@ -421,7 +421,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) } } } else if (blk_pm_request(rq)) { - struct request_pm_state *pm = rq->end_io_data; + struct request_pm_state *pm = rq->data; #ifdef DEBUG_PM printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n", drive->name, rq->pm->pm_step, stat, err); @@ -933,7 +933,7 @@ done: static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) { - struct request_pm_state *pm = rq->end_io_data; + struct request_pm_state *pm = rq->data; if (blk_pm_suspend_request(rq) && pm->pm_step == ide_pm_state_start_suspend) @@ -1018,7 +1018,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) rq->cmd_type == REQ_TYPE_ATA_TASKFILE) return execute_drive_cmd(drive, rq); else if (blk_pm_request(rq)) { - struct request_pm_state *pm = rq->end_io_data; + struct request_pm_state *pm = rq->data; #ifdef DEBUG_PM printk("%s: start_power_step(step: %d)\n", drive->name, rq->pm->pm_step); @@ -1718,7 +1718,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio */ if (must_wait) { rq->ref_count++; - rq->waiting = &wait; + rq->end_io_data = &wait; rq->end_io = blk_end_sync_rq; } @@ -1736,7 +1736,6 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio err = 0; if (must_wait) { wait_for_completion(&wait); - rq->waiting = NULL; if (rq->errors) err = -EIO; diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 643e4b9ac651..66f9678d2f10 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -2773,7 +2773,7 @@ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) return; } #endif /* IDETAPE_DEBUG_BUGS */ - rq->waiting = &wait; + rq->end_io_data = &wait; rq->end_io = blk_end_sync_rq; spin_unlock_irq(&tape->spinlock); wait_for_completion(&wait); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 9384a3fdde6c..2b1a1389c318 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1219,7 +1219,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) memset(&args, 0, sizeof(args)); rq.cmd_type = REQ_TYPE_PM_SUSPEND; rq.special = &args; - rq.end_io_data = &rqpm; + rq.data = &rqpm; rqpm.pm_step = ide_pm_state_start_suspend; if (mesg.event == PM_EVENT_PRETHAW) mesg.event = PM_EVENT_FREEZE; @@ -1240,7 +1240,7 @@ static int generic_ide_resume(struct device *dev) memset(&args, 0, sizeof(args)); rq.cmd_type = REQ_TYPE_PM_RESUME; rq.special = &args; - rq.end_io_data = &rqpm; + rq.data = &rqpm; rqpm.pm_step = ide_pm_state_start_resume; rqpm.pm_state = PM_EVENT_ON; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index d2dc17151f6c..604f23189097 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -266,7 +266,6 @@ struct request { request_queue_t *q; struct request_list *rl; - struct completion *waiting; void *special; char *buffer; @@ -285,7 +284,7 @@ struct request { int retries; /* - * completion callback. end_io_data should be folded in with waiting + * completion callback. */ rq_end_io_fn *end_io; void *end_io_data; -- cgit v1.2.3 From 49171e5c6f414d49a061b5c1c84967c2eb569822 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 10 Aug 2006 08:59:11 +0200 Subject: [PATCH] Remove struct request_list from struct request It is always identical to &q->rq, and we only use it for detecting whether this request came out of our mempool or not. So replace it with an additional ->flags bit flag. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 10 ++-------- include/linux/blkdev.h | 3 ++- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 3b6aad2affd8..f7462502bfdf 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -452,7 +452,6 @@ static void queue_flush(request_queue_t *q, unsigned which) rq->elevator_private = NULL; rq->elevator_private2 = NULL; rq->rq_disk = q->bar_rq.rq_disk; - rq->rl = NULL; rq->end_io = end_io; q->prepare_flush_fn(q, rq); @@ -480,7 +479,6 @@ static inline struct request *start_ordered(request_queue_t *q, rq->cmd_flags |= q->ordered & QUEUE_ORDERED_FUA ? REQ_FUA : 0; rq->elevator_private = NULL; rq->elevator_private2 = NULL; - rq->rl = NULL; init_request_from_bio(rq, q->orig_bar_rq->bio); rq->end_io = bar_end_io; @@ -2018,7 +2016,7 @@ blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, * first three bits are identical in rq->cmd_flags and bio->bi_rw, * see bio.h and blkdev.h */ - rq->cmd_flags = rw; + rq->cmd_flags = rw | REQ_ALLOCED; if (priv) { if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) { @@ -2196,7 +2194,6 @@ rq_starved: ioc->nr_batch_requests--; rq_init(q, rq); - rq->rl = rl; blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ); out: @@ -2681,8 +2678,6 @@ EXPORT_SYMBOL_GPL(disk_round_stats); */ void __blk_put_request(request_queue_t *q, struct request *req) { - struct request_list *rl = req->rl; - if (unlikely(!q)) return; if (unlikely(--req->ref_count)) @@ -2691,13 +2686,12 @@ void __blk_put_request(request_queue_t *q, struct request *req) elv_completed_request(q, req); req->rq_status = RQ_INACTIVE; - req->rl = NULL; /* * Request may not have originated from ll_rw_blk. if not, * it didn't come out of our reserved rq pools */ - if (rl) { + if (req->cmd_flags & REQ_ALLOCED) { int rw = rq_data_dir(req); int priv = req->cmd_flags & REQ_ELVPRIV; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 604f23189097..d4c1dd046e27 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -180,6 +180,7 @@ enum rq_flag_bits { __REQ_PREEMPT, /* set for "ide_preempt" requests */ __REQ_ORDERED_COLOR, /* is before or after barrier */ __REQ_RW_SYNC, /* request is sync (O_DIRECT) */ + __REQ_ALLOCED, /* request came from our alloc pool */ __REQ_NR_BITS, /* stops here */ }; @@ -199,6 +200,7 @@ enum rq_flag_bits { #define REQ_PREEMPT (1 << __REQ_PREEMPT) #define REQ_ORDERED_COLOR (1 << __REQ_ORDERED_COLOR) #define REQ_RW_SYNC (1 << __REQ_RW_SYNC) +#define REQ_ALLOCED (1 << __REQ_ALLOCED) #define BLK_MAX_CDB 16 @@ -264,7 +266,6 @@ struct request { int ref_count; request_queue_t *q; - struct request_list *rl; void *special; char *buffer; -- cgit v1.2.3 From cdd6026217c0e4cda2efce1bdc318661bef1f66f Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Jul 2006 09:32:07 +0200 Subject: [PATCH] Remove ->rq_status from struct request After Christophs SCSI change, the only usage left is RQ_ACTIVE and RQ_INACTIVE. The block layer sets RQ_INACTIVE right before freeing the request, so any check for RQ_INACTIVE in a driver is a bug and indicates use-after-free. So kill/clean the remaining users, straight forward. Signed-off-by: Jens Axboe --- arch/um/drivers/ubd_kern.c | 2 -- block/ll_rw_blk.c | 3 --- drivers/block/paride/pd.c | 1 - drivers/block/swim3.c | 4 ++-- drivers/block/swim_iop.c | 4 ++-- drivers/fc4/fc.c | 1 - drivers/ide/ide-floppy.c | 3 +-- drivers/ide/ide-io.c | 1 - drivers/ide/ide-tape.c | 4 ++-- drivers/scsi/ide-scsi.c | 2 +- drivers/scsi/scsi.c | 2 +- include/linux/blkdev.h | 13 +++++-------- 12 files changed, 14 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 5fa4c8e258a4..fda4a3940698 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -981,8 +981,6 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) __u64 offset; int len; - if(req->rq_status == RQ_INACTIVE) return(1); - /* This should be impossible now */ if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ printk("Write attempted on readonly ubd device %s\n", diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index f7462502bfdf..b94a396aa624 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -283,7 +283,6 @@ static inline void rq_init(request_queue_t *q, struct request *rq) INIT_LIST_HEAD(&rq->donelist); rq->errors = 0; - rq->rq_status = RQ_ACTIVE; rq->bio = rq->biotail = NULL; INIT_HLIST_NODE(&rq->hash); RB_CLEAR_NODE(&rq->rb_node); @@ -2685,8 +2684,6 @@ void __blk_put_request(request_queue_t *q, struct request *req) elv_completed_request(q, req); - req->rq_status = RQ_INACTIVE; - /* * Request may not have originated from ll_rw_blk. if not, * it didn't come out of our reserved rq pools diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 500d2ebb41e4..38578b9dbfd1 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -719,7 +719,6 @@ static int pd_special_command(struct pd_unit *disk, memset(&rq, 0, sizeof(rq)); rq.errors = 0; - rq.rq_status = RQ_ACTIVE; rq.rq_disk = disk->gd; rq.ref_count = 1; rq.end_io_data = &wait; diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index cc42e762396f..f2305ee792a1 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -319,8 +319,8 @@ static void start_request(struct floppy_state *fs) printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n", req->rq_disk->disk_name, req->cmd, (long)req->sector, req->nr_sectors, req->buffer); - printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n", - req->rq_status, req->errors, req->current_nr_sectors); + printk(" errors=%d current_nr_sectors=%ld\n", + req->errors, req->current_nr_sectors); #endif if (req->sector < 0 || req->sector >= fs->total_secs) { diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c index 89e3c2f8b776..dfda796eba56 100644 --- a/drivers/block/swim_iop.c +++ b/drivers/block/swim_iop.c @@ -529,8 +529,8 @@ static void start_request(struct floppy_state *fs) printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n", CURRENT->rq_disk->disk_name, CURRENT->cmd, CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer); - printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n", - CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors); + printk(" errors=%d current_nr_sectors=%ld\n", + CURRENT->errors, CURRENT->current_nr_sectors); #endif if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) { diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c index 1a159e8843ca..22d17474755f 100644 --- a/drivers/fc4/fc.c +++ b/drivers/fc4/fc.c @@ -974,7 +974,6 @@ int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt) */ fc->rst_pkt->device->host->eh_action = &sem; - fc->rst_pkt->request->rq_status = RQ_SCSI_BUSY; fc->rst_pkt->done = fcp_scsi_reset_done; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 0edc32204915..8ccee9c769f8 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -1281,8 +1281,7 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request idefloppy_pc_t *pc; unsigned long block = (unsigned long)block_s; - debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n", - rq->rq_status, + debug_log(KERN_INFO "dev: %s, flags: %lx, errors: %d\n", rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->flags, rq->errors); debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, " diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index a3ffb04436bd..38479a29d3e1 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -1710,7 +1710,6 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio int must_wait = (action == ide_wait || action == ide_head_wait); rq->errors = 0; - rq->rq_status = RQ_ACTIVE; /* * we need to hold an extra reference to request for safe inspection diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 66f9678d2f10..2ebc3760f261 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -2423,8 +2423,8 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, #if IDETAPE_DEBUG_LOG #if 0 if (tape->debug_level >= 5) - printk(KERN_INFO "ide-tape: rq_status: %d, " - "dev: %s, cmd: %ld, errors: %d\n", rq->rq_status, + printk(KERN_INFO "ide-tape: %d, " + "dev: %s, cmd: %ld, errors: %d\n", rq->rq_disk->disk_name, rq->cmd[0], rq->errors); #endif if (tape->debug_level >= 2) diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 65b19695ebe2..1427a41e8441 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -708,7 +708,7 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc) static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, sector_t block) { #if IDESCSI_DEBUG_LOG - printk (KERN_INFO "rq_status: %d, dev: %s, cmd: %x, errors: %d\n",rq->rq_status, rq->rq_disk->disk_name,rq->cmd[0],rq->errors); + printk (KERN_INFO "dev: %s, cmd: %x, errors: %d\n", rq->rq_disk->disk_name,rq->cmd[0],rq->errors); printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); #endif /* IDESCSI_DEBUG_LOG */ diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 7a054f9d1ee3..12f6639dda2d 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1065,7 +1065,7 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery) spin_lock_irqsave(&sdev->list_lock, flags); list_for_each_entry(scmd, &sdev->cmd_list, list) { - if (scmd->request && scmd->request->rq_status != RQ_INACTIVE) { + if (scmd->request) { /* * If we are unable to remove the timer, it means * that the command has already timed out or diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index d4c1dd046e27..8a3e309e0842 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -243,8 +243,6 @@ struct request { void *completion_data; - int rq_status; /* should split this into a few status bits */ - int errors; struct gendisk *rq_disk; unsigned long start_time; @@ -262,14 +260,16 @@ struct request { unsigned short ioprio; - int tag; - - int ref_count; request_queue_t *q; void *special; char *buffer; + int tag; + int errors; + + int ref_count; + /* * when request is used as a packet command carrier */ @@ -456,9 +456,6 @@ struct request_queue struct mutex sysfs_lock; }; -#define RQ_INACTIVE (-1) -#define RQ_ACTIVE 1 - #define QUEUE_FLAG_CLUSTER 0 /* cluster several segments into 1 */ #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */ #define QUEUE_FLAG_STOPPED 2 /* queue is stopped */ -- cgit v1.2.3 From cb78b285c8f9d59b0d4e4f6a54c2977ce1d9b880 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Jul 2006 09:32:57 +0200 Subject: [PATCH] Drop useless bio passing in may_queue/set_request API It's not needed for anything, so kill the bio passing. Signed-off-by: Jens Axboe --- block/as-iosched.c | 2 +- block/cfq-iosched.c | 5 ++--- block/elevator.c | 9 ++++----- block/ll_rw_blk.c | 9 ++++----- include/linux/elevator.h | 8 ++++---- 5 files changed, 15 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/block/as-iosched.c b/block/as-iosched.c index 02eb9333898f..66015bc79e6f 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -1284,7 +1284,7 @@ static void as_work_handler(void *data) spin_unlock_irqrestore(q->queue_lock, flags); } -static int as_may_queue(request_queue_t *q, int rw, struct bio *bio) +static int as_may_queue(request_queue_t *q, int rw) { int ret = ELV_MQUEUE_MAY; struct as_data *ad = q->elevator->elevator_data; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3c5fd9c2c205..2ac35aacbbf9 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1752,7 +1752,7 @@ __cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq, return ELV_MQUEUE_MAY; } -static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio) +static int cfq_may_queue(request_queue_t *q, int rw) { struct cfq_data *cfqd = q->elevator->elevator_data; struct task_struct *tsk = current; @@ -1817,8 +1817,7 @@ static void cfq_put_request(request_queue_t *q, struct request *rq) * Allocate cfq data structures associated with this request. */ static int -cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - gfp_t gfp_mask) +cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask) { struct cfq_data *cfqd = q->elevator->elevator_data; struct task_struct *tsk = current; diff --git a/block/elevator.c b/block/elevator.c index 924b81b08f86..788d2d81994c 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -796,13 +796,12 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq) return NULL; } -int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - gfp_t gfp_mask) +int elv_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask) { elevator_t *e = q->elevator; if (e->ops->elevator_set_req_fn) - return e->ops->elevator_set_req_fn(q, rq, bio, gfp_mask); + return e->ops->elevator_set_req_fn(q, rq, gfp_mask); rq->elevator_private = NULL; return 0; @@ -816,12 +815,12 @@ void elv_put_request(request_queue_t *q, struct request *rq) e->ops->elevator_put_req_fn(q, rq); } -int elv_may_queue(request_queue_t *q, int rw, struct bio *bio) +int elv_may_queue(request_queue_t *q, int rw) { elevator_t *e = q->elevator; if (e->ops->elevator_may_queue_fn) - return e->ops->elevator_may_queue_fn(q, rw, bio); + return e->ops->elevator_may_queue_fn(q, rw); return ELV_MQUEUE_MAY; } diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index b94a396aa624..b1ea941f6dc3 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2003,8 +2003,7 @@ static inline void blk_free_request(request_queue_t *q, struct request *rq) } static inline struct request * -blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, - int priv, gfp_t gfp_mask) +blk_alloc_request(request_queue_t *q, int rw, int priv, gfp_t gfp_mask) { struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); @@ -2018,7 +2017,7 @@ blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, rq->cmd_flags = rw | REQ_ALLOCED; if (priv) { - if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) { + if (unlikely(elv_set_request(q, rq, gfp_mask))) { mempool_free(rq, q->rq.rq_pool); return NULL; } @@ -2109,7 +2108,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, struct io_context *ioc = NULL; int may_queue, priv; - may_queue = elv_may_queue(q, rw, bio); + may_queue = elv_may_queue(q, rw); if (may_queue == ELV_MQUEUE_NO) goto rq_starved; @@ -2157,7 +2156,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, spin_unlock_irq(q->queue_lock); - rq = blk_alloc_request(q, rw, bio, priv, gfp_mask); + rq = blk_alloc_request(q, rw, priv, gfp_mask); if (unlikely(!rq)) { /* * Allocation failed presumably due to memory. Undo anything diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 0e7b1a733919..cc81645a3e18 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -14,9 +14,9 @@ typedef void (elevator_add_req_fn) (request_queue_t *, struct request *); typedef int (elevator_queue_empty_fn) (request_queue_t *); typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *); typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *); -typedef int (elevator_may_queue_fn) (request_queue_t *, int, struct bio *); +typedef int (elevator_may_queue_fn) (request_queue_t *, int); -typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, struct bio *, gfp_t); +typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, gfp_t); typedef void (elevator_put_req_fn) (request_queue_t *, struct request *); typedef void (elevator_activate_req_fn) (request_queue_t *, struct request *); typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *); @@ -105,9 +105,9 @@ extern struct request *elv_former_request(request_queue_t *, struct request *); extern struct request *elv_latter_request(request_queue_t *, struct request *); extern int elv_register_queue(request_queue_t *q); extern void elv_unregister_queue(request_queue_t *q); -extern int elv_may_queue(request_queue_t *, int, struct bio *); +extern int elv_may_queue(request_queue_t *, int); extern void elv_completed_request(request_queue_t *, struct request *); -extern int elv_set_request(request_queue_t *, struct request *, struct bio *, gfp_t); +extern int elv_set_request(request_queue_t *, struct request *, gfp_t); extern void elv_put_request(request_queue_t *, struct request *); /* -- cgit v1.2.3 From e6a1c874a064e7d07f24986aba7cd537b7f4a25d Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 10 Aug 2006 09:00:21 +0200 Subject: [PATCH] struct request: shrink and optimize some more Move some members around and unionize completion_data and rb_node since they cannot ever be used at the same time. Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 8a3e309e0842..a1e288069e2e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -211,6 +211,8 @@ struct request { struct list_head queuelist; struct list_head donelist; + request_queue_t *q; + unsigned int cmd_flags; enum rq_cmd_type_bits cmd_type; @@ -219,12 +221,12 @@ struct request { */ sector_t sector; /* next sector to submit */ + sector_t hard_sector; /* next sector to complete */ unsigned long nr_sectors; /* no. of sectors left to submit */ + unsigned long hard_nr_sectors; /* no. of sectors left to complete */ /* no. of sectors left to submit in the current segment */ unsigned int current_nr_sectors; - sector_t hard_sector; /* next sector to complete */ - unsigned long hard_nr_sectors; /* no. of sectors left to complete */ /* no. of sectors left to complete in the current segment */ unsigned int hard_cur_sectors; @@ -232,7 +234,15 @@ struct request { struct bio *biotail; struct hlist_node hash; /* merge hash */ - struct rb_node rb_node; /* sort/lookup */ + /* + * The rb_node is only used inside the io scheduler, requests + * are pruned when moved to the dispatch queue. So let the + * completion_data share space with the rb_node. + */ + union { + struct rb_node rb_node; /* sort/lookup */ + void *completion_data; + }; /* * two pointers are available for the IO schedulers, if they need @@ -241,8 +251,6 @@ struct request { void *elevator_private; void *elevator_private2; - void *completion_data; - struct gendisk *rq_disk; unsigned long start_time; @@ -260,8 +268,6 @@ struct request { unsigned short ioprio; - request_queue_t *q; - void *special; char *buffer; -- cgit v1.2.3 From fc46379daf90dce57bf765c81d3b39f55150aac2 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 29 Aug 2006 09:05:44 +0200 Subject: [PATCH] cfq-iosched: kill cfq_exit_lock cfq_exit_lock is protecting two things now: - The per-ioc rbtree of cfq_io_contexts - The per-cfqd linked list of cfq_io_contexts The per-cfqd linked list can be protected by the queue lock, as it is (by definition) per cfqd as the queue lock is. The per-ioc rbtree is mainly used and updated by the process itself only. The only outside use is the io priority changing. If we move the priority changing to not browsing the rbtree, we can remove any locking from the rbtree updates and lookup completely. Let the sys_ioprio syscall just mark processes as having the iopriority changed and lazily update the private cfq io contexts the next time io is queued, and we can remove this locking as well. Signed-off-by: Jens Axboe --- block/cfq-iosched.c | 54 ++++++++++++++++---------------------------------- block/ll_rw_blk.c | 2 +- fs/ioprio.c | 4 ++-- include/linux/blkdev.h | 2 +- 4 files changed, 21 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index ec24284e9d39..33e0b0c5e31d 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -31,8 +31,6 @@ static int cfq_slice_idle = HZ / 125; #define CFQ_KEY_ASYNC (0) -static DEFINE_SPINLOCK(cfq_exit_lock); - /* * for the hash of cfqq inside the cfqd */ @@ -1084,12 +1082,6 @@ static void cfq_free_io_context(struct io_context *ioc) complete(ioc_gone); } -static void cfq_trim(struct io_context *ioc) -{ - ioc->set_ioprio = NULL; - cfq_free_io_context(ioc); -} - static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) { if (unlikely(cfqq == cfqd->active_queue)) @@ -1101,6 +1093,10 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) static void __cfq_exit_single_io_context(struct cfq_data *cfqd, struct cfq_io_context *cic) { + list_del_init(&cic->queue_list); + smp_wmb(); + cic->key = NULL; + if (cic->cfqq[ASYNC]) { cfq_exit_cfqq(cfqd, cic->cfqq[ASYNC]); cic->cfqq[ASYNC] = NULL; @@ -1110,9 +1106,6 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd, cfq_exit_cfqq(cfqd, cic->cfqq[SYNC]); cic->cfqq[SYNC] = NULL; } - - cic->key = NULL; - list_del_init(&cic->queue_list); } @@ -1123,27 +1116,23 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic) { struct cfq_data *cfqd = cic->key; - WARN_ON(!irqs_disabled()); - if (cfqd) { request_queue_t *q = cfqd->queue; - spin_lock(q->queue_lock); + spin_lock_irq(q->queue_lock); __cfq_exit_single_io_context(cfqd, cic); - spin_unlock(q->queue_lock); + spin_unlock_irq(q->queue_lock); } } static void cfq_exit_io_context(struct io_context *ioc) { struct cfq_io_context *__cic; - unsigned long flags; struct rb_node *n; /* * put the reference this task is holding to the various queues */ - spin_lock_irqsave(&cfq_exit_lock, flags); n = rb_first(&ioc->cic_root); while (n != NULL) { @@ -1152,8 +1141,6 @@ static void cfq_exit_io_context(struct io_context *ioc) cfq_exit_single_io_context(__cic); n = rb_next(n); } - - spin_unlock_irqrestore(&cfq_exit_lock, flags); } static struct cfq_io_context * @@ -1248,15 +1235,12 @@ static inline void changed_ioprio(struct cfq_io_context *cic) spin_unlock(cfqd->queue->queue_lock); } -/* - * callback from sys_ioprio_set, irqs are disabled - */ -static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio) +static void cfq_ioc_set_ioprio(struct io_context *ioc) { struct cfq_io_context *cic; struct rb_node *n; - spin_lock(&cfq_exit_lock); + ioc->ioprio_changed = 0; n = rb_first(&ioc->cic_root); while (n != NULL) { @@ -1265,10 +1249,6 @@ static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio) changed_ioprio(cic); n = rb_next(n); } - - spin_unlock(&cfq_exit_lock); - - return 0; } static struct cfq_queue * @@ -1336,10 +1316,8 @@ out: static void cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic) { - spin_lock(&cfq_exit_lock); + WARN_ON(!list_empty(&cic->queue_list)); rb_erase(&cic->rb_node, &ioc->cic_root); - list_del_init(&cic->queue_list); - spin_unlock(&cfq_exit_lock); kmem_cache_free(cfq_ioc_pool, cic); atomic_dec(&ioc_count); } @@ -1385,7 +1363,6 @@ cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc, cic->ioc = ioc; cic->key = cfqd; - ioc->set_ioprio = cfq_ioc_set_ioprio; restart: parent = NULL; p = &ioc->cic_root.rb_node; @@ -1407,11 +1384,12 @@ restart: BUG(); } - spin_lock(&cfq_exit_lock); rb_link_node(&cic->rb_node, parent, p); rb_insert_color(&cic->rb_node, &ioc->cic_root); + + spin_lock_irq(cfqd->queue->queue_lock); list_add(&cic->queue_list, &cfqd->cic_list); - spin_unlock(&cfq_exit_lock); + spin_unlock_irq(cfqd->queue->queue_lock); } /* @@ -1441,6 +1419,10 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) cfq_cic_link(cfqd, ioc, cic); out: + smp_read_barrier_depends(); + if (unlikely(ioc->ioprio_changed)) + cfq_ioc_set_ioprio(ioc); + return cic; err: put_io_context(ioc); @@ -1945,7 +1927,6 @@ static void cfq_exit_queue(elevator_t *e) cfq_shutdown_timer_wq(cfqd); - spin_lock(&cfq_exit_lock); spin_lock_irq(q->queue_lock); if (cfqd->active_queue) @@ -1960,7 +1941,6 @@ static void cfq_exit_queue(elevator_t *e) } spin_unlock_irq(q->queue_lock); - spin_unlock(&cfq_exit_lock); cfq_shutdown_timer_wq(cfqd); @@ -2149,7 +2129,7 @@ static struct elevator_type iosched_cfq = { .elevator_may_queue_fn = cfq_may_queue, .elevator_init_fn = cfq_init_queue, .elevator_exit_fn = cfq_exit_queue, - .trim = cfq_trim, + .trim = cfq_free_io_context, }, .elevator_attrs = cfq_attrs, .elevator_name = "cfq", diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index e25b4cd2dcd1..508548b834f1 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -3654,7 +3654,7 @@ struct io_context *current_io_context(gfp_t gfp_flags) if (ret) { atomic_set(&ret->refcount, 1); ret->task = current; - ret->set_ioprio = NULL; + ret->ioprio_changed = 0; ret->last_waited = jiffies; /* doesn't matter... */ ret->nr_batch_requests = 0; /* because this is 0 */ ret->aic = NULL; diff --git a/fs/ioprio.c b/fs/ioprio.c index 78b1deae3fa2..0fd1089d7bf6 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -47,8 +47,8 @@ static int set_task_ioprio(struct task_struct *task, int ioprio) /* see wmb() in current_io_context() */ smp_read_barrier_depends(); - if (ioc && ioc->set_ioprio) - ioc->set_ioprio(ioc, ioprio); + if (ioc) + ioc->ioprio_changed = 1; task_unlock(task); return 0; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index a1e288069e2e..79cb9fa8034a 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -90,7 +90,7 @@ struct io_context { atomic_t refcount; struct task_struct *task; - int (*set_ioprio)(struct io_context *, unsigned int); + unsigned int ioprio_changed; /* * For request batching -- cgit v1.2.3 From 4a893e837bb470867d74c05d6c6b97bba5a96185 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sat, 22 Jul 2006 15:37:43 +0200 Subject: [PATCH] elevator: define ioc counting mechanism None of the in-kernel primitives for handling "atomic" counting seem to be a good fit. We need something that is essentially free for incrementing/decrementing, while the read side may be more expensive as we only ever need to do that when a device is removed from the kernel. Use a per-cpu variable for maintaining a per-cpu ioc count and define a reading mechanism that just sums up the values. Signed-off-by: Jens Axboe --- include/linux/elevator.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'include/linux') diff --git a/include/linux/elevator.h b/include/linux/elevator.h index cc81645a3e18..9c5a04f6114c 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -1,6 +1,8 @@ #ifndef _LINUX_ELEVATOR_H #define _LINUX_ELEVATOR_H +#include + typedef int (elevator_merge_fn) (request_queue_t *, struct request **, struct bio *); @@ -178,4 +180,27 @@ enum { INIT_LIST_HEAD(&(rq)->donelist); \ } while (0) +/* + * io context count accounting + */ +#define elv_ioc_count_mod(name, __val) \ + do { \ + preempt_disable(); \ + __get_cpu_var(name) += (__val); \ + preempt_enable(); \ + } while (0) + +#define elv_ioc_count_inc(name) elv_ioc_count_mod(name, 1) +#define elv_ioc_count_dec(name) elv_ioc_count_mod(name, -1) + +#define elv_ioc_count_read(name) \ +({ \ + unsigned long __val = 0; \ + int __cpu; \ + smp_wmb(); \ + for_each_possible_cpu(__cpu) \ + __val += per_cpu(name, __cpu); \ + __val; \ +}) + #endif -- cgit v1.2.3 From a3b05e8f58c95dfccbf2c824d0c68e5990571f24 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Jul 2006 09:36:46 +0200 Subject: [PATCH] Kill various deprecated/unused block layer defines/functions Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 1 - drivers/block/cpqarray.c | 1 - include/linux/blkdev.h | 29 ----------------------------- include/linux/fs.h | 1 - 4 files changed, 32 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 2cd3391ff878..c211065ad829 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1229,7 +1229,6 @@ static inline void complete_buffers(struct bio *bio, int status) int nr_sectors = bio_sectors(bio); bio->bi_next = NULL; - blk_finished_io(len); bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); bio = xbh; } diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 78082edc14b4..4abc193314ee 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -989,7 +989,6 @@ static inline void complete_buffers(struct bio *bio, int ok) xbh = bio->bi_next; bio->bi_next = NULL; - blk_finished_io(nr_sectors); bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO); bio = xbh; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 79cb9fa8034a..593386162f47 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -578,12 +578,6 @@ static inline void blk_clear_queue_full(struct request_queue *q, int rw) #define rq_mergeable(rq) \ (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq))) -/* - * noop, requests are automagically marked as active/inactive by I/O - * scheduler -- see elv_next_request - */ -#define blk_queue_headactive(q, head_active) - /* * q->prep_rq_fn return values */ @@ -621,11 +615,6 @@ static inline void blk_queue_bounce(request_queue_t *q, struct bio **bio) if ((rq->bio)) \ for (_bio = (rq)->bio; _bio; _bio = _bio->bi_next) -struct sec_size { - unsigned block_size; - unsigned block_size_bits; -}; - extern int blk_register_queue(struct gendisk *disk); extern void blk_unregister_queue(struct gendisk *disk); extern void register_disk(struct gendisk *dev); @@ -690,16 +679,6 @@ extern void end_that_request_last(struct request *, int); extern void end_request(struct request *req, int uptodate); extern void blk_complete_request(struct request *); -static inline int rq_all_done(struct request *rq, unsigned int nr_bytes) -{ - if (blk_fs_request(rq)) - return (nr_bytes >= (rq->hard_nr_sectors << 9)); - else if (blk_pc_request(rq)) - return nr_bytes >= rq->data_len; - - return 0; -} - /* * end_that_request_first/chunk() takes an uptodate argument. we account * any value <= as an io error. 0 means -EIO for compatability reasons, @@ -807,14 +786,6 @@ static inline int queue_dma_alignment(request_queue_t *q) return retval; } -static inline int bdev_dma_aligment(struct block_device *bdev) -{ - return queue_dma_alignment(bdev_get_queue(bdev)); -} - -#define blk_finished_io(nsects) do { } while (0) -#define blk_started_io(nsects) do { } while (0) - /* assumes size > 256 */ static inline unsigned int blksize_bits(unsigned int size) { diff --git a/include/linux/fs.h b/include/linux/fs.h index 6eafbe309483..9306f63bf77e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -79,7 +79,6 @@ extern int dir_notify_enable; #define WRITE 1 #define READA 2 /* read-ahead - don't block if no resources */ #define SWRITE 3 /* for ll_rw_block() - wait for buffer lock */ -#define SPECIAL 4 /* For non-blockdevice requests in request queue */ #define READ_SYNC (READ | (1 << BIO_RW_SYNC)) #define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC)) #define WRITE_BARRIER ((1 << BIO_RW) | (1 << BIO_RW_BARRIER)) -- cgit v1.2.3 From b5deef901282628d88c784f4c9d2f0583ec3b355 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 19 Jul 2006 23:39:40 +0200 Subject: [PATCH] Make sure all block/io scheduler setups are node aware Some were kmalloc_node(), some were still kmalloc(). Change them all to kmalloc_node(). Signed-off-by: Jens Axboe --- block/as-iosched.c | 8 ++++---- block/cfq-iosched.c | 13 +++++++------ block/elevator.c | 11 ++++++----- block/ll_rw_blk.c | 13 +++++++------ block/noop-iosched.c | 2 +- include/linux/blkdev.h | 3 +-- 6 files changed, 26 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/block/as-iosched.c b/block/as-iosched.c index 8e1fef1eafc9..f6dc95489316 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -210,9 +210,9 @@ static struct as_io_context *alloc_as_io_context(void) * If the current task has no AS IO context then create one and initialise it. * Then take a ref on the task's io context and return it. */ -static struct io_context *as_get_io_context(void) +static struct io_context *as_get_io_context(int node) { - struct io_context *ioc = get_io_context(GFP_ATOMIC); + struct io_context *ioc = get_io_context(GFP_ATOMIC, node); if (ioc && !ioc->aic) { ioc->aic = alloc_as_io_context(); if (!ioc->aic) { @@ -1148,7 +1148,7 @@ static void as_add_request(request_queue_t *q, struct request *rq) data_dir = rq_is_sync(rq); - rq->elevator_private = as_get_io_context(); + rq->elevator_private = as_get_io_context(q->node); if (RQ_IOC(rq)) { as_update_iohist(ad, RQ_IOC(rq)->aic, rq); @@ -1292,7 +1292,7 @@ static int as_may_queue(request_queue_t *q, int rw) struct io_context *ioc; if (ad->antic_status == ANTIC_WAIT_REQ || ad->antic_status == ANTIC_WAIT_NEXT) { - ioc = as_get_io_context(); + ioc = as_get_io_context(q->node); if (ad->io_context == ioc) ret = ELV_MQUEUE_MUST; put_io_context(ioc); diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 85f1d87e86d4..0452108a932e 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1148,8 +1148,9 @@ static void cfq_exit_io_context(struct io_context *ioc) static struct cfq_io_context * cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) { - struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask); + struct cfq_io_context *cic; + cic = kmem_cache_alloc_node(cfq_ioc_pool, gfp_mask, cfqd->queue->node); if (cic) { memset(cic, 0, sizeof(*cic)); cic->last_end_request = jiffies; @@ -1277,11 +1278,11 @@ retry: * free memory. */ spin_unlock_irq(cfqd->queue->queue_lock); - new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask|__GFP_NOFAIL); + new_cfqq = kmem_cache_alloc_node(cfq_pool, gfp_mask|__GFP_NOFAIL, cfqd->queue->node); spin_lock_irq(cfqd->queue->queue_lock); goto retry; } else { - cfqq = kmem_cache_alloc(cfq_pool, gfp_mask); + cfqq = kmem_cache_alloc_node(cfq_pool, gfp_mask, cfqd->queue->node); if (!cfqq) goto out; } @@ -1407,7 +1408,7 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) might_sleep_if(gfp_mask & __GFP_WAIT); - ioc = get_io_context(gfp_mask); + ioc = get_io_context(gfp_mask, cfqd->queue->node); if (!ioc) return NULL; @@ -1955,7 +1956,7 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e) struct cfq_data *cfqd; int i; - cfqd = kmalloc(sizeof(*cfqd), GFP_KERNEL); + cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node); if (!cfqd) return NULL; @@ -1970,7 +1971,7 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e) INIT_LIST_HEAD(&cfqd->empty_list); INIT_LIST_HEAD(&cfqd->cic_list); - cfqd->cfq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL); + cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node); if (!cfqd->cfq_hash) goto out_free; diff --git a/block/elevator.c b/block/elevator.c index 788d2d81994c..e643291793a4 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -161,12 +161,12 @@ __setup("elevator=", elevator_setup); static struct kobj_type elv_ktype; -static elevator_t *elevator_alloc(struct elevator_type *e) +static elevator_t *elevator_alloc(request_queue_t *q, struct elevator_type *e) { elevator_t *eq; int i; - eq = kmalloc(sizeof(elevator_t), GFP_KERNEL); + eq = kmalloc_node(sizeof(elevator_t), GFP_KERNEL, q->node); if (unlikely(!eq)) goto err; @@ -178,7 +178,8 @@ static elevator_t *elevator_alloc(struct elevator_type *e) eq->kobj.ktype = &elv_ktype; mutex_init(&eq->sysfs_lock); - eq->hash = kmalloc(sizeof(struct hlist_head) * ELV_HASH_ENTRIES, GFP_KERNEL); + eq->hash = kmalloc_node(sizeof(struct hlist_head) * ELV_HASH_ENTRIES, + GFP_KERNEL, q->node); if (!eq->hash) goto err; @@ -224,7 +225,7 @@ int elevator_init(request_queue_t *q, char *name) e = elevator_get("noop"); } - eq = elevator_alloc(e); + eq = elevator_alloc(q, e); if (!eq) return -ENOMEM; @@ -987,7 +988,7 @@ static int elevator_switch(request_queue_t *q, struct elevator_type *new_e) /* * Allocate new elevator */ - e = elevator_alloc(new_e); + e = elevator_alloc(q, new_e); if (!e) return 0; diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 4b7b4461e8d6..c6dfa889206c 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -39,6 +39,7 @@ static void blk_unplug_timeout(unsigned long data); static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io); static void init_request_from_bio(struct request *req, struct bio *bio); static int __make_request(request_queue_t *q, struct bio *bio); +static struct io_context *current_io_context(gfp_t gfp_flags, int node); /* * For the allocated request tables @@ -2114,7 +2115,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, if (rl->count[rw]+1 >= queue_congestion_on_threshold(q)) { if (rl->count[rw]+1 >= q->nr_requests) { - ioc = current_io_context(GFP_ATOMIC); + ioc = current_io_context(GFP_ATOMIC, q->node); /* * The queue will fill after this allocation, so set * it as full, and mark this process as "batching". @@ -2234,7 +2235,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw, * up to a big batch of them for a small period time. * See ioc_batching, ioc_set_batching */ - ioc = current_io_context(GFP_NOIO); + ioc = current_io_context(GFP_NOIO, q->node); ioc_set_batching(q, ioc); spin_lock_irq(q->queue_lock); @@ -3641,7 +3642,7 @@ void exit_io_context(void) * but since the current task itself holds a reference, the context can be * used in general code, so long as it stays within `current` context. */ -struct io_context *current_io_context(gfp_t gfp_flags) +static struct io_context *current_io_context(gfp_t gfp_flags, int node) { struct task_struct *tsk = current; struct io_context *ret; @@ -3650,7 +3651,7 @@ struct io_context *current_io_context(gfp_t gfp_flags) if (likely(ret)) return ret; - ret = kmem_cache_alloc(iocontext_cachep, gfp_flags); + ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node); if (ret) { atomic_set(&ret->refcount, 1); ret->task = current; @@ -3674,10 +3675,10 @@ EXPORT_SYMBOL(current_io_context); * * This is always called in the context of the task which submitted the I/O. */ -struct io_context *get_io_context(gfp_t gfp_flags) +struct io_context *get_io_context(gfp_t gfp_flags, int node) { struct io_context *ret; - ret = current_io_context(gfp_flags); + ret = current_io_context(gfp_flags, node); if (likely(ret)) atomic_inc(&ret->refcount); return ret; diff --git a/block/noop-iosched.c b/block/noop-iosched.c index 56a7c620574f..79af43179421 100644 --- a/block/noop-iosched.c +++ b/block/noop-iosched.c @@ -69,7 +69,7 @@ static void *noop_init_queue(request_queue_t *q, elevator_t *e) { struct noop_data *nd; - nd = kmalloc(sizeof(*nd), GFP_KERNEL); + nd = kmalloc_node(sizeof(*nd), GFP_KERNEL, q->node); if (!nd) return NULL; INIT_LIST_HEAD(&nd->queue); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 593386162f47..6609371c303e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -104,8 +104,7 @@ struct io_context { void put_io_context(struct io_context *ioc); void exit_io_context(void); -struct io_context *current_io_context(gfp_t gfp_flags); -struct io_context *get_io_context(gfp_t gfp_flags); +struct io_context *get_io_context(gfp_t gfp_flags, int node); void copy_io_context(struct io_context **pdst, struct io_context **psrc); void swap_io_context(struct io_context **ioc1, struct io_context **ioc2); -- cgit v1.2.3 From dc72ef4ae35c2016fb594bcc85ce871376682174 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 20 Jul 2006 14:54:05 +0200 Subject: [PATCH] Add blk_start_queueing() helper CFQ implements this on its own now, but it's really block layer knowledge. Tells a device queue to start dispatching requests to the driver, taking care to unplug if needed. Also fixes the issue where as/cfq will invoke a stopped queue, which we really don't want. Signed-off-by: Jens Axboe --- block/as-iosched.c | 3 +-- block/cfq-iosched.c | 22 ++++------------------ block/ll_rw_blk.c | 25 ++++++++++++++++++++----- include/linux/blkdev.h | 1 + 4 files changed, 26 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/block/as-iosched.c b/block/as-iosched.c index f6dc95489316..bc13dc0b29be 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -1280,8 +1280,7 @@ static void as_work_handler(void *data) unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); - if (!as_queue_empty(q)) - q->request_fn(q); + blk_start_queueing(q); spin_unlock_irqrestore(q->queue_lock, flags); } diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 6fb1613d44d7..9f684cc66bd1 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1552,19 +1552,6 @@ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) __cfq_set_active_queue(cfqd, cfqq); } -/* - * should really be a ll_rw_blk.c helper - */ -static void cfq_start_queueing(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - request_queue_t *q = cfqd->queue; - - if (!blk_queue_plugged(q)) - q->request_fn(q); - else - __generic_unplug_device(q); -} - /* * Called when a new fs request (rq) is added (to cfqq). Check if there's * something we should do about it @@ -1593,7 +1580,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, if (cic == cfqd->active_cic && del_timer(&cfqd->idle_slice_timer)) { cfq_slice_expired(cfqd, 0); - cfq_start_queueing(cfqd, cfqq); + blk_start_queueing(cfqd->queue); } return; } @@ -1614,7 +1601,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, if (cfq_cfqq_wait_request(cfqq)) { cfq_mark_cfqq_must_dispatch(cfqq); del_timer(&cfqd->idle_slice_timer); - cfq_start_queueing(cfqd, cfqq); + blk_start_queueing(cfqd->queue); } } else if (cfq_should_preempt(cfqd, cfqq, rq)) { /* @@ -1624,7 +1611,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, */ cfq_preempt_queue(cfqd, cfqq); cfq_mark_cfqq_must_dispatch(cfqq); - cfq_start_queueing(cfqd, cfqq); + blk_start_queueing(cfqd->queue); } } @@ -1832,8 +1819,7 @@ static void cfq_kick_queue(void *data) unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); - blk_remove_plug(q); - q->request_fn(q); + blk_start_queueing(q); spin_unlock_irqrestore(q->queue_lock, flags); } diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index c6dfa889206c..346be9ae31f6 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2266,6 +2266,25 @@ struct request *blk_get_request(request_queue_t *q, int rw, gfp_t gfp_mask) } EXPORT_SYMBOL(blk_get_request); +/** + * blk_start_queueing - initiate dispatch of requests to device + * @q: request queue to kick into gear + * + * This is basically a helper to remove the need to know whether a queue + * is plugged or not if someone just wants to initiate dispatch of requests + * for this queue. + * + * The queue lock must be held with interrupts disabled. + */ +void blk_start_queueing(request_queue_t *q) +{ + if (!blk_queue_plugged(q)) + q->request_fn(q); + else + __generic_unplug_device(q); +} +EXPORT_SYMBOL(blk_start_queueing); + /** * blk_requeue_request - put a request back on queue * @q: request queue where request should be inserted @@ -2333,11 +2352,7 @@ void blk_insert_request(request_queue_t *q, struct request *rq, drive_stat_acct(rq, rq->nr_sectors, 1); __elv_add_request(q, rq, where, 0); - - if (blk_queue_plugged(q)) - __generic_unplug_device(q); - else - q->request_fn(q); + blk_start_queueing(q); spin_unlock_irqrestore(q->queue_lock, flags); } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6609371c303e..5d8e288db163 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -635,6 +635,7 @@ extern void blk_stop_queue(request_queue_t *q); extern void blk_sync_queue(struct request_queue *q); extern void __blk_stop_queue(request_queue_t *q); extern void blk_run_queue(request_queue_t *); +extern void blk_start_queueing(request_queue_t *); extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int); extern int blk_rq_unmap_user(struct bio *, unsigned int); -- cgit v1.2.3 From 5404bc7a87b9949cf61e0174b21f80e73239ab25 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 10 Aug 2006 09:01:02 +0200 Subject: [PATCH] Allow file systems to differentiate between data and meta reads We can use this information for making more intelligent priority decisions, and it will also be useful for blktrace. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 2 ++ include/linux/bio.h | 2 ++ include/linux/blkdev.h | 3 +++ include/linux/fs.h | 1 + 4 files changed, 8 insertions(+) (limited to 'include/linux') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index e3980ec747c1..57992ae511c2 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2884,6 +2884,8 @@ static void init_request_from_bio(struct request *req, struct bio *bio) if (bio_sync(bio)) req->cmd_flags |= REQ_RW_SYNC; + if (bio_rw_meta(bio)) + req->cmd_flags |= REQ_RW_META; req->errors = 0; req->hard_sector = req->sector = bio->bi_sector; diff --git a/include/linux/bio.h b/include/linux/bio.h index 76bdaeab6f62..711c321a7011 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -148,6 +148,7 @@ struct bio { #define BIO_RW_BARRIER 2 #define BIO_RW_FAILFAST 3 #define BIO_RW_SYNC 4 +#define BIO_RW_META 5 /* * upper 16 bits of bi_rw define the io priority of this bio @@ -178,6 +179,7 @@ struct bio { #define bio_sync(bio) ((bio)->bi_rw & (1 << BIO_RW_SYNC)) #define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST)) #define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD)) +#define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META)) /* * will die diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 5d8e288db163..2c01a90998a7 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -180,6 +180,7 @@ enum rq_flag_bits { __REQ_ORDERED_COLOR, /* is before or after barrier */ __REQ_RW_SYNC, /* request is sync (O_DIRECT) */ __REQ_ALLOCED, /* request came from our alloc pool */ + __REQ_RW_META, /* metadata io request */ __REQ_NR_BITS, /* stops here */ }; @@ -200,6 +201,7 @@ enum rq_flag_bits { #define REQ_ORDERED_COLOR (1 << __REQ_ORDERED_COLOR) #define REQ_RW_SYNC (1 << __REQ_RW_SYNC) #define REQ_ALLOCED (1 << __REQ_ALLOCED) +#define REQ_RW_META (1 << __REQ_RW_META) #define BLK_MAX_CDB 16 @@ -543,6 +545,7 @@ enum { * We regard a request as sync, if it's a READ or a SYNC write. */ #define rq_is_sync(rq) (rq_data_dir((rq)) == READ || (rq)->cmd_flags & REQ_RW_SYNC) +#define rq_is_meta(rq) ((rq)->cmd_flags & REQ_RW_META) static inline int blk_queue_full(struct request_queue *q, int rw) { diff --git a/include/linux/fs.h b/include/linux/fs.h index 9306f63bf77e..d68c37af4dfb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -80,6 +80,7 @@ extern int dir_notify_enable; #define READA 2 /* read-ahead - don't block if no resources */ #define SWRITE 3 /* for ll_rw_block() - wait for buffer lock */ #define READ_SYNC (READ | (1 << BIO_RW_SYNC)) +#define READ_META (READ | (1 << BIO_RW_META)) #define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC)) #define WRITE_BARRIER ((1 << BIO_RW) | (1 << BIO_RW_BARRIER)) -- cgit v1.2.3 From 7457e6e2d7406c7009e9ad03db1335fe93b5fb71 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sun, 23 Jul 2006 02:12:01 +0200 Subject: [PATCH] blktrace: support for logging metadata reads Signed-off-by: Jens Axboe --- block/blktrace.c | 5 ++++- include/linux/blktrace_api.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/block/blktrace.c b/block/blktrace.c index 8ff33441d8a2..2592f215a905 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -69,7 +69,7 @@ static u32 ddir_act[2] __read_mostly = { BLK_TC_ACT(BLK_TC_READ), BLK_TC_ACT(BLK /* * Bio action bits of interest */ -static u32 bio_act[5] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC), 0, BLK_TC_ACT(BLK_TC_AHEAD) }; +static u32 bio_act[9] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC), 0, BLK_TC_ACT(BLK_TC_AHEAD), 0, 0, 0, BLK_TC_ACT(BLK_TC_META) }; /* * More could be added as needed, taking care to increment the decrementer @@ -81,6 +81,8 @@ static u32 bio_act[5] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_AC (((rw) & (1 << BIO_RW_SYNC)) >> (BIO_RW_SYNC - 1)) #define trace_ahead_bit(rw) \ (((rw) & (1 << BIO_RW_AHEAD)) << (2 - BIO_RW_AHEAD)) +#define trace_meta_bit(rw) \ + (((rw) & (1 << BIO_RW_META)) >> (BIO_RW_META - 3)) /* * The worker for the various blk_add_trace*() types. Fills out a @@ -103,6 +105,7 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, what |= bio_act[trace_barrier_bit(rw)]; what |= bio_act[trace_sync_bit(rw)]; what |= bio_act[trace_ahead_bit(rw)]; + what |= bio_act[trace_meta_bit(rw)]; pid = tsk->pid; if (unlikely(act_log_check(bt, what, sector, pid))) diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index ea48eb1b3fd3..b99a714fcac6 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -20,6 +20,7 @@ enum blktrace_cat { BLK_TC_PC = 1 << 9, /* pc requests */ BLK_TC_NOTIFY = 1 << 10, /* special message */ BLK_TC_AHEAD = 1 << 11, /* readahead */ + BLK_TC_META = 1 << 12, /* metadata */ BLK_TC_END = 1 << 15, /* only 16-bits, reminder */ }; -- cgit v1.2.3 From cf9a2ae8d49948f861b56e5333530e491a9da190 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 29 Aug 2006 19:05:54 +0100 Subject: [PATCH] BLOCK: Move functions out of buffer code [try #6] Move some functions out of the buffering code that aren't strictly buffering specific. This is a precursor to being able to disable the block layer. (*) Moved some stuff out of fs/buffer.c: (*) The file sync and general sync stuff moved to fs/sync.c. (*) The superblock sync stuff moved to fs/super.c. (*) do_invalidatepage() moved to mm/truncate.c. (*) try_to_release_page() moved to mm/filemap.c. (*) Moved some related declarations between header files: (*) declarations for do_invalidatepage() and try_to_release_page() moved to linux/mm.h. (*) __set_page_dirty_buffers() moved to linux/buffer_head.h. Signed-Off-By: David Howells Signed-off-by: Jens Axboe --- fs/buffer.c | 174 -------------------------------------------- fs/super.c | 31 ++++++++ fs/sync.c | 113 ++++++++++++++++++++++++++++ include/linux/buffer_head.h | 3 +- include/linux/fs.h | 1 + include/linux/mm.h | 4 +- mm/filemap.c | 30 ++++++++ mm/page-writeback.c | 1 + mm/truncate.c | 24 ++++++ 9 files changed, 204 insertions(+), 177 deletions(-) (limited to 'include/linux') diff --git a/fs/buffer.c b/fs/buffer.c index 3b6d701073e7..16cfbcd254f1 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -159,31 +159,6 @@ int sync_blockdev(struct block_device *bdev) } EXPORT_SYMBOL(sync_blockdev); -static void __fsync_super(struct super_block *sb) -{ - sync_inodes_sb(sb, 0); - DQUOT_SYNC(sb); - lock_super(sb); - if (sb->s_dirt && sb->s_op->write_super) - sb->s_op->write_super(sb); - unlock_super(sb); - if (sb->s_op->sync_fs) - sb->s_op->sync_fs(sb, 1); - sync_blockdev(sb->s_bdev); - sync_inodes_sb(sb, 1); -} - -/* - * Write out and wait upon all dirty data associated with this - * superblock. Filesystem data as well as the underlying block - * device. Takes the superblock lock. - */ -int fsync_super(struct super_block *sb) -{ - __fsync_super(sb); - return sync_blockdev(sb->s_bdev); -} - /* * Write out and wait upon all dirty data associated with this * device. Filesystem data as well as the underlying block @@ -259,118 +234,6 @@ void thaw_bdev(struct block_device *bdev, struct super_block *sb) } EXPORT_SYMBOL(thaw_bdev); -/* - * sync everything. Start out by waking pdflush, because that writes back - * all queues in parallel. - */ -static void do_sync(unsigned long wait) -{ - wakeup_pdflush(0); - sync_inodes(0); /* All mappings, inodes and their blockdevs */ - DQUOT_SYNC(NULL); - sync_supers(); /* Write the superblocks */ - sync_filesystems(0); /* Start syncing the filesystems */ - sync_filesystems(wait); /* Waitingly sync the filesystems */ - sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ - if (!wait) - printk("Emergency Sync complete\n"); - if (unlikely(laptop_mode)) - laptop_sync_completion(); -} - -asmlinkage long sys_sync(void) -{ - do_sync(1); - return 0; -} - -void emergency_sync(void) -{ - pdflush_operation(do_sync, 0); -} - -/* - * Generic function to fsync a file. - * - * filp may be NULL if called via the msync of a vma. - */ - -int file_fsync(struct file *filp, struct dentry *dentry, int datasync) -{ - struct inode * inode = dentry->d_inode; - struct super_block * sb; - int ret, err; - - /* sync the inode to buffers */ - ret = write_inode_now(inode, 0); - - /* sync the superblock to buffers */ - sb = inode->i_sb; - lock_super(sb); - if (sb->s_op->write_super) - sb->s_op->write_super(sb); - unlock_super(sb); - - /* .. finally sync the buffers to disk */ - err = sync_blockdev(sb->s_bdev); - if (!ret) - ret = err; - return ret; -} - -long do_fsync(struct file *file, int datasync) -{ - int ret; - int err; - struct address_space *mapping = file->f_mapping; - - if (!file->f_op || !file->f_op->fsync) { - /* Why? We can still call filemap_fdatawrite */ - ret = -EINVAL; - goto out; - } - - ret = filemap_fdatawrite(mapping); - - /* - * We need to protect against concurrent writers, which could cause - * livelocks in fsync_buffers_list(). - */ - mutex_lock(&mapping->host->i_mutex); - err = file->f_op->fsync(file, file->f_dentry, datasync); - if (!ret) - ret = err; - mutex_unlock(&mapping->host->i_mutex); - err = filemap_fdatawait(mapping); - if (!ret) - ret = err; -out: - return ret; -} - -static long __do_fsync(unsigned int fd, int datasync) -{ - struct file *file; - int ret = -EBADF; - - file = fget(fd); - if (file) { - ret = do_fsync(file, datasync); - fput(file); - } - return ret; -} - -asmlinkage long sys_fsync(unsigned int fd) -{ - return __do_fsync(fd, 0); -} - -asmlinkage long sys_fdatasync(unsigned int fd) -{ - return __do_fsync(fd, 1); -} - /* * Various filesystems appear to want __find_get_block to be non-blocking. * But it's the page lock which protects the buffers. To get around this, @@ -1550,35 +1413,6 @@ static void discard_buffer(struct buffer_head * bh) unlock_buffer(bh); } -/** - * try_to_release_page() - release old fs-specific metadata on a page - * - * @page: the page which the kernel is trying to free - * @gfp_mask: memory allocation flags (and I/O mode) - * - * The address_space is to try to release any data against the page - * (presumably at page->private). If the release was successful, return `1'. - * Otherwise return zero. - * - * The @gfp_mask argument specifies whether I/O may be performed to release - * this page (__GFP_IO), and whether the call may block (__GFP_WAIT). - * - * NOTE: @gfp_mask may go away, and this function may become non-blocking. - */ -int try_to_release_page(struct page *page, gfp_t gfp_mask) -{ - struct address_space * const mapping = page->mapping; - - BUG_ON(!PageLocked(page)); - if (PageWriteback(page)) - return 0; - - if (mapping && mapping->a_ops->releasepage) - return mapping->a_ops->releasepage(page, gfp_mask); - return try_to_free_buffers(page); -} -EXPORT_SYMBOL(try_to_release_page); - /** * block_invalidatepage - invalidate part of all of a buffer-backed page * @@ -1630,14 +1464,6 @@ out: } EXPORT_SYMBOL(block_invalidatepage); -void do_invalidatepage(struct page *page, unsigned long offset) -{ - void (*invalidatepage)(struct page *, unsigned long); - invalidatepage = page->mapping->a_ops->invalidatepage ? : - block_invalidatepage; - (*invalidatepage)(page, offset); -} - /* * We attach and possibly dirty the buffers atomically wrt * __set_page_dirty_buffers() via private_lock. try_to_free_buffers diff --git a/fs/super.c b/fs/super.c index 6987824d0dce..15671cd048b1 100644 --- a/fs/super.c +++ b/fs/super.c @@ -220,6 +220,37 @@ static int grab_super(struct super_block *s) __releases(sb_lock) return 0; } +/* + * Write out and wait upon all dirty data associated with this + * superblock. Filesystem data as well as the underlying block + * device. Takes the superblock lock. Requires a second blkdev + * flush by the caller to complete the operation. + */ +void __fsync_super(struct super_block *sb) +{ + sync_inodes_sb(sb, 0); + DQUOT_SYNC(sb); + lock_super(sb); + if (sb->s_dirt && sb->s_op->write_super) + sb->s_op->write_super(sb); + unlock_super(sb); + if (sb->s_op->sync_fs) + sb->s_op->sync_fs(sb, 1); + sync_blockdev(sb->s_bdev); + sync_inodes_sb(sb, 1); +} + +/* + * Write out and wait upon all dirty data associated with this + * superblock. Filesystem data as well as the underlying block + * device. Takes the superblock lock. + */ +int fsync_super(struct super_block *sb) +{ + __fsync_super(sb); + return sync_blockdev(sb->s_bdev); +} + /** * generic_shutdown_super - common helper for ->kill_sb() * @sb: superblock to kill diff --git a/fs/sync.c b/fs/sync.c index 955aef04da28..1de747b5ddb9 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -10,10 +10,123 @@ #include #include #include +#include +#include #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ SYNC_FILE_RANGE_WAIT_AFTER) +/* + * sync everything. Start out by waking pdflush, because that writes back + * all queues in parallel. + */ +static void do_sync(unsigned long wait) +{ + wakeup_pdflush(0); + sync_inodes(0); /* All mappings, inodes and their blockdevs */ + DQUOT_SYNC(NULL); + sync_supers(); /* Write the superblocks */ + sync_filesystems(0); /* Start syncing the filesystems */ + sync_filesystems(wait); /* Waitingly sync the filesystems */ + sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ + if (!wait) + printk("Emergency Sync complete\n"); + if (unlikely(laptop_mode)) + laptop_sync_completion(); +} + +asmlinkage long sys_sync(void) +{ + do_sync(1); + return 0; +} + +void emergency_sync(void) +{ + pdflush_operation(do_sync, 0); +} + +/* + * Generic function to fsync a file. + * + * filp may be NULL if called via the msync of a vma. + */ +int file_fsync(struct file *filp, struct dentry *dentry, int datasync) +{ + struct inode * inode = dentry->d_inode; + struct super_block * sb; + int ret, err; + + /* sync the inode to buffers */ + ret = write_inode_now(inode, 0); + + /* sync the superblock to buffers */ + sb = inode->i_sb; + lock_super(sb); + if (sb->s_op->write_super) + sb->s_op->write_super(sb); + unlock_super(sb); + + /* .. finally sync the buffers to disk */ + err = sync_blockdev(sb->s_bdev); + if (!ret) + ret = err; + return ret; +} + +long do_fsync(struct file *file, int datasync) +{ + int ret; + int err; + struct address_space *mapping = file->f_mapping; + + if (!file->f_op || !file->f_op->fsync) { + /* Why? We can still call filemap_fdatawrite */ + ret = -EINVAL; + goto out; + } + + ret = filemap_fdatawrite(mapping); + + /* + * We need to protect against concurrent writers, which could cause + * livelocks in fsync_buffers_list(). + */ + mutex_lock(&mapping->host->i_mutex); + err = file->f_op->fsync(file, file->f_dentry, datasync); + if (!ret) + ret = err; + mutex_unlock(&mapping->host->i_mutex); + err = filemap_fdatawait(mapping); + if (!ret) + ret = err; +out: + return ret; +} + +static long __do_fsync(unsigned int fd, int datasync) +{ + struct file *file; + int ret = -EBADF; + + file = fget(fd); + if (file) { + ret = do_fsync(file, datasync); + fput(file); + } + return ret; +} + +asmlinkage long sys_fsync(unsigned int fd) +{ + return __do_fsync(fd, 0); +} + +asmlinkage long sys_fdatasync(unsigned int fd) +{ + return __do_fsync(fd, 1); +} + /* * sys_sync_file_range() permits finely controlled syncing over a segment of * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 737e407d0cd1..64b508e35d2a 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -190,9 +190,7 @@ extern int buffer_heads_over_limit; * Generic address_space_operations implementations for buffer_head-backed * address_spaces. */ -int try_to_release_page(struct page * page, gfp_t gfp_mask); void block_invalidatepage(struct page *page, unsigned long offset); -void do_invalidatepage(struct page *page, unsigned long offset); int block_write_full_page(struct page *page, get_block_t *get_block, struct writeback_control *wbc); int block_read_full_page(struct page*, get_block_t*); @@ -302,4 +300,5 @@ static inline void lock_buffer(struct buffer_head *bh) __lock_buffer(bh); } +extern int __set_page_dirty_buffers(struct page *page); #endif /* _LINUX_BUFFER_HEAD_H */ diff --git a/include/linux/fs.h b/include/linux/fs.h index d68c37af4dfb..1728142ec4b6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1546,6 +1546,7 @@ extern int __filemap_fdatawrite_range(struct address_space *mapping, extern long do_fsync(struct file *file, int datasync); extern void sync_supers(void); extern void sync_filesystems(int wait); +extern void __fsync_super(struct super_block *sb); extern void emergency_sync(void); extern void emergency_remount(void); extern int do_remount_sb(struct super_block *sb, int flags, diff --git a/include/linux/mm.h b/include/linux/mm.h index 7b703b6d4358..4edf1934e5ca 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -743,7 +743,9 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long int len, int write, int force, struct page **pages, struct vm_area_struct **vmas); void print_bad_pte(struct vm_area_struct *, pte_t, unsigned long); -int __set_page_dirty_buffers(struct page *page); +extern int try_to_release_page(struct page * page, gfp_t gfp_mask); +extern void do_invalidatepage(struct page *page, unsigned long offset); + int __set_page_dirty_nobuffers(struct page *page); int redirty_page_for_writepage(struct writeback_control *wbc, struct page *page); diff --git a/mm/filemap.c b/mm/filemap.c index 3277f3b23524..d6846de08887 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2491,3 +2491,33 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, } return retval; } + +/** + * try_to_release_page() - release old fs-specific metadata on a page + * + * @page: the page which the kernel is trying to free + * @gfp_mask: memory allocation flags (and I/O mode) + * + * The address_space is to try to release any data against the page + * (presumably at page->private). If the release was successful, return `1'. + * Otherwise return zero. + * + * The @gfp_mask argument specifies whether I/O may be performed to release + * this page (__GFP_IO), and whether the call may block (__GFP_WAIT). + * + * NOTE: @gfp_mask may go away, and this function may become non-blocking. + */ +int try_to_release_page(struct page *page, gfp_t gfp_mask) +{ + struct address_space * const mapping = page->mapping; + + BUG_ON(!PageLocked(page)); + if (PageWriteback(page)) + return 0; + + if (mapping && mapping->a_ops->releasepage) + return mapping->a_ops->releasepage(page, gfp_mask); + return try_to_free_buffers(page); +} + +EXPORT_SYMBOL(try_to_release_page); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 488b7088557c..9fdcc7903956 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -30,6 +30,7 @@ #include #include #include +#include /* * The maximum number of pages to writeout in a single bdflush/kupdate diff --git a/mm/truncate.c b/mm/truncate.c index a654928323dc..cd3e34b816db 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -17,6 +17,30 @@ do_invalidatepage */ +/** + * do_invalidatepage - invalidate part of all of a page + * @page: the page which is affected + * @offset: the index of the truncation point + * + * do_invalidatepage() is called when all or part of the page has become + * invalidated by a truncate operation. + * + * do_invalidatepage() does not have to release all buffers, but it must + * ensure that no dirty buffer is left outside @offset and that no I/O + * is underway against any of the blocks which are outside the truncation + * point. Because the caller is about to free (and possibly reuse) those + * blocks on-disk. + */ +void do_invalidatepage(struct page *page, unsigned long offset) +{ + void (*invalidatepage)(struct page *, unsigned long); + invalidatepage = page->mapping->a_ops->invalidatepage; + if (!invalidatepage) + invalidatepage = block_invalidatepage; + if (invalidatepage) + (*invalidatepage)(page, offset); +} + static inline void truncate_partial_page(struct page *page, unsigned partial) { memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial); -- cgit v1.2.3 From 0d67a46df0125e20d14f12dbd3646f1f1bf23e8c Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 29 Aug 2006 19:05:56 +0100 Subject: [PATCH] BLOCK: Remove duplicate declaration of exit_io_context() [try #6] Remove the duplicate declaration of exit_io_context() from linux/sched.h. Signed-Off-By: David Howells Signed-off-by: Jens Axboe --- include/linux/sched.h | 1 - kernel/exit.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index a06fc89cf6e5..fc4a9873ec10 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -710,7 +710,6 @@ extern unsigned int max_cache_size; struct io_context; /* See blkdev.h */ -void exit_io_context(void); struct cpuset; #define NGROUPS_SMALL 32 diff --git a/kernel/exit.c b/kernel/exit.c index 2e4c13cba95a..c189de2927ab 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -38,6 +38,7 @@ #include #include /* for audit_free() */ #include +#include #include #include -- cgit v1.2.3 From 07f3f05c1e3052b8656129b2a5aca9f888241a34 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sat, 30 Sep 2006 20:52:18 +0200 Subject: [PATCH] BLOCK: Move extern declarations out of fs/*.c into header files [try #6] Create a new header file, fs/internal.h, for common definitions local to the sources in the fs/ directory. Move extern definitions that should be in header files from fs/*.c to fs/internal.h or other main header files where they span directories. Signed-Off-By: David Howells Signed-off-by: Jens Axboe --- arch/mips/kernel/signal_n32.c | 4 ++-- fs/binfmt_elf.c | 1 - fs/block_dev.c | 1 + fs/char_dev.c | 1 + fs/compat.c | 10 +++------- fs/compat_ioctl.c | 2 -- fs/dcache.c | 4 +--- fs/fs-writeback.c | 3 +-- fs/internal.h | 36 ++++++++++++++++++++++++++++++++++++ fs/namespace.c | 3 +-- include/linux/ramfs.h | 1 + include/linux/tty.h | 3 +++ kernel/compat.c | 2 ++ 13 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 fs/internal.h (limited to 'include/linux') diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 477c5334ec1b..50c17eaa7f25 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -42,6 +42,8 @@ #include "signal-common.h" +extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); + /* * Including would give use the 64-bit syscall numbers ... */ @@ -81,8 +83,6 @@ struct rt_sigframe_n32 { #endif }; -extern void sigset_from_compat (sigset_t *set, compat_sigset_t *compat); - save_static_function(sysn32_rt_sigsuspend); __attribute_used__ noinline static int _sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 6eb48e1446ec..bad52433de69 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -46,7 +46,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); static int load_elf_library(struct file *); static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); -extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); #ifndef elf_addr_t #define elf_addr_t unsigned long diff --git a/fs/block_dev.c b/fs/block_dev.c index 4346468139e8..20f7333ba372 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -22,6 +22,7 @@ #include #include #include +#include "internal.h" struct bdev_inode { struct block_device bdev; diff --git a/fs/char_dev.c b/fs/char_dev.c index 1f3285affa39..a885f46ca001 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -24,6 +24,7 @@ #ifdef CONFIG_KMOD #include #endif +#include "internal.h" /* * capabilities for /dev/mem, /dev/kmem and similar directly mappable character diff --git a/fs/compat.c b/fs/compat.c index ce982f6e8c80..122b4e3992b5 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -52,11 +52,12 @@ #include #include #include - -extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); +#include "internal.h" int compat_log = 1; +extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); + int compat_printk(const char *fmt, ...) { va_list ap; @@ -313,9 +314,6 @@ out: #define IOCTL_HASHSIZE 256 static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE]; -extern struct ioctl_trans ioctl_start[]; -extern int ioctl_table_size; - static inline unsigned long ioctl32_hash(unsigned long cmd) { return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE; @@ -838,8 +836,6 @@ static int do_nfs4_super_data_conv(void *raw_data) return 0; } -extern int copy_mount_options (const void __user *, unsigned long *); - #define SMBFS_NAME "smbfs" #define NCPFS_NAME "ncpfs" #define NFS4_NAME "nfs4" diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 4063a9396977..ab74c9bd55fe 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -1279,8 +1279,6 @@ static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg) return err; } -extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); - #ifdef CONFIG_VT static int vt_check(struct file *file) diff --git a/fs/dcache.c b/fs/dcache.c index 17b392a2049e..fc2faa44f8d1 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -32,6 +32,7 @@ #include #include #include +#include "internal.h" int sysctl_vfs_cache_pressure __read_mostly = 100; @@ -1877,9 +1878,6 @@ kmem_cache_t *filp_cachep __read_mostly; EXPORT_SYMBOL(d_genocide); -extern void bdev_cache_init(void); -extern void chrdev_init(void); - void __init vfs_caches_init_early(void) { dcache_init_early(); diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 892643dc9af1..0639024d83a9 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -22,8 +22,7 @@ #include #include #include - -extern struct super_block *blockdev_superblock; +#include "internal.h" /** * __mark_inode_dirty - internal function diff --git a/fs/internal.h b/fs/internal.h new file mode 100644 index 000000000000..c21ecd37b1e7 --- /dev/null +++ b/fs/internal.h @@ -0,0 +1,36 @@ +/* fs/ internal definitions + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include + +/* + * block_dev.c + */ +extern struct super_block *blockdev_superblock; +extern void __init bdev_cache_init(void); + +/* + * char_dev.c + */ +extern void __init chrdev_init(void); + +/* + * compat_ioctl.c + */ +#ifdef CONFIG_COMPAT +extern struct ioctl_trans ioctl_start[]; +extern int ioctl_table_size; +#endif + +/* + * namespace.c + */ +extern int copy_mount_options(const void __user *, unsigned long *); diff --git a/fs/namespace.c b/fs/namespace.c index 6ede3a539ed8..66d921e14fee 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -24,12 +24,11 @@ #include #include #include +#include #include #include #include "pnode.h" -extern int __init init_rootfs(void); - /* spinlock for vfsmount related operations, inplace of dcache_lock */ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h index 00b340ba6612..b160fb18e8d6 100644 --- a/include/linux/ramfs.h +++ b/include/linux/ramfs.h @@ -17,5 +17,6 @@ extern int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma); extern const struct file_operations ramfs_file_operations; extern struct vm_operations_struct generic_file_vm_ops; +extern int __init init_rootfs(void); #endif diff --git a/include/linux/tty.h b/include/linux/tty.h index ea4c2605f8da..44091c0db0b4 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -307,6 +307,9 @@ extern void tty_ldisc_put(int); extern void tty_wakeup(struct tty_struct *tty); extern void tty_ldisc_flush(struct tty_struct *tty); +extern int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg); + extern struct mutex tty_mutex; /* n_tty.c */ diff --git a/kernel/compat.c b/kernel/compat.c index 75573e5d27b0..b4fbd838cd77 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -26,6 +26,8 @@ #include +extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); + int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) { return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || -- cgit v1.2.3 From 811d736f9e8013966e1a5a930c0db09508bdbb15 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 29 Aug 2006 19:06:09 +0100 Subject: [PATCH] BLOCK: Dissociate generic_writepages() from mpage stuff [try #6] Dissociate the generic_writepages() function from the mpage stuff, moving its declaration to linux/mm.h and actually emitting a full implementation into mm/page-writeback.c. The implementation is a partial duplicate of mpage_writepages() with all BIO references removed. It is used by NFS to do writeback. Signed-Off-By: David Howells Signed-off-by: Jens Axboe --- fs/block_dev.c | 1 + fs/mpage.c | 2 + include/linux/mpage.h | 6 --- include/linux/writeback.h | 2 + mm/page-writeback.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/block_dev.c b/fs/block_dev.c index 20f7333ba372..335c38bb86eb 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/mpage.c b/fs/mpage.c index 1e4598247d0b..692a3e578fc8 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -693,6 +693,8 @@ out: * the call was made get new I/O started against them. If wbc->sync_mode is * WB_SYNC_ALL then we were called for data integrity and we must wait for * existing IO to complete. + * + * If you fix this you should check generic_writepages() also! */ int mpage_writepages(struct address_space *mapping, diff --git a/include/linux/mpage.h b/include/linux/mpage.h index 3ca880463c47..517c098fde20 100644 --- a/include/linux/mpage.h +++ b/include/linux/mpage.h @@ -20,9 +20,3 @@ int mpage_writepages(struct address_space *mapping, struct writeback_control *wbc, get_block_t get_block); int mpage_writepage(struct page *page, get_block_t *get_block, struct writeback_control *wbc); - -static inline int -generic_writepages(struct address_space *mapping, struct writeback_control *wbc) -{ - return mpage_writepages(mapping, wbc, NULL); -} diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 9d4074ecd0cd..4f4d98addb44 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -111,6 +111,8 @@ balance_dirty_pages_ratelimited(struct address_space *mapping) } int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0); +extern int generic_writepages(struct address_space *mapping, + struct writeback_control *wbc); int do_writepages(struct address_space *mapping, struct writeback_control *wbc); int sync_page_range(struct inode *inode, struct address_space *mapping, loff_t pos, loff_t count); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 9fdcc7903956..ecf27839c203 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -31,6 +31,7 @@ #include #include #include +#include /* * The maximum number of pages to writeout in a single bdflush/kupdate @@ -551,6 +552,139 @@ void __init page_writeback_init(void) register_cpu_notifier(&ratelimit_nb); } +/** + * generic_writepages - walk the list of dirty pages of the given + * address space and writepage() all of them. + * + * @mapping: address space structure to write + * @wbc: subtract the number of written pages from *@wbc->nr_to_write + * + * This is a library function, which implements the writepages() + * address_space_operation. + * + * If a page is already under I/O, generic_writepages() skips it, even + * if it's dirty. This is desirable behaviour for memory-cleaning writeback, + * but it is INCORRECT for data-integrity system calls such as fsync(). fsync() + * and msync() need to guarantee that all the data which was dirty at the time + * the call was made get new I/O started against them. If wbc->sync_mode is + * WB_SYNC_ALL then we were called for data integrity and we must wait for + * existing IO to complete. + * + * Derived from mpage_writepages() - if you fix this you should check that + * also! + */ +int generic_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + struct backing_dev_info *bdi = mapping->backing_dev_info; + int ret = 0; + int done = 0; + int (*writepage)(struct page *page, struct writeback_control *wbc); + struct pagevec pvec; + int nr_pages; + pgoff_t index; + pgoff_t end; /* Inclusive */ + int scanned = 0; + int range_whole = 0; + + if (wbc->nonblocking && bdi_write_congested(bdi)) { + wbc->encountered_congestion = 1; + return 0; + } + + writepage = mapping->a_ops->writepage; + + /* deal with chardevs and other special file */ + if (!writepage) + return 0; + + pagevec_init(&pvec, 0); + if (wbc->range_cyclic) { + index = mapping->writeback_index; /* Start from prev offset */ + end = -1; + } else { + index = wbc->range_start >> PAGE_CACHE_SHIFT; + end = wbc->range_end >> PAGE_CACHE_SHIFT; + if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) + range_whole = 1; + scanned = 1; + } +retry: + while (!done && (index <= end) && + (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, + PAGECACHE_TAG_DIRTY, + min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) { + unsigned i; + + scanned = 1; + for (i = 0; i < nr_pages; i++) { + struct page *page = pvec.pages[i]; + + /* + * At this point we hold neither mapping->tree_lock nor + * lock on the page itself: the page may be truncated or + * invalidated (changing page->mapping to NULL), or even + * swizzled back from swapper_space to tmpfs file + * mapping + */ + lock_page(page); + + if (unlikely(page->mapping != mapping)) { + unlock_page(page); + continue; + } + + if (!wbc->range_cyclic && page->index > end) { + done = 1; + unlock_page(page); + continue; + } + + if (wbc->sync_mode != WB_SYNC_NONE) + wait_on_page_writeback(page); + + if (PageWriteback(page) || + !clear_page_dirty_for_io(page)) { + unlock_page(page); + continue; + } + + ret = (*writepage)(page, wbc); + if (ret) { + if (ret == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + else + set_bit(AS_EIO, &mapping->flags); + } + + if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) + unlock_page(page); + if (ret || (--(wbc->nr_to_write) <= 0)) + done = 1; + if (wbc->nonblocking && bdi_write_congested(bdi)) { + wbc->encountered_congestion = 1; + done = 1; + } + } + pagevec_release(&pvec); + cond_resched(); + } + if (!scanned && !done) { + /* + * We hit the last page and there is more work to be done: wrap + * back to the start of the file + */ + scanned = 1; + index = 0; + goto retry; + } + if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) + mapping->writeback_index = index; + return ret; +} + +EXPORT_SYMBOL(generic_writepages); + int do_writepages(struct address_space *mapping, struct writeback_control *wbc) { int ret; -- cgit v1.2.3 From 863d5b822c02d0e7215fb84ca79e9f8c3e35f04e Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 29 Aug 2006 19:06:14 +0100 Subject: [PATCH] BLOCK: Move the loop device ioctl compat stuff to the loop driver [try #6] Move the loop device ioctl compat stuff from fs/compat_ioctl.c to the loop driver so that the loop header file doesn't need to be included. Signed-Off-By: David Howells Signed-off-by: Jens Axboe --- drivers/block/loop.c | 160 +++++++++++++++++++++++++++++++++++++++++++ fs/compat_ioctl.c | 68 ------------------ include/linux/compat_ioctl.h | 6 -- 3 files changed, 160 insertions(+), 74 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 68b0471ad5a6..d6bb8da955a2 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include /* for invalidate_bdev() */ @@ -1165,6 +1166,162 @@ static int lo_ioctl(struct inode * inode, struct file * file, return err; } +#ifdef CONFIG_COMPAT +struct compat_loop_info { + compat_int_t lo_number; /* ioctl r/o */ + compat_dev_t lo_device; /* ioctl r/o */ + compat_ulong_t lo_inode; /* ioctl r/o */ + compat_dev_t lo_rdevice; /* ioctl r/o */ + compat_int_t lo_offset; + compat_int_t lo_encrypt_type; + compat_int_t lo_encrypt_key_size; /* ioctl w/o */ + compat_int_t lo_flags; /* ioctl r/o */ + char lo_name[LO_NAME_SIZE]; + unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ + compat_ulong_t lo_init[2]; + char reserved[4]; +}; + +/* + * Transfer 32-bit compatibility structure in userspace to 64-bit loop info + * - noinlined to reduce stack space usage in main part of driver + */ +static noinline int +loop_info64_from_compat(const struct compat_loop_info *arg, + struct loop_info64 *info64) +{ + struct compat_loop_info info; + + if (copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + + memset(info64, 0, sizeof(*info64)); + info64->lo_number = info.lo_number; + info64->lo_device = info.lo_device; + info64->lo_inode = info.lo_inode; + info64->lo_rdevice = info.lo_rdevice; + info64->lo_offset = info.lo_offset; + info64->lo_sizelimit = 0; + info64->lo_encrypt_type = info.lo_encrypt_type; + info64->lo_encrypt_key_size = info.lo_encrypt_key_size; + info64->lo_flags = info.lo_flags; + info64->lo_init[0] = info.lo_init[0]; + info64->lo_init[1] = info.lo_init[1]; + if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI) + memcpy(info64->lo_crypt_name, info.lo_name, LO_NAME_SIZE); + else + memcpy(info64->lo_file_name, info.lo_name, LO_NAME_SIZE); + memcpy(info64->lo_encrypt_key, info.lo_encrypt_key, LO_KEY_SIZE); + return 0; +} + +/* + * Transfer 64-bit loop info to 32-bit compatibility structure in userspace + * - noinlined to reduce stack space usage in main part of driver + */ +static noinline int +loop_info64_to_compat(const struct loop_info64 *info64, + struct compat_loop_info __user *arg) +{ + struct compat_loop_info info; + + memset(&info, 0, sizeof(info)); + info.lo_number = info64->lo_number; + info.lo_device = info64->lo_device; + info.lo_inode = info64->lo_inode; + info.lo_rdevice = info64->lo_rdevice; + info.lo_offset = info64->lo_offset; + info.lo_encrypt_type = info64->lo_encrypt_type; + info.lo_encrypt_key_size = info64->lo_encrypt_key_size; + info.lo_flags = info64->lo_flags; + info.lo_init[0] = info64->lo_init[0]; + info.lo_init[1] = info64->lo_init[1]; + if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI) + memcpy(info.lo_name, info64->lo_crypt_name, LO_NAME_SIZE); + else + memcpy(info.lo_name, info64->lo_file_name, LO_NAME_SIZE); + memcpy(info.lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE); + + /* error in case values were truncated */ + if (info.lo_device != info64->lo_device || + info.lo_rdevice != info64->lo_rdevice || + info.lo_inode != info64->lo_inode || + info.lo_offset != info64->lo_offset || + info.lo_init[0] != info64->lo_init[0] || + info.lo_init[1] != info64->lo_init[1]) + return -EOVERFLOW; + + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +static int +loop_set_status_compat(struct loop_device *lo, + const struct compat_loop_info __user *arg) +{ + struct loop_info64 info64; + int ret; + + ret = loop_info64_from_compat(arg, &info64); + if (ret < 0) + return ret; + return loop_set_status(lo, &info64); +} + +static int +loop_get_status_compat(struct loop_device *lo, + struct compat_loop_info __user *arg) +{ + struct loop_info64 info64; + int err = 0; + + if (!arg) + err = -EINVAL; + if (!err) + err = loop_get_status(lo, &info64); + if (!err) + err = loop_info64_to_compat(&info64, arg); + return err; +} + +static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = file->f_dentry->d_inode; + struct loop_device *lo = inode->i_bdev->bd_disk->private_data; + int err; + + lock_kernel(); + switch(cmd) { + case LOOP_SET_STATUS: + mutex_lock(&lo->lo_ctl_mutex); + err = loop_set_status_compat( + lo, (const struct compat_loop_info __user *) arg); + mutex_unlock(&lo->lo_ctl_mutex); + break; + case LOOP_GET_STATUS: + mutex_lock(&lo->lo_ctl_mutex); + err = loop_get_status_compat( + lo, (struct compat_loop_info __user *) arg); + mutex_unlock(&lo->lo_ctl_mutex); + break; + case LOOP_CLR_FD: + case LOOP_GET_STATUS64: + case LOOP_SET_STATUS64: + arg = (unsigned long) compat_ptr(arg); + case LOOP_SET_FD: + case LOOP_CHANGE_FD: + err = lo_ioctl(inode, file, cmd, arg); + break; + default: + err = -ENOIOCTLCMD; + break; + } + unlock_kernel(); + return err; +} +#endif + static int lo_open(struct inode *inode, struct file *file) { struct loop_device *lo = inode->i_bdev->bd_disk->private_data; @@ -1192,6 +1349,9 @@ static struct block_device_operations lo_fops = { .open = lo_open, .release = lo_release, .ioctl = lo_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = lo_compat_ioctl, +#endif }; /* diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index ab74c9bd55fe..3b0cf7fbd95a 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -1214,71 +1213,6 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar return err; } -struct loop_info32 { - compat_int_t lo_number; /* ioctl r/o */ - compat_dev_t lo_device; /* ioctl r/o */ - compat_ulong_t lo_inode; /* ioctl r/o */ - compat_dev_t lo_rdevice; /* ioctl r/o */ - compat_int_t lo_offset; - compat_int_t lo_encrypt_type; - compat_int_t lo_encrypt_key_size; /* ioctl w/o */ - compat_int_t lo_flags; /* ioctl r/o */ - char lo_name[LO_NAME_SIZE]; - unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ - compat_ulong_t lo_init[2]; - char reserved[4]; -}; - -static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct loop_info l; - struct loop_info32 __user *ul; - int err = -EINVAL; - - ul = compat_ptr(arg); - switch(cmd) { - case LOOP_SET_STATUS: - err = get_user(l.lo_number, &ul->lo_number); - err |= __get_user(l.lo_device, &ul->lo_device); - err |= __get_user(l.lo_inode, &ul->lo_inode); - err |= __get_user(l.lo_rdevice, &ul->lo_rdevice); - err |= __copy_from_user(&l.lo_offset, &ul->lo_offset, - 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); - if (err) { - err = -EFAULT; - } else { - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&l); - set_fs (old_fs); - } - break; - case LOOP_GET_STATUS: - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&l); - set_fs (old_fs); - if (!err) { - err = put_user(l.lo_number, &ul->lo_number); - err |= __put_user(l.lo_device, &ul->lo_device); - err |= __put_user(l.lo_inode, &ul->lo_inode); - err |= __put_user(l.lo_rdevice, &ul->lo_rdevice); - err |= __copy_to_user(&ul->lo_offset, &l.lo_offset, - (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); - if (err) - err = -EFAULT; - } - break; - default: { - static int count; - if (++count <= 20) - printk("%s: Unknown loop ioctl cmd, fd(%d) " - "cmd(%08x) arg(%08lx)\n", - __FUNCTION__, fd, cmd, arg); - } - } - return err; -} - #ifdef CONFIG_VT static int vt_check(struct file *file) @@ -2808,8 +2742,6 @@ HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) -HANDLE_IOCTL(LOOP_SET_STATUS, loop_status) -HANDLE_IOCTL(LOOP_GET_STATUS, loop_status) #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) #ifdef CONFIG_VT diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index bea0255196c4..98d40e08ba6e 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -395,12 +395,6 @@ COMPATIBLE_IOCTL(DVD_WRITE_STRUCT) COMPATIBLE_IOCTL(DVD_AUTH) /* pktcdvd */ COMPATIBLE_IOCTL(PACKET_CTRL_CMD) -/* Big L */ -ULONG_IOCTL(LOOP_SET_FD) -ULONG_IOCTL(LOOP_CHANGE_FD) -COMPATIBLE_IOCTL(LOOP_CLR_FD) -COMPATIBLE_IOCTL(LOOP_GET_STATUS64) -COMPATIBLE_IOCTL(LOOP_SET_STATUS64) /* Big A */ /* sparc only */ /* Big Q for sound/OSS */ -- cgit v1.2.3 From 36695673b012096228ebdc1b39a6a5850daa474e Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 29 Aug 2006 19:06:16 +0100 Subject: [PATCH] BLOCK: Move common FS-specific ioctls to linux/fs.h [try #6] Move common FS-specific ioctls from linux/ext2_fs.h to linux/fs.h as FS_IOC_* and FS_IOC32_* and have the users of them use those as a base. Also move the GETFLAGS/SETFLAGS flags to linux/fs.h as FS_*_FL macros, and then have the other users use them as a base. Signed-Off-By: David Howells Signed-off-by: Jens Axboe --- fs/cifs/ioctl.c | 7 +++-- fs/compat_ioctl.c | 15 ----------- fs/hfsplus/hfsplus_fs.h | 8 ++---- fs/hfsplus/ioctl.c | 17 ++++++------ fs/jfs/ioctl.c | 15 +++++------ include/linux/ext2_fs.h | 64 +++++++++++++++++++++++++-------------------- include/linux/ext3_fs.h | 20 +++++++++++--- include/linux/fs.h | 39 +++++++++++++++++++++++++++ include/linux/reiserfs_fs.h | 28 +++++++++----------- 9 files changed, 124 insertions(+), 89 deletions(-) (limited to 'include/linux') diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index b0ea6687ab55..e34c7db00f6f 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -22,7 +22,6 @@ */ #include -#include #include "cifspdu.h" #include "cifsglob.h" #include "cifsproto.h" @@ -74,7 +73,7 @@ int cifs_ioctl (struct inode * inode, struct file * filep, } break; #ifdef CONFIG_CIFS_POSIX - case EXT2_IOC_GETFLAGS: + case FS_IOC_GETFLAGS: if(CIFS_UNIX_EXTATTR_CAP & caps) { if (pSMBFile == NULL) break; @@ -82,12 +81,12 @@ int cifs_ioctl (struct inode * inode, struct file * filep, &ExtAttrBits, &ExtAttrMask); if(rc == 0) rc = put_user(ExtAttrBits & - EXT2_FL_USER_VISIBLE, + FS_FL_USER_VISIBLE, (int __user *)arg); } break; - case EXT2_IOC_SETFLAGS: + case FS_IOC_SETFLAGS: if(CIFS_UNIX_EXTATTR_CAP & caps) { if(get_user(ExtAttrBits,(int __user *)arg)) { rc = -EFAULT; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 3b0cf7fbd95a..bd9c4f49d4e5 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -123,21 +123,6 @@ #include #include -/* Aiee. Someone does not find a difference between int and long */ -#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int) -#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int) -#define EXT3_IOC32_GETVERSION _IOR('f', 3, int) -#define EXT3_IOC32_SETVERSION _IOW('f', 4, int) -#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int) -#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int) -#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int) -#ifdef CONFIG_JBD_DEBUG -#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int) -#endif - -#define EXT2_IOC32_GETVERSION _IOR('v', 1, int) -#define EXT2_IOC32_SETVERSION _IOW('v', 2, int) - static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *f) { diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 8a1ca5ef7ada..3915635b4470 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -246,12 +246,8 @@ struct hfsplus_readdir_data { /* ext2 ioctls (EXT2_IOC_GETFLAGS and EXT2_IOC_SETFLAGS) to support * chattr/lsattr */ -#define HFSPLUS_IOC_EXT2_GETFLAGS _IOR('f', 1, long) -#define HFSPLUS_IOC_EXT2_SETFLAGS _IOW('f', 2, long) - -#define EXT2_FLAG_IMMUTABLE 0x00000010 /* Immutable file */ -#define EXT2_FLAG_APPEND 0x00000020 /* writes to file may only append */ -#define EXT2_FLAG_NODUMP 0x00000040 /* do not dump file */ +#define HFSPLUS_IOC_EXT2_GETFLAGS FS_IOC_GETFLAGS +#define HFSPLUS_IOC_EXT2_SETFLAGS FS_IOC_SETFLAGS /* diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index 13cf848ac833..79fd10402ea3 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c @@ -28,11 +28,11 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, case HFSPLUS_IOC_EXT2_GETFLAGS: flags = 0; if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE) - flags |= EXT2_FLAG_IMMUTABLE; /* EXT2_IMMUTABLE_FL */ + flags |= FS_IMMUTABLE_FL; /* EXT2_IMMUTABLE_FL */ if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND) - flags |= EXT2_FLAG_APPEND; /* EXT2_APPEND_FL */ + flags |= FS_APPEND_FL; /* EXT2_APPEND_FL */ if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP) - flags |= EXT2_FLAG_NODUMP; /* EXT2_NODUMP_FL */ + flags |= FS_NODUMP_FL; /* EXT2_NODUMP_FL */ return put_user(flags, (int __user *)arg); case HFSPLUS_IOC_EXT2_SETFLAGS: { if (IS_RDONLY(inode)) @@ -44,32 +44,31 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, if (get_user(flags, (int __user *)arg)) return -EFAULT; - if (flags & (EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND) || + if (flags & (FS_IMMUTABLE_FL|FS_APPEND_FL) || HFSPLUS_I(inode).rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) { if (!capable(CAP_LINUX_IMMUTABLE)) return -EPERM; } /* don't silently ignore unsupported ext2 flags */ - if (flags & ~(EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND| - EXT2_FLAG_NODUMP)) + if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) return -EOPNOTSUPP; - if (flags & EXT2_FLAG_IMMUTABLE) { /* EXT2_IMMUTABLE_FL */ + if (flags & FS_IMMUTABLE_FL) { /* EXT2_IMMUTABLE_FL */ inode->i_flags |= S_IMMUTABLE; HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_IMMUTABLE; } else { inode->i_flags &= ~S_IMMUTABLE; HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_IMMUTABLE; } - if (flags & EXT2_FLAG_APPEND) { /* EXT2_APPEND_FL */ + if (flags & FS_APPEND_FL) { /* EXT2_APPEND_FL */ inode->i_flags |= S_APPEND; HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_APPEND; } else { inode->i_flags &= ~S_APPEND; HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_APPEND; } - if (flags & EXT2_FLAG_NODUMP) /* EXT2_NODUMP_FL */ + if (flags & FS_NODUMP_FL) /* EXT2_NODUMP_FL */ HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP; else HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP; diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c index 67b3774820eb..37db52488262 100644 --- a/fs/jfs/ioctl.c +++ b/fs/jfs/ioctl.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include @@ -22,13 +21,13 @@ static struct { long jfs_flag; long ext2_flag; } jfs_map[] = { - {JFS_NOATIME_FL, EXT2_NOATIME_FL}, - {JFS_DIRSYNC_FL, EXT2_DIRSYNC_FL}, - {JFS_SYNC_FL, EXT2_SYNC_FL}, - {JFS_SECRM_FL, EXT2_SECRM_FL}, - {JFS_UNRM_FL, EXT2_UNRM_FL}, - {JFS_APPEND_FL, EXT2_APPEND_FL}, - {JFS_IMMUTABLE_FL, EXT2_IMMUTABLE_FL}, + {JFS_NOATIME_FL, FS_NOATIME_FL}, + {JFS_DIRSYNC_FL, FS_DIRSYNC_FL}, + {JFS_SYNC_FL, FS_SYNC_FL}, + {JFS_SECRM_FL, FS_SECRM_FL}, + {JFS_UNRM_FL, FS_UNRM_FL}, + {JFS_APPEND_FL, FS_APPEND_FL}, + {JFS_IMMUTABLE_FL, FS_IMMUTABLE_FL}, {0, 0}, }; diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index 33a1aa107329..153d755376a4 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -165,41 +165,49 @@ struct ext2_group_desc #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) /* - * Inode flags + * Inode flags (GETFLAGS/SETFLAGS) */ -#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */ -#define EXT2_UNRM_FL 0x00000002 /* Undelete */ -#define EXT2_COMPR_FL 0x00000004 /* Compress file */ -#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */ -#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */ -#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */ -#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */ -#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */ +#define EXT2_SECRM_FL FS_SECRM_FL /* Secure deletion */ +#define EXT2_UNRM_FL FS_UNRM_FL /* Undelete */ +#define EXT2_COMPR_FL FS_COMPR_FL /* Compress file */ +#define EXT2_SYNC_FL FS_SYNC_FL /* Synchronous updates */ +#define EXT2_IMMUTABLE_FL FS_IMMUTABLE_FL /* Immutable file */ +#define EXT2_APPEND_FL FS_APPEND_FL /* writes to file may only append */ +#define EXT2_NODUMP_FL FS_NODUMP_FL /* do not dump file */ +#define EXT2_NOATIME_FL FS_NOATIME_FL /* do not update atime */ /* Reserved for compression usage... */ -#define EXT2_DIRTY_FL 0x00000100 -#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ -#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */ -#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */ +#define EXT2_DIRTY_FL FS_DIRTY_FL +#define EXT2_COMPRBLK_FL FS_COMPRBLK_FL /* One or more compressed clusters */ +#define EXT2_NOCOMP_FL FS_NOCOMP_FL /* Don't compress */ +#define EXT2_ECOMPR_FL FS_ECOMPR_FL /* Compression error */ /* End compression flags --- maybe not all used */ -#define EXT2_BTREE_FL 0x00001000 /* btree format dir */ -#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */ -#define EXT2_IMAGIC_FL 0x00002000 /* AFS directory */ -#define EXT2_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */ -#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */ -#define EXT2_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ -#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ -#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ - -#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ -#define EXT2_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ +#define EXT2_BTREE_FL FS_BTREE_FL /* btree format dir */ +#define EXT2_INDEX_FL FS_INDEX_FL /* hash-indexed directory */ +#define EXT2_IMAGIC_FL FS_IMAGIC_FL /* AFS directory */ +#define EXT2_JOURNAL_DATA_FL FS_JOURNAL_DATA_FL /* Reserved for ext3 */ +#define EXT2_NOTAIL_FL FS_NOTAIL_FL /* file tail should not be merged */ +#define EXT2_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */ +#define EXT2_TOPDIR_FL FS_TOPDIR_FL /* Top of directory hierarchies*/ +#define EXT2_RESERVED_FL FS_RESERVED_FL /* reserved for ext2 lib */ + +#define EXT2_FL_USER_VISIBLE FS_FL_USER_VISIBLE /* User visible flags */ +#define EXT2_FL_USER_MODIFIABLE FS_FL_USER_MODIFIABLE /* User modifiable flags */ /* * ioctl commands */ -#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) -#define EXT2_IOC_SETFLAGS _IOW('f', 2, long) -#define EXT2_IOC_GETVERSION _IOR('v', 1, long) -#define EXT2_IOC_SETVERSION _IOW('v', 2, long) +#define EXT2_IOC_GETFLAGS FS_IOC_GETFLAGS +#define EXT2_IOC_SETFLAGS FS_IOC_SETFLAGS +#define EXT2_IOC_GETVERSION FS_IOC_GETVERSION +#define EXT2_IOC_SETVERSION FS_IOC_SETVERSION + +/* + * ioctl commands in 32 bit emulation + */ +#define EXT2_IOC32_GETFLAGS FS_IOC32_GETFLAGS +#define EXT2_IOC32_SETFLAGS FS_IOC32_SETFLAGS +#define EXT2_IOC32_GETVERSION FS_IOC32_GETVERSION +#define EXT2_IOC32_SETVERSION FS_IOC32_SETVERSION /* * Structure of an inode on the disk diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index cc08f56750da..a7a01ff44669 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -216,20 +216,32 @@ struct ext3_new_group_data { /* * ioctl commands */ -#define EXT3_IOC_GETFLAGS _IOR('f', 1, long) -#define EXT3_IOC_SETFLAGS _IOW('f', 2, long) +#define EXT3_IOC_GETFLAGS FS_IOC_GETFLAGS +#define EXT3_IOC_SETFLAGS FS_IOC_SETFLAGS #define EXT3_IOC_GETVERSION _IOR('f', 3, long) #define EXT3_IOC_SETVERSION _IOW('f', 4, long) #define EXT3_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) #define EXT3_IOC_GROUP_ADD _IOW('f', 8,struct ext3_new_group_input) -#define EXT3_IOC_GETVERSION_OLD _IOR('v', 1, long) -#define EXT3_IOC_SETVERSION_OLD _IOW('v', 2, long) +#define EXT3_IOC_GETVERSION_OLD FS_IOC_GETVERSION +#define EXT3_IOC_SETVERSION_OLD FS_IOC_SETVERSION #ifdef CONFIG_JBD_DEBUG #define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long) #endif #define EXT3_IOC_GETRSVSZ _IOR('f', 5, long) #define EXT3_IOC_SETRSVSZ _IOW('f', 6, long) +/* + * ioctl commands in 32 bit emulation + */ +#define EXT3_IOC32_GETVERSION _IOR('f', 3, int) +#define EXT3_IOC32_SETVERSION _IOW('f', 4, int) +#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int) +#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int) +#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int) +#ifdef CONFIG_JBD_DEBUG +#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int) +#endif + /* * Mount options */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 1728142ec4b6..b73a47582dbe 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -217,6 +217,45 @@ extern int dir_notify_enable; #define FIBMAP _IO(0x00,1) /* bmap access */ #define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */ +#define FS_IOC_GETFLAGS _IOR('f', 1, long) +#define FS_IOC_SETFLAGS _IOW('f', 2, long) +#define FS_IOC_GETVERSION _IOR('v', 1, long) +#define FS_IOC_SETVERSION _IOW('v', 2, long) +#define FS_IOC32_GETFLAGS _IOR('f', 1, int) +#define FS_IOC32_SETFLAGS _IOW('f', 2, int) +#define FS_IOC32_GETVERSION _IOR('v', 1, int) +#define FS_IOC32_SETVERSION _IOW('v', 2, int) + +/* + * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS) + */ +#define FS_SECRM_FL 0x00000001 /* Secure deletion */ +#define FS_UNRM_FL 0x00000002 /* Undelete */ +#define FS_COMPR_FL 0x00000004 /* Compress file */ +#define FS_SYNC_FL 0x00000008 /* Synchronous updates */ +#define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define FS_APPEND_FL 0x00000020 /* writes to file may only append */ +#define FS_NODUMP_FL 0x00000040 /* do not dump file */ +#define FS_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define FS_DIRTY_FL 0x00000100 +#define FS_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define FS_NOCOMP_FL 0x00000400 /* Don't compress */ +#define FS_ECOMPR_FL 0x00000800 /* Compression error */ +/* End compression flags --- maybe not all used */ +#define FS_BTREE_FL 0x00001000 /* btree format dir */ +#define FS_INDEX_FL 0x00001000 /* hash-indexed directory */ +#define FS_IMAGIC_FL 0x00002000 /* AFS directory */ +#define FS_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */ +#define FS_NOTAIL_FL 0x00008000 /* file tail should not be merged */ +#define FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ +#define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ + +#define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ +#define FS_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ + + #define SYNC_FILE_RANGE_WAIT_BEFORE 1 #define SYNC_FILE_RANGE_WRITE 2 #define SYNC_FILE_RANGE_WAIT_AFTER 4 diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index 28493ffaafe7..0100d6d1d84c 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -807,21 +807,19 @@ struct stat_data_v1 { #define set_sd_v1_first_direct_byte(sdp,v) \ ((sdp)->sd_first_direct_byte = cpu_to_le32(v)) -#include - /* inode flags stored in sd_attrs (nee sd_reserved) */ /* we want common flags to have the same values as in ext2, so chattr(1) will work without problems */ -#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL -#define REISERFS_APPEND_FL EXT2_APPEND_FL -#define REISERFS_SYNC_FL EXT2_SYNC_FL -#define REISERFS_NOATIME_FL EXT2_NOATIME_FL -#define REISERFS_NODUMP_FL EXT2_NODUMP_FL -#define REISERFS_SECRM_FL EXT2_SECRM_FL -#define REISERFS_UNRM_FL EXT2_UNRM_FL -#define REISERFS_COMPR_FL EXT2_COMPR_FL -#define REISERFS_NOTAIL_FL EXT2_NOTAIL_FL +#define REISERFS_IMMUTABLE_FL FS_IMMUTABLE_FL +#define REISERFS_APPEND_FL FS_APPEND_FL +#define REISERFS_SYNC_FL FS_SYNC_FL +#define REISERFS_NOATIME_FL FS_NOATIME_FL +#define REISERFS_NODUMP_FL FS_NODUMP_FL +#define REISERFS_SECRM_FL FS_SECRM_FL +#define REISERFS_UNRM_FL FS_UNRM_FL +#define REISERFS_COMPR_FL FS_COMPR_FL +#define REISERFS_NOTAIL_FL FS_NOTAIL_FL /* persistent flags that file inherits from the parent directory */ #define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \ @@ -2168,10 +2166,10 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, #define REISERFS_IOC_UNPACK _IOW(0xCD,1,long) /* define following flags to be the same as in ext2, so that chattr(1), lsattr(1) will work with us. */ -#define REISERFS_IOC_GETFLAGS EXT2_IOC_GETFLAGS -#define REISERFS_IOC_SETFLAGS EXT2_IOC_SETFLAGS -#define REISERFS_IOC_GETVERSION EXT2_IOC_GETVERSION -#define REISERFS_IOC_SETVERSION EXT2_IOC_SETVERSION +#define REISERFS_IOC_GETFLAGS FS_IOC_GETFLAGS +#define REISERFS_IOC_SETFLAGS FS_IOC_SETFLAGS +#define REISERFS_IOC_GETVERSION FS_IOC_GETVERSION +#define REISERFS_IOC_SETVERSION FS_IOC_SETVERSION /* Locking primitives */ /* Right now we are still falling back to (un)lock_kernel, but eventually that -- cgit v1.2.3 From 52b499c438ff60991eb3855ca090782569b3e8cf Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 29 Aug 2006 19:06:18 +0100 Subject: [PATCH] BLOCK: Move the ReiserFS device ioctl compat stuff to the ReiserFS driver [try #6] Move the ReiserFS device ioctl compat stuff from fs/compat_ioctl.c to the ReiserFS driver so that the ReiserFS header file doesn't need to be included. Signed-Off-By: David Howells Signed-off-by: Jens Axboe --- fs/compat_ioctl.c | 12 ------------ fs/reiserfs/dir.c | 3 +++ fs/reiserfs/file.c | 4 ++++ fs/reiserfs/ioctl.c | 35 +++++++++++++++++++++++++++++++++++ include/linux/reiserfs_fs.h | 9 +++++++++ 5 files changed, 51 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index bd9c4f49d4e5..0346f2ab57c4 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include #include @@ -2014,16 +2013,6 @@ static int vfat_ioctl32(unsigned fd, unsigned cmd, unsigned long arg) return ret; } -#define REISERFS_IOC_UNPACK32 _IOW(0xCD,1,int) - -static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr) -{ - if (cmd == REISERFS_IOC_UNPACK32) - cmd = REISERFS_IOC_UNPACK; - - return sys_ioctl(fd,cmd,ptr); -} - struct raw32_config_request { compat_int_t raw_minor; @@ -2784,7 +2773,6 @@ HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64) /* vfat */ HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32) HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32) -HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32) /* Raw devices */ HANDLE_IOCTL(RAW_SETBIND, raw_ioctl) HANDLE_IOCTL(RAW_GETBIND, raw_ioctl) diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index 9aabcc0ccd2d..657050ad7430 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c @@ -22,6 +22,9 @@ const struct file_operations reiserfs_dir_operations = { .readdir = reiserfs_readdir, .fsync = reiserfs_dir_fsync, .ioctl = reiserfs_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = reiserfs_compat_ioctl, +#endif }; static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 1cfbe857ba27..3e08f7161a3d 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -2,6 +2,7 @@ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ +#include #include #include #include @@ -1568,6 +1569,9 @@ const struct file_operations reiserfs_file_operations = { .read = generic_file_read, .write = reiserfs_file_write, .ioctl = reiserfs_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = reiserfs_compat_ioctl, +#endif .mmap = generic_file_mmap, .release = reiserfs_file_release, .fsync = reiserfs_sync_file, diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index a986b5e1e288..9c57578cb831 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -9,6 +9,7 @@ #include #include #include +#include static int reiserfs_unpack(struct inode *inode, struct file *filp); @@ -94,6 +95,40 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, } } +#ifdef CONFIG_COMPAT +long reiserfs_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct inode *inode = file->f_dentry->d_inode; + int ret; + + /* These are just misnamed, they actually get/put from/to user an int */ + switch (cmd) { + case REISERFS_IOC32_UNPACK: + cmd = REISERFS_IOC_UNPACK; + break; + case REISERFS_IOC32_GETFLAGS: + cmd = REISERFS_IOC_GETFLAGS; + break; + case REISERFS_IOC32_SETFLAGS: + cmd = REISERFS_IOC_SETFLAGS; + break; + case REISERFS_IOC32_GETVERSION: + cmd = REISERFS_IOC_GETVERSION; + break; + case REISERFS_IOC32_SETVERSION: + cmd = REISERFS_IOC_SETVERSION; + break; + default: + return -ENOIOCTLCMD; + } + lock_kernel(); + ret = reiserfs_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); + unlock_kernel(); + return ret; +} +#endif + /* ** reiserfs_unpack ** Function try to convert tail from direct item into indirect. diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index 0100d6d1d84c..9c63abffd7b2 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -2161,6 +2161,8 @@ __u32 r5_hash(const signed char *msg, int len); /* prototypes from ioctl.c */ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +long reiserfs_compat_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg); /* ioctl's command */ #define REISERFS_IOC_UNPACK _IOW(0xCD,1,long) @@ -2171,6 +2173,13 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, #define REISERFS_IOC_GETVERSION FS_IOC_GETVERSION #define REISERFS_IOC_SETVERSION FS_IOC_SETVERSION +/* the 32 bit compat definitions with int argument */ +#define REISERFS_IOC32_UNPACK _IOW(0xCD, 1, int) +#define REISERFS_IOC32_GETFLAGS FS_IOC32_GETFLAGS +#define REISERFS_IOC32_SETFLAGS FS_IOC32_SETFLAGS +#define REISERFS_IOC32_GETVERSION FS_IOC32_GETVERSION +#define REISERFS_IOC32_SETVERSION FS_IOC32_SETVERSION + /* Locking primitives */ /* Right now we are still falling back to (un)lock_kernel, but eventually that would evolve into real per-fs locks */ -- cgit v1.2.3 From 52a700c5675f399c07e6e57328291e57f13ef3bb Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 29 Aug 2006 19:06:23 +0100 Subject: [PATCH] BLOCK: Move the Ext3 device ioctl compat stuff to the Ext3 driver [try #6] Move the Ext3 device ioctl compat stuff from fs/compat_ioctl.c to the Ext3 driver so that the Ext3 header file doesn't need to be included. Signed-Off-By: David Howells Signed-off-by: Jens Axboe --- fs/compat_ioctl.c | 27 ------------------------ fs/ext3/dir.c | 3 +++ fs/ext3/file.c | 3 +++ fs/ext3/ioctl.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/ext3_fs.h | 6 ++++++ 5 files changed, 66 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 3594668559af..e5eb0f10f05a 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -45,8 +45,6 @@ #include #include #include -#include -#include #include #include #include @@ -158,22 +156,6 @@ static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg) return err; } -static int do_ext3_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - /* These are just misnamed, they actually get/put from/to user an int */ - switch (cmd) { - case EXT3_IOC32_GETVERSION: cmd = EXT3_IOC_GETVERSION; break; - case EXT3_IOC32_SETVERSION: cmd = EXT3_IOC_SETVERSION; break; - case EXT3_IOC32_GETRSVSZ: cmd = EXT3_IOC_GETRSVSZ; break; - case EXT3_IOC32_SETRSVSZ: cmd = EXT3_IOC_SETRSVSZ; break; - case EXT3_IOC32_GROUP_EXTEND: cmd = EXT3_IOC_GROUP_EXTEND; break; -#ifdef CONFIG_JBD_DEBUG - case EXT3_IOC32_WAIT_FOR_READONLY: cmd = EXT3_IOC_WAIT_FOR_READONLY; break; -#endif - } - return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg)); -} - struct compat_video_event { int32_t type; compat_time_t timestamp; @@ -2712,15 +2694,6 @@ HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl) HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl) HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl) #endif -HANDLE_IOCTL(EXT3_IOC32_GETVERSION, do_ext3_ioctl) -HANDLE_IOCTL(EXT3_IOC32_SETVERSION, do_ext3_ioctl) -HANDLE_IOCTL(EXT3_IOC32_GETRSVSZ, do_ext3_ioctl) -HANDLE_IOCTL(EXT3_IOC32_SETRSVSZ, do_ext3_ioctl) -HANDLE_IOCTL(EXT3_IOC32_GROUP_EXTEND, do_ext3_ioctl) -COMPATIBLE_IOCTL(EXT3_IOC_GROUP_ADD) -#ifdef CONFIG_JBD_DEBUG -HANDLE_IOCTL(EXT3_IOC32_WAIT_FOR_READONLY, do_ext3_ioctl) -#endif /* One SMB ioctl needs translations. */ #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 429acbb4e064..d0b54f30b914 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -44,6 +44,9 @@ const struct file_operations ext3_dir_operations = { .read = generic_read_dir, .readdir = ext3_readdir, /* we take BKL. needed?*/ .ioctl = ext3_ioctl, /* BKL held */ +#ifdef CONFIG_COMPAT + .compat_ioctl = ext3_compat_ioctl, +#endif .fsync = ext3_sync_file, /* BKL held */ #ifdef CONFIG_EXT3_INDEX .release = ext3_release_dir, diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 994efd189f4e..74ff20f9d09b 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -114,6 +114,9 @@ const struct file_operations ext3_file_operations = { .readv = generic_file_readv, .writev = generic_file_writev, .ioctl = ext3_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ext3_compat_ioctl, +#endif .mmap = generic_file_mmap, .open = generic_file_open, .release = ext3_release_file, diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index 3a6b012d120c..12daa6869572 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c @@ -13,9 +13,10 @@ #include #include #include +#include +#include #include - int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { @@ -252,3 +253,55 @@ flags_err: return -ENOTTY; } } + +#ifdef CONFIG_COMPAT +long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = file->f_dentry->d_inode; + int ret; + + /* These are just misnamed, they actually get/put from/to user an int */ + switch (cmd) { + case EXT3_IOC32_GETFLAGS: + cmd = EXT3_IOC_GETFLAGS; + break; + case EXT3_IOC32_SETFLAGS: + cmd = EXT3_IOC_SETFLAGS; + break; + case EXT3_IOC32_GETVERSION: + cmd = EXT3_IOC_GETVERSION; + break; + case EXT3_IOC32_SETVERSION: + cmd = EXT3_IOC_SETVERSION; + break; + case EXT3_IOC32_GROUP_EXTEND: + cmd = EXT3_IOC_GROUP_EXTEND; + break; + case EXT3_IOC32_GETVERSION_OLD: + cmd = EXT3_IOC_GETVERSION_OLD; + break; + case EXT3_IOC32_SETVERSION_OLD: + cmd = EXT3_IOC_SETVERSION_OLD; + break; +#ifdef CONFIG_JBD_DEBUG + case EXT3_IOC32_WAIT_FOR_READONLY: + cmd = EXT3_IOC_WAIT_FOR_READONLY; + break; +#endif + case EXT3_IOC32_GETRSVSZ: + cmd = EXT3_IOC_GETRSVSZ; + break; + case EXT3_IOC32_SETRSVSZ: + cmd = EXT3_IOC_SETRSVSZ; + break; + case EXT3_IOC_GROUP_ADD: + break; + default: + return -ENOIOCTLCMD; + } + lock_kernel(); + ret = ext3_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); + unlock_kernel(); + return ret; +} +#endif diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index a7a01ff44669..11cca1bdc0c7 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -233,6 +233,8 @@ struct ext3_new_group_data { /* * ioctl commands in 32 bit emulation */ +#define EXT3_IOC32_GETFLAGS FS_IOC32_GETFLAGS +#define EXT3_IOC32_SETFLAGS FS_IOC32_SETFLAGS #define EXT3_IOC32_GETVERSION _IOR('f', 3, int) #define EXT3_IOC32_SETVERSION _IOW('f', 4, int) #define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int) @@ -241,6 +243,9 @@ struct ext3_new_group_data { #ifdef CONFIG_JBD_DEBUG #define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int) #endif +#define EXT3_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION +#define EXT3_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION + /* * Mount options @@ -824,6 +829,7 @@ extern void ext3_set_aops(struct inode *inode); /* ioctl.c */ extern int ext3_ioctl (struct inode *, struct file *, unsigned int, unsigned long); +extern long ext3_compat_ioctl (struct file *, unsigned int, unsigned long); /* namei.c */ extern int ext3_orphan_add(handle_t *, struct inode *); -- cgit v1.2.3 From 9361401eb7619c033e2394e4f9f6d410d6719ac7 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sat, 30 Sep 2006 20:45:40 +0200 Subject: [PATCH] BLOCK: Make it possible to disable the block layer [try #6] Make it possible to disable the block layer. Not all embedded devices require it, some can make do with just JFFS2, NFS, ramfs, etc - none of which require the block layer to be present. This patch does the following: (*) Introduces CONFIG_BLOCK to disable the block layer, buffering and blockdev support. (*) Adds dependencies on CONFIG_BLOCK to any configuration item that controls an item that uses the block layer. This includes: (*) Block I/O tracing. (*) Disk partition code. (*) All filesystems that are block based, eg: Ext3, ReiserFS, ISOFS. (*) The SCSI layer. As far as I can tell, even SCSI chardevs use the block layer to do scheduling. Some drivers that use SCSI facilities - such as USB storage - end up disabled indirectly from this. (*) Various block-based device drivers, such as IDE and the old CDROM drivers. (*) MTD blockdev handling and FTL. (*) JFFS - which uses set_bdev_super(), something it could avoid doing by taking a leaf out of JFFS2's book. (*) Makes most of the contents of linux/blkdev.h, linux/buffer_head.h and linux/elevator.h contingent on CONFIG_BLOCK being set. sector_div() is, however, still used in places, and so is still available. (*) Also made contingent are the contents of linux/mpage.h, linux/genhd.h and parts of linux/fs.h. (*) Makes a number of files in fs/ contingent on CONFIG_BLOCK. (*) Makes mm/bounce.c (bounce buffering) contingent on CONFIG_BLOCK. (*) set_page_dirty() doesn't call __set_page_dirty_buffers() if CONFIG_BLOCK is not enabled. (*) fs/no-block.c is created to hold out-of-line stubs and things that are required when CONFIG_BLOCK is not set: (*) Default blockdev file operations (to give error ENODEV on opening). (*) Makes some /proc changes: (*) /proc/devices does not list any blockdevs. (*) /proc/diskstats and /proc/partitions are contingent on CONFIG_BLOCK. (*) Makes some compat ioctl handling contingent on CONFIG_BLOCK. (*) If CONFIG_BLOCK is not defined, makes sys_quotactl() return -ENODEV if given command other than Q_SYNC or if a special device is specified. (*) In init/do_mounts.c, no reference is made to the blockdev routines if CONFIG_BLOCK is not defined. This does not prohibit NFS roots or JFFS2. (*) The bdflush, ioprio_set and ioprio_get syscalls can now be absent (return error ENOSYS by way of cond_syscall if so). (*) The seclvl_bd_claim() and seclvl_bd_release() security calls do nothing if CONFIG_BLOCK is not set, since they can't then happen. Signed-Off-By: David Howells Signed-off-by: Jens Axboe --- block/Kconfig | 20 ++++++++++++++++++ block/Kconfig.iosched | 3 +++ block/Makefile | 2 +- drivers/block/Kconfig | 4 ++++ drivers/cdrom/Kconfig | 2 +- drivers/char/Kconfig | 1 + drivers/char/random.c | 4 ++++ drivers/ide/Kconfig | 4 ++++ drivers/md/Kconfig | 3 +++ drivers/message/i2o/Kconfig | 2 +- drivers/mmc/Kconfig | 2 +- drivers/mmc/Makefile | 3 ++- drivers/mtd/Kconfig | 12 +++++------ drivers/mtd/devices/Kconfig | 2 +- drivers/s390/block/Kconfig | 2 +- drivers/scsi/Kconfig | 2 ++ fs/Kconfig | 31 ++++++++++++++++++++------- fs/Makefile | 14 +++++++++---- fs/compat_ioctl.c | 18 ++++++++++++++++ fs/internal.h | 6 ++++++ fs/no-block.c | 22 +++++++++++++++++++ fs/partitions/Makefile | 2 +- fs/proc/proc_misc.c | 11 +++++++++- fs/quota.c | 44 ++++++++++++++++++++++++++------------ fs/super.c | 4 ++++ fs/xfs/Kconfig | 1 + include/linux/blkdev.h | 50 +++++++++++++++++++++++++++++++------------- include/linux/buffer_head.h | 16 ++++++++++++++ include/linux/compat_ioctl.h | 2 ++ include/linux/elevator.h | 3 +++ include/linux/fs.h | 25 +++++++++++++++++++--- include/linux/genhd.h | 4 ++++ include/linux/mpage.h | 3 +++ include/linux/raid/md.h | 3 +++ include/linux/raid/md_k.h | 3 +++ include/scsi/scsi_tcq.h | 3 ++- init/Kconfig | 2 +- init/do_mounts.c | 13 +++++++++++- kernel/sys_ni.c | 5 +++++ mm/Makefile | 2 +- mm/filemap.c | 4 ++++ mm/migrate.c | 2 ++ mm/page-writeback.c | 8 ++++--- mm/truncate.c | 2 ++ 44 files changed, 308 insertions(+), 63 deletions(-) create mode 100644 fs/no-block.c (limited to 'include/linux') diff --git a/block/Kconfig b/block/Kconfig index b6f5f0a79655..9af6c614dfde 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -1,6 +1,24 @@ # # Block layer core configuration # +config BLOCK + bool "Enable the block layer" + default y + help + This permits the block layer to be removed from the kernel if it's not + needed (on some embedded devices for example). If this option is + disabled, then blockdev files will become unusable and some + filesystems (such as ext3) will become unavailable. + + This option will also disable SCSI character devices and USB storage + since they make use of various block layer definitions and + facilities. + + Say Y here unless you know you really don't want to mount disks and + suchlike. + +if BLOCK + #XXX - it makes sense to enable this only for 32-bit subarch's, not for x86_64 #for instance. config LBD @@ -33,4 +51,6 @@ config LSF If unsure, say Y. +endif + source block/Kconfig.iosched diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched index 48d090e266fc..903f0d3b6852 100644 --- a/block/Kconfig.iosched +++ b/block/Kconfig.iosched @@ -1,3 +1,4 @@ +if BLOCK menu "IO Schedulers" @@ -67,3 +68,5 @@ config DEFAULT_IOSCHED default "noop" if DEFAULT_NOOP endmenu + +endif diff --git a/block/Makefile b/block/Makefile index c05de0e0037f..4b84d0d5947b 100644 --- a/block/Makefile +++ b/block/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel block layer # -obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o +obj-$(CONFIG_BLOCK) := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o obj-$(CONFIG_IOSCHED_AS) += as-iosched.o diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index b5382cedf0c0..422e31d5f8e5 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -2,6 +2,8 @@ # Block device driver configuration # +if BLOCK + menu "Block devices" config BLK_DEV_FD @@ -468,3 +470,5 @@ config ATA_OVER_ETH devices like the Coraid EtherDrive (R) Storage Blade. endmenu + +endif diff --git a/drivers/cdrom/Kconfig b/drivers/cdrom/Kconfig index ff5652d40619..4b12e9031fb3 100644 --- a/drivers/cdrom/Kconfig +++ b/drivers/cdrom/Kconfig @@ -3,7 +3,7 @@ # menu "Old CD-ROM drivers (not SCSI, not IDE)" - depends on ISA + depends on ISA && BLOCK config CD_NO_IDESCSI bool "Support non-SCSI/IDE/ATAPI CDROM drives" diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 4cc619edf424..bde1c665d9f4 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -1006,6 +1006,7 @@ config GPIO_VR41XX config RAW_DRIVER tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)" + depends on BLOCK help The raw driver permits block devices to be bound to /dev/raw/rawN. Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. diff --git a/drivers/char/random.c b/drivers/char/random.c index 4c3a5ca9d8f7..b430a12eb819 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -655,6 +655,7 @@ void add_interrupt_randomness(int irq) add_timer_randomness(irq_timer_state[irq], 0x100 + irq); } +#ifdef CONFIG_BLOCK void add_disk_randomness(struct gendisk *disk) { if (!disk || !disk->random) @@ -667,6 +668,7 @@ void add_disk_randomness(struct gendisk *disk) } EXPORT_SYMBOL(add_disk_randomness); +#endif #define EXTRACT_SIZE 10 @@ -918,6 +920,7 @@ void rand_initialize_irq(int irq) } } +#ifdef CONFIG_BLOCK void rand_initialize_disk(struct gendisk *disk) { struct timer_rand_state *state; @@ -932,6 +935,7 @@ void rand_initialize_disk(struct gendisk *disk) disk->random = state; } } +#endif static ssize_t random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index b6fb167e20f6..69d627bd537a 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -4,6 +4,8 @@ # Andre Hedrick # +if BLOCK + menu "ATA/ATAPI/MFM/RLL support" config IDE @@ -1082,3 +1084,5 @@ config BLK_DEV_HD endif endmenu + +endif diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index bf869ed03eed..6dd31a291d84 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -2,6 +2,8 @@ # Block device driver configuration # +if BLOCK + menu "Multi-device support (RAID and LVM)" config MD @@ -251,3 +253,4 @@ config DM_MULTIPATH_EMC endmenu +endif diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig index fef677103880..6443392bffff 100644 --- a/drivers/message/i2o/Kconfig +++ b/drivers/message/i2o/Kconfig @@ -88,7 +88,7 @@ config I2O_BUS config I2O_BLOCK tristate "I2O Block OSM" - depends on I2O + depends on I2O && BLOCK ---help--- Include support for the I2O Block OSM. The Block OSM presents disk and other structured block devices to the operating system. If you diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 45bcf098e762..f540bd88dc5a 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -21,7 +21,7 @@ config MMC_DEBUG config MMC_BLOCK tristate "MMC block device driver" - depends on MMC + depends on MMC && BLOCK default y help Say Y here to enable the MMC block device driver support. diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index d2957e35cc6f..b1f6e03e7aa9 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -24,7 +24,8 @@ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o -mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o +mmc_core-y := mmc.o mmc_sysfs.o +mmc_core-$(CONFIG_BLOCK) += mmc_queue.o ifeq ($(CONFIG_MMC_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index a03e862851db..a304b34c2632 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -166,7 +166,7 @@ config MTD_CHAR config MTD_BLOCK tristate "Caching block device access to MTD devices" - depends on MTD + depends on MTD && BLOCK ---help--- Although most flash chips have an erase size too large to be useful as block devices, it is possible to use MTD devices which are based @@ -188,7 +188,7 @@ config MTD_BLOCK config MTD_BLOCK_RO tristate "Readonly block device access to MTD devices" - depends on MTD_BLOCK!=y && MTD + depends on MTD_BLOCK!=y && MTD && BLOCK help This allows you to mount read-only file systems (such as cramfs) from an MTD device, without the overhead (and danger) of the caching @@ -199,7 +199,7 @@ config MTD_BLOCK_RO config FTL tristate "FTL (Flash Translation Layer) support" - depends on MTD + depends on MTD && BLOCK ---help--- This provides support for the original Flash Translation Layer which is part of the PCMCIA specification. It uses a kind of pseudo- @@ -215,7 +215,7 @@ config FTL config NFTL tristate "NFTL (NAND Flash Translation Layer) support" - depends on MTD + depends on MTD && BLOCK ---help--- This provides support for the NAND Flash Translation Layer which is used on M-Systems' DiskOnChip devices. It uses a kind of pseudo- @@ -238,7 +238,7 @@ config NFTL_RW config INFTL tristate "INFTL (Inverse NAND Flash Translation Layer) support" - depends on MTD + depends on MTD && BLOCK ---help--- This provides support for the Inverse NAND Flash Translation Layer which is used on M-Systems' newer DiskOnChip devices. It @@ -255,7 +255,7 @@ config INFTL config RFD_FTL tristate "Resident Flash Disk (Flash Translation Layer) support" - depends on MTD + depends on MTD && BLOCK ---help--- This provides support for the flash translation layer known as the Resident Flash Disk (RFD), as used by the Embedded BIOS diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 16c02b5ccf7e..440f6851da69 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -136,7 +136,7 @@ config MTDRAM_ABS_POS config MTD_BLOCK2MTD tristate "MTD using block device" - depends on MTD + depends on MTD && BLOCK help This driver allows a block device to appear as an MTD. It would generally be used in the following cases: diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index 929d6fff6152..b250c5354503 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig @@ -1,4 +1,4 @@ -if S390 +if S390 && BLOCK comment "S/390 block device drivers" depends on S390 diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index c4dfcc91ddda..dab082002e6f 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -3,11 +3,13 @@ menu "SCSI device support" config RAID_ATTRS tristate "RAID Transport Class" default n + depends on BLOCK ---help--- Provides RAID config SCSI tristate "SCSI device support" + depends on BLOCK ---help--- If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or any other SCSI device under Linux, say Y and make sure that you know diff --git a/fs/Kconfig b/fs/Kconfig index 4fd9efac29ab..1453d2d164f7 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -4,6 +4,8 @@ menu "File systems" +if BLOCK + config EXT2_FS tristate "Second extended fs support" help @@ -399,6 +401,8 @@ config ROMFS_FS If you don't know whether you need it, then you don't need it: answer N. +endif + config INOTIFY bool "Inotify file change notification support" default y @@ -530,6 +534,7 @@ config FUSE_FS If you want to develop a userspace FS, or if you want to use a filesystem based on FUSE, answer Y or M. +if BLOCK menu "CD-ROM/DVD Filesystems" config ISO9660_FS @@ -597,7 +602,9 @@ config UDF_NLS depends on (UDF_FS=m && NLS) || (UDF_FS=y && NLS=y) endmenu +endif +if BLOCK menu "DOS/FAT/NT Filesystems" config FAT_FS @@ -782,6 +789,7 @@ config NTFS_RW It is perfectly safe to say N here. endmenu +endif menu "Pseudo filesystems" @@ -939,7 +947,7 @@ menu "Miscellaneous filesystems" config ADFS_FS tristate "ADFS file system support (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on BLOCK && EXPERIMENTAL help The Acorn Disc Filing System is the standard file system of the RiscOS operating system which runs on Acorn's ARM-based Risc PC @@ -967,7 +975,7 @@ config ADFS_FS_RW config AFFS_FS tristate "Amiga FFS file system support (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on BLOCK && EXPERIMENTAL help The Fast File System (FFS) is the common file system used on hard disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20). Say Y @@ -989,7 +997,7 @@ config AFFS_FS config HFS_FS tristate "Apple Macintosh file system support (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on BLOCK && EXPERIMENTAL select NLS help If you say Y here, you will be able to mount Macintosh-formatted @@ -1002,6 +1010,7 @@ config HFS_FS config HFSPLUS_FS tristate "Apple Extended HFS file system support" + depends on BLOCK select NLS select NLS_UTF8 help @@ -1015,7 +1024,7 @@ config HFSPLUS_FS config BEFS_FS tristate "BeOS file system (BeFS) support (read only) (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on BLOCK && EXPERIMENTAL select NLS help The BeOS File System (BeFS) is the native file system of Be, Inc's @@ -1042,7 +1051,7 @@ config BEFS_DEBUG config BFS_FS tristate "BFS file system support (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on BLOCK && EXPERIMENTAL help Boot File System (BFS) is a file system used under SCO UnixWare to allow the bootloader access to the kernel image and other important @@ -1064,7 +1073,7 @@ config BFS_FS config EFS_FS tristate "EFS file system support (read only) (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on BLOCK && EXPERIMENTAL help EFS is an older file system used for non-ISO9660 CD-ROMs and hard disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer @@ -1079,7 +1088,7 @@ config EFS_FS config JFFS_FS tristate "Journalling Flash File System (JFFS) support" - depends on MTD + depends on MTD && BLOCK help JFFS is the Journaling Flash File System developed by Axis Communications in Sweden, aimed at providing a crash/powerdown-safe @@ -1264,6 +1273,7 @@ endchoice config CRAMFS tristate "Compressed ROM file system support (cramfs)" + depends on BLOCK select ZLIB_INFLATE help Saying Y here includes support for CramFs (Compressed ROM File @@ -1283,6 +1293,7 @@ config CRAMFS config VXFS_FS tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" + depends on BLOCK help FreeVxFS is a file system driver that support the VERITAS VxFS(TM) file system format. VERITAS VxFS(TM) is the standard file system @@ -1300,6 +1311,7 @@ config VXFS_FS config HPFS_FS tristate "OS/2 HPFS file system support" + depends on BLOCK help OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS is the file system used for organizing files on OS/2 hard disk @@ -1316,6 +1328,7 @@ config HPFS_FS config QNX4FS_FS tristate "QNX4 file system support (read only)" + depends on BLOCK help This is the file system used by the real-time operating systems QNX 4 and QNX 6 (the latter is also called QNX RTP). @@ -1343,6 +1356,7 @@ config QNX4FS_RW config SYSV_FS tristate "System V/Xenix/V7/Coherent file system support" + depends on BLOCK help SCO, Xenix and Coherent are commercial Unix systems for Intel machines, and Version 7 was used on the DEC PDP-11. Saying Y @@ -1381,6 +1395,7 @@ config SYSV_FS config UFS_FS tristate "UFS file system support (read only)" + depends on BLOCK help BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD, OpenBSD and NeXTstep) use a file system called UFS. Some System V @@ -1959,11 +1974,13 @@ config GENERIC_ACL endmenu +if BLOCK menu "Partition Types" source "fs/partitions/Kconfig" endmenu +endif source "fs/nls/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index 46b8cfe497b2..a503e6ce0f32 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -5,12 +5,18 @@ # Rewritten to use lists instead of if-statements. # -obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \ - block_dev.o char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ +obj-y := open.o read_write.o file_table.o super.o \ + char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \ attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \ - seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \ - ioprio.o pnode.o drop_caches.o splice.o sync.o + seq_file.o xattr.o libfs.o fs-writeback.o \ + pnode.o drop_caches.o splice.o sync.o + +ifeq ($(CONFIG_BLOCK),y) +obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o +else +obj-y += no-block.o +endif obj-$(CONFIG_INOTIFY) += inotify.o obj-$(CONFIG_INOTIFY_USER) += inotify_user.o diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index e1a56437040a..64b34533edea 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -645,6 +645,7 @@ out: } #endif +#ifdef CONFIG_BLOCK struct hd_geometry32 { unsigned char heads; unsigned char sectors; @@ -869,6 +870,7 @@ static int sg_grt_trans(unsigned int fd, unsigned int cmd, unsigned long arg) } return err; } +#endif /* CONFIG_BLOCK */ struct sock_fprog32 { unsigned short len; @@ -992,6 +994,7 @@ static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) } +#ifdef CONFIG_BLOCK struct mtget32 { compat_long_t mt_type; compat_long_t mt_resid; @@ -1164,6 +1167,7 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar return err; } +#endif /* CONFIG_BLOCK */ #ifdef CONFIG_VT @@ -1491,6 +1495,7 @@ ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) return -EINVAL; } +#ifdef CONFIG_BLOCK static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg) { /* The mkswap binary hard codes it to Intel value :-((( */ @@ -1525,12 +1530,14 @@ static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar return sys_ioctl(fd, cmd, (unsigned long)a); } +#endif static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) { return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); } +#ifdef CONFIG_BLOCK /* Fix sizeof(sizeof()) breakage */ #define BLKBSZGET_32 _IOR(0x12,112,int) #define BLKBSZSET_32 _IOW(0x12,113,int) @@ -1551,6 +1558,7 @@ static int do_blkgetsize64(unsigned int fd, unsigned int cmd, { return sys_ioctl(fd, BLKGETSIZE64, (unsigned long)compat_ptr(arg)); } +#endif /* Bluetooth ioctls */ #define HCIUARTSETPROTO _IOW('U', 200, int) @@ -1571,6 +1579,7 @@ static int do_blkgetsize64(unsigned int fd, unsigned int cmd, #define HIDPGETCONNLIST _IOR('H', 210, int) #define HIDPGETCONNINFO _IOR('H', 211, int) +#ifdef CONFIG_BLOCK struct floppy_struct32 { compat_uint_t size; compat_uint_t sect; @@ -1895,6 +1904,7 @@ out: kfree(karg); return err; } +#endif struct mtd_oob_buf32 { u_int32_t start; @@ -1936,6 +1946,7 @@ static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg) return err; } +#ifdef CONFIG_BLOCK struct raw32_config_request { compat_int_t raw_minor; @@ -2000,6 +2011,7 @@ static int raw_ioctl(unsigned fd, unsigned cmd, unsigned long arg) } return ret; } +#endif /* CONFIG_BLOCK */ struct serial_struct32 { compat_int_t type; @@ -2606,6 +2618,7 @@ HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc) HANDLE_IOCTL(SIOCRTMSG, ret_einval) HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) #endif +#ifdef CONFIG_BLOCK HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo) HANDLE_IOCTL(BLKRAGET, w_long) HANDLE_IOCTL(BLKGETSIZE, w_long) @@ -2631,14 +2644,17 @@ HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans) HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans) HANDLE_IOCTL(SG_IO,sg_ioctl_trans) HANDLE_IOCTL(SG_GET_REQUEST_TABLE, sg_grt_trans) +#endif HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans) HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans) HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans) HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans) +#ifdef CONFIG_BLOCK HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) +#endif #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) #ifdef CONFIG_VT @@ -2677,12 +2693,14 @@ HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) /* block stuff */ +#ifdef CONFIG_BLOCK HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget) HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset) HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64) /* Raw devices */ HANDLE_IOCTL(RAW_SETBIND, raw_ioctl) HANDLE_IOCTL(RAW_GETBIND, raw_ioctl) +#endif /* Serial */ HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl) HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl) diff --git a/fs/internal.h b/fs/internal.h index f662b703bb97..f07147d63255 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -14,10 +14,16 @@ /* * block_dev.c */ +#ifdef CONFIG_BLOCK extern struct super_block *blockdev_superblock; extern void __init bdev_cache_init(void); #define sb_is_blkdev_sb(sb) ((sb) == blockdev_superblock) +#else +static inline void bdev_cache_init(void) {} + +#define sb_is_blkdev_sb(sb) 0 +#endif /* * char_dev.c diff --git a/fs/no-block.c b/fs/no-block.c new file mode 100644 index 000000000000..d269a93d3467 --- /dev/null +++ b/fs/no-block.c @@ -0,0 +1,22 @@ +/* no-block.c: implementation of routines required for non-BLOCK configuration + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include + +static int no_blkdev_open(struct inode * inode, struct file * filp) +{ + return -ENODEV; +} + +const struct file_operations def_blk_fops = { + .open = no_blkdev_open, +}; diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile index d713ce6b3e12..67e665fdb7fc 100644 --- a/fs/partitions/Makefile +++ b/fs/partitions/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y := check.o +obj-$(CONFIG_BLOCK) := check.o obj-$(CONFIG_ACORN_PARTITION) += acorn.o obj-$(CONFIG_AMIGA_PARTITION) += amiga.o diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 5bbd60896050..66bc425f2f3d 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -277,12 +277,15 @@ static int devinfo_show(struct seq_file *f, void *v) if (i == 0) seq_printf(f, "Character devices:\n"); chrdev_show(f, i); - } else { + } +#ifdef CONFIG_BLOCK + else { i -= CHRDEV_MAJOR_HASH_SIZE; if (i == 0) seq_printf(f, "\nBlock devices:\n"); blkdev_show(f, i); } +#endif return 0; } @@ -355,6 +358,7 @@ static int stram_read_proc(char *page, char **start, off_t off, } #endif +#ifdef CONFIG_BLOCK extern struct seq_operations partitions_op; static int partitions_open(struct inode *inode, struct file *file) { @@ -378,6 +382,7 @@ static struct file_operations proc_diskstats_operations = { .llseek = seq_lseek, .release = seq_release, }; +#endif #ifdef CONFIG_MODULES extern struct seq_operations modules_op; @@ -695,7 +700,9 @@ void __init proc_misc_init(void) entry->proc_fops = &proc_kmsg_operations; create_seq_entry("devices", 0, &proc_devinfo_operations); create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); +#ifdef CONFIG_BLOCK create_seq_entry("partitions", 0, &proc_partitions_operations); +#endif create_seq_entry("stat", 0, &proc_stat_operations); create_seq_entry("interrupts", 0, &proc_interrupts_operations); #ifdef CONFIG_SLAB @@ -707,7 +714,9 @@ void __init proc_misc_init(void) create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations); +#ifdef CONFIG_BLOCK create_seq_entry("diskstats", 0, &proc_diskstats_operations); +#endif #ifdef CONFIG_MODULES create_seq_entry("modules", 0, &proc_modules_operations); #endif diff --git a/fs/quota.c b/fs/quota.c index d6a2be826e29..b9dae76a0b6e 100644 --- a/fs/quota.c +++ b/fs/quota.c @@ -337,6 +337,34 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void return 0; } +/* + * look up a superblock on which quota ops will be performed + * - use the name of a block device to find the superblock thereon + */ +static inline struct super_block *quotactl_block(const char __user *special) +{ +#ifdef CONFIG_BLOCK + struct block_device *bdev; + struct super_block *sb; + char *tmp = getname(special); + + if (IS_ERR(tmp)) + return ERR_PTR(PTR_ERR(tmp)); + bdev = lookup_bdev(tmp); + putname(tmp); + if (IS_ERR(bdev)) + return ERR_PTR(PTR_ERR(bdev)); + sb = get_super(bdev); + bdput(bdev); + if (!sb) + return ERR_PTR(-ENODEV); + + return sb; +#else + return ERR_PTR(-ENODEV); +#endif +} + /* * This is the system call interface. This communicates with * the user-level programs. Currently this only supports diskquota @@ -347,25 +375,15 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t { uint cmds, type; struct super_block *sb = NULL; - struct block_device *bdev; - char *tmp; int ret; cmds = cmd >> SUBCMDSHIFT; type = cmd & SUBCMDMASK; if (cmds != Q_SYNC || special) { - tmp = getname(special); - if (IS_ERR(tmp)) - return PTR_ERR(tmp); - bdev = lookup_bdev(tmp); - putname(tmp); - if (IS_ERR(bdev)) - return PTR_ERR(bdev); - sb = get_super(bdev); - bdput(bdev); - if (!sb) - return -ENODEV; + sb = quotactl_block(special); + if (IS_ERR(sb)) + return PTR_ERR(sb); } ret = check_quotactl_valid(sb, type, cmds, id); diff --git a/fs/super.c b/fs/super.c index 15671cd048b1..aec99ddbe53f 100644 --- a/fs/super.c +++ b/fs/super.c @@ -571,8 +571,10 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) { int retval; +#ifdef CONFIG_BLOCK if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev)) return -EACCES; +#endif if (flags & MS_RDONLY) acct_auto_close(sb); shrink_dcache_sb(sb); @@ -692,6 +694,7 @@ void kill_litter_super(struct super_block *sb) EXPORT_SYMBOL(kill_litter_super); +#ifdef CONFIG_BLOCK static int set_bdev_super(struct super_block *s, void *data) { s->s_bdev = data; @@ -787,6 +790,7 @@ void kill_block_super(struct super_block *sb) } EXPORT_SYMBOL(kill_block_super); +#endif int get_sb_nodev(struct file_system_type *fs_type, int flags, void *data, diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig index 26b364c9d62c..35115bca036e 100644 --- a/fs/xfs/Kconfig +++ b/fs/xfs/Kconfig @@ -1,5 +1,6 @@ config XFS_FS tristate "XFS filesystem support" + depends on BLOCK help XFS is a high performance journaling filesystem which originated on the SGI IRIX platform. It is completely multi-threaded, can diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2c01a90998a7..3e36107d342a 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -16,6 +16,22 @@ #include +#ifdef CONFIG_LBD +# include +# define sector_div(a, b) do_div(a, b) +#else +# define sector_div(n, b)( \ +{ \ + int _res; \ + _res = (n) % (b); \ + (n) /= (b); \ + _res; \ +} \ +) +#endif + +#ifdef CONFIG_BLOCK + struct scsi_ioctl_command; struct request_queue; @@ -818,24 +834,30 @@ struct work_struct; int kblockd_schedule_work(struct work_struct *work); void kblockd_flush(void); -#ifdef CONFIG_LBD -# include -# define sector_div(a, b) do_div(a, b) -#else -# define sector_div(n, b)( \ -{ \ - int _res; \ - _res = (n) % (b); \ - (n) /= (b); \ - _res; \ -} \ -) -#endif - #define MODULE_ALIAS_BLOCKDEV(major,minor) \ MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor)) #define MODULE_ALIAS_BLOCKDEV_MAJOR(major) \ MODULE_ALIAS("block-major-" __stringify(major) "-*") +#else /* CONFIG_BLOCK */ +/* + * stubs for when the block layer is configured out + */ +#define buffer_heads_over_limit 0 + +static inline long blk_congestion_wait(int rw, long timeout) +{ + return timeout; +} + +static inline long nr_blockdev_pages(void) +{ + return 0; +} + +static inline void exit_io_context(void) {} + +#endif /* CONFIG_BLOCK */ + #endif diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 64b508e35d2a..131ffd37e716 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -14,6 +14,8 @@ #include #include +#ifdef CONFIG_BLOCK + enum bh_state_bits { BH_Uptodate, /* Contains valid data */ BH_Dirty, /* Is dirty */ @@ -301,4 +303,18 @@ static inline void lock_buffer(struct buffer_head *bh) } extern int __set_page_dirty_buffers(struct page *page); + +#else /* CONFIG_BLOCK */ + +static inline void buffer_init(void) {} +static inline int try_to_free_buffers(struct page *page) { return 1; } +static inline int sync_blockdev(struct block_device *bdev) { return 0; } +static inline int inode_has_buffers(struct inode *inode) { return 0; } +static inline void invalidate_inode_buffers(struct inode *inode) {} +static inline int remove_inode_buffers(struct inode *inode) { return 1; } +static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; } +static inline void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers) {} + + +#endif /* CONFIG_BLOCK */ #endif /* _LINUX_BUFFER_HEAD_H */ diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index 98d40e08ba6e..d61ef5951538 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -90,6 +90,7 @@ COMPATIBLE_IOCTL(FDTWADDLE) COMPATIBLE_IOCTL(FDFMTTRK) COMPATIBLE_IOCTL(FDRAWCMD) /* 0x12 */ +#ifdef CONFIG_BLOCK COMPATIBLE_IOCTL(BLKRASET) COMPATIBLE_IOCTL(BLKROSET) COMPATIBLE_IOCTL(BLKROGET) @@ -103,6 +104,7 @@ COMPATIBLE_IOCTL(BLKTRACESETUP) COMPATIBLE_IOCTL(BLKTRACETEARDOWN) ULONG_IOCTL(BLKRASET) ULONG_IOCTL(BLKFRASET) +#endif /* RAID */ COMPATIBLE_IOCTL(RAID_VERSION) COMPATIBLE_IOCTL(GET_ARRAY_INFO) diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 9c5a04f6114c..b3370ef5164d 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -3,6 +3,8 @@ #include +#ifdef CONFIG_BLOCK + typedef int (elevator_merge_fn) (request_queue_t *, struct request **, struct bio *); @@ -203,4 +205,5 @@ enum { __val; \ }) +#endif /* CONFIG_BLOCK */ #endif diff --git a/include/linux/fs.h b/include/linux/fs.h index b73a47582dbe..5baf3a153403 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1482,6 +1482,7 @@ extern void __init vfs_caches_init(unsigned long); extern void putname(const char *name); #endif +#ifdef CONFIG_BLOCK extern int register_blkdev(unsigned int, const char *); extern int unregister_blkdev(unsigned int, const char *); extern struct block_device *bdget(dev_t); @@ -1490,11 +1491,15 @@ extern void bd_forget(struct inode *inode); extern void bdput(struct block_device *); extern struct block_device *open_by_devnum(dev_t, unsigned); extern struct block_device *open_partition_by_devnum(dev_t, unsigned); -extern const struct file_operations def_blk_fops; extern const struct address_space_operations def_blk_aops; +#else +static inline void bd_forget(struct inode *inode) {} +#endif +extern const struct file_operations def_blk_fops; extern const struct file_operations def_chr_fops; extern const struct file_operations bad_sock_fops; extern const struct file_operations def_fifo_fops; +#ifdef CONFIG_BLOCK extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long); extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long); @@ -1510,6 +1515,7 @@ extern void bd_release_from_disk(struct block_device *, struct gendisk *); #define bd_claim_by_disk(bdev, holder, disk) bd_claim(bdev, holder) #define bd_release_from_disk(bdev, disk) bd_release(bdev) #endif +#endif /* fs/char_dev.c */ #define CHRDEV_MAJOR_HASH_SIZE 255 @@ -1523,14 +1529,19 @@ extern int chrdev_open(struct inode *, struct file *); extern void chrdev_show(struct seq_file *,off_t); /* fs/block_dev.c */ -#define BLKDEV_MAJOR_HASH_SIZE 255 #define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */ + +#ifdef CONFIG_BLOCK +#define BLKDEV_MAJOR_HASH_SIZE 255 extern const char *__bdevname(dev_t, char *buffer); extern const char *bdevname(struct block_device *bdev, char *buffer); extern struct block_device *lookup_bdev(const char *); extern struct block_device *open_bdev_excl(const char *, int, void *); extern void close_bdev_excl(struct block_device *); extern void blkdev_show(struct seq_file *,off_t); +#else +#define BLKDEV_MAJOR_HASH_SIZE 0 +#endif extern void init_special_inode(struct inode *, umode_t, dev_t); @@ -1544,6 +1555,7 @@ extern const struct file_operations rdwr_fifo_fops; extern int fs_may_remount_ro(struct super_block *); +#ifdef CONFIG_BLOCK /* * return READ, READA, or WRITE */ @@ -1555,9 +1567,10 @@ extern int fs_may_remount_ro(struct super_block *); #define bio_data_dir(bio) ((bio)->bi_rw & 1) extern int check_disk_change(struct block_device *); -extern int invalidate_inodes(struct super_block *); extern int __invalidate_device(struct block_device *); extern int invalidate_partition(struct gendisk *, int); +#endif +extern int invalidate_inodes(struct super_block *); unsigned long invalidate_mapping_pages(struct address_space *mapping, pgoff_t start, pgoff_t end); unsigned long invalidate_inode_pages(struct address_space *mapping); @@ -1590,7 +1603,9 @@ extern void emergency_sync(void); extern void emergency_remount(void); extern int do_remount_sb(struct super_block *sb, int flags, void *data, int force); +#ifdef CONFIG_BLOCK extern sector_t bmap(struct inode *, sector_t); +#endif extern int notify_change(struct dentry *, struct iattr *); extern int permission(struct inode *, int, struct nameidata *); extern int generic_permission(struct inode *, int, @@ -1673,9 +1688,11 @@ static inline void insert_inode_hash(struct inode *inode) { extern struct file * get_empty_filp(void); extern void file_move(struct file *f, struct list_head *list); extern void file_kill(struct file *f); +#ifdef CONFIG_BLOCK struct bio; extern void submit_bio(int, struct bio *); extern int bdev_read_only(struct block_device *); +#endif extern int set_blocksize(struct block_device *, int); extern int sb_set_blocksize(struct super_block *, int); extern int sb_min_blocksize(struct super_block *, int); @@ -1756,6 +1773,7 @@ static inline void do_generic_file_read(struct file * filp, loff_t *ppos, actor); } +#ifdef CONFIG_BLOCK ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, struct block_device *bdev, const struct iovec *iov, loff_t offset, unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, @@ -1793,6 +1811,7 @@ static inline ssize_t blockdev_direct_IO_own_locking(int rw, struct kiocb *iocb, return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, nr_segs, get_block, end_io, DIO_OWN_LOCKING); } +#endif extern const struct file_operations generic_ro_fops; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index e4af57e87c17..41f276fdd185 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -11,6 +11,8 @@ #include +#ifdef CONFIG_BLOCK + enum { /* These three have identical behaviour; use the second one if DOS FDISK gets confused about extended/logical partitions starting past cylinder 1023. */ @@ -420,3 +422,5 @@ static inline struct block_device *bdget_disk(struct gendisk *disk, int index) #endif #endif + +#endif diff --git a/include/linux/mpage.h b/include/linux/mpage.h index 517c098fde20..cc5fb75af78a 100644 --- a/include/linux/mpage.h +++ b/include/linux/mpage.h @@ -9,6 +9,7 @@ * (And no, it doesn't do the #ifdef __MPAGE_H thing, and it doesn't do * nested includes. Get it right in the .c file). */ +#ifdef CONFIG_BLOCK struct writeback_control; typedef int (writepage_t)(struct page *page, struct writeback_control *wbc); @@ -20,3 +21,5 @@ int mpage_writepages(struct address_space *mapping, struct writeback_control *wbc, get_block_t get_block); int mpage_writepage(struct page *page, get_block_t *get_block, struct writeback_control *wbc); + +#endif diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h index eb3e547c8fee..c588709acbbc 100644 --- a/include/linux/raid/md.h +++ b/include/linux/raid/md.h @@ -53,6 +53,8 @@ #include #include +#ifdef CONFIG_MD + /* * Different major versions are not compatible. * Different minor versions are only downward compatible. @@ -95,5 +97,6 @@ extern void md_new_event(mddev_t *mddev); extern void md_update_sb(mddev_t * mddev); +#endif /* CONFIG_MD */ #endif diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index d28890295852..920b94fe31fa 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -18,6 +18,8 @@ /* and dm-bio-list.h is not under include/linux because.... ??? */ #include "../../../drivers/md/dm-bio-list.h" +#ifdef CONFIG_BLOCK + #define LEVEL_MULTIPATH (-4) #define LEVEL_LINEAR (-1) #define LEVEL_FAULTY (-5) @@ -362,5 +364,6 @@ static inline void safe_put_page(struct page *p) if (p) put_page(p); } +#endif /* CONFIG_BLOCK */ #endif diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h index bbf66219b769..c247a28259bc 100644 --- a/include/scsi/scsi_tcq.h +++ b/include/scsi/scsi_tcq.h @@ -6,7 +6,6 @@ #include #include - #define MSG_SIMPLE_TAG 0x20 #define MSG_HEAD_TAG 0x21 #define MSG_ORDERED_TAG 0x22 @@ -14,6 +13,7 @@ #define SCSI_NO_TAG (-1) /* identify no tag in use */ +#ifdef CONFIG_BLOCK /** * scsi_get_tag_type - get the type of tag the device supports @@ -144,4 +144,5 @@ static inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth) return shost->bqt ? 0 : -ENOMEM; } +#endif /* CONFIG_BLOCK */ #endif /* _SCSI_SCSI_TCQ_H */ diff --git a/init/Kconfig b/init/Kconfig index 4381006dd666..d2eb7a84a264 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -92,7 +92,7 @@ config LOCALVERSION_AUTO config SWAP bool "Support for paging of anonymous memory (swap)" - depends on MMU + depends on MMU && BLOCK default y help This option allows you to choose whether you want to have support diff --git a/init/do_mounts.c b/init/do_mounts.c index b290aadb1d3f..dc1ec0803ef9 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -285,7 +285,11 @@ void __init mount_block_root(char *name, int flags) { char *fs_names = __getname(); char *p; +#ifdef CONFIG_BLOCK char b[BDEVNAME_SIZE]; +#else + const char *b = name; +#endif get_fs_names(fs_names); retry: @@ -304,7 +308,9 @@ retry: * Allow the user to distinguish between failed sys_open * and bad superblock on root device. */ +#ifdef CONFIG_BLOCK __bdevname(ROOT_DEV, b); +#endif printk("VFS: Cannot open root device \"%s\" or %s\n", root_device_name, b); printk("Please append a correct \"root=\" boot option\n"); @@ -316,7 +322,10 @@ retry: for (p = fs_names; *p; p += strlen(p)+1) printk(" %s", p); printk("\n"); - panic("VFS: Unable to mount root fs on %s", __bdevname(ROOT_DEV, b)); +#ifdef CONFIG_BLOCK + __bdevname(ROOT_DEV, b); +#endif + panic("VFS: Unable to mount root fs on %s", b); out: putname(fs_names); } @@ -387,8 +396,10 @@ void __init mount_root(void) change_floppy("root floppy"); } #endif +#ifdef CONFIG_BLOCK create_dev("/dev/root", ROOT_DEV); mount_block_root("/dev/root", root_mountflags); +#endif } /* diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 6991bece67e8..7a3b2e75f040 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -134,3 +134,8 @@ cond_syscall(sys_madvise); cond_syscall(sys_mremap); cond_syscall(sys_remap_file_pages); cond_syscall(compat_sys_move_pages); + +/* block-layer dependent */ +cond_syscall(sys_bdflush); +cond_syscall(sys_ioprio_set); +cond_syscall(sys_ioprio_get); diff --git a/mm/Makefile b/mm/Makefile index 4f2166a833b9..12b3a4eee88d 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -12,7 +12,7 @@ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ readahead.o swap.o truncate.o vmscan.o \ prio_tree.o util.o mmzone.o vmstat.o $(mmu-y) -ifeq ($(CONFIG_MMU),y) +ifeq ($(CONFIG_MMU)$(CONFIG_BLOCK),yy) obj-y += bounce.o endif obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o diff --git a/mm/filemap.c b/mm/filemap.c index d6846de08887..c4fe97f5ace0 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2020,6 +2020,7 @@ inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count, i if (unlikely(*pos + *count > inode->i_sb->s_maxbytes)) *count = inode->i_sb->s_maxbytes - *pos; } else { +#ifdef CONFIG_BLOCK loff_t isize; if (bdev_read_only(I_BDEV(inode))) return -EPERM; @@ -2031,6 +2032,9 @@ inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count, i if (*pos + *count > isize) *count = isize - *pos; +#else + return -EPERM; +#endif } return 0; } diff --git a/mm/migrate.c b/mm/migrate.c index 7f50e3ff54cd..ba2453f9483d 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -409,6 +409,7 @@ int migrate_page(struct address_space *mapping, } EXPORT_SYMBOL(migrate_page); +#ifdef CONFIG_BLOCK /* * Migration function for pages with buffers. This function can only be used * if the underlying filesystem guarantees that no other references to "page" @@ -466,6 +467,7 @@ int buffer_migrate_page(struct address_space *mapping, return 0; } EXPORT_SYMBOL(buffer_migrate_page); +#endif /* * Writeback a page to clean the dirty state diff --git a/mm/page-writeback.c b/mm/page-writeback.c index ecf27839c203..c0d4ce144dec 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -807,9 +807,11 @@ int fastcall set_page_dirty(struct page *page) if (likely(mapping)) { int (*spd)(struct page *) = mapping->a_ops->set_page_dirty; - if (spd) - return (*spd)(page); - return __set_page_dirty_buffers(page); +#ifdef CONFIG_BLOCK + if (!spd) + spd = __set_page_dirty_buffers; +#endif + return (*spd)(page); } if (!PageDirty(page)) { if (!TestSetPageDirty(page)) diff --git a/mm/truncate.c b/mm/truncate.c index cd3e34b816db..8fde6580657e 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -35,8 +35,10 @@ void do_invalidatepage(struct page *page, unsigned long offset) { void (*invalidatepage)(struct page *, unsigned long); invalidatepage = page->mapping->a_ops->invalidatepage; +#ifdef CONFIG_BLOCK if (!invalidatepage) invalidatepage = block_invalidatepage; +#endif if (invalidatepage) (*invalidatepage)(page, offset); } -- cgit v1.2.3 From bcfd8d36151e531e1c6c731f1fbf792509a1c494 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 31 Aug 2006 12:56:06 +0200 Subject: [PATCH] CONFIG_BLOCK: blk_congestion_wait() fix Don't just do nothing: it'll cause busywaits all over writeback and page reclaim. For now, take a fixed-length nap. Will improve when NFS starts waking up throttled processes. Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 3e36107d342a..1d79b8d4ca6d 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1,6 +1,7 @@ #ifndef _LINUX_BLKDEV_H #define _LINUX_BLKDEV_H +#include #include #include #include @@ -848,7 +849,7 @@ void kblockd_flush(void); static inline long blk_congestion_wait(int rw, long timeout) { - return timeout; + return io_schedule_timeout(timeout); } static inline long nr_blockdev_pages(void) @@ -856,7 +857,9 @@ static inline long nr_blockdev_pages(void) return 0; } -static inline void exit_io_context(void) {} +static inline void exit_io_context(void) +{ +} #endif /* CONFIG_BLOCK */ -- cgit v1.2.3 From 236561e5df009f79f1939e3ca269b9b6f18092f5 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 30 Sep 2006 23:27:03 -0700 Subject: [PATCH] PCI quirks update This fixes two things Firstly someone mistakenly used "errata" for the singular. This causes Dave Woodhouse to emit diagnostics whenever the string is read, and so should be fixed. Secondly the AMD AGP tunnel has an erratum which causes hangs if you try and do direct PCI to AGP transfers in some cases. We have a flag for PCI/PCI failures but we need a different flag for this really as in this case we don't want to stop PCI/PCI transfers using things like IOAT and the new RAID offload work. I'll post some updates to make proper use of the PCIAGP flag in the media/video drivers to Mauro. Signed-off-by: Alan Cox Cc: David Woodhouse Signed-off-by: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/quirks.c | 17 +++++++++++++++-- include/linux/pci.h | 5 +++-- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 08cd86a6dd66..23b599d6a9d5 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -93,8 +93,21 @@ static void __devinit quirk_nopcipci(struct pci_dev *dev) pci_pci_problems |= PCIPCI_FAIL; } } + +static void __devinit quirk_nopciamd(struct pci_dev *dev) +{ + u8 rev; + pci_read_config_byte(dev, 0x08, &rev); + if (rev == 0x13) { + /* Erratum 24 */ + printk(KERN_INFO "Chipset erratum: Disabling direct PCI/AGP transfers.\n"); + pci_pci_problems |= PCIAGP_FAIL; + } +} + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci ); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd ); /* * Triton requires workarounds to be used by the drivers @@ -555,7 +568,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_vt * is currently marked NoFix * * We have multiple reports of hangs with this chipset that went away with - * noapic specified. For the moment we assume its the errata. We may be wrong + * noapic specified. For the moment we assume it's the erratum. We may be wrong * of course. However the advice is demonstrably good even if so.. */ static void __devinit quirk_amd_ioapic(struct pci_dev *dev) @@ -564,7 +577,7 @@ static void __devinit quirk_amd_ioapic(struct pci_dev *dev) pci_read_config_byte(dev, PCI_REVISION_ID, &rev); if (rev >= 0x02) { - printk(KERN_WARNING "I/O APIC: AMD Errata #22 may be present. In the event of instability try\n"); + printk(KERN_WARNING "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n"); printk(KERN_WARNING " : booting with the \"noapic\" option.\n"); } } diff --git a/include/linux/pci.h b/include/linux/pci.h index 5c3a4176eb64..4431ce4e1e6f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -787,12 +787,13 @@ enum pci_fixup_pass { void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); extern int pci_pci_problems; -#define PCIPCI_FAIL 1 +#define PCIPCI_FAIL 1 /* No PCI PCI DMA */ #define PCIPCI_TRITON 2 #define PCIPCI_NATOMA 4 #define PCIPCI_VIAETBF 8 #define PCIPCI_VSFX 16 -#define PCIPCI_ALIMAGIK 32 +#define PCIPCI_ALIMAGIK 32 /* Need low latency setting */ +#define PCIAGP_FAIL 64 /* No PCI to AGP DMA */ #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ -- cgit v1.2.3 From f28c5edc06ecd8068b38b7662ad19f4d20d741af Mon Sep 17 00:00:00 2001 From: Keith Mannthey Date: Sat, 30 Sep 2006 23:27:04 -0700 Subject: [PATCH] hot-add-mem x86_64: fixup externs Fix up externs in memory_hotplug.c. Cleanup. Signed-off-by: Keith Mannthey Cc: KAMEZAWA Hiroyuki Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/memory_hotplug.h | 2 ++ include/linux/mm.h | 2 ++ mm/memory_hotplug.c | 4 ---- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 218501cfaeb9..7b54666cea8e 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -172,5 +172,7 @@ static inline int __remove_pages(struct zone *zone, unsigned long start_pfn, extern int add_memory(int nid, u64 start, u64 size); extern int arch_add_memory(int nid, u64 start, u64 size); extern int remove_memory(u64 start, u64 size); +extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, + int nr_pages); #endif /* __LINUX_MEMORY_HOTPLUG_H */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 4edf1934e5ca..b7966ab8cb6a 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -946,6 +946,8 @@ extern void mem_init(void); extern void show_mem(void); extern void si_meminfo(struct sysinfo * val); extern void si_meminfo_node(struct sysinfo *val, int nid); +extern void zonetable_add(struct zone *zone, int nid, enum zone_type zid, + unsigned long pfn, unsigned long size); #ifdef CONFIG_NUMA extern void setup_per_cpu_pageset(void); diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 2053bb165a21..63b14d4f68fb 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -26,8 +26,6 @@ #include -extern void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn, - unsigned long size); static int __add_zone(struct zone *zone, unsigned long phys_start_pfn) { struct pglist_data *pgdat = zone->zone_pgdat; @@ -47,8 +45,6 @@ static int __add_zone(struct zone *zone, unsigned long phys_start_pfn) return 0; } -extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, - int nr_pages); static int __add_section(struct zone *zone, unsigned long phys_start_pfn) { int nr_pages = PAGES_PER_SECTION; -- cgit v1.2.3 From 53947027ad90542ddb2bb746e3175827c270610a Mon Sep 17 00:00:00 2001 From: Keith Mannthey Date: Sat, 30 Sep 2006 23:27:08 -0700 Subject: [PATCH] hot-add-mem x86_64: use CONFIG_MEMORY_HOTPLUG_SPARSE Migate CONFIG_MEMORY_HOTPLUG to CONFIG_MEMORY_HOTPLUG_SPARSE where needed. Signed-off-by: Keith Mannthey Cc: KAMEZAWA Hiroyuki Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/Makefile | 2 +- include/linux/memory.h | 4 ++-- mm/memory_hotplug.c | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/Makefile b/drivers/base/Makefile index b539e5e75b56..7bbb9eeda235 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -8,7 +8,7 @@ obj-y += power/ obj-$(CONFIG_ISA) += isa.o obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o -obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o +obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o obj-$(CONFIG_SMP) += topology.o obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o diff --git a/include/linux/memory.h b/include/linux/memory.h index 8f04143ca363..654ef5544878 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -57,7 +57,7 @@ struct memory_block { struct notifier_block; struct mem_section; -#ifndef CONFIG_MEMORY_HOTPLUG +#ifndef CONFIG_MEMORY_HOTPLUG_SPARSE static inline int memory_dev_init(void) { return 0; @@ -78,7 +78,7 @@ extern int remove_memory_block(unsigned long, struct mem_section *, int); #define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION< +#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE static int __add_zone(struct zone *zone, unsigned long phys_start_pfn) { struct pglist_data *pgdat = zone->zone_pgdat; @@ -192,6 +193,7 @@ int online_pages(unsigned long pfn, unsigned long nr_pages) writeback_set_ratelimit(); return 0; } +#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ static pg_data_t *hotadd_new_pgdat(int nid, u64 start) { -- cgit v1.2.3 From 6e21828743247270d09a86756a0c11702500dbfb Mon Sep 17 00:00:00 2001 From: Richard Knutsson Date: Sat, 30 Sep 2006 23:27:11 -0700 Subject: [PATCH] Generic boolean This patch defines: * a generic boolean-type, named 'bool' * aliases to 0 and 1, named 'false' and 'true' Removing colliding definitions of 'bool', 'false' and 'true'. Signed-off-by: Richard Knutsson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/DAC960.h | 2 +- drivers/media/video/cpia2/cpia2.h | 4 ---- drivers/net/dgrs.c | 1 - drivers/scsi/BusLogic.h | 5 +---- include/linux/stddef.h | 6 ++++++ include/linux/types.h | 2 ++ 6 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index a82f37f749a5..f9217c34bc2b 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -71,7 +71,7 @@ Define a Boolean data type. */ -typedef enum { false, true } __attribute__ ((packed)) boolean; +typedef bool boolean; /* diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h index c5ecb2be5f93..8d2dfc128821 100644 --- a/drivers/media/video/cpia2/cpia2.h +++ b/drivers/media/video/cpia2/cpia2.h @@ -50,10 +50,6 @@ /*** * Image defines ***/ -#ifndef true -#define true 1 -#define false 0 -#endif /* Misc constants */ #define ALLOW_CORRUPT 0 /* Causes collater to discard checksum */ diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index e9361cb5f4cd..d0842527b369 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -110,7 +110,6 @@ static char version[] __initdata = * DGRS include files */ typedef unsigned char uchar; -typedef unsigned int bool; #define vol volatile #include "dgrs.h" diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index 9792e5af5252..d6d1d5613c8a 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -237,10 +237,7 @@ enum BusLogic_BIOS_DiskGeometryTranslation { Define a Boolean data type. */ -typedef enum { - false, - true -} PACKED boolean; +typedef bool boolean; /* Define a 10^18 Statistics Byte Counter data type. diff --git a/include/linux/stddef.h b/include/linux/stddef.h index ea65dfb60cd8..6a40c76bdcf1 100644 --- a/include/linux/stddef.h +++ b/include/linux/stddef.h @@ -11,6 +11,12 @@ #endif #ifdef __KERNEL__ + +enum { + false = 0, + true = 1 +}; + #undef offsetof #ifdef __compiler_offsetof #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) diff --git a/include/linux/types.h b/include/linux/types.h index 3f235660a3cd..406d4ae57631 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -33,6 +33,8 @@ typedef __kernel_clockid_t clockid_t; typedef __kernel_mqd_t mqd_t; #ifdef __KERNEL__ +typedef _Bool bool; + typedef __kernel_uid32_t uid_t; typedef __kernel_gid32_t gid_t; typedef __kernel_uid16_t uid16_t; -- cgit v1.2.3 From 5c87579e65ee4f419b2369407f82326d38b5d2d8 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sat, 30 Sep 2006 23:27:17 -0700 Subject: [PATCH] maximum latency tracking infrastructure Add infrastructure to track "maximum allowable latency" for power saving policies. The reason for adding this infrastructure is that power management in the idle loop needs to make a tradeoff between latency and power savings (deeper power save modes have a longer latency to running code again). The code that today makes this tradeoff just does a rather simple algorithm; however this is not good enough: There are devices and use cases where a lower latency is required than that the higher power saving states provide. An example would be audio playback, but another example is the ipw2100 wireless driver that right now has a very direct and ugly acpi hook to disable some higher power states randomly when it gets certain types of error. The proposed solution is to have an interface where drivers can * announce the maximum latency (in microseconds) that they can deal with * modify this latency * give up their constraint and a function where the code that decides on power saving strategy can query the current global desired maximum. This patch has a user of each side: on the consumer side, ACPI is patched to use this, on the producer side the ipw2100 driver is patched. A generic maximum latency is also registered of 2 timer ticks (more and you lose accurate time tracking after all). While the existing users of the patch are x86 specific, the infrastructure is not. I'd like to ask the arch maintainers of other architectures if the infrastructure is generic enough for their use (assuming the architecture has such a tradeoff as concept at all), and the sound/multimedia driver owners to look at the driver facing API to see if this is something they can use. [akpm@osdl.org: cleanups] Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Acked-by: Jesse Barnes Cc: "Brown, Len" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/processor_idle.c | 38 +++++- drivers/net/wireless/ipw2100.c | 10 ++ include/linux/latency.h | 25 ++++ kernel/Makefile | 2 +- kernel/latency.c | 279 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 349 insertions(+), 5 deletions(-) create mode 100644 include/linux/latency.h create mode 100644 kernel/latency.c (limited to 'include/linux') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 71066066d626..0a395fca843b 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -38,6 +38,7 @@ #include #include #include /* need_resched() */ +#include #include #include @@ -453,7 +454,8 @@ static void acpi_processor_idle(void) */ if (cx->promotion.state && ((cx->promotion.state - pr->power.states) <= max_cstate)) { - if (sleep_ticks > cx->promotion.threshold.ticks) { + if (sleep_ticks > cx->promotion.threshold.ticks && + cx->promotion.state->latency <= system_latency_constraint()) { cx->promotion.count++; cx->demotion.count = 0; if (cx->promotion.count >= @@ -494,8 +496,10 @@ static void acpi_processor_idle(void) end: /* * Demote if current state exceeds max_cstate + * or if the latency of the current state is unacceptable */ - if ((pr->power.state - pr->power.states) > max_cstate) { + if ((pr->power.state - pr->power.states) > max_cstate || + pr->power.state->latency > system_latency_constraint()) { if (cx->demotion.state) next_state = cx->demotion.state; } @@ -1009,9 +1013,11 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset) seq_printf(seq, "active state: C%zd\n" "max_cstate: C%d\n" - "bus master activity: %08x\n", + "bus master activity: %08x\n" + "maximum allowed latency: %d usec\n", pr->power.state ? pr->power.state - pr->power.states : 0, - max_cstate, (unsigned)pr->power.bm_activity); + max_cstate, (unsigned)pr->power.bm_activity, + system_latency_constraint()); seq_puts(seq, "states:\n"); @@ -1077,6 +1083,28 @@ static const struct file_operations acpi_processor_power_fops = { .release = single_release, }; +static void smp_callback(void *v) +{ + /* we already woke the CPU up, nothing more to do */ +} + +/* + * This function gets called when a part of the kernel has a new latency + * requirement. This means we need to get all processors out of their C-state, + * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that + * wakes them all right up. + */ +static int acpi_processor_latency_notify(struct notifier_block *b, + unsigned long l, void *v) +{ + smp_call_function(smp_callback, NULL, 0, 1); + return NOTIFY_OK; +} + +static struct notifier_block acpi_processor_latency_notifier = { + .notifier_call = acpi_processor_latency_notify, +}; + int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) { @@ -1093,6 +1121,7 @@ int acpi_processor_power_init(struct acpi_processor *pr, "ACPI: processor limited to max C-state %d\n", max_cstate); first_run++; + register_latency_notifier(&acpi_processor_latency_notifier); } if (!pr) @@ -1164,6 +1193,7 @@ int acpi_processor_power_exit(struct acpi_processor *pr, * copies of pm_idle before proceeding. */ cpu_idle_wait(); + unregister_latency_notifier(&acpi_processor_latency_notifier); } return 0; diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 6c5add701a6f..97937809de09 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -163,6 +163,7 @@ that only one external action is invoked at a time. #include #include #include +#include #include "ipw2100.h" @@ -1697,6 +1698,11 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) return 0; } + /* the ipw2100 hardware really doesn't want power management delays + * longer than 175usec + */ + modify_acceptable_latency("ipw2100", 175); + /* If the interrupt is enabled, turn it off... */ spin_lock_irqsave(&priv->low_lock, flags); ipw2100_disable_interrupts(priv); @@ -1849,6 +1855,8 @@ static void ipw2100_down(struct ipw2100_priv *priv) ipw2100_disable_interrupts(priv); spin_unlock_irqrestore(&priv->low_lock, flags); + modify_acceptable_latency("ipw2100", INFINITE_LATENCY); + #ifdef ACPI_CSTATE_LIMIT_DEFINED if (priv->config & CFG_C3_DISABLED) { IPW_DEBUG_INFO(": Resetting C3 transitions.\n"); @@ -6534,6 +6542,7 @@ static int __init ipw2100_init(void) ret = pci_register_driver(&ipw2100_pci_driver); + set_acceptable_latency("ipw2100", INFINITE_LATENCY); #ifdef CONFIG_IPW2100_DEBUG ipw2100_debug_level = debug; driver_create_file(&ipw2100_pci_driver.driver, @@ -6554,6 +6563,7 @@ static void __exit ipw2100_exit(void) &driver_attr_debug_level); #endif pci_unregister_driver(&ipw2100_pci_driver); + remove_acceptable_latency("ipw2100"); } module_init(ipw2100_init); diff --git a/include/linux/latency.h b/include/linux/latency.h new file mode 100644 index 000000000000..c08b52bb55b0 --- /dev/null +++ b/include/linux/latency.h @@ -0,0 +1,25 @@ +/* + * latency.h: Explicit system-wide latency-expectation infrastructure + * + * (C) Copyright 2006 Intel Corporation + * Author: Arjan van de Ven + * + */ + +#ifndef _INCLUDE_GUARD_LATENCY_H_ +#define _INCLUDE_GUARD_LATENCY_H_ + +#include + +void set_acceptable_latency(char *identifier, int usecs); +void modify_acceptable_latency(char *identifier, int usecs); +void remove_acceptable_latency(char *identifier); +void synchronize_acceptable_latency(void); +int system_latency_constraint(void); + +int register_latency_notifier(struct notifier_block * nb); +int unregister_latency_notifier(struct notifier_block * nb); + +#define INFINITE_LATENCY 1000000 + +#endif diff --git a/kernel/Makefile b/kernel/Makefile index d62ec66c1af2..e210e8cf7237 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,7 +8,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o extable.o params.o posix-timers.o \ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ - hrtimer.o rwsem.o + hrtimer.o rwsem.o latency.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += time/ diff --git a/kernel/latency.c b/kernel/latency.c new file mode 100644 index 000000000000..258f2555abbc --- /dev/null +++ b/kernel/latency.c @@ -0,0 +1,279 @@ +/* + * latency.c: Explicit system-wide latency-expectation infrastructure + * + * The purpose of this infrastructure is to allow device drivers to set + * latency constraint they have and to collect and summarize these + * expectations globally. The cummulated result can then be used by + * power management and similar users to make decisions that have + * tradoffs with a latency component. + * + * An example user of this are the x86 C-states; each higher C state saves + * more power, but has a higher exit latency. For the idle loop power + * code to make a good decision which C-state to use, information about + * acceptable latencies is required. + * + * An example announcer of latency is an audio driver that knowns it + * will get an interrupt when the hardware has 200 usec of samples + * left in the DMA buffer; in that case the driver can set a latency + * constraint of, say, 150 usec. + * + * Multiple drivers can each announce their maximum accepted latency, + * to keep these appart, a string based identifier is used. + * + * + * (C) Copyright 2006 Intel Corporation + * Author: Arjan van de Ven + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct latency_info { + struct list_head list; + int usecs; + char *identifier; +}; + +/* + * locking rule: all modifications to current_max_latency and + * latency_list need to be done while holding the latency_lock. + * latency_lock needs to be taken _irqsave. + */ +static atomic_t current_max_latency; +static DEFINE_SPINLOCK(latency_lock); + +static LIST_HEAD(latency_list); +static BLOCKING_NOTIFIER_HEAD(latency_notifier); + +/* + * This function returns the maximum latency allowed, which + * happens to be the minimum of all maximum latencies on the + * list. + */ +static int __find_max_latency(void) +{ + int min = INFINITE_LATENCY; + struct latency_info *info; + + list_for_each_entry(info, &latency_list, list) { + if (info->usecs < min) + min = info->usecs; + } + return min; +} + +/** + * set_acceptable_latency - sets the maximum latency acceptable + * @identifier: string that identifies this driver + * @usecs: maximum acceptable latency for this driver + * + * This function informs the kernel that this device(driver) + * can accept at most usecs latency. This setting is used for + * power management and similar tradeoffs. + * + * This function sleeps and can only be called from process + * context. + * Calling this function with an existing identifier is valid + * and will cause the existing latency setting to be changed. + */ +void set_acceptable_latency(char *identifier, int usecs) +{ + struct latency_info *info, *iter; + unsigned long flags; + int found_old = 0; + + info = kzalloc(sizeof(struct latency_info), GFP_KERNEL); + if (!info) + return; + info->usecs = usecs; + info->identifier = kstrdup(identifier, GFP_KERNEL); + if (!info->identifier) + goto free_info; + + spin_lock_irqsave(&latency_lock, flags); + list_for_each_entry(iter, &latency_list, list) { + if (strcmp(iter->identifier, identifier)==0) { + found_old = 1; + iter->usecs = usecs; + break; + } + } + if (!found_old) + list_add(&info->list, &latency_list); + + if (usecs < atomic_read(¤t_max_latency)) + atomic_set(¤t_max_latency, usecs); + + spin_unlock_irqrestore(&latency_lock, flags); + + blocking_notifier_call_chain(&latency_notifier, + atomic_read(¤t_max_latency), NULL); + + /* + * if we inserted the new one, we're done; otherwise there was + * an existing one so we need to free the redundant data + */ + if (!found_old) + return; + + kfree(info->identifier); +free_info: + kfree(info); +} +EXPORT_SYMBOL_GPL(set_acceptable_latency); + +/** + * modify_acceptable_latency - changes the maximum latency acceptable + * @identifier: string that identifies this driver + * @usecs: maximum acceptable latency for this driver + * + * This function informs the kernel that this device(driver) + * can accept at most usecs latency. This setting is used for + * power management and similar tradeoffs. + * + * This function does not sleep and can be called in any context. + * Trying to use a non-existing identifier silently gets ignored. + * + * Due to the atomic nature of this function, the modified latency + * value will only be used for future decisions; past decisions + * can still lead to longer latencies in the near future. + */ +void modify_acceptable_latency(char *identifier, int usecs) +{ + struct latency_info *iter; + unsigned long flags; + + spin_lock_irqsave(&latency_lock, flags); + list_for_each_entry(iter, &latency_list, list) { + if (strcmp(iter->identifier, identifier) == 0) { + iter->usecs = usecs; + break; + } + } + if (usecs < atomic_read(¤t_max_latency)) + atomic_set(¤t_max_latency, usecs); + spin_unlock_irqrestore(&latency_lock, flags); +} +EXPORT_SYMBOL_GPL(modify_acceptable_latency); + +/** + * remove_acceptable_latency - removes the maximum latency acceptable + * @identifier: string that identifies this driver + * + * This function removes a previously set maximum latency setting + * for the driver and frees up any resources associated with the + * bookkeeping needed for this. + * + * This function does not sleep and can be called in any context. + * Trying to use a non-existing identifier silently gets ignored. + */ +void remove_acceptable_latency(char *identifier) +{ + unsigned long flags; + int newmax = 0; + struct latency_info *iter, *temp; + + spin_lock_irqsave(&latency_lock, flags); + + list_for_each_entry_safe(iter, temp, &latency_list, list) { + if (strcmp(iter->identifier, identifier) == 0) { + list_del(&iter->list); + newmax = iter->usecs; + kfree(iter->identifier); + kfree(iter); + break; + } + } + + /* If we just deleted the system wide value, we need to + * recalculate with a full search + */ + if (newmax == atomic_read(¤t_max_latency)) { + newmax = __find_max_latency(); + atomic_set(¤t_max_latency, newmax); + } + spin_unlock_irqrestore(&latency_lock, flags); +} +EXPORT_SYMBOL_GPL(remove_acceptable_latency); + +/** + * system_latency_constraint - queries the system wide latency maximum + * + * This function returns the system wide maximum latency in + * microseconds. + * + * This function does not sleep and can be called in any context. + */ +int system_latency_constraint(void) +{ + return atomic_read(¤t_max_latency); +} +EXPORT_SYMBOL_GPL(system_latency_constraint); + +/** + * synchronize_acceptable_latency - recalculates all latency decisions + * + * This function will cause a callback to various kernel pieces that + * will make those pieces rethink their latency decisions. This implies + * that if there are overlong latencies in hardware state already, those + * latencies get taken right now. When this call completes no overlong + * latency decisions should be active anymore. + * + * Typical usecase of this is after a modify_acceptable_latency() call, + * which in itself is non-blocking and non-synchronizing. + * + * This function blocks and should not be called with locks held. + */ + +void synchronize_acceptable_latency(void) +{ + blocking_notifier_call_chain(&latency_notifier, + atomic_read(¤t_max_latency), NULL); +} +EXPORT_SYMBOL_GPL(synchronize_acceptable_latency); + +/* + * Latency notifier: this notifier gets called when a non-atomic new + * latency value gets set. The expectation nof the caller of the + * non-atomic set is that when the call returns, future latencies + * are within bounds, so the functions on the notifier list are + * expected to take the overlong latencies immediately, inside the + * callback, and not make a overlong latency decision anymore. + * + * The callback gets called when the new latency value is made + * active so system_latency_constraint() returns the new latency. + */ +int register_latency_notifier(struct notifier_block * nb) +{ + return blocking_notifier_chain_register(&latency_notifier, nb); +} +EXPORT_SYMBOL_GPL(register_latency_notifier); + +int unregister_latency_notifier(struct notifier_block * nb) +{ + return blocking_notifier_chain_unregister(&latency_notifier, nb); +} +EXPORT_SYMBOL_GPL(unregister_latency_notifier); + +static __init int latency_init(void) +{ + atomic_set(¤t_max_latency, INFINITE_LATENCY); + /* + * we don't want by default to have longer latencies than 2 ticks, + * since that would cause lost ticks + */ + set_acceptable_latency("kernel", 2*1000000/HZ); + return 0; +} + +module_init(latency_init); -- cgit v1.2.3 From 1a2f67b459bb7846d4a15924face63eb2683acc2 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 30 Sep 2006 23:27:20 -0700 Subject: [PATCH] kmemdup: introduce One of idiomatic ways to duplicate a region of memory is dst = kmalloc(len, GFP_KERNEL); if (!dst) return -ENOMEM; memcpy(dst, src, len); which is neat code except a programmer needs to write size twice. Which sometimes leads to mistakes. If len passed to kmalloc is smaller that len passed to memcpy, it's straight overwrite-beyond-end. If len passed to memcpy is smaller than len passed to kmalloc, it's either a) legit behaviour ;-), or b) cloned buffer will contain garbage in second half. Slight trolling of commit lists shows several duplications bugs done exactly because of diverged lenghts: Linux: [CRYPTO]: Fix memcpy/memset args. [PATCH] memcpy/memset fixes OpenBSD: kerberosV/src/lib/asn1: der_copy.c:1.4 If programmer is given only one place to play with lengths, I believe, such mistakes could be avoided. With kmemdup, the snippet above will be rewritten as: dst = kmemdup(src, len, GFP_KERNEL); if (!dst) return -ENOMEM; This also leads to smaller code (kzalloc effect). Quick grep shows 200+ places where kmemdup() can be used. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/string.h | 1 + mm/util.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'include/linux') diff --git a/include/linux/string.h b/include/linux/string.h index e4c755860316..4f69ef9e6eb5 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -99,6 +99,7 @@ extern void * memchr(const void *,int,__kernel_size_t); #endif extern char *kstrdup(const char *s, gfp_t gfp); +extern void *kmemdup(const void *src, size_t len, gfp_t gfp); #ifdef __cplusplus } diff --git a/mm/util.c b/mm/util.c index 7368479220b3..e14fa84ef39a 100644 --- a/mm/util.c +++ b/mm/util.c @@ -40,6 +40,24 @@ char *kstrdup(const char *s, gfp_t gfp) } EXPORT_SYMBOL(kstrdup); +/** + * kmemdup - duplicate region of memory + * + * @src: memory region to duplicate + * @len: memory region length + * @gfp: GFP mask to use + */ +void *kmemdup(const void *src, size_t len, gfp_t gfp) +{ + void *p; + + p = ____kmalloc(len, gfp); + if (p) + memcpy(p, src, len); + return p; +} +EXPORT_SYMBOL(kmemdup); + /* * strndup_user - duplicate an existing string from user space * -- cgit v1.2.3 From 82b0547cfae1fb2ee26cad588f6d49a347d24740 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 30 Sep 2006 23:27:22 -0700 Subject: [PATCH] Create fs/utimes.c * fs/open.c is getting bit crowdy * preparation to lutimes(2) Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/Makefile | 2 +- fs/open.c | 134 ------------------------------------------------ fs/utimes.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/namei.h | 1 + include/linux/utime.h | 2 + 5 files changed, 141 insertions(+), 135 deletions(-) create mode 100644 fs/utimes.c (limited to 'include/linux') diff --git a/fs/Makefile b/fs/Makefile index a503e6ce0f32..819b2a93bebe 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -10,7 +10,7 @@ obj-y := open.o read_write.o file_table.o super.o \ ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \ attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ - pnode.o drop_caches.o splice.o sync.o + pnode.o drop_caches.o splice.o sync.o utimes.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o diff --git a/fs/open.c b/fs/open.c index 304c1c7814cb..35c3e454458e 100644 --- a/fs/open.c +++ b/fs/open.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -29,8 +28,6 @@ #include #include -#include - int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) { int retval = -ENODEV; @@ -353,137 +350,6 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length) } #endif -#ifdef __ARCH_WANT_SYS_UTIME - -/* - * sys_utime() can be implemented in user-level using sys_utimes(). - * Is this for backwards compatibility? If so, why not move it - * into the appropriate arch directory (for those architectures that - * need it). - */ - -/* If times==NULL, set access and modification to current time, - * must be owner or have write permission. - * Else, update from *times, must be owner or super user. - */ -asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times) -{ - int error; - struct nameidata nd; - struct inode * inode; - struct iattr newattrs; - - error = user_path_walk(filename, &nd); - if (error) - goto out; - inode = nd.dentry->d_inode; - - error = -EROFS; - if (IS_RDONLY(inode)) - goto dput_and_out; - - /* Don't worry, the checks are done in inode_change_ok() */ - newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; - if (times) { - error = -EPERM; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - goto dput_and_out; - - error = get_user(newattrs.ia_atime.tv_sec, ×->actime); - newattrs.ia_atime.tv_nsec = 0; - if (!error) - error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime); - newattrs.ia_mtime.tv_nsec = 0; - if (error) - goto dput_and_out; - - newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; - } else { - error = -EACCES; - if (IS_IMMUTABLE(inode)) - goto dput_and_out; - - if (current->fsuid != inode->i_uid && - (error = vfs_permission(&nd, MAY_WRITE)) != 0) - goto dput_and_out; - } - mutex_lock(&inode->i_mutex); - error = notify_change(nd.dentry, &newattrs); - mutex_unlock(&inode->i_mutex); -dput_and_out: - path_release(&nd); -out: - return error; -} - -#endif - -/* If times==NULL, set access and modification to current time, - * must be owner or have write permission. - * Else, update from *times, must be owner or super user. - */ -long do_utimes(int dfd, char __user *filename, struct timeval *times) -{ - int error; - struct nameidata nd; - struct inode * inode; - struct iattr newattrs; - - error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); - - if (error) - goto out; - inode = nd.dentry->d_inode; - - error = -EROFS; - if (IS_RDONLY(inode)) - goto dput_and_out; - - /* Don't worry, the checks are done in inode_change_ok() */ - newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; - if (times) { - error = -EPERM; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - goto dput_and_out; - - newattrs.ia_atime.tv_sec = times[0].tv_sec; - newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000; - newattrs.ia_mtime.tv_sec = times[1].tv_sec; - newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000; - newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; - } else { - error = -EACCES; - if (IS_IMMUTABLE(inode)) - goto dput_and_out; - - if (current->fsuid != inode->i_uid && - (error = vfs_permission(&nd, MAY_WRITE)) != 0) - goto dput_and_out; - } - mutex_lock(&inode->i_mutex); - error = notify_change(nd.dentry, &newattrs); - mutex_unlock(&inode->i_mutex); -dput_and_out: - path_release(&nd); -out: - return error; -} - -asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes) -{ - struct timeval times[2]; - - if (utimes && copy_from_user(×, utimes, sizeof(times))) - return -EFAULT; - return do_utimes(dfd, filename, utimes ? times : NULL); -} - -asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes) -{ - return sys_futimesat(AT_FDCWD, filename, utimes); -} - - /* * access() needs to use the real uid/gid, not the effective uid/gid. * We do this by temporarily clearing all FS-related capabilities and diff --git a/fs/utimes.c b/fs/utimes.c new file mode 100644 index 000000000000..1bcd852fc4a9 --- /dev/null +++ b/fs/utimes.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ARCH_WANT_SYS_UTIME + +/* + * sys_utime() can be implemented in user-level using sys_utimes(). + * Is this for backwards compatibility? If so, why not move it + * into the appropriate arch directory (for those architectures that + * need it). + */ + +/* If times==NULL, set access and modification to current time, + * must be owner or have write permission. + * Else, update from *times, must be owner or super user. + */ +asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times) +{ + int error; + struct nameidata nd; + struct inode * inode; + struct iattr newattrs; + + error = user_path_walk(filename, &nd); + if (error) + goto out; + inode = nd.dentry->d_inode; + + error = -EROFS; + if (IS_RDONLY(inode)) + goto dput_and_out; + + /* Don't worry, the checks are done in inode_change_ok() */ + newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; + if (times) { + error = -EPERM; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + goto dput_and_out; + + error = get_user(newattrs.ia_atime.tv_sec, ×->actime); + newattrs.ia_atime.tv_nsec = 0; + if (!error) + error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime); + newattrs.ia_mtime.tv_nsec = 0; + if (error) + goto dput_and_out; + + newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; + } else { + error = -EACCES; + if (IS_IMMUTABLE(inode)) + goto dput_and_out; + + if (current->fsuid != inode->i_uid && + (error = vfs_permission(&nd, MAY_WRITE)) != 0) + goto dput_and_out; + } + mutex_lock(&inode->i_mutex); + error = notify_change(nd.dentry, &newattrs); + mutex_unlock(&inode->i_mutex); +dput_and_out: + path_release(&nd); +out: + return error; +} + +#endif + +/* If times==NULL, set access and modification to current time, + * must be owner or have write permission. + * Else, update from *times, must be owner or super user. + */ +long do_utimes(int dfd, char __user *filename, struct timeval *times) +{ + int error; + struct nameidata nd; + struct inode * inode; + struct iattr newattrs; + + error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); + + if (error) + goto out; + inode = nd.dentry->d_inode; + + error = -EROFS; + if (IS_RDONLY(inode)) + goto dput_and_out; + + /* Don't worry, the checks are done in inode_change_ok() */ + newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; + if (times) { + error = -EPERM; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + goto dput_and_out; + + newattrs.ia_atime.tv_sec = times[0].tv_sec; + newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000; + newattrs.ia_mtime.tv_sec = times[1].tv_sec; + newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000; + newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; + } else { + error = -EACCES; + if (IS_IMMUTABLE(inode)) + goto dput_and_out; + + if (current->fsuid != inode->i_uid && + (error = vfs_permission(&nd, MAY_WRITE)) != 0) + goto dput_and_out; + } + mutex_lock(&inode->i_mutex); + error = notify_change(nd.dentry, &newattrs); + mutex_unlock(&inode->i_mutex); +dput_and_out: + path_release(&nd); +out: + return error; +} + +asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes) +{ + struct timeval times[2]; + + if (utimes && copy_from_user(×, utimes, sizeof(times))) + return -EFAULT; + return do_utimes(dfd, filename, utimes ? times : NULL); +} + +asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes) +{ + return sys_futimesat(AT_FDCWD, filename, utimes); +} diff --git a/include/linux/namei.h b/include/linux/namei.h index c6470ba00668..f5f19606effb 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -1,6 +1,7 @@ #ifndef _LINUX_NAMEI_H #define _LINUX_NAMEI_H +#include #include struct vfsmount; diff --git a/include/linux/utime.h b/include/linux/utime.h index c6bf27b7897e..640be6a1959e 100644 --- a/include/linux/utime.h +++ b/include/linux/utime.h @@ -1,6 +1,8 @@ #ifndef _LINUX_UTIME_H #define _LINUX_UTIME_H +#include + struct utimbuf { time_t actime; time_t modtime; -- cgit v1.2.3 From cb10dc9ac7eea2c891df6b79b9ef1fbe59cb5429 Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Sat, 30 Sep 2006 23:27:45 -0700 Subject: [PATCH] synclink_gt: add bisync and monosync modes Add bisync and monosync serial protocol support to the synclink_gt driver. Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/synclink_gt.c | 88 +++++++++++++++++++++++++++++++++------------- include/linux/synclink.h | 4 ++- 2 files changed, 66 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 2f07b085536b..bd3821679ac8 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -461,7 +461,7 @@ static int adapter_test(struct slgt_info *info); static void reset_adapter(struct slgt_info *info); static void reset_port(struct slgt_info *info); static void async_mode(struct slgt_info *info); -static void hdlc_mode(struct slgt_info *info); +static void sync_mode(struct slgt_info *info); static void rx_stop(struct slgt_info *info); static void rx_start(struct slgt_info *info); @@ -881,7 +881,9 @@ static int write(struct tty_struct *tty, if (!count) goto cleanup; - if (info->params.mode == MGSL_MODE_RAW) { + if (info->params.mode == MGSL_MODE_RAW || + info->params.mode == MGSL_MODE_MONOSYNC || + info->params.mode == MGSL_MODE_BISYNC) { unsigned int bufs_needed = (count/DMABUFSIZE); unsigned int bufs_free = free_tbuf_count(info); if (count % DMABUFSIZE) @@ -1897,6 +1899,8 @@ static void bh_handler(void* context) while(rx_get_frame(info)); break; case MGSL_MODE_RAW: + case MGSL_MODE_MONOSYNC: + case MGSL_MODE_BISYNC: while(rx_get_buf(info)); break; } @@ -2362,10 +2366,9 @@ static void program_hw(struct slgt_info *info) rx_stop(info); tx_stop(info); - if (info->params.mode == MGSL_MODE_HDLC || - info->params.mode == MGSL_MODE_RAW || + if (info->params.mode != MGSL_MODE_ASYNC || info->netcount) - hdlc_mode(info); + sync_mode(info); else async_mode(info); @@ -2564,6 +2567,10 @@ static int rx_enable(struct slgt_info *info, int enable) if (enable) { if (!info->rx_enabled) rx_start(info); + else if (enable == 2) { + /* force hunt mode (write 1 to RCR[3]) */ + wr_reg16(info, RCR, rd_reg16(info, RCR) | BIT3); + } } else { if (info->rx_enabled) rx_stop(info); @@ -3748,7 +3755,7 @@ static void tx_start(struct slgt_info *info) { if (!info->tx_enabled) { wr_reg16(info, TCR, - (unsigned short)(rd_reg16(info, TCR) | BIT1)); + (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2)); info->tx_enabled = TRUE; } @@ -3775,13 +3782,18 @@ static void tx_start(struct slgt_info *info) tdma_reset(info); /* set 1st descriptor address */ wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); - if (info->params.mode == MGSL_MODE_RAW) + switch(info->params.mode) { + case MGSL_MODE_RAW: + case MGSL_MODE_MONOSYNC: + case MGSL_MODE_BISYNC: wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */ - else + break; + default: wr_reg32(info, TDCSR, BIT0); /* DMA enable */ + } } - if (info->params.mode != MGSL_MODE_RAW) { + if (info->params.mode == MGSL_MODE_HDLC) { info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); add_timer(&info->tx_timer); } @@ -3814,7 +3826,6 @@ static void tx_stop(struct slgt_info *info) /* reset and disable transmitter */ val = rd_reg16(info, TCR) & ~BIT1; /* clear enable bit */ wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ - wr_reg16(info, TCR, val); /* clear reset */ slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); @@ -3982,7 +3993,7 @@ static void async_mode(struct slgt_info *info) enable_loopback(info); } -static void hdlc_mode(struct slgt_info *info) +static void sync_mode(struct slgt_info *info) { unsigned short val; @@ -3992,7 +4003,7 @@ static void hdlc_mode(struct slgt_info *info) /* TCR (tx control) * - * 15..13 mode, 000=HDLC 001=raw sync + * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync * 12..10 encoding * 09 CRC enable * 08 CRC32 @@ -4006,8 +4017,11 @@ static void hdlc_mode(struct slgt_info *info) */ val = 0; - if (info->params.mode == MGSL_MODE_RAW) - val |= BIT13; + switch(info->params.mode) { + case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; + case MGSL_MODE_BISYNC: val |= BIT15; break; + case MGSL_MODE_RAW: val |= BIT13; break; + } if (info->if_mode & MGSL_INTERFACE_RTS_EN) val |= BIT7; @@ -4058,7 +4072,7 @@ static void hdlc_mode(struct slgt_info *info) /* RCR (rx control) * - * 15..13 mode, 000=HDLC 001=raw sync + * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync * 12..10 encoding * 09 CRC enable * 08 CRC32 @@ -4069,8 +4083,11 @@ static void hdlc_mode(struct slgt_info *info) */ val = 0; - if (info->params.mode == MGSL_MODE_RAW) - val |= BIT13; + switch(info->params.mode) { + case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; + case MGSL_MODE_BISYNC: val |= BIT15; break; + case MGSL_MODE_RAW: val |= BIT13; break; + } switch(info->params.encoding) { @@ -4309,10 +4326,15 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last while(!done) { /* reset current buffer for reuse */ info->rbufs[i].status = 0; - if (info->params.mode == MGSL_MODE_RAW) + switch(info->params.mode) { + case MGSL_MODE_RAW: + case MGSL_MODE_MONOSYNC: + case MGSL_MODE_BISYNC: set_desc_count(info->rbufs[i], info->raw_rx_size); - else + break; + default: set_desc_count(info->rbufs[i], DMABUFSIZE); + } if (i == last) done = 1; @@ -4477,13 +4499,24 @@ cleanup: static int rx_get_buf(struct slgt_info *info) { unsigned int i = info->rbuf_current; + unsigned int count; if (!desc_complete(info->rbufs[i])) return 0; - DBGDATA(info, info->rbufs[i].buf, desc_count(info->rbufs[i]), "rx"); - DBGINFO(("rx_get_buf size=%d\n", desc_count(info->rbufs[i]))); - ldisc_receive_buf(info->tty, info->rbufs[i].buf, - info->flag_buf, desc_count(info->rbufs[i])); + count = desc_count(info->rbufs[i]); + switch(info->params.mode) { + case MGSL_MODE_MONOSYNC: + case MGSL_MODE_BISYNC: + /* ignore residue in byte synchronous modes */ + if (desc_residue(info->rbufs[i])) + count--; + break; + } + DBGDATA(info, info->rbufs[i].buf, count, "rx"); + DBGINFO(("rx_get_buf size=%d\n", count)); + if (count) + ldisc_receive_buf(info->tty, info->rbufs[i].buf, + info->flag_buf, count); free_rbufs(info, i, i); return 1; } @@ -4549,8 +4582,13 @@ static void tx_load(struct slgt_info *info, const char *buf, unsigned int size) size -= count; buf += count; - if (!size && info->params.mode != MGSL_MODE_RAW) - set_desc_eof(*d, 1); /* HDLC: set EOF of last desc */ + /* + * set EOF bit for last buffer of HDLC frame or + * for every buffer in raw mode + */ + if ((!size && info->params.mode == MGSL_MODE_HDLC) || + info->params.mode == MGSL_MODE_RAW) + set_desc_eof(*d, 1); else set_desc_eof(*d, 0); diff --git a/include/linux/synclink.h b/include/linux/synclink.h index 0577f5284cbc..c8b042667af1 100644 --- a/include/linux/synclink.h +++ b/include/linux/synclink.h @@ -1,7 +1,7 @@ /* * SyncLink Multiprotocol Serial Adapter Driver * - * $Id: synclink.h,v 3.13 2006/05/23 18:25:06 paulkf Exp $ + * $Id: synclink.h,v 3.14 2006/07/17 20:15:43 paulkf Exp $ * * Copyright (C) 1998-2000 by Microgate Corporation * @@ -124,6 +124,8 @@ #define MGSL_MODE_ASYNC 1 #define MGSL_MODE_HDLC 2 +#define MGSL_MODE_MONOSYNC 3 +#define MGSL_MODE_BISYNC 4 #define MGSL_MODE_RAW 6 #define MGSL_BUS_TYPE_ISA 1 -- cgit v1.2.3 From 89bbc03c01f68e627a2b120963f136e2815f0d84 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Sat, 30 Sep 2006 23:27:54 -0700 Subject: [PATCH] Prevent multiple inclusion of linux/sysrq.h Prevent multiple inclusions of include/linux/sysrq.h using traditional #ifndef..#endif. Signed-off-by: Thomas Petazzoni Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sysrq.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index 4812ff60561c..e657e523b9bf 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h @@ -11,6 +11,8 @@ * based upon discusions in irc://irc.openprojects.net/#kernelnewbies */ +#ifndef _LINUX_SYSRQ_H +#define _LINUX_SYSRQ_H struct pt_regs; struct tty_struct; @@ -57,3 +59,5 @@ static inline int __reterr(void) #define unregister_sysrq_key(ig,nore) __reterr() #endif + +#endif /* _LINUX_SYSRQ_H */ -- cgit v1.2.3 From 54f67f631dfc25ca7a8b19200e34013abc974337 Mon Sep 17 00:00:00 2001 From: Petr Vandrovec Date: Sat, 30 Sep 2006 23:27:55 -0700 Subject: [PATCH] Move ncpfs 32bit compat ioctl to ncpfs The ncp specific compat ioctls are clearly local to one file system, so the code can better live there. This version of the patch moves everything into the generic ioctl handler and uses it for both 32 and 64 bit calls. Signed-off-by: Arnd Bergmann Signed-off-by: Petr Vandrovec Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/compat_ioctl.c | 198 ----------------------------------- fs/ncpfs/dir.c | 3 + fs/ncpfs/file.c | 3 + fs/ncpfs/ioctl.c | 239 +++++++++++++++++++++++++++++++++++++------ include/linux/compat_ioctl.h | 12 --- include/linux/ncp_fs.h | 1 + 6 files changed, 217 insertions(+), 239 deletions(-) (limited to 'include/linux') diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 64b34533edea..27ca1aa30562 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -60,7 +60,6 @@ #include #include #include -#include #include #include #include @@ -2348,193 +2347,6 @@ static int rtc_ioctl(unsigned fd, unsigned cmd, unsigned long arg) } } -#if defined(CONFIG_NCP_FS) || defined(CONFIG_NCP_FS_MODULE) -struct ncp_ioctl_request_32 { - u32 function; - u32 size; - compat_caddr_t data; -}; - -struct ncp_fs_info_v2_32 { - s32 version; - u32 mounted_uid; - u32 connection; - u32 buffer_size; - - u32 volume_number; - u32 directory_id; - - u32 dummy1; - u32 dummy2; - u32 dummy3; -}; - -struct ncp_objectname_ioctl_32 -{ - s32 auth_type; - u32 object_name_len; - compat_caddr_t object_name; /* an userspace data, in most cases user name */ -}; - -struct ncp_privatedata_ioctl_32 -{ - u32 len; - compat_caddr_t data; /* ~1000 for NDS */ -}; - -#define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct ncp_ioctl_request_32) -#define NCP_IOC_GETMOUNTUID2_32 _IOW('n', 2, u32) -#define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct ncp_fs_info_v2_32) -#define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct ncp_objectname_ioctl_32) -#define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct ncp_objectname_ioctl_32) -#define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct ncp_privatedata_ioctl_32) -#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct ncp_privatedata_ioctl_32) - -static int do_ncp_ncprequest(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ncp_ioctl_request_32 n32; - struct ncp_ioctl_request __user *p = compat_alloc_user_space(sizeof(*p)); - - if (copy_from_user(&n32, compat_ptr(arg), sizeof(n32)) || - put_user(n32.function, &p->function) || - put_user(n32.size, &p->size) || - put_user(compat_ptr(n32.data), &p->data)) - return -EFAULT; - - return sys_ioctl(fd, NCP_IOC_NCPREQUEST, (unsigned long)p); -} - -static int do_ncp_getmountuid2(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - __kernel_uid_t kuid; - int err; - - cmd = NCP_IOC_GETMOUNTUID2; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&kuid); - set_fs(old_fs); - - if (!err) - err = put_user(kuid, - (unsigned int __user *) compat_ptr(arg)); - - return err; -} - -static int do_ncp_getfsinfo2(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct ncp_fs_info_v2_32 n32; - struct ncp_fs_info_v2 n; - int err; - - if (copy_from_user(&n32, compat_ptr(arg), sizeof(n32))) - return -EFAULT; - if (n32.version != NCP_GET_FS_INFO_VERSION_V2) - return -EINVAL; - n.version = NCP_GET_FS_INFO_VERSION_V2; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, NCP_IOC_GET_FS_INFO_V2, (unsigned long)&n); - set_fs(old_fs); - - if (!err) { - n32.version = n.version; - n32.mounted_uid = n.mounted_uid; - n32.connection = n.connection; - n32.buffer_size = n.buffer_size; - n32.volume_number = n.volume_number; - n32.directory_id = n.directory_id; - n32.dummy1 = n.dummy1; - n32.dummy2 = n.dummy2; - n32.dummy3 = n.dummy3; - err = copy_to_user(compat_ptr(arg), &n32, sizeof(n32)) ? -EFAULT : 0; - } - return err; -} - -static int do_ncp_getobjectname(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ncp_objectname_ioctl_32 n32, __user *p32 = compat_ptr(arg); - struct ncp_objectname_ioctl __user *p = compat_alloc_user_space(sizeof(*p)); - s32 auth_type; - u32 name_len; - int err; - - if (copy_from_user(&n32, p32, sizeof(n32)) || - put_user(n32.object_name_len, &p->object_name_len) || - put_user(compat_ptr(n32.object_name), &p->object_name)) - return -EFAULT; - - err = sys_ioctl(fd, NCP_IOC_GETOBJECTNAME, (unsigned long)p); - if (err) - return err; - - if (get_user(auth_type, &p->auth_type) || - put_user(auth_type, &p32->auth_type) || - get_user(name_len, &p->object_name_len) || - put_user(name_len, &p32->object_name_len)) - return -EFAULT; - - return 0; -} - -static int do_ncp_setobjectname(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ncp_objectname_ioctl_32 n32, __user *p32 = compat_ptr(arg); - struct ncp_objectname_ioctl __user *p = compat_alloc_user_space(sizeof(*p)); - - if (copy_from_user(&n32, p32, sizeof(n32)) || - put_user(n32.auth_type, &p->auth_type) || - put_user(n32.object_name_len, &p->object_name_len) || - put_user(compat_ptr(n32.object_name), &p->object_name)) - return -EFAULT; - - return sys_ioctl(fd, NCP_IOC_SETOBJECTNAME, (unsigned long)p); -} - -static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ncp_privatedata_ioctl_32 n32, __user *p32 = compat_ptr(arg); - struct ncp_privatedata_ioctl __user *p = - compat_alloc_user_space(sizeof(*p)); - u32 len; - int err; - - if (copy_from_user(&n32, p32, sizeof(n32)) || - put_user(n32.len, &p->len) || - put_user(compat_ptr(n32.data), &p->data)) - return -EFAULT; - - err = sys_ioctl(fd, NCP_IOC_GETPRIVATEDATA, (unsigned long)p); - if (err) - return err; - - if (get_user(len, &p->len) || - put_user(len, &p32->len)) - return -EFAULT; - - return 0; -} - -static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ncp_privatedata_ioctl_32 n32; - struct ncp_privatedata_ioctl_32 __user *p32 = compat_ptr(arg); - struct ncp_privatedata_ioctl __user *p = - compat_alloc_user_space(sizeof(*p)); - - if (copy_from_user(&n32, p32, sizeof(n32)) || - put_user(n32.len, &p->len) || - put_user(compat_ptr(n32.data), &p->data)) - return -EFAULT; - - return sys_ioctl(fd, NCP_IOC_SETPRIVATEDATA, (unsigned long)p); -} -#endif - static int lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { @@ -2748,16 +2560,6 @@ HANDLE_IOCTL(RTC_IRQP_SET32, rtc_ioctl) HANDLE_IOCTL(RTC_EPOCH_READ32, rtc_ioctl) HANDLE_IOCTL(RTC_EPOCH_SET32, rtc_ioctl) -#if defined(CONFIG_NCP_FS) || defined(CONFIG_NCP_FS_MODULE) -HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest) -HANDLE_IOCTL(NCP_IOC_GETMOUNTUID2_32, do_ncp_getmountuid2) -HANDLE_IOCTL(NCP_IOC_GET_FS_INFO_V2_32, do_ncp_getfsinfo2) -HANDLE_IOCTL(NCP_IOC_GETOBJECTNAME_32, do_ncp_getobjectname) -HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, do_ncp_setobjectname) -HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata) -HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata) -#endif - /* dvb */ HANDLE_IOCTL(VIDEO_GET_EVENT, do_video_get_event) HANDLE_IOCTL(VIDEO_STILLPICTURE, do_video_stillpicture) diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index b4ee89250e95..458b3b785194 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -53,6 +53,9 @@ const struct file_operations ncp_dir_operations = .read = generic_read_dir, .readdir = ncp_readdir, .ioctl = ncp_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ncp_compat_ioctl, +#endif }; struct inode_operations ncp_dir_inode_operations = diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index e6b7c67cf057..df37524b85db 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -289,6 +289,9 @@ const struct file_operations ncp_file_operations = .read = ncp_file_read, .write = ncp_file_write, .ioctl = ncp_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ncp_compat_ioctl, +#endif .mmap = ncp_mmap, .release = ncp_release, .fsync = ncp_fsync, diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 42039fe0653c..a89ac84a8241 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -7,19 +7,21 @@ * */ - -#include #include +#include #include #include #include #include #include #include +#include #include #include +#include + #include "ncplib_kernel.h" /* maximum limit for ncp_objectname_ioctl */ @@ -89,6 +91,82 @@ ncp_get_fs_info_v2(struct ncp_server * server, struct file *file, return 0; } +#ifdef CONFIG_COMPAT +struct compat_ncp_objectname_ioctl +{ + s32 auth_type; + u32 object_name_len; + compat_caddr_t object_name; /* an userspace data, in most cases user name */ +}; + +struct compat_ncp_fs_info_v2 { + s32 version; + u32 mounted_uid; + u32 connection; + u32 buffer_size; + + u32 volume_number; + u32 directory_id; + + u32 dummy1; + u32 dummy2; + u32 dummy3; +}; + +struct compat_ncp_ioctl_request { + u32 function; + u32 size; + compat_caddr_t data; +}; + +struct compat_ncp_privatedata_ioctl +{ + u32 len; + compat_caddr_t data; /* ~1000 for NDS */ +}; + +#define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct compat_ncp_fs_info_v2) +#define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct compat_ncp_ioctl_request) +#define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct compat_ncp_objectname_ioctl) +#define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct compat_ncp_objectname_ioctl) +#define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct compat_ncp_privatedata_ioctl) +#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl) + +static int +ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file, + struct compat_ncp_fs_info_v2 __user * arg) +{ + struct inode *inode = file->f_dentry->d_inode; + struct compat_ncp_fs_info_v2 info2; + + if ((file_permission(file, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) { + return -EACCES; + } + if (copy_from_user(&info2, arg, sizeof(info2))) + return -EFAULT; + + if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { + DPRINTK("info.version invalid: %d\n", info2.version); + return -EINVAL; + } + info2.mounted_uid = server->m.mounted_uid; + info2.connection = server->connection; + info2.buffer_size = server->buffer_size; + info2.volume_number = NCP_FINFO(inode)->volNumber; + info2.directory_id = NCP_FINFO(inode)->DosDirNum; + info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; + + if (copy_to_user(arg, &info2, sizeof(info2))) + return -EFAULT; + return 0; +} +#endif + +#define NCP_IOC_GETMOUNTUID16 _IOW('n', 2, u16) +#define NCP_IOC_GETMOUNTUID32 _IOW('n', 2, u32) +#define NCP_IOC_GETMOUNTUID64 _IOW('n', 2, u64) + #ifdef CONFIG_NCPFS_NLS /* Here we are select the iocharset and the codepage for NLS. * Thanks Petr Vandrovec for idea and many hints. @@ -192,12 +270,24 @@ int ncp_ioctl(struct inode *inode, struct file *filp, void __user *argp = (void __user *)arg; switch (cmd) { +#ifdef CONFIG_COMPAT + case NCP_IOC_NCPREQUEST_32: +#endif case NCP_IOC_NCPREQUEST: - if ((file_permission(filp, MAY_WRITE) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; } +#ifdef CONFIG_COMPAT + if (cmd == NCP_IOC_NCPREQUEST_32) { + struct compat_ncp_ioctl_request request32; + if (copy_from_user(&request32, argp, sizeof(request32))) + return -EFAULT; + request.function = request32.function; + request.size = request32.size; + request.data = compat_ptr(request32.data); + } else +#endif if (copy_from_user(&request, argp, sizeof(request))) return -EFAULT; @@ -254,19 +344,35 @@ int ncp_ioctl(struct inode *inode, struct file *filp, case NCP_IOC_GET_FS_INFO_V2: return ncp_get_fs_info_v2(server, filp, argp); - case NCP_IOC_GETMOUNTUID2: - { - unsigned long tmp = server->m.mounted_uid; - - if ((file_permission(filp, MAY_READ) != 0) - && (current->uid != server->m.mounted_uid)) - { - return -EACCES; - } - if (put_user(tmp, (unsigned long __user *)argp)) +#ifdef CONFIG_COMPAT + case NCP_IOC_GET_FS_INFO_V2_32: + return ncp_get_compat_fs_info_v2(server, filp, argp); +#endif + /* we have too many combinations of CONFIG_COMPAT, + * CONFIG_64BIT and CONFIG_UID16, so just handle + * any of the possible ioctls */ + case NCP_IOC_GETMOUNTUID16: + case NCP_IOC_GETMOUNTUID32: + case NCP_IOC_GETMOUNTUID64: + if ((file_permission(filp, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) { + return -EACCES; + } + if (cmd == NCP_IOC_GETMOUNTUID16) { + u16 uid; + SET_UID(uid, server->m.mounted_uid); + if (put_user(uid, (u16 __user *)argp)) + return -EFAULT; + } else if (cmd == NCP_IOC_GETMOUNTUID32) { + if (put_user(server->m.mounted_uid, + (u32 __user *)argp)) + return -EFAULT; + } else { + if (put_user(server->m.mounted_uid, + (u64 __user *)argp)) return -EFAULT; - return 0; } + return 0; case NCP_IOC_GETROOT: { @@ -476,6 +582,32 @@ outrel: } #endif /* CONFIG_NCPFS_IOCTL_LOCKING */ +#ifdef CONFIG_COMPAT + case NCP_IOC_GETOBJECTNAME_32: + if (current->uid != server->m.mounted_uid) { + return -EACCES; + } + { + struct compat_ncp_objectname_ioctl user; + size_t outl; + + if (copy_from_user(&user, argp, sizeof(user))) + return -EFAULT; + user.auth_type = server->auth.auth_type; + outl = user.object_name_len; + user.object_name_len = server->auth.object_name_len; + if (outl > user.object_name_len) + outl = user.object_name_len; + if (outl) { + if (copy_to_user(compat_ptr(user.object_name), + server->auth.object_name, + outl)) return -EFAULT; + } + if (copy_to_user(argp, &user, sizeof(user))) + return -EFAULT; + return 0; + } +#endif case NCP_IOC_GETOBJECTNAME: if (current->uid != server->m.mounted_uid) { return -EACCES; @@ -500,6 +632,9 @@ outrel: return -EFAULT; return 0; } +#ifdef CONFIG_COMPAT + case NCP_IOC_SETOBJECTNAME_32: +#endif case NCP_IOC_SETOBJECTNAME: if (current->uid != server->m.mounted_uid) { return -EACCES; @@ -512,8 +647,19 @@ outrel: void* oldprivate; size_t oldprivatelen; +#ifdef CONFIG_COMPAT + if (cmd == NCP_IOC_SETOBJECTNAME_32) { + struct compat_ncp_objectname_ioctl user32; + if (copy_from_user(&user32, argp, sizeof(user32))) + return -EFAULT; + user.auth_type = user32.auth_type; + user.object_name_len = user32.object_name_len; + user.object_name = compat_ptr(user32.object_name); + } else +#endif if (copy_from_user(&user, argp, sizeof(user))) return -EFAULT; + if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN) return -ENOMEM; if (user.object_name_len) { @@ -544,6 +690,9 @@ outrel: kfree(oldname); return 0; } +#ifdef CONFIG_COMPAT + case NCP_IOC_GETPRIVATEDATA_32: +#endif case NCP_IOC_GETPRIVATEDATA: if (current->uid != server->m.mounted_uid) { return -EACCES; @@ -552,8 +701,18 @@ outrel: struct ncp_privatedata_ioctl user; size_t outl; +#ifdef CONFIG_COMPAT + if (cmd == NCP_IOC_GETPRIVATEDATA_32) { + struct compat_ncp_privatedata_ioctl user32; + if (copy_from_user(&user32, argp, sizeof(user32))) + return -EFAULT; + user.len = user32.len; + user.data = compat_ptr(user32.data); + } else +#endif if (copy_from_user(&user, argp, sizeof(user))) return -EFAULT; + outl = user.len; user.len = server->priv.len; if (outl > user.len) outl = user.len; @@ -562,10 +721,23 @@ outrel: server->priv.data, outl)) return -EFAULT; } +#ifdef CONFIG_COMPAT + if (cmd == NCP_IOC_GETPRIVATEDATA_32) { + struct compat_ncp_privatedata_ioctl user32; + user32.len = user.len; + user32.data = (unsigned long) user.data; + if (copy_to_user(&user32, argp, sizeof(user32))) + return -EFAULT; + } else +#endif if (copy_to_user(argp, &user, sizeof(user))) return -EFAULT; + return 0; } +#ifdef CONFIG_COMPAT + case NCP_IOC_SETPRIVATEDATA_32: +#endif case NCP_IOC_SETPRIVATEDATA: if (current->uid != server->m.mounted_uid) { return -EACCES; @@ -576,8 +748,18 @@ outrel: void* old; size_t oldlen; +#ifdef CONFIG_COMPAT + if (cmd == NCP_IOC_SETPRIVATEDATA_32) { + struct compat_ncp_privatedata_ioctl user32; + if (copy_from_user(&user32, argp, sizeof(user32))) + return -EFAULT; + user.len = user32.len; + user.data = compat_ptr(user32.data); + } else +#endif if (copy_from_user(&user, argp, sizeof(user))) return -EFAULT; + if (user.len > NCP_PRIVATE_DATA_MAX_LEN) return -ENOMEM; if (user.len) { @@ -636,20 +818,19 @@ outrel: } } -/* #ifdef CONFIG_UID16 */ - /* NCP_IOC_GETMOUNTUID may be same as NCP_IOC_GETMOUNTUID2, - so we have this out of switch */ - if (cmd == NCP_IOC_GETMOUNTUID) { - __kernel_uid_t uid = 0; - if ((file_permission(filp, MAY_READ) != 0) - && (current->uid != server->m.mounted_uid)) { - return -EACCES; - } - SET_UID(uid, server->m.mounted_uid); - if (put_user(uid, (__kernel_uid_t __user *)argp)) - return -EFAULT; - return 0; - } -/* #endif */ return -EINVAL; } + +#ifdef CONFIG_COMPAT +long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = file->f_dentry->d_inode; + int ret; + + lock_kernel(); + arg = (unsigned long) compat_ptr(arg); + ret = ncp_ioctl(inode, file, cmd, arg); + unlock_kernel(); + return ret; +} +#endif diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index d61ef5951538..d5b7abc4f409 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -569,18 +569,6 @@ COMPATIBLE_IOCTL(RAW_SETBIND) COMPATIBLE_IOCTL(RAW_GETBIND) /* SMB ioctls which do not need any translations */ COMPATIBLE_IOCTL(SMB_IOC_NEWCONN) -/* NCP ioctls which do not need any translations */ -COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN) -COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT) -COMPATIBLE_IOCTL(NCP_IOC_SIGN_WANTED) -COMPATIBLE_IOCTL(NCP_IOC_SET_SIGN_WANTED) -COMPATIBLE_IOCTL(NCP_IOC_LOCKUNLOCK) -COMPATIBLE_IOCTL(NCP_IOC_GETROOT) -COMPATIBLE_IOCTL(NCP_IOC_SETROOT) -COMPATIBLE_IOCTL(NCP_IOC_GETCHARSETS) -COMPATIBLE_IOCTL(NCP_IOC_SETCHARSETS) -COMPATIBLE_IOCTL(NCP_IOC_GETDENTRYTTL) -COMPATIBLE_IOCTL(NCP_IOC_SETDENTRYTTL) /* Little a */ COMPATIBLE_IOCTL(ATMSIGD_CTRL) COMPATIBLE_IOCTL(ATMARPD_CTRL) diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h index 02e352be717e..0ea7f89e613c 100644 --- a/include/linux/ncp_fs.h +++ b/include/linux/ncp_fs.h @@ -212,6 +212,7 @@ void ncp_date_unix2dos(int unix_date, __le16 * time, __le16 * date); /* linux/fs/ncpfs/ioctl.c */ int ncp_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +long ncp_compat_ioctl(struct file *, unsigned int, unsigned long); /* linux/fs/ncpfs/sock.c */ int ncp_request2(struct ncp_server *server, int function, -- cgit v1.2.3 From c69c31270c35a6b8421a8e4ba81de1247ac6df95 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sat, 30 Sep 2006 23:27:56 -0700 Subject: [PATCH] IPMI: per-channel command registration This patch adds the ability to register for a command per-channel in the IPMI driver. If your BMC supports multiple channels, incoming messages can be useful to have the ability to register to receive commands on a specific channel instead the current behaviour of all channels. Signed-off-by: David Barksdale Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/IPMI.txt | 9 +++-- drivers/char/ipmi/ipmi_devintf.c | 34 ++++++++++++++++- drivers/char/ipmi/ipmi_msghandler.c | 75 +++++++++++++++++++++++++++---------- include/linux/ipmi.h | 48 ++++++++++++++++++++++-- 4 files changed, 138 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt index 0256805b548f..7756e09ea759 100644 --- a/Documentation/IPMI.txt +++ b/Documentation/IPMI.txt @@ -326,9 +326,12 @@ for events, they will all receive all events that come in. For receiving commands, you have to individually register commands you want to receive. Call ipmi_register_for_cmd() and supply the netfn -and command name for each command you want to receive. Only one user -may be registered for each netfn/cmd, but different users may register -for different commands. +and command name for each command you want to receive. You also +specify a bitmask of the channels you want to receive the command from +(or use IPMI_CHAN_ALL for all channels if you don't care). Only one +user may be registered for each netfn/cmd/channel, but different users +may register for different commands, or the same command if the +channel bitmasks do not overlap. From userland, equivalent IOCTLs are provided to do these functions. diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 68d7c61a864e..81fcf0ce21d1 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -377,7 +377,8 @@ static int ipmi_ioctl(struct inode *inode, break; } - rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd); + rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd, + IPMI_CHAN_ALL); break; } @@ -390,7 +391,36 @@ static int ipmi_ioctl(struct inode *inode, break; } - rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd); + rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd, + IPMI_CHAN_ALL); + break; + } + + case IPMICTL_REGISTER_FOR_CMD_CHANS: + { + struct ipmi_cmdspec_chans val; + + if (copy_from_user(&val, arg, sizeof(val))) { + rv = -EFAULT; + break; + } + + rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd, + val.chans); + break; + } + + case IPMICTL_UNREGISTER_FOR_CMD_CHANS: + { + struct ipmi_cmdspec_chans val; + + if (copy_from_user(&val, arg, sizeof(val))) { + rv = -EFAULT; + break; + } + + rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd, + val.chans); break; } diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 843d34c8627c..2455e8d478ac 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -96,6 +96,7 @@ struct cmd_rcvr ipmi_user_t user; unsigned char netfn; unsigned char cmd; + unsigned int chans; /* * This is used to form a linked lised during mass deletion. @@ -953,24 +954,41 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf, unsigned char netfn, - unsigned char cmd) + unsigned char cmd, + unsigned char chan) { struct cmd_rcvr *rcvr; list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { - if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) + if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd) + && (rcvr->chans & (1 << chan))) return rcvr; } return NULL; } +static int is_cmd_rcvr_exclusive(ipmi_smi_t intf, + unsigned char netfn, + unsigned char cmd, + unsigned int chans) +{ + struct cmd_rcvr *rcvr; + + list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { + if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd) + && (rcvr->chans & chans)) + return 0; + } + return 1; +} + int ipmi_register_for_cmd(ipmi_user_t user, unsigned char netfn, - unsigned char cmd) + unsigned char cmd, + unsigned int chans) { ipmi_smi_t intf = user->intf; struct cmd_rcvr *rcvr; - struct cmd_rcvr *entry; int rv = 0; @@ -979,12 +997,12 @@ int ipmi_register_for_cmd(ipmi_user_t user, return -ENOMEM; rcvr->cmd = cmd; rcvr->netfn = netfn; + rcvr->chans = chans; rcvr->user = user; mutex_lock(&intf->cmd_rcvrs_mutex); /* Make sure the command/netfn is not already registered. */ - entry = find_cmd_rcvr(intf, netfn, cmd); - if (entry) { + if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) { rv = -EBUSY; goto out_unlock; } @@ -1001,24 +1019,39 @@ int ipmi_register_for_cmd(ipmi_user_t user, int ipmi_unregister_for_cmd(ipmi_user_t user, unsigned char netfn, - unsigned char cmd) + unsigned char cmd, + unsigned int chans) { ipmi_smi_t intf = user->intf; struct cmd_rcvr *rcvr; + struct cmd_rcvr *rcvrs = NULL; + int i, rv = -ENOENT; mutex_lock(&intf->cmd_rcvrs_mutex); - /* Make sure the command/netfn is not already registered. */ - rcvr = find_cmd_rcvr(intf, netfn, cmd); - if ((rcvr) && (rcvr->user == user)) { - list_del_rcu(&rcvr->link); - mutex_unlock(&intf->cmd_rcvrs_mutex); - synchronize_rcu(); + for (i = 0; i < IPMI_NUM_CHANNELS; i++) { + if (((1 << i) & chans) == 0) + continue; + rcvr = find_cmd_rcvr(intf, netfn, cmd, i); + if (rcvr == NULL) + continue; + if (rcvr->user == user) { + rv = 0; + rcvr->chans &= ~chans; + if (rcvr->chans == 0) { + list_del_rcu(&rcvr->link); + rcvr->next = rcvrs; + rcvrs = rcvr; + } + } + } + mutex_unlock(&intf->cmd_rcvrs_mutex); + synchronize_rcu(); + while (rcvrs) { + rcvr = rcvrs; + rcvrs = rcvr->next; kfree(rcvr); - return 0; - } else { - mutex_unlock(&intf->cmd_rcvrs_mutex); - return -ENOENT; } + return rv; } void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) @@ -2548,6 +2581,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, int rv = 0; unsigned char netfn; unsigned char cmd; + unsigned char chan; ipmi_user_t user = NULL; struct ipmi_ipmb_addr *ipmb_addr; struct ipmi_recv_msg *recv_msg; @@ -2568,9 +2602,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, netfn = msg->rsp[4] >> 2; cmd = msg->rsp[8]; + chan = msg->rsp[3] & 0xf; rcu_read_lock(); - rcvr = find_cmd_rcvr(intf, netfn, cmd); + rcvr = find_cmd_rcvr(intf, netfn, cmd, chan); if (rcvr) { user = rcvr->user; kref_get(&user->refcount); @@ -2728,6 +2763,7 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, int rv = 0; unsigned char netfn; unsigned char cmd; + unsigned char chan; ipmi_user_t user = NULL; struct ipmi_lan_addr *lan_addr; struct ipmi_recv_msg *recv_msg; @@ -2748,9 +2784,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, netfn = msg->rsp[6] >> 2; cmd = msg->rsp[10]; + chan = msg->rsp[3] & 0xf; rcu_read_lock(); - rcvr = find_cmd_rcvr(intf, netfn, cmd); + rcvr = find_cmd_rcvr(intf, netfn, cmd, chan); if (rcvr) { user = rcvr->user; kref_get(&user->refcount); diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index d09fbeabf1dc..796ca009fd46 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h @@ -148,6 +148,13 @@ struct ipmi_lan_addr #define IPMI_BMC_CHANNEL 0xf #define IPMI_NUM_CHANNELS 0x10 +/* + * Used to signify an "all channel" bitmask. This is more than the + * actual number of channels because this is used in userland and + * will cover us if the number of channels is extended. + */ +#define IPMI_CHAN_ALL (~0) + /* * A raw IPMI message without any addressing. This covers both @@ -350,18 +357,21 @@ int ipmi_request_supply_msgs(ipmi_user_t user, /* * When commands come in to the SMS, the user can register to receive - * them. Only one user can be listening on a specific netfn/cmd pair + * them. Only one user can be listening on a specific netfn/cmd/chan tuple * at a time, you will get an EBUSY error if the command is already * registered. If a command is received that does not have a user * registered, the driver will automatically return the proper - * error. + * error. Channels are specified as a bitfield, use IPMI_CHAN_ALL to + * mean all channels. */ int ipmi_register_for_cmd(ipmi_user_t user, unsigned char netfn, - unsigned char cmd); + unsigned char cmd, + unsigned int chans); int ipmi_unregister_for_cmd(ipmi_user_t user, unsigned char netfn, - unsigned char cmd); + unsigned char cmd, + unsigned int chans); /* * Allow run-to-completion mode to be set for the interface of @@ -571,6 +581,36 @@ struct ipmi_cmdspec #define IPMICTL_UNREGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 15, \ struct ipmi_cmdspec) +/* + * Register to get commands from other entities on specific channels. + * This way, you can only listen on specific channels, or have messages + * from some channels go to one place and other channels to someplace + * else. The chans field is a bitmask, (1 << channel) for each channel. + * It may be IPMI_CHAN_ALL for all channels. + */ +struct ipmi_cmdspec_chans +{ + unsigned int netfn; + unsigned int cmd; + unsigned int chans; +}; + +/* + * Register to receive a specific command on specific channels. error values: + * - EFAULT - an address supplied was invalid. + * - EBUSY - One of the netfn/cmd/chans supplied was already in use. + * - ENOMEM - could not allocate memory for the entry. + */ +#define IPMICTL_REGISTER_FOR_CMD_CHANS _IOR(IPMI_IOC_MAGIC, 28, \ + struct ipmi_cmdspec_chans) +/* + * Unregister some netfn/cmd/chans. error values: + * - EFAULT - an address supplied was invalid. + * - ENOENT - None of the netfn/cmd/chans were found registered for this user. + */ +#define IPMICTL_UNREGISTER_FOR_CMD_CHANS _IOR(IPMI_IOC_MAGIC, 29, \ + struct ipmi_cmdspec_chans) + /* * Set whether this interface receives events. Note that the first * user registered for events will get all pending events for the -- cgit v1.2.3 From 3a2711116073db258224afd2cc0f478bdf305575 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Sat, 30 Sep 2006 23:28:09 -0700 Subject: [PATCH] Remove BUG_ON(unlikely) in include/linux/aio.h BUG_ON() does this unlikely check itself, as bugs in Linux are unlikely anyway :) Signed-off-by: Rolf Eike Beer Acked-by: Zach Brown Acked-by: Benjamin LaHaise Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/aio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/aio.h b/include/linux/aio.h index 00c8efa95cc3..8a0193385a9b 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -213,11 +213,11 @@ int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, struct iocb *iocb)); #define get_ioctx(kioctx) do { \ - BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0)); \ + BUG_ON(atomic_read(&(kioctx)->users) <= 0); \ atomic_inc(&(kioctx)->users); \ } while (0) #define put_ioctx(kioctx) do { \ - BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0)); \ + BUG_ON(atomic_read(&(kioctx)->users) <= 0); \ if (unlikely(atomic_dec_and_test(&(kioctx)->users))) \ __put_ioctx(kioctx); \ } while (0) -- cgit v1.2.3 From ff8371ac9a5a55c956991fed8e5f58640c7a32f3 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 30 Sep 2006 23:28:17 -0700 Subject: [PATCH] constify rtc_class_ops: update drivers Update RTC framework so that drivers can constify their method tables, moving them from ".data" to ".rodata". Then update the drivers. Signed-off-by: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/class.c | 2 +- drivers/rtc/rtc-at91.c | 2 +- drivers/rtc/rtc-dev.c | 4 ++-- drivers/rtc/rtc-ds1307.c | 2 +- drivers/rtc/rtc-ds1553.c | 2 +- drivers/rtc/rtc-ds1672.c | 2 +- drivers/rtc/rtc-ds1742.c | 2 +- drivers/rtc/rtc-ep93xx.c | 2 +- drivers/rtc/rtc-isl1208.c | 2 +- drivers/rtc/rtc-m48t86.c | 2 +- drivers/rtc/rtc-max6902.c | 2 +- drivers/rtc/rtc-pcf8563.c | 2 +- drivers/rtc/rtc-pcf8583.c | 2 +- drivers/rtc/rtc-pl031.c | 2 +- drivers/rtc/rtc-proc.c | 2 +- drivers/rtc/rtc-rs5c348.c | 2 +- drivers/rtc/rtc-rs5c372.c | 2 +- drivers/rtc/rtc-s3c.c | 2 +- drivers/rtc/rtc-sa1100.c | 2 +- drivers/rtc/rtc-test.c | 2 +- drivers/rtc/rtc-v3020.c | 2 +- drivers/rtc/rtc-vr41xx.c | 2 +- drivers/rtc/rtc-x1205.c | 2 +- include/linux/rtc.h | 4 ++-- 24 files changed, 26 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 306d600a764a..7a0d8ee2de9c 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -39,7 +39,7 @@ static void rtc_device_release(struct class_device *class_dev) * Returns the pointer to the new struct class device. */ struct rtc_device *rtc_device_register(const char *name, struct device *dev, - struct rtc_class_ops *ops, + const struct rtc_class_ops *ops, struct module *owner) { struct rtc_device *rtc; diff --git a/drivers/rtc/rtc-at91.c b/drivers/rtc/rtc-at91.c index dfd0ce86f6a0..3cf3529888c7 100644 --- a/drivers/rtc/rtc-at91.c +++ b/drivers/rtc/rtc-at91.c @@ -267,7 +267,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id, return IRQ_NONE; /* not handled */ } -static struct rtc_class_ops at91_rtc_ops = { +static const struct rtc_class_ops at91_rtc_ops = { .ioctl = at91_rtc_ioctl, .read_time = at91_rtc_readtime, .set_time = at91_rtc_settime, diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 629d47cc7e88..583789c66cdb 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -24,7 +24,7 @@ static int rtc_dev_open(struct inode *inode, struct file *file) int err; struct rtc_device *rtc = container_of(inode->i_cdev, struct rtc_device, char_dev); - struct rtc_class_ops *ops = rtc->ops; + const struct rtc_class_ops *ops = rtc->ops; /* We keep the lock as long as the device is in use * and return immediately if busy @@ -209,7 +209,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, int err = 0; struct class_device *class_dev = file->private_data; struct rtc_device *rtc = to_rtc_device(class_dev); - struct rtc_class_ops *ops = rtc->ops; + const struct rtc_class_ops *ops = rtc->ops; struct rtc_time tm; struct rtc_wkalrm alarm; void __user *uarg = (void __user *) arg; diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index e8afb9384786..cc5032b6f42a 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -178,7 +178,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) return 0; } -static struct rtc_class_ops ds13xx_rtc_ops = { +static const struct rtc_class_ops ds13xx_rtc_ops = { .read_time = ds1307_get_time, .set_time = ds1307_set_time, }; diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 209001495474..4fc9422ed86d 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -250,7 +250,7 @@ static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd, return 0; } -static struct rtc_class_ops ds1553_rtc_ops = { +static const struct rtc_class_ops ds1553_rtc_ops = { .read_time = ds1553_rtc_read_time, .set_time = ds1553_rtc_set_time, .read_alarm = ds1553_rtc_read_alarm, diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 9be81fd4737c..9c68ec99afa5 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -156,7 +156,7 @@ static ssize_t show_control(struct device *dev, struct device_attribute *attr, c } static DEVICE_ATTR(control, S_IRUGO, show_control, NULL); -static struct rtc_class_ops ds1672_rtc_ops = { +static const struct rtc_class_ops ds1672_rtc_ops = { .read_time = ds1672_rtc_read_time, .set_time = ds1672_rtc_set_time, .set_mmss = ds1672_rtc_set_mmss, diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 8e47e5a06d2a..01da5ab15fbc 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -116,7 +116,7 @@ static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm) return 0; } -static struct rtc_class_ops ds1742_rtc_ops = { +static const struct rtc_class_ops ds1742_rtc_ops = { .read_time = ds1742_rtc_read_time, .set_time = ds1742_rtc_set_time, }; diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index e1a1169e4664..ef4f147f3c0c 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -73,7 +73,7 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } -static struct rtc_class_ops ep93xx_rtc_ops = { +static const struct rtc_class_ops ep93xx_rtc_ops = { .read_time = ep93xx_rtc_read_time, .set_time = ep93xx_rtc_set_time, .set_mmss = ep93xx_rtc_set_mmss, diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index f324d0a635d4..1c743641b73b 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -390,7 +390,7 @@ static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm); } -static struct rtc_class_ops isl1208_rtc_ops = { +static const struct rtc_class_ops isl1208_rtc_ops = { .proc = isl1208_rtc_proc, .read_time = isl1208_rtc_read_time, .set_time = isl1208_rtc_set_time, diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 8c0d1a6739ad..8ff4a1221f59 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -138,7 +138,7 @@ static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } -static struct rtc_class_ops m48t86_rtc_ops = { +static const struct rtc_class_ops m48t86_rtc_ops = { .read_time = m48t86_rtc_read_time, .set_time = m48t86_rtc_set_time, .proc = m48t86_rtc_proc, diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 2c9739562b5c..9eeef964663a 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -207,7 +207,7 @@ static int max6902_set_time(struct device *dev, struct rtc_time *tm) return max6902_set_datetime(dev, tm); } -static struct rtc_class_ops max6902_rtc_ops = { +static const struct rtc_class_ops max6902_rtc_ops = { .read_time = max6902_read_time, .set_time = max6902_set_time, }; diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index bd4310643038..a760cf69af90 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -227,7 +227,7 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) return pcf8563_set_datetime(to_i2c_client(dev), tm); } -static struct rtc_class_ops pcf8563_rtc_ops = { +static const struct rtc_class_ops pcf8563_rtc_ops = { .read_time = pcf8563_rtc_read_time, .set_time = pcf8563_rtc_set_time, }; diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index b235a30cb661..5875ebb8c79d 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -273,7 +273,7 @@ static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm) return ret; } -static struct rtc_class_ops pcf8583_rtc_ops = { +static const struct rtc_class_ops pcf8583_rtc_ops = { .read_time = pcf8583_rtc_read_time, .set_time = pcf8583_rtc_set_time, }; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index d6d1c5726b0e..739d1a6e14eb 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -128,7 +128,7 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) return 0; } -static struct rtc_class_ops pl031_ops = { +static const struct rtc_class_ops pl031_ops = { .open = pl031_open, .release = pl031_release, .ioctl = pl031_ioctl, diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index 2943d83edfd1..d51d8f20e634 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -23,7 +23,7 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) { int err; struct class_device *class_dev = seq->private; - struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops; + const struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops; struct rtc_wkalrm alrm; struct rtc_time tm; diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c index 25589061f931..f50f3fc353cd 100644 --- a/drivers/rtc/rtc-rs5c348.c +++ b/drivers/rtc/rtc-rs5c348.c @@ -140,7 +140,7 @@ rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm) return 0; } -static struct rtc_class_ops rs5c348_rtc_ops = { +static const struct rtc_class_ops rs5c348_rtc_ops = { .read_time = rs5c348_rtc_read_time, .set_time = rs5c348_rtc_set_time, }; diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 7553d797603f..bbdad099471d 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -160,7 +160,7 @@ static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } -static struct rtc_class_ops rs5c372_rtc_ops = { +static const struct rtc_class_ops rs5c372_rtc_ops = { .proc = rs5c372_rtc_proc, .read_time = rs5c372_rtc_read_time, .set_time = rs5c372_rtc_set_time, diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 2c7de79c83b9..625dad2eeb4f 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -386,7 +386,7 @@ static void s3c_rtc_release(struct device *dev) free_irq(s3c_rtc_tickno, rtc_dev); } -static struct rtc_class_ops s3c_rtcops = { +static const struct rtc_class_ops s3c_rtcops = { .open = s3c_rtc_open, .release = s3c_rtc_release, .ioctl = s3c_rtc_ioctl, diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index ee4b61ee67b0..439c41aea31c 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -303,7 +303,7 @@ static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } -static struct rtc_class_ops sa1100_rtc_ops = { +static const struct rtc_class_ops sa1100_rtc_ops = { .open = sa1100_rtc_open, .read_callback = sa1100_rtc_read_callback, .release = sa1100_rtc_release, diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index e1fa5fe7901f..bc4bd24508a2 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -75,7 +75,7 @@ static int test_rtc_ioctl(struct device *dev, unsigned int cmd, } } -static struct rtc_class_ops test_rtc_ops = { +static const struct rtc_class_ops test_rtc_ops = { .proc = test_rtc_proc, .read_time = test_rtc_read_time, .set_time = test_rtc_set_time, diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index e28cc4b0901a..09b714f1cdc3 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -149,7 +149,7 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt) return 0; } -static struct rtc_class_ops v3020_rtc_ops = { +static const struct rtc_class_ops v3020_rtc_ops = { .read_time = v3020_read_time, .set_time = v3020_set_time, }; diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 596764fd29f5..58e5ed0aa127 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -296,7 +296,7 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *reg return IRQ_HANDLED; } -static struct rtc_class_ops vr41xx_rtc_ops = { +static const struct rtc_class_ops vr41xx_rtc_ops = { .release = vr41xx_rtc_release, .ioctl = vr41xx_rtc_ioctl, .read_time = vr41xx_rtc_read_time, diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 788b6d1f8f2f..522c69753bbf 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -460,7 +460,7 @@ static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } -static struct rtc_class_ops x1205_rtc_ops = { +static const struct rtc_class_ops x1205_rtc_ops = { .proc = x1205_rtc_proc, .read_time = x1205_rtc_read_time, .set_time = x1205_rtc_set_time, diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 5371e4e74595..b89f09357054 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -141,7 +141,7 @@ struct rtc_device int id; char name[RTC_DEVICE_NAME_SIZE]; - struct rtc_class_ops *ops; + const struct rtc_class_ops *ops; struct mutex ops_lock; struct class_device *rtc_dev; @@ -172,7 +172,7 @@ struct rtc_device extern struct rtc_device *rtc_device_register(const char *name, struct device *dev, - struct rtc_class_ops *ops, + const struct rtc_class_ops *ops, struct module *owner); extern void rtc_device_unregister(struct rtc_device *rdev); extern int rtc_interface_register(struct class_interface *intf); -- cgit v1.2.3 From c902e0a0102f1095eec4b3511c13c84ca2bc4577 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 30 Sep 2006 23:28:21 -0700 Subject: [PATCH] Pass sparse the lock expression given to lock annotations The lock annotation macros __acquires, __releases, __acquire, and __release all currently throw away the lock expression passed as an argument. Now that sparse can parse __context__ and __attribute__((context)) with a context expression, pass the lock expression down to sparse as the context expression. This requires a version of sparse from GIT commit 37475a6c1c3e66219e68d912d5eb833f4098fd72 or later. Signed-off-by: Josh Triplett Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/compiler.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 0780de440220..538423d4a865 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -10,10 +10,10 @@ # define __force __attribute__((force)) # define __nocast __attribute__((nocast)) # define __iomem __attribute__((noderef, address_space(2))) -# define __acquires(x) __attribute__((context(0,1))) -# define __releases(x) __attribute__((context(1,0))) -# define __acquire(x) __context__(1) -# define __release(x) __context__(-1) +# define __acquires(x) __attribute__((context(x,0,1))) +# define __releases(x) __attribute__((context(x,1,0))) +# define __acquire(x) __context__(x,1) +# define __release(x) __context__(x,-1) # define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) extern void __chk_user_ptr(void __user *); extern void __chk_io_ptr(void __iomem *); -- cgit v1.2.3 From 4c7ee8de956fc250fe31e2fa91f6da980fabe317 Mon Sep 17 00:00:00 2001 From: john stultz Date: Sat, 30 Sep 2006 23:28:22 -0700 Subject: [PATCH] NTP: Move all the NTP related code to ntp.c Move all the NTP related code to ntp.c [akpm@osdl.org: cleanups, build fix] Signed-off-by: John Stultz Cc: Ingo Molnar Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/timex.h | 10 +- kernel/time.c | 173 ---------------------- kernel/time/Makefile | 2 +- kernel/time/ntp.c | 389 ++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/timer.c | 211 +-------------------------- 5 files changed, 399 insertions(+), 386 deletions(-) create mode 100644 kernel/time/ntp.c (limited to 'include/linux') diff --git a/include/linux/timex.h b/include/linux/timex.h index d543d3871e38..2a21485bf183 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -294,11 +294,15 @@ extern void register_time_interpolator(struct time_interpolator *); extern void unregister_time_interpolator(struct time_interpolator *); extern void time_interpolator_reset(void); extern unsigned long time_interpolator_get_offset(void); +extern void time_interpolator_update(long delta_nsec); #else /* !CONFIG_TIME_INTERPOLATION */ -static inline void -time_interpolator_reset(void) +static inline void time_interpolator_reset(void) +{ +} + +static inline void time_interpolator_update(long delta_nsec) { } @@ -309,6 +313,8 @@ time_interpolator_reset(void) /* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */ extern u64 current_tick_length(void); +extern void second_overflow(void); +extern void update_ntp_one_tick(void); extern int do_adjtimex(struct timex *); #endif /* KERNEL */ diff --git a/kernel/time.c b/kernel/time.c index 5bd489747643..0e017bff4c19 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -202,179 +202,6 @@ asmlinkage long sys_settimeofday(struct timeval __user *tv, return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL); } -/* we call this to notify the arch when the clock is being - * controlled. If no such arch routine, do nothing. - */ -void __attribute__ ((weak)) notify_arch_cmos_timer(void) -{ - return; -} - -/* adjtimex mainly allows reading (and writing, if superuser) of - * kernel time-keeping variables. used by xntpd. - */ -int do_adjtimex(struct timex *txc) -{ - long ltemp, mtemp, save_adjust; - int result; - - /* In order to modify anything, you gotta be super-user! */ - if (txc->modes && !capable(CAP_SYS_TIME)) - return -EPERM; - - /* Now we validate the data before disabling interrupts */ - - if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) - /* singleshot must not be used with any other mode bits */ - if (txc->modes != ADJ_OFFSET_SINGLESHOT) - return -EINVAL; - - if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET)) - /* adjustment Offset limited to +- .512 seconds */ - if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE ) - return -EINVAL; - - /* if the quartz is off by more than 10% something is VERY wrong ! */ - if (txc->modes & ADJ_TICK) - if (txc->tick < 900000/USER_HZ || - txc->tick > 1100000/USER_HZ) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - result = time_state; /* mostly `TIME_OK' */ - - /* Save for later - semantics of adjtime is to return old value */ - save_adjust = time_next_adjust ? time_next_adjust : time_adjust; - -#if 0 /* STA_CLOCKERR is never set yet */ - time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */ -#endif - /* If there are input parameters, then process them */ - if (txc->modes) - { - if (txc->modes & ADJ_STATUS) /* only set allowed bits */ - time_status = (txc->status & ~STA_RONLY) | - (time_status & STA_RONLY); - - if (txc->modes & ADJ_FREQUENCY) { /* p. 22 */ - if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) { - result = -EINVAL; - goto leave; - } - time_freq = txc->freq; - } - - if (txc->modes & ADJ_MAXERROR) { - if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) { - result = -EINVAL; - goto leave; - } - time_maxerror = txc->maxerror; - } - - if (txc->modes & ADJ_ESTERROR) { - if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) { - result = -EINVAL; - goto leave; - } - time_esterror = txc->esterror; - } - - if (txc->modes & ADJ_TIMECONST) { /* p. 24 */ - if (txc->constant < 0) { /* NTP v4 uses values > 6 */ - result = -EINVAL; - goto leave; - } - time_constant = txc->constant; - } - - if (txc->modes & ADJ_OFFSET) { /* values checked earlier */ - if (txc->modes == ADJ_OFFSET_SINGLESHOT) { - /* adjtime() is independent from ntp_adjtime() */ - if ((time_next_adjust = txc->offset) == 0) - time_adjust = 0; - } - else if (time_status & STA_PLL) { - ltemp = txc->offset; - - /* - * Scale the phase adjustment and - * clamp to the operating range. - */ - if (ltemp > MAXPHASE) - time_offset = MAXPHASE << SHIFT_UPDATE; - else if (ltemp < -MAXPHASE) - time_offset = -(MAXPHASE << SHIFT_UPDATE); - else - time_offset = ltemp << SHIFT_UPDATE; - - /* - * Select whether the frequency is to be controlled - * and in which mode (PLL or FLL). Clamp to the operating - * range. Ugly multiply/divide should be replaced someday. - */ - - if (time_status & STA_FREQHOLD || time_reftime == 0) - time_reftime = xtime.tv_sec; - mtemp = xtime.tv_sec - time_reftime; - time_reftime = xtime.tv_sec; - if (time_status & STA_FLL) { - if (mtemp >= MINSEC) { - ltemp = (time_offset / mtemp) << (SHIFT_USEC - - SHIFT_UPDATE); - time_freq += shift_right(ltemp, SHIFT_KH); - } else /* calibration interval too short (p. 12) */ - result = TIME_ERROR; - } else { /* PLL mode */ - if (mtemp < MAXSEC) { - ltemp *= mtemp; - time_freq += shift_right(ltemp,(time_constant + - time_constant + - SHIFT_KF - SHIFT_USEC)); - } else /* calibration interval too long (p. 12) */ - result = TIME_ERROR; - } - time_freq = min(time_freq, time_tolerance); - time_freq = max(time_freq, -time_tolerance); - } /* STA_PLL */ - } /* txc->modes & ADJ_OFFSET */ - if (txc->modes & ADJ_TICK) { - tick_usec = txc->tick; - tick_nsec = TICK_USEC_TO_NSEC(tick_usec); - } - } /* txc->modes */ -leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) - result = TIME_ERROR; - - if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) - txc->offset = save_adjust; - else { - txc->offset = shift_right(time_offset, SHIFT_UPDATE); - } - txc->freq = time_freq; - txc->maxerror = time_maxerror; - txc->esterror = time_esterror; - txc->status = time_status; - txc->constant = time_constant; - txc->precision = time_precision; - txc->tolerance = time_tolerance; - txc->tick = tick_usec; - - /* PPS is not implemented, so these are zero */ - txc->ppsfreq = 0; - txc->jitter = 0; - txc->shift = 0; - txc->stabil = 0; - txc->jitcnt = 0; - txc->calcnt = 0; - txc->errcnt = 0; - txc->stbcnt = 0; - write_sequnlock_irq(&xtime_lock); - do_gettimeofday(&txc->time); - notify_arch_cmos_timer(); - return(result); -} - asmlinkage long sys_adjtimex(struct timex __user *txc_p) { struct timex txc; /* Local copy of parameter */ diff --git a/kernel/time/Makefile b/kernel/time/Makefile index e1dfd8e86cce..61a3907d16fb 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -1 +1 @@ -obj-y += clocksource.o jiffies.o +obj-y += ntp.o clocksource.o jiffies.o diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c new file mode 100644 index 000000000000..8ccce15b4b23 --- /dev/null +++ b/kernel/time/ntp.c @@ -0,0 +1,389 @@ +/* + * linux/kernel/time/ntp.c + * + * NTP state machine interfaces and logic. + * + * This code was mainly moved from kernel/timer.c and kernel/time.c + * Please see those files for relevant copyright info and historical + * changelogs. + */ + +#include +#include +#include + +#include +#include + +/* Don't completely fail for HZ > 500. */ +int tickadj = 500/HZ ? : 1; /* microsecs */ + +/* + * phase-lock loop variables + */ +/* TIME_ERROR prevents overwriting the CMOS clock */ +int time_state = TIME_OK; /* clock synchronization status */ +int time_status = STA_UNSYNC; /* clock status bits */ +long time_offset; /* time adjustment (us) */ +long time_constant = 2; /* pll time constant */ +long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */ +long time_precision = 1; /* clock precision (us) */ +long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */ +long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */ +long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_USEC; + /* frequency offset (scaled ppm)*/ +static long time_adj; /* tick adjust (scaled 1 / HZ) */ +long time_reftime; /* time at last adjustment (s) */ +long time_adjust; +long time_next_adjust; + +/* + * this routine handles the overflow of the microsecond field + * + * The tricky bits of code to handle the accurate clock support + * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. + * They were originally developed for SUN and DEC kernels. + * All the kudos should go to Dave for this stuff. + */ +void second_overflow(void) +{ + long ltemp; + + /* Bump the maxerror field */ + time_maxerror += time_tolerance >> SHIFT_USEC; + if (time_maxerror > NTP_PHASE_LIMIT) { + time_maxerror = NTP_PHASE_LIMIT; + time_status |= STA_UNSYNC; + } + + /* + * Leap second processing. If in leap-insert state at the end of the + * day, the system clock is set back one second; if in leap-delete + * state, the system clock is set ahead one second. The microtime() + * routine or external clock driver will insure that reported time is + * always monotonic. The ugly divides should be replaced. + */ + switch (time_state) { + case TIME_OK: + if (time_status & STA_INS) + time_state = TIME_INS; + else if (time_status & STA_DEL) + time_state = TIME_DEL; + break; + case TIME_INS: + if (xtime.tv_sec % 86400 == 0) { + xtime.tv_sec--; + wall_to_monotonic.tv_sec++; + /* + * The timer interpolator will make time change + * gradually instead of an immediate jump by one second + */ + time_interpolator_update(-NSEC_PER_SEC); + time_state = TIME_OOP; + clock_was_set(); + printk(KERN_NOTICE "Clock: inserting leap second " + "23:59:60 UTC\n"); + } + break; + case TIME_DEL: + if ((xtime.tv_sec + 1) % 86400 == 0) { + xtime.tv_sec++; + wall_to_monotonic.tv_sec--; + /* + * Use of time interpolator for a gradual change of + * time + */ + time_interpolator_update(NSEC_PER_SEC); + time_state = TIME_WAIT; + clock_was_set(); + printk(KERN_NOTICE "Clock: deleting leap second " + "23:59:59 UTC\n"); + } + break; + case TIME_OOP: + time_state = TIME_WAIT; + break; + case TIME_WAIT: + if (!(time_status & (STA_INS | STA_DEL))) + time_state = TIME_OK; + } + + /* + * Compute the phase adjustment for the next second. In PLL mode, the + * offset is reduced by a fixed factor times the time constant. In FLL + * mode the offset is used directly. In either mode, the maximum phase + * adjustment for each second is clamped so as to spread the adjustment + * over not more than the number of seconds between updates. + */ + ltemp = time_offset; + if (!(time_status & STA_FLL)) + ltemp = shift_right(ltemp, SHIFT_KG + time_constant); + ltemp = min(ltemp, (MAXPHASE / MINSEC) << SHIFT_UPDATE); + ltemp = max(ltemp, -(MAXPHASE / MINSEC) << SHIFT_UPDATE); + time_offset -= ltemp; + time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE); + + /* + * Compute the frequency estimate and additional phase adjustment due + * to frequency error for the next second. + */ + ltemp = time_freq; + time_adj += shift_right(ltemp,(SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE)); + +#if HZ == 100 + /* + * Compensate for (HZ==100) != (1 << SHIFT_HZ). Add 25% and 3.125% to + * get 128.125; => only 0.125% error (p. 14) + */ + time_adj += shift_right(time_adj, 2) + shift_right(time_adj, 5); +#endif +#if HZ == 250 + /* + * Compensate for (HZ==250) != (1 << SHIFT_HZ). Add 1.5625% and + * 0.78125% to get 255.85938; => only 0.05% error (p. 14) + */ + time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7); +#endif +#if HZ == 1000 + /* + * Compensate for (HZ==1000) != (1 << SHIFT_HZ). Add 1.5625% and + * 0.78125% to get 1023.4375; => only 0.05% error (p. 14) + */ + time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7); +#endif +} + +/* + * Returns how many microseconds we need to add to xtime this tick + * in doing an adjustment requested with adjtime. + */ +static long adjtime_adjustment(void) +{ + long time_adjust_step; + + time_adjust_step = time_adjust; + if (time_adjust_step) { + /* + * We are doing an adjtime thing. Prepare time_adjust_step to + * be within bounds. Note that a positive time_adjust means we + * want the clock to run faster. + * + * Limit the amount of the step to be in the range + * -tickadj .. +tickadj + */ + time_adjust_step = min(time_adjust_step, (long)tickadj); + time_adjust_step = max(time_adjust_step, (long)-tickadj); + } + return time_adjust_step; +} + +/* in the NTP reference this is called "hardclock()" */ +void update_ntp_one_tick(void) +{ + long time_adjust_step; + + time_adjust_step = adjtime_adjustment(); + if (time_adjust_step) + /* Reduce by this step the amount of time left */ + time_adjust -= time_adjust_step; + + /* Changes by adjtime() do not take effect till next tick. */ + if (time_next_adjust != 0) { + time_adjust = time_next_adjust; + time_next_adjust = 0; + } +} + +/* + * Return how long ticks are at the moment, that is, how much time + * update_wall_time_one_tick will add to xtime next time we call it + * (assuming no calls to do_adjtimex in the meantime). + * The return value is in fixed-point nanoseconds shifted by the + * specified number of bits to the right of the binary point. + * This function has no side-effects. + */ +u64 current_tick_length(void) +{ + long delta_nsec; + u64 ret; + + /* calculate the finest interval NTP will allow. + * ie: nanosecond value shifted by (SHIFT_SCALE - 10) + */ + delta_nsec = tick_nsec + adjtime_adjustment() * 1000; + ret = (u64)delta_nsec << TICK_LENGTH_SHIFT; + ret += (s64)time_adj << (TICK_LENGTH_SHIFT - (SHIFT_SCALE - 10)); + + return ret; +} + + +void __attribute__ ((weak)) notify_arch_cmos_timer(void) +{ + return; +} + +/* adjtimex mainly allows reading (and writing, if superuser) of + * kernel time-keeping variables. used by xntpd. + */ +int do_adjtimex(struct timex *txc) +{ + long ltemp, mtemp, save_adjust; + int result; + + /* In order to modify anything, you gotta be super-user! */ + if (txc->modes && !capable(CAP_SYS_TIME)) + return -EPERM; + + /* Now we validate the data before disabling interrupts */ + + if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) + /* singleshot must not be used with any other mode bits */ + if (txc->modes != ADJ_OFFSET_SINGLESHOT) + return -EINVAL; + + if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET)) + /* adjustment Offset limited to +- .512 seconds */ + if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE ) + return -EINVAL; + + /* if the quartz is off by more than 10% something is VERY wrong ! */ + if (txc->modes & ADJ_TICK) + if (txc->tick < 900000/USER_HZ || + txc->tick > 1100000/USER_HZ) + return -EINVAL; + + write_seqlock_irq(&xtime_lock); + result = time_state; /* mostly `TIME_OK' */ + + /* Save for later - semantics of adjtime is to return old value */ + save_adjust = time_next_adjust ? time_next_adjust : time_adjust; + +#if 0 /* STA_CLOCKERR is never set yet */ + time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */ +#endif + /* If there are input parameters, then process them */ + if (txc->modes) + { + if (txc->modes & ADJ_STATUS) /* only set allowed bits */ + time_status = (txc->status & ~STA_RONLY) | + (time_status & STA_RONLY); + + if (txc->modes & ADJ_FREQUENCY) { /* p. 22 */ + if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) { + result = -EINVAL; + goto leave; + } + time_freq = txc->freq; + } + + if (txc->modes & ADJ_MAXERROR) { + if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) { + result = -EINVAL; + goto leave; + } + time_maxerror = txc->maxerror; + } + + if (txc->modes & ADJ_ESTERROR) { + if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) { + result = -EINVAL; + goto leave; + } + time_esterror = txc->esterror; + } + + if (txc->modes & ADJ_TIMECONST) { /* p. 24 */ + if (txc->constant < 0) { /* NTP v4 uses values > 6 */ + result = -EINVAL; + goto leave; + } + time_constant = txc->constant; + } + + if (txc->modes & ADJ_OFFSET) { /* values checked earlier */ + if (txc->modes == ADJ_OFFSET_SINGLESHOT) { + /* adjtime() is independent from ntp_adjtime() */ + if ((time_next_adjust = txc->offset) == 0) + time_adjust = 0; + } + else if (time_status & STA_PLL) { + ltemp = txc->offset; + + /* + * Scale the phase adjustment and + * clamp to the operating range. + */ + if (ltemp > MAXPHASE) + time_offset = MAXPHASE << SHIFT_UPDATE; + else if (ltemp < -MAXPHASE) + time_offset = -(MAXPHASE << SHIFT_UPDATE); + else + time_offset = ltemp << SHIFT_UPDATE; + + /* + * Select whether the frequency is to be controlled + * and in which mode (PLL or FLL). Clamp to the operating + * range. Ugly multiply/divide should be replaced someday. + */ + + if (time_status & STA_FREQHOLD || time_reftime == 0) + time_reftime = xtime.tv_sec; + mtemp = xtime.tv_sec - time_reftime; + time_reftime = xtime.tv_sec; + if (time_status & STA_FLL) { + if (mtemp >= MINSEC) { + ltemp = (time_offset / mtemp) << (SHIFT_USEC - + SHIFT_UPDATE); + time_freq += shift_right(ltemp, SHIFT_KH); + } else /* calibration interval too short (p. 12) */ + result = TIME_ERROR; + } else { /* PLL mode */ + if (mtemp < MAXSEC) { + ltemp *= mtemp; + time_freq += shift_right(ltemp,(time_constant + + time_constant + + SHIFT_KF - SHIFT_USEC)); + } else /* calibration interval too long (p. 12) */ + result = TIME_ERROR; + } + time_freq = min(time_freq, time_tolerance); + time_freq = max(time_freq, -time_tolerance); + } /* STA_PLL */ + } /* txc->modes & ADJ_OFFSET */ + if (txc->modes & ADJ_TICK) { + tick_usec = txc->tick; + tick_nsec = TICK_USEC_TO_NSEC(tick_usec); + } + } /* txc->modes */ +leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) + result = TIME_ERROR; + + if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) + txc->offset = save_adjust; + else { + txc->offset = shift_right(time_offset, SHIFT_UPDATE); + } + txc->freq = time_freq; + txc->maxerror = time_maxerror; + txc->esterror = time_esterror; + txc->status = time_status; + txc->constant = time_constant; + txc->precision = time_precision; + txc->tolerance = time_tolerance; + txc->tick = tick_usec; + + /* PPS is not implemented, so these are zero */ + txc->ppsfreq = 0; + txc->jitter = 0; + txc->shift = 0; + txc->stabil = 0; + txc->jitcnt = 0; + txc->calcnt = 0; + txc->errcnt = 0; + txc->stbcnt = 0; + write_sequnlock_irq(&xtime_lock); + do_gettimeofday(&txc->time); + notify_arch_cmos_timer(); + return(result); +} diff --git a/kernel/timer.c b/kernel/timer.c index 4f55622b0d38..5fccc7cbf3b4 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -41,12 +41,6 @@ #include #include -#ifdef CONFIG_TIME_INTERPOLATION -static void time_interpolator_update(long delta_nsec); -#else -#define time_interpolator_update(x) -#endif - u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; EXPORT_SYMBOL(jiffies_64); @@ -587,209 +581,6 @@ struct timespec wall_to_monotonic __attribute__ ((aligned (16))); EXPORT_SYMBOL(xtime); -/* Don't completely fail for HZ > 500. */ -int tickadj = 500/HZ ? : 1; /* microsecs */ - - -/* - * phase-lock loop variables - */ -/* TIME_ERROR prevents overwriting the CMOS clock */ -int time_state = TIME_OK; /* clock synchronization status */ -int time_status = STA_UNSYNC; /* clock status bits */ -long time_offset; /* time adjustment (us) */ -long time_constant = 2; /* pll time constant */ -long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */ -long time_precision = 1; /* clock precision (us) */ -long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */ -long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */ -long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_USEC; - /* frequency offset (scaled ppm)*/ -static long time_adj; /* tick adjust (scaled 1 / HZ) */ -long time_reftime; /* time at last adjustment (s) */ -long time_adjust; -long time_next_adjust; - -/* - * this routine handles the overflow of the microsecond field - * - * The tricky bits of code to handle the accurate clock support - * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. - * They were originally developed for SUN and DEC kernels. - * All the kudos should go to Dave for this stuff. - * - */ -static void second_overflow(void) -{ - long ltemp; - - /* Bump the maxerror field */ - time_maxerror += time_tolerance >> SHIFT_USEC; - if (time_maxerror > NTP_PHASE_LIMIT) { - time_maxerror = NTP_PHASE_LIMIT; - time_status |= STA_UNSYNC; - } - - /* - * Leap second processing. If in leap-insert state at the end of the - * day, the system clock is set back one second; if in leap-delete - * state, the system clock is set ahead one second. The microtime() - * routine or external clock driver will insure that reported time is - * always monotonic. The ugly divides should be replaced. - */ - switch (time_state) { - case TIME_OK: - if (time_status & STA_INS) - time_state = TIME_INS; - else if (time_status & STA_DEL) - time_state = TIME_DEL; - break; - case TIME_INS: - if (xtime.tv_sec % 86400 == 0) { - xtime.tv_sec--; - wall_to_monotonic.tv_sec++; - /* - * The timer interpolator will make time change - * gradually instead of an immediate jump by one second - */ - time_interpolator_update(-NSEC_PER_SEC); - time_state = TIME_OOP; - clock_was_set(); - printk(KERN_NOTICE "Clock: inserting leap second " - "23:59:60 UTC\n"); - } - break; - case TIME_DEL: - if ((xtime.tv_sec + 1) % 86400 == 0) { - xtime.tv_sec++; - wall_to_monotonic.tv_sec--; - /* - * Use of time interpolator for a gradual change of - * time - */ - time_interpolator_update(NSEC_PER_SEC); - time_state = TIME_WAIT; - clock_was_set(); - printk(KERN_NOTICE "Clock: deleting leap second " - "23:59:59 UTC\n"); - } - break; - case TIME_OOP: - time_state = TIME_WAIT; - break; - case TIME_WAIT: - if (!(time_status & (STA_INS | STA_DEL))) - time_state = TIME_OK; - } - - /* - * Compute the phase adjustment for the next second. In PLL mode, the - * offset is reduced by a fixed factor times the time constant. In FLL - * mode the offset is used directly. In either mode, the maximum phase - * adjustment for each second is clamped so as to spread the adjustment - * over not more than the number of seconds between updates. - */ - ltemp = time_offset; - if (!(time_status & STA_FLL)) - ltemp = shift_right(ltemp, SHIFT_KG + time_constant); - ltemp = min(ltemp, (MAXPHASE / MINSEC) << SHIFT_UPDATE); - ltemp = max(ltemp, -(MAXPHASE / MINSEC) << SHIFT_UPDATE); - time_offset -= ltemp; - time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE); - - /* - * Compute the frequency estimate and additional phase adjustment due - * to frequency error for the next second. - */ - ltemp = time_freq; - time_adj += shift_right(ltemp,(SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE)); - -#if HZ == 100 - /* - * Compensate for (HZ==100) != (1 << SHIFT_HZ). Add 25% and 3.125% to - * get 128.125; => only 0.125% error (p. 14) - */ - time_adj += shift_right(time_adj, 2) + shift_right(time_adj, 5); -#endif -#if HZ == 250 - /* - * Compensate for (HZ==250) != (1 << SHIFT_HZ). Add 1.5625% and - * 0.78125% to get 255.85938; => only 0.05% error (p. 14) - */ - time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7); -#endif -#if HZ == 1000 - /* - * Compensate for (HZ==1000) != (1 << SHIFT_HZ). Add 1.5625% and - * 0.78125% to get 1023.4375; => only 0.05% error (p. 14) - */ - time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7); -#endif -} - -/* - * Returns how many microseconds we need to add to xtime this tick - * in doing an adjustment requested with adjtime. - */ -static long adjtime_adjustment(void) -{ - long time_adjust_step; - - time_adjust_step = time_adjust; - if (time_adjust_step) { - /* - * We are doing an adjtime thing. Prepare time_adjust_step to - * be within bounds. Note that a positive time_adjust means we - * want the clock to run faster. - * - * Limit the amount of the step to be in the range - * -tickadj .. +tickadj - */ - time_adjust_step = min(time_adjust_step, (long)tickadj); - time_adjust_step = max(time_adjust_step, (long)-tickadj); - } - return time_adjust_step; -} - -/* in the NTP reference this is called "hardclock()" */ -static void update_ntp_one_tick(void) -{ - long time_adjust_step; - - time_adjust_step = adjtime_adjustment(); - if (time_adjust_step) - /* Reduce by this step the amount of time left */ - time_adjust -= time_adjust_step; - - /* Changes by adjtime() do not take effect till next tick. */ - if (time_next_adjust != 0) { - time_adjust = time_next_adjust; - time_next_adjust = 0; - } -} - -/* - * Return how long ticks are at the moment, that is, how much time - * update_wall_time_one_tick will add to xtime next time we call it - * (assuming no calls to do_adjtimex in the meantime). - * The return value is in fixed-point nanoseconds shifted by the - * specified number of bits to the right of the binary point. - * This function has no side-effects. - */ -u64 current_tick_length(void) -{ - long delta_nsec; - u64 ret; - - /* calculate the finest interval NTP will allow. - * ie: nanosecond value shifted by (SHIFT_SCALE - 10) - */ - delta_nsec = tick_nsec + adjtime_adjustment() * 1000; - ret = (u64)delta_nsec << TICK_LENGTH_SHIFT; - ret += (s64)time_adj << (TICK_LENGTH_SHIFT - (SHIFT_SCALE - 10)); - - return ret; -} /* XXX - all of this timekeeping code should be later moved to time.c */ #include @@ -1775,7 +1566,7 @@ unsigned long time_interpolator_get_offset(void) #define INTERPOLATOR_ADJUST 65536 #define INTERPOLATOR_MAX_SKIP 10*INTERPOLATOR_ADJUST -static void time_interpolator_update(long delta_nsec) +void time_interpolator_update(long delta_nsec) { u64 counter; unsigned long offset; -- cgit v1.2.3 From b0ee75561beadc4db4d9a899c8ef4a7db50aa0ab Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Sat, 30 Sep 2006 23:28:22 -0700 Subject: [PATCH] ntp: add ntp_update_frequency This introduces ntp_update_frequency() and deinlines ntp_clear() (as it's not performance critical). ntp_update_frequency() calculates the base tick length using tick_usec and adds a base adjustment, in case the frequency doesn't divide evenly by HZ. Signed-off-by: Roman Zippel Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/timex.h | 14 ++------------ kernel/time/ntp.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ kernel/timer.c | 11 ++++------- 3 files changed, 50 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timex.h b/include/linux/timex.h index 2a21485bf183..b589c8218bb9 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -219,18 +219,8 @@ extern long time_reftime; /* time at last adjustment (s) */ extern long time_adjust; /* The amount of adjtime left */ extern long time_next_adjust; /* Value for time_adjust at next tick */ -/** - * ntp_clear - Clears the NTP state variables - * - * Must be called while holding a write on the xtime_lock - */ -static inline void ntp_clear(void) -{ - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; -} +extern void ntp_clear(void); +extern void ntp_update_frequency(void); /** * ntp_synced - Returns 1 if the NTP status is not UNSYNC diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 8ccce15b4b23..77137bec2aea 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -15,6 +15,13 @@ #include #include +/* + * Timekeeping variables + */ +unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */ +unsigned long tick_nsec; /* ACTHZ period (nsec) */ +static u64 tick_length, tick_length_base; + /* Don't completely fail for HZ > 500. */ int tickadj = 500/HZ ? : 1; /* microsecs */ @@ -37,6 +44,36 @@ long time_reftime; /* time at last adjustment (s) */ long time_adjust; long time_next_adjust; +/** + * ntp_clear - Clears the NTP state variables + * + * Must be called while holding a write on the xtime_lock + */ +void ntp_clear(void) +{ + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + + ntp_update_frequency(); + + tick_length = tick_length_base; +} + +#define CLOCK_TICK_OVERFLOW (LATCH * HZ - CLOCK_TICK_RATE) +#define CLOCK_TICK_ADJUST (((s64)CLOCK_TICK_OVERFLOW * NSEC_PER_SEC) / (s64)CLOCK_TICK_RATE) + +void ntp_update_frequency(void) +{ + tick_length_base = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << TICK_LENGTH_SHIFT; + tick_length_base += (s64)CLOCK_TICK_ADJUST << TICK_LENGTH_SHIFT; + + do_div(tick_length_base, HZ); + + tick_nsec = tick_length_base >> TICK_LENGTH_SHIFT; +} + /* * this routine handles the overflow of the microsecond field * @@ -151,6 +188,7 @@ void second_overflow(void) */ time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7); #endif + tick_length = tick_length_base; } /* @@ -204,14 +242,13 @@ void update_ntp_one_tick(void) */ u64 current_tick_length(void) { - long delta_nsec; u64 ret; /* calculate the finest interval NTP will allow. * ie: nanosecond value shifted by (SHIFT_SCALE - 10) */ - delta_nsec = tick_nsec + adjtime_adjustment() * 1000; - ret = (u64)delta_nsec << TICK_LENGTH_SHIFT; + ret = tick_length; + ret += (u64)(adjtime_adjustment() * 1000) << TICK_LENGTH_SHIFT; ret += (s64)time_adj << (TICK_LENGTH_SHIFT - (SHIFT_SCALE - 10)); return ret; @@ -351,10 +388,11 @@ int do_adjtimex(struct timex *txc) time_freq = max(time_freq, -time_tolerance); } /* STA_PLL */ } /* txc->modes & ADJ_OFFSET */ - if (txc->modes & ADJ_TICK) { + if (txc->modes & ADJ_TICK) tick_usec = txc->tick; - tick_nsec = TICK_USEC_TO_NSEC(tick_usec); - } + + if (txc->modes & ADJ_TICK) + ntp_update_frequency(); } /* txc->modes */ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) result = TIME_ERROR; diff --git a/kernel/timer.c b/kernel/timer.c index 5fccc7cbf3b4..78d3fa10fcd6 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -562,12 +562,6 @@ found: /******************************************************************/ -/* - * Timekeeping variables - */ -unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */ -unsigned long tick_nsec = TICK_NSEC; /* ACTHZ period (nsec) */ - /* * The current time * wall_to_monotonic is what we need to add to xtime (or xtime corrected @@ -757,10 +751,13 @@ void __init timekeeping_init(void) unsigned long flags; write_seqlock_irqsave(&xtime_lock, flags); + + ntp_clear(); + clock = clocksource_get_next(); clocksource_calculate_interval(clock, tick_nsec); clock->cycle_last = clocksource_read(clock); - ntp_clear(); + write_sequnlock_irqrestore(&xtime_lock, flags); } -- cgit v1.2.3 From 3d3675cc3d04d7fd4bb11e8c1ea79e5ade4f5e44 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Sat, 30 Sep 2006 23:28:25 -0700 Subject: [PATCH] ntp: prescale time_offset This converts time_offset into a scaled per tick value. This avoids now completely the crude compensation in second_overflow(). Signed-off-by: Roman Zippel Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/timex.h | 2 +- kernel/time/ntp.c | 64 +++++++++++++-------------------------------------- 2 files changed, 17 insertions(+), 49 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timex.h b/include/linux/timex.h index b589c8218bb9..1cde6f6a2712 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -89,7 +89,7 @@ * FINENSEC is 1 ns in SHIFT_UPDATE units of the time_phase variable. */ #define SHIFT_SCALE 22 /* phase scale (shift) */ -#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */ +#define SHIFT_UPDATE (SHIFT_HZ + 1) /* time offset scale (shift) */ #define SHIFT_USEC 16 /* frequency offset scale (shift) */ #define FINENSEC (1L << (SHIFT_SCALE - 10)) /* ~1 ns in phase units */ diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index ab21eb06e09b..238ce47ef09d 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -31,7 +31,7 @@ int tickadj = 500/HZ ? : 1; /* microsecs */ /* TIME_ERROR prevents overwriting the CMOS clock */ int time_state = TIME_OK; /* clock synchronization status */ int time_status = STA_UNSYNC; /* clock status bits */ -long time_offset; /* time adjustment (us) */ +long time_offset; /* time adjustment (ns) */ long time_constant = 2; /* pll time constant */ long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */ long time_precision = 1; /* clock precision (us) */ @@ -57,6 +57,7 @@ void ntp_clear(void) ntp_update_frequency(); tick_length = tick_length_base; + time_offset = 0; } #define CLOCK_TICK_OVERFLOW (LATCH * HZ - CLOCK_TICK_RATE) @@ -83,7 +84,7 @@ void ntp_update_frequency(void) */ void second_overflow(void) { - long ltemp, time_adj; + long time_adj; /* Bump the maxerror field */ time_maxerror += time_tolerance >> SHIFT_USEC; @@ -151,42 +152,14 @@ void second_overflow(void) * adjustment for each second is clamped so as to spread the adjustment * over not more than the number of seconds between updates. */ - ltemp = time_offset; - if (!(time_status & STA_FLL)) - ltemp = shift_right(ltemp, SHIFT_KG + time_constant); - ltemp = min(ltemp, (MAXPHASE / MINSEC) << SHIFT_UPDATE); - ltemp = max(ltemp, -(MAXPHASE / MINSEC) << SHIFT_UPDATE); - time_offset -= ltemp; - time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE); - - /* - * Compute the frequency estimate and additional phase adjustment due - * to frequency error for the next second. - */ - -#if HZ == 100 - /* - * Compensate for (HZ==100) != (1 << SHIFT_HZ). Add 25% and 3.125% to - * get 128.125; => only 0.125% error (p. 14) - */ - time_adj += shift_right(time_adj, 2) + shift_right(time_adj, 5); -#endif -#if HZ == 250 - /* - * Compensate for (HZ==250) != (1 << SHIFT_HZ). Add 1.5625% and - * 0.78125% to get 255.85938; => only 0.05% error (p. 14) - */ - time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7); -#endif -#if HZ == 1000 - /* - * Compensate for (HZ==1000) != (1 << SHIFT_HZ). Add 1.5625% and - * 0.78125% to get 1023.4375; => only 0.05% error (p. 14) - */ - time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7); -#endif tick_length = tick_length_base; - tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - (SHIFT_SCALE - 10)); + time_adj = time_offset; + if (!(time_status & STA_FLL)) + time_adj = shift_right(time_adj, SHIFT_KG + time_constant); + time_adj = min(time_adj, -((MAXPHASE / HZ) << SHIFT_UPDATE) / MINSEC); + time_adj = max(time_adj, ((MAXPHASE / HZ) << SHIFT_UPDATE) / MINSEC); + time_offset -= time_adj; + tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE); } /* @@ -347,12 +320,8 @@ int do_adjtimex(struct timex *txc) * Scale the phase adjustment and * clamp to the operating range. */ - if (ltemp > MAXPHASE) - time_offset = MAXPHASE << SHIFT_UPDATE; - else if (ltemp < -MAXPHASE) - time_offset = -(MAXPHASE << SHIFT_UPDATE); - else - time_offset = ltemp << SHIFT_UPDATE; + time_offset = min(ltemp, MAXPHASE); + time_offset = max(time_offset, -MAXPHASE); /* * Select whether the frequency is to be controlled @@ -366,8 +335,7 @@ int do_adjtimex(struct timex *txc) time_reftime = xtime.tv_sec; if (time_status & STA_FLL) { if (mtemp >= MINSEC) { - ltemp = (time_offset / mtemp) << (SHIFT_USEC - - SHIFT_UPDATE); + ltemp = ((time_offset << 12) / mtemp) << (SHIFT_USEC - 12); time_freq += shift_right(ltemp, SHIFT_KH); } else /* calibration interval too short (p. 12) */ result = TIME_ERROR; @@ -382,6 +350,7 @@ int do_adjtimex(struct timex *txc) } time_freq = min(time_freq, time_tolerance); time_freq = max(time_freq, -time_tolerance); + time_offset = (time_offset * NSEC_PER_USEC / HZ) << SHIFT_UPDATE; } /* STA_PLL */ } /* txc->modes & ADJ_OFFSET */ if (txc->modes & ADJ_TICK) @@ -395,9 +364,8 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) txc->offset = save_adjust; - else { - txc->offset = shift_right(time_offset, SHIFT_UPDATE); - } + else + txc->offset = shift_right(time_offset, SHIFT_UPDATE) * HZ / 1000; txc->freq = time_freq; txc->maxerror = time_maxerror; txc->esterror = time_esterror; -- cgit v1.2.3 From 8f807f8d2137ba728d22820103131038639b68a9 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Sat, 30 Sep 2006 23:28:25 -0700 Subject: [PATCH] ntp: add time_adjust to tick length This folds update_ntp_one_tick() into second_overflow() and adds time_adjust to the tick length, this makes time_next_adjust unnecessary. This slightly changes the adjtime() behaviour, instead of applying it to the next tick, it's applied to the next second. Signed-off-by: Roman Zippel Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/timex.h | 1 - kernel/time/ntp.c | 71 +++++++++++++-------------------------------------- kernel/timer.c | 2 -- 3 files changed, 18 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timex.h b/include/linux/timex.h index 1cde6f6a2712..b5f297e17668 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -217,7 +217,6 @@ extern long time_freq; /* frequency offset (scaled ppm) */ extern long time_reftime; /* time at last adjustment (s) */ extern long time_adjust; /* The amount of adjtime left */ -extern long time_next_adjust; /* Value for time_adjust at next tick */ extern void ntp_clear(void); extern void ntp_update_frequency(void); diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 238ce47ef09d..65223b7ed810 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -22,8 +22,9 @@ unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */ unsigned long tick_nsec; /* ACTHZ period (nsec) */ static u64 tick_length, tick_length_base; -/* Don't completely fail for HZ > 500. */ -int tickadj = 500/HZ ? : 1; /* microsecs */ +#define MAX_TICKADJ 500 /* microsecs */ +#define MAX_TICKADJ_SCALED (((u64)(MAX_TICKADJ * NSEC_PER_USEC) << \ + TICK_LENGTH_SHIFT) / HZ) /* * phase-lock loop variables @@ -40,7 +41,6 @@ long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */ long time_freq; /* frequency offset (scaled ppm)*/ long time_reftime; /* time at last adjustment (s) */ long time_adjust; -long time_next_adjust; /** * ntp_clear - Clears the NTP state variables @@ -160,46 +160,19 @@ void second_overflow(void) time_adj = max(time_adj, ((MAXPHASE / HZ) << SHIFT_UPDATE) / MINSEC); time_offset -= time_adj; tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE); -} - -/* - * Returns how many microseconds we need to add to xtime this tick - * in doing an adjustment requested with adjtime. - */ -static long adjtime_adjustment(void) -{ - long time_adjust_step; - - time_adjust_step = time_adjust; - if (time_adjust_step) { - /* - * We are doing an adjtime thing. Prepare time_adjust_step to - * be within bounds. Note that a positive time_adjust means we - * want the clock to run faster. - * - * Limit the amount of the step to be in the range - * -tickadj .. +tickadj - */ - time_adjust_step = min(time_adjust_step, (long)tickadj); - time_adjust_step = max(time_adjust_step, (long)-tickadj); - } - return time_adjust_step; -} -/* in the NTP reference this is called "hardclock()" */ -void update_ntp_one_tick(void) -{ - long time_adjust_step; - - time_adjust_step = adjtime_adjustment(); - if (time_adjust_step) - /* Reduce by this step the amount of time left */ - time_adjust -= time_adjust_step; - - /* Changes by adjtime() do not take effect till next tick. */ - if (time_next_adjust != 0) { - time_adjust = time_next_adjust; - time_next_adjust = 0; + if (unlikely(time_adjust)) { + if (time_adjust > MAX_TICKADJ) { + time_adjust -= MAX_TICKADJ; + tick_length += MAX_TICKADJ_SCALED; + } else if (time_adjust < -MAX_TICKADJ) { + time_adjust += MAX_TICKADJ; + tick_length -= MAX_TICKADJ_SCALED; + } else { + time_adjust = 0; + tick_length += (s64)(time_adjust * NSEC_PER_USEC / + HZ) << TICK_LENGTH_SHIFT; + } } } @@ -213,14 +186,7 @@ void update_ntp_one_tick(void) */ u64 current_tick_length(void) { - u64 ret; - - /* calculate the finest interval NTP will allow. - */ - ret = tick_length; - ret += (u64)(adjtime_adjustment() * 1000) << TICK_LENGTH_SHIFT; - - return ret; + return tick_length; } @@ -263,7 +229,7 @@ int do_adjtimex(struct timex *txc) result = time_state; /* mostly `TIME_OK' */ /* Save for later - semantics of adjtime is to return old value */ - save_adjust = time_next_adjust ? time_next_adjust : time_adjust; + save_adjust = time_adjust; #if 0 /* STA_CLOCKERR is never set yet */ time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */ @@ -310,8 +276,7 @@ int do_adjtimex(struct timex *txc) if (txc->modes & ADJ_OFFSET) { /* values checked earlier */ if (txc->modes == ADJ_OFFSET_SINGLESHOT) { /* adjtime() is independent from ntp_adjtime() */ - if ((time_next_adjust = txc->offset) == 0) - time_adjust = 0; + time_adjust = txc->offset; } else if (time_status & STA_PLL) { ltemp = txc->offset; diff --git a/kernel/timer.c b/kernel/timer.c index 78d3fa10fcd6..654dd5df2417 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -937,8 +937,6 @@ static void update_wall_time(void) /* interpolator bits */ time_interpolator_update(clock->xtime_interval >> clock->shift); - /* increment the NTP state machine */ - update_ntp_one_tick(); /* accumulate error between NTP and clock interval */ clock->error += current_tick_length(); -- cgit v1.2.3 From 97eebe138caaf78354b1fad233e63bafdcc4fd54 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Sat, 30 Sep 2006 23:28:26 -0700 Subject: [PATCH] ntp: remove time_tolerance time_tolerance isn't changed at all in the kernel, so simply remove it, this simplifies the next patch, as it avoids a number of conversions. Signed-off-by: Roman Zippel Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/timex.h | 1 - kernel/time/ntp.c | 9 ++++----- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timex.h b/include/linux/timex.h index b5f297e17668..7715b4c0caf9 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -208,7 +208,6 @@ extern int time_state; /* clock status */ extern int time_status; /* clock synchronization status bits */ extern long time_offset; /* time adjustment (us) */ extern long time_constant; /* pll time constant */ -extern long time_tolerance; /* frequency tolerance (ppm) */ extern long time_precision; /* clock precision (us) */ extern long time_maxerror; /* maximum error */ extern long time_esterror; /* estimated error */ diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 65223b7ed810..af7563f5d4e2 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -34,7 +34,6 @@ int time_state = TIME_OK; /* clock synchronization status */ int time_status = STA_UNSYNC; /* clock status bits */ long time_offset; /* time adjustment (ns) */ long time_constant = 2; /* pll time constant */ -long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */ long time_precision = 1; /* clock precision (us) */ long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */ long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */ @@ -87,7 +86,7 @@ void second_overflow(void) long time_adj; /* Bump the maxerror field */ - time_maxerror += time_tolerance >> SHIFT_USEC; + time_maxerror += MAXFREQ >> SHIFT_USEC; if (time_maxerror > NTP_PHASE_LIMIT) { time_maxerror = NTP_PHASE_LIMIT; time_status |= STA_UNSYNC; @@ -313,8 +312,8 @@ int do_adjtimex(struct timex *txc) } else /* calibration interval too long (p. 12) */ result = TIME_ERROR; } - time_freq = min(time_freq, time_tolerance); - time_freq = max(time_freq, -time_tolerance); + time_freq = min(time_freq, MAXFREQ); + time_freq = max(time_freq, -MAXFREQ); time_offset = (time_offset * NSEC_PER_USEC / HZ) << SHIFT_UPDATE; } /* STA_PLL */ } /* txc->modes & ADJ_OFFSET */ @@ -337,7 +336,7 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) txc->status = time_status; txc->constant = time_constant; txc->precision = time_precision; - txc->tolerance = time_tolerance; + txc->tolerance = MAXFREQ; txc->tick = tick_usec; /* PPS is not implemented, so these are zero */ -- cgit v1.2.3 From 04b617e71e363e640e88be1e43f53fa6a3afef9f Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Sat, 30 Sep 2006 23:28:27 -0700 Subject: [PATCH] ntp: convert time_freq to nsec value This converts time_freq to a scaled nsec value and adds around 6bit of extra resolution. This pushes the time_freq to its 32bit limits so the calculatons have to be done with 64bit. Signed-off-by: Roman Zippel Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/timex.h | 2 ++ kernel/time/ntp.c | 36 ++++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timex.h b/include/linux/timex.h index 7715b4c0caf9..671609ee1a3d 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -91,10 +91,12 @@ #define SHIFT_SCALE 22 /* phase scale (shift) */ #define SHIFT_UPDATE (SHIFT_HZ + 1) /* time offset scale (shift) */ #define SHIFT_USEC 16 /* frequency offset scale (shift) */ +#define SHIFT_NSEC 12 /* kernel frequency offset scale */ #define FINENSEC (1L << (SHIFT_SCALE - 10)) /* ~1 ns in phase units */ #define MAXPHASE 512000L /* max phase error (us) */ #define MAXFREQ (512L << SHIFT_USEC) /* max frequency error (ppm) */ +#define MAXFREQ_NSEC (512000L << SHIFT_NSEC) /* max frequency error (ppb) */ #define MINSEC 16L /* min interval between updates (s) */ #define MAXSEC 1200L /* max interval between updates (s) */ #define NTP_PHASE_LIMIT (MAXPHASE << 5) /* beyond max. dispersion */ diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index af7563f5d4e2..9137b54613e0 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -66,7 +66,7 @@ void ntp_update_frequency(void) { tick_length_base = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << TICK_LENGTH_SHIFT; tick_length_base += (s64)CLOCK_TICK_ADJUST << TICK_LENGTH_SHIFT; - tick_length_base += ((s64)time_freq * NSEC_PER_USEC) << (TICK_LENGTH_SHIFT - SHIFT_USEC); + tick_length_base += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC); do_div(tick_length_base, HZ); @@ -200,6 +200,7 @@ void __attribute__ ((weak)) notify_arch_cmos_timer(void) int do_adjtimex(struct timex *txc) { long ltemp, mtemp, save_adjust; + s64 freq_adj; int result; /* In order to modify anything, you gotta be super-user! */ @@ -245,7 +246,7 @@ int do_adjtimex(struct timex *txc) result = -EINVAL; goto leave; } - time_freq = txc->freq; + time_freq = ((s64)txc->freq * NSEC_PER_USEC) >> (SHIFT_USEC - SHIFT_NSEC); } if (txc->modes & ADJ_MAXERROR) { @@ -278,14 +279,14 @@ int do_adjtimex(struct timex *txc) time_adjust = txc->offset; } else if (time_status & STA_PLL) { - ltemp = txc->offset; + ltemp = txc->offset * NSEC_PER_USEC; /* * Scale the phase adjustment and * clamp to the operating range. */ - time_offset = min(ltemp, MAXPHASE); - time_offset = max(time_offset, -MAXPHASE); + time_offset = min(ltemp, MAXPHASE * NSEC_PER_USEC); + time_offset = max(time_offset, -MAXPHASE * NSEC_PER_USEC); /* * Select whether the frequency is to be controlled @@ -297,24 +298,31 @@ int do_adjtimex(struct timex *txc) time_reftime = xtime.tv_sec; mtemp = xtime.tv_sec - time_reftime; time_reftime = xtime.tv_sec; + freq_adj = 0; if (time_status & STA_FLL) { if (mtemp >= MINSEC) { - ltemp = ((time_offset << 12) / mtemp) << (SHIFT_USEC - 12); - time_freq += shift_right(ltemp, SHIFT_KH); + freq_adj = (s64)time_offset << (SHIFT_NSEC - SHIFT_KH); + if (time_offset < 0) { + freq_adj = -freq_adj; + do_div(freq_adj, mtemp); + freq_adj = -freq_adj; + } else + do_div(freq_adj, mtemp); } else /* calibration interval too short (p. 12) */ result = TIME_ERROR; } else { /* PLL mode */ if (mtemp < MAXSEC) { - ltemp *= mtemp; - time_freq += shift_right(ltemp,(time_constant + + freq_adj = (s64)ltemp * mtemp; + freq_adj = shift_right(freq_adj,(time_constant + time_constant + - SHIFT_KF - SHIFT_USEC)); + SHIFT_KF - SHIFT_NSEC)); } else /* calibration interval too long (p. 12) */ result = TIME_ERROR; } - time_freq = min(time_freq, MAXFREQ); - time_freq = max(time_freq, -MAXFREQ); - time_offset = (time_offset * NSEC_PER_USEC / HZ) << SHIFT_UPDATE; + freq_adj += time_freq; + freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC); + time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC); + time_offset = (time_offset / HZ) << SHIFT_UPDATE; } /* STA_PLL */ } /* txc->modes & ADJ_OFFSET */ if (txc->modes & ADJ_TICK) @@ -330,7 +338,7 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) txc->offset = save_adjust; else txc->offset = shift_right(time_offset, SHIFT_UPDATE) * HZ / 1000; - txc->freq = time_freq; + txc->freq = (time_freq / NSEC_PER_USEC) << (SHIFT_USEC - SHIFT_NSEC); txc->maxerror = time_maxerror; txc->esterror = time_esterror; txc->status = time_status; -- cgit v1.2.3 From f19923937321244e7dc334767eb4b67e0e3d5c74 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Sat, 30 Sep 2006 23:28:28 -0700 Subject: [PATCH] ntp: convert to the NTP4 reference model This converts the kernel ntp model into a model which matches the nanokernel reference implementations. The previous patches already increased the resolution and precision of the computations, so that this conversion becomes quite simple. explains: The original NTP kernel interface was defined in units of microseconds. That's what Linux implements. As computers have gotten faster and can now split microseconds easily, a new kernel interface using nanosecond units was defined ("the nanokernel", confusing as that name is to OS hackers), and there's an STA_NANO bit in the adjtimex() status field to tell the application which units it's using. The current ntpd supports both, but Linux loses some possible timing resolution because of quantization effects, and the ntpd hackers would really like to be able to drop the backwards compatibility code. Ulrich Windl has been maintaining a patch set to do the conversion for years, but it's hard to keep in sync. Signed-off-by: Roman Zippel Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/timex.h | 11 +++++------ kernel/time/ntp.c | 51 +++++++++++++++++++-------------------------------- 2 files changed, 24 insertions(+), 38 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timex.h b/include/linux/timex.h index 671609ee1a3d..ac808f13fa0e 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -69,10 +69,9 @@ * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours, * respectively. */ -#define SHIFT_KG 6 /* phase factor (shift) */ -#define SHIFT_KF 16 /* PLL frequency factor (shift) */ -#define SHIFT_KH 2 /* FLL frequency factor (shift) */ -#define MAXTC 6 /* maximum time constant (shift) */ +#define SHIFT_PLL 4 /* PLL frequency factor (shift) */ +#define SHIFT_FLL 2 /* FLL frequency factor (shift) */ +#define MAXTC 10 /* maximum time constant (shift) */ /* * The SHIFT_SCALE define establishes the decimal point of the time_phase @@ -97,8 +96,8 @@ #define MAXPHASE 512000L /* max phase error (us) */ #define MAXFREQ (512L << SHIFT_USEC) /* max frequency error (ppm) */ #define MAXFREQ_NSEC (512000L << SHIFT_NSEC) /* max frequency error (ppb) */ -#define MINSEC 16L /* min interval between updates (s) */ -#define MAXSEC 1200L /* max interval between updates (s) */ +#define MINSEC 256 /* min interval between updates (s) */ +#define MAXSEC 2048 /* max interval between updates (s) */ #define NTP_PHASE_LIMIT (MAXPHASE << 5) /* beyond max. dispersion */ /* diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 9137b54613e0..1ab5e9d7fa50 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -145,18 +145,11 @@ void second_overflow(void) } /* - * Compute the phase adjustment for the next second. In PLL mode, the - * offset is reduced by a fixed factor times the time constant. In FLL - * mode the offset is used directly. In either mode, the maximum phase - * adjustment for each second is clamped so as to spread the adjustment - * over not more than the number of seconds between updates. + * Compute the phase adjustment for the next second. The offset is + * reduced by a fixed factor times the time constant. */ tick_length = tick_length_base; - time_adj = time_offset; - if (!(time_status & STA_FLL)) - time_adj = shift_right(time_adj, SHIFT_KG + time_constant); - time_adj = min(time_adj, -((MAXPHASE / HZ) << SHIFT_UPDATE) / MINSEC); - time_adj = max(time_adj, ((MAXPHASE / HZ) << SHIFT_UPDATE) / MINSEC); + time_adj = shift_right(time_offset, SHIFT_PLL + time_constant); time_offset -= time_adj; tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE); @@ -200,7 +193,7 @@ void __attribute__ ((weak)) notify_arch_cmos_timer(void) int do_adjtimex(struct timex *txc) { long ltemp, mtemp, save_adjust; - s64 freq_adj; + s64 freq_adj, temp64; int result; /* In order to modify anything, you gotta be super-user! */ @@ -270,7 +263,7 @@ int do_adjtimex(struct timex *txc) result = -EINVAL; goto leave; } - time_constant = txc->constant; + time_constant = min(txc->constant + 4, (long)MAXTC); } if (txc->modes & ADJ_OFFSET) { /* values checked earlier */ @@ -298,26 +291,20 @@ int do_adjtimex(struct timex *txc) time_reftime = xtime.tv_sec; mtemp = xtime.tv_sec - time_reftime; time_reftime = xtime.tv_sec; - freq_adj = 0; - if (time_status & STA_FLL) { - if (mtemp >= MINSEC) { - freq_adj = (s64)time_offset << (SHIFT_NSEC - SHIFT_KH); - if (time_offset < 0) { - freq_adj = -freq_adj; - do_div(freq_adj, mtemp); - freq_adj = -freq_adj; - } else - do_div(freq_adj, mtemp); - } else /* calibration interval too short (p. 12) */ - result = TIME_ERROR; - } else { /* PLL mode */ - if (mtemp < MAXSEC) { - freq_adj = (s64)ltemp * mtemp; - freq_adj = shift_right(freq_adj,(time_constant + - time_constant + - SHIFT_KF - SHIFT_NSEC)); - } else /* calibration interval too long (p. 12) */ - result = TIME_ERROR; + + freq_adj = (s64)time_offset * mtemp; + freq_adj = shift_right(freq_adj, time_constant * 2 + + (SHIFT_PLL + 2) * 2 - SHIFT_NSEC); + if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) { + temp64 = (s64)time_offset << (SHIFT_NSEC - SHIFT_FLL); + if (time_offset < 0) { + temp64 = -temp64; + do_div(temp64, mtemp); + freq_adj -= temp64; + } else { + do_div(temp64, mtemp); + freq_adj += temp64; + } } freq_adj += time_freq; freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC); -- cgit v1.2.3 From 0883d899ef862c1b0f8b2c2d38098470c193a3dd Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Sat, 30 Sep 2006 23:28:29 -0700 Subject: [PATCH] ntp: cleanup defines and comments Remove a few unused defines and remove obsolete information from comments. Signed-off-by: Roman Zippel Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-frv/timex.h | 5 ----- include/asm-m32r/timex.h | 3 --- include/asm-sh64/timex.h | 3 --- include/asm-xtensa/timex.h | 3 --- include/linux/timex.h | 13 +++---------- 5 files changed, 3 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/include/asm-frv/timex.h b/include/asm-frv/timex.h index 2aa562fa067b..a89bddefdacf 100644 --- a/include/asm-frv/timex.h +++ b/include/asm-frv/timex.h @@ -6,11 +6,6 @@ #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ #define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ -#define FINETUNE \ -((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ - (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ - << (SHIFT_SCALE-SHIFT_HZ)) / HZ) - typedef unsigned long cycles_t; static inline cycles_t get_cycles(void) diff --git a/include/asm-m32r/timex.h b/include/asm-m32r/timex.h index e89bfd17db51..019441c1d7a0 100644 --- a/include/asm-m32r/timex.h +++ b/include/asm-m32r/timex.h @@ -12,9 +12,6 @@ #define CLOCK_TICK_RATE (CONFIG_BUS_CLOCK / CONFIG_TIMER_DIVIDE) #define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ -#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ - (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ - << (SHIFT_SCALE-SHIFT_HZ)) / HZ) #ifdef __KERNEL__ /* diff --git a/include/asm-sh64/timex.h b/include/asm-sh64/timex.h index af0b79269661..163e2b62fe27 100644 --- a/include/asm-sh64/timex.h +++ b/include/asm-sh64/timex.h @@ -17,9 +17,6 @@ #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ #define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ -#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ - (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ - << (SHIFT_SCALE-SHIFT_HZ)) / HZ) typedef unsigned long cycles_t; diff --git a/include/asm-xtensa/timex.h b/include/asm-xtensa/timex.h index d14a3755a12b..c7b705e66655 100644 --- a/include/asm-xtensa/timex.h +++ b/include/asm-xtensa/timex.h @@ -31,9 +31,6 @@ #define CLOCK_TICK_RATE 1193180 /* (everyone is using this value) */ #define CLOCK_TICK_FACTOR 20 /* Factor of both 10^6 and CLOCK_TICK_RATE */ -#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ - (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ - << (SHIFT_SCALE-SHIFT_HZ)) / HZ) #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT extern unsigned long ccount_per_jiffy; diff --git a/include/linux/timex.h b/include/linux/timex.h index ac808f13fa0e..261381b5da82 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -74,24 +74,17 @@ #define MAXTC 10 /* maximum time constant (shift) */ /* - * The SHIFT_SCALE define establishes the decimal point of the time_phase - * variable which serves as an extension to the low-order bits of the - * system clock variable. The SHIFT_UPDATE define establishes the decimal - * point of the time_offset variable which represents the current offset - * with respect to standard time. The FINENSEC define represents 1 nsec in - * scaled units. + * The SHIFT_UPDATE define establishes the decimal point of the + * time_offset variable which represents the current offset with + * respect to standard time. * * SHIFT_USEC defines the scaling (shift) of the time_freq and * time_tolerance variables, which represent the current frequency * offset and maximum frequency tolerance. - * - * FINENSEC is 1 ns in SHIFT_UPDATE units of the time_phase variable. */ -#define SHIFT_SCALE 22 /* phase scale (shift) */ #define SHIFT_UPDATE (SHIFT_HZ + 1) /* time offset scale (shift) */ #define SHIFT_USEC 16 /* frequency offset scale (shift) */ #define SHIFT_NSEC 12 /* kernel frequency offset scale */ -#define FINENSEC (1L << (SHIFT_SCALE - 10)) /* ~1 ns in phase units */ #define MAXPHASE 512000L /* max phase error (us) */ #define MAXFREQ (512L << SHIFT_USEC) /* max frequency error (ppm) */ -- cgit v1.2.3 From 70bc42f90a3f4721c89dbe865e6c95da8565b41c Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 30 Sep 2006 23:28:29 -0700 Subject: [PATCH] kernel/time/ntp.c: possible cleanups This patch contains the following possible cleanups: - make the following needlessly global function static: - ntp_update_frequency() - make the following needlessly global variables static: - time_state - time_offset - time_constant - time_reftime - remove the following read-only global variable: - time_precision Signed-off-by: Adrian Bunk Cc: Roman Zippel Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/timex.h | 6 ------ kernel/time/ntp.c | 40 ++++++++++++++++++++-------------------- 2 files changed, 20 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timex.h b/include/linux/timex.h index 261381b5da82..049dfe4a11f2 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -198,21 +198,15 @@ extern int tickadj; /* amount of adjustment per tick */ /* * phase-lock loop variables */ -extern int time_state; /* clock status */ extern int time_status; /* clock synchronization status bits */ -extern long time_offset; /* time adjustment (us) */ -extern long time_constant; /* pll time constant */ -extern long time_precision; /* clock precision (us) */ extern long time_maxerror; /* maximum error */ extern long time_esterror; /* estimated error */ extern long time_freq; /* frequency offset (scaled ppm) */ -extern long time_reftime; /* time at last adjustment (s) */ extern long time_adjust; /* The amount of adjtime left */ extern void ntp_clear(void); -extern void ntp_update_frequency(void); /** * ntp_synced - Returns 1 if the NTP status is not UNSYNC diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 1ab5e9d7fa50..47195fa0ec4f 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -30,17 +30,31 @@ static u64 tick_length, tick_length_base; * phase-lock loop variables */ /* TIME_ERROR prevents overwriting the CMOS clock */ -int time_state = TIME_OK; /* clock synchronization status */ +static int time_state = TIME_OK; /* clock synchronization status */ int time_status = STA_UNSYNC; /* clock status bits */ -long time_offset; /* time adjustment (ns) */ -long time_constant = 2; /* pll time constant */ -long time_precision = 1; /* clock precision (us) */ +static long time_offset; /* time adjustment (ns) */ +static long time_constant = 2; /* pll time constant */ long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */ long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */ long time_freq; /* frequency offset (scaled ppm)*/ -long time_reftime; /* time at last adjustment (s) */ +static long time_reftime; /* time at last adjustment (s) */ long time_adjust; +#define CLOCK_TICK_OVERFLOW (LATCH * HZ - CLOCK_TICK_RATE) +#define CLOCK_TICK_ADJUST (((s64)CLOCK_TICK_OVERFLOW * NSEC_PER_SEC) / \ + (s64)CLOCK_TICK_RATE) + +static void ntp_update_frequency(void) +{ + tick_length_base = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << TICK_LENGTH_SHIFT; + tick_length_base += (s64)CLOCK_TICK_ADJUST << TICK_LENGTH_SHIFT; + tick_length_base += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC); + + do_div(tick_length_base, HZ); + + tick_nsec = tick_length_base >> TICK_LENGTH_SHIFT; +} + /** * ntp_clear - Clears the NTP state variables * @@ -59,20 +73,6 @@ void ntp_clear(void) time_offset = 0; } -#define CLOCK_TICK_OVERFLOW (LATCH * HZ - CLOCK_TICK_RATE) -#define CLOCK_TICK_ADJUST (((s64)CLOCK_TICK_OVERFLOW * NSEC_PER_SEC) / (s64)CLOCK_TICK_RATE) - -void ntp_update_frequency(void) -{ - tick_length_base = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << TICK_LENGTH_SHIFT; - tick_length_base += (s64)CLOCK_TICK_ADJUST << TICK_LENGTH_SHIFT; - tick_length_base += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC); - - do_div(tick_length_base, HZ); - - tick_nsec = tick_length_base >> TICK_LENGTH_SHIFT; -} - /* * this routine handles the overflow of the microsecond field * @@ -330,7 +330,7 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) txc->esterror = time_esterror; txc->status = time_status; txc->constant = time_constant; - txc->precision = time_precision; + txc->precision = 1; txc->tolerance = MAXFREQ; txc->tick = tick_usec; -- cgit v1.2.3 From e1fabd3ccf02901374bffa434e0af472749a5bd9 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Sat, 30 Sep 2006 23:28:40 -0700 Subject: [PATCH] reiserfs: fix is_reusable bitmap check to not traverse the bitmap info array There is a check in is_reusable to determine if a particular block is a bitmap block. It verifies this by going through the array of bitmap block buffer heads and comparing the block number to each one. Bitmap blocks are at defined locations on the disk in both old and current formats. Simply checking against the known good values is enough. This is a trivial optimization for a non-production codepath, but this is the first in a series of patches that will ultimately remove the buffer heads from that array. Signed-off-by: Jeff Mahoney Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/bitmap.c | 40 +++++++++++++++++++++++++--------------- fs/reiserfs/super.c | 2 ++ include/linux/reiserfs_fs_sb.h | 1 + 3 files changed, 28 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index 4a7dbdee1b6d..1022347a211f 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -50,16 +50,15 @@ static inline void get_bit_address(struct super_block *s, { /* It is in the bitmap block number equal to the block * number divided by the number of bits in a block. */ - *bmap_nr = block / (s->s_blocksize << 3); + *bmap_nr = block >> (s->s_blocksize_bits + 3); /* Within that bitmap block it is located at bit offset *offset. */ *offset = block & ((s->s_blocksize << 3) - 1); - return; } #ifdef CONFIG_REISERFS_CHECK int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) { - int i, j; + int bmap, offset; if (block == 0 || block >= SB_BLOCK_COUNT(s)) { reiserfs_warning(s, @@ -68,34 +67,45 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) return 0; } - /* it can't be one of the bitmap blocks */ - for (i = 0; i < SB_BMAP_NR(s); i++) - if (block == SB_AP_BITMAP(s)[i].bh->b_blocknr) { + get_bit_address(s, block, &bmap, &offset); + + /* Old format filesystem? Unlikely, but the bitmaps are all up front so + * we need to account for it. */ + if (unlikely(test_bit(REISERFS_OLD_FORMAT, + &(REISERFS_SB(s)->s_properties)))) { + b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1; + if (block >= bmap1 && block <= bmap1 + SB_BMAP_NR(s)) { + reiserfs_warning(s, "vs: 4019: is_reusable: " + "bitmap block %lu(%u) can't be freed or reused", + block, SB_BMAP_NR(s)); + return 0; + } + } else { + if (offset == 0) { reiserfs_warning(s, "vs: 4020: is_reusable: " "bitmap block %lu(%u) can't be freed or reused", block, SB_BMAP_NR(s)); return 0; } + } - get_bit_address(s, block, &i, &j); - - if (i >= SB_BMAP_NR(s)) { + if (bmap >= SB_BMAP_NR(s)) { reiserfs_warning(s, "vs-4030: is_reusable: there is no so many bitmap blocks: " - "block=%lu, bitmap_nr=%d", block, i); + "block=%lu, bitmap_nr=%d", block, bmap); return 0; } if ((bit_value == 0 && - reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data)) || + reiserfs_test_le_bit(offset, SB_AP_BITMAP(s)[bmap].bh->b_data)) || (bit_value == 1 && - reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data) == 0)) { + reiserfs_test_le_bit(offset, SB_AP_BITMAP(s)[bmap].bh->b_data) == 0)) { reiserfs_warning(s, "vs-4040: is_reusable: corresponding bit of block %lu does not " - "match required value (i==%d, j==%d) test_bit==%d", - block, i, j, reiserfs_test_le_bit(j, + "match required value (bmap==%d, offset==%d) test_bit==%d", + block, bmap, offset, reiserfs_test_le_bit(offset, SB_AP_BITMAP - (s)[i].bh-> + (s)[bmap].bh-> b_data)); return 0; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 80fc3b32802f..db2c581df766 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1818,6 +1818,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) if (is_reiserfs_3_5(rs) || (is_reiserfs_jr(rs) && SB_VERSION(s) == REISERFS_VERSION_1)) set_bit(REISERFS_3_5, &(sbi->s_properties)); + else if (old_format) + set_bit(REISERFS_OLD_FORMAT, &(sbi->s_properties)); else set_bit(REISERFS_3_6, &(sbi->s_properties)); diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h index 31b4c0bd4fa0..4f21ad388c79 100644 --- a/include/linux/reiserfs_fs_sb.h +++ b/include/linux/reiserfs_fs_sb.h @@ -414,6 +414,7 @@ struct reiserfs_sb_info { /* Definitions of reiserfs on-disk properties: */ #define REISERFS_3_5 0 #define REISERFS_3_6 1 +#define REISERFS_OLD_FORMAT 2 enum reiserfs_mount_options { /* Mount options */ -- cgit v1.2.3 From 6f01046b35d940079822827498a7dd6d3eec8c6b Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Sat, 30 Sep 2006 23:28:43 -0700 Subject: [PATCH] reiserfs: reorganize bitmap loading functions This patch moves the bitmap loading code from super.c to bitmap.c The code is also restructured somewhat. The only difference between new format bitmaps and old format bitmaps is where they are. That's a two liner before loading the block to use the correct one. There's no need for an entirely separate code path. The load path is generally the same, with the pattern being to throw out a bunch of requests and then wait for them, then cache the metadata from the contents. Again, like the previous patches, the purpose is to set up for later ones. Update: There was a bug in the previously posted version of this that resulted in corruption. The problem was that bitmap 0 on new format file systems must be treated specially, and wasn't. A stupid bug with an easy fix. This is hopefully the last fix for the disaster that is the reiserfs bitmap patch set. If a bitmap block was full, first_zero_hint would end up at zero since it would never be changed from it's zeroed out value. This just sets it beyond the end of the bitmap block. If any bits are freed, it will be reset to a valid bit. When info->free_count = 0, then we already know it's full. Signed-off-by: Jeff Mahoney Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/bitmap.c | 88 ++++++++++++++++++++++++++++++++++ fs/reiserfs/resize.c | 1 + fs/reiserfs/super.c | 114 +------------------------------------------- include/linux/reiserfs_fs.h | 4 ++ 4 files changed, 94 insertions(+), 113 deletions(-) (limited to 'include/linux') diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index 44d9410e9d6a..abdd6d9c4558 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -1285,3 +1286,90 @@ int reiserfs_can_fit_pages(struct super_block *sb /* superblock of filesystem return space > 0 ? space : 0; } + +void reiserfs_cache_bitmap_metadata(struct super_block *sb, + struct buffer_head *bh, + struct reiserfs_bitmap_info *info) +{ + unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size); + + info->first_zero_hint = 1 << (sb->s_blocksize_bits + 3); + + while (--cur >= (unsigned long *)bh->b_data) { + int base = ((char *)cur - bh->b_data) << 3; + + /* 0 and ~0 are special, we can optimize for them */ + if (*cur == 0) { + info->first_zero_hint = base; + info->free_count += BITS_PER_LONG; + } else if (*cur != ~0L) { /* A mix, investigate */ + int b; + for (b = BITS_PER_LONG - 1; b >= 0; b--) { + if (!reiserfs_test_le_bit(b, cur)) { + info->first_zero_hint = base + b; + info->free_count++; + } + } + } + } + /* The first bit must ALWAYS be 1 */ + BUG_ON(info->first_zero_hint == 0); +} + +struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, + unsigned int bitmap) +{ + b_blocknr_t block = (sb->s_blocksize << 3) * bitmap; + struct buffer_head *bh; + + /* Way old format filesystems had the bitmaps packed up front. + * I doubt there are any of these left, but just in case... */ + if (unlikely(test_bit(REISERFS_OLD_FORMAT, + &(REISERFS_SB(sb)->s_properties)))) + block = REISERFS_SB(sb)->s_sbh->b_blocknr + 1 + bitmap; + else if (bitmap == 0) + block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1; + + bh = sb_getblk(sb, block); + if (!buffer_uptodate(bh)) + ll_rw_block(READ, 1, &bh); + + return bh; +} + +int reiserfs_init_bitmap_cache(struct super_block *sb) +{ + struct reiserfs_bitmap_info *bitmap; + int i; + + bitmap = vmalloc(sizeof (*bitmap) * SB_BMAP_NR(sb)); + if (bitmap == NULL) + return -ENOMEM; + + memset(bitmap, 0, sizeof (*bitmap) * SB_BMAP_NR(sb)); + + for (i = 0; i < SB_BMAP_NR(sb); i++) + bitmap[i].bh = reiserfs_read_bitmap_block(sb, i); + + /* make sure we have them all */ + for (i = 0; i < SB_BMAP_NR(sb); i++) { + wait_on_buffer(bitmap[i].bh); + if (!buffer_uptodate(bitmap[i].bh)) { + reiserfs_warning(sb, "sh-2029: %s: " + "bitmap block (#%lu) reading failed", + __FUNCTION__, bitmap[i].bh->b_blocknr); + for (i = 0; i < SB_BMAP_NR(sb); i++) + brelse(bitmap[i].bh); + vfree(bitmap); + return -EIO; + } + } + + /* Cache the info on the bitmaps before we get rolling */ + for (i = 0; i < SB_BMAP_NR(sb); i++) + reiserfs_cache_bitmap_metadata(sb, bitmap[i].bh, &bitmap[i]); + + SB_AP_BITMAP(sb) = bitmap; + + return 0; +} diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c index 958b75978994..90d39fd3096f 100644 --- a/fs/reiserfs/resize.c +++ b/fs/reiserfs/resize.c @@ -132,6 +132,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) get_bh(bh); memset(bh->b_data, 0, sb_blocksize(sb)); reiserfs_test_and_set_le_bit(0, bh->b_data); + reiserfs_cache_bitmap_metadata(s, bh, bitmap + i); set_buffer_uptodate(bh); mark_buffer_dirty(bh); diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index db2c581df766..c78e99e196fa 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1243,118 +1243,6 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) return 0; } -/* load_bitmap_info_data - Sets up the reiserfs_bitmap_info structure from disk. - * @sb - superblock for this filesystem - * @bi - the bitmap info to be loaded. Requires that bi->bh is valid. - * - * This routine counts how many free bits there are, finding the first zero - * as a side effect. Could also be implemented as a loop of test_bit() calls, or - * a loop of find_first_zero_bit() calls. This implementation is similar to - * find_first_zero_bit(), but doesn't return after it finds the first bit. - * Should only be called on fs mount, but should be fairly efficient anyways. - * - * bi->first_zero_hint is considered unset if it == 0, since the bitmap itself - * will * invariably occupt block 0 represented in the bitmap. The only - * exception to this is when free_count also == 0, since there will be no - * free blocks at all. - */ - -static void load_bitmap_info_data(struct super_block *sb, - struct reiserfs_bitmap_info *bi) -{ - unsigned long *cur = (unsigned long *)bi->bh->b_data; - - while ((char *)cur < (bi->bh->b_data + sb->s_blocksize)) { - - /* No need to scan if all 0's or all 1's. - * Since we're only counting 0's, we can simply ignore all 1's */ - if (*cur == 0) { - if (bi->first_zero_hint == 0) { - bi->first_zero_hint = - ((char *)cur - bi->bh->b_data) << 3; - } - bi->free_count += sizeof(unsigned long) * 8; - } else if (*cur != ~0L) { - int b; - for (b = 0; b < sizeof(unsigned long) * 8; b++) { - if (!reiserfs_test_le_bit(b, cur)) { - bi->free_count++; - if (bi->first_zero_hint == 0) - bi->first_zero_hint = - (((char *)cur - - bi->bh->b_data) << 3) + b; - } - } - } - cur++; - } - -#ifdef CONFIG_REISERFS_CHECK -// This outputs a lot of unneded info on big FSes -// reiserfs_warning ("bitmap loaded from block %d: %d free blocks", -// bi->bh->b_blocknr, bi->free_count); -#endif -} - -static int read_bitmaps(struct super_block *s) -{ - int i, bmap_nr; - - SB_AP_BITMAP(s) = - vmalloc(sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s)); - if (SB_AP_BITMAP(s) == 0) - return 1; - memset(SB_AP_BITMAP(s), 0, - sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s)); - for (i = 0, bmap_nr = - REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize + 1; - i < SB_BMAP_NR(s); i++, bmap_nr = s->s_blocksize * 8 * i) { - SB_AP_BITMAP(s)[i].bh = sb_getblk(s, bmap_nr); - if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) - ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh); - } - for (i = 0; i < SB_BMAP_NR(s); i++) { - wait_on_buffer(SB_AP_BITMAP(s)[i].bh); - if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) { - reiserfs_warning(s, "sh-2029: reiserfs read_bitmaps: " - "bitmap block (#%lu) reading failed", - SB_AP_BITMAP(s)[i].bh->b_blocknr); - for (i = 0; i < SB_BMAP_NR(s); i++) - brelse(SB_AP_BITMAP(s)[i].bh); - vfree(SB_AP_BITMAP(s)); - SB_AP_BITMAP(s) = NULL; - return 1; - } - load_bitmap_info_data(s, SB_AP_BITMAP(s) + i); - } - return 0; -} - -static int read_old_bitmaps(struct super_block *s) -{ - int i; - struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s); - int bmp1 = (REISERFS_OLD_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1; /* first of bitmap blocks */ - - /* read true bitmap */ - SB_AP_BITMAP(s) = - vmalloc(sizeof(struct reiserfs_buffer_info *) * sb_bmap_nr(rs)); - if (SB_AP_BITMAP(s) == 0) - return 1; - - memset(SB_AP_BITMAP(s), 0, - sizeof(struct reiserfs_buffer_info *) * sb_bmap_nr(rs)); - - for (i = 0; i < sb_bmap_nr(rs); i++) { - SB_AP_BITMAP(s)[i].bh = sb_bread(s, bmp1 + i); - if (!SB_AP_BITMAP(s)[i].bh) - return 1; - load_bitmap_info_data(s, SB_AP_BITMAP(s) + i); - } - - return 0; -} - static int read_super_block(struct super_block *s, int offset) { struct buffer_head *bh; @@ -1736,7 +1624,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) sbi->s_mount_state = SB_REISERFS_STATE(s); sbi->s_mount_state = REISERFS_VALID_FS; - if (old_format ? read_old_bitmaps(s) : read_bitmaps(s)) { + if ((errval = reiserfs_init_bitmap_cache(s))) { SWARN(silent, s, "jmacd-8: reiserfs_fill_super: unable to read bitmap"); goto error; diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index 9c63abffd7b2..7bc6bfb86253 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -2073,6 +2073,10 @@ void reiserfs_init_alloc_options(struct super_block *s); */ __le32 reiserfs_choose_packing(struct inode *dir); +int reiserfs_init_bitmap_cache(struct super_block *sb); +void reiserfs_free_bitmap_cache(struct super_block *sb); +void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info); +struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap); int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value); void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *, b_blocknr_t, int for_unformatted); -- cgit v1.2.3 From 5065227b46235ec0131b383cc2f537069b55c6b6 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Sat, 30 Sep 2006 23:28:44 -0700 Subject: [PATCH] reiserfs: on-demand bitmap loading This is the patch the three previous ones have been leading up to. It changes the behavior of ReiserFS from loading and caching all the bitmaps as special, to treating the bitmaps like any other bit of metadata and just letting the system-wide caches figure out what to hang on to. Buffer heads are allocated on the fly, so there is no need to retain pointers to all of them. The caching of the metadata occurs when the data is read and updated, and is considered invalid and uncached until then. I needed to remove the vs-4040 check for performing a duplicate operation on a particular bit. The reason is that while the other sites for working with bitmaps are allowed to schedule, is_reusable() is called from do_balance(), which will panic if a schedule occurs in certain places. The benefit of on-demand bitmaps clearly outweighs a sanity check that depends on a compile-time option that is discouraged. [akpm@osdl.org: warning fix] Signed-off-by: Jeff Mahoney Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/bitmap.c | 97 +++++++++++++++++++----------------------- fs/reiserfs/resize.c | 24 ++++++++--- fs/reiserfs/super.c | 39 ++++------------- include/linux/reiserfs_fs_sb.h | 1 - 4 files changed, 70 insertions(+), 91 deletions(-) (limited to 'include/linux') diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index abdd6d9c4558..cca1dbf5458f 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -60,7 +60,6 @@ static inline void get_bit_address(struct super_block *s, int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) { int bmap, offset; - struct buffer_head *bh; if (block == 0 || block >= SB_BLOCK_COUNT(s)) { reiserfs_warning(s, @@ -98,22 +97,6 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) return 0; } - bh = SB_AP_BITMAP(s)[bmap].bh; - get_bh(bh); - - if ((bit_value == 0 && reiserfs_test_le_bit(offset, bh->b_data)) || - (bit_value == 1 && reiserfs_test_le_bit(offset, bh->b_data) == 0)) { - reiserfs_warning(s, - "vs-4040: is_reusable: corresponding bit of block %lu does not " - "match required value (bmap==%d, offset==%d) test_bit==%d", - block, bmap, offset, - reiserfs_test_le_bit(offset, bh->b_data)); - - brelse(bh); - return 0; - } - brelse(bh); - if (bit_value == 0 && block == SB_ROOT_BLOCK(s)) { reiserfs_warning(s, "vs-4050: is_reusable: this is root block (%u), " @@ -173,13 +156,10 @@ static int scan_bitmap_block(struct reiserfs_transaction_handle *th, bmap_n); return 0; } - bh = bi->bh; - get_bh(bh); - if (buffer_locked(bh)) { - PROC_INFO_INC(s, scan_bitmap.wait); - __wait_on_buffer(bh); - } + bh = reiserfs_read_bitmap_block(s, bmap_n); + if (bh == NULL) + return 0; while (1) { cont: @@ -285,9 +265,20 @@ static int bmap_hash_id(struct super_block *s, u32 id) */ static inline int block_group_used(struct super_block *s, u32 id) { - int bm; - bm = bmap_hash_id(s, id); - if (SB_AP_BITMAP(s)[bm].free_count > ((s->s_blocksize << 3) * 60 / 100)) { + int bm = bmap_hash_id(s, id); + struct reiserfs_bitmap_info *info = &SB_AP_BITMAP(s)[bm]; + + /* If we don't have cached information on this bitmap block, we're + * going to have to load it later anyway. Loading it here allows us + * to make a better decision. This favors long-term performace gain + * with a better on-disk layout vs. a short term gain of skipping the + * read and potentially having a bad placement. */ + if (info->first_zero_hint == 0) { + struct buffer_head *bh = reiserfs_read_bitmap_block(s, bm); + brelse(bh); + } + + if (info->free_count > ((s->s_blocksize << 3) * 60 / 100)) { return 0; } return 1; @@ -413,8 +404,9 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th, return; } - bmbh = apbi[nr].bh; - get_bh(bmbh); + bmbh = reiserfs_read_bitmap_block(s, nr); + if (!bmbh) + return; reiserfs_prepare_for_journal(s, bmbh, 1); @@ -1320,6 +1312,7 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap) { b_blocknr_t block = (sb->s_blocksize << 3) * bitmap; + struct reiserfs_bitmap_info *info = SB_AP_BITMAP(sb) + bitmap; struct buffer_head *bh; /* Way old format filesystems had the bitmaps packed up front. @@ -1330,9 +1323,21 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, else if (bitmap == 0) block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1; - bh = sb_getblk(sb, block); - if (!buffer_uptodate(bh)) - ll_rw_block(READ, 1, &bh); + bh = sb_bread(sb, block); + if (bh == NULL) + reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%lu) " + "reading failed", __FUNCTION__, bh->b_blocknr); + else { + if (buffer_locked(bh)) { + PROC_INFO_INC(sb, scan_bitmap.wait); + __wait_on_buffer(bh); + } + BUG_ON(!buffer_uptodate(bh)); + BUG_ON(atomic_read(&bh->b_count) == 0); + + if (info->first_zero_hint == 0) + reiserfs_cache_bitmap_metadata(sb, bh, info); + } return bh; } @@ -1340,7 +1345,6 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, int reiserfs_init_bitmap_cache(struct super_block *sb) { struct reiserfs_bitmap_info *bitmap; - int i; bitmap = vmalloc(sizeof (*bitmap) * SB_BMAP_NR(sb)); if (bitmap == NULL) @@ -1348,28 +1352,15 @@ int reiserfs_init_bitmap_cache(struct super_block *sb) memset(bitmap, 0, sizeof (*bitmap) * SB_BMAP_NR(sb)); - for (i = 0; i < SB_BMAP_NR(sb); i++) - bitmap[i].bh = reiserfs_read_bitmap_block(sb, i); - - /* make sure we have them all */ - for (i = 0; i < SB_BMAP_NR(sb); i++) { - wait_on_buffer(bitmap[i].bh); - if (!buffer_uptodate(bitmap[i].bh)) { - reiserfs_warning(sb, "sh-2029: %s: " - "bitmap block (#%lu) reading failed", - __FUNCTION__, bitmap[i].bh->b_blocknr); - for (i = 0; i < SB_BMAP_NR(sb); i++) - brelse(bitmap[i].bh); - vfree(bitmap); - return -EIO; - } - } - - /* Cache the info on the bitmaps before we get rolling */ - for (i = 0; i < SB_BMAP_NR(sb); i++) - reiserfs_cache_bitmap_metadata(sb, bitmap[i].bh, &bitmap[i]); - SB_AP_BITMAP(sb) = bitmap; return 0; } + +void reiserfs_free_bitmap_cache(struct super_block *sb) +{ + if (SB_AP_BITMAP(sb)) { + vfree(SB_AP_BITMAP(sb)); + SB_AP_BITMAP(sb) = NULL; + } +} diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c index 90d39fd3096f..315684793d1d 100644 --- a/fs/reiserfs/resize.c +++ b/fs/reiserfs/resize.c @@ -128,8 +128,9 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) * transaction begins, and the new bitmaps don't matter if the * transaction fails. */ for (i = bmap_nr; i < bmap_nr_new; i++) { - bh = sb_getblk(s, i * s->s_blocksize * 8); - get_bh(bh); + /* don't use read_bitmap_block since it will cache + * the uninitialized bitmap */ + bh = sb_bread(s, i * s->s_blocksize * 8); memset(bh->b_data, 0, sb_blocksize(sb)); reiserfs_test_and_set_le_bit(0, bh->b_data); reiserfs_cache_bitmap_metadata(s, bh, bitmap + i); @@ -140,7 +141,6 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) // update bitmap_info stuff bitmap[i].first_zero_hint = 1; bitmap[i].free_count = sb_blocksize(sb) * 8 - 1; - bitmap[i].bh = bh; brelse(bh); } /* free old bitmap blocks array */ @@ -157,8 +157,13 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) /* Extend old last bitmap block - new blocks have been made available */ info = SB_AP_BITMAP(s) + bmap_nr - 1; - bh = info->bh; - get_bh(bh); + bh = reiserfs_read_bitmap_block(s, bmap_nr - 1); + if (!bh) { + int jerr = journal_end(&th, s, 10); + if (jerr) + return jerr; + return -EIO; + } reiserfs_prepare_for_journal(s, bh, 1); for (i = block_r; i < s->s_blocksize * 8; i++) @@ -172,8 +177,13 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) /* Correct new last bitmap block - It may not be full */ info = SB_AP_BITMAP(s) + bmap_nr_new - 1; - bh = info->bh; - get_bh(bh); + bh = reiserfs_read_bitmap_block(s, bmap_nr_new - 1); + if (!bh) { + int jerr = journal_end(&th, s, 10); + if (jerr) + return jerr; + return -EIO; + } reiserfs_prepare_for_journal(s, bh, 1); for (i = block_r_new; i < s->s_blocksize * 8; i++) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index c78e99e196fa..c89aa2338191 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -432,7 +432,6 @@ int remove_save_link(struct inode *inode, int truncate) static void reiserfs_put_super(struct super_block *s) { - int i; struct reiserfs_transaction_handle th; th.t_trans_id = 0; @@ -462,10 +461,7 @@ static void reiserfs_put_super(struct super_block *s) */ journal_release(&th, s); - for (i = 0; i < SB_BMAP_NR(s); i++) - brelse(SB_AP_BITMAP(s)[i].bh); - - vfree(SB_AP_BITMAP(s)); + reiserfs_free_bitmap_cache(s); brelse(SB_BUFFER_WITH_SB(s)); @@ -1344,7 +1340,6 @@ static int read_super_block(struct super_block *s, int offset) /* after journal replay, reread all bitmap and super blocks */ static int reread_meta_blocks(struct super_block *s) { - int i; ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s))); wait_on_buffer(SB_BUFFER_WITH_SB(s)); if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) { @@ -1353,20 +1348,7 @@ static int reread_meta_blocks(struct super_block *s) return 1; } - for (i = 0; i < SB_BMAP_NR(s); i++) { - ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i].bh)); - wait_on_buffer(SB_AP_BITMAP(s)[i].bh); - if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) { - reiserfs_warning(s, - "reread_meta_blocks, error reading bitmap block number %d at %llu", - i, - (unsigned long long)SB_AP_BITMAP(s)[i]. - bh->b_blocknr); - return 1; - } - } return 0; - } ///////////////////////////////////////////////////// @@ -1547,7 +1529,6 @@ static int function2code(hashf_t func) static int reiserfs_fill_super(struct super_block *s, void *data, int silent) { struct inode *root_inode; - int j; struct reiserfs_transaction_handle th; int old_format = 0; unsigned long blocks; @@ -1793,19 +1774,17 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) if (jinit_done) { /* kill the commit thread, free journal ram */ journal_release_error(NULL, s); } - if (SB_DISK_SUPER_BLOCK(s)) { - for (j = 0; j < SB_BMAP_NR(s); j++) { - if (SB_AP_BITMAP(s)) - brelse(SB_AP_BITMAP(s)[j].bh); - } - vfree(SB_AP_BITMAP(s)); - } + + reiserfs_free_bitmap_cache(s); if (SB_BUFFER_WITH_SB(s)) brelse(SB_BUFFER_WITH_SB(s)); #ifdef CONFIG_QUOTA - for (j = 0; j < MAXQUOTAS; j++) { - kfree(sbi->s_qf_names[j]); - sbi->s_qf_names[j] = NULL; + { + int j; + for (j = 0; j < MAXQUOTAS; j++) { + kfree(sbi->s_qf_names[j]); + sbi->s_qf_names[j] = NULL; + } } #endif kfree(sbi); diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h index 4f21ad388c79..73e0becec086 100644 --- a/include/linux/reiserfs_fs_sb.h +++ b/include/linux/reiserfs_fs_sb.h @@ -267,7 +267,6 @@ struct reiserfs_bitmap_info { // FIXME: Won't work with block sizes > 8K __u16 first_zero_hint; __u16 free_count; - struct buffer_head *bh; /* the actual bitmap */ }; struct proc_dir_entry; -- cgit v1.2.3 From 027445c37282bc1ed26add45e573ad2d3e4860a5 Mon Sep 17 00:00:00 2001 From: Badari Pulavarty Date: Sat, 30 Sep 2006 23:28:46 -0700 Subject: [PATCH] Vectorize aio_read/aio_write fileop methods This patch vectorizes aio_read() and aio_write() methods to prepare for collapsing all aio & vectored operations into one interface - which is aio_read()/aio_write(). Signed-off-by: Badari Pulavarty Signed-off-by: Christoph Hellwig Cc: Michael Holzheu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/Locking | 5 +-- Documentation/filesystems/vfs.txt | 4 +- arch/s390/hypfs/inode.c | 17 +++++++-- drivers/char/raw.c | 14 +------ drivers/usb/gadget/inode.c | 80 +++++++++++++++++++++++++++------------ fs/aio.c | 15 ++++++-- fs/block_dev.c | 10 +---- fs/cifs/cifsfs.c | 6 +-- fs/ext3/file.c | 5 ++- fs/nfs/direct.c | 26 ++++++++++--- fs/nfs/file.c | 34 +++++++++-------- fs/ntfs/file.c | 8 ++-- fs/ocfs2/file.c | 28 +++++++------- fs/read_write.c | 20 ++++++++-- fs/reiserfs/file.c | 4 +- fs/xfs/linux-2.6/xfs_file.c | 46 +++++++++++----------- include/linux/aio.h | 2 + include/linux/fs.h | 10 ++--- include/linux/nfs_fs.h | 10 +++-- include/net/sock.h | 1 - mm/filemap.c | 39 +++++++++---------- net/socket.c | 49 +++++++++++------------- 22 files changed, 242 insertions(+), 191 deletions(-) (limited to 'include/linux') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 247d7f619aa2..eb1a6cad21e6 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -356,10 +356,9 @@ The last two are called only from check_disk_change(). prototypes: loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); - ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); - ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, - loff_t); + ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); + ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 1cb7e8be927a..cd07c21b8400 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -699,9 +699,9 @@ This describes how the VFS can manipulate an open file. As of kernel struct file_operations { loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); - ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); - ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t); + ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); + ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 813fc21358f9..cd702ae45d6d 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -134,12 +134,20 @@ static int hypfs_open(struct inode *inode, struct file *filp) return 0; } -static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf, - size_t count, loff_t offset) +static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t offset) { char *data; size_t len; struct file *filp = iocb->ki_filp; + /* XXX: temporary */ + char __user *buf = iov[0].iov_base; + size_t count = iov[0].iov_len; + + if (nr_segs != 1) { + count = -EINVAL; + goto out; + } data = filp->private_data; len = strlen(data); @@ -158,12 +166,13 @@ static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf, out: return count; } -static ssize_t hypfs_aio_write(struct kiocb *iocb, const char __user *buf, - size_t count, loff_t pos) +static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t offset) { int rc; struct super_block *sb; struct hypfs_sb_info *fs_info; + size_t count = iov_length(iov, nr_segs); sb = iocb->ki_filp->f_dentry->d_inode->i_sb; fs_info = sb->s_fs_info; diff --git a/drivers/char/raw.c b/drivers/char/raw.c index c596a08c07b3..173fb08555d5 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -249,23 +249,11 @@ static ssize_t raw_file_write(struct file *file, const char __user *buf, return generic_file_write_nolock(file, &local_iov, 1, ppos); } -static ssize_t raw_file_aio_write(struct kiocb *iocb, const char __user *buf, - size_t count, loff_t pos) -{ - struct iovec local_iov = { - .iov_base = (char __user *)buf, - .iov_len = count - }; - - return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); -} - - static const struct file_operations raw_fops = { .read = generic_file_read, .aio_read = generic_file_aio_read, .write = raw_file_write, - .aio_write = raw_file_aio_write, + .aio_write = generic_file_aio_write_nolock, .open = raw_open, .release= raw_release, .ioctl = raw_ioctl, diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 4a000d846a93..86924f9cdd7e 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -533,7 +533,8 @@ struct kiocb_priv { struct usb_request *req; struct ep_data *epdata; void *buf; - char __user *ubuf; /* NULL for writes */ + const struct iovec *iv; + unsigned long nr_segs; unsigned actual; }; @@ -561,17 +562,32 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) static ssize_t ep_aio_read_retry(struct kiocb *iocb) { struct kiocb_priv *priv = iocb->private; - ssize_t status = priv->actual; - - /* we "retry" to get the right mm context for this: */ - status = copy_to_user(priv->ubuf, priv->buf, priv->actual); - if (unlikely(0 != status)) - status = -EFAULT; - else - status = priv->actual; - kfree(priv->buf); - kfree(priv); - return status; + ssize_t len, total; + int i; + + /* we "retry" to get the right mm context for this: */ + + /* copy stuff into user buffers */ + total = priv->actual; + len = 0; + for (i=0; i < priv->nr_segs; i++) { + ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); + + if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { + if (len == 0) + len = -EFAULT; + break; + } + + total -= this; + len += this; + if (total == 0) + break; + } + kfree(priv->buf); + kfree(priv); + aio_put_req(iocb); + return len; } static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) @@ -584,7 +600,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) spin_lock(&epdata->dev->lock); priv->req = NULL; priv->epdata = NULL; - if (priv->ubuf == NULL + if (priv->iv == NULL || unlikely(req->actual == 0) || unlikely(kiocbIsCancelled(iocb))) { kfree(req->buf); @@ -619,7 +635,8 @@ ep_aio_rwtail( char *buf, size_t len, struct ep_data *epdata, - char __user *ubuf + const struct iovec *iv, + unsigned long nr_segs ) { struct kiocb_priv *priv; @@ -634,7 +651,8 @@ fail: return value; } iocb->private = priv; - priv->ubuf = ubuf; + priv->iv = iv; + priv->nr_segs = nr_segs; value = get_ready_ep(iocb->ki_filp->f_flags, epdata); if (unlikely(value < 0)) { @@ -674,41 +692,53 @@ fail: kfree(priv); put_ep(epdata); } else - value = (ubuf ? -EIOCBRETRY : -EIOCBQUEUED); + value = (iv ? -EIOCBRETRY : -EIOCBQUEUED); return value; } static ssize_t -ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) +ep_aio_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t o) { struct ep_data *epdata = iocb->ki_filp->private_data; char *buf; if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN)) return -EINVAL; - buf = kmalloc(len, GFP_KERNEL); + + buf = kmalloc(iocb->ki_left, GFP_KERNEL); if (unlikely(!buf)) return -ENOMEM; + iocb->ki_retry = ep_aio_read_retry; - return ep_aio_rwtail(iocb, buf, len, epdata, ubuf); + return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs); } static ssize_t -ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) +ep_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t o) { struct ep_data *epdata = iocb->ki_filp->private_data; char *buf; + size_t len = 0; + int i = 0; if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN))) return -EINVAL; - buf = kmalloc(len, GFP_KERNEL); + + buf = kmalloc(iocb->ki_left, GFP_KERNEL); if (unlikely(!buf)) return -ENOMEM; - if (unlikely(copy_from_user(buf, ubuf, len) != 0)) { - kfree(buf); - return -EFAULT; + + for (i=0; i < nr_segs; i++) { + if (unlikely(copy_from_user(&buf[len], iov[i].iov_base, + iov[i].iov_len) != 0)) { + kfree(buf); + return -EFAULT; + } + len += iov[i].iov_len; } - return ep_aio_rwtail(iocb, buf, len, epdata, NULL); + return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0); } /*----------------------------------------------------------------------*/ diff --git a/fs/aio.c b/fs/aio.c index 950630187acc..27ff56540c73 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -15,6 +15,7 @@ #include #include #include +#include #define DEBUG 0 @@ -1315,8 +1316,11 @@ static ssize_t aio_pread(struct kiocb *iocb) ssize_t ret = 0; do { - ret = file->f_op->aio_read(iocb, iocb->ki_buf, - iocb->ki_left, iocb->ki_pos); + iocb->ki_inline_vec.iov_base = iocb->ki_buf; + iocb->ki_inline_vec.iov_len = iocb->ki_left; + + ret = file->f_op->aio_read(iocb, &iocb->ki_inline_vec, + 1, iocb->ki_pos); /* * Can't just depend on iocb->ki_left to determine * whether we are done. This may have been a short read. @@ -1349,8 +1353,11 @@ static ssize_t aio_pwrite(struct kiocb *iocb) ssize_t ret = 0; do { - ret = file->f_op->aio_write(iocb, iocb->ki_buf, - iocb->ki_left, iocb->ki_pos); + iocb->ki_inline_vec.iov_base = iocb->ki_buf; + iocb->ki_inline_vec.iov_len = iocb->ki_left; + + ret = file->f_op->aio_write(iocb, &iocb->ki_inline_vec, + 1, iocb->ki_pos); if (ret > 0) { iocb->ki_buf += ret; iocb->ki_left -= ret; diff --git a/fs/block_dev.c b/fs/block_dev.c index 0c361ea7e5a6..8c819117310b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1162,14 +1162,6 @@ static ssize_t blkdev_file_write(struct file *file, const char __user *buf, return generic_file_write_nolock(file, &local_iov, 1, ppos); } -static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char __user *buf, - size_t count, loff_t pos) -{ - struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count }; - - return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); -} - static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) { return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); @@ -1192,7 +1184,7 @@ const struct file_operations def_blk_fops = { .read = generic_file_read, .write = blkdev_file_write, .aio_read = generic_file_aio_read, - .aio_write = blkdev_file_aio_write, + .aio_write = generic_file_aio_write_nolock, .mmap = generic_file_mmap, .fsync = block_fsync, .unlocked_ioctl = block_ioctl, diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 22bcf4d7e7ae..5abb42a7c53e 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -492,13 +492,13 @@ static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov, return written; } -static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf, - size_t count, loff_t pos) +static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct inode *inode = iocb->ki_filp->f_dentry->d_inode; ssize_t written; - written = generic_file_aio_write(iocb, buf, count, pos); + written = generic_file_aio_write(iocb, iov, nr_segs, pos); if (!CIFS_I(inode)->clientCanCacheAll) filemap_fdatawrite(inode->i_mapping); return written; diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 74ff20f9d09b..5c762457bc89 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -48,14 +48,15 @@ static int ext3_release_file (struct inode * inode, struct file * filp) } static ssize_t -ext3_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) +ext3_file_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_dentry->d_inode; ssize_t ret; int err; - ret = generic_file_aio_write(iocb, buf, count, pos); + ret = generic_file_aio_write(iocb, iov, nr_segs, pos); /* * Skip flushing if there was an error, or if nothing was written. diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 377839bed172..9f7f8b9ea1e2 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -707,8 +707,8 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz /** * nfs_file_direct_read - file direct read operation for NFS files * @iocb: target I/O control block - * @buf: user's buffer into which to read data - * @count: number of bytes to read + * @iov: vector of user buffers into which to read data + * @nr_segs: size of iov vector * @pos: byte offset in file where reading starts * * We use this function for direct reads instead of calling @@ -725,17 +725,24 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz * client must read the updated atime from the server back into its * cache. */ -ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) +ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { ssize_t retval = -EINVAL; struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; + /* XXX: temporary */ + const char __user *buf = iov[0].iov_base; + size_t count = iov[0].iov_len; dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n", file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name, (unsigned long) count, (long long) pos); + if (nr_segs != 1) + return -EINVAL; + if (count < 0) goto out; retval = -EFAULT; @@ -760,8 +767,8 @@ out: /** * nfs_file_direct_write - file direct write operation for NFS files * @iocb: target I/O control block - * @buf: user's buffer from which to write data - * @count: number of bytes to write + * @iov: vector of user buffers from which to write data + * @nr_segs: size of iov vector * @pos: byte offset in file where writing starts * * We use this function for direct writes instead of calling @@ -782,17 +789,24 @@ out: * Note that O_APPEND is not supported for NFS direct writes, as there * is no atomic O_APPEND write facility in the NFS protocol. */ -ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) +ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { ssize_t retval; struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; + /* XXX: temporary */ + const char __user *buf = iov[0].iov_base; + size_t count = iov[0].iov_len; dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name, (unsigned long) count, (long long) pos); + if (nr_segs != 1) + return -EINVAL; + retval = generic_write_checks(file, &pos, &count, 0); if (retval) goto out; diff --git a/fs/nfs/file.c b/fs/nfs/file.c index be997d649127..cc93865cea93 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -41,8 +41,10 @@ static int nfs_file_release(struct inode *, struct file *); static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin); static int nfs_file_mmap(struct file *, struct vm_area_struct *); static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *); -static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t); -static ssize_t nfs_file_write(struct kiocb *, const char __user *, size_t, loff_t); +static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, + unsigned long nr_segs, loff_t pos); +static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, + unsigned long nr_segs, loff_t pos); static int nfs_file_flush(struct file *, fl_owner_t id); static int nfs_fsync(struct file *, struct dentry *dentry, int datasync); static int nfs_check_flags(int flags); @@ -53,8 +55,8 @@ const struct file_operations nfs_file_operations = { .llseek = nfs_file_llseek, .read = do_sync_read, .write = do_sync_write, - .aio_read = nfs_file_read, - .aio_write = nfs_file_write, + .aio_read = nfs_file_read, + .aio_write = nfs_file_write, .mmap = nfs_file_mmap, .open = nfs_file_open, .flush = nfs_file_flush, @@ -196,15 +198,17 @@ nfs_file_flush(struct file *file, fl_owner_t id) } static ssize_t -nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos) +nfs_file_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct dentry * dentry = iocb->ki_filp->f_dentry; struct inode * inode = dentry->d_inode; ssize_t result; + size_t count = iov_length(iov, nr_segs); #ifdef CONFIG_NFS_DIRECTIO if (iocb->ki_filp->f_flags & O_DIRECT) - return nfs_file_direct_read(iocb, buf, count, pos); + return nfs_file_direct_read(iocb, iov, nr_segs, pos); #endif dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", @@ -214,7 +218,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos) result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count); if (!result) - result = generic_file_aio_read(iocb, buf, count, pos); + result = generic_file_aio_read(iocb, iov, nr_segs, pos); return result; } @@ -336,24 +340,22 @@ const struct address_space_operations nfs_file_aops = { #endif }; -/* - * Write to a file (through the page cache). - */ -static ssize_t -nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) +static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct dentry * dentry = iocb->ki_filp->f_dentry; struct inode * inode = dentry->d_inode; ssize_t result; + size_t count = iov_length(iov, nr_segs); #ifdef CONFIG_NFS_DIRECTIO if (iocb->ki_filp->f_flags & O_DIRECT) - return nfs_file_direct_write(iocb, buf, count, pos); + return nfs_file_direct_write(iocb, iov, nr_segs, pos); #endif - dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%lu)\n", + dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n", dentry->d_parent->d_name.name, dentry->d_name.name, - inode->i_ino, (unsigned long) count, (unsigned long) pos); + inode->i_ino, (unsigned long) count, (long long) pos); result = -EBUSY; if (IS_SWAPFILE(inode)) @@ -372,7 +374,7 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t goto out; nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); - result = generic_file_aio_write(iocb, buf, count, pos); + result = generic_file_aio_write(iocb, iov, nr_segs, pos); out: return result; diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 585a79d39c9d..0c46f5c86b71 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -2176,20 +2176,18 @@ out: /** * ntfs_file_aio_write - */ -static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const char __user *buf, - size_t count, loff_t pos) +static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; ssize_t ret; - struct iovec local_iov = { .iov_base = (void __user *)buf, - .iov_len = count }; BUG_ON(iocb->ki_pos != pos); mutex_lock(&inode->i_mutex); - ret = ntfs_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); + ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos); mutex_unlock(&inode->i_mutex); if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { int err = sync_page_range(inode, mapping, pos, ret); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 2bbfa17090cf..d9ba0a931a03 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -961,25 +961,23 @@ static inline int ocfs2_write_should_remove_suid(struct inode *inode) } static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, - const char __user *buf, - size_t count, + const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { - struct iovec local_iov = { .iov_base = (void __user *)buf, - .iov_len = count }; int ret, rw_level = -1, meta_level = -1, have_alloc_sem = 0; u32 clusters; struct file *filp = iocb->ki_filp; struct inode *inode = filp->f_dentry->d_inode; loff_t newsize, saved_pos; - mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf, - (unsigned int)count, + mlog_entry("(0x%p, %u, '%.*s')\n", filp, + (unsigned int)nr_segs, filp->f_dentry->d_name.len, filp->f_dentry->d_name.name); /* happy write of zero bytes */ - if (count == 0) + if (iocb->ki_left == 0) return 0; if (!inode) { @@ -1048,7 +1046,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, } else { saved_pos = iocb->ki_pos; } - newsize = count + saved_pos; + newsize = iocb->ki_left + saved_pos; mlog(0, "pos=%lld newsize=%lld cursize=%lld\n", (long long) saved_pos, (long long) newsize, @@ -1081,7 +1079,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, if (!clusters) break; - ret = ocfs2_extend_file(inode, NULL, newsize, count); + ret = ocfs2_extend_file(inode, NULL, newsize, iocb->ki_left); if (ret < 0) { if (ret != -ENOSPC) mlog_errno(ret); @@ -1098,7 +1096,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, /* communicate with ocfs2_dio_end_io */ ocfs2_iocb_set_rw_locked(iocb); - ret = generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); + ret = generic_file_aio_write_nolock(iocb, iov, nr_segs, iocb->ki_pos); /* buffered aio wouldn't have proper lock coverage today */ BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT)); @@ -1132,16 +1130,16 @@ out: } static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, - char __user *buf, - size_t count, + const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { int ret = 0, rw_level = -1, have_alloc_sem = 0; struct file *filp = iocb->ki_filp; struct inode *inode = filp->f_dentry->d_inode; - mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf, - (unsigned int)count, + mlog_entry("(0x%p, %u, '%.*s')\n", filp, + (unsigned int)nr_segs, filp->f_dentry->d_name.len, filp->f_dentry->d_name.name); @@ -1185,7 +1183,7 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, } ocfs2_meta_unlock(inode, 0); - ret = generic_file_aio_read(iocb, buf, count, iocb->ki_pos); + ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos); if (ret == -EINVAL) mlog(ML_ERROR, "generic_file_aio_read returned -EINVAL\n"); diff --git a/fs/read_write.c b/fs/read_write.c index d4cb3183c99c..679dd535380f 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -227,14 +227,20 @@ static void wait_on_retry_sync_kiocb(struct kiocb *iocb) ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) { + struct iovec iov = { .iov_base = buf, .iov_len = len }; struct kiocb kiocb; ssize_t ret; init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; - while (-EIOCBRETRY == - (ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos))) + kiocb.ki_left = len; + + for (;;) { + ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos); + if (ret != -EIOCBRETRY) + break; wait_on_retry_sync_kiocb(&kiocb); + } if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); @@ -279,14 +285,20 @@ EXPORT_SYMBOL(vfs_read); ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) { + struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len }; struct kiocb kiocb; ssize_t ret; init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; - while (-EIOCBRETRY == - (ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos))) + kiocb.ki_left = len; + + for (;;) { + ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos); + if (ret != -EIOCBRETRY) + break; wait_on_retry_sync_kiocb(&kiocb); + } if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index c11f6118c9ca..41f24369e47a 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -1334,7 +1334,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t if (err) return err; } - result = generic_file_write(file, buf, count, ppos); + result = do_sync_write(file, buf, count, ppos); if (after_file_end) { /* Now update i_size and remove the savelink */ struct reiserfs_transaction_handle th; @@ -1566,7 +1566,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t } const struct file_operations reiserfs_file_operations = { - .read = generic_file_read, + .read = do_sync_read, .write = reiserfs_file_write, .ioctl = reiserfs_ioctl, #ifdef CONFIG_COMPAT diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 41cfcba7ce49..4737971c6a39 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -49,50 +49,49 @@ static struct vm_operations_struct xfs_dmapi_file_vm_ops; STATIC inline ssize_t __xfs_file_read( struct kiocb *iocb, - char __user *buf, + const struct iovec *iov, + unsigned long nr_segs, int ioflags, - size_t count, loff_t pos) { - struct iovec iov = {buf, count}; struct file *file = iocb->ki_filp; bhv_vnode_t *vp = vn_from_inode(file->f_dentry->d_inode); BUG_ON(iocb->ki_pos != pos); if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; - return bhv_vop_read(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL); + return bhv_vop_read(vp, iocb, iov, nr_segs, &iocb->ki_pos, + ioflags, NULL); } STATIC ssize_t xfs_file_aio_read( struct kiocb *iocb, - char __user *buf, - size_t count, + const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { - return __xfs_file_read(iocb, buf, IO_ISAIO, count, pos); + return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO, pos); } STATIC ssize_t xfs_file_aio_read_invis( struct kiocb *iocb, - char __user *buf, - size_t count, + const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { - return __xfs_file_read(iocb, buf, IO_ISAIO|IO_INVIS, count, pos); + return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos); } STATIC inline ssize_t __xfs_file_write( - struct kiocb *iocb, - const char __user *buf, - int ioflags, - size_t count, - loff_t pos) + struct kiocb *iocb, + const struct iovec *iov, + unsigned long nr_segs, + int ioflags, + loff_t pos) { - struct iovec iov = {(void __user *)buf, count}; struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; bhv_vnode_t *vp = vn_from_inode(inode); @@ -100,27 +99,28 @@ __xfs_file_write( BUG_ON(iocb->ki_pos != pos); if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; - return bhv_vop_write(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL); + return bhv_vop_write(vp, iocb, iov, nr_segs, &iocb->ki_pos, + ioflags, NULL); } STATIC ssize_t xfs_file_aio_write( struct kiocb *iocb, - const char __user *buf, - size_t count, + const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { - return __xfs_file_write(iocb, buf, IO_ISAIO, count, pos); + return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO, pos); } STATIC ssize_t xfs_file_aio_write_invis( struct kiocb *iocb, - const char __user *buf, - size_t count, + const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { - return __xfs_file_write(iocb, buf, IO_ISAIO|IO_INVIS, count, pos); + return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos); } STATIC inline ssize_t diff --git a/include/linux/aio.h b/include/linux/aio.h index 8a0193385a9b..58349e58b749 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -112,6 +113,7 @@ struct kiocb { long ki_retried; /* just for testing */ long ki_kicked; /* just for testing */ long ki_queued; /* just for testing */ + struct iovec ki_inline_vec; /* inline vector */ struct list_head ki_list; /* the aio core uses this * for cancellation */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 5baf3a153403..257bae16f545 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1097,9 +1097,9 @@ struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); - ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); - ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t); + ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); + ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); @@ -1704,11 +1704,11 @@ extern int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned extern ssize_t generic_file_read(struct file *, char __user *, size_t, loff_t *); int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk); extern ssize_t generic_file_write(struct file *, const char __user *, size_t, loff_t *); -extern ssize_t generic_file_aio_read(struct kiocb *, char __user *, size_t, loff_t); +extern ssize_t generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t); extern ssize_t __generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t *); -extern ssize_t generic_file_aio_write(struct kiocb *, const char __user *, size_t, loff_t); +extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t); extern ssize_t generic_file_aio_write_nolock(struct kiocb *, const struct iovec *, - unsigned long, loff_t *); + unsigned long, loff_t); extern ssize_t generic_file_direct_write(struct kiocb *, const struct iovec *, unsigned long *, loff_t, loff_t *, size_t, size_t); extern ssize_t generic_file_buffered_write(struct kiocb *, const struct iovec *, diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 98c9b9f667a5..76ff54846ada 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -367,10 +367,12 @@ extern int nfs3_removexattr (struct dentry *, const char *name); */ extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t, unsigned long); -extern ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, - size_t count, loff_t pos); -extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, - size_t count, loff_t pos); +extern ssize_t nfs_file_direct_read(struct kiocb *iocb, + const struct iovec *iov, unsigned long nr_segs, + loff_t pos); +extern ssize_t nfs_file_direct_write(struct kiocb *iocb, + const struct iovec *iov, unsigned long nr_segs, + loff_t pos); /* * linux/fs/nfs/dir.c diff --git a/include/net/sock.h b/include/net/sock.h index edd4d73ce7f5..40bb90ebb2d1 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -665,7 +665,6 @@ struct sock_iocb { struct sock *sk; struct scm_cookie *scm; struct msghdr *msg, async_msg; - struct iovec async_iov; struct kiocb *kiocb; }; diff --git a/mm/filemap.c b/mm/filemap.c index c4fe97f5ace0..f6c1d22b504f 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1226,12 +1226,11 @@ out: EXPORT_SYMBOL(__generic_file_aio_read); ssize_t -generic_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) +generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { - struct iovec local_iov = { .iov_base = buf, .iov_len = count }; - BUG_ON(iocb->ki_pos != pos); - return __generic_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); + return __generic_file_aio_read(iocb, iov, nr_segs, &iocb->ki_pos); } EXPORT_SYMBOL(generic_file_aio_read); @@ -2315,22 +2314,22 @@ out: current->backing_dev_info = NULL; return written ? written : err; } -EXPORT_SYMBOL(generic_file_aio_write_nolock); -ssize_t -generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) +ssize_t generic_file_aio_write_nolock(struct kiocb *iocb, + const struct iovec *iov, unsigned long nr_segs, loff_t pos) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; ssize_t ret; - loff_t pos = *ppos; - ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs, ppos); + BUG_ON(iocb->ki_pos != pos); + + ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs, + &iocb->ki_pos); if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { - int err; + ssize_t err; err = sync_page_range_nolock(inode, mapping, pos, ret); if (err < 0) @@ -2338,6 +2337,7 @@ generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, } return ret; } +EXPORT_SYMBOL(generic_file_aio_write_nolock); static ssize_t __generic_file_write_nolock(struct file *file, const struct iovec *iov, @@ -2347,8 +2347,9 @@ __generic_file_write_nolock(struct file *file, const struct iovec *iov, ssize_t ret; init_sync_kiocb(&kiocb, file); + kiocb.ki_pos = *ppos; ret = __generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos); - if (ret == -EIOCBQUEUED) + if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); return ret; } @@ -2361,28 +2362,28 @@ generic_file_write_nolock(struct file *file, const struct iovec *iov, ssize_t ret; init_sync_kiocb(&kiocb, file); - ret = generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos); + kiocb.ki_pos = *ppos; + ret = generic_file_aio_write_nolock(&kiocb, iov, nr_segs, *ppos); if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); + *ppos = kiocb.ki_pos; return ret; } EXPORT_SYMBOL(generic_file_write_nolock); -ssize_t generic_file_aio_write(struct kiocb *iocb, const char __user *buf, - size_t count, loff_t pos) +ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; ssize_t ret; - struct iovec local_iov = { .iov_base = (void __user *)buf, - .iov_len = count }; BUG_ON(iocb->ki_pos != pos); mutex_lock(&inode->i_mutex); - ret = __generic_file_aio_write_nolock(iocb, &local_iov, 1, - &iocb->ki_pos); + ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs, + &iocb->ki_pos); mutex_unlock(&inode->i_mutex); if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { diff --git a/net/socket.c b/net/socket.c index 1bc4167e0da8..df92e4252749 100644 --- a/net/socket.c +++ b/net/socket.c @@ -95,10 +95,10 @@ #include static int sock_no_open(struct inode *irrelevant, struct file *dontcare); -static ssize_t sock_aio_read(struct kiocb *iocb, char __user *buf, - size_t size, loff_t pos); -static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *buf, - size_t size, loff_t pos); +static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos); +static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos); static int sock_mmap(struct file *file, struct vm_area_struct *vma); static int sock_close(struct inode *inode, struct file *file); @@ -664,7 +664,6 @@ static ssize_t sock_sendpage(struct file *file, struct page *page, } static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, - char __user *ubuf, size_t size, struct sock_iocb *siocb) { if (!is_sync_kiocb(iocb)) { @@ -675,16 +674,13 @@ static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, } siocb->kiocb = iocb; - siocb->async_iov.iov_base = ubuf; - siocb->async_iov.iov_len = size; - iocb->private = siocb; return siocb; } static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, - struct file *file, struct iovec *iov, - unsigned long nr_segs) + struct file *file, const struct iovec *iov, + unsigned long nr_segs) { struct socket *sock = file->private_data; size_t size = 0; @@ -715,32 +711,33 @@ static ssize_t sock_readv(struct file *file, const struct iovec *iov, init_sync_kiocb(&iocb, NULL); iocb.private = &siocb; - ret = do_sock_read(&msg, &iocb, file, (struct iovec *)iov, nr_segs); + ret = do_sock_read(&msg, &iocb, file, iov, nr_segs); if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&iocb); return ret; } -static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, - size_t count, loff_t pos) +static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct sock_iocb siocb, *x; if (pos != 0) return -ESPIPE; - if (count == 0) /* Match SYS5 behaviour */ + + if (iocb->ki_left == 0) /* Match SYS5 behaviour */ return 0; - x = alloc_sock_iocb(iocb, ubuf, count, &siocb); + + x = alloc_sock_iocb(iocb, &siocb); if (!x) return -ENOMEM; - return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, - &x->async_iov, 1); + return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); } static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, - struct file *file, struct iovec *iov, - unsigned long nr_segs) + struct file *file, const struct iovec *iov, + unsigned long nr_segs) { struct socket *sock = file->private_data; size_t size = 0; @@ -773,28 +770,28 @@ static ssize_t sock_writev(struct file *file, const struct iovec *iov, init_sync_kiocb(&iocb, NULL); iocb.private = &siocb; - ret = do_sock_write(&msg, &iocb, file, (struct iovec *)iov, nr_segs); + ret = do_sock_write(&msg, &iocb, file, iov, nr_segs); if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&iocb); return ret; } -static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, - size_t count, loff_t pos) +static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct sock_iocb siocb, *x; if (pos != 0) return -ESPIPE; - if (count == 0) /* Match SYS5 behaviour */ + + if (iocb->ki_left == 0) /* Match SYS5 behaviour */ return 0; - x = alloc_sock_iocb(iocb, (void __user *)ubuf, count, &siocb); + x = alloc_sock_iocb(iocb, &siocb); if (!x) return -ENOMEM; - return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, - &x->async_iov, 1); + return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); } /* -- cgit v1.2.3 From ee0b3e671baff681d69fbf0db33b47603c0a8280 Mon Sep 17 00:00:00 2001 From: Badari Pulavarty Date: Sat, 30 Sep 2006 23:28:47 -0700 Subject: [PATCH] Remove readv/writev methods and use aio_read/aio_write instead This patch removes readv() and writev() methods and replaces them with aio_read()/aio_write() methods. Signed-off-by: Badari Pulavarty Signed-off-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/raw.c | 2 - drivers/net/tun.c | 37 +++++----------- fs/bad_inode.c | 2 - fs/block_dev.c | 2 - fs/cifs/cifsfs.c | 16 ------- fs/compat.c | 44 +++++-------------- fs/ext2/file.c | 2 - fs/ext3/file.c | 2 - fs/fat/file.c | 2 - fs/fuse/dev.c | 37 +++++----------- fs/hostfs/hostfs_kern.c | 2 - fs/jfs/file.c | 2 - fs/ntfs/file.c | 2 - fs/pipe.c | 59 ++++++++++---------------- fs/read_write.c | 101 +++++++++++++++++++++++++++++--------------- fs/read_write.h | 14 ++++++ fs/xfs/linux-2.6/xfs_file.c | 94 ----------------------------------------- include/linux/fs.h | 6 --- mm/filemap.c | 36 ---------------- net/socket.c | 40 ------------------ sound/core/pcm_native.c | 40 +++++++++--------- 21 files changed, 154 insertions(+), 388 deletions(-) create mode 100644 fs/read_write.h (limited to 'include/linux') diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 173fb08555d5..490db531e2d8 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -257,8 +257,6 @@ static const struct file_operations raw_fops = { .open = raw_open, .release= raw_release, .ioctl = raw_ioctl, - .readv = generic_file_readv, - .writev = generic_file_writev, .owner = THIS_MODULE, }; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index de8da6dee1b0..bc0face01d25 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -288,11 +288,10 @@ static inline size_t iov_total(const struct iovec *iv, unsigned long count) return len; } -/* Writev */ -static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv, - unsigned long count, loff_t *pos) +static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, + unsigned long count, loff_t pos) { - struct tun_struct *tun = file->private_data; + struct tun_struct *tun = iocb->ki_filp->private_data; if (!tun) return -EBADFD; @@ -302,14 +301,6 @@ static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv, return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count)); } -/* Write */ -static ssize_t tun_chr_write(struct file * file, const char __user * buf, - size_t count, loff_t *pos) -{ - struct iovec iv = { (void __user *) buf, count }; - return tun_chr_writev(file, &iv, 1, pos); -} - /* Put packet to the user space buffer */ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, struct sk_buff *skb, @@ -343,10 +334,10 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, return total; } -/* Readv */ -static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv, - unsigned long count, loff_t *pos) +static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, + unsigned long count, loff_t pos) { + struct file *file = iocb->ki_filp; struct tun_struct *tun = file->private_data; DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; @@ -426,14 +417,6 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv, return ret; } -/* Read */ -static ssize_t tun_chr_read(struct file * file, char __user * buf, - size_t count, loff_t *pos) -{ - struct iovec iv = { buf, count }; - return tun_chr_readv(file, &iv, 1, pos); -} - static void tun_setup(struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); @@ -764,10 +747,10 @@ static int tun_chr_close(struct inode *inode, struct file *file) static struct file_operations tun_fops = { .owner = THIS_MODULE, .llseek = no_llseek, - .read = tun_chr_read, - .readv = tun_chr_readv, - .write = tun_chr_write, - .writev = tun_chr_writev, + .read = do_sync_read, + .aio_read = tun_chr_aio_read, + .write = do_sync_write, + .aio_write = tun_chr_aio_write, .poll = tun_chr_poll, .ioctl = tun_chr_ioctl, .open = tun_chr_open, diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 80599ae33966..34e6d7b220c3 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -40,8 +40,6 @@ static const struct file_operations bad_file_ops = .aio_fsync = EIO_ERROR, .fasync = EIO_ERROR, .lock = EIO_ERROR, - .readv = EIO_ERROR, - .writev = EIO_ERROR, .sendfile = EIO_ERROR, .sendpage = EIO_ERROR, .get_unmapped_area = EIO_ERROR, diff --git a/fs/block_dev.c b/fs/block_dev.c index 8c819117310b..0f143094ef1d 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1191,8 +1191,6 @@ const struct file_operations def_blk_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = compat_blkdev_ioctl, #endif - .readv = generic_file_readv, - .writev = generic_file_write_nolock, .sendfile = generic_file_sendfile, .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5abb42a7c53e..c00c654f2e11 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -480,18 +480,6 @@ cifs_get_sb(struct file_system_type *fs_type, return simple_set_mnt(mnt, sb); } -static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct inode *inode = file->f_dentry->d_inode; - ssize_t written; - - written = generic_file_writev(file, iov, nr_segs, ppos); - if (!CIFS_I(inode)->clientCanCacheAll) - filemap_fdatawrite(inode->i_mapping); - return written; -} - static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { @@ -577,8 +565,6 @@ struct inode_operations cifs_symlink_inode_ops = { const struct file_operations cifs_file_ops = { .read = do_sync_read, .write = do_sync_write, - .readv = generic_file_readv, - .writev = cifs_file_writev, .aio_read = generic_file_aio_read, .aio_write = cifs_file_aio_write, .open = cifs_open, @@ -620,8 +606,6 @@ const struct file_operations cifs_file_direct_ops = { const struct file_operations cifs_file_nobrl_ops = { .read = do_sync_read, .write = do_sync_write, - .readv = generic_file_readv, - .writev = cifs_file_writev, .aio_read = generic_file_aio_read, .aio_write = cifs_file_aio_write, .open = cifs_open, diff --git a/fs/compat.c b/fs/compat.c index 122b4e3992b5..6b90bf35f61d 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -70,6 +70,8 @@ int compat_printk(const char *fmt, ...) return ret; } +#include "read_write.h" + /* * Not all architectures have sys_utime, so implement this in terms * of sys_utimes. @@ -1149,9 +1151,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, const struct compat_iovec __user *uvector, unsigned long nr_segs, loff_t *pos) { - typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *); - typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *); - compat_ssize_t tot_len; struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov=iovstack, *vector; @@ -1234,39 +1233,18 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, fnv = NULL; if (type == READ) { fn = file->f_op->read; - fnv = file->f_op->readv; + fnv = file->f_op->aio_read; } else { fn = (io_fn_t)file->f_op->write; - fnv = file->f_op->writev; - } - if (fnv) { - ret = fnv(file, iov, nr_segs, pos); - goto out; + fnv = file->f_op->aio_write; } - /* Do it by hand, with file-ops */ - ret = 0; - vector = iov; - while (nr_segs > 0) { - void __user * base; - size_t len; - ssize_t nr; - - base = vector->iov_base; - len = vector->iov_len; - vector++; - nr_segs--; - - nr = fn(file, base, len, pos); + if (fnv) + ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, + pos, fnv); + else + ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn); - if (nr < 0) { - if (!ret) ret = nr; - break; - } - ret += nr; - if (nr != len) - break; - } out: if (iov != iovstack) kfree(iov); @@ -1294,7 +1272,7 @@ compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsign goto out; ret = -EINVAL; - if (!file->f_op || (!file->f_op->readv && !file->f_op->read)) + if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read)) goto out; ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos); @@ -1317,7 +1295,7 @@ compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsig goto out; ret = -EINVAL; - if (!file->f_op || (!file->f_op->writev && !file->f_op->write)) + if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write)) goto out; ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos); diff --git a/fs/ext2/file.c b/fs/ext2/file.c index e8bbed9dd268..e893e2be9ed4 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -53,8 +53,6 @@ const struct file_operations ext2_file_operations = { .open = generic_file_open, .release = ext2_release_file, .fsync = ext2_sync_file, - .readv = generic_file_readv, - .writev = generic_file_writev, .sendfile = generic_file_sendfile, .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 5c762457bc89..e96c388047e0 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -112,8 +112,6 @@ const struct file_operations ext3_file_operations = { .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write = ext3_file_write, - .readv = generic_file_readv, - .writev = generic_file_writev, .ioctl = ext3_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext3_compat_ioctl, diff --git a/fs/fat/file.c b/fs/fat/file.c index d50fc47169c1..f4b8f8b3fbdd 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -127,8 +127,6 @@ const struct file_operations fat_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, - .readv = generic_file_readv, - .writev = generic_file_writev, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 4fc557c40cc0..66571eafbb1e 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -680,14 +680,15 @@ static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req, * request_end(). Otherwise add it to the processing list, and set * the 'sent' flag. */ -static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t *off) +static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { int err; struct fuse_req *req; struct fuse_in *in; struct fuse_copy_state cs; unsigned reqsize; + struct file *file = iocb->ki_filp; struct fuse_conn *fc = fuse_get_conn(file); if (!fc) return -EPERM; @@ -761,15 +762,6 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov, return err; } -static ssize_t fuse_dev_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *off) -{ - struct iovec iov; - iov.iov_len = nbytes; - iov.iov_base = buf; - return fuse_dev_readv(file, &iov, 1, off); -} - /* Look up request on processing list by unique ID */ static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique) { @@ -814,15 +806,15 @@ static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out, * it from the list and copy the rest of the buffer to the request. * The request is finished by calling request_end() */ -static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t *off) +static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { int err; unsigned nbytes = iov_length(iov, nr_segs); struct fuse_req *req; struct fuse_out_header oh; struct fuse_copy_state cs; - struct fuse_conn *fc = fuse_get_conn(file); + struct fuse_conn *fc = fuse_get_conn(iocb->ki_filp); if (!fc) return -EPERM; @@ -898,15 +890,6 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov, return err; } -static ssize_t fuse_dev_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *off) -{ - struct iovec iov; - iov.iov_len = nbytes; - iov.iov_base = (char __user *) buf; - return fuse_dev_writev(file, &iov, 1, off); -} - static unsigned fuse_dev_poll(struct file *file, poll_table *wait) { unsigned mask = POLLOUT | POLLWRNORM; @@ -1041,10 +1024,10 @@ static int fuse_dev_fasync(int fd, struct file *file, int on) const struct file_operations fuse_dev_operations = { .owner = THIS_MODULE, .llseek = no_llseek, - .read = fuse_dev_read, - .readv = fuse_dev_readv, - .write = fuse_dev_write, - .writev = fuse_dev_writev, + .read = do_sync_read, + .aio_read = fuse_dev_read, + .write = do_sync_write, + .aio_write = fuse_dev_write, .poll = fuse_dev_poll, .release = fuse_dev_release, .fasync = fuse_dev_fasync, diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 322e876c35ed..4908c38a5885 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -389,8 +389,6 @@ static const struct file_operations hostfs_file_fops = { .sendfile = generic_file_sendfile, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, - .readv = generic_file_readv, - .writev = generic_file_writev, .write = generic_file_write, .mmap = generic_file_mmap, .open = hostfs_file_open, diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 1c9745be5ada..f535f2911c12 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -108,8 +108,6 @@ const struct file_operations jfs_file_operations = { .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, - .readv = generic_file_readv, - .writev = generic_file_writev, .sendfile = generic_file_sendfile, .fsync = jfs_fsync, .release = jfs_release, diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 0c46f5c86b71..2f9b5a0953ff 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -2298,11 +2298,9 @@ const struct file_operations ntfs_file_ops = { .llseek = generic_file_llseek, /* Seek inside file. */ .read = generic_file_read, /* Read from file. */ .aio_read = generic_file_aio_read, /* Async read from file. */ - .readv = generic_file_readv, /* Read from file. */ #ifdef NTFS_RW .write = ntfs_file_write, /* Write to file. */ .aio_write = ntfs_file_aio_write, /* Async write to file. */ - .writev = ntfs_file_writev, /* Write to file. */ /*.release = ,*/ /* Last file is closed. See fs/ext2/file.c:: ext2_release_file() for diff --git a/fs/pipe.c b/fs/pipe.c index f3b6f71e9d0b..2e60e1c8815e 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -218,9 +218,10 @@ static struct pipe_buf_operations anon_pipe_buf_ops = { }; static ssize_t -pipe_readv(struct file *filp, const struct iovec *_iov, - unsigned long nr_segs, loff_t *ppos) +pipe_read(struct kiocb *iocb, const struct iovec *_iov, + unsigned long nr_segs, loff_t pos) { + struct file *filp = iocb->ki_filp; struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *pipe; int do_wakeup; @@ -330,17 +331,10 @@ redo: } static ssize_t -pipe_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) -{ - struct iovec iov = { .iov_base = buf, .iov_len = count }; - - return pipe_readv(filp, &iov, 1, ppos); -} - -static ssize_t -pipe_writev(struct file *filp, const struct iovec *_iov, - unsigned long nr_segs, loff_t *ppos) +pipe_write(struct kiocb *iocb, const struct iovec *_iov, + unsigned long nr_segs, loff_t ppos) { + struct file *filp = iocb->ki_filp; struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *pipe; ssize_t ret; @@ -509,15 +503,6 @@ out: return ret; } -static ssize_t -pipe_write(struct file *filp, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count }; - - return pipe_writev(filp, &iov, 1, ppos); -} - static ssize_t bad_pipe_r(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { @@ -736,8 +721,8 @@ pipe_rdwr_open(struct inode *inode, struct file *filp) */ const struct file_operations read_fifo_fops = { .llseek = no_llseek, - .read = pipe_read, - .readv = pipe_readv, + .read = do_sync_read, + .aio_read = pipe_read, .write = bad_pipe_w, .poll = pipe_poll, .ioctl = pipe_ioctl, @@ -749,8 +734,8 @@ const struct file_operations read_fifo_fops = { const struct file_operations write_fifo_fops = { .llseek = no_llseek, .read = bad_pipe_r, - .write = pipe_write, - .writev = pipe_writev, + .write = do_sync_write, + .aio_write = pipe_write, .poll = pipe_poll, .ioctl = pipe_ioctl, .open = pipe_write_open, @@ -760,10 +745,10 @@ const struct file_operations write_fifo_fops = { const struct file_operations rdwr_fifo_fops = { .llseek = no_llseek, - .read = pipe_read, - .readv = pipe_readv, - .write = pipe_write, - .writev = pipe_writev, + .read = do_sync_read, + .aio_read = pipe_read, + .write = do_sync_write, + .aio_write = pipe_write, .poll = pipe_poll, .ioctl = pipe_ioctl, .open = pipe_rdwr_open, @@ -773,8 +758,8 @@ const struct file_operations rdwr_fifo_fops = { static struct file_operations read_pipe_fops = { .llseek = no_llseek, - .read = pipe_read, - .readv = pipe_readv, + .read = do_sync_read, + .aio_read = pipe_read, .write = bad_pipe_w, .poll = pipe_poll, .ioctl = pipe_ioctl, @@ -786,8 +771,8 @@ static struct file_operations read_pipe_fops = { static struct file_operations write_pipe_fops = { .llseek = no_llseek, .read = bad_pipe_r, - .write = pipe_write, - .writev = pipe_writev, + .write = do_sync_write, + .aio_write = pipe_write, .poll = pipe_poll, .ioctl = pipe_ioctl, .open = pipe_write_open, @@ -797,10 +782,10 @@ static struct file_operations write_pipe_fops = { static struct file_operations rdwr_pipe_fops = { .llseek = no_llseek, - .read = pipe_read, - .readv = pipe_readv, - .write = pipe_write, - .writev = pipe_writev, + .read = do_sync_read, + .aio_read = pipe_read, + .write = do_sync_write, + .aio_write = pipe_write, .poll = pipe_poll, .ioctl = pipe_ioctl, .open = pipe_rdwr_open, diff --git a/fs/read_write.c b/fs/read_write.c index 679dd535380f..32d54cca9bd9 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -15,6 +15,7 @@ #include #include #include +#include "read_write.h" #include #include @@ -450,6 +451,62 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to) EXPORT_UNUSED_SYMBOL(iov_shorten); /* June 2006 */ +ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, + unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn) +{ + struct kiocb kiocb; + ssize_t ret; + + init_sync_kiocb(&kiocb, filp); + kiocb.ki_pos = *ppos; + kiocb.ki_left = len; + kiocb.ki_nbytes = len; + + for (;;) { + ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos); + if (ret != -EIOCBRETRY) + break; + wait_on_retry_sync_kiocb(&kiocb); + } + + if (ret == -EIOCBQUEUED) + ret = wait_on_sync_kiocb(&kiocb); + *ppos = kiocb.ki_pos; + return ret; +} + +/* Do it by hand, with file-ops */ +ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, + unsigned long nr_segs, loff_t *ppos, io_fn_t fn) +{ + struct iovec *vector = iov; + ssize_t ret = 0; + + while (nr_segs > 0) { + void __user *base; + size_t len; + ssize_t nr; + + base = vector->iov_base; + len = vector->iov_len; + vector++; + nr_segs--; + + nr = fn(filp, base, len, ppos); + + if (nr < 0) { + if (!ret) + ret = nr; + break; + } + ret += nr; + if (nr != len) + break; + } + + return ret; +} + /* A write operation does a read from user space and vice versa */ #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) @@ -457,12 +514,9 @@ static ssize_t do_readv_writev(int type, struct file *file, const struct iovec __user * uvector, unsigned long nr_segs, loff_t *pos) { - typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *); - typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *); - size_t tot_len; struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov=iovstack, *vector; + struct iovec *iov = iovstack; ssize_t ret; int seg; io_fn_t fn; @@ -532,39 +586,18 @@ static ssize_t do_readv_writev(int type, struct file *file, fnv = NULL; if (type == READ) { fn = file->f_op->read; - fnv = file->f_op->readv; + fnv = file->f_op->aio_read; } else { fn = (io_fn_t)file->f_op->write; - fnv = file->f_op->writev; - } - if (fnv) { - ret = fnv(file, iov, nr_segs, pos); - goto out; + fnv = file->f_op->aio_write; } - /* Do it by hand, with file-ops */ - ret = 0; - vector = iov; - while (nr_segs > 0) { - void __user * base; - size_t len; - ssize_t nr; - - base = vector->iov_base; - len = vector->iov_len; - vector++; - nr_segs--; - - nr = fn(file, base, len, pos); + if (fnv) + ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, + pos, fnv); + else + ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn); - if (nr < 0) { - if (!ret) ret = nr; - break; - } - ret += nr; - if (nr != len) - break; - } out: if (iov != iovstack) kfree(iov); @@ -585,7 +618,7 @@ ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, { if (!(file->f_mode & FMODE_READ)) return -EBADF; - if (!file->f_op || (!file->f_op->readv && !file->f_op->read)) + if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read)) return -EINVAL; return do_readv_writev(READ, file, vec, vlen, pos); @@ -598,7 +631,7 @@ ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, { if (!(file->f_mode & FMODE_WRITE)) return -EBADF; - if (!file->f_op || (!file->f_op->writev && !file->f_op->write)) + if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write)) return -EINVAL; return do_readv_writev(WRITE, file, vec, vlen, pos); diff --git a/fs/read_write.h b/fs/read_write.h new file mode 100644 index 000000000000..d07b954c6e0c --- /dev/null +++ b/fs/read_write.h @@ -0,0 +1,14 @@ +/* + * This file is only for sharing some helpers from read_write.c with compat.c. + * Don't use anywhere else. + */ + + +typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *); +typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *, + unsigned long, loff_t); + +ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, + unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn); +ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, + unsigned long nr_segs, loff_t *ppos, io_fn_t fn); diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 4737971c6a39..d93d8dd1958d 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -123,96 +123,6 @@ xfs_file_aio_write_invis( return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos); } -STATIC inline ssize_t -__xfs_file_readv( - struct file *file, - const struct iovec *iov, - int ioflags, - unsigned long nr_segs, - loff_t *ppos) -{ - struct inode *inode = file->f_mapping->host; - bhv_vnode_t *vp = vn_from_inode(inode); - struct kiocb kiocb; - ssize_t rval; - - init_sync_kiocb(&kiocb, file); - kiocb.ki_pos = *ppos; - - if (unlikely(file->f_flags & O_DIRECT)) - ioflags |= IO_ISDIRECT; - rval = bhv_vop_read(vp, &kiocb, iov, nr_segs, - &kiocb.ki_pos, ioflags, NULL); - - *ppos = kiocb.ki_pos; - return rval; -} - -STATIC ssize_t -xfs_file_readv( - struct file *file, - const struct iovec *iov, - unsigned long nr_segs, - loff_t *ppos) -{ - return __xfs_file_readv(file, iov, 0, nr_segs, ppos); -} - -STATIC ssize_t -xfs_file_readv_invis( - struct file *file, - const struct iovec *iov, - unsigned long nr_segs, - loff_t *ppos) -{ - return __xfs_file_readv(file, iov, IO_INVIS, nr_segs, ppos); -} - -STATIC inline ssize_t -__xfs_file_writev( - struct file *file, - const struct iovec *iov, - int ioflags, - unsigned long nr_segs, - loff_t *ppos) -{ - struct inode *inode = file->f_mapping->host; - bhv_vnode_t *vp = vn_from_inode(inode); - struct kiocb kiocb; - ssize_t rval; - - init_sync_kiocb(&kiocb, file); - kiocb.ki_pos = *ppos; - if (unlikely(file->f_flags & O_DIRECT)) - ioflags |= IO_ISDIRECT; - - rval = bhv_vop_write(vp, &kiocb, iov, nr_segs, - &kiocb.ki_pos, ioflags, NULL); - - *ppos = kiocb.ki_pos; - return rval; -} - -STATIC ssize_t -xfs_file_writev( - struct file *file, - const struct iovec *iov, - unsigned long nr_segs, - loff_t *ppos) -{ - return __xfs_file_writev(file, iov, 0, nr_segs, ppos); -} - -STATIC ssize_t -xfs_file_writev_invis( - struct file *file, - const struct iovec *iov, - unsigned long nr_segs, - loff_t *ppos) -{ - return __xfs_file_writev(file, iov, IO_INVIS, nr_segs, ppos); -} - STATIC ssize_t xfs_file_sendfile( struct file *filp, @@ -540,8 +450,6 @@ const struct file_operations xfs_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, - .readv = xfs_file_readv, - .writev = xfs_file_writev, .aio_read = xfs_file_aio_read, .aio_write = xfs_file_aio_write, .sendfile = xfs_file_sendfile, @@ -565,8 +473,6 @@ const struct file_operations xfs_invis_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, - .readv = xfs_file_readv_invis, - .writev = xfs_file_writev_invis, .aio_read = xfs_file_aio_read_invis, .aio_write = xfs_file_aio_write_invis, .sendfile = xfs_file_sendfile_invis, diff --git a/include/linux/fs.h b/include/linux/fs.h index 257bae16f545..afb6e6f89a01 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1113,8 +1113,6 @@ struct file_operations { int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); - ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); - ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); @@ -1734,10 +1732,6 @@ extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, extern void file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); -extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos); -ssize_t generic_file_writev(struct file *filp, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos); extern loff_t no_llseek(struct file *file, loff_t offset, int origin); extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin); extern loff_t remote_llseek(struct file *file, loff_t offset, int origin); diff --git a/mm/filemap.c b/mm/filemap.c index f6c1d22b504f..48497094ae83 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2421,42 +2421,6 @@ ssize_t generic_file_write(struct file *file, const char __user *buf, } EXPORT_SYMBOL(generic_file_write); -ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct kiocb kiocb; - ssize_t ret; - - init_sync_kiocb(&kiocb, filp); - ret = __generic_file_aio_read(&kiocb, iov, nr_segs, ppos); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&kiocb); - return ret; -} -EXPORT_SYMBOL(generic_file_readv); - -ssize_t generic_file_writev(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - ssize_t ret; - - mutex_lock(&inode->i_mutex); - ret = __generic_file_write_nolock(file, iov, nr_segs, ppos); - mutex_unlock(&inode->i_mutex); - - if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { - int err; - - err = sync_page_range(inode, mapping, *ppos - ret, ret); - if (err < 0) - ret = err; - } - return ret; -} -EXPORT_SYMBOL(generic_file_writev); - /* * Called under i_mutex for writes to S_ISREG files. Returns -EIO if something * went wrong during pagecache shootdown. diff --git a/net/socket.c b/net/socket.c index df92e4252749..01918f7a301a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -110,10 +110,6 @@ static long compat_sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); #endif static int sock_fasync(int fd, struct file *filp, int on); -static ssize_t sock_readv(struct file *file, const struct iovec *vector, - unsigned long count, loff_t *ppos); -static ssize_t sock_writev(struct file *file, const struct iovec *vector, - unsigned long count, loff_t *ppos); static ssize_t sock_sendpage(struct file *file, struct page *page, int offset, size_t size, loff_t *ppos, int more); @@ -136,8 +132,6 @@ static struct file_operations socket_file_ops = { .open = sock_no_open, /* special open code to disallow open via /proc */ .release = sock_close, .fasync = sock_fasync, - .readv = sock_readv, - .writev = sock_writev, .sendpage = sock_sendpage, .splice_write = generic_splice_sendpage, }; @@ -700,23 +694,6 @@ static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags); } -static ssize_t sock_readv(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct kiocb iocb; - struct sock_iocb siocb; - struct msghdr msg; - int ret; - - init_sync_kiocb(&iocb, NULL); - iocb.private = &siocb; - - ret = do_sock_read(&msg, &iocb, file, iov, nr_segs); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&iocb); - return ret; -} - static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { @@ -759,23 +736,6 @@ static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, return __sock_sendmsg(iocb, sock, msg, size); } -static ssize_t sock_writev(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct msghdr msg; - struct kiocb iocb; - struct sock_iocb siocb; - int ret; - - init_sync_kiocb(&iocb, NULL); - iocb.private = &siocb; - - ret = do_sock_write(&msg, &iocb, file, iov, nr_segs); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&iocb); - return ret; -} - static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 891d7140553c..37b4b10850ae 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2852,8 +2852,8 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf, return result; } -static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector, - unsigned long count, loff_t * offset) +static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct snd_pcm_file *pcm_file; @@ -2864,22 +2864,22 @@ static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector, void __user **bufs; snd_pcm_uframes_t frames; - pcm_file = file->private_data; + pcm_file = iocb->ki_filp->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - if (count > 1024 || count != runtime->channels) + if (nr_segs > 1024 || nr_segs != runtime->channels) return -EINVAL; - if (!frame_aligned(runtime, _vector->iov_len)) + if (!frame_aligned(runtime, iov->iov_len)) return -EINVAL; - frames = bytes_to_samples(runtime, _vector->iov_len); - bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL); + frames = bytes_to_samples(runtime, iov->iov_len); + bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); if (bufs == NULL) return -ENOMEM; - for (i = 0; i < count; ++i) - bufs[i] = _vector[i].iov_base; + for (i = 0; i < nr_segs; ++i) + bufs[i] = iov[i].iov_base; result = snd_pcm_lib_readv(substream, bufs, frames); if (result > 0) result = frames_to_bytes(runtime, result); @@ -2887,8 +2887,8 @@ static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector, return result; } -static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector, - unsigned long count, loff_t * offset) +static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream; @@ -2898,7 +2898,7 @@ static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector, void __user **bufs; snd_pcm_uframes_t frames; - pcm_file = file->private_data; + pcm_file = iocb->ki_filp->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, result = -ENXIO; goto end); runtime = substream->runtime; @@ -2906,17 +2906,17 @@ static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector, result = -EBADFD; goto end; } - if (count > 128 || count != runtime->channels || - !frame_aligned(runtime, _vector->iov_len)) { + if (nr_segs > 128 || nr_segs != runtime->channels || + !frame_aligned(runtime, iov->iov_len)) { result = -EINVAL; goto end; } - frames = bytes_to_samples(runtime, _vector->iov_len); - bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL); + frames = bytes_to_samples(runtime, iov->iov_len); + bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); if (bufs == NULL) return -ENOMEM; - for (i = 0; i < count; ++i) - bufs[i] = _vector[i].iov_base; + for (i = 0; i < nr_segs; ++i) + bufs[i] = iov[i].iov_base; result = snd_pcm_lib_writev(substream, bufs, frames); if (result > 0) result = frames_to_bytes(runtime, result); @@ -3426,7 +3426,7 @@ struct file_operations snd_pcm_f_ops[2] = { { .owner = THIS_MODULE, .write = snd_pcm_write, - .writev = snd_pcm_writev, + .aio_write = snd_pcm_aio_write, .open = snd_pcm_playback_open, .release = snd_pcm_release, .poll = snd_pcm_playback_poll, @@ -3438,7 +3438,7 @@ struct file_operations snd_pcm_f_ops[2] = { { .owner = THIS_MODULE, .read = snd_pcm_read, - .readv = snd_pcm_readv, + .aio_read = snd_pcm_aio_read, .open = snd_pcm_capture_open, .release = snd_pcm_release, .poll = snd_pcm_capture_poll, -- cgit v1.2.3 From 543ade1fc901db4c3dbe9fb27241fb977f1f3eea Mon Sep 17 00:00:00 2001 From: Badari Pulavarty Date: Sat, 30 Sep 2006 23:28:48 -0700 Subject: [PATCH] Streamline generic_file_* interfaces and filemap cleanups This patch cleans up generic_file_*_read/write() interfaces. Christoph Hellwig gave me the idea for this clean ups. In a nutshell, all filesystems should set .aio_read/.aio_write methods and use do_sync_read/ do_sync_write() as their .read/.write methods. This allows us to cleanup all variants of generic_file_* routines. Final available interfaces: generic_file_aio_read() - read handler generic_file_aio_write() - write handler generic_file_aio_write_nolock() - no lock write handler __generic_file_aio_write_nolock() - internal worker routine Signed-off-by: Badari Pulavarty Signed-off-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/raw.c | 15 ++------ fs/adfs/file.c | 6 ++-- fs/affs/file.c | 6 ++-- fs/bfs/file.c | 6 ++-- fs/block_dev.c | 12 ++----- fs/ext2/file.c | 4 +-- fs/fuse/file.c | 6 ++-- fs/hfs/inode.c | 6 ++-- fs/hfsplus/inode.c | 6 ++-- fs/hostfs/hostfs_kern.c | 4 +-- fs/hpfs/file.c | 6 ++-- fs/jffs/inode-v23.c | 6 ++-- fs/jffs2/file.c | 6 ++-- fs/jfs/file.c | 4 +-- fs/minix/file.c | 6 ++-- fs/ntfs/file.c | 2 +- fs/qnx4/file.c | 6 ++-- fs/ramfs/file-mmu.c | 6 ++-- fs/ramfs/file-nommu.c | 6 ++-- fs/read_write.c | 3 +- fs/smbfs/file.c | 24 ++++++++----- fs/sysv/file.c | 6 ++-- fs/udf/file.c | 16 +++++---- fs/ufs/file.c | 6 ++-- fs/xfs/linux-2.6/xfs_lrw.c | 4 ++- include/linux/fs.h | 5 --- mm/filemap.c | 87 +++------------------------------------------- 27 files changed, 105 insertions(+), 165 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 490db531e2d8..89b718e326e5 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -238,21 +238,10 @@ out: return err; } -static ssize_t raw_file_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct iovec local_iov = { - .iov_base = (char __user *)buf, - .iov_len = count - }; - - return generic_file_write_nolock(file, &local_iov, 1, ppos); -} - static const struct file_operations raw_fops = { - .read = generic_file_read, + .read = do_sync_read, .aio_read = generic_file_aio_read, - .write = raw_file_write, + .write = do_sync_write, .aio_write = generic_file_aio_write_nolock, .open = raw_open, .release= raw_release, diff --git a/fs/adfs/file.c b/fs/adfs/file.c index 1014b9f2117b..6101ea679cb1 100644 --- a/fs/adfs/file.c +++ b/fs/adfs/file.c @@ -27,10 +27,12 @@ const struct file_operations adfs_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, + .read = do_sync_read, + .aio_read = generic_file_aio_read, .mmap = generic_file_mmap, .fsync = file_fsync, - .write = generic_file_write, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .sendfile = generic_file_sendfile, }; diff --git a/fs/affs/file.c b/fs/affs/file.c index 3de8590e4f6a..05b5e22de759 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -27,8 +27,10 @@ static int affs_file_release(struct inode *inode, struct file *filp); const struct file_operations affs_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .open = affs_file_open, .release = affs_file_release, diff --git a/fs/bfs/file.c b/fs/bfs/file.c index 3d5aca28a0a0..a9164a87f8de 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -19,8 +19,10 @@ const struct file_operations bfs_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .sendfile = generic_file_sendfile, }; diff --git a/fs/block_dev.c b/fs/block_dev.c index 0f143094ef1d..bc8f27cc4483 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1154,14 +1154,6 @@ static int blkdev_close(struct inode * inode, struct file * filp) return blkdev_put(bdev); } -static ssize_t blkdev_file_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count }; - - return generic_file_write_nolock(file, &local_iov, 1, ppos); -} - static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) { return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); @@ -1181,8 +1173,8 @@ const struct file_operations def_blk_fops = { .open = blkdev_open, .release = blkdev_close, .llseek = block_llseek, - .read = generic_file_read, - .write = blkdev_file_write, + .read = do_sync_read, + .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write_nolock, .mmap = generic_file_mmap, diff --git a/fs/ext2/file.c b/fs/ext2/file.c index e893e2be9ed4..2dba473c524a 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -41,8 +41,8 @@ static int ext2_release_file (struct inode * inode, struct file * filp) */ const struct file_operations ext2_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, .ioctl = ext2_ioctl, diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 5c4fcd1dbf59..183626868eea 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -753,8 +753,10 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) static const struct file_operations fuse_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .mmap = fuse_file_mmap, .open = fuse_open, .flush = fuse_flush, diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index d05641c35fc9..02f5573e0349 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -601,8 +601,10 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) static const struct file_operations hfs_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .sendfile = generic_file_sendfile, .fsync = file_fsync, diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 0eb1a6092668..9e3675249633 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -282,8 +282,10 @@ static struct inode_operations hfsplus_file_inode_operations = { static const struct file_operations hfsplus_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .sendfile = generic_file_sendfile, .fsync = file_fsync, diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 4908c38a5885..b6bd33ca3731 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -385,11 +385,11 @@ int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync) static const struct file_operations hostfs_file_fops = { .llseek = generic_file_llseek, - .read = generic_file_read, + .read = do_sync_read, .sendfile = generic_file_sendfile, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, - .write = generic_file_write, + .write = do_sync_write, .mmap = generic_file_mmap, .open = hostfs_file_open, .release = NULL, diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index d9eb19b7b8ae..8b94d24855f0 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -113,7 +113,7 @@ static ssize_t hpfs_file_write(struct file *file, const char __user *buf, { ssize_t retval; - retval = generic_file_write(file, buf, count, ppos); + retval = do_sync_write(file, buf, count, ppos); if (retval > 0) hpfs_i(file->f_dentry->d_inode)->i_dirty = 1; return retval; @@ -122,8 +122,10 @@ static ssize_t hpfs_file_write(struct file *file, const char __user *buf, const struct file_operations hpfs_file_ops = { .llseek = generic_file_llseek, - .read = generic_file_read, + .read = do_sync_read, + .aio_read = generic_file_aio_read, .write = hpfs_file_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .release = hpfs_file_release, .fsync = hpfs_file_fsync, diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index f5cf9c93e243..068ef0de8de2 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -1632,8 +1632,10 @@ static const struct file_operations jffs_file_operations = { .open = generic_file_open, .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .ioctl = jffs_ioctl, .mmap = generic_file_readonly_mmap, .fsync = jffs_fsync, diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 3ed6e3e120b6..242875f77cb3 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -42,8 +42,10 @@ const struct file_operations jffs2_file_operations = { .llseek = generic_file_llseek, .open = generic_file_open, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .ioctl = jffs2_ioctl, .mmap = generic_file_readonly_mmap, .fsync = jffs2_fsync, diff --git a/fs/jfs/file.c b/fs/jfs/file.c index f535f2911c12..976e90dc2d1b 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -103,8 +103,8 @@ struct inode_operations jfs_file_inode_operations = { const struct file_operations jfs_file_operations = { .open = jfs_open, .llseek = generic_file_llseek, - .write = generic_file_write, - .read = generic_file_read, + .write = do_sync_write, + .read = do_sync_read, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, diff --git a/fs/minix/file.c b/fs/minix/file.c index 420b32882a10..40eac2e60d25 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c @@ -17,8 +17,10 @@ int minix_sync_file(struct file *, struct dentry *, int); const struct file_operations minix_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .fsync = minix_sync_file, .sendfile = generic_file_sendfile, diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 2f9b5a0953ff..ae2fe0016d2c 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -2296,7 +2296,7 @@ static int ntfs_file_fsync(struct file *filp, struct dentry *dentry, const struct file_operations ntfs_file_ops = { .llseek = generic_file_llseek, /* Seek inside file. */ - .read = generic_file_read, /* Read from file. */ + .read = do_sync_read, /* Read from file. */ .aio_read = generic_file_aio_read, /* Async read from file. */ #ifdef NTFS_RW .write = ntfs_file_write, /* Write to file. */ diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c index 62af4b1348bd..467e5ac7280e 100644 --- a/fs/qnx4/file.c +++ b/fs/qnx4/file.c @@ -22,11 +22,13 @@ const struct file_operations qnx4_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, + .read = do_sync_read, + .aio_read = generic_file_aio_read, .mmap = generic_file_mmap, .sendfile = generic_file_sendfile, #ifdef CONFIG_QNX4FS_RW - .write = generic_file_write, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .fsync = qnx4_sync_file, #endif }; diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c index 86f14cacf641..0947fb57dcf3 100644 --- a/fs/ramfs/file-mmu.c +++ b/fs/ramfs/file-mmu.c @@ -33,8 +33,10 @@ const struct address_space_operations ramfs_aops = { }; const struct file_operations ramfs_file_operations = { - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .fsync = simple_sync_file, .sendfile = generic_file_sendfile, diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index 677139b48e00..bfe5dbf1002e 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -36,8 +36,10 @@ const struct address_space_operations ramfs_aops = { const struct file_operations ramfs_file_operations = { .mmap = ramfs_nommu_mmap, .get_unmapped_area = ramfs_nommu_get_unmapped_area, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .fsync = simple_sync_file, .sendfile = generic_file_sendfile, .llseek = generic_file_llseek, diff --git a/fs/read_write.c b/fs/read_write.c index 32d54cca9bd9..4ed839bcb91c 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -22,7 +22,8 @@ const struct file_operations generic_ro_fops = { .llseek = generic_file_llseek, - .read = generic_file_read, + .read = do_sync_read, + .aio_read = generic_file_aio_read, .mmap = generic_file_readonly_mmap, .sendfile = generic_file_sendfile, }; diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index dae67048baba..50784d13c87b 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -214,13 +214,15 @@ smb_updatepage(struct file *file, struct page *page, unsigned long offset, } static ssize_t -smb_file_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) +smb_file_aio_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { + struct file * file = iocb->ki_filp; struct dentry * dentry = file->f_dentry; ssize_t status; VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry), - (unsigned long) count, (unsigned long) *ppos); + (unsigned long) iocb->ki_left, (unsigned long) pos); status = smb_revalidate_inode(dentry); if (status) { @@ -233,7 +235,7 @@ smb_file_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) (long)dentry->d_inode->i_size, dentry->d_inode->i_flags, dentry->d_inode->i_atime); - status = generic_file_read(file, buf, count, ppos); + status = generic_file_aio_read(iocb, iov, nr_segs, pos); out: return status; } @@ -317,14 +319,16 @@ const struct address_space_operations smb_file_aops = { * Write to a file (through the page cache). */ static ssize_t -smb_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +smb_file_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { + struct file * file = iocb->ki_filp; struct dentry * dentry = file->f_dentry; ssize_t result; VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry), - (unsigned long) count, (unsigned long) *ppos); + (unsigned long) iocb->ki_left, (unsigned long) pos); result = smb_revalidate_inode(dentry); if (result) { @@ -337,8 +341,8 @@ smb_file_write(struct file *file, const char __user *buf, size_t count, loff_t * if (result) goto out; - if (count > 0) { - result = generic_file_write(file, buf, count, ppos); + if (iocb->ki_left > 0) { + result = generic_file_aio_write(iocb, iov, nr_segs, pos); VERBOSE("pos=%ld, size=%ld, mtime=%ld, atime=%ld\n", (long) file->f_pos, (long) dentry->d_inode->i_size, dentry->d_inode->i_mtime, dentry->d_inode->i_atime); @@ -402,8 +406,10 @@ smb_file_permission(struct inode *inode, int mask, struct nameidata *nd) const struct file_operations smb_file_operations = { .llseek = remote_llseek, - .read = smb_file_read, - .write = smb_file_write, + .read = do_sync_read, + .aio_read = smb_file_aio_read, + .write = do_sync_write, + .aio_write = smb_file_aio_write, .ioctl = smb_ioctl, .mmap = smb_file_mmap, .open = smb_file_open, diff --git a/fs/sysv/file.c b/fs/sysv/file.c index a59e303135fa..47a4b728f15b 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -21,8 +21,10 @@ */ const struct file_operations sysv_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .fsync = sysv_sync_file, .sendfile = generic_file_sendfile, diff --git a/fs/udf/file.c b/fs/udf/file.c index a59e5f33daf6..7aedd552cba1 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -103,19 +103,21 @@ const struct address_space_operations udf_adinicb_aops = { .commit_write = udf_adinicb_commit_write, }; -static ssize_t udf_file_write(struct file * file, const char __user * buf, - size_t count, loff_t *ppos) +static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t ppos) { ssize_t retval; + struct file *file = iocb->ki_filp; struct inode *inode = file->f_dentry->d_inode; int err, pos; + size_t count = iocb->ki_left; if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) { if (file->f_flags & O_APPEND) pos = inode->i_size; else - pos = *ppos; + pos = ppos; if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) + pos + count)) @@ -136,7 +138,7 @@ static ssize_t udf_file_write(struct file * file, const char __user * buf, } } - retval = generic_file_write(file, buf, count, ppos); + retval = generic_file_aio_write(iocb, iov, nr_segs, ppos); if (retval > 0) mark_inode_dirty(inode); @@ -249,11 +251,13 @@ static int udf_release_file(struct inode * inode, struct file * filp) } const struct file_operations udf_file_operations = { - .read = generic_file_read, + .read = do_sync_read, + .aio_read = generic_file_aio_read, .ioctl = udf_ioctl, .open = generic_file_open, .mmap = generic_file_mmap, - .write = udf_file_write, + .write = do_sync_write, + .aio_write = udf_file_aio_write, .release = udf_release_file, .fsync = udf_fsync_file, .sendfile = generic_file_sendfile, diff --git a/fs/ufs/file.c b/fs/ufs/file.c index a9c6e5f04fae..1e096323bad4 100644 --- a/fs/ufs/file.c +++ b/fs/ufs/file.c @@ -53,8 +53,10 @@ static int ufs_sync_file(struct file *file, struct dentry *dentry, int datasync) const struct file_operations ufs_file_operations = { .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .open = generic_file_open, .fsync = ufs_sync_file, diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 55992b40353c..fa842f1c9fa2 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -279,7 +279,9 @@ xfs_read( xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, (void *)iovp, segs, *offset, ioflags); - ret = __generic_file_aio_read(iocb, iovp, segs, offset); + + iocb->ki_pos = *offset; + ret = generic_file_aio_read(iocb, iovp, segs, *offset); if (ret == -EIOCBQUEUED && !(ioflags & IO_ISAIO)) ret = wait_on_sync_kiocb(iocb); if (ret > 0) diff --git a/include/linux/fs.h b/include/linux/fs.h index afb6e6f89a01..011129f8803e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1699,11 +1699,8 @@ extern int generic_file_mmap(struct file *, struct vm_area_struct *); extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *); extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); extern int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); -extern ssize_t generic_file_read(struct file *, char __user *, size_t, loff_t *); int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk); -extern ssize_t generic_file_write(struct file *, const char __user *, size_t, loff_t *); extern ssize_t generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t); -extern ssize_t __generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t *); extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t); extern ssize_t generic_file_aio_write_nolock(struct kiocb *, const struct iovec *, unsigned long, loff_t); @@ -1713,8 +1710,6 @@ extern ssize_t generic_file_buffered_write(struct kiocb *, const struct iovec *, unsigned long, loff_t, loff_t *, size_t, ssize_t); extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); -ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos); extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *); extern void do_generic_mapping_read(struct address_space *mapping, struct file_ra_state *, struct file *, diff --git a/mm/filemap.c b/mm/filemap.c index 48497094ae83..ec469235985d 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1149,13 +1149,14 @@ success: * that can use the page cache directly. */ ssize_t -__generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) +generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) { struct file *filp = iocb->ki_filp; ssize_t retval; unsigned long seg; size_t count; + loff_t *ppos = &iocb->ki_pos; count = 0; for (seg = 0; seg < nr_segs; seg++) { @@ -1179,7 +1180,7 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ if (filp->f_flags & O_DIRECT) { - loff_t pos = *ppos, size; + loff_t size; struct address_space *mapping; struct inode *inode; @@ -1223,32 +1224,8 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, out: return retval; } -EXPORT_SYMBOL(__generic_file_aio_read); - -ssize_t -generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) -{ - BUG_ON(iocb->ki_pos != pos); - return __generic_file_aio_read(iocb, iov, nr_segs, &iocb->ki_pos); -} EXPORT_SYMBOL(generic_file_aio_read); -ssize_t -generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) -{ - struct iovec local_iov = { .iov_base = buf, .iov_len = count }; - struct kiocb kiocb; - ssize_t ret; - - init_sync_kiocb(&kiocb, filp); - ret = __generic_file_aio_read(&kiocb, &local_iov, 1, ppos); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&kiocb); - return ret; -} -EXPORT_SYMBOL(generic_file_read); - int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) { ssize_t written; @@ -2339,38 +2316,6 @@ ssize_t generic_file_aio_write_nolock(struct kiocb *iocb, } EXPORT_SYMBOL(generic_file_aio_write_nolock); -static ssize_t -__generic_file_write_nolock(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct kiocb kiocb; - ssize_t ret; - - init_sync_kiocb(&kiocb, file); - kiocb.ki_pos = *ppos; - ret = __generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&kiocb); - return ret; -} - -ssize_t -generic_file_write_nolock(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct kiocb kiocb; - ssize_t ret; - - init_sync_kiocb(&kiocb, file); - kiocb.ki_pos = *ppos; - ret = generic_file_aio_write_nolock(&kiocb, iov, nr_segs, *ppos); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&kiocb); - *ppos = kiocb.ki_pos; - return ret; -} -EXPORT_SYMBOL(generic_file_write_nolock); - ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { @@ -2397,30 +2342,6 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, } EXPORT_SYMBOL(generic_file_aio_write); -ssize_t generic_file_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - ssize_t ret; - struct iovec local_iov = { .iov_base = (void __user *)buf, - .iov_len = count }; - - mutex_lock(&inode->i_mutex); - ret = __generic_file_write_nolock(file, &local_iov, 1, ppos); - mutex_unlock(&inode->i_mutex); - - if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { - ssize_t err; - - err = sync_page_range(inode, mapping, *ppos - ret, ret); - if (err < 0) - ret = err; - } - return ret; -} -EXPORT_SYMBOL(generic_file_write); - /* * Called under i_mutex for writes to S_ISREG files. Returns -EIO if something * went wrong during pagecache shootdown. -- cgit v1.2.3 From eed4e51fb60c3863c134a5e9f6006b29805ead97 Mon Sep 17 00:00:00 2001 From: Badari Pulavarty Date: Sat, 30 Sep 2006 23:28:49 -0700 Subject: [PATCH] Add vector AIO support This work is initially done by Zach Brown to add support for vectored aio. These are the core changes for AIO to support IOCB_CMD_PREADV/IOCB_CMD_PWRITEV. [akpm@osdl.org: huge build fix] Signed-off-by: Zach Brown Signed-off-by: Christoph Hellwig Signed-off-by: Badari Pulavarty Acked-by: Benjamin LaHaise Acked-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/aio.c | 171 +++++++++++++++++++++++++++++++++--------------- fs/read_write.c | 129 +++++++++++++++++++++--------------- include/linux/aio.h | 4 ++ include/linux/aio_abi.h | 2 + include/linux/fs.h | 5 ++ 5 files changed, 203 insertions(+), 108 deletions(-) (limited to 'include/linux') diff --git a/fs/aio.c b/fs/aio.c index 27ff56540c73..2e0d1505ee36 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -415,6 +415,7 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx) req->ki_retry = NULL; req->ki_dtor = NULL; req->private = NULL; + req->ki_iovec = NULL; INIT_LIST_HEAD(&req->ki_run_list); /* Check if the completion queue has enough free space to @@ -460,6 +461,8 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) if (req->ki_dtor) req->ki_dtor(req); + if (req->ki_iovec != &req->ki_inline_vec) + kfree(req->ki_iovec); kmem_cache_free(kiocb_cachep, req); ctx->reqs_active--; @@ -1301,69 +1304,63 @@ asmlinkage long sys_io_destroy(aio_context_t ctx) return -EINVAL; } -/* - * aio_p{read,write} are the default ki_retry methods for - * IO_CMD_P{READ,WRITE}. They maintains kiocb retry state around potentially - * multiple calls to f_op->aio_read(). They loop around partial progress - * instead of returning -EIOCBRETRY because they don't have the means to call - * kick_iocb(). - */ -static ssize_t aio_pread(struct kiocb *iocb) +static void aio_advance_iovec(struct kiocb *iocb, ssize_t ret) { - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - ssize_t ret = 0; - - do { - iocb->ki_inline_vec.iov_base = iocb->ki_buf; - iocb->ki_inline_vec.iov_len = iocb->ki_left; - - ret = file->f_op->aio_read(iocb, &iocb->ki_inline_vec, - 1, iocb->ki_pos); - /* - * Can't just depend on iocb->ki_left to determine - * whether we are done. This may have been a short read. - */ - if (ret > 0) { - iocb->ki_buf += ret; - iocb->ki_left -= ret; + struct iovec *iov = &iocb->ki_iovec[iocb->ki_cur_seg]; + + BUG_ON(ret <= 0); + + while (iocb->ki_cur_seg < iocb->ki_nr_segs && ret > 0) { + ssize_t this = min((ssize_t)iov->iov_len, ret); + iov->iov_base += this; + iov->iov_len -= this; + iocb->ki_left -= this; + ret -= this; + if (iov->iov_len == 0) { + iocb->ki_cur_seg++; + iov++; } + } - /* - * For pipes and sockets we return once we have some data; for - * regular files we retry till we complete the entire read or - * find that we can't read any more data (e.g short reads). - */ - } while (ret > 0 && iocb->ki_left > 0 && - !S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode)); - - /* This means we must have transferred all that we could */ - /* No need to retry anymore */ - if ((ret == 0) || (iocb->ki_left == 0)) - ret = iocb->ki_nbytes - iocb->ki_left; - - return ret; + /* the caller should not have done more io than what fit in + * the remaining iovecs */ + BUG_ON(ret > 0 && iocb->ki_left == 0); } -/* see aio_pread() */ -static ssize_t aio_pwrite(struct kiocb *iocb) +static ssize_t aio_rw_vect_retry(struct kiocb *iocb) { struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + ssize_t (*rw_op)(struct kiocb *, const struct iovec *, + unsigned long, loff_t); ssize_t ret = 0; + unsigned short opcode; + + if ((iocb->ki_opcode == IOCB_CMD_PREADV) || + (iocb->ki_opcode == IOCB_CMD_PREAD)) { + rw_op = file->f_op->aio_read; + opcode = IOCB_CMD_PREADV; + } else { + rw_op = file->f_op->aio_write; + opcode = IOCB_CMD_PWRITEV; + } do { - iocb->ki_inline_vec.iov_base = iocb->ki_buf; - iocb->ki_inline_vec.iov_len = iocb->ki_left; - - ret = file->f_op->aio_write(iocb, &iocb->ki_inline_vec, - 1, iocb->ki_pos); - if (ret > 0) { - iocb->ki_buf += ret; - iocb->ki_left -= ret; - } - } while (ret > 0 && iocb->ki_left > 0); + ret = rw_op(iocb, &iocb->ki_iovec[iocb->ki_cur_seg], + iocb->ki_nr_segs - iocb->ki_cur_seg, + iocb->ki_pos); + if (ret > 0) + aio_advance_iovec(iocb, ret); + + /* retry all partial writes. retry partial reads as long as its a + * regular file. */ + } while (ret > 0 && iocb->ki_left > 0 && + (opcode == IOCB_CMD_PWRITEV || + (!S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode)))); + /* This means we must have transferred all that we could */ + /* No need to retry anymore */ if ((ret == 0) || (iocb->ki_left == 0)) ret = iocb->ki_nbytes - iocb->ki_left; @@ -1390,6 +1387,38 @@ static ssize_t aio_fsync(struct kiocb *iocb) return ret; } +static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb) +{ + ssize_t ret; + + ret = rw_copy_check_uvector(type, (struct iovec __user *)kiocb->ki_buf, + kiocb->ki_nbytes, 1, + &kiocb->ki_inline_vec, &kiocb->ki_iovec); + if (ret < 0) + goto out; + + kiocb->ki_nr_segs = kiocb->ki_nbytes; + kiocb->ki_cur_seg = 0; + /* ki_nbytes/left now reflect bytes instead of segs */ + kiocb->ki_nbytes = ret; + kiocb->ki_left = ret; + + ret = 0; +out: + return ret; +} + +static ssize_t aio_setup_single_vector(struct kiocb *kiocb) +{ + kiocb->ki_iovec = &kiocb->ki_inline_vec; + kiocb->ki_iovec->iov_base = kiocb->ki_buf; + kiocb->ki_iovec->iov_len = kiocb->ki_left; + kiocb->ki_nr_segs = 1; + kiocb->ki_cur_seg = 0; + kiocb->ki_nbytes = kiocb->ki_left; + return 0; +} + /* * aio_setup_iocb: * Performs the initial checks and aio retry method @@ -1412,9 +1441,12 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb) ret = security_file_permission(file, MAY_READ); if (unlikely(ret)) break; + ret = aio_setup_single_vector(kiocb); + if (ret) + break; ret = -EINVAL; if (file->f_op->aio_read) - kiocb->ki_retry = aio_pread; + kiocb->ki_retry = aio_rw_vect_retry; break; case IOCB_CMD_PWRITE: ret = -EBADF; @@ -1427,9 +1459,40 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb) ret = security_file_permission(file, MAY_WRITE); if (unlikely(ret)) break; + ret = aio_setup_single_vector(kiocb); + if (ret) + break; + ret = -EINVAL; + if (file->f_op->aio_write) + kiocb->ki_retry = aio_rw_vect_retry; + break; + case IOCB_CMD_PREADV: + ret = -EBADF; + if (unlikely(!(file->f_mode & FMODE_READ))) + break; + ret = security_file_permission(file, MAY_READ); + if (unlikely(ret)) + break; + ret = aio_setup_vectored_rw(READ, kiocb); + if (ret) + break; + ret = -EINVAL; + if (file->f_op->aio_read) + kiocb->ki_retry = aio_rw_vect_retry; + break; + case IOCB_CMD_PWRITEV: + ret = -EBADF; + if (unlikely(!(file->f_mode & FMODE_WRITE))) + break; + ret = security_file_permission(file, MAY_WRITE); + if (unlikely(ret)) + break; + ret = aio_setup_vectored_rw(WRITE, kiocb); + if (ret) + break; ret = -EINVAL; if (file->f_op->aio_write) - kiocb->ki_retry = aio_pwrite; + kiocb->ki_retry = aio_rw_vect_retry; break; case IOCB_CMD_FDSYNC: ret = -EINVAL; diff --git a/fs/read_write.c b/fs/read_write.c index 4ed839bcb91c..f792000a28e6 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -511,6 +511,74 @@ ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, /* A write operation does a read from user space and vice versa */ #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) +ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, + unsigned long nr_segs, unsigned long fast_segs, + struct iovec *fast_pointer, + struct iovec **ret_pointer) + { + unsigned long seg; + ssize_t ret; + struct iovec *iov = fast_pointer; + + /* + * SuS says "The readv() function *may* fail if the iovcnt argument + * was less than or equal to 0, or greater than {IOV_MAX}. Linux has + * traditionally returned zero for zero segments, so... + */ + if (nr_segs == 0) { + ret = 0; + goto out; + } + + /* + * First get the "struct iovec" from user memory and + * verify all the pointers + */ + if (nr_segs > UIO_MAXIOV) { + ret = -EINVAL; + goto out; + } + if (nr_segs > fast_segs) { + iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); + if (iov == NULL) { + ret = -ENOMEM; + goto out; + } + } + if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) { + ret = -EFAULT; + goto out; + } + + /* + * According to the Single Unix Specification we should return EINVAL + * if an element length is < 0 when cast to ssize_t or if the + * total length would overflow the ssize_t return value of the + * system call. + */ + ret = 0; + for (seg = 0; seg < nr_segs; seg++) { + void __user *buf = iov[seg].iov_base; + ssize_t len = (ssize_t)iov[seg].iov_len; + + /* see if we we're about to use an invalid len or if + * it's about to overflow ssize_t */ + if (len < 0 || (ret + len < ret)) { + ret = -EINVAL; + goto out; + } + if (unlikely(!access_ok(vrfy_dir(type), buf, len))) { + ret = -EFAULT; + goto out; + } + + ret += len; + } +out: + *ret_pointer = iov; + return ret; +} + static ssize_t do_readv_writev(int type, struct file *file, const struct iovec __user * uvector, unsigned long nr_segs, loff_t *pos) @@ -519,64 +587,20 @@ static ssize_t do_readv_writev(int type, struct file *file, struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov = iovstack; ssize_t ret; - int seg; io_fn_t fn; iov_fn_t fnv; - /* - * SuS says "The readv() function *may* fail if the iovcnt argument - * was less than or equal to 0, or greater than {IOV_MAX}. Linux has - * traditionally returned zero for zero segments, so... - */ - ret = 0; - if (nr_segs == 0) - goto out; - - /* - * First get the "struct iovec" from user memory and - * verify all the pointers - */ - ret = -EINVAL; - if (nr_segs > UIO_MAXIOV) - goto out; - if (!file->f_op) - goto out; - if (nr_segs > UIO_FASTIOV) { - ret = -ENOMEM; - iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); - if (!iov) - goto out; - } - ret = -EFAULT; - if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) + if (!file->f_op) { + ret = -EINVAL; goto out; + } - /* - * Single unix specification: - * We should -EINVAL if an element length is not >= 0 and fitting an - * ssize_t. The total length is fitting an ssize_t - * - * Be careful here because iov_len is a size_t not an ssize_t - */ - tot_len = 0; - ret = -EINVAL; - for (seg = 0; seg < nr_segs; seg++) { - void __user *buf = iov[seg].iov_base; - ssize_t len = (ssize_t)iov[seg].iov_len; - - if (len < 0) /* size_t not fitting an ssize_t .. */ - goto out; - if (unlikely(!access_ok(vrfy_dir(type), buf, len))) - goto Efault; - tot_len += len; - if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */ - goto out; - } - if (tot_len == 0) { - ret = 0; + ret = rw_copy_check_uvector(type, uvector, nr_segs, + ARRAY_SIZE(iovstack), iovstack, &iov); + if (ret <= 0) goto out; - } + tot_len = ret; ret = rw_verify_area(type, file, pos, tot_len); if (ret < 0) goto out; @@ -609,9 +633,6 @@ out: fsnotify_modify(file->f_dentry); } return ret; -Efault: - ret = -EFAULT; - goto out; } ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, diff --git a/include/linux/aio.h b/include/linux/aio.h index 58349e58b749..5722568fc71e 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -7,6 +7,7 @@ #include #include +#include #define AIO_MAXSEGS 4 #define AIO_KIOGRP_NR_ATOMIC 8 @@ -114,6 +115,9 @@ struct kiocb { long ki_kicked; /* just for testing */ long ki_queued; /* just for testing */ struct iovec ki_inline_vec; /* inline vector */ + struct iovec *ki_iovec; + unsigned long ki_nr_segs; + unsigned long ki_cur_seg; struct list_head ki_list; /* the aio core uses this * for cancellation */ diff --git a/include/linux/aio_abi.h b/include/linux/aio_abi.h index 30fdcc89d142..3466b1d0ffd2 100644 --- a/include/linux/aio_abi.h +++ b/include/linux/aio_abi.h @@ -41,6 +41,8 @@ enum { * IOCB_CMD_POLL = 5, */ IOCB_CMD_NOOP = 6, + IOCB_CMD_PREADV = 7, + IOCB_CMD_PWRITEV = 8, }; /* read() from /dev/aio returns these structures. */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 011129f8803e..4bb70871873f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1150,6 +1150,11 @@ struct inode_operations { struct seq_file; +ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, + unsigned long nr_segs, unsigned long fast_segs, + struct iovec *fast_pointer, + struct iovec **ret_pointer); + extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *); extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *); extern ssize_t vfs_readv(struct file *, const struct iovec __user *, -- cgit v1.2.3 From 31608214fe21dc31d8046679054ab033b1fe5cf1 Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" Date: Sat, 30 Sep 2006 23:28:50 -0700 Subject: [PATCH] clean up unused kiocb variables Signed-off-by: Ken Chen Acked-by: Zach Brown Cc: Suparna Bhattacharya Cc: Benjamin LaHaise Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/aio.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/aio.h b/include/linux/aio.h index 5722568fc71e..0d71c0041f13 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -112,8 +112,6 @@ struct kiocb { char __user *ki_buf; /* remaining iocb->aio_buf */ size_t ki_left; /* remaining bytes */ long ki_retried; /* just for testing */ - long ki_kicked; /* just for testing */ - long ki_queued; /* just for testing */ struct iovec ki_inline_vec; /* inline vector */ struct iovec *ki_iovec; unsigned long ki_nr_segs; -- cgit v1.2.3 From f3cef7a99469afc159fec3a61b42dc7ca5b6824f Mon Sep 17 00:00:00 2001 From: Jay Lan Date: Sat, 30 Sep 2006 23:28:55 -0700 Subject: [PATCH] csa: basic accounting over taskstats Add some basic accounting fields to the taskstats struct, add a new kernel/tsacct.c to handle basic accounting data handling upon exit. A handle is added to taskstats.c to invoke the basic accounting data handling. Signed-off-by: Jay Lan Cc: Shailabh Nagar Cc: Balbir Singh Cc: Jes Sorensen Cc: Chris Sturtivant Cc: Tony Ernst Cc: Guillaume Thouvenin Cc: "Michal Piotrowski" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/taskstats.h | 29 ++++++++++++++---- include/linux/tsacct_kern.h | 19 ++++++++++++ kernel/Makefile | 2 +- kernel/taskstats.c | 4 +++ kernel/tsacct.c | 72 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 include/linux/tsacct_kern.h create mode 100644 kernel/tsacct.c (limited to 'include/linux') diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h index f1cb6cddd19d..af93a63a5092 100644 --- a/include/linux/taskstats.h +++ b/include/linux/taskstats.h @@ -2,6 +2,7 @@ * * Copyright (C) Shailabh Nagar, IBM Corp. 2006 * (C) Balbir Singh, IBM Corp. 2006 + * (C) Jay Lan, SGI, 2006 * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2.1 of the GNU Lesser General Public License @@ -29,16 +30,18 @@ * c) add new fields after version comment; maintain 64-bit alignment */ -#define TASKSTATS_VERSION 1 + +#define TASKSTATS_VERSION 2 +#define TS_COMM_LEN 16 /* should sync up with TASK_COMM_LEN + * in linux/sched.h */ struct taskstats { /* Version 1 */ __u16 version; - __u16 padding[3]; /* Userspace should not interpret the padding - * field which can be replaced by useful - * fields if struct taskstats is extended. - */ + __u32 ac_exitcode; /* Exit status */ + __u8 ac_flag; /* Record flags */ + __u8 ac_nice; /* task_nice */ /* Delay accounting fields start * @@ -88,6 +91,22 @@ struct taskstats { __u64 cpu_run_virtual_total; /* Delay accounting fields end */ /* version 1 ends here */ + + /* Basic Accounting Fields start */ + char ac_comm[TS_COMM_LEN]; /* Command name */ + __u8 ac_sched; /* Scheduling discipline */ + __u8 ac_pad[3]; + __u32 ac_uid; /* User ID */ + __u32 ac_gid; /* Group ID */ + __u32 ac_pid; /* Process ID */ + __u32 ac_ppid; /* Parent process ID */ + __u32 ac_btime; /* Begin time [sec since 1970] */ + __u64 ac_etime; /* Elapsed time [usec] */ + __u64 ac_utime; /* User CPU time [usec] */ + __u64 ac_stime; /* SYstem CPU time [usec] */ + __u64 ac_minflt; /* Minor Page Fault */ + __u64 ac_majflt; /* Major Page Fault */ + /* Basic Accounting Fields end */ }; diff --git a/include/linux/tsacct_kern.h b/include/linux/tsacct_kern.h new file mode 100644 index 000000000000..7e8196a02118 --- /dev/null +++ b/include/linux/tsacct_kern.h @@ -0,0 +1,19 @@ +/* + * tsacct_kern.h - kernel header for system accounting over taskstats interface + * + * Copyright (C) Jay Lan SGI + */ + +#ifndef _LINUX_TSACCT_KERN_H +#define _LINUX_TSACCT_KERN_H + +#include + +#ifdef CONFIG_TASKSTATS +extern void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk); +#else +static inline void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk) +{} +#endif /* CONFIG_TASKSTATS */ + +#endif diff --git a/kernel/Makefile b/kernel/Makefile index e210e8cf7237..aacaafb28b9d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -49,7 +49,7 @@ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o -obj-$(CONFIG_TASKSTATS) += taskstats.o +obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff --git a/kernel/taskstats.c b/kernel/taskstats.c index c451af2ddb50..6c38dce88e8c 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -198,7 +199,10 @@ static int fill_pid(pid_t pid, struct task_struct *pidtsk, */ delayacct_add_tsk(stats, tsk); + + /* fill in basic acct fields */ stats->version = TASKSTATS_VERSION; + bacct_add_tsk(stats, tsk); /* Define err: label here if needed */ put_task_struct(tsk); diff --git a/kernel/tsacct.c b/kernel/tsacct.c new file mode 100644 index 000000000000..899067950a88 --- /dev/null +++ b/kernel/tsacct.c @@ -0,0 +1,72 @@ +/* + * tsacct.c - System accounting over taskstats interface + * + * Copyright (C) Jay Lan, + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + + +#define USEC_PER_TICK (USEC_PER_SEC/HZ) +/* + * fill in basic accounting fields + */ +void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk) +{ + struct timespec uptime, ts; + s64 ac_etime; + + BUILD_BUG_ON(TS_COMM_LEN < TASK_COMM_LEN); + + /* calculate task elapsed time in timespec */ + do_posix_clock_monotonic_gettime(&uptime); + ts = timespec_sub(uptime, current->group_leader->start_time); + /* rebase elapsed time to usec */ + ac_etime = timespec_to_ns(&ts); + do_div(ac_etime, NSEC_PER_USEC); + stats->ac_etime = ac_etime; + stats->ac_btime = xtime.tv_sec - ts.tv_sec; + if (thread_group_leader(tsk)) { + stats->ac_exitcode = tsk->exit_code; + if (tsk->flags & PF_FORKNOEXEC) + stats->ac_flag |= AFORK; + } + if (tsk->flags & PF_SUPERPRIV) + stats->ac_flag |= ASU; + if (tsk->flags & PF_DUMPCORE) + stats->ac_flag |= ACORE; + if (tsk->flags & PF_SIGNALED) + stats->ac_flag |= AXSIG; + stats->ac_nice = task_nice(tsk); + stats->ac_sched = tsk->policy; + stats->ac_uid = tsk->uid; + stats->ac_gid = tsk->gid; + stats->ac_pid = tsk->pid; + stats->ac_ppid = (tsk->parent) ? tsk->parent->pid : 0; + stats->ac_utime = cputime_to_msecs(tsk->utime) * USEC_PER_MSEC; + stats->ac_stime = cputime_to_msecs(tsk->stime) * USEC_PER_MSEC; + stats->ac_minflt = tsk->min_flt; + stats->ac_majflt = tsk->maj_flt; + /* Each process gets a minimum of one usec cpu time */ + if ((stats->ac_utime == 0) && (stats->ac_stime == 0)) { + stats->ac_stime = 1; + } + + strncpy(stats->ac_comm, tsk->comm, sizeof(stats->ac_comm)); +} + -- cgit v1.2.3 From 9acc1853519a0473620d424105f9d49ea5b4e62e Mon Sep 17 00:00:00 2001 From: Jay Lan Date: Sat, 30 Sep 2006 23:28:58 -0700 Subject: [PATCH] csa: Extended system accounting over taskstats Add extended system accounting handling over taskstats interface. A CONFIG_TASK_XACCT flag is created to enable the extended accounting code. Signed-off-by: Jay Lan Cc: Shailabh Nagar Cc: Balbir Singh Cc: Jes Sorensen Cc: Chris Sturtivant Cc: Tony Ernst Cc: Guillaume Thouvenin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/taskstats.h | 11 +++++++++++ include/linux/tsacct_kern.h | 9 +++++++++ init/Kconfig | 9 +++++++++ kernel/taskstats.c | 4 ++++ kernel/tsacct.c | 19 +++++++++++++++++++ 5 files changed, 52 insertions(+) (limited to 'include/linux') diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h index af93a63a5092..3d2c304886b0 100644 --- a/include/linux/taskstats.h +++ b/include/linux/taskstats.h @@ -107,6 +107,17 @@ struct taskstats { __u64 ac_minflt; /* Minor Page Fault */ __u64 ac_majflt; /* Major Page Fault */ /* Basic Accounting Fields end */ + + /* Extended accounting fields start */ + __u64 acct_rss_mem1; /* accumulated rss usage */ + __u64 acct_vm_mem1; /* accumulated virtual memory usage */ + __u64 hiwater_rss; /* High-watermark of RSS usage */ + __u64 hiwater_vm; /* High-water virtual memory usage */ + __u64 read_char; /* bytes read */ + __u64 write_char; /* bytes written */ + __u64 read_syscalls; /* read syscalls */ + __u64 write_syscalls; /* write syscalls */ + /* Extended accounting fields end */ }; diff --git a/include/linux/tsacct_kern.h b/include/linux/tsacct_kern.h index 7e8196a02118..74102dcae67a 100644 --- a/include/linux/tsacct_kern.h +++ b/include/linux/tsacct_kern.h @@ -16,4 +16,13 @@ static inline void bacct_add_tsk(struct taskstats *stats, struct task_struct *ts {} #endif /* CONFIG_TASKSTATS */ +#ifdef CONFIG_TASK_XACCT +extern void xacct_add_tsk(struct taskstats *stats, struct task_struct *p); +#else +static inline void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) +{} +#endif /* CONFIG_TASK_XACCT */ + #endif + + diff --git a/init/Kconfig b/init/Kconfig index d2d72704f875..f7a04d0daf07 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -257,6 +257,15 @@ config CC_OPTIMIZE_FOR_SIZE If unsure, say N. +config TASK_XACCT + bool "Enable extended accounting over taskstats (EXPERIMENTAL)" + depends on TASKSTATS + help + Collect extended task accounting data and send the data + to userland for processing over the taskstats interface. + + Say N if unsure. + config SYSCTL bool diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 6c38dce88e8c..5d6a8c54ee85 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -204,6 +205,9 @@ static int fill_pid(pid_t pid, struct task_struct *pidtsk, stats->version = TASKSTATS_VERSION; bacct_add_tsk(stats, tsk); + /* fill in extended acct fields */ + xacct_add_tsk(stats, tsk); + /* Define err: label here if needed */ put_task_struct(tsk); return rc; diff --git a/kernel/tsacct.c b/kernel/tsacct.c index 899067950a88..410483490cf6 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c @@ -70,3 +70,22 @@ void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk) strncpy(stats->ac_comm, tsk->comm, sizeof(stats->ac_comm)); } + +#ifdef CONFIG_TASK_XACCT +/* + * fill in extended accounting fields + */ +void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) +{ + stats->acct_rss_mem1 = p->acct_rss_mem1; + stats->acct_vm_mem1 = p->acct_vm_mem1; + if (p->mm) { + stats->hiwater_rss = p->mm->hiwater_rss; + stats->hiwater_vm = p->mm->hiwater_vm; + } + stats->read_char = p->rchar; + stats->write_char = p->wchar; + stats->read_syscalls = p->syscr; + stats->write_syscalls = p->syscw; +} +#endif -- cgit v1.2.3 From 8f0ab5147951267134612570604cf8341901a80c Mon Sep 17 00:00:00 2001 From: Jay Lan Date: Sat, 30 Sep 2006 23:28:59 -0700 Subject: [PATCH] csa: convert CONFIG tag for extended accounting routines There were a few accounting data/macros that are used in CSA but are #ifdef'ed inside CONFIG_BSD_PROCESS_ACCT. This patch is to change those ifdef's from CONFIG_BSD_PROCESS_ACCT to CONFIG_TASK_XACCT. A few defines are moved from kernel/acct.c and include/linux/acct.h to kernel/tsacct.c and include/linux/tsacct_kern.h. Signed-off-by: Jay Lan Cc: Shailabh Nagar Cc: Balbir Singh Cc: Jes Sorensen Cc: Chris Sturtivant Cc: Tony Ernst Cc: Guillaume Thouvenin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/compat.c | 2 +- fs/exec.c | 2 +- include/linux/acct.h | 4 ---- include/linux/sched.h | 2 +- include/linux/tsacct_kern.h | 6 ++++++ kernel/acct.c | 30 ------------------------------ kernel/exit.c | 1 + kernel/fork.c | 1 + kernel/sched.c | 2 +- kernel/tsacct.c | 30 ++++++++++++++++++++++++++++++ 10 files changed, 42 insertions(+), 38 deletions(-) (limited to 'include/linux') diff --git a/fs/compat.c b/fs/compat.c index 6b90bf35f61d..13fb08d096c4 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include /* siocdevprivate_ioctl */ diff --git a/fs/exec.c b/fs/exec.c index a8efe35176b0..0db3fc3c5f0f 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/linux/acct.h b/include/linux/acct.h index e86bae7324d2..0496d1f09952 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h @@ -124,16 +124,12 @@ extern void acct_auto_close(struct super_block *sb); extern void acct_init_pacct(struct pacct_struct *pacct); extern void acct_collect(long exitcode, int group_dead); extern void acct_process(void); -extern void acct_update_integrals(struct task_struct *tsk); -extern void acct_clear_integrals(struct task_struct *tsk); #else #define acct_auto_close_mnt(x) do { } while (0) #define acct_auto_close(x) do { } while (0) #define acct_init_pacct(x) do { } while (0) #define acct_collect(x,y) do { } while (0) #define acct_process() do { } while (0) -#define acct_update_integrals(x) do { } while (0) -#define acct_clear_integrals(task) do { } while (0) #endif /* diff --git a/include/linux/sched.h b/include/linux/sched.h index fc4a9873ec10..4ddeb0f982fb 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -981,7 +981,7 @@ struct task_struct { wait_queue_t *io_wait; /* i/o counters(bytes read/written, #syscalls */ u64 rchar, wchar, syscr, syscw; -#if defined(CONFIG_BSD_PROCESS_ACCT) +#if defined(CONFIG_TASK_XACCT) u64 acct_rss_mem1; /* accumulated rss usage */ u64 acct_vm_mem1; /* accumulated virtual memory usage */ clock_t acct_stimexpd; /* clock_t-converted stime since last update */ diff --git a/include/linux/tsacct_kern.h b/include/linux/tsacct_kern.h index 74102dcae67a..7e50ac795b0b 100644 --- a/include/linux/tsacct_kern.h +++ b/include/linux/tsacct_kern.h @@ -18,9 +18,15 @@ static inline void bacct_add_tsk(struct taskstats *stats, struct task_struct *ts #ifdef CONFIG_TASK_XACCT extern void xacct_add_tsk(struct taskstats *stats, struct task_struct *p); +extern void acct_update_integrals(struct task_struct *tsk); +extern void acct_clear_integrals(struct task_struct *tsk); #else static inline void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) {} +static inline void acct_update_integrals(struct task_struct *tsk) +{} +static inline void acct_clear_integrals(struct task_struct *tsk) +{} #endif /* CONFIG_TASK_XACCT */ #endif diff --git a/kernel/acct.c b/kernel/acct.c index f4330acead46..0aad5ca36a81 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -602,33 +602,3 @@ void acct_process(void) do_acct_process(file); fput(file); } - - -/** - * acct_update_integrals - update mm integral fields in task_struct - * @tsk: task_struct for accounting - */ -void acct_update_integrals(struct task_struct *tsk) -{ - if (likely(tsk->mm)) { - long delta = - cputime_to_jiffies(tsk->stime) - tsk->acct_stimexpd; - - if (delta == 0) - return; - tsk->acct_stimexpd = tsk->stime; - tsk->acct_rss_mem1 += delta * get_mm_rss(tsk->mm); - tsk->acct_vm_mem1 += delta * tsk->mm->total_vm; - } -} - -/** - * acct_clear_integrals - clear the mm integral fields in task_struct - * @tsk: task_struct whose accounting fields are cleared - */ -void acct_clear_integrals(struct task_struct *tsk) -{ - tsk->acct_stimexpd = 0; - tsk->acct_rss_mem1 = 0; - tsk->acct_vm_mem1 = 0; -} diff --git a/kernel/exit.c b/kernel/exit.c index c189de2927ab..3b47f26985f2 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/kernel/fork.c b/kernel/fork.c index 1c999f3e0b47..89f666491d1f 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include diff --git a/kernel/sched.c b/kernel/sched.c index 74f169ac0773..2bbd948f0169 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -49,7 +49,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/kernel/tsacct.c b/kernel/tsacct.c index 410483490cf6..47c71daa416f 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c @@ -88,4 +88,34 @@ void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) stats->read_syscalls = p->syscr; stats->write_syscalls = p->syscw; } + + +/** + * acct_update_integrals - update mm integral fields in task_struct + * @tsk: task_struct for accounting + */ +void acct_update_integrals(struct task_struct *tsk) +{ + if (likely(tsk->mm)) { + long delta = + cputime_to_jiffies(tsk->stime) - tsk->acct_stimexpd; + + if (delta == 0) + return; + tsk->acct_stimexpd = tsk->stime; + tsk->acct_rss_mem1 += delta * get_mm_rss(tsk->mm); + tsk->acct_vm_mem1 += delta * tsk->mm->total_vm; + } +} + +/** + * acct_clear_integrals - clear the mm integral fields in task_struct + * @tsk: task_struct whose accounting fields are cleared + */ +void acct_clear_integrals(struct task_struct *tsk) +{ + tsk->acct_stimexpd = 0; + tsk->acct_rss_mem1 = 0; + tsk->acct_vm_mem1 = 0; +} #endif -- cgit v1.2.3 From db5fed26b2e0beed939b773dd5896077a1794d65 Mon Sep 17 00:00:00 2001 From: Jay Lan Date: Sat, 30 Sep 2006 23:29:00 -0700 Subject: [PATCH] csa accounting taskstats update ChangeLog: Feedbacks from Andrew Morton: - define TS_COMM_LEN to 32 - change acct_stimexpd field of task_struct to be of cputime_t, which is to be used to save the tsk->stime of last timer interrupt update. - a new Documentation/accounting/taskstats-struct.txt to describe fields of taskstats struct. Feedback from Balbir Singh: - keep the stime of a task to be zero when both stime and utime are zero as recoreded in task_struct. Misc: - convert accumulated RSS/VM from platform dependent pages-ticks to MBytes-usecs in the kernel Cc: Shailabh Nagar Cc: Balbir Singh Cc: Jes Sorensen Cc: Chris Sturtivant Cc: Tony Ernst Cc: Guillaume Thouvenin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/accounting/taskstats-struct.txt | 161 ++++++++++++++++++++++++++ include/linux/sched.h | 2 +- include/linux/taskstats.h | 40 +++++-- kernel/tsacct.c | 25 ++-- 4 files changed, 207 insertions(+), 21 deletions(-) create mode 100644 Documentation/accounting/taskstats-struct.txt (limited to 'include/linux') diff --git a/Documentation/accounting/taskstats-struct.txt b/Documentation/accounting/taskstats-struct.txt new file mode 100644 index 000000000000..661c797eaf79 --- /dev/null +++ b/Documentation/accounting/taskstats-struct.txt @@ -0,0 +1,161 @@ +The struct taskstats +-------------------- + +This document contains an explanation of the struct taskstats fields. + +There are three different groups of fields in the struct taskstats: + +1) Common and basic accounting fields + If CONFIG_TASKSTATS is set, the taskstats inteface is enabled and + the common fields and basic accounting fields are collected for + delivery at do_exit() of a task. +2) Delay accounting fields + These fields are placed between + /* Delay accounting fields start */ + and + /* Delay accounting fields end */ + Their values are collected if CONFIG_TASK_DELAY_ACCT is set. +3) Extended accounting fields + These fields are placed between + /* Extended accounting fields start */ + and + /* Extended accounting fields end */ + Their values are collected if CONFIG_TASK_XACCT is set. + +Future extension should add fields to the end of the taskstats struct, and +should not change the relative position of each field within the struct. + + +struct taskstats { + +1) Common and basic accounting fields: + /* The version number of this struct. This field is always set to + * TAKSTATS_VERSION, which is defined in . + * Each time the struct is changed, the value should be incremented. + */ + __u16 version; + + /* The exit code of a task. */ + __u32 ac_exitcode; /* Exit status */ + + /* The accounting flags of a task as defined in + * Defined values are AFORK, ASU, ACOMPAT, ACORE, and AXSIG. + */ + __u8 ac_flag; /* Record flags */ + + /* The value of task_nice() of a task. */ + __u8 ac_nice; /* task_nice */ + + /* The name of the command that started this task. */ + char ac_comm[TS_COMM_LEN]; /* Command name */ + + /* The scheduling discipline as set in task->policy field. */ + __u8 ac_sched; /* Scheduling discipline */ + + __u8 ac_pad[3]; + __u32 ac_uid; /* User ID */ + __u32 ac_gid; /* Group ID */ + __u32 ac_pid; /* Process ID */ + __u32 ac_ppid; /* Parent process ID */ + + /* The time when a task begins, in [secs] since 1970. */ + __u32 ac_btime; /* Begin time [sec since 1970] */ + + /* The elapsed time of a task, in [usec]. */ + __u64 ac_etime; /* Elapsed time [usec] */ + + /* The user CPU time of a task, in [usec]. */ + __u64 ac_utime; /* User CPU time [usec] */ + + /* The system CPU time of a task, in [usec]. */ + __u64 ac_stime; /* System CPU time [usec] */ + + /* The minor page fault count of a task, as set in task->min_flt. */ + __u64 ac_minflt; /* Minor Page Fault Count */ + + /* The major page fault count of a task, as set in task->maj_flt. */ + __u64 ac_majflt; /* Major Page Fault Count */ + + +2) Delay accounting fields: + /* Delay accounting fields start + * + * All values, until the comment "Delay accounting fields end" are + * available only if delay accounting is enabled, even though the last + * few fields are not delays + * + * xxx_count is the number of delay values recorded + * xxx_delay_total is the corresponding cumulative delay in nanoseconds + * + * xxx_delay_total wraps around to zero on overflow + * xxx_count incremented regardless of overflow + */ + + /* Delay waiting for cpu, while runnable + * count, delay_total NOT updated atomically + */ + __u64 cpu_count; + __u64 cpu_delay_total; + + /* Following four fields atomically updated using task->delays->lock */ + + /* Delay waiting for synchronous block I/O to complete + * does not account for delays in I/O submission + */ + __u64 blkio_count; + __u64 blkio_delay_total; + + /* Delay waiting for page fault I/O (swap in only) */ + __u64 swapin_count; + __u64 swapin_delay_total; + + /* cpu "wall-clock" running time + * On some architectures, value will adjust for cpu time stolen + * from the kernel in involuntary waits due to virtualization. + * Value is cumulative, in nanoseconds, without a corresponding count + * and wraps around to zero silently on overflow + */ + __u64 cpu_run_real_total; + + /* cpu "virtual" running time + * Uses time intervals seen by the kernel i.e. no adjustment + * for kernel's involuntary waits due to virtualization. + * Value is cumulative, in nanoseconds, without a corresponding count + * and wraps around to zero silently on overflow + */ + __u64 cpu_run_virtual_total; + /* Delay accounting fields end */ + /* version 1 ends here */ + + +3) Extended accounting fields + /* Extended accounting fields start */ + + /* Accumulated RSS usage in duration of a task, in MBytes-usecs. + * The current rss usage is added to this counter every time + * a tick is charged to a task's system time. So, at the end we + * will have memory usage multiplied by system time. Thus an + * average usage per system time unit can be calculated. + */ + __u64 coremem; /* accumulated RSS usage in MB-usec */ + + /* Accumulated virtual memory usage in duration of a task. + * Same as acct_rss_mem1 above except that we keep track of VM usage. + */ + __u64 virtmem; /* accumulated VM usage in MB-usec */ + + /* High watermark of RSS usage in duration of a task, in KBytes. */ + __u64 hiwater_rss; /* High-watermark of RSS usage */ + + /* High watermark of VM usage in duration of a task, in KBytes. */ + __u64 hiwater_vm; /* High-water virtual memory usage */ + + /* The following four fields are I/O statistics of a task. */ + __u64 read_char; /* bytes read */ + __u64 write_char; /* bytes written */ + __u64 read_syscalls; /* read syscalls */ + __u64 write_syscalls; /* write syscalls */ + + /* Extended accounting fields end */ + +} diff --git a/include/linux/sched.h b/include/linux/sched.h index 4ddeb0f982fb..7ef899c47c29 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -984,7 +984,7 @@ struct task_struct { #if defined(CONFIG_TASK_XACCT) u64 acct_rss_mem1; /* accumulated rss usage */ u64 acct_vm_mem1; /* accumulated virtual memory usage */ - clock_t acct_stimexpd; /* clock_t-converted stime since last update */ + cputime_t acct_stimexpd;/* stime since last update */ #endif #ifdef CONFIG_NUMA struct mempolicy *mempolicy; diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h index 3d2c304886b0..45248806ae9c 100644 --- a/include/linux/taskstats.h +++ b/include/linux/taskstats.h @@ -32,14 +32,21 @@ #define TASKSTATS_VERSION 2 -#define TS_COMM_LEN 16 /* should sync up with TASK_COMM_LEN +#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN * in linux/sched.h */ struct taskstats { - /* Version 1 */ + /* The version number of this struct. This field is always set to + * TAKSTATS_VERSION, which is defined in . + * Each time the struct is changed, the value should be incremented. + */ __u16 version; - __u32 ac_exitcode; /* Exit status */ + __u32 ac_exitcode; /* Exit status */ + + /* The accounting flags of a task as defined in + * Defined values are AFORK, ASU, ACOMPAT, ACORE, and AXSIG. + */ __u8 ac_flag; /* Record flags */ __u8 ac_nice; /* task_nice */ @@ -104,15 +111,30 @@ struct taskstats { __u64 ac_etime; /* Elapsed time [usec] */ __u64 ac_utime; /* User CPU time [usec] */ __u64 ac_stime; /* SYstem CPU time [usec] */ - __u64 ac_minflt; /* Minor Page Fault */ - __u64 ac_majflt; /* Major Page Fault */ + __u64 ac_minflt; /* Minor Page Fault Count */ + __u64 ac_majflt; /* Major Page Fault Count */ /* Basic Accounting Fields end */ /* Extended accounting fields start */ - __u64 acct_rss_mem1; /* accumulated rss usage */ - __u64 acct_vm_mem1; /* accumulated virtual memory usage */ - __u64 hiwater_rss; /* High-watermark of RSS usage */ - __u64 hiwater_vm; /* High-water virtual memory usage */ + /* Accumulated RSS usage in duration of a task, in MBytes-usecs. + * The current rss usage is added to this counter every time + * a tick is charged to a task's system time. So, at the end we + * will have memory usage multiplied by system time. Thus an + * average usage per system time unit can be calculated. + */ + __u64 coremem; /* accumulated RSS usage in MB-usec */ + /* Accumulated virtual memory usage in duration of a task. + * Same as acct_rss_mem1 above except that we keep track of VM usage. + */ + __u64 virtmem; /* accumulated VM usage in MB-usec */ + + /* High watermark of RSS and virtual memory usage in duration of + * a task, in KBytes. + */ + __u64 hiwater_rss; /* High-watermark of RSS usage, in KB */ + __u64 hiwater_vm; /* High-water VM usage, in KB */ + + /* The following four fields are I/O statistics of a task. */ __u64 read_char; /* bytes read */ __u64 write_char; /* bytes written */ __u64 read_syscalls; /* read syscalls */ diff --git a/kernel/tsacct.c b/kernel/tsacct.c index 47c71daa416f..db443221ba5b 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c @@ -20,6 +20,7 @@ #include #include #include +#include #define USEC_PER_TICK (USEC_PER_SEC/HZ) @@ -62,33 +63,35 @@ void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk) stats->ac_stime = cputime_to_msecs(tsk->stime) * USEC_PER_MSEC; stats->ac_minflt = tsk->min_flt; stats->ac_majflt = tsk->maj_flt; - /* Each process gets a minimum of one usec cpu time */ - if ((stats->ac_utime == 0) && (stats->ac_stime == 0)) { - stats->ac_stime = 1; - } strncpy(stats->ac_comm, tsk->comm, sizeof(stats->ac_comm)); } #ifdef CONFIG_TASK_XACCT + +#define KB 1024 +#define MB (1024*KB) /* * fill in extended accounting fields */ void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) { - stats->acct_rss_mem1 = p->acct_rss_mem1; - stats->acct_vm_mem1 = p->acct_vm_mem1; + /* convert pages-jiffies to Mbyte-usec */ + stats->coremem = jiffies_to_usecs(p->acct_rss_mem1) * PAGE_SIZE / MB; + stats->virtmem = jiffies_to_usecs(p->acct_vm_mem1) * PAGE_SIZE / MB; if (p->mm) { - stats->hiwater_rss = p->mm->hiwater_rss; - stats->hiwater_vm = p->mm->hiwater_vm; + /* adjust to KB unit */ + stats->hiwater_rss = p->mm->hiwater_rss * PAGE_SIZE / KB; + stats->hiwater_vm = p->mm->hiwater_vm * PAGE_SIZE / KB; } stats->read_char = p->rchar; stats->write_char = p->wchar; stats->read_syscalls = p->syscr; stats->write_syscalls = p->syscw; } - +#undef KB +#undef MB /** * acct_update_integrals - update mm integral fields in task_struct @@ -97,8 +100,8 @@ void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) void acct_update_integrals(struct task_struct *tsk) { if (likely(tsk->mm)) { - long delta = - cputime_to_jiffies(tsk->stime) - tsk->acct_stimexpd; + long delta = cputime_to_jiffies( + cputime_sub(tsk->stime, tsk->acct_stimexpd)); if (delta == 0) return; -- cgit v1.2.3 From 9a53c3a783c2fa9b969628e65695c11c3e51e673 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Sat, 30 Sep 2006 23:29:03 -0700 Subject: [PATCH] r/o bind mounts: unlink: monitor i_nlink When a filesystem decrements i_nlink to zero, it means that a write must be performed in order to drop the inode from the filesystem. We're shortly going to have keep filesystems from being remounted r/o between the time that this i_nlink decrement and that write occurs. So, add a little helper function to do the decrements. We'll tie into it in a bit to note when i_nlink hits zero. Signed-off-by: Dave Hansen Acked-by: Christoph Hellwig Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/core/inode.c | 7 ++++--- fs/autofs/root.c | 2 +- fs/autofs4/root.c | 2 +- fs/bfs/dir.c | 9 +++------ fs/cifs/inode.c | 10 +++++----- fs/coda/dir.c | 4 ++-- fs/ext2/namei.c | 2 +- fs/ext3/namei.c | 14 +++++++------- fs/hfs/dir.c | 2 +- fs/hfsplus/dir.c | 2 +- fs/hpfs/namei.c | 6 +++--- fs/jffs/inode-v23.c | 3 +-- fs/jffs2/dir.c | 6 +++--- fs/jfs/namei.c | 14 ++++++-------- fs/libfs.c | 10 +++++----- fs/minix/namei.c | 2 +- fs/msdos/namei.c | 9 ++++----- fs/nfs/dir.c | 6 +++--- fs/ocfs2/namei.c | 4 ++-- fs/qnx4/namei.c | 6 ++---- fs/reiserfs/namei.c | 6 +++--- fs/sysv/namei.c | 2 +- fs/udf/namei.c | 18 ++++++------------ fs/ufs/namei.c | 2 +- fs/vfat/namei.c | 9 ++++----- include/linux/fs.h | 7 ++++++- ipc/mqueue.c | 2 +- mm/shmem.c | 10 +++++----- 28 files changed, 83 insertions(+), 93 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index df3d152f0493..88002e45a6b4 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -332,7 +332,7 @@ static int usbfs_unlink (struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; mutex_lock(&inode->i_mutex); - dentry->d_inode->i_nlink--; + drop_nlink(dentry->d_inode); dput(dentry); mutex_unlock(&inode->i_mutex); d_delete(dentry); @@ -347,10 +347,11 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) mutex_lock(&inode->i_mutex); dentry_unhash(dentry); if (usbfs_empty(dentry)) { - dentry->d_inode->i_nlink -= 2; + drop_nlink(dentry->d_inode); + drop_nlink(dentry->d_inode); dput(dentry); inode->i_flags |= S_DEAD; - dir->i_nlink--; + drop_nlink(dir); error = 0; } mutex_unlock(&inode->i_mutex); diff --git a/fs/autofs/root.c b/fs/autofs/root.c index 9cac08d6a873..54ad70731927 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -414,7 +414,7 @@ static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry) dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL; autofs_hash_delete(ent); - dir->i_nlink--; + drop_nlink(dir); d_drop(dentry); unlock_kernel(); diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 563ef9d7da9f..348bec0982b0 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -676,7 +676,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) dentry->d_inode->i_nlink = 0; if (dir->i_nlink) - dir->i_nlink--; + drop_nlink(dir); return 0; } diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index dcf04cb13283..ce05d1643dd1 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c @@ -117,8 +117,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode, err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino); if (err) { - inode->i_nlink--; - mark_inode_dirty(inode); + inode_dec_link_count(inode); iput(inode); unlock_kernel(); return err; @@ -196,9 +195,8 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry) mark_buffer_dirty(bh); dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(dir); - inode->i_nlink--; inode->i_ctime = dir->i_ctime; - mark_inode_dirty(inode); + inode_dec_link_count(inode); error = 0; out_brelse: @@ -249,9 +247,8 @@ static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry, old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(old_dir); if (new_inode) { - new_inode->i_nlink--; new_inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(new_inode); + inode_dec_link_count(new_inode); } mark_buffer_dirty(old_bh); error = 0; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 05f874c7441b..74441a17e186 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -590,7 +590,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) if (!rc) { if (direntry->d_inode) - direntry->d_inode->i_nlink--; + drop_nlink(direntry->d_inode); } else if (rc == -ENOENT) { d_drop(direntry); } else if (rc == -ETXTBSY) { @@ -609,7 +609,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); if (direntry->d_inode) - direntry->d_inode->i_nlink--; + drop_nlink(direntry->d_inode); } } else if (rc == -EACCES) { /* try only if r/o attribute set in local lookup data? */ @@ -663,7 +663,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { if (direntry->d_inode) - direntry->d_inode->i_nlink--; + drop_nlink(direntry->d_inode); } else if (rc == -ETXTBSY) { int oplock = FALSE; __u16 netfid; @@ -684,7 +684,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); if (direntry->d_inode) - direntry->d_inode->i_nlink--; + drop_nlink(direntry->d_inode); } /* BB if rc = -ETXTBUSY goto the rename logic BB */ } @@ -816,7 +816,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { - inode->i_nlink--; + drop_nlink(inode); i_size_write(direntry->d_inode,0); direntry->d_inode->i_nlink = 0; } diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 8651ea6a23b7..0a2fd8bb7579 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -367,7 +367,7 @@ int coda_unlink(struct inode *dir, struct dentry *de) } coda_dir_changed(dir, 0); - de->d_inode->i_nlink--; + drop_nlink(de->d_inode); unlock_kernel(); return 0; @@ -394,7 +394,7 @@ int coda_rmdir(struct inode *dir, struct dentry *de) } coda_dir_changed(dir, -1); - de->d_inode->i_nlink--; + drop_nlink(de->d_inode); d_delete(de); unlock_kernel(); diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 4ca824985321..e1af5b4cf80c 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -326,7 +326,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, ext2_set_link(new_dir, new_de, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) - new_inode->i_nlink--; + drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { if (dir_de) { diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 235e77b52ea5..14c55adfae83 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1621,7 +1621,7 @@ static inline void ext3_inc_count(handle_t *handle, struct inode *inode) static inline void ext3_dec_count(handle_t *handle, struct inode *inode) { - inode->i_nlink--; + drop_nlink(inode); } static int ext3_add_nondir(handle_t *handle, @@ -1743,7 +1743,7 @@ retry: inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize; dir_block = ext3_bread (handle, inode, 0, 1, &err); if (!dir_block) { - inode->i_nlink--; /* is this nlink == 0? */ + drop_nlink(inode); /* is this nlink == 0? */ ext3_mark_inode_dirty(handle, inode); iput (inode); goto out_stop; @@ -2053,7 +2053,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) ext3_orphan_add(handle, inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, inode); - dir->i_nlink--; + drop_nlink(dir); ext3_update_dx_flag(dir); ext3_mark_inode_dirty(handle, dir); @@ -2104,7 +2104,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; ext3_update_dx_flag(dir); ext3_mark_inode_dirty(handle, dir); - inode->i_nlink--; + drop_nlink(inode); if (!inode->i_nlink) ext3_orphan_add(handle, inode); inode->i_ctime = dir->i_ctime; @@ -2326,7 +2326,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, } if (new_inode) { - new_inode->i_nlink--; + drop_nlink(new_inode); new_inode->i_ctime = CURRENT_TIME_SEC; } old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; @@ -2337,9 +2337,9 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino); BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata"); ext3_journal_dirty_metadata(handle, dir_bh); - old_dir->i_nlink--; + drop_nlink(old_dir); if (new_inode) { - new_inode->i_nlink--; + drop_nlink(new_inode); } else { new_dir->i_nlink++; ext3_update_dx_flag(new_dir); diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 7cd8cc03aea7..cfef6ad529a7 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -246,7 +246,7 @@ static int hfs_unlink(struct inode *dir, struct dentry *dentry) if (res) return res; - inode->i_nlink--; + drop_nlink(inode); hfs_delete_inode(inode); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 1f9ece0de326..9ceb0dfaa1cc 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -338,7 +338,7 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) return res; if (inode->i_nlink > 0) - inode->i_nlink--; + drop_nlink(inode); hfsplus_delete_inode(inode); if (inode->i_ino != cnid && !inode->i_nlink) { if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 59e7dc182a0c..4078b0becc5e 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -434,7 +434,7 @@ again: unlock_kernel(); return -ENOSPC; default: - inode->i_nlink--; + drop_nlink(inode); err = 0; } goto out; @@ -494,7 +494,7 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) err = -ENOSPC; break; default: - dir->i_nlink--; + drop_nlink(dir); inode->i_nlink = 0; err = 0; } @@ -636,7 +636,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, hpfs_i(i)->i_parent_dir = new_dir->i_ino; if (S_ISDIR(i->i_mode)) { new_dir->i_nlink++; - old_dir->i_nlink--; + drop_nlink(old_dir); } if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) { fnode->up = new_dir->i_ino; diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 068ef0de8de2..3f7899ea4cba 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -1052,9 +1052,8 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type) dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(dir); - inode->i_nlink--; inode->i_ctime = dir->i_ctime; - mark_inode_dirty(inode); + inode_dec_link_count(inode); d_delete(dentry); /* This also frees the inode */ diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index edd8371fc6a5..a5e9f2205b33 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -615,7 +615,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) } ret = jffs2_unlink(dir_i, dentry); if (!ret) - dir_i->i_nlink--; + drop_nlink(dir_i); return ret; } @@ -823,7 +823,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, if (victim_f) { /* There was a victim. Kill it off nicely */ - new_dentry->d_inode->i_nlink--; + drop_nlink(new_dentry->d_inode); /* Don't oops if the victim was a dirent pointing to an inode which didn't exist. */ if (victim_f->inocache) { @@ -862,7 +862,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, } if (S_ISDIR(old_dentry->d_inode->i_mode)) - old_dir_i->i_nlink--; + drop_nlink(old_dir_i); new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 295268ad231b..088b85976ac0 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -393,9 +393,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) /* update parent directory's link count corresponding * to ".." entry of the target directory deleted */ - dip->i_nlink--; dip->i_ctime = dip->i_mtime = CURRENT_TIME; - mark_inode_dirty(dip); + inode_dec_link_count(dip); /* * OS/2 could have created EA and/or ACL @@ -515,8 +514,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) mark_inode_dirty(dip); /* update target's inode */ - ip->i_nlink--; - mark_inode_dirty(ip); + inode_dec_link_count(ip); /* * commit zero link count object @@ -835,7 +833,7 @@ static int jfs_link(struct dentry *old_dentry, rc = txCommit(tid, 2, &iplist[0], 0); if (rc) { - ip->i_nlink--; + ip->i_nlink--; /* never instantiated */ iput(ip); } else d_instantiate(dentry, ip); @@ -1155,9 +1153,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, old_ip->i_ino, JFS_RENAME); if (rc) goto out4; - new_ip->i_nlink--; + drop_nlink(new_ip); if (S_ISDIR(new_ip->i_mode)) { - new_ip->i_nlink--; + drop_nlink(new_ip); if (new_ip->i_nlink) { mutex_unlock(&JFS_IP(new_ip)->commit_mutex); if (old_dir != new_dir) @@ -1223,7 +1221,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out4; } if (S_ISDIR(old_ip->i_mode)) { - old_dir->i_nlink--; + drop_nlink(old_dir); if (old_dir != new_dir) { /* * Change inode number of parent for moved directory diff --git a/fs/libfs.c b/fs/libfs.c index 3793aaa14577..9204feba75ac 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -275,7 +275,7 @@ int simple_unlink(struct inode *dir, struct dentry *dentry) struct inode *inode = dentry->d_inode; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - inode->i_nlink--; + drop_nlink(inode); dput(dentry); return 0; } @@ -285,9 +285,9 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry) if (!simple_empty(dentry)) return -ENOTEMPTY; - dentry->d_inode->i_nlink--; + drop_nlink(dentry->d_inode); simple_unlink(dir, dentry); - dir->i_nlink--; + drop_nlink(dir); return 0; } @@ -303,9 +303,9 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry, if (new_dentry->d_inode) { simple_unlink(new_dir, new_dentry); if (they_are_dirs) - old_dir->i_nlink--; + drop_nlink(old_dir); } else if (they_are_dirs) { - old_dir->i_nlink--; + drop_nlink(old_dir); new_dir->i_nlink++; } diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 5b6a4540a05b..299bb66e3bde 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -249,7 +249,7 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry, minix_set_link(new_de, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) - new_inode->i_nlink--; + drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { if (dir_de) { diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index d220165d4918..635613f2f65a 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -343,7 +343,7 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) err = fat_remove_entries(dir, &sinfo); /* and releases bh */ if (err) goto out; - dir->i_nlink--; + drop_nlink(dir); inode->i_nlink = 0; inode->i_ctime = CURRENT_TIME_SEC; @@ -549,7 +549,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, if (err) goto error_dotdot; } - old_dir->i_nlink--; + drop_nlink(old_dir); if (!new_inode) new_dir->i_nlink++; } @@ -566,10 +566,9 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, mark_inode_dirty(old_dir); if (new_inode) { + drop_nlink(new_inode); if (is_dir) - new_inode->i_nlink -= 2; - else - new_inode->i_nlink--; + drop_nlink(new_inode); new_inode->i_ctime = ts; } out: diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 7432f1a43f3d..26eecb86f9b0 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -843,7 +843,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) nfs_inode_return_delegation(inode); if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { lock_kernel(); - inode->i_nlink--; + drop_nlink(inode); nfs_complete_unlink(dentry); unlock_kernel(); } @@ -1401,7 +1401,7 @@ static int nfs_safe_remove(struct dentry *dentry) error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); /* The VFS may want to delete this inode */ if (error == 0) - inode->i_nlink--; + drop_nlink(inode); nfs_mark_for_revalidate(inode); nfs_end_data_update(inode); } else @@ -1639,7 +1639,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out; } } else - new_inode->i_nlink--; + drop_nlink(new_inode); go_ahead: /* diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 849c3b4bb94a..40f83f53053a 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -739,7 +739,7 @@ static int ocfs2_link(struct dentry *old_dentry, err = ocfs2_journal_dirty(handle, fe_bh); if (err < 0) { le16_add_cpu(&fe->i_links_count, -1); - inode->i_nlink--; + drop_nlink(inode); mlog_errno(err); goto bail; } @@ -749,7 +749,7 @@ static int ocfs2_link(struct dentry *old_dentry, parent_fe_bh, de_bh); if (err) { le16_add_cpu(&fe->i_links_count, -1); - inode->i_nlink--; + drop_nlink(inode); mlog_errno(err); goto bail; } diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c index c3d83f67154a..ad5afa4ea8f3 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c @@ -189,8 +189,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry) inode->i_nlink = 0; mark_inode_dirty(inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; - dir->i_nlink--; - mark_inode_dirty(dir); + inode_dec_link_count(dir); retval = 0; end_rmdir: @@ -234,9 +233,8 @@ int qnx4_unlink(struct inode *dir, struct dentry *dentry) mark_buffer_dirty(bh); dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(dir); - inode->i_nlink--; inode->i_ctime = dir->i_ctime; - mark_inode_dirty(inode); + inode_dec_link_count(inode); retval = 0; end_unlink: diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index c61710e49c62..c76d427e027b 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -20,7 +20,7 @@ #include #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; } -#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--; +#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) drop_nlink(i); // directory item contains array of entry headers. This performs // binary search through that array @@ -994,7 +994,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry) inode->i_nlink = 1; } - inode->i_nlink--; + drop_nlink(inode); /* * we schedule before doing the add_save_link call, save the link @@ -1475,7 +1475,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (S_ISDIR(new_dentry_inode->i_mode)) { new_dentry_inode->i_nlink = 0; } else { - new_dentry_inode->i_nlink--; + drop_nlink(new_dentry_inode); } new_dentry_inode->i_ctime = ctime; savelink = new_dentry_inode->i_nlink; diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index b8a73f716fbe..f7c08db8e34c 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -250,7 +250,7 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry, sysv_set_link(new_de, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) - new_inode->i_nlink--; + drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { if (dir_de) { diff --git a/fs/udf/namei.c b/fs/udf/namei.c index ab9a7629d23e..d14d25534aa8 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -878,8 +878,7 @@ static int udf_rmdir(struct inode * dir, struct dentry * dentry) inode->i_nlink); inode->i_nlink = 0; inode->i_size = 0; - mark_inode_dirty(inode); - dir->i_nlink --; + inode_dec_link_count(inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb); mark_inode_dirty(dir); @@ -923,8 +922,7 @@ static int udf_unlink(struct inode * dir, struct dentry * dentry) goto end_unlink; dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb); mark_inode_dirty(dir); - inode->i_nlink--; - mark_inode_dirty(inode); + inode_dec_link_count(inode); inode->i_ctime = dir->i_ctime; retval = 0; @@ -1101,8 +1099,7 @@ out: return err; out_no_entry: - inode->i_nlink--; - mark_inode_dirty(inode); + inode_dec_link_count(inode); iput(inode); goto out; } @@ -1261,9 +1258,8 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry, if (new_inode) { - new_inode->i_nlink--; new_inode->i_ctime = current_fs_time(new_inode->i_sb); - mark_inode_dirty(new_inode); + inode_dec_link_count(new_inode); } old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb); mark_inode_dirty(old_dir); @@ -1279,12 +1275,10 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry, } else mark_buffer_dirty_inode(dir_bh, old_inode); - old_dir->i_nlink --; - mark_inode_dirty(old_dir); + inode_dec_link_count(old_dir); if (new_inode) { - new_inode->i_nlink --; - mark_inode_dirty(new_inode); + inode_dec_link_count(new_inode); } else { diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index d344b411e261..e84c0ecf0730 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -308,7 +308,7 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry, ufs_set_link(new_dir, new_de, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) - new_inode->i_nlink--; + drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { if (dir_de) { diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 9a8f48bae956..090d74ffa061 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -782,7 +782,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) err = fat_remove_entries(dir, &sinfo); /* and releases bh */ if (err) goto out; - dir->i_nlink--; + drop_nlink(dir); inode->i_nlink = 0; inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; @@ -930,7 +930,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, if (err) goto error_dotdot; } - old_dir->i_nlink--; + drop_nlink(old_dir); if (!new_inode) new_dir->i_nlink++; } @@ -947,10 +947,9 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, mark_inode_dirty(old_dir); if (new_inode) { + drop_nlink(new_inode); if (is_dir) - new_inode->i_nlink -= 2; - else - new_inode->i_nlink--; + drop_nlink(new_inode); new_inode->i_ctime = ts; } out: diff --git a/include/linux/fs.h b/include/linux/fs.h index 4bb70871873f..26d3c61116c0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1225,9 +1225,14 @@ static inline void inode_inc_link_count(struct inode *inode) mark_inode_dirty(inode); } -static inline void inode_dec_link_count(struct inode *inode) +static inline void drop_nlink(struct inode *inode) { inode->i_nlink--; +} + +static inline void inode_dec_link_count(struct inode *inode) +{ + drop_nlink(inode); mark_inode_dirty(inode); } diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 840f8a6fb85f..10aa8eeeb112 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -307,7 +307,7 @@ static int mqueue_unlink(struct inode *dir, struct dentry *dentry) dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; dir->i_size -= DIRENT_SIZE; - inode->i_nlink--; + drop_nlink(inode); dput(dentry); return 0; } diff --git a/mm/shmem.c b/mm/shmem.c index b96de69f236b..908dd947b1ea 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1772,7 +1772,7 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry) dir->i_size -= BOGO_DIRENT_SIZE; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - inode->i_nlink--; + drop_nlink(inode); dput(dentry); /* Undo the count from "create" - this does all the work */ return 0; } @@ -1782,8 +1782,8 @@ static int shmem_rmdir(struct inode *dir, struct dentry *dentry) if (!simple_empty(dentry)) return -ENOTEMPTY; - dentry->d_inode->i_nlink--; - dir->i_nlink--; + drop_nlink(dentry->d_inode); + drop_nlink(dir); return shmem_unlink(dir, dentry); } @@ -1804,9 +1804,9 @@ static int shmem_rename(struct inode *old_dir, struct dentry *old_dentry, struct if (new_dentry->d_inode) { (void) shmem_unlink(new_dir, new_dentry); if (they_are_dirs) - old_dir->i_nlink--; + drop_nlink(old_dir); } else if (they_are_dirs) { - old_dir->i_nlink--; + drop_nlink(old_dir); new_dir->i_nlink++; } -- cgit v1.2.3 From d8c76e6f45c111c32a4b3e50a2adc9210737b0d8 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Sat, 30 Sep 2006 23:29:04 -0700 Subject: [PATCH] r/o bind mount prepwork: inc_nlink() helper This is mostly included for parity with dec_nlink(), where we will have some more hooks. This one should stay pretty darn straightforward for now. Signed-off-by: Dave Hansen Acked-by: Christoph Hellwig Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/ipath/ipath_fs.c | 4 ++-- drivers/usb/core/inode.c | 4 ++-- fs/9p/vfs_inode.c | 2 +- fs/autofs/root.c | 2 +- fs/autofs4/root.c | 2 +- fs/bfs/dir.c | 2 +- fs/cifs/inode.c | 2 +- fs/coda/dir.c | 2 +- fs/configfs/dir.c | 4 ++-- fs/configfs/mount.c | 2 +- fs/debugfs/inode.c | 4 ++-- fs/ext3/namei.c | 6 +++--- fs/fuse/control.c | 2 +- fs/hfsplus/dir.c | 2 +- fs/hpfs/namei.c | 4 ++-- fs/hugetlbfs/inode.c | 4 ++-- fs/jffs2/dir.c | 6 +++--- fs/jffs2/fs.c | 6 +++--- fs/jfs/namei.c | 6 +++--- fs/libfs.c | 4 ++-- fs/msdos/namei.c | 4 ++-- fs/ocfs2/dlm/dlmfs.c | 6 +++--- fs/ocfs2/namei.c | 8 ++++---- fs/ramfs/inode.c | 4 ++-- fs/reiserfs/namei.c | 6 +++--- fs/sysfs/dir.c | 4 ++-- fs/sysfs/mount.c | 2 +- fs/udf/inode.c | 2 +- fs/udf/namei.c | 6 +++--- fs/vfat/namei.c | 4 ++-- include/linux/fs.h | 7 ++++++- ipc/mqueue.c | 2 +- kernel/cpuset.c | 8 ++++---- mm/shmem.c | 8 ++++---- net/sunrpc/rpc_pipe.c | 6 +++--- security/inode.c | 4 ++-- security/selinux/selinuxfs.c | 4 ++-- 37 files changed, 80 insertions(+), 75 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index a507d0b5be6c..d9ff283f725e 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -66,8 +66,8 @@ static int ipathfs_mknod(struct inode *dir, struct dentry *dentry, inode->i_private = data; if ((mode & S_IFMT) == S_IFDIR) { inode->i_op = &simple_dir_inode_operations; - inode->i_nlink++; - dir->i_nlink++; + inc_nlink(inode); + inc_nlink(dir); } inode->i_fop = fops; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 88002e45a6b4..7c77c2d8d300 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -263,7 +263,7 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); break; } } @@ -295,7 +295,7 @@ static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; res = usbfs_mknod (dir, dentry, mode, 0); if (!res) - dir->i_nlink++; + inc_nlink(dir); return res; } diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 7a7ec2d1d2f4..5241c600ce28 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -233,7 +233,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) inode->i_op = &v9fs_symlink_inode_operations; break; case S_IFDIR: - inode->i_nlink++; + inc_nlink(inode); if(v9ses->extended) inode->i_op = &v9fs_dir_inode_operations_ext; else diff --git a/fs/autofs/root.c b/fs/autofs/root.c index 54ad70731927..368a1c33a3c8 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -466,7 +466,7 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode) ent->dentry = dentry; autofs_hash_insert(dh,ent); - dir->i_nlink++; + inc_nlink(dir); d_instantiate(dentry, iget(dir->i_sb,ino)); unlock_kernel(); diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 348bec0982b0..e21bb4668201 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -713,7 +713,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (p_ino && dentry->d_parent != dentry) atomic_inc(&p_ino->count); ino->inode = inode; - dir->i_nlink++; + inc_nlink(dir); dir->i_mtime = CURRENT_TIME; return 0; diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index ce05d1643dd1..a650f1d0b85e 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c @@ -163,7 +163,7 @@ static int bfs_link(struct dentry * old, struct inode * dir, struct dentry * new unlock_kernel(); return err; } - inode->i_nlink++; + inc_nlink(inode); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); atomic_inc(&inode->i_count); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 74441a17e186..76b7fb34101a 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -735,7 +735,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) cFYI(1, ("cifs_mkdir returned 0x%x", rc)); d_drop(direntry); } else { - inode->i_nlink++; + inc_nlink(inode); if (pTcon->ses->capabilities & CAP_UNIX) rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,xid); diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 0a2fd8bb7579..0102b28a15fb 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -304,7 +304,7 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode, coda_dir_changed(dir_inode, 0); atomic_inc(&inode->i_count); d_instantiate(de, inode); - inode->i_nlink++; + inc_nlink(inode); out: unlock_kernel(); diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 816e8ef64560..8a3b6a1a6ad1 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -139,7 +139,7 @@ static int init_dir(struct inode * inode) inode->i_fop = &configfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); return 0; } @@ -169,7 +169,7 @@ static int create_dir(struct config_item * k, struct dentry * p, if (!error) { error = configfs_create(d, mode, init_dir); if (!error) { - p->d_inode->i_nlink++; + inc_nlink(p->d_inode); (d)->d_op = &configfs_dentry_ops; } else { struct configfs_dirent *sd = d->d_fsdata; diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 3e5fe843e1df..68bd5c93ca52 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -84,7 +84,7 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) inode->i_op = &configfs_dir_inode_operations; inode->i_fop = &configfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); } else { pr_debug("configfs: could not get root inode\n"); return -ENOMEM; diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 269e649e6dc6..ecf3da9edf21 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -54,7 +54,7 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); break; } } @@ -87,7 +87,7 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; res = debugfs_mknod(dir, dentry, mode, 0); if (!res) - dir->i_nlink++; + inc_nlink(dir); return res; } diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 14c55adfae83..b45c88bd5f73 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1616,7 +1616,7 @@ static int ext3_delete_entry (handle_t *handle, */ static inline void ext3_inc_count(handle_t *handle, struct inode *inode) { - inode->i_nlink++; + inc_nlink(inode); } static inline void ext3_dec_count(handle_t *handle, struct inode *inode) @@ -1775,7 +1775,7 @@ retry: iput (inode); goto out_stop; } - dir->i_nlink++; + inc_nlink(dir); ext3_update_dx_flag(dir); ext3_mark_inode_dirty(handle, dir); d_instantiate(dentry, inode); @@ -2341,7 +2341,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, if (new_inode) { drop_nlink(new_inode); } else { - new_dir->i_nlink++; + inc_nlink(new_dir); ext3_update_dx_flag(new_dir); ext3_mark_inode_dirty(handle, new_dir); } diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 79ec1f23d4d2..16b39c053d47 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -116,7 +116,7 @@ int fuse_ctl_add_conn(struct fuse_conn *fc) return 0; parent = fuse_control_sb->s_root; - parent->d_inode->i_nlink++; + inc_nlink(parent->d_inode); sprintf(name, "%llu", (unsigned long long) fc->id); parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2, &simple_dir_inode_operations, diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 9ceb0dfaa1cc..99b4ed1b87d2 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -298,7 +298,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, if (res) return res; - inode->i_nlink++; + inc_nlink(inode); hfsplus_instantiate(dst_dentry, inode, cnid); atomic_inc(&inode->i_count); inode->i_ctime = CURRENT_TIME_SEC; diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 4078b0becc5e..25dd6f81eca7 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -89,7 +89,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) brelse(bh); hpfs_mark_4buffers_dirty(&qbh0); hpfs_brelse4(&qbh0); - dir->i_nlink++; + inc_nlink(dir); insert_inode_hash(result); if (result->i_uid != current->fsuid || @@ -635,7 +635,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, end: hpfs_i(i)->i_parent_dir = new_dir->i_ino; if (S_ISDIR(i->i_mode)) { - new_dir->i_nlink++; + inc_nlink(new_dir); drop_nlink(old_dir); } if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) { diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index f5b8f329aca6..5e03b2f67b93 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -377,7 +377,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; @@ -418,7 +418,7 @@ static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { int retval = hugetlbfs_mknod(dir, dentry, mode | S_IFDIR, 0); if (!retval) - dir->i_nlink++; + inc_nlink(dir); return retval; } diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index a5e9f2205b33..9def6adf4a5d 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -588,7 +588,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) } dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); - dir_i->i_nlink++; + inc_nlink(dir_i); jffs2_free_raw_dirent(rd); @@ -836,7 +836,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, /* If it was a directory we moved, and there was no victim, increase i_nlink on its new parent */ if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) - new_dir_i->i_nlink++; + inc_nlink(new_dir_i); /* Unlink the original */ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), @@ -848,7 +848,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, /* Oh shit. We really ought to make a single node which can do both atomically */ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); down(&f->sem); - old_dentry->d_inode->i_nlink++; + inc_nlink(old_dentry->d_inode); if (f->inocache) f->inocache->nlink++; up(&f->sem); diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 72d9909d95ff..7bc1a4201c0c 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -277,13 +277,13 @@ void jffs2_read_inode (struct inode *inode) for (fd=f->dents; fd; fd = fd->next) { if (fd->type == DT_DIR && fd->ino) - inode->i_nlink++; + inc_nlink(inode); } /* and '..' */ - inode->i_nlink++; + inc_nlink(inode); /* Root dir gets i_nlink 3 for some reason */ if (inode->i_ino == 1) - inode->i_nlink++; + inc_nlink(inode); inode->i_op = &jffs2_dir_inode_operations; inode->i_fop = &jffs2_dir_operations; diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 088b85976ac0..8cef88170aa4 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -292,7 +292,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) mark_inode_dirty(ip); /* update parent directory inode */ - dip->i_nlink++; /* for '..' from child directory */ + inc_nlink(dip); /* for '..' from child directory */ dip->i_ctime = dip->i_mtime = CURRENT_TIME; mark_inode_dirty(dip); @@ -822,7 +822,7 @@ static int jfs_link(struct dentry *old_dentry, goto free_dname; /* update object inode */ - ip->i_nlink++; /* for new link */ + inc_nlink(ip); /* for new link */ ip->i_ctime = CURRENT_TIME; dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); @@ -1206,7 +1206,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out4; } if (S_ISDIR(old_ip->i_mode)) - new_dir->i_nlink++; + inc_nlink(new_dir); } /* * Remove old directory entry diff --git a/fs/libfs.c b/fs/libfs.c index 9204feba75ac..bd08e0e64a8c 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -243,7 +243,7 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den struct inode *inode = old_dentry->d_inode; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - inode->i_nlink++; + inc_nlink(inode); atomic_inc(&inode->i_count); dget(dentry); d_instantiate(dentry, inode); @@ -306,7 +306,7 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry, drop_nlink(old_dir); } else if (they_are_dirs) { drop_nlink(old_dir); - new_dir->i_nlink++; + inc_nlink(new_dir); } old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime = diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 635613f2f65a..fa868c755907 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -389,7 +389,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode) err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo); if (err) goto out_free; - dir->i_nlink++; + inc_nlink(dir); inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); brelse(sinfo.bh); @@ -551,7 +551,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, } drop_nlink(old_dir); if (!new_inode) - new_dir->i_nlink++; + inc_nlink(new_dir); } err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */ diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index 0368c6402182..16b8d1ba7066 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c @@ -338,7 +338,7 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb) inode->i_blocks = 0; inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_nlink++; + inc_nlink(inode); inode->i_fop = &simple_dir_operations; inode->i_op = &dlmfs_root_inode_operations; @@ -395,7 +395,7 @@ static struct inode *dlmfs_get_inode(struct inode *parent, /* directory inodes start off with i_nlink == * 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); break; } @@ -449,7 +449,7 @@ static int dlmfs_mkdir(struct inode * dir, } ip->ip_dlm = dlm; - dir->i_nlink++; + inc_nlink(dir); d_instantiate(dentry, inode); dget(dentry); /* Extra count - pin the dentry in core */ diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 40f83f53053a..8c370a39e0c1 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -429,7 +429,7 @@ static int ocfs2_mknod(struct inode *dir, mlog_errno(status); goto leave; } - dir->i_nlink++; + inc_nlink(dir); } status = ocfs2_add_entry(handle, dentry, inode, @@ -730,7 +730,7 @@ static int ocfs2_link(struct dentry *old_dentry, goto bail; } - inode->i_nlink++; + inc_nlink(inode); inode->i_ctime = CURRENT_TIME; fe->i_links_count = cpu_to_le16(inode->i_nlink); fe->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); @@ -952,7 +952,7 @@ static int ocfs2_unlink(struct inode *dir, parent_node_bh); if (status < 0) { mlog_errno(status); - dir->i_nlink++; + inc_nlink(dir); } } @@ -1382,7 +1382,7 @@ static int ocfs2_rename(struct inode *old_dir, if (new_inode) { new_inode->i_nlink--; } else { - new_dir->i_nlink++; + inc_nlink(new_dir); mark_inode_dirty(new_dir); } } diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index bc0e51662424..2faf4cdf61b0 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -75,7 +75,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev) inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; @@ -113,7 +113,7 @@ static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) { int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0); if (!retval) - dir->i_nlink++; + inc_nlink(dir); return retval; } diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index c76d427e027b..cf92e89515f2 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -19,7 +19,7 @@ #include #include -#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; } +#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; } #define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) drop_nlink(i); // directory item contains array of entry headers. This performs @@ -1006,7 +1006,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry) reiserfs_cut_from_item(&th, &path, &(de.de_entry_key), dir, NULL, 0); if (retval < 0) { - inode->i_nlink++; + inc_nlink(inode); goto end_unlink; } inode->i_ctime = CURRENT_TIME_SEC; @@ -1143,7 +1143,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir, } /* inc before scheduling so reiserfs_unlink knows we are here */ - inode->i_nlink++; + inc_nlink(inode); retval = journal_begin(&th, dir->i_sb, jbegin_count); if (retval) { diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5f3d725d1125..3aa3434621ca 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -103,7 +103,7 @@ static int init_dir(struct inode * inode) inode->i_fop = &sysfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); return 0; } @@ -137,7 +137,7 @@ static int create_dir(struct kobject * k, struct dentry * p, if (!error) { error = sysfs_create(*d, mode, init_dir); if (!error) { - p->d_inode->i_nlink++; + inc_nlink(p->d_inode); (*d)->d_op = &sysfs_dentry_ops; d_rehash(*d); } diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 40190c489271..20551a1b8a56 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -49,7 +49,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) inode->i_op = &sysfs_dir_inode_operations; inode->i_fop = &sysfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); } else { pr_debug("sysfs: could not get root inode\n"); return -ENOMEM; diff --git a/fs/udf/inode.c b/fs/udf/inode.c index b223b32db991..ae21a0e59e95 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1165,7 +1165,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_op = &udf_dir_inode_operations; inode->i_fop = &udf_dir_operations; inode->i_mode |= S_IFDIR; - inode->i_nlink ++; + inc_nlink(inode); break; } case ICBTAG_FILE_TYPE_REALTIME: diff --git a/fs/udf/namei.c b/fs/udf/namei.c index d14d25534aa8..e40c95e65117 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -762,7 +762,7 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode) cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL); cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY; udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); - dir->i_nlink++; + inc_nlink(dir); mark_inode_dirty(dir); d_instantiate(dentry, inode); if (fibh.sbh != fibh.ebh) @@ -1147,7 +1147,7 @@ static int udf_link(struct dentry * old_dentry, struct inode * dir, if (fibh.sbh != fibh.ebh) udf_release_data(fibh.ebh); udf_release_data(fibh.sbh); - inode->i_nlink ++; + inc_nlink(inode); inode->i_ctime = current_fs_time(inode->i_sb); mark_inode_dirty(inode); atomic_inc(&inode->i_count); @@ -1282,7 +1282,7 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry, } else { - new_dir->i_nlink ++; + inc_nlink(new_dir); mark_inode_dirty(new_dir); } } diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 090d74ffa061..5846ba2d5d9f 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -837,7 +837,7 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (err) goto out_free; dir->i_version++; - dir->i_nlink++; + inc_nlink(dir); inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); brelse(sinfo.bh); @@ -932,7 +932,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, } drop_nlink(old_dir); if (!new_inode) - new_dir->i_nlink++; + inc_nlink(new_dir); } err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 26d3c61116c0..6a5267da565f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1219,9 +1219,14 @@ static inline void mark_inode_dirty_sync(struct inode *inode) __mark_inode_dirty(inode, I_DIRTY_SYNC); } -static inline void inode_inc_link_count(struct inode *inode) +static inline void inc_nlink(struct inode *inode) { inode->i_nlink++; +} + +static inline void inode_inc_link_count(struct inode *inode) +{ + inc_nlink(inode); mark_inode_dirty(inode); } diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 10aa8eeeb112..d75d0ba83360 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -168,7 +168,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, /* all is ok */ info->user = get_uid(u); } else if (S_ISDIR(mode)) { - inode->i_nlink++; + inc_nlink(inode); /* Some things misbehave if size == 0 on a directory */ inode->i_size = 2 * DIRENT_SIZE; inode->i_op = &mqueue_dir_inode_operations; diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 8c3c400cce91..9d850ae13b1b 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -377,7 +377,7 @@ static int cpuset_fill_super(struct super_block *sb, void *unused_data, inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; /* directories start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); } else { return -ENOMEM; } @@ -1565,7 +1565,7 @@ static int cpuset_create_file(struct dentry *dentry, int mode) inode->i_fop = &simple_dir_operations; /* start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); } else if (S_ISREG(mode)) { inode->i_size = 0; inode->i_fop = &cpuset_file_operations; @@ -1598,7 +1598,7 @@ static int cpuset_create_dir(struct cpuset *cs, const char *name, int mode) error = cpuset_create_file(dentry, S_IFDIR | mode); if (!error) { dentry->d_fsdata = cs; - parent->d_inode->i_nlink++; + inc_nlink(parent->d_inode); cs->dentry = dentry; } dput(dentry); @@ -2033,7 +2033,7 @@ int __init cpuset_init(void) } root = cpuset_mount->mnt_sb->s_root; root->d_fsdata = &top_cpuset; - root->d_inode->i_nlink++; + inc_nlink(root->d_inode); top_cpuset.dentry = root; root->d_inode->i_op = &cpuset_dir_inode_operations; number_of_cpusets = 1; diff --git a/mm/shmem.c b/mm/shmem.c index 908dd947b1ea..bb8ca7ef7094 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1379,7 +1379,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) &sbinfo->policy_nodes); break; case S_IFDIR: - inode->i_nlink++; + inc_nlink(inode); /* Some things misbehave if size == 0 on a directory */ inode->i_size = 2 * BOGO_DIRENT_SIZE; inode->i_op = &shmem_dir_inode_operations; @@ -1715,7 +1715,7 @@ static int shmem_mkdir(struct inode *dir, struct dentry *dentry, int mode) if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0))) return error; - dir->i_nlink++; + inc_nlink(dir); return 0; } @@ -1750,7 +1750,7 @@ static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentr dir->i_size += BOGO_DIRENT_SIZE; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - inode->i_nlink++; + inc_nlink(inode); atomic_inc(&inode->i_count); /* New dentry reference */ dget(dentry); /* Extra pinning count for the created dentry */ d_instantiate(dentry, inode); @@ -1807,7 +1807,7 @@ static int shmem_rename(struct inode *old_dir, struct dentry *old_dentry, struct drop_nlink(old_dir); } else if (they_are_dirs) { drop_nlink(old_dir); - new_dir->i_nlink++; + inc_nlink(new_dir); } old_dir->i_size -= BOGO_DIRENT_SIZE; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 700c6e061a04..9a0b41a97f90 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -494,7 +494,7 @@ rpc_get_inode(struct super_block *sb, int mode) case S_IFDIR: inode->i_fop = &simple_dir_operations; inode->i_op = &simple_dir_inode_operations; - inode->i_nlink++; + inc_nlink(inode); default: break; } @@ -571,7 +571,7 @@ rpc_populate(struct dentry *parent, if (private) rpc_inode_setowner(inode, private); if (S_ISDIR(mode)) - dir->i_nlink++; + inc_nlink(dir); d_add(dentry, inode); } mutex_unlock(&dir->i_mutex); @@ -593,7 +593,7 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry) goto out_err; inode->i_ino = iunique(dir->i_sb, 100); d_instantiate(dentry, inode); - dir->i_nlink++; + inc_nlink(dir); inode_dir_notify(dir, DN_CREATE); return 0; out_err: diff --git a/security/inode.c b/security/inode.c index 49ee51529396..9b16e14f3a80 100644 --- a/security/inode.c +++ b/security/inode.c @@ -78,7 +78,7 @@ static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev) inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); break; } } @@ -111,7 +111,7 @@ static int mkdir(struct inode *dir, struct dentry *dentry, int mode) mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; res = mknod(dir, dentry, mode, 0); if (!res) - dir->i_nlink++; + inc_nlink(dir); return res; } diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index bab7b386cb8d..cd244419c980 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1253,10 +1253,10 @@ static int sel_make_dir(struct inode *dir, struct dentry *dentry) inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); d_add(dentry, inode); /* bump link count on parent directory, too */ - dir->i_nlink++; + inc_nlink(dir); out: return ret; } -- cgit v1.2.3 From ce71ec36840368b877fb63bd14c8e67ab62d08b1 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Sat, 30 Sep 2006 23:29:06 -0700 Subject: [PATCH] r/o bind mounts: monitor zeroing of i_nlink Some filesystems, instead of simply decrementing i_nlink, simply zero it during an unlink operation. We need to catch these in addition to the decrement operations. Signed-off-by: Dave Hansen Acked-by: Christoph Hellwig Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/autofs4/root.c | 4 ++-- fs/cifs/inode.c | 2 +- fs/ext3/namei.c | 2 +- fs/fuse/dir.c | 4 ++-- fs/hfs/dir.c | 2 +- fs/hfsplus/dir.c | 4 ++-- fs/hpfs/namei.c | 4 ++-- fs/jfs/namei.c | 2 +- fs/msdos/namei.c | 4 ++-- fs/nfs/dir.c | 2 +- fs/qnx4/namei.c | 2 +- fs/reiserfs/namei.c | 4 ++-- fs/udf/namei.c | 2 +- fs/vfat/namei.c | 4 ++-- include/linux/fs.h | 5 +++++ 15 files changed, 26 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index e21bb4668201..c1493524da4d 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -638,7 +638,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) dput(ino->dentry); dentry->d_inode->i_size = 0; - dentry->d_inode->i_nlink = 0; + clear_nlink(dentry->d_inode); dir->i_mtime = CURRENT_TIME; @@ -673,7 +673,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) } dput(ino->dentry); dentry->d_inode->i_size = 0; - dentry->d_inode->i_nlink = 0; + clear_nlink(dentry->d_inode); if (dir->i_nlink) drop_nlink(dir); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 76b7fb34101a..6b90ef98e4cf 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -818,7 +818,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) if (!rc) { drop_nlink(inode); i_size_write(direntry->d_inode,0); - direntry->d_inode->i_nlink = 0; + clear_nlink(direntry->d_inode); } cifsInode = CIFS_I(direntry->d_inode); diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index b45c88bd5f73..906731a20f1a 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -2045,7 +2045,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) "empty directory has nlink!=2 (%d)", inode->i_nlink); inode->i_version++; - inode->i_nlink = 0; + clear_nlink(inode); /* There's no need to set i_disksize: the fact that i_nlink is * zero will ensure that the right thing happens during any * recovery. */ diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index f85b2a282f13..8605155db171 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -508,7 +508,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) /* Set nlink to zero so the inode can be cleared, if the inode does have more links this will be discovered at the next lookup/getattr */ - inode->i_nlink = 0; + clear_nlink(inode); fuse_invalidate_attr(inode); fuse_invalidate_attr(dir); fuse_invalidate_entry_cache(entry); @@ -534,7 +534,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) err = req->out.h.error; fuse_put_request(fc, req); if (!err) { - entry->d_inode->i_nlink = 0; + clear_nlink(entry->d_inode); fuse_invalidate_attr(dir); fuse_invalidate_entry_cache(entry); } else if (err == -EINTR) diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index cfef6ad529a7..37d681b4f216 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -273,7 +273,7 @@ static int hfs_rmdir(struct inode *dir, struct dentry *dentry) res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name); if (res) return res; - inode->i_nlink = 0; + clear_nlink(inode); inode->i_ctime = CURRENT_TIME_SEC; hfs_delete_inode(inode); mark_inode_dirty(inode); diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 99b4ed1b87d2..7e309751645f 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -348,7 +348,7 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) } else inode->i_flags |= S_DEAD; } else - inode->i_nlink = 0; + clear_nlink(inode); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); @@ -387,7 +387,7 @@ static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry) res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); if (res) return res; - inode->i_nlink = 0; + clear_nlink(inode); inode->i_ctime = CURRENT_TIME_SEC; hfsplus_delete_inode(inode); mark_inode_dirty(inode); diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 25dd6f81eca7..2507e7393f3c 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -495,7 +495,7 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) break; default: drop_nlink(dir); - inode->i_nlink = 0; + clear_nlink(inode); err = 0; } goto out; @@ -590,7 +590,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, int r; if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) { if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) { - new_inode->i_nlink = 0; + clear_nlink(new_inode); copy_de(nde, &de); memcpy(nde->name, new_name, new_len); hpfs_mark_4buffers_dirty(&qbh1); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 8cef88170aa4..b8d16a6aa88f 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -414,7 +414,7 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) JFS_IP(ip)->acl.flag = 0; /* mark the target directory as deleted */ - ip->i_nlink = 0; + clear_nlink(ip); mark_inode_dirty(ip); rc = txCommit(tid, 2, &iplist[0], 0); diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index fa868c755907..b0f01b3b0536 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -345,7 +345,7 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) goto out; drop_nlink(dir); - inode->i_nlink = 0; + clear_nlink(inode); inode->i_ctime = CURRENT_TIME_SEC; fat_detach(inode); out: @@ -430,7 +430,7 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry) err = fat_remove_entries(dir, &sinfo); /* and releases bh */ if (err) goto out; - inode->i_nlink = 0; + clear_nlink(inode); inode->i_ctime = CURRENT_TIME_SEC; fat_detach(inode); out: diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 26eecb86f9b0..481f8892a919 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1286,7 +1286,7 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); /* Ensure the VFS deletes this inode */ if (error == 0 && dentry->d_inode != NULL) - dentry->d_inode->i_nlink = 0; + clear_nlink(dentry->d_inode); nfs_end_data_update(dir); unlock_kernel(); diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c index ad5afa4ea8f3..733cdf01d645 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c @@ -186,7 +186,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry) memset(de->di_fname, 0, sizeof de->di_fname); de->di_mode = 0; mark_buffer_dirty(bh); - inode->i_nlink = 0; + clear_nlink(inode); mark_inode_dirty(inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; inode_dec_link_count(dir); diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index cf92e89515f2..16e9cff8f15d 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -913,7 +913,7 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry) reiserfs_warning(inode->i_sb, "%s: empty directory has nlink " "!= 2 (%d)", __FUNCTION__, inode->i_nlink); - inode->i_nlink = 0; + clear_nlink(inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; reiserfs_update_sd(&th, inode); @@ -1473,7 +1473,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (new_dentry_inode) { // adjust link number of the victim if (S_ISDIR(new_dentry_inode->i_mode)) { - new_dentry_inode->i_nlink = 0; + clear_nlink(new_dentry_inode); } else { drop_nlink(new_dentry_inode); } diff --git a/fs/udf/namei.c b/fs/udf/namei.c index e40c95e65117..73163325e5ec 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -876,7 +876,7 @@ static int udf_rmdir(struct inode * dir, struct dentry * dentry) udf_warning(inode->i_sb, "udf_rmdir", "empty directory has nlink != 2 (%d)", inode->i_nlink); - inode->i_nlink = 0; + clear_nlink(inode); inode->i_size = 0; inode_dec_link_count(inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb); diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 5846ba2d5d9f..edb711ff7b05 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -784,7 +784,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) goto out; drop_nlink(dir); - inode->i_nlink = 0; + clear_nlink(inode); inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; fat_detach(inode); out: @@ -808,7 +808,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) err = fat_remove_entries(dir, &sinfo); /* and releases bh */ if (err) goto out; - inode->i_nlink = 0; + clear_nlink(inode); inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; fat_detach(inode); out: diff --git a/include/linux/fs.h b/include/linux/fs.h index 6a5267da565f..3493d2828f7d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1235,6 +1235,11 @@ static inline void drop_nlink(struct inode *inode) inode->i_nlink--; } +static inline void clear_nlink(struct inode *inode) +{ + inode->i_nlink = 0; +} + static inline void inode_dec_link_count(struct inode *inode) { drop_nlink(inode); -- cgit v1.2.3 From 74588d8ba34ff1bda027cfa737972af01ab00c8b Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Sat, 30 Sep 2006 23:29:12 -0700 Subject: [PATCH] Generic ioremap_page_range: implementation This patch adds a generic implementation of ioremap_page_range() in lib/ioremap.c based on the i386 implementation. It differs from the i386 version in the following ways: * The PTE flags are passed as a pgprot_t argument and must be determined up front by the arch-specific code. No additional PTE flags are added. * Uses set_pte_at() instead of set_pte() [bunk@stusta.de: warning fix] ]dhowells@redhat.com: nommu build fix] Signed-off-by: Haavard Skinnemoen Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Russell King Cc: Mikael Starvik Cc: Andi Kleen Cc: Cc: Ralf Baechle Cc: Kyle McMartin Cc: Martin Schwidefsky Cc: Paul Mundt Signed-off-by: Adrian Bunk Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/io.h | 4 +++ lib/Makefile | 1 + lib/ioremap.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 lib/ioremap.c (limited to 'include/linux') diff --git a/include/linux/io.h b/include/linux/io.h index 420e2fdf26f6..aa3f5af670b5 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -19,8 +19,12 @@ #define _LINUX_IO_H #include +#include void __iowrite32_copy(void __iomem *to, const void *from, size_t count); void __iowrite64_copy(void __iomem *to, const void *from, size_t count); +int ioremap_page_range(unsigned long addr, unsigned long end, + unsigned long phys_addr, pgprot_t prot); + #endif /* _LINUX_IO_H */ diff --git a/lib/Makefile b/lib/Makefile index 402762fead70..ddf3e676e1f4 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -7,6 +7,7 @@ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \ sha1.o +lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o lib-y += kobject.o kref.o kobject_uevent.o klist.o diff --git a/lib/ioremap.c b/lib/ioremap.c new file mode 100644 index 000000000000..29c810ec9813 --- /dev/null +++ b/lib/ioremap.c @@ -0,0 +1,94 @@ +/* + * Re-map IO memory to kernel address space so that we can access it. + * This is needed for high PCI addresses that aren't mapped in the + * 640k-1MB IO memory area on PC's + * + * (C) Copyright 1995 1996 Linus Torvalds + */ +#include +#include +#include + +#include +#include + +static int ioremap_pte_range(pmd_t *pmd, unsigned long addr, + unsigned long end, unsigned long phys_addr, pgprot_t prot) +{ + pte_t *pte; + unsigned long pfn; + + pfn = phys_addr >> PAGE_SHIFT; + pte = pte_alloc_kernel(pmd, addr); + if (!pte) + return -ENOMEM; + do { + BUG_ON(!pte_none(*pte)); + set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot)); + pfn++; + } while (pte++, addr += PAGE_SIZE, addr != end); + return 0; +} + +static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr, + unsigned long end, unsigned long phys_addr, pgprot_t prot) +{ + pmd_t *pmd; + unsigned long next; + + phys_addr -= addr; + pmd = pmd_alloc(&init_mm, pud, addr); + if (!pmd) + return -ENOMEM; + do { + next = pmd_addr_end(addr, end); + if (ioremap_pte_range(pmd, addr, next, phys_addr + addr, prot)) + return -ENOMEM; + } while (pmd++, addr = next, addr != end); + return 0; +} + +static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr, + unsigned long end, unsigned long phys_addr, pgprot_t prot) +{ + pud_t *pud; + unsigned long next; + + phys_addr -= addr; + pud = pud_alloc(&init_mm, pgd, addr); + if (!pud) + return -ENOMEM; + do { + next = pud_addr_end(addr, end); + if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, prot)) + return -ENOMEM; + } while (pud++, addr = next, addr != end); + return 0; +} + +int ioremap_page_range(unsigned long addr, + unsigned long end, unsigned long phys_addr, pgprot_t prot) +{ + pgd_t *pgd; + unsigned long start; + unsigned long next; + int err; + + BUG_ON(addr >= end); + + flush_cache_all(); + + start = addr; + phys_addr -= addr; + pgd = pgd_offset_k(addr); + do { + next = pgd_addr_end(addr, end); + err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, prot); + if (err) + break; + } while (pgd++, addr = next, addr != end); + + flush_tlb_all(); + + return err; +} -- cgit v1.2.3 From d6cbd281d189977b38eac7eb2a4678de19b6b483 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 30 Sep 2006 23:29:26 -0700 Subject: [PATCH] Some cleanup in the pipe code Split the big and hard to read do_pipe function into smaller pieces. This creates new create_write_pipe/free_write_pipe/create_read_pipe functions. These functions are made global so that they can be used by other parts of the kernel. The resulting code is more generic and easier to read and has cleaner error handling and less gotos. [akpm@osdl.org: cleanup] Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/pipe.c | 155 ++++++++++++++++++++++++++++++++--------------------- include/linux/fs.h | 3 ++ 2 files changed, 96 insertions(+), 62 deletions(-) (limited to 'include/linux') diff --git a/fs/pipe.c b/fs/pipe.c index 2e60e1c8815e..b1626f269a34 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -874,87 +874,118 @@ fail_inode: return NULL; } -int do_pipe(int *fd) +struct file *create_write_pipe(void) { - struct qstr this; - char name[32]; + int err; + struct inode *inode; + struct file *f; struct dentry *dentry; - struct inode * inode; - struct file *f1, *f2; - int error; - int i, j; - - error = -ENFILE; - f1 = get_empty_filp(); - if (!f1) - goto no_files; - - f2 = get_empty_filp(); - if (!f2) - goto close_f1; + char name[32]; + struct qstr this; + f = get_empty_filp(); + if (!f) + return ERR_PTR(-ENFILE); + err = -ENFILE; inode = get_pipe_inode(); if (!inode) - goto close_f12; + goto err_file; - error = get_unused_fd(); - if (error < 0) - goto close_f12_inode; - i = error; - - error = get_unused_fd(); - if (error < 0) - goto close_f12_inode_i; - j = error; - - error = -ENOMEM; sprintf(name, "[%lu]", inode->i_ino); this.name = name; this.len = strlen(name); this.hash = inode->i_ino; /* will go */ + err = -ENOMEM; dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this); if (!dentry) - goto close_f12_inode_i_j; + goto err_inode; dentry->d_op = &pipefs_dentry_operations; d_add(dentry, inode); - f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt)); - f1->f_dentry = f2->f_dentry = dget(dentry); - f1->f_mapping = f2->f_mapping = inode->i_mapping; - - /* read file */ - f1->f_pos = f2->f_pos = 0; - f1->f_flags = O_RDONLY; - f1->f_op = &read_pipe_fops; - f1->f_mode = FMODE_READ; - f1->f_version = 0; - - /* write file */ - f2->f_flags = O_WRONLY; - f2->f_op = &write_pipe_fops; - f2->f_mode = FMODE_WRITE; - f2->f_version = 0; - - fd_install(i, f1); - fd_install(j, f2); - fd[0] = i; - fd[1] = j; + f->f_vfsmnt = mntget(pipe_mnt); + f->f_dentry = dentry; + f->f_mapping = inode->i_mapping; - return 0; + f->f_flags = O_WRONLY; + f->f_op = &write_pipe_fops; + f->f_mode = FMODE_WRITE; + f->f_version = 0; -close_f12_inode_i_j: - put_unused_fd(j); -close_f12_inode_i: - put_unused_fd(i); -close_f12_inode: + return f; + + err_inode: free_pipe_info(inode); iput(inode); -close_f12: - put_filp(f2); -close_f1: - put_filp(f1); -no_files: - return error; + err_file: + put_filp(f); + return ERR_PTR(err); +} + +void free_write_pipe(struct file *f) +{ + mntput(f->f_vfsmnt); + dput(f->f_dentry); + put_filp(f); +} + +struct file *create_read_pipe(struct file *wrf) +{ + struct file *f = get_empty_filp(); + if (!f) + return ERR_PTR(-ENFILE); + + /* Grab pipe from the writer */ + f->f_vfsmnt = mntget(wrf->f_vfsmnt); + f->f_dentry = dget(wrf->f_dentry); + f->f_mapping = wrf->f_dentry->d_inode->i_mapping; + + f->f_pos = 0; + f->f_flags = O_RDONLY; + f->f_op = &read_pipe_fops; + f->f_mode = FMODE_READ; + f->f_version = 0; + + return f; +} + +int do_pipe(int *fd) +{ + struct file *fw, *fr; + int error; + int fdw, fdr; + + fw = create_write_pipe(); + if (IS_ERR(fw)) + return PTR_ERR(fw); + fr = create_read_pipe(fw); + error = PTR_ERR(fr); + if (IS_ERR(fr)) + goto err_write_pipe; + + error = get_unused_fd(); + if (error < 0) + goto err_read_pipe; + fdr = error; + + error = get_unused_fd(); + if (error < 0) + goto err_fdr; + fdw = error; + + fd_install(fdr, fr); + fd_install(fdw, fw); + fd[0] = fdr; + fd[1] = fdw; + + return 0; + + err_fdr: + put_unused_fd(fdr); + err_read_pipe: + put_filp(fr); + err_write_pipe: + free_write_pipe(fw); + return error; } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 3493d2828f7d..2e29a2edaeec 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1641,6 +1641,9 @@ static inline void allow_write_access(struct file *file) atomic_inc(&file->f_dentry->d_inode->i_writecount); } extern int do_pipe(int *); +extern struct file *create_read_pipe(struct file *f); +extern struct file *create_write_pipe(void); +extern void free_write_pipe(struct file *); extern int open_namei(int dfd, const char *, int, int, struct nameidata *); extern int may_open(struct nameidata *, int, int); -- cgit v1.2.3 From e239ca540594cff00adcce163dc332b27015d8e5 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 30 Sep 2006 23:29:27 -0700 Subject: [PATCH] Create call_usermodehelper_pipe() A new member in the ever growing family of call_usermode* functions is born. The new call_usermodehelper_pipe() function allows to pipe data to the stdin of the called user mode progam and behaves otherwise like the normal call_usermodehelp() (except that it always waits for the child to finish) Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kmod.h | 4 ++++ kernel/kmod.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 0db22a1ab474..10f505c8431d 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -47,4 +47,8 @@ call_usermodehelper(char *path, char **argv, char **envp, int wait) extern void usermodehelper_init(void); +struct file; +extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[], + struct file **filp); + #endif /* __LINUX_KMOD_H__ */ diff --git a/kernel/kmod.c b/kernel/kmod.c index 842f8015d7fd..5c63c53014a9 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -122,6 +122,7 @@ struct subprocess_info { struct key *ring; int wait; int retval; + struct file *stdin; }; /* @@ -145,12 +146,26 @@ static int ____call_usermodehelper(void *data) key_put(old_session); + /* Install input pipe when needed */ + if (sub_info->stdin) { + struct files_struct *f = current->files; + struct fdtable *fdt; + /* no races because files should be private here */ + sys_close(0); + fd_install(0, sub_info->stdin); + spin_lock(&f->file_lock); + fdt = files_fdtable(f); + FD_SET(0, fdt->open_fds); + FD_CLR(0, fdt->close_on_exec); + spin_unlock(&f->file_lock); + } + /* We can run anywhere, unlike our parent keventd(). */ set_cpus_allowed(current, CPU_MASK_ALL); retval = -EPERM; if (current->fs->root) - retval = execve(sub_info->path, sub_info->argv,sub_info->envp); + retval = execve(sub_info->path, sub_info->argv, sub_info->envp); /* Exec failed? */ sub_info->retval = retval; @@ -268,6 +283,44 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp, } EXPORT_SYMBOL(call_usermodehelper_keys); +int call_usermodehelper_pipe(char *path, char **argv, char **envp, + struct file **filp) +{ + DECLARE_COMPLETION(done); + struct subprocess_info sub_info = { + .complete = &done, + .path = path, + .argv = argv, + .envp = envp, + .retval = 0, + }; + struct file *f; + DECLARE_WORK(work, __call_usermodehelper, &sub_info); + + if (!khelper_wq) + return -EBUSY; + + if (path[0] == '\0') + return 0; + + f = create_write_pipe(); + if (!f) + return -ENOMEM; + *filp = f; + + f = create_read_pipe(f); + if (!f) { + free_write_pipe(*filp); + return -ENOMEM; + } + sub_info.stdin = f; + + queue_work(khelper_wq, &work); + wait_for_completion(&done); + return sub_info.retval; +} +EXPORT_SYMBOL(call_usermodehelper_pipe); + void __init usermodehelper_init(void) { khelper_wq = create_singlethread_workqueue("khelper"); -- cgit v1.2.3 From 5a73fdc5ea836d2edc5e02890b51185fe304d7d3 Mon Sep 17 00:00:00 2001 From: Zachary Amsden Date: Sat, 30 Sep 2006 23:29:38 -0700 Subject: [PATCH] Some config.h removals During tracking down a PAE compile failure, I found that config.h was being included in a bunch of places in i386 code. It is no longer necessary, so drop it. Signed-off-by: Zachary Amsden Cc: Rusty Russell Cc: Jeremy Fitzhardinge Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/boot/video.S | 2 -- arch/i386/kernel/nmi.c | 1 - arch/i386/lib/delay.c | 1 - include/linux/unwind.h | 2 -- 4 files changed, 6 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S index 8c2a6faeeae5..2c5b5cc55f79 100644 --- a/arch/i386/boot/video.S +++ b/arch/i386/boot/video.S @@ -11,8 +11,6 @@ * */ -#include /* for CONFIG_VIDEO_* */ - /* Enable autodetection of SVGA adapters and modes. */ #undef CONFIG_VIDEO_SVGA diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 0fc4997fb143..3e8e3adb0489 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -13,7 +13,6 @@ * Mikael Pettersson : PM converted to driver model. Disable/enable API. */ -#include #include #include #include diff --git a/arch/i386/lib/delay.c b/arch/i386/lib/delay.c index 3c0714c4b669..f6edb11364df 100644 --- a/arch/i386/lib/delay.c +++ b/arch/i386/lib/delay.c @@ -11,7 +11,6 @@ */ #include -#include #include #include diff --git a/include/linux/unwind.h b/include/linux/unwind.h index ce48e2cd37a2..73e1751d03dd 100644 --- a/include/linux/unwind.h +++ b/include/linux/unwind.h @@ -12,8 +12,6 @@ * is not much point in implementing the full Dwarf2 unwind API. */ -#include - struct module; #ifdef CONFIG_STACK_UNWIND -- cgit v1.2.3 From a6b93a908508810c5d51dd9b390283345af6f2d9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 1 Oct 2006 17:17:40 +0100 Subject: [SERIAL] Fix oops when removing suspended serial port A serial card might have been removed when the system is resumed. This results in a suspended port being shut down, which results in the ports shutdown method being called twice in a row. This causes BUGs. Avoid this by tracking the suspended state separately from the initialised state. Signed-off-by: Russell King --- drivers/serial/serial_core.c | 9 +++++++-- include/linux/serial_core.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index d814bb1dcb05..397147a7054f 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1940,6 +1940,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) if (state->info && state->info->flags & UIF_INITIALIZED) { const struct uart_ops *ops = port->ops; + state->info->flags = (state->info->flags & ~UIF_INITIALIZED) + | UIF_SUSPENDED; + spin_lock_irq(&port->lock); ops->stop_tx(port); ops->set_mctrl(port, 0); @@ -2006,7 +2009,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) console_start(port->cons); } - if (state->info && state->info->flags & UIF_INITIALIZED) { + if (state->info && state->info->flags & UIF_SUSPENDED) { const struct uart_ops *ops = port->ops; int ret; @@ -2018,15 +2021,17 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) ops->set_mctrl(port, port->mctrl); ops->start_tx(port); spin_unlock_irq(&port->lock); + state->info->flags |= UIF_INITIALIZED; } else { /* * Failed to resume - maybe hardware went away? * Clear the "initialized" flag so we won't try * to call the low level drivers shutdown method. */ - state->info->flags &= ~UIF_INITIALIZED; uart_shutdown(state); } + + state->info->flags &= ~UIF_SUSPENDED; } mutex_unlock(&state->mutex); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 86501a3de2ac..f9fdf97506ea 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -319,6 +319,7 @@ struct uart_info { #define UIF_CTS_FLOW ((__force uif_t) (1 << 26)) #define UIF_NORMAL_ACTIVE ((__force uif_t) (1 << 29)) #define UIF_INITIALIZED ((__force uif_t) (1 << 31)) +#define UIF_SUSPENDED ((__force uif_t) (1 << 30)) int blocked_open; -- cgit v1.2.3 From d8d64d6b29d331f1217c77999f5104fe68b0ef3a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 25 Sep 2006 16:51:28 -0700 Subject: [SERIAL] Magic SysRq SAK does nothing on serial consoles Make sysrq-K work on serial console by passing in the tty. Signed-off-by: Andrew Morton Signed-off-by: Russell King --- include/linux/serial_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index f9fdf97506ea..de2e68159d96 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -415,7 +415,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch, #ifdef SUPPORT_SYSRQ if (port->sysrq) { if (ch && time_before(jiffies, port->sysrq)) { - handle_sysrq(ch, regs, NULL); + handle_sysrq(ch, regs, port->info->tty); port->sysrq = 0; return 1; } -- cgit v1.2.3 From 322acc96d4bd3debea11cd0160b18bd5d7ff0d73 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 2 Oct 2006 02:17:00 -0700 Subject: [PATCH] LIB: add gen_pool_destroy() Modules using the genpool allocator need to be able to destroy the data structure when unloading. Signed-off-by: Steve Wise Cc: Randy Dunlap Cc: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/genalloc.h | 1 + lib/genalloc.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'include/linux') diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h index 690c42803d2e..9869ef3674ac 100644 --- a/include/linux/genalloc.h +++ b/include/linux/genalloc.h @@ -31,5 +31,6 @@ struct gen_pool_chunk { extern struct gen_pool *gen_pool_create(int, int); extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int); +extern void gen_pool_destroy(struct gen_pool *); extern unsigned long gen_pool_alloc(struct gen_pool *, size_t); extern void gen_pool_free(struct gen_pool *, unsigned long, size_t); diff --git a/lib/genalloc.c b/lib/genalloc.c index 71338b48e889..7d16ecabba96 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -70,6 +70,36 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size, EXPORT_SYMBOL(gen_pool_add); +/* + * Destroy a memory pool. Verifies that there are no outstanding allocations. + * + * @pool: pool to destroy + */ +void gen_pool_destroy(struct gen_pool *pool) +{ + struct list_head *_chunk, *_next_chunk; + struct gen_pool_chunk *chunk; + int order = pool->min_alloc_order; + int bit, end_bit; + + + write_lock(&pool->lock); + list_for_each_safe(_chunk, _next_chunk, &pool->chunks) { + chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); + list_del(&chunk->next_chunk); + + end_bit = (chunk->end_addr - chunk->start_addr) >> order; + bit = find_next_bit(chunk->bits, end_bit, 0); + BUG_ON(bit < end_bit); + + kfree(chunk); + } + kfree(pool); + return; +} +EXPORT_SYMBOL(gen_pool_destroy); + + /* * Allocate the requested number of bytes from the specified pool. * Uses a first-fit algorithm. -- cgit v1.2.3 From 2bc2d61a9638dab670d8361e928d1a5a291173ef Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 2 Oct 2006 02:17:02 -0700 Subject: [PATCH] list module taint flags in Oops/panic When listing loaded modules during an oops or panic, also list each module's Tainted flags if non-zero (P: Proprietary or F: Forced load only). If a module is did not taint the kernel, it is just listed like usbcore but if it did taint the kernel, it is listed like wizmodem(PF) Example: [ 3260.121718] Unable to handle kernel NULL pointer dereference at 0000000000000000 RIP: [ 3260.121729] [] :dump_test:proc_dump_test+0x99/0xc8 [ 3260.121742] PGD fe8d067 PUD 264a6067 PMD 0 [ 3260.121748] Oops: 0002 [1] SMP [ 3260.121753] CPU 1 [ 3260.121756] Modules linked in: dump_test(P) snd_pcm_oss snd_mixer_oss snd_seq snd_seq_device ide_cd generic ohci1394 snd_hda_intel snd_hda_codec snd_pcm snd_timer snd ieee1394 snd_page_alloc piix ide_core arcmsr aic79xx scsi_transport_spi usblp [ 3260.121785] Pid: 5556, comm: bash Tainted: P 2.6.18-git10 #1 [Alternatively, I can look into listing tainted flags with 'lsmod', but that won't help in oopsen/panics so much.] [akpm@osdl.org: cleanup] Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/module.h | 2 ++ kernel/module.c | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/module.h b/include/linux/module.h index 2c599175c583..4b2d8091a410 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -320,6 +320,8 @@ struct module /* Am I GPL-compatible */ int license_gplok; + unsigned int taints; /* same bits as kernel:tainted */ + #ifdef CONFIG_MODULE_UNLOAD /* Reference counts */ struct module_ref ref[NR_CPUS]; diff --git a/kernel/module.c b/kernel/module.c index 05625d5dc758..7c77a0a9275c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -851,6 +851,7 @@ static int check_version(Elf_Shdr *sechdrs, printk("%s: no version for \"%s\" found: kernel tainted.\n", mod->name, symname); add_taint(TAINT_FORCED_MODULE); + mod->taints |= TAINT_FORCED_MODULE; } return 1; } @@ -1339,6 +1340,7 @@ static void set_license(struct module *mod, const char *license) printk(KERN_WARNING "%s: module license '%s' taints kernel.\n", mod->name, license); add_taint(TAINT_PROPRIETARY_MODULE); + mod->taints |= TAINT_PROPRIETARY_MODULE; } } @@ -1618,6 +1620,7 @@ static struct module *load_module(void __user *umod, /* This is allowed: modprobe --force will invalidate it. */ if (!modmagic) { add_taint(TAINT_FORCED_MODULE); + mod->taints |= TAINT_FORCED_MODULE; printk(KERN_WARNING "%s: no version magic, tainting kernel.\n", mod->name); } else if (!same_magic(modmagic, vermagic)) { @@ -1711,10 +1714,14 @@ static struct module *load_module(void __user *umod, /* Set up license info based on the info section */ set_license(mod, get_modinfo(sechdrs, infoindex, "license")); - if (strcmp(mod->name, "ndiswrapper") == 0) + if (strcmp(mod->name, "ndiswrapper") == 0) { add_taint(TAINT_PROPRIETARY_MODULE); - if (strcmp(mod->name, "driverloader") == 0) + mod->taints |= TAINT_PROPRIETARY_MODULE; + } + if (strcmp(mod->name, "driverloader") == 0) { add_taint(TAINT_PROPRIETARY_MODULE); + mod->taints |= TAINT_PROPRIETARY_MODULE; + } /* Set up MODINFO_ATTR fields */ setup_modinfo(mod, sechdrs, infoindex); @@ -1760,6 +1767,7 @@ static struct module *load_module(void __user *umod, printk(KERN_WARNING "%s: No versions for exported symbols." " Tainting kernel.\n", mod->name); add_taint(TAINT_FORCED_MODULE); + mod->taints |= TAINT_FORCED_MODULE; } #endif @@ -2226,14 +2234,37 @@ struct module *module_text_address(unsigned long addr) return mod; } +static char *taint_flags(unsigned int taints, char *buf) +{ + *buf = '\0'; + if (taints) { + int bx; + + buf[0] = '('; + bx = 1; + if (taints & TAINT_PROPRIETARY_MODULE) + buf[bx++] = 'P'; + if (taints & TAINT_FORCED_MODULE) + buf[bx++] = 'F'; + /* + * TAINT_FORCED_RMMOD: could be added. + * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't + * apply to modules. + */ + buf[bx] = ')'; + } + return buf; +} + /* Don't grab lock, we're oopsing. */ void print_modules(void) { struct module *mod; + char buf[8]; printk("Modules linked in:"); list_for_each_entry(mod, &modules, list) - printk(" %s", mod->name); + printk(" %s%s", mod->name, taint_flags(mod->taints, buf)); printk("\n"); } -- cgit v1.2.3 From 0804ef4b0de7121261f77c565b20a11ac694e877 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 2 Oct 2006 02:17:04 -0700 Subject: [PATCH] proc: readdir race fix (take 3) The problem: An opendir, readdir, closedir sequence can fail to report process ids that are continually in use throughout the sequence of system calls. For this race to trigger the process that proc_pid_readdir stops at must exit before readdir is called again. This can cause ps to fail to report processes, and it is in violation of posix guarantees and normal application expectations with respect to readdir. Currently there is no way to work around this problem in user space short of providing a gargantuan buffer to user space so the directory read all happens in on system call. This patch implements the normal directory semantics for proc, that guarantee that a directory entry that is neither created nor destroyed while reading the directory entry will be returned. For directory that are either created or destroyed during the readdir you may or may not see them. Furthermore you may seek to a directory offset you have previously seen. These are the guarantee that ext[23] provides and that posix requires, and more importantly that user space expects. Plus it is a simple semantic to implement reliable service. It is just a matter of calling readdir a second time if you are wondering if something new has show up. These better semantics are implemented by scanning through the pids in numerical order and by making the file offset a pid plus a fixed offset. The pid scan happens on the pid bitmap, which when you look at it is remarkably efficient for a brute force algorithm. Given that a typical cache line is 64 bytes and thus covers space for 64*8 == 200 pids. There are only 40 cache lines for the entire 32K pid space. A typical system will have 100 pids or more so this is actually fewer cache lines we have to look at to scan a linked list, and the worst case of having to scan the entire pid bitmap is pretty reasonable. If we need something more efficient we can go to a more efficient data structure for indexing the pids, but for now what we have should be sufficient. In addition this takes no additional locks and is actually less code than what we are doing now. Also another very subtle bug in this area has been fixed. It is possible to catch a task in the middle of de_thread where a thread is assuming the thread of it's thread group leader. This patch carefully handles that case so if we hit it we don't fail to return the pid, that is undergoing the de_thread dance. Thanks to KAMEZAWA Hiroyuki for providing the first fix, pointing this out and working on it. [oleg@tv-sign.ru: fix it] Signed-off-by: Eric W. Biederman Acked-by: KAMEZAWA Hiroyuki Signed-off-by: Oleg Nesterov Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 104 +++++++++++++++++--------------------------------- include/linux/pid.h | 1 + include/linux/sched.h | 11 ++++++ kernel/pid.c | 36 +++++++++++++++++ 4 files changed, 83 insertions(+), 69 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/base.c b/fs/proc/base.c index 89c20d9d50bf..b18f3773dd43 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2142,72 +2142,43 @@ out_no_task: } /* - * Find the first tgid to return to user space. + * Find the first task with tgid >= tgid * - * Usually this is just whatever follows &init_task, but if the users - * buffer was too small to hold the full list or there was a seek into - * the middle of the directory we have more work to do. - * - * In the case of a short read we start with find_task_by_pid. - * - * In the case of a seek we start with &init_task and walk nr - * threads past it. */ -static struct task_struct *first_tgid(int tgid, unsigned int nr) +static struct task_struct *next_tgid(unsigned int tgid) { - struct task_struct *pos; - rcu_read_lock(); - if (tgid && nr) { - pos = find_task_by_pid(tgid); - if (pos && thread_group_leader(pos)) - goto found; - } - /* If nr exceeds the number of processes get out quickly */ - pos = NULL; - if (nr && nr >= nr_processes()) - goto done; - - /* If we haven't found our starting place yet start with - * the init_task and walk nr tasks forward. - */ - for (pos = next_task(&init_task); nr > 0; --nr) { - pos = next_task(pos); - if (pos == &init_task) { - pos = NULL; - goto done; - } - } -found: - get_task_struct(pos); -done: - rcu_read_unlock(); - return pos; -} + struct task_struct *task; + struct pid *pid; -/* - * Find the next task in the task list. - * Return NULL if we loop or there is any error. - * - * The reference to the input task_struct is released. - */ -static struct task_struct *next_tgid(struct task_struct *start) -{ - struct task_struct *pos; rcu_read_lock(); - pos = start; - if (pid_alive(start)) - pos = next_task(start); - if (pid_alive(pos) && (pos != &init_task)) { - get_task_struct(pos); - goto done; +retry: + task = NULL; + pid = find_ge_pid(tgid); + if (pid) { + tgid = pid->nr + 1; + task = pid_task(pid, PIDTYPE_PID); + /* What we to know is if the pid we have find is the + * pid of a thread_group_leader. Testing for task + * being a thread_group_leader is the obvious thing + * todo but there is a window when it fails, due to + * the pid transfer logic in de_thread. + * + * So we perform the straight forward test of seeing + * if the pid we have found is the pid of a thread + * group leader, and don't worry if the task we have + * found doesn't happen to be a thread group leader. + * As we don't care in the case of readdir. + */ + if (!task || !has_group_leader_pid(task)) + goto retry; + get_task_struct(task); } - pos = NULL; -done: rcu_read_unlock(); - put_task_struct(start); - return pos; + return task; } +#define TGID_OFFSET (FIRST_PROCESS_ENTRY + (1 /* /proc/self */)) + /* for the /proc/ directory itself, after non-process stuff has been done */ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) { @@ -2223,29 +2194,24 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) filp->f_pos++; nr++; } - nr -= 1; - /* f_version caches the tgid value that the last readdir call couldn't - * return. lseek aka telldir automagically resets f_version to 0. - */ - tgid = filp->f_version; - filp->f_version = 0; - for (task = first_tgid(tgid, nr); + tgid = filp->f_pos - TGID_OFFSET; + for (task = next_tgid(tgid); task; - task = next_tgid(task), filp->f_pos++) { + put_task_struct(task), task = next_tgid(tgid + 1)) { int len; ino_t ino; tgid = task->pid; + filp->f_pos = tgid + TGID_OFFSET; len = snprintf(buf, sizeof(buf), "%d", tgid); ino = fake_ino(tgid, PROC_TGID_INO); if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) { - /* returning this tgid failed, save it as the first - * pid for the next readir call */ - filp->f_version = tgid; put_task_struct(task); - break; + goto out; } } + filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET; +out: return 0; } diff --git a/include/linux/pid.h b/include/linux/pid.h index 93da7e2d9f30..359121086de1 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -89,6 +89,7 @@ extern struct pid *FASTCALL(find_pid(int nr)); * Lookup a PID in the hash table, and return with it's count elevated. */ extern struct pid *find_get_pid(int nr); +extern struct pid *find_ge_pid(int nr); extern struct pid *alloc_pid(void); extern void FASTCALL(free_pid(struct pid *pid)); diff --git a/include/linux/sched.h b/include/linux/sched.h index 7ef899c47c29..be658e33bd26 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1358,6 +1358,17 @@ extern void wait_task_inactive(struct task_struct * p); /* de_thread depends on thread_group_leader not being a pid based check */ #define thread_group_leader(p) (p == p->group_leader) +/* Do to the insanities of de_thread it is possible for a process + * to have the pid of the thread group leader without actually being + * the thread group leader. For iteration through the pids in proc + * all we care about is that we have a task with the appropriate + * pid, we don't actually care if we have the right task. + */ +static inline int has_group_leader_pid(struct task_struct *p) +{ + return p->pid == p->tgid; +} + static inline struct task_struct *next_thread(const struct task_struct *p) { return list_entry(rcu_dereference(p->thread_group.next), diff --git a/kernel/pid.c b/kernel/pid.c index 8387e8c68193..ed89a732432c 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -145,6 +145,23 @@ static int alloc_pidmap(void) return -1; } +static int next_pidmap(int last) +{ + int offset; + pidmap_t *map; + + offset = (last + 1) & BITS_PER_PAGE_MASK; + map = &pidmap_array[(last + 1)/BITS_PER_PAGE]; + for (; map < &pidmap_array[PIDMAP_ENTRIES]; map++, offset = 0) { + if (unlikely(!map->page)) + continue; + offset = find_next_bit((map)->page, BITS_PER_PAGE, offset); + if (offset < BITS_PER_PAGE) + return mk_pid(map, offset); + } + return -1; +} + fastcall void put_pid(struct pid *pid) { if (!pid) @@ -302,6 +319,25 @@ struct pid *find_get_pid(pid_t nr) return pid; } +/* + * Used by proc to find the first pid that is greater then or equal to nr. + * + * If there is a pid at nr this function is exactly the same as find_pid. + */ +struct pid *find_ge_pid(int nr) +{ + struct pid *pid; + + do { + pid = find_pid(nr); + if (pid) + break; + nr = next_pidmap(nr); + } while (nr > 0); + + return pid; +} + /* * The pid hash table is scaled according to the amount of memory in the * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or -- cgit v1.2.3 From 20cdc894c45d2e4ab0c69e95a56b7c5ed36ae0dd Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 2 Oct 2006 02:17:07 -0700 Subject: [PATCH] proc: modify proc_pident_lookup to be completely table driven Currently proc_pident_lookup gets the names and types from a table and then has a huge switch statement to get the inode and file operations it needs. That is silly and is becoming increasingly hard to maintain so I just put all of the information in the table. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 347 +++++++++++++++--------------------------------- include/linux/proc_fs.h | 10 +- 2 files changed, 112 insertions(+), 245 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/base.c b/fs/proc/base.c index cb0cf84df748..9c6a809f92b6 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -194,9 +194,36 @@ struct pid_entry { int len; char *name; mode_t mode; + struct inode_operations *iop; + struct file_operations *fop; + union proc_op op; }; -#define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)} +#define NOD(TYPE, NAME, MODE, IOP, FOP, OP) { \ + .type = (TYPE), \ + .len = sizeof(NAME) - 1, \ + .name = (NAME), \ + .mode = MODE, \ + .iop = IOP, \ + .fop = FOP, \ + .op = OP, \ +} + +#define DIR(TYPE, NAME, MODE, OTYPE) \ + NOD(TYPE, NAME, (S_IFDIR|(MODE)), \ + &proc_##OTYPE##_inode_operations, &proc_##OTYPE##_operations, \ + {} ) +#define LNK(TYPE, NAME, OTYPE) \ + NOD(TYPE, NAME, (S_IFLNK|S_IRWXUGO), \ + &proc_pid_link_inode_operations, NULL, \ + { .proc_get_link = &proc_##OTYPE##_link } ) +#define REG(TYPE, NAME, MODE, OTYPE) \ + NOD(TYPE, NAME, (S_IFREG|(MODE)), NULL, \ + &proc_##OTYPE##_operations, {}) +#define INF(TYPE, NAME, MODE, OTYPE) \ + NOD(TYPE, NAME, (S_IFREG|(MODE)), \ + NULL, &proc_info_file_operations, \ + { .proc_read = &proc_##OTYPE } ) static struct fs_struct *get_fs_struct(struct task_struct *task) { @@ -1367,17 +1394,6 @@ static struct inode_operations proc_fd_inode_operations = { .setattr = proc_setattr, }; -static struct file_operations proc_task_operations; -static struct inode_operations proc_task_inode_operations; - -#ifdef CONFIG_SECURITY -static struct file_operations proc_pid_attr_operations; -static struct file_operations proc_tid_attr_operations; -static struct inode_operations proc_tid_attr_inode_operations; -static struct file_operations proc_tgid_attr_operations; -static struct inode_operations proc_tgid_attr_inode_operations; -#endif - /* SMP-safe */ static struct dentry *proc_pident_lookup(struct inode *dir, struct dentry *dentry, @@ -1395,6 +1411,10 @@ static struct dentry *proc_pident_lookup(struct inode *dir, if (!task) goto out_no_task; + /* + * Yes, it does not scale. And it should not. Don't add + * new entries into /proc// without very good reasons. + */ for (p = ents; p->name; p++) { if (p->len != dentry->d_name.len) continue; @@ -1411,171 +1431,13 @@ static struct dentry *proc_pident_lookup(struct inode *dir, ei = PROC_I(inode); inode->i_mode = p->mode; - /* - * Yes, it does not scale. And it should not. Don't add - * new entries into /proc// without very good reasons. - */ - switch(p->type) { - case PROC_TGID_TASK: - inode->i_nlink = 2; - inode->i_op = &proc_task_inode_operations; - inode->i_fop = &proc_task_operations; - break; - case PROC_TID_FD: - case PROC_TGID_FD: - inode->i_nlink = 2; - inode->i_op = &proc_fd_inode_operations; - inode->i_fop = &proc_fd_operations; - break; - case PROC_TID_EXE: - case PROC_TGID_EXE: - inode->i_op = &proc_pid_link_inode_operations; - ei->op.proc_get_link = proc_exe_link; - break; - case PROC_TID_CWD: - case PROC_TGID_CWD: - inode->i_op = &proc_pid_link_inode_operations; - ei->op.proc_get_link = proc_cwd_link; - break; - case PROC_TID_ROOT: - case PROC_TGID_ROOT: - inode->i_op = &proc_pid_link_inode_operations; - ei->op.proc_get_link = proc_root_link; - break; - case PROC_TID_ENVIRON: - case PROC_TGID_ENVIRON: - inode->i_fop = &proc_info_file_operations; - ei->op.proc_read = proc_pid_environ; - break; - case PROC_TID_AUXV: - case PROC_TGID_AUXV: - inode->i_fop = &proc_info_file_operations; - ei->op.proc_read = proc_pid_auxv; - break; - case PROC_TID_STATUS: - case PROC_TGID_STATUS: - inode->i_fop = &proc_info_file_operations; - ei->op.proc_read = proc_pid_status; - break; - case PROC_TID_STAT: - inode->i_fop = &proc_info_file_operations; - ei->op.proc_read = proc_tid_stat; - break; - case PROC_TGID_STAT: - inode->i_fop = &proc_info_file_operations; - ei->op.proc_read = proc_tgid_stat; - break; - case PROC_TID_CMDLINE: - case PROC_TGID_CMDLINE: - inode->i_fop = &proc_info_file_operations; - ei->op.proc_read = proc_pid_cmdline; - break; - case PROC_TID_STATM: - case PROC_TGID_STATM: - inode->i_fop = &proc_info_file_operations; - ei->op.proc_read = proc_pid_statm; - break; - case PROC_TID_MAPS: - case PROC_TGID_MAPS: - inode->i_fop = &proc_maps_operations; - break; -#ifdef CONFIG_NUMA - case PROC_TID_NUMA_MAPS: - case PROC_TGID_NUMA_MAPS: - inode->i_fop = &proc_numa_maps_operations; - break; -#endif - case PROC_TID_MEM: - case PROC_TGID_MEM: - inode->i_fop = &proc_mem_operations; - break; -#ifdef CONFIG_SECCOMP - case PROC_TID_SECCOMP: - case PROC_TGID_SECCOMP: - inode->i_fop = &proc_seccomp_operations; - break; -#endif /* CONFIG_SECCOMP */ - case PROC_TID_MOUNTS: - case PROC_TGID_MOUNTS: - inode->i_fop = &proc_mounts_operations; - break; -#ifdef CONFIG_MMU - case PROC_TID_SMAPS: - case PROC_TGID_SMAPS: - inode->i_fop = &proc_smaps_operations; - break; -#endif - case PROC_TID_MOUNTSTATS: - case PROC_TGID_MOUNTSTATS: - inode->i_fop = &proc_mountstats_operations; - break; -#ifdef CONFIG_SECURITY - case PROC_TID_ATTR: - inode->i_nlink = 2; - inode->i_op = &proc_tid_attr_inode_operations; - inode->i_fop = &proc_tid_attr_operations; - break; - case PROC_TGID_ATTR: - inode->i_nlink = 2; - inode->i_op = &proc_tgid_attr_inode_operations; - inode->i_fop = &proc_tgid_attr_operations; - break; - case PROC_TID_ATTR_CURRENT: - case PROC_TGID_ATTR_CURRENT: - case PROC_TID_ATTR_PREV: - case PROC_TGID_ATTR_PREV: - case PROC_TID_ATTR_EXEC: - case PROC_TGID_ATTR_EXEC: - case PROC_TID_ATTR_FSCREATE: - case PROC_TGID_ATTR_FSCREATE: - case PROC_TID_ATTR_KEYCREATE: - case PROC_TGID_ATTR_KEYCREATE: - case PROC_TID_ATTR_SOCKCREATE: - case PROC_TGID_ATTR_SOCKCREATE: - inode->i_fop = &proc_pid_attr_operations; - break; -#endif -#ifdef CONFIG_KALLSYMS - case PROC_TID_WCHAN: - case PROC_TGID_WCHAN: - inode->i_fop = &proc_info_file_operations; - ei->op.proc_read = proc_pid_wchan; - break; -#endif -#ifdef CONFIG_SCHEDSTATS - case PROC_TID_SCHEDSTAT: - case PROC_TGID_SCHEDSTAT: - inode->i_fop = &proc_info_file_operations; - ei->op.proc_read = proc_pid_schedstat; - break; -#endif -#ifdef CONFIG_CPUSETS - case PROC_TID_CPUSET: - case PROC_TGID_CPUSET: - inode->i_fop = &proc_cpuset_operations; - break; -#endif - case PROC_TID_OOM_SCORE: - case PROC_TGID_OOM_SCORE: - inode->i_fop = &proc_info_file_operations; - ei->op.proc_read = proc_oom_score; - break; - case PROC_TID_OOM_ADJUST: - case PROC_TGID_OOM_ADJUST: - inode->i_fop = &proc_oom_adjust_operations; - break; -#ifdef CONFIG_AUDITSYSCALL - case PROC_TID_LOGINUID: - case PROC_TGID_LOGINUID: - inode->i_fop = &proc_loginuid_operations; - break; -#endif - default: - printk("procfs: impossible type (%d)",p->type); - iput(inode); - error = ERR_PTR(-EINVAL); - goto out; - } + if (S_ISDIR(inode->i_mode)) + inode->i_nlink = 2; /* Use getattr to fix if necessary */ + if (p->iop) + inode->i_op = p->iop; + if (p->fop) + inode->i_fop = p->fop; + ei->op = p->op; dentry->d_op = &pid_dentry_operations; d_add(dentry, inode); /* Close the race of the process dying before we return the dentry */ @@ -1720,22 +1582,22 @@ static struct file_operations proc_pid_attr_operations = { }; static struct pid_entry tgid_attr_stuff[] = { - E(PROC_TGID_ATTR_CURRENT, "current", S_IFREG|S_IRUGO|S_IWUGO), - E(PROC_TGID_ATTR_PREV, "prev", S_IFREG|S_IRUGO), - E(PROC_TGID_ATTR_EXEC, "exec", S_IFREG|S_IRUGO|S_IWUGO), - E(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO), - E(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO), - E(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO), - {0,0,NULL,0} + REG(PROC_TGID_ATTR_CURRENT, "current", S_IRUGO|S_IWUGO, pid_attr), + REG(PROC_TGID_ATTR_PREV, "prev", S_IRUGO, pid_attr), + REG(PROC_TGID_ATTR_EXEC, "exec", S_IRUGO|S_IWUGO, pid_attr), + REG(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IRUGO|S_IWUGO, pid_attr), + REG(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IRUGO|S_IWUGO, pid_attr), + REG(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IRUGO|S_IWUGO, pid_attr), + {} }; static struct pid_entry tid_attr_stuff[] = { - E(PROC_TID_ATTR_CURRENT, "current", S_IFREG|S_IRUGO|S_IWUGO), - E(PROC_TID_ATTR_PREV, "prev", S_IFREG|S_IRUGO), - E(PROC_TID_ATTR_EXEC, "exec", S_IFREG|S_IRUGO|S_IWUGO), - E(PROC_TID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO), - E(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO), - E(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO), - {0,0,NULL,0} + REG(PROC_TID_ATTR_CURRENT, "current", S_IRUGO|S_IWUGO, pid_attr), + REG(PROC_TID_ATTR_PREV, "prev", S_IRUGO, pid_attr), + REG(PROC_TID_ATTR_EXEC, "exec", S_IRUGO|S_IWUGO, pid_attr), + REG(PROC_TID_ATTR_FSCREATE, "fscreate", S_IRUGO|S_IWUGO, pid_attr), + REG(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IRUGO|S_IWUGO, pid_attr), + REG(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IRUGO|S_IWUGO, pid_attr), + {} }; static int proc_tgid_attr_readdir(struct file * filp, @@ -1813,49 +1675,52 @@ static struct inode_operations proc_self_inode_operations = { /* * Thread groups */ +static struct file_operations proc_task_operations; +static struct inode_operations proc_task_inode_operations; + static struct pid_entry tgid_base_stuff[] = { - E(PROC_TGID_TASK, "task", S_IFDIR|S_IRUGO|S_IXUGO), - E(PROC_TGID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR), - E(PROC_TGID_ENVIRON, "environ", S_IFREG|S_IRUSR), - E(PROC_TGID_AUXV, "auxv", S_IFREG|S_IRUSR), - E(PROC_TGID_STATUS, "status", S_IFREG|S_IRUGO), - E(PROC_TGID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), - E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), - E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), - E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), + DIR(PROC_TGID_TASK, "task", S_IRUGO|S_IXUGO, task), + DIR(PROC_TGID_FD, "fd", S_IRUSR|S_IXUSR, fd), + INF(PROC_TGID_ENVIRON, "environ", S_IRUSR, pid_environ), + INF(PROC_TGID_AUXV, "auxv", S_IRUSR, pid_auxv), + INF(PROC_TGID_STATUS, "status", S_IRUGO, pid_status), + INF(PROC_TGID_CMDLINE, "cmdline", S_IRUGO, pid_cmdline), + INF(PROC_TGID_STAT, "stat", S_IRUGO, tgid_stat), + INF(PROC_TGID_STATM, "statm", S_IRUGO, pid_statm), + REG(PROC_TGID_MAPS, "maps", S_IRUGO, maps), #ifdef CONFIG_NUMA - E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO), + REG(PROC_TGID_NUMA_MAPS, "numa_maps", S_IRUGO, numa_maps), #endif - E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), + REG(PROC_TGID_MEM, "mem", S_IRUSR|S_IWUSR, mem), #ifdef CONFIG_SECCOMP - E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), + REG(PROC_TGID_SECCOMP, "seccomp", S_IRUSR|S_IWUSR, seccomp), #endif - E(PROC_TGID_CWD, "cwd", S_IFLNK|S_IRWXUGO), - E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), - E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), - E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), - E(PROC_TGID_MOUNTSTATS, "mountstats", S_IFREG|S_IRUSR), + LNK(PROC_TGID_CWD, "cwd", cwd), + LNK(PROC_TGID_ROOT, "root", root), + LNK(PROC_TGID_EXE, "exe", exe), + REG(PROC_TGID_MOUNTS, "mounts", S_IRUGO, mounts), + REG(PROC_TGID_MOUNTSTATS, "mountstats", S_IRUSR, mountstats), #ifdef CONFIG_MMU - E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), + REG(PROC_TGID_SMAPS, "smaps", S_IRUGO, smaps), #endif #ifdef CONFIG_SECURITY - E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), + DIR(PROC_TGID_ATTR, "attr", S_IRUGO|S_IXUGO, tgid_attr), #endif #ifdef CONFIG_KALLSYMS - E(PROC_TGID_WCHAN, "wchan", S_IFREG|S_IRUGO), + INF(PROC_TGID_WCHAN, "wchan", S_IRUGO, pid_wchan), #endif #ifdef CONFIG_SCHEDSTATS - E(PROC_TGID_SCHEDSTAT, "schedstat", S_IFREG|S_IRUGO), + INF(PROC_TGID_SCHEDSTAT, "schedstat", S_IRUGO, pid_schedstat), #endif #ifdef CONFIG_CPUSETS - E(PROC_TGID_CPUSET, "cpuset", S_IFREG|S_IRUGO), + REG(PROC_TGID_CPUSET, "cpuset", S_IRUGO, cpuset), #endif - E(PROC_TGID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO), - E(PROC_TGID_OOM_ADJUST,"oom_adj", S_IFREG|S_IRUGO|S_IWUSR), + INF(PROC_TGID_OOM_SCORE, "oom_score", S_IRUGO, oom_score), + REG(PROC_TGID_OOM_ADJUST, "oom_adj", S_IRUGO|S_IWUSR, oom_adjust), #ifdef CONFIG_AUDITSYSCALL - E(PROC_TGID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO), + REG(PROC_TGID_LOGINUID, "loginuid", S_IWUSR|S_IRUGO, loginuid), #endif - {0,0,NULL,0} + {} }; static int proc_tgid_base_readdir(struct file * filp, @@ -2088,46 +1953,46 @@ out: * Tasks */ static struct pid_entry tid_base_stuff[] = { - E(PROC_TID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR), - E(PROC_TID_ENVIRON, "environ", S_IFREG|S_IRUSR), - E(PROC_TID_AUXV, "auxv", S_IFREG|S_IRUSR), - E(PROC_TID_STATUS, "status", S_IFREG|S_IRUGO), - E(PROC_TID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), - E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), - E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), - E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), + DIR(PROC_TID_FD, "fd", S_IRUSR|S_IXUSR, fd), + INF(PROC_TID_ENVIRON, "environ", S_IRUSR, pid_environ), + INF(PROC_TID_AUXV, "auxv", S_IRUSR, pid_auxv), + INF(PROC_TID_STATUS, "status", S_IRUGO, pid_status), + INF(PROC_TID_CMDLINE, "cmdline", S_IRUGO, pid_cmdline), + INF(PROC_TID_STAT, "stat", S_IRUGO, tid_stat), + INF(PROC_TID_STATM, "statm", S_IRUGO, pid_statm), + REG(PROC_TID_MAPS, "maps", S_IRUGO, maps), #ifdef CONFIG_NUMA - E(PROC_TID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO), + REG(PROC_TID_NUMA_MAPS, "numa_maps", S_IRUGO, numa_maps), #endif - E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), + REG(PROC_TID_MEM, "mem", S_IRUSR|S_IWUSR, mem), #ifdef CONFIG_SECCOMP - E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), + REG(PROC_TID_SECCOMP, "seccomp", S_IRUSR|S_IWUSR, seccomp), #endif - E(PROC_TID_CWD, "cwd", S_IFLNK|S_IRWXUGO), - E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), - E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), - E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), + LNK(PROC_TID_CWD, "cwd", cwd), + LNK(PROC_TID_ROOT, "root", root), + LNK(PROC_TID_EXE, "exe", exe), + REG(PROC_TID_MOUNTS, "mounts", S_IRUGO, mounts), #ifdef CONFIG_MMU - E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO), + REG(PROC_TID_SMAPS, "smaps", S_IRUGO, smaps), #endif #ifdef CONFIG_SECURITY - E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), + DIR(PROC_TID_ATTR, "attr", S_IRUGO|S_IXUGO, tid_attr), #endif #ifdef CONFIG_KALLSYMS - E(PROC_TID_WCHAN, "wchan", S_IFREG|S_IRUGO), + INF(PROC_TID_WCHAN, "wchan", S_IRUGO, pid_wchan), #endif #ifdef CONFIG_SCHEDSTATS - E(PROC_TID_SCHEDSTAT, "schedstat",S_IFREG|S_IRUGO), + INF(PROC_TID_SCHEDSTAT, "schedstat", S_IRUGO, pid_schedstat), #endif #ifdef CONFIG_CPUSETS - E(PROC_TID_CPUSET, "cpuset", S_IFREG|S_IRUGO), + REG(PROC_TID_CPUSET, "cpuset", S_IRUGO, cpuset), #endif - E(PROC_TID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO), - E(PROC_TID_OOM_ADJUST, "oom_adj", S_IFREG|S_IRUGO|S_IWUSR), + INF(PROC_TID_OOM_SCORE, "oom_score", S_IRUGO, oom_score), + REG(PROC_TID_OOM_ADJUST, "oom_adj", S_IRUGO|S_IWUSR, oom_adjust), #ifdef CONFIG_AUDITSYSCALL - E(PROC_TID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO), + REG(PROC_TID_LOGINUID, "loginuid", S_IWUSR|S_IRUGO, loginuid), #endif - {0,0,NULL,0} + {} }; static int proc_tid_base_readdir(struct file * filp, diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 57f70bc8b24b..87dec8fe6de9 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -244,13 +244,15 @@ static inline void kclist_add(struct kcore_list *new, void *addr, size_t size) extern void kclist_add(struct kcore_list *, void *, size_t); #endif +union proc_op { + int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **); + int (*proc_read)(struct task_struct *task, char *page); +}; + struct proc_inode { struct pid *pid; int fd; - union { - int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **); - int (*proc_read)(struct task_struct *task, char *page); - } op; + union proc_op op; struct proc_dir_entry *pde; struct inode vfs_inode; }; -- cgit v1.2.3 From 22c935f47c03399c78e64c71b757eb36fa917ff6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 2 Oct 2006 02:17:09 -0700 Subject: [PATCH] pid: implement access helpers for a tacks various process groups In the last round of cleaning up the pid hash table a more general struct pid was introduced, that can be referenced counted. With the more general struct pid most if not all places where we store a pid_t we can now store a struct pid * and remove the need for a hash table lookup, and avoid any possible problems with pid roll over. Looking forward to the pid namespaces struct pid * gives us an absolute form a pid so we can compare and use them without caring which pid namespace we are in. This patchset introduces the infrastructure needed to use struct pid instead of pid_t, and then it goes on to convert two different kernel users that currently store a pid_t value. There are a lot more places to go but this is enough to get the basic idea. Before we can merge a pid namespace patch all of the kernel pid_t users need to be examined. Those that deal with user space processes need to be converted to using a struct pid *. Those that deal with kernel processes need to converted to using the kthread api. A rare few that only use their current processes pid values get to be left alone. This patch: task_session returns the struct pid of a tasks session. task_pgrp returns the struct pid of a tasks process group. task_tgid returns the struct pid of a tasks thread group. task_pid returns the struct pid of a tasks process id. These can be used to avoid unnecessary hash table lookups, and to implement safe pid comparisions in the face of a pid namespace. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index be658e33bd26..660b02f80523 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1020,6 +1020,26 @@ static inline pid_t process_group(struct task_struct *tsk) return tsk->signal->pgrp; } +static inline struct pid *task_pid(struct task_struct *task) +{ + return task->pids[PIDTYPE_PID].pid; +} + +static inline struct pid *task_tgid(struct task_struct *task) +{ + return task->group_leader->pids[PIDTYPE_PID].pid; +} + +static inline struct pid *task_pgrp(struct task_struct *task) +{ + return task->group_leader->pids[PIDTYPE_PGID].pid; +} + +static inline struct pid *task_session(struct task_struct *task) +{ + return task->group_leader->pids[PIDTYPE_SID].pid; +} + /** * pid_alive - check that a task structure is not stale * @p: Task structure to be checked. -- cgit v1.2.3 From 558cb325485aaf655130f140e8ddd25392f6c972 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 2 Oct 2006 02:17:09 -0700 Subject: [PATCH] pid: add do_each_pid_task To avoid pid rollover confusion the kernel needs to work with struct pid * instead of pid_t. Currently there is not an iterator that walks through all of the tasks of a given pid type starting with a struct pid. This prevents us replacing some pid_t instances with struct pid. So this patch adds do_each_pid_task which walks through the set of task for a given pid type starting with a struct pid. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pid.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pid.h b/include/linux/pid.h index 359121086de1..8cf9b11ed264 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -119,4 +119,17 @@ extern void FASTCALL(free_pid(struct pid *pid)); 1; }) ); \ } +#define do_each_pid_task(pid, type, task) \ + if ((task = pid_task(pid, type))) { \ + prefetch(pid_next(task, type)); \ + do { + +#define while_each_pid_task(pid, type, task) \ + } while (pid_next(task, type) && ({ \ + task = pid_next_task(task, type); \ + rcu_dereference(task); \ + prefetch(pid_next(task, type)); \ + 1; }) ); \ + } + #endif /* _LINUX_PID_H */ -- cgit v1.2.3 From c4b92fc112f7be5cce308128236ff75cc98535c3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 2 Oct 2006 02:17:10 -0700 Subject: [PATCH] pid: implement signal functions that take a struct pid * Currently the signal functions all either take a task or a pid_t argument. This patch implements variants that take a struct pid *. After all of the users have been update it is my intention to remove the variants that take a pid_t as using pid_t can be more work (an extra hash table lookup) and difficult to get right in the presence of multiple pid namespaces. There are two kinds of functions introduced in this patch. The are the general use functions kill_pgrp and kill_pid which take a priv argument that is ultimately used to create the appropriate siginfo information, Then there are _kill_pgrp_info, kill_pgrp_info, kill_pid_info the internal implementation helpers that take an explicit siginfo. The distinction is made because filling out an explcit siginfo is tricky, and will be even more tricky when pid namespaces are introduced. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 5 +++++ kernel/signal.c | 57 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 660b02f80523..dd6c2164e4a4 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1267,6 +1267,11 @@ extern int send_sig_info(int, struct siginfo *, struct task_struct *); extern int send_group_sig_info(int, struct siginfo *, struct task_struct *); extern int force_sigsegv(int, struct task_struct *); extern int force_sig_info(int, struct siginfo *, struct task_struct *); +extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp); +extern int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp); +extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid); +extern int kill_pgrp(struct pid *pid, int sig, int priv); +extern int kill_pid(struct pid *pid, int sig, int priv); extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); extern int kill_pg_info(int, struct siginfo *, pid_t); extern int kill_proc_info(int, struct siginfo *, pid_t); diff --git a/kernel/signal.c b/kernel/signal.c index fb5da6d19f14..5230ddcb1757 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1055,28 +1055,44 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) } /* - * kill_pg_info() sends a signal to a process group: this is what the tty + * kill_pgrp_info() sends a signal to a process group: this is what the tty * control characters do (^C, ^Z etc) */ -int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) +int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) { struct task_struct *p = NULL; int retval, success; - if (pgrp <= 0) - return -EINVAL; - success = 0; retval = -ESRCH; - do_each_task_pid(pgrp, PIDTYPE_PGID, p) { + do_each_pid_task(pgrp, PIDTYPE_PGID, p) { int err = group_send_sig_info(sig, info, p); success |= !err; retval = err; - } while_each_task_pid(pgrp, PIDTYPE_PGID, p); + } while_each_pid_task(pgrp, PIDTYPE_PGID, p); return success ? 0 : retval; } +int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) +{ + int retval; + + read_lock(&tasklist_lock); + retval = __kill_pgrp_info(sig, info, pgrp); + read_unlock(&tasklist_lock); + + return retval; +} + +int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) +{ + if (pgrp <= 0) + return -EINVAL; + + return __kill_pgrp_info(sig, info, find_pid(pgrp)); +} + int kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) { @@ -1089,8 +1105,7 @@ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) return retval; } -int -kill_proc_info(int sig, struct siginfo *info, pid_t pid) +int kill_pid_info(int sig, struct siginfo *info, struct pid *pid) { int error; int acquired_tasklist_lock = 0; @@ -1101,7 +1116,7 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid) read_lock(&tasklist_lock); acquired_tasklist_lock = 1; } - p = find_task_by_pid(pid); + p = pid_task(pid, PIDTYPE_PID); error = -ESRCH; if (p) error = group_send_sig_info(sig, info, p); @@ -1111,6 +1126,16 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid) return error; } +int +kill_proc_info(int sig, struct siginfo *info, pid_t pid) +{ + int error; + rcu_read_lock(); + error = kill_pid_info(sig, info, find_pid(pid)); + rcu_read_unlock(); + return error; +} + /* like kill_proc_info(), but doesn't use uid/euid of "current" */ int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, uid_t uid, uid_t euid, u32 secid) @@ -1264,6 +1289,18 @@ force_sigsegv(int sig, struct task_struct *p) return 0; } +int kill_pgrp(struct pid *pid, int sig, int priv) +{ + return kill_pgrp_info(sig, __si_special(priv), pid); +} +EXPORT_SYMBOL(kill_pgrp); + +int kill_pid(struct pid *pid, int sig, int priv) +{ + return kill_pid_info(sig, __si_special(priv), pid); +} +EXPORT_SYMBOL(kill_pid); + int kill_pg(pid_t pgrp, int sig, int priv) { -- cgit v1.2.3 From 5feb8f5f8403d8874a04aac443692dfe83bd63d2 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 2 Oct 2006 02:17:12 -0700 Subject: [PATCH] pid: implement pid_nr As we stop storing pid_t's and move to storing struct pid *. We need a way to get the pid_t from the struct pid to report to user space what we have stored. Having a clean well defined way to do this is especially important as we move to multiple pid spaces as may need to report a different value to the caller depending on which pid space the caller is in. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pid.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pid.h b/include/linux/pid.h index 8cf9b11ed264..dba1b2d677a3 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -94,6 +94,14 @@ extern struct pid *find_ge_pid(int nr); extern struct pid *alloc_pid(void); extern void FASTCALL(free_pid(struct pid *pid)); +static inline pid_t pid_nr(struct pid *pid) +{ + pid_t nr = 0; + if (pid) + nr = pid->nr; + return nr; +} + #define pid_next(task, type) \ ((task)->pids[(type)].node.next) -- cgit v1.2.3 From 81af8d67d4fc35b1ee6e0feb1f1b34b3a33eeb44 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 2 Oct 2006 02:17:13 -0700 Subject: [PATCH] vt: rework the console spawning variables This is such a rare path it took me a while to figure out how to test this after soring out the locking. This patch does several things. - The variables used are moved into a structure and declared in vt_kern.h - A spinlock is added so we don't have SMP races updating the values. - Instead of raw pid_t value a struct_pid is used to guard against pid wrap around issues, if the daemon to spawn a new console dies. Signed-off-by: Eric W. Biederman Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/keyboard.c | 16 ++++++++++++---- drivers/char/vt_ioctl.c | 9 ++++++--- include/linux/vt_kern.h | 7 +++++++ 3 files changed, 25 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 3e90aac37510..99fb070fdbf8 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -108,7 +108,11 @@ const int NR_TYPES = ARRAY_SIZE(max_vals); struct kbd_struct kbd_table[MAX_NR_CONSOLES]; static struct kbd_struct *kbd = kbd_table; -int spawnpid, spawnsig; +struct vt_spawn_console vt_spawn_con = { + .lock = SPIN_LOCK_UNLOCKED, + .pid = NULL, + .sig = 0, +}; /* * Variables exported for vt.c @@ -578,9 +582,13 @@ static void fn_compose(struct vc_data *vc, struct pt_regs *regs) static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs) { - if (spawnpid) - if (kill_proc(spawnpid, spawnsig, 1)) - spawnpid = 0; + spin_lock(&vt_spawn_con.lock); + if (vt_spawn_con.pid) + if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) { + put_pid(vt_spawn_con.pid); + vt_spawn_con.pid = NULL; + } + spin_unlock(&vt_spawn_con.lock); } static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index a53e382cc107..dc408af165ab 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -645,13 +645,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, */ case KDSIGACCEPT: { - extern int spawnpid, spawnsig; if (!perm || !capable(CAP_KILL)) return -EPERM; if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) return -EINVAL; - spawnpid = current->pid; - spawnsig = arg; + + spin_lock_irq(&vt_spawn_con.lock); + put_pid(vt_spawn_con.pid); + vt_spawn_con.pid = get_pid(task_pid(current)); + vt_spawn_con.sig = arg; + spin_unlock_irq(&vt_spawn_con.lock); return 0; } diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 1009d3fe1fc2..37a1a41f5b65 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -84,4 +84,11 @@ void reset_vc(struct vc_data *vc); extern char con_buf[CON_BUF_SIZE]; extern struct semaphore con_buf_sem; +struct vt_spawn_console { + spinlock_t lock; + struct pid *pid; + int sig; +}; +extern struct vt_spawn_console vt_spawn_con; + #endif /* _VT_KERN_H */ -- cgit v1.2.3 From bde0d2c98bcfc9acc83ac79c33a6ac1335b95a92 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 2 Oct 2006 02:17:14 -0700 Subject: [PATCH] vt: Make vt_pid a struct pid (making it pid wrap around safe). I took a good hard look at the locking and it appears the locking on vt_pid is the console semaphore. Every modified path is called under the console semaphore except reset_vc when it is called from fn_SAK or do_SAK both of which appear to be in interrupt context. In addition I need to be careful because in the presence of an oops the console_sem may be arbitrarily dropped. Which leads me to conclude the current locking is inadequate for my needs. Given the weird cases we could hit because of oops printing instead of introducing an extra spin lock to protect the data and keep the pid to signal and the signal to send in sync, I have opted to use xchg on just the struct pid * pointer instead. Due to console_sem we will stay in sync between vt_pid and vt_mode except for a small window during a SAK, or oops handling. SAK handling should kill any user space process that care, and oops handling we are broken anyway. Besides the worst that can happen is that I try to send the wrong signal. Signed-off-by: Eric W. Biederman Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/vt.c | 1 + drivers/char/vt_ioctl.c | 8 ++++---- include/linux/console_struct.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index fb75da940b59..303956d34569 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -903,6 +903,7 @@ void vc_deallocate(unsigned int currcons) if (vc_cons_allocated(currcons)) { struct vc_data *vc = vc_cons[currcons].d; vc->vc_sw->con_deinit(vc); + put_pid(vc->vt_pid); module_put(vc->vc_sw->owner); if (vc->vc_kmalloced) kfree(vc->vc_screenbuf); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index dc408af165ab..ac5d60edbafa 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -672,7 +672,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, vc->vt_mode = tmp; /* the frsig is ignored, so we set it to 0 */ vc->vt_mode.frsig = 0; - vc->vt_pid = current->pid; + put_pid(xchg(&vc->vt_pid, get_pid(task_pid(current)))); /* no switch is required -- saw@shade.msu.ru */ vc->vt_newvt = -1; release_console_sem(); @@ -1063,7 +1063,7 @@ void reset_vc(struct vc_data *vc) vc->vt_mode.relsig = 0; vc->vt_mode.acqsig = 0; vc->vt_mode.frsig = 0; - vc->vt_pid = -1; + put_pid(xchg(&vc->vt_pid, NULL)); vc->vt_newvt = -1; if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ reset_palette(vc); @@ -1114,7 +1114,7 @@ static void complete_change_console(struct vc_data *vc) * tell us if the process has gone or something else * is awry */ - if (kill_proc(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { + if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { /* * The controlling process has died, so we revert back to * normal operation. In this case, we'll also change back @@ -1174,7 +1174,7 @@ void change_console(struct vc_data *new_vc) * tell us if the process has gone or something else * is awry */ - if (kill_proc(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { + if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { /* * It worked. Mark the vt to switch to and * return. The process needs to send us a diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index 25423f79bf9f..ed6c0fee1ac7 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -54,7 +54,7 @@ struct vc_data { struct tty_struct *vc_tty; /* TTY we are attached to */ /* data for manual vt switching */ struct vt_mode vt_mode; - int vt_pid; + struct pid *vt_pid; int vt_newvt; wait_queue_head_t paste_wait; /* mode flags */ -- cgit v1.2.3 From 609d7fa9565c754428d2520cac2accc9052e1245 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 2 Oct 2006 02:17:15 -0700 Subject: [PATCH] file: modify struct fown_struct to use a struct pid File handles can be requested to send sigio and sigurg to processes. By tracking the destination processes using struct pid instead of pid_t we make the interface safe from all potential pid wrap around problems. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/tun.c | 2 +- fs/dnotify.c | 2 +- fs/fcntl.c | 77 ++++++++++++++++++++++++++++++++++-------------------- fs/file_table.c | 1 + fs/locks.c | 2 +- include/linux/fs.h | 5 +++- kernel/futex.c | 2 +- net/socket.c | 2 +- 8 files changed, 59 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index bc0face01d25..151a2e10e4f3 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -697,7 +697,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on) return ret; if (on) { - ret = f_setown(file, current->pid, 0); + ret = __f_setown(file, task_pid(current), PIDTYPE_PID, 0); if (ret) return ret; tun->flags |= TUN_FASYNC; diff --git a/fs/dnotify.c b/fs/dnotify.c index f932591df5a4..2b0442db67e0 100644 --- a/fs/dnotify.c +++ b/fs/dnotify.c @@ -92,7 +92,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) prev = &odn->dn_next; } - error = f_setown(filp, current->pid, 0); + error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); if (error) goto out_free; diff --git a/fs/fcntl.c b/fs/fcntl.c index d35cbc6bc112..e7c66a1bf831 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -250,19 +250,22 @@ static int setfl(int fd, struct file * filp, unsigned long arg) return error; } -static void f_modown(struct file *filp, unsigned long pid, +static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, uid_t uid, uid_t euid, int force) { write_lock_irq(&filp->f_owner.lock); if (force || !filp->f_owner.pid) { - filp->f_owner.pid = pid; + put_pid(filp->f_owner.pid); + filp->f_owner.pid = get_pid(pid); + filp->f_owner.pid_type = type; filp->f_owner.uid = uid; filp->f_owner.euid = euid; } write_unlock_irq(&filp->f_owner.lock); } -int f_setown(struct file *filp, unsigned long arg, int force) +int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, + int force) { int err; @@ -270,15 +273,42 @@ int f_setown(struct file *filp, unsigned long arg, int force) if (err) return err; - f_modown(filp, arg, current->uid, current->euid, force); + f_modown(filp, pid, type, current->uid, current->euid, force); return 0; } +EXPORT_SYMBOL(__f_setown); +int f_setown(struct file *filp, unsigned long arg, int force) +{ + enum pid_type type; + struct pid *pid; + int who = arg; + int result; + type = PIDTYPE_PID; + if (who < 0) { + type = PIDTYPE_PGID; + who = -who; + } + rcu_read_lock(); + pid = find_pid(who); + result = __f_setown(filp, pid, type, force); + rcu_read_unlock(); + return result; +} EXPORT_SYMBOL(f_setown); void f_delown(struct file *filp) { - f_modown(filp, 0, 0, 0, 1); + f_modown(filp, NULL, PIDTYPE_PID, 0, 0, 1); +} + +pid_t f_getown(struct file *filp) +{ + pid_t pid; + pid = pid_nr(filp->f_owner.pid); + if (filp->f_owner.pid_type == PIDTYPE_PGID) + pid = -pid; + return pid; } static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, @@ -319,7 +349,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, * current syscall conventions, the only way * to fix this will be in libc. */ - err = filp->f_owner.pid; + err = f_getown(filp); force_successful_syscall_return(); break; case F_SETOWN: @@ -470,24 +500,19 @@ static void send_sigio_to_task(struct task_struct *p, void send_sigio(struct fown_struct *fown, int fd, int band) { struct task_struct *p; - int pid; + enum pid_type type; + struct pid *pid; read_lock(&fown->lock); + type = fown->pid_type; pid = fown->pid; if (!pid) goto out_unlock_fown; read_lock(&tasklist_lock); - if (pid > 0) { - p = find_task_by_pid(pid); - if (p) { - send_sigio_to_task(p, fown, fd, band); - } - } else { - do_each_task_pid(-pid, PIDTYPE_PGID, p) { - send_sigio_to_task(p, fown, fd, band); - } while_each_task_pid(-pid, PIDTYPE_PGID, p); - } + do_each_pid_task(pid, type, p) { + send_sigio_to_task(p, fown, fd, band); + } while_each_pid_task(pid, type, p); read_unlock(&tasklist_lock); out_unlock_fown: read_unlock(&fown->lock); @@ -503,9 +528,12 @@ static void send_sigurg_to_task(struct task_struct *p, int send_sigurg(struct fown_struct *fown) { struct task_struct *p; - int pid, ret = 0; + enum pid_type type; + struct pid *pid; + int ret = 0; read_lock(&fown->lock); + type = fown->pid_type; pid = fown->pid; if (!pid) goto out_unlock_fown; @@ -513,16 +541,9 @@ int send_sigurg(struct fown_struct *fown) ret = 1; read_lock(&tasklist_lock); - if (pid > 0) { - p = find_task_by_pid(pid); - if (p) { - send_sigurg_to_task(p, fown); - } - } else { - do_each_task_pid(-pid, PIDTYPE_PGID, p) { - send_sigurg_to_task(p, fown); - } while_each_task_pid(-pid, PIDTYPE_PGID, p); - } + do_each_pid_task(pid, type, p) { + send_sigurg_to_task(p, fown); + } while_each_pid_task(pid, type, p); read_unlock(&tasklist_lock); out_unlock_fown: read_unlock(&fown->lock); diff --git a/fs/file_table.c b/fs/file_table.c index bc35a40417d7..24f25a057d9c 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -174,6 +174,7 @@ void fastcall __fput(struct file *file) fops_put(file->f_op); if (file->f_mode & FMODE_WRITE) put_write_access(inode); + put_pid(file->f_owner.pid); file_kill(file); file->f_dentry = NULL; file->f_vfsmnt = NULL; diff --git a/fs/locks.c b/fs/locks.c index 21dfadfca2bc..e0b6a80649a0 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1514,7 +1514,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) goto out_unlock; } - error = f_setown(filp, current->pid, 0); + error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); out_unlock: unlock_kernel(); return error; diff --git a/include/linux/fs.h b/include/linux/fs.h index 2e29a2edaeec..91c0b2a32a90 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -684,7 +684,8 @@ extern struct block_device *I_BDEV(struct inode *inode); struct fown_struct { rwlock_t lock; /* protects pid, uid, euid fields */ - int pid; /* pid or -pgrp where SIGIO should be sent */ + struct pid *pid; /* pid or -pgrp where SIGIO should be sent */ + enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */ uid_t uid, euid; /* uid/euid of process setting the owner */ int signum; /* posix.1b rt signal to be delivered on IO */ }; @@ -880,8 +881,10 @@ extern void kill_fasync(struct fasync_struct **, int, int); /* only for net: no internal synchronization */ extern void __kill_fasync(struct fasync_struct *, int, int); +extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force); extern int f_setown(struct file *filp, unsigned long arg, int force); extern void f_delown(struct file *filp); +extern pid_t f_getown(struct file *filp); extern int send_sigurg(struct fown_struct *fown); /* diff --git a/kernel/futex.c b/kernel/futex.c index 4b6770e9806d..4aaf91951a43 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1527,7 +1527,7 @@ static int futex_fd(u32 __user *uaddr, int signal) filp->f_mapping = filp->f_dentry->d_inode->i_mapping; if (signal) { - err = f_setown(filp, current->pid, 1); + err = __f_setown(filp, task_pid(current), PIDTYPE_PID, 1); if (err < 0) { goto error; } diff --git a/net/socket.c b/net/socket.c index 01918f7a301a..6c9b9b326d76 100644 --- a/net/socket.c +++ b/net/socket.c @@ -825,7 +825,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) break; case FIOGETOWN: case SIOCGPGRP: - err = put_user(sock->file->f_owner.pid, + err = put_user(f_getown(sock->file), (int __user *)argp); break; case SIOCGIFBR: -- cgit v1.2.3 From b68e31d0ebbcc909d1941f9f230c9d062a3a13d3 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 2 Oct 2006 02:17:18 -0700 Subject: [PATCH] const struct tty_operations As part of an SMP cleanliness pass over UML, I consted a bunch of structures in order to not have to document their locking. One of these structures was a struct tty_operations. In order to const it in UML without introducing compiler complaints, the declaration of tty_set_operations needs to be changed, and then all of its callers need to be fixed. This patch declares all struct tty_operations in the tree as const. In all cases, they are static and used only as input to tty_set_operations. As an extra check, I ran an i386 allyesconfig build which produced no extra warnings. 53 drivers are affected. I checked the history of a bunch of them, and in most cases, there have been only a handful of maintenance changes in the last six months. serial_core.c was the busiest one that I looked at. Signed-off-by: Jeff Dike Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/srmcons.c | 2 +- arch/ia64/hp/sim/simserial.c | 2 +- arch/ppc/4xx_io/serial_sicc.c | 2 +- arch/um/drivers/line.c | 6 +++--- arch/um/include/line.h | 7 +++---- arch/v850/kernel/memcons.c | 2 +- arch/v850/kernel/simcons.c | 2 +- arch/xtensa/platform-iss/console.c | 2 +- drivers/char/amiserial.c | 2 +- drivers/char/cyclades.c | 2 +- drivers/char/epca.c | 2 +- drivers/char/esp.c | 2 +- drivers/char/hvc_console.c | 2 +- drivers/char/hvcs.c | 2 +- drivers/char/hvsi.c | 2 +- drivers/char/ip2/ip2main.c | 2 +- drivers/char/isicom.c | 2 +- drivers/char/istallion.c | 2 +- drivers/char/moxa.c | 2 +- drivers/char/mxser.c | 2 +- drivers/char/pcmcia/synclink_cs.c | 2 +- drivers/char/pty.c | 2 +- drivers/char/rio/rio_linux.c | 2 +- drivers/char/riscom8.c | 2 +- drivers/char/rocket.c | 2 +- drivers/char/ser_a2232.c | 2 +- drivers/char/serial167.c | 2 +- drivers/char/specialix.c | 2 +- drivers/char/stallion.c | 2 +- drivers/char/sx.c | 2 +- drivers/char/synclink.c | 2 +- drivers/char/synclink_gt.c | 2 +- drivers/char/synclinkmp.c | 2 +- drivers/char/tty_io.c | 3 ++- drivers/char/viocons.c | 2 +- drivers/char/vme_scc.c | 2 +- drivers/char/vt.c | 2 +- drivers/isdn/capi/capi.c | 2 +- drivers/isdn/gigaset/interface.c | 2 +- drivers/isdn/i4l/isdn_tty.c | 2 +- drivers/s390/char/con3215.c | 2 +- drivers/s390/char/sclp_tty.c | 2 +- drivers/s390/char/sclp_vt220.c | 2 +- drivers/s390/char/tty3270.c | 2 +- drivers/sbus/char/aurora.c | 2 +- drivers/serial/68328serial.c | 2 +- drivers/serial/68360serial.c | 2 +- drivers/serial/crisv10.c | 2 +- drivers/serial/mcfserial.c | 2 +- drivers/serial/serial_core.c | 2 +- drivers/tc/zs.c | 2 +- drivers/usb/class/cdc-acm.c | 2 +- drivers/usb/gadget/serial.c | 2 +- drivers/usb/serial/usb-serial.c | 2 +- include/linux/tty_driver.h | 3 ++- net/bluetooth/rfcomm/tty.c | 2 +- net/irda/ircomm/ircomm_tty.c | 2 +- 57 files changed, 63 insertions(+), 62 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index 9d7dff27f815..756923203860 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -229,7 +229,7 @@ srmcons_close(struct tty_struct *tty, struct file *filp) static struct tty_driver *srmcons_driver; -static struct tty_operations srmcons_ops = { +static const struct tty_operations srmcons_ops = { .open = srmcons_open, .close = srmcons_close, .write = srmcons_write, diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 0daacc20ed36..246eb3d3757a 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -940,7 +940,7 @@ static inline void show_serial_version(void) printk(KERN_INFO " no serial options enabled\n"); } -static struct tty_operations hp_ops = { +static const struct tty_operations hp_ops = { .open = rs_open, .close = rs_close, .write = rs_write, diff --git a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c index b81a367dc278..87fe9a89dba7 100644 --- a/arch/ppc/4xx_io/serial_sicc.c +++ b/arch/ppc/4xx_io/serial_sicc.c @@ -1720,7 +1720,7 @@ static int siccuart_open(struct tty_struct *tty, struct file *filp) return 0; } -static struct tty_operations sicc_ops = { +static const struct tty_operations sicc_ops = { .open = siccuart_open, .close = siccuart_close, .write = siccuart_write, diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 563ce7690a1e..24747a413785 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -642,9 +642,9 @@ int line_remove(struct line *lines, unsigned int num, int n) } struct tty_driver *line_register_devfs(struct lines *set, - struct line_driver *line_driver, - struct tty_operations *ops, struct line *lines, - int nlines) + struct line_driver *line_driver, + const struct tty_operations *ops, + struct line *lines, int nlines) { int i; struct tty_driver *driver = alloc_tty_driver(nlines); diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 642c9a0320f9..7be24811bb30 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -91,10 +91,9 @@ extern int line_setup_irq(int fd, int input, int output, struct line *line, void *data); extern void line_close_chan(struct line *line); extern struct tty_driver * line_register_devfs(struct lines *set, - struct line_driver *line_driver, - struct tty_operations *driver, - struct line *lines, - int nlines); + struct line_driver *line_driver, + const struct tty_operations *driver, + struct line *lines, int nlines); extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts); extern void close_lines(struct line *lines, int nlines); diff --git a/arch/v850/kernel/memcons.c b/arch/v850/kernel/memcons.c index 815f8a43926f..92f514fdcc79 100644 --- a/arch/v850/kernel/memcons.c +++ b/arch/v850/kernel/memcons.c @@ -104,7 +104,7 @@ int memcons_tty_chars_in_buffer (struct tty_struct *tty) return 0; } -static struct tty_operations ops = { +static const struct tty_operations ops = { .open = memcons_tty_open, .write = memcons_tty_write, .write_room = memcons_tty_write_room, diff --git a/arch/v850/kernel/simcons.c b/arch/v850/kernel/simcons.c index 3975aa02cef8..9973596ae304 100644 --- a/arch/v850/kernel/simcons.c +++ b/arch/v850/kernel/simcons.c @@ -77,7 +77,7 @@ int simcons_tty_chars_in_buffer (struct tty_struct *tty) return 0; } -static struct tty_operations ops = { +static const struct tty_operations ops = { .open = simcons_tty_open, .write = simcons_tty_write, .write_room = simcons_tty_write_room, diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c index 22d3c571a7bc..5c947cae7520 100644 --- a/arch/xtensa/platform-iss/console.c +++ b/arch/xtensa/platform-iss/console.c @@ -191,7 +191,7 @@ static int rs_read_proc(char *page, char **start, off_t off, int count, } -static struct tty_operations serial_ops = { +static const struct tty_operations serial_ops = { .open = rs_open, .close = rs_close, .write = rs_write, diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 9d6713a93ed7..d0e92ed0a367 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -1958,7 +1958,7 @@ static void show_serial_version(void) } -static struct tty_operations serial_ops = { +static const struct tty_operations serial_ops = { .open = rs_open, .close = rs_close, .write = rs_write, diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index c1c67281750d..f85b4eb16618 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -5205,7 +5205,7 @@ done: extra ports are ignored. */ -static struct tty_operations cy_ops = { +static const struct tty_operations cy_ops = { .open = cy_open, .close = cy_close, .write = cy_write, diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 86d290e9f307..3baa2ab8cbd4 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1125,7 +1125,7 @@ static void __exit epca_module_exit(void) module_exit(epca_module_exit); -static struct tty_operations pc_ops = { +static const struct tty_operations pc_ops = { .open = pc_open, .close = pc_close, .write = pc_write, diff --git a/drivers/char/esp.c b/drivers/char/esp.c index afcd83d9984b..05788c75d7fc 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -2376,7 +2376,7 @@ static inline int autoconfig(struct esp_struct * info) return (port_detected); } -static struct tty_operations esp_ops = { +static const struct tty_operations esp_ops = { .open = esp_open, .close = rs_close, .write = rs_write, diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index a76d2c40dd5e..4053d1cd393f 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -696,7 +696,7 @@ int khvcd(void *unused) return 0; } -static struct tty_operations hvc_ops = { +static const struct tty_operations hvc_ops = { .open = hvc_open, .close = hvc_close, .write = hvc_write, diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 4589ff302b07..0b89bcde8c52 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -1306,7 +1306,7 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty) return hvcsd->chars_in_buffer; } -static struct tty_operations hvcs_ops = { +static const struct tty_operations hvcs_ops = { .open = hvcs_open, .close = hvcs_close, .hangup = hvcs_hangup, diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index a89a95fb5e40..c07dc58d5c1d 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -1130,7 +1130,7 @@ static int hvsi_tiocmset(struct tty_struct *tty, struct file *file, } -static struct tty_operations hvsi_ops = { +static const struct tty_operations hvsi_ops = { .open = hvsi_open, .close = hvsi_close, .write = hvsi_write, diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 331f447e6228..4828bc914ce3 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -458,7 +458,7 @@ cleanup_module(void) } #endif /* MODULE */ -static struct tty_operations ip2_ops = { +static const struct tty_operations ip2_ops = { .open = ip2_open, .close = ip2_close, .write = ip2_write, diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 2e1da632aee1..ea2bbf80ad33 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -1550,7 +1550,7 @@ static void isicom_unregister_ioregion(struct pci_dev *pdev) board->base = 0; } -static struct tty_operations isicom_ops = { +static const struct tty_operations isicom_ops = { .open = isicom_open, .close = isicom_close, .write = isicom_write, diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 6b4d82a4565f..d6e031542c6b 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -4636,7 +4636,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un return rc; } -static struct tty_operations stli_ops = { +static const struct tty_operations stli_ops = { .open = stli_open, .close = stli_close, .write = stli_write, diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index c1a6d3c48da1..b401383808c2 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -281,7 +281,7 @@ static int moxa_get_serial_info(struct moxa_str *, struct serial_struct __user * static int moxa_set_serial_info(struct moxa_str *, struct serial_struct __user *); static void MoxaSetFifo(int port, int enable); -static struct tty_operations moxa_ops = { +static const struct tty_operations moxa_ops = { .open = moxa_open, .close = moxa_close, .write = moxa_write, diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 27a653772049..8253fca8efd5 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -453,7 +453,7 @@ static int CheckIsMoxaMust(int io) /* above is modified by Victor Yu. 08-15-2002 */ -static struct tty_operations mxser_ops = { +static const struct tty_operations mxser_ops = { .open = mxser_open, .close = mxser_close, .write = mxser_write, diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 00f574cbb0d4..dd845cbefe94 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -3010,7 +3010,7 @@ static struct pcmcia_driver mgslpc_driver = { .resume = mgslpc_resume, }; -static struct tty_operations mgslpc_ops = { +static const struct tty_operations mgslpc_ops = { .open = mgslpc_open, .close = mgslpc_close, .write = mgslpc_write, diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 34dd4c38110e..80d3eedd7f96 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -224,7 +224,7 @@ static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios) tty->termios->c_cflag |= (CS8 | CREAD); } -static struct tty_operations pty_ops = { +static const struct tty_operations pty_ops = { .open = pty_open, .close = pty_close, .write = pty_write, diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 3fa80aaf4527..202a3b0945b7 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -727,7 +727,7 @@ static struct vpd_prom *get_VPD_PROM(struct Host *hp) return &vpdp; } -static struct tty_operations rio_ops = { +static const struct tty_operations rio_ops = { .open = riotopen, .close = gs_close, .write = gs_write, diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 06b9f78a95d9..214d850112fd 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -1583,7 +1583,7 @@ static void do_softint(void *private_) } } -static struct tty_operations riscom_ops = { +static const struct tty_operations riscom_ops = { .open = rc_open, .close = rc_close, .write = rc_write, diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 0ac131881322..bac80056f7e0 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -2334,7 +2334,7 @@ static int __init init_ISA(int i) return (1); } -static struct tty_operations rocket_ops = { +static const struct tty_operations rocket_ops = { .open = rp_open, .close = rp_close, .write = rp_write, diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 510bd3e0e88b..65c751d0d643 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -661,7 +661,7 @@ static void a2232_init_portstructs(void) } } -static struct tty_operations a2232_ops = { +static const struct tty_operations a2232_ops = { .open = a2232_open, .close = gs_close, .write = gs_write, diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 21a710cb4bba..b4ea1266b663 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -2158,7 +2158,7 @@ mvme167_serial_console_setup(int cflag) rcor >> 5, rbpr); } /* serial_console_init */ -static struct tty_operations cy_ops = { +static const struct tty_operations cy_ops = { .open = cy_open, .close = cy_close, .write = cy_write, diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index f52c7c31badf..902c48dca3bc 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -2363,7 +2363,7 @@ static void do_softint(void *private_) func_exit(); } -static struct tty_operations sx_ops = { +static const struct tty_operations sx_ops = { .open = sx_open, .close = sx_close, .write = sx_write, diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 3beb2203d24b..bd711537ec4e 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -2993,7 +2993,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns return(rc); } -static struct tty_operations stl_ops = { +static const struct tty_operations stl_ops = { .open = stl_open, .close = stl_close, .write = stl_write, diff --git a/drivers/char/sx.c b/drivers/char/sx.c index e1cd2bc4b1e4..57e31e5eaedb 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -2226,7 +2226,7 @@ static int probe_si (struct sx_board *board) return 1; } -static struct tty_operations sx_ops = { +static const struct tty_operations sx_ops = { .break_ctl = sx_break, .open = sx_open, .close = gs_close, diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 78b1b1a2732b..244dc308c770 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -4360,7 +4360,7 @@ static struct mgsl_struct* mgsl_allocate_device(void) } /* end of mgsl_allocate_device()*/ -static struct tty_operations mgsl_ops = { +static const struct tty_operations mgsl_ops = { .open = mgsl_open, .close = mgsl_close, .write = mgsl_write, diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 78bc85180c82..bdc7cb248b8f 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -3441,7 +3441,7 @@ static void __devexit remove_one(struct pci_dev *dev) { } -static struct tty_operations ops = { +static const struct tty_operations ops = { .open = open, .close = close, .write = write, diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 66f3754fbbdf..6eb75dcd7961 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -3929,7 +3929,7 @@ void device_init(int adapter_num, struct pci_dev *pdev) } } -static struct tty_operations ops = { +static const struct tty_operations ops = { .open = open, .close = close, .write = write, diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 333741770f1e..e90ea39c7c4b 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -3680,7 +3680,8 @@ void put_tty_driver(struct tty_driver *driver) kfree(driver); } -void tty_set_operations(struct tty_driver *driver, struct tty_operations *op) +void tty_set_operations(struct tty_driver *driver, + const struct tty_operations *op) { driver->open = op->open; driver->close = op->close; diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index f3efeaf2826e..a362ee9c92dd 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c @@ -1047,7 +1047,7 @@ static int send_open(HvLpIndex remoteLp, void *sem) 0, 0, 0, 0); } -static struct tty_operations serial_ops = { +static const struct tty_operations serial_ops = { .open = viotty_open, .close = viotty_close, .write = viotty_write, diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index bfe5ea948f6a..c2ca31eb850b 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -113,7 +113,7 @@ static struct real_driver scc_real_driver = { }; -static struct tty_operations scc_ops = { +static const struct tty_operations scc_ops = { .open = scc_open, .close = gs_close, .write = gs_write, diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 303956d34569..ec0c070bf15f 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -2675,7 +2675,7 @@ static int __init con_init(void) } console_initcall(con_init); -static struct tty_operations con_ops = { +static const struct tty_operations con_ops = { .open = con_open, .close = con_close, .write = con_write, diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 669f76393b5a..11844bbfe933 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1298,7 +1298,7 @@ static int capinc_tty_read_proc(char *page, char **start, off_t off, static struct tty_driver *capinc_tty_driver; -static struct tty_operations capinc_ops = { +static const struct tty_operations capinc_ops = { .open = capinc_tty_open, .close = capinc_tty_close, .write = capinc_tty_write, diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index bd2e4267528e..596f3aebe2f7 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -134,7 +134,7 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file, static int if_write(struct tty_struct *tty, const unsigned char *buf, int count); -static struct tty_operations if_ops = { +static const struct tty_operations if_ops = { .open = if_open, .close = if_close, .ioctl = if_ioctl, diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 9ab66e8960d5..2b91bb07fc7f 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1860,7 +1860,7 @@ modem_write_profile(atemu * m) send_sig(SIGIO, dev->profd, 1); } -static struct tty_operations modem_ops = { +static const struct tty_operations modem_ops = { .open = isdn_tty_open, .close = isdn_tty_close, .write = isdn_tty_write, diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 2fa566fa6da4..d7de175d53f0 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -1103,7 +1103,7 @@ tty3215_start(struct tty_struct *tty) } } -static struct tty_operations tty3215_ops = { +static const struct tty_operations tty3215_ops = { .open = tty3215_open, .close = tty3215_close, .write = tty3215_write, diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index f6cf9023039e..6f43e04dbefd 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -711,7 +711,7 @@ static struct sclp_register sclp_input_event = .receiver_fn = sclp_tty_receiver }; -static struct tty_operations sclp_ops = { +static const struct tty_operations sclp_ops = { .open = sclp_tty_open, .close = sclp_tty_close, .write = sclp_tty_write, diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 54fba6f17188..723bf4191bfe 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -655,7 +655,7 @@ __sclp_vt220_init(int early) return 0; } -static struct tty_operations sclp_vt220_ops = { +static const struct tty_operations sclp_vt220_ops = { .open = sclp_vt220_open, .close = sclp_vt220_close, .write = sclp_vt220_write, diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 06e2eeec8473..4717c3611601 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -1737,7 +1737,7 @@ tty3270_ioctl(struct tty_struct *tty, struct file *file, return kbd_ioctl(tp->kbd, file, cmd, arg); } -static struct tty_operations tty3270_ops = { +static const struct tty_operations tty3270_ops = { .open = tty3270_open, .close = tty3270_close, .write = tty3270_write, diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c index 4fdb2c932210..a305d4091547 100644 --- a/drivers/sbus/char/aurora.c +++ b/drivers/sbus/char/aurora.c @@ -2187,7 +2187,7 @@ static void do_softint(void *private_) #endif } -static struct tty_operations aurora_ops = { +static const struct tty_operations aurora_ops = { .open = aurora_open, .close = aurora_close, .write = aurora_write, diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index 993a702422ec..bac853c5abb5 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -1378,7 +1378,7 @@ void startup_console(void) #endif /* CONFIG_PM_LEGACY */ -static struct tty_operations rs_ops = { +static const struct tty_operations rs_ops = { .open = rs_open, .close = rs_close, .write = rs_write, diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index e80e70e9b126..1b299e8c57cd 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -2424,7 +2424,7 @@ long console_360_init(long kmem_start, long kmem_end) */ static int baud_idx; -static struct tty_operations rs_360_ops = { +static const struct tty_operations rs_360_ops = { .owner = THIS_MODULE, .open = rs_360_open, .close = rs_360_close, diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index cabd048c8636..9851d9eff022 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -4825,7 +4825,7 @@ show_serial_version(void) /* rs_init inits the driver at boot (using the module_init chain) */ -static struct tty_operations rs_ops = { +static const struct tty_operations rs_ops = { .open = rs_open, .close = rs_close, .write = rs_write, diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 832abd3c4706..00d7859c167e 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -1666,7 +1666,7 @@ static void show_serial_version(void) printk(mcfrs_drivername); } -static struct tty_operations mcfrs_ops = { +static const struct tty_operations mcfrs_ops = { .open = mcfrs_open, .close = mcfrs_close, .write = mcfrs_write, diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 5f7ba1adb309..de5e8930a6fd 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -2111,7 +2111,7 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, } } -static struct tty_operations uart_ops = { +static const struct tty_operations uart_ops = { .open = uart_open, .close = uart_close, .write = uart_write, diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 5e8a27620f6f..622881f26761 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -1701,7 +1701,7 @@ static void __init probe_sccs(void) spin_unlock_irqrestore(&zs_lock, flags); } -static struct tty_operations serial_ops = { +static const struct tty_operations serial_ops = { .open = rs_open, .close = rs_close, .write = rs_write, diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ca90326f2f5c..71288295df2f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1120,7 +1120,7 @@ static struct usb_driver acm_driver = { * TTY driver structures. */ -static struct tty_operations acm_ops = { +static const struct tty_operations acm_ops = { .open = acm_tty_open, .close = acm_tty_close, .write = acm_tty_write, diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index b893e3118e1b..489a85e58bca 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -271,7 +271,7 @@ static unsigned int use_acm = GS_DEFAULT_USE_ACM; /* tty driver struct */ -static struct tty_operations gs_tty_ops = { +static const struct tty_operations gs_tty_ops = { .open = gs_open, .close = gs_close, .write = gs_write, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 0222d92842b8..8006e51c34bb 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1015,7 +1015,7 @@ void usb_serial_disconnect(struct usb_interface *interface) dev_info(dev, "device disconnected\n"); } -static struct tty_operations serial_ops = { +static const struct tty_operations serial_ops = { .open = serial_open, .close = serial_close, .write = serial_write, diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 58c961c9e170..5c8473bb6882 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -219,7 +219,8 @@ extern struct list_head tty_drivers; struct tty_driver *alloc_tty_driver(int lines); void put_tty_driver(struct tty_driver *driver); -void tty_set_operations(struct tty_driver *driver, struct tty_operations *op); +void tty_set_operations(struct tty_driver *driver, + const struct tty_operations *op); /* tty driver magic number */ #define TTY_DRIVER_MAGIC 0x5402 diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 26f322737db0..1958ad1b8541 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -1011,7 +1011,7 @@ static int rfcomm_tty_tiocmset(struct tty_struct *tty, struct file *filp, unsign /* ---- TTY structure ---- */ -static struct tty_operations rfcomm_ops = { +static const struct tty_operations rfcomm_ops = { .open = rfcomm_tty_open, .close = rfcomm_tty_close, .write = rfcomm_tty_write, diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 3bcdb467efc5..d50a02030ad7 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -79,7 +79,7 @@ static struct tty_driver *driver; hashbin_t *ircomm_tty = NULL; -static struct tty_operations ops = { +static const struct tty_operations ops = { .open = ircomm_tty_open, .close = ircomm_tty_close, .write = ircomm_tty_write, -- cgit v1.2.3 From d387cae075b0aec479adbdfb71df39f7de8e9adb Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 2 Oct 2006 02:17:22 -0700 Subject: [PATCH] pid: simplify pid iterators I think it is hardly possible to read the current do_each_task_pid(). The new version is much simpler and makes the code smaller. Only the do_each_task_pid change is tested, the do_each_pid_task isn't. Signed-off-by: Oleg Nesterov Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pid.h | 59 +++++++++++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pid.h b/include/linux/pid.h index dba1b2d677a3..7e39767b4c60 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -102,42 +102,29 @@ static inline pid_t pid_nr(struct pid *pid) return nr; } -#define pid_next(task, type) \ - ((task)->pids[(type)].node.next) -#define pid_next_task(task, type) \ - hlist_entry(pid_next(task, type), struct task_struct, \ - pids[(type)].node) - - -/* We could use hlist_for_each_entry_rcu here but it takes more arguments - * than the do_each_task_pid/while_each_task_pid. So we roll our own - * to preserve the existing interface. - */ -#define do_each_task_pid(who, type, task) \ - if ((task = find_task_by_pid_type(type, who))) { \ - prefetch(pid_next(task, type)); \ - do { - -#define while_each_task_pid(who, type, task) \ - } while (pid_next(task, type) && ({ \ - task = pid_next_task(task, type); \ - rcu_dereference(task); \ - prefetch(pid_next(task, type)); \ - 1; }) ); \ - } - -#define do_each_pid_task(pid, type, task) \ - if ((task = pid_task(pid, type))) { \ - prefetch(pid_next(task, type)); \ - do { - -#define while_each_pid_task(pid, type, task) \ - } while (pid_next(task, type) && ({ \ - task = pid_next_task(task, type); \ - rcu_dereference(task); \ - prefetch(pid_next(task, type)); \ - 1; }) ); \ - } +#define do_each_task_pid(who, type, task) \ + do { \ + struct hlist_node *pos___; \ + struct pid *pid___ = find_pid(who); \ + if (pid___ != NULL) \ + hlist_for_each_entry_rcu((task), pos___, \ + &pid___->tasks[type], pids[type].node) { + +#define while_each_task_pid(who, type, task) \ + } \ + } while (0) + + +#define do_each_pid_task(pid, type, task) \ + do { \ + struct hlist_node *pos___; \ + if (pid != NULL) \ + hlist_for_each_entry_rcu((task), pos___, \ + &pid->tasks[type], pids[type].node) { + +#define while_each_pid_task(pid, type, task) \ + } \ + } while (0) #endif /* _LINUX_PID_H */ -- cgit v1.2.3 From aa5a6662f93f52605b6c447ba6f7291e92f515c5 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Mon, 2 Oct 2006 02:17:23 -0700 Subject: [PATCH] Move pidmap to pspace.h Move struct pidmap and PIDMAP_ENTRIES to a new file, include/linux/pspace.h where it will be used in subsequent patches to define pid spaces. Its a subset of Eric Biederman's patch http://lkml.org/lkml/2006/2/6/285 [akpm@osdl.org: cleanups] Signed-off-by: Eric W. Biederman Signed-off-by: Sukadev Bhattiprolu Cc: Dave Hansen Cc: Serge Hallyn Cc: Cedric Le Goater Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pspace.h | 16 ++++++++++++++++ kernel/pid.c | 7 +------ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 include/linux/pspace.h (limited to 'include/linux') diff --git a/include/linux/pspace.h b/include/linux/pspace.h new file mode 100644 index 000000000000..a8a064b0ad18 --- /dev/null +++ b/include/linux/pspace.h @@ -0,0 +1,16 @@ +#ifndef _LINUX_PSPACE_H +#define _LINUX_PSPACE_H + +#include +#include +#include +#include + +struct pidmap { + atomic_t nr_free; + void *page; +}; + +#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8) + +#endif /* _LINUX_PSPACE_H */ diff --git a/kernel/pid.c b/kernel/pid.c index 373639a10d84..8234bd08a3cb 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -26,6 +26,7 @@ #include #include #include +#include #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) static struct hlist_head *pid_hash; @@ -40,7 +41,6 @@ int last_pid; int pid_max_min = RESERVED_PIDS + 1; int pid_max_max = PID_MAX_LIMIT; -#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8) #define BITS_PER_PAGE (PAGE_SIZE*8) #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) #define mk_pid(map, off) (((map) - pidmap_array)*BITS_PER_PAGE + (off)) @@ -53,11 +53,6 @@ int pid_max_max = PID_MAX_LIMIT; * value does not cause lots of bitmaps to be allocated, but * the scheme scales to up to 4 million PIDs, runtime. */ -struct pidmap { - atomic_t nr_free; - void *page; -}; - static struct pidmap pidmap_array[PIDMAP_ENTRIES] = { [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } }; -- cgit v1.2.3 From 3fbc96486459324e182717b03c50c90c880be6ec Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Mon, 2 Oct 2006 02:17:24 -0700 Subject: [PATCH] Define struct pspace Define a per-container pid space object. And create one instance of this object, init_pspace, to define the entire pid space. Subsequent patches will provide/use interfaces to create/destroy pid spaces. Its a subset/rework of Eric Biederman's patch http://lkml.org/lkml/2006/2/6/285 . Signed-off-by: Eric Biederman Signed-off-by: Sukadev Bhattiprolu Cc: Dave Hansen Cc: Serge Hallyn Cc: Cedric Le Goater Cc: Kirill Korotaev Cc: Andrey Savochkin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/proc_misc.c | 3 ++- include/linux/pspace.h | 7 +++++++ include/linux/sched.h | 1 - kernel/pid.c | 53 +++++++++++++++++++++++++++++--------------------- 4 files changed, 40 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 66bc425f2f3d..8d88e58ed5cc 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -91,7 +92,7 @@ static int loadavg_read_proc(char *page, char **start, off_t off, LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), - nr_running(), nr_threads, last_pid); + nr_running(), nr_threads, init_pspace.last_pid); return proc_calc_metrics(page, start, off, count, eof, len); } diff --git a/include/linux/pspace.h b/include/linux/pspace.h index a8a064b0ad18..91d48b8b2d99 100644 --- a/include/linux/pspace.h +++ b/include/linux/pspace.h @@ -13,4 +13,11 @@ struct pidmap { #define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8) +struct pspace { + struct pidmap pidmap[PIDMAP_ENTRIES]; + int last_pid; +}; + +extern struct pspace init_pspace; + #endif /* _LINUX_PSPACE_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index dd6c2164e4a4..3b7c99265ace 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -118,7 +118,6 @@ extern unsigned long avenrun[]; /* Load averages */ extern unsigned long total_forks; extern int nr_threads; -extern int last_pid; DECLARE_PER_CPU(unsigned long, process_counts); extern int nr_processes(void); extern unsigned long nr_running(void); diff --git a/kernel/pid.c b/kernel/pid.c index 8234bd08a3cb..89107b7481af 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -34,7 +34,6 @@ static int pidhash_shift; static kmem_cache_t *pid_cachep; int pid_max = PID_MAX_DEFAULT; -int last_pid; #define RESERVED_PIDS 300 @@ -43,7 +42,12 @@ int pid_max_max = PID_MAX_LIMIT; #define BITS_PER_PAGE (PAGE_SIZE*8) #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) -#define mk_pid(map, off) (((map) - pidmap_array)*BITS_PER_PAGE + (off)) + +static inline int mk_pid(struct pspace *pspace, struct pidmap *map, int off) +{ + return (map - pspace->pidmap)*BITS_PER_PAGE + off; +} + #define find_next_offset(map, off) \ find_next_zero_bit((map)->page, BITS_PER_PAGE, off) @@ -53,8 +57,12 @@ int pid_max_max = PID_MAX_LIMIT; * value does not cause lots of bitmaps to be allocated, but * the scheme scales to up to 4 million PIDs, runtime. */ -static struct pidmap pidmap_array[PIDMAP_ENTRIES] = - { [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } }; +struct pspace init_pspace = { + .pidmap = { + [ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } + }, + .last_pid = 0 +}; /* * Note: disable interrupts while the pidmap_lock is held as an @@ -69,40 +77,41 @@ static struct pidmap pidmap_array[PIDMAP_ENTRIES] = * irq handlers that take it we can leave the interrupts enabled. * For now it is easier to be safe than to prove it can't happen. */ + static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock); -static fastcall void free_pidmap(int pid) +static fastcall void free_pidmap(struct pspace *pspace, int pid) { - struct pidmap *map = pidmap_array + pid / BITS_PER_PAGE; + struct pidmap *map = pspace->pidmap + pid / BITS_PER_PAGE; int offset = pid & BITS_PER_PAGE_MASK; clear_bit(offset, map->page); atomic_inc(&map->nr_free); } -static int alloc_pidmap(void) +static int alloc_pidmap(struct pspace *pspace) { - int i, offset, max_scan, pid, last = last_pid; + int i, offset, max_scan, pid, last = pspace->last_pid; struct pidmap *map; pid = last + 1; if (pid >= pid_max) pid = RESERVED_PIDS; offset = pid & BITS_PER_PAGE_MASK; - map = &pidmap_array[pid/BITS_PER_PAGE]; + map = &pspace->pidmap[pid/BITS_PER_PAGE]; max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset; for (i = 0; i <= max_scan; ++i) { if (unlikely(!map->page)) { - unsigned long page = get_zeroed_page(GFP_KERNEL); + void *page = kzalloc(PAGE_SIZE, GFP_KERNEL); /* * Free the page if someone raced with us * installing it: */ spin_lock_irq(&pidmap_lock); if (map->page) - free_page(page); + kfree(page); else - map->page = (void *)page; + map->page = page; spin_unlock_irq(&pidmap_lock); if (unlikely(!map->page)) break; @@ -111,11 +120,11 @@ static int alloc_pidmap(void) do { if (!test_and_set_bit(offset, map->page)) { atomic_dec(&map->nr_free); - last_pid = pid; + pspace->last_pid = pid; return pid; } offset = find_next_offset(map, offset); - pid = mk_pid(map, offset); + pid = mk_pid(pspace, map, offset); /* * find_next_offset() found a bit, the pid from it * is in-bounds, and if we fell back to the last @@ -126,16 +135,16 @@ static int alloc_pidmap(void) (i != max_scan || pid < last || !((last+1) & BITS_PER_PAGE_MASK))); } - if (map < &pidmap_array[(pid_max-1)/BITS_PER_PAGE]) { + if (map < &pspace->pidmap[(pid_max-1)/BITS_PER_PAGE]) { ++map; offset = 0; } else { - map = &pidmap_array[0]; + map = &pspace->pidmap[0]; offset = RESERVED_PIDS; if (unlikely(last == offset)) break; } - pid = mk_pid(map, offset); + pid = mk_pid(pspace, map, offset); } return -1; } @@ -182,7 +191,7 @@ fastcall void free_pid(struct pid *pid) hlist_del_rcu(&pid->pid_chain); spin_unlock_irqrestore(&pidmap_lock, flags); - free_pidmap(pid->nr); + free_pidmap(&init_pspace, pid->nr); call_rcu(&pid->rcu, delayed_put_pid); } @@ -196,7 +205,7 @@ struct pid *alloc_pid(void) if (!pid) goto out; - nr = alloc_pidmap(); + nr = alloc_pidmap(&init_pspace); if (nr < 0) goto out_free; @@ -363,10 +372,10 @@ void __init pidhash_init(void) void __init pidmap_init(void) { - pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL); + init_pspace.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); /* Reserve PID 0. We never call free_pidmap(0) */ - set_bit(0, pidmap_array->page); - atomic_dec(&pidmap_array->nr_free); + set_bit(0, init_pspace.pidmap[0].page); + atomic_dec(&init_pspace.pidmap[0].nr_free); pid_cachep = kmem_cache_create("pid", sizeof(struct pid), __alignof__(struct pid), -- cgit v1.2.3 From 2425c08b37244005ff221efe4957d8aaff18609c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 2 Oct 2006 02:17:28 -0700 Subject: [PATCH] usb: fixup usb so it uses struct pid The problem with remembering a user space process by its pid is that it is possible that the process will exit, pid wrap around will occur. Converting to a struct pid avoid that problem, and paves the way for implementing a pid namespace. Also since usb is the only user of kill_proc_info_as_uid rename kill_proc_info_as_uid to kill_pid_info_as_uid and have the new version take a struct pid. Signed-off-by: Eric W. Biederman Acked-by: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/core/devio.c | 10 ++++++---- drivers/usb/core/inode.c | 2 +- drivers/usb/core/usb.h | 2 +- include/linux/sched.h | 2 +- kernel/signal.c | 8 ++++---- 5 files changed, 13 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index a94c63bef632..3f509beb88e4 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -65,7 +65,7 @@ DEFINE_MUTEX(usbfs_mutex); struct async { struct list_head asynclist; struct dev_state *ps; - pid_t pid; + struct pid *pid; uid_t uid, euid; unsigned int signr; unsigned int ifnum; @@ -225,6 +225,7 @@ static struct async *alloc_async(unsigned int numisoframes) static void free_async(struct async *as) { + put_pid(as->pid); kfree(as->urb->transfer_buffer); kfree(as->urb->setup_packet); usb_free_urb(as->urb); @@ -317,7 +318,7 @@ static void async_completed(struct urb *urb, struct pt_regs *regs) sinfo.si_errno = as->urb->status; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = as->userurb; - kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid, + kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, as->euid, as->secid); } snoop(&urb->dev->dev, "urb complete\n"); @@ -573,7 +574,7 @@ static int usbdev_open(struct inode *inode, struct file *file) INIT_LIST_HEAD(&ps->async_completed); init_waitqueue_head(&ps->wait); ps->discsignr = 0; - ps->disc_pid = current->pid; + ps->disc_pid = get_pid(task_pid(current)); ps->disc_uid = current->uid; ps->disc_euid = current->euid; ps->disccontext = NULL; @@ -611,6 +612,7 @@ static int usbdev_release(struct inode *inode, struct file *file) usb_autosuspend_device(dev, 1); usb_unlock_device(dev); usb_put_dev(dev); + put_pid(ps->disc_pid); kfree(ps); return 0; } @@ -1063,7 +1065,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->userbuffer = NULL; as->signr = uurb->signr; as->ifnum = ifnum; - as->pid = current->pid; + as->pid = get_pid(task_pid(current)); as->uid = current->uid; as->euid = current->euid; security_task_getsecid(current, &as->secid); diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 7c77c2d8d300..b5d6a79af0be 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -699,7 +699,7 @@ static void usbfs_remove_device(struct usb_device *dev) sinfo.si_errno = EPIPE; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = ds->disccontext; - kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid); + kill_pid_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid); } } } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index f69df137ec0e..13322e33f912 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -139,7 +139,7 @@ struct dev_state { struct list_head async_completed; wait_queue_head_t wait; /* wake up if a request completed */ unsigned int discsignr; - pid_t disc_pid; + struct pid *disc_pid; uid_t disc_uid, disc_euid; void __user *disccontext; unsigned long ifclaimed; diff --git a/include/linux/sched.h b/include/linux/sched.h index 3b7c99265ace..a7fff3304bd6 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1269,12 +1269,12 @@ extern int force_sig_info(int, struct siginfo *, struct task_struct *); extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp); extern int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp); extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid); +extern int kill_pid_info_as_uid(int, struct siginfo *, struct pid *, uid_t, uid_t, u32); extern int kill_pgrp(struct pid *pid, int sig, int priv); extern int kill_pid(struct pid *pid, int sig, int priv); extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); extern int kill_pg_info(int, struct siginfo *, pid_t); extern int kill_proc_info(int, struct siginfo *, pid_t); -extern int kill_proc_info_as_uid(int, struct siginfo *, pid_t, uid_t, uid_t, u32); extern void do_notify_parent(struct task_struct *, int); extern void force_sig(int, struct task_struct *); extern void force_sig_specific(int, struct task_struct *); diff --git a/kernel/signal.c b/kernel/signal.c index 5230ddcb1757..7ed8d5304bec 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1136,8 +1136,8 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid) return error; } -/* like kill_proc_info(), but doesn't use uid/euid of "current" */ -int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, +/* like kill_pid_info(), but doesn't use uid/euid of "current" */ +int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, uid_t uid, uid_t euid, u32 secid) { int ret = -EINVAL; @@ -1147,7 +1147,7 @@ int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, return ret; read_lock(&tasklist_lock); - p = find_task_by_pid(pid); + p = pid_task(pid, PIDTYPE_PID); if (!p) { ret = -ESRCH; goto out_unlock; @@ -1171,7 +1171,7 @@ out_unlock: read_unlock(&tasklist_lock); return ret; } -EXPORT_SYMBOL_GPL(kill_proc_info_as_uid); +EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); /* * kill_something_info() interprets pid in interesting ways just like kill(2). -- cgit v1.2.3 From 3a872d89baae821a0f6e2c1055d4b47650661137 Mon Sep 17 00:00:00 2001 From: Ananth N Mavinakayanahalli Date: Mon, 2 Oct 2006 02:17:30 -0700 Subject: [PATCH] Kprobes: Make kprobe modules more portable In an effort to make kprobe modules more portable, here is a patch that: o Introduces the "symbol_name" field to struct kprobe. The symbol->address resolution now happens in the kernel in an architecture agnostic manner. 64-bit powerpc users no longer have to specify the ".symbols" o Introduces the "offset" field to struct kprobe to allow a user to specify an offset into a symbol. o The legacy mechanism of specifying the kprobe.addr is still supported. However, if both the kprobe.addr and kprobe.symbol_name are specified, probe registration fails with an -EINVAL. o The symbol resolution code uses kallsyms_lookup_name(). So CONFIG_KPROBES now depends on CONFIG_KALLSYMS o Apparantly kprobe modules were the only legitimate out-of-tree user of the kallsyms_lookup_name() EXPORT. Now that the symbol resolution happens in-kernel, remove the EXPORT as suggested by Christoph Hellwig o Modify tcp_probe.c that uses the kprobe interface so as to make it work on multiple platforms (in its earlier form, the code wouldn't work, say, on powerpc) Signed-off-by: Ananth N Mavinakayanahalli Signed-off-by: Prasanna S Panchamukhi Signed-off-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/Kconfig | 2 +- arch/ia64/Kconfig | 2 +- arch/powerpc/Kconfig | 2 +- arch/sparc64/Kconfig | 2 +- arch/x86_64/Kconfig | 2 +- include/asm-powerpc/kprobes.h | 15 +++++++++++++++ include/linux/kprobes.h | 6 ++++++ kernel/kallsyms.c | 1 - kernel/kprobes.c | 26 ++++++++++++++++++++++++++ net/ipv4/tcp_probe.c | 6 ++++-- 10 files changed, 56 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 3fd2f256f2be..af219e51734f 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -1142,7 +1142,7 @@ source "arch/i386/oprofile/Kconfig" config KPROBES bool "Kprobes (EXPERIMENTAL)" - depends on EXPERIMENTAL && MODULES + depends on KALLSYMS && EXPERIMENTAL && MODULES help Kprobes allows you to trap at almost any kernel address and execute a callback function. register_kprobe() establishes diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 0b7f701d5cf7..70f7eb9fed35 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -516,7 +516,7 @@ source "arch/ia64/oprofile/Kconfig" config KPROBES bool "Kprobes (EXPERIMENTAL)" - depends on EXPERIMENTAL && MODULES + depends on KALLSYMS && EXPERIMENTAL && MODULES help Kprobes allows you to trap at almost any kernel address and execute a callback function. register_kprobe() establishes diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a0dd1b0ee483..032e6ab5d3c4 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -1069,7 +1069,7 @@ source "arch/powerpc/oprofile/Kconfig" config KPROBES bool "Kprobes (EXPERIMENTAL)" - depends on PPC64 && EXPERIMENTAL && MODULES + depends on PPC64 && KALLSYMS && EXPERIMENTAL && MODULES help Kprobes allows you to trap at almost any kernel address and execute a callback function. register_kprobe() establishes diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 8d8ca716f7a7..b627f8dbcaad 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -420,7 +420,7 @@ source "arch/sparc64/oprofile/Kconfig" config KPROBES bool "Kprobes (EXPERIMENTAL)" - depends on EXPERIMENTAL && MODULES + depends on KALLSYMS && EXPERIMENTAL && MODULES help Kprobes allows you to trap at almost any kernel address and execute a callback function. register_kprobe() establishes diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index b87a19f0d584..0a5d8e659aa4 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -690,7 +690,7 @@ source "arch/x86_64/oprofile/Kconfig" config KPROBES bool "Kprobes (EXPERIMENTAL)" - depends on EXPERIMENTAL && MODULES + depends on KALLSYMS && EXPERIMENTAL && MODULES help Kprobes allows you to trap at almost any kernel address and execute a callback function. register_kprobe() establishes diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h index 34e1f89a5fa0..1ef54be6abfa 100644 --- a/include/asm-powerpc/kprobes.h +++ b/include/asm-powerpc/kprobes.h @@ -44,6 +44,21 @@ typedef unsigned int kprobe_opcode_t; #define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000) #define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000) +/* + * 64bit powerpc uses function descriptors. + * Handle cases where: + * - User passes a <.symbol> + * - User passes a + * - User passes a non-existant symbol, kallsyms_lookup_name + * returns 0. Don't deref the NULL pointer in that case + */ +#define kprobe_lookup_name(name, addr) \ +{ \ + addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \ + if (!(name[0] == '.') && addr) \ + addr = *(kprobe_opcode_t **)addr; \ +} + #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry) #define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \ diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 8bf6702da2a0..a5c5a0cb0d5c 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -77,6 +77,12 @@ struct kprobe { /* location of the probe point */ kprobe_opcode_t *addr; + /* Allow user to indicate symbol name of the probe point */ + char *symbol_name; + + /* Offset into the symbol */ + unsigned int offset; + /* Called before addr is executed. */ kprobe_pre_handler_t pre_handler; diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index ab16a5a4cfe9..342bca62c496 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -154,7 +154,6 @@ unsigned long kallsyms_lookup_name(const char *name) } return module_kallsyms_lookup_name(name); } -EXPORT_SYMBOL_GPL(kallsyms_lookup_name); /* * Lookup an address diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 3f57dfdc8f92..f66b8e681b4d 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,16 @@ #define KPROBE_HASH_BITS 6 #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) + +/* + * Some oddball architectures like 64bit powerpc have function descriptors + * so this must be overridable. + */ +#ifndef kprobe_lookup_name +#define kprobe_lookup_name(name, addr) \ + addr = ((kprobe_opcode_t *)(kallsyms_lookup_name(name))) +#endif + static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; static atomic_t kprobe_count; @@ -447,6 +458,21 @@ static int __kprobes __register_kprobe(struct kprobe *p, struct kprobe *old_p; struct module *probed_mod; + /* + * If we have a symbol_name argument look it up, + * and add it to the address. That way the addr + * field can either be global or relative to a symbol. + */ + if (p->symbol_name) { + if (p->addr) + return -EINVAL; + kprobe_lookup_name(p->symbol_name, p->addr); + } + + if (!p->addr) + return -EINVAL; + p->addr = (kprobe_opcode_t *)(((char *)p->addr)+ p->offset); + if ((!kernel_text_address((unsigned long) p->addr)) || in_kprobes_functions((unsigned long) p->addr)) return -EINVAL; diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index dab37d2f65fc..4be336f17883 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c @@ -99,8 +99,10 @@ static int jtcp_sendmsg(struct kiocb *iocb, struct sock *sk, } static struct jprobe tcp_send_probe = { - .kp = { .addr = (kprobe_opcode_t *) &tcp_sendmsg, }, - .entry = (kprobe_opcode_t *) &jtcp_sendmsg, + .kp = { + .symbol_name = "tcp_sendmsg", + }, + .entry = JPROBE_ENTRY(jtcp_sendmsg), }; -- cgit v1.2.3 From 99219a3fbc2dcf2eaa954f7b2ac27299fd7894cd Mon Sep 17 00:00:00 2001 From: "bibo,mao" Date: Mon, 2 Oct 2006 02:17:35 -0700 Subject: [PATCH] kretprobe spinlock deadlock patch kprobe_flush_task() possibly calls kfree function during holding kretprobe_lock spinlock, if kfree function is probed by kretprobe that will incur spinlock deadlock. This patch moves kfree function out scope of kretprobe_lock. Signed-off-by: bibo, mao Signed-off-by: Ananth N Mavinakayanahalli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/kprobes.c | 9 +++++++-- arch/ia64/kernel/kprobes.c | 9 +++++++-- arch/powerpc/kernel/kprobes.c | 9 +++++++-- arch/s390/kernel/kprobes.c | 9 +++++++-- arch/x86_64/kernel/kprobes.c | 9 +++++++-- include/linux/kprobes.h | 2 +- kernel/kprobes.c | 15 +++++++++++---- 7 files changed, 47 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c index 7a97544f15a0..d98e44b16fe2 100644 --- a/arch/i386/kernel/kprobes.c +++ b/arch/i386/kernel/kprobes.c @@ -396,11 +396,12 @@ no_kprobe: fastcall void *__kprobes trampoline_handler(struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; - struct hlist_head *head; + struct hlist_head *head, empty_rp; struct hlist_node *node, *tmp; unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; + INIT_HLIST_HEAD(&empty_rp); spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); @@ -429,7 +430,7 @@ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs) } orig_ret_address = (unsigned long)ri->ret_addr; - recycle_rp_inst(ri); + recycle_rp_inst(ri, &empty_rp); if (orig_ret_address != trampoline_address) /* @@ -444,6 +445,10 @@ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs) spin_unlock_irqrestore(&kretprobe_lock, flags); + hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { + hlist_del(&ri->hlist); + kfree(ri); + } return (void*)orig_ret_address; } diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 9c9c8fcdfbdc..51217d63285e 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c @@ -338,12 +338,13 @@ static void kretprobe_trampoline(void) int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; - struct hlist_head *head; + struct hlist_head *head, empty_rp; struct hlist_node *node, *tmp; unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address = ((struct fnptr *)kretprobe_trampoline)->ip; + INIT_HLIST_HEAD(&empty_rp); spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); @@ -369,7 +370,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) ri->rp->handler(ri, regs); orig_ret_address = (unsigned long)ri->ret_addr; - recycle_rp_inst(ri); + recycle_rp_inst(ri, &empty_rp); if (orig_ret_address != trampoline_address) /* @@ -387,6 +388,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) spin_unlock_irqrestore(&kretprobe_lock, flags); preempt_enable_no_resched(); + hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { + hlist_del(&ri->hlist); + kfree(ri); + } /* * By returning a non-zero value, we are telling * kprobe_handler() that we don't want the post_handler diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 46d2fd0e5789..7b8d12b9026c 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -260,11 +260,12 @@ void kretprobe_trampoline_holder(void) int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; - struct hlist_head *head; + struct hlist_head *head, empty_rp; struct hlist_node *node, *tmp; unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; + INIT_HLIST_HEAD(&empty_rp); spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); @@ -290,7 +291,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) ri->rp->handler(ri, regs); orig_ret_address = (unsigned long)ri->ret_addr; - recycle_rp_inst(ri); + recycle_rp_inst(ri, &empty_rp); if (orig_ret_address != trampoline_address) /* @@ -308,6 +309,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) spin_unlock_irqrestore(&kretprobe_lock, flags); preempt_enable_no_resched(); + hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { + hlist_del(&ri->hlist); + kfree(ri); + } /* * By returning a non-zero value, we are telling * kprobe_handler() that we don't want the post_handler diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index ca28fb0b3790..4d9ff5ce4cbd 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -369,11 +369,12 @@ void __kprobes kretprobe_trampoline_holder(void) int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; - struct hlist_head *head; + struct hlist_head *head, empty_rp; struct hlist_node *node, *tmp; unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; + INIT_HLIST_HEAD(&empty_rp); spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); @@ -399,7 +400,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) ri->rp->handler(ri, regs); orig_ret_address = (unsigned long)ri->ret_addr; - recycle_rp_inst(ri); + recycle_rp_inst(ri, &empty_rp); if (orig_ret_address != trampoline_address) { /* @@ -417,6 +418,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) spin_unlock_irqrestore(&kretprobe_lock, flags); preempt_enable_no_resched(); + hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { + hlist_del(&ri->hlist); + kfree(ri); + } /* * By returning a non-zero value, we are telling * kprobe_handler() that we don't want the post_handler diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c index d04f0ab2ff40..ac241567e682 100644 --- a/arch/x86_64/kernel/kprobes.c +++ b/arch/x86_64/kernel/kprobes.c @@ -405,11 +405,12 @@ no_kprobe: int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; - struct hlist_head *head; + struct hlist_head *head, empty_rp; struct hlist_node *node, *tmp; unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; + INIT_HLIST_HEAD(&empty_rp); spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); @@ -435,7 +436,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) ri->rp->handler(ri, regs); orig_ret_address = (unsigned long)ri->ret_addr; - recycle_rp_inst(ri); + recycle_rp_inst(ri, &empty_rp); if (orig_ret_address != trampoline_address) /* @@ -453,6 +454,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) spin_unlock_irqrestore(&kretprobe_lock, flags); preempt_enable_no_resched(); + hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { + hlist_del(&ri->hlist); + kfree(ri); + } /* * By returning a non-zero value, we are telling * kprobe_handler() that we don't want the post_handler diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index a5c5a0cb0d5c..ac4c0559f751 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -202,7 +202,7 @@ void unregister_kretprobe(struct kretprobe *rp); struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp); void add_rp_inst(struct kretprobe_instance *ri); void kprobe_flush_task(struct task_struct *tk); -void recycle_rp_inst(struct kretprobe_instance *ri); +void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head); #else /* CONFIG_KPROBES */ #define __kprobes /**/ diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 41dfda50e22a..610c837ad9e0 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -319,7 +319,8 @@ void __kprobes add_rp_inst(struct kretprobe_instance *ri) } /* Called with kretprobe_lock held */ -void __kprobes recycle_rp_inst(struct kretprobe_instance *ri) +void __kprobes recycle_rp_inst(struct kretprobe_instance *ri, + struct hlist_head *head) { /* remove rp inst off the rprobe_inst_table */ hlist_del(&ri->hlist); @@ -331,7 +332,7 @@ void __kprobes recycle_rp_inst(struct kretprobe_instance *ri) hlist_add_head(&ri->uflist, &ri->rp->free_instances); } else /* Unregistering */ - kfree(ri); + hlist_add_head(&ri->hlist, head); } struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk) @@ -348,17 +349,23 @@ struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk) void __kprobes kprobe_flush_task(struct task_struct *tk) { struct kretprobe_instance *ri; - struct hlist_head *head; + struct hlist_head *head, empty_rp; struct hlist_node *node, *tmp; unsigned long flags = 0; + INIT_HLIST_HEAD(&empty_rp); spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(tk); hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { if (ri->task == tk) - recycle_rp_inst(ri); + recycle_rp_inst(ri, &empty_rp); } spin_unlock_irqrestore(&kretprobe_lock, flags); + + hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { + hlist_del(&ri->hlist); + kfree(ri); + } } static inline void free_rp_inst(struct kretprobe *rp) -- cgit v1.2.3 From 0f532f3861d2c4e5aa7dcd33fb18e9975eb28457 Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Mon, 2 Oct 2006 02:17:39 -0700 Subject: [PATCH] cpumask: add highest_possible_node_id cpumask: add highest_possible_node_id(), analogous to highest_possible_processor_id(). [pj@sgi.com: fix typo] Signed-off-by: Greg Banks Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/nodemask.h | 2 ++ lib/cpumask.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) (limited to 'include/linux') diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 1a9ef3e627d1..5dce5c21822c 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -352,6 +352,7 @@ extern nodemask_t node_possible_map; #define node_possible(node) node_isset((node), node_possible_map) #define first_online_node first_node(node_online_map) #define next_online_node(nid) next_node((nid), node_online_map) +int highest_possible_node_id(void); #else #define num_online_nodes() 1 #define num_possible_nodes() 1 @@ -359,6 +360,7 @@ extern nodemask_t node_possible_map; #define node_possible(node) ((node) == 0) #define first_online_node 0 #define next_online_node(nid) (MAX_NUMNODES) +#define highest_possible_node_id() 0 #endif #define any_online_node(mask) \ diff --git a/lib/cpumask.c b/lib/cpumask.c index 3a67dc5ada7d..7a2a73f88d59 100644 --- a/lib/cpumask.c +++ b/lib/cpumask.c @@ -43,3 +43,19 @@ int __any_online_cpu(const cpumask_t *mask) return cpu; } EXPORT_SYMBOL(__any_online_cpu); + +#if MAX_NUMNODES > 1 +/* + * Find the highest possible node id. + */ +int highest_possible_node_id(void) +{ + unsigned int node; + unsigned int highest = 0; + + for_each_node_mask(node, node_possible_map) + highest = node; + return highest; +} +EXPORT_SYMBOL(highest_possible_node_id); +#endif -- cgit v1.2.3 From bc591ccff27e6a85d3a0d6fcb16cfadcc45267a8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 2 Oct 2006 02:17:44 -0700 Subject: [PATCH] knfsd: add a callback for when last rpc thread finishes nfsd has some cleanup that it wants to do when the last thread exits, and there will shortly be some more. So collect this all into one place and define a callback for an rpc service to call when the service is about to be destroyed. [akpm@osdl.org: cleanups, build fix] Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svc.c | 2 +- fs/nfs/callback.c | 2 +- fs/nfsd/nfssvc.c | 40 ++++++++++++++++++---------------------- include/linux/sunrpc/svc.h | 8 +++++++- net/sunrpc/svc.c | 7 ++++++- 5 files changed, 33 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 9a991b52c647..13feba45030e 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -236,7 +236,7 @@ lockd_up(void) "lockd_up: no pid, %d users??\n", nlmsvc_users); error = -ENOMEM; - serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE); + serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL); if (!serv) { printk(KERN_WARNING "lockd_up: create service failed\n"); goto out; diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index a3ee11364db0..e244cdc7afab 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -116,7 +116,7 @@ int nfs_callback_up(void) goto out; init_completion(&nfs_callback_info.started); init_completion(&nfs_callback_info.stopped); - serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE); + serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); ret = -ENOMEM; if (!serv) goto out_err; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index ec1decf29bab..c52c99964a4c 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -130,11 +130,25 @@ int nfsd_nrthreads(void) return nfsd_serv->sv_nrthreads; } +static int killsig; /* signal that was used to kill last nfsd */ +static void nfsd_last_thread(struct svc_serv *serv) +{ + /* When last nfsd thread exits we need to do some clean-up */ + nfsd_serv = NULL; + nfsd_racache_shutdown(); + nfs4_state_shutdown(); + + printk(KERN_WARNING "nfsd: last server has exited\n"); + if (killsig != SIG_NOCLEAN) { + printk(KERN_WARNING "nfsd: unexporting all filesystems\n"); + nfsd_export_flush(); + } +} int nfsd_svc(unsigned short port, int nrservs) { int error; - int none_left, found_one, i; + int found_one, i; struct list_head *victim; lock_kernel(); @@ -197,7 +211,8 @@ nfsd_svc(unsigned short port, int nrservs) atomic_set(&nfsd_busy, 0); error = -ENOMEM; - nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE); + nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE, + nfsd_last_thread); if (nfsd_serv == NULL) goto out; error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); @@ -231,13 +246,7 @@ nfsd_svc(unsigned short port, int nrservs) nrservs++; } failure: - none_left = (nfsd_serv->sv_nrthreads == 1); svc_destroy(nfsd_serv); /* Release server */ - if (none_left) { - nfsd_serv = NULL; - nfsd_racache_shutdown(); - nfs4_state_shutdown(); - } out: unlock_kernel(); return error; @@ -353,7 +362,7 @@ nfsd(struct svc_rqst *rqstp) if (sigismember(¤t->pending.signal, signo) && !sigismember(¤t->blocked, signo)) break; - err = signo; + killsig = signo; } /* Clear signals before calling lockd_down() and svc_exit_thread() */ flush_signals(current); @@ -362,19 +371,6 @@ nfsd(struct svc_rqst *rqstp) /* Release lockd */ lockd_down(); - - /* Check if this is last thread */ - if (serv->sv_nrthreads==1) { - - printk(KERN_WARNING "nfsd: last server has exited\n"); - if (err != SIG_NOCLEAN) { - printk(KERN_WARNING "nfsd: unexporting all filesystems\n"); - nfsd_export_flush(); - } - nfsd_serv = NULL; - nfsd_racache_shutdown(); /* release read-ahead cache */ - nfs4_state_shutdown(); - } list_del(&me.list); nfsdstats.th_cnt --; diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 73140ee5c638..bff5e9b486c2 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -42,6 +42,11 @@ struct svc_serv { int sv_tmpcnt; /* count of temporary sockets */ char * sv_name; /* service name */ + + void (*sv_shutdown)(struct svc_serv *serv); + /* Callback to use when last thread + * exits. + */ }; /* @@ -328,7 +333,8 @@ typedef void (*svc_thread_fn)(struct svc_rqst *); /* * Function prototypes. */ -struct svc_serv * svc_create(struct svc_program *, unsigned int); +struct svc_serv * svc_create(struct svc_program *, unsigned int, + void (*shutdown)(struct svc_serv*)); int svc_create_thread(svc_thread_fn, struct svc_serv *); void svc_exit_thread(struct svc_rqst *); void svc_destroy(struct svc_serv *); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 44b8d9d4c18a..f5aee4c61676 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -26,7 +26,8 @@ * Create an RPC service */ struct svc_serv * -svc_create(struct svc_program *prog, unsigned int bufsize) +svc_create(struct svc_program *prog, unsigned int bufsize, + void (*shutdown)(struct svc_serv *serv)) { struct svc_serv *serv; int vers; @@ -39,6 +40,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize) serv->sv_nrthreads = 1; serv->sv_stats = prog->pg_stats; serv->sv_bufsz = bufsize? bufsize : 4096; + serv->sv_shutdown = shutdown; xdrsize = 0; while (prog) { prog->pg_lovers = prog->pg_nvers-1; @@ -91,6 +93,9 @@ svc_destroy(struct svc_serv *serv) sk_list); svc_delete_socket(svsk); } + if (serv->sv_shutdown) + serv->sv_shutdown(serv); + while (!list_empty(&serv->sv_permsocks)) { svsk = list_entry(serv->sv_permsocks.next, struct svc_sock, -- cgit v1.2.3 From 24e36663c375df577d2dcae437713481ffd6850c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 2 Oct 2006 02:17:45 -0700 Subject: [PATCH] knfsd: be more selective in which sockets lockd listens on Currently lockd listens on UDP always, and TCP if CONFIG_NFSD_TCP is set. However as lockd performs services of the client as well, this is a problem. If CONFIG_NfSD_TCP is not set, and a tcp mount is used, the server will not be able to call back to lockd. So: - add an option to lockd_up saying which protocol is needed - Always open sockets for which an explicit port was given, otherwise only open a socket of the type required - Change nfsd to do one lockd_up per socket rather than one per thread. This - removes the dependancy on CONFIG_NFSD_TCP - means that lockd may open sockets other than at startup - means that lockd will *not* listen on UDP if the only mounts are TCP mount (and nfsd hasn't started). The latter is the only one that concerns me at all - I don't know if this might be a problem with some servers. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntlock.c | 2 +- fs/lockd/svc.c | 47 +++++++++++++++++++++++++++++++++++++++------- fs/nfs/client.c | 3 ++- fs/nfsd/nfssvc.c | 16 ++++++++++------ include/linux/lockd/bind.h | 2 +- 5 files changed, 54 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index f95cc3f3c42d..6abb465b650f 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -202,7 +202,7 @@ reclaimer(void *ptr) /* This one ensures that our parent doesn't terminate while the * reclaim is in progress */ lock_kernel(); - lockd_up(); + lockd_up(0); nlmclnt_prepare_reclaim(host); /* First, reclaim all locks that have been marked. */ diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 13feba45030e..8d19de6a14dc 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,7 @@ EXPORT_SYMBOL(nlmsvc_ops); static DEFINE_MUTEX(nlmsvc_mutex); static unsigned int nlmsvc_users; static pid_t nlmsvc_pid; +static struct svc_serv *nlmsvc_serv; int nlmsvc_grace_period; unsigned long nlmsvc_timeout; @@ -112,6 +114,7 @@ lockd(struct svc_rqst *rqstp) * Let our maker know we're running. */ nlmsvc_pid = current->pid; + nlmsvc_serv = serv; complete(&lockd_start_done); daemonize("lockd"); @@ -189,6 +192,7 @@ lockd(struct svc_rqst *rqstp) nlmsvc_invalidate_all(); nlm_shutdown_hosts(); nlmsvc_pid = 0; + nlmsvc_serv = NULL; } else printk(KERN_DEBUG "lockd: new process, skipping host shutdown\n"); @@ -205,11 +209,42 @@ lockd(struct svc_rqst *rqstp) module_put_and_exit(0); } + +static int find_socket(struct svc_serv *serv, int proto) +{ + struct svc_sock *svsk; + int found = 0; + list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) + if (svsk->sk_sk->sk_protocol == proto) { + found = 1; + break; + } + return found; +} + +static int make_socks(struct svc_serv *serv, int proto) +{ + /* Make any sockets that are needed but not present. + * If nlm_udpport or nlm_tcpport were set as module + * options, make those sockets unconditionally + */ + int err = 0; + if (proto == IPPROTO_UDP || nlm_udpport) + if (!find_socket(serv, IPPROTO_UDP)) + err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport); + if (err) + return err; + if (proto == IPPROTO_TCP || nlm_tcpport) + if (!find_socket(serv, IPPROTO_TCP)) + err= svc_makesock(serv, IPPROTO_TCP, nlm_tcpport); + return err; +} + /* * Bring up the lockd process if it's not already up. */ int -lockd_up(void) +lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ { static int warned; struct svc_serv * serv; @@ -224,8 +259,10 @@ lockd_up(void) /* * Check whether we're already up and running. */ - if (nlmsvc_pid) + if (nlmsvc_pid) { + error = make_socks(nlmsvc_serv, proto); goto out; + } /* * Sanity check: if there's no pid, @@ -242,11 +279,7 @@ lockd_up(void) goto out; } - if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0 -#ifdef CONFIG_NFSD_TCP - || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0 -#endif - ) { + if ((error = make_socks(serv, proto)) < 0) { if (warned++ == 0) printk(KERN_WARNING "lockd_up: makesock failed, error=%d\n", error); diff --git a/fs/nfs/client.c b/fs/nfs/client.c index ec1938d4b814..8106f3b29e4a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -460,7 +460,8 @@ static int nfs_start_lockd(struct nfs_server *server) goto out; if (server->flags & NFS_MOUNT_NONLM) goto out; - error = lockd_up(); + error = lockd_up((server->flags & NFS_MOUNT_TCP) ? + IPPROTO_TCP : IPPROTO_UDP); if (error < 0) server->flags |= NFS_MOUNT_NONLM; else diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index c52c99964a4c..0339b4ddfa3b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -134,6 +134,9 @@ static int killsig; /* signal that was used to kill last nfsd */ static void nfsd_last_thread(struct svc_serv *serv) { /* When last nfsd thread exits we need to do some clean-up */ + struct svc_sock *svsk; + list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) + lockd_down(); nfsd_serv = NULL; nfsd_racache_shutdown(); nfs4_state_shutdown(); @@ -218,11 +221,16 @@ nfsd_svc(unsigned short port, int nrservs) error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); if (error < 0) goto failure; - + error = lockd_up(IPPROTO_UDP); + if (error < 0) + goto failure; #ifdef CONFIG_NFSD_TCP error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); if (error < 0) goto failure; + error = lockd_up(IPPROTO_TCP); + if (error < 0) + goto failure; #endif do_gettimeofday(&nfssvc_boot); /* record boot time */ } else @@ -306,8 +314,6 @@ nfsd(struct svc_rqst *rqstp) nfsdstats.th_cnt++; - lockd_up(); /* start lockd */ - me.task = current; list_add(&me.list, &nfsd_list); @@ -364,13 +370,11 @@ nfsd(struct svc_rqst *rqstp) break; killsig = signo; } - /* Clear signals before calling lockd_down() and svc_exit_thread() */ + /* Clear signals before calling svc_exit_thread() */ flush_signals(current); lock_kernel(); - /* Release lockd */ - lockd_down(); list_del(&me.list); nfsdstats.th_cnt --; diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index b054debef2e0..81e3a185f951 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h @@ -30,7 +30,7 @@ extern struct nlmsvc_binding * nlmsvc_ops; * Functions exported by the lockd module */ extern int nlmclnt_proc(struct inode *, int, struct file_lock *); -extern int lockd_up(void); +extern int lockd_up(int proto); extern void lockd_down(void); #endif /* LINUX_LOCKD_BIND_H */ -- cgit v1.2.3 From 6658d3a7bbfd1768a7b599def47939417f0ee8ef Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 2 Oct 2006 02:17:46 -0700 Subject: [PATCH] knfsd: remove nfsd_versbits as intermediate storage for desired versions We have an array 'nfsd_version' which lists the available versions of nfsd, and 'nfsd_versions' (poor choice there :-() which lists the currently active versions. Then we have a bitmap - nfsd_versbits which says which versions are wanted. The bits in this bitset cause content to be copied from nfsd_version to nfsd_versions when nfsd starts. This patch removes nfsd_versbits and moves information directly from nfsd_version to nfsd_versions when requests for version changes arrive. Note that this doesn't make it possible to change versions while the server is running. This is because serv->sv_xdrsize is calculated when a service is created, and used when threads are created, and xdrsize depends on the active versions. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsctl.c | 18 ++++----- fs/nfsd/nfssvc.c | 93 ++++++++++++++++++++++++-------------------- include/linux/nfsd/nfsd.h | 4 ++ include/linux/nfsd/syscall.h | 17 -------- 4 files changed, 62 insertions(+), 70 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 7046ac9cf97f..d6881774ea57 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -35,8 +35,6 @@ #include -unsigned int nfsd_versbits = ~0; - /* * We have a single directory with 9 nodes in it. */ @@ -372,6 +370,10 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) if (size>0) { if (nfsd_serv) + /* Cannot change versions without updating + * nfsd_serv->sv_xdrsize, and reallocing + * rq_argp and rq_resp + */ return -EBUSY; if (buf[size-1] != '\n') return -EINVAL; @@ -390,10 +392,7 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) case 2: case 3: case 4: - if (sign != '-') - NFSCTL_VERSET(nfsd_versbits, num); - else - NFSCTL_VERUNSET(nfsd_versbits, num); + nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET); break; default: return -EINVAL; @@ -404,16 +403,15 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) /* If all get turned off, turn them back on, as * having no versions is BAD */ - if ((nfsd_versbits & NFSCTL_VERALL)==0) - nfsd_versbits = NFSCTL_VERALL; + nfsd_reset_versions(); } /* Now write current state into reply buffer */ len = 0; sep = ""; for (num=2 ; num <= 4 ; num++) - if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) { + if (nfsd_vers(num, NFSD_AVAIL)) { len += sprintf(buf+len, "%s%c%d", sep, - NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-', + nfsd_vers(num, NFSD_TEST)?'+':'-', num); sep = " "; } diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 0339b4ddfa3b..140e3a2d1b9f 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -117,6 +117,32 @@ struct svc_program nfsd_program = { }; +int nfsd_vers(int vers, enum vers_op change) +{ + if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS) + return -1; + switch(change) { + case NFSD_SET: + nfsd_versions[vers] = nfsd_version[vers]; + break; +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) + if (vers < NFSD_ACL_NRVERS) + nfsd_acl_version[vers] = nfsd_acl_version[vers]; +#endif + case NFSD_CLEAR: + nfsd_versions[vers] = NULL; +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) + if (vers < NFSD_ACL_NRVERS) + nfsd_acl_version[vers] = NULL; +#endif + break; + case NFSD_TEST: + return nfsd_versions[vers] != NULL; + case NFSD_AVAIL: + return nfsd_version[vers] != NULL; + } + return 0; +} /* * Maximum number of nfsd processes */ @@ -147,16 +173,36 @@ static void nfsd_last_thread(struct svc_serv *serv) nfsd_export_flush(); } } + +void nfsd_reset_versions(void) +{ + int found_one = 0; + int i; + + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { + if (nfsd_program.pg_vers[i]) + found_one = 1; + } + + if (!found_one) { + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) + nfsd_program.pg_vers[i] = nfsd_version[i]; +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) + for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) + nfsd_acl_program.pg_vers[i] = + nfsd_acl_version[i]; +#endif + } +} + int nfsd_svc(unsigned short port, int nrservs) { int error; - int found_one, i; struct list_head *victim; lock_kernel(); - dprintk("nfsd: creating service: vers 0x%x\n", - nfsd_versbits); + dprintk("nfsd: creating service\n"); error = -EINVAL; if (nrservs <= 0) nrservs = 0; @@ -171,46 +217,7 @@ nfsd_svc(unsigned short port, int nrservs) if (error<0) goto out; if (!nfsd_serv) { - /* - * Use the nfsd_ctlbits to define which - * versions that will be advertised. - * If nfsd_ctlbits doesn't list any version, - * export them all. - */ - found_one = 0; - - for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { - if (NFSCTL_VERISSET(nfsd_versbits, i)) { - nfsd_program.pg_vers[i] = nfsd_version[i]; - found_one = 1; - } else - nfsd_program.pg_vers[i] = NULL; - } - - if (!found_one) { - for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) - nfsd_program.pg_vers[i] = nfsd_version[i]; - } - - -#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) - found_one = 0; - - for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) { - if (NFSCTL_VERISSET(nfsd_versbits, i)) { - nfsd_acl_program.pg_vers[i] = - nfsd_acl_version[i]; - found_one = 1; - } else - nfsd_acl_program.pg_vers[i] = NULL; - } - - if (!found_one) { - for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) - nfsd_acl_program.pg_vers[i] = - nfsd_acl_version[i]; - } -#endif + nfsd_reset_versions(); atomic_set(&nfsd_busy, 0); error = -ENOMEM; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 2dcad295fece..46f1dc5b96dd 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -140,6 +140,10 @@ struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); #endif +enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; +int nfsd_vers(int vers, enum vers_op change); +void nfsd_reset_versions(void); + /* * NFSv4 State diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h index dae0faea2807..8bcddccb6c42 100644 --- a/include/linux/nfsd/syscall.h +++ b/include/linux/nfsd/syscall.h @@ -38,21 +38,6 @@ #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ #define NFSCTL_GETFS 8 /* get an fh by path with max FH len */ -/* - * Macros used to set version - */ -#define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << (_v))) -#define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v))) -#define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << (_v))) - -#if defined(CONFIG_NFSD_V4) -#define NFSCTL_VERALL (0x1c /* 0b011100 */) -#elif defined(CONFIG_NFSD_V3) -#define NFSCTL_VERALL (0x0c /* 0b001100 */) -#else -#define NFSCTL_VERALL (0x04 /* 0b000100 */) -#endif - /* SVC */ struct nfsctl_svc { unsigned short svc_port; @@ -134,8 +119,6 @@ extern int exp_delclient(struct nfsctl_client *ncp); extern int exp_export(struct nfsctl_export *nxp); extern int exp_unexport(struct nfsctl_export *nxp); -extern unsigned int nfsd_versbits; - #endif /* __KERNEL__ */ #endif /* NFSD_SYSCALL_H */ -- cgit v1.2.3 From 80212d59e32a8a8e030c2ddc5861d8ff70542c56 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 2 Oct 2006 02:17:47 -0700 Subject: [PATCH] knfsd: define new nfsdfs file: portlist - contains list of ports This file will list all ports that nfsd has open. Default when TCP enabled will be ipv4 udp 0.0.0.0 2049 ipv4 tcp 0.0.0.0 2049 Later, the list of ports will be settable. 'portlist' chosen rather than 'ports', to avoid unnecessary confusion with non-mainline patches which created 'ports' with different semantics. [akpm@osdl.org: cleanups, build fix] Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsctl.c | 20 ++++++++++++++++++++ include/linux/sunrpc/svcsock.h | 1 + net/sunrpc/svcsock.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) (limited to 'include/linux') diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index d6881774ea57..d4041a05bc19 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -23,10 +23,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -51,6 +53,7 @@ enum { NFSD_Fh, NFSD_Threads, NFSD_Versions, + NFSD_Ports, /* * The below MUST come last. Otherwise we leave a hole in nfsd_files[] * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops @@ -74,6 +77,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size); static ssize_t write_filehandle(struct file *file, char *buf, size_t size); static ssize_t write_threads(struct file *file, char *buf, size_t size); static ssize_t write_versions(struct file *file, char *buf, size_t size); +static ssize_t write_ports(struct file *file, char *buf, size_t size); #ifdef CONFIG_NFSD_V4 static ssize_t write_leasetime(struct file *file, char *buf, size_t size); static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); @@ -90,6 +94,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { [NFSD_Fh] = write_filehandle, [NFSD_Threads] = write_threads, [NFSD_Versions] = write_versions, + [NFSD_Ports] = write_ports, #ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = write_leasetime, [NFSD_RecoveryDir] = write_recoverydir, @@ -419,6 +424,20 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) return len; } +static ssize_t write_ports(struct file *file, char *buf, size_t size) +{ + /* for now, ignore what was written and just + * return known ports + * AF proto address port + */ + int len = 0; + lock_kernel(); + if (nfsd_serv) + len = svc_sock_names(buf, nfsd_serv); + unlock_kernel(); + return len; +} + #ifdef CONFIG_NFSD_V4 extern time_t nfs4_leasetime(void); @@ -482,6 +501,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, #ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index b4acb3d37c3f..3caf92d72a81 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -61,5 +61,6 @@ int svc_recv(struct svc_serv *, struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); void svc_sock_update_bufs(struct svc_serv *serv); +int svc_sock_names(char *buf, struct svc_serv *serv); #endif /* SUNRPC_SVCSOCK_H */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 5b0fe1b66a23..3ee4b78742b1 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -428,6 +428,46 @@ out: return len; } +/* + * Report socket names for nfsdfs + */ +static int one_sock_name(char *buf, struct svc_sock *svsk) +{ + int len; + + switch(svsk->sk_sk->sk_family) { + case AF_INET: + len = sprintf(buf, "ipv4 %s %u.%u.%u.%u %d\n", + svsk->sk_sk->sk_protocol==IPPROTO_UDP? + "udp" : "tcp", + NIPQUAD(inet_sk(svsk->sk_sk)->rcv_saddr), + inet_sk(svsk->sk_sk)->num); + break; + default: + len = sprintf(buf, "*unknown-%d*\n", + svsk->sk_sk->sk_family); + } + return len; +} + +int +svc_sock_names(char *buf, struct svc_serv *serv) +{ + struct svc_sock *svsk; + int len = 0; + + if (!serv) + return 0; + spin_lock(&serv->sv_lock); + list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) { + int onelen = one_sock_name(buf+len, svsk); + len += onelen; + } + spin_unlock(&serv->sv_lock); + return len; +} +EXPORT_SYMBOL(svc_sock_names); + /* * Check input queue length */ -- cgit v1.2.3 From b41b66d63c730cc45a1024e1f1e67439e507e40f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 2 Oct 2006 02:17:48 -0700 Subject: [PATCH] knfsd: allow sockets to be passed to nfsd via 'portlist' Userspace should create and bind a socket (but not connectted) and write the 'fd' to portlist. This will cause the nfs server to listen on that socket. To close a socket, the name of the socket - as read from 'portlist' can be written to 'portlist' with a preceding '-'. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsctl.c | 59 +++++++++++++++++++++++++++++++++++------- fs/nfsd/nfssvc.c | 4 +-- include/linux/nfsd/nfsd.h | 1 + include/linux/sunrpc/svcsock.h | 6 ++++- net/sunrpc/svcsock.c | 49 ++++++++++++++++++++++++++++++++--- 5 files changed, 102 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index d4041a05bc19..80e97a5ffc3f 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -24,9 +24,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -426,16 +428,55 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) static ssize_t write_ports(struct file *file, char *buf, size_t size) { - /* for now, ignore what was written and just - * return known ports - * AF proto address port + if (size == 0) { + int len = 0; + lock_kernel(); + if (nfsd_serv) + len = svc_sock_names(buf, nfsd_serv, NULL); + unlock_kernel(); + return len; + } + /* Either a single 'fd' number is written, in which + * case it must be for a socket of a supported family/protocol, + * and we use it as an nfsd socket, or + * A '-' followed by the 'name' of a socket in which case + * we close the socket. */ - int len = 0; - lock_kernel(); - if (nfsd_serv) - len = svc_sock_names(buf, nfsd_serv); - unlock_kernel(); - return len; + if (isdigit(buf[0])) { + char *mesg = buf; + int fd; + int err; + err = get_int(&mesg, &fd); + if (err) + return -EINVAL; + if (fd < 0) + return -EINVAL; + err = nfsd_create_serv(); + if (!err) { + int proto = 0; + err = svc_addsock(nfsd_serv, fd, buf, &proto); + /* Decrease the count, but don't shutdown the + * the service + */ + if (err >= 0) + lockd_up(proto); + nfsd_serv->sv_nrthreads--; + } + return err; + } + if (buf[0] == '-') { + char *toclose = kstrdup(buf+1, GFP_KERNEL); + int len = 0; + if (!toclose) + return -ENOMEM; + lock_kernel(); + if (nfsd_serv) + len = svc_sock_names(buf, nfsd_serv, toclose); + unlock_kernel(); + kfree(toclose); + return len; + } + return -EINVAL; } #ifdef CONFIG_NFSD_V4 diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 5d473d8f0630..784f94fbebf3 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -195,7 +195,7 @@ void nfsd_reset_versions(void) } } -static int nfsd_create_serv(void) +int nfsd_create_serv(void) { int err = 0; lock_kernel(); @@ -210,8 +210,6 @@ static int nfsd_create_serv(void) nfsd_last_thread); if (nfsd_serv == NULL) err = -ENOMEM; - else - nfsd_serv->sv_nrthreads++; unlock_kernel(); do_gettimeofday(&nfssvc_boot); /* record boot time */ return err; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 46f1dc5b96dd..e1dbc86c270b 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -143,6 +143,7 @@ int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; int nfsd_vers(int vers, enum vers_op change); void nfsd_reset_versions(void); +int nfsd_create_serv(void); /* diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 3caf92d72a81..b8a9652b8755 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -61,6 +61,10 @@ int svc_recv(struct svc_serv *, struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); void svc_sock_update_bufs(struct svc_serv *serv); -int svc_sock_names(char *buf, struct svc_serv *serv); +int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose); +int svc_addsock(struct svc_serv *serv, + int fd, + char *name_return, + int *proto); #endif /* SUNRPC_SVCSOCK_H */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 3ee4b78742b1..c6be67a86ae7 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -451,9 +452,9 @@ static int one_sock_name(char *buf, struct svc_sock *svsk) } int -svc_sock_names(char *buf, struct svc_serv *serv) +svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) { - struct svc_sock *svsk; + struct svc_sock *svsk, *closesk = NULL; int len = 0; if (!serv) @@ -461,9 +462,14 @@ svc_sock_names(char *buf, struct svc_serv *serv) spin_lock(&serv->sv_lock); list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) { int onelen = one_sock_name(buf+len, svsk); - len += onelen; + if (toclose && strcmp(toclose, buf+len) == 0) + closesk = svsk; + else + len += onelen; } spin_unlock(&serv->sv_lock); + if (closesk) + svc_delete_socket(closesk); return len; } EXPORT_SYMBOL(svc_sock_names); @@ -1407,6 +1413,38 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, return svsk; } +int svc_addsock(struct svc_serv *serv, + int fd, + char *name_return, + int *proto) +{ + int err = 0; + struct socket *so = sockfd_lookup(fd, &err); + struct svc_sock *svsk = NULL; + + if (!so) + return err; + if (so->sk->sk_family != AF_INET) + err = -EAFNOSUPPORT; + else if (so->sk->sk_protocol != IPPROTO_TCP && + so->sk->sk_protocol != IPPROTO_UDP) + err = -EPROTONOSUPPORT; + else if (so->state > SS_UNCONNECTED) + err = -EISCONN; + else { + svsk = svc_setup_socket(serv, so, &err, 1); + if (svsk) + err = 0; + } + if (err) { + sockfd_put(so); + return err; + } + if (proto) *proto = so->sk->sk_protocol; + return one_sock_name(name_return, svsk); +} +EXPORT_SYMBOL_GPL(svc_addsock); + /* * Create socket for RPC service. */ @@ -1482,7 +1520,10 @@ svc_delete_socket(struct svc_sock *svsk) if (!svsk->sk_inuse) { spin_unlock_bh(&serv->sv_lock); - sock_release(svsk->sk_sock); + if (svsk->sk_sock->file) + sockfd_put(svsk->sk_sock); + else + sock_release(svsk->sk_sock); kfree(svsk); } else { spin_unlock_bh(&serv->sv_lock); -- cgit v1.2.3 From 6fb2b47fa16c81317ec282248e6cff521cca31c2 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 2 Oct 2006 02:17:50 -0700 Subject: [PATCH] knfsd: Drop 'serv' option to svc_recv and svc_process It isn't needed as it is available in rqstp->rq_server, and dropping it allows some local vars to be dropped. [akpm@osdl.org: build fix] Cc: "J. Bruce Fields" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svc.c | 7 +++---- fs/nfs/callback.c | 5 ++--- fs/nfsd/nfssvc.c | 6 ++---- include/linux/sunrpc/svc.h | 2 +- include/linux/sunrpc/svcsock.h | 2 +- net/sunrpc/svc.c | 3 ++- net/sunrpc/svcsock.c | 3 ++- 7 files changed, 13 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 8d19de6a14dc..f0791cff45ac 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -98,7 +98,6 @@ static inline void clear_grace_period(void) static void lockd(struct svc_rqst *rqstp) { - struct svc_serv *serv = rqstp->rq_server; int err = 0; unsigned long grace_period_expire; @@ -114,7 +113,7 @@ lockd(struct svc_rqst *rqstp) * Let our maker know we're running. */ nlmsvc_pid = current->pid; - nlmsvc_serv = serv; + nlmsvc_serv = rqstp->rq_server; complete(&lockd_start_done); daemonize("lockd"); @@ -164,7 +163,7 @@ lockd(struct svc_rqst *rqstp) * Find a socket with data available and call its * recvfrom routine. */ - err = svc_recv(serv, rqstp, timeout); + err = svc_recv(rqstp, timeout); if (err == -EAGAIN || err == -EINTR) continue; if (err < 0) { @@ -177,7 +176,7 @@ lockd(struct svc_rqst *rqstp) dprintk("lockd: request from %08x\n", (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr)); - svc_process(serv, rqstp); + svc_process(rqstp); } diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index e244cdc7afab..7933e2e99dbc 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -58,7 +58,6 @@ module_param_call(callback_tcpport, param_set_port, param_get_int, */ static void nfs_callback_svc(struct svc_rqst *rqstp) { - struct svc_serv *serv = rqstp->rq_server; int err; __module_get(THIS_MODULE); @@ -80,7 +79,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) /* * Listen for a request on the socket */ - err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT); + err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); if (err == -EAGAIN || err == -EINTR) continue; if (err < 0) { @@ -91,7 +90,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) } dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__, NIPQUAD(rqstp->rq_addr.sin_addr.s_addr)); - svc_process(serv, rqstp); + svc_process(rqstp); } svc_exit_thread(rqstp); diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 784f94fbebf3..f1314c63e823 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -323,7 +323,6 @@ update_thread_usage(int busy_threads) static void nfsd(struct svc_rqst *rqstp) { - struct svc_serv *serv = rqstp->rq_server; struct fs_struct *fsp; int err; struct nfsd_list me; @@ -373,8 +372,7 @@ nfsd(struct svc_rqst *rqstp) * Find a socket with data available and call its * recvfrom routine. */ - while ((err = svc_recv(serv, rqstp, - 60*60*HZ)) == -EAGAIN) + while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN) ; if (err < 0) break; @@ -387,7 +385,7 @@ nfsd(struct svc_rqst *rqstp) /* Process request with signals blocked. */ sigprocmask(SIG_SETMASK, &allowed_mask, NULL); - svc_process(serv, rqstp); + svc_process(rqstp); /* Unlock export hash tables */ exp_readunlock(); diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index bff5e9b486c2..cb341f96eb8d 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -338,7 +338,7 @@ struct svc_serv * svc_create(struct svc_program *, unsigned int, int svc_create_thread(svc_thread_fn, struct svc_serv *); void svc_exit_thread(struct svc_rqst *); void svc_destroy(struct svc_serv *); -int svc_process(struct svc_serv *, struct svc_rqst *); +int svc_process(struct svc_rqst *); int svc_register(struct svc_serv *, int, unsigned short); void svc_wake_up(struct svc_serv *); void svc_reserve(struct svc_rqst *rqstp, int space); diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index b8a9652b8755..d5f15e8db929 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -57,7 +57,7 @@ struct svc_sock { */ int svc_makesock(struct svc_serv *, int, unsigned short); void svc_delete_socket(struct svc_sock *); -int svc_recv(struct svc_serv *, struct svc_rqst *, long); +int svc_recv(struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); void svc_sock_update_bufs(struct svc_serv *serv); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index f5aee4c61676..eee45a58f3ee 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -253,13 +253,14 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port) * Process the RPC request. */ int -svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) +svc_process(struct svc_rqst *rqstp) { struct svc_program *progp; struct svc_version *versp = NULL; /* compiler food */ struct svc_procedure *procp = NULL; struct kvec * argv = &rqstp->rq_arg.head[0]; struct kvec * resv = &rqstp->rq_res.head[0]; + struct svc_serv *serv = rqstp->rq_server; kxdrproc_t xdr; __be32 *statp; u32 dir, prog, vers, proc; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index c6be67a86ae7..bc9bd189a540 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1166,9 +1166,10 @@ svc_sock_update_bufs(struct svc_serv *serv) * Receive the next request on any socket. */ int -svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) +svc_recv(struct svc_rqst *rqstp, long timeout) { struct svc_sock *svsk =NULL; + struct svc_serv *serv = rqstp->rq_server; int len; int pages; struct xdr_buf *arg; -- cgit v1.2.3 From 36bdfc8bae51339aa27ef8e4ce148185293061ae Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Mon, 2 Oct 2006 02:17:54 -0700 Subject: [PATCH] knfsd: move tempsock aging to a timer Following are 11 patches from Greg Banks which combine to make knfsd more Numa-aware. They reduce hitting on 'global' data structures, and create some data-structures that can be node-local. knfsd threads are bound to a particular node, and the thread to handle a new request is chosen from the threads that are attach to the node that received the interrupt. The distribution of threads across nodes can be controlled by a new file in the 'nfsd' filesystem, though the default approach of an even spread is probably fine for most sites. Some (old) numbers that show the efficacy of these patches: N == number of NICs == number of CPUs == nmber of clients. Number of NUMA nodes == N/2 N Throughput, MiB/s CPU usage, % (max=N*100) Before After Before After --- ------ ---- ----- ----- 4 312 435 350 228 6 500 656 501 418 8 562 804 690 589 This patch: Move the aging of RPC/TCP connection sockets from the main svc_recv() loop to a timer which uses a mark-and-sweep algorithm every 6 minutes. This reduces the amount of work that needs to be done in the main RPC loop and the length of time we need to hold the (effectively global) svc_serv->sv_lock. [akpm@osdl.org: cleanup] Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/svc.h | 1 + include/linux/sunrpc/svcsock.h | 2 + net/sunrpc/svc.c | 3 ++ net/sunrpc/svcsock.c | 96 ++++++++++++++++++++++++++++++------------ 4 files changed, 76 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index cb341f96eb8d..5eabded11061 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -40,6 +40,7 @@ struct svc_serv { struct list_head sv_permsocks; /* all permanent sockets */ struct list_head sv_tempsocks; /* all temporary sockets */ int sv_tmpcnt; /* count of temporary sockets */ + struct timer_list sv_temptimer; /* timer for aging temporary sockets */ char * sv_name; /* service name */ diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index d5f15e8db929..846aee95eec7 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -31,6 +31,8 @@ struct svc_sock { #define SK_DEAD 6 /* socket closed */ #define SK_CHNGBUF 7 /* need to change snd/rcv buffer sizes */ #define SK_DEFERRED 8 /* request on sk_deferred */ +#define SK_OLD 9 /* used for temp socket aging mark+sweep */ +#define SK_DETACHED 10 /* detached from tempsocks list */ int sk_reserved; /* space on outq that is reserved */ diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index eee45a58f3ee..0c2c52276285 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -59,6 +59,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize, INIT_LIST_HEAD(&serv->sv_sockets); INIT_LIST_HEAD(&serv->sv_tempsocks); INIT_LIST_HEAD(&serv->sv_permsocks); + init_timer(&serv->sv_temptimer); spin_lock_init(&serv->sv_lock); /* Remove any stale portmap registrations */ @@ -87,6 +88,8 @@ svc_destroy(struct svc_serv *serv) } else printk("svc_destroy: no threads for serv=%p!\n", serv); + del_timer_sync(&serv->sv_temptimer); + while (!list_empty(&serv->sv_tempsocks)) { svsk = list_entry(serv->sv_tempsocks.next, struct svc_sock, diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index bc9bd189a540..9ba1a071ff06 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -74,6 +74,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk); static int svc_deferred_recv(struct svc_rqst *rqstp); static struct cache_deferred_req *svc_defer(struct cache_req *req); +/* apparently the "standard" is that clients close + * idle connections after 5 minutes, servers after + * 6 minutes + * http://www.connectathon.org/talks96/nfstcp.pdf + */ +static int svc_conn_age_period = 6*60; + /* * Queue up an idle server thread. Must have serv->sv_lock held. * Note: this is really a stack rather than a queue, so that we only @@ -1220,24 +1227,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout) return -EINTR; spin_lock_bh(&serv->sv_lock); - if (!list_empty(&serv->sv_tempsocks)) { - svsk = list_entry(serv->sv_tempsocks.next, - struct svc_sock, sk_list); - /* apparently the "standard" is that clients close - * idle connections after 5 minutes, servers after - * 6 minutes - * http://www.connectathon.org/talks96/nfstcp.pdf - */ - if (get_seconds() - svsk->sk_lastrecv < 6*60 - || test_bit(SK_BUSY, &svsk->sk_flags)) - svsk = NULL; - } - if (svsk) { - set_bit(SK_BUSY, &svsk->sk_flags); - set_bit(SK_CLOSE, &svsk->sk_flags); - rqstp->rq_sock = svsk; - svsk->sk_inuse++; - } else if ((svsk = svc_sock_dequeue(serv)) != NULL) { + if ((svsk = svc_sock_dequeue(serv)) != NULL) { rqstp->rq_sock = svsk; svsk->sk_inuse++; rqstp->rq_reserved = serv->sv_bufsz; @@ -1282,13 +1272,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout) return -EAGAIN; } svsk->sk_lastrecv = get_seconds(); - if (test_bit(SK_TEMP, &svsk->sk_flags)) { - /* push active sockets to end of list */ - spin_lock_bh(&serv->sv_lock); - if (!list_empty(&svsk->sk_list)) - list_move_tail(&svsk->sk_list, &serv->sv_tempsocks); - spin_unlock_bh(&serv->sv_lock); - } + clear_bit(SK_OLD, &svsk->sk_flags); rqstp->rq_secure = ntohs(rqstp->rq_addr.sin_port) < 1024; rqstp->rq_chandle.defer = svc_defer; @@ -1347,6 +1331,58 @@ svc_send(struct svc_rqst *rqstp) return len; } +/* + * Timer function to close old temporary sockets, using + * a mark-and-sweep algorithm. + */ +static void +svc_age_temp_sockets(unsigned long closure) +{ + struct svc_serv *serv = (struct svc_serv *)closure; + struct svc_sock *svsk; + struct list_head *le, *next; + LIST_HEAD(to_be_aged); + + dprintk("svc_age_temp_sockets\n"); + + if (!spin_trylock_bh(&serv->sv_lock)) { + /* busy, try again 1 sec later */ + dprintk("svc_age_temp_sockets: busy\n"); + mod_timer(&serv->sv_temptimer, jiffies + HZ); + return; + } + + list_for_each_safe(le, next, &serv->sv_tempsocks) { + svsk = list_entry(le, struct svc_sock, sk_list); + + if (!test_and_set_bit(SK_OLD, &svsk->sk_flags)) + continue; + if (svsk->sk_inuse || test_bit(SK_BUSY, &svsk->sk_flags)) + continue; + svsk->sk_inuse++; + list_move(le, &to_be_aged); + set_bit(SK_CLOSE, &svsk->sk_flags); + set_bit(SK_DETACHED, &svsk->sk_flags); + } + spin_unlock_bh(&serv->sv_lock); + + while (!list_empty(&to_be_aged)) { + le = to_be_aged.next; + /* fiddling the sk_list node is safe 'cos we're SK_DETACHED */ + list_del_init(le); + svsk = list_entry(le, struct svc_sock, sk_list); + + dprintk("queuing svsk %p for closing, %lu seconds old\n", + svsk, get_seconds() - svsk->sk_lastrecv); + + /* a thread will dequeue and close it soon */ + svc_sock_enqueue(svsk); + svc_sock_put(svsk); + } + + mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); +} + /* * Initialize socket for RPC use and create svc_sock struct * XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF. @@ -1400,6 +1436,13 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, set_bit(SK_TEMP, &svsk->sk_flags); list_add(&svsk->sk_list, &serv->sv_tempsocks); serv->sv_tmpcnt++; + if (serv->sv_temptimer.function == NULL) { + /* setup timer to age temp sockets */ + setup_timer(&serv->sv_temptimer, svc_age_temp_sockets, + (unsigned long)serv); + mod_timer(&serv->sv_temptimer, + jiffies + svc_conn_age_period * HZ); + } } else { clear_bit(SK_TEMP, &svsk->sk_flags); list_add(&svsk->sk_list, &serv->sv_permsocks); @@ -1513,7 +1556,8 @@ svc_delete_socket(struct svc_sock *svsk) spin_lock_bh(&serv->sv_lock); - list_del_init(&svsk->sk_list); + if (!test_and_set_bit(SK_DETACHED, &svsk->sk_flags)) + list_del_init(&svsk->sk_list); list_del_init(&svsk->sk_ready); if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) if (test_bit(SK_TEMP, &svsk->sk_flags)) -- cgit v1.2.3 From c45c357d7dbc9e94338f44349e0035149da86b26 Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Mon, 2 Oct 2006 02:17:54 -0700 Subject: [PATCH] knfsd: convert sk_inuse to atomic_t Convert the svc_sock->sk_inuse counter from an int protected by svc_serv->sv_lock, to an atomic. This reduces the number of places we need to take the (effectively global) svc_serv->sv_lock. Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/svcsock.h | 2 +- net/sunrpc/svcsock.c | 29 +++++++++++------------------ 2 files changed, 12 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 846aee95eec7..17cb834a748c 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -21,7 +21,7 @@ struct svc_sock { struct sock * sk_sk; /* INET layer */ struct svc_serv * sk_server; /* service for this socket */ - unsigned int sk_inuse; /* use count */ + atomic_t sk_inuse; /* use count */ unsigned long sk_flags; #define SK_BUSY 0 /* enqueued/receiving */ #define SK_CONN 1 /* conn pending */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 9ba1a071ff06..d836031e4581 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -206,7 +206,7 @@ svc_sock_enqueue(struct svc_sock *svsk) "svc_sock_enqueue: server %p, rq_sock=%p!\n", rqstp, rqstp->rq_sock); rqstp->rq_sock = svsk; - svsk->sk_inuse++; + atomic_inc(&svsk->sk_inuse); rqstp->rq_reserved = serv->sv_bufsz; svsk->sk_reserved += rqstp->rq_reserved; wake_up(&rqstp->rq_wait); @@ -235,7 +235,7 @@ svc_sock_dequeue(struct svc_serv *serv) list_del_init(&svsk->sk_ready); dprintk("svc: socket %p dequeued, inuse=%d\n", - svsk->sk_sk, svsk->sk_inuse); + svsk->sk_sk, atomic_read(&svsk->sk_inuse)); return svsk; } @@ -285,17 +285,11 @@ void svc_reserve(struct svc_rqst *rqstp, int space) static inline void svc_sock_put(struct svc_sock *svsk) { - struct svc_serv *serv = svsk->sk_server; - - spin_lock_bh(&serv->sv_lock); - if (!--(svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) { - spin_unlock_bh(&serv->sv_lock); + if (atomic_dec_and_test(&svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) { dprintk("svc: releasing dead socket\n"); sock_release(svsk->sk_sock); kfree(svsk); } - else - spin_unlock_bh(&serv->sv_lock); } static void @@ -897,7 +891,7 @@ svc_tcp_accept(struct svc_sock *svsk) struct svc_sock, sk_list); set_bit(SK_CLOSE, &svsk->sk_flags); - svsk->sk_inuse ++; + atomic_inc(&svsk->sk_inuse); } spin_unlock_bh(&serv->sv_lock); @@ -1229,7 +1223,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout) spin_lock_bh(&serv->sv_lock); if ((svsk = svc_sock_dequeue(serv)) != NULL) { rqstp->rq_sock = svsk; - svsk->sk_inuse++; + atomic_inc(&svsk->sk_inuse); rqstp->rq_reserved = serv->sv_bufsz; svsk->sk_reserved += rqstp->rq_reserved; } else { @@ -1261,7 +1255,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout) spin_unlock_bh(&serv->sv_lock); dprintk("svc: server %p, socket %p, inuse=%d\n", - rqstp, svsk, svsk->sk_inuse); + rqstp, svsk, atomic_read(&svsk->sk_inuse)); len = svsk->sk_recvfrom(rqstp); dprintk("svc: got len=%d\n", len); @@ -1357,9 +1351,9 @@ svc_age_temp_sockets(unsigned long closure) if (!test_and_set_bit(SK_OLD, &svsk->sk_flags)) continue; - if (svsk->sk_inuse || test_bit(SK_BUSY, &svsk->sk_flags)) + if (atomic_read(&svsk->sk_inuse) || test_bit(SK_BUSY, &svsk->sk_flags)) continue; - svsk->sk_inuse++; + atomic_inc(&svsk->sk_inuse); list_move(le, &to_be_aged); set_bit(SK_CLOSE, &svsk->sk_flags); set_bit(SK_DETACHED, &svsk->sk_flags); @@ -1420,6 +1414,7 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, svsk->sk_odata = inet->sk_data_ready; svsk->sk_owspace = inet->sk_write_space; svsk->sk_server = serv; + atomic_set(&svsk->sk_inuse, 0); svsk->sk_lastrecv = get_seconds(); INIT_LIST_HEAD(&svsk->sk_deferred); INIT_LIST_HEAD(&svsk->sk_ready); @@ -1563,7 +1558,7 @@ svc_delete_socket(struct svc_sock *svsk) if (test_bit(SK_TEMP, &svsk->sk_flags)) serv->sv_tmpcnt--; - if (!svsk->sk_inuse) { + if (!atomic_read(&svsk->sk_inuse)) { spin_unlock_bh(&serv->sv_lock); if (svsk->sk_sock->file) sockfd_put(svsk->sk_sock); @@ -1644,10 +1639,8 @@ svc_defer(struct cache_req *req) dr->argslen = rqstp->rq_arg.len >> 2; memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, dr->argslen<<2); } - spin_lock_bh(&rqstp->rq_server->sv_lock); - rqstp->rq_sock->sk_inuse++; + atomic_inc(&rqstp->rq_sock->sk_inuse); dr->svsk = rqstp->rq_sock; - spin_unlock_bh(&rqstp->rq_server->sv_lock); dr->handle.revisit = svc_revisit; return &dr->handle; -- cgit v1.2.3 From 1a68d952af5f43032012d26dd0d5164c9e9986bc Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Mon, 2 Oct 2006 02:17:55 -0700 Subject: [PATCH] knfsd: use new lock for svc_sock deferred list Protect the svc_sock->sk_deferred list with a new lock svc_sock->sk_defer_lock instead of svc_serv->sv_lock. Using the more fine-grained lock reduces the number of places we need to take the svc_serv lock. Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/svcsock.h | 1 + net/sunrpc/svcsock.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 17cb834a748c..7766a1001660 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -36,6 +36,7 @@ struct svc_sock { int sk_reserved; /* space on outq that is reserved */ + spinlock_t sk_defer_lock; /* protects sk_deferred */ struct list_head sk_deferred; /* deferred requests that need to * be revisted */ struct mutex sk_mutex; /* to serialize sending data */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index d836031e4581..bdb5c2841db7 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -47,6 +47,7 @@ /* SMP locking strategy: * * svc_serv->sv_lock protects most stuff for that service. + * svc_sock->sk_defer_lock protects the svc_sock->sk_deferred list * * Some flags can be set to certain values at any time * providing that certain rules are followed: @@ -1416,6 +1417,7 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, svsk->sk_server = serv; atomic_set(&svsk->sk_inuse, 0); svsk->sk_lastrecv = get_seconds(); + spin_lock_init(&svsk->sk_defer_lock); INIT_LIST_HEAD(&svsk->sk_deferred); INIT_LIST_HEAD(&svsk->sk_ready); mutex_init(&svsk->sk_mutex); @@ -1594,7 +1596,6 @@ svc_makesock(struct svc_serv *serv, int protocol, unsigned short port) static void svc_revisit(struct cache_deferred_req *dreq, int too_many) { struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle); - struct svc_serv *serv = dreq->owner; struct svc_sock *svsk; if (too_many) { @@ -1605,9 +1606,9 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many) dprintk("revisit queued\n"); svsk = dr->svsk; dr->svsk = NULL; - spin_lock_bh(&serv->sv_lock); + spin_lock_bh(&svsk->sk_defer_lock); list_add(&dr->handle.recent, &svsk->sk_deferred); - spin_unlock_bh(&serv->sv_lock); + spin_unlock_bh(&svsk->sk_defer_lock); set_bit(SK_DEFERRED, &svsk->sk_flags); svc_sock_enqueue(svsk); svc_sock_put(svsk); @@ -1667,11 +1668,10 @@ static int svc_deferred_recv(struct svc_rqst *rqstp) static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk) { struct svc_deferred_req *dr = NULL; - struct svc_serv *serv = svsk->sk_server; if (!test_bit(SK_DEFERRED, &svsk->sk_flags)) return NULL; - spin_lock_bh(&serv->sv_lock); + spin_lock_bh(&svsk->sk_defer_lock); clear_bit(SK_DEFERRED, &svsk->sk_flags); if (!list_empty(&svsk->sk_deferred)) { dr = list_entry(svsk->sk_deferred.next, @@ -1680,6 +1680,6 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk) list_del_init(&dr->handle.recent); set_bit(SK_DEFERRED, &svsk->sk_flags); } - spin_unlock_bh(&serv->sv_lock); + spin_unlock_bh(&svsk->sk_defer_lock); return dr; } -- cgit v1.2.3 From 5685f0fa1c24b138d041ef129ed419c5effa40e1 Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Mon, 2 Oct 2006 02:17:56 -0700 Subject: [PATCH] knfsd: convert sk_reserved to atomic_t Convert the svc_sock->sk_reserved variable from an int protected by svc_serv->sv_lock, to an atomic. This reduces (by 1) the number of places we need to take the (effectively global) svc_serv->sv_lock. Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/svcsock.h | 2 +- net/sunrpc/svcsock.c | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 7766a1001660..7154e71c6d1f 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -34,7 +34,7 @@ struct svc_sock { #define SK_OLD 9 /* used for temp socket aging mark+sweep */ #define SK_DETACHED 10 /* detached from tempsocks list */ - int sk_reserved; /* space on outq that is reserved */ + atomic_t sk_reserved; /* space on outq that is reserved */ spinlock_t sk_defer_lock; /* protects sk_deferred */ struct list_head sk_deferred; /* deferred requests that need to diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index bdb5c2841db7..88b51c4ecb8b 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -177,13 +177,13 @@ svc_sock_enqueue(struct svc_sock *svsk) } set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); - if (((svsk->sk_reserved + serv->sv_bufsz)*2 + if (((atomic_read(&svsk->sk_reserved) + serv->sv_bufsz)*2 > svc_sock_wspace(svsk)) && !test_bit(SK_CLOSE, &svsk->sk_flags) && !test_bit(SK_CONN, &svsk->sk_flags)) { /* Don't enqueue while not enough space for reply */ dprintk("svc: socket %p no space, %d*2 > %ld, not enqueued\n", - svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz, + svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_bufsz, svc_sock_wspace(svsk)); goto out_unlock; } @@ -209,7 +209,7 @@ svc_sock_enqueue(struct svc_sock *svsk) rqstp->rq_sock = svsk; atomic_inc(&svsk->sk_inuse); rqstp->rq_reserved = serv->sv_bufsz; - svsk->sk_reserved += rqstp->rq_reserved; + atomic_add(rqstp->rq_reserved, &svsk->sk_reserved); wake_up(&rqstp->rq_wait); } else { dprintk("svc: socket %p put into queue\n", svsk->sk_sk); @@ -271,10 +271,8 @@ void svc_reserve(struct svc_rqst *rqstp, int space) if (space < rqstp->rq_reserved) { struct svc_sock *svsk = rqstp->rq_sock; - spin_lock_bh(&svsk->sk_server->sv_lock); - svsk->sk_reserved -= (rqstp->rq_reserved - space); + atomic_sub((rqstp->rq_reserved - space), &svsk->sk_reserved); rqstp->rq_reserved = space; - spin_unlock_bh(&svsk->sk_server->sv_lock); svc_sock_enqueue(svsk); } @@ -1226,7 +1224,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout) rqstp->rq_sock = svsk; atomic_inc(&svsk->sk_inuse); rqstp->rq_reserved = serv->sv_bufsz; - svsk->sk_reserved += rqstp->rq_reserved; + atomic_add(rqstp->rq_reserved, &svsk->sk_reserved); } else { /* No data pending. Go to sleep */ svc_serv_enqueue(serv, rqstp); -- cgit v1.2.3 From 3262c816a3d7fb1eaabce633caa317887ed549ae Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Mon, 2 Oct 2006 02:17:58 -0700 Subject: [PATCH] knfsd: split svc_serv into pools Split out the list of idle threads and pending sockets from svc_serv into a new svc_pool structure, and allocate a fixed number (in this patch, 1) of pools per svc_serv. The new structure contains a lock which takes over several of the duties of svc_serv->sv_lock, which is now relegated to protecting only sv_tempsocks, sv_permsocks, and sv_tmpcnt in svc_serv. The point is to move the hottest fields out of svc_serv and into svc_pool, allowing a following patch to arrange for a svc_pool per NUMA node or per CPU. This is a major step towards making the NFS server NUMA-friendly. Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/svc.h | 25 ++++++++- include/linux/sunrpc/svcsock.h | 1 + net/sunrpc/svc.c | 56 +++++++++++++++--- net/sunrpc/svcsock.c | 125 ++++++++++++++++++++++++++--------------- 4 files changed, 153 insertions(+), 54 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 5eabded11061..c27d806af310 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -17,6 +17,25 @@ #include #include + +/* + * + * RPC service thread pool. + * + * Pool of threads and temporary sockets. Generally there is only + * a single one of these per RPC service, but on NUMA machines those + * services that can benefit from it (i.e. nfs but not lockd) will + * have one pool per NUMA node. This optimisation reduces cross- + * node traffic on multi-node NUMA NFS servers. + */ +struct svc_pool { + unsigned int sp_id; /* pool id; also node id on NUMA */ + spinlock_t sp_lock; /* protects all fields */ + struct list_head sp_threads; /* idle server threads */ + struct list_head sp_sockets; /* pending sockets */ + unsigned int sp_nrthreads; /* # of threads in pool */ +} ____cacheline_aligned_in_smp; + /* * RPC service. * @@ -28,8 +47,6 @@ * We currently do not support more than one RPC program per daemon. */ struct svc_serv { - struct list_head sv_threads; /* idle server threads */ - struct list_head sv_sockets; /* pending sockets */ struct svc_program * sv_program; /* RPC program */ struct svc_stat * sv_stats; /* RPC statistics */ spinlock_t sv_lock; @@ -44,6 +61,9 @@ struct svc_serv { char * sv_name; /* service name */ + unsigned int sv_nrpools; /* number of thread pools */ + struct svc_pool * sv_pools; /* array of thread pools */ + void (*sv_shutdown)(struct svc_serv *serv); /* Callback to use when last thread * exits. @@ -138,6 +158,7 @@ struct svc_rqst { int rq_addrlen; struct svc_serv * rq_server; /* RPC service definition */ + struct svc_pool * rq_pool; /* thread pool */ struct svc_procedure * rq_procinfo; /* procedure info */ struct auth_ops * rq_authop; /* authentication flavour */ struct svc_cred rq_cred; /* auth info */ diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 7154e71c6d1f..4c296152cbfa 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -20,6 +20,7 @@ struct svc_sock { struct socket * sk_sock; /* berkeley socket layer */ struct sock * sk_sk; /* INET layer */ + struct svc_pool * sk_pool; /* current pool iff queued */ struct svc_serv * sk_server; /* service for this socket */ atomic_t sk_inuse; /* use count */ unsigned long sk_flags; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 0c2c52276285..6750cd474f84 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -32,6 +32,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize, struct svc_serv *serv; int vers; unsigned int xdrsize; + unsigned int i; if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) return NULL; @@ -55,13 +56,33 @@ svc_create(struct svc_program *prog, unsigned int bufsize, prog = prog->pg_next; } serv->sv_xdrsize = xdrsize; - INIT_LIST_HEAD(&serv->sv_threads); - INIT_LIST_HEAD(&serv->sv_sockets); INIT_LIST_HEAD(&serv->sv_tempsocks); INIT_LIST_HEAD(&serv->sv_permsocks); init_timer(&serv->sv_temptimer); spin_lock_init(&serv->sv_lock); + serv->sv_nrpools = 1; + serv->sv_pools = + kcalloc(sizeof(struct svc_pool), serv->sv_nrpools, + GFP_KERNEL); + if (!serv->sv_pools) { + kfree(serv); + return NULL; + } + + for (i = 0; i < serv->sv_nrpools; i++) { + struct svc_pool *pool = &serv->sv_pools[i]; + + dprintk("initialising pool %u for %s\n", + i, serv->sv_name); + + pool->sp_id = i; + INIT_LIST_HEAD(&pool->sp_threads); + INIT_LIST_HEAD(&pool->sp_sockets); + spin_lock_init(&pool->sp_lock); + } + + /* Remove any stale portmap registrations */ svc_register(serv, 0, 0); @@ -69,7 +90,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize, } /* - * Destroy an RPC service + * Destroy an RPC service. Should be called with the BKL held */ void svc_destroy(struct svc_serv *serv) @@ -110,6 +131,7 @@ svc_destroy(struct svc_serv *serv) /* Unregister service with the portmapper */ svc_register(serv, 0, 0); + kfree(serv->sv_pools); kfree(serv); } @@ -158,10 +180,11 @@ svc_release_buffer(struct svc_rqst *rqstp) } /* - * Create a server thread + * Create a thread in the given pool. Caller must hold BKL. */ -int -svc_create_thread(svc_thread_fn func, struct svc_serv *serv) +static int +__svc_create_thread(svc_thread_fn func, struct svc_serv *serv, + struct svc_pool *pool) { struct svc_rqst *rqstp; int error = -ENOMEM; @@ -178,7 +201,11 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv) goto out_thread; serv->sv_nrthreads++; + spin_lock_bh(&pool->sp_lock); + pool->sp_nrthreads++; + spin_unlock_bh(&pool->sp_lock); rqstp->rq_server = serv; + rqstp->rq_pool = pool; error = kernel_thread((int (*)(void *)) func, rqstp, 0); if (error < 0) goto out_thread; @@ -193,17 +220,32 @@ out_thread: } /* - * Destroy an RPC server thread + * Create a thread in the default pool. Caller must hold BKL. + */ +int +svc_create_thread(svc_thread_fn func, struct svc_serv *serv) +{ + return __svc_create_thread(func, serv, &serv->sv_pools[0]); +} + +/* + * Called from a server thread as it's exiting. Caller must hold BKL. */ void svc_exit_thread(struct svc_rqst *rqstp) { struct svc_serv *serv = rqstp->rq_server; + struct svc_pool *pool = rqstp->rq_pool; svc_release_buffer(rqstp); kfree(rqstp->rq_resp); kfree(rqstp->rq_argp); kfree(rqstp->rq_auth_data); + + spin_lock_bh(&pool->sp_lock); + pool->sp_nrthreads--; + spin_unlock_bh(&pool->sp_lock); + kfree(rqstp); /* Release the server */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index a38df4589ae9..b78659adeff3 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -46,7 +46,10 @@ /* SMP locking strategy: * - * svc_serv->sv_lock protects most stuff for that service. + * svc_pool->sp_lock protects most of the fields of that pool. + * svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt. + * when both need to be taken (rare), svc_serv->sv_lock is first. + * BKL protects svc_serv->sv_nrthread. * svc_sock->sk_defer_lock protects the svc_sock->sk_deferred list * svc_sock->sk_flags.SK_BUSY prevents a svc_sock being enqueued multiply. * @@ -82,22 +85,22 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req); static int svc_conn_age_period = 6*60; /* - * Queue up an idle server thread. Must have serv->sv_lock held. + * Queue up an idle server thread. Must have pool->sp_lock held. * Note: this is really a stack rather than a queue, so that we only - * use as many different threads as we need, and the rest don't polute + * use as many different threads as we need, and the rest don't pollute * the cache. */ static inline void -svc_serv_enqueue(struct svc_serv *serv, struct svc_rqst *rqstp) +svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp) { - list_add(&rqstp->rq_list, &serv->sv_threads); + list_add(&rqstp->rq_list, &pool->sp_threads); } /* - * Dequeue an nfsd thread. Must have serv->sv_lock held. + * Dequeue an nfsd thread. Must have pool->sp_lock held. */ static inline void -svc_serv_dequeue(struct svc_serv *serv, struct svc_rqst *rqstp) +svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp) { list_del(&rqstp->rq_list); } @@ -148,6 +151,7 @@ static void svc_sock_enqueue(struct svc_sock *svsk) { struct svc_serv *serv = svsk->sk_server; + struct svc_pool *pool = &serv->sv_pools[0]; struct svc_rqst *rqstp; if (!(svsk->sk_flags & @@ -156,10 +160,10 @@ svc_sock_enqueue(struct svc_sock *svsk) if (test_bit(SK_DEAD, &svsk->sk_flags)) return; - spin_lock_bh(&serv->sv_lock); + spin_lock_bh(&pool->sp_lock); - if (!list_empty(&serv->sv_threads) && - !list_empty(&serv->sv_sockets)) + if (!list_empty(&pool->sp_threads) && + !list_empty(&pool->sp_sockets)) printk(KERN_ERR "svc_sock_enqueue: threads and sockets both waiting??\n"); @@ -179,6 +183,8 @@ svc_sock_enqueue(struct svc_sock *svsk) dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk); goto out_unlock; } + BUG_ON(svsk->sk_pool != NULL); + svsk->sk_pool = pool; set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); if (((atomic_read(&svsk->sk_reserved) + serv->sv_bufsz)*2 @@ -189,19 +195,20 @@ svc_sock_enqueue(struct svc_sock *svsk) dprintk("svc: socket %p no space, %d*2 > %ld, not enqueued\n", svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_bufsz, svc_sock_wspace(svsk)); + svsk->sk_pool = NULL; clear_bit(SK_BUSY, &svsk->sk_flags); goto out_unlock; } clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); - if (!list_empty(&serv->sv_threads)) { - rqstp = list_entry(serv->sv_threads.next, + if (!list_empty(&pool->sp_threads)) { + rqstp = list_entry(pool->sp_threads.next, struct svc_rqst, rq_list); dprintk("svc: socket %p served by daemon %p\n", svsk->sk_sk, rqstp); - svc_serv_dequeue(serv, rqstp); + svc_thread_dequeue(pool, rqstp); if (rqstp->rq_sock) printk(KERN_ERR "svc_sock_enqueue: server %p, rq_sock=%p!\n", @@ -210,28 +217,30 @@ svc_sock_enqueue(struct svc_sock *svsk) atomic_inc(&svsk->sk_inuse); rqstp->rq_reserved = serv->sv_bufsz; atomic_add(rqstp->rq_reserved, &svsk->sk_reserved); + BUG_ON(svsk->sk_pool != pool); wake_up(&rqstp->rq_wait); } else { dprintk("svc: socket %p put into queue\n", svsk->sk_sk); - list_add_tail(&svsk->sk_ready, &serv->sv_sockets); + list_add_tail(&svsk->sk_ready, &pool->sp_sockets); + BUG_ON(svsk->sk_pool != pool); } out_unlock: - spin_unlock_bh(&serv->sv_lock); + spin_unlock_bh(&pool->sp_lock); } /* - * Dequeue the first socket. Must be called with the serv->sv_lock held. + * Dequeue the first socket. Must be called with the pool->sp_lock held. */ static inline struct svc_sock * -svc_sock_dequeue(struct svc_serv *serv) +svc_sock_dequeue(struct svc_pool *pool) { struct svc_sock *svsk; - if (list_empty(&serv->sv_sockets)) + if (list_empty(&pool->sp_sockets)) return NULL; - svsk = list_entry(serv->sv_sockets.next, + svsk = list_entry(pool->sp_sockets.next, struct svc_sock, sk_ready); list_del_init(&svsk->sk_ready); @@ -250,6 +259,7 @@ svc_sock_dequeue(struct svc_serv *serv) static inline void svc_sock_received(struct svc_sock *svsk) { + svsk->sk_pool = NULL; clear_bit(SK_BUSY, &svsk->sk_flags); svc_sock_enqueue(svsk); } @@ -322,25 +332,33 @@ svc_sock_release(struct svc_rqst *rqstp) /* * External function to wake up a server waiting for data + * This really only makes sense for services like lockd + * which have exactly one thread anyway. */ void svc_wake_up(struct svc_serv *serv) { struct svc_rqst *rqstp; - - spin_lock_bh(&serv->sv_lock); - if (!list_empty(&serv->sv_threads)) { - rqstp = list_entry(serv->sv_threads.next, - struct svc_rqst, - rq_list); - dprintk("svc: daemon %p woken up.\n", rqstp); - /* - svc_serv_dequeue(serv, rqstp); - rqstp->rq_sock = NULL; - */ - wake_up(&rqstp->rq_wait); + unsigned int i; + struct svc_pool *pool; + + for (i = 0; i < serv->sv_nrpools; i++) { + pool = &serv->sv_pools[i]; + + spin_lock_bh(&pool->sp_lock); + if (!list_empty(&pool->sp_threads)) { + rqstp = list_entry(pool->sp_threads.next, + struct svc_rqst, + rq_list); + dprintk("svc: daemon %p woken up.\n", rqstp); + /* + svc_thread_dequeue(pool, rqstp); + rqstp->rq_sock = NULL; + */ + wake_up(&rqstp->rq_wait); + } + spin_unlock_bh(&pool->sp_lock); } - spin_unlock_bh(&serv->sv_lock); } /* @@ -603,7 +621,10 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) /* udp sockets need large rcvbuf as all pending * requests are still in that buffer. sndbuf must * also be large enough that there is enough space - * for one reply per thread. + * for one reply per thread. We count all threads + * rather than threads in a particular pool, which + * provides an upper bound on the number of threads + * which will access the socket. */ svc_sock_setbufsize(svsk->sk_sock, (serv->sv_nrthreads+3) * serv->sv_bufsz, @@ -948,6 +969,11 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp) /* sndbuf needs to have room for one request * per thread, otherwise we can stall even when the * network isn't a bottleneck. + * + * We count all threads rather than threads in a + * particular pool, which provides an upper bound + * on the number of threads which will access the socket. + * * rcvbuf just needs to be able to hold a few requests. * Normally they will be removed from the queue * as soon a a complete request arrives. @@ -1163,13 +1189,16 @@ svc_sock_update_bufs(struct svc_serv *serv) } /* - * Receive the next request on any socket. + * Receive the next request on any socket. This code is carefully + * organised not to touch any cachelines in the shared svc_serv + * structure, only cachelines in the local svc_pool. */ int svc_recv(struct svc_rqst *rqstp, long timeout) { struct svc_sock *svsk =NULL; struct svc_serv *serv = rqstp->rq_server; + struct svc_pool *pool = rqstp->rq_pool; int len; int pages; struct xdr_buf *arg; @@ -1219,15 +1248,15 @@ svc_recv(struct svc_rqst *rqstp, long timeout) if (signalled()) return -EINTR; - spin_lock_bh(&serv->sv_lock); - if ((svsk = svc_sock_dequeue(serv)) != NULL) { + spin_lock_bh(&pool->sp_lock); + if ((svsk = svc_sock_dequeue(pool)) != NULL) { rqstp->rq_sock = svsk; atomic_inc(&svsk->sk_inuse); rqstp->rq_reserved = serv->sv_bufsz; atomic_add(rqstp->rq_reserved, &svsk->sk_reserved); } else { /* No data pending. Go to sleep */ - svc_serv_enqueue(serv, rqstp); + svc_thread_enqueue(pool, rqstp); /* * We have to be able to interrupt this wait @@ -1235,26 +1264,26 @@ svc_recv(struct svc_rqst *rqstp, long timeout) */ set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&rqstp->rq_wait, &wait); - spin_unlock_bh(&serv->sv_lock); + spin_unlock_bh(&pool->sp_lock); schedule_timeout(timeout); try_to_freeze(); - spin_lock_bh(&serv->sv_lock); + spin_lock_bh(&pool->sp_lock); remove_wait_queue(&rqstp->rq_wait, &wait); if (!(svsk = rqstp->rq_sock)) { - svc_serv_dequeue(serv, rqstp); - spin_unlock_bh(&serv->sv_lock); + svc_thread_dequeue(pool, rqstp); + spin_unlock_bh(&pool->sp_lock); dprintk("svc: server %p, no data yet\n", rqstp); return signalled()? -EINTR : -EAGAIN; } } - spin_unlock_bh(&serv->sv_lock); + spin_unlock_bh(&pool->sp_lock); - dprintk("svc: server %p, socket %p, inuse=%d\n", - rqstp, svsk, atomic_read(&svsk->sk_inuse)); + dprintk("svc: server %p, pool %u, socket %p, inuse=%d\n", + rqstp, pool->sp_id, svsk, atomic_read(&svsk->sk_inuse)); len = svsk->sk_recvfrom(rqstp); dprintk("svc: got len=%d\n", len); @@ -1553,7 +1582,13 @@ svc_delete_socket(struct svc_sock *svsk) if (!test_and_set_bit(SK_DETACHED, &svsk->sk_flags)) list_del_init(&svsk->sk_list); - list_del_init(&svsk->sk_ready); + /* + * We used to delete the svc_sock from whichever list + * it's sk_ready node was on, but we don't actually + * need to. This is because the only time we're called + * while still attached to a queue, the queue itself + * is about to be destroyed (in svc_destroy). + */ if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) if (test_bit(SK_TEMP, &svsk->sk_flags)) serv->sv_tmpcnt--; -- cgit v1.2.3 From 9a24ab5749a31aa10ee60d9310ad72f24d7c38ab Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Mon, 2 Oct 2006 02:17:58 -0700 Subject: [PATCH] knfsd: add svc_get add svc_get() for those occasions when we need to temporarily bump up svc_serv->sv_nrthreads as a pseudo refcount. Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfssvc.c | 2 +- include/linux/sunrpc/svc.h | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index cdec3993e0d5..9773f593b3ff 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -200,7 +200,7 @@ int nfsd_create_serv(void) int err = 0; lock_kernel(); if (nfsd_serv) { - nfsd_serv->sv_nrthreads++; + svc_get(nfsd_serv); unlock_kernel(); return 0; } diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index c27d806af310..54d8e7bc2341 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -70,6 +70,17 @@ struct svc_serv { */ }; +/* + * We use sv_nrthreads as a reference count. svc_destroy() drops + * this refcount, so we need to bump it up around operations that + * change the number of threads. Horrible, but there it is. + * Should be called with the BKL held. + */ +static inline void svc_get(struct svc_serv *serv) +{ + serv->sv_nrthreads++; +} + /* * Maximum payload size supported by a kernel RPC server. * This is use to determine the max number of pages nfsd is -- cgit v1.2.3 From a74554429eada89a7ddb47317e6a2968d03e41a2 Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Mon, 2 Oct 2006 02:17:59 -0700 Subject: [PATCH] knfsd: add svc_set_num_threads Currently knfsd keeps its own list of all nfsd threads in nfssvc.c; add a new way of managing the list of all threads in a svc_serv. Add svc_create_pooled() to allow creation of a svc_serv whose threads are managed by the sunrpc code. Add svc_set_num_threads() to manage the number of threads in a service, either per-pool or globally across the service. Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/svc.h | 21 +++++-- net/sunrpc/sunrpc_syms.c | 2 + net/sunrpc/svc.c | 139 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 154 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 54d8e7bc2341..f2eeb833e7d8 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -17,6 +17,10 @@ #include #include +/* + * This is the RPC server thread function prototype + */ +typedef void (*svc_thread_fn)(struct svc_rqst *); /* * @@ -34,6 +38,7 @@ struct svc_pool { struct list_head sp_threads; /* idle server threads */ struct list_head sp_sockets; /* pending sockets */ unsigned int sp_nrthreads; /* # of threads in pool */ + struct list_head sp_all_threads; /* all server threads */ } ____cacheline_aligned_in_smp; /* @@ -68,6 +73,11 @@ struct svc_serv { /* Callback to use when last thread * exits. */ + + struct module * sv_module; /* optional module to count when + * adding threads */ + svc_thread_fn sv_function; /* main function for threads */ + int sv_kill_signal; /* signal to kill threads */ }; /* @@ -164,6 +174,7 @@ static inline void svc_putu32(struct kvec *iov, __be32 val) */ struct svc_rqst { struct list_head rq_list; /* idle list */ + struct list_head rq_all; /* all threads list */ struct svc_sock * rq_sock; /* socket */ struct sockaddr_in rq_addr; /* peer address */ int rq_addrlen; @@ -218,6 +229,7 @@ struct svc_rqst { * to prevent encrypting page * cache pages */ wait_queue_head_t rq_wait; /* synchronization */ + struct task_struct *rq_task; /* service thread */ }; /* @@ -358,11 +370,6 @@ struct svc_procedure { unsigned int pc_xdrressize; /* maximum size of XDR reply */ }; -/* - * This is the RPC server thread function prototype - */ -typedef void (*svc_thread_fn)(struct svc_rqst *); - /* * Function prototypes. */ @@ -370,6 +377,10 @@ struct svc_serv * svc_create(struct svc_program *, unsigned int, void (*shutdown)(struct svc_serv*)); int svc_create_thread(svc_thread_fn, struct svc_serv *); void svc_exit_thread(struct svc_rqst *); +struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, + void (*shutdown)(struct svc_serv*), + svc_thread_fn, int sig, struct module *); +int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); void svc_destroy(struct svc_serv *); int svc_process(struct svc_rqst *); int svc_register(struct svc_serv *, int, unsigned short); diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 26c0531d7e25..192dff5dabcb 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -70,6 +70,8 @@ EXPORT_SYMBOL(put_rpccred); /* RPC server stuff */ EXPORT_SYMBOL(svc_create); EXPORT_SYMBOL(svc_create_thread); +EXPORT_SYMBOL(svc_create_pooled); +EXPORT_SYMBOL(svc_set_num_threads); EXPORT_SYMBOL(svc_exit_thread); EXPORT_SYMBOL(svc_destroy); EXPORT_SYMBOL(svc_drop); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 6750cd474f84..8c75eec4fd6a 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -25,8 +27,8 @@ /* * Create an RPC service */ -struct svc_serv * -svc_create(struct svc_program *prog, unsigned int bufsize, +static struct svc_serv * +__svc_create(struct svc_program *prog, unsigned int bufsize, int npools, void (*shutdown)(struct svc_serv *serv)) { struct svc_serv *serv; @@ -61,7 +63,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize, init_timer(&serv->sv_temptimer); spin_lock_init(&serv->sv_lock); - serv->sv_nrpools = 1; + serv->sv_nrpools = npools; serv->sv_pools = kcalloc(sizeof(struct svc_pool), serv->sv_nrpools, GFP_KERNEL); @@ -79,6 +81,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize, pool->sp_id = i; INIT_LIST_HEAD(&pool->sp_threads); INIT_LIST_HEAD(&pool->sp_sockets); + INIT_LIST_HEAD(&pool->sp_all_threads); spin_lock_init(&pool->sp_lock); } @@ -89,6 +92,31 @@ svc_create(struct svc_program *prog, unsigned int bufsize, return serv; } +struct svc_serv * +svc_create(struct svc_program *prog, unsigned int bufsize, + void (*shutdown)(struct svc_serv *serv)) +{ + return __svc_create(prog, bufsize, /*npools*/1, shutdown); +} + +struct svc_serv * +svc_create_pooled(struct svc_program *prog, unsigned int bufsize, + void (*shutdown)(struct svc_serv *serv), + svc_thread_fn func, int sig, struct module *mod) +{ + struct svc_serv *serv; + + serv = __svc_create(prog, bufsize, /*npools*/1, shutdown); + + if (serv != NULL) { + serv->sv_function = func; + serv->sv_kill_signal = sig; + serv->sv_module = mod; + } + + return serv; +} + /* * Destroy an RPC service. Should be called with the BKL held */ @@ -203,6 +231,7 @@ __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, serv->sv_nrthreads++; spin_lock_bh(&pool->sp_lock); pool->sp_nrthreads++; + list_add(&rqstp->rq_all, &pool->sp_all_threads); spin_unlock_bh(&pool->sp_lock); rqstp->rq_server = serv; rqstp->rq_pool = pool; @@ -228,6 +257,109 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv) return __svc_create_thread(func, serv, &serv->sv_pools[0]); } +/* + * Choose a pool in which to create a new thread, for svc_set_num_threads + */ +static inline struct svc_pool * +choose_pool(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) +{ + if (pool != NULL) + return pool; + + return &serv->sv_pools[(*state)++ % serv->sv_nrpools]; +} + +/* + * Choose a thread to kill, for svc_set_num_threads + */ +static inline struct task_struct * +choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) +{ + unsigned int i; + struct task_struct *task = NULL; + + if (pool != NULL) { + spin_lock_bh(&pool->sp_lock); + } else { + /* choose a pool in round-robin fashion */ + for (i = 0; i < serv->sv_nrpools; i++) { + pool = &serv->sv_pools[--(*state) % serv->sv_nrpools]; + spin_lock_bh(&pool->sp_lock); + if (!list_empty(&pool->sp_all_threads)) + goto found_pool; + spin_unlock_bh(&pool->sp_lock); + } + return NULL; + } + +found_pool: + if (!list_empty(&pool->sp_all_threads)) { + struct svc_rqst *rqstp; + + /* + * Remove from the pool->sp_all_threads list + * so we don't try to kill it again. + */ + rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all); + list_del_init(&rqstp->rq_all); + task = rqstp->rq_task; + } + spin_unlock_bh(&pool->sp_lock); + + return task; +} + +/* + * Create or destroy enough new threads to make the number + * of threads the given number. If `pool' is non-NULL, applies + * only to threads in that pool, otherwise round-robins between + * all pools. Must be called with a svc_get() reference and + * the BKL held. + * + * Destroying threads relies on the service threads filling in + * rqstp->rq_task, which only the nfs ones do. Assumes the serv + * has been created using svc_create_pooled(). + * + * Based on code that used to be in nfsd_svc() but tweaked + * to be pool-aware. + */ +int +svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) +{ + struct task_struct *victim; + int error = 0; + unsigned int state = serv->sv_nrthreads-1; + + if (pool == NULL) { + /* The -1 assumes caller has done a svc_get() */ + nrservs -= (serv->sv_nrthreads-1); + } else { + spin_lock_bh(&pool->sp_lock); + nrservs -= pool->sp_nrthreads; + spin_unlock_bh(&pool->sp_lock); + } + + /* create new threads */ + while (nrservs > 0) { + nrservs--; + __module_get(serv->sv_module); + error = __svc_create_thread(serv->sv_function, serv, + choose_pool(serv, pool, &state)); + if (error < 0) { + module_put(serv->sv_module); + break; + } + } + /* destroy old threads */ + while (nrservs < 0 && + (victim = choose_victim(serv, pool, &state)) != NULL) { + send_sig(serv->sv_kill_signal, victim, 1); + nrservs++; + } + + return error; +} + /* * Called from a server thread as it's exiting. Caller must hold BKL. */ @@ -244,6 +376,7 @@ svc_exit_thread(struct svc_rqst *rqstp) spin_lock_bh(&pool->sp_lock); pool->sp_nrthreads--; + list_del(&rqstp->rq_all); spin_unlock_bh(&pool->sp_lock); kfree(rqstp); -- cgit v1.2.3 From bfd241600a3b0db4fe43c859f1460d0a958d924a Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Mon, 2 Oct 2006 02:18:01 -0700 Subject: [PATCH] knfsd: make rpc threads pools numa aware Actually implement multiple pools. On NUMA machines, allocate a svc_pool per NUMA node; on SMP a svc_pool per CPU; otherwise a single global pool. Enqueue sockets on the svc_pool corresponding to the CPU on which the socket bh is run (i.e. the NIC interrupt CPU). Threads have their cpu mask set to limit them to the CPUs in the svc_pool that owns them. This is the patch that allows an Altix to scale NFS traffic linearly beyond 4 CPUs and 4 NICs. Incorporates changes and feedback from Neil Brown, Trond Myklebust, and Christoph Hellwig. Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/svc.h | 1 + net/sunrpc/svc.c | 255 ++++++++++++++++++++++++++++++++++++++++++++- net/sunrpc/svcsock.c | 7 +- 3 files changed, 261 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index f2eeb833e7d8..4ebcdf91f3b3 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -386,5 +386,6 @@ int svc_process(struct svc_rqst *); int svc_register(struct svc_serv *, int, unsigned short); void svc_wake_up(struct svc_serv *); void svc_reserve(struct svc_rqst *rqstp, int space); +struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu); #endif /* SUNRPC_SVC_H */ diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 8c75eec4fd6a..a99e67b164c1 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -4,6 +4,10 @@ * High-level RPC service routines * * Copyright (C) 1995, 1996 Olaf Kirch + * + * Multiple threads pools and NUMAisation + * Copyright (c) 2006 Silicon Graphics, Inc. + * by Greg Banks */ #include @@ -24,6 +28,242 @@ #define RPCDBG_FACILITY RPCDBG_SVCDSP #define RPC_PARANOIA 1 +/* + * Mode for mapping cpus to pools. + */ +enum { + SVC_POOL_NONE = -1, /* uninitialised, choose one of the others */ + SVC_POOL_GLOBAL, /* no mapping, just a single global pool + * (legacy & UP mode) */ + SVC_POOL_PERCPU, /* one pool per cpu */ + SVC_POOL_PERNODE /* one pool per numa node */ +}; + +/* + * Structure for mapping cpus to pools and vice versa. + * Setup once during sunrpc initialisation. + */ +static struct svc_pool_map { + int mode; /* Note: int not enum to avoid + * warnings about "enumeration value + * not handled in switch" */ + unsigned int npools; + unsigned int *pool_to; /* maps pool id to cpu or node */ + unsigned int *to_pool; /* maps cpu or node to pool id */ +} svc_pool_map = { + .mode = SVC_POOL_NONE +}; + + +/* + * Detect best pool mapping mode heuristically, + * according to the machine's topology. + */ +static int +svc_pool_map_choose_mode(void) +{ + unsigned int node; + + if (num_online_nodes() > 1) { + /* + * Actually have multiple NUMA nodes, + * so split pools on NUMA node boundaries + */ + return SVC_POOL_PERNODE; + } + + node = any_online_node(node_online_map); + if (nr_cpus_node(node) > 2) { + /* + * Non-trivial SMP, or CONFIG_NUMA on + * non-NUMA hardware, e.g. with a generic + * x86_64 kernel on Xeons. In this case we + * want to divide the pools on cpu boundaries. + */ + return SVC_POOL_PERCPU; + } + + /* default: one global pool */ + return SVC_POOL_GLOBAL; +} + +/* + * Allocate the to_pool[] and pool_to[] arrays. + * Returns 0 on success or an errno. + */ +static int +svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools) +{ + m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); + if (!m->to_pool) + goto fail; + m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); + if (!m->pool_to) + goto fail_free; + + return 0; + +fail_free: + kfree(m->to_pool); +fail: + return -ENOMEM; +} + +/* + * Initialise the pool map for SVC_POOL_PERCPU mode. + * Returns number of pools or <0 on error. + */ +static int +svc_pool_map_init_percpu(struct svc_pool_map *m) +{ + unsigned int maxpools = highest_possible_processor_id()+1; + unsigned int pidx = 0; + unsigned int cpu; + int err; + + err = svc_pool_map_alloc_arrays(m, maxpools); + if (err) + return err; + + for_each_online_cpu(cpu) { + BUG_ON(pidx > maxpools); + m->to_pool[cpu] = pidx; + m->pool_to[pidx] = cpu; + pidx++; + } + /* cpus brought online later all get mapped to pool0, sorry */ + + return pidx; +}; + + +/* + * Initialise the pool map for SVC_POOL_PERNODE mode. + * Returns number of pools or <0 on error. + */ +static int +svc_pool_map_init_pernode(struct svc_pool_map *m) +{ + unsigned int maxpools = highest_possible_node_id()+1; + unsigned int pidx = 0; + unsigned int node; + int err; + + err = svc_pool_map_alloc_arrays(m, maxpools); + if (err) + return err; + + for_each_node_with_cpus(node) { + /* some architectures (e.g. SN2) have cpuless nodes */ + BUG_ON(pidx > maxpools); + m->to_pool[node] = pidx; + m->pool_to[pidx] = node; + pidx++; + } + /* nodes brought online later all get mapped to pool0, sorry */ + + return pidx; +} + + +/* + * Build the global map of cpus to pools and vice versa. + */ +static unsigned int +svc_pool_map_init(void) +{ + struct svc_pool_map *m = &svc_pool_map; + int npools = -1; + + if (m->mode != SVC_POOL_NONE) + return m->npools; + + m->mode = svc_pool_map_choose_mode(); + + switch (m->mode) { + case SVC_POOL_PERCPU: + npools = svc_pool_map_init_percpu(m); + break; + case SVC_POOL_PERNODE: + npools = svc_pool_map_init_pernode(m); + break; + } + + if (npools < 0) { + /* default, or memory allocation failure */ + npools = 1; + m->mode = SVC_POOL_GLOBAL; + } + m->npools = npools; + + return m->npools; +} + +/* + * Set the current thread's cpus_allowed mask so that it + * will only run on cpus in the given pool. + * + * Returns 1 and fills in oldmask iff a cpumask was applied. + */ +static inline int +svc_pool_map_set_cpumask(unsigned int pidx, cpumask_t *oldmask) +{ + struct svc_pool_map *m = &svc_pool_map; + unsigned int node; /* or cpu */ + + /* + * The caller checks for sv_nrpools > 1, which + * implies that we've been initialized and the + * map mode is not NONE. + */ + BUG_ON(m->mode == SVC_POOL_NONE); + + switch (m->mode) + { + default: + return 0; + case SVC_POOL_PERCPU: + node = m->pool_to[pidx]; + *oldmask = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(node)); + return 1; + case SVC_POOL_PERNODE: + node = m->pool_to[pidx]; + *oldmask = current->cpus_allowed; + set_cpus_allowed(current, node_to_cpumask(node)); + return 1; + } +} + +/* + * Use the mapping mode to choose a pool for a given CPU. + * Used when enqueueing an incoming RPC. Always returns + * a non-NULL pool pointer. + */ +struct svc_pool * +svc_pool_for_cpu(struct svc_serv *serv, int cpu) +{ + struct svc_pool_map *m = &svc_pool_map; + unsigned int pidx = 0; + + /* + * SVC_POOL_NONE happens in a pure client when + * lockd is brought up, so silently treat it the + * same as SVC_POOL_GLOBAL. + */ + + switch (m->mode) { + case SVC_POOL_PERCPU: + pidx = m->to_pool[cpu]; + break; + case SVC_POOL_PERNODE: + pidx = m->to_pool[cpu_to_node(cpu)]; + break; + } + return &serv->sv_pools[pidx % serv->sv_nrpools]; +} + + /* * Create an RPC service */ @@ -105,8 +345,9 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, svc_thread_fn func, int sig, struct module *mod) { struct svc_serv *serv; + unsigned int npools = svc_pool_map_init(); - serv = __svc_create(prog, bufsize, /*npools*/1, shutdown); + serv = __svc_create(prog, bufsize, npools, shutdown); if (serv != NULL) { serv->sv_function = func; @@ -209,6 +450,8 @@ svc_release_buffer(struct svc_rqst *rqstp) /* * Create a thread in the given pool. Caller must hold BKL. + * On a NUMA or SMP machine, with a multi-pool serv, the thread + * will be restricted to run on the cpus belonging to the pool. */ static int __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, @@ -216,6 +459,8 @@ __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, { struct svc_rqst *rqstp; int error = -ENOMEM; + int have_oldmask = 0; + cpumask_t oldmask; rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL); if (!rqstp) @@ -235,7 +480,15 @@ __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, spin_unlock_bh(&pool->sp_lock); rqstp->rq_server = serv; rqstp->rq_pool = pool; + + if (serv->sv_nrpools > 1) + have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask); + error = kernel_thread((int (*)(void *)) func, rqstp, 0); + + if (have_oldmask) + set_cpus_allowed(current, oldmask); + if (error < 0) goto out_thread; svc_sock_update_bufs(serv); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index b78659adeff3..cba85d195222 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -151,8 +151,9 @@ static void svc_sock_enqueue(struct svc_sock *svsk) { struct svc_serv *serv = svsk->sk_server; - struct svc_pool *pool = &serv->sv_pools[0]; + struct svc_pool *pool; struct svc_rqst *rqstp; + int cpu; if (!(svsk->sk_flags & ( (1<sk_flags)) return; + cpu = get_cpu(); + pool = svc_pool_for_cpu(svsk->sk_server, cpu); + put_cpu(); + spin_lock_bh(&pool->sp_lock); if (!list_empty(&pool->sp_threads) && -- cgit v1.2.3 From 12fd352038c037ba3a7071a2ca8597c55114abc3 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 2 Oct 2006 02:18:03 -0700 Subject: [PATCH] nfsd: lockdep annotation while doing a kernel make modules_install install over an NFS mount. ============================================= [ INFO: possible recursive locking detected ] --------------------------------------------- nfsd/9550 is trying to acquire lock: (&inode->i_mutex){--..}, at: [] mutex_lock+0x1c/0x1f but task is already holding lock: (&inode->i_mutex){--..}, at: [] mutex_lock+0x1c/0x1f other info that might help us debug this: 2 locks held by nfsd/9550: #0: (hash_sem){..--}, at: [] exp_readlock+0xd/0xf [nfsd] #1: (&inode->i_mutex){--..}, at: [] mutex_lock+0x1c/0x1f stack backtrace: [] show_trace_log_lvl+0x58/0x152 [] show_trace+0xd/0x10 [] dump_stack+0x19/0x1b [] __lock_acquire+0x77a/0x9a3 [] lock_acquire+0x60/0x80 [] __mutex_lock_slowpath+0xa7/0x20e [] mutex_lock+0x1c/0x1f [] vfs_unlink+0x34/0x8a [] nfsd_unlink+0x18f/0x1e2 [nfsd] [] nfsd3_proc_remove+0x95/0xa2 [nfsd] [] nfsd_dispatch+0xc0/0x178 [nfsd] [] svc_process+0x3a5/0x5ed [] nfsd+0x1a7/0x305 [nfsd] [] kernel_thread_helper+0x5/0xb DWARF2 unwinder stuck at kernel_thread_helper+0x5/0xb Leftover inexact backtrace: [] show_trace+0xd/0x10 [] dump_stack+0x19/0x1b [] __lock_acquire+0x77a/0x9a3 [] lock_acquire+0x60/0x80 [] __mutex_lock_slowpath+0xa7/0x20e [] mutex_lock+0x1c/0x1f [] vfs_unlink+0x34/0x8a [] nfsd_unlink+0x18f/0x1e2 [nfsd] [] nfsd3_proc_remove+0x95/0xa2 [nfsd] [] nfsd_dispatch+0xc0/0x178 [nfsd] [] svc_process+0x3a5/0x5ed [] nfsd+0x1a7/0x305 [nfsd] [] kernel_thread_helper+0x5/0xb ============================================= [ INFO: possible recursive locking detected ] --------------------------------------------- nfsd/9580 is trying to acquire lock: (&inode->i_mutex){--..}, at: [] mutex_lock+0x1c/0x1f but task is already holding lock: (&inode->i_mutex){--..}, at: [] mutex_lock+0x1c/0x1f other info that might help us debug this: 2 locks held by nfsd/9580: #0: (hash_sem){..--}, at: [] exp_readlock+0xd/0xf [nfsd] #1: (&inode->i_mutex){--..}, at: [] mutex_lock+0x1c/0x1f stack backtrace: [] show_trace_log_lvl+0x58/0x152 [] show_trace+0xd/0x10 [] dump_stack+0x19/0x1b [] __lock_acquire+0x77a/0x9a3 [] lock_acquire+0x60/0x80 [] __mutex_lock_slowpath+0xa7/0x20e [] mutex_lock+0x1c/0x1f [] nfsd_setattr+0x2c8/0x499 [nfsd] [] nfsd_create_v3+0x31b/0x4ac [nfsd] [] nfsd3_proc_create+0x128/0x138 [nfsd] [] nfsd_dispatch+0xc0/0x178 [nfsd] [] svc_process+0x3a5/0x5ed [] nfsd+0x1a7/0x305 [nfsd] [] kernel_thread_helper+0x5/0xb DWARF2 unwinder stuck at kernel_thread_helper+0x5/0xb Leftover inexact backtrace: [] show_trace+0xd/0x10 [] dump_stack+0x19/0x1b [] __lock_acquire+0x77a/0x9a3 [] lock_acquire+0x60/0x80 [] __mutex_lock_slowpath+0xa7/0x20e [] mutex_lock+0x1c/0x1f [] nfsd_setattr+0x2c8/0x499 [nfsd] [] nfsd_create_v3+0x31b/0x4ac [nfsd] [] nfsd3_proc_create+0x128/0x138 [nfsd] [] nfsd_dispatch+0xc0/0x178 [nfsd] [] svc_process+0x3a5/0x5ed [] nfsd+0x1a7/0x305 [nfsd] [] kernel_thread_helper+0x5/0xb Signed-off-by: Peter Zijlstra Cc: Neil Brown Cc: Ingo Molnar Cc: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/vfs.c | 8 ++++---- include/linux/nfsd/nfsfh.h | 11 +++++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index c9e3b5a8fe07..443ebc52e382 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1114,7 +1114,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, */ if (!resfhp->fh_dentry) { /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ - fh_lock(fhp); + fh_lock_nested(fhp, I_MUTEX_PARENT); dchild = lookup_one_len(fname, dentry, flen); err = PTR_ERR(dchild); if (IS_ERR(dchild)) @@ -1240,7 +1240,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_notdir; if(!dirp->i_op || !dirp->i_op->lookup) goto out; - fh_lock(fhp); + fh_lock_nested(fhp, I_MUTEX_PARENT); /* * Compose the response file handle. @@ -1494,7 +1494,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, if (isdotent(name, len)) goto out; - fh_lock(ffhp); + fh_lock_nested(ffhp, I_MUTEX_PARENT); ddir = ffhp->fh_dentry; dirp = ddir->d_inode; @@ -1644,7 +1644,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, if (err) goto out; - fh_lock(fhp); + fh_lock_nested(fhp, I_MUTEX_PARENT); dentry = fhp->fh_dentry; dirp = dentry->d_inode; diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index 31a3cb617ce0..069257ea99a0 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -290,8 +290,9 @@ fill_post_wcc(struct svc_fh *fhp) * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once * so, any changes here should be reflected there. */ + static inline void -fh_lock(struct svc_fh *fhp) +fh_lock_nested(struct svc_fh *fhp, unsigned int subclass) { struct dentry *dentry = fhp->fh_dentry; struct inode *inode; @@ -310,11 +311,17 @@ fh_lock(struct svc_fh *fhp) } inode = dentry->d_inode; - mutex_lock(&inode->i_mutex); + mutex_lock_nested(&inode->i_mutex, subclass); fill_pre_wcc(fhp); fhp->fh_locked = 1; } +static inline void +fh_lock(struct svc_fh *fhp) +{ + fh_lock_nested(fhp, I_MUTEX_NORMAL); +} + /* * Unlock a file handle/inode */ -- cgit v1.2.3 From ab516013ad9ca47f1d3a936fa81303bfbf734d52 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Mon, 2 Oct 2006 02:18:06 -0700 Subject: [PATCH] namespaces: add nsproxy This patch adds a nsproxy structure to the task struct. Later patches will move the fs namespace pointer into this structure, and introduce a new utsname namespace into the nsproxy. The vserver and openvz functionality, then, would be implemented in large part by virtualizing/isolating more and more resources into namespaces, each contained in the nsproxy. [akpm@osdl.org: build fix] Signed-off-by: Serge Hallyn Cc: Kirill Korotaev Cc: "Eric W. Biederman" Cc: Herbert Poetzl Cc: Andrey Savochkin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/init_task.c | 2 + arch/arm/kernel/init_task.c | 2 + arch/arm26/kernel/init_task.c | 2 + arch/frv/kernel/init_task.c | 2 + arch/h8300/kernel/init_task.c | 2 + arch/i386/kernel/init_task.c | 2 + arch/ia64/kernel/init_task.c | 2 + arch/m32r/kernel/init_task.c | 2 + arch/m68knommu/kernel/init_task.c | 2 + arch/mips/kernel/init_task.c | 2 + arch/parisc/kernel/init_task.c | 2 + arch/powerpc/kernel/init_task.c | 2 + arch/s390/kernel/init_task.c | 2 + arch/sh/kernel/init_task.c | 2 + arch/sh64/kernel/init_task.c | 2 + arch/sparc/kernel/init_task.c | 2 + arch/sparc64/kernel/init_task.c | 2 + arch/um/kernel/init_task.c | 2 + arch/v850/kernel/init_task.c | 2 + arch/x86_64/kernel/init_task.c | 2 + include/linux/init_task.h | 7 ++++ include/linux/nsproxy.h | 45 +++++++++++++++++++++++ include/linux/sched.h | 2 + kernel/Makefile | 2 +- kernel/exit.c | 7 ++++ kernel/fork.c | 18 ++++++++- kernel/nsproxy.c | 77 +++++++++++++++++++++++++++++++++++++++ 27 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 include/linux/nsproxy.h create mode 100644 kernel/nsproxy.c (limited to 'include/linux') diff --git a/arch/alpha/kernel/init_task.c b/arch/alpha/kernel/init_task.c index 835d09a7b332..83d09021ed97 100644 --- a/arch/alpha/kernel/init_task.c +++ b/arch/alpha/kernel/init_task.c @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -13,6 +14,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); struct task_struct init_task = INIT_TASK(init_task); EXPORT_SYMBOL(init_mm); diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c index a00cca0000bd..80f5eeb6d3a8 100644 --- a/arch/arm/kernel/init_task.c +++ b/arch/arm/kernel/init_task.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/arm26/kernel/init_task.c b/arch/arm26/kernel/init_task.c index 4191565b889b..678c7b57f9c7 100644 --- a/arch/arm26/kernel/init_task.c +++ b/arch/arm26/kernel/init_task.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/frv/kernel/init_task.c b/arch/frv/kernel/init_task.c index 22993932b3fc..5ec27422bfe3 100644 --- a/arch/frv/kernel/init_task.c +++ b/arch/frv/kernel/init_task.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -15,6 +16,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/h8300/kernel/init_task.c b/arch/h8300/kernel/init_task.c index 19272c2ac56a..ef5755af6e28 100644 --- a/arch/h8300/kernel/init_task.c +++ b/arch/h8300/kernel/init_task.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c index cff95d10a4d8..bd97f69ac34f 100644 --- a/arch/i386/kernel/init_task.c +++ b/arch/i386/kernel/init_task.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -15,6 +16,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c index b69c397ed1bf..2d62471bfd02 100644 --- a/arch/ia64/kernel/init_task.c +++ b/arch/ia64/kernel/init_task.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -21,6 +22,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/m32r/kernel/init_task.c b/arch/m32r/kernel/init_task.c index 9e508fd9d970..005747590da6 100644 --- a/arch/m32r/kernel/init_task.c +++ b/arch/m32r/kernel/init_task.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/m68knommu/kernel/init_task.c b/arch/m68knommu/kernel/init_task.c index 3897043a126a..b99fc6d6b7c1 100644 --- a/arch/m68knommu/kernel/init_task.c +++ b/arch/m68knommu/kernel/init_task.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/mips/kernel/init_task.c b/arch/mips/kernel/init_task.c index aeda7f58391b..dfe47e6a8b37 100644 --- a/arch/mips/kernel/init_task.c +++ b/arch/mips/kernel/init_task.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/parisc/kernel/init_task.c b/arch/parisc/kernel/init_task.c index 8384bf9cecd2..c0c43e29973b 100644 --- a/arch/parisc/kernel/init_task.c +++ b/arch/parisc/kernel/init_task.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/powerpc/kernel/init_task.c b/arch/powerpc/kernel/init_task.c index 941043ae040f..e24ace618987 100644 --- a/arch/powerpc/kernel/init_task.c +++ b/arch/powerpc/kernel/init_task.c @@ -5,6 +5,7 @@ #include #include #include +#include #include static struct fs_struct init_fs = INIT_FS; @@ -12,6 +13,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/s390/kernel/init_task.c b/arch/s390/kernel/init_task.c index d73a74013e73..0918921763b1 100644 --- a/arch/s390/kernel/init_task.c +++ b/arch/s390/kernel/init_task.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/sh/kernel/init_task.c b/arch/sh/kernel/init_task.c index 44053ea92936..81caf0fd3bee 100644 --- a/arch/sh/kernel/init_task.c +++ b/arch/sh/kernel/init_task.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -12,6 +13,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/sh64/kernel/init_task.c b/arch/sh64/kernel/init_task.c index de2d07db1f88..0c95f40c5403 100644 --- a/arch/sh64/kernel/init_task.c +++ b/arch/sh64/kernel/init_task.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); struct pt_regs fake_swapper_regs; diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c index fc31de66b1c2..a73926d5176b 100644 --- a/arch/sparc/kernel/init_task.c +++ b/arch/sparc/kernel/init_task.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -12,6 +13,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); struct task_struct init_task = INIT_TASK(init_task); EXPORT_SYMBOL(init_mm); diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c index 329b38fa5c89..f1e9a4b021ae 100644 --- a/arch/sparc64/kernel/init_task.c +++ b/arch/sparc64/kernel/init_task.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -13,6 +14,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index 49ed5ddf0704..11188af64d86 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c @@ -9,6 +9,7 @@ #include "linux/sched.h" #include "linux/init_task.h" #include "linux/mqueue.h" +#include "linux/nsproxy.h" #include "asm/uaccess.h" #include "asm/pgtable.h" #include "user_util.h" @@ -17,6 +18,7 @@ static struct fs_struct init_fs = INIT_FS; struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); diff --git a/arch/v850/kernel/init_task.c b/arch/v850/kernel/init_task.c index ed2f93cf7c66..9d2de7590849 100644 --- a/arch/v850/kernel/init_task.c +++ b/arch/v850/kernel/init_task.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS (init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM (init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task.c index 3dc5854ba21e..879728bff73f 100644 --- a/arch/x86_64/kernel/init_task.c +++ b/arch/x86_64/kernel/init_task.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -15,6 +16,7 @@ static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); +struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); EXPORT_SYMBOL(init_mm); diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 60aac2cea0cf..8f8bb422a5c7 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -68,6 +68,12 @@ .session = 1, \ } +extern struct nsproxy init_nsproxy; +#define INIT_NSPROXY(nsproxy) { \ + .count = ATOMIC_INIT(1), \ + .nslock = SPIN_LOCK_UNLOCKED, \ +} + #define INIT_SIGHAND(sighand) { \ .count = ATOMIC_INIT(1), \ .action = { { { .sa_handler = NULL, } }, }, \ @@ -117,6 +123,7 @@ extern struct group_info init_groups; .files = &init_files, \ .signal = &init_signals, \ .sighand = &init_sighand, \ + .nsproxy = &init_nsproxy, \ .pending = { \ .list = LIST_HEAD_INIT(tsk.pending.list), \ .signal = {{0}}}, \ diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h new file mode 100644 index 000000000000..7bdebfaab6a5 --- /dev/null +++ b/include/linux/nsproxy.h @@ -0,0 +1,45 @@ +#ifndef _LINUX_NSPROXY_H +#define _LINUX_NSPROXY_H + +#include +#include + +/* + * A structure to contain pointers to all per-process + * namespaces - fs (mount), uts, network, sysvipc, etc. + * + * 'count' is the number of tasks holding a reference. + * The count for each namespace, then, will be the number + * of nsproxies pointing to it, not the number of tasks. + * + * The nsproxy is shared by tasks which share all namespaces. + * As soon as a single namespace is cloned or unshared, the + * nsproxy is copied. + */ +struct nsproxy { + atomic_t count; + spinlock_t nslock; +}; +extern struct nsproxy init_nsproxy; + +struct nsproxy *dup_namespaces(struct nsproxy *orig); +int copy_namespaces(int flags, struct task_struct *tsk); +void get_task_namespaces(struct task_struct *tsk); +void free_nsproxy(struct nsproxy *ns); + +static inline void put_nsproxy(struct nsproxy *ns) +{ + if (atomic_dec_and_test(&ns->count)) { + free_nsproxy(ns); + } +} + +static inline void exit_task_namespaces(struct task_struct *p) +{ + struct nsproxy *ns = p->nsproxy; + if (ns) { + put_nsproxy(ns); + p->nsproxy = NULL; + } +} +#endif diff --git a/include/linux/sched.h b/include/linux/sched.h index a7fff3304bd6..4fa631fa55e3 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -239,6 +239,7 @@ extern signed long schedule_timeout_uninterruptible(signed long timeout); asmlinkage void schedule(void); struct namespace; +struct nsproxy; /* Maximum number of active map areas.. This is a random (large) number */ #define DEFAULT_MAX_MAP_COUNT 65536 @@ -898,6 +899,7 @@ struct task_struct { struct files_struct *files; /* namespace */ struct namespace *namespace; + struct nsproxy *nsproxy; /* signal handlers */ struct signal_struct *signal; struct sighand_struct *sighand; diff --git a/kernel/Makefile b/kernel/Makefile index aacaafb28b9d..6ec53009b866 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,7 +8,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o extable.o params.o posix-timers.o \ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ - hrtimer.o rwsem.o latency.o + hrtimer.o rwsem.o latency.o nsproxy.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += time/ diff --git a/kernel/exit.c b/kernel/exit.c index 3b47f26985f2..1d0e9ea1fa05 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -397,9 +398,14 @@ void daemonize(const char *name, ...) fs = init_task.fs; current->fs = fs; atomic_inc(&fs->count); + exit_namespace(current); + exit_task_namespaces(current); current->namespace = init_task.namespace; + current->nsproxy = init_task.nsproxy; get_namespace(current->namespace); + get_task_namespaces(current); + exit_files(current); current->files = init_task.files; atomic_inc(¤t->files->count); @@ -918,6 +924,7 @@ fastcall NORET_TYPE void do_exit(long code) __exit_files(tsk); __exit_fs(tsk); exit_namespace(tsk); + exit_task_namespaces(tsk); exit_thread(); cpuset_exit(tsk); exit_keys(tsk); diff --git a/kernel/fork.c b/kernel/fork.c index 89f666491d1f..c9e660ae47aa 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1116,8 +1117,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, goto bad_fork_cleanup_signal; if ((retval = copy_keys(clone_flags, p))) goto bad_fork_cleanup_mm; - if ((retval = copy_namespace(clone_flags, p))) + if ((retval = copy_namespaces(clone_flags, p))) goto bad_fork_cleanup_keys; + if ((retval = copy_namespace(clone_flags, p))) + goto bad_fork_cleanup_namespaces; retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); if (retval) goto bad_fork_cleanup_namespace; @@ -1262,6 +1265,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, bad_fork_cleanup_namespace: exit_namespace(p); +bad_fork_cleanup_namespaces: + exit_task_namespaces(p); bad_fork_cleanup_keys: exit_keys(p); bad_fork_cleanup_mm: @@ -1606,6 +1611,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL; struct files_struct *fd, *new_fd = NULL; struct sem_undo_list *new_ulist = NULL; + struct nsproxy *new_nsproxy, *old_nsproxy; check_unshare_flags(&unshare_flags); @@ -1632,7 +1638,15 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist) { + old_nsproxy = current->nsproxy; + new_nsproxy = dup_namespaces(old_nsproxy); + if (!new_nsproxy) { + err = -ENOMEM; + goto bad_unshare_cleanup_semundo; + } + task_lock(current); + current->nsproxy = new_nsproxy; if (new_fs) { fs = current->fs; @@ -1668,8 +1682,10 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) } task_unlock(current); + put_nsproxy(old_nsproxy); } +bad_unshare_cleanup_semundo: bad_unshare_cleanup_fd: if (new_fd) put_files_struct(new_fd); diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c new file mode 100644 index 000000000000..ad9508865473 --- /dev/null +++ b/kernel/nsproxy.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2006 IBM Corporation + * + * Author: Serge Hallyn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#include +#include +#include + +static inline void get_nsproxy(struct nsproxy *ns) +{ + atomic_inc(&ns->count); +} + +void get_task_namespaces(struct task_struct *tsk) +{ + struct nsproxy *ns = tsk->nsproxy; + if (ns) { + get_nsproxy(ns); + } +} + +/* + * creates a copy of "orig" with refcount 1. + * This does not grab references to the contained namespaces, + * so that needs to be done by dup_namespaces. + */ +static inline struct nsproxy *clone_namespaces(struct nsproxy *orig) +{ + struct nsproxy *ns; + + ns = kmalloc(sizeof(struct nsproxy), GFP_KERNEL); + if (ns) { + memcpy(ns, orig, sizeof(struct nsproxy)); + atomic_set(&ns->count, 1); + } + return ns; +} + +/* + * copies the nsproxy, setting refcount to 1, and grabbing a + * reference to all contained namespaces. Called from + * sys_unshare() + */ +struct nsproxy *dup_namespaces(struct nsproxy *orig) +{ + struct nsproxy *ns = clone_namespaces(orig); + + return ns; +} + +/* + * called from clone. This now handles copy for nsproxy and all + * namespaces therein. + */ +int copy_namespaces(int flags, struct task_struct *tsk) +{ + struct nsproxy *old_ns = tsk->nsproxy; + + if (!old_ns) + return 0; + + get_nsproxy(old_ns); + + return 0; +} + +void free_nsproxy(struct nsproxy *ns) +{ + kfree(ns); +} -- cgit v1.2.3 From 1651e14e28a2d9f446018ef522882e0709a2ce4f Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Mon, 2 Oct 2006 02:18:08 -0700 Subject: [PATCH] namespaces: incorporate fs namespace into nsproxy This moves the mount namespace into the nsproxy. The mount namespace count now refers to the number of nsproxies point to it, rather than the number of tasks. As a result, the unshare_namespace() function in kernel/fork.c no longer checks whether it is being shared. Signed-off-by: Serge Hallyn Cc: Kirill Korotaev Cc: "Eric W. Biederman" Cc: Herbert Poetzl Cc: Andrey Savochkin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namespace.c | 22 ++++++++-------------- fs/proc/base.c | 5 +++-- include/linux/init_task.h | 1 + include/linux/namespace.h | 6 ++---- include/linux/nsproxy.h | 3 +++ include/linux/sched.h | 4 +--- kernel/exit.c | 4 ---- kernel/fork.c | 17 ++++++----------- kernel/nsproxy.c | 32 +++++++++++++++++++++++++++++++- 9 files changed, 55 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/fs/namespace.c b/fs/namespace.c index 66d921e14fee..55442a6cf221 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -133,7 +133,7 @@ struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) static inline int check_mnt(struct vfsmount *mnt) { - return mnt->mnt_namespace == current->namespace; + return mnt->mnt_namespace == current->nsproxy->namespace; } static void touch_namespace(struct namespace *ns) @@ -830,7 +830,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, if (parent_nd) { detach_mnt(source_mnt, parent_nd); attach_mnt(source_mnt, nd); - touch_namespace(current->namespace); + touch_namespace(current->nsproxy->namespace); } else { mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); commit_tree(source_mnt); @@ -1441,7 +1441,7 @@ dput_out: */ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) { - struct namespace *namespace = tsk->namespace; + struct namespace *namespace = tsk->nsproxy->namespace; struct namespace *new_ns; struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; struct vfsmount *p, *q; @@ -1508,7 +1508,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) int copy_namespace(int flags, struct task_struct *tsk) { - struct namespace *namespace = tsk->namespace; + struct namespace *namespace = tsk->nsproxy->namespace; struct namespace *new_ns; int err = 0; @@ -1531,7 +1531,7 @@ int copy_namespace(int flags, struct task_struct *tsk) goto out; } - tsk->namespace = new_ns; + tsk->nsproxy->namespace = new_ns; out: put_namespace(namespace); @@ -1754,7 +1754,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root, detach_mnt(user_nd.mnt, &root_parent); attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ - touch_namespace(current->namespace); + touch_namespace(current->nsproxy->namespace); spin_unlock(&vfsmount_lock); chroot_fs_refs(&user_nd, &new_nd); security_sb_post_pivotroot(&user_nd, &new_nd); @@ -1780,7 +1780,6 @@ static void __init init_mount_tree(void) { struct vfsmount *mnt; struct namespace *namespace; - struct task_struct *g, *p; mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); if (IS_ERR(mnt)) @@ -1796,13 +1795,8 @@ static void __init init_mount_tree(void) namespace->root = mnt; mnt->mnt_namespace = namespace; - init_task.namespace = namespace; - read_lock(&tasklist_lock); - do_each_thread(g, p) { - get_namespace(namespace); - p->namespace = namespace; - } while_each_thread(g, p); - read_unlock(&tasklist_lock); + init_task.nsproxy->namespace = namespace; + get_namespace(namespace); set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root); set_fs_root(current->fs, namespace->root, namespace->root->mnt_root); diff --git a/fs/proc/base.c b/fs/proc/base.c index 9c6a809f92b6..6d00ccc48c1c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -71,6 +71,7 @@ #include #include #include +#include #include "internal.h" /* NOTE: @@ -473,7 +474,7 @@ static int mounts_open(struct inode *inode, struct file *file) if (task) { task_lock(task); - namespace = task->namespace; + namespace = task->nsproxy->namespace; if (namespace) get_namespace(namespace); task_unlock(task); @@ -544,7 +545,7 @@ static int mountstats_open(struct inode *inode, struct file *file) if (task) { task_lock(task); - namespace = task->namespace; + namespace = task->nsproxy->namespace; if (namespace) get_namespace(namespace); task_unlock(task); diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 8f8bb422a5c7..4865348ca8bd 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -72,6 +72,7 @@ extern struct nsproxy init_nsproxy; #define INIT_NSPROXY(nsproxy) { \ .count = ATOMIC_INIT(1), \ .nslock = SPIN_LOCK_UNLOCKED, \ + .namespace = NULL, \ } #define INIT_SIGHAND(sighand) { \ diff --git a/include/linux/namespace.h b/include/linux/namespace.h index 3abc8e3b4879..d137009f0b2b 100644 --- a/include/linux/namespace.h +++ b/include/linux/namespace.h @@ -4,6 +4,7 @@ #include #include +#include struct namespace { atomic_t count; @@ -26,11 +27,8 @@ static inline void put_namespace(struct namespace *namespace) static inline void exit_namespace(struct task_struct *p) { - struct namespace *namespace = p->namespace; + struct namespace *namespace = p->nsproxy->namespace; if (namespace) { - task_lock(p); - p->namespace = NULL; - task_unlock(p); put_namespace(namespace); } } diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index 7bdebfaab6a5..7ebe66670c59 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h @@ -4,6 +4,8 @@ #include #include +struct namespace; + /* * A structure to contain pointers to all per-process * namespaces - fs (mount), uts, network, sysvipc, etc. @@ -19,6 +21,7 @@ struct nsproxy { atomic_t count; spinlock_t nslock; + struct namespace *namespace; }; extern struct nsproxy init_nsproxy; diff --git a/include/linux/sched.h b/include/linux/sched.h index 4fa631fa55e3..670b89a20070 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -238,7 +238,6 @@ extern signed long schedule_timeout_interruptible(signed long timeout); extern signed long schedule_timeout_uninterruptible(signed long timeout); asmlinkage void schedule(void); -struct namespace; struct nsproxy; /* Maximum number of active map areas.. This is a random (large) number */ @@ -897,8 +896,7 @@ struct task_struct { struct fs_struct *fs; /* open file information */ struct files_struct *files; -/* namespace */ - struct namespace *namespace; +/* namespaces */ struct nsproxy *nsproxy; /* signal handlers */ struct signal_struct *signal; diff --git a/kernel/exit.c b/kernel/exit.c index 1d0e9ea1fa05..741bbe42dfe8 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -399,11 +399,8 @@ void daemonize(const char *name, ...) current->fs = fs; atomic_inc(&fs->count); - exit_namespace(current); exit_task_namespaces(current); - current->namespace = init_task.namespace; current->nsproxy = init_task.nsproxy; - get_namespace(current->namespace); get_task_namespaces(current); exit_files(current); @@ -923,7 +920,6 @@ fastcall NORET_TYPE void do_exit(long code) exit_sem(tsk); __exit_files(tsk); __exit_fs(tsk); - exit_namespace(tsk); exit_task_namespaces(tsk); exit_thread(); cpuset_exit(tsk); diff --git a/kernel/fork.c b/kernel/fork.c index c9e660ae47aa..33fcf0733ca6 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1119,11 +1119,9 @@ static struct task_struct *copy_process(unsigned long clone_flags, goto bad_fork_cleanup_mm; if ((retval = copy_namespaces(clone_flags, p))) goto bad_fork_cleanup_keys; - if ((retval = copy_namespace(clone_flags, p))) - goto bad_fork_cleanup_namespaces; retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); if (retval) - goto bad_fork_cleanup_namespace; + goto bad_fork_cleanup_namespaces; p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; /* @@ -1215,7 +1213,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, spin_unlock(¤t->sighand->siglock); write_unlock_irq(&tasklist_lock); retval = -ERESTARTNOINTR; - goto bad_fork_cleanup_namespace; + goto bad_fork_cleanup_namespaces; } if (clone_flags & CLONE_THREAD) { @@ -1263,8 +1261,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, proc_fork_connector(p); return p; -bad_fork_cleanup_namespace: - exit_namespace(p); bad_fork_cleanup_namespaces: exit_task_namespaces(p); bad_fork_cleanup_keys: @@ -1519,10 +1515,9 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) */ static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) { - struct namespace *ns = current->namespace; + struct namespace *ns = current->nsproxy->namespace; - if ((unshare_flags & CLONE_NEWNS) && - (ns && atomic_read(&ns->count) > 1)) { + if ((unshare_flags & CLONE_NEWNS) && ns) { if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1655,8 +1650,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) } if (new_ns) { - ns = current->namespace; - current->namespace = new_ns; + ns = current->nsproxy->namespace; + current->nsproxy->namespace = new_ns; new_ns = ns; } diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index a3612f82f187..e10385c17f73 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -13,6 +13,7 @@ #include #include #include +#include struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); @@ -55,6 +56,11 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) { struct nsproxy *ns = clone_namespaces(orig); + if (ns) { + if (ns->namespace) + get_namespace(ns->namespace); + } + return ns; } @@ -65,16 +71,40 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) int copy_namespaces(int flags, struct task_struct *tsk) { struct nsproxy *old_ns = tsk->nsproxy; + struct nsproxy *new_ns; + int err = 0; if (!old_ns) return 0; get_nsproxy(old_ns); - return 0; + if (!(flags & CLONE_NEWNS)) + return 0; + + new_ns = clone_namespaces(old_ns); + if (!new_ns) { + err = -ENOMEM; + goto out; + } + + tsk->nsproxy = new_ns; + + err = copy_namespace(flags, tsk); + if (err) { + tsk->nsproxy = old_ns; + put_nsproxy(new_ns); + goto out; + } + +out: + put_nsproxy(old_ns); + return err; } void free_nsproxy(struct nsproxy *ns) { + if (ns->namespace) + put_namespace(ns->namespace); kfree(ns); } -- cgit v1.2.3 From 0bdd7aab7f0ecd5d337910816aa058c18398628e Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Mon, 2 Oct 2006 02:18:10 -0700 Subject: [PATCH] namespaces: utsname: introduce temporary helpers Define utsname() and init_utsname() which return &system_utsname. Users of system_utsname will be changed to use these helpers, after which system_utsname will disappear. Signed-off-by: Serge E. Hallyn Cc: Kirill Korotaev Cc: "Eric W. Biederman" Cc: Herbert Poetzl Cc: Andrey Savochkin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/utsname.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include/linux') diff --git a/include/linux/utsname.h b/include/linux/utsname.h index 13e1da0c538d..77e97a5755d9 100644 --- a/include/linux/utsname.h +++ b/include/linux/utsname.h @@ -32,5 +32,15 @@ struct new_utsname { extern struct new_utsname system_utsname; +static inline struct new_utsname *utsname(void) +{ + return &system_utsname; +} + +static inline struct new_utsname *init_utsname(void) +{ + return &system_utsname; +} + extern struct rw_semaphore uts_sem; #endif -- cgit v1.2.3 From e9ff3990f08e9a0c2839cc22808b01732ea5b3e4 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Mon, 2 Oct 2006 02:18:11 -0700 Subject: [PATCH] namespaces: utsname: switch to using uts namespaces Replace references to system_utsname to the per-process uts namespace where appropriate. This includes things like uname. Changes: Per Eric Biederman's comments, use the per-process uts namespace for ELF_PLATFORM, sunrpc, and parts of net/ipv4/ipconfig.c [jdike@addtoit.com: UML fix] [clg@fr.ibm.com: cleanup] [akpm@osdl.org: build fix] Signed-off-by: Serge E. Hallyn Cc: Kirill Korotaev Cc: "Eric W. Biederman" Cc: Herbert Poetzl Cc: Andrey Savochkin Signed-off-by: Cedric Le Goater Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/osf_sys.c | 26 ++++++++++++------------- arch/i386/kernel/sys_i386.c | 27 +++++++++++++++----------- arch/ia64/sn/kernel/sn2/sn_hwperf.c | 2 +- arch/m32r/kernel/sys_m32r.c | 2 +- arch/mips/kernel/linux32.c | 2 +- arch/mips/kernel/syscall.c | 27 +++++++++++++++----------- arch/mips/kernel/sysirix.c | 12 ++++++------ arch/parisc/hpux/sys_hpux.c | 37 ++++++++++++++++++++---------------- arch/powerpc/kernel/syscalls.c | 14 +++++++------- arch/sh/kernel/sys_sh.c | 2 +- arch/sh64/kernel/sys_sh64.c | 2 +- arch/sparc/kernel/sys_sparc.c | 4 ++-- arch/sparc/kernel/sys_sunos.c | 15 ++++++++++----- arch/sparc64/kernel/sys_sparc.c | 4 ++-- arch/sparc64/kernel/sys_sunos32.c | 10 +++++----- arch/sparc64/solaris/misc.c | 6 +++--- arch/um/drivers/mconsole_kern.c | 6 +++--- arch/um/kernel/syscall.c | 22 ++++++++++----------- arch/um/sys-x86_64/syscalls.c | 2 +- arch/x86_64/ia32/sys_ia32.c | 38 ++++++++++++++++++------------------- arch/x86_64/kernel/sys_x86_64.c | 2 +- arch/xtensa/kernel/syscalls.c | 2 +- drivers/char/random.c | 4 ++-- fs/cifs/connect.c | 22 ++++++++++----------- fs/exec.c | 2 +- fs/lockd/clntproc.c | 4 ++-- fs/lockd/mon.c | 2 +- fs/lockd/svclock.c | 2 +- fs/lockd/xdr.c | 2 +- fs/nfs/nfsroot.c | 2 +- include/asm-i386/elf.h | 2 +- include/linux/lockd/lockd.h | 2 +- kernel/sys.c | 14 +++++++------- net/ipv4/ipconfig.c | 14 +++++++------- net/sunrpc/clnt.c | 4 ++-- 35 files changed, 180 insertions(+), 160 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 73c7622b5297..8a31fc1bfb15 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -402,15 +402,15 @@ osf_utsname(char __user *name) down_read(&uts_sem); error = -EFAULT; - if (copy_to_user(name + 0, system_utsname.sysname, 32)) + if (copy_to_user(name + 0, utsname()->sysname, 32)) goto out; - if (copy_to_user(name + 32, system_utsname.nodename, 32)) + if (copy_to_user(name + 32, utsname()->nodename, 32)) goto out; - if (copy_to_user(name + 64, system_utsname.release, 32)) + if (copy_to_user(name + 64, utsname()->release, 32)) goto out; - if (copy_to_user(name + 96, system_utsname.version, 32)) + if (copy_to_user(name + 96, utsname()->version, 32)) goto out; - if (copy_to_user(name + 128, system_utsname.machine, 32)) + if (copy_to_user(name + 128, utsname()->machine, 32)) goto out; error = 0; @@ -449,8 +449,8 @@ osf_getdomainname(char __user *name, int namelen) down_read(&uts_sem); for (i = 0; i < len; ++i) { - __put_user(system_utsname.domainname[i], name + i); - if (system_utsname.domainname[i] == '\0') + __put_user(utsname()->domainname[i], name + i); + if (utsname()->domainname[i] == '\0') break; } up_read(&uts_sem); @@ -607,12 +607,12 @@ osf_sigstack(struct sigstack __user *uss, struct sigstack __user *uoss) asmlinkage long osf_sysinfo(int command, char __user *buf, long count) { - static char * sysinfo_table[] = { - system_utsname.sysname, - system_utsname.nodename, - system_utsname.release, - system_utsname.version, - system_utsname.machine, + char *sysinfo_table[] = { + utsname()->sysname, + utsname()->nodename, + utsname()->release, + utsname()->version, + utsname()->machine, "alpha", /* instruction set architecture */ "dummy", /* hardware serial number */ "dummy", /* hardware manufacturer */ diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c index 8fdb1fb17a5f..dc6e3bbeba31 100644 --- a/arch/i386/kernel/sys_i386.c +++ b/arch/i386/kernel/sys_i386.c @@ -210,7 +210,7 @@ asmlinkage int sys_uname(struct old_utsname __user * name) if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } @@ -226,16 +226,21 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name) down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); - error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); - error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); - error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); - error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); - error |= __put_user(0,name->machine+__OLD_UTS_LEN); + error = __copy_to_user(&name->sysname, &utsname()->sysname, + __OLD_UTS_LEN); + error |= __put_user(0, name->sysname + __OLD_UTS_LEN); + error |= __copy_to_user(&name->nodename, &utsname()->nodename, + __OLD_UTS_LEN); + error |= __put_user(0, name->nodename + __OLD_UTS_LEN); + error |= __copy_to_user(&name->release, &utsname()->release, + __OLD_UTS_LEN); + error |= __put_user(0, name->release + __OLD_UTS_LEN); + error |= __copy_to_user(&name->version, &utsname()->version, + __OLD_UTS_LEN); + error |= __put_user(0, name->version + __OLD_UTS_LEN); + error |= __copy_to_user(&name->machine, &utsname()->machine, + __OLD_UTS_LEN); + error |= __put_user(0, name->machine + __OLD_UTS_LEN); up_read(&uts_sem); diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index b632b9c1e3b3..462ea178f49a 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c @@ -423,7 +423,7 @@ static int sn_topology_show(struct seq_file *s, void *d) "coherency_domain %d, " "region_size %d\n", - partid, system_utsname.nodename, + partid, utsname()->nodename, shubtype ? "shub2" : "shub1", (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, system_size, sharing_size, coher, region_size); diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c index a9cea32eb824..7c29396cc670 100644 --- a/arch/m32r/kernel/sys_m32r.c +++ b/arch/m32r/kernel/sys_m32r.c @@ -205,7 +205,7 @@ asmlinkage int sys_uname(struct old_utsname * name) if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 43b1162d714f..52cada45b353 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -1039,7 +1039,7 @@ asmlinkage long sys32_newuname(struct new_utsname __user * name) int ret = 0; down_read(&uts_sem); - if (copy_to_user(name,&system_utsname,sizeof *name)) + if (copy_to_user(name, utsname(), sizeof *name)) ret = -EFAULT; up_read(&uts_sem); diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 9951240cc3fd..970e3e96b1d0 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -231,7 +231,7 @@ out: */ asmlinkage int sys_uname(struct old_utsname __user * name) { - if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + if (name && !copy_to_user(name, utsname(), sizeof (*name))) return 0; return -EFAULT; } @@ -248,16 +248,21 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name) if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) return -EFAULT; - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); - error -= __put_user(0,name->sysname+__OLD_UTS_LEN); - error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); - error -= __put_user(0,name->nodename+__OLD_UTS_LEN); - error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); - error -= __put_user(0,name->release+__OLD_UTS_LEN); - error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); - error -= __put_user(0,name->version+__OLD_UTS_LEN); - error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); - error = __put_user(0,name->machine+__OLD_UTS_LEN); + error = __copy_to_user(&name->sysname, &utsname()->sysname, + __OLD_UTS_LEN); + error -= __put_user(0, name->sysname + __OLD_UTS_LEN); + error -= __copy_to_user(&name->nodename, &utsname()->nodename, + __OLD_UTS_LEN); + error -= __put_user(0, name->nodename + __OLD_UTS_LEN); + error -= __copy_to_user(&name->release, &utsname()->release, + __OLD_UTS_LEN); + error -= __put_user(0, name->release + __OLD_UTS_LEN); + error -= __copy_to_user(&name->version, &utsname()->version, + __OLD_UTS_LEN); + error -= __put_user(0, name->version + __OLD_UTS_LEN); + error -= __copy_to_user(&name->machine, &utsname()->machine, + __OLD_UTS_LEN); + error = __put_user(0, name->machine + __OLD_UTS_LEN); error = error ? -EFAULT : 0; return error; diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 1137dd6ea7aa..11bb97174972 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -884,7 +884,7 @@ asmlinkage int irix_getdomainname(char __user *name, int len) down_read(&uts_sem); if (len > __NEW_UTS_LEN) len = __NEW_UTS_LEN; - err = copy_to_user(name, system_utsname.domainname, len) ? -EFAULT : 0; + err = copy_to_user(name, utsname()->domainname, len) ? -EFAULT : 0; up_read(&uts_sem); return err; @@ -1127,11 +1127,11 @@ struct iuname { asmlinkage int irix_uname(struct iuname __user *buf) { down_read(&uts_sem); - if (copy_from_user(system_utsname.sysname, buf->sysname, 65) - || copy_from_user(system_utsname.nodename, buf->nodename, 65) - || copy_from_user(system_utsname.release, buf->release, 65) - || copy_from_user(system_utsname.version, buf->version, 65) - || copy_from_user(system_utsname.machine, buf->machine, 65)) { + if (copy_from_user(utsname()->sysname, buf->sysname, 65) + || copy_from_user(utsname()->nodename, buf->nodename, 65) + || copy_from_user(utsname()->release, buf->release, 65) + || copy_from_user(utsname()->version, buf->version, 65) + || copy_from_user(utsname()->machine, buf->machine, 65)) { return -EFAULT; } up_read(&uts_sem); diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c index cb69727027ae..2e2dc4f2c853 100644 --- a/arch/parisc/hpux/sys_hpux.c +++ b/arch/parisc/hpux/sys_hpux.c @@ -266,16 +266,21 @@ static int hpux_uname(struct hpux_utsname *name) down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,HPUX_UTSLEN-1); - error |= __put_user(0,name->sysname+HPUX_UTSLEN-1); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename,HPUX_UTSLEN-1); - error |= __put_user(0,name->nodename+HPUX_UTSLEN-1); - error |= __copy_to_user(&name->release,&system_utsname.release,HPUX_UTSLEN-1); - error |= __put_user(0,name->release+HPUX_UTSLEN-1); - error |= __copy_to_user(&name->version,&system_utsname.version,HPUX_UTSLEN-1); - error |= __put_user(0,name->version+HPUX_UTSLEN-1); - error |= __copy_to_user(&name->machine,&system_utsname.machine,HPUX_UTSLEN-1); - error |= __put_user(0,name->machine+HPUX_UTSLEN-1); + error = __copy_to_user(&name->sysname, &utsname()->sysname, + HPUX_UTSLEN - 1); + error |= __put_user(0, name->sysname + HPUX_UTSLEN - 1); + error |= __copy_to_user(&name->nodename, &utsname()->nodename, + HPUX_UTSLEN - 1); + error |= __put_user(0, name->nodename + HPUX_UTSLEN - 1); + error |= __copy_to_user(&name->release, &utsname()->release, + HPUX_UTSLEN - 1); + error |= __put_user(0, name->release + HPUX_UTSLEN - 1); + error |= __copy_to_user(&name->version, &utsname()->version, + HPUX_UTSLEN - 1); + error |= __put_user(0, name->version + HPUX_UTSLEN - 1); + error |= __copy_to_user(&name->machine, &utsname()->machine, + HPUX_UTSLEN - 1); + error |= __put_user(0, name->machine + HPUX_UTSLEN - 1); up_read(&uts_sem); @@ -373,8 +378,8 @@ int hpux_utssys(char *ubuf, int n, int type) /* TODO: print a warning about using this? */ down_write(&uts_sem); error = -EFAULT; - if (!copy_from_user(system_utsname.sysname, ubuf, len)) { - system_utsname.sysname[len] = 0; + if (!copy_from_user(utsname()->sysname, ubuf, len)) { + utsname()->sysname[len] = 0; error = 0; } up_write(&uts_sem); @@ -400,8 +405,8 @@ int hpux_utssys(char *ubuf, int n, int type) /* TODO: print a warning about this? */ down_write(&uts_sem); error = -EFAULT; - if (!copy_from_user(system_utsname.release, ubuf, len)) { - system_utsname.release[len] = 0; + if (!copy_from_user(utsname()->release, ubuf, len)) { + utsname()->release[len] = 0; error = 0; } up_write(&uts_sem); @@ -422,13 +427,13 @@ int hpux_getdomainname(char *name, int len) down_read(&uts_sem); - nlen = strlen(system_utsname.domainname) + 1; + nlen = strlen(utsname()->domainname) + 1; if (nlen < len) len = nlen; if(len > __NEW_UTS_LEN) goto done; - if(copy_to_user(name, system_utsname.domainname, len)) + if(copy_to_user(name, utsname()->domainname, len)) goto done; err = 0; done: diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 9b69d99a9103..d358866b880f 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -260,7 +260,7 @@ long ppc_newuname(struct new_utsname __user * name) int err = 0; down_read(&uts_sem); - if (copy_to_user(name, &system_utsname, sizeof(*name))) + if (copy_to_user(name, utsname(), sizeof(*name))) err = -EFAULT; up_read(&uts_sem); if (!err) @@ -273,7 +273,7 @@ int sys_uname(struct old_utsname __user *name) int err = 0; down_read(&uts_sem); - if (copy_to_user(name, &system_utsname, sizeof(*name))) + if (copy_to_user(name, utsname(), sizeof(*name))) err = -EFAULT; up_read(&uts_sem); if (!err) @@ -289,19 +289,19 @@ int sys_olduname(struct oldold_utsname __user *name) return -EFAULT; down_read(&uts_sem); - error = __copy_to_user(&name->sysname, &system_utsname.sysname, + error = __copy_to_user(&name->sysname, &utsname()->sysname, __OLD_UTS_LEN); error |= __put_user(0, name->sysname + __OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename, &system_utsname.nodename, + error |= __copy_to_user(&name->nodename, &utsname()->nodename, __OLD_UTS_LEN); error |= __put_user(0, name->nodename + __OLD_UTS_LEN); - error |= __copy_to_user(&name->release, &system_utsname.release, + error |= __copy_to_user(&name->release, &utsname()->release, __OLD_UTS_LEN); error |= __put_user(0, name->release + __OLD_UTS_LEN); - error |= __copy_to_user(&name->version, &system_utsname.version, + error |= __copy_to_user(&name->version, &utsname()->version, __OLD_UTS_LEN); error |= __put_user(0, name->version + __OLD_UTS_LEN); - error |= __copy_to_user(&name->machine, &system_utsname.machine, + error |= __copy_to_user(&name->machine, &utsname()->machine, __OLD_UTS_LEN); error |= override_machine(name->machine); up_read(&uts_sem); diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index b68ff705f067..11c2acde6eaa 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -281,7 +281,7 @@ asmlinkage int sys_uname(struct old_utsname * name) if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } diff --git a/arch/sh64/kernel/sys_sh64.c b/arch/sh64/kernel/sys_sh64.c index 58ff7d522d81..c6de1a95af44 100644 --- a/arch/sh64/kernel/sys_sh64.c +++ b/arch/sh64/kernel/sys_sh64.c @@ -279,7 +279,7 @@ asmlinkage int sys_uname(struct old_utsname * name) if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index 896863fb208a..002ab4dbe5cb 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c @@ -475,13 +475,13 @@ asmlinkage int sys_getdomainname(char __user *name, int len) down_read(&uts_sem); - nlen = strlen(system_utsname.domainname) + 1; + nlen = strlen(utsname()->domainname) + 1; err = -EINVAL; if (nlen > len) goto out; err = -EFAULT; - if (!copy_to_user(name, system_utsname.domainname, nlen)) + if (!copy_to_user(name, utsname()->domainname, nlen)) err = 0; out: diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index aa0fb2efb615..9d2cd97d1c3a 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -483,13 +483,18 @@ asmlinkage int sunos_uname(struct sunos_utsname __user *name) { int ret; down_read(&uts_sem); - ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1); + ret = copy_to_user(&name->sname[0], &utsname()->sysname[0], + sizeof(name->sname) - 1); if (!ret) { - ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); + ret |= __copy_to_user(&name->nname[0], &utsname()->nodename[0], + sizeof(name->nname) - 1); ret |= __put_user('\0', &name->nname[8]); - ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); - ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); - ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); + ret |= __copy_to_user(&name->rel[0], &utsname()->release[0], + sizeof(name->rel) - 1); + ret |= __copy_to_user(&name->ver[0], &utsname()->version[0], + sizeof(name->ver) - 1); + ret |= __copy_to_user(&name->mach[0], &utsname()->machine[0], + sizeof(name->mach) - 1); } up_read(&uts_sem); return ret ? -EFAULT : 0; diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index c608c947e6c3..89ac435aacc0 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -712,13 +712,13 @@ asmlinkage long sys_getdomainname(char __user *name, int len) down_read(&uts_sem); - nlen = strlen(system_utsname.domainname) + 1; + nlen = strlen(utsname()->domainname) + 1; err = -EINVAL; if (nlen > len) goto out; err = -EFAULT; - if (!copy_to_user(name, system_utsname.domainname, nlen)) + if (!copy_to_user(name, utsname()->domainname, nlen)) err = 0; out: diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index 87ebdf858a3a..953296b73f3f 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -439,16 +439,16 @@ asmlinkage int sunos_uname(struct sunos_utsname __user *name) int ret; down_read(&uts_sem); - ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], + ret = copy_to_user(&name->sname[0], &utsname()->sysname[0], sizeof(name->sname) - 1); - ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], + ret |= copy_to_user(&name->nname[0], &utsname()->nodename[0], sizeof(name->nname) - 1); ret |= put_user('\0', &name->nname[8]); - ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], + ret |= copy_to_user(&name->rel[0], &utsname()->release[0], sizeof(name->rel) - 1); - ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], + ret |= copy_to_user(&name->ver[0], &utsname()->version[0], sizeof(name->ver) - 1); - ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], + ret |= copy_to_user(&name->mach[0], &utsname()->machine[0], sizeof(name->mach) - 1); up_read(&uts_sem); return (ret ? -EFAULT : 0); diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 9c581328e76a..9ed997982f8d 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -249,7 +249,7 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2) /* Let's cheat */ err = set_utsfield(v->sysname, "SunOS", 1, 0); down_read(&uts_sem); - err |= set_utsfield(v->nodename, system_utsname.nodename, + err |= set_utsfield(v->nodename, utsname()->nodename, 1, 1); up_read(&uts_sem); err |= set_utsfield(v->release, "2.6", 0, 0); @@ -273,7 +273,7 @@ asmlinkage int solaris_utsname(u32 buf) /* Why should we not lie a bit? */ down_read(&uts_sem); err = set_utsfield(v->sysname, "SunOS", 0, 0); - err |= set_utsfield(v->nodename, system_utsname.nodename, 1, 1); + err |= set_utsfield(v->nodename, utsname()->nodename, 1, 1); err |= set_utsfield(v->release, "5.6", 0, 0); err |= set_utsfield(v->version, "Generic", 0, 0); err |= set_utsfield(v->machine, machine(), 0, 0); @@ -305,7 +305,7 @@ asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count) case SI_HOSTNAME: r = buffer + 256; down_read(&uts_sem); - for (p = system_utsname.nodename, q = buffer; + for (p = utsname()->nodename, q = buffer; q < r && *p && *p != '.'; *q++ = *p++); up_read(&uts_sem); *q = 0; diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 773a134e7fdb..a67dcbd78de4 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -106,9 +106,9 @@ void mconsole_version(struct mc_request *req) { char version[256]; - sprintf(version, "%s %s %s %s %s", system_utsname.sysname, - system_utsname.nodename, system_utsname.release, - system_utsname.version, system_utsname.machine); + sprintf(version, "%s %s %s %s %s", utsname()->sysname, + utsname()->nodename, utsname()->release, + utsname()->version, utsname()->machine); mconsole_reply(req, version, 0, 0); } diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index 48cf88dd02d4..abf14aaf905f 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -110,7 +110,7 @@ long sys_uname(struct old_utsname __user * name) if (!name) return -EFAULT; down_read(&uts_sem); - err = copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } @@ -126,21 +126,21 @@ long sys_olduname(struct oldold_utsname __user * name) down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname, + error = __copy_to_user(&name->sysname, &utsname()->sysname, __OLD_UTS_LEN); - error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename, + error |= __put_user(0, name->sysname + __OLD_UTS_LEN); + error |= __copy_to_user(&name->nodename, &utsname()->nodename, __OLD_UTS_LEN); - error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release, + error |= __put_user(0, name->nodename + __OLD_UTS_LEN); + error |= __copy_to_user(&name->release, &utsname()->release, __OLD_UTS_LEN); - error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version, + error |= __put_user(0, name->release + __OLD_UTS_LEN); + error |= __copy_to_user(&name->version, &utsname()->version, __OLD_UTS_LEN); - error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine, + error |= __put_user(0, name->version + __OLD_UTS_LEN); + error |= __copy_to_user(&name->machine, &utsname()->machine, __OLD_UTS_LEN); - error |= __put_user(0,name->machine+__OLD_UTS_LEN); + error |= __put_user(0, name->machine + __OLD_UTS_LEN); up_read(&uts_sem); diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index 6fce9f45dfdc..73ce4463f70c 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c @@ -21,7 +21,7 @@ asmlinkage long sys_uname64(struct new_utsname __user * name) { int err; down_read(&uts_sem); - err = copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, utsname(), sizeof (*name)); up_read(&uts_sem); if (personality(current->personality) == PER_LINUX32) err |= copy_to_user(&name->machine, "i686", 5); diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index f280d3665f4b..26a01717cc1a 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -784,36 +784,36 @@ asmlinkage long sys32_olduname(struct oldold_utsname __user * name) if (!name) return -EFAULT; - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) + if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) return -EFAULT; down_read(&uts_sem); - - err = __copy_to_user(&name->sysname,&system_utsname.sysname, + + err = __copy_to_user(&name->sysname,&utsname()->sysname, __OLD_UTS_LEN); err |= __put_user(0,name->sysname+__OLD_UTS_LEN); - err |= __copy_to_user(&name->nodename,&system_utsname.nodename, + err |= __copy_to_user(&name->nodename,&utsname()->nodename, __OLD_UTS_LEN); err |= __put_user(0,name->nodename+__OLD_UTS_LEN); - err |= __copy_to_user(&name->release,&system_utsname.release, + err |= __copy_to_user(&name->release,&utsname()->release, __OLD_UTS_LEN); err |= __put_user(0,name->release+__OLD_UTS_LEN); - err |= __copy_to_user(&name->version,&system_utsname.version, + err |= __copy_to_user(&name->version,&utsname()->version, __OLD_UTS_LEN); err |= __put_user(0,name->version+__OLD_UTS_LEN); - { - char *arch = "x86_64"; - if (personality(current->personality) == PER_LINUX32) - arch = "i686"; + { + char *arch = "x86_64"; + if (personality(current->personality) == PER_LINUX32) + arch = "i686"; - err |= __copy_to_user(&name->machine,arch,strlen(arch)+1); - } - - up_read(&uts_sem); - - err = err ? -EFAULT : 0; - - return err; + err |= __copy_to_user(&name->machine, arch, strlen(arch)+1); + } + + up_read(&uts_sem); + + err = err ? -EFAULT : 0; + + return err; } long sys32_uname(struct old_utsname __user * name) @@ -822,7 +822,7 @@ long sys32_uname(struct old_utsname __user * name) if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, utsname(), sizeof (*name)); up_read(&uts_sem); if (personality(current->personality) == PER_LINUX32) err |= copy_to_user(&name->machine, "i686", 5); diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c index 6449ea8fe756..76bf7c241fe4 100644 --- a/arch/x86_64/kernel/sys_x86_64.c +++ b/arch/x86_64/kernel/sys_x86_64.c @@ -148,7 +148,7 @@ asmlinkage long sys_uname(struct new_utsname __user * name) { int err; down_read(&uts_sem); - err = copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, utsname(), sizeof (*name)); up_read(&uts_sem); if (personality(current->personality) == PER_LINUX32) err |= copy_to_user(&name->machine, "i686", 5); diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c index 4688ba2db84d..37c90ca5b98d 100644 --- a/arch/xtensa/kernel/syscalls.c +++ b/arch/xtensa/kernel/syscalls.c @@ -128,7 +128,7 @@ out: int sys_uname(struct old_utsname * name) { - if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + if (name && !copy_to_user(name, utsname(), sizeof (*name))) return 0; return -EFAULT; } diff --git a/drivers/char/random.c b/drivers/char/random.c index b430a12eb819..07f47a0208a7 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -889,8 +889,8 @@ static void init_std_data(struct entropy_store *r) do_gettimeofday(&tv); add_entropy_words(r, (__u32 *)&tv, sizeof(tv)/4); - add_entropy_words(r, (__u32 *)&system_utsname, - sizeof(system_utsname)/4); + add_entropy_words(r, (__u32 *)utsname(), + sizeof(*(utsname()))/4); } static int __init rand_initialize(void) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0e9ba0b9d71e..c78762051da4 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -772,12 +772,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) separator[1] = 0; memset(vol->source_rfc1001_name,0x20,15); - for(i=0;i < strnlen(system_utsname.nodename,15);i++) { + for(i=0;i < strnlen(utsname()->nodename,15);i++) { /* does not have to be a perfect mapping since the field is informational, only used for servers that do not support port 445 and it can be overridden at mount time */ vol->source_rfc1001_name[i] = - toupper(system_utsname.nodename[i]); + toupper(utsname()->nodename[i]); } vol->source_rfc1001_name[15] = 0; /* null target name indicates to use *SMBSERVR default called name @@ -2153,7 +2153,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, + cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; @@ -2180,8 +2180,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, } strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); - strcpy(bcc_ptr, system_utsname.release); - bcc_ptr += strlen(system_utsname.release) + 1; + strcpy(bcc_ptr, utsname()->release); + bcc_ptr += strlen(utsname()->release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; } @@ -2445,7 +2445,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null terminate Linux version */ @@ -2462,8 +2462,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, } else { /* ASCII */ strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); - strcpy(bcc_ptr, system_utsname.release); - bcc_ptr += strlen(system_utsname.release) + 1; + strcpy(bcc_ptr, utsname()->release); + bcc_ptr += strlen(utsname()->release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; bcc_ptr++; /* empty domain field */ @@ -2836,7 +2836,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null term version string */ @@ -2888,8 +2888,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); - strcpy(bcc_ptr, system_utsname.release); - bcc_ptr += strlen(system_utsname.release) + 1; + strcpy(bcc_ptr, utsname()->release); + bcc_ptr += strlen(utsname()->release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; bcc_ptr++; /* null domain */ diff --git a/fs/exec.c b/fs/exec.c index 6270f8f20a63..d993ea1a81ae 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1318,7 +1318,7 @@ static void format_corename(char *corename, const char *pattern, long signr) case 'h': down_read(&uts_sem); rc = snprintf(out_ptr, out_end - out_ptr, - "%s", system_utsname.nodename); + "%s", utsname()->nodename); up_read(&uts_sem); if (rc > out_end - out_ptr) goto out; diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 271e2165fff6..0116729cec5f 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -129,11 +129,11 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) nlmclnt_next_cookie(&argp->cookie); argp->state = nsm_local_state; memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); - lock->caller = system_utsname.nodename; + lock->caller = utsname()->nodename; lock->oh.data = req->a_owner; lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", (unsigned int)fl->fl_u.nfs_fl.owner->pid, - system_utsname.nodename); + utsname()->nodename); lock->svid = fl->fl_u.nfs_fl.owner->pid; lock->fl.fl_start = fl->fl_start; lock->fl.fl_end = fl->fl_end; diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 5954dcb497e4..a816b920d431 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -145,7 +145,7 @@ xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) */ sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); if (!(p = xdr_encode_string(p, buffer)) - || !(p = xdr_encode_string(p, system_utsname.nodename))) + || !(p = xdr_encode_string(p, utsname()->nodename))) return ERR_PTR(-EIO); *p++ = htonl(argp->prog); *p++ = htonl(argp->vers); diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index c9d419703cf3..93c00ee7189d 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -325,7 +325,7 @@ static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock) { locks_copy_lock(&call->a_args.lock.fl, &lock->fl); memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh)); - call->a_args.lock.caller = system_utsname.nodename; + call->a_args.lock.caller = utsname()->nodename; call->a_args.lock.oh.len = lock->oh.len; /* set default data area */ diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 033ea4ac2c30..61c46facf257 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -515,7 +515,7 @@ nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) */ #define NLM_void_sz 0 #define NLM_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) -#define NLM_caller_sz 1+XDR_QUADLEN(sizeof(system_utsname.nodename)) +#define NLM_caller_sz 1+XDR_QUADLEN(sizeof(utsname()->nodename)) #define NLM_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ) /* #define NLM_owner_sz 1+XDR_QUADLEN(NLM_MAXOWNER) */ #define NLM_fhandle_sz 1+XDR_QUADLEN(NFS2_FHSIZE) diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index c0a754ecdee6..1d656a645199 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -312,7 +312,7 @@ static int __init root_nfs_name(char *name) /* Override them by options set on kernel command-line */ root_nfs_parse(name, buf); - cp = system_utsname.nodename; + cp = utsname()->nodename; if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) { printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n"); return -1; diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h index db4344d9f73f..3a05436f31c0 100644 --- a/include/asm-i386/elf.h +++ b/include/asm-i386/elf.h @@ -112,7 +112,7 @@ typedef struct user_fxsr_struct elf_fpxregset_t; For the moment, we have only optimizations for the Intel generations, but that could change... */ -#define ELF_PLATFORM (system_utsname.machine) +#define ELF_PLATFORM (utsname()->machine) #define SET_PERSONALITY(ex, ibcs2) do { } while (0) diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 0d92c468d55a..47b7dbd647a6 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -80,7 +80,7 @@ struct nlm_wait; /* * Memory chunk for NLM client RPC request. */ -#define NLMCLNT_OHSIZE (sizeof(system_utsname.nodename)+10) +#define NLMCLNT_OHSIZE (sizeof(utsname()->nodename)+10) struct nlm_rqst { unsigned int a_flags; /* initial RPC task flags */ struct nlm_host * a_host; /* host handle */ diff --git a/kernel/sys.c b/kernel/sys.c index 398d57923f95..3a4776e8f16e 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1655,7 +1655,7 @@ asmlinkage long sys_newuname(struct new_utsname __user * name) int errno = 0; down_read(&uts_sem); - if (copy_to_user(name,&system_utsname,sizeof *name)) + if (copy_to_user(name, utsname(), sizeof *name)) errno = -EFAULT; up_read(&uts_sem); return errno; @@ -1673,8 +1673,8 @@ asmlinkage long sys_sethostname(char __user *name, int len) down_write(&uts_sem); errno = -EFAULT; if (!copy_from_user(tmp, name, len)) { - memcpy(system_utsname.nodename, tmp, len); - system_utsname.nodename[len] = 0; + memcpy(utsname()->nodename, tmp, len); + utsname()->nodename[len] = 0; errno = 0; } up_write(&uts_sem); @@ -1690,11 +1690,11 @@ asmlinkage long sys_gethostname(char __user *name, int len) if (len < 0) return -EINVAL; down_read(&uts_sem); - i = 1 + strlen(system_utsname.nodename); + i = 1 + strlen(utsname()->nodename); if (i > len) i = len; errno = 0; - if (copy_to_user(name, system_utsname.nodename, i)) + if (copy_to_user(name, utsname()->nodename, i)) errno = -EFAULT; up_read(&uts_sem); return errno; @@ -1719,8 +1719,8 @@ asmlinkage long sys_setdomainname(char __user *name, int len) down_write(&uts_sem); errno = -EFAULT; if (!copy_from_user(tmp, name, len)) { - memcpy(system_utsname.domainname, tmp, len); - system_utsname.domainname[len] = 0; + memcpy(utsname()->domainname, tmp, len); + utsname()->domainname[len] = 0; errno = 0; } up_write(&uts_sem); diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 1fbb38415b19..99d50065aa79 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -805,7 +805,7 @@ static void __init ic_do_bootp_ext(u8 *ext) } break; case 12: /* Host name */ - ic_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN); + ic_bootp_string(utsname()->nodename, ext+1, *ext, __NEW_UTS_LEN); ic_host_name_set = 1; break; case 15: /* Domain name (DNS) */ @@ -816,7 +816,7 @@ static void __init ic_do_bootp_ext(u8 *ext) ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path)); break; case 40: /* NIS Domain name (_not_ DNS) */ - ic_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN); + ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN); break; } } @@ -1368,7 +1368,7 @@ static int __init ip_auto_config(void) printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask)); printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway)); printk(",\n host=%s, domain=%s, nis-domain=%s", - system_utsname.nodename, ic_domain, system_utsname.domainname); + utsname()->nodename, ic_domain, utsname()->domainname); printk(",\n bootserver=%u.%u.%u.%u", NIPQUAD(ic_servaddr)); printk(", rootserver=%u.%u.%u.%u", NIPQUAD(root_server_addr)); printk(", rootpath=%s", root_server_path); @@ -1478,11 +1478,11 @@ static int __init ip_auto_config_setup(char *addrs) case 4: if ((dp = strchr(ip, '.'))) { *dp++ = '\0'; - strlcpy(system_utsname.domainname, dp, - sizeof(system_utsname.domainname)); + strlcpy(utsname()->domainname, dp, + sizeof(utsname()->domainname)); } - strlcpy(system_utsname.nodename, ip, - sizeof(system_utsname.nodename)); + strlcpy(utsname()->nodename, ip, + sizeof(utsname()->nodename)); ic_host_name_set = 1; break; case 5: diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 124ff0ceb55b..78696f2dc7d6 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -161,10 +161,10 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s } /* save the nodename */ - clnt->cl_nodelen = strlen(system_utsname.nodename); + clnt->cl_nodelen = strlen(utsname()->nodename); if (clnt->cl_nodelen > UNX_MAXNODENAME) clnt->cl_nodelen = UNX_MAXNODENAME; - memcpy(clnt->cl_nodename, system_utsname.nodename, clnt->cl_nodelen); + memcpy(clnt->cl_nodename, utsname()->nodename, clnt->cl_nodelen); return clnt; out_no_auth: -- cgit v1.2.3 From 4865ecf1315b450ab3317a745a6678c04d311e40 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Mon, 2 Oct 2006 02:18:14 -0700 Subject: [PATCH] namespaces: utsname: implement utsname namespaces This patch defines the uts namespace and some manipulators. Adds the uts namespace to task_struct, and initializes a system-wide init namespace. It leaves a #define for system_utsname so sysctl will compile. This define will be removed in a separate patch. [akpm@osdl.org: build fix, cleanup] Signed-off-by: Serge Hallyn Cc: Kirill Korotaev Cc: "Eric W. Biederman" Cc: Herbert Poetzl Cc: Andrey Savochkin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/init_task.h | 2 ++ include/linux/nsproxy.h | 2 ++ include/linux/sched.h | 1 + include/linux/utsname.h | 40 +++++++++++++++++++++++++++++++++++++--- init/Kconfig | 8 ++++++++ init/version.c | 23 ++++++++++++++--------- kernel/Makefile | 1 + kernel/nsproxy.c | 14 ++++++++++++++ kernel/utsname.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 121 insertions(+), 12 deletions(-) create mode 100644 kernel/utsname.c (limited to 'include/linux') diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 4865348ca8bd..e08531ec32f0 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #define INIT_FDTABLE \ @@ -72,6 +73,7 @@ extern struct nsproxy init_nsproxy; #define INIT_NSPROXY(nsproxy) { \ .count = ATOMIC_INIT(1), \ .nslock = SPIN_LOCK_UNLOCKED, \ + .uts_ns = &init_uts_ns, \ .namespace = NULL, \ } diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index 7ebe66670c59..9c2e0ad508db 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h @@ -5,6 +5,7 @@ #include struct namespace; +struct uts_namespace; /* * A structure to contain pointers to all per-process @@ -21,6 +22,7 @@ struct namespace; struct nsproxy { atomic_t count; spinlock_t nslock; + struct uts_namespace *uts_ns; struct namespace *namespace; }; extern struct nsproxy init_nsproxy; diff --git a/include/linux/sched.h b/include/linux/sched.h index 670b89a20070..46d6f5be72f2 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -753,6 +753,7 @@ static inline void prefetch_stack(struct task_struct *t) { } struct audit_context; /* See audit.c */ struct mempolicy; struct pipe_inode_info; +struct uts_namespace; enum sleep_type { SLEEP_NORMAL, diff --git a/include/linux/utsname.h b/include/linux/utsname.h index 77e97a5755d9..afa54e1542b3 100644 --- a/include/linux/utsname.h +++ b/include/linux/utsname.h @@ -1,6 +1,11 @@ #ifndef _LINUX_UTSNAME_H #define _LINUX_UTSNAME_H +#include +#include +#include +#include + #define __OLD_UTS_LEN 8 struct oldold_utsname { @@ -30,17 +35,46 @@ struct new_utsname { char domainname[65]; }; -extern struct new_utsname system_utsname; +struct uts_namespace { + struct kref kref; + struct new_utsname name; +}; +extern struct uts_namespace init_uts_ns; + +static inline void get_uts_ns(struct uts_namespace *ns) +{ + kref_get(&ns->kref); +} + +#ifdef CONFIG_UTS_NS +extern int copy_utsname(int flags, struct task_struct *tsk); +extern void free_uts_ns(struct kref *kref); + +static inline void put_uts_ns(struct uts_namespace *ns) +{ + kref_put(&ns->kref, free_uts_ns); +} +#else +static inline int copy_utsname(int flags, struct task_struct *tsk) +{ + return 0; +} +static inline void put_uts_ns(struct uts_namespace *ns) +{ +} +#endif static inline struct new_utsname *utsname(void) { - return &system_utsname; + return ¤t->nsproxy->uts_ns->name; } static inline struct new_utsname *init_utsname(void) { - return &system_utsname; + return &init_uts_ns.name; } +#define system_utsname init_uts_ns.name + extern struct rw_semaphore uts_sem; #endif diff --git a/init/Kconfig b/init/Kconfig index f7a04d0daf07..b0ea97554473 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -182,6 +182,14 @@ config TASK_DELAY_ACCT Say N if unsure. +config UTS_NS + bool "UTS Namespaces" + default n + help + Support uts namespaces. This allows containers, i.e. + vservers, to use uts namespaces to provide different + uts info for different servers. If unsure, say N. + config AUDIT bool "Auditing support" depends on NET diff --git a/init/version.c b/init/version.c index e290802c6bd2..8f28344d9c70 100644 --- a/init/version.c +++ b/init/version.c @@ -12,22 +12,27 @@ #include #include #include +#include #define version(a) Version_ ## a #define version_string(a) version(a) int version_string(LINUX_VERSION_CODE); -struct new_utsname system_utsname = { - .sysname = UTS_SYSNAME, - .nodename = UTS_NODENAME, - .release = UTS_RELEASE, - .version = UTS_VERSION, - .machine = UTS_MACHINE, - .domainname = UTS_DOMAINNAME, +struct uts_namespace init_uts_ns = { + .kref = { + .refcount = ATOMIC_INIT(2), + }, + .name = { + .sysname = UTS_SYSNAME, + .nodename = UTS_NODENAME, + .release = UTS_RELEASE, + .version = UTS_VERSION, + .machine = UTS_MACHINE, + .domainname = UTS_DOMAINNAME, + }, }; - -EXPORT_SYMBOL(system_utsname); +EXPORT_SYMBOL_GPL(init_uts_ns); const char linux_banner[] = "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" diff --git a/kernel/Makefile b/kernel/Makefile index 6ec53009b866..d948ca12acf0 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_RELAY) += relay.o +obj-$(CONFIG_UTS_NS) += utsname.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index e10385c17f73..47c19280c55b 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -14,6 +14,7 @@ #include #include #include +#include struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); @@ -59,6 +60,8 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) if (ns) { if (ns->namespace) get_namespace(ns->namespace); + if (ns->uts_ns) + get_uts_ns(ns->uts_ns); } return ns; @@ -97,6 +100,15 @@ int copy_namespaces(int flags, struct task_struct *tsk) goto out; } + err = copy_utsname(flags, tsk); + if (err) { + if (new_ns->namespace) + put_namespace(new_ns->namespace); + tsk->nsproxy = old_ns; + put_nsproxy(new_ns); + goto out; + } + out: put_nsproxy(old_ns); return err; @@ -106,5 +118,7 @@ void free_nsproxy(struct nsproxy *ns) { if (ns->namespace) put_namespace(ns->namespace); + if (ns->uts_ns) + put_uts_ns(ns->uts_ns); kfree(ns); } diff --git a/kernel/utsname.c b/kernel/utsname.c new file mode 100644 index 000000000000..1824384ecfa3 --- /dev/null +++ b/kernel/utsname.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004 IBM Corporation + * + * Author: Serge Hallyn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#include +#include +#include +#include + +/* + * Copy task tsk's utsname namespace, or clone it if flags + * specifies CLONE_NEWUTS. In latter case, changes to the + * utsname of this process won't be seen by parent, and vice + * versa. + */ +int copy_utsname(int flags, struct task_struct *tsk) +{ + struct uts_namespace *old_ns = tsk->nsproxy->uts_ns; + int err = 0; + + if (!old_ns) + return 0; + + get_uts_ns(old_ns); + + return err; +} + +void free_uts_ns(struct kref *kref) +{ + struct uts_namespace *ns; + + ns = container_of(kref, struct uts_namespace, kref); + kfree(ns); +} -- cgit v1.2.3 From bf47fdcda65b44dbd674eeedcaa06e0aa28a5a00 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Mon, 2 Oct 2006 02:18:16 -0700 Subject: [PATCH] namespaces: utsname: remove system_utsname The system_utsname isn't needed now that kernel/sysctl.c is fixed. Nuke it. Signed-off-by: Serge E. Hallyn Cc: Kirill Korotaev Cc: "Eric W. Biederman" Cc: Herbert Poetzl Cc: Andrey Savochkin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/utsname.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/utsname.h b/include/linux/utsname.h index afa54e1542b3..99e522369f4f 100644 --- a/include/linux/utsname.h +++ b/include/linux/utsname.h @@ -74,7 +74,5 @@ static inline struct new_utsname *init_utsname(void) return &init_uts_ns.name; } -#define system_utsname init_uts_ns.name - extern struct rw_semaphore uts_sem; #endif -- cgit v1.2.3 From 071df104f808b8195c40643dcb4d060681742e29 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Mon, 2 Oct 2006 02:18:17 -0700 Subject: [PATCH] namespaces: utsname: implement CLONE_NEWUTS flag Implement a CLONE_NEWUTS flag, and use it at clone and sys_unshare. [clg@fr.ibm.com: IPC unshare fix] [bunk@stusta.de: cleanup] Signed-off-by: Serge Hallyn Cc: Kirill Korotaev Cc: "Eric W. Biederman" Cc: Herbert Poetzl Cc: Andrey Savochkin Signed-off-by: Adrian Bunk Signed-off-by: Cedric Le Goater Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 + include/linux/utsname.h | 11 ++++++++++ kernel/fork.c | 20 ++++++++++++++++--- kernel/nsproxy.c | 2 +- kernel/utsname.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 46d6f5be72f2..a973e7012315 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -24,6 +24,7 @@ #define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */ #define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ #define CLONE_STOPPED 0x02000000 /* Start in stopped state */ +#define CLONE_NEWUTS 0x04000000 /* New utsname group? */ /* * Scheduling policies diff --git a/include/linux/utsname.h b/include/linux/utsname.h index 99e522369f4f..02e4b6972064 100644 --- a/include/linux/utsname.h +++ b/include/linux/utsname.h @@ -47,6 +47,8 @@ static inline void get_uts_ns(struct uts_namespace *ns) } #ifdef CONFIG_UTS_NS +extern int unshare_utsname(unsigned long unshare_flags, + struct uts_namespace **new_uts); extern int copy_utsname(int flags, struct task_struct *tsk); extern void free_uts_ns(struct kref *kref); @@ -55,6 +57,15 @@ static inline void put_uts_ns(struct uts_namespace *ns) kref_put(&ns->kref, free_uts_ns); } #else +static inline int unshare_utsname(unsigned long unshare_flags, + struct uts_namespace **new_uts) +{ + if (unshare_flags & CLONE_NEWUTS) + return -EINVAL; + + return 0; +} + static inline int copy_utsname(int flags, struct task_struct *tsk) { return 0; diff --git a/kernel/fork.c b/kernel/fork.c index 33fcf0733ca6..c08cf05dd59b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1607,13 +1607,14 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) struct files_struct *fd, *new_fd = NULL; struct sem_undo_list *new_ulist = NULL; struct nsproxy *new_nsproxy, *old_nsproxy; + struct uts_namespace *uts, *new_uts = NULL; check_unshare_flags(&unshare_flags); /* Return -EINVAL for all unsupported flags */ err = -EINVAL; if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| - CLONE_VM|CLONE_FILES|CLONE_SYSVSEM)) + CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|CLONE_NEWUTS)) goto bad_unshare_out; if ((err = unshare_thread(unshare_flags))) @@ -1630,14 +1631,17 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) goto bad_unshare_cleanup_vm; if ((err = unshare_semundo(unshare_flags, &new_ulist))) goto bad_unshare_cleanup_fd; + if ((err = unshare_utsname(unshare_flags, &new_uts))) + goto bad_unshare_cleanup_semundo; - if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist) { + if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist || + new_uts) { old_nsproxy = current->nsproxy; new_nsproxy = dup_namespaces(old_nsproxy); if (!new_nsproxy) { err = -ENOMEM; - goto bad_unshare_cleanup_semundo; + goto bad_unshare_cleanup_uts; } task_lock(current); @@ -1676,10 +1680,20 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) new_fd = fd; } + if (new_uts) { + uts = current->nsproxy->uts_ns; + current->nsproxy->uts_ns = new_uts; + new_uts = uts; + } + task_unlock(current); put_nsproxy(old_nsproxy); } +bad_unshare_cleanup_uts: + if (new_uts) + put_uts_ns(new_uts); + bad_unshare_cleanup_semundo: bad_unshare_cleanup_fd: if (new_fd) diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 47c19280c55b..8246813335cc 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -82,7 +82,7 @@ int copy_namespaces(int flags, struct task_struct *tsk) get_nsproxy(old_ns); - if (!(flags & CLONE_NEWNS)) + if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS))) return 0; new_ns = clone_namespaces(old_ns); diff --git a/kernel/utsname.c b/kernel/utsname.c index 1824384ecfa3..c859164a6993 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c @@ -14,6 +14,41 @@ #include #include +/* + * Clone a new ns copying an original utsname, setting refcount to 1 + * @old_ns: namespace to clone + * Return NULL on error (failure to kmalloc), new ns otherwise + */ +static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns) +{ + struct uts_namespace *ns; + + ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); + if (ns) { + memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); + kref_init(&ns->kref); + } + return ns; +} + +/* + * unshare the current process' utsname namespace. + * called only in sys_unshare() + */ +int unshare_utsname(unsigned long unshare_flags, struct uts_namespace **new_uts) +{ + if (unshare_flags & CLONE_NEWUTS) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + *new_uts = clone_uts_ns(current->nsproxy->uts_ns); + if (!*new_uts) + return -ENOMEM; + } + + return 0; +} + /* * Copy task tsk's utsname namespace, or clone it if flags * specifies CLONE_NEWUTS. In latter case, changes to the @@ -23,6 +58,7 @@ int copy_utsname(int flags, struct task_struct *tsk) { struct uts_namespace *old_ns = tsk->nsproxy->uts_ns; + struct uts_namespace *new_ns; int err = 0; if (!old_ns) @@ -30,6 +66,23 @@ int copy_utsname(int flags, struct task_struct *tsk) get_uts_ns(old_ns); + if (!(flags & CLONE_NEWUTS)) + return 0; + + if (!capable(CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } + + new_ns = clone_uts_ns(old_ns); + if (!new_ns) { + err = -ENOMEM; + goto out; + } + tsk->nsproxy->uts_ns = new_ns; + +out: + put_uts_ns(old_ns); return err; } -- cgit v1.2.3 From 25b21cb2f6d69b0475b134e0a3e8e269137270fa Mon Sep 17 00:00:00 2001 From: Kirill Korotaev Date: Mon, 2 Oct 2006 02:18:19 -0700 Subject: [PATCH] IPC namespace core This patch set allows to unshare IPCs and have a private set of IPC objects (sem, shm, msg) inside namespace. Basically, it is another building block of containers functionality. This patch implements core IPC namespace changes: - ipc_namespace structure - new config option CONFIG_IPC_NS - adds CLONE_NEWIPC flag - unshare support [clg@fr.ibm.com: small fix for unshare of ipc namespace] [akpm@osdl.org: build fix] Signed-off-by: Pavel Emelianov Signed-off-by: Kirill Korotaev Signed-off-by: Cedric Le Goater Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/init_task.h | 1 + include/linux/ipc.h | 36 ++++++++++++++++++++++++++++++++++++ include/linux/nsproxy.h | 2 ++ include/linux/sched.h | 1 + init/Kconfig | 9 +++++++++ kernel/fork.c | 22 ++++++++++++++++++---- kernel/nsproxy.c | 41 ++++++++++++++++++++++++++++------------- 7 files changed, 95 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/include/linux/init_task.h b/include/linux/init_task.h index e08531ec32f0..ceecf69dfa39 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -74,6 +74,7 @@ extern struct nsproxy init_nsproxy; .count = ATOMIC_INIT(1), \ .nslock = SPIN_LOCK_UNLOCKED, \ .uts_ns = &init_uts_ns, \ + .ipc_ns = &init_ipc_ns, \ .namespace = NULL, \ } diff --git a/include/linux/ipc.h b/include/linux/ipc.h index b291189737e7..36027b10f283 100644 --- a/include/linux/ipc.h +++ b/include/linux/ipc.h @@ -2,6 +2,7 @@ #define _LINUX_IPC_H #include +#include #define IPC_PRIVATE ((__kernel_key_t) 0) @@ -68,6 +69,41 @@ struct kern_ipc_perm void *security; }; +struct ipc_ids; +struct ipc_namespace { + struct kref kref; + struct ipc_ids *ids[3]; + + int sem_ctls[4]; + int used_sems; + + int msg_ctlmax; + int msg_ctlmnb; + int msg_ctlmni; + + size_t shm_ctlmax; + size_t shm_ctlall; + int shm_ctlmni; + int shm_tot; +}; + +extern struct ipc_namespace init_ipc_ns; +extern void free_ipc_ns(struct kref *kref); +extern int copy_ipcs(unsigned long flags, struct task_struct *tsk); +extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns); + +static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) +{ + if (ns) + kref_get(&ns->kref); + return ns; +} + +static inline void put_ipc_ns(struct ipc_namespace *ns) +{ + kref_put(&ns->kref, free_ipc_ns); +} + #endif /* __KERNEL__ */ #endif /* _LINUX_IPC_H */ diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index 9c2e0ad508db..f6baecdeecd6 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h @@ -6,6 +6,7 @@ struct namespace; struct uts_namespace; +struct ipc_namespace; /* * A structure to contain pointers to all per-process @@ -23,6 +24,7 @@ struct nsproxy { atomic_t count; spinlock_t nslock; struct uts_namespace *uts_ns; + struct ipc_namespace *ipc_ns; struct namespace *namespace; }; extern struct nsproxy init_nsproxy; diff --git a/include/linux/sched.h b/include/linux/sched.h index a973e7012315..9ba959e34266 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -25,6 +25,7 @@ #define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ #define CLONE_STOPPED 0x02000000 /* Start in stopped state */ #define CLONE_NEWUTS 0x04000000 /* New utsname group? */ +#define CLONE_NEWIPC 0x08000000 /* New ipcs */ /* * Scheduling policies diff --git a/init/Kconfig b/init/Kconfig index b0ea97554473..10382931eead 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -115,6 +115,15 @@ config SYSVIPC section 6.4 of the Linux Programmer's Guide, available from . +config IPC_NS + bool "IPC Namespaces" + depends on SYSVIPC + default n + help + Support ipc namespaces. This allows containers, i.e. virtual + environments, to use ipc namespaces to provide different ipc + objects for different servers. If unsure, say N. + config POSIX_MQUEUE bool "POSIX Message Queues" depends on NET && EXPERIMENTAL diff --git a/kernel/fork.c b/kernel/fork.c index 208dd99f13bc..d6cc56558507 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1608,13 +1608,15 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) struct sem_undo_list *new_ulist = NULL; struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL; struct uts_namespace *uts, *new_uts = NULL; + struct ipc_namespace *ipc, *new_ipc = NULL; check_unshare_flags(&unshare_flags); /* Return -EINVAL for all unsupported flags */ err = -EINVAL; if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| - CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|CLONE_NEWUTS)) + CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| + CLONE_NEWUTS|CLONE_NEWIPC)) goto bad_unshare_out; if ((err = unshare_thread(unshare_flags))) @@ -1633,18 +1635,20 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) goto bad_unshare_cleanup_fd; if ((err = unshare_utsname(unshare_flags, &new_uts))) goto bad_unshare_cleanup_semundo; + if ((err = unshare_ipcs(unshare_flags, &new_ipc))) + goto bad_unshare_cleanup_uts; - if (new_ns || new_uts) { + if (new_ns || new_uts || new_ipc) { old_nsproxy = current->nsproxy; new_nsproxy = dup_namespaces(old_nsproxy); if (!new_nsproxy) { err = -ENOMEM; - goto bad_unshare_cleanup_uts; + goto bad_unshare_cleanup_ipc; } } if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist || - new_uts) { + new_uts || new_ipc) { task_lock(current); @@ -1692,12 +1696,22 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) new_uts = uts; } + if (new_ipc) { + ipc = current->nsproxy->ipc_ns; + current->nsproxy->ipc_ns = new_ipc; + new_ipc = ipc; + } + task_unlock(current); } if (new_nsproxy) put_nsproxy(new_nsproxy); +bad_unshare_cleanup_ipc: + if (new_ipc) + put_ipc_ns(new_ipc); + bad_unshare_cleanup_uts: if (new_uts) put_uts_ns(new_uts); diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 8246813335cc..8d6c852dc51e 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -7,6 +7,10 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2 of the * License. + * + * Jun 2006 - namespaces support + * OpenVZ, SWsoft Inc. + * Pavel Emelianov */ #include @@ -62,6 +66,8 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) get_namespace(ns->namespace); if (ns->uts_ns) get_uts_ns(ns->uts_ns); + if (ns->ipc_ns) + get_ipc_ns(ns->ipc_ns); } return ns; @@ -82,7 +88,7 @@ int copy_namespaces(int flags, struct task_struct *tsk) get_nsproxy(old_ns); - if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS))) + if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC))) return 0; new_ns = clone_namespaces(old_ns); @@ -94,24 +100,31 @@ int copy_namespaces(int flags, struct task_struct *tsk) tsk->nsproxy = new_ns; err = copy_namespace(flags, tsk); - if (err) { - tsk->nsproxy = old_ns; - put_nsproxy(new_ns); - goto out; - } + if (err) + goto out_ns; err = copy_utsname(flags, tsk); - if (err) { - if (new_ns->namespace) - put_namespace(new_ns->namespace); - tsk->nsproxy = old_ns; - put_nsproxy(new_ns); - goto out; - } + if (err) + goto out_uts; + + err = copy_ipcs(flags, tsk); + if (err) + goto out_ipc; out: put_nsproxy(old_ns); return err; + +out_ipc: + if (new_ns->uts_ns) + put_uts_ns(new_ns->uts_ns); +out_uts: + if (new_ns->namespace) + put_namespace(new_ns->namespace); +out_ns: + tsk->nsproxy = old_ns; + put_nsproxy(new_ns); + goto out; } void free_nsproxy(struct nsproxy *ns) @@ -120,5 +133,7 @@ void free_nsproxy(struct nsproxy *ns) put_namespace(ns->namespace); if (ns->uts_ns) put_uts_ns(ns->uts_ns); + if (ns->ipc_ns) + put_ipc_ns(ns->ipc_ns); kfree(ns); } -- cgit v1.2.3 From 73ea41302bab5e02c9e86ab15c509494a550f1db Mon Sep 17 00:00:00 2001 From: Kirill Korotaev Date: Mon, 2 Oct 2006 02:18:20 -0700 Subject: [PATCH] IPC namespace - utils This patch adds basic IPC namespace functionality to IPC utils: - init_ipc_ns - copy/clone/unshare/free IPC ns - /proc preparations Signed-off-by: Pavel Emelianov Signed-off-by: Kirill Korotaev Cc: "Eric W. Biederman" Cc: Cedric Le Goater Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/init_task.h | 3 +- include/linux/ipc.h | 18 +++++++ ipc/util.c | 132 ++++++++++++++++++++++++++++++++++++++++++---- ipc/util.h | 24 +++++++-- kernel/fork.c | 10 ++++ 5 files changed, 173 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/init_task.h b/include/linux/init_task.h index ceecf69dfa39..33c5daacc743 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -6,6 +6,7 @@ #include #include #include +#include #define INIT_FDTABLE \ { \ @@ -74,8 +75,8 @@ extern struct nsproxy init_nsproxy; .count = ATOMIC_INIT(1), \ .nslock = SPIN_LOCK_UNLOCKED, \ .uts_ns = &init_uts_ns, \ - .ipc_ns = &init_ipc_ns, \ .namespace = NULL, \ + INIT_IPC_NS(ipc_ns) \ } #define INIT_SIGHAND(sighand) { \ diff --git a/include/linux/ipc.h b/include/linux/ipc.h index 36027b10f283..d9e2b3f36c35 100644 --- a/include/linux/ipc.h +++ b/include/linux/ipc.h @@ -88,20 +88,38 @@ struct ipc_namespace { }; extern struct ipc_namespace init_ipc_ns; + +#ifdef CONFIG_SYSVIPC +#define INIT_IPC_NS(ns) .ns = &init_ipc_ns, +#else +#define INIT_IPC_NS(ns) +#endif + +#ifdef CONFIG_IPC_NS extern void free_ipc_ns(struct kref *kref); extern int copy_ipcs(unsigned long flags, struct task_struct *tsk); extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns); +#else +static inline int copy_ipcs(unsigned long flags, struct task_struct *tsk) +{ + return 0; +} +#endif static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) { +#ifdef CONFIG_IPC_NS if (ns) kref_get(&ns->kref); +#endif return ns; } static inline void put_ipc_ns(struct ipc_namespace *ns) { +#ifdef CONFIG_IPC_NS kref_put(&ns->kref, free_ipc_ns); +#endif } #endif /* __KERNEL__ */ diff --git a/ipc/util.c b/ipc/util.c index 67b6d178db6e..42479e4eec59 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -12,6 +12,9 @@ * Mingming Cao * Mar 2006 - support for audit of ipc object properties * Dustin Kirkland + * Jun 2006 - namespaces ssupport + * OpenVZ, SWsoft Inc. + * Pavel Emelianov */ #include @@ -29,6 +32,7 @@ #include #include #include +#include #include @@ -37,10 +41,111 @@ struct ipc_proc_iface { const char *path; const char *header; - struct ipc_ids *ids; + int ids; int (*show)(struct seq_file *, void *); }; +struct ipc_namespace init_ipc_ns = { + .kref = { + .refcount = ATOMIC_INIT(2), + }, +}; + +#ifdef CONFIG_IPC_NS +static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) +{ + int err; + struct ipc_namespace *ns; + + err = -ENOMEM; + ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL); + if (ns == NULL) + goto err_mem; + + err = sem_init_ns(ns); + if (err) + goto err_sem; + err = msg_init_ns(ns); + if (err) + goto err_msg; + err = shm_init_ns(ns); + if (err) + goto err_shm; + + kref_init(&ns->kref); + return ns; + +err_shm: + msg_exit_ns(ns); +err_msg: + sem_exit_ns(ns); +err_sem: + kfree(ns); +err_mem: + return ERR_PTR(err); +} + +int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc) +{ + struct ipc_namespace *new; + + if (unshare_flags & CLONE_NEWIPC) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + new = clone_ipc_ns(current->nsproxy->ipc_ns); + if (IS_ERR(new)) + return PTR_ERR(new); + + *new_ipc = new; + } + + return 0; +} + +int copy_ipcs(unsigned long flags, struct task_struct *tsk) +{ + struct ipc_namespace *old_ns = tsk->nsproxy->ipc_ns; + struct ipc_namespace *new_ns; + int err = 0; + + if (!old_ns) + return 0; + + get_ipc_ns(old_ns); + + if (!(flags & CLONE_NEWIPC)) + return 0; + + if (!capable(CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } + + new_ns = clone_ipc_ns(old_ns); + if (!new_ns) { + err = -ENOMEM; + goto out; + } + + tsk->nsproxy->ipc_ns = new_ns; +out: + put_ipc_ns(old_ns); + return err; +} + +void free_ipc_ns(struct kref *kref) +{ + struct ipc_namespace *ns; + + ns = container_of(kref, struct ipc_namespace, kref); + sem_exit_ns(ns); + msg_exit_ns(ns); + shm_exit_ns(ns); + kfree(ns); +} +#endif + /** * ipc_init - initialise IPC subsystem * @@ -67,7 +172,7 @@ __initcall(ipc_init); * array itself. */ -void __init ipc_init_ids(struct ipc_ids* ids, int size) +void __ipc_init ipc_init_ids(struct ipc_ids* ids, int size) { int i; @@ -110,8 +215,7 @@ static struct file_operations sysvipc_proc_fops; * @show: show routine. */ void __init ipc_init_proc_interface(const char *path, const char *header, - struct ipc_ids *ids, - int (*show)(struct seq_file *, void *)) + int ids, int (*show)(struct seq_file *, void *)) { struct proc_dir_entry *pde; struct ipc_proc_iface *iface; @@ -635,6 +739,9 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) struct ipc_proc_iface *iface = s->private; struct kern_ipc_perm *ipc = it; loff_t p; + struct ipc_ids *ids; + + ids = current->nsproxy->ipc_ns->ids[iface->ids]; /* If we had an ipc id locked before, unlock it */ if (ipc && ipc != SEQ_START_TOKEN) @@ -644,8 +751,8 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) * p = *pos - 1 (because id 0 starts at position 1) * + 1 (because we increment the position by one) */ - for (p = *pos; p <= iface->ids->max_id; p++) { - if ((ipc = ipc_lock(iface->ids, p)) != NULL) { + for (p = *pos; p <= ids->max_id; p++) { + if ((ipc = ipc_lock(ids, p)) != NULL) { *pos = p + 1; return ipc; } @@ -664,12 +771,15 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) struct ipc_proc_iface *iface = s->private; struct kern_ipc_perm *ipc; loff_t p; + struct ipc_ids *ids; + + ids = current->nsproxy->ipc_ns->ids[iface->ids]; /* * Take the lock - this will be released by the corresponding * call to stop(). */ - mutex_lock(&iface->ids->mutex); + mutex_lock(&ids->mutex); /* pos < 0 is invalid */ if (*pos < 0) @@ -680,8 +790,8 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) return SEQ_START_TOKEN; /* Find the (pos-1)th ipc */ - for (p = *pos - 1; p <= iface->ids->max_id; p++) { - if ((ipc = ipc_lock(iface->ids, p)) != NULL) { + for (p = *pos - 1; p <= ids->max_id; p++) { + if ((ipc = ipc_lock(ids, p)) != NULL) { *pos = p + 1; return ipc; } @@ -693,13 +803,15 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it) { struct kern_ipc_perm *ipc = it; struct ipc_proc_iface *iface = s->private; + struct ipc_ids *ids; /* If we had a locked segment, release it */ if (ipc && ipc != SEQ_START_TOKEN) ipc_unlock(ipc); + ids = current->nsproxy->ipc_ns->ids[iface->ids]; /* Release the lock we took in start() */ - mutex_unlock(&iface->ids->mutex); + mutex_unlock(&ids->mutex); } static int sysvipc_proc_show(struct seq_file *s, void *it) diff --git a/ipc/util.h b/ipc/util.h index 0181553d31d8..c8fd6b9d77b5 100644 --- a/ipc/util.h +++ b/ipc/util.h @@ -3,6 +3,8 @@ * Copyright (C) 1999 Christoph Rohland * * ipc helper functions (c) 1999 Manfred Spraul + * namespaces support. 2006 OpenVZ, SWsoft Inc. + * Pavel Emelianov */ #ifndef _IPC_UTIL_H @@ -15,6 +17,14 @@ void sem_init (void); void msg_init (void); void shm_init (void); +int sem_init_ns(struct ipc_namespace *ns); +int msg_init_ns(struct ipc_namespace *ns); +int shm_init_ns(struct ipc_namespace *ns); + +void sem_exit_ns(struct ipc_namespace *ns); +void msg_exit_ns(struct ipc_namespace *ns); +void shm_exit_ns(struct ipc_namespace *ns); + struct ipc_id_ary { int size; struct kern_ipc_perm *p[0]; @@ -31,15 +41,23 @@ struct ipc_ids { }; struct seq_file; -void __init ipc_init_ids(struct ipc_ids* ids, int size); +#ifdef CONFIG_IPC_NS +#define __ipc_init +#else +#define __ipc_init __init +#endif +void __ipc_init ipc_init_ids(struct ipc_ids *ids, int size); #ifdef CONFIG_PROC_FS void __init ipc_init_proc_interface(const char *path, const char *header, - struct ipc_ids *ids, - int (*show)(struct seq_file *, void *)); + int ids, int (*show)(struct seq_file *, void *)); #else #define ipc_init_proc_interface(path, header, ids, show) do {} while (0) #endif +#define IPC_SEM_IDS 0 +#define IPC_MSG_IDS 1 +#define IPC_SHM_IDS 2 + /* must be called with ids->mutex acquired.*/ int ipc_findkey(struct ipc_ids* ids, key_t key); int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size); diff --git a/kernel/fork.c b/kernel/fork.c index d6cc56558507..7dc6140baac6 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1589,6 +1589,16 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n return 0; } +#ifndef CONFIG_IPC_NS +static inline int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns) +{ + if (flags & CLONE_NEWIPC) + return -EINVAL; + + return 0; +} +#endif + /* * unshare allows a process to 'unshare' part of the process * context which was originally shared using clone. copy_* -- cgit v1.2.3 From 3db03b4afb3ecd66a0399b8ba57742ca953b0ecd Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 2 Oct 2006 02:18:31 -0700 Subject: [PATCH] rename the provided execve functions to kernel_execve Some architectures provide an execve function that does not set errno, but instead returns the result code directly. Rename these to kernel_execve to get the right semantics there. Moreover, there is no reasone for any of these architectures to still provide __KERNEL_SYSCALLS__ or _syscallN macros, so remove these right away. [akpm@osdl.org: build fix] [bunk@stusta.de: build fix] Signed-off-by: Arnd Bergmann Cc: Andi Kleen Acked-by: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Russell King Cc: Ian Molton Cc: Mikael Starvik Cc: David Howells Cc: Yoshinori Sato Cc: Hirokazu Takata Cc: Ralf Baechle Cc: Kyle McMartin Cc: Heiko Carstens Cc: Martin Schwidefsky Cc: Paul Mundt Cc: Kazumoto Kojima Cc: Richard Curnow Cc: William Lee Irwin III Cc: "David S. Miller" Cc: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Cc: Miles Bader Cc: Chris Zankel Cc: "Luck, Tony" Cc: Geert Uytterhoeven Cc: Roman Zippel Signed-off-by: Adrian Bunk Cc: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/alpha_ksyms.c | 3 +- arch/alpha/kernel/entry.S | 10 ++--- arch/arm/kernel/sys_arm.c | 4 +- arch/arm26/kernel/sys_arm.c | 4 +- arch/ia64/kernel/entry.S | 4 +- arch/parisc/kernel/process.c | 9 +++- arch/powerpc/kernel/misc_32.S | 2 +- arch/powerpc/kernel/misc_64.S | 2 +- arch/um/kernel/syscall.c | 13 ++++++ arch/x86_64/kernel/entry.S | 4 +- drivers/sbus/char/bbc_envctrl.c | 5 +-- drivers/sbus/char/envctrl.c | 7 ++-- include/asm-alpha/unistd.h | 69 ------------------------------ include/asm-arm/unistd.h | 24 ----------- include/asm-arm26/unistd.h | 24 ----------- include/asm-ia64/unistd.h | 72 ------------------------------- include/asm-parisc/unistd.h | 86 ------------------------------------- include/asm-powerpc/unistd.h | 7 ---- include/asm-um/unistd.h | 28 ------------- include/asm-x86_64/unistd.h | 93 +++-------------------------------------- include/linux/syscalls.h | 2 + 21 files changed, 49 insertions(+), 423 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index f042cc42b00f..dbe327d32b6f 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -36,7 +36,6 @@ #include #include -#define __KERNEL_SYSCALLS__ #include extern struct hwrpb_struct *hwrpb; @@ -116,7 +115,7 @@ EXPORT_SYMBOL(sys_dup); EXPORT_SYMBOL(sys_exit); EXPORT_SYMBOL(sys_write); EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(execve); +EXPORT_SYMBOL(kernel_execve); EXPORT_SYMBOL(sys_setsid); EXPORT_SYMBOL(sys_wait4); diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 01ecd09d4a64..c95e95e1ab04 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -655,12 +655,12 @@ kernel_thread: .end kernel_thread /* - * execve(path, argv, envp) + * kernel_execve(path, argv, envp) */ .align 4 - .globl execve - .ent execve -execve: + .globl kernel_execve + .ent kernel_execve +kernel_execve: /* We can be called from a module. */ ldgp $gp, 0($27) lda $sp, -(32+SIZEOF_PT_REGS+8)($sp) @@ -704,7 +704,7 @@ execve: 1: lda $sp, 32+SIZEOF_PT_REGS+8($sp) ret -.end execve +.end kernel_execve /* diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index 8170af471439..00c18d35913c 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c @@ -279,7 +279,7 @@ out: return error; } -long execve(const char *filename, char **argv, char **envp) +int kernel_execve(const char *filename, char *const argv[], char *const envp[]) { struct pt_regs regs; int ret; @@ -317,7 +317,7 @@ long execve(const char *filename, char **argv, char **envp) out: return ret; } -EXPORT_SYMBOL(execve); +EXPORT_SYMBOL(kernel_execve); /* * Since loff_t is a 64 bit type we avoid a lot of ABI hastle diff --git a/arch/arm26/kernel/sys_arm.c b/arch/arm26/kernel/sys_arm.c index 85457897b8a9..dc05aba58baf 100644 --- a/arch/arm26/kernel/sys_arm.c +++ b/arch/arm26/kernel/sys_arm.c @@ -283,7 +283,7 @@ out: } /* FIXME - see if this is correct for arm26 */ -long execve(const char *filename, char **argv, char **envp) +int kernel_execve(const char *filename, char *const argv[], char *const envp[]) { struct pt_regs regs; int ret; @@ -320,4 +320,4 @@ long execve(const char *filename, char **argv, char **envp) return ret; } -EXPORT_SYMBOL(execve); +EXPORT_SYMBOL(kernel_execve); diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 12701cf32d99..e5b1be51b197 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -492,11 +492,11 @@ GLOBAL_ENTRY(prefetch_stack) br.ret.sptk.many rp END(prefetch_stack) -GLOBAL_ENTRY(execve) +GLOBAL_ENTRY(kernel_execve) mov r15=__NR_execve // put syscall number in place break __BREAK_SYSCALL br.ret.sptk.many rp -END(execve) +END(kernel_execve) GLOBAL_ENTRY(clone) mov r15=__NR_clone // put syscall number in place diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 0b485ef4be89..2f9f9dfa66f7 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -368,7 +368,14 @@ out: return error; } -unsigned long +extern int __execve(const char *filename, char *const argv[], + char *const envp[], struct task_struct *task); +int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +{ + return __execve(filename, argv, envp, current); +} + +unsigned long get_wchan(struct task_struct *p) { struct unwind_frame_info info; diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 58758d883361..88fd73fdf048 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -843,7 +843,7 @@ _GLOBAL(kernel_thread) addi r1,r1,16 blr -_GLOBAL(execve) +_GLOBAL(kernel_execve) li r0,__NR_execve sc bnslr diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index e3ed21cd3d94..9c54eccad993 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -556,7 +556,7 @@ _GLOBAL(giveup_altivec) #endif /* CONFIG_ALTIVEC */ -_GLOBAL(execve) +_GLOBAL(kernel_execve) li r0,__NR_execve sc bnslr diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index abf14aaf905f..f5ed8624648b 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -164,3 +164,16 @@ int next_syscall_index(int limit) spin_unlock(&syscall_lock); return(ret); } + +int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +{ + mm_segment_t fs; + int ret; + + fs = get_fs(); + set_fs(KERNEL_DS); + ret = um_execve(filename, argv, envp); + set_fs(fs); + + return ret; +} diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index 2802524104f3..b8285cf1a9c3 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -1023,7 +1023,7 @@ ENDPROC(child_rip) * do_sys_execve asm fallback arguments: * rdi: name, rsi: argv, rdx: envp, fake frame on the stack */ -ENTRY(execve) +ENTRY(kernel_execve) CFI_STARTPROC FAKE_STACK_FRAME $0 SAVE_ALL @@ -1036,7 +1036,7 @@ ENTRY(execve) UNFAKE_STACK_FRAME ret CFI_ENDPROC -ENDPROC(execve) +ENDPROC(kernel_execve) KPROBE_ENTRY(page_fault) errorentry do_page_fault diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index 1cc706e11119..d27e4f6d7045 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -4,9 +4,6 @@ * Copyright (C) 2001 David S. Miller (davem@redhat.com) */ -#define __KERNEL_SYSCALLS__ -static int errno; - #include #include #include @@ -200,7 +197,7 @@ static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp) printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n"); shutting_down = 1; - if (execve("/sbin/shutdown", argv, envp) < 0) + if (kernel_execve("/sbin/shutdown", argv, envp) < 0) printk(KERN_CRIT "envctrl: shutdown execution failed\n"); } diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 063e676a3ac0..728a133d0fc5 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -19,9 +19,6 @@ * Daniele Bellucci */ -#define __KERNEL_SYSCALLS__ -static int errno; - #include #include #include @@ -976,13 +973,15 @@ static void envctrl_do_shutdown(void) "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; char *argv[] = { "/sbin/shutdown", "-h", "now", NULL }; + int ret; if (inprog != 0) return; inprog = 1; printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n"); - if (0 > execve("/sbin/shutdown", argv, envp)) { + ret = kernel_execve("/sbin/shutdown", argv, envp); + if (ret < 0) { printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); inprog = 0; /* unlikely to succeed, but we could try again */ } diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h index bc6e6a9259dc..2cabbd465c0c 100644 --- a/include/asm-alpha/unistd.h +++ b/include/asm-alpha/unistd.h @@ -580,75 +580,6 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, type6 arg6)\ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include -#include -#include -#include - -static inline long open(const char * name, int mode, int flags) -{ - return sys_open(name, mode, flags); -} - -static inline long dup(int fd) -{ - return sys_dup(fd); -} - -static inline long close(int fd) -{ - return sys_close(fd); -} - -static inline off_t lseek(int fd, off_t off, int whence) -{ - return sys_lseek(fd, off, whence); -} - -static inline void _exit(int value) -{ - sys_exit(value); -} - -#define exit(x) _exit(x) - -static inline long write(int fd, const char * buf, size_t nr) -{ - return sys_write(fd, buf, nr); -} - -static inline long read(int fd, char * buf, size_t nr) -{ - return sys_read(fd, buf, nr); -} - -extern int execve(char *, char **, char **); - -static inline long setsid(void) -{ - return sys_setsid(); -} - -static inline pid_t waitpid(int pid, int * wait_stat, int flags) -{ - return sys_wait4(pid, wait_stat, flags, NULL); -} - -asmlinkage int sys_execve(char *ufilename, char **argv, char **envp, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs regs); -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize, - void *restorer); - -#endif /* __KERNEL_SYSCALLS__ */ - /* "Conditional" syscalls. What we want is __attribute__((weak,alias("sys_ni_syscall"))) diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index 2ab4078334bf..14a87eec5a2d 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -549,30 +549,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 #define __ARCH_WANT_SYS_SOCKETCALL #endif -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include - -extern long execve(const char *file, char **argv, char **envp); - -struct pt_regs; -asmlinkage int sys_execve(char *filenamei, char **argv, char **envp, - struct pt_regs *regs); -asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, - struct pt_regs *regs); -asmlinkage int sys_fork(struct pt_regs *regs); -asmlinkage int sys_vfork(struct pt_regs *regs); -asmlinkage int sys_pipe(unsigned long *fildes); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-arm26/unistd.h b/include/asm-arm26/unistd.h index c6d2436c9d34..25a5eead85be 100644 --- a/include/asm-arm26/unistd.h +++ b/include/asm-arm26/unistd.h @@ -464,30 +464,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include - -extern long execve(const char *file, char **argv, char **envp); - -struct pt_regs; -asmlinkage int sys_execve(char *filenamei, char **argv, char **envp, - struct pt_regs *regs); -asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, - struct pt_regs *regs); -asmlinkage int sys_fork(struct pt_regs *regs); -asmlinkage int sys_vfork(struct pt_regs *regs); -asmlinkage int sys_pipe(unsigned long *fildes); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index bb0eb727dcd0..53c5c0ee122c 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -319,78 +319,6 @@ extern long __ia64_syscall (long a0, long a1, long a2, long a3, long a4, long nr); -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include -#include -#include -#include - -static inline long -open (const char * name, int mode, int flags) -{ - return sys_open(name, mode, flags); -} - -static inline long -dup (int fd) -{ - return sys_dup(fd); -} - -static inline long -close (int fd) -{ - return sys_close(fd); -} - -static inline off_t -lseek (int fd, off_t off, int whence) -{ - return sys_lseek(fd, off, whence); -} - -static inline void -_exit (int value) -{ - sys_exit(value); -} - -#define exit(x) _exit(x) - -static inline long -write (int fd, const char * buf, size_t nr) -{ - return sys_write(fd, buf, nr); -} - -static inline long -read (int fd, char * buf, size_t nr) -{ - return sys_read(fd, buf, nr); -} - - -static inline long -setsid (void) -{ - return sys_setsid(); -} - -static inline pid_t -waitpid (int pid, int * wait_stat, int flags) -{ - return sys_wait4(pid, wait_stat, flags, NULL); -} - - -extern int execve (const char *filename, char *const av[], char *const ep[]); -extern pid_t clone (unsigned long flags, void *sp); - -#endif /* __KERNEL_SYSCALLS__ */ - asmlinkage unsigned long sys_mmap( unsigned long addr, unsigned long len, int prot, int flags, diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h index 27bcfad1c3e3..53b0f5d290e4 100644 --- a/include/asm-parisc/unistd.h +++ b/include/asm-parisc/unistd.h @@ -952,92 +952,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -/* mmap & mmap2 take 6 arguments */ -#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \ -{ \ - return K_INLINE_SYSCALL(name, 6, arg1, arg2, arg3, arg4, arg5, arg6); \ -} - -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include -#include - -static inline pid_t setsid(void) -{ - return sys_setsid(); -} - -static inline int write(int fd, const char *buf, off_t count) -{ - return sys_write(fd, buf, count); -} - -static inline int read(int fd, char *buf, off_t count) -{ - return sys_read(fd, buf, count); -} - -static inline off_t lseek(int fd, off_t offset, int count) -{ - return sys_lseek(fd, offset, count); -} - -static inline int dup(int fd) -{ - return sys_dup(fd); -} - -static inline int execve(char *filename, char * argv [], - char * envp[]) -{ - extern int __execve(char *, char **, char **, struct task_struct *); - return __execve(filename, argv, envp, current); -} - -static inline int open(const char *file, int flag, int mode) -{ - return sys_open(file, flag, mode); -} - -static inline int close(int fd) -{ - return sys_close(fd); -} - -static inline void _exit(int exitcode) -{ - sys_exit(exitcode); -} - -static inline pid_t waitpid(pid_t pid, int *wait_stat, int options) -{ - return sys_wait4(pid, wait_stat, options, NULL); -} - -asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long offset); -asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -struct pt_regs; -asmlinkage int sys_execve(struct pt_regs *regs); -int sys_clone(unsigned long clone_flags, unsigned long usp, - struct pt_regs *regs); -int sys_vfork(struct pt_regs *regs); -int sys_pipe(int *fildes); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - #endif /* __ASSEMBLY__ */ #undef STR diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h index eb66eae6616f..464a48cce7f5 100644 --- a/include/asm-powerpc/unistd.h +++ b/include/asm-powerpc/unistd.h @@ -478,13 +478,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 #define __ARCH_WANT_SYS_NEWFSTATAT #endif -/* - * System call prototypes. - */ -#ifdef __KERNEL_SYSCALLS__ -extern int execve(const char *file, char **argv, char **envp); -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-um/unistd.h b/include/asm-um/unistd.h index afccfcaa9ea9..732c83f04c3d 100644 --- a/include/asm-um/unistd.h +++ b/include/asm-um/unistd.h @@ -37,34 +37,6 @@ extern int um_execve(const char *file, char *const argv[], char *const env[]); #define __ARCH_WANT_SYS_RT_SIGSUSPEND #endif -#ifdef __KERNEL_SYSCALLS__ - -#include -#include - -static inline int execve(const char *filename, char *const argv[], - char *const envp[]) -{ - mm_segment_t fs; - int ret; - - fs = get_fs(); - set_fs(KERNEL_DS); - ret = um_execve(filename, argv, envp); - set_fs(fs); - - if (ret >= 0) - return ret; - - errno = -(long)ret; - return -1; -} - -int sys_execve(char *file, char **argv, char **env); - -#endif /* __KERNEL_SYSCALLS__ */ - -#undef __KERNEL_SYSCALLS__ #include "asm/arch/unistd.h" #endif /* _UM_UNISTD_H_*/ diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index 6137146516d3..777288eb7e75 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -620,10 +620,11 @@ __SYSCALL(__NR_vmsplice, sys_vmsplice) #define __NR_move_pages 279 __SYSCALL(__NR_move_pages, sys_move_pages) -#ifdef __KERNEL__ - #define __NR_syscall_max __NR_move_pages + +#ifdef __KERNEL__ #include +#endif #ifndef __NO_STUBS @@ -663,8 +664,6 @@ do { \ #define __ARCH_WANT_SYS_TIME #define __ARCH_WANT_COMPAT_SYS_TIME -#ifndef __KERNEL_SYSCALLS__ - #define __syscall "syscall" #define _syscall0(type,name) \ @@ -746,83 +745,7 @@ __asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; movq %7,%%r9 ; " __syscall \ __syscall_return(type,__res); \ } -#else /* __KERNEL_SYSCALLS__ */ - -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit - -static inline pid_t setsid(void) -{ - return sys_setsid(); -} - -static inline ssize_t write(unsigned int fd, char * buf, size_t count) -{ - return sys_write(fd, buf, count); -} - -static inline ssize_t read(unsigned int fd, char * buf, size_t count) -{ - return sys_read(fd, buf, count); -} - -static inline off_t lseek(unsigned int fd, off_t offset, unsigned int origin) -{ - return sys_lseek(fd, offset, origin); -} - -static inline long dup(unsigned int fd) -{ - return sys_dup(fd); -} - -/* implemented in asm in arch/x86_64/kernel/entry.S */ -extern int execve(const char *, char * const *, char * const *); - -static inline long open(const char * filename, int flags, int mode) -{ - return sys_open(filename, flags, mode); -} - -static inline long close(unsigned int fd) -{ - return sys_close(fd); -} - -static inline pid_t waitpid(int pid, int * wait_stat, int flags) -{ - return sys_wait4(pid, wait_stat, flags, NULL); -} - -extern long sys_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long off); - -extern int sys_modify_ldt(int func, void *ptr, unsigned long bytecount); - -asmlinkage long sys_execve(char *name, char **argv, char **envp, - struct pt_regs regs); -asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, - void *parent_tid, void *child_tid, - struct pt_regs regs); -asmlinkage long sys_fork(struct pt_regs regs); -asmlinkage long sys_vfork(struct pt_regs regs); -asmlinkage long sys_pipe(int *fildes); - +#ifdef __KERNEL__ #ifndef __ASSEMBLY__ #include @@ -839,8 +762,8 @@ asmlinkage long sys_rt_sigaction(int sig, size_t sigsetsize); #endif /* __ASSEMBLY__ */ - -#endif /* __KERNEL_SYSCALLS__ */ +#endif /* __KERNEL__ */ +#endif /* __NO_STUBS */ /* * "Conditional" syscalls @@ -850,8 +773,4 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") -#endif /* __NO_STUBS */ - -#endif /* __KERNEL__ */ - #endif /* _ASM_X86_64_UNISTD_H_ */ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 2d1c3d5c83ac..3efcfc7e9c6c 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -599,4 +599,6 @@ asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len); asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); +int kernel_execve(const char *filename, char *const argv[], char *const envp[]); + #endif -- cgit v1.2.3 From 135ab6ec8fdad6f61aabe53f456821baf4a4aa0e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 2 Oct 2006 02:18:44 -0700 Subject: [PATCH] remove remaining errno and __KERNEL_SYSCALLS__ references The last in-kernel user of errno is gone, so we should remove the definition and everything referring to it. This also removes the now-unused lib/execve.c file that was introduced earlier. Also remove every trace of __KERNEL_SYSCALLS__ that still remained in the kernel. Signed-off-by: Arnd Bergmann Cc: Andi Kleen Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Russell King Cc: Ian Molton Cc: Mikael Starvik Cc: David Howells Cc: Yoshinori Sato Cc: Hirokazu Takata Cc: Ralf Baechle Cc: Kyle McMartin Cc: Heiko Carstens Cc: Martin Schwidefsky Cc: Paul Mundt Cc: Kazumoto Kojima Cc: Richard Curnow Cc: William Lee Irwin III Cc: "David S. Miller" Cc: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Cc: Miles Bader Cc: Chris Zankel Cc: "Luck, Tony" Cc: Geert Uytterhoeven Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ia64/kernel/process.c | 2 - drivers/media/dvb/dvb-core/dvb_ringbuffer.c | 1 - drivers/net/wireless/ipw2100.c | 1 - include/asm-cris/unistd.h | 61 ------------------------- include/asm-frv/unistd.h | 25 ----------- include/asm-h8300/unistd.h | 51 --------------------- include/asm-i386/unistd.h | 39 ---------------- include/asm-m32r/unistd.h | 37 --------------- include/asm-m68k/unistd.h | 6 --- include/asm-m68knommu/unistd.h | 55 ----------------------- include/asm-mips/unistd.h | 39 ---------------- include/asm-s390/unistd.h | 51 --------------------- include/asm-sh/unistd.h | 70 ----------------------------- include/asm-sh64/unistd.h | 41 ----------------- include/asm-sparc/unistd.h | 47 ------------------- include/asm-sparc64/unistd.h | 42 ----------------- include/asm-v850/unistd.h | 51 --------------------- include/asm-xtensa/unistd.h | 5 --- include/linux/unistd.h | 6 +-- lib/Makefile | 4 +- lib/errno.c | 7 --- lib/execve.c | 23 ---------- 22 files changed, 2 insertions(+), 662 deletions(-) delete mode 100644 lib/errno.c delete mode 100644 lib/execve.c (limited to 'include/linux') diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index ea914cc6812a..51922b98086a 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -8,8 +8,6 @@ * 2005-10-07 Keith Owens * Add notify_die() hooks. */ -#define __KERNEL_SYSCALLS__ /* see */ - #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c index c972fe014c58..9878183ba3f0 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c @@ -26,7 +26,6 @@ -#define __KERNEL_SYSCALLS__ #include #include #include diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 97937809de09..eddfa8786e83 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -150,7 +150,6 @@ that only one external action is invoked at a time. #include #include #include -#define __KERNEL_SYSCALLS__ #include #include #include diff --git a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h index 7372efae0516..7c90fa970c38 100644 --- a/include/asm-cris/unistd.h +++ b/include/asm-cris/unistd.h @@ -322,67 +322,6 @@ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static inline _syscall0(pid_t,setsid) -static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) -static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static inline _syscall1(int,dup,int,fd) -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static inline _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) - -struct pt_regs; -asmlinkage long sys_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -asmlinkage int sys_execve(const char *fname, char **argv, char **envp, - long r13, long mof, long srp, struct pt_regs *regs); -asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, - int* parent_tid, int* child_tid, long mof, long srp, - struct pt_regs *regs); -asmlinkage int sys_fork(long r10, long r11, long r12, long r13, - long mof, long srp, struct pt_regs *regs); -asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, - long mof, long srp, struct pt_regs *regs); -asmlinkage int sys_pipe(unsigned long __user *fildes); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -/* - * Since we define it "external", it collides with the built-in - * definition, which has the "noreturn" attribute and will cause - * complaints. We don't want to use -fno-builtin, so just use a - * different name when in the kernel. - */ -#define _exit kernel_syscall_exit -static inline _syscall1(int,_exit,int,exitcode) -static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -#endif /* __KERNEL_SYSCALLS__ */ - - /* * "Conditional" syscalls * diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h index d104d1b91d39..725e854928cf 100644 --- a/include/asm-frv/unistd.h +++ b/include/asm-frv/unistd.h @@ -440,31 +440,6 @@ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg __syscall_return(type, __sc0); \ } - -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) - -#endif /* __KERNEL_SYSCALLS__ */ - #define __ARCH_WANT_IPC_PARSE_VERSION /* #define __ARCH_WANT_OLD_READDIR */ #define __ARCH_WANT_OLD_STAT diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h index a2dd90462d80..747788d629ae 100644 --- a/include/asm-h8300/unistd.h +++ b/include/asm-h8300/unistd.h @@ -485,57 +485,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e, ftype f) \ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#ifdef __KERNEL_SYSCALLS__ - -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static inline _syscall0(int,pause) -static inline _syscall0(int,sync) -static inline _syscall0(pid_t,setsid) -static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) -static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static inline _syscall1(int,dup,int,fd) -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static inline _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) -static inline _syscall1(int,_exit,int,exitcode) -static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -static inline _syscall1(int,delete_module,const char *,name) - -static inline pid_t wait(int * wait_stat) -{ - return waitpid(-1,wait_stat,0); -} - -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -asmlinkage int sys_execve(char *name, char **argv, char **envp, - int dummy, ...); -asmlinkage int sys_pipe(unsigned long *fildes); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls */ diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index bd9987087adc..3ca7ab963d7d 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -451,45 +451,6 @@ __syscall_return(type,__res); \ #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) - -asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount); -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -asmlinkage int sys_execve(struct pt_regs regs); -asmlinkage int sys_clone(struct pt_regs regs); -asmlinkage int sys_fork(struct pt_regs regs); -asmlinkage int sys_vfork(struct pt_regs regs); -asmlinkage int sys_pipe(unsigned long __user *fildes); -asmlinkage long sys_iopl(unsigned long unused); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-m32r/unistd.h b/include/asm-m32r/unistd.h index 5c6a9ac6cf1a..95aa34298d82 100644 --- a/include/asm-m32r/unistd.h +++ b/include/asm-m32r/unistd.h @@ -424,43 +424,6 @@ __syscall_return(type,__res); \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_RT_SIGACTION -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -static __inline__ _syscall3(int,execve,const char *,file,char **,argv,char **,envp) - -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -asmlinkage int sys_execve(struct pt_regs regs); -asmlinkage int sys_clone(struct pt_regs regs); -asmlinkage int sys_fork(struct pt_regs regs); -asmlinkage int sys_vfork(struct pt_regs regs); -asmlinkage int sys_pipe(unsigned long __user *fildes); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h index 751632b904db..3ab716f0fc18 100644 --- a/include/asm-m68k/unistd.h +++ b/include/asm-m68k/unistd.h @@ -409,12 +409,6 @@ __syscall_return(type,__res); \ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#ifdef __KERNEL_SYSCALLS__ - -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h index 21fdc37c5c2c..daafb5d43ef1 100644 --- a/include/asm-m68knommu/unistd.h +++ b/include/asm-m68knommu/unistd.h @@ -463,61 +463,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e) \ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static inline _syscall0(int,pause) -static inline _syscall0(int,sync) -static inline _syscall0(pid_t,setsid) -static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) -static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static inline _syscall1(int,dup,int,fd) -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static inline _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) -static inline _syscall1(int,_exit,int,exitcode) -static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -static inline _syscall1(int,delete_module,const char *,name) - -static inline pid_t wait(int * wait_stat) -{ - return waitpid(-1,wait_stat,0); -} -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -asmlinkage int sys_execve(char *name, char **argv, char **envp); -asmlinkage int sys_pipe(unsigned long *fildes); -struct pt_regs; -int sys_request_irq(unsigned int, - irqreturn_t (*)(int, void *, struct pt_regs *), - unsigned long, const char *, void *); -void sys_free_irq(unsigned int, void *); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h index c39142920fe6..685c91467e63 100644 --- a/include/asm-mips/unistd.h +++ b/include/asm-mips/unistd.h @@ -1212,45 +1212,6 @@ type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \ # define __ARCH_WANT_COMPAT_SYS_TIME # endif -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) - -asmlinkage unsigned long sys_mmap( - unsigned long addr, size_t len, - int prot, int flags, - int fd, off_t offset); -asmlinkage long sys_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs); -asmlinkage int sys_pipe(nabi_no_regargs struct pt_regs regs); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ #endif /* !__ASSEMBLY__ */ /* diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index 0361ac5dcde3..0cccfd83c457 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -523,57 +523,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ # define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND # endif -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static inline _syscall0(pid_t,setsid) -static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) -static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static inline _syscall1(int,dup,int,fd) -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static inline _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) -static inline _syscall2(long,stat,char *,filename,struct stat *,statbuf) - -static inline pid_t waitpid(int pid, int *wait_stat, int flags) -{ - return sys_wait4(pid, wait_stat, flags, NULL); -} -struct mmap_arg_struct; -asmlinkage long sys_mmap2(struct mmap_arg_struct __user *arg); - -asmlinkage long sys_execve(struct pt_regs regs); -asmlinkage long sys_clone(struct pt_regs regs); -asmlinkage long sys_fork(struct pt_regs regs); -asmlinkage long sys_vfork(struct pt_regs regs); -asmlinkage long sys_pipe(unsigned long __user *fildes); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h index 5d5e9f94def5..f1a0cbc966be 100644 --- a/include/asm-sh/unistd.h +++ b/include/asm-sh/unistd.h @@ -472,76 +472,6 @@ __syscall_return(type,__sc0); \ #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND -#ifdef __KERNEL_SYSCALLS__ - -#include -#include -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static __inline__ _syscall0(int,pause) -static __inline__ _syscall0(int,sync) -static __inline__ _syscall0(pid_t,setsid) -static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count) -static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static __inline__ _syscall1(int,dup,int,fd) -static __inline__ _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static __inline__ _syscall3(int,open,const char *,file,int,flag,int,mode) -static __inline__ _syscall1(int,close,int,fd) -static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -static __inline__ _syscall1(int,delete_module,const char *,name) - -static __inline__ pid_t wait(int * wait_stat) -{ - return waitpid(-1,wait_stat,0); -} - -asmlinkage long sys_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -asmlinkage int sys_execve(char *ufilename, char **uargv, - char **uenvp, unsigned long r7, - struct pt_regs regs); -asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, - unsigned long parent_tidptr, - unsigned long child_tidptr, - struct pt_regs regs); -asmlinkage int sys_fork(unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs regs); -asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs regs); -asmlinkage int sys_pipe(unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs regs); -asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char *buf, - size_t count, long dummy, loff_t pos); -asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char *buf, - size_t count, long dummy, loff_t pos); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h index c113566bef33..ee7828b27ad1 100644 --- a/include/asm-sh64/unistd.h +++ b/include/asm-sh64/unistd.h @@ -513,47 +513,6 @@ __syscall_return(type,__sc0); \ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#ifdef __KERNEL_SYSCALLS__ - -/* Copy from sh */ -#include -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static inline _syscall0(int,pause) -static inline _syscall1(int,setup,int,magic) -static inline _syscall0(int,sync) -static inline _syscall0(pid_t,setsid) -static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) -static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static inline _syscall1(int,dup,int,fd) -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static inline _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) -static inline _syscall1(int,_exit,int,exitcode) -static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -static inline _syscall1(int,delete_module,const char *,name) - -static inline pid_t wait(int * wait_stat) -{ - return waitpid(-1,wait_stat,0); -} -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h index 2553762465ca..c7a495afc82e 100644 --- a/include/asm-sparc/unistd.h +++ b/include/asm-sparc/unistd.h @@ -478,53 +478,6 @@ return -1; \ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGSUSPEND -#ifdef __KERNEL_SYSCALLS__ - -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static __inline__ _syscall0(pid_t,setsid) -static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count) -static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count) -static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static __inline__ _syscall1(int,dup,int,fd) -static __inline__ _syscall3(int,execve,__const__ char *,file,char **,argv,char **,envp) -static __inline__ _syscall3(int,open,__const__ char *,file,int,flag,int,mode) -static __inline__ _syscall1(int,close,int,fd) -static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) - -#include - -asmlinkage unsigned long sys_mmap( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long off); -asmlinkage unsigned long sys_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - void __user *restorer, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls * diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h index badc73fdcb97..124cf076717f 100644 --- a/include/asm-sparc64/unistd.h +++ b/include/asm-sparc64/unistd.h @@ -445,48 +445,6 @@ if (__res>=0) \ errno = -__res; \ return -1; \ } -#ifdef __KERNEL_SYSCALLS__ - -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static __inline__ _syscall0(pid_t,setsid) -static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count) -static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count) -static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static __inline__ _syscall1(int,dup,int,fd) -static __inline__ _syscall3(int,execve,__const__ char *,file,char **,argv,char **,envp) -static __inline__ _syscall3(int,open,__const__ char *,file,int,flag,int,mode) -static __inline__ _syscall1(int,close,int,fd) -static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) - -#include - -asmlinkage unsigned long sys_mmap( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long off); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - void __user *restorer, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ /* sysconf options, for SunOS compatibility */ #define _SC_ARG_MAX 1 diff --git a/include/asm-v850/unistd.h b/include/asm-v850/unistd.h index 552b7c873a57..737401e7d3ad 100644 --- a/include/asm-v850/unistd.h +++ b/include/asm-v850/unistd.h @@ -387,57 +387,6 @@ type name (atype a, btype b, ctype c, dtype d, etype e, ftype f) \ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#ifdef __KERNEL_SYSCALLS__ - -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -extern inline _syscall0(pid_t,setsid) -extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count) -extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -extern inline _syscall1(int,dup,int,fd) -extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -extern inline _syscall3(int,open,const char *,file,int,flag,int,mode) -extern inline _syscall1(int,close,int,fd) -extern inline _syscall1(int,_exit,int,exitcode) -extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) - -extern inline pid_t wait(int * wait_stat) -{ - return waitpid (-1, wait_stat, 0); -} - -unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset); -unsigned long sys_mmap2(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -struct pt_regs; -int sys_execve (char *name, char **argv, char **envp, struct pt_regs *regs); -int sys_pipe (int *fildes); -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); - -#endif /* __KERNEL_SYSCALLS__ */ - /* * "Conditional" syscalls */ diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h index 5e1b99dc4ab3..411f810a55c6 100644 --- a/include/asm-xtensa/unistd.h +++ b/include/asm-xtensa/unistd.h @@ -402,11 +402,6 @@ __asm__ __volatile__ ( \ __syscall_return(type,__res); \ } - -#ifdef __KERNEL_SYSCALLS__ -static __inline__ _syscall3(int,execve,const char*,file,char**,argv,char**,envp) -#endif - /* * "Conditional" syscalls * diff --git a/include/linux/unistd.h b/include/linux/unistd.h index c18c60f3254e..aa8d5b5e2e3e 100644 --- a/include/linux/unistd.h +++ b/include/linux/unistd.h @@ -1,12 +1,8 @@ #ifndef _LINUX_UNISTD_H_ #define _LINUX_UNISTD_H_ -#ifdef __KERNEL__ -extern int errno; -#endif - /* - * Include machine specific syscallX macros + * Include machine specific syscall numbers */ #include diff --git a/lib/Makefile b/lib/Makefile index 4d752be0edc0..b0361756e22e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for some libs needed in the kernel. # -lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ +lib-y := ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \ sha1.o @@ -35,8 +35,6 @@ ifneq ($(CONFIG_HAVE_DEC_LOCK),y) lib-y += dec_and_lock.o endif -lib-y += execve.o - obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o obj-$(CONFIG_CRC16) += crc16.o obj-$(CONFIG_CRC32) += crc32.o diff --git a/lib/errno.c b/lib/errno.c deleted file mode 100644 index 41cb9d76c052..000000000000 --- a/lib/errno.c +++ /dev/null @@ -1,7 +0,0 @@ -/* - * linux/lib/errno.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -int errno; diff --git a/lib/execve.c b/lib/execve.c deleted file mode 100644 index 2667ebc15045..000000000000 --- a/lib/execve.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - -#define __KERNEL_SYSCALLS__ -static int errno __attribute__((unused)); -#include - -#ifdef _syscall3 -int kernel_execve (const char *filename, char *const argv[], char *const envp[]) - __attribute__((__weak__)); -int kernel_execve (const char *filename, char *const argv[], char *const envp[]) -{ - mm_segment_t fs = get_fs(); - int ret; - - WARN_ON(segment_eq(fs, USER_DS)); - ret = execve(filename, (char **)argv, (char **)envp); - if (ret) - ret = -errno; - - return ret; -} -#endif -- cgit v1.2.3 From 1a657f78dcc8ea7c53eaa1f2a45ea2315738c15f Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 2 Oct 2006 02:18:59 -0700 Subject: [PATCH] introduce get_task_pid() to fix unsafe get_pid() proc_pid_make_inode: ei->pid = get_pid(task_pid(task)); I think this is not safe. get_pid() can be preempted after checking "pid != NULL". Then the task exits, does detach_pid(), and RCU frees the pid. Signed-off-by: Oleg Nesterov Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 4 ++-- include/linux/pid.h | 2 ++ kernel/pid.c | 9 +++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/base.c b/fs/proc/base.c index a317eb2c4442..82da55b5cffe 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -958,7 +958,7 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st /* * grab the reference to task. */ - ei->pid = get_pid(task_pid(task)); + ei->pid = get_task_pid(task, PIDTYPE_PID); if (!ei->pid) goto out_unlock; @@ -1677,7 +1677,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir, /* * grab the reference to the task. */ - ei->pid = get_pid(task_pid(task)); + ei->pid = get_task_pid(task, PIDTYPE_PID); if (!ei->pid) goto out_iput; diff --git a/include/linux/pid.h b/include/linux/pid.h index 7e39767b4c60..17b9e04d3586 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -68,6 +68,8 @@ extern struct task_struct *FASTCALL(pid_task(struct pid *pid, enum pid_type)); extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid, enum pid_type)); +extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type); + /* * attach_pid() and detach_pid() must be called with the tasklist_lock * write-held. diff --git a/kernel/pid.c b/kernel/pid.c index e4779bbb2058..b914392085f9 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -304,6 +304,15 @@ struct task_struct *find_task_by_pid_type(int type, int nr) EXPORT_SYMBOL(find_task_by_pid_type); +struct pid *get_task_pid(struct task_struct *task, enum pid_type type) +{ + struct pid *pid; + rcu_read_lock(); + pid = get_pid(task->pids[type].pid); + rcu_read_unlock(); + return pid; +} + struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type) { struct task_struct *result; -- cgit v1.2.3 From 9ec52099e4b8678a60e9f93e41ad87885d64f3e6 Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Mon, 2 Oct 2006 02:19:00 -0700 Subject: [PATCH] replace cad_pid by a struct pid There are a few places in the kernel where the init task is signaled. The ctrl+alt+del sequence is one them. It kills a task, usually init, using a cached pid (cad_pid). This patch replaces the pid_t by a struct pid to avoid pid wrap around problem. The struct pid is initialized at boot time in init() and can be modified through systctl with /proc/sys/kernel/cad_pid [ I haven't found any distro using it ? ] It also introduces a small helper routine kill_cad_pid() which is used where it seemed ok to use cad_pid instead of pid 1. [akpm@osdl.org: cleanups, build fix] Signed-off-by: Cedric Le Goater Cc: Eric W. Biederman Cc: Martin Schwidefsky Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/mips/sgi-ip22/ip22-reset.c | 3 ++- arch/mips/sgi-ip32/ip32-reset.c | 2 +- arch/powerpc/platforms/iseries/mf.c | 2 +- drivers/char/nwbutton.c | 5 ++--- drivers/char/snsc_event.c | 2 +- drivers/parisc/power.c | 3 +-- drivers/s390/s390mach.c | 2 +- include/linux/sched.h | 7 +++++++ init/main.c | 2 ++ kernel/sys.c | 6 +++--- kernel/sysctl.c | 30 +++++++++++++++++++++++++++--- 11 files changed, 48 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c index 8134220ed600..7a941ecff3bb 100644 --- a/arch/mips/sgi-ip22/ip22-reset.c +++ b/arch/mips/sgi-ip22/ip22-reset.c @@ -123,7 +123,8 @@ static inline void power_button(void) if (machine_state & MACHINE_PANICED) return; - if ((machine_state & MACHINE_SHUTTING_DOWN) || kill_proc(1,SIGINT,1)) { + if ((machine_state & MACHINE_SHUTTING_DOWN) || + kill_cad_pid(SIGINT, 1)) { /* No init process or button pressed twice. */ sgi_machine_power_off(); } diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index 79ddb4605659..fd0932b2d521 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c @@ -120,7 +120,7 @@ static inline void ip32_power_button(void) if (has_panicked) return; - if (shuting_down || kill_proc(1, SIGINT, 1)) { + if (shuting_down || kill_cad_pid(SIGINT, 1)) { /* No init process or button pressed twice. */ ip32_machine_power_off(); } diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 1a2c2a50f922..1983b640bac1 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -357,7 +357,7 @@ static int dma_and_signal_ce_msg(char *ce_msg, */ static int shutdown(void) { - int rc = kill_proc(1, SIGINT, 1); + int rc = kill_cad_pid(SIGINT, 1); if (rc) { printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), " diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 7c57ebfa8640..ea1aa7764f8e 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -127,9 +127,8 @@ static void button_consume_callbacks (int bpcount) static void button_sequence_finished (unsigned long parameters) { #ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */ - if (button_press_count == reboot_count) { - kill_proc (1, SIGINT, 1); /* Ask init to reboot us */ - } + if (button_press_count == reboot_count) + kill_cad_pid(SIGINT, 1); /* Ask init to reboot us */ #endif /* CONFIG_NWBUTTON_REBOOT */ button_consume_callbacks (button_press_count); bcount = sprintf (button_output_buffer, "%d\n", button_press_count); diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index d12d4f629cec..864854c58866 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -220,7 +220,7 @@ scdrv_dispatch_event(char *event, int len) " Sending SIGPWR to init...\n"); /* give a SIGPWR signal to init proc */ - kill_proc(1, SIGPWR, 0); + kill_cad_pid(SIGPWR, 0); } else { /* print to system log */ printk("%s|$(0x%x)%s\n", severity, esp_code, desc); diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c index fad5a33bf0fa..4a9f025a6b58 100644 --- a/drivers/parisc/power.c +++ b/drivers/parisc/power.c @@ -84,8 +84,7 @@ static void deferred_poweroff(void *dummy) { - extern int cad_pid; /* from kernel/sys.c */ - if (kill_proc(cad_pid, SIGINT, 1)) { + if (kill_cad_pid(SIGINT, 1)) { /* just in case killing init process failed */ machine_power_off(); } diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 479364d0332a..e088b5e28711 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -208,7 +208,7 @@ s390_handle_mcck(void) */ __ctl_clear_bit(14, 24); /* Disable WARNING MCH */ if (xchg(&mchchk_wng_posted, 1) == 0) - kill_proc(1, SIGPWR, 1); + kill_cad_pid(SIGPWR, 1); } #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index 9ba959e34266..38530232d92f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1065,6 +1065,8 @@ static inline int is_init(struct task_struct *tsk) return tsk->pid == 1; } +extern struct pid *cad_pid; + extern void free_task(struct task_struct *tsk); #define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0) @@ -1292,6 +1294,11 @@ extern int send_group_sigqueue(int, struct sigqueue *, struct task_struct *); extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *); extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long); +static inline int kill_cad_pid(int sig, int priv) +{ + return kill_pid(cad_pid, sig, priv); +} + /* These can be the second arg to send_sig_info/send_group_sig_info. */ #define SEND_SIG_NOINFO ((struct siginfo *) 0) #define SEND_SIG_PRIV ((struct siginfo *) 1) diff --git a/init/main.c b/init/main.c index a49b00235bda..ee123243fb53 100644 --- a/init/main.c +++ b/init/main.c @@ -721,6 +721,8 @@ static int init(void * unused) */ child_reaper = current; + cad_pid = task_pid(current); + smp_prepare_cpus(max_cpus); do_pre_smp_initcalls(); diff --git a/kernel/sys.c b/kernel/sys.c index 3a4776e8f16e..2314867ae34f 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -92,7 +92,8 @@ EXPORT_SYMBOL(fs_overflowgid); */ int C_A_D = 1; -int cad_pid = 1; +struct pid *cad_pid; +EXPORT_SYMBOL(cad_pid); /* * Notifier list for kernel code which wants to be called @@ -773,10 +774,9 @@ void ctrl_alt_del(void) if (C_A_D) schedule_work(&cad_work); else - kill_proc(cad_pid, SIGINT, 1); + kill_cad_pid(SIGINT, 1); } - /* * Unprivileged users may change the real gid to the effective gid * or vice versa. (BSD-style) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index a79ccf9d113b..8020fb273c4f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -68,7 +68,6 @@ extern int sysrq_enabled; extern int core_uses_pid; extern int suid_dumpable; extern char core_pattern[]; -extern int cad_pid; extern int pid_max; extern int min_free_kbytes; extern int printk_ratelimit_jiffies; @@ -137,6 +136,9 @@ static int parse_table(int __user *, int, void __user *, size_t __user *, static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos); +static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos); + static ctl_table root_table[]; static struct ctl_table_header root_table_header = { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) }; @@ -543,10 +545,10 @@ static ctl_table kern_table[] = { { .ctl_name = KERN_CADPID, .procname = "cad_pid", - .data = &cad_pid, + .data = NULL, .maxlen = sizeof (int), .mode = 0600, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_do_cad_pid, }, { .ctl_name = KERN_MAX_THREADS, @@ -2427,6 +2429,28 @@ proc_minmax: } #endif +static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct pid *new_pid; + pid_t tmp; + int r; + + tmp = pid_nr(cad_pid); + + r = __do_proc_dointvec(&tmp, table, write, filp, buffer, + lenp, ppos, NULL, NULL); + if (r || !write) + return r; + + new_pid = find_get_pid(tmp); + if (!new_pid) + return -ESRCH; + + put_pid(xchg(&cad_pid, new_pid)); + return 0; +} + #else /* CONFIG_PROC_FS */ int proc_dostring(ctl_table *table, int write, struct file *filp, -- cgit v1.2.3 From 3f2e05e90e0846c42626e3d272454f26be34a1bc Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 2 Oct 2006 14:12:31 +0100 Subject: [PATCH] BLOCK: Revert patch to hack around undeclared sigset_t in linux/compat.h Revert Andrew Morton's patch to temporarily hack around the lack of a declaration of sigset_t in linux/compat.h to make the block-disablement patches build on IA64. This got accidentally pushed to Linus and should be fixed in a different manner. Also make linux/compat.h #include asm/signal.h to gain a definition of sigset_t so that it can externally declare sigset_from_compat(). This has been compile-tested for i386, x86_64, ia64, mips, mips64, frv, ppc and ppc64 and run-tested on frv. Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/mips/kernel/signal_n32.c | 4 ++-- fs/compat.c | 2 -- include/linux/compat.h | 1 + kernel/compat.c | 2 -- 4 files changed, 3 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 50c17eaa7f25..477c5334ec1b 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -42,8 +42,6 @@ #include "signal-common.h" -extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); - /* * Including would give use the 64-bit syscall numbers ... */ @@ -83,6 +81,8 @@ struct rt_sigframe_n32 { #endif }; +extern void sigset_from_compat (sigset_t *set, compat_sigset_t *compat); + save_static_function(sysn32_rt_sigsuspend); __attribute_used__ noinline static int _sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) diff --git a/fs/compat.c b/fs/compat.c index 13fb08d096c4..d98c96f4a44d 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -56,8 +56,6 @@ int compat_log = 1; -extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); - int compat_printk(const char *fmt, ...) { va_list ap; diff --git a/include/linux/compat.h b/include/linux/compat.h index 9760753e662b..6f110957cc97 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -13,6 +13,7 @@ #include #include +#include #define compat_jiffies_to_clock_t(x) \ (((unsigned long)(x) * COMPAT_USER_HZ) / HZ) diff --git a/kernel/compat.c b/kernel/compat.c index b4fbd838cd77..75573e5d27b0 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -26,8 +26,6 @@ #include -extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); - int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) { return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || -- cgit v1.2.3 From 128e5ebaf8abbda375bba82690b09630003c9213 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 2 Oct 2006 11:24:43 -0400 Subject: [GFS2] Remove iflags.h, use FS_ Update GFS2 in the light of David Howells' patch: [PATCH] BLOCK: Move common FS-specific ioctls to linux/fs.h [try #6] 36695673b012096228ebdc1b39a6a5850daa474e which calls the filesystem independant flags FS_..._FL. As a result we no longer need the flags.h file and the conversion routine is moved into the GFS2 source code. Userland programs which used to include iflags.h should now include fs.h and use the new flag names. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_file.c | 74 ++++++++++++++++++++++------------- include/linux/Kbuild | 1 - include/linux/fs.h | 2 + include/linux/iflags.h | 102 ------------------------------------------------- 4 files changed, 49 insertions(+), 130 deletions(-) delete mode 100644 include/linux/iflags.h (limited to 'include/linux') diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index fafa48b9105e..3064f133bf3c 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -201,27 +200,48 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) return error; } +/** + * fsflags_cvt + * @table: A table of 32 u32 flags + * @val: a 32 bit value to convert + * + * This function can be used to convert between fsflags values and + * GFS2's own flags values. + * + * Returns: the converted flags + */ +static u32 fsflags_cvt(const u32 *table, u32 val) +{ + u32 res = 0; + while(val) { + if (val & 1) + res |= *table; + table++; + val >>= 1; + } + return res; +} -static const u32 iflags_to_gfs2[32] = { - [iflag_Sync] = GFS2_DIF_SYNC, - [iflag_Immutable] = GFS2_DIF_IMMUTABLE, - [iflag_Append] = GFS2_DIF_APPENDONLY, - [iflag_NoAtime] = GFS2_DIF_NOATIME, - [iflag_Index] = GFS2_DIF_EXHASH, - [iflag_JournalData] = GFS2_DIF_JDATA, - [iflag_DirectIO] = GFS2_DIF_DIRECTIO, +static const u32 fsflags_to_gfs2[32] = { + [3] = GFS2_DIF_SYNC, + [4] = GFS2_DIF_IMMUTABLE, + [5] = GFS2_DIF_APPENDONLY, + [7] = GFS2_DIF_NOATIME, + [12] = GFS2_DIF_EXHASH, + [14] = GFS2_DIF_JDATA, + [20] = GFS2_DIF_DIRECTIO, }; -static const u32 gfs2_to_iflags[32] = { - [gfs2fl_Sync] = IFLAG_SYNC, - [gfs2fl_Immutable] = IFLAG_IMMUTABLE, - [gfs2fl_AppendOnly] = IFLAG_APPEND, - [gfs2fl_NoAtime] = IFLAG_NOATIME, - [gfs2fl_ExHash] = IFLAG_INDEX, - [gfs2fl_Jdata] = IFLAG_JOURNAL_DATA, - [gfs2fl_Directio] = IFLAG_DIRECTIO, - [gfs2fl_InheritDirectio] = IFLAG_DIRECTIO, - [gfs2fl_InheritJdata] = IFLAG_JOURNAL_DATA, +static const u32 gfs2_to_fsflags[32] = { + [gfs2fl_Sync] = FS_SYNC_FL, + [gfs2fl_Immutable] = FS_IMMUTABLE_FL, + [gfs2fl_AppendOnly] = FS_APPEND_FL, + [gfs2fl_NoAtime] = FS_NOATIME_FL, + [gfs2fl_ExHash] = FS_INDEX_FL, + [gfs2fl_Jdata] = FS_JOURNAL_DATA_FL, + [gfs2fl_Directio] = FS_DIRECTIO_FL, + [gfs2fl_InheritDirectio] = FS_DIRECTIO_FL, + [gfs2fl_InheritJdata] = FS_JOURNAL_DATA_FL, }; static int gfs2_get_flags(struct file *filp, u32 __user *ptr) @@ -230,15 +250,15 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr) struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int error; - u32 iflags; + u32 fsflags; gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); error = gfs2_glock_nq_m_atime(1, &gh); if (error) return error; - iflags = iflags_cvt(gfs2_to_iflags, ip->i_di.di_flags); - if (put_user(iflags, ptr)) + fsflags = fsflags_cvt(gfs2_to_fsflags, ip->i_di.di_flags); + if (put_user(fsflags, ptr)) error = -EFAULT; gfs2_glock_dq_m(1, &gh); @@ -327,19 +347,19 @@ out: static int gfs2_set_flags(struct file *filp, u32 __user *ptr) { - u32 iflags, gfsflags; - if (get_user(iflags, ptr)) + u32 fsflags, gfsflags; + if (get_user(fsflags, ptr)) return -EFAULT; - gfsflags = iflags_cvt(iflags_to_gfs2, iflags); + gfsflags = fsflags_cvt(fsflags_to_gfs2, fsflags); return do_gfs2_set_flags(filp, gfsflags, ~0); } static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd) { - case IFLAGS_GET_IOC: + case FS_IOC_GETFLAGS: return gfs2_get_flags(filp, (u32 __user *)arg); - case IFLAGS_SET_IOC: + case FS_IOC_SETFLAGS: return gfs2_set_flags(filp, (u32 __user *)arg); } return -ENOTTY; diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 839a97ee1f7c..15667cc947d5 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -223,7 +223,6 @@ unifdef-y += hpet.h unifdef-y += i2c.h unifdef-y += i2o-dev.h unifdef-y += icmpv6.h -unifdef-y += iflags.h unifdef-y += if_bridge.h unifdef-y += if_ec.h unifdef-y += if_eql.h diff --git a/include/linux/fs.h b/include/linux/fs.h index 2e29a2edaeec..bc0e645abb80 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -250,6 +250,8 @@ extern int dir_notify_enable; #define FS_NOTAIL_FL 0x00008000 /* file tail should not be merged */ #define FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ #define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define FS_EXTENT_FL 0x00080000 /* Extents */ +#define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */ #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ #define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ diff --git a/include/linux/iflags.h b/include/linux/iflags.h deleted file mode 100644 index 5b27102dfeaf..000000000000 --- a/include/linux/iflags.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef _LINUX_IFLAGS_H -#define _LINUX_IFLAGS_H - -/* - * A universal set of inode flags. - * - * Originally taken from ext2/3 with additions for other filesystems. - * Filesystems supporting this interface should interoperate with - * the lsattr and chattr command line tools. - * - * This interface is supported in whole or in part by: - * ext2 - * ext3 - * xfs - * jfs - * gfs2 - * - */ - -#define IFLAGS_GET_IOC _IOR('f', 1, long) -#define IFLAGS_SET_IOC _IOW('f', 2, long) - -/* - * These values are provided for use as indices of an array - * for use with the iflags_cvt function below - */ -enum { - iflag_SecureRm = 0, /* Secure deletion */ - iflag_Unrm = 1, /* Undelete */ - iflag_Compress = 2, /* Compress file */ - iflag_Sync = 3, /* Synchronous updates */ - iflag_Immutable = 4, /* Immutable */ - iflag_Append = 5, /* Append */ - iflag_NoDump = 6, /* Don't dump file */ - iflag_NoAtime = 7, /* No atime updates */ - /* Reserved for compression usage */ - iflag_Dirty = 8, - iflag_ComprBlk = 9, /* One or more compressed clusters */ - iflag_NoComp = 10, /* Don't compress */ - iflag_Ecompr = 11, /* Compression error */ - /* End of compression flags */ - iflag_Btree = 12, /* btree format dir */ - iflag_Index = 12, /* hash-indexed directory */ - iflag_Imagic = 13, /* AFS directory */ - iflag_JournalData = 14, /* file data should be journaled */ - iflag_NoTail = 15, /* file tail should not be merged */ - iflag_DirSync = 16, /* dirsync behaviour */ - iflag_TopDir = 17, /* Top of directory hierarchies */ - iflag_Extent = 19, /* Extents */ - iflag_DirectIO = 20, /* Always use direct I/O on this file */ - iflag_Reserved = 31 /* reserved for ext2/3 lib */ -}; - -#define __IFL(x) (1<<(iflag_##x)) -#define IFLAG_SECRM __IFL(SecureRm) /* 0x00000001 */ -#define IFLAG_UNRM __IFL(Unrm) /* 0x00000002 */ -#define IFLAG_COMPR __IFL(Compr) /* 0x00000004 */ -#define IFLAG_SYNC __IFL(Sync) /* 0x00000008 */ -#define IFLAG_IMMUTABLE __IFL(Immutable) /* 0x00000010 */ -#define IFLAG_APPEND __IFL(Append) /* 0x00000020 */ -#define IFLAG_NODUMP __IFL(NoDump) /* 0x00000040 */ -#define IFLAG_NOATIME __IFL(NoAtime) /* 0x00000080 */ -#define IFLAG_DIRTY __IFL(Dirty) /* 0x00000100 */ -#define IFLAG_COMPRBLK __IFL(ComprBlk) /* 0x00000200 */ -#define IFLAG_NOCOMP __IFL(NoComp) /* 0x00000400 */ -#define IFLAG_ECOMPR __IFL(Ecompr) /* 0x00000800 */ -#define IFLAG_BTREE __IFL(Btree) /* 0x00001000 */ -#define IFLAG_INDEX __IFL(Index) /* 0x00001000 */ -#define IFLAG_IMAGIC __IFL(Imagic) /* 0x00002000 */ -#define IFLAG_JOURNAL_DATA __IFL(JournalData) /* 0x00004000 */ -#define IFLAG_NOTAIL __IFL(NoTail) /* 0x00008000 */ -#define IFLAG_DIRSYNC __IFL(DirSync) /* 0x00010000 */ -#define IFLAG_TOPDIR __IFL(TopDir) /* 0x00020000 */ -#define IFLAG_EXTENT __IFL(Extent) /* 0x00080000 */ -#define IFLAG_DIRECTIO __IFL(DirectIO) /* 0x00100000 */ -#define IFLAG_RESERVED __IFL(Reserved) /* 0x80000000 */ - -#ifdef __KERNEL__ -/** - * iflags_cvt - * @table: A table of 32 u32 flags - * @val: a 32 bit value to convert - * - * This function can be used to convert between IFLAGS values and - * the filesystem's own flags values. - * - * Returns: the converted flags - */ -static inline u32 iflags_cvt(const u32 *table, u32 val) -{ - u32 res = 0; - while(val) { - if (val & 1) - res |= *table; - table++; - val >>= 1; - } - return res; -} -#endif /* __KERNEL__ */ - -#endif /* _LINUX_IFLAGS_H */ -- cgit v1.2.3 From 0235497f7a961db57ef975eb889503809ce82fe5 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 2 Oct 2006 14:05:20 -0700 Subject: Add prototype for sigset_from_compat() Duh. I screwed up editing David Howells patch in commit 3f2e05e90e0846c42626e3d272454f26be34a1bc, and the actual declaration for the sigset_from_compat() function went missing. My bad. Olaf Hering saved the day and noticed that I'm a moron. Signed-off-by: Linus Torvalds --- include/linux/compat.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/compat.h b/include/linux/compat.h index 6f110957cc97..ef5cd192784c 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -228,6 +228,7 @@ static inline int compat_timespec_compare(struct compat_timespec *lhs, asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); extern int compat_printk(const char *fmt, ...); +extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); #endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */ -- cgit v1.2.3 From 1d32849b14bc8792e6f35ab27dd990d74b16126c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 3 Oct 2006 01:13:45 -0700 Subject: [PATCH] pid.h cleanup Make the pid.h macros look less revolting in an 80-col window. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pid.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pid.h b/include/linux/pid.h index 17b9e04d3586..2c0007d17218 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -105,28 +105,28 @@ static inline pid_t pid_nr(struct pid *pid) } -#define do_each_task_pid(who, type, task) \ - do { \ - struct hlist_node *pos___; \ - struct pid *pid___ = find_pid(who); \ - if (pid___ != NULL) \ - hlist_for_each_entry_rcu((task), pos___, \ +#define do_each_task_pid(who, type, task) \ + do { \ + struct hlist_node *pos___; \ + struct pid *pid___ = find_pid(who); \ + if (pid___ != NULL) \ + hlist_for_each_entry_rcu((task), pos___, \ &pid___->tasks[type], pids[type].node) { -#define while_each_task_pid(who, type, task) \ - } \ +#define while_each_task_pid(who, type, task) \ + } \ } while (0) -#define do_each_pid_task(pid, type, task) \ - do { \ - struct hlist_node *pos___; \ - if (pid != NULL) \ - hlist_for_each_entry_rcu((task), pos___, \ +#define do_each_pid_task(pid, type, task) \ + do { \ + struct hlist_node *pos___; \ + if (pid != NULL) \ + hlist_for_each_entry_rcu((task), pos___, \ &pid->tasks[type], pids[type].node) { -#define while_each_pid_task(pid, type, task) \ - } \ +#define while_each_pid_task(pid, type, task) \ + } \ } while (0) #endif /* _LINUX_PID_H */ -- cgit v1.2.3 From afefdbb28a0a2af689926c30b94a14aea6036719 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 3 Oct 2006 01:13:46 -0700 Subject: [PATCH] VFS: Make filldir_t and struct kstat deal in 64-bit inode numbers These patches make the kernel pass 64-bit inode numbers internally when communicating to userspace, even on a 32-bit system. They are required because some filesystems have intrinsic 64-bit inode numbers: NFS3+ and XFS for example. The 64-bit inode numbers are then propagated to userspace automatically where the arch supports it. Problems have been seen with userspace (eg: ld.so) using the 64-bit inode number returned by stat64() or getdents64() to differentiate files, and failing because the 64-bit inode number space was compressed to 32-bits, and so overlaps occur. This patch: Make filldir_t take a 64-bit inode number and struct kstat carry a 64-bit inode number so that 64-bit inode numbers can be passed back to userspace. The stat functions then returns the full 64-bit inode number where available and where possible. If it is not possible to represent the inode number supplied by the filesystem in the field provided by userspace, then error EOVERFLOW will be issued. Similarly, the getdents/readdir functions now pass the full 64-bit inode number to userspace where possible, returning EOVERFLOW instead when a directory entry is encountered that can't be properly represented. Note that this means that some inodes will not be stat'able on a 32-bit system with old libraries where they were before - but it does mean that there will be no ambiguity over what a 32-bit inode number refers to. Note similarly that directory scans may be cut short with an error on a 32-bit system with old libraries where the scan would work before for the same reasons. It is judged unlikely that this situation will occur because modern glibc uses 64-bit capable versions of stat and getdents class functions exclusively, and that older systems are unlikely to encounter unrepresentable inode numbers anyway. [akpm: alpha build fix] Signed-off-by: David Howells Cc: Trond Myklebust Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/osf_sys.c | 8 ++++++-- arch/ia64/ia32/sys_ia32.c | 23 ++++++++++++++++++----- arch/mips/kernel/linux32.c | 2 ++ arch/mips/kernel/sysirix.c | 10 +++++++--- arch/parisc/hpux/fs.c | 6 +++++- arch/parisc/kernel/sys_parisc32.c | 19 ++++++++++++++++--- arch/powerpc/kernel/sys_ppc32.c | 15 ++++++++++++--- arch/s390/kernel/compat_linux.c | 5 +++++ arch/sparc/kernel/sys_sunos.c | 16 ++++++++++++---- arch/sparc64/kernel/sys_sparc32.c | 5 +++++ arch/sparc64/kernel/sys_sunos32.c | 12 ++++++++++-- arch/sparc64/solaris/fs.c | 7 ++++++- arch/x86_64/ia32/sys_ia32.c | 7 ++++++- fs/afs/dir.c | 4 ++-- fs/compat.c | 18 +++++++++++++----- fs/exportfs/expfs.c | 2 +- fs/fat/dir.c | 2 +- fs/nfsd/nfs4recover.c | 2 +- fs/readdir.c | 18 +++++++++++++----- fs/reiserfs/xattr.c | 6 +++--- fs/stat.c | 6 ++++++ include/linux/fs.h | 2 +- include/linux/stat.h | 2 +- 23 files changed, 152 insertions(+), 45 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 8a31fc1bfb15..ad6173651995 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -111,22 +111,26 @@ struct osf_dirent_callback { static int osf_filldir(void *__buf, const char *name, int namlen, loff_t offset, - ino_t ino, unsigned int d_type) + u64 ino, unsigned int d_type) { struct osf_dirent __user *dirent; struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf; unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1); + unsigned int d_ino; buf->error = -EINVAL; /* only used if we fail */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; if (buf->basep) { if (put_user(offset, buf->basep)) return -EFAULT; buf->basep = NULL; } dirent = buf->dirent; - put_user(ino, &dirent->d_ino); + put_user(d_ino, &dirent->d_ino); put_user(namlen, &dirent->d_namlen); put_user(reclen, &dirent->d_reclen); if (copy_to_user(dirent->d_name, name, namlen) || diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index bddbd22706ed..9d6a3f210148 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -125,6 +125,7 @@ sys32_execve (char __user *name, compat_uptr_t __user *argv, compat_uptr_t __use int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) { + compat_ino_t ino; int err; if ((u64) stat->size > MAX_NON_LFS || @@ -132,11 +133,15 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) !old_valid_dev(stat->rdev)) return -EOVERFLOW; + ino = stat->ino; + if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino) + return -EOVERFLOW; + if (clear_user(ubuf, sizeof(*ubuf))) return -EFAULT; err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev); - err |= __put_user(stat->ino, &ubuf->st_ino); + err |= __put_user(ino, &ubuf->st_ino); err |= __put_user(stat->mode, &ubuf->st_mode); err |= __put_user(stat->nlink, &ubuf->st_nlink); err |= __put_user(high2lowuid(stat->uid), &ubuf->st_uid); @@ -1222,16 +1227,20 @@ struct readdir32_callback { }; static int -filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, +filldir32 (void *__buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { struct compat_dirent __user * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; int reclen = ROUND_UP(offsetof(struct compat_dirent, d_name) + namlen + 1, 4); + u32 d_ino; buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; buf->error = -EFAULT; /* only used if we fail.. */ dirent = buf->previous; if (dirent) @@ -1239,7 +1248,7 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, return -EFAULT; dirent = buf->current_dir; buf->previous = dirent; - if (put_user(ino, &dirent->d_ino) + if (put_user(d_ino, &dirent->d_ino) || put_user(reclen, &dirent->d_reclen) || copy_to_user(dirent->d_name, name, namlen) || put_user(0, dirent->d_name + namlen)) @@ -1287,17 +1296,21 @@ out: } static int -fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, +fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { struct readdir32_callback * buf = (struct readdir32_callback *) __buf; struct old_linux32_dirent __user * dirent; + u32 d_ino; if (buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; buf->count++; dirent = buf->dirent; - if (put_user(ino, &dirent->d_ino) + if (put_user(d_ino, &dirent->d_ino) || put_user(offset, &dirent->d_offset) || put_user(namlen, &dirent->d_namlen) || copy_to_user(dirent->d_name, name, namlen) diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 52cada45b353..53f4171fc188 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -77,6 +77,8 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) memset(&tmp, 0, sizeof(tmp)); tmp.st_dev = new_encode_dev(stat->dev); tmp.st_ino = stat->ino; + if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) + return -EOVERFLOW; tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; SET_UID(tmp.st_uid, stat->uid); diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 11bb97174972..93c74fefff76 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -1739,12 +1739,13 @@ struct irix_dirent32_callback { #define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1)) static int irix_filldir32(void *__buf, const char *name, - int namlen, loff_t offset, ino_t ino, unsigned int d_type) + int namlen, loff_t offset, u64 ino, unsigned int d_type) { struct irix_dirent32 __user *dirent; struct irix_dirent32_callback *buf = __buf; unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1); int err = 0; + u32 d_ino; #ifdef DEBUG_GETDENTS printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]", @@ -1753,12 +1754,15 @@ static int irix_filldir32(void *__buf, const char *name, buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; dirent = buf->previous; if (dirent) err = __put_user(offset, &dirent->d_off); dirent = buf->current_dir; err |= __put_user(dirent, &buf->previous); - err |= __put_user(ino, &dirent->d_ino); + err |= __put_user(d_ino, &dirent->d_ino); err |= __put_user(reclen, &dirent->d_reclen); err |= copy_to_user((char __user *)dirent->d_name, name, namlen) ? -EFAULT : 0; err |= __put_user(0, &dirent->d_name[namlen]); @@ -1837,7 +1841,7 @@ struct irix_dirent64_callback { #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) static int irix_filldir64(void *__buf, const char *name, - int namlen, loff_t offset, ino_t ino, unsigned int d_type) + int namlen, loff_t offset, u64 ino, unsigned int d_type) { struct irix_dirent64 __user *dirent; struct irix_dirent64_callback * buf = __buf; diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index d7c80edf4489..6e79dbf3f6bd 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -77,17 +77,21 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, { struct hpux_dirent * dirent; struct getdents_callback * buf = (struct getdents_callback *) __buf; + ino_t d_ino; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; dirent = buf->previous; if (dirent) put_user(offset, &dirent->d_off); dirent = buf->current_dir; buf->previous = dirent; - put_user(ino, &dirent->d_ino); + put_user(d_ino, &dirent->d_ino); put_user(reclen, &dirent->d_reclen); put_user(namlen, &dirent->d_namlen); copy_to_user(dirent->d_name, name, namlen); diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index b74869803081..e3b30bc36453 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -237,14 +237,19 @@ int sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) { + compat_ino_t ino; int err; if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev)) return -EOVERFLOW; + ino = stat->ino; + if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino) + return -EOVERFLOW; + err = put_user(new_encode_dev(stat->dev), &statbuf->st_dev); - err |= put_user(stat->ino, &statbuf->st_ino); + err |= put_user(ino, &statbuf->st_ino); err |= put_user(stat->mode, &statbuf->st_mode); err |= put_user(stat->nlink, &statbuf->st_nlink); err |= put_user(0, &statbuf->st_reserved1); @@ -312,16 +317,20 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, struct linux32_dirent __user * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4); + u32 d_ino; buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; dirent = buf->previous; if (dirent) put_user(offset, &dirent->d_off); dirent = buf->current_dir; buf->previous = dirent; - put_user(ino, &dirent->d_ino); + put_user(d_ino, &dirent->d_ino); put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); @@ -371,12 +380,16 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t { struct readdir32_callback * buf = (struct readdir32_callback *) __buf; struct old_linux32_dirent __user * dirent; + u32 d_ino; if (buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; buf->count++; dirent = buf->dirent; - put_user(ino, &dirent->d_ino); + put_user(d_ino, &dirent->d_ino); put_user(offset, &dirent->d_offset); put_user(namlen, &dirent->d_namlen); copy_to_user(dirent->d_name, name, namlen); diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index 5e391fc25340..d15c33e95959 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c @@ -69,16 +69,20 @@ struct readdir_callback32 { }; static int fillonedir(void * __buf, const char * name, int namlen, - off_t offset, ino_t ino, unsigned int d_type) + off_t offset, u64 ino, unsigned int d_type) { struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf; struct old_linux_dirent32 __user * dirent; + ino_t d_ino; if (buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; buf->count++; dirent = buf->dirent; - put_user(ino, &dirent->d_ino); + put_user(d_ino, &dirent->d_ino); put_user(offset, &dirent->d_offset); put_user(namlen, &dirent->d_namlen); copy_to_user(dirent->d_name, name, namlen); @@ -120,15 +124,20 @@ asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp, int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) { + compat_ino_t ino; long err; if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev)) return -EOVERFLOW; + ino = stat->ino; + if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino) + return -EOVERFLOW; + err = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT; err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev); - err |= __put_user(stat->ino, &statbuf->st_ino); + err |= __put_user(ino, &statbuf->st_ino); err |= __put_user(stat->mode, &statbuf->st_mode); err |= __put_user(stat->nlink, &statbuf->st_nlink); err |= __put_user(stat->uid, &statbuf->st_uid); diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index c46e3d48e410..e15e1489aef5 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -357,11 +357,16 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) { + compat_ino_t ino; int err; if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) return -EOVERFLOW; + ino = stat->ino; + if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino) + return -EOVERFLOW; + err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev); err |= put_user(stat->ino, &statbuf->st_ino); err |= put_user(stat->mode, &statbuf->st_mode); diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 9d2cd97d1c3a..6f3ac548ee66 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -325,21 +325,25 @@ struct sunos_dirent_callback { #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) static int sunos_filldir(void * __buf, const char * name, int namlen, - loff_t offset, ino_t ino, unsigned int d_type) + loff_t offset, u64 ino, unsigned int d_type) { struct sunos_dirent __user *dirent; struct sunos_dirent_callback * buf = __buf; + unsigned long d_ino; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; dirent = buf->previous; if (dirent) put_user(offset, &dirent->d_off); dirent = buf->curr; buf->previous = dirent; - put_user(ino, &dirent->d_ino); + put_user(d_ino, &dirent->d_ino); put_user(namlen, &dirent->d_namlen); put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); @@ -406,19 +410,23 @@ struct sunos_direntry_callback { }; static int sunos_filldirentry(void * __buf, const char * name, int namlen, - loff_t offset, ino_t ino, unsigned int d_type) + loff_t offset, u64 ino, unsigned int d_type) { struct sunos_direntry __user *dirent; struct sunos_direntry_callback *buf = __buf; + unsigned long d_ino; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; dirent = buf->previous; dirent = buf->curr; buf->previous = dirent; - put_user(ino, &dirent->d_ino); + put_user(d_ino, &dirent->d_ino); put_user(namlen, &dirent->d_namlen); put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 69444f266e2d..dbc6d1a3be1f 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -337,12 +337,17 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) { + compat_ino_t ino; int err; if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) return -EOVERFLOW; + ino = stat->ino; + if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino) + return -EOVERFLOW; + err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev); err |= put_user(stat->ino, &statbuf->st_ino); err |= put_user(stat->mode, &statbuf->st_mode); diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index 953296b73f3f..e414c8ef0225 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -280,16 +280,20 @@ static int sunos_filldir(void * __buf, const char * name, int namlen, struct sunos_dirent __user *dirent; struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); + u32 d_ino; buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; dirent = buf->previous; if (dirent) put_user(offset, &dirent->d_off); dirent = buf->curr; buf->previous = dirent; - put_user(ino, &dirent->d_ino); + put_user(d_ino, &dirent->d_ino); put_user(namlen, &dirent->d_namlen); put_user(reclen, &dirent->d_reclen); if (copy_to_user(dirent->d_name, name, namlen)) @@ -363,14 +367,18 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen, struct sunos_direntry_callback * buf = (struct sunos_direntry_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); + u32 d_ino; buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; dirent = buf->previous; dirent = buf->curr; buf->previous = dirent; - put_user(ino, &dirent->d_ino); + put_user(d_ino, &dirent->d_ino); put_user(namlen, &dirent->d_namlen); put_user(reclen, &dirent->d_reclen); if (copy_to_user(dirent->d_name, name, namlen)) diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index 0f0eb6aa1c40..12a940cc791f 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -82,12 +82,17 @@ struct sol_stat64 { static inline int putstat(struct sol_stat __user *ubuf, struct kstat *kbuf) { + u32 ino; + if (kbuf->size > MAX_NON_LFS || !sysv_valid_dev(kbuf->dev) || !sysv_valid_dev(kbuf->rdev)) return -EOVERFLOW; + ino = kbuf->ino; + if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino) + return -EOVERFLOW; if (put_user (sysv_encode_dev(kbuf->dev), &ubuf->st_dev) || - __put_user (kbuf->ino, &ubuf->st_ino) || + __put_user (ino, &ubuf->st_ino) || __put_user (kbuf->mode, &ubuf->st_mode) || __put_user (kbuf->nlink, &ubuf->st_nlink) || __put_user (kbuf->uid, &ubuf->st_uid) || diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index 26a01717cc1a..c9bac3af29d6 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -76,6 +76,8 @@ int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf) { + compat_ino_t ino; + typeof(ubuf->st_uid) uid = 0; typeof(ubuf->st_gid) gid = 0; SET_UID(uid, kbuf->uid); @@ -84,9 +86,12 @@ int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf) return -EOVERFLOW; if (kbuf->size >= 0x7fffffff) return -EOVERFLOW; + ino = kbuf->ino; + if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino) + return -EOVERFLOW; if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) || __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) || - __put_user (kbuf->ino, &ubuf->st_ino) || + __put_user (ino, &ubuf->st_ino) || __put_user (kbuf->mode, &ubuf->st_mode) || __put_user (kbuf->nlink, &ubuf->st_nlink) || __put_user (uid, &ubuf->st_uid) || diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 2fc99877cb0d..cf8a2cb28505 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -30,7 +30,7 @@ static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir); static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd); static int afs_d_delete(struct dentry *dentry); static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, - loff_t fpos, ino_t ino, unsigned dtype); + loff_t fpos, u64 ino, unsigned dtype); const struct file_operations afs_dir_file_operations = { .open = afs_dir_open, @@ -409,7 +409,7 @@ static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir) * uniquifier through dtype */ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, - loff_t fpos, ino_t ino, unsigned dtype) + loff_t fpos, u64 ino, unsigned dtype) { struct afs_dir_lookup_cookie *cookie = _cookie; diff --git a/fs/compat.c b/fs/compat.c index d98c96f4a44d..4d3fbcb2ddb1 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -914,20 +914,24 @@ struct compat_readdir_callback { }; static int compat_fillonedir(void *__buf, const char *name, int namlen, - loff_t offset, ino_t ino, unsigned int d_type) + loff_t offset, u64 ino, unsigned int d_type) { struct compat_readdir_callback *buf = __buf; struct compat_old_linux_dirent __user *dirent; + compat_ulong_t d_ino; if (buf->result) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; buf->result++; dirent = buf->dirent; if (!access_ok(VERIFY_WRITE, dirent, (unsigned long)(dirent->d_name + namlen + 1) - (unsigned long)dirent)) goto efault; - if ( __put_user(ino, &dirent->d_ino) || + if ( __put_user(d_ino, &dirent->d_ino) || __put_user(offset, &dirent->d_offset) || __put_user(namlen, &dirent->d_namlen) || __copy_to_user(dirent->d_name, name, namlen) || @@ -978,22 +982,26 @@ struct compat_getdents_callback { }; static int compat_filldir(void *__buf, const char *name, int namlen, - loff_t offset, ino_t ino, unsigned int d_type) + loff_t offset, u64 ino, unsigned int d_type) { struct compat_linux_dirent __user * dirent; struct compat_getdents_callback *buf = __buf; + compat_ulong_t d_ino; int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) goto efault; } dirent = buf->current_dir; - if (__put_user(ino, &dirent->d_ino)) + if (__put_user(d_ino, &dirent->d_ino)) goto efault; if (__put_user(reclen, &dirent->d_reclen)) goto efault; @@ -1064,7 +1072,7 @@ struct compat_getdents_callback64 { }; static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset, - ino_t ino, unsigned int d_type) + u64 ino, unsigned int d_type) { struct linux_dirent64 __user *dirent; struct compat_getdents_callback64 *buf = __buf; diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 4c39009350f3..93e77c3d2490 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -315,7 +315,7 @@ struct getdents_callback { * the name matching the specified inode number. */ static int filldir_one(void * __buf, const char * name, int len, - loff_t pos, ino_t ino, unsigned int d_type) + loff_t pos, u64 ino, unsigned int d_type) { struct getdents_callback *buf = __buf; int result = 0; diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 3e50a4166283..69c439f44387 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -648,7 +648,7 @@ static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir) } static int fat_ioctl_filldir(void *__buf, const char *name, int name_len, - loff_t offset, ino_t ino, unsigned int d_type) + loff_t offset, u64 ino, unsigned int d_type) { struct fat_ioctl_filldir_callback *buf = __buf; struct dirent __user *d1 = buf->dirent; diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index e35d7e52fdeb..1cbd2e4ee122 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -184,7 +184,7 @@ struct dentry_list_arg { static int nfsd4_build_dentrylist(void *arg, const char *name, int namlen, - loff_t offset, ino_t ino, unsigned int d_type) + loff_t offset, u64 ino, unsigned int d_type) { struct dentry_list_arg *dla = arg; struct list_head *dentries = &dla->dentries; diff --git a/fs/readdir.c b/fs/readdir.c index b6109329b607..bff3ee58e2f8 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -69,20 +69,24 @@ struct readdir_callback { }; static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset, - ino_t ino, unsigned int d_type) + u64 ino, unsigned int d_type) { struct readdir_callback * buf = (struct readdir_callback *) __buf; struct old_linux_dirent __user * dirent; + unsigned long d_ino; if (buf->result) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; buf->result++; dirent = buf->dirent; if (!access_ok(VERIFY_WRITE, dirent, (unsigned long)(dirent->d_name + namlen + 1) - (unsigned long)dirent)) goto efault; - if ( __put_user(ino, &dirent->d_ino) || + if ( __put_user(d_ino, &dirent->d_ino) || __put_user(offset, &dirent->d_offset) || __put_user(namlen, &dirent->d_namlen) || __copy_to_user(dirent->d_name, name, namlen) || @@ -138,22 +142,26 @@ struct getdents_callback { }; static int filldir(void * __buf, const char * name, int namlen, loff_t offset, - ino_t ino, unsigned int d_type) + u64 ino, unsigned int d_type) { struct linux_dirent __user * dirent; struct getdents_callback * buf = (struct getdents_callback *) __buf; + unsigned long d_ino; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + d_ino = ino; + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) + return -EOVERFLOW; dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) goto efault; } dirent = buf->current_dir; - if (__put_user(ino, &dirent->d_ino)) + if (__put_user(d_ino, &dirent->d_ino)) goto efault; if (__put_user(reclen, &dirent->d_reclen)) goto efault; @@ -222,7 +230,7 @@ struct getdents_callback64 { }; static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, - ino_t ino, unsigned int d_type) + u64 ino, unsigned int d_type) { struct linux_dirent64 __user *dirent; struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf; diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index d935fb9394e3..7bdb0ed443e1 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -773,7 +773,7 @@ int reiserfs_xattr_del(struct inode *inode, const char *name) static int reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, - loff_t offset, ino_t ino, unsigned int d_type) + loff_t offset, u64 ino, unsigned int d_type) { struct dentry *xadir = (struct dentry *)buf; @@ -851,7 +851,7 @@ struct reiserfs_chown_buf { /* XXX: If there is a better way to do this, I'd love to hear about it */ static int reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, - loff_t offset, ino_t ino, unsigned int d_type) + loff_t offset, u64 ino, unsigned int d_type) { struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; struct dentry *xafile, *xadir = chown_buf->xadir; @@ -1036,7 +1036,7 @@ struct reiserfs_listxattr_buf { static int reiserfs_listxattr_filler(void *buf, const char *name, int namelen, - loff_t offset, ino_t ino, unsigned int d_type) + loff_t offset, u64 ino, unsigned int d_type) { struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf; int len = 0; diff --git a/fs/stat.c b/fs/stat.c index 60a31d5e5966..bca07eb2003c 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -140,6 +140,8 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta memset(&tmp, 0, sizeof(struct __old_kernel_stat)); tmp.st_dev = old_encode_dev(stat->dev); tmp.st_ino = stat->ino; + if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) + return -EOVERFLOW; tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; if (tmp.st_nlink != stat->nlink) @@ -210,6 +212,8 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) tmp.st_dev = new_encode_dev(stat->dev); #endif tmp.st_ino = stat->ino; + if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) + return -EOVERFLOW; tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; if (tmp.st_nlink != stat->nlink) @@ -347,6 +351,8 @@ static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) tmp.st_rdev = huge_encode_dev(stat->rdev); #endif tmp.st_ino = stat->ino; + if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) + return -EOVERFLOW; #ifdef STAT64_HAS_BROKEN_ST_INO tmp.__st_ino = stat->ino; #endif diff --git a/include/linux/fs.h b/include/linux/fs.h index 91c0b2a32a90..7b61e94bf8fc 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1049,7 +1049,7 @@ int generic_osync_inode(struct inode *, struct address_space *, int); * This allows the kernel to read directories into kernel space or * to have different dirent layouts depending on the binary type. */ -typedef int (*filldir_t)(void *, const char *, int, loff_t, ino_t, unsigned); +typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); struct block_device_operations { int (*open) (struct inode *, struct file *); diff --git a/include/linux/stat.h b/include/linux/stat.h index 8669291352db..679ef0d70b6b 100644 --- a/include/linux/stat.h +++ b/include/linux/stat.h @@ -57,7 +57,7 @@ #include struct kstat { - unsigned long ino; + u64 ino; dev_t dev; umode_t mode; unsigned int nlink; -- cgit v1.2.3 From ffc5089196446c08d9a005cf0dd7cab18d119606 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Tue, 3 Oct 2006 01:13:48 -0700 Subject: [PATCH] Create kallsyms_lookup_size_offset() Some uses of kallsyms_lookup() do not need to find out the name of a symbol and its module's name it belongs. This is specially true in arch specific code, which needs to unwind the stack to show the back trace during oops (mips is an example). In this specific case, we just need to retreive the function's size and the offset of the active intruction inside it. Adds a new entry "kallsyms_lookup_size_offset()" This new entry does exactly the same as kallsyms_lookup() but does not require any buffers to store any names. It returns 0 if it fails otherwise 1. Signed-off-by: Franck Bui-Huu Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kallsyms.h | 11 +++++ kernel/kallsyms.c | 123 ++++++++++++++++++++++++++++++----------------- kernel/module.c | 3 +- 3 files changed, 93 insertions(+), 44 deletions(-) (limited to 'include/linux') diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h index 849043ce4ed6..1cebcbc28b47 100644 --- a/include/linux/kallsyms.h +++ b/include/linux/kallsyms.h @@ -12,6 +12,10 @@ /* Lookup the address for a symbol. Returns 0 if not found. */ unsigned long kallsyms_lookup_name(const char *name); +extern int kallsyms_lookup_size_offset(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset); + /* Lookup an address. modname is set to NULL if it's in the kernel. */ const char *kallsyms_lookup(unsigned long addr, unsigned long *symbolsize, @@ -28,6 +32,13 @@ static inline unsigned long kallsyms_lookup_name(const char *name) return 0; } +static inline int kallsyms_lookup_size_offset(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset) +{ + return 0; +} + static inline const char *kallsyms_lookup(unsigned long addr, unsigned long *symbolsize, unsigned long *offset, diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 342bca62c496..eeac3e313b2b 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -69,6 +69,15 @@ static inline int is_kernel(unsigned long addr) return in_gate_area_no_task(addr); } +static int is_ksym_addr(unsigned long addr) +{ + if (all_var) + return is_kernel(addr); + + return is_kernel_text(addr) || is_kernel_inittext(addr) || + is_kernel_extratext(addr); +} + /* expand a compressed symbol data into the resulting uncompressed string, given the offset to where the symbol is in the compressed stream */ static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) @@ -155,6 +164,73 @@ unsigned long kallsyms_lookup_name(const char *name) return module_kallsyms_lookup_name(name); } +static unsigned long get_symbol_pos(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset) +{ + unsigned long symbol_start = 0, symbol_end = 0; + unsigned long i, low, high, mid; + + /* This kernel should never had been booted. */ + BUG_ON(!kallsyms_addresses); + + /* do a binary search on the sorted kallsyms_addresses array */ + low = 0; + high = kallsyms_num_syms; + + while (high - low > 1) { + mid = (low + high) / 2; + if (kallsyms_addresses[mid] <= addr) + low = mid; + else + high = mid; + } + + /* + * search for the first aliased symbol. Aliased + * symbols are symbols with the same address + */ + while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low]) + --low; + + symbol_start = kallsyms_addresses[low]; + + /* Search for next non-aliased symbol */ + for (i = low + 1; i < kallsyms_num_syms; i++) { + if (kallsyms_addresses[i] > symbol_start) { + symbol_end = kallsyms_addresses[i]; + break; + } + } + + /* if we found no next symbol, we use the end of the section */ + if (!symbol_end) { + if (is_kernel_inittext(addr)) + symbol_end = (unsigned long)_einittext; + else if (all_var) + symbol_end = (unsigned long)_end; + else + symbol_end = (unsigned long)_etext; + } + + *symbolsize = symbol_end - symbol_start; + *offset = addr - symbol_start; + + return low; +} + +/* + * Lookup an address but don't bother to find any names. + */ +int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, + unsigned long *offset) +{ + if (is_ksym_addr(addr)) + return !!get_symbol_pos(addr, symbolsize, offset); + + return !!module_address_lookup(addr, symbolsize, offset, NULL); +} + /* * Lookup an address * - modname is set to NULL if it's in the kernel @@ -167,57 +243,18 @@ const char *kallsyms_lookup(unsigned long addr, unsigned long *offset, char **modname, char *namebuf) { - unsigned long i, low, high, mid; const char *msym; - /* This kernel should never had been booted. */ - BUG_ON(!kallsyms_addresses); - namebuf[KSYM_NAME_LEN] = 0; namebuf[0] = 0; - if ((all_var && is_kernel(addr)) || - (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr) || - is_kernel_extratext(addr)))) { - unsigned long symbol_end = 0; - - /* do a binary search on the sorted kallsyms_addresses array */ - low = 0; - high = kallsyms_num_syms; - - while (high-low > 1) { - mid = (low + high) / 2; - if (kallsyms_addresses[mid] <= addr) low = mid; - else high = mid; - } - - /* search for the first aliased symbol. Aliased symbols are - symbols with the same address */ - while (low && kallsyms_addresses[low - 1] == kallsyms_addresses[low]) - --low; + if (is_ksym_addr(addr)) { + unsigned long pos; + pos = get_symbol_pos(addr, symbolsize, offset); /* Grab name */ - kallsyms_expand_symbol(get_symbol_offset(low), namebuf); - - /* Search for next non-aliased symbol */ - for (i = low + 1; i < kallsyms_num_syms; i++) { - if (kallsyms_addresses[i] > kallsyms_addresses[low]) { - symbol_end = kallsyms_addresses[i]; - break; - } - } - - /* if we found no next symbol, we use the end of the section */ - if (!symbol_end) { - if (is_kernel_inittext(addr)) - symbol_end = (unsigned long)_einittext; - else - symbol_end = all_var ? (unsigned long)_end : (unsigned long)_etext; - } - - *symbolsize = symbol_end - kallsyms_addresses[low]; + kallsyms_expand_symbol(get_symbol_offset(pos), namebuf); *modname = NULL; - *offset = addr - kallsyms_addresses[low]; return namebuf; } diff --git a/kernel/module.c b/kernel/module.c index 7c77a0a9275c..7f60e782de1e 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2040,7 +2040,8 @@ const char *module_address_lookup(unsigned long addr, list_for_each_entry(mod, &modules, list) { if (within(addr, mod->module_init, mod->init_size) || within(addr, mod->module_core, mod->core_size)) { - *modname = mod->name; + if (modname) + *modname = mod->name; return get_ksymbol(mod, addr, size, offset); } } -- cgit v1.2.3 From 1a84887080dc15f048db7c3a643e98f1435790d6 Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" Date: Tue, 3 Oct 2006 01:14:08 -0700 Subject: [PATCH] sched: introduce child field in sched_domain Introduce the child field in sched_domain struct and use it in sched_balance_self(). We will also use this field in cleaning up the sched group cpu_power setup(done in a different patch) code. Signed-off-by: Suresh Siddha Acked-by: Ingo Molnar Acked-by: Nick Piggin Cc: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-i386/topology.h | 1 + include/asm-ia64/topology.h | 2 ++ include/asm-mips/mach-ip27/topology.h | 1 + include/asm-powerpc/topology.h | 1 + include/asm-x86_64/topology.h | 1 + include/linux/sched.h | 1 + include/linux/topology.h | 3 +++ kernel/sched.c | 40 ++++++++++++++++++++++++++--------- 8 files changed, 40 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h index 6adbd9b1ae88..978d09596130 100644 --- a/include/asm-i386/topology.h +++ b/include/asm-i386/topology.h @@ -74,6 +74,7 @@ static inline int node_to_first_cpu(int node) #define SD_NODE_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ + .child = NULL, \ .groups = NULL, \ .min_interval = 8, \ .max_interval = 32, \ diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h index 937c21257523..a6e38565ab4c 100644 --- a/include/asm-ia64/topology.h +++ b/include/asm-ia64/topology.h @@ -59,6 +59,7 @@ void build_cpu_to_node_map(void); #define SD_CPU_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ + .child = NULL, \ .groups = NULL, \ .min_interval = 1, \ .max_interval = 4, \ @@ -84,6 +85,7 @@ void build_cpu_to_node_map(void); #define SD_NODE_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ + .child = NULL, \ .groups = NULL, \ .min_interval = 8, \ .max_interval = 8*(min(num_online_cpus(), 32)), \ diff --git a/include/asm-mips/mach-ip27/topology.h b/include/asm-mips/mach-ip27/topology.h index 59d26b52ba32..a13b715fd9ca 100644 --- a/include/asm-mips/mach-ip27/topology.h +++ b/include/asm-mips/mach-ip27/topology.h @@ -22,6 +22,7 @@ extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES]; #define SD_NODE_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ + .child = NULL, \ .groups = NULL, \ .min_interval = 8, \ .max_interval = 32, \ diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h index bbc3844b086f..8f7ee16781a4 100644 --- a/include/asm-powerpc/topology.h +++ b/include/asm-powerpc/topology.h @@ -43,6 +43,7 @@ extern int pcibus_to_node(struct pci_bus *bus); #define SD_NODE_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ + .child = NULL, \ .groups = NULL, \ .min_interval = 8, \ .max_interval = 32, \ diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h index 6e7a2e976b04..5c8f49280dbc 100644 --- a/include/asm-x86_64/topology.h +++ b/include/asm-x86_64/topology.h @@ -31,6 +31,7 @@ extern int __node_distance(int, int); #define SD_NODE_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ + .child = NULL, \ .groups = NULL, \ .min_interval = 8, \ .max_interval = 32, \ diff --git a/include/linux/sched.h b/include/linux/sched.h index 38530232d92f..8e26c9069f15 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -644,6 +644,7 @@ struct sched_group { struct sched_domain { /* These fields must be setup */ struct sched_domain *parent; /* top domain must be null terminated */ + struct sched_domain *child; /* bottom domain must be null terminated */ struct sched_group *groups; /* the balancing groups of the domain */ cpumask_t span; /* span of all CPUs in this domain */ unsigned long min_interval; /* Minimum balance interval ms */ diff --git a/include/linux/topology.h b/include/linux/topology.h index ec1eca85290a..486bec23f986 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -89,6 +89,7 @@ #define SD_SIBLING_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ + .child = NULL, \ .groups = NULL, \ .min_interval = 1, \ .max_interval = 2, \ @@ -119,6 +120,7 @@ #define SD_CPU_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ + .child = NULL, \ .groups = NULL, \ .min_interval = 1, \ .max_interval = 4, \ @@ -146,6 +148,7 @@ #define SD_ALLNODES_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ + .child = NULL, \ .groups = NULL, \ .min_interval = 64, \ .max_interval = 64*num_online_cpus(), \ diff --git a/kernel/sched.c b/kernel/sched.c index 6d7bf55ec33d..0feeacb91497 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1286,21 +1286,29 @@ static int sched_balance_self(int cpu, int flag) while (sd) { cpumask_t span; struct sched_group *group; - int new_cpu; - int weight; + int new_cpu, weight; + + if (!(sd->flags & flag)) { + sd = sd->child; + continue; + } span = sd->span; group = find_idlest_group(sd, t, cpu); - if (!group) - goto nextlevel; + if (!group) { + sd = sd->child; + continue; + } new_cpu = find_idlest_cpu(group, t, cpu); - if (new_cpu == -1 || new_cpu == cpu) - goto nextlevel; + if (new_cpu == -1 || new_cpu == cpu) { + /* Now try balancing at a lower domain level of cpu */ + sd = sd->child; + continue; + } - /* Now try balancing at a lower domain level */ + /* Now try balancing at a lower domain level of new_cpu */ cpu = new_cpu; -nextlevel: sd = NULL; weight = cpus_weight(span); for_each_domain(cpu, tmp) { @@ -5448,12 +5456,18 @@ static void cpu_attach_domain(struct sched_domain *sd, int cpu) struct sched_domain *parent = tmp->parent; if (!parent) break; - if (sd_parent_degenerate(tmp, parent)) + if (sd_parent_degenerate(tmp, parent)) { tmp->parent = parent->parent; + if (parent->parent) + parent->parent->child = tmp; + } } - if (sd && sd_degenerate(sd)) + if (sd && sd_degenerate(sd)) { sd = sd->parent; + if (sd) + sd->child = NULL; + } sched_domain_debug(sd, cpu); @@ -6288,6 +6302,8 @@ static int build_sched_domains(const cpumask_t *cpu_map) *sd = SD_NODE_INIT; sd->span = sched_domain_node_span(cpu_to_node(i)); sd->parent = p; + if (p) + p->child = sd; cpus_and(sd->span, sd->span, *cpu_map); #endif @@ -6297,6 +6313,8 @@ static int build_sched_domains(const cpumask_t *cpu_map) *sd = SD_CPU_INIT; sd->span = nodemask; sd->parent = p; + if (p) + p->child = sd; sd->groups = &sched_group_phys[group]; #ifdef CONFIG_SCHED_MC @@ -6307,6 +6325,7 @@ static int build_sched_domains(const cpumask_t *cpu_map) sd->span = cpu_coregroup_map(i); cpus_and(sd->span, sd->span, *cpu_map); sd->parent = p; + p->child = sd; sd->groups = &sched_group_core[group]; #endif @@ -6318,6 +6337,7 @@ static int build_sched_domains(const cpumask_t *cpu_map) sd->span = cpu_sibling_map[i]; cpus_and(sd->span, sd->span, *cpu_map); sd->parent = p; + p->child = sd; sd->groups = &sched_group_cpus[group]; #endif } -- cgit v1.2.3 From 89c4710ee9bbbefe6a4d469d9f36266a92c275c5 Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" Date: Tue, 3 Oct 2006 01:14:09 -0700 Subject: [PATCH] sched: cleanup sched_group cpu_power setup Up to now sched group's cpu_power for each sched domain is initialized independently. This made the setup code ugly as the new sched domains are getting added. Make the sched group cpu_power setup code generic, by using domain child field and new domain flag in sched_domain. For most of the sched domains(except NUMA), sched group's cpu_power is now computed generically using the domain properties of itself and of the child domain. sched groups in NUMA domains are setup little differently and hence they don't use this generic mechanism. Signed-off-by: Suresh Siddha Acked-by: Ingo Molnar Acked-by: Nick Piggin Cc: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 12 +++- include/linux/topology.h | 43 ++++++++++---- kernel/sched.c | 145 +++++++++++++++++++++++++++-------------------- 3 files changed, 125 insertions(+), 75 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 8e26c9069f15..331f4502e92b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -625,9 +625,17 @@ enum idle_type #define SD_WAKE_BALANCE 64 /* Perform balancing at task wakeup */ #define SD_SHARE_CPUPOWER 128 /* Domain members share cpu power */ #define SD_POWERSAVINGS_BALANCE 256 /* Balance for power savings */ +#define SD_SHARE_PKG_RESOURCES 512 /* Domain members share cpu pkg resources */ -#define BALANCE_FOR_POWER ((sched_mc_power_savings || sched_smt_power_savings) \ - ? SD_POWERSAVINGS_BALANCE : 0) +#define BALANCE_FOR_MC_POWER \ + (sched_smt_power_savings ? SD_POWERSAVINGS_BALANCE : 0) + +#define BALANCE_FOR_PKG_POWER \ + ((sched_mc_power_savings || sched_smt_power_savings) ? \ + SD_POWERSAVINGS_BALANCE : 0) + +#define test_sd_parent(sd, flag) ((sd->parent && \ + (sd->parent->flags & flag)) ? 1 : 0) struct sched_group { diff --git a/include/linux/topology.h b/include/linux/topology.h index 486bec23f986..da508d1998e4 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -115,6 +115,38 @@ #endif #endif /* CONFIG_SCHED_SMT */ +#ifdef CONFIG_SCHED_MC +/* Common values for MC siblings. for now mostly derived from SD_CPU_INIT */ +#ifndef SD_MC_INIT +#define SD_MC_INIT (struct sched_domain) { \ + .span = CPU_MASK_NONE, \ + .parent = NULL, \ + .child = NULL, \ + .groups = NULL, \ + .min_interval = 1, \ + .max_interval = 4, \ + .busy_factor = 64, \ + .imbalance_pct = 125, \ + .cache_nice_tries = 1, \ + .per_cpu_gain = 100, \ + .busy_idx = 2, \ + .idle_idx = 1, \ + .newidle_idx = 2, \ + .wake_idx = 1, \ + .forkexec_idx = 1, \ + .flags = SD_LOAD_BALANCE \ + | SD_BALANCE_NEWIDLE \ + | SD_BALANCE_EXEC \ + | SD_WAKE_AFFINE \ + | SD_SHARE_PKG_RESOURCES\ + | BALANCE_FOR_MC_POWER, \ + .last_balance = jiffies, \ + .balance_interval = 1, \ + .nr_balance_failed = 0, \ +} +#endif +#endif /* CONFIG_SCHED_MC */ + /* Common values for CPUs */ #ifndef SD_CPU_INIT #define SD_CPU_INIT (struct sched_domain) { \ @@ -137,7 +169,7 @@ | SD_BALANCE_NEWIDLE \ | SD_BALANCE_EXEC \ | SD_WAKE_AFFINE \ - | BALANCE_FOR_POWER, \ + | BALANCE_FOR_PKG_POWER,\ .last_balance = jiffies, \ .balance_interval = 1, \ .nr_balance_failed = 0, \ @@ -168,15 +200,6 @@ .nr_balance_failed = 0, \ } -#ifdef CONFIG_SCHED_MC -#ifndef SD_MC_INIT -/* for now its same as SD_CPU_INIT. - * TBD: Tune Domain parameters! - */ -#define SD_MC_INIT SD_CPU_INIT -#endif -#endif - #ifdef CONFIG_NUMA #ifndef SD_NODE_INIT #error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!! diff --git a/kernel/sched.c b/kernel/sched.c index 0feeacb91497..0a5e814cc618 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2541,8 +2541,14 @@ static int load_balance(int this_cpu, struct rq *this_rq, struct rq *busiest; cpumask_t cpus = CPU_MASK_ALL; + /* + * When power savings policy is enabled for the parent domain, idle + * sibling can pick up load irrespective of busy siblings. In this case, + * let the state of idle sibling percolate up as IDLE, instead of + * portraying it as NOT_IDLE. + */ if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER && - !sched_smt_power_savings) + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) sd_idle = 1; schedstat_inc(sd, lb_cnt[idle]); @@ -2638,7 +2644,7 @@ redo: } if (!nr_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER && - !sched_smt_power_savings) + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) return -1; return nr_moved; @@ -2654,7 +2660,7 @@ out_one_pinned: sd->balance_interval *= 2; if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && - !sched_smt_power_savings) + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) return -1; return 0; } @@ -2676,7 +2682,14 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd) int sd_idle = 0; cpumask_t cpus = CPU_MASK_ALL; - if (sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings) + /* + * When power savings policy is enabled for the parent domain, idle + * sibling can pick up load irrespective of busy siblings. In this case, + * let the state of idle sibling percolate up as IDLE, instead of + * portraying it as NOT_IDLE. + */ + if (sd->flags & SD_SHARE_CPUPOWER && + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) sd_idle = 1; schedstat_inc(sd, lb_cnt[NEWLY_IDLE]); @@ -2717,7 +2730,8 @@ redo: if (!nr_moved) { schedstat_inc(sd, lb_failed[NEWLY_IDLE]); - if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER) + if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) return -1; } else sd->nr_balance_failed = 0; @@ -2727,7 +2741,7 @@ redo: out_balanced: schedstat_inc(sd, lb_balanced[NEWLY_IDLE]); if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && - !sched_smt_power_savings) + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) return -1; sd->nr_balance_failed = 0; @@ -5400,7 +5414,9 @@ static int sd_degenerate(struct sched_domain *sd) if (sd->flags & (SD_LOAD_BALANCE | SD_BALANCE_NEWIDLE | SD_BALANCE_FORK | - SD_BALANCE_EXEC)) { + SD_BALANCE_EXEC | + SD_SHARE_CPUPOWER | + SD_SHARE_PKG_RESOURCES)) { if (sd->groups != sd->groups->next) return 0; } @@ -5434,7 +5450,9 @@ sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent) pflags &= ~(SD_LOAD_BALANCE | SD_BALANCE_NEWIDLE | SD_BALANCE_FORK | - SD_BALANCE_EXEC); + SD_BALANCE_EXEC | + SD_SHARE_CPUPOWER | + SD_SHARE_PKG_RESOURCES); } if (~cflags & pflags) return 0; @@ -6240,6 +6258,58 @@ static void free_sched_groups(const cpumask_t *cpu_map) } #endif +/* + * Initialize sched groups cpu_power. + * + * cpu_power indicates the capacity of sched group, which is used while + * distributing the load between different sched groups in a sched domain. + * Typically cpu_power for all the groups in a sched domain will be same unless + * there are asymmetries in the topology. If there are asymmetries, group + * having more cpu_power will pickup more load compared to the group having + * less cpu_power. + * + * cpu_power will be a multiple of SCHED_LOAD_SCALE. This multiple represents + * the maximum number of tasks a group can handle in the presence of other idle + * or lightly loaded groups in the same sched domain. + */ +static void init_sched_groups_power(int cpu, struct sched_domain *sd) +{ + struct sched_domain *child; + struct sched_group *group; + + WARN_ON(!sd || !sd->groups); + + if (cpu != first_cpu(sd->groups->cpumask)) + return; + + child = sd->child; + + /* + * For perf policy, if the groups in child domain share resources + * (for example cores sharing some portions of the cache hierarchy + * or SMT), then set this domain groups cpu_power such that each group + * can handle only one task, when there are other idle groups in the + * same sched domain. + */ + if (!child || (!(sd->flags & SD_POWERSAVINGS_BALANCE) && + (child->flags & + (SD_SHARE_CPUPOWER | SD_SHARE_PKG_RESOURCES)))) { + sd->groups->cpu_power = SCHED_LOAD_SCALE; + return; + } + + sd->groups->cpu_power = 0; + + /* + * add cpu_power of each child group to this groups cpu_power + */ + group = child->groups; + do { + sd->groups->cpu_power += group->cpu_power; + group = group->next; + } while (group != child->groups); +} + /* * Build sched domains for a given set of cpus and attach the sched domains * to the individual cpus @@ -6247,6 +6317,7 @@ static void free_sched_groups(const cpumask_t *cpu_map) static int build_sched_domains(const cpumask_t *cpu_map) { int i; + struct sched_domain *sd; #ifdef CONFIG_NUMA struct sched_group **sched_group_nodes = NULL; struct sched_group *sched_group_allnodes = NULL; @@ -6456,72 +6527,20 @@ static int build_sched_domains(const cpumask_t *cpu_map) /* Calculate CPU power for physical packages and nodes */ #ifdef CONFIG_SCHED_SMT for_each_cpu_mask(i, *cpu_map) { - struct sched_domain *sd; sd = &per_cpu(cpu_domains, i); - sd->groups->cpu_power = SCHED_LOAD_SCALE; + init_sched_groups_power(i, sd); } #endif #ifdef CONFIG_SCHED_MC for_each_cpu_mask(i, *cpu_map) { - int power; - struct sched_domain *sd; sd = &per_cpu(core_domains, i); - if (sched_smt_power_savings) - power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask); - else - power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1) - * SCHED_LOAD_SCALE / 10; - sd->groups->cpu_power = power; + init_sched_groups_power(i, sd); } #endif for_each_cpu_mask(i, *cpu_map) { - struct sched_domain *sd; -#ifdef CONFIG_SCHED_MC - sd = &per_cpu(phys_domains, i); - if (i != first_cpu(sd->groups->cpumask)) - continue; - - sd->groups->cpu_power = 0; - if (sched_mc_power_savings || sched_smt_power_savings) { - int j; - - for_each_cpu_mask(j, sd->groups->cpumask) { - struct sched_domain *sd1; - sd1 = &per_cpu(core_domains, j); - /* - * for each core we will add once - * to the group in physical domain - */ - if (j != first_cpu(sd1->groups->cpumask)) - continue; - - if (sched_smt_power_savings) - sd->groups->cpu_power += sd1->groups->cpu_power; - else - sd->groups->cpu_power += SCHED_LOAD_SCALE; - } - } else - /* - * This has to be < 2 * SCHED_LOAD_SCALE - * Lets keep it SCHED_LOAD_SCALE, so that - * while calculating NUMA group's cpu_power - * we can simply do - * numa_group->cpu_power += phys_group->cpu_power; - * - * See "only add power once for each physical pkg" - * comment below - */ - sd->groups->cpu_power = SCHED_LOAD_SCALE; -#else - int power; sd = &per_cpu(phys_domains, i); - if (sched_smt_power_savings) - power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask); - else - power = SCHED_LOAD_SCALE; - sd->groups->cpu_power = power; -#endif + init_sched_groups_power(i, sd); } #ifdef CONFIG_NUMA -- cgit v1.2.3 From 020e322de3ff75d32daa58e431aad07071da27c6 Mon Sep 17 00:00:00 2001 From: Sergei Shtylylov Date: Tue, 3 Oct 2006 01:14:13 -0700 Subject: [PATCH] IDE: claim extra DMA ports regardless of channel - Claim extra DMA I/O ports regardless of what IDE channels are present/enabled. - Remove extra ports handling from ide_mapped_mmio_dma() since it's not applicable to the custom-mapping IDE drivers. Signed-off-by: Sergei Shtylyov Cc: Bartlomiej Zolnierkiewicz Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/ide-dma.c | 32 ++++++++++++++++++++++---------- drivers/ide/ide.c | 14 +++++++++----- include/linux/ide.h | 4 +++- 3 files changed, 34 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index c3546fe9af63..9937fa7da546 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -798,9 +798,9 @@ static int ide_release_dma_engine(ide_hwif_t *hwif) static int ide_release_iomio_dma(ide_hwif_t *hwif) { - if ((hwif->dma_extra) && (hwif->channel == 0)) - release_region((hwif->dma_base + 16), hwif->dma_extra); release_region(hwif->dma_base, 8); + if (hwif->extra_ports) + release_region(hwif->extra_base, hwif->extra_ports); if (hwif->dma_base2) release_region(hwif->dma_base, 8); return 1; @@ -840,9 +840,7 @@ static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned in { printk(KERN_INFO " %s: MMIO-DMA ", hwif->name); - hwif->dma_base = base; - if (hwif->cds->extra && hwif->channel == 0) - hwif->dma_extra = hwif->cds->extra; + hwif->dma_base = base; if(hwif->mate) hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base; @@ -854,17 +852,29 @@ static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned in static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports) { printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx", - hwif->name, base, base + ports - 1); + hwif->name, base, base + ports - 1); + if (!request_region(base, ports, hwif->name)) { printk(" -- Error, ports in use.\n"); return 1; } + hwif->dma_base = base; - if ((hwif->cds->extra) && (hwif->channel == 0)) { - request_region(base+16, hwif->cds->extra, hwif->cds->name); - hwif->dma_extra = hwif->cds->extra; + + if (hwif->cds->extra) { + hwif->extra_base = base + (hwif->channel ? 8 : 16); + + if (!hwif->mate || !hwif->mate->extra_ports) { + if (!request_region(hwif->extra_base, + hwif->cds->extra, hwif->cds->name)) { + printk(" -- Error, extra ports in use.\n"); + release_region(base, ports); + return 1; + } + hwif->extra_ports = hwif->cds->extra; + } } - + if(hwif->mate) hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base; else @@ -874,6 +884,8 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port { printk(" -- Error, secondary ports in use.\n"); release_region(base, ports); + if (hwif->extra_ports) + release_region(hwif->extra_base, hwif->extra_ports); return 1; } } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 2b1a1389c318..8c3f06242280 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -450,7 +450,7 @@ void ide_hwif_release_regions(ide_hwif_t *hwif) * @hwif: hwif to update * @tmp_hwif: template * - * Restore hwif to a previous state by copying most settngs + * Restore hwif to a previous state by copying most settings * from the template. */ @@ -539,9 +539,10 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->dma_vendor3 = tmp_hwif->dma_vendor3; hwif->dma_prdtable = tmp_hwif->dma_prdtable; - hwif->dma_extra = tmp_hwif->dma_extra; hwif->config_data = tmp_hwif->config_data; hwif->select_data = tmp_hwif->select_data; + hwif->extra_base = tmp_hwif->extra_base; + hwif->extra_ports = tmp_hwif->extra_ports; hwif->autodma = tmp_hwif->autodma; hwif->udma_four = tmp_hwif->udma_four; hwif->no_dsc = tmp_hwif->no_dsc; @@ -550,7 +551,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) } /** - * ide_unregister - free an ide interface + * ide_unregister - free an IDE interface * @index: index of interface (will change soon to a pointer) * * Perform the final unregister of an IDE interface. At the moment @@ -563,8 +564,8 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) * deadlocking the IDE layer. The shutdown callback is called * before we take the lock and free resources. It is up to the * caller to be sure there is no pending I/O here, and that - * the interfce will not be reopened (present/vanishing locking - * isnt yet done btw). After we commit to the final kill we + * the interface will not be reopened (present/vanishing locking + * isn't yet done BTW). After we commit to the final kill we * call the cleanup callback with the ide locks held. * * Unregister restores the hwif structures to the default state. @@ -674,6 +675,9 @@ void ide_unregister(unsigned int index) hwif->dma_status = 0; hwif->dma_vendor3 = 0; hwif->dma_prdtable = 0; + + hwif->extra_base = 0; + hwif->extra_ports = 0; } /* copy original settings */ diff --git a/include/linux/ide.h b/include/linux/ide.h index 99620451d958..11608cd03d4c 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -775,10 +775,12 @@ typedef struct hwif_s { unsigned long dma_prdtable; /* actual prd table address */ unsigned long dma_base2; /* extended base addr for dma ports */ - unsigned dma_extra; /* extra addr for dma ports */ unsigned long config_data; /* for use by chipset-specific code */ unsigned long select_data; /* for use by chipset-specific code */ + unsigned long extra_base; /* extra addr for dma ports */ + unsigned extra_ports; /* number of extra dma ports */ + unsigned noprobe : 1; /* don't probe for this interface */ unsigned present : 1; /* this interface exists */ unsigned hold : 1; /* this interface is always present */ -- cgit v1.2.3 From 83d7dbc4095a0c314b191c573be5fb4fa6ce0897 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Tue, 3 Oct 2006 01:14:16 -0700 Subject: [PATCH] Make number of IDE interfaces configurable Make IDE_HWIFS configurable if EMBEDDED This lets us lop as much as 16k off an x86 build. It's a little ugly, but it's dead simple. Note the fix for HWIFS < 2. Sizing interfaces dynamically unfortunately turns out to be pretty major surgery. add/remove: 0/1 grow/shrink: 0/11 up/down: 0/-16182 (-16182) function old new delta ide_hwifs 16920 1692 -15228 init_irq 1113 750 -363 ideprobe_init 283 138 -145 ide_pci_setup_ports 1329 1193 -136 save_match 85 - -85 ide_register_hw_with_fixup 367 287 -80 ide_setup 1364 1308 -56 is_chipset_set 40 4 -36 create_proc_ide_interfaces 225 205 -20 init_ide_data 84 67 -17 ide_probe_for_cmd640x 1198 1183 -15 ide_unregister 1452 1451 -1 Signed-off-by: Matt Mackall Cc: Bartlomiej Zolnierkiewicz Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/Kconfig | 2 +- drivers/ide/setup-pci.c | 2 +- include/linux/ide.h | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 0524f17175fd..abcabb295592 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -56,7 +56,7 @@ if IDE config IDE_MAX_HWIFS int "Max IDE interfaces" - depends on ALPHA || SUPERH || IA64 + depends on ALPHA || SUPERH || IA64 || EMBEDDED default 4 help This is the maximum number of IDE hardware interfaces that will diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index eb0945284acc..157fe93ea342 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -101,7 +101,7 @@ static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char return hwif; /* pick an unused entry */ } } - for (h = 0; h < 2; ++h) { + for (h = 0; h < 2 && h < MAX_HWIFS; ++h) { hwif = ide_hwifs + h; if (hwif->chipset == ide_unknown) return hwif; /* pick an unused entry */ diff --git a/include/linux/ide.h b/include/linux/ide.h index 11608cd03d4c..bdb2733208c5 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -251,7 +251,8 @@ static inline void ide_std_init_ports(hw_regs_t *hw, #include -#ifndef MAX_HWIFS +#if !defined(MAX_HWIFS) || defined(CONFIG_EMBEDDED) +#undef MAX_HWIFS #define MAX_HWIFS CONFIG_IDE_MAX_HWIFS #endif -- cgit v1.2.3 From 27ac6036f31dea8117ecc525e0dbfd17b23e8c09 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 3 Oct 2006 01:14:24 -0700 Subject: [PATCH] drivers/ide/: cleanups - setup-pci.c: remove the unused ide_pci_unregister_driver() - ide-dma.c: remove the unused EXPORT_SYMBOL_GPL(ide_in_drive_list) Signed-off-by: Adrian Bunk Acked-by: Alan Cox Cc: Bartlomiej Zolnierkiewicz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/ide-dma.c | 2 -- drivers/ide/setup-pci.c | 18 ------------------ include/linux/ide.h | 1 - 3 files changed, 21 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 53feaf82576e..9069766f236e 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -151,8 +151,6 @@ int ide_in_drive_list(struct hd_driveid *id, const struct drive_list_entry *driv return 0; } -EXPORT_SYMBOL_GPL(ide_in_drive_list); - /** * ide_dma_intr - IDE DMA interrupt handler * @drive: the drive the interrupt is for diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 157fe93ea342..0719b6484824 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -794,24 +794,6 @@ int __ide_pci_register_driver(struct pci_driver *driver, struct module *module) EXPORT_SYMBOL_GPL(__ide_pci_register_driver); -/** - * ide_unregister_pci_driver - unregister an IDE driver - * @driver: driver to remove - * - * Unregister a currently installed IDE driver. Returns are the same - * as for pci_unregister_driver - */ - -void ide_pci_unregister_driver(struct pci_driver *driver) -{ - if(!pre_init) - pci_unregister_driver(driver); - else - list_del(&driver->node); -} - -EXPORT_SYMBOL_GPL(ide_pci_unregister_driver); - /** * ide_scan_pcidev - find an IDE driver for a device * @dev: PCI device to check diff --git a/include/linux/ide.h b/include/linux/ide.h index bdb2733208c5..097d16e5ab37 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1193,7 +1193,6 @@ extern int ideprobe_init(void); extern void ide_scan_pcibus(int scan_direction) __init; extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner); #define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE) -extern void ide_pci_unregister_driver(struct pci_driver *driver); void ide_pci_setup_ports(struct pci_dev *, struct ide_pci_device_s *, int, ata_index_t *); extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d); -- cgit v1.2.3 From 3f63c5e88a5ce45b423f3712293f1664115b09c0 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 3 Oct 2006 01:14:25 -0700 Subject: [PATCH] ide: remove dma_base2 field from ide_hwif_t Remove dma_base2 field from ide_hwif_t as it's used only in 2 drivers and without great need. Signed-off-by: Sergei Shtylyov Cc: John Keller Signed-off-by: Jeremy Higdon Acked-by: Alan Cox Cc: Bartlomiej Zolnierkiewicz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/ide-dma.c | 14 +------------- drivers/ide/pci/sgiioc4.c | 20 +++++++++----------- drivers/ide/pci/siimage.c | 1 - include/linux/ide.h | 1 - 4 files changed, 10 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 9069766f236e..56efed6742d4 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -799,8 +799,6 @@ static int ide_release_iomio_dma(ide_hwif_t *hwif) release_region(hwif->dma_base, 8); if (hwif->extra_ports) release_region(hwif->extra_base, hwif->extra_ports); - if (hwif->dma_base2) - release_region(hwif->dma_base, 8); return 1; } @@ -872,19 +870,9 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port } if(hwif->mate) - hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base; + hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base:base; else hwif->dma_master = base; - if (hwif->dma_base2) { - if (!request_region(hwif->dma_base2, ports, hwif->name)) - { - printk(" -- Error, secondary ports in use.\n"); - release_region(base, ports); - if (hwif->extra_ports) - release_region(hwif->extra_base, hwif->extra_ports); - return 1; - } - } return 0; } diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index d8a0d87df734..f3fe287fbd89 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -220,7 +220,7 @@ sgiioc4_ide_dma_end(ide_drive_t * drive) ide_hwif_t *hwif = HWIF(drive); u64 dma_base = hwif->dma_base; int dma_stat = 0; - unsigned long *ending_dma = (unsigned long *) hwif->dma_base2; + unsigned long *ending_dma = ide_get_hwifdata(hwif); hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4); @@ -369,6 +369,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) { void __iomem *virt_dma_base; int num_ports = sizeof (ioc4_dma_regs_t); + void *pad; printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name, dma_base, dma_base + num_ports - 1); @@ -400,17 +401,14 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) hwif->sg_max_nents = IOC4_PRD_ENTRIES; - hwif->dma_base2 = (unsigned long) - pci_alloc_consistent(hwif->pci_dev, - IOC4_IDE_CACHELINE_SIZE, - (dma_addr_t *) &(hwif->dma_status)); + pad = pci_alloc_consistent(hwif->pci_dev, IOC4_IDE_CACHELINE_SIZE, + (dma_addr_t *) &(hwif->dma_status)); - if (!hwif->dma_base2) - goto dma_base2alloc_failure; - - return; + if (pad) { + ide_set_hwifdata(hwif, pad); + return; + } -dma_base2alloc_failure: pci_free_consistent(hwif->pci_dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES, hwif->dmatable_cpu, hwif->dmatable_dma); @@ -476,7 +474,7 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) hwif->OUTL(dma_addr, dma_base + IOC4_DMA_PTR_L * 4); /* Address of the Ending DMA */ - memset((unsigned int *) hwif->dma_base2, 0, IOC4_IDE_CACHELINE_SIZE); + memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE); ending_dma_addr = cpu_to_le32(hwif->dma_status); hwif->OUTL(ending_dma_addr, dma_base + IOC4_DMA_END_ADDR * 4); diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 20b392948f36..697f566fb90a 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -898,7 +898,6 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) base = (unsigned long) addr; hwif->dma_base = base + (ch ? 0x08 : 0x00); - hwif->dma_base2 = base + (ch ? 0x18 : 0x10); hwif->mmio = 2; } diff --git a/include/linux/ide.h b/include/linux/ide.h index 097d16e5ab37..a9a9e33e448f 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -774,7 +774,6 @@ typedef struct hwif_s { unsigned long dma_status; /* dma status register */ unsigned long dma_vendor3; /* dma vendor 3 register */ unsigned long dma_prdtable; /* actual prd table address */ - unsigned long dma_base2; /* extended base addr for dma ports */ unsigned long config_data; /* for use by chipset-specific code */ unsigned long select_data; /* for use by chipset-specific code */ -- cgit v1.2.3 From 913759ac90a727b86da72efcfb70931f497d1cb7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 3 Oct 2006 01:14:33 -0700 Subject: [PATCH] ide: Fix crash on repeated reset Michal Miroslaw reported a problem (bugzilla #7023) where a user initiated reset while the IDE layer was already resetting the channel caused a crash, and provided a rough fix. This is a slightly cleaner version of the fix which tracks the reset state and blocks further reset requests while a reset is in progress. Note this is not a security issue - random end users can't access the ioctl in question anyway. Signed-off-by: Alan Cox Cc: Michal Miroslaw Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/ide-iops.c | 4 ++++ drivers/ide/ide.c | 5 +++++ include/linux/ide.h | 3 +++ 3 files changed, 12 insertions(+) (limited to 'include/linux') diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 77703acaec17..badde6331775 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -998,6 +998,7 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive) } /* done polling */ hwgroup->polling = 0; + hwgroup->resetting = 0; return ide_stopped; } @@ -1057,6 +1058,7 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive) } } hwgroup->polling = 0; /* done polling */ + hwgroup->resetting = 0; /* done reset attempt */ return ide_stopped; } @@ -1143,6 +1145,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) /* For an ATAPI device, first try an ATAPI SRST. */ if (drive->media != ide_disk && !do_not_try_atapi) { + hwgroup->resetting = 1; pre_reset(drive); SELECT_DRIVE(drive); udelay (20); @@ -1168,6 +1171,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) return ide_stopped; } + hwgroup->resetting = 1; /* * Note that we also set nIEN while resetting the device, * to mask unwanted interrupts from the interface during the reset. diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 97b162ca9885..287a66201150 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1364,6 +1364,11 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device spin_lock_irqsave(&ide_lock, flags); + if (HWGROUP(drive)->resetting) { + spin_unlock_irqrestore(&ide_lock, flags); + return -EBUSY; + } + ide_abort(drive, "drive reset"); BUG_ON(HWGROUP(drive)->handler); diff --git a/include/linux/ide.h b/include/linux/ide.h index a9a9e33e448f..07d8d725541f 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -825,6 +825,9 @@ typedef struct hwgroup_s { unsigned int sleeping : 1; /* BOOL: polling active & poll_timeout field valid */ unsigned int polling : 1; + /* BOOL: in a polling reset situation. Must not trigger another reset yet */ + unsigned int resetting : 1; + /* current drive */ ide_drive_t *drive; /* ptr to current hwif in linked-list */ -- cgit v1.2.3 From fc5891c8a3ba284f13994d7bc1f1bfa8283982de Mon Sep 17 00:00:00 2001 From: Dennis Munsie Date: Tue, 3 Oct 2006 01:14:42 -0700 Subject: [PATCH] fbdev: Add generic ddc read functionality Adds functionality to read the EDID information over the DDC bus in a generic way. This code is based on the DDC implementation in the radeon driver. [adaplas] - separate from fbmon.c and place in new file fb_ddc.c - remove dependency to CONFIG_I2C and CONFIG_I2C_ALGOBIT, otherwise, feature will not compile if i2c support is compiled as a module - feature is selectable only by drivers needing it. It must have a 'select FB_DDC if xxx' in Kconfig - change printk's to dev_*, the i2c people prefers it Signed-off-by: Dennis Munsie Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/Kconfig | 5 +++ drivers/video/Makefile | 1 + drivers/video/fb_ddc.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fb.h | 2 + 4 files changed, 124 insertions(+) create mode 100644 drivers/video/fb_ddc.c (limited to 'include/linux') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 652d202adf75..d498e908f4b7 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -53,6 +53,11 @@ config FB (e.g. an accelerated X server) and that are not frame buffer device-aware may cause unexpected results. If unsure, say N. +config FB_DDC + tristate + depends on FB && I2C && I2C_ALGOBIT + default n + config FB_CFB_FILLRECT tristate depends on FB diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 481c6c9695f8..a6980e9a2481 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o obj-$(CONFIG_FB_MACMODES) += macmodes.o +obj-$(CONFIG_FB_DDC) += fb_ddc.o # Hardware specific drivers go first obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o diff --git a/drivers/video/fb_ddc.c b/drivers/video/fb_ddc.c new file mode 100644 index 000000000000..3aa6ebf68f17 --- /dev/null +++ b/drivers/video/fb_ddc.c @@ -0,0 +1,116 @@ +/* + * driver/vide/fb_ddc.c - DDC/EDID read support. + * + * Copyright (C) 2006 Dennis Munsie + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include + +#include "edid.h" + +#define DDC_ADDR 0x50 + +static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter) +{ + unsigned char start = 0x0; + struct i2c_msg msgs[] = { + { + .addr = DDC_ADDR, + .len = 1, + .buf = &start, + }, { + .addr = DDC_ADDR, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + } + }; + unsigned char *buf; + + buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!buf) { + dev_warn(&adapter->dev, "unable to allocate memory for EDID " + "block.\n"); + return NULL; + } + msgs[1].buf = buf; + + if (i2c_transfer(adapter, msgs, 2) == 2) + return buf; + + dev_warn(&adapter->dev, "unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + +unsigned char *fb_ddc_read(struct i2c_adapter *adapter) +{ + struct i2c_algo_bit_data *algo_data = adapter->algo_data; + unsigned char *edid = NULL; + int i, j; + + algo_data->setscl(algo_data->data, 1); + algo_data->setscl(algo_data->data, 0); + + for (i = 0; i < 3; i++) { + /* For some old monitors we need the + * following process to initialize/stop DDC + */ + algo_data->setsda(algo_data->data, 0); + msleep(13); + + algo_data->setscl(algo_data->data, 1); + for (j = 0; j < 5; j++) { + msleep(10); + if (algo_data->getscl(algo_data->data)) + break; + } + if (j == 5) + continue; + + algo_data->setsda(algo_data->data, 0); + msleep(15); + algo_data->setscl(algo_data->data, 0); + msleep(15); + algo_data->setsda(algo_data->data, 1); + msleep(15); + + /* Do the real work */ + edid = fb_do_probe_ddc_edid(adapter); + algo_data->setsda(algo_data->data, 0); + algo_data->setscl(algo_data->data, 0); + msleep(15); + + algo_data->setscl(algo_data->data, 1); + for (j = 0; j < 10; j++) { + msleep(10); + if (algo_data->getscl(algo_data->data)) + break; + } + + algo_data->setsda(algo_data->data, 1); + msleep(15); + algo_data->setscl(algo_data->data, 0); + if (edid) + break; + } + /* Release the DDC lines when done or the Apple Cinema HD display + * will switch off + */ + algo_data->setsda(algo_data->data, 0); + algo_data->setscl(algo_data->data, 0); + + return edid; +} + +EXPORT_SYMBOL_GPL(fb_ddc_read); + +MODULE_AUTHOR("Dennis Munsie "); +MODULE_DESCRIPTION("DDC/EDID reading support"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/fb.h b/include/linux/fb.h index 2f335e966011..37aab314f0c4 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -2,6 +2,7 @@ #define _LINUX_FB_H #include +#include /* Definitions of frame buffers */ @@ -940,6 +941,7 @@ extern void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs); extern void fb_destroy_modedb(struct fb_videomode *modedb); extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb); +extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter); /* drivers/video/modedb.c */ #define VESA_MODEDB_SIZE 34 -- cgit v1.2.3 From 1a6600be3e5dafe2ddcc5d969d931c2591eed896 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" Date: Tue, 3 Oct 2006 01:14:50 -0700 Subject: [PATCH] fbdev: Honor the return value of device_create_file Check the return value of device_create_file(). If return is 'fail', remove attributes by calling device_remove_file(). Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/fbsysfs.c | 35 ++++++++++++++++++++++++++++------- include/linux/fb.h | 1 + 2 files changed, 29 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index c151dcf68786..d3a50417ed9a 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -20,6 +20,8 @@ #include #include +#define FB_SYSFS_FLAG_ATTR 1 + /** * framebuffer_alloc - creates a new frame buffer info structure * @@ -483,12 +485,27 @@ static struct class_device_attribute class_device_attrs[] = { int fb_init_class_device(struct fb_info *fb_info) { - unsigned int i; + int i, error = 0; + class_set_devdata(fb_info->class_device, fb_info); - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) - class_device_create_file(fb_info->class_device, - &class_device_attrs[i]); + fb_info->class_flag |= FB_SYSFS_FLAG_ATTR; + + for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { + error = class_device_create_file(fb_info->class_device, + &class_device_attrs[i]); + + if (error) + break; + } + + if (error) { + while (--i >= 0) + class_device_remove_file(fb_info->class_device, + &class_device_attrs[i]); + fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR; + } + return 0; } @@ -496,9 +513,13 @@ void fb_cleanup_class_device(struct fb_info *fb_info) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) - class_device_remove_file(fb_info->class_device, - &class_device_attrs[i]); + if (fb_info->class_flag & FB_SYSFS_FLAG_ATTR) { + for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) + class_device_remove_file(fb_info->class_device, + &class_device_attrs[i]); + + fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR; + } } #ifdef CONFIG_FB_BACKLIGHT diff --git a/include/linux/fb.h b/include/linux/fb.h index 37aab314f0c4..3e69241e6a81 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -776,6 +776,7 @@ struct fb_info { struct fb_ops *fbops; struct device *device; struct class_device *class_device; /* sysfs per device attrs */ + int class_flag; /* private sysfs flags */ #ifdef CONFIG_FB_TILEBLITTING struct fb_tile_ops *tileops; /* Tile Blitting */ #endif -- cgit v1.2.3 From 3cb340ecbb010013229ac56f26707252ebed09b8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 3 Oct 2006 01:15:06 -0700 Subject: [PATCH] vt: proper prototypes for some console functions This patch adds proper prototypes to header files for three console init functions used on drivers/char/vt.c Signed-off-by: Adrian Bunk Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/vt.c | 8 -------- include/linux/console.h | 3 +++ include/linux/consolemap.h | 1 + 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index a398b6b6aa65..8e4413f6fbaf 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -139,14 +139,6 @@ const struct consw *conswitchp; extern void vcs_make_sysfs(struct tty_struct *tty); extern void vcs_remove_sysfs(struct tty_struct *tty); -extern void console_map_init(void); -#ifdef CONFIG_PROM_CONSOLE -extern void prom_con_init(void); -#endif -#ifdef CONFIG_MDA_CONSOLE -extern int mda_console_init(void); -#endif - struct vc vc_cons [MAX_NR_CONSOLES]; #ifndef VT_SINGLE_DRIVER diff --git a/include/linux/console.h b/include/linux/console.h index 76a1807726eb..7d0420274de0 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -129,6 +129,9 @@ static inline void suspend_console(void) {} static inline void resume_console(void) {} #endif /* CONFIG_DISABLE_CONSOLE_SUSPEND */ +int mda_console_init(void); +void prom_con_init(void); + /* Some debug stub to catch some of the obvious races in the VT code */ #if 1 #define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && !oops_in_progress) diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h index 65842efc1b70..82c9a1f11020 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -13,3 +13,4 @@ struct vc_data; extern unsigned char inverse_translate(struct vc_data *conp, int glyph); extern unsigned short *set_translate(int m, struct vc_data *vc); extern int conv_uni_to_pc(struct vc_data *conp, long ucs); +void console_map_init(void); -- cgit v1.2.3 From aa129a2247b164173d45da8ad43cca5de9211403 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Tue, 3 Oct 2006 01:15:15 -0700 Subject: [PATCH] dm: support ioctls on mapped devices Extend the core device-mapper infrastructure to accept arbitrary ioctls on a mapped device provided that it has exactly one target and it is capable of supporting ioctls. [We can't use unlocked_ioctl because we need 'inode': 'file' might be NULL. Is it worth changing this?] Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon Arnd Bergmann wrote: > Am Wednesday 21 June 2006 21:31 schrieb Alasdair G Kergon: > > static struct block_device_operations dm_blk_dops = { > > .open = dm_blk_open, > > .release = dm_blk_close, > > +.ioctl = dm_blk_ioctl, > > .getgeo = dm_blk_getgeo, > > .owner = THIS_MODULE > > I guess this also needs a ->compat_ioctl method, otherwise it won't > work for ioctl numbers that have a compat_ioctl implementation in the > low-level device driver. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/linux/device-mapper.h | 5 +++++ include/linux/dm-ioctl.h | 2 +- 3 files changed, 47 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index c99bf9f01759..5792686936c1 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -20,6 +20,7 @@ #include #include #include +#include #define DM_MSG_PREFIX "core" @@ -288,6 +289,45 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) return dm_get_geometry(md, geo); } +static int dm_blk_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mapped_device *md; + struct dm_table *map; + struct dm_target *tgt; + int r = -ENOTTY; + + /* We don't really need this lock, but we do need 'inode'. */ + unlock_kernel(); + + md = inode->i_bdev->bd_disk->private_data; + + map = dm_get_table(md); + + if (!map || !dm_table_get_size(map)) + goto out; + + /* We only support devices that have a single target */ + if (dm_table_get_num_targets(map) != 1) + goto out; + + tgt = dm_table_get_target(map, 0); + + if (dm_suspended(md)) { + r = -EAGAIN; + goto out; + } + + if (tgt->type->ioctl) + r = tgt->type->ioctl(tgt, inode, file, cmd, arg); + +out: + dm_table_put(map); + + lock_kernel(); + return r; +} + static inline struct dm_io *alloc_io(struct mapped_device *md) { return mempool_alloc(md->io_pool, GFP_NOIO); @@ -1377,6 +1417,7 @@ int dm_suspended(struct mapped_device *md) static struct block_device_operations dm_blk_dops = { .open = dm_blk_open, .release = dm_blk_close, + .ioctl = dm_blk_ioctl, .getgeo = dm_blk_getgeo, .owner = THIS_MODULE }; diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index e3d1c33d1558..d44a99650af3 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -64,6 +64,10 @@ typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type, typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv); +typedef int (*dm_ioctl_fn) (struct dm_target *ti, struct inode *inode, + struct file *filp, unsigned int cmd, + unsigned long arg); + void dm_error(const char *message); /* @@ -91,6 +95,7 @@ struct target_type { dm_resume_fn resume; dm_status_fn status; dm_message_fn message; + dm_ioctl_fn ioctl; }; struct io_restrictions { diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index 9623bb625090..b349b768df35 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h @@ -285,7 +285,7 @@ typedef char ioctl_struct[308]; #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 7 +#define DM_VERSION_MINOR 8 #define DM_VERSION_PATCHLEVEL 0 #define DM_VERSION_EXTRA "-ioctl (2006-06-24)" -- cgit v1.2.3 From 7006f6eca874cd44d37ccb8cfeb8bed04e3bff22 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 3 Oct 2006 01:15:21 -0700 Subject: [PATCH] dm: export blkdev_driver_ioctl Export blkdev_driver_ioctl for device-mapper. If we get as far as the device-mapper ioctl handler, we know the ioctl is not a standard block layer BLK* one, so we don't need to check for them a second time and can call blkdev_driver_ioctl() directly. Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- block/ioctl.c | 5 +++-- drivers/md/dm-linear.c | 2 +- drivers/md/dm-mpath.c | 3 ++- include/linux/fs.h | 3 +++ 4 files changed, 9 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/block/ioctl.c b/block/ioctl.c index 309760b7e37f..58aab630dfc1 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -199,8 +199,8 @@ static int blkdev_locked_ioctl(struct file *file, struct block_device *bdev, return -ENOIOCTLCMD; } -static int blkdev_driver_ioctl(struct inode *inode, struct file *file, - struct gendisk *disk, unsigned cmd, unsigned long arg) +int blkdev_driver_ioctl(struct inode *inode, struct file *file, + struct gendisk *disk, unsigned cmd, unsigned long arg) { int ret; if (disk->fops->unlocked_ioctl) @@ -215,6 +215,7 @@ static int blkdev_driver_ioctl(struct inode *inode, struct file *file, return -ENOTTY; } +EXPORT_SYMBOL_GPL(blkdev_driver_ioctl); int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg) diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index c58f072ccae6..2a6bad451f86 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -105,7 +105,7 @@ static int linear_ioctl(struct dm_target *ti, struct inode *inode, struct linear_c *lc = (struct linear_c *) ti->private; struct block_device *bdev = lc->dev->bdev; - return blkdev_ioctl(bdev->bd_inode, filp, cmd, arg); + return blkdev_driver_ioctl(bdev->bd_inode, filp, bdev->bd_disk, cmd, arg); } static struct target_type linear_target = { diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 14cfdb538efd..dcfbf830964c 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1290,7 +1290,8 @@ static int multipath_ioctl(struct dm_target *ti, struct inode *inode, spin_unlock_irqrestore(&m->lock, flags); - return r ? : blkdev_ioctl(bdev->bd_inode, filp, cmd, arg); + return r ? : blkdev_driver_ioctl(bdev->bd_inode, filp, bdev->bd_disk, + cmd, arg); } /*----------------------------------------------------------------- diff --git a/include/linux/fs.h b/include/linux/fs.h index 7b61e94bf8fc..f53bf4ff1955 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1523,6 +1523,9 @@ extern const struct file_operations def_fifo_fops; #ifdef CONFIG_BLOCK extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long); +extern int blkdev_driver_ioctl(struct inode *inode, struct file *file, + struct gendisk *disk, unsigned cmd, + unsigned long arg); extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long); extern int blkdev_get(struct block_device *, mode_t, unsigned); extern int blkdev_put(struct block_device *); -- cgit v1.2.3 From 8757b7764f13e336f3c0eb1f634440d4ee4c3a67 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Tue, 3 Oct 2006 01:15:36 -0700 Subject: [PATCH] dm table: add target preresume This patch adds a target preresume hook. It is called before the targets are resumed and if it returns an error the resume gets cancelled. The crypt target will use this to indicate that it is unable to process I/O because no encryption key has been supplied. Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-table.c | 17 +++++++++++++++-- drivers/md/dm.c | 4 +++- drivers/md/dm.h | 2 +- include/linux/device-mapper.h | 2 ++ include/linux/dm-ioctl.h | 4 ++-- 5 files changed, 23 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 75fe9493e6af..47412ae98fb9 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -939,9 +939,20 @@ void dm_table_postsuspend_targets(struct dm_table *t) return suspend_targets(t, 1); } -void dm_table_resume_targets(struct dm_table *t) +int dm_table_resume_targets(struct dm_table *t) { - int i; + int i, r = 0; + + for (i = 0; i < t->num_targets; i++) { + struct dm_target *ti = t->targets + i; + + if (!ti->type->preresume) + continue; + + r = ti->type->preresume(ti); + if (r) + return r; + } for (i = 0; i < t->num_targets; i++) { struct dm_target *ti = t->targets + i; @@ -949,6 +960,8 @@ void dm_table_resume_targets(struct dm_table *t) if (ti->type->resume) ti->type->resume(ti); } + + return 0; } int dm_table_any_congested(struct dm_table *t, int bdi_bits) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 883860c3565b..aeb63a3ac330 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1360,7 +1360,9 @@ int dm_resume(struct mapped_device *md) if (!map || !dm_table_get_size(map)) goto out; - dm_table_resume_targets(map); + r = dm_table_resume_targets(map); + if (r) + goto out; down_write(&md->io_lock); clear_bit(DMF_BLOCK_IO, &md->flags); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index fe701c4834fe..a48ec5e3c1f4 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -57,7 +57,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q); struct list_head *dm_table_get_devices(struct dm_table *t); void dm_table_presuspend_targets(struct dm_table *t); void dm_table_postsuspend_targets(struct dm_table *t); -void dm_table_resume_targets(struct dm_table *t); +int dm_table_resume_targets(struct dm_table *t); int dm_table_any_congested(struct dm_table *t, int bdi_bits); void dm_table_unplug_all(struct dm_table *t); int dm_table_flush_all(struct dm_table *t); diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index d44a99650af3..8cbc46b8e3db 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -57,6 +57,7 @@ typedef int (*dm_endio_fn) (struct dm_target *ti, typedef void (*dm_presuspend_fn) (struct dm_target *ti); typedef void (*dm_postsuspend_fn) (struct dm_target *ti); +typedef int (*dm_preresume_fn) (struct dm_target *ti); typedef void (*dm_resume_fn) (struct dm_target *ti); typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type, @@ -92,6 +93,7 @@ struct target_type { dm_endio_fn end_io; dm_presuspend_fn presuspend; dm_postsuspend_fn postsuspend; + dm_preresume_fn preresume; dm_resume_fn resume; dm_status_fn status; dm_message_fn message; diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index b349b768df35..f28b5c87aa6b 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h @@ -285,9 +285,9 @@ typedef char ioctl_struct[308]; #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 8 +#define DM_VERSION_MINOR 9 #define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2006-06-24)" +#define DM_VERSION_EXTRA "-ioctl (2006-09-14)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ -- cgit v1.2.3 From 3cb4021453a69585e458ec2177677c0c1300dccf Mon Sep 17 00:00:00 2001 From: Bryn Reeves Date: Tue, 3 Oct 2006 01:15:42 -0700 Subject: [PATCH] dm: extract device limit setting Separate the setting of device I/O limits from dm_get_device(). dm-loop will use this. Signed-off-by: Bryn Reeves Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-table.c | 87 +++++++++++++++++++++++-------------------- include/linux/device-mapper.h | 5 +++ 2 files changed, 51 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 47412ae98fb9..4920998efeeb 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -522,56 +522,61 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti, return 0; } - -int dm_get_device(struct dm_target *ti, const char *path, sector_t start, - sector_t len, int mode, struct dm_dev **result) +void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev) { - int r = __table_get_device(ti->table, ti, path, - start, len, mode, result); - if (!r) { - request_queue_t *q = bdev_get_queue((*result)->bdev); - struct io_restrictions *rs = &ti->limits; - - /* - * Combine the device limits low. - * - * FIXME: if we move an io_restriction struct - * into q this would just be a call to - * combine_restrictions_low() - */ + request_queue_t *q = bdev_get_queue(bdev); + struct io_restrictions *rs = &ti->limits; + + /* + * Combine the device limits low. + * + * FIXME: if we move an io_restriction struct + * into q this would just be a call to + * combine_restrictions_low() + */ + rs->max_sectors = + min_not_zero(rs->max_sectors, q->max_sectors); + + /* FIXME: Device-Mapper on top of RAID-0 breaks because DM + * currently doesn't honor MD's merge_bvec_fn routine. + * In this case, we'll force DM to use PAGE_SIZE or + * smaller I/O, just to be safe. A better fix is in the + * works, but add this for the time being so it will at + * least operate correctly. + */ + if (q->merge_bvec_fn) rs->max_sectors = - min_not_zero(rs->max_sectors, q->max_sectors); + min_not_zero(rs->max_sectors, + (unsigned int) (PAGE_SIZE >> 9)); - /* FIXME: Device-Mapper on top of RAID-0 breaks because DM - * currently doesn't honor MD's merge_bvec_fn routine. - * In this case, we'll force DM to use PAGE_SIZE or - * smaller I/O, just to be safe. A better fix is in the - * works, but add this for the time being so it will at - * least operate correctly. - */ - if (q->merge_bvec_fn) - rs->max_sectors = - min_not_zero(rs->max_sectors, - (unsigned int) (PAGE_SIZE >> 9)); + rs->max_phys_segments = + min_not_zero(rs->max_phys_segments, + q->max_phys_segments); - rs->max_phys_segments = - min_not_zero(rs->max_phys_segments, - q->max_phys_segments); + rs->max_hw_segments = + min_not_zero(rs->max_hw_segments, q->max_hw_segments); - rs->max_hw_segments = - min_not_zero(rs->max_hw_segments, q->max_hw_segments); + rs->hardsect_size = max(rs->hardsect_size, q->hardsect_size); - rs->hardsect_size = max(rs->hardsect_size, q->hardsect_size); + rs->max_segment_size = + min_not_zero(rs->max_segment_size, q->max_segment_size); - rs->max_segment_size = - min_not_zero(rs->max_segment_size, q->max_segment_size); + rs->seg_boundary_mask = + min_not_zero(rs->seg_boundary_mask, + q->seg_boundary_mask); - rs->seg_boundary_mask = - min_not_zero(rs->seg_boundary_mask, - q->seg_boundary_mask); + rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); +} +EXPORT_SYMBOL_GPL(dm_set_device_limits); - rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); - } +int dm_get_device(struct dm_target *ti, const char *path, sector_t start, + sector_t len, int mode, struct dm_dev **result) +{ + int r = __table_get_device(ti->table, ti, path, + start, len, mode, result); + + if (!r) + dm_set_device_limits(ti, (*result)->bdev); return r; } diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 8cbc46b8e3db..7a48d428d0a1 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -71,6 +71,11 @@ typedef int (*dm_ioctl_fn) (struct dm_target *ti, struct inode *inode, void dm_error(const char *message); +/* + * Combine device limits. + */ +void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev); + /* * Constructors should call these functions to ensure destination devices * are opened/closed correctly. -- cgit v1.2.3 From 999d816851c3e080412a19558f111d01852d2f04 Mon Sep 17 00:00:00 2001 From: Bryn Reeves Date: Tue, 3 Oct 2006 01:15:43 -0700 Subject: [PATCH] dm table: add target flush This patch adds support for a per-target dm_flush_fn method. This is needed to allow dm-loop to invalidate page cache mappings in response to BLKFLSBUF ioctl commands. Signed-off-by: Bryn Reeves Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-table.c | 5 +++++ include/linux/device-mapper.h | 2 ++ include/linux/dm-ioctl.h | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 4920998efeeb..05befa91807a 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1001,6 +1001,11 @@ int dm_table_flush_all(struct dm_table *t) { struct list_head *d, *devices = dm_table_get_devices(t); int ret = 0; + unsigned i; + + for (i = 0; i < t->num_targets; i++) + if (t->targets[i].type->flush) + t->targets[i].type->flush(&t->targets[i]); for (d = devices->next; d != devices; d = d->next) { struct dm_dev *dd = list_entry(d, struct dm_dev, list); diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 7a48d428d0a1..03ef41c1eaac 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -55,6 +55,7 @@ typedef int (*dm_endio_fn) (struct dm_target *ti, struct bio *bio, int error, union map_info *map_context); +typedef void (*dm_flush_fn) (struct dm_target *ti); typedef void (*dm_presuspend_fn) (struct dm_target *ti); typedef void (*dm_postsuspend_fn) (struct dm_target *ti); typedef int (*dm_preresume_fn) (struct dm_target *ti); @@ -96,6 +97,7 @@ struct target_type { dm_dtr_fn dtr; dm_map_fn map; dm_endio_fn end_io; + dm_flush_fn flush; dm_presuspend_fn presuspend; dm_postsuspend_fn postsuspend; dm_preresume_fn preresume; diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index f28b5c87aa6b..8853fc4d1c5e 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h @@ -285,7 +285,7 @@ typedef char ioctl_struct[308]; #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 9 +#define DM_VERSION_MINOR 10 #define DM_VERSION_PATCHLEVEL 0 #define DM_VERSION_EXTRA "-ioctl (2006-09-14)" -- cgit v1.2.3 From fbedac04fa11d7f9f9f425c7ec253f55becaae57 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 3 Oct 2006 01:15:44 -0700 Subject: [PATCH] md: the scheduled removal of the START_ARRAY ioctl for md This patch contains the scheduled removal of the START_ARRAY ioctl for md. Signed-off-by: Adrian Bunk Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/feature-removal-schedule.txt | 9 ---- drivers/md/md.c | 82 ------------------------------ include/linux/compat_ioctl.h | 1 - include/linux/raid/md_u.h | 2 +- 4 files changed, 1 insertion(+), 93 deletions(-) (limited to 'include/linux') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 57e72e63df09..b98f01fc14bf 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -122,15 +122,6 @@ Who: Arjan van de Ven --------------------------- -What: START_ARRAY ioctl for md -When: July 2006 -Files: drivers/md/md.c -Why: Not reliable by design - can fail when most needed. - Alternatives exist -Who: NeilBrown - ---------------------------- - What: eepro100 network driver When: January 2007 Why: replaced by the e100 driver diff --git a/drivers/md/md.c b/drivers/md/md.c index 8dbab2ef3885..3af6f1f06020 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3440,67 +3440,6 @@ static void autorun_devices(int part) printk(KERN_INFO "md: ... autorun DONE.\n"); } -/* - * import RAID devices based on one partition - * if possible, the array gets run as well. - */ - -static int autostart_array(dev_t startdev) -{ - char b[BDEVNAME_SIZE]; - int err = -EINVAL, i; - mdp_super_t *sb = NULL; - mdk_rdev_t *start_rdev = NULL, *rdev; - - start_rdev = md_import_device(startdev, 0, 0); - if (IS_ERR(start_rdev)) - return err; - - - /* NOTE: this can only work for 0.90.0 superblocks */ - sb = (mdp_super_t*)page_address(start_rdev->sb_page); - if (sb->major_version != 0 || - sb->minor_version != 90 ) { - printk(KERN_WARNING "md: can only autostart 0.90.0 arrays\n"); - export_rdev(start_rdev); - return err; - } - - if (test_bit(Faulty, &start_rdev->flags)) { - printk(KERN_WARNING - "md: can not autostart based on faulty %s!\n", - bdevname(start_rdev->bdev,b)); - export_rdev(start_rdev); - return err; - } - list_add(&start_rdev->same_set, &pending_raid_disks); - - for (i = 0; i < MD_SB_DISKS; i++) { - mdp_disk_t *desc = sb->disks + i; - dev_t dev = MKDEV(desc->major, desc->minor); - - if (!dev) - continue; - if (dev == startdev) - continue; - if (MAJOR(dev) != desc->major || MINOR(dev) != desc->minor) - continue; - rdev = md_import_device(dev, 0, 0); - if (IS_ERR(rdev)) - continue; - - list_add(&rdev->same_set, &pending_raid_disks); - } - - /* - * possibly return codes - */ - autorun_devices(0); - return 0; - -} - - static int get_version(void __user * arg) { mdu_version_t ver; @@ -4259,27 +4198,6 @@ static int md_ioctl(struct inode *inode, struct file *file, goto abort; } - - if (cmd == START_ARRAY) { - /* START_ARRAY doesn't need to lock the array as autostart_array - * does the locking, and it could even be a different array - */ - static int cnt = 3; - if (cnt > 0 ) { - printk(KERN_WARNING - "md: %s(pid %d) used deprecated START_ARRAY ioctl. " - "This will not be supported beyond July 2006\n", - current->comm, current->pid); - cnt--; - } - err = autostart_array(new_decode_dev(arg)); - if (err) { - printk(KERN_WARNING "md: autostart failed!\n"); - goto abort; - } - goto done; - } - err = mddev_lock(mddev); if (err) { printk(KERN_INFO diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index d5b7abc4f409..fad3957728a2 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -122,7 +122,6 @@ COMPATIBLE_IOCTL(PROTECT_ARRAY) ULONG_IOCTL(HOT_ADD_DISK) ULONG_IOCTL(SET_DISK_FAULTY) COMPATIBLE_IOCTL(RUN_ARRAY) -ULONG_IOCTL(START_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY_RO) COMPATIBLE_IOCTL(RESTART_ARRAY_RW) diff --git a/include/linux/raid/md_u.h b/include/linux/raid/md_u.h index 81da20ccec4d..7192035fc4b0 100644 --- a/include/linux/raid/md_u.h +++ b/include/linux/raid/md_u.h @@ -41,7 +41,7 @@ /* usage */ #define RUN_ARRAY _IOW (MD_MAJOR, 0x30, mdu_param_t) -#define START_ARRAY _IO (MD_MAJOR, 0x31) +/* 0x31 was START_ARRAY */ #define STOP_ARRAY _IO (MD_MAJOR, 0x32) #define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33) #define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34) -- cgit v1.2.3 From b5c124af69119c1b5c1e728bd2e7b5b1fad9b7be Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 3 Oct 2006 01:15:45 -0700 Subject: [PATCH] md: fix a comment that is wrong in raid5.h Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/raid/raid5.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h index 20ed4c997636..f1e28952a82f 100644 --- a/include/linux/raid/raid5.h +++ b/include/linux/raid/raid5.h @@ -195,8 +195,9 @@ struct stripe_head { * it to the count of prereading stripes. * When write is initiated, or the stripe refcnt == 0 (just in case) we * clear the PREREAD_ACTIVE flag and decrement the count - * Whenever the delayed queue is empty and the device is not plugged, we - * move any strips from delayed to handle and clear the DELAYED flag and set PREREAD_ACTIVE. + * Whenever the 'handle' queue is empty and the device is not plugged, we + * move any strips from delayed to handle and clear the DELAYED flag and set + * PREREAD_ACTIVE. * In stripe_handle, if we find pre-reading is necessary, we do it if * PREREAD_ACTIVE is set, else we set DELAYED which will send it to the delayed queue. * HANDLE gets cleared if stripe_handle leave nothing locked. -- cgit v1.2.3 From 850b2b420cd5b363ed4cf48a8816d656c8b5251b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 3 Oct 2006 01:15:46 -0700 Subject: [PATCH] md: replace magic numbers in sb_dirty with well defined bit flags Instead of magic numbers (0,1,2,3) in sb_dirty, we have some flags instead: MD_CHANGE_DEVS Some device state has changed requiring superblock update on all devices. MD_CHANGE_CLEAN The array has transitions from 'clean' to 'dirty' or back, requiring a superblock update on active devices, but possibly not on spares MD_CHANGE_PENDING A superblock update is underway. We wait for an update to complete by waiting for all flags to be clear. A flag can be set at any time, even during an update, without risk that the change will be lost. Stop exporting md_update_sb - isn't needed. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/md.c | 76 +++++++++++++++++++++++++---------------------- drivers/md/multipath.c | 3 +- drivers/md/raid1.c | 2 +- drivers/md/raid10.c | 2 +- drivers/md/raid5.c | 8 ++--- include/linux/raid/md.h | 1 - include/linux/raid/md_k.h | 6 +++- 7 files changed, 52 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index 3af6f1f06020..8b08043f07ef 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1587,7 +1587,7 @@ static void sync_sbs(mddev_t * mddev, int nospares) } } -void md_update_sb(mddev_t * mddev) +static void md_update_sb(mddev_t * mddev, int force_change) { int err; struct list_head *tmp; @@ -1598,7 +1598,18 @@ void md_update_sb(mddev_t * mddev) repeat: spin_lock_irq(&mddev->write_lock); - if (mddev->degraded && mddev->sb_dirty == 3) + set_bit(MD_CHANGE_PENDING, &mddev->flags); + if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags)) + force_change = 1; + if (test_and_clear_bit(MD_CHANGE_CLEAN, &mddev->flags)) + /* just a clean<-> dirty transition, possibly leave spares alone, + * though if events isn't the right even/odd, we will have to do + * spares after all + */ + nospares = 1; + if (force_change) + nospares = 0; + if (mddev->degraded) /* If the array is degraded, then skipping spares is both * dangerous and fairly pointless. * Dangerous because a device that was removed from the array @@ -1608,20 +1619,14 @@ repeat: * then a recovery will happen and soon that array won't * be degraded any more and the spare can go back to sleep then. */ - mddev->sb_dirty = 1; + nospares = 0; sync_req = mddev->in_sync; mddev->utime = get_seconds(); - if (mddev->sb_dirty == 3) - /* just a clean<-> dirty transition, possibly leave spares alone, - * though if events isn't the right even/odd, we will have to do - * spares after all - */ - nospares = 1; /* If this is just a dirty<->clean transition, and the array is clean * and 'events' is odd, we can roll back to the previous clean state */ - if (mddev->sb_dirty == 3 + if (nospares && (mddev->in_sync && mddev->recovery_cp == MaxSector) && (mddev->events & 1)) mddev->events--; @@ -1652,7 +1657,6 @@ repeat: MD_BUG(); mddev->events --; } - mddev->sb_dirty = 2; sync_sbs(mddev, nospares); /* @@ -1660,7 +1664,7 @@ repeat: * nonpersistent superblocks */ if (!mddev->persistent) { - mddev->sb_dirty = 0; + clear_bit(MD_CHANGE_PENDING, &mddev->flags); spin_unlock_irq(&mddev->write_lock); wake_up(&mddev->sb_wait); return; @@ -1697,20 +1701,20 @@ repeat: break; } md_super_wait(mddev); - /* if there was a failure, sb_dirty was set to 1, and we re-write super */ + /* if there was a failure, MD_CHANGE_DEVS was set, and we re-write super */ spin_lock_irq(&mddev->write_lock); - if (mddev->in_sync != sync_req|| mddev->sb_dirty == 1) { + if (mddev->in_sync != sync_req || + test_bit(MD_CHANGE_DEVS, &mddev->flags)) { /* have to write it out again */ spin_unlock_irq(&mddev->write_lock); goto repeat; } - mddev->sb_dirty = 0; + clear_bit(MD_CHANGE_PENDING, &mddev->flags); spin_unlock_irq(&mddev->write_lock); wake_up(&mddev->sb_wait); } -EXPORT_SYMBOL_GPL(md_update_sb); /* words written to sysfs files may, or my not, be \n terminated. * We want to accept with case. For this we use cmd_match. @@ -1783,7 +1787,7 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len) else { mddev_t *mddev = rdev->mddev; kick_rdev_from_array(rdev); - md_update_sb(mddev); + md_update_sb(mddev, 1); md_new_event(mddev); err = 0; } @@ -2426,7 +2430,7 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) spin_lock_irq(&mddev->write_lock); if (atomic_read(&mddev->writes_pending) == 0) { mddev->in_sync = 1; - mddev->sb_dirty = 1; + set_bit(MD_CHANGE_CLEAN, &mddev->flags); } spin_unlock_irq(&mddev->write_lock); } else { @@ -2438,7 +2442,7 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) case active: if (mddev->pers) { restart_array(mddev); - mddev->sb_dirty = 0; + clear_bit(MD_CHANGE_CLEAN, &mddev->flags); wake_up(&mddev->sb_wait); err = 0; } else { @@ -2543,7 +2547,7 @@ size_store(mddev_t *mddev, const char *buf, size_t len) if (mddev->pers) { err = update_size(mddev, size); - md_update_sb(mddev); + md_update_sb(mddev, 1); } else { if (mddev->size == 0 || mddev->size > size) @@ -3111,8 +3115,8 @@ static int do_md_run(mddev_t * mddev) set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); - if (mddev->sb_dirty) - md_update_sb(mddev); + if (mddev->flags) + md_update_sb(mddev, 0); set_capacity(disk, mddev->array_size<<1); @@ -3275,10 +3279,10 @@ static int do_md_stop(mddev_t * mddev, int mode) if (mddev->ro) mddev->ro = 0; } - if (!mddev->in_sync || mddev->sb_dirty) { + if (!mddev->in_sync || mddev->flags) { /* mark array as shutdown cleanly */ mddev->in_sync = 1; - md_update_sb(mddev); + md_update_sb(mddev, 1); } if (mode == 1) set_disk_ro(disk, 1); @@ -3747,7 +3751,7 @@ static int hot_remove_disk(mddev_t * mddev, dev_t dev) goto busy; kick_rdev_from_array(rdev); - md_update_sb(mddev); + md_update_sb(mddev, 1); md_new_event(mddev); return 0; @@ -3824,7 +3828,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev) rdev->raid_disk = -1; - md_update_sb(mddev); + md_update_sb(mddev, 1); /* * Kick recovery, maybe this spare has to be added to the @@ -3955,7 +3959,8 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) mddev->max_disks = MD_SB_DISKS; - mddev->sb_dirty = 1; + mddev->flags = 0; + set_bit(MD_CHANGE_DEVS, &mddev->flags); mddev->default_bitmap_offset = MD_SB_BYTES >> 9; mddev->bitmap_offset = 0; @@ -4124,7 +4129,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) mddev->bitmap_offset = 0; } } - md_update_sb(mddev); + md_update_sb(mddev, 1); return rv; } @@ -4960,12 +4965,12 @@ void md_write_start(mddev_t *mddev, struct bio *bi) spin_lock_irq(&mddev->write_lock); if (mddev->in_sync) { mddev->in_sync = 0; - mddev->sb_dirty = 3; + set_bit(MD_CHANGE_CLEAN, &mddev->flags); md_wakeup_thread(mddev->thread); } spin_unlock_irq(&mddev->write_lock); } - wait_event(mddev->sb_wait, mddev->sb_dirty==0); + wait_event(mddev->sb_wait, mddev->flags==0); } void md_write_end(mddev_t *mddev) @@ -5235,7 +5240,6 @@ void md_do_sync(mddev_t *mddev) !test_bit(In_sync, &rdev->flags) && rdev->recovery_offset < mddev->curr_resync) rdev->recovery_offset = mddev->curr_resync; - mddev->sb_dirty = 1; } } @@ -5292,7 +5296,7 @@ void md_check_recovery(mddev_t *mddev) } if ( ! ( - mddev->sb_dirty || + mddev->flags || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || test_bit(MD_RECOVERY_DONE, &mddev->recovery) || (mddev->safemode == 1) || @@ -5308,14 +5312,14 @@ void md_check_recovery(mddev_t *mddev) if (mddev->safemode && !atomic_read(&mddev->writes_pending) && !mddev->in_sync && mddev->recovery_cp == MaxSector) { mddev->in_sync = 1; - mddev->sb_dirty = 3; + set_bit(MD_CHANGE_CLEAN, &mddev->flags); } if (mddev->safemode == 1) mddev->safemode = 0; spin_unlock_irq(&mddev->write_lock); - if (mddev->sb_dirty) - md_update_sb(mddev); + if (mddev->flags) + md_update_sb(mddev, 0); if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) && @@ -5334,7 +5338,7 @@ void md_check_recovery(mddev_t *mddev) /* activate any spares */ mddev->pers->spare_active(mddev); } - md_update_sb(mddev); + md_update_sb(mddev, 1); /* if array is no-longer degraded, then any saved_raid_disk * information must be scrapped diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 1cc9de44ce86..e4f168d063db 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -253,7 +253,7 @@ static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev) char b[BDEVNAME_SIZE]; clear_bit(In_sync, &rdev->flags); set_bit(Faulty, &rdev->flags); - mddev->sb_dirty = 1; + set_bit(MD_CHANGE_DEVS, &mddev->flags); conf->working_disks--; printk(KERN_ALERT "multipath: IO failure on %s," " disabling IO path. \n Operation continuing" @@ -470,7 +470,6 @@ static int multipath_run (mddev_t *mddev) } conf->raid_disks = mddev->raid_disks; - mddev->sb_dirty = 1; conf->mddev = mddev; spin_lock_init(&conf->device_lock); INIT_LIST_HEAD(&conf->retry_list); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 3b4d69c05623..2817c477302d 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -969,7 +969,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) } clear_bit(In_sync, &rdev->flags); set_bit(Faulty, &rdev->flags); - mddev->sb_dirty = 1; + set_bit(MD_CHANGE_DEVS, &mddev->flags); printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n" " Operation continuing on %d devices\n", bdevname(rdev->bdev,b), conf->working_disks); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 7bf5ce281c4d..85e3df2d268a 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -960,7 +960,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) } clear_bit(In_sync, &rdev->flags); set_bit(Faulty, &rdev->flags); - mddev->sb_dirty = 1; + set_bit(MD_CHANGE_DEVS, &mddev->flags); printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n" " Operation continuing on %d devices\n", bdevname(rdev->bdev,b), conf->working_disks); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 450066007160..d5a06b258427 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -696,7 +696,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) PRINTK("raid5: error called\n"); if (!test_bit(Faulty, &rdev->flags)) { - mddev->sb_dirty = 1; + set_bit(MD_CHANGE_DEVS, &mddev->flags); if (test_bit(In_sync, &rdev->flags)) { conf->working_disks--; mddev->degraded++; @@ -2781,9 +2781,9 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped wait_event(conf->wait_for_overlap, atomic_read(&conf->reshape_stripes)==0); mddev->reshape_position = conf->expand_progress; - mddev->sb_dirty = 1; + set_bit(MD_CHANGE_DEVS, &mddev->flags); md_wakeup_thread(mddev->thread); - wait_event(mddev->sb_wait, mddev->sb_dirty == 0 || + wait_event(mddev->sb_wait, mddev->flags == 0 || kthread_should_stop()); spin_lock_irq(&conf->device_lock); conf->expand_lo = mddev->reshape_position; @@ -3605,7 +3605,7 @@ static int raid5_start_reshape(mddev_t *mddev) mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) - added_devices; mddev->raid_disks = conf->raid_disks; mddev->reshape_position = 0; - mddev->sb_dirty = 1; + set_bit(MD_CHANGE_DEVS, &mddev->flags); clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h index c588709acbbc..866a1e2b0ce0 100644 --- a/include/linux/raid/md.h +++ b/include/linux/raid/md.h @@ -95,7 +95,6 @@ extern int sync_page_io(struct block_device *bdev, sector_t sector, int size, extern void md_do_sync(mddev_t *mddev); extern void md_new_event(mddev_t *mddev); -extern void md_update_sb(mddev_t * mddev); #endif /* CONFIG_MD */ #endif diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 920b94fe31fa..e423dad1a7fd 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -116,7 +116,11 @@ struct mddev_s dev_t unit; int md_minor; struct list_head disks; - int sb_dirty; + unsigned long flags; +#define MD_CHANGE_DEVS 0 /* Some device status has changed */ +#define MD_CHANGE_CLEAN 1 /* transition to or from 'clean' */ +#define MD_CHANGE_PENDING 2 /* superblock update in progress */ + int ro; struct gendisk *gendisk; -- cgit v1.2.3 From 02c2de8cc835885bdff51a8bfd6c0b659b969f50 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 3 Oct 2006 01:15:47 -0700 Subject: [PATCH] md: remove the working_disks and failed_disks from raid5 state data. They are not needed. conf->failed_disks is the same as mddev->degraded and conf->working_disks is conf->raid_disks - mddev->degraded. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/raid5.c | 20 ++++++++------------ include/linux/raid/raid5.h | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index d5a06b258427..1c8ab340a11d 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -698,9 +698,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) if (!test_bit(Faulty, &rdev->flags)) { set_bit(MD_CHANGE_DEVS, &mddev->flags); if (test_bit(In_sync, &rdev->flags)) { - conf->working_disks--; mddev->degraded++; - conf->failed_disks++; clear_bit(In_sync, &rdev->flags); /* * if recovery was running, make sure it aborts. @@ -711,7 +709,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) printk (KERN_ALERT "raid5: Disk failure on %s, disabling device." " Operation continuing on %d devices\n", - bdevname(rdev->bdev,b), conf->working_disks); + bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded); } } @@ -3074,6 +3072,7 @@ static int run(mddev_t *mddev) mdk_rdev_t *rdev; struct disk_info *disk; struct list_head *tmp; + int working_disks = 0; if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) { printk(KERN_ERR "raid5: %s: raid level not set to 4/5/6 (%d)\n", @@ -3176,14 +3175,14 @@ static int run(mddev_t *mddev) printk(KERN_INFO "raid5: device %s operational as raid" " disk %d\n", bdevname(rdev->bdev,b), raid_disk); - conf->working_disks++; + working_disks++; } } /* * 0 for a fully functional array, 1 or 2 for a degraded array. */ - mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks; + mddev->degraded = conf->raid_disks - working_disks; conf->mddev = mddev; conf->chunk_size = mddev->chunk_size; conf->level = mddev->level; @@ -3218,7 +3217,7 @@ static int run(mddev_t *mddev) if (mddev->degraded > conf->max_degraded) { printk(KERN_ERR "raid5: not enough operational devices for %s" " (%d/%d failed)\n", - mdname(mddev), conf->failed_disks, conf->raid_disks); + mdname(mddev), mddev->degraded, conf->raid_disks); goto abort; } @@ -3375,7 +3374,7 @@ static void status (struct seq_file *seq, mddev_t *mddev) int i; seq_printf (seq, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout); - seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->working_disks); + seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->raid_disks - mddev->degraded); for (i = 0; i < conf->raid_disks; i++) seq_printf (seq, "%s", conf->disks[i].rdev && @@ -3397,8 +3396,8 @@ static void print_raid5_conf (raid5_conf_t *conf) printk("(conf==NULL)\n"); return; } - printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks, - conf->working_disks, conf->failed_disks); + printk(" --- rd:%d wd:%d\n", conf->raid_disks, + conf->raid_disks - conf->mddev->degraded); for (i = 0; i < conf->raid_disks; i++) { char b[BDEVNAME_SIZE]; @@ -3422,8 +3421,6 @@ static int raid5_spare_active(mddev_t *mddev) && !test_bit(Faulty, &tmp->rdev->flags) && !test_bit(In_sync, &tmp->rdev->flags)) { mddev->degraded--; - conf->failed_disks--; - conf->working_disks++; set_bit(In_sync, &tmp->rdev->flags); } } @@ -3593,7 +3590,6 @@ static int raid5_start_reshape(mddev_t *mddev) if (raid5_add_disk(mddev, rdev)) { char nm[20]; set_bit(In_sync, &rdev->flags); - conf->working_disks++; added_devices++; rdev->recovery_offset = 0; sprintf(nm, "rd%d", rdev->raid_disk); diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h index f1e28952a82f..f13299a15591 100644 --- a/include/linux/raid/raid5.h +++ b/include/linux/raid/raid5.h @@ -214,7 +214,7 @@ struct raid5_private_data { struct disk_info *spare; int chunk_size, level, algorithm; int max_degraded; - int raid_disks, working_disks, failed_disks; + int raid_disks; int max_nr_stripes; /* used during an expand */ -- cgit v1.2.3 From 76186dd8b73d2b7b9b4c8629b89c845e97009801 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 3 Oct 2006 01:15:48 -0700 Subject: [PATCH] md: remove 'working_disks' from raid10 state It isn't needed as mddev->degraded contains equivalent info. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/raid10.c | 12 ++++-------- include/linux/raid/raid10.h | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 85e3df2d268a..233a4faede94 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -921,7 +921,7 @@ static void status(struct seq_file *seq, mddev_t *mddev) seq_printf(seq, " %d far-copies", conf->far_copies); } seq_printf(seq, " [%d/%d] [", conf->raid_disks, - conf->working_disks); + conf->raid_disks - mddev->degraded); for (i = 0; i < conf->raid_disks; i++) seq_printf(seq, "%s", conf->mirrors[i].rdev && @@ -941,7 +941,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) * else mark the drive as failed */ if (test_bit(In_sync, &rdev->flags) - && conf->working_disks == 1) + && conf->raid_disks-mddev->degraded == 1) /* * Don't fail the drive, just return an IO error. * The test should really be more sophisticated than @@ -952,7 +952,6 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) return; if (test_bit(In_sync, &rdev->flags)) { mddev->degraded++; - conf->working_disks--; /* * if recovery is running, make sure it aborts. */ @@ -963,7 +962,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) set_bit(MD_CHANGE_DEVS, &mddev->flags); printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n" " Operation continuing on %d devices\n", - bdevname(rdev->bdev,b), conf->working_disks); + bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded); } static void print_conf(conf_t *conf) @@ -976,7 +975,7 @@ static void print_conf(conf_t *conf) printk("(!conf)\n"); return; } - printk(" --- wd:%d rd:%d\n", conf->working_disks, + printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded, conf->raid_disks); for (i = 0; i < conf->raid_disks; i++) { @@ -1035,7 +1034,6 @@ static int raid10_spare_active(mddev_t *mddev) if (tmp->rdev && !test_bit(Faulty, &tmp->rdev->flags) && !test_bit(In_sync, &tmp->rdev->flags)) { - conf->working_disks++; mddev->degraded--; set_bit(In_sync, &tmp->rdev->flags); } @@ -2035,8 +2033,6 @@ static int run(mddev_t *mddev) mddev->queue->max_sectors = (PAGE_SIZE>>9); disk->head_position = 0; - if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags)) - conf->working_disks++; } conf->raid_disks = mddev->raid_disks; conf->mddev = mddev; diff --git a/include/linux/raid/raid10.h b/include/linux/raid/raid10.h index c41e56a7c090..e9091cfeb286 100644 --- a/include/linux/raid/raid10.h +++ b/include/linux/raid/raid10.h @@ -16,7 +16,6 @@ struct r10_private_data_s { mddev_t *mddev; mirror_info_t *mirrors; int raid_disks; - int working_disks; spinlock_t device_lock; /* geometry */ -- cgit v1.2.3 From 9b1d1dac181d8c1b9492e05cee660a985d035a06 Mon Sep 17 00:00:00 2001 From: Paul Clements Date: Tue, 3 Oct 2006 01:15:49 -0700 Subject: [PATCH] md: new sysfs interface for setting bits in the write-intent-bitmap Add a new sysfs interface that allows the bitmap of an array to be dirtied. The interface is write-only, and is used as follows: echo "1000" > /sys/block/md2/md/bitmap (dirty the bit for chunk 1000 [offset 0] in the in-memory and on-disk bitmaps of array md2) echo "1000-2000" > /sys/block/md1/md/bitmap (dirty the bits for chunks 1000-2000 in md1's bitmap) This is useful, for example, in cluster environments where you may need to combine two disjoint bitmaps into one (following a server failure, after a secondary server has taken over the array). By combining the bitmaps on the two servers, a full resync can be avoided (This was discussed on the list back on March 18, 2005, "[PATCH 1/2] md bitmap bug fixes" thread). Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/md.txt | 9 +++++++++ drivers/md/bitmap.c | 14 ++++++++++++++ drivers/md/md.c | 31 +++++++++++++++++++++++++++++++ include/linux/raid/bitmap.h | 2 ++ 4 files changed, 56 insertions(+) (limited to 'include/linux') diff --git a/Documentation/md.txt b/Documentation/md.txt index 0668f9dc9d29..084ecf4eb2f8 100644 --- a/Documentation/md.txt +++ b/Documentation/md.txt @@ -410,6 +410,15 @@ also have than sectors, this my be larger than the number of actual errors by a factor of the number of sectors in a page. + bitmap_set_bits + If the array has a write-intent bitmap, then writing to this + attribute can set bits in the bitmap, indicating that a resync + would need to check the corresponding blocks. Either individual + numbers or start-end pairs can be written. Multiple numbers + can be separated by a space. + Note that the numbers are 'bit' numbers, not 'block' numbers. + They should be scaled by the bitmap_chunksize. + Each active md device may also have attributes specific to the personality module that manages it. These are specific to the implementation of the module and could diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index ecc56765d949..0a44298fb353 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -613,6 +613,7 @@ static inline unsigned long file_page_offset(unsigned long chunk) static inline struct page *filemap_get_page(struct bitmap *bitmap, unsigned long chunk) { + if (file_page_index(chunk) >= bitmap->file_pages) return NULL; return bitmap->filemap[file_page_index(chunk) - file_page_index(0)]; } @@ -739,6 +740,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) } page = filemap_get_page(bitmap, chunk); + if (!page) return; bit = file_page_offset(chunk); /* set the bit */ @@ -1322,6 +1324,18 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n } +/* dirty the memory and file bits for bitmap chunks "s" to "e" */ +void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e) +{ + unsigned long chunk; + + for (chunk = s; chunk <= e; chunk++) { + sector_t sec = chunk << CHUNK_BLOCK_SHIFT(bitmap); + bitmap_set_memory_bits(bitmap, sec, 1); + bitmap_file_set_bit(bitmap, sec); + } +} + /* * flush out any pending updates */ diff --git a/drivers/md/md.c b/drivers/md/md.c index 8b08043f07ef..b95dd8a183ec 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2523,6 +2523,36 @@ new_dev_store(mddev_t *mddev, const char *buf, size_t len) static struct md_sysfs_entry md_new_device = __ATTR(new_dev, S_IWUSR, null_show, new_dev_store); +static ssize_t +bitmap_store(mddev_t *mddev, const char *buf, size_t len) +{ + char *end; + unsigned long chunk, end_chunk; + + if (!mddev->bitmap) + goto out; + /* buf should be ... or - ... (range) */ + while (*buf) { + chunk = end_chunk = simple_strtoul(buf, &end, 0); + if (buf == end) break; + if (*end == '-') { /* range */ + buf = end + 1; + end_chunk = simple_strtoul(buf, &end, 0); + if (buf == end) break; + } + if (*end && !isspace(*end)) break; + bitmap_dirty_bits(mddev->bitmap, chunk, end_chunk); + buf = end; + while (isspace(*buf)) buf++; + } + bitmap_unplug(mddev->bitmap); /* flush the bits to disk */ +out: + return len; +} + +static struct md_sysfs_entry md_bitmap = +__ATTR(bitmap_set_bits, S_IWUSR, null_show, bitmap_store); + static ssize_t size_show(mddev_t *mddev, char *page) { @@ -2843,6 +2873,7 @@ static struct attribute *md_redundancy_attrs[] = { &md_sync_completed.attr, &md_suspend_lo.attr, &md_suspend_hi.attr, + &md_bitmap.attr, NULL, }; static struct attribute_group md_redundancy_group = { diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h index 63df898fe2e9..84d887751855 100644 --- a/include/linux/raid/bitmap.h +++ b/include/linux/raid/bitmap.h @@ -265,6 +265,8 @@ int bitmap_update_sb(struct bitmap *bitmap); int bitmap_setallbits(struct bitmap *bitmap); void bitmap_write_all(struct bitmap *bitmap); +void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e); + /* these are exported */ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, int behind); -- cgit v1.2.3 From 11ce99e625fe2718ad2682bfdd99070b337e6252 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 3 Oct 2006 01:15:52 -0700 Subject: [PATCH] md: Remove working_disks from raid1 state data It is equivalent to conf->raid_disks - conf->mddev->degraded. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/raid1.c | 28 ++++++++++++---------------- include/linux/raid/raid1.h | 1 - 2 files changed, 12 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 13b59e6a6acb..3fc9ec239478 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -271,7 +271,7 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int */ update_head_pos(mirror, r1_bio); - if (uptodate || conf->working_disks <= 1) { + if (uptodate || (conf->raid_disks - conf->mddev->degraded) <= 1) { /* * Set R1BIO_Uptodate in our master bio, so that * we will return a good error code for to the higher @@ -929,7 +929,7 @@ static void status(struct seq_file *seq, mddev_t *mddev) int i; seq_printf(seq, " [%d/%d] [", conf->raid_disks, - conf->working_disks); + conf->raid_disks - mddev->degraded); rcu_read_lock(); for (i = 0; i < conf->raid_disks; i++) { mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev); @@ -953,7 +953,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) * else mark the drive as failed */ if (test_bit(In_sync, &rdev->flags) - && conf->working_disks == 1) + && (conf->raid_disks - mddev->degraded) == 1) /* * Don't fail the drive, act as though we were just a * normal single drive @@ -961,7 +961,6 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) return; if (test_bit(In_sync, &rdev->flags)) { mddev->degraded++; - conf->working_disks--; /* * if recovery is running, make sure it aborts. */ @@ -972,7 +971,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) set_bit(MD_CHANGE_DEVS, &mddev->flags); printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n" " Operation continuing on %d devices\n", - bdevname(rdev->bdev,b), conf->working_disks); + bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded); } static void print_conf(conf_t *conf) @@ -984,7 +983,7 @@ static void print_conf(conf_t *conf) printk("(!conf)\n"); return; } - printk(" --- wd:%d rd:%d\n", conf->working_disks, + printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded, conf->raid_disks); rcu_read_lock(); @@ -1024,7 +1023,6 @@ static int raid1_spare_active(mddev_t *mddev) if (rdev && !test_bit(Faulty, &rdev->flags) && !test_bit(In_sync, &rdev->flags)) { - conf->working_disks++; mddev->degraded--; set_bit(In_sync, &rdev->flags); } @@ -1901,15 +1899,11 @@ static int run(mddev_t *mddev) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->head_position = 0; - if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags)) - conf->working_disks++; } conf->raid_disks = mddev->raid_disks; conf->mddev = mddev; spin_lock_init(&conf->device_lock); INIT_LIST_HEAD(&conf->retry_list); - if (conf->working_disks == 1) - mddev->recovery_cp = MaxSector; spin_lock_init(&conf->resync_lock); init_waitqueue_head(&conf->wait_barrier); @@ -1917,11 +1911,6 @@ static int run(mddev_t *mddev) bio_list_init(&conf->pending_bio_list); bio_list_init(&conf->flushing_bio_list); - if (!conf->working_disks) { - printk(KERN_ERR "raid1: no operational mirrors for %s\n", - mdname(mddev)); - goto out_free_conf; - } mddev->degraded = 0; for (i = 0; i < conf->raid_disks; i++) { @@ -1934,6 +1923,13 @@ static int run(mddev_t *mddev) mddev->degraded++; } } + if (mddev->degraded == conf->raid_disks) { + printk(KERN_ERR "raid1: no operational mirrors for %s\n", + mdname(mddev)); + goto out_free_conf; + } + if (conf->raid_disks - mddev->degraded == 1) + mddev->recovery_cp = MaxSector; /* * find the first working one and use it as a starting point diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h index 3009c813d83d..0a9ba7c3302e 100644 --- a/include/linux/raid/raid1.h +++ b/include/linux/raid/raid1.h @@ -30,7 +30,6 @@ struct r1_private_data_s { mddev_t *mddev; mirror_info_t *mirrors; int raid_disks; - int working_disks; int last_used; sector_t next_seq_sect; spinlock_t device_lock; -- cgit v1.2.3 From e8703fe1f5cdcff686f7eb0a46487b5a04a9324a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 3 Oct 2006 01:15:59 -0700 Subject: [PATCH] md: remove MAX_MD_DEVS which is an arbitrary limit Once upon a time we needed to fixed limit to the number of md devices, probably because we preallocated some array. This need no longer exists, but we still have an arbitrary limit. So remove MAX_MD_DEVS and allow as many devices as we can fit into the 'minor' part of a device number. Also remove some useless noise at init time (which reports MAX_MD_DEVS) and remove MD_THREAD_NAME_MAX which hasn't been used for a while. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/md.c | 33 +++++++++++++++------------------ include/linux/raid/md_k.h | 5 +---- init/do_mounts_md.c | 8 ++------ 3 files changed, 18 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index db1ac84a739a..40cb79ac4039 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3409,6 +3409,7 @@ static void autorun_devices(int part) printk(KERN_INFO "md: autorun ...\n"); while (!list_empty(&pending_raid_disks)) { + int unit; dev_t dev; LIST_HEAD(candidates); rdev0 = list_entry(pending_raid_disks.next, @@ -3428,16 +3429,19 @@ static void autorun_devices(int part) * mostly sane superblocks. It's time to allocate the * mddev. */ - if (rdev0->preferred_minor < 0 || rdev0->preferred_minor >= MAX_MD_DEVS) { + if (part) { + dev = MKDEV(mdp_major, + rdev0->preferred_minor << MdpMinorShift); + unit = MINOR(dev) >> MdpMinorShift; + } else { + dev = MKDEV(MD_MAJOR, rdev0->preferred_minor); + unit = MINOR(dev); + } + if (rdev0->preferred_minor != unit) { printk(KERN_INFO "md: unit number in %s is bad: %d\n", bdevname(rdev0->bdev, b), rdev0->preferred_minor); break; } - if (part) - dev = MKDEV(mdp_major, - rdev0->preferred_minor << MdpMinorShift); - else - dev = MKDEV(MD_MAJOR, rdev0->preferred_minor); md_probe(dev, NULL, NULL); mddev = mddev_find(dev); @@ -5524,22 +5528,15 @@ static void md_geninit(void) static int __init md_init(void) { - printk(KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d," - " MD_SB_DISKS=%d\n", - MD_MAJOR_VERSION, MD_MINOR_VERSION, - MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS); - printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR_HI, - BITMAP_MINOR); - if (register_blkdev(MAJOR_NR, "md")) return -1; if ((mdp_major=register_blkdev(0, "mdp"))<=0) { unregister_blkdev(MAJOR_NR, "md"); return -1; } - blk_register_region(MKDEV(MAJOR_NR, 0), MAX_MD_DEVS, THIS_MODULE, - md_probe, NULL, NULL); - blk_register_region(MKDEV(mdp_major, 0), MAX_MD_DEVS<= MAX_MD_DEVS) { - printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor); - return 0; - } for (ent=0 ; ent< md_setup_ents ; ent++) if (md_setup_args[ent].minor == minor && md_setup_args[ent].partitioned == partitioned) { @@ -72,7 +68,7 @@ static int __init md_setup(char *str) "Replacing previous definition.\n", partitioned?"d":"", minor); break; } - if (ent >= MAX_MD_DEVS) { + if (ent >= ARRAY_SIZE(md_setup_args)) { printk(KERN_WARNING "md: md=%s%d - too many md initialisations\n", partitioned?"d":"", minor); return 0; } -- cgit v1.2.3 From d19c2ee0b8d1cd83f8bc0f1f5e94e6b6ec71ea10 Mon Sep 17 00:00:00 2001 From: Paul Clements Date: Tue, 3 Oct 2006 01:16:02 -0700 Subject: [PATCH] md: allow SET_BITMAP_FILE to work on 64bit kernel with 32bit userspace Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/compat_ioctl.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index fad3957728a2..4e1663d7691e 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -125,6 +125,7 @@ COMPATIBLE_IOCTL(RUN_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY_RO) COMPATIBLE_IOCTL(RESTART_ARRAY_RW) +ULONG_IOCTL(SET_BITMAP_FILE) /* DM */ COMPATIBLE_IOCTL(DM_VERSION_32) COMPATIBLE_IOCTL(DM_REMOVE_ALL_32) -- cgit v1.2.3 From 8b2a1fd1b394c60eaa2587716102dd5e9b4e5990 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 3 Oct 2006 01:16:15 -0700 Subject: [PATCH] pr_debug: check pr_debug() arguments check pr_debug() arguments When DEBUG isn't defined pr_debug() is defined away as an empty macro. By throwing away the arguments we allow completely incorrect code to build. Instead let's make it an empty inline which checks arguments and mark it so gcc can check the format specification. This results in a seemingly insignificant code size increase. A x86-64 allyesconfig: text data bss dec hex filename 25354768 7191098 4854720 37400586 23ab00a vmlinux.before 25354945 7191138 4854720 37400803 23ab0e3 vmlinux Signed-off-by: Zach Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 4d00988dad03..80f39cab470a 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -216,8 +216,10 @@ extern void dump_stack(void); #define pr_debug(fmt,arg...) \ printk(KERN_DEBUG fmt,##arg) #else -#define pr_debug(fmt,arg...) \ - do { } while (0) +static inline int __attribute__ ((format (printf, 1, 2))) pr_debug(const char * fmt, ...) +{ + return 0; +} #endif #define pr_info(fmt,arg...) \ -- cgit v1.2.3 From 15a1c5140436c5be7673a4709c5d7e1f3cd7bdd9 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 2 Oct 2006 12:55:09 +0100 Subject: [MIPS] BCM1250: TRDY timeout tweaks for Broadcom SiByte systems It was obesrved that at least one older PCI card predating the requirement for the TRDY signal to respond within 16 clock ticks actually does not meet this rule nor even the power-on defaults of the PCI bridges found in development systems built around the Broadcom SiByte SOCs. Here is a patch that bumps up the timeout to the highest finite value supported by these chips, which is 255 clock ticks. The bridges affected are the SiByte SOC itself and the SP1011. This change does not effectively affect systems only having PCI option cards installed that meet the TRDY requirement of the current PCI spec. The rule was introduced with PCI 2.1, so any older card may make the system affected. If this is the case, performance of the system will suffer in return for the card working at all. If this is a concern, then the solution is not to use such cards. Signed-off-by: Maciej W. Rozycki Signed-off-by: Ralf Baechle --- --- arch/mips/pci/fixup-sb1250.c | 23 ++++++++++++++++++++++- include/linux/pci_ids.h | 3 +++ 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c index 13791b78e598..7a7444874e80 100644 --- a/arch/mips/pci/fixup-sb1250.c +++ b/arch/mips/pci/fixup-sb1250.c @@ -1,7 +1,7 @@ /* * arch/mips/pci/fixup-sb1250.c * - * Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2004, 2006 MIPS Technologies, Inc. All rights reserved. * Author: Maciej W. Rozycki * * This program is free software; you can redistribute it and/or @@ -13,6 +13,17 @@ #include #include +/* + * Set the the BCM1250, etc. PCI host bridge's TRDY timeout + * to the finite max. + */ +static void __init quirk_sb1250_pci(struct pci_dev *dev) +{ + pci_write_config_byte(dev, 0x40, 0xff); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI, + quirk_sb1250_pci); + /* * The BCM1250, etc. PCI/HT bridge reports as a host bridge. */ @@ -22,3 +33,13 @@ static void __init quirk_sb1250_ht(struct pci_dev *dev) } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT, quirk_sb1250_ht); + +/* + * Set the the SP1011 HT/PCI bridge's TRDY timeout to the finite max. + */ +static void __init quirk_sp1011(struct pci_dev *dev) +{ + pci_write_config_byte(dev, 0x64, 0xff); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIPACKETS, PCI_DEVICE_ID_SP1011, + quirk_sp1011); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c9ffbc3843d5..dc7f573d36e4 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1883,6 +1883,8 @@ #define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400 #define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402 +#define PCI_VENDOR_ID_SIPACKETS 0x14d9 +#define PCI_DEVICE_ID_SP1011 0x0010 #define PCI_VENDOR_ID_AFAVLAB 0x14db #define PCI_DEVICE_ID_AFAVLAB_P028 0x2180 @@ -1997,6 +1999,7 @@ #define PCI_DEVICE_ID_FARSITE_TE1C 0x1612 #define PCI_VENDOR_ID_SIBYTE 0x166d +#define PCI_DEVICE_ID_BCM1250_PCI 0x0001 #define PCI_DEVICE_ID_BCM1250_HT 0x0002 #define PCI_VENDOR_ID_NETCELL 0x169c -- cgit v1.2.3 From af8b128719f5248e542036ea994610a29d0642a6 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Mon, 2 Oct 2006 23:19:00 +0900 Subject: [MIPS] Remove IT8172-based platforms, ITE 8172G and Globespan IVR support. As per feature-removal-schedule.txt. Signed-off-by: Yoichi Yuasa Acked-by: Alan Cox Signed-off-by: Ralf Baechle --- Documentation/feature-removal-schedule.txt | 10 - arch/mips/Kconfig | 47 - arch/mips/Makefile | 13 - arch/mips/configs/it8172_defconfig | 964 ------------ arch/mips/configs/ivr_defconfig | 920 ----------- arch/mips/ite-boards/Kconfig | 8 - arch/mips/ite-boards/generic/Makefile | 15 - arch/mips/ite-boards/generic/dbg_io.c | 124 -- arch/mips/ite-boards/generic/irq.c | 308 ---- arch/mips/ite-boards/generic/it8172_cir.c | 170 -- arch/mips/ite-boards/generic/it8172_setup.c | 352 ----- arch/mips/ite-boards/generic/lpc.c | 144 -- arch/mips/ite-boards/generic/pmon_prom.c | 135 -- arch/mips/ite-boards/generic/puts.c | 139 -- arch/mips/ite-boards/generic/reset.c | 60 - arch/mips/ite-boards/generic/time.c | 249 --- arch/mips/ite-boards/ivr/Makefile | 10 - arch/mips/ite-boards/ivr/README | 3 - arch/mips/ite-boards/ivr/init.c | 81 - arch/mips/ite-boards/qed-4n-s01b/Makefile | 10 - arch/mips/ite-boards/qed-4n-s01b/README | 2 - arch/mips/ite-boards/qed-4n-s01b/init.c | 82 - arch/mips/pci/Makefile | 3 - arch/mips/pci/fixup-ite8172g.c | 80 - arch/mips/pci/fixup-ivr.c | 75 - arch/mips/pci/ops-it8172.c | 213 --- drivers/char/.gitignore | 1 - drivers/char/Kconfig | 30 - drivers/char/Makefile | 6 +- drivers/char/ite_gpio.c | 419 ----- drivers/char/qtronixmap.c_shipped | 265 ---- drivers/char/qtronixmap.map | 287 ---- drivers/ide/Kconfig | 9 - drivers/ide/pci/Makefile | 1 - drivers/ide/pci/it8172.c | 307 ---- include/asm-mips/bootinfo.h | 12 - include/asm-mips/it8172/it8172.h | 348 ----- include/asm-mips/it8172/it8172_cir.h | 140 -- include/asm-mips/it8172/it8172_dbg.h | 38 - include/asm-mips/it8172/it8172_int.h | 144 -- include/asm-mips/it8172/it8172_pci.h | 108 -- include/asm-mips/it8712.h | 28 - include/asm-mips/serial.h | 34 - include/linux/ite_gpio.h | 66 - include/linux/pci_ids.h | 2 - sound/oss/Kconfig | 4 - sound/oss/Makefile | 1 - sound/oss/ite8172.c | 2261 --------------------------- 48 files changed, 2 insertions(+), 8726 deletions(-) delete mode 100644 arch/mips/configs/it8172_defconfig delete mode 100644 arch/mips/configs/ivr_defconfig delete mode 100644 arch/mips/ite-boards/Kconfig delete mode 100644 arch/mips/ite-boards/generic/Makefile delete mode 100644 arch/mips/ite-boards/generic/dbg_io.c delete mode 100644 arch/mips/ite-boards/generic/irq.c delete mode 100644 arch/mips/ite-boards/generic/it8172_cir.c delete mode 100644 arch/mips/ite-boards/generic/it8172_setup.c delete mode 100644 arch/mips/ite-boards/generic/lpc.c delete mode 100644 arch/mips/ite-boards/generic/pmon_prom.c delete mode 100644 arch/mips/ite-boards/generic/puts.c delete mode 100644 arch/mips/ite-boards/generic/reset.c delete mode 100644 arch/mips/ite-boards/generic/time.c delete mode 100644 arch/mips/ite-boards/ivr/Makefile delete mode 100644 arch/mips/ite-boards/ivr/README delete mode 100644 arch/mips/ite-boards/ivr/init.c delete mode 100644 arch/mips/ite-boards/qed-4n-s01b/Makefile delete mode 100644 arch/mips/ite-boards/qed-4n-s01b/README delete mode 100644 arch/mips/ite-boards/qed-4n-s01b/init.c delete mode 100644 arch/mips/pci/fixup-ite8172g.c delete mode 100644 arch/mips/pci/fixup-ivr.c delete mode 100644 arch/mips/pci/ops-it8172.c delete mode 100644 drivers/char/ite_gpio.c delete mode 100644 drivers/char/qtronixmap.c_shipped delete mode 100644 drivers/char/qtronixmap.map delete mode 100644 drivers/ide/pci/it8172.c delete mode 100644 include/asm-mips/it8172/it8172.h delete mode 100644 include/asm-mips/it8172/it8172_cir.h delete mode 100644 include/asm-mips/it8172/it8172_dbg.h delete mode 100644 include/asm-mips/it8172/it8172_int.h delete mode 100644 include/asm-mips/it8172/it8172_pci.h delete mode 100644 include/asm-mips/it8712.h delete mode 100644 include/linux/ite_gpio.h delete mode 100644 sound/oss/ite8172.c (limited to 'include/linux') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 68d2ee743ba4..2e410f5aa750 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -211,16 +211,6 @@ Who: Nick Piggin --------------------------- -What: Support for the IT8172-based platforms, ITE 8172G and Globespan IVR -When: September 2006 -Why: Code does no longer build since at least 2.6.0, apparently there is - no user base left for these platforms. Hardware out of production - since several years and hardly a trace of the manufacturer left on - the net. -Who: Ralf Baechle - ---------------------------- - What: Interrupt only SA_* flags When: Januar 2007 Why: The interrupt related SA_* flags are replaced by IRQF_* to move them diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 87cee341eb54..9fe90507e6c7 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -203,39 +203,6 @@ config MIPS_EV64120 . Say Y here if you wish to build a kernel for this platform. -config MIPS_IVR - bool "Globespan IVR board" - select DMA_NONCOHERENT - select HW_HAS_PCI - select ITE_BOARD_GEN - select SYS_HAS_CPU_NEVADA - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL - select SYS_SUPPORTS_LITTLE_ENDIAN - help - This is an evaluation board built by Globespan to showcase thir - iVR (Internet Video Recorder) design. It utilizes a QED RM5231 - R5000 MIPS core. More information can be found out their website - located at . Say Y here if you wish to - build a kernel for this platform. - -config MIPS_ITE8172 - bool "ITE 8172G board" - select DMA_NONCOHERENT - select HW_HAS_PCI - select ITE_BOARD_GEN - select SYS_HAS_CPU_R5432 - select SYS_HAS_CPU_NEVADA - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL - select SYS_SUPPORTS_LITTLE_ENDIAN - help - Ths is an evaluation board made by ITE - with ATX form factor that utilizes a MIPS R5000 to work with its - ITE8172G companion internet appliance chip. The MIPS core can be - either a NEC Vr5432 or QED RM5231. Say Y here if you wish to build - a kernel for this platform. - config MACH_JAZZ bool "Jazz family of machines" select ARC @@ -804,7 +771,6 @@ endchoice source "arch/mips/ddb5xxx/Kconfig" source "arch/mips/gt64120/ev64120/Kconfig" source "arch/mips/jazz/Kconfig" -source "arch/mips/ite-boards/Kconfig" source "arch/mips/lasat/Kconfig" source "arch/mips/momentum/Kconfig" source "arch/mips/pmc-sierra/Kconfig" @@ -964,9 +930,6 @@ config MIPS_RM9122 config PCI_MARVELL bool -config ITE_BOARD_GEN - bool - config SOC_AU1000 bool select SOC_AU1X00 @@ -1050,16 +1013,6 @@ config AU1X00_USB_DEVICE depends on MIPS_PB1500 || MIPS_PB1100 || MIPS_PB1000 default n -config IT8172_CIR - bool - depends on MIPS_ITE8172 || MIPS_IVR - default y - -config IT8712 - bool - depends on MIPS_ITE8172 - default y - config BOOT_ELF32 bool diff --git a/arch/mips/Makefile b/arch/mips/Makefile index e521826b4234..2124350ab94d 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -286,19 +286,6 @@ core-$(CONFIG_WR_PPMC) += arch/mips/gt64120/wrppmc/ cflags-$(CONFIG_WR_PPMC) += -Iinclude/asm-mips/mach-wrppmc load-$(CONFIG_WR_PPMC) += 0xffffffff80100000 -# -# Globespan IVR eval board with QED 5231 CPU -# -core-$(CONFIG_ITE_BOARD_GEN) += arch/mips/ite-boards/generic/ -core-$(CONFIG_MIPS_IVR) += arch/mips/ite-boards/ivr/ -load-$(CONFIG_MIPS_IVR) += 0xffffffff80100000 - -# -# ITE 8172 eval board with QED 5231 CPU -# -core-$(CONFIG_MIPS_ITE8172) += arch/mips/ite-boards/qed-4n-s01b/ -load-$(CONFIG_MIPS_ITE8172) += 0xffffffff80100000 - # # For all MIPS, Inc. eval boards # diff --git a/arch/mips/configs/it8172_defconfig b/arch/mips/configs/it8172_defconfig deleted file mode 100644 index 18d20fb7d5f0..000000000000 --- a/arch/mips/configs/it8172_defconfig +++ /dev/null @@ -1,964 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:04:11 2006 -# -CONFIG_MIPS=y - -# -# Machine selection -# -# CONFIG_MIPS_MTX1 is not set -# CONFIG_MIPS_BOSPORUS is not set -# CONFIG_MIPS_PB1000 is not set -# CONFIG_MIPS_PB1100 is not set -# CONFIG_MIPS_PB1500 is not set -# CONFIG_MIPS_PB1550 is not set -# CONFIG_MIPS_PB1200 is not set -# CONFIG_MIPS_DB1000 is not set -# CONFIG_MIPS_DB1100 is not set -# CONFIG_MIPS_DB1500 is not set -# CONFIG_MIPS_DB1550 is not set -# CONFIG_MIPS_DB1200 is not set -# CONFIG_MIPS_MIRAGE is not set -# CONFIG_BASLER_EXCITE is not set -# CONFIG_MIPS_COBALT is not set -# CONFIG_MACH_DECSTATION is not set -# CONFIG_MIPS_EV64120 is not set -# CONFIG_MIPS_IVR is not set -CONFIG_MIPS_ITE8172=y -# CONFIG_MACH_JAZZ is not set -# CONFIG_LASAT is not set -# CONFIG_MIPS_ATLAS is not set -# CONFIG_MIPS_MALTA is not set -# CONFIG_MIPS_SEAD is not set -# CONFIG_WR_PPMC is not set -# CONFIG_MIPS_SIM is not set -# CONFIG_MOMENCO_JAGUAR_ATX is not set -# CONFIG_MOMENCO_OCELOT is not set -# CONFIG_MOMENCO_OCELOT_3 is not set -# CONFIG_MOMENCO_OCELOT_C is not set -# CONFIG_MOMENCO_OCELOT_G is not set -# CONFIG_MIPS_XXS1500 is not set -# CONFIG_PNX8550_V2PCI is not set -# CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5477 is not set -# CONFIG_MACH_VR41XX is not set -# CONFIG_PMC_YOSEMITE is not set -# CONFIG_QEMU is not set -# CONFIG_MARKEINS is not set -# CONFIG_SGI_IP22 is not set -# CONFIG_SGI_IP27 is not set -# CONFIG_SGI_IP32 is not set -# CONFIG_SIBYTE_BIGSUR is not set -# CONFIG_SIBYTE_SWARM is not set -# CONFIG_SIBYTE_SENTOSA is not set -# CONFIG_SIBYTE_RHONE is not set -# CONFIG_SIBYTE_CARMEL is not set -# CONFIG_SIBYTE_PTSWARM is not set -# CONFIG_SIBYTE_LITTLESUR is not set -# CONFIG_SIBYTE_CRHINE is not set -# CONFIG_SIBYTE_CRHONE is not set -# CONFIG_SNI_RM200_PCI is not set -# CONFIG_TOSHIBA_JMR3927 is not set -# CONFIG_TOSHIBA_RBTX4927 is not set -# CONFIG_TOSHIBA_RBTX4938 is not set -# CONFIG_IT8172_REVC is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_GENERIC_FIND_NEXT_BIT=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -CONFIG_DMA_NONCOHERENT=y -CONFIG_DMA_NEED_PCI_MAP_STATE=y -# CONFIG_CPU_BIG_ENDIAN is not set -CONFIG_CPU_LITTLE_ENDIAN=y -CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -CONFIG_ITE_BOARD_GEN=y -CONFIG_IT8172_CIR=y -CONFIG_IT8712=y -CONFIG_MIPS_L1_CACHE_SHIFT=5 - -# -# CPU selection -# -# CONFIG_CPU_MIPS32_R1 is not set -# CONFIG_CPU_MIPS32_R2 is not set -# CONFIG_CPU_MIPS64_R1 is not set -# CONFIG_CPU_MIPS64_R2 is not set -# CONFIG_CPU_R3000 is not set -# CONFIG_CPU_TX39XX is not set -# CONFIG_CPU_VR41XX is not set -# CONFIG_CPU_R4300 is not set -# CONFIG_CPU_R4X00 is not set -# CONFIG_CPU_TX49XX is not set -# CONFIG_CPU_R5000 is not set -# CONFIG_CPU_R5432 is not set -# CONFIG_CPU_R6000 is not set -CONFIG_CPU_NEVADA=y -# CONFIG_CPU_R8000 is not set -# CONFIG_CPU_R10000 is not set -# CONFIG_CPU_RM7000 is not set -# CONFIG_CPU_RM9000 is not set -# CONFIG_CPU_SB1 is not set -CONFIG_SYS_HAS_CPU_R5432=y -CONFIG_SYS_HAS_CPU_NEVADA=y -CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y - -# -# Kernel type -# -CONFIG_32BIT=y -# CONFIG_64BIT is not set -CONFIG_PAGE_SIZE_4KB=y -# CONFIG_PAGE_SIZE_8KB is not set -# CONFIG_PAGE_SIZE_16KB is not set -# CONFIG_PAGE_SIZE_64KB is not set -CONFIG_MIPS_MT_DISABLED=y -# CONFIG_MIPS_MT_SMTC is not set -# CONFIG_MIPS_MT_SMP is not set -# CONFIG_MIPS_VPE_LOADER is not set -CONFIG_CPU_HAS_LLSC=y -CONFIG_CPU_HAS_SYNC=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_ARCH_FLATMEM_ENABLE=y -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -# CONFIG_SPARSEMEM_STATIC is not set -CONFIG_SPLIT_PTLOCK_CPUS=4 -# CONFIG_RESOURCES_64BIT is not set -# CONFIG_HZ_48 is not set -# CONFIG_HZ_100 is not set -# CONFIG_HZ_128 is not set -# CONFIG_HZ_250 is not set -# CONFIG_HZ_256 is not set -CONFIG_HZ_1000=y -# CONFIG_HZ_1024 is not set -CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -CONFIG_HZ=1000 -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -CONFIG_LOCKDEP_SUPPORT=y -CONFIG_STACKTRACE_SUPPORT=y -CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# -CONFIG_LOCALVERSION="" -CONFIG_LOCALVERSION_AUTO=y -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -# CONFIG_POSIX_MQUEUE is not set -CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set -CONFIG_RELAY=y -CONFIG_INITRAMFS_SOURCE="" -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_EXTRA_PASS is not set -# CONFIG_HOTPLUG is not set -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -CONFIG_BASE_FULL=y -CONFIG_RT_MUTEXES=y -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_SHMEM=y -CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_MODVERSIONS=y -CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_KMOD=y - -# -# Block layer -# -# CONFIG_LBD is not set -# CONFIG_BLK_DEV_IO_TRACE is not set -# CONFIG_LSF is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_DEFAULT_AS=y -# CONFIG_DEFAULT_DEADLINE is not set -# CONFIG_DEFAULT_CFQ is not set -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="anticipatory" - -# -# Bus options (PCI, PCMCIA, EISA, ISA, TC) -# -CONFIG_HW_HAS_PCI=y -# CONFIG_PCI is not set -CONFIG_MMU=y - -# -# PCCARD (PCMCIA/CardBus) support -# -# CONFIG_PCCARD is not set - -# -# PCI Hotplug Support -# - -# -# Executable file formats -# -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -CONFIG_TRAD_SIGNALS=y - -# -# Networking -# -CONFIG_NET=y - -# -# Networking options -# -# CONFIG_NETDEBUG is not set -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -CONFIG_XFRM=y -CONFIG_XFRM_USER=m -CONFIG_NET_KEY=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_FIB_HASH=y -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_XFRM_TUNNEL is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_INET_XFRM_MODE_TRANSPORT=m -CONFIG_INET_XFRM_MODE_TUNNEL=m -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y -# CONFIG_IPV6 is not set -# CONFIG_INET6_XFRM_TUNNEL is not set -# CONFIG_INET6_TUNNEL is not set -CONFIG_NETWORK_SECMARK=y -# CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# -# CONFIG_TIPC is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -CONFIG_IEEE80211=m -# CONFIG_IEEE80211_DEBUG is not set -CONFIG_IEEE80211_CRYPT_WEP=m -CONFIG_IEEE80211_CRYPT_CCMP=m -CONFIG_IEEE80211_SOFTMAC=m -# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set -CONFIG_WIRELESS_EXT=y - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set -# CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# -CONFIG_CONNECTOR=m - -# -# Memory Technology Devices (MTD) -# -CONFIG_MTD=y -# CONFIG_MTD_DEBUG is not set -# CONFIG_MTD_CONCAT is not set -# CONFIG_MTD_PARTITIONS is not set - -# -# User Modules And Translation Layers -# -CONFIG_MTD_CHAR=y -# CONFIG_MTD_BLOCK is not set -# CONFIG_MTD_BLOCK_RO is not set -# CONFIG_FTL is not set -# CONFIG_NFTL is not set -# CONFIG_INFTL is not set -# CONFIG_RFD_FTL is not set - -# -# RAM/ROM/Flash chip drivers -# -CONFIG_MTD_CFI=y -# CONFIG_MTD_JEDECPROBE is not set -CONFIG_MTD_GEN_PROBE=y -# CONFIG_MTD_CFI_ADV_OPTIONS is not set -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y -CONFIG_MTD_MAP_BANK_WIDTH_4=y -# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=y -# CONFIG_MTD_CFI_I4 is not set -# CONFIG_MTD_CFI_I8 is not set -CONFIG_MTD_CFI_INTELEXT=y -# CONFIG_MTD_CFI_AMDSTD is not set -# CONFIG_MTD_CFI_STAA is not set -CONFIG_MTD_CFI_UTIL=y -# CONFIG_MTD_RAM is not set -# CONFIG_MTD_ROM is not set -# CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set - -# -# Mapping drivers for chip access -# -# CONFIG_MTD_COMPLEX_MAPPINGS is not set -CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_PHYSMAP_START=0x8000000 -CONFIG_MTD_PHYSMAP_LEN=0x2000000 -CONFIG_MTD_PHYSMAP_BANKWIDTH=2 -# CONFIG_MTD_PLATRAM is not set - -# -# Self-contained MTD device drivers -# -# CONFIG_MTD_SLRAM is not set -# CONFIG_MTD_PHRAM is not set -# CONFIG_MTD_MTDRAM is not set -# CONFIG_MTD_BLOCK2MTD is not set - -# -# Disk-On-Chip Device Drivers -# -# CONFIG_MTD_DOC2000 is not set -# CONFIG_MTD_DOC2001 is not set -# CONFIG_MTD_DOC2001PLUS is not set - -# -# NAND Flash Device Drivers -# -# CONFIG_MTD_NAND is not set - -# -# OneNAND Flash Device Drivers -# -# CONFIG_MTD_ONENAND is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Plug and Play support -# - -# -# Block devices -# -# CONFIG_BLK_DEV_COW_COMMON is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set -CONFIG_CDROM_PKTCDVD=m -CONFIG_CDROM_PKTCDVD_BUFFERS=8 -# CONFIG_CDROM_PKTCDVD_WCACHE is not set -CONFIG_ATA_OVER_ETH=m - -# -# ATA/ATAPI/MFM/RLL support -# -CONFIG_IDE=y -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_IDE_SATA is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_IDE_TASK_IOCTL is not set - -# -# IDE chipset support/bugfixes -# -CONFIG_IDE_GENERIC=y -# CONFIG_IDE_ARM is not set -# CONFIG_BLK_DEV_IDEDMA is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_BLK_DEV_HD is not set - -# -# SCSI device support -# -CONFIG_RAID_ATTRS=m -# CONFIG_SCSI is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set - -# -# PHY device support -# -CONFIG_PHYLIB=m - -# -# MII PHY device drivers -# -CONFIG_MARVELL_PHY=m -CONFIG_DAVICOM_PHY=m -CONFIG_QSEMI_PHY=m -CONFIG_LXT_PHY=m -CONFIG_CICADA_PHY=m -CONFIG_VITESSE_PHY=m -CONFIG_SMSC_PHY=m - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_MII is not set -# CONFIG_DM9000 is not set - -# -# Ethernet (1000 Mbit) -# - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Telephony Support -# -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_LIBPS2 is not set -CONFIG_SERIO_RAW=m -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -CONFIG_VT_HW_CONSOLE_BINDING=y -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_QTRONIX_KEYBOARD is not set -# CONFIG_IT8172_SCR0 is not set -# CONFIG_IT8172_SCR1 is not set -# CONFIG_ITE_GPIO is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=4 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# -# CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# SPI support -# -# CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# -# CONFIG_W1 is not set - -# -# Hardware Monitoring support -# -# CONFIG_HWMON is not set -# CONFIG_HWMON_VID is not set - -# -# Misc devices -# - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# Graphics support -# -# CONFIG_FIRMWARE_EDID is not set -# CONFIG_FB is not set - -# -# Console display driver support -# -# CONFIG_VGA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y - -# -# Sound -# -CONFIG_SOUND=y - -# -# Advanced Linux Sound Architecture -# -# CONFIG_SND is not set - -# -# Open Sound System -# -CONFIG_SOUND_PRIME=y -CONFIG_SOUND_IT8172=y -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set - -# -# USB support -# -# CONFIG_USB_ARCH_HAS_HCD is not set -# CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USB_ARCH_HAS_EHCI is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_MMC is not set - -# -# LED devices -# -# CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# -# Real Time Clock -# -# CONFIG_RTC_CLASS is not set - -# -# DMA Engine support -# -# CONFIG_DMA_ENGINE is not set - -# -# DMA Clients -# - -# -# DMA Devices -# - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT2_FS_XIP is not set -# CONFIG_EXT3_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set -# CONFIG_XFS_FS is not set -# CONFIG_OCFS2_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_INOTIFY=y -CONFIG_INOTIFY_USER=y -# CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -CONFIG_FUSE_FS=m - -# -# CD-ROM/DVD Filesystems -# -# CONFIG_ISO9660_FS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_SYSFS=y -# CONFIG_TMPFS is not set -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y -# CONFIG_CONFIGFS_FS is not set - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set -# CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set -CONFIG_ROOT_NFS=y -CONFIG_LOCKD=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y -# CONFIG_RPCSEC_GSS_KRB5 is not set -# CONFIG_RPCSEC_GSS_SPKM3 is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_CIFS_DEBUG2 is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# -# CONFIG_NLS is not set - -# -# Profiling support -# -# CONFIG_PROFILING is not set - -# -# Kernel hacking -# -CONFIG_TRACE_IRQFLAGS_SUPPORT=y -# CONFIG_PRINTK_TIME is not set -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_DEBUG_FS is not set -CONFIG_CROSSCOMPILE=y -CONFIG_CMDLINE="" - -# -# Security options -# -CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -CONFIG_CRYPTO=y -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m -CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_SHA256=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_DES=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_AES=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_ARC4=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_DEFLATE=m -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_CRC32C=m -# CONFIG_CRYPTO_TEST is not set - -# -# Hardware crypto devices -# - -# -# Library routines -# -# CONFIG_CRC_CCITT is not set -CONFIG_CRC16=m -CONFIG_CRC32=m -CONFIG_LIBCRC32C=m -CONFIG_ZLIB_INFLATE=m -CONFIG_ZLIB_DEFLATE=m -CONFIG_PLIST=y diff --git a/arch/mips/configs/ivr_defconfig b/arch/mips/configs/ivr_defconfig deleted file mode 100644 index 99831d0bf76b..000000000000 --- a/arch/mips/configs/ivr_defconfig +++ /dev/null @@ -1,920 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:04:12 2006 -# -CONFIG_MIPS=y - -# -# Machine selection -# -# CONFIG_MIPS_MTX1 is not set -# CONFIG_MIPS_BOSPORUS is not set -# CONFIG_MIPS_PB1000 is not set -# CONFIG_MIPS_PB1100 is not set -# CONFIG_MIPS_PB1500 is not set -# CONFIG_MIPS_PB1550 is not set -# CONFIG_MIPS_PB1200 is not set -# CONFIG_MIPS_DB1000 is not set -# CONFIG_MIPS_DB1100 is not set -# CONFIG_MIPS_DB1500 is not set -# CONFIG_MIPS_DB1550 is not set -# CONFIG_MIPS_DB1200 is not set -# CONFIG_MIPS_MIRAGE is not set -# CONFIG_BASLER_EXCITE is not set -# CONFIG_MIPS_COBALT is not set -# CONFIG_MACH_DECSTATION is not set -# CONFIG_MIPS_EV64120 is not set -CONFIG_MIPS_IVR=y -# CONFIG_MIPS_ITE8172 is not set -# CONFIG_MACH_JAZZ is not set -# CONFIG_LASAT is not set -# CONFIG_MIPS_ATLAS is not set -# CONFIG_MIPS_MALTA is not set -# CONFIG_MIPS_SEAD is not set -# CONFIG_WR_PPMC is not set -# CONFIG_MIPS_SIM is not set -# CONFIG_MOMENCO_JAGUAR_ATX is not set -# CONFIG_MOMENCO_OCELOT is not set -# CONFIG_MOMENCO_OCELOT_3 is not set -# CONFIG_MOMENCO_OCELOT_C is not set -# CONFIG_MOMENCO_OCELOT_G is not set -# CONFIG_MIPS_XXS1500 is not set -# CONFIG_PNX8550_V2PCI is not set -# CONFIG_PNX8550_JBS is not set -# CONFIG_DDB5477 is not set -# CONFIG_MACH_VR41XX is not set -# CONFIG_PMC_YOSEMITE is not set -# CONFIG_QEMU is not set -# CONFIG_MARKEINS is not set -# CONFIG_SGI_IP22 is not set -# CONFIG_SGI_IP27 is not set -# CONFIG_SGI_IP32 is not set -# CONFIG_SIBYTE_BIGSUR is not set -# CONFIG_SIBYTE_SWARM is not set -# CONFIG_SIBYTE_SENTOSA is not set -# CONFIG_SIBYTE_RHONE is not set -# CONFIG_SIBYTE_CARMEL is not set -# CONFIG_SIBYTE_PTSWARM is not set -# CONFIG_SIBYTE_LITTLESUR is not set -# CONFIG_SIBYTE_CRHINE is not set -# CONFIG_SIBYTE_CRHONE is not set -# CONFIG_SNI_RM200_PCI is not set -# CONFIG_TOSHIBA_JMR3927 is not set -# CONFIG_TOSHIBA_RBTX4927 is not set -# CONFIG_TOSHIBA_RBTX4938 is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_GENERIC_FIND_NEXT_BIT=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -CONFIG_DMA_NONCOHERENT=y -CONFIG_DMA_NEED_PCI_MAP_STATE=y -# CONFIG_CPU_BIG_ENDIAN is not set -CONFIG_CPU_LITTLE_ENDIAN=y -CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -CONFIG_ITE_BOARD_GEN=y -CONFIG_IT8172_CIR=y -CONFIG_MIPS_L1_CACHE_SHIFT=5 - -# -# CPU selection -# -# CONFIG_CPU_MIPS32_R1 is not set -# CONFIG_CPU_MIPS32_R2 is not set -# CONFIG_CPU_MIPS64_R1 is not set -# CONFIG_CPU_MIPS64_R2 is not set -# CONFIG_CPU_R3000 is not set -# CONFIG_CPU_TX39XX is not set -# CONFIG_CPU_VR41XX is not set -# CONFIG_CPU_R4300 is not set -# CONFIG_CPU_R4X00 is not set -# CONFIG_CPU_TX49XX is not set -# CONFIG_CPU_R5000 is not set -# CONFIG_CPU_R5432 is not set -# CONFIG_CPU_R6000 is not set -CONFIG_CPU_NEVADA=y -# CONFIG_CPU_R8000 is not set -# CONFIG_CPU_R10000 is not set -# CONFIG_CPU_RM7000 is not set -# CONFIG_CPU_RM9000 is not set -# CONFIG_CPU_SB1 is not set -CONFIG_SYS_HAS_CPU_NEVADA=y -CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y - -# -# Kernel type -# -CONFIG_32BIT=y -# CONFIG_64BIT is not set -CONFIG_PAGE_SIZE_4KB=y -# CONFIG_PAGE_SIZE_8KB is not set -# CONFIG_PAGE_SIZE_16KB is not set -# CONFIG_PAGE_SIZE_64KB is not set -CONFIG_MIPS_MT_DISABLED=y -# CONFIG_MIPS_MT_SMTC is not set -# CONFIG_MIPS_MT_SMP is not set -# CONFIG_MIPS_VPE_LOADER is not set -CONFIG_CPU_HAS_LLSC=y -CONFIG_CPU_HAS_SYNC=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_ARCH_FLATMEM_ENABLE=y -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -# CONFIG_SPARSEMEM_STATIC is not set -CONFIG_SPLIT_PTLOCK_CPUS=4 -# CONFIG_RESOURCES_64BIT is not set -# CONFIG_HZ_48 is not set -# CONFIG_HZ_100 is not set -# CONFIG_HZ_128 is not set -# CONFIG_HZ_250 is not set -# CONFIG_HZ_256 is not set -CONFIG_HZ_1000=y -# CONFIG_HZ_1024 is not set -CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -CONFIG_HZ=1000 -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -CONFIG_LOCKDEP_SUPPORT=y -CONFIG_STACKTRACE_SUPPORT=y -CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# -CONFIG_LOCALVERSION="" -CONFIG_LOCALVERSION_AUTO=y -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -# CONFIG_POSIX_MQUEUE is not set -CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set -CONFIG_RELAY=y -CONFIG_INITRAMFS_SOURCE="" -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_EXTRA_PASS is not set -CONFIG_HOTPLUG=y -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -CONFIG_BASE_FULL=y -CONFIG_RT_MUTEXES=y -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_SHMEM=y -CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_MODVERSIONS=y -CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_KMOD=y - -# -# Block layer -# -# CONFIG_LBD is not set -# CONFIG_BLK_DEV_IO_TRACE is not set -# CONFIG_LSF is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_DEFAULT_AS=y -# CONFIG_DEFAULT_DEADLINE is not set -# CONFIG_DEFAULT_CFQ is not set -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="anticipatory" - -# -# Bus options (PCI, PCMCIA, EISA, ISA, TC) -# -CONFIG_HW_HAS_PCI=y -CONFIG_PCI=y -CONFIG_MMU=y - -# -# PCCARD (PCMCIA/CardBus) support -# -# CONFIG_PCCARD is not set - -# -# PCI Hotplug Support -# -# CONFIG_HOTPLUG_PCI is not set - -# -# Executable file formats -# -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -CONFIG_TRAD_SIGNALS=y - -# -# Networking -# -CONFIG_NET=y - -# -# Networking options -# -# CONFIG_NETDEBUG is not set -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -CONFIG_XFRM=y -CONFIG_XFRM_USER=m -CONFIG_NET_KEY=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_FIB_HASH=y -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_XFRM_TUNNEL is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_INET_XFRM_MODE_TRANSPORT=m -CONFIG_INET_XFRM_MODE_TUNNEL=m -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y -# CONFIG_IPV6 is not set -# CONFIG_INET6_XFRM_TUNNEL is not set -# CONFIG_INET6_TUNNEL is not set -CONFIG_NETWORK_SECMARK=y -# CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# -# CONFIG_TIPC is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -CONFIG_IEEE80211=m -# CONFIG_IEEE80211_DEBUG is not set -CONFIG_IEEE80211_CRYPT_WEP=m -CONFIG_IEEE80211_CRYPT_CCMP=m -CONFIG_IEEE80211_SOFTMAC=m -# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set -CONFIG_WIRELESS_EXT=y - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -CONFIG_FW_LOADER=m -# CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# -CONFIG_CONNECTOR=m - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Plug and Play support -# - -# -# Block devices -# -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_UMEM is not set -# CONFIG_BLK_DEV_COW_COMMON is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_SX8 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set -CONFIG_CDROM_PKTCDVD=m -CONFIG_CDROM_PKTCDVD_BUFFERS=8 -# CONFIG_CDROM_PKTCDVD_WCACHE is not set -CONFIG_ATA_OVER_ETH=m - -# -# ATA/ATAPI/MFM/RLL support -# -CONFIG_IDE=y -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_IDE_SATA is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_IDE_TASK_IOCTL is not set - -# -# IDE chipset support/bugfixes -# -CONFIG_IDE_GENERIC=y -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_ARM is not set -# CONFIG_BLK_DEV_IDEDMA is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_BLK_DEV_HD is not set - -# -# SCSI device support -# -CONFIG_RAID_ATTRS=m -# CONFIG_SCSI is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# -# CONFIG_IEEE1394 is not set - -# -# I2O device support -# -# CONFIG_I2O is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set - -# -# PHY device support -# -CONFIG_PHYLIB=m - -# -# MII PHY device drivers -# -CONFIG_MARVELL_PHY=m -CONFIG_DAVICOM_PHY=m -CONFIG_QSEMI_PHY=m -CONFIG_LXT_PHY=m -CONFIG_CICADA_PHY=m -CONFIG_VITESSE_PHY=m -CONFIG_SMSC_PHY=m - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_MII is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNGEM is not set -# CONFIG_CASSINI is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_DM9000 is not set - -# -# Tulip family network device support -# -# CONFIG_NET_TULIP is not set -# CONFIG_HP100 is not set -# CONFIG_NET_PCI is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_E1000 is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_R8169 is not set -# CONFIG_SIS190 is not set -# CONFIG_SKGE is not set -# CONFIG_SKY2 is not set -# CONFIG_SK98LIN is not set -# CONFIG_TIGON3 is not set -# CONFIG_BNX2 is not set - -# -# Ethernet (10000 Mbit) -# -# CONFIG_CHELSIO_T1 is not set -# CONFIG_IXGB is not set -# CONFIG_S2IO is not set -# CONFIG_MYRI10GE is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Telephony Support -# -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_PCIPS2 is not set -# CONFIG_SERIO_LIBPS2 is not set -CONFIG_SERIO_RAW=m -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -CONFIG_VT_HW_CONSOLE_BINDING=y -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_QTRONIX_KEYBOARD=y -CONFIG_IT8172_SCR0=y -CONFIG_IT8172_SCR1=y - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_NR_UARTS=4 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -# CONFIG_SERIAL_JSM is not set -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_HW_RANDOM is not set -CONFIG_RTC=y -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_DRM is not set -# CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# -# CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# SPI support -# -# CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# -# CONFIG_W1 is not set - -# -# Hardware Monitoring support -# -# CONFIG_HWMON is not set -# CONFIG_HWMON_VID is not set - -# -# Misc devices -# - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# Graphics support -# -# CONFIG_FIRMWARE_EDID is not set -# CONFIG_FB is not set - -# -# Console display driver support -# -# CONFIG_VGA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB_ARCH_HAS_OHCI=y -CONFIG_USB_ARCH_HAS_EHCI=y -# CONFIG_USB is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_MMC is not set - -# -# LED devices -# -# CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# -# CONFIG_INFINIBAND is not set - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# -# Real Time Clock -# -# CONFIG_RTC_CLASS is not set - -# -# DMA Engine support -# -# CONFIG_DMA_ENGINE is not set - -# -# DMA Clients -# - -# -# DMA Devices -# - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT2_FS_XIP is not set -# CONFIG_EXT3_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set -# CONFIG_XFS_FS is not set -# CONFIG_OCFS2_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_INOTIFY=y -CONFIG_INOTIFY_USER=y -# CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -CONFIG_FUSE_FS=m - -# -# CD-ROM/DVD Filesystems -# -# CONFIG_ISO9660_FS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_SYSFS=y -# CONFIG_TMPFS is not set -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y -# CONFIG_CONFIGFS_FS is not set - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set -# CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set -CONFIG_ROOT_NFS=y -CONFIG_LOCKD=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y -# CONFIG_RPCSEC_GSS_KRB5 is not set -# CONFIG_RPCSEC_GSS_SPKM3 is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_CIFS_DEBUG2 is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# -# CONFIG_NLS is not set - -# -# Profiling support -# -# CONFIG_PROFILING is not set - -# -# Kernel hacking -# -CONFIG_TRACE_IRQFLAGS_SUPPORT=y -# CONFIG_PRINTK_TIME is not set -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_DEBUG_FS is not set -CONFIG_CROSSCOMPILE=y -CONFIG_CMDLINE="" - -# -# Security options -# -CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -CONFIG_CRYPTO=y -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m -CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_SHA256=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_DES=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_AES=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_ARC4=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_DEFLATE=m -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_CRC32C=m -# CONFIG_CRYPTO_TEST is not set - -# -# Hardware crypto devices -# - -# -# Library routines -# -# CONFIG_CRC_CCITT is not set -CONFIG_CRC16=m -CONFIG_CRC32=m -CONFIG_LIBCRC32C=m -CONFIG_ZLIB_INFLATE=m -CONFIG_ZLIB_DEFLATE=m -CONFIG_PLIST=y diff --git a/arch/mips/ite-boards/Kconfig b/arch/mips/ite-boards/Kconfig deleted file mode 100644 index a6d59ad8f846..000000000000 --- a/arch/mips/ite-boards/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config IT8172_REVC - bool "Support for older IT8172 (Rev C)" - depends on MIPS_ITE8172 - help - Say Y here to support the older, Revision C version of the Integrated - Technology Express, Inc. ITE8172 SBC. Vendor page at - ; picture of the - board at . diff --git a/arch/mips/ite-boards/generic/Makefile b/arch/mips/ite-boards/generic/Makefile deleted file mode 100644 index 63431538d0ec..000000000000 --- a/arch/mips/ite-boards/generic/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Copyright 2000 MontaVista Software Inc. -# Author: MontaVista Software, Inc. -# ppopov@mvista.com or source@mvista.com -# -# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files. -# - -obj-y += it8172_setup.o irq.o pmon_prom.o \ - time.o lpc.o puts.o reset.o - -obj-$(CONFIG_IT8172_CIR)+= it8172_cir.o -obj-$(CONFIG_KGDB) += dbg_io.o - -EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/ite-boards/generic/dbg_io.c b/arch/mips/ite-boards/generic/dbg_io.c deleted file mode 100644 index 8e9cd8a9670a..000000000000 --- a/arch/mips/ite-boards/generic/dbg_io.c +++ /dev/null @@ -1,124 +0,0 @@ - - -#ifdef CONFIG_KGDB - -/* --- CONFIG --- */ - -/* we need uint32 uint8 */ -/* #include "types.h" */ -typedef unsigned char uint8; -typedef unsigned int uint32; - -/* --- END OF CONFIG --- */ - -#define UART16550_BAUD_2400 2400 -#define UART16550_BAUD_4800 4800 -#define UART16550_BAUD_9600 9600 -#define UART16550_BAUD_19200 19200 -#define UART16550_BAUD_38400 38400 -#define UART16550_BAUD_57600 57600 -#define UART16550_BAUD_115200 115200 - -#define UART16550_PARITY_NONE 0 -#define UART16550_PARITY_ODD 0x08 -#define UART16550_PARITY_EVEN 0x18 -#define UART16550_PARITY_MARK 0x28 -#define UART16550_PARITY_SPACE 0x38 - -#define UART16550_DATA_5BIT 0x0 -#define UART16550_DATA_6BIT 0x1 -#define UART16550_DATA_7BIT 0x2 -#define UART16550_DATA_8BIT 0x3 - -#define UART16550_STOP_1BIT 0x0 -#define UART16550_STOP_2BIT 0x4 - -/* ----------------------------------------------------- */ - -/* === CONFIG === */ - -/* [stevel] we use the IT8712 serial port for kgdb */ -#define DEBUG_BASE 0xB40003F8 /* 8712 serial port 1 base address */ -#define MAX_BAUD 115200 - -/* === END OF CONFIG === */ - -/* register offset */ -#define OFS_RCV_BUFFER 0 -#define OFS_TRANS_HOLD 0 -#define OFS_SEND_BUFFER 0 -#define OFS_INTR_ENABLE 1 -#define OFS_INTR_ID 2 -#define OFS_DATA_FORMAT 3 -#define OFS_LINE_CONTROL 3 -#define OFS_MODEM_CONTROL 4 -#define OFS_RS232_OUTPUT 4 -#define OFS_LINE_STATUS 5 -#define OFS_MODEM_STATUS 6 -#define OFS_RS232_INPUT 6 -#define OFS_SCRATCH_PAD 7 - -#define OFS_DIVISOR_LSB 0 -#define OFS_DIVISOR_MSB 1 - - -/* memory-mapped read/write of the port */ -#define UART16550_READ(y) (*((volatile uint8*)(DEBUG_BASE + y))) -#define UART16550_WRITE(y,z) ((*((volatile uint8*)(DEBUG_BASE + y))) = z) - -void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) -{ - /* disable interrupts */ - UART16550_WRITE(OFS_INTR_ENABLE, 0); - - /* set up baud rate */ - { - uint32 divisor; - - /* set DIAB bit */ - UART16550_WRITE(OFS_LINE_CONTROL, 0x80); - - /* set divisor */ - divisor = MAX_BAUD / baud; - UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); - UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8); - - /* clear DIAB bit */ - UART16550_WRITE(OFS_LINE_CONTROL, 0x0); - } - - /* set data format */ - UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); -} - -static int remoteDebugInitialized = 0; - -uint8 getDebugChar(void) -{ - if (!remoteDebugInitialized) { - remoteDebugInitialized = 1; - debugInit(UART16550_BAUD_115200, - UART16550_DATA_8BIT, - UART16550_PARITY_NONE, UART16550_STOP_1BIT); - } - - while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); - return UART16550_READ(OFS_RCV_BUFFER); -} - - -int putDebugChar(uint8 byte) -{ - if (!remoteDebugInitialized) { - remoteDebugInitialized = 1; - debugInit(UART16550_BAUD_115200, - UART16550_DATA_8BIT, - UART16550_PARITY_NONE, UART16550_STOP_1BIT); - } - - while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0); - UART16550_WRITE(OFS_SEND_BUFFER, byte); - return 1; -} - -#endif diff --git a/arch/mips/ite-boards/generic/irq.c b/arch/mips/ite-boards/generic/irq.c deleted file mode 100644 index cb59ca4f76f0..000000000000 --- a/arch/mips/ite-boards/generic/irq.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * ITE 8172G interrupt/setup routines. - * - * Copyright 2000,2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * Part of this file was derived from Carsten Langgaard's - * arch/mips/mips-boards/atlas/atlas_int.c. - * - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* revisit */ -#define EXT_IRQ0_TO_IP 2 /* IP 2 */ -#define EXT_IRQ5_TO_IP 7 /* IP 7 */ - -#define ALLINTS_NOTIMER (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4) - -extern void set_debug_traps(void); -extern void mips_timer_interrupt(int irq, struct pt_regs *regs); - -struct it8172_intc_regs volatile *it8172_hw0_icregs = - (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE)); - -static void disable_it8172_irq(unsigned int irq_nr) -{ - if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) { - /* LPC interrupt */ - it8172_hw0_icregs->lpc_mask |= - (1 << (irq_nr - IT8172_LPC_IRQ_BASE)); - } else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) { - /* Local Bus interrupt */ - it8172_hw0_icregs->lb_mask |= - (1 << (irq_nr - IT8172_LB_IRQ_BASE)); - } else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) { - /* PCI and other interrupts */ - it8172_hw0_icregs->pci_mask |= - (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); - } else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) { - /* NMI interrupts */ - it8172_hw0_icregs->nmi_mask |= - (1 << (irq_nr - IT8172_NMI_IRQ_BASE)); - } else { - panic("disable_it8172_irq: bad irq %d", irq_nr); - } -} - -static void enable_it8172_irq(unsigned int irq_nr) -{ - if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) { - /* LPC interrupt */ - it8172_hw0_icregs->lpc_mask &= - ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE)); - } - else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) { - /* Local Bus interrupt */ - it8172_hw0_icregs->lb_mask &= - ~(1 << (irq_nr - IT8172_LB_IRQ_BASE)); - } - else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) { - /* PCI and other interrupts */ - it8172_hw0_icregs->pci_mask &= - ~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); - } - else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) { - /* NMI interrupts */ - it8172_hw0_icregs->nmi_mask &= - ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE)); - } - else { - panic("enable_it8172_irq: bad irq %d", irq_nr); - } -} - -static unsigned int startup_ite_irq(unsigned int irq) -{ - enable_it8172_irq(irq); - return 0; -} - -#define shutdown_ite_irq disable_it8172_irq -#define mask_and_ack_ite_irq disable_it8172_irq - -static void end_ite_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_it8172_irq(irq); -} - -static struct irq_chip it8172_irq_type = { - .typename = "ITE8172", - .startup = startup_ite_irq, - .shutdown = shutdown_ite_irq, - .enable = enable_it8172_irq, - .disable = disable_it8172_irq, - .ack = mask_and_ack_ite_irq, - .end = end_ite_irq, -}; - - -static void enable_none(unsigned int irq) { } -static unsigned int startup_none(unsigned int irq) { return 0; } -static void disable_none(unsigned int irq) { } -static void ack_none(unsigned int irq) { } - -/* startup is the same as "enable", shutdown is same as "disable" */ -#define shutdown_none disable_none -#define end_none enable_none - -static struct irq_chip cp0_irq_type = { - .typename = "CP0 Count", - .startup = startup_none, - .shutdown = shutdown_none, - .enable = enable_none, - .disable = disable_none, - .ack = ack_none, - .end = end_none -}; - -void enable_cpu_timer(void) -{ - unsigned long flags; - - local_irq_save(flags); - set_c0_status(0x100 << EXT_IRQ5_TO_IP); - local_irq_restore(flags); -} - -void __init arch_init_irq(void) -{ - int i; - unsigned long flags; - - /* mask all interrupts */ - it8172_hw0_icregs->lb_mask = 0xffff; - it8172_hw0_icregs->lpc_mask = 0xffff; - it8172_hw0_icregs->pci_mask = 0xffff; - it8172_hw0_icregs->nmi_mask = 0xffff; - - /* make all interrupts level triggered */ - it8172_hw0_icregs->lb_trigger = 0; - it8172_hw0_icregs->lpc_trigger = 0; - it8172_hw0_icregs->pci_trigger = 0; - it8172_hw0_icregs->nmi_trigger = 0; - - /* active level setting */ - /* uart, keyboard, and mouse are active high */ - it8172_hw0_icregs->lpc_level = (0x10 | 0x2 | 0x1000); - it8172_hw0_icregs->lb_level |= 0x20; - - /* keyboard and mouse are edge triggered */ - it8172_hw0_icregs->lpc_trigger |= (0x2 | 0x1000); - - -#if 0 - // Enable this piece of code to make internal USB interrupt - // edge triggered. - it8172_hw0_icregs->pci_trigger |= - (1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE)); - it8172_hw0_icregs->pci_level &= - ~(1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE)); -#endif - - for (i = 0; i <= IT8172_LAST_IRQ; i++) { - irq_desc[i].chip = &it8172_irq_type; - spin_lock_init(&irq_desc[i].lock); - } - irq_desc[MIPS_CPU_TIMER_IRQ].chip = &cp0_irq_type; - set_c0_status(ALLINTS_NOTIMER); -} - -void mips_spurious_interrupt(struct pt_regs *regs) -{ -#if 1 - return; -#else - unsigned long status, cause; - - printk("got spurious interrupt\n"); - status = read_c0_status(); - cause = read_c0_cause(); - printk("status %x cause %x\n", status, cause); - printk("epc %x badvaddr %x \n", regs->cp0_epc, regs->cp0_badvaddr); -#endif -} - -void it8172_hw0_irqdispatch(struct pt_regs *regs) -{ - int irq; - unsigned short intstatus = 0, status = 0; - - intstatus = it8172_hw0_icregs->intstatus; - if (intstatus & 0x8) { - panic("Got NMI interrupt"); - } else if (intstatus & 0x4) { - /* PCI interrupt */ - irq = 0; - status |= it8172_hw0_icregs->pci_req; - while (!(status & 0x1)) { - irq++; - status >>= 1; - } - irq += IT8172_PCI_DEV_IRQ_BASE; - } else if (intstatus & 0x1) { - /* Local Bus interrupt */ - irq = 0; - status |= it8172_hw0_icregs->lb_req; - while (!(status & 0x1)) { - irq++; - status >>= 1; - } - irq += IT8172_LB_IRQ_BASE; - } else if (intstatus & 0x2) { - /* LPC interrupt */ - /* Since some lpc interrupts are edge triggered, - * we could lose an interrupt this way because - * we acknowledge all ints at onces. Revisit. - */ - status |= it8172_hw0_icregs->lpc_req; - it8172_hw0_icregs->lpc_req = 0; /* acknowledge ints */ - irq = 0; - while (!(status & 0x1)) { - irq++; - status >>= 1; - } - irq += IT8172_LPC_IRQ_BASE; - } else - return; - - do_IRQ(irq, regs); -} - -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) -{ - unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; - - if (!pending) - mips_spurious_interrupt(regs); - else if (pending & CAUSEF_IP7) - ll_timer_interrupt(127, regs); - else if (pending & CAUSEF_IP2) - it8172_hw0_irqdispatch(regs); -} - -void show_pending_irqs(void) -{ - fputs("intstatus: "); - put32(it8172_hw0_icregs->intstatus); - puts(""); - - fputs("pci_req: "); - put32(it8172_hw0_icregs->pci_req); - puts(""); - - fputs("lb_req: "); - put32(it8172_hw0_icregs->lb_req); - puts(""); - - fputs("lpc_req: "); - put32(it8172_hw0_icregs->lpc_req); - puts(""); -} diff --git a/arch/mips/ite-boards/generic/it8172_cir.c b/arch/mips/ite-boards/generic/it8172_cir.c deleted file mode 100644 index bfc25adcfec6..000000000000 --- a/arch/mips/ite-boards/generic/it8172_cir.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * IT8172 Consumer IR port generic routines. - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#ifdef CONFIG_IT8172_CIR - -#include -#include -#include -#include - -#include -#include - - -volatile struct it8172_cir_regs *cir_regs[NUM_CIR_PORTS] = { - (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR0_BASE)), - (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR1_BASE))}; - - -/* - * Initialize Consumer IR Port. - */ -int cir_port_init(struct cir_port *cir) -{ - int port = cir->port; - unsigned char data; - - /* set baud rate */ - cir_regs[port]->bdlr = cir->baud_rate & 0xff; - cir_regs[port]->bdhr = (cir->baud_rate >> 8) & 0xff; - - /* set receiver control register */ - cir_regs[port]->rcr = (CIR_SET_RDWOS(cir->rdwos) | CIR_SET_RXDCR(cir->rxdcr)); - - /* set carrier frequency register */ - cir_regs[port]->cfr = (CIR_SET_CF(cir->cfq) | CIR_SET_HS(cir->hcfs)); - - /* set fifo threshold */ - data = cir_regs[port]->mstcr & 0xf3; - data |= CIR_SET_FIFO_TL(cir->fifo_tl); - cir_regs[port]->mstcr = data; - - clear_fifo(cir); - enable_receiver(cir); - disable_rx_demodulation(cir); - - set_rx_active(cir); - int_enable(cir); - rx_int_enable(cir); - - return 0; -} - - -void clear_fifo(struct cir_port *cir) -{ - cir_regs[cir->port]->mstcr |= CIR_FIFO_CLEAR; -} - -void enable_receiver(struct cir_port *cir) -{ - cir_regs[cir->port]->rcr |= CIR_RXEN; -} - -void disable_receiver(struct cir_port *cir) -{ - cir_regs[cir->port]->rcr &= ~CIR_RXEN; -} - -void enable_rx_demodulation(struct cir_port *cir) -{ - cir_regs[cir->port]->rcr |= CIR_RXEND; -} - -void disable_rx_demodulation(struct cir_port *cir) -{ - cir_regs[cir->port]->rcr &= ~CIR_RXEND; -} - -void set_rx_active(struct cir_port *cir) -{ - cir_regs[cir->port]->rcr |= CIR_RXACT; -} - -void int_enable(struct cir_port *cir) -{ - cir_regs[cir->port]->ier |= CIR_IEC; -} - -void rx_int_enable(struct cir_port *cir) -{ - cir_regs[cir->port]->ier |= CIR_RDAIE; -} - -void dump_regs(struct cir_port *cir) -{ - printk("mstcr %x ier %x iir %x cfr %x rcr %x tcr %x tfsr %x rfsr %x\n", - cir_regs[cir->port]->mstcr, - cir_regs[cir->port]->ier, - cir_regs[cir->port]->iir, - cir_regs[cir->port]->cfr, - cir_regs[cir->port]->rcr, - cir_regs[cir->port]->tcr, - cir_regs[cir->port]->tfsr, - cir_regs[cir->port]->rfsr); - - while (cir_regs[cir->port]->iir & CIR_RDAI) { - printk("data %x\n", cir_regs[cir->port]->dr); - } -} - -void dump_reg_addr(struct cir_port *cir) -{ - printk("dr %x mstcr %x ier %x iir %x cfr %x rcr %x tcr %x bdlr %x bdhr %x tfsr %x rfsr %x\n", - (unsigned)&cir_regs[cir->port]->dr, - (unsigned)&cir_regs[cir->port]->mstcr, - (unsigned)&cir_regs[cir->port]->ier, - (unsigned)&cir_regs[cir->port]->iir, - (unsigned)&cir_regs[cir->port]->cfr, - (unsigned)&cir_regs[cir->port]->rcr, - (unsigned)&cir_regs[cir->port]->tcr, - (unsigned)&cir_regs[cir->port]->bdlr, - (unsigned)&cir_regs[cir->port]->bdhr, - (unsigned)&cir_regs[cir->port]->tfsr, - (unsigned)&cir_regs[cir->port]->rfsr); -} - -int cir_get_rx_count(struct cir_port *cir) -{ - return cir_regs[cir->port]->rfsr & CIR_RXFBC_MASK; -} - -char cir_read_data(struct cir_port *cir) -{ - return cir_regs[cir->port]->dr; -} - -char get_int_status(struct cir_port *cir) -{ - return cir_regs[cir->port]->iir; -} -#endif diff --git a/arch/mips/ite-boards/generic/it8172_setup.c b/arch/mips/ite-boards/generic/it8172_setup.c deleted file mode 100644 index 07faf3cacff2..000000000000 --- a/arch/mips/ite-boards/generic/it8172_setup.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * IT8172/QED5231 board setup. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct resource ioport_resource; -#ifdef CONFIG_SERIO_I8042 -int init_8712_keyboard(void); -#endif - -extern int SearchIT8712(void); -extern void InitLPCInterface(void); -extern char * __init prom_getcmdline(void); -extern void it8172_restart(char *command); -extern void it8172_halt(void); -extern void it8172_power_off(void); - -extern void it8172_time_init(void); - -#ifdef CONFIG_IT8172_REVC -struct { - struct resource ram; - struct resource pci_mem; - struct resource pci_io; - struct resource flash; - struct resource boot; -} it8172_resources = { - { - .start = 0, /* to be initted */ - .end = 0, - .name = "RAM", - .flags = IORESOURCE_MEM - }, { - .start = 0x10000000, - .end = 0x13FFFFFF, - .name = "PCI Mem", - .flags = IORESOURCE_MEM - }, { - .start = 0x14000000, - .end = 0x17FFFFFF - .name = "PCI I/O", - }, { - .start = 0x08000000, - .end = 0x0CFFFFFF - .name = "Flash", - }, { - .start = 0x1FC00000, - .end = 0x1FFFFFFF - .name = "Boot ROM", - } -}; -#else -struct { - struct resource ram; - struct resource pci_mem0; - struct resource pci_mem1; - struct resource pci_io; - struct resource pci_mem2; - struct resource pci_mem3; - struct resource flash; - struct resource boot; -} it8172_resources = { - { - .start = 0, /* to be initted */ - .end = 0, - .name = "RAM", - .flags = IORESOURCE_MEM - }, { - .start = 0x0C000000, - .end = 0x0FFFFFFF, - .name = "PCI Mem0", - .flags = IORESOURCE_MEM - }, { - .start = 0x10000000, - .end = 0x13FFFFFF, - .name = "PCI Mem1", - .flags = IORESOURCE_MEM - }, { - .start = 0x14000000, - .end = 0x17FFFFFF - .name = "PCI I/O", - }, { - .start = 0x1A000000, - .end = 0x1BFFFFFF, - .name = "PCI Mem2", - .flags = IORESOURCE_MEM - }, { - .start = 0x1C000000, - .end = 0x1FBFFFFF, - .name = "PCI Mem3", - .flags = IORESOURCE_MEM - }, { - .start = 0x08000000, - .end = 0x0CFFFFFF - .name = "Flash", - }, { - .start = 0x1FC00000, - .end = 0x1FFFFFFF - .name = "Boot ROM", - } -}; -#endif - - -void __init it8172_init_ram_resource(unsigned long memsize) -{ - it8172_resources.ram.end = memsize; -} - -void __init plat_mem_setup(void) -{ - unsigned short dsr; - char *argptr; - - argptr = prom_getcmdline(); -#ifdef CONFIG_SERIAL_CONSOLE - if ((argptr = strstr(argptr, "console=")) == NULL) { - argptr = prom_getcmdline(); - strcat(argptr, " console=ttyS0,115200"); - } -#endif - - clear_c0_status(ST0_FR); - - board_time_init = it8172_time_init; - - _machine_restart = it8172_restart; - _machine_halt = it8172_halt; - pm_power_off = it8172_power_off; - - /* - * IO/MEM resources. - * - * revisit this area. - */ - set_io_port_base(KSEG1); - ioport_resource.start = it8172_resources.pci_io.start; - ioport_resource.end = it8172_resources.pci_io.end; -#ifdef CONFIG_IT8172_REVC - iomem_resource.start = it8172_resources.pci_mem.start; - iomem_resource.end = it8172_resources.pci_mem.end; -#else - iomem_resource.start = it8172_resources.pci_mem0.start; - iomem_resource.end = it8172_resources.pci_mem3.end; -#endif - -#ifdef CONFIG_BLK_DEV_INITRD - ROOT_DEV = Root_RAM0; -#endif - - /* - * Pull enabled devices out of standby - */ - IT_IO_READ16(IT_PM_DSR, dsr); - - /* - * Fixme: This breaks when these drivers are modules!!! - */ -#ifdef CONFIG_SOUND_IT8172 - dsr &= ~IT_PM_DSR_ACSB; -#else - dsr |= IT_PM_DSR_ACSB; -#endif -#ifdef CONFIG_BLK_DEV_IT8172 - dsr &= ~IT_PM_DSR_IDESB; -#else - dsr |= IT_PM_DSR_IDESB; -#endif - IT_IO_WRITE16(IT_PM_DSR, dsr); - - InitLPCInterface(); - -#ifdef CONFIG_MIPS_ITE8172 - if (SearchIT8712()) { - printk("Found IT8712 Super IO\n"); - /* enable IT8712 serial port */ - LPCSetConfig(LDN_SERIAL1, 0x30, 0x01); /* enable */ - LPCSetConfig(LDN_SERIAL1, 0x23, 0x01); /* clock selection */ -#ifdef CONFIG_SERIO_I8042 - if (init_8712_keyboard()) { - printk("Unable to initialize keyboard\n"); - LPCSetConfig(LDN_KEYBOARD, 0x30, 0x0); /* disable keyboard */ - } else { - LPCSetConfig(LDN_KEYBOARD, 0x30, 0x1); /* enable keyboard */ - LPCSetConfig(LDN_KEYBOARD, 0xf0, 0x2); - LPCSetConfig(LDN_KEYBOARD, 0x71, 0x3); - - LPCSetConfig(LDN_MOUSE, 0x30, 0x1); /* enable mouse */ - - LPCSetConfig(0x4, 0x30, 0x1); - LPCSetConfig(0x4, 0xf4, LPCGetConfig(0x4, 0xf4) | 0x80); - - if ((LPCGetConfig(LDN_KEYBOARD, 0x30) == 0) || - (LPCGetConfig(LDN_MOUSE, 0x30) == 0)) - printk("Error: keyboard or mouse not enabled\n"); - - } -#endif - } - else { - printk("IT8712 Super IO not found\n"); - } -#endif - -#ifdef CONFIG_IT8172_CIR - { - unsigned long data; - //printk("Enabling CIR0\n"); - IT_IO_READ16(IT_PM_DSR, data); - data &= ~IT_PM_DSR_CIR0SB; - IT_IO_WRITE16(IT_PM_DSR, data); - //printk("DSR register: %x\n", (unsigned)IT_IO_READ16(IT_PM_DSR, data)); - } -#endif -#ifdef CONFIG_IT8172_SCR0 - { - unsigned i; - /* Enable Smart Card Reader 0 */ - /* First power it up */ - IT_IO_READ16(IT_PM_DSR, i); - i &= ~IT_PM_DSR_SCR0SB; - IT_IO_WRITE16(IT_PM_DSR, i); - /* Then initialize its registers */ - outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT - |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT - |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT - |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT - |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT), - IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SFR); - outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT, - IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SCDR); - } -#endif /* CONFIG_IT8172_SCR0 */ -#ifdef CONFIG_IT8172_SCR1 - { - unsigned i; - /* Enable Smart Card Reader 1 */ - /* First power it up */ - IT_IO_READ16(IT_PM_DSR, i); - i &= ~IT_PM_DSR_SCR1SB; - IT_IO_WRITE16(IT_PM_DSR, i); - /* Then initialize its registers */ - outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT - |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT - |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT - |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT - |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT), - IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SFR); - outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT, - IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SCDR); - } -#endif /* CONFIG_IT8172_SCR1 */ -} - -#ifdef CONFIG_SERIO_I8042 -/* - * According to the ITE Special BIOS Note for waking up the - * keyboard controller... - */ -static int init_8712_keyboard(void) -{ - unsigned int cmd_port = 0x14000064; - unsigned int data_port = 0x14000060; - ^^^^^^^^^^^ - Somebody here doesn't grok the concept of io ports. - - unsigned char data; - int i; - - outb(0xaa, cmd_port); /* send self-test cmd */ - i = 0; - while (!(inb(cmd_port) & 0x1)) { /* wait output buffer full */ - i++; - if (i > 0xffffff) - return 1; - } - - data = inb(data_port); - outb(0xcb, cmd_port); /* set ps2 mode */ - while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ - i++; - if (i > 0xffffff) - return 1; - } - outb(0x01, data_port); - while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ - i++; - if (i > 0xffffff) - return 1; - } - - outb(0x60, cmd_port); /* write 8042 command byte */ - while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ - i++; - if (i > 0xffffff) - return 1; - } - outb(0x45, data_port); /* at interface, keyboard enabled, system flag */ - while (inb(cmd_port) & 0x2) { /* wait while input buffer full */ - i++; - if (i > 0xffffff) - return 1; - } - - outb(0xae, cmd_port); /* enable interface */ - return 0; -} -#endif diff --git a/arch/mips/ite-boards/generic/lpc.c b/arch/mips/ite-boards/generic/lpc.c deleted file mode 100644 index cc7584fbef8a..000000000000 --- a/arch/mips/ite-boards/generic/lpc.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * ITE Semi IT8712 Super I/O functions. - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -void LPCEnterMBPnP(void) -{ - int i; - unsigned char key[4] = {0x87, 0x01, 0x55, 0x55}; - - for (i = 0; i<4; i++) - outb(key[i], LPC_KEY_ADDR); - -} - -void LPCExitMBPnP(void) -{ - outb(0x02, LPC_KEY_ADDR); - outb(0x02, LPC_DATA_ADDR); -} - -void LPCSetConfig(char LdnNumber, char Index, char data) -{ - LPCEnterMBPnP(); // Enter IT8712 MB PnP mode - outb(0x07, LPC_KEY_ADDR); - outb(LdnNumber, LPC_DATA_ADDR); - outb(Index, LPC_KEY_ADDR); - outb(data, LPC_DATA_ADDR); - LPCExitMBPnP(); -} - -char LPCGetConfig(char LdnNumber, char Index) -{ - char rtn; - - LPCEnterMBPnP(); // Enter IT8712 MB PnP mode - outb(0x07, LPC_KEY_ADDR); - outb(LdnNumber, LPC_DATA_ADDR); - outb(Index, LPC_KEY_ADDR); - rtn = inb(LPC_DATA_ADDR); - LPCExitMBPnP(); - return rtn; -} - -int SearchIT8712(void) -{ - unsigned char Id1, Id2; - unsigned short Id; - - LPCEnterMBPnP(); - outb(0x20, LPC_KEY_ADDR); /* chip id byte 1 */ - Id1 = inb(LPC_DATA_ADDR); - outb(0x21, LPC_KEY_ADDR); /* chip id byte 2 */ - Id2 = inb(LPC_DATA_ADDR); - Id = (Id1 << 8) | Id2; - LPCExitMBPnP(); - if (Id == 0x8712) - return TRUE; - else - return FALSE; -} - -void InitLPCInterface(void) -{ - unsigned char bus, dev_fn; - unsigned long data; - - bus = 0; - dev_fn = 1<<3 | 4; - - - /* pci cmd, SERR# Enable */ - IT_WRITE(IT_CONFADDR, - (bus << IT_BUSNUM_SHF) | - (dev_fn << IT_FUNCNUM_SHF) | - ((0x4 / 4) << IT_REGNUM_SHF)); - IT_READ(IT_CONFDATA, data); - data |= 0x0100; - IT_WRITE(IT_CONFADDR, - (bus << IT_BUSNUM_SHF) | - (dev_fn << IT_FUNCNUM_SHF) | - ((0x4 / 4) << IT_REGNUM_SHF)); - IT_WRITE(IT_CONFDATA, data); - - /* setup serial irq control register */ - IT_WRITE(IT_CONFADDR, - (bus << IT_BUSNUM_SHF) | - (dev_fn << IT_FUNCNUM_SHF) | - ((0x48 / 4) << IT_REGNUM_SHF)); - IT_READ(IT_CONFDATA, data); - data = (data & 0xffff00ff) | 0xc400; - IT_WRITE(IT_CONFADDR, - (bus << IT_BUSNUM_SHF) | - (dev_fn << IT_FUNCNUM_SHF) | - ((0x48 / 4) << IT_REGNUM_SHF)); - IT_WRITE(IT_CONFDATA, data); - - - /* Enable I/O Space Subtractive Decode */ - /* default 0x4C is 0x3f220000 */ - IT_WRITE(IT_CONFADDR, - (bus << IT_BUSNUM_SHF) | - (dev_fn << IT_FUNCNUM_SHF) | - ((0x4C / 4) << IT_REGNUM_SHF)); - IT_WRITE(IT_CONFDATA, 0x3f2200f3); -} diff --git a/arch/mips/ite-boards/generic/pmon_prom.c b/arch/mips/ite-boards/generic/pmon_prom.c deleted file mode 100644 index 7d0a79be34d8..000000000000 --- a/arch/mips/ite-boards/generic/pmon_prom.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * PROM library initialisation code, assuming a version of - * pmon is the boot code. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This file was derived from Carsten Langgaard's - * arch/mips/mips-boards/xx files. - * - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include - -#include - -extern int prom_argc; -extern char **prom_argv, **prom_envp; - -typedef struct -{ - char *name; -/* char *val; */ -}t_env_var; - - -char * __init prom_getcmdline(void) -{ - return &(arcs_cmdline[0]); -} - -void __init prom_init_cmdline(void) -{ - char *cp; - int actr; - - actr = 1; /* Always ignore argv[0] */ - - cp = &(arcs_cmdline[0]); - while(actr < prom_argc) { - strcpy(cp, prom_argv[actr]); - cp += strlen(prom_argv[actr]); - *cp++ = ' '; - actr++; - } - if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ - --cp; - *cp = '\0'; - -} - - -char *prom_getenv(char *envname) -{ - /* - * Return a pointer to the given environment variable. - * Environment variables are stored in the form of "memsize=64". - */ - - t_env_var *env = (t_env_var *)prom_envp; - int i; - - i = strlen(envname); - - while(env->name) { - if(strncmp(envname, env->name, i) == 0) { - return(env->name + strlen(envname) + 1); - } - env++; - } - return(NULL); -} - -static inline unsigned char str2hexnum(unsigned char c) -{ - if(c >= '0' && c <= '9') - return c - '0'; - if(c >= 'a' && c <= 'f') - return c - 'a' + 10; - return 0; /* foo */ -} - -unsigned long __init prom_free_prom_memory(void) -{ - return 0; -} - -unsigned long __init prom_get_memsize(void) -{ - char *memsize_str; - unsigned int memsize; - - memsize_str = prom_getenv("memsize"); - if (!memsize_str) { -#ifdef CONFIG_MIPS_ITE8172 - memsize = 32; -#elif defined(CONFIG_MIPS_IVR) - memsize = 64; -#else - memsize = 8; -#endif - printk("memsize unknown: setting to %dMB\n", memsize); - } else { - printk("memsize: %s\n", memsize_str); - memsize = simple_strtol(memsize_str, NULL, 0); - } - return memsize; -} diff --git a/arch/mips/ite-boards/generic/puts.c b/arch/mips/ite-boards/generic/puts.c deleted file mode 100644 index 20b02df6b414..000000000000 --- a/arch/mips/ite-boards/generic/puts.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * Low level uart routines to directly access a 16550 uart. - * - * Copyright 2000,2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#define SERIAL_BASE 0xB4011800 /* it8172 */ -#define SER_CMD 5 -#define SER_DATA 0x00 -#define TX_BUSY 0x20 - -#define TIMEOUT 0xffff -#undef SLOW_DOWN - -static const char digits[16] = "0123456789abcdef"; -static volatile unsigned char *const com1 = (unsigned char *) SERIAL_BASE; - - -#ifdef SLOW_DOWN -static inline void slow_down() -{ - int k; - for (k = 0; k < 10000; k++); -} -#else -#define slow_down() -#endif - -void putch(const unsigned char c) -{ - unsigned char ch; - int i = 0; - - do { - ch = com1[SER_CMD]; - slow_down(); - i++; - if (i > TIMEOUT) { - break; - } - } while (0 == (ch & TX_BUSY)); - com1[SER_DATA] = c; -} - -void puts(unsigned char *cp) -{ - unsigned char ch; - int i = 0; - - while (*cp) { - do { - ch = com1[SER_CMD]; - slow_down(); - i++; - if (i > TIMEOUT) { - break; - } - } while (0 == (ch & TX_BUSY)); - com1[SER_DATA] = *cp++; - } - putch('\r'); - putch('\n'); -} - -void fputs(unsigned char *cp) -{ - unsigned char ch; - int i = 0; - - while (*cp) { - - do { - ch = com1[SER_CMD]; - slow_down(); - i++; - if (i > TIMEOUT) { - break; - } - } while (0 == (ch & TX_BUSY)); - com1[SER_DATA] = *cp++; - } -} - - -void put64(uint64_t ul) -{ - int cnt; - unsigned ch; - - cnt = 16; /* 16 nibbles in a 64 bit long */ - putch('0'); - putch('x'); - do { - cnt--; - ch = (unsigned char) (ul >> cnt * 4) & 0x0F; - putch(digits[ch]); - } while (cnt > 0); -} - -void put32(unsigned u) -{ - int cnt; - unsigned ch; - - cnt = 8; /* 8 nibbles in a 32 bit long */ - putch('0'); - putch('x'); - do { - cnt--; - ch = (unsigned char) (u >> cnt * 4) & 0x0F; - putch(digits[ch]); - } while (cnt > 0); -} diff --git a/arch/mips/ite-boards/generic/reset.c b/arch/mips/ite-boards/generic/reset.c deleted file mode 100644 index 03bd5ba8c913..000000000000 --- a/arch/mips/ite-boards/generic/reset.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * ITE 8172 reset routines. - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -void it8172_restart() -{ - set_c0_status(ST0_BEV | ST0_ERL); - change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); - flush_cache_all(); - write_c0_wired(0); - __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); -} - -void it8172_halt(void) -{ - printk(KERN_NOTICE "\n** You can safely turn off the power\n"); - while (1) - __asm__(".set\tmips3\n\t" - "wait\n\t" - ".set\tmips0"); -} - -void it8172_power_off(void) -{ - it8172_halt(); -} diff --git a/arch/mips/ite-boards/generic/time.c b/arch/mips/ite-boards/generic/time.c deleted file mode 100644 index 3dc55569ff7f..000000000000 --- a/arch/mips/ite-boards/generic/time.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * - * Copyright (C) 2003 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Setting up the clock on the MIPS boards. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define IT8172_RTC_ADR_REG (IT8172_PCI_IO_BASE + IT_RTC_BASE) -#define IT8172_RTC_DAT_REG (IT8172_RTC_ADR_REG + 1) -#define IT8172_RTC_CENTURY_REG (IT8172_PCI_IO_BASE + IT_RTC_CENTURY) - -static volatile char *rtc_adr_reg = (char*)KSEG1ADDR(IT8172_RTC_ADR_REG); -static volatile char *rtc_dat_reg = (char*)KSEG1ADDR(IT8172_RTC_DAT_REG); -static volatile char *rtc_century_reg = (char*)KSEG1ADDR(IT8172_RTC_CENTURY_REG); - -unsigned char it8172_rtc_read_data(unsigned long addr) -{ - unsigned char retval; - - *rtc_adr_reg = addr; - retval = *rtc_dat_reg; - return retval; -} - -void it8172_rtc_write_data(unsigned char data, unsigned long addr) -{ - *rtc_adr_reg = addr; - *rtc_dat_reg = data; -} - -#undef CMOS_READ -#undef CMOS_WRITE -#define CMOS_READ(addr) it8172_rtc_read_data(addr) -#define CMOS_WRITE(data, addr) it8172_rtc_write_data(data, addr) - -static unsigned char saved_control; /* remember rtc control reg */ -static inline int rtc_24h(void) { return saved_control & RTC_24H; } -static inline int rtc_dm_binary(void) { return saved_control & RTC_DM_BINARY; } - -static inline unsigned char -bin_to_hw(unsigned char c) -{ - if (rtc_dm_binary()) - return c; - else - return ((c/10) << 4) + (c%10); -} - -static inline unsigned char -hw_to_bin(unsigned char c) -{ - if (rtc_dm_binary()) - return c; - else - return (c>>4)*10 + (c &0xf); -} - -/* 0x80 bit indicates pm in 12-hour format */ -static inline unsigned char -hour_bin_to_hw(unsigned char c) -{ - if (rtc_24h()) - return bin_to_hw(c); - if (c >= 12) - return 0x80 | bin_to_hw((c==12)?12:c-12); /* 12 is 12pm */ - else - return bin_to_hw((c==0)?12:c); /* 0 is 12 AM, not 0 am */ -} - -static inline unsigned char -hour_hw_to_bin(unsigned char c) -{ - unsigned char tmp = hw_to_bin(c&0x3f); - if (rtc_24h()) - return tmp; - if (c & 0x80) - return (tmp==12)?12:tmp+12; /* 12pm is 12, not 24 */ - else - return (tmp==12)?0:tmp; /* 12am is 0 */ -} - -static unsigned long r4k_offset; /* Amount to increment compare reg each time */ -static unsigned long r4k_cur; /* What counter should be at next timer irq */ -extern unsigned int mips_hpt_frequency; - -/* - * Figure out the r4k offset, the amount to increment the compare - * register for each time tick. - * Use the RTC to calculate offset. - */ -static unsigned long __init cal_r4koff(void) -{ - unsigned int flags; - - local_irq_save(flags); - - /* Start counter exactly on falling edge of update flag */ - while (CMOS_READ(RTC_REG_A) & RTC_UIP); - while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - - /* Start r4k counter. */ - write_c0_count(0); - - /* Read counter exactly on falling edge of update flag */ - while (CMOS_READ(RTC_REG_A) & RTC_UIP); - while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - - mips_hpt_frequency = read_c0_count(); - - /* restore interrupts */ - local_irq_restore(flags); - - return (mips_hpt_frequency / HZ); -} - -static unsigned long -it8172_rtc_get_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - unsigned int flags; - - /* avoid update-in-progress. */ - for (;;) { - local_irq_save(flags); - if (! (CMOS_READ(RTC_REG_A) & RTC_UIP)) - break; - /* don't hold intr closed all the time */ - local_irq_restore(flags); - } - - /* Read regs. */ - sec = hw_to_bin(CMOS_READ(RTC_SECONDS)); - min = hw_to_bin(CMOS_READ(RTC_MINUTES)); - hour = hour_hw_to_bin(CMOS_READ(RTC_HOURS)); - day = hw_to_bin(CMOS_READ(RTC_DAY_OF_MONTH)); - mon = hw_to_bin(CMOS_READ(RTC_MONTH)); - year = hw_to_bin(CMOS_READ(RTC_YEAR)) + - hw_to_bin(*rtc_century_reg) * 100; - - /* restore interrupts */ - local_irq_restore(flags); - - return mktime(year, mon, day, hour, min, sec); -} - -static int -it8172_rtc_set_time(unsigned long t) -{ - struct rtc_time tm; - unsigned int flags; - - /* convert */ - to_tm(t, &tm); - - /* avoid update-in-progress. */ - for (;;) { - local_irq_save(flags); - if (! (CMOS_READ(RTC_REG_A) & RTC_UIP)) - break; - /* don't hold intr closed all the time */ - local_irq_restore(flags); - } - - *rtc_century_reg = bin_to_hw(tm.tm_year/100); - CMOS_WRITE(bin_to_hw(tm.tm_sec), RTC_SECONDS); - CMOS_WRITE(bin_to_hw(tm.tm_min), RTC_MINUTES); - CMOS_WRITE(hour_bin_to_hw(tm.tm_hour), RTC_HOURS); - CMOS_WRITE(bin_to_hw(tm.tm_mday), RTC_DAY_OF_MONTH); - CMOS_WRITE(bin_to_hw(tm.tm_mon+1), RTC_MONTH); /* tm_mon starts from 0 */ - CMOS_WRITE(bin_to_hw(tm.tm_year%100), RTC_YEAR); - - /* restore interrupts */ - local_irq_restore(flags); - - return 0; -} - -void __init it8172_time_init(void) -{ - unsigned int est_freq, flags; - - local_irq_save(flags); - - saved_control = CMOS_READ(RTC_CONTROL); - - printk("calculating r4koff... "); - r4k_offset = cal_r4koff(); - printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); - - est_freq = 2*r4k_offset*HZ; - est_freq += 5000; /* round */ - est_freq -= est_freq%10000; - printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, - (est_freq%1000000)*100/1000000); - - local_irq_restore(flags); - - rtc_mips_get_time = it8172_rtc_get_time; - rtc_mips_set_time = it8172_rtc_set_time; -} - -#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) - -void __init plat_timer_setup(struct irqaction *irq) -{ - puts("timer_setup\n"); - put32(NR_IRQS); - puts(""); - /* we are using the cpu counter for timer interrupts */ - setup_irq(MIPS_CPU_TIMER_IRQ, irq); - - /* to generate the first timer interrupt */ - r4k_cur = (read_c0_count() + r4k_offset); - write_c0_compare(r4k_cur); - set_c0_status(ALLINTS); -} diff --git a/arch/mips/ite-boards/ivr/Makefile b/arch/mips/ite-boards/ivr/Makefile deleted file mode 100644 index e4fa6042b472..000000000000 --- a/arch/mips/ite-boards/ivr/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright 2000 MontaVista Software Inc. -# Author: MontaVista Software, Inc. -# ppopov@mvista.com or source@mvista.com -# -# Makefile for the Globespan IVR board, -# board-specific files. -# - -obj-y += init.o diff --git a/arch/mips/ite-boards/ivr/README b/arch/mips/ite-boards/ivr/README deleted file mode 100644 index aa7d8db855bb..000000000000 --- a/arch/mips/ite-boards/ivr/README +++ /dev/null @@ -1,3 +0,0 @@ -This is not really a board made by ITE Semi, but it's very -similar to the ITE QED-4N-S01B board. The IVR board is made -by Globespan and it's a reference board for the PVR chip. diff --git a/arch/mips/ite-boards/ivr/init.c b/arch/mips/ite-boards/ivr/init.c deleted file mode 100644 index 05cf9218c432..000000000000 --- a/arch/mips/ite-boards/ivr/init.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * IVR board setup. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int prom_argc; -char **prom_argv, **prom_envp; - -extern void __init prom_init_cmdline(void); -extern unsigned long __init prom_get_memsize(void); -extern void __init it8172_init_ram_resource(unsigned long memsize); - -const char *get_system_type(void) -{ - return "Globespan IVR"; -} - -void __init prom_init(void) -{ - unsigned long mem_size; - unsigned long pcicr; - - prom_argc = fw_arg0; - prom_argv = (char **) fw_arg1; - prom_envp = (int *) fw_arg3; - - mips_machgroup = MACH_GROUP_GLOBESPAN; - mips_machtype = MACH_IVR; /* Globespan's iTVC15 reference board */ - - prom_init_cmdline(); - - /* pmon does not set memsize */ - mem_size = prom_get_memsize(); - mem_size = mem_size << 20; - - /* - * make the entire physical memory visible to pci bus masters - */ - IT_READ(IT_MC_PCICR, pcicr); - pcicr &= ~0x1f; - pcicr |= (mem_size - 1) >> 22; - IT_WRITE(IT_MC_PCICR, pcicr); - - it8172_init_ram_resource(mem_size); - add_memory_region(0, mem_size, BOOT_MEM_RAM); -} diff --git a/arch/mips/ite-boards/qed-4n-s01b/Makefile b/arch/mips/ite-boards/qed-4n-s01b/Makefile deleted file mode 100644 index bb9972ad9c45..000000000000 --- a/arch/mips/ite-boards/qed-4n-s01b/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright 2000 MontaVista Software Inc. -# Author: MontaVista Software, Inc. -# ppopov@mvista.com or source@mvista.com -# -# Makefile for the ITE 8172 (qed-4n-s01b) board, board -# specific files. -# - -obj-y := init.o diff --git a/arch/mips/ite-boards/qed-4n-s01b/README b/arch/mips/ite-boards/qed-4n-s01b/README deleted file mode 100644 index fb4b5197e800..000000000000 --- a/arch/mips/ite-boards/qed-4n-s01b/README +++ /dev/null @@ -1,2 +0,0 @@ -This is an ITE (www.iteusa.com) eval board for the ITE 8172G -system controller, with a QED 5231 CPU. diff --git a/arch/mips/ite-boards/qed-4n-s01b/init.c b/arch/mips/ite-boards/qed-4n-s01b/init.c deleted file mode 100644 index ea2a754cafe5..000000000000 --- a/arch/mips/ite-boards/qed-4n-s01b/init.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * IT8172/QED5231 board setup. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int prom_argc; -char **prom_argv, **prom_envp; - -extern void __init prom_init_cmdline(void); -extern unsigned long __init prom_get_memsize(void); -extern void __init it8172_init_ram_resource(unsigned long memsize); - -const char *get_system_type(void) -{ - return "ITE QED-4N-S01B"; -} - -void __init prom_init(void) -{ - unsigned long mem_size; - unsigned long pcicr; - - prom_argc = fw_arg0; - prom_argv = (char **) fw_arg1; - prom_envp = (int *) fw_arg3; - - mips_machgroup = MACH_GROUP_ITE; - mips_machtype = MACH_QED_4N_S01B; /* ITE board name/number */ - - prom_init_cmdline(); - mem_size = prom_get_memsize(); - - printk("Memory size: %dMB\n", (unsigned)mem_size); - - mem_size <<= 20; /* MB */ - - /* - * make the entire physical memory visible to pci bus masters - */ - IT_READ(IT_MC_PCICR, pcicr); - pcicr &= ~0x1f; - pcicr |= (mem_size - 1) >> 22; - IT_WRITE(IT_MC_PCICR, pcicr); - - it8172_init_ram_resource(mem_size); - add_memory_region(0, mem_size, BOOT_MEM_RAM); -} diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index edefa97b2330..3cf0dd4ba548 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -7,7 +7,6 @@ obj-y += pci.o # # PCI bus host bridge specific code # -obj-$(CONFIG_ITE_BOARD_GEN) += ops-it8172.o obj-$(CONFIG_MIPS_BONITO64) += ops-bonito64.o obj-$(CONFIG_MIPS_GT64111) += ops-gt64111.o obj-$(CONFIG_MIPS_GT64120) += ops-gt64120.o @@ -28,8 +27,6 @@ obj-$(CONFIG_LASAT) += pci-lasat.o obj-$(CONFIG_MIPS_ATLAS) += fixup-atlas.o obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o obj-$(CONFIG_MIPS_EV64120) += fixup-ev64120.o -obj-$(CONFIG_MIPS_ITE8172) += fixup-ite8172g.o -obj-$(CONFIG_MIPS_IVR) += fixup-ivr.o obj-$(CONFIG_SOC_AU1500) += fixup-au1000.o ops-au1000.o obj-$(CONFIG_SOC_AU1550) += fixup-au1000.o ops-au1000.o obj-$(CONFIG_SOC_PNX8550) += fixup-pnx8550.o ops-pnx8550.o diff --git a/arch/mips/pci/fixup-ite8172g.c b/arch/mips/pci/fixup-ite8172g.c deleted file mode 100644 index 2290ea4228dd..000000000000 --- a/arch/mips/pci/fixup-ite8172g.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * Board specific pci fixups. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include - -#include -#include -#include - -/* - * Shortcuts - */ -#define INTA IT8172_PCI_INTA_IRQ -#define INTB IT8172_PCI_INTB_IRQ -#define INTC IT8172_PCI_INTC_IRQ -#define INTD IT8172_PCI_INTD_IRQ - -static const int internal_func_irqs[7] __initdata = { - IT8172_AC97_IRQ, - IT8172_DMA_IRQ, - IT8172_CDMA_IRQ, - IT8172_USB_IRQ, - IT8172_BRIDGE_MASTER_IRQ, - IT8172_IDE_IRQ, - IT8172_MC68K_IRQ -}; - -static char irq_tab_ite8172g[][5] __initdata = { - [0x10] = { 0, INTA, INTB, INTC, INTD }, - [0x11] = { 0, INTA, INTB, INTC, INTD }, - [0x12] = { 0, INTB, INTC, INTD, INTA }, - [0x13] = { 0, INTC, INTD, INTA, INTB }, - [0x14] = { 0, INTD, INTA, INTB, INTC }, -}; - -int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - /* - * Internal device 1 is actually 7 different internal devices on the - * IT8172G (a multifunction device). - */ - if (slot == 1) - return internal_func_irqs[PCI_FUNC(dev->devfn)]; - - return irq_tab_ite8172g[slot][pin]; -} - -/* Do platform specific device initialization at pci_enable_device() time */ -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - return 0; -} diff --git a/arch/mips/pci/fixup-ivr.c b/arch/mips/pci/fixup-ivr.c deleted file mode 100644 index 0c7c16464c11..000000000000 --- a/arch/mips/pci/fixup-ivr.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * Globespan IVR board-specific pci fixups. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include - -#include -#include -#include - -/* - * Shortcuts - */ -#define INTA IT8172_PCI_INTA_IRQ -#define INTB IT8172_PCI_INTB_IRQ -#define INTC IT8172_PCI_INTC_IRQ -#define INTD IT8172_PCI_INTD_IRQ - -static const int internal_func_irqs[7] __initdata = { - IT8172_AC97_IRQ, - IT8172_DMA_IRQ, - IT8172_CDMA_IRQ, - IT8172_USB_IRQ, - IT8172_BRIDGE_MASTER_IRQ, - IT8172_IDE_IRQ, - IT8172_MC68K_IRQ -}; - -static char irq_tab_ivr[][5] __initdata = { - [0x11] = { INTC, INTC, INTD, INTA, INTB }, /* Realtek RTL-8139 */ - [0x12] = { INTB, INTB, INTB, INTC, INTC }, /* IVR slot */ - [0x13] = { INTA, INTA, INTB, INTC, INTD } /* Expansion slot */ -}; - -int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - if (slot == 1) - return internal_func_irqs[PCI_FUNC(dev->devfn)]; - - return irq_tab_ivr[slot][pin]; -} - -/* Do platform specific device initialization at pci_enable_device() time */ -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - return 0; -} diff --git a/arch/mips/pci/ops-it8172.c b/arch/mips/pci/ops-it8172.c deleted file mode 100644 index ba8328505a0a..000000000000 --- a/arch/mips/pci/ops-it8172.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * IT8172 system controller specific pci support. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include - -#include -#include - -#define PCI_ACCESS_READ 0 -#define PCI_ACCESS_WRITE 1 - -#undef DEBUG -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -static struct resource pci_mem_resource_1; - -static struct resource pci_io_resource = { - .start = 0x14018000, - .end = 0x17FFFFFF, - .name = "io pci IO space", - .flags = IORESOURCE_IO -}; - -static struct resource pci_mem_resource_0 = { - .start = 0x10101000, - .end = 0x13FFFFFF, - .name = "ext pci memory space 0/1", - .flags = IORESOURCE_MEM, - .parent = &pci_mem_resource_0, - .sibling = NULL, - .child = &pci_mem_resource_1 -}; - -static struct resource pci_mem_resource_1 = { - .start = 0x1A000000, - .end = 0x1FBFFFFF, - .name = "ext pci memory space 2/3", - .flags = IORESOURCE_MEM, - .parent = &pci_mem_resource_0 -}; - -extern struct pci_ops it8172_pci_ops; - -struct pci_controller it8172_controller = { - .pci_ops = &it8172_pci_ops, - .io_resource = &pci_io_resource, - .mem_resource = &pci_mem_resource_0, -}; - -static int it8172_pcibios_config_access(unsigned char access_type, - struct pci_bus *bus, - unsigned int devfn, int where, - u32 * data) -{ - /* - * config cycles are on 4 byte boundary only - */ - - /* Setup address */ - IT_WRITE(IT_CONFADDR, (bus->number << IT_BUSNUM_SHF) | - (devfn << IT_FUNCNUM_SHF) | (where & ~0x3)); - - if (access_type == PCI_ACCESS_WRITE) { - IT_WRITE(IT_CONFDATA, *data); - } else { - IT_READ(IT_CONFDATA, *data); - } - - /* - * Revisit: check for master or target abort. - */ - return 0; -} - - -/* - * We can't address 8 and 16 bit words directly. Instead we have to - * read/write a 32bit word and mask/modify the data we actually want. - */ -static write_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 val) -{ - u32 data = 0; - - switch (size) { - case 1: - if (it8172_pcibios_config_access - (PCI_ACCESS_READ, dev, where, &data)) - return -1; - - *val = (data >> ((where & 3) << 3)) & 0xff; - - return PCIBIOS_SUCCESSFUL; - - case 2: - - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - - if (it8172_pcibios_config_access - (PCI_ACCESS_READ, dev, where, &data)) - return -1; - - *val = (data >> ((where & 3) << 3)) & 0xffff; - DBG("cfg read word: bus %d dev_fn %x where %x: val %x\n", - dev->bus->number, dev->devfn, where, *val); - - return PCIBIOS_SUCCESSFUL; - - case 4: - - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; - - if (it8172_pcibios_config_access - (PCI_ACCESS_READ, dev, where, &data)) - return -1; - - *val = data; - - return PCIBIOS_SUCCESSFUL; - } -} - - -static write_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 val) -{ - u32 data = 0; - - switch (size) { - case 1: - if (it8172_pcibios_config_access - (PCI_ACCESS_READ, dev, where, &data)) - return -1; - - data = (data & ~(0xff << ((where & 3) << 3))) | - (val << ((where & 3) << 3)); - - if (it8172_pcibios_config_access - (PCI_ACCESS_WRITE, dev, where, &data)) - return -1; - - return PCIBIOS_SUCCESSFUL; - - case 2: - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - - if (it8172_pcibios_config_access - (PCI_ACCESS_READ, dev, where, &data)) - eturn - 1; - - data = (data & ~(0xffff << ((where & 3) << 3))) | - (val << ((where & 3) << 3)); - - if (it8172_pcibios_config_access - (PCI_ACCESS_WRITE, dev, where, &data)) - return -1; - - return PCIBIOS_SUCCESSFUL; - - case 4: - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; - - if (it8172_pcibios_config_access - (PCI_ACCESS_WRITE, dev, where, &val)) - return -1; - - return PCIBIOS_SUCCESSFUL; - } -} - -struct pci_ops it8172_pci_ops = { - .read = read_config, - .write = write_config, -}; diff --git a/drivers/char/.gitignore b/drivers/char/.gitignore index 73dfdcebfbba..83683a2d8e6a 100644 --- a/drivers/char/.gitignore +++ b/drivers/char/.gitignore @@ -1,3 +1,2 @@ consolemap_deftbl.c defkeymap.c -qtronixmap.c diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index bde1c665d9f4..0e6f35fcc2eb 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -371,36 +371,6 @@ config AU1000_SERIAL_CONSOLE If you have an Alchemy AU1000 processor (MIPS based) and you want to use a console on a serial port, say Y. Otherwise, say N. -config QTRONIX_KEYBOARD - bool "Enable Qtronix 990P Keyboard Support" - depends on IT8712 - help - Images of Qtronix keyboards are at - . - -config IT8172_CIR - bool - depends on QTRONIX_KEYBOARD - default y - -config IT8172_SCR0 - bool "Enable Smart Card Reader 0 Support " - depends on IT8712 - help - Say Y here to support smart-card reader 0 (SCR0) on the Integrated - Technology Express, Inc. ITE8172 SBC. Vendor page at - ; picture of the - board at . - -config IT8172_SCR1 - bool "Enable Smart Card Reader 1 Support " - depends on IT8712 - help - Say Y here to support smart-card reader 1 (SCR1) on the Integrated - Technology Express, Inc. ITE8172 SBC. Vendor page at - ; picture of the - board at . - config A2232 tristate "Commodore A2232 serial support (EXPERIMENTAL)" depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 19114df59bbd..777cad045094 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -102,7 +102,7 @@ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o obj-$(CONFIG_TCG_TPM) += tpm/ # Files generated that shall be removed upon make clean -clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c +clean-files := consolemap_deftbl.c defkeymap.c quiet_cmd_conmk = CONMK $@ cmd_conmk = scripts/conmakehash $< > $@ @@ -112,8 +112,6 @@ $(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) $(obj)/defkeymap.o: $(obj)/defkeymap.c -$(obj)/qtronixmap.o: $(obj)/qtronixmap.c - # Uncomment if you're changing the keymap and have an appropriate # loadkeys version for the map. By default, we'll use the shipped # versions. @@ -121,7 +119,7 @@ $(obj)/qtronixmap.o: $(obj)/qtronixmap.c ifdef GENERATE_KEYMAP -$(obj)/defkeymap.c $(obj)/qtronixmap.c: $(obj)/%.c: $(src)/%.map +$(obj)/defkeymap.c $(obj)/%.c: $(src)/%.map loadkeys --mktable $< > $@.tmp sed -e 's/^static *//' $@.tmp > $@ rm $@.tmp diff --git a/drivers/char/ite_gpio.c b/drivers/char/ite_gpio.c deleted file mode 100644 index cde562d70c4f..000000000000 --- a/drivers/char/ite_gpio.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * FILE NAME ite_gpio.c - * - * BRIEF MODULE DESCRIPTION - * API for ITE GPIO device. - * Driver for ITE GPIO device. - * - * Author: MontaVista Software, Inc. - * Hai-Pao Fan - * - * Copyright 2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ite_gpio_base 0x14013800 - -#define ITE_GPADR (*(volatile __u8 *)(0x14013800 + KSEG1)) -#define ITE_GPBDR (*(volatile __u8 *)(0x14013808 + KSEG1)) -#define ITE_GPCDR (*(volatile __u8 *)(0x14013810 + KSEG1)) -#define ITE_GPACR (*(volatile __u16 *)(0x14013802 + KSEG1)) -#define ITE_GPBCR (*(volatile __u16 *)(0x1401380a + KSEG1)) -#define ITE_GPCCR (*(volatile __u16 *)(0x14013812 + KSEG1)) -#define ITE_GPAICR (*(volatile __u16 *)(0x14013804 + KSEG1)) -#define ITE_GPBICR (*(volatile __u16 *)(0x1401380c + KSEG1)) -#define ITE_GPCICR (*(volatile __u16 *)(0x14013814 + KSEG1)) -#define ITE_GPAISR (*(volatile __u8 *)(0x14013806 + KSEG1)) -#define ITE_GPBISR (*(volatile __u8 *)(0x1401380e + KSEG1)) -#define ITE_GPCISR (*(volatile __u8 *)(0x14013816 + KSEG1)) -#define ITE_GCR (*(volatile __u8 *)(0x14013818 + KSEG1)) - -#define MAX_GPIO_LINE 21 -static int ite_gpio_irq=IT8172_GPIO_IRQ; - -static long ite_irq_counter[MAX_GPIO_LINE]; -wait_queue_head_t ite_gpio_wait[MAX_GPIO_LINE]; -static int ite_gpio_irq_pending[MAX_GPIO_LINE]; - -static int ite_gpio_debug=0; -#define DEB(x) if (ite_gpio_debug>=1) x - -int ite_gpio_in(__u32 device, __u32 mask, volatile __u32 *data) -{ - DEB(printk("ite_gpio_in mask=0x%x\n",mask)); - - switch (device) { - case ITE_GPIO_PORTA: - ITE_GPACR = (__u16)mask; /* 0xffff */ - *data = ITE_GPADR; - break; - case ITE_GPIO_PORTB: - ITE_GPBCR = (__u16)mask; /* 0xffff */ - *data = ITE_GPBDR; - break; - case ITE_GPIO_PORTC: - ITE_GPCCR = (__u16)mask; /* 0x03ff */ - *data = ITE_GPCDR; - break; - default: - return -EFAULT; - } - - return 0; -} - - -int ite_gpio_out(__u32 device, __u32 mask, __u32 data) -{ - switch (device) { - case ITE_GPIO_PORTA: - ITE_GPACR = (__u16)mask; /* 0x5555 */ - ITE_GPADR = (__u8)data; - break; - case ITE_GPIO_PORTB: - ITE_GPBCR = (__u16)mask; /* 0x5555 */ - ITE_GPBDR = (__u8)data; - break; - case ITE_GPIO_PORTC: - ITE_GPCCR = (__u16)mask; /* 0x0155 */ - ITE_GPCDR = (__u8)data; - break; - default: - return -EFAULT; - } - - return 0; -} - -int ite_gpio_int_ctrl(__u32 device, __u32 mask, __u32 data) -{ - switch (device) { - case ITE_GPIO_PORTA: - ITE_GPAICR = (ITE_GPAICR & ~mask) | (data & mask); - break; - case ITE_GPIO_PORTB: - ITE_GPBICR = (ITE_GPBICR & ~mask) | (data & mask); - break; - case ITE_GPIO_PORTC: - ITE_GPCICR = (ITE_GPCICR & ~mask) | (data & mask); - break; - default: - return -EFAULT; - } - - return 0; -} - -int ite_gpio_in_status(__u32 device, __u32 mask, volatile __u32 *data) -{ - int ret=-1; - - if ((MAX_GPIO_LINE > *data) && (*data >= 0)) - ret=ite_gpio_irq_pending[*data]; - - DEB(printk("ite_gpio_in_status %d ret=%d\n",*data, ret)); - - switch (device) { - case ITE_GPIO_PORTA: - *data = ITE_GPAISR & mask; - break; - case ITE_GPIO_PORTB: - *data = ITE_GPBISR & mask; - break; - case ITE_GPIO_PORTC: - *data = ITE_GPCISR & mask; - break; - default: - return -EFAULT; - } - - return ret; -} - -int ite_gpio_out_status(__u32 device, __u32 mask, __u32 data) -{ - switch (device) { - case ITE_GPIO_PORTA: - ITE_GPAISR = (ITE_GPAISR & ~mask) | (data & mask); - break; - case ITE_GPIO_PORTB: - ITE_GPBISR = (ITE_GPBISR & ~mask) | (data & mask); - break; - case ITE_GPIO_PORTC: - ITE_GPCISR = (ITE_GPCISR & ~mask) | (data & mask); - break; - default: - return -EFAULT; - } - - return 0; -} - -int ite_gpio_gen_ctrl(__u32 device, __u32 mask, __u32 data) -{ - ITE_GCR = (ITE_GCR & ~mask) | (data & mask); - - return 0; -} - -int ite_gpio_int_wait (__u32 device, __u32 mask, __u32 data) -{ - int i,line=0, ret=0; - unsigned long flags; - - switch (device) { - case ITE_GPIO_PORTA: - line = data & mask; - break; - case ITE_GPIO_PORTB: - line = (data & mask) <<8; - break; - case ITE_GPIO_PORTC: - line = (data & mask) <<16; - break; - } - for (i=MAX_GPIO_LINE-1; i >= 0; i--) { - if ( (line) & (1 << i)) - break; - } - - DEB(printk("wait device=0x%d mask=0x%x data=0x%x index %d\n", - device, mask, data, i)); - - if (line & ~(1< ITE_GPIO_PORTC) ) - return -EFAULT; - - switch(cmd) { - case ITE_GPIO_IN: - if (ite_gpio_in(ioctl_data.device, ioctl_data.mask, - &ioctl_data.data)) - return -EFAULT; - - if (copy_to_user((struct ite_gpio_ioctl_data *)arg, - &ioctl_data, sizeof(ioctl_data))) - return -EFAULT; - break; - - case ITE_GPIO_OUT: - return ite_gpio_out(ioctl_data.device, - ioctl_data.mask, ioctl_data.data); - break; - - case ITE_GPIO_INT_CTRL: - return ite_gpio_int_ctrl(ioctl_data.device, - ioctl_data.mask, ioctl_data.data); - break; - - case ITE_GPIO_IN_STATUS: - if (ite_gpio_in_status(ioctl_data.device, ioctl_data.mask, - &ioctl_data.data)) - return -EFAULT; - if (copy_to_user((struct ite_gpio_ioctl_data *)arg, - &ioctl_data, sizeof(ioctl_data))) - return -EFAULT; - break; - - case ITE_GPIO_OUT_STATUS: - return ite_gpio_out_status(ioctl_data.device, - ioctl_data.mask, ioctl_data.data); - break; - - case ITE_GPIO_GEN_CTRL: - return ite_gpio_gen_ctrl(ioctl_data.device, - ioctl_data.mask, ioctl_data.data); - break; - - case ITE_GPIO_INT_WAIT: - return ite_gpio_int_wait(ioctl_data.device, - ioctl_data.mask, ioctl_data.data); - break; - - default: - return -ENOIOCTLCMD; - - } - - return 0; -} - -static void ite_gpio_irq_handler(int this_irq, void *dev_id, - struct pt_regs *regs) -{ - int i,line; - - line = ITE_GPCISR & 0x1f; - for (i=4; i >=0; i--) { - if ( line & (1 << i)) { - ++ite_irq_counter[i+16]; - ite_gpio_irq_pending[i+16] = 2; - wake_up_interruptible(&ite_gpio_wait[i+16]); - -DEB(printk("interrupt 0x%x %d\n", &ite_gpio_wait[i+16], i+16)); - - ITE_GPCISR = ITE_GPCISR & (1<= 0; i--) { - if ( line & (1 << i)) { - ++ite_irq_counter[i+8]; - ite_gpio_irq_pending[i+8] = 2; - wake_up_interruptible(&ite_gpio_wait[i+8]); - -DEB(printk("interrupt 0x%x %d\n",ITE_GPBISR, i+8)); - - ITE_GPBISR = ITE_GPBISR & (1<= 0; i--) { - if ( line & (1 << i)) { - ++ite_irq_counter[i]; - ite_gpio_irq_pending[i] = 2; - wake_up_interruptible(&ite_gpio_wait[i]); - -DEB(printk("interrupt 0x%x %d\n",ITE_GPAISR, i)); - - ITE_GPAISR = ITE_GPAISR & (1< defkeymap.c */ - -#include -#include -#include - -u_short plain_map[NR_KEYS] = { - 0xf200, 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, - 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf200, 0xf07f, - 0xf009, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, - 0xfb69, 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf05c, 0xf207, 0xfb61, - 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, - 0xf03b, 0xf027, 0xf060, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78, - 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, - 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, - 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, - 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200, - 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107, - 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, -}; - -u_short shift_map[NR_KEYS] = { - 0xf200, 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, - 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf200, 0xf07f, - 0xf009, 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, - 0xfb49, 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf07c, 0xf207, 0xfb41, - 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, - 0xf03a, 0xf022, 0xf07e, 0xf201, 0xf700, 0xf200, 0xfb5a, 0xfb58, - 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, - 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, - 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf20b, 0xf20a, 0xf200, - 0xf200, 0xf602, 0xf213, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200, - 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111, - 0xf112, 0xf113, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, -}; - -u_short altgr_map[NR_KEYS] = { - 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, - 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, - 0xf200, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, - 0xfb69, 0xfb6f, 0xfb70, 0xf200, 0xf200, 0xf200, 0xf207, 0xfb61, - 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, - 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78, - 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, - 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, - 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, - 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513, - 0xf514, 0xf515, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, -}; - -u_short ctrl_map[NR_KEYS] = { - 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, - 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf008, - 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, - 0xf009, 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf01c, 0xf207, 0xf001, - 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, - 0xf007, 0xf000, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018, - 0xf003, 0xf016, 0xf002, 0xf00e, 0xf20e, 0xf07f, 0xf200, 0xf200, - 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf000, 0xf703, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, - 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, - 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, - 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107, - 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, -}; - -u_short shift_ctrl_map[NR_KEYS] = { - 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, - 0xf009, 0xf00f, 0xf010, 0xf200, 0xf200, 0xf200, 0xf207, 0xf001, - 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, - 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018, - 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, - 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, - 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, -}; - -u_short alt_map[NR_KEYS] = { - 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, - 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf200, 0xf87f, - 0xf809, 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, - 0xf869, 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf85c, 0xf207, 0xf861, - 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf83b, - 0xf827, 0xf860, 0xf200, 0xf80d, 0xf700, 0xf200, 0xf87a, 0xf878, - 0xf863, 0xf876, 0xf862, 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf200, - 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf820, 0xf703, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf210, - 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, - 0xf200, 0xf211, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, - 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507, - 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, -}; - -u_short ctrl_alt_map[NR_KEYS] = { - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, - 0xf809, 0xf80f, 0xf810, 0xf200, 0xf200, 0xf200, 0xf207, 0xf801, - 0xf813, 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, - 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf81a, 0xf818, - 0xf803, 0xf816, 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, - 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, - 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, - 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507, - 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, -}; - -ushort *key_maps[MAX_NR_KEYMAPS] = { - plain_map, shift_map, altgr_map, 0, - ctrl_map, shift_ctrl_map, 0, 0, - alt_map, 0, 0, 0, - ctrl_alt_map, 0 -}; - -unsigned int keymap_count = 7; - - -/* - * Philosophy: most people do not define more strings, but they who do - * often want quite a lot of string space. So, we statically allocate - * the default and allocate dynamically in chunks of 512 bytes. - */ - -char func_buf[] = { - '\033', '[', '[', 'A', 0, - '\033', '[', '[', 'B', 0, - '\033', '[', '[', 'C', 0, - '\033', '[', '[', 'D', 0, - '\033', '[', '[', 'E', 0, - '\033', '[', '1', '7', '~', 0, - '\033', '[', '1', '8', '~', 0, - '\033', '[', '1', '9', '~', 0, - '\033', '[', '2', '0', '~', 0, - '\033', '[', '2', '1', '~', 0, - '\033', '[', '2', '3', '~', 0, - '\033', '[', '2', '4', '~', 0, - '\033', '[', '2', '5', '~', 0, - '\033', '[', '2', '6', '~', 0, - '\033', '[', '2', '8', '~', 0, - '\033', '[', '2', '9', '~', 0, - '\033', '[', '3', '1', '~', 0, - '\033', '[', '3', '2', '~', 0, - '\033', '[', '3', '3', '~', 0, - '\033', '[', '3', '4', '~', 0, - '\033', '[', '1', '~', 0, - '\033', '[', '2', '~', 0, - '\033', '[', '3', '~', 0, - '\033', '[', '4', '~', 0, - '\033', '[', '5', '~', 0, - '\033', '[', '6', '~', 0, - '\033', '[', 'M', 0, - '\033', '[', 'P', 0, -}; - - -char *funcbufptr = func_buf; -int funcbufsize = sizeof(func_buf); -int funcbufleft = 0; /* space left */ - -char *func_table[MAX_NR_FUNC] = { - func_buf + 0, - func_buf + 5, - func_buf + 10, - func_buf + 15, - func_buf + 20, - func_buf + 25, - func_buf + 31, - func_buf + 37, - func_buf + 43, - func_buf + 49, - func_buf + 55, - func_buf + 61, - func_buf + 67, - func_buf + 73, - func_buf + 79, - func_buf + 85, - func_buf + 91, - func_buf + 97, - func_buf + 103, - func_buf + 109, - func_buf + 115, - func_buf + 120, - func_buf + 125, - func_buf + 130, - func_buf + 135, - func_buf + 140, - func_buf + 145, - 0, - 0, - func_buf + 149, - 0, -}; - -struct kbdiacr accent_table[MAX_DIACR] = { - {'`', 'A', 'À'}, {'`', 'a', 'à'}, - {'\'', 'A', 'Á'}, {'\'', 'a', 'á'}, - {'^', 'A', 'Â'}, {'^', 'a', 'â'}, - {'~', 'A', 'Ã'}, {'~', 'a', 'ã'}, - {'"', 'A', 'Ä'}, {'"', 'a', 'ä'}, - {'O', 'A', 'Å'}, {'o', 'a', 'å'}, - {'0', 'A', 'Å'}, {'0', 'a', 'å'}, - {'A', 'A', 'Å'}, {'a', 'a', 'å'}, - {'A', 'E', 'Æ'}, {'a', 'e', 'æ'}, - {',', 'C', 'Ç'}, {',', 'c', 'ç'}, - {'`', 'E', 'È'}, {'`', 'e', 'è'}, - {'\'', 'E', 'É'}, {'\'', 'e', 'é'}, - {'^', 'E', 'Ê'}, {'^', 'e', 'ê'}, - {'"', 'E', 'Ë'}, {'"', 'e', 'ë'}, - {'`', 'I', 'Ì'}, {'`', 'i', 'ì'}, - {'\'', 'I', 'Í'}, {'\'', 'i', 'í'}, - {'^', 'I', 'Î'}, {'^', 'i', 'î'}, - {'"', 'I', 'Ï'}, {'"', 'i', 'ï'}, - {'-', 'D', 'Ð'}, {'-', 'd', 'ð'}, - {'~', 'N', 'Ñ'}, {'~', 'n', 'ñ'}, - {'`', 'O', 'Ò'}, {'`', 'o', 'ò'}, - {'\'', 'O', 'Ó'}, {'\'', 'o', 'ó'}, - {'^', 'O', 'Ô'}, {'^', 'o', 'ô'}, - {'~', 'O', 'Õ'}, {'~', 'o', 'õ'}, - {'"', 'O', 'Ö'}, {'"', 'o', 'ö'}, - {'/', 'O', 'Ø'}, {'/', 'o', 'ø'}, - {'`', 'U', 'Ù'}, {'`', 'u', 'ù'}, - {'\'', 'U', 'Ú'}, {'\'', 'u', 'ú'}, - {'^', 'U', 'Û'}, {'^', 'u', 'û'}, - {'"', 'U', 'Ü'}, {'"', 'u', 'ü'}, - {'\'', 'Y', 'Ý'}, {'\'', 'y', 'ý'}, - {'T', 'H', 'Þ'}, {'t', 'h', 'þ'}, - {'s', 's', 'ß'}, {'"', 'y', 'ÿ'}, - {'s', 'z', 'ß'}, {'i', 'j', 'ÿ'}, -}; - -unsigned int accent_table_size = 68; diff --git a/drivers/char/qtronixmap.map b/drivers/char/qtronixmap.map deleted file mode 100644 index 8d1ff5c1e281..000000000000 --- a/drivers/char/qtronixmap.map +++ /dev/null @@ -1,287 +0,0 @@ -# Default kernel keymap. This uses 7 modifier combinations. -keymaps 0-2,4-5,8,12 -# Change the above line into -# keymaps 0-2,4-6,8,12 -# in case you want the entries -# altgr control keycode 83 = Boot -# altgr control keycode 111 = Boot -# below. -# -# In fact AltGr is used very little, and one more keymap can -# be saved by mapping AltGr to Alt (and adapting a few entries): -# keycode 100 = Alt -# -keycode 1 = grave asciitilde - alt keycode 1 = Meta_Escape -keycode 2 = one exclam - alt keycode 2 = Meta_one -keycode 3 = two at at - control keycode 3 = nul - shift control keycode 3 = nul - alt keycode 3 = Meta_two -keycode 4 = three numbersign - control keycode 4 = Escape - alt keycode 4 = Meta_three -keycode 5 = four dollar dollar - control keycode 5 = Control_backslash - alt keycode 5 = Meta_four -keycode 6 = five percent - control keycode 6 = Control_bracketright - alt keycode 6 = Meta_five -keycode 7 = six asciicircum - control keycode 7 = Control_asciicircum - alt keycode 7 = Meta_six -keycode 8 = seven ampersand braceleft - control keycode 8 = Control_underscore - alt keycode 8 = Meta_seven -keycode 9 = eight asterisk bracketleft - control keycode 9 = Delete - alt keycode 9 = Meta_eight -keycode 10 = nine parenleft bracketright - alt keycode 10 = Meta_nine -keycode 11 = zero parenright braceright - alt keycode 11 = Meta_zero -keycode 12 = minus underscore backslash - control keycode 12 = Control_underscore - shift control keycode 12 = Control_underscore - alt keycode 12 = Meta_minus -keycode 13 = equal plus - alt keycode 13 = Meta_equal -keycode 15 = Delete Delete - control keycode 15 = BackSpace - alt keycode 15 = Meta_Delete -keycode 16 = Tab Tab - alt keycode 16 = Meta_Tab -keycode 17 = q -keycode 18 = w -keycode 19 = e -keycode 20 = r -keycode 21 = t -keycode 22 = y -keycode 23 = u -keycode 24 = i -keycode 25 = o -keycode 26 = p -keycode 27 = bracketleft braceleft - control keycode 27 = Escape - alt keycode 27 = Meta_bracketleft -keycode 28 = bracketright braceright - control keycode 28 = Control_bracketright - alt keycode 28 = Meta_bracketright -keycode 29 = backslash bar - control keycode 29 = Control_backslash - alt keycode 29 = Meta_backslash -keycode 30 = Caps_Lock -keycode 31 = a -keycode 32 = s -keycode 33 = d -keycode 34 = f -keycode 35 = g -keycode 36 = h -keycode 37 = j -keycode 38 = k -keycode 39 = l -keycode 40 = semicolon colon - alt keycode 39 = Meta_semicolon -keycode 41 = apostrophe quotedbl - control keycode 40 = Control_g - alt keycode 40 = Meta_apostrophe -keycode 42 = grave asciitilde - control keycode 41 = nul - alt keycode 41 = Meta_grave -keycode 43 = Return - alt keycode 43 = Meta_Control_m -keycode 44 = Shift -keycode 46 = z -keycode 47 = x -keycode 48 = c -keycode 49 = v -keycode 50 = b -keycode 51 = n -keycode 52 = m -keycode 53 = comma less - alt keycode 51 = Meta_comma -keycode 54 = period greater - control keycode 52 = Compose - alt keycode 52 = Meta_period -keycode 55 = slash question - control keycode 53 = Delete - alt keycode 53 = Meta_slash -keycode 57 = Shift -keycode 58 = Control -keycode 60 = Alt -keycode 61 = space space - control keycode 61 = nul - alt keycode 61 = Meta_space -keycode 62 = Alt - -keycode 75 = Insert -keycode 76 = Delete - -keycode 83 = Up -keycode 84 = Down - -keycode 85 = Prior - shift keycode 85 = Scroll_Backward -keycode 86 = Next - shift keycode 86 = Scroll_Forward -keycode 89 = Right - alt keycode 89 = Incr_Console -keycode 79 = Left - alt keycode 79 = Decr_Console - -keycode 90 = Num_Lock - shift keycode 90 = Bare_Num_Lock - -keycode 91 = minus -keycode 92 = plus -keycode 93 = KP_Multiply -keycode 94 = period -keycode 95 = KP_Divide - -keycode 107 = Select -keycode 108 = Down - -keycode 110 = Escape Escape - alt keycode 1 = Meta_Escape - -keycode 112 = F1 F11 Console_13 - control keycode 112 = F1 - alt keycode 112 = Console_1 - control alt keycode 112 = Console_1 -keycode 113 = F2 F12 Console_14 - control keycode 113 = F2 - alt keycode 113 = Console_2 - control alt keycode 113 = Console_2 -keycode 114 = F3 F13 Console_15 - control keycode 114 = F3 - alt keycode 114 = Console_3 - control alt keycode 114 = Console_3 -keycode 115 = F4 F14 Console_16 - control keycode 115 = F4 - alt keycode 115 = Console_4 - control alt keycode 115 = Console_4 -keycode 116 = F5 F15 Console_17 - control keycode 116 = F5 - alt keycode 116 = Console_5 - control alt keycode 116 = Console_5 -keycode 117 = F6 F16 Console_18 - control keycode 117 = F6 - alt keycode 117 = Console_6 - control alt keycode 117 = Console_6 -keycode 118 = F7 F17 Console_19 - control keycode 118 = F7 - alt keycode 118 = Console_7 - control alt keycode 118 = Console_7 -keycode 119 = F8 F18 Console_20 - control keycode 119 = F8 - alt keycode 119 = Console_8 - control alt keycode 119 = Console_8 -keycode 120 = F9 F19 Console_21 - control keycode 120 = F9 - alt keycode 120 = Console_9 - control alt keycode 120 = Console_9 -keycode 121 = F10 F20 Console_22 - control keycode 121 = F10 - alt keycode 121 = Console_10 - control alt keycode 121 = Console_10 - -keycode 126 = Pause - - -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index abcabb295592..0c68d0f0d8e5 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -614,15 +614,6 @@ config BLK_DEV_PIIX the kernel to change PIO, DMA and UDMA speeds and to configure the chip to optimum performance. -config BLK_DEV_IT8172 - bool "IT8172 IDE support" - depends on (MIPS_ITE8172 || MIPS_IVR) - help - Say Y here to support the on-board IDE controller on the Integrated - Technology Express, Inc. ITE8172 SBC. Vendor page at - ; picture of the - board at . - config BLK_DEV_IT821X tristate "IT821X IDE support" help diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile index 640a54b09b5a..fef08960aa4c 100644 --- a/drivers/ide/pci/Makefile +++ b/drivers/ide/pci/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o #obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o -obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o diff --git a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c deleted file mode 100644 index 0fc89fafad65..000000000000 --- a/drivers/ide/pci/it8172.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * IT8172 IDE controller support - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * stevel@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* - * Prototypes - */ -static u8 it8172_ratemask (ide_drive_t *drive) -{ - return 1; -} - -static void it8172_tune_drive (ide_drive_t *drive, u8 pio) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - int is_slave = (&hwif->drives[1] == drive); - unsigned long flags; - u16 drive_enables; - u32 drive_timing; - - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - spin_lock_irqsave(&ide_lock, flags); - pci_read_config_word(dev, 0x40, &drive_enables); - pci_read_config_dword(dev, 0x44, &drive_timing); - - /* - * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44 - * are being left at the default values of 8 PCI clocks (242 nsec - * for a 33 MHz clock). These can be safely shortened at higher - * PIO modes. The DIOR/DIOW pulse width and recovery times only - * apply to PIO modes, not to the DMA modes. - */ - - /* - * Enable port 0x44. The IT8172G spec is confused; it calls - * this register the "Slave IDE Timing Register", but in fact, - * it controls timing for both master and slave drives. - */ - drive_enables |= 0x4000; - - if (is_slave) { - drive_enables &= 0xc006; - if (pio > 1) - /* enable prefetch and IORDY sample-point */ - drive_enables |= 0x0060; - } else { - drive_enables &= 0xc060; - if (pio > 1) - /* enable prefetch and IORDY sample-point */ - drive_enables |= 0x0006; - } - - pci_write_config_word(dev, 0x40, drive_enables); - spin_unlock_irqrestore(&ide_lock, flags); -} - -static u8 it8172_dma_2_pio (u8 xfer_rate) -{ - switch(xfer_rate) { - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_PIO_4: - return 4; - case XFER_MW_DMA_1: - case XFER_PIO_3: - return 3; - case XFER_SW_DMA_2: - case XFER_PIO_2: - return 2; - case XFER_MW_DMA_0: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - case XFER_PIO_1: - case XFER_PIO_0: - case XFER_PIO_SLOW: - default: - return 0; - } -} - -static int it8172_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(it8172_ratemask(drive), xferspeed); - int a_speed = 3 << (drive->dn * 4); - int u_flag = 1 << drive->dn; - int u_speed = 0; - u8 reg48, reg4a; - - pci_read_config_byte(dev, 0x48, ®48); - pci_read_config_byte(dev, 0x4a, ®4a); - - /* - * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec - * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA - * transfers on some drives, even though both numbers meet the minimum - * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively. - * So the faster times are just commented out here. The good news is - * that the slower cycle time has very little affect on transfer - * performance. - */ - - switch(speed) { - case XFER_UDMA_4: - case XFER_UDMA_2: //u_speed = 2 << (drive->dn * 4); break; - case XFER_UDMA_5: - case XFER_UDMA_3: - case XFER_UDMA_1: //u_speed = 1 << (drive->dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - case XFER_SW_DMA_2: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_0: break; - default: return -1; - } - - if (speed >= XFER_UDMA_0) { - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - reg4a &= ~a_speed; - pci_write_config_byte(dev, 0x4a, reg4a | u_speed); - } else { - pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); - pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed); - } - - it8172_tune_drive(drive, it8172_dma_2_pio(speed)); - return (ide_config_drive_speed(drive, speed)); -} - -static int it8172_config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, it8172_ratemask(drive)); - - if (!(speed)) { - u8 tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL); - speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed); - } - - (void) it8172_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -static int it8172_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - drive->init_speed = 0; - - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (it8172_config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - it8172_tune_drive(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -static unsigned int __devinit init_chipset_it8172 (struct pci_dev *dev, const char *name) -{ - unsigned char progif; - - /* - * Place both IDE interfaces into PCI "native" mode - */ - pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); - pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05); - - return IT8172_IDE_IRQ; -} - - -static void __devinit init_hwif_it8172 (ide_hwif_t *hwif) -{ - struct pci_dev* dev = hwif->pci_dev; - unsigned long cmdBase, ctrlBase; - - hwif->autodma = 0; - hwif->tuneproc = &it8172_tune_drive; - hwif->speedproc = &it8172_tune_chipset; - - cmdBase = dev->resource[0].start; - ctrlBase = dev->resource[1].start; - - ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL); - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->noprobe = 0; - - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x07; - hwif->mwdma_mask = 0x06; - hwif->swdma_mask = 0x04; - - hwif->ide_dma_check = &it8172_config_drive_xfer_rate; - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t it8172_chipsets[] __devinitdata = { - { /* 0 */ - .name = "IT8172G", - .init_chipset = init_chipset_it8172, - .init_hwif = init_hwif_it8172, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x40,0x00,0x01}}, - .bootable = ON_BOARD, - } -}; - -static int __devinit it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - if ((!(PCI_FUNC(dev->devfn) & 1) || - (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))) - return -ENODEV; /* IT8172 is more than an IDE controller */ - return ide_setup_pci_device(dev, &it8172_chipsets[id->driver_data]); -} - -static struct pci_device_id it8172_pci_tbl[] = { - { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, it8172_pci_tbl); - -static struct pci_driver driver = { - .name = "IT8172_IDE", - .id_table = it8172_pci_tbl, - .probe = it8172_init_one, -}; - -static int it8172_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(it8172_ide_init); - -MODULE_AUTHOR("SteveL@mvista.com"); -MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE"); -MODULE_LICENSE("GPL"); diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index 78c35ec46362..1e5ccdad3b02 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -124,12 +124,6 @@ #define MACH_MOMENCO_JAGUAR_ATX 3 #define MACH_MOMENCO_OCELOT_3 4 -/* - * Valid machtype for group ITE - */ -#define MACH_GROUP_ITE 13 /* ITE Semi Eval Boards */ -#define MACH_QED_4N_S01B 0 /* ITE8172 based eval board */ - /* * Valid machtype for group PHILIPS */ @@ -138,12 +132,6 @@ #define MACH_PHILIPS_VELO 1 /* Velo */ #define MACH_PHILIPS_JBS 2 /* JBS */ -/* - * Valid machtype for group Globespan - */ -#define MACH_GROUP_GLOBESPAN 15 /* Globespan */ -#define MACH_IVR 0 /* IVR eval board */ - /* * Valid machtype for group SIBYTE */ diff --git a/include/asm-mips/it8172/it8172.h b/include/asm-mips/it8172/it8172.h deleted file mode 100644 index 8f23af0a1ee8..000000000000 --- a/include/asm-mips/it8172/it8172.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * IT8172 system controller defines. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __IT8172__H__ -#define __IT8172__H__ - -#include - -#define IT8172_BASE 0x18000000 -#define IT8172_PCI_IO_BASE 0x14000000 -#define IT8172_PCI_MEM_BASE 0x10000000 - -// System registers offsets from IT8172_BASE -#define IT_CMFPCR 0x0 -#define IT_DSRR 0x2 -#define IT_PCDCR 0x4 -#define IT_SPLLCR 0x6 -#define IT_CIDR 0x10 -#define IT_CRNR 0x12 -#define IT_CPUTR 0x14 -#define IT_CTCR 0x16 -#define IT_SDPR 0xF0 - -// Power management register offset from IT8172_PCI_IO_BASE -// Power Management Device Standby Register -#define IT_PM_DSR 0x15800 - -#define IT_PM_DSR_TMR0SB 0x0001 -#define IT_PM_DSR_TMR1SB 0x0002 -#define IT_PM_DSR_CIR0SB 0x0004 -#define IT_PM_DSR_CIR1SB 0x0008 -#define IT_PM_DSR_SCR0SB 0x0010 -#define IT_PM_DSR_SCR1SB 0x0020 -#define IT_PM_DSR_PPSB 0x0040 -#define IT_PM_DSR_I2CSB 0x0080 -#define IT_PM_DSR_UARTSB 0x0100 -#define IT_PM_DSR_IDESB 0x0200 -#define IT_PM_DSR_ACSB 0x0400 -#define IT_PM_DSR_M68KSB 0x0800 - -// Power Management PCI Device Software Reset Register -#define IT_PM_PCISR 0x15802 - -#define IT_PM_PCISR_IDESR 0x0001 -#define IT_PM_PCISR_CDMASR 0x0002 -#define IT_PM_PCISR_USBSR 0x0004 -#define IT_PM_PCISR_DMASR 0x0008 -#define IT_PM_PCISR_ACSR 0x0010 -#define IT_PM_PCISR_MEMSR 0x0020 -#define IT_PM_PCISR_68KSR 0x0040 - - -// PCI Configuration address and data register offsets -// from IT8172_BASE -#define IT_CONFADDR 0x4000 -#define IT_BUSNUM_SHF 16 -#define IT_DEVNUM_SHF 11 -#define IT_FUNCNUM_SHF 8 -#define IT_REGNUM_SHF 2 - -#define IT_CONFDATA 0x4004 - -// PCI configuration header common register offsets -#define IT_VID 0x00 -#define IT_DID 0x02 -#define IT_PCICMD 0x04 -#define IT_PCISTS 0x06 -#define IT_RID 0x08 -#define IT_CLASSC 0x09 -#define IT_HEADT 0x0E -#define IT_SERIRQC 0x49 - -// PCI to Internal/LPC Bus Bridge configuration header register offset -#define IT_P2I_BCR 0x4C -#define IT_P2I_D0IOSC 0x50 -#define IT_P2I_D1IOSC 0x54 -#define IT_P2I_D2IOSC 0x58 -#define IT_P2I_D3IOSC 0x5C -#define IT_P2I_D4IOSC 0x60 -#define IT_P2I_D5IOSC 0x64 -#define IT_P2I_D6IOSC 0x68 -#define IT_P2I_D7IOSC 0x6C -#define IT_P2I_D8IOSC 0x70 -#define IT_P2I_D9IOSC 0x74 -#define IT_P2I_D10IOSC 0x78 -#define IT_P2I_D11IOSC 0x7C - -// Memory controller register offsets from IT8172_BASE -#define IT_MC_SDRMR 0x1000 -#define IT_MC_SDRTR 0x1004 -#define IT_MC_MCR 0x1008 -#define IT_MC_SDTYPE 0x100C -#define IT_MC_WPBA 0x1010 -#define IT_MC_WPTA 0x1014 -#define IT_MC_HATR 0x1018 -#define IT_MC_PCICR 0x101C - -// Flash/ROM control register offsets from IT8172_BASE -#define IT_FC_BRCR 0x2000 -#define IT_FC_FCR 0x2004 -#define IT_FC_DCR 0x2008 - -// M68K interface bridge configuration header register offset -#define IT_M68K_MBCSR 0x54 -#define IT_M68K_TMR 0x58 -#define IT_M68K_BCR 0x5C -#define IT_M68K_BSR 0x5D -#define IT_M68K_DTR 0x5F - -// Register offset from IT8172_PCI_IO_BASE -// These registers are accessible through 8172 PCI IO window. - -// INTC -#define IT_INTC_BASE 0x10000 -#define IT_INTC_LBDNIRR 0x10000 -#define IT_INTC_LBDNIMR 0x10002 -#define IT_INTC_LBDNITR 0x10004 -#define IT_INTC_LBDNIAR 0x10006 -#define IT_INTC_LPCNIRR 0x10010 -#define IT_INTC_LPCNIMR 0x10012 -#define IT_INTC_LPCNITR 0x10014 -#define IT_INTC_LPCNIAR 0x10016 -#define IT_INTC_PDNIRR 0x10020 -#define IT_INTC_PDNIMR 0x10022 -#define IT_INTC_PDNITR 0x10024 -#define IT_INTC_PDNIAR 0x10026 -#define IT_INTC_UMNIRR 0x10030 -#define IT_INTC_UMNITR 0x10034 -#define IT_INTC_UMNIAR 0x10036 -#define IT_INTC_TYPER 0x107FE - -// IT8172 PCI device number -#define IT_C2P_DEVICE 0 -#define IT_AUDIO_DEVICE 1 -#define IT_DMAC_DEVICE 1 -#define IT_CDMAC_DEVICE 1 -#define IT_USB_DEVICE 1 -#define IT_P2I_DEVICE 1 -#define IT_IDE_DEVICE 1 -#define IT_M68K_DEVICE 1 - -// IT8172 PCI function number -#define IT_C2P_FUNCION 0 -#define IT_AUDIO_FUNCTION 0 -#define IT_DMAC_FUNCTION 1 -#define IT_CDMAC_FUNCTION 2 -#define IT_USB_FUNCTION 3 -#define IT_P2I_FUNCTION 4 -#define IT_IDE_FUNCTION 5 -#define IT_M68K_FUNCTION 6 - -// IT8172 GPIO -#define IT_GPADR 0x13800 -#define IT_GPBDR 0x13808 -#define IT_GPCDR 0x13810 -#define IT_GPACR 0x13802 -#define IT_GPBCR 0x1380A -#define IT_GPCCR 0x13812 -#define IT_GPAICR 0x13804 -#define IT_GPBICR 0x1380C -#define IT_GPCICR 0x13814 -#define IT_GPAISR 0x13806 -#define IT_GPBISR 0x1380E -#define IT_GPCISR 0x13816 -#define IT_GCR 0x13818 - -// IT8172 RTC -#define IT_RTC_BASE 0x14800 -#define IT_RTC_CENTURY 0x14808 - -#define IT_RTC_RIR0 0x00 -#define IT_RTC_RTR0 0x01 -#define IT_RTC_RIR1 0x02 -#define IT_RTC_RTR1 0x03 -#define IT_RTC_RIR2 0x04 -#define IT_RTC_RTR2 0x05 -#define IT_RTC_RCTR 0x08 -#define IT_RTC_RA 0x0A -#define IT_RTC_RB 0x0B -#define IT_RTC_RC 0x0C -#define IT_RTC_RD 0x0D - -#define RTC_SEC_INDEX 0x00 -#define RTC_MIN_INDEX 0x02 -#define RTC_HOUR_INDEX 0x04 -#define RTC_DAY_INDEX 0x06 -#define RTC_DATE_INDEX 0x07 -#define RTC_MONTH_INDEX 0x08 -#define RTC_YEAR_INDEX 0x09 - -// IT8172 internal device registers -#define IT_TIMER_BASE 0x10800 -#define IT_CIR0_BASE 0x11000 -#define IT_UART_BASE 0x11800 -#define IT_SCR0_BASE 0x12000 -#define IT_SCR1_BASE 0x12800 -#define IT_PP_BASE 0x13000 -#define IT_I2C_BASE 0x14000 -#define IT_CIR1_BASE 0x15000 - -// IT8172 Smart Card Reader offsets from IT_SCR*_BASE -#define IT_SCR_SFR 0x08 -#define IT_SCR_SCDR 0x09 - -// IT8172 IT_SCR_SFR bit definition & mask -#define IT_SCR_SFR_GATE_UART 0x40 -#define IT_SCR_SFR_GATE_UART_BIT 6 -#define IT_SCR_SFR_GATE_UART_OFF 0 -#define IT_SCR_SFR_GATE_UART_ON 1 -#define IT_SCR_SFR_FET_CHARGE 0x30 -#define IT_SCR_SFR_FET_CHARGE_BIT 4 -#define IT_SCR_SFR_FET_CHARGE_3_3_US 3 -#define IT_SCR_SFR_FET_CHARGE_13_US 2 -#define IT_SCR_SFR_FET_CHARGE_53_US 1 -#define IT_SCR_SFR_FET_CHARGE_213_US 0 -#define IT_SCR_SFR_CARD_FREQ 0x0C -#define IT_SCR_SFR_CARD_FREQ_BIT 2 -#define IT_SCR_SFR_CARD_FREQ_STOP 3 -#define IT_SCR_SFR_CARD_FREQ_3_5_MHZ 0 -#define IT_SCR_SFR_CARD_FREQ_7_1_MHZ 2 -#define IT_SCR_SFR_CARD_FREQ_96_DIV_MHZ 1 -#define IT_SCR_SFR_FET_ACTIVE 0x02 -#define IT_SCR_SFR_FET_ACTIVE_BIT 1 -#define IT_SCR_SFR_FET_ACTIVE_INVERT 0 -#define IT_SCR_SFR_FET_ACTIVE_NONINVERT 1 -#define IT_SCR_SFR_ENABLE 0x01 -#define IT_SCR_SFR_ENABLE_BIT 0 -#define IT_SCR_SFR_ENABLE_OFF 0 -#define IT_SCR_SFR_ENABLE_ON 1 - -// IT8172 IT_SCR_SCDR bit definition & mask -#define IT_SCR_SCDR_RESET_MODE 0x80 -#define IT_SCR_SCDR_RESET_MODE_BIT 7 -#define IT_SCR_SCDR_RESET_MODE_ASYNC 0 -#define IT_SCR_SCDR_RESET_MODE_SYNC 1 -#define IT_SCR_SCDR_DIVISOR 0x7F -#define IT_SCR_SCDR_DIVISOR_BIT 0 -#define IT_SCR_SCDR_DIVISOR_STOP_VAL_1 0x00 -#define IT_SCR_SCDR_DIVISOR_STOP_VAL_2 0x01 -#define IT_SCR_SCDR_DIVISOR_STOP_VAL_3 0x7F - -// IT8172 DMA -#define IT_DMAC_BASE 0x16000 -#define IT_DMAC_BCAR0 0x00 -#define IT_DMAC_BCAR1 0x04 -#define IT_DMAC_BCAR2 0x08 -#define IT_DMAC_BCAR3 0x0C -#define IT_DMAC_BCCR0 0x02 -#define IT_DMAC_BCCR1 0x06 -#define IT_DMAC_BCCR2 0x0a -#define IT_DMAC_BCCR3 0x0e -#define IT_DMAC_CR 0x10 -#define IT_DMAC_SR 0x12 -#define IT_DMAC_ESR 0x13 -#define IT_DMAC_RQR 0x14 -#define IT_DMAC_MR 0x16 -#define IT_DMAC_EMR 0x17 -#define IT_DMAC_MKR 0x18 -#define IT_DMAC_PAR0 0x20 -#define IT_DMAC_PAR1 0x22 -#define IT_DMAC_PAR2 0x24 -#define IT_DMAC_PAR3 0x26 - -// IT8172 IDE -#define IT_IDE_BASE 0x17800 -#define IT_IDE_STATUS 0x1F7 - -// IT8172 Audio Controller -#define IT_AC_BASE 0x17000 -#define IT_AC_PCMOV 0x00 -#define IT_AC_FMOV 0x02 -#define IT_AC_I2SV 0x04 -#define IT_AC_DRSS 0x06 -#define IT_AC_PCC 0x08 -#define IT_AC_PCDL 0x0A -#define IT_AC_PCB1STA 0x0C -#define IT_AC_PCB2STA 0x10 -#define IT_AC_CAPCC 0x14 -#define IT_AC_CAPCDL 0x16 -#define IT_AC_CAPB1STA 0x18 -#define IT_AC_CAPB2STA 0x1C -#define IT_AC_CODECC 0x22 -#define IT_AC_I2SMC 0x24 -#define IT_AC_VS 0x26 -#define IT_AC_SRCS 0x28 -#define IT_AC_CIRCP 0x2A -#define IT_AC_CIRDP 0x2C -#define IT_AC_TM 0x4A -#define IT_AC_PFDP 0x4C -#define IT_AC_GC 0x54 -#define IT_AC_IMC 0x56 -#define IT_AC_ISC 0x5B -#define IT_AC_OPL3SR 0x68 -#define IT_AC_OPL3DWDR 0x69 -#define IT_AC_OPL3AB1W 0x6A -#define IT_AC_OPL3DW 0x6B -#define IT_AC_BPDC 0x70 - - -// IT8172 Timer -#define IT_TIMER_BASE 0x10800 -#define TIMER_TCVR0 0x00 -#define TIMER_TRVR0 0x02 -#define TIMER_TCR0 0x04 -#define TIMER_TIRR 0x06 -#define TIMER_TCVR1 0x08 -#define TIMER_TRVR1 0x0A -#define TIMER_TCR1 0x0C -#define TIMER_TIDR 0x0E - - -#define IT_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) = data -#define IT_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) - -#define IT_IO_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data -#define IT_IO_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) - -#define IT_IO_WRITE16(ofs, data) *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data -#define IT_IO_READ16(ofs, data) data = *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) - -#endif diff --git a/include/asm-mips/it8172/it8172_cir.h b/include/asm-mips/it8172/it8172_cir.h deleted file mode 100644 index 6a1dbd29f6d1..000000000000 --- a/include/asm-mips/it8172/it8172_cir.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * IT8172 Consumer IR port defines. - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define NUM_CIR_PORTS 2 - -/* Master Control Register */ -#define CIR_RESET 0x1 -#define CIR_FIFO_CLEAR 0x2 -#define CIR_SET_FIFO_TL(x) (((x)&0x3)<<2) -#define CIR_ILE 0x10 -#define CIR_ILSEL 0x20 - -/* Interrupt Enable Register */ -#define CIR_TLDLIE 0x1 -#define CIR_RDAIE 0x2 -#define CIR_RFOIE 0x4 -#define CIR_IEC 0x80 - -/* Interrupt Identification Register */ -#define CIR_TLDLI 0x1 -#define CIR_RDAI 0x2 -#define CIR_RFOI 0x4 -#define CIR_NIP 0x80 - -/* Carrier Frequency Register */ -#define CIR_SET_CF(x) ((x)&0x1f) - #define CFQ_38_480 0xB /* 38 KHz low, 480 KHz high */ -#define CIR_HCFS 0x20 - #define CIR_SET_HS(x) (((x)&0x1)<<5) - - -/* Receiver Control Register */ -#define CIR_SET_RXDCR(x) ((x)&0x7) -#define CIR_RXACT 0x8 -#define CIR_RXEND 0x10 -#define CIR_RDWOS 0x20 - #define CIR_SET_RDWOS(x) (((x)&0x1)<<5) -#define CIR_RXEN 0x80 - -/* Transmitter Control Register */ -#define CIR_SET_TXMPW(x) ((x)&0x7) -#define CIR_SET_TXMPM(x) (((x)&0x3)<<3) -#define CIR_TXENDF 0x20 -#define CIR_TXRLE 0x40 - -/* Receiver FIFO Status Register */ -#define CIR_RXFBC_MASK 0x3f -#define CIR_RXFTO 0x80 - -/* Wakeup Code Length Register */ -#define CIR_SET_WCL ((x)&0x3f) -#define CIR_WCL_MASK(x) ((x)&0x3f) - -/* Wakeup Power Control/Status Register */ -#define CIR_BTMON 0x2 -#define CIR_CIRON 0x4 -#define CIR_RCRST 0x10 -#define CIR_WCRST 0x20 - -struct cir_port { - int port; - unsigned short baud_rate; - unsigned char fifo_tl; - unsigned char cfq; - unsigned char hcfs; - unsigned char rdwos; - unsigned char rxdcr; -}; - -struct it8172_cir_regs { - unsigned char dr; /* data */ - char pad; - unsigned char mstcr; /* master control */ - char pad1; - unsigned char ier; /* interrupt enable */ - char pad2; - unsigned char iir; /* interrupt identification */ - char pad3; - unsigned char cfr; /* carrier frequency */ - char pad4; - unsigned char rcr; /* receiver control */ - char pad5; - unsigned char tcr; /* transmitter control */ - char pad6; - char pad7; - char pad8; - unsigned char bdlr; /* baud rate divisor low byte */ - char pad9; - unsigned char bdhr; /* baud rate divisor high byte */ - char pad10; - unsigned char tfsr; /* tx fifo byte count */ - char pad11; - unsigned char rfsr; /* rx fifo status */ - char pad12; - unsigned char wcl; /* wakeup code length */ - char pad13; - unsigned char wcr; /* wakeup code read/write */ - char pad14; - unsigned char wps; /* wakeup power control/status */ -}; - -int cir_port_init(struct cir_port *cir); -extern void clear_fifo(struct cir_port *cir); -extern void enable_receiver(struct cir_port *cir); -extern void disable_receiver(struct cir_port *cir); -extern void enable_rx_demodulation(struct cir_port *cir); -extern void disable_rx_demodulation(struct cir_port *cir); -extern void set_rx_active(struct cir_port *cir); -extern void int_enable(struct cir_port *cir); -extern void rx_int_enable(struct cir_port *cir); -extern char get_int_status(struct cir_port *cir); -extern int cir_get_rx_count(struct cir_port *cir); -extern char cir_read_data(struct cir_port *cir); diff --git a/include/asm-mips/it8172/it8172_dbg.h b/include/asm-mips/it8172/it8172_dbg.h deleted file mode 100644 index f404ec7c03ac..000000000000 --- a/include/asm-mips/it8172/it8172_dbg.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * Function prototypes for low level uart routines to - * directly access a 16550 uart. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -extern void putch(const unsigned char c); -extern void puts(unsigned char *cp); -extern void fputs(unsigned char *cp); -extern void put64(uint64_t ul); -extern void put32(unsigned u); diff --git a/include/asm-mips/it8172/it8172_int.h b/include/asm-mips/it8172/it8172_int.h deleted file mode 100644 index 837e83ac25f5..000000000000 --- a/include/asm-mips/it8172/it8172_int.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * ITE 8172 Interrupt Numbering - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _MIPS_ITEINT_H -#define _MIPS_ITEINT_H - -/* - * Here's the "strategy": - * We number the LPC serial irqs from 0 to 15, - * the local bus irqs from 16 to 31, - * the pci dev register interrupts from 32 to 47, - * and the non-maskable ints from 48 to 53. - */ - -#define IT8172_LPC_IRQ_BASE 0 /* first LPC int number */ -#define IT8172_SERIRQ_0 (IT8172_LPC_IRQ_BASE + 0) -#define IT8172_SERIRQ_1 (IT8172_LPC_IRQ_BASE + 1) -#define IT8172_SERIRQ_2 (IT8172_LPC_IRQ_BASE + 2) -#define IT8172_SERIRQ_3 (IT8172_LPC_IRQ_BASE + 3) -#define IT8172_SERIRQ_4 (IT8172_LPC_IRQ_BASE + 4) -#define IT8172_SERIRQ_5 (IT8172_LPC_IRQ_BASE + 5) -#define IT8172_SERIRQ_6 (IT8172_LPC_IRQ_BASE + 6) -#define IT8172_SERIRQ_7 (IT8172_LPC_IRQ_BASE + 7) -#define IT8172_SERIRQ_8 (IT8172_LPC_IRQ_BASE + 8) -#define IT8172_SERIRQ_9 (IT8172_LPC_IRQ_BASE + 9) -#define IT8172_SERIRQ_10 (IT8172_LPC_IRQ_BASE + 10) -#define IT8172_SERIRQ_11 (IT8172_LPC_IRQ_BASE + 11) -#define IT8172_SERIRQ_12 (IT8172_LPC_IRQ_BASE + 12) -#define IT8172_SERIRQ_13 (IT8172_LPC_IRQ_BASE + 13) -#define IT8172_SERIRQ_14 (IT8172_LPC_IRQ_BASE + 14) -#define IT8172_SERIRQ_15 (IT8172_LPC_IRQ_BASE + 15) - -#define IT8172_LB_IRQ_BASE 16 /* first local bus int number */ -#define IT8172_PPR_IRQ (IT8172_LB_IRQ_BASE + 0) /* parallel port */ -#define IT8172_TIMER0_IRQ (IT8172_LB_IRQ_BASE + 1) -#define IT8172_TIMER1_IRQ (IT8172_LB_IRQ_BASE + 2) -#define IT8172_I2C_IRQ (IT8172_LB_IRQ_BASE + 3) -#define IT8172_GPIO_IRQ (IT8172_LB_IRQ_BASE + 4) -#define IT8172_CIR0_IRQ (IT8172_LB_IRQ_BASE + 5) -#define IT8172_CIR1_IRQ (IT8172_LB_IRQ_BASE + 6) -#define IT8172_UART_IRQ (IT8172_LB_IRQ_BASE + 7) -#define IT8172_SCR0_IRQ (IT8172_LB_IRQ_BASE + 8) -#define IT8172_SCR1_IRQ (IT8172_LB_IRQ_BASE + 9) -#define IT8172_RTC_IRQ (IT8172_LB_IRQ_BASE + 10) -#define IT8172_IOCHK_IRQ (IT8172_LB_IRQ_BASE + 11) -/* 12 - 15 reserved */ - -/* - * Note here that the pci dev registers includes bits for more than - * just the pci devices. - */ -#define IT8172_PCI_DEV_IRQ_BASE 32 /* first pci dev irq */ -#define IT8172_AC97_IRQ (IT8172_PCI_DEV_IRQ_BASE + 0) -#define IT8172_MC68K_IRQ (IT8172_PCI_DEV_IRQ_BASE + 1) -#define IT8172_IDE_IRQ (IT8172_PCI_DEV_IRQ_BASE + 2) -#define IT8172_USB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 3) -#define IT8172_BRIDGE_MASTER_IRQ (IT8172_PCI_DEV_IRQ_BASE + 4) -#define IT8172_BRIDGE_TARGET_IRQ (IT8172_PCI_DEV_IRQ_BASE + 5) -#define IT8172_PCI_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 6) -#define IT8172_PCI_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 7) -#define IT8172_PCI_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 8) -#define IT8172_PCI_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 9) -#define IT8172_S_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 10) -#define IT8172_S_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 11) -#define IT8172_S_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 12) -#define IT8172_S_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 13) -#define IT8172_CDMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 14) -#define IT8172_DMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 15) - -#define IT8172_NMI_IRQ_BASE 48 -#define IT8172_SER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 0) -#define IT8172_PCI_NMI_IRQ (IT8172_NMI_IRQ_BASE + 1) -#define IT8172_RTC_NMI_IRQ (IT8172_NMI_IRQ_BASE + 2) -#define IT8172_CPUIF_NMI_IRQ (IT8172_NMI_IRQ_BASE + 3) -#define IT8172_PMER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 4) -#define IT8172_POWER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 5) - -#define IT8172_LAST_IRQ (IT8172_POWER_NMI_IRQ) -/* Finally, let's move over here the mips cpu timer interrupt. - */ -#define MIPS_CPU_TIMER_IRQ (NR_IRQS-1) - -/* - * IT8172 Interrupt Controller Registers - */ -struct it8172_intc_regs { - volatile unsigned short lb_req; /* offset 0 */ - volatile unsigned short lb_mask; - volatile unsigned short lb_trigger; - volatile unsigned short lb_level; - unsigned char pad0[8]; - - volatile unsigned short lpc_req; /* offset 0x10 */ - volatile unsigned short lpc_mask; - volatile unsigned short lpc_trigger; - volatile unsigned short lpc_level; - unsigned char pad1[8]; - - volatile unsigned short pci_req; /* offset 0x20 */ - volatile unsigned short pci_mask; - volatile unsigned short pci_trigger; - volatile unsigned short pci_level; - unsigned char pad2[8]; - - volatile unsigned short nmi_req; /* offset 0x30 */ - volatile unsigned short nmi_mask; - volatile unsigned short nmi_trigger; - volatile unsigned short nmi_level; - unsigned char pad3[6]; - - volatile unsigned short nmi_redir; /* offset 0x3E */ - unsigned char pad4[0xBE]; - - volatile unsigned short intstatus; /* offset 0xFE */ -}; - -#endif /* _MIPS_ITEINT_H */ diff --git a/include/asm-mips/it8172/it8172_pci.h b/include/asm-mips/it8172/it8172_pci.h deleted file mode 100644 index 42c61f56eeba..000000000000 --- a/include/asm-mips/it8172/it8172_pci.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * IT8172 system controller specific pci defines. - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _8172PCI_H_ -#define _8172PCI_H_ - -// PCI configuration space Type0 -#define PCI_IDREG 0x00 -#define PCI_CMDSTSREG 0x04 -#define PCI_CLASSREG 0x08 -#define PCI_BHLCREG 0x0C -#define PCI_BASE1REG 0x10 -#define PCI_BASE2REG 0x14 -#define PCI_BASE3REG 0x18 -#define PCI_BASE4REG 0x1C -#define PCI_BASE5REG 0x20 -#define PCI_BASE6REG 0x24 -#define PCI_ROMBASEREG 0x30 -#define PCI_INTRREG 0x3C - -// PCI configuration space Type1 -#define PCI_BUSNOREG 0x18 - -#define IT_PCI_VENDORID(x) ((x) & 0xFFFF) -#define IT_PCI_DEVICEID(x) (((x)>>16) & 0xFFFF) - -// Command register -#define PCI_CMD_IOEN 0x00000001 -#define PCI_CMD_MEMEN 0x00000002 -#define PCI_CMD_BUSMASTER 0x00000004 -#define PCI_CMD_SPCYCLE 0x00000008 -#define PCI_CMD_WRINV 0x00000010 -#define PCI_CMD_VGASNOOP 0x00000020 -#define PCI_CMD_PERR 0x00000040 -#define PCI_CMD_WAITCTRL 0x00000080 -#define PCI_CMD_SERR 0x00000100 -#define PCI_CMD_FAST_BACKTOBACK 0x00000200 - -// Status register -#define PCI_STS_66MHZ 0x00200000 -#define PCI_STS_SUPPORT_UDF 0x00400000 -#define PCI_STS_FAST_BACKTOBACK 0x00800000 -#define PCI_STS_DATA_PERR 0x01000000 -#define PCI_STS_DEVSEL0 0x02000000 -#define PCI_STS_DEVSEL1 0x04000000 -#define PCI_STS_SIG_TGTABORT 0x08000000 -#define PCI_STS_RCV_TGTABORT 0x10000000 -#define PCI_STS_RCV_MSTABORT 0x20000000 -#define PCI_STS_SYSERR 0x40000000 -#define PCI_STS_DETCT_PERR 0x80000000 - -#define IT_PCI_CLASS(x) (((x)>>24) & 0xFF) -#define IT_PCI_SUBCLASS(x) (((x)>>16) & 0xFF) -#define IT_PCI_INTERFACE(x) (((x)>>8) & 0xFF) -#define IT_PCI_REVISION(x) ((x) & 0xFF) - -// PCI class code -#define PCI_CLASS_BRIDGE 0x06 - -// bridge subclass -#define PCI_SUBCLASS_BRIDGE_HOST 0x00 -#define PCI_SUBCLASS_BRIDGE_PCI 0x04 - -// BHLCREG -#define IT_PCI_BIST(x) (((x)>>24) & 0xFF) -#define IT_PCI_HEADERTYPE(x) (((x)>>16) & 0xFF) -#define IT_PCI_LATENCYTIMER(x) (((x)>>8) & 0xFF) -#define IT_PCI_CACHELINESIZE(x) ((x) & 0xFF) - -#define PCI_MULTIFUNC 0x80 - -// INTRREG -#define IT_PCI_MAXLAT(x) (((x)>>24) & 0xFF) -#define IT_PCI_MINGNT(x) (((x)>>16) & 0xFF) -#define IT_PCI_INTRPIN(x) (((x)>>8) & 0xFF) -#define IT_PCI_INTRLINE(x) ((x) & 0xFF) - -#define PCI_VENDOR_NEC 0x1033 -#define PCI_VENDOR_DEC 0x1101 - -#endif // _8172PCI_H_ diff --git a/include/asm-mips/it8712.h b/include/asm-mips/it8712.h deleted file mode 100644 index ca2dee02a011..000000000000 --- a/include/asm-mips/it8712.h +++ /dev/null @@ -1,28 +0,0 @@ - -#ifndef __IT8712_H__ -#define __IT8712_H__ - -#define LPC_BASE_ADDR 0x14000000 - -// MB PnP configuration register -#define LPC_KEY_ADDR 0x1400002E -#define LPC_DATA_ADDR 0x1400002F - -// Device LDN -#define LDN_SERIAL1 0x01 -#define LDN_SERIAL2 0x02 -#define LDN_PARALLEL 0x03 -#define LDN_KEYBOARD 0x05 -#define LDN_MOUSE 0x06 - -#define IT8712_UART1_PORT 0x3F8 -#define IT8712_UART2_PORT 0x2F8 - -#ifndef ASM_ONLY - -void LPCSetConfig(char LdnNumber, char Index, char data); -char LPCGetConfig(char LdnNumber, char Index); - -#endif - -#endif diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h index c882e04e1497..d7a65135d837 100644 --- a/include/asm-mips/serial.h +++ b/include/asm-mips/serial.h @@ -69,38 +69,6 @@ #define EV64120_SERIAL_PORT_DEFNS #endif -#ifdef CONFIG_MIPS_ITE8172 -#include -#include -#include -#define ITE_SERIAL_PORT_DEFNS \ - { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_UART_BASE), \ - .irq = IT8172_UART_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \ - { .baud_base = (24000000/(16*13)), .port = (IT8172_PCI_IO_BASE + IT8712_UART1_PORT), \ - .irq = IT8172_SERIRQ_4, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \ - /* Smart Card Reader 0 */ \ - { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR0_BASE), \ - .irq = IT8172_SCR0_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \ - /* Smart Card Reader 1 */ \ - { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR1_BASE), \ - .irq = IT8172_SCR1_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, -#else -#define ITE_SERIAL_PORT_DEFNS -#endif - -#ifdef CONFIG_MIPS_IVR -#include -#include -#define IVR_SERIAL_PORT_DEFNS \ - { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_UART_BASE), \ - .irq = IT8172_UART_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \ - /* Smart Card Reader 1 */ \ - { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR1_BASE), \ - .irq = IT8172_SCR1_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, -#else -#define IVR_SERIAL_PORT_DEFNS -#endif - #ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT #define STD_SERIAL_PORT_DEFNS \ /* UART CLK PORT IRQ FLAGS */ \ @@ -240,8 +208,6 @@ DDB5477_SERIAL_PORT_DEFNS \ EV64120_SERIAL_PORT_DEFNS \ IP32_SERIAL_PORT_DEFNS \ - ITE_SERIAL_PORT_DEFNS \ - IVR_SERIAL_PORT_DEFNS \ JAZZ_SERIAL_PORT_DEFNS \ STD_SERIAL_PORT_DEFNS \ MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS \ diff --git a/include/linux/ite_gpio.h b/include/linux/ite_gpio.h deleted file mode 100644 index b123a14292d3..000000000000 --- a/include/linux/ite_gpio.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * FILE NAME ite_gpio.h - * - * BRIEF MODULE DESCRIPTION - * Generic gpio. - * - * Author: MontaVista Software, Inc. - * Hai-Pao Fan - * - * Copyright 2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ITE_GPIO_H -#define __ITE_GPIO_H - -#include - -struct ite_gpio_ioctl_data { - __u32 device; - __u32 mask; - __u32 data; -}; - -#define ITE_GPIO_IOCTL_BASE 'Z' - -#define ITE_GPIO_IN _IOWR(ITE_GPIO_IOCTL_BASE, 0, struct ite_gpio_ioctl_data) -#define ITE_GPIO_OUT _IOW (ITE_GPIO_IOCTL_BASE, 1, struct ite_gpio_ioctl_data) -#define ITE_GPIO_INT_CTRL _IOW (ITE_GPIO_IOCTL_BASE, 2, struct ite_gpio_ioctl_data) -#define ITE_GPIO_IN_STATUS _IOW (ITE_GPIO_IOCTL_BASE, 3, struct ite_gpio_ioctl_data) -#define ITE_GPIO_OUT_STATUS _IOW (ITE_GPIO_IOCTL_BASE, 4, struct ite_gpio_ioctl_data) -#define ITE_GPIO_GEN_CTRL _IOW (ITE_GPIO_IOCTL_BASE, 5, struct ite_gpio_ioctl_data) -#define ITE_GPIO_INT_WAIT _IOW (ITE_GPIO_IOCTL_BASE, 6, struct ite_gpio_ioctl_data) - -#define ITE_GPIO_PORTA 0x01 -#define ITE_GPIO_PORTB 0x02 -#define ITE_GPIO_PORTC 0x04 - -extern int ite_gpio_in(__u32 device, __u32 mask, volatile __u32 *data); -extern int ite_gpio_out(__u32 device, __u32 mask, __u32 data); -extern int ite_gpio_int_ctrl(__u32 device, __u32 mask, __u32 data); -extern int ite_gpio_in_status(__u32 device, __u32 mask, volatile __u32 *data); -extern int ite_gpio_out_status(__u32 device, __u32 mask, __u32 data); -extern int ite_gpio_gen_ctrl(__u32 device, __u32 mask, __u32 data); -extern int ite_gpio_int_wait(__u32 device, __u32 mask, __u32 data); - -#endif diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index dc7f573d36e4..f069df245469 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1615,8 +1615,6 @@ #define PCI_VENDOR_ID_ROCKWELL 0x127A #define PCI_VENDOR_ID_ITE 0x1283 -#define PCI_DEVICE_ID_ITE_IT8172G 0x8172 -#define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801 #define PCI_DEVICE_ID_ITE_8211 0x8211 #define PCI_DEVICE_ID_ITE_8212 0x8212 #define PCI_DEVICE_ID_ITE_8872 0x8872 diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 97e38b665587..f3b3530402cb 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -115,10 +115,6 @@ config SOUND_HAL2 Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to use its on-board A2 audio system. -config SOUND_IT8172 - tristate "IT8172G Sound" - depends on SOUND_PRIME && (MIPS_ITE8172 || MIPS_IVR) - config SOUND_VRC5477 tristate "NEC Vrc5477 AC97 sound" depends on SOUND_PRIME && DDB5477 diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 9bf3ee544d86..86811792002f 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -77,7 +77,6 @@ obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o obj-$(CONFIG_SOUND_BT878) += btaudio.o obj-$(CONFIG_SOUND_ALI5455) += ali5455.o ac97_codec.o -obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o obj-$(CONFIG_SOUND_FORTE) += forte.o ac97_codec.o obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o ac97_codec.o diff --git a/sound/oss/ite8172.c b/sound/oss/ite8172.c deleted file mode 100644 index 68aab3605d74..000000000000 --- a/sound/oss/ite8172.c +++ /dev/null @@ -1,2261 +0,0 @@ -/* - * ite8172.c -- ITE IT8172G Sound Driver. - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * stevel@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * Module command line parameters: - * - * Supported devices: - * /dev/dsp standard OSS /dev/dsp device - * /dev/mixer standard OSS /dev/mixer device - * - * Notes: - * - * 1. Much of the OSS buffer allocation, ioctl's, and mmap'ing are - * taken, slightly modified or not at all, from the ES1371 driver, - * so refer to the credits in es1371.c for those. The rest of the - * code (probe, open, read, write, the ISR, etc.) is new. - * 2. The following support is untested: - * * Memory mapping the audio buffers, and the ioctl controls that go - * with it. - * * S/PDIF output. - * * I2S support. - * 3. The following is not supported: - * * legacy audio mode. - * 4. Support for volume button interrupts is implemented but doesn't - * work yet. - * - * Revision history - * 02.08.2001 Initial release - * 06.22.2001 Added I2S support - * 07.30.2003 Removed initialisation to zero for static variables - * (spdif[NR_DEVICE], i2s_fmt[NR_DEVICE], and devindex) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* --------------------------------------------------------------------- */ - -#undef OSS_DOCUMENTED_MIXER_SEMANTICS -#define IT8172_DEBUG -#undef IT8172_VERBOSE_DEBUG -#define DBG(x) {} - -#define IT8172_MODULE_NAME "IT8172 audio" -#define PFX IT8172_MODULE_NAME - -#ifdef IT8172_DEBUG -#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) -#else -#define dbg(format, arg...) do {} while (0) -#endif -#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) -#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) -#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) - - -#define IT8172_MODULE_NAME "IT8172 audio" -#define PFX IT8172_MODULE_NAME - -#ifdef IT8172_DEBUG -#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) -#else -#define dbg(format, arg...) do {} while (0) -#endif -#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) -#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) -#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) - - -static const unsigned sample_shift[] = { 0, 1, 1, 2 }; - - -/* - * Audio Controller register bit definitions follow. See - * include/asm/it8172/it8172.h for register offsets. - */ - -/* PCM Out Volume Reg */ -#define PCMOV_PCMOM (1<<15) /* PCM Out Mute default 1: mute */ -#define PCMOV_PCMRCG_BIT 8 /* PCM Right channel Gain */ -#define PCMOV_PCMRCG_MASK (0x1f<= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -/* --------------------------------------------------------------------- */ - -static void it8172_delay(int msec) -{ - unsigned long tmo; - signed long tmo2; - - if (in_interrupt()) - return; - - tmo = jiffies + (msec*HZ)/1000; - for (;;) { - tmo2 = tmo - jiffies; - if (tmo2 <= 0) - break; - schedule_timeout(tmo2); - } -} - - -static unsigned short -get_compat_rate(unsigned* rate) -{ - unsigned rate_out = *rate; - unsigned short sr; - - if (rate_out >= 46050) { - sr = CC_SR_48000; rate_out = 48000; - } else if (rate_out >= 41250) { - sr = CC_SR_44100; rate_out = 44100; - } else if (rate_out >= 35200) { - sr = CC_SR_38400; rate_out = 38400; - } else if (rate_out >= 27025) { - sr = CC_SR_32000; rate_out = 32000; - } else if (rate_out >= 20625) { - sr = CC_SR_22050; rate_out = 22050; - } else if (rate_out >= 17600) { - sr = CC_SR_19200; rate_out = 19200; - } else if (rate_out >= 13513) { - sr = CC_SR_16000; rate_out = 16000; - } else if (rate_out >= 10313) { - sr = CC_SR_11025; rate_out = 11025; - } else if (rate_out >= 8800) { - sr = CC_SR_9600; rate_out = 9600; - } else if (rate_out >= 6750) { - sr = CC_SR_8000; rate_out = 8000; - } else { - sr = CC_SR_5500; rate_out = 5500; - } - - *rate = rate_out; - return sr; -} - -static void set_adc_rate(struct it8172_state *s, unsigned rate) -{ - unsigned long flags; - unsigned short sr; - - sr = get_compat_rate(&rate); - - spin_lock_irqsave(&s->lock, flags); - s->capcc &= ~CC_SR_MASK; - s->capcc |= sr; - outw(s->capcc, s->io+IT_AC_CAPCC); - spin_unlock_irqrestore(&s->lock, flags); - - s->adcrate = rate; -} - - -static void set_dac_rate(struct it8172_state *s, unsigned rate) -{ - unsigned long flags; - unsigned short sr; - - sr = get_compat_rate(&rate); - - spin_lock_irqsave(&s->lock, flags); - s->pcc &= ~CC_SR_MASK; - s->pcc |= sr; - outw(s->pcc, s->io+IT_AC_PCC); - spin_unlock_irqrestore(&s->lock, flags); - - s->dacrate = rate; -} - - -/* --------------------------------------------------------------------- */ - -static u16 rdcodec(struct ac97_codec *codec, u8 addr) -{ - struct it8172_state *s = (struct it8172_state *)codec->private_data; - unsigned long flags; - unsigned short circp, data; - int i; - - spin_lock_irqsave(&s->lock, flags); - - for (i = 0; i < POLL_COUNT; i++) - if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS)) - break; - if (i == POLL_COUNT) - err("rdcodec: codec ready poll expired!"); - - circp = addr & CIRCP_CIA_MASK; - circp |= (codec->id << CIRCP_CID_BIT); - circp |= CIRCP_RWC; // read command - outw(circp, s->io+IT_AC_CIRCP); - - /* now wait for the data */ - for (i = 0; i < POLL_COUNT; i++) - if (inw(s->io+IT_AC_CIRCP) & CIRCP_DPVF) - break; - if (i == POLL_COUNT) - err("rdcodec: read poll expired!"); - - data = inw(s->io+IT_AC_CIRDP); - spin_unlock_irqrestore(&s->lock, flags); - - return data; -} - - -static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data) -{ - struct it8172_state *s = (struct it8172_state *)codec->private_data; - unsigned long flags; - unsigned short circp; - int i; - - spin_lock_irqsave(&s->lock, flags); - - for (i = 0; i < POLL_COUNT; i++) - if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS)) - break; - if (i == POLL_COUNT) - err("wrcodec: codec ready poll expired!"); - - circp = addr & CIRCP_CIA_MASK; - circp |= (codec->id << CIRCP_CID_BIT); - circp &= ~CIRCP_RWC; // write command - - outw(data, s->io+IT_AC_CIRDP); // send data first - outw(circp, s->io+IT_AC_CIRCP); - - spin_unlock_irqrestore(&s->lock, flags); -} - - -static void waitcodec(struct ac97_codec *codec) -{ - unsigned short temp; - - /* codec_wait is used to wait for a ready state after - an AC97_RESET. */ - it8172_delay(10); - - temp = rdcodec(codec, 0x26); - - // If power down, power up - if (temp & 0x3f00) { - // Power on - wrcodec(codec, 0x26, 0); - it8172_delay(100); - // Reread - temp = rdcodec(codec, 0x26); - } - - // Check if Codec REF,ANL,DAC,ADC ready***/ - if ((temp & 0x3f0f) != 0x000f) { - err("codec reg 26 status (0x%x) not ready!!", temp); - return; - } -} - - -/* --------------------------------------------------------------------- */ - -static inline void stop_adc(struct it8172_state *s) -{ - struct dmabuf* db = &s->dma_adc; - unsigned long flags; - unsigned char imc; - - if (db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - s->capcc &= ~(CC_CA | CC_CP | CC_CB2L | CC_CB1L); - s->capcc |= CC_CSP; - outw(s->capcc, s->io+IT_AC_CAPCC); - - // disable capture interrupt - imc = inb(s->io+IT_AC_IMC); - outb(imc | IMC_CCIM, s->io+IT_AC_IMC); - - db->stopped = 1; - - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void stop_dac(struct it8172_state *s) -{ - struct dmabuf* db = &s->dma_dac; - unsigned long flags; - unsigned char imc; - - if (db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - s->pcc &= ~(CC_CA | CC_CP | CC_CB2L | CC_CB1L); - s->pcc |= CC_CSP; - outw(s->pcc, s->io+IT_AC_PCC); - - // disable playback interrupt - imc = inb(s->io+IT_AC_IMC); - outb(imc | IMC_PCIM, s->io+IT_AC_IMC); - - db->stopped = 1; - - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac(struct it8172_state *s) -{ - struct dmabuf* db = &s->dma_dac; - unsigned long flags; - unsigned char imc; - unsigned long buf1, buf2; - - if (!db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - // reset Buffer 1 and 2 pointers to nextOut and nextOut+fragsize - buf1 = virt_to_bus(db->nextOut); - buf2 = buf1 + db->fragsize; - if (buf2 >= db->dmaaddr + db->dmasize) - buf2 -= db->dmasize; - - outl(buf1, s->io+IT_AC_PCB1STA); - outl(buf2, s->io+IT_AC_PCB2STA); - db->curBufPtr = IT_AC_PCB1STA; - - // enable playback interrupt - imc = inb(s->io+IT_AC_IMC); - outb(imc & ~IMC_PCIM, s->io+IT_AC_IMC); - - s->pcc &= ~(CC_CSP | CC_CP | CC_CB2L | CC_CB1L); - s->pcc |= CC_CA; - outw(s->pcc, s->io+IT_AC_PCC); - - db->stopped = 0; - - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_adc(struct it8172_state *s) -{ - struct dmabuf* db = &s->dma_adc; - unsigned long flags; - unsigned char imc; - unsigned long buf1, buf2; - - if (!db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - // reset Buffer 1 and 2 pointers to nextIn and nextIn+fragsize - buf1 = virt_to_bus(db->nextIn); - buf2 = buf1 + db->fragsize; - if (buf2 >= db->dmaaddr + db->dmasize) - buf2 -= db->dmasize; - - outl(buf1, s->io+IT_AC_CAPB1STA); - outl(buf2, s->io+IT_AC_CAPB2STA); - db->curBufPtr = IT_AC_CAPB1STA; - - // enable capture interrupt - imc = inb(s->io+IT_AC_IMC); - outb(imc & ~IMC_CCIM, s->io+IT_AC_IMC); - - s->capcc &= ~(CC_CSP | CC_CP | CC_CB2L | CC_CB1L); - s->capcc |= CC_CA; - outw(s->capcc, s->io+IT_AC_CAPCC); - - db->stopped = 0; - - spin_unlock_irqrestore(&s->lock, flags); -} - -/* --------------------------------------------------------------------- */ - -#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - -static inline void dealloc_dmabuf(struct it8172_state *s, struct dmabuf *db) -{ - struct page *page, *pend; - - if (db->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(db->rawbuf + - (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - ClearPageReserved(page); - pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, - db->rawbuf, db->dmaaddr); - } - db->rawbuf = db->nextIn = db->nextOut = NULL; - db->mapped = db->ready = 0; -} - -static int prog_dmabuf(struct it8172_state *s, struct dmabuf *db, - unsigned rate, unsigned fmt, unsigned reg) -{ - int order; - unsigned bytepersec; - unsigned bufs; - struct page *page, *pend; - - if (!db->rawbuf) { - db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; - order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = - pci_alloc_consistent(s->dev, - PAGE_SIZE << order, - &db->dmaaddr))) - break; - if (!db->rawbuf) - return -ENOMEM; - db->buforder = order; - /* now mark the pages as reserved; - otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(db->rawbuf + - (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - SetPageReserved(page); - } - - db->count = 0; - db->nextIn = db->nextOut = db->rawbuf; - - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? - db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; - memset(db->rawbuf, (fmt & (CC_DF>>CC_FMT_BIT)) ? 0 : 0x80, bufs); - -#ifdef IT8172_VERBOSE_DEBUG - dbg("rate=%d, fragsize=%d, numfrag=%d, dmasize=%d", - rate, db->fragsize, db->numfrag, db->dmasize); -#endif - - // set data length register - outw(db->fragsize, s->io+reg+2); - db->ready = 1; - - return 0; -} - -static inline int prog_dmabuf_adc(struct it8172_state *s) -{ - stop_adc(s); - return prog_dmabuf(s, &s->dma_adc, s->adcrate, - (s->capcc & CC_FMT_MASK) >> CC_FMT_BIT, - IT_AC_CAPCC); -} - -static inline int prog_dmabuf_dac(struct it8172_state *s) -{ - stop_dac(s); - return prog_dmabuf(s, &s->dma_dac, s->dacrate, - (s->pcc & CC_FMT_MASK) >> CC_FMT_BIT, - IT_AC_PCC); -} - - -/* hold spinlock for the following! */ - -static irqreturn_t it8172_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct it8172_state *s = (struct it8172_state *)dev_id; - struct dmabuf* dac = &s->dma_dac; - struct dmabuf* adc = &s->dma_adc; - unsigned char isc, vs; - unsigned short vol, mute; - unsigned long newptr; - - spin_lock(&s->lock); - - isc = inb(s->io+IT_AC_ISC); - - /* fastpath out, to ease interrupt sharing */ - if (!(isc & (ISC_VCI | ISC_CCI | ISC_PCI))) { - spin_unlock(&s->lock); - return IRQ_NONE; - } - - /* clear audio interrupts first */ - outb(isc | ISC_VCI | ISC_CCI | ISC_PCI, s->io+IT_AC_ISC); - - /* handle volume button events (ignore if S/PDIF enabled) */ - if ((isc & ISC_VCI) && s->spdif_volume == -1) { - vs = inb(s->io+IT_AC_VS); - outb(0, s->io+IT_AC_VS); - vol = inw(s->io+IT_AC_PCMOV); - mute = vol & PCMOV_PCMOM; - vol &= PCMOV_PCMLCG_MASK; - if ((vs & VS_VUP) && vol > 0) - vol--; - if ((vs & VS_VDP) && vol < 0x1f) - vol++; - vol |= (vol << PCMOV_PCMRCG_BIT); - if (vs & VS_VMP) - vol |= (mute ^ PCMOV_PCMOM); - outw(vol, s->io+IT_AC_PCMOV); - } - - /* update capture pointers */ - if (isc & ISC_CCI) { - if (adc->count > adc->dmasize - adc->fragsize) { - // Overrun. Stop ADC and log the error - stop_adc(s); - adc->error++; - dbg("adc overrun"); - } else { - newptr = virt_to_bus(adc->nextIn) + 2*adc->fragsize; - if (newptr >= adc->dmaaddr + adc->dmasize) - newptr -= adc->dmasize; - - outl(newptr, s->io+adc->curBufPtr); - adc->curBufPtr = (adc->curBufPtr == IT_AC_CAPB1STA) ? - IT_AC_CAPB2STA : IT_AC_CAPB1STA; - - adc->nextIn += adc->fragsize; - if (adc->nextIn >= adc->rawbuf + adc->dmasize) - adc->nextIn -= adc->dmasize; - - adc->count += adc->fragsize; - adc->total_bytes += adc->fragsize; - - /* wake up anybody listening */ - if (waitqueue_active(&adc->wait)) - wake_up_interruptible(&adc->wait); - } - } - - /* update playback pointers */ - if (isc & ISC_PCI) { - newptr = virt_to_bus(dac->nextOut) + 2*dac->fragsize; - if (newptr >= dac->dmaaddr + dac->dmasize) - newptr -= dac->dmasize; - - outl(newptr, s->io+dac->curBufPtr); - dac->curBufPtr = (dac->curBufPtr == IT_AC_PCB1STA) ? - IT_AC_PCB2STA : IT_AC_PCB1STA; - - dac->nextOut += dac->fragsize; - if (dac->nextOut >= dac->rawbuf + dac->dmasize) - dac->nextOut -= dac->dmasize; - - dac->count -= dac->fragsize; - dac->total_bytes += dac->fragsize; - - /* wake up anybody listening */ - if (waitqueue_active(&dac->wait)) - wake_up_interruptible(&dac->wait); - - if (dac->count <= 0) - stop_dac(s); - } - - spin_unlock(&s->lock); - return IRQ_HANDLED; -} - -/* --------------------------------------------------------------------- */ - -static int it8172_open_mixdev(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct list_head *list; - struct it8172_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct it8172_state, devs); - if (s->codec.dev_mixer == minor) - break; - } - file->private_data = s; - return nonseekable_open(inode, file); -} - -static int it8172_release_mixdev(struct inode *inode, struct file *file) -{ - return 0; -} - - -static u16 -cvt_ossvol(unsigned int gain) -{ - u16 ret; - - if (gain == 0) - return 0; - - if (gain > 100) - gain = 100; - - ret = (100 - gain + 32) / 4; - ret = ret > 31 ? 31 : ret; - return ret; -} - - -static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, - unsigned long arg) -{ - struct it8172_state *s = (struct it8172_state *)codec->private_data; - unsigned int left, right; - unsigned long flags; - int val; - u16 vol; - - /* - * When we are in S/PDIF mode, we want to disable any analog output so - * we filter the master/PCM channel volume ioctls. - * - * Also filter I2S channel, which AC'97 knows nothing about. - */ - - switch (cmd) { - case SOUND_MIXER_WRITE_VOLUME: - // if not in S/PDIF mode, pass to AC'97 - if (s->spdif_volume == -1) - break; - return 0; - case SOUND_MIXER_WRITE_PCM: - // if not in S/PDIF mode, pass to AC'97 - if (s->spdif_volume == -1) - break; - if (get_user(val, (int *)arg)) - return -EFAULT; - right = ((val >> 8) & 0xff); - left = (val & 0xff); - if (right > 100) - right = 100; - if (left > 100) - left = 100; - s->spdif_volume = (right << 8) | left; - vol = cvt_ossvol(left); - vol |= (cvt_ossvol(right) << PCMOV_PCMRCG_BIT); - if (vol == 0) - vol = PCMOV_PCMOM; // mute - spin_lock_irqsave(&s->lock, flags); - outw(vol, s->io+IT_AC_PCMOV); - spin_unlock_irqrestore(&s->lock, flags); - return put_user(s->spdif_volume, (int *)arg); - case SOUND_MIXER_READ_PCM: - // if not in S/PDIF mode, pass to AC'97 - if (s->spdif_volume == -1) - break; - return put_user(s->spdif_volume, (int *)arg); - case SOUND_MIXER_WRITE_I2S: - if (get_user(val, (int *)arg)) - return -EFAULT; - right = ((val >> 8) & 0xff); - left = (val & 0xff); - if (right > 100) - right = 100; - if (left > 100) - left = 100; - s->i2s_volume = (right << 8) | left; - vol = cvt_ossvol(left); - vol |= (cvt_ossvol(right) << I2SV_I2SRCG_BIT); - if (vol == 0) - vol = I2SV_I2SOM; // mute - outw(vol, s->io+IT_AC_I2SV); - return put_user(s->i2s_volume, (int *)arg); - case SOUND_MIXER_READ_I2S: - return put_user(s->i2s_volume, (int *)arg); - case SOUND_MIXER_WRITE_RECSRC: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val & SOUND_MASK_I2S) { - s->i2s_recording = 1; - outb(DRSS_I2S, s->io+IT_AC_DRSS); - return 0; - } else { - s->i2s_recording = 0; - outb(DRSS_AC97_PRIM, s->io+IT_AC_DRSS); - // now let AC'97 select record source - break; - } - case SOUND_MIXER_READ_RECSRC: - if (s->i2s_recording) - return put_user(SOUND_MASK_I2S, (int *)arg); - else - // let AC'97 report recording source - break; - } - - return codec->mixer_ioctl(codec, cmd, arg); -} - -static int it8172_ioctl_mixdev(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct it8172_state *s = (struct it8172_state *)file->private_data; - struct ac97_codec *codec = &s->codec; - - return mixdev_ioctl(codec, cmd, arg); -} - -static /*const*/ struct file_operations it8172_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = it8172_ioctl_mixdev, - .open = it8172_open_mixdev, - .release = it8172_release_mixdev, -}; - -/* --------------------------------------------------------------------- */ - -static int drain_dac(struct it8172_state *s, int nonblock) -{ - unsigned long flags; - int count, tmo; - - if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped) - return 0; - - for (;;) { - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - //if (nonblock) - //return -EBUSY; - tmo = 1000 * count / s->dacrate; - tmo >>= sample_shift[(s->pcc & CC_FMT_MASK) >> CC_FMT_BIT]; - it8172_delay(tmo); - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ - - -/* - * Copy audio data to/from user buffer from/to dma buffer, taking care - * that we wrap when reading/writing the dma buffer. Returns actual byte - * count written to or read from the dma buffer. - */ -static int copy_dmabuf_user(struct dmabuf *db, char* userbuf, - int count, int to_user) -{ - char* bufptr = to_user ? db->nextOut : db->nextIn; - char* bufend = db->rawbuf + db->dmasize; - - if (bufptr + count > bufend) { - int partial = (int)(bufend - bufptr); - if (to_user) { - if (copy_to_user(userbuf, bufptr, partial)) - return -EFAULT; - if (copy_to_user(userbuf + partial, db->rawbuf, - count - partial)) - return -EFAULT; - } else { - if (copy_from_user(bufptr, userbuf, partial)) - return -EFAULT; - if (copy_from_user(db->rawbuf, - userbuf + partial, - count - partial)) - return -EFAULT; - } - } else { - if (to_user) { - if (copy_to_user(userbuf, bufptr, count)) - return -EFAULT; - } else { - if (copy_from_user(bufptr, userbuf, count)) - return -EFAULT; - } - } - - return count; -} - - -static ssize_t it8172_read(struct file *file, char *buffer, - size_t count, loff_t *ppos) -{ - struct it8172_state *s = (struct it8172_state *)file->private_data; - struct dmabuf *db = &s->dma_adc; - ssize_t ret; - unsigned long flags; - int cnt, remainder, avail; - - if (db->mapped) - return -ENXIO; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - - while (count > 0) { - // wait for samples in capture buffer - do { - spin_lock_irqsave(&s->lock, flags); - if (db->stopped) - start_adc(s); - avail = db->count; - spin_unlock_irqrestore(&s->lock, flags); - if (avail <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - return ret; - } - interruptible_sleep_on(&db->wait); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - return ret; - } - } - } while (avail <= 0); - - // copy from nextOut to user - if ((cnt = copy_dmabuf_user(db, buffer, count > avail ? - avail : count, 1)) < 0) { - if (!ret) - ret = -EFAULT; - return ret; - } - - spin_lock_irqsave(&s->lock, flags); - db->count -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - - db->nextOut += cnt; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - - count -= cnt; - buffer += cnt; - ret += cnt; - } // while (count > 0) - - /* - * See if the dma buffer count after this read call is - * aligned on a fragsize boundary. If not, read from - * buffer until we reach a boundary, and let's hope this - * is just the last remainder of an audio record. If not - * it means the user is not reading in fragsize chunks, in - * which case it's his/her fault that there are audio gaps - * in their record. - */ - spin_lock_irqsave(&s->lock, flags); - remainder = db->count % db->fragsize; - if (remainder) { - db->nextOut += remainder; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - db->count -= remainder; - } - spin_unlock_irqrestore(&s->lock, flags); - - return ret; -} - -static ssize_t it8172_write(struct file *file, const char *buffer, - size_t count, loff_t *ppos) -{ - struct it8172_state *s = (struct it8172_state *)file->private_data; - struct dmabuf *db = &s->dma_dac; - ssize_t ret; - unsigned long flags; - int cnt, remainder, avail; - - if (db->mapped) - return -ENXIO; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - - while (count > 0) { - // wait for space in playback buffer - do { - spin_lock_irqsave(&s->lock, flags); - avail = db->dmasize - db->count; - spin_unlock_irqrestore(&s->lock, flags); - if (avail <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - return ret; - } - interruptible_sleep_on(&db->wait); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - return ret; - } - } - } while (avail <= 0); - - // copy to nextIn - if ((cnt = copy_dmabuf_user(db, (char*)buffer, - count > avail ? - avail : count, 0)) < 0) { - if (!ret) - ret = -EFAULT; - return ret; - } - - spin_lock_irqsave(&s->lock, flags); - db->count += cnt; - if (db->stopped) - start_dac(s); - spin_unlock_irqrestore(&s->lock, flags); - - db->nextIn += cnt; - if (db->nextIn >= db->rawbuf + db->dmasize) - db->nextIn -= db->dmasize; - - count -= cnt; - buffer += cnt; - ret += cnt; - } // while (count > 0) - - /* - * See if the dma buffer count after this write call is - * aligned on a fragsize boundary. If not, fill buffer - * with silence to the next boundary, and let's hope this - * is just the last remainder of an audio playback. If not - * it means the user is not sending us fragsize chunks, in - * which case it's his/her fault that there are audio gaps - * in their playback. - */ - spin_lock_irqsave(&s->lock, flags); - remainder = db->count % db->fragsize; - if (remainder) { - int fill_cnt = db->fragsize - remainder; - memset(db->nextIn, 0, fill_cnt); - db->nextIn += fill_cnt; - if (db->nextIn >= db->rawbuf + db->dmasize) - db->nextIn -= db->dmasize; - db->count += fill_cnt; - } - spin_unlock_irqrestore(&s->lock, flags); - - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int it8172_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct it8172_state *s = (struct it8172_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac.ready) - return 0; - poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac.dmasize >= - s->dma_dac.count + (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int it8172_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct it8172_state *s = (struct it8172_state *)file->private_data; - struct dmabuf *db; - unsigned long size; - - lock_kernel(); - if (vma->vm_flags & VM_WRITE) - db = &s->dma_dac; - else if (vma->vm_flags & VM_READ) - db = &s->dma_adc; - else { - unlock_kernel(); - return -EINVAL; - } - if (vma->vm_pgoff != 0) { - unlock_kernel(); - return -EINVAL; - } - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) { - unlock_kernel(); - return -EINVAL; - } - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) { - unlock_kernel(); - return -EAGAIN; - } - db->mapped = 1; - unlock_kernel(); - return 0; -} - - -#ifdef IT8172_VERBOSE_DEBUG -static struct ioctl_str_t { - unsigned int cmd; - const char* str; -} ioctl_str[] = { - {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"}, - {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"}, - {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"}, - {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"}, - {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"}, - {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"}, - {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"}, - {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"}, - {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"}, - {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"}, - {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"}, - {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"}, - {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"}, - {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"}, - {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"}, - {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"}, - {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"}, - {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"}, - {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"}, - {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"}, - {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"}, - {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"}, - {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"}, - {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"}, - {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"}, - {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"}, - {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"}, - {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"}, - {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"}, - {OSS_GETVERSION, "OSS_GETVERSION"}, - {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"}, - {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"}, - {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"}, - {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"} -}; -#endif - -static int it8172_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct it8172_state *s = (struct it8172_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, mapped, ret, diff; - - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - -#ifdef IT8172_VERBOSE_DEBUG - for (count=0; countf_mode & FMODE_WRITE) - return drain_dac(s, file->f_flags & O_NONBLOCK); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | - DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(s->irq); - s->dma_dac.count = s->dma_dac.total_bytes = 0; - s->dma_dac.nextIn = s->dma_dac.nextOut = - s->dma_dac.rawbuf; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->irq); - s->dma_adc.count = s->dma_adc.total_bytes = 0; - s->dma_adc.nextIn = s->dma_adc.nextOut = - s->dma_adc.rawbuf; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - set_adc_rate(s, val); - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - set_dac_rate(s, val); - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } - return put_user((file->f_mode & FMODE_READ) ? - s->adcrate : s->dacrate, (int *)arg); - - case SNDCTL_DSP_STEREO: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - if (val) - s->capcc |= CC_SM; - else - s->capcc &= ~CC_SM; - outw(s->capcc, s->io+IT_AC_CAPCC); - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - if (val) - s->pcc |= CC_SM; - else - s->pcc &= ~CC_SM; - outw(s->pcc, s->io+IT_AC_PCC); - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - if (val >= 2) { - val = 2; - s->capcc |= CC_SM; - } - else - s->capcc &= ~CC_SM; - outw(s->capcc, s->io+IT_AC_CAPCC); - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - switch (val) { - case 1: - s->pcc &= ~CC_SM; - break; - case 2: - s->pcc |= CC_SM; - break; - default: - // FIX! support multichannel??? - val = 2; - s->pcc |= CC_SM; - break; - } - outw(s->pcc, s->io+IT_AC_PCC); - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } - return put_user(val, (int *)arg); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - if (val == AFMT_S16_LE) - s->capcc |= CC_DF; - else { - val = AFMT_U8; - s->capcc &= ~CC_DF; - } - outw(s->capcc, s->io+IT_AC_CAPCC); - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - if (val == AFMT_S16_LE) - s->pcc |= CC_DF; - else { - val = AFMT_U8; - s->pcc &= ~CC_DF; - } - outw(s->pcc, s->io+IT_AC_PCC); - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } else { - if (file->f_mode & FMODE_READ) - val = (s->capcc & CC_DF) ? - AFMT_S16_LE : AFMT_U8; - else - val = (s->pcc & CC_DF) ? - AFMT_S16_LE : AFMT_U8; - } - return put_user(val, (int *)arg); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ && !s->dma_adc.stopped) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped) - val |= PCM_ENABLE_OUTPUT; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) - start_adc(s); - else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) - start_dac(s); - else - stop_dac(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - abinfo.fragsize = s->dma_dac.fragsize; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - if (!s->dma_dac.stopped) - count -= (s->dma_dac.fragsize - - inw(s->io+IT_AC_PCDL)); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - abinfo.bytes = s->dma_dac.dmasize - count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? - -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - abinfo.fragsize = s->dma_adc.fragsize; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_adc.count; - if (!s->dma_adc.stopped) - count += (s->dma_adc.fragsize - - inw(s->io+IT_AC_CAPCDL)); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - abinfo.bytes = count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? - -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - if (!s->dma_dac.stopped) - count -= (s->dma_dac.fragsize - - inw(s->io+IT_AC_PCDL)); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - return put_user(count, (int *)arg); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cinfo.bytes = s->dma_adc.total_bytes; - count = s->dma_adc.count; - if (!s->dma_adc.stopped) { - diff = s->dma_adc.fragsize - inw(s->io+IT_AC_CAPCDL); - count += diff; - cinfo.bytes += diff; - cinfo.ptr = inl(s->io+s->dma_adc.curBufPtr) - - s->dma_adc.dmaaddr; - } else - cinfo.ptr = virt_to_bus(s->dma_adc.nextIn) - - s->dma_adc.dmaaddr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_adc.fragshift; - if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cinfo.bytes = s->dma_dac.total_bytes; - count = s->dma_dac.count; - if (!s->dma_dac.stopped) { - diff = s->dma_dac.fragsize - inw(s->io+IT_AC_CAPCDL); - count -= diff; - cinfo.bytes += diff; - cinfo.ptr = inl(s->io+s->dma_dac.curBufPtr) - - s->dma_dac.dmaaddr; - } else - cinfo.ptr = virt_to_bus(s->dma_dac.nextOut) - - s->dma_dac.dmaaddr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac.fragshift; - if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) - return put_user(s->dma_dac.fragsize, (int *)arg); - else - return put_user(s->dma_adc.fragsize, (int *)arg); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.subdivision = val; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.subdivision = val; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? - s->adcrate : s->dacrate, (int *)arg); - - case SOUND_PCM_READ_CHANNELS: - if (file->f_mode & FMODE_READ) - return put_user((s->capcc & CC_SM) ? 2 : 1, - (int *)arg); - else - return put_user((s->pcc & CC_SM) ? 2 : 1, - (int *)arg); - - case SOUND_PCM_READ_BITS: - if (file->f_mode & FMODE_READ) - return put_user((s->capcc & CC_DF) ? 16 : 8, - (int *)arg); - else - return put_user((s->pcc & CC_DF) ? 16 : 8, - (int *)arg); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - } - - return mixdev_ioctl(&s->codec, cmd, arg); -} - - -static int it8172_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct it8172_state *s; - int ret; - -#ifdef IT8172_VERBOSE_DEBUG - if (file->f_flags & O_NONBLOCK) - dbg("%s: non-blocking", __FUNCTION__); - else - dbg("%s: blocking", __FUNCTION__); -#endif - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct it8172_state, devs); - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - - spin_lock_irqsave(&s->lock, flags); - - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = - s->dma_adc.subdivision = s->dma_adc.total_bytes = 0; - s->capcc &= ~(CC_SM | CC_DF); - set_adc_rate(s, 8000); - if ((minor & 0xf) == SND_DEV_DSP16) - s->capcc |= CC_DF; - outw(s->capcc, s->io+IT_AC_CAPCC); - if ((ret = prog_dmabuf_adc(s))) { - spin_unlock_irqrestore(&s->lock, flags); - return ret; - } - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = - s->dma_dac.subdivision = s->dma_dac.total_bytes = 0; - s->pcc &= ~(CC_SM | CC_DF); - set_dac_rate(s, 8000); - if ((minor & 0xf) == SND_DEV_DSP16) - s->pcc |= CC_DF; - outw(s->pcc, s->io+IT_AC_PCC); - if ((ret = prog_dmabuf_dac(s))) { - spin_unlock_irqrestore(&s->lock, flags); - return ret; - } - } - - spin_unlock_irqrestore(&s->lock, flags); - - s->open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE)); - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int it8172_release(struct inode *inode, struct file *file) -{ - struct it8172_state *s = (struct it8172_state *)file->private_data; - -#ifdef IT8172_VERBOSE_DEBUG - dbg("%s", __FUNCTION__); -#endif - lock_kernel(); - if (file->f_mode & FMODE_WRITE) - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - dealloc_dmabuf(s, &s->dma_dac); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - } - s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations it8172_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = it8172_read, - .write = it8172_write, - .poll = it8172_poll, - .ioctl = it8172_ioctl, - .mmap = it8172_mmap, - .open = it8172_open, - .release = it8172_release, -}; - - -/* --------------------------------------------------------------------- */ - - -/* --------------------------------------------------------------------- */ - -/* - * for debugging purposes, we'll create a proc device that dumps the - * CODEC chipstate - */ - -#ifdef IT8172_DEBUG -static int proc_it8172_dump (char *buf, char **start, off_t fpos, - int length, int *eof, void *data) -{ - struct it8172_state *s; - int cnt, len = 0; - - if (list_empty(&devs)) - return 0; - s = list_entry(devs.next, struct it8172_state, devs); - - /* print out header */ - len += sprintf(buf + len, "\n\t\tIT8172 Audio Debug\n\n"); - - // print out digital controller state - len += sprintf (buf + len, "IT8172 Audio Controller registers\n"); - len += sprintf (buf + len, "---------------------------------\n"); - cnt=0; - while (cnt < 0x72) { - if (cnt == IT_AC_PCB1STA || cnt == IT_AC_PCB2STA || - cnt == IT_AC_CAPB1STA || cnt == IT_AC_CAPB2STA || - cnt == IT_AC_PFDP) { - len+= sprintf (buf + len, "reg %02x = %08x\n", - cnt, inl(s->io+cnt)); - cnt += 4; - } else { - len+= sprintf (buf + len, "reg %02x = %04x\n", - cnt, inw(s->io+cnt)); - cnt += 2; - } - } - - /* print out CODEC state */ - len += sprintf (buf + len, "\nAC97 CODEC registers\n"); - len += sprintf (buf + len, "----------------------\n"); - for (cnt=0; cnt <= 0x7e; cnt = cnt +2) - len+= sprintf (buf + len, "reg %02x = %04x\n", - cnt, rdcodec(&s->codec, cnt)); - - if (fpos >=len){ - *start = buf; - *eof =1; - return 0; - } - *start = buf + fpos; - if ((len -= fpos) > length) - return length; - *eof =1; - return len; - -} -#endif /* IT8172_DEBUG */ - -/* --------------------------------------------------------------------- */ - -/* maximum number of devices; only used for command line params */ -#define NR_DEVICE 5 - -static int spdif[NR_DEVICE]; -static int i2s_fmt[NR_DEVICE]; - -static unsigned int devindex; - -module_param_array(spdif, int, NULL, 0); -MODULE_PARM_DESC(spdif, "if 1 the S/PDIF digital output is enabled"); -module_param_array(i2s_fmt, int, NULL, 0); -MODULE_PARM_DESC(i2s_fmt, "the format of I2S"); - -MODULE_AUTHOR("Monta Vista Software, stevel@mvista.com"); -MODULE_DESCRIPTION("IT8172 Audio Driver"); - -/* --------------------------------------------------------------------- */ - -static int __devinit it8172_probe(struct pci_dev *pcidev, - const struct pci_device_id *pciid) -{ - struct it8172_state *s; - int i, val; - unsigned short pcisr, vol; - unsigned char legacy, imc; - char proc_str[80]; - - if (pcidev->irq == 0) - return -1; - - if (!(s = kmalloc(sizeof(struct it8172_state), GFP_KERNEL))) { - err("alloc of device struct failed"); - return -1; - } - - memset(s, 0, sizeof(struct it8172_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - mutex_init(&s->open_mutex); - spin_lock_init(&s->lock); - s->dev = pcidev; - s->io = pci_resource_start(pcidev, 0); - s->irq = pcidev->irq; - s->vendor = pcidev->vendor; - s->device = pcidev->device; - pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev); - s->codec.private_data = s; - s->codec.id = 0; - s->codec.codec_read = rdcodec; - s->codec.codec_write = wrcodec; - s->codec.codec_wait = waitcodec; - - if (!request_region(s->io, pci_resource_len(pcidev,0), - IT8172_MODULE_NAME)) { - err("io ports %#lx->%#lx in use", - s->io, s->io + pci_resource_len(pcidev,0)-1); - goto err_region; - } - if (request_irq(s->irq, it8172_interrupt, IRQF_DISABLED, - IT8172_MODULE_NAME, s)) { - err("irq %u in use", s->irq); - goto err_irq; - } - - info("IO at %#lx, IRQ %d", s->io, s->irq); - - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&it8172_audio_fops, -1)) < 0) - goto err_dev1; - if ((s->codec.dev_mixer = - register_sound_mixer(&it8172_mixer_fops, -1)) < 0) - goto err_dev2; - -#ifdef IT8172_DEBUG - /* initialize the debug proc device */ - s->ps = create_proc_read_entry(IT8172_MODULE_NAME, 0, NULL, - proc_it8172_dump, NULL); -#endif /* IT8172_DEBUG */ - - /* - * Reset the Audio device using the IT8172 PCI Reset register. This - * creates an audible double click on a speaker connected to Line-out. - */ - IT_IO_READ16(IT_PM_PCISR, pcisr); - pcisr |= IT_PM_PCISR_ACSR; - IT_IO_WRITE16(IT_PM_PCISR, pcisr); - /* wait up to 100msec for reset to complete */ - for (i=0; pcisr & IT_PM_PCISR_ACSR; i++) { - it8172_delay(10); - if (i == 10) - break; - IT_IO_READ16(IT_PM_PCISR, pcisr); - } - if (i == 10) { - err("chip reset timeout!"); - goto err_dev3; - } - - /* enable pci io and bus mastering */ - if (pci_enable_device(pcidev)) - goto err_dev3; - pci_set_master(pcidev); - - /* get out of legacy mode */ - pci_read_config_byte (pcidev, 0x40, &legacy); - pci_write_config_byte (pcidev, 0x40, legacy & ~1); - - s->spdif_volume = -1; - /* check to see if s/pdif mode is being requested */ - if (spdif[devindex]) { - info("enabling S/PDIF output"); - s->spdif_volume = 0; - outb(GC_SOE, s->io+IT_AC_GC); - } else { - info("disabling S/PDIF output"); - outb(0, s->io+IT_AC_GC); - } - - /* check to see if I2S format requested */ - if (i2s_fmt[devindex]) { - info("setting I2S format to 0x%02x", i2s_fmt[devindex]); - outb(i2s_fmt[devindex], s->io+IT_AC_I2SMC); - } else { - outb(I2SMC_I2SF_I2S, s->io+IT_AC_I2SMC); - } - - /* cold reset the AC97 */ - outw(CODECC_CR, s->io+IT_AC_CODECC); - udelay(1000); - outw(0, s->io+IT_AC_CODECC); - /* need to delay around 500msec(bleech) to give - some CODECs enough time to wakeup */ - it8172_delay(500); - - /* AC97 warm reset to start the bitclk */ - outw(CODECC_WR, s->io+IT_AC_CODECC); - udelay(1000); - outw(0, s->io+IT_AC_CODECC); - - /* codec init */ - if (!ac97_probe_codec(&s->codec)) - goto err_dev3; - - /* add I2S as allowable recording source */ - s->codec.record_sources |= SOUND_MASK_I2S; - - /* Enable Volume button interrupts */ - imc = inb(s->io+IT_AC_IMC); - outb(imc & ~IMC_VCIM, s->io+IT_AC_IMC); - - /* Un-mute PCM and FM out on the controller */ - vol = inw(s->io+IT_AC_PCMOV); - outw(vol & ~PCMOV_PCMOM, s->io+IT_AC_PCMOV); - vol = inw(s->io+IT_AC_FMOV); - outw(vol & ~FMOV_FMOM, s->io+IT_AC_FMOV); - - /* set channel defaults to 8-bit, mono, 8 Khz */ - s->pcc = 0; - s->capcc = 0; - set_dac_rate(s, 8000); - set_adc_rate(s, 8000); - - /* set mic to be the recording source */ - val = SOUND_MASK_MIC; - mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC, - (unsigned long)&val); - - /* mute AC'97 master and PCM when in S/PDIF mode */ - if (s->spdif_volume != -1) { - val = 0x0000; - s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_VOLUME, - (unsigned long)&val); - s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_PCM, - (unsigned long)&val); - } - -#ifdef IT8172_DEBUG - sprintf(proc_str, "driver/%s/%d/ac97", IT8172_MODULE_NAME, - s->codec.id); - s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL, - ac97_read_proc, &s->codec); -#endif - - /* store it in the driver field */ - pci_set_drvdata(pcidev, s); - pcidev->dma_mask = 0xffffffff; - /* put it into driver list */ - list_add_tail(&s->devs, &devs); - /* increment devindex */ - if (devindex < NR_DEVICE-1) - devindex++; - return 0; - - err_dev3: - unregister_sound_mixer(s->codec.dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - err("cannot register misc device"); - free_irq(s->irq, s); - err_irq: - release_region(s->io, pci_resource_len(pcidev,0)); - err_region: - kfree(s); - return -1; -} - -static void __devexit it8172_remove(struct pci_dev *dev) -{ - struct it8172_state *s = pci_get_drvdata(dev); - - if (!s) - return; - list_del(&s->devs); -#ifdef IT8172_DEBUG - if (s->ps) - remove_proc_entry(IT8172_MODULE_NAME, NULL); -#endif /* IT8172_DEBUG */ - synchronize_irq(s->irq); - free_irq(s->irq, s); - release_region(s->io, pci_resource_len(dev,0)); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->codec.dev_mixer); - kfree(s); - pci_set_drvdata(dev, NULL); -} - - - -static struct pci_device_id id_table[] = { - { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G_AUDIO, PCI_ANY_ID, - PCI_ANY_ID, 0, 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, id_table); - -static struct pci_driver it8172_driver = { - .name = IT8172_MODULE_NAME, - .id_table = id_table, - .probe = it8172_probe, - .remove = __devexit_p(it8172_remove) -}; - -static int __init init_it8172(void) -{ - info("version v0.5 time " __TIME__ " " __DATE__); - return pci_register_driver(&it8172_driver); -} - -static void __exit cleanup_it8172(void) -{ - info("unloading"); - pci_unregister_driver(&it8172_driver); -} - -module_init(init_it8172); -module_exit(cleanup_it8172); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -/* format is: it8172=[spdif],[i2s:] */ - -static int __init it8172_setup(char *options) -{ - char* this_opt; - static unsigned __initdata nr_dev = 0; - - if (nr_dev >= NR_DEVICE) - return 0; - - if (!options || !*options) - return 0; - - while (this_opt = strsep(&options, ",")) { - if (!*this_opt) - continue; - if (!strncmp(this_opt, "spdif", 5)) { - spdif[nr_dev] = 1; - } else if (!strncmp(this_opt, "i2s:", 4)) { - if (!strncmp(this_opt+4, "dac", 3)) - i2s_fmt[nr_dev] = I2SMC_I2SF_DAC; - else if (!strncmp(this_opt+4, "adc", 3)) - i2s_fmt[nr_dev] = I2SMC_I2SF_ADC; - else if (!strncmp(this_opt+4, "i2s", 3)) - i2s_fmt[nr_dev] = I2SMC_I2SF_I2S; - } - } - - nr_dev++; - return 1; -} - -__setup("it8172=", it8172_setup); - -#endif /* MODULE */ -- cgit v1.2.3 From 92b2db08b1150576d295ba9440e172675095c3ae Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 28 Sep 2006 13:42:05 -0300 Subject: V4L/DVB (4672): Frame format enumeration (1/2) Add VIDIOC_ENUM_FRAMESIZES and VIDIOC_ENUM_FRAMEINTERVALS ioctls to enumerate supported frame sizes and frame intervals. Signed-off-by: Martin Rubli Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) (limited to 'include/linux') diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 44c59da26ed2..253a7ed3abb3 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -276,6 +276,79 @@ struct v4l2_fmtdesc #define V4L2_FMT_FLAG_COMPRESSED 0x0001 +/* + * F R A M E S I Z E E N U M E R A T I O N + */ +enum v4l2_frmsizetypes +{ + V4L2_FRMSIZE_TYPE_DISCRETE = 1, + V4L2_FRMSIZE_TYPE_CONTINUOUS = 2, + V4L2_FRMSIZE_TYPE_STEPWISE = 3, +}; + +struct v4l2_frmsize_discrete +{ + __u32 width; /* Frame width [pixel] */ + __u32 height; /* Frame height [pixel] */ +}; + +struct v4l2_frmsize_stepwise +{ + __u32 min_width; /* Minimum frame width [pixel] */ + __u32 max_width; /* Maximum frame width [pixel] */ + __u32 step_width; /* Frame width step size [pixel] */ + __u32 min_height; /* Minimum frame height [pixel] */ + __u32 max_height; /* Maximum frame height [pixel] */ + __u32 step_height; /* Frame height step size [pixel] */ +}; + +struct v4l2_frmsizeenum +{ + __u32 index; /* Frame size number */ + __u32 pixel_format; /* Pixel format */ + __u32 type; /* Frame size type the device supports. */ + + union { /* Frame size */ + struct v4l2_frmsize_discrete discrete; + struct v4l2_frmsize_stepwise stepwise; + }; + + __u32 reserved[2]; /* Reserved space for future use */ +}; + +/* + * F R A M E R A T E E N U M E R A T I O N + */ +enum v4l2_frmivaltypes +{ + V4L2_FRMIVAL_TYPE_DISCRETE = 1, + V4L2_FRMIVAL_TYPE_CONTINUOUS = 2, + V4L2_FRMIVAL_TYPE_STEPWISE = 3, +}; + +struct v4l2_frmival_stepwise +{ + struct v4l2_fract min; /* Minimum frame interval [s] */ + struct v4l2_fract max; /* Maximum frame interval [s] */ + struct v4l2_fract step; /* Frame interval step size [s] */ +}; + +struct v4l2_frmivalenum +{ + __u32 index; /* Frame format index */ + __u32 pixel_format; /* Pixel format */ + __u32 width; /* Frame width */ + __u32 height; /* Frame height */ + __u32 type; /* Frame interval type the device supports. */ + + union { /* Frame interval */ + struct v4l2_fract discrete; + struct v4l2_frmival_stepwise stepwise; + }; + + __u32 reserved[2]; /* Reserved space for future use */ +}; + /* * T I M E C O D E */ @@ -1249,6 +1322,8 @@ struct v4l2_streamparm #define VIDIOC_G_EXT_CTRLS _IOWR ('V', 71, struct v4l2_ext_controls) #define VIDIOC_S_EXT_CTRLS _IOWR ('V', 72, struct v4l2_ext_controls) #define VIDIOC_TRY_EXT_CTRLS _IOWR ('V', 73, struct v4l2_ext_controls) +#define VIDIOC_ENUM_FRAMESIZES _IOWR ('V', 74, struct v4l2_frmsizeenum) +#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR ('V', 75, struct v4l2_frmivalenum) #ifdef __OLD_VIDIOC_ /* for compatibility, will go away some day */ -- cgit v1.2.3 From dcc29cbcec8c8482eea249030e0aa65b7451073d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 28 Sep 2006 13:48:26 -0300 Subject: V4L/DVB (4673): Mark the two newer ioctls as experimental VIDIOC_ENUM_FRAMESIZES and VIDIOC_ENUM_FRAMEINTERVALS ioctls are meant to be used to provide better support for webcams. Currently, it is not yet used on kernel drivers. Better to keep it marked as experimental, until we have several kernel drivers supporting those features. Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 253a7ed3abb3..c5fdf6259548 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -276,6 +276,8 @@ struct v4l2_fmtdesc #define V4L2_FMT_FLAG_COMPRESSED 0x0001 +#if 1 + /* Experimental Frame Size and frame rate enumeration */ /* * F R A M E S I Z E E N U M E R A T I O N */ @@ -348,6 +350,7 @@ struct v4l2_frmivalenum __u32 reserved[2]; /* Reserved space for future use */ }; +#endif /* * T I M E C O D E @@ -1322,8 +1325,10 @@ struct v4l2_streamparm #define VIDIOC_G_EXT_CTRLS _IOWR ('V', 71, struct v4l2_ext_controls) #define VIDIOC_S_EXT_CTRLS _IOWR ('V', 72, struct v4l2_ext_controls) #define VIDIOC_TRY_EXT_CTRLS _IOWR ('V', 73, struct v4l2_ext_controls) +#if 1 #define VIDIOC_ENUM_FRAMESIZES _IOWR ('V', 74, struct v4l2_frmsizeenum) #define VIDIOC_ENUM_FRAMEINTERVALS _IOWR ('V', 75, struct v4l2_frmivalenum) +#endif #ifdef __OLD_VIDIOC_ /* for compatibility, will go away some day */ -- cgit v1.2.3 From f30c2269544bffc7bf1b0d7c0abe5be1be83b8cb Mon Sep 17 00:00:00 2001 From: Uwe Zeisberger Date: Tue, 3 Oct 2006 23:01:26 +0200 Subject: fix file specification in comments Many files include the filename at the beginning, serveral used a wrong one. Signed-off-by: Uwe Zeisberger Signed-off-by: Adrian Bunk --- arch/alpha/kernel/alpha_ksyms.c | 2 +- arch/alpha/kernel/head.S | 2 +- arch/alpha/kernel/machvec_impl.h | 2 +- arch/alpha/lib/dbg_stackcheck.S | 2 +- arch/alpha/lib/dbg_stackkill.S | 2 +- arch/alpha/lib/memset.S | 2 +- arch/arm/boot/compressed/head-clps7500.S | 2 +- arch/arm/common/sa1111.c | 2 +- arch/arm/mach-imx/leds.c | 2 +- arch/arm/mach-imx/leds.h | 2 +- arch/arm/mach-ixp4xx/coyote-pci.c | 2 +- arch/arm/mach-ixp4xx/ixdpg425-pci.c | 2 +- arch/arm/mach-omap1/serial.c | 2 +- arch/arm/mach-omap2/board-apollon.c | 2 +- arch/arm/mach-omap2/board-generic.c | 2 +- arch/arm/mach-omap2/board-h4.c | 2 +- arch/arm/mach-omap2/irq.c | 2 +- arch/arm/mach-omap2/prcm-regs.h | 2 +- arch/arm/mach-omap2/serial.c | 2 +- arch/arm/mach-omap2/sram-fn.S | 2 +- arch/arm/mach-pxa/corgi_lcd.c | 2 +- arch/arm/mach-pxa/leds.h | 2 +- arch/arm/mach-s3c2410/s3c2400-gpio.c | 2 +- arch/arm/mach-s3c2410/s3c2410-clock.c | 2 +- arch/arm/mach-s3c2410/s3c2410-gpio.c | 2 +- arch/arm/mach-s3c2410/s3c2442.c | 2 +- arch/arm/mach-s3c2410/s3c244x-irq.c | 2 +- arch/arm/mach-s3c2410/s3c244x.h | 2 +- arch/arm/mach-s3c2410/usb-simtec.h | 2 +- arch/arm/mach-sa1100/dma.c | 2 +- arch/arm/mach-shark/leds.c | 2 +- arch/arm/plat-omap/sram-fn.S | 2 +- arch/h8300/kernel/ints.c | 2 +- arch/i386/kernel/ldt.c | 2 +- arch/i386/mach-visws/visws_apic.c | 2 +- arch/ia64/kernel/acpi-processor.c | 2 +- arch/ia64/kernel/entry.S | 2 +- arch/ia64/kernel/irq_ia64.c | 2 +- arch/m68k/mm/motorola.c | 2 +- arch/m68k/sun3/sun3dvma.c | 2 +- arch/m68knommu/platform/68328/head-pilot.S | 2 +- arch/mips/dec/boot/decstation.c | 2 +- arch/mips/dec/prom/call_o32.S | 2 +- arch/mips/pci/fixup-vr4133.c | 2 +- arch/mips/tx4938/common/irq.c | 2 +- arch/powerpc/kernel/perfmon_fsl_booke.c | 2 +- arch/powerpc/oprofile/op_model_7450.c | 2 +- arch/powerpc/oprofile/op_model_fsl_booke.c | 2 +- arch/powerpc/platforms/83xx/mpc834x_sys.h | 2 +- arch/powerpc/platforms/85xx/mpc8540_ads.h | 2 +- arch/powerpc/platforms/85xx/mpc85xx.h | 2 +- arch/powerpc/platforms/85xx/mpc85xx_cds.h | 2 +- arch/powerpc/sysdev/ipic.c | 2 +- arch/ppc/boot/include/mpsc_defs.h | 2 +- arch/ppc/platforms/4xx/xparameters/xparameters.h | 2 +- arch/ppc/platforms/lopec.h | 2 +- arch/ppc/platforms/mpc8272ads_setup.c | 2 +- arch/ppc/platforms/mpc885ads_setup.c | 2 +- arch/ppc/platforms/mvme5100.h | 2 +- arch/ppc/platforms/powerpmc250.h | 2 +- arch/ppc/platforms/prpmc750.h | 2 +- arch/ppc/platforms/prpmc800.h | 2 +- arch/ppc/platforms/spruce.h | 2 +- arch/sh/boards/bigsur/io.c | 2 +- arch/sh/boards/bigsur/led.c | 2 +- arch/sh/boards/ec3104/io.c | 2 +- arch/sh/boards/hp6xx/setup.c | 2 +- arch/sh/boards/mpc1211/led.c | 2 +- arch/sh/boards/mpc1211/setup.c | 2 +- arch/sh/boards/renesas/hs7751rvoip/io.c | 2 +- arch/sh/boards/renesas/hs7751rvoip/pci.c | 2 +- arch/sh/boards/renesas/rts7751r2d/led.c | 2 +- arch/sh/boards/renesas/systemh/io.c | 2 +- arch/sh/boards/renesas/systemh/irq.c | 2 +- arch/sh/boards/renesas/systemh/setup.c | 2 +- arch/sh/boards/se/770x/led.c | 2 +- arch/sh/boards/se/7751/led.c | 2 +- arch/sh/boards/se/7751/pci.c | 2 +- arch/sh/boards/superh/microdev/io.c | 2 +- arch/sh/boards/superh/microdev/led.c | 2 +- arch/sh/drivers/dma/dma-pvr2.c | 2 +- arch/sh/drivers/pci/dma-dreamcast.c | 2 +- arch/sh/drivers/pci/fixups-dreamcast.c | 2 +- arch/sh/drivers/pci/ops-bigsur.c | 2 +- arch/sh/drivers/pci/ops-dreamcast.c | 2 +- arch/sh/drivers/pci/ops-rts7751r2d.c | 2 +- arch/sh/kernel/cpu/ubc.S | 2 +- arch/sh64/boot/compressed/misc.c | 2 +- arch/sh64/kernel/alphanum.c | 2 +- arch/sh64/lib/c-checksum.c | 2 +- arch/sh64/mach-cayman/led.c | 2 +- arch/sh64/oprofile/op_model_null.c | 2 +- arch/sparc/kernel/sys_solaris.c | 2 +- arch/xtensa/kernel/module.c | 2 +- arch/xtensa/kernel/pci-dma.c | 2 +- arch/xtensa/kernel/pci.c | 2 +- arch/xtensa/kernel/setup.c | 2 +- arch/xtensa/kernel/syscalls.c | 2 +- arch/xtensa/lib/pci-auto.c | 2 +- arch/xtensa/mm/pgtable.c | 2 +- arch/xtensa/mm/tlb.c | 2 +- drivers/acorn/block/mfmhd.c | 2 +- drivers/cdrom/cdrom.c | 2 +- drivers/char/hw_random/ixp4xx-rng.c | 2 +- drivers/char/hw_random/omap-rng.c | 2 +- drivers/char/watchdog/ixp2000_wdt.c | 2 +- drivers/char/watchdog/ixp4xx_wdt.c | 2 +- drivers/firmware/edd.c | 2 +- drivers/i2c/busses/i2c-ibm_iic.c | 2 +- drivers/i2c/busses/i2c-ibm_iic.h | 2 +- drivers/i2c/busses/i2c-ixp4xx.c | 2 +- drivers/i2c/busses/scx200_i2c.c | 2 +- drivers/ide/h8300/ide-h8300.c | 2 +- drivers/ide/ppc/pmac.c | 2 +- drivers/isdn/hisax/amd7930_fn.h | 2 +- drivers/leds/leds-locomo.c | 2 +- drivers/macintosh/adbhid.c | 2 +- drivers/mtd/maps/bast-flash.c | 2 +- drivers/mtd/maps/dmv182.c | 2 +- drivers/net/arm/am79c961a.h | 2 +- drivers/net/ibm_emac/ibm_emac_debug.h | 2 +- drivers/net/ibm_emac/ibm_emac_rgmii.h | 2 +- drivers/parisc/power.c | 2 +- drivers/rtc/rtc-max6902.c | 2 +- drivers/scsi/arm/arxescsi.c | 2 +- drivers/serial/21285.c | 2 +- drivers/serial/cpm_uart/cpm_uart_cpm1.h | 2 +- drivers/serial/cpm_uart/cpm_uart_cpm2.h | 2 +- drivers/usb/core/file.c | 2 +- drivers/usb/core/usb.c | 2 +- drivers/video/s3c2410fb.h | 2 +- fs/befs/befs_fs_types.h | 2 +- fs/hfsplus/part_tbl.c | 2 +- fs/jbd/commit.c | 2 +- fs/jbd/journal.c | 2 +- fs/nfsd/nfs2acl.c | 2 +- fs/nfsd/nfsxdr.c | 2 +- fs/nls/nls_ascii.c | 2 +- fs/nls/nls_base.c | 2 +- fs/nls/nls_cp1250.c | 2 +- fs/nls/nls_cp1251.c | 2 +- fs/nls/nls_cp1255.c | 2 +- fs/nls/nls_cp437.c | 2 +- fs/nls/nls_cp737.c | 2 +- fs/nls/nls_cp775.c | 2 +- fs/nls/nls_cp850.c | 2 +- fs/nls/nls_cp852.c | 2 +- fs/nls/nls_cp855.c | 2 +- fs/nls/nls_cp857.c | 2 +- fs/nls/nls_cp860.c | 2 +- fs/nls/nls_cp861.c | 2 +- fs/nls/nls_cp862.c | 2 +- fs/nls/nls_cp863.c | 2 +- fs/nls/nls_cp864.c | 2 +- fs/nls/nls_cp865.c | 2 +- fs/nls/nls_cp866.c | 2 +- fs/nls/nls_cp869.c | 2 +- fs/nls/nls_cp874.c | 2 +- fs/nls/nls_cp932.c | 2 +- fs/nls/nls_cp936.c | 2 +- fs/nls/nls_cp949.c | 2 +- fs/nls/nls_cp950.c | 2 +- fs/nls/nls_euc-jp.c | 2 +- fs/nls/nls_iso8859-1.c | 2 +- fs/nls/nls_iso8859-13.c | 2 +- fs/nls/nls_iso8859-14.c | 2 +- fs/nls/nls_iso8859-15.c | 2 +- fs/nls/nls_iso8859-2.c | 2 +- fs/nls/nls_iso8859-3.c | 2 +- fs/nls/nls_iso8859-4.c | 2 +- fs/nls/nls_iso8859-5.c | 2 +- fs/nls/nls_iso8859-6.c | 2 +- fs/nls/nls_iso8859-7.c | 2 +- fs/nls/nls_iso8859-9.c | 2 +- fs/nls/nls_koi8-r.c | 2 +- fs/nls/nls_koi8-ru.c | 2 +- fs/nls/nls_koi8-u.c | 2 +- include/asm-arm/arch-clps711x/entry-macro.S | 2 +- include/asm-arm/arch-ebsa285/entry-macro.S | 2 +- include/asm-arm/arch-h720x/system.h | 2 +- include/asm-arm/arch-ixp4xx/system.h | 2 +- include/asm-arm/arch-omap/dmtimer.h | 2 +- include/asm-arm/arch-omap/mcbsp.h | 2 +- include/asm-arm/arch-omap/pm.h | 2 +- include/asm-arm/arch-pnx4008/platform.h | 2 +- include/asm-arm/arch-s3c2410/fb.h | 2 +- include/asm-arm/arch-s3c2410/regs-adc.h | 2 +- include/asm-arm/arch-s3c2410/regs-clock.h | 2 +- include/asm-arm/arch-s3c2410/regs-dsc.h | 2 +- include/asm-arm/arch-s3c2410/regs-gpio.h | 2 +- include/asm-arm/arch-s3c2410/regs-gpioj.h | 2 +- include/asm-arm/arch-s3c2410/regs-iis.h | 2 +- include/asm-arm/arch-s3c2410/regs-irq.h | 2 +- include/asm-arm/arch-s3c2410/regs-lcd.h | 2 +- include/asm-arm/arch-s3c2410/regs-rtc.h | 2 +- include/asm-arm/arch-s3c2410/regs-sdi.h | 2 +- include/asm-arm/arch-s3c2410/regs-timer.h | 2 +- include/asm-arm/arch-s3c2410/regs-udc.h | 2 +- include/asm-arm/arch-s3c2410/spi-gpio.h | 2 +- include/asm-arm/arch-sa1100/neponset.h | 2 +- include/asm-arm/arch-sa1100/uncompress.h | 2 +- include/asm-arm/arch-shark/vmalloc.h | 2 +- include/asm-arm/hardware/debug-8250.S | 2 +- include/asm-arm/hardware/debug-pl01x.S | 2 +- include/asm-arm/hardware/entry-macro-iomd.S | 2 +- include/asm-arm/hardware/sa1111.h | 2 +- include/asm-arm26/assembler.h | 2 +- include/asm-arm26/namei.h | 2 +- include/asm-arm26/semaphore.h | 2 +- include/asm-frv/namei.h | 2 +- include/asm-generic/mutex-dec.h | 2 +- include/asm-generic/mutex-null.h | 2 +- include/asm-generic/mutex-xchg.h | 2 +- include/asm-generic/rtc.h | 2 +- include/asm-generic/tlb.h | 2 +- include/asm-m32r/m32104ut/m32104ut_pld.h | 2 +- include/asm-m32r/m32700ut/m32700ut_lan.h | 2 +- include/asm-m32r/m32700ut/m32700ut_lcd.h | 2 +- include/asm-m32r/m32700ut/m32700ut_pld.h | 2 +- include/asm-m32r/mappi2/mappi2_pld.h | 2 +- include/asm-m32r/mappi3/mappi3_pld.h | 2 +- include/asm-m32r/opsput/opsput_lan.h | 2 +- include/asm-m32r/opsput/opsput_lcd.h | 2 +- include/asm-m32r/opsput/opsput_pld.h | 2 +- include/asm-m68k/rtc.h | 2 +- include/asm-m68knommu/processor.h | 2 +- include/asm-mips/tx4938/tx4938_mips.h | 2 +- include/asm-parisc/rtc.h | 2 +- include/asm-powerpc/ipic.h | 2 +- include/asm-ppc/mv64x60_defs.h | 2 +- include/asm-ppc/rheap.h | 2 +- include/asm-ppc/rtc.h | 2 +- include/asm-s390/qdio.h | 2 +- include/asm-sh/bigsur/io.h | 2 +- include/asm-sh/bigsur/serial.h | 2 +- include/asm-sh/dreamcast/sysasic.h | 2 +- include/asm-sh/hd64465/io.h | 2 +- include/asm-sh/mpc1211/io.h | 2 +- include/asm-sh64/serial.h | 2 +- include/asm-sparc/reg.h | 2 +- include/asm-x86_64/cache.h | 2 +- include/asm-xtensa/a.out.h | 2 +- include/asm-xtensa/cache.h | 2 +- include/asm-xtensa/coprocessor.h | 2 +- include/asm-xtensa/dma-mapping.h | 2 +- include/asm-xtensa/ioctls.h | 2 +- include/asm-xtensa/pgtable.h | 2 +- include/asm-xtensa/siginfo.h | 2 +- include/linux/aio_abi.h | 2 +- include/linux/awe_voice.h | 2 +- include/linux/harrier_defs.h | 2 +- include/linux/lockd/xdr4.h | 2 +- include/linux/mtd/plat-ram.h | 2 +- include/linux/nfsd/stats.h | 2 +- include/linux/nfsd/xdr.h | 2 +- include/linux/ppdev.h | 2 +- include/linux/slab.h | 2 +- include/linux/sunrpc/auth_gss.h | 2 +- include/linux/sunrpc/gss_api.h | 2 +- include/linux/sunrpc/msg_prot.h | 2 +- include/linux/sunrpc/svcauth_gss.h | 2 +- include/linux/writeback.h | 2 +- include/video/s1d13xxxfb.h | 2 +- ipc/msgutil.c | 2 +- kernel/posix-timers.c | 2 +- lib/reed_solomon/reed_solomon.c | 2 +- mm/page-writeback.c | 2 +- net/ipv4/arp.c | 2 +- net/sunrpc/auth_gss/auth_gss.c | 2 +- sound/oss/ad1848.c | 2 +- sound/oss/ad1848_mixer.h | 2 +- sound/oss/adlib_card.c | 2 +- sound/oss/audio.c | 2 +- sound/oss/awe_hw.h | 2 +- sound/oss/awe_wave.c | 2 +- sound/oss/awe_wave.h | 2 +- sound/oss/dev_table.c | 2 +- sound/oss/dmabuf.c | 2 +- sound/oss/gus_card.c | 2 +- sound/oss/gus_midi.c | 2 +- sound/oss/gus_wave.c | 2 +- sound/oss/harmony.c | 2 +- sound/oss/ics2101.c | 2 +- sound/oss/iwmem.h | 2 +- sound/oss/maui.c | 2 +- sound/oss/midi_synth.c | 2 +- sound/oss/midibuf.c | 2 +- sound/oss/mpu401.c | 2 +- sound/oss/opl3.c | 2 +- sound/oss/opl3sa.c | 2 +- sound/oss/opl3sa2.c | 2 +- sound/oss/pas2_card.c | 2 +- sound/oss/pas2_midi.c | 2 +- sound/oss/pas2_mixer.c | 2 +- sound/oss/pss.c | 2 +- sound/oss/sb_audio.c | 2 +- sound/oss/sb_common.c | 2 +- sound/oss/sb_midi.c | 2 +- sound/oss/sb_mixer.c | 2 +- sound/oss/sb_mixer.h | 2 +- sound/oss/sequencer.c | 2 +- sound/oss/sgalaxy.c | 2 +- sound/oss/sound_timer.c | 2 +- sound/oss/soundcard.c | 2 +- sound/oss/sscape.c | 2 +- sound/oss/sys_timer.c | 2 +- sound/oss/trix.c | 2 +- sound/oss/uart401.c | 2 +- sound/oss/uart6850.c | 2 +- sound/oss/v_midi.c | 2 +- sound/oss/waveartist.c | 2 +- sound/oss/waveartist.h | 2 +- sound/oss/wf_midi.c | 2 +- 313 files changed, 313 insertions(+), 313 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index dbe327d32b6f..8b02420f732e 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -1,5 +1,5 @@ /* - * linux/arch/alpha/kernel/ksyms.c + * linux/arch/alpha/kernel/alpha_ksyms.c * * Export the alpha-specific functions that are needed for loadable * modules. diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S index 1e2a62a1f75f..e27d23c74ba8 100644 --- a/arch/alpha/kernel/head.S +++ b/arch/alpha/kernel/head.S @@ -1,5 +1,5 @@ /* - * alpha/boot/head.S + * arch/alpha/kernel/head.S * * initial boot stuff.. At this point, the bootloader has already * switched into OSF/1 PAL-code, and loaded us at the correct address diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h index 08b8302e64ca..0caa45aa128d 100644 --- a/arch/alpha/kernel/machvec_impl.h +++ b/arch/alpha/kernel/machvec_impl.h @@ -1,5 +1,5 @@ /* - * linux/arch/alpha/kernel/machvec.h + * linux/arch/alpha/kernel/machvec_impl.h * * Copyright (C) 1997, 1998 Richard Henderson * diff --git a/arch/alpha/lib/dbg_stackcheck.S b/arch/alpha/lib/dbg_stackcheck.S index 3c1f3e6522e5..78f6b924ad8f 100644 --- a/arch/alpha/lib/dbg_stackcheck.S +++ b/arch/alpha/lib/dbg_stackcheck.S @@ -1,5 +1,5 @@ /* - * arch/alpha/lib/stackcheck.S + * arch/alpha/lib/dbg_stackcheck.S * Contributed by Richard Henderson (rth@tamu.edu) * * Verify that we have not overflowed the stack. Oops if we have. diff --git a/arch/alpha/lib/dbg_stackkill.S b/arch/alpha/lib/dbg_stackkill.S index e9f6a9dcf2b7..c1e40a1a43d5 100644 --- a/arch/alpha/lib/dbg_stackkill.S +++ b/arch/alpha/lib/dbg_stackkill.S @@ -1,5 +1,5 @@ /* - * arch/alpha/lib/killstack.S + * arch/alpha/lib/dbg_stackkill.S * Contributed by Richard Henderson (rth@cygnus.com) * * Clobber the balance of the kernel stack, hoping to catch diff --git a/arch/alpha/lib/memset.S b/arch/alpha/lib/memset.S index 8ff6e7e1773e..311b8cfc6914 100644 --- a/arch/alpha/lib/memset.S +++ b/arch/alpha/lib/memset.S @@ -1,5 +1,5 @@ /* - * linux/arch/alpha/memset.S + * linux/arch/alpha/lib/memset.S * * This is an efficient (and small) implementation of the C library "memset()" * function for the alpha. diff --git a/arch/arm/boot/compressed/head-clps7500.S b/arch/arm/boot/compressed/head-clps7500.S index 941c5f5cbacf..4f3c78ac30a0 100644 --- a/arch/arm/boot/compressed/head-clps7500.S +++ b/arch/arm/boot/compressed/head-clps7500.S @@ -1,5 +1,5 @@ /* - * linux/arch/arm/boot/compressed/head.S + * linux/arch/arm/boot/compressed/head-clps7500.S * * Copyright (C) 1999, 2000, 2001 Nexus Electronics Ltd */ diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 29818bd3248f..30046ad41ced 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-sa1100/sa1111.c + * linux/arch/arm/common/sa1111.c * * SA1111 support * diff --git a/arch/arm/mach-imx/leds.c b/arch/arm/mach-imx/leds.c index 471c1db7c57f..cf30803e019b 100644 --- a/arch/arm/mach-imx/leds.c +++ b/arch/arm/mach-imx/leds.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-imx/leds.h + * linux/arch/arm/mach-imx/leds.c * * Copyright (C) 2004 Sascha Hauer * diff --git a/arch/arm/mach-imx/leds.h b/arch/arm/mach-imx/leds.h index 83fa21e795a9..49dc1c1da338 100644 --- a/arch/arm/mach-imx/leds.h +++ b/arch/arm/mach-imx/leds.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-imx/leds.h + * arch/arm/mach-imx/leds.h * * Copyright (c) 2004 Sascha Hauer * diff --git a/arch/arm/mach-ixp4xx/coyote-pci.c b/arch/arm/mach-ixp4xx/coyote-pci.c index 2cebb2878895..7bc94f3def1c 100644 --- a/arch/arm/mach-ixp4xx/coyote-pci.c +++ b/arch/arm/mach-ixp4xx/coyote-pci.c @@ -1,5 +1,5 @@ /* - * arch/arch/mach-ixp4xx/coyote-pci.c + * arch/arm/mach-ixp4xx/coyote-pci.c * * PCI setup routines for ADI Engineering Coyote platform * diff --git a/arch/arm/mach-ixp4xx/ixdpg425-pci.c b/arch/arm/mach-ixp4xx/ixdpg425-pci.c index ed5270800217..509a95a692a4 100644 --- a/arch/arm/mach-ixp4xx/ixdpg425-pci.c +++ b/arch/arm/mach-ixp4xx/ixdpg425-pci.c @@ -1,5 +1,5 @@ /* - * arch/arch/mach-ixp4xx/ixdpg425-pci.c + * arch/arm/mach-ixp4xx/ixdpg425-pci.c * * PCI setup routines for Intel IXDPG425 Platform * diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index 976edfb882e2..c4b790217a5b 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap1/id.c + * linux/arch/arm/mach-omap1/serial.c * * OMAP1 CPU identification code * diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c index 2db6b732b084..c37b0e6d1248 100644 --- a/arch/arm/mach-omap2/board-apollon.c +++ b/arch/arm/mach-omap2/board-apollon.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/omap2/board-apollon.c + * linux/arch/arm/mach-omap2/board-apollon.c * * Copyright (C) 2005,2006 Samsung Electronics * Author: Kyungmin Park diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index eaecbf422d8c..90938151bcf1 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/omap2/board-generic.c + * linux/arch/arm/mach-omap2/board-generic.c * * Copyright (C) 2005 Nokia Corporation * Author: Paul Mundt diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index 996aeda1285d..26a95a642ad7 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/omap2/board-h4.c + * linux/arch/arm/mach-omap2/board-h4.c * * Copyright (C) 2005 Nokia Corporation * Author: Paul Mundt diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index 1ed2fff4691a..11870093d7a1 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/omap2/irq.c + * linux/arch/arm/mach-omap2/irq.c * * Interrupt handler for OMAP2 boards. * diff --git a/arch/arm/mach-omap2/prcm-regs.h b/arch/arm/mach-omap2/prcm-regs.h index 22ac7be4f782..5e1c4b53ee9d 100644 --- a/arch/arm/mach-omap2/prcm-regs.h +++ b/arch/arm/mach-omap2/prcm-regs.h @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap2/prcm-reg.h + * linux/arch/arm/mach-omap2/prcm-regs.h * * OMAP24XX Power Reset and Clock Management (PRCM) registers * diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 0884bc7c23b7..aaa5589e8169 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-omap/omap2/serial.c + * arch/arm/mach-omap2/serial.c * * OMAP2 serial support. * diff --git a/arch/arm/mach-omap2/sram-fn.S b/arch/arm/mach-omap2/sram-fn.S index a5ef7f611da9..b27576690f8d 100644 --- a/arch/arm/mach-omap2/sram-fn.S +++ b/arch/arm/mach-omap2/sram-fn.S @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap2/sram.S + * linux/arch/arm/mach-omap2/sram-fn.S * * Omap2 specific functions that need to be run in internal SRAM * diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c index d7815491b752..a72476c24621 100644 --- a/arch/arm/mach-pxa/corgi_lcd.c +++ b/arch/arm/mach-pxa/corgi_lcd.c @@ -1,5 +1,5 @@ /* - * linux/drivers/video/w100fb.c + * linux/arch/arm/mach-pxa/corgi_lcd.c * * Corgi/Spitz LCD Specific Code * diff --git a/arch/arm/mach-pxa/leds.h b/arch/arm/mach-pxa/leds.h index 4f829b8c39dd..7f0dfe01345a 100644 --- a/arch/arm/mach-pxa/leds.h +++ b/arch/arm/mach-pxa/leds.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-pxa/leds.h + * arch/arm/mach-pxa/leds.h * * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. * diff --git a/arch/arm/mach-s3c2410/s3c2400-gpio.c b/arch/arm/mach-s3c2410/s3c2400-gpio.c index f2a78175a70a..1576d01d5f82 100644 --- a/arch/arm/mach-s3c2410/s3c2400-gpio.c +++ b/arch/arm/mach-s3c2410/s3c2400-gpio.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/gpio.c +/* linux/arch/arm/mach-s3c2410/s3c2400-gpio.c * * Copyright (c) 2006 Lucas Correia Villa Real * diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c index 99718663318e..00abe199a08e 100644 --- a/arch/arm/mach-s3c2410/s3c2410-clock.c +++ b/arch/arm/mach-s3c2410/s3c2410-clock.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/clock.c +/* linux/arch/arm/mach-s3c2410/s3c2410-clock.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c index 471a71490010..a2098f692d83 100644 --- a/arch/arm/mach-s3c2410/s3c2410-gpio.c +++ b/arch/arm/mach-s3c2410/s3c2410-gpio.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/gpio.c +/* linux/arch/arm/mach-s3c2410/s3c2410-gpio.c * * Copyright (c) 2004-2006 Simtec Electronics * Ben Dooks diff --git a/arch/arm/mach-s3c2410/s3c2442.c b/arch/arm/mach-s3c2410/s3c2442.c index debae2430557..581667efd13c 100644 --- a/arch/arm/mach-s3c2410/s3c2442.c +++ b/arch/arm/mach-s3c2410/s3c2442.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2440.c +/* linux/arch/arm/mach-s3c2410/s3c2442.c * * Copyright (c) 2006 Simtec Electronics * Ben Dooks diff --git a/arch/arm/mach-s3c2410/s3c244x-irq.c b/arch/arm/mach-s3c2410/s3c244x-irq.c index 0d13546c3500..ec702f88b299 100644 --- a/arch/arm/mach-s3c2410/s3c244x-irq.c +++ b/arch/arm/mach-s3c2410/s3c244x-irq.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c +/* linux/arch/arm/mach-s3c2410/s3c244x-irq.c * * Copyright (c) 2003,2004 Simtec Electronics * Ben Dooks diff --git a/arch/arm/mach-s3c2410/s3c244x.h b/arch/arm/mach-s3c2410/s3c244x.h index 3e7f5f75134d..1488c1eb37e6 100644 --- a/arch/arm/mach-s3c2410/s3c244x.h +++ b/arch/arm/mach-s3c2410/s3c244x.h @@ -1,4 +1,4 @@ -/* arch/arm/mach-s3c2410/s3c2440.h +/* arch/arm/mach-s3c2410/s3c244x.h * * Copyright (c) 2004-2005 Simtec Electronics * Ben Dooks diff --git a/arch/arm/mach-s3c2410/usb-simtec.h b/arch/arm/mach-s3c2410/usb-simtec.h index 92c0cc83aeec..d8aa6127dedb 100644 --- a/arch/arm/mach-s3c2410/usb-simtec.h +++ b/arch/arm/mach-s3c2410/usb-simtec.h @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-s3c2410/usb-simtec.c +/* linux/arch/arm/mach-s3c2410/usb-simtec.h * * Copyright (c) 2004 Simtec Electronics * Ben Dooks diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c index 3c6441d4bc59..2ea2a657a034 100644 --- a/arch/arm/mach-sa1100/dma.c +++ b/arch/arm/mach-sa1100/dma.c @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/dma-sa1100.c + * arch/arm/mach-sa1100/dma.c * * Support functions for the SA11x0 internal DMA channels. * diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c index 7cd86d357a3c..5386a81f796a 100644 --- a/arch/arm/mach-shark/leds.c +++ b/arch/arm/mach-shark/leds.c @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/leds-shark.c + * arch/arm/mach-shark/leds.c * by Alexander Schulz * * derived from: diff --git a/arch/arm/plat-omap/sram-fn.S b/arch/arm/plat-omap/sram-fn.S index 85cffe2c6266..9e1813c77e05 100644 --- a/arch/arm/plat-omap/sram-fn.S +++ b/arch/arm/plat-omap/sram-fn.S @@ -1,5 +1,5 @@ /* - * linux/arch/arm/plat-omap/sram.S + * linux/arch/arm/plat-omap/sram-fn.S * * Functions that need to be run in internal SRAM * diff --git a/arch/h8300/kernel/ints.c b/arch/h8300/kernel/ints.c index 1488b6ace18c..1bfc77e391d5 100644 --- a/arch/h8300/kernel/ints.c +++ b/arch/h8300/kernel/ints.c @@ -1,5 +1,5 @@ /* - * linux/arch/h8300/platform/h8300h/ints.c + * linux/arch/h8300/kernel/ints.c * * Yoshinori Sato * diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c index 983f95707e11..445211eb2d57 100644 --- a/arch/i386/kernel/ldt.c +++ b/arch/i386/kernel/ldt.c @@ -1,5 +1,5 @@ /* - * linux/kernel/ldt.c + * linux/arch/i386/kernel/ldt.c * * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds * Copyright (C) 1999 Ingo Molnar diff --git a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c index 828522541a88..5929f884d79b 100644 --- a/arch/i386/mach-visws/visws_apic.c +++ b/arch/i386/mach-visws/visws_apic.c @@ -1,5 +1,5 @@ /* - * linux/arch/i386/mach_visws/visws_apic.c + * linux/arch/i386/mach-visws/visws_apic.c * * Copyright (C) 1999 Bent Hagemark, Ingo Molnar * diff --git a/arch/ia64/kernel/acpi-processor.c b/arch/ia64/kernel/acpi-processor.c index e683630c8ce2..4d4993a47e55 100644 --- a/arch/ia64/kernel/acpi-processor.c +++ b/arch/ia64/kernel/acpi-processor.c @@ -1,5 +1,5 @@ /* - * arch/ia64/kernel/cpufreq/processor.c + * arch/ia64/kernel/acpi-processor.c * * Copyright (C) 2005 Intel Corporation * Venkatesh Pallipadi diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index e5b1be51b197..3390b7c5a63f 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1,5 +1,5 @@ /* - * ia64/kernel/entry.S + * arch/ia64/kernel/entry.S * * Kernel entry points. * diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index a041367f043b..aafca18ab33b 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -1,5 +1,5 @@ /* - * linux/arch/ia64/kernel/irq.c + * linux/arch/ia64/kernel/irq_ia64.c * * Copyright (C) 1998-2001 Hewlett-Packard Co * Stephane Eranian diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c index 49015e32d8fc..afcccdc6ad45 100644 --- a/arch/m68k/mm/motorola.c +++ b/arch/m68k/mm/motorola.c @@ -1,5 +1,5 @@ /* - * linux/arch/m68k/motorola.c + * linux/arch/m68k/mm/motorola.c * * Routines specific to the Motorola MMU, originally from: * linux/arch/m68k/init.c diff --git a/arch/m68k/sun3/sun3dvma.c b/arch/m68k/sun3/sun3dvma.c index 6c265222cbcd..a2bc2da7f8f0 100644 --- a/arch/m68k/sun3/sun3dvma.c +++ b/arch/m68k/sun3/sun3dvma.c @@ -1,5 +1,5 @@ /* - * linux/arch/m68k/mm/sun3dvma.c + * linux/arch/m68k/sun3/sun3dvma.c * * Copyright (C) 2000 Sam Creasey * diff --git a/arch/m68knommu/platform/68328/head-pilot.S b/arch/m68knommu/platform/68328/head-pilot.S index 9e07faa3e81d..aecff532b343 100644 --- a/arch/m68knommu/platform/68328/head-pilot.S +++ b/arch/m68knommu/platform/68328/head-pilot.S @@ -1,5 +1,5 @@ /* - * linux/arch/m68knommu/platform/68328/head-rom.S + * linux/arch/m68knommu/platform/68328/head-pilot.S * - A startup file for the MC68328 * * Copyright (C) 1998 D. Jeff Dionne , diff --git a/arch/mips/dec/boot/decstation.c b/arch/mips/dec/boot/decstation.c index 4db8bacaf22d..f2fb82bd34a9 100644 --- a/arch/mips/dec/boot/decstation.c +++ b/arch/mips/dec/boot/decstation.c @@ -1,5 +1,5 @@ /* - * arch/mips/dec/decstation.c + * arch/mips/dec/boot/decstation.c */ #include diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S index 0dd56db9b3d0..e523454bda3a 100644 --- a/arch/mips/dec/prom/call_o32.S +++ b/arch/mips/dec/prom/call_o32.S @@ -1,5 +1,5 @@ /* - * arch/mips/dec/call_o32.S + * arch/mips/dec/prom/call_o32.S * * O32 interface for the 64 (or N32) ABI. * diff --git a/arch/mips/pci/fixup-vr4133.c b/arch/mips/pci/fixup-vr4133.c index 8e01d0c1b76b..597b89764ba1 100644 --- a/arch/mips/pci/fixup-vr4133.c +++ b/arch/mips/pci/fixup-vr4133.c @@ -1,5 +1,5 @@ /* - * arch/mips/vr41xx/nec-cmbvr4133/pci_fixup.c + * arch/mips/pci/fixup-vr4133.c * * The NEC CMB-VR4133 Board specific PCI fixups. * diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c index dc30d66123b6..cbfb34221b59 100644 --- a/arch/mips/tx4938/common/irq.c +++ b/arch/mips/tx4938/common/irq.c @@ -1,5 +1,5 @@ /* - * linux/arch/mps/tx4938/common/irq.c + * linux/arch/mips/tx4938/common/irq.c * * Common tx4938 irq handler * Copyright (C) 2000-2001 Toshiba Corporation diff --git a/arch/powerpc/kernel/perfmon_fsl_booke.c b/arch/powerpc/kernel/perfmon_fsl_booke.c index bdc3977a7b06..e0dcf2b41fbe 100644 --- a/arch/powerpc/kernel/perfmon_fsl_booke.c +++ b/arch/powerpc/kernel/perfmon_fsl_booke.c @@ -1,4 +1,4 @@ -/* kernel/perfmon_fsl_booke.c +/* arch/powerpc/kernel/perfmon_fsl_booke.c * Freescale Book-E Performance Monitor code * * Author: Andy Fleming diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c index e0491c3c71f1..d8ee3aea83f8 100644 --- a/arch/powerpc/oprofile/op_model_7450.c +++ b/arch/powerpc/oprofile/op_model_7450.c @@ -1,5 +1,5 @@ /* - * oprofile/op_model_7450.c + * arch/powerpc/oprofile/op_model_7450.c * * Freescale 745x/744x oprofile support, based on fsl_booke support * Copyright (C) 2004 Anton Blanchard , IBM diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c index 93d63e62662f..e29dede31423 100644 --- a/arch/powerpc/oprofile/op_model_fsl_booke.c +++ b/arch/powerpc/oprofile/op_model_fsl_booke.c @@ -1,5 +1,5 @@ /* - * oprofile/op_model_e500.c + * arch/powerpc/oprofile/op_model_fsl_booke.c * * Freescale Book-E oprofile support, based on ppc64 oprofile support * Copyright (C) 2004 Anton Blanchard , IBM diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.h b/arch/powerpc/platforms/83xx/mpc834x_sys.h index fedecb73f7ff..7d5bbef084e7 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_sys.h +++ b/arch/powerpc/platforms/83xx/mpc834x_sys.h @@ -1,5 +1,5 @@ /* - * arch/powerppc/platforms/83xx/mpc834x_sys.h + * arch/powerpc/platforms/83xx/mpc834x_sys.h * * MPC834X SYS common board definitions * diff --git a/arch/powerpc/platforms/85xx/mpc8540_ads.h b/arch/powerpc/platforms/85xx/mpc8540_ads.h index c0d56d2bb5a5..da82f4c0fdac 100644 --- a/arch/powerpc/platforms/85xx/mpc8540_ads.h +++ b/arch/powerpc/platforms/85xx/mpc8540_ads.h @@ -1,5 +1,5 @@ /* - * arch/ppc/platforms/85xx/mpc8540_ads.h + * arch/powerpc/platforms/85xx/mpc8540_ads.h * * MPC8540ADS board definitions * diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h index b44db6268f3d..83415db33378 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx.h +++ b/arch/powerpc/platforms/85xx/mpc85xx.h @@ -1,5 +1,5 @@ /* - * arch/ppc/platforms/85xx/mpc85xx.h + * arch/powerpc/platforms/85xx/mpc85xx.h * * MPC85xx soc definitions/function decls * diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.h b/arch/powerpc/platforms/85xx/mpc85xx_cds.h index 671f54ff185a..b251c9feb3dc 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.h +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.h @@ -1,5 +1,5 @@ /* - * arch/ppc/platforms/85xx/mpc85xx_cds_common.h + * arch/powerpc/platforms/85xx/mpc85xx_cds.h * * MPC85xx CDS board definitions * diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 0251b7c68d0e..6ebdae8e6f69 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -1,5 +1,5 @@ /* - * include/asm-ppc/ipic.c + * arch/powerpc/sysdev/ipic.c * * IPIC routines implementations. * diff --git a/arch/ppc/boot/include/mpsc_defs.h b/arch/ppc/boot/include/mpsc_defs.h index 2ce7bbba7277..9f37e1355b17 100644 --- a/arch/ppc/boot/include/mpsc_defs.h +++ b/arch/ppc/boot/include/mpsc_defs.h @@ -1,5 +1,5 @@ /* - * drivers/serial/mpsc/mpsc_defs.h + * arch/ppc/boot/include/mpsc_defs.h * * Register definitions for the Marvell Multi-Protocol Serial Controller (MPSC), * Serial DMA Controller (SDMA), and Baud Rate Generator (BRG). diff --git a/arch/ppc/platforms/4xx/xparameters/xparameters.h b/arch/ppc/platforms/4xx/xparameters/xparameters.h index cd7d0e7d9863..66ec5f35f306 100644 --- a/arch/ppc/platforms/4xx/xparameters/xparameters.h +++ b/arch/ppc/platforms/4xx/xparameters/xparameters.h @@ -1,5 +1,5 @@ /* - * include/asm-ppc/xparameters.h + * arch/ppc/platforms/4xx/xparameters/xparameters.h * * This file includes the correct xparameters.h for the CONFIG'ed board plus * fixups to translate board specific XPAR values to a common set of names diff --git a/arch/ppc/platforms/lopec.h b/arch/ppc/platforms/lopec.h index 5490edb2d263..d597b6878693 100644 --- a/arch/ppc/platforms/lopec.h +++ b/arch/ppc/platforms/lopec.h @@ -1,5 +1,5 @@ /* - * include/asm-ppc/lopec_serial.h + * arch/ppc/platforms/lopec.h * * Definitions for Motorola LoPEC board. * diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c index d5d36c372c8e..d7b3a6afa78f 100644 --- a/arch/ppc/platforms/mpc8272ads_setup.c +++ b/arch/ppc/platforms/mpc8272ads_setup.c @@ -1,5 +1,5 @@ /* - * arch/ppc/platforms/82xx/pq2ads_pd.c + * arch/ppc/platforms/mpc8272ads_setup.c * * MPC82xx Board-specific PlatformDevice descriptions * diff --git a/arch/ppc/platforms/mpc885ads_setup.c b/arch/ppc/platforms/mpc885ads_setup.c index bf388ed04d46..02293141efb5 100644 --- a/arch/ppc/platforms/mpc885ads_setup.c +++ b/arch/ppc/platforms/mpc885ads_setup.c @@ -1,4 +1,4 @@ -/*arch/ppc/platforms/mpc885ads-setup.c +/*arch/ppc/platforms/mpc885ads_setup.c * * Platform setup for the Freescale mpc885ads board * diff --git a/arch/ppc/platforms/mvme5100.h b/arch/ppc/platforms/mvme5100.h index edd479439a4e..9e2a09e636ae 100644 --- a/arch/ppc/platforms/mvme5100.h +++ b/arch/ppc/platforms/mvme5100.h @@ -1,5 +1,5 @@ /* - * include/asm-ppc/platforms/mvme5100.h + * arch/ppc/platforms/mvme5100.h * * Definitions for Motorola MVME5100. * diff --git a/arch/ppc/platforms/powerpmc250.h b/arch/ppc/platforms/powerpmc250.h index 41a6dc881911..d33ad8dc0439 100644 --- a/arch/ppc/platforms/powerpmc250.h +++ b/arch/ppc/platforms/powerpmc250.h @@ -1,5 +1,5 @@ /* - * include/asm-ppc/platforms/powerpmc250.h + * arch/ppc/platforms/powerpmc250.h * * Definitions for Force PowerPMC-250 board support * diff --git a/arch/ppc/platforms/prpmc750.h b/arch/ppc/platforms/prpmc750.h index 015b4f52c3eb..4c7adcc9ae33 100644 --- a/arch/ppc/platforms/prpmc750.h +++ b/arch/ppc/platforms/prpmc750.h @@ -1,5 +1,5 @@ /* - * include/asm-ppc/platforms/prpmc750.h + * arch/ppc/platforms/prpmc750.h * * Definitions for Motorola PrPMC750 board support * diff --git a/arch/ppc/platforms/prpmc800.h b/arch/ppc/platforms/prpmc800.h index e53ec9b42a35..26f604e05cfa 100644 --- a/arch/ppc/platforms/prpmc800.h +++ b/arch/ppc/platforms/prpmc800.h @@ -1,5 +1,5 @@ /* - * include/asm-ppc/platforms/prpmc800.h + * arch/ppc/platforms/prpmc800.h * * Definitions for Motorola PrPMC800 board support * diff --git a/arch/ppc/platforms/spruce.h b/arch/ppc/platforms/spruce.h index a31ff7ee698f..f1f96f1de72a 100644 --- a/arch/ppc/platforms/spruce.h +++ b/arch/ppc/platforms/spruce.h @@ -1,5 +1,5 @@ /* - * include/asm-ppc/platforms/spruce.h + * arch/ppc/platforms/spruce.h * * Definitions for IBM Spruce reference board support * diff --git a/arch/sh/boards/bigsur/io.c b/arch/sh/boards/bigsur/io.c index 6835381da5fd..23071f97eec3 100644 --- a/arch/sh/boards/bigsur/io.c +++ b/arch/sh/boards/bigsur/io.c @@ -1,5 +1,5 @@ /* - * include/asm-sh/io_bigsur.c + * arch/sh/boards/bigsur/io.c * * By Dustin McIntire (dustin@sensoria.com) (c)2001 * Derived from io_hd64465.h, which bore the message: diff --git a/arch/sh/boards/bigsur/led.c b/arch/sh/boards/bigsur/led.c index 6b08c0e1c453..d221439aafcc 100644 --- a/arch/sh/boards/bigsur/led.c +++ b/arch/sh/boards/bigsur/led.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/led_bigsur.c + * linux/arch/sh/boards/bigsur/led.c * * By Dustin McIntire (dustin@sensoria.com) (c)2001 * Derived from led_se.c and led.c, which bore the message: diff --git a/arch/sh/boards/ec3104/io.c b/arch/sh/boards/ec3104/io.c index a70928c44753..2f86394b280b 100644 --- a/arch/sh/boards/ec3104/io.c +++ b/arch/sh/boards/ec3104/io.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/io_ec3104.c + * linux/arch/sh/boards/ec3104/io.c * EC3104 companion chip support * * Copyright (C) 2000 Philipp Rumpf diff --git a/arch/sh/boards/hp6xx/setup.c b/arch/sh/boards/hp6xx/setup.c index 60ab17ad6054..2d3a5b4faf58 100644 --- a/arch/sh/boards/hp6xx/setup.c +++ b/arch/sh/boards/hp6xx/setup.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/boards/hp6xx/hp680/setup.c + * linux/arch/sh/boards/hp6xx/setup.c * * Copyright (C) 2002 Andriy Skulysh * diff --git a/arch/sh/boards/mpc1211/led.c b/arch/sh/boards/mpc1211/led.c index 1fe36927f691..8df1591823d6 100644 --- a/arch/sh/boards/mpc1211/led.c +++ b/arch/sh/boards/mpc1211/led.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/led_mpc1211.c + * linux/arch/sh/boards/mpc1211/led.c * * Copyright (C) 2001 Saito.K & Jeanne * diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c index 8eb5d4303972..01c10fa5c058 100644 --- a/arch/sh/boards/mpc1211/setup.c +++ b/arch/sh/boards/mpc1211/setup.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/board/mpc1211/setup.c + * linux/arch/sh/boards/mpc1211/setup.c * * Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y * diff --git a/arch/sh/boards/renesas/hs7751rvoip/io.c b/arch/sh/boards/renesas/hs7751rvoip/io.c index 9ea1136b219b..51f3f6574210 100644 --- a/arch/sh/boards/renesas/hs7751rvoip/io.c +++ b/arch/sh/boards/renesas/hs7751rvoip/io.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/io_hs7751rvoip.c + * linux/arch/sh/boards/renesas/hs7751rvoip/io.c * * Copyright (C) 2001 Ian da Silva, Jeremy Siegel * Based largely on io_se.c. diff --git a/arch/sh/boards/renesas/hs7751rvoip/pci.c b/arch/sh/boards/renesas/hs7751rvoip/pci.c index 7e5786b58110..1c0ddee30d21 100644 --- a/arch/sh/boards/renesas/hs7751rvoip/pci.c +++ b/arch/sh/boards/renesas/hs7751rvoip/pci.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/pci-hs7751rvoip.c + * linux/arch/sh/boards/renesas/hs7751rvoip/pci.c * * Author: Ian DaSilva (idasilva@mvista.com) * diff --git a/arch/sh/boards/renesas/rts7751r2d/led.c b/arch/sh/boards/renesas/rts7751r2d/led.c index e14a13d12d4a..a7ce66c1e4f0 100644 --- a/arch/sh/boards/renesas/rts7751r2d/led.c +++ b/arch/sh/boards/renesas/rts7751r2d/led.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/led_rts7751r2d.c + * linux/arch/sh/boards/renesas/rts7751r2d/led.c * * Copyright (C) Atom Create Engineering Co., Ltd. * diff --git a/arch/sh/boards/renesas/systemh/io.c b/arch/sh/boards/renesas/systemh/io.c index cde6e5d192c4..1b767e1a1428 100644 --- a/arch/sh/boards/renesas/systemh/io.c +++ b/arch/sh/boards/renesas/systemh/io.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/boards/systemh/io.c + * linux/arch/sh/boards/renesas/systemh/io.c * * Copyright (C) 2001 Ian da Silva, Jeremy Siegel * Based largely on io_se.c. diff --git a/arch/sh/boards/renesas/systemh/irq.c b/arch/sh/boards/renesas/systemh/irq.c index 8d016dae2333..0ba2fe674c47 100644 --- a/arch/sh/boards/renesas/systemh/irq.c +++ b/arch/sh/boards/renesas/systemh/irq.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/boards/systemh/irq.c + * linux/arch/sh/boards/renesas/systemh/irq.c * * Copyright (C) 2000 Kazumoto Kojima * diff --git a/arch/sh/boards/renesas/systemh/setup.c b/arch/sh/boards/renesas/systemh/setup.c index bab7d3cdc87b..936117659b74 100644 --- a/arch/sh/boards/renesas/systemh/setup.c +++ b/arch/sh/boards/renesas/systemh/setup.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/boards/systemh/setup.c + * linux/arch/sh/boards/renesas/systemh/setup.c * * Copyright (C) 2000 Kazumoto Kojima * Copyright (C) 2003 Paul Mundt diff --git a/arch/sh/boards/se/770x/led.c b/arch/sh/boards/se/770x/led.c index daf7b1ee786a..d93dd831b2ad 100644 --- a/arch/sh/boards/se/770x/led.c +++ b/arch/sh/boards/se/770x/led.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/led_se.c + * linux/arch/sh/boards/se/770x/led.c * * Copyright (C) 2000 Stuart Menefy * diff --git a/arch/sh/boards/se/7751/led.c b/arch/sh/boards/se/7751/led.c index ff0355dea81b..de4194d97c88 100644 --- a/arch/sh/boards/se/7751/led.c +++ b/arch/sh/boards/se/7751/led.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/led_se.c + * linux/arch/sh/boards/se/7751/led.c * * Copyright (C) 2000 Stuart Menefy * diff --git a/arch/sh/boards/se/7751/pci.c b/arch/sh/boards/se/7751/pci.c index 3ee03014dea3..203b2923fe7f 100644 --- a/arch/sh/boards/se/7751/pci.c +++ b/arch/sh/boards/se/7751/pci.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/pci-7751se.c + * linux/arch/sh/boards/se/7751/pci.c * * Author: Ian DaSilva (idasilva@mvista.com) * diff --git a/arch/sh/boards/superh/microdev/io.c b/arch/sh/boards/superh/microdev/io.c index 4836b9422e27..83419bf4c834 100644 --- a/arch/sh/boards/superh/microdev/io.c +++ b/arch/sh/boards/superh/microdev/io.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/io_microdev.c + * linux/arch/sh/boards/superh/microdev/io.c * * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com) * Copyright (C) 2003, 2004 SuperH, Inc. diff --git a/arch/sh/boards/superh/microdev/led.c b/arch/sh/boards/superh/microdev/led.c index a38f5351bd16..36e54b47a752 100644 --- a/arch/sh/boards/superh/microdev/led.c +++ b/arch/sh/boards/superh/microdev/led.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/led_microdev.c + * linux/arch/sh/boards/superh/microdev/led.c * * Copyright (C) 2002 Stuart Menefy * Copyright (C) 2003 Richard Curnow (Richard.Curnow@superh.com) diff --git a/arch/sh/drivers/dma/dma-pvr2.c b/arch/sh/drivers/dma/dma-pvr2.c index 3b0b0f60bb3c..c1b6bc23c107 100644 --- a/arch/sh/drivers/dma/dma-pvr2.c +++ b/arch/sh/drivers/dma/dma-pvr2.c @@ -1,5 +1,5 @@ /* - * arch/sh/boards/dreamcast/dma-pvr2.c + * arch/sh/drivers/dma/dma-pvr2.c * * NEC PowerVR 2 (Dreamcast) DMA support * diff --git a/arch/sh/drivers/pci/dma-dreamcast.c b/arch/sh/drivers/pci/dma-dreamcast.c index 6acf02b9375b..230d6ec0d239 100644 --- a/arch/sh/drivers/pci/dma-dreamcast.c +++ b/arch/sh/drivers/pci/dma-dreamcast.c @@ -1,5 +1,5 @@ /* - * arch/sh/pci/dma-dreamcast.c + * arch/sh/drivers/pci/dma-dreamcast.c * * PCI DMA support for the Sega Dreamcast * diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c index c0af5f7ef414..6f53f8200dc3 100644 --- a/arch/sh/drivers/pci/fixups-dreamcast.c +++ b/arch/sh/drivers/pci/fixups-dreamcast.c @@ -1,5 +1,5 @@ /* - * arch/sh/pci/fixups-dreamcast.c + * arch/sh/drivers/pci/fixups-dreamcast.c * * PCI fixups for the Sega Dreamcast * diff --git a/arch/sh/drivers/pci/ops-bigsur.c b/arch/sh/drivers/pci/ops-bigsur.c index 5da501bd77b5..eb31be751524 100644 --- a/arch/sh/drivers/pci/ops-bigsur.c +++ b/arch/sh/drivers/pci/ops-bigsur.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/pci-bigsur.c + * linux/arch/sh/drivers/pci/ops-bigsur.c * * By Dustin McIntire (dustin@sensoria.com) (c)2001 * diff --git a/arch/sh/drivers/pci/ops-dreamcast.c b/arch/sh/drivers/pci/ops-dreamcast.c index 23d52791917e..381306cf5425 100644 --- a/arch/sh/drivers/pci/ops-dreamcast.c +++ b/arch/sh/drivers/pci/ops-dreamcast.c @@ -1,5 +1,5 @@ /* - * arch/sh/pci/ops-dreamcast.c + * arch/sh/drivers/pci/ops-dreamcast.c * * PCI operations for the Sega Dreamcast * diff --git a/arch/sh/drivers/pci/ops-rts7751r2d.c b/arch/sh/drivers/pci/ops-rts7751r2d.c index 88f44e245424..b68824c8b81e 100644 --- a/arch/sh/drivers/pci/ops-rts7751r2d.c +++ b/arch/sh/drivers/pci/ops-rts7751r2d.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/pci-rts7751r2d.c + * linux/arch/sh/drivers/pci/ops-rts7751r2d.c * * Author: Ian DaSilva (idasilva@mvista.com) * diff --git a/arch/sh/kernel/cpu/ubc.S b/arch/sh/kernel/cpu/ubc.S index 0c569b20e1c1..81923079fa12 100644 --- a/arch/sh/kernel/cpu/ubc.S +++ b/arch/sh/kernel/cpu/ubc.S @@ -1,5 +1,5 @@ /* - * arch/sh/kernel/ubc.S + * arch/sh/kernel/cpu/ubc.S * * Set of management routines for the User Break Controller (UBC) * diff --git a/arch/sh64/boot/compressed/misc.c b/arch/sh64/boot/compressed/misc.c index ee7a1b6acb83..aea00c53ce29 100644 --- a/arch/sh64/boot/compressed/misc.c +++ b/arch/sh64/boot/compressed/misc.c @@ -1,5 +1,5 @@ /* - * arch/shmedia/boot/compressed/misc.c + * arch/sh64/boot/compressed/misc.c * * This is a collection of several routines from gzip-1.0.3 * adapted for Linux. diff --git a/arch/sh64/kernel/alphanum.c b/arch/sh64/kernel/alphanum.c index 9079d1e94f2b..91707c1acd70 100644 --- a/arch/sh64/kernel/alphanum.c +++ b/arch/sh64/kernel/alphanum.c @@ -1,5 +1,5 @@ /* - * arch/sh64/kernel/alpanum.c + * arch/sh64/kernel/alphanum.c * * Copyright (C) 2002 Stuart Menefy * diff --git a/arch/sh64/lib/c-checksum.c b/arch/sh64/lib/c-checksum.c index 53c1cabb3428..0e8a742abf8c 100644 --- a/arch/sh64/lib/c-checksum.c +++ b/arch/sh64/lib/c-checksum.c @@ -1,5 +1,5 @@ /* - * arch/sh/lib/csum_parial.c + * arch/sh64/lib/c-checksum.c * * This file contains network checksum routines that are better done * in an architecture-specific manner due to speed.. diff --git a/arch/sh64/mach-cayman/led.c b/arch/sh64/mach-cayman/led.c index 8b3cc4c78870..b4e122fd9502 100644 --- a/arch/sh64/mach-cayman/led.c +++ b/arch/sh64/mach-cayman/led.c @@ -1,5 +1,5 @@ /* - * arch/sh64/kernel/led_cayman.c + * arch/sh64/mach-cayman/led.c * * Copyright (C) 2002 Stuart Menefy * diff --git a/arch/sh64/oprofile/op_model_null.c b/arch/sh64/oprofile/op_model_null.c index a845b088edb4..a750ea1fee98 100644 --- a/arch/sh64/oprofile/op_model_null.c +++ b/arch/sh64/oprofile/op_model_null.c @@ -1,5 +1,5 @@ /* - * arch/sh/oprofile/op_model_null.c + * arch/sh64/oprofile/op_model_null.c * * Copyright (C) 2003 Paul Mundt * diff --git a/arch/sparc/kernel/sys_solaris.c b/arch/sparc/kernel/sys_solaris.c index c09afd96dd9c..01b07bb440f0 100644 --- a/arch/sparc/kernel/sys_solaris.c +++ b/arch/sparc/kernel/sys_solaris.c @@ -1,5 +1,5 @@ /* - * linux/arch/sparc/sys_solaris.c + * linux/arch/sparc/kernel/sys_solaris.c * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) */ diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c index d1683cfa19a2..2ea1755a0858 100644 --- a/arch/xtensa/kernel/module.c +++ b/arch/xtensa/kernel/module.c @@ -1,5 +1,5 @@ /* - * arch/xtensa/kernel/platform.c + * arch/xtensa/kernel/module.c * * Module support. * diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c index 1ff82268e8ea..6648fa9d9192 100644 --- a/arch/xtensa/kernel/pci-dma.c +++ b/arch/xtensa/kernel/pci-dma.c @@ -1,5 +1,5 @@ /* - * arch/xtensa/pci-dma.c + * arch/xtensa/kernel/pci-dma.c * * DMA coherent memory allocation. * diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c index 8709f8249d02..45571ccb72d6 100644 --- a/arch/xtensa/kernel/pci.c +++ b/arch/xtensa/kernel/pci.c @@ -1,5 +1,5 @@ /* - * arch/xtensa/pcibios.c + * arch/xtensa/kernel/pci.c * * PCI bios-type initialisation for PCI machines * diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 82684d05910a..c99ab72b41b6 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -1,5 +1,5 @@ /* - * arch/xtensa/setup.c + * arch/xtensa/kernel/setup.c * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c index d9285d4d5565..f49cb239e603 100644 --- a/arch/xtensa/kernel/syscalls.c +++ b/arch/xtensa/kernel/syscalls.c @@ -1,5 +1,5 @@ /* - * arch/xtensa/kernel/syscall.c + * arch/xtensa/kernel/syscalls.c * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff --git a/arch/xtensa/lib/pci-auto.c b/arch/xtensa/lib/pci-auto.c index 90c790f6123b..a71733ae1193 100644 --- a/arch/xtensa/lib/pci-auto.c +++ b/arch/xtensa/lib/pci-auto.c @@ -1,5 +1,5 @@ /* - * arch/xtensa/kernel/pci-auto.c + * arch/xtensa/lib/pci-auto.c * * PCI autoconfiguration library * diff --git a/arch/xtensa/mm/pgtable.c b/arch/xtensa/mm/pgtable.c index 7d28914d11cb..697992738205 100644 --- a/arch/xtensa/mm/pgtable.c +++ b/arch/xtensa/mm/pgtable.c @@ -1,5 +1,5 @@ /* - * arch/xtensa/mm/fault.c + * arch/xtensa/mm/pgtable.c * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c index d3bd3bfc3b3b..0fefb8666874 100644 --- a/arch/xtensa/mm/tlb.c +++ b/arch/xtensa/mm/tlb.c @@ -1,5 +1,5 @@ /* - * arch/xtensa/mm/mmu.c + * arch/xtensa/mm/tlb.c * * Logic that manipulates the Xtensa MMU. Derived from MIPS. * diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index 3dd6b7bb5d35..1bace29f4b6a 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/drivers/block/mfmhd.c + * linux/drivers/acorn/block/mfmhd.c * * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd@cs.man.ac.uk) * diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index b38c84a7a8e3..2a0c50d84fc5 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1,4 +1,4 @@ -/* linux/drivers/cdrom/cdrom.c. +/* linux/drivers/cdrom/cdrom.c Copyright (c) 1996, 1997 David A. van Leeuwen. Copyright (c) 1997, 1998 Erik Andersen Copyright (c) 1998, 1999 Jens Axboe diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c index ef71022423c9..3cf4d641a51c 100644 --- a/drivers/char/hw_random/ixp4xx-rng.c +++ b/drivers/char/hw_random/ixp4xx-rng.c @@ -1,5 +1,5 @@ /* - * drivers/char/rng/ixp4xx-rng.c + * drivers/char/hw_random/ixp4xx-rng.c * * RNG driver for Intel IXP4xx family of NPUs * diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index a01d796d1eeb..e13dd1892bfd 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -1,5 +1,5 @@ /* - * driver/char/hw_random/omap-rng.c + * drivers/char/hw_random/omap-rng.c * * RNG driver for TI OMAP CPU family * diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c index c91d9a660ec0..fd955dbd588c 100644 --- a/drivers/char/watchdog/ixp2000_wdt.c +++ b/drivers/char/watchdog/ixp2000_wdt.c @@ -1,5 +1,5 @@ /* - * drivers/watchdog/ixp2000_wdt.c + * drivers/char/watchdog/ixp2000_wdt.c * * Watchdog driver for Intel IXP2000 network processors * diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c index db477f712388..5864bb865cfe 100644 --- a/drivers/char/watchdog/ixp4xx_wdt.c +++ b/drivers/char/watchdog/ixp4xx_wdt.c @@ -1,5 +1,5 @@ /* - * drivers/watchdog/ixp4xx_wdt.c + * drivers/char/watchdog/ixp4xx_wdt.c * * Watchdog driver for Intel IXP4xx network processors * diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index b4502ed65793..5c261e1f92b2 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -1,5 +1,5 @@ /* - * linux/arch/i386/kernel/edd.c + * linux/drivers/firmware/edd.c * Copyright (C) 2002, 2003, 2004 Dell Inc. * by Matt Domsch * disk signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 5bccb5d68318..80d4ba1bdfec 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -1,5 +1,5 @@ /* - * drivers/i2c/i2c-ibm_iic.c + * drivers/i2c/busses/i2c-ibm_iic.c * * Support for the IIC peripheral on IBM PPC 4xx * diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h index 2b3219d00e92..59d7b437f7ff 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.h +++ b/drivers/i2c/busses/i2c-ibm_iic.h @@ -1,5 +1,5 @@ /* - * drivers/i2c/i2c-ibm_iic.h + * drivers/i2c/busses/i2c-ibm_iic.h * * Support for the IIC peripheral on IBM PPC 4xx * diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index ab573254a8aa..1ce01fb0ac09 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -1,5 +1,5 @@ /* - * drivers/i2c/i2c-adap-ixp4xx.c + * drivers/i2c/busses/i2c-ixp4xx.c * * Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have * an on board I2C controller but provide 16 GPIO pins that are often diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c index 8b65a5cf8251..8ddbae4fafe6 100644 --- a/drivers/i2c/busses/scx200_i2c.c +++ b/drivers/i2c/busses/scx200_i2c.c @@ -1,4 +1,4 @@ -/* linux/drivers/i2c/scx200_i2c.c +/* linux/drivers/i2c/busses/scx200_i2c.c Copyright (c) 2001,2002 Christer Weinigel diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c index 15955996a1f3..608ca871744b 100644 --- a/drivers/ide/h8300/ide-h8300.c +++ b/drivers/ide/h8300/ide-h8300.c @@ -1,5 +1,5 @@ /* - * drivers/ide/ide-h8300.c + * drivers/ide/h8300/ide-h8300.c * H8/300 generic IDE interface */ diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 31ad79f52df7..91c5344a945d 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-pmac.c + * linux/drivers/ide/ppc/pmac.c * * Support for IDE interfaces on PowerMacs. * These IDE interfaces are memory-mapped and have a DBDMA channel diff --git a/drivers/isdn/hisax/amd7930_fn.h b/drivers/isdn/hisax/amd7930_fn.h index e039c3a0f2a2..1f4d80c5e5a6 100644 --- a/drivers/isdn/hisax/amd7930_fn.h +++ b/drivers/isdn/hisax/amd7930_fn.h @@ -1,4 +1,4 @@ -/* 2001/10/02 +/* drivers/isdn/hisax/amd7930_fn.h * * gerdes_amd7930.h Header-file included by * gerdes_amd7930.c diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c index 3b87951aa555..6f2d449ba983 100644 --- a/drivers/leds/leds-locomo.c +++ b/drivers/leds/leds-locomo.c @@ -1,5 +1,5 @@ /* - * linux/drivers/leds/locomo.c + * linux/drivers/leds/leds-locomo.c * * Copyright (C) 2005 John Lenz * diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index efd51e01c06e..b7fb367808d8 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -1,5 +1,5 @@ /* - * drivers/input/adbhid.c + * drivers/macintosh/adbhid.c * * ADB HID driver for Power Macintosh computers. * diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c index 51f962dd7e31..e074bb6787d2 100644 --- a/drivers/mtd/maps/bast-flash.c +++ b/drivers/mtd/maps/bast-flash.c @@ -1,4 +1,4 @@ -/* linux/drivers/mtd/maps/bast_flash.c +/* linux/drivers/mtd/maps/bast-flash.c * * Copyright (c) 2004-2005 Simtec Electronics * Ben Dooks diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c index a43c49905cac..e0558b0b2fe6 100644 --- a/drivers/mtd/maps/dmv182.c +++ b/drivers/mtd/maps/dmv182.c @@ -1,6 +1,6 @@ /* - * drivers/mtd/maps/svme182.c + * drivers/mtd/maps/dmv182.c * * Flash map driver for the Dy4 SVME182 board * diff --git a/drivers/net/arm/am79c961a.h b/drivers/net/arm/am79c961a.h index 6a49ac7f6d46..483009fe6ec2 100644 --- a/drivers/net/arm/am79c961a.h +++ b/drivers/net/arm/am79c961a.h @@ -1,5 +1,5 @@ /* - * linux/drivers/net/am79c961.h + * linux/drivers/net/arm/am79c961a.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/net/ibm_emac/ibm_emac_debug.h b/drivers/net/ibm_emac/ibm_emac_debug.h index 5761389495d0..6c7dccc84bf5 100644 --- a/drivers/net/ibm_emac/ibm_emac_debug.h +++ b/drivers/net/ibm_emac/ibm_emac_debug.h @@ -1,5 +1,5 @@ /* - * drivers/net/ibm_emac/ibm_ocp_debug.h + * drivers/net/ibm_emac/ibm_emac_debug.h * * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. * diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.h b/drivers/net/ibm_emac/ibm_emac_rgmii.h index 94abde55e2e9..117ea486c2ca 100644 --- a/drivers/net/ibm_emac/ibm_emac_rgmii.h +++ b/drivers/net/ibm_emac/ibm_emac_rgmii.h @@ -1,5 +1,5 @@ /* - * drivers/net/ibm_emac/ibm_emac_rgmii.c + * drivers/net/ibm_emac/ibm_emac_rgmii.h * * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. * diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c index 4a9f025a6b58..2eb3577a88c5 100644 --- a/drivers/parisc/power.c +++ b/drivers/parisc/power.c @@ -1,5 +1,5 @@ /* - * linux/arch/parisc/kernel/power.c + * linux/drivers/parisc/power.c * HP PARISC soft power switch support driver * * Copyright (c) 2001-2005 Helge Deller diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 9eeef964663a..2f0b77724192 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -1,4 +1,4 @@ -/* drivers/char/max6902.c +/* drivers/rtc/rtc-max6902.c * * Copyright (C) 2006 8D Technologies inc. * Copyright (C) 2004 Compulab Ltd. diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c index a28940156703..4385e9e3ded6 100644 --- a/drivers/scsi/arm/arxescsi.c +++ b/drivers/scsi/arm/arxescsi.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/drivers/scsi/arxescsi.c + * linux/drivers/scsi/arm/arxescsi.c * * Copyright (C) 1997-2000 Russell King, Stefan Hanske * diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index 57438326b07f..76d83ade9857 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -1,5 +1,5 @@ /* - * linux/drivers/char/21285.c + * linux/drivers/serial/21285.c * * Driver for the serial port on the 21285 StrongArm-110 core logic chip. * diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h index 5d867ab581b7..5eb49ea63bfe 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h @@ -1,5 +1,5 @@ /* - * linux/drivers/serial/cpm_uart_cpm1.h + * linux/drivers/serial/cpm_uart/cpm_uart_cpm1.h * * Driver for CPM (SCC/SMC) serial ports * diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h index a663300d3476..4b779111eaf9 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h @@ -1,5 +1,5 @@ /* - * linux/drivers/serial/cpm_uart_cpm2.h + * linux/drivers/serial/cpm_uart/cpm_uart_cpm2.h * * Driver for CPM (SCC/SMC) serial ports * diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index c376c655c5de..f794f07cfb33 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -1,5 +1,5 @@ /* - * drivers/usb/file.c + * drivers/usb/core/file.c * * (C) Copyright Linus Torvalds 1999 * (C) Copyright Johannes Erdfelt 1999-2001 diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index e4df9edf1bc0..467cb02832f3 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1,5 +1,5 @@ /* - * drivers/usb/usb.c + * drivers/usb/core/usb.c * * (C) Copyright Linus Torvalds 1999 * (C) Copyright Johannes Erdfelt 1999-2001 diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h index be40968f899e..f3f8a8e15012 100644 --- a/drivers/video/s3c2410fb.h +++ b/drivers/video/s3c2410fb.h @@ -1,5 +1,5 @@ /* - * linux/drivers/s3c2410fb.h + * linux/drivers/video/s3c2410fb.h * Copyright (c) Arnaud Patard * * This file is subject to the terms and conditions of the GNU General Public diff --git a/fs/befs/befs_fs_types.h b/fs/befs/befs_fs_types.h index 9095518e918d..63ef1e18fb84 100644 --- a/fs/befs/befs_fs_types.h +++ b/fs/befs/befs_fs_types.h @@ -1,5 +1,5 @@ /* - * include/linux/befs_fs_types.h + * fs/befs/befs_fs_types.h * * Copyright (C) 2001 Will Dyson (will@cs.earlham.edu) * diff --git a/fs/hfsplus/part_tbl.c b/fs/hfsplus/part_tbl.c index ae783066fc3a..1528a6fd0299 100644 --- a/fs/hfsplus/part_tbl.c +++ b/fs/hfsplus/part_tbl.c @@ -1,5 +1,5 @@ /* - * linux/fs/hfs/part_tbl.c + * linux/fs/hfsplus/part_tbl.c * * Copyright (C) 1996-1997 Paul H. Hargrove * This file may be distributed under the terms of the GNU General Public License. diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 32a8caf0c41e..10be51290a27 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -1,5 +1,5 @@ /* - * linux/fs/commit.c + * linux/fs/jbd/commit.c * * Written by Stephen C. Tweedie , 1998 * diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 7af6099c911c..c518dd8fe60a 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1,5 +1,5 @@ /* - * linux/fs/journal.c + * linux/fs/jbd/journal.c * * Written by Stephen C. Tweedie , 1998 * diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index fc95c4df6693..fe56b38364cc 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -1,5 +1,5 @@ /* - * linux/fs/nfsd/nfsacl.c + * linux/fs/nfsd/nfs2acl.c * * Process version 2 NFSACL requests. * diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index e3a0797dd56b..3f14a17eaa6e 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -1,5 +1,5 @@ /* - * linux/fs/nfsd/xdr.c + * linux/fs/nfsd/nfsxdr.c * * XDR support for nfsd * diff --git a/fs/nls/nls_ascii.c b/fs/nls/nls_ascii.c index b83381c07ad6..6993faea28ac 100644 --- a/fs/nls/nls_ascii.c +++ b/fs/nls/nls_ascii.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_ascii.c + * linux/fs/nls/nls_ascii.c * * Charset ascii translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index b1317ad5ca18..7dfdab98729b 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_base.c + * linux/fs/nls/nls_base.c * * Native language support--charsets and unicode translations. * By Gordon Chaffee 1996, 1997 diff --git a/fs/nls/nls_cp1250.c b/fs/nls/nls_cp1250.c index 32e78cf95180..570aa69846a0 100644 --- a/fs/nls/nls_cp1250.c +++ b/fs/nls/nls_cp1250.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp1250.c + * linux/fs/nls/nls_cp1250.c * * Charset cp1250 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp1251.c b/fs/nls/nls_cp1251.c index cb41c8ae4486..f114afa069db 100644 --- a/fs/nls/nls_cp1251.c +++ b/fs/nls/nls_cp1251.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp1251.c + * linux/fs/nls/nls_cp1251.c * * Charset cp1251 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp1255.c b/fs/nls/nls_cp1255.c index efdeefee5346..e57f2cbf5bc0 100644 --- a/fs/nls/nls_cp1255.c +++ b/fs/nls/nls_cp1255.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp1255.c + * linux/fs/nls/nls_cp1255.c * * Charset cp1255 translation tables. * The Unicode to charset table has only exact mappings. diff --git a/fs/nls/nls_cp437.c b/fs/nls/nls_cp437.c index 5c4a1cd685dd..d41930ce4a44 100644 --- a/fs/nls/nls_cp437.c +++ b/fs/nls/nls_cp437.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp437.c + * linux/fs/nls/nls_cp437.c * * Charset cp437 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp737.c b/fs/nls/nls_cp737.c index e8b3ca8462e7..d21f8790aa19 100644 --- a/fs/nls/nls_cp737.c +++ b/fs/nls/nls_cp737.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp737.c + * linux/fs/nls/nls_cp737.c * * Charset cp737 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp775.c b/fs/nls/nls_cp775.c index bdb290ea523a..c97714c38a90 100644 --- a/fs/nls/nls_cp775.c +++ b/fs/nls/nls_cp775.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp775.c + * linux/fs/nls/nls_cp775.c * * Charset cp775 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp850.c b/fs/nls/nls_cp850.c index 25deaa4c8648..843b7d975ba2 100644 --- a/fs/nls/nls_cp850.c +++ b/fs/nls/nls_cp850.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp850.c + * linux/fs/nls/nls_cp850.c * * Charset cp850 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp852.c b/fs/nls/nls_cp852.c index b822a7b6b970..83cfd844d5ca 100644 --- a/fs/nls/nls_cp852.c +++ b/fs/nls/nls_cp852.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp852.c + * linux/fs/nls/nls_cp852.c * * Charset cp852 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp855.c b/fs/nls/nls_cp855.c index e8641b7a8b27..9190b7b574ff 100644 --- a/fs/nls/nls_cp855.c +++ b/fs/nls/nls_cp855.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp855.c + * linux/fs/nls/nls_cp855.c * * Charset cp855 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp857.c b/fs/nls/nls_cp857.c index 7ba589ef8cc0..ef3d36db8082 100644 --- a/fs/nls/nls_cp857.c +++ b/fs/nls/nls_cp857.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp857.c + * linux/fs/nls/nls_cp857.c * * Charset cp857 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp860.c b/fs/nls/nls_cp860.c index 3b9e49ce8c80..7e2fb6645893 100644 --- a/fs/nls/nls_cp860.c +++ b/fs/nls/nls_cp860.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp860.c + * linux/fs/nls/nls_cp860.c * * Charset cp860 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp861.c b/fs/nls/nls_cp861.c index 959ff64ee971..66d8d808ccf1 100644 --- a/fs/nls/nls_cp861.c +++ b/fs/nls/nls_cp861.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp861.c + * linux/fs/nls/nls_cp861.c * * Charset cp861 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp862.c b/fs/nls/nls_cp862.c index b96928f5a023..360ba388485f 100644 --- a/fs/nls/nls_cp862.c +++ b/fs/nls/nls_cp862.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp862.c + * linux/fs/nls/nls_cp862.c * * Charset cp862 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp863.c b/fs/nls/nls_cp863.c index baa6e0eab1d6..656a93113e37 100644 --- a/fs/nls/nls_cp863.c +++ b/fs/nls/nls_cp863.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp863.c + * linux/fs/nls/nls_cp863.c * * Charset cp863 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp864.c b/fs/nls/nls_cp864.c index f4dabb037dfe..01ca7309753e 100644 --- a/fs/nls/nls_cp864.c +++ b/fs/nls/nls_cp864.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp864.c + * linux/fs/nls/nls_cp864.c * * Charset cp864 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp865.c b/fs/nls/nls_cp865.c index 4caeafae32c2..5ba6ee13e109 100644 --- a/fs/nls/nls_cp865.c +++ b/fs/nls/nls_cp865.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp865.c + * linux/fs/nls/nls_cp865.c * * Charset cp865 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp866.c b/fs/nls/nls_cp866.c index f2b4a9a293fb..c5f82221c9fe 100644 --- a/fs/nls/nls_cp866.c +++ b/fs/nls/nls_cp866.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp866.c + * linux/fs/nls/nls_cp866.c * * Charset cp866 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp869.c b/fs/nls/nls_cp869.c index 12b436f4eca1..8d4015124d11 100644 --- a/fs/nls/nls_cp869.c +++ b/fs/nls/nls_cp869.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp869.c + * linux/fs/nls/nls_cp869.c * * Charset cp869 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp874.c b/fs/nls/nls_cp874.c index b5766a01703a..df042052c2db 100644 --- a/fs/nls/nls_cp874.c +++ b/fs/nls/nls_cp874.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp874.c + * linux/fs/nls/nls_cp874.c * * Charset cp874 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_cp932.c b/fs/nls/nls_cp932.c index 2c1a17cdcd24..2a9ccf3bc7ef 100644 --- a/fs/nls/nls_cp932.c +++ b/fs/nls/nls_cp932.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp932.c + * linux/fs/nls/nls_cp932.c * * Charset cp932 translation tables. * This translation table was generated automatically, the diff --git a/fs/nls/nls_cp936.c b/fs/nls/nls_cp936.c index ef4cef464aba..046fde8170ea 100644 --- a/fs/nls/nls_cp936.c +++ b/fs/nls/nls_cp936.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp936.c + * linux/fs/nls/nls_cp936.c * * Charset cp936 translation tables. * This translation table was generated automatically, the diff --git a/fs/nls/nls_cp949.c b/fs/nls/nls_cp949.c index 4351ae21d897..92ae19372f0f 100644 --- a/fs/nls/nls_cp949.c +++ b/fs/nls/nls_cp949.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp949.c + * linux/fs/nls/nls_cp949.c * * Charset cp949 translation tables. * This translation table was generated automatically, the diff --git a/fs/nls/nls_cp950.c b/fs/nls/nls_cp950.c index 8167a2858879..5665945fb88c 100644 --- a/fs/nls/nls_cp950.c +++ b/fs/nls/nls_cp950.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_cp950.c + * linux/fs/nls/nls_cp950.c * * Charset cp950 translation tables. * This translation table was generated automatically, the diff --git a/fs/nls/nls_euc-jp.c b/fs/nls/nls_euc-jp.c index 06640c3e4021..73293511578b 100644 --- a/fs/nls/nls_euc-jp.c +++ b/fs/nls/nls_euc-jp.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_euc-jp.c + * linux/fs/nls/nls_euc-jp.c * * Added `OSF/JVC Recommended Code Set Conversion Specification * between Japanese EUC and Shift-JIS' support: diff --git a/fs/nls/nls_iso8859-1.c b/fs/nls/nls_iso8859-1.c index 70a2c1956723..2483c3c6c1c1 100644 --- a/fs/nls/nls_iso8859-1.c +++ b/fs/nls/nls_iso8859-1.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-1.c + * linux/fs/nls/nls_iso8859-1.c * * Charset iso8859-1 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_iso8859-13.c b/fs/nls/nls_iso8859-13.c index 4547035f21a3..7b8721d74368 100644 --- a/fs/nls/nls_iso8859-13.c +++ b/fs/nls/nls_iso8859-13.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-13.c + * linux/fs/nls/nls_iso8859-13.c * * Charset iso8859-13 translation tables. * The Unicode to charset table has only exact mappings. diff --git a/fs/nls/nls_iso8859-14.c b/fs/nls/nls_iso8859-14.c index 13628d0dd3a9..2e895e638dba 100644 --- a/fs/nls/nls_iso8859-14.c +++ b/fs/nls/nls_iso8859-14.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-14.c + * linux/fs/nls/nls_iso8859-14.c * * Charset iso8859-14 translation tables. * diff --git a/fs/nls/nls_iso8859-15.c b/fs/nls/nls_iso8859-15.c index 88b924bf7e18..5c91592779fe 100644 --- a/fs/nls/nls_iso8859-15.c +++ b/fs/nls/nls_iso8859-15.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-15.c + * linux/fs/nls/nls_iso8859-15.c * * Charset iso8859-15 translation tables. * The Unicode to charset table has only exact mappings. diff --git a/fs/nls/nls_iso8859-2.c b/fs/nls/nls_iso8859-2.c index 372528a6c40c..892d38fe9530 100644 --- a/fs/nls/nls_iso8859-2.c +++ b/fs/nls/nls_iso8859-2.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-2.c + * linux/fs/nls/nls_iso8859-2.c * * Charset iso8859-2 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_iso8859-3.c b/fs/nls/nls_iso8859-3.c index 81b45a234369..49317bcdb4be 100644 --- a/fs/nls/nls_iso8859-3.c +++ b/fs/nls/nls_iso8859-3.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-3.c + * linux/fs/nls/nls_iso8859-3.c * * Charset iso8859-3 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_iso8859-4.c b/fs/nls/nls_iso8859-4.c index 101b87f5a49b..9f3b9368c2cf 100644 --- a/fs/nls/nls_iso8859-4.c +++ b/fs/nls/nls_iso8859-4.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-4.c + * linux/fs/nls/nls_iso8859-4.c * * Charset iso8859-4 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_iso8859-5.c b/fs/nls/nls_iso8859-5.c index 83b0084de5eb..001a2bb132ce 100644 --- a/fs/nls/nls_iso8859-5.c +++ b/fs/nls/nls_iso8859-5.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-5.c + * linux/fs/nls/nls_iso8859-5.c * * Charset iso8859-5 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_iso8859-6.c b/fs/nls/nls_iso8859-6.c index 0c519d65f55b..8cec03d66088 100644 --- a/fs/nls/nls_iso8859-6.c +++ b/fs/nls/nls_iso8859-6.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-6.c + * linux/fs/nls/nls_iso8859-6.c * * Charset iso8859-6 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_iso8859-7.c b/fs/nls/nls_iso8859-7.c index bd0854625acf..1be707d5ac31 100644 --- a/fs/nls/nls_iso8859-7.c +++ b/fs/nls/nls_iso8859-7.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-7.c + * linux/fs/nls/nls_iso8859-7.c * * Charset iso8859-7 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_iso8859-9.c b/fs/nls/nls_iso8859-9.c index 988eff791c06..8c0146f73834 100644 --- a/fs/nls/nls_iso8859-9.c +++ b/fs/nls/nls_iso8859-9.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_iso8859-9.c + * linux/fs/nls/nls_iso8859-9.c * * Charset iso8859-9 translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_koi8-r.c b/fs/nls/nls_koi8-r.c index 0ad22c249796..fefbe0807265 100644 --- a/fs/nls/nls_koi8-r.c +++ b/fs/nls/nls_koi8-r.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_koi8-r.c + * linux/fs/nls/nls_koi8-r.c * * Charset koi8-r translation tables. * Generated automatically from the Unicode and charset diff --git a/fs/nls/nls_koi8-ru.c b/fs/nls/nls_koi8-ru.c index 5db83efe27c6..e7bc1d75c78c 100644 --- a/fs/nls/nls_koi8-ru.c +++ b/fs/nls/nls_koi8-ru.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_koi8-ru.c + * linux/fs/nls/nls_koi8-ru.c * * Charset koi8-ru translation based on charset koi8-u. * The Unicode to charset table has only exact mappings. diff --git a/fs/nls/nls_koi8-u.c b/fs/nls/nls_koi8-u.c index 9d30fd61cf46..015070211f22 100644 --- a/fs/nls/nls_koi8-u.c +++ b/fs/nls/nls_koi8-u.c @@ -1,5 +1,5 @@ /* - * linux/fs/nls_koi8-u.c + * linux/fs/nls/nls_koi8-u.c * * Charset koi8-u translation tables. * The Unicode to charset table has only exact mappings. diff --git a/include/asm-arm/arch-clps711x/entry-macro.S b/include/asm-arm/arch-clps711x/entry-macro.S index 21f6ee485819..de4481dd8ba0 100644 --- a/include/asm-arm/arch-clps711x/entry-macro.S +++ b/include/asm-arm/arch-clps711x/entry-macro.S @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-CLPS711x/entry-macro.S + * include/asm-arm/arch-clps711x/entry-macro.S * * Low-level IRQ helper macros for CLPS711X-based platforms * diff --git a/include/asm-arm/arch-ebsa285/entry-macro.S b/include/asm-arm/arch-ebsa285/entry-macro.S index cf10ac96fdde..ce812d4f4a33 100644 --- a/include/asm-arm/arch-ebsa285/entry-macro.S +++ b/include/asm-arm/arch-ebsa285/entry-macro.S @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-footbridge/entry-macro.S + * include/asm-arm/arch-ebsa285/entry-macro.S * * Low-level IRQ helper macros for footbridge-based platforms * diff --git a/include/asm-arm/arch-h720x/system.h b/include/asm-arm/arch-h720x/system.h index 09eda84592ff..8dc1460b2305 100644 --- a/include/asm-arm/arch-h720x/system.h +++ b/include/asm-arm/arch-h720x/system.h @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-h720x/system.h + * linux/include/asm-arm/arch-h720x/system.h * * Copyright (C) 2001-2002 Jungjun Kim, Hynix Semiconductor Inc. * diff --git a/include/asm-arm/arch-ixp4xx/system.h b/include/asm-arm/arch-ixp4xx/system.h index 73589aad8dd6..8e1db423b1cc 100644 --- a/include/asm-arm/arch-ixp4xx/system.h +++ b/include/asm-arm/arch-ixp4xx/system.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-ixp4x//system.h + * include/asm-arm/arch-ixp4xx/system.h * * Copyright (C) 2002 Intel Corporation. * diff --git a/include/asm-arm/arch-omap/dmtimer.h b/include/asm-arm/arch-omap/dmtimer.h index b5f3a71b899d..fefb276ed402 100644 --- a/include/asm-arm/arch-omap/dmtimer.h +++ b/include/asm-arm/arch-omap/dmtimer.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/arm/arch-omap/dmtimer.h + * linux/include/asm-arm/arch-omap/dmtimer.h * * OMAP Dual-Mode Timers * diff --git a/include/asm-arm/arch-omap/mcbsp.h b/include/asm-arm/arch-omap/mcbsp.h index ed0dde4f7219..c7a0cc1c4e93 100644 --- a/include/asm-arm/arch-omap/mcbsp.h +++ b/include/asm-arm/arch-omap/mcbsp.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/arch-omap/gpio.h + * linux/include/asm-arm/arch-omap/mcbsp.h * * Defines for Multi-Channel Buffered Serial Port * diff --git a/include/asm-arm/arch-omap/pm.h b/include/asm-arm/arch-omap/pm.h index e46623c61a72..14588059981f 100644 --- a/include/asm-arm/arch-omap/pm.h +++ b/include/asm-arm/arch-omap/pm.h @@ -1,5 +1,5 @@ /* - * linux/include/asm/arch-omap/pm.h + * linux/include/asm-arm/arch-omap/pm.h * * Header file for OMAP Power Management Routines * diff --git a/include/asm-arm/arch-pnx4008/platform.h b/include/asm-arm/arch-pnx4008/platform.h index 485a3651b4d7..2613c7c669b1 100644 --- a/include/asm-arm/arch-pnx4008/platform.h +++ b/include/asm-arm/arch-pnx4008/platform.h @@ -1,5 +1,5 @@ /* - * include/asm-arm/arch-pnx4008/platfrom.h + * include/asm-arm/arch-pnx4008/platform.h * * PNX4008 Base addresses - header file * diff --git a/include/asm-arm/arch-s3c2410/fb.h b/include/asm-arm/arch-s3c2410/fb.h index 71161797bc89..90894214cace 100644 --- a/include/asm-arm/arch-s3c2410/fb.h +++ b/include/asm-arm/arch-s3c2410/fb.h @@ -1,4 +1,4 @@ -/* linux/include/asm/arch-s3c2410/fb.h +/* linux/include/asm-arm/arch-s3c2410/fb.h * * Copyright (c) 2004 Arnaud Patard * diff --git a/include/asm-arm/arch-s3c2410/regs-adc.h b/include/asm-arm/arch-s3c2410/regs-adc.h index c7b90b3ecc9e..3196a2849e8a 100644 --- a/include/asm-arm/arch-s3c2410/regs-adc.h +++ b/include/asm-arm/arch-s3c2410/regs-adc.h @@ -1,4 +1,4 @@ -/* linux/include/asm/arch-s3c2410/regs-adc.h +/* linux/include/asm-arm/arch-s3c2410/regs-adc.h * * Copyright (c) 2004 Shannon Holland * diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h index b2f4690c0791..e39656b7a086 100644 --- a/include/asm-arm/arch-s3c2410/regs-clock.h +++ b/include/asm-arm/arch-s3c2410/regs-clock.h @@ -1,4 +1,4 @@ -/* linux/include/asm/arch-s3c2410/regs-clock.h +/* linux/include/asm-arm/arch-s3c2410/regs-clock.h * * Copyright (c) 2003,2004,2005,2006 Simtec Electronics * http://armlinux.simtec.co.uk/ diff --git a/include/asm-arm/arch-s3c2410/regs-dsc.h b/include/asm-arm/arch-s3c2410/regs-dsc.h index a0a124875164..c0748511edbc 100644 --- a/include/asm-arm/arch-s3c2410/regs-dsc.h +++ b/include/asm-arm/arch-s3c2410/regs-dsc.h @@ -1,4 +1,4 @@ -/* linux/include/asm/hardware/s3c2410/regs-dsc.h +/* linux/include/asm-arm/arch-s3c2410/regs-dsc.h * * Copyright (c) 2004 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h index 93c49432db95..b2893e32a236 100644 --- a/include/asm-arm/arch-s3c2410/regs-gpio.h +++ b/include/asm-arm/arch-s3c2410/regs-gpio.h @@ -1,4 +1,4 @@ -/* linux/include/asm/hardware/s3c2410/regs-gpio.h +/* linux/include/asm-arm/arch-s3c2410/regs-gpio.h * * Copyright (c) 2003,2004 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ diff --git a/include/asm-arm/arch-s3c2410/regs-gpioj.h b/include/asm-arm/arch-s3c2410/regs-gpioj.h index 91cefa260497..02131a5a1d3a 100644 --- a/include/asm-arm/arch-s3c2410/regs-gpioj.h +++ b/include/asm-arm/arch-s3c2410/regs-gpioj.h @@ -1,4 +1,4 @@ -/* linux/include/asm/hardware/s3c2410/regs-gpioj.h +/* linux/include/asm-arm/arch-s3c2410/regs-gpioj.h * * Copyright (c) 2004 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ diff --git a/include/asm-arm/arch-s3c2410/regs-iis.h b/include/asm-arm/arch-s3c2410/regs-iis.h index 72cd2509822e..eaf77916a602 100644 --- a/include/asm-arm/arch-s3c2410/regs-iis.h +++ b/include/asm-arm/arch-s3c2410/regs-iis.h @@ -1,4 +1,4 @@ -/* linux/include/asm/arch-s3c2410/regs-iis.h +/* linux/include/asm-arm/arch-s3c2410/regs-iis.h * * Copyright (c) 2003 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ diff --git a/include/asm-arm/arch-s3c2410/regs-irq.h b/include/asm-arm/arch-s3c2410/regs-irq.h index 29fb8ef670f0..498184cb8adc 100644 --- a/include/asm-arm/arch-s3c2410/regs-irq.h +++ b/include/asm-arm/arch-s3c2410/regs-irq.h @@ -1,4 +1,4 @@ -/* linux/include/asm/arch-s3c2410/regs-irq.h +/* linux/include/asm-arm/arch-s3c2410/regs-irq.h * * Copyright (c) 2003 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ diff --git a/include/asm-arm/arch-s3c2410/regs-lcd.h b/include/asm-arm/arch-s3c2410/regs-lcd.h index 6d7881c8cfc8..b7faeb04c0ff 100644 --- a/include/asm-arm/arch-s3c2410/regs-lcd.h +++ b/include/asm-arm/arch-s3c2410/regs-lcd.h @@ -1,4 +1,4 @@ -/* linux/include/asm/arch-s3c2410/regs-lcd.h +/* linux/include/asm-arm/arch-s3c2410/regs-lcd.h * * Copyright (c) 2003 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ diff --git a/include/asm-arm/arch-s3c2410/regs-rtc.h b/include/asm-arm/arch-s3c2410/regs-rtc.h index cd88fd634d12..93b03c49710a 100644 --- a/include/asm-arm/arch-s3c2410/regs-rtc.h +++ b/include/asm-arm/arch-s3c2410/regs-rtc.h @@ -1,4 +1,4 @@ -/* linux/include/asm/arch-s3c2410/regs-rtc.h +/* linux/include/asm-arm/arch-s3c2410/regs-rtc.h * * Copyright (c) 2003 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ diff --git a/include/asm-arm/arch-s3c2410/regs-sdi.h b/include/asm-arm/arch-s3c2410/regs-sdi.h index 06e716e5b46d..bb9d30b72952 100644 --- a/include/asm-arm/arch-s3c2410/regs-sdi.h +++ b/include/asm-arm/arch-s3c2410/regs-sdi.h @@ -1,4 +1,4 @@ -/* linux/include/asm/arch-s3c2410/regs-sdi.h +/* linux/include/asm-arm/arch-s3c2410/regs-sdi.h * * Copyright (c) 2004 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ diff --git a/include/asm-arm/arch-s3c2410/regs-timer.h b/include/asm-arm/arch-s3c2410/regs-timer.h index 731918e77831..6f8fe432fe3a 100644 --- a/include/asm-arm/arch-s3c2410/regs-timer.h +++ b/include/asm-arm/arch-s3c2410/regs-timer.h @@ -1,4 +1,4 @@ -/* linux/include/asm/arch-s3c2410/regs-timer.h +/* linux/include/asm-arm/arch-s3c2410/regs-timer.h * * Copyright (c) 2003 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ diff --git a/include/asm-arm/arch-s3c2410/regs-udc.h b/include/asm-arm/arch-s3c2410/regs-udc.h index 3aa31a27da1a..487861d5b49a 100644 --- a/include/asm-arm/arch-s3c2410/regs-udc.h +++ b/include/asm-arm/arch-s3c2410/regs-udc.h @@ -1,4 +1,4 @@ -/* linux/include/asm/arch-s3c2410/regs-udc.h +/* linux/include/asm-arm/arch-s3c2410/regs-udc.h * * Copyright (C) 2004 Herbert Poetzl * diff --git a/include/asm-arm/arch-s3c2410/spi-gpio.h b/include/asm-arm/arch-s3c2410/spi-gpio.h index 258c00bca270..c1e4db7c9710 100644 --- a/include/asm-arm/arch-s3c2410/spi-gpio.h +++ b/include/asm-arm/arch-s3c2410/spi-gpio.h @@ -1,4 +1,4 @@ -/* linux/include/asm-arm/arch-s3c2410/spi.h +/* linux/include/asm-arm/arch-s3c2410/spi-gpio.h * * Copyright (c) 2006 Simtec Electronics * Ben Dooks diff --git a/include/asm-arm/arch-sa1100/neponset.h b/include/asm-arm/arch-sa1100/neponset.h index 8051fd73a80b..09ec9e2bd182 100644 --- a/include/asm-arm/arch-sa1100/neponset.h +++ b/include/asm-arm/arch-sa1100/neponset.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/arch-sa1100/assabet.h + * linux/include/asm-arm/arch-sa1100/neponset.h * * Created 2000/06/05 by Nicolas Pitre * diff --git a/include/asm-arm/arch-sa1100/uncompress.h b/include/asm-arm/arch-sa1100/uncompress.h index 2601a77a6dda..17e64d232e7d 100644 --- a/include/asm-arm/arch-sa1100/uncompress.h +++ b/include/asm-arm/arch-sa1100/uncompress.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/arch-brutus/uncompress.h + * linux/include/asm-arm/arch-sa1100/uncompress.h * * (C) 1999 Nicolas Pitre * diff --git a/include/asm-arm/arch-shark/vmalloc.h b/include/asm-arm/arch-shark/vmalloc.h index 10db5d188231..fac37c636b38 100644 --- a/include/asm-arm/arch-shark/vmalloc.h +++ b/include/asm-arm/arch-shark/vmalloc.h @@ -1,4 +1,4 @@ /* - * linux/include/asm-arm/arch-rpc/vmalloc.h + * linux/include/asm-arm/arch-shark/vmalloc.h */ #define VMALLOC_END (PAGE_OFFSET + 0x10000000) diff --git a/include/asm-arm/hardware/debug-8250.S b/include/asm-arm/hardware/debug-8250.S index 4594fea91ec1..07c97fb233fc 100644 --- a/include/asm-arm/hardware/debug-8250.S +++ b/include/asm-arm/hardware/debug-8250.S @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/hardware/debug-8250.h + * linux/include/asm-arm/hardware/debug-8250.S * * Copyright (C) 1994-1999 Russell King * diff --git a/include/asm-arm/hardware/debug-pl01x.S b/include/asm-arm/hardware/debug-pl01x.S index db0d0f7de5e9..23c541a9e89a 100644 --- a/include/asm-arm/hardware/debug-pl01x.S +++ b/include/asm-arm/hardware/debug-pl01x.S @@ -1,4 +1,4 @@ -/* linux/include/asm-arm/arch-integrator/debug-macro.S +/* linux/include/asm-arm/hardware/debug-pl01x.S * * Debugging macro include header * diff --git a/include/asm-arm/hardware/entry-macro-iomd.S b/include/asm-arm/hardware/entry-macro-iomd.S index 30c7b92c2416..fbed08f298d0 100644 --- a/include/asm-arm/hardware/entry-macro-iomd.S +++ b/include/asm-arm/hardware/entry-macro-iomd.S @@ -1,5 +1,5 @@ /* - * arch/arm/commond/entry-macro-iomd.S + * include/asm-arm/hardware/entry-macro-iomd.S * * Low-level IRQ helper macros for IOC/IOMD based platforms * diff --git a/include/asm-arm/hardware/sa1111.h b/include/asm-arm/hardware/sa1111.h index 319aea064c36..6aa0a5b75b69 100644 --- a/include/asm-arm/hardware/sa1111.h +++ b/include/asm-arm/hardware/sa1111.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/hardware/SA-1111.h + * linux/include/asm-arm/hardware/sa1111.h * * Copyright (C) 2000 John G Dorsey * diff --git a/include/asm-arm26/assembler.h b/include/asm-arm26/assembler.h index 83f9aec55e4f..bb507a9a4a55 100644 --- a/include/asm-arm26/assembler.h +++ b/include/asm-arm26/assembler.h @@ -1,5 +1,5 @@ /* - * linux/asm/assembler.h + * linux/include/asm-arm26/assembler.h * * This file contains arm architecture specific defines * for the different processors. diff --git a/include/asm-arm26/namei.h b/include/asm-arm26/namei.h index a402d3b9d0f7..3f5d340110eb 100644 --- a/include/asm-arm26/namei.h +++ b/include/asm-arm26/namei.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/namei.h + * linux/include/asm-arm26/namei.h * * Routines to handle famous /usr/gnemul * Derived from the Sparc version of this file diff --git a/include/asm-arm26/semaphore.h b/include/asm-arm26/semaphore.h index ccf15e704109..1fda54375ed8 100644 --- a/include/asm-arm26/semaphore.h +++ b/include/asm-arm26/semaphore.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/semaphore.h + * linux/include/asm-arm26/semaphore.h */ #ifndef __ASM_ARM_SEMAPHORE_H #define __ASM_ARM_SEMAPHORE_H diff --git a/include/asm-frv/namei.h b/include/asm-frv/namei.h index 84ddd6445f23..4ea57171d951 100644 --- a/include/asm-frv/namei.h +++ b/include/asm-frv/namei.h @@ -1,5 +1,5 @@ /* - * asm/namei.h + * include/asm-frv/namei.h * * Included from linux/fs/namei.c */ diff --git a/include/asm-generic/mutex-dec.h b/include/asm-generic/mutex-dec.h index 29c6ac34e236..0134151656af 100644 --- a/include/asm-generic/mutex-dec.h +++ b/include/asm-generic/mutex-dec.h @@ -1,5 +1,5 @@ /* - * asm-generic/mutex-dec.h + * include/asm-generic/mutex-dec.h * * Generic implementation of the mutex fastpath, based on atomic * decrement/increment. diff --git a/include/asm-generic/mutex-null.h b/include/asm-generic/mutex-null.h index 254a126ede5c..e1bbbc72b6a2 100644 --- a/include/asm-generic/mutex-null.h +++ b/include/asm-generic/mutex-null.h @@ -1,5 +1,5 @@ /* - * asm-generic/mutex-null.h + * include/asm-generic/mutex-null.h * * Generic implementation of the mutex fastpath, based on NOP :-) * diff --git a/include/asm-generic/mutex-xchg.h b/include/asm-generic/mutex-xchg.h index 32a2100c1aeb..6a7e8c141b53 100644 --- a/include/asm-generic/mutex-xchg.h +++ b/include/asm-generic/mutex-xchg.h @@ -1,5 +1,5 @@ /* - * asm-generic/mutex-xchg.h + * include/asm-generic/mutex-xchg.h * * Generic implementation of the mutex fastpath, based on xchg(). * diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h index 4087037a4225..d3238f1f70a6 100644 --- a/include/asm-generic/rtc.h +++ b/include/asm-generic/rtc.h @@ -1,5 +1,5 @@ /* - * inclue/asm-generic/rtc.h + * include/asm-generic/rtc.h * * Author: Tom Rini * diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index 867d9008fafa..f490e43a90b9 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h @@ -1,4 +1,4 @@ -/* asm-generic/tlb.h +/* include/asm-generic/tlb.h * * Generic TLB shootdown code * diff --git a/include/asm-m32r/m32104ut/m32104ut_pld.h b/include/asm-m32r/m32104ut/m32104ut_pld.h index 6ba4ddf7dcf7..cbdbc5891445 100644 --- a/include/asm-m32r/m32104ut/m32104ut_pld.h +++ b/include/asm-m32r/m32104ut/m32104ut_pld.h @@ -1,5 +1,5 @@ /* - * include/asm/m32104ut/m32104ut_pld.h + * include/asm-m32r/m32104ut/m32104ut_pld.h * * Definitions for Programable Logic Device(PLD) on M32104UT board. * Based on m32700ut_pld.h diff --git a/include/asm-m32r/m32700ut/m32700ut_lan.h b/include/asm-m32r/m32700ut/m32700ut_lan.h index c050b19e8101..f1e47ae1f891 100644 --- a/include/asm-m32r/m32700ut/m32700ut_lan.h +++ b/include/asm-m32r/m32700ut/m32700ut_lan.h @@ -1,5 +1,5 @@ /* - * include/asm/m32700ut_lan.h + * include/asm-m32r/m32700ut/m32700ut_lan.h * * M32700UT-LAN board * diff --git a/include/asm-m32r/m32700ut/m32700ut_lcd.h b/include/asm-m32r/m32700ut/m32700ut_lcd.h index 4da4e822e2f3..e41c4aa48b4c 100644 --- a/include/asm-m32r/m32700ut/m32700ut_lcd.h +++ b/include/asm-m32r/m32700ut/m32700ut_lcd.h @@ -1,5 +1,5 @@ /* - * include/asm/m32700ut_lcd.h + * include/asm-m32r/m32700ut/m32700ut_lcd.h * * M32700UT-LCD board * diff --git a/include/asm-m32r/m32700ut/m32700ut_pld.h b/include/asm-m32r/m32700ut/m32700ut_pld.h index f35f9159acff..a48c22c978ca 100644 --- a/include/asm-m32r/m32700ut/m32700ut_pld.h +++ b/include/asm-m32r/m32700ut/m32700ut_pld.h @@ -1,5 +1,5 @@ /* - * include/asm/m32700ut/m32700ut_pld.h + * include/asm-m32r/m32700ut/m32700ut_pld.h * * Definitions for Programable Logic Device(PLD) on M32700UT board. * diff --git a/include/asm-m32r/mappi2/mappi2_pld.h b/include/asm-m32r/mappi2/mappi2_pld.h index 01dcdd19dbe6..56a2b12f2bfc 100644 --- a/include/asm-m32r/mappi2/mappi2_pld.h +++ b/include/asm-m32r/mappi2/mappi2_pld.h @@ -1,5 +1,5 @@ /* - * include/asm/mappi2/mappi2_pld.h + * include/asm-m32r/mappi2/mappi2_pld.h * * Definitions for Extended IO Logic on MAPPI2 board. * based on m32700ut_pld.h by diff --git a/include/asm-m32r/mappi3/mappi3_pld.h b/include/asm-m32r/mappi3/mappi3_pld.h index 031369a7afc8..92f10defaef8 100644 --- a/include/asm-m32r/mappi3/mappi3_pld.h +++ b/include/asm-m32r/mappi3/mappi3_pld.h @@ -1,5 +1,5 @@ /* - * include/asm/mappi3/mappi3_pld.h + * include/asm-m32r/mappi3/mappi3_pld.h * * Definitions for Extended IO Logic on MAPPI3 board. * based on m32700ut_pld.h diff --git a/include/asm-m32r/opsput/opsput_lan.h b/include/asm-m32r/opsput/opsput_lan.h index 61948296f445..f53e10187c03 100644 --- a/include/asm-m32r/opsput/opsput_lan.h +++ b/include/asm-m32r/opsput/opsput_lan.h @@ -1,5 +1,5 @@ /* - * include/asm/opsput_lan.h + * include/asm-m32r/opsput/opsput_lan.h * * OPSPUT-LAN board * diff --git a/include/asm-m32r/opsput/opsput_lcd.h b/include/asm-m32r/opsput/opsput_lcd.h index 44cfd7fe2d88..99f296e1b61b 100644 --- a/include/asm-m32r/opsput/opsput_lcd.h +++ b/include/asm-m32r/opsput/opsput_lcd.h @@ -1,5 +1,5 @@ /* - * include/asm/opsput_lcd.h + * include/asm-m32r/opsput/opsput_lcd.h * * OPSPUT-LCD board * diff --git a/include/asm-m32r/opsput/opsput_pld.h b/include/asm-m32r/opsput/opsput_pld.h index 46296fe1ec1a..a8d6452076f1 100644 --- a/include/asm-m32r/opsput/opsput_pld.h +++ b/include/asm-m32r/opsput/opsput_pld.h @@ -1,5 +1,5 @@ /* - * include/asm/opsput/opsput_pld.h + * include/asm-m32r/opsput/opsput_pld.h * * Definitions for Programable Logic Device(PLD) on OPSPUT board. * diff --git a/include/asm-m68k/rtc.h b/include/asm-m68k/rtc.h index 71406fc4e599..5d3e03859844 100644 --- a/include/asm-m68k/rtc.h +++ b/include/asm-m68k/rtc.h @@ -1,4 +1,4 @@ -/* asm-m68k/rtc.h +/* include/asm-m68k/rtc.h * * Copyright Richard Zidlicky * implementation details for genrtc/q40rtc driver diff --git a/include/asm-m68knommu/processor.h b/include/asm-m68knommu/processor.h index 9d3a1bf41231..91cba18acdd3 100644 --- a/include/asm-m68knommu/processor.h +++ b/include/asm-m68knommu/processor.h @@ -1,5 +1,5 @@ /* - * include/asm-m68k/processor.h + * include/asm-m68knommu/processor.h * * Copyright (C) 1995 Hamish Macdonald */ diff --git a/include/asm-mips/tx4938/tx4938_mips.h b/include/asm-mips/tx4938/tx4938_mips.h index cf89b205f103..5f8498fef005 100644 --- a/include/asm-mips/tx4938/tx4938_mips.h +++ b/include/asm-mips/tx4938/tx4938_mips.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-mips/tx4938/tx4938_bitmask.h + * linux/include/asm-mips/tx4938/tx4938_mips.h * Generic bitmask definitions * * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the diff --git a/include/asm-parisc/rtc.h b/include/asm-parisc/rtc.h index f3d3d6b110ba..f4ebff11dcbd 100644 --- a/include/asm-parisc/rtc.h +++ b/include/asm-parisc/rtc.h @@ -1,5 +1,5 @@ /* - * inclue/asm-parisc/rtc.h + * include/asm-parisc/rtc.h * * Copyright 2002 Randolph CHung * diff --git a/include/asm-powerpc/ipic.h b/include/asm-powerpc/ipic.h index 53079ec3a515..1ce09a35906e 100644 --- a/include/asm-powerpc/ipic.h +++ b/include/asm-powerpc/ipic.h @@ -1,5 +1,5 @@ /* - * include/asm-ppc/ipic.h + * include/asm-powerpc/ipic.h * * IPIC external definitions and structure. * diff --git a/include/asm-ppc/mv64x60_defs.h b/include/asm-ppc/mv64x60_defs.h index f8f7f16b9b53..5b0704a3e6ea 100644 --- a/include/asm-ppc/mv64x60_defs.h +++ b/include/asm-ppc/mv64x60_defs.h @@ -1,5 +1,5 @@ /* - * include/asm-ppc/gt64260_defs.h + * include/asm-ppc/mv64x60_defs.h * * Register definitions for the Marvell/Galileo GT64260, MV64360, etc. * host bridges. diff --git a/include/asm-ppc/rheap.h b/include/asm-ppc/rheap.h index 65b93225a778..39a10d862244 100644 --- a/include/asm-ppc/rheap.h +++ b/include/asm-ppc/rheap.h @@ -1,5 +1,5 @@ /* - * include/asm-ppc/rheap.c + * include/asm-ppc/rheap.h * * Header file for the implementation of a remote heap. * diff --git a/include/asm-ppc/rtc.h b/include/asm-ppc/rtc.h index 05fbf912ab4d..6025b46d0a2a 100644 --- a/include/asm-ppc/rtc.h +++ b/include/asm-ppc/rtc.h @@ -1,5 +1,5 @@ /* - * inclue/asm-ppc/rtc.h + * include/asm-ppc/rtc.h * * Author: Tom Rini * diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h index a2f37a9353d3..7189c79bc673 100644 --- a/include/asm-s390/qdio.h +++ b/include/asm-s390/qdio.h @@ -1,5 +1,5 @@ /* - * linux/include/asm/qdio.h + * linux/include/asm-s390/qdio.h * * Linux for S/390 QDIO base support, Hipersocket base support * version 2 diff --git a/include/asm-sh/bigsur/io.h b/include/asm-sh/bigsur/io.h index 939735ee8dc5..1470ac8d4a39 100644 --- a/include/asm-sh/bigsur/io.h +++ b/include/asm-sh/bigsur/io.h @@ -1,5 +1,5 @@ /* - * include/asm-sh/io_bigsur.h + * include/asm-sh/bigsur/io.h * * By Dustin McIntire (dustin@sensoria.com) (c)2001 * Derived from io_hd64465.h, which bore the message: diff --git a/include/asm-sh/bigsur/serial.h b/include/asm-sh/bigsur/serial.h index 7233af42f755..a08fa82fe45a 100644 --- a/include/asm-sh/bigsur/serial.h +++ b/include/asm-sh/bigsur/serial.h @@ -1,5 +1,5 @@ /* - * include/asm-sh/serial-bigsur.h + * include/asm-sh/bigsur/serial.h * * Configuration details for Big Sur 16550 based serial ports * i.e. HD64465, PCMCIA, etc. diff --git a/include/asm-sh/dreamcast/sysasic.h b/include/asm-sh/dreamcast/sysasic.h index c8858537803c..7874e3dac736 100644 --- a/include/asm-sh/dreamcast/sysasic.h +++ b/include/asm-sh/dreamcast/sysasic.h @@ -1,4 +1,4 @@ -/* include/asm-sh/dc_sysasic.h +/* include/asm-sh/dreamcast/sysasic.h * * Definitions for the Dreamcast System ASIC and related peripherals. * diff --git a/include/asm-sh/hd64465/io.h b/include/asm-sh/hd64465/io.h index 1100bcf4968e..139f1472e5bb 100644 --- a/include/asm-sh/hd64465/io.h +++ b/include/asm-sh/hd64465/io.h @@ -1,5 +1,5 @@ /* - * include/asm-sh/io_hd64465.h + * include/asm-sh/hd64465/io.h * * By Greg Banks * (c) 2000 PocketPenguins Inc. diff --git a/include/asm-sh/mpc1211/io.h b/include/asm-sh/mpc1211/io.h index eba8a0b5fd7b..6298370bec2d 100644 --- a/include/asm-sh/mpc1211/io.h +++ b/include/asm-sh/mpc1211/io.h @@ -1,5 +1,5 @@ /* - * include/asm-sh/io_mpc1211.h + * include/asm-sh/mpc1211/io.h * * Copyright 2001 Saito.K & Jeanne * diff --git a/include/asm-sh64/serial.h b/include/asm-sh64/serial.h index 29c9be15112b..e8d7b3f2da57 100644 --- a/include/asm-sh64/serial.h +++ b/include/asm-sh64/serial.h @@ -1,5 +1,5 @@ /* - * include/asm-sh/serial.h + * include/asm-sh64/serial.h * * Configuration details for 8250, 16450, 16550, etc. serial ports */ diff --git a/include/asm-sparc/reg.h b/include/asm-sparc/reg.h index ed60ebec5930..ea0a7e590bb3 100644 --- a/include/asm-sparc/reg.h +++ b/include/asm-sparc/reg.h @@ -1,5 +1,5 @@ /* - * linux/asm-sparc/reg.h + * linux/include/asm-sparc/reg.h * Layout of the registers as expected by gdb on the Sparc * we should replace the user.h definitions with those in * this file, we don't even use the other diff --git a/include/asm-x86_64/cache.h b/include/asm-x86_64/cache.h index ed8a9d25272d..052df758ae61 100644 --- a/include/asm-x86_64/cache.h +++ b/include/asm-x86_64/cache.h @@ -1,5 +1,5 @@ /* - * include/asm-x8664/cache.h + * include/asm-x86_64/cache.h */ #ifndef __ARCH_X8664_CACHE_H #define __ARCH_X8664_CACHE_H diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h index 3be701dfe098..ffc4dcfd6ac1 100644 --- a/include/asm-xtensa/a.out.h +++ b/include/asm-xtensa/a.out.h @@ -1,5 +1,5 @@ /* - * include/asm-xtensa/addrspace.h + * include/asm-xtensa/a.out.h * * Dummy a.out file. Xtensa does not support the a.out format, but the kernel * seems to depend on it. diff --git a/include/asm-xtensa/cache.h b/include/asm-xtensa/cache.h index 5aae3f12407c..1e79c0e27460 100644 --- a/include/asm-xtensa/cache.h +++ b/include/asm-xtensa/cache.h @@ -1,5 +1,5 @@ /* - * include/asm-xtensa/cacheflush.h + * include/asm-xtensa/cache.h * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff --git a/include/asm-xtensa/coprocessor.h b/include/asm-xtensa/coprocessor.h index a91b96dc0efe..5093034723be 100644 --- a/include/asm-xtensa/coprocessor.h +++ b/include/asm-xtensa/coprocessor.h @@ -1,5 +1,5 @@ /* - * include/asm-xtensa/cpextra.h + * include/asm-xtensa/coprocessor.h * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff --git a/include/asm-xtensa/dma-mapping.h b/include/asm-xtensa/dma-mapping.h index c425f10d086a..c39c91dfcc69 100644 --- a/include/asm-xtensa/dma-mapping.h +++ b/include/asm-xtensa/dma-mapping.h @@ -1,5 +1,5 @@ /* - * include/asm-xtensa/dma_mapping.h + * include/asm-xtensa/dma-mapping.h * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff --git a/include/asm-xtensa/ioctls.h b/include/asm-xtensa/ioctls.h index 3b89a772d0a0..39e6f23921bb 100644 --- a/include/asm-xtensa/ioctls.h +++ b/include/asm-xtensa/ioctls.h @@ -1,5 +1,5 @@ /* - * include/asm-xtensa/ioctl.h + * include/asm-xtensa/ioctls.h * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h index a47cc734c20c..b4318934b10d 100644 --- a/include/asm-xtensa/pgtable.h +++ b/include/asm-xtensa/pgtable.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-xtensa/page.h + * linux/include/asm-xtensa/pgtable.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version2 as diff --git a/include/asm-xtensa/siginfo.h b/include/asm-xtensa/siginfo.h index 44f0ae77b539..6916248295df 100644 --- a/include/asm-xtensa/siginfo.h +++ b/include/asm-xtensa/siginfo.h @@ -1,5 +1,5 @@ /* - * include/asm-xtensa/processor.h + * include/asm-xtensa/siginfo.h * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff --git a/include/linux/aio_abi.h b/include/linux/aio_abi.h index 3466b1d0ffd2..e3ca0a485cc6 100644 --- a/include/linux/aio_abi.h +++ b/include/linux/aio_abi.h @@ -1,4 +1,4 @@ -/* linux/aio_abi.h +/* include/linux/aio_abi.h * * Copyright 2000,2001,2002 Red Hat. * diff --git a/include/linux/awe_voice.h b/include/linux/awe_voice.h index 4bf9f33048e2..bf33f17bea99 100644 --- a/include/linux/awe_voice.h +++ b/include/linux/awe_voice.h @@ -1,5 +1,5 @@ /* - * sound/awe_voice.h + * include/linux/awe_voice.h * * Voice information definitions for the low level driver for the * AWE32/SB32/AWE64 wave table synth. diff --git a/include/linux/harrier_defs.h b/include/linux/harrier_defs.h index 685b252e16cc..efef11db790f 100644 --- a/include/linux/harrier_defs.h +++ b/include/linux/harrier_defs.h @@ -1,5 +1,5 @@ /* - * asm-ppc/harrier_defs.h + * include/linux/harrier_defs.h * * Definitions for Motorola MCG Harrier North Bridge & Memory controller * diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h index cee36e7c0548..3cc1ae25009b 100644 --- a/include/linux/lockd/xdr4.h +++ b/include/linux/lockd/xdr4.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/lockd/xdr.h + * linux/include/linux/lockd/xdr4.h * * XDR types for the NLM protocol * diff --git a/include/linux/mtd/plat-ram.h b/include/linux/mtd/plat-ram.h index 2332eda07e0e..9667863bd7e3 100644 --- a/include/linux/mtd/plat-ram.h +++ b/include/linux/mtd/plat-ram.h @@ -1,4 +1,4 @@ -/* linux/include/mtd/plat-ram.h +/* linux/include/linux/mtd/plat-ram.h * * (c) 2004 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ diff --git a/include/linux/nfsd/stats.h b/include/linux/nfsd/stats.h index 28a82fdd922f..7678cfbe9960 100644 --- a/include/linux/nfsd/stats.h +++ b/include/linux/nfsd/stats.h @@ -1,5 +1,5 @@ /* - * linux/include/nfsd/stats.h + * linux/include/linux/nfsd/stats.h * * Statistics for NFS server. * diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h index 3f4f7142bbe3..a38f9d776de9 100644 --- a/include/linux/nfsd/xdr.h +++ b/include/linux/nfsd/xdr.h @@ -1,5 +1,5 @@ /* - * linux/inxlude/linux/nfsd/xdr.h + * linux/include/linux/nfsd/xdr.h * * XDR types for nfsd. This is mainly a typing exercise. */ diff --git a/include/linux/ppdev.h b/include/linux/ppdev.h index f376a7598a78..dc18c5d23ebe 100644 --- a/include/linux/ppdev.h +++ b/include/linux/ppdev.h @@ -1,5 +1,5 @@ /* - * linux/drivers/char/ppdev.h + * linux/include/linux/ppdev.h * * User-space parallel port device driver (header file). * diff --git a/include/linux/slab.h b/include/linux/slab.h index a96fd9310d55..70be57d8ae0d 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -1,5 +1,5 @@ /* - * linux/mm/slab.h + * linux/include/linux/slab.h * Written by Mark Hemment, 1996. * (markhe@nextd.demon.co.uk) */ diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h index 03084dc4bb6a..97b62e97dd8d 100644 --- a/include/linux/sunrpc/auth_gss.h +++ b/include/linux/sunrpc/auth_gss.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/auth_gss.h + * linux/include/linux/sunrpc/auth_gss.h * * Declarations for RPCSEC_GSS * diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index 6e112cc5cdda..5eca9e442051 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/gss_api.h + * linux/include/linux/sunrpc/gss_api.h * * Somewhat simplified version of the gss api. * diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h index d9f5934ac9fe..8d10d148834e 100644 --- a/include/linux/sunrpc/msg_prot.h +++ b/include/linux/sunrpc/msg_prot.h @@ -1,5 +1,5 @@ /* - * linux/include/net/sunrpc/msg_prot.h + * linux/include/linux/sunrpc/msg_prot.h * * Copyright (C) 1996, Olaf Kirch */ diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h index 3a2206f61de0..5a5db16ab660 100644 --- a/include/linux/sunrpc/svcauth_gss.h +++ b/include/linux/sunrpc/svcauth_gss.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/svcauth_gss.h + * linux/include/linux/sunrpc/svcauth_gss.h * * Bruce Fields * Copyright (c) 2002 The Regents of the Unviersity of Michigan diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 4f4d98addb44..a341c8032866 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -1,5 +1,5 @@ /* - * include/linux/writeback.h. + * include/linux/writeback.h */ #ifndef WRITEBACK_H #define WRITEBACK_H diff --git a/include/video/s1d13xxxfb.h b/include/video/s1d13xxxfb.h index f06cc88607f5..c99d261df8f7 100644 --- a/include/video/s1d13xxxfb.h +++ b/include/video/s1d13xxxfb.h @@ -1,4 +1,4 @@ -/* drivers/video/s1d3xxxfb.h +/* include/video/s1d13xxxfb.h * * (c) 2004 Simtec Electronics * (c) 2005 Thibaut VARENE diff --git a/ipc/msgutil.c b/ipc/msgutil.c index 66cfb87646eb..0992616eeed6 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -1,5 +1,5 @@ /* - * linux/ipc/util.c + * linux/ipc/msgutil.c * Copyright (C) 1999, 2004 Manfred Spraul * * This file is released under GNU General Public Licence version 2 or diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index e5ebcc1ec3a0..9cbb5d1be06f 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c @@ -1,5 +1,5 @@ /* - * linux/kernel/posix_timers.c + * linux/kernel/posix-timers.c * * * 2002-10-15 Posix Clocks & timers diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c index 2cc11faa4ff1..a4b730a2180c 100644 --- a/lib/reed_solomon/reed_solomon.c +++ b/lib/reed_solomon/reed_solomon.c @@ -1,5 +1,5 @@ /* - * lib/reed_solomon/rslib.c + * lib/reed_solomon/reed_solomon.c * * Overview: * Generic Reed Solomon encoder / decoder library diff --git a/mm/page-writeback.c b/mm/page-writeback.c index c0d4ce144dec..a0f339057449 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1,5 +1,5 @@ /* - * mm/page-writeback.c. + * mm/page-writeback.c * * Copyright (C) 2002, Linus Torvalds. * diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index cfe5c8474286..cfb5d3de9c84 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1,4 +1,4 @@ -/* linux/net/inet/arp.c +/* linux/net/ipv4/arp.c * * Version: $Id: arp.c,v 1.99 2001/08/30 22:55:42 davem Exp $ * diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index a6ed2d22a6e6..b36b9463f5a4 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -1,5 +1,5 @@ /* - * linux/net/sunrpc/auth_gss.c + * linux/net/sunrpc/auth_gss/auth_gss.c * * RPCSEC_GSS client authentication. * diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c index 3b45e11e5303..f6b6b886c2ad 100644 --- a/sound/oss/ad1848.c +++ b/sound/oss/ad1848.c @@ -1,5 +1,5 @@ /* - * sound/ad1848.c + * sound/oss/ad1848.c * * The low level driver for the AD1848/CS4248 codec chip which * is used for example in the MS Sound System. diff --git a/sound/oss/ad1848_mixer.h b/sound/oss/ad1848_mixer.h index f9231c6cd4e1..2cf719b5fbbc 100644 --- a/sound/oss/ad1848_mixer.h +++ b/sound/oss/ad1848_mixer.h @@ -1,5 +1,5 @@ /* - * sound/ad1848_mixer.h + * sound/oss/ad1848_mixer.h * * Definitions for the mixer of AD1848 and compatible codecs. */ diff --git a/sound/oss/adlib_card.c b/sound/oss/adlib_card.c index 6414ceb8f072..c9a7c9b470de 100644 --- a/sound/oss/adlib_card.c +++ b/sound/oss/adlib_card.c @@ -1,5 +1,5 @@ /* - * sound/adlib_card.c + * sound/oss/adlib_card.c * * Detection routine for the AdLib card. * diff --git a/sound/oss/audio.c b/sound/oss/audio.c index 22dd63c36816..89bd27a5e865 100644 --- a/sound/oss/audio.c +++ b/sound/oss/audio.c @@ -1,5 +1,5 @@ /* - * sound/audio.c + * sound/oss/audio.c * * Device file manager for /dev/audio */ diff --git a/sound/oss/awe_hw.h b/sound/oss/awe_hw.h index 7e403ad68152..ab00c3c67e4e 100644 --- a/sound/oss/awe_hw.h +++ b/sound/oss/awe_hw.h @@ -1,5 +1,5 @@ /* - * sound/awe_hw.h + * sound/oss/awe_hw.h * * Access routines and definitions for the low level driver for the * Creative AWE32/SB32/AWE64 wave table synth. diff --git a/sound/oss/awe_wave.c b/sound/oss/awe_wave.c index d1a0eb294d6f..01c592cee045 100644 --- a/sound/oss/awe_wave.c +++ b/sound/oss/awe_wave.c @@ -1,5 +1,5 @@ /* - * sound/awe_wave.c + * sound/oss/awe_wave.c * * The low level driver for the AWE32/SB32/AWE64 wave table synth. * version 0.4.4; Jan. 4, 2000 diff --git a/sound/oss/awe_wave.h b/sound/oss/awe_wave.h index a3aa018118bd..fe584810608f 100644 --- a/sound/oss/awe_wave.h +++ b/sound/oss/awe_wave.h @@ -1,5 +1,5 @@ /* - * sound/awe_config.h + * sound/oss/awe_wave.h * * Configuration of AWE32/SB32/AWE64 wave table synth driver. * version 0.4.4; Jan. 4, 2000 diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c index f65a90469d8a..fb64279f3935 100644 --- a/sound/oss/dev_table.c +++ b/sound/oss/dev_table.c @@ -1,5 +1,5 @@ /* - * sound/dev_table.c + * sound/oss/dev_table.c * * Device call tables. * diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c index 15ce7119c5f4..6c1cf74b78c5 100644 --- a/sound/oss/dmabuf.c +++ b/sound/oss/dmabuf.c @@ -1,5 +1,5 @@ /* - * sound/dmabuf.c + * sound/oss/dmabuf.c * * The DMA buffer manager for digitized voice applications */ diff --git a/sound/oss/gus_card.c b/sound/oss/gus_card.c index dbb29771e2bb..a3d6ae33fe8b 100644 --- a/sound/oss/gus_card.c +++ b/sound/oss/gus_card.c @@ -1,5 +1,5 @@ /* - * sound/gus_card.c + * sound/oss/gus_card.c * * Detection routine for the Gravis Ultrasound. * diff --git a/sound/oss/gus_midi.c b/sound/oss/gus_midi.c index b48f57c24e48..d1997a417ad0 100644 --- a/sound/oss/gus_midi.c +++ b/sound/oss/gus_midi.c @@ -1,5 +1,5 @@ /* - * sound/gus2_midi.c + * sound/oss/gus_midi.c * * The low level driver for the GUS Midi Interface. * diff --git a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c index 942d5186580d..597db7aee632 100644 --- a/sound/oss/gus_wave.c +++ b/sound/oss/gus_wave.c @@ -1,5 +1,5 @@ /* - * sound/gus_wave.c + * sound/oss/gus_wave.c * * Driver for the Gravis UltraSound wave table synth. * diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c index 591683c55f27..6601b284f03a 100644 --- a/sound/oss/harmony.c +++ b/sound/oss/harmony.c @@ -1,5 +1,5 @@ /* - drivers/sound/harmony.c + sound/oss/harmony.c This is a sound driver for ASP's and Lasi's Harmony sound chip and is unlikely to be used for anything other than on a HP PA-RISC. diff --git a/sound/oss/ics2101.c b/sound/oss/ics2101.c index d5f3be8550f3..45918df150b3 100644 --- a/sound/oss/ics2101.c +++ b/sound/oss/ics2101.c @@ -1,5 +1,5 @@ /* - * sound/ics2101.c + * sound/oss/ics2101.c * * Driver for the ICS2101 mixer of GUS v3.7. * diff --git a/sound/oss/iwmem.h b/sound/oss/iwmem.h index 84745fbcabcb..48d333c7302b 100644 --- a/sound/oss/iwmem.h +++ b/sound/oss/iwmem.h @@ -1,5 +1,5 @@ /* - * sound/iwmem.h + * sound/oss/iwmem.h * * DRAM size encoding table for AMD Interwave chip. */ diff --git a/sound/oss/maui.c b/sound/oss/maui.c index 05cf194eda6b..317f22589a05 100644 --- a/sound/oss/maui.c +++ b/sound/oss/maui.c @@ -1,5 +1,5 @@ /* - * sound/maui.c + * sound/oss/maui.c * * The low level driver for Turtle Beach Maui and Tropez. * diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c index 972edc62afd1..d2ab5c08b616 100644 --- a/sound/oss/midi_synth.c +++ b/sound/oss/midi_synth.c @@ -1,5 +1,5 @@ /* - * sound/midi_synth.c + * sound/oss/midi_synth.c * * High level midi sequencer manager for dumb MIDI interfaces. */ diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c index 6982556ded56..c0e4bbc22c80 100644 --- a/sound/oss/midibuf.c +++ b/sound/oss/midibuf.c @@ -1,5 +1,5 @@ /* - * sound/midibuf.c + * sound/oss/midibuf.c * * Device file manager for /dev/midi# */ diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index 0aac54c68f01..321f4c4b5a7b 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -1,5 +1,5 @@ /* - * sound/mpu401.c + * sound/oss/mpu401.c * * The low level driver for Roland MPU-401 compatible Midi cards. */ diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c index a31734b7842f..4799bc77f987 100644 --- a/sound/oss/opl3.c +++ b/sound/oss/opl3.c @@ -1,5 +1,5 @@ /* - * sound/opl3.c + * sound/oss/opl3.c * * A low level driver for Yamaha YM3812 and OPL-3 -chips * diff --git a/sound/oss/opl3sa.c b/sound/oss/opl3sa.c index fe4907c6e8fc..2535ed0b5fbf 100644 --- a/sound/oss/opl3sa.c +++ b/sound/oss/opl3sa.c @@ -1,5 +1,5 @@ /* - * sound/opl3sa.c + * sound/oss/opl3sa.c * * Low level driver for Yamaha YMF701B aka OPL3-SA chip * diff --git a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c index aec05a2bfc87..e20051f1be4d 100644 --- a/sound/oss/opl3sa2.c +++ b/sound/oss/opl3sa2.c @@ -1,5 +1,5 @@ /* - * sound/opl3sa2.c + * sound/oss/opl3sa2.c * * A low level driver for Yamaha OPL3-SA2 and SA3 cards. * NOTE: All traces of the name OPL3-SAx have now (December 2000) been diff --git a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c index 97666007b274..4ebb9638746e 100644 --- a/sound/oss/pas2_card.c +++ b/sound/oss/pas2_card.c @@ -1,5 +1,5 @@ /* - * sound/pas2_card.c + * sound/oss/pas2_card.c * * Detection routine for the Pro Audio Spectrum cards. */ diff --git a/sound/oss/pas2_midi.c b/sound/oss/pas2_midi.c index 79d6a5827b6d..1122d10a20c3 100644 --- a/sound/oss/pas2_midi.c +++ b/sound/oss/pas2_midi.c @@ -1,5 +1,5 @@ /* - * sound/pas2_midi.c + * sound/oss/pas2_midi.c * * The low level driver for the PAS Midi Interface. */ diff --git a/sound/oss/pas2_mixer.c b/sound/oss/pas2_mixer.c index 4aade5304587..a0bcb85c3904 100644 --- a/sound/oss/pas2_mixer.c +++ b/sound/oss/pas2_mixer.c @@ -1,6 +1,6 @@ /* - * sound/pas2_mixer.c + * sound/oss/pas2_mixer.c * * Mixer routines for the Pro Audio Spectrum cards. */ diff --git a/sound/oss/pss.c b/sound/oss/pss.c index 37ee234b587c..ece428b2ba9f 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -1,5 +1,5 @@ /* - * sound/pss.c + * sound/oss/pss.c * * The low level driver for the Personal Sound System (ECHO ESC614). * diff --git a/sound/oss/sb_audio.c b/sound/oss/sb_audio.c index 75e54f6f638a..733b014ec7d1 100644 --- a/sound/oss/sb_audio.c +++ b/sound/oss/sb_audio.c @@ -1,5 +1,5 @@ /* - * sound/sb_audio.c + * sound/oss/sb_audio.c * * Audio routines for Sound Blaster compatible cards. * diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c index 35bab6e2f998..bbe5b7596d0e 100644 --- a/sound/oss/sb_common.c +++ b/sound/oss/sb_common.c @@ -1,5 +1,5 @@ /* - * sound/sb_common.c + * sound/oss/sb_common.c * * Common routines for Sound Blaster compatible cards. * diff --git a/sound/oss/sb_midi.c b/sound/oss/sb_midi.c index ed3bd0640ffd..2e3bc045caba 100644 --- a/sound/oss/sb_midi.c +++ b/sound/oss/sb_midi.c @@ -1,5 +1,5 @@ /* - * sound/sb_dsp.c + * sound/oss/sb_midi.c * * The low level driver for the Sound Blaster DS chips. * diff --git a/sound/oss/sb_mixer.c b/sound/oss/sb_mixer.c index ccb21d48d42c..238e2cf44b08 100644 --- a/sound/oss/sb_mixer.c +++ b/sound/oss/sb_mixer.c @@ -1,5 +1,5 @@ /* - * sound/sb_mixer.c + * sound/oss/sb_mixer.c * * The low level mixer driver for the Sound Blaster compatible cards. */ diff --git a/sound/oss/sb_mixer.h b/sound/oss/sb_mixer.h index ab74426157ba..4b9425f085e3 100644 --- a/sound/oss/sb_mixer.h +++ b/sound/oss/sb_mixer.h @@ -1,5 +1,5 @@ /* - * sound/sb_mixer.h + * sound/oss/sb_mixer.h * * Definitions for the SB Pro and SB16 mixers */ diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c index 6815c30e0bc1..0ce4e4ef6fe9 100644 --- a/sound/oss/sequencer.c +++ b/sound/oss/sequencer.c @@ -1,5 +1,5 @@ /* - * sound/sequencer.c + * sound/oss/sequencer.c * * The sequencer personality manager. */ diff --git a/sound/oss/sgalaxy.c b/sound/oss/sgalaxy.c index 3f32d4674371..0bcff6735319 100644 --- a/sound/oss/sgalaxy.c +++ b/sound/oss/sgalaxy.c @@ -1,5 +1,5 @@ /* - * sound/sgalaxy.c + * sound/oss/sgalaxy.c * * Low level driver for Aztech Sound Galaxy cards. * Copyright 1998 Artur Skawina diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c index bc2777dd2ef9..146bf85de958 100644 --- a/sound/oss/sound_timer.c +++ b/sound/oss/sound_timer.c @@ -1,5 +1,5 @@ /* - * sound/sound_timer.c + * sound/oss/sound_timer.c */ /* * Copyright (C) by Hannu Savolainen 1993-1997 diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 0860d6789715..683dc00a8d2b 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -1,5 +1,5 @@ /* - * linux/drivers/sound/soundcard.c + * linux/sound/oss/soundcard.c * * Sound card driver for Linux * diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c index 9ed5211c3168..51f2fa615413 100644 --- a/sound/oss/sscape.c +++ b/sound/oss/sscape.c @@ -1,5 +1,5 @@ /* - * sound/sscape.c + * sound/oss/sscape.c * * Low level driver for Ensoniq SoundScape * diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c index c9d04518b172..107534477a2f 100644 --- a/sound/oss/sys_timer.c +++ b/sound/oss/sys_timer.c @@ -1,5 +1,5 @@ /* - * sound/sys_timer.c + * sound/oss/sys_timer.c * * The default timer for the Level 2 sequencer interface * Uses the (1/HZ sec) timer of kernel. diff --git a/sound/oss/trix.c b/sound/oss/trix.c index d1f1f154dcce..e04169e8e3f8 100644 --- a/sound/oss/trix.c +++ b/sound/oss/trix.c @@ -1,5 +1,5 @@ /* - * sound/trix.c + * sound/oss/trix.c * * Low level driver for the MediaTrix AudioTrix Pro * (MT-0002-PC Control Chip) diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c index a3d75baf6df8..8e18b6e25818 100644 --- a/sound/oss/uart401.c +++ b/sound/oss/uart401.c @@ -1,5 +1,5 @@ /* - * sound/uart401.c + * sound/oss/uart401.c * * MPU-401 UART driver (formerly uart401_midi.c) * diff --git a/sound/oss/uart6850.c b/sound/oss/uart6850.c index 74ae75f9e2dc..501d3e654a67 100644 --- a/sound/oss/uart6850.c +++ b/sound/oss/uart6850.c @@ -1,5 +1,5 @@ /* - * sound/uart6850.c + * sound/oss/uart6850.c * * * Copyright (C) by Hannu Savolainen 1993-1997 diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c index a7ef04fab075..d952b2264da1 100644 --- a/sound/oss/v_midi.c +++ b/sound/oss/v_midi.c @@ -1,5 +1,5 @@ /* - * sound/v_midi.c + * sound/oss/v_midi.c * * The low level driver for the Sound Blaster DS chips. * diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c index 22d26624b34a..59a2f28eb5a5 100644 --- a/sound/oss/waveartist.c +++ b/sound/oss/waveartist.c @@ -1,5 +1,5 @@ /* - * linux/drivers/sound/waveartist.c + * linux/sound/oss/waveartist.c * * The low level driver for the RWA010 Rockwell Wave Artist * codec chip used in the Rebel.com NetWinder. diff --git a/sound/oss/waveartist.h b/sound/oss/waveartist.h index 2033fb87b247..dac4ca910d95 100644 --- a/sound/oss/waveartist.h +++ b/sound/oss/waveartist.h @@ -1,5 +1,5 @@ /* - * linux/drivers/sound/waveartist.h + * linux/sound/oss/waveartist.h * * def file for Rockwell RWA010 chip set, as installed in Rebel.com NetWinder */ diff --git a/sound/oss/wf_midi.c b/sound/oss/wf_midi.c index 3f3a390014ca..75c0c143a759 100644 --- a/sound/oss/wf_midi.c +++ b/sound/oss/wf_midi.c @@ -1,5 +1,5 @@ /* - * sound/wf_midi.c + * sound/oss/wf_midi.c * * The low level driver for the WaveFront ICS2115 MIDI interface(s) * Note that there is also an MPU-401 emulation (actually, a UART-401 -- cgit v1.2.3 From 9865853851313e0d94a4acde42d6f9d8070bb376 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Tue, 3 Oct 2006 23:10:46 -0500 Subject: [POWERPC] Add QUICC Engine (QE) infrastructure Add QUICC Engine (QE) configuration, header files, and QE management and library code that are used by QE devices drivers. Includes Leo's modifications up to, and including, the platform_device to of_device adaptation: "The series of patches add generic QE infrastructure called qe_lib, and MPC8360EMDS board support. Qe_lib is used by QE device drivers such as ucc_geth driver. This version updates QE interrupt controller to use new irq mapping mechanism, addresses all the comments received with last submission and includes some style fixes. v2: Change to use device tree for BCSR and MURAM; Remove I/O port interrupt handling code as it is not generic enough. v3: Address comments from Kumar; Update definition of several device tree nodes; Copyright style change." In addition, the following changes have been made: o removed typedefs o uint -> u32 conversions o removed following defines: QE_SIZEOF_BD, BD_BUFFER_ARG, BD_BUFFER_CLEAR, BD_BUFFER, BD_STATUS_AND_LENGTH_SET, BD_STATUS_AND_LENGTH, and BD_BUFFER_SET because they hid sizeof/in_be32/out_be32 operations from the reader. o fixed qe_snums_init() serial num assignment to use a const array o made CONFIG_UCC_FAST select UCC_SLOW o reduced NR_QE_IC_INTS from 128 to 64 o remove _IO_BASE, etc. defines (not used) o removed irrelevant comments, added others to resemble removed BD_ defines o realigned struct definitions in headers o various other style fixes including things like pinMask -> pin_mask o fixed a ton of whitespace issues o marked ioregs as __be32/__be16 o removed platform_device code and redundant get_qe_base() o removed redundant comments o added cpu_relax() to qe_reset o uncasted all get_property() assignments o eliminated unneeded casts o eliminated immrbar_phys_to_virt (not used) Signed-off-by: Li Yang Signed-off-by: Shlomi Gridish Signed-off-by: Kim Phillips Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 12 + arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/qe_lib/Kconfig | 30 ++ arch/powerpc/sysdev/qe_lib/Makefile | 8 + arch/powerpc/sysdev/qe_lib/qe.c | 353 +++++++++++++++++++++ arch/powerpc/sysdev/qe_lib/qe_ic.c | 555 ++++++++++++++++++++++++++++++++++ arch/powerpc/sysdev/qe_lib/qe_ic.h | 106 +++++++ arch/powerpc/sysdev/qe_lib/qe_io.c | 226 ++++++++++++++ arch/powerpc/sysdev/qe_lib/ucc.c | 251 +++++++++++++++ arch/powerpc/sysdev/qe_lib/ucc_fast.c | 396 ++++++++++++++++++++++++ arch/powerpc/sysdev/qe_lib/ucc_slow.c | 404 +++++++++++++++++++++++++ include/asm-powerpc/immap_qe.h | 477 +++++++++++++++++++++++++++++ include/asm-powerpc/qe.h | 457 ++++++++++++++++++++++++++++ include/asm-powerpc/qe_ic.h | 64 ++++ include/asm-powerpc/ucc.h | 84 +++++ include/asm-powerpc/ucc_fast.h | 243 +++++++++++++++ include/asm-powerpc/ucc_slow.h | 289 ++++++++++++++++++ include/linux/fsl_devices.h | 65 +++- 18 files changed, 4007 insertions(+), 14 deletions(-) create mode 100644 arch/powerpc/sysdev/qe_lib/Kconfig create mode 100644 arch/powerpc/sysdev/qe_lib/Makefile create mode 100644 arch/powerpc/sysdev/qe_lib/qe.c create mode 100644 arch/powerpc/sysdev/qe_lib/qe_ic.c create mode 100644 arch/powerpc/sysdev/qe_lib/qe_ic.h create mode 100644 arch/powerpc/sysdev/qe_lib/qe_io.c create mode 100644 arch/powerpc/sysdev/qe_lib/ucc.c create mode 100644 arch/powerpc/sysdev/qe_lib/ucc_fast.c create mode 100644 arch/powerpc/sysdev/qe_lib/ucc_slow.c create mode 100644 include/asm-powerpc/immap_qe.h create mode 100644 include/asm-powerpc/qe.h create mode 100644 include/asm-powerpc/qe_ic.h create mode 100644 include/asm-powerpc/ucc.h create mode 100644 include/asm-powerpc/ucc_fast.h create mode 100644 include/asm-powerpc/ucc_slow.h (limited to 'include/linux') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b29adaa97348..2587468eec43 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -351,6 +351,16 @@ config APUS . endchoice +config QUICC_ENGINE + bool + depends on PPC_MPC836x || PPC_MPC832x + default y + help + The QUICC Engine (QE) is a new generation of communications + coprocessors on Freescale embedded CPUs (akin to CPM in older chips). + Selecting this option means that you wish to build a kernel + for a machine with a QE coprocessor. + config PPC_PSERIES depends on PPC_MULTIPLATFORM && PPC64 bool "IBM pSeries & new (POWER5-based) iSeries" @@ -1059,6 +1069,8 @@ source "fs/Kconfig" # XXX source "arch/ppc/8260_io/Kconfig" +source "arch/powerpc/sysdev/qe_lib/Kconfig" + source "arch/powerpc/platforms/iseries/Kconfig" source "lib/Kconfig" diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index f15f4d78aee9..91f052d8cce0 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_PPC_TODC) += todc.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o +obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig new file mode 100644 index 000000000000..a725e80befa8 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/Kconfig @@ -0,0 +1,30 @@ +# +# QE Communication options +# + +menu "QE Options" + depends on QUICC_ENGINE + +config UCC_SLOW + bool "UCC Slow Protocols Support" + default n + select UCC + help + This option provides qe_lib support to UCC slow + protocols: UART, BISYNC, QMC + +config UCC_FAST + bool "UCC Fast Protocols Support" + default n + select UCC + select UCC_SLOW + help + This option provides qe_lib support to UCC fast + protocols: HDLC, Ethernet, ATM, transparent + +config UCC + bool + default y if UCC_FAST || UCC_SLOW + +endmenu + diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/sysdev/qe_lib/Makefile new file mode 100644 index 000000000000..874fe1a5b1cf --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the linux ppc-specific parts of QE +# +obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_ic.o qe_io.o + +obj-$(CONFIG_UCC) += ucc.o +obj-$(CONFIG_UCC_SLOW) += ucc_slow.o +obj-$(CONFIG_UCC_FAST) += ucc_fast.o diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c new file mode 100644 index 000000000000..2bae632d3ad7 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Authors: Shlomi Gridish + * Li Yang + * Based on cpm2_common.c from Dan Malek (dmalek@jlc.net) + * + * Description: + * General Purpose functions for the global management of the + * QUICC Engine (QE). + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void qe_snums_init(void); +static void qe_muram_init(void); +static int qe_sdma_init(void); + +static DEFINE_SPINLOCK(qe_lock); + +/* QE snum state */ +enum qe_snum_state { + QE_SNUM_STATE_USED, + QE_SNUM_STATE_FREE +}; + +/* QE snum */ +struct qe_snum { + u8 num; + enum qe_snum_state state; +}; + +/* We allocate this here because it is used almost exclusively for + * the communication processor devices. + */ +struct qe_immap *qe_immr = NULL; +EXPORT_SYMBOL(qe_immr); + +static struct qe_snum snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */ + +static phys_addr_t qebase = -1; + +phys_addr_t get_qe_base(void) +{ + struct device_node *qe; + + if (qebase != -1) + return qebase; + + qe = of_find_node_by_type(NULL, "qe"); + if (qe) { + unsigned int size; + const void *prop = get_property(qe, "reg", &size); + qebase = of_translate_address(qe, prop); + of_node_put(qe); + }; + + return qebase; +} + +EXPORT_SYMBOL(get_qe_base); + +void qe_reset(void) +{ + if (qe_immr == NULL) + qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE); + + qe_snums_init(); + + qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, + QE_CR_PROTOCOL_UNSPECIFIED, 0); + + /* Reclaim the MURAM memory for our use. */ + qe_muram_init(); + + if (qe_sdma_init()) + panic("sdma init failed!"); +} + +int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input) +{ + unsigned long flags; + u8 mcn_shift = 0, dev_shift = 0; + + spin_lock_irqsave(&qe_lock, flags); + if (cmd == QE_RESET) { + out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG)); + } else { + if (cmd == QE_ASSIGN_PAGE) { + /* Here device is the SNUM, not sub-block */ + dev_shift = QE_CR_SNUM_SHIFT; + } else if (cmd == QE_ASSIGN_RISC) { + /* Here device is the SNUM, and mcnProtocol is + * e_QeCmdRiscAssignment value */ + dev_shift = QE_CR_SNUM_SHIFT; + mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT; + } else { + if (device == QE_CR_SUBBLOCK_USB) + mcn_shift = QE_CR_MCN_USB_SHIFT; + else + mcn_shift = QE_CR_MCN_NORMAL_SHIFT; + } + + out_be32(&qe_immr->cp.cecdr, + immrbar_virt_to_phys((void *)cmd_input)); + out_be32(&qe_immr->cp.cecr, + (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32) + mcn_protocol << mcn_shift)); + } + + /* wait for the QE_CR_FLG to clear */ + while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) + cpu_relax(); + spin_unlock_irqrestore(&qe_lock, flags); + + return 0; +} +EXPORT_SYMBOL(qe_issue_cmd); + +/* Set a baud rate generator. This needs lots of work. There are + * 16 BRGs, which can be connected to the QE channels or output + * as clocks. The BRGs are in two different block of internal + * memory mapped space. + * The baud rate clock is the system clock divided by something. + * It was set up long ago during the initial boot phase and is + * is given to us. + * Baud rate clocks are zero-based in the driver code (as that maps + * to port numbers). Documentation uses 1-based numbering. + */ +static unsigned int brg_clk = 0; + +unsigned int get_brg_clk(void) +{ + struct device_node *qe; + if (brg_clk) + return brg_clk; + + qe = of_find_node_by_type(NULL, "qe"); + if (qe) { + unsigned int size; + const u32 *prop = get_property(qe, "brg-frequency", &size); + brg_clk = *prop; + of_node_put(qe); + }; + return brg_clk; +} + +/* This function is used by UARTS, or anything else that uses a 16x + * oversampled clock. + */ +void qe_setbrg(u32 brg, u32 rate) +{ + volatile u32 *bp; + u32 divisor, tempval; + int div16 = 0; + + bp = &qe_immr->brg.brgc1; + bp += brg; + + divisor = (get_brg_clk() / rate); + if (divisor > QE_BRGC_DIVISOR_MAX + 1) { + div16 = 1; + divisor /= 16; + } + + tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; + if (div16) + tempval |= QE_BRGC_DIV16; + + out_be32(bp, tempval); +} + +/* Initialize SNUMs (thread serial numbers) according to + * QE Module Control chapter, SNUM table + */ +static void qe_snums_init(void) +{ + int i; + static const u8 snum_init[] = { + 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, + 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89, + 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9, + 0xD8, 0xD9, 0xE8, 0xE9, + }; + + for (i = 0; i < QE_NUM_OF_SNUM; i++) { + snums[i].num = snum_init[i]; + snums[i].state = QE_SNUM_STATE_FREE; + } +} + +int qe_get_snum(void) +{ + unsigned long flags; + int snum = -EBUSY; + int i; + + spin_lock_irqsave(&qe_lock, flags); + for (i = 0; i < QE_NUM_OF_SNUM; i++) { + if (snums[i].state == QE_SNUM_STATE_FREE) { + snums[i].state = QE_SNUM_STATE_USED; + snum = snums[i].num; + break; + } + } + spin_unlock_irqrestore(&qe_lock, flags); + + return snum; +} +EXPORT_SYMBOL(qe_get_snum); + +void qe_put_snum(u8 snum) +{ + int i; + + for (i = 0; i < QE_NUM_OF_SNUM; i++) { + if (snums[i].num == snum) { + snums[i].state = QE_SNUM_STATE_FREE; + break; + } + } +} +EXPORT_SYMBOL(qe_put_snum); + +static int qe_sdma_init(void) +{ + struct sdma *sdma = &qe_immr->sdma; + u32 sdma_buf_offset; + + if (!sdma) + return -ENODEV; + + /* allocate 2 internal temporary buffers (512 bytes size each) for + * the SDMA */ + sdma_buf_offset = qe_muram_alloc(512 * 2, 64); + if (IS_MURAM_ERR(sdma_buf_offset)) + return -ENOMEM; + + out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK); + out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | (0x1 >> + QE_SDMR_CEN_SHIFT))); + + return 0; +} + +/* + * muram_alloc / muram_free bits. + */ +static DEFINE_SPINLOCK(qe_muram_lock); + +/* 16 blocks should be enough to satisfy all requests + * until the memory subsystem goes up... */ +static rh_block_t qe_boot_muram_rh_block[16]; +static rh_info_t qe_muram_info; + +static void qe_muram_init(void) +{ + struct device_node *np; + u32 address; + u64 size; + unsigned int flags; + + /* initialize the info header */ + rh_init(&qe_muram_info, 1, + sizeof(qe_boot_muram_rh_block) / + sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block); + + /* Attach the usable muram area */ + /* XXX: This is a subset of the available muram. It + * varies with the processor and the microcode patches activated. + */ + if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) { + address = *of_get_address(np, 0, &size, &flags); + of_node_put(np); + rh_attach_region(&qe_muram_info, + (void *)address, (int)size); + } +} + +/* This function returns an index into the MURAM area. + */ +u32 qe_muram_alloc(u32 size, u32 align) +{ + void *start; + unsigned long flags; + + spin_lock_irqsave(&qe_muram_lock, flags); + start = rh_alloc_align(&qe_muram_info, size, align, "QE"); + spin_unlock_irqrestore(&qe_muram_lock, flags); + + return (u32) start; +} +EXPORT_SYMBOL(qe_muram_alloc); + +int qe_muram_free(u32 offset) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&qe_muram_lock, flags); + ret = rh_free(&qe_muram_info, (void *)offset); + spin_unlock_irqrestore(&qe_muram_lock, flags); + + return ret; +} +EXPORT_SYMBOL(qe_muram_free); + +/* not sure if this is ever needed */ +u32 qe_muram_alloc_fixed(u32 offset, u32 size) +{ + void *start; + unsigned long flags; + + spin_lock_irqsave(&qe_muram_lock, flags); + start = rh_alloc_fixed(&qe_muram_info, (void *)offset, size, "commproc"); + spin_unlock_irqrestore(&qe_muram_lock, flags); + + return (u32) start; +} +EXPORT_SYMBOL(qe_muram_alloc_fixed); + +void qe_muram_dump(void) +{ + rh_dump(&qe_muram_info); +} +EXPORT_SYMBOL(qe_muram_dump); + +void *qe_muram_addr(u32 offset) +{ + return (void *)&qe_immr->muram[offset]; +} +EXPORT_SYMBOL(qe_muram_addr); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c new file mode 100644 index 000000000000..c229d07d4957 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -0,0 +1,555 @@ +/* + * arch/powerpc/sysdev/qe_lib/qe_ic.c + * + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Author: Li Yang + * Based on code from Shlomi Gridish + * + * QUICC ENGINE Interrupt Controller + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qe_ic.h" + +static DEFINE_SPINLOCK(qe_ic_lock); + +static struct qe_ic_info qe_ic_info[] = { + [1] = { + .mask = 0x00008000, + .mask_reg = QEIC_CIMR, + .pri_code = 0, + .pri_reg = QEIC_CIPWCC, + }, + [2] = { + .mask = 0x00004000, + .mask_reg = QEIC_CIMR, + .pri_code = 1, + .pri_reg = QEIC_CIPWCC, + }, + [3] = { + .mask = 0x00002000, + .mask_reg = QEIC_CIMR, + .pri_code = 2, + .pri_reg = QEIC_CIPWCC, + }, + [10] = { + .mask = 0x00000040, + .mask_reg = QEIC_CIMR, + .pri_code = 1, + .pri_reg = QEIC_CIPZCC, + }, + [11] = { + .mask = 0x00000020, + .mask_reg = QEIC_CIMR, + .pri_code = 2, + .pri_reg = QEIC_CIPZCC, + }, + [12] = { + .mask = 0x00000010, + .mask_reg = QEIC_CIMR, + .pri_code = 3, + .pri_reg = QEIC_CIPZCC, + }, + [13] = { + .mask = 0x00000008, + .mask_reg = QEIC_CIMR, + .pri_code = 4, + .pri_reg = QEIC_CIPZCC, + }, + [14] = { + .mask = 0x00000004, + .mask_reg = QEIC_CIMR, + .pri_code = 5, + .pri_reg = QEIC_CIPZCC, + }, + [15] = { + .mask = 0x00000002, + .mask_reg = QEIC_CIMR, + .pri_code = 6, + .pri_reg = QEIC_CIPZCC, + }, + [20] = { + .mask = 0x10000000, + .mask_reg = QEIC_CRIMR, + .pri_code = 3, + .pri_reg = QEIC_CIPRTA, + }, + [25] = { + .mask = 0x00800000, + .mask_reg = QEIC_CRIMR, + .pri_code = 0, + .pri_reg = QEIC_CIPRTB, + }, + [26] = { + .mask = 0x00400000, + .mask_reg = QEIC_CRIMR, + .pri_code = 1, + .pri_reg = QEIC_CIPRTB, + }, + [27] = { + .mask = 0x00200000, + .mask_reg = QEIC_CRIMR, + .pri_code = 2, + .pri_reg = QEIC_CIPRTB, + }, + [28] = { + .mask = 0x00100000, + .mask_reg = QEIC_CRIMR, + .pri_code = 3, + .pri_reg = QEIC_CIPRTB, + }, + [32] = { + .mask = 0x80000000, + .mask_reg = QEIC_CIMR, + .pri_code = 0, + .pri_reg = QEIC_CIPXCC, + }, + [33] = { + .mask = 0x40000000, + .mask_reg = QEIC_CIMR, + .pri_code = 1, + .pri_reg = QEIC_CIPXCC, + }, + [34] = { + .mask = 0x20000000, + .mask_reg = QEIC_CIMR, + .pri_code = 2, + .pri_reg = QEIC_CIPXCC, + }, + [35] = { + .mask = 0x10000000, + .mask_reg = QEIC_CIMR, + .pri_code = 3, + .pri_reg = QEIC_CIPXCC, + }, + [36] = { + .mask = 0x08000000, + .mask_reg = QEIC_CIMR, + .pri_code = 4, + .pri_reg = QEIC_CIPXCC, + }, + [40] = { + .mask = 0x00800000, + .mask_reg = QEIC_CIMR, + .pri_code = 0, + .pri_reg = QEIC_CIPYCC, + }, + [41] = { + .mask = 0x00400000, + .mask_reg = QEIC_CIMR, + .pri_code = 1, + .pri_reg = QEIC_CIPYCC, + }, + [42] = { + .mask = 0x00200000, + .mask_reg = QEIC_CIMR, + .pri_code = 2, + .pri_reg = QEIC_CIPYCC, + }, + [43] = { + .mask = 0x00100000, + .mask_reg = QEIC_CIMR, + .pri_code = 3, + .pri_reg = QEIC_CIPYCC, + }, +}; + +static inline u32 qe_ic_read(volatile __be32 __iomem * base, unsigned int reg) +{ + return in_be32(base + (reg >> 2)); +} + +static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg, + u32 value) +{ + out_be32(base + (reg >> 2), value); +} + +static inline struct qe_ic *qe_ic_from_irq(unsigned int virq) +{ + return irq_desc[virq].chip_data; +} + +#define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) + +static void qe_ic_unmask_irq(unsigned int virq) +{ + struct qe_ic *qe_ic = qe_ic_from_irq(virq); + unsigned int src = virq_to_hw(virq); + unsigned long flags; + u32 temp; + + spin_lock_irqsave(&qe_ic_lock, flags); + + temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg); + qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg, + temp | qe_ic_info[src].mask); + + spin_unlock_irqrestore(&qe_ic_lock, flags); +} + +static void qe_ic_mask_irq(unsigned int virq) +{ + struct qe_ic *qe_ic = qe_ic_from_irq(virq); + unsigned int src = virq_to_hw(virq); + unsigned long flags; + u32 temp; + + spin_lock_irqsave(&qe_ic_lock, flags); + + temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg); + qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg, + temp & ~qe_ic_info[src].mask); + + spin_unlock_irqrestore(&qe_ic_lock, flags); +} + +static void qe_ic_mask_irq_and_ack(unsigned int virq) +{ + struct qe_ic *qe_ic = qe_ic_from_irq(virq); + unsigned int src = virq_to_hw(virq); + unsigned long flags; + u32 temp; + + spin_lock_irqsave(&qe_ic_lock, flags); + + temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg); + qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg, + temp & ~qe_ic_info[src].mask); + + /* There is nothing to do for ack here, ack is handled in ISR */ + + spin_unlock_irqrestore(&qe_ic_lock, flags); +} + +static struct irq_chip qe_ic_irq_chip = { + .typename = " QEIC ", + .unmask = qe_ic_unmask_irq, + .mask = qe_ic_mask_irq, + .mask_ack = qe_ic_mask_irq_and_ack, +}; + +static int qe_ic_host_match(struct irq_host *h, struct device_node *node) +{ + struct qe_ic *qe_ic = h->host_data; + + /* Exact match, unless qe_ic node is NULL */ + return qe_ic->of_node == NULL || qe_ic->of_node == node; +} + +static int qe_ic_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct qe_ic *qe_ic = h->host_data; + struct irq_chip *chip; + + if (qe_ic_info[hw].mask == 0) { + printk(KERN_ERR "Can't map reserved IRQ \n"); + return -EINVAL; + } + /* Default chip */ + chip = &qe_ic->hc_irq; + + set_irq_chip_data(virq, qe_ic); + get_irq_desc(virq)->status |= IRQ_LEVEL; + + set_irq_chip_and_handler(virq, chip, handle_level_irq); + + return 0; +} + +static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct, + u32 * intspec, unsigned int intsize, + irq_hw_number_t * out_hwirq, + unsigned int *out_flags) +{ + *out_hwirq = intspec[0]; + if (intsize > 1) + *out_flags = intspec[1]; + else + *out_flags = IRQ_TYPE_NONE; + return 0; +} + +static struct irq_host_ops qe_ic_host_ops = { + .match = qe_ic_host_match, + .map = qe_ic_host_map, + .xlate = qe_ic_host_xlate, +}; + +/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ +unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic, struct pt_regs *regs) +{ + int irq; + + BUG_ON(qe_ic == NULL); + + /* get the interrupt source vector. */ + irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26; + + if (irq == 0) + return NO_IRQ; + + return irq_linear_revmap(qe_ic->irqhost, irq); +} + +/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ +unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic, struct pt_regs *regs) +{ + int irq; + + BUG_ON(qe_ic == NULL); + + /* get the interrupt source vector. */ + irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26; + + if (irq == 0) + return NO_IRQ; + + return irq_linear_revmap(qe_ic->irqhost, irq); +} + +/* FIXME: We mask all the QE Low interrupts while handling. We should + * let other interrupt come in, but BAD interrupts are generated */ +void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc, + struct pt_regs *regs) +{ + struct qe_ic *qe_ic = desc->handler_data; + struct irq_chip *chip = irq_desc[irq].chip; + + unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic, regs); + + chip->mask_ack(irq); + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq, regs); + chip->unmask(irq); +} + +/* FIXME: We mask all the QE High interrupts while handling. We should + * let other interrupt come in, but BAD interrupts are generated */ +void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc, + struct pt_regs *regs) +{ + struct qe_ic *qe_ic = desc->handler_data; + struct irq_chip *chip = irq_desc[irq].chip; + + unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic, regs); + + chip->mask_ack(irq); + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq, regs); + chip->unmask(irq); +} + +void __init qe_ic_init(struct device_node *node, unsigned int flags) +{ + struct qe_ic *qe_ic; + struct resource res; + u32 temp = 0, ret, high_active = 0; + + qe_ic = alloc_bootmem(sizeof(struct qe_ic)); + if (qe_ic == NULL) + return; + + memset(qe_ic, 0, sizeof(struct qe_ic)); + qe_ic->of_node = node ? of_node_get(node) : NULL; + + qe_ic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, + NR_QE_IC_INTS, &qe_ic_host_ops, 0); + if (qe_ic->irqhost == NULL) { + of_node_put(node); + return; + } + + ret = of_address_to_resource(node, 0, &res); + if (ret) + return; + + qe_ic->regs = ioremap(res.start, res.end - res.start + 1); + + qe_ic->irqhost->host_data = qe_ic; + qe_ic->hc_irq = qe_ic_irq_chip; + + qe_ic->virq_high = irq_of_parse_and_map(node, 0); + qe_ic->virq_low = irq_of_parse_and_map(node, 1); + + if (qe_ic->virq_low == NO_IRQ) { + printk(KERN_ERR "Failed to map QE_IC low IRQ\n"); + return; + } + + /* default priority scheme is grouped. If spread mode is */ + /* required, configure cicr accordingly. */ + if (flags & QE_IC_SPREADMODE_GRP_W) + temp |= CICR_GWCC; + if (flags & QE_IC_SPREADMODE_GRP_X) + temp |= CICR_GXCC; + if (flags & QE_IC_SPREADMODE_GRP_Y) + temp |= CICR_GYCC; + if (flags & QE_IC_SPREADMODE_GRP_Z) + temp |= CICR_GZCC; + if (flags & QE_IC_SPREADMODE_GRP_RISCA) + temp |= CICR_GRTA; + if (flags & QE_IC_SPREADMODE_GRP_RISCB) + temp |= CICR_GRTB; + + /* choose destination signal for highest priority interrupt */ + if (flags & QE_IC_HIGH_SIGNAL) { + temp |= (SIGNAL_HIGH << CICR_HPIT_SHIFT); + high_active = 1; + } + + qe_ic_write(qe_ic->regs, QEIC_CICR, temp); + + set_irq_data(qe_ic->virq_low, qe_ic); + set_irq_chained_handler(qe_ic->virq_low, qe_ic_cascade_low); + + if (qe_ic->virq_high != NO_IRQ) { + set_irq_data(qe_ic->virq_high, qe_ic); + set_irq_chained_handler(qe_ic->virq_high, qe_ic_cascade_high); + } + + printk("QEIC (%d IRQ sources) at %p\n", NR_QE_IC_INTS, qe_ic->regs); +} + +void qe_ic_set_highest_priority(unsigned int virq, int high) +{ + struct qe_ic *qe_ic = qe_ic_from_irq(virq); + unsigned int src = virq_to_hw(virq); + u32 temp = 0; + + temp = qe_ic_read(qe_ic->regs, QEIC_CICR); + + temp &= ~CICR_HP_MASK; + temp |= src << CICR_HP_SHIFT; + + temp &= ~CICR_HPIT_MASK; + temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT; + + qe_ic_write(qe_ic->regs, QEIC_CICR, temp); +} + +/* Set Priority level within its group, from 1 to 8 */ +int qe_ic_set_priority(unsigned int virq, unsigned int priority) +{ + struct qe_ic *qe_ic = qe_ic_from_irq(virq); + unsigned int src = virq_to_hw(virq); + u32 temp; + + if (priority > 8 || priority == 0) + return -EINVAL; + if (src > 127) + return -EINVAL; + if (qe_ic_info[src].pri_reg == 0) + return -EINVAL; + + temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg); + + if (priority < 4) { + temp &= ~(0x7 << (32 - priority * 3)); + temp |= qe_ic_info[src].pri_code << (32 - priority * 3); + } else { + temp &= ~(0x7 << (24 - priority * 3)); + temp |= qe_ic_info[src].pri_code << (24 - priority * 3); + } + + qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp); + + return 0; +} + +/* Set a QE priority to use high irq, only priority 1~2 can use high irq */ +int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high) +{ + struct qe_ic *qe_ic = qe_ic_from_irq(virq); + unsigned int src = virq_to_hw(virq); + u32 temp, control_reg = QEIC_CICNR, shift = 0; + + if (priority > 2 || priority == 0) + return -EINVAL; + + switch (qe_ic_info[src].pri_reg) { + case QEIC_CIPZCC: + shift = CICNR_ZCC1T_SHIFT; + break; + case QEIC_CIPWCC: + shift = CICNR_WCC1T_SHIFT; + break; + case QEIC_CIPYCC: + shift = CICNR_YCC1T_SHIFT; + break; + case QEIC_CIPXCC: + shift = CICNR_XCC1T_SHIFT; + break; + case QEIC_CIPRTA: + shift = CRICR_RTA1T_SHIFT; + control_reg = QEIC_CRICR; + break; + case QEIC_CIPRTB: + shift = CRICR_RTB1T_SHIFT; + control_reg = QEIC_CRICR; + break; + default: + return -EINVAL; + } + + shift += (2 - priority) * 2; + temp = qe_ic_read(qe_ic->regs, control_reg); + temp &= ~(SIGNAL_MASK << shift); + temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift; + qe_ic_write(qe_ic->regs, control_reg, temp); + + return 0; +} + +static struct sysdev_class qe_ic_sysclass = { + set_kset_name("qe_ic"), +}; + +static struct sys_device device_qe_ic = { + .id = 0, + .cls = &qe_ic_sysclass, +}; + +static int __init init_qe_ic_sysfs(void) +{ + int rc; + + printk(KERN_DEBUG "Registering qe_ic with sysfs...\n"); + + rc = sysdev_class_register(&qe_ic_sysclass); + if (rc) { + printk(KERN_ERR "Failed registering qe_ic sys class\n"); + return -ENODEV; + } + rc = sysdev_register(&device_qe_ic); + if (rc) { + printk(KERN_ERR "Failed registering qe_ic sys device\n"); + return -ENODEV; + } + return 0; +} + +subsys_initcall(init_qe_ic_sysfs); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h new file mode 100644 index 000000000000..9a631adb189d --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h @@ -0,0 +1,106 @@ +/* + * arch/powerpc/sysdev/qe_lib/qe_ic.h + * + * QUICC ENGINE Interrupt Controller Header + * + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Author: Li Yang + * Based on code from Shlomi Gridish + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef _POWERPC_SYSDEV_QE_IC_H +#define _POWERPC_SYSDEV_QE_IC_H + +#include + +#define NR_QE_IC_INTS 64 + +/* QE IC registers offset */ +#define QEIC_CICR 0x00 +#define QEIC_CIVEC 0x04 +#define QEIC_CRIPNR 0x08 +#define QEIC_CIPNR 0x0c +#define QEIC_CIPXCC 0x10 +#define QEIC_CIPYCC 0x14 +#define QEIC_CIPWCC 0x18 +#define QEIC_CIPZCC 0x1c +#define QEIC_CIMR 0x20 +#define QEIC_CRIMR 0x24 +#define QEIC_CICNR 0x28 +#define QEIC_CIPRTA 0x30 +#define QEIC_CIPRTB 0x34 +#define QEIC_CRICR 0x3c +#define QEIC_CHIVEC 0x60 + +/* Interrupt priority registers */ +#define CIPCC_SHIFT_PRI0 29 +#define CIPCC_SHIFT_PRI1 26 +#define CIPCC_SHIFT_PRI2 23 +#define CIPCC_SHIFT_PRI3 20 +#define CIPCC_SHIFT_PRI4 13 +#define CIPCC_SHIFT_PRI5 10 +#define CIPCC_SHIFT_PRI6 7 +#define CIPCC_SHIFT_PRI7 4 + +/* CICR priority modes */ +#define CICR_GWCC 0x00040000 +#define CICR_GXCC 0x00020000 +#define CICR_GYCC 0x00010000 +#define CICR_GZCC 0x00080000 +#define CICR_GRTA 0x00200000 +#define CICR_GRTB 0x00400000 +#define CICR_HPIT_SHIFT 8 +#define CICR_HPIT_MASK 0x00000300 +#define CICR_HP_SHIFT 24 +#define CICR_HP_MASK 0x3f000000 + +/* CICNR */ +#define CICNR_WCC1T_SHIFT 20 +#define CICNR_ZCC1T_SHIFT 28 +#define CICNR_YCC1T_SHIFT 12 +#define CICNR_XCC1T_SHIFT 4 + +/* CRICR */ +#define CRICR_RTA1T_SHIFT 20 +#define CRICR_RTB1T_SHIFT 28 + +/* Signal indicator */ +#define SIGNAL_MASK 3 +#define SIGNAL_HIGH 2 +#define SIGNAL_LOW 0 + +struct qe_ic { + /* Control registers offset */ + volatile u32 __iomem *regs; + + /* The remapper for this QEIC */ + struct irq_host *irqhost; + + /* The "linux" controller struct */ + struct irq_chip hc_irq; + + /* The device node of the interrupt controller */ + struct device_node *of_node; + + /* VIRQ numbers of QE high/low irqs */ + unsigned int virq_high; + unsigned int virq_low; +}; + +/* + * QE interrupt controller internal structure + */ +struct qe_ic_info { + u32 mask; /* location of this source at the QIMR register. */ + u32 mask_reg; /* Mask register offset */ + u8 pri_code; /* for grouped interrupts sources - the interrupt + code as appears at the group priority register */ + u32 pri_reg; /* Group priority register offset */ +}; + +#endif /* _POWERPC_SYSDEV_QE_IC_H */ diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c new file mode 100644 index 000000000000..aea435970389 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -0,0 +1,226 @@ +/* + * arch/powerpc/sysdev/qe_lib/qe_io.c + * + * QE Parallel I/O ports configuration routines + * + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Li Yang + * Based on code from Shlomi Gridish + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#undef DEBUG + +#define NUM_OF_PINS 32 + +struct port_regs { + __be32 cpodr; /* Open drain register */ + __be32 cpdata; /* Data register */ + __be32 cpdir1; /* Direction register */ + __be32 cpdir2; /* Direction register */ + __be32 cppar1; /* Pin assignment register */ + __be32 cppar2; /* Pin assignment register */ +}; + +static struct port_regs *par_io = NULL; +static int num_par_io_ports = 0; + +int par_io_init(struct device_node *np) +{ + struct resource res; + int ret; + const u32 *num_ports; + + /* Map Parallel I/O ports registers */ + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + par_io = ioremap(res.start, res.end - res.start + 1); + + num_ports = get_property(np, "num-ports", NULL); + if (num_ports) + num_par_io_ports = *num_ports; + + return 0; +} + +int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, + int assignment, int has_irq) +{ + u32 pin_mask1bit, pin_mask2bits, new_mask2bits, tmp_val; + + if (!par_io) + return -1; + + /* calculate pin location for single and 2 bits information */ + pin_mask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1))); + + /* Set open drain, if required */ + tmp_val = in_be32(&par_io[port].cpodr); + if (open_drain) + out_be32(&par_io[port].cpodr, pin_mask1bit | tmp_val); + else + out_be32(&par_io[port].cpodr, ~pin_mask1bit & tmp_val); + + /* define direction */ + tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? + in_be32(&par_io[port].cpdir2) : + in_be32(&par_io[port].cpdir1); + + /* get all bits mask for 2 bit per port */ + pin_mask2bits = (u32) (0x3 << (NUM_OF_PINS - + (pin % (NUM_OF_PINS / 2) + 1) * 2)); + + /* Get the final mask we need for the right definition */ + new_mask2bits = (u32) (dir << (NUM_OF_PINS - + (pin % (NUM_OF_PINS / 2) + 1) * 2)); + + /* clear and set 2 bits mask */ + if (pin > (NUM_OF_PINS / 2) - 1) { + out_be32(&par_io[port].cpdir2, + ~pin_mask2bits & tmp_val); + tmp_val &= ~pin_mask2bits; + out_be32(&par_io[port].cpdir2, new_mask2bits | tmp_val); + } else { + out_be32(&par_io[port].cpdir1, + ~pin_mask2bits & tmp_val); + tmp_val &= ~pin_mask2bits; + out_be32(&par_io[port].cpdir1, new_mask2bits | tmp_val); + } + /* define pin assignment */ + tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? + in_be32(&par_io[port].cppar2) : + in_be32(&par_io[port].cppar1); + + new_mask2bits = (u32) (assignment << (NUM_OF_PINS - + (pin % (NUM_OF_PINS / 2) + 1) * 2)); + /* clear and set 2 bits mask */ + if (pin > (NUM_OF_PINS / 2) - 1) { + out_be32(&par_io[port].cppar2, + ~pin_mask2bits & tmp_val); + tmp_val &= ~pin_mask2bits; + out_be32(&par_io[port].cppar2, new_mask2bits | tmp_val); + } else { + out_be32(&par_io[port].cppar1, + ~pin_mask2bits & tmp_val); + tmp_val &= ~pin_mask2bits; + out_be32(&par_io[port].cppar1, new_mask2bits | tmp_val); + } + + return 0; +} +EXPORT_SYMBOL(par_io_config_pin); + +int par_io_data_set(u8 port, u8 pin, u8 val) +{ + u32 pin_mask, tmp_val; + + if (port >= num_par_io_ports) + return -EINVAL; + if (pin >= NUM_OF_PINS) + return -EINVAL; + /* calculate pin location */ + pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - pin)); + + tmp_val = in_be32(&par_io[port].cpdata); + + if (val == 0) /* clear */ + out_be32(&par_io[port].cpdata, ~pin_mask & tmp_val); + else /* set */ + out_be32(&par_io[port].cpdata, pin_mask | tmp_val); + + return 0; +} +EXPORT_SYMBOL(par_io_data_set); + +int par_io_of_config(struct device_node *np) +{ + struct device_node *pio; + const phandle *ph; + int pio_map_len; + const unsigned int *pio_map; + + if (par_io == NULL) { + printk(KERN_ERR "par_io not initialized \n"); + return -1; + } + + ph = get_property(np, "pio-handle", NULL); + if (ph == 0) { + printk(KERN_ERR "pio-handle not available \n"); + return -1; + } + + pio = of_find_node_by_phandle(*ph); + + pio_map = get_property(pio, "pio-map", &pio_map_len); + if (pio_map == NULL) { + printk(KERN_ERR "pio-map is not set! \n"); + return -1; + } + pio_map_len /= sizeof(unsigned int); + if ((pio_map_len % 6) != 0) { + printk(KERN_ERR "pio-map format wrong! \n"); + return -1; + } + + while (pio_map_len > 0) { + par_io_config_pin((u8) pio_map[0], (u8) pio_map[1], + (int) pio_map[2], (int) pio_map[3], + (int) pio_map[4], (int) pio_map[5]); + pio_map += 6; + pio_map_len -= 6; + } + of_node_put(pio); + return 0; +} +EXPORT_SYMBOL(par_io_of_config); + +#ifdef DEBUG +static void dump_par_io(void) +{ + int i; + + printk(KERN_INFO "PAR IO registars:\n"); + printk(KERN_INFO "Base address: 0x%08x\n", (u32) par_io); + for (i = 0; i < num_par_io_ports; i++) { + printk(KERN_INFO "cpodr[%d] : addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cpodr, + in_be32(&par_io[i].cpodr)); + printk(KERN_INFO "cpdata[%d]: addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cpdata, + in_be32(&par_io[i].cpdata)); + printk(KERN_INFO "cpdir1[%d]: addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cpdir1, + in_be32(&par_io[i].cpdir1)); + printk(KERN_INFO "cpdir2[%d]: addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cpdir2, + in_be32(&par_io[i].cpdir2)); + printk(KERN_INFO "cppar1[%d]: addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cppar1, + in_be32(&par_io[i].cppar1)); + printk(KERN_INFO "cppar2[%d]: addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cppar2, + in_be32(&par_io[i].cppar2)); + } + +} +EXPORT_SYMBOL(dump_par_io); +#endif /* DEBUG */ diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c new file mode 100644 index 000000000000..916c9e5df57f --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/ucc.c @@ -0,0 +1,251 @@ +/* + * arch/powerpc/sysdev/qe_lib/ucc.c + * + * QE UCC API Set - UCC specific routines implementations. + * + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Authors: Shlomi Gridish + * Li Yang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static DEFINE_SPINLOCK(ucc_lock); + +int ucc_set_qe_mux_mii_mng(int ucc_num) +{ + unsigned long flags; + + spin_lock_irqsave(&ucc_lock, flags); + out_be32(&qe_immr->qmx.cmxgcr, + ((in_be32(&qe_immr->qmx.cmxgcr) & + ~QE_CMXGCR_MII_ENET_MNG) | + (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT))); + spin_unlock_irqrestore(&ucc_lock, flags); + + return 0; +} + +int ucc_set_type(int ucc_num, struct ucc_common *regs, + enum ucc_speed_type speed) +{ + u8 guemr = 0; + + /* check if the UCC number is in range. */ + if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) + return -EINVAL; + + guemr = regs->guemr; + guemr &= ~(UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX); + switch (speed) { + case UCC_SPEED_TYPE_SLOW: + guemr |= (UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX); + break; + case UCC_SPEED_TYPE_FAST: + guemr |= (UCC_GUEMR_MODE_FAST_RX | UCC_GUEMR_MODE_FAST_TX); + break; + default: + return -EINVAL; + } + regs->guemr = guemr; + + return 0; +} + +int ucc_init_guemr(struct ucc_common *regs) +{ + u8 guemr = 0; + + if (!regs) + return -EINVAL; + + /* Set bit 3 (which is reserved in the GUEMR register) to 1 */ + guemr = UCC_GUEMR_SET_RESERVED3; + + regs->guemr = guemr; + + return 0; +} + +static void get_cmxucr_reg(int ucc_num, volatile u32 ** p_cmxucr, u8 * reg_num, + u8 * shift) +{ + switch (ucc_num) { + case 0: *p_cmxucr = &(qe_immr->qmx.cmxucr1); + *reg_num = 1; + *shift = 16; + break; + case 2: *p_cmxucr = &(qe_immr->qmx.cmxucr1); + *reg_num = 1; + *shift = 0; + break; + case 4: *p_cmxucr = &(qe_immr->qmx.cmxucr2); + *reg_num = 2; + *shift = 16; + break; + case 6: *p_cmxucr = &(qe_immr->qmx.cmxucr2); + *reg_num = 2; + *shift = 0; + break; + case 1: *p_cmxucr = &(qe_immr->qmx.cmxucr3); + *reg_num = 3; + *shift = 16; + break; + case 3: *p_cmxucr = &(qe_immr->qmx.cmxucr3); + *reg_num = 3; + *shift = 0; + break; + case 5: *p_cmxucr = &(qe_immr->qmx.cmxucr4); + *reg_num = 4; + *shift = 16; + break; + case 7: *p_cmxucr = &(qe_immr->qmx.cmxucr4); + *reg_num = 4; + *shift = 0; + break; + default: + break; + } +} + +int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask) +{ + volatile u32 *p_cmxucr; + u8 reg_num; + u8 shift; + + /* check if the UCC number is in range. */ + if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) + return -EINVAL; + + get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); + + if (set) + out_be32(p_cmxucr, in_be32(p_cmxucr) | (mask << shift)); + else + out_be32(p_cmxucr, in_be32(p_cmxucr) & ~(mask << shift)); + + return 0; +} + +int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode) +{ + volatile u32 *p_cmxucr; + u8 reg_num; + u8 shift; + u32 clock_bits; + u32 clock_mask; + int source = -1; + + /* check if the UCC number is in range. */ + if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) + return -EINVAL; + + if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) { + printk(KERN_ERR + "ucc_set_qe_mux_rxtx: bad comm mode type passed."); + return -EINVAL; + } + + get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); + + switch (reg_num) { + case 1: + switch (clock) { + case QE_BRG1: source = 1; break; + case QE_BRG2: source = 2; break; + case QE_BRG7: source = 3; break; + case QE_BRG8: source = 4; break; + case QE_CLK9: source = 5; break; + case QE_CLK10: source = 6; break; + case QE_CLK11: source = 7; break; + case QE_CLK12: source = 8; break; + case QE_CLK15: source = 9; break; + case QE_CLK16: source = 10; break; + default: source = -1; break; + } + break; + case 2: + switch (clock) { + case QE_BRG5: source = 1; break; + case QE_BRG6: source = 2; break; + case QE_BRG7: source = 3; break; + case QE_BRG8: source = 4; break; + case QE_CLK13: source = 5; break; + case QE_CLK14: source = 6; break; + case QE_CLK19: source = 7; break; + case QE_CLK20: source = 8; break; + case QE_CLK15: source = 9; break; + case QE_CLK16: source = 10; break; + default: source = -1; break; + } + break; + case 3: + switch (clock) { + case QE_BRG9: source = 1; break; + case QE_BRG10: source = 2; break; + case QE_BRG15: source = 3; break; + case QE_BRG16: source = 4; break; + case QE_CLK3: source = 5; break; + case QE_CLK4: source = 6; break; + case QE_CLK17: source = 7; break; + case QE_CLK18: source = 8; break; + case QE_CLK7: source = 9; break; + case QE_CLK8: source = 10; break; + default: source = -1; break; + } + break; + case 4: + switch (clock) { + case QE_BRG13: source = 1; break; + case QE_BRG14: source = 2; break; + case QE_BRG15: source = 3; break; + case QE_BRG16: source = 4; break; + case QE_CLK5: source = 5; break; + case QE_CLK6: source = 6; break; + case QE_CLK21: source = 7; break; + case QE_CLK22: source = 8; break; + case QE_CLK7: source = 9; break; + case QE_CLK8: source = 10; break; + default: source = -1; break; + } + break; + default: + source = -1; + break; + } + + if (source == -1) { + printk(KERN_ERR + "ucc_set_qe_mux_rxtx: Bad combination of clock and UCC."); + return -ENOENT; + } + + clock_bits = (u32) source; + clock_mask = QE_CMXUCR_TX_CLK_SRC_MASK; + if (mode == COMM_DIR_RX) { + clock_bits <<= 4; /* Rx field is 4 bits to left of Tx field */ + clock_mask <<= 4; /* Rx field is 4 bits to left of Tx field */ + } + clock_bits <<= shift; + clock_mask <<= shift; + + out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clock_mask) | clock_bits); + + return 0; +} diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c new file mode 100644 index 000000000000..c2be7348fcbd --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c @@ -0,0 +1,396 @@ +/* + * arch/powerpc/sysdev/qe_lib/ucc_fast.c + * + * QE UCC Fast API Set - UCC Fast specific routines implementations. + * + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Authors: Shlomi Gridish + * Li Yang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define uccf_printk(level, format, arg...) \ + printk(level format "\n", ## arg) + +#define uccf_dbg(format, arg...) \ + uccf_printk(KERN_DEBUG , format , ## arg) +#define uccf_err(format, arg...) \ + uccf_printk(KERN_ERR , format , ## arg) +#define uccf_info(format, arg...) \ + uccf_printk(KERN_INFO , format , ## arg) +#define uccf_warn(format, arg...) \ + uccf_printk(KERN_WARNING , format , ## arg) + +#ifdef UCCF_VERBOSE_DEBUG +#define uccf_vdbg uccf_dbg +#else +#define uccf_vdbg(fmt, args...) do { } while (0) +#endif /* UCCF_VERBOSE_DEBUG */ + +void ucc_fast_dump_regs(struct ucc_fast_private * uccf) +{ + uccf_info("UCC%d Fast registers:", uccf->uf_info->ucc_num); + uccf_info("Base address: 0x%08x", (u32) uccf->uf_regs); + + uccf_info("gumr : addr - 0x%08x, val - 0x%08x", + (u32) & uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr)); + uccf_info("upsmr : addr - 0x%08x, val - 0x%08x", + (u32) & uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr)); + uccf_info("utodr : addr - 0x%08x, val - 0x%04x", + (u32) & uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr)); + uccf_info("udsr : addr - 0x%08x, val - 0x%04x", + (u32) & uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr)); + uccf_info("ucce : addr - 0x%08x, val - 0x%08x", + (u32) & uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce)); + uccf_info("uccm : addr - 0x%08x, val - 0x%08x", + (u32) & uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm)); + uccf_info("uccs : addr - 0x%08x, val - 0x%02x", + (u32) & uccf->uf_regs->uccs, uccf->uf_regs->uccs); + uccf_info("urfb : addr - 0x%08x, val - 0x%08x", + (u32) & uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb)); + uccf_info("urfs : addr - 0x%08x, val - 0x%04x", + (u32) & uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs)); + uccf_info("urfet : addr - 0x%08x, val - 0x%04x", + (u32) & uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet)); + uccf_info("urfset: addr - 0x%08x, val - 0x%04x", + (u32) & uccf->uf_regs->urfset, + in_be16(&uccf->uf_regs->urfset)); + uccf_info("utfb : addr - 0x%08x, val - 0x%08x", + (u32) & uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb)); + uccf_info("utfs : addr - 0x%08x, val - 0x%04x", + (u32) & uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs)); + uccf_info("utfet : addr - 0x%08x, val - 0x%04x", + (u32) & uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet)); + uccf_info("utftt : addr - 0x%08x, val - 0x%04x", + (u32) & uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt)); + uccf_info("utpt : addr - 0x%08x, val - 0x%04x", + (u32) & uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt)); + uccf_info("urtry : addr - 0x%08x, val - 0x%08x", + (u32) & uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry)); + uccf_info("guemr : addr - 0x%08x, val - 0x%02x", + (u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr); +} + +u32 ucc_fast_get_qe_cr_subblock(int uccf_num) +{ + switch (uccf_num) { + case 0: return QE_CR_SUBBLOCK_UCCFAST1; + case 1: return QE_CR_SUBBLOCK_UCCFAST2; + case 2: return QE_CR_SUBBLOCK_UCCFAST3; + case 3: return QE_CR_SUBBLOCK_UCCFAST4; + case 4: return QE_CR_SUBBLOCK_UCCFAST5; + case 5: return QE_CR_SUBBLOCK_UCCFAST6; + case 6: return QE_CR_SUBBLOCK_UCCFAST7; + case 7: return QE_CR_SUBBLOCK_UCCFAST8; + default: return QE_CR_SUBBLOCK_INVALID; + } +} + +void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf) +{ + out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD); +} + +void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode) +{ + struct ucc_fast *uf_regs; + u32 gumr; + + uf_regs = uccf->uf_regs; + + /* Enable reception and/or transmission on this UCC. */ + gumr = in_be32(&uf_regs->gumr); + if (mode & COMM_DIR_TX) { + gumr |= UCC_FAST_GUMR_ENT; + uccf->enabled_tx = 1; + } + if (mode & COMM_DIR_RX) { + gumr |= UCC_FAST_GUMR_ENR; + uccf->enabled_rx = 1; + } + out_be32(&uf_regs->gumr, gumr); +} + +void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode) +{ + struct ucc_fast *uf_regs; + u32 gumr; + + uf_regs = uccf->uf_regs; + + /* Disable reception and/or transmission on this UCC. */ + gumr = in_be32(&uf_regs->gumr); + if (mode & COMM_DIR_TX) { + gumr &= ~UCC_FAST_GUMR_ENT; + uccf->enabled_tx = 0; + } + if (mode & COMM_DIR_RX) { + gumr &= ~UCC_FAST_GUMR_ENR; + uccf->enabled_rx = 0; + } + out_be32(&uf_regs->gumr, gumr); +} + +int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret) +{ + struct ucc_fast_private *uccf; + struct ucc_fast *uf_regs; + u32 gumr = 0; + int ret; + + uccf_vdbg("%s: IN", __FUNCTION__); + + if (!uf_info) + return -EINVAL; + + /* check if the UCC port number is in range. */ + if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) { + uccf_err("ucc_fast_init: Illagal UCC number!"); + return -EINVAL; + } + + /* Check that 'max_rx_buf_length' is properly aligned (4). */ + if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1)) { + uccf_err("ucc_fast_init: max_rx_buf_length not aligned."); + return -EINVAL; + } + + /* Validate Virtual Fifo register values */ + if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) { + uccf_err + ("ucc_fast_init: Virtual Fifo register urfs too small."); + return -EINVAL; + } + + if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { + uccf_err + ("ucc_fast_init: Virtual Fifo register urfs not aligned."); + return -EINVAL; + } + + if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { + uccf_err + ("ucc_fast_init: Virtual Fifo register urfet not aligned."); + return -EINVAL; + } + + if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { + uccf_err + ("ucc_fast_init: Virtual Fifo register urfset not aligned."); + return -EINVAL; + } + + if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { + uccf_err + ("ucc_fast_init: Virtual Fifo register utfs not aligned."); + return -EINVAL; + } + + if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { + uccf_err + ("ucc_fast_init: Virtual Fifo register utfet not aligned."); + return -EINVAL; + } + + if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { + uccf_err + ("ucc_fast_init: Virtual Fifo register utftt not aligned."); + return -EINVAL; + } + + uccf = (struct ucc_fast_private *) + kmalloc(sizeof(struct ucc_fast_private), GFP_KERNEL); + if (!uccf) { + uccf_err + ("ucc_fast_init: No memory for UCC slow data structure!"); + return -ENOMEM; + } + memset(uccf, 0, sizeof(struct ucc_fast_private)); + + /* Fill fast UCC structure */ + uccf->uf_info = uf_info; + /* Set the PHY base address */ + uccf->uf_regs = + (struct ucc_fast *) ioremap(uf_info->regs, sizeof(struct ucc_fast)); + if (uccf->uf_regs == NULL) { + uccf_err + ("ucc_fast_init: No memory map for UCC slow controller!"); + return -ENOMEM; + } + + uccf->enabled_tx = 0; + uccf->enabled_rx = 0; + uccf->stopped_tx = 0; + uccf->stopped_rx = 0; + uf_regs = uccf->uf_regs; + uccf->p_ucce = (u32 *) & (uf_regs->ucce); + uccf->p_uccm = (u32 *) & (uf_regs->uccm); +#ifdef STATISTICS + uccf->tx_frames = 0; + uccf->rx_frames = 0; + uccf->rx_discarded = 0; +#endif /* STATISTICS */ + + /* Init Guemr register */ + if ((ret = ucc_init_guemr((struct ucc_common *) (uf_regs)))) { + uccf_err("ucc_fast_init: Could not init the guemr register."); + ucc_fast_free(uccf); + return ret; + } + + /* Set UCC to fast type */ + if ((ret = ucc_set_type(uf_info->ucc_num, + (struct ucc_common *) (uf_regs), + UCC_SPEED_TYPE_FAST))) { + uccf_err("ucc_fast_init: Could not set type to fast."); + ucc_fast_free(uccf); + return ret; + } + + uccf->mrblr = uf_info->max_rx_buf_length; + + /* Set GUMR */ + /* For more details see the hardware spec. */ + /* gumr starts as zero. */ + if (uf_info->tci) + gumr |= UCC_FAST_GUMR_TCI; + gumr |= uf_info->ttx_trx; + if (uf_info->cdp) + gumr |= UCC_FAST_GUMR_CDP; + if (uf_info->ctsp) + gumr |= UCC_FAST_GUMR_CTSP; + if (uf_info->cds) + gumr |= UCC_FAST_GUMR_CDS; + if (uf_info->ctss) + gumr |= UCC_FAST_GUMR_CTSS; + if (uf_info->txsy) + gumr |= UCC_FAST_GUMR_TXSY; + if (uf_info->rsyn) + gumr |= UCC_FAST_GUMR_RSYN; + gumr |= uf_info->synl; + if (uf_info->rtsm) + gumr |= UCC_FAST_GUMR_RTSM; + gumr |= uf_info->renc; + if (uf_info->revd) + gumr |= UCC_FAST_GUMR_REVD; + gumr |= uf_info->tenc; + gumr |= uf_info->tcrc; + gumr |= uf_info->mode; + out_be32(&uf_regs->gumr, gumr); + + /* Allocate memory for Tx Virtual Fifo */ + uccf->ucc_fast_tx_virtual_fifo_base_offset = + qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + if (IS_MURAM_ERR(uccf->ucc_fast_tx_virtual_fifo_base_offset)) { + uccf_err + ("ucc_fast_init: Can not allocate MURAM memory for " + "struct ucc_fastx_virtual_fifo_base_offset."); + uccf->ucc_fast_tx_virtual_fifo_base_offset = 0; + ucc_fast_free(uccf); + return -ENOMEM; + } + + /* Allocate memory for Rx Virtual Fifo */ + uccf->ucc_fast_rx_virtual_fifo_base_offset = + qe_muram_alloc(uf_info->urfs + + (u32) + UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR, + UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + if (IS_MURAM_ERR(uccf->ucc_fast_rx_virtual_fifo_base_offset)) { + uccf_err + ("ucc_fast_init: Can not allocate MURAM memory for " + "ucc_fast_rx_virtual_fifo_base_offset."); + uccf->ucc_fast_rx_virtual_fifo_base_offset = 0; + ucc_fast_free(uccf); + return -ENOMEM; + } + + /* Set Virtual Fifo registers */ + out_be16(&uf_regs->urfs, uf_info->urfs); + out_be16(&uf_regs->urfet, uf_info->urfet); + out_be16(&uf_regs->urfset, uf_info->urfset); + out_be16(&uf_regs->utfs, uf_info->utfs); + out_be16(&uf_regs->utfet, uf_info->utfet); + out_be16(&uf_regs->utftt, uf_info->utftt); + /* utfb, urfb are offsets from MURAM base */ + out_be32(&uf_regs->utfb, uccf->ucc_fast_tx_virtual_fifo_base_offset); + out_be32(&uf_regs->urfb, uccf->ucc_fast_rx_virtual_fifo_base_offset); + + /* Mux clocking */ + /* Grant Support */ + ucc_set_qe_mux_grant(uf_info->ucc_num, uf_info->grant_support); + /* Breakpoint Support */ + ucc_set_qe_mux_bkpt(uf_info->ucc_num, uf_info->brkpt_support); + /* Set Tsa or NMSI mode. */ + ucc_set_qe_mux_tsa(uf_info->ucc_num, uf_info->tsa); + /* If NMSI (not Tsa), set Tx and Rx clock. */ + if (!uf_info->tsa) { + /* Rx clock routing */ + if (uf_info->rx_clock != QE_CLK_NONE) { + if (ucc_set_qe_mux_rxtx + (uf_info->ucc_num, uf_info->rx_clock, + COMM_DIR_RX)) { + uccf_err + ("ucc_fast_init: Illegal value for parameter 'RxClock'."); + ucc_fast_free(uccf); + return -EINVAL; + } + } + /* Tx clock routing */ + if (uf_info->tx_clock != QE_CLK_NONE) { + if (ucc_set_qe_mux_rxtx + (uf_info->ucc_num, uf_info->tx_clock, + COMM_DIR_TX)) { + uccf_err + ("ucc_fast_init: Illegal value for parameter 'TxClock'."); + ucc_fast_free(uccf); + return -EINVAL; + } + } + } + + /* Set interrupt mask register at UCC level. */ + out_be32(&uf_regs->uccm, uf_info->uccm_mask); + + /* First, clear anything pending at UCC level, + * otherwise, old garbage may come through + * as soon as the dam is opened + * Writing '1' clears + */ + out_be32(&uf_regs->ucce, 0xffffffff); + + *uccf_ret = uccf; + return 0; +} + +void ucc_fast_free(struct ucc_fast_private * uccf) +{ + if (!uccf) + return; + + if (uccf->ucc_fast_tx_virtual_fifo_base_offset) + qe_muram_free(uccf->ucc_fast_tx_virtual_fifo_base_offset); + + if (uccf->ucc_fast_rx_virtual_fifo_base_offset) + qe_muram_free(uccf->ucc_fast_rx_virtual_fifo_base_offset); + + kfree(uccf); +} diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c new file mode 100644 index 000000000000..1fb88ef7cf06 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Authors: Shlomi Gridish + * Li Yang + * + * Description: + * QE UCC Slow API Set - UCC Slow specific routines implementations. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define uccs_printk(level, format, arg...) \ + printk(level format "\n", ## arg) + +#define uccs_dbg(format, arg...) \ + uccs_printk(KERN_DEBUG , format , ## arg) +#define uccs_err(format, arg...) \ + uccs_printk(KERN_ERR , format , ## arg) +#define uccs_info(format, arg...) \ + uccs_printk(KERN_INFO , format , ## arg) +#define uccs_warn(format, arg...) \ + uccs_printk(KERN_WARNING , format , ## arg) + +#ifdef UCCS_VERBOSE_DEBUG +#define uccs_vdbg uccs_dbg +#else +#define uccs_vdbg(fmt, args...) do { } while (0) +#endif /* UCCS_VERBOSE_DEBUG */ + +u32 ucc_slow_get_qe_cr_subblock(int uccs_num) +{ + switch (uccs_num) { + case 0: return QE_CR_SUBBLOCK_UCCSLOW1; + case 1: return QE_CR_SUBBLOCK_UCCSLOW2; + case 2: return QE_CR_SUBBLOCK_UCCSLOW3; + case 3: return QE_CR_SUBBLOCK_UCCSLOW4; + case 4: return QE_CR_SUBBLOCK_UCCSLOW5; + case 5: return QE_CR_SUBBLOCK_UCCSLOW6; + case 6: return QE_CR_SUBBLOCK_UCCSLOW7; + case 7: return QE_CR_SUBBLOCK_UCCSLOW8; + default: return QE_CR_SUBBLOCK_INVALID; + } +} + +void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs) +{ + out_be16(&uccs->us_regs->utodr, UCC_SLOW_TOD); +} + +void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs) +{ + struct ucc_slow_info *us_info = uccs->us_info; + u32 id; + + id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_TX, id, + QE_CR_PROTOCOL_UNSPECIFIED, 0); +} + +void ucc_slow_stop_tx(struct ucc_slow_private * uccs) +{ + struct ucc_slow_info *us_info = uccs->us_info; + u32 id; + + id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); + qe_issue_cmd(QE_STOP_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); +} + +void ucc_slow_restart_tx(struct ucc_slow_private * uccs) +{ + struct ucc_slow_info *us_info = uccs->us_info; + u32 id; + + id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); + qe_issue_cmd(QE_RESTART_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); +} + +void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode) +{ + struct ucc_slow *us_regs; + u32 gumr_l; + + us_regs = uccs->us_regs; + + /* Enable reception and/or transmission on this UCC. */ + gumr_l = in_be32(&us_regs->gumr_l); + if (mode & COMM_DIR_TX) { + gumr_l |= UCC_SLOW_GUMR_L_ENT; + uccs->enabled_tx = 1; + } + if (mode & COMM_DIR_RX) { + gumr_l |= UCC_SLOW_GUMR_L_ENR; + uccs->enabled_rx = 1; + } + out_be32(&us_regs->gumr_l, gumr_l); +} + +void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) +{ + struct ucc_slow *us_regs; + u32 gumr_l; + + us_regs = uccs->us_regs; + + /* Disable reception and/or transmission on this UCC. */ + gumr_l = in_be32(&us_regs->gumr_l); + if (mode & COMM_DIR_TX) { + gumr_l &= ~UCC_SLOW_GUMR_L_ENT; + uccs->enabled_tx = 0; + } + if (mode & COMM_DIR_RX) { + gumr_l &= ~UCC_SLOW_GUMR_L_ENR; + uccs->enabled_rx = 0; + } + out_be32(&us_regs->gumr_l, gumr_l); +} + +int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret) +{ + u32 i; + struct ucc_slow *us_regs; + u32 gumr; + u8 function_code = 0; + u8 *bd; + struct ucc_slow_private *uccs; + u32 id; + u32 command; + int ret; + + uccs_vdbg("%s: IN", __FUNCTION__); + + if (!us_info) + return -EINVAL; + + /* check if the UCC port number is in range. */ + if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) { + uccs_err("ucc_slow_init: Illagal UCC number!"); + return -EINVAL; + } + + /* + * Set mrblr + * Check that 'max_rx_buf_length' is properly aligned (4), unless + * rfw is 1, meaning that QE accepts one byte at a time, unlike normal + * case when QE accepts 32 bits at a time. + */ + if ((!us_info->rfw) && + (us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) { + uccs_err("max_rx_buf_length not aligned."); + return -EINVAL; + } + + uccs = (struct ucc_slow_private *) + kmalloc(sizeof(struct ucc_slow_private), GFP_KERNEL); + if (!uccs) { + uccs_err + ("ucc_slow_init: No memory for UCC slow data structure!"); + return -ENOMEM; + } + memset(uccs, 0, sizeof(struct ucc_slow_private)); + + /* Fill slow UCC structure */ + uccs->us_info = us_info; + uccs->saved_uccm = 0; + uccs->p_rx_frame = 0; + uccs->us_regs = us_info->us_regs; + us_regs = uccs->us_regs; + uccs->p_ucce = (u16 *) & (us_regs->ucce); + uccs->p_uccm = (u16 *) & (us_regs->uccm); +#ifdef STATISTICS + uccs->rx_frames = 0; + uccs->tx_frames = 0; + uccs->rx_discarded = 0; +#endif /* STATISTICS */ + + /* Get PRAM base */ + uccs->us_pram_offset = qe_muram_alloc(UCC_SLOW_PRAM_SIZE, + ALIGNMENT_OF_UCC_SLOW_PRAM); + if (IS_MURAM_ERR(uccs->us_pram_offset)) { + uccs_err + ("ucc_slow_init: Can not allocate MURAM memory " + "for Slow UCC."); + ucc_slow_free(uccs); + return -ENOMEM; + } + id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); + qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, QE_CR_PROTOCOL_UNSPECIFIED, + (u32) uccs->us_pram_offset); + + uccs->us_pram = qe_muram_addr(uccs->us_pram_offset); + + /* Init Guemr register */ + if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->us_regs)))) { + uccs_err("ucc_slow_init: Could not init the guemr register."); + ucc_slow_free(uccs); + return ret; + } + + /* Set UCC to slow type */ + if ((ret = ucc_set_type(us_info->ucc_num, + (struct ucc_common *) (us_info->us_regs), + UCC_SPEED_TYPE_SLOW))) { + uccs_err("ucc_slow_init: Could not init the guemr register."); + ucc_slow_free(uccs); + return ret; + } + + out_be16(&uccs->us_pram->mrblr, us_info->max_rx_buf_length); + + INIT_LIST_HEAD(&uccs->confQ); + + /* Allocate BDs. */ + uccs->rx_base_offset = + qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd), + QE_ALIGNMENT_OF_BD); + if (IS_MURAM_ERR(uccs->rx_base_offset)) { + uccs_err("ucc_slow_init: No memory for Rx BD's."); + uccs->rx_base_offset = 0; + ucc_slow_free(uccs); + return -ENOMEM; + } + + uccs->tx_base_offset = + qe_muram_alloc(us_info->tx_bd_ring_len * sizeof(struct qe_bd), + QE_ALIGNMENT_OF_BD); + if (IS_MURAM_ERR(uccs->tx_base_offset)) { + uccs_err("ucc_slow_init: No memory for Tx BD's."); + uccs->tx_base_offset = 0; + ucc_slow_free(uccs); + return -ENOMEM; + } + + /* Init Tx bds */ + bd = uccs->confBd = uccs->tx_bd = qe_muram_addr(uccs->tx_base_offset); + for (i = 0; i < us_info->tx_bd_ring_len; i++) { + /* clear bd buffer */ + out_be32(&(((struct qe_bd *)bd)->buf), 0); + /* set bd status and length */ + out_be32((u32*)bd, 0); + bd += sizeof(struct qe_bd); + } + bd -= sizeof(struct qe_bd); + /* set bd status and length */ + out_be32((u32*)bd, T_W); /* for last BD set Wrap bit */ + + /* Init Rx bds */ + bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset); + for (i = 0; i < us_info->rx_bd_ring_len; i++) { + /* set bd status and length */ + out_be32((u32*)bd, 0); + /* clear bd buffer */ + out_be32(&(((struct qe_bd *)bd)->buf), 0); + bd += sizeof(struct qe_bd); + } + bd -= sizeof(struct qe_bd); + /* set bd status and length */ + out_be32((u32*)bd, R_W); /* for last BD set Wrap bit */ + + /* Set GUMR (For more details see the hardware spec.). */ + /* gumr_h */ + gumr = 0; + gumr |= us_info->tcrc; + if (us_info->cdp) + gumr |= UCC_SLOW_GUMR_H_CDP; + if (us_info->ctsp) + gumr |= UCC_SLOW_GUMR_H_CTSP; + if (us_info->cds) + gumr |= UCC_SLOW_GUMR_H_CDS; + if (us_info->ctss) + gumr |= UCC_SLOW_GUMR_H_CTSS; + if (us_info->tfl) + gumr |= UCC_SLOW_GUMR_H_TFL; + if (us_info->rfw) + gumr |= UCC_SLOW_GUMR_H_RFW; + if (us_info->txsy) + gumr |= UCC_SLOW_GUMR_H_TXSY; + if (us_info->rtsm) + gumr |= UCC_SLOW_GUMR_H_RTSM; + out_be32(&us_regs->gumr_h, gumr); + + /* gumr_l */ + gumr = 0; + if (us_info->tci) + gumr |= UCC_SLOW_GUMR_L_TCI; + if (us_info->rinv) + gumr |= UCC_SLOW_GUMR_L_RINV; + if (us_info->tinv) + gumr |= UCC_SLOW_GUMR_L_TINV; + if (us_info->tend) + gumr |= UCC_SLOW_GUMR_L_TEND; + gumr |= us_info->tdcr; + gumr |= us_info->rdcr; + gumr |= us_info->tenc; + gumr |= us_info->renc; + gumr |= us_info->diag; + gumr |= us_info->mode; + out_be32(&us_regs->gumr_l, gumr); + + /* Function code registers */ + /* function_code has initial value 0 */ + + /* if the data is in cachable memory, the 'global' */ + /* in the function code should be set. */ + function_code |= us_info->data_mem_part; + function_code |= QE_BMR_BYTE_ORDER_BO_MOT; /* Required for QE */ + uccs->us_pram->tfcr = function_code; + uccs->us_pram->rfcr = function_code; + + /* rbase, tbase are offsets from MURAM base */ + out_be16(&uccs->us_pram->rbase, uccs->us_pram_offset); + out_be16(&uccs->us_pram->tbase, uccs->us_pram_offset); + + /* Mux clocking */ + /* Grant Support */ + ucc_set_qe_mux_grant(us_info->ucc_num, us_info->grant_support); + /* Breakpoint Support */ + ucc_set_qe_mux_bkpt(us_info->ucc_num, us_info->brkpt_support); + /* Set Tsa or NMSI mode. */ + ucc_set_qe_mux_tsa(us_info->ucc_num, us_info->tsa); + /* If NMSI (not Tsa), set Tx and Rx clock. */ + if (!us_info->tsa) { + /* Rx clock routing */ + if (ucc_set_qe_mux_rxtx + (us_info->ucc_num, us_info->rx_clock, COMM_DIR_RX)) { + uccs_err + ("ucc_slow_init: Illegal value for parameter" + " 'RxClock'."); + ucc_slow_free(uccs); + return -EINVAL; + } + /* Tx clock routing */ + if (ucc_set_qe_mux_rxtx(us_info->ucc_num, + us_info->tx_clock, COMM_DIR_TX)) { + uccs_err + ("ucc_slow_init: Illegal value for parameter " + "'TxClock'."); + ucc_slow_free(uccs); + return -EINVAL; + } + } + + /* + * INTERRUPTS + */ + /* Set interrupt mask register at UCC level. */ + out_be16(&us_regs->uccm, us_info->uccm_mask); + + /* First, clear anything pending at UCC level, */ + /* otherwise, old garbage may come through */ + /* as soon as the dam is opened. */ + + /* Writing '1' clears */ + out_be16(&us_regs->ucce, 0xffff); + + /* Issue QE Init command */ + if (us_info->init_tx && us_info->init_rx) + command = QE_INIT_TX_RX; + else if (us_info->init_tx) + command = QE_INIT_TX; + else + command = QE_INIT_RX; /* We know at least one is TRUE */ + id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); + qe_issue_cmd(command, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); + + *uccs_ret = uccs; + return 0; +} + +void ucc_slow_free(struct ucc_slow_private * uccs) +{ + if (!uccs) + return; + + if (uccs->rx_base_offset) + qe_muram_free(uccs->rx_base_offset); + + if (uccs->tx_base_offset) + qe_muram_free(uccs->tx_base_offset); + + if (uccs->us_pram) { + qe_muram_free(uccs->us_pram_offset); + uccs->us_pram = NULL; + } + + kfree(uccs); +} diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h new file mode 100644 index 000000000000..ce12f85fff9b --- /dev/null +++ b/include/asm-powerpc/immap_qe.h @@ -0,0 +1,477 @@ +/* + * include/asm-powerpc/immap_qe.h + * + * QUICC Engine (QE) Internal Memory Map. + * The Internal Memory Map for devices with QE on them. This + * is the superset of all QE devices (8360, etc.). + + * Copyright (C) 2006. Freescale Semicondutor, Inc. All rights reserved. + * + * Authors: Shlomi Gridish + * Li Yang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef _ASM_POWERPC_IMMAP_QE_H +#define _ASM_POWERPC_IMMAP_QE_H +#ifdef __KERNEL__ + +#include + +#define QE_IMMAP_SIZE (1024 * 1024) /* 1MB from 1MB+IMMR */ + +/* QE I-RAM */ +struct qe_iram { + __be32 iadd; /* I-RAM Address Register */ + __be32 idata; /* I-RAM Data Register */ + u8 res0[0x78]; +} __attribute__ ((packed)); + +/* QE Interrupt Controller */ +struct qe_ic_regs { + __be32 qicr; + __be32 qivec; + __be32 qripnr; + __be32 qipnr; + __be32 qipxcc; + __be32 qipycc; + __be32 qipwcc; + __be32 qipzcc; + __be32 qimr; + __be32 qrimr; + __be32 qicnr; + u8 res0[0x4]; + __be32 qiprta; + __be32 qiprtb; + u8 res1[0x4]; + __be32 qricr; + u8 res2[0x20]; + __be32 qhivec; + u8 res3[0x1C]; +} __attribute__ ((packed)); + +/* Communications Processor */ +struct cp_qe { + __be32 cecr; /* QE command register */ + __be32 ceccr; /* QE controller configuration register */ + __be32 cecdr; /* QE command data register */ + u8 res0[0xA]; + __be16 ceter; /* QE timer event register */ + u8 res1[0x2]; + __be16 cetmr; /* QE timers mask register */ + __be32 cetscr; /* QE time-stamp timer control register */ + __be32 cetsr1; /* QE time-stamp register 1 */ + __be32 cetsr2; /* QE time-stamp register 2 */ + u8 res2[0x8]; + __be32 cevter; /* QE virtual tasks event register */ + __be32 cevtmr; /* QE virtual tasks mask register */ + __be16 cercr; /* QE RAM control register */ + u8 res3[0x2]; + u8 res4[0x24]; + __be16 ceexe1; /* QE external request 1 event register */ + u8 res5[0x2]; + __be16 ceexm1; /* QE external request 1 mask register */ + u8 res6[0x2]; + __be16 ceexe2; /* QE external request 2 event register */ + u8 res7[0x2]; + __be16 ceexm2; /* QE external request 2 mask register */ + u8 res8[0x2]; + __be16 ceexe3; /* QE external request 3 event register */ + u8 res9[0x2]; + __be16 ceexm3; /* QE external request 3 mask register */ + u8 res10[0x2]; + __be16 ceexe4; /* QE external request 4 event register */ + u8 res11[0x2]; + __be16 ceexm4; /* QE external request 4 mask register */ + u8 res12[0x2]; + u8 res13[0x280]; +} __attribute__ ((packed)); + +/* QE Multiplexer */ +struct qe_mux { + __be32 cmxgcr; /* CMX general clock route register */ + __be32 cmxsi1cr_l; /* CMX SI1 clock route low register */ + __be32 cmxsi1cr_h; /* CMX SI1 clock route high register */ + __be32 cmxsi1syr; /* CMX SI1 SYNC route register */ + __be32 cmxucr1; /* CMX UCC1, UCC3 clock route register */ + __be32 cmxucr2; /* CMX UCC5, UCC7 clock route register */ + __be32 cmxucr3; /* CMX UCC2, UCC4 clock route register */ + __be32 cmxucr4; /* CMX UCC6, UCC8 clock route register */ + __be32 cmxupcr; /* CMX UPC clock route register */ + u8 res0[0x1C]; +} __attribute__ ((packed)); + +/* QE Timers */ +struct qe_timers { + u8 gtcfr1; /* Timer 1 and Timer 2 global config register*/ + u8 res0[0x3]; + u8 gtcfr2; /* Timer 3 and timer 4 global config register*/ + u8 res1[0xB]; + __be16 gtmdr1; /* Timer 1 mode register */ + __be16 gtmdr2; /* Timer 2 mode register */ + __be16 gtrfr1; /* Timer 1 reference register */ + __be16 gtrfr2; /* Timer 2 reference register */ + __be16 gtcpr1; /* Timer 1 capture register */ + __be16 gtcpr2; /* Timer 2 capture register */ + __be16 gtcnr1; /* Timer 1 counter */ + __be16 gtcnr2; /* Timer 2 counter */ + __be16 gtmdr3; /* Timer 3 mode register */ + __be16 gtmdr4; /* Timer 4 mode register */ + __be16 gtrfr3; /* Timer 3 reference register */ + __be16 gtrfr4; /* Timer 4 reference register */ + __be16 gtcpr3; /* Timer 3 capture register */ + __be16 gtcpr4; /* Timer 4 capture register */ + __be16 gtcnr3; /* Timer 3 counter */ + __be16 gtcnr4; /* Timer 4 counter */ + __be16 gtevr1; /* Timer 1 event register */ + __be16 gtevr2; /* Timer 2 event register */ + __be16 gtevr3; /* Timer 3 event register */ + __be16 gtevr4; /* Timer 4 event register */ + __be16 gtps; /* Timer 1 prescale register */ + u8 res2[0x46]; +} __attribute__ ((packed)); + +/* BRG */ +struct qe_brg { + __be32 brgc1; /* BRG1 configuration register */ + __be32 brgc2; /* BRG2 configuration register */ + __be32 brgc3; /* BRG3 configuration register */ + __be32 brgc4; /* BRG4 configuration register */ + __be32 brgc5; /* BRG5 configuration register */ + __be32 brgc6; /* BRG6 configuration register */ + __be32 brgc7; /* BRG7 configuration register */ + __be32 brgc8; /* BRG8 configuration register */ + __be32 brgc9; /* BRG9 configuration register */ + __be32 brgc10; /* BRG10 configuration register */ + __be32 brgc11; /* BRG11 configuration register */ + __be32 brgc12; /* BRG12 configuration register */ + __be32 brgc13; /* BRG13 configuration register */ + __be32 brgc14; /* BRG14 configuration register */ + __be32 brgc15; /* BRG15 configuration register */ + __be32 brgc16; /* BRG16 configuration register */ + u8 res0[0x40]; +} __attribute__ ((packed)); + +/* SPI */ +struct spi { + u8 res0[0x20]; + __be32 spmode; /* SPI mode register */ + u8 res1[0x2]; + u8 spie; /* SPI event register */ + u8 res2[0x1]; + u8 res3[0x2]; + u8 spim; /* SPI mask register */ + u8 res4[0x1]; + u8 res5[0x1]; + u8 spcom; /* SPI command register */ + u8 res6[0x2]; + __be32 spitd; /* SPI transmit data register (cpu mode) */ + __be32 spird; /* SPI receive data register (cpu mode) */ + u8 res7[0x8]; +} __attribute__ ((packed)); + +/* SI */ +struct si1 { + __be16 siamr1; /* SI1 TDMA mode register */ + __be16 sibmr1; /* SI1 TDMB mode register */ + __be16 sicmr1; /* SI1 TDMC mode register */ + __be16 sidmr1; /* SI1 TDMD mode register */ + u8 siglmr1_h; /* SI1 global mode register high */ + u8 res0[0x1]; + u8 sicmdr1_h; /* SI1 command register high */ + u8 res2[0x1]; + u8 sistr1_h; /* SI1 status register high */ + u8 res3[0x1]; + __be16 sirsr1_h; /* SI1 RAM shadow address register high */ + u8 sitarc1; /* SI1 RAM counter Tx TDMA */ + u8 sitbrc1; /* SI1 RAM counter Tx TDMB */ + u8 sitcrc1; /* SI1 RAM counter Tx TDMC */ + u8 sitdrc1; /* SI1 RAM counter Tx TDMD */ + u8 sirarc1; /* SI1 RAM counter Rx TDMA */ + u8 sirbrc1; /* SI1 RAM counter Rx TDMB */ + u8 sircrc1; /* SI1 RAM counter Rx TDMC */ + u8 sirdrc1; /* SI1 RAM counter Rx TDMD */ + u8 res4[0x8]; + __be16 siemr1; /* SI1 TDME mode register 16 bits */ + __be16 sifmr1; /* SI1 TDMF mode register 16 bits */ + __be16 sigmr1; /* SI1 TDMG mode register 16 bits */ + __be16 sihmr1; /* SI1 TDMH mode register 16 bits */ + u8 siglmg1_l; /* SI1 global mode register low 8 bits */ + u8 res5[0x1]; + u8 sicmdr1_l; /* SI1 command register low 8 bits */ + u8 res6[0x1]; + u8 sistr1_l; /* SI1 status register low 8 bits */ + u8 res7[0x1]; + __be16 sirsr1_l; /* SI1 RAM shadow address register low 16 bits*/ + u8 siterc1; /* SI1 RAM counter Tx TDME 8 bits */ + u8 sitfrc1; /* SI1 RAM counter Tx TDMF 8 bits */ + u8 sitgrc1; /* SI1 RAM counter Tx TDMG 8 bits */ + u8 sithrc1; /* SI1 RAM counter Tx TDMH 8 bits */ + u8 sirerc1; /* SI1 RAM counter Rx TDME 8 bits */ + u8 sirfrc1; /* SI1 RAM counter Rx TDMF 8 bits */ + u8 sirgrc1; /* SI1 RAM counter Rx TDMG 8 bits */ + u8 sirhrc1; /* SI1 RAM counter Rx TDMH 8 bits */ + u8 res8[0x8]; + __be32 siml1; /* SI1 multiframe limit register */ + u8 siedm1; /* SI1 extended diagnostic mode register */ + u8 res9[0xBB]; +} __attribute__ ((packed)); + +/* SI Routing Tables */ +struct sir { + u8 tx[0x400]; + u8 rx[0x400]; + u8 res0[0x800]; +} __attribute__ ((packed)); + +/* USB Controller */ +struct usb_ctlr { + u8 usb_usmod; + u8 usb_usadr; + u8 usb_uscom; + u8 res1[1]; + __be16 usb_usep1; + __be16 usb_usep2; + __be16 usb_usep3; + __be16 usb_usep4; + u8 res2[4]; + __be16 usb_usber; + u8 res3[2]; + __be16 usb_usbmr; + u8 res4[1]; + u8 usb_usbs; + __be16 usb_ussft; + u8 res5[2]; + __be16 usb_usfrn; + u8 res6[0x22]; +} __attribute__ ((packed)); + +/* MCC */ +struct mcc { + __be32 mcce; /* MCC event register */ + __be32 mccm; /* MCC mask register */ + __be32 mccf; /* MCC configuration register */ + __be32 merl; /* MCC emergency request level register */ + u8 res0[0xF0]; +} __attribute__ ((packed)); + +/* QE UCC Slow */ +struct ucc_slow { + __be32 gumr_l; /* UCCx general mode register (low) */ + __be32 gumr_h; /* UCCx general mode register (high) */ + __be16 upsmr; /* UCCx protocol-specific mode register */ + u8 res0[0x2]; + __be16 utodr; /* UCCx transmit on demand register */ + __be16 udsr; /* UCCx data synchronization register */ + __be16 ucce; /* UCCx event register */ + u8 res1[0x2]; + __be16 uccm; /* UCCx mask register */ + u8 res2[0x1]; + u8 uccs; /* UCCx status register */ + u8 res3[0x24]; + __be16 utpt; + u8 guemr; /* UCC general extended mode register */ + u8 res4[0x200 - 0x091]; +} __attribute__ ((packed)); + +/* QE UCC Fast */ +struct ucc_fast { + __be32 gumr; /* UCCx general mode register */ + __be32 upsmr; /* UCCx protocol-specific mode register */ + __be16 utodr; /* UCCx transmit on demand register */ + u8 res0[0x2]; + __be16 udsr; /* UCCx data synchronization register */ + u8 res1[0x2]; + __be32 ucce; /* UCCx event register */ + __be32 uccm; /* UCCx mask register */ + u8 uccs; /* UCCx status register */ + u8 res2[0x7]; + __be32 urfb; /* UCC receive FIFO base */ + __be16 urfs; /* UCC receive FIFO size */ + u8 res3[0x2]; + __be16 urfet; /* UCC receive FIFO emergency threshold */ + __be16 urfset; /* UCC receive FIFO special emergency + threshold */ + __be32 utfb; /* UCC transmit FIFO base */ + __be16 utfs; /* UCC transmit FIFO size */ + u8 res4[0x2]; + __be16 utfet; /* UCC transmit FIFO emergency threshold */ + u8 res5[0x2]; + __be16 utftt; /* UCC transmit FIFO transmit threshold */ + u8 res6[0x2]; + __be16 utpt; /* UCC transmit polling timer */ + u8 res7[0x2]; + __be32 urtry; /* UCC retry counter register */ + u8 res8[0x4C]; + u8 guemr; /* UCC general extended mode register */ + u8 res9[0x100 - 0x091]; +} __attribute__ ((packed)); + +/* QE UCC */ +struct ucc_common { + u8 res1[0x90]; + u8 guemr; + u8 res2[0x200 - 0x091]; +} __attribute__ ((packed)); + +struct ucc { + union { + struct ucc_slow slow; + struct ucc_fast fast; + struct ucc_common common; + }; +} __attribute__ ((packed)); + +/* MultiPHY UTOPIA POS Controllers (UPC) */ +struct upc { + __be32 upgcr; /* UTOPIA/POS general configuration register */ + __be32 uplpa; /* UTOPIA/POS last PHY address */ + __be32 uphec; /* ATM HEC register */ + __be32 upuc; /* UTOPIA/POS UCC configuration */ + __be32 updc1; /* UTOPIA/POS device 1 configuration */ + __be32 updc2; /* UTOPIA/POS device 2 configuration */ + __be32 updc3; /* UTOPIA/POS device 3 configuration */ + __be32 updc4; /* UTOPIA/POS device 4 configuration */ + __be32 upstpa; /* UTOPIA/POS STPA threshold */ + u8 res0[0xC]; + __be32 updrs1_h; /* UTOPIA/POS device 1 rate select */ + __be32 updrs1_l; /* UTOPIA/POS device 1 rate select */ + __be32 updrs2_h; /* UTOPIA/POS device 2 rate select */ + __be32 updrs2_l; /* UTOPIA/POS device 2 rate select */ + __be32 updrs3_h; /* UTOPIA/POS device 3 rate select */ + __be32 updrs3_l; /* UTOPIA/POS device 3 rate select */ + __be32 updrs4_h; /* UTOPIA/POS device 4 rate select */ + __be32 updrs4_l; /* UTOPIA/POS device 4 rate select */ + __be32 updrp1; /* UTOPIA/POS device 1 receive priority low */ + __be32 updrp2; /* UTOPIA/POS device 2 receive priority low */ + __be32 updrp3; /* UTOPIA/POS device 3 receive priority low */ + __be32 updrp4; /* UTOPIA/POS device 4 receive priority low */ + __be32 upde1; /* UTOPIA/POS device 1 event */ + __be32 upde2; /* UTOPIA/POS device 2 event */ + __be32 upde3; /* UTOPIA/POS device 3 event */ + __be32 upde4; /* UTOPIA/POS device 4 event */ + __be16 uprp1; + __be16 uprp2; + __be16 uprp3; + __be16 uprp4; + u8 res1[0x8]; + __be16 uptirr1_0; /* Device 1 transmit internal rate 0 */ + __be16 uptirr1_1; /* Device 1 transmit internal rate 1 */ + __be16 uptirr1_2; /* Device 1 transmit internal rate 2 */ + __be16 uptirr1_3; /* Device 1 transmit internal rate 3 */ + __be16 uptirr2_0; /* Device 2 transmit internal rate 0 */ + __be16 uptirr2_1; /* Device 2 transmit internal rate 1 */ + __be16 uptirr2_2; /* Device 2 transmit internal rate 2 */ + __be16 uptirr2_3; /* Device 2 transmit internal rate 3 */ + __be16 uptirr3_0; /* Device 3 transmit internal rate 0 */ + __be16 uptirr3_1; /* Device 3 transmit internal rate 1 */ + __be16 uptirr3_2; /* Device 3 transmit internal rate 2 */ + __be16 uptirr3_3; /* Device 3 transmit internal rate 3 */ + __be16 uptirr4_0; /* Device 4 transmit internal rate 0 */ + __be16 uptirr4_1; /* Device 4 transmit internal rate 1 */ + __be16 uptirr4_2; /* Device 4 transmit internal rate 2 */ + __be16 uptirr4_3; /* Device 4 transmit internal rate 3 */ + __be32 uper1; /* Device 1 port enable register */ + __be32 uper2; /* Device 2 port enable register */ + __be32 uper3; /* Device 3 port enable register */ + __be32 uper4; /* Device 4 port enable register */ + u8 res2[0x150]; +} __attribute__ ((packed)); + +/* SDMA */ +struct sdma { + __be32 sdsr; /* Serial DMA status register */ + __be32 sdmr; /* Serial DMA mode register */ + __be32 sdtr1; /* SDMA system bus threshold register */ + __be32 sdtr2; /* SDMA secondary bus threshold register */ + __be32 sdhy1; /* SDMA system bus hysteresis register */ + __be32 sdhy2; /* SDMA secondary bus hysteresis register */ + __be32 sdta1; /* SDMA system bus address register */ + __be32 sdta2; /* SDMA secondary bus address register */ + __be32 sdtm1; /* SDMA system bus MSNUM register */ + __be32 sdtm2; /* SDMA secondary bus MSNUM register */ + u8 res0[0x10]; + __be32 sdaqr; /* SDMA address bus qualify register */ + __be32 sdaqmr; /* SDMA address bus qualify mask register */ + u8 res1[0x4]; + __be32 sdebcr; /* SDMA CAM entries base register */ + u8 res2[0x38]; +} __attribute__ ((packed)); + +/* Debug Space */ +struct dbg { + __be32 bpdcr; /* Breakpoint debug command register */ + __be32 bpdsr; /* Breakpoint debug status register */ + __be32 bpdmr; /* Breakpoint debug mask register */ + __be32 bprmrr0; /* Breakpoint request mode risc register 0 */ + __be32 bprmrr1; /* Breakpoint request mode risc register 1 */ + u8 res0[0x8]; + __be32 bprmtr0; /* Breakpoint request mode trb register 0 */ + __be32 bprmtr1; /* Breakpoint request mode trb register 1 */ + u8 res1[0x8]; + __be32 bprmir; /* Breakpoint request mode immediate register */ + __be32 bprmsr; /* Breakpoint request mode serial register */ + __be32 bpemr; /* Breakpoint exit mode register */ + u8 res2[0x48]; +} __attribute__ ((packed)); + +/* RISC Special Registers (Trap and Breakpoint) */ +struct rsp { + u8 fixme[0x100]; +} __attribute__ ((packed)); + +struct qe_immap { + struct qe_iram iram; /* I-RAM */ + struct qe_ic_regs ic; /* Interrupt Controller */ + struct cp_qe cp; /* Communications Processor */ + struct qe_mux qmx; /* QE Multiplexer */ + struct qe_timers qet; /* QE Timers */ + struct spi spi[0x2]; /* spi */ + struct mcc mcc; /* mcc */ + struct qe_brg brg; /* brg */ + struct usb_ctlr usb; /* USB */ + struct si1 si1; /* SI */ + u8 res11[0x800]; + struct sir sir; /* SI Routing Tables */ + struct ucc ucc1; /* ucc1 */ + struct ucc ucc3; /* ucc3 */ + struct ucc ucc5; /* ucc5 */ + struct ucc ucc7; /* ucc7 */ + u8 res12[0x600]; + struct upc upc1; /* MultiPHY UTOPIA POS Ctrlr 1*/ + struct ucc ucc2; /* ucc2 */ + struct ucc ucc4; /* ucc4 */ + struct ucc ucc6; /* ucc6 */ + struct ucc ucc8; /* ucc8 */ + u8 res13[0x600]; + struct upc upc2; /* MultiPHY UTOPIA POS Ctrlr 2*/ + struct sdma sdma; /* SDMA */ + struct dbg dbg; /* Debug Space */ + struct rsp rsp[0x2]; /* RISC Special Registers + (Trap and Breakpoint) */ + u8 res14[0x300]; + u8 res15[0x3A00]; + u8 res16[0x8000]; /* 0x108000 - 0x110000 */ + u8 muram[0xC000]; /* 0x110000 - 0x11C000 + Multi-user RAM */ + u8 res17[0x24000]; /* 0x11C000 - 0x140000 */ + u8 res18[0xC0000]; /* 0x140000 - 0x200000 */ +} __attribute__ ((packed)); + +extern struct qe_immap *qe_immr; +extern phys_addr_t get_qe_base(void); + +static inline unsigned long immrbar_virt_to_phys(volatile void * address) +{ + if ( ((u32)address >= (u32)qe_immr) && + ((u32)address < ((u32)qe_immr + QE_IMMAP_SIZE)) ) + return (unsigned long)(address - (u32)qe_immr + + (u32)get_qe_base()); + return (unsigned long)virt_to_phys(address); +} + +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_IMMAP_QE_H */ diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h new file mode 100644 index 000000000000..a62168ec535f --- /dev/null +++ b/include/asm-powerpc/qe.h @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Authors: Shlomi Gridish + * Li Yang + * + * Description: + * QUICC Engine (QE) external definitions and structure. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef _ASM_POWERPC_QE_H +#define _ASM_POWERPC_QE_H +#ifdef __KERNEL__ + +#include + +#define QE_NUM_OF_SNUM 28 +#define QE_NUM_OF_BRGS 16 +#define QE_NUM_OF_PORTS 1024 + +/* Memory partitions +*/ +#define MEM_PART_SYSTEM 0 +#define MEM_PART_SECONDARY 1 +#define MEM_PART_MURAM 2 + +/* Export QE common operations */ +extern void qe_reset(void); +extern int par_io_init(struct device_node *np); +extern int par_io_of_config(struct device_node *np); + +/* QE internal API */ +int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input); +void qe_setbrg(u32 brg, u32 rate); +int qe_get_snum(void); +void qe_put_snum(u8 snum); +u32 qe_muram_alloc(u32 size, u32 align); +int qe_muram_free(u32 offset); +u32 qe_muram_alloc_fixed(u32 offset, u32 size); +void qe_muram_dump(void); +void *qe_muram_addr(u32 offset); + +/* Buffer descriptors */ +struct qe_bd { + u16 status; + u16 length; + u32 buf; +} __attribute__ ((packed)); + +#define BD_STATUS_MASK 0xffff0000 +#define BD_LENGTH_MASK 0x0000ffff + +/* Alignment */ +#define QE_INTR_TABLE_ALIGN 16 /* ??? */ +#define QE_ALIGNMENT_OF_BD 8 +#define QE_ALIGNMENT_OF_PRAM 64 + +/* RISC allocation */ +enum qe_risc_allocation { + QE_RISC_ALLOCATION_RISC1 = 1, /* RISC 1 */ + QE_RISC_ALLOCATION_RISC2 = 2, /* RISC 2 */ + QE_RISC_ALLOCATION_RISC1_AND_RISC2 = 3 /* Dynamically choose + RISC 1 or RISC 2 */ +}; + +/* QE extended filtering Table Lookup Key Size */ +enum qe_fltr_tbl_lookup_key_size { + QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES + = 0x3f, /* LookupKey parsed by the Generate LookupKey + CMD is truncated to 8 bytes */ + QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES + = 0x5f, /* LookupKey parsed by the Generate LookupKey + CMD is truncated to 16 bytes */ +}; + +/* QE FLTR extended filtering Largest External Table Lookup Key Size */ +enum qe_fltr_largest_external_tbl_lookup_key_size { + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE + = 0x0,/* not used */ + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES + = QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES, /* 8 bytes */ + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES + = QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES, /* 16 bytes */ +}; + +/* structure representing QE parameter RAM */ +struct qe_timer_tables { + u16 tm_base; /* QE timer table base adr */ + u16 tm_ptr; /* QE timer table pointer */ + u16 r_tmr; /* QE timer mode register */ + u16 r_tmv; /* QE timer valid register */ + u32 tm_cmd; /* QE timer cmd register */ + u32 tm_cnt; /* QE timer internal cnt */ +} __attribute__ ((packed)); + +#define QE_FLTR_TAD_SIZE 8 + +/* QE extended filtering Termination Action Descriptor (TAD) */ +struct qe_fltr_tad { + u8 serialized[QE_FLTR_TAD_SIZE]; +} __attribute__ ((packed)); + +/* Communication Direction */ +enum comm_dir { + COMM_DIR_NONE = 0, + COMM_DIR_RX = 1, + COMM_DIR_TX = 2, + COMM_DIR_RX_AND_TX = 3 +}; + +/* Clocks and BRGs */ +enum qe_clock { + QE_CLK_NONE = 0, + QE_BRG1, /* Baud Rate Generator 1 */ + QE_BRG2, /* Baud Rate Generator 2 */ + QE_BRG3, /* Baud Rate Generator 3 */ + QE_BRG4, /* Baud Rate Generator 4 */ + QE_BRG5, /* Baud Rate Generator 5 */ + QE_BRG6, /* Baud Rate Generator 6 */ + QE_BRG7, /* Baud Rate Generator 7 */ + QE_BRG8, /* Baud Rate Generator 8 */ + QE_BRG9, /* Baud Rate Generator 9 */ + QE_BRG10, /* Baud Rate Generator 10 */ + QE_BRG11, /* Baud Rate Generator 11 */ + QE_BRG12, /* Baud Rate Generator 12 */ + QE_BRG13, /* Baud Rate Generator 13 */ + QE_BRG14, /* Baud Rate Generator 14 */ + QE_BRG15, /* Baud Rate Generator 15 */ + QE_BRG16, /* Baud Rate Generator 16 */ + QE_CLK1, /* Clock 1 */ + QE_CLK2, /* Clock 2 */ + QE_CLK3, /* Clock 3 */ + QE_CLK4, /* Clock 4 */ + QE_CLK5, /* Clock 5 */ + QE_CLK6, /* Clock 6 */ + QE_CLK7, /* Clock 7 */ + QE_CLK8, /* Clock 8 */ + QE_CLK9, /* Clock 9 */ + QE_CLK10, /* Clock 10 */ + QE_CLK11, /* Clock 11 */ + QE_CLK12, /* Clock 12 */ + QE_CLK13, /* Clock 13 */ + QE_CLK14, /* Clock 14 */ + QE_CLK15, /* Clock 15 */ + QE_CLK16, /* Clock 16 */ + QE_CLK17, /* Clock 17 */ + QE_CLK18, /* Clock 18 */ + QE_CLK19, /* Clock 19 */ + QE_CLK20, /* Clock 20 */ + QE_CLK21, /* Clock 21 */ + QE_CLK22, /* Clock 22 */ + QE_CLK23, /* Clock 23 */ + QE_CLK24, /* Clock 24 */ + QE_CLK_DUMMY, +}; + +/* QE CMXUCR Registers. + * There are two UCCs represented in each of the four CMXUCR registers. + * These values are for the UCC in the LSBs + */ +#define QE_CMXUCR_MII_ENET_MNG 0x00007000 +#define QE_CMXUCR_MII_ENET_MNG_SHIFT 12 +#define QE_CMXUCR_GRANT 0x00008000 +#define QE_CMXUCR_TSA 0x00004000 +#define QE_CMXUCR_BKPT 0x00000100 +#define QE_CMXUCR_TX_CLK_SRC_MASK 0x0000000F + +/* QE CMXGCR Registers. +*/ +#define QE_CMXGCR_MII_ENET_MNG 0x00007000 +#define QE_CMXGCR_MII_ENET_MNG_SHIFT 12 +#define QE_CMXGCR_USBCS 0x0000000f + +/* QE CECR Commands. +*/ +#define QE_CR_FLG 0x00010000 +#define QE_RESET 0x80000000 +#define QE_INIT_TX_RX 0x00000000 +#define QE_INIT_RX 0x00000001 +#define QE_INIT_TX 0x00000002 +#define QE_ENTER_HUNT_MODE 0x00000003 +#define QE_STOP_TX 0x00000004 +#define QE_GRACEFUL_STOP_TX 0x00000005 +#define QE_RESTART_TX 0x00000006 +#define QE_CLOSE_RX_BD 0x00000007 +#define QE_SWITCH_COMMAND 0x00000007 +#define QE_SET_GROUP_ADDRESS 0x00000008 +#define QE_START_IDMA 0x00000009 +#define QE_MCC_STOP_RX 0x00000009 +#define QE_ATM_TRANSMIT 0x0000000a +#define QE_HPAC_CLEAR_ALL 0x0000000b +#define QE_GRACEFUL_STOP_RX 0x0000001a +#define QE_RESTART_RX 0x0000001b +#define QE_HPAC_SET_PRIORITY 0x0000010b +#define QE_HPAC_STOP_TX 0x0000020b +#define QE_HPAC_STOP_RX 0x0000030b +#define QE_HPAC_GRACEFUL_STOP_TX 0x0000040b +#define QE_HPAC_GRACEFUL_STOP_RX 0x0000050b +#define QE_HPAC_START_TX 0x0000060b +#define QE_HPAC_START_RX 0x0000070b +#define QE_USB_STOP_TX 0x0000000a +#define QE_USB_RESTART_TX 0x0000000b +#define QE_QMC_STOP_TX 0x0000000c +#define QE_QMC_STOP_RX 0x0000000d +#define QE_SS7_SU_FIL_RESET 0x0000000e +/* jonathbr added from here down for 83xx */ +#define QE_RESET_BCS 0x0000000a +#define QE_MCC_INIT_TX_RX_16 0x00000003 +#define QE_MCC_STOP_TX 0x00000004 +#define QE_MCC_INIT_TX_1 0x00000005 +#define QE_MCC_INIT_RX_1 0x00000006 +#define QE_MCC_RESET 0x00000007 +#define QE_SET_TIMER 0x00000008 +#define QE_RANDOM_NUMBER 0x0000000c +#define QE_ATM_MULTI_THREAD_INIT 0x00000011 +#define QE_ASSIGN_PAGE 0x00000012 +#define QE_ADD_REMOVE_HASH_ENTRY 0x00000013 +#define QE_START_FLOW_CONTROL 0x00000014 +#define QE_STOP_FLOW_CONTROL 0x00000015 +#define QE_ASSIGN_PAGE_TO_DEVICE 0x00000016 + +#define QE_ASSIGN_RISC 0x00000010 +#define QE_CR_MCN_NORMAL_SHIFT 6 +#define QE_CR_MCN_USB_SHIFT 4 +#define QE_CR_MCN_RISC_ASSIGN_SHIFT 8 +#define QE_CR_SNUM_SHIFT 17 + +/* QE CECR Sub Block - sub block of QE command. +*/ +#define QE_CR_SUBBLOCK_INVALID 0x00000000 +#define QE_CR_SUBBLOCK_USB 0x03200000 +#define QE_CR_SUBBLOCK_UCCFAST1 0x02000000 +#define QE_CR_SUBBLOCK_UCCFAST2 0x02200000 +#define QE_CR_SUBBLOCK_UCCFAST3 0x02400000 +#define QE_CR_SUBBLOCK_UCCFAST4 0x02600000 +#define QE_CR_SUBBLOCK_UCCFAST5 0x02800000 +#define QE_CR_SUBBLOCK_UCCFAST6 0x02a00000 +#define QE_CR_SUBBLOCK_UCCFAST7 0x02c00000 +#define QE_CR_SUBBLOCK_UCCFAST8 0x02e00000 +#define QE_CR_SUBBLOCK_UCCSLOW1 0x00000000 +#define QE_CR_SUBBLOCK_UCCSLOW2 0x00200000 +#define QE_CR_SUBBLOCK_UCCSLOW3 0x00400000 +#define QE_CR_SUBBLOCK_UCCSLOW4 0x00600000 +#define QE_CR_SUBBLOCK_UCCSLOW5 0x00800000 +#define QE_CR_SUBBLOCK_UCCSLOW6 0x00a00000 +#define QE_CR_SUBBLOCK_UCCSLOW7 0x00c00000 +#define QE_CR_SUBBLOCK_UCCSLOW8 0x00e00000 +#define QE_CR_SUBBLOCK_MCC1 0x03800000 +#define QE_CR_SUBBLOCK_MCC2 0x03a00000 +#define QE_CR_SUBBLOCK_MCC3 0x03000000 +#define QE_CR_SUBBLOCK_IDMA1 0x02800000 +#define QE_CR_SUBBLOCK_IDMA2 0x02a00000 +#define QE_CR_SUBBLOCK_IDMA3 0x02c00000 +#define QE_CR_SUBBLOCK_IDMA4 0x02e00000 +#define QE_CR_SUBBLOCK_HPAC 0x01e00000 +#define QE_CR_SUBBLOCK_SPI1 0x01400000 +#define QE_CR_SUBBLOCK_SPI2 0x01600000 +#define QE_CR_SUBBLOCK_RAND 0x01c00000 +#define QE_CR_SUBBLOCK_TIMER 0x01e00000 +#define QE_CR_SUBBLOCK_GENERAL 0x03c00000 + +/* QE CECR Protocol - For non-MCC, specifies mode for QE CECR command */ +#define QE_CR_PROTOCOL_UNSPECIFIED 0x00 /* For all other protocols */ +#define QE_CR_PROTOCOL_HDLC_TRANSPARENT 0x00 +#define QE_CR_PROTOCOL_ATM_POS 0x0A +#define QE_CR_PROTOCOL_ETHERNET 0x0C +#define QE_CR_PROTOCOL_L2_SWITCH 0x0D + +/* BMR byte order */ +#define QE_BMR_BYTE_ORDER_BO_PPC 0x08 /* powerpc little endian */ +#define QE_BMR_BYTE_ORDER_BO_MOT 0x10 /* motorola big endian */ +#define QE_BMR_BYTE_ORDER_BO_MAX 0x18 + +/* BRG configuration register */ +#define QE_BRGC_ENABLE 0x00010000 +#define QE_BRGC_DIVISOR_SHIFT 1 +#define QE_BRGC_DIVISOR_MAX 0xFFF +#define QE_BRGC_DIV16 1 + +/* QE Timers registers */ +#define QE_GTCFR1_PCAS 0x80 +#define QE_GTCFR1_STP2 0x20 +#define QE_GTCFR1_RST2 0x10 +#define QE_GTCFR1_GM2 0x08 +#define QE_GTCFR1_GM1 0x04 +#define QE_GTCFR1_STP1 0x02 +#define QE_GTCFR1_RST1 0x01 + +/* SDMA registers */ +#define QE_SDSR_BER1 0x02000000 +#define QE_SDSR_BER2 0x01000000 + +#define QE_SDMR_GLB_1_MSK 0x80000000 +#define QE_SDMR_ADR_SEL 0x20000000 +#define QE_SDMR_BER1_MSK 0x02000000 +#define QE_SDMR_BER2_MSK 0x01000000 +#define QE_SDMR_EB1_MSK 0x00800000 +#define QE_SDMR_ER1_MSK 0x00080000 +#define QE_SDMR_ER2_MSK 0x00040000 +#define QE_SDMR_CEN_MASK 0x0000E000 +#define QE_SDMR_SBER_1 0x00000200 +#define QE_SDMR_SBER_2 0x00000200 +#define QE_SDMR_EB1_PR_MASK 0x000000C0 +#define QE_SDMR_ER1_PR 0x00000008 + +#define QE_SDMR_CEN_SHIFT 13 +#define QE_SDMR_EB1_PR_SHIFT 6 + +#define QE_SDTM_MSNUM_SHIFT 24 + +#define QE_SDEBCR_BA_MASK 0x01FFFFFF + +/* UPC */ +#define UPGCR_PROTOCOL 0x80000000 /* protocol ul2 or pl2 */ +#define UPGCR_TMS 0x40000000 /* Transmit master/slave mode */ +#define UPGCR_RMS 0x20000000 /* Receive master/slave mode */ +#define UPGCR_ADDR 0x10000000 /* Master MPHY Addr multiplexing */ +#define UPGCR_DIAG 0x01000000 /* Diagnostic mode */ + +/* UCC */ +#define UCC_GUEMR_MODE_MASK_RX 0x02 +#define UCC_GUEMR_MODE_MASK_TX 0x01 +#define UCC_GUEMR_MODE_FAST_RX 0x02 +#define UCC_GUEMR_MODE_FAST_TX 0x01 +#define UCC_GUEMR_MODE_SLOW_RX 0x00 +#define UCC_GUEMR_MODE_SLOW_TX 0x00 +#define UCC_GUEMR_SET_RESERVED3 0x10 /* Bit 3 in the guemr is reserved but + must be set 1 */ + +/* structure representing UCC SLOW parameter RAM */ +struct ucc_slow_pram { + u16 rbase; /* RX BD base address */ + u16 tbase; /* TX BD base address */ + u8 rfcr; /* Rx function code */ + u8 tfcr; /* Tx function code */ + u16 mrblr; /* Rx buffer length */ + u32 rstate; /* Rx internal state */ + u32 rptr; /* Rx internal data pointer */ + u16 rbptr; /* rb BD Pointer */ + u16 rcount; /* Rx internal byte count */ + u32 rtemp; /* Rx temp */ + u32 tstate; /* Tx internal state */ + u32 tptr; /* Tx internal data pointer */ + u16 tbptr; /* Tx BD pointer */ + u16 tcount; /* Tx byte count */ + u32 ttemp; /* Tx temp */ + u32 rcrc; /* temp receive CRC */ + u32 tcrc; /* temp transmit CRC */ +} __attribute__ ((packed)); + +/* General UCC SLOW Mode Register (GUMRH & GUMRL) */ +#define UCC_SLOW_GUMR_H_CRC16 0x00004000 +#define UCC_SLOW_GUMR_H_CRC16CCITT 0x00000000 +#define UCC_SLOW_GUMR_H_CRC32CCITT 0x00008000 +#define UCC_SLOW_GUMR_H_REVD 0x00002000 +#define UCC_SLOW_GUMR_H_TRX 0x00001000 +#define UCC_SLOW_GUMR_H_TTX 0x00000800 +#define UCC_SLOW_GUMR_H_CDP 0x00000400 +#define UCC_SLOW_GUMR_H_CTSP 0x00000200 +#define UCC_SLOW_GUMR_H_CDS 0x00000100 +#define UCC_SLOW_GUMR_H_CTSS 0x00000080 +#define UCC_SLOW_GUMR_H_TFL 0x00000040 +#define UCC_SLOW_GUMR_H_RFW 0x00000020 +#define UCC_SLOW_GUMR_H_TXSY 0x00000010 +#define UCC_SLOW_GUMR_H_4SYNC 0x00000004 +#define UCC_SLOW_GUMR_H_8SYNC 0x00000008 +#define UCC_SLOW_GUMR_H_16SYNC 0x0000000c +#define UCC_SLOW_GUMR_H_RTSM 0x00000002 +#define UCC_SLOW_GUMR_H_RSYN 0x00000001 + +#define UCC_SLOW_GUMR_L_TCI 0x10000000 +#define UCC_SLOW_GUMR_L_RINV 0x02000000 +#define UCC_SLOW_GUMR_L_TINV 0x01000000 +#define UCC_SLOW_GUMR_L_TEND 0x00020000 +#define UCC_SLOW_GUMR_L_ENR 0x00000020 +#define UCC_SLOW_GUMR_L_ENT 0x00000010 + +/* General UCC FAST Mode Register */ +#define UCC_FAST_GUMR_TCI 0x20000000 +#define UCC_FAST_GUMR_TRX 0x10000000 +#define UCC_FAST_GUMR_TTX 0x08000000 +#define UCC_FAST_GUMR_CDP 0x04000000 +#define UCC_FAST_GUMR_CTSP 0x02000000 +#define UCC_FAST_GUMR_CDS 0x01000000 +#define UCC_FAST_GUMR_CTSS 0x00800000 +#define UCC_FAST_GUMR_TXSY 0x00020000 +#define UCC_FAST_GUMR_RSYN 0x00010000 +#define UCC_FAST_GUMR_RTSM 0x00002000 +#define UCC_FAST_GUMR_REVD 0x00000400 +#define UCC_FAST_GUMR_ENR 0x00000020 +#define UCC_FAST_GUMR_ENT 0x00000010 + +/* Slow UCC Event Register (UCCE) */ +#define UCC_SLOW_UCCE_GLR 0x1000 +#define UCC_SLOW_UCCE_GLT 0x0800 +#define UCC_SLOW_UCCE_DCC 0x0400 +#define UCC_SLOW_UCCE_FLG 0x0200 +#define UCC_SLOW_UCCE_AB 0x0200 +#define UCC_SLOW_UCCE_IDLE 0x0100 +#define UCC_SLOW_UCCE_GRA 0x0080 +#define UCC_SLOW_UCCE_TXE 0x0010 +#define UCC_SLOW_UCCE_RXF 0x0008 +#define UCC_SLOW_UCCE_CCR 0x0008 +#define UCC_SLOW_UCCE_RCH 0x0008 +#define UCC_SLOW_UCCE_BSY 0x0004 +#define UCC_SLOW_UCCE_TXB 0x0002 +#define UCC_SLOW_UCCE_TX 0x0002 +#define UCC_SLOW_UCCE_RX 0x0001 +#define UCC_SLOW_UCCE_GOV 0x0001 +#define UCC_SLOW_UCCE_GUN 0x0002 +#define UCC_SLOW_UCCE_GINT 0x0004 +#define UCC_SLOW_UCCE_IQOV 0x0008 + +#define UCC_SLOW_UCCE_HDLC_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ + UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF | \ + UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR) +#define UCC_SLOW_UCCE_ENET_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ + UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF) +#define UCC_SLOW_UCCE_TRANS_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ + UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \ + UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR) +#define UCC_SLOW_UCCE_UART_SET (UCC_SLOW_UCCE_BSY | UCC_SLOW_UCCE_GRA | \ + UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \ + UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR) +#define UCC_SLOW_UCCE_QMC_SET (UCC_SLOW_UCCE_IQOV | UCC_SLOW_UCCE_GINT | \ + UCC_SLOW_UCCE_GUN | UCC_SLOW_UCCE_GOV) + +#define UCC_SLOW_UCCE_OTHER (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ + UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | \ + UCC_SLOW_UCCE_GLR) + +#define UCC_SLOW_INTR_TX UCC_SLOW_UCCE_TXB +#define UCC_SLOW_INTR_RX (UCC_SLOW_UCCE_RXF | UCC_SLOW_UCCE_RX) +#define UCC_SLOW_INTR (UCC_SLOW_INTR_TX | UCC_SLOW_INTR_RX) + +/* UCC Transmit On Demand Register (UTODR) */ +#define UCC_SLOW_TOD 0x8000 +#define UCC_FAST_TOD 0x8000 + +/* Function code masks */ +#define FC_GBL 0x20 +#define FC_DTB_LCL 0x02 +#define UCC_FAST_FUNCTION_CODE_GBL 0x20 +#define UCC_FAST_FUNCTION_CODE_DTB_LCL 0x02 +#define UCC_FAST_FUNCTION_CODE_BDB_LCL 0x01 + +static inline long IS_MURAM_ERR(const u32 offset) +{ + return offset > (u32) - 1000L; +} + +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_QE_H */ diff --git a/include/asm-powerpc/qe_ic.h b/include/asm-powerpc/qe_ic.h new file mode 100644 index 000000000000..e386fb7e44b0 --- /dev/null +++ b/include/asm-powerpc/qe_ic.h @@ -0,0 +1,64 @@ +/* + * include/asm-powerpc/qe_ic.h + * + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Authors: Shlomi Gridish + * Li Yang + * + * Description: + * QE IC external definitions and structure. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef _ASM_POWERPC_QE_IC_H +#define _ASM_POWERPC_QE_IC_H + +#include + +#define NUM_OF_QE_IC_GROUPS 6 + +/* Flags when we init the QE IC */ +#define QE_IC_SPREADMODE_GRP_W 0x00000001 +#define QE_IC_SPREADMODE_GRP_X 0x00000002 +#define QE_IC_SPREADMODE_GRP_Y 0x00000004 +#define QE_IC_SPREADMODE_GRP_Z 0x00000008 +#define QE_IC_SPREADMODE_GRP_RISCA 0x00000010 +#define QE_IC_SPREADMODE_GRP_RISCB 0x00000020 + +#define QE_IC_LOW_SIGNAL 0x00000100 +#define QE_IC_HIGH_SIGNAL 0x00000200 + +#define QE_IC_GRP_W_PRI0_DEST_SIGNAL_HIGH 0x00001000 +#define QE_IC_GRP_W_PRI1_DEST_SIGNAL_HIGH 0x00002000 +#define QE_IC_GRP_X_PRI0_DEST_SIGNAL_HIGH 0x00004000 +#define QE_IC_GRP_X_PRI1_DEST_SIGNAL_HIGH 0x00008000 +#define QE_IC_GRP_Y_PRI0_DEST_SIGNAL_HIGH 0x00010000 +#define QE_IC_GRP_Y_PRI1_DEST_SIGNAL_HIGH 0x00020000 +#define QE_IC_GRP_Z_PRI0_DEST_SIGNAL_HIGH 0x00040000 +#define QE_IC_GRP_Z_PRI1_DEST_SIGNAL_HIGH 0x00080000 +#define QE_IC_GRP_RISCA_PRI0_DEST_SIGNAL_HIGH 0x00100000 +#define QE_IC_GRP_RISCA_PRI1_DEST_SIGNAL_HIGH 0x00200000 +#define QE_IC_GRP_RISCB_PRI0_DEST_SIGNAL_HIGH 0x00400000 +#define QE_IC_GRP_RISCB_PRI1_DEST_SIGNAL_HIGH 0x00800000 +#define QE_IC_GRP_W_DEST_SIGNAL_SHIFT (12) + +/* QE interrupt sources groups */ +enum qe_ic_grp_id { + QE_IC_GRP_W = 0, /* QE interrupt controller group W */ + QE_IC_GRP_X, /* QE interrupt controller group X */ + QE_IC_GRP_Y, /* QE interrupt controller group Y */ + QE_IC_GRP_Z, /* QE interrupt controller group Z */ + QE_IC_GRP_RISCA, /* QE interrupt controller RISC group A */ + QE_IC_GRP_RISCB /* QE interrupt controller RISC group B */ +}; + +void qe_ic_init(struct device_node *node, unsigned int flags); +void qe_ic_set_highest_priority(unsigned int virq, int high); +int qe_ic_set_priority(unsigned int virq, unsigned int priority); +int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high); + +#endif /* _ASM_POWERPC_QE_IC_H */ diff --git a/include/asm-powerpc/ucc.h b/include/asm-powerpc/ucc.h new file mode 100644 index 000000000000..afe3076bdc03 --- /dev/null +++ b/include/asm-powerpc/ucc.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Authors: Shlomi Gridish + * Li Yang + * + * Description: + * Internal header file for UCC unit routines. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __UCC_H__ +#define __UCC_H__ + +#include +#include + +#define STATISTICS + +#define UCC_MAX_NUM 8 + +/* Slow or fast type for UCCs. +*/ +enum ucc_speed_type { + UCC_SPEED_TYPE_FAST, UCC_SPEED_TYPE_SLOW +}; + +/* Initial UCCs Parameter RAM address relative to: MEM_MAP_BASE (IMMR). +*/ +enum ucc_pram_initial_offset { + UCC_PRAM_OFFSET_UCC1 = 0x8400, + UCC_PRAM_OFFSET_UCC2 = 0x8500, + UCC_PRAM_OFFSET_UCC3 = 0x8600, + UCC_PRAM_OFFSET_UCC4 = 0x9000, + UCC_PRAM_OFFSET_UCC5 = 0x8000, + UCC_PRAM_OFFSET_UCC6 = 0x8100, + UCC_PRAM_OFFSET_UCC7 = 0x8200, + UCC_PRAM_OFFSET_UCC8 = 0x8300 +}; + +/* ucc_set_type + * Sets UCC to slow or fast mode. + * + * ucc_num - (In) number of UCC (0-7). + * regs - (In) pointer to registers base for the UCC. + * speed - (In) slow or fast mode for UCC. + */ +int ucc_set_type(int ucc_num, struct ucc_common *regs, + enum ucc_speed_type speed); + +/* ucc_init_guemr + * Init the Guemr register. + * + * regs - (In) pointer to registers base for the UCC. + */ +int ucc_init_guemr(struct ucc_common *regs); + +int ucc_set_qe_mux_mii_mng(int ucc_num); + +int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode); + +int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask); + +/* QE MUX clock routing for UCC +*/ +static inline int ucc_set_qe_mux_grant(int ucc_num, int set) +{ + return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_GRANT); +} + +static inline int ucc_set_qe_mux_tsa(int ucc_num, int set) +{ + return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_TSA); +} + +static inline int ucc_set_qe_mux_bkpt(int ucc_num, int set) +{ + return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_BKPT); +} + +#endif /* __UCC_H__ */ diff --git a/include/asm-powerpc/ucc_fast.h b/include/asm-powerpc/ucc_fast.h new file mode 100644 index 000000000000..39d1c90fd2ca --- /dev/null +++ b/include/asm-powerpc/ucc_fast.h @@ -0,0 +1,243 @@ +/* + * include/asm-powerpc/ucc_fast.h + * + * Internal header file for UCC FAST unit routines. + * + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Authors: Shlomi Gridish + * Li Yang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __UCC_FAST_H__ +#define __UCC_FAST_H__ + +#include + +#include +#include + +#include "ucc.h" + +/* Receive BD's status */ +#define R_E 0x80000000 /* buffer empty */ +#define R_W 0x20000000 /* wrap bit */ +#define R_I 0x10000000 /* interrupt on reception */ +#define R_L 0x08000000 /* last */ +#define R_F 0x04000000 /* first */ + +/* transmit BD's status */ +#define T_R 0x80000000 /* ready bit */ +#define T_W 0x20000000 /* wrap bit */ +#define T_I 0x10000000 /* interrupt on completion */ +#define T_L 0x08000000 /* last */ + +/* Rx Data buffer must be 4 bytes aligned in most cases */ +#define UCC_FAST_RX_ALIGN 4 +#define UCC_FAST_MRBLR_ALIGNMENT 4 +#define UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT 8 + +/* Sizes */ +#define UCC_FAST_URFS_MIN_VAL 0x88 +#define UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR 8 + +/* ucc_fast_channel_protocol_mode - UCC FAST mode */ +enum ucc_fast_channel_protocol_mode { + UCC_FAST_PROTOCOL_MODE_HDLC = 0x00000000, + UCC_FAST_PROTOCOL_MODE_RESERVED01 = 0x00000001, + UCC_FAST_PROTOCOL_MODE_RESERVED_QMC = 0x00000002, + UCC_FAST_PROTOCOL_MODE_RESERVED02 = 0x00000003, + UCC_FAST_PROTOCOL_MODE_RESERVED_UART = 0x00000004, + UCC_FAST_PROTOCOL_MODE_RESERVED03 = 0x00000005, + UCC_FAST_PROTOCOL_MODE_RESERVED_EX_MAC_1 = 0x00000006, + UCC_FAST_PROTOCOL_MODE_RESERVED_EX_MAC_2 = 0x00000007, + UCC_FAST_PROTOCOL_MODE_RESERVED_BISYNC = 0x00000008, + UCC_FAST_PROTOCOL_MODE_RESERVED04 = 0x00000009, + UCC_FAST_PROTOCOL_MODE_ATM = 0x0000000A, + UCC_FAST_PROTOCOL_MODE_RESERVED05 = 0x0000000B, + UCC_FAST_PROTOCOL_MODE_ETHERNET = 0x0000000C, + UCC_FAST_PROTOCOL_MODE_RESERVED06 = 0x0000000D, + UCC_FAST_PROTOCOL_MODE_POS = 0x0000000E, + UCC_FAST_PROTOCOL_MODE_RESERVED07 = 0x0000000F +}; + +/* ucc_fast_transparent_txrx - UCC Fast Transparent TX & RX */ +enum ucc_fast_transparent_txrx { + UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL = 0x00000000, + UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_TRANSPARENT = 0x18000000 +}; + +/* UCC fast diagnostic mode */ +enum ucc_fast_diag_mode { + UCC_FAST_DIAGNOSTIC_NORMAL = 0x0, + UCC_FAST_DIAGNOSTIC_LOCAL_LOOP_BACK = 0x40000000, + UCC_FAST_DIAGNOSTIC_AUTO_ECHO = 0x80000000, + UCC_FAST_DIAGNOSTIC_LOOP_BACK_AND_ECHO = 0xC0000000 +}; + +/* UCC fast Sync length (transparent mode only) */ +enum ucc_fast_sync_len { + UCC_FAST_SYNC_LEN_NOT_USED = 0x0, + UCC_FAST_SYNC_LEN_AUTOMATIC = 0x00004000, + UCC_FAST_SYNC_LEN_8_BIT = 0x00008000, + UCC_FAST_SYNC_LEN_16_BIT = 0x0000C000 +}; + +/* UCC fast RTS mode */ +enum ucc_fast_ready_to_send { + UCC_FAST_SEND_IDLES_BETWEEN_FRAMES = 0x00000000, + UCC_FAST_SEND_FLAGS_BETWEEN_FRAMES = 0x00002000 +}; + +/* UCC fast receiver decoding mode */ +enum ucc_fast_rx_decoding_method { + UCC_FAST_RX_ENCODING_NRZ = 0x00000000, + UCC_FAST_RX_ENCODING_NRZI = 0x00000800, + UCC_FAST_RX_ENCODING_RESERVED0 = 0x00001000, + UCC_FAST_RX_ENCODING_RESERVED1 = 0x00001800 +}; + +/* UCC fast transmitter encoding mode */ +enum ucc_fast_tx_encoding_method { + UCC_FAST_TX_ENCODING_NRZ = 0x00000000, + UCC_FAST_TX_ENCODING_NRZI = 0x00000100, + UCC_FAST_TX_ENCODING_RESERVED0 = 0x00000200, + UCC_FAST_TX_ENCODING_RESERVED1 = 0x00000300 +}; + +/* UCC fast CRC length */ +enum ucc_fast_transparent_tcrc { + UCC_FAST_16_BIT_CRC = 0x00000000, + UCC_FAST_CRC_RESERVED0 = 0x00000040, + UCC_FAST_32_BIT_CRC = 0x00000080, + UCC_FAST_CRC_RESERVED1 = 0x000000C0 +}; + +/* Fast UCC initialization structure */ +struct ucc_fast_info { + int ucc_num; + enum qe_clock rx_clock; + enum qe_clock tx_clock; + u32 regs; + int irq; + u32 uccm_mask; + int bd_mem_part; + int brkpt_support; + int grant_support; + int tsa; + int cdp; + int cds; + int ctsp; + int ctss; + int tci; + int txsy; + int rtsm; + int revd; + int rsyn; + u16 max_rx_buf_length; + u16 urfs; + u16 urfet; + u16 urfset; + u16 utfs; + u16 utfet; + u16 utftt; + u16 ufpt; + enum ucc_fast_channel_protocol_mode mode; + enum ucc_fast_transparent_txrx ttx_trx; + enum ucc_fast_tx_encoding_method tenc; + enum ucc_fast_rx_decoding_method renc; + enum ucc_fast_transparent_tcrc tcrc; + enum ucc_fast_sync_len synl; +}; + +struct ucc_fast_private { + struct ucc_fast_info *uf_info; + struct ucc_fast *uf_regs; /* a pointer to memory map of UCC regs. */ + u32 *p_ucce; /* a pointer to the event register in memory. */ + u32 *p_uccm; /* a pointer to the mask register in memory. */ + int enabled_tx; /* Whether channel is enabled for Tx (ENT) */ + int enabled_rx; /* Whether channel is enabled for Rx (ENR) */ + int stopped_tx; /* Whether channel has been stopped for Tx + (STOP_TX, etc.) */ + int stopped_rx; /* Whether channel has been stopped for Rx */ + u32 ucc_fast_tx_virtual_fifo_base_offset;/* pointer to base of Tx + virtual fifo */ + u32 ucc_fast_rx_virtual_fifo_base_offset;/* pointer to base of Rx + virtual fifo */ +#ifdef STATISTICS + u32 tx_frames; /* Transmitted frames counter. */ + u32 rx_frames; /* Received frames counter (only frames + passed to application). */ + u32 tx_discarded; /* Discarded tx frames counter (frames that + were discarded by the driver due to errors). + */ + u32 rx_discarded; /* Discarded rx frames counter (frames that + were discarded by the driver due to errors). + */ +#endif /* STATISTICS */ + u16 mrblr; /* maximum receive buffer length */ +}; + +/* ucc_fast_init + * Initializes Fast UCC according to user provided parameters. + * + * uf_info - (In) pointer to the fast UCC info structure. + * uccf_ret - (Out) pointer to the fast UCC structure. + */ +int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret); + +/* ucc_fast_free + * Frees all resources for fast UCC. + * + * uccf - (In) pointer to the fast UCC structure. + */ +void ucc_fast_free(struct ucc_fast_private * uccf); + +/* ucc_fast_enable + * Enables a fast UCC port. + * This routine enables Tx and/or Rx through the General UCC Mode Register. + * + * uccf - (In) pointer to the fast UCC structure. + * mode - (In) TX, RX, or both. + */ +void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode); + +/* ucc_fast_disable + * Disables a fast UCC port. + * This routine disables Tx and/or Rx through the General UCC Mode Register. + * + * uccf - (In) pointer to the fast UCC structure. + * mode - (In) TX, RX, or both. + */ +void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode); + +/* ucc_fast_irq + * Handles interrupts on fast UCC. + * Called from the general interrupt routine to handle interrupts on fast UCC. + * + * uccf - (In) pointer to the fast UCC structure. + */ +void ucc_fast_irq(struct ucc_fast_private * uccf); + +/* ucc_fast_transmit_on_demand + * Immediately forces a poll of the transmitter for data to be sent. + * Typically, the hardware performs a periodic poll for data that the + * transmit routine has set up to be transmitted. In cases where + * this polling cycle is not soon enough, this optional routine can + * be invoked to force a poll right away, instead. Proper use for + * each transmission for which this functionality is desired is to + * call the transmit routine and then this routine right after. + * + * uccf - (In) pointer to the fast UCC structure. + */ +void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf); + +u32 ucc_fast_get_qe_cr_subblock(int uccf_num); + +void ucc_fast_dump_regs(struct ucc_fast_private * uccf); + +#endif /* __UCC_FAST_H__ */ diff --git a/include/asm-powerpc/ucc_slow.h b/include/asm-powerpc/ucc_slow.h new file mode 100644 index 000000000000..ca93bc99237e --- /dev/null +++ b/include/asm-powerpc/ucc_slow.h @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * + * Authors: Shlomi Gridish + * Li Yang + * + * Description: + * Internal header file for UCC SLOW unit routines. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __UCC_SLOW_H__ +#define __UCC_SLOW_H__ + +#include + +#include +#include + +#include "ucc.h" + +/* transmit BD's status */ +#define T_R 0x80000000 /* ready bit */ +#define T_PAD 0x40000000 /* add pads to short frames */ +#define T_W 0x20000000 /* wrap bit */ +#define T_I 0x10000000 /* interrupt on completion */ +#define T_L 0x08000000 /* last */ + +#define T_A 0x04000000 /* Address - the data transmitted as address + chars */ +#define T_TC 0x04000000 /* transmit CRC */ +#define T_CM 0x02000000 /* continuous mode */ +#define T_DEF 0x02000000 /* collision on previous attempt to transmit */ +#define T_P 0x01000000 /* Preamble - send Preamble sequence before + data */ +#define T_HB 0x01000000 /* heartbeat */ +#define T_NS 0x00800000 /* No Stop */ +#define T_LC 0x00800000 /* late collision */ +#define T_RL 0x00400000 /* retransmission limit */ +#define T_UN 0x00020000 /* underrun */ +#define T_CT 0x00010000 /* CTS lost */ +#define T_CSL 0x00010000 /* carrier sense lost */ +#define T_RC 0x003c0000 /* retry count */ + +/* Receive BD's status */ +#define R_E 0x80000000 /* buffer empty */ +#define R_W 0x20000000 /* wrap bit */ +#define R_I 0x10000000 /* interrupt on reception */ +#define R_L 0x08000000 /* last */ +#define R_C 0x08000000 /* the last byte in this buffer is a cntl + char */ +#define R_F 0x04000000 /* first */ +#define R_A 0x04000000 /* the first byte in this buffer is address + byte */ +#define R_CM 0x02000000 /* continuous mode */ +#define R_ID 0x01000000 /* buffer close on reception of idles */ +#define R_M 0x01000000 /* Frame received because of promiscuous + mode */ +#define R_AM 0x00800000 /* Address match */ +#define R_DE 0x00800000 /* Address match */ +#define R_LG 0x00200000 /* Break received */ +#define R_BR 0x00200000 /* Frame length violation */ +#define R_NO 0x00100000 /* Rx Non Octet Aligned Packet */ +#define R_FR 0x00100000 /* Framing Error (no stop bit) character + received */ +#define R_PR 0x00080000 /* Parity Error character received */ +#define R_AB 0x00080000 /* Frame Aborted */ +#define R_SH 0x00080000 /* frame is too short */ +#define R_CR 0x00040000 /* CRC Error */ +#define R_OV 0x00020000 /* Overrun */ +#define R_CD 0x00010000 /* CD lost */ +#define R_CL 0x00010000 /* this frame is closed because of a + collision */ + +/* Rx Data buffer must be 4 bytes aligned in most cases.*/ +#define UCC_SLOW_RX_ALIGN 4 +#define UCC_SLOW_MRBLR_ALIGNMENT 4 +#define UCC_SLOW_PRAM_SIZE 0x100 +#define ALIGNMENT_OF_UCC_SLOW_PRAM 64 + +/* UCC Slow Channel Protocol Mode */ +enum ucc_slow_channel_protocol_mode { + UCC_SLOW_CHANNEL_PROTOCOL_MODE_QMC = 0x00000002, + UCC_SLOW_CHANNEL_PROTOCOL_MODE_UART = 0x00000004, + UCC_SLOW_CHANNEL_PROTOCOL_MODE_BISYNC = 0x00000008, +}; + +/* UCC Slow Transparent Transmit CRC (TCRC) */ +enum ucc_slow_transparent_tcrc { + /* 16-bit CCITT CRC (HDLC). (X16 + X12 + X5 + 1) */ + UCC_SLOW_TRANSPARENT_TCRC_CCITT_CRC16 = 0x00000000, + /* CRC16 (BISYNC). (X16 + X15 + X2 + 1) */ + UCC_SLOW_TRANSPARENT_TCRC_CRC16 = 0x00004000, + /* 32-bit CCITT CRC (Ethernet and HDLC) */ + UCC_SLOW_TRANSPARENT_TCRC_CCITT_CRC32 = 0x00008000, +}; + +/* UCC Slow oversampling rate for transmitter (TDCR) */ +enum ucc_slow_tx_oversampling_rate { + /* 1x clock mode */ + UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_1 = 0x00000000, + /* 8x clock mode */ + UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_8 = 0x00010000, + /* 16x clock mode */ + UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_16 = 0x00020000, + /* 32x clock mode */ + UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_32 = 0x00030000, +}; + +/* UCC Slow Oversampling rate for receiver (RDCR) +*/ +enum ucc_slow_rx_oversampling_rate { + /* 1x clock mode */ + UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_1 = 0x00000000, + /* 8x clock mode */ + UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_8 = 0x00004000, + /* 16x clock mode */ + UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_16 = 0x00008000, + /* 32x clock mode */ + UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_32 = 0x0000c000, +}; + +/* UCC Slow Transmitter encoding method (TENC) +*/ +enum ucc_slow_tx_encoding_method { + UCC_SLOW_TRANSMITTER_ENCODING_METHOD_TENC_NRZ = 0x00000000, + UCC_SLOW_TRANSMITTER_ENCODING_METHOD_TENC_NRZI = 0x00000100 +}; + +/* UCC Slow Receiver decoding method (RENC) +*/ +enum ucc_slow_rx_decoding_method { + UCC_SLOW_RECEIVER_DECODING_METHOD_RENC_NRZ = 0x00000000, + UCC_SLOW_RECEIVER_DECODING_METHOD_RENC_NRZI = 0x00000800 +}; + +/* UCC Slow Diagnostic mode (DIAG) +*/ +enum ucc_slow_diag_mode { + UCC_SLOW_DIAG_MODE_NORMAL = 0x00000000, + UCC_SLOW_DIAG_MODE_LOOPBACK = 0x00000040, + UCC_SLOW_DIAG_MODE_ECHO = 0x00000080, + UCC_SLOW_DIAG_MODE_LOOPBACK_ECHO = 0x000000c0 +}; + +struct ucc_slow_info { + int ucc_num; + enum qe_clock rx_clock; + enum qe_clock tx_clock; + struct ucc_slow *us_regs; + int irq; + u16 uccm_mask; + int data_mem_part; + int init_tx; + int init_rx; + u32 tx_bd_ring_len; + u32 rx_bd_ring_len; + int rx_interrupts; + int brkpt_support; + int grant_support; + int tsa; + int cdp; + int cds; + int ctsp; + int ctss; + int rinv; + int tinv; + int rtsm; + int rfw; + int tci; + int tend; + int tfl; + int txsy; + u16 max_rx_buf_length; + enum ucc_slow_transparent_tcrc tcrc; + enum ucc_slow_channel_protocol_mode mode; + enum ucc_slow_diag_mode diag; + enum ucc_slow_tx_oversampling_rate tdcr; + enum ucc_slow_rx_oversampling_rate rdcr; + enum ucc_slow_tx_encoding_method tenc; + enum ucc_slow_rx_decoding_method renc; +}; + +struct ucc_slow_private { + struct ucc_slow_info *us_info; + struct ucc_slow *us_regs; /* a pointer to memory map of UCC regs */ + struct ucc_slow_pram *us_pram; /* a pointer to the parameter RAM */ + u32 us_pram_offset; + int enabled_tx; /* Whether channel is enabled for Tx (ENT) */ + int enabled_rx; /* Whether channel is enabled for Rx (ENR) */ + int stopped_tx; /* Whether channel has been stopped for Tx + (STOP_TX, etc.) */ + int stopped_rx; /* Whether channel has been stopped for Rx */ + struct list_head confQ; /* frames passed to chip waiting for tx */ + u32 first_tx_bd_mask; /* mask is used in Tx routine to save status + and length for first BD in a frame */ + u32 tx_base_offset; /* first BD in Tx BD table offset (In MURAM) */ + u32 rx_base_offset; /* first BD in Rx BD table offset (In MURAM) */ + u8 *confBd; /* next BD for confirm after Tx */ + u8 *tx_bd; /* next BD for new Tx request */ + u8 *rx_bd; /* next BD to collect after Rx */ + void *p_rx_frame; /* accumulating receive frame */ + u16 *p_ucce; /* a pointer to the event register in memory. + */ + u16 *p_uccm; /* a pointer to the mask register in memory */ + u16 saved_uccm; /* a saved mask for the RX Interrupt bits */ +#ifdef STATISTICS + u32 tx_frames; /* Transmitted frames counters */ + u32 rx_frames; /* Received frames counters (only frames + passed to application) */ + u32 rx_discarded; /* Discarded frames counters (frames that + were discarded by the driver due to + errors) */ +#endif /* STATISTICS */ +}; + +/* ucc_slow_init + * Initializes Slow UCC according to provided parameters. + * + * us_info - (In) pointer to the slow UCC info structure. + * uccs_ret - (Out) pointer to the slow UCC structure. + */ +int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret); + +/* ucc_slow_free + * Frees all resources for slow UCC. + * + * uccs - (In) pointer to the slow UCC structure. + */ +void ucc_slow_free(struct ucc_slow_private * uccs); + +/* ucc_slow_enable + * Enables a fast UCC port. + * This routine enables Tx and/or Rx through the General UCC Mode Register. + * + * uccs - (In) pointer to the slow UCC structure. + * mode - (In) TX, RX, or both. + */ +void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode); + +/* ucc_slow_disable + * Disables a fast UCC port. + * This routine disables Tx and/or Rx through the General UCC Mode Register. + * + * uccs - (In) pointer to the slow UCC structure. + * mode - (In) TX, RX, or both. + */ +void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode); + +/* ucc_slow_poll_transmitter_now + * Immediately forces a poll of the transmitter for data to be sent. + * Typically, the hardware performs a periodic poll for data that the + * transmit routine has set up to be transmitted. In cases where + * this polling cycle is not soon enough, this optional routine can + * be invoked to force a poll right away, instead. Proper use for + * each transmission for which this functionality is desired is to + * call the transmit routine and then this routine right after. + * + * uccs - (In) pointer to the slow UCC structure. + */ +void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs); + +/* ucc_slow_graceful_stop_tx + * Smoothly stops transmission on a specified slow UCC. + * + * uccs - (In) pointer to the slow UCC structure. + */ +void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs); + +/* ucc_slow_stop_tx + * Stops transmission on a specified slow UCC. + * + * uccs - (In) pointer to the slow UCC structure. + */ +void ucc_slow_stop_tx(struct ucc_slow_private * uccs); + +/* ucc_slow_restart_x + * Restarts transmitting on a specified slow UCC. + * + * uccs - (In) pointer to the slow UCC structure. + */ +void ucc_slow_restart_x(struct ucc_slow_private * uccs); + +u32 ucc_slow_get_qe_cr_subblock(int uccs_num); + +#endif /* __UCC_SLOW_H__ */ diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 16fbe59edeb1..3da29e2d524a 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -46,18 +46,17 @@ struct gianfar_platform_data { /* device specific information */ - u32 device_flags; - + u32 device_flags; /* board specific information */ - u32 board_flags; - u32 bus_id; - u32 phy_id; - u8 mac_addr[6]; + u32 board_flags; + u32 bus_id; + u32 phy_id; + u8 mac_addr[6]; }; struct gianfar_mdio_data { /* board specific information */ - int irq[32]; + int irq[32]; }; /* Flags related to gianfar device features */ @@ -76,14 +75,13 @@ struct gianfar_mdio_data { struct fsl_i2c_platform_data { /* device specific information */ - u32 device_flags; + u32 device_flags; }; /* Flags related to I2C device features */ #define FSL_I2C_DEV_SEPARATE_DFSRR 0x00000001 #define FSL_I2C_DEV_CLOCK_5200 0x00000002 - enum fsl_usb2_operating_modes { FSL_USB2_MPH_HOST, FSL_USB2_DR_HOST, @@ -101,9 +99,9 @@ enum fsl_usb2_phy_modes { struct fsl_usb2_platform_data { /* board specific information */ - enum fsl_usb2_operating_modes operating_mode; - enum fsl_usb2_phy_modes phy_mode; - unsigned int port_enables; + enum fsl_usb2_operating_modes operating_mode; + enum fsl_usb2_phy_modes phy_mode; + unsigned int port_enables; }; /* Flags in fsl_usb2_mph_platform_data */ @@ -121,5 +119,44 @@ struct fsl_spi_platform_data { u32 sysclk; }; -#endif /* _FSL_DEVICE_H_ */ -#endif /* __KERNEL__ */ +/* Ethernet interface (phy management and speed) +*/ +enum enet_interface { + ENET_10_MII, /* 10 Base T, MII interface */ + ENET_10_RMII, /* 10 Base T, RMII interface */ + ENET_10_RGMII, /* 10 Base T, RGMII interface */ + ENET_100_MII, /* 100 Base T, MII interface */ + ENET_100_RMII, /* 100 Base T, RMII interface */ + ENET_100_RGMII, /* 100 Base T, RGMII interface */ + ENET_1000_GMII, /* 1000 Base T, GMII interface */ + ENET_1000_RGMII, /* 1000 Base T, RGMII interface */ + ENET_1000_TBI, /* 1000 Base T, TBI interface */ + ENET_1000_RTBI /* 1000 Base T, RTBI interface */ +}; + +struct ucc_geth_platform_data { + /* device specific information */ + u32 device_flags; + u32 phy_reg_addr; + + /* board specific information */ + u32 board_flags; + u8 rx_clock; + u8 tx_clock; + u32 phy_id; + enum enet_interface phy_interface; + u32 phy_interrupt; + u8 mac_addr[6]; +}; + +/* Flags related to UCC Gigabit Ethernet device features */ +#define FSL_UGETH_DEV_HAS_GIGABIT 0x00000001 +#define FSL_UGETH_DEV_HAS_COALESCE 0x00000002 +#define FSL_UGETH_DEV_HAS_RMON 0x00000004 + +/* Flags in ucc_geth_platform_data */ +#define FSL_UGETH_BRD_HAS_PHY_INTR 0x00000001 + /* if not set use a timer */ + +#endif /* _FSL_DEVICE_H_ */ +#endif /* __KERNEL__ */ -- cgit v1.2.3 From b4c4ed175ff0ee816df48571cfa9b73f521964b6 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 2 Oct 2006 16:11:13 -0700 Subject: [NETFILTER]: add type parameter to ip_route_me_harder By adding a type parameter to ip_route_me_harder() the expensive call to inet_addr_type() can be avoided in some cases. A followup patch where ip_route_me_harder() is called from within ip_vs_out() is one such example. Signed-off-By: Simon Horman Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4.h | 2 +- net/ipv4/netfilter.c | 9 ++++++--- net/ipv4/netfilter/ip_nat_standalone.c | 3 ++- net/ipv4/netfilter/iptable_mangle.c | 3 ++- 4 files changed, 11 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index ce02c984f3ba..5b63a231a76b 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -77,7 +77,7 @@ enum nf_ip_hook_priorities { #define SO_ORIGINAL_DST 80 #ifdef __KERNEL__ -extern int ip_route_me_harder(struct sk_buff **pskb); +extern int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type); extern int ip_xfrm_me_harder(struct sk_buff **pskb); extern unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 5ac15379a0cf..e2005c6810a4 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -8,7 +8,7 @@ #include /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ -int ip_route_me_harder(struct sk_buff **pskb) +int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) { struct iphdr *iph = (*pskb)->nh.iph; struct rtable *rt; @@ -16,10 +16,13 @@ int ip_route_me_harder(struct sk_buff **pskb) struct dst_entry *odst; unsigned int hh_len; + if (addr_type == RTN_UNSPEC) + addr_type = inet_addr_type(iph->saddr); + /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook. */ - if (inet_addr_type(iph->saddr) == RTN_LOCAL) { + if (addr_type == RTN_LOCAL) { fl.nl_u.ip4_u.daddr = iph->daddr; fl.nl_u.ip4_u.saddr = iph->saddr; fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); @@ -156,7 +159,7 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info) if (!(iph->tos == rt_info->tos && iph->daddr == rt_info->daddr && iph->saddr == rt_info->saddr)) - return ip_route_me_harder(pskb); + return ip_route_me_harder(pskb, RTN_UNSPEC); } return 0; } diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 021395b67463..d85d2de50449 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -265,7 +265,8 @@ ip_nat_local_fn(unsigned int hooknum, ct->tuplehash[!dir].tuple.src.u.all #endif ) - return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; + if (ip_route_me_harder(pskb, RTN_UNSPEC)) + ret = NF_DROP; } return ret; } diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index e62ea2bb9c0a..b91f3582359b 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -157,7 +157,8 @@ ipt_local_hook(unsigned int hook, || (*pskb)->nfmark != nfmark #endif || (*pskb)->nh.iph->tos != tos)) - return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; + if (ip_route_me_harder(pskb, RTN_UNSPEC)) + ret = NF_DROP; return ret; } -- cgit v1.2.3 From b18dfa90c008850e0f3bfd63638dd8fbe8e08701 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Mon, 2 Oct 2006 16:12:52 -0700 Subject: [NETFILTER]: ebt_mark: add or/and/xor action support to mark target The following patch adds or/and/xor functionality for the mark target, while staying backwards compatible. Signed-off-by: Bart De Schuymer Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_bridge/ebt_mark_t.h | 12 ++++++++++++ net/bridge/netfilter/ebt_mark.c | 21 +++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_bridge/ebt_mark_t.h b/include/linux/netfilter_bridge/ebt_mark_t.h index 110fec6a40a2..6270f6f33693 100644 --- a/include/linux/netfilter_bridge/ebt_mark_t.h +++ b/include/linux/netfilter_bridge/ebt_mark_t.h @@ -1,6 +1,18 @@ #ifndef __LINUX_BRIDGE_EBT_MARK_T_H #define __LINUX_BRIDGE_EBT_MARK_T_H +/* The target member is reused for adding new actions, the + * value of the real target is -1 to -NUM_STANDARD_TARGETS. + * For backward compatibility, the 4 lsb (2 would be enough, + * but let's play it safe) are kept to designate this target. + * The remaining bits designate the action. By making the set + * action 0xfffffff0, the result will look ok for older + * versions. [September 2006] */ +#define MARK_SET_VALUE (0xfffffff0) +#define MARK_OR_VALUE (0xffffffe0) +#define MARK_AND_VALUE (0xffffffd0) +#define MARK_XOR_VALUE (0xffffffc0) + struct ebt_mark_t_info { unsigned long mark; diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c index 770c0df972a3..b54306a934e5 100644 --- a/net/bridge/netfilter/ebt_mark.c +++ b/net/bridge/netfilter/ebt_mark.c @@ -22,24 +22,37 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr, const void *data, unsigned int datalen) { struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data; + int action = info->target & -16; - if ((*pskb)->nfmark != info->mark) + if (action == MARK_SET_VALUE) (*pskb)->nfmark = info->mark; + else if (action == MARK_OR_VALUE) + (*pskb)->nfmark |= info->mark; + else if (action == MARK_AND_VALUE) + (*pskb)->nfmark &= info->mark; + else + (*pskb)->nfmark ^= info->mark; - return info->target; + return info->target | -16; } static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data; + int tmp; if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info))) return -EINVAL; - if (BASE_CHAIN && info->target == EBT_RETURN) + tmp = info->target | -16; + if (BASE_CHAIN && tmp == EBT_RETURN) return -EINVAL; CLEAR_BASE_CHAIN_BIT; - if (INVALID_TARGET) + if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) + return -EINVAL; + tmp = info->target & -16; + if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE && + tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE) return -EINVAL; return 0; } -- cgit v1.2.3 From 0a69452cb45add0841c2bc1e75c25f6bd4f1d8d9 Mon Sep 17 00:00:00 2001 From: Diego Beltrami Date: Tue, 3 Oct 2006 23:47:05 -0700 Subject: [XFRM]: BEET mode This patch introduces the BEET mode (Bound End-to-End Tunnel) with as specified by the ietf draft at the following link: http://www.ietf.org/internet-drafts/draft-nikander-esp-beet-mode-06.txt The patch provides only single family support (i.e. inner family = outer family). Signed-off-by: Diego Beltrami Signed-off-by: Miika Komu Signed-off-by: Herbert Xu Signed-off-by: Abhinav Pathak Signed-off-by: Jeff Ahrenholz Signed-off-by: David S. Miller --- include/linux/in.h | 1 + include/linux/ip.h | 9 +++ include/linux/ipsec.h | 3 +- include/linux/xfrm.h | 3 +- net/ipv4/Kconfig | 9 +++ net/ipv4/Makefile | 1 + net/ipv4/esp4.c | 26 ++++++--- net/ipv4/ipcomp.c | 5 +- net/ipv4/xfrm4_mode_beet.c | 139 +++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/Kconfig | 10 ++++ net/ipv6/Makefile | 1 + net/ipv6/ipcomp6.c | 5 +- net/ipv6/xfrm6_mode_beet.c | 107 ++++++++++++++++++++++++++++++++++ net/xfrm/xfrm_user.c | 1 + 14 files changed, 309 insertions(+), 11 deletions(-) create mode 100644 net/ipv4/xfrm4_mode_beet.c create mode 100644 net/ipv6/xfrm6_mode_beet.c (limited to 'include/linux') diff --git a/include/linux/in.h b/include/linux/in.h index d79fc75fa7c2..2619859f6e1b 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -40,6 +40,7 @@ enum { IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ IPPROTO_AH = 51, /* Authentication Header protocol */ + IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ IPPROTO_PIM = 103, /* Protocol Independent Multicast */ IPPROTO_COMP = 108, /* Compression Header protocol */ diff --git a/include/linux/ip.h b/include/linux/ip.h index 6b25d36fc54c..ecee9bb27d0e 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -80,6 +80,8 @@ #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ #define IPOPT_TS_PRESPEC 3 /* specified modules only */ +#define IPV4_BEET_PHMAXLEN 8 + struct iphdr { #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 ihl:4, @@ -123,4 +125,11 @@ struct ip_comp_hdr { __be16 cpi; }; +struct ip_beet_phdr { + __u8 nexthdr; + __u8 hdrlen; + __u8 padlen; + __u8 reserved; +}; + #endif /* _LINUX_IP_H */ diff --git a/include/linux/ipsec.h b/include/linux/ipsec.h index d3c527616b5e..d17a6302a0e9 100644 --- a/include/linux/ipsec.h +++ b/include/linux/ipsec.h @@ -12,7 +12,8 @@ enum { IPSEC_MODE_ANY = 0, /* We do not support this for SA */ IPSEC_MODE_TRANSPORT = 1, - IPSEC_MODE_TUNNEL = 2 + IPSEC_MODE_TUNNEL = 2, + IPSEC_MODE_BEET = 3 }; enum { diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 430afd058269..8ae7f744917b 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -129,7 +129,8 @@ enum #define XFRM_MODE_TUNNEL 1 #define XFRM_MODE_ROUTEOPTIMIZATION 2 #define XFRM_MODE_IN_TRIGGER 3 -#define XFRM_MODE_MAX 4 +#define XFRM_MODE_BEET 4 +#define XFRM_MODE_MAX 5 /* Netlink configuration messages. */ enum { diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index d172a9804448..5572071af735 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -434,6 +434,15 @@ config INET_XFRM_MODE_TUNNEL If unsure, say Y. +config INET_XFRM_MODE_BEET + tristate "IP: IPsec BEET mode" + default y + select XFRM + ---help--- + Support for IPsec BEET mode. + + If unsure, say Y. + config INET_DIAG tristate "INET: socket monitoring interface" default y diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index f66049e28aeb..15645c51520c 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_INET_AH) += ah4.o obj-$(CONFIG_INET_ESP) += esp4.o obj-$(CONFIG_INET_IPCOMP) += ipcomp.o obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o +obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o obj-$(CONFIG_INET_TUNNEL) += tunnel4.o obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 13b29360d102..b5c205b57669 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -253,7 +253,8 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) * as per draft-ietf-ipsec-udp-encaps-06, * section 3.1.2 */ - if (x->props.mode == XFRM_MODE_TRANSPORT) + if (x->props.mode == XFRM_MODE_TRANSPORT || + x->props.mode == XFRM_MODE_BEET) skb->ip_summed = CHECKSUM_UNNECESSARY; } @@ -271,17 +272,28 @@ static u32 esp4_get_max_size(struct xfrm_state *x, int mtu) { struct esp_data *esp = x->data; u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); - - if (x->props.mode == XFRM_MODE_TUNNEL) { - mtu = ALIGN(mtu + 2, blksize); - } else { - /* The worst case. */ + int enclen = 0; + + switch (x->props.mode) { + case XFRM_MODE_TUNNEL: + mtu = ALIGN(mtu +2, blksize); + break; + default: + case XFRM_MODE_TRANSPORT: + /* The worst case */ mtu = ALIGN(mtu + 2, 4) + blksize - 4; + break; + case XFRM_MODE_BEET: + /* The worst case. */ + enclen = IPV4_BEET_PHMAXLEN; + mtu = ALIGN(mtu + enclen + 2, blksize); + break; } + if (esp->conf.padlen) mtu = ALIGN(mtu, esp->conf.padlen); - return mtu + x->props.header_len + esp->auth.icv_trunc_len; + return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen; } static void esp4_err(struct sk_buff *skb, u32 info) diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 2017d36024d4..3839b706142e 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -206,6 +206,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) { struct xfrm_state *t; + u8 mode = XFRM_MODE_TUNNEL; t = xfrm_state_alloc(); if (t == NULL) @@ -216,7 +217,9 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) t->id.daddr.a4 = x->id.daddr.a4; memcpy(&t->sel, &x->sel, sizeof(t->sel)); t->props.family = AF_INET; - t->props.mode = XFRM_MODE_TUNNEL; + if (x->props.mode == XFRM_MODE_BEET) + mode = x->props.mode; + t->props.mode = mode; t->props.saddr.a4 = x->props.saddr.a4; t->props.flags = x->props.flags; diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c new file mode 100644 index 000000000000..89cf59ea7bbe --- /dev/null +++ b/net/ipv4/xfrm4_mode_beet.c @@ -0,0 +1,139 @@ +/* + * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4. + * + * Copyright (c) 2006 Diego Beltrami + * Miika Komu + * Herbert Xu + * Abhinav Pathak + * Jeff Ahrenholz + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Add encapsulation header. + * + * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. + * The following fields in it shall be filled in by x->type->output: + * tot_len + * check + * + * On exit, skb->h will be set to the start of the payload to be processed + * by x->type->output and skb->nh will be set to the top IP header. + */ +static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) +{ + struct iphdr *iph, *top_iph = NULL; + int hdrlen, optlen; + + iph = skb->nh.iph; + skb->h.ipiph = iph; + + hdrlen = 0; + optlen = iph->ihl * 4 - sizeof(*iph); + if (unlikely(optlen)) + hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); + + skb->nh.raw = skb_push(skb, x->props.header_len + hdrlen); + top_iph = skb->nh.iph; + hdrlen = iph->ihl * 4 - optlen; + skb->h.raw += hdrlen; + + memmove(top_iph, iph, hdrlen); + if (unlikely(optlen)) { + struct ip_beet_phdr *ph; + + BUG_ON(optlen < 0); + + ph = (struct ip_beet_phdr *)skb->h.raw; + ph->padlen = 4 - (optlen & 4); + ph->hdrlen = (optlen + ph->padlen + sizeof(*ph)) / 8; + ph->nexthdr = top_iph->protocol; + + top_iph->protocol = IPPROTO_BEETPH; + top_iph->ihl = sizeof(struct iphdr) / 4; + } + + top_iph->saddr = x->props.saddr.a4; + top_iph->daddr = x->id.daddr.a4; + + return 0; +} + +static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb) +{ + struct iphdr *iph = skb->nh.iph; + int phlen = 0; + int optlen = 0; + __u8 ph_nexthdr = 0, protocol = 0; + int err = -EINVAL; + + protocol = iph->protocol; + + if (unlikely(iph->protocol == IPPROTO_BEETPH)) { + struct ip_beet_phdr *ph = (struct ip_beet_phdr*)(iph + 1); + + if (!pskb_may_pull(skb, sizeof(*ph))) + goto out; + + phlen = ph->hdrlen * 8; + optlen = phlen - ph->padlen - sizeof(*ph); + if (optlen < 0 || optlen & 3 || optlen > 250) + goto out; + + if (!pskb_may_pull(skb, phlen)) + goto out; + + ph_nexthdr = ph->nexthdr; + } + + skb_push(skb, sizeof(*iph) - phlen + optlen); + memmove(skb->data, skb->nh.raw, sizeof(*iph)); + skb->nh.raw = skb->data; + + iph = skb->nh.iph; + iph->ihl = (sizeof(*iph) + optlen) / 4; + iph->tot_len = htons(skb->len); + iph->daddr = x->sel.daddr.a4; + iph->saddr = x->sel.saddr.a4; + if (ph_nexthdr) + iph->protocol = ph_nexthdr; + else + iph->protocol = protocol; + iph->check = 0; + iph->check = ip_fast_csum(skb->nh.raw, iph->ihl); + err = 0; +out: + return err; +} + +static struct xfrm_mode xfrm4_beet_mode = { + .input = xfrm4_beet_input, + .output = xfrm4_beet_output, + .owner = THIS_MODULE, + .encap = XFRM_MODE_BEET, +}; + +static int __init xfrm4_beet_init(void) +{ + return xfrm_register_mode(&xfrm4_beet_mode, AF_INET); +} + +static void __exit xfrm4_beet_exit(void) +{ + int err; + + err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET); + BUG_ON(err); +} + +module_init(xfrm4_beet_init); +module_exit(xfrm4_beet_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET); diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index a2d211da2aba..a460e8132b4d 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -136,6 +136,16 @@ config INET6_XFRM_MODE_TUNNEL If unsure, say Y. +config INET6_XFRM_MODE_BEET + tristate "IPv6: IPsec BEET mode" + depends on IPV6 + default IPV6 + select XFRM + ---help--- + Support for IPsec BEET mode. + + If unsure, say Y. + config INET6_XFRM_MODE_ROUTEOPTIMIZATION tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)" depends on IPV6 && EXPERIMENTAL diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 0213c6612b58..87274e47fe32 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o +obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o obj-$(CONFIG_NETFILTER) += netfilter/ obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index a2860e35efd7..71f59f18ede8 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -199,6 +199,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) { struct xfrm_state *t = NULL; + u8 mode = XFRM_MODE_TUNNEL; t = xfrm_state_alloc(); if (!t) @@ -212,7 +213,9 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr)); memcpy(&t->sel, &x->sel, sizeof(t->sel)); t->props.family = AF_INET6; - t->props.mode = XFRM_MODE_TUNNEL; + if (x->props.mode == XFRM_MODE_BEET) + mode = x->props.mode; + t->props.mode = mode; memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); if (xfrm_init_state(t)) diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c new file mode 100644 index 000000000000..edcfffa9e87b --- /dev/null +++ b/net/ipv6/xfrm6_mode_beet.c @@ -0,0 +1,107 @@ +/* + * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6. + * + * Copyright (c) 2006 Diego Beltrami + * Miika Komu + * Herbert Xu + * Abhinav Pathak + * Jeff Ahrenholz + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Add encapsulation header. + * + * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. + * The following fields in it shall be filled in by x->type->output: + * payload_len + * + * On exit, skb->h will be set to the start of the encapsulation header to be + * filled in by x->type->output and skb->nh will be set to the nextheader field + * of the extension header directly preceding the encapsulation header, or in + * its absence, that of the top IP header. The value of skb->data will always + * point to the top IP header. + */ +static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) +{ + struct ipv6hdr *iph, *top_iph; + u8 *prevhdr; + int hdr_len; + + skb_push(skb, x->props.header_len); + iph = skb->nh.ipv6h; + + hdr_len = ip6_find_1stfragopt(skb, &prevhdr); + skb->nh.raw = prevhdr - x->props.header_len; + skb->h.raw = skb->data + hdr_len; + memmove(skb->data, iph, hdr_len); + + skb->nh.raw = skb->data; + top_iph = skb->nh.ipv6h; + skb->nh.raw = &top_iph->nexthdr; + skb->h.ipv6h = top_iph + 1; + + ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); + ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); + + return 0; +} + +static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb) +{ + struct ipv6hdr *ip6h; + int size = sizeof(struct ipv6hdr); + int err = -EINVAL; + + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto out; + + skb_push(skb, size); + memmove(skb->data, skb->nh.raw, size); + skb->nh.raw = skb->data; + + skb->mac.raw = memmove(skb->data - skb->mac_len, + skb->mac.raw, skb->mac_len); + + ip6h = skb->nh.ipv6h; + ip6h->payload_len = htons(skb->len - size); + ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6); + ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6); + err = 0; +out: + return err; +} + +static struct xfrm_mode xfrm6_beet_mode = { + .input = xfrm6_beet_input, + .output = xfrm6_beet_output, + .owner = THIS_MODULE, + .encap = XFRM_MODE_BEET, +}; + +static int __init xfrm6_beet_init(void) +{ + return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6); +} + +static void __exit xfrm6_beet_exit(void) +{ + int err; + + err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6); + BUG_ON(err); +} + +module_init(xfrm6_beet_init); +module_exit(xfrm6_beet_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c59a78d2923a..d54b3a70d5df 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -211,6 +211,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, case XFRM_MODE_TRANSPORT: case XFRM_MODE_TUNNEL: case XFRM_MODE_ROUTEOPTIMIZATION: + case XFRM_MODE_BEET: break; default: -- cgit v1.2.3 From 038b0a6d8d32db934bba6a24e74e76e4e327a94f Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 4 Oct 2006 03:38:54 -0400 Subject: Remove all inclusions of kbuild explicitly includes this at build time. Signed-off-by: Dave Jones --- arch/alpha/kernel/setup.c | 1 - arch/alpha/kernel/systbls.S | 1 - arch/arm/kernel/crunch.c | 1 - arch/arm/kernel/iwmmxt-notifier.c | 1 - arch/arm/mach-at91rm9200/board-1arm.c | 1 - arch/arm/mach-at91rm9200/board-carmeva.c | 1 - arch/arm/mach-at91rm9200/board-eb9200.c | 1 - arch/arm/mach-at91rm9200/board-kafa.c | 1 - arch/arm/mach-at91rm9200/board-kb9202.c | 1 - arch/arm/mach-ep93xx/edb9302.c | 1 - arch/arm/mach-ep93xx/edb9312.c | 1 - arch/arm/mach-ep93xx/edb9315.c | 1 - arch/arm/mach-ep93xx/edb9315a.c | 1 - arch/arm/mach-lh7a40x/clcd.c | 2 +- arch/arm/mach-lh7a40x/clocks.c | 1 - arch/arm/mach-omap2/pm-domain.c | 1 - arch/arm/mach-pnx4008/gpio.c | 1 - arch/arm/mach-pnx4008/sleep.S | 1 - arch/arm/mach-pnx4008/time.c | 1 - arch/arm/mach-pxa/leds-trizeps4.c | 1 - arch/arm/tools/gen-mach-types | 1 - arch/arm26/lib/ecard.S | 1 - arch/arm26/lib/io-acorn.S | 1 - arch/frv/kernel/time.c | 1 - arch/h8300/kernel/time.c | 1 - arch/i386/lib/semaphore.S | 1 - arch/m32r/mm/mmu.S | 1 - arch/m68k/kernel/time.c | 1 - arch/m68knommu/platform/532x/config.c | 1 - arch/m68knommu/platform/68328/romvec.S | 2 -- arch/parisc/kernel/head.S | 2 -- arch/parisc/kernel/syscall.S | 1 - arch/powerpc/platforms/83xx/mpc834x_itx.c | 1 - arch/powerpc/platforms/85xx/mpc85xx_ads.h | 1 - arch/powerpc/platforms/85xx/mpc85xx_cds.c | 1 - arch/powerpc/platforms/cell/cbe_regs.c | 2 -- arch/powerpc/platforms/cell/ras.c | 1 - arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | 1 - arch/powerpc/platforms/pasemi/setup.c | 1 - arch/powerpc/platforms/pasemi/time.c | 1 - arch/powerpc/sysdev/tsi108_dev.c | 1 - arch/ppc/amiga/time.c | 1 - arch/ppc/platforms/4xx/cpci405.h | 1 - arch/s390/kernel/kprobes.c | 1 - arch/sparc/kernel/ioport.c | 1 - arch/sparc/kernel/of_device.c | 1 - arch/sparc64/kernel/auxio.c | 1 - arch/sparc64/kernel/of_device.c | 1 - arch/sparc64/kernel/prom.c | 1 - arch/um/drivers/hostaudio_kern.c | 1 - arch/um/drivers/net_kern.c | 1 - arch/um/drivers/slip_kern.c | 1 - arch/um/drivers/ssl.c | 1 - arch/um/drivers/stdio_console.c | 1 - arch/um/drivers/ubd_kern.c | 1 - arch/um/include/mconsole_kern.h | 1 - arch/um/include/mode_kern.h | 2 -- arch/um/include/skas/mmu-skas.h | 1 - arch/um/include/sysdep-ppc/ptrace.h | 1 - arch/um/include/um_uaccess.h | 1 - arch/um/kernel/init_task.c | 1 - arch/um/kernel/irq.c | 1 - arch/um/kernel/ksyms.c | 1 - arch/um/kernel/signal.c | 1 - arch/um/kernel/skas/mem.c | 1 - arch/um/kernel/skas/mmu.c | 1 - arch/um/kernel/skas/tlb.c | 1 - arch/um/kernel/smp.c | 1 - arch/um/kernel/sysrq.c | 1 - arch/um/kernel/trap.c | 1 - arch/um/kernel/tt/gdb_kern.c | 1 - arch/um/kernel/tt/mem.c | 1 - arch/um/kernel/um_arch.c | 1 - arch/um/sys-i386/ldt.c | 1 - arch/um/sys-i386/sysrq.c | 1 - arch/um/sys-i386/tls.c | 1 - arch/v850/kernel/time.c | 1 - arch/x86_64/boot/video.S | 2 -- arch/x86_64/ia32/ia32_binfmt.c | 1 - arch/x86_64/kernel/pci-calgary.c | 1 - arch/x86_64/kernel/tce.c | 1 - arch/x86_64/kernel/x8664_ksyms.c | 1 - arch/x86_64/lib/copy_page.S | 3 +-- arch/x86_64/lib/delay.c | 1 - arch/x86_64/lib/memcpy.S | 3 +-- arch/x86_64/lib/memset.S | 1 - arch/x86_64/lib/thunk.S | 1 - drivers/block/cciss.c | 1 - drivers/block/cpqarray.c | 1 - drivers/char/briq_panel.c | 1 - drivers/char/ftape/lowlevel/fdc-io.c | 1 - drivers/char/ftape/zftape/zftape-rw.c | 1 - drivers/char/ftape/zftape/zftape-rw.h | 1 - drivers/char/hw_random/ixp4xx-rng.c | 1 - drivers/char/mspec.c | 1 - drivers/char/nsc_gpio.c | 1 - drivers/char/pcmcia/synclink_cs.c | 1 - drivers/char/sx.c | 2 -- drivers/char/synclink.c | 1 - drivers/char/watchdog/iTCO_wdt.c | 1 - drivers/char/watchdog/omap_wdt.c | 1 - drivers/char/watchdog/pcwd.c | 1 - drivers/char/watchdog/pcwd_pci.c | 1 - drivers/char/watchdog/pnx4008_wdt.c | 1 - drivers/hwmon/w83791d.c | 1 - drivers/i2c/busses/i2c-ocores.c | 1 - drivers/ide/pci/generic.c | 1 - drivers/ide/pci/jmicron.c | 1 - drivers/ide/pci/rz1000.c | 1 - drivers/infiniband/hw/ipath/ipath_mmap.c | 1 - drivers/leds/leds-ams-delta.c | 1 - drivers/net/arm/ep93xx_eth.c | 1 - drivers/net/fs_enet/mii-fec.c | 2 -- drivers/net/pcnet32.c | 2 -- drivers/net/phy/fixed.c | 1 - drivers/net/ucc_geth_phy.c | 1 - drivers/rtc/rtc-max6902.c | 1 - drivers/scsi/aic94xx/aic94xx_init.c | 1 - drivers/scsi/imm.h | 1 - drivers/scsi/ppa.h | 1 - drivers/serial/cpm_uart/cpm_uart.h | 1 - drivers/serial/netx-serial.c | 2 -- drivers/serial/sh-sci.c | 1 - drivers/serial/sh-sci.h | 1 - drivers/spi/spi_s3c24xx.c | 1 - drivers/spi/spi_s3c24xx_gpio.c | 1 - drivers/usb/core/generic.c | 1 - drivers/usb/gadget/gmidi.c | 1 - drivers/usb/host/u132-hcd.c | 1 - drivers/usb/input/usbtouchscreen.c | 1 - drivers/usb/misc/appledisplay.c | 1 - drivers/usb/misc/ftdi-elan.c | 1 - drivers/usb/misc/sisusbvga/sisusb.c | 1 - drivers/usb/misc/sisusbvga/sisusb_con.c | 1 - drivers/video/intelfb/intelfb_i2c.c | 1 - fs/isofs/namei.c | 1 - fs/nfs/client.c | 1 - fs/nfs/getroot.c | 1 - fs/nfs/namespace.c | 2 -- fs/nfs/nfs4namespace.c | 2 -- fs/nfs/nfsroot.c | 1 - fs/nfs/super.c | 1 - fs/reiserfs/file.c | 1 - include/asm-arm/arch-lh7a40x/clocks.h | 2 -- include/asm-arm/pgtable-nommu.h | 1 - include/asm-i386/alternative-asm.i | 2 -- include/asm-i386/frame.i | 1 - include/asm-powerpc/irq.h | 1 - include/asm-powerpc/pci-bridge.h | 1 - include/asm-sparc64/compat_signal.h | 1 - include/asm-x86_64/alternative-asm.i | 2 -- include/linux/config.h | 1 + include/net/netdma.h | 1 - init/do_mounts.h | 1 - kernel/rtmutex-debug.c | 1 - kernel/rtmutex-tester.c | 1 - mm/filemap.h | 1 - mm/slab.c | 1 - mm/vmstat.c | 1 - net/atm/lec.h | 1 - net/core/fib_rules.c | 1 - net/ipv6/fib6_rules.c | 1 - net/ipv6/mip6.c | 1 - sound/aoa/soundbus/sysfs.c | 1 - sound/core/memory.c | 1 - sound/oss/ac97_plugin_ad1980.c | 1 - sound/oss/awe_wave.c | 1 - sound/oss/cmpci.c | 1 - sound/oss/forte.c | 3 +-- sound/oss/gus_card.c | 7 +++---- sound/oss/gus_wave.c | 5 ++--- sound/oss/mad16.c | 1 - sound/oss/maestro3.c | 1 - sound/oss/maui.c | 1 - sound/oss/wavfront.c | 3 +-- sound/oss/ymfpci.c | 1 - sound/oss/ymfpci.h | 1 - 177 files changed, 11 insertions(+), 199 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index fd4a8fa0c93d..a94e6d93e2ee 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -21,7 +21,6 @@ #include #include #include -#include /* CONFIG_ALPHA_LCA etc */ #include #include #include diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S index 4342cea1a926..f6cfe8ce3f96 100644 --- a/arch/alpha/kernel/systbls.S +++ b/arch/alpha/kernel/systbls.S @@ -4,7 +4,6 @@ * The system call table. */ -#include /* CONFIG_OSF4_COMPAT */ #include .data diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c index 748175921f9b..cec83783206e 100644 --- a/arch/arm/kernel/crunch.c +++ b/arch/arm/kernel/crunch.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/arch/arm/kernel/iwmmxt-notifier.c b/arch/arm/kernel/iwmmxt-notifier.c index 44a86c33796e..0d1a1db40062 100644 --- a/arch/arm/kernel/iwmmxt-notifier.c +++ b/arch/arm/kernel/iwmmxt-notifier.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/arch/arm/mach-at91rm9200/board-1arm.c b/arch/arm/mach-at91rm9200/board-1arm.c index 36eecd7161f5..971c3e2d8e36 100644 --- a/arch/arm/mach-at91rm9200/board-1arm.c +++ b/arch/arm/mach-at91rm9200/board-1arm.c @@ -18,7 +18,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/arch/arm/mach-at91rm9200/board-carmeva.c b/arch/arm/mach-at91rm9200/board-carmeva.c index 50e513681ae6..98208740e7c5 100644 --- a/arch/arm/mach-at91rm9200/board-carmeva.c +++ b/arch/arm/mach-at91rm9200/board-carmeva.c @@ -19,7 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/arch/arm/mach-at91rm9200/board-eb9200.c b/arch/arm/mach-at91rm9200/board-eb9200.c index c6e0d51fbea0..65e867ba2df3 100644 --- a/arch/arm/mach-at91rm9200/board-eb9200.c +++ b/arch/arm/mach-at91rm9200/board-eb9200.c @@ -19,7 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/arch/arm/mach-at91rm9200/board-kafa.c b/arch/arm/mach-at91rm9200/board-kafa.c index 91e301924f2c..6ef3c4879829 100644 --- a/arch/arm/mach-at91rm9200/board-kafa.c +++ b/arch/arm/mach-at91rm9200/board-kafa.c @@ -18,7 +18,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/arch/arm/mach-at91rm9200/board-kb9202.c b/arch/arm/mach-at91rm9200/board-kb9202.c index 272fe43bceca..35a954a44b1b 100644 --- a/arch/arm/mach-at91rm9200/board-kb9202.c +++ b/arch/arm/mach-at91rm9200/board-kb9202.c @@ -19,7 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/arch/arm/mach-ep93xx/edb9302.c b/arch/arm/mach-ep93xx/edb9302.c index 62a8efd23256..0315615b74da 100644 --- a/arch/arm/mach-ep93xx/edb9302.c +++ b/arch/arm/mach-ep93xx/edb9302.c @@ -10,7 +10,6 @@ * your option) any later version. */ -#include #include #include #include diff --git a/arch/arm/mach-ep93xx/edb9312.c b/arch/arm/mach-ep93xx/edb9312.c index 9e399211108c..e310e4d72990 100644 --- a/arch/arm/mach-ep93xx/edb9312.c +++ b/arch/arm/mach-ep93xx/edb9312.c @@ -11,7 +11,6 @@ * your option) any later version. */ -#include #include #include #include diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c index ef7482faad81..249ca9e57bc6 100644 --- a/arch/arm/mach-ep93xx/edb9315.c +++ b/arch/arm/mach-ep93xx/edb9315.c @@ -10,7 +10,6 @@ * your option) any later version. */ -#include #include #include #include diff --git a/arch/arm/mach-ep93xx/edb9315a.c b/arch/arm/mach-ep93xx/edb9315a.c index fa958e9d6ddd..7ca0e6170a41 100644 --- a/arch/arm/mach-ep93xx/edb9315a.c +++ b/arch/arm/mach-ep93xx/edb9315a.c @@ -10,7 +10,6 @@ * your option) any later version. */ -#include #include #include #include diff --git a/arch/arm/mach-lh7a40x/clcd.c b/arch/arm/mach-lh7a40x/clcd.c index 93751fee793d..1992db4c2523 100644 --- a/arch/arm/mach-lh7a40x/clcd.c +++ b/arch/arm/mach-lh7a40x/clcd.c @@ -8,7 +8,7 @@ * version 2 as published by the Free Software Foundation. * */ -#include + #include #include #include diff --git a/arch/arm/mach-lh7a40x/clocks.c b/arch/arm/mach-lh7a40x/clocks.c index 2291afe9f23e..7530a95c15a6 100644 --- a/arch/arm/mach-lh7a40x/clocks.c +++ b/arch/arm/mach-lh7a40x/clocks.c @@ -8,7 +8,6 @@ * */ -#include #include #include #include diff --git a/arch/arm/mach-omap2/pm-domain.c b/arch/arm/mach-omap2/pm-domain.c index 5e20e740cde5..2494091a078b 100644 --- a/arch/arm/mach-omap2/pm-domain.c +++ b/arch/arm/mach-omap2/pm-domain.c @@ -15,7 +15,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include diff --git a/arch/arm/mach-pnx4008/gpio.c b/arch/arm/mach-pnx4008/gpio.c index e1ce050d8fe0..1ab84ced7b5a 100644 --- a/arch/arm/mach-pnx4008/gpio.c +++ b/arch/arm/mach-pnx4008/gpio.c @@ -14,7 +14,6 @@ * or implied. */ -#include #include #include #include diff --git a/arch/arm/mach-pnx4008/sleep.S b/arch/arm/mach-pnx4008/sleep.S index 93c802bac269..fea1e17a3650 100644 --- a/arch/arm/mach-pnx4008/sleep.S +++ b/arch/arm/mach-pnx4008/sleep.S @@ -11,7 +11,6 @@ * or implied. */ -#include #include #include #include diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c index 756228ddd035..b986065cd0f3 100644 --- a/arch/arm/mach-pnx4008/time.c +++ b/arch/arm/mach-pnx4008/time.c @@ -11,7 +11,6 @@ * or implied. */ -#include #include #include #include diff --git a/arch/arm/mach-pxa/leds-trizeps4.c b/arch/arm/mach-pxa/leds-trizeps4.c index 14cfc85e44b5..2271d20ffeda 100644 --- a/arch/arm/mach-pxa/leds-trizeps4.c +++ b/arch/arm/mach-pxa/leds-trizeps4.c @@ -10,7 +10,6 @@ * published by the Free Software Foundation. */ -#include #include #include diff --git a/arch/arm/tools/gen-mach-types b/arch/arm/tools/gen-mach-types index 2f9c9b5dd260..ce319ef64bc1 100644 --- a/arch/arm/tools/gen-mach-types +++ b/arch/arm/tools/gen-mach-types @@ -28,7 +28,6 @@ END { printf(" */\n\n"); printf("#ifndef __ASM_ARM_MACH_TYPE_H\n"); printf("#define __ASM_ARM_MACH_TYPE_H\n\n"); - printf("#include \n\n"); printf("#ifndef __ASSEMBLY__\n"); printf("/* The type of machine we're running on */\n"); printf("extern unsigned int __machine_arch_type;\n"); diff --git a/arch/arm26/lib/ecard.S b/arch/arm26/lib/ecard.S index b4633150f01c..658bc4529c9d 100644 --- a/arch/arm26/lib/ecard.S +++ b/arch/arm26/lib/ecard.S @@ -7,7 +7,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include /* for CONFIG_CPU_nn */ #include #include #include diff --git a/arch/arm26/lib/io-acorn.S b/arch/arm26/lib/io-acorn.S index f6c3e30b1b4f..5f62ade5be39 100644 --- a/arch/arm26/lib/io-acorn.S +++ b/arch/arm26/lib/io-acorn.S @@ -7,7 +7,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include /* for CONFIG_CPU_nn */ #include #include #include diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c index 7e55884135ed..44a9aebc4f5a 100644 --- a/arch/frv/kernel/time.c +++ b/arch/frv/kernel/time.c @@ -10,7 +10,6 @@ * 2 of the License, or (at your option) any later version. */ -#include /* CONFIG_HEARTBEAT */ #include #include #include diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c index e569d17b4ae6..8abab3bc2b6f 100644 --- a/arch/h8300/kernel/time.c +++ b/arch/h8300/kernel/time.c @@ -16,7 +16,6 @@ * "A Kernel Model for Precision Timekeeping" by Dave Mills */ -#include /* CONFIG_HEARTBEAT */ #include #include #include diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S index 01f80b5c45d2..ef6ad9e1a609 100644 --- a/arch/i386/lib/semaphore.S +++ b/arch/i386/lib/semaphore.S @@ -13,7 +13,6 @@ * rw semaphores implemented November 1999 by Benjamin LaHaise */ -#include #include #include #include diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S index 0c28f11d6677..9a4d40b3d6a2 100644 --- a/arch/m32r/mm/mmu.S +++ b/arch/m32r/mm/mmu.S @@ -6,7 +6,6 @@ /* $Id: mmu.S,v 1.15 2004/03/16 02:56:27 takata Exp $ */ -#include /* CONFIG_MMU */ #include #include #include diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index 6cfc984380d9..28b2fefa4513 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -10,7 +10,6 @@ * "A Kernel Model for Precision Timekeeping" by Dave Mills */ -#include /* CONFIG_HEARTBEAT */ #include #include #include diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c index ceef9bc181ea..c7d6ad513820 100644 --- a/arch/m68knommu/platform/532x/config.c +++ b/arch/m68knommu/platform/532x/config.c @@ -17,7 +17,6 @@ /***************************************************************************/ -#include #include #include #include diff --git a/arch/m68knommu/platform/68328/romvec.S b/arch/m68knommu/platform/68328/romvec.S index 3e7fe1e14913..31084466eae8 100644 --- a/arch/m68knommu/platform/68328/romvec.S +++ b/arch/m68knommu/platform/68328/romvec.S @@ -10,8 +10,6 @@ * Copyright 2006 Greg Ungerer */ -#include - .global _start .global _buserr .global trap diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index 3e79e62f7b0b..eaad2328fea1 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -12,8 +12,6 @@ * Initial Version 04-23-1999 by Helge Deller */ -#include /* for CONFIG_SMP */ - #include #include #include diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 9670a89c77fe..a05800429304 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -6,7 +6,6 @@ * thanks to Philipp Rumpf, Mike Shaver and various others * sorry about the wall, puffin.. */ -#include /* for CONFIG_SMP */ #include #include diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 8c676d763bb0..5446bab08eca 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -11,7 +11,6 @@ * option) any later version. */ -#include #include #include #include diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.h b/arch/powerpc/platforms/85xx/mpc85xx_ads.h index effcbf78f851..46c3532992aa 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.h +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.h @@ -18,7 +18,6 @@ #ifndef __MACH_MPC85XXADS_H #define __MACH_MPC85XXADS_H -#include #include #include diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 4c1fede6470e..193a5d7921b5 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -11,7 +11,6 @@ * option) any later version. */ -#include #include #include #include diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c index 3f3859d12e00..2f194ba29899 100644 --- a/arch/powerpc/platforms/cell/cbe_regs.c +++ b/arch/powerpc/platforms/cell/cbe_regs.c @@ -6,8 +6,6 @@ * (c) 2006 Benjamin Herrenschmidt , IBM Corp. */ - -#include #include #include diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index 033ad6e2827b..0984c7071695 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c @@ -1,6 +1,5 @@ #define DEBUG -#include #include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index e4f2b9df5e17..cb6f084844f2 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -18,7 +18,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include #include diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 628482671c15..106896c3b60a 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -22,7 +22,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/arch/powerpc/platforms/pasemi/time.c b/arch/powerpc/platforms/pasemi/time.c index 9bd410b8fec6..fa54351ac268 100644 --- a/arch/powerpc/platforms/pasemi/time.c +++ b/arch/powerpc/platforms/pasemi/time.c @@ -17,7 +17,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c index f3038461d4c0..11de090eb901 100644 --- a/arch/powerpc/sysdev/tsi108_dev.c +++ b/arch/powerpc/sysdev/tsi108_dev.c @@ -9,7 +9,6 @@ * option) any later version. */ -#include #include #include #include diff --git a/arch/ppc/amiga/time.c b/arch/ppc/amiga/time.c index 0073527a7036..8c880c0ca380 100644 --- a/arch/ppc/amiga/time.c +++ b/arch/ppc/amiga/time.c @@ -1,4 +1,3 @@ -#include /* CONFIG_HEARTBEAT */ #include #include #include diff --git a/arch/ppc/platforms/4xx/cpci405.h b/arch/ppc/platforms/4xx/cpci405.h index f5a5c0cd062d..a6c0a138b0d7 100644 --- a/arch/ppc/platforms/4xx/cpci405.h +++ b/arch/ppc/platforms/4xx/cpci405.h @@ -13,7 +13,6 @@ #ifndef __CPCI405_H__ #define __CPCI405_H__ -#include #include #include diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 4d9ff5ce4cbd..67914fe7f317 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -20,7 +20,6 @@ * s390 port, used ppc64 as template. Mike Grundy */ -#include #include #include #include diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index d33f8a07ccac..54d51b404603 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -25,7 +25,6 @@ * Sounds reasonable */ -#include #include #include #include diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index 97bf87e8cdde..74bef2a2d37f 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c index 718350aba1ec..826118ee53d5 100644 --- a/arch/sparc64/kernel/auxio.c +++ b/arch/sparc64/kernel/auxio.c @@ -5,7 +5,6 @@ * Refactoring for unified NCR/PCIO support 2002 Eric Brower (ebrower@usa.net) */ -#include #include #include #include diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 238bbf6de07d..7f9204535770 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 5cc5ab63293f..e21cd6afa709 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -15,7 +15,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include #include diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index d247ef45c374..a0d148ea63d6 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/module.h" #include "linux/init.h" #include "linux/slab.h" diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 300a54a6523e..c1c5604752fb 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -5,7 +5,6 @@ * Licensed under the GPL. */ -#include "linux/config.h" #include "linux/kernel.h" #include "linux/netdevice.h" #include "linux/rtnetlink.h" diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index ccea2d7885e5..788da5439a2d 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c @@ -1,4 +1,3 @@ -#include "linux/config.h" #include "linux/kernel.h" #include "linux/stddef.h" #include "linux/init.h" diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 6f13e7c71a82..ed9c59082d0d 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/fs.h" #include "linux/tty.h" #include "linux/tty_driver.h" diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index e4bfcfe8550b..7a4897e27f42 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/posix_types.h" #include "linux/tty.h" #include "linux/tty_flip.h" diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index fda4a3940698..f0b0668458b7 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -20,7 +20,6 @@ #define MAJOR_NR UBD_MAJOR #define UBD_SHIFT 4 -#include "linux/config.h" #include "linux/module.h" #include "linux/blkdev.h" #include "linux/hdreg.h" diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h index d86ee14260ce..d0b690197fd7 100644 --- a/arch/um/include/mconsole_kern.h +++ b/arch/um/include/mconsole_kern.h @@ -6,7 +6,6 @@ #ifndef __MCONSOLE_KERN_H__ #define __MCONSOLE_KERN_H__ -#include "linux/config.h" #include "linux/list.h" #include "mconsole.h" diff --git a/arch/um/include/mode_kern.h b/arch/um/include/mode_kern.h index e7539a8451ef..88e5e77bf517 100644 --- a/arch/um/include/mode_kern.h +++ b/arch/um/include/mode_kern.h @@ -6,8 +6,6 @@ #ifndef __MODE_KERN_H__ #define __MODE_KERN_H__ -#include "linux/config.h" - #ifdef CONFIG_MODE_TT #include "mode_kern_tt.h" #endif diff --git a/arch/um/include/skas/mmu-skas.h b/arch/um/include/skas/mmu-skas.h index d8869a6ef1b4..b26986c0c3d2 100644 --- a/arch/um/include/skas/mmu-skas.h +++ b/arch/um/include/skas/mmu-skas.h @@ -6,7 +6,6 @@ #ifndef __SKAS_MMU_H #define __SKAS_MMU_H -#include "linux/config.h" #include "mm_id.h" #include "asm/ldt.h" diff --git a/arch/um/include/sysdep-ppc/ptrace.h b/arch/um/include/sysdep-ppc/ptrace.h index 8a27353733a9..df2397dba3e5 100644 --- a/arch/um/include/sysdep-ppc/ptrace.h +++ b/arch/um/include/sysdep-ppc/ptrace.h @@ -5,7 +5,6 @@ #ifndef __SYS_PTRACE_PPC_H #define __SYS_PTRACE_PPC_H -#include "linux/config.h" #include "linux/types.h" /* the following taken from */ diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h index 4567f1eeb4a7..5126a99b5961 100644 --- a/arch/um/include/um_uaccess.h +++ b/arch/um/include/um_uaccess.h @@ -6,7 +6,6 @@ #ifndef __ARCH_UM_UACCESS_H #define __ARCH_UM_UACCESS_H -#include "linux/config.h" #include "choose-mode.h" #ifdef CONFIG_MODE_TT diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index 49ed5ddf0704..8cde431348cc 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/mm.h" #include "linux/module.h" #include "linux/sched.h" diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index ce7f233fc490..eee97bb81ba5 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -5,7 +5,6 @@ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar */ -#include "linux/config.h" #include "linux/kernel.h" #include "linux/module.h" #include "linux/smp.h" diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index f030e44262ba..0e00cf93f900 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/module.h" #include "linux/string.h" #include "linux/smp_lock.h" diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c index 4aa9808ba264..2a32e5e8e9c9 100644 --- a/arch/um/kernel/signal.c +++ b/arch/um/kernel/signal.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/stddef.h" #include "linux/sys.h" #include "linux/sched.h" diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c index 27bbf54b1e52..0d2cce621134 100644 --- a/arch/um/kernel/skas/mem.c +++ b/arch/um/kernel/skas/mem.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/mm.h" #include "asm/pgtable.h" #include "mem_user.h" diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 4cd2ff546ef6..c17eddcf89b3 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/sched.h" #include "linux/list.h" #include "linux/spinlock.h" diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c index 6e84963dfc29..27eb29ce666b 100644 --- a/arch/um/kernel/skas/tlb.c +++ b/arch/um/kernel/skas/tlb.c @@ -6,7 +6,6 @@ #include "linux/stddef.h" #include "linux/sched.h" -#include "linux/config.h" #include "linux/mm.h" #include "asm/page.h" #include "asm/pgtable.h" diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index 511116aebaf7..759b07053160 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/percpu.h" #include "asm/pgalloc.h" #include "asm/tlb.h" diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index b331e970002f..239c98054dec 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/sched.h" #include "linux/kernel.h" #include "linux/module.h" diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index c7b195c7e51f..b5f124a2f6ae 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -8,7 +8,6 @@ #include "linux/sched.h" #include "linux/mm.h" #include "linux/spinlock.h" -#include "linux/config.h" #include "linux/init.h" #include "linux/ptrace.h" #include "asm/semaphore.h" diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c index 26506388a6aa..68e1bf63cd0a 100644 --- a/arch/um/kernel/tt/gdb_kern.c +++ b/arch/um/kernel/tt/gdb_kern.c @@ -4,7 +4,6 @@ */ #include "linux/init.h" -#include "linux/config.h" #include "mconsole_kern.h" #ifdef CONFIG_MCONSOLE diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c index 84a23b14f770..4d1929dfa285 100644 --- a/arch/um/kernel/tt/mem.c +++ b/arch/um/kernel/tt/mem.c @@ -4,7 +4,6 @@ */ #include "linux/stddef.h" -#include "linux/config.h" #include "linux/mm.h" #include "asm/uaccess.h" #include "mem_user.h" diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 97d88e7902f7..66f43c906821 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/kernel.h" #include "linux/sched.h" #include "linux/notifier.h" diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index 69971b78beaf..e299ee5a753d 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -4,7 +4,6 @@ */ #include "linux/stddef.h" -#include "linux/config.h" #include "linux/sched.h" #include "linux/slab.h" #include "linux/types.h" diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c index d5244f070539..171b3e9dc867 100644 --- a/arch/um/sys-i386/sysrq.c +++ b/arch/um/sys-i386/sysrq.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/kernel.h" #include "linux/smp.h" #include "linux/sched.h" diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c index 71b9796258ef..643dab585727 100644 --- a/arch/um/sys-i386/tls.c +++ b/arch/um/sys-i386/tls.c @@ -3,7 +3,6 @@ * Licensed under the GPL */ -#include "linux/config.h" #include "linux/kernel.h" #include "linux/sched.h" #include "linux/slab.h" diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c index f4d1a4d3cdc2..cd06f47c0ea7 100644 --- a/arch/v850/kernel/time.c +++ b/arch/v850/kernel/time.c @@ -10,7 +10,6 @@ * "A Kernel Model for Precision Timekeeping" by Dave Mills */ -#include /* CONFIG_HEARTBEAT */ #include #include #include diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S index 2aa565c136e5..d6ff88f35135 100644 --- a/arch/x86_64/boot/video.S +++ b/arch/x86_64/boot/video.S @@ -11,8 +11,6 @@ * */ -#include /* for CONFIG_VIDEO_* */ - /* Enable autodetection of SVGA adapters and modes. */ #undef CONFIG_VIDEO_SVGA diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c index 2fd5a67fd435..82ef182de6ae 100644 --- a/arch/x86_64/ia32/ia32_binfmt.c +++ b/arch/x86_64/ia32/ia32_binfmt.c @@ -6,7 +6,6 @@ * of ugly preprocessor tricks. Talk about very very poor man's inheritance. */ #include -#include #include #include #include diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index cfb09b07ae99..f760045d6d35 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -21,7 +21,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/arch/x86_64/kernel/tce.c b/arch/x86_64/kernel/tce.c index cbabfdf78e06..f61fb8e4f129 100644 --- a/arch/x86_64/kernel/tce.c +++ b/arch/x86_64/kernel/tce.c @@ -23,7 +23,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c index c3454af5e3a2..6d77e4797a47 100644 --- a/arch/x86_64/kernel/x8664_ksyms.c +++ b/arch/x86_64/kernel/x8664_ksyms.c @@ -1,7 +1,6 @@ /* Exports for assembly files. All C exports should go in the respective C files. */ -#include #include #include diff --git a/arch/x86_64/lib/copy_page.S b/arch/x86_64/lib/copy_page.S index 0ebb03b60e79..727a5d46d2fc 100644 --- a/arch/x86_64/lib/copy_page.S +++ b/arch/x86_64/lib/copy_page.S @@ -1,6 +1,5 @@ /* Written 2003 by Andi Kleen, based on a kernel by Evandro Menezes */ - -#include + #include #include diff --git a/arch/x86_64/lib/delay.c b/arch/x86_64/lib/delay.c index b6cd3cca2f45..50be90975d04 100644 --- a/arch/x86_64/lib/delay.c +++ b/arch/x86_64/lib/delay.c @@ -8,7 +8,6 @@ * depends wildly on alignment on many x86 processors. */ -#include #include #include #include diff --git a/arch/x86_64/lib/memcpy.S b/arch/x86_64/lib/memcpy.S index 967b22fa7d07..0ea0ddc875a7 100644 --- a/arch/x86_64/lib/memcpy.S +++ b/arch/x86_64/lib/memcpy.S @@ -1,6 +1,5 @@ /* Copyright 2002 Andi Kleen */ - -#include + #include #include #include diff --git a/arch/x86_64/lib/memset.S b/arch/x86_64/lib/memset.S index 09ed1f6b0eaa..2c5948116bd2 100644 --- a/arch/x86_64/lib/memset.S +++ b/arch/x86_64/lib/memset.S @@ -1,6 +1,5 @@ /* Copyright 2002 Andi Kleen, SuSE Labs */ -#include #include #include diff --git a/arch/x86_64/lib/thunk.S b/arch/x86_64/lib/thunk.S index 0025535cac8d..55e586d352d3 100644 --- a/arch/x86_64/lib/thunk.S +++ b/arch/x86_64/lib/thunk.S @@ -5,7 +5,6 @@ * Subject to the GNU public license, v.2. No warranty of any kind. */ - #include #include #include #include diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 99f87efe0f58..36b88f6c5f82 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -20,7 +20,6 @@ * */ -#include /* CONFIG_PROC_FS */ #include #include #include diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 4abc193314ee..ada68e65b5ff 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -19,7 +19,6 @@ * Questions/Comments/Bugfixes to iss_storagedev@hp.com * */ -#include /* CONFIG_PROC_FS */ #include #include #include diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c index b8c22255f6ad..9f8082f8dd29 100644 --- a/drivers/char/briq_panel.c +++ b/drivers/char/briq_panel.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c index 65c9d2ec60bd..216532445652 100644 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ b/drivers/char/ftape/lowlevel/fdc-io.c @@ -26,7 +26,6 @@ * Linux. */ -#include /* for CONFIG_FT_* */ #include #include #include diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c index a61ef50f3dfc..dab634686885 100644 --- a/drivers/char/ftape/zftape/zftape-rw.c +++ b/drivers/char/ftape/zftape/zftape-rw.c @@ -24,7 +24,6 @@ * zftape. */ -#include /* for CONFIG_ZFT_DFLT_BLK_SZ */ #include #include diff --git a/drivers/char/ftape/zftape/zftape-rw.h b/drivers/char/ftape/zftape/zftape-rw.h index 14c07f086575..1ceec22b60bd 100644 --- a/drivers/char/ftape/zftape/zftape-rw.h +++ b/drivers/char/ftape/zftape/zftape-rw.h @@ -28,7 +28,6 @@ * */ -#include /* for CONFIG_ZFT_DFLT_BLK_SZ */ #include "../zftape/zftape-buffers.h" #define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape) diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c index 3cf4d641a51c..c9caff57db85 100644 --- a/drivers/char/hw_random/ixp4xx-rng.c +++ b/drivers/char/hw_random/ixp4xx-rng.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 5426b1e5595f..5c0dec39cf6c 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -30,7 +30,6 @@ * processor from ever speculating a cache line from this page. */ -#include #include #include #include diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c index 7719bd75810b..4d47d79bcea7 100644 --- a/drivers/char/nsc_gpio.c +++ b/drivers/char/nsc_gpio.c @@ -7,7 +7,6 @@ Copyright (c) 2005 Jim Cromie */ -#include #include #include #include diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index d1ecb2c6de98..73e324209913 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -35,7 +35,6 @@ #define MAX_DEVICE_COUNT 4 -#include #include #include #include diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 57e31e5eaedb..8fd71a5fc619 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -203,9 +203,7 @@ #define RCS_ID "$Id: sx.c,v 1.33 2000/03/08 10:01:02 wolff, pvdl Exp $" #define RCS_REV "$Revision: 1.33 $" - #include -#include #include #include #include diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 38d94987de83..a4150c4519c4 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -63,7 +63,6 @@ #define MAX_PCI_DEVICES 10 #define MAX_TOTAL_DEVICES 20 -#include #include #include #include diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index 8f89948832fc..aaac94db0d8b 100644 --- a/drivers/char/watchdog/iTCO_wdt.c +++ b/drivers/char/watchdog/iTCO_wdt.c @@ -49,7 +49,6 @@ #define PFX DRV_NAME ": " /* Includes */ -#include /* For CONFIG_WATCHDOG_NOWAYOUT/... */ #include /* For module specific items */ #include /* For new moduleparam's */ #include /* For standard types (like size_t) */ diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c index 8f90b90a5021..5dbd7dc2936f 100644 --- a/drivers/char/watchdog/omap_wdt.c +++ b/drivers/char/watchdog/omap_wdt.c @@ -27,7 +27,6 @@ */ #include -#include #include #include #include diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c index 6f8515db5b07..8e1e6e48e0a7 100644 --- a/drivers/char/watchdog/pcwd.c +++ b/drivers/char/watchdog/pcwd.c @@ -49,7 +49,6 @@ * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ */ -#include /* For CONFIG_WATCHDOG_NOWAYOUT/... */ #include /* For module specific items */ #include /* For new moduleparam's */ #include /* For standard types (like size_t) */ diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index 2de6e497c140..f4872c871063 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c @@ -31,7 +31,6 @@ * Includes, defines, variables, module parameters, ... */ -#include /* For CONFIG_WATCHDOG_NOWAYOUT/... */ #include /* For module specific items */ #include /* For new moduleparam's */ #include /* For standard types (like size_t) */ diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c index db2731ba88e3..3a55fc6abcd8 100644 --- a/drivers/char/watchdog/pnx4008_wdt.c +++ b/drivers/char/watchdog/pnx4008_wdt.c @@ -14,7 +14,6 @@ * or implied. */ -#include #include #include #include diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index d965d074cd61..371ed4f69a97 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -32,7 +32,6 @@ The w83791g chip is the same as the w83791d but lead-free. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 952a28d485ce..3e276e958ef7 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -9,7 +9,6 @@ * kind, whether express or implied. */ -#include #include #include #include diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index 0cb7b9b520ea..965c43659e35 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -23,7 +23,6 @@ #undef REALLY_SLOW_IO /* most systems can safely undef this */ -#include /* for CONFIG_BLK_DEV_IDEPCI */ #include #include #include diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index 68c74bbf8b06..c1cec236ecf0 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -5,7 +5,6 @@ * May be copied or modified under the terms of the GNU General Public License */ -#include #include #include #include diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c index 608cd7609072..5f6950c2d1d1 100644 --- a/drivers/ide/pci/rz1000.c +++ b/drivers/ide/pci/rz1000.c @@ -17,7 +17,6 @@ #undef REALLY_SLOW_IO /* most systems can safely undef this */ -#include /* for CONFIG_BLK_DEV_IDEPCI */ #include #include #include diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c index 11b7378ff214..a82157db4689 100644 --- a/drivers/infiniband/hw/ipath/ipath_mmap.c +++ b/drivers/infiniband/hw/ipath/ipath_mmap.c @@ -30,7 +30,6 @@ * SOFTWARE. */ -#include #include #include #include diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c index e9f06116c4d7..599878c8e714 100644 --- a/drivers/leds/leds-ams-delta.c +++ b/drivers/leds/leds-ams-delta.c @@ -8,7 +8,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index cef00744a9dc..d231efa624d4 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -9,7 +9,6 @@ * (at your option) any later version. */ -#include #include #include #include diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 1328e10caa35..baaae3dbf2e6 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -12,8 +12,6 @@ * kind, whether express or implied. */ - -#include #include #include #include diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 21dc68eff514..a43e24245b7e 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -21,8 +21,6 @@ * *************************************************************************/ -#include - #define DRV_NAME "pcnet32" #ifdef CONFIG_PCNET32_NAPI #define DRV_VERSION "1.33-NAPI" diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index 94b47c8d0ab4..f14e99276dba 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -13,7 +13,6 @@ * option) any later version. * */ -#include #include #include #include diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c index f91028c5386d..67260eb3188a 100644 --- a/drivers/net/ucc_geth_phy.c +++ b/drivers/net/ucc_geth_phy.c @@ -17,7 +17,6 @@ * */ -#include #include #include #include diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 2f0b77724192..0b20dfacbf59 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -19,7 +19,6 @@ * - Initial driver creation. */ -#include #include #include diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index ee2ccad70487..734adc9d5206 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -24,7 +24,6 @@ * */ -#include #include #include #include diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h index ece936ac29c7..8f6f32fc61ff 100644 --- a/drivers/scsi/imm.h +++ b/drivers/scsi/imm.h @@ -66,7 +66,6 @@ */ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ -#include #include #include #include diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h index 7511df3588e4..ba8021427b88 100644 --- a/drivers/scsi/ppa.h +++ b/drivers/scsi/ppa.h @@ -73,7 +73,6 @@ */ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ -#include #include #include #include diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 3b35cb779539..a8f894c78194 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -16,7 +16,6 @@ #ifndef CPM_UART_H #define CPM_UART_H -#include #include #include diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c index c1adc9e4b239..7502109d37f0 100644 --- a/drivers/serial/netx-serial.c +++ b/drivers/serial/netx-serial.c @@ -17,8 +17,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include - #if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index f336ba6778dd..5c025d1190c1 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -20,7 +20,6 @@ #undef DEBUG -#include #include #include #include diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 28643c4dc850..7ee992146ae9 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -10,7 +10,6 @@ * Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003). * Modified to support H8/300 Series Yoshinori Sato (Feb 2004). */ -#include #include #include diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index 5fc14563ee3a..20eb6e95a3a0 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -13,7 +13,6 @@ //#define DEBUG -#include #include #include #include diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c index aacdceb8f44b..a5d2cdfff46f 100644 --- a/drivers/spi/spi_s3c24xx_gpio.c +++ b/drivers/spi/spi_s3c24xx_gpio.c @@ -11,7 +11,6 @@ * */ -#include #include #include #include diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 16332cc57946..ebb20ff7ac58 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -17,7 +17,6 @@ * */ -#include #include #include "usb.h" diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 83601d4009e3..64554acad63f 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -21,7 +21,6 @@ #define DEBUG 1 // #define VERBOSE -#include #include #include #include diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index cb2e2a604d1b..0a315200b331 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -35,7 +35,6 @@ * via an ELAN U132 adapter. * */ -#include #include #include #include diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index 4640d1000d83..923e22db18d4 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -35,7 +35,6 @@ //#define DEBUG -#include #include #include #include diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index bfde82f5d180..fc6cc147996f 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -20,7 +20,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include #include #include #include diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index b88a09497c28..c6f2f488a40f 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -35,7 +35,6 @@ * via an ELAN U132 adapter. * */ -#include #include #include #include diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index a44124c7e851..a287836e39f1 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -36,7 +36,6 @@ * */ -#include #include #include #include diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index fb48feca8353..bf26c3c56990 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -47,7 +47,6 @@ * */ -#include #include #include #include diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index c1113d6e941d..5686e2164e39 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -25,7 +25,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************/ -#include #include #include #include diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index e7ba0c30e071..c04b3a14a3e9 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -6,7 +6,6 @@ * (C) 1991 Linus Torvalds - minix filesystem */ -#include /* Joliet? */ #include #include "isofs.h" diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 8106f3b29e4a..6e4e48c5092a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -10,7 +10,6 @@ */ -#include #include #include diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 76b08ae9ed82..20c6f39ea38a 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -9,7 +9,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 60408646176b..ec1114b33d89 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -7,8 +7,6 @@ * NFS namespace */ -#include - #include #include #include diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 24e47f3bbd17..b872779d7cd5 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -7,8 +7,6 @@ * NFSv4 namespace */ -#include - #include #include #include diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 1d656a645199..8dfefe41a8da 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -69,7 +69,6 @@ * Fabian Frederick: Option parser rebuilt (using parser lib) */ -#include #include #include #include diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e8d40030cab4..28659a919d6e 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -20,7 +20,6 @@ * of another (see nfs_lookup()) */ -#include #include #include diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index c093642fb983..b67ce9354048 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -2,7 +2,6 @@ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ -#include #include #include #include diff --git a/include/asm-arm/arch-lh7a40x/clocks.h b/include/asm-arm/arch-lh7a40x/clocks.h index bee02fd8dab1..7d0ba18ad578 100644 --- a/include/asm-arm/arch-lh7a40x/clocks.h +++ b/include/asm-arm/arch-lh7a40x/clocks.h @@ -8,8 +8,6 @@ * */ -#include - #ifndef __ASM_ARCH_CLOCKS_H #define __ASM_ARCH_CLOCKS_H diff --git a/include/asm-arm/pgtable-nommu.h b/include/asm-arm/pgtable-nommu.h index b13322dccf41..c1b264dff287 100644 --- a/include/asm-arm/pgtable-nommu.h +++ b/include/asm-arm/pgtable-nommu.h @@ -13,7 +13,6 @@ #ifndef __ASSEMBLY__ -#include #include #include #include diff --git a/include/asm-i386/alternative-asm.i b/include/asm-i386/alternative-asm.i index 6c47e3b9484b..f0510209ccbe 100644 --- a/include/asm-i386/alternative-asm.i +++ b/include/asm-i386/alternative-asm.i @@ -1,5 +1,3 @@ -#include - #ifdef CONFIG_SMP .macro LOCK_PREFIX 1: lock diff --git a/include/asm-i386/frame.i b/include/asm-i386/frame.i index 4d68ddce18b6..03620251ae17 100644 --- a/include/asm-i386/frame.i +++ b/include/asm-i386/frame.i @@ -1,4 +1,3 @@ -#include #include /* The annotation hides the frame from the unwinder and makes it look diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h index 4da41efb1319..89ed545b446b 100644 --- a/include/asm-powerpc/irq.h +++ b/include/asm-powerpc/irq.h @@ -9,7 +9,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include #include diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 4f55573762bb..86ee46b09b8a 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -6,7 +6,6 @@ #include #else -#include #include #include diff --git a/include/asm-sparc64/compat_signal.h b/include/asm-sparc64/compat_signal.h index 7aefa301321e..b759eab9b51c 100644 --- a/include/asm-sparc64/compat_signal.h +++ b/include/asm-sparc64/compat_signal.h @@ -1,7 +1,6 @@ #ifndef _COMPAT_SIGNAL_H #define _COMPAT_SIGNAL_H -#include #include #include diff --git a/include/asm-x86_64/alternative-asm.i b/include/asm-x86_64/alternative-asm.i index e4041f4fa4dc..0b3f1a2bb2cb 100644 --- a/include/asm-x86_64/alternative-asm.i +++ b/include/asm-x86_64/alternative-asm.i @@ -1,5 +1,3 @@ -#include - #ifdef CONFIG_SMP .macro LOCK_PREFIX 1: lock diff --git a/include/linux/config.h b/include/linux/config.h index a91f5e55b525..479ffb0a22d8 100644 --- a/include/linux/config.h +++ b/include/linux/config.h @@ -3,6 +3,7 @@ /* This file is no longer in use and kept only for backward compatibility. * autoconf.h is now included via -imacros on the commandline */ +#warning Including config.h is deprecated. #include #endif diff --git a/include/net/netdma.h b/include/net/netdma.h index 7f53cd1d8b1e..f28c6e064e8f 100644 --- a/include/net/netdma.h +++ b/include/net/netdma.h @@ -20,7 +20,6 @@ */ #ifndef NETDMA_H #define NETDMA_H -#include #ifdef CONFIG_NET_DMA #include #include diff --git a/init/do_mounts.h b/init/do_mounts.h index e7f2e7fa066e..735705d137ff 100644 --- a/init/do_mounts.h +++ b/init/do_mounts.h @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/kernel/rtmutex-debug.c b/kernel/rtmutex-debug.c index 0c1faa950af7..da8d6bf46457 100644 --- a/kernel/rtmutex-debug.c +++ b/kernel/rtmutex-debug.c @@ -16,7 +16,6 @@ * * See rt.c in preempt-rt for proper credits and further information */ -#include #include #include #include diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c index 948bd8f643e2..6dcea9dd8c94 100644 --- a/kernel/rtmutex-tester.c +++ b/kernel/rtmutex-tester.c @@ -6,7 +6,6 @@ * Copyright (C) 2006, Timesys Corp., Thomas Gleixner * */ -#include #include #include #include diff --git a/mm/filemap.h b/mm/filemap.h index 3f2a343c6015..c2bff04c84ed 100644 --- a/mm/filemap.h +++ b/mm/filemap.h @@ -12,7 +12,6 @@ #include #include #include -#include #include size_t diff --git a/mm/slab.c b/mm/slab.c index 3dbd6f4e7477..f3514351aed8 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -86,7 +86,6 @@ * All object allocations for a node occur from node specific slab lists. */ -#include #include #include #include diff --git a/mm/vmstat.c b/mm/vmstat.c index a2b6a9f96e5c..45b124e012f5 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -9,7 +9,6 @@ * Christoph Lameter */ -#include #include #include #include diff --git a/net/atm/lec.h b/net/atm/lec.h index 8ac6b7321635..877f50939696 100644 --- a/net/atm/lec.h +++ b/net/atm/lec.h @@ -7,7 +7,6 @@ #ifndef _LEC_H_ #define _LEC_H_ -#include #include #include #include diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index a99d87d82b7f..6b0e63cacd93 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -8,7 +8,6 @@ * Authors: Thomas Graf */ -#include #include #include #include diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 34f5bfaddfc2..d8c1057e8b00 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -13,7 +13,6 @@ * Ville Nuorvala */ -#include #include #include diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 99d116caecda..7ccdc8fc5a31 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -22,7 +22,6 @@ * Masahide NAKAMURA @USAGI */ -#include #include #include #include diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c index d31f8146952a..f580942b5c09 100644 --- a/sound/aoa/soundbus/sysfs.c +++ b/sound/aoa/soundbus/sysfs.c @@ -1,4 +1,3 @@ -#include #include #include /* FIX UP */ diff --git a/sound/core/memory.c b/sound/core/memory.c index fe59850be868..93537ab7c2ac 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -20,7 +20,6 @@ * */ -#include #include #include #include diff --git a/sound/oss/ac97_plugin_ad1980.c b/sound/oss/ac97_plugin_ad1980.c index 24a9acd28160..0435c43d9704 100644 --- a/sound/oss/ac97_plugin_ad1980.c +++ b/sound/oss/ac97_plugin_ad1980.c @@ -28,7 +28,6 @@ */ -#include #include #include #include diff --git a/sound/oss/awe_wave.c b/sound/oss/awe_wave.c index 01c592cee045..1b968f7ecb3f 100644 --- a/sound/oss/awe_wave.c +++ b/sound/oss/awe_wave.c @@ -28,7 +28,6 @@ */ #include -#include #include #include #include diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c index ea51aafaf401..20628aa07a25 100644 --- a/sound/oss/cmpci.c +++ b/sound/oss/cmpci.c @@ -106,7 +106,6 @@ */ /*****************************************************************************/ -#include #include #include #include diff --git a/sound/oss/forte.c b/sound/oss/forte.c index ea1c0207aef2..6c910498924a 100644 --- a/sound/oss/forte.c +++ b/sound/oss/forte.c @@ -26,8 +26,7 @@ * USA * */ - -#include + #include #include diff --git a/sound/oss/gus_card.c b/sound/oss/gus_card.c index a3d6ae33fe8b..4539269b3d95 100644 --- a/sound/oss/gus_card.c +++ b/sound/oss/gus_card.c @@ -11,11 +11,10 @@ * Christoph Hellwig: Adapted to module_init/module_exit, simple cleanups. * * Status: - * Tested... + * Tested... */ - - -#include + + #include #include #include diff --git a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c index 597db7aee632..de10cedee1c7 100644 --- a/sound/oss/gus_wave.c +++ b/sound/oss/gus_wave.c @@ -16,9 +16,8 @@ * usage of CS4231A codec, GUS wave and MIDI for GUS MAX. * Bartlomiej Zolnierkiewicz : added some __init/__exit */ - -#include -#include + +#include #include #define GUSPNP_AUTODETECT diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c index aa3c50db66c4..954647f41dff 100644 --- a/sound/oss/mad16.c +++ b/sound/oss/mad16.c @@ -39,7 +39,6 @@ * Pavel Rabel Clean up Nov-2000 */ -#include #include #include #include diff --git a/sound/oss/maestro3.c b/sound/oss/maestro3.c index 5548e3cff7ce..5ef6e617911b 100644 --- a/sound/oss/maestro3.c +++ b/sound/oss/maestro3.c @@ -124,7 +124,6 @@ /*****************************************************************************/ -#include #include #include #include diff --git a/sound/oss/maui.c b/sound/oss/maui.c index 317f22589a05..9130fcf96552 100644 --- a/sound/oss/maui.c +++ b/sound/oss/maui.c @@ -25,7 +25,6 @@ */ #include -#include #include #include diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c index 1dec3958cc7b..38d9aa0f16a5 100644 --- a/sound/oss/wavfront.c +++ b/sound/oss/wavfront.c @@ -76,10 +76,9 @@ #include #include #include -#include +#include #include #include -#include #include diff --git a/sound/oss/ymfpci.c b/sound/oss/ymfpci.c index 6e22472df952..4c89af9ea03c 100644 --- a/sound/oss/ymfpci.c +++ b/sound/oss/ymfpci.c @@ -51,7 +51,6 @@ * is entirely harmless. */ -#include #include #include #include diff --git a/sound/oss/ymfpci.h b/sound/oss/ymfpci.h index ac1785f2b7e7..75a751fb9966 100644 --- a/sound/oss/ymfpci.h +++ b/sound/oss/ymfpci.h @@ -21,7 +21,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ -#include #include /* -- cgit v1.2.3 From c8e649ba908954447e9a095677f6a6c8e50a37b2 Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Fri, 29 Sep 2006 11:56:49 -0400 Subject: [PATCH] message types updated Hi, This patch adds a new type for 3rd party module use and cleans up a deprecated message type. Signed-off-by: Steve Grubb Signed-off-by: Al Viro --- include/linux/audit.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/audit.h b/include/linux/audit.h index c3aa09751814..b2ca666d9997 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -75,7 +75,7 @@ #define AUDIT_DAEMON_CONFIG 1203 /* Daemon config change */ #define AUDIT_SYSCALL 1300 /* Syscall event */ -#define AUDIT_FS_WATCH 1301 /* Filesystem watch event */ +/* #define AUDIT_FS_WATCH 1301 * Deprecated */ #define AUDIT_PATH 1302 /* Filename path information */ #define AUDIT_IPC 1303 /* IPC record */ #define AUDIT_SOCKETCALL 1304 /* sys_socketcall arguments */ @@ -88,6 +88,7 @@ #define AUDIT_MQ_SENDRECV 1313 /* POSIX MQ send/receive record type */ #define AUDIT_MQ_NOTIFY 1314 /* POSIX MQ notify record type */ #define AUDIT_MQ_GETSETATTR 1315 /* POSIX MQ get/set attribute record type */ +#define AUDIT_KERNEL_OTHER 1316 /* For use by 3rd party modules */ #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ -- cgit v1.2.3 From f86e45131f9d41b1617fbaac7aa1ef23e8d0ab48 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 21:09:31 -0400 Subject: [PATCH] Need forward decl of task_struct in linux/debug_locks.h Signed-off-by: Kyle McMartin --- include/linux/debug_locks.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h index 88dafa246d87..952bee79a8f3 100644 --- a/include/linux/debug_locks.h +++ b/include/linux/debug_locks.h @@ -43,6 +43,8 @@ extern int debug_locks_off(void); # define locking_selftest() do { } while (0) #endif +struct task_struct; + #ifdef CONFIG_LOCKDEP extern void debug_show_all_locks(void); extern void debug_show_held_locks(struct task_struct *task); -- cgit v1.2.3 From b119f13f56a7a47915278ab5eb3c666ca5dbb067 Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Wed, 4 Oct 2006 02:15:19 -0700 Subject: [PATCH] ipc: headers_check fix Fix headers_check #ifdef __KERNEL__ stuff. Signed-off-by: Cedric Le Goater All-the-fault-of: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/Kbuild | 2 +- include/linux/ipc.h | 3 ++- include/linux/utsname.h | 17 +++++++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index f7a52e19b4be..9e8bcb5fa99c 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -156,7 +156,6 @@ header-y += toshiba.h header-y += ultrasound.h header-y += un.h header-y += utime.h -header-y += utsname.h header-y += video_decoder.h header-y += video_encoder.h header-y += videotext.h @@ -333,6 +332,7 @@ unifdef-y += unistd.h unifdef-y += usb_ch9.h unifdef-y += usbdevice_fs.h unifdef-y += user.h +unifdef-y += utsname.h unifdef-y += videodev2.h unifdef-y += videodev.h unifdef-y += wait.h diff --git a/include/linux/ipc.h b/include/linux/ipc.h index d9e2b3f36c35..636094c29b16 100644 --- a/include/linux/ipc.h +++ b/include/linux/ipc.h @@ -2,7 +2,6 @@ #define _LINUX_IPC_H #include -#include #define IPC_PRIVATE ((__kernel_key_t) 0) @@ -52,6 +51,8 @@ struct ipc_perm #ifdef __KERNEL__ +#include + #define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */ /* used by in-kernel data structures */ diff --git a/include/linux/utsname.h b/include/linux/utsname.h index 02e4b6972064..a4555fe3754c 100644 --- a/include/linux/utsname.h +++ b/include/linux/utsname.h @@ -1,11 +1,6 @@ #ifndef _LINUX_UTSNAME_H #define _LINUX_UTSNAME_H -#include -#include -#include -#include - #define __OLD_UTS_LEN 8 struct oldold_utsname { @@ -35,6 +30,13 @@ struct new_utsname { char domainname[65]; }; +#ifdef __KERNEL__ + +#include +#include +#include +#include + struct uts_namespace { struct kref kref; struct new_utsname name; @@ -86,4 +88,7 @@ static inline struct new_utsname *init_utsname(void) } extern struct rw_semaphore uts_sem; -#endif + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_UTSNAME_H */ -- cgit v1.2.3 From 1d2c8eea698514cfaa53fc991b960791d09508e1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 4 Oct 2006 02:15:25 -0700 Subject: [PATCH] slab: clean up leak tracking ifdefs a little bit - rename ____kmalloc to kmalloc_track_caller so that people have a chance to guess what it does just from it's name. Add a comment describing it for those who don't. Also move it after kmalloc in slab.h so people get less confused when they are just looking for kmalloc - move things around in slab.c a little to reduce the ifdef mess. [penberg@cs.helsinki.fi: Fix up reversed #ifdef] Signed-off-by: Christoph Hellwig Signed-off-by: Pekka Enberg Cc: Christoph Lameter Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 26 ++++++++++++++++++-------- mm/slab.c | 13 ++++++++----- mm/util.c | 6 +++--- net/core/skbuff.c | 3 ++- 4 files changed, 31 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index 70be57d8ae0d..c4947b8a2c03 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -77,13 +77,6 @@ struct cache_sizes { extern struct cache_sizes malloc_sizes[]; extern void *__kmalloc(size_t, gfp_t); -#ifndef CONFIG_DEBUG_SLAB -#define ____kmalloc(size, flags) __kmalloc(size, flags) -#else -extern void *__kmalloc_track_caller(size_t, gfp_t, void*); -#define ____kmalloc(size, flags) \ - __kmalloc_track_caller(size, flags, __builtin_return_address(0)) -#endif /** * kmalloc - allocate memory @@ -153,6 +146,23 @@ found: return __kmalloc(size, flags); } +/* + * kmalloc_track_caller is a special version of kmalloc that records the + * calling function of the routine calling it for slab leak tracking instead + * of just the calling function (confusing, eh?). + * It's useful when the call to kmalloc comes from a widely-used standard + * allocator where we care about the real place the memory allocation + * request comes from. + */ +#ifndef CONFIG_DEBUG_SLAB +#define kmalloc_track_caller(size, flags) \ + __kmalloc(size, flags) +#else +extern void *__kmalloc_track_caller(size_t, gfp_t, void*); +#define kmalloc_track_caller(size, flags) \ + __kmalloc_track_caller(size, flags, __builtin_return_address(0)) +#endif + extern void *__kzalloc(size_t, gfp_t); /** @@ -271,7 +281,7 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) #define kmem_cache_alloc_node(c, f, n) kmem_cache_alloc(c, f) #define kmalloc_node(s, f, n) kmalloc(s, f) #define kzalloc(s, f) __kzalloc(s, f) -#define ____kmalloc kmalloc +#define kmalloc_track_caller kmalloc #endif /* CONFIG_SLOB */ diff --git a/mm/slab.c b/mm/slab.c index 3dbd6f4e7477..c23b99250df2 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3488,22 +3488,25 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, } +#ifdef CONFIG_DEBUG_SLAB void *__kmalloc(size_t size, gfp_t flags) { -#ifndef CONFIG_DEBUG_SLAB - return __do_kmalloc(size, flags, NULL); -#else return __do_kmalloc(size, flags, __builtin_return_address(0)); -#endif } EXPORT_SYMBOL(__kmalloc); -#ifdef CONFIG_DEBUG_SLAB void *__kmalloc_track_caller(size_t size, gfp_t flags, void *caller) { return __do_kmalloc(size, flags, caller); } EXPORT_SYMBOL(__kmalloc_track_caller); + +#else +void *__kmalloc(size_t size, gfp_t flags) +{ + return __do_kmalloc(size, flags, NULL); +} +EXPORT_SYMBOL(__kmalloc); #endif /** diff --git a/mm/util.c b/mm/util.c index e14fa84ef39a..ace2aea69f1a 100644 --- a/mm/util.c +++ b/mm/util.c @@ -11,7 +11,7 @@ */ void *__kzalloc(size_t size, gfp_t flags) { - void *ret = ____kmalloc(size, flags); + void *ret = kmalloc_track_caller(size, flags); if (ret) memset(ret, 0, size); return ret; @@ -33,7 +33,7 @@ char *kstrdup(const char *s, gfp_t gfp) return NULL; len = strlen(s) + 1; - buf = ____kmalloc(len, gfp); + buf = kmalloc_track_caller(len, gfp); if (buf) memcpy(buf, s, len); return buf; @@ -51,7 +51,7 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp) { void *p; - p = ____kmalloc(len, gfp); + p = kmalloc_track_caller(len, gfp); if (p) memcpy(p, src, len); return p; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c448c7f6fde2..3c23760c5827 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -156,7 +156,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, /* Get the DATA. Size must match skb_add_mtu(). */ size = SKB_DATA_ALIGN(size); - data = ____kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); + data = kmalloc_track_caller(size + sizeof(struct skb_shared_info), + gfp_mask); if (!data) goto nodata; -- cgit v1.2.3 From 856fe98f168e5b80b053979769af2514aab96d6b Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Wed, 4 Oct 2006 02:15:35 -0700 Subject: [PATCH] scx200_hrt: fix precedence bug manifesting as 27x clock in 1 MHz mode Fix paren-placement / precedence bug breaking initialization for 1 MHz clock mode. Also fix comment spelling error, and fence-post (off-by-one) error on symbol used in request_region. Addresses http://bugzilla.kernel.org/show_bug.cgi?id=7242 Thanks alexander.krause@erazor-zone.de, dzpost@dedekind.net, for the reports and patch test, and phelps@mantara.com for the independent patch and verification. Signed-off-by: Jim Cromie Cc: Cc: Cc: Acked-by: John Stultz Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/clocksource/scx200_hrt.c | 4 ++-- include/linux/scx200.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c index d418b8297211..22915cc46ba7 100644 --- a/drivers/clocksource/scx200_hrt.c +++ b/drivers/clocksource/scx200_hrt.c @@ -63,7 +63,7 @@ static struct clocksource cs_hrt = { static int __init init_hrt_clocksource(void) { - /* Make sure scx200 has initializedd the configuration block */ + /* Make sure scx200 has initialized the configuration block */ if (!scx200_cb_present()) return -ENODEV; @@ -76,7 +76,7 @@ static int __init init_hrt_clocksource(void) } /* write timer config */ - outb(HR_TMEN | (mhz27) ? HR_TMCLKSEL : 0, + outb(HR_TMEN | (mhz27 ? HR_TMCLKSEL : 0), scx200_cb_base + SCx200_TMCNFG_OFFSET); if (mhz27) { diff --git a/include/linux/scx200.h b/include/linux/scx200.h index 693c0557e70b..de466e11e271 100644 --- a/include/linux/scx200.h +++ b/include/linux/scx200.h @@ -32,7 +32,7 @@ extern unsigned scx200_cb_base; /* High Resolution Timer */ #define SCx200_TIMER_OFFSET 0x08 -#define SCx200_TIMER_SIZE 0x05 +#define SCx200_TIMER_SIZE 0x06 /* Clock Generators */ #define SCx200_CLOCKGEN_OFFSET 0x10 -- cgit v1.2.3 From 4020f2d7f0b0e68b92bec9a3e1f4a54a7a9dc672 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Wed, 4 Oct 2006 02:15:37 -0700 Subject: [PATCH] mmc: driver for TI FlashMedia card reader - source Driver for TI Flash Media card reader. At present, only MMC/SD cards are supported. [akpm@osdl.org: cleanups, build fixes] Signed-off-by: Alex Dubov Cc: Daniel Qarras Acked-by: Pierre Ossman Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 5 + drivers/misc/tifm_7xx1.c | 437 ++++++++++++++++++++++ drivers/misc/tifm_core.c | 272 ++++++++++++++ drivers/mmc/tifm_sd.c | 933 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/tifm.h | 158 ++++++++ 5 files changed, 1805 insertions(+) create mode 100644 drivers/misc/tifm_7xx1.c create mode 100644 drivers/misc/tifm_core.c create mode 100644 drivers/mmc/tifm_sd.c create mode 100644 include/linux/tifm.h (limited to 'include/linux') diff --git a/MAINTAINERS b/MAINTAINERS index 1c6223d3ce70..77e58585ce55 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2854,6 +2854,11 @@ M: hlhung3i@gmail.com W: http://tcp-lp-mod.sourceforge.net/ S: Maintained +TI FLASH MEDIA INTERFACE DRIVER +P: Alex Dubov +M: oakad@yahoo.com +S: Maintained + TI OMAP RANDOM NUMBER GENERATOR SUPPORT P: Deepak Saxena M: dsaxena@plexity.net diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c new file mode 100644 index 000000000000..a7ed30446185 --- /dev/null +++ b/drivers/misc/tifm_7xx1.c @@ -0,0 +1,437 @@ +/* + * tifm_7xx1.c - TI FlashMedia driver + * + * Copyright (C) 2006 Alex Dubov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include + +#define DRIVER_NAME "tifm_7xx1" +#define DRIVER_VERSION "0.6" + +static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) +{ + int cnt; + unsigned long flags; + + spin_lock_irqsave(&fm->lock, flags); + if (!fm->inhibit_new_cards) { + for (cnt = 0; cnt < fm->max_sockets; cnt++) { + if (fm->sockets[cnt] == sock) { + fm->remove_mask |= (1 << cnt); + queue_work(fm->wq, &fm->media_remover); + break; + } + } + } + spin_unlock_irqrestore(&fm->lock, flags); +} + +static void tifm_7xx1_remove_media(void *adapter) +{ + struct tifm_adapter *fm = adapter; + unsigned long flags; + int cnt; + struct tifm_dev *sock; + + if (!class_device_get(&fm->cdev)) + return; + spin_lock_irqsave(&fm->lock, flags); + for (cnt = 0; cnt < fm->max_sockets; cnt++) { + if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) { + printk(KERN_INFO DRIVER_NAME + ": demand removing card from socket %d\n", cnt); + sock = fm->sockets[cnt]; + fm->sockets[cnt] = 0; + fm->remove_mask &= ~(1 << cnt); + + writel(0x0e00, sock->addr + SOCK_CONTROL); + + writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, + fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, + fm->addr + FM_SET_INTERRUPT_ENABLE); + + spin_unlock_irqrestore(&fm->lock, flags); + device_unregister(&sock->dev); + spin_lock_irqsave(&fm->lock, flags); + } + } + spin_unlock_irqrestore(&fm->lock, flags); + class_device_put(&fm->cdev); +} + +static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct tifm_adapter *fm = dev_id; + unsigned int irq_status; + unsigned int sock_irq_status, cnt; + + spin_lock(&fm->lock); + irq_status = readl(fm->addr + FM_INTERRUPT_STATUS); + if (irq_status == 0 || irq_status == (~0)) { + spin_unlock(&fm->lock); + return IRQ_NONE; + } + + if (irq_status & TIFM_IRQ_ENABLE) { + writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + + for (cnt = 0; cnt < fm->max_sockets; cnt++) { + sock_irq_status = (irq_status >> cnt) & + (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK); + + if (fm->sockets[cnt]) { + if (sock_irq_status && + fm->sockets[cnt]->signal_irq) + sock_irq_status = fm->sockets[cnt]-> + signal_irq(fm->sockets[cnt], + sock_irq_status); + + if (irq_status & (1 << cnt)) + fm->remove_mask |= 1 << cnt; + } else { + if (irq_status & (1 << cnt)) + fm->insert_mask |= 1 << cnt; + } + } + } + writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); + + if (!fm->inhibit_new_cards) { + if (!fm->remove_mask && !fm->insert_mask) { + writel(TIFM_IRQ_ENABLE, + fm->addr + FM_SET_INTERRUPT_ENABLE); + } else { + queue_work(fm->wq, &fm->media_remover); + queue_work(fm->wq, &fm->media_inserter); + } + } + + spin_unlock(&fm->lock); + return IRQ_HANDLED; +} + +static tifm_media_id tifm_7xx1_toggle_sock_power(char *sock_addr, int is_x2) +{ + unsigned int s_state; + int cnt; + + writel(0x0e00, sock_addr + SOCK_CONTROL); + + for (cnt = 0; cnt < 100; cnt++) { + if (!(TIFM_SOCK_STATE_POWERED & + readl(sock_addr + SOCK_PRESENT_STATE))) + break; + msleep(10); + } + + s_state = readl(sock_addr + SOCK_PRESENT_STATE); + if (!(TIFM_SOCK_STATE_OCCUPIED & s_state)) + return FM_NULL; + + if (is_x2) { + writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL); + } else { + // SmartMedia cards need extra 40 msec + if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1) + msleep(40); + writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED, + sock_addr + SOCK_CONTROL); + msleep(10); + writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED, + sock_addr + SOCK_CONTROL); + } + + for (cnt = 0; cnt < 100; cnt++) { + if ((TIFM_SOCK_STATE_POWERED & + readl(sock_addr + SOCK_PRESENT_STATE))) + break; + msleep(10); + } + + if (!is_x2) + writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED), + sock_addr + SOCK_CONTROL); + + return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7; +} + +inline static char *tifm_7xx1_sock_addr(char *base_addr, unsigned int sock_num) +{ + return base_addr + ((sock_num + 1) << 10); +} + +static void tifm_7xx1_insert_media(void *adapter) +{ + struct tifm_adapter *fm = adapter; + unsigned long flags; + tifm_media_id media_id; + char *card_name = "xx"; + int cnt, ok_to_register; + unsigned int insert_mask; + struct tifm_dev *new_sock = 0; + + if (!class_device_get(&fm->cdev)) + return; + spin_lock_irqsave(&fm->lock, flags); + insert_mask = fm->insert_mask; + fm->insert_mask = 0; + if (fm->inhibit_new_cards) { + spin_unlock_irqrestore(&fm->lock, flags); + class_device_put(&fm->cdev); + return; + } + spin_unlock_irqrestore(&fm->lock, flags); + + for (cnt = 0; cnt < fm->max_sockets; cnt++) { + if (!(insert_mask & (1 << cnt))) + continue; + + media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt), + fm->max_sockets == 2); + if (media_id) { + ok_to_register = 0; + new_sock = tifm_alloc_device(fm, cnt); + if (new_sock) { + new_sock->addr = tifm_7xx1_sock_addr(fm->addr, + cnt); + new_sock->media_id = media_id; + switch (media_id) { + case 1: + card_name = "xd"; + break; + case 2: + card_name = "ms"; + break; + case 3: + card_name = "sd"; + break; + default: + break; + } + snprintf(new_sock->dev.bus_id, BUS_ID_SIZE, + "tifm_%s%u:%u", card_name, fm->id, cnt); + printk(KERN_INFO DRIVER_NAME + ": %s card detected in socket %d\n", + card_name, cnt); + spin_lock_irqsave(&fm->lock, flags); + if (!fm->sockets[cnt]) { + fm->sockets[cnt] = new_sock; + ok_to_register = 1; + } + spin_unlock_irqrestore(&fm->lock, flags); + if (!ok_to_register || + device_register(&new_sock->dev)) { + spin_lock_irqsave(&fm->lock, flags); + fm->sockets[cnt] = 0; + spin_unlock_irqrestore(&fm->lock, + flags); + tifm_free_device(&new_sock->dev); + } + } + } + writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, + fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, + fm->addr + FM_SET_INTERRUPT_ENABLE); + } + + writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); + class_device_put(&fm->cdev); +} + +static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) +{ + struct tifm_adapter *fm = pci_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&fm->lock, flags); + fm->inhibit_new_cards = 1; + fm->remove_mask = 0xf; + fm->insert_mask = 0; + writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&fm->lock, flags); + flush_workqueue(fm->wq); + + tifm_7xx1_remove_media(fm); + + pci_set_power_state(dev, PCI_D3hot); + pci_disable_device(dev); + pci_save_state(dev); + return 0; +} + +static int tifm_7xx1_resume(struct pci_dev *dev) +{ + struct tifm_adapter *fm = pci_get_drvdata(dev); + unsigned long flags; + + pci_restore_state(dev); + pci_enable_device(dev); + pci_set_power_state(dev, PCI_D0); + pci_set_master(dev); + + spin_lock_irqsave(&fm->lock, flags); + fm->inhibit_new_cards = 0; + writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS); + writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, + fm->addr + FM_SET_INTERRUPT_ENABLE); + fm->insert_mask = 0xf; + spin_unlock_irqrestore(&fm->lock, flags); + return 0; +} + +static int tifm_7xx1_probe(struct pci_dev *dev, + const struct pci_device_id *dev_id) +{ + struct tifm_adapter *fm; + int pci_dev_busy = 0; + int rc; + + rc = pci_set_dma_mask(dev, DMA_32BIT_MASK); + if (rc) + return rc; + + rc = pci_enable_device(dev); + if (rc) + return rc; + + pci_set_master(dev); + + rc = pci_request_regions(dev, DRIVER_NAME); + if (rc) { + pci_dev_busy = 1; + goto err_out; + } + + pci_intx(dev, 1); + + fm = tifm_alloc_adapter(); + if (!fm) { + rc = -ENOMEM; + goto err_out_int; + } + + fm->dev = &dev->dev; + fm->max_sockets = (dev->device == 0x803B) ? 2 : 4; + fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets, + GFP_KERNEL); + if (!fm->sockets) + goto err_out_free; + + INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media, fm); + INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media, fm); + fm->eject = tifm_7xx1_eject; + pci_set_drvdata(dev, fm); + + fm->addr = ioremap(pci_resource_start(dev, 0), + pci_resource_len(dev, 0)); + if (!fm->addr) + goto err_out_free; + + rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm); + if (rc) + goto err_out_unmap; + + rc = tifm_add_adapter(fm); + if (rc) + goto err_out_irq; + + writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, + fm->addr + FM_SET_INTERRUPT_ENABLE); + + fm->insert_mask = 0xf; + + return 0; + +err_out_irq: + free_irq(dev->irq, fm); +err_out_unmap: + iounmap(fm->addr); +err_out_free: + pci_set_drvdata(dev, NULL); + tifm_free_adapter(fm); +err_out_int: + pci_intx(dev, 0); + pci_release_regions(dev); +err_out: + if (!pci_dev_busy) + pci_disable_device(dev); + return rc; +} + +static void tifm_7xx1_remove(struct pci_dev *dev) +{ + struct tifm_adapter *fm = pci_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&fm->lock, flags); + fm->inhibit_new_cards = 1; + fm->remove_mask = 0xf; + fm->insert_mask = 0; + writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&fm->lock, flags); + + flush_workqueue(fm->wq); + + tifm_7xx1_remove_media(fm); + + writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + free_irq(dev->irq, fm); + + tifm_remove_adapter(fm); + + pci_set_drvdata(dev, 0); + + iounmap(fm->addr); + pci_intx(dev, 0); + pci_release_regions(dev); + + pci_disable_device(dev); + tifm_free_adapter(fm); +} + +static struct pci_device_id tifm_7xx1_pci_tbl [] = { + { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + 0 }, /* xx21 - the one I have */ + { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + 0 }, /* xx12 - should be also supported */ + { } +}; + +static struct pci_driver tifm_7xx1_driver = { + .name = DRIVER_NAME, + .id_table = tifm_7xx1_pci_tbl, + .probe = tifm_7xx1_probe, + .remove = tifm_7xx1_remove, + .suspend = tifm_7xx1_suspend, + .resume = tifm_7xx1_resume, +}; + +static int __init tifm_7xx1_init(void) +{ + return pci_register_driver(&tifm_7xx1_driver); +} + +static void __exit tifm_7xx1_exit(void) +{ + pci_unregister_driver(&tifm_7xx1_driver); +} + +MODULE_AUTHOR("Alex Dubov"); +MODULE_DESCRIPTION("TI FlashMedia host driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl); +MODULE_VERSION(DRIVER_VERSION); + +module_init(tifm_7xx1_init); +module_exit(tifm_7xx1_exit); diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c new file mode 100644 index 000000000000..cca5f8522469 --- /dev/null +++ b/drivers/misc/tifm_core.c @@ -0,0 +1,272 @@ +/* + * tifm_core.c - TI FlashMedia driver + * + * Copyright (C) 2006 Alex Dubov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + +#define DRIVER_NAME "tifm_core" +#define DRIVER_VERSION "0.6" + +static DEFINE_IDR(tifm_adapter_idr); +static DEFINE_SPINLOCK(tifm_adapter_lock); + +static tifm_media_id *tifm_device_match(tifm_media_id *ids, + struct tifm_dev *dev) +{ + while (*ids) { + if (dev->media_id == *ids) + return ids; + ids++; + } + return NULL; +} + +static int tifm_match(struct device *dev, struct device_driver *drv) +{ + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + struct tifm_driver *fm_drv; + + fm_drv = container_of(drv, struct tifm_driver, driver); + if (!fm_drv->id_table) + return -EINVAL; + if (tifm_device_match(fm_drv->id_table, fm_dev)) + return 1; + return -ENODEV; +} + +static int tifm_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct tifm_dev *fm_dev; + int i = 0; + int length = 0; + const char *card_type_name[] = {"INV", "SM", "MS", "SD"}; + + if (!dev || !(fm_dev = container_of(dev, struct tifm_dev, dev))) + return -ENODEV; + if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, + "TIFM_CARD_TYPE=%s", card_type_name[fm_dev->media_id])) + return -ENOMEM; + + return 0; +} + +static struct bus_type tifm_bus_type = { + .name = "tifm", + .match = tifm_match, + .uevent = tifm_uevent, +}; + +static void tifm_free(struct class_device *cdev) +{ + struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev); + + kfree(fm->sockets); + if (fm->wq) + destroy_workqueue(fm->wq); + kfree(fm); +} + +static struct class tifm_adapter_class = { + .name = "tifm_adapter", + .release = tifm_free +}; + +struct tifm_adapter *tifm_alloc_adapter(void) +{ + struct tifm_adapter *fm; + + fm = kzalloc(sizeof(struct tifm_adapter), GFP_KERNEL); + if (fm) { + fm->cdev.class = &tifm_adapter_class; + spin_lock_init(&fm->lock); + class_device_initialize(&fm->cdev); + } + return fm; +} +EXPORT_SYMBOL(tifm_alloc_adapter); + +void tifm_free_adapter(struct tifm_adapter *fm) +{ + class_device_put(&fm->cdev); +} +EXPORT_SYMBOL(tifm_free_adapter); + +int tifm_add_adapter(struct tifm_adapter *fm) +{ + int rc; + + if (!idr_pre_get(&tifm_adapter_idr, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(&tifm_adapter_lock); + rc = idr_get_new(&tifm_adapter_idr, fm, &fm->id); + spin_unlock(&tifm_adapter_lock); + if (!rc) { + snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); + strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN); + + fm->wq = create_singlethread_workqueue(fm->wq_name); + if (fm->wq) + return class_device_add(&fm->cdev); + + spin_lock(&tifm_adapter_lock); + idr_remove(&tifm_adapter_idr, fm->id); + spin_unlock(&tifm_adapter_lock); + rc = -ENOMEM; + } + return rc; +} +EXPORT_SYMBOL(tifm_add_adapter); + +void tifm_remove_adapter(struct tifm_adapter *fm) +{ + class_device_del(&fm->cdev); + + spin_lock(&tifm_adapter_lock); + idr_remove(&tifm_adapter_idr, fm->id); + spin_unlock(&tifm_adapter_lock); +} +EXPORT_SYMBOL(tifm_remove_adapter); + +void tifm_free_device(struct device *dev) +{ + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + if (fm_dev->wq) + destroy_workqueue(fm_dev->wq); + kfree(fm_dev); +} +EXPORT_SYMBOL(tifm_free_device); + +struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id) +{ + struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL); + + if (dev) { + spin_lock_init(&dev->lock); + snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id); + dev->wq = create_singlethread_workqueue(dev->wq_name); + if (!dev->wq) { + kfree(dev); + return 0; + } + dev->dev.parent = fm->dev; + dev->dev.bus = &tifm_bus_type; + dev->dev.release = tifm_free_device; + } + return dev; +} +EXPORT_SYMBOL(tifm_alloc_device); + +void tifm_eject(struct tifm_dev *sock) +{ + struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent); + fm->eject(fm, sock); +} +EXPORT_SYMBOL(tifm_eject); + +int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents, + int direction) +{ + return pci_map_sg(to_pci_dev(sock->dev.parent), sg, nents, direction); +} +EXPORT_SYMBOL(tifm_map_sg); + +void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents, + int direction) +{ + pci_unmap_sg(to_pci_dev(sock->dev.parent), sg, nents, direction); +} +EXPORT_SYMBOL(tifm_unmap_sg); + +static int tifm_device_probe(struct device *dev) +{ + struct tifm_driver *drv; + struct tifm_dev *fm_dev; + int rc = 0; + const tifm_media_id *id; + + drv = container_of(dev->driver, struct tifm_driver, driver); + fm_dev = container_of(dev, struct tifm_dev, dev); + get_device(dev); + if (!fm_dev->drv && drv->probe && drv->id_table) { + rc = -ENODEV; + id = tifm_device_match(drv->id_table, fm_dev); + if (id) + rc = drv->probe(fm_dev); + if (rc >= 0) { + rc = 0; + fm_dev->drv = drv; + } + } + if (rc) + put_device(dev); + return rc; +} + +static int tifm_device_remove(struct device *dev) +{ + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + struct tifm_driver *drv = fm_dev->drv; + + if (drv) { + if (drv->remove) drv->remove(fm_dev); + fm_dev->drv = 0; + } + + put_device(dev); + return 0; +} + +int tifm_register_driver(struct tifm_driver *drv) +{ + drv->driver.bus = &tifm_bus_type; + drv->driver.probe = tifm_device_probe; + drv->driver.remove = tifm_device_remove; + + return driver_register(&drv->driver); +} +EXPORT_SYMBOL(tifm_register_driver); + +void tifm_unregister_driver(struct tifm_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL(tifm_unregister_driver); + +static int __init tifm_init(void) +{ + int rc = bus_register(&tifm_bus_type); + + if (!rc) { + rc = class_register(&tifm_adapter_class); + if (rc) + bus_unregister(&tifm_bus_type); + } + + return rc; +} + +static void __exit tifm_exit(void) +{ + class_unregister(&tifm_adapter_class); + bus_unregister(&tifm_bus_type); +} + +subsys_initcall(tifm_init); +module_exit(tifm_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alex Dubov"); +MODULE_DESCRIPTION("TI FlashMedia core driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c new file mode 100644 index 000000000000..6d23dc08d169 --- /dev/null +++ b/drivers/mmc/tifm_sd.c @@ -0,0 +1,933 @@ +/* + * tifm_sd.c - TI FlashMedia driver + * + * Copyright (C) 2006 Alex Dubov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + + +#include +#include +#include +#include + +#define DRIVER_NAME "tifm_sd" +#define DRIVER_VERSION "0.6" + +static int no_dma = 0; +static int fixed_timeout = 0; +module_param(no_dma, bool, 0644); +module_param(fixed_timeout, bool, 0644); + +/* Constants here are mostly from OMAP5912 datasheet */ +#define TIFM_MMCSD_RESET 0x0002 +#define TIFM_MMCSD_CLKMASK 0x03ff +#define TIFM_MMCSD_POWER 0x0800 +#define TIFM_MMCSD_4BBUS 0x8000 +#define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */ +#define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */ +#define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */ +#define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */ +#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */ +#define TIFM_MMCSD_READ 0x8000 + +#define TIFM_MMCSD_DATAMASK 0x001d /* set bits: EOFB, BRS, CB, EOC */ +#define TIFM_MMCSD_ERRMASK 0x41e0 /* set bits: CERR, CCRC, CTO, DCRC, DTO */ +#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */ +#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */ +#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */ +#define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */ +#define TIFM_MMCSD_DTO 0x0020 /* data time-out */ +#define TIFM_MMCSD_DCRC 0x0040 /* data crc error */ +#define TIFM_MMCSD_CTO 0x0080 /* command time-out */ +#define TIFM_MMCSD_CCRC 0x0100 /* command crc error */ +#define TIFM_MMCSD_AF 0x0400 /* fifo almost full */ +#define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */ +#define TIFM_MMCSD_CERR 0x4000 /* card status error */ + +#define TIFM_MMCSD_FIFO_SIZE 0x0020 + +#define TIFM_MMCSD_RSP_R0 0x0000 +#define TIFM_MMCSD_RSP_R1 0x0100 +#define TIFM_MMCSD_RSP_R2 0x0200 +#define TIFM_MMCSD_RSP_R3 0x0300 +#define TIFM_MMCSD_RSP_R4 0x0400 +#define TIFM_MMCSD_RSP_R5 0x0500 +#define TIFM_MMCSD_RSP_R6 0x0600 + +#define TIFM_MMCSD_RSP_BUSY 0x0800 + +#define TIFM_MMCSD_CMD_BC 0x0000 +#define TIFM_MMCSD_CMD_BCR 0x1000 +#define TIFM_MMCSD_CMD_AC 0x2000 +#define TIFM_MMCSD_CMD_ADTC 0x3000 + +typedef enum { + IDLE = 0, + CMD, /* main command ended */ + BRS, /* block transfer finished */ + SCMD, /* stop command ended */ + CARD, /* card left busy state */ + FIFO, /* FIFO operation completed (uncertain) */ + READY +} card_state_t; + +enum { + FIFO_RDY = 0x0001, /* hardware dependent value */ + HOST_REG = 0x0002, + EJECT = 0x0004, + EJECT_DONE = 0x0008, + CARD_BUSY = 0x0010, + OPENDRAIN = 0x0040, /* hardware dependent value */ + CARD_EVENT = 0x0100, /* hardware dependent value */ + CARD_RO = 0x0200, /* hardware dependent value */ + FIFO_EVENT = 0x10000 }; /* hardware dependent value */ + +struct tifm_sd { + struct tifm_dev *dev; + + unsigned int flags; + card_state_t state; + unsigned int clk_freq; + unsigned int clk_div; + unsigned long timeout_jiffies; // software timeout - 2 sec + + struct mmc_request *req; + struct work_struct cmd_handler; + struct work_struct abort_handler; + wait_queue_head_t can_eject; + + size_t written_blocks; + char *buffer; + size_t buffer_size; + size_t buffer_pos; + +}; + +static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, + unsigned int host_status) +{ + struct mmc_command *cmd = host->req->cmd; + unsigned int t_val = 0, cnt = 0; + + if (host_status & TIFM_MMCSD_BRS) { + /* in non-dma rx mode BRS fires when fifo is still not empty */ + if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) { + while (host->buffer_size > host->buffer_pos) { + t_val = readl(sock->addr + SOCK_MMCSD_DATA); + host->buffer[host->buffer_pos++] = t_val & 0xff; + host->buffer[host->buffer_pos++] = + (t_val >> 8) & 0xff; + } + } + return 1; + } else if (host->buffer) { + if ((cmd->data->flags & MMC_DATA_READ) && + (host_status & TIFM_MMCSD_AF)) { + for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { + t_val = readl(sock->addr + SOCK_MMCSD_DATA); + if (host->buffer_size > host->buffer_pos) { + host->buffer[host->buffer_pos++] = + t_val & 0xff; + host->buffer[host->buffer_pos++] = + (t_val >> 8) & 0xff; + } + } + } else if ((cmd->data->flags & MMC_DATA_WRITE) + && (host_status & TIFM_MMCSD_AE)) { + for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { + if (host->buffer_size > host->buffer_pos) { + t_val = host->buffer[host->buffer_pos++] & 0x00ff; + t_val |= ((host->buffer[host->buffer_pos++]) << 8) + & 0xff00; + writel(t_val, + sock->addr + SOCK_MMCSD_DATA); + } + } + } + } + return 0; +} + +static unsigned int tifm_sd_op_flags(struct mmc_command *cmd) +{ + unsigned int rc = 0; + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + rc |= TIFM_MMCSD_RSP_R0; + break; + case MMC_RSP_R1B: + rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through + case MMC_RSP_R1: + rc |= TIFM_MMCSD_RSP_R1; + break; + case MMC_RSP_R2: + rc |= TIFM_MMCSD_RSP_R2; + break; + case MMC_RSP_R3: + rc |= TIFM_MMCSD_RSP_R3; + break; + case MMC_RSP_R6: + rc |= TIFM_MMCSD_RSP_R6; + break; + default: + BUG(); + } + + switch (mmc_cmd_type(cmd)) { + case MMC_CMD_BC: + rc |= TIFM_MMCSD_CMD_BC; + break; + case MMC_CMD_BCR: + rc |= TIFM_MMCSD_CMD_BCR; + break; + case MMC_CMD_AC: + rc |= TIFM_MMCSD_CMD_AC; + break; + case MMC_CMD_ADTC: + rc |= TIFM_MMCSD_CMD_ADTC; + break; + default: + BUG(); + } + return rc; +} + +static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd) +{ + struct tifm_dev *sock = host->dev; + unsigned int cmd_mask = tifm_sd_op_flags(cmd) | + (host->flags & OPENDRAIN); + + if (cmd->data && (cmd->data->flags & MMC_DATA_READ)) + cmd_mask |= TIFM_MMCSD_READ; + + dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n", + cmd->opcode, cmd->arg, cmd_mask); + + writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH); + writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW); + writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND); +} + +static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock) +{ + cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16) + | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18); + cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16) + | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10); + cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16) + | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08); + cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16) + | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00); +} + +static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host, + unsigned int host_status) +{ + struct mmc_command *cmd = host->req->cmd; + +change_state: + switch (host->state) { + case IDLE: + return; + case CMD: + if (host_status & TIFM_MMCSD_EOC) { + tifm_sd_fetch_resp(cmd, sock); + if (cmd->data) { + host->state = BRS; + } else + host->state = READY; + goto change_state; + } + break; + case BRS: + if (tifm_sd_transfer_data(sock, host, host_status)) { + if (!host->req->stop) { + if (cmd->data->flags & MMC_DATA_WRITE) { + host->state = CARD; + } else { + host->state = + host->buffer ? READY : FIFO; + } + goto change_state; + } + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + } + break; + case SCMD: + if (host_status & TIFM_MMCSD_EOC) { + tifm_sd_fetch_resp(host->req->stop, sock); + if (cmd->error) { + host->state = READY; + } else if (cmd->data->flags & MMC_DATA_WRITE) { + host->state = CARD; + } else { + host->state = host->buffer ? READY : FIFO; + } + goto change_state; + } + break; + case CARD: + if (!(host->flags & CARD_BUSY) + && (host->written_blocks == cmd->data->blocks)) { + host->state = host->buffer ? READY : FIFO; + goto change_state; + } + break; + case FIFO: + if (host->flags & FIFO_RDY) { + host->state = READY; + host->flags &= ~FIFO_RDY; + goto change_state; + } + break; + case READY: + queue_work(sock->wq, &host->cmd_handler); + return; + } + + queue_delayed_work(sock->wq, &host->abort_handler, + host->timeout_jiffies); +} + +/* Called from interrupt handler */ +static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, + unsigned int sock_irq_status) +{ + struct tifm_sd *host; + unsigned int host_status = 0, fifo_status = 0; + int error_code = 0; + + spin_lock(&sock->lock); + host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); + cancel_delayed_work(&host->abort_handler); + + if (sock_irq_status & FIFO_EVENT) { + fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); + writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS); + + host->flags |= fifo_status & FIFO_RDY; + } + + if (sock_irq_status & CARD_EVENT) { + host_status = readl(sock->addr + SOCK_MMCSD_STATUS); + writel(host_status, sock->addr + SOCK_MMCSD_STATUS); + + if (!(host->flags & HOST_REG)) + queue_work(sock->wq, &host->cmd_handler); + if (!host->req) + goto done; + + if (host_status & TIFM_MMCSD_ERRMASK) { + if (host_status & TIFM_MMCSD_CERR) + error_code = MMC_ERR_FAILED; + else if (host_status & + (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) + error_code = MMC_ERR_TIMEOUT; + else if (host_status & + (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) + error_code = MMC_ERR_BADCRC; + + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); + + if (host->req->stop) { + if (host->state == SCMD) { + host->req->stop->error = error_code; + } else if(host->state == BRS) { + host->req->cmd->error = error_code; + tifm_sd_exec(host, host->req->stop); + queue_delayed_work(sock->wq, + &host->abort_handler, + host->timeout_jiffies); + host->state = SCMD; + goto done; + } else { + host->req->cmd->error = error_code; + } + } else { + host->req->cmd->error = error_code; + } + host->state = READY; + } + + if (host_status & TIFM_MMCSD_CB) + host->flags |= CARD_BUSY; + if ((host_status & TIFM_MMCSD_EOFB) && + (host->flags & CARD_BUSY)) { + host->written_blocks++; + host->flags &= ~CARD_BUSY; + } + } + + if (host->req) + tifm_sd_process_cmd(sock, host, host_status); +done: + dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n", + host_status, fifo_status); + spin_unlock(&sock->lock); + return sock_irq_status; +} + +static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) +{ + struct tifm_dev *sock = card->dev; + unsigned int dest_cnt; + + /* DMA style IO */ + + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(long_log2(cmd->data->blksz) - 2, + sock->addr + SOCK_FIFO_PAGE_SIZE); + writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL); + writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); + + dest_cnt = (cmd->data->blocks) << 8; + + writel(sg_dma_address(cmd->data->sg), sock->addr + SOCK_DMA_ADDRESS); + + writel(cmd->data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS); + writel(cmd->data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN); + + if (cmd->data->flags & MMC_DATA_WRITE) { + writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); + writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN, + sock->addr + SOCK_DMA_CONTROL); + } else { + writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); + writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL); + } +} + +static void tifm_sd_set_data_timeout(struct tifm_sd *host, + struct mmc_data *data) +{ + struct tifm_dev *sock = host->dev; + unsigned int data_timeout = data->timeout_clks; + + if (fixed_timeout) + return; + + data_timeout += data->timeout_ns / + ((1000000000 / host->clk_freq) * host->clk_div); + data_timeout *= 10; // call it fudge factor for now + + if (data_timeout < 0xffff) { + writel((~TIFM_MMCSD_DPE) & + readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), + sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); + writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); + } else { + writel(TIFM_MMCSD_DPE | + readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), + sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); + data_timeout = (data_timeout >> 10) + 1; + if(data_timeout > 0xffff) + data_timeout = 0; /* set to unlimited */ + writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); + } +} + +static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct tifm_sd *host = mmc_priv(mmc); + struct tifm_dev *sock = host->dev; + unsigned long flags; + int sg_count = 0; + struct mmc_data *r_data = mrq->cmd->data; + + spin_lock_irqsave(&sock->lock, flags); + if (host->flags & EJECT) { + spin_unlock_irqrestore(&sock->lock, flags); + goto err_out; + } + + if (host->req) { + printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n"); + spin_unlock_irqrestore(&sock->lock, flags); + goto err_out; + } + + if (r_data) { + tifm_sd_set_data_timeout(host, r_data); + + sg_count = tifm_map_sg(sock, r_data->sg, r_data->sg_len, + mrq->cmd->flags & MMC_DATA_WRITE + ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + if (sg_count != 1) { + printk(KERN_ERR DRIVER_NAME + ": scatterlist map failed\n"); + spin_unlock_irqrestore(&sock->lock, flags); + goto err_out; + } + + host->written_blocks = 0; + host->flags &= ~CARD_BUSY; + tifm_sd_prepare_data(host, mrq->cmd); + } + + host->req = mrq; + host->state = CMD; + queue_delayed_work(sock->wq, &host->abort_handler, + host->timeout_jiffies); + writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + tifm_sd_exec(host, mrq->cmd); + spin_unlock_irqrestore(&sock->lock, flags); + return; + +err_out: + if (sg_count > 0) + tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, + (r_data->flags & MMC_DATA_WRITE) + ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + + mrq->cmd->error = MMC_ERR_TIMEOUT; + mmc_request_done(mmc, mrq); +} + +static void tifm_sd_end_cmd(void *data) +{ + struct tifm_sd *host = data; + struct tifm_dev *sock = host->dev; + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct mmc_request *mrq; + struct mmc_data *r_data = 0; + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + + mrq = host->req; + host->req = 0; + host->state = IDLE; + + if (!mrq) { + printk(KERN_ERR DRIVER_NAME ": no request to complete?\n"); + spin_unlock_irqrestore(&sock->lock, flags); + return; + } + + r_data = mrq->cmd->data; + if (r_data) { + if (r_data->flags & MMC_DATA_WRITE) { + r_data->bytes_xfered = host->written_blocks * + r_data->blksz; + } else { + r_data->bytes_xfered = r_data->blocks - + readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; + r_data->bytes_xfered *= r_data->blksz; + r_data->bytes_xfered += r_data->blksz - + readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; + } + tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, + (r_data->flags & MMC_DATA_WRITE) + ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + } + + writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + + spin_unlock_irqrestore(&sock->lock, flags); + mmc_request_done(mmc, mrq); +} + +static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct tifm_sd *host = mmc_priv(mmc); + struct tifm_dev *sock = host->dev; + unsigned long flags; + struct mmc_data *r_data = mrq->cmd->data; + char *t_buffer = 0; + + if (r_data) { + t_buffer = kmap(r_data->sg->page); + if (!t_buffer) { + printk(KERN_ERR DRIVER_NAME ": kmap failed\n"); + goto err_out; + } + } + + spin_lock_irqsave(&sock->lock, flags); + if (host->flags & EJECT) { + spin_unlock_irqrestore(&sock->lock, flags); + goto err_out; + } + + if (host->req) { + printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n"); + spin_unlock_irqrestore(&sock->lock, flags); + goto err_out; + } + + if (r_data) { + tifm_sd_set_data_timeout(host, r_data); + + host->buffer = t_buffer + r_data->sg->offset; + host->buffer_size = mrq->cmd->data->blocks * + mrq->cmd->data->blksz; + + writel(TIFM_MMCSD_BUFINT | + readl(sock->addr + SOCK_MMCSD_INT_ENABLE), + sock->addr + SOCK_MMCSD_INT_ENABLE); + writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) | + (TIFM_MMCSD_FIFO_SIZE - 1), + sock->addr + SOCK_MMCSD_BUFFER_CONFIG); + + host->written_blocks = 0; + host->flags &= ~CARD_BUSY; + host->buffer_pos = 0; + writel(r_data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS); + writel(r_data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN); + } + + host->req = mrq; + host->state = CMD; + queue_delayed_work(sock->wq, &host->abort_handler, + host->timeout_jiffies); + writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + tifm_sd_exec(host, mrq->cmd); + spin_unlock_irqrestore(&sock->lock, flags); + return; + +err_out: + if (t_buffer) + kunmap(r_data->sg->page); + + mrq->cmd->error = MMC_ERR_TIMEOUT; + mmc_request_done(mmc, mrq); +} + +static void tifm_sd_end_cmd_nodma(void *data) +{ + struct tifm_sd *host = (struct tifm_sd*)data; + struct tifm_dev *sock = host->dev; + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct mmc_request *mrq; + struct mmc_data *r_data = 0; + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + + mrq = host->req; + host->req = 0; + host->state = IDLE; + + if (!mrq) { + printk(KERN_ERR DRIVER_NAME ": no request to complete?\n"); + spin_unlock_irqrestore(&sock->lock, flags); + return; + } + + r_data = mrq->cmd->data; + if (r_data) { + writel((~TIFM_MMCSD_BUFINT) & + readl(sock->addr + SOCK_MMCSD_INT_ENABLE), + sock->addr + SOCK_MMCSD_INT_ENABLE); + + if (r_data->flags & MMC_DATA_WRITE) { + r_data->bytes_xfered = host->written_blocks * + r_data->blksz; + } else { + r_data->bytes_xfered = r_data->blocks - + readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; + r_data->bytes_xfered *= r_data->blksz; + r_data->bytes_xfered += r_data->blksz - + readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; + } + host->buffer = 0; + host->buffer_pos = 0; + host->buffer_size = 0; + } + + writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + + spin_unlock_irqrestore(&sock->lock, flags); + + if (r_data) + kunmap(r_data->sg->page); + + mmc_request_done(mmc, mrq); +} + +static void tifm_sd_abort(void *data) +{ + printk(KERN_ERR DRIVER_NAME + ": card failed to respond for a long period of time"); + tifm_eject(((struct tifm_sd*)data)->dev); +} + +static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct tifm_sd *host = mmc_priv(mmc); + struct tifm_dev *sock = host->dev; + unsigned int clk_div1, clk_div2; + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + + dev_dbg(&sock->dev, "Setting bus width %d, power %d\n", ios->bus_width, + ios->power_mode); + if (ios->bus_width == MMC_BUS_WIDTH_4) { + writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG), + sock->addr + SOCK_MMCSD_CONFIG); + } else { + writel((~TIFM_MMCSD_4BBUS) & + readl(sock->addr + SOCK_MMCSD_CONFIG), + sock->addr + SOCK_MMCSD_CONFIG); + } + + if (ios->clock) { + clk_div1 = 20000000 / ios->clock; + if (!clk_div1) + clk_div1 = 1; + + clk_div2 = 24000000 / ios->clock; + if (!clk_div2) + clk_div2 = 1; + + if ((20000000 / clk_div1) > ios->clock) + clk_div1++; + if ((24000000 / clk_div2) > ios->clock) + clk_div2++; + if ((20000000 / clk_div1) > (24000000 / clk_div2)) { + host->clk_freq = 20000000; + host->clk_div = clk_div1; + writel((~TIFM_CTRL_FAST_CLK) & + readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + } else { + host->clk_freq = 24000000; + host->clk_div = clk_div2; + writel(TIFM_CTRL_FAST_CLK | + readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + } + } else { + host->clk_div = 0; + } + host->clk_div &= TIFM_MMCSD_CLKMASK; + writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) & + readl(sock->addr + SOCK_MMCSD_CONFIG)), + sock->addr + SOCK_MMCSD_CONFIG); + + if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) + host->flags |= OPENDRAIN; + else + host->flags &= ~OPENDRAIN; + + /* chip_select : maybe later */ + //vdd + //power is set before probe / after remove + //I believe, power_off when already marked for eject is sufficient to + // allow removal. + if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) { + host->flags |= EJECT_DONE; + wake_up_all(&host->can_eject); + } + + spin_unlock_irqrestore(&sock->lock, flags); +} + +static int tifm_sd_ro(struct mmc_host *mmc) +{ + int rc; + struct tifm_sd *host = mmc_priv(mmc); + struct tifm_dev *sock = host->dev; + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + + host->flags |= (CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE)); + rc = (host->flags & CARD_RO) ? 1 : 0; + + spin_unlock_irqrestore(&sock->lock, flags); + return rc; +} + +static struct mmc_host_ops tifm_sd_ops = { + .request = tifm_sd_request, + .set_ios = tifm_sd_ios, + .get_ro = tifm_sd_ro +}; + +static void tifm_sd_register_host(void *data) +{ + struct tifm_sd *host = (struct tifm_sd*)data; + struct tifm_dev *sock = host->dev; + struct mmc_host *mmc = tifm_get_drvdata(sock); + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + host->flags |= HOST_REG; + PREPARE_WORK(&host->cmd_handler, + no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd, + data); + spin_unlock_irqrestore(&sock->lock, flags); + dev_dbg(&sock->dev, "adding host\n"); + mmc_add_host(mmc); +} + +static int tifm_sd_probe(struct tifm_dev *sock) +{ + struct mmc_host *mmc; + struct tifm_sd *host; + int rc = -EIO; + + if (!(TIFM_SOCK_STATE_OCCUPIED & + readl(sock->addr + SOCK_PRESENT_STATE))) { + printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n"); + return rc; + } + + mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev); + if (!mmc) + return -ENOMEM; + + host = mmc_priv(mmc); + host->dev = sock; + host->clk_div = 61; + init_waitqueue_head(&host->can_eject); + INIT_WORK(&host->cmd_handler, tifm_sd_register_host, host); + INIT_WORK(&host->abort_handler, tifm_sd_abort, host); + + tifm_set_drvdata(sock, mmc); + sock->signal_irq = tifm_sd_signal_irq; + + host->clk_freq = 20000000; + host->timeout_jiffies = msecs_to_jiffies(1000); + + tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request; + mmc->ops = &tifm_sd_ops; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->f_min = 20000000 / 60; + mmc->f_max = 24000000; + mmc->max_hw_segs = 1; + mmc->max_phys_segs = 1; + mmc->max_sectors = 127; + mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length + + writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); + writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); + writel(host->clk_div | TIFM_MMCSD_POWER, + sock->addr + SOCK_MMCSD_CONFIG); + + for (rc = 0; rc < 50; rc++) { + /* Wait for reset ack */ + if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { + rc = 0; + break; + } + msleep(10); + } + + if (rc) { + printk(KERN_ERR DRIVER_NAME + ": card not ready - probe failed\n"); + mmc_free_host(mmc); + return -ENODEV; + } + + writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); + writel(host->clk_div | TIFM_MMCSD_POWER, + sock->addr + SOCK_MMCSD_CONFIG); + writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); + writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK, + sock->addr + SOCK_MMCSD_INT_ENABLE); + + writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now + writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); + writel(host->clk_div | TIFM_MMCSD_POWER, + sock->addr + SOCK_MMCSD_CONFIG); + + queue_delayed_work(sock->wq, &host->abort_handler, + host->timeout_jiffies); + + return 0; +} + +static int tifm_sd_host_is_down(struct tifm_dev *sock) +{ + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct tifm_sd *host = mmc_priv(mmc); + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&sock->lock, flags); + rc = (host->flags & EJECT_DONE); + spin_unlock_irqrestore(&sock->lock, flags); + return rc; +} + +static void tifm_sd_remove(struct tifm_dev *sock) +{ + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct tifm_sd *host = mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + host->flags |= EJECT; + if (host->req) + queue_work(sock->wq, &host->cmd_handler); + spin_unlock_irqrestore(&sock->lock, flags); + wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock), + host->timeout_jiffies); + + if (host->flags & HOST_REG) + mmc_remove_host(mmc); + + /* The meaning of the bit majority in this constant is unknown. */ + writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); + + tifm_set_drvdata(sock, 0); + mmc_free_host(mmc); +} + +static tifm_media_id tifm_sd_id_tbl[] = { + FM_SD, 0 +}; + +static struct tifm_driver tifm_sd_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE + }, + .id_table = tifm_sd_id_tbl, + .probe = tifm_sd_probe, + .remove = tifm_sd_remove +}; + +static int __init tifm_sd_init(void) +{ + return tifm_register_driver(&tifm_sd_driver); +} + +static void __exit tifm_sd_exit(void) +{ + tifm_unregister_driver(&tifm_sd_driver); +} + +MODULE_AUTHOR("Alex Dubov"); +MODULE_DESCRIPTION("TI FlashMedia SD driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl); +MODULE_VERSION(DRIVER_VERSION); + +module_init(tifm_sd_init); +module_exit(tifm_sd_exit); diff --git a/include/linux/tifm.h b/include/linux/tifm.h new file mode 100644 index 000000000000..203dd5e11ecb --- /dev/null +++ b/include/linux/tifm.h @@ -0,0 +1,158 @@ +/* + * tifm.h - TI FlashMedia driver + * + * Copyright (C) 2006 Alex Dubov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TIFM_H +#define _TIFM_H + +#include +#include +#include +#include +#include + +/* Host registers (relative to pci base address): */ +enum { + FM_SET_INTERRUPT_ENABLE = 0x008, + FM_CLEAR_INTERRUPT_ENABLE = 0x00c, + FM_INTERRUPT_STATUS = 0x014 }; + +/* Socket registers (relative to socket base address): */ +enum { + SOCK_CONTROL = 0x004, + SOCK_PRESENT_STATE = 0x008, + SOCK_DMA_ADDRESS = 0x00c, + SOCK_DMA_CONTROL = 0x010, + SOCK_DMA_FIFO_INT_ENABLE_SET = 0x014, + SOCK_DMA_FIFO_INT_ENABLE_CLEAR = 0x018, + SOCK_DMA_FIFO_STATUS = 0x020, + SOCK_FIFO_CONTROL = 0x024, + SOCK_FIFO_PAGE_SIZE = 0x028, + SOCK_MMCSD_COMMAND = 0x104, + SOCK_MMCSD_ARG_LOW = 0x108, + SOCK_MMCSD_ARG_HIGH = 0x10c, + SOCK_MMCSD_CONFIG = 0x110, + SOCK_MMCSD_STATUS = 0x114, + SOCK_MMCSD_INT_ENABLE = 0x118, + SOCK_MMCSD_COMMAND_TO = 0x11c, + SOCK_MMCSD_DATA_TO = 0x120, + SOCK_MMCSD_DATA = 0x124, + SOCK_MMCSD_BLOCK_LEN = 0x128, + SOCK_MMCSD_NUM_BLOCKS = 0x12c, + SOCK_MMCSD_BUFFER_CONFIG = 0x130, + SOCK_MMCSD_SPI_CONFIG = 0x134, + SOCK_MMCSD_SDIO_MODE_CONFIG = 0x138, + SOCK_MMCSD_RESPONSE = 0x144, + SOCK_MMCSD_SDIO_SR = 0x164, + SOCK_MMCSD_SYSTEM_CONTROL = 0x168, + SOCK_MMCSD_SYSTEM_STATUS = 0x16c, + SOCK_MS_COMMAND = 0x184, + SOCK_MS_DATA = 0x188, + SOCK_MS_STATUS = 0x18c, + SOCK_MS_SYSTEM = 0x190, + SOCK_FIFO_ACCESS = 0x200 }; + + +#define TIFM_IRQ_ENABLE 0x80000000 +#define TIFM_IRQ_SOCKMASK 0x00000001 +#define TIFM_IRQ_CARDMASK 0x00000100 +#define TIFM_IRQ_FIFOMASK 0x00010000 +#define TIFM_IRQ_SETALL 0xffffffff +#define TIFM_IRQ_SETALLSOCK 0x0000000f + +#define TIFM_CTRL_LED 0x00000040 +#define TIFM_CTRL_FAST_CLK 0x00000100 + +#define TIFM_SOCK_STATE_OCCUPIED 0x00000008 +#define TIFM_SOCK_STATE_POWERED 0x00000080 + +#define TIFM_FIFO_ENABLE 0x00000001 /* Meaning of this constant is unverified */ +#define TIFM_FIFO_INT_SETALL 0x0000ffff +#define TIFM_FIFO_INTMASK 0x00000005 /* Meaning of this constant is unverified */ + +#define TIFM_DMA_RESET 0x00000002 /* Meaning of this constant is unverified */ +#define TIFM_DMA_TX 0x00008000 /* Meaning of this constant is unverified */ +#define TIFM_DMA_EN 0x00000001 /* Meaning of this constant is unverified */ + +typedef enum {FM_NULL = 0, FM_XD = 0x01, FM_MS = 0x02, FM_SD = 0x03} tifm_media_id; + +struct tifm_driver; +struct tifm_dev { + char __iomem *addr; + spinlock_t lock; + tifm_media_id media_id; + char wq_name[KOBJ_NAME_LEN]; + struct workqueue_struct *wq; + + unsigned int (*signal_irq)(struct tifm_dev *sock, + unsigned int sock_irq_status); + + struct tifm_driver *drv; + struct device dev; +}; + +struct tifm_driver { + tifm_media_id *id_table; + int (*probe)(struct tifm_dev *dev); + void (*remove)(struct tifm_dev *dev); + + struct device_driver driver; +}; + +struct tifm_adapter { + char __iomem *addr; + unsigned int irq_status; + unsigned int insert_mask; + unsigned int remove_mask; + spinlock_t lock; + unsigned int id; + unsigned int max_sockets; + char wq_name[KOBJ_NAME_LEN]; + unsigned int inhibit_new_cards; + struct workqueue_struct *wq; + struct work_struct media_inserter; + struct work_struct media_remover; + struct tifm_dev **sockets; + struct class_device cdev; + struct device *dev; + + void (*eject)(struct tifm_adapter *fm, struct tifm_dev *sock); +}; + +struct tifm_adapter *tifm_alloc_adapter(void); +void tifm_free_device(struct device *dev); +void tifm_free_adapter(struct tifm_adapter *fm); +int tifm_add_adapter(struct tifm_adapter *fm); +void tifm_remove_adapter(struct tifm_adapter *fm); +struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id); +int tifm_register_driver(struct tifm_driver *drv); +void tifm_unregister_driver(struct tifm_driver *drv); +void tifm_eject(struct tifm_dev *sock); +int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents, + int direction); +void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents, + int direction); + + +static inline void *tifm_get_drvdata(struct tifm_dev *dev) +{ + return dev_get_drvdata(&dev->dev); +} + +static inline void tifm_set_drvdata(struct tifm_dev *dev, void *data) +{ + dev_set_drvdata(&dev->dev, data); +} + +struct tifm_device_id { + tifm_media_id media_id; +}; + +#endif -- cgit v1.2.3 From 4452435948424e5322c2a2fefbdc2cf3732cc45d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:15:46 -0700 Subject: [PATCH] knfsd: Replace two page lists in struct svc_rqst with one We are planning to increase RPCSVC_MAXPAGES from about 8 to about 256. This means we need to be a bit careful about arrays of size RPCSVC_MAXPAGES. struct svc_rqst contains two such arrays. However the there are never more that RPCSVC_MAXPAGES pages in the two arrays together, so only one array is needed. The two arrays are for the pages holding the request, and the pages holding the reply. Instead of two arrays, we can simply keep an index into where the first reply page is. This patch also removes a number of small inline functions that probably server to obscure what is going on rather than clarify it, and opencode the needed functionality. Also remove the 'rq_restailpage' variable as it is *always* 0. i.e. if the response 'xdr' structure has a non-empty tail it is always in the same pages as the head. check counters are initilised and incr properly check for consistant usage of ++ etc maybe extra some inlines for common approach general review Signed-off-by: Neil Brown Cc: Magnus Maatta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs2acl.c | 2 +- fs/nfsd/nfs3acl.c | 2 +- fs/nfsd/nfs3xdr.c | 23 +++++-------- fs/nfsd/nfs4xdr.c | 27 ++++++++------- fs/nfsd/nfsxdr.c | 13 +++----- fs/nfsd/vfs.c | 16 +++++---- include/linux/sunrpc/svc.h | 69 ++++++--------------------------------- net/sunrpc/auth_gss/svcauth_gss.c | 4 +-- net/sunrpc/svc.c | 21 ++++-------- net/sunrpc/svcsock.c | 41 +++++++++++------------ 10 files changed, 77 insertions(+), 141 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index fe56b38364cc..71108da2e54e 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -241,7 +241,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, rqstp->rq_res.page_len = w; while (w > 0) { - if (!svc_take_res_page(rqstp)) + if (!rqstp->rq_respages[rqstp->rq_resused++]) return 0; w -= PAGE_SIZE; } diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 16e10c170aed..f813b054f4a1 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -185,7 +185,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, rqstp->rq_res.page_len = w; while (w > 0) { - if (!svc_take_res_page(rqstp)) + if (!rqstp->rq_respages[rqstp->rq_resused++]) return 0; w -= PAGE_SIZE; } diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 243d94b9653a..20ba728a4642 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -343,8 +343,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, /* set up the kvec */ v=0; while (len > 0) { - pn = rqstp->rq_resused; - svc_take_page(rqstp); + pn = rqstp->rq_resused++; args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]); args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE; len -= args->vec[v].iov_len; @@ -382,7 +381,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, while (len > args->vec[v].iov_len) { len -= args->vec[v].iov_len; v++; - args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]); + args->vec[v].iov_base = page_address(rqstp->rq_pages[v]); args->vec[v].iov_len = PAGE_SIZE; } args->vec[v].iov_len = len; @@ -446,11 +445,11 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, * This page appears in the rq_res.pages list, but as pages_len is always * 0, it won't get in the way */ - svc_take_page(rqstp); len = ntohl(*p++); if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE) return 0; - args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); + args->tname = new = + page_address(rqstp->rq_respages[rqstp->rq_resused++]); args->tlen = len; /* first copy and check from the first page */ old = (char*)p; @@ -522,8 +521,8 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, { if (!(p = decode_fh(p, &args->fh))) return 0; - svc_take_page(rqstp); - args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); + args->buffer = + page_address(rqstp->rq_respages[rqstp->rq_resused++]); return xdr_argsize_check(rqstp, p); } @@ -554,8 +553,8 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, if (args->count > PAGE_SIZE) args->count = PAGE_SIZE; - svc_take_page(rqstp); - args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); + args->buffer = + page_address(rqstp->rq_respages[rqstp->rq_resused++]); return xdr_argsize_check(rqstp, p); } @@ -578,8 +577,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p, args->count = len; while (len > 0) { - pn = rqstp->rq_resused; - svc_take_page(rqstp); + pn = rqstp->rq_resused++; if (!args->buffer) args->buffer = page_address(rqstp->rq_respages[pn]); len -= PAGE_SIZE; @@ -668,7 +666,6 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, rqstp->rq_res.page_len = resp->len; if (resp->len & 3) { /* need to pad the tail */ - rqstp->rq_restailpage = 0; rqstp->rq_res.tail[0].iov_base = p; *p = 0; rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); @@ -693,7 +690,6 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p, rqstp->rq_res.page_len = resp->count; if (resp->count & 3) { /* need to pad the tail */ - rqstp->rq_restailpage = 0; rqstp->rq_res.tail[0].iov_base = p; *p = 0; rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3); @@ -768,7 +764,6 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, rqstp->rq_res.page_len = (resp->count) << 2; /* add the 'tail' to the end of the 'head' page - page 0. */ - rqstp->rq_restailpage = 0; rqstp->rq_res.tail[0].iov_base = p; *p++ = 0; /* no more entries */ *p++ = htonl(resp->common.err == nfserr_eof); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5be00436b5b8..9f30c53ac0ed 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2039,7 +2039,8 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct n } static int -nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read) +nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, + struct nfsd4_read *read) { u32 eof; int v, pn; @@ -2061,10 +2062,11 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read len = maxcount; v = 0; while (len > 0) { - pn = resp->rqstp->rq_resused; - svc_take_page(resp->rqstp); - read->rd_iov[v].iov_base = page_address(resp->rqstp->rq_respages[pn]); - read->rd_iov[v].iov_len = len < PAGE_SIZE ? len : PAGE_SIZE; + pn = resp->rqstp->rq_resused++; + read->rd_iov[v].iov_base = + page_address(resp->rqstp->rq_respages[pn]); + read->rd_iov[v].iov_len = + len < PAGE_SIZE ? len : PAGE_SIZE; v++; len -= PAGE_SIZE; } @@ -2078,7 +2080,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read nfserr = nfserr_inval; if (nfserr) return nfserr; - eof = (read->rd_offset + maxcount >= read->rd_fhp->fh_dentry->d_inode->i_size); + eof = (read->rd_offset + maxcount >= + read->rd_fhp->fh_dentry->d_inode->i_size); WRITE32(eof); WRITE32(maxcount); @@ -2088,7 +2091,6 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read resp->xbuf->page_len = maxcount; /* Use rest of head for padding and remaining ops: */ - resp->rqstp->rq_restailpage = 0; resp->xbuf->tail[0].iov_base = p; resp->xbuf->tail[0].iov_len = 0; if (maxcount&3) { @@ -2113,8 +2115,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r if (resp->xbuf->page_len) return nfserr_resource; - svc_take_page(resp->rqstp); - page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); + page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); maxcount = PAGE_SIZE; RESERVE_SPACE(4); @@ -2138,7 +2139,6 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r resp->xbuf->page_len = maxcount; /* Use rest of head for padding and remaining ops: */ - resp->rqstp->rq_restailpage = 0; resp->xbuf->tail[0].iov_base = p; resp->xbuf->tail[0].iov_len = 0; if (maxcount&3) { @@ -2189,8 +2189,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re goto err_no_verf; } - svc_take_page(resp->rqstp); - page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); + page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); readdir->common.err = 0; readdir->buflen = maxcount; readdir->buffer = page; @@ -2215,10 +2214,10 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re p = readdir->buffer; *p++ = 0; /* no more entries */ *p++ = htonl(readdir->common.err == nfserr_eof); - resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); + resp->xbuf->page_len = ((char*)p) - (char*)page_address( + resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); /* Use rest of head for padding and remaining ops: */ - resp->rqstp->rq_restailpage = 0; resp->xbuf->tail[0].iov_base = tailbase; resp->xbuf->tail[0].iov_len = 0; resp->p = resp->xbuf->tail[0].iov_base; diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 3f14a17eaa6e..ad2fba3c54f8 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -262,8 +262,7 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p, */ v=0; while (len > 0) { - pn=rqstp->rq_resused; - svc_take_page(rqstp); + pn = rqstp->rq_resused++; args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]); args->vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE; len -= args->vec[v].iov_len; @@ -295,7 +294,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, while (len > args->vec[v].iov_len) { len -= args->vec[v].iov_len; v++; - args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]); + args->vec[v].iov_base = page_address(rqstp->rq_pages[v]); args->vec[v].iov_len = PAGE_SIZE; } args->vec[v].iov_len = len; @@ -333,8 +332,7 @@ nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinka { if (!(p = decode_fh(p, &args->fh))) return 0; - svc_take_page(rqstp); - args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); + args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]); return xdr_argsize_check(rqstp, p); } @@ -375,8 +373,7 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, if (args->count > PAGE_SIZE) args->count = PAGE_SIZE; - svc_take_page(rqstp); - args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); + args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]); return xdr_argsize_check(rqstp, p); } @@ -416,7 +413,6 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, rqstp->rq_res.page_len = resp->len; if (resp->len & 3) { /* need to pad the tail */ - rqstp->rq_restailpage = 0; rqstp->rq_res.tail[0].iov_base = p; *p = 0; rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); @@ -436,7 +432,6 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p, rqstp->rq_res.page_len = resp->count; if (resp->count & 3) { /* need to pad the tail */ - rqstp->rq_restailpage = 0; rqstp->rq_res.tail[0].iov_base = p; *p = 0; rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 443ebc52e382..bfd36e587ec5 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -791,22 +791,26 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset { unsigned long count = desc->count; struct svc_rqst *rqstp = desc->arg.data; + struct page **pp = rqstp->rq_respages + rqstp->rq_resused; if (size > count) size = count; if (rqstp->rq_res.page_len == 0) { get_page(page); - rqstp->rq_respages[rqstp->rq_resused++] = page; + put_page(*pp); + *pp = page; + rqstp->rq_resused++; rqstp->rq_res.page_base = offset; rqstp->rq_res.page_len = size; - } else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) { + } else if (page != pp[-1]) { get_page(page); - rqstp->rq_respages[rqstp->rq_resused++] = page; + put_page(*pp); + *pp = page; + rqstp->rq_resused++; rqstp->rq_res.page_len += size; - } else { + } else rqstp->rq_res.page_len += size; - } desc->count = count - size; desc->written += size; @@ -837,7 +841,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, file->f_ra = ra->p_ra; if (file->f_op->sendfile && rqstp->rq_sendfile_ok) { - svc_pushback_unused_pages(rqstp); + rqstp->rq_resused = 1; err = file->f_op->sendfile(file, &offset, *count, nfsd_read_actor, rqstp); } else { diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 4ebcdf91f3b3..3669e91c43b8 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -170,7 +170,6 @@ static inline void svc_putu32(struct kvec *iov, __be32 val) /* * The context of a single thread, including the request currently being * processed. - * NOTE: First two items must be prev/next. */ struct svc_rqst { struct list_head rq_list; /* idle list */ @@ -189,12 +188,9 @@ struct svc_rqst { struct xdr_buf rq_arg; struct xdr_buf rq_res; - struct page * rq_argpages[RPCSVC_MAXPAGES]; - struct page * rq_respages[RPCSVC_MAXPAGES]; - int rq_restailpage; - short rq_argused; /* pages used for argument */ - short rq_arghi; /* pages available in argument page list */ - short rq_resused; /* pages used for result */ + struct page * rq_pages[RPCSVC_MAXPAGES]; + struct page * *rq_respages; /* points into rq_pages */ + int rq_resused; /* number of pages used for result */ __be32 rq_xid; /* transmission id */ u32 rq_prog; /* program number */ @@ -255,63 +251,18 @@ xdr_ressize_check(struct svc_rqst *rqstp, __be32 *p) return vec->iov_len <= PAGE_SIZE; } -static inline struct page * -svc_take_res_page(struct svc_rqst *rqstp) +static inline void svc_free_res_pages(struct svc_rqst *rqstp) { - if (rqstp->rq_arghi <= rqstp->rq_argused) - return NULL; - rqstp->rq_arghi--; - rqstp->rq_respages[rqstp->rq_resused] = - rqstp->rq_argpages[rqstp->rq_arghi]; - return rqstp->rq_respages[rqstp->rq_resused++]; -} - -static inline void svc_take_page(struct svc_rqst *rqstp) -{ - if (rqstp->rq_arghi <= rqstp->rq_argused) { - WARN_ON(1); - return; - } - rqstp->rq_arghi--; - rqstp->rq_respages[rqstp->rq_resused] = - rqstp->rq_argpages[rqstp->rq_arghi]; - rqstp->rq_resused++; -} - -static inline void svc_pushback_allpages(struct svc_rqst *rqstp) -{ - while (rqstp->rq_resused) { - if (rqstp->rq_respages[--rqstp->rq_resused] == NULL) - continue; - rqstp->rq_argpages[rqstp->rq_arghi++] = - rqstp->rq_respages[rqstp->rq_resused]; - rqstp->rq_respages[rqstp->rq_resused] = NULL; - } -} - -static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp) -{ - while (rqstp->rq_resused && - rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) { - - if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) { - rqstp->rq_argpages[rqstp->rq_arghi++] = - rqstp->rq_respages[rqstp->rq_resused]; - rqstp->rq_respages[rqstp->rq_resused] = NULL; + while (rqstp->rq_resused) { + struct page **pp = (rqstp->rq_respages + + --rqstp->rq_resused); + if (*pp) { + put_page(*pp); + *pp = NULL; } } } -static inline void svc_free_allpages(struct svc_rqst *rqstp) -{ - while (rqstp->rq_resused) { - if (rqstp->rq_respages[--rqstp->rq_resused] == NULL) - continue; - put_page(rqstp->rq_respages[rqstp->rq_resused]); - rqstp->rq_respages[rqstp->rq_resused] = NULL; - } -} - struct svc_deferred_req { u32 prot; /* protocol (UDP or TCP) */ struct sockaddr_in addr; diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 638c0b576203..558692d7e465 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1191,7 +1191,6 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp) resbuf->tail[0].iov_base = resbuf->head[0].iov_base + resbuf->head[0].iov_len; resbuf->tail[0].iov_len = 0; - rqstp->rq_restailpage = 0; resv = &resbuf->tail[0]; } else { resv = &resbuf->tail[0]; @@ -1240,7 +1239,7 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp) inpages = resbuf->pages; /* XXX: Would be better to write some xdr helper functions for * nfs{2,3,4}xdr.c that place the data right, instead of copying: */ - if (resbuf->tail[0].iov_base && rqstp->rq_restailpage == 0) { + if (resbuf->tail[0].iov_base) { BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base + PAGE_SIZE); BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base); @@ -1258,7 +1257,6 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp) resbuf->tail[0].iov_base = resbuf->head[0].iov_base + resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE; resbuf->tail[0].iov_len = 0; - rqstp->rq_restailpage = 0; } if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages)) return -ENOMEM; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index a99e67b164c1..f4a509a925b5 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -417,18 +417,15 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size) if (size > RPCSVC_MAXPAYLOAD) size = RPCSVC_MAXPAYLOAD; pages = 2 + (size+ PAGE_SIZE -1) / PAGE_SIZE; - rqstp->rq_argused = 0; - rqstp->rq_resused = 0; arghi = 0; BUG_ON(pages > RPCSVC_MAXPAGES); while (pages) { struct page *p = alloc_page(GFP_KERNEL); if (!p) break; - rqstp->rq_argpages[arghi++] = p; + rqstp->rq_pages[arghi++] = p; pages--; } - rqstp->rq_arghi = arghi; return ! pages; } @@ -438,14 +435,10 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size) static void svc_release_buffer(struct svc_rqst *rqstp) { - while (rqstp->rq_arghi) - put_page(rqstp->rq_argpages[--rqstp->rq_arghi]); - while (rqstp->rq_resused) { - if (rqstp->rq_respages[--rqstp->rq_resused] == NULL) - continue; - put_page(rqstp->rq_respages[rqstp->rq_resused]); - } - rqstp->rq_argused = 0; + int i; + for (i=0; irq_pages); i++) + if (rqstp->rq_pages[i]) + put_page(rqstp->rq_pages[i]); } /* @@ -707,10 +700,10 @@ svc_process(struct svc_rqst *rqstp) /* setup response xdr_buf. * Initially it has just one page */ - svc_take_page(rqstp); /* must succeed */ + rqstp->rq_resused = 1; resv->iov_base = page_address(rqstp->rq_respages[0]); resv->iov_len = 0; - rqstp->rq_res.pages = rqstp->rq_respages+1; + rqstp->rq_res.pages = rqstp->rq_respages + 1; rqstp->rq_res.len = 0; rqstp->rq_res.page_base = 0; rqstp->rq_res.page_len = 0; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 4de8626e4f54..25096d53667a 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -313,7 +313,7 @@ svc_sock_release(struct svc_rqst *rqstp) svc_release_skb(rqstp); - svc_free_allpages(rqstp); + svc_free_res_pages(rqstp); rqstp->rq_res.page_len = 0; rqstp->rq_res.page_base = 0; @@ -412,7 +412,8 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) /* send head */ if (slen == xdr->head[0].iov_len) flags = 0; - len = kernel_sendpage(sock, rqstp->rq_respages[0], 0, xdr->head[0].iov_len, flags); + len = kernel_sendpage(sock, rqstp->rq_respages[0], 0, + xdr->head[0].iov_len, flags); if (len != xdr->head[0].iov_len) goto out; slen -= xdr->head[0].iov_len; @@ -437,8 +438,9 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) } /* send tail */ if (xdr->tail[0].iov_len) { - result = kernel_sendpage(sock, rqstp->rq_respages[rqstp->rq_restailpage], - ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1), + result = kernel_sendpage(sock, rqstp->rq_respages[0], + ((unsigned long)xdr->tail[0].iov_base) + & (PAGE_SIZE-1), xdr->tail[0].iov_len, 0); if (result > 0) @@ -708,9 +710,11 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) if (len <= rqstp->rq_arg.head[0].iov_len) { rqstp->rq_arg.head[0].iov_len = len; rqstp->rq_arg.page_len = 0; + rqstp->rq_respages = rqstp->rq_pages+1; } else { rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len; - rqstp->rq_argused += (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE; + rqstp->rq_respages = rqstp->rq_pages + 1 + + (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE; } if (serv->sv_stats) @@ -1053,11 +1057,12 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp) vlen = PAGE_SIZE; pnum = 1; while (vlen < len) { - vec[pnum].iov_base = page_address(rqstp->rq_argpages[rqstp->rq_argused++]); + vec[pnum].iov_base = page_address(rqstp->rq_pages[pnum]); vec[pnum].iov_len = PAGE_SIZE; pnum++; vlen += PAGE_SIZE; } + rqstp->rq_respages = &rqstp->rq_pages[pnum]; /* Now receive data */ len = svc_recvfrom(rqstp, vec, pnum, len); @@ -1209,7 +1214,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout) struct svc_sock *svsk =NULL; struct svc_serv *serv = rqstp->rq_server; struct svc_pool *pool = rqstp->rq_pool; - int len; + int len, i; int pages; struct xdr_buf *arg; DECLARE_WAITQUEUE(wait, current); @@ -1226,27 +1231,22 @@ svc_recv(struct svc_rqst *rqstp, long timeout) "svc_recv: service %p, wait queue active!\n", rqstp); - /* Initialize the buffers */ - /* first reclaim pages that were moved to response list */ - svc_pushback_allpages(rqstp); /* now allocate needed pages. If we get a failure, sleep briefly */ pages = 2 + (serv->sv_bufsz + PAGE_SIZE -1) / PAGE_SIZE; - while (rqstp->rq_arghi < pages) { - struct page *p = alloc_page(GFP_KERNEL); - if (!p) { - schedule_timeout_uninterruptible(msecs_to_jiffies(500)); - continue; + for (i=0; i < pages ; i++) + while (rqstp->rq_pages[i] == NULL) { + struct page *p = alloc_page(GFP_KERNEL); + if (!p) + schedule_timeout_uninterruptible(msecs_to_jiffies(500)); + rqstp->rq_pages[i] = p; } - rqstp->rq_argpages[rqstp->rq_arghi++] = p; - } /* Make arg->head point to first page and arg->pages point to rest */ arg = &rqstp->rq_arg; - arg->head[0].iov_base = page_address(rqstp->rq_argpages[0]); + arg->head[0].iov_base = page_address(rqstp->rq_pages[0]); arg->head[0].iov_len = PAGE_SIZE; - rqstp->rq_argused = 1; - arg->pages = rqstp->rq_argpages + 1; + arg->pages = rqstp->rq_pages + 1; arg->page_base = 0; /* save at least one page for response */ arg->page_len = (pages-2)*PAGE_SIZE; @@ -1704,6 +1704,7 @@ static int svc_deferred_recv(struct svc_rqst *rqstp) rqstp->rq_prot = dr->prot; rqstp->rq_addr = dr->addr; rqstp->rq_daddr = dr->daddr; + rqstp->rq_respages = rqstp->rq_pages; return dr->argslen<<2; } -- cgit v1.2.3 From 3cc03b164cf01c6f36e64720b58610d292fb26f7 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:15:47 -0700 Subject: [PATCH] knfsd: Avoid excess stack usage in svc_tcp_recvfrom .. by allocating the array of 'kvec' in 'struct svc_rqst'. As we plan to increase RPCSVC_MAXPAGES from 8 upto 256, we can no longer allocate an array of this size on the stack. So we allocate it in 'struct svc_rqst'. However svc_rqst contains (indirectly) an array of the same type and size (actually several, but they are in a union). So rather than waste space, we move those arrays out of the separately allocated union and into svc_rqst to share with the kvec moved out of svc_tcp_recvfrom (various arrays are used at different times, so there is no conflict). Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs3proc.c | 4 ++-- fs/nfsd/nfs3xdr.c | 22 +++++++++++----------- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfs4xdr.c | 26 +++++++++++++------------- fs/nfsd/nfsproc.c | 4 ++-- fs/nfsd/nfsxdr.c | 22 +++++++++++----------- include/linux/nfsd/xdr.h | 2 -- include/linux/nfsd/xdr3.h | 2 -- include/linux/nfsd/xdr4.h | 2 -- include/linux/sunrpc/svc.h | 2 ++ net/sunrpc/svcsock.c | 3 ++- 11 files changed, 44 insertions(+), 47 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index f61142afea44..0c4fab018791 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -180,7 +180,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_read(rqstp, &resp->fh, NULL, argp->offset, - argp->vec, argp->vlen, + rqstp->rq_vec, argp->vlen, &resp->count); if (nfserr == 0) { struct inode *inode = resp->fh.fh_dentry->d_inode; @@ -210,7 +210,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, resp->committed = argp->stable; nfserr = nfsd_write(rqstp, &resp->fh, NULL, argp->offset, - argp->vec, argp->vlen, + rqstp->rq_vec, argp->vlen, argp->len, &resp->committed); resp->count = argp->count; diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 20ba728a4642..4b9aefbcc93c 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -344,9 +344,9 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, v=0; while (len > 0) { pn = rqstp->rq_resused++; - args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]); - args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE; - len -= args->vec[v].iov_len; + rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]); + rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE; + len -= rqstp->rq_vec[v].iov_len; v++; } args->vlen = v; @@ -372,22 +372,22 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, rqstp->rq_arg.len - hdr < len) return 0; - args->vec[0].iov_base = (void*)p; - args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; + rqstp->rq_vec[0].iov_base = (void*)p; + rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; if (len > NFSSVC_MAXBLKSIZE) len = NFSSVC_MAXBLKSIZE; v= 0; - while (len > args->vec[v].iov_len) { - len -= args->vec[v].iov_len; + while (len > rqstp->rq_vec[v].iov_len) { + len -= rqstp->rq_vec[v].iov_len; v++; - args->vec[v].iov_base = page_address(rqstp->rq_pages[v]); - args->vec[v].iov_len = PAGE_SIZE; + rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]); + rqstp->rq_vec[v].iov_len = PAGE_SIZE; } - args->vec[v].iov_len = len; + rqstp->rq_vec[v].iov_len = len; args->vlen = v+1; - return args->count == args->len && args->vec[0].iov_len > 0; + return args->count == args->len && rqstp->rq_vec[0].iov_len > 0; } int diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 15ded7a30a72..38b0f91175d0 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -646,7 +646,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ *p++ = nfssvc_boot.tv_usec; status = nfsd_write(rqstp, current_fh, filp, write->wr_offset, - write->wr_vec, write->wr_vlen, write->wr_buflen, + rqstp->rq_vec, write->wr_vlen, write->wr_buflen, &write->wr_how_written); if (filp) fput(filp); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 9f30c53ac0ed..df341956254e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -926,26 +926,26 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); goto xdr_error; } - write->wr_vec[0].iov_base = p; - write->wr_vec[0].iov_len = avail; + argp->rqstp->rq_vec[0].iov_base = p; + argp->rqstp->rq_vec[0].iov_len = avail; v = 0; len = write->wr_buflen; - while (len > write->wr_vec[v].iov_len) { - len -= write->wr_vec[v].iov_len; + while (len > argp->rqstp->rq_vec[v].iov_len) { + len -= argp->rqstp->rq_vec[v].iov_len; v++; - write->wr_vec[v].iov_base = page_address(argp->pagelist[0]); + argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]); argp->pagelist++; if (argp->pagelen >= PAGE_SIZE) { - write->wr_vec[v].iov_len = PAGE_SIZE; + argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE; argp->pagelen -= PAGE_SIZE; } else { - write->wr_vec[v].iov_len = argp->pagelen; + argp->rqstp->rq_vec[v].iov_len = argp->pagelen; argp->pagelen -= len; } } - argp->end = (u32*) (write->wr_vec[v].iov_base + write->wr_vec[v].iov_len); - argp->p = (u32*) (write->wr_vec[v].iov_base + (XDR_QUADLEN(len) << 2)); - write->wr_vec[v].iov_len = len; + argp->end = (u32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len); + argp->p = (u32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2)); + argp->rqstp->rq_vec[v].iov_len = len; write->wr_vlen = v+1; DECODE_TAIL; @@ -2063,9 +2063,9 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, v = 0; while (len > 0) { pn = resp->rqstp->rq_resused++; - read->rd_iov[v].iov_base = + resp->rqstp->rq_vec[v].iov_base = page_address(resp->rqstp->rq_respages[pn]); - read->rd_iov[v].iov_len = + resp->rqstp->rq_vec[v].iov_len = len < PAGE_SIZE ? len : PAGE_SIZE; v++; len -= PAGE_SIZE; @@ -2073,7 +2073,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, read->rd_vlen = v; nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp, - read->rd_offset, read->rd_iov, read->rd_vlen, + read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, &maxcount); if (nfserr == nfserr_symlink) diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 4e06810b6104..ca4973150218 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -159,7 +159,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, resp->count = argp->count; nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, argp->offset, - argp->vec, argp->vlen, + rqstp->rq_vec, argp->vlen, &resp->count); if (nfserr) return nfserr; @@ -185,7 +185,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp, nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, argp->offset, - argp->vec, argp->vlen, + rqstp->rq_vec, argp->vlen, argp->len, &stable); return nfsd_return_attrs(nfserr, resp); diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index ad2fba3c54f8..ab6745e78d16 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -263,9 +263,9 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p, v=0; while (len > 0) { pn = rqstp->rq_resused++; - args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]); - args->vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE; - len -= args->vec[v].iov_len; + rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]); + rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE; + len -= rqstp->rq_vec[v].iov_len; v++; } args->vlen = v; @@ -285,21 +285,21 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, args->offset = ntohl(*p++); /* offset */ p++; /* totalcount */ len = args->len = ntohl(*p++); - args->vec[0].iov_base = (void*)p; - args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - + rqstp->rq_vec[0].iov_base = (void*)p; + rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - (((void*)p) - rqstp->rq_arg.head[0].iov_base); if (len > NFSSVC_MAXBLKSIZE) len = NFSSVC_MAXBLKSIZE; v = 0; - while (len > args->vec[v].iov_len) { - len -= args->vec[v].iov_len; + while (len > rqstp->rq_vec[v].iov_len) { + len -= rqstp->rq_vec[v].iov_len; v++; - args->vec[v].iov_base = page_address(rqstp->rq_pages[v]); - args->vec[v].iov_len = PAGE_SIZE; + rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]); + rqstp->rq_vec[v].iov_len = PAGE_SIZE; } - args->vec[v].iov_len = len; + rqstp->rq_vec[v].iov_len = len; args->vlen = v+1; - return args->vec[0].iov_len > 0; + return rqstp->rq_vec[0].iov_len > 0; } int diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h index a38f9d776de9..0e53de87d886 100644 --- a/include/linux/nfsd/xdr.h +++ b/include/linux/nfsd/xdr.h @@ -30,7 +30,6 @@ struct nfsd_readargs { struct svc_fh fh; __u32 offset; __u32 count; - struct kvec vec[RPCSVC_MAXPAGES]; int vlen; }; @@ -38,7 +37,6 @@ struct nfsd_writeargs { svc_fh fh; __u32 offset; int len; - struct kvec vec[RPCSVC_MAXPAGES]; int vlen; }; diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h index a4322741f8b9..474d882dc2f3 100644 --- a/include/linux/nfsd/xdr3.h +++ b/include/linux/nfsd/xdr3.h @@ -33,7 +33,6 @@ struct nfsd3_readargs { struct svc_fh fh; __u64 offset; __u32 count; - struct kvec vec[RPCSVC_MAXPAGES]; int vlen; }; @@ -43,7 +42,6 @@ struct nfsd3_writeargs { __u32 count; int stable; __u32 len; - struct kvec vec[RPCSVC_MAXPAGES]; int vlen; }; diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index 77adba7d2281..66e642762a07 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -241,7 +241,6 @@ struct nfsd4_read { stateid_t rd_stateid; /* request */ u64 rd_offset; /* request */ u32 rd_length; /* request */ - struct kvec rd_iov[RPCSVC_MAXPAGES]; int rd_vlen; struct file *rd_filp; @@ -326,7 +325,6 @@ struct nfsd4_write { u64 wr_offset; /* request */ u32 wr_stable_how; /* request */ u32 wr_buflen; /* request */ - struct kvec wr_vec[RPCSVC_MAXPAGES]; /* request */ int wr_vlen; u32 wr_bytes_written; /* response */ diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 3669e91c43b8..cb0ed9beb227 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -192,6 +192,8 @@ struct svc_rqst { struct page * *rq_respages; /* points into rq_pages */ int rq_resused; /* number of pages used for result */ + struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */ + __be32 rq_xid; /* transmission id */ u32 rq_prog; /* program number */ u32 rq_vers; /* program version */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 25096d53667a..1d512337ccd9 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -955,7 +955,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp) struct svc_sock *svsk = rqstp->rq_sock; struct svc_serv *serv = svsk->sk_server; int len; - struct kvec vec[RPCSVC_MAXPAGES]; + struct kvec *vec; int pnum, vlen; dprintk("svc: tcp_recv %p data %d conn %d close %d\n", @@ -1053,6 +1053,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp) len = svsk->sk_reclen; set_bit(SK_DATA, &svsk->sk_flags); + vec = rqstp->rq_vec; vec[0] = rqstp->rq_arg.head[0]; vlen = PAGE_SIZE; pnum = 1; -- cgit v1.2.3 From 7adae489fe794e3e203ff168595f635d0b845e59 Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Wed, 4 Oct 2006 02:15:47 -0700 Subject: [PATCH] knfsd: Prepare knfsd for support of rsize/wsize of up to 1MB, over TCP The limit over UDP remains at 32K. Also, make some of the apparently arbitrary sizing constants clearer. The biggest change here involves replacing NFSSVC_MAXBLKSIZE by a function of the rqstp. This allows it to be different for different protocols (udp/tcp) and also allows it to depend on the servers declared sv_bufsiz. Note that we don't actually increase sv_bufsz for nfs yet. That comes next. Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs3proc.c | 14 ++++++++------ fs/nfsd/nfs3xdr.c | 13 ++++++++----- fs/nfsd/nfs4xdr.c | 6 +++--- fs/nfsd/nfsproc.c | 6 +++--- fs/nfsd/nfsxdr.c | 10 +++++----- include/linux/nfsd/const.h | 15 ++++++++++++++- include/linux/sunrpc/auth.h | 3 --- include/linux/sunrpc/msg_prot.h | 40 ++++++++++++++++++++++++++++++++++++++++ include/linux/sunrpc/svc.h | 23 ++++++++++++++++++++++- include/linux/sunrpc/xprt.h | 8 +------- net/sunrpc/svc.c | 15 +++++++++++++++ 11 files changed, 119 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 0c4fab018791..a5ebc7dbb384 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -160,6 +160,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, struct nfsd3_readres *resp) { int nfserr; + u32 max_blocksize = svc_max_payload(rqstp); dprintk("nfsd: READ(3) %s %lu bytes at %lu\n", SVCFH_fmt(&argp->fh), @@ -172,8 +173,8 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, */ resp->count = argp->count; - if (NFSSVC_MAXBLKSIZE < resp->count) - resp->count = NFSSVC_MAXBLKSIZE; + if (max_blocksize < resp->count) + resp->count = max_blocksize; svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); @@ -538,15 +539,16 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd3_fsinfores *resp) { int nfserr; + u32 max_blocksize = svc_max_payload(rqstp); dprintk("nfsd: FSINFO(3) %s\n", SVCFH_fmt(&argp->fh)); - resp->f_rtmax = NFSSVC_MAXBLKSIZE; - resp->f_rtpref = NFSSVC_MAXBLKSIZE; + resp->f_rtmax = max_blocksize; + resp->f_rtpref = max_blocksize; resp->f_rtmult = PAGE_SIZE; - resp->f_wtmax = NFSSVC_MAXBLKSIZE; - resp->f_wtpref = NFSSVC_MAXBLKSIZE; + resp->f_wtmax = max_blocksize; + resp->f_wtpref = max_blocksize; resp->f_wtmult = PAGE_SIZE; resp->f_dtpref = PAGE_SIZE; resp->f_maxfilesize = ~(u32) 0; diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 4b9aefbcc93c..247d518248bf 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -330,6 +330,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, { unsigned int len; int v,pn; + u32 max_blocksize = svc_max_payload(rqstp); if (!(p = decode_fh(p, &args->fh)) || !(p = xdr_decode_hyper(p, &args->offset))) @@ -337,8 +338,8 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, len = args->count = ntohl(*p++); - if (len > NFSSVC_MAXBLKSIZE) - len = NFSSVC_MAXBLKSIZE; + if (len > max_blocksize) + len = max_blocksize; /* set up the kvec */ v=0; @@ -358,6 +359,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_writeargs *args) { unsigned int len, v, hdr; + u32 max_blocksize = svc_max_payload(rqstp); if (!(p = decode_fh(p, &args->fh)) || !(p = xdr_decode_hyper(p, &args->offset))) @@ -375,8 +377,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, rqstp->rq_vec[0].iov_base = (void*)p; rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; - if (len > NFSSVC_MAXBLKSIZE) - len = NFSSVC_MAXBLKSIZE; + if (len > max_blocksize) + len = max_blocksize; v= 0; while (len > rqstp->rq_vec[v].iov_len) { len -= rqstp->rq_vec[v].iov_len; @@ -564,6 +566,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_readdirargs *args) { int len, pn; + u32 max_blocksize = svc_max_payload(rqstp); if (!(p = decode_fh(p, &args->fh))) return 0; @@ -572,7 +575,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p, args->dircount = ntohl(*p++); args->count = ntohl(*p++); - len = (args->count > NFSSVC_MAXBLKSIZE) ? NFSSVC_MAXBLKSIZE : + len = (args->count > max_blocksize) ? max_blocksize : args->count; args->count = len; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index df341956254e..4cfacc557b40 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1536,12 +1536,12 @@ out_acl: if (bmval0 & FATTR4_WORD0_MAXREAD) { if ((buflen -= 8) < 0) goto out_resource; - WRITE64((u64) NFSSVC_MAXBLKSIZE); + WRITE64((u64) svc_max_payload(rqstp)); } if (bmval0 & FATTR4_WORD0_MAXWRITE) { if ((buflen -= 8) < 0) goto out_resource; - WRITE64((u64) NFSSVC_MAXBLKSIZE); + WRITE64((u64) svc_max_payload(rqstp)); } if (bmval1 & FATTR4_WORD1_MODE) { if ((buflen -= 4) < 0) @@ -2055,7 +2055,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, RESERVE_SPACE(8); /* eof flag and byte count */ - maxcount = NFSSVC_MAXBLKSIZE; + maxcount = svc_max_payload(resp->rqstp); if (maxcount > read->rd_length) maxcount = read->rd_length; diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index ca4973150218..9ee1dab5d44a 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -146,13 +146,13 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, * status, 17 words for fattr, and 1 word for the byte count. */ - if (NFSSVC_MAXBLKSIZE < argp->count) { + if (NFSSVC_MAXBLKSIZE_V2 < argp->count) { printk(KERN_NOTICE "oversized read request from %u.%u.%u.%u:%d (%d bytes)\n", NIPQUAD(rqstp->rq_addr.sin_addr.s_addr), ntohs(rqstp->rq_addr.sin_port), argp->count); - argp->count = NFSSVC_MAXBLKSIZE; + argp->count = NFSSVC_MAXBLKSIZE_V2; } svc_reserve(rqstp, (19<<2) + argp->count + 4); @@ -553,7 +553,7 @@ static struct svc_procedure nfsd_procedures2[18] = { PROC(none, void, void, none, RC_NOCACHE, ST), PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT), PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4), - PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE/4), + PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4), PROC(none, void, void, none, RC_NOCACHE, ST), PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index ab6745e78d16..1135c0d14557 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -254,8 +254,8 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p, len = args->count = ntohl(*p++); p++; /* totalcount - unused */ - if (len > NFSSVC_MAXBLKSIZE) - len = NFSSVC_MAXBLKSIZE; + if (len > NFSSVC_MAXBLKSIZE_V2) + len = NFSSVC_MAXBLKSIZE_V2; /* set up somewhere to store response. * We take pages, put them on reslist and include in iovec @@ -288,8 +288,8 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, rqstp->rq_vec[0].iov_base = (void*)p; rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - (((void*)p) - rqstp->rq_arg.head[0].iov_base); - if (len > NFSSVC_MAXBLKSIZE) - len = NFSSVC_MAXBLKSIZE; + if (len > NFSSVC_MAXBLKSIZE_V2) + len = NFSSVC_MAXBLKSIZE_V2; v = 0; while (len > rqstp->rq_vec[v].iov_len) { len -= rqstp->rq_vec[v].iov_len; @@ -458,7 +458,7 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p, { struct kstatfs *stat = &resp->stats; - *p++ = htonl(NFSSVC_MAXBLKSIZE); /* max transfer size */ + *p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */ *p++ = htonl(stat->f_bsize); *p++ = htonl(stat->f_blocks); *p++ = htonl(stat->f_bfree); diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h index b75bb1b38d09..adbddf007898 100644 --- a/include/linux/nfsd/const.h +++ b/include/linux/nfsd/const.h @@ -13,6 +13,7 @@ #include #include #include +#include /* * Maximum protocol version supported by knfsd @@ -23,6 +24,8 @@ * Maximum blocksize supported by daemon currently at 32K */ #define NFSSVC_MAXBLKSIZE (32*1024) +/* NFSv2 is limited by the protocol specification, see RFC 1094 */ +#define NFSSVC_MAXBLKSIZE_V2 (8*1024) #ifdef __KERNEL__ @@ -30,7 +33,17 @@ # define NFS_SUPER_MAGIC 0x6969 #endif -#define NFSD_BUFSIZE (1024 + NFSSVC_MAXBLKSIZE) +/* + * Largest number of bytes we need to allocate for an NFS + * call or reply. Used to control buffer sizes. We use + * the length of v3 WRITE, READDIR and READDIR replies + * which are an RPC header, up to 26 XDR units of reply + * data, and some page data. + * + * Note that accuracy here doesn't matter too much as the + * size is rounded up to a page size when allocating space. + */ +#define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE) #ifdef CONFIG_NFSD_V4 # define NFSSVC_XDRSIZE NFS4_SVC_XDRSIZE diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 862c0d8c8381..534cdc7be58d 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -20,9 +20,6 @@ /* size of the nodename buffer */ #define UNX_MAXNODENAME 32 -/* Maximum size (in bytes) of an rpc credential or verifier */ -#define RPC_MAX_AUTH_SIZE (400) - /* Work around the lack of a VFS credential */ struct auth_cred { uid_t uid; diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h index 8d10d148834e..1e65f2dd80e5 100644 --- a/include/linux/sunrpc/msg_prot.h +++ b/include/linux/sunrpc/msg_prot.h @@ -11,6 +11,9 @@ #define RPC_VERSION 2 +/* size of an XDR encoding unit in bytes, i.e. 32bit */ +#define XDR_UNIT (4) + /* spec defines authentication flavor as an unsigned 32 bit integer */ typedef u32 rpc_authflavor_t; @@ -34,6 +37,9 @@ enum rpc_auth_flavors { RPC_AUTH_GSS_SPKMP = 390011, }; +/* Maximum size (in bytes) of an rpc credential or verifier */ +#define RPC_MAX_AUTH_SIZE (400) + enum rpc_msg_type { RPC_CALL = 0, RPC_REPLY = 1 @@ -101,5 +107,39 @@ typedef __be32 rpc_fraghdr; #define RPC_FRAGMENT_SIZE_MASK (~RPC_LAST_STREAM_FRAGMENT) #define RPC_MAX_FRAGMENT_SIZE ((1U << 31) - 1) +/* + * RPC call and reply header size as number of 32bit words (verifier + * size computed separately, see below) + */ +#define RPC_CALLHDRSIZE (6) +#define RPC_REPHDRSIZE (4) + + +/* + * Maximum RPC header size, including authentication, + * as number of 32bit words (see RFCs 1831, 1832). + * + * xid 1 xdr unit = 4 bytes + * mtype 1 + * rpc_version 1 + * program 1 + * prog_version 1 + * procedure 1 + * cred { + * flavor 1 + * length 1 + * body 100 xdr units = 400 bytes + * } + * verf { + * flavor 1 + * length 1 + * body 100 xdr units = 400 bytes + * } + * TOTAL 210 xdr units = 840 bytes + */ +#define RPC_MAX_HEADER_WITH_AUTH \ + (RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4)) + + #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_MSGPROT_H_ */ diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index cb0ed9beb227..74e52c245da4 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -95,8 +96,28 @@ static inline void svc_get(struct svc_serv *serv) * Maximum payload size supported by a kernel RPC server. * This is use to determine the max number of pages nfsd is * willing to return in a single READ operation. + * + * These happen to all be powers of 2, which is not strictly + * necessary but helps enforce the real limitation, which is + * that they should be multiples of PAGE_CACHE_SIZE. + * + * For UDP transports, a block plus NFS,RPC, and UDP headers + * has to fit into the IP datagram limit of 64K. The largest + * feasible number for all known page sizes is probably 48K, + * but we choose 32K here. This is the same as the historical + * Linux limit; someone who cares more about NFS/UDP performance + * can test a larger number. + * + * For TCP transports we have more freedom. A size of 1MB is + * chosen to match the client limit. Other OSes are known to + * have larger limits, but those numbers are probably beyond + * the point of diminishing returns. */ -#define RPCSVC_MAXPAYLOAD (64*1024u) +#define RPCSVC_MAXPAYLOAD (1*1024*1024u) +#define RPCSVC_MAXPAYLOAD_TCP RPCSVC_MAXPAYLOAD +#define RPCSVC_MAXPAYLOAD_UDP (32*1024u) + +extern u32 svc_max_payload(const struct svc_rqst *rqstp); /* * RPC Requsts and replies are stored in one or more pages. diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 6cf626580752..60394fbc4c70 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -15,6 +15,7 @@ #include #include #include +#include extern unsigned int xprt_udp_slot_table_entries; extern unsigned int xprt_tcp_slot_table_entries; @@ -23,13 +24,6 @@ extern unsigned int xprt_tcp_slot_table_entries; #define RPC_DEF_SLOT_TABLE (16U) #define RPC_MAX_SLOT_TABLE (128U) -/* - * RPC call and reply header size as number of 32bit words (verifier - * size computed separately) - */ -#define RPC_CALLHDRSIZE 6 -#define RPC_REPHDRSIZE 4 - /* * Parameters for choosing a free port */ diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index f4a509a925b5..b252401c8601 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -919,3 +919,18 @@ err_bad: svc_putnl(resv, ntohl(rpc_stat)); goto sendit; } + +/* + * Return (transport-specific) limit on the rpc payload. + */ +u32 svc_max_payload(const struct svc_rqst *rqstp) +{ + int max = RPCSVC_MAXPAYLOAD_TCP; + + if (rqstp->rq_sock->sk_sock->type == SOCK_DGRAM) + max = RPCSVC_MAXPAYLOAD_UDP; + if (rqstp->rq_server->sv_bufsz < max) + max = rqstp->rq_server->sv_bufsz; + return max; +} +EXPORT_SYMBOL_GPL(svc_max_payload); -- cgit v1.2.3 From 596bbe53eb3abfe7326b2f5e8afd614265c319c8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:15:48 -0700 Subject: [PATCH] knfsd: Allow max size of NFSd payload to be configured The max possible is the maximum RPC payload. The default depends on amount of total memory. The value can be set within reason as long as no nfsd threads are currently running. The value can also be ready, allowing the default to be determined after nfsd has started. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsctl.c | 33 +++++++++++++++++++++++++++++++++ fs/nfsd/nfssvc.c | 19 ++++++++++++++++++- include/linux/nfsd/const.h | 4 ++-- include/linux/nfsd/nfsd.h | 1 + 4 files changed, 54 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 6c2ddfed2cfc..39aed901514b 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -57,6 +57,7 @@ enum { NFSD_Pool_Threads, NFSD_Versions, NFSD_Ports, + NFSD_MaxBlkSize, /* * The below MUST come last. Otherwise we leave a hole in nfsd_files[] * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops @@ -82,6 +83,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size); static ssize_t write_pool_threads(struct file *file, char *buf, size_t size); static ssize_t write_versions(struct file *file, char *buf, size_t size); static ssize_t write_ports(struct file *file, char *buf, size_t size); +static ssize_t write_maxblksize(struct file *file, char *buf, size_t size); #ifdef CONFIG_NFSD_V4 static ssize_t write_leasetime(struct file *file, char *buf, size_t size); static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); @@ -100,6 +102,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { [NFSD_Pool_Threads] = write_pool_threads, [NFSD_Versions] = write_versions, [NFSD_Ports] = write_ports, + [NFSD_MaxBlkSize] = write_maxblksize, #ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = write_leasetime, [NFSD_RecoveryDir] = write_recoverydir, @@ -555,6 +558,35 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) return -EINVAL; } +int nfsd_max_blksize; + +static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) +{ + char *mesg = buf; + if (size > 0) { + int bsize; + int rv = get_int(&mesg, &bsize); + if (rv) + return rv; + /* force bsize into allowed range and + * required alignment. + */ + if (bsize < 1024) + bsize = 1024; + if (bsize > NFSSVC_MAXBLKSIZE) + bsize = NFSSVC_MAXBLKSIZE; + bsize &= ~(1024-1); + lock_kernel(); + if (nfsd_serv && nfsd_serv->sv_nrthreads) { + unlock_kernel(); + return -EBUSY; + } + nfsd_max_blksize = bsize; + unlock_kernel(); + } + return sprintf(buf, "%d\n", nfsd_max_blksize); +} + #ifdef CONFIG_NFSD_V4 extern time_t nfs4_leasetime(void); @@ -620,6 +652,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, + [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO}, #ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 19443056ec30..0603baad5426 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -198,9 +198,26 @@ int nfsd_create_serv(void) unlock_kernel(); return 0; } + if (nfsd_max_blksize == 0) { + /* choose a suitable default */ + struct sysinfo i; + si_meminfo(&i); + /* Aim for 1/4096 of memory per thread + * This gives 1MB on 4Gig machines + * But only uses 32K on 128M machines. + * Bottom out at 8K on 32M and smaller. + * Of course, this is only a default. + */ + nfsd_max_blksize = NFSSVC_MAXBLKSIZE; + i.totalram >>= 12; + while (nfsd_max_blksize > i.totalram && + nfsd_max_blksize >= 8*1024*2) + nfsd_max_blksize /= 2; + } atomic_set(&nfsd_busy, 0); - nfsd_serv = svc_create_pooled(&nfsd_program, NFSD_BUFSIZE, + nfsd_serv = svc_create_pooled(&nfsd_program, + NFSD_BUFSIZE - NFSSVC_MAXBLKSIZE + nfsd_max_blksize, nfsd_last_thread, nfsd, SIG_NOCLEAN, THIS_MODULE); if (nfsd_serv == NULL) diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h index adbddf007898..f478066f9cd5 100644 --- a/include/linux/nfsd/const.h +++ b/include/linux/nfsd/const.h @@ -21,9 +21,9 @@ #define NFSSVC_MAXVERS 3 /* - * Maximum blocksize supported by daemon currently at 32K + * Maximum blocksizes supported by daemon under various circumstances. */ -#define NFSSVC_MAXBLKSIZE (32*1024) +#define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD /* NFSv2 is limited by the protocol specification, see RFC 1094 */ #define NFSSVC_MAXBLKSIZE_V2 (8*1024) diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index e1dbc86c270b..259841bb2f6c 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -145,6 +145,7 @@ int nfsd_vers(int vers, enum vers_op change); void nfsd_reset_versions(void); int nfsd_create_serv(void); +extern int nfsd_max_blksize; /* * NFSv4 State -- cgit v1.2.3 From 7b2b1fee30df7e2165525cd03f7d1d01a3a56794 Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Wed, 4 Oct 2006 02:15:50 -0700 Subject: [PATCH] knfsd: knfsd: cache ipmap per TCP socket Speed up high call-rate workloads by caching the struct ip_map for the peer on the connected struct svc_sock instead of looking it up in the ip_map cache hashtable on every call. This helps workloads using AUTH_SYS authentication over TCP. Testing was on a 4 CPU 4 NIC Altix using 4 IRIX clients, each with 16 synthetic client threads simulating an rsync (i.e. recursive directory listing) workload reading from an i386 RH9 install image (161480 regular files in 10841 directories) on the server. That tree is small enough to fill in the server's RAM so no disk traffic was involved. This setup gives a sustained call rate in excess of 60000 calls/sec before being CPU-bound on the server. Profiling showed strcmp(), called from ip_map_match(), was taking 4.8% of each CPU, and ip_map_lookup() was taking 2.9%. This patch drops both contribution into the profile noise. Note that the above result overstates this value of this patch for most workloads. The synthetic clients are all using separate IP addresses, so there are 64 entries in the ip_map cache hash. Because the kernel measured contained the bug fixed in commit commit 1f1e030bf75774b6a283518e1534d598e14147d4 and was running on 64bit little-endian machine, probably all of those 64 entries were on a single chain, thus increasing the cost of ip_map_lookup(). With a modern kernel you would need more clients to see the same amount of performance improvement. This patch has helped to scale knfsd to handle a deployment with 2000 NFS clients. Signed-off-by: Greg Banks Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/cache.h | 11 ++++++++++ include/linux/sunrpc/svcauth.h | 1 + include/linux/sunrpc/svcsock.h | 3 +++ net/sunrpc/svcauth_unix.c | 47 +++++++++++++++++++++++++++++++++++++++--- net/sunrpc/svcsock.c | 2 ++ 5 files changed, 61 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index b5612c958cce..3699dff7db8f 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -163,6 +163,17 @@ static inline void cache_put(struct cache_head *h, struct cache_detail *cd) kref_put(&h->ref, cd->cache_put); } +static inline int cache_valid(struct cache_head *h) +{ + /* If an item has been unhashed pending removal when + * the refcount drops to 0, the expiry_time will be + * set to 0. We don't want to consider such items + * valid in this context even though CACHE_VALID is + * set. + */ + return (h->expiry_time != 0 && test_bit(CACHE_VALID, &h->flags)); +} + extern int cache_check(struct cache_detail *detail, struct cache_head *h, struct cache_req *rqstp); extern void cache_flush(void); diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index a6601650deeb..de92619b0826 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h @@ -126,6 +126,7 @@ extern struct auth_domain *auth_domain_find(char *name); extern struct auth_domain *auth_unix_lookup(struct in_addr addr); extern int auth_unix_forget_old(struct auth_domain *dom); extern void svcauth_unix_purge(void); +extern void svcauth_unix_info_release(void *); static inline unsigned long hash_str(char *name, int bits) { diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 4c296152cbfa..98b21ad370fd 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -54,6 +54,9 @@ struct svc_sock { int sk_reclen; /* length of record */ int sk_tcplen; /* current read length */ time_t sk_lastrecv; /* time of last received request */ + + /* cache of various info for TCP sockets */ + void *sk_info_authunix; }; /* diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 40d41a2831d7..e1bd933629fe 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -9,6 +9,7 @@ #include #include #include +#include #define RPCDBG_FACILITY RPCDBG_AUTH @@ -375,6 +376,44 @@ void svcauth_unix_purge(void) cache_purge(&ip_map_cache); } +static inline struct ip_map * +ip_map_cached_get(struct svc_rqst *rqstp) +{ + struct ip_map *ipm = rqstp->rq_sock->sk_info_authunix; + if (ipm != NULL) { + if (!cache_valid(&ipm->h)) { + /* + * The entry has been invalidated since it was + * remembered, e.g. by a second mount from the + * same IP address. + */ + rqstp->rq_sock->sk_info_authunix = NULL; + cache_put(&ipm->h, &ip_map_cache); + return NULL; + } + cache_get(&ipm->h); + } + return ipm; +} + +static inline void +ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm) +{ + struct svc_sock *svsk = rqstp->rq_sock; + + if (svsk->sk_sock->type == SOCK_STREAM && svsk->sk_info_authunix == NULL) + svsk->sk_info_authunix = ipm; /* newly cached, keep the reference */ + else + cache_put(&ipm->h, &ip_map_cache); +} + +void +svcauth_unix_info_release(void *info) +{ + struct ip_map *ipm = info; + cache_put(&ipm->h, &ip_map_cache); +} + static int svcauth_unix_set_client(struct svc_rqst *rqstp) { @@ -384,8 +423,10 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) if (rqstp->rq_proc == 0) return SVC_OK; - ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, - rqstp->rq_addr.sin_addr); + ipm = ip_map_cached_get(rqstp); + if (ipm == NULL) + ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, + rqstp->rq_addr.sin_addr); if (ipm == NULL) return SVC_DENIED; @@ -400,7 +441,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) case 0: rqstp->rq_client = &ipm->m_client->h; kref_get(&rqstp->rq_client->ref); - cache_put(&ipm->h, &ip_map_cache); + ip_map_cached_put(rqstp, ipm); break; } return SVC_OK; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 1d512337ccd9..b39e7e2b648f 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1610,6 +1610,8 @@ svc_delete_socket(struct svc_sock *svsk) sockfd_put(svsk->sk_sock); else sock_release(svsk->sk_sock); + if (svsk->sk_info_authunix != NULL) + svcauth_unix_info_release(svsk->sk_info_authunix); kfree(svsk); } else { spin_unlock_bh(&serv->sv_lock); -- cgit v1.2.3 From cf712c24d72341effcfd28330b83b49f77cb627b Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:52 -0700 Subject: [PATCH] knfsd: consolidate common code for statd->lockd notification Common code from nlm4svc_proc_sm_notify and nlmsvc_proc_sm_notify is moved into a new nlm_host_rebooted. This is in preparation of a patch that will change the reboot notification handling entirely. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/host.c | 30 ++++++++++++++++++++++++++++-- fs/lockd/svc4proc.c | 19 ++----------------- fs/lockd/svcproc.c | 17 ++--------------- include/linux/lockd/lockd.h | 5 +++-- 4 files changed, 35 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 637ec9567066..bcc21b05808a 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -39,7 +39,7 @@ static void nlm_gc_hosts(void); * Find an NLM server handle in the cache. If there is none, create it. */ struct nlm_host * -nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version) +nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version) { return nlm_lookup_host(0, sin, proto, version); } @@ -58,7 +58,7 @@ nlmsvc_lookup_host(struct svc_rqst *rqstp) * Common host lookup routine for server & client */ struct nlm_host * -nlm_lookup_host(int server, struct sockaddr_in *sin, +nlm_lookup_host(int server, const struct sockaddr_in *sin, int proto, int version) { struct nlm_host *host, **hp; @@ -259,6 +259,32 @@ void nlm_release_host(struct nlm_host *host) } } +/* + * We were notified that the host indicated by address &sin + * has rebooted. + * Release all resources held by that peer. + */ +void nlm_host_rebooted(const struct sockaddr_in *sin, const struct nlm_reboot *argp) +{ + struct nlm_host *host; + + /* Obtain the host pointer for this NFS server and try to + * reclaim all locks we hold on this server. + */ + if ((argp->proto & 1)==0) { + /* We are client, he's the server: try to reclaim all locks. */ + if ((host = nlmclnt_lookup_host(sin, argp->proto >> 1, argp->vers)) == NULL) + return; + nlmclnt_recovery(host, argp->state); + } else { + /* He's the client, we're the server: delete all locks held by the client */ + if ((host = nlm_lookup_host(1, sin, argp->proto >> 1, argp->vers)) == NULL) + return; + nlmsvc_free_host_resources(host); + } + nlm_release_host(host); +} + /* * Shut down the hosts module. * Note that this routine is called only at server shutdown time. diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index b5aceb83f8cb..97bd36c09a5b 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -420,10 +420,6 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, void *resp) { struct sockaddr_in saddr = rqstp->rq_addr; - int vers = argp->vers; - int prot = argp->proto >> 1; - - struct nlm_host *host; dprintk("lockd: SM_NOTIFY called\n"); if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) @@ -438,21 +434,10 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, /* Obtain the host pointer for this NFS server and try to * reclaim all locks we hold on this server. */ + memset(&saddr, 0, sizeof(saddr)); saddr.sin_addr.s_addr = argp->addr; + nlm_host_rebooted(&saddr, argp); - if ((argp->proto & 1)==0) { - if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) { - nlmclnt_recovery(host, argp->state); - nlm_release_host(host); - } - } else { - /* If we run on an NFS server, delete all locks held by the client */ - - if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) { - nlmsvc_free_host_resources(host); - nlm_release_host(host); - } - } return rpc_success; } diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index dbc4ea2638c9..452eb5e5ea44 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -449,9 +449,6 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, void *resp) { struct sockaddr_in saddr = rqstp->rq_addr; - int vers = argp->vers; - int prot = argp->proto >> 1; - struct nlm_host *host; dprintk("lockd: SM_NOTIFY called\n"); if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) @@ -466,19 +463,9 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, /* Obtain the host pointer for this NFS server and try to * reclaim all locks we hold on this server. */ + memset(&saddr, 0, sizeof(saddr)); saddr.sin_addr.s_addr = argp->addr; - if ((argp->proto & 1)==0) { - if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) { - nlmclnt_recovery(host, argp->state); - nlm_release_host(host); - } - } else { - /* If we run on an NFS server, delete all locks held by the client */ - if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) { - nlmsvc_free_host_resources(host); - nlm_release_host(host); - } - } + nlm_host_rebooted(&saddr, argp); return rpc_success; } diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 47b7dbd647a6..5f886695ac90 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -161,15 +161,16 @@ int nlmclnt_reclaim(struct nlm_host *, struct file_lock *); /* * Host cache */ -struct nlm_host * nlmclnt_lookup_host(struct sockaddr_in *, int, int); +struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int); struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *); -struct nlm_host * nlm_lookup_host(int server, struct sockaddr_in *, int, int); +struct nlm_host * nlm_lookup_host(int server, const struct sockaddr_in *, int, int); struct rpc_clnt * nlm_bind_host(struct nlm_host *); void nlm_rebind_host(struct nlm_host *); struct nlm_host * nlm_get_host(struct nlm_host *); void nlm_release_host(struct nlm_host *); void nlm_shutdown_hosts(void); extern struct nlm_host *nlm_find_client(void); +extern void nlm_host_rebooted(const struct sockaddr_in *, const struct nlm_reboot *); /* -- cgit v1.2.3 From db4e4c9a9e741ee812e1febf5e386d6a24218a71 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:52 -0700 Subject: [PATCH] knfsd: when looking up a lockd host, pass hostname & length This patch adds the peer's hostname (and name length) to all calls to nlm*_lookup_host functions. A subsequent patch will make use of these (is requested by a sysctl). Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntproc.c | 5 ++++- fs/lockd/host.c | 37 +++++++++++++++++++++++++------------ fs/lockd/svc4proc.c | 6 ++++-- fs/lockd/svclock.c | 3 ++- fs/lockd/svcproc.c | 6 ++++-- include/linux/lockd/lockd.h | 6 +++--- 6 files changed, 42 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 5436be623e30..7e6f22e2a3b4 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -153,6 +153,7 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) { struct rpc_clnt *client = NFS_CLIENT(inode); struct sockaddr_in addr; + struct nfs_server *nfssrv = NFS_SERVER(inode); struct nlm_host *host; struct nlm_rqst *call; sigset_t oldset; @@ -166,7 +167,9 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) } rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr)); - host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers); + host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers, + nfssrv->nfs_client->cl_hostname, + strlen(nfssrv->nfs_client->cl_hostname)); if (host == NULL) return -ENOLCK; diff --git a/fs/lockd/host.c b/fs/lockd/host.c index bcc21b05808a..481ce7ee1002 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -39,19 +39,23 @@ static void nlm_gc_hosts(void); * Find an NLM server handle in the cache. If there is none, create it. */ struct nlm_host * -nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version) +nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version, + const char *hostname, int hostname_len) { - return nlm_lookup_host(0, sin, proto, version); + return nlm_lookup_host(0, sin, proto, version, + hostname, hostname_len); } /* * Find an NLM client handle in the cache. If there is none, create it. */ struct nlm_host * -nlmsvc_lookup_host(struct svc_rqst *rqstp) +nlmsvc_lookup_host(struct svc_rqst *rqstp, + const char *hostname, int hostname_len) { return nlm_lookup_host(1, &rqstp->rq_addr, - rqstp->rq_prot, rqstp->rq_vers); + rqstp->rq_prot, rqstp->rq_vers, + hostname, hostname_len); } /* @@ -59,14 +63,20 @@ nlmsvc_lookup_host(struct svc_rqst *rqstp) */ struct nlm_host * nlm_lookup_host(int server, const struct sockaddr_in *sin, - int proto, int version) + int proto, int version, + const char *hostname, + int hostname_len) { struct nlm_host *host, **hp; u32 addr; int hash; - dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n", - (unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version); + dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n", + NIPQUAD(sin->sin_addr.s_addr), proto, version, + server? "server" : "client", + hostname_len, + hostname? hostname : ""); + hash = NLM_ADDRHASH(sin->sin_addr.s_addr); @@ -267,19 +277,22 @@ void nlm_release_host(struct nlm_host *host) void nlm_host_rebooted(const struct sockaddr_in *sin, const struct nlm_reboot *argp) { struct nlm_host *host; + int server; /* Obtain the host pointer for this NFS server and try to * reclaim all locks we hold on this server. */ - if ((argp->proto & 1)==0) { + server = (argp->proto & 1)? 1 : 0; + host = nlm_lookup_host(server, sin, argp->proto >> 1, argp->vers, + argp->mon, argp->len); + if (host == NULL) + return; + + if (server == 0) { /* We are client, he's the server: try to reclaim all locks. */ - if ((host = nlmclnt_lookup_host(sin, argp->proto >> 1, argp->vers)) == NULL) - return; nlmclnt_recovery(host, argp->state); } else { /* He's the client, we're the server: delete all locks held by the client */ - if ((host = nlm_lookup_host(1, sin, argp->proto >> 1, argp->vers)) == NULL) - return; nlmsvc_free_host_resources(host); } nlm_release_host(host); diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 97bd36c09a5b..7d835ad81074 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -38,7 +38,7 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, return nlm_lck_denied_nolocks; /* Obtain host handle */ - if (!(host = nlmsvc_lookup_host(rqstp)) + if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len)) || (argp->monitor && nsm_monitor(host) < 0)) goto no_locks; *hostp = host; @@ -260,7 +260,9 @@ static int nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *a struct nlm_rqst *call; int stat; - host = nlmsvc_lookup_host(rqstp); + host = nlmsvc_lookup_host(rqstp, + argp->lock.caller, + argp->lock.len); if (host == NULL) return rpc_system_err; diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 93c00ee7189d..3127ae9e435c 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -179,7 +179,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_rqst *call = NULL; /* Create host handle for callback */ - host = nlmsvc_lookup_host(rqstp); + host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len); if (host == NULL) return NULL; @@ -451,6 +451,7 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, (long long)conflock->fl.fl_start, (long long)conflock->fl.fl_end); conflock->caller = "somehost"; /* FIXME */ + conflock->len = strlen(conflock->caller); conflock->oh.len = 0; /* don't return OH info */ conflock->svid = conflock->fl.fl_pid; return nlm_lck_denied; diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 452eb5e5ea44..12291ab1e722 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -66,7 +66,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, return nlm_lck_denied_nolocks; /* Obtain host handle */ - if (!(host = nlmsvc_lookup_host(rqstp)) + if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len)) || (argp->monitor && nsm_monitor(host) < 0)) goto no_locks; *hostp = host; @@ -287,7 +287,9 @@ static int nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *ar struct nlm_rqst *call; int stat; - host = nlmsvc_lookup_host(rqstp); + host = nlmsvc_lookup_host(rqstp, + argp->lock.caller, + argp->lock.len); if (host == NULL) return rpc_system_err; diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 5f886695ac90..0f9b236bca7f 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -161,9 +161,9 @@ int nlmclnt_reclaim(struct nlm_host *, struct file_lock *); /* * Host cache */ -struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int); -struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *); -struct nlm_host * nlm_lookup_host(int server, const struct sockaddr_in *, int, int); +struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int, const char *, int); +struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *, const char *, int); +struct nlm_host * nlm_lookup_host(int server, const struct sockaddr_in *, int, int, const char *, int); struct rpc_clnt * nlm_bind_host(struct nlm_host *); void nlm_rebind_host(struct nlm_host *); struct nlm_host * nlm_get_host(struct nlm_host *); -- cgit v1.2.3 From 8dead0dbd478f35fd943f3719591e5af1ac0950d Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:53 -0700 Subject: [PATCH] knfsd: lockd: introduce nsm_handle This patch introduces the nsm_handle, which is shared by all nlm_host objects referring to the same client. With this patch applied, all nlm_hosts from the same address will share the same nsm_handle. A future patch will add sharing by name. Note: this patch changes h_name so that it is no longer guaranteed to be an IP address of the host. When the host represents an NFS server, h_name will be the name passed in the mount call. When the host represents a client, h_name will be the name presented in the lock request received from the client. A h_name is only used for printing informational messages, this change should not be significant. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntlock.c | 3 +- fs/lockd/host.c | 121 ++++++++++++++++++++++++++++++++++++++++---- fs/lockd/mon.c | 14 +++-- include/linux/lockd/lockd.h | 17 +++++-- 4 files changed, 136 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 87e1d03e8267..54e63ddef043 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -150,7 +150,8 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock) static void nlmclnt_prepare_reclaim(struct nlm_host *host) { down_write(&host->h_rwsem); - host->h_monitored = 0; + if (host->h_nsmhandle) + host->h_nsmhandle->sm_monitored = 0; host->h_state++; host->h_nextrebind = 0; nlm_rebind_host(host); diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 481ce7ee1002..0bf4afb71d25 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -34,6 +34,8 @@ static DEFINE_MUTEX(nlm_host_mutex); static void nlm_gc_hosts(void); +static struct nsm_handle * __nsm_find(const struct sockaddr_in *, + const char *, int, int); /* * Find an NLM server handle in the cache. If there is none, create it. @@ -68,7 +70,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, int hostname_len) { struct nlm_host *host, **hp; - u32 addr; + struct nsm_handle *nsm = NULL; int hash; dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n", @@ -86,7 +88,21 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, if (time_after_eq(jiffies, next_gc)) nlm_gc_hosts(); + /* We may keep several nlm_host objects for a peer, because each + * nlm_host is identified by + * (address, protocol, version, server/client) + * We could probably simplify this a little by putting all those + * different NLM rpc_clients into one single nlm_host object. + * This would allow us to have one nlm_host per address. + */ for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) { + if (!nlm_cmp_addr(&host->h_addr, sin)) + continue; + + /* See if we have an NSM handle for this client */ + if (!nsm && (nsm = host->h_nsmhandle) != 0) + atomic_inc(&nsm->sm_count); + if (host->h_proto != proto) continue; if (host->h_version != version) @@ -94,7 +110,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, if (host->h_server != server) continue; - if (nlm_cmp_addr(&host->h_addr, sin)) { + { if (hp != nlm_hosts + hash) { *hp = host->h_next; host->h_next = nlm_hosts[hash]; @@ -106,16 +122,18 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, } } - /* Ooops, no host found, create it */ - dprintk("lockd: creating host entry\n"); + /* Sadly, the host isn't in our hash table yet. See if + * we have an NSM handle for it. If not, create one. + */ + if (!nsm && !(nsm = nsm_find(sin, hostname, hostname_len))) + goto out; host = kzalloc(sizeof(*host), GFP_KERNEL); - if (!host) - goto nohost; - - addr = sin->sin_addr.s_addr; - sprintf(host->h_name, "%u.%u.%u.%u", NIPQUAD(addr)); - + if (!host) { + nsm_release(nsm); + goto out; + } + host->h_name = nsm->sm_name; host->h_addr = *sin; host->h_addr.sin_port = 0; /* ouch! */ host->h_version = version; @@ -129,6 +147,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, init_rwsem(&host->h_rwsem); host->h_state = 0; /* pseudo NSM state */ host->h_nsmstate = 0; /* real NSM state */ + host->h_nsmhandle = nsm; host->h_server = server; host->h_next = nlm_hosts[hash]; nlm_hosts[hash] = host; @@ -140,7 +159,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, if (++nrhosts > NLM_HOST_MAX) next_gc = 0; -nohost: +out: mutex_unlock(&nlm_host_mutex); return host; } @@ -393,3 +412,83 @@ nlm_gc_hosts(void) next_gc = jiffies + NLM_HOST_COLLECT; } + +/* + * Manage NSM handles + */ +static LIST_HEAD(nsm_handles); +static DECLARE_MUTEX(nsm_sema); + +static struct nsm_handle * +__nsm_find(const struct sockaddr_in *sin, + const char *hostname, int hostname_len, + int create) +{ + struct nsm_handle *nsm = NULL; + struct list_head *pos; + + if (!sin) + return NULL; + + if (hostname && memchr(hostname, '/', hostname_len) != NULL) { + if (printk_ratelimit()) { + printk(KERN_WARNING "Invalid hostname \"%.*s\" " + "in NFS lock request\n", + hostname_len, hostname); + } + return NULL; + } + + down(&nsm_sema); + list_for_each(pos, &nsm_handles) { + nsm = list_entry(pos, struct nsm_handle, sm_link); + + if (!nlm_cmp_addr(&nsm->sm_addr, sin)) + continue; + atomic_inc(&nsm->sm_count); + goto out; + } + + if (!create) { + nsm = NULL; + goto out; + } + + nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); + if (nsm != NULL) { + nsm->sm_addr = *sin; + nsm->sm_name = (char *) (nsm + 1); + memcpy(nsm->sm_name, hostname, hostname_len); + nsm->sm_name[hostname_len] = '\0'; + atomic_set(&nsm->sm_count, 1); + + list_add(&nsm->sm_link, &nsm_handles); + } + +out: up(&nsm_sema); + return nsm; +} + +struct nsm_handle * +nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len) +{ + return __nsm_find(sin, hostname, hostname_len, 1); +} + +/* + * Release an NSM handle + */ +void +nsm_release(struct nsm_handle *nsm) +{ + if (!nsm) + return; + if (atomic_dec_and_test(&nsm->sm_count)) { + down(&nsm_sema); + if (atomic_read(&nsm->sm_count) == 0) { + list_del(&nsm->sm_link); + kfree(nsm); + } + up(&nsm_sema); + } +} diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index e02a1a4dfced..e27981403fbe 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -70,11 +70,14 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res) int nsm_monitor(struct nlm_host *host) { + struct nsm_handle *nsm = host->h_nsmhandle; struct nsm_res res; int status; dprintk("lockd: nsm_monitor(%s)\n", host->h_name); - if (host->h_monitored) + BUG_ON(nsm == NULL); + + if (nsm->sm_monitored) return 0; status = nsm_mon_unmon(host, SM_MON, &res); @@ -82,7 +85,7 @@ nsm_monitor(struct nlm_host *host) if (status < 0 || res.status != 0) printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name); else - host->h_monitored = 1; + nsm->sm_monitored = 1; return status; } @@ -92,19 +95,22 @@ nsm_monitor(struct nlm_host *host) int nsm_unmonitor(struct nlm_host *host) { + struct nsm_handle *nsm = host->h_nsmhandle; struct nsm_res res; int status = 0; dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name); - if (!host->h_monitored) + if (nsm == NULL) return 0; - host->h_monitored = 0; + host->h_nsmhandle = NULL; if (!host->h_killed) { status = nsm_mon_unmon(host, SM_UNMON, &res); if (status < 0) printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name); + nsm->sm_monitored = 0; } + nsm_release(nsm); return status; } diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 0f9b236bca7f..ab2ffc8a0b44 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -40,14 +40,13 @@ struct nlm_host { struct nlm_host * h_next; /* linked list (hash table) */ struct sockaddr_in h_addr; /* peer address */ struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ - char h_name[20]; /* remote hostname */ + char * h_name; /* remote hostname */ u32 h_version; /* interface version */ unsigned short h_proto; /* transport proto */ unsigned short h_reclaiming : 1, h_server : 1, /* server side, not client side */ h_inuse : 1, - h_killed : 1, - h_monitored : 1; + h_killed : 1; wait_queue_head_t h_gracewait; /* wait while reclaiming */ struct rw_semaphore h_rwsem; /* Reboot recovery lock */ u32 h_state; /* pseudo-state counter */ @@ -61,6 +60,16 @@ struct nlm_host { spinlock_t h_lock; struct list_head h_granted; /* Locks in GRANTED state */ struct list_head h_reclaim; /* Locks in RECLAIM state */ + struct nsm_handle * h_nsmhandle; /* NSM status handle */ +}; + +struct nsm_handle { + struct list_head sm_link; + atomic_t sm_count; + char * sm_name; + struct sockaddr_in sm_addr; + unsigned int sm_monitored : 1, + sm_sticky : 1; /* don't unmonitor */ }; /* @@ -171,6 +180,8 @@ void nlm_release_host(struct nlm_host *); void nlm_shutdown_hosts(void); extern struct nlm_host *nlm_find_client(void); extern void nlm_host_rebooted(const struct sockaddr_in *, const struct nlm_reboot *); +struct nsm_handle *nsm_find(const struct sockaddr_in *, const char *, int); +void nsm_release(struct nsm_handle *); /* -- cgit v1.2.3 From 5c8dd29ca7fc7483690cef4306549742d534f2a2 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:55 -0700 Subject: [PATCH] knfsd: lockd: Make nlm_host_rebooted use the nsm_handle This patch makes the SM_NOTIFY handling understand and use the nsm_handle. To make it a bit clear what is happening: nlmclent_prepare_reclaim and nlmclnt_finish_reclaim get open-coded into 'reclaimer' The result is tidied up. Then some of that functionality is moved out into nlm_host_rebooted (which calls nlmclnt_recovery which starts a thread which runs reclaimer). Also host_rebooted now finds an nsm_handle rather than a host, then then iterates over all hosts and deals with each host that shares that nsm_handle. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntlock.c | 55 ++++++++++++++------------------------- fs/lockd/host.c | 63 +++++++++++++++++++++++++++++++++------------ fs/lockd/svc4proc.c | 2 +- fs/lockd/svcproc.c | 2 +- include/linux/lockd/lockd.h | 4 +-- 5 files changed, 69 insertions(+), 57 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 54e63ddef043..a4ab6dd7661f 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -143,44 +143,13 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock) * server crash. */ -/* - * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number, - * that we mark locks for reclaiming, and that we bump the pseudo NSM state. - */ -static void nlmclnt_prepare_reclaim(struct nlm_host *host) -{ - down_write(&host->h_rwsem); - if (host->h_nsmhandle) - host->h_nsmhandle->sm_monitored = 0; - host->h_state++; - host->h_nextrebind = 0; - nlm_rebind_host(host); - - /* - * Mark the locks for reclaiming. - */ - list_splice_init(&host->h_granted, &host->h_reclaim); - - dprintk("NLM: reclaiming locks for host %s\n", host->h_name); -} - -static void nlmclnt_finish_reclaim(struct nlm_host *host) -{ - host->h_reclaiming = 0; - up_write(&host->h_rwsem); - dprintk("NLM: done reclaiming locks for host %s", host->h_name); -} - /* * Reclaim all locks on server host. We do this by spawning a separate * reclaimer thread. */ void -nlmclnt_recovery(struct nlm_host *host, u32 newstate) +nlmclnt_recovery(struct nlm_host *host) { - if (host->h_nsmstate == newstate) - return; - host->h_nsmstate = newstate; if (!host->h_reclaiming++) { nlm_get_host(host); __module_get(THIS_MODULE); @@ -200,18 +169,30 @@ reclaimer(void *ptr) daemonize("%s-reclaim", host->h_name); allow_signal(SIGKILL); + down_write(&host->h_rwsem); + /* This one ensures that our parent doesn't terminate while the * reclaim is in progress */ lock_kernel(); lockd_up(0); /* note: this cannot fail as lockd is already running */ - nlmclnt_prepare_reclaim(host); - /* First, reclaim all locks that have been marked. */ + dprintk("lockd: reclaiming locks for host %s", host->h_name); + restart: nsmstate = host->h_nsmstate; + + /* Force a portmap getport - the peer's lockd will + * most likely end up on a different port. + */ + host->h_nextrebind = 0; + nlm_rebind_host(host); + + /* First, reclaim all locks that have been granted. */ + list_splice_init(&host->h_granted, &host->h_reclaim); list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) { list_del_init(&fl->fl_u.nfs_fl.list); + /* Why are we leaking memory here? --okir */ if (signalled()) continue; if (nlmclnt_reclaim(host, fl) != 0) @@ -219,11 +200,13 @@ restart: list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted); if (host->h_nsmstate != nsmstate) { /* Argh! The server rebooted again! */ - list_splice_init(&host->h_granted, &host->h_reclaim); goto restart; } } - nlmclnt_finish_reclaim(host); + + host->h_reclaiming = 0; + up_write(&host->h_rwsem); + dprintk("NLM: done reclaiming locks for host %s", host->h_name); /* Now, wake up all processes that sleep on a blocked lock */ list_for_each_entry(block, &nlm_blocked, b_list) { diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 4990223a3e18..3cd96e2e1256 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -290,28 +290,57 @@ void nlm_release_host(struct nlm_host *host) * has rebooted. * Release all resources held by that peer. */ -void nlm_host_rebooted(const struct sockaddr_in *sin, const struct nlm_reboot *argp) +void nlm_host_rebooted(const struct sockaddr_in *sin, + const char *hostname, int hostname_len, + u32 new_state) { - struct nlm_host *host; - int server; + struct nsm_handle *nsm; + struct nlm_host *host, **hp; + int hash; - /* Obtain the host pointer for this NFS server and try to - * reclaim all locks we hold on this server. - */ - server = (argp->proto & 1)? 1 : 0; - host = nlm_lookup_host(server, sin, argp->proto >> 1, argp->vers, - argp->mon, argp->len); - if (host == NULL) + dprintk("lockd: nlm_host_rebooted(%s, %u.%u.%u.%u)\n", + hostname, NIPQUAD(sin->sin_addr)); + + /* Find the NSM handle for this peer */ + if (!(nsm = __nsm_find(sin, hostname, hostname_len, 0))) return; - if (server == 0) { - /* We are client, he's the server: try to reclaim all locks. */ - nlmclnt_recovery(host, argp->state); - } else { - /* He's the client, we're the server: delete all locks held by the client */ - nlmsvc_free_host_resources(host); + /* When reclaiming locks on this peer, make sure that + * we set up a new notification */ + nsm->sm_monitored = 0; + + /* Mark all hosts tied to this NSM state as having rebooted. + * We run the loop repeatedly, because we drop the host table + * lock for this. + * To avoid processing a host several times, we match the nsmstate. + */ +again: mutex_lock(&nlm_host_mutex); + for (hash = 0; hash < NLM_HOST_NRHASH; hash++) { + for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) { + if (host->h_nsmhandle == nsm + && host->h_nsmstate != new_state) { + host->h_nsmstate = new_state; + host->h_state++; + + nlm_get_host(host); + mutex_unlock(&nlm_host_mutex); + + if (host->h_server) { + /* We're server for this guy, just ditch + * all the locks he held. */ + nlmsvc_free_host_resources(host); + } else { + /* He's the server, initiate lock recovery. */ + nlmclnt_recovery(host); + } + + nlm_release_host(host); + goto again; + } + } } - nlm_release_host(host); + + mutex_unlock(&nlm_host_mutex); } /* diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 7d835ad81074..b8525fb62934 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -438,7 +438,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, */ memset(&saddr, 0, sizeof(saddr)); saddr.sin_addr.s_addr = argp->addr; - nlm_host_rebooted(&saddr, argp); + nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state); return rpc_success; } diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 12291ab1e722..66e7b0b3430e 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -467,7 +467,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, */ memset(&saddr, 0, sizeof(saddr)); saddr.sin_addr.s_addr = argp->addr; - nlm_host_rebooted(&saddr, argp); + nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state); return rpc_success; } diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index ab2ffc8a0b44..a41eb841428b 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -164,7 +164,7 @@ struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock void nlmclnt_finish_block(struct nlm_wait *block); int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout); u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *); -void nlmclnt_recovery(struct nlm_host *, u32); +void nlmclnt_recovery(struct nlm_host *); int nlmclnt_reclaim(struct nlm_host *, struct file_lock *); /* @@ -179,7 +179,7 @@ struct nlm_host * nlm_get_host(struct nlm_host *); void nlm_release_host(struct nlm_host *); void nlm_shutdown_hosts(void); extern struct nlm_host *nlm_find_client(void); -extern void nlm_host_rebooted(const struct sockaddr_in *, const struct nlm_reboot *); +extern void nlm_host_rebooted(const struct sockaddr_in *, const char *, int, u32); struct nsm_handle *nsm_find(const struct sockaddr_in *, const char *, int); void nsm_release(struct nsm_handle *); -- cgit v1.2.3 From 9502c52259f7038b6c1e31532e22884716a56b1a Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:56 -0700 Subject: [PATCH] knfsd: lockd: make the nsm upcalls use the nsm_handle This converts the statd upcalls to use the nsm_handle This means that we only register each host once with statd, rather than registering each host/vers/protocol triple. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/mon.c | 30 ++++++++++++++++++------------ include/linux/lockd/sm_inter.h | 1 - 2 files changed, 18 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index e27981403fbe..626b6c116a6d 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -30,7 +30,7 @@ u32 nsm_local_state; * Common procedure for SM_MON/SM_UNMON calls */ static int -nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res) +nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) { struct rpc_clnt *clnt; int status; @@ -46,10 +46,10 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res) goto out; } - args.addr = host->h_addr.sin_addr.s_addr; - args.proto= (host->h_proto<<1) | host->h_server; + memset(&args, 0, sizeof(args)); + args.addr = nsm->sm_addr.sin_addr.s_addr; args.prog = NLM_PROGRAM; - args.vers = host->h_version; + args.vers = 3; args.proc = NLMPROC_NSM_NOTIFY; memset(res, 0, sizeof(*res)); @@ -80,7 +80,7 @@ nsm_monitor(struct nlm_host *host) if (nsm->sm_monitored) return 0; - status = nsm_mon_unmon(host, SM_MON, &res); + status = nsm_mon_unmon(nsm, SM_MON, &res); if (status < 0 || res.status != 0) printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name); @@ -99,16 +99,20 @@ nsm_unmonitor(struct nlm_host *host) struct nsm_res res; int status = 0; - dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name); if (nsm == NULL) return 0; host->h_nsmhandle = NULL; - if (!host->h_killed) { - status = nsm_mon_unmon(host, SM_UNMON, &res); + if (atomic_read(&nsm->sm_count) == 1 + && nsm->sm_monitored && !nsm->sm_sticky) { + dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name); + + status = nsm_mon_unmon(nsm, SM_UNMON, &res); if (status < 0) - printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name); - nsm->sm_monitored = 0; + printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", + host->h_name); + else + nsm->sm_monitored = 0; } nsm_release(nsm); return status; @@ -171,9 +175,11 @@ xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) p = xdr_encode_common(rqstp, p, argp); if (IS_ERR(p)) return PTR_ERR(p); + + /* Surprise - there may even be room for an IPv6 address now */ *p++ = argp->addr; - *p++ = argp->vers; - *p++ = argp->proto; + *p++ = 0; + *p++ = 0; *p++ = 0; rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); return 0; diff --git a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h index 1080bb6ae315..d93b074668ce 100644 --- a/include/linux/lockd/sm_inter.h +++ b/include/linux/lockd/sm_inter.h @@ -28,7 +28,6 @@ struct nsm_args { u32 prog; /* RPC callback info */ u32 vers; u32 proc; - u32 proto; /* protocol (udp/tcp) plus server/client flag */ }; /* -- cgit v1.2.3 From 0cea32761a2f954c6d42ca79d7d1e6b9663b1e4a Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:56 -0700 Subject: [PATCH] knfsd: lockd: make the hash chains use a hlist_node Get rid of the home-grown singly linked lists for the nlm_host hash table. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/host.c | 71 +++++++++++++++++++++++++-------------------- include/linux/lockd/lockd.h | 2 +- 2 files changed, 40 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 3cd96e2e1256..4449ef0b7837 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -27,7 +27,7 @@ #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) -static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH]; +static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; static unsigned long next_gc; static int nrhosts; static DEFINE_MUTEX(nlm_host_mutex); @@ -69,7 +69,9 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, const char *hostname, int hostname_len) { - struct nlm_host *host, **hp; + struct hlist_head *chain; + struct hlist_node *pos; + struct nlm_host *host; struct nsm_handle *nsm = NULL; int hash; @@ -95,7 +97,8 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, * different NLM rpc_clients into one single nlm_host object. * This would allow us to have one nlm_host per address. */ - for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) { + chain = &nlm_hosts[hash]; + hlist_for_each_entry(host, pos, chain, h_hash) { if (!nlm_cmp_addr(&host->h_addr, sin)) continue; @@ -110,15 +113,16 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, if (host->h_server != server) continue; - if (hp != nlm_hosts + hash) { - *hp = host->h_next; - host->h_next = nlm_hosts[hash]; - nlm_hosts[hash] = host; - } + /* Move to head of hash chain. */ + hlist_del(&host->h_hash); + hlist_add_head(&host->h_hash, chain); + nlm_get_host(host); goto out; } + host = NULL; + /* Sadly, the host isn't in our hash table yet. See if * we have an NSM handle for it. If not, create one. */ @@ -146,8 +150,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, host->h_nsmstate = 0; /* real NSM state */ host->h_nsmhandle = nsm; host->h_server = server; - host->h_next = nlm_hosts[hash]; - nlm_hosts[hash] = host; + hlist_add_head(&host->h_hash, chain); INIT_LIST_HEAD(&host->h_lockowners); spin_lock_init(&host->h_lock); INIT_LIST_HEAD(&host->h_granted); @@ -164,14 +167,17 @@ out: struct nlm_host * nlm_find_client(void) { + struct hlist_head *chain; + struct hlist_node *pos; + /* find a nlm_host for a client for which h_killed == 0. * and return it */ - int hash; mutex_lock(&nlm_host_mutex); - for (hash = 0 ; hash < NLM_HOST_NRHASH; hash++) { - struct nlm_host *host, **hp; - for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) { + for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { + struct nlm_host *host; + + hlist_for_each_entry(host, pos, chain, h_hash) { if (host->h_server && host->h_killed == 0) { nlm_get_host(host); @@ -294,9 +300,10 @@ void nlm_host_rebooted(const struct sockaddr_in *sin, const char *hostname, int hostname_len, u32 new_state) { + struct hlist_head *chain; + struct hlist_node *pos; struct nsm_handle *nsm; - struct nlm_host *host, **hp; - int hash; + struct nlm_host *host; dprintk("lockd: nlm_host_rebooted(%s, %u.%u.%u.%u)\n", hostname, NIPQUAD(sin->sin_addr)); @@ -315,8 +322,8 @@ void nlm_host_rebooted(const struct sockaddr_in *sin, * To avoid processing a host several times, we match the nsmstate. */ again: mutex_lock(&nlm_host_mutex); - for (hash = 0; hash < NLM_HOST_NRHASH; hash++) { - for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) { + for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { + hlist_for_each_entry(host, pos, chain, h_hash) { if (host->h_nsmhandle == nsm && host->h_nsmstate != new_state) { host->h_nsmstate = new_state; @@ -350,16 +357,17 @@ again: mutex_lock(&nlm_host_mutex); void nlm_shutdown_hosts(void) { + struct hlist_head *chain; + struct hlist_node *pos; struct nlm_host *host; - int i; dprintk("lockd: shutting down host module\n"); mutex_lock(&nlm_host_mutex); /* First, make all hosts eligible for gc */ dprintk("lockd: nuking all hosts...\n"); - for (i = 0; i < NLM_HOST_NRHASH; i++) { - for (host = nlm_hosts[i]; host; host = host->h_next) + for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { + hlist_for_each_entry(host, pos, chain, h_hash) host->h_expires = jiffies - 1; } @@ -371,8 +379,8 @@ nlm_shutdown_hosts(void) if (nrhosts) { printk(KERN_WARNING "lockd: couldn't shutdown host module!\n"); dprintk("lockd: %d hosts left:\n", nrhosts); - for (i = 0; i < NLM_HOST_NRHASH; i++) { - for (host = nlm_hosts[i]; host; host = host->h_next) { + for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { + hlist_for_each_entry(host, pos, chain, h_hash) { dprintk(" %s (cnt %d use %d exp %ld)\n", host->h_name, atomic_read(&host->h_count), host->h_inuse, host->h_expires); @@ -389,32 +397,31 @@ nlm_shutdown_hosts(void) static void nlm_gc_hosts(void) { - struct nlm_host **q, *host; + struct hlist_head *chain; + struct hlist_node *pos, *next; + struct nlm_host *host; struct rpc_clnt *clnt; - int i; dprintk("lockd: host garbage collection\n"); - for (i = 0; i < NLM_HOST_NRHASH; i++) { - for (host = nlm_hosts[i]; host; host = host->h_next) + for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { + hlist_for_each_entry(host, pos, chain, h_hash) host->h_inuse = 0; } /* Mark all hosts that hold locks, blocks or shares */ nlmsvc_mark_resources(); - for (i = 0; i < NLM_HOST_NRHASH; i++) { - q = &nlm_hosts[i]; - while ((host = *q) != NULL) { + for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { + hlist_for_each_entry_safe(host, pos, next, chain, h_hash) { if (atomic_read(&host->h_count) || host->h_inuse || time_before(jiffies, host->h_expires)) { dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n", host->h_name, atomic_read(&host->h_count), host->h_inuse, host->h_expires); - q = &host->h_next; continue; } dprintk("lockd: delete host %s\n", host->h_name); - *q = host->h_next; + hlist_del_init(&host->h_hash); /* * Unmonitor unless host was invalidated (i.e. lockd restarted) diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index a41eb841428b..c8635d84d5d2 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -37,7 +37,7 @@ * Lockd host handle (used both by the client and server personality). */ struct nlm_host { - struct nlm_host * h_next; /* linked list (hash table) */ + struct hlist_node h_hash; /* doubly linked list */ struct sockaddr_in h_addr; /* peer address */ struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ char * h_name; /* remote hostname */ -- cgit v1.2.3 From 68a2d76cea4234bc027df23085d9df4f2171f7fc Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:57 -0700 Subject: [PATCH] knfsd: lockd: Change list of blocked list to list_node This patch changes the nlm_blocked list to use a list_node instead of homegrown linked list handling. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svclock.c | 119 +++++++++++++++++++++----------------------- fs/lockd/svcsubs.c | 5 +- include/linux/lockd/lockd.h | 7 ++- 3 files changed, 62 insertions(+), 69 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 3127ae9e435c..7209712f3832 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -40,7 +40,7 @@ static void nlmsvc_release_block(struct nlm_block *block); static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); -static int nlmsvc_remove_block(struct nlm_block *block); +static void nlmsvc_remove_block(struct nlm_block *block); static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock); static void nlmsvc_freegrantargs(struct nlm_rqst *call); @@ -49,7 +49,7 @@ static const struct rpc_call_ops nlmsvc_grant_ops; /* * The list of blocked locks to retry */ -static struct nlm_block * nlm_blocked; +static LIST_HEAD(nlm_blocked); /* * Insert a blocked lock into the global list @@ -57,48 +57,44 @@ static struct nlm_block * nlm_blocked; static void nlmsvc_insert_block(struct nlm_block *block, unsigned long when) { - struct nlm_block **bp, *b; + struct nlm_block *b; + struct list_head *pos; dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when); - kref_get(&block->b_count); - if (block->b_queued) - nlmsvc_remove_block(block); - bp = &nlm_blocked; + if (list_empty(&block->b_list)) { + kref_get(&block->b_count); + } else { + list_del_init(&block->b_list); + } + + pos = &nlm_blocked; if (when != NLM_NEVER) { if ((when += jiffies) == NLM_NEVER) when ++; - while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER) - bp = &b->b_next; - } else - while ((b = *bp) != 0) - bp = &b->b_next; + list_for_each(pos, &nlm_blocked) { + b = list_entry(pos, struct nlm_block, b_list); + if (time_after(b->b_when,when) || b->b_when == NLM_NEVER) + break; + } + /* On normal exit from the loop, pos == &nlm_blocked, + * so we will be adding to the end of the list - good + */ + } - block->b_queued = 1; + list_add_tail(&block->b_list, pos); block->b_when = when; - block->b_next = b; - *bp = block; } /* * Remove a block from the global list */ -static int +static inline void nlmsvc_remove_block(struct nlm_block *block) { - struct nlm_block **bp, *b; - - if (!block->b_queued) - return 1; - for (bp = &nlm_blocked; (b = *bp) != 0; bp = &b->b_next) { - if (b == block) { - *bp = block->b_next; - block->b_queued = 0; - nlmsvc_release_block(block); - return 1; - } + if (!list_empty(&block->b_list)) { + list_del_init(&block->b_list); + nlmsvc_release_block(block); } - - return 0; } /* @@ -107,14 +103,14 @@ nlmsvc_remove_block(struct nlm_block *block) static struct nlm_block * nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock) { - struct nlm_block **head, *block; + struct nlm_block *block; struct file_lock *fl; dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n", file, lock->fl.fl_pid, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end, lock->fl.fl_type); - for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) { + list_for_each_entry(block, &nlm_blocked, b_list) { fl = &block->b_call->a_args.lock.fl; dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n", block->b_file, fl->fl_pid, @@ -147,16 +143,16 @@ nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin) { struct nlm_block *block; - for (block = nlm_blocked; block; block = block->b_next) { - dprintk("cookie: head of blocked queue %p, block %p\n", - nlm_blocked, block); + list_for_each_entry(block, &nlm_blocked, b_list) { if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie) && nlm_cmp_addr(sin, &block->b_host->h_addr)) - break; + goto found; } - if (block != NULL) - kref_get(&block->b_count); + return NULL; + +found: + kref_get(&block->b_count); return block; } @@ -192,6 +188,8 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, if (block == NULL) goto failed; kref_init(&block->b_count); + INIT_LIST_HEAD(&block->b_list); + INIT_LIST_HEAD(&block->b_flist); if (!nlmsvc_setgrantargs(call, lock)) goto failed_free; @@ -210,8 +208,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, file->f_count++; /* Add to file's list of blocks */ - block->b_fnext = file->f_blocks; - file->f_blocks = block; + list_add(&block->b_flist, &file->f_blocks); /* Set up RPC arguments for callback */ block->b_call = call; @@ -248,18 +245,12 @@ static void nlmsvc_free_block(struct kref *kref) { struct nlm_block *block = container_of(kref, struct nlm_block, b_count); struct nlm_file *file = block->b_file; - struct nlm_block **bp; dprintk("lockd: freeing block %p...\n", block); - down(&file->f_sema); /* Remove block from file's list of blocks */ - for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) { - if (*bp == block) { - *bp = block->b_fnext; - break; - } - } + down(&file->f_sema); + list_del_init(&block->b_flist); up(&file->f_sema); nlmsvc_freegrantargs(block->b_call); @@ -279,21 +270,23 @@ static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file) struct nlm_block *block; down(&file->f_sema); - for (block = file->f_blocks; block != NULL; block = block->b_fnext) + list_for_each_entry(block, &file->f_blocks, b_flist) block->b_host->h_inuse = 1; up(&file->f_sema); } static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file) { - struct nlm_block *block; + struct nlm_block *block, *next; restart: down(&file->f_sema); - for (block = file->f_blocks; block != NULL; block = block->b_fnext) { + list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) { if (host != NULL && host != block->b_host) continue; - if (!block->b_queued) + /* Do not destroy blocks that are not on + * the global retry list - why? */ + if (list_empty(&block->b_list)) continue; kref_get(&block->b_count); up(&file->f_sema); @@ -528,10 +521,10 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) static void nlmsvc_notify_blocked(struct file_lock *fl) { - struct nlm_block **bp, *block; + struct nlm_block *block; dprintk("lockd: VFS unblock notification for block %p\n", fl); - for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) { + list_for_each_entry(block, &nlm_blocked, b_list) { if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) { nlmsvc_insert_block(block, 0); svc_wake_up(block->b_daemon); @@ -697,16 +690,19 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status unsigned long nlmsvc_retry_blocked(void) { - struct nlm_block *block; + unsigned long timeout = MAX_SCHEDULE_TIMEOUT; + struct nlm_block *block; + + while (!list_empty(&nlm_blocked)) { + block = list_entry(nlm_blocked.next, struct nlm_block, b_list); - dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", - nlm_blocked, - nlm_blocked? nlm_blocked->b_when : 0); - while ((block = nlm_blocked) != 0) { if (block->b_when == NLM_NEVER) break; - if (time_after(block->b_when,jiffies)) + if (time_after(block->b_when,jiffies)) { + timeout = block->b_when - jiffies; break; + } + dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", block, block->b_when); kref_get(&block->b_count); @@ -714,8 +710,5 @@ nlmsvc_retry_blocked(void) nlmsvc_release_block(block); } - if ((block = nlm_blocked) && block->b_when != NLM_NEVER) - return (block->b_when - jiffies); - - return MAX_SCHEDULE_TIMEOUT; + return timeout; } diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index c8308bccd319..a92fc5813144 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -107,6 +107,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, memcpy(&file->f_handle, f, sizeof(struct nfs_fh)); file->f_hash = hash; init_MUTEX(&file->f_sema); + INIT_LIST_HEAD(&file->f_blocks); /* Open the file. Note that this must not sleep for too long, else * we would lock up lockd:-) So no NFS re-exports, folks. @@ -220,7 +221,7 @@ nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action) { if (action == NLM_ACT_CHECK) { /* Fast path for mark and sweep garbage collection */ - if (file->f_count || file->f_blocks || file->f_shares) + if (file->f_count || list_empty(&file->f_blocks) || file->f_shares) return 1; } else { nlmsvc_traverse_blocks(host, file, action); @@ -253,7 +254,7 @@ nlm_traverse_files(struct nlm_host *host, int action) mutex_lock(&nlm_file_mutex); file->f_count--; /* No more references to this file. Let go of it. */ - if (!file->f_blocks && !file->f_locks + if (list_empty(&file->f_blocks) && !file->f_locks && !file->f_shares && !file->f_count) { *fp = file->f_next; nlmsvc_ops->fclose(file->f_file); diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index c8635d84d5d2..2e740f6a2f77 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -109,7 +109,7 @@ struct nlm_file { struct nfs_fh f_handle; /* NFS file handle */ struct file * f_file; /* VFS file pointer */ struct nlm_share * f_shares; /* DOS shares */ - struct nlm_block * f_blocks; /* blocked locks */ + struct list_head f_blocks; /* blocked locks */ unsigned int f_locks; /* guesstimate # of locks */ unsigned int f_count; /* reference count */ struct semaphore f_sema; /* avoid concurrent access */ @@ -123,14 +123,13 @@ struct nlm_file { #define NLM_NEVER (~(unsigned long) 0) struct nlm_block { struct kref b_count; /* Reference count */ - struct nlm_block * b_next; /* linked list (all blocks) */ - struct nlm_block * b_fnext; /* linked list (per file) */ + struct list_head b_list; /* linked list of all blocks */ + struct list_head b_flist; /* linked list (per file) */ struct nlm_rqst * b_call; /* RPC args & callback info */ struct svc_serv * b_daemon; /* NLM service */ struct nlm_host * b_host; /* host handle for RPC clnt */ unsigned long b_when; /* next re-xmit */ unsigned int b_id; /* block id */ - unsigned char b_queued; /* re-queued */ unsigned char b_granted; /* VFS granted lock */ struct nlm_file * b_file; /* file in question */ }; -- cgit v1.2.3 From 07ba80635117c136714084e019375aa508365375 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:58 -0700 Subject: [PATCH] knfsd: change nlm_file to use a hlist This changes struct nlm_file and the nlm_files hash table to use a hlist instead of the home-grown lists. This allows us to remove f_hash which was only used to find the right hash chain to delete an entry from. It also increases the size of the nlm_files hash table from 32 to 128. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svcsubs.c | 42 ++++++++++++++++-------------------------- include/linux/lockd/lockd.h | 3 +-- 2 files changed, 17 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index a92fc5813144..91731353dfa4 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -25,9 +25,9 @@ /* * Global file hash table */ -#define FILE_HASH_BITS 5 +#define FILE_HASH_BITS 7 #define FILE_NRHASH (1<f_next) + hlist_for_each_entry(file, pos, &nlm_files[hash], f_list) if (!nfs_compare_fh(&file->f_handle, f)) goto found; @@ -105,8 +106,8 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, goto out_unlock; memcpy(&file->f_handle, f, sizeof(struct nfs_fh)); - file->f_hash = hash; init_MUTEX(&file->f_sema); + INIT_HLIST_NODE(&file->f_list); INIT_LIST_HEAD(&file->f_blocks); /* Open the file. Note that this must not sleep for too long, else @@ -120,8 +121,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, goto out_free; } - file->f_next = nlm_files[hash]; - nlm_files[hash] = file; + hlist_add_head(&file->f_list, &nlm_files[hash]); found: dprintk("lockd: found file %p (count %d)\n", file, file->f_count); @@ -150,22 +150,14 @@ out_free: static inline void nlm_delete_file(struct nlm_file *file) { - struct nlm_file **fp, *f; - nlm_debug_print_file("closing file", file); - - fp = nlm_files + file->f_hash; - while ((f = *fp) != NULL) { - if (f == file) { - *fp = file->f_next; - nlmsvc_ops->fclose(file->f_file); - kfree(file); - return; - } - fp = &f->f_next; + if (!hlist_unhashed(&file->f_list)) { + hlist_del(&file->f_list); + nlmsvc_ops->fclose(file->f_file); + kfree(file); + } else { + printk(KERN_WARNING "lockd: attempt to release unknown file!\n"); } - - printk(KERN_WARNING "lockd: attempt to release unknown file!\n"); } /* @@ -236,13 +228,13 @@ nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action) static int nlm_traverse_files(struct nlm_host *host, int action) { - struct nlm_file *file, **fp; + struct hlist_node *pos, *next; + struct nlm_file *file; int i, ret = 0; mutex_lock(&nlm_file_mutex); for (i = 0; i < FILE_NRHASH; i++) { - fp = nlm_files + i; - while ((file = *fp) != NULL) { + hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) { file->f_count++; mutex_unlock(&nlm_file_mutex); @@ -256,11 +248,9 @@ nlm_traverse_files(struct nlm_host *host, int action) /* No more references to this file. Let go of it. */ if (list_empty(&file->f_blocks) && !file->f_locks && !file->f_shares && !file->f_count) { - *fp = file->f_next; + hlist_del(&file->f_list); nlmsvc_ops->fclose(file->f_file); kfree(file); - } else { - fp = &file->f_next; } } } diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 2e740f6a2f77..777a91e1ac8f 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -105,7 +105,7 @@ struct nlm_rqst { * an NFS client. */ struct nlm_file { - struct nlm_file * f_next; /* linked list */ + struct hlist_node f_list; /* linked list */ struct nfs_fh f_handle; /* NFS file handle */ struct file * f_file; /* VFS file pointer */ struct nlm_share * f_shares; /* DOS shares */ @@ -113,7 +113,6 @@ struct nlm_file { unsigned int f_locks; /* guesstimate # of locks */ unsigned int f_count; /* reference count */ struct semaphore f_sema; /* avoid concurrent access */ - int f_hash; /* hash of f_handle */ }; /* -- cgit v1.2.3 From f2af793db02d2c2f677bdb5bf8e0efdcbf9c0256 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:15:59 -0700 Subject: [PATCH] knfsd: lockd: make nlm_traverse_* more flexible This patch makes nlm_traverse{locks,blocks,shares} and friends use a function pointer rather than a "action" enum. This function pointer is given two nlm_hosts (one given by the caller, the other taken from the lock/block/share currently visited), and is free to do with them as it wants. If it returns a non-zero value, the lockd/block/share is released. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svclock.c | 33 ++++---------- fs/lockd/svcshare.c | 20 ++++----- fs/lockd/svcsubs.c | 105 ++++++++++++++++++++++++++++++++------------ include/linux/lockd/lockd.h | 15 +++---- include/linux/lockd/share.h | 3 +- 5 files changed, 102 insertions(+), 74 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 7209712f3832..1f91567a1b88 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -265,24 +265,20 @@ static void nlmsvc_release_block(struct nlm_block *block) kref_put(&block->b_count, nlmsvc_free_block); } -static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file) -{ - struct nlm_block *block; - - down(&file->f_sema); - list_for_each_entry(block, &file->f_blocks, b_flist) - block->b_host->h_inuse = 1; - up(&file->f_sema); -} - -static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file) +/* + * Loop over all blocks and delete blocks held by + * a matching host. + */ +void nlmsvc_traverse_blocks(struct nlm_host *host, + struct nlm_file *file, + nlm_host_match_fn_t match) { struct nlm_block *block, *next; restart: down(&file->f_sema); list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) { - if (host != NULL && host != block->b_host) + if (!match(block->b_host, host)) continue; /* Do not destroy blocks that are not on * the global retry list - why? */ @@ -297,19 +293,6 @@ restart: up(&file->f_sema); } -/* - * Loop over all blocks and perform the action specified. - * (NLM_ACT_CHECK handled by nlmsvc_inspect_file). - */ -void -nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) -{ - if (action == NLM_ACT_MARK) - nlmsvc_act_mark(host, file); - else - nlmsvc_act_unlock(host, file); -} - /* * Initialize arguments for GRANTED call. The nlm_rqst structure * has been cleared already. diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c index 27288c83da96..b9926ce8782e 100644 --- a/fs/lockd/svcshare.c +++ b/fs/lockd/svcshare.c @@ -85,24 +85,20 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, } /* - * Traverse all shares for a given file (and host). - * NLM_ACT_CHECK is handled by nlmsvc_inspect_file. + * Traverse all shares for a given file, and delete + * those owned by the given (type of) host */ -void -nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action) +void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, + nlm_host_match_fn_t match) { struct nlm_share *share, **shpp; shpp = &file->f_shares; while ((share = *shpp) != NULL) { - if (action == NLM_ACT_MARK) - share->s_host->h_inuse = 1; - else if (action == NLM_ACT_UNLOCK) { - if (host == NULL || host == share->s_host) { - *shpp = share->s_next; - kfree(share); - continue; - } + if (match(share->s_host, host)) { + *shpp = share->s_next; + kfree(share); + continue; } shpp = &share->s_next; } diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 91731353dfa4..bb13a48210f5 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -165,7 +165,8 @@ nlm_delete_file(struct nlm_file *file) * action. */ static int -nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action) +nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, + nlm_host_match_fn_t match) { struct inode *inode = nlmsvc_file_inode(file); struct file_lock *fl; @@ -179,17 +180,11 @@ again: /* update current lock count */ file->f_locks++; + lockhost = (struct nlm_host *) fl->fl_owner; - if (action == NLM_ACT_MARK) - lockhost->h_inuse = 1; - else if (action == NLM_ACT_CHECK) - return 1; - else if (action == NLM_ACT_UNLOCK) { + if (match(lockhost, host)) { struct file_lock lock = *fl; - if (host && lockhost != host) - continue; - lock.fl_type = F_UNLCK; lock.fl_start = 0; lock.fl_end = OFFSET_MAX; @@ -206,27 +201,42 @@ again: } /* - * Operate on a single file + * Inspect a single file + */ +static inline int +nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match) +{ + nlmsvc_traverse_blocks(host, file, match); + nlmsvc_traverse_shares(host, file, match); + return nlm_traverse_locks(host, file, match); +} + +/* + * Quick check whether there are still any locks, blocks or + * shares on a given file. */ static inline int -nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action) +nlm_file_inuse(struct nlm_file *file) { - if (action == NLM_ACT_CHECK) { - /* Fast path for mark and sweep garbage collection */ - if (file->f_count || list_empty(&file->f_blocks) || file->f_shares) + struct inode *inode = nlmsvc_file_inode(file); + struct file_lock *fl; + + if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares) + return 1; + + for (fl = inode->i_flock; fl; fl = fl->fl_next) { + if (fl->fl_lmops == &nlmsvc_lock_operations) return 1; - } else { - nlmsvc_traverse_blocks(host, file, action); - nlmsvc_traverse_shares(host, file, action); } - return nlm_traverse_locks(host, file, action); + file->f_locks = 0; + return 0; } /* * Loop over all files in the file table. */ static int -nlm_traverse_files(struct nlm_host *host, int action) +nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match) { struct hlist_node *pos, *next; struct nlm_file *file; @@ -240,7 +250,7 @@ nlm_traverse_files(struct nlm_host *host, int action) /* Traverse locks, blocks and shares of this file * and update file->f_locks count */ - if (nlm_inspect_file(host, file, action)) + if (nlm_inspect_file(host, file, match)) ret = 1; mutex_lock(&nlm_file_mutex); @@ -277,14 +287,46 @@ nlm_release_file(struct nlm_file *file) mutex_lock(&nlm_file_mutex); /* If there are no more locks etc, delete the file */ - if(--file->f_count == 0) { - if(!nlm_inspect_file(NULL, file, NLM_ACT_CHECK)) - nlm_delete_file(file); - } + if (--file->f_count == 0 && !nlm_file_inuse(file)) + nlm_delete_file(file); mutex_unlock(&nlm_file_mutex); } +/* + * Helpers function for resource traversal + * + * nlmsvc_mark_host: + * used by the garbage collector; simply sets h_inuse. + * Always returns 0. + * + * nlmsvc_same_host: + * returns 1 iff the two hosts match. Used to release + * all resources bound to a specific host. + * + * nlmsvc_is_client: + * returns 1 iff the host is a client. + * Used by nlmsvc_invalidate_all + */ +static int +nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy) +{ + host->h_inuse = 1; + return 0; +} + +static int +nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other) +{ + return host == other; +} + +static int +nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy) +{ + return host->h_server; +} + /* * Mark all hosts that still hold resources */ @@ -292,8 +334,7 @@ void nlmsvc_mark_resources(void) { dprintk("lockd: nlmsvc_mark_resources\n"); - - nlm_traverse_files(NULL, NLM_ACT_MARK); + nlm_traverse_files(NULL, nlmsvc_mark_host); } /* @@ -304,7 +345,7 @@ nlmsvc_free_host_resources(struct nlm_host *host) { dprintk("lockd: nlmsvc_free_host_resources\n"); - if (nlm_traverse_files(host, NLM_ACT_UNLOCK)) { + if (nlm_traverse_files(host, nlmsvc_same_host)) { printk(KERN_WARNING "lockd: couldn't remove all locks held by %s\n", host->h_name); @@ -319,8 +360,16 @@ void nlmsvc_invalidate_all(void) { struct nlm_host *host; + + /* Release all locks held by NFS clients. + * Previously, the code would call + * nlmsvc_free_host_resources for each client in + * turn, which is about as inefficient as it gets. + * Now we just do it once in nlm_traverse_files. + */ + nlm_traverse_files(NULL, nlmsvc_is_client); + while ((host = nlm_find_client()) != NULL) { - nlmsvc_free_host_resources(host); host->h_expires = 0; host->h_killed = 1; nlm_release_host(host); diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 777a91e1ac8f..8c1145669d06 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -133,13 +133,6 @@ struct nlm_block { struct nlm_file * b_file; /* file in question */ }; -/* - * Valid actions for nlmsvc_traverse_files - */ -#define NLM_ACT_CHECK 0 /* check for locks */ -#define NLM_ACT_MARK 1 /* mark & sweep */ -#define NLM_ACT_UNLOCK 2 /* release all locks */ - /* * Global variables */ @@ -182,6 +175,12 @@ struct nsm_handle *nsm_find(const struct sockaddr_in *, const char *, int); void nsm_release(struct nsm_handle *); +/* + * This is used in garbage collection and resource reclaim + * A return value != 0 means destroy the lock/block/share + */ +typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref); + /* * Server-side lock handling */ @@ -193,7 +192,7 @@ u32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *, u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); unsigned long nlmsvc_retry_blocked(void); void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, - int action); + nlm_host_match_fn_t match); void nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32); /* diff --git a/include/linux/lockd/share.h b/include/linux/lockd/share.h index c75a424ebe4c..cd7816e74c05 100644 --- a/include/linux/lockd/share.h +++ b/include/linux/lockd/share.h @@ -25,6 +25,7 @@ u32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *, struct nlm_args *); u32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *, struct nlm_args *); -void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, int); +void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, + nlm_host_match_fn_t); #endif /* LINUX_LOCKD_SHARE_H */ -- cgit v1.2.3 From 350fce8dbf43f7d441b77366851c9ce3cd28d6dc Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 4 Oct 2006 02:16:00 -0700 Subject: [PATCH] knfsd: simplify nlmsvc_invalidate_all As a result of previous patches, the loop in nlmsvc_invalidate_all just sets h_expires for all client/hosts to 0 (though does it in a very complicated way). This was possibly meant to trigger early garbage collection but half the time '0' is in the future and so it infact delays garbage collection. Pre-aging the 'hosts' is not really needed at this point anyway so we throw out the loop and nlm_find_client which is no longer needed. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/host.c | 27 --------------------------- fs/lockd/svcsubs.c | 10 +--------- include/linux/lockd/lockd.h | 4 +--- 3 files changed, 2 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 3b55fe5e94a2..1bf384307d15 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -192,33 +192,6 @@ nlm_destroy_host(struct nlm_host *host) kfree(host); } -struct nlm_host * -nlm_find_client(void) -{ - struct hlist_head *chain; - struct hlist_node *pos; - - /* find a nlm_host for a client for which h_killed == 0. - * and return it - */ - mutex_lock(&nlm_host_mutex); - for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { - struct nlm_host *host; - - hlist_for_each_entry(host, pos, chain, h_hash) { - if (host->h_server && - host->h_killed == 0) { - nlm_get_host(host); - mutex_unlock(&nlm_host_mutex); - return host; - } - } - } - mutex_unlock(&nlm_host_mutex); - return NULL; -} - - /* * Create the NLM RPC client for an NLM peer */ diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index bb13a48210f5..a1c7c0848415 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -354,13 +354,11 @@ nlmsvc_free_host_resources(struct nlm_host *host) } /* - * delete all hosts structs for clients + * Remove all locks held for clients */ void nlmsvc_invalidate_all(void) { - struct nlm_host *host; - /* Release all locks held by NFS clients. * Previously, the code would call * nlmsvc_free_host_resources for each client in @@ -368,10 +366,4 @@ nlmsvc_invalidate_all(void) * Now we just do it once in nlm_traverse_files. */ nlm_traverse_files(NULL, nlmsvc_is_client); - - while ((host = nlm_find_client()) != NULL) { - host->h_expires = 0; - host->h_killed = 1; - nlm_release_host(host); - } } diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 8c1145669d06..1fcf936d75b9 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -45,8 +45,7 @@ struct nlm_host { unsigned short h_proto; /* transport proto */ unsigned short h_reclaiming : 1, h_server : 1, /* server side, not client side */ - h_inuse : 1, - h_killed : 1; + h_inuse : 1; wait_queue_head_t h_gracewait; /* wait while reclaiming */ struct rw_semaphore h_rwsem; /* Reboot recovery lock */ u32 h_state; /* pseudo-state counter */ @@ -169,7 +168,6 @@ void nlm_rebind_host(struct nlm_host *); struct nlm_host * nlm_get_host(struct nlm_host *); void nlm_release_host(struct nlm_host *); void nlm_shutdown_hosts(void); -extern struct nlm_host *nlm_find_client(void); extern void nlm_host_rebooted(const struct sockaddr_in *, const char *, int, u32); struct nsm_handle *nsm_find(const struct sockaddr_in *, const char *, int); void nsm_release(struct nsm_handle *); -- cgit v1.2.3 From abd1f50094cad9dff6d68ada98b495549f52fc30 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:01 -0700 Subject: [PATCH] knfsd: lockd: optionally use hostnames for identifying peers This patch adds the nsm_use_hostnames sysctl and module param. If set, lockd will use the client's name (as given in the NLM arguments) to find the NSM handle. This makes recovery work when the NFS peer is multi-homed, and the reboot notification arrives from a different IP than the original lock calls. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/host.c | 6 +++++- fs/lockd/mon.c | 12 +++++++++--- fs/lockd/svc.c | 10 ++++++++++ include/linux/lockd/lockd.h | 1 + include/linux/lockd/sm_inter.h | 2 ++ 5 files changed, 27 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 1bf384307d15..a1423c66df04 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -462,7 +462,11 @@ __nsm_find(const struct sockaddr_in *sin, list_for_each(pos, &nsm_handles) { nsm = list_entry(pos, struct nsm_handle, sm_link); - if (!nlm_cmp_addr(&nsm->sm_addr, sin)) + if (hostname && nsm_use_hostnames) { + if (strlen(nsm->sm_name) != hostname_len + || memcmp(nsm->sm_name, hostname, hostname_len)) + continue; + } else if (!nlm_cmp_addr(&nsm->sm_addr, sin)) continue; atomic_inc(&nsm->sm_count); goto out; diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 626b6c116a6d..709cf7c80545 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -47,6 +47,7 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) } memset(&args, 0, sizeof(args)); + args.mon_name = nsm->sm_name; args.addr = nsm->sm_addr.sin_addr.s_addr; args.prog = NLM_PROGRAM; args.vers = 3; @@ -150,7 +151,7 @@ nsm_create(void) static u32 * xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) { - char buffer[20]; + char buffer[20], *name; /* * Use the dotted-quad IP address of the remote host as @@ -158,8 +159,13 @@ xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) * hostname first for whatever remote hostname it receives, * so this works alright. */ - sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); - if (!(p = xdr_encode_string(p, buffer)) + if (nsm_use_hostnames) { + name = argp->mon_name; + } else { + sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); + name = buffer; + } + if (!(p = xdr_encode_string(p, name)) || !(p = xdr_encode_string(p, utsname()->nodename))) return ERR_PTR(-EIO); *p++ = htonl(argp->prog); diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 3cc369e5693f..a3b7602cd383 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -61,6 +61,7 @@ static DECLARE_WAIT_QUEUE_HEAD(lockd_exit); static unsigned long nlm_grace_period; static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO; static int nlm_udpport, nlm_tcpport; +int nsm_use_hostnames = 0; /* * Constants needed for the sysctl interface. @@ -395,6 +396,14 @@ static ctl_table nlm_sysctls[] = { .extra1 = (int *) &nlm_port_min, .extra2 = (int *) &nlm_port_max, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nsm_use_hostnames", + .data = &nsm_use_hostnames, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { .ctl_name = 0 } }; @@ -483,6 +492,7 @@ module_param_call(nlm_udpport, param_set_port, param_get_int, &nlm_udpport, 0644); module_param_call(nlm_tcpport, param_set_port, param_get_int, &nlm_tcpport, 0644); +module_param(nsm_use_hostnames, bool, 0644); /* * Initialising and terminating the module. diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 1fcf936d75b9..7be7aeaeee58 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -142,6 +142,7 @@ extern struct svc_procedure nlmsvc_procedures4[]; #endif extern int nlmsvc_grace_period; extern unsigned long nlmsvc_timeout; +extern int nsm_use_hostnames; /* * Lockd client functions diff --git a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h index d93b074668ce..daef509bb9b3 100644 --- a/include/linux/lockd/sm_inter.h +++ b/include/linux/lockd/sm_inter.h @@ -28,6 +28,8 @@ struct nsm_args { u32 prog; /* RPC callback info */ u32 vers; u32 proc; + + char * mon_name; }; /* -- cgit v1.2.3 From 031d869d0e0be18cfe35526be5608225b8f0a7be Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:02 -0700 Subject: [PATCH] knfsd: make nlmclnt_next_cookie SMP safe The way we incremented the NLM cookie in nlmclnt_next_cookie was not thread safe. This patch changes the counter to an atomic_t Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntproc.c | 10 +++++----- include/linux/lockd/lockd.h | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 7e6f22e2a3b4..3d84f600b633 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -36,14 +36,14 @@ static const struct rpc_call_ops nlmclnt_cancel_ops; /* * Cookie counter for NLM requests */ -static u32 nlm_cookie = 0x1234; +static atomic_t nlm_cookie = ATOMIC_INIT(0x1234); -static inline void nlmclnt_next_cookie(struct nlm_cookie *c) +void nlmclnt_next_cookie(struct nlm_cookie *c) { - memcpy(c->data, &nlm_cookie, 4); - memset(c->data+4, 0, 4); + u32 cookie = atomic_inc_return(&nlm_cookie); + + memcpy(c->data, &cookie, 4); c->len=4; - nlm_cookie++; } static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner) diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 7be7aeaeee58..a345650e5622 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -157,6 +157,7 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout) u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *); void nlmclnt_recovery(struct nlm_host *); int nlmclnt_reclaim(struct nlm_host *, struct file_lock *); +void nlmclnt_next_cookie(struct nlm_cookie *); /* * Host cache -- cgit v1.2.3 From 39be4502cb75dc26007fe1659735b26c8e63fcc6 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:03 -0700 Subject: [PATCH] knfsd: match GRANTED_RES replies using cookies When we send a GRANTED_MSG call, we current copy the NLM cookie provided in the original LOCK call - because in 1996, some broken clients seemed to rely on this bug. However, this means the cookies are not unique, so that when the client's GRANTED_RES message comes back, we cannot simply match it based on the cookie, but have to use the client's IP address in addition. Which breaks when you have a multi-homed NFS client. The X/Open spec explicitly mentions that clients should not expect the same cookie; so one may hope that any clients that were broken in 1996 have either been fixed or rendered obsolete. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svc4proc.c | 2 +- fs/lockd/svclock.c | 24 +++++++++++++----------- fs/lockd/svcproc.c | 2 +- include/linux/lockd/lockd.h | 2 +- 4 files changed, 16 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index b8525fb62934..fa370f6eb07b 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -455,7 +455,7 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, dprintk("lockd: GRANTED_RES called\n"); - nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); + nlmsvc_grant_reply(&argp->cookie, argp->status); return rpc_success; } diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 1f91567a1b88..3d2b8a831be5 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -139,19 +139,19 @@ static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b) * Find a block with a given NLM cookie. */ static inline struct nlm_block * -nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin) +nlmsvc_find_block(struct nlm_cookie *cookie) { struct nlm_block *block; list_for_each_entry(block, &nlm_blocked, b_list) { - if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie) - && nlm_cmp_addr(sin, &block->b_host->h_addr)) + if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)) goto found; } return NULL; found: + dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block); kref_get(&block->b_count); return block; } @@ -165,6 +165,11 @@ found: * request, but (as I found out later) that's because some implementations * do just this. Never mind the standards comittees, they support our * logging industries. + * + * 10 years later: I hope we can safely ignore these old and broken + * clients by now. Let's fix this so we can uniquely identify an incoming + * GRANTED_RES message by cookie, without having to rely on the client's IP + * address. --okir */ static inline struct nlm_block * nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, @@ -197,7 +202,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, /* Set notifier function for VFS, and init args */ call->a_args.lock.fl.fl_flags |= FL_SLEEP; call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations; - call->a_args.cookie = *cookie; /* see above */ + nlmclnt_next_cookie(&call->a_args.cookie); dprintk("lockd: created block %p...\n", block); @@ -640,17 +645,14 @@ static const struct rpc_call_ops nlmsvc_grant_ops = { * block. */ void -nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status) +nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status) { struct nlm_block *block; - struct nlm_file *file; - dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n", - *(unsigned int *)(cookie->data), - ntohl(rqstp->rq_addr.sin_addr.s_addr), status); - if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr))) + dprintk("grant_reply: looking for cookie %x, s=%d \n", + *(unsigned int *)(cookie->data), status); + if (!(block = nlmsvc_find_block(cookie))) return; - file = block->b_file; if (block) { if (status == NLM_LCK_DENIED_GRACE_PERIOD) { diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 66e7b0b3430e..75b2c81bcb93 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -484,7 +484,7 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, dprintk("lockd: GRANTED_RES called\n"); - nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); + nlmsvc_grant_reply(&argp->cookie, argp->status); return rpc_success; } diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index a345650e5622..5920ecaeed66 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -193,7 +193,7 @@ u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); unsigned long nlmsvc_retry_blocked(void); void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, nlm_host_match_fn_t match); -void nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32); +void nlmsvc_grant_reply(struct nlm_cookie *, u32); /* * File handling for the server personality -- cgit v1.2.3 From 460f5cac1e24e947509b6112c99c5bc9ff687b45 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:03 -0700 Subject: [PATCH] knfsd: export nsm_local_state to user space via sysctl Every NLM call includes the client's NSM state. Currently, the Linux client always reports 0 - which seems not to cause any problems, but is not what the protocol says. This patch exposes the kernel's internal variable to user space via a sysctl, which can be set at system boot time by statd. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/mon.c | 2 +- fs/lockd/svc.c | 9 +++++++++ include/linux/lockd/sm_inter.h | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 709cf7c80545..e0179f8c327f 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -24,7 +24,7 @@ static struct rpc_program nsm_program; /* * Local NSM state */ -u32 nsm_local_state; +int nsm_local_state; /* * Common procedure for SM_MON/SM_UNMON calls diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index a3b7602cd383..634139232aaf 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #define NLMDBG_FACILITY NLMDBG_SVC @@ -404,6 +405,14 @@ static ctl_table nlm_sysctls[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nsm_local_state", + .data = &nsm_local_state, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { .ctl_name = 0 } }; diff --git a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h index daef509bb9b3..fc61d40964da 100644 --- a/include/linux/lockd/sm_inter.h +++ b/include/linux/lockd/sm_inter.h @@ -42,6 +42,6 @@ struct nsm_res { int nsm_monitor(struct nlm_host *); int nsm_unmonitor(struct nlm_host *); -extern u32 nsm_local_state; +extern int nsm_local_state; #endif /* LINUX_LOCKD_SM_INTER_H */ -- cgit v1.2.3 From bc5fea4299b8bda5f73c6f79dc35d388caf8bced Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 4 Oct 2006 02:16:05 -0700 Subject: [PATCH] knfsd: register all RPC programs with portmapper by default The NFSACL patches introduced support for multiple RPC services listening on the same transport. However, only the first of these services was registered with portmapper. This was perfectly fine for nfsacl, as you traditionally do not want these to show up in a portmapper listing. The patch below changes the default behavior to always register all services listening on a given transport, but retains the old behavior for nfsacl services. Signed-off-by: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs2acl.c | 1 + fs/nfsd/nfs3acl.c | 1 + include/linux/sunrpc/svc.h | 3 +++ net/sunrpc/svc.c | 37 +++++++++++++++++++++++-------------- 4 files changed, 28 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 71108da2e54e..9187755661df 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -333,4 +333,5 @@ struct svc_version nfsd_acl_version2 = { .vs_proc = nfsd_acl_procedures2, .vs_dispatch = nfsd_dispatch, .vs_xdrsize = NFS3_SVC_XDRSIZE, + .vs_hidden = 1, }; diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index f813b054f4a1..d4bdc00c1169 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -263,5 +263,6 @@ struct svc_version nfsd_acl_version3 = { .vs_proc = nfsd_acl_procedures3, .vs_dispatch = nfsd_dispatch, .vs_xdrsize = NFS3_SVC_XDRSIZE, + .vs_hidden = 1, }; diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 74e52c245da4..d6288e89fd9d 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -321,6 +321,9 @@ struct svc_version { struct svc_procedure * vs_proc; /* per-procedure info */ u32 vs_xdrsize; /* xdrsize needed for this version */ + unsigned int vs_hidden : 1; /* Don't register with portmapper. + * Only used for nfsacl so far. */ + /* Override dispatch function (e.g. when caching replies). * A return value of 0 means drop the request. * vs_dispatch == NULL means use default dispatcher. diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index b252401c8601..550441d13a08 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -644,23 +644,32 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port) unsigned long flags; int i, error = 0, dummy; - progp = serv->sv_program; - - dprintk("RPC: svc_register(%s, %s, %d)\n", - progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port); - if (!port) clear_thread_flag(TIF_SIGPENDING); - for (i = 0; i < progp->pg_nvers; i++) { - if (progp->pg_vers[i] == NULL) - continue; - error = rpc_register(progp->pg_prog, i, proto, port, &dummy); - if (error < 0) - break; - if (port && !dummy) { - error = -EACCES; - break; + for (progp = serv->sv_program; progp; progp = progp->pg_next) { + for (i = 0; i < progp->pg_nvers; i++) { + if (progp->pg_vers[i] == NULL) + continue; + + dprintk("RPC: svc_register(%s, %s, %d, %d)%s\n", + progp->pg_name, + proto == IPPROTO_UDP? "udp" : "tcp", + port, + i, + progp->pg_vers[i]->vs_hidden? + " (but not telling portmap)" : ""); + + if (progp->pg_vers[i]->vs_hidden) + continue; + + error = rpc_register(progp->pg_prog, i, proto, port, &dummy); + if (error < 0) + break; + if (port && !dummy) { + error = -EACCES; + break; + } } } -- cgit v1.2.3 From 89e63ef609fb0064a47281e31e38010159c32d57 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Wed, 4 Oct 2006 02:16:06 -0700 Subject: [PATCH] Convert lockd to use the newer mutex instead of the older semaphore Both the (recently introduces) nsm_sema and the older f_sema are converted over. Cc: Olaf Kirch Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/host.c | 11 ++++++----- fs/lockd/svclock.c | 22 +++++++++++----------- fs/lockd/svcsubs.c | 2 +- include/linux/lockd/lockd.h | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index a1423c66df04..0257a5594524 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -436,7 +436,7 @@ nlm_gc_hosts(void) * Manage NSM handles */ static LIST_HEAD(nsm_handles); -static DECLARE_MUTEX(nsm_sema); +static DEFINE_MUTEX(nsm_mutex); static struct nsm_handle * __nsm_find(const struct sockaddr_in *sin, @@ -458,7 +458,7 @@ __nsm_find(const struct sockaddr_in *sin, return NULL; } - down(&nsm_sema); + mutex_lock(&nsm_mutex); list_for_each(pos, &nsm_handles) { nsm = list_entry(pos, struct nsm_handle, sm_link); @@ -488,7 +488,8 @@ __nsm_find(const struct sockaddr_in *sin, list_add(&nsm->sm_link, &nsm_handles); } -out: up(&nsm_sema); +out: + mutex_unlock(&nsm_mutex); return nsm; } @@ -507,11 +508,11 @@ nsm_release(struct nsm_handle *nsm) if (!nsm) return; if (atomic_dec_and_test(&nsm->sm_count)) { - down(&nsm_sema); + mutex_lock(&nsm_mutex); if (atomic_read(&nsm->sm_count) == 0) { list_del(&nsm->sm_link); kfree(nsm); } - up(&nsm_sema); + mutex_unlock(&nsm_mutex); } } diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 3d2b8a831be5..814c6064c9e0 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -254,9 +254,9 @@ static void nlmsvc_free_block(struct kref *kref) dprintk("lockd: freeing block %p...\n", block); /* Remove block from file's list of blocks */ - down(&file->f_sema); + mutex_lock(&file->f_mutex); list_del_init(&block->b_flist); - up(&file->f_sema); + mutex_unlock(&file->f_mutex); nlmsvc_freegrantargs(block->b_call); nlm_release_call(block->b_call); @@ -281,7 +281,7 @@ void nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_block *block, *next; restart: - down(&file->f_sema); + mutex_lock(&file->f_mutex); list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) { if (!match(block->b_host, host)) continue; @@ -290,12 +290,12 @@ restart: if (list_empty(&block->b_list)) continue; kref_get(&block->b_count); - up(&file->f_sema); + mutex_unlock(&file->f_mutex); nlmsvc_unlink_block(block); nlmsvc_release_block(block); goto restart; } - up(&file->f_sema); + mutex_unlock(&file->f_mutex); } /* @@ -354,7 +354,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, lock->fl.fl_flags &= ~FL_SLEEP; again: /* Lock file against concurrent access */ - down(&file->f_sema); + mutex_lock(&file->f_mutex); /* Get existing block (in case client is busy-waiting) */ block = nlmsvc_lookup_block(file, lock); if (block == NULL) { @@ -392,10 +392,10 @@ again: /* If we don't have a block, create and initialize it. Then * retry because we may have slept in kmalloc. */ - /* We have to release f_sema as nlmsvc_create_block may try to + /* We have to release f_mutex as nlmsvc_create_block may try to * to claim it while doing host garbage collection */ if (newblock == NULL) { - up(&file->f_sema); + mutex_unlock(&file->f_mutex); dprintk("lockd: blocking on this lock (allocating).\n"); if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie))) return nlm_lck_denied_nolocks; @@ -405,7 +405,7 @@ again: /* Append to list of blocked */ nlmsvc_insert_block(newblock, NLM_NEVER); out: - up(&file->f_sema); + mutex_unlock(&file->f_mutex); nlmsvc_release_block(newblock); nlmsvc_release_block(block); dprintk("lockd: nlmsvc_lock returned %u\n", ret); @@ -489,9 +489,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) (long long)lock->fl.fl_start, (long long)lock->fl.fl_end); - down(&file->f_sema); + mutex_lock(&file->f_mutex); block = nlmsvc_lookup_block(file, lock); - up(&file->f_sema); + mutex_unlock(&file->f_mutex); if (block != NULL) { status = nlmsvc_unlink_block(block); nlmsvc_release_block(block); diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index a1c7c0848415..514f5f20701e 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -106,7 +106,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, goto out_unlock; memcpy(&file->f_handle, f, sizeof(struct nfs_fh)); - init_MUTEX(&file->f_sema); + mutex_init(&file->f_mutex); INIT_HLIST_NODE(&file->f_list); INIT_LIST_HEAD(&file->f_blocks); diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 5920ecaeed66..2909619c0295 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -111,7 +111,7 @@ struct nlm_file { struct list_head f_blocks; /* blocked locks */ unsigned int f_locks; /* guesstimate # of locks */ unsigned int f_count; /* reference count */ - struct semaphore f_sema; /* avoid concurrent access */ + struct mutex f_mutex; /* avoid concurrent access */ }; /* -- cgit v1.2.3 From b009a873de05c6e0d7613df3584b6dcb2e4280ee Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:17 -0700 Subject: [PATCH] knfsd: nfsd: store export path in export Store the export path in the svc_export structure instead of storing only the dentry. This will prevent the need for additional d_path calls to provide NFSv4 fs_locations support. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/export.c | 10 ++++++++++ include/linux/nfsd/export.h | 1 + 2 files changed, 11 insertions(+) (limited to 'include/linux') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 597b3cbf8b0b..d3178de589e4 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -325,6 +325,7 @@ static void svc_export_put(struct kref *ref) dput(exp->ex_dentry); mntput(exp->ex_mnt); auth_domain_put(exp->ex_client); + kfree(exp->ex_path); kfree(exp); } @@ -398,6 +399,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) int an_int; nd.dentry = NULL; + exp.ex_path = NULL; if (mesg[mlen-1] != '\n') return -EINVAL; @@ -428,6 +430,10 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) exp.ex_client = dom; exp.ex_mnt = nd.mnt; exp.ex_dentry = nd.dentry; + exp.ex_path = kstrdup(buf, GFP_KERNEL); + err = -ENOMEM; + if (!exp.ex_path) + goto out; /* expiry */ err = -EINVAL; @@ -473,6 +479,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) else exp_put(expp); out: + kfree(exp.ex_path); if (nd.dentry) path_release(&nd); out_no_path: @@ -524,6 +531,7 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) new->ex_client = item->ex_client; new->ex_dentry = dget(item->ex_dentry); new->ex_mnt = mntget(item->ex_mnt); + new->ex_path = NULL; } static void export_update(struct cache_head *cnew, struct cache_head *citem) @@ -535,6 +543,8 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) new->ex_anon_uid = item->ex_anon_uid; new->ex_anon_gid = item->ex_anon_gid; new->ex_fsid = item->ex_fsid; + new->ex_path = item->ex_path; + item->ex_path = NULL; } static struct cache_head *svc_export_alloc(void) diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index d2a8abb5011a..47d96684b611 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -51,6 +51,7 @@ struct svc_export { int ex_flags; struct vfsmount * ex_mnt; struct dentry * ex_dentry; + char * ex_path; uid_t ex_anon_uid; gid_t ex_anon_gid; int ex_fsid; -- cgit v1.2.3 From 933469190ed5915b0568bc564346bb8db718f460 Mon Sep 17 00:00:00 2001 From: Manoj Naik Date: Wed, 4 Oct 2006 02:16:18 -0700 Subject: [PATCH] knfsd: nfsd4: fslocations data structures Define FS locations structures, some functions to manipulate them, and add code to parse FS locations in downcall and add to the exports structure. [bfields@fieldses.org: bunch of fixes and cleanups] Signed-off-by: Manoj Naik Signed-off-by: Fred Isaman Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/export.c | 118 ++++++++++++++++++++++++++++++++++++++++++-- include/linux/nfsd/export.h | 20 ++++++++ 2 files changed, 134 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index d3178de589e4..e13fa23bd108 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -319,6 +319,17 @@ svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) static struct cache_head *export_table[EXPORT_HASHMAX]; +static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc) +{ + int i; + + for (i = 0; i < fsloc->locations_count; i++) { + kfree(fsloc->locations[i].path); + kfree(fsloc->locations[i].hosts); + } + kfree(fsloc->locations); +} + static void svc_export_put(struct kref *ref) { struct svc_export *exp = container_of(ref, struct svc_export, h.ref); @@ -326,6 +337,7 @@ static void svc_export_put(struct kref *ref) mntput(exp->ex_mnt); auth_domain_put(exp->ex_client); kfree(exp->ex_path); + nfsd4_fslocs_free(&exp->ex_fslocs); kfree(exp); } @@ -387,6 +399,69 @@ static int check_export(struct inode *inode, int flags) } +#ifdef CONFIG_NFSD_V4 + +static int +fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) +{ + int len; + int migrated, i, err; + + len = qword_get(mesg, buf, PAGE_SIZE); + if (len != 5 || memcmp(buf, "fsloc", 5)) + return 0; + + /* listsize */ + err = get_int(mesg, &fsloc->locations_count); + if (err) + return err; + if (fsloc->locations_count > MAX_FS_LOCATIONS) + return -EINVAL; + if (fsloc->locations_count == 0) + return 0; + + fsloc->locations = kzalloc(fsloc->locations_count + * sizeof(struct nfsd4_fs_location), GFP_KERNEL); + if (!fsloc->locations) + return -ENOMEM; + for (i=0; i < fsloc->locations_count; i++) { + /* colon separated host list */ + err = -EINVAL; + len = qword_get(mesg, buf, PAGE_SIZE); + if (len <= 0) + goto out_free_all; + err = -ENOMEM; + fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL); + if (!fsloc->locations[i].hosts) + goto out_free_all; + err = -EINVAL; + /* slash separated path component list */ + len = qword_get(mesg, buf, PAGE_SIZE); + if (len <= 0) + goto out_free_all; + err = -ENOMEM; + fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL); + if (!fsloc->locations[i].path) + goto out_free_all; + } + /* migrated */ + err = get_int(mesg, &migrated); + if (err) + goto out_free_all; + err = -EINVAL; + if (migrated < 0 || migrated > 1) + goto out_free_all; + fsloc->migrated = migrated; + return 0; +out_free_all: + nfsd4_fslocs_free(fsloc); + return err; +} + +#else /* CONFIG_NFSD_V4 */ +static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; } +#endif + static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) { /* client path expiry [flags anonuid anongid fsid] */ @@ -441,6 +516,11 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) if (exp.h.expiry_time == 0) goto out; + /* fs locations */ + exp.ex_fslocs.locations = NULL; + exp.ex_fslocs.locations_count = 0; + exp.ex_fslocs.migrated = 0; + /* flags */ err = get_int(&mesg, &an_int); if (err == -ENOENT) @@ -466,6 +546,10 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) err = check_export(nd.dentry->d_inode, exp.ex_flags); if (err) goto out; + + err = fsloc_parse(&mesg, buf, &exp.ex_fslocs); + if (err) + goto out; } expp = svc_export_lookup(&exp); @@ -489,7 +573,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) return err; } -static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong); +static void exp_flags(struct seq_file *m, int flag, int fsid, + uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs); static int svc_export_show(struct seq_file *m, struct cache_detail *cd, @@ -508,8 +593,8 @@ static int svc_export_show(struct seq_file *m, seq_putc(m, '('); if (test_bit(CACHE_VALID, &h->flags) && !test_bit(CACHE_NEGATIVE, &h->flags)) - exp_flags(m, exp->ex_flags, exp->ex_fsid, - exp->ex_anon_uid, exp->ex_anon_gid); + exp_flags(m, exp->ex_flags, exp->ex_fsid, + exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs); seq_puts(m, ")\n"); return 0; } @@ -532,6 +617,9 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) new->ex_dentry = dget(item->ex_dentry); new->ex_mnt = mntget(item->ex_mnt); new->ex_path = NULL; + new->ex_fslocs.locations = NULL; + new->ex_fslocs.locations_count = 0; + new->ex_fslocs.migrated = 0; } static void export_update(struct cache_head *cnew, struct cache_head *citem) @@ -545,6 +633,12 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) new->ex_fsid = item->ex_fsid; new->ex_path = item->ex_path; item->ex_path = NULL; + new->ex_fslocs.locations = item->ex_fslocs.locations; + item->ex_fslocs.locations = NULL; + new->ex_fslocs.locations_count = item->ex_fslocs.locations_count; + item->ex_fslocs.locations_count = 0; + new->ex_fslocs.migrated = item->ex_fslocs.migrated; + item->ex_fslocs.migrated = 0; } static struct cache_head *svc_export_alloc(void) @@ -1159,7 +1253,8 @@ static struct flags { { 0, {"", ""}} }; -static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong) +static void exp_flags(struct seq_file *m, int flag, int fsid, + uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc) { int first = 0; struct flags *flg; @@ -1175,6 +1270,21 @@ static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t seq_printf(m, "%sanonuid=%d", first++?",":"", anonu); if (anong != (gid_t)-2 && anong != (0x10000-2)) seq_printf(m, "%sanongid=%d", first++?",":"", anong); + if (fsloc && fsloc->locations_count > 0) { + char *loctype = (fsloc->migrated) ? "refer" : "replicas"; + int i; + + seq_printf(m, "%s%s=", first++?",":"", loctype); + seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\"); + seq_putc(m, '@'); + seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\"); + for (i = 1; i < fsloc->locations_count; i++) { + seq_putc(m, ';'); + seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\"); + seq_putc(m, '@'); + seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\"); + } + } } static int e_show(struct seq_file *m, void *p) diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 47d96684b611..6e78ea969f49 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -45,6 +45,25 @@ #ifdef __KERNEL__ +/* + * FS Locations + */ + +#define MAX_FS_LOCATIONS 128 + +struct nfsd4_fs_location { + char *hosts; /* colon separated list of hosts */ + char *path; /* slash separated list of path components */ +}; + +struct nfsd4_fs_locations { + uint32_t locations_count; + struct nfsd4_fs_location *locations; +/* If we're not actually serving this data ourselves (only providing a + * list of replicas that do serve it) then we set "migrated": */ + int migrated; +}; + struct svc_export { struct cache_head h; struct auth_domain * ex_client; @@ -55,6 +74,7 @@ struct svc_export { uid_t ex_anon_uid; gid_t ex_anon_gid; int ex_fsid; + struct nfsd4_fs_locations ex_fslocs; }; /* an "export key" (expkey) maps a filehandlefragement to an -- cgit v1.2.3 From 81c3f4130202a1dcb2b28ab56684eb5e9d43d8c1 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:19 -0700 Subject: [PATCH] knfsd: nfsd4: xdr encoding for fs_locations Encode fs_locations attribute. Signed-off-by: Manoj Naik Signed-off-by: Fred Isaman Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4xdr.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/nfsd/nfsd.h | 3 +- 2 files changed, 126 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4cfacc557b40..0589852007e6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1223,6 +1223,119 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) stateowner->so_replay.rp_buflen); \ } } while (0); +/* Encode as an array of strings the string given with components + * seperated @sep. + */ +static int nfsd4_encode_components(char sep, char *components, + u32 **pp, int *buflen) +{ + u32 *p = *pp; + u32 *countp = p; + int strlen, count=0; + char *str, *end; + + dprintk("nfsd4_encode_components(%s)\n", components); + if ((*buflen -= 4) < 0) + return nfserr_resource; + WRITE32(0); /* We will fill this in with @count later */ + end = str = components; + while (*end) { + for (; *end && (*end != sep); end++) + ; /* Point to end of component */ + strlen = end - str; + if (strlen) { + if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0) + return nfserr_resource; + WRITE32(strlen); + WRITEMEM(str, strlen); + count++; + } + else + end++; + str = end; + } + *pp = p; + p = countp; + WRITE32(count); + return 0; +} + +/* + * encode a location element of a fs_locations structure + */ +static int nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, + u32 **pp, int *buflen) +{ + int status; + u32 *p = *pp; + + status = nfsd4_encode_components(':', location->hosts, &p, buflen); + if (status) + return status; + status = nfsd4_encode_components('/', location->path, &p, buflen); + if (status) + return status; + *pp = p; + return 0; +} + +/* + * Return the path to an export point in the pseudo filesystem namespace + * Returned string is safe to use as long as the caller holds a reference + * to @exp. + */ +static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp) +{ + struct svc_fh tmp_fh; + char *path, *rootpath; + int stat; + + fh_init(&tmp_fh, NFS4_FHSIZE); + stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle); + if (stat) + return ERR_PTR(stat); + rootpath = tmp_fh.fh_export->ex_path; + + path = exp->ex_path; + + if (strncmp(path, rootpath, strlen(rootpath))) { + printk("nfsd: fs_locations failed;" + "%s is not contained in %s\n", path, rootpath); + return ERR_PTR(-EOPNOTSUPP); + } + + return path + strlen(rootpath); +} + +/* + * encode a fs_locations structure + */ +static int nfsd4_encode_fs_locations(struct svc_rqst *rqstp, + struct svc_export *exp, + u32 **pp, int *buflen) +{ + int status, i; + u32 *p = *pp; + struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; + char *root = nfsd4_path(rqstp, exp); + + if (IS_ERR(root)) + return PTR_ERR(root); + status = nfsd4_encode_components('/', root, &p, buflen); + if (status) + return status; + if ((*buflen -= 4) < 0) + return nfserr_resource; + WRITE32(fslocs->locations_count); + for (i=0; ilocations_count; i++) { + status = nfsd4_encode_fs_location4(&fslocs->locations[i], + &p, buflen); + if (status) + return status; + } + *pp = p; + return 0; +} static u32 nfs4_ftypes[16] = { NF4BAD, NF4FIFO, NF4CHR, NF4BAD, @@ -1334,6 +1447,11 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, goto out_nfserr; } } + if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { + if (exp->ex_fslocs.locations == NULL) { + bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS; + } + } if ((buflen -= 16) < 0) goto out_resource; @@ -1513,6 +1631,13 @@ out_acl: goto out_resource; WRITE64((u64) statfs.f_files); } + if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { + status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen); + if (status == nfserr_resource) + goto out_resource; + if (status) + goto out; + } if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) { if ((buflen -= 4) < 0) goto out_resource; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 259841bb2f6c..8094142d95ea 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -292,7 +292,6 @@ static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh) /* * The following attributes are currently not supported by the NFSv4 server: * ARCHIVE (deprecated anyway) - * FS_LOCATIONS (will be supported eventually) * HIDDEN (unlikely to be supported any time soon) * MIMETYPE (unlikely to be supported any time soon) * QUOTA_* (will be supported in a forthcoming patch) @@ -308,7 +307,7 @@ static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh) | FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_CANSETTIME | FATTR4_WORD0_CASE_INSENSITIVE \ | FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED \ | FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FILEID | FATTR4_WORD0_FILES_AVAIL \ - | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_HOMOGENEOUS \ + | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS \ | FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \ | FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL) -- cgit v1.2.3 From 42ca09938157105c1f573c831a35e9c3e02eb354 Mon Sep 17 00:00:00 2001 From: "J.Bruce Fields" Date: Wed, 4 Oct 2006 02:16:20 -0700 Subject: [PATCH] knfsd: nfsd4: actually use all the pieces to implement referrals Use all the pieces set up so far to implement referral support, allowing return of NFS4ERR_MOVED and fs_locations attribute. Signed-off-by: Manoj Naik Signed-off-by: Fred Isaman Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4proc.c | 30 +++++++++++++++++++++------- fs/nfsd/nfs4xdr.c | 51 +++++++++++++++++++++++++++++++++++++++++------ include/linux/nfsd/nfsd.h | 1 + 3 files changed, 69 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 38b0f91175d0..8333db12caca 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -802,13 +802,29 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH * require a valid current filehandle */ - if ((!current_fh->fh_dentry) && - !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) || - (op->opnum == OP_SETCLIENTID) || - (op->opnum == OP_SETCLIENTID_CONFIRM) || - (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) || - (op->opnum == OP_RELEASE_LOCKOWNER))) { - op->status = nfserr_nofilehandle; + if (!current_fh->fh_dentry) { + if (!((op->opnum == OP_PUTFH) || + (op->opnum == OP_PUTROOTFH) || + (op->opnum == OP_SETCLIENTID) || + (op->opnum == OP_SETCLIENTID_CONFIRM) || + (op->opnum == OP_RENEW) || + (op->opnum == OP_RESTOREFH) || + (op->opnum == OP_RELEASE_LOCKOWNER))) { + op->status = nfserr_nofilehandle; + goto encode_op; + } + } + /* Check must be done at start of each operation, except + * for GETATTR and ops not listed as returning NFS4ERR_MOVED + */ + else if (current_fh->fh_export->ex_fslocs.migrated && + !((op->opnum == OP_GETATTR) || + (op->opnum == OP_PUTROOTFH) || + (op->opnum == OP_PUTPUBFH) || + (op->opnum == OP_RENEW) || + (op->opnum == OP_SETCLIENTID) || + (op->opnum == OP_RELEASE_LOCKOWNER))) { + op->status = nfserr_moved; goto encode_op; } switch (op->opnum) { diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0589852007e6..41fc241b729a 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -60,6 +60,14 @@ #define NFSDDBG_FACILITY NFSDDBG_XDR +/* + * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing + * directory in order to indicate to the client that a filesystem boundary is present + * We use a fixed fsid for a referral + */ +#define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL +#define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL + static int check_filename(char *str, int len, int err) { @@ -1385,6 +1393,25 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen); } +#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ + FATTR4_WORD0_RDATTR_ERROR) +#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID + +static int fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) +{ + /* As per referral draft: */ + if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS || + *bmval1 & ~WORD1_ABSENT_FS_ATTRS) { + if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR || + *bmval0 & FATTR4_WORD0_FS_LOCATIONS) + *rdattr_err = NFSERR_MOVED; + else + return nfserr_moved; + } + *bmval0 &= WORD0_ABSENT_FS_ATTRS; + *bmval1 &= WORD1_ABSENT_FS_ATTRS; + return 0; +} /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle @@ -1407,6 +1434,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, u32 *attrlenp; u32 dummy; u64 dummy64; + u32 rdattr_err = 0; u32 *p = buffer; int status; int aclsupport = 0; @@ -1416,6 +1444,12 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0); BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1); + if (exp->ex_fslocs.migrated) { + status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err); + if (status) + goto out; + } + status = vfs_getattr(exp->ex_mnt, dentry, &stat); if (status) goto out_nfserr; @@ -1461,12 +1495,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, attrlenp = p++; /* to be backfilled later */ if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { + u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0; if ((buflen -= 12) < 0) goto out_resource; + if (!aclsupport) + word0 &= ~FATTR4_WORD0_ACL; + if (!exp->ex_fslocs.locations) + word0 &= ~FATTR4_WORD0_FS_LOCATIONS; WRITE32(2); - WRITE32(aclsupport ? - NFSD_SUPPORTED_ATTRS_WORD0 : - NFSD_SUPPORTED_ATTRS_WORD0 & ~FATTR4_WORD0_ACL); + WRITE32(word0); WRITE32(NFSD_SUPPORTED_ATTRS_WORD1); } if (bmval0 & FATTR4_WORD0_TYPE) { @@ -1520,7 +1557,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, if (bmval0 & FATTR4_WORD0_FSID) { if ((buflen -= 16) < 0) goto out_resource; - if (is_fsid(fhp, rqstp->rq_reffh)) { + if (exp->ex_fslocs.migrated) { + WRITE64(NFS4_REFERRAL_FSID_MAJOR); + WRITE64(NFS4_REFERRAL_FSID_MINOR); + } else if (is_fsid(fhp, rqstp->rq_reffh)) { WRITE64((u64)exp->ex_fsid); WRITE64((u64)0); } else { @@ -1543,7 +1583,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { if ((buflen -= 4) < 0) goto out_resource; - WRITE32(0); + WRITE32(rdattr_err); } if (bmval0 & FATTR4_WORD0_ACL) { struct nfs4_ace *ace; @@ -1970,7 +2010,6 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_ge nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry, resp->p, &buflen, getattr->ga_bmval, resp->rqstp); - if (!nfserr) resp->p += buflen; return nfserr; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 8094142d95ea..d0d4aae7085f 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -216,6 +216,7 @@ void nfsd_lockd_shutdown(void); #define nfserr_clid_inuse __constant_htonl(NFSERR_CLID_INUSE) #define nfserr_stale_clientid __constant_htonl(NFSERR_STALE_CLIENTID) #define nfserr_resource __constant_htonl(NFSERR_RESOURCE) +#define nfserr_moved __constant_htonl(NFSERR_MOVED) #define nfserr_nofilehandle __constant_htonl(NFSERR_NOFILEHANDLE) #define nfserr_minor_vers_mismatch __constant_htonl(NFSERR_MINOR_VERS_MISMATCH) #define nfserr_share_denied __constant_htonl(NFSERR_SHARE_DENIED) -- cgit v1.2.3 From f7aa2638f288f4c67acdb55947472740bd27d27a Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Wed, 4 Oct 2006 02:16:21 -0700 Subject: [PATCH] Fix linux/nfsd/const.h for make headers_check make headers_check fails on linux/nfsd/const.h. Since linux/sunrpc/msg_prot.h does not seem to export anything interesting for userspace, this patch moves it in the __KERNEL__ protected section. Signed-off-by: Cedric Le Goater Cc: David Woodhouse Cc: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/nfsd/const.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h index f478066f9cd5..f0cc77790527 100644 --- a/include/linux/nfsd/const.h +++ b/include/linux/nfsd/const.h @@ -13,7 +13,6 @@ #include #include #include -#include /* * Maximum protocol version supported by knfsd @@ -29,6 +28,8 @@ #ifdef __KERNEL__ +#include + #ifndef NFS_SUPER_MAGIC # define NFS_SUPER_MAGIC 0x6969 #endif -- cgit v1.2.3 From a24ceab4f44f21749aa0b6bd38bee37c775e036f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:27 -0700 Subject: [PATCH] genirq: irq: convert the move_irq flag from a 32bit word to a single bit The primary aim of this patchset is to remove maintenances problems caused by the irq infrastructure. The two big issues I address are an artificially small cap on the number of irqs, and that MSI assumes vector == irq. My primary focus is on x86_64 but I have touched other architectures where necessary to keep them from breaking. - To increase the number of irqs I modify the code to look at the (cpu, vector) pair instead of just looking at the vector. With a large number of irqs available systems with a large irq count no longer need to compress their irq numbers to fit. Removing a lot of brittle special cases. For acpi guys the result is that irq == gsi. - Addressing the fact that MSI assumes irq == vector takes a few more patches. But suffice it to say when I am done none of the generic irq code even knows what a vector is. In quick testing on a large Unisys x86_64 machine we stumbled over at least one driver that assumed that NR_IRQS could always fit into an 8 bit number. This driver is clearly buggy today. But this has become a class of bugs that it is now much easier to hit. This patch: This is a minor space optimization. In practice I don't think this has any affect because of our alignment constraints and the other fields but there is not point in chewing up an uncessary word and since we already read the flag field this should improve the cache hit ratio of the irq handler. Signed-off-by: Eric W. Biederman Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Benjamin Herrenschmidt Cc: Rajesh Shah Cc: Andi Kleen Cc: "Protasevich, Natalie" Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irq.h | 3 +-- kernel/irq/migration.c | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 48d3cb3b6a47..3eab46f590a9 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -59,6 +59,7 @@ #define IRQ_NOAUTOEN 0x08000000 /* IRQ will not be enabled on request irq */ #define IRQ_DELAYED_DISABLE 0x10000000 /* IRQ disable (masking) happens delayed. */ #define IRQ_WAKEUP 0x20000000 /* IRQ triggers system wakeup */ +#define IRQ_MOVE_PENDING 0x40000000 /* need to re-target IRQ destination */ struct proc_dir_entry; @@ -132,7 +133,6 @@ struct irq_chip { * @affinity: IRQ affinity on SMP * @cpu: cpu index useful for balancing * @pending_mask: pending rebalanced interrupts - * @move_irq: need to re-target IRQ destination * @dir: /proc/irq/ procfs entry * @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP * @@ -159,7 +159,6 @@ struct irq_desc { #endif #if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE) cpumask_t pending_mask; - unsigned int move_irq; /* need to re-target IRQ dest */ #endif #ifdef CONFIG_PROC_FS struct proc_dir_entry *dir; diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index a57ebe9fa6f6..9b234df810d0 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c @@ -7,7 +7,7 @@ void set_pending_irq(unsigned int irq, cpumask_t mask) unsigned long flags; spin_lock_irqsave(&desc->lock, flags); - desc->move_irq = 1; + desc->status |= IRQ_MOVE_PENDING; irq_desc[irq].pending_mask = mask; spin_unlock_irqrestore(&desc->lock, flags); } @@ -17,7 +17,7 @@ void move_native_irq(int irq) struct irq_desc *desc = irq_desc + irq; cpumask_t tmp; - if (likely(!desc->move_irq)) + if (likely(!(desc->status & IRQ_MOVE_PENDING))) return; /* @@ -28,7 +28,7 @@ void move_native_irq(int irq) return; } - desc->move_irq = 0; + desc->status &= ~IRQ_MOVE_PENDING; if (unlikely(cpus_empty(irq_desc[irq].pending_mask))) return; -- cgit v1.2.3 From e7b946e98a456077dd6897f726f3d6197bd7e3b9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:29 -0700 Subject: [PATCH] genirq: irq: add moved_masked_irq Currently move_native_irq disables and renables the irq we are migrating to ensure we don't take that irq when we are actually doing the migration operation. Disabling the irq needs to happen but sometimes doing the work is move_native_irq is too late. On x86 with ioapics the irq move sequences needs to be: edge_triggered: mask irq. move irq. unmask irq. ack irq. level_triggered: mask irq. ack irq. move irq. unmask irq. We can easily perform the edge triggered sequence, with the current defintion of move_native_irq. However the level triggered case does not map well. For that I have added move_masked_irq, to allow me to disable the irqs around both the ack and the move. Q: Why have we not seen this problem earlier? A: The only symptom I have been able to reproduce is that if we change the vector before acknowleding an irq the wrong irq is acknowledged. Since we currently are not reprogramming the irq vector during migration no problems show up. We have to mask the irq before we acknowledge the irq or else we could hit a window where an irq is asserted just before we acknowledge it. Edge triggered irqs do not have this problem because acknowledgements do not propogate in the same way. Signed-off-by: Eric W. Biederman Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Benjamin Herrenschmidt Cc: Rajesh Shah Cc: Andi Kleen Cc: "Protasevich, Natalie" Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irq.h | 6 ++++++ kernel/irq/migration.c | 28 +++++++++++++++++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 3eab46f590a9..a31a7d8acdb2 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -205,6 +205,7 @@ static inline void set_native_irq_info(int irq, cpumask_t mask) void set_pending_irq(unsigned int irq, cpumask_t mask); void move_native_irq(int irq); +void move_masked_irq(int irq); #ifdef CONFIG_PCI_MSI /* @@ -246,6 +247,10 @@ static inline void move_native_irq(int irq) { } +static inline void move_masked_irq(int irq) +{ +} + static inline void set_pending_irq(unsigned int irq, cpumask_t mask) { } @@ -261,6 +266,7 @@ static inline void set_irq_info(int irq, cpumask_t mask) #define move_irq(x) #define move_native_irq(x) +#define move_masked_irq(x) #endif /* CONFIG_SMP */ diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index 9b234df810d0..4baa3bbcd25a 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c @@ -12,7 +12,7 @@ void set_pending_irq(unsigned int irq, cpumask_t mask) spin_unlock_irqrestore(&desc->lock, flags); } -void move_native_irq(int irq) +void move_masked_irq(int irq) { struct irq_desc *desc = irq_desc + irq; cpumask_t tmp; @@ -48,15 +48,29 @@ void move_native_irq(int irq) * when an active trigger is comming in. This could * cause some ioapics to mal-function. * Being paranoid i guess! + * + * For correct operation this depends on the caller + * masking the irqs. */ if (likely(!cpus_empty(tmp))) { - if (likely(!(desc->status & IRQ_DISABLED))) - desc->chip->disable(irq); - desc->chip->set_affinity(irq,tmp); - - if (likely(!(desc->status & IRQ_DISABLED))) - desc->chip->enable(irq); } cpus_clear(irq_desc[irq].pending_mask); } + +void move_native_irq(int irq) +{ + struct irq_desc *desc = irq_desc + irq; + + if (likely(!(desc->status & IRQ_MOVE_PENDING))) + return; + + if (likely(!(desc->status & IRQ_DISABLED))) + desc->chip->disable(irq); + + move_masked_irq(irq); + + if (likely(!(desc->status & IRQ_DISABLED))) + desc->chip->enable(irq); +} + -- cgit v1.2.3 From 0366f8f7137deb072991e4c50769c6da31f8940c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:33 -0700 Subject: [PATCH] genirq: msi: implement helper functions read_msi_msg and write_msi_msg In support of this I also add a struct msi_msg that captures the the two address and one data field ina typical msi message, and I remember the pos and if the address is 64bit in struct msi_desc. This makes the code a little more readable and easier to maintain, and paves the way to further simplfications. Signed-off-by: Eric W. Biederman Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Benjamin Herrenschmidt Cc: Rajesh Shah Cc: Andi Kleen Cc: "Protasevich, Natalie" Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/msi.c | 195 +++++++++++++++++++++++++--------------------------- drivers/pci/msi.h | 9 +-- include/linux/pci.h | 6 ++ 3 files changed, 104 insertions(+), 106 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 75d1c0dacffa..cca6cb3ccdac 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -87,63 +87,100 @@ static void msi_set_mask_bit(unsigned int vector, int flag) } } -#ifdef CONFIG_SMP -static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) +static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { - struct msi_desc *entry; - u32 address_hi, address_lo; - unsigned int irq = vector; - unsigned int dest_cpu = first_cpu(cpu_mask); - - entry = (struct msi_desc *)msi_desc[vector]; - if (!entry || !entry->dev) - return; + switch(entry->msi_attrib.type) { + case PCI_CAP_ID_MSI: + { + struct pci_dev *dev = entry->dev; + int pos = entry->msi_attrib.pos; + u16 data; + + pci_read_config_dword(dev, msi_lower_address_reg(pos), + &msg->address_lo); + if (entry->msi_attrib.is_64) { + pci_read_config_dword(dev, msi_upper_address_reg(pos), + &msg->address_hi); + pci_read_config_word(dev, msi_data_reg(pos, 1), &data); + } else { + msg->address_hi = 0; + pci_read_config_word(dev, msi_data_reg(pos, 1), &data); + } + msg->data = data; + break; + } + case PCI_CAP_ID_MSIX: + { + void __iomem *base; + base = entry->mask_base + + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; + + msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); + msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); + msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET); + break; + } + default: + BUG(); + } +} +static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) +{ switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: { - int pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI); - - if (!pos) - return; - - pci_read_config_dword(entry->dev, msi_upper_address_reg(pos), - &address_hi); - pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), - &address_lo); - - msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); - - pci_write_config_dword(entry->dev, msi_upper_address_reg(pos), - address_hi); - pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), - address_lo); - set_native_irq_info(irq, cpu_mask); + struct pci_dev *dev = entry->dev; + int pos = entry->msi_attrib.pos; + + pci_write_config_dword(dev, msi_lower_address_reg(pos), + msg->address_lo); + if (entry->msi_attrib.is_64) { + pci_write_config_dword(dev, msi_upper_address_reg(pos), + msg->address_hi); + pci_write_config_word(dev, msi_data_reg(pos, 1), + msg->data); + } else { + pci_write_config_word(dev, msi_data_reg(pos, 0), + msg->data); + } break; } case PCI_CAP_ID_MSIX: { - int offset_hi = - entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET; - int offset_lo = - entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; - - address_hi = readl(entry->mask_base + offset_hi); - address_lo = readl(entry->mask_base + offset_lo); - - msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); - - writel(address_hi, entry->mask_base + offset_hi); - writel(address_lo, entry->mask_base + offset_lo); - set_native_irq_info(irq, cpu_mask); + void __iomem *base; + base = entry->mask_base + + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; + + writel(msg->address_lo, + base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); + writel(msg->address_hi, + base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); + writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET); break; } default: - break; + BUG(); } } + +#ifdef CONFIG_SMP +static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) +{ + struct msi_desc *entry; + struct msi_msg msg; + unsigned int irq = vector; + unsigned int dest_cpu = first_cpu(cpu_mask); + + entry = (struct msi_desc *)msi_desc[vector]; + if (!entry || !entry->dev) + return; + + read_msi_msg(entry, &msg); + msi_ops->target(vector, dest_cpu, &msg.address_hi, &msg.address_lo); + write_msi_msg(entry, &msg); + set_native_irq_info(irq, cpu_mask); +} #else #define set_msi_affinity NULL #endif /* CONFIG_SMP */ @@ -606,23 +643,10 @@ int pci_save_msix_state(struct pci_dev *dev) vector = head = dev->irq; while (head != tail) { - int j; - void __iomem *base; struct msi_desc *entry; entry = msi_desc[vector]; - base = entry->mask_base; - j = entry->msi_attrib.entry_nr; - - entry->address_lo_save = - readl(base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); - entry->address_hi_save = - readl(base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); - entry->data_save = - readl(base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_DATA_OFFSET); + read_msi_msg(entry, &entry->msg_save); tail = msi_desc[vector]->link.tail; vector = tail; @@ -639,8 +663,6 @@ void pci_restore_msix_state(struct pci_dev *dev) u16 save; int pos; int vector, head, tail = 0; - void __iomem *base; - int j; struct msi_desc *entry; int temp; struct pci_cap_saved_state *save_state; @@ -663,18 +685,7 @@ void pci_restore_msix_state(struct pci_dev *dev) vector = head = dev->irq; while (head != tail) { entry = msi_desc[vector]; - base = entry->mask_base; - j = entry->msi_attrib.entry_nr; - - writel(entry->address_lo_save, - base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); - writel(entry->address_hi_save, - base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); - writel(entry->data_save, - base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_DATA_OFFSET); + write_msi_msg(entry, &entry->msg_save); tail = msi_desc[vector]->link.tail; vector = tail; @@ -689,29 +700,19 @@ void pci_restore_msix_state(struct pci_dev *dev) static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) { int status; - u32 address_hi; - u32 address_lo; - u32 data; + struct msi_msg msg; int pos, vector = dev->irq; u16 control; - pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + pos = entry->msi_attrib.pos; pci_read_config_word(dev, msi_control_reg(pos), &control); /* Configure MSI capability structure */ - status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data); + status = msi_ops->setup(dev, vector, &msg.address_hi, &msg.address_lo, &msg.data); if (status < 0) return status; - pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo); - if (is_64bit_address(control)) { - pci_write_config_dword(dev, - msi_upper_address_reg(pos), address_hi); - pci_write_config_word(dev, - msi_data_reg(pos, 1), data); - } else - pci_write_config_word(dev, - msi_data_reg(pos, 0), data); + write_msi_msg(entry, &msg); if (entry->msi_attrib.maskbit) { unsigned int maskbits, temp; /* All MSIs are unmasked by default, Mask them all */ @@ -761,9 +762,11 @@ static int msi_capability_init(struct pci_dev *dev) entry->link.tail = vector; entry->msi_attrib.type = PCI_CAP_ID_MSI; entry->msi_attrib.state = 0; /* Mark it not active */ + entry->msi_attrib.is_64 = is_64bit_address(control); entry->msi_attrib.entry_nr = 0; entry->msi_attrib.maskbit = is_mask_bit_support(control); entry->msi_attrib.default_vector = dev->irq; /* Save IOAPIC IRQ */ + entry->msi_attrib.pos = pos; dev->irq = vector; entry->dev = dev; if (is_mask_bit_support(control)) { @@ -801,9 +804,7 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, int nvec) { struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; - u32 address_hi; - u32 address_lo; - u32 data; + struct msi_msg msg; int status; int vector, pos, i, j, nr_entries, temp = 0; unsigned long phys_addr; @@ -840,9 +841,11 @@ static int msix_capability_init(struct pci_dev *dev, entries[i].vector = vector; entry->msi_attrib.type = PCI_CAP_ID_MSIX; entry->msi_attrib.state = 0; /* Mark it not active */ + entry->msi_attrib.is_64 = 1; entry->msi_attrib.entry_nr = j; entry->msi_attrib.maskbit = 1; entry->msi_attrib.default_vector = dev->irq; + entry->msi_attrib.pos = pos; entry->dev = dev; entry->mask_base = base; if (!head) { @@ -861,21 +864,13 @@ static int msix_capability_init(struct pci_dev *dev, irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); /* Configure MSI-X capability structure */ status = msi_ops->setup(dev, vector, - &address_hi, - &address_lo, - &data); + &msg.address_hi, + &msg.address_lo, + &msg.data); if (status < 0) break; - writel(address_lo, - base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); - writel(address_hi, - base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); - writel(data, - base + j * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_DATA_OFFSET); + write_msi_msg(entry, &msg); attach_msi_entry(entry, vector); } if (i != nvec) { diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 9b31d4cbbce4..62f61b61d2c9 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -130,10 +130,10 @@ struct msi_desc { __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ __u8 maskbit : 1; /* mask-pending bit supported ? */ __u8 state : 1; /* {0: free, 1: busy} */ - __u8 reserved: 1; /* reserved */ + __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ __u8 entry_nr; /* specific enabled entry */ __u8 default_vector; /* default pre-assigned vector */ - __u8 unused; /* formerly unused destination cpu*/ + __u8 pos; /* Location of the msi capability */ }msi_attrib; struct { @@ -146,10 +146,7 @@ struct msi_desc { #ifdef CONFIG_PM /* PM save area for MSIX address/data */ - - u32 address_hi_save; - u32 address_lo_save; - u32 data_save; + struct msi_msg msg_save; #endif }; diff --git a/include/linux/pci.h b/include/linux/pci.h index 4431ce4e1e6f..b9bb6c46e056 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -595,6 +595,12 @@ struct msix_entry { u16 entry; /* driver uses to specify entry, OS writes */ }; +struct msi_msg { + u32 address_lo; /* low 32 bits of msi message address */ + u32 address_hi; /* high 32 bits of msi message address */ + u32 data; /* 16 bits of msi message data */ +}; + #ifndef CONFIG_PCI_MSI static inline void pci_scan_msi_device(struct pci_dev *dev) {} static inline int pci_enable_msi(struct pci_dev *dev) {return -1;} -- cgit v1.2.3 From 38bc0361303535c86f6b67b151a541728d7bdae6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:34 -0700 Subject: [PATCH] genirq: msi: refactor the msi_ops The current msi_ops are short sighted in a number of ways, this patch attempts to fix the glaring deficiences. - Report in msi_ops if a 64bit address is needed in the msi message, so we can fail 32bit only msi structures. - Send and receive a full struct msi_msg in both setup and target. This is a little cleaner and allows for architectures that need to modify the data to retarget the msi interrupt to a different cpu. - In target pass in the full cpu mask instead of just the first cpu in case we can make use of the full cpu mask. - Operate in terms of irqs and not vectors, currently there is still a 1-1 relationship but on architectures other than ia64 I expect this will change. Signed-off-by: Eric W. Biederman Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Benjamin Herrenschmidt Cc: Rajesh Shah Cc: Andi Kleen Cc: "Protasevich, Natalie" Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/msi-altix.c | 49 +++++++++++++++++++------------------- drivers/pci/msi-apic.c | 36 ++++++++++++++-------------- drivers/pci/msi.c | 22 +++++++++--------- drivers/pci/msi.h | 62 ------------------------------------------------- include/linux/pci.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 115 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c index bed4183a5e39..7aedc2ac8c28 100644 --- a/drivers/pci/msi-altix.c +++ b/drivers/pci/msi-altix.c @@ -26,7 +26,7 @@ struct sn_msi_info { static struct sn_msi_info *sn_msi_info; static void -sn_msi_teardown(unsigned int vector) +sn_msi_teardown(unsigned int irq) { nasid_t nasid; int widget; @@ -36,7 +36,7 @@ sn_msi_teardown(unsigned int vector) struct pcibus_bussoft *bussoft; struct sn_pcibus_provider *provider; - sn_irq_info = sn_msi_info[vector].sn_irq_info; + sn_irq_info = sn_msi_info[irq].sn_irq_info; if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) return; @@ -45,9 +45,9 @@ sn_msi_teardown(unsigned int vector) provider = SN_PCIDEV_BUSPROVIDER(pdev); (*provider->dma_unmap)(pdev, - sn_msi_info[vector].pci_addr, + sn_msi_info[irq].pci_addr, PCI_DMA_FROMDEVICE); - sn_msi_info[vector].pci_addr = 0; + sn_msi_info[irq].pci_addr = 0; bussoft = SN_PCIDEV_BUSSOFT(pdev); nasid = NASID_GET(bussoft->bs_base); @@ -56,14 +56,13 @@ sn_msi_teardown(unsigned int vector) SWIN_WIDGETNUM(bussoft->bs_base); sn_intr_free(nasid, widget, sn_irq_info); - sn_msi_info[vector].sn_irq_info = NULL; + sn_msi_info[irq].sn_irq_info = NULL; return; } int -sn_msi_setup(struct pci_dev *pdev, unsigned int vector, - u32 *addr_hi, u32 *addr_lo, u32 *data) +sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) { int widget; int status; @@ -93,7 +92,7 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int vector, if (! sn_irq_info) return -ENOMEM; - status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1); + status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1); if (status) { kfree(sn_irq_info); return -ENOMEM; @@ -119,28 +118,27 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int vector, return -ENOMEM; } - sn_msi_info[vector].sn_irq_info = sn_irq_info; - sn_msi_info[vector].pci_addr = bus_addr; + sn_msi_info[irq].sn_irq_info = sn_irq_info; + sn_msi_info[irq].pci_addr = bus_addr; - *addr_hi = (u32)(bus_addr >> 32); - *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); + msg->address_hi = (u32)(bus_addr >> 32); + msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff); /* * In the SN platform, bit 16 is a "send vector" bit which * must be present in order to move the vector through the system. */ - *data = 0x100 + (unsigned int)vector; + msg->data = 0x100 + irq; #ifdef CONFIG_SMP - set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0); + set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0); #endif return 0; } static void -sn_msi_target(unsigned int vector, unsigned int cpu, - u32 *addr_hi, u32 *addr_lo) +sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) { int slice; nasid_t nasid; @@ -150,8 +148,10 @@ sn_msi_target(unsigned int vector, unsigned int cpu, struct sn_irq_info *sn_irq_info; struct sn_irq_info *new_irq_info; struct sn_pcibus_provider *provider; + unsigned int cpu; - sn_irq_info = sn_msi_info[vector].sn_irq_info; + cpu = first_cpu(cpu_mask); + sn_irq_info = sn_msi_info[irq].sn_irq_info; if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) return; @@ -163,15 +163,15 @@ sn_msi_target(unsigned int vector, unsigned int cpu, pdev = sn_pdev->pdi_linux_pcidev; provider = SN_PCIDEV_BUSPROVIDER(pdev); - bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo); + bus_addr = (u64)(msg->address_hi) << 32 | (u64)(msg->address_lo); (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); - sn_msi_info[vector].pci_addr = 0; + sn_msi_info[irq].pci_addr = 0; nasid = cpuid_to_nasid(cpu); slice = cpuid_to_slice(cpu); new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); - sn_msi_info[vector].sn_irq_info = new_irq_info; + sn_msi_info[irq].sn_irq_info = new_irq_info; if (new_irq_info == NULL) return; @@ -184,12 +184,13 @@ sn_msi_target(unsigned int vector, unsigned int cpu, sizeof(new_irq_info->irq_xtalkaddr), SN_DMA_MSI|SN_DMA_ADDR_XIO); - sn_msi_info[vector].pci_addr = bus_addr; - *addr_hi = (u32)(bus_addr >> 32); - *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); + sn_msi_info[irq].pci_addr = bus_addr; + msg->address_hi = (u32)(bus_addr >> 32); + msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff); } struct msi_ops sn_msi_ops = { + .needs_64bit_address = 1, .setup = sn_msi_setup, .teardown = sn_msi_teardown, #ifdef CONFIG_SMP @@ -201,7 +202,7 @@ int sn_msi_init(void) { sn_msi_info = - kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL); + kzalloc(sizeof(struct sn_msi_info) * NR_IRQS, GFP_KERNEL); if (! sn_msi_info) return -ENOMEM; diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c index 5ed798b319c7..afc0ed13aa89 100644 --- a/drivers/pci/msi-apic.c +++ b/drivers/pci/msi-apic.c @@ -46,37 +46,36 @@ static void -msi_target_apic(unsigned int vector, - unsigned int dest_cpu, - u32 *address_hi, /* in/out */ - u32 *address_lo) /* in/out */ +msi_target_apic(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) { - u32 addr = *address_lo; + u32 addr = msg->address_lo; addr &= MSI_ADDR_DESTID_MASK; - addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu)); + addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask))); - *address_lo = addr; + msg->address_lo = addr; } static int msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ - unsigned int vector, - u32 *address_hi, - u32 *address_lo, - u32 *data) + unsigned int irq, + struct msi_msg *msg) { unsigned long dest_phys_id; + unsigned int vector; dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); + vector = irq; - *address_hi = 0; - *address_lo = MSI_ADDR_HEADER | - MSI_ADDR_DESTMODE_PHYS | - MSI_ADDR_REDIRECTION_CPU | - MSI_ADDR_DESTID_CPU(dest_phys_id); + msg->address_hi = 0; + msg->address_lo = + MSI_ADDR_HEADER | + MSI_ADDR_DESTMODE_PHYS | + MSI_ADDR_REDIRECTION_CPU | + MSI_ADDR_DESTID_CPU(dest_phys_id); - *data = MSI_DATA_TRIGGER_EDGE | + msg->data = + MSI_DATA_TRIGGER_EDGE | MSI_DATA_LEVEL_ASSERT | MSI_DATA_DELIVERY_FIXED | MSI_DATA_VECTOR(vector); @@ -85,7 +84,7 @@ msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ } static void -msi_teardown_apic(unsigned int vector) +msi_teardown_apic(unsigned int irq) { return; /* no-op */ } @@ -95,6 +94,7 @@ msi_teardown_apic(unsigned int vector) */ struct msi_ops msi_apic_ops = { + .needs_64bit_address = 0, .setup = msi_setup_apic, .teardown = msi_teardown_apic, .target = msi_target_apic, diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index cca6cb3ccdac..6d9de026e141 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -165,19 +165,17 @@ static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) } #ifdef CONFIG_SMP -static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) +static void set_msi_affinity(unsigned int irq, cpumask_t cpu_mask) { struct msi_desc *entry; struct msi_msg msg; - unsigned int irq = vector; - unsigned int dest_cpu = first_cpu(cpu_mask); - entry = (struct msi_desc *)msi_desc[vector]; + entry = msi_desc[irq]; if (!entry || !entry->dev) return; read_msi_msg(entry, &msg); - msi_ops->target(vector, dest_cpu, &msg.address_hi, &msg.address_lo); + msi_ops->target(irq, cpu_mask, &msg); write_msi_msg(entry, &msg); set_native_irq_info(irq, cpu_mask); } @@ -701,14 +699,14 @@ static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) { int status; struct msi_msg msg; - int pos, vector = dev->irq; + int pos; u16 control; pos = entry->msi_attrib.pos; pci_read_config_word(dev, msi_control_reg(pos), &control); /* Configure MSI capability structure */ - status = msi_ops->setup(dev, vector, &msg.address_hi, &msg.address_lo, &msg.data); + status = msi_ops->setup(dev, dev->irq, &msg); if (status < 0) return status; @@ -863,10 +861,7 @@ static int msix_capability_init(struct pci_dev *dev, /* Replace with MSI-X handler */ irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); /* Configure MSI-X capability structure */ - status = msi_ops->setup(dev, vector, - &msg.address_hi, - &msg.address_lo, - &msg.data); + status = msi_ops->setup(dev, vector, &msg); if (status < 0) break; @@ -928,6 +923,7 @@ int pci_msi_supported(struct pci_dev * dev) int pci_enable_msi(struct pci_dev* dev) { int pos, temp, status; + u16 control; if (pci_msi_supported(dev) < 0) return -EINVAL; @@ -942,6 +938,10 @@ int pci_enable_msi(struct pci_dev* dev) if (!pos) return -EINVAL; + pci_read_config_word(dev, msi_control_reg(pos), &control); + if (!is_64bit_address(control) && msi_ops->needs_64bit_address) + return -EINVAL; + WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSI)); /* Check whether driver already requested for MSI-X vectors */ diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 62f61b61d2c9..3519eca50d8a 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -6,68 +6,6 @@ #ifndef MSI_H #define MSI_H -/* - * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) - * to abstract platform-specific tasks relating to MSI address generation - * and resource management. - */ -struct msi_ops { - /** - * setup - generate an MSI bus address and data for a given vector - * @pdev: PCI device context (in) - * @vector: vector allocated by the msi core (in) - * @addr_hi: upper 32 bits of PCI bus MSI address (out) - * @addr_lo: lower 32 bits of PCI bus MSI address (out) - * @data: MSI data payload (out) - * - * Description: The setup op is used to generate a PCI bus addres and - * data which the msi core will program into the card MSI capability - * registers. The setup routine is responsible for picking an initial - * cpu to target the MSI at. The setup routine is responsible for - * examining pdev to determine the MSI capabilities of the card and - * generating a suitable address/data. The setup routine is - * responsible for allocating and tracking any system resources it - * needs to route the MSI to the cpu it picks, and for associating - * those resources with the passed in vector. - * - * Returns 0 if the MSI address/data was successfully setup. - **/ - - int (*setup) (struct pci_dev *pdev, unsigned int vector, - u32 *addr_hi, u32 *addr_lo, u32 *data); - - /** - * teardown - release resources allocated by setup - * @vector: vector context for resources (in) - * - * Description: The teardown op is used to release any resources - * that were allocated in the setup routine associated with the passed - * in vector. - **/ - - void (*teardown) (unsigned int vector); - - /** - * target - retarget an MSI at a different cpu - * @vector: vector context for resources (in) - * @cpu: new cpu to direct vector at (in) - * @addr_hi: new value of PCI bus upper 32 bits (in/out) - * @addr_lo: new value of PCI bus lower 32 bits (in/out) - * - * Description: The target op is used to redirect an MSI vector - * at a different cpu. addr_hi/addr_lo coming in are the existing - * values that the MSI core has programmed into the card. The - * target code is responsible for freeing any resources (if any) - * associated with the old address, and generating a new PCI bus - * addr_hi/addr_lo that will redirect the vector at the indicated cpu. - **/ - - void (*target) (unsigned int vector, unsigned int cpu, - u32 *addr_hi, u32 *addr_lo); -}; - -extern int msi_register(struct msi_ops *ops); - #include /* diff --git a/include/linux/pci.h b/include/linux/pci.h index b9bb6c46e056..2aabe90f1cd2 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -617,6 +617,68 @@ extern int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec); extern void pci_disable_msix(struct pci_dev *dev); extern void msi_remove_pci_irq_vectors(struct pci_dev *dev); + +/* + * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) + * to abstract platform-specific tasks relating to MSI address generation + * and resource management. + */ +struct msi_ops { + int needs_64bit_address; + /** + * setup - generate an MSI bus address and data for a given vector + * @pdev: PCI device context (in) + * @irq: irq allocated by the msi core (in) + * @msg: PCI bus address and data for msi message (out) + * + * Description: The setup op is used to generate a PCI bus addres and + * data which the msi core will program into the card MSI capability + * registers. The setup routine is responsible for picking an initial + * cpu to target the MSI at. The setup routine is responsible for + * examining pdev to determine the MSI capabilities of the card and + * generating a suitable address/data. The setup routine is + * responsible for allocating and tracking any system resources it + * needs to route the MSI to the cpu it picks, and for associating + * those resources with the passed in vector. + * + * Returns 0 if the MSI address/data was successfully setup. + **/ + + int (*setup) (struct pci_dev *pdev, unsigned int irq, + struct msi_msg *msg); + + /** + * teardown - release resources allocated by setup + * @vector: vector context for resources (in) + * + * Description: The teardown op is used to release any resources + * that were allocated in the setup routine associated with the passed + * in vector. + **/ + + void (*teardown) (unsigned int irq); + + /** + * target - retarget an MSI at a different cpu + * @vector: vector context for resources (in) + * @cpu: new cpu to direct vector at (in) + * @addr_hi: new value of PCI bus upper 32 bits (in/out) + * @addr_lo: new value of PCI bus lower 32 bits (in/out) + * + * Description: The target op is used to redirect an MSI vector + * at a different cpu. addr_hi/addr_lo coming in are the existing + * values that the MSI core has programmed into the card. The + * target code is responsible for freeing any resources (if any) + * associated with the old address, and generating a new PCI bus + * addr_hi/addr_lo that will redirect the vector at the indicated cpu. + **/ + + void (*target) (unsigned int irq, cpumask_t cpumask, + struct msi_msg *msg); +}; + +extern int msi_register(struct msi_ops *ops); + #endif extern void pci_block_user_cfg_access(struct pci_dev *dev); -- cgit v1.2.3 From 3a16d713626735f3016da0521b7bf251cd78e836 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:37 -0700 Subject: [PATCH] genirq: irq: add a dynamic irq creation API With the msi support comes a new concept in irq handling, irqs that are created dynamically at run time. Currently the msi code allocates irqs backwards. First it allocates a platform dependent routing value for an interrupt the ``vector'' and then it figures out from the vector which irq you are on. This msi backwards allocator suffers from two basic problems. The allocator suffers because it is trying to do something that is architecture specific in a generic way making it brittle, inflexible, and tied to tightly to the architecture implementation. The alloctor also suffers from it's very backwards nature as it has tied things together that should have no dependencies. To solve the basic dynamic irq allocation problem two new architecture specific functions are added: create_irq and destroy_irq. create_irq takes no input and returns an unused irq number, that won't be reused until it is returned to the free poll with destroy_irq. The irq then can be used for any purpose although the only initial consumer is the msi code. destroy_irq takes an irq number allocated with create_irq and returns it to the free pool. Making this functionality per architecture increases the simplicity of the irq allocation code and increases it's flexibility. dynamic_irq_init() and dynamic_irq_cleanup() are added to automate the irq_desc initializtion that should happen for dynamic irqs. Signed-off-by: Eric W. Biederman Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Benjamin Herrenschmidt Cc: Rajesh Shah Cc: Andi Kleen Cc: "Protasevich, Natalie" Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irq.h | 9 ++++++++- kernel/irq/chip.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index a31a7d8acdb2..82dbb0e8f40b 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -404,8 +404,15 @@ set_irq_chained_handler(unsigned int irq, __set_irq_handler(irq, handle, 1); } -/* Set/get chip/data for an IRQ: */ +/* Handle dynamic irq creation and destruction */ +extern int create_irq(void); +extern void destroy_irq(unsigned int irq); + +/* Dynamic irq helper functions */ +extern void dynamic_irq_init(unsigned int irq); +extern void dynamic_irq_cleanup(unsigned int irq); +/* Set/get chip/data for an IRQ: */ extern int set_irq_chip(unsigned int irq, struct irq_chip *chip); extern int set_irq_data(unsigned int irq, void *data); extern int set_irq_chip_data(unsigned int irq, void *data); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 736cb0bd498f..0dc24386dd99 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -17,6 +17,62 @@ #include "internals.h" +/** + * dynamic_irq_init - initialize a dynamically allocated irq + * @irq: irq number to initialize + */ +void dynamic_irq_init(unsigned int irq) +{ + struct irq_desc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to initialize invalid IRQ%d\n", irq); + WARN_ON(1); + return; + } + + /* Ensure we don't have left over values from a previous use of this irq */ + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock, flags); + desc->status = IRQ_DISABLED; + desc->chip = &no_irq_chip; + desc->handle_irq = handle_bad_irq; + desc->depth = 1; + desc->handler_data = NULL; + desc->chip_data = NULL; + desc->action = NULL; + desc->irq_count = 0; + desc->irqs_unhandled = 0; +#ifdef CONFIG_SMP + desc->affinity = CPU_MASK_ALL; +#endif + spin_unlock_irqrestore(&desc->lock, flags); +} + +/** + * dynamic_irq_cleanup - cleanup a dynamically allocated irq + * @irq: irq number to initialize + */ +void dynamic_irq_cleanup(unsigned int irq) +{ + struct irq_desc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq); + WARN_ON(1); + return; + } + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock, flags); + desc->handle_irq = handle_bad_irq; + desc->chip = &no_irq_chip; + spin_unlock_irqrestore(&desc->lock, flags); +} + + /** * set_irq_chip - set the irq chip for an irq * @irq: irq number -- cgit v1.2.3 From 323a01c50832749d23664954f91df6fc43e73975 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:48 -0700 Subject: [PATCH] genirq: irq: remove msi hacks Because of the nasty way that CONFIG_PCI_MSI was implemented we wound up with set_irq_info and set_native_irq_info, with move_irq and move_native_irq. Both functions did the same thing but they were built and called under different circumstances. Now that the msi hacks are gone we can kill move_irq and set_irq_info. Signed-off-by: Eric W. Biederman Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Benjamin Herrenschmidt Cc: Rajesh Shah Cc: Andi Kleen Cc: "Protasevich, Natalie" Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irq.h | 36 ------------------------------------ 1 file changed, 36 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 82dbb0e8f40b..69855b23dff9 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -207,36 +207,6 @@ void set_pending_irq(unsigned int irq, cpumask_t mask); void move_native_irq(int irq); void move_masked_irq(int irq); -#ifdef CONFIG_PCI_MSI -/* - * Wonder why these are dummies? - * For e.g the set_ioapic_affinity_vector() calls the set_ioapic_affinity_irq() - * counter part after translating the vector to irq info. We need to perform - * this operation on the real irq, when we dont use vector, i.e when - * pci_use_vector() is false. - */ -static inline void move_irq(int irq) -{ -} - -static inline void set_irq_info(int irq, cpumask_t mask) -{ -} - -#else /* CONFIG_PCI_MSI */ - -static inline void move_irq(int irq) -{ - move_native_irq(irq); -} - -static inline void set_irq_info(int irq, cpumask_t mask) -{ - set_native_irq_info(irq, mask); -} - -#endif /* CONFIG_PCI_MSI */ - #else /* CONFIG_GENERIC_PENDING_IRQ || CONFIG_IRQBALANCE */ static inline void move_irq(int irq) @@ -255,16 +225,10 @@ static inline void set_pending_irq(unsigned int irq, cpumask_t mask) { } -static inline void set_irq_info(int irq, cpumask_t mask) -{ - set_native_irq_info(irq, mask); -} - #endif /* CONFIG_GENERIC_PENDING_IRQ */ #else /* CONFIG_SMP */ -#define move_irq(x) #define move_native_irq(x) #define move_masked_irq(x) -- cgit v1.2.3 From 23d0b8b053391afe15c9667d80de77ca88e18b8b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:49 -0700 Subject: [PATCH] genirq: irq: generalize the check for HARDIRQ_BITS This patch adds support for systems that cannot receive every interrupt on a single cpu simultaneously, in the check to see if we have enough HARDIRQ_BITS. MAX_HARDIRQS_PER_CPU becomes the count of the maximum number of hardare generated interrupts per cpu. On architectures that support per cpu interrupt delivery this can be a significant space savings and scalability bonus. This patch adds support for systems that cannot receive every interrupt on Signed-off-by: Eric W. Biederman Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Benjamin Herrenschmidt Cc: Rajesh Shah Cc: Andi Kleen Cc: "Protasevich, Natalie" Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-x86_64/hardirq.h | 3 +++ include/linux/hardirq.h | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h index 64a65ce2f41f..95d5e090ed89 100644 --- a/include/asm-x86_64/hardirq.h +++ b/include/asm-x86_64/hardirq.h @@ -6,6 +6,9 @@ #include #include +/* We can have at most NR_VECTORS irqs routed to a cpu at a time */ +#define MAX_HARDIRQS_PER_CPU NR_VECTORS + #define __ARCH_IRQ_STAT 1 #define local_softirq_pending() read_pda(__softirq_pending) diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 50d8b5744cf6..612472aaa79c 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -28,11 +28,16 @@ #ifndef HARDIRQ_BITS #define HARDIRQ_BITS 12 + +#ifndef MAX_HARDIRQS_PER_CPU +#define MAX_HARDIRQS_PER_CPU NR_IRQS +#endif + /* * The hardirq mask has to be large enough to have space for potentially * all IRQ sources in the system nesting on a single CPU. */ -#if (1 << HARDIRQ_BITS) < NR_IRQS +#if (1 << HARDIRQ_BITS) < MAX_HARDIRQS_PER_CPU # error HARDIRQ_BITS is too low! #endif #endif -- cgit v1.2.3 From e78d01693be38bf93dd6bb49b86e143da450de86 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:54 -0700 Subject: [PATCH] Add Hypertransport capability defines This adds defines for the hypertransport capability subtypes and starts using them a little. [akpm@osdl.org: fix typo] Signed-off-by: Eric W. Biederman Acked-by: Benjamin Herrenschmidt Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/sysdev/mpic.c | 2 +- include/linux/pci_regs.h | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 723972bb5bd9..3ee03a9a98fa 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -341,7 +341,7 @@ static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); if (id == PCI_CAP_ID_HT) { id = readb(devbase + pos + 3); - if (id == 0x80) + if (id == HT_CAPTYPE_IRQ) break; } } diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 7d0e26cba420..c312a12ad2d6 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -12,6 +12,11 @@ * PCI Local Bus Specification * PCI to PCI Bridge Specification * PCI System Design Guide + * + * For hypertransport information, please consult the following manuals + * from http://www.hypertransport.org + * + * The Hypertransport I/O Link Specification */ #ifndef LINUX_PCI_REGS_H @@ -463,4 +468,20 @@ #define PCI_PWR_CAP 12 /* Capability */ #define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ +/* Hypertransport sub capability types */ +#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ +#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ +#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ +#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ +#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ +#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */ +#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */ +#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */ +#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */ +#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */ +#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ +#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */ +#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */ + + #endif /* LINUX_PCI_REGS_H */ -- cgit v1.2.3 From 8b955b0dddb35e398b07e217a81f8bd49400796f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:55 -0700 Subject: [PATCH] Initial generic hypertransport interrupt support This patch implements two functions ht_create_irq and ht_destroy_irq for use by drivers. Several other functions are implemented as helpers for arch specific irq_chip handlers. The driver for the card I tested this on isn't yet ready to be merged. However this code is and hypertransport irqs are in use in a few other places in the kernel. Not that any of this will get merged before 2.6.19 Because the ipath-ht400 is slightly out of spec this code will need to be generalized to work there. I think all of the powerpc uses are for a plain interrupt controller in a chipset so support for native hypertransport devices is a little less interesting. However I think this is a half way decent model on how to separate arch specific and generic helper code, and I think this is a functional model of how to get the architecture dependencies out of the msi code. [akpm@osdl.org: Kconfig fix] Signed-off-by: Eric W. Biederman Cc: Greg KH Cc: Andi Kleen Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/io_apic.c | 90 +++++++++++++++++ arch/x86_64/kernel/io_apic.c | 96 ++++++++++++++++++ drivers/pci/Kconfig | 9 ++ drivers/pci/Makefile | 1 + drivers/pci/htirq.c | 189 ++++++++++++++++++++++++++++++++++++ include/asm-i386/hypertransport.h | 42 ++++++++ include/asm-x86_64/hypertransport.h | 42 ++++++++ include/linux/pci.h | 17 ++++ 8 files changed, 486 insertions(+) create mode 100644 drivers/pci/htirq.c create mode 100644 include/asm-i386/hypertransport.h create mode 100644 include/asm-x86_64/hypertransport.h (limited to 'include/linux') diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 03e7606be6e6..100406b453b8 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -2518,6 +2519,95 @@ struct msi_ops arch_msi_ops = { #endif /* CONFIG_PCI_MSI */ +/* + * Hypertransport interrupt support + */ +#ifdef CONFIG_HT_IRQ + +#ifdef CONFIG_SMP + +static void target_ht_irq(unsigned int irq, unsigned int dest) +{ + u32 low, high; + low = read_ht_irq_low(irq); + high = read_ht_irq_high(irq); + + low &= ~(HT_IRQ_LOW_DEST_ID_MASK); + high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); + + low |= HT_IRQ_LOW_DEST_ID(dest); + high |= HT_IRQ_HIGH_DEST_ID(dest); + + write_ht_irq_low(irq, low); + write_ht_irq_high(irq, high); +} + +static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) +{ + unsigned int dest; + cpumask_t tmp; + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) + tmp = TARGET_CPUS; + + cpus_and(mask, tmp, CPU_MASK_ALL); + + dest = cpu_mask_to_apicid(mask); + + target_ht_irq(irq, dest); + set_native_irq_info(irq, mask); +} +#endif + +static struct hw_interrupt_type ht_irq_chip = { + .name = "PCI-HT", + .mask = mask_ht_irq, + .unmask = unmask_ht_irq, + .ack = ack_ioapic_irq, +#ifdef CONFIG_SMP + .set_affinity = set_ht_irq_affinity, +#endif + .retrigger = ioapic_retrigger_irq, +}; + +int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) +{ + int vector; + + vector = assign_irq_vector(irq); + if (vector >= 0) { + u32 low, high; + unsigned dest; + cpumask_t tmp; + + cpus_clear(tmp); + cpu_set(vector >> 8, tmp); + dest = cpu_mask_to_apicid(tmp); + + high = HT_IRQ_HIGH_DEST_ID(dest); + + low = HT_IRQ_LOW_BASE | + HT_IRQ_LOW_DEST_ID(dest) | + HT_IRQ_LOW_VECTOR(vector) | + ((INT_DEST_MODE == 0) ? + HT_IRQ_LOW_DM_PHYSICAL : + HT_IRQ_LOW_DM_LOGICAL) | + HT_IRQ_LOW_RQEOI_EDGE | + ((INT_DELIVERY_MODE != dest_LowestPrio) ? + HT_IRQ_LOW_MT_FIXED : + HT_IRQ_LOW_MT_ARBITRATED) | + HT_IRQ_LOW_IRQ_MASKED; + + write_ht_irq_low(irq, low); + write_ht_irq_high(irq, high); + + set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq); + } + return vector; +} +#endif /* CONFIG_HT_IRQ */ + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 7cc29b50b0c1..31c270fee337 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -43,6 +43,7 @@ #include #include #include +#include static int assign_irq_vector(int irq, cpumask_t mask); @@ -1772,6 +1773,101 @@ struct msi_ops arch_msi_ops = { #endif +/* + * Hypertransport interrupt support + */ +#ifdef CONFIG_HT_IRQ + +#ifdef CONFIG_SMP + +static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) +{ + u32 low, high; + low = read_ht_irq_low(irq); + high = read_ht_irq_high(irq); + + low &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK); + high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); + + low |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest); + high |= HT_IRQ_HIGH_DEST_ID(dest); + + write_ht_irq_low(irq, low); + write_ht_irq_high(irq, high); +} + +static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) +{ + unsigned int dest; + cpumask_t tmp; + int vector; + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) + tmp = TARGET_CPUS; + + cpus_and(mask, tmp, CPU_MASK_ALL); + + vector = assign_irq_vector(irq, mask); + if (vector < 0) + return; + + cpus_clear(tmp); + cpu_set(vector >> 8, tmp); + dest = cpu_mask_to_apicid(tmp); + + target_ht_irq(irq, dest, vector & 0xff); + set_native_irq_info(irq, mask); +} +#endif + +static struct hw_interrupt_type ht_irq_chip = { + .name = "PCI-HT", + .mask = mask_ht_irq, + .unmask = unmask_ht_irq, + .ack = ack_apic_edge, +#ifdef CONFIG_SMP + .set_affinity = set_ht_irq_affinity, +#endif + .retrigger = ioapic_retrigger_irq, +}; + +int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) +{ + int vector; + + vector = assign_irq_vector(irq, TARGET_CPUS); + if (vector >= 0) { + u32 low, high; + unsigned dest; + cpumask_t tmp; + + cpus_clear(tmp); + cpu_set(vector >> 8, tmp); + dest = cpu_mask_to_apicid(tmp); + + high = HT_IRQ_HIGH_DEST_ID(dest); + + low = HT_IRQ_LOW_BASE | + HT_IRQ_LOW_DEST_ID(dest) | + HT_IRQ_LOW_VECTOR(vector) | + ((INT_DEST_MODE == 0) ? + HT_IRQ_LOW_DM_PHYSICAL : + HT_IRQ_LOW_DM_LOGICAL) | + HT_IRQ_LOW_RQEOI_EDGE | + ((INT_DELIVERY_MODE != dest_LowestPrio) ? + HT_IRQ_LOW_MT_FIXED : + HT_IRQ_LOW_MT_ARBITRATED); + + write_ht_irq_low(irq, low); + write_ht_irq_high(irq, high); + + set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq); + } + return vector; +} +#endif /* CONFIG_HT_IRQ */ + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index c27e782e6df9..0af6d7288415 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -52,3 +52,12 @@ config PCI_DEBUG When in doubt, say N. +config HT_IRQ + bool "Interrupts on hypertransport devices" + default y + depends on PCI_MSI + depends on X86_LOCAL_APIC && X86_IO_APIC + help + This allows native hypertransport devices to use interrupts. + + If unsure say Y. diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 983d0f86aa33..2752c57ecf01 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_PPC32) += setup-irq.o obj-$(CONFIG_PPC64) += setup-bus.o obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o +obj-$(CONFIG_HT_IRQ) += htirq.o msiobj-y := msi.o msiobj-$(CONFIG_IA64) += msi-apic.o diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c new file mode 100644 index 000000000000..4ba46359d367 --- /dev/null +++ b/drivers/pci/htirq.c @@ -0,0 +1,189 @@ +/* + * File: htirq.c + * Purpose: Hypertransport Interrupt Capability + * + * Copyright (C) 2006 Linux Networx + * Copyright (C) Eric Biederman + */ + +#include +#include +#include +#include +#include + +/* Global ht irq lock. + * + * This is needed to serialize access to the data port in hypertransport + * irq capability. + * + * With multiple simultaneous hypertransport irq devices it might pay + * to make this more fine grained. But start with simple, stupid, and correct. + */ +static DEFINE_SPINLOCK(ht_irq_lock); + +struct ht_irq_cfg { + struct pci_dev *dev; + unsigned pos; + unsigned idx; +}; + +void write_ht_irq_low(unsigned int irq, u32 data) +{ + struct ht_irq_cfg *cfg = get_irq_data(irq); + unsigned long flags; + spin_lock_irqsave(&ht_irq_lock, flags); + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); + pci_write_config_dword(cfg->dev, cfg->pos + 4, data); + spin_unlock_irqrestore(&ht_irq_lock, flags); +} + +void write_ht_irq_high(unsigned int irq, u32 data) +{ + struct ht_irq_cfg *cfg = get_irq_data(irq); + unsigned long flags; + spin_lock_irqsave(&ht_irq_lock, flags); + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); + pci_write_config_dword(cfg->dev, cfg->pos + 4, data); + spin_unlock_irqrestore(&ht_irq_lock, flags); +} + +u32 read_ht_irq_low(unsigned int irq) +{ + struct ht_irq_cfg *cfg = get_irq_data(irq); + unsigned long flags; + u32 data; + spin_lock_irqsave(&ht_irq_lock, flags); + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); + pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); + spin_unlock_irqrestore(&ht_irq_lock, flags); + return data; +} + +u32 read_ht_irq_high(unsigned int irq) +{ + struct ht_irq_cfg *cfg = get_irq_data(irq); + unsigned long flags; + u32 data; + spin_lock_irqsave(&ht_irq_lock, flags); + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); + pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); + spin_unlock_irqrestore(&ht_irq_lock, flags); + return data; +} + +void mask_ht_irq(unsigned int irq) +{ + struct ht_irq_cfg *cfg; + unsigned long flags; + u32 data; + + cfg = get_irq_data(irq); + + spin_lock_irqsave(&ht_irq_lock, flags); + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); + pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); + data |= 1; + pci_write_config_dword(cfg->dev, cfg->pos + 4, data); + spin_unlock_irqrestore(&ht_irq_lock, flags); +} + +void unmask_ht_irq(unsigned int irq) +{ + struct ht_irq_cfg *cfg; + unsigned long flags; + u32 data; + + cfg = get_irq_data(irq); + + spin_lock_irqsave(&ht_irq_lock, flags); + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); + pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); + data &= ~1; + pci_write_config_dword(cfg->dev, cfg->pos + 4, data); + spin_unlock_irqrestore(&ht_irq_lock, flags); +} + +/** + * ht_create_irq - create an irq and attach it to a device. + * @dev: The hypertransport device to find the irq capability on. + * @idx: Which of the possible irqs to attach to. + * + * ht_create_irq is needs to be called for all hypertransport devices + * that generate irqs. + * + * The irq number of the new irq or a negative error value is returned. + */ +int ht_create_irq(struct pci_dev *dev, int idx) +{ + struct ht_irq_cfg *cfg; + unsigned long flags; + u32 data; + int max_irq; + int pos; + int irq; + + pos = pci_find_capability(dev, PCI_CAP_ID_HT); + while (pos) { + u8 subtype; + pci_read_config_byte(dev, pos + 3, &subtype); + if (subtype == HT_CAPTYPE_IRQ) + break; + pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT); + } + if (!pos) + return -EINVAL; + + /* Verify the idx I want to use is in range */ + spin_lock_irqsave(&ht_irq_lock, flags); + pci_write_config_byte(dev, pos + 2, 1); + pci_read_config_dword(dev, pos + 4, &data); + spin_unlock_irqrestore(&ht_irq_lock, flags); + + max_irq = (data >> 16) & 0xff; + if ( idx > max_irq) + return -EINVAL; + + cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->dev = dev; + cfg->pos = pos; + cfg->idx = 0x10 + (idx * 2); + + irq = create_irq(); + if (irq < 0) { + kfree(cfg); + return -EBUSY; + } + set_irq_data(irq, cfg); + + if (arch_setup_ht_irq(irq, dev) < 0) { + ht_destroy_irq(irq); + return -EBUSY; + } + + return irq; +} + +/** + * ht_destroy_irq - destroy an irq created with ht_create_irq + * + * This reverses ht_create_irq removing the specified irq from + * existence. The irq should be free before this happens. + */ +void ht_destroy_irq(unsigned int irq) +{ + struct ht_irq_cfg *cfg; + + cfg = get_irq_data(irq); + set_irq_chip(irq, NULL); + set_irq_data(irq, NULL); + destroy_irq(irq); + + kfree(cfg); +} + +EXPORT_SYMBOL(ht_create_irq); +EXPORT_SYMBOL(ht_destroy_irq); diff --git a/include/asm-i386/hypertransport.h b/include/asm-i386/hypertransport.h new file mode 100644 index 000000000000..c16c6ff4bdd7 --- /dev/null +++ b/include/asm-i386/hypertransport.h @@ -0,0 +1,42 @@ +#ifndef ASM_HYPERTRANSPORT_H +#define ASM_HYPERTRANSPORT_H + +/* + * Constants for x86 Hypertransport Interrupts. + */ + +#define HT_IRQ_LOW_BASE 0xf8000000 + +#define HT_IRQ_LOW_VECTOR_SHIFT 16 +#define HT_IRQ_LOW_VECTOR_MASK 0x00ff0000 +#define HT_IRQ_LOW_VECTOR(v) (((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK) + +#define HT_IRQ_LOW_DEST_ID_SHIFT 8 +#define HT_IRQ_LOW_DEST_ID_MASK 0x0000ff00 +#define HT_IRQ_LOW_DEST_ID(v) (((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK) + +#define HT_IRQ_LOW_DM_PHYSICAL 0x0000000 +#define HT_IRQ_LOW_DM_LOGICAL 0x0000040 + +#define HT_IRQ_LOW_RQEOI_EDGE 0x0000000 +#define HT_IRQ_LOW_RQEOI_LEVEL 0x0000020 + + +#define HT_IRQ_LOW_MT_FIXED 0x0000000 +#define HT_IRQ_LOW_MT_ARBITRATED 0x0000004 +#define HT_IRQ_LOW_MT_SMI 0x0000008 +#define HT_IRQ_LOW_MT_NMI 0x000000c +#define HT_IRQ_LOW_MT_INIT 0x0000010 +#define HT_IRQ_LOW_MT_STARTUP 0x0000014 +#define HT_IRQ_LOW_MT_EXTINT 0x0000018 +#define HT_IRQ_LOW_MT_LINT1 0x000008c +#define HT_IRQ_LOW_MT_LINT0 0x0000098 + +#define HT_IRQ_LOW_IRQ_MASKED 0x0000001 + + +#define HT_IRQ_HIGH_DEST_ID_SHIFT 0 +#define HT_IRQ_HIGH_DEST_ID_MASK 0x00ffffff +#define HT_IRQ_HIGH_DEST_ID(v) ((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK) + +#endif /* ASM_HYPERTRANSPORT_H */ diff --git a/include/asm-x86_64/hypertransport.h b/include/asm-x86_64/hypertransport.h new file mode 100644 index 000000000000..c16c6ff4bdd7 --- /dev/null +++ b/include/asm-x86_64/hypertransport.h @@ -0,0 +1,42 @@ +#ifndef ASM_HYPERTRANSPORT_H +#define ASM_HYPERTRANSPORT_H + +/* + * Constants for x86 Hypertransport Interrupts. + */ + +#define HT_IRQ_LOW_BASE 0xf8000000 + +#define HT_IRQ_LOW_VECTOR_SHIFT 16 +#define HT_IRQ_LOW_VECTOR_MASK 0x00ff0000 +#define HT_IRQ_LOW_VECTOR(v) (((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK) + +#define HT_IRQ_LOW_DEST_ID_SHIFT 8 +#define HT_IRQ_LOW_DEST_ID_MASK 0x0000ff00 +#define HT_IRQ_LOW_DEST_ID(v) (((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK) + +#define HT_IRQ_LOW_DM_PHYSICAL 0x0000000 +#define HT_IRQ_LOW_DM_LOGICAL 0x0000040 + +#define HT_IRQ_LOW_RQEOI_EDGE 0x0000000 +#define HT_IRQ_LOW_RQEOI_LEVEL 0x0000020 + + +#define HT_IRQ_LOW_MT_FIXED 0x0000000 +#define HT_IRQ_LOW_MT_ARBITRATED 0x0000004 +#define HT_IRQ_LOW_MT_SMI 0x0000008 +#define HT_IRQ_LOW_MT_NMI 0x000000c +#define HT_IRQ_LOW_MT_INIT 0x0000010 +#define HT_IRQ_LOW_MT_STARTUP 0x0000014 +#define HT_IRQ_LOW_MT_EXTINT 0x0000018 +#define HT_IRQ_LOW_MT_LINT1 0x000008c +#define HT_IRQ_LOW_MT_LINT0 0x0000098 + +#define HT_IRQ_LOW_IRQ_MASKED 0x0000001 + + +#define HT_IRQ_HIGH_DEST_ID_SHIFT 0 +#define HT_IRQ_HIGH_DEST_ID_MASK 0x00ffffff +#define HT_IRQ_HIGH_DEST_ID(v) ((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK) + +#endif /* ASM_HYPERTRANSPORT_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 2aabe90f1cd2..9b34bc8f34e4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -681,6 +681,23 @@ extern int msi_register(struct msi_ops *ops); #endif +#ifdef CONFIG_HT_IRQ +/* Helper functions.. */ +void write_ht_irq_low(unsigned int irq, u32 data); +void write_ht_irq_high(unsigned int irq, u32 data); +u32 read_ht_irq_low(unsigned int irq); +u32 read_ht_irq_high(unsigned int irq); +void mask_ht_irq(unsigned int irq); +void unmask_ht_irq(unsigned int irq); + +/* The functions a driver should call */ +int ht_create_irq(struct pci_dev *dev, int idx); +void ht_destroy_irq(unsigned int irq); + +/* The arch hook for getting things started */ +int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev); +#endif /* CONFIG_HT_IRQ */ + extern void pci_block_user_cfg_access(struct pci_dev *dev); extern void pci_unblock_user_cfg_access(struct pci_dev *dev); -- cgit v1.2.3 From 1f80025e624bb14fefadfef7e80fbfb9740d4714 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:56 -0700 Subject: [PATCH] msi: simplify msi sanity checks by adding with generic irq code Currently msi.c is doing sanity checks that make certain before an irq is destroyed it has no more users. By adding irq_has_action I can perform the test is a generic way, instead of relying on a msi specific data structure. By performing the core check in dynamic_irq_cleanup I ensure every user of dynamic irqs has a test present and we don't free resources that are in use. In msi.c this allows me to kill the attrib.state member of msi_desc and all of the assciated code to maintain it. To keep from freeing data structures when irq cleanup code is called to soon changing dyanamic_irq_cleanup is insufficient because there are msi specific data structures that are also not safe to free. Signed-off-by: Eric W. Biederman Cc: Ingo Molnar Cc: Tony Luck Cc: Andi Kleen Cc: Thomas Gleixner Cc: Greg KH Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/msi.c | 43 ++++++++----------------------------------- drivers/pci/msi.h | 2 +- include/linux/irq.h | 7 +++++++ kernel/irq/chip.c | 7 +++++++ 4 files changed, 23 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index da2c6c2b6b11..e3ba3963988c 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -188,18 +188,6 @@ static void unmask_MSI_irq(unsigned int irq) static unsigned int startup_msi_irq_wo_maskbit(unsigned int irq) { - struct msi_desc *entry; - unsigned long flags; - - spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[irq]; - if (!entry || !entry->dev) { - spin_unlock_irqrestore(&msi_lock, flags); - return 0; - } - entry->msi_attrib.state = 1; /* Mark it active */ - spin_unlock_irqrestore(&msi_lock, flags); - return 0; /* never anything pending */ } @@ -212,14 +200,6 @@ static unsigned int startup_msi_irq_w_maskbit(unsigned int irq) static void shutdown_msi_irq(unsigned int irq) { - struct msi_desc *entry; - unsigned long flags; - - spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[irq]; - if (entry && entry->dev) - entry->msi_attrib.state = 0; /* Mark it not active */ - spin_unlock_irqrestore(&msi_lock, flags); } static void end_msi_irq_wo_maskbit(unsigned int irq) @@ -671,7 +651,6 @@ static int msi_capability_init(struct pci_dev *dev) entry->link.head = irq; entry->link.tail = irq; entry->msi_attrib.type = PCI_CAP_ID_MSI; - entry->msi_attrib.state = 0; /* Mark it not active */ entry->msi_attrib.is_64 = is_64bit_address(control); entry->msi_attrib.entry_nr = 0; entry->msi_attrib.maskbit = is_mask_bit_support(control); @@ -744,7 +723,6 @@ static int msix_capability_init(struct pci_dev *dev, j = entries[i].entry; entries[i].vector = irq; entry->msi_attrib.type = PCI_CAP_ID_MSIX; - entry->msi_attrib.state = 0; /* Mark it not active */ entry->msi_attrib.is_64 = 1; entry->msi_attrib.entry_nr = j; entry->msi_attrib.maskbit = 1; @@ -897,12 +875,12 @@ void pci_disable_msi(struct pci_dev* dev) spin_unlock_irqrestore(&msi_lock, flags); return; } - if (entry->msi_attrib.state) { + if (irq_has_action(dev->irq)) { spin_unlock_irqrestore(&msi_lock, flags); printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without " "free_irq() on MSI irq %d\n", pci_name(dev), dev->irq); - BUG_ON(entry->msi_attrib.state > 0); + BUG_ON(irq_has_action(dev->irq)); } else { default_irq = entry->msi_attrib.default_irq; spin_unlock_irqrestore(&msi_lock, flags); @@ -1035,17 +1013,16 @@ void pci_disable_msix(struct pci_dev* dev) temp = dev->irq; if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { - int state, irq, head, tail = 0, warning = 0; + int irq, head, tail = 0, warning = 0; unsigned long flags; irq = head = dev->irq; dev->irq = temp; /* Restore pin IRQ */ while (head != tail) { spin_lock_irqsave(&msi_lock, flags); - state = msi_desc[irq]->msi_attrib.state; tail = msi_desc[irq]->link.tail; spin_unlock_irqrestore(&msi_lock, flags); - if (state) + if (irq_has_action(irq)) warning = 1; else if (irq != head) /* Release MSI-X irq */ msi_free_irq(dev, irq); @@ -1072,7 +1049,7 @@ void pci_disable_msix(struct pci_dev* dev) **/ void msi_remove_pci_irq_vectors(struct pci_dev* dev) { - int state, pos, temp; + int pos, temp; unsigned long flags; if (!pci_msi_enable || !dev) @@ -1081,14 +1058,11 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) temp = dev->irq; /* Save IOAPIC IRQ */ pos = pci_find_capability(dev, PCI_CAP_ID_MSI); if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) { - spin_lock_irqsave(&msi_lock, flags); - state = msi_desc[dev->irq]->msi_attrib.state; - spin_unlock_irqrestore(&msi_lock, flags); - if (state) { + if (irq_has_action(dev->irq)) { printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " "called without free_irq() on MSI irq %d\n", pci_name(dev), dev->irq); - BUG_ON(state > 0); + BUG_ON(irq_has_action(dev->irq)); } else /* Release MSI irq assigned to this device */ msi_free_irq(dev, dev->irq); dev->irq = temp; /* Restore IOAPIC IRQ */ @@ -1101,11 +1075,10 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) irq = head = dev->irq; while (head != tail) { spin_lock_irqsave(&msi_lock, flags); - state = msi_desc[irq]->msi_attrib.state; tail = msi_desc[irq]->link.tail; base = msi_desc[irq]->mask_base; spin_unlock_irqrestore(&msi_lock, flags); - if (state) + if (irq_has_action(irq)) warning = 1; else if (irq != head) /* Release MSI-X irq */ msi_free_irq(dev, irq); diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 435d05aae4ba..77823bfed5c1 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -53,7 +53,7 @@ struct msi_desc { struct { __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ __u8 maskbit : 1; /* mask-pending bit supported ? */ - __u8 state : 1; /* {0: free, 1: busy} */ + __u8 unused : 1; __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ __u8 pos; /* Location of the msi capability */ __u16 entry_nr; /* specific enabled entry */ diff --git a/include/linux/irq.h b/include/linux/irq.h index 69855b23dff9..6f463606c318 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -372,6 +372,13 @@ set_irq_chained_handler(unsigned int irq, extern int create_irq(void); extern void destroy_irq(unsigned int irq); +/* Test to see if a driver has successfully requested an irq */ +static inline int irq_has_action(unsigned int irq) +{ + struct irq_desc *desc = irq_desc + irq; + return desc->action != NULL; +} + /* Dynamic irq helper functions */ extern void dynamic_irq_init(unsigned int irq); extern void dynamic_irq_cleanup(unsigned int irq); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 0dc24386dd99..4cf65f5c6a74 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -67,6 +67,13 @@ void dynamic_irq_cleanup(unsigned int irq) desc = irq_desc + irq; spin_lock_irqsave(&desc->lock, flags); + if (desc->action) { + spin_unlock_irqrestore(&desc->lock, flags); + printk(KERN_ERR "Destroying IRQ%d without calling free_irq\n", + irq); + WARN_ON(1); + return; + } desc->handle_irq = handle_bad_irq; desc->chip = &no_irq_chip; spin_unlock_irqrestore(&desc->lock, flags); -- cgit v1.2.3 From 3b7d1921f4cdd6d6ddb7899ae7a8d413991c5cf4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:16:59 -0700 Subject: [PATCH] msi: refactor and move the msi irq_chip into the arch code It turns out msi_ops was simply not enough to abstract the architecture specific details of msi. So I have moved the resposibility of constructing the struct irq_chip to the architectures, and have two architecture specific functions arch_setup_msi_irq, and arch_teardown_msi_irq. For simple architectures those functions can do all of the work. For architectures with platform dependencies they can call into the appropriate platform code. With this msi.c is finally free of assuming you have an apic, and this actually takes less code. The helpers for the architecture specific code are declared in the linux/msi.h to keep them separate from the msi functions used by drivers in linux/pci.h Signed-off-by: Eric W. Biederman Cc: Ingo Molnar Cc: Tony Luck Cc: Andi Kleen Cc: Thomas Gleixner Cc: Greg KH Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/io_apic.c | 81 +++++++++++++++------- arch/x86_64/kernel/io_apic.c | 89 ++++++++++++++++-------- drivers/pci/msi-altix.c | 81 +++++++++++++--------- drivers/pci/msi-apic.c | 86 +++++++++++++++++------ drivers/pci/msi.c | 150 +++++++++-------------------------------- drivers/pci/msi.h | 27 -------- include/asm-i386/msi.h | 20 ------ include/asm-ia64/machvec.h | 21 ++++-- include/asm-ia64/machvec_sn2.h | 9 ++- include/asm-ia64/msi.h | 29 -------- include/asm-x86_64/msi.h | 21 ------ include/linux/msi.h | 49 ++++++++++++++ include/linux/pci.h | 67 ------------------ 13 files changed, 335 insertions(+), 395 deletions(-) delete mode 100644 include/asm-i386/msi.h delete mode 100644 include/asm-ia64/msi.h delete mode 100644 include/asm-x86_64/msi.h create mode 100644 include/linux/msi.h (limited to 'include/linux') diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 100406b453b8..5a1252753dbb 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -2455,11 +2456,8 @@ void destroy_irq(unsigned int irq) * MSI mesage composition */ #ifdef CONFIG_PCI_MSI -static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) +static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) { - /* For now always this code always uses physical delivery - * mode. - */ int vector; unsigned dest; @@ -2489,34 +2487,71 @@ static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg return vector; } -static void msi_msg_teardown(unsigned int irq) -{ - return; -} - -static void msi_msg_set_affinity(unsigned int irq, cpumask_t mask, struct msi_msg *msg) +#ifdef CONFIG_SMP +static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) { + struct msi_msg msg; + unsigned int dest; + cpumask_t tmp; int vector; - unsigned dest; + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) + tmp = TARGET_CPUS; vector = assign_irq_vector(irq); - if (vector > 0) { - dest = cpu_mask_to_apicid(mask); + if (vector < 0) + return; - msg->data &= ~MSI_DATA_VECTOR_MASK; - msg->data |= MSI_DATA_VECTOR(vector); - msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK; - msg->address_lo |= MSI_ADDR_DEST_ID(dest); - } + dest = cpu_mask_to_apicid(mask); + + read_msi_msg(irq, &msg); + + msg.data &= ~MSI_DATA_VECTOR_MASK; + msg.data |= MSI_DATA_VECTOR(vector); + msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; + msg.address_lo |= MSI_ADDR_DEST_ID(dest); + + write_msi_msg(irq, &msg); + set_native_irq_info(irq, mask); } +#endif /* CONFIG_SMP */ -struct msi_ops arch_msi_ops = { - .needs_64bit_address = 0, - .setup = msi_msg_setup, - .teardown = msi_msg_teardown, - .target = msi_msg_set_affinity, +/* + * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, + * which implement the MSI or MSI-X Capability Structure. + */ +static struct irq_chip msi_chip = { + .name = "PCI-MSI", + .unmask = unmask_msi_irq, + .mask = mask_msi_irq, + .ack = ack_ioapic_irq, +#ifdef CONFIG_SMP + .set_affinity = set_msi_irq_affinity, +#endif + .retrigger = ioapic_retrigger_irq, }; +int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) +{ + struct msi_msg msg; + int ret; + ret = msi_compose_msg(dev, irq, &msg); + if (ret < 0) + return ret; + + write_msi_msg(irq, &msg); + + set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq); + + return 0; +} + +void arch_teardown_msi_irq(unsigned int irq) +{ + return; +} + #endif /* CONFIG_PCI_MSI */ /* diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 31c270fee337..e55028fba942 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef CONFIG_ACPI #include #endif @@ -1701,11 +1702,8 @@ void destroy_irq(unsigned int irq) * MSI mesage composition */ #ifdef CONFIG_PCI_MSI -static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) +static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) { - /* For now always this code always uses physical delivery - * mode. - */ int vector; unsigned dest; @@ -1739,39 +1737,76 @@ static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg return vector; } -static void msi_msg_teardown(unsigned int irq) -{ - return; -} - -static void msi_msg_set_affinity(unsigned int irq, cpumask_t mask, struct msi_msg *msg) +#ifdef CONFIG_SMP +static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) { + struct msi_msg msg; + unsigned int dest; + cpumask_t tmp; int vector; - unsigned dest; + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) + tmp = TARGET_CPUS; + + cpus_and(mask, tmp, CPU_MASK_ALL); vector = assign_irq_vector(irq, mask); - if (vector > 0) { - cpumask_t tmp; + if (vector < 0) + return; - cpus_clear(tmp); - cpu_set(vector >> 8, tmp); - dest = cpu_mask_to_apicid(tmp); + cpus_clear(tmp); + cpu_set(vector >> 8, tmp); + dest = cpu_mask_to_apicid(tmp); - msg->data &= ~MSI_DATA_VECTOR_MASK; - msg->data |= MSI_DATA_VECTOR(vector); - msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK; - msg->address_lo |= MSI_ADDR_DEST_ID(dest); - } + read_msi_msg(irq, &msg); + + msg.data &= ~MSI_DATA_VECTOR_MASK; + msg.data |= MSI_DATA_VECTOR(vector); + msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; + msg.address_lo |= MSI_ADDR_DEST_ID(dest); + + write_msi_msg(irq, &msg); + set_native_irq_info(irq, mask); } +#endif /* CONFIG_SMP */ -struct msi_ops arch_msi_ops = { - .needs_64bit_address = 0, - .setup = msi_msg_setup, - .teardown = msi_msg_teardown, - .target = msi_msg_set_affinity, +/* + * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, + * which implement the MSI or MSI-X Capability Structure. + */ +static struct irq_chip msi_chip = { + .name = "PCI-MSI", + .unmask = unmask_msi_irq, + .mask = mask_msi_irq, + .ack = ack_apic_edge, +#ifdef CONFIG_SMP + .set_affinity = set_msi_irq_affinity, +#endif + .retrigger = ioapic_retrigger_irq, }; -#endif +int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) +{ + struct msi_msg msg; + int ret; + ret = msi_compose_msg(dev, irq, &msg); + if (ret < 0) + return ret; + + write_msi_msg(irq, &msg); + + set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq); + + return 0; +} + +void arch_teardown_msi_irq(unsigned int irq) +{ + return; +} + +#endif /* CONFIG_PCI_MSI */ /* * Hypertransport interrupt support diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c index 7aedc2ac8c28..6ffd1f850d41 100644 --- a/drivers/pci/msi-altix.c +++ b/drivers/pci/msi-altix.c @@ -7,8 +7,10 @@ */ #include +#include #include #include +#include #include #include @@ -16,17 +18,16 @@ #include #include -#include "msi.h" - struct sn_msi_info { u64 pci_addr; struct sn_irq_info *sn_irq_info; }; -static struct sn_msi_info *sn_msi_info; +static struct sn_msi_info sn_msi_info[NR_IRQS]; + +static struct irq_chip sn_msi_chip; -static void -sn_msi_teardown(unsigned int irq) +void sn_teardown_msi_irq(unsigned int irq) { nasid_t nasid; int widget; @@ -61,9 +62,10 @@ sn_msi_teardown(unsigned int irq) return; } -int -sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) +int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) { + struct msi_msg msg; + struct msi_desc *entry; int widget; int status; nasid_t nasid; @@ -72,6 +74,10 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); + entry = get_irq_data(irq); + if (!entry->msi_attrib.is_64) + return -EINVAL; + if (bussoft == NULL) return -EINVAL; @@ -121,25 +127,29 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) sn_msi_info[irq].sn_irq_info = sn_irq_info; sn_msi_info[irq].pci_addr = bus_addr; - msg->address_hi = (u32)(bus_addr >> 32); - msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff); + msg.address_hi = (u32)(bus_addr >> 32); + msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff); /* * In the SN platform, bit 16 is a "send vector" bit which * must be present in order to move the vector through the system. */ - msg->data = 0x100 + irq; + msg.data = 0x100 + irq; #ifdef CONFIG_SMP set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0); #endif + write_msi_msg(irq, &msg); + set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq); + return 0; } -static void -sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) +#ifdef CONFIG_SMP +static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask) { + struct msi_msg msg; int slice; nasid_t nasid; u64 bus_addr; @@ -159,11 +169,12 @@ sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) * Release XIO resources for the old MSI PCI address */ + read_msi_msg(irq, &msg); sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; pdev = sn_pdev->pdi_linux_pcidev; provider = SN_PCIDEV_BUSPROVIDER(pdev); - bus_addr = (u64)(msg->address_hi) << 32 | (u64)(msg->address_lo); + bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo); (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); sn_msi_info[irq].pci_addr = 0; @@ -185,27 +196,35 @@ sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) SN_DMA_MSI|SN_DMA_ADDR_XIO); sn_msi_info[irq].pci_addr = bus_addr; - msg->address_hi = (u32)(bus_addr >> 32); - msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff); + msg.address_hi = (u32)(bus_addr >> 32); + msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff); + + write_msi_msg(irq, &msg); + set_native_irq_info(irq, cpu_mask); } +#endif /* CONFIG_SMP */ -struct msi_ops sn_msi_ops = { - .needs_64bit_address = 1, - .setup = sn_msi_setup, - .teardown = sn_msi_teardown, -#ifdef CONFIG_SMP - .target = sn_msi_target, -#endif -}; +static void sn_ack_msi_irq(unsigned int irq) +{ + move_native_irq(irq); + ia64_eoi(); +} -int -sn_msi_init(void) +static int sn_msi_retrigger_irq(unsigned int irq) { - sn_msi_info = - kzalloc(sizeof(struct sn_msi_info) * NR_IRQS, GFP_KERNEL); - if (! sn_msi_info) - return -ENOMEM; + unsigned int vector = irq; + ia64_resend_irq(vector); - msi_register(&sn_msi_ops); - return 0; + return 1; } + +static struct irq_chip sn_msi_chip = { + .name = "PCI-MSI", + .mask = mask_msi_irq, + .unmask = unmask_msi_irq, + .ack = sn_ack_msi_irq, +#ifdef CONFIG_SMP + .set_affinity = sn_set_msi_irq_affinity, +#endif + .retrigger = sn_msi_retrigger_irq, +}; diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c index afc0ed13aa89..822e59a1b822 100644 --- a/drivers/pci/msi-apic.c +++ b/drivers/pci/msi-apic.c @@ -4,10 +4,9 @@ #include #include +#include #include -#include "msi.h" - /* * Shifts for APIC-based data */ @@ -31,6 +30,7 @@ * Shift/mask fields for APIC-based bus address */ +#define MSI_TARGET_CPU_SHIFT 4 #define MSI_ADDR_HEADER 0xfee00000 #define MSI_ADDR_DESTID_MASK 0xfff0000f @@ -44,58 +44,100 @@ #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) #define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) +static struct irq_chip ia64_msi_chip; -static void -msi_target_apic(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) +#ifdef CONFIG_SMP +static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask) { - u32 addr = msg->address_lo; + struct msi_msg msg; + u32 addr; + + read_msi_msg(irq, &msg); + addr = msg.address_lo; addr &= MSI_ADDR_DESTID_MASK; addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask))); + msg.address_lo = addr; - msg->address_lo = addr; + write_msi_msg(irq, &msg); + set_native_irq_info(irq, cpu_mask); } +#endif /* CONFIG_SMP */ -static int -msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ - unsigned int irq, - struct msi_msg *msg) +int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) { + struct msi_msg msg; unsigned long dest_phys_id; unsigned int vector; dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); vector = irq; - msg->address_hi = 0; - msg->address_lo = + msg.address_hi = 0; + msg.address_lo = MSI_ADDR_HEADER | MSI_ADDR_DESTMODE_PHYS | MSI_ADDR_REDIRECTION_CPU | MSI_ADDR_DESTID_CPU(dest_phys_id); - msg->data = + msg.data = MSI_DATA_TRIGGER_EDGE | MSI_DATA_LEVEL_ASSERT | MSI_DATA_DELIVERY_FIXED | MSI_DATA_VECTOR(vector); + write_msi_msg(irq, &msg); + set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq); + return 0; } -static void -msi_teardown_apic(unsigned int irq) +void ia64_teardown_msi_irq(unsigned int irq) { return; /* no-op */ } +static void ia64_ack_msi_irq(unsigned int irq) +{ + move_native_irq(irq); + ia64_eoi(); +} + +static int ia64_msi_retrigger_irq(unsigned int irq) +{ + unsigned int vector = irq; + ia64_resend_irq(vector); + + return 1; +} + /* - * Generic ops used on most IA archs/platforms. Set with msi_register() + * Generic ops used on most IA64 platforms. */ - -struct msi_ops msi_apic_ops = { - .needs_64bit_address = 0, - .setup = msi_setup_apic, - .teardown = msi_teardown_apic, - .target = msi_target_apic, +static struct irq_chip ia64_msi_chip = { + .name = "PCI-MSI", + .mask = mask_msi_irq, + .unmask = unmask_msi_irq, + .ack = ia64_ack_msi_irq, +#ifdef CONFIG_SMP + .set_affinity = ia64_set_msi_irq_affinity, +#endif + .retrigger = ia64_msi_retrigger_irq, }; + + +int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) +{ + if (platform_setup_msi_irq) + return platform_setup_msi_irq(irq, pdev); + + return ia64_setup_msi_irq(irq, pdev); +} + +void arch_teardown_msi_irq(unsigned int irq) +{ + if (platform_teardown_msi_irq) + return platform_teardown_msi_irq(irq); + + return ia64_teardown_msi_irq(irq); +} diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index fc7dd2a239dd..f9fdc54473c4 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -29,15 +30,6 @@ static kmem_cache_t* msi_cachep; static int pci_msi_enable = 1; -static struct msi_ops *msi_ops; - -int -msi_register(struct msi_ops *ops) -{ - msi_ops = ops; - return 0; -} - static int msi_cache_init(void) { msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc), @@ -80,8 +72,9 @@ static void msi_set_mask_bit(unsigned int irq, int flag) } } -static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) +void read_msi_msg(unsigned int irq, struct msi_msg *msg) { + struct msi_desc *entry = get_irq_data(irq); switch(entry->msi_attrib.type) { case PCI_CAP_ID_MSI: { @@ -118,8 +111,9 @@ static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) } } -static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) +void write_msi_msg(unsigned int irq, struct msi_msg *msg) { + struct msi_desc *entry = get_irq_data(irq); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: { @@ -157,53 +151,16 @@ static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) } } -#ifdef CONFIG_SMP -static void set_msi_affinity(unsigned int irq, cpumask_t cpu_mask) -{ - struct msi_desc *entry; - struct msi_msg msg; - - entry = msi_desc[irq]; - if (!entry || !entry->dev) - return; - - read_msi_msg(entry, &msg); - msi_ops->target(irq, cpu_mask, &msg); - write_msi_msg(entry, &msg); - set_native_irq_info(irq, cpu_mask); -} -#else -#define set_msi_affinity NULL -#endif /* CONFIG_SMP */ - -static void mask_MSI_irq(unsigned int irq) +void mask_msi_irq(unsigned int irq) { msi_set_mask_bit(irq, 1); } -static void unmask_MSI_irq(unsigned int irq) +void unmask_msi_irq(unsigned int irq) { msi_set_mask_bit(irq, 0); } -static void ack_msi_irq(unsigned int irq) -{ - move_native_irq(irq); - ack_APIC_irq(); -} - -/* - * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, - * which implement the MSI or MSI-X Capability Structure. - */ -static struct irq_chip msi_chip = { - .name = "PCI-MSI", - .unmask = unmask_MSI_irq, - .mask = mask_MSI_irq, - .ack = ack_msi_irq, - .set_affinity = set_msi_affinity -}; - static int msi_free_irq(struct pci_dev* dev, int irq); static int msi_init(void) { @@ -219,22 +176,6 @@ static int msi_init(void) return status; } - status = msi_arch_init(); - if (status < 0) { - pci_msi_enable = 0; - printk(KERN_WARNING - "PCI: MSI arch init failed. MSI disabled.\n"); - return status; - } - - if (! msi_ops) { - pci_msi_enable = 0; - printk(KERN_WARNING - "PCI: MSI ops not registered. MSI disabled.\n"); - status = -EINVAL; - return status; - } - status = msi_cache_init(); if (status < 0) { pci_msi_enable = 0; @@ -268,7 +209,7 @@ static void attach_msi_entry(struct msi_desc *entry, int irq) spin_unlock_irqrestore(&msi_lock, flags); } -static int create_msi_irq(struct irq_chip *chip) +static int create_msi_irq(void) { struct msi_desc *entry; int irq; @@ -283,7 +224,6 @@ static int create_msi_irq(struct irq_chip *chip) return -EBUSY; } - set_irq_chip_and_handler(irq, chip, handle_edge_irq); set_irq_data(irq, entry); return irq; @@ -473,7 +413,7 @@ int pci_save_msix_state(struct pci_dev *dev) struct msi_desc *entry; entry = msi_desc[irq]; - read_msi_msg(entry, &entry->msg_save); + read_msi_msg(irq, &entry->msg_save); tail = msi_desc[irq]->link.tail; irq = tail; @@ -512,7 +452,7 @@ void pci_restore_msix_state(struct pci_dev *dev) irq = head = dev->irq; while (head != tail) { entry = msi_desc[irq]; - write_msi_msg(entry, &entry->msg_save); + write_msi_msg(irq, &entry->msg_save); tail = msi_desc[irq]->link.tail; irq = tail; @@ -524,39 +464,6 @@ void pci_restore_msix_state(struct pci_dev *dev) } #endif -static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) -{ - int status; - struct msi_msg msg; - int pos; - u16 control; - - pos = entry->msi_attrib.pos; - pci_read_config_word(dev, msi_control_reg(pos), &control); - - /* Configure MSI capability structure */ - status = msi_ops->setup(dev, dev->irq, &msg); - if (status < 0) - return status; - - write_msi_msg(entry, &msg); - if (entry->msi_attrib.maskbit) { - unsigned int maskbits, temp; - /* All MSIs are unmasked by default, Mask them all */ - pci_read_config_dword(dev, - msi_mask_bits_reg(pos, is_64bit_address(control)), - &maskbits); - temp = (1 << multi_msi_capable(control)); - temp = ((temp - 1) & ~temp); - maskbits |= temp; - pci_write_config_dword(dev, - msi_mask_bits_reg(pos, is_64bit_address(control)), - maskbits); - } - - return 0; -} - /** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function @@ -576,7 +483,7 @@ static int msi_capability_init(struct pci_dev *dev) pos = pci_find_capability(dev, PCI_CAP_ID_MSI); pci_read_config_word(dev, msi_control_reg(pos), &control); /* MSI Entry Initialization */ - irq = create_msi_irq(&msi_chip); + irq = create_msi_irq(); if (irq < 0) return irq; @@ -589,16 +496,27 @@ static int msi_capability_init(struct pci_dev *dev) entry->msi_attrib.maskbit = is_mask_bit_support(control); entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ entry->msi_attrib.pos = pos; - dev->irq = irq; - entry->dev = dev; if (is_mask_bit_support(control)) { entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos, is_64bit_address(control)); } + entry->dev = dev; + if (entry->msi_attrib.maskbit) { + unsigned int maskbits, temp; + /* All MSIs are unmasked by default, Mask them all */ + pci_read_config_dword(dev, + msi_mask_bits_reg(pos, is_64bit_address(control)), + &maskbits); + temp = (1 << multi_msi_capable(control)); + temp = ((temp - 1) & ~temp); + maskbits |= temp; + pci_write_config_dword(dev, + msi_mask_bits_reg(pos, is_64bit_address(control)), + maskbits); + } /* Configure MSI capability structure */ - status = msi_register_init(dev, entry); - if (status != 0) { - dev->irq = entry->msi_attrib.default_irq; + status = arch_setup_msi_irq(irq, dev); + if (status < 0) { destroy_msi_irq(irq); return status; } @@ -607,6 +525,7 @@ static int msi_capability_init(struct pci_dev *dev) /* Set MSI enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + dev->irq = irq; return 0; } @@ -624,7 +543,6 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, int nvec) { struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; - struct msi_msg msg; int status; int irq, pos, i, j, nr_entries, temp = 0; unsigned long phys_addr; @@ -648,7 +566,7 @@ static int msix_capability_init(struct pci_dev *dev, /* MSI-X Table Initialization */ for (i = 0; i < nvec; i++) { - irq = create_msi_irq(&msi_chip); + irq = create_msi_irq(); if (irq < 0) break; @@ -676,13 +594,12 @@ static int msix_capability_init(struct pci_dev *dev, temp = irq; tail = entry; /* Configure MSI-X capability structure */ - status = msi_ops->setup(dev, irq, &msg); + status = arch_setup_msi_irq(irq, dev); if (status < 0) { destroy_msi_irq(irq); break; } - write_msi_msg(entry, &msg); attach_msi_entry(entry, irq); } if (i != nvec) { @@ -746,7 +663,6 @@ int pci_msi_supported(struct pci_dev * dev) int pci_enable_msi(struct pci_dev* dev) { int pos, temp, status; - u16 control; if (pci_msi_supported(dev) < 0) return -EINVAL; @@ -761,10 +677,6 @@ int pci_enable_msi(struct pci_dev* dev) if (!pos) return -EINVAL; - pci_read_config_word(dev, msi_control_reg(pos), &control); - if (!is_64bit_address(control) && msi_ops->needs_64bit_address) - return -EINVAL; - WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI)); /* Check whether driver already requested for MSI-X irqs */ @@ -831,7 +743,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq) void __iomem *base; unsigned long flags; - msi_ops->teardown(irq); + arch_teardown_msi_irq(irq); spin_lock_irqsave(&msi_lock, flags); entry = msi_desc[irq]; diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 77823bfed5c1..f0cca1772f9c 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -6,8 +6,6 @@ #ifndef MSI_H #define MSI_H -#include - /* * MSI-X Address Register */ @@ -49,29 +47,4 @@ #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) -struct msi_desc { - struct { - __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ - __u8 maskbit : 1; /* mask-pending bit supported ? */ - __u8 unused : 1; - __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ - __u8 pos; /* Location of the msi capability */ - __u16 entry_nr; /* specific enabled entry */ - unsigned default_irq; /* default pre-assigned irq */ - }msi_attrib; - - struct { - __u16 head; - __u16 tail; - }link; - - void __iomem *mask_base; - struct pci_dev *dev; - -#ifdef CONFIG_PM - /* PM save area for MSIX address/data */ - struct msi_msg msg_save; -#endif -}; - #endif /* MSI_H */ diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h deleted file mode 100644 index 7368a89a0f42..000000000000 --- a/include/asm-i386/msi.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2003-2004 Intel - * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) - */ - -#ifndef ASM_MSI_H -#define ASM_MSI_H - -#include -#include - -extern struct msi_ops arch_msi_ops; - -static inline int msi_arch_init(void) -{ - msi_register(&arch_msi_ops); - return 0; -} - -#endif /* ASM_MSI_H */ diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h index 15b545a897a4..90cba967df35 100644 --- a/include/asm-ia64/machvec.h +++ b/include/asm-ia64/machvec.h @@ -20,6 +20,7 @@ struct page; struct mm_struct; struct pci_bus; struct task_struct; +struct pci_dev; typedef void ia64_mv_setup_t (char **); typedef void ia64_mv_cpu_init_t (void); @@ -75,7 +76,9 @@ typedef unsigned char ia64_mv_readb_relaxed_t (const volatile void __iomem *); typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *); typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *); typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *); -typedef int ia64_mv_msi_init_t (void); + +typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev); +typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq); static inline void machvec_noop (void) @@ -154,7 +157,8 @@ extern void machvec_tlb_migrate_finish (struct mm_struct *); # define platform_readl_relaxed ia64_mv.readl_relaxed # define platform_readq_relaxed ia64_mv.readq_relaxed # define platform_migrate ia64_mv.migrate -# define platform_msi_init ia64_mv.msi_init +# define platform_setup_msi_irq ia64_mv.setup_msi_irq +# define platform_teardown_msi_irq ia64_mv.teardown_msi_irq # endif /* __attribute__((__aligned__(16))) is required to make size of the @@ -204,7 +208,8 @@ struct ia64_machine_vector { ia64_mv_readl_relaxed_t *readl_relaxed; ia64_mv_readq_relaxed_t *readq_relaxed; ia64_mv_migrate_t *migrate; - ia64_mv_msi_init_t *msi_init; + ia64_mv_setup_msi_irq_t *setup_msi_irq; + ia64_mv_teardown_msi_irq_t *teardown_msi_irq; } __attribute__((__aligned__(16))); /* align attrib? see above comment */ #define MACHVEC_INIT(name) \ @@ -250,7 +255,8 @@ struct ia64_machine_vector { platform_readl_relaxed, \ platform_readq_relaxed, \ platform_migrate, \ - platform_msi_init, \ + platform_setup_msi_irq, \ + platform_teardown_msi_irq, \ } extern struct ia64_machine_vector ia64_mv; @@ -404,8 +410,11 @@ extern int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size #ifndef platform_migrate # define platform_migrate machvec_noop_task #endif -#ifndef platform_msi_init -# define platform_msi_init ((ia64_mv_msi_init_t*)NULL) +#ifndef platform_setup_msi_irq +# define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL) +#endif +#ifndef platform_teardown_msi_irq +# define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL) #endif #endif /* _ASM_IA64_MACHVEC_H */ diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h index cf724dc79d8c..c54b165b1c17 100644 --- a/include/asm-ia64/machvec_sn2.h +++ b/include/asm-ia64/machvec_sn2.h @@ -67,7 +67,8 @@ extern ia64_mv_dma_sync_sg_for_device sn_dma_sync_sg_for_device; extern ia64_mv_dma_mapping_error sn_dma_mapping_error; extern ia64_mv_dma_supported sn_dma_supported; extern ia64_mv_migrate_t sn_migrate; -extern ia64_mv_msi_init_t sn_msi_init; +extern ia64_mv_setup_msi_irq_t sn_setup_msi_irq; +extern ia64_mv_teardown_msi_irq_t sn_teardown_msi_irq; /* @@ -120,9 +121,11 @@ extern ia64_mv_msi_init_t sn_msi_init; #define platform_dma_supported sn_dma_supported #define platform_migrate sn_migrate #ifdef CONFIG_PCI_MSI -#define platform_msi_init sn_msi_init +#define platform_setup_msi_irq sn_setup_msi_irq +#define platform_teardown_msi_irq sn_teardown_msi_irq #else -#define platform_msi_init ((ia64_mv_msi_init_t*)NULL) +#define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL) +#define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL) #endif #include diff --git a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h deleted file mode 100644 index bb92b0dbde2f..000000000000 --- a/include/asm-ia64/msi.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2003-2004 Intel - * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) - */ - -#ifndef ASM_MSI_H -#define ASM_MSI_H - -#define NR_VECTORS NR_IRQS -#define FIRST_DEVICE_VECTOR IA64_FIRST_DEVICE_VECTOR -#define LAST_DEVICE_VECTOR IA64_LAST_DEVICE_VECTOR -static inline void set_intr_gate (int nr, void *func) {} -#define IO_APIC_VECTOR(irq) (irq) -#define ack_APIC_irq ia64_eoi -#define MSI_TARGET_CPU_SHIFT 4 - -extern struct msi_ops msi_apic_ops; - -static inline int msi_arch_init(void) -{ - if (platform_msi_init) - return platform_msi_init(); - - /* default ops for most ia64 platforms */ - msi_register(&msi_apic_ops); - return 0; -} - -#endif /* ASM_MSI_H */ diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h deleted file mode 100644 index 1876fda52ae3..000000000000 --- a/include/asm-x86_64/msi.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2003-2004 Intel - * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) - */ - -#ifndef ASM_MSI_H -#define ASM_MSI_H - -#include -#include -#include - -extern struct msi_ops arch_msi_ops; - -static inline int msi_arch_init(void) -{ - msi_register(&arch_msi_ops); - return 0; -} - -#endif /* ASM_MSI_H */ diff --git a/include/linux/msi.h b/include/linux/msi.h new file mode 100644 index 000000000000..c7ef94343673 --- /dev/null +++ b/include/linux/msi.h @@ -0,0 +1,49 @@ +#ifndef LINUX_MSI_H +#define LINUX_MSI_H + +struct msi_msg { + u32 address_lo; /* low 32 bits of msi message address */ + u32 address_hi; /* high 32 bits of msi message address */ + u32 data; /* 16 bits of msi message data */ +}; + +/* Heper functions */ +extern void mask_msi_irq(unsigned int irq); +extern void unmask_msi_irq(unsigned int irq); +extern void read_msi_msg(unsigned int irq, struct msi_msg *msg); + +extern void write_msi_msg(unsigned int irq, struct msi_msg *msg); + +struct msi_desc { + struct { + __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ + __u8 maskbit : 1; /* mask-pending bit supported ? */ + __u8 unused : 1; + __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ + __u8 pos; /* Location of the msi capability */ + __u16 entry_nr; /* specific enabled entry */ + unsigned default_irq; /* default pre-assigned irq */ + }msi_attrib; + + struct { + __u16 head; + __u16 tail; + }link; + + void __iomem *mask_base; + struct pci_dev *dev; + +#ifdef CONFIG_PM + /* PM save area for MSIX address/data */ + struct msi_msg msg_save; +#endif +}; + +/* + * The arch hook for setup up msi irqs + */ +int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev); +void arch_teardown_msi_irq(unsigned int irq); + + +#endif /* LINUX_MSI_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 9b34bc8f34e4..0da5a4a8940f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -595,11 +595,6 @@ struct msix_entry { u16 entry; /* driver uses to specify entry, OS writes */ }; -struct msi_msg { - u32 address_lo; /* low 32 bits of msi message address */ - u32 address_hi; /* high 32 bits of msi message address */ - u32 data; /* 16 bits of msi message data */ -}; #ifndef CONFIG_PCI_MSI static inline void pci_scan_msi_device(struct pci_dev *dev) {} @@ -617,68 +612,6 @@ extern int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec); extern void pci_disable_msix(struct pci_dev *dev); extern void msi_remove_pci_irq_vectors(struct pci_dev *dev); - -/* - * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) - * to abstract platform-specific tasks relating to MSI address generation - * and resource management. - */ -struct msi_ops { - int needs_64bit_address; - /** - * setup - generate an MSI bus address and data for a given vector - * @pdev: PCI device context (in) - * @irq: irq allocated by the msi core (in) - * @msg: PCI bus address and data for msi message (out) - * - * Description: The setup op is used to generate a PCI bus addres and - * data which the msi core will program into the card MSI capability - * registers. The setup routine is responsible for picking an initial - * cpu to target the MSI at. The setup routine is responsible for - * examining pdev to determine the MSI capabilities of the card and - * generating a suitable address/data. The setup routine is - * responsible for allocating and tracking any system resources it - * needs to route the MSI to the cpu it picks, and for associating - * those resources with the passed in vector. - * - * Returns 0 if the MSI address/data was successfully setup. - **/ - - int (*setup) (struct pci_dev *pdev, unsigned int irq, - struct msi_msg *msg); - - /** - * teardown - release resources allocated by setup - * @vector: vector context for resources (in) - * - * Description: The teardown op is used to release any resources - * that were allocated in the setup routine associated with the passed - * in vector. - **/ - - void (*teardown) (unsigned int irq); - - /** - * target - retarget an MSI at a different cpu - * @vector: vector context for resources (in) - * @cpu: new cpu to direct vector at (in) - * @addr_hi: new value of PCI bus upper 32 bits (in/out) - * @addr_lo: new value of PCI bus lower 32 bits (in/out) - * - * Description: The target op is used to redirect an MSI vector - * at a different cpu. addr_hi/addr_lo coming in are the existing - * values that the MSI core has programmed into the card. The - * target code is responsible for freeing any resources (if any) - * associated with the old address, and generating a new PCI bus - * addr_hi/addr_lo that will redirect the vector at the indicated cpu. - **/ - - void (*target) (unsigned int irq, cpumask_t cpumask, - struct msi_msg *msg); -}; - -extern int msi_register(struct msi_ops *ops); - #endif #ifdef CONFIG_HT_IRQ -- cgit v1.2.3 From 95d77884c77beed676036d2f74d10b470a483c63 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 4 Oct 2006 02:17:01 -0700 Subject: [PATCH] htirq: tidy up the htirq code This moves the declarations for the architecture helpers into include/linux/htirq.h from the generic include/linux/pci.h. Hopefully this will make this distinction clearer. htirq.h is included where it is needed. The dependency on the msi code is fixed and removed. The Makefile is tidied up. Signed-off-by: Eric W. Biederman Cc: Ingo Molnar Cc: Tony Luck Cc: Andi Kleen Cc: Thomas Gleixner Cc: Greg KH Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/io_apic.c | 5 ++--- arch/x86_64/kernel/io_apic.c | 1 + drivers/pci/Kconfig | 1 - drivers/pci/Makefile | 4 +++- drivers/pci/htirq.c | 1 + include/linux/htirq.h | 15 +++++++++++++++ include/linux/pci.h | 11 ----------- 7 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 include/linux/htirq.h (limited to 'include/linux') diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 5a1252753dbb..b7287fb499f3 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -2409,9 +2410,8 @@ static int __init ioapic_init_sysfs(void) device_initcall(ioapic_init_sysfs); -#ifdef CONFIG_PCI_MSI /* - * Dynamic irq allocate and deallocation for MSI + * Dynamic irq allocate and deallocation */ int create_irq(void) { @@ -2450,7 +2450,6 @@ void destroy_irq(unsigned int irq) irq_vector[irq] = 0; spin_unlock_irqrestore(&vector_lock, flags); } -#endif /* CONFIG_PCI_MSI */ /* * MSI mesage composition diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index e55028fba942..91728d9d3472 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef CONFIG_ACPI #include #endif diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 0af6d7288415..30294127a0aa 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -55,7 +55,6 @@ config PCI_DEBUG config HT_IRQ bool "Interrupts on hypertransport devices" default y - depends on PCI_MSI depends on X86_LOCAL_APIC && X86_IO_APIC help This allows native hypertransport devices to use interrupts. diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 04694ec7224b..e3beb784406f 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -17,6 +17,9 @@ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ # Build the PCI MSI interrupt support obj-$(CONFIG_PCI_MSI) += msi.o +# Build the Hypertransport interrupt support +obj-$(CONFIG_HT_IRQ) += htirq.o + # # Some architectures use the generic PCI setup functions # @@ -29,7 +32,6 @@ obj-$(CONFIG_PPC32) += setup-irq.o obj-$(CONFIG_PPC64) += setup-bus.o obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o -obj-$(CONFIG_HT_IRQ) += htirq.o # # ACPI Related PCI FW Functions diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 4ba46359d367..0e27f2404a83 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -11,6 +11,7 @@ #include #include #include +#include /* Global ht irq lock. * diff --git a/include/linux/htirq.h b/include/linux/htirq.h new file mode 100644 index 000000000000..1f15ce279a23 --- /dev/null +++ b/include/linux/htirq.h @@ -0,0 +1,15 @@ +#ifndef LINUX_HTIRQ_H +#define LINUX_HTIRQ_H + +/* Helper functions.. */ +void write_ht_irq_low(unsigned int irq, u32 data); +void write_ht_irq_high(unsigned int irq, u32 data); +u32 read_ht_irq_low(unsigned int irq); +u32 read_ht_irq_high(unsigned int irq); +void mask_ht_irq(unsigned int irq); +void unmask_ht_irq(unsigned int irq); + +/* The arch hook for getting things started */ +int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev); + +#endif /* LINUX_HTIRQ_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 0da5a4a8940f..5c604f5fad67 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -615,20 +615,9 @@ extern void msi_remove_pci_irq_vectors(struct pci_dev *dev); #endif #ifdef CONFIG_HT_IRQ -/* Helper functions.. */ -void write_ht_irq_low(unsigned int irq, u32 data); -void write_ht_irq_high(unsigned int irq, u32 data); -u32 read_ht_irq_low(unsigned int irq); -u32 read_ht_irq_high(unsigned int irq); -void mask_ht_irq(unsigned int irq); -void unmask_ht_irq(unsigned int irq); - /* The functions a driver should call */ int ht_create_irq(struct pci_dev *dev, int idx); void ht_destroy_irq(unsigned int irq); - -/* The arch hook for getting things started */ -int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev); #endif /* CONFIG_HT_IRQ */ extern void pci_block_user_cfg_access(struct pci_dev *dev); -- cgit v1.2.3 From 621934ee7ed5b073c7fd638b347e632c53572761 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 4 Oct 2006 02:17:02 -0700 Subject: [PATCH] srcu-3: RCU variant permitting read-side blocking Updated patch adding a variant of RCU that permits sleeping in read-side critical sections. SRCU is as follows: o Each use of SRCU creates its own srcu_struct, and each srcu_struct has its own set of grace periods. This is critical, as it prevents one subsystem with a blocking reader from holding up SRCU grace periods for other subsystems. o The SRCU primitives (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu()) all take a pointer to a srcu_struct. o The SRCU primitives must be called from process context. o srcu_read_lock() returns an int that must be passed to the matching srcu_read_unlock(). Realtime RCU avoids the need for this by storing the state in the task struct, but SRCU needs to allow a given code path to pass through multiple SRCU domains -- storing state in the task struct would therefore require either arbitrary space in the task struct or arbitrary limits on SRCU nesting. So I kicked the state-storage problem up to the caller. Of course, it is not permitted to call synchronize_srcu() while in an SRCU read-side critical section. o There is no call_srcu(). It would not be hard to implement one, but it seems like too easy a way to OOM the system. (Hey, we have enough trouble with call_rcu(), which does -not- permit readers to sleep!!!) So, if you want it, please tell me why... [josht@us.ibm.com: sparse notation] Signed-off-by: Paul E. McKenney Signed-off-by: Josh Triplett Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/RCU/checklist.txt | 38 ++++++ Documentation/RCU/rcu.txt | 3 +- Documentation/RCU/whatisRCU.txt | 3 + include/linux/srcu.h | 49 ++++++++ kernel/Makefile | 2 +- kernel/srcu.c | 257 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 include/linux/srcu.h create mode 100644 kernel/srcu.c (limited to 'include/linux') diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt index 1d50cf0c905e..f4dffadbcb00 100644 --- a/Documentation/RCU/checklist.txt +++ b/Documentation/RCU/checklist.txt @@ -221,3 +221,41 @@ over a rather long period of time, but improvements are always welcome! disable irq on a given acquisition of that lock will result in deadlock as soon as the RCU callback happens to interrupt that acquisition's critical section. + +13. SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu()) + may only be invoked from process context. Unlike other forms of + RCU, it -is- permissible to block in an SRCU read-side critical + section (demarked by srcu_read_lock() and srcu_read_unlock()), + hence the "SRCU": "sleepable RCU". Please note that if you + don't need to sleep in read-side critical sections, you should + be using RCU rather than SRCU, because RCU is almost always + faster and easier to use than is SRCU. + + Also unlike other forms of RCU, explicit initialization + and cleanup is required via init_srcu_struct() and + cleanup_srcu_struct(). These are passed a "struct srcu_struct" + that defines the scope of a given SRCU domain. Once initialized, + the srcu_struct is passed to srcu_read_lock(), srcu_read_unlock() + and synchronize_srcu(). A given synchronize_srcu() waits only + for SRCU read-side critical sections governed by srcu_read_lock() + and srcu_read_unlock() calls that have been passd the same + srcu_struct. This property is what makes sleeping read-side + critical sections tolerable -- a given subsystem delays only + its own updates, not those of other subsystems using SRCU. + Therefore, SRCU is less prone to OOM the system than RCU would + be if RCU's read-side critical sections were permitted to + sleep. + + The ability to sleep in read-side critical sections does not + come for free. First, corresponding srcu_read_lock() and + srcu_read_unlock() calls must be passed the same srcu_struct. + Second, grace-period-detection overhead is amortized only + over those updates sharing a given srcu_struct, rather than + being globally amortized as they are for other forms of RCU. + Therefore, SRCU should be used in preference to rw_semaphore + only in extremely read-intensive situations, or in situations + requiring SRCU's read-side deadlock immunity or low read-side + realtime latency. + + Note that, rcu_assign_pointer() and rcu_dereference() relate to + SRCU just as they do to other forms of RCU. diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt index 02e27bf1d365..f84407cba816 100644 --- a/Documentation/RCU/rcu.txt +++ b/Documentation/RCU/rcu.txt @@ -45,7 +45,8 @@ o How can I see where RCU is currently used in the Linux kernel? Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu", "rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh", - "synchronize_rcu", and "synchronize_net". + "srcu_read_lock", "srcu_read_unlock", "synchronize_rcu", + "synchronize_net", and "synchronize_srcu". o What guidelines should I follow when writing code that uses RCU? diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 820fee236967..e0d6d99b8f9b 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -778,6 +778,8 @@ Markers for RCU read-side critical sections: rcu_read_unlock rcu_read_lock_bh rcu_read_unlock_bh + srcu_read_lock + srcu_read_unlock RCU pointer/list traversal: @@ -804,6 +806,7 @@ RCU grace period: synchronize_net synchronize_sched synchronize_rcu + synchronize_srcu call_rcu call_rcu_bh diff --git a/include/linux/srcu.h b/include/linux/srcu.h new file mode 100644 index 000000000000..947fdab2ddb0 --- /dev/null +++ b/include/linux/srcu.h @@ -0,0 +1,49 @@ +/* + * Sleepable Read-Copy Update mechanism for mutual exclusion + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) IBM Corporation, 2006 + * + * Author: Paul McKenney + * + * For detailed explanation of Read-Copy Update mechanism see - + * Documentation/RCU/ *.txt + * + */ + +struct srcu_struct_array { + int c[2]; +}; + +struct srcu_struct { + int completed; + struct srcu_struct_array *per_cpu_ref; + struct mutex mutex; +}; + +#ifndef CONFIG_PREEMPT +#define srcu_barrier() barrier() +#else /* #ifndef CONFIG_PREEMPT */ +#define srcu_barrier() +#endif /* #else #ifndef CONFIG_PREEMPT */ + +void init_srcu_struct(struct srcu_struct *sp); +void cleanup_srcu_struct(struct srcu_struct *sp); +int srcu_read_lock(struct srcu_struct *sp) __acquires(sp); +void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp); +void synchronize_srcu(struct srcu_struct *sp); +long srcu_batches_completed(struct srcu_struct *sp); +void cleanup_srcu_struct(struct srcu_struct *sp); diff --git a/kernel/Makefile b/kernel/Makefile index d948ca12acf0..5e3f3b75563a 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,7 +8,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o extable.o params.o posix-timers.o \ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ - hrtimer.o rwsem.o latency.o nsproxy.o + hrtimer.o rwsem.o latency.o nsproxy.o srcu.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += time/ diff --git a/kernel/srcu.c b/kernel/srcu.c new file mode 100644 index 000000000000..7e1979f624ba --- /dev/null +++ b/kernel/srcu.c @@ -0,0 +1,257 @@ +/* + * Sleepable Read-Copy Update mechanism for mutual exclusion. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) IBM Corporation, 2006 + * + * Author: Paul McKenney + * + * For detailed explanation of Read-Copy Update mechanism see - + * Documentation/RCU/ *.txt + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * init_srcu_struct - initialize a sleep-RCU structure + * @sp: structure to initialize. + * + * Must invoke this on a given srcu_struct before passing that srcu_struct + * to any other function. Each srcu_struct represents a separate domain + * of SRCU protection. + */ +void init_srcu_struct(struct srcu_struct *sp) +{ + sp->completed = 0; + sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array); + mutex_init(&sp->mutex); +} + +/* + * srcu_readers_active_idx -- returns approximate number of readers + * active on the specified rank of per-CPU counters. + */ + +static int srcu_readers_active_idx(struct srcu_struct *sp, int idx) +{ + int cpu; + int sum; + + sum = 0; + for_each_possible_cpu(cpu) + sum += per_cpu_ptr(sp->per_cpu_ref, cpu)->c[idx]; + return sum; +} + +/** + * srcu_readers_active - returns approximate number of readers. + * @sp: which srcu_struct to count active readers (holding srcu_read_lock). + * + * Note that this is not an atomic primitive, and can therefore suffer + * severe errors when invoked on an active srcu_struct. That said, it + * can be useful as an error check at cleanup time. + */ +int srcu_readers_active(struct srcu_struct *sp) +{ + return srcu_readers_active_idx(sp, 0) + srcu_readers_active_idx(sp, 1); +} + +/** + * cleanup_srcu_struct - deconstruct a sleep-RCU structure + * @sp: structure to clean up. + * + * Must invoke this after you are finished using a given srcu_struct that + * was initialized via init_srcu_struct(), else you leak memory. + */ +void cleanup_srcu_struct(struct srcu_struct *sp) +{ + int sum; + + sum = srcu_readers_active(sp); + WARN_ON(sum); /* Leakage unless caller handles error. */ + if (sum != 0) + return; + free_percpu(sp->per_cpu_ref); + sp->per_cpu_ref = NULL; +} + +/** + * srcu_read_lock - register a new reader for an SRCU-protected structure. + * @sp: srcu_struct in which to register the new reader. + * + * Counts the new reader in the appropriate per-CPU element of the + * srcu_struct. Must be called from process context. + * Returns an index that must be passed to the matching srcu_read_unlock(). + */ +int srcu_read_lock(struct srcu_struct *sp) +{ + int idx; + + preempt_disable(); + idx = sp->completed & 0x1; + barrier(); /* ensure compiler looks -once- at sp->completed. */ + per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]++; + srcu_barrier(); /* ensure compiler won't misorder critical section. */ + preempt_enable(); + return idx; +} + +/** + * srcu_read_unlock - unregister a old reader from an SRCU-protected structure. + * @sp: srcu_struct in which to unregister the old reader. + * @idx: return value from corresponding srcu_read_lock(). + * + * Removes the count for the old reader from the appropriate per-CPU + * element of the srcu_struct. Note that this may well be a different + * CPU than that which was incremented by the corresponding srcu_read_lock(). + * Must be called from process context. + */ +void srcu_read_unlock(struct srcu_struct *sp, int idx) +{ + preempt_disable(); + srcu_barrier(); /* ensure compiler won't misorder critical section. */ + per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]--; + preempt_enable(); +} + +/** + * synchronize_srcu - wait for prior SRCU read-side critical-section completion + * @sp: srcu_struct with which to synchronize. + * + * Flip the completed counter, and wait for the old count to drain to zero. + * As with classic RCU, the updater must use some separate means of + * synchronizing concurrent updates. Can block; must be called from + * process context. + * + * Note that it is illegal to call synchornize_srcu() from the corresponding + * SRCU read-side critical section; doing so will result in deadlock. + * However, it is perfectly legal to call synchronize_srcu() on one + * srcu_struct from some other srcu_struct's read-side critical section. + */ +void synchronize_srcu(struct srcu_struct *sp) +{ + int idx; + + idx = sp->completed; + mutex_lock(&sp->mutex); + + /* + * Check to see if someone else did the work for us while we were + * waiting to acquire the lock. We need -two- advances of + * the counter, not just one. If there was but one, we might have + * shown up -after- our helper's first synchronize_sched(), thus + * having failed to prevent CPU-reordering races with concurrent + * srcu_read_unlock()s on other CPUs (see comment below). So we + * either (1) wait for two or (2) supply the second ourselves. + */ + + if ((sp->completed - idx) >= 2) { + mutex_unlock(&sp->mutex); + return; + } + + synchronize_sched(); /* Force memory barrier on all CPUs. */ + + /* + * The preceding synchronize_sched() ensures that any CPU that + * sees the new value of sp->completed will also see any preceding + * changes to data structures made by this CPU. This prevents + * some other CPU from reordering the accesses in its SRCU + * read-side critical section to precede the corresponding + * srcu_read_lock() -- ensuring that such references will in + * fact be protected. + * + * So it is now safe to do the flip. + */ + + idx = sp->completed & 0x1; + sp->completed++; + + synchronize_sched(); /* Force memory barrier on all CPUs. */ + + /* + * At this point, because of the preceding synchronize_sched(), + * all srcu_read_lock() calls using the old counters have completed. + * Their corresponding critical sections might well be still + * executing, but the srcu_read_lock() primitives themselves + * will have finished executing. + */ + + while (srcu_readers_active_idx(sp, idx)) + schedule_timeout_interruptible(1); + + synchronize_sched(); /* Force memory barrier on all CPUs. */ + + /* + * The preceding synchronize_sched() forces all srcu_read_unlock() + * primitives that were executing concurrently with the preceding + * for_each_possible_cpu() loop to have completed by this point. + * More importantly, it also forces the corresponding SRCU read-side + * critical sections to have also completed, and the corresponding + * references to SRCU-protected data items to be dropped. + * + * Note: + * + * Despite what you might think at first glance, the + * preceding synchronize_sched() -must- be within the + * critical section ended by the following mutex_unlock(). + * Otherwise, a task taking the early exit can race + * with a srcu_read_unlock(), which might have executed + * just before the preceding srcu_readers_active() check, + * and whose CPU might have reordered the srcu_read_unlock() + * with the preceding critical section. In this case, there + * is nothing preventing the synchronize_sched() task that is + * taking the early exit from freeing a data structure that + * is still being referenced (out of order) by the task + * doing the srcu_read_unlock(). + * + * Alternatively, the comparison with "2" on the early exit + * could be changed to "3", but this increases synchronize_srcu() + * latency for bulk loads. So the current code is preferred. + */ + + mutex_unlock(&sp->mutex); +} + +/** + * srcu_batches_completed - return batches completed. + * @sp: srcu_struct on which to report batch completion. + * + * Report the number of batches, correlated with, but not necessarily + * precisely the same as, the number of grace periods that have elapsed. + */ + +long srcu_batches_completed(struct srcu_struct *sp) +{ + return sp->completed; +} + +EXPORT_SYMBOL_GPL(init_srcu_struct); +EXPORT_SYMBOL_GPL(cleanup_srcu_struct); +EXPORT_SYMBOL_GPL(srcu_read_lock); +EXPORT_SYMBOL_GPL(srcu_read_unlock); +EXPORT_SYMBOL_GPL(synchronize_srcu); +EXPORT_SYMBOL_GPL(srcu_batches_completed); +EXPORT_SYMBOL_GPL(srcu_readers_active); -- cgit v1.2.3 From eabc069401bcf45bcc3f19e643017bf761780aa8 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 4 Oct 2006 02:17:04 -0700 Subject: [PATCH] Add SRCU-based notifier chains This patch (as751) adds a new type of notifier chain, based on the SRCU (Sleepable Read-Copy Update) primitives recently added to the kernel. An SRCU notifier chain is much like a blocking notifier chain, in that it must be called in process context and its callout routines are allowed to sleep. The difference is that the chain's links are protected by the SRCU mechanism rather than by an rw-semaphore, so calling the chain has extremely low overhead: no memory barriers and no cache-line bouncing. On the other hand, unregistering from the chain is expensive and the chain head requires special runtime initialization (plus cleanup if it is to be deallocated). SRCU notifiers are appropriate for notifiers that will be called very frequently and for which unregistration occurs very seldom. The proposed "task notifier" scheme qualifies, as may some of the network notifiers. Signed-off-by: Alan Stern Acked-by: Paul E. McKenney Acked-by: Chandra Seetharaman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/notifier.h | 43 ++++++++++++++-- include/linux/srcu.h | 6 ++- kernel/sys.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 166 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/notifier.h b/include/linux/notifier.h index 7ff386a6ae87..10a43ed0527e 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h @@ -12,9 +12,10 @@ #include #include #include +#include /* - * Notifier chains are of three types: + * Notifier chains are of four types: * * Atomic notifier chains: Chain callbacks run in interrupt/atomic * context. Callouts are not allowed to block. @@ -23,13 +24,27 @@ * Raw notifier chains: There are no restrictions on callbacks, * registration, or unregistration. All locking and protection * must be provided by the caller. + * SRCU notifier chains: A variant of blocking notifier chains, with + * the same restrictions. * * atomic_notifier_chain_register() may be called from an atomic context, - * but blocking_notifier_chain_register() must be called from a process - * context. Ditto for the corresponding _unregister() routines. + * but blocking_notifier_chain_register() and srcu_notifier_chain_register() + * must be called from a process context. Ditto for the corresponding + * _unregister() routines. * - * atomic_notifier_chain_unregister() and blocking_notifier_chain_unregister() - * _must not_ be called from within the call chain. + * atomic_notifier_chain_unregister(), blocking_notifier_chain_unregister(), + * and srcu_notifier_chain_unregister() _must not_ be called from within + * the call chain. + * + * SRCU notifier chains are an alternative form of blocking notifier chains. + * They use SRCU (Sleepable Read-Copy Update) instead of rw-semaphores for + * protection of the chain links. This means there is _very_ low overhead + * in srcu_notifier_call_chain(): no cache bounces and no memory barriers. + * As compensation, srcu_notifier_chain_unregister() is rather expensive. + * SRCU notifier chains should be used when the chain will be called very + * often but notifier_blocks will seldom be removed. Also, SRCU notifier + * chains are slightly more difficult to use because they require special + * runtime initialization. */ struct notifier_block { @@ -52,6 +67,12 @@ struct raw_notifier_head { struct notifier_block *head; }; +struct srcu_notifier_head { + struct mutex mutex; + struct srcu_struct srcu; + struct notifier_block *head; +}; + #define ATOMIC_INIT_NOTIFIER_HEAD(name) do { \ spin_lock_init(&(name)->lock); \ (name)->head = NULL; \ @@ -64,6 +85,11 @@ struct raw_notifier_head { (name)->head = NULL; \ } while (0) +/* srcu_notifier_heads must be initialized and cleaned up dynamically */ +extern void srcu_init_notifier_head(struct srcu_notifier_head *nh); +#define srcu_cleanup_notifier_head(name) \ + cleanup_srcu_struct(&(name)->srcu); + #define ATOMIC_NOTIFIER_INIT(name) { \ .lock = __SPIN_LOCK_UNLOCKED(name.lock), \ .head = NULL } @@ -72,6 +98,7 @@ struct raw_notifier_head { .head = NULL } #define RAW_NOTIFIER_INIT(name) { \ .head = NULL } +/* srcu_notifier_heads cannot be initialized statically */ #define ATOMIC_NOTIFIER_HEAD(name) \ struct atomic_notifier_head name = \ @@ -91,6 +118,8 @@ extern int blocking_notifier_chain_register(struct blocking_notifier_head *, struct notifier_block *); extern int raw_notifier_chain_register(struct raw_notifier_head *, struct notifier_block *); +extern int srcu_notifier_chain_register(struct srcu_notifier_head *, + struct notifier_block *); extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *, struct notifier_block *); @@ -98,6 +127,8 @@ extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *, struct notifier_block *); extern int raw_notifier_chain_unregister(struct raw_notifier_head *, struct notifier_block *); +extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *, + struct notifier_block *); extern int atomic_notifier_call_chain(struct atomic_notifier_head *, unsigned long val, void *v); @@ -105,6 +136,8 @@ extern int blocking_notifier_call_chain(struct blocking_notifier_head *, unsigned long val, void *v); extern int raw_notifier_call_chain(struct raw_notifier_head *, unsigned long val, void *v); +extern int srcu_notifier_call_chain(struct srcu_notifier_head *, + unsigned long val, void *v); #define NOTIFY_DONE 0x0000 /* Don't care */ #define NOTIFY_OK 0x0001 /* Suits me */ diff --git a/include/linux/srcu.h b/include/linux/srcu.h index 947fdab2ddb0..8a45367b5f3a 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -24,6 +24,9 @@ * */ +#ifndef _LINUX_SRCU_H +#define _LINUX_SRCU_H + struct srcu_struct_array { int c[2]; }; @@ -46,4 +49,5 @@ int srcu_read_lock(struct srcu_struct *sp) __acquires(sp); void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp); void synchronize_srcu(struct srcu_struct *sp); long srcu_batches_completed(struct srcu_struct *sp); -void cleanup_srcu_struct(struct srcu_struct *sp); + +#endif diff --git a/kernel/sys.c b/kernel/sys.c index 2314867ae34f..fd5c71006775 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -153,7 +153,7 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl, /* * Atomic notifier chain routines. Registration and unregistration - * use a mutex, and call_chain is synchronized by RCU (no locks). + * use a spinlock, and call_chain is synchronized by RCU (no locks). */ /** @@ -401,6 +401,128 @@ int raw_notifier_call_chain(struct raw_notifier_head *nh, EXPORT_SYMBOL_GPL(raw_notifier_call_chain); +/* + * SRCU notifier chain routines. Registration and unregistration + * use a mutex, and call_chain is synchronized by SRCU (no locks). + */ + +/** + * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain + * @nh: Pointer to head of the SRCU notifier chain + * @n: New entry in notifier chain + * + * Adds a notifier to an SRCU notifier chain. + * Must be called in process context. + * + * Currently always returns zero. + */ + +int srcu_notifier_chain_register(struct srcu_notifier_head *nh, + struct notifier_block *n) +{ + int ret; + + /* + * This code gets used during boot-up, when task switching is + * not yet working and interrupts must remain disabled. At + * such times we must not call mutex_lock(). + */ + if (unlikely(system_state == SYSTEM_BOOTING)) + return notifier_chain_register(&nh->head, n); + + mutex_lock(&nh->mutex); + ret = notifier_chain_register(&nh->head, n); + mutex_unlock(&nh->mutex); + return ret; +} + +EXPORT_SYMBOL_GPL(srcu_notifier_chain_register); + +/** + * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain + * @nh: Pointer to head of the SRCU notifier chain + * @n: Entry to remove from notifier chain + * + * Removes a notifier from an SRCU notifier chain. + * Must be called from process context. + * + * Returns zero on success or %-ENOENT on failure. + */ +int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, + struct notifier_block *n) +{ + int ret; + + /* + * This code gets used during boot-up, when task switching is + * not yet working and interrupts must remain disabled. At + * such times we must not call mutex_lock(). + */ + if (unlikely(system_state == SYSTEM_BOOTING)) + return notifier_chain_unregister(&nh->head, n); + + mutex_lock(&nh->mutex); + ret = notifier_chain_unregister(&nh->head, n); + mutex_unlock(&nh->mutex); + synchronize_srcu(&nh->srcu); + return ret; +} + +EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister); + +/** + * srcu_notifier_call_chain - Call functions in an SRCU notifier chain + * @nh: Pointer to head of the SRCU notifier chain + * @val: Value passed unmodified to notifier function + * @v: Pointer passed unmodified to notifier function + * + * Calls each function in a notifier chain in turn. The functions + * run in a process context, so they are allowed to block. + * + * If the return value of the notifier can be and'ed + * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain + * will return immediately, with the return value of + * the notifier function which halted execution. + * Otherwise the return value is the return value + * of the last notifier function called. + */ + +int srcu_notifier_call_chain(struct srcu_notifier_head *nh, + unsigned long val, void *v) +{ + int ret; + int idx; + + idx = srcu_read_lock(&nh->srcu); + ret = notifier_call_chain(&nh->head, val, v); + srcu_read_unlock(&nh->srcu, idx); + return ret; +} + +EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); + +/** + * srcu_init_notifier_head - Initialize an SRCU notifier head + * @nh: Pointer to head of the srcu notifier chain + * + * Unlike other sorts of notifier heads, SRCU notifier heads require + * dynamic initialization. Be sure to call this routine before + * calling any of the other SRCU notifier routines for this head. + * + * If an SRCU notifier head is deallocated, it must first be cleaned + * up by calling srcu_cleanup_notifier_head(). Otherwise the head's + * per-cpu data (used by the SRCU mechanism) will leak. + */ + +void srcu_init_notifier_head(struct srcu_notifier_head *nh) +{ + mutex_init(&nh->mutex); + init_srcu_struct(&nh->srcu); + nh->head = NULL; +} + +EXPORT_SYMBOL_GPL(srcu_init_notifier_head); + /** * register_reboot_notifier - Register function to be called at reboot time * @nb: Info about notifier function to be called -- cgit v1.2.3 From e6a92013ba458804161c0c5b6d134d82204dc233 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 4 Oct 2006 02:17:05 -0700 Subject: [PATCH] SRCU: report out-of-memory errors Currently the init_srcu_struct() routine has no way to report out-of-memory errors. This patch (as761) makes it return -ENOMEM when the per-cpu data allocation fails. The patch also makes srcu_init_notifier_head() report a BUG if a notifier head can't be initialized. Perhaps it should return -ENOMEM instead, but in the most likely cases where this might occur I don't think any recovery is possible. Notifier chains generally are not created dynamically. [akpm@osdl.org: avoid statement-with-side-effect in macro] Signed-off-by: Alan Stern Acked-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/srcu.h | 2 +- kernel/srcu.c | 5 +++-- kernel/sys.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/srcu.h b/include/linux/srcu.h index 8a45367b5f3a..aca0eee53930 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -43,7 +43,7 @@ struct srcu_struct { #define srcu_barrier() #endif /* #else #ifndef CONFIG_PREEMPT */ -void init_srcu_struct(struct srcu_struct *sp); +int init_srcu_struct(struct srcu_struct *sp); void cleanup_srcu_struct(struct srcu_struct *sp); int srcu_read_lock(struct srcu_struct *sp) __acquires(sp); void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp); diff --git a/kernel/srcu.c b/kernel/srcu.c index 7e1979f624ba..3507cabe963b 100644 --- a/kernel/srcu.c +++ b/kernel/srcu.c @@ -42,11 +42,12 @@ * to any other function. Each srcu_struct represents a separate domain * of SRCU protection. */ -void init_srcu_struct(struct srcu_struct *sp) +int init_srcu_struct(struct srcu_struct *sp) { sp->completed = 0; - sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array); mutex_init(&sp->mutex); + sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array); + return (sp->per_cpu_ref ? 0 : -ENOMEM); } /* diff --git a/kernel/sys.c b/kernel/sys.c index fd5c71006775..98489d82801b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -517,7 +517,8 @@ EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); void srcu_init_notifier_head(struct srcu_notifier_head *nh) { mutex_init(&nh->mutex); - init_srcu_struct(&nh->srcu); + if (init_srcu_struct(&nh->srcu) < 0) + BUG(); nh->head = NULL; } -- cgit v1.2.3 From 20e9751bd9dd6b832fd84ada27840360f7e877f1 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 4 Oct 2006 02:17:17 -0700 Subject: [PATCH] rcu: simplify/improve batch tuning Kill a hard-to-calculate 'rsinterval' boot parameter and per-cpu rcu_data.last_rs_qlen. Instead, it adds adds a flag rcu_ctrlblk.signaled, which records the fact that one of CPUs has sent a resched IPI since the last rcu_start_batch(). Roughly speaking, we need two rcu_start_batch()s in order to move callbacks from ->nxtlist to ->donelist. This means that when ->qlen exceeds qhimark and continues to grow, we should send a resched IPI, and then do it again after we gone through a quiescent state. On the other hand, if it was already sent, we don't need to do it again when another CPU detects overflow of the queue. Signed-off-by: Oleg Nesterov Acked-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 4 ---- include/linux/rcupdate.h | 5 ++--- kernel/rcupdate.c | 11 +++-------- 3 files changed, 5 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 12b3b24bfd2f..e1543a32a557 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1357,10 +1357,6 @@ and is between 256 and 4096 characters. It is defined in the file rcu.qlowmark= [KNL,BOOT] Set threshold of queued RCU callbacks below which batch limiting is re-enabled. - rcu.rsinterval= [KNL,BOOT,SMP] Set the number of additional - RCU callbacks to queued before forcing reschedule - on all cpus. - rdinit= [KNL] Format: Run specified binary instead of /init from the ramdisk, diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index b4ca73d65891..f6dd71bf8a4b 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -66,6 +66,8 @@ struct rcu_ctrlblk { long completed; /* Number of the last completed batch */ int next_pending; /* Is the next batch already waiting? */ + int signaled; + spinlock_t lock ____cacheline_internodealigned_in_smp; cpumask_t cpumask; /* CPUs that need to switch in order */ /* for current batch to proceed. */ @@ -106,9 +108,6 @@ struct rcu_data { long blimit; /* Upper limit on a processed batch */ int cpu; struct rcu_head barrier; -#ifdef CONFIG_SMP - long last_rs_qlen; /* qlen during the last resched */ -#endif }; DECLARE_PER_CPU(struct rcu_data, rcu_data); diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 523e46483b99..26bb5ffe1ef1 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -71,9 +71,6 @@ static DEFINE_PER_CPU(struct tasklet_struct, rcu_tasklet) = {NULL}; static int blimit = 10; static int qhimark = 10000; static int qlowmark = 100; -#ifdef CONFIG_SMP -static int rsinterval = 1000; -#endif static atomic_t rcu_barrier_cpu_count; static DEFINE_MUTEX(rcu_barrier_mutex); @@ -86,8 +83,8 @@ static void force_quiescent_state(struct rcu_data *rdp, int cpu; cpumask_t cpumask; set_need_resched(); - if (unlikely(rdp->qlen - rdp->last_rs_qlen > rsinterval)) { - rdp->last_rs_qlen = rdp->qlen; + if (unlikely(!rcp->signaled)) { + rcp->signaled = 1; /* * Don't send IPI to itself. With irqs disabled, * rdp->cpu is the current cpu. @@ -301,6 +298,7 @@ static void rcu_start_batch(struct rcu_ctrlblk *rcp) smp_mb(); cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask); + rcp->signaled = 0; } } @@ -628,9 +626,6 @@ void synchronize_rcu(void) module_param(blimit, int, 0); module_param(qhimark, int, 0); module_param(qlowmark, int, 0); -#ifdef CONFIG_SMP -module_param(rsinterval, int, 0); -#endif EXPORT_SYMBOL_GPL(rcu_batches_completed); EXPORT_SYMBOL_GPL(rcu_batches_completed_bh); EXPORT_SYMBOL_GPL(call_rcu); -- cgit v1.2.3 From 595182bcdf64fbfd7ae22c67ea6081b7d387d246 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 4 Oct 2006 02:17:21 -0700 Subject: [PATCH] RCU: CREDITS and MAINTAINERS Add MAINTAINERS entry for Read-Copy Update (RCU), listing Dipankar Sarma as maintainer, and giving the URL for Paul McKenney's RCU site. Add MAINTAINERS entry for rcutorture, listing myself as maintainer. Add CREDITS entries for developers of RCU, RCU variants, and rcutorture. Use Paul McKenney's preferred email address in include/linux/rcupdate.h . Signed-off-by: Josh Triplett Cc: Paul McKenney Cc: Dipankar Sarma Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- CREDITS | 16 ++++++++++++++++ MAINTAINERS | 13 +++++++++++++ include/linux/rcupdate.h | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/CREDITS b/CREDITS index dba3e6334691..5d75254bcb81 100644 --- a/CREDITS +++ b/CREDITS @@ -2240,6 +2240,12 @@ D: tc: HFSC scheduler S: Freiburg S: Germany +N: Paul E. McKenney +E: paulmck@us.ibm.com +W: http://www.rdrop.com/users/paulmck/ +D: RCU and variants +D: rcutorture module + N: Mike McLagan E: mike.mclagan@linux.org W: http://www.invlogic.com/~mmclagan @@ -2981,6 +2987,10 @@ S: 69 rue Dunois S: 75013 Paris S: France +N: Dipankar Sarma +E: dipankar@in.ibm.com +D: RCU + N: Hannu Savolainen E: hannu@opensound.com D: Maintainer of the sound drivers until 2.1.x days. @@ -3293,6 +3303,12 @@ S: 3 Ballow Crescent S: MacGregor A.C.T 2615 S: Australia +N: Josh Triplett +E: josh@freedesktop.org +P: 1024D/D0FE7AFB B24A 65C9 1D71 2AC2 DE87 CA26 189B 9946 D0FE 7AFB +D: rcutorture maintainer +D: lock annotations, finding and fixing lock bugs + N: Winfried Trümper E: winni@xpilot.org W: http://www.shop.de/~winni/ diff --git a/MAINTAINERS b/MAINTAINERS index 129511c0c27e..fb10f71b8b64 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2441,6 +2441,19 @@ M: mporter@kernel.crashing.org L: linux-kernel@vger.kernel.org S: Maintained +READ-COPY UPDATE (RCU) +P: Dipankar Sarma +M: dipankar@in.ibm.com +W: http://www.rdrop.com/users/paulmck/rclock/ +L: linux-kernel@vger.kernel.org +S: Supported + +RCUTORTURE MODULE +P: Josh Triplett +M: josh@freedesktop.org +L: linux-kernel@vger.kernel.org +S: Maintained + REAL TIME CLOCK DRIVER P: Paul Gortmaker M: p_gortmaker@yahoo.com diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index f6dd71bf8a4b..c6b7485eac7c 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -19,7 +19,7 @@ * * Author: Dipankar Sarma * - * Based on the original work by Paul McKenney + * Based on the original work by Paul McKenney * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. * Papers: * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf -- cgit v1.2.3 From d56b9b9c464a10ab1ee51a4c6190a2b57b8ef7a6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 4 Oct 2006 02:17:22 -0700 Subject: [PATCH] The scheduled removal of some OSS drivers This patch contains the scheduled removal of OSS drivers that: - have ALSA drivers for the same hardware without known regressions and - whose Kconfig options have been removed in 2.6.17. [michal.k.k.piotrowski@gmail.com: build fix] Signed-off-by: Adrian Bunk Signed-off-by: Michal Piotrowski Cc: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/feature-removal-schedule.txt | 8 - Documentation/kernel-parameters.txt | 25 - Documentation/sound/oss/AWE32 | 76 - Documentation/sound/oss/CMI8338 | 85 - Documentation/sound/oss/INSTALL.awe | 134 - Documentation/sound/oss/MAD16 | 56 - Documentation/sound/oss/Maestro | 123 - Documentation/sound/oss/Maestro3 | 92 - Documentation/sound/oss/NEWS | 42 - Documentation/sound/oss/OPL3-SA | 52 - Documentation/sound/oss/README.awe | 218 - Documentation/sound/oss/Wavefront | 339 -- Documentation/sound/oss/es1370 | 70 - Documentation/sound/oss/rme96xx | 767 ---- Documentation/sound/oss/solo1 | 70 - Documentation/sound/oss/sonicvibes | 81 - MAINTAINERS | 11 - include/linux/Kbuild | 1 - include/linux/ac97_codec.h | 5 - include/linux/sound.h | 2 - include/linux/wavefront.h | 675 --- sound/oss/Makefile | 49 +- sound/oss/ac97.c | 20 - sound/oss/ac97.h | 3 - sound/oss/ac97_codec.c | 89 - sound/oss/ac97_plugin_ad1980.c | 126 - sound/oss/ad1848.c | 4 +- sound/oss/ad1848.h | 1 - sound/oss/ali5455.c | 3735 ----------------- sound/oss/au1000.c | 2216 ---------- sound/oss/audio_syms.c | 2 - sound/oss/awe_hw.h | 99 - sound/oss/awe_wave.c | 6149 ---------------------------- sound/oss/awe_wave.h | 77 - sound/oss/cmpci.c | 3381 --------------- sound/oss/cs4281/Makefile | 6 - sound/oss/cs4281/cs4281_hwdefs.h | 1234 ------ sound/oss/cs4281/cs4281_wrapper-24.c | 41 - sound/oss/cs4281/cs4281m.c | 4487 -------------------- sound/oss/cs4281/cs4281pm-24.c | 45 - sound/oss/cs4281/cs4281pm.h | 74 - sound/oss/dm.h | 79 - sound/oss/dmabuf.c | 30 - sound/oss/es1370.c | 2819 ------------- sound/oss/esssolo1.c | 2516 ------------ sound/oss/forte.c | 2139 ---------- sound/oss/gus.h | 24 - sound/oss/gus_card.c | 293 -- sound/oss/gus_hw.h | 50 - sound/oss/gus_linearvol.h | 18 - sound/oss/gus_midi.c | 256 -- sound/oss/gus_vol.c | 153 - sound/oss/gus_wave.c | 3464 ---------------- sound/oss/harmony.c | 1330 ------ sound/oss/ics2101.c | 247 -- sound/oss/iwmem.h | 36 - sound/oss/mad16.c | 1113 ----- sound/oss/maestro.c | 3686 ----------------- sound/oss/maestro.h | 60 - sound/oss/maestro3.c | 2969 -------------- sound/oss/maestro3.h | 821 ---- sound/oss/maui.c | 478 --- sound/oss/mpu401.c | 13 +- sound/oss/mpu401.h | 2 - sound/oss/opl3sa.c | 329 -- sound/oss/rme96xx.c | 1857 --------- sound/oss/rme96xx.h | 78 - sound/oss/sequencer.c | 1 - sound/oss/sequencer_syms.c | 7 - sound/oss/sgalaxy.c | 207 - sound/oss/sonicvibes.c | 2792 ------------- sound/oss/sound_calls.h | 2 - sound/oss/tuning.h | 10 +- sound/oss/wavfront.c | 3554 ---------------- sound/oss/wf_midi.c | 880 ---- sound/oss/ymfpci.c | 2692 ------------ sound/oss/ymfpci.h | 361 -- sound/oss/ymfpci_image.h | 1565 ------- sound/oss/yss225.c | 319 -- sound/oss/yss225.h | 24 - sound/sound_core.c | 34 - 81 files changed, 6 insertions(+), 62072 deletions(-) delete mode 100644 Documentation/sound/oss/AWE32 delete mode 100644 Documentation/sound/oss/CMI8338 delete mode 100644 Documentation/sound/oss/INSTALL.awe delete mode 100644 Documentation/sound/oss/MAD16 delete mode 100644 Documentation/sound/oss/Maestro delete mode 100644 Documentation/sound/oss/Maestro3 delete mode 100644 Documentation/sound/oss/NEWS delete mode 100644 Documentation/sound/oss/OPL3-SA delete mode 100644 Documentation/sound/oss/README.awe delete mode 100644 Documentation/sound/oss/Wavefront delete mode 100644 Documentation/sound/oss/es1370 delete mode 100644 Documentation/sound/oss/rme96xx delete mode 100644 Documentation/sound/oss/solo1 delete mode 100644 Documentation/sound/oss/sonicvibes delete mode 100644 include/linux/wavefront.h delete mode 100644 sound/oss/ac97_plugin_ad1980.c delete mode 100644 sound/oss/ali5455.c delete mode 100644 sound/oss/au1000.c delete mode 100644 sound/oss/awe_hw.h delete mode 100644 sound/oss/awe_wave.c delete mode 100644 sound/oss/awe_wave.h delete mode 100644 sound/oss/cmpci.c delete mode 100644 sound/oss/cs4281/Makefile delete mode 100644 sound/oss/cs4281/cs4281_hwdefs.h delete mode 100644 sound/oss/cs4281/cs4281_wrapper-24.c delete mode 100644 sound/oss/cs4281/cs4281m.c delete mode 100644 sound/oss/cs4281/cs4281pm-24.c delete mode 100644 sound/oss/cs4281/cs4281pm.h delete mode 100644 sound/oss/dm.h delete mode 100644 sound/oss/es1370.c delete mode 100644 sound/oss/esssolo1.c delete mode 100644 sound/oss/forte.c delete mode 100644 sound/oss/gus.h delete mode 100644 sound/oss/gus_card.c delete mode 100644 sound/oss/gus_hw.h delete mode 100644 sound/oss/gus_linearvol.h delete mode 100644 sound/oss/gus_midi.c delete mode 100644 sound/oss/gus_vol.c delete mode 100644 sound/oss/gus_wave.c delete mode 100644 sound/oss/harmony.c delete mode 100644 sound/oss/ics2101.c delete mode 100644 sound/oss/iwmem.h delete mode 100644 sound/oss/mad16.c delete mode 100644 sound/oss/maestro.c delete mode 100644 sound/oss/maestro.h delete mode 100644 sound/oss/maestro3.c delete mode 100644 sound/oss/maestro3.h delete mode 100644 sound/oss/maui.c delete mode 100644 sound/oss/opl3sa.c delete mode 100644 sound/oss/rme96xx.c delete mode 100644 sound/oss/rme96xx.h delete mode 100644 sound/oss/sgalaxy.c delete mode 100644 sound/oss/sonicvibes.c delete mode 100644 sound/oss/wavfront.c delete mode 100644 sound/oss/wf_midi.c delete mode 100644 sound/oss/ymfpci.c delete mode 100644 sound/oss/ymfpci.h delete mode 100644 sound/oss/ymfpci_image.h delete mode 100644 sound/oss/yss225.c delete mode 100644 sound/oss/yss225.h (limited to 'include/linux') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 42b95e0ad558..24f3c63b3017 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -29,14 +29,6 @@ Who: Adrian Bunk --------------------------- -What: drivers that were depending on OBSOLETE_OSS_DRIVER - (config options already removed) -When: before 2.6.19 -Why: OSS drivers with ALSA replacements -Who: Adrian Bunk - ---------------------------- - What: raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN When: November 2006 Why: Deprecated in favour of the new ioctl-based rawiso interface, which is diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index e1543a32a557..ff571f9298e0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -289,9 +289,6 @@ and is between 256 and 4096 characters. It is defined in the file autotest [IA64] - awe= [HW,OSS] AWE32/SB32/AWE64 wave table synth - Format: ,, - aztcd= [HW,CD] Aztech CD268 CDROM driver Format: ,0x79 (?) @@ -536,10 +533,6 @@ and is between 256 and 4096 characters. It is defined in the file Default value is 0. Value can be changed at runtime via /selinux/enforce. - es1370= [HW,OSS] - Format: [,] - See also header of sound/oss/es1370.c. - es1371= [HW,OSS] Format: ,[,[]] See also header of sound/oss/es1371.c. @@ -580,9 +573,6 @@ and is between 256 and 4096 characters. It is defined in the file gscd= [HW,CD] Format: - gus= [HW,OSS] - Format: ,,, - gvp11= [HW,SCSI] hashdist= [KNL,NUMA] Large hashes allocated during boot @@ -841,12 +831,6 @@ and is between 256 and 4096 characters. It is defined in the file (machvec) in a generic kernel. Example: machvec=hpzx1_swiotlb - mad16= [HW,OSS] Format: - ,,,,,, - - maui= [HW,OSS] - Format: , - max_loop= [LOOP] Maximum number of loopback devices that can be mounted Format: <1-256> @@ -1114,9 +1098,6 @@ and is between 256 and 4096 characters. It is defined in the file opl3= [HW,OSS] Format: - opl3sa= [HW,OSS] - Format: ,,,,, - opl3sa2= [HW,OSS] Format: ,,,,,,,[,,,,,, - shapers= [NET] Maximal number of shapers. @@ -1594,9 +1572,6 @@ and is between 256 and 4096 characters. It is defined in the file snd-ymfpci= [HW,ALSA] - sonicvibes= [HW,OSS] - Format: - sonycd535= [HW,CD] Format: [,] diff --git a/Documentation/sound/oss/AWE32 b/Documentation/sound/oss/AWE32 deleted file mode 100644 index b5908a66ff55..000000000000 --- a/Documentation/sound/oss/AWE32 +++ /dev/null @@ -1,76 +0,0 @@ - Installing and using Creative AWE midi sound under Linux. - -This documentation is devoted to the Creative Sound Blaster AWE32, AWE64 and -SB32. - -1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This - is important, because the driver works only with real Creative cards. - -2) The first thing you need to do is re-compile your kernel with support for - your sound card. Run your favourite tool to configure the kernel and when - you get to the "Sound" menu you should enable support for the following: - - Sound card support, - OSS sound modules, - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support, - AWE32 synth - - If your card is "Plug and Play" you will also need to enable these two - options, found under the "Plug and Play configuration" menu: - - Plug and Play support - ISA Plug and Play support - - Now compile and install the kernel in normal fashion. If you don't know - how to do this you can find instructions for this in the README file - located in the root directory of the kernel source. - -3) Before you can start playing midi files you will have to load a sound - bank file. The utility needed for doing this is called "sfxload", and it - is one of the utilities found in a package called "awesfx". If this - package is not available in your distribution you can download the AWE - snapshot from Creative Labs Open Source website: - - http://www.opensource.creative.com/snapshot.html - - Once you have unpacked the AWE snapshot you will see a "awesfx" - directory. Follow the instructions in awesfx/docs/INSTALL to install the - utilities in this package. After doing this, sfxload should be installed - as: - - /usr/local/bin/sfxload - - To enable AWE general midi synthesis you should also get the sound bank - file for general midi from: - - http://members.xoom.com/yar/synthgm.sbk.gz - - Copy it to a directory of your choice, and unpack it there. - -4) Edit /etc/modprobe.conf, and insert the following lines at the end of the - file: - - alias sound-slot-0 sb - alias sound-service-0-1 awe_wave - install awe_wave /sbin/modprobe --first-time -i awe_wave && /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE - - You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full - path of the sound bank file. That will enable the Sound Blaster and AWE - wave synthesis. To play midi files you should get one of these programs if - you don't already have them: - - Playmidi: http://playmidi.openprojects.net - - AWEMidi Player (drvmidi) Included in the previously mentioned AWE - snapshot. - - You will probably have to pass the "-e" switch to playmidi to have it use - your midi device. drvmidi should work without switches. - - If something goes wrong please e-mail me. All comments and suggestions are - welcome. - - Yaroslav Rosomakho (alons55@dialup.ptt.ru) - http://www.yar.opennet.ru - -Last Updated: Feb 3 2001 diff --git a/Documentation/sound/oss/CMI8338 b/Documentation/sound/oss/CMI8338 deleted file mode 100644 index 387d058c3f95..000000000000 --- a/Documentation/sound/oss/CMI8338 +++ /dev/null @@ -1,85 +0,0 @@ -Audio driver for CM8338/CM8738 chips by Chen-Li Tien - - -HARDWARE SUPPORTED -================================================================================ -C-Media CMI8338 -C-Media CMI8738 -On-board C-Media chips - - -STEPS TO BUILD DRIVER -================================================================================ - - 1. Backup the Config.in and Makefile in the sound driver directory - (/usr/src/linux/driver/sound). - The Configure.help provide help when you config driver in step - 4, please backup the original one (/usr/src/linux/Document) and - copy this file. - The cmpci is document for the driver in detail, please copy it - to /usr/src/linux/Document/sound so you can refer it. Backup if - there is already one. - - 2. Extract the tar file by 'tar xvzf cmpci-xx.tar.gz' in the above - directory. - - 3. Change directory to /usr/src/linux - - 4. Config cm8338 driver by 'make menuconfig', 'make config' or - 'make xconfig' command. - - 5. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI - driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested. - For driver option, please refer 'DRIVER PARAMETER' - - 6. Compile the kernel if necessary. - - 7. Compile the modules by 'make modules'. - - 8. Install the modules by 'make modules_install' - - -INSTALL DRIVER -================================================================================ - - 1. Before first time to run the driver, create module dependency by - 'depmod -a' - - 2. To install the driver manually, enter 'modprobe cmpci'. - - 3. Driver installation for various distributions: - - a. Slackware 4.0 - Add the 'modprobe cmpci' command in your /etc/rc.d/rc.modules - file.so you can start the driver automatically each time booting. - - b. Caldera OpenLinux 2.2 - Use LISA to load the cmpci module. - - c. RedHat 6.0 and S.u.S.E. 6.1 - Add following command in /etc/conf.modules: - - alias sound cmpci - - also visit http://www.cmedia.com.tw for installation instruction. - -DRIVER PARAMETER -================================================================================ - - Some functions for the cm8738 can be configured in Kernel Configuration - or modules parameters. Set these parameters to 1 to enable. - - mpuio: I/O ports base for MPU-401, 0 if disabled. - fmio: I/O ports base for OPL-3, 0 if disabled. - spdif_inverse:Inverse the S/PDIF-in signal, this depends on your - CD-ROM or DVD-ROM. - spdif_loop: Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out - directly. - speakers: Number of speakers used. - use_line_as_rear:Enable this if you want to use line-in as - rear-out. - use_line_as_bass:Enable this if you want to use line-in as - bass-out. - joystick: Enable joystick. You will need to install Linux joystick - driver. - diff --git a/Documentation/sound/oss/INSTALL.awe b/Documentation/sound/oss/INSTALL.awe deleted file mode 100644 index 310f42ca1e83..000000000000 --- a/Documentation/sound/oss/INSTALL.awe +++ /dev/null @@ -1,134 +0,0 @@ -================================================================ - INSTALLATION OF AWE32 SOUND DRIVER FOR LINUX - Takashi Iwai -================================================================ - ----------------------------------------------------------------- -* Attention to SB-PnP Card Users - -If you're using PnP cards, the initialization of PnP is required -before loading this driver. You have now three options: - 1. Use isapnptools. - 2. Use in-kernel isapnp support. - 3. Initialize PnP on DOS/Windows, then boot linux by loadlin. -In this document, only the case 1 case is treated. - ----------------------------------------------------------------- -* Installation on Red Hat 5.0 Sound Driver - -Please use install-rh.sh under RedHat5.0 directory. -DO NOT USE install.sh below. -See INSTALL.RH for more details. - ----------------------------------------------------------------- -* Installation/Update by Shell Script - - 1. Become root - - % su - - 2. If you have never configured the kernel tree yet, run make config - once (to make dependencies and symlinks). - - # cd /usr/src/linux - # make xconfig - - 3. Run install.sh script - - # sh ./install.sh - - 4. Configure your kernel - - (for Linux 2.[01].x user) - # cd /usr/src/linux - # make xconfig (or make menuconfig) - - (for Linux 1.2.x user) - # cd /usr/src/linux - # make config - - Answer YES to both "lowlevel drivers" and "AWE32 wave synth" items - in Sound menu. ("lowlevel drivers" will appear only in 2.x - kernel.) - - 5. Make your kernel (and modules), and install them as usual. - - 5a. make kernel image - # make zImage - - 5b. make modules and install them - # make modules && make modules_install - - 5c. If you're using lilo, copy the kernel image and run lilo. - Otherwise, copy the kernel image to suitable directory or - media for your system. - - 6. Reboot the kernel if necessary. - - If you updated only the modules, you don't have to reboot - the system. Just remove the old sound modules here. - in - # rmmod sound.o (linux-2.0 or OSS/Free) - # rmmod awe_wave.o (linux-2.1) - - 7. If your AWE card is a PnP and not initialized yet, you'll have to - do it by isapnp tools. Otherwise, skip to 8. - - This section described only a brief explanation. For more - details, please see the AWE64-Mini-HOWTO or isapnp tools FAQ. - - 7a. If you have no isapnp.conf file, generate it by pnpdump. - Otherwise, skip to 7d. - # pnpdump > /etc/isapnp.conf - - 7b. Edit isapnp.conf file. Comment out the appropriate - lines containing desirable I/O ports, DMA and IRQs. - Don't forget to enable (ACT Y) line. - - 7c. Add two i/o ports (0xA20 and 0xE20) in WaveTable part. - ex) - (CONFIGURE CTL0048/58128 (LD 2 - # ANSI string -->WaveTable<-- - (IO 0 (BASE 0x0620)) - (IO 1 (BASE 0x0A20)) - (IO 2 (BASE 0x0E20)) - (ACT Y) - )) - - 7d. Load the config file. - CAUTION: This will reset all PnP cards! - - # isapnp /etc/isapnp.conf - - 8. Load the sound module (if you configured it as a module): - - for 2.0 kernel or OSS/Free monolithic module: - - # modprobe sound.o - - for 2.1 kernel: - - # modprobe sound - # insmod uart401 - # insmod sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330 - (These values depend on your settings.) - # insmod awe_wave - (Be sure to load awe_wave after sb!) - - See Documentation/sound/oss/AWE32 for - more details. - - 9. (only for obsolete systems) If you don't have /dev/sequencer - device file, make it according to Readme.linux file on - /usr/src/linux/drivers/sound. (Run a shell script included in - that file). <-- This file no longer exists in the recent kernels! - - 10. OK, load your own soundfont file, and enjoy MIDI! - - % sfxload synthgm.sbk - % drvmidi foo.mid - - 11. For more advanced use (eg. dynamic loading, virtual bank and - etc.), please read the awedrv FAQ or the instructions in awesfx - and awemidi packages. - -Good luck! diff --git a/Documentation/sound/oss/MAD16 b/Documentation/sound/oss/MAD16 deleted file mode 100644 index 865dbd848742..000000000000 --- a/Documentation/sound/oss/MAD16 +++ /dev/null @@ -1,56 +0,0 @@ -(This recipe has been edited to update the configuration symbols, - and change over to modprobe.conf for 2.6) - -From: Shaw Carruthers - -I have been using mad16 sound for some time now with no problems, current -kernel 2.1.89 - -lsmod shows: - -mad16 5176 0 -sb 22044 0 [mad16] -uart401 5576 0 [mad16 sb] -ad1848 14176 1 [mad16] -sound 61928 0 [mad16 sb uart401 ad1848] - -.config has: - -CONFIG_SOUND=m -CONFIG_SOUND_ADLIB=m -CONFIG_SOUND_MAD16=m -CONFIG_SOUND_YM3812=m - -modprobe.conf has: - -alias char-major-14-* mad16 -options sb mad16=1 -options mad16 io=0x530 irq=7 dma=0 dma16=1 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0 - - -To get the built in mixer to work this needs to be: - -options adlib_card io=0x388 # FM synthesizer -options sb mad16=1 -options mad16 io=0x530 irq=7 dma=0 dma16=1 mpu_io=816 mpu_irq=5 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0 - -The addition of the "mpu_io=816 mpu_irq=5" to the mad16 options line is - ------------------------------------------------------------------------- -The mad16 module in addition supports the following options: - -option: meaning: default: -joystick=0,1 disabled, enabled disabled -cdtype=0x00,0x02,0x04, disabled, Sony CDU31A, disabled - 0x06,0x08,0x0a Mitsumi, Panasonic, - Secondary IDE, Primary IDE -cdport=0x340,0x320, 0x340 - 0x330,0x360 -cdirq=0,3,5,7,9,10,11 disabled, IRQ3, ... disabled -cddma=0,5,6,7 disabled, DMA5, ... DMA5 for Mitsumi or IDE -cddma=0,1,2,3 disabled, DMA1, ... DMA3 for Sony or Panasonic -opl4=0,1 OPL3, OPL4 OPL3 - -for more details see linux/drivers/sound/mad16.c - -Rui Sousa diff --git a/Documentation/sound/oss/Maestro b/Documentation/sound/oss/Maestro deleted file mode 100644 index 4a80eb3f8e00..000000000000 --- a/Documentation/sound/oss/Maestro +++ /dev/null @@ -1,123 +0,0 @@ - An OSS/Lite Driver for the ESS Maestro family of sound cards - - Zach Brown, December 1999 - -Driver Status and Availability ------------------------------- - -The most recent version of this driver will hopefully always be available at - http://www.zabbo.net/maestro/ - -I will try and maintain the most recent stable version of the driver -in both the stable and development kernel lines. - -ESS Maestro Chip Family ------------------------ - -There are 3 main variants of the ESS Maestro PCI sound chip. The first -is the Maestro 1. It was originally produced by Platform Tech as the -'AGOGO'. It can be recognized by Platform Tech's PCI ID 0x1285 with -0x0100 as the device ID. It was put on some sound boards and a few laptops. -ESS bought the design and cleaned it up as the Maestro 2. This starts -their marking with the ESS vendor ID 0x125D and the 'year' device IDs. -The Maestro 2 claims 0x1968 while the Maestro 2e has 0x1978. - -The various families of Maestro are mostly identical as far as this -driver is concerned. It doesn't touch the DSP parts that differ (though -it could for FM synthesis). - -Driver OSS Behavior --------------------- - -This OSS driver exports /dev/mixer and /dev/dsp to applications, which -mostly adhere to the OSS spec. This driver doesn't register itself -with /dev/sndstat, so don't expect information to appear there. - -The /dev/dsp device exported behaves almost as expected. Playback is -supported in all the various lovely formats. 8/16bit stereo/mono from -8khz to 48khz, and mmap()ing for playback behaves. Capture/recording -is limited due to oddities with the Maestro hardware. One can only -record in 16bit stereo. For recording the maestro uses non interleaved -stereo buffers so that mmap()ing the incoming data does not result in -a ring buffer of LRLR data. mmap()ing of the read buffers is therefore -disallowed until this can be cleaned up. - -/dev/mixer is an interface to the AC'97 codec on the Maestro. It is -worth noting that there are a variety of AC'97s that can be wired to -the Maestro. Which is used is entirely up to the hardware implementor. -This should only be visible to the user by the presence, or lack, of -'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them. - -The driver doesn't support MIDI or FM playback at the moment. Typically -the Maestro is wired to an MPU MIDI chip, but some hardware implementations -don't. We need to assemble a white list of hardware implementations that -have MIDI wired properly before we can claim to support it safely. - -Compiling and Installing ------------------------- - -With the drivers inclusion into the kernel, compiling and installing -is the same as most OSS/Lite modular sound drivers. Compilation -of the driver is enabled through the CONFIG_SOUND_MAESTRO variable -in the config system. - -It may be modular or statically linked. If it is modular it should be -installed with the rest of the modules for the kernel on the system. -Typically this will be in /lib/modules/ somewhere. 'alias sound maestro' -should also be added to your module configs (typically /etc/conf.modules) -if you're using modular OSS/Lite sound and want to default to using a -maestro chip. - -As this is a PCI device, the module does not need to be informed of -any IO or IRQ resources it should use, it devines these from the -system. Sometimes, on sucky PCs, the BIOS fails to allocated resources -for the maestro. This will result in a message like: - maestro: PCI subsystem reports IRQ 0, this might not be correct. -from the kernel. Should this happen the sound chip most likely will -not operate correctly. To solve this one has to dig through their BIOS -(typically entered by hitting a hot key at boot time) and figure out -what magic needs to happen so that the BIOS will reward the maestro with -an IRQ. This operation is incredibly system specific, so you're on your -own. Sometimes the magic lies in 'PNP Capable Operating System' settings. - -There are very few options to the driver. One is 'debug' which will -tell the driver to print minimal debugging information as it runs. This -can be collected with 'dmesg' or through the klogd daemon. - -The other, more interesting option, is 'dsps_order'. Typically at -install time the driver will only register one available /dev/dsp device -for its use. The 'dsps_order' module parameter allows for more devices -to be allocated, as a power of two. Up to 4 devices can be registered -( dsps_order=2 ). These devices act as fully distinct units and use -separate channels in the maestro. - -Power Management ----------------- - -As of version 0.14, this driver has a minimal understanding of PCI -Power Management. If it finds a valid power management capability -on the PCI device it will attempt to use the power management -functions of the maestro. It will only do this on Maestro 2Es and -only on machines that are known to function well. You can -force the use of power management by setting the 'use_pm' module -option to 1, or can disable it entirely by setting it to 0. - -When using power management, the driver does a few things -differently. It will keep the chip in a lower power mode -when the module is inserted but /dev/dsp is not open. This -allows the mixer to function but turns off the clocks -on other parts of the chip. When /dev/dsp is opened the chip -is brought into full power mode, and brought back down -when it is closed. It also powers down the chip entirely -when the module is removed or the machine is shutdown. This -can have nonobvious consequences. CD audio may not work -after a power managing driver is removed. Also, software that -doesn't understand power management may not be able to talk -to the powered down chip until the machine goes through a hard -reboot to bring it back. - -.. more details .. ------------------- - -drivers/sound/maestro.c contains comments that hopefully explain -the maestro implementation. diff --git a/Documentation/sound/oss/Maestro3 b/Documentation/sound/oss/Maestro3 deleted file mode 100644 index a113718e8034..000000000000 --- a/Documentation/sound/oss/Maestro3 +++ /dev/null @@ -1,92 +0,0 @@ - An OSS/Lite Driver for the ESS Maestro3 family of sound chips - - Zach Brown, January 2001 - -Driver Status and Availability ------------------------------- - -The most recent version of this driver will hopefully always be available at - http://www.zabbo.net/maestro3/ - -I will try and maintain the most recent stable version of the driver -in both the stable and development kernel lines. - -Historically I've sucked pretty hard at actually doing that, however. - -ESS Maestro3 Chip Family ------------------------ - -The 'Maestro3' is much like the Maestro2 chip. The noted improvement -is the removal of the silicon in the '2' that did PCM mixing. All that -work is now done through a custom DSP called the ASSP, the Asynchronus -Specific Signal Processor. - -The 'Allegro' is a baby version of the Maestro3. I'm not entirely clear -on the extent of the differences, but the driver supports them both :) - -The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998, -both under ESS's vendor ID of 0x125D. The Maestro3 can also show up as -0x199a when hardware strapping is used. - -The chip can also act as a multi function device. The modem IDs follow -the audio multimedia device IDs. (so the modem part of an Allegro shows -up as 0x1989) - -Driver OSS Behavior --------------------- - -This OSS driver exports /dev/mixer and /dev/dsp to applications, which -mostly adhere to the OSS spec. This driver doesn't register itself -with /dev/sndstat, so don't expect information to appear there. - -The /dev/dsp device exported behaves as expected. Playback is -supported in all the various lovely formats. 8/16bit stereo/mono from -8khz to 48khz, with both read()/write(), and mmap(). - -/dev/mixer is an interface to the AC'97 codec on the Maestro3. It is -worth noting that there are a variety of AC'97s that can be wired to -the Maestro3. Which is used is entirely up to the hardware implementor. -This should only be visible to the user by the presence, or lack, of -'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them. -The Allegro has an onchip AC'97. - -The driver doesn't support MIDI or FM playback at the moment. - -Compiling and Installing ------------------------- - -With the drivers inclusion into the kernel, compiling and installing -is the same as most OSS/Lite modular sound drivers. Compilation -of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable -in the config system. - -It may be modular or statically linked. If it is modular it should be -installed with the rest of the modules for the kernel on the system. -Typically this will be in /lib/modules/ somewhere. 'alias sound-slot-0 -maestro3' should also be added to your module configs (typically -/etc/modprobe.conf) if you're using modular OSS/Lite sound and want to -default to using a maestro3 chip. - -There are very few options to the driver. One is 'debug' which will -tell the driver to print minimal debugging information as it runs. This -can be collected with 'dmesg' or through the klogd daemon. - -One is 'external_amp', which tells the driver to attempt to enable -an external amplifier. This defaults to '1', you can tell the driver -not to bother enabling such an amplifier by setting it to '0'. - -And the last is 'gpio_pin', which tells the driver which GPIO pin number -the external amp uses (0-15), The Allegro uses 8 by default, all others 1. -If everything loads correctly and seems to be working but you get no sound, -try tweaking this value. - -Systems known to need a different value - Panasonic ToughBook CF-72: gpio_pin=13 - -Power Management ----------------- - -This driver has a minimal understanding of PCI Power Management. It will -try and power down the chip when the system is suspended, and power -it up with it is resumed. It will also try and power down the chip -when the machine is shut down. diff --git a/Documentation/sound/oss/NEWS b/Documentation/sound/oss/NEWS deleted file mode 100644 index a81e0ef72ae9..000000000000 --- a/Documentation/sound/oss/NEWS +++ /dev/null @@ -1,42 +0,0 @@ -Linux 2.4 Sound Changes -2000-September-25 -Christoph Hellwig, - - - -=== isapnp support - -The Linux 2.4 Kernel does have reliable in-kernel isapnp support. -Some drivers (sb.o, ad1816.o awe_wave.o) do now support automatically -detecting and configuring isapnp devices. -If you have a not yet supported isapnp soundcard, mail me the content -of '/proc/isapnp' on your system and some information about your card -and its driver(s) so I can try to get isapnp working for it. - - - -=== soundcard resources on kernel commandline - -Before Linux 2.4 you had to specify the resources for sounddrivers -statically linked into the kernel at compile time -(in make config/menuconfig/xconfig). In Linux 2.4 the resources are -now specified at the boot-time kernel commandline (e.g. the lilo -'append=' line or everything that's after the kernel name in grub). -Read the Configure.help entry for your card for the parameters. - - -=== softoss is gone - -In Linux 2.4 the softoss in-kernel software synthesizer is no more aviable. -Use a user space software synthesizer like timidity instead. - - - -=== /dev/sndstat and /proc/sound are gone - -In older Linux versions those files exported some information about the -OSS/Free configuration to userspace. In Linux 2.3 they were removed because -they did not support the growing number of pci soundcards and there were -some general problems with this interface. - - diff --git a/Documentation/sound/oss/OPL3-SA b/Documentation/sound/oss/OPL3-SA deleted file mode 100644 index 66a91835d918..000000000000 --- a/Documentation/sound/oss/OPL3-SA +++ /dev/null @@ -1,52 +0,0 @@ -OPL3-SA1 sound driver (opl3sa.o) - ---- -Note: This howto only describes how to setup the OPL3-SA1 chip; this info -does not apply to the SA2, SA3, or SA4. ---- - -The Yamaha OPL3-SA1 sound chip is usually found built into motherboards, and -it's a decent little chip offering a WSS mode, a SB Pro emulation mode, MPU401 -and OPL3 FM Synth capabilities. - -You can enable inclusion of the driver via CONFIG_SOUND_OPL3SA1=m, or -CONFIG_SOUND_OPL3SA1=y through 'make config/xconfig/menuconfig'. - -You'll need to know all of the relevant info (irq, dma, and io port) for the -chip's WSS mode, since that is the mode the kernel sound driver uses, and of -course you'll also need to know about where the MPU401 and OPL3 ports and -IRQs are if you want to use those. - -Here's the skinny on how to load it as a module: - - modprobe opl3sa io=0x530 irq=11 dma=0 dma2=1 mpu_io=0x330 mpu_irq=5 - -Module options in detail: - - io: This is the WSS's port base. - irq: This is the WSS's IRQ. - dma: This is the WSS's DMA line. In my BIOS setup screen this was - listed as "WSS Play DMA" - dma2: This is the WSS's secondary DMA line. My BIOS calls it the - "WSS capture DMA" - - mpu_io: This is the MPU401's port base. - mpu_irq: This is the MPU401's IRQ. - -If you'd like to use the OPL3 FM Synthesizer, make sure you enable -CONFIG_SOUND_YM3812 (in 'make config'). That'll build the opl3.o module. - -Then a simple 'insmod opl3 io=0x388', and you now have FM Synth. - -You can also use the SoftOSS software synthesizer instead of the builtin OPL3. -Here's how: - -Say 'y' or 'm' to "SoftOSS software wave table engine" in make config. - -If you said yes, the software synth is available once you boot your new -kernel. - -If you chose to build it as a module, just insmod the resulting softoss2.o - -Questions? Comments? - diff --git a/Documentation/sound/oss/README.awe b/Documentation/sound/oss/README.awe deleted file mode 100644 index 80054cd8fcde..000000000000 --- a/Documentation/sound/oss/README.awe +++ /dev/null @@ -1,218 +0,0 @@ -================================================================ - AWE32 Sound Driver for Linux / FreeBSD - version 0.4.3; Nov. 1, 1998 - - Takashi Iwai -================================================================ - -* GENERAL NOTES - -This is a sound driver extension for SoundBlaster AWE32 and other -compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable -the wave synth operations. The driver is provided for Linux 1.2.x -and 2.[012].x kernels, as well as FreeBSD, on Intel x86 and DEC -Alpha systems. - -This driver was written by Takashi Iwai , -and provided "as is". The original source (awedrv-0.4.3.tar.gz) and -binary packages are available on the following URL: - http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/ -Note that since the author is apart from this web site, the update is -not frequent now. - - -* NOTE TO LINUX USERS - -To enable this driver on linux-2.[01].x kernels, you need turn on -"AWE32 synth" options in sound menu when configure your linux kernel -and modules. The precise installation procedure is described in the -AWE64-Mini-HOWTO and linux-kernel/Documetation/sound/AWE32. - -If you're using PnP cards, the card must be initialized before loading -the sound driver. There're several options to do this: - - Initialize the card via ISA PnP tools, and load the sound module. - - Initialize the card on DOS, and load linux by loadlin.exe - - Use PnP kernel driver (for Linux-2.x.x) -The detailed instruction for the solution using isapnp tools is found -in many documents like above. A brief instruction is also included in -the installation document of this package. -For PnP driver project, please refer to the following URL: - http://www-jcr.lmh.ox.ac.uk/~pnp/ - - -* USING THE DRIVER - -The awedrv has several different playing modes to realize easy channel -allocation for MIDI songs. To hear the exact sound quality, you need -to obtain the extended sequencer program, drvmidi or playmidi-2.5. - -For playing MIDI files, you *MUST* load the soundfont file on the -driver previously by sfxload utility. Otherwise you'll here no sounds -at all! All the utilities and driver source packages are found in the -above URL. The sfxload program is included in the package -awesfx-0.4.3.tgz. Binary packages are available there, too. See the -instruction in each package for installation. - -Loading a soundfont file is very simple. Just execute the command - - % sfxload synthgm.sbk - -Then, sfxload transfers the file "synthgm.sbk" to the driver. -Both SF1 and SF2 formats are accepted. - -Now you can hear midi musics by a midi player. - - % drvmidi foo.mid - -If you run MIDI player after MOD player, you need to load soundfont -files again, since MOD player programs clear the previous loaded -samples by their own data. - -If you have only 512kb on the sound card, I recommend to use dynamic -sample loading via -L option of drvmidi. 2MB GM/GS soundfont file is -available in most midi files. - - % sfxload synthgm - % drvmidi -L 2mbgmgs foo.mid - -This makes a big difference (believe me)! For more details, please -refer to the FAQ list which is available on the URL above. - -The current chorus, reverb and equalizer status can be changed by -aweset utility program (included in awesfx package). Note that -some awedrv-native programs (like drvmidi and xmp) will change the -current settings by themselves. The aweset program is effective -only for other programs like playmidi. - -Enjoy. - - -* COMPILE FLAGS - -Compile conditions are defined in awe_config.h. - -[Compatibility Conditions] -The following flags are defined automatically when using installation -shell script. - -- AWE_MODULE_SUPPORT - indicates your Linux kernel supports module for each sound card - (in recent 2.1 or 2.2 kernels and unofficial patched 2.0 kernels - as distributed in the RH5.0 package). - This flag is automatically set when you're using 2.1.x kernels. - You can pass the base address and memory size via the following - module options, - io = base I/O port address (eg. 0x620) - memsize = DRAM size in kilobytes (eg. 512) - As default, AWE driver probes these values automatically. - - -[Hardware Conditions] -You DON'T have to define the following two values. -Define them only when the driver couldn't detect the card properly. - -- AWE_DEFAULT_BASE_ADDR (default: not defined) - specifies the base port address of your AWE32 card. - 0 means to autodetect the address. - -- AWE_DEFAULT_MEM_SIZE (default: not defined) - specifies the memory size of your AWE32 card in kilobytes. - -1 means to autodetect its size. - - -[Sample Table Size] -From ver.0.4.0, sample tables are allocated dynamically (except -Linux-1.2.x system), so you need NOT to touch these parameters. -Linux-1.2.x users may need to increase these values to appropriate size -if the sound card is equipped with more DRAM. - -- AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS - - -[Other Conditions] - -- AWE_ALWAYS_INIT_FM (default: not defined) - indicates the AWE driver always initialize FM passthrough even - without DRAM on board. Emu8000 chip has a restriction for playing - samples on DRAM that at least two channels must be occupied as - passthrough channels. - -- AWE_DEBUG_ON (default: defined) - turns on debugging messages if defined. - -- AWE_HAS_GUS_COMPATIBILITY (default: defined) - Enables GUS compatibility mode if defined, reading GUS patches and - GUS control commands. Define this option to use GMOD or other - GUS module players. - -- CONFIG_AWE32_MIDIEMU (default: defined) - Adds a MIDI emulation device by Emu8000 wavetable. The emulation - device can be accessed as an external MIDI, and sends the MIDI - control codes directly. XG and GS sysex/NRPN are accepted. - No MIDI input is supported. - -- CONFIG_AWE32_MIXER (default: not defined) - Adds a mixer device for AWE32 bass/treble equalizer control. - You can access this device using /dev/mixer?? (usually mixer01). - -- AWE_USE_NEW_VOLUME_CALC (default: defined) - Use the new method to calculate the volume change as compatible - with DOS/Win drivers. This option can be toggled via aweset - program, or drvmidi player. - -- AWE_CHECK_VTARGET (default: defined) - Check the current volume target value when searching for an - empty channel to allocate a new voice. This is experimentally - implemented in this version. (probably, this option doesn't - affect the sound quality severely...) - -- AWE_ALLOW_SAMPLE_SHARING (default: defined) - Allow sample sharing for differently loaded patches. - This function is available only together with awesfx-0.4.3p3. - Note that this is still an experimental option. - -- DEF_FM_CHORUS_DEPTH (default: 0x10) - The default strength to be sent to the chorus effect engine. - From 0 to 0xff. Larger numbers may often cause weird sounds. - -- DEF_FM_REVERB_DEPTH (default: 0x10) - The default strength to be sent to the reverb effect engine. - From 0 to 0xff. Larger numbers may often cause weird sounds. - - -* ACKNOWLEDGMENTS - -Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for much advice -on programming of AWE32. Much code is brought from his AWE32-native -MOD player, ALMP. -The port of awedrv to FreeBSD is done by Randall Hopper -(rhh@ct.picker.com). -The new volume calculation routine was derived from Mark Weaver's -ADIP compatible routines. -I also thank linux-awe-ml members for their efforts -to reboot their system many times :-) - - -* TODO'S - -- Complete DOS/Win compatibility -- DSP-like output - - -* COPYRIGHT - -Copyright (C) 1996-1998 Takashi Iwai - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/Documentation/sound/oss/Wavefront b/Documentation/sound/oss/Wavefront deleted file mode 100644 index 16f57ea43052..000000000000 --- a/Documentation/sound/oss/Wavefront +++ /dev/null @@ -1,339 +0,0 @@ - An OSS/Free Driver for WaveFront soundcards - (Turtle Beach Maui, Tropez, Tropez Plus) - - Paul Barton-Davis, July 1998 - - VERSION 0.2.5 - -Driver Status -------------- - -Requires: Kernel 2.1.106 or later (the driver is included with kernels -2.1.109 and above) - -As of 7/22/1998, this driver is currently in *BETA* state. This means -that it compiles and runs, and that I use it on my system (Linux -2.1.106) with some reasonably demanding applications and uses. I -believe the code is approaching an initial "finished" state that -provides bug-free support for the Tropez Plus. - -Please note that to date, the driver has ONLY been tested on a Tropez -Plus. I would very much like to hear (and help out) people with Tropez -and Maui cards, since I think the driver can support those cards as -well. - -Finally, the driver has not been tested (or even compiled) as a static -(non-modular) part of the kernel. Alan Cox's good work in modularizing -OSS/Free for Linux makes this rather unnecessary. - -Some Questions --------------- - -********************************************************************** -0) What does this driver do that the maui driver did not ? -********************************************************************** - -* can fully initialize a WaveFront card from cold boot - no DOS - utilities needed -* working patch/sample/program loading and unloading (the maui - driver didn't document how to make this work, and assumed - user-level preparation of the patch data for writing - to the board. ick.) -* full user-level access to all WaveFront commands -* for the Tropez Plus, (primitive) control of the YSS225 FX processor -* Virtual MIDI mode supported - 2 MIDI devices accessible via the - WaveFront's MPU401/UART emulation. One - accesses the WaveFront synth, the other accesses the - external MIDI connector. Full MIDI read/write semantics - for both devices. -* OSS-compliant /dev/sequencer interface for the WaveFront synth, - including native and GUS-format patch downloading. -* semi-intelligent patch management (prototypical at this point) - -********************************************************************** -1) What to do about MIDI interfaces ? -********************************************************************** - -The Tropez Plus (and perhaps other WF cards) can in theory support up -to 2 physical MIDI interfaces. One of these is connected to the -ICS2115 chip (the WaveFront synth itself) and is controlled by -MPU/UART-401 emulation code running as part of the WaveFront OS. The -other is controlled by the CS4232 chip present on the board. However, -physical access to the CS4232 connector is difficult, and it is -unlikely (though not impossible) that you will want to use it. - -An older version of this driver introduced an additional kernel config -variable which controlled whether or not the CS4232 MIDI interface was -configured. Because of Alan Cox's work on modularizing the sound -drivers, and now backporting them to 2.0.34 kernels, there seems to be -little reason to support "static" configuration variables, and so this -has been abandoned in favor of *only* module parameters. Specifying -"mpuio" and "mpuirq" for the cs4232 parameter will result in the -CS4232 MIDI interface being configured; leaving them unspecified will -leave it unconfigured (and thus unusable). - -BTW, I have heard from one Tropez+ user that the CS4232 interface is -more reliable than the ICS2115 one. I have had no problems with the -latter, and I don't have the right cable to test the former one -out. Reports welcome. - -********************************************************************** -2) Why does line XXX of the code look like this .... ? -********************************************************************** - -Either because it's not finished yet, or because you're a better coder -than I am, or because you don't understand some aspect of how the card -or the code works. - -I absolutely welcome comments, criticisms and suggestions about the -design and implementation of the driver. - -********************************************************************** -3) What files are included ? -********************************************************************** - - drivers/sound/README.wavefront -- this file - - drivers/sound/wavefront.patch -- patches for the 2.1.106 sound drivers - needed to make the rest of this work - DO NOT USE IF YOU'VE APPLIED THEM - BEFORE, OR HAVE 2.1.109 OR ABOVE - - drivers/sound/wavfront.c -- the driver - drivers/sound/ys225.h -- data declarations for FX config - drivers/sound/ys225.c -- data definitions for FX config - drivers/sound/wf_midi.c -- the "uart401" driver - to support virtual MIDI mode. - include/wavefront.h -- the header file - Documentation/sound/oss/Tropez+ -- short docs on configuration - -********************************************************************** -4) How do I compile/install/use it ? -********************************************************************** - -PART ONE: install the source code into your sound driver directory - - cd - tar -zxvf - -PART TWO: apply the patches - - DO THIS ONLY IF YOU HAVE A KERNEL VERSION BELOW 2.1.109 - AND HAVE NOT ALREADY INSTALLED THE PATCH(ES). - - cd drivers/sound - patch < wavefront.patch - -PART THREE: configure your kernel - - cd - make xconfig (or whichever config option you use) - - - choose YES for Sound Support - - choose MODULE (M) for OSS Sound Modules - - choose MODULE(M) to YM3812/OPL3 support - - choose MODULE(M) for WaveFront support - - choose MODULE(M) for CS4232 support - - - choose "N" for everything else (unless you have other - soundcards you want support for) - - - make boot - . - . - . - - make modules - . - . - . - make modules_install - -Here's my autoconf.h SOUND section: - -/* - * Sound - */ -#define CONFIG_SOUND 1 -#undef CONFIG_SOUND_OSS -#define CONFIG_SOUND_OSS_MODULE 1 -#undef CONFIG_SOUND_PAS -#undef CONFIG_SOUND_SB -#undef CONFIG_SOUND_ADLIB -#undef CONFIG_SOUND_GUS -#undef CONFIG_SOUND_MPU401 -#undef CONFIG_SOUND_PSS -#undef CONFIG_SOUND_MSS -#undef CONFIG_SOUND_SSCAPE -#undef CONFIG_SOUND_TRIX -#undef CONFIG_SOUND_MAD16 -#undef CONFIG_SOUND_WAVEFRONT -#define CONFIG_SOUND_WAVEFRONT_MODULE 1 -#undef CONFIG_SOUND_CS4232 -#define CONFIG_SOUND_CS4232_MODULE 1 -#undef CONFIG_SOUND_MAUI -#undef CONFIG_SOUND_SGALAXY -#undef CONFIG_SOUND_OPL3SA1 -#undef CONFIG_SOUND_SOFTOSS -#undef CONFIG_SOUND_YM3812 -#define CONFIG_SOUND_YM3812_MODULE 1 -#undef CONFIG_SOUND_VMIDI -#undef CONFIG_SOUND_UART6850 -/* - * Additional low level sound drivers - */ -#undef CONFIG_LOWLEVEL_SOUND - -************************************************************ -6) How do I configure my card ? -************************************************************ - -You need to edit /etc/modprobe.conf. Here's mine (edited to show the -relevant details): - - # Sound system - alias char-major-14-* wavefront - alias synth0 wavefront - alias mixer0 cs4232 - alias audio0 cs4232 - install wavefront /sbin/modprobe cs4232 && /sbin/modprobe -i wavefront && /sbin/modprobe opl3 - options wavefront io=0x200 irq=9 - options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0 - options opl3 io=0x388 - -Things to note: - - the wavefront options "io" and "irq" ***MUST*** match the "synthio" - and "synthirq" cs4232 options. - - you can do without the opl3 module if you don't - want to use the OPL/[34] FM synth on the soundcard - - the opl3 io parameter is conventionally not adjustable. - In theory, any not-in-use IO port address would work, but - just use 0x388 and stick with the crowd. - -********************************************************************** -7) What about firmware ? -********************************************************************** - -Turtle Beach have not given me permission to distribute their firmware -for the ICS2115. However, if you have a WaveFront card, then you -almost certainly have the firmware, and if not, its freely available -on their website, at: - - http://www.tbeach.com/tbs/downloads/scardsdown.htm#tropezplus - -The file is called WFOS2001.MOT (for the Tropez+). - -This driver, however, doesn't use the pure firmware as distributed, -but instead relies on a somewhat processed form of it. You can -generate this very easily. Following an idea from Andrew Veliath's -Pinnacle driver, the following flex program will generate the -processed version: - ----- cut here ------------------------- -%option main -%% -^S[28].*\r$ printf ("%c%.*s", yyleng-1,yyleng-1,yytext); -<> { fputc ('\0', stdout); return; } -\n {} -. {} ----- cut here ------------------------- - -To use it, put the above in file (say, ws.l) compile it like this: - - shell> flex -ows.c ws.l - shell> cc -o ws ws.c - -and then use it like this: - - ws < my-copy-of-the-oswf.mot-file > /etc/sound/wavefront.os - -If you put it somewhere else, you'll always have to use the wf_ospath -module parameter (see below) or alter the source code. - -********************************************************************** -7) How do I get it working ? -********************************************************************** - -Optionally, you can reboot with the "new" kernel (even though the only -changes have really been made to a module). - -Then, as root do: - - modprobe wavefront - -You should get something like this in /var/log/messages: - - WaveFront: firmware 1.20 already loaded. - -or - - WaveFront: no response to firmware probe, assume raw. - -then: - - WaveFront: waiting for memory configuration ... - WaveFront: hardware version 1.64 - WaveFront: available DRAM 8191k - WaveFront: 332 samples used (266 real, 13 aliases, 53 multi), 180 empty - WaveFront: 128 programs slots in use - WaveFront: 256 patch slots filled, 142 in use - -The whole process takes about 16 seconds, the longest waits being -after reporting the hardware version (during the firmware download), -and after reporting program status (during patch status inquiry). Its -shorter (about 10 secs) if the firmware is already loaded (i.e. only -warm reboots since the last firmware load). - -The "available DRAM" line will vary depending on how much added RAM -your card has. Mine has 8MB. - -To check basically functionality, use play(1) or splay(1) to send a -.WAV or other audio file through the audio portion. Then use playmidi -to play a General MIDI file. Try the "-D 0" to hear the -difference between sending MIDI to the WaveFront and using the OPL/3, -which is the default (I think ...). If you have an external synth(s) -hooked to the soundcard, you can use "-e" to route to the -external synth(s) (in theory, -D 1 should work as well, but I think -there is a bug in playmidi which prevents this from doing what it -should). - -********************************************************************** -8) What are the module parameters ? -********************************************************************** - -Its best to read wavefront.c for this, but here is a summary: - -integers: - wf_raw - if set, ignore apparent presence of firmware - loaded onto the ICS2115, reset the whole - board, and initialize it from scratch. (default = 0) - - fx_raw - if set, always initialize the YSS225 processor - on the Tropez plus. (default = 1) - - < The next 4 are basically for kernel hackers to allow - tweaking the driver for testing purposes. > - - wait_usecs - loop timer used when waiting for - status conditions on the board. - The default is 150. - - debug_default - debugging flags. See sound/wavefront.h - for WF_DEBUG_* values. Default is zero. - Setting this allows you to debug the - driver during module installation. -strings: - ospath - path to get to the pre-processed OS firmware. - (default: /etc/sound/wavefront.os) - -********************************************************************** -9) Who should I contact if I have problems? -********************************************************************** - -Just me: Paul Barton-Davis - - diff --git a/Documentation/sound/oss/es1370 b/Documentation/sound/oss/es1370 deleted file mode 100644 index 7b38b1a096a3..000000000000 --- a/Documentation/sound/oss/es1370 +++ /dev/null @@ -1,70 +0,0 @@ -/proc/sound, /dev/sndstat -------------------------- - -/proc/sound and /dev/sndstat is not supported by the -driver. To find out whether the driver succeeded loading, -check the kernel log (dmesg). - - -ALaw/uLaw sample formats ------------------------- - -This driver does not support the ALaw/uLaw sample formats. -ALaw is the default mode when opening a sound device -using OSS/Free. The reason for the lack of support is -that the hardware does not support these formats, and adding -conversion routines to the kernel would lead to very ugly -code in the presence of the mmap interface to the driver. -And since xquake uses mmap, mmap is considered important :-) -and no sane application uses ALaw/uLaw these days anyway. -In short, playing a Sun .au file as follows: - -cat my_file.au > /dev/dsp - -does not work. Instead, you may use the play script from -Chris Bagwell's sox-12.14 package (available from the URL -below) to play many different audio file formats. -The script automatically determines the audio format -and does do audio conversions if necessary. -http://home.sprynet.com/sprynet/cbagwell/projects.html - - -Blocking vs. nonblocking IO ---------------------------- - -Unlike OSS/Free this driver honours the O_NONBLOCK file flag -not only during open, but also during read and write. -This is an effort to make the sound driver interface more -regular. Timidity has problems with this; a patch -is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html. -(Timidity patched will also run on OSS/Free). - - -MIDI UART ---------- - -The driver supports a simple MIDI UART interface, with -no ioctl's supported. - - -MIDI synthesizer ----------------- - -This soundcard does not have any hardware MIDI synthesizer; -MIDI synthesis has to be done in software. To allow this -the driver/soundcard supports two PCM (/dev/dsp) interfaces. -The second one goes to the mixer "synth" setting and supports -only a limited set of sampling rates (44100, 22050, 11025, 5512). -By setting lineout to 1 on the driver command line -(eg. insmod es1370 lineout=1) it is even possible on some -cards to convert the LINEIN jack into a second LINEOUT jack, thus -making it possible to output four independent audio channels! - -There is a freely available software package that allows -MIDI file playback on this soundcard called Timidity. -See http://www.cgs.fi/~tt/timidity/. - - - -Thomas Sailer -t.sailer@alumni.ethz.ch diff --git a/Documentation/sound/oss/rme96xx b/Documentation/sound/oss/rme96xx deleted file mode 100644 index 87d7b7b65fa1..000000000000 --- a/Documentation/sound/oss/rme96xx +++ /dev/null @@ -1,767 +0,0 @@ -Beta release of the rme96xx (driver for RME 96XX cards like the -"Hammerfall" and the "Hammerfall light") - -Important: The driver module has to be installed on a freshly rebooted system, -otherwise the driver might not be able to acquire its buffers. - -features: - - - OSS programming interface (i.e. runs with standard OSS soundsoftware) - - OSS/Multichannel interface (OSS multichannel is done by just aquiring - more than 2 channels). The driver does not use more than one device - ( yet .. this feature may be implemented later ) - - more than one RME card supported - -The driver uses a specific multichannel interface, which I will document -when the driver gets stable. (take a look at the defines in rme96xx.h, -which adds blocked multichannel formats i.e instead of -lrlrlrlr --> llllrrrr etc. - -Use the "rmectrl" programm to look at the status of the card .. -or use xrmectrl, a GUI interface for the ctrl program. - -What you can do with the rmectrl program is to set the stereo device for -OSS emulation (e.g. if you use SPDIF out). - -You do: - -./ctrl offset 24 24 - -which makes the stereo device use channels 25 and 26. - -Guenter Geiger - -copy the first part of the attached source code into rmectrl.c -and the second part into xrmectrl (or get the program from -http://gige.xdv.org/pages/soft/pages/rme) - -to compile: gcc -o rmectrl rmectrl.c ------------------------------- snip ------------------------------------ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rme96xx.h" - -/* - remctrl.c - (C) 2000 Guenter Geiger - HP20020201 - Heiko Purnhagen -*/ - -/* # define DEVICE_NAME "/dev/mixer" */ -# define DEVICE_NAME "/dev/mixer1" - - -void usage(void) -{ - fprintf(stderr,"usage: rmectrl [/dev/mixer] [command [options]]\n\n"); - fprintf(stderr,"where command is one of:\n"); - fprintf(stderr," help show this help\n"); - fprintf(stderr," status show status bits\n"); - fprintf(stderr," control show control bits\n"); - fprintf(stderr," mix show mixer/offset status\n"); - fprintf(stderr," master set sync master\n"); - fprintf(stderr," pro set spdif out pro\n"); - fprintf(stderr," emphasis set spdif out emphasis\n"); - fprintf(stderr," dolby set spdif out no audio\n"); - fprintf(stderr," optout set spdif out optical\n"); - fprintf(stderr," wordclock set sync wordclock\n"); - fprintf(stderr," spdifin set spdif in (0=optical,1=coax,2=intern)\n"); - fprintf(stderr," syncref set sync source (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n"); - fprintf(stderr," adat1cd set ADAT1 on internal CD\n"); - fprintf(stderr," offset set dev (0..3) offset (0..25)\n"); - exit(-1); -} - - -int main(int argc, char* argv[]) -{ - int cards; - int ret; - int i; - double ft; - int fd, fdwr; - int param,orig; - rme_status_t stat; - rme_ctrl_t ctrl; - char *device; - int argidx; - - if (argc < 2) - usage(); - - if (*argv[1]=='/') { - device = argv[1]; - argidx = 2; - } - else { - device = DEVICE_NAME; - argidx = 1; - } - - fprintf(stdout,"mixer device %s\n",device); - if ((fd = open(device,O_RDONLY)) < 0) { - fprintf(stdout,"opening device failed\n"); - exit(-1); - } - - if ((fdwr = open(device,O_WRONLY)) < 0) { - fprintf(stdout,"opening device failed\n"); - exit(-1); - } - - if (argc < argidx+1) - usage(); - - if (!strcmp(argv[argidx],"help")) - usage(); - if (!strcmp(argv[argidx],"-h")) - usage(); - if (!strcmp(argv[argidx],"--help")) - usage(); - - if (!strcmp(argv[argidx],"status")) { - ioctl(fd,SOUND_MIXER_PRIVATE2,&stat); - fprintf(stdout,"stat.irq %d\n",stat.irq); - fprintf(stdout,"stat.lockmask %d\n",stat.lockmask); - fprintf(stdout,"stat.sr48 %d\n",stat.sr48); - fprintf(stdout,"stat.wclock %d\n",stat.wclock); - fprintf(stdout,"stat.bufpoint %d\n",stat.bufpoint); - fprintf(stdout,"stat.syncmask %d\n",stat.syncmask); - fprintf(stdout,"stat.doublespeed %d\n",stat.doublespeed); - fprintf(stdout,"stat.tc_busy %d\n",stat.tc_busy); - fprintf(stdout,"stat.tc_out %d\n",stat.tc_out); - fprintf(stdout,"stat.crystalrate %d (0=64k 3=96k 4=88.2k 5=48k 6=44.1k 7=32k)\n",stat.crystalrate); - fprintf(stdout,"stat.spdif_error %d\n",stat.spdif_error); - fprintf(stdout,"stat.bufid %d\n",stat.bufid); - fprintf(stdout,"stat.tc_valid %d\n",stat.tc_valid); - exit (0); - } - - if (!strcmp(argv[argidx],"control")) { - ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); - fprintf(stdout,"ctrl.start %d\n",ctrl.start); - fprintf(stdout,"ctrl.latency %d (0=64 .. 7=8192)\n",ctrl.latency); - fprintf(stdout,"ctrl.master %d\n",ctrl.master); - fprintf(stdout,"ctrl.ie %d\n",ctrl.ie); - fprintf(stdout,"ctrl.sr48 %d\n",ctrl.sr48); - fprintf(stdout,"ctrl.spare %d\n",ctrl.spare); - fprintf(stdout,"ctrl.doublespeed %d\n",ctrl.doublespeed); - fprintf(stdout,"ctrl.pro %d\n",ctrl.pro); - fprintf(stdout,"ctrl.emphasis %d\n",ctrl.emphasis); - fprintf(stdout,"ctrl.dolby %d\n",ctrl.dolby); - fprintf(stdout,"ctrl.opt_out %d\n",ctrl.opt_out); - fprintf(stdout,"ctrl.wordclock %d\n",ctrl.wordclock); - fprintf(stdout,"ctrl.spdif_in %d (0=optical,1=coax,2=intern)\n",ctrl.spdif_in); - fprintf(stdout,"ctrl.sync_ref %d (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n",ctrl.sync_ref); - fprintf(stdout,"ctrl.spdif_reset %d\n",ctrl.spdif_reset); - fprintf(stdout,"ctrl.spdif_select %d\n",ctrl.spdif_select); - fprintf(stdout,"ctrl.spdif_clock %d\n",ctrl.spdif_clock); - fprintf(stdout,"ctrl.spdif_write %d\n",ctrl.spdif_write); - fprintf(stdout,"ctrl.adat1_cd %d\n",ctrl.adat1_cd); - exit (0); - } - - if (!strcmp(argv[argidx],"mix")) { - rme_mixer mix; - int i; - - for (i=0; i<4; i++) { - mix.devnr = i; - ioctl(fd,SOUND_MIXER_PRIVATE1,&mix); - if (mix.devnr == i) { - fprintf(stdout,"devnr %d\n",mix.devnr); - fprintf(stdout,"mix.i_offset %2d (0-25)\n",mix.i_offset); - fprintf(stdout,"mix.o_offset %2d (0-25)\n",mix.o_offset); - } - } - exit (0); - } - -/* the control flags */ - - if (argc < argidx+2) - usage(); - - if (!strcmp(argv[argidx],"master")) { - int val = atoi(argv[argidx+1]); - ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); - printf("master = %d\n",val); - ctrl.master = val; - ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); - exit (0); - } - - if (!strcmp(argv[argidx],"pro")) { - int val = atoi(argv[argidx+1]); - ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); - printf("pro = %d\n",val); - ctrl.pro = val; - ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); - exit (0); - } - - if (!strcmp(argv[argidx],"emphasis")) { - int val = atoi(argv[argidx+1]); - ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); - printf("emphasis = %d\n",val); - ctrl.emphasis = val; - ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); - exit (0); - } - - if (!strcmp(argv[argidx],"dolby")) { - int val = atoi(argv[argidx+1]); - ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); - printf("dolby = %d\n",val); - ctrl.dolby = val; - ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); - exit (0); - } - - if (!strcmp(argv[argidx],"optout")) { - int val = atoi(argv[argidx+1]); - ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); - printf("optout = %d\n",val); - ctrl.opt_out = val; - ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); - exit (0); - } - - if (!strcmp(argv[argidx],"wordclock")) { - int val = atoi(argv[argidx+1]); - ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); - printf("wordclock = %d\n",val); - ctrl.wordclock = val; - ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); - exit (0); - } - - if (!strcmp(argv[argidx],"spdifin")) { - int val = atoi(argv[argidx+1]); - ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); - printf("spdifin = %d\n",val); - ctrl.spdif_in = val; - ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); - exit (0); - } - - if (!strcmp(argv[argidx],"syncref")) { - int val = atoi(argv[argidx+1]); - ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); - printf("syncref = %d\n",val); - ctrl.sync_ref = val; - ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); - exit (0); - } - - if (!strcmp(argv[argidx],"adat1cd")) { - int val = atoi(argv[argidx+1]); - ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); - printf("adat1cd = %d\n",val); - ctrl.adat1_cd = val; - ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); - exit (0); - } - -/* setting offset */ - - if (argc < argidx+4) - usage(); - - if (!strcmp(argv[argidx],"offset")) { - rme_mixer mix; - - mix.devnr = atoi(argv[argidx+1]); - - mix.i_offset = atoi(argv[argidx+2]); - mix.o_offset = atoi(argv[argidx+3]); - ioctl(fdwr,SOUND_MIXER_PRIVATE1,&mix); - fprintf(stdout,"devnr %d\n",mix.devnr); - fprintf(stdout,"mix.i_offset to %d\n",mix.i_offset); - fprintf(stdout,"mix.o_offset to %d\n",mix.o_offset); - exit (0); - } - - usage(); - exit (0); /* to avoid warning */ -} - - ----------------------------- -------------------------------- -#!/usr/bin/wish - -# xrmectrl -# (C) 2000 Guenter Geiger -# HP20020201 - Heiko Purnhagen - -#set defaults "-relief ridged" -set CTRLPROG "./rmectrl" -if {$argc} { - set CTRLPROG "$CTRLPROG $argv" -} -puts "CTRLPROG $CTRLPROG" - -frame .butts -button .butts.exit -text "Exit" -command "exit" -relief ridge -#button .butts.state -text "State" -command "get_all" - -pack .butts.exit -side left -pack .butts -side bottom - - -# -# STATUS -# - -frame .status - -# Sampling Rate - -frame .status.sr -label .status.sr.text -text "Sampling Rate" -justify left -radiobutton .status.sr.441 -selectcolor red -text "44.1 kHz" -width 10 -anchor nw -variable srate -value 44100 -font times -radiobutton .status.sr.480 -selectcolor red -text "48 kHz" -width 10 -anchor nw -variable srate -value 48000 -font times -radiobutton .status.sr.882 -selectcolor red -text "88.2 kHz" -width 10 -anchor nw -variable srate -value 88200 -font times -radiobutton .status.sr.960 -selectcolor red -text "96 kHz" -width 10 -anchor nw -variable srate -value 96000 -font times - -pack .status.sr.text .status.sr.441 .status.sr.480 .status.sr.882 .status.sr.960 -side top -padx 3 - -# Lock - -frame .status.lock -label .status.lock.text -text "Lock" -justify left -checkbutton .status.lock.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatlock1 -font times -checkbutton .status.lock.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatlock2 -font times -checkbutton .status.lock.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatlock3 -font times - -pack .status.lock.text .status.lock.adat1 .status.lock.adat2 .status.lock.adat3 -side top -padx 3 - -# Sync - -frame .status.sync -label .status.sync.text -text "Sync" -justify left -checkbutton .status.sync.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatsync1 -font times -checkbutton .status.sync.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatsync2 -font times -checkbutton .status.sync.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatsync3 -font times - -pack .status.sync.text .status.sync.adat1 .status.sync.adat2 .status.sync.adat3 -side top -padx 3 - -# Timecode - -frame .status.tc -label .status.tc.text -text "Timecode" -justify left -checkbutton .status.tc.busy -selectcolor red -text "busy" -anchor nw -width 10 -variable tcbusy -font times -checkbutton .status.tc.out -selectcolor red -text "out" -anchor nw -width 10 -variable tcout -font times -checkbutton .status.tc.valid -selectcolor red -text "valid" -anchor nw -width 10 -variable tcvalid -font times - -pack .status.tc.text .status.tc.busy .status.tc.out .status.tc.valid -side top -padx 3 - -# SPDIF In - -frame .status.spdif -label .status.spdif.text -text "SPDIF In" -justify left -label .status.spdif.sr -text "--.- kHz" -anchor n -width 10 -font times -checkbutton .status.spdif.error -selectcolor red -text "Input Lock" -anchor nw -width 10 -variable spdiferr -font times - -pack .status.spdif.text .status.spdif.sr .status.spdif.error -side top -padx 3 - -pack .status.sr .status.lock .status.sync .status.tc .status.spdif -side left -fill x -anchor n -expand 1 - - -# -# CONTROL -# - -proc setprof {} { - global CTRLPROG - global spprof - exec $CTRLPROG pro $spprof -} - -proc setemph {} { - global CTRLPROG - global spemph - exec $CTRLPROG emphasis $spemph -} - -proc setnoaud {} { - global CTRLPROG - global spnoaud - exec $CTRLPROG dolby $spnoaud -} - -proc setoptical {} { - global CTRLPROG - global spoptical - exec $CTRLPROG optout $spoptical -} - -proc setspdifin {} { - global CTRLPROG - global spdifin - exec $CTRLPROG spdifin [expr $spdifin - 1] -} - -proc setsyncsource {} { - global CTRLPROG - global syncsource - exec $CTRLPROG syncref [expr $syncsource -1] -} - - -proc setmaster {} { - global CTRLPROG - global master - exec $CTRLPROG master $master -} - -proc setwordclock {} { - global CTRLPROG - global wordclock - exec $CTRLPROG wordclock $wordclock -} - -proc setadat1cd {} { - global CTRLPROG - global adat1cd - exec $CTRLPROG adat1cd $adat1cd -} - - -frame .control - -# SPDIF In & SPDIF Out - - -frame .control.spdif - -frame .control.spdif.in -label .control.spdif.in.text -text "SPDIF In" -justify left -radiobutton .control.spdif.in.input1 -text "Optical" -anchor nw -width 13 -variable spdifin -value 1 -command setspdifin -selectcolor blue -font times -radiobutton .control.spdif.in.input2 -text "Coaxial" -anchor nw -width 13 -variable spdifin -value 2 -command setspdifin -selectcolor blue -font times -radiobutton .control.spdif.in.input3 -text "Intern " -anchor nw -width 13 -variable spdifin -command setspdifin -value 3 -selectcolor blue -font times - -checkbutton .control.spdif.in.adat1cd -text "ADAT1 Intern" -anchor nw -width 13 -variable adat1cd -command setadat1cd -selectcolor blue -font times - -pack .control.spdif.in.text .control.spdif.in.input1 .control.spdif.in.input2 .control.spdif.in.input3 .control.spdif.in.adat1cd - -label .control.spdif.space - -frame .control.spdif.out -label .control.spdif.out.text -text "SPDIF Out" -justify left -checkbutton .control.spdif.out.pro -text "Professional" -anchor nw -width 13 -variable spprof -command setprof -selectcolor blue -font times -checkbutton .control.spdif.out.emphasis -text "Emphasis" -anchor nw -width 13 -variable spemph -command setemph -selectcolor blue -font times -checkbutton .control.spdif.out.dolby -text "NoAudio" -anchor nw -width 13 -variable spnoaud -command setnoaud -selectcolor blue -font times -checkbutton .control.spdif.out.optout -text "Optical Out" -anchor nw -width 13 -variable spoptical -command setoptical -selectcolor blue -font times - -pack .control.spdif.out.optout .control.spdif.out.dolby .control.spdif.out.emphasis .control.spdif.out.pro .control.spdif.out.text -side bottom - -pack .control.spdif.in .control.spdif.space .control.spdif.out -side top -fill y -padx 3 -expand 1 - -# Sync Mode & Sync Source - -frame .control.sync -frame .control.sync.mode -label .control.sync.mode.text -text "Sync Mode" -justify left -checkbutton .control.sync.mode.master -text "Master" -anchor nw -width 13 -variable master -command setmaster -selectcolor blue -font times -checkbutton .control.sync.mode.wc -text "Wordclock" -anchor nw -width 13 -variable wordclock -command setwordclock -selectcolor blue -font times - -pack .control.sync.mode.text .control.sync.mode.master .control.sync.mode.wc - -label .control.sync.space - -frame .control.sync.src -label .control.sync.src.text -text "Sync Source" -justify left -radiobutton .control.sync.src.input1 -text "ADAT1" -anchor nw -width 13 -variable syncsource -value 1 -command setsyncsource -selectcolor blue -font times -radiobutton .control.sync.src.input2 -text "ADAT2" -anchor nw -width 13 -variable syncsource -value 2 -command setsyncsource -selectcolor blue -font times -radiobutton .control.sync.src.input3 -text "ADAT3" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 3 -selectcolor blue -font times -radiobutton .control.sync.src.input4 -text "SPDIF" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 4 -selectcolor blue -font times - -pack .control.sync.src.input4 .control.sync.src.input3 .control.sync.src.input2 .control.sync.src.input1 .control.sync.src.text -side bottom - -pack .control.sync.mode .control.sync.space .control.sync.src -side top -fill y -padx 3 -expand 1 - -label .control.space -text "" -width 10 - -# Buffer Size - -frame .control.buf -label .control.buf.text -text "Buffer Size (Latency)" -justify left -radiobutton .control.buf.b1 -selectcolor red -text "64 (1.5 ms)" -width 13 -anchor nw -variable ssrate -value 1 -font times -radiobutton .control.buf.b2 -selectcolor red -text "128 (3 ms)" -width 13 -anchor nw -variable ssrate -value 2 -font times -radiobutton .control.buf.b3 -selectcolor red -text "256 (6 ms)" -width 13 -anchor nw -variable ssrate -value 3 -font times -radiobutton .control.buf.b4 -selectcolor red -text "512 (12 ms)" -width 13 -anchor nw -variable ssrate -value 4 -font times -radiobutton .control.buf.b5 -selectcolor red -text "1024 (23 ms)" -width 13 -anchor nw -variable ssrate -value 5 -font times -radiobutton .control.buf.b6 -selectcolor red -text "2048 (46 ms)" -width 13 -anchor nw -variable ssrate -value 6 -font times -radiobutton .control.buf.b7 -selectcolor red -text "4096 (93 ms)" -width 13 -anchor nw -variable ssrate -value 7 -font times -radiobutton .control.buf.b8 -selectcolor red -text "8192 (186 ms)" -width 13 -anchor nw -variable ssrate -value 8 -font times - -pack .control.buf.text .control.buf.b1 .control.buf.b2 .control.buf.b3 .control.buf.b4 .control.buf.b5 .control.buf.b6 .control.buf.b7 .control.buf.b8 -side top -padx 3 - -# Offset - -frame .control.offset - -frame .control.offset.in -label .control.offset.in.text -text "Offset In" -justify left -label .control.offset.in.off0 -text "dev\#0: -" -anchor nw -width 10 -font times -label .control.offset.in.off1 -text "dev\#1: -" -anchor nw -width 10 -font times -label .control.offset.in.off2 -text "dev\#2: -" -anchor nw -width 10 -font times -label .control.offset.in.off3 -text "dev\#3: -" -anchor nw -width 10 -font times - -pack .control.offset.in.text .control.offset.in.off0 .control.offset.in.off1 .control.offset.in.off2 .control.offset.in.off3 - -label .control.offset.space - -frame .control.offset.out -label .control.offset.out.text -text "Offset Out" -justify left -label .control.offset.out.off0 -text "dev\#0: -" -anchor nw -width 10 -font times -label .control.offset.out.off1 -text "dev\#1: -" -anchor nw -width 10 -font times -label .control.offset.out.off2 -text "dev\#2: -" -anchor nw -width 10 -font times -label .control.offset.out.off3 -text "dev\#3: -" -anchor nw -width 10 -font times - -pack .control.offset.out.off3 .control.offset.out.off2 .control.offset.out.off1 .control.offset.out.off0 .control.offset.out.text -side bottom - -pack .control.offset.in .control.offset.space .control.offset.out -side top -fill y -padx 3 -expand 1 - - -pack .control.spdif .control.sync .control.space .control.buf .control.offset -side left -fill both -anchor n -expand 1 - - -label .statustext -text Status -justify center -relief ridge -label .controltext -text Control -justify center -relief ridge - -label .statusspace -label .controlspace - -pack .statustext .status .statusspace .controltext .control .controlspace -side top -anchor nw -fill both -expand 1 - - -proc get_bit {output sstr} { - set idx1 [string last [concat $sstr 1] $output] - set idx1 [expr $idx1 != -1] - return $idx1 -} - -proc get_val {output sstr} { - set val [string wordend $output [string last $sstr $output]] - set val [string range $output $val [expr $val+1]] - return $val -} - -proc get_val2 {output sstr} { - set val [string wordend $output [string first $sstr $output]] - set val [string range $output $val [expr $val+2]] - return $val -} - -proc get_control {} { - global spprof - global spemph - global spnoaud - global spoptical - global spdifin - global ssrate - global master - global wordclock - global syncsource - global CTRLPROG - - set f [open "| $CTRLPROG control" r+] - set ooo [read $f 1000] - close $f -# puts $ooo - - set spprof [ get_bit $ooo "pro"] - set spemph [ get_bit $ooo "emphasis"] - set spnoaud [ get_bit $ooo "dolby"] - set spoptical [ get_bit $ooo "opt_out"] - set spdifin [ expr [ get_val $ooo "spdif_in"] + 1] - set ssrate [ expr [ get_val $ooo "latency"] + 1] - set master [ expr [ get_val $ooo "master"]] - set wordclock [ expr [ get_val $ooo "wordclock"]] - set syncsource [ expr [ get_val $ooo "sync_ref"] + 1] -} - -proc get_status {} { - global srate - global ctrlcom - - global adatlock1 - global adatlock2 - global adatlock3 - - global adatsync1 - global adatsync2 - global adatsync3 - - global tcbusy - global tcout - global tcvalid - - global spdiferr - global crystal - global .status.spdif.text - global CTRLPROG - - - set f [open "| $CTRLPROG status" r+] - set ooo [read $f 1000] - close $f -# puts $ooo - -# samplerate - - set idx1 [string last "sr48 1" $ooo] - set idx2 [string last "doublespeed 1" $ooo] - if {$idx1 >= 0} { - set fact1 48000 - } else { - set fact1 44100 - } - - if {$idx2 >= 0} { - set fact2 2 - } else { - set fact2 1 - } - set srate [expr $fact1 * $fact2] -# ADAT lock - - set val [get_val $ooo lockmask] - set adatlock1 0 - set adatlock2 0 - set adatlock3 0 - if {[expr $val & 1]} { - set adatlock3 1 - } - if {[expr $val & 2]} { - set adatlock2 1 - } - if {[expr $val & 4]} { - set adatlock1 1 - } - -# ADAT sync - set val [get_val $ooo syncmask] - set adatsync1 0 - set adatsync2 0 - set adatsync3 0 - - if {[expr $val & 1]} { - set adatsync3 1 - } - if {[expr $val & 2]} { - set adatsync2 1 - } - if {[expr $val & 4]} { - set adatsync1 1 - } - -# TC busy - - set tcbusy [get_bit $ooo "busy"] - set tcout [get_bit $ooo "out"] - set tcvalid [get_bit $ooo "valid"] - set spdiferr [expr [get_bit $ooo "spdif_error"] == 0] - -# 000=64kHz, 100=88.2kHz, 011=96kHz -# 111=32kHz, 110=44.1kHz, 101=48kHz - - set val [get_val $ooo crystalrate] - - set crystal "--.- kHz" - if {$val == 0} { - set crystal "64 kHz" - } - if {$val == 4} { - set crystal "88.2 kHz" - } - if {$val == 3} { - set crystal "96 kHz" - } - if {$val == 7} { - set crystal "32 kHz" - } - if {$val == 6} { - set crystal "44.1 kHz" - } - if {$val == 5} { - set crystal "48 kHz" - } - .status.spdif.sr configure -text $crystal -} - -proc get_offset {} { - global inoffset - global outoffset - global CTRLPROG - - set f [open "| $CTRLPROG mix" r+] - set ooo [read $f 1000] - close $f -# puts $ooo - - if { [string match "*devnr*" $ooo] } { - set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] - set val [get_val2 $ooo i_offset] - .control.offset.in.off0 configure -text "dev\#0: $val" - set val [get_val2 $ooo o_offset] - .control.offset.out.off0 configure -text "dev\#0: $val" - } else { - .control.offset.in.off0 configure -text "dev\#0: -" - .control.offset.out.off0 configure -text "dev\#0: -" - } - if { [string match "*devnr*" $ooo] } { - set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] - set val [get_val2 $ooo i_offset] - .control.offset.in.off1 configure -text "dev\#1: $val" - set val [get_val2 $ooo o_offset] - .control.offset.out.off1 configure -text "dev\#1: $val" - } else { - .control.offset.in.off1 configure -text "dev\#1: -" - .control.offset.out.off1 configure -text "dev\#1: -" - } - if { [string match "*devnr*" $ooo] } { - set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] - set val [get_val2 $ooo i_offset] - .control.offset.in.off2 configure -text "dev\#2: $val" - set val [get_val2 $ooo o_offset] - .control.offset.out.off2 configure -text "dev\#2: $val" - } else { - .control.offset.in.off2 configure -text "dev\#2: -" - .control.offset.out.off2 configure -text "dev\#2: -" - } - if { [string match "*devnr*" $ooo] } { - set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] - set val [get_val2 $ooo i_offset] - .control.offset.in.off3 configure -text "dev\#3: $val" - set val [get_val2 $ooo o_offset] - .control.offset.out.off3 configure -text "dev\#3: $val" - } else { - .control.offset.in.off3 configure -text "dev\#3: -" - .control.offset.out.off3 configure -text "dev\#3: -" - } -} - - -proc get_all {} { -get_status -get_control -get_offset -} - -# main -while {1} { - after 200 - get_all - update -} diff --git a/Documentation/sound/oss/solo1 b/Documentation/sound/oss/solo1 deleted file mode 100644 index 95c4c83422b3..000000000000 --- a/Documentation/sound/oss/solo1 +++ /dev/null @@ -1,70 +0,0 @@ -Recording ---------- - -Recording does not work on the author's card, but there -is at least one report of it working on later silicon. -The chip behaves differently than described in the data sheet, -likely due to a chip bug. Working around this would require -the help of ESS (for example by publishing an errata sheet), -but ESS has not done so far. - -Also, the chip only supports 24 bit addresses for recording, -which means it cannot work on some Alpha mainboards. - - -/proc/sound, /dev/sndstat -------------------------- - -/proc/sound and /dev/sndstat is not supported by the -driver. To find out whether the driver succeeded loading, -check the kernel log (dmesg). - - -ALaw/uLaw sample formats ------------------------- - -This driver does not support the ALaw/uLaw sample formats. -ALaw is the default mode when opening a sound device -using OSS/Free. The reason for the lack of support is -that the hardware does not support these formats, and adding -conversion routines to the kernel would lead to very ugly -code in the presence of the mmap interface to the driver. -And since xquake uses mmap, mmap is considered important :-) -and no sane application uses ALaw/uLaw these days anyway. -In short, playing a Sun .au file as follows: - -cat my_file.au > /dev/dsp - -does not work. Instead, you may use the play script from -Chris Bagwell's sox-12.14 package (or later, available from the URL -below) to play many different audio file formats. -The script automatically determines the audio format -and does do audio conversions if necessary. -http://home.sprynet.com/sprynet/cbagwell/projects.html - - -Blocking vs. nonblocking IO ---------------------------- - -Unlike OSS/Free this driver honours the O_NONBLOCK file flag -not only during open, but also during read and write. -This is an effort to make the sound driver interface more -regular. Timidity has problems with this; a patch -is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html. -(Timidity patched will also run on OSS/Free). - - -MIDI UART ---------- - -The driver supports a simple MIDI UART interface, with -no ioctl's supported. - - -MIDI synthesizer ----------------- - -The card has an OPL compatible FM synthesizer. - -Thomas Sailer -t.sailer@alumni.ethz.ch diff --git a/Documentation/sound/oss/sonicvibes b/Documentation/sound/oss/sonicvibes deleted file mode 100644 index 84dee2e0b37d..000000000000 --- a/Documentation/sound/oss/sonicvibes +++ /dev/null @@ -1,81 +0,0 @@ -/proc/sound, /dev/sndstat -------------------------- - -/proc/sound and /dev/sndstat is not supported by the -driver. To find out whether the driver succeeded loading, -check the kernel log (dmesg). - - -ALaw/uLaw sample formats ------------------------- - -This driver does not support the ALaw/uLaw sample formats. -ALaw is the default mode when opening a sound device -using OSS/Free. The reason for the lack of support is -that the hardware does not support these formats, and adding -conversion routines to the kernel would lead to very ugly -code in the presence of the mmap interface to the driver. -And since xquake uses mmap, mmap is considered important :-) -and no sane application uses ALaw/uLaw these days anyway. -In short, playing a Sun .au file as follows: - -cat my_file.au > /dev/dsp - -does not work. Instead, you may use the play script from -Chris Bagwell's sox-12.14 package (available from the URL -below) to play many different audio file formats. -The script automatically determines the audio format -and does do audio conversions if necessary. -http://home.sprynet.com/sprynet/cbagwell/projects.html - - -Blocking vs. nonblocking IO ---------------------------- - -Unlike OSS/Free this driver honours the O_NONBLOCK file flag -not only during open, but also during read and write. -This is an effort to make the sound driver interface more -regular. Timidity has problems with this; a patch -is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html. -(Timidity patched will also run on OSS/Free). - - -MIDI UART ---------- - -The driver supports a simple MIDI UART interface, with -no ioctl's supported. - - -MIDI synthesizer ----------------- - -The card both has an OPL compatible FM synthesizer as well as -a wavetable synthesizer. - -I haven't managed so far to get the OPL synth running. - -Using the wavetable synthesizer requires allocating -1-4MB of physically contiguous memory, which isn't possible -currently on Linux without ugly hacks like the bigphysarea -patch. Therefore, the driver doesn't support wavetable -synthesis. - - -No support from S3 ------------------- - -I do not get any support from S3. Therefore, the driver -still has many problems. For example, although the manual -states that the chip should be able to access the sample -buffer anywhere in 32bit address space, I haven't managed to -get it working with buffers above 16M. Therefore, the card -has the same disadvantages as ISA soundcards. - -Given that the card is also very noisy, and if you haven't -already bought it, you should strongly opt for one of the -comparatively priced Ensoniq products. - - -Thomas Sailer -t.sailer@alumni.ethz.ch diff --git a/MAINTAINERS b/MAINTAINERS index fb10f71b8b64..8c35b3c503aa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1900,11 +1900,6 @@ M: rroesler@syskonnect.de W: http://www.syskonnect.com S: Supported -MAESTRO PCI SOUND DRIVERS -P: Zach Brown -M: zab@zabbo.net -S: Odd Fixes - MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7 P: Michael Kerrisk M: mtk-manpages@gmx.net @@ -3402,12 +3397,6 @@ M: Henk.Vergonet@gmail.com L: usbb2k-api-dev@nongnu.org S: Maintained -YMFPCI YAMAHA PCI SOUND (Use ALSA instead) -P: Pete Zaitcev -M: zaitcev@yahoo.com -L: linux-kernel@vger.kernel.org -S: Obsolete - Z8530 DRIVER FOR AX.25 P: Joerg Reuter M: jreuter@yaina.de diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 9e8bcb5fa99c..7d564b6fc98f 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -160,7 +160,6 @@ header-y += video_decoder.h header-y += video_encoder.h header-y += videotext.h header-y += vt.h -header-y += wavefront.h header-y += wireless.h header-y += xattr.h header-y += x25.h diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h index 2ed2fd855133..22eb9367235a 100644 --- a/include/linux/ac97_codec.h +++ b/include/linux/ac97_codec.h @@ -331,8 +331,6 @@ extern int ac97_read_proc (char *page_out, char **start, off_t off, extern int ac97_probe_codec(struct ac97_codec *); extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate); extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate); -extern int ac97_save_state(struct ac97_codec *codec); -extern int ac97_restore_state(struct ac97_codec *codec); extern struct ac97_codec *ac97_alloc_codec(void); extern void ac97_release_codec(struct ac97_codec *codec); @@ -346,9 +344,6 @@ struct ac97_driver { void (*remove) (struct ac97_codec *codec, struct ac97_driver *driver); }; -extern int ac97_register_driver(struct ac97_driver *driver); -extern void ac97_unregister_driver(struct ac97_driver *driver); - /* quirk types */ enum { AC97_TUNE_DEFAULT = -1, /* use default from quirk list (not valid in list) */ diff --git a/include/linux/sound.h b/include/linux/sound.h index f63d8342ffa3..9e2a94feed6b 100644 --- a/include/linux/sound.h +++ b/include/linux/sound.h @@ -35,10 +35,8 @@ extern int register_sound_special_device(const struct file_operations *fops, int extern int register_sound_mixer(const struct file_operations *fops, int dev); extern int register_sound_midi(const struct file_operations *fops, int dev); extern int register_sound_dsp(const struct file_operations *fops, int dev); -extern int register_sound_synth(const struct file_operations *fops, int dev); extern void unregister_sound_special(int unit); extern void unregister_sound_mixer(int unit); extern void unregister_sound_midi(int unit); extern void unregister_sound_dsp(int unit); -extern void unregister_sound_synth(int unit); diff --git a/include/linux/wavefront.h b/include/linux/wavefront.h deleted file mode 100644 index 51ab3c933acd..000000000000 --- a/include/linux/wavefront.h +++ /dev/null @@ -1,675 +0,0 @@ -#ifndef __wavefront_h__ -#define __wavefront_h__ - -/* WaveFront header file. - * - * Copyright (C) by Paul Barton-Davis 1998 - * - * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - -#if (!defined(__GNUC__) && !defined(__GNUG__)) - - You will not be able to compile this file correctly without gcc, because - it is necessary to pack the "wavefront_alias" structure to a size - of 22 bytes, corresponding to 16-bit alignment (as would have been - the case on the original platform, MS-DOS). If this is not done, - then WavePatch-format files cannot be read/written correctly. - The method used to do this here ("__attribute__((packed)") is - completely compiler dependent. - - All other wavefront_* types end up aligned to 32 bit values and - still have the same (correct) size. - -#else - - /* However, note that as of G++ 2.7.3.2, g++ was unable to - correctly parse *type* __attribute__ tags. It will do the - right thing if we use the "packed" attribute on each struct - member, which has the same semantics anyway. - */ - -#endif /* __GNUC__ */ - -/***************************** WARNING ******************************** - PLEASE DO NOT MODIFY THIS FILE IN ANY WAY THAT AFFECTS ITS ABILITY TO - BE USED WITH EITHER C *OR* C++. - **********************************************************************/ - -#ifndef NUM_MIDIKEYS -#define NUM_MIDIKEYS 128 -#endif /* NUM_MIDIKEYS */ - -#ifndef NUM_MIDICHANNELS -#define NUM_MIDICHANNELS 16 -#endif /* NUM_MIDICHANNELS */ - -/* These are very useful/important. the original wavefront interface - was developed on a 16 bit system, where sizeof(int) = 2 - bytes. Defining things like this makes the code much more portable, and - easier to understand without having to toggle back and forth - between a 16-bit view of the world and a 32-bit one. - */ - -typedef short INT16; -typedef unsigned short UINT16; -typedef int INT32; -typedef unsigned int UINT32; -typedef char CHAR8; -typedef unsigned char UCHAR8; - -/* Pseudo-commands not part of the WaveFront command set. - These are used for various driver controls and direct - hardware control. - */ - -#define WFC_DEBUG_DRIVER 0 -#define WFC_FX_IOCTL 1 -#define WFC_PATCH_STATUS 2 -#define WFC_PROGRAM_STATUS 3 -#define WFC_SAMPLE_STATUS 4 -#define WFC_DISABLE_INTERRUPTS 5 -#define WFC_ENABLE_INTERRUPTS 6 -#define WFC_INTERRUPT_STATUS 7 -#define WFC_ROMSAMPLES_RDONLY 8 -#define WFC_IDENTIFY_SLOT_TYPE 9 - -/* Wavefront synth commands - */ - -#define WFC_DOWNLOAD_SAMPLE 0x80 -#define WFC_DOWNLOAD_BLOCK 0x81 -#define WFC_DOWNLOAD_MULTISAMPLE 0x82 -#define WFC_DOWNLOAD_SAMPLE_ALIAS 0x83 -#define WFC_DELETE_SAMPLE 0x84 -#define WFC_REPORT_FREE_MEMORY 0x85 -#define WFC_DOWNLOAD_PATCH 0x86 -#define WFC_DOWNLOAD_PROGRAM 0x87 -#define WFC_SET_SYNTHVOL 0x89 -#define WFC_SET_NVOICES 0x8B -#define WFC_DOWNLOAD_DRUM 0x90 -#define WFC_GET_SYNTHVOL 0x92 -#define WFC_GET_NVOICES 0x94 -#define WFC_DISABLE_CHANNEL 0x9A -#define WFC_ENABLE_CHANNEL 0x9B -#define WFC_MISYNTH_OFF 0x9D -#define WFC_MISYNTH_ON 0x9E -#define WFC_FIRMWARE_VERSION 0x9F -#define WFC_GET_NSAMPLES 0xA0 -#define WFC_DISABLE_DRUM_PROGRAM 0xA2 -#define WFC_UPLOAD_PATCH 0xA3 -#define WFC_UPLOAD_PROGRAM 0xA4 -#define WFC_SET_TUNING 0xA6 -#define WFC_GET_TUNING 0xA7 -#define WFC_VMIDI_ON 0xA8 -#define WFC_VMIDI_OFF 0xA9 -#define WFC_MIDI_STATUS 0xAA -#define WFC_GET_CHANNEL_STATUS 0xAB -#define WFC_DOWNLOAD_SAMPLE_HEADER 0xAC -#define WFC_UPLOAD_SAMPLE_HEADER 0xAD -#define WFC_UPLOAD_MULTISAMPLE 0xAE -#define WFC_UPLOAD_SAMPLE_ALIAS 0xAF -#define WFC_IDENTIFY_SAMPLE_TYPE 0xB0 -#define WFC_DOWNLOAD_EDRUM_PROGRAM 0xB1 -#define WFC_UPLOAD_EDRUM_PROGRAM 0xB2 -#define WFC_SET_EDRUM_CHANNEL 0xB3 -#define WFC_INSTOUT_LEVELS 0xB4 -#define WFC_PEAKOUT_LEVELS 0xB5 -#define WFC_REPORT_CHANNEL_PROGRAMS 0xB6 -#define WFC_HARDWARE_VERSION 0xCF -#define WFC_UPLOAD_SAMPLE_PARAMS 0xD7 -#define WFC_DOWNLOAD_OS 0xF1 -#define WFC_NOOP 0xFF - -#define WF_MAX_SAMPLE 512 -#define WF_MAX_PATCH 256 -#define WF_MAX_PROGRAM 128 - -#define WF_SECTION_MAX 44 /* longest OS section length */ - -/* # of bytes we send to the board when sending it various kinds of - substantive data, such as samples, patches and programs. -*/ - -#define WF_PROGRAM_BYTES 32 -#define WF_PATCH_BYTES 132 -#define WF_SAMPLE_BYTES 27 -#define WF_SAMPLE_HDR_BYTES 25 -#define WF_ALIAS_BYTES 25 -#define WF_DRUM_BYTES 9 -#define WF_MSAMPLE_BYTES 259 /* (MIDI_KEYS * 2) + 3 */ - -#define WF_ACK 0x80 -#define WF_DMA_ACK 0x81 - -/* OR-values for MIDI status bits */ - -#define WF_MIDI_VIRTUAL_ENABLED 0x1 -#define WF_MIDI_VIRTUAL_IS_EXTERNAL 0x2 -#define WF_MIDI_IN_TO_SYNTH_DISABLED 0x4 - -/* slot indexes for struct address_info: makes code a little more mnemonic */ - -#define WF_SYNTH_SLOT 0 -#define WF_INTERNAL_MIDI_SLOT 1 -#define WF_EXTERNAL_MIDI_SLOT 2 - -/* Magic MIDI bytes used to switch I/O streams on the ICS2115 MPU401 - emulation. Note these NEVER show up in output from the device and - should NEVER be used in input unless Virtual MIDI mode has been - disabled. If they do show up as input, the results are unpredictable. -*/ - -#define WF_EXTERNAL_SWITCH 0xFD -#define WF_INTERNAL_SWITCH 0xF9 - -/* Debugging flags */ - -#define WF_DEBUG_CMD 0x1 -#define WF_DEBUG_DATA 0x2 -#define WF_DEBUG_LOAD_PATCH 0x4 -#define WF_DEBUG_IO 0x8 - -/* WavePatch file format stuff */ - -#define WF_WAVEPATCH_VERSION 120; /* Current version number (1.2) */ -#define WF_MAX_COMMENT 64 /* Comment length */ -#define WF_NUM_LAYERS 4 -#define WF_NAME_LENGTH 32 -#define WF_SOURCE_LENGTH 260 - -#define BankFileID "Bank" -#define DrumkitFileID "DrumKit" -#define ProgramFileID "Program" - -struct wf_envelope -{ - UCHAR8 attack_time:7; - UCHAR8 Unused1:1; - - UCHAR8 decay1_time:7; - UCHAR8 Unused2:1; - - UCHAR8 decay2_time:7; - UCHAR8 Unused3:1; - - UCHAR8 sustain_time:7; - UCHAR8 Unused4:1; - - UCHAR8 release_time:7; - UCHAR8 Unused5:1; - - UCHAR8 release2_time:7; - UCHAR8 Unused6:1; - - CHAR8 attack_level; - CHAR8 decay1_level; - CHAR8 decay2_level; - CHAR8 sustain_level; - CHAR8 release_level; - - UCHAR8 attack_velocity:7; - UCHAR8 Unused7:1; - - UCHAR8 volume_velocity:7; - UCHAR8 Unused8:1; - - UCHAR8 keyboard_scaling:7; - UCHAR8 Unused9:1; -}; -typedef struct wf_envelope wavefront_envelope; - -struct wf_lfo -{ - UCHAR8 sample_number; - - UCHAR8 frequency:7; - UCHAR8 Unused1:1; - - UCHAR8 am_src:4; - UCHAR8 fm_src:4; - - CHAR8 fm_amount; - CHAR8 am_amount; - CHAR8 start_level; - CHAR8 end_level; - - UCHAR8 ramp_delay:7; - UCHAR8 wave_restart:1; /* for LFO2 only */ - - UCHAR8 ramp_time:7; - UCHAR8 Unused2:1; -}; -typedef struct wf_lfo wavefront_lfo; - -struct wf_patch -{ - INT16 frequency_bias; /* ** THIS IS IN MOTOROLA FORMAT!! ** */ - - UCHAR8 amplitude_bias:7; - UCHAR8 Unused1:1; - - UCHAR8 portamento:7; - UCHAR8 Unused2:1; - - UCHAR8 sample_number; - - UCHAR8 pitch_bend:4; - UCHAR8 sample_msb:1; - UCHAR8 Unused3:3; - - UCHAR8 mono:1; - UCHAR8 retrigger:1; - UCHAR8 nohold:1; - UCHAR8 restart:1; - UCHAR8 filterconfig:2; /* SDK says "not used" */ - UCHAR8 reuse:1; - UCHAR8 reset_lfo:1; - - UCHAR8 fm_src2:4; - UCHAR8 fm_src1:4; - - CHAR8 fm_amount1; - CHAR8 fm_amount2; - - UCHAR8 am_src:4; - UCHAR8 Unused4:4; - - CHAR8 am_amount; - - UCHAR8 fc1_mode:4; - UCHAR8 fc2_mode:4; - - CHAR8 fc1_mod_amount; - CHAR8 fc1_keyboard_scaling; - CHAR8 fc1_bias; - CHAR8 fc2_mod_amount; - CHAR8 fc2_keyboard_scaling; - CHAR8 fc2_bias; - - UCHAR8 randomizer:7; - UCHAR8 Unused5:1; - - struct wf_envelope envelope1; - struct wf_envelope envelope2; - struct wf_lfo lfo1; - struct wf_lfo lfo2; -}; -typedef struct wf_patch wavefront_patch; - -struct wf_layer -{ - UCHAR8 patch_number; - - UCHAR8 mix_level:7; - UCHAR8 mute:1; - - UCHAR8 split_point:7; - UCHAR8 play_below:1; - - UCHAR8 pan_mod_src:2; - UCHAR8 pan_or_mod:1; - UCHAR8 pan:4; - UCHAR8 split_type:1; -}; -typedef struct wf_layer wavefront_layer; - -struct wf_program -{ - struct wf_layer layer[WF_NUM_LAYERS]; -}; -typedef struct wf_program wavefront_program; - -struct wf_sample_offset -{ - INT32 Fraction:4; - INT32 Integer:20; - INT32 Unused:8; -}; -typedef struct wf_sample_offset wavefront_sample_offset; - -/* Sample slot types */ - -#define WF_ST_SAMPLE 0 -#define WF_ST_MULTISAMPLE 1 -#define WF_ST_ALIAS 2 -#define WF_ST_EMPTY 3 - -/* pseudo's */ - -#define WF_ST_DRUM 4 -#define WF_ST_PROGRAM 5 -#define WF_ST_PATCH 6 -#define WF_ST_SAMPLEHDR 7 - -#define WF_ST_MASK 0xf - -/* Flags for slot status. These occupy the upper bits of the same byte - as a sample type. -*/ - -#define WF_SLOT_USED 0x80 /* XXX don't rely on this being accurate */ -#define WF_SLOT_FILLED 0x40 -#define WF_SLOT_ROM 0x20 - -#define WF_SLOT_MASK 0xf0 - -/* channel constants */ - -#define WF_CH_MONO 0 -#define WF_CH_LEFT 1 -#define WF_CH_RIGHT 2 - -/* Sample formats */ - -#define LINEAR_16BIT 0 -#define WHITE_NOISE 1 -#define LINEAR_8BIT 2 -#define MULAW_8BIT 3 - -#define WF_SAMPLE_IS_8BIT(smpl) ((smpl)->SampleResolution&2) - - -/* - - Because most/all of the sample data we pass in via pointers has - never been copied (just mmap-ed into user space straight from the - disk), it would be nice to allow handling of multi-channel sample - data without forcing user-level extraction of the relevant bytes. - - So, we need a way of specifying which channel to use (the WaveFront - only handles mono samples in a given slot), and the only way to do - this without using some struct other than wavefront_sample as the - interface is the awful hack of using the unused bits in a - wavefront_sample: - - Val Meaning - --- ------- - 0 no channel selection (use channel 1, sample is MONO) - 1 use first channel, and skip one - 2 use second channel, and skip one - 3 use third channel, and skip two - 4 use fourth channel, skip three - 5 use fifth channel, skip four - 6 use six channel, skip five - - - This can handle up to 4 channels, and anyone downloading >4 channels - of sample data just to select one of them needs to find some tools - like sox ... - - NOTE: values 0, 1 and 2 correspond to WF_CH_* above. This is - important. - -*/ - -#define WF_SET_CHANNEL(samp,chn) \ - (samp)->Unused1 = chn & 0x1; \ - (samp)->Unused2 = chn & 0x2; \ - (samp)->Unused3 = chn & 0x4 - -#define WF_GET_CHANNEL(samp) \ - (((samp)->Unused3 << 2)|((samp)->Unused2<<1)|(samp)->Unused1) - -typedef struct wf_sample { - struct wf_sample_offset sampleStartOffset; - struct wf_sample_offset loopStartOffset; - struct wf_sample_offset loopEndOffset; - struct wf_sample_offset sampleEndOffset; - INT16 FrequencyBias; - UCHAR8 SampleResolution:2; /* sample_format */ - UCHAR8 Unused1:1; - UCHAR8 Loop:1; - UCHAR8 Bidirectional:1; - UCHAR8 Unused2:1; - UCHAR8 Reverse:1; - UCHAR8 Unused3:1; -} wavefront_sample; - -typedef struct wf_multisample { - INT16 NumberOfSamples; /* log2 of the number of samples */ - INT16 SampleNumber[NUM_MIDIKEYS]; -} wavefront_multisample; - -typedef struct wf_alias { - INT16 OriginalSample; - - struct wf_sample_offset sampleStartOffset; - struct wf_sample_offset loopStartOffset; - struct wf_sample_offset sampleEndOffset; - struct wf_sample_offset loopEndOffset; - - INT16 FrequencyBias; - - UCHAR8 SampleResolution:2; - UCHAR8 Unused1:1; - UCHAR8 Loop:1; - UCHAR8 Bidirectional:1; - UCHAR8 Unused2:1; - UCHAR8 Reverse:1; - UCHAR8 Unused3:1; - - /* This structure is meant to be padded only to 16 bits on their - original. Of course, whoever wrote their documentation didn't - realize that sizeof(struct) can be >= - sum(sizeof(struct-fields)) and so thought that giving a C level - description of the structs used in WavePatch files was - sufficient. I suppose it was, as long as you remember the - standard 16->32 bit issues. - */ - - UCHAR8 sixteen_bit_padding; -} __attribute__((packed)) wavefront_alias; - -typedef struct wf_drum { - UCHAR8 PatchNumber; - UCHAR8 MixLevel:7; - UCHAR8 Unmute:1; - UCHAR8 Group:4; - UCHAR8 Unused1:4; - UCHAR8 PanModSource:2; - UCHAR8 PanModulated:1; - UCHAR8 PanAmount:4; - UCHAR8 Unused2:1; -} wavefront_drum; - -typedef struct wf_drumkit { - struct wf_drum drum[NUM_MIDIKEYS]; -} wavefront_drumkit; - -typedef struct wf_channel_programs { - UCHAR8 Program[NUM_MIDICHANNELS]; -} wavefront_channel_programs; - -/* How to get MIDI channel status from the data returned by - a WFC_GET_CHANNEL_STATUS command (a struct wf_channel_programs) -*/ - -#define WF_CHANNEL_STATUS(ch,wcp) (wcp)[(ch/7)] & (1<<((ch)%7)) - -typedef union wf_any { - wavefront_sample s; - wavefront_multisample ms; - wavefront_alias a; - wavefront_program pr; - wavefront_patch p; - wavefront_drum d; -} wavefront_any; - -/* Hannu Solvainen hoped that his "patch_info" struct in soundcard.h - might work for other wave-table based patch loading situations. - Alas, his fears were correct. The WaveFront doesn't even come with - just "patches", but several different kind of structures that - control the sound generation process. - */ - -typedef struct wf_patch_info { - - /* the first two fields are used by the OSS "patch loading" interface - only, and are unused by the current user-level library. - */ - - INT16 key; /* Use WAVEFRONT_PATCH here */ - UINT16 devno; /* fill in when sending */ - UCHAR8 subkey; /* WF_ST_{SAMPLE,ALIAS,etc.} */ - -#define WAVEFRONT_FIND_FREE_SAMPLE_SLOT 999 - - UINT16 number; /* patch/sample/prog number */ - - UINT32 size; /* size of any data included in - one of the fields in `hdrptr', or - as `dataptr'. - - NOTE: for actual samples, this is - the size of the *SELECTED CHANNEL* - even if more data is actually available. - - So, a stereo sample (2 channels) of - 6000 bytes total has `size' = 3000. - - See the macros and comments for - WF_{GET,SET}_CHANNEL above. - - */ - wavefront_any __user *hdrptr; /* user-space ptr to hdr bytes */ - UINT16 __user *dataptr; /* actual sample data */ - - wavefront_any hdr; /* kernel-space copy of hdr bytes */ -} wavefront_patch_info; - -/* The maximum number of bytes we will ever move to or from user space - in response to a WFC_* command. This obviously doesn't cover - actual sample data. -*/ - -#define WF_MAX_READ sizeof(wavefront_multisample) -#define WF_MAX_WRITE sizeof(wavefront_multisample) - -/* - This allows us to execute any WF command except the download/upload - ones, which are handled differently due to copyin/copyout issues as - well as data-nybbling to/from the card. - */ - -typedef struct wavefront_control { - int cmd; /* WFC_* */ - char status; /* return status to user-space */ - unsigned char rbuf[WF_MAX_READ]; /* bytes read from card */ - unsigned char wbuf[WF_MAX_WRITE]; /* bytes written to card */ -} wavefront_control; - -#define WFCTL_WFCMD 0x1 -#define WFCTL_LOAD_SPP 0x2 - -/* Modulator table */ - -#define WF_MOD_LFO1 0 -#define WF_MOD_LFO2 1 -#define WF_MOD_ENV1 2 -#define WF_MOD_ENV2 3 -#define WF_MOD_KEYBOARD 4 -#define WF_MOD_LOGKEY 5 -#define WF_MOD_VELOCITY 6 -#define WF_MOD_LOGVEL 7 -#define WF_MOD_RANDOM 8 -#define WF_MOD_PRESSURE 9 -#define WF_MOD_MOD_WHEEL 10 -#define WF_MOD_1 WF_MOD_MOD_WHEEL -#define WF_MOD_BREATH 11 -#define WF_MOD_2 WF_MOD_BREATH -#define WF_MOD_FOOT 12 -#define WF_MOD_4 WF_MOD_FOOT -#define WF_MOD_VOLUME 13 -#define WF_MOD_7 WF_MOD_VOLUME -#define WF_MOD_PAN 14 -#define WF_MOD_10 WF_MOD_PAN -#define WF_MOD_EXPR 15 -#define WF_MOD_11 WF_MOD_EXPR - -/* FX-related material */ - -typedef struct wf_fx_info { - int request; /* see list below */ - int data[4]; /* we don't need much */ -} wavefront_fx_info; - -/* support for each of these will be forthcoming once I or someone - else has figured out which of the addresses on page 6 and page 7 of - the YSS225 control each parameter. Incidentally, these come from - the Windows driver interface, but again, Turtle Beach didn't - document the API to use them. -*/ - -#define WFFX_SETOUTGAIN 0 -#define WFFX_SETSTEREOOUTGAIN 1 -#define WFFX_SETREVERBIN1GAIN 2 -#define WFFX_SETREVERBIN2GAIN 3 -#define WFFX_SETREVERBIN3GAIN 4 -#define WFFX_SETCHORUSINPORT 5 -#define WFFX_SETREVERBIN1PORT 6 -#define WFFX_SETREVERBIN2PORT 7 -#define WFFX_SETREVERBIN3PORT 8 -#define WFFX_SETEFFECTPORT 9 -#define WFFX_SETAUXPORT 10 -#define WFFX_SETREVERBTYPE 11 -#define WFFX_SETREVERBDELAY 12 -#define WFFX_SETCHORUSLFO 13 -#define WFFX_SETCHORUSPMD 14 -#define WFFX_SETCHORUSAMD 15 -#define WFFX_SETEFFECT 16 -#define WFFX_SETBASEALL 17 -#define WFFX_SETREVERBALL 18 -#define WFFX_SETCHORUSALL 20 -#define WFFX_SETREVERBDEF 22 -#define WFFX_SETCHORUSDEF 23 -#define WFFX_DELAYSETINGAIN 24 -#define WFFX_DELAYSETFBGAIN 25 -#define WFFX_DELAYSETFBLPF 26 -#define WFFX_DELAYSETGAIN 27 -#define WFFX_DELAYSETTIME 28 -#define WFFX_DELAYSETFBTIME 29 -#define WFFX_DELAYSETALL 30 -#define WFFX_DELAYSETDEF 32 -#define WFFX_SDELAYSETINGAIN 33 -#define WFFX_SDELAYSETFBGAIN 34 -#define WFFX_SDELAYSETFBLPF 35 -#define WFFX_SDELAYSETGAIN 36 -#define WFFX_SDELAYSETTIME 37 -#define WFFX_SDELAYSETFBTIME 38 -#define WFFX_SDELAYSETALL 39 -#define WFFX_SDELAYSETDEF 41 -#define WFFX_DEQSETINGAIN 42 -#define WFFX_DEQSETFILTER 43 -#define WFFX_DEQSETALL 44 -#define WFFX_DEQSETDEF 46 -#define WFFX_MUTE 47 -#define WFFX_FLANGESETBALANCE 48 -#define WFFX_FLANGESETDELAY 49 -#define WFFX_FLANGESETDWFFX_TH 50 -#define WFFX_FLANGESETFBGAIN 51 -#define WFFX_FLANGESETINGAIN 52 -#define WFFX_FLANGESETLFO 53 -#define WFFX_FLANGESETALL 54 -#define WFFX_FLANGESETDEF 56 -#define WFFX_PITCHSETSHIFT 57 -#define WFFX_PITCHSETBALANCE 58 -#define WFFX_PITCHSETALL 59 -#define WFFX_PITCHSETDEF 61 -#define WFFX_SRSSETINGAIN 62 -#define WFFX_SRSSETSPACE 63 -#define WFFX_SRSSETCENTER 64 -#define WFFX_SRSSETGAIN 65 -#define WFFX_SRSSETMODE 66 -#define WFFX_SRSSETDEF 68 - -/* Allow direct user-space control over FX memory/coefficient data. - In theory this could be used to download the FX microprogram, - but it would be a little slower, and involve some weird code. - */ - -#define WFFX_MEMSET 69 - -#endif /* __wavefront_h__ */ diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 86811792002f..8313757b6487 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -15,71 +15,42 @@ obj-$(CONFIG_SOUND_HAL2) += hal2.o obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o -obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o -obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o obj-$(CONFIG_SOUND_MSS) += ad1848.o obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_KAHLUA) += kahlua.o -obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o -obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o obj-$(CONFIG_SOUND_MPU401) += mpu401.o obj-$(CONFIG_SOUND_UART6850) += uart6850.o -obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o obj-$(CONFIG_SOUND_ADLIB) += adlib_card.o opl3.o obj-$(CONFIG_SOUND_YM3812) += opl3.o obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o -obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o obj-$(CONFIG_SOUND_AD1816) += ad1816.o obj-$(CONFIG_SOUND_AD1889) += ad1889.o ac97_codec.o obj-$(CONFIG_SOUND_ACI_MIXER) += aci.o -obj-$(CONFIG_SOUND_AWE32_SYNTH) += awe_wave.o obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o ifeq ($(CONFIG_MIDI_VIA82CXXX),y) obj-$(CONFIG_SOUND_VIA82CXXX) += sound.o uart401.o endif -obj-$(CONFIG_SOUND_YMFPCI) += ymfpci.o ac97_codec.o -ifeq ($(CONFIG_SOUND_YMFPCI_LEGACY),y) - obj-$(CONFIG_SOUND_YMFPCI) += opl3.o uart401.o -endif obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_VWSND) += vwsnd.o obj-$(CONFIG_SOUND_NM256) += nm256_audio.o ac97.o obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o -obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o -obj-$(CONFIG_SOUND_CMPCI) += cmpci.o -ifeq ($(CONFIG_SOUND_CMPCI_FM),y) - obj-$(CONFIG_SOUND_CMPCI) += sound.o opl3.o -endif -ifeq ($(CONFIG_SOUND_CMPCI_MIDI),y) - obj-$(CONFIG_SOUND_CMPCI) += sound.o mpu401.o -endif -obj-$(CONFIG_SOUND_ES1370) += es1370.o obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o obj-$(CONFIG_SOUND_VRC5477) += nec_vrc5477.o ac97_codec.o -obj-$(CONFIG_SOUND_AU1000) += au1000.o ac97_codec.o obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o -obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o -obj-$(CONFIG_SOUND_MAESTRO) += maestro.o -obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o ac97_codec.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o -obj-$(CONFIG_SOUND_HARMONY) += harmony.o obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o -obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o obj-$(CONFIG_SOUND_BT878) += btaudio.o -obj-$(CONFIG_SOUND_ALI5455) += ali5455.o ac97_codec.o -obj-$(CONFIG_SOUND_FORTE) += forte.o ac97_codec.o -obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o ac97_codec.o obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o ifeq ($(CONFIG_MIDI_EMU10K1),y) @@ -87,7 +58,6 @@ ifeq ($(CONFIG_MIDI_EMU10K1),y) endif obj-$(CONFIG_SOUND_EMU10K1) += emu10k1/ -obj-$(CONFIG_SOUND_CS4281) += cs4281/ obj-$(CONFIG_DMASOUND) += dmasound/ # Declare multi-part drivers. @@ -98,17 +68,15 @@ sound-objs := \ midi_syms.o midi_synth.o midibuf.o \ sequencer.o sequencer_syms.o sound_timer.o sys_timer.o -gus-objs := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o sb-objs := sb_card.o sb_lib-objs := sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o vidc_mod-objs := vidc.o vidc_fill.o -wavefront-objs := wavfront.o wf_midi.o yss225.o hostprogs-y := bin2hex hex2hex # Files generated that shall be removed upon make clean -clean-files := maui_boot.h msndperm.c msndinit.c pndsperm.c pndspini.c \ +clean-files := msndperm.c msndinit.c pndsperm.c pndspini.c \ pss_boot.h trix_boot.h # Firmware files that need translation @@ -118,21 +86,6 @@ clean-files := maui_boot.h msndperm.c msndinit.c pndsperm.c pndspini.c \ # will be forced to be remade. # -# Turtle Beach Maui / Tropez - -$(obj)/maui.o: $(obj)/maui_boot.h - -ifeq ($(CONFIG_MAUI_HAVE_BOOT),y) - $(obj)/maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) $(obj)/bin2hex - $(obj)/bin2hex -i maui_os < $< > $@ -else - $(obj)/maui_boot.h: - ( \ - echo 'static unsigned char * maui_os = NULL;'; \ - echo 'static int maui_osLen = 0;'; \ - ) > $@ -endif - # Turtle Beach MultiSound ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y) diff --git a/sound/oss/ac97.c b/sound/oss/ac97.c index 3ba6d91e891d..72cf4ed77937 100644 --- a/sound/oss/ac97.c +++ b/sound/oss/ac97.c @@ -112,25 +112,6 @@ ac97_init (struct ac97_hwint *dev) return 0; } -/* Reset the mixer to the currently saved settings. */ -int -ac97_reset (struct ac97_hwint *dev) -{ - int x; - - if (dev->reset_device (dev)) - return -1; - - /* Now set the registers back to their last-written values. */ - for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) { - int regnum = mixerRegs[x].ac97_regnum; - int value = dev->last_written_mixer_values [regnum / 2]; - if (value >= 0) - ac97_put_register (dev, regnum, value); - } - return 0; -} - /* Return the contents of register REG; use the cache if the value in it is valid. Returns a negative error code on failure. */ static int @@ -441,7 +422,6 @@ EXPORT_SYMBOL(ac97_init); EXPORT_SYMBOL(ac97_set_values); EXPORT_SYMBOL(ac97_put_register); EXPORT_SYMBOL(ac97_mixer_ioctl); -EXPORT_SYMBOL(ac97_reset); MODULE_LICENSE("GPL"); diff --git a/sound/oss/ac97.h b/sound/oss/ac97.h index 77d454ea3202..01837a9d7d6e 100644 --- a/sound/oss/ac97.h +++ b/sound/oss/ac97.h @@ -192,9 +192,6 @@ extern int ac97_put_register (struct ac97_hwint *dev, u8 reg, u16 value); extern int ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd, void __user * arg); -/* Do a complete reset on the AC97 mixer, restoring all mixer registers to - the current values. Normally used after an APM resume event. */ -extern int ac97_reset (struct ac97_hwint *dev); #endif /* diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c index 972327c97644..602db497929a 100644 --- a/sound/oss/ac97_codec.c +++ b/sound/oss/ac97_codec.c @@ -1399,95 +1399,6 @@ unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate) EXPORT_SYMBOL(ac97_set_adc_rate); -int ac97_save_state(struct ac97_codec *codec) -{ - return 0; -} - -EXPORT_SYMBOL(ac97_save_state); - -int ac97_restore_state(struct ac97_codec *codec) -{ - int i; - unsigned int left, right, val; - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (!supported_mixer(codec, i)) - continue; - - val = codec->mixer_state[i]; - right = val >> 8; - left = val & 0xff; - codec->write_mixer(codec, i, left, right); - } - return 0; -} - -EXPORT_SYMBOL(ac97_restore_state); - -/** - * ac97_register_driver - register a codec helper - * @driver: Driver handler - * - * Register a handler for codecs matching the codec id. The handler - * attach function is called for all present codecs and will be - * called when new codecs are discovered. - */ - -int ac97_register_driver(struct ac97_driver *driver) -{ - struct list_head *l; - struct ac97_codec *c; - - mutex_lock(&codec_mutex); - INIT_LIST_HEAD(&driver->list); - list_add(&driver->list, &codec_drivers); - - list_for_each(l, &codecs) - { - c = list_entry(l, struct ac97_codec, list); - if(c->driver != NULL || ((c->model ^ driver->codec_id) & driver->codec_mask)) - continue; - if(driver->probe(c, driver)) - continue; - c->driver = driver; - } - mutex_unlock(&codec_mutex); - return 0; -} - -EXPORT_SYMBOL_GPL(ac97_register_driver); - -/** - * ac97_unregister_driver - unregister a codec helper - * @driver: Driver handler - * - * Unregister a handler for codecs matching the codec id. The handler - * remove function is called for all matching codecs. - */ - -void ac97_unregister_driver(struct ac97_driver *driver) -{ - struct list_head *l; - struct ac97_codec *c; - - mutex_lock(&codec_mutex); - list_del_init(&driver->list); - - list_for_each(l, &codecs) - { - c = list_entry(l, struct ac97_codec, list); - if (c->driver == driver) { - driver->remove(c, driver); - c->driver = NULL; - } - } - - mutex_unlock(&codec_mutex); -} - -EXPORT_SYMBOL_GPL(ac97_unregister_driver); - static int swap_headphone(int remove_master) { struct list_head *l; diff --git a/sound/oss/ac97_plugin_ad1980.c b/sound/oss/ac97_plugin_ad1980.c deleted file mode 100644 index 24a9acd28160..000000000000 --- a/sound/oss/ac97_plugin_ad1980.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - ac97_plugin_ad1980.c Copyright (C) 2003 Red Hat, Inc. All rights reserved. - - The contents of this file are subject to the Open Software License version 1.1 - that can be found at http://www.opensource.org/licenses/osl-1.1.txt and is - included herein by reference. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL") as - distributed in the kernel source COPYING file, in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the OSL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the OSL or the GPL. - - Authors: Alan Cox - - This is an example codec plugin. This one switches the connections - around to match the setups some vendors use with audio switched to - non standard front connectors not the normal rear ones - - This code primarily exists to demonstrate how to use the codec - interface - -*/ - -#include -#include -#include -#include -#include - -/** - * ad1980_remove - codec remove callback - * @codec: The codec that is being removed - * - * This callback occurs when an AC97 codec is being removed. A - * codec remove call will not occur for a codec during that codec - * probe callback. - * - * Most drivers will need to lock their remove versus their - * use of the codec after the probe function. - */ - -static void __devexit ad1980_remove(struct ac97_codec *codec, struct ac97_driver *driver) -{ - /* Nothing to do in the simple example */ -} - - -/** - * ad1980_probe - codec found callback - * @codec: ac97 codec matching the idents - * @driver: ac97_driver it matched - * - * This entry point is called when a codec is found which matches - * the driver. At the point it is called the codec is basically - * operational, mixer operations have been initialised and can - * be overriden. Called in process context. The field driver_private - * is available for the driver to use to store stuff. - * - * The caller can claim the device by returning zero, or return - * a negative error code. - */ - -static int ad1980_probe(struct ac97_codec *codec, struct ac97_driver *driver) -{ - u16 control; - -#define AC97_AD_MISC 0x76 - - /* Switch the inputs/outputs over (from Dell code) */ - control = codec->codec_read(codec, AC97_AD_MISC); - codec->codec_write(codec, AC97_AD_MISC, control | 0x4420); - - /* We could refuse the device since we dont need to hang around, - but we will claim it */ - return 0; -} - - -static struct ac97_driver ad1980_driver = { - .codec_id = 0x41445370, - .codec_mask = 0xFFFFFFFF, - .name = "AD1980 example", - .probe = ad1980_probe, - .remove = __devexit_p(ad1980_remove), -}; - -/** - * ad1980_exit - module exit path - * - * Our module is being unloaded. At this point unregister_driver - * will call back our remove handler for any existing codecs. You - * may not unregister_driver from interrupt context or from a - * probe/remove callback. - */ - -static void ad1980_exit(void) -{ - ac97_unregister_driver(&ad1980_driver); -} - -/** - * ad1980_init - set up ad1980 handlers - * - * After we call the register function it will call our probe - * function for each existing matching device before returning to us. - * Any devices appearing afterwards whose id's match the codec_id - * will also cause the probe function to be called. - * You may not register_driver from interrupt context or from a - * probe/remove callback. - */ - -static int ad1980_init(void) -{ - return ac97_register_driver(&ad1980_driver); -} - -module_init(ad1980_init); -module_exit(ad1980_exit); -MODULE_LICENSE("GPL"); diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c index f6b6b886c2ad..257b7536fb18 100644 --- a/sound/oss/ad1848.c +++ b/sound/oss/ad1848.c @@ -195,6 +195,7 @@ static void ad1848_halt(int dev); static void ad1848_halt_input(int dev); static void ad1848_halt_output(int dev); static void ad1848_trigger(int dev, int bits); +static irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy); #ifndef EXCLUDE_TIMERS static int ad1848_tmr_install(int dev); @@ -2195,7 +2196,7 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base); } -irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy) +static irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy) { unsigned char status; ad1848_info *devc; @@ -2802,7 +2803,6 @@ EXPORT_SYMBOL(ad1848_detect); EXPORT_SYMBOL(ad1848_init); EXPORT_SYMBOL(ad1848_unload); EXPORT_SYMBOL(ad1848_control); -EXPORT_SYMBOL(adintr); EXPORT_SYMBOL(probe_ms_sound); EXPORT_SYMBOL(attach_ms_sound); EXPORT_SYMBOL(unload_ms_sound); diff --git a/sound/oss/ad1848.h b/sound/oss/ad1848.h index d0573b023973..b95ebe28d426 100644 --- a/sound/oss/ad1848.h +++ b/sound/oss/ad1848.h @@ -18,7 +18,6 @@ void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int int ad1848_detect (struct resource *ports, int *flags, int *osp); int ad1848_control(int cmd, int arg); -irqreturn_t adintr(int irq, void *dev_id, struct pt_regs * dummy); void attach_ms_sound(struct address_info * hw_config, struct resource *ports, struct module * owner); int probe_ms_sound(struct address_info *hw_config, struct resource *ports); diff --git a/sound/oss/ali5455.c b/sound/oss/ali5455.c deleted file mode 100644 index 70dcd703a66f..000000000000 --- a/sound/oss/ali5455.c +++ /dev/null @@ -1,3735 +0,0 @@ -/* - * ALI ali5455 and friends ICH driver for Linux - * LEI HU - * - * Built from: - * drivers/sound/i810_audio - * - * The ALi 5455 is similar but not quite identical to the Intel ICH - * series of controllers. Its easier to keep the driver separated from - * the i810 driver. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * ALi 5455 theory of operation - * - * The chipset provides three DMA channels that talk to an AC97 - * CODEC (AC97 is a digital/analog mixer standard). At its simplest - * you get 48Khz audio with basic volume and mixer controls. At the - * best you get rate adaption in the codec. We set the card up so - * that we never take completion interrupts but instead keep the card - * chasing its tail around a ring buffer. This is needed for mmap - * mode audio and happens to work rather well for non-mmap modes too. - * - * The board has one output channel for PCM audio (supported) and - * a stereo line in and mono microphone input. Again these are normally - * locked to 48Khz only. Right now recording is not finished. - * - * There is no midi support, no synth support. Use timidity. To get - * esd working you need to use esd -r 48000 as it won't probe 48KHz - * by default. mpg123 can't handle 48Khz only audio so use xmms. - * - * If you need to force a specific rate set the clocking= option - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifndef PCI_DEVICE_ID_ALI_5455 -#define PCI_DEVICE_ID_ALI_5455 0x5455 -#endif - -#ifndef PCI_VENDOR_ID_ALI -#define PCI_VENDOR_ID_ALI 0x10b9 -#endif - -static int strict_clocking = 0; -static unsigned int clocking = 0; -static unsigned int codec_pcmout_share_spdif_locked = 0; -static unsigned int codec_independent_spdif_locked = 0; -static unsigned int controller_pcmout_share_spdif_locked = 0; -static unsigned int controller_independent_spdif_locked = 0; -static unsigned int globel = 0; - -#define ADC_RUNNING 1 -#define DAC_RUNNING 2 -#define CODEC_SPDIFOUT_RUNNING 8 -#define CONTROLLER_SPDIFOUT_RUNNING 4 - -#define SPDIF_ENABLE_OUTPUT 4 /* bits 0,1 are PCM */ - -#define ALI5455_FMT_16BIT 1 -#define ALI5455_FMT_STEREO 2 -#define ALI5455_FMT_MASK 3 - -#define SPDIF_ON 0x0004 -#define SURR_ON 0x0010 -#define CENTER_LFE_ON 0x0020 -#define VOL_MUTED 0x8000 - - -#define ALI_SPDIF_OUT_CH_STATUS 0xbf -/* the 810's array of pointers to data buffers */ - -struct sg_item { -#define BUSADDR_MASK 0xFFFFFFFE - u32 busaddr; -#define CON_IOC 0x80000000 /* interrupt on completion */ -#define CON_BUFPAD 0x40000000 /* pad underrun with last sample, else 0 */ -#define CON_BUFLEN_MASK 0x0000ffff /* buffer length in samples */ - u32 control; -}; - -/* an instance of the ali channel */ -#define SG_LEN 32 -struct ali_channel { - /* these sg guys should probably be allocated - separately as nocache. Must be 8 byte aligned */ - struct sg_item sg[SG_LEN]; /* 32*8 */ - u32 offset; /* 4 */ - u32 port; /* 4 */ - u32 used; - u32 num; -}; - -/* - * we have 3 separate dma engines. pcm in, pcm out, and mic. - * each dma engine has controlling registers. These goofy - * names are from the datasheet, but make it easy to write - * code while leafing through it. - */ - -#define ENUM_ENGINE(PRE,DIG) \ -enum { \ - PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \ - PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \ - PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \ - PRE##_SR = 0x##DIG##6, /* Status Register */ \ - PRE##_PICB = 0x##DIG##8, /* Position In Current Buffer */ \ - PRE##_CR = 0x##DIG##b /* Control Register */ \ -} - -ENUM_ENGINE(OFF, 0); /* Offsets */ -ENUM_ENGINE(PI, 4); /* PCM In */ -ENUM_ENGINE(PO, 5); /* PCM Out */ -ENUM_ENGINE(MC, 6); /* Mic In */ -ENUM_ENGINE(CODECSPDIFOUT, 7); /* CODEC SPDIF OUT */ -ENUM_ENGINE(CONTROLLERSPDIFIN, A); /* CONTROLLER SPDIF In */ -ENUM_ENGINE(CONTROLLERSPDIFOUT, B); /* CONTROLLER SPDIF OUT */ - - -enum { - ALI_SCR = 0x00, /* System Control Register */ - ALI_SSR = 0x04, /* System Status Register */ - ALI_DMACR = 0x08, /* DMA Control Register */ - ALI_FIFOCR1 = 0x0c, /* FIFO Control Register 1 */ - ALI_INTERFACECR = 0x10, /* Interface Control Register */ - ALI_INTERRUPTCR = 0x14, /* Interrupt control Register */ - ALI_INTERRUPTSR = 0x18, /* Interrupt Status Register */ - ALI_FIFOCR2 = 0x1c, /* FIFO Control Register 2 */ - ALI_CPR = 0x20, /* Command Port Register */ - ALI_SPR = 0x24, /* Status Port Register */ - ALI_FIFOCR3 = 0x2c, /* FIFO Control Register 3 */ - ALI_TTSR = 0x30, /* Transmit Tag Slot Register */ - ALI_RTSR = 0x34, /* Receive Tag Slot Register */ - ALI_CSPSR = 0x38, /* Command/Status Port Status Register */ - ALI_CAS = 0x3c, /* Codec Write Semaphore Register */ - ALI_SPDIFCSR = 0xf8, /* spdif channel status register */ - ALI_SPDIFICS = 0xfc /* spdif interface control/status */ -}; - -// x-status register(x:pcm in ,pcm out, mic in,) -/* interrupts for a dma engine */ -#define DMA_INT_FIFO (1<<4) /* fifo under/over flow */ -#define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */ -#define DMA_INT_LVI (1<<2) /* last valid done */ -#define DMA_INT_CELV (1<<1) /* last valid is current */ -#define DMA_INT_DCH (1) /* DMA Controller Halted (happens on LVI interrupts) */ //not eqult intel -#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI) - -/* interrupts for the whole chip */// by interrupt status register finish - -#define INT_SPDIFOUT (1<<23) /* controller spdif out INTERRUPT */ -#define INT_SPDIFIN (1<<22) -#define INT_CODECSPDIFOUT (1<<19) -#define INT_MICIN (1<<18) -#define INT_PCMOUT (1<<17) -#define INT_PCMIN (1<<16) -#define INT_CPRAIS (1<<7) -#define INT_SPRAIS (1<<5) -#define INT_GPIO (1<<1) -#define INT_MASK (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN) - -#define DRIVER_VERSION "0.02ac" - -/* magic numbers to protect our data structures */ -#define ALI5455_CARD_MAGIC 0x5072696E /* "Prin" */ -#define ALI5455_STATE_MAGIC 0x63657373 /* "cess" */ -#define ALI5455_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */ -#define NR_HW_CH 5 //I think 5 channel - -/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ -#define NR_AC97 2 - -/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */ -/* stream at a minimum for this card to be happy */ -static const unsigned sample_size[] = { 1, 2, 2, 4 }; -/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */ -/* values are one less than might be expected */ -static const unsigned sample_shift[] = { -1, 0, 0, 1 }; - -#define ALI5455 -static char *card_names[] = { - "ALI 5455" -}; - -static struct pci_device_id ali_pci_tbl[] = { - {PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, ali_pci_tbl); - -#ifdef CONFIG_PM -#define PM_SUSPENDED(card) (card->pm_suspended) -#else -#define PM_SUSPENDED(card) (0) -#endif - -/* "software" or virtual channel, an instance of opened /dev/dsp */ -struct ali_state { - unsigned int magic; - struct ali_card *card; /* Card info */ - - /* single open lock mechanism, only used for recording */ - struct mutex open_mutex; - wait_queue_head_t open_wait; - - /* file mode */ - mode_t open_mode; - - /* virtual channel number */ - int virt; - -#ifdef CONFIG_PM - unsigned int pm_saved_dac_rate, pm_saved_adc_rate; -#endif - struct dmabuf { - /* wave sample stuff */ - unsigned int rate; - unsigned char fmt, enable, trigger; - - /* hardware channel */ - struct ali_channel *read_channel; - struct ali_channel *write_channel; - struct ali_channel *codec_spdifout_channel; - struct ali_channel *controller_spdifout_channel; - - /* OSS buffer management stuff */ - void *rawbuf; - dma_addr_t dma_handle; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - - /* our buffer acts like a circular ring */ - unsigned hwptr; /* where dma last started, updated by update_ptr */ - unsigned swptr; /* where driver last clear/filled, updated by read/write */ - int count; /* bytes to be consumed or been generated by dma machine */ - unsigned total_bytes; /* total bytes dmaed by hardware */ - - unsigned error; /* number of over/underruns */ - wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */ - - /* redundant, but makes calculations easier */ - /* what the hardware uses */ - unsigned dmasize; - unsigned fragsize; - unsigned fragsamples; - - /* what we tell the user to expect */ - unsigned userfrags; - unsigned userfragsize; - - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned update_flag; - unsigned ossfragsize; - unsigned ossmaxfrags; - unsigned subdivision; - } dmabuf; -}; - - -struct ali_card { - struct ali_channel channel[5]; - unsigned int magic; - - /* We keep ali5455 cards in a linked list */ - struct ali_card *next; - - /* The ali has a certain amount of cross channel interaction - so we use a single per card lock */ - spinlock_t lock; - spinlock_t ac97_lock; - - /* PCI device stuff */ - struct pci_dev *pci_dev; - u16 pci_id; -#ifdef CONFIG_PM - u16 pm_suspended; - int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97]; -#endif - /* soundcore stuff */ - int dev_audio; - - /* structures for abstraction of hardware facilities, codecs, banks and channels */ - struct ac97_codec *ac97_codec[NR_AC97]; - struct ali_state *states[NR_HW_CH]; - - u16 ac97_features; - u16 ac97_status; - u16 channels; - - /* hardware resources */ - unsigned long iobase; - - u32 irq; - - /* Function support */ - struct ali_channel *(*alloc_pcm_channel) (struct ali_card *); - struct ali_channel *(*alloc_rec_pcm_channel) (struct ali_card *); - struct ali_channel *(*alloc_rec_mic_channel) (struct ali_card *); - struct ali_channel *(*alloc_codec_spdifout_channel) (struct ali_card *); - struct ali_channel *(*alloc_controller_spdifout_channel) (struct ali_card *); - void (*free_pcm_channel) (struct ali_card *, int chan); - - /* We have a *very* long init time possibly, so use this to block */ - /* attempts to open our devices before we are ready (stops oops'es) */ - int initializing; -}; - - -static struct ali_card *devs = NULL; - -static int ali_open_mixdev(struct inode *inode, struct file *file); -static int ali_ioctl_mixdev(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg); -static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data); - -static struct ali_channel *ali_alloc_pcm_channel(struct ali_card *card) -{ - if (card->channel[1].used == 1) - return NULL; - card->channel[1].used = 1; - return &card->channel[1]; -} - -static struct ali_channel *ali_alloc_rec_pcm_channel(struct ali_card *card) -{ - if (card->channel[0].used == 1) - return NULL; - card->channel[0].used = 1; - return &card->channel[0]; -} - -static struct ali_channel *ali_alloc_rec_mic_channel(struct ali_card *card) -{ - if (card->channel[2].used == 1) - return NULL; - card->channel[2].used = 1; - return &card->channel[2]; -} - -static struct ali_channel *ali_alloc_codec_spdifout_channel(struct ali_card *card) -{ - if (card->channel[3].used == 1) - return NULL; - card->channel[3].used = 1; - return &card->channel[3]; -} - -static struct ali_channel *ali_alloc_controller_spdifout_channel(struct ali_card *card) -{ - if (card->channel[4].used == 1) - return NULL; - card->channel[4].used = 1; - return &card->channel[4]; -} -static void ali_free_pcm_channel(struct ali_card *card, int channel) -{ - card->channel[channel].used = 0; -} - - -//add support codec spdif out -static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate) -{ - unsigned long id = 0L; - - id = (ali_ac97_get(codec, AC97_VENDOR_ID1) << 16); - id |= ali_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff; - switch (id) { - case 0x41445361: /* AD1886 */ - if (rate == 48000) { - return 1; - } - break; - case 0x414c4720: /* ALC650 */ - if (rate == 48000) { - return 1; - } - break; - default: /* all other codecs, until we know otherwiae */ - if (rate == 48000 || rate == 44100 || rate == 32000) { - return 1; - } - break; - } - return (0); -} - -/* ali_set_spdif_output - * - * Configure the S/PDIF output transmitter. When we turn on - * S/PDIF, we turn off the analog output. This may not be - * the right thing to do. - * - * Assumptions: - * The DSP sample rate must already be set to a supported - * S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort. - */ -static void ali_set_spdif_output(struct ali_state *state, int slots, - int rate) -{ - int vol; - int aud_reg; - struct ac97_codec *codec = state->card->ac97_codec[0]; - - if (!(state->card->ac97_features & 4)) { - state->card->ac97_status &= ~SPDIF_ON; - } else { - if (slots == -1) { /* Turn off S/PDIF */ - aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); - ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF)); - - /* If the volume wasn't muted before we turned on S/PDIF, unmute it */ - if (!(state->card->ac97_status & VOL_MUTED)) { - aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO); - ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, - (aud_reg & ~VOL_MUTED)); - } - state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON); - return; - } - - vol = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO); - state->card->ac97_status = vol & VOL_MUTED; - - /* Set S/PDIF transmitter sample rate */ - aud_reg = ali_ac97_get(codec, AC97_SPDIF_CONTROL); - switch (rate) { - case 32000: - aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K; - break; - case 44100: - aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K; - break; - case 48000: - aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K; - break; - default: - /* turn off S/PDIF */ - aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); - ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF)); - state->card->ac97_status &= ~SPDIF_ON; - return; - } - - ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg); - - aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); - aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF; - ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg); - - aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL); - aud_reg |= 0x0002; - ali_ac97_set(codec, AC97_POWER_CONTROL, aud_reg); - udelay(1); - - state->card->ac97_status |= SPDIF_ON; - - /* Check to make sure the configuration is valid */ - aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); - if (!(aud_reg & 0x0400)) { - /* turn off S/PDIF */ - ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF)); - state->card->ac97_status &= ~SPDIF_ON; - return; - } - if (codec_independent_spdif_locked > 0) { - aud_reg = ali_ac97_get(codec, 0x6a); - ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff)); - } - /* Mute the analog output */ - /* Should this only mute the PCM volume??? */ - } -} - -/* ali_set_dac_channels - * - * Configure the codec's multi-channel DACs - * - * The logic is backwards. Setting the bit to 1 turns off the DAC. - * - * What about the ICH? We currently configure it using the - * SNDCTL_DSP_CHANNELS ioctl. If we're turnning on the DAC, - * does that imply that we want the ICH set to support - * these channels? - * - * TODO: - * vailidate that the codec really supports these DACs - * before turning them on. - */ -static void ali_set_dac_channels(struct ali_state *state, int channel) -{ - int aud_reg; - struct ac97_codec *codec = state->card->ac97_codec[0]; - - aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); - aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK; - state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON); - - switch (channel) { - case 2: /* always enabled */ - break; - case 4: - aud_reg &= ~AC97_EA_PRJ; - state->card->ac97_status |= SURR_ON; - break; - case 6: - aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK); - state->card->ac97_status |= SURR_ON | CENTER_LFE_ON; - break; - default: - break; - } - ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg); - -} - -/* set playback sample rate */ -static unsigned int ali_set_dac_rate(struct ali_state *state, - unsigned int rate) -{ - struct dmabuf *dmabuf = &state->dmabuf; - u32 new_rate; - struct ac97_codec *codec = state->card->ac97_codec[0]; - - if (!(state->card->ac97_features & 0x0001)) { - dmabuf->rate = clocking; - return clocking; - } - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - dmabuf->rate = rate; - - /* - * Adjust for misclocked crap - */ - - rate = (rate * clocking) / 48000; - - if (strict_clocking && rate < 8000) { - rate = 8000; - dmabuf->rate = (rate * 48000) / clocking; - } - - new_rate = ac97_set_dac_rate(codec, rate); - if (new_rate != rate) { - dmabuf->rate = (new_rate * 48000) / clocking; - } - rate = new_rate; - return dmabuf->rate; -} - -/* set recording sample rate */ -static unsigned int ali_set_adc_rate(struct ali_state *state, - unsigned int rate) -{ - struct dmabuf *dmabuf = &state->dmabuf; - u32 new_rate; - struct ac97_codec *codec = state->card->ac97_codec[0]; - - if (!(state->card->ac97_features & 0x0001)) { - dmabuf->rate = clocking; - return clocking; - } - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - dmabuf->rate = rate; - - /* - * Adjust for misclocked crap - */ - - rate = (rate * clocking) / 48000; - if (strict_clocking && rate < 8000) { - rate = 8000; - dmabuf->rate = (rate * 48000) / clocking; - } - - new_rate = ac97_set_adc_rate(codec, rate); - - if (new_rate != rate) { - dmabuf->rate = (new_rate * 48000) / clocking; - rate = new_rate; - } - return dmabuf->rate; -} - -/* set codec independent spdifout sample rate */ -static unsigned int ali_set_codecspdifout_rate(struct ali_state *state, - unsigned int rate) -{ - struct dmabuf *dmabuf = &state->dmabuf; - - if (!(state->card->ac97_features & 0x0001)) { - dmabuf->rate = clocking; - return clocking; - } - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - dmabuf->rate = rate; - - return dmabuf->rate; -} - -/* set controller independent spdif out function sample rate */ -static void ali_set_spdifout_rate(struct ali_state *state, - unsigned int rate) -{ - unsigned char ch_st_sel; - unsigned short status_rate; - - switch (rate) { - case 44100: - status_rate = 0; - break; - case 32000: - status_rate = 0x300; - break; - case 48000: - default: - status_rate = 0x200; - break; - } - - ch_st_sel = inb(state->card->iobase + ALI_SPDIFICS) & ALI_SPDIF_OUT_CH_STATUS; //select spdif_out - - ch_st_sel |= 0x80; //select right - outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS)); - outb(status_rate | 0x20, (state->card->iobase + ALI_SPDIFCSR + 2)); - - ch_st_sel &= (~0x80); //select left - outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS)); - outw(status_rate | 0x10, (state->card->iobase + ALI_SPDIFCSR + 2)); -} - -/* get current playback/recording dma buffer pointer (byte offset from LBA), - called with spinlock held! */ - -static inline unsigned ali_get_dma_addr(struct ali_state *state, int rec) -{ - struct dmabuf *dmabuf = &state->dmabuf; - unsigned int civ, offset, port, port_picb; - unsigned int data; - - if (!dmabuf->enable) - return 0; - - if (rec == 1) - port = state->card->iobase + dmabuf->read_channel->port; - else if (rec == 2) - port = state->card->iobase + dmabuf->codec_spdifout_channel->port; - else if (rec == 3) - port = state->card->iobase + dmabuf->controller_spdifout_channel->port; - else - port = state->card->iobase + dmabuf->write_channel->port; - - port_picb = port + OFF_PICB; - - do { - civ = inb(port + OFF_CIV) & 31; - offset = inw(port_picb); - /* Must have a delay here! */ - if (offset == 0) - udelay(1); - - /* Reread both registers and make sure that that total - * offset from the first reading to the second is 0. - * There is an issue with SiS hardware where it will count - * picb down to 0, then update civ to the next value, - * then set the new picb to fragsize bytes. We can catch - * it between the civ update and the picb update, making - * it look as though we are 1 fragsize ahead of where we - * are. The next to we get the address though, it will - * be back in thdelay is more than long enough - * that we won't have to worry about the chip still being - * out of sync with reality ;-) - */ - } while (civ != (inb(port + OFF_CIV) & 31) || offset != inw(port_picb)); - - data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize; - if (inw(port_picb) == 0) - data -= 2048; - - return data; -} - -/* Stop recording (lock held) */ -static inline void __stop_adc(struct ali_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct ali_card *card = state->card; - - dmabuf->enable &= ~ADC_RUNNING; - - outl((1 << 18) | (1 << 16), card->iobase + ALI_DMACR); - udelay(1); - - outb(0, card->iobase + PI_CR); - while (inb(card->iobase + PI_CR) != 0); - - // now clear any latent interrupt bits (like the halt bit) - outb(inb(card->iobase + PI_SR) | 0x001e, card->iobase + PI_SR); - outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMIN, card->iobase + ALI_INTERRUPTSR); -} - -static void stop_adc(struct ali_state *state) -{ - struct ali_card *card = state->card; - unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - __stop_adc(state); - spin_unlock_irqrestore(&card->lock, flags); -} - -static inline void __start_adc(struct ali_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - - if (dmabuf->count < dmabuf->dmasize && dmabuf->ready - && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_INPUT)) { - dmabuf->enable |= ADC_RUNNING; - outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR); - if (state->card->channel[0].used == 1) - outl(1, state->card->iobase + ALI_DMACR); // DMA CONTROL REGISTRER - udelay(100); - if (state->card->channel[2].used == 1) - outl((1 << 2), state->card->iobase + ALI_DMACR); //DMA CONTROL REGISTER - udelay(100); - } -} - -static void start_adc(struct ali_state *state) -{ - struct ali_card *card = state->card; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - __start_adc(state); - spin_unlock_irqrestore(&card->lock, flags); -} - -/* stop playback (lock held) */ -static inline void __stop_dac(struct ali_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct ali_card *card = state->card; - - dmabuf->enable &= ~DAC_RUNNING; - outl(0x00020000, card->iobase + 0x08); - outb(0, card->iobase + PO_CR); - while (inb(card->iobase + PO_CR) != 0) - cpu_relax(); - - outb(inb(card->iobase + PO_SR) | 0x001e, card->iobase + PO_SR); - - outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMOUT, card->iobase + ALI_INTERRUPTSR); -} - -static void stop_dac(struct ali_state *state) -{ - struct ali_card *card = state->card; - unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - __stop_dac(state); - spin_unlock_irqrestore(&card->lock, flags); -} - -static inline void __start_dac(struct ali_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable && - (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { - dmabuf->enable |= DAC_RUNNING; - outb((1 << 4) | (1 << 2), state->card->iobase + PO_CR); - outl((1 << 1), state->card->iobase + 0x08); //dma control register - } -} - -static void start_dac(struct ali_state *state) -{ - struct ali_card *card = state->card; - unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - __start_dac(state); - spin_unlock_irqrestore(&card->lock, flags); -} - -/* stop codec and controller spdif out (lock held) */ -static inline void __stop_spdifout(struct ali_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct ali_card *card = state->card; - - if (codec_independent_spdif_locked > 0) { - dmabuf->enable &= ~CODEC_SPDIFOUT_RUNNING; - outl((1 << 19), card->iobase + 0x08); - outb(0, card->iobase + CODECSPDIFOUT_CR); - - while (inb(card->iobase + CODECSPDIFOUT_CR) != 0) - cpu_relax(); - - outb(inb(card->iobase + CODECSPDIFOUT_SR) | 0x001e, card->iobase + CODECSPDIFOUT_SR); - outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_CODECSPDIFOUT, card->iobase + ALI_INTERRUPTSR); - } else { - if (controller_independent_spdif_locked > 0) { - dmabuf->enable &= ~CONTROLLER_SPDIFOUT_RUNNING; - outl((1 << 23), card->iobase + 0x08); - outb(0, card->iobase + CONTROLLERSPDIFOUT_CR); - while (inb(card->iobase + CONTROLLERSPDIFOUT_CR) != 0) - cpu_relax(); - outb(inb(card->iobase + CONTROLLERSPDIFOUT_SR) | 0x001e, card->iobase + CONTROLLERSPDIFOUT_SR); - outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_SPDIFOUT, card->iobase + ALI_INTERRUPTSR); - } - } -} - -static void stop_spdifout(struct ali_state *state) -{ - struct ali_card *card = state->card; - unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - __stop_spdifout(state); - spin_unlock_irqrestore(&card->lock, flags); -} - -static inline void __start_spdifout(struct ali_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable && - (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) { - if (codec_independent_spdif_locked > 0) { - dmabuf->enable |= CODEC_SPDIFOUT_RUNNING; - outb((1 << 4) | (1 << 2), state->card->iobase + CODECSPDIFOUT_CR); - outl((1 << 3), state->card->iobase + 0x08); //dma control register - } else { - if (controller_independent_spdif_locked > 0) { - dmabuf->enable |= CONTROLLER_SPDIFOUT_RUNNING; - outb((1 << 4) | (1 << 2), state->card->iobase + CONTROLLERSPDIFOUT_CR); - outl((1 << 7), state->card->iobase + 0x08); //dma control register - } - } - } -} - -static void start_spdifout(struct ali_state *state) -{ - struct ali_card *card = state->card; - unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - __start_spdifout(state); - spin_unlock_irqrestore(&card->lock, flags); -} - -#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - -/* allocate DMA buffer, playback , recording,spdif out buffer should be allocated separately */ -static int alloc_dmabuf(struct ali_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - void *rawbuf = NULL; - int order, size; - struct page *page, *pend; - - /* If we don't have any oss frag params, then use our default ones */ - if (dmabuf->ossmaxfrags == 0) - dmabuf->ossmaxfrags = 4; - if (dmabuf->ossfragsize == 0) - dmabuf->ossfragsize = (PAGE_SIZE << DMABUF_DEFAULTORDER) / dmabuf->ossmaxfrags; - size = dmabuf->ossfragsize * dmabuf->ossmaxfrags; - - if (dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size) - return 0; - /* alloc enough to satisfy the oss params */ - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) { - if ((PAGE_SIZE << order) > size) - continue; - if ((rawbuf = pci_alloc_consistent(state->card->pci_dev, - PAGE_SIZE << order, - &dmabuf->dma_handle))) - break; - } - if (!rawbuf) - return -ENOMEM; - - dmabuf->ready = dmabuf->mapped = 0; - dmabuf->rawbuf = rawbuf; - dmabuf->buforder = order; - - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(rawbuf); page <= pend; page++) - SetPageReserved(page); - return 0; -} - -/* free DMA buffer */ -static void dealloc_dmabuf(struct ali_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct page *page, *pend; - - if (dmabuf->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); - for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++) - ClearPageReserved(page); - pci_free_consistent(state->card->pci_dev, - PAGE_SIZE << dmabuf->buforder, - dmabuf->rawbuf, dmabuf->dma_handle); - } - dmabuf->rawbuf = NULL; - dmabuf->mapped = dmabuf->ready = 0; -} - -static int prog_dmabuf(struct ali_state *state, unsigned rec) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct ali_channel *c = NULL; - struct sg_item *sg; - unsigned long flags; - int ret; - unsigned fragint; - int i; - - spin_lock_irqsave(&state->card->lock, flags); - if (dmabuf->enable & DAC_RUNNING) - __stop_dac(state); - if (dmabuf->enable & ADC_RUNNING) - __stop_adc(state); - if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) - __stop_spdifout(state); - if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) - __stop_spdifout(state); - - dmabuf->total_bytes = 0; - dmabuf->count = dmabuf->error = 0; - dmabuf->swptr = dmabuf->hwptr = 0; - spin_unlock_irqrestore(&state->card->lock, flags); - - /* allocate DMA buffer, let alloc_dmabuf determine if we are already - * allocated well enough or if we should replace the current buffer - * (assuming one is already allocated, if it isn't, then allocate it). - */ - if ((ret = alloc_dmabuf(state))) - return ret; - - /* FIXME: figure out all this OSS fragment stuff */ - /* I did, it now does what it should according to the OSS API. DL */ - /* We may not have realloced our dmabuf, but the fragment size to - * fragment number ratio may have changed, so go ahead and reprogram - * things - */ - - dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder; - dmabuf->numfrag = SG_LEN; - dmabuf->fragsize = dmabuf->dmasize / dmabuf->numfrag; - dmabuf->fragsamples = dmabuf->fragsize >> 1; - dmabuf->userfragsize = dmabuf->ossfragsize; - dmabuf->userfrags = dmabuf->dmasize / dmabuf->ossfragsize; - - memset(dmabuf->rawbuf, 0, dmabuf->dmasize); - - if (dmabuf->ossmaxfrags == 4) { - fragint = 8; - dmabuf->fragshift = 2; - } else if (dmabuf->ossmaxfrags == 8) { - fragint = 4; - dmabuf->fragshift = 3; - } else if (dmabuf->ossmaxfrags == 16) { - fragint = 2; - dmabuf->fragshift = 4; - } else { - fragint = 1; - dmabuf->fragshift = 5; - } - /* - * Now set up the ring - */ - - if (rec == 1) - c = dmabuf->read_channel; - else if (rec == 2) - c = dmabuf->codec_spdifout_channel; - else if (rec == 3) - c = dmabuf->controller_spdifout_channel; - else if (rec == 0) - c = dmabuf->write_channel; - if (c != NULL) { - sg = &c->sg[0]; - /* - * Load up 32 sg entries and take an interrupt at half - * way (we might want more interrupts later..) - */ - for (i = 0; i < dmabuf->numfrag; i++) { - sg->busaddr = - virt_to_bus(dmabuf->rawbuf + - dmabuf->fragsize * i); - // the card will always be doing 16bit stereo - sg->control = dmabuf->fragsamples; - sg->control |= CON_BUFPAD; //I modify - // set us up to get IOC interrupts as often as needed to - // satisfy numfrag requirements, no more - if (((i + 1) % fragint) == 0) { - sg->control |= CON_IOC; - } - sg++; - } - spin_lock_irqsave(&state->card->lock, flags); - outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */ - outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR); - outb(0, state->card->iobase + c->port + OFF_CIV); - outb(0, state->card->iobase + c->port + OFF_LVI); - spin_unlock_irqrestore(&state->card->lock, flags); - } - /* set the ready flag for the dma buffer */ - dmabuf->ready = 1; - return 0; -} - -static void __ali_update_lvi(struct ali_state *state, int rec) -{ - struct dmabuf *dmabuf = &state->dmabuf; - int x, port; - port = state->card->iobase; - if (rec == 1) - port += dmabuf->read_channel->port; - else if (rec == 2) - port += dmabuf->codec_spdifout_channel->port; - else if (rec == 3) - port += dmabuf->controller_spdifout_channel->port; - else if (rec == 0) - port += dmabuf->write_channel->port; - /* if we are currently stopped, then our CIV is actually set to our - * *last* sg segment and we are ready to wrap to the next. However, - * if we set our LVI to the last sg segment, then it won't wrap to - * the next sg segment, it won't even get a start. So, instead, when - * we are stopped, we set both the LVI value and also we increment - * the CIV value to the next sg segment to be played so that when - * we call start_{dac,adc}, things will operate properly - */ - if (!dmabuf->enable && dmabuf->ready) { - if (rec && dmabuf->count < dmabuf->dmasize && (dmabuf->trigger & PCM_ENABLE_INPUT)) { - outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI); - __start_adc(state); - while (! (inb(port + OFF_CR) & ((1 << 4) | (1 << 2)))) - cpu_relax(); - } else if (!rec && dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { - outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI); - __start_dac(state); - while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2)))) - cpu_relax(); - } else if (rec && dmabuf->count && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) { - if (codec_independent_spdif_locked > 0) { - // outb((inb(port+OFF_CIV))&31, port+OFF_LVI); - outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI); - __start_spdifout(state); - while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2)))) - cpu_relax(); - } else { - if (controller_independent_spdif_locked > 0) { - outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI); - __start_spdifout(state); - while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2)))) - cpu_relax(); - } - } - } - } - - /* swptr - 1 is the tail of our transfer */ - x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize; - x /= dmabuf->fragsize; - outb(x, port + OFF_LVI); -} - -static void ali_update_lvi(struct ali_state *state, int rec) -{ - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - if (!dmabuf->ready) - return; - spin_lock_irqsave(&state->card->lock, flags); - __ali_update_lvi(state, rec); - spin_unlock_irqrestore(&state->card->lock, flags); -} - -/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ -static void ali_update_ptr(struct ali_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - unsigned hwptr; - int diff; - - /* error handling and process wake up for DAC */ - if (dmabuf->enable == ADC_RUNNING) { - /* update hardware pointer */ - hwptr = ali_get_dma_addr(state, 1); - diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - dmabuf->count += diff; - if (dmabuf->count > dmabuf->dmasize) { - /* buffer underrun or buffer overrun */ - /* this is normal for the end of a read */ - /* only give an error if we went past the */ - /* last valid sg entry */ - if ((inb(state->card->iobase + PI_CIV) & 31) != (inb(state->card->iobase + PI_LVI) & 31)) { - printk(KERN_WARNING "ali_audio: DMA overrun on read\n"); - dmabuf->error++; - } - } - if (dmabuf->count > dmabuf->userfragsize) - wake_up(&dmabuf->wait); - } - /* error handling and process wake up for DAC */ - if (dmabuf->enable == DAC_RUNNING) { - /* update hardware pointer */ - hwptr = ali_get_dma_addr(state, 0); - diff = - (dmabuf->dmasize + hwptr - - dmabuf->hwptr) % dmabuf->dmasize; -#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP) - printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); -#endif - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - dmabuf->count -= diff; - if (dmabuf->count < 0) { - /* buffer underrun or buffer overrun */ - /* this is normal for the end of a write */ - /* only give an error if we went past the */ - /* last valid sg entry */ - if ((inb(state->card->iobase + PO_CIV) & 31) != (inb(state->card->iobase + PO_LVI) & 31)) { - printk(KERN_WARNING "ali_audio: DMA overrun on write\n"); - printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n", - inb(state->card->iobase + PO_CIV) & 31, - inb(state->card->iobase + PO_LVI) & 31, - dmabuf->hwptr, - dmabuf->count); - dmabuf->error++; - } - } - if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize)) - wake_up(&dmabuf->wait); - } - - /* error handling and process wake up for CODEC SPDIF OUT */ - if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) { - /* update hardware pointer */ - hwptr = ali_get_dma_addr(state, 2); - diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - dmabuf->count -= diff; - if (dmabuf->count < 0) { - /* buffer underrun or buffer overrun */ - /* this is normal for the end of a write */ - /* only give an error if we went past the */ - /* last valid sg entry */ - if ((inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31)) { - printk(KERN_WARNING "ali_audio: DMA overrun on write\n"); - printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n", - inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31, - inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31, - dmabuf->hwptr, dmabuf->count); - dmabuf->error++; - } - } - if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize)) - wake_up(&dmabuf->wait); - } - /* error handling and process wake up for CONTROLLER SPDIF OUT */ - if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) { - /* update hardware pointer */ - hwptr = ali_get_dma_addr(state, 3); - diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - dmabuf->count -= diff; - if (dmabuf->count < 0) { - /* buffer underrun or buffer overrun */ - /* this is normal for the end of a write */ - /* only give an error if we went past the */ - /* last valid sg entry */ - if ((inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31)) { - printk(KERN_WARNING - "ali_audio: DMA overrun on write\n"); - printk("ali_audio: CIV %d, LVI %d, hwptr %x, " - "count %d\n", - inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31, - inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31, - dmabuf->hwptr, dmabuf->count); - dmabuf->error++; - } - } - if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize)) - wake_up(&dmabuf->wait); - } -} - -static inline int ali_get_free_write_space(struct - ali_state - *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - int free; - - if (dmabuf->count < 0) { - dmabuf->count = 0; - dmabuf->swptr = dmabuf->hwptr; - } - free = dmabuf->dmasize - dmabuf->swptr; - if ((dmabuf->count + free) > dmabuf->dmasize){ - free = dmabuf->dmasize - dmabuf->count; - } - return free; -} - -static inline int ali_get_available_read_data(struct - ali_state - *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - int avail; - ali_update_ptr(state); - // catch overruns during record - if (dmabuf->count > dmabuf->dmasize) { - dmabuf->count = dmabuf->dmasize; - dmabuf->swptr = dmabuf->hwptr; - } - avail = dmabuf->count; - avail -= (dmabuf->hwptr % dmabuf->fragsize); - if (avail < 0) - return (0); - return (avail); -} - -static int drain_dac(struct ali_state *state, int signals_allowed) -{ - - DECLARE_WAITQUEUE(wait, current); - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - unsigned long tmo; - int count; - if (!dmabuf->ready) - return 0; - if (dmabuf->mapped) { - stop_dac(state); - return 0; - } - add_wait_queue(&dmabuf->wait, &wait); - for (;;) { - - spin_lock_irqsave(&state->card->lock, flags); - ali_update_ptr(state); - count = dmabuf->count; - spin_unlock_irqrestore(&state->card->lock, flags); - if (count <= 0) - break; - /* - * This will make sure that our LVI is correct, that our - * pointer is updated, and that the DAC is running. We - * have to force the setting of dmabuf->trigger to avoid - * any possible deadlocks. - */ - if (!dmabuf->enable) { - dmabuf->trigger = PCM_ENABLE_OUTPUT; - ali_update_lvi(state, 0); - } - if (signal_pending(current) && signals_allowed) { - break; - } - - /* It seems that we have to set the current state to - * TASK_INTERRUPTIBLE every time to make the process - * really go to sleep. This also has to be *after* the - * update_ptr() call because update_ptr is likely to - * do a wake_up() which will unset this before we ever - * try to sleep, resuling in a tight loop in this code - * instead of actually sleeping and waiting for an - * interrupt to wake us up! - */ - set_current_state(TASK_INTERRUPTIBLE); - /* - * set the timeout to significantly longer than it *should* - * take for the DAC to drain the DMA buffer - */ - tmo = (count * HZ) / (dmabuf->rate); - if (!schedule_timeout(tmo >= 2 ? tmo : 2)) { - printk(KERN_ERR "ali_audio: drain_dac, dma timeout?\n"); - count = 0; - break; - } - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&dmabuf->wait, &wait); - if (count > 0 && signal_pending(current) && signals_allowed) - return -ERESTARTSYS; - stop_dac(state); - return 0; -} - - -static int drain_spdifout(struct ali_state *state, int signals_allowed) -{ - - DECLARE_WAITQUEUE(wait, current); - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - unsigned long tmo; - int count; - if (!dmabuf->ready) - return 0; - if (dmabuf->mapped) { - stop_spdifout(state); - return 0; - } - add_wait_queue(&dmabuf->wait, &wait); - for (;;) { - - spin_lock_irqsave(&state->card->lock, flags); - ali_update_ptr(state); - count = dmabuf->count; - spin_unlock_irqrestore(&state->card->lock, flags); - if (count <= 0) - break; - /* - * This will make sure that our LVI is correct, that our - * pointer is updated, and that the DAC is running. We - * have to force the setting of dmabuf->trigger to avoid - * any possible deadlocks. - */ - if (!dmabuf->enable) { - if (codec_independent_spdif_locked > 0) { - dmabuf->trigger = SPDIF_ENABLE_OUTPUT; - ali_update_lvi(state, 2); - } else { - if (controller_independent_spdif_locked > 0) { - dmabuf->trigger = SPDIF_ENABLE_OUTPUT; - ali_update_lvi(state, 3); - } - } - } - if (signal_pending(current) && signals_allowed) { - break; - } - - /* It seems that we have to set the current state to - * TASK_INTERRUPTIBLE every time to make the process - * really go to sleep. This also has to be *after* the - * update_ptr() call because update_ptr is likely to - * do a wake_up() which will unset this before we ever - * try to sleep, resuling in a tight loop in this code - * instead of actually sleeping and waiting for an - * interrupt to wake us up! - */ - set_current_state(TASK_INTERRUPTIBLE); - /* - * set the timeout to significantly longer than it *should* - * take for the DAC to drain the DMA buffer - */ - tmo = (count * HZ) / (dmabuf->rate); - if (!schedule_timeout(tmo >= 2 ? tmo : 2)) { - printk(KERN_ERR "ali_audio: drain_spdifout, dma timeout?\n"); - count = 0; - break; - } - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&dmabuf->wait, &wait); - if (count > 0 && signal_pending(current) && signals_allowed) - return -ERESTARTSYS; - stop_spdifout(state); - return 0; -} - -static void ali_channel_interrupt(struct ali_card *card) -{ - int i, count; - - for (i = 0; i < NR_HW_CH; i++) { - struct ali_state *state = card->states[i]; - struct ali_channel *c = NULL; - struct dmabuf *dmabuf; - unsigned long port = card->iobase; - u16 status; - if (!state) - continue; - if (!state->dmabuf.ready) - continue; - dmabuf = &state->dmabuf; - if (codec_independent_spdif_locked > 0) { - if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) { - c = dmabuf->codec_spdifout_channel; - } - } else { - if (controller_independent_spdif_locked > 0) { - if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) - c = dmabuf->controller_spdifout_channel; - } else { - if (dmabuf->enable & DAC_RUNNING) { - c = dmabuf->write_channel; - } else if (dmabuf->enable & ADC_RUNNING) { - c = dmabuf->read_channel; - } else - continue; - } - } - port += c->port; - - status = inw(port + OFF_SR); - - if (status & DMA_INT_COMPLETE) { - /* only wake_up() waiters if this interrupt signals - * us being beyond a userfragsize of data open or - * available, and ali_update_ptr() does that for - * us - */ - ali_update_ptr(state); - } - - if (status & DMA_INT_LVI) { - ali_update_ptr(state); - wake_up(&dmabuf->wait); - - if (dmabuf->enable & DAC_RUNNING) - count = dmabuf->count; - else if (dmabuf->enable & ADC_RUNNING) - count = dmabuf->dmasize - dmabuf->count; - else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) - count = dmabuf->count; - else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) - count = dmabuf->count; - else count = 0; - - if (count > 0) { - if (dmabuf->enable & DAC_RUNNING) - outl((1 << 1), state->card->iobase + ALI_DMACR); - else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) - outl((1 << 3), state->card->iobase + ALI_DMACR); - else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) - outl((1 << 7), state->card->iobase + ALI_DMACR); - } else { - if (dmabuf->enable & DAC_RUNNING) - __stop_dac(state); - if (dmabuf->enable & ADC_RUNNING) - __stop_adc(state); - if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) - __stop_spdifout(state); - if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) - __stop_spdifout(state); - dmabuf->enable = 0; - wake_up(&dmabuf->wait); - } - - } - if (!(status & DMA_INT_DCH)) { - ali_update_ptr(state); - wake_up(&dmabuf->wait); - if (dmabuf->enable & DAC_RUNNING) - count = dmabuf->count; - else if (dmabuf->enable & ADC_RUNNING) - count = dmabuf->dmasize - dmabuf->count; - else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) - count = dmabuf->count; - else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) - count = dmabuf->count; - else - count = 0; - - if (count > 0) { - if (dmabuf->enable & DAC_RUNNING) - outl((1 << 1), state->card->iobase + ALI_DMACR); - else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) - outl((1 << 3), state->card->iobase + ALI_DMACR); - else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) - outl((1 << 7), state->card->iobase + ALI_DMACR); - } else { - if (dmabuf->enable & DAC_RUNNING) - __stop_dac(state); - if (dmabuf->enable & ADC_RUNNING) - __stop_adc(state); - if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) - __stop_spdifout(state); - if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) - __stop_spdifout(state); - dmabuf->enable = 0; - wake_up(&dmabuf->wait); - } - } - outw(status & DMA_INT_MASK, port + OFF_SR); - } -} - -static irqreturn_t ali_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct ali_card *card = (struct ali_card *) dev_id; - u32 status; - u16 status2; - - spin_lock(&card->lock); - status = inl(card->iobase + ALI_INTERRUPTSR); - if (!(status & INT_MASK)) { - spin_unlock(&card->lock); - return IRQ_NONE; /* not for us */ - } - - if (codec_independent_spdif_locked > 0) { - if (globel == 0) { - globel += 1; - status2 = inw(card->iobase + 0x76); - outw(status2 | 0x000c, card->iobase + 0x76); - } else { - if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT)) - ali_channel_interrupt(card); - } - } else { - if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT)) - ali_channel_interrupt(card); - } - - /* clear 'em */ - outl(status & INT_MASK, card->iobase + ALI_INTERRUPTSR); - spin_unlock(&card->lock); - return IRQ_HANDLED; -} - -/* in this loop, dmabuf.count signifies the amount of data that is - waiting to be copied to the user's buffer. It is filled by the dma - machine and drained by this loop. */ - -static ssize_t ali_read(struct file *file, char __user *buffer, - size_t count, loff_t * ppos) -{ - struct ali_state *state = (struct ali_state *) file->private_data; - struct ali_card *card = state ? state->card : NULL; - struct dmabuf *dmabuf = &state->dmabuf; - ssize_t ret; - unsigned long flags; - unsigned int swptr; - int cnt; - DECLARE_WAITQUEUE(waita, current); -#ifdef DEBUG2 - printk("ali_audio: ali_read called, count = %d\n", count); -#endif - if (dmabuf->mapped) - return -ENXIO; - if (dmabuf->enable & DAC_RUNNING) - return -ENODEV; - if (!dmabuf->read_channel) { - dmabuf->ready = 0; - dmabuf->read_channel = card->alloc_rec_pcm_channel(card); - if (!dmabuf->read_channel) { - return -EBUSY; - } - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - add_wait_queue(&dmabuf->wait, &waita); - while (count > 0) { - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&card->lock, flags); - if (PM_SUSPENDED(card)) { - spin_unlock_irqrestore(&card->lock, flags); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -EAGAIN; - break; - } - continue; - } - swptr = dmabuf->swptr; - cnt = ali_get_available_read_data(state); - // this is to make the copy_to_user simpler below - if (cnt > (dmabuf->dmasize - swptr)) - cnt = dmabuf->dmasize - swptr; - spin_unlock_irqrestore(&card->lock, flags); - if (cnt > count) - cnt = count; - /* Lop off the last two bits to force the code to always - * write in full samples. This keeps software that sets - * O_NONBLOCK but doesn't check the return value of the - * write call from getting things out of state where they - * think a full 4 byte sample was written when really only - * a portion was, resulting in odd sound and stereo - * hysteresis. - */ - cnt &= ~0x3; - if (cnt <= 0) { - unsigned long tmo; - /* - * Don't let us deadlock. The ADC won't start if - * dmabuf->trigger isn't set. A call to SETTRIGGER - * could have turned it off after we set it to on - * previously. - */ - dmabuf->trigger = PCM_ENABLE_INPUT; - /* - * This does three things. Updates LVI to be correct, - * makes sure the ADC is running, and updates the - * hwptr. - */ - ali_update_lvi(state, 1); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto done; - } - /* Set the timeout to how long it would take to fill - * two of our buffers. If we haven't been woke up - * by then, then we know something is wrong. - */ - tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4); - - /* There are two situations when sleep_on_timeout returns, one is when - the interrupt is serviced correctly and the process is waked up by - ISR ON TIME. Another is when timeout is expired, which means that - either interrupt is NOT serviced correctly (pending interrupt) or it - is TOO LATE for the process to be scheduled to run (scheduler latency) - which results in a (potential) buffer overrun. And worse, there is - NOTHING we can do to prevent it. */ - if (!schedule_timeout(tmo >= 2 ? tmo : 2)) { - printk(KERN_ERR - "ali_audio: recording schedule timeout, " - "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - dmabuf->dmasize, dmabuf->fragsize, - dmabuf->count, dmabuf->hwptr, - dmabuf->swptr); - /* a buffer overrun, we delay the recovery until next time the - while loop begin and we REALLY have space to record */ - } - if (signal_pending(current)) { - ret = ret ? ret : -ERESTARTSYS; - goto done; - } - continue; - } - - if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { - if (!ret) - ret = -EFAULT; - goto done; - } - - swptr = (swptr + cnt) % dmabuf->dmasize; - spin_lock_irqsave(&card->lock, flags); - if (PM_SUSPENDED(card)) { - spin_unlock_irqrestore(&card->lock, flags); - continue; - } - dmabuf->swptr = swptr; - dmabuf->count -= cnt; - spin_unlock_irqrestore(&card->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - } -done: - ali_update_lvi(state, 1); - set_current_state(TASK_RUNNING); - remove_wait_queue(&dmabuf->wait, &waita); - return ret; -} - -/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to - the soundcard. it is drained by the dma machine and filled by this loop. */ -static ssize_t ali_write(struct file *file, - const char __user *buffer, size_t count, loff_t * ppos) -{ - struct ali_state *state = (struct ali_state *) file->private_data; - struct ali_card *card = state ? state->card : NULL; - struct dmabuf *dmabuf = &state->dmabuf; - ssize_t ret; - unsigned long flags; - unsigned int swptr = 0; - int cnt, x; - DECLARE_WAITQUEUE(waita, current); -#ifdef DEBUG2 - printk("ali_audio: ali_write called, count = %d\n", count); -#endif - if (dmabuf->mapped) - return -ENXIO; - if (dmabuf->enable & ADC_RUNNING) - return -ENODEV; - if (codec_independent_spdif_locked > 0) { - if (!dmabuf->codec_spdifout_channel) { - dmabuf->ready = 0; - dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card); - if (!dmabuf->codec_spdifout_channel) - return -EBUSY; - } - } else { - if (controller_independent_spdif_locked > 0) { - if (!dmabuf->controller_spdifout_channel) { - dmabuf->ready = 0; - dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card); - if (!dmabuf->controller_spdifout_channel) - return -EBUSY; - } - } else { - if (!dmabuf->write_channel) { - dmabuf->ready = 0; - dmabuf->write_channel = - card->alloc_pcm_channel(card); - if (!dmabuf->write_channel) - return -EBUSY; - } - } - } - - if (codec_independent_spdif_locked > 0) { - if (!dmabuf->ready && (ret = prog_dmabuf(state, 2))) - return ret; - } else { - if (controller_independent_spdif_locked > 0) { - if (!dmabuf->ready && (ret = prog_dmabuf(state, 3))) - return ret; - } else { - - if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) - return ret; - } - } - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - add_wait_queue(&dmabuf->wait, &waita); - while (count > 0) { - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&state->card->lock, flags); - if (PM_SUSPENDED(card)) { - spin_unlock_irqrestore(&card->lock, flags); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -EAGAIN; - break; - } - continue; - } - - swptr = dmabuf->swptr; - cnt = ali_get_free_write_space(state); - /* Bound the maximum size to how much we can copy to the - * dma buffer before we hit the end. If we have more to - * copy then it will get done in a second pass of this - * loop starting from the beginning of the buffer. - */ - if (cnt > (dmabuf->dmasize - swptr)) - cnt = dmabuf->dmasize - swptr; - spin_unlock_irqrestore(&state->card->lock, flags); -#ifdef DEBUG2 - printk(KERN_INFO - "ali_audio: ali_write: %d bytes available space\n", - cnt); -#endif - if (cnt > count) - cnt = count; - /* Lop off the last two bits to force the code to always - * write in full samples. This keeps software that sets - * O_NONBLOCK but doesn't check the return value of the - * write call from getting things out of state where they - * think a full 4 byte sample was written when really only - * a portion was, resulting in odd sound and stereo - * hysteresis. - */ - cnt &= ~0x3; - if (cnt <= 0) { - unsigned long tmo; - // There is data waiting to be played - /* - * Force the trigger setting since we would - * deadlock with it set any other way - */ - if (codec_independent_spdif_locked > 0) { - dmabuf->trigger = SPDIF_ENABLE_OUTPUT; - ali_update_lvi(state, 2); - } else { - if (controller_independent_spdif_locked > 0) { - dmabuf->trigger = SPDIF_ENABLE_OUTPUT; - ali_update_lvi(state, 3); - } else { - - dmabuf->trigger = PCM_ENABLE_OUTPUT; - ali_update_lvi(state, 0); - } - } - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto ret; - } - /* Not strictly correct but works */ - tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4); - /* There are two situations when sleep_on_timeout returns, one is when - the interrupt is serviced correctly and the process is waked up by - ISR ON TIME. Another is when timeout is expired, which means that - either interrupt is NOT serviced correctly (pending interrupt) or it - is TOO LATE for the process to be scheduled to run (scheduler latency) - which results in a (potential) buffer underrun. And worse, there is - NOTHING we can do to prevent it. */ - - /* FIXME - do timeout handling here !! */ - schedule_timeout(tmo >= 2 ? tmo : 2); - - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto ret; - } - continue; - } - if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - goto ret; - } - - swptr = (swptr + cnt) % dmabuf->dmasize; - spin_lock_irqsave(&state->card->lock, flags); - if (PM_SUSPENDED(card)) { - spin_unlock_irqrestore(&card->lock, flags); - continue; - } - - dmabuf->swptr = swptr; - dmabuf->count += cnt; - count -= cnt; - buffer += cnt; - ret += cnt; - spin_unlock_irqrestore(&state->card->lock, flags); - } - if (swptr % dmabuf->fragsize) { - x = dmabuf->fragsize - (swptr % dmabuf->fragsize); - memset(dmabuf->rawbuf + swptr, '\0', x); - } -ret: - if (codec_independent_spdif_locked > 0) { - ali_update_lvi(state, 2); - } else { - if (controller_independent_spdif_locked > 0) { - ali_update_lvi(state, 3); - } else { - ali_update_lvi(state, 0); - } - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&dmabuf->wait, &waita); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int ali_poll(struct file *file, struct poll_table_struct - *wait) -{ - struct ali_state *state = (struct ali_state *) file->private_data; - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - unsigned int mask = 0; - if (!dmabuf->ready) - return 0; - poll_wait(file, &dmabuf->wait, wait); - spin_lock_irqsave(&state->card->lock, flags); - ali_update_ptr(state); - if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) { - if (dmabuf->count >= (signed) dmabuf->fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE && (dmabuf->enable & (DAC_RUNNING|CODEC_SPDIFOUT_RUNNING|CONTROLLER_SPDIFOUT_RUNNING))) { - if ((signed) dmabuf->dmasize >= dmabuf->count + (signed) dmabuf->fragsize) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&state->card->lock, flags); - return mask; -} - -static int ali_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct ali_state *state = (struct ali_state *) file->private_data; - struct dmabuf *dmabuf = &state->dmabuf; - int ret = -EINVAL; - unsigned long size; - lock_kernel(); - if (vma->vm_flags & VM_WRITE) { - if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) { - ret = -EBUSY; - goto out; - } - } - if (vma->vm_flags & VM_READ) { - if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) { - ret = -EBUSY; - goto out; - } - } - if ((ret = prog_dmabuf(state, 0)) != 0) - goto out; - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << dmabuf->buforder)) - goto out; - ret = -EAGAIN; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - dmabuf->mapped = 1; - dmabuf->trigger = 0; - ret = 0; -out: - unlock_kernel(); - return ret; -} - -static int ali_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct ali_state *state = (struct ali_state *) file->private_data; - struct ali_channel *c = NULL; - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - unsigned int i_scr; - int val = 0, ret; - struct ac97_codec *codec = state->card->ac97_codec[0]; - void __user *argp = (void __user *)arg; - int __user *p = argp; - -#ifdef DEBUG - printk("ali_audio: ali_ioctl, arg=0x%x, cmd=", - arg ? *p : 0); -#endif - switch (cmd) { - case OSS_GETVERSION: -#ifdef DEBUG - printk("OSS_GETVERSION\n"); -#endif - return put_user(SOUND_VERSION, p); - case SNDCTL_DSP_RESET: -#ifdef DEBUG - printk("SNDCTL_DSP_RESET\n"); -#endif - spin_lock_irqsave(&state->card->lock, flags); - if (dmabuf->enable == DAC_RUNNING) { - c = dmabuf->write_channel; - __stop_dac(state); - } - if (dmabuf->enable == ADC_RUNNING) { - c = dmabuf->read_channel; - __stop_adc(state); - } - if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) { - c = dmabuf->codec_spdifout_channel; - __stop_spdifout(state); - } - if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) { - c = dmabuf->controller_spdifout_channel; - __stop_spdifout(state); - } - if (c != NULL) { - outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */ - outl(virt_to_bus(&c->sg[0]), - state->card->iobase + c->port + OFF_BDBAR); - outb(0, state->card->iobase + c->port + OFF_CIV); - outb(0, state->card->iobase + c->port + OFF_LVI); - } - - spin_unlock_irqrestore(&state->card->lock, flags); - synchronize_irq(state->card->pci_dev->irq); - dmabuf->ready = 0; - dmabuf->swptr = dmabuf->hwptr = 0; - dmabuf->count = dmabuf->total_bytes = 0; - return 0; - case SNDCTL_DSP_SYNC: -#ifdef DEBUG - printk("SNDCTL_DSP_SYNC\n"); -#endif - if (codec_independent_spdif_locked > 0) { - if (dmabuf->enable != CODEC_SPDIFOUT_RUNNING - || file->f_flags & O_NONBLOCK) - return 0; - if ((val = drain_spdifout(state, 1))) - return val; - } else { - if (controller_independent_spdif_locked > 0) { - if (dmabuf->enable != - CONTROLLER_SPDIFOUT_RUNNING - || file->f_flags & O_NONBLOCK) - return 0; - if ((val = drain_spdifout(state, 1))) - return val; - } else { - if (dmabuf->enable != DAC_RUNNING - || file->f_flags & O_NONBLOCK) - return 0; - if ((val = drain_dac(state, 1))) - return val; - } - } - dmabuf->total_bytes = 0; - return 0; - case SNDCTL_DSP_SPEED: /* set smaple rate */ -#ifdef DEBUG - printk("SNDCTL_DSP_SPEED\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_WRITE) { - if ((state->card->ac97_status & SPDIF_ON)) { /* S/PDIF Enabled */ - /* RELTEK ALC650 only support 48000, need to check that */ - if (ali_valid_spdif_rate(codec, val)) { - if (codec_independent_spdif_locked > 0) { - ali_set_spdif_output(state, -1, 0); - stop_spdifout(state); - dmabuf->ready = 0; - /* I add test codec independent spdif out */ - spin_lock_irqsave(&state->card->lock, flags); - ali_set_codecspdifout_rate(state, val); // I modified - spin_unlock_irqrestore(&state->card->lock, flags); - /* Set S/PDIF transmitter rate. */ - i_scr = inl(state->card->iobase + ALI_SCR); - if ((i_scr & 0x00300000) == 0x00100000) { - ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); - } else { - if ((i_scr&0x00300000) == 0x00200000) - { - ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked); - } else { - if ((i_scr & 0x00300000) == 0x00300000) { - ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked); - } else { - ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); - } - } - } - - if (!(state->card->ac97_status & SPDIF_ON)) { - val = dmabuf->rate; - } - } else { - if (controller_independent_spdif_locked > 0) - { - stop_spdifout(state); - dmabuf->ready = 0; - spin_lock_irqsave(&state->card->lock, flags); - ali_set_spdifout_rate(state, controller_independent_spdif_locked); - spin_unlock_irqrestore(&state->card->lock, flags); - } else { - /* Set DAC rate */ - ali_set_spdif_output(state, -1, 0); - stop_dac(state); - dmabuf->ready = 0; - spin_lock_irqsave(&state->card->lock, flags); - ali_set_dac_rate(state, val); - spin_unlock_irqrestore(&state->card->lock, flags); - /* Set S/PDIF transmitter rate. */ - ali_set_spdif_output(state, AC97_EA_SPSA_3_4, val); - if (!(state->card->ac97_status & SPDIF_ON)) - { - val = dmabuf->rate; - } - } - } - } else { /* Not a valid rate for S/PDIF, ignore it */ - val = dmabuf->rate; - } - } else { - stop_dac(state); - dmabuf->ready = 0; - spin_lock_irqsave(&state->card->lock, flags); - ali_set_dac_rate(state, val); - spin_unlock_irqrestore(&state->card->lock, flags); - } - } - if (file->f_mode & FMODE_READ) { - stop_adc(state); - dmabuf->ready = 0; - spin_lock_irqsave(&state->card->lock, flags); - ali_set_adc_rate(state, val); - spin_unlock_irqrestore(&state->card->lock, flags); - } - } - return put_user(dmabuf->rate, p); - case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ -#ifdef DEBUG - printk("SNDCTL_DSP_STEREO\n"); -#endif - if (dmabuf->enable & DAC_RUNNING) { - stop_dac(state); - } - if (dmabuf->enable & ADC_RUNNING) { - stop_adc(state); - } - if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) { - stop_spdifout(state); - } - if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) { - stop_spdifout(state); - } - return put_user(1, p); - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if (codec_independent_spdif_locked > 0) { - if (!dmabuf->ready && (val = prog_dmabuf(state, 2))) - return val; - } else { - if (controller_independent_spdif_locked > 0) { - if (!dmabuf->ready && (val = prog_dmabuf(state, 3))) - return val; - } else { - if (!dmabuf->ready && (val = prog_dmabuf(state, 0))) - return val; - } - } - } - - if (file->f_mode & FMODE_READ) { - if (!dmabuf->ready && (val = prog_dmabuf(state, 1))) - return val; - } -#ifdef DEBUG - printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize); -#endif - return put_user(dmabuf->userfragsize, p); - case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format */ -#ifdef DEBUG - printk("SNDCTL_DSP_GETFMTS\n"); -#endif - return put_user(AFMT_S16_LE, p); - case SNDCTL_DSP_SETFMT: /* Select sample format */ -#ifdef DEBUG - printk("SNDCTL_DSP_SETFMT\n"); -#endif - return put_user(AFMT_S16_LE, p); - case SNDCTL_DSP_CHANNELS: // add support 4,6 channel -#ifdef DEBUG - printk("SNDCTL_DSP_CHANNELS\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - if (val > 0) { - if (dmabuf->enable & DAC_RUNNING) { - stop_dac(state); - } - if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) { - stop_spdifout(state); - } - if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) { - stop_spdifout(state); - } - if (dmabuf->enable & ADC_RUNNING) { - stop_adc(state); - } - } else { - return put_user(state->card->channels, p); - } - - i_scr = inl(state->card->iobase + ALI_SCR); - /* Current # of channels enabled */ - if (i_scr & 0x00000100) - ret = 4; - else if (i_scr & 0x00000200) - ret = 6; - else - ret = 2; - switch (val) { - case 2: /* 2 channels is always supported */ - if (codec_independent_spdif_locked > 0) { - outl(((i_scr & 0xfffffcff) | 0x00100000), (state->card->iobase + ALI_SCR)); - } else - outl((i_scr & 0xfffffcff), (state->card->iobase + ALI_SCR)); - /* Do we need to change mixer settings???? */ - break; - case 4: /* Supported on some chipsets, better check first */ - if (codec_independent_spdif_locked > 0) { - outl(((i_scr & 0xfffffcff) | 0x00000100 | 0x00200000), (state->card->iobase + ALI_SCR)); - } else - outl(((i_scr & 0xfffffcff) | 0x00000100), (state->card->iobase + ALI_SCR)); - break; - case 6: /* Supported on some chipsets, better check first */ - if (codec_independent_spdif_locked > 0) { - outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000 | 0x00300000), (state->card->iobase + ALI_SCR)); - } else - outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000), (state->card->iobase + ALI_SCR)); - break; - default: /* nothing else is ever supported by the chipset */ - val = ret; - break; - } - return put_user(val, p); - case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */ - /* we update the swptr to the end of the last sg segment then return */ -#ifdef DEBUG - printk("SNDCTL_DSP_POST\n"); -#endif - if (codec_independent_spdif_locked > 0) { - if (!dmabuf->ready || (dmabuf->enable != CODEC_SPDIFOUT_RUNNING)) - return 0; - } else { - if (controller_independent_spdif_locked > 0) { - if (!dmabuf->ready || (dmabuf->enable != CONTROLLER_SPDIFOUT_RUNNING)) - return 0; - } else { - if (!dmabuf->ready || (dmabuf->enable != DAC_RUNNING)) - return 0; - } - } - if ((dmabuf->swptr % dmabuf->fragsize) != 0) { - val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize); - dmabuf->swptr += val; - dmabuf->count += val; - } - return 0; - case SNDCTL_DSP_SUBDIVIDE: - if (dmabuf->subdivision) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; -#ifdef DEBUG - printk("SNDCTL_DSP_SUBDIVIDE %d\n", val); -#endif - dmabuf->subdivision = val; - dmabuf->ready = 0; - return 0; - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - dmabuf->ossfragsize = 1 << (val & 0xffff); - dmabuf->ossmaxfrags = (val >> 16) & 0xffff; - if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags) - return -EINVAL; - /* - * Bound the frag size into our allowed range of 256 - 4096 - */ - if (dmabuf->ossfragsize < 256) - dmabuf->ossfragsize = 256; - else if (dmabuf->ossfragsize > 4096) - dmabuf->ossfragsize = 4096; - /* - * The numfrags could be something reasonable, or it could - * be 0xffff meaning "Give me as much as possible". So, - * we check the numfrags * fragsize doesn't exceed our - * 64k buffer limit, nor is it less than our 8k minimum. - * If it fails either one of these checks, then adjust the - * number of fragments, not the size of them. It's OK if - * our number of fragments doesn't equal 32 or anything - * like our hardware based number now since we are using - * a different frag count for the hardware. Before we get - * into this though, bound the maxfrags to avoid overflow - * issues. A reasonable bound would be 64k / 256 since our - * maximum buffer size is 64k and our minimum frag size is - * 256. On the other end, our minimum buffer size is 8k and - * our maximum frag size is 4k, so the lower bound should - * be 2. - */ - if (dmabuf->ossmaxfrags > 256) - dmabuf->ossmaxfrags = 256; - else if (dmabuf->ossmaxfrags < 2) - dmabuf->ossmaxfrags = 2; - val = dmabuf->ossfragsize * dmabuf->ossmaxfrags; - while (val < 8192) { - val <<= 1; - dmabuf->ossmaxfrags <<= 1; - } - while (val > 65536) { - val >>= 1; - dmabuf->ossmaxfrags >>= 1; - } - dmabuf->ready = 0; -#ifdef DEBUG - printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val, - dmabuf->ossfragsize, dmabuf->ossmaxfrags); -#endif - return 0; - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (codec_independent_spdif_locked > 0) { - if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0) - return val; - } else { - if (controller_independent_spdif_locked > 0) { - if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0) - return val; - } else { - if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - return val; - } - } - spin_lock_irqsave(&state->card->lock, flags); - ali_update_ptr(state); - abinfo.fragsize = dmabuf->userfragsize; - abinfo.fragstotal = dmabuf->userfrags; - if (dmabuf->mapped) - abinfo.bytes = dmabuf->dmasize; - else - abinfo.bytes = ali_get_free_write_space(state); - abinfo.fragments = abinfo.bytes / dmabuf->userfragsize; - spin_unlock_irqrestore(&state->card->lock, flags); -#if defined(DEBUG) || defined(DEBUG_MMAP) - printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", - abinfo.bytes, abinfo.fragsize, abinfo.fragments, - abinfo.fragstotal); -#endif - return copy_to_user(argp, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (codec_independent_spdif_locked > 0) { - if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0) - return val; - } else { - if (controller_independent_spdif_locked > 0) { - if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0) - return val; - } else { - if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - return val; - } - } - spin_lock_irqsave(&state->card->lock, flags); - val = ali_get_free_write_space(state); - cinfo.bytes = dmabuf->total_bytes; - cinfo.ptr = dmabuf->hwptr; - cinfo.blocks = val / dmabuf->userfragsize; - if (codec_independent_spdif_locked > 0) { - if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) { - dmabuf->count += val; - dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; - __ali_update_lvi(state, 2); - } - } else { - if (controller_independent_spdif_locked > 0) { - if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) { - dmabuf->count += val; - dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; - __ali_update_lvi(state, 3); - } - } else { - if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { - dmabuf->count += val; - dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; - __ali_update_lvi(state, 0); - } - } - } - spin_unlock_irqrestore(&state->card->lock, flags); -#if defined(DEBUG) || defined(DEBUG_MMAP) - printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes, - cinfo.blocks, cinfo.ptr, dmabuf->count); -#endif - return copy_to_user(argp, &cinfo, sizeof(cinfo))? -EFAULT : 0; - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) - return val; - spin_lock_irqsave(&state->card->lock, flags); - abinfo.bytes = ali_get_available_read_data(state); - abinfo.fragsize = dmabuf->userfragsize; - abinfo.fragstotal = dmabuf->userfrags; - abinfo.fragments = abinfo.bytes / dmabuf->userfragsize; - spin_unlock_irqrestore(&state->card->lock, flags); -#if defined(DEBUG) || defined(DEBUG_MMAP) - printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", - abinfo.bytes, abinfo.fragsize, abinfo.fragments, - abinfo.fragstotal); -#endif - return copy_to_user(argp, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - return val; - spin_lock_irqsave(&state->card->lock, flags); - val = ali_get_available_read_data(state); - cinfo.bytes = dmabuf->total_bytes; - cinfo.blocks = val / dmabuf->userfragsize; - cinfo.ptr = dmabuf->hwptr; - if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) { - dmabuf->count -= val; - dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; - __ali_update_lvi(state, 1); - } - spin_unlock_irqrestore(&state->card->lock, flags); -#if defined(DEBUG) || defined(DEBUG_MMAP) - printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes, - cinfo.blocks, cinfo.ptr, dmabuf->count); -#endif - return copy_to_user(argp, &cinfo, sizeof(cinfo))? -EFAULT: 0; - case SNDCTL_DSP_NONBLOCK: -#ifdef DEBUG - printk("SNDCTL_DSP_NONBLOCK\n"); -#endif - file->f_flags |= O_NONBLOCK; - return 0; - case SNDCTL_DSP_GETCAPS: -#ifdef DEBUG - printk("SNDCTL_DSP_GETCAPS\n"); -#endif - return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | - DSP_CAP_MMAP | DSP_CAP_BIND, p); - case SNDCTL_DSP_GETTRIGGER: - val = 0; -#ifdef DEBUG - printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger); -#endif - return put_user(dmabuf->trigger, p); - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; -#if defined(DEBUG) || defined(DEBUG_MMAP) - printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val); -#endif - if (!(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) { - stop_adc(state); - } - if (!(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) { - stop_dac(state); - } - if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CODEC_SPDIFOUT_RUNNING) { - stop_spdifout(state); - } - if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) { - stop_spdifout(state); - } - dmabuf->trigger = val; - if (val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) { - if (!dmabuf->write_channel) { - dmabuf->ready = 0; - dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); - if (!dmabuf->write_channel) - return -EBUSY; - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) - return ret; - if (dmabuf->mapped) { - spin_lock_irqsave(&state->card->lock, flags); - ali_update_ptr(state); - dmabuf->count = 0; - dmabuf->swptr = dmabuf->hwptr; - dmabuf->count = ali_get_free_write_space(state); - dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize; - __ali_update_lvi(state, 0); - spin_unlock_irqrestore(&state->card->lock, - flags); - } else - start_dac(state); - } - if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CODEC_SPDIFOUT_RUNNING)) { - if (!dmabuf->codec_spdifout_channel) { - dmabuf->ready = 0; - dmabuf->codec_spdifout_channel = state->card->alloc_codec_spdifout_channel(state->card); - if (!dmabuf->codec_spdifout_channel) - return -EBUSY; - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 2))) - return ret; - if (dmabuf->mapped) { - spin_lock_irqsave(&state->card->lock, flags); - ali_update_ptr(state); - dmabuf->count = 0; - dmabuf->swptr = dmabuf->hwptr; - dmabuf->count = ali_get_free_write_space(state); - dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize; - __ali_update_lvi(state, 2); - spin_unlock_irqrestore(&state->card->lock, - flags); - } else - start_spdifout(state); - } - if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)) { - if (!dmabuf->controller_spdifout_channel) { - dmabuf->ready = 0; - dmabuf->controller_spdifout_channel = state->card->alloc_controller_spdifout_channel(state->card); - if (!dmabuf->controller_spdifout_channel) - return -EBUSY; - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 3))) - return ret; - if (dmabuf->mapped) { - spin_lock_irqsave(&state->card->lock, flags); - ali_update_ptr(state); - dmabuf->count = 0; - dmabuf->swptr = dmabuf->hwptr; - dmabuf->count = ali_get_free_write_space(state); - dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize; - __ali_update_lvi(state, 3); - spin_unlock_irqrestore(&state->card->lock, flags); - } else - start_spdifout(state); - } - if (val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) { - if (!dmabuf->read_channel) { - dmabuf->ready = 0; - dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); - if (!dmabuf->read_channel) - return -EBUSY; - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; - if (dmabuf->mapped) { - spin_lock_irqsave(&state->card->lock, - flags); - ali_update_ptr(state); - dmabuf->swptr = dmabuf->hwptr; - dmabuf->count = 0; - spin_unlock_irqrestore(&state->card->lock, flags); - } - ali_update_lvi(state, 1); - start_adc(state); - } - return 0; - case SNDCTL_DSP_SETDUPLEX: -#ifdef DEBUG - printk("SNDCTL_DSP_SETDUPLEX\n"); -#endif - return -EINVAL; - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&state->card->lock, flags); - ali_update_ptr(state); - val = dmabuf->count; - spin_unlock_irqrestore(&state->card->lock, flags); -#ifdef DEBUG - printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count); -#endif - return put_user(val, p); - case SOUND_PCM_READ_RATE: -#ifdef DEBUG - printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate); -#endif - return put_user(dmabuf->rate, p); - case SOUND_PCM_READ_CHANNELS: -#ifdef DEBUG - printk("SOUND_PCM_READ_CHANNELS\n"); -#endif - return put_user(2, p); - case SOUND_PCM_READ_BITS: -#ifdef DEBUG - printk("SOUND_PCM_READ_BITS\n"); -#endif - return put_user(AFMT_S16_LE, p); - case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */ -#ifdef DEBUG - printk("SNDCTL_DSP_SETSPDIF\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - /* Check to make sure the codec supports S/PDIF transmitter */ - if ((state->card->ac97_features & 4)) { - /* mask out the transmitter speed bits so the user can't set them */ - val &= ~0x3000; - /* Add the current transmitter speed bits to the passed value */ - ret = ali_ac97_get(codec, AC97_SPDIF_CONTROL); - val |= (ret & 0x3000); - ali_ac97_set(codec, AC97_SPDIF_CONTROL, val); - if (ali_ac97_get(codec, AC97_SPDIF_CONTROL) != val) { - printk(KERN_ERR "ali_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val); - return -EFAULT; - } - } -#ifdef DEBUG - else - printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n"); -#endif - return put_user(val, p); - case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */ -#ifdef DEBUG - printk("SNDCTL_DSP_GETSPDIF\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - /* Check to make sure the codec supports S/PDIF transmitter */ - if (!(state->card->ac97_features & 4)) { -#ifdef DEBUG - printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n"); -#endif - val = 0; - } else { - val = ali_ac97_get(codec, AC97_SPDIF_CONTROL); - } - - return put_user(val, p); -//end add support spdif out -//add support 4,6 channel - case SNDCTL_DSP_GETCHANNELMASK: -#ifdef DEBUG - printk("SNDCTL_DSP_GETCHANNELMASK\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - /* Based on AC'97 DAC support, not ICH hardware */ - val = DSP_BIND_FRONT; - if (state->card->ac97_features & 0x0004) - val |= DSP_BIND_SPDIF; - if (state->card->ac97_features & 0x0080) - val |= DSP_BIND_SURR; - if (state->card->ac97_features & 0x0140) - val |= DSP_BIND_CENTER_LFE; - return put_user(val, p); - case SNDCTL_DSP_BIND_CHANNEL: -#ifdef DEBUG - printk("SNDCTL_DSP_BIND_CHANNEL\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - if (val == DSP_BIND_QUERY) { - val = DSP_BIND_FRONT; /* Always report this as being enabled */ - if (state->card->ac97_status & SPDIF_ON) - val |= DSP_BIND_SPDIF; - else { - if (state->card->ac97_status & SURR_ON) - val |= DSP_BIND_SURR; - if (state->card-> - ac97_status & CENTER_LFE_ON) - val |= DSP_BIND_CENTER_LFE; - } - } else { /* Not a query, set it */ - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (dmabuf->enable == DAC_RUNNING) { - stop_dac(state); - } - if (val & DSP_BIND_SPDIF) { /* Turn on SPDIF */ - /* Ok, this should probably define what slots - * to use. For now, we'll only set it to the - * defaults: - * - * non multichannel codec maps to slots 3&4 - * 2 channel codec maps to slots 7&8 - * 4 channel codec maps to slots 6&9 - * 6 channel codec maps to slots 10&11 - * - * there should be some way for the app to - * select the slot assignment. - */ - i_scr = inl(state->card->iobase + ALI_SCR); - if (codec_independent_spdif_locked > 0) { - - if ((i_scr & 0x00300000) == 0x00100000) { - ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); - } else { - if ((i_scr & 0x00300000) == 0x00200000) { - ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked); - } else { - if ((i_scr & 0x00300000) == 0x00300000) { - ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked); - } - } - } - } else { /* codec spdif out (pcm out share ) */ - ali_set_spdif_output(state, AC97_EA_SPSA_3_4, dmabuf->rate); //I do not modify - } - - if (!(state->card->ac97_status & SPDIF_ON)) - val &= ~DSP_BIND_SPDIF; - } else { - int mask; - int channels; - /* Turn off S/PDIF if it was on */ - if (state->card->ac97_status & SPDIF_ON) - ali_set_spdif_output(state, -1, 0); - mask = - val & (DSP_BIND_FRONT | DSP_BIND_SURR | - DSP_BIND_CENTER_LFE); - switch (mask) { - case DSP_BIND_FRONT: - channels = 2; - break; - case DSP_BIND_FRONT | DSP_BIND_SURR: - channels = 4; - break; - case DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE: - channels = 6; - break; - default: - val = DSP_BIND_FRONT; - channels = 2; - break; - } - ali_set_dac_channels(state, channels); - /* check that they really got turned on */ - if (!state->card->ac97_status & SURR_ON) - val &= ~DSP_BIND_SURR; - if (!state->card-> - ac97_status & CENTER_LFE_ON) - val &= ~DSP_BIND_CENTER_LFE; - } - } - return put_user(val, p); - case SNDCTL_DSP_MAPINBUF: - case SNDCTL_DSP_MAPOUTBUF: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_WRITE_FILTER: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - } - return -EINVAL; -} - -static int ali_open(struct inode *inode, struct file *file) -{ - int i = 0; - struct ali_card *card = devs; - struct ali_state *state = NULL; - struct dmabuf *dmabuf = NULL; - unsigned int i_scr; - - /* find an available virtual channel (instance of /dev/dsp) */ - - while (card != NULL) { - - /* - * If we are initializing and then fail, card could go - * away unuexpectedly while we are in the for() loop. - * So, check for card on each iteration before we check - * for card->initializing to avoid a possible oops. - * This usually only matters for times when the driver is - * autoloaded by kmod. - */ - for (i = 0; i < 50 && card && card->initializing; i++) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 20); - } - - for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) { - if (card->states[i] == NULL) { - state = card->states[i] = (struct ali_state *) kmalloc(sizeof(struct ali_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - memset(state, 0, sizeof(struct ali_state)); - dmabuf = &state->dmabuf; - goto found_virt; - } - } - card = card->next; - } - - /* no more virtual channel avaiable */ - if (!state) - return -ENODEV; -found_virt: - /* initialize the virtual channel */ - - state->virt = i; - state->card = card; - state->magic = ALI5455_STATE_MAGIC; - init_waitqueue_head(&dmabuf->wait); - mutex_init(&state->open_mutex); - file->private_data = state; - dmabuf->trigger = 0; - /* allocate hardware channels */ - if (file->f_mode & FMODE_READ) { - if ((dmabuf->read_channel = - card->alloc_rec_pcm_channel(card)) == NULL) { - kfree(card->states[i]); - card->states[i] = NULL; - return -EBUSY; - } - dmabuf->trigger |= PCM_ENABLE_INPUT; - ali_set_adc_rate(state, 8000); - } - if (file->f_mode & FMODE_WRITE) { - if (codec_independent_spdif_locked > 0) { - if ((dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card)) == NULL) { - kfree(card->states[i]); - card->states[i] = NULL; - return -EBUSY; - } - dmabuf->trigger |= SPDIF_ENABLE_OUTPUT; - ali_set_codecspdifout_rate(state, codec_independent_spdif_locked); //It must add - i_scr = inl(state->card->iobase + ALI_SCR); - if ((i_scr & 0x00300000) == 0x00100000) { - ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); - } else { - if ((i_scr & 0x00300000) == 0x00200000) { - ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked); - } else { - if ((i_scr & 0x00300000) == 0x00300000) { - ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked); - } else { - ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); - } - } - - } - } else { - if (controller_independent_spdif_locked > 0) { - if ((dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card)) == NULL) { - kfree(card->states[i]); - card->states[i] = NULL; - return -EBUSY; - } - dmabuf->trigger |= SPDIF_ENABLE_OUTPUT; - ali_set_spdifout_rate(state, controller_independent_spdif_locked); - } else { - if ((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) { - kfree(card->states[i]); - card->states[i] = NULL; - return -EBUSY; - } - /* Initialize to 8kHz? What if we don't support 8kHz? */ - /* Let's change this to check for S/PDIF stuff */ - - dmabuf->trigger |= PCM_ENABLE_OUTPUT; - if (codec_pcmout_share_spdif_locked) { - ali_set_dac_rate(state, codec_pcmout_share_spdif_locked); - ali_set_spdif_output(state, AC97_EA_SPSA_3_4, codec_pcmout_share_spdif_locked); - } else { - ali_set_dac_rate(state, 8000); - } - } - - } - } - - /* set default sample format. According to OSS Programmer's Guide /dev/dsp - should be default to unsigned 8-bits, mono, with sample rate 8kHz and - /dev/dspW will accept 16-bits sample, but we don't support those so we - set it immediately to stereo and 16bit, which is all we do support */ - dmabuf->fmt |= ALI5455_FMT_16BIT | ALI5455_FMT_STEREO; - dmabuf->ossfragsize = 0; - dmabuf->ossmaxfrags = 0; - dmabuf->subdivision = 0; - state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - outl(0x00000000, card->iobase + ALI_INTERRUPTCR); - outl(0x00000000, card->iobase + ALI_INTERRUPTSR); - return nonseekable_open(inode, file); -} - -static int ali_release(struct inode *inode, struct file *file) -{ - struct ali_state *state = (struct ali_state *) file->private_data; - struct ali_card *card = state->card; - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - lock_kernel(); - - /* stop DMA state machine and free DMA buffers/channels */ - if (dmabuf->trigger & PCM_ENABLE_OUTPUT) - drain_dac(state, 0); - - if (dmabuf->trigger & SPDIF_ENABLE_OUTPUT) - drain_spdifout(state, 0); - - if (dmabuf->trigger & PCM_ENABLE_INPUT) - stop_adc(state); - - spin_lock_irqsave(&card->lock, flags); - dealloc_dmabuf(state); - if (file->f_mode & FMODE_WRITE) { - if (codec_independent_spdif_locked > 0) { - state->card->free_pcm_channel(state->card, dmabuf->codec_spdifout_channel->num); - } else { - if (controller_independent_spdif_locked > 0) - state->card->free_pcm_channel(state->card, - dmabuf->controller_spdifout_channel->num); - else state->card->free_pcm_channel(state->card, - dmabuf->write_channel->num); - } - } - if (file->f_mode & FMODE_READ) - state->card->free_pcm_channel(state->card, dmabuf->read_channel->num); - - state->card->states[state->virt] = NULL; - kfree(state); - spin_unlock_irqrestore(&card->lock, flags); - unlock_kernel(); - return 0; -} - -static /*const */ struct file_operations ali_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ali_read, - .write = ali_write, - .poll = ali_poll, - .ioctl = ali_ioctl, - .mmap = ali_mmap, - .open = ali_open, - .release = ali_release, -}; - -/* Read AC97 codec registers */ -static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg) -{ - struct ali_card *card = dev->private_data; - int count1 = 100; - char val; - unsigned short int data = 0, count, addr1, addr2 = 0; - - spin_lock(&card->ac97_lock); - while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000)) - udelay(1); - - addr1 = reg; - reg |= 0x0080; - for (count = 0; count < 0x7f; count++) { - val = inb(card->iobase + ALI_CSPSR); - if (val & 0x08) - break; - } - if (count == 0x7f) - { - spin_unlock(&card->ac97_lock); - return -1; - } - outw(reg, (card->iobase + ALI_CPR) + 2); - for (count = 0; count < 0x7f; count++) { - val = inb(card->iobase + ALI_CSPSR); - if (val & 0x02) { - data = inw(card->iobase + ALI_SPR); - addr2 = inw((card->iobase + ALI_SPR) + 2); - break; - } - } - spin_unlock(&card->ac97_lock); - if (count == 0x7f) - return -1; - if (addr2 != addr1) - return -1; - return ((u16) data); -} - -/* write ac97 codec register */ - -static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data) -{ - struct ali_card *card = dev->private_data; - int count1 = 100; - char val; - unsigned short int count; - - spin_lock(&card->ac97_lock); - while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000)) - udelay(1); - - for (count = 0; count < 0x7f; count++) { - val = inb(card->iobase + ALI_CSPSR); - if (val & 0x08) - break; - } - if (count == 0x7f) { - printk(KERN_WARNING "ali_ac97_set: AC97 codec register access timed out. \n"); - spin_unlock(&card->ac97_lock); - return; - } - outw(data, (card->iobase + ALI_CPR)); - outb(reg, (card->iobase + ALI_CPR) + 2); - for (count = 0; count < 0x7f; count++) { - val = inb(card->iobase + ALI_CSPSR); - if (val & 0x01) - break; - } - spin_unlock(&card->ac97_lock); - if (count == 0x7f) - printk(KERN_WARNING "ali_ac97_set: AC97 codec register access timed out. \n"); - return; -} - -/* OSS /dev/mixer file operation methods */ - -static int ali_open_mixdev(struct inode *inode, struct file *file) -{ - int i; - int minor = iminor(inode); - struct ali_card *card = devs; - for (card = devs; card != NULL; card = card->next) { - /* - * If we are initializing and then fail, card could go - * away unuexpectedly while we are in the for() loop. - * So, check for card on each iteration before we check - * for card->initializing to avoid a possible oops. - * This usually only matters for times when the driver is - * autoloaded by kmod. - */ - for (i = 0; i < 50 && card && card->initializing; i++) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 20); - } - for (i = 0; i < NR_AC97 && card && !card->initializing; i++) - if (card->ac97_codec[i] != NULL - && card->ac97_codec[i]->dev_mixer == minor) { - file->private_data = card->ac97_codec[i]; - return nonseekable_open(inode, file); - } - } - return -ENODEV; -} - -static int ali_ioctl_mixdev(struct inode *inode, - struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ac97_codec *codec = (struct ac97_codec *) file->private_data; - return codec->mixer_ioctl(codec, cmd, arg); -} - -static /*const */ struct file_operations ali_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = ali_ioctl_mixdev, - .open = ali_open_mixdev, -}; - -/* AC97 codec initialisation. These small functions exist so we don't - duplicate code between module init and apm resume */ - -static inline int ali_ac97_exists(struct ali_card *card, int ac97_number) -{ - unsigned int i = 1; - u32 reg = inl(card->iobase + ALI_RTSR); - if (ac97_number) { - while (i < 100) { - - reg = inl(card->iobase + ALI_RTSR); - if (reg & 0x40) { - break; - } else { - outl(reg | 0x00000040, - card->iobase + 0x34); - udelay(1); - } - i++; - } - - } else { - while (i < 100) { - reg = inl(card->iobase + ALI_RTSR); - if (reg & 0x80) { - break; - } else { - outl(reg | 0x00000080, - card->iobase + 0x34); - udelay(1); - } - i++; - } - } - - if (ac97_number) - return reg & 0x40; - else - return reg & 0x80; -} - -static inline int ali_ac97_enable_variable_rate(struct ac97_codec *codec) -{ - ali_ac97_set(codec, AC97_EXTENDED_STATUS, 9); - ali_ac97_set(codec, AC97_EXTENDED_STATUS, ali_ac97_get(codec, AC97_EXTENDED_STATUS) | 0xE800); - return (ali_ac97_get(codec, AC97_EXTENDED_STATUS) & 1); -} - - -static int ali_ac97_probe_and_powerup(struct ali_card *card, struct ac97_codec *codec) -{ - /* Returns 0 on failure */ - int i; - u16 addr; - if (ac97_probe_codec(codec) == 0) - return 0; - /* ac97_probe_codec is success ,then begin to init codec */ - ali_ac97_set(codec, AC97_RESET, 0xffff); - if (card->channel[0].used == 1) { - ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000); - ali_ac97_set(codec, AC97_LINEIN_VOL, 0x0808); - ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F); - } - - if (card->channel[2].used == 1) //if MICin then init codec - { - ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000); - ali_ac97_set(codec, AC97_MIC_VOL, 0x8808); - ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F); - ali_ac97_set(codec, AC97_RECORD_GAIN_MIC, 0x0000); - } - - ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, 0x0000); - ali_ac97_set(codec, AC97_HEADPHONE_VOL, 0x0000); - ali_ac97_set(codec, AC97_PCMOUT_VOL, 0x0000); - ali_ac97_set(codec, AC97_CD_VOL, 0x0808); - ali_ac97_set(codec, AC97_VIDEO_VOL, 0x0808); - ali_ac97_set(codec, AC97_AUX_VOL, 0x0808); - ali_ac97_set(codec, AC97_PHONE_VOL, 0x8048); - ali_ac97_set(codec, AC97_PCBEEP_VOL, 0x0000); - ali_ac97_set(codec, AC97_GENERAL_PURPOSE, AC97_GP_MIX); - ali_ac97_set(codec, AC97_MASTER_VOL_MONO, 0x0000); - ali_ac97_set(codec, 0x38, 0x0000); - addr = ali_ac97_get(codec, 0x2a); - ali_ac97_set(codec, 0x2a, addr | 0x0001); - addr = ali_ac97_get(codec, 0x2a); - addr = ali_ac97_get(codec, 0x28); - ali_ac97_set(codec, 0x2c, 0xbb80); - addr = ali_ac97_get(codec, 0x2c); - /* power it all up */ - ali_ac97_set(codec, AC97_POWER_CONTROL, - ali_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00); - /* wait for analog ready */ - for (i = 10; i && ((ali_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 20); - } - /* FIXME !! */ - i++; - return i; -} - - -/* I clone ali5455(2.4.7 ) not clone i810_audio(2.4.18) */ - -static int ali_reset_5455(struct ali_card *card) -{ - outl(0x80000003, card->iobase + ALI_SCR); - outl(0x83838383, card->iobase + ALI_FIFOCR1); - outl(0x83838383, card->iobase + ALI_FIFOCR2); - if (controller_pcmout_share_spdif_locked > 0) { - outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001), - card->iobase + ALI_SPDIFICS); - outl(0x0408000a, card->iobase + ALI_INTERFACECR); - } else { - if (codec_independent_spdif_locked > 0) { - outl((inl(card->iobase + ALI_SCR) | 0x00100000), card->iobase + ALI_SCR); // now I select slot 7 & 8 - outl(0x00200000, card->iobase + ALI_INTERFACECR); //enable codec independent spdifout - } else - outl(0x04080002, card->iobase + ALI_INTERFACECR); - } - - outl(0x00000000, card->iobase + ALI_INTERRUPTCR); - outl(0x00000000, card->iobase + ALI_INTERRUPTSR); - if (controller_independent_spdif_locked > 0) - outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001), - card->iobase + ALI_SPDIFICS); - return 1; -} - - -static int ali_ac97_random_init_stuff(struct ali_card - *card) -{ - u32 reg = inl(card->iobase + ALI_SCR); - int i = 0; - reg = inl(card->iobase + ALI_SCR); - if ((reg & 2) == 0) /* Cold required */ - reg |= 2; - else - reg |= 1; /* Warm */ - reg &= ~0x80000000; /* ACLink on */ - outl(reg, card->iobase + ALI_SCR); - - while (i < 10) { - if ((inl(card->iobase + 0x18) & (1 << 1)) == 0) - break; - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ / 20); - i++; - } - if (i == 10) { - printk(KERN_ERR "ali_audio: AC'97 reset failed.\n"); - return 0; - } - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 2); - return 1; -} - -/* AC97 codec initialisation. */ - -static int __devinit ali_ac97_init(struct ali_card *card) -{ - int num_ac97 = 0; - int total_channels = 0; - struct ac97_codec *codec; - u16 eid; - - if (!ali_ac97_random_init_stuff(card)) - return 0; - - /* Number of channels supported */ - /* What about the codec? Just because the ICH supports */ - /* multiple channels doesn't mean the codec does. */ - /* we'll have to modify this in the codec section below */ - /* to reflect what the codec has. */ - /* ICH and ICH0 only support 2 channels so don't bother */ - /* to check.... */ - inl(card->iobase + ALI_CPR); - card->channels = 2; - - for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { - - /* Assume codec isn't available until we go through the - * gauntlet below */ - card->ac97_codec[num_ac97] = NULL; - /* The ICH programmer's reference says you should */ - /* check the ready status before probing. So we chk */ - /* What do we do if it's not ready? Wait and try */ - /* again, or abort? */ - if (!ali_ac97_exists(card, num_ac97)) { - if (num_ac97 == 0) - printk(KERN_ERR "ali_audio: Primary codec not ready.\n"); - break; - } - - if ((codec = ac97_alloc_codec()) == NULL) - return -ENOMEM; - /* initialize some basic codec information, other fields will be filled - in ac97_probe_codec */ - codec->private_data = card; - codec->id = num_ac97; - codec->codec_read = ali_ac97_get; - codec->codec_write = ali_ac97_set; - if (!ali_ac97_probe_and_powerup(card, codec)) { - printk(KERN_ERR "ali_audio: timed out waiting for codec %d analog ready", - num_ac97); - kfree(codec); - break; /* it didn't work */ - } - - /* Store state information about S/PDIF transmitter */ - card->ac97_status = 0; - /* Don't attempt to get eid until powerup is complete */ - eid = ali_ac97_get(codec, AC97_EXTENDED_ID); - if (eid == 0xFFFF) { - printk(KERN_ERR "ali_audio: no codec attached ?\n"); - kfree(codec); - break; - } - - card->ac97_features = eid; - /* Now check the codec for useful features to make up for - the dumbness of the ali5455 hardware engine */ - if (!(eid & 0x0001)) - printk(KERN_WARNING - "ali_audio: only 48Khz playback available.\n"); - else { - if (!ali_ac97_enable_variable_rate(codec)) { - printk(KERN_WARNING - "ali_audio: Codec refused to allow VRA, using 48Khz only.\n"); - card->ac97_features &= ~1; - } - } - - /* Determine how many channels the codec(s) support */ - /* - The primary codec always supports 2 */ - /* - If the codec supports AMAP, surround DACs will */ - /* automaticlly get assigned to slots. */ - /* * Check for surround DACs and increment if */ - /* found. */ - /* - Else check if the codec is revision 2.2 */ - /* * If surround DACs exist, assign them to slots */ - /* and increment channel count. */ - - /* All of this only applies to ICH2 and above. ICH */ - /* and ICH0 only support 2 channels. ICH2 will only */ - /* support multiple codecs in a "split audio" config. */ - /* as described above. */ - - /* TODO: Remove all the debugging messages! */ - - if ((eid & 0xc000) == 0) /* primary codec */ - total_channels += 2; - if ((codec->dev_mixer = register_sound_mixer(&ali_mixer_fops, -1)) < 0) { - printk(KERN_ERR "ali_audio: couldn't register mixer!\n"); - kfree(codec); - break; - } - card->ac97_codec[num_ac97] = codec; - } - /* pick the minimum of channels supported by ICHx or codec(s) */ - card->channels = (card->channels > total_channels) ? total_channels : card->channels; - return num_ac97; -} - -static void __devinit ali_configure_clocking(void) -{ - struct ali_card *card; - struct ali_state *state; - struct dmabuf *dmabuf; - unsigned int i, offset, new_offset; - unsigned long flags; - card = devs; - - /* We could try to set the clocking for multiple cards, but can you even have - * more than one ali in a machine? Besides, clocking is global, so unless - * someone actually thinks more than one ali in a machine is possible and - * decides to rewrite that little bit, setting the rate for more than one card - * is a waste of time. - */ - if (card != NULL) { - state = card->states[0] = (struct ali_state *) - kmalloc(sizeof(struct ali_state), GFP_KERNEL); - if (state == NULL) - return; - memset(state, 0, sizeof(struct ali_state)); - dmabuf = &state->dmabuf; - dmabuf->write_channel = card->alloc_pcm_channel(card); - state->virt = 0; - state->card = card; - state->magic = ALI5455_STATE_MAGIC; - init_waitqueue_head(&dmabuf->wait); - mutex_init(&state->open_mutex); - dmabuf->fmt = ALI5455_FMT_STEREO | ALI5455_FMT_16BIT; - dmabuf->trigger = PCM_ENABLE_OUTPUT; - ali_set_dac_rate(state, 48000); - if (prog_dmabuf(state, 0) != 0) - goto config_out_nodmabuf; - - if (dmabuf->dmasize < 16384) - goto config_out; - - dmabuf->count = dmabuf->dmasize; - outb(31, card->iobase + dmabuf->write_channel->port + OFF_LVI); - - local_irq_save(flags); - start_dac(state); - offset = ali_get_dma_addr(state, 0); - mdelay(50); - new_offset = ali_get_dma_addr(state, 0); - stop_dac(state); - - outb(2, card->iobase + dmabuf->write_channel->port + OFF_CR); - local_irq_restore(flags); - - i = new_offset - offset; - - if (i == 0) - goto config_out; - i = i / 4 * 20; - if (i > 48500 || i < 47500) { - clocking = clocking * clocking / i; - } -config_out: - dealloc_dmabuf(state); -config_out_nodmabuf: - state->card->free_pcm_channel(state->card, state->dmabuf. write_channel->num); - kfree(state); - card->states[0] = NULL; - } -} - -/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered - until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ - -static int __devinit ali_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - struct ali_card *card; - if (pci_enable_device(pci_dev)) - return -EIO; - if (pci_set_dma_mask(pci_dev, ALI5455_DMA_MASK)) { - printk(KERN_ERR "ali5455: architecture does not support" - " 32bit PCI busmaster DMA\n"); - return -ENODEV; - } - - if ((card = kmalloc(sizeof(struct ali_card), GFP_KERNEL)) == NULL) { - printk(KERN_ERR "ali_audio: out of memory\n"); - return -ENOMEM; - } - memset(card, 0, sizeof(*card)); - card->initializing = 1; - card->iobase = pci_resource_start(pci_dev, 0); - card->pci_dev = pci_dev; - card->pci_id = pci_id->device; - card->irq = pci_dev->irq; - card->next = devs; - card->magic = ALI5455_CARD_MAGIC; -#ifdef CONFIG_PM - card->pm_suspended = 0; -#endif - spin_lock_init(&card->lock); - spin_lock_init(&card->ac97_lock); - devs = card; - pci_set_master(pci_dev); - printk(KERN_INFO "ali: %s found at IO 0x%04lx, IRQ %d\n", - card_names[pci_id->driver_data], card->iobase, card->irq); - card->alloc_pcm_channel = ali_alloc_pcm_channel; - card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel; - card->alloc_rec_mic_channel = ali_alloc_rec_mic_channel; - card->alloc_codec_spdifout_channel = ali_alloc_codec_spdifout_channel; - card->alloc_controller_spdifout_channel = ali_alloc_controller_spdifout_channel; - card->free_pcm_channel = ali_free_pcm_channel; - card->channel[0].offset = 0; - card->channel[0].port = 0x40; - card->channel[0].num = 0; - card->channel[1].offset = 0; - card->channel[1].port = 0x50; - card->channel[1].num = 1; - card->channel[2].offset = 0; - card->channel[2].port = 0x60; - card->channel[2].num = 2; - card->channel[3].offset = 0; - card->channel[3].port = 0x70; - card->channel[3].num = 3; - card->channel[4].offset = 0; - card->channel[4].port = 0xb0; - card->channel[4].num = 4; - /* claim our iospace and irq */ - request_region(card->iobase, 256, card_names[pci_id->driver_data]); - if (request_irq(card->irq, &ali_interrupt, IRQF_SHARED, - card_names[pci_id->driver_data], card)) { - printk(KERN_ERR "ali_audio: unable to allocate irq %d\n", - card->irq); - release_region(card->iobase, 256); - kfree(card); - return -ENODEV; - } - - if (ali_reset_5455(card) <= 0) { - unregister_sound_dsp(card->dev_audio); - release_region(card->iobase, 256); - free_irq(card->irq, card); - kfree(card); - return -ENODEV; - } - - /* initialize AC97 codec and register /dev/mixer */ - if (ali_ac97_init(card) < 0) { - release_region(card->iobase, 256); - free_irq(card->irq, card); - kfree(card); - return -ENODEV; - } - - pci_set_drvdata(pci_dev, card); - - if (clocking == 0) { - clocking = 48000; - ali_configure_clocking(); - } - - /* register /dev/dsp */ - if ((card->dev_audio = register_sound_dsp(&ali_audio_fops, -1)) < 0) { - int i; - printk(KERN_ERR"ali_audio: couldn't register DSP device!\n"); - release_region(card->iobase, 256); - free_irq(card->irq, card); - for (i = 0; i < NR_AC97; i++) - if (card->ac97_codec[i] != NULL) { - unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); - kfree(card->ac97_codec[i]); - } - kfree(card); - return -ENODEV; - } - card->initializing = 0; - return 0; -} - -static void __devexit ali_remove(struct pci_dev *pci_dev) -{ - int i; - struct ali_card *card = pci_get_drvdata(pci_dev); - /* free hardware resources */ - free_irq(card->irq, devs); - release_region(card->iobase, 256); - /* unregister audio devices */ - for (i = 0; i < NR_AC97; i++) - if (card->ac97_codec[i] != NULL) { - unregister_sound_mixer(card->ac97_codec[i]-> - dev_mixer); - ac97_release_codec(card->ac97_codec[i]); - card->ac97_codec[i] = NULL; - } - unregister_sound_dsp(card->dev_audio); - kfree(card); -} - -#ifdef CONFIG_PM -static int ali_pm_suspend(struct pci_dev *dev, pm_message_t pm_state) -{ - struct ali_card *card = pci_get_drvdata(dev); - struct ali_state *state; - unsigned long flags; - struct dmabuf *dmabuf; - int i, num_ac97; - - if (!card) - return 0; - spin_lock_irqsave(&card->lock, flags); - card->pm_suspended = 1; - for (i = 0; i < NR_HW_CH; i++) { - state = card->states[i]; - if (!state) - continue; - /* this happens only if there are open files */ - dmabuf = &state->dmabuf; - if (dmabuf->enable & DAC_RUNNING || - (dmabuf->count - && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) { - state->pm_saved_dac_rate = dmabuf->rate; - stop_dac(state); - } else { - state->pm_saved_dac_rate = 0; - } - if (dmabuf->enable & ADC_RUNNING) { - state->pm_saved_adc_rate = dmabuf->rate; - stop_adc(state); - } else { - state->pm_saved_adc_rate = 0; - } - dmabuf->ready = 0; - dmabuf->swptr = dmabuf->hwptr = 0; - dmabuf->count = dmabuf->total_bytes = 0; - } - - spin_unlock_irqrestore(&card->lock, flags); - /* save mixer settings */ - for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { - struct ac97_codec *codec = card->ac97_codec[num_ac97]; - if (!codec) - continue; - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if ((supported_mixer(codec, i)) && (codec->read_mixer)) { - card->pm_saved_mixer_settings[i][num_ac97] = codec->read_mixer(codec, i); - } - } - } - pci_save_state(dev); /* XXX do we need this? */ - pci_disable_device(dev); /* disable busmastering */ - pci_set_power_state(dev, 3); /* Zzz. */ - return 0; -} - - -static int ali_pm_resume(struct pci_dev *dev) -{ - int num_ac97, i = 0; - struct ali_card *card = pci_get_drvdata(dev); - pci_enable_device(dev); - pci_restore_state(dev); - /* observation of a toshiba portege 3440ct suggests that the - hardware has to be more or less completely reinitialized from - scratch after an apm suspend. Works For Me. -dan */ - ali_ac97_random_init_stuff(card); - for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { - struct ac97_codec *codec = card->ac97_codec[num_ac97]; - /* check they haven't stolen the hardware while we were - away */ - if (!codec || !ali_ac97_exists(card, num_ac97)) { - if (num_ac97) - continue; - else - BUG(); - } - if (!ali_ac97_probe_and_powerup(card, codec)) - BUG(); - if ((card->ac97_features & 0x0001)) { - /* at probe time we found we could do variable - rates, but APM suspend has made it forget - its magical powers */ - if (!ali_ac97_enable_variable_rate(codec)) - BUG(); - } - /* we lost our mixer settings, so restore them */ - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (supported_mixer(codec, i)) { - int val = card->pm_saved_mixer_settings[i][num_ac97]; - codec->mixer_state[i] = val; - codec->write_mixer(codec, i, - (val & 0xff), - ((val >> 8) & 0xff)); - } - } - } - - /* we need to restore the sample rate from whatever it was */ - for (i = 0; i < NR_HW_CH; i++) { - struct ali_state *state = card->states[i]; - if (state) { - if (state->pm_saved_adc_rate) - ali_set_adc_rate(state, state->pm_saved_adc_rate); - if (state->pm_saved_dac_rate) - ali_set_dac_rate(state, state->pm_saved_dac_rate); - } - } - - card->pm_suspended = 0; - /* any processes that were reading/writing during the suspend - probably ended up here */ - for (i = 0; i < NR_HW_CH; i++) { - struct ali_state *state = card->states[i]; - if (state) - wake_up(&state->dmabuf.wait); - } - return 0; -} -#endif /* CONFIG_PM */ - -MODULE_AUTHOR(""); -MODULE_DESCRIPTION("ALI 5455 audio support"); -MODULE_LICENSE("GPL"); -module_param(clocking, int, 0); -/* FIXME: bool? */ -module_param(strict_clocking, uint, 0); -module_param(codec_pcmout_share_spdif_locked, uint, 0); -module_param(codec_independent_spdif_locked, uint, 0); -module_param(controller_pcmout_share_spdif_locked, uint, 0); -module_param(controller_independent_spdif_locked, uint, 0); -#define ALI5455_MODULE_NAME "ali5455" -static struct pci_driver ali_pci_driver = { - .name = ALI5455_MODULE_NAME, - .id_table = ali_pci_tbl, - .probe = ali_probe, - .remove = __devexit_p(ali_remove), -#ifdef CONFIG_PM - .suspend = ali_pm_suspend, - .resume = ali_pm_resume, -#endif /* CONFIG_PM */ -}; - -static int __init ali_init_module(void) -{ - printk(KERN_INFO "ALI 5455 + AC97 Audio, version " - DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); - - if (codec_independent_spdif_locked > 0) { - if (codec_independent_spdif_locked == 32000 - || codec_independent_spdif_locked == 44100 - || codec_independent_spdif_locked == 48000) { - printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_independent_spdif_locked); - } else { - printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n"); - codec_independent_spdif_locked = 0; - } - } - if (controller_independent_spdif_locked > 0) { - if (controller_independent_spdif_locked == 32000 - || controller_independent_spdif_locked == 44100 - || controller_independent_spdif_locked == 48000) { - printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", controller_independent_spdif_locked); - } else { - printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n"); - controller_independent_spdif_locked = 0; - } - } - - if (codec_pcmout_share_spdif_locked > 0) { - if (codec_pcmout_share_spdif_locked == 32000 - || codec_pcmout_share_spdif_locked == 44100 - || codec_pcmout_share_spdif_locked == 48000) { - printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_pcmout_share_spdif_locked); - } else { - printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n"); - codec_pcmout_share_spdif_locked = 0; - } - } - if (controller_pcmout_share_spdif_locked > 0) { - if (controller_pcmout_share_spdif_locked == 32000 - || controller_pcmout_share_spdif_locked == 44100 - || controller_pcmout_share_spdif_locked == 48000) { - printk(KERN_INFO "ali_audio: Enabling controller S/PDIF at sample rate %dHz.\n", controller_pcmout_share_spdif_locked); - } else { - printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n"); - controller_pcmout_share_spdif_locked = 0; - } - } - return pci_register_driver(&ali_pci_driver); -} - -static void __exit ali_cleanup_module(void) -{ - pci_unregister_driver(&ali_pci_driver); -} - -module_init(ali_init_module); -module_exit(ali_cleanup_module); -/* -Local Variables: -c-basic-offset: 8 -End: -*/ diff --git a/sound/oss/au1000.c b/sound/oss/au1000.c deleted file mode 100644 index e3796231452a..000000000000 --- a/sound/oss/au1000.c +++ /dev/null @@ -1,2216 +0,0 @@ -/* - * au1000.c -- Sound driver for Alchemy Au1000 MIPS Internet Edge - * Processor. - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * stevel@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * Module command line parameters: - * - * Supported devices: - * /dev/dsp standard OSS /dev/dsp device - * /dev/mixer standard OSS /dev/mixer device - * - * Notes: - * - * 1. Much of the OSS buffer allocation, ioctl's, and mmap'ing are - * taken, slightly modified or not at all, from the ES1371 driver, - * so refer to the credits in es1371.c for those. The rest of the - * code (probe, open, read, write, the ISR, etc.) is new. - * - * Revision history - * 06.27.2001 Initial version - * 03.20.2002 Added mutex locks around read/write methods, to prevent - * simultaneous access on SMP or preemptible kernels. Also - * removed the counter/pointer fragment aligning at the end - * of read/write methods [stevel]. - * 03.21.2002 Add support for coherent DMA on the audio read/write DMA - * channels [stevel]. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* --------------------------------------------------------------------- */ - -#undef OSS_DOCUMENTED_MIXER_SEMANTICS -#undef AU1000_DEBUG -#undef AU1000_VERBOSE_DEBUG - -#define AU1000_MODULE_NAME "Au1000 audio" -#define PFX AU1000_MODULE_NAME - -#ifdef AU1000_DEBUG -#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) -#else -#define dbg(format, arg...) do {} while (0) -#endif -#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) -#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) -#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) - - -/* misc stuff */ -#define POLL_COUNT 0x5000 -#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC) - -/* Boot options */ -static int vra = 0; // 0 = no VRA, 1 = use VRA if codec supports it -module_param(vra, bool, 0); -MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); - - -/* --------------------------------------------------------------------- */ - -struct au1000_state { - /* soundcore stuff */ - int dev_audio; - -#ifdef AU1000_DEBUG - /* debug /proc entry */ - struct proc_dir_entry *ps; - struct proc_dir_entry *ac97_ps; -#endif /* AU1000_DEBUG */ - - struct ac97_codec codec; - unsigned codec_base_caps;// AC'97 reg 00h, "Reset Register" - unsigned codec_ext_caps; // AC'97 reg 28h, "Extended Audio ID" - int no_vra; // do not use VRA - - spinlock_t lock; - struct mutex open_mutex; - struct mutex sem; - mode_t open_mode; - wait_queue_head_t open_wait; - - struct dmabuf { - unsigned int dmanr; // DMA Channel number - unsigned sample_rate; // Hz - unsigned src_factor; // SRC interp/decimation (no vra) - unsigned sample_size; // 8 or 16 - int num_channels; // 1 = mono, 2 = stereo, 4, 6 - int dma_bytes_per_sample;// DMA bytes per audio sample frame - int user_bytes_per_sample;// User bytes per audio sample frame - int cnt_factor; // user-to-DMA bytes per audio - // sample frame - void *rawbuf; - dma_addr_t dmaaddr; - unsigned buforder; - unsigned numfrag; // # of DMA fragments in DMA buffer - unsigned fragshift; - void *nextIn; // ptr to next-in to DMA buffer - void *nextOut;// ptr to next-out from DMA buffer - int count; // current byte count in DMA buffer - unsigned total_bytes; // total bytes written or read - unsigned error; // over/underrun - wait_queue_head_t wait; - /* redundant, but makes calculations easier */ - unsigned fragsize; // user perception of fragment size - unsigned dma_fragsize; // DMA (real) fragment size - unsigned dmasize; // Total DMA buffer size - // (mult. of DMA fragsize) - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned stopped:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac , dma_adc; -} au1000_state; - -/* --------------------------------------------------------------------- */ - - -static inline unsigned ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -/* --------------------------------------------------------------------- */ - -static void au1000_delay(int msec) -{ - unsigned long tmo; - signed long tmo2; - - if (in_interrupt()) - return; - - tmo = jiffies + (msec * HZ) / 1000; - for (;;) { - tmo2 = tmo - jiffies; - if (tmo2 <= 0) - break; - schedule_timeout(tmo2); - } -} - - -/* --------------------------------------------------------------------- */ - -static u16 rdcodec(struct ac97_codec *codec, u8 addr) -{ - struct au1000_state *s = (struct au1000_state *)codec->private_data; - unsigned long flags; - u32 cmd; - u16 data; - int i; - - spin_lock_irqsave(&s->lock, flags); - - for (i = 0; i < POLL_COUNT; i++) - if (!(au_readl(AC97C_STATUS) & AC97C_CP)) - break; - if (i == POLL_COUNT) - err("rdcodec: codec cmd pending expired!"); - - cmd = (u32) addr & AC97C_INDEX_MASK; - cmd |= AC97C_READ; // read command - au_writel(cmd, AC97C_CMD); - - /* now wait for the data */ - for (i = 0; i < POLL_COUNT; i++) - if (!(au_readl(AC97C_STATUS) & AC97C_CP)) - break; - if (i == POLL_COUNT) { - err("rdcodec: read poll expired!"); - return 0; - } - - data = au_readl(AC97C_CMD) & 0xffff; - - spin_unlock_irqrestore(&s->lock, flags); - - return data; -} - - -static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data) -{ - struct au1000_state *s = (struct au1000_state *)codec->private_data; - unsigned long flags; - u32 cmd; - int i; - - spin_lock_irqsave(&s->lock, flags); - - for (i = 0; i < POLL_COUNT; i++) - if (!(au_readl(AC97C_STATUS) & AC97C_CP)) - break; - if (i == POLL_COUNT) - err("wrcodec: codec cmd pending expired!"); - - cmd = (u32) addr & AC97C_INDEX_MASK; - cmd &= ~AC97C_READ; // write command - cmd |= ((u32) data << AC97C_WD_BIT); // OR in the data word - au_writel(cmd, AC97C_CMD); - - spin_unlock_irqrestore(&s->lock, flags); -} - -static void waitcodec(struct ac97_codec *codec) -{ - u16 temp; - int i; - - /* codec_wait is used to wait for a ready state after - an AC97C_RESET. */ - au1000_delay(10); - - // first poll the CODEC_READY tag bit - for (i = 0; i < POLL_COUNT; i++) - if (au_readl(AC97C_STATUS) & AC97C_READY) - break; - if (i == POLL_COUNT) { - err("waitcodec: CODEC_READY poll expired!"); - return; - } - // get AC'97 powerdown control/status register - temp = rdcodec(codec, AC97_POWER_CONTROL); - - // If anything is powered down, power'em up - if (temp & 0x7f00) { - // Power on - wrcodec(codec, AC97_POWER_CONTROL, 0); - au1000_delay(100); - // Reread - temp = rdcodec(codec, AC97_POWER_CONTROL); - } - - // Check if Codec REF,ANL,DAC,ADC ready - if ((temp & 0x7f0f) != 0x000f) - err("codec reg 26 status (0x%x) not ready!!", temp); -} - - -/* --------------------------------------------------------------------- */ - -/* stop the ADC before calling */ -static void set_adc_rate(struct au1000_state *s, unsigned rate) -{ - struct dmabuf *adc = &s->dma_adc; - struct dmabuf *dac = &s->dma_dac; - unsigned adc_rate, dac_rate; - u16 ac97_extstat; - - if (s->no_vra) { - // calc SRC factor - adc->src_factor = ((96000 / rate) + 1) >> 1; - adc->sample_rate = 48000 / adc->src_factor; - return; - } - - adc->src_factor = 1; - - ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS); - - rate = rate > 48000 ? 48000 : rate; - - // enable VRA - wrcodec(&s->codec, AC97_EXTENDED_STATUS, - ac97_extstat | AC97_EXTSTAT_VRA); - // now write the sample rate - wrcodec(&s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate); - // read it back for actual supported rate - adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE); - -#ifdef AU1000_VERBOSE_DEBUG - dbg("%s: set to %d Hz", __FUNCTION__, adc_rate); -#endif - - // some codec's don't allow unequal DAC and ADC rates, in which case - // writing one rate reg actually changes both. - dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE); - if (dac->num_channels > 2) - wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate); - if (dac->num_channels > 4) - wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate); - - adc->sample_rate = adc_rate; - dac->sample_rate = dac_rate; -} - -/* stop the DAC before calling */ -static void set_dac_rate(struct au1000_state *s, unsigned rate) -{ - struct dmabuf *dac = &s->dma_dac; - struct dmabuf *adc = &s->dma_adc; - unsigned adc_rate, dac_rate; - u16 ac97_extstat; - - if (s->no_vra) { - // calc SRC factor - dac->src_factor = ((96000 / rate) + 1) >> 1; - dac->sample_rate = 48000 / dac->src_factor; - return; - } - - dac->src_factor = 1; - - ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS); - - rate = rate > 48000 ? 48000 : rate; - - // enable VRA - wrcodec(&s->codec, AC97_EXTENDED_STATUS, - ac97_extstat | AC97_EXTSTAT_VRA); - // now write the sample rate - wrcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate); - // I don't support different sample rates for multichannel, - // so make these channels the same. - if (dac->num_channels > 2) - wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate); - if (dac->num_channels > 4) - wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate); - // read it back for actual supported rate - dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE); - -#ifdef AU1000_VERBOSE_DEBUG - dbg("%s: set to %d Hz", __FUNCTION__, dac_rate); -#endif - - // some codec's don't allow unequal DAC and ADC rates, in which case - // writing one rate reg actually changes both. - adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE); - - dac->sample_rate = dac_rate; - adc->sample_rate = adc_rate; -} - -static void stop_dac(struct au1000_state *s) -{ - struct dmabuf *db = &s->dma_dac; - unsigned long flags; - - if (db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - disable_dma(db->dmanr); - - db->stopped = 1; - - spin_unlock_irqrestore(&s->lock, flags); -} - -static void stop_adc(struct au1000_state *s) -{ - struct dmabuf *db = &s->dma_adc; - unsigned long flags; - - if (db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - disable_dma(db->dmanr); - - db->stopped = 1; - - spin_unlock_irqrestore(&s->lock, flags); -} - - -static void set_xmit_slots(int num_channels) -{ - u32 ac97_config = au_readl(AC97C_CONFIG) & ~AC97C_XMIT_SLOTS_MASK; - - switch (num_channels) { - case 1: // mono - case 2: // stereo, slots 3,4 - ac97_config |= (0x3 << AC97C_XMIT_SLOTS_BIT); - break; - case 4: // stereo with surround, slots 3,4,7,8 - ac97_config |= (0x33 << AC97C_XMIT_SLOTS_BIT); - break; - case 6: // stereo with surround and center/LFE, slots 3,4,6,7,8,9 - ac97_config |= (0x7b << AC97C_XMIT_SLOTS_BIT); - break; - } - - au_writel(ac97_config, AC97C_CONFIG); -} - -static void set_recv_slots(int num_channels) -{ - u32 ac97_config = au_readl(AC97C_CONFIG) & ~AC97C_RECV_SLOTS_MASK; - - /* - * Always enable slots 3 and 4 (stereo). Slot 6 is - * optional Mic ADC, which I don't support yet. - */ - ac97_config |= (0x3 << AC97C_RECV_SLOTS_BIT); - - au_writel(ac97_config, AC97C_CONFIG); -} - -static void start_dac(struct au1000_state *s) -{ - struct dmabuf *db = &s->dma_dac; - unsigned long flags; - unsigned long buf1, buf2; - - if (!db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - au_readl(AC97C_STATUS); // read status to clear sticky bits - - // reset Buffer 1 and 2 pointers to nextOut and nextOut+dma_fragsize - buf1 = virt_to_phys(db->nextOut); - buf2 = buf1 + db->dma_fragsize; - if (buf2 >= db->dmaaddr + db->dmasize) - buf2 -= db->dmasize; - - set_xmit_slots(db->num_channels); - - init_dma(db->dmanr); - if (get_dma_active_buffer(db->dmanr) == 0) { - clear_dma_done0(db->dmanr); // clear DMA done bit - set_dma_addr0(db->dmanr, buf1); - set_dma_addr1(db->dmanr, buf2); - } else { - clear_dma_done1(db->dmanr); // clear DMA done bit - set_dma_addr1(db->dmanr, buf1); - set_dma_addr0(db->dmanr, buf2); - } - set_dma_count(db->dmanr, db->dma_fragsize>>1); - enable_dma_buffers(db->dmanr); - - start_dma(db->dmanr); - -#ifdef AU1000_VERBOSE_DEBUG - dump_au1000_dma_channel(db->dmanr); -#endif - - db->stopped = 0; - - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_adc(struct au1000_state *s) -{ - struct dmabuf *db = &s->dma_adc; - unsigned long flags; - unsigned long buf1, buf2; - - if (!db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - au_readl(AC97C_STATUS); // read status to clear sticky bits - - // reset Buffer 1 and 2 pointers to nextIn and nextIn+dma_fragsize - buf1 = virt_to_phys(db->nextIn); - buf2 = buf1 + db->dma_fragsize; - if (buf2 >= db->dmaaddr + db->dmasize) - buf2 -= db->dmasize; - - set_recv_slots(db->num_channels); - - init_dma(db->dmanr); - if (get_dma_active_buffer(db->dmanr) == 0) { - clear_dma_done0(db->dmanr); // clear DMA done bit - set_dma_addr0(db->dmanr, buf1); - set_dma_addr1(db->dmanr, buf2); - } else { - clear_dma_done1(db->dmanr); // clear DMA done bit - set_dma_addr1(db->dmanr, buf1); - set_dma_addr0(db->dmanr, buf2); - } - set_dma_count(db->dmanr, db->dma_fragsize>>1); - enable_dma_buffers(db->dmanr); - - start_dma(db->dmanr); - -#ifdef AU1000_VERBOSE_DEBUG - dump_au1000_dma_channel(db->dmanr); -#endif - - db->stopped = 0; - - spin_unlock_irqrestore(&s->lock, flags); -} - -/* --------------------------------------------------------------------- */ - -#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - -static inline void dealloc_dmabuf(struct au1000_state *s, struct dmabuf *db) -{ - struct page *page, *pend; - - if (db->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(db->rawbuf + - (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - ClearPageReserved(page); - dma_free_noncoherent(NULL, - PAGE_SIZE << db->buforder, - db->rawbuf, - db->dmaaddr); - } - db->rawbuf = db->nextIn = db->nextOut = NULL; - db->mapped = db->ready = 0; -} - -static int prog_dmabuf(struct au1000_state *s, struct dmabuf *db) -{ - int order; - unsigned user_bytes_per_sec; - unsigned bufs; - struct page *page, *pend; - unsigned rate = db->sample_rate; - - if (!db->rawbuf) { - db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; - order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = dma_alloc_noncoherent(NULL, - PAGE_SIZE << order, - &db->dmaaddr, - 0))) - break; - if (!db->rawbuf) - return -ENOMEM; - db->buforder = order; - /* now mark the pages as reserved; - otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(db->rawbuf + - (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - SetPageReserved(page); - } - - db->cnt_factor = 1; - if (db->sample_size == 8) - db->cnt_factor *= 2; - if (db->num_channels == 1) - db->cnt_factor *= 2; - db->cnt_factor *= db->src_factor; - - db->count = 0; - db->nextIn = db->nextOut = db->rawbuf; - - db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels; - db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ? - 2 : db->num_channels); - - user_bytes_per_sec = rate * db->user_bytes_per_sample; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < user_bytes_per_sec) - db->fragshift = ld2(user_bytes_per_sec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(user_bytes_per_sec / 100 / - (db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - - db->fragsize = 1 << db->fragshift; - db->dma_fragsize = db->fragsize * db->cnt_factor; - db->numfrag = bufs / db->dma_fragsize; - - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->fragsize = 1 << db->fragshift; - db->dma_fragsize = db->fragsize * db->cnt_factor; - db->numfrag = bufs / db->dma_fragsize; - } - - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - - db->dmasize = db->dma_fragsize * db->numfrag; - memset(db->rawbuf, 0, bufs); - -#ifdef AU1000_VERBOSE_DEBUG - dbg("rate=%d, samplesize=%d, channels=%d", - rate, db->sample_size, db->num_channels); - dbg("fragsize=%d, cnt_factor=%d, dma_fragsize=%d", - db->fragsize, db->cnt_factor, db->dma_fragsize); - dbg("numfrag=%d, dmasize=%d", db->numfrag, db->dmasize); -#endif - - db->ready = 1; - return 0; -} - -static inline int prog_dmabuf_adc(struct au1000_state *s) -{ - stop_adc(s); - return prog_dmabuf(s, &s->dma_adc); - -} - -static inline int prog_dmabuf_dac(struct au1000_state *s) -{ - stop_dac(s); - return prog_dmabuf(s, &s->dma_dac); -} - - -/* hold spinlock for the following */ -static irqreturn_t dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct au1000_state *s = (struct au1000_state *) dev_id; - struct dmabuf *dac = &s->dma_dac; - unsigned long newptr; - u32 ac97c_stat, buff_done; - - ac97c_stat = au_readl(AC97C_STATUS); -#ifdef AU1000_VERBOSE_DEBUG - if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE)) - dbg("AC97C status = 0x%08x", ac97c_stat); -#endif - - if ((buff_done = get_dma_buffer_done(dac->dmanr)) == 0) { - /* fastpath out, to ease interrupt sharing */ - return IRQ_HANDLED; - } - - spin_lock(&s->lock); - - if (buff_done != (DMA_D0 | DMA_D1)) { - dac->nextOut += dac->dma_fragsize; - if (dac->nextOut >= dac->rawbuf + dac->dmasize) - dac->nextOut -= dac->dmasize; - - /* update playback pointers */ - newptr = virt_to_phys(dac->nextOut) + dac->dma_fragsize; - if (newptr >= dac->dmaaddr + dac->dmasize) - newptr -= dac->dmasize; - - dac->count -= dac->dma_fragsize; - dac->total_bytes += dac->dma_fragsize; - - if (dac->count <= 0) { -#ifdef AU1000_VERBOSE_DEBUG - dbg("dac underrun"); -#endif - spin_unlock(&s->lock); - stop_dac(s); - spin_lock(&s->lock); - dac->count = 0; - dac->nextIn = dac->nextOut; - } else if (buff_done == DMA_D0) { - clear_dma_done0(dac->dmanr); // clear DMA done bit - set_dma_count0(dac->dmanr, dac->dma_fragsize>>1); - set_dma_addr0(dac->dmanr, newptr); - enable_dma_buffer0(dac->dmanr); // reenable - } else { - clear_dma_done1(dac->dmanr); // clear DMA done bit - set_dma_count1(dac->dmanr, dac->dma_fragsize>>1); - set_dma_addr1(dac->dmanr, newptr); - enable_dma_buffer1(dac->dmanr); // reenable - } - } else { - // both done bits set, we missed an interrupt - spin_unlock(&s->lock); - stop_dac(s); - spin_lock(&s->lock); - - dac->nextOut += 2*dac->dma_fragsize; - if (dac->nextOut >= dac->rawbuf + dac->dmasize) - dac->nextOut -= dac->dmasize; - - dac->count -= 2*dac->dma_fragsize; - dac->total_bytes += 2*dac->dma_fragsize; - - if (dac->count > 0) { - spin_unlock(&s->lock); - start_dac(s); - spin_lock(&s->lock); - } - } - - /* wake up anybody listening */ - if (waitqueue_active(&dac->wait)) - wake_up(&dac->wait); - - spin_unlock(&s->lock); - - return IRQ_HANDLED; -} - - -static irqreturn_t adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct au1000_state *s = (struct au1000_state *) dev_id; - struct dmabuf *adc = &s->dma_adc; - unsigned long newptr; - u32 ac97c_stat, buff_done; - - ac97c_stat = au_readl(AC97C_STATUS); -#ifdef AU1000_VERBOSE_DEBUG - if (ac97c_stat & (AC97C_RU | AC97C_RO)) - dbg("AC97C status = 0x%08x", ac97c_stat); -#endif - - if ((buff_done = get_dma_buffer_done(adc->dmanr)) == 0) { - /* fastpath out, to ease interrupt sharing */ - return IRQ_HANDLED; - } - - spin_lock(&s->lock); - - if (buff_done != (DMA_D0 | DMA_D1)) { - if (adc->count + adc->dma_fragsize > adc->dmasize) { - // Overrun. Stop ADC and log the error - spin_unlock(&s->lock); - stop_adc(s); - adc->error++; - err("adc overrun"); - return IRQ_NONE; - } - - adc->nextIn += adc->dma_fragsize; - if (adc->nextIn >= adc->rawbuf + adc->dmasize) - adc->nextIn -= adc->dmasize; - - /* update capture pointers */ - newptr = virt_to_phys(adc->nextIn) + adc->dma_fragsize; - if (newptr >= adc->dmaaddr + adc->dmasize) - newptr -= adc->dmasize; - - adc->count += adc->dma_fragsize; - adc->total_bytes += adc->dma_fragsize; - - if (buff_done == DMA_D0) { - clear_dma_done0(adc->dmanr); // clear DMA done bit - set_dma_count0(adc->dmanr, adc->dma_fragsize>>1); - set_dma_addr0(adc->dmanr, newptr); - enable_dma_buffer0(adc->dmanr); // reenable - } else { - clear_dma_done1(adc->dmanr); // clear DMA done bit - set_dma_count1(adc->dmanr, adc->dma_fragsize>>1); - set_dma_addr1(adc->dmanr, newptr); - enable_dma_buffer1(adc->dmanr); // reenable - } - } else { - // both done bits set, we missed an interrupt - spin_unlock(&s->lock); - stop_adc(s); - spin_lock(&s->lock); - - if (adc->count + 2*adc->dma_fragsize > adc->dmasize) { - // Overrun. Log the error - adc->error++; - err("adc overrun"); - spin_unlock(&s->lock); - return IRQ_NONE; - } - - adc->nextIn += 2*adc->dma_fragsize; - if (adc->nextIn >= adc->rawbuf + adc->dmasize) - adc->nextIn -= adc->dmasize; - - adc->count += 2*adc->dma_fragsize; - adc->total_bytes += 2*adc->dma_fragsize; - - spin_unlock(&s->lock); - start_adc(s); - spin_lock(&s->lock); - } - - /* wake up anybody listening */ - if (waitqueue_active(&adc->wait)) - wake_up(&adc->wait); - - spin_unlock(&s->lock); - - return IRQ_HANDLED; -} - -/* --------------------------------------------------------------------- */ - -static loff_t au1000_llseek(struct file *file, loff_t offset, int origin) -{ - return -ESPIPE; -} - - -static int au1000_open_mixdev(struct inode *inode, struct file *file) -{ - file->private_data = &au1000_state; - return nonseekable_open(inode, file); -} - -static int au1000_release_mixdev(struct inode *inode, struct file *file) -{ - return 0; -} - -static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, - unsigned long arg) -{ - return codec->mixer_ioctl(codec, cmd, arg); -} - -static int au1000_ioctl_mixdev(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct au1000_state *s = (struct au1000_state *)file->private_data; - struct ac97_codec *codec = &s->codec; - - return mixdev_ioctl(codec, cmd, arg); -} - -static /*const */ struct file_operations au1000_mixer_fops = { - .owner = THIS_MODULE, - .llseek = au1000_llseek, - .ioctl = au1000_ioctl_mixdev, - .open = au1000_open_mixdev, - .release = au1000_release_mixdev, -}; - -/* --------------------------------------------------------------------- */ - -static int drain_dac(struct au1000_state *s, int nonblock) -{ - unsigned long flags; - int count, tmo; - - if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped) - return 0; - - for (;;) { - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) - return -EBUSY; - tmo = 1000 * count / (s->no_vra ? - 48000 : s->dma_dac.sample_rate); - tmo /= s->dma_dac.dma_bytes_per_sample; - au1000_delay(tmo); - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static inline u8 S16_TO_U8(s16 ch) -{ - return (u8) (ch >> 8) + 0x80; -} -static inline s16 U8_TO_S16(u8 ch) -{ - return (s16) (ch - 0x80) << 8; -} - -/* - * Translates user samples to dma buffer suitable for AC'97 DAC data: - * If mono, copy left channel to right channel in dma buffer. - * If 8 bit samples, cvt to 16-bit before writing to dma buffer. - * If interpolating (no VRA), duplicate every audio frame src_factor times. - */ -static int translate_from_user(struct dmabuf *db, - char* dmabuf, - char* userbuf, - int dmacount) -{ - int sample, i; - int interp_bytes_per_sample; - int num_samples; - int mono = (db->num_channels == 1); - char usersample[12]; - s16 ch, dmasample[6]; - - if (db->sample_size == 16 && !mono && db->src_factor == 1) { - // no translation necessary, just copy - if (copy_from_user(dmabuf, userbuf, dmacount)) - return -EFAULT; - return dmacount; - } - - interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor; - num_samples = dmacount / interp_bytes_per_sample; - - for (sample = 0; sample < num_samples; sample++) { - if (copy_from_user(usersample, userbuf, - db->user_bytes_per_sample)) { - dbg("%s: fault", __FUNCTION__); - return -EFAULT; - } - - for (i = 0; i < db->num_channels; i++) { - if (db->sample_size == 8) - ch = U8_TO_S16(usersample[i]); - else - ch = *((s16 *) (&usersample[i * 2])); - dmasample[i] = ch; - if (mono) - dmasample[i + 1] = ch; // right channel - } - - // duplicate every audio frame src_factor times - for (i = 0; i < db->src_factor; i++) - memcpy(dmabuf, dmasample, db->dma_bytes_per_sample); - - userbuf += db->user_bytes_per_sample; - dmabuf += interp_bytes_per_sample; - } - - return num_samples * interp_bytes_per_sample; -} - -/* - * Translates AC'97 ADC samples to user buffer: - * If mono, send only left channel to user buffer. - * If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer. - * If decimating (no VRA), skip over src_factor audio frames. - */ -static int translate_to_user(struct dmabuf *db, - char* userbuf, - char* dmabuf, - int dmacount) -{ - int sample, i; - int interp_bytes_per_sample; - int num_samples; - int mono = (db->num_channels == 1); - char usersample[12]; - - if (db->sample_size == 16 && !mono && db->src_factor == 1) { - // no translation necessary, just copy - if (copy_to_user(userbuf, dmabuf, dmacount)) - return -EFAULT; - return dmacount; - } - - interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor; - num_samples = dmacount / interp_bytes_per_sample; - - for (sample = 0; sample < num_samples; sample++) { - for (i = 0; i < db->num_channels; i++) { - if (db->sample_size == 8) - usersample[i] = - S16_TO_U8(*((s16 *) (&dmabuf[i * 2]))); - else - *((s16 *) (&usersample[i * 2])) = - *((s16 *) (&dmabuf[i * 2])); - } - - if (copy_to_user(userbuf, usersample, - db->user_bytes_per_sample)) { - dbg("%s: fault", __FUNCTION__); - return -EFAULT; - } - - userbuf += db->user_bytes_per_sample; - dmabuf += interp_bytes_per_sample; - } - - return num_samples * interp_bytes_per_sample; -} - -/* - * Copy audio data to/from user buffer from/to dma buffer, taking care - * that we wrap when reading/writing the dma buffer. Returns actual byte - * count written to or read from the dma buffer. - */ -static int copy_dmabuf_user(struct dmabuf *db, char* userbuf, - int count, int to_user) -{ - char *bufptr = to_user ? db->nextOut : db->nextIn; - char *bufend = db->rawbuf + db->dmasize; - int cnt, ret; - - if (bufptr + count > bufend) { - int partial = (int) (bufend - bufptr); - if (to_user) { - if ((cnt = translate_to_user(db, userbuf, - bufptr, partial)) < 0) - return cnt; - ret = cnt; - if ((cnt = translate_to_user(db, userbuf + partial, - db->rawbuf, - count - partial)) < 0) - return cnt; - ret += cnt; - } else { - if ((cnt = translate_from_user(db, bufptr, userbuf, - partial)) < 0) - return cnt; - ret = cnt; - if ((cnt = translate_from_user(db, db->rawbuf, - userbuf + partial, - count - partial)) < 0) - return cnt; - ret += cnt; - } - } else { - if (to_user) - ret = translate_to_user(db, userbuf, bufptr, count); - else - ret = translate_from_user(db, bufptr, userbuf, count); - } - - return ret; -} - - -static ssize_t au1000_read(struct file *file, char *buffer, - size_t count, loff_t *ppos) -{ - struct au1000_state *s = (struct au1000_state *)file->private_data; - struct dmabuf *db = &s->dma_adc; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - int cnt, usercnt, avail; - - if (db->mapped) - return -ENXIO; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - - count *= db->cnt_factor; - - mutex_lock(&s->sem); - add_wait_queue(&db->wait, &wait); - - while (count > 0) { - // wait for samples in ADC dma buffer - do { - if (db->stopped) - start_adc(s); - spin_lock_irqsave(&s->lock, flags); - avail = db->count; - if (avail <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (avail <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->sem); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out2; - } - mutex_lock(&s->sem); - } - } while (avail <= 0); - - // copy from nextOut to user - if ((cnt = copy_dmabuf_user(db, buffer, - count > avail ? - avail : count, 1)) < 0) { - if (!ret) - ret = -EFAULT; - goto out; - } - - spin_lock_irqsave(&s->lock, flags); - db->count -= cnt; - db->nextOut += cnt; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - spin_unlock_irqrestore(&s->lock, flags); - - count -= cnt; - usercnt = cnt / db->cnt_factor; - buffer += usercnt; - ret += usercnt; - } // while (count > 0) - -out: - mutex_unlock(&s->sem); -out2: - remove_wait_queue(&db->wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -static ssize_t au1000_write(struct file *file, const char *buffer, - size_t count, loff_t * ppos) -{ - struct au1000_state *s = (struct au1000_state *)file->private_data; - struct dmabuf *db = &s->dma_dac; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - int cnt, usercnt, avail; - -#ifdef AU1000_VERBOSE_DEBUG - dbg("write: count=%d", count); -#endif - - if (db->mapped) - return -ENXIO; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - - count *= db->cnt_factor; - - mutex_lock(&s->sem); - add_wait_queue(&db->wait, &wait); - - while (count > 0) { - // wait for space in playback buffer - do { - spin_lock_irqsave(&s->lock, flags); - avail = (int) db->dmasize - db->count; - if (avail <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (avail <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->sem); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out2; - } - mutex_lock(&s->sem); - } - } while (avail <= 0); - - // copy from user to nextIn - if ((cnt = copy_dmabuf_user(db, (char *) buffer, - count > avail ? - avail : count, 0)) < 0) { - if (!ret) - ret = -EFAULT; - goto out; - } - - spin_lock_irqsave(&s->lock, flags); - db->count += cnt; - db->nextIn += cnt; - if (db->nextIn >= db->rawbuf + db->dmasize) - db->nextIn -= db->dmasize; - spin_unlock_irqrestore(&s->lock, flags); - if (db->stopped) - start_dac(s); - - count -= cnt; - usercnt = cnt / db->cnt_factor; - buffer += usercnt; - ret += usercnt; - } // while (count > 0) - -out: - mutex_unlock(&s->sem); -out2: - remove_wait_queue(&db->wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - - -/* No kernel lock - we have our own spinlock */ -static unsigned int au1000_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct au1000_state *s = (struct au1000_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac.ready) - return 0; - poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - - spin_lock_irqsave(&s->lock, flags); - - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= - (signed)s->dma_dac.dma_fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed) s->dma_dac.dmasize >= - s->dma_dac.count + (signed)s->dma_dac.dma_fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int au1000_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct au1000_state *s = (struct au1000_state *)file->private_data; - struct dmabuf *db; - unsigned long size; - int ret = 0; - - dbg("%s", __FUNCTION__); - - lock_kernel(); - mutex_lock(&s->sem); - if (vma->vm_flags & VM_WRITE) - db = &s->dma_dac; - else if (vma->vm_flags & VM_READ) - db = &s->dma_adc; - else { - ret = -EINVAL; - goto out; - } - if (vma->vm_pgoff != 0) { - ret = -EINVAL; - goto out; - } - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) { - ret = -EINVAL; - goto out; - } - if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), - size, vma->vm_page_prot)) { - ret = -EAGAIN; - goto out; - } - vma->vm_flags &= ~VM_IO; - db->mapped = 1; -out: - mutex_unlock(&s->sem); - unlock_kernel(); - return ret; -} - - -#ifdef AU1000_VERBOSE_DEBUG -static struct ioctl_str_t { - unsigned int cmd; - const char *str; -} ioctl_str[] = { - {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"}, - {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"}, - {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"}, - {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"}, - {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"}, - {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"}, - {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"}, - {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"}, - {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"}, - {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"}, - {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"}, - {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"}, - {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"}, - {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"}, - {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"}, - {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"}, - {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"}, - {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"}, - {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"}, - {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"}, - {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"}, - {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"}, - {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"}, - {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"}, - {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"}, - {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"}, - {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"}, - {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"}, - {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"}, - {OSS_GETVERSION, "OSS_GETVERSION"}, - {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"}, - {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"}, - {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"}, - {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"} -}; -#endif - -// Need to hold a spin-lock before calling this! -static int dma_count_done(struct dmabuf *db) -{ - if (db->stopped) - return 0; - - return db->dma_fragsize - get_dma_residue(db->dmanr); -} - - -static int au1000_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct au1000_state *s = (struct au1000_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, mapped, ret, diff; - - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - -#ifdef AU1000_VERBOSE_DEBUG - for (count=0; countf_mode & FMODE_WRITE) - return drain_dac(s, file->f_flags & O_NONBLOCK); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | - DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(); - s->dma_dac.count = s->dma_dac.total_bytes = 0; - s->dma_dac.nextIn = s->dma_dac.nextOut = - s->dma_dac.rawbuf; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(); - s->dma_adc.count = s->dma_adc.total_bytes = 0; - s->dma_adc.nextIn = s->dma_adc.nextOut = - s->dma_adc.rawbuf; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - set_adc_rate(s, val); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - set_dac_rate(s, val); - } - if (s->open_mode & FMODE_READ) - if ((ret = prog_dmabuf_adc(s))) - return ret; - if (s->open_mode & FMODE_WRITE) - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return put_user((file->f_mode & FMODE_READ) ? - s->dma_adc.sample_rate : - s->dma_dac.sample_rate, - (int *)arg); - - case SNDCTL_DSP_STEREO: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.num_channels = val ? 2 : 1; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.num_channels = val ? 2 : 1; - if (s->codec_ext_caps & AC97_EXT_DACS) { - // disable surround and center/lfe in AC'97 - u16 ext_stat = rdcodec(&s->codec, - AC97_EXTENDED_STATUS); - wrcodec(&s->codec, AC97_EXTENDED_STATUS, - ext_stat | (AC97_EXTSTAT_PRI | - AC97_EXTSTAT_PRJ | - AC97_EXTSTAT_PRK)); - } - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != 0) { - if (file->f_mode & FMODE_READ) { - if (val < 0 || val > 2) - return -EINVAL; - stop_adc(s); - s->dma_adc.num_channels = val; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - switch (val) { - case 1: - case 2: - break; - case 3: - case 5: - return -EINVAL; - case 4: - if (!(s->codec_ext_caps & - AC97_EXTID_SDAC)) - return -EINVAL; - break; - case 6: - if ((s->codec_ext_caps & - AC97_EXT_DACS) != AC97_EXT_DACS) - return -EINVAL; - break; - default: - return -EINVAL; - } - - stop_dac(s); - if (val <= 2 && - (s->codec_ext_caps & AC97_EXT_DACS)) { - // disable surround and center/lfe - // channels in AC'97 - u16 ext_stat = - rdcodec(&s->codec, - AC97_EXTENDED_STATUS); - wrcodec(&s->codec, - AC97_EXTENDED_STATUS, - ext_stat | (AC97_EXTSTAT_PRI | - AC97_EXTSTAT_PRJ | - AC97_EXTSTAT_PRK)); - } else if (val >= 4) { - // enable surround, center/lfe - // channels in AC'97 - u16 ext_stat = - rdcodec(&s->codec, - AC97_EXTENDED_STATUS); - ext_stat &= ~AC97_EXTSTAT_PRJ; - if (val == 6) - ext_stat &= - ~(AC97_EXTSTAT_PRI | - AC97_EXTSTAT_PRK); - wrcodec(&s->codec, - AC97_EXTENDED_STATUS, - ext_stat); - } - - s->dma_dac.num_channels = val; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } - return put_user(val, (int *) arg); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - if (val == AFMT_S16_LE) - s->dma_adc.sample_size = 16; - else { - val = AFMT_U8; - s->dma_adc.sample_size = 8; - } - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - if (val == AFMT_S16_LE) - s->dma_dac.sample_size = 16; - else { - val = AFMT_U8; - s->dma_dac.sample_size = 8; - } - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } else { - if (file->f_mode & FMODE_READ) - val = (s->dma_adc.sample_size == 16) ? - AFMT_S16_LE : AFMT_U8; - else - val = (s->dma_dac.sample_size == 16) ? - AFMT_S16_LE : AFMT_U8; - } - return put_user(val, (int *) arg); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ && !s->dma_adc.stopped) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped) - val |= PCM_ENABLE_OUTPUT; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *) arg); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) - start_adc(s); - else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) - start_dac(s); - else - stop_dac(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - abinfo.fragsize = s->dma_dac.fragsize; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - count -= dma_count_done(&s->dma_dac); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - abinfo.bytes = (s->dma_dac.dmasize - count) / - s->dma_dac.cnt_factor; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; -#ifdef AU1000_VERBOSE_DEBUG - dbg("bytes=%d, fragments=%d", abinfo.bytes, abinfo.fragments); -#endif - return copy_to_user((void *) arg, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - abinfo.fragsize = s->dma_adc.fragsize; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_adc.count; - count += dma_count_done(&s->dma_adc); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - abinfo.bytes = count / s->dma_adc.cnt_factor; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - return copy_to_user((void *) arg, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - count -= dma_count_done(&s->dma_dac); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - count /= s->dma_dac.cnt_factor; - return put_user(count, (int *) arg); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cinfo.bytes = s->dma_adc.total_bytes; - count = s->dma_adc.count; - if (!s->dma_adc.stopped) { - diff = dma_count_done(&s->dma_adc); - count += diff; - cinfo.bytes += diff; - cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) + diff - - s->dma_adc.dmaaddr; - } else - cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) - - s->dma_adc.dmaaddr; - if (s->dma_adc.mapped) - s->dma_adc.count &= (s->dma_adc.dma_fragsize-1); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_adc.fragshift; - return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cinfo.bytes = s->dma_dac.total_bytes; - count = s->dma_dac.count; - if (!s->dma_dac.stopped) { - diff = dma_count_done(&s->dma_dac); - count -= diff; - cinfo.bytes += diff; - cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff - - s->dma_dac.dmaaddr; - } else - cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) - - s->dma_dac.dmaaddr; - if (s->dma_dac.mapped) - s->dma_dac.count &= (s->dma_dac.dma_fragsize-1); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac.fragshift; - return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) - return put_user(s->dma_dac.fragsize, (int *) arg); - else - return put_user(s->dma_adc.fragsize, (int *) arg); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.subdivision = val; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.subdivision = val; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? - s->dma_adc.sample_rate : - s->dma_dac.sample_rate, - (int *)arg); - - case SOUND_PCM_READ_CHANNELS: - if (file->f_mode & FMODE_READ) - return put_user(s->dma_adc.num_channels, (int *)arg); - else - return put_user(s->dma_dac.num_channels, (int *)arg); - - case SOUND_PCM_READ_BITS: - if (file->f_mode & FMODE_READ) - return put_user(s->dma_adc.sample_size, (int *)arg); - else - return put_user(s->dma_dac.sample_size, (int *)arg); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - } - - return mixdev_ioctl(&s->codec, cmd, arg); -} - - -static int au1000_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - struct au1000_state *s = &au1000_state; - int ret; - -#ifdef AU1000_VERBOSE_DEBUG - if (file->f_flags & O_NONBLOCK) - dbg("%s: non-blocking", __FUNCTION__); - else - dbg("%s: blocking", __FUNCTION__); -#endif - - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - - stop_dac(s); - stop_adc(s); - - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = - s->dma_adc.subdivision = s->dma_adc.total_bytes = 0; - s->dma_adc.num_channels = 1; - s->dma_adc.sample_size = 8; - set_adc_rate(s, 8000); - if ((minor & 0xf) == SND_DEV_DSP16) - s->dma_adc.sample_size = 16; - } - - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = - s->dma_dac.subdivision = s->dma_dac.total_bytes = 0; - s->dma_dac.num_channels = 1; - s->dma_dac.sample_size = 8; - set_dac_rate(s, 8000); - if ((minor & 0xf) == SND_DEV_DSP16) - s->dma_dac.sample_size = 16; - } - - if (file->f_mode & FMODE_READ) { - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - mutex_unlock(&s->open_mutex); - mutex_init(&s->sem); - return nonseekable_open(inode, file); -} - -static int au1000_release(struct inode *inode, struct file *file) -{ - struct au1000_state *s = (struct au1000_state *)file->private_data; - - lock_kernel(); - - if (file->f_mode & FMODE_WRITE) { - unlock_kernel(); - drain_dac(s, file->f_flags & O_NONBLOCK); - lock_kernel(); - } - - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - dealloc_dmabuf(s, &s->dma_dac); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - } - s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static /*const */ struct file_operations au1000_audio_fops = { - .owner = THIS_MODULE, - .llseek = au1000_llseek, - .read = au1000_read, - .write = au1000_write, - .poll = au1000_poll, - .ioctl = au1000_ioctl, - .mmap = au1000_mmap, - .open = au1000_open, - .release = au1000_release, -}; - - -/* --------------------------------------------------------------------- */ - - -/* --------------------------------------------------------------------- */ - -/* - * for debugging purposes, we'll create a proc device that dumps the - * CODEC chipstate - */ - -#ifdef AU1000_DEBUG -static int proc_au1000_dump(char *buf, char **start, off_t fpos, - int length, int *eof, void *data) -{ - struct au1000_state *s = &au1000_state; - int cnt, len = 0; - - /* print out header */ - len += sprintf(buf + len, "\n\t\tAU1000 Audio Debug\n\n"); - - // print out digital controller state - len += sprintf(buf + len, "AU1000 Audio Controller registers\n"); - len += sprintf(buf + len, "---------------------------------\n"); - len += sprintf (buf + len, "AC97C_CONFIG = %08x\n", - au_readl(AC97C_CONFIG)); - len += sprintf (buf + len, "AC97C_STATUS = %08x\n", - au_readl(AC97C_STATUS)); - len += sprintf (buf + len, "AC97C_CNTRL = %08x\n", - au_readl(AC97C_CNTRL)); - - /* print out CODEC state */ - len += sprintf(buf + len, "\nAC97 CODEC registers\n"); - len += sprintf(buf + len, "----------------------\n"); - for (cnt = 0; cnt <= 0x7e; cnt += 2) - len += sprintf(buf + len, "reg %02x = %04x\n", - cnt, rdcodec(&s->codec, cnt)); - - if (fpos >= len) { - *start = buf; - *eof = 1; - return 0; - } - *start = buf + fpos; - if ((len -= fpos) > length) - return length; - *eof = 1; - return len; - -} -#endif /* AU1000_DEBUG */ - -/* --------------------------------------------------------------------- */ - -MODULE_AUTHOR("Monta Vista Software, stevel@mvista.com"); -MODULE_DESCRIPTION("Au1000 Audio Driver"); - -/* --------------------------------------------------------------------- */ - -static int __devinit au1000_probe(void) -{ - struct au1000_state *s = &au1000_state; - int val; -#ifdef AU1000_DEBUG - char proc_str[80]; -#endif - - memset(s, 0, sizeof(struct au1000_state)); - - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - mutex_init(&s->open_mutex); - spin_lock_init(&s->lock); - s->codec.private_data = s; - s->codec.id = 0; - s->codec.codec_read = rdcodec; - s->codec.codec_write = wrcodec; - s->codec.codec_wait = waitcodec; - - if (!request_mem_region(CPHYSADDR(AC97C_CONFIG), - 0x14, AU1000_MODULE_NAME)) { - err("AC'97 ports in use"); - return -1; - } - // Allocate the DMA Channels - if ((s->dma_dac.dmanr = request_au1000_dma(DMA_ID_AC97C_TX, - "audio DAC", - dac_dma_interrupt, - IRQF_DISABLED, s)) < 0) { - err("Can't get DAC DMA"); - goto err_dma1; - } - if ((s->dma_adc.dmanr = request_au1000_dma(DMA_ID_AC97C_RX, - "audio ADC", - adc_dma_interrupt, - IRQF_DISABLED, s)) < 0) { - err("Can't get ADC DMA"); - goto err_dma2; - } - - info("DAC: DMA%d/IRQ%d, ADC: DMA%d/IRQ%d", - s->dma_dac.dmanr, get_dma_done_irq(s->dma_dac.dmanr), - s->dma_adc.dmanr, get_dma_done_irq(s->dma_adc.dmanr)); - - // enable DMA coherency in read/write DMA channels - set_dma_mode(s->dma_dac.dmanr, - get_dma_mode(s->dma_dac.dmanr) & ~DMA_NC); - set_dma_mode(s->dma_adc.dmanr, - get_dma_mode(s->dma_adc.dmanr) & ~DMA_NC); - - /* register devices */ - - if ((s->dev_audio = register_sound_dsp(&au1000_audio_fops, -1)) < 0) - goto err_dev1; - if ((s->codec.dev_mixer = - register_sound_mixer(&au1000_mixer_fops, -1)) < 0) - goto err_dev2; - -#ifdef AU1000_DEBUG - /* intialize the debug proc device */ - s->ps = create_proc_read_entry(AU1000_MODULE_NAME, 0, NULL, - proc_au1000_dump, NULL); -#endif /* AU1000_DEBUG */ - - // configure pins for AC'97 - au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC); - - // Assert reset for 10msec to the AC'97 controller, and enable clock - au_writel(AC97C_RS | AC97C_CE, AC97C_CNTRL); - au1000_delay(10); - au_writel(AC97C_CE, AC97C_CNTRL); - au1000_delay(10); // wait for clock to stabilize - - /* cold reset the AC'97 */ - au_writel(AC97C_RESET, AC97C_CONFIG); - au1000_delay(10); - au_writel(0, AC97C_CONFIG); - /* need to delay around 500msec(bleech) to give - some CODECs enough time to wakeup */ - au1000_delay(500); - - /* warm reset the AC'97 to start the bitclk */ - au_writel(AC97C_SG | AC97C_SYNC, AC97C_CONFIG); - udelay(100); - au_writel(0, AC97C_CONFIG); - - /* codec init */ - if (!ac97_probe_codec(&s->codec)) - goto err_dev3; - - s->codec_base_caps = rdcodec(&s->codec, AC97_RESET); - s->codec_ext_caps = rdcodec(&s->codec, AC97_EXTENDED_ID); - info("AC'97 Base/Extended ID = %04x/%04x", - s->codec_base_caps, s->codec_ext_caps); - - /* - * On the Pb1000, audio playback is on the AUX_OUT - * channel (which defaults to LNLVL_OUT in AC'97 - * rev 2.2) so make sure this channel is listed - * as supported (soundcard.h calls this channel - * ALTPCM). ac97_codec.c does not handle detection - * of this channel correctly. - */ - s->codec.supported_mixers |= SOUND_MASK_ALTPCM; - /* - * Now set AUX_OUT's default volume. - */ - val = 0x4343; - mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_ALTPCM, - (unsigned long) &val); - - if (!(s->codec_ext_caps & AC97_EXTID_VRA)) { - // codec does not support VRA - s->no_vra = 1; - } else if (!vra) { - // Boot option says disable VRA - u16 ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS); - wrcodec(&s->codec, AC97_EXTENDED_STATUS, - ac97_extstat & ~AC97_EXTSTAT_VRA); - s->no_vra = 1; - } - if (s->no_vra) - info("no VRA, interpolating and decimating"); - - /* set mic to be the recording source */ - val = SOUND_MASK_MIC; - mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC, - (unsigned long) &val); - -#ifdef AU1000_DEBUG - sprintf(proc_str, "driver/%s/%d/ac97", AU1000_MODULE_NAME, - s->codec.id); - s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL, - ac97_read_proc, &s->codec); -#endif - -#ifdef CONFIG_MIPS_XXS1500 - /* deassert eapd */ - wrcodec(&s->codec, AC97_POWER_CONTROL, - rdcodec(&s->codec, AC97_POWER_CONTROL) & ~0x8000); - /* mute a number of signals which seem to be causing problems - * if not muted. - */ - wrcodec(&s->codec, AC97_PCBEEP_VOL, 0x8000); - wrcodec(&s->codec, AC97_PHONE_VOL, 0x8008); - wrcodec(&s->codec, AC97_MIC_VOL, 0x8008); - wrcodec(&s->codec, AC97_LINEIN_VOL, 0x8808); - wrcodec(&s->codec, AC97_CD_VOL, 0x8808); - wrcodec(&s->codec, AC97_VIDEO_VOL, 0x8808); - wrcodec(&s->codec, AC97_AUX_VOL, 0x8808); - wrcodec(&s->codec, AC97_PCMOUT_VOL, 0x0808); - wrcodec(&s->codec, AC97_GENERAL_PURPOSE, 0x2000); -#endif - - return 0; - - err_dev3: - unregister_sound_mixer(s->codec.dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - free_au1000_dma(s->dma_adc.dmanr); - err_dma2: - free_au1000_dma(s->dma_dac.dmanr); - err_dma1: - release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14); - return -1; -} - -static void au1000_remove(void) -{ - struct au1000_state *s = &au1000_state; - - if (!s) - return; -#ifdef AU1000_DEBUG - if (s->ps) - remove_proc_entry(AU1000_MODULE_NAME, NULL); -#endif /* AU1000_DEBUG */ - synchronize_irq(); - free_au1000_dma(s->dma_adc.dmanr); - free_au1000_dma(s->dma_dac.dmanr); - release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->codec.dev_mixer); -} - -static int __init init_au1000(void) -{ - info("stevel@mvista.com, built " __TIME__ " on " __DATE__); - return au1000_probe(); -} - -static void __exit cleanup_au1000(void) -{ - info("unloading"); - au1000_remove(); -} - -module_init(init_au1000); -module_exit(cleanup_au1000); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -static int __init au1000_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return 0; - - while ((this_opt = strsep(&options, ","))) { - if (!*this_opt) - continue; - if (!strncmp(this_opt, "vra", 3)) { - vra = 1; - } - } - - return 1; -} - -__setup("au1000_audio=", au1000_setup); - -#endif /* MODULE */ diff --git a/sound/oss/audio_syms.c b/sound/oss/audio_syms.c index 5da217fcbedd..3919e4d6b3f3 100644 --- a/sound/oss/audio_syms.c +++ b/sound/oss/audio_syms.c @@ -10,7 +10,5 @@ char audio_syms_symbol; #include "sound_calls.h" EXPORT_SYMBOL(DMAbuf_start_dma); -EXPORT_SYMBOL(DMAbuf_open_dma); -EXPORT_SYMBOL(DMAbuf_close_dma); EXPORT_SYMBOL(DMAbuf_inputintr); EXPORT_SYMBOL(DMAbuf_outputintr); diff --git a/sound/oss/awe_hw.h b/sound/oss/awe_hw.h deleted file mode 100644 index ab00c3c67e4e..000000000000 --- a/sound/oss/awe_hw.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * sound/oss/awe_hw.h - * - * Access routines and definitions for the low level driver for the - * Creative AWE32/SB32/AWE64 wave table synth. - * version 0.4.4; Jan. 4, 2000 - * - * Copyright (C) 1996-2000 Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef AWE_HW_H_DEF -#define AWE_HW_H_DEF - -/* - * Emu-8000 control registers - * name(channel) reg, port - */ - -#define awe_cmd_idx(reg,ch) (((reg)<< 5) | (ch)) - -#define Data0 0 /* 0x620: doubleword r/w */ -#define Data1 1 /* 0xA20: doubleword r/w */ -#define Data2 2 /* 0xA22: word r/w */ -#define Data3 3 /* 0xE20: word r/w */ -#define Pointer 4 /* 0xE22 register pointer r/w */ - -#define AWE_CPF(ch) awe_cmd_idx(0,ch), Data0 /* DW: current pitch and fractional address */ -#define AWE_PTRX(ch) awe_cmd_idx(1,ch), Data0 /* DW: pitch target and reverb send */ -#define AWE_CVCF(ch) awe_cmd_idx(2,ch), Data0 /* DW: current volume and filter cutoff */ -#define AWE_VTFT(ch) awe_cmd_idx(3,ch), Data0 /* DW: volume and filter cutoff targets */ -#define AWE_0080(ch) awe_cmd_idx(4,ch), Data0 /* DW: ?? */ -#define AWE_00A0(ch) awe_cmd_idx(5,ch), Data0 /* DW: ?? */ -#define AWE_PSST(ch) awe_cmd_idx(6,ch), Data0 /* DW: pan send and loop start address */ -#define AWE_CSL(ch) awe_cmd_idx(7,ch), Data0 /* DW: chorus send and loop end address */ -#define AWE_CCCA(ch) awe_cmd_idx(0,ch), Data1 /* DW: Q, control bits, and current address */ -#define AWE_HWCF4 awe_cmd_idx(1,9), Data1 /* DW: config dw 4 */ -#define AWE_HWCF5 awe_cmd_idx(1,10), Data1 /* DW: config dw 5 */ -#define AWE_HWCF6 awe_cmd_idx(1,13), Data1 /* DW: config dw 6 */ -#define AWE_HWCF7 awe_cmd_idx(1,14), Data1 /* DW: config dw 7? (not documented) */ -#define AWE_SMALR awe_cmd_idx(1,20), Data1 /* DW: sound memory address for left read */ -#define AWE_SMARR awe_cmd_idx(1,21), Data1 /* DW: for right read */ -#define AWE_SMALW awe_cmd_idx(1,22), Data1 /* DW: sound memory address for left write */ -#define AWE_SMARW awe_cmd_idx(1,23), Data1 /* DW: for right write */ -#define AWE_SMLD awe_cmd_idx(1,26), Data1 /* W: sound memory left data */ -#define AWE_SMRD awe_cmd_idx(1,26), Data2 /* W: right data */ -#define AWE_WC awe_cmd_idx(1,27), Data2 /* W: sample counter */ -#define AWE_WC_Cmd awe_cmd_idx(1,27) -#define AWE_WC_Port Data2 -#define AWE_HWCF1 awe_cmd_idx(1,29), Data1 /* W: config w 1 */ -#define AWE_HWCF2 awe_cmd_idx(1,30), Data1 /* W: config w 2 */ -#define AWE_HWCF3 awe_cmd_idx(1,31), Data1 /* W: config w 3 */ -#define AWE_INIT1(ch) awe_cmd_idx(2,ch), Data1 /* W: init array 1 */ -#define AWE_INIT2(ch) awe_cmd_idx(2,ch), Data2 /* W: init array 2 */ -#define AWE_INIT3(ch) awe_cmd_idx(3,ch), Data1 /* W: init array 3 */ -#define AWE_INIT4(ch) awe_cmd_idx(3,ch), Data2 /* W: init array 4 */ -#define AWE_ENVVOL(ch) awe_cmd_idx(4,ch), Data1 /* W: volume envelope delay */ -#define AWE_DCYSUSV(ch) awe_cmd_idx(5,ch), Data1 /* W: volume envelope sustain and decay */ -#define AWE_ENVVAL(ch) awe_cmd_idx(6,ch), Data1 /* W: modulation envelope delay */ -#define AWE_DCYSUS(ch) awe_cmd_idx(7,ch), Data1 /* W: modulation envelope sustain and decay */ -#define AWE_ATKHLDV(ch) awe_cmd_idx(4,ch), Data2 /* W: volume envelope attack and hold */ -#define AWE_LFO1VAL(ch) awe_cmd_idx(5,ch), Data2 /* W: LFO#1 Delay */ -#define AWE_ATKHLD(ch) awe_cmd_idx(6,ch), Data2 /* W: modulation envelope attack and hold */ -#define AWE_LFO2VAL(ch) awe_cmd_idx(7,ch), Data2 /* W: LFO#2 Delay */ -#define AWE_IP(ch) awe_cmd_idx(0,ch), Data3 /* W: initial pitch */ -#define AWE_IFATN(ch) awe_cmd_idx(1,ch), Data3 /* W: initial filter cutoff and attenuation */ -#define AWE_PEFE(ch) awe_cmd_idx(2,ch), Data3 /* W: pitch and filter envelope heights */ -#define AWE_FMMOD(ch) awe_cmd_idx(3,ch), Data3 /* W: vibrato and filter modulation freq */ -#define AWE_TREMFRQ(ch) awe_cmd_idx(4,ch), Data3 /* W: LFO#1 tremolo amount and freq */ -#define AWE_FM2FRQ2(ch) awe_cmd_idx(5,ch), Data3 /* W: LFO#2 vibrato amount and freq */ - -/* used during detection (returns ROM version?; not documented in ADIP) */ -#define AWE_U1 0xE0, Data3 /* (R)(W) used in initialization */ -#define AWE_U2(ch) 0xC0+(ch), Data3 /* (W)(W) used in init envelope */ - - -#define AWE_MAX_VOICES 32 -#define AWE_NORMAL_VOICES 30 /*30&31 are reserved for DRAM refresh*/ - -#define AWE_MAX_CHANNELS 32 /* max midi channels (must >= voices) */ -#define AWE_MAX_LAYERS AWE_MAX_VOICES /* maximum number of multiple layers */ - -#define AWE_DRAM_OFFSET 0x200000 -#define AWE_MAX_DRAM_SIZE (28 * 1024) /* 28 MB is max onboard memory */ - -#endif diff --git a/sound/oss/awe_wave.c b/sound/oss/awe_wave.c deleted file mode 100644 index 01c592cee045..000000000000 --- a/sound/oss/awe_wave.c +++ /dev/null @@ -1,6149 +0,0 @@ -/* - * sound/oss/awe_wave.c - * - * The low level driver for the AWE32/SB32/AWE64 wave table synth. - * version 0.4.4; Jan. 4, 2000 - * - * Copyright (C) 1996-2000 Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Changelog: - * Aug 18, 2003, Adam Belay - * - detection code rewrite - */ - -#include -#include -#include -#include -#include -#include - -#include "sound_config.h" - -#include "awe_wave.h" -#include "awe_hw.h" - -#ifdef AWE_HAS_GUS_COMPATIBILITY -#include "tuning.h" -#include -#endif - -/* - * debug message - */ - -#ifdef AWE_DEBUG_ON -#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }} -#define ERRMSG(XXX) {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }} -#define FATALERR(XXX) XXX -#else -#define DEBUG(LVL,XXX) /**/ -#define ERRMSG(XXX) XXX -#define FATALERR(XXX) XXX -#endif - -/* - * bank and voice record - */ - -typedef struct _sf_list sf_list; -typedef struct _awe_voice_list awe_voice_list; -typedef struct _awe_sample_list awe_sample_list; - -/* soundfont record */ -struct _sf_list { - unsigned short sf_id; /* id number */ - unsigned short type; /* lock & shared flags */ - int num_info; /* current info table index */ - int num_sample; /* current sample table index */ - int mem_ptr; /* current word byte pointer */ - awe_voice_list *infos, *last_infos; /* instruments */ - awe_sample_list *samples, *last_samples; /* samples */ -#ifdef AWE_ALLOW_SAMPLE_SHARING - sf_list *shared; /* shared list */ - unsigned char name[AWE_PATCH_NAME_LEN]; /* sharing id */ -#endif - sf_list *next, *prev; -}; - -/* instrument list */ -struct _awe_voice_list { - awe_voice_info v; /* instrument information */ - sf_list *holder; /* parent sf_list of this record */ - unsigned char bank, instr; /* preset number information */ - char type, disabled; /* type=normal/mapped, disabled=boolean */ - awe_voice_list *next; /* linked list with same sf_id */ - awe_voice_list *next_instr; /* instrument list */ - awe_voice_list *next_bank; /* hash table list */ -}; - -/* voice list type */ -#define V_ST_NORMAL 0 -#define V_ST_MAPPED 1 - -/* sample list */ -struct _awe_sample_list { - awe_sample_info v; /* sample information */ - sf_list *holder; /* parent sf_list of this record */ - awe_sample_list *next; /* linked list with same sf_id */ -}; - -/* sample and information table */ -static int current_sf_id; /* current number of fonts */ -static int locked_sf_id; /* locked position */ -static sf_list *sfhead, *sftail; /* linked-lists */ - -#define awe_free_mem_ptr() (sftail ? sftail->mem_ptr : 0) -#define awe_free_info() (sftail ? sftail->num_info : 0) -#define awe_free_sample() (sftail ? sftail->num_sample : 0) - -#define AWE_MAX_PRESETS 256 -#define AWE_DEFAULT_PRESET 0 -#define AWE_DEFAULT_BANK 0 -#define AWE_DEFAULT_DRUM 0 -#define AWE_DRUM_BANK 128 - -#define MAX_LAYERS AWE_MAX_VOICES - -/* preset table index */ -static awe_voice_list *preset_table[AWE_MAX_PRESETS]; - -/* - * voice table - */ - -/* effects table */ -typedef struct FX_Rec { /* channel effects */ - unsigned char flags[AWE_FX_END]; - short val[AWE_FX_END]; -} FX_Rec; - - -/* channel parameters */ -typedef struct _awe_chan_info { - int channel; /* channel number */ - int bank; /* current tone bank */ - int instr; /* current program */ - int bender; /* midi pitchbend (-8192 - 8192) */ - int bender_range; /* midi bender range (x100) */ - int panning; /* panning (0-127) */ - int main_vol; /* channel volume (0-127) */ - int expression_vol; /* midi expression (0-127) */ - int chan_press; /* channel pressure */ - int sustained; /* sustain status in MIDI */ - FX_Rec fx; /* effects */ - FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */ -} awe_chan_info; - -/* voice parameters */ -typedef struct _voice_info { - int state; -#define AWE_ST_OFF (1<<0) /* no sound */ -#define AWE_ST_ON (1<<1) /* playing */ -#define AWE_ST_STANDBY (1<<2) /* stand by for playing */ -#define AWE_ST_SUSTAINED (1<<3) /* sustained */ -#define AWE_ST_MARK (1<<4) /* marked for allocation */ -#define AWE_ST_DRAM (1<<5) /* DRAM read/write */ -#define AWE_ST_FM (1<<6) /* reserved for FM */ -#define AWE_ST_RELEASED (1<<7) /* released */ - - int ch; /* midi channel */ - int key; /* internal key for search */ - int layer; /* layer number (for channel mode only) */ - int time; /* allocated time */ - awe_chan_info *cinfo; /* channel info */ - - int note; /* midi key (0-127) */ - int velocity; /* midi velocity (0-127) */ - int sostenuto; /* sostenuto on/off */ - awe_voice_info *sample; /* assigned voice */ - - /* EMU8000 parameters */ - int apitch; /* pitch parameter */ - int avol; /* volume parameter */ - int apan; /* panning parameter */ - int acutoff; /* cutoff parameter */ - short aaux; /* aux word */ -} voice_info; - -/* voice information */ -static voice_info voices[AWE_MAX_VOICES]; - -#define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED)) -#define IS_NO_EFFECT(v) (voices[v].state != AWE_ST_ON) -#define IS_PLAYING(v) (voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED)) -#define IS_EMPTY(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM)) - - -/* MIDI channel effects information (for hw control) */ -static awe_chan_info channels[AWE_MAX_CHANNELS]; - - -/* - * global variables - */ - -#ifndef AWE_DEFAULT_BASE_ADDR -#define AWE_DEFAULT_BASE_ADDR 0 /* autodetect */ -#endif - -#ifndef AWE_DEFAULT_MEM_SIZE -#define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */ -#endif - -static int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */ -static int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */ -#ifdef CONFIG_PNP -static int isapnp = -1; -#else -static int isapnp; -#endif - -MODULE_AUTHOR("Takashi Iwai "); -MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver"); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "base i/o port of Emu8000"); -module_param(memsize, int, 0); -MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes"); -module_param(isapnp, bool, 0); -MODULE_PARM_DESC(isapnp, "use ISAPnP detection"); - -/* DRAM start offset */ -static int awe_mem_start = AWE_DRAM_OFFSET; - -/* maximum channels for playing */ -static int awe_max_voices = AWE_MAX_VOICES; - -static int patch_opened; /* sample already loaded? */ - -static char atten_relative = FALSE; -static short atten_offset; - -static int awe_present = FALSE; /* awe device present? */ -static int awe_busy = FALSE; /* awe device opened? */ - -static int my_dev = -1; - -#define DEFAULT_DRUM_FLAGS ((1 << 9) | (1 << 25)) -#define IS_DRUM_CHANNEL(c) (drum_flags & (1 << (c))) -#define DRUM_CHANNEL_ON(c) (drum_flags |= (1 << (c))) -#define DRUM_CHANNEL_OFF(c) (drum_flags &= ~(1 << (c))) -static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */ - -static int playing_mode = AWE_PLAY_INDIRECT; -#define SINGLE_LAYER_MODE() (playing_mode == AWE_PLAY_INDIRECT || playing_mode == AWE_PLAY_DIRECT) -#define MULTI_LAYER_MODE() (playing_mode == AWE_PLAY_MULTI || playing_mode == AWE_PLAY_MULTI2) - -static int current_alloc_time; /* voice allocation index for channel mode */ - -static struct synth_info awe_info = { - "AWE32 Synth", /* name */ - 0, /* device */ - SYNTH_TYPE_SAMPLE, /* synth_type */ - SAMPLE_TYPE_AWE32, /* synth_subtype */ - 0, /* perc_mode (obsolete) */ - AWE_MAX_VOICES, /* nr_voices */ - 0, /* nr_drums (obsolete) */ - 400 /* instr_bank_size */ -}; - - -static struct voice_alloc_info *voice_alloc; /* set at initialization */ - - -/* - * function prototypes - */ - -static int awe_request_region(void); -static void awe_release_region(void); - -static void awe_reset_samples(void); -/* emu8000 chip i/o access */ -static void setup_ports(int p1, int p2, int p3); -static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data); -static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data); -static unsigned short awe_peek(unsigned short cmd, unsigned short port); -static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port); -static void awe_wait(unsigned short delay); - -/* initialize emu8000 chip */ -static void awe_initialize(void); - -/* set voice parameters */ -static void awe_init_ctrl_parms(int init_all); -static void awe_init_voice_info(awe_voice_info *vp); -static void awe_init_voice_parm(awe_voice_parm *pp); -#ifdef AWE_HAS_GUS_COMPATIBILITY -static int freq_to_note(int freq); -static int calc_rate_offset(int Hz); -/*static int calc_parm_delay(int msec);*/ -static int calc_parm_hold(int msec); -static int calc_parm_attack(int msec); -static int calc_parm_decay(int msec); -static int calc_parm_search(int msec, short *table); -#endif /* gus compat */ - -/* turn on/off note */ -static void awe_note_on(int voice); -static void awe_note_off(int voice); -static void awe_terminate(int voice); -static void awe_exclusive_off(int voice); -static void awe_note_off_all(int do_sustain); - -/* calculate voice parameters */ -typedef void (*fx_affect_func)(int voice, int forced); -static void awe_set_pitch(int voice, int forced); -static void awe_set_voice_pitch(int voice, int forced); -static void awe_set_volume(int voice, int forced); -static void awe_set_voice_vol(int voice, int forced); -static void awe_set_pan(int voice, int forced); -static void awe_fx_fmmod(int voice, int forced); -static void awe_fx_tremfrq(int voice, int forced); -static void awe_fx_fm2frq2(int voice, int forced); -static void awe_fx_filterQ(int voice, int forced); -static void awe_calc_pitch(int voice); -#ifdef AWE_HAS_GUS_COMPATIBILITY -static void awe_calc_pitch_from_freq(int voice, int freq); -#endif -static void awe_calc_volume(int voice); -static void awe_update_volume(void); -static void awe_change_master_volume(short val); -static void awe_voice_init(int voice, int init_all); -static void awe_channel_init(int ch, int init_all); -static void awe_fx_init(int ch); -static void awe_send_effect(int voice, int layer, int type, int val); -static void awe_modwheel_change(int voice, int value); - -/* sequencer interface */ -static int awe_open(int dev, int mode); -static void awe_close(int dev); -static int awe_ioctl(int dev, unsigned int cmd, void __user * arg); -static int awe_kill_note(int dev, int voice, int note, int velocity); -static int awe_start_note(int dev, int v, int note_num, int volume); -static int awe_set_instr(int dev, int voice, int instr_no); -static int awe_set_instr_2(int dev, int voice, int instr_no); -static void awe_reset(int dev); -static void awe_hw_control(int dev, unsigned char *event); -static int awe_load_patch(int dev, int format, const char __user *addr, - int offs, int count, int pmgr_flag); -static void awe_aftertouch(int dev, int voice, int pressure); -static void awe_controller(int dev, int voice, int ctrl_num, int value); -static void awe_panning(int dev, int voice, int value); -static void awe_volume_method(int dev, int mode); -static void awe_bender(int dev, int voice, int value); -static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc); -static void awe_setup_voice(int dev, int voice, int chn); - -#define awe_key_pressure(dev,voice,key,press) awe_start_note(dev,voice,(key)+128,press) - -/* hardware controls */ -#ifdef AWE_HAS_GUS_COMPATIBILITY -static void awe_hw_gus_control(int dev, int cmd, unsigned char *event); -#endif -static void awe_hw_awe_control(int dev, int cmd, unsigned char *event); -static void awe_voice_change(int voice, fx_affect_func func); -static void awe_sostenuto_on(int voice, int forced); -static void awe_sustain_off(int voice, int forced); -static void awe_terminate_and_init(int voice, int forced); - -/* voice search */ -static int awe_search_key(int bank, int preset, int note); -static awe_voice_list *awe_search_instr(int bank, int preset, int note); -static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist); -static void awe_alloc_multi_voices(int ch, int note, int velocity, int key); -static void awe_alloc_one_voice(int voice, int note, int velocity); -static int awe_clear_voice(void); - -/* load / remove patches */ -static int awe_open_patch(awe_patch_info *patch, const char __user *addr, int count); -static int awe_close_patch(awe_patch_info *patch, const char __user *addr, int count); -static int awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count); -static int awe_load_info(awe_patch_info *patch, const char __user *addr, int count); -static int awe_remove_info(awe_patch_info *patch, const char __user *addr, int count); -static int awe_load_data(awe_patch_info *patch, const char __user *addr, int count); -static int awe_replace_data(awe_patch_info *patch, const char __user *addr, int count); -static int awe_load_map(awe_patch_info *patch, const char __user *addr, int count); -#ifdef AWE_HAS_GUS_COMPATIBILITY -static int awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag); -#endif -/*static int awe_probe_info(awe_patch_info *patch, const char __user *addr, int count);*/ -static int awe_probe_data(awe_patch_info *patch, const char __user *addr, int count); -static sf_list *check_patch_opened(int type, char *name); -static int awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *sp, int channels); -static int awe_create_sf(int type, char *name); -static void awe_free_sf(sf_list *sf); -static void add_sf_info(sf_list *sf, awe_voice_list *rec); -static void add_sf_sample(sf_list *sf, awe_sample_list *smp); -static void purge_old_list(awe_voice_list *rec, awe_voice_list *next); -static void add_info_list(awe_voice_list *rec); -static void awe_remove_samples(int sf_id); -static void rebuild_preset_list(void); -static short awe_set_sample(awe_voice_list *rec); -static awe_sample_list *search_sample_index(sf_list *sf, int sample); - -static int is_identical_holder(sf_list *sf1, sf_list *sf2); -#ifdef AWE_ALLOW_SAMPLE_SHARING -static int is_identical_name(unsigned char *name, sf_list *p); -static int is_shared_sf(unsigned char *name); -static int info_duplicated(sf_list *sf, awe_voice_list *rec); -#endif /* allow sharing */ - -/* lowlevel functions */ -static void awe_init_audio(void); -static void awe_init_dma(void); -static void awe_init_array(void); -static void awe_send_array(unsigned short *data); -static void awe_tweak_voice(int voice); -static void awe_tweak(void); -static void awe_init_fm(void); -static int awe_open_dram_for_write(int offset, int channels); -static void awe_open_dram_for_check(void); -static void awe_close_dram(void); -/*static void awe_write_dram(unsigned short c);*/ -static int awe_detect_base(int addr); -static int awe_detect(void); -static void awe_check_dram(void); -static int awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count); -static void awe_set_chorus_mode(int mode); -static void awe_update_chorus_mode(void); -static int awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count); -static void awe_set_reverb_mode(int mode); -static void awe_update_reverb_mode(void); -static void awe_equalizer(int bass, int treble); -static void awe_update_equalizer(void); - -#ifdef CONFIG_AWE32_MIXER -static void attach_mixer(void); -static void unload_mixer(void); -#endif - -#ifdef CONFIG_AWE32_MIDIEMU -static void attach_midiemu(void); -static void unload_midiemu(void); -#endif - -#define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b) - -/* - * control parameters - */ - - -#ifdef AWE_USE_NEW_VOLUME_CALC -#define DEF_VOLUME_CALC TRUE -#else -#define DEF_VOLUME_CALC FALSE -#endif /* new volume */ - -#define DEF_ZERO_ATTEN 32 /* 12dB below */ -#define DEF_MOD_SENSE 18 -#define DEF_CHORUS_MODE 2 -#define DEF_REVERB_MODE 4 -#define DEF_BASS_LEVEL 5 -#define DEF_TREBLE_LEVEL 9 - -static struct CtrlParmsDef { - int value; - int init_each_time; - void (*update)(void); -} ctrl_parms[AWE_MD_END] = { - {0,0, NULL}, {0,0, NULL}, /* <-- not used */ - {AWE_VERSION_NUMBER, FALSE, NULL}, - {TRUE, FALSE, NULL}, /* exclusive */ - {TRUE, FALSE, NULL}, /* realpan */ - {AWE_DEFAULT_BANK, FALSE, NULL}, /* gusbank */ - {FALSE, TRUE, NULL}, /* keep effect */ - {DEF_ZERO_ATTEN, FALSE, awe_update_volume}, /* zero_atten */ - {FALSE, FALSE, NULL}, /* chn_prior */ - {DEF_MOD_SENSE, FALSE, NULL}, /* modwheel sense */ - {AWE_DEFAULT_PRESET, FALSE, NULL}, /* def_preset */ - {AWE_DEFAULT_BANK, FALSE, NULL}, /* def_bank */ - {AWE_DEFAULT_DRUM, FALSE, NULL}, /* def_drum */ - {FALSE, FALSE, NULL}, /* toggle_drum_bank */ - {DEF_VOLUME_CALC, FALSE, awe_update_volume}, /* new_volume_calc */ - {DEF_CHORUS_MODE, FALSE, awe_update_chorus_mode}, /* chorus mode */ - {DEF_REVERB_MODE, FALSE, awe_update_reverb_mode}, /* reverb mode */ - {DEF_BASS_LEVEL, FALSE, awe_update_equalizer}, /* bass level */ - {DEF_TREBLE_LEVEL, FALSE, awe_update_equalizer}, /* treble level */ - {0, FALSE, NULL}, /* debug mode */ - {FALSE, FALSE, NULL}, /* pan exchange */ -}; - -static int ctrls[AWE_MD_END]; - - -/* - * synth operation table - */ - -static struct synth_operations awe_operations = -{ - .owner = THIS_MODULE, - .id = "EMU8K", - .info = &awe_info, - .midi_dev = 0, - .synth_type = SYNTH_TYPE_SAMPLE, - .synth_subtype = SAMPLE_TYPE_AWE32, - .open = awe_open, - .close = awe_close, - .ioctl = awe_ioctl, - .kill_note = awe_kill_note, - .start_note = awe_start_note, - .set_instr = awe_set_instr_2, - .reset = awe_reset, - .hw_control = awe_hw_control, - .load_patch = awe_load_patch, - .aftertouch = awe_aftertouch, - .controller = awe_controller, - .panning = awe_panning, - .volume_method = awe_volume_method, - .bender = awe_bender, - .alloc_voice = awe_alloc, - .setup_voice = awe_setup_voice -}; - -static void free_tables(void) -{ - if (sftail) { - sf_list *p, *prev; - for (p = sftail; p; p = prev) { - prev = p->prev; - awe_free_sf(p); - } - } - sfhead = sftail = NULL; -} - -/* - * clear sample tables - */ - -static void -awe_reset_samples(void) -{ - /* free all bank tables */ - memset(preset_table, 0, sizeof(preset_table)); - free_tables(); - - current_sf_id = 0; - locked_sf_id = 0; - patch_opened = 0; -} - - -/* - * EMU register access - */ - -/* select a given AWE32 pointer */ -static int awe_ports[5]; -static int port_setuped = FALSE; -static int awe_cur_cmd = -1; -#define awe_set_cmd(cmd) \ -if (awe_cur_cmd != cmd) { outw(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; } - -/* write 16bit data */ -static void -awe_poke(unsigned short cmd, unsigned short port, unsigned short data) -{ - awe_set_cmd(cmd); - outw(data, awe_ports[port]); -} - -/* write 32bit data */ -static void -awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data) -{ - unsigned short addr = awe_ports[port]; - awe_set_cmd(cmd); - outw(data, addr); /* write lower 16 bits */ - outw(data >> 16, addr + 2); /* write higher 16 bits */ -} - -/* read 16bit data */ -static unsigned short -awe_peek(unsigned short cmd, unsigned short port) -{ - unsigned short k; - awe_set_cmd(cmd); - k = inw(awe_ports[port]); - return k; -} - -/* read 32bit data */ -static unsigned int -awe_peek_dw(unsigned short cmd, unsigned short port) -{ - unsigned int k1, k2; - unsigned short addr = awe_ports[port]; - awe_set_cmd(cmd); - k1 = inw(addr); - k2 = inw(addr + 2); - k1 |= k2 << 16; - return k1; -} - -/* wait delay number of AWE32 44100Hz clocks */ -#ifdef WAIT_BY_LOOP /* wait by loop -- that's not good.. */ -static void -awe_wait(unsigned short delay) -{ - unsigned short clock, target; - unsigned short port = awe_ports[AWE_WC_Port]; - int counter; - - /* sample counter */ - awe_set_cmd(AWE_WC_Cmd); - clock = (unsigned short)inw(port); - target = clock + delay; - counter = 0; - if (target < clock) { - for (; (unsigned short)inw(port) > target; counter++) - if (counter > 65536) - break; - } - for (; (unsigned short)inw(port) < target; counter++) - if (counter > 65536) - break; -} -#else - -static void awe_wait(unsigned short delay) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((HZ*(unsigned long)delay + 44099)/44100); -} -/* -static void awe_wait(unsigned short delay) -{ - udelay(((unsigned long)delay * 1000000L + 44099) / 44100); -} -*/ -#endif /* wait by loop */ - -/* write a word data */ -#define awe_write_dram(c) awe_poke(AWE_SMLD, c) - -/* - * AWE32 voice parameters - */ - -/* initialize voice_info record */ -static void -awe_init_voice_info(awe_voice_info *vp) -{ - vp->sample = 0; - vp->rate_offset = 0; - - vp->start = 0; - vp->end = 0; - vp->loopstart = 0; - vp->loopend = 0; - vp->mode = 0; - vp->root = 60; - vp->tune = 0; - vp->low = 0; - vp->high = 127; - vp->vellow = 0; - vp->velhigh = 127; - - vp->fixkey = -1; - vp->fixvel = -1; - vp->fixpan = -1; - vp->pan = -1; - - vp->exclusiveClass = 0; - vp->amplitude = 127; - vp->attenuation = 0; - vp->scaleTuning = 100; - - awe_init_voice_parm(&vp->parm); -} - -/* initialize voice_parm record: - * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0. - * Vibrato and Tremolo effects are zero. - * Cutoff is maximum. - * Chorus and Reverb effects are zero. - */ -static void -awe_init_voice_parm(awe_voice_parm *pp) -{ - pp->moddelay = 0x8000; - pp->modatkhld = 0x7f7f; - pp->moddcysus = 0x7f7f; - pp->modrelease = 0x807f; - pp->modkeyhold = 0; - pp->modkeydecay = 0; - - pp->voldelay = 0x8000; - pp->volatkhld = 0x7f7f; - pp->voldcysus = 0x7f7f; - pp->volrelease = 0x807f; - pp->volkeyhold = 0; - pp->volkeydecay = 0; - - pp->lfo1delay = 0x8000; - pp->lfo2delay = 0x8000; - pp->pefe = 0; - - pp->fmmod = 0; - pp->tremfrq = 0; - pp->fm2frq2 = 0; - - pp->cutoff = 0xff; - pp->filterQ = 0; - - pp->chorus = 0; - pp->reverb = 0; -} - - -#ifdef AWE_HAS_GUS_COMPATIBILITY - -/* convert frequency mHz to abstract cents (= midi key * 100) */ -static int -freq_to_note(int mHz) -{ - /* abscents = log(mHz/8176) / log(2) * 1200 */ - unsigned int max_val = (unsigned int)0xffffffff / 10000; - int i, times; - unsigned int base; - unsigned int freq; - int note, tune; - - if (mHz == 0) - return 0; - if (mHz < 0) - return 12799; /* maximum */ - - freq = mHz; - note = 0; - for (base = 8176 * 2; freq >= base; base *= 2) { - note += 12; - if (note >= 128) /* over maximum */ - return 12799; - } - base /= 2; - - /* to avoid overflow... */ - times = 10000; - while (freq > max_val) { - max_val *= 10; - times /= 10; - base /= 10; - } - - freq = freq * times / base; - for (i = 0; i < 12; i++) { - if (freq < semitone_tuning[i+1]) - break; - note++; - } - - tune = 0; - freq = freq * 10000 / semitone_tuning[i]; - for (i = 0; i < 100; i++) { - if (freq < cent_tuning[i+1]) - break; - tune++; - } - - return note * 100 + tune; -} - - -/* convert Hz to AWE32 rate offset: - * sample pitch offset for the specified sample rate - * rate=44100 is no offset, each 4096 is 1 octave (twice). - * eg, when rate is 22050, this offset becomes -4096. - */ -static int -calc_rate_offset(int Hz) -{ - /* offset = log(Hz / 44100) / log(2) * 4096 */ - int freq, base, i; - - /* maybe smaller than max (44100Hz) */ - if (Hz <= 0 || Hz >= 44100) return 0; - - base = 0; - for (freq = Hz * 2; freq < 44100; freq *= 2) - base++; - base *= 1200; - - freq = 44100 * 10000 / (freq/2); - for (i = 0; i < 12; i++) { - if (freq < semitone_tuning[i+1]) - break; - base += 100; - } - freq = freq * 10000 / semitone_tuning[i]; - for (i = 0; i < 100; i++) { - if (freq < cent_tuning[i+1]) - break; - base++; - } - return -base * 4096 / 1200; -} - - -/* - * convert envelope time parameter to AWE32 raw parameter - */ - -/* attack & decay/release time table (msec) */ -static short attack_time_tbl[128] = { -32767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816, -707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, -361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, -180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, -90, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, -45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, -22, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12, -11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0, -}; - -static short decay_time_tbl[128] = { -32767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082, -2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507, -1443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722, -691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361, -345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180, -172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90, -86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45, -43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22, -}; - -#define calc_parm_delay(msec) (0x8000 - (msec) * 1000 / 725); - -/* delay time = 0x8000 - msec/92 */ -static int -calc_parm_hold(int msec) -{ - int val = (0x7f * 92 - msec) / 92; - if (val < 1) val = 1; - if (val > 127) val = 127; - return val; -} - -/* attack time: search from time table */ -static int -calc_parm_attack(int msec) -{ - return calc_parm_search(msec, attack_time_tbl); -} - -/* decay/release time: search from time table */ -static int -calc_parm_decay(int msec) -{ - return calc_parm_search(msec, decay_time_tbl); -} - -/* search an index for specified time from given time table */ -static int -calc_parm_search(int msec, short *table) -{ - int left = 1, right = 127, mid; - while (left < right) { - mid = (left + right) / 2; - if (msec < (int)table[mid]) - left = mid + 1; - else - right = mid; - } - return left; -} -#endif /* AWE_HAS_GUS_COMPATIBILITY */ - - -/* - * effects table - */ - -/* set an effect value */ -#define FX_FLAG_OFF 0 -#define FX_FLAG_SET 1 -#define FX_FLAG_ADD 2 - -#define FX_SET(rec,type,value) \ - ((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value)) -#define FX_ADD(rec,type,value) \ - ((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value)) -#define FX_UNSET(rec,type) \ - ((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0) - -/* check the effect value is set */ -#define FX_ON(rec,type) ((rec)->flags[type]) - -#define PARM_BYTE 0 -#define PARM_WORD 1 -#define PARM_SIGN 2 - -static struct PARM_DEFS { - int type; /* byte or word */ - int low, high; /* value range */ - fx_affect_func realtime; /* realtime paramater change */ -} parm_defs[] = { - {PARM_WORD, 0, 0x8000, NULL}, /* env1 delay */ - {PARM_BYTE, 1, 0x7f, NULL}, /* env1 attack */ - {PARM_BYTE, 0, 0x7e, NULL}, /* env1 hold */ - {PARM_BYTE, 1, 0x7f, NULL}, /* env1 decay */ - {PARM_BYTE, 1, 0x7f, NULL}, /* env1 release */ - {PARM_BYTE, 0, 0x7f, NULL}, /* env1 sustain */ - {PARM_BYTE, 0, 0xff, NULL}, /* env1 pitch */ - {PARM_BYTE, 0, 0xff, NULL}, /* env1 cutoff */ - - {PARM_WORD, 0, 0x8000, NULL}, /* env2 delay */ - {PARM_BYTE, 1, 0x7f, NULL}, /* env2 attack */ - {PARM_BYTE, 0, 0x7e, NULL}, /* env2 hold */ - {PARM_BYTE, 1, 0x7f, NULL}, /* env2 decay */ - {PARM_BYTE, 1, 0x7f, NULL}, /* env2 release */ - {PARM_BYTE, 0, 0x7f, NULL}, /* env2 sustain */ - - {PARM_WORD, 0, 0x8000, NULL}, /* lfo1 delay */ - {PARM_BYTE, 0, 0xff, awe_fx_tremfrq}, /* lfo1 freq */ - {PARM_SIGN, -128, 127, awe_fx_tremfrq}, /* lfo1 volume */ - {PARM_SIGN, -128, 127, awe_fx_fmmod}, /* lfo1 pitch */ - {PARM_BYTE, 0, 0xff, awe_fx_fmmod}, /* lfo1 cutoff */ - - {PARM_WORD, 0, 0x8000, NULL}, /* lfo2 delay */ - {PARM_BYTE, 0, 0xff, awe_fx_fm2frq2}, /* lfo2 freq */ - {PARM_SIGN, -128, 127, awe_fx_fm2frq2}, /* lfo2 pitch */ - - {PARM_WORD, 0, 0xffff, awe_set_voice_pitch}, /* initial pitch */ - {PARM_BYTE, 0, 0xff, NULL}, /* chorus */ - {PARM_BYTE, 0, 0xff, NULL}, /* reverb */ - {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial cutoff */ - {PARM_BYTE, 0, 15, awe_fx_filterQ}, /* initial resonance */ - - {PARM_WORD, 0, 0xffff, NULL}, /* sample start */ - {PARM_WORD, 0, 0xffff, NULL}, /* loop start */ - {PARM_WORD, 0, 0xffff, NULL}, /* loop end */ - {PARM_WORD, 0, 0xffff, NULL}, /* coarse sample start */ - {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop start */ - {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop end */ - {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial attenuation */ -}; - - -static unsigned char -FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value) -{ - int effect = 0; - int on = 0; - if (lay && (on = FX_ON(lay, type)) != 0) - effect = lay->val[type]; - if (!on && (on = FX_ON(rec, type)) != 0) - effect = rec->val[type]; - if (on == FX_FLAG_ADD) { - if (parm_defs[type].type == PARM_SIGN) { - if (value > 0x7f) - effect += (int)value - 0x100; - else - effect += (int)value; - } else { - effect += (int)value; - } - } - if (on) { - if (effect < parm_defs[type].low) - effect = parm_defs[type].low; - else if (effect > parm_defs[type].high) - effect = parm_defs[type].high; - return (unsigned char)effect; - } - return value; -} - -/* get word effect value */ -static unsigned short -FX_WORD(FX_Rec *rec, FX_Rec *lay, int type, unsigned short value) -{ - int effect = 0; - int on = 0; - if (lay && (on = FX_ON(lay, type)) != 0) - effect = lay->val[type]; - if (!on && (on = FX_ON(rec, type)) != 0) - effect = rec->val[type]; - if (on == FX_FLAG_ADD) - effect += (int)value; - if (on) { - if (effect < parm_defs[type].low) - effect = parm_defs[type].low; - else if (effect > parm_defs[type].high) - effect = parm_defs[type].high; - return (unsigned short)effect; - } - return value; -} - -/* get word (upper=type1/lower=type2) effect value */ -static unsigned short -FX_COMB(FX_Rec *rec, FX_Rec *lay, int type1, int type2, unsigned short value) -{ - unsigned short tmp; - tmp = FX_BYTE(rec, lay, type1, (unsigned char)(value >> 8)); - tmp <<= 8; - tmp |= FX_BYTE(rec, lay, type2, (unsigned char)(value & 0xff)); - return tmp; -} - -/* address offset */ -static int -FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode) -{ - int addr = 0; - if (lay && FX_ON(lay, hi)) - addr = (short)lay->val[hi]; - else if (FX_ON(rec, hi)) - addr = (short)rec->val[hi]; - addr = addr << 15; - if (lay && FX_ON(lay, lo)) - addr += (short)lay->val[lo]; - else if (FX_ON(rec, lo)) - addr += (short)rec->val[lo]; - if (!(mode & AWE_SAMPLE_8BITS)) - addr /= 2; - return addr; -} - - -/* - * turn on/off sample - */ - -/* table for volume target calculation */ -static unsigned short voltarget[16] = { - 0xEAC0, 0XE0C8, 0XD740, 0XCE20, 0XC560, 0XBD08, 0XB500, 0XAD58, - 0XA5F8, 0X9EF0, 0X9830, 0X91C0, 0X8B90, 0X85A8, 0X8000, 0X7A90 -}; - -static void -awe_note_on(int voice) -{ - unsigned int temp; - int addr; - int vtarget, ftarget, ptarget, pitch; - awe_voice_info *vp; - awe_voice_parm_block *parm; - FX_Rec *fx = &voices[voice].cinfo->fx; - FX_Rec *fx_lay = NULL; - if (voices[voice].layer < MAX_LAYERS) - fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - - /* A voice sample must assigned before calling */ - if ((vp = voices[voice].sample) == NULL || vp->index == 0) - return; - - parm = (awe_voice_parm_block*)&vp->parm; - - /* channel to be silent and idle */ - awe_poke(AWE_DCYSUSV(voice), 0x0080); - awe_poke(AWE_VTFT(voice), 0x0000FFFF); - awe_poke(AWE_CVCF(voice), 0x0000FFFF); - awe_poke(AWE_PTRX(voice), 0); - awe_poke(AWE_CPF(voice), 0); - - /* set pitch offset */ - awe_set_pitch(voice, TRUE); - - /* modulation & volume envelope */ - if (parm->modatk >= 0x80 && parm->moddelay >= 0x8000) { - awe_poke(AWE_ENVVAL(voice), 0xBFFF); - pitch = (parm->env1pit<<4) + voices[voice].apitch; - if (pitch > 0xffff) pitch = 0xffff; - /* calculate filter target */ - ftarget = parm->cutoff + parm->env1fc; - limitvalue(ftarget, 0, 255); - ftarget <<= 8; - } else { - awe_poke(AWE_ENVVAL(voice), - FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, parm->moddelay)); - ftarget = parm->cutoff; - ftarget <<= 8; - pitch = voices[voice].apitch; - } - - /* calcualte pitch target */ - if (pitch != 0xffff) { - ptarget = 1 << (pitch >> 12); - if (pitch & 0x800) ptarget += (ptarget*0x102e)/0x2710; - if (pitch & 0x400) ptarget += (ptarget*0x764)/0x2710; - if (pitch & 0x200) ptarget += (ptarget*0x389)/0x2710; - ptarget += (ptarget>>1); - if (ptarget > 0xffff) ptarget = 0xffff; - - } else ptarget = 0xffff; - if (parm->modatk >= 0x80) - awe_poke(AWE_ATKHLD(voice), - FX_BYTE(fx, fx_lay, AWE_FX_ENV1_HOLD, parm->modhld) << 8 | 0x7f); - else - awe_poke(AWE_ATKHLD(voice), - FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK, - vp->parm.modatkhld)); - awe_poke(AWE_DCYSUS(voice), - FX_COMB(fx, fx_lay, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY, - vp->parm.moddcysus)); - - if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) { - awe_poke(AWE_ENVVOL(voice), 0xBFFF); - vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4); - } else { - awe_poke(AWE_ENVVOL(voice), - FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay)); - vtarget = 0; - } - if (parm->volatk >= 0x80) - awe_poke(AWE_ATKHLDV(voice), - FX_BYTE(fx, fx_lay, AWE_FX_ENV2_HOLD, parm->volhld) << 8 | 0x7f); - else - awe_poke(AWE_ATKHLDV(voice), - FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK, - vp->parm.volatkhld)); - /* decay/sustain parameter for volume envelope must be set at last */ - - /* cutoff and volume */ - awe_set_volume(voice, TRUE); - - /* modulation envelope heights */ - awe_poke(AWE_PEFE(voice), - FX_COMB(fx, fx_lay, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF, - vp->parm.pefe)); - - /* lfo1/2 delay */ - awe_poke(AWE_LFO1VAL(voice), - FX_WORD(fx, fx_lay, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay)); - awe_poke(AWE_LFO2VAL(voice), - FX_WORD(fx, fx_lay, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay)); - - /* lfo1 pitch & cutoff shift */ - awe_fx_fmmod(voice, TRUE); - /* lfo1 volume & freq */ - awe_fx_tremfrq(voice, TRUE); - /* lfo2 pitch & freq */ - awe_fx_fm2frq2(voice, TRUE); - /* pan & loop start */ - awe_set_pan(voice, TRUE); - - /* chorus & loop end (chorus 8bit, MSB) */ - addr = vp->loopend - 1; - addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_END, - AWE_FX_COARSE_LOOP_END, vp->mode); - temp = FX_BYTE(fx, fx_lay, AWE_FX_CHORUS, vp->parm.chorus); - temp = (temp <<24) | (unsigned int)addr; - awe_poke_dw(AWE_CSL(voice), temp); - DEBUG(4,printk("AWE32: [-- loopend=%x/%x]\n", vp->loopend, addr)); - - /* Q & current address (Q 4bit value, MSB) */ - addr = vp->start - 1; - addr += FX_OFFSET(fx, fx_lay, AWE_FX_SAMPLE_START, - AWE_FX_COARSE_SAMPLE_START, vp->mode); - temp = FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ); - temp = (temp<<28) | (unsigned int)addr; - awe_poke_dw(AWE_CCCA(voice), temp); - DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", vp->start, addr)); - - /* clear unknown registers */ - awe_poke_dw(AWE_00A0(voice), 0); - awe_poke_dw(AWE_0080(voice), 0); - - /* reset volume */ - awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget); - awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget); - - /* set reverb */ - temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb); - temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux; - awe_poke_dw(AWE_PTRX(voice), temp); - awe_poke_dw(AWE_CPF(voice), ptarget << 16); - /* turn on envelope */ - awe_poke(AWE_DCYSUSV(voice), - FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY, - vp->parm.voldcysus)); - - voices[voice].state = AWE_ST_ON; - - /* clear voice position for the next note on this channel */ - if (SINGLE_LAYER_MODE()) { - FX_UNSET(fx, AWE_FX_SAMPLE_START); - FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START); - } -} - - -/* turn off the voice */ -static void -awe_note_off(int voice) -{ - awe_voice_info *vp; - unsigned short tmp; - FX_Rec *fx = &voices[voice].cinfo->fx; - FX_Rec *fx_lay = NULL; - if (voices[voice].layer < MAX_LAYERS) - fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - - if ((vp = voices[voice].sample) == NULL) { - voices[voice].state = AWE_ST_OFF; - return; - } - - tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV1_RELEASE, - (unsigned char)vp->parm.modrelease); - awe_poke(AWE_DCYSUS(voice), tmp); - tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE, - (unsigned char)vp->parm.volrelease); - awe_poke(AWE_DCYSUSV(voice), tmp); - voices[voice].state = AWE_ST_RELEASED; -} - -/* force to terminate the voice (no releasing echo) */ -static void -awe_terminate(int voice) -{ - awe_poke(AWE_DCYSUSV(voice), 0x807F); - awe_tweak_voice(voice); - voices[voice].state = AWE_ST_OFF; -} - -/* turn off other voices with the same exclusive class (for drums) */ -static void -awe_exclusive_off(int voice) -{ - int i, exclass; - - if (voices[voice].sample == NULL) - return; - if ((exclass = voices[voice].sample->exclusiveClass) == 0) - return; /* not exclusive */ - - /* turn off voices with the same class */ - for (i = 0; i < awe_max_voices; i++) { - if (i != voice && IS_PLAYING(i) && - voices[i].sample && voices[i].ch == voices[voice].ch && - voices[i].sample->exclusiveClass == exclass) { - DEBUG(4,printk("AWE32: [exoff(%d)]\n", i)); - awe_terminate(i); - awe_voice_init(i, TRUE); - } - } -} - - -/* - * change the parameters of an audible voice - */ - -/* change pitch */ -static void -awe_set_pitch(int voice, int forced) -{ - if (IS_NO_EFFECT(voice) && !forced) return; - awe_poke(AWE_IP(voice), voices[voice].apitch); - DEBUG(3,printk("AWE32: [-- pitch=%x]\n", voices[voice].apitch)); -} - -/* calculate & change pitch */ -static void -awe_set_voice_pitch(int voice, int forced) -{ - awe_calc_pitch(voice); - awe_set_pitch(voice, forced); -} - -/* change volume & cutoff */ -static void -awe_set_volume(int voice, int forced) -{ - awe_voice_info *vp; - unsigned short tmp2; - FX_Rec *fx = &voices[voice].cinfo->fx; - FX_Rec *fx_lay = NULL; - if (voices[voice].layer < MAX_LAYERS) - fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - - if (!IS_PLAYING(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index == 0) - return; - - tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF, - (unsigned char)voices[voice].acutoff); - tmp2 = (tmp2 << 8); - tmp2 |= FX_BYTE(fx, fx_lay, AWE_FX_ATTEN, - (unsigned char)voices[voice].avol); - awe_poke(AWE_IFATN(voice), tmp2); -} - -/* calculate & change volume */ -static void -awe_set_voice_vol(int voice, int forced) -{ - if (IS_EMPTY(voice)) - return; - awe_calc_volume(voice); - awe_set_volume(voice, forced); -} - - -/* change pan; this could make a click noise.. */ -static void -awe_set_pan(int voice, int forced) -{ - unsigned int temp; - int addr; - awe_voice_info *vp; - FX_Rec *fx = &voices[voice].cinfo->fx; - FX_Rec *fx_lay = NULL; - if (voices[voice].layer < MAX_LAYERS) - fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - - if (IS_NO_EFFECT(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index == 0) - return; - - /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */ - if (vp->fixpan > 0) /* 0-127 */ - temp = 255 - (int)vp->fixpan * 2; - else { - int pos = 0; - if (vp->pan >= 0) /* 0-127 */ - pos = (int)vp->pan * 2 - 128; - pos += voices[voice].cinfo->panning; /* -128 - 127 */ - temp = 127 - pos; - } - limitvalue(temp, 0, 255); - if (ctrls[AWE_MD_PAN_EXCHANGE]) { - temp = 255 - temp; - } - if (forced || temp != voices[voice].apan) { - voices[voice].apan = temp; - if (temp == 0) - voices[voice].aaux = 0xff; - else - voices[voice].aaux = (-temp) & 0xff; - addr = vp->loopstart - 1; - addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START, - AWE_FX_COARSE_LOOP_START, vp->mode); - temp = (temp<<24) | (unsigned int)addr; - awe_poke_dw(AWE_PSST(voice), temp); - DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr)); - } -} - -/* effects change during playing */ -static void -awe_fx_fmmod(int voice, int forced) -{ - awe_voice_info *vp; - FX_Rec *fx = &voices[voice].cinfo->fx; - FX_Rec *fx_lay = NULL; - if (voices[voice].layer < MAX_LAYERS) - fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - - if (IS_NO_EFFECT(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index == 0) - return; - awe_poke(AWE_FMMOD(voice), - FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF, - vp->parm.fmmod)); -} - -/* set tremolo (lfo1) volume & frequency */ -static void -awe_fx_tremfrq(int voice, int forced) -{ - awe_voice_info *vp; - FX_Rec *fx = &voices[voice].cinfo->fx; - FX_Rec *fx_lay = NULL; - if (voices[voice].layer < MAX_LAYERS) - fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - - if (IS_NO_EFFECT(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index == 0) - return; - awe_poke(AWE_TREMFRQ(voice), - FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ, - vp->parm.tremfrq)); -} - -/* set lfo2 pitch & frequency */ -static void -awe_fx_fm2frq2(int voice, int forced) -{ - awe_voice_info *vp; - FX_Rec *fx = &voices[voice].cinfo->fx; - FX_Rec *fx_lay = NULL; - if (voices[voice].layer < MAX_LAYERS) - fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - - if (IS_NO_EFFECT(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index == 0) - return; - awe_poke(AWE_FM2FRQ2(voice), - FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ, - vp->parm.fm2frq2)); -} - - -/* Q & current address (Q 4bit value, MSB) */ -static void -awe_fx_filterQ(int voice, int forced) -{ - unsigned int addr; - awe_voice_info *vp; - FX_Rec *fx = &voices[voice].cinfo->fx; - FX_Rec *fx_lay = NULL; - if (voices[voice].layer < MAX_LAYERS) - fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - - if (IS_NO_EFFECT(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index == 0) - return; - - addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff; - addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28); - awe_poke_dw(AWE_CCCA(voice), addr); -} - -/* - * calculate pitch offset - * - * 0xE000 is no pitch offset at 44100Hz sample. - * Every 4096 is one octave. - */ - -static void -awe_calc_pitch(int voice) -{ - voice_info *vp = &voices[voice]; - awe_voice_info *ap; - awe_chan_info *cp = voices[voice].cinfo; - int offset; - - /* search voice information */ - if ((ap = vp->sample) == NULL) - return; - if (ap->index == 0) { - DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); - if (awe_set_sample((awe_voice_list*)ap) == 0) - return; - } - - /* calculate offset */ - if (ap->fixkey >= 0) { - DEBUG(3,printk("AWE32: p-> fixkey(%d) tune(%d)\n", ap->fixkey, ap->tune)); - offset = (ap->fixkey - ap->root) * 4096 / 12; - } else { - DEBUG(3,printk("AWE32: p(%d)-> root(%d) tune(%d)\n", vp->note, ap->root, ap->tune)); - offset = (vp->note - ap->root) * 4096 / 12; - DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset)); - } - offset = (offset * ap->scaleTuning) / 100; - DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset)); - offset += ap->tune * 4096 / 1200; - DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset)); - if (cp->bender != 0) { - DEBUG(3,printk("AWE32: p-> bend(%d) %d\n", voice, cp->bender)); - /* (819200: 1 semitone) ==> (4096: 12 semitones) */ - offset += cp->bender * cp->bender_range / 2400; - } - - /* add initial pitch correction */ - if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH)) - offset += cp->fx_layer[vp->layer].val[AWE_FX_INIT_PITCH]; - else if (FX_ON(&cp->fx, AWE_FX_INIT_PITCH)) - offset += cp->fx.val[AWE_FX_INIT_PITCH]; - - /* 0xe000: root pitch */ - vp->apitch = 0xe000 + ap->rate_offset + offset; - DEBUG(4,printk("AWE32: p-> sum aofs=%x, rate_ofs=%d\n", vp->apitch, ap->rate_offset)); - if (vp->apitch > 0xffff) - vp->apitch = 0xffff; - if (vp->apitch < 0) - vp->apitch = 0; -} - - -#ifdef AWE_HAS_GUS_COMPATIBILITY -/* calculate MIDI key and semitone from the specified frequency */ -static void -awe_calc_pitch_from_freq(int voice, int freq) -{ - voice_info *vp = &voices[voice]; - awe_voice_info *ap; - FX_Rec *fx = &voices[voice].cinfo->fx; - FX_Rec *fx_lay = NULL; - int offset; - int note; - - if (voices[voice].layer < MAX_LAYERS) - fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - - /* search voice information */ - if ((ap = vp->sample) == NULL) - return; - if (ap->index == 0) { - DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); - if (awe_set_sample((awe_voice_list*)ap) == 0) - return; - } - note = freq_to_note(freq); - offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200; - offset = (offset * ap->scaleTuning) / 100; - if (fx_lay && FX_ON(fx_lay, AWE_FX_INIT_PITCH)) - offset += fx_lay->val[AWE_FX_INIT_PITCH]; - else if (FX_ON(fx, AWE_FX_INIT_PITCH)) - offset += fx->val[AWE_FX_INIT_PITCH]; - vp->apitch = 0xe000 + ap->rate_offset + offset; - if (vp->apitch > 0xffff) - vp->apitch = 0xffff; - if (vp->apitch < 0) - vp->apitch = 0; -} -#endif /* AWE_HAS_GUS_COMPATIBILITY */ - - -/* - * calculate volume attenuation - * - * Voice volume is controlled by volume attenuation parameter. - * So volume becomes maximum when avol is 0 (no attenuation), and - * minimum when 255 (-96dB or silence). - */ - -static int vol_table[128] = { - 255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49, - 47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32, - 31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22, - 22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16, - 15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10, - 10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6, - 6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3, - 2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0, -}; - -/* tables for volume->attenuation calculation */ -static unsigned char voltab1[128] = { - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, - 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, - 0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, - 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, - 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, - 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char voltab2[128] = { - 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a, - 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21, - 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a, - 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15, - 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, - 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, - 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, - 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char expressiontab[128] = { - 0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42, - 0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30, - 0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, - 0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e, - 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18, - 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13, - 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f, - 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, - 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, - 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, - 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, - 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static void -awe_calc_volume(int voice) -{ - voice_info *vp = &voices[voice]; - awe_voice_info *ap; - awe_chan_info *cp = voices[voice].cinfo; - int vol; - - /* search voice information */ - if ((ap = vp->sample) == NULL) - return; - - ap = vp->sample; - if (ap->index == 0) { - DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); - if (awe_set_sample((awe_voice_list*)ap) == 0) - return; - } - - if (ctrls[AWE_MD_NEW_VOLUME_CALC]) { - int main_vol = cp->main_vol * ap->amplitude / 127; - limitvalue(vp->velocity, 0, 127); - limitvalue(main_vol, 0, 127); - limitvalue(cp->expression_vol, 0, 127); - - vol = voltab1[main_vol] + voltab2[vp->velocity]; - vol = (vol * 8) / 3; - vol += ap->attenuation; - if (cp->expression_vol < 127) - vol += ((0x100 - vol) * expressiontab[cp->expression_vol])/128; - vol += atten_offset; - if (atten_relative) - vol += ctrls[AWE_MD_ZERO_ATTEN]; - limitvalue(vol, 0, 255); - vp->avol = vol; - - } else { - /* 0 - 127 */ - vol = (vp->velocity * cp->main_vol * cp->expression_vol) / (127*127); - vol = vol * ap->amplitude / 127; - - if (vol < 0) vol = 0; - if (vol > 127) vol = 127; - - /* calc to attenuation */ - vol = vol_table[vol]; - vol += (int)ap->attenuation; - vol += atten_offset; - if (atten_relative) - vol += ctrls[AWE_MD_ZERO_ATTEN]; - if (vol > 255) vol = 255; - - vp->avol = vol; - } - if (cp->bank != AWE_DRUM_BANK && ((awe_voice_parm_block*)(&ap->parm))->volatk < 0x7d) { - int atten; - if (vp->velocity < 70) atten = 70; - else atten = vp->velocity; - vp->acutoff = (atten * ap->parm.cutoff + 0xa0) >> 7; - } else { - vp->acutoff = ap->parm.cutoff; - } - DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol)); -} - -/* change master volume */ -static void -awe_change_master_volume(short val) -{ - limitvalue(val, 0, 127); - atten_offset = vol_table[val]; - atten_relative = TRUE; - awe_update_volume(); -} - -/* update volumes of all available channels */ -static void awe_update_volume(void) -{ - int i; - for (i = 0; i < awe_max_voices; i++) - awe_set_voice_vol(i, TRUE); -} - -/* set sostenuto on */ -static void awe_sostenuto_on(int voice, int forced) -{ - if (IS_NO_EFFECT(voice) && !forced) return; - voices[voice].sostenuto = 127; -} - - -/* drop sustain */ -static void awe_sustain_off(int voice, int forced) -{ - if (voices[voice].state == AWE_ST_SUSTAINED) { - awe_note_off(voice); - awe_fx_init(voices[voice].ch); - awe_voice_init(voice, FALSE); - } -} - - -/* terminate and initialize voice */ -static void awe_terminate_and_init(int voice, int forced) -{ - awe_terminate(voice); - awe_fx_init(voices[voice].ch); - awe_voice_init(voice, TRUE); -} - - -/* - * synth operation routines - */ - -#define AWE_VOICE_KEY(v) (0x8000 | (v)) -#define AWE_CHAN_KEY(c,n) (((c) << 8) | ((n) + 1)) -#define KEY_CHAN_MATCH(key,c) (((key) >> 8) == (c)) - -/* initialize the voice */ -static void -awe_voice_init(int voice, int init_all) -{ - voice_info *vp = &voices[voice]; - - /* reset voice search key */ - if (playing_mode == AWE_PLAY_DIRECT) - vp->key = AWE_VOICE_KEY(voice); - else - vp->key = 0; - - /* clear voice mapping */ - voice_alloc->map[voice] = 0; - - /* touch the timing flag */ - vp->time = current_alloc_time; - - /* initialize other parameters if necessary */ - if (init_all) { - vp->note = -1; - vp->velocity = 0; - vp->sostenuto = 0; - - vp->sample = NULL; - vp->cinfo = &channels[voice]; - vp->ch = voice; - vp->state = AWE_ST_OFF; - - /* emu8000 parameters */ - vp->apitch = 0; - vp->avol = 255; - vp->apan = -1; - } -} - -/* clear effects */ -static void awe_fx_init(int ch) -{ - if (SINGLE_LAYER_MODE() && !ctrls[AWE_MD_KEEP_EFFECT]) { - memset(&channels[ch].fx, 0, sizeof(channels[ch].fx)); - memset(&channels[ch].fx_layer, 0, sizeof(&channels[ch].fx_layer)); - } -} - -/* initialize channel info */ -static void awe_channel_init(int ch, int init_all) -{ - awe_chan_info *cp = &channels[ch]; - cp->channel = ch; - if (init_all) { - cp->panning = 0; /* zero center */ - cp->bender_range = 200; /* sense * 100 */ - cp->main_vol = 127; - if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) { - cp->instr = ctrls[AWE_MD_DEF_DRUM]; - cp->bank = AWE_DRUM_BANK; - } else { - cp->instr = ctrls[AWE_MD_DEF_PRESET]; - cp->bank = ctrls[AWE_MD_DEF_BANK]; - } - } - - cp->bender = 0; /* zero tune skew */ - cp->expression_vol = 127; - cp->chan_press = 0; - cp->sustained = 0; - - if (! ctrls[AWE_MD_KEEP_EFFECT]) { - memset(&cp->fx, 0, sizeof(cp->fx)); - memset(&cp->fx_layer, 0, sizeof(cp->fx_layer)); - } -} - - -/* change the voice parameters; voice = channel */ -static void awe_voice_change(int voice, fx_affect_func func) -{ - int i; - switch (playing_mode) { - case AWE_PLAY_DIRECT: - func(voice, FALSE); - break; - case AWE_PLAY_INDIRECT: - for (i = 0; i < awe_max_voices; i++) - if (voices[i].key == AWE_VOICE_KEY(voice)) - func(i, FALSE); - break; - default: - for (i = 0; i < awe_max_voices; i++) - if (KEY_CHAN_MATCH(voices[i].key, voice)) - func(i, FALSE); - break; - } -} - - -/* - * device open / close - */ - -/* open device: - * reset status of all voices, and clear sample position flag - */ -static int -awe_open(int dev, int mode) -{ - if (awe_busy) - return -EBUSY; - - awe_busy = TRUE; - - /* set default mode */ - awe_init_ctrl_parms(FALSE); - atten_relative = TRUE; - atten_offset = 0; - drum_flags = DEFAULT_DRUM_FLAGS; - playing_mode = AWE_PLAY_INDIRECT; - - /* reset voices & channels */ - awe_reset(dev); - - patch_opened = 0; - - return 0; -} - - -/* close device: - * reset all voices again (terminate sounds) - */ -static void -awe_close(int dev) -{ - awe_reset(dev); - awe_busy = FALSE; -} - - -/* set miscellaneous mode parameters - */ -static void -awe_init_ctrl_parms(int init_all) -{ - int i; - for (i = 0; i < AWE_MD_END; i++) { - if (init_all || ctrl_parms[i].init_each_time) - ctrls[i] = ctrl_parms[i].value; - } -} - - -/* sequencer I/O control: - */ -static int -awe_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - switch (cmd) { - case SNDCTL_SYNTH_INFO: - if (playing_mode == AWE_PLAY_DIRECT) - awe_info.nr_voices = awe_max_voices; - else - awe_info.nr_voices = AWE_MAX_CHANNELS; - if (copy_to_user(arg, &awe_info, sizeof(awe_info))) - return -EFAULT; - return 0; - break; - - case SNDCTL_SEQ_RESETSAMPLES: - awe_reset(dev); - awe_reset_samples(); - return 0; - break; - - case SNDCTL_SEQ_PERCMODE: - /* what's this? */ - return 0; - break; - - case SNDCTL_SYNTH_MEMAVL: - return memsize - awe_free_mem_ptr() * 2; - break; - - default: - printk(KERN_WARNING "AWE32: unsupported ioctl %d\n", cmd); - return -EINVAL; - break; - } -} - - -static int voice_in_range(int voice) -{ - if (playing_mode == AWE_PLAY_DIRECT) { - if (voice < 0 || voice >= awe_max_voices) - return FALSE; - } else { - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return FALSE; - } - return TRUE; -} - -static void release_voice(int voice, int do_sustain) -{ - if (IS_NO_SOUND(voice)) - return; - if (do_sustain && (voices[voice].cinfo->sustained == 127 || - voices[voice].sostenuto == 127)) - voices[voice].state = AWE_ST_SUSTAINED; - else { - awe_note_off(voice); - awe_fx_init(voices[voice].ch); - awe_voice_init(voice, FALSE); - } -} - -/* release all notes */ -static void awe_note_off_all(int do_sustain) -{ - int i; - for (i = 0; i < awe_max_voices; i++) - release_voice(i, do_sustain); -} - -/* kill a voice: - * not terminate, just release the voice. - */ -static int -awe_kill_note(int dev, int voice, int note, int velocity) -{ - int i, v2, key; - - DEBUG(2,printk("AWE32: [off(%d) nt=%d vl=%d]\n", voice, note, velocity)); - if (! voice_in_range(voice)) - return -EINVAL; - - switch (playing_mode) { - case AWE_PLAY_DIRECT: - case AWE_PLAY_INDIRECT: - key = AWE_VOICE_KEY(voice); - break; - - case AWE_PLAY_MULTI2: - v2 = voice_alloc->map[voice] >> 8; - voice_alloc->map[voice] = 0; - voice = v2; - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return -EINVAL; - /* continue to below */ - default: - key = AWE_CHAN_KEY(voice, note); - break; - } - - for (i = 0; i < awe_max_voices; i++) { - if (voices[i].key == key) - release_voice(i, TRUE); - } - return 0; -} - - -static void start_or_volume_change(int voice, int velocity) -{ - voices[voice].velocity = velocity; - awe_calc_volume(voice); - if (voices[voice].state == AWE_ST_STANDBY) - awe_note_on(voice); - else if (voices[voice].state == AWE_ST_ON) - awe_set_volume(voice, FALSE); -} - -static void set_and_start_voice(int voice, int state) -{ - /* calculate pitch & volume parameters */ - voices[voice].state = state; - awe_calc_pitch(voice); - awe_calc_volume(voice); - if (state == AWE_ST_ON) - awe_note_on(voice); -} - -/* start a voice: - * if note is 255, identical with aftertouch function. - * Otherwise, start a voice with specified not and volume. - */ -static int -awe_start_note(int dev, int voice, int note, int velocity) -{ - int i, key, state, volonly; - - DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", voice, note, velocity)); - if (! voice_in_range(voice)) - return -EINVAL; - - if (velocity == 0) - state = AWE_ST_STANDBY; /* stand by for playing */ - else - state = AWE_ST_ON; /* really play */ - volonly = FALSE; - - switch (playing_mode) { - case AWE_PLAY_DIRECT: - case AWE_PLAY_INDIRECT: - key = AWE_VOICE_KEY(voice); - if (note == 255) - volonly = TRUE; - break; - - case AWE_PLAY_MULTI2: - voice = voice_alloc->map[voice] >> 8; - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return -EINVAL; - /* continue to below */ - default: - if (note >= 128) { /* key volume mode */ - note -= 128; - volonly = TRUE; - } - key = AWE_CHAN_KEY(voice, note); - break; - } - - /* dynamic volume change */ - if (volonly) { - for (i = 0; i < awe_max_voices; i++) { - if (voices[i].key == key) - start_or_volume_change(i, velocity); - } - return 0; - } - - /* if the same note still playing, stop it */ - if (playing_mode != AWE_PLAY_DIRECT || ctrls[AWE_MD_EXCLUSIVE_SOUND]) { - for (i = 0; i < awe_max_voices; i++) - if (voices[i].key == key) { - if (voices[i].state == AWE_ST_ON) { - awe_note_off(i); - awe_voice_init(i, FALSE); - } else if (voices[i].state == AWE_ST_STANDBY) - awe_voice_init(i, TRUE); - } - } - - /* allocate voices */ - if (playing_mode == AWE_PLAY_DIRECT) - awe_alloc_one_voice(voice, note, velocity); - else - awe_alloc_multi_voices(voice, note, velocity, key); - - /* turn off other voices exlusively (for drums) */ - for (i = 0; i < awe_max_voices; i++) - if (voices[i].key == key) - awe_exclusive_off(i); - - /* set up pitch and volume parameters */ - for (i = 0; i < awe_max_voices; i++) { - if (voices[i].key == key && voices[i].state == AWE_ST_OFF) - set_and_start_voice(i, state); - } - - return 0; -} - - -/* calculate hash key */ -static int -awe_search_key(int bank, int preset, int note) -{ - unsigned int key; - -#if 1 /* new hash table */ - if (bank == AWE_DRUM_BANK) - key = preset + note + 128; - else - key = bank + preset; -#else - key = preset; -#endif - key %= AWE_MAX_PRESETS; - - return (int)key; -} - - -/* search instrument from hash table */ -static awe_voice_list * -awe_search_instr(int bank, int preset, int note) -{ - awe_voice_list *p; - int key, key2; - - key = awe_search_key(bank, preset, note); - for (p = preset_table[key]; p; p = p->next_bank) { - if (p->instr == preset && p->bank == bank) - return p; - } - key2 = awe_search_key(bank, preset, 0); /* search default */ - if (key == key2) - return NULL; - for (p = preset_table[key2]; p; p = p->next_bank) { - if (p->instr == preset && p->bank == bank) - return p; - } - return NULL; -} - - -/* assign the instrument to a voice */ -static int -awe_set_instr_2(int dev, int voice, int instr_no) -{ - if (playing_mode == AWE_PLAY_MULTI2) { - voice = voice_alloc->map[voice] >> 8; - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return -EINVAL; - } - return awe_set_instr(dev, voice, instr_no); -} - -/* assign the instrument to a channel; voice is the channel number */ -static int -awe_set_instr(int dev, int voice, int instr_no) -{ - awe_chan_info *cinfo; - - if (! voice_in_range(voice)) - return -EINVAL; - - if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS) - return -EINVAL; - - cinfo = &channels[voice]; - cinfo->instr = instr_no; - DEBUG(2,printk("AWE32: [program(%d) %d]\n", voice, instr_no)); - - return 0; -} - - -/* reset all voices; terminate sounds and initialize parameters */ -static void -awe_reset(int dev) -{ - int i; - current_alloc_time = 0; - /* don't turn off voice 31 and 32. they are used also for FM voices */ - for (i = 0; i < awe_max_voices; i++) { - awe_terminate(i); - awe_voice_init(i, TRUE); - } - for (i = 0; i < AWE_MAX_CHANNELS; i++) - awe_channel_init(i, TRUE); - for (i = 0; i < 16; i++) { - awe_operations.chn_info[i].controllers[CTL_MAIN_VOLUME] = 127; - awe_operations.chn_info[i].controllers[CTL_EXPRESSION] = 127; - } - awe_init_fm(); - awe_tweak(); -} - - -/* hardware specific control: - * GUS specific and AWE32 specific controls are available. - */ -static void -awe_hw_control(int dev, unsigned char *event) -{ - int cmd = event[2]; - if (cmd & _AWE_MODE_FLAG) - awe_hw_awe_control(dev, cmd & _AWE_MODE_VALUE_MASK, event); -#ifdef AWE_HAS_GUS_COMPATIBILITY - else - awe_hw_gus_control(dev, cmd & _AWE_MODE_VALUE_MASK, event); -#endif -} - - -#ifdef AWE_HAS_GUS_COMPATIBILITY - -/* GUS compatible controls */ -static void -awe_hw_gus_control(int dev, int cmd, unsigned char *event) -{ - int voice, i, key; - unsigned short p1; - short p2; - int plong; - - if (MULTI_LAYER_MODE()) - return; - if (cmd == _GUS_NUMVOICES) - return; - - voice = event[3]; - if (! voice_in_range(voice)) - return; - - p1 = *(unsigned short *) &event[4]; - p2 = *(short *) &event[6]; - plong = *(int*) &event[4]; - - switch (cmd) { - case _GUS_VOICESAMPLE: - awe_set_instr(dev, voice, p1); - return; - - case _GUS_VOICEBALA: - /* 0 to 15 --> -128 to 127 */ - awe_panning(dev, voice, ((int)p1 << 4) - 128); - return; - - case _GUS_VOICEVOL: - case _GUS_VOICEVOL2: - /* not supported yet */ - return; - - case _GUS_RAMPRANGE: - case _GUS_RAMPRATE: - case _GUS_RAMPMODE: - case _GUS_RAMPON: - case _GUS_RAMPOFF: - /* volume ramping not supported */ - return; - - case _GUS_VOLUME_SCALE: - return; - - case _GUS_VOICE_POS: - FX_SET(&channels[voice].fx, AWE_FX_SAMPLE_START, - (short)(plong & 0x7fff)); - FX_SET(&channels[voice].fx, AWE_FX_COARSE_SAMPLE_START, - (plong >> 15) & 0xffff); - return; - } - - key = AWE_VOICE_KEY(voice); - for (i = 0; i < awe_max_voices; i++) { - if (voices[i].key == key) { - switch (cmd) { - case _GUS_VOICEON: - awe_note_on(i); - break; - - case _GUS_VOICEOFF: - awe_terminate(i); - awe_fx_init(voices[i].ch); - awe_voice_init(i, TRUE); - break; - - case _GUS_VOICEFADE: - awe_note_off(i); - awe_fx_init(voices[i].ch); - awe_voice_init(i, FALSE); - break; - - case _GUS_VOICEFREQ: - awe_calc_pitch_from_freq(i, plong); - break; - } - } - } -} - -#endif /* gus_compat */ - - -/* AWE32 specific controls */ -static void -awe_hw_awe_control(int dev, int cmd, unsigned char *event) -{ - int voice; - unsigned short p1; - short p2; - int i; - - voice = event[3]; - if (! voice_in_range(voice)) - return; - - if (playing_mode == AWE_PLAY_MULTI2) { - voice = voice_alloc->map[voice] >> 8; - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return; - } - - p1 = *(unsigned short *) &event[4]; - p2 = *(short *) &event[6]; - - switch (cmd) { - case _AWE_DEBUG_MODE: - ctrls[AWE_MD_DEBUG_MODE] = p1; - printk(KERN_DEBUG "AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]); - break; - case _AWE_REVERB_MODE: - ctrls[AWE_MD_REVERB_MODE] = p1; - awe_update_reverb_mode(); - break; - - case _AWE_CHORUS_MODE: - ctrls[AWE_MD_CHORUS_MODE] = p1; - awe_update_chorus_mode(); - break; - - case _AWE_REMOVE_LAST_SAMPLES: - DEBUG(0,printk("AWE32: remove last samples\n")); - awe_reset(0); - if (locked_sf_id > 0) - awe_remove_samples(locked_sf_id); - break; - - case _AWE_INITIALIZE_CHIP: - awe_initialize(); - break; - - case _AWE_SEND_EFFECT: - i = -1; - if (p1 >= 0x100) { - i = (p1 >> 8); - if (i < 0 || i >= MAX_LAYERS) - break; - } - awe_send_effect(voice, i, p1, p2); - break; - - case _AWE_RESET_CHANNEL: - awe_channel_init(voice, !p1); - break; - - case _AWE_TERMINATE_ALL: - awe_reset(0); - break; - - case _AWE_TERMINATE_CHANNEL: - awe_voice_change(voice, awe_terminate_and_init); - break; - - case _AWE_RELEASE_ALL: - awe_note_off_all(FALSE); - break; - case _AWE_NOTEOFF_ALL: - awe_note_off_all(TRUE); - break; - - case _AWE_INITIAL_VOLUME: - DEBUG(0,printk("AWE32: init attenuation %d\n", p1)); - atten_relative = (char)p2; - atten_offset = (short)p1; - awe_update_volume(); - break; - - case _AWE_CHN_PRESSURE: - channels[voice].chan_press = p1; - awe_modwheel_change(voice, p1); - break; - - case _AWE_CHANNEL_MODE: - DEBUG(0,printk("AWE32: channel mode = %d\n", p1)); - playing_mode = p1; - awe_reset(0); - break; - - case _AWE_DRUM_CHANNELS: - DEBUG(0,printk("AWE32: drum flags = %x\n", p1)); - drum_flags = *(unsigned int*)&event[4]; - break; - - case _AWE_MISC_MODE: - DEBUG(0,printk("AWE32: ctrl parms = %d %d\n", p1, p2)); - if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) { - ctrls[p1] = p2; - if (ctrl_parms[p1].update) - ctrl_parms[p1].update(); - } - break; - - case _AWE_EQUALIZER: - ctrls[AWE_MD_BASS_LEVEL] = p1; - ctrls[AWE_MD_TREBLE_LEVEL] = p2; - awe_update_equalizer(); - break; - - default: - DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice)); - break; - } -} - - -/* change effects */ -static void -awe_send_effect(int voice, int layer, int type, int val) -{ - awe_chan_info *cinfo; - FX_Rec *fx; - int mode; - - cinfo = &channels[voice]; - if (layer >= 0 && layer < MAX_LAYERS) - fx = &cinfo->fx_layer[layer]; - else - fx = &cinfo->fx; - - if (type & 0x40) - mode = FX_FLAG_OFF; - else if (type & 0x80) - mode = FX_FLAG_ADD; - else - mode = FX_FLAG_SET; - type &= 0x3f; - - if (type >= 0 && type < AWE_FX_END) { - DEBUG(2,printk("AWE32: effects (%d) %d %d\n", voice, type, val)); - if (mode == FX_FLAG_SET) - FX_SET(fx, type, val); - else if (mode == FX_FLAG_ADD) - FX_ADD(fx, type, val); - else - FX_UNSET(fx, type); - if (mode != FX_FLAG_OFF && parm_defs[type].realtime) { - DEBUG(2,printk("AWE32: fx_realtime (%d)\n", voice)); - awe_voice_change(voice, parm_defs[type].realtime); - } - } -} - - -/* change modulation wheel; voice is already mapped on multi2 mode */ -static void -awe_modwheel_change(int voice, int value) -{ - int i; - awe_chan_info *cinfo; - - cinfo = &channels[voice]; - i = value * ctrls[AWE_MD_MOD_SENSE] / 1200; - FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i); - awe_voice_change(voice, awe_fx_fmmod); - FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i); - awe_voice_change(voice, awe_fx_fm2frq2); -} - - -/* voice pressure change */ -static void -awe_aftertouch(int dev, int voice, int pressure) -{ - int note; - - DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure)); - if (! voice_in_range(voice)) - return; - - switch (playing_mode) { - case AWE_PLAY_DIRECT: - case AWE_PLAY_INDIRECT: - awe_start_note(dev, voice, 255, pressure); - break; - case AWE_PLAY_MULTI2: - note = (voice_alloc->map[voice] & 0xff) - 1; - awe_key_pressure(dev, voice, note + 0x80, pressure); - break; - } -} - - -/* voice control change */ -static void -awe_controller(int dev, int voice, int ctrl_num, int value) -{ - awe_chan_info *cinfo; - - if (! voice_in_range(voice)) - return; - - if (playing_mode == AWE_PLAY_MULTI2) { - voice = voice_alloc->map[voice] >> 8; - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return; - } - - cinfo = &channels[voice]; - - switch (ctrl_num) { - case CTL_BANK_SELECT: /* MIDI control #0 */ - DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value)); - if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) && - !ctrls[AWE_MD_TOGGLE_DRUM_BANK]) - break; - if (value < 0 || value > 255) - break; - cinfo->bank = value; - if (cinfo->bank == AWE_DRUM_BANK) - DRUM_CHANNEL_ON(cinfo->channel); - else - DRUM_CHANNEL_OFF(cinfo->channel); - awe_set_instr(dev, voice, cinfo->instr); - break; - - case CTL_MODWHEEL: /* MIDI control #1 */ - DEBUG(2,printk("AWE32: [modwheel(%d) %d]\n", voice, value)); - awe_modwheel_change(voice, value); - break; - - case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */ - DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value)); - /* zero centered */ - cinfo->bender = value; - awe_voice_change(voice, awe_set_voice_pitch); - break; - - case CTRL_PITCH_BENDER_RANGE: /* SEQ1 V2 control */ - DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value)); - /* value = sense x 100 */ - cinfo->bender_range = value; - /* no audible pitch change yet.. */ - break; - - case CTL_EXPRESSION: /* MIDI control #11 */ - if (SINGLE_LAYER_MODE()) - value /= 128; - case CTRL_EXPRESSION: /* SEQ1 V2 control */ - DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value)); - /* 0 - 127 */ - cinfo->expression_vol = value; - awe_voice_change(voice, awe_set_voice_vol); - break; - - case CTL_PAN: /* MIDI control #10 */ - DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value)); - /* (0-127) -> signed 8bit */ - cinfo->panning = value * 2 - 128; - if (ctrls[AWE_MD_REALTIME_PAN]) - awe_voice_change(voice, awe_set_pan); - break; - - case CTL_MAIN_VOLUME: /* MIDI control #7 */ - if (SINGLE_LAYER_MODE()) - value = (value * 100) / 16383; - case CTRL_MAIN_VOLUME: /* SEQ1 V2 control */ - DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value)); - /* 0 - 127 */ - cinfo->main_vol = value; - awe_voice_change(voice, awe_set_voice_vol); - break; - - case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */ - DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value)); - FX_SET(&cinfo->fx, AWE_FX_REVERB, value * 2); - break; - - case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */ - DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value)); - FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2); - break; - - case 120: /* all sounds off */ - awe_note_off_all(FALSE); - break; - case 123: /* all notes off */ - awe_note_off_all(TRUE); - break; - - case CTL_SUSTAIN: /* MIDI control #64 */ - cinfo->sustained = value; - if (value != 127) - awe_voice_change(voice, awe_sustain_off); - break; - - case CTL_SOSTENUTO: /* MIDI control #66 */ - if (value == 127) - awe_voice_change(voice, awe_sostenuto_on); - else - awe_voice_change(voice, awe_sustain_off); - break; - - default: - DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n", - voice, ctrl_num, value)); - break; - } -} - - -/* voice pan change (value = -128 - 127) */ -static void -awe_panning(int dev, int voice, int value) -{ - awe_chan_info *cinfo; - - if (! voice_in_range(voice)) - return; - - if (playing_mode == AWE_PLAY_MULTI2) { - voice = voice_alloc->map[voice] >> 8; - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return; - } - - cinfo = &channels[voice]; - cinfo->panning = value; - DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning)); - if (ctrls[AWE_MD_REALTIME_PAN]) - awe_voice_change(voice, awe_set_pan); -} - - -/* volume mode change */ -static void -awe_volume_method(int dev, int mode) -{ - /* not impremented */ - DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode)); -} - - -/* pitch wheel change: 0-16384 */ -static void -awe_bender(int dev, int voice, int value) -{ - awe_chan_info *cinfo; - - if (! voice_in_range(voice)) - return; - - if (playing_mode == AWE_PLAY_MULTI2) { - voice = voice_alloc->map[voice] >> 8; - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return; - } - - /* convert to zero centered value */ - cinfo = &channels[voice]; - cinfo->bender = value - 8192; - DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, cinfo->bender)); - awe_voice_change(voice, awe_set_voice_pitch); -} - - -/* - * load a sound patch: - * three types of patches are accepted: AWE, GUS, and SYSEX. - */ - -static int -awe_load_patch(int dev, int format, const char __user *addr, - int offs, int count, int pmgr_flag) -{ - awe_patch_info patch; - int rc = 0; - -#ifdef AWE_HAS_GUS_COMPATIBILITY - if (format == GUS_PATCH) { - return awe_load_guspatch(addr, offs, count, pmgr_flag); - } else -#endif - if (format == SYSEX_PATCH) { - /* no system exclusive message supported yet */ - return 0; - } else if (format != AWE_PATCH) { - printk(KERN_WARNING "AWE32 Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; - } - - if (count < AWE_PATCH_INFO_SIZE) { - printk(KERN_WARNING "AWE32 Error: Patch header too short\n"); - return -EINVAL; - } - if (copy_from_user(((char*)&patch) + offs, addr + offs, - AWE_PATCH_INFO_SIZE - offs)) - return -EFAULT; - - count -= AWE_PATCH_INFO_SIZE; - if (count < patch.len) { - printk(KERN_WARNING "AWE32: sample: Patch record too short (%d<%d)\n", - count, patch.len); - return -EINVAL; - } - - switch (patch.type) { - case AWE_LOAD_INFO: - rc = awe_load_info(&patch, addr, count); - break; - case AWE_LOAD_DATA: - rc = awe_load_data(&patch, addr, count); - break; - case AWE_OPEN_PATCH: - rc = awe_open_patch(&patch, addr, count); - break; - case AWE_CLOSE_PATCH: - rc = awe_close_patch(&patch, addr, count); - break; - case AWE_UNLOAD_PATCH: - rc = awe_unload_patch(&patch, addr, count); - break; - case AWE_REPLACE_DATA: - rc = awe_replace_data(&patch, addr, count); - break; - case AWE_MAP_PRESET: - rc = awe_load_map(&patch, addr, count); - break; - /* case AWE_PROBE_INFO: - rc = awe_probe_info(&patch, addr, count); - break;*/ - case AWE_PROBE_DATA: - rc = awe_probe_data(&patch, addr, count); - break; - case AWE_REMOVE_INFO: - rc = awe_remove_info(&patch, addr, count); - break; - case AWE_LOAD_CHORUS_FX: - rc = awe_load_chorus_fx(&patch, addr, count); - break; - case AWE_LOAD_REVERB_FX: - rc = awe_load_reverb_fx(&patch, addr, count); - break; - - default: - printk(KERN_WARNING "AWE32 Error: unknown patch format type %d\n", - patch.type); - rc = -EINVAL; - } - - return rc; -} - - -/* create an sf list record */ -static int -awe_create_sf(int type, char *name) -{ - sf_list *rec; - - /* terminate sounds */ - awe_reset(0); - rec = (sf_list *)kmalloc(sizeof(*rec), GFP_KERNEL); - if (rec == NULL) - return 1; /* no memory */ - rec->sf_id = current_sf_id + 1; - rec->type = type; - if (/*current_sf_id == 0 ||*/ (type & AWE_PAT_LOCKED) != 0) - locked_sf_id = current_sf_id + 1; - rec->num_info = awe_free_info(); - rec->num_sample = awe_free_sample(); - rec->mem_ptr = awe_free_mem_ptr(); - rec->infos = rec->last_infos = NULL; - rec->samples = rec->last_samples = NULL; - - /* add to linked-list */ - rec->next = NULL; - rec->prev = sftail; - if (sftail) - sftail->next = rec; - else - sfhead = rec; - sftail = rec; - current_sf_id++; - -#ifdef AWE_ALLOW_SAMPLE_SHARING - rec->shared = NULL; - if (name) - memcpy(rec->name, name, AWE_PATCH_NAME_LEN); - else - strcpy(rec->name, "*TEMPORARY*"); - if (current_sf_id > 1 && name && (type & AWE_PAT_SHARED) != 0) { - /* is the current font really a shared font? */ - if (is_shared_sf(rec->name)) { - /* check if the shared font is already installed */ - sf_list *p; - for (p = rec->prev; p; p = p->prev) { - if (is_identical_name(rec->name, p)) { - rec->shared = p; - break; - } - } - } - } -#endif /* allow sharing */ - - return 0; -} - - -#ifdef AWE_ALLOW_SAMPLE_SHARING - -/* check if the given name is a valid shared name */ -#define ASC_TO_KEY(c) ((c) - 'A' + 1) -static int is_shared_sf(unsigned char *name) -{ - static unsigned char id_head[4] = { - ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'), - AWE_MAJOR_VERSION, - }; - if (memcmp(name, id_head, 4) == 0) - return TRUE; - return FALSE; -} - -/* check if the given name matches to the existing list */ -static int is_identical_name(unsigned char *name, sf_list *p) -{ - char *id = p->name; - if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0) - return TRUE; - return FALSE; -} - -/* check if the given voice info exists */ -static int info_duplicated(sf_list *sf, awe_voice_list *rec) -{ - /* search for all sharing lists */ - for (; sf; sf = sf->shared) { - awe_voice_list *p; - for (p = sf->infos; p; p = p->next) { - if (p->type == V_ST_NORMAL && - p->bank == rec->bank && - p->instr == rec->instr && - p->v.low == rec->v.low && - p->v.high == rec->v.high && - p->v.sample == rec->v.sample) - return TRUE; - } - } - return FALSE; -} - -#endif /* AWE_ALLOW_SAMPLE_SHARING */ - - -/* free sf_list record */ -/* linked-list in this function is not cared */ -static void -awe_free_sf(sf_list *sf) -{ - if (sf->infos) { - awe_voice_list *p, *next; - for (p = sf->infos; p; p = next) { - next = p->next; - kfree(p); - } - } - if (sf->samples) { - awe_sample_list *p, *next; - for (p = sf->samples; p; p = next) { - next = p->next; - kfree(p); - } - } - kfree(sf); -} - - -/* open patch; create sf list and set opened flag */ -static int -awe_open_patch(awe_patch_info *patch, const char __user *addr, int count) -{ - awe_open_parm parm; - int shared; - - if (copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm))) - return -EFAULT; - shared = FALSE; - -#ifdef AWE_ALLOW_SAMPLE_SHARING - if (sftail && (parm.type & AWE_PAT_SHARED) != 0) { - /* is the previous font the same font? */ - if (is_identical_name(parm.name, sftail)) { - /* then append to the previous */ - shared = TRUE; - awe_reset(0); - if (parm.type & AWE_PAT_LOCKED) - locked_sf_id = current_sf_id; - } - } -#endif /* allow sharing */ - if (! shared) { - if (awe_create_sf(parm.type, parm.name)) { - printk(KERN_ERR "AWE32: can't open: failed to alloc new list\n"); - return -ENOMEM; - } - } - patch_opened = TRUE; - return current_sf_id; -} - -/* check if the patch is already opened */ -static sf_list * -check_patch_opened(int type, char *name) -{ - if (! patch_opened) { - if (awe_create_sf(type, name)) { - printk(KERN_ERR "AWE32: failed to alloc new list\n"); - return NULL; - } - patch_opened = TRUE; - return sftail; - } - return sftail; -} - -/* close the patch; if no voice is loaded, remove the patch */ -static int -awe_close_patch(awe_patch_info *patch, const char __user *addr, int count) -{ - if (patch_opened && sftail) { - /* if no voice is loaded, release the current patch */ - if (sftail->infos == NULL) { - awe_reset(0); - awe_remove_samples(current_sf_id - 1); - } - } - patch_opened = 0; - return 0; -} - - -/* remove the latest patch */ -static int -awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count) -{ - if (current_sf_id > 0 && current_sf_id > locked_sf_id) { - awe_reset(0); - awe_remove_samples(current_sf_id - 1); - } - return 0; -} - -/* allocate voice info list records */ -static awe_voice_list * -alloc_new_info(void) -{ - awe_voice_list *newlist; - - newlist = kmalloc(sizeof(*newlist), GFP_KERNEL); - if (newlist == NULL) { - printk(KERN_ERR "AWE32: can't alloc info table\n"); - return NULL; - } - return newlist; -} - -/* allocate sample info list records */ -static awe_sample_list * -alloc_new_sample(void) -{ - awe_sample_list *newlist; - - newlist = (awe_sample_list *)kmalloc(sizeof(*newlist), GFP_KERNEL); - if (newlist == NULL) { - printk(KERN_ERR "AWE32: can't alloc sample table\n"); - return NULL; - } - return newlist; -} - -/* load voice map */ -static int -awe_load_map(awe_patch_info *patch, const char __user *addr, int count) -{ - awe_voice_map map; - awe_voice_list *rec, *p; - sf_list *sf; - - /* get the link info */ - if (count < sizeof(map)) { - printk(KERN_WARNING "AWE32 Error: invalid patch info length\n"); - return -EINVAL; - } - if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map))) - return -EFAULT; - - /* check if the identical mapping already exists */ - p = awe_search_instr(map.map_bank, map.map_instr, map.map_key); - for (; p; p = p->next_instr) { - if (p->type == V_ST_MAPPED && - p->v.start == map.src_instr && - p->v.end == map.src_bank && - p->v.fixkey == map.src_key) - return 0; /* already present! */ - } - - if ((sf = check_patch_opened(AWE_PAT_TYPE_MAP, NULL)) == NULL) - return -ENOMEM; - - if ((rec = alloc_new_info()) == NULL) - return -ENOMEM; - - rec->bank = map.map_bank; - rec->instr = map.map_instr; - rec->type = V_ST_MAPPED; - rec->disabled = FALSE; - awe_init_voice_info(&rec->v); - if (map.map_key >= 0) { - rec->v.low = map.map_key; - rec->v.high = map.map_key; - } - rec->v.start = map.src_instr; - rec->v.end = map.src_bank; - rec->v.fixkey = map.src_key; - add_sf_info(sf, rec); - add_info_list(rec); - - return 0; -} - -#if 0 -/* probe preset in the current list -- nothing to be loaded */ -static int -awe_probe_info(awe_patch_info *patch, const char __user *addr, int count) -{ -#ifdef AWE_ALLOW_SAMPLE_SHARING - awe_voice_map map; - awe_voice_list *p; - - if (! patch_opened) - return -EINVAL; - - /* get the link info */ - if (count < sizeof(map)) { - printk(KERN_WARNING "AWE32 Error: invalid patch info length\n"); - return -EINVAL; - } - if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map))) - return -EFAULT; - - /* check if the identical mapping already exists */ - if (sftail == NULL) - return -EINVAL; - p = awe_search_instr(map.src_bank, map.src_instr, map.src_key); - for (; p; p = p->next_instr) { - if (p->type == V_ST_NORMAL && - is_identical_holder(p->holder, sftail) && - p->v.low <= map.src_key && - p->v.high >= map.src_key) - return 0; /* already present! */ - } -#endif /* allow sharing */ - return -EINVAL; -} -#endif - -/* probe sample in the current list -- nothing to be loaded */ -static int -awe_probe_data(awe_patch_info *patch, const char __user *addr, int count) -{ -#ifdef AWE_ALLOW_SAMPLE_SHARING - if (! patch_opened) - return -EINVAL; - - /* search the specified sample by optarg */ - if (search_sample_index(sftail, patch->optarg) != NULL) - return 0; -#endif /* allow sharing */ - return -EINVAL; -} - - -/* remove the present instrument layers */ -static int -remove_info(sf_list *sf, int bank, int instr) -{ - awe_voice_list *prev, *next, *p; - int removed = 0; - - prev = NULL; - for (p = sf->infos; p; p = next) { - next = p->next; - if (p->type == V_ST_NORMAL && - p->bank == bank && p->instr == instr) { - /* remove this layer */ - if (prev) - prev->next = next; - else - sf->infos = next; - if (p == sf->last_infos) - sf->last_infos = prev; - sf->num_info--; - removed++; - kfree(p); - } else - prev = p; - } - if (removed) - rebuild_preset_list(); - return removed; -} - -/* load voice information data */ -static int -awe_load_info(awe_patch_info *patch, const char __user *addr, int count) -{ - int offset; - awe_voice_rec_hdr hdr; - int i; - int total_size; - sf_list *sf; - awe_voice_list *rec; - - if (count < AWE_VOICE_REC_SIZE) { - printk(KERN_WARNING "AWE32 Error: invalid patch info length\n"); - return -EINVAL; - } - - offset = AWE_PATCH_INFO_SIZE; - if (copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE)) - return -EFAULT; - offset += AWE_VOICE_REC_SIZE; - - if (hdr.nvoices <= 0 || hdr.nvoices >= 100) { - printk(KERN_WARNING "AWE32 Error: Invalid voice number %d\n", hdr.nvoices); - return -EINVAL; - } - total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices; - if (count < total_size) { - printk(KERN_WARNING "AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n", - count, hdr.nvoices); - return -EINVAL; - } - - if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL) - return -ENOMEM; - - switch (hdr.write_mode) { - case AWE_WR_EXCLUSIVE: - /* exclusive mode - if the instrument already exists, - return error */ - for (rec = sf->infos; rec; rec = rec->next) { - if (rec->type == V_ST_NORMAL && - rec->bank == hdr.bank && - rec->instr == hdr.instr) - return -EINVAL; - } - break; - case AWE_WR_REPLACE: - /* replace mode - remove the instrument if it already exists */ - remove_info(sf, hdr.bank, hdr.instr); - break; - } - - /* append new layers */ - for (i = 0; i < hdr.nvoices; i++) { - rec = alloc_new_info(); - if (rec == NULL) - return -ENOMEM; - - rec->bank = hdr.bank; - rec->instr = hdr.instr; - rec->type = V_ST_NORMAL; - rec->disabled = FALSE; - - /* copy awe_voice_info parameters */ - if (copy_from_user(&rec->v, addr + offset, AWE_VOICE_INFO_SIZE)) { - kfree(rec); - return -EFAULT; - } - offset += AWE_VOICE_INFO_SIZE; -#ifdef AWE_ALLOW_SAMPLE_SHARING - if (sf && sf->shared) { - if (info_duplicated(sf, rec)) { - kfree(rec); - continue; - } - } -#endif /* allow sharing */ - if (rec->v.mode & AWE_MODE_INIT_PARM) - awe_init_voice_parm(&rec->v.parm); - add_sf_info(sf, rec); - awe_set_sample(rec); - add_info_list(rec); - } - - return 0; -} - - -/* remove instrument layers */ -static int -awe_remove_info(awe_patch_info *patch, const char __user *addr, int count) -{ - unsigned char bank, instr; - sf_list *sf; - - if (! patch_opened || (sf = sftail) == NULL) { - printk(KERN_WARNING "AWE32: remove_info: patch not opened\n"); - return -EINVAL; - } - - bank = ((unsigned short)patch->optarg >> 8) & 0xff; - instr = (unsigned short)patch->optarg & 0xff; - if (! remove_info(sf, bank, instr)) - return -EINVAL; - return 0; -} - - -/* load wave sample data */ -static int -awe_load_data(awe_patch_info *patch, const char __user *addr, int count) -{ - int offset, size; - int rc; - awe_sample_info tmprec; - awe_sample_list *rec; - sf_list *sf; - - if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL) - return -ENOMEM; - - size = (count - AWE_SAMPLE_INFO_SIZE) / 2; - offset = AWE_PATCH_INFO_SIZE; - if (copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE)) - return -EFAULT; - offset += AWE_SAMPLE_INFO_SIZE; - if (size != tmprec.size) { - printk(KERN_WARNING "AWE32: load: sample size differed (%d != %d)\n", - tmprec.size, size); - return -EINVAL; - } - - if (search_sample_index(sf, tmprec.sample) != NULL) { -#ifdef AWE_ALLOW_SAMPLE_SHARING - /* if shared sample, skip this data */ - if (sf->type & AWE_PAT_SHARED) - return 0; -#endif /* allow sharing */ - DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample)); - return -EINVAL; - } - - if ((rec = alloc_new_sample()) == NULL) - return -ENOMEM; - - memcpy(&rec->v, &tmprec, sizeof(tmprec)); - - if (rec->v.size > 0) { - if ((rc = awe_write_wave_data(addr, offset, rec, -1)) < 0) { - kfree(rec); - return rc; - } - sf->mem_ptr += rc; - } - - add_sf_sample(sf, rec); - return 0; -} - - -/* replace wave sample data */ -static int -awe_replace_data(awe_patch_info *patch, const char __user *addr, int count) -{ - int offset; - int size; - int rc; - int channels; - awe_sample_info cursmp; - int save_mem_ptr; - sf_list *sf; - awe_sample_list *rec; - - if (! patch_opened || (sf = sftail) == NULL) { - printk(KERN_WARNING "AWE32: replace: patch not opened\n"); - return -EINVAL; - } - - size = (count - AWE_SAMPLE_INFO_SIZE) / 2; - offset = AWE_PATCH_INFO_SIZE; - if (copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE)) - return -EFAULT; - offset += AWE_SAMPLE_INFO_SIZE; - if (cursmp.size == 0 || size != cursmp.size) { - printk(KERN_WARNING "AWE32: replace: invalid sample size (%d!=%d)\n", - cursmp.size, size); - return -EINVAL; - } - channels = patch->optarg; - if (channels <= 0 || channels > AWE_NORMAL_VOICES) { - printk(KERN_WARNING "AWE32: replace: invalid channels %d\n", channels); - return -EINVAL; - } - - for (rec = sf->samples; rec; rec = rec->next) { - if (rec->v.sample == cursmp.sample) - break; - } - if (rec == NULL) { - printk(KERN_WARNING "AWE32: replace: cannot find existing sample data %d\n", - cursmp.sample); - return -EINVAL; - } - - if (rec->v.size != cursmp.size) { - printk(KERN_WARNING "AWE32: replace: exiting size differed (%d!=%d)\n", - rec->v.size, cursmp.size); - return -EINVAL; - } - - save_mem_ptr = awe_free_mem_ptr(); - sftail->mem_ptr = rec->v.start - awe_mem_start; - memcpy(&rec->v, &cursmp, sizeof(cursmp)); - rec->v.sf_id = current_sf_id; - if ((rc = awe_write_wave_data(addr, offset, rec, channels)) < 0) - return rc; - sftail->mem_ptr = save_mem_ptr; - - return 0; -} - - -/*----------------------------------------------------------------*/ - -static const char __user *readbuf_addr; -static int readbuf_offs; -static int readbuf_flags; - -/* initialize read buffer */ -static int -readbuf_init(const char __user *addr, int offset, awe_sample_info *sp) -{ - readbuf_addr = addr; - readbuf_offs = offset; - readbuf_flags = sp->mode_flags; - return 0; -} - -/* read directly from user buffer */ -static unsigned short -readbuf_word(int pos) -{ - unsigned short c; - /* read from user buffer */ - if (readbuf_flags & AWE_SAMPLE_8BITS) { - unsigned char cc; - get_user(cc, (unsigned char __user *)(readbuf_addr + readbuf_offs + pos)); - c = (unsigned short)cc << 8; /* convert 8bit -> 16bit */ - } else { - get_user(c, (unsigned short __user *)(readbuf_addr + readbuf_offs + pos * 2)); - } - if (readbuf_flags & AWE_SAMPLE_UNSIGNED) - c ^= 0x8000; /* unsigned -> signed */ - return c; -} - -#define readbuf_word_cache readbuf_word -#define readbuf_end() /**/ - -/*----------------------------------------------------------------*/ - -#define BLANK_LOOP_START 8 -#define BLANK_LOOP_END 40 -#define BLANK_LOOP_SIZE 48 - -/* loading onto memory - return the actual written size */ -static int -awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *list, int channels) -{ - int i, truesize, dram_offset; - awe_sample_info *sp = &list->v; - int rc; - - /* be sure loop points start < end */ - if (sp->loopstart > sp->loopend) { - int tmp = sp->loopstart; - sp->loopstart = sp->loopend; - sp->loopend = tmp; - } - - /* compute true data size to be loaded */ - truesize = sp->size; - if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) - truesize += sp->loopend - sp->loopstart; - if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) - truesize += BLANK_LOOP_SIZE; - if (awe_free_mem_ptr() + truesize >= memsize/2) { - DEBUG(-1,printk("AWE32 Error: Sample memory full\n")); - return -ENOSPC; - } - - /* recalculate address offset */ - sp->end -= sp->start; - sp->loopstart -= sp->start; - sp->loopend -= sp->start; - - dram_offset = awe_free_mem_ptr() + awe_mem_start; - sp->start = dram_offset; - sp->end += dram_offset; - sp->loopstart += dram_offset; - sp->loopend += dram_offset; - - /* set the total size (store onto obsolete checksum value) */ - if (sp->size == 0) - sp->checksum = 0; - else - sp->checksum = truesize; - - if ((rc = awe_open_dram_for_write(dram_offset, channels)) != 0) - return rc; - - if (readbuf_init(addr, offset, sp) < 0) - return -ENOSPC; - - for (i = 0; i < sp->size; i++) { - unsigned short c; - c = readbuf_word(i); - awe_write_dram(c); - if (i == sp->loopend && - (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))) { - int looplen = sp->loopend - sp->loopstart; - /* copy reverse loop */ - int k; - for (k = 1; k <= looplen; k++) { - c = readbuf_word_cache(i - k); - awe_write_dram(c); - } - if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) { - sp->end += looplen; - } else { - sp->start += looplen; - sp->end += looplen; - } - } - } - readbuf_end(); - - /* if no blank loop is attached in the sample, add it */ - if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) { - for (i = 0; i < BLANK_LOOP_SIZE; i++) - awe_write_dram(0); - if (sp->mode_flags & AWE_SAMPLE_SINGLESHOT) { - sp->loopstart = sp->end + BLANK_LOOP_START; - sp->loopend = sp->end + BLANK_LOOP_END; - } - } - - awe_close_dram(); - - /* initialize FM */ - awe_init_fm(); - - return truesize; -} - - -/*----------------------------------------------------------------*/ - -#ifdef AWE_HAS_GUS_COMPATIBILITY - -/* calculate GUS envelope time: - * is this correct? i have no idea.. - */ -static int -calc_gus_envelope_time(int rate, int start, int end) -{ - int r, p, t; - r = (3 - ((rate >> 6) & 3)) * 3; - p = rate & 0x3f; - t = end - start; - if (t < 0) t = -t; - if (13 > r) - t = t << (13 - r); - else - t = t >> (r - 13); - return (t * 10) / (p * 441); -} - -#define calc_gus_sustain(val) (0x7f - vol_table[(val)/2]) -#define calc_gus_attenuation(val) vol_table[(val)/2] - -/* load GUS patch */ -static int -awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag) -{ - struct patch_info patch; - awe_voice_info *rec; - awe_sample_info *smp; - awe_voice_list *vrec; - awe_sample_list *smprec; - int sizeof_patch; - int note, rc; - sf_list *sf; - - sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */ - if (size < sizeof_patch) { - printk(KERN_WARNING "AWE32 Error: Patch header too short\n"); - return -EINVAL; - } - if (copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs)) - return -EFAULT; - size -= sizeof_patch; - if (size < patch.len) { - printk(KERN_WARNING "AWE32 Error: Patch record too short (%d<%d)\n", - size, patch.len); - return -EINVAL; - } - if ((sf = check_patch_opened(AWE_PAT_TYPE_GUS, NULL)) == NULL) - return -ENOMEM; - if ((smprec = alloc_new_sample()) == NULL) - return -ENOMEM; - if ((vrec = alloc_new_info()) == NULL) { - kfree(smprec); - return -ENOMEM; - } - - smp = &smprec->v; - smp->sample = sf->num_sample; - smp->start = 0; - smp->end = patch.len; - smp->loopstart = patch.loop_start; - smp->loopend = patch.loop_end; - smp->size = patch.len; - - /* set up mode flags */ - smp->mode_flags = 0; - if (!(patch.mode & WAVE_16_BITS)) - smp->mode_flags |= AWE_SAMPLE_8BITS; - if (patch.mode & WAVE_UNSIGNED) - smp->mode_flags |= AWE_SAMPLE_UNSIGNED; - smp->mode_flags |= AWE_SAMPLE_NO_BLANK; - if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK))) - smp->mode_flags |= AWE_SAMPLE_SINGLESHOT; - if (patch.mode & WAVE_BIDIR_LOOP) - smp->mode_flags |= AWE_SAMPLE_BIDIR_LOOP; - if (patch.mode & WAVE_LOOP_BACK) - smp->mode_flags |= AWE_SAMPLE_REVERSE_LOOP; - - DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, smp->mode_flags)); - if (patch.mode & WAVE_16_BITS) { - /* convert to word offsets */ - smp->size /= 2; - smp->end /= 2; - smp->loopstart /= 2; - smp->loopend /= 2; - } - smp->checksum_flag = 0; - smp->checksum = 0; - - if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0) { - kfree(vrec); - return rc; - } - sf->mem_ptr += rc; - add_sf_sample(sf, smprec); - - /* set up voice info */ - rec = &vrec->v; - awe_init_voice_info(rec); - rec->sample = sf->num_info; /* the last sample */ - rec->rate_offset = calc_rate_offset(patch.base_freq); - note = freq_to_note(patch.base_note); - rec->root = note / 100; - rec->tune = -(note % 100); - rec->low = freq_to_note(patch.low_note) / 100; - rec->high = freq_to_note(patch.high_note) / 100; - DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n", - rec->rate_offset, note, - rec->low, rec->high, - patch.low_note, patch.high_note)); - /* panning position; -128 - 127 => 0-127 */ - rec->pan = (patch.panning + 128) / 2; - - /* detuning is ignored */ - /* 6points volume envelope */ - if (patch.mode & WAVE_ENVELOPES) { - int attack, hold, decay, release; - attack = calc_gus_envelope_time - (patch.env_rate[0], 0, patch.env_offset[0]); - hold = calc_gus_envelope_time - (patch.env_rate[1], patch.env_offset[0], - patch.env_offset[1]); - decay = calc_gus_envelope_time - (patch.env_rate[2], patch.env_offset[1], - patch.env_offset[2]); - release = calc_gus_envelope_time - (patch.env_rate[3], patch.env_offset[1], - patch.env_offset[4]); - release += calc_gus_envelope_time - (patch.env_rate[4], patch.env_offset[3], - patch.env_offset[4]); - release += calc_gus_envelope_time - (patch.env_rate[5], patch.env_offset[4], - patch.env_offset[5]); - rec->parm.volatkhld = (calc_parm_hold(hold) << 8) | - calc_parm_attack(attack); - rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) | - calc_parm_decay(decay); - rec->parm.volrelease = 0x8000 | calc_parm_decay(release); - DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release)); - rec->attenuation = calc_gus_attenuation(patch.env_offset[0]); - } - - /* tremolo effect */ - if (patch.mode & WAVE_TREMOLO) { - int rate = (patch.tremolo_rate * 1000 / 38) / 42; - rec->parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate; - DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n", - patch.tremolo_rate, patch.tremolo_depth, - rec->parm.tremfrq)); - } - /* vibrato effect */ - if (patch.mode & WAVE_VIBRATO) { - int rate = (patch.vibrato_rate * 1000 / 38) / 42; - rec->parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate; - DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n", - patch.tremolo_rate, patch.tremolo_depth, - rec->parm.tremfrq)); - } - - /* scale_freq, scale_factor, volume, and fractions not implemented */ - - /* append to the tail of the list */ - vrec->bank = ctrls[AWE_MD_GUS_BANK]; - vrec->instr = patch.instr_no; - vrec->disabled = FALSE; - vrec->type = V_ST_NORMAL; - - add_sf_info(sf, vrec); - add_info_list(vrec); - - /* set the voice index */ - awe_set_sample(vrec); - - return 0; -} - -#endif /* AWE_HAS_GUS_COMPATIBILITY */ - -/* - * sample and voice list handlers - */ - -/* append this to the current sf list */ -static void add_sf_info(sf_list *sf, awe_voice_list *rec) -{ - if (sf == NULL) - return; - rec->holder = sf; - rec->v.sf_id = sf->sf_id; - if (sf->last_infos) - sf->last_infos->next = rec; - else - sf->infos = rec; - sf->last_infos = rec; - rec->next = NULL; - sf->num_info++; -} - -/* prepend this sample to sf list */ -static void add_sf_sample(sf_list *sf, awe_sample_list *rec) -{ - if (sf == NULL) - return; - rec->holder = sf; - rec->v.sf_id = sf->sf_id; - if (sf->last_samples) - sf->last_samples->next = rec; - else - sf->samples = rec; - sf->last_samples = rec; - rec->next = NULL; - sf->num_sample++; -} - -/* purge the old records which don't belong with the same file id */ -static void purge_old_list(awe_voice_list *rec, awe_voice_list *next) -{ - rec->next_instr = next; - if (rec->bank == AWE_DRUM_BANK) { - /* remove samples with the same note range */ - awe_voice_list *cur, *prev = rec; - int low = rec->v.low; - int high = rec->v.high; - for (cur = next; cur; cur = cur->next_instr) { - if (cur->v.low == low && - cur->v.high == high && - ! is_identical_holder(cur->holder, rec->holder)) - prev->next_instr = cur->next_instr; - else - prev = cur; - } - } else { - if (! is_identical_holder(next->holder, rec->holder)) - /* remove all samples */ - rec->next_instr = NULL; - } -} - -/* prepend to top of the preset table */ -static void add_info_list(awe_voice_list *rec) -{ - awe_voice_list *prev, *cur; - int key; - - if (rec->disabled) - return; - - key = awe_search_key(rec->bank, rec->instr, rec->v.low); - prev = NULL; - for (cur = preset_table[key]; cur; cur = cur->next_bank) { - /* search the first record with the same bank number */ - if (cur->instr == rec->instr && cur->bank == rec->bank) { - /* replace the list with the new record */ - rec->next_bank = cur->next_bank; - if (prev) - prev->next_bank = rec; - else - preset_table[key] = rec; - purge_old_list(rec, cur); - return; - } - prev = cur; - } - - /* this is the first bank record.. just add this */ - rec->next_instr = NULL; - rec->next_bank = preset_table[key]; - preset_table[key] = rec; -} - -/* remove samples later than the specified sf_id */ -static void -awe_remove_samples(int sf_id) -{ - sf_list *p, *prev; - - if (sf_id <= 0) { - awe_reset_samples(); - return; - } - /* already removed? */ - if (current_sf_id <= sf_id) - return; - - for (p = sftail; p; p = prev) { - if (p->sf_id <= sf_id) - break; - prev = p->prev; - awe_free_sf(p); - } - sftail = p; - if (sftail) { - sf_id = sftail->sf_id; - sftail->next = NULL; - } else { - sf_id = 0; - sfhead = NULL; - } - current_sf_id = sf_id; - if (locked_sf_id > sf_id) - locked_sf_id = sf_id; - - rebuild_preset_list(); -} - -/* rebuild preset search list */ -static void rebuild_preset_list(void) -{ - sf_list *p; - awe_voice_list *rec; - - memset(preset_table, 0, sizeof(preset_table)); - - for (p = sfhead; p; p = p->next) { - for (rec = p->infos; rec; rec = rec->next) - add_info_list(rec); - } -} - -/* compare the given sf_id pair */ -static int is_identical_holder(sf_list *sf1, sf_list *sf2) -{ - if (sf1 == NULL || sf2 == NULL) - return FALSE; - if (sf1 == sf2) - return TRUE; -#ifdef AWE_ALLOW_SAMPLE_SHARING - { - /* compare with the sharing id */ - sf_list *p; - int counter = 0; - if (sf1->sf_id < sf2->sf_id) { /* make sure id1 > id2 */ - sf_list *tmp; tmp = sf1; sf1 = sf2; sf2 = tmp; - } - for (p = sf1->shared; p; p = p->shared) { - if (counter++ > current_sf_id) - break; /* strange sharing loop.. quit */ - if (p == sf2) - return TRUE; - } - } -#endif /* allow sharing */ - return FALSE; -} - -/* search the sample index matching with the given sample id */ -static awe_sample_list * -search_sample_index(sf_list *sf, int sample) -{ - awe_sample_list *p; -#ifdef AWE_ALLOW_SAMPLE_SHARING - int counter = 0; - while (sf) { - for (p = sf->samples; p; p = p->next) { - if (p->v.sample == sample) - return p; - } - sf = sf->shared; - if (counter++ > current_sf_id) - break; /* strange sharing loop.. quit */ - } -#else - if (sf) { - for (p = sf->samples; p; p = p->next) { - if (p->v.sample == sample) - return p; - } - } -#endif - return NULL; -} - -/* search the specified sample */ -/* non-zero = found */ -static short -awe_set_sample(awe_voice_list *rec) -{ - awe_sample_list *smp; - awe_voice_info *vp = &rec->v; - - vp->index = 0; - if ((smp = search_sample_index(rec->holder, vp->sample)) == NULL) - return 0; - - /* set the actual sample offsets */ - vp->start += smp->v.start; - vp->end += smp->v.end; - vp->loopstart += smp->v.loopstart; - vp->loopend += smp->v.loopend; - /* copy mode flags */ - vp->mode = smp->v.mode_flags; - /* set flag */ - vp->index = 1; - - return 1; -} - - -/* - * voice allocation - */ - -/* look for all voices associated with the specified note & velocity */ -static int -awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, - awe_voice_info **vlist) -{ - int nvoices; - - nvoices = 0; - for (; rec; rec = rec->next_instr) { - if (note >= rec->v.low && - note <= rec->v.high && - velocity >= rec->v.vellow && - velocity <= rec->v.velhigh) { - if (rec->type == V_ST_MAPPED) { - /* mapper */ - vlist[0] = &rec->v; - return -1; - } - vlist[nvoices++] = &rec->v; - if (nvoices >= AWE_MAX_VOICES) - break; - } - } - return nvoices; -} - -/* store the voice list from the specified note and velocity. - if the preset is mapped, seek for the destination preset, and rewrite - the note number if necessary. - */ -static int -really_alloc_voices(int bank, int instr, int *note, int velocity, awe_voice_info **vlist) -{ - int nvoices; - awe_voice_list *vrec; - int level = 0; - - for (;;) { - vrec = awe_search_instr(bank, instr, *note); - nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); - if (nvoices == 0) { - if (bank == AWE_DRUM_BANK) - /* search default drumset */ - vrec = awe_search_instr(bank, ctrls[AWE_MD_DEF_DRUM], *note); - else - /* search default preset */ - vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr, *note); - nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); - } - if (nvoices == 0) { - if (bank == AWE_DRUM_BANK && ctrls[AWE_MD_DEF_DRUM] != 0) - /* search default drumset */ - vrec = awe_search_instr(bank, 0, *note); - else if (bank != AWE_DRUM_BANK && ctrls[AWE_MD_DEF_BANK] != 0) - /* search default preset */ - vrec = awe_search_instr(0, instr, *note); - nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); - } - if (nvoices < 0) { /* mapping */ - int key = vlist[0]->fixkey; - instr = vlist[0]->start; - bank = vlist[0]->end; - if (level++ > 5) { - printk(KERN_ERR "AWE32: too deep mapping level\n"); - return 0; - } - if (key >= 0) - *note = key; - } else - break; - } - - return nvoices; -} - -/* allocate voices corresponding note and velocity; supports multiple insts. */ -static void -awe_alloc_multi_voices(int ch, int note, int velocity, int key) -{ - int i, v, nvoices, bank; - awe_voice_info *vlist[AWE_MAX_VOICES]; - - if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) - bank = AWE_DRUM_BANK; /* always search drumset */ - else - bank = channels[ch].bank; - - /* check the possible voices; note may be changeable if mapped */ - nvoices = really_alloc_voices(bank, channels[ch].instr, - ¬e, velocity, vlist); - - /* set the voices */ - current_alloc_time++; - for (i = 0; i < nvoices; i++) { - v = awe_clear_voice(); - voices[v].key = key; - voices[v].ch = ch; - voices[v].note = note; - voices[v].velocity = velocity; - voices[v].time = current_alloc_time; - voices[v].cinfo = &channels[ch]; - voices[v].sample = vlist[i]; - voices[v].state = AWE_ST_MARK; - voices[v].layer = nvoices - i - 1; /* in reverse order */ - } - - /* clear the mark in allocated voices */ - for (i = 0; i < awe_max_voices; i++) { - if (voices[i].state == AWE_ST_MARK) - voices[i].state = AWE_ST_OFF; - - } -} - - -/* search an empty voice. - if no empty voice is found, at least terminate a voice - */ -static int -awe_clear_voice(void) -{ - enum { - OFF=0, RELEASED, SUSTAINED, PLAYING, END - }; - struct voice_candidate_t { - int best; - int time; - int vtarget; - } candidate[END]; - int i, type, vtarget; - - vtarget = 0xffff; - for (type = OFF; type < END; type++) { - candidate[type].best = -1; - candidate[type].time = current_alloc_time + 1; - candidate[type].vtarget = vtarget; - } - - for (i = 0; i < awe_max_voices; i++) { - if (voices[i].state & AWE_ST_OFF) - type = OFF; - else if (voices[i].state & AWE_ST_RELEASED) - type = RELEASED; - else if (voices[i].state & AWE_ST_SUSTAINED) - type = SUSTAINED; - else if (voices[i].state & ~AWE_ST_MARK) - type = PLAYING; - else - continue; -#ifdef AWE_CHECK_VTARGET - /* get current volume */ - vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff; -#endif - if (candidate[type].best < 0 || - vtarget < candidate[type].vtarget || - (vtarget == candidate[type].vtarget && - voices[i].time < candidate[type].time)) { - candidate[type].best = i; - candidate[type].time = voices[i].time; - candidate[type].vtarget = vtarget; - } - } - - for (type = OFF; type < END; type++) { - if ((i = candidate[type].best) >= 0) { - if (voices[i].state != AWE_ST_OFF) - awe_terminate(i); - awe_voice_init(i, TRUE); - return i; - } - } - return 0; -} - - -/* search sample for the specified note & velocity and set it on the voice; - * note that voice is the voice index (not channel index) - */ -static void -awe_alloc_one_voice(int voice, int note, int velocity) -{ - int ch, nvoices, bank; - awe_voice_info *vlist[AWE_MAX_VOICES]; - - ch = voices[voice].ch; - if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice)) - bank = AWE_DRUM_BANK; /* always search drumset */ - else - bank = voices[voice].cinfo->bank; - - nvoices = really_alloc_voices(bank, voices[voice].cinfo->instr, - ¬e, velocity, vlist); - if (nvoices > 0) { - voices[voice].time = ++current_alloc_time; - voices[voice].sample = vlist[0]; /* use the first one */ - voices[voice].layer = 0; - voices[voice].note = note; - voices[voice].velocity = velocity; - } -} - - -/* - * sequencer2 functions - */ - -/* search an empty voice; used by sequencer2 */ -static int -awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) -{ - playing_mode = AWE_PLAY_MULTI2; - awe_info.nr_voices = AWE_MAX_CHANNELS; - return awe_clear_voice(); -} - - -/* set up voice; used by sequencer2 */ -static void -awe_setup_voice(int dev, int voice, int chn) -{ - struct channel_info *info; - if (synth_devs[dev] == NULL || - (info = &synth_devs[dev]->chn_info[chn]) == NULL) - return; - - if (voice < 0 || voice >= awe_max_voices) - return; - - DEBUG(2,printk("AWE32: [setup(%d) ch=%d]\n", voice, chn)); - channels[chn].expression_vol = info->controllers[CTL_EXPRESSION]; - channels[chn].main_vol = info->controllers[CTL_MAIN_VOLUME]; - channels[chn].panning = - info->controllers[CTL_PAN] * 2 - 128; /* signed 8bit */ - channels[chn].bender = info->bender_value; /* zero center */ - channels[chn].bank = info->controllers[CTL_BANK_SELECT]; - channels[chn].sustained = info->controllers[CTL_SUSTAIN]; - if (info->controllers[CTL_EXT_EFF_DEPTH]) { - FX_SET(&channels[chn].fx, AWE_FX_REVERB, - info->controllers[CTL_EXT_EFF_DEPTH] * 2); - } - if (info->controllers[CTL_CHORUS_DEPTH]) { - FX_SET(&channels[chn].fx, AWE_FX_CHORUS, - info->controllers[CTL_CHORUS_DEPTH] * 2); - } - awe_set_instr(dev, chn, info->pgm_num); -} - - -#ifdef CONFIG_AWE32_MIXER -/* - * AWE32 mixer device control - */ - -static int awe_mixer_ioctl(int dev, unsigned int cmd, void __user *arg); - -static int my_mixerdev = -1; - -static struct mixer_operations awe_mixer_operations = { - .owner = THIS_MODULE, - .id = "AWE", - .name = "AWE32 Equalizer", - .ioctl = awe_mixer_ioctl, -}; - -static void __init attach_mixer(void) -{ - if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) { - mixer_devs[my_mixerdev] = &awe_mixer_operations; - } -} - -static void unload_mixer(void) -{ - if (my_mixerdev >= 0) - sound_unload_mixerdev(my_mixerdev); -} - -static int -awe_mixer_ioctl(int dev, unsigned int cmd, void __user * arg) -{ - int i, level, value; - - if (((cmd >> 8) & 0xff) != 'M') - return -EINVAL; - - if (get_user(level, (int __user *)arg)) - return -EFAULT; - level = ((level & 0xff) + (level >> 8)) / 2; - DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level)); - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - switch (cmd & 0xff) { - case SOUND_MIXER_BASS: - value = level * 12 / 100; - if (value >= 12) - value = 11; - ctrls[AWE_MD_BASS_LEVEL] = value; - awe_update_equalizer(); - break; - case SOUND_MIXER_TREBLE: - value = level * 12 / 100; - if (value >= 12) - value = 11; - ctrls[AWE_MD_TREBLE_LEVEL] = value; - awe_update_equalizer(); - break; - case SOUND_MIXER_VOLUME: - level = level * 127 / 100; - if (level >= 128) level = 127; - atten_relative = FALSE; - atten_offset = vol_table[level]; - awe_update_volume(); - break; - } - } - switch (cmd & 0xff) { - case SOUND_MIXER_BASS: - level = ctrls[AWE_MD_BASS_LEVEL] * 100 / 24; - level = (level << 8) | level; - break; - case SOUND_MIXER_TREBLE: - level = ctrls[AWE_MD_TREBLE_LEVEL] * 100 / 24; - level = (level << 8) | level; - break; - case SOUND_MIXER_VOLUME: - value = atten_offset; - if (atten_relative) - value += ctrls[AWE_MD_ZERO_ATTEN]; - for (i = 127; i > 0; i--) { - if (value <= vol_table[i]) - break; - } - level = i * 100 / 127; - level = (level << 8) | level; - break; - case SOUND_MIXER_DEVMASK: - level = SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_VOLUME; - break; - default: - level = 0; - break; - } - if (put_user(level, (int __user *)arg)) - return -EFAULT; - return level; -} -#endif /* CONFIG_AWE32_MIXER */ - - -/* - * initialization of Emu8000 - */ - -/* intiailize audio channels */ -static void -awe_init_audio(void) -{ - int ch; - - /* turn off envelope engines */ - for (ch = 0; ch < AWE_MAX_VOICES; ch++) { - awe_poke(AWE_DCYSUSV(ch), 0x80); - } - - /* reset all other parameters to zero */ - for (ch = 0; ch < AWE_MAX_VOICES; ch++) { - awe_poke(AWE_ENVVOL(ch), 0); - awe_poke(AWE_ENVVAL(ch), 0); - awe_poke(AWE_DCYSUS(ch), 0); - awe_poke(AWE_ATKHLDV(ch), 0); - awe_poke(AWE_LFO1VAL(ch), 0); - awe_poke(AWE_ATKHLD(ch), 0); - awe_poke(AWE_LFO2VAL(ch), 0); - awe_poke(AWE_IP(ch), 0); - awe_poke(AWE_IFATN(ch), 0); - awe_poke(AWE_PEFE(ch), 0); - awe_poke(AWE_FMMOD(ch), 0); - awe_poke(AWE_TREMFRQ(ch), 0); - awe_poke(AWE_FM2FRQ2(ch), 0); - awe_poke_dw(AWE_PTRX(ch), 0); - awe_poke_dw(AWE_VTFT(ch), 0); - awe_poke_dw(AWE_PSST(ch), 0); - awe_poke_dw(AWE_CSL(ch), 0); - awe_poke_dw(AWE_CCCA(ch), 0); - } - - for (ch = 0; ch < AWE_MAX_VOICES; ch++) { - awe_poke_dw(AWE_CPF(ch), 0); - awe_poke_dw(AWE_CVCF(ch), 0); - } -} - - -/* initialize DMA address */ -static void -awe_init_dma(void) -{ - awe_poke_dw(AWE_SMALR, 0); - awe_poke_dw(AWE_SMARR, 0); - awe_poke_dw(AWE_SMALW, 0); - awe_poke_dw(AWE_SMARW, 0); -} - - -/* initialization arrays; from ADIP */ - -static unsigned short init1[128] = { - 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330, - 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730, - 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30, - 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30, - - 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330, - 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730, - 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30, - 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30, - - 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330, - 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730, - 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30, - 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30, - - 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330, - 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730, - 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30, - 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30, -}; - -static unsigned short init2[128] = { - 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330, - 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730, - 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30, - 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30, - - 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330, - 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730, - 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30, - 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30, - - 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330, - 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730, - 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30, - 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30, - - 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330, - 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730, - 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30, - 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30, -}; - -static unsigned short init3[128] = { - 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, - 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254, - 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234, - 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224, - - 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254, - 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264, - 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294, - 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3, - - 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287, - 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7, - 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386, - 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55, - - 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308, - 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F, - 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319, - 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570, -}; - -static unsigned short init4[128] = { - 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, - 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254, - 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234, - 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224, - - 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254, - 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264, - 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294, - 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3, - - 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287, - 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7, - 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386, - 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55, - - 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308, - 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F, - 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319, - 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570, -}; - - -/* send initialization arrays to start up */ -static void -awe_init_array(void) -{ - awe_send_array(init1); - awe_wait(1024); - awe_send_array(init2); - awe_send_array(init3); - awe_poke_dw(AWE_HWCF4, 0); - awe_poke_dw(AWE_HWCF5, 0x83); - awe_poke_dw(AWE_HWCF6, 0x8000); - awe_send_array(init4); -} - -/* send an initialization array */ -static void -awe_send_array(unsigned short *data) -{ - int i; - unsigned short *p; - - p = data; - for (i = 0; i < AWE_MAX_VOICES; i++, p++) - awe_poke(AWE_INIT1(i), *p); - for (i = 0; i < AWE_MAX_VOICES; i++, p++) - awe_poke(AWE_INIT2(i), *p); - for (i = 0; i < AWE_MAX_VOICES; i++, p++) - awe_poke(AWE_INIT3(i), *p); - for (i = 0; i < AWE_MAX_VOICES; i++, p++) - awe_poke(AWE_INIT4(i), *p); -} - - -/* - * set up awe32 channels to some known state. - */ - -/* set the envelope & LFO parameters to the default values; see ADIP */ -static void -awe_tweak_voice(int i) -{ - /* set all mod/vol envelope shape to minimum */ - awe_poke(AWE_ENVVOL(i), 0x8000); - awe_poke(AWE_ENVVAL(i), 0x8000); - awe_poke(AWE_DCYSUS(i), 0x7F7F); - awe_poke(AWE_ATKHLDV(i), 0x7F7F); - awe_poke(AWE_ATKHLD(i), 0x7F7F); - awe_poke(AWE_PEFE(i), 0); /* mod envelope height to zero */ - awe_poke(AWE_LFO1VAL(i), 0x8000); /* no delay for LFO1 */ - awe_poke(AWE_LFO2VAL(i), 0x8000); - awe_poke(AWE_IP(i), 0xE000); /* no pitch shift */ - awe_poke(AWE_IFATN(i), 0xFF00); /* volume to minimum */ - awe_poke(AWE_FMMOD(i), 0); - awe_poke(AWE_TREMFRQ(i), 0); - awe_poke(AWE_FM2FRQ2(i), 0); -} - -static void -awe_tweak(void) -{ - int i; - /* reset all channels */ - for (i = 0; i < awe_max_voices; i++) - awe_tweak_voice(i); -} - - -/* - * initializes the FM section of AWE32; - * see Vince Vu's unofficial AWE32 programming guide - */ - -static void -awe_init_fm(void) -{ -#ifndef AWE_ALWAYS_INIT_FM - /* if no extended memory is on board.. */ - if (memsize <= 0) - return; -#endif - DEBUG(3,printk("AWE32: initializing FM\n")); - - /* Initialize the last two channels for DRAM refresh and producing - the reverb and chorus effects for Yamaha OPL-3 synthesizer */ - - /* 31: FM left channel, 0xffffe0-0xffffe8 */ - awe_poke(AWE_DCYSUSV(30), 0x80); - awe_poke_dw(AWE_PSST(30), 0xFFFFFFE0); /* full left */ - awe_poke_dw(AWE_CSL(30), 0x00FFFFE8 | - (DEF_FM_CHORUS_DEPTH << 24)); - awe_poke_dw(AWE_PTRX(30), (DEF_FM_REVERB_DEPTH << 8)); - awe_poke_dw(AWE_CPF(30), 0); - awe_poke_dw(AWE_CCCA(30), 0x00FFFFE3); - - /* 32: FM right channel, 0xfffff0-0xfffff8 */ - awe_poke(AWE_DCYSUSV(31), 0x80); - awe_poke_dw(AWE_PSST(31), 0x00FFFFF0); /* full right */ - awe_poke_dw(AWE_CSL(31), 0x00FFFFF8 | - (DEF_FM_CHORUS_DEPTH << 24)); - awe_poke_dw(AWE_PTRX(31), (DEF_FM_REVERB_DEPTH << 8)); - awe_poke_dw(AWE_CPF(31), 0x8000); - awe_poke_dw(AWE_CCCA(31), 0x00FFFFF3); - - /* skew volume & cutoff */ - awe_poke_dw(AWE_VTFT(30), 0x8000FFFF); - awe_poke_dw(AWE_VTFT(31), 0x8000FFFF); - - voices[30].state = AWE_ST_FM; - voices[31].state = AWE_ST_FM; - - /* change maximum channels to 30 */ - awe_max_voices = AWE_NORMAL_VOICES; - if (playing_mode == AWE_PLAY_DIRECT) - awe_info.nr_voices = awe_max_voices; - else - awe_info.nr_voices = AWE_MAX_CHANNELS; - voice_alloc->max_voice = awe_max_voices; -} - -/* - * AWE32 DRAM access routines - */ - -/* open DRAM write accessing mode */ -static int -awe_open_dram_for_write(int offset, int channels) -{ - int vidx[AWE_NORMAL_VOICES]; - int i; - - if (channels < 0 || channels >= AWE_NORMAL_VOICES) { - channels = AWE_NORMAL_VOICES; - for (i = 0; i < AWE_NORMAL_VOICES; i++) - vidx[i] = i; - } else { - for (i = 0; i < channels; i++) { - vidx[i] = awe_clear_voice(); - voices[vidx[i]].state = AWE_ST_MARK; - } - } - - /* use all channels for DMA transfer */ - for (i = 0; i < channels; i++) { - if (vidx[i] < 0) continue; - awe_poke(AWE_DCYSUSV(vidx[i]), 0x80); - awe_poke_dw(AWE_VTFT(vidx[i]), 0); - awe_poke_dw(AWE_CVCF(vidx[i]), 0); - awe_poke_dw(AWE_PTRX(vidx[i]), 0x40000000); - awe_poke_dw(AWE_CPF(vidx[i]), 0x40000000); - awe_poke_dw(AWE_PSST(vidx[i]), 0); - awe_poke_dw(AWE_CSL(vidx[i]), 0); - awe_poke_dw(AWE_CCCA(vidx[i]), 0x06000000); - voices[vidx[i]].state = AWE_ST_DRAM; - } - /* point channels 31 & 32 to ROM samples for DRAM refresh */ - awe_poke_dw(AWE_VTFT(30), 0); - awe_poke_dw(AWE_PSST(30), 0x1d8); - awe_poke_dw(AWE_CSL(30), 0x1e0); - awe_poke_dw(AWE_CCCA(30), 0x1d8); - awe_poke_dw(AWE_VTFT(31), 0); - awe_poke_dw(AWE_PSST(31), 0x1d8); - awe_poke_dw(AWE_CSL(31), 0x1e0); - awe_poke_dw(AWE_CCCA(31), 0x1d8); - voices[30].state = AWE_ST_FM; - voices[31].state = AWE_ST_FM; - - /* if full bit is on, not ready to write on */ - if (awe_peek_dw(AWE_SMALW) & 0x80000000) { - for (i = 0; i < channels; i++) { - awe_poke_dw(AWE_CCCA(vidx[i]), 0); - voices[vidx[i]].state = AWE_ST_OFF; - } - printk("awe: not ready to write..\n"); - return -EPERM; - } - - /* set address to write */ - awe_poke_dw(AWE_SMALW, offset); - - return 0; -} - -/* open DRAM for RAM size detection */ -static void -awe_open_dram_for_check(void) -{ - int i; - for (i = 0; i < AWE_NORMAL_VOICES; i++) { - awe_poke(AWE_DCYSUSV(i), 0x80); - awe_poke_dw(AWE_VTFT(i), 0); - awe_poke_dw(AWE_CVCF(i), 0); - awe_poke_dw(AWE_PTRX(i), 0x40000000); - awe_poke_dw(AWE_CPF(i), 0x40000000); - awe_poke_dw(AWE_PSST(i), 0); - awe_poke_dw(AWE_CSL(i), 0); - if (i & 1) /* DMA write */ - awe_poke_dw(AWE_CCCA(i), 0x06000000); - else /* DMA read */ - awe_poke_dw(AWE_CCCA(i), 0x04000000); - voices[i].state = AWE_ST_DRAM; - } -} - - -/* close dram access */ -static void -awe_close_dram(void) -{ - int i; - /* wait until FULL bit in SMAxW register be false */ - for (i = 0; i < 10000; i++) { - if (!(awe_peek_dw(AWE_SMALW) & 0x80000000)) - break; - awe_wait(10); - } - - for (i = 0; i < AWE_NORMAL_VOICES; i++) { - if (voices[i].state == AWE_ST_DRAM) { - awe_poke_dw(AWE_CCCA(i), 0); - awe_poke(AWE_DCYSUSV(i), 0x807F); - voices[i].state = AWE_ST_OFF; - } - } -} - - -/* - * check dram size on AWE board - */ - -/* any three numbers you like */ -#define UNIQUE_ID1 0x1234 -#define UNIQUE_ID2 0x4321 -#define UNIQUE_ID3 0xABCD - -static void __init -awe_check_dram(void) -{ - if (awe_present) /* already initialized */ - return; - - if (memsize >= 0) { /* given by config file or module option */ - memsize *= 1024; /* convert to Kbytes */ - return; - } - - awe_open_dram_for_check(); - - memsize = 0; - - /* set up unique two id numbers */ - awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET); - awe_poke(AWE_SMLD, UNIQUE_ID1); - awe_poke(AWE_SMLD, UNIQUE_ID2); - - while (memsize < AWE_MAX_DRAM_SIZE) { - awe_wait(5); - /* read a data on the DRAM start address */ - awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET); - awe_peek(AWE_SMLD); /* discard stale data */ - if (awe_peek(AWE_SMLD) != UNIQUE_ID1) - break; - if (awe_peek(AWE_SMLD) != UNIQUE_ID2) - break; - memsize += 512; /* increment 512kbytes */ - /* Write a unique data on the test address; - * if the address is out of range, the data is written on - * 0x200000(=AWE_DRAM_OFFSET). Then the two id words are - * broken by this data. - */ - awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + memsize*512L); - awe_poke(AWE_SMLD, UNIQUE_ID3); - awe_wait(5); - /* read a data on the just written DRAM address */ - awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + memsize*512L); - awe_peek(AWE_SMLD); /* discard stale data */ - if (awe_peek(AWE_SMLD) != UNIQUE_ID3) - break; - } - awe_close_dram(); - - DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", memsize)); - - /* convert to Kbytes */ - memsize *= 1024; -} - - -/*----------------------------------------------------------------*/ - -/* - * chorus and reverb controls; from VV's guide - */ - -/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */ -static char chorus_defined[AWE_CHORUS_NUMBERS]; -static awe_chorus_fx_rec chorus_parm[AWE_CHORUS_NUMBERS] = { - {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */ - {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */ - {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */ - {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */ - {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */ - {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */ - {0xE600, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay */ - {0xE6C0, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay + feedback */ -}; - -static int -awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count) -{ - if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) { - printk(KERN_WARNING "AWE32 Error: invalid chorus mode %d for uploading\n", patch->optarg); - return -EINVAL; - } - if (count < sizeof(awe_chorus_fx_rec)) { - printk(KERN_WARNING "AWE32 Error: too short chorus fx parameters\n"); - return -EINVAL; - } - if (copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE, - sizeof(awe_chorus_fx_rec))) - return -EFAULT; - chorus_defined[patch->optarg] = TRUE; - return 0; -} - -static void -awe_set_chorus_mode(int effect) -{ - if (effect < 0 || effect >= AWE_CHORUS_NUMBERS || - (effect >= AWE_CHORUS_PREDEFINED && !chorus_defined[effect])) - return; - awe_poke(AWE_INIT3(9), chorus_parm[effect].feedback); - awe_poke(AWE_INIT3(12), chorus_parm[effect].delay_offset); - awe_poke(AWE_INIT4(3), chorus_parm[effect].lfo_depth); - awe_poke_dw(AWE_HWCF4, chorus_parm[effect].delay); - awe_poke_dw(AWE_HWCF5, chorus_parm[effect].lfo_freq); - awe_poke_dw(AWE_HWCF6, 0x8000); - awe_poke_dw(AWE_HWCF7, 0x0000); -} - -static void -awe_update_chorus_mode(void) -{ - awe_set_chorus_mode(ctrls[AWE_MD_CHORUS_MODE]); -} - -/*----------------------------------------------------------------*/ - -/* reverb mode settings; write the following 28 data of 16 bit length - * on the corresponding ports in the reverb_cmds array - */ -static char reverb_defined[AWE_CHORUS_NUMBERS]; -static awe_reverb_fx_rec reverb_parm[AWE_REVERB_NUMBERS] = { -{{ /* room 1 */ - 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4, - 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516, - 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, - 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, -}}, -{{ /* room 2 */ - 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284, - 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548, - 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, - 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, -}}, -{{ /* room 3 */ - 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284, - 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516, - 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B, - 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A, -}}, -{{ /* hall 1 */ - 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284, - 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548, - 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A, - 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, -}}, -{{ /* hall 2 */ - 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254, - 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3, - 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, - 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, -}}, -{{ /* plate */ - 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234, - 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548, - 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, - 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, -}}, -{{ /* delay */ - 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204, - 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500, - 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, - 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, -}}, -{{ /* panning delay */ - 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204, - 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500, - 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, - 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, -}}, -}; - -static struct ReverbCmdPair { - unsigned short cmd, port; -} reverb_cmds[28] = { - {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)}, - {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)}, - {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)}, - {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)}, - {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)}, - {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)}, - {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)}, -}; - -static int -awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count) -{ - if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) { - printk(KERN_WARNING "AWE32 Error: invalid reverb mode %d for uploading\n", patch->optarg); - return -EINVAL; - } - if (count < sizeof(awe_reverb_fx_rec)) { - printk(KERN_WARNING "AWE32 Error: too short reverb fx parameters\n"); - return -EINVAL; - } - if (copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE, - sizeof(awe_reverb_fx_rec))) - return -EFAULT; - reverb_defined[patch->optarg] = TRUE; - return 0; -} - -static void -awe_set_reverb_mode(int effect) -{ - int i; - if (effect < 0 || effect >= AWE_REVERB_NUMBERS || - (effect >= AWE_REVERB_PREDEFINED && !reverb_defined[effect])) - return; - for (i = 0; i < 28; i++) - awe_poke(reverb_cmds[i].cmd, reverb_cmds[i].port, - reverb_parm[effect].parms[i]); -} - -static void -awe_update_reverb_mode(void) -{ - awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]); -} - -/* - * treble/bass equalizer control - */ - -static unsigned short bass_parm[12][3] = { - {0xD26A, 0xD36A, 0x0000}, /* -12 dB */ - {0xD25B, 0xD35B, 0x0000}, /* -8 */ - {0xD24C, 0xD34C, 0x0000}, /* -6 */ - {0xD23D, 0xD33D, 0x0000}, /* -4 */ - {0xD21F, 0xD31F, 0x0000}, /* -2 */ - {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */ - {0xC219, 0xC319, 0x0001}, /* +2 */ - {0xC22A, 0xC32A, 0x0001}, /* +4 */ - {0xC24C, 0xC34C, 0x0001}, /* +6 */ - {0xC26E, 0xC36E, 0x0001}, /* +8 */ - {0xC248, 0xC348, 0x0002}, /* +10 */ - {0xC26A, 0xC36A, 0x0002}, /* +12 dB */ -}; - -static unsigned short treble_parm[12][9] = { - {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */ - {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, - {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, - {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, - {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, - {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002}, - {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002}, - {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002}, - {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002}, - {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */ - {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, - {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +12 dB */ -}; - - -/* - * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB] - */ -static void -awe_equalizer(int bass, int treble) -{ - unsigned short w; - - if (bass < 0 || bass > 11 || treble < 0 || treble > 11) - return; - awe_poke(AWE_INIT4(0x01), bass_parm[bass][0]); - awe_poke(AWE_INIT4(0x11), bass_parm[bass][1]); - awe_poke(AWE_INIT3(0x11), treble_parm[treble][0]); - awe_poke(AWE_INIT3(0x13), treble_parm[treble][1]); - awe_poke(AWE_INIT3(0x1B), treble_parm[treble][2]); - awe_poke(AWE_INIT4(0x07), treble_parm[treble][3]); - awe_poke(AWE_INIT4(0x0B), treble_parm[treble][4]); - awe_poke(AWE_INIT4(0x0D), treble_parm[treble][5]); - awe_poke(AWE_INIT4(0x17), treble_parm[treble][6]); - awe_poke(AWE_INIT4(0x19), treble_parm[treble][7]); - w = bass_parm[bass][2] + treble_parm[treble][8]; - awe_poke(AWE_INIT4(0x15), (unsigned short)(w + 0x0262)); - awe_poke(AWE_INIT4(0x1D), (unsigned short)(w + 0x8362)); -} - -static void awe_update_equalizer(void) -{ - awe_equalizer(ctrls[AWE_MD_BASS_LEVEL], ctrls[AWE_MD_TREBLE_LEVEL]); -} - - -/*----------------------------------------------------------------*/ - -#ifdef CONFIG_AWE32_MIDIEMU - -/* - * Emu8000 MIDI Emulation - */ - -/* - * midi queue record - */ - -/* queue type */ -enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, }; - -#define MAX_MIDIBUF 64 - -/* midi status */ -typedef struct MidiStatus { - int queue; /* queue type */ - int qlen; /* queue length */ - int read; /* chars read */ - int status; /* current status */ - int chan; /* current channel */ - unsigned char buf[MAX_MIDIBUF]; -} MidiStatus; - -/* MIDI mode type */ -enum { MODE_GM, MODE_GS, MODE_XG, }; - -/* NRPN / CC -> Emu8000 parameter converter */ -typedef struct { - int control; - int awe_effect; - unsigned short (*convert)(int val); -} ConvTable; - - -/* - * prototypes - */ - -static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int)); -static void awe_midi_close(int dev); -static int awe_midi_ioctl(int dev, unsigned cmd, void __user * arg); -static int awe_midi_outputc(int dev, unsigned char midi_byte); - -static void init_midi_status(MidiStatus *st); -static void clear_rpn(void); -static void get_midi_char(MidiStatus *st, int c); -/*static void queue_varlen(MidiStatus *st, int c);*/ -static void special_event(MidiStatus *st, int c); -static void queue_read(MidiStatus *st, int c); -static void midi_note_on(MidiStatus *st); -static void midi_note_off(MidiStatus *st); -static void midi_key_pressure(MidiStatus *st); -static void midi_channel_pressure(MidiStatus *st); -static void midi_pitch_wheel(MidiStatus *st); -static void midi_program_change(MidiStatus *st); -static void midi_control_change(MidiStatus *st); -static void midi_select_bank(MidiStatus *st, int val); -static void midi_nrpn_event(MidiStatus *st); -static void midi_rpn_event(MidiStatus *st); -static void midi_detune(int chan, int coarse, int fine); -static void midi_system_exclusive(MidiStatus *st); -static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val); -static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val); -static int xg_control_change(MidiStatus *st, int cmd, int val); - -#define numberof(ary) (sizeof(ary)/sizeof(ary[0])) - - -/* - * OSS Midi device record - */ - -static struct midi_operations awe_midi_operations = -{ - .owner = THIS_MODULE, - .info = {"AWE Midi Emu", 0, 0, SNDCARD_SB}, - .in_info = {0}, - .open = awe_midi_open, /*open*/ - .close = awe_midi_close, /*close*/ - .ioctl = awe_midi_ioctl, /*ioctl*/ - .outputc = awe_midi_outputc, /*outputc*/ -}; - -static int my_mididev = -1; - -static void __init attach_midiemu(void) -{ - if ((my_mididev = sound_alloc_mididev()) < 0) - printk ("Sound: Too many midi devices detected\n"); - else - midi_devs[my_mididev] = &awe_midi_operations; -} - -static void unload_midiemu(void) -{ - if (my_mididev >= 0) - sound_unload_mididev(my_mididev); -} - - -/* - * open/close midi device - */ - -static int midi_opened = FALSE; - -static int midi_mode; -static int coarsetune, finetune; - -static int xg_mapping = TRUE; -static int xg_bankmode; - -/* effect sensitivity */ - -#define FX_CUTOFF 0 -#define FX_RESONANCE 1 -#define FX_ATTACK 2 -#define FX_RELEASE 3 -#define FX_VIBRATE 4 -#define FX_VIBDEPTH 5 -#define FX_VIBDELAY 6 -#define FX_NUMS 7 - -#define DEF_FX_CUTOFF 170 -#define DEF_FX_RESONANCE 6 -#define DEF_FX_ATTACK 50 -#define DEF_FX_RELEASE 50 -#define DEF_FX_VIBRATE 30 -#define DEF_FX_VIBDEPTH 4 -#define DEF_FX_VIBDELAY 1500 - -/* effect sense: */ -static int gs_sense[] = -{ - DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE, - DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY -}; -static int xg_sense[] = -{ - DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE, - DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY -}; - - -/* current status */ -static MidiStatus curst; - - -static int -awe_midi_open (int dev, int mode, - void (*input)(int,unsigned char), - void (*output)(int)) -{ - if (midi_opened) - return -EBUSY; - - midi_opened = TRUE; - - midi_mode = MODE_GM; - - curst.queue = Q_NONE; - curst.qlen = 0; - curst.read = 0; - curst.status = 0; - curst.chan = 0; - memset(curst.buf, 0, sizeof(curst.buf)); - - init_midi_status(&curst); - - return 0; -} - -static void -awe_midi_close (int dev) -{ - midi_opened = FALSE; -} - - -static int -awe_midi_ioctl (int dev, unsigned cmd, void __user *arg) -{ - return -EPERM; -} - -static int -awe_midi_outputc (int dev, unsigned char midi_byte) -{ - if (! midi_opened) - return 1; - - /* force to change playing mode */ - playing_mode = AWE_PLAY_MULTI; - - get_midi_char(&curst, midi_byte); - return 1; -} - - -/* - * initialize - */ - -static void init_midi_status(MidiStatus *st) -{ - clear_rpn(); - coarsetune = 0; - finetune = 0; -} - - -/* - * RPN & NRPN - */ - -#define MAX_MIDI_CHANNELS 16 - -/* RPN & NRPN */ -static unsigned char nrpn[MAX_MIDI_CHANNELS]; /* current event is NRPN? */ -static int msb_bit; /* current event is msb for RPN/NRPN */ -/* RPN & NRPN indeces */ -static unsigned char rpn_msb[MAX_MIDI_CHANNELS], rpn_lsb[MAX_MIDI_CHANNELS]; -/* RPN & NRPN values */ -static int rpn_val[MAX_MIDI_CHANNELS]; - -static void clear_rpn(void) -{ - int i; - for (i = 0; i < MAX_MIDI_CHANNELS; i++) { - nrpn[i] = 0; - rpn_msb[i] = 127; - rpn_lsb[i] = 127; - rpn_val[i] = 0; - } - msb_bit = 0; -} - - -/* - * process midi queue - */ - -/* status event types */ -typedef void (*StatusEvent)(MidiStatus *st); -static struct StatusEventList { - StatusEvent process; - int qlen; -} status_event[8] = { - {midi_note_off, 2}, - {midi_note_on, 2}, - {midi_key_pressure, 2}, - {midi_control_change, 2}, - {midi_program_change, 1}, - {midi_channel_pressure, 1}, - {midi_pitch_wheel, 2}, - {NULL, 0}, -}; - - -/* read a char from fifo and process it */ -static void get_midi_char(MidiStatus *st, int c) -{ - if (c == 0xfe) { - /* ignore active sense */ - st->queue = Q_NONE; - return; - } - - switch (st->queue) { - /* case Q_VARLEN: queue_varlen(st, c); break;*/ - case Q_READ: - case Q_SYSEX: - queue_read(st, c); - break; - case Q_NONE: - st->read = 0; - if ((c & 0xf0) == 0xf0) { - special_event(st, c); - } else if (c & 0x80) { /* status change */ - st->status = (c >> 4) & 0x07; - st->chan = c & 0x0f; - st->queue = Q_READ; - st->qlen = status_event[st->status].qlen; - if (st->qlen == 0) - st->queue = Q_NONE; - } - break; - } -} - -/* 0xfx events */ -static void special_event(MidiStatus *st, int c) -{ - switch (c) { - case 0xf0: /* system exclusive */ - st->queue = Q_SYSEX; - st->qlen = 0; - break; - case 0xf1: /* MTC quarter frame */ - case 0xf3: /* song select */ - st->queue = Q_READ; - st->qlen = 1; - break; - case 0xf2: /* song position */ - st->queue = Q_READ; - st->qlen = 2; - break; - } -} - -#if 0 -/* read variable length value */ -static void queue_varlen(MidiStatus *st, int c) -{ - st->qlen += (c & 0x7f); - if (c & 0x80) { - st->qlen <<= 7; - return; - } - if (st->qlen <= 0) { - st->qlen = 0; - st->queue = Q_NONE; - } - st->queue = Q_READ; - st->read = 0; -} -#endif - - -/* read a char */ -static void queue_read(MidiStatus *st, int c) -{ - if (st->read < MAX_MIDIBUF) { - if (st->queue != Q_SYSEX) - c &= 0x7f; - st->buf[st->read] = (unsigned char)c; - } - st->read++; - if (st->queue == Q_SYSEX && c == 0xf7) { - midi_system_exclusive(st); - st->queue = Q_NONE; - } else if (st->queue == Q_READ && st->read >= st->qlen) { - if (status_event[st->status].process) - status_event[st->status].process(st); - st->queue = Q_NONE; - } -} - - -/* - * status events - */ - -/* note on */ -static void midi_note_on(MidiStatus *st) -{ - DEBUG(2,printk("midi: note_on (%d) %d %d\n", st->chan, st->buf[0], st->buf[1])); - if (st->buf[1] == 0) - midi_note_off(st); - else - awe_start_note(0, st->chan, st->buf[0], st->buf[1]); -} - -/* note off */ -static void midi_note_off(MidiStatus *st) -{ - DEBUG(2,printk("midi: note_off (%d) %d %d\n", st->chan, st->buf[0], st->buf[1])); - awe_kill_note(0, st->chan, st->buf[0], st->buf[1]); -} - -/* key pressure change */ -static void midi_key_pressure(MidiStatus *st) -{ - awe_key_pressure(0, st->chan, st->buf[0], st->buf[1]); -} - -/* channel pressure change */ -static void midi_channel_pressure(MidiStatus *st) -{ - channels[st->chan].chan_press = st->buf[0]; - awe_modwheel_change(st->chan, st->buf[0]); -} - -/* pitch wheel change */ -static void midi_pitch_wheel(MidiStatus *st) -{ - int val = (int)st->buf[1] * 128 + st->buf[0]; - awe_bender(0, st->chan, val); -} - -/* program change */ -static void midi_program_change(MidiStatus *st) -{ - int preset; - preset = st->buf[0]; - if (midi_mode == MODE_GS && IS_DRUM_CHANNEL(st->chan) && preset == 127) - preset = 0; - else if (midi_mode == MODE_XG && xg_mapping && IS_DRUM_CHANNEL(st->chan)) - preset += 64; - - awe_set_instr(0, st->chan, preset); -} - -#define send_effect(chan,type,val) awe_send_effect(chan,-1,type,val) -#define add_effect(chan,type,val) awe_send_effect(chan,-1,(type)|0x80,val) -#define unset_effect(chan,type) awe_send_effect(chan,-1,(type)|0x40,0) - -/* midi control change */ -static void midi_control_change(MidiStatus *st) -{ - int cmd = st->buf[0]; - int val = st->buf[1]; - - DEBUG(2,printk("midi: control (%d) %d %d\n", st->chan, cmd, val)); - if (midi_mode == MODE_XG) { - if (xg_control_change(st, cmd, val)) - return; - } - - /* controls #31 - #64 are LSB of #0 - #31 */ - msb_bit = 1; - if (cmd >= 0x20 && cmd < 0x40) { - msb_bit = 0; - cmd -= 0x20; - } - - switch (cmd) { - case CTL_SOFT_PEDAL: - if (val == 127) - add_effect(st->chan, AWE_FX_CUTOFF, -160); - else - unset_effect(st->chan, AWE_FX_CUTOFF); - break; - - case CTL_BANK_SELECT: - midi_select_bank(st, val); - break; - - /* set RPN/NRPN parameter */ - case CTL_REGIST_PARM_NUM_MSB: - nrpn[st->chan]=0; rpn_msb[st->chan]=val; - break; - case CTL_REGIST_PARM_NUM_LSB: - nrpn[st->chan]=0; rpn_lsb[st->chan]=val; - break; - case CTL_NONREG_PARM_NUM_MSB: - nrpn[st->chan]=1; rpn_msb[st->chan]=val; - break; - case CTL_NONREG_PARM_NUM_LSB: - nrpn[st->chan]=1; rpn_lsb[st->chan]=val; - break; - - /* send RPN/NRPN entry */ - case CTL_DATA_ENTRY: - if (msb_bit) - rpn_val[st->chan] = val * 128; - else - rpn_val[st->chan] |= val; - if (nrpn[st->chan]) - midi_nrpn_event(st); - else - midi_rpn_event(st); - break; - - /* increase/decrease data entry */ - case CTL_DATA_INCREMENT: - rpn_val[st->chan]++; - midi_rpn_event(st); - break; - case CTL_DATA_DECREMENT: - rpn_val[st->chan]--; - midi_rpn_event(st); - break; - - /* default */ - default: - awe_controller(0, st->chan, cmd, val); - break; - } -} - -/* tone bank change */ -static void midi_select_bank(MidiStatus *st, int val) -{ - if (midi_mode == MODE_XG && msb_bit) { - xg_bankmode = val; - /* XG MSB value; not normal bank selection */ - switch (val) { - case 127: /* remap to drum channel */ - awe_controller(0, st->chan, CTL_BANK_SELECT, 128); - break; - default: /* remap to normal channel */ - awe_controller(0, st->chan, CTL_BANK_SELECT, val); - break; - } - return; - } else if (midi_mode == MODE_GS && !msb_bit) - /* ignore LSB bank in GS mode (used for mapping) */ - return; - - /* normal bank controls; accept both MSB and LSB */ - if (! IS_DRUM_CHANNEL(st->chan)) { - if (midi_mode == MODE_XG) { - if (xg_bankmode) return; - if (val == 64 || val == 126) - val = 0; - } else if (midi_mode == MODE_GS && val == 127) - val = 0; - awe_controller(0, st->chan, CTL_BANK_SELECT, val); - } -} - - -/* - * RPN events - */ - -static void midi_rpn_event(MidiStatus *st) -{ - int type; - type = (rpn_msb[st->chan]<<8) | rpn_lsb[st->chan]; - switch (type) { - case 0x0000: /* Pitch bend sensitivity */ - /* MSB only / 1 semitone per 128 */ - if (msb_bit) { - channels[st->chan].bender_range = - rpn_val[st->chan] * 100 / 128; - } - break; - - case 0x0001: /* fine tuning: */ - /* MSB/LSB, 8192=center, 100/8192 cent step */ - finetune = rpn_val[st->chan] - 8192; - midi_detune(st->chan, coarsetune, finetune); - break; - - case 0x0002: /* coarse tuning */ - /* MSB only / 8192=center, 1 semitone per 128 */ - if (msb_bit) { - coarsetune = rpn_val[st->chan] - 8192; - midi_detune(st->chan, coarsetune, finetune); - } - break; - - case 0x7F7F: /* "lock-in" RPN */ - break; - } -} - - -/* tuning: - * coarse = -8192 to 8192 (100 cent per 128) - * fine = -8192 to 8192 (max=100cent) - */ -static void midi_detune(int chan, int coarse, int fine) -{ - /* 4096 = 1200 cents in AWE parameter */ - int val; - val = coarse * 4096 / (12 * 128); - val += fine / 24; - if (val) - send_effect(chan, AWE_FX_INIT_PITCH, val); - else - unset_effect(chan, AWE_FX_INIT_PITCH); -} - - -/* - * system exclusive message - * GM/GS/XG macros are accepted - */ - -static void midi_system_exclusive(MidiStatus *st) -{ - /* GM on */ - static unsigned char gm_on_macro[] = { - 0x7e,0x7f,0x09,0x01, - }; - /* XG on */ - static unsigned char xg_on_macro[] = { - 0x43,0x10,0x4c,0x00,0x00,0x7e,0x00, - }; - /* GS prefix - * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off - * reverb mode: XX=0x01, YY=0x30, ZZ=0-7 - * chorus mode: XX=0x01, YY=0x38, ZZ=0-7 - */ - static unsigned char gs_pfx_macro[] = { - 0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/ - }; - -#if 0 - /* SC88 system mode set - * single module mode: XX=1 - * double module mode: XX=0 - */ - static unsigned char gs_mode_macro[] = { - 0x41,0x10,0x42,0x12,0x00,0x00,0x7F,/*ZZ*/ - }; - /* SC88 display macro: XX=01:bitmap, 00:text - */ - static unsigned char gs_disp_macro[] = { - 0x41,0x10,0x45,0x12,0x10,/*XX,00*/ - }; -#endif - - /* GM on */ - if (memcmp(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) { - if (midi_mode != MODE_GS && midi_mode != MODE_XG) - midi_mode = MODE_GM; - init_midi_status(st); - } - - /* GS macros */ - else if (memcmp(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) { - if (midi_mode != MODE_GS && midi_mode != MODE_XG) - midi_mode = MODE_GS; - - if (st->buf[5] == 0x00 && st->buf[6] == 0x7f && st->buf[7] == 0x00) { - /* GS reset */ - init_midi_status(st); - } - - else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x15) { - /* drum pattern */ - int p = st->buf[5] & 0x0f; - if (p == 0) p = 9; - else if (p < 10) p--; - if (st->buf[7] == 0) - DRUM_CHANNEL_OFF(p); - else - DRUM_CHANNEL_ON(p); - - } else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x21) { - /* program */ - int p = st->buf[5] & 0x0f; - if (p == 0) p = 9; - else if (p < 10) p--; - if (! IS_DRUM_CHANNEL(p)) - awe_set_instr(0, p, st->buf[7]); - - } else if (st->buf[5] == 0x01 && st->buf[6] == 0x30) { - /* reverb mode */ - awe_set_reverb_mode(st->buf[7]); - - } else if (st->buf[5] == 0x01 && st->buf[6] == 0x38) { - /* chorus mode */ - awe_set_chorus_mode(st->buf[7]); - - } else if (st->buf[5] == 0x00 && st->buf[6] == 0x04) { - /* master volume */ - awe_change_master_volume(st->buf[7]); - - } - } - - /* XG on */ - else if (memcmp(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) { - midi_mode = MODE_XG; - xg_mapping = TRUE; - xg_bankmode = 0; - } -} - - -/*----------------------------------------------------------------*/ - -/* - * convert NRPN/control values - */ - -static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val) -{ - int i, cval; - for (i = 0; i < num_tables; i++) { - if (table[i].control == type) { - cval = table[i].convert(val); - send_effect(st->chan, table[i].awe_effect, cval); - return TRUE; - } - } - return FALSE; -} - -static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val) -{ - int i, cval; - for (i = 0; i < num_tables; i++) { - if (table[i].control == type) { - cval = table[i].convert(val); - add_effect(st->chan, table[i].awe_effect|0x80, cval); - return TRUE; - } - } - return FALSE; -} - - -/* - * AWE32 NRPN effects - */ - -static unsigned short fx_delay(int val); -static unsigned short fx_attack(int val); -static unsigned short fx_hold(int val); -static unsigned short fx_decay(int val); -static unsigned short fx_the_value(int val); -static unsigned short fx_twice_value(int val); -static unsigned short fx_conv_pitch(int val); -static unsigned short fx_conv_Q(int val); - -/* function for each NRPN */ /* [range] units */ -#define fx_env1_delay fx_delay /* [0,5900] 4msec */ -#define fx_env1_attack fx_attack /* [0,5940] 1msec */ -#define fx_env1_hold fx_hold /* [0,8191] 1msec */ -#define fx_env1_decay fx_decay /* [0,5940] 4msec */ -#define fx_env1_release fx_decay /* [0,5940] 4msec */ -#define fx_env1_sustain fx_the_value /* [0,127] 0.75dB */ -#define fx_env1_pitch fx_the_value /* [-127,127] 9.375cents */ -#define fx_env1_cutoff fx_the_value /* [-127,127] 56.25cents */ - -#define fx_env2_delay fx_delay /* [0,5900] 4msec */ -#define fx_env2_attack fx_attack /* [0,5940] 1msec */ -#define fx_env2_hold fx_hold /* [0,8191] 1msec */ -#define fx_env2_decay fx_decay /* [0,5940] 4msec */ -#define fx_env2_release fx_decay /* [0,5940] 4msec */ -#define fx_env2_sustain fx_the_value /* [0,127] 0.75dB */ - -#define fx_lfo1_delay fx_delay /* [0,5900] 4msec */ -#define fx_lfo1_freq fx_twice_value /* [0,127] 84mHz */ -#define fx_lfo1_volume fx_twice_value /* [0,127] 0.1875dB */ -#define fx_lfo1_pitch fx_the_value /* [-127,127] 9.375cents */ -#define fx_lfo1_cutoff fx_twice_value /* [-64,63] 56.25cents */ - -#define fx_lfo2_delay fx_delay /* [0,5900] 4msec */ -#define fx_lfo2_freq fx_twice_value /* [0,127] 84mHz */ -#define fx_lfo2_pitch fx_the_value /* [-127,127] 9.375cents */ - -#define fx_init_pitch fx_conv_pitch /* [-8192,8192] cents */ -#define fx_chorus fx_the_value /* [0,255] -- */ -#define fx_reverb fx_the_value /* [0,255] -- */ -#define fx_cutoff fx_twice_value /* [0,127] 62Hz */ -#define fx_filterQ fx_conv_Q /* [0,127] -- */ - -static unsigned short fx_delay(int val) -{ - return (unsigned short)calc_parm_delay(val); -} - -static unsigned short fx_attack(int val) -{ - return (unsigned short)calc_parm_attack(val); -} - -static unsigned short fx_hold(int val) -{ - return (unsigned short)calc_parm_hold(val); -} - -static unsigned short fx_decay(int val) -{ - return (unsigned short)calc_parm_decay(val); -} - -static unsigned short fx_the_value(int val) -{ - return (unsigned short)(val & 0xff); -} - -static unsigned short fx_twice_value(int val) -{ - return (unsigned short)((val * 2) & 0xff); -} - -static unsigned short fx_conv_pitch(int val) -{ - return (short)(val * 4096 / 1200); -} - -static unsigned short fx_conv_Q(int val) -{ - return (unsigned short)((val / 8) & 0xff); -} - - -static ConvTable awe_effects[] = -{ - { 0, AWE_FX_LFO1_DELAY, fx_lfo1_delay}, - { 1, AWE_FX_LFO1_FREQ, fx_lfo1_freq}, - { 2, AWE_FX_LFO2_DELAY, fx_lfo2_delay}, - { 3, AWE_FX_LFO2_FREQ, fx_lfo2_freq}, - - { 4, AWE_FX_ENV1_DELAY, fx_env1_delay}, - { 5, AWE_FX_ENV1_ATTACK,fx_env1_attack}, - { 6, AWE_FX_ENV1_HOLD, fx_env1_hold}, - { 7, AWE_FX_ENV1_DECAY, fx_env1_decay}, - { 8, AWE_FX_ENV1_SUSTAIN, fx_env1_sustain}, - { 9, AWE_FX_ENV1_RELEASE, fx_env1_release}, - - {10, AWE_FX_ENV2_DELAY, fx_env2_delay}, - {11, AWE_FX_ENV2_ATTACK, fx_env2_attack}, - {12, AWE_FX_ENV2_HOLD, fx_env2_hold}, - {13, AWE_FX_ENV2_DECAY, fx_env2_decay}, - {14, AWE_FX_ENV2_SUSTAIN, fx_env2_sustain}, - {15, AWE_FX_ENV2_RELEASE, fx_env2_release}, - - {16, AWE_FX_INIT_PITCH, fx_init_pitch}, - {17, AWE_FX_LFO1_PITCH, fx_lfo1_pitch}, - {18, AWE_FX_LFO2_PITCH, fx_lfo2_pitch}, - {19, AWE_FX_ENV1_PITCH, fx_env1_pitch}, - {20, AWE_FX_LFO1_VOLUME, fx_lfo1_volume}, - {21, AWE_FX_CUTOFF, fx_cutoff}, - {22, AWE_FX_FILTERQ, fx_filterQ}, - {23, AWE_FX_LFO1_CUTOFF, fx_lfo1_cutoff}, - {24, AWE_FX_ENV1_CUTOFF, fx_env1_cutoff}, - {25, AWE_FX_CHORUS, fx_chorus}, - {26, AWE_FX_REVERB, fx_reverb}, -}; - -static int num_awe_effects = numberof(awe_effects); - - -/* - * GS(SC88) NRPN effects; still experimental - */ - -/* cutoff: quarter semitone step, max=255 */ -static unsigned short gs_cutoff(int val) -{ - return (val - 64) * gs_sense[FX_CUTOFF] / 50; -} - -/* resonance: 0 to 15(max) */ -static unsigned short gs_filterQ(int val) -{ - return (val - 64) * gs_sense[FX_RESONANCE] / 50; -} - -/* attack: */ -static unsigned short gs_attack(int val) -{ - return -(val - 64) * gs_sense[FX_ATTACK] / 50; -} - -/* decay: */ -static unsigned short gs_decay(int val) -{ - return -(val - 64) * gs_sense[FX_RELEASE] / 50; -} - -/* release: */ -static unsigned short gs_release(int val) -{ - return -(val - 64) * gs_sense[FX_RELEASE] / 50; -} - -/* vibrato freq: 0.042Hz step, max=255 */ -static unsigned short gs_vib_rate(int val) -{ - return (val - 64) * gs_sense[FX_VIBRATE] / 50; -} - -/* vibrato depth: max=127, 1 octave */ -static unsigned short gs_vib_depth(int val) -{ - return (val - 64) * gs_sense[FX_VIBDEPTH] / 50; -} - -/* vibrato delay: -0.725msec step */ -static unsigned short gs_vib_delay(int val) -{ - return -(val - 64) * gs_sense[FX_VIBDELAY] / 50; -} - -static ConvTable gs_effects[] = -{ - {32, AWE_FX_CUTOFF, gs_cutoff}, - {33, AWE_FX_FILTERQ, gs_filterQ}, - {99, AWE_FX_ENV2_ATTACK, gs_attack}, - {100, AWE_FX_ENV2_DECAY, gs_decay}, - {102, AWE_FX_ENV2_RELEASE, gs_release}, - {8, AWE_FX_LFO1_FREQ, gs_vib_rate}, - {9, AWE_FX_LFO1_VOLUME, gs_vib_depth}, - {10, AWE_FX_LFO1_DELAY, gs_vib_delay}, -}; - -static int num_gs_effects = numberof(gs_effects); - - -/* - * NRPN events: accept as AWE32/SC88 specific controls - */ - -static void midi_nrpn_event(MidiStatus *st) -{ - if (rpn_msb[st->chan] == 127 && rpn_lsb[st->chan] <= 26) { - if (! msb_bit) /* both MSB/LSB necessary */ - send_converted_effect(awe_effects, num_awe_effects, - st, rpn_lsb[st->chan], - rpn_val[st->chan] - 8192); - } else if (rpn_msb[st->chan] == 1) { - if (msb_bit) /* only MSB is valid */ - add_converted_effect(gs_effects, num_gs_effects, - st, rpn_lsb[st->chan], - rpn_val[st->chan] / 128); - } -} - - -/* - * XG control effects; still experimental - */ - -/* cutoff: quarter semitone step, max=255 */ -static unsigned short xg_cutoff(int val) -{ - return (val - 64) * xg_sense[FX_CUTOFF] / 64; -} - -/* resonance: 0(open) to 15(most nasal) */ -static unsigned short xg_filterQ(int val) -{ - return (val - 64) * xg_sense[FX_RESONANCE] / 64; -} - -/* attack: */ -static unsigned short xg_attack(int val) -{ - return -(val - 64) * xg_sense[FX_ATTACK] / 64; -} - -/* release: */ -static unsigned short xg_release(int val) -{ - return -(val - 64) * xg_sense[FX_RELEASE] / 64; -} - -static ConvTable xg_effects[] = -{ - {71, AWE_FX_CUTOFF, xg_cutoff}, - {74, AWE_FX_FILTERQ, xg_filterQ}, - {72, AWE_FX_ENV2_RELEASE, xg_release}, - {73, AWE_FX_ENV2_ATTACK, xg_attack}, -}; - -static int num_xg_effects = numberof(xg_effects); - -static int xg_control_change(MidiStatus *st, int cmd, int val) -{ - return add_converted_effect(xg_effects, num_xg_effects, st, cmd, val); -} - -#endif /* CONFIG_AWE32_MIDIEMU */ - - -/*----------------------------------------------------------------*/ - - -/* - * initialization of AWE driver - */ - -static void -awe_initialize(void) -{ - DEBUG(0,printk("AWE32: initializing..\n")); - - /* initialize hardware configuration */ - awe_poke(AWE_HWCF1, 0x0059); - awe_poke(AWE_HWCF2, 0x0020); - - /* disable audio; this seems to reduce a clicking noise a bit.. */ - awe_poke(AWE_HWCF3, 0); - - /* initialize audio channels */ - awe_init_audio(); - - /* initialize DMA */ - awe_init_dma(); - - /* initialize init array */ - awe_init_array(); - - /* check DRAM memory size */ - awe_check_dram(); - - /* initialize the FM section of the AWE32 */ - awe_init_fm(); - - /* set up voice envelopes */ - awe_tweak(); - - /* enable audio */ - awe_poke(AWE_HWCF3, 0x0004); - - /* set default values */ - awe_init_ctrl_parms(TRUE); - - /* set equalizer */ - awe_update_equalizer(); - - /* set reverb & chorus modes */ - awe_update_reverb_mode(); - awe_update_chorus_mode(); -} - - -/* - * Core Device Management Functions - */ - -/* store values to i/o port array */ -static void setup_ports(int port1, int port2, int port3) -{ - awe_ports[0] = port1; - if (port2 == 0) - port2 = port1 + 0x400; - awe_ports[1] = port2; - awe_ports[2] = port2 + 2; - if (port3 == 0) - port3 = port1 + 0x800; - awe_ports[3] = port3; - awe_ports[4] = port3 + 2; - - port_setuped = TRUE; -} - -/* - * port request - * 0x620-623, 0xA20-A23, 0xE20-E23 - */ - -static int -awe_request_region(void) -{ - if (! port_setuped) - return 0; - if (! request_region(awe_ports[0], 4, "sound driver (AWE32)")) - return 0; - if (! request_region(awe_ports[1], 4, "sound driver (AWE32)")) - goto err_out; - if (! request_region(awe_ports[3], 4, "sound driver (AWE32)")) - goto err_out1; - return 1; -err_out1: - release_region(awe_ports[1], 4); -err_out: - release_region(awe_ports[0], 4); - return 0; -} - -static void -awe_release_region(void) -{ - if (! port_setuped) return; - release_region(awe_ports[0], 4); - release_region(awe_ports[1], 4); - release_region(awe_ports[3], 4); -} - -static int awe_attach_device(void) -{ - if (awe_present) return 0; /* for OSS38.. called twice? */ - - /* reserve I/O ports for awedrv */ - if (! awe_request_region()) { - printk(KERN_ERR "AWE32: I/O area already used.\n"); - return 0; - } - - /* set buffers to NULL */ - sfhead = sftail = NULL; - - my_dev = sound_alloc_synthdev(); - if (my_dev == -1) { - printk(KERN_ERR "AWE32 Error: too many synthesizers\n"); - awe_release_region(); - return 0; - } - - voice_alloc = &awe_operations.alloc; - voice_alloc->max_voice = awe_max_voices; - synth_devs[my_dev] = &awe_operations; - -#ifdef CONFIG_AWE32_MIXER - attach_mixer(); -#endif -#ifdef CONFIG_AWE32_MIDIEMU - attach_midiemu(); -#endif - - /* clear all samples */ - awe_reset_samples(); - - /* initialize AWE32 hardware */ - awe_initialize(); - - sprintf(awe_info.name, "AWE32-%s (RAM%dk)", - AWEDRV_VERSION, memsize/1024); - printk(KERN_INFO "\n", memsize/1024); - - awe_present = TRUE; - - return 1; -} - -static void awe_dettach_device(void) -{ - if (awe_present) { - awe_reset_samples(); - awe_release_region(); - free_tables(); -#ifdef CONFIG_AWE32_MIXER - unload_mixer(); -#endif -#ifdef CONFIG_AWE32_MIDIEMU - unload_midiemu(); -#endif - sound_unload_synthdev(my_dev); - awe_present = FALSE; - } -} - - -/* - * Legacy device Probing - */ - -/* detect emu8000 chip on the specified address; from VV's guide */ - -static int __init -awe_detect_base(int addr) -{ - setup_ports(addr, 0, 0); - if ((awe_peek(AWE_U1) & 0x000F) != 0x000C) - return 0; - if ((awe_peek(AWE_HWCF1) & 0x007E) != 0x0058) - return 0; - if ((awe_peek(AWE_HWCF2) & 0x0003) != 0x0003) - return 0; - DEBUG(0,printk("AWE32 found at %x\n", addr)); - return 1; -} - -static int __init awe_detect_legacy_devices(void) -{ - int base; - for (base = 0x620; base <= 0x680; base += 0x20) - if (awe_detect_base(base)) { - awe_attach_device(); - return 1; - } - DEBUG(0,printk("AWE32 Legacy detection failed\n")); - return 0; -} - - -/* - * PnP device Probing - */ - -static struct pnp_device_id awe_pnp_ids[] = { - {.id = "CTL0021", .driver_data = 0}, /* AWE32 WaveTable */ - {.id = "CTL0022", .driver_data = 0}, /* AWE64 WaveTable */ - {.id = "CTL0023", .driver_data = 0}, /* AWE64 Gold WaveTable */ - { } /* terminator */ -}; - -MODULE_DEVICE_TABLE(pnp, awe_pnp_ids); - -static int awe_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) -{ - int io1, io2, io3; - - if (awe_present) { - printk(KERN_ERR "AWE32: This driver only supports one AWE32 device, skipping.\n"); - } - - if (!pnp_port_valid(dev,0) || - !pnp_port_valid(dev,1) || - !pnp_port_valid(dev,2)) { - printk(KERN_ERR "AWE32: The PnP device does not have the required resources.\n"); - return -EINVAL; - } - io1 = pnp_port_start(dev,0); - io2 = pnp_port_start(dev,1); - io3 = pnp_port_start(dev,2); - printk(KERN_INFO "AWE32: A PnP Wave Table was detected at IO's %#x,%#x,%#x.\n", - io1, io2, io3); - setup_ports(io1, io2, io3); - - awe_attach_device(); - return 0; -} - -static void awe_pnp_remove(struct pnp_dev *dev) -{ - awe_dettach_device(); -} - -static struct pnp_driver awe_pnp_driver = { - .name = "AWE32", - .id_table = awe_pnp_ids, - .probe = awe_pnp_probe, - .remove = awe_pnp_remove, -}; - -static int __init awe_detect_pnp_devices(void) -{ - int ret; - - ret = pnp_register_driver(&awe_pnp_driver); - if (ret<0) - printk(KERN_ERR "AWE32: PnP support is unavailable.\n"); - return ret; -} - - -/* - * device / lowlevel (module) interface - */ - -static int __init -awe_detect(void) -{ - printk(KERN_INFO "AWE32: Probing for WaveTable...\n"); - if (isapnp) { - if (awe_detect_pnp_devices()>=0) - return 1; - } else - printk(KERN_INFO "AWE32: Skipping PnP detection.\n"); - - if (awe_detect_legacy_devices()) - return 1; - - return 0; -} - -static int __init attach_awe(void) -{ - return awe_detect() ? 0 : -ENODEV; -} - -static void __exit unload_awe(void) -{ - pnp_unregister_driver(&awe_pnp_driver); - awe_dettach_device(); -} - - -module_init(attach_awe); -module_exit(unload_awe); - -#ifndef MODULE -static int __init setup_awe(char *str) -{ - /* io, memsize, isapnp */ - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - memsize = ints[2]; - isapnp = ints[3]; - - return 1; -} - -__setup("awe=", setup_awe); -#endif diff --git a/sound/oss/awe_wave.h b/sound/oss/awe_wave.h deleted file mode 100644 index fe584810608f..000000000000 --- a/sound/oss/awe_wave.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * sound/oss/awe_wave.h - * - * Configuration of AWE32/SB32/AWE64 wave table synth driver. - * version 0.4.4; Jan. 4, 2000 - * - * Copyright (C) 1996-1998 Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * chorus & reverb effects send for FM chip: from 0 to 0xff - * larger numbers often cause weird sounds. - */ - -#define DEF_FM_CHORUS_DEPTH 0x10 -#define DEF_FM_REVERB_DEPTH 0x10 - - -/* - * other compile conditions - */ - -/* initialize FM passthrough even without extended RAM */ -#undef AWE_ALWAYS_INIT_FM - -/* debug on */ -#define AWE_DEBUG_ON - -/* GUS compatible mode */ -#define AWE_HAS_GUS_COMPATIBILITY - -/* add MIDI emulation by wavetable */ -#define CONFIG_AWE32_MIDIEMU - -/* add mixer control of emu8000 equalizer */ -#undef CONFIG_AWE32_MIXER - -/* use new volume calculation method as default */ -#define AWE_USE_NEW_VOLUME_CALC - -/* check current volume target for searching empty voices */ -#define AWE_CHECK_VTARGET - -/* allow sample sharing */ -#define AWE_ALLOW_SAMPLE_SHARING - -/* - * AWE32 card configuration: - * uncomment the following lines *ONLY* when auto detection doesn't - * work properly on your machine. - */ - -/*#define AWE_DEFAULT_BASE_ADDR 0x620*/ /* base port address */ -/*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */ - -/* - * AWE driver version number - */ -#define AWE_MAJOR_VERSION 0 -#define AWE_MINOR_VERSION 4 -#define AWE_TINY_VERSION 4 -#define AWE_VERSION_NUMBER ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION) -#define AWEDRV_VERSION "0.4.4" diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c deleted file mode 100644 index ea51aafaf401..000000000000 --- a/sound/oss/cmpci.c +++ /dev/null @@ -1,3381 +0,0 @@ -/* - * cmpci.c -- C-Media PCI audio driver. - * - * Copyright (C) 1999 C-media support (support@cmedia.com.tw) - * - * Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * For update, visit: - * http://www.cmedia.com.tw - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Special thanks to David C. Niemi, Jan Pfeifer - * - * - * Module command line parameters: - * none so far - * - * - * Supported devices: - * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible - * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible - * /dev/midi simple MIDI UART interface, no ioctl - * - * The card has both an FM and a Wavetable synth, but I have to figure - * out first how to drive them... - * - * Revision history - * 06.05.98 0.1 Initial release - * 10.05.98 0.2 Fixed many bugs, esp. ADC rate calculation - * First stab at a simple midi interface (no bells&whistles) - * 13.05.98 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of - * set_dac_rate in the FMODE_WRITE case in cm_open - * Fix hwptr out of bounds (now mpg123 works) - * 14.05.98 0.4 Don't allow excessive interrupt rates - * 08.06.98 0.5 First release using Alan Cox' soundcore instead of miscdevice - * 03.08.98 0.6 Do not include modversions.h - * Now mixer behaviour can basically be selected between - * "OSS documented" and "OSS actual" behaviour - * 31.08.98 0.7 Fix realplayer problems - dac.count issues - * 10.12.98 0.8 Fix drain_dac trying to wait on not yet initialized DMA - * 16.12.98 0.9 Fix a few f_file & FMODE_ bugs - * 06.01.99 0.10 remove the silly SA_INTERRUPT flag. - * hopefully killed the egcs section type conflict - * 12.03.99 0.11 cinfo.blocks should be reset after GETxPTR ioctl. - * reported by Johan Maes - * 22.03.99 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK - * read/write cannot be executed - * 18.08.99 1.5 Only deallocate DMA buffer when unloading. - * 02.09.99 1.6 Enable SPDIF LOOP - * Change the mixer read back - * 21.09.99 2.33 Use RCS version as driver version. - * Add support for modem, S/PDIF loop and 4 channels. - * (8738 only) - * Fix bug cause x11amp cannot play. - * - * Fixes: - * Arnaldo Carvalho de Melo - * 18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it - * was calling prog_dmabuf with s->lock held, call missing - * unlock_kernel in cm_midi_release - * 08/10/2001 - use set_current_state in some more places - * - * Carlos Eduardo Gorges - * Fri May 25 2001 - * - SMP support ( spin[un]lock* revision ) - * - speaker mixer support - * Mon Aug 13 2001 - * - optimizations and cleanups - * - * 03/01/2003 - open_mode fixes from Georg Acher - * Simon Braunschmidt - * Sat Jan 31 2004 - * - provide support for opl3 FM by releasing IO range after initialization - * - * ChenLi Tien - * Mar 9 2004 - * - Fix S/PDIF out if spdif_loop enabled - * - Load opl3 driver if enabled (fmio in proper range) - * - Load mpu401 if enabled (mpuio in proper range) - * Apr 5 2004 - * - Fix DUAL_DAC dma synchronization bug - * - Check exist FM/MPU401 I/O before activate. - * - Add AFTM_S16_BE format support, so MPlayer/Xine can play AC3/mutlichannel - * on Mac - * - Change to support kernel 2.6 so only small patch needed - * - All parameters default to 0 - * - Add spdif_out to send PCM through S/PDIF out jack - * - Add hw_copy to get 4-spaker output for general PCM/analog output - * - * Stefan Thater - * Apr 5 2004 - * - Fix mute single channel for CD/Line-in/AUX-in - */ -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef CONFIG_SOUND_CMPCI_MIDI -#include "sound_config.h" -#include "mpu401.h" -#endif -#ifdef CONFIG_SOUND_CMPCI_FM -#include "opl3.h" -#endif -#ifdef CONFIG_SOUND_CMPCI_JOYSTICK -#include -#include - -#endif - -/* --------------------------------------------------------------------- */ -#undef OSS_DOCUMENTED_MIXER_SEMANTICS -#undef DMABYTEIO -#define DBG(x) {} -/* --------------------------------------------------------------------- */ - -#define CM_MAGIC ((PCI_VENDOR_ID_CMEDIA<<16)|PCI_DEVICE_ID_CMEDIA_CM8338A) - -/* CM8338 registers definition ****************/ - -#define CODEC_CMI_FUNCTRL0 (0x00) -#define CODEC_CMI_FUNCTRL1 (0x04) -#define CODEC_CMI_CHFORMAT (0x08) -#define CODEC_CMI_INT_HLDCLR (0x0C) -#define CODEC_CMI_INT_STATUS (0x10) -#define CODEC_CMI_LEGACY_CTRL (0x14) -#define CODEC_CMI_MISC_CTRL (0x18) -#define CODEC_CMI_TDMA_POS (0x1C) -#define CODEC_CMI_MIXER (0x20) -#define CODEC_SB16_DATA (0x22) -#define CODEC_SB16_ADDR (0x23) -#define CODEC_CMI_MIXER1 (0x24) -#define CODEC_CMI_MIXER2 (0x25) -#define CODEC_CMI_AUX_VOL (0x26) -#define CODEC_CMI_MISC (0x27) -#define CODEC_CMI_AC97 (0x28) - -#define CODEC_CMI_CH0_FRAME1 (0x80) -#define CODEC_CMI_CH0_FRAME2 (0x84) -#define CODEC_CMI_CH1_FRAME1 (0x88) -#define CODEC_CMI_CH1_FRAME2 (0x8C) - -#define CODEC_CMI_SPDIF_CTRL (0x90) -#define CODEC_CMI_MISC_CTRL2 (0x92) - -#define CODEC_CMI_EXT_REG (0xF0) - -/* Mixer registers for SB16 ******************/ - -#define DSP_MIX_DATARESETIDX ((unsigned char)(0x00)) - -#define DSP_MIX_MASTERVOLIDX_L ((unsigned char)(0x30)) -#define DSP_MIX_MASTERVOLIDX_R ((unsigned char)(0x31)) -#define DSP_MIX_VOICEVOLIDX_L ((unsigned char)(0x32)) -#define DSP_MIX_VOICEVOLIDX_R ((unsigned char)(0x33)) -#define DSP_MIX_FMVOLIDX_L ((unsigned char)(0x34)) -#define DSP_MIX_FMVOLIDX_R ((unsigned char)(0x35)) -#define DSP_MIX_CDVOLIDX_L ((unsigned char)(0x36)) -#define DSP_MIX_CDVOLIDX_R ((unsigned char)(0x37)) -#define DSP_MIX_LINEVOLIDX_L ((unsigned char)(0x38)) -#define DSP_MIX_LINEVOLIDX_R ((unsigned char)(0x39)) - -#define DSP_MIX_MICVOLIDX ((unsigned char)(0x3A)) -#define DSP_MIX_SPKRVOLIDX ((unsigned char)(0x3B)) - -#define DSP_MIX_OUTMIXIDX ((unsigned char)(0x3C)) - -#define DSP_MIX_ADCMIXIDX_L ((unsigned char)(0x3D)) -#define DSP_MIX_ADCMIXIDX_R ((unsigned char)(0x3E)) - -#define DSP_MIX_INGAINIDX_L ((unsigned char)(0x3F)) -#define DSP_MIX_INGAINIDX_R ((unsigned char)(0x40)) -#define DSP_MIX_OUTGAINIDX_L ((unsigned char)(0x41)) -#define DSP_MIX_OUTGAINIDX_R ((unsigned char)(0x42)) - -#define DSP_MIX_AGCIDX ((unsigned char)(0x43)) - -#define DSP_MIX_TREBLEIDX_L ((unsigned char)(0x44)) -#define DSP_MIX_TREBLEIDX_R ((unsigned char)(0x45)) -#define DSP_MIX_BASSIDX_L ((unsigned char)(0x46)) -#define DSP_MIX_BASSIDX_R ((unsigned char)(0x47)) -#define DSP_MIX_EXTENSION ((unsigned char)(0xf0)) -// pseudo register for AUX -#define DSP_MIX_AUXVOL_L ((unsigned char)(0x50)) -#define DSP_MIX_AUXVOL_R ((unsigned char)(0x51)) - -// I/O length -#define CM_EXTENT_CODEC 0x100 -#define CM_EXTENT_MIDI 0x2 -#define CM_EXTENT_SYNTH 0x4 -#define CM_EXTENT_GAME 0x8 - -// Function Control Register 0 (00h) -#define CHADC0 0x01 -#define CHADC1 0x02 -#define PAUSE0 0x04 -#define PAUSE1 0x08 - -// Function Control Register 0+2 (02h) -#define CHEN0 0x01 -#define CHEN1 0x02 -#define RST_CH0 0x04 -#define RST_CH1 0x08 - -// Function Control Register 1 (04h) -#define JYSTK_EN 0x02 -#define UART_EN 0x04 -#define SPDO2DAC 0x40 -#define SPDFLOOP 0x80 - -// Function Control Register 1+1 (05h) -#define SPDF_0 0x01 -#define SPDF_1 0x02 -#define ASFC 0x1c -#define DSFC 0xe0 -#define SPDIF2DAC (SPDF_1 << 8 | SPDO2DAC) - -// Channel Format Register (08h) -#define CM_CFMT_STEREO 0x01 -#define CM_CFMT_16BIT 0x02 -#define CM_CFMT_MASK 0x03 -#define POLVALID 0x20 -#define INVSPDIFI 0x80 - -// Channel Format Register+2 (0ah) -#define SPD24SEL 0x20 - -// Channel Format Register+3 (0bh) -#define CHB3D 0x20 -#define CHB3D5C 0x80 - -// Interrupt Hold/Clear Register+2 (0eh) -#define CH0_INT_EN 0x01 -#define CH1_INT_EN 0x02 - -// Interrupt Register (10h) -#define CHINT0 0x01 -#define CHINT1 0x02 -#define CH0BUSY 0x04 -#define CH1BUSY 0x08 - -// Legacy Control/Status Register+1 (15h) -#define EXBASEN 0x10 -#define BASE2LIN 0x20 -#define CENTR2LIN 0x40 -#define CB2LIN (BASE2LIN | CENTR2LIN) -#define CHB3D6C 0x80 - -// Legacy Control/Status Register+2 (16h) -#define DAC2SPDO 0x20 -#define SPDCOPYRHT 0x40 -#define ENSPDOUT 0x80 - -// Legacy Control/Status Register+3 (17h) -#define FMSEL 0x03 -#define VSBSEL 0x0c -#define VMPU 0x60 -#define NXCHG 0x80 - -// Miscellaneous Control Register (18h) -#define REAR2LIN 0x20 -#define MUTECH1 0x40 -#define ENCENTER 0x80 - -// Miscellaneous Control Register+1 (19h) -#define SELSPDIFI2 0x01 -#define SPDF_AC97 0x80 - -// Miscellaneous Control Register+2 (1ah) -#define AC3_EN 0x04 -#define FM_EN 0x08 -#define SPD32SEL 0x20 -#define XCHGDAC 0x40 -#define ENDBDAC 0x80 - -// Miscellaneous Control Register+3 (1bh) -#define SPDIFI48K 0x01 -#define SPDO5V 0x02 -#define N4SPK3D 0x04 -#define RESET 0x40 -#define PWD 0x80 -#define SPDIF48K (SPDIFI48K << 24 | SPDF_AC97 << 8) - -// Mixer1 (24h) -#define CDPLAY 0x01 -#define X3DEN 0x02 -#define REAR2FRONT 0x10 -#define SPK4 0x20 -#define WSMUTE 0x40 -#define FMMUTE 0x80 - -// Miscellaneous Register (27h) -#define SPDVALID 0x02 -#define CENTR2MIC 0x04 - -// Miscellaneous Register2 (92h) -#define SPD32KFMT 0x10 - -#define CM_CFMT_DACSHIFT 2 -#define CM_CFMT_ADCSHIFT 0 -#define CM_FREQ_DACSHIFT 5 -#define CM_FREQ_ADCSHIFT 2 -#define RSTDAC RST_CH1 -#define RSTADC RST_CH0 -#define ENDAC CHEN1 -#define ENADC CHEN0 -#define PAUSEDAC PAUSE1 -#define PAUSEADC PAUSE0 -#define CODEC_CMI_ADC_FRAME1 CODEC_CMI_CH0_FRAME1 -#define CODEC_CMI_ADC_FRAME2 CODEC_CMI_CH0_FRAME2 -#define CODEC_CMI_DAC_FRAME1 CODEC_CMI_CH1_FRAME1 -#define CODEC_CMI_DAC_FRAME2 CODEC_CMI_CH1_FRAME2 -#define DACINT CHINT1 -#define ADCINT CHINT0 -#define DACBUSY CH1BUSY -#define ADCBUSY CH0BUSY -#define ENDACINT CH1_INT_EN -#define ENADCINT CH0_INT_EN - -static const unsigned sample_size[] = { 1, 2, 2, 4 }; -static const unsigned sample_shift[] = { 0, 1, 1, 2 }; - -#define SND_DEV_DSP16 5 - -#define NR_DEVICE 3 /* maximum number of devices */ - -#define set_dac1_rate set_adc_rate -#define set_dac1_rate_unlocked set_adc_rate_unlocked -#define stop_dac1 stop_adc -#define stop_dac1_unlocked stop_adc_unlocked -#define get_dmadac1 get_dmaadc - -static unsigned int devindex = 0; - -//*********************************************/ - -struct cm_state { - /* magic */ - unsigned int magic; - - /* list of cmedia devices */ - struct list_head devs; - - /* the corresponding pci_dev structure */ - struct pci_dev *dev; - - int dev_audio; /* soundcore stuff */ - int dev_mixer; - - unsigned int iosb, iobase, iosynth, - iomidi, iogame, irq; /* hardware resources */ - unsigned short deviceid; /* pci_id */ - - struct { /* mixer stuff */ - unsigned int modcnt; - unsigned short vol[13]; - } mix; - - unsigned int rateadc, ratedac; /* wave stuff */ - unsigned char fmt, enable; - - spinlock_t lock; - struct mutex open_mutex; - mode_t open_mode; - wait_queue_head_t open_wait; - - struct dmabuf { - void *rawbuf; - dma_addr_t dmaaddr; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - unsigned hwptr, swptr; - unsigned total_bytes; - int count; - unsigned error; /* over/underrun */ - wait_queue_head_t wait; - - unsigned fragsize; /* redundant, but makes calculations easier */ - unsigned dmasize; - unsigned fragsamples; - unsigned dmasamples; - - unsigned mapped:1; /* OSS stuff */ - unsigned ready:1; - unsigned endcleared:1; - unsigned enabled:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac, dma_adc; - -#ifdef CONFIG_SOUND_CMPCI_MIDI - int midi_devc; - struct address_info mpu_data; -#endif -#ifdef CONFIG_SOUND_CMPCI_JOYSTICK - struct gameport *gameport; -#endif - - int chip_version; - int max_channels; - int curr_channels; - int capability; /* HW capability, various for chip versions */ - - int status; /* HW or SW state */ - - int spdif_counter; /* spdif frame counter */ -}; - -/* flags used for capability */ -#define CAN_AC3_HW 0x00000001 /* 037 or later */ -#define CAN_AC3_SW 0x00000002 /* 033 or later */ -#define CAN_AC3 (CAN_AC3_HW | CAN_AC3_SW) -#define CAN_DUAL_DAC 0x00000004 /* 033 or later */ -#define CAN_MULTI_CH_HW 0x00000008 /* 039 or later */ -#define CAN_MULTI_CH (CAN_MULTI_CH_HW | CAN_DUAL_DAC) -#define CAN_LINE_AS_REAR 0x00000010 /* 033 or later */ -#define CAN_LINE_AS_BASS 0x00000020 /* 039 or later */ -#define CAN_MIC_AS_BASS 0x00000040 /* 039 or later */ - -/* flags used for status */ -#define DO_AC3_HW 0x00000001 -#define DO_AC3_SW 0x00000002 -#define DO_AC3 (DO_AC3_HW | DO_AC3_SW) -#define DO_DUAL_DAC 0x00000004 -#define DO_MULTI_CH_HW 0x00000008 -#define DO_MULTI_CH (DO_MULTI_CH_HW | DO_DUAL_DAC) -#define DO_LINE_AS_REAR 0x00000010 /* 033 or later */ -#define DO_LINE_AS_BASS 0x00000020 /* 039 or later */ -#define DO_MIC_AS_BASS 0x00000040 /* 039 or later */ -#define DO_SPDIF_OUT 0x00000100 -#define DO_SPDIF_IN 0x00000200 -#define DO_SPDIF_LOOP 0x00000400 -#define DO_BIGENDIAN_W 0x00001000 /* used in PowerPC */ -#define DO_BIGENDIAN_R 0x00002000 /* used in PowerPC */ - -static LIST_HEAD(devs); - -static int mpuio; -static int fmio; -static int joystick; -static int spdif_inverse; -static int spdif_loop; -static int spdif_out; -static int use_line_as_rear; -static int use_line_as_bass; -static int use_mic_as_bass; -static int mic_boost; -static int hw_copy; -module_param(mpuio, int, 0); -module_param(fmio, int, 0); -module_param(joystick, bool, 0); -module_param(spdif_inverse, bool, 0); -module_param(spdif_loop, bool, 0); -module_param(spdif_out, bool, 0); -module_param(use_line_as_rear, bool, 0); -module_param(use_line_as_bass, bool, 0); -module_param(use_mic_as_bass, bool, 0); -module_param(mic_boost, bool, 0); -module_param(hw_copy, bool, 0); -MODULE_PARM_DESC(mpuio, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable"); -MODULE_PARM_DESC(fmio, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable"); -MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver"); -MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal"); -MODULE_PARM_DESC(spdif_loop, "(1/0) Route S/PDIF-in to S/PDIF-out directly"); -MODULE_PARM_DESC(spdif_out, "(1/0) Send PCM to S/PDIF-out (PCM volume will not function)"); -MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out"); -MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center"); -MODULE_PARM_DESC(use_mic_as_bass, "(1/0) Use mic-in jack as bass/center"); -MODULE_PARM_DESC(mic_boost, "(1/0) Enable microphone boost"); -MODULE_PARM_DESC(hw_copy, "Copy front channel to surround channel"); - -/* --------------------------------------------------------------------- */ - -static inline unsigned ld2(unsigned int x) -{ - unsigned exp=16,l=5,r=0; - static const unsigned num[]={0x2,0x4,0x10,0x100,0x10000}; - - /* num: 2, 4, 16, 256, 65536 */ - /* exp: 1, 2, 4, 8, 16 */ - - while(l--) { - if( x >= num[l] ) { - if(num[l]>2) x >>= exp; - r+=exp; - } - exp>>=1; - } - - return r; -} - -/* --------------------------------------------------------------------- */ - -static void maskb(unsigned int addr, unsigned int mask, unsigned int value) -{ - outb((inb(addr) & mask) | value, addr); -} - -static void maskw(unsigned int addr, unsigned int mask, unsigned int value) -{ - outw((inw(addr) & mask) | value, addr); -} - -static void maskl(unsigned int addr, unsigned int mask, unsigned int value) -{ - outl((inl(addr) & mask) | value, addr); -} - -static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count) -{ - if (addr) - outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1); - outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2); - maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC0, 0); -} - -static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count) -{ - outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1); - outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2); - maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, CHADC0); -} - -static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count) -{ - outl(addr, s->iobase + CODEC_CMI_DAC_FRAME1); - outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2); - maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, 0); - if (s->status & DO_DUAL_DAC) - set_dmadac1(s, 0, count); -} - -static void set_countadc(struct cm_state *s, unsigned count) -{ - outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2 + 2); -} - -static void set_countdac(struct cm_state *s, unsigned count) -{ - outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2 + 2); - if (s->status & DO_DUAL_DAC) - set_countadc(s, count); -} - -static unsigned get_dmadac(struct cm_state *s) -{ - unsigned int curr_addr; - - curr_addr = inw(s->iobase + CODEC_CMI_DAC_FRAME2) + 1; - curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]; - curr_addr = s->dma_dac.dmasize - curr_addr; - - return curr_addr; -} - -static unsigned get_dmaadc(struct cm_state *s) -{ - unsigned int curr_addr; - - curr_addr = inw(s->iobase + CODEC_CMI_ADC_FRAME2) + 1; - curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK]; - curr_addr = s->dma_adc.dmasize - curr_addr; - - return curr_addr; -} - -static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data) -{ - unsigned char regval, pseudo; - - // pseudo register - if (idx == DSP_MIX_AUXVOL_L) { - data >>= 4; - data &= 0x0f; - regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0x0f; - outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL); - return; - } - if (idx == DSP_MIX_AUXVOL_R) { - data &= 0xf0; - regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0xf0; - outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL); - return; - } - outb(idx, s->iobase + CODEC_SB16_ADDR); - udelay(10); - // pseudo bits - if (idx == DSP_MIX_OUTMIXIDX) { - pseudo = data & ~0x1f; - pseudo >>= 1; - regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x30; - outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2); - } - if (idx == DSP_MIX_ADCMIXIDX_L) { - pseudo = data & 0x80; - pseudo >>= 1; - regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x40; - outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2); - } - if (idx == DSP_MIX_ADCMIXIDX_R) { - pseudo = data & 0x80; - regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x80; - outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2); - } - outb(data, s->iobase + CODEC_SB16_DATA); - udelay(10); -} - -static unsigned char rdmixer(struct cm_state *s, unsigned char idx) -{ - unsigned char v, pseudo; - - // pseudo register - if (idx == DSP_MIX_AUXVOL_L) { - v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0x0f; - v <<= 4; - return v; - } - if (idx == DSP_MIX_AUXVOL_L) { - v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0xf0; - return v; - } - outb(idx, s->iobase + CODEC_SB16_ADDR); - udelay(10); - v = inb(s->iobase + CODEC_SB16_DATA); - udelay(10); - // pseudo bits - if (idx == DSP_MIX_OUTMIXIDX) { - pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x30; - pseudo <<= 1; - v |= pseudo; - } - if (idx == DSP_MIX_ADCMIXIDX_L) { - pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x40; - pseudo <<= 1; - v |= pseudo; - } - if (idx == DSP_MIX_ADCMIXIDX_R) { - pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x80; - v |= pseudo; - } - return v; -} - -static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data) -{ - if (mask && s->chip_version > 0) { /* 8338 cannot keep this */ - s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT); - udelay(10); - } - s->fmt = (s->fmt & mask) | data; - outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT); - udelay(10); -} - -static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - set_fmt_unlocked(s,mask,data); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data) -{ - outb(idx, s->iobase + CODEC_SB16_ADDR); - udelay(10); - outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA); - udelay(10); -} - -static struct { - unsigned rate; - unsigned lower; - unsigned upper; - unsigned char freq; -} rate_lookup[] = -{ - { 5512, (0 + 5512) / 2, (5512 + 8000) / 2, 0 }, - { 8000, (5512 + 8000) / 2, (8000 + 11025) / 2, 4 }, - { 11025, (8000 + 11025) / 2, (11025 + 16000) / 2, 1 }, - { 16000, (11025 + 16000) / 2, (16000 + 22050) / 2, 5 }, - { 22050, (16000 + 22050) / 2, (22050 + 32000) / 2, 2 }, - { 32000, (22050 + 32000) / 2, (32000 + 44100) / 2, 6 }, - { 44100, (32000 + 44100) / 2, (44100 + 48000) / 2, 3 }, - { 48000, (44100 + 48000) / 2, 48000, 7 } -}; - -static void set_spdif_copyright(struct cm_state *s, int spdif_copyright) -{ - /* enable SPDIF-in Copyright */ - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~SPDCOPYRHT, spdif_copyright ? SPDCOPYRHT : 0); -} - -static void set_spdif_loop(struct cm_state *s, int spdif_loop) -{ - /* enable SPDIF loop */ - if (spdif_loop) { - s->status |= DO_SPDIF_LOOP; - /* turn on spdif-in to spdif-out */ - maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, SPDFLOOP); - } else { - s->status &= ~DO_SPDIF_LOOP; - /* turn off spdif-in to spdif-out */ - maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDFLOOP, 0); - } -} - -static void set_spdif_monitor(struct cm_state *s, int channel) -{ - // SPDO2DAC - maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDO2DAC, channel == 2 ? SPDO2DAC : 0); - // CDPLAY - if (s->chip_version >= 39) - maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, channel ? CDPLAY : 0); -} - -static void set_spdifout_level(struct cm_state *s, int level5v) -{ - /* SPDO5V */ - if (s->chip_version > 0) - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~SPDO5V, level5v ? SPDO5V : 0); -} - -static void set_spdifin_inverse(struct cm_state *s, int spdif_inverse) -{ - if (s->chip_version == 0) /* 8338 has not this feature */ - return; - if (spdif_inverse) { - /* turn on spdif-in inverse */ - if (s->chip_version >= 39) - maskb(s->iobase + CODEC_CMI_CHFORMAT, ~0, INVSPDIFI); - else - maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1); - } else { - /* turn off spdif-ininverse */ - if (s->chip_version >= 39) - maskb(s->iobase + CODEC_CMI_CHFORMAT, ~INVSPDIFI, 0); - else - maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0); - } -} - -static void set_spdifin_channel2(struct cm_state *s, int channel2) -{ - /* SELSPDIFI2 */ - if (s->chip_version >= 39) - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 1, ~SELSPDIFI2, channel2 ? SELSPDIFI2 : 0); -} - -static void set_spdifin_valid(struct cm_state *s, int valid) -{ - /* SPDVALID */ - maskb(s->iobase + CODEC_CMI_MISC, ~SPDVALID, valid ? SPDVALID : 0); -} - -static void set_spdifout_unlocked(struct cm_state *s, unsigned rate) -{ - if (rate != 48000 && rate != 44100) - rate = 0; - if (rate == 48000 || rate == 44100) { - set_spdif_loop(s, 0); - // SPDF_1 - maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1); - // SPDIFI48K SPDF_AC97 - maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0); - if (s->chip_version >= 55) - // SPD32KFMT - maskb(s->iobase + CODEC_CMI_MISC_CTRL2, ~SPD32KFMT, rate == 48000 ? SPD32KFMT : 0); - if (s->chip_version > 0) - // ENSPDOUT - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, ENSPDOUT); - // monitor SPDIF out - set_spdif_monitor(s, 2); - s->status |= DO_SPDIF_OUT; - } else { - maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0); - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~ENSPDOUT, 0); - // monitor none - set_spdif_monitor(s, 0); - s->status &= ~DO_SPDIF_OUT; - } -} - -static void set_spdifout(struct cm_state *s, unsigned rate) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - set_spdifout_unlocked(s,rate); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void set_spdifin_unlocked(struct cm_state *s, unsigned rate) -{ - if (rate == 48000 || rate == 44100) { - // SPDF_1 - maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1); - // SPDIFI48K SPDF_AC97 - maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0); - s->status |= DO_SPDIF_IN; - } else { - maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0); - s->status &= ~DO_SPDIF_IN; - } -} - -static void set_spdifin(struct cm_state *s, unsigned rate) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - set_spdifin_unlocked(s,rate); - spin_unlock_irqrestore(&s->lock, flags); -} - -/* find parity for bit 4~30 */ -static unsigned parity(unsigned data) -{ - unsigned parity = 0; - int counter = 4; - - data >>= 4; // start from bit 4 - while (counter <= 30) { - if (data & 1) - parity++; - data >>= 1; - counter++; - } - return parity & 1; -} - -static void set_ac3_unlocked(struct cm_state *s, unsigned rate) -{ - if (!(s->capability & CAN_AC3)) - return; - /* enable AC3 */ - if (rate && rate != 44100) - rate = 48000; - if (rate == 48000 || rate == 44100) { - // mute DAC - maskb(s->iobase + CODEC_CMI_MIXER1, ~0, WSMUTE); - if (s->chip_version >= 39) - maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0, MUTECH1); - // AC3EN for 039, 0x04 - if (s->chip_version >= 39) { - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, AC3_EN); - if (s->chip_version == 55) - maskb(s->iobase + CODEC_CMI_SPDIF_CTRL, ~2, 0); - // AC3EN for 037, 0x10 - } else if (s->chip_version == 37) - maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10); - if (s->capability & CAN_AC3_HW) { - // SPD24SEL for 039, 0x20, but cannot be set - if (s->chip_version == 39) - maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, SPD24SEL); - // SPD24SEL for 037, 0x02 - else if (s->chip_version == 37) - maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02); - if (s->chip_version >= 39) - maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, 0); - - s->status |= DO_AC3_HW; - } else { - // SPD32SEL for 037 & 039 - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, SPD32SEL); - // set 176K sample rate to fix 033 HW bug - if (s->chip_version == 33) { - if (rate == 48000) - maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0, 0x08); - else - maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0); - } - s->status |= DO_AC3_SW; - } - } else { - maskb(s->iobase + CODEC_CMI_MIXER1, ~WSMUTE, 0); - if (s->chip_version >= 39) - maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~MUTECH1, 0); - maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~(SPD24SEL|0x12), 0); - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~(SPD32SEL|AC3_EN), 0); - if (s->chip_version == 33) - maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0); - if (s->chip_version >= 39) - maskb(s->iobase + CODEC_CMI_MIXER1, ~0, CDPLAY); - s->status &= ~DO_AC3; - } - s->spdif_counter = 0; -} - -static void set_line_as_rear(struct cm_state *s, int use_line_as_rear) -{ - if (!(s->capability & CAN_LINE_AS_REAR)) - return; - if (use_line_as_rear) { - maskb(s->iobase + CODEC_CMI_MIXER1, ~0, SPK4); - s->status |= DO_LINE_AS_REAR; - } else { - maskb(s->iobase + CODEC_CMI_MIXER1, ~SPK4, 0); - s->status &= ~DO_LINE_AS_REAR; - } -} - -static void set_line_as_bass(struct cm_state *s, int use_line_as_bass) -{ - if (!(s->capability & CAN_LINE_AS_BASS)) - return; - if (use_line_as_bass) { - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, CB2LIN); - s->status |= DO_LINE_AS_BASS; - } else { - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CB2LIN, 0); - s->status &= ~DO_LINE_AS_BASS; - } -} - -static void set_mic_as_bass(struct cm_state *s, int use_mic_as_bass) -{ - if (!(s->capability & CAN_MIC_AS_BASS)) - return; - if (use_mic_as_bass) { - maskb(s->iobase + CODEC_CMI_MISC, ~0, 0x04); - s->status |= DO_MIC_AS_BASS; - } else { - maskb(s->iobase + CODEC_CMI_MISC, ~0x04, 0); - s->status &= ~DO_MIC_AS_BASS; - } -} - -static void set_hw_copy(struct cm_state *s, int hw_copy) -{ - if (s->max_channels > 2 && hw_copy) - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, N4SPK3D); - else - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~N4SPK3D, 0); -} - -static void set_ac3(struct cm_state *s, unsigned rate) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - set_spdifout_unlocked(s, rate); - set_ac3_unlocked(s, rate); - spin_unlock_irqrestore(&s->lock, flags); -} - -static int trans_ac3(struct cm_state *s, void *dest, const char __user *source, int size) -{ - int i = size / 2; - unsigned long data; - unsigned short data16; - unsigned long *dst = (unsigned long *) dest; - unsigned short __user *src = (unsigned short __user *)source; - int err; - - do { - if ((err = __get_user(data16, src++))) - return err; - data = (unsigned long)le16_to_cpu(data16); - data <<= 12; // ok for 16-bit data - if (s->spdif_counter == 2 || s->spdif_counter == 3) - data |= 0x40000000; // indicate AC-3 raw data - if (parity(data)) - data |= 0x80000000; // parity - if (s->spdif_counter == 0) - data |= 3; // preamble 'M' - else if (s->spdif_counter & 1) - data |= 5; // odd, 'W' - else - data |= 9; // even, 'M' - *dst++ = cpu_to_le32(data); - s->spdif_counter++; - if (s->spdif_counter == 384) - s->spdif_counter = 0; - } while (--i); - - return 0; -} - -static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate) -{ - unsigned char freq = 4; - int i; - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) { - if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) { - rate = rate_lookup[i].rate; - freq = rate_lookup[i].freq; - break; - } - } - s->rateadc = rate; - freq <<= CM_FREQ_ADCSHIFT; - - maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq); -} - -static void set_adc_rate(struct cm_state *s, unsigned rate) -{ - unsigned long flags; - unsigned char freq = 4; - int i; - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) { - if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) { - rate = rate_lookup[i].rate; - freq = rate_lookup[i].freq; - break; - } - } - s->rateadc = rate; - freq <<= CM_FREQ_ADCSHIFT; - - spin_lock_irqsave(&s->lock, flags); - maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void set_dac_rate(struct cm_state *s, unsigned rate) -{ - unsigned long flags; - unsigned char freq = 4; - int i; - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) { - if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) { - rate = rate_lookup[i].rate; - freq = rate_lookup[i].freq; - break; - } - } - s->ratedac = rate; - freq <<= CM_FREQ_DACSHIFT; - - spin_lock_irqsave(&s->lock, flags); - maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~DSFC, freq); - spin_unlock_irqrestore(&s->lock, flags); - - if (s->curr_channels <= 2 && spdif_out) - set_spdifout(s, rate); - if (s->status & DO_DUAL_DAC) - set_dac1_rate(s, rate); -} - -/* --------------------------------------------------------------------- */ -static inline void reset_adc(struct cm_state *s) -{ - /* reset bus master */ - outb(s->enable | RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2); - udelay(10); - outb(s->enable & ~RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2); -} - -static inline void reset_dac(struct cm_state *s) -{ - /* reset bus master */ - outb(s->enable | RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2); - udelay(10); - outb(s->enable & ~RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2); - if (s->status & DO_DUAL_DAC) - reset_adc(s); -} - -static inline void pause_adc(struct cm_state *s) -{ - maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEADC); -} - -static inline void pause_dac(struct cm_state *s) -{ - maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEDAC); - if (s->status & DO_DUAL_DAC) - pause_adc(s); -} - -static inline void disable_adc(struct cm_state *s) -{ - /* disable channel */ - s->enable &= ~ENADC; - outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2); - reset_adc(s); -} - -static inline void disable_dac(struct cm_state *s) -{ - /* disable channel */ - s->enable &= ~ENDAC; - outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2); - reset_dac(s); - if (s->status & DO_DUAL_DAC) - disable_adc(s); -} - -static inline void enable_adc(struct cm_state *s) -{ - if (!(s->enable & ENADC)) { - /* enable channel */ - s->enable |= ENADC; - outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2); - } - maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEADC, 0); -} - -static inline void enable_dac_unlocked(struct cm_state *s) -{ - if (!(s->enable & ENDAC)) { - /* enable channel */ - s->enable |= ENDAC; - outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2); - } - maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEDAC, 0); - - if (s->status & DO_DUAL_DAC) - enable_adc(s); -} - -static inline void stop_adc_unlocked(struct cm_state *s) -{ - if (s->enable & ENADC) { - /* disable interrupt */ - maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENADCINT, 0); - disable_adc(s); - } -} - -static inline void stop_adc(struct cm_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - stop_adc_unlocked(s); - spin_unlock_irqrestore(&s->lock, flags); - -} - -static inline void stop_dac_unlocked(struct cm_state *s) -{ - if (s->enable & ENDAC) { - /* disable interrupt */ - maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENDACINT, 0); - disable_dac(s); - } - if (s->status & DO_DUAL_DAC) - stop_dac1_unlocked(s); -} - -static inline void stop_dac(struct cm_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - stop_dac_unlocked(s); - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void start_adc_unlocked(struct cm_state *s) -{ - if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) - && s->dma_adc.ready) { - /* enable interrupt */ - maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT); - enable_adc(s); - } -} - -static void start_adc(struct cm_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - start_adc_unlocked(s); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac1_unlocked(struct cm_state *s) -{ - if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) { - /* enable interrupt */ - maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT); - enable_dac_unlocked(s); - } -} - -static void start_dac_unlocked(struct cm_state *s) -{ - if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { - /* enable interrupt */ - maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENDACINT); - enable_dac_unlocked(s); - } - if (s->status & DO_DUAL_DAC) - start_dac1_unlocked(s); -} - -static void start_dac(struct cm_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - start_dac_unlocked(s); - spin_unlock_irqrestore(&s->lock, flags); -} - -static int prog_dmabuf(struct cm_state *s, unsigned rec); - -static int set_dac_channels(struct cm_state *s, int channels) -{ - unsigned long flags; - static unsigned int fmmute = 0; - - spin_lock_irqsave(&s->lock, flags); - - if ((channels > 2) && (channels <= s->max_channels) - && (((s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK) == (CM_CFMT_STEREO | CM_CFMT_16BIT))) { - set_spdifout_unlocked(s, 0); - if (s->capability & CAN_MULTI_CH_HW) { - // NXCHG - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, NXCHG); - // CHB3D or CHB3D5C - maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), channels > 4 ? CHB3D5C : CHB3D); - // CHB3D6C - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, channels == 6 ? CHB3D6C : 0); - // ENCENTER - maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~ENCENTER, channels == 6 ? ENCENTER : 0); - s->status |= DO_MULTI_CH_HW; - } else if (s->capability & CAN_DUAL_DAC) { - unsigned char fmtm = ~0, fmts = 0; - ssize_t ret; - - // ENDBDAC, turn on double DAC mode - // XCHGDAC, CH0 -> back, CH1->front - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, ENDBDAC|XCHGDAC); - // mute FM - fmmute = inb(s->iobase + CODEC_CMI_MIXER1) & FMMUTE; - maskb(s->iobase + CODEC_CMI_MIXER1, ~0, FMMUTE); - s->status |= DO_DUAL_DAC; - // prepare secondary buffer - spin_unlock_irqrestore(&s->lock, flags); - ret = prog_dmabuf(s, 1); - if (ret) return ret; - spin_lock_irqsave(&s->lock, flags); - - // copy the hw state - fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT); - fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT); - // the HW only support 16-bit stereo - fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT; - fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT; - fmts |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT; - fmts |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT; - - set_fmt_unlocked(s, fmtm, fmts); - set_adc_rate_unlocked(s, s->ratedac); - } - // disable 4 speaker mode (analog duplicate) - set_hw_copy(s, 0); - s->curr_channels = channels; - - // enable jack redirect - set_line_as_rear(s, use_line_as_rear); - if (channels > 4) { - set_line_as_bass(s, use_line_as_bass); - set_mic_as_bass(s, use_mic_as_bass); - } - } else { - if (s->status & DO_MULTI_CH_HW) { - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~NXCHG, 0); - maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), 0); - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, 0); - } else if (s->status & DO_DUAL_DAC) { - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~ENDBDAC, 0); - maskb(s->iobase + CODEC_CMI_MIXER1, ~FMMUTE, fmmute); - } - // enable 4 speaker mode (analog duplicate) - set_hw_copy(s, hw_copy); - s->status &= ~DO_MULTI_CH; - s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1; - // disable jack redirect - set_line_as_rear(s, hw_copy ? use_line_as_rear : 0); - set_line_as_bass(s, 0); - set_mic_as_bass(s, 0); - } - spin_unlock_irqrestore(&s->lock, flags); - return s->curr_channels; -} - -/* --------------------------------------------------------------------- */ - -#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - -static void dealloc_dmabuf(struct cm_state *s, struct dmabuf *db) -{ - struct page *pstart, *pend; - - if (db->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++) - ClearPageReserved(pstart); - pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); - } - db->rawbuf = NULL; - db->mapped = db->ready = 0; -} - -/* Ch1 is used for playback, Ch0 is used for recording */ - -static int prog_dmabuf(struct cm_state *s, unsigned rec) -{ - struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; - unsigned rate = rec ? s->rateadc : s->ratedac; - int order; - unsigned bytepersec; - unsigned bufs; - struct page *pstart, *pend; - unsigned char fmt; - unsigned long flags; - - fmt = s->fmt; - if (rec) { - stop_adc(s); - fmt >>= CM_CFMT_ADCSHIFT; - } else { - stop_dac(s); - fmt >>= CM_CFMT_DACSHIFT; - } - - fmt &= CM_CFMT_MASK; - db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; - if (!db->rawbuf) { - db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) - break; - if (!db->rawbuf || !db->dmaaddr) - return -ENOMEM; - db->buforder = order; - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++) - SetPageReserved(pstart); - } - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - /* to make fragsize >= 4096 */ - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; - db->dmasamples = db->dmasize >> sample_shift[fmt]; - memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize); - spin_lock_irqsave(&s->lock, flags); - if (rec) { - if (s->status & DO_DUAL_DAC) - set_dmadac1(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]); - else - set_dmaadc(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]); - /* program sample counts */ - set_countdac(s, db->fragsamples); - } else { - set_dmadac(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]); - /* program sample counts */ - set_countdac(s, db->fragsamples); - } - spin_unlock_irqrestore(&s->lock, flags); - db->enabled = 1; - db->ready = 1; - return 0; -} - -static inline void clear_advance(struct cm_state *s) -{ - unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80; - unsigned char *buf = s->dma_dac.rawbuf; - unsigned char *buf1 = s->dma_adc.rawbuf; - unsigned bsize = s->dma_dac.dmasize; - unsigned bptr = s->dma_dac.swptr; - unsigned len = s->dma_dac.fragsize; - - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(buf + bptr, c, x); - if (s->status & DO_DUAL_DAC) - memset(buf1 + bptr, c, x); - bptr = 0; - len -= x; - } - memset(buf + bptr, c, len); - if (s->status & DO_DUAL_DAC) - memset(buf1 + bptr, c, len); -} - -/* call with spinlock held! */ -static void cm_update_ptr(struct cm_state *s) -{ - unsigned hwptr; - int diff; - - /* update ADC pointer */ - if (s->dma_adc.ready) { - if (s->status & DO_DUAL_DAC) { - /* the dac part will finish for this */ - } else { - hwptr = get_dmaadc(s) % s->dma_adc.dmasize; - diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; - s->dma_adc.hwptr = hwptr; - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - wake_up(&s->dma_adc.wait); - if (!s->dma_adc.mapped) { - if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { - pause_adc(s); - s->dma_adc.error++; - } - } - } - } - /* update DAC pointer */ - if (s->dma_dac.ready) { - hwptr = get_dmadac(s) % s->dma_dac.dmasize; - diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; - s->dma_dac.hwptr = hwptr; - s->dma_dac.total_bytes += diff; - if (s->status & DO_DUAL_DAC) { - s->dma_adc.hwptr = hwptr; - s->dma_adc.total_bytes += diff; - } - if (s->dma_dac.mapped) { - s->dma_dac.count += diff; - if (s->status & DO_DUAL_DAC) - s->dma_adc.count += diff; - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - wake_up(&s->dma_dac.wait); - } else { - s->dma_dac.count -= diff; - if (s->status & DO_DUAL_DAC) - s->dma_adc.count -= diff; - if (s->dma_dac.count <= 0) { - pause_dac(s); - s->dma_dac.error++; - } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { - clear_advance(s); - s->dma_dac.endcleared = 1; - if (s->status & DO_DUAL_DAC) - s->dma_adc.endcleared = 1; - } - if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) - wake_up(&s->dma_dac.wait); - } - } -} - -static irqreturn_t cm_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct cm_state *s = (struct cm_state *)dev_id; - unsigned int intsrc, intstat; - unsigned char mask = 0; - - /* fastpath out, to ease interrupt sharing */ - intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS); - if (!(intsrc & 0x80000000)) - return IRQ_NONE; - spin_lock(&s->lock); - intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2); - /* acknowledge interrupt */ - if (intsrc & ADCINT) - mask |= ENADCINT; - if (intsrc & DACINT) - mask |= ENDACINT; - outb(intstat & ~mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2); - outb(intstat | mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2); - cm_update_ptr(s); - spin_unlock(&s->lock); -#ifdef CONFIG_SOUND_CMPCI_MIDI - if (intsrc & 0x00010000) { // UART interrupt - if (s->midi_devc && intchk_mpu401((void *)s->midi_devc)) - mpuintr(irq, (void *)s->midi_devc, regs); - else - inb(s->iomidi);// dummy read - } -#endif - return IRQ_HANDLED; -} - -/* --------------------------------------------------------------------- */ - -static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != CM_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -/* --------------------------------------------------------------------- */ - -#define MT_4 1 -#define MT_5MUTE 2 -#define MT_4MUTEMONO 3 -#define MT_6MUTE 4 -#define MT_5MUTEMONO 5 - -static const struct { - unsigned left; - unsigned right; - unsigned type; - unsigned rec; - unsigned play; -} mixtable[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_CD] = { DSP_MIX_CDVOLIDX_L, DSP_MIX_CDVOLIDX_R, MT_5MUTE, 0x04, 0x06 }, - [SOUND_MIXER_LINE] = { DSP_MIX_LINEVOLIDX_L, DSP_MIX_LINEVOLIDX_R, MT_5MUTE, 0x10, 0x18 }, - [SOUND_MIXER_MIC] = { DSP_MIX_MICVOLIDX, DSP_MIX_MICVOLIDX, MT_5MUTEMONO, 0x01, 0x01 }, - [SOUND_MIXER_SYNTH] = { DSP_MIX_FMVOLIDX_L, DSP_MIX_FMVOLIDX_R, MT_5MUTE, 0x40, 0x00 }, - [SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE, 0x00, 0x00 }, - [SOUND_MIXER_PCM] = { DSP_MIX_VOICEVOLIDX_L, DSP_MIX_VOICEVOLIDX_R, MT_5MUTE, 0x00, 0x00 }, - [SOUND_MIXER_LINE1] = { DSP_MIX_AUXVOL_L, DSP_MIX_AUXVOL_R, MT_5MUTE, 0x80, 0x60 }, - [SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX, DSP_MIX_SPKRVOLIDX, MT_5MUTEMONO, 0x00, 0x01 } -}; - -static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = -{ - [SOUND_MIXER_CD] = 1, - [SOUND_MIXER_LINE] = 2, - [SOUND_MIXER_MIC] = 3, - [SOUND_MIXER_SYNTH] = 4, - [SOUND_MIXER_VOLUME] = 5, - [SOUND_MIXER_PCM] = 6, - [SOUND_MIXER_LINE1] = 7, - [SOUND_MIXER_SPEAKER]= 8 -}; - -static unsigned mixer_outmask(struct cm_state *s) -{ - unsigned long flags; - int i, j, k; - - spin_lock_irqsave(&s->lock, flags); - j = rdmixer(s, DSP_MIX_OUTMIXIDX); - spin_unlock_irqrestore(&s->lock, flags); - for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (j & mixtable[i].play) - k |= 1 << i; - return k; -} - -static unsigned mixer_recmask(struct cm_state *s) -{ - unsigned long flags; - int i, j, k; - - spin_lock_irqsave(&s->lock, flags); - j = rdmixer(s, DSP_MIX_ADCMIXIDX_L); - spin_unlock_irqrestore(&s->lock, flags); - for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (j & mixtable[i].rec) - k |= 1 << i; - return k; -} - -static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - int i, val, j; - unsigned char l, r, rl, rr; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_STATE(s); - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, "cmpci", sizeof(info.id)); - strlcpy(info.name, "C-Media PCI", sizeof(info.name)); - info.modify_counter = s->mix.modcnt; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, "cmpci", sizeof(info.id)); - strlcpy(info.name, "C-Media cmpci", sizeof(info.name)); - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, p); - if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - if (_SIOC_DIR(cmd) == _SIOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - val = mixer_recmask(s); - return put_user(val, p); - - case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */ - val = mixer_outmask(s); - return put_user(val, p); - - case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ - for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].type) - val |= 1 << i; - return put_user(val, p); - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].rec) - val |= 1 << i; - return put_user(val, p); - - case SOUND_MIXER_OUTMASK: /* Arg contains a bit for each supported recording source */ - for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].play) - val |= 1 << i; - return put_user(val, p); - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO) - val |= 1 << i; - return put_user(val, p); - - case SOUND_MIXER_CAPS: - return put_user(0, p); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) - return -EINVAL; - if (!volidx[i]) - return -EINVAL; - return put_user(s->mix.vol[volidx[i]-1], p); - } - } - if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) - return -EINVAL; - s->mix.modcnt++; - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - if (get_user(val, p)) - return -EFAULT; - i = hweight32(val); - for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (!(val & (1 << i))) - continue; - if (!mixtable[i].rec) { - val &= ~(1 << i); - continue; - } - j |= mixtable[i].rec; - } - spin_lock_irqsave(&s->lock, flags); - wrmixer(s, DSP_MIX_ADCMIXIDX_L, j); - wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1) | (j & 0x80)); - spin_unlock_irqrestore(&s->lock, flags); - return 0; - - case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */ - if (get_user(val, p)) - return -EFAULT; - for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (!(val & (1 << i))) - continue; - if (!mixtable[i].play) { - val &= ~(1 << i); - continue; - } - j |= mixtable[i].play; - } - spin_lock_irqsave(&s->lock, flags); - wrmixer(s, DSP_MIX_OUTMIXIDX, j); - spin_unlock_irqrestore(&s->lock, flags); - return 0; - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - l = val & 0xff; - r = (val >> 8) & 0xff; - if (l > 100) - l = 100; - if (r > 100) - r = 100; - spin_lock_irqsave(&s->lock, flags); - switch (mixtable[i].type) { - case MT_4: - if (l >= 10) - l -= 10; - if (r >= 10) - r -= 10; - frobindir(s, mixtable[i].left, 0xf0, l / 6); - frobindir(s, mixtable[i].right, 0xf0, l / 6); - break; - - case MT_4MUTEMONO: - rl = (l < 4 ? 0 : (l - 5) / 3) & 31; - rr = (rl >> 2) & 7; - wrmixer(s, mixtable[i].left, rl<<3); - if (i == SOUND_MIXER_MIC) - maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1); - break; - - case MT_5MUTEMONO: - rl = l < 4 ? 0 : (l - 5) / 3; - wrmixer(s, mixtable[i].left, rl<<3); - l = rdmixer(s, DSP_MIX_OUTMIXIDX) & ~mixtable[i].play; - r = rl ? mixtable[i].play : 0; - wrmixer(s, DSP_MIX_OUTMIXIDX, l | r); - /* for recording */ - if (i == SOUND_MIXER_MIC) { - if (s->chip_version >= 37) { - rr = rl >> 1; - maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, (rr&0x07)<<1); - frobindir(s, DSP_MIX_EXTENSION, ~0x01, rr>>3); - } else { - rr = rl >> 2; - maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1); - } - } - break; - - case MT_5MUTE: - rl = l < 4 ? 0 : (l - 5) / 3; - rr = r < 4 ? 0 : (r - 5) / 3; - wrmixer(s, mixtable[i].left, rl<<3); - wrmixer(s, mixtable[i].right, rr<<3); - l = rdmixer(s, DSP_MIX_OUTMIXIDX); - l &= ~mixtable[i].play; - r = (rl|rr) ? mixtable[i].play : 0; - wrmixer(s, DSP_MIX_OUTMIXIDX, l | r); - break; - - case MT_6MUTE: - if (l < 6) - rl = 0x00; - else - rl = l * 2 / 3; - if (r < 6) - rr = 0x00; - else - rr = r * 2 / 3; - wrmixer(s, mixtable[i].left, rl); - wrmixer(s, mixtable[i].right, rr); - break; - } - spin_unlock_irqrestore(&s->lock, flags); - - if (!volidx[i]) - return -EINVAL; - s->mix.vol[volidx[i]-1] = val; - return put_user(s->mix.vol[volidx[i]-1], p); - } -} - -/* --------------------------------------------------------------------- */ - -static int cm_open_mixdev(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct list_head *list; - struct cm_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct cm_state, devs); - if (s->dev_mixer == minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - return nonseekable_open(inode, file); -} - -static int cm_release_mixdev(struct inode *inode, struct file *file) -{ - struct cm_state *s = (struct cm_state *)file->private_data; - - VALIDATE_STATE(s); - return 0; -} - -static int cm_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - return mixer_ioctl((struct cm_state *)file->private_data, cmd, arg); -} - -static /*const*/ struct file_operations cm_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = cm_ioctl_mixdev, - .open = cm_open_mixdev, - .release = cm_release_mixdev, -}; - - -/* --------------------------------------------------------------------- */ - -static int drain_dac(struct cm_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count, tmo; - - if (s->dma_dac.mapped || !s->dma_dac.ready) - return 0; - add_wait_queue(&s->dma_dac.wait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac; - tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]; - if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG "cmpci: dma timed out??\n");) - } - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static ssize_t cm_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct cm_state *s = (struct cm_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - - add_wait_queue(&s->dma_adc.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - swptr = s->dma_adc.swptr; - cnt = s->dma_adc.dmasize-swptr; - if (s->dma_adc.count < cnt) - cnt = s->dma_adc.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_adc.enabled) - start_adc(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - if (!schedule_timeout(HZ)) { - printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, - s->dma_adc.hwptr, s->dma_adc.swptr); - spin_lock_irqsave(&s->lock, flags); - stop_adc_unlocked(s); - set_dmaadc(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples); - /* program sample counts */ - set_countadc(s, s->dma_adc.fragsamples); - s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; - spin_unlock_irqrestore(&s->lock, flags); - } - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out; - } - continue; - } - if (s->status & DO_BIGENDIAN_R) { - int i, err; - unsigned char *src; - char __user *dst = buffer; - unsigned char data[2]; - - src = (unsigned char *) (s->dma_adc.rawbuf + swptr); - // copy left/right sample at one time - for (i = 0; i < cnt / 2; i++) { - data[0] = src[1]; - data[1] = src[0]; - if ((err = __put_user(data[0], dst++))) { - ret = err; - goto out; - } - if ((err = __put_user(data[1], dst++))) { - ret = err; - goto out; - } - src += 2; - } - } else if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { - if (!ret) - ret = -EFAULT; - goto out; - } - swptr = (swptr + cnt) % s->dma_adc.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_adc.swptr = swptr; - s->dma_adc.count -= cnt; - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_adc.enabled) - start_adc_unlocked(s); - spin_unlock_irqrestore(&s->lock, flags); - } -out: - remove_wait_queue(&s->dma_adc.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -static ssize_t cm_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct cm_state *s = (struct cm_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac.mapped) - return -ENXIO; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - if (s->status & DO_DUAL_DAC) { - if (s->dma_adc.mapped) - return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - } - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - - add_wait_queue(&s->dma_dac.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - if (s->dma_dac.count < 0) { - s->dma_dac.count = 0; - s->dma_dac.swptr = s->dma_dac.hwptr; - } - if (s->status & DO_DUAL_DAC) { - s->dma_adc.swptr = s->dma_dac.swptr; - s->dma_adc.count = s->dma_dac.count; - s->dma_adc.endcleared = s->dma_dac.endcleared; - } - swptr = s->dma_dac.swptr; - cnt = s->dma_dac.dmasize-swptr; - if (s->status & DO_AC3_SW) { - if (s->dma_dac.count + 2 * cnt > s->dma_dac.dmasize) - cnt = (s->dma_dac.dmasize - s->dma_dac.count) / 2; - } else { - if (s->dma_dac.count + cnt > s->dma_dac.dmasize) - cnt = s->dma_dac.dmasize - s->dma_dac.count; - } - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if ((s->status & DO_DUAL_DAC) && (cnt > count / 2)) - cnt = count / 2; - if (cnt <= 0) { - if (s->dma_dac.enabled) - start_dac(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - if (!schedule_timeout(HZ)) { - printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, - s->dma_dac.hwptr, s->dma_dac.swptr); - spin_lock_irqsave(&s->lock, flags); - stop_dac_unlocked(s); - set_dmadac(s, s->dma_dac.dmaaddr, s->dma_dac.dmasamples); - /* program sample counts */ - set_countdac(s, s->dma_dac.fragsamples); - s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; - if (s->status & DO_DUAL_DAC) { - set_dmadac1(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples); - s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; - } - spin_unlock_irqrestore(&s->lock, flags); - } - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out; - } - continue; - } - if (s->status & DO_AC3_SW) { - int err; - - // clip exceeded data, caught by 033 and 037 - if (swptr + 2 * cnt > s->dma_dac.dmasize) - cnt = (s->dma_dac.dmasize - swptr) / 2; - if ((err = trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt))) { - ret = err; - goto out; - } - swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize; - } else if ((s->status & DO_DUAL_DAC) && (s->status & DO_BIGENDIAN_W)) { - int i, err; - const char __user *src = buffer; - unsigned char *dst0, *dst1; - unsigned char data[8]; - - dst0 = (unsigned char *) (s->dma_dac.rawbuf + swptr); - dst1 = (unsigned char *) (s->dma_adc.rawbuf + swptr); - // copy left/right sample at one time - for (i = 0; i < cnt / 4; i++) { - if ((err = __get_user(data[0], src++))) { - ret = err; - goto out; - } - if ((err = __get_user(data[1], src++))) { - ret = err; - goto out; - } - if ((err = __get_user(data[2], src++))) { - ret = err; - goto out; - } - if ((err = __get_user(data[3], src++))) { - ret = err; - goto out; - } - if ((err = __get_user(data[4], src++))) { - ret = err; - goto out; - } - if ((err = __get_user(data[5], src++))) { - ret = err; - goto out; - } - if ((err = __get_user(data[6], src++))) { - ret = err; - goto out; - } - if ((err = __get_user(data[7], src++))) { - ret = err; - goto out; - } - dst0[0] = data[1]; - dst0[1] = data[0]; - dst0[2] = data[3]; - dst0[3] = data[2]; - dst1[0] = data[5]; - dst1[1] = data[4]; - dst1[2] = data[7]; - dst1[3] = data[6]; - dst0 += 4; - dst1 += 4; - } - swptr = (swptr + cnt) % s->dma_dac.dmasize; - } else if (s->status & DO_DUAL_DAC) { - int i, err; - unsigned long __user *src = (unsigned long __user *) buffer; - unsigned long *dst0, *dst1; - - dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr); - dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr); - // copy left/right sample at one time - for (i = 0; i < cnt / 4; i++) { - if ((err = __get_user(*dst0++, src++))) { - ret = err; - goto out; - } - if ((err = __get_user(*dst1++, src++))) { - ret = err; - goto out; - } - } - swptr = (swptr + cnt) % s->dma_dac.dmasize; - } else if (s->status & DO_BIGENDIAN_W) { - int i, err; - const char __user *src = buffer; - unsigned char *dst; - unsigned char data[2]; - - dst = (unsigned char *) (s->dma_dac.rawbuf + swptr); - // swap hi/lo bytes for each sample - for (i = 0; i < cnt / 2; i++) { - if ((err = __get_user(data[0], src++))) { - ret = err; - goto out; - } - if ((err = __get_user(data[1], src++))) { - ret = err; - goto out; - } - dst[0] = data[1]; - dst[1] = data[0]; - dst += 2; - } - swptr = (swptr + cnt) % s->dma_dac.dmasize; - } else { - if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - goto out; - } - swptr = (swptr + cnt) % s->dma_dac.dmasize; - } - spin_lock_irqsave(&s->lock, flags); - s->dma_dac.swptr = swptr; - s->dma_dac.count += cnt; - if (s->status & DO_AC3_SW) - s->dma_dac.count += cnt; - s->dma_dac.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->status & DO_DUAL_DAC) { - count -= cnt; - buffer += cnt; - ret += cnt; - } - if (s->dma_dac.enabled) - start_dac(s); - } -out: - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait) -{ - struct cm_state *s = (struct cm_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac.ready && prog_dmabuf(s, 0)) - return 0; - poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready && prog_dmabuf(s, 1)) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - spin_lock_irqsave(&s->lock, flags); - cm_update_ptr(s); - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int cm_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cm_state *s = (struct cm_state *)file->private_data; - struct dmabuf *db; - int ret = -EINVAL; - unsigned long size; - - VALIDATE_STATE(s); - lock_kernel(); - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf(s, 0)) != 0) - goto out; - db = &s->dma_dac; - } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf(s, 1)) != 0) - goto out; - db = &s->dma_adc; - } else - goto out; - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) - goto out; - ret = -EINVAL; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - db->mapped = 1; - ret = 0; -out: - unlock_kernel(); - return ret; -} - -#define SNDCTL_SPDIF_COPYRIGHT _SIOW('S', 0, int) // set/reset S/PDIF copy protection -#define SNDCTL_SPDIF_LOOP _SIOW('S', 1, int) // set/reset S/PDIF loop -#define SNDCTL_SPDIF_MONITOR _SIOW('S', 2, int) // set S/PDIF monitor -#define SNDCTL_SPDIF_LEVEL _SIOW('S', 3, int) // set/reset S/PDIF out level -#define SNDCTL_SPDIF_INV _SIOW('S', 4, int) // set/reset S/PDIF in inverse -#define SNDCTL_SPDIF_SEL2 _SIOW('S', 5, int) // set S/PDIF in #2 -#define SNDCTL_SPDIF_VALID _SIOW('S', 6, int) // set S/PDIF valid -#define SNDCTL_SPDIFOUT _SIOW('S', 7, int) // set S/PDIF out -#define SNDCTL_SPDIFIN _SIOW('S', 8, int) // set S/PDIF out - -static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct cm_state *s = (struct cm_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int val, mapped, ret; - unsigned char fmtm, fmtd; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_BIND, p); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(s->irq); - s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; - if (s->status & DO_DUAL_DAC) - s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->irq); - s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&s->lock, flags); - stop_adc_unlocked(s); - s->dma_adc.ready = 0; - set_adc_rate_unlocked(s, val); - spin_unlock_irqrestore(&s->lock, flags); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (s->status & DO_DUAL_DAC) - s->dma_adc.ready = 0; - set_dac_rate(s, val); - } - } - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val) - fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT; - else - fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val) - fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT; - else - fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT); - if (s->status & DO_DUAL_DAC) { - s->dma_adc.ready = 0; - if (val) - fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT; - else - fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT); - } - } - set_fmt(s, fmtm, fmtd); - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val >= 2) - fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT; - else - fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val >= 2) - fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT; - else - fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT); - if (s->status & DO_DUAL_DAC) { - s->dma_adc.ready = 0; - if (val >= 2) - fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT; - else - fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT); - } - } - set_fmt(s, fmtm, fmtd); - if ((s->capability & CAN_MULTI_CH) - && (file->f_mode & FMODE_WRITE)) { - val = set_dac_channels(s, val); - return put_user(val, p); - } - } - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) - : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_BE|AFMT_S16_LE|AFMT_U8| - ((s->capability & CAN_AC3) ? AFMT_AC3 : 0), p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val == AFMT_S16_BE || val == AFMT_S16_LE) - fmtd |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT; - else - fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_ADCSHIFT); - if (val == AFMT_S16_BE) - s->status |= DO_BIGENDIAN_R; - else - s->status &= ~DO_BIGENDIAN_R; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val == AFMT_S16_BE || val == AFMT_S16_LE || val == AFMT_AC3) - fmtd |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT; - else - fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_DACSHIFT); - if (val == AFMT_AC3) { - fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT; - set_ac3(s, 48000); - } else - set_ac3(s, 0); - if (s->status & DO_DUAL_DAC) { - s->dma_adc.ready = 0; - if (val == AFMT_S16_BE || val == AFMT_S16_LE) - fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT; - else - fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT); - } - if (val == AFMT_S16_BE) - s->status |= DO_BIGENDIAN_W; - else - s->status &= ~DO_BIGENDIAN_W; - } - set_fmt(s, fmtm, fmtd); - } - if (s->status & DO_AC3) return put_user(AFMT_AC3, p); - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) - : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? val : AFMT_U8, p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if (s->status & DO_DUAL_DAC) { - if (file->f_mode & FMODE_WRITE && - (s->enable & ENDAC) && - (s->enable & ENADC)) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - } - if (file->f_mode & FMODE_READ && s->enable & ENADC) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && s->enable & ENDAC) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - s->dma_adc.enabled = 1; - start_adc(s); - } else { - s->dma_adc.enabled = 0; - stop_adc(s); - } - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - if (s->status & DO_DUAL_DAC) { - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - } - s->dma_dac.enabled = 1; - start_dac(s); - } else { - s->dma_dac.enabled = 0; - stop_dac(s); - } - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!(s->enable & ENDAC) && (val = prog_dmabuf(s, 0)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - cm_update_ptr(s); - abinfo.fragsize = s->dma_dac.fragsize; - abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!(s->enable & ENADC) && (val = prog_dmabuf(s, 1)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - cm_update_ptr(s); - abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cm_update_ptr(s); - val = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, p); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cm_update_ptr(s); - cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cm_update_ptr(s); - cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; - cinfo.ptr = s->dma_dac.hwptr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize-1; - if (s->status & DO_DUAL_DAC) { - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - } - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf(s, 0))) - return val; - if (s->status & DO_DUAL_DAC) { - if ((val = prog_dmabuf(s, 1))) - return val; - return put_user(2 * s->dma_dac.fragsize, p); - } - return put_user(s->dma_dac.fragsize, p); - } - if ((val = prog_dmabuf(s, 1))) - return val; - return put_user(s->dma_adc.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - if (s->status & DO_DUAL_DAC) { - s->dma_adc.ossfragshift = s->dma_dac.ossfragshift; - s->dma_adc.ossmaxfrags = s->dma_dac.ossmaxfrags; - } - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.subdivision = val; - if (s->status & DO_DUAL_DAC) - s->dma_adc.subdivision = val; - } - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? 16 : 8, p); - - case SOUND_PCM_READ_FILTER: - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SNDCTL_DSP_GETCHANNELMASK: - return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, p); - - case SNDCTL_DSP_BIND_CHANNEL: - if (get_user(val, p)) - return -EFAULT; - if (val == DSP_BIND_QUERY) { - val = DSP_BIND_FRONT; - if (s->status & DO_SPDIF_OUT) - val |= DSP_BIND_SPDIF; - else { - if (s->curr_channels == 4) - val |= DSP_BIND_SURR; - if (s->curr_channels > 4) - val |= DSP_BIND_CENTER_LFE; - } - } else { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val & DSP_BIND_SPDIF) { - set_spdifin(s, s->rateadc); - if (!(s->status & DO_SPDIF_OUT)) - val &= ~DSP_BIND_SPDIF; - } - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val & DSP_BIND_SPDIF) { - set_spdifout(s, s->ratedac); - set_dac_channels(s, s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1); - if (!(s->status & DO_SPDIF_OUT)) - val &= ~DSP_BIND_SPDIF; - } else { - int channels; - int mask; - - mask = val & (DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE); - switch (mask) { - case DSP_BIND_FRONT: - channels = 2; - break; - case DSP_BIND_FRONT|DSP_BIND_SURR: - channels = 4; - break; - case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE: - channels = 6; - break; - default: - channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1; - break; - } - set_dac_channels(s, channels); - } - } - } - return put_user(val, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_MAPINBUF: - case SNDCTL_DSP_MAPOUTBUF: - case SNDCTL_DSP_SETSYNCRO: - return -EINVAL; - case SNDCTL_SPDIF_COPYRIGHT: - if (get_user(val, p)) - return -EFAULT; - set_spdif_copyright(s, val); - return 0; - case SNDCTL_SPDIF_LOOP: - if (get_user(val, p)) - return -EFAULT; - set_spdif_loop(s, val); - return 0; - case SNDCTL_SPDIF_MONITOR: - if (get_user(val, p)) - return -EFAULT; - set_spdif_monitor(s, val); - return 0; - case SNDCTL_SPDIF_LEVEL: - if (get_user(val, p)) - return -EFAULT; - set_spdifout_level(s, val); - return 0; - case SNDCTL_SPDIF_INV: - if (get_user(val, p)) - return -EFAULT; - set_spdifin_inverse(s, val); - return 0; - case SNDCTL_SPDIF_SEL2: - if (get_user(val, p)) - return -EFAULT; - set_spdifin_channel2(s, val); - return 0; - case SNDCTL_SPDIF_VALID: - if (get_user(val, p)) - return -EFAULT; - set_spdifin_valid(s, val); - return 0; - case SNDCTL_SPDIFOUT: - if (get_user(val, p)) - return -EFAULT; - set_spdifout(s, val ? s->ratedac : 0); - return 0; - case SNDCTL_SPDIFIN: - if (get_user(val, p)) - return -EFAULT; - set_spdifin(s, val ? s->rateadc : 0); - return 0; - } - return mixer_ioctl(s, cmd, arg); -} - -static int cm_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned char fmtm = ~0, fmts = 0; - struct list_head *list; - struct cm_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct cm_state, devs); - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - if (file->f_mode & FMODE_READ) { - s->status &= ~DO_BIGENDIAN_R; - fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT; - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; - s->dma_adc.enabled = 1; - set_adc_rate(s, 8000); - // spdif-in is turnned off by default - set_spdifin(s, 0); - } - if (file->f_mode & FMODE_WRITE) { - s->status &= ~DO_BIGENDIAN_W; - fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT; - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; - s->dma_dac.enabled = 1; - set_dac_rate(s, 8000); - // clear previous multichannel, spdif, ac3 state - set_spdifout(s, 0); - set_ac3(s, 0); - set_dac_channels(s, 1); - } - set_fmt(s, fmtm, fmts); - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int cm_release(struct inode *inode, struct file *file) -{ - struct cm_state *s = (struct cm_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - if (file->f_mode & FMODE_WRITE) - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - - dealloc_dmabuf(s, &s->dma_dac); - if (s->status & DO_DUAL_DAC) - dealloc_dmabuf(s, &s->dma_adc); - - if (s->status & DO_MULTI_CH) - set_dac_channels(s, 1); - if (s->status & DO_AC3) - set_ac3(s, 0); - if (s->status & DO_SPDIF_OUT) - set_spdifout(s, 0); - /* enable SPDIF loop */ - set_spdif_loop(s, spdif_loop); - s->status &= ~DO_BIGENDIAN_W; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - s->status &= ~DO_BIGENDIAN_R; - } - s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE)); - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations cm_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cm_read, - .write = cm_write, - .poll = cm_poll, - .ioctl = cm_ioctl, - .mmap = cm_mmap, - .open = cm_open, - .release = cm_release, -}; - -/* --------------------------------------------------------------------- */ - -static struct initvol { - int mixch; - int vol; -} initvol[] __devinitdata = { - { SOUND_MIXER_WRITE_CD, 0x4f4f }, - { SOUND_MIXER_WRITE_LINE, 0x4f4f }, - { SOUND_MIXER_WRITE_MIC, 0x4f4f }, - { SOUND_MIXER_WRITE_SYNTH, 0x4f4f }, - { SOUND_MIXER_WRITE_VOLUME, 0x4f4f }, - { SOUND_MIXER_WRITE_PCM, 0x4f4f } -}; - -/* check chip version and capability */ -static int query_chip(struct cm_state *s) -{ - int ChipVersion = -1; - unsigned char RegValue; - - // check reg 0Ch, bit 24-31 - RegValue = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 3); - if (RegValue == 0) { - // check reg 08h, bit 24-28 - RegValue = inb(s->iobase + CODEC_CMI_CHFORMAT + 3); - RegValue &= 0x1f; - if (RegValue == 0) { - ChipVersion = 33; - s->max_channels = 4; - s->capability |= CAN_AC3_SW; - s->capability |= CAN_DUAL_DAC; - } else { - ChipVersion = 37; - s->max_channels = 4; - s->capability |= CAN_AC3_HW; - s->capability |= CAN_DUAL_DAC; - } - } else { - // check reg 0Ch, bit 26 - if (RegValue & (1 << (26-24))) { - ChipVersion = 39; - if (RegValue & (1 << (24-24))) - s->max_channels = 6; - else - s->max_channels = 4; - s->capability |= CAN_AC3_HW; - s->capability |= CAN_DUAL_DAC; - s->capability |= CAN_MULTI_CH_HW; - s->capability |= CAN_LINE_AS_BASS; - s->capability |= CAN_MIC_AS_BASS; - } else { - ChipVersion = 55; // 4 or 6 channels - s->max_channels = 6; - s->capability |= CAN_AC3_HW; - s->capability |= CAN_DUAL_DAC; - s->capability |= CAN_MULTI_CH_HW; - s->capability |= CAN_LINE_AS_BASS; - s->capability |= CAN_MIC_AS_BASS; - } - } - s->capability |= CAN_LINE_AS_REAR; - return ChipVersion; -} - -#ifdef CONFIG_SOUND_CMPCI_JOYSTICK -static int __devinit cm_create_gameport(struct cm_state *s, int io_port) -{ - struct gameport *gp; - - if (!request_region(io_port, CM_EXTENT_GAME, "cmpci GAME")) { - printk(KERN_ERR "cmpci: gameport io ports 0x%#x in use\n", io_port); - return -EBUSY; - } - - if (!(s->gameport = gp = gameport_allocate_port())) { - printk(KERN_ERR "cmpci: can not allocate memory for gameport\n"); - release_region(io_port, CM_EXTENT_GAME); - return -ENOMEM; - } - - gameport_set_name(gp, "C-Media GP"); - gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev)); - gp->dev.parent = &s->dev->dev; - gp->io = io_port; - - /* enable joystick */ - maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02); - - gameport_register_port(gp); - - return 0; -} - -static void __devexit cm_free_gameport(struct cm_state *s) -{ - if (s->gameport) { - int gpio = s->gameport->io; - - gameport_unregister_port(s->gameport); - s->gameport = NULL; - maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0); - release_region(gpio, CM_EXTENT_GAME); - } -} -#else -static inline int cm_create_gameport(struct cm_state *s, int io_port) { return -ENOSYS; } -static inline void cm_free_gameport(struct cm_state *s) { } -#endif - -#define echo_option(x)\ -if (x) strcat(options, "" #x " ") - -static int __devinit cm_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) -{ - struct cm_state *s; - mm_segment_t fs; - int i, val, ret; - unsigned char reg_mask; - int timeout; - struct resource *ports; - struct { - unsigned short deviceid; - char *devicename; - } devicetable[] = { - { PCI_DEVICE_ID_CMEDIA_CM8338A, "CM8338A" }, - { PCI_DEVICE_ID_CMEDIA_CM8338B, "CM8338B" }, - { PCI_DEVICE_ID_CMEDIA_CM8738, "CM8738" }, - { PCI_DEVICE_ID_CMEDIA_CM8738B, "CM8738B" }, - }; - char *devicename = "unknown"; - char options[256]; - - if ((ret = pci_enable_device(pcidev))) - return ret; - if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO)) - return -ENODEV; - if (pcidev->irq == 0) - return -ENODEV; - i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); - if (i) { - printk(KERN_WARNING "cmpci: architecture does not support 32bit PCI busmaster DMA\n"); - return i; - } - s = kmalloc(sizeof(*s), GFP_KERNEL); - if (!s) { - printk(KERN_WARNING "cmpci: out of memory\n"); - return -ENOMEM; - } - /* search device name */ - for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++) { - if (devicetable[i].deviceid == pcidev->device) { - devicename = devicetable[i].devicename; - break; - } - } - memset(s, 0, sizeof(struct cm_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - mutex_init(&s->open_mutex); - spin_lock_init(&s->lock); - s->magic = CM_MAGIC; - s->dev = pcidev; - s->iobase = pci_resource_start(pcidev, 0); - s->iosynth = fmio; - s->iomidi = mpuio; -#ifdef CONFIG_SOUND_CMPCI_MIDI - s->midi_devc = 0; -#endif - s->status = 0; - if (s->iobase == 0) - return -ENODEV; - s->irq = pcidev->irq; - - if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) { - printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1); - ret = -EBUSY; - goto err_region5; - } - /* dump parameters */ - strcpy(options, "cmpci: "); - echo_option(joystick); - echo_option(spdif_inverse); - echo_option(spdif_loop); - echo_option(spdif_out); - echo_option(use_line_as_rear); - echo_option(use_line_as_bass); - echo_option(use_mic_as_bass); - echo_option(mic_boost); - echo_option(hw_copy); - printk(KERN_INFO "%s\n", options); - - /* initialize codec registers */ - outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */ - outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */ - /* reset mixer */ - wrmixer(s, DSP_MIX_DATARESETIDX, 0); - - /* request irq */ - if ((ret = request_irq(s->irq, cm_interrupt, IRQF_SHARED, "cmpci", s))) { - printk(KERN_ERR "cmpci: irq %u in use\n", s->irq); - goto err_irq; - } - printk(KERN_INFO "cmpci: found %s adapter at io %#x irq %u\n", - devicename, s->iobase, s->irq); - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0) { - ret = s->dev_audio; - goto err_dev1; - } - if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0) { - ret = s->dev_mixer; - goto err_dev2; - } - pci_set_master(pcidev); /* enable bus mastering */ - /* initialize the chips */ - fs = get_fs(); - set_fs(KERNEL_DS); - /* set mixer output */ - frobindir(s, DSP_MIX_OUTMIXIDX, 0x1f, 0x1f); - /* set mixer input */ - val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD|SOUND_MASK_MIC; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); - } - set_fs(fs); - /* use channel 1 for playback, channel 0 for record */ - maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, CHADC0); - /* turn off VMIC3 - mic boost */ - if (mic_boost) - maskb(s->iobase + CODEC_CMI_MIXER2, ~1, 0); - else - maskb(s->iobase + CODEC_CMI_MIXER2, ~0, 1); - s->deviceid = pcidev->device; - - if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738 - || pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738B) { - - /* chip version and hw capability check */ - s->chip_version = query_chip(s); - printk(KERN_INFO "cmpci: chip version = 0%d\n", s->chip_version); - - /* set SPDIF-in inverse before enable SPDIF loop */ - set_spdifin_inverse(s, spdif_inverse); - - /* use SPDIF in #1 */ - set_spdifin_channel2(s, 0); - } else { - s->chip_version = 0; - /* 8338 will fall here */ - s->max_channels = 4; - s->capability |= CAN_DUAL_DAC; - s->capability |= CAN_LINE_AS_REAR; - } - /* enable SPDIF loop */ - set_spdif_loop(s, spdif_loop); - - // enable 4 speaker mode (analog duplicate) - set_hw_copy(s, hw_copy); - - reg_mask = 0; -#ifdef CONFIG_SOUND_CMPCI_FM - /* disable FM */ - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0); - if (s->iosynth) { - /* don't enable OPL3 if there is one */ - if (opl3_detect(s->iosynth, NULL)) { - s->iosynth = 0; - } else { - /* set IO based at 0x388 */ - switch (s->iosynth) { - case 0x388: - reg_mask = 0; - break; - case 0x3C8: - reg_mask = 0x01; - break; - case 0x3E0: - reg_mask = 0x02; - break; - case 0x3E8: - reg_mask = 0x03; - break; - default: - s->iosynth = 0; - break; - } - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x03, reg_mask); - /* enable FM */ - if (s->iosynth) { - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8); - if (opl3_detect(s->iosynth, NULL)) - ret = opl3_init(s->iosynth, NULL, THIS_MODULE); - else { - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0); - s->iosynth = 0; - } - } - } - } -#endif -#ifdef CONFIG_SOUND_CMPCI_MIDI - switch (s->iomidi) { - case 0x330: - reg_mask = 0; - break; - case 0x320: - reg_mask = 0x20; - break; - case 0x310: - reg_mask = 0x40; - break; - case 0x300: - reg_mask = 0x60; - break; - default: - s->iomidi = 0; - goto skip_mpu; - } - ports = request_region(s->iomidi, 2, "mpu401"); - if (!ports) - goto skip_mpu; - /* disable MPU-401 */ - maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0); - s->mpu_data.name = "cmpci mpu"; - s->mpu_data.io_base = s->iomidi; - s->mpu_data.irq = -s->irq; // tell mpu401 to share irq - if (probe_mpu401(&s->mpu_data, ports)) { - release_region(s->iomidi, 2); - s->iomidi = 0; - goto skip_mpu; - } - maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x60, reg_mask); - /* enable MPU-401 */ - maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04); - /* clear all previously received interrupt */ - for (timeout = 900000; timeout > 0; timeout--) { - if ((inb(s->iomidi + 1) && 0x80) == 0) - inb(s->iomidi); - else - break; - } - if (!probe_mpu401(&s->mpu_data, ports)) { - release_region(s->iomidi, 2); - s->iomidi = 0; - maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04); - } else { - attach_mpu401(&s->mpu_data, THIS_MODULE); - s->midi_devc = s->mpu_data.slots[1]; - } -skip_mpu: -#endif - /* disable joystick port */ - maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0); - if (joystick) - cm_create_gameport(s, 0x200); - - /* store it in the driver field */ - pci_set_drvdata(pcidev, s); - /* put it into driver list */ - list_add_tail(&s->devs, &devs); - /* increment devindex */ - if (devindex < NR_DEVICE-1) - devindex++; - return 0; - -err_dev2: - unregister_sound_dsp(s->dev_audio); -err_dev1: - printk(KERN_ERR "cmpci: cannot register misc device\n"); - free_irq(s->irq, s); -err_irq: - release_region(s->iobase, CM_EXTENT_CODEC); -err_region5: - kfree(s); - return ret; -} - -/* --------------------------------------------------------------------- */ - -MODULE_AUTHOR("ChenLi Tien, cltien@cmedia.com.tw"); -MODULE_DESCRIPTION("CM8x38 Audio Driver"); -MODULE_LICENSE("GPL"); - -static void __devexit cm_remove(struct pci_dev *dev) -{ - struct cm_state *s = pci_get_drvdata(dev); - - if (!s) - return; - - cm_free_gameport(s); - -#ifdef CONFIG_SOUND_CMPCI_FM - if (s->iosynth) { - /* disable FM */ - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0); - } -#endif -#ifdef CONFIG_SOUND_CMPCI_MIDI - if (s->iomidi) { - unload_mpu401(&s->mpu_data); - /* disable MPU-401 */ - maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0); - } -#endif - set_spdif_loop(s, 0); - list_del(&s->devs); - outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */ - synchronize_irq(s->irq); - outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */ - free_irq(s->irq, s); - - /* reset mixer */ - wrmixer(s, DSP_MIX_DATARESETIDX, 0); - - release_region(s->iobase, CM_EXTENT_CODEC); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - kfree(s); - pci_set_drvdata(dev, NULL); -} - -static struct pci_device_id id_table[] __devinitdata = { - { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, id_table); - -static struct pci_driver cm_driver = { - .name = "cmpci", - .id_table = id_table, - .probe = cm_probe, - .remove = __devexit_p(cm_remove) -}; - -static int __init init_cmpci(void) -{ - printk(KERN_INFO "cmpci: version $Revision: 6.82 $ time " __TIME__ " " __DATE__ "\n"); - return pci_register_driver(&cm_driver); -} - -static void __exit cleanup_cmpci(void) -{ - printk(KERN_INFO "cmpci: unloading\n"); - pci_unregister_driver(&cm_driver); -} - -module_init(init_cmpci); -module_exit(cleanup_cmpci); diff --git a/sound/oss/cs4281/Makefile b/sound/oss/cs4281/Makefile deleted file mode 100644 index 6d527e8530d6..000000000000 --- a/sound/oss/cs4281/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# Makefile for Cirrus Logic-Crystal CS4281 -# - -obj-$(CONFIG_SOUND_CS4281) += cs4281.o - -cs4281-objs += cs4281m.o diff --git a/sound/oss/cs4281/cs4281_hwdefs.h b/sound/oss/cs4281/cs4281_hwdefs.h deleted file mode 100644 index 701d595e33f5..000000000000 --- a/sound/oss/cs4281/cs4281_hwdefs.h +++ /dev/null @@ -1,1234 +0,0 @@ -//**************************************************************************** -// -// HWDEFS.H - Definitions of the registers and data structures used by the -// CS4281 -// -// Copyright (c) 1999,2000,2001 Crystal Semiconductor Corp. -// -//**************************************************************************** - -#ifndef _H_HWDEFS -#define _H_HWDEFS - -//**************************************************************************** -// -// The following define the offsets of the registers located in the PCI -// configuration space of the CS4281 part. -// -//**************************************************************************** -#define PCICONFIG_DEVID_VENID 0x00000000L -#define PCICONFIG_STATUS_COMMAND 0x00000004L -#define PCICONFIG_CLASS_REVISION 0x00000008L -#define PCICONFIG_LATENCY_TIMER 0x0000000CL -#define PCICONFIG_BA0 0x00000010L -#define PCICONFIG_BA1 0x00000014L -#define PCICONFIG_SUBSYSID_SUBSYSVENID 0x0000002CL -#define PCICONFIG_INTERRUPT 0x0000003CL - -//**************************************************************************** -// -// The following define the offsets of the registers accessed via base address -// register zero on the CS4281 part. -// -//**************************************************************************** -#define BA0_HISR 0x00000000L -#define BA0_HICR 0x00000008L -#define BA0_HIMR 0x0000000CL -#define BA0_IIER 0x00000010L -#define BA0_HDSR0 0x000000F0L -#define BA0_HDSR1 0x000000F4L -#define BA0_HDSR2 0x000000F8L -#define BA0_HDSR3 0x000000FCL -#define BA0_DCA0 0x00000110L -#define BA0_DCC0 0x00000114L -#define BA0_DBA0 0x00000118L -#define BA0_DBC0 0x0000011CL -#define BA0_DCA1 0x00000120L -#define BA0_DCC1 0x00000124L -#define BA0_DBA1 0x00000128L -#define BA0_DBC1 0x0000012CL -#define BA0_DCA2 0x00000130L -#define BA0_DCC2 0x00000134L -#define BA0_DBA2 0x00000138L -#define BA0_DBC2 0x0000013CL -#define BA0_DCA3 0x00000140L -#define BA0_DCC3 0x00000144L -#define BA0_DBA3 0x00000148L -#define BA0_DBC3 0x0000014CL -#define BA0_DMR0 0x00000150L -#define BA0_DCR0 0x00000154L -#define BA0_DMR1 0x00000158L -#define BA0_DCR1 0x0000015CL -#define BA0_DMR2 0x00000160L -#define BA0_DCR2 0x00000164L -#define BA0_DMR3 0x00000168L -#define BA0_DCR3 0x0000016CL -#define BA0_DLMR 0x00000170L -#define BA0_DLSR 0x00000174L -#define BA0_FCR0 0x00000180L -#define BA0_FCR1 0x00000184L -#define BA0_FCR2 0x00000188L -#define BA0_FCR3 0x0000018CL -#define BA0_FPDR0 0x00000190L -#define BA0_FPDR1 0x00000194L -#define BA0_FPDR2 0x00000198L -#define BA0_FPDR3 0x0000019CL -#define BA0_FCHS 0x0000020CL -#define BA0_FSIC0 0x00000210L -#define BA0_FSIC1 0x00000214L -#define BA0_FSIC2 0x00000218L -#define BA0_FSIC3 0x0000021CL -#define BA0_PCICFG00 0x00000300L -#define BA0_PCICFG04 0x00000304L -#define BA0_PCICFG08 0x00000308L -#define BA0_PCICFG0C 0x0000030CL -#define BA0_PCICFG10 0x00000310L -#define BA0_PCICFG14 0x00000314L -#define BA0_PCICFG18 0x00000318L -#define BA0_PCICFG1C 0x0000031CL -#define BA0_PCICFG20 0x00000320L -#define BA0_PCICFG24 0x00000324L -#define BA0_PCICFG28 0x00000328L -#define BA0_PCICFG2C 0x0000032CL -#define BA0_PCICFG30 0x00000330L -#define BA0_PCICFG34 0x00000334L -#define BA0_PCICFG38 0x00000338L -#define BA0_PCICFG3C 0x0000033CL -#define BA0_PCICFG40 0x00000340L -#define BA0_PMCS 0x00000344L -#define BA0_CWPR 0x000003E0L -#define BA0_EPPMC 0x000003E4L -#define BA0_GPIOR 0x000003E8L -#define BA0_SPMC 0x000003ECL -#define BA0_CFLR 0x000003F0L -#define BA0_IISR 0x000003F4L -#define BA0_TMS 0x000003F8L -#define BA0_SSVID 0x000003FCL -#define BA0_CLKCR1 0x00000400L -#define BA0_FRR 0x00000410L -#define BA0_SLT12O 0x0000041CL -#define BA0_SERMC 0x00000420L -#define BA0_SERC1 0x00000428L -#define BA0_SERC2 0x0000042CL -#define BA0_SLT12M 0x0000045CL -#define BA0_ACCTL 0x00000460L -#define BA0_ACSTS 0x00000464L -#define BA0_ACOSV 0x00000468L -#define BA0_ACCAD 0x0000046CL -#define BA0_ACCDA 0x00000470L -#define BA0_ACISV 0x00000474L -#define BA0_ACSAD 0x00000478L -#define BA0_ACSDA 0x0000047CL -#define BA0_JSPT 0x00000480L -#define BA0_JSCTL 0x00000484L -#define BA0_MIDCR 0x00000490L -#define BA0_MIDCMD 0x00000494L -#define BA0_MIDSR 0x00000494L -#define BA0_MIDWP 0x00000498L -#define BA0_MIDRP 0x0000049CL -#define BA0_AODSD1 0x000004A8L -#define BA0_AODSD2 0x000004ACL -#define BA0_CFGI 0x000004B0L -#define BA0_SLT12M2 0x000004DCL -#define BA0_ACSTS2 0x000004E4L -#define BA0_ACISV2 0x000004F4L -#define BA0_ACSAD2 0x000004F8L -#define BA0_ACSDA2 0x000004FCL -#define BA0_IOTGP 0x00000500L -#define BA0_IOTSB 0x00000504L -#define BA0_IOTFM 0x00000508L -#define BA0_IOTDMA 0x0000050CL -#define BA0_IOTAC0 0x00000500L -#define BA0_IOTAC1 0x00000504L -#define BA0_IOTAC2 0x00000508L -#define BA0_IOTAC3 0x0000050CL -#define BA0_IOTPCP 0x0000052CL -#define BA0_IOTCC 0x00000530L -#define BA0_IOTCR 0x0000058CL -#define BA0_PCPRR 0x00000600L -#define BA0_PCPGR 0x00000604L -#define BA0_PCPCR 0x00000608L -#define BA0_PCPCIEN 0x00000608L -#define BA0_SBMAR 0x00000700L -#define BA0_SBMDR 0x00000704L -#define BA0_SBRR 0x00000708L -#define BA0_SBRDP 0x0000070CL -#define BA0_SBWDP 0x00000710L -#define BA0_SBWBS 0x00000710L -#define BA0_SBRBS 0x00000714L -#define BA0_FMSR 0x00000730L -#define BA0_B0AP 0x00000730L -#define BA0_FMDP 0x00000734L -#define BA0_B1AP 0x00000738L -#define BA0_B1DP 0x0000073CL -#define BA0_SSPM 0x00000740L -#define BA0_DACSR 0x00000744L -#define BA0_ADCSR 0x00000748L -#define BA0_SSCR 0x0000074CL -#define BA0_FMLVC 0x00000754L -#define BA0_FMRVC 0x00000758L -#define BA0_SRCSA 0x0000075CL -#define BA0_PPLVC 0x00000760L -#define BA0_PPRVC 0x00000764L -#define BA0_PASR 0x00000768L -#define BA0_CASR 0x0000076CL - -//**************************************************************************** -// -// The following define the offsets of the AC97 shadow registers, which appear -// as a virtual extension to the base address register zero memory range. -// -//**************************************************************************** -#define AC97_REG_OFFSET_MASK 0x0000007EL -#define AC97_CODEC_NUMBER_MASK 0x00003000L - -#define BA0_AC97_RESET 0x00001000L -#define BA0_AC97_MASTER_VOLUME 0x00001002L -#define BA0_AC97_HEADPHONE_VOLUME 0x00001004L -#define BA0_AC97_MASTER_VOLUME_MONO 0x00001006L -#define BA0_AC97_MASTER_TONE 0x00001008L -#define BA0_AC97_PC_BEEP_VOLUME 0x0000100AL -#define BA0_AC97_PHONE_VOLUME 0x0000100CL -#define BA0_AC97_MIC_VOLUME 0x0000100EL -#define BA0_AC97_LINE_IN_VOLUME 0x00001010L -#define BA0_AC97_CD_VOLUME 0x00001012L -#define BA0_AC97_VIDEO_VOLUME 0x00001014L -#define BA0_AC97_AUX_VOLUME 0x00001016L -#define BA0_AC97_PCM_OUT_VOLUME 0x00001018L -#define BA0_AC97_RECORD_SELECT 0x0000101AL -#define BA0_AC97_RECORD_GAIN 0x0000101CL -#define BA0_AC97_RECORD_GAIN_MIC 0x0000101EL -#define BA0_AC97_GENERAL_PURPOSE 0x00001020L -#define BA0_AC97_3D_CONTROL 0x00001022L -#define BA0_AC97_MODEM_RATE 0x00001024L -#define BA0_AC97_POWERDOWN 0x00001026L -#define BA0_AC97_EXT_AUDIO_ID 0x00001028L -#define BA0_AC97_EXT_AUDIO_POWER 0x0000102AL -#define BA0_AC97_PCM_FRONT_DAC_RATE 0x0000102CL -#define BA0_AC97_PCM_SURR_DAC_RATE 0x0000102EL -#define BA0_AC97_PCM_LFE_DAC_RATE 0x00001030L -#define BA0_AC97_PCM_LR_ADC_RATE 0x00001032L -#define BA0_AC97_MIC_ADC_RATE 0x00001034L -#define BA0_AC97_6CH_VOL_C_LFE 0x00001036L -#define BA0_AC97_6CH_VOL_SURROUND 0x00001038L -#define BA0_AC97_RESERVED_3A 0x0000103AL -#define BA0_AC97_EXT_MODEM_ID 0x0000103CL -#define BA0_AC97_EXT_MODEM_POWER 0x0000103EL -#define BA0_AC97_LINE1_CODEC_RATE 0x00001040L -#define BA0_AC97_LINE2_CODEC_RATE 0x00001042L -#define BA0_AC97_HANDSET_CODEC_RATE 0x00001044L -#define BA0_AC97_LINE1_CODEC_LEVEL 0x00001046L -#define BA0_AC97_LINE2_CODEC_LEVEL 0x00001048L -#define BA0_AC97_HANDSET_CODEC_LEVEL 0x0000104AL -#define BA0_AC97_GPIO_PIN_CONFIG 0x0000104CL -#define BA0_AC97_GPIO_PIN_TYPE 0x0000104EL -#define BA0_AC97_GPIO_PIN_STICKY 0x00001050L -#define BA0_AC97_GPIO_PIN_WAKEUP 0x00001052L -#define BA0_AC97_GPIO_PIN_STATUS 0x00001054L -#define BA0_AC97_MISC_MODEM_AFE_STAT 0x00001056L -#define BA0_AC97_RESERVED_58 0x00001058L -#define BA0_AC97_CRYSTAL_REV_N_FAB_ID 0x0000105AL -#define BA0_AC97_TEST_AND_MISC_CTRL 0x0000105CL -#define BA0_AC97_AC_MODE 0x0000105EL -#define BA0_AC97_MISC_CRYSTAL_CONTROL 0x00001060L -#define BA0_AC97_LINE1_HYPRID_CTRL 0x00001062L -#define BA0_AC97_VENDOR_RESERVED_64 0x00001064L -#define BA0_AC97_VENDOR_RESERVED_66 0x00001066L -#define BA0_AC97_SPDIF_CONTROL 0x00001068L -#define BA0_AC97_VENDOR_RESERVED_6A 0x0000106AL -#define BA0_AC97_VENDOR_RESERVED_6C 0x0000106CL -#define BA0_AC97_VENDOR_RESERVED_6E 0x0000106EL -#define BA0_AC97_VENDOR_RESERVED_70 0x00001070L -#define BA0_AC97_VENDOR_RESERVED_72 0x00001072L -#define BA0_AC97_VENDOR_RESERVED_74 0x00001074L -#define BA0_AC97_CAL_ADDRESS 0x00001076L -#define BA0_AC97_CAL_DATA 0x00001078L -#define BA0_AC97_VENDOR_RESERVED_7A 0x0000107AL -#define BA0_AC97_VENDOR_ID1 0x0000107CL -#define BA0_AC97_VENDOR_ID2 0x0000107EL - -//**************************************************************************** -// -// The following define the offsets of the registers and memories accessed via -// base address register one on the CS4281 part. -// -//**************************************************************************** - -//**************************************************************************** -// -// The following defines are for the flags in the PCI device ID/vendor ID -// register. -// -//**************************************************************************** -#define PDV_VENID_MASK 0x0000FFFFL -#define PDV_DEVID_MASK 0xFFFF0000L -#define PDV_VENID_SHIFT 0L -#define PDV_DEVID_SHIFT 16L -#define VENID_CIRRUS_LOGIC 0x1013L -#define DEVID_CS4281 0x6005L - -//**************************************************************************** -// -// The following defines are for the flags in the PCI status and command -// register. -// -//**************************************************************************** -#define PSC_IO_SPACE_ENABLE 0x00000001L -#define PSC_MEMORY_SPACE_ENABLE 0x00000002L -#define PSC_BUS_MASTER_ENABLE 0x00000004L -#define PSC_SPECIAL_CYCLES 0x00000008L -#define PSC_MWI_ENABLE 0x00000010L -#define PSC_VGA_PALETTE_SNOOP 0x00000020L -#define PSC_PARITY_RESPONSE 0x00000040L -#define PSC_WAIT_CONTROL 0x00000080L -#define PSC_SERR_ENABLE 0x00000100L -#define PSC_FAST_B2B_ENABLE 0x00000200L -#define PSC_UDF_MASK 0x007F0000L -#define PSC_FAST_B2B_CAPABLE 0x00800000L -#define PSC_PARITY_ERROR_DETECTED 0x01000000L -#define PSC_DEVSEL_TIMING_MASK 0x06000000L -#define PSC_TARGET_ABORT_SIGNALLED 0x08000000L -#define PSC_RECEIVED_TARGET_ABORT 0x10000000L -#define PSC_RECEIVED_MASTER_ABORT 0x20000000L -#define PSC_SIGNALLED_SERR 0x40000000L -#define PSC_DETECTED_PARITY_ERROR 0x80000000L -#define PSC_UDF_SHIFT 16L -#define PSC_DEVSEL_TIMING_SHIFT 25L - -//**************************************************************************** -// -// The following defines are for the flags in the PCI class/revision ID -// register. -// -//**************************************************************************** -#define PCR_REVID_MASK 0x000000FFL -#define PCR_INTERFACE_MASK 0x0000FF00L -#define PCR_SUBCLASS_MASK 0x00FF0000L -#define PCR_CLASS_MASK 0xFF000000L -#define PCR_REVID_SHIFT 0L -#define PCR_INTERFACE_SHIFT 8L -#define PCR_SUBCLASS_SHIFT 16L -#define PCR_CLASS_SHIFT 24L - -//**************************************************************************** -// -// The following defines are for the flags in the PCI latency timer register. -// -//**************************************************************************** -#define PLT_CACHE_LINE_SIZE_MASK 0x000000FFL -#define PLT_LATENCY_TIMER_MASK 0x0000FF00L -#define PLT_HEADER_TYPE_MASK 0x00FF0000L -#define PLT_BIST_MASK 0xFF000000L -#define PLT_CACHE_LINE_SIZE_SHIFT 0L -#define PLT_LATENCY_TIMER_SHIFT 8L -#define PLT_HEADER_TYPE_SHIFT 16L -#define PLT_BIST_SHIFT 24L - -//**************************************************************************** -// -// The following defines are for the flags in the PCI base address registers. -// -//**************************************************************************** -#define PBAR_MEMORY_SPACE_INDICATOR 0x00000001L -#define PBAR_LOCATION_TYPE_MASK 0x00000006L -#define PBAR_NOT_PREFETCHABLE 0x00000008L -#define PBAR_ADDRESS_MASK 0xFFFFFFF0L -#define PBAR_LOCATION_TYPE_SHIFT 1L - -//**************************************************************************** -// -// The following defines are for the flags in the PCI subsystem ID/subsystem -// vendor ID register. -// -//**************************************************************************** -#define PSS_SUBSYSTEM_VENDOR_ID_MASK 0x0000FFFFL -#define PSS_SUBSYSTEM_ID_MASK 0xFFFF0000L -#define PSS_SUBSYSTEM_VENDOR_ID_SHIFT 0L -#define PSS_SUBSYSTEM_ID_SHIFT 16L - -//**************************************************************************** -// -// The following defines are for the flags in the PCI interrupt register. -// -//**************************************************************************** -#define PI_LINE_MASK 0x000000FFL -#define PI_PIN_MASK 0x0000FF00L -#define PI_MIN_GRANT_MASK 0x00FF0000L -#define PI_MAX_LATENCY_MASK 0xFF000000L -#define PI_LINE_SHIFT 0L -#define PI_PIN_SHIFT 8L -#define PI_MIN_GRANT_SHIFT 16L -#define PI_MAX_LATENCY_SHIFT 24L - -//**************************************************************************** -// -// The following defines are for the flags in the host interrupt status -// register. -// -//**************************************************************************** -#define HISR_HVOLMASK 0x00000003L -#define HISR_VDNI 0x00000001L -#define HISR_VUPI 0x00000002L -#define HISR_GP1I 0x00000004L -#define HISR_GP3I 0x00000008L -#define HISR_GPSI 0x00000010L -#define HISR_GPPI 0x00000020L -#define HISR_DMAI 0x00040000L -#define HISR_FIFOI 0x00100000L -#define HISR_HVOL 0x00200000L -#define HISR_MIDI 0x00400000L -#define HISR_SBINT 0x00800000L -#define HISR_INTENA 0x80000000L -#define HISR_DMA_MASK 0x00000F00L -#define HISR_FIFO_MASK 0x0000F000L -#define HISR_DMA_SHIFT 8L -#define HISR_FIFO_SHIFT 12L -#define HISR_FIFO0 0x00001000L -#define HISR_FIFO1 0x00002000L -#define HISR_FIFO2 0x00004000L -#define HISR_FIFO3 0x00008000L -#define HISR_DMA0 0x00000100L -#define HISR_DMA1 0x00000200L -#define HISR_DMA2 0x00000400L -#define HISR_DMA3 0x00000800L -#define HISR_RESERVED 0x40000000L - -//**************************************************************************** -// -// The following defines are for the flags in the host interrupt control -// register. -// -//**************************************************************************** -#define HICR_IEV 0x00000001L -#define HICR_CHGM 0x00000002L - -//**************************************************************************** -// -// The following defines are for the flags in the DMA Mode Register n -// (DMRn) -// -//**************************************************************************** -#define DMRn_TR_MASK 0x0000000CL -#define DMRn_TR_SHIFT 2L -#define DMRn_AUTO 0x00000010L -#define DMRn_TR_READ 0x00000008L -#define DMRn_TR_WRITE 0x00000004L -#define DMRn_TYPE_MASK 0x000000C0L -#define DMRn_TYPE_SHIFT 6L -#define DMRn_SIZE8 0x00010000L -#define DMRn_MONO 0x00020000L -#define DMRn_BEND 0x00040000L -#define DMRn_USIGN 0x00080000L -#define DMRn_SIZE20 0x00100000L -#define DMRn_SWAPC 0x00400000L -#define DMRn_CBC 0x01000000L -#define DMRn_TBC 0x02000000L -#define DMRn_POLL 0x10000000L -#define DMRn_DMA 0x20000000L -#define DMRn_FSEL_MASK 0xC0000000L -#define DMRn_FSEL_SHIFT 30L -#define DMRn_FSEL0 0x00000000L -#define DMRn_FSEL1 0x40000000L -#define DMRn_FSEL2 0x80000000L -#define DMRn_FSEL3 0xC0000000L - -//**************************************************************************** -// -// The following defines are for the flags in the DMA Command Register n -// (DCRn) -// -//**************************************************************************** -#define DCRn_HTCIE 0x00020000L -#define DCRn_TCIE 0x00010000L -#define DCRn_MSK 0x00000001L - -//**************************************************************************** -// -// The following defines are for the flags in the FIFO Control -// register n.(FCRn) -// -//**************************************************************************** -#define FCRn_OF_MASK 0x0000007FL -#define FCRn_OF_SHIFT 0L -#define FCRn_SZ_MASK 0x00007F00L -#define FCRn_SZ_SHIFT 8L -#define FCRn_LS_MASK 0x001F0000L -#define FCRn_LS_SHIFT 16L -#define FCRn_RS_MASK 0x1F000000L -#define FCRn_RS_SHIFT 24L -#define FCRn_FEN 0x80000000L -#define FCRn_PSH 0x20000000L -#define FCRn_DACZ 0x40000000L - -//**************************************************************************** -// -// The following defines are for the flags in the serial port Power Management -// control register.(SPMC) -// -//**************************************************************************** -#define SPMC_RSTN 0x00000001L -#define SPMC_ASYN 0x00000002L -#define SPMC_WUP1 0x00000004L -#define SPMC_WUP2 0x00000008L -#define SPMC_ASDI2E 0x00000100L -#define SPMC_ESSPD 0x00000200L -#define SPMC_GISPEN 0x00004000L -#define SPMC_GIPPEN 0x00008000L - -//**************************************************************************** -// -// The following defines are for the flags in the Configuration Load register. -// (CFLR) -// -//**************************************************************************** -#define CFLR_CLOCK_SOURCE_MASK 0x00000003L -#define CFLR_CLOCK_SOURCE_AC97 0x00000001L - -#define CFLR_CB0_MASK 0x000000FFL -#define CFLR_CB1_MASK 0x0000FF00L -#define CFLR_CB2_MASK 0x00FF0000L -#define CFLR_CB3_MASK 0xFF000000L -#define CFLR_CB0_SHIFT 0L -#define CFLR_CB1_SHIFT 8L -#define CFLR_CB2_SHIFT 16L -#define CFLR_CB3_SHIFT 24L - -#define IOTCR_DMA0 0x00000000L -#define IOTCR_DMA1 0x00000400L -#define IOTCR_DMA2 0x00000800L -#define IOTCR_DMA3 0x00000C00L -#define IOTCR_CCLS 0x00000100L -#define IOTCR_PCPCI 0x00000200L -#define IOTCR_DDMA 0x00000300L - -#define SBWBS_WBB 0x00000080L - -//**************************************************************************** -// -// The following defines are for the flags in the SRC Slot Assignment Register -// (SRCSA) -// -//**************************************************************************** -#define SRCSA_PLSS_MASK 0x0000001FL -#define SRCSA_PLSS_SHIFT 0L -#define SRCSA_PRSS_MASK 0x00001F00L -#define SRCSA_PRSS_SHIFT 8L -#define SRCSA_CLSS_MASK 0x001F0000L -#define SRCSA_CLSS_SHIFT 16L -#define SRCSA_CRSS_MASK 0x1F000000L -#define SRCSA_CRSS_SHIFT 24L - -//**************************************************************************** -// -// The following defines are for the flags in the Sound System Power Management -// register.(SSPM) -// -//**************************************************************************** -#define SSPM_FPDN 0x00000080L -#define SSPM_MIXEN 0x00000040L -#define SSPM_CSRCEN 0x00000020L -#define SSPM_PSRCEN 0x00000010L -#define SSPM_JSEN 0x00000008L -#define SSPM_ACLEN 0x00000004L -#define SSPM_FMEN 0x00000002L - -//**************************************************************************** -// -// The following defines are for the flags in the Sound System Control -// Register. (SSCR) -// -//**************************************************************************** -#define SSCR_SB 0x00000004L -#define SSCR_HVC 0x00000008L -#define SSCR_LPFIFO 0x00000040L -#define SSCR_LPSRC 0x00000080L -#define SSCR_XLPSRC 0x00000100L -#define SSCR_MVMD 0x00010000L -#define SSCR_MVAD 0x00020000L -#define SSCR_MVLD 0x00040000L -#define SSCR_MVCS 0x00080000L - -//**************************************************************************** -// -// The following defines are for the flags in the Clock Control Register 1. -// (CLKCR1) -// -//**************************************************************************** -#define CLKCR1_DLLSS_MASK 0x0000000CL -#define CLKCR1_DLLSS_SHIFT 2L -#define CLKCR1_DLLP 0x00000010L -#define CLKCR1_SWCE 0x00000020L -#define CLKCR1_DLLOS 0x00000040L -#define CLKCR1_CKRA 0x00010000L -#define CLKCR1_CKRN 0x00020000L -#define CLKCR1_DLLRDY 0x01000000L -#define CLKCR1_CLKON 0x02000000L - -//**************************************************************************** -// -// The following defines are for the flags in the Sound Blaster Read Buffer -// Status.(SBRBS) -// -//**************************************************************************** -#define SBRBS_RD_MASK 0x0000007FL -#define SBRBS_RD_SHIFT 0L -#define SBRBS_RBF 0x00000080L - -//**************************************************************************** -// -// The following defines are for the flags in the serial port master control -// register.(SERMC) -// -//**************************************************************************** -#define SERMC_MSPE 0x00000001L -#define SERMC_PTC_MASK 0x0000000EL -#define SERMC_PTC_SHIFT 1L -#define SERMC_PTC_AC97 0x00000002L -#define SERMC_PLB 0x00000010L -#define SERMC_PXLB 0x00000020L -#define SERMC_LOFV 0x00080000L -#define SERMC_SLB 0x00100000L -#define SERMC_SXLB 0x00200000L -#define SERMC_ODSEN1 0x01000000L -#define SERMC_ODSEN2 0x02000000L - -//**************************************************************************** -// -// The following defines are for the flags in the General Purpose I/O Register. -// (GPIOR) -// -//**************************************************************************** -#define GPIOR_VDNS 0x00000001L -#define GPIOR_VUPS 0x00000002L -#define GPIOR_GP1S 0x00000004L -#define GPIOR_GP3S 0x00000008L -#define GPIOR_GPSS 0x00000010L -#define GPIOR_GPPS 0x00000020L -#define GPIOR_GP1D 0x00000400L -#define GPIOR_GP3D 0x00000800L -#define GPIOR_VDNLT 0x00010000L -#define GPIOR_VDNPO 0x00020000L -#define GPIOR_VDNST 0x00040000L -#define GPIOR_VDNW 0x00080000L -#define GPIOR_VUPLT 0x00100000L -#define GPIOR_VUPPO 0x00200000L -#define GPIOR_VUPST 0x00400000L -#define GPIOR_VUPW 0x00800000L -#define GPIOR_GP1OE 0x01000000L -#define GPIOR_GP1PT 0x02000000L -#define GPIOR_GP1ST 0x04000000L -#define GPIOR_GP1W 0x08000000L -#define GPIOR_GP3OE 0x10000000L -#define GPIOR_GP3PT 0x20000000L -#define GPIOR_GP3ST 0x40000000L -#define GPIOR_GP3W 0x80000000L - -//**************************************************************************** -// -// The following defines are for the flags in the clock control register 1. -// -//**************************************************************************** -#define CLKCR1_PLLSS_MASK 0x0000000CL -#define CLKCR1_PLLSS_SERIAL 0x00000000L -#define CLKCR1_PLLSS_CRYSTAL 0x00000004L -#define CLKCR1_PLLSS_PCI 0x00000008L -#define CLKCR1_PLLSS_RESERVED 0x0000000CL -#define CLKCR1_PLLP 0x00000010L -#define CLKCR1_SWCE 0x00000020L -#define CLKCR1_PLLOS 0x00000040L - -//**************************************************************************** -// -// The following defines are for the flags in the feature reporting register. -// -//**************************************************************************** -#define FRR_FAB_MASK 0x00000003L -#define FRR_MASK_MASK 0x0000001CL -#define FRR_ID_MASK 0x00003000L -#define FRR_FAB_SHIFT 0L -#define FRR_MASK_SHIFT 2L -#define FRR_ID_SHIFT 12L - -//**************************************************************************** -// -// The following defines are for the flags in the serial port 1 configuration -// register. -// -//**************************************************************************** -#define SERC1_VALUE 0x00000003L -#define SERC1_SO1EN 0x00000001L -#define SERC1_SO1F_MASK 0x0000000EL -#define SERC1_SO1F_CS423X 0x00000000L -#define SERC1_SO1F_AC97 0x00000002L -#define SERC1_SO1F_DAC 0x00000004L -#define SERC1_SO1F_SPDIF 0x00000006L - -//**************************************************************************** -// -// The following defines are for the flags in the serial port 2 configuration -// register. -// -//**************************************************************************** -#define SERC2_VALUE 0x00000003L -#define SERC2_SI1EN 0x00000001L -#define SERC2_SI1F_MASK 0x0000000EL -#define SERC2_SI1F_CS423X 0x00000000L -#define SERC2_SI1F_AC97 0x00000002L -#define SERC2_SI1F_ADC 0x00000004L -#define SERC2_SI1F_SPDIF 0x00000006L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 control register. -// -//**************************************************************************** -#define ACCTL_ESYN 0x00000002L -#define ACCTL_VFRM 0x00000004L -#define ACCTL_DCV 0x00000008L -#define ACCTL_CRW 0x00000010L -#define ACCTL_TC 0x00000040L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 status register. -// -//**************************************************************************** -#define ACSTS_CRDY 0x00000001L -#define ACSTS_VSTS 0x00000002L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 output slot valid -// register. -// -//**************************************************************************** -#define ACOSV_SLV3 0x00000001L -#define ACOSV_SLV4 0x00000002L -#define ACOSV_SLV5 0x00000004L -#define ACOSV_SLV6 0x00000008L -#define ACOSV_SLV7 0x00000010L -#define ACOSV_SLV8 0x00000020L -#define ACOSV_SLV9 0x00000040L -#define ACOSV_SLV10 0x00000080L -#define ACOSV_SLV11 0x00000100L -#define ACOSV_SLV12 0x00000200L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 command address -// register. -// -//**************************************************************************** -#define ACCAD_CI_MASK 0x0000007FL -#define ACCAD_CI_SHIFT 0L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 command data register. -// -//**************************************************************************** -#define ACCDA_CD_MASK 0x0000FFFFL -#define ACCDA_CD_SHIFT 0L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 input slot valid -// register. -// -//**************************************************************************** -#define ACISV_ISV3 0x00000001L -#define ACISV_ISV4 0x00000002L -#define ACISV_ISV5 0x00000004L -#define ACISV_ISV6 0x00000008L -#define ACISV_ISV7 0x00000010L -#define ACISV_ISV8 0x00000020L -#define ACISV_ISV9 0x00000040L -#define ACISV_ISV10 0x00000080L -#define ACISV_ISV11 0x00000100L -#define ACISV_ISV12 0x00000200L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 status address -// register. -// -//**************************************************************************** -#define ACSAD_SI_MASK 0x0000007FL -#define ACSAD_SI_SHIFT 0L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 status data register. -// -//**************************************************************************** -#define ACSDA_SD_MASK 0x0000FFFFL -#define ACSDA_SD_SHIFT 0L - -//**************************************************************************** -// -// The following defines are for the flags in the I/O trap address and control -// registers (all 12). -// -//**************************************************************************** -#define IOTAC_SA_MASK 0x0000FFFFL -#define IOTAC_MSK_MASK 0x000F0000L -#define IOTAC_IODC_MASK 0x06000000L -#define IOTAC_IODC_16_BIT 0x00000000L -#define IOTAC_IODC_10_BIT 0x02000000L -#define IOTAC_IODC_12_BIT 0x04000000L -#define IOTAC_WSPI 0x08000000L -#define IOTAC_RSPI 0x10000000L -#define IOTAC_WSE 0x20000000L -#define IOTAC_WE 0x40000000L -#define IOTAC_RE 0x80000000L -#define IOTAC_SA_SHIFT 0L -#define IOTAC_MSK_SHIFT 16L - -//**************************************************************************** -// -// The following defines are for the flags in the PC/PCI master enable -// register. -// -//**************************************************************************** -#define PCPCIEN_EN 0x00000001L - -//**************************************************************************** -// -// The following defines are for the flags in the joystick poll/trigger -// register. -// -//**************************************************************************** -#define JSPT_CAX 0x00000001L -#define JSPT_CAY 0x00000002L -#define JSPT_CBX 0x00000004L -#define JSPT_CBY 0x00000008L -#define JSPT_BA1 0x00000010L -#define JSPT_BA2 0x00000020L -#define JSPT_BB1 0x00000040L -#define JSPT_BB2 0x00000080L - -//**************************************************************************** -// -// The following defines are for the flags in the joystick control register. -// The TBF bit has been moved from MIDSR register to JSCTL register bit 8. -// -//**************************************************************************** -#define JSCTL_SP_MASK 0x00000003L -#define JSCTL_SP_SLOW 0x00000000L -#define JSCTL_SP_MEDIUM_SLOW 0x00000001L -#define JSCTL_SP_MEDIUM_FAST 0x00000002L -#define JSCTL_SP_FAST 0x00000003L -#define JSCTL_ARE 0x00000004L -#define JSCTL_TBF 0x00000100L - - -//**************************************************************************** -// -// The following defines are for the flags in the MIDI control register. -// -//**************************************************************************** -#define MIDCR_TXE 0x00000001L -#define MIDCR_RXE 0x00000002L -#define MIDCR_RIE 0x00000004L -#define MIDCR_TIE 0x00000008L -#define MIDCR_MLB 0x00000010L -#define MIDCR_MRST 0x00000020L - -//**************************************************************************** -// -// The following defines are for the flags in the MIDI status register. -// -//**************************************************************************** -#define MIDSR_RBE 0x00000080L -#define MIDSR_RDA 0x00008000L - -//**************************************************************************** -// -// The following defines are for the flags in the MIDI write port register. -// -//**************************************************************************** -#define MIDWP_MWD_MASK 0x000000FFL -#define MIDWP_MWD_SHIFT 0L - -//**************************************************************************** -// -// The following defines are for the flags in the MIDI read port register. -// -//**************************************************************************** -#define MIDRP_MRD_MASK 0x000000FFL -#define MIDRP_MRD_SHIFT 0L - -//**************************************************************************** -// -// The following defines are for the flags in the configuration interface -// register. -// -//**************************************************************************** -#define CFGI_CLK 0x00000001L -#define CFGI_DOUT 0x00000002L -#define CFGI_DIN_EEN 0x00000004L -#define CFGI_EELD 0x00000008L - -//**************************************************************************** -// -// The following defines are for the flags in the subsystem ID and vendor ID -// register. -// -//**************************************************************************** -#define SSVID_VID_MASK 0x0000FFFFL -#define SSVID_SID_MASK 0xFFFF0000L -#define SSVID_VID_SHIFT 0L -#define SSVID_SID_SHIFT 16L - -//**************************************************************************** -// -// The following defines are for the flags in the GPIO pin interface register. -// -//**************************************************************************** -#define GPIOR_VOLDN 0x00000001L -#define GPIOR_VOLUP 0x00000002L -#define GPIOR_SI2D 0x00000004L -#define GPIOR_SI2OE 0x00000008L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 status register 2. -// -//**************************************************************************** -#define ACSTS2_CRDY 0x00000001L -#define ACSTS2_VSTS 0x00000002L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 input slot valid -// register 2. -// -//**************************************************************************** -#define ACISV2_ISV3 0x00000001L -#define ACISV2_ISV4 0x00000002L -#define ACISV2_ISV5 0x00000004L -#define ACISV2_ISV6 0x00000008L -#define ACISV2_ISV7 0x00000010L -#define ACISV2_ISV8 0x00000020L -#define ACISV2_ISV9 0x00000040L -#define ACISV2_ISV10 0x00000080L -#define ACISV2_ISV11 0x00000100L -#define ACISV2_ISV12 0x00000200L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 status address -// register 2. -// -//**************************************************************************** -#define ACSAD2_SI_MASK 0x0000007FL -#define ACSAD2_SI_SHIFT 0L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 status data register 2. -// -//**************************************************************************** -#define ACSDA2_SD_MASK 0x0000FFFFL -#define ACSDA2_SD_SHIFT 0L - -//**************************************************************************** -// -// The following defines are for the flags in the I/O trap control register. -// -//**************************************************************************** -#define IOTCR_ITD 0x00000001L -#define IOTCR_HRV 0x00000002L -#define IOTCR_SRV 0x00000004L -#define IOTCR_DTI 0x00000008L -#define IOTCR_DFI 0x00000010L -#define IOTCR_DDP 0x00000020L -#define IOTCR_JTE 0x00000040L -#define IOTCR_PPE 0x00000080L - -//**************************************************************************** -// -// The following defines are for the flags in the I/O trap address and control -// registers for Hardware Master Volume. -// -//**************************************************************************** -#define IOTGP_SA_MASK 0x0000FFFFL -#define IOTGP_MSK_MASK 0x000F0000L -#define IOTGP_IODC_MASK 0x06000000L -#define IOTGP_IODC_16_BIT 0x00000000L -#define IOTGP_IODC_10_BIT 0x02000000L -#define IOTGP_IODC_12_BIT 0x04000000L -#define IOTGP_WSPI 0x08000000L -#define IOTGP_RSPI 0x10000000L -#define IOTGP_WSE 0x20000000L -#define IOTGP_WE 0x40000000L -#define IOTGP_RE 0x80000000L -#define IOTGP_SA_SHIFT 0L -#define IOTGP_MSK_SHIFT 16L - -//**************************************************************************** -// -// The following defines are for the flags in the I/O trap address and control -// registers for Sound Blaster -// -//**************************************************************************** -#define IOTSB_SA_MASK 0x0000FFFFL -#define IOTSB_MSK_MASK 0x000F0000L -#define IOTSB_IODC_MASK 0x06000000L -#define IOTSB_IODC_16_BIT 0x00000000L -#define IOTSB_IODC_10_BIT 0x02000000L -#define IOTSB_IODC_12_BIT 0x04000000L -#define IOTSB_WSPI 0x08000000L -#define IOTSB_RSPI 0x10000000L -#define IOTSB_WSE 0x20000000L -#define IOTSB_WE 0x40000000L -#define IOTSB_RE 0x80000000L -#define IOTSB_SA_SHIFT 0L -#define IOTSB_MSK_SHIFT 16L - -//**************************************************************************** -// -// The following defines are for the flags in the I/O trap address and control -// registers for FM. -// -//**************************************************************************** -#define IOTFM_SA_MASK 0x0000FFFFL -#define IOTFM_MSK_MASK 0x000F0000L -#define IOTFM_IODC_MASK 0x06000000L -#define IOTFM_IODC_16_BIT 0x00000000L -#define IOTFM_IODC_10_BIT 0x02000000L -#define IOTFM_IODC_12_BIT 0x04000000L -#define IOTFM_WSPI 0x08000000L -#define IOTFM_RSPI 0x10000000L -#define IOTFM_WSE 0x20000000L -#define IOTFM_WE 0x40000000L -#define IOTFM_RE 0x80000000L -#define IOTFM_SA_SHIFT 0L -#define IOTFM_MSK_SHIFT 16L - -//**************************************************************************** -// -// The following defines are for the flags in the PC/PCI request register. -// -//**************************************************************************** -#define PCPRR_RDC_MASK 0x00000007L -#define PCPRR_REQ 0x00008000L -#define PCPRR_RDC_SHIFT 0L - -//**************************************************************************** -// -// The following defines are for the flags in the PC/PCI grant register. -// -//**************************************************************************** -#define PCPGR_GDC_MASK 0x00000007L -#define PCPGR_VL 0x00008000L -#define PCPGR_GDC_SHIFT 0L - -//**************************************************************************** -// -// The following defines are for the flags in the PC/PCI Control Register. -// -//**************************************************************************** -#define PCPCR_EN 0x00000001L - -//**************************************************************************** -// -// The following defines are for the flags in the debug index register. -// -//**************************************************************************** -#define DREG_REGID_MASK 0x0000007FL -#define DREG_DEBUG 0x00000080L -#define DREG_RGBK_MASK 0x00000700L -#define DREG_TRAP 0x00000800L -#if !defined(NO_CS4612) -#if !defined(NO_CS4615) -#define DREG_TRAPX 0x00001000L -#endif -#endif -#define DREG_REGID_SHIFT 0L -#define DREG_RGBK_SHIFT 8L -#define DREG_RGBK_REGID_MASK 0x0000077FL -#define DREG_REGID_R0 0x00000010L -#define DREG_REGID_R1 0x00000011L -#define DREG_REGID_R2 0x00000012L -#define DREG_REGID_R3 0x00000013L -#define DREG_REGID_R4 0x00000014L -#define DREG_REGID_R5 0x00000015L -#define DREG_REGID_R6 0x00000016L -#define DREG_REGID_R7 0x00000017L -#define DREG_REGID_R8 0x00000018L -#define DREG_REGID_R9 0x00000019L -#define DREG_REGID_RA 0x0000001AL -#define DREG_REGID_RB 0x0000001BL -#define DREG_REGID_RC 0x0000001CL -#define DREG_REGID_RD 0x0000001DL -#define DREG_REGID_RE 0x0000001EL -#define DREG_REGID_RF 0x0000001FL -#define DREG_REGID_RA_BUS_LOW 0x00000020L -#define DREG_REGID_RA_BUS_HIGH 0x00000038L -#define DREG_REGID_YBUS_LOW 0x00000050L -#define DREG_REGID_YBUS_HIGH 0x00000058L -#define DREG_REGID_TRAP_0 0x00000100L -#define DREG_REGID_TRAP_1 0x00000101L -#define DREG_REGID_TRAP_2 0x00000102L -#define DREG_REGID_TRAP_3 0x00000103L -#define DREG_REGID_TRAP_4 0x00000104L -#define DREG_REGID_TRAP_5 0x00000105L -#define DREG_REGID_TRAP_6 0x00000106L -#define DREG_REGID_TRAP_7 0x00000107L -#define DREG_REGID_INDIRECT_ADDRESS 0x0000010EL -#define DREG_REGID_TOP_OF_STACK 0x0000010FL -#if !defined(NO_CS4612) -#if !defined(NO_CS4615) -#define DREG_REGID_TRAP_8 0x00000110L -#define DREG_REGID_TRAP_9 0x00000111L -#define DREG_REGID_TRAP_10 0x00000112L -#define DREG_REGID_TRAP_11 0x00000113L -#define DREG_REGID_TRAP_12 0x00000114L -#define DREG_REGID_TRAP_13 0x00000115L -#define DREG_REGID_TRAP_14 0x00000116L -#define DREG_REGID_TRAP_15 0x00000117L -#define DREG_REGID_TRAP_16 0x00000118L -#define DREG_REGID_TRAP_17 0x00000119L -#define DREG_REGID_TRAP_18 0x0000011AL -#define DREG_REGID_TRAP_19 0x0000011BL -#define DREG_REGID_TRAP_20 0x0000011CL -#define DREG_REGID_TRAP_21 0x0000011DL -#define DREG_REGID_TRAP_22 0x0000011EL -#define DREG_REGID_TRAP_23 0x0000011FL -#endif -#endif -#define DREG_REGID_RSA0_LOW 0x00000200L -#define DREG_REGID_RSA0_HIGH 0x00000201L -#define DREG_REGID_RSA1_LOW 0x00000202L -#define DREG_REGID_RSA1_HIGH 0x00000203L -#define DREG_REGID_RSA2 0x00000204L -#define DREG_REGID_RSA3 0x00000205L -#define DREG_REGID_RSI0_LOW 0x00000206L -#define DREG_REGID_RSI0_HIGH 0x00000207L -#define DREG_REGID_RSI1 0x00000208L -#define DREG_REGID_RSI2 0x00000209L -#define DREG_REGID_SAGUSTATUS 0x0000020AL -#define DREG_REGID_RSCONFIG01_LOW 0x0000020BL -#define DREG_REGID_RSCONFIG01_HIGH 0x0000020CL -#define DREG_REGID_RSCONFIG23_LOW 0x0000020DL -#define DREG_REGID_RSCONFIG23_HIGH 0x0000020EL -#define DREG_REGID_RSDMA01E 0x0000020FL -#define DREG_REGID_RSDMA23E 0x00000210L -#define DREG_REGID_RSD0_LOW 0x00000211L -#define DREG_REGID_RSD0_HIGH 0x00000212L -#define DREG_REGID_RSD1_LOW 0x00000213L -#define DREG_REGID_RSD1_HIGH 0x00000214L -#define DREG_REGID_RSD2_LOW 0x00000215L -#define DREG_REGID_RSD2_HIGH 0x00000216L -#define DREG_REGID_RSD3_LOW 0x00000217L -#define DREG_REGID_RSD3_HIGH 0x00000218L -#define DREG_REGID_SRAR_HIGH 0x0000021AL -#define DREG_REGID_SRAR_LOW 0x0000021BL -#define DREG_REGID_DMA_STATE 0x0000021CL -#define DREG_REGID_CURRENT_DMA_STREAM 0x0000021DL -#define DREG_REGID_NEXT_DMA_STREAM 0x0000021EL -#define DREG_REGID_CPU_STATUS 0x00000300L -#define DREG_REGID_MAC_MODE 0x00000301L -#define DREG_REGID_STACK_AND_REPEAT 0x00000302L -#define DREG_REGID_INDEX0 0x00000304L -#define DREG_REGID_INDEX1 0x00000305L -#define DREG_REGID_DMA_STATE_0_3 0x00000400L -#define DREG_REGID_DMA_STATE_4_7 0x00000404L -#define DREG_REGID_DMA_STATE_8_11 0x00000408L -#define DREG_REGID_DMA_STATE_12_15 0x0000040CL -#define DREG_REGID_DMA_STATE_16_19 0x00000410L -#define DREG_REGID_DMA_STATE_20_23 0x00000414L -#define DREG_REGID_DMA_STATE_24_27 0x00000418L -#define DREG_REGID_DMA_STATE_28_31 0x0000041CL -#define DREG_REGID_DMA_STATE_32_35 0x00000420L -#define DREG_REGID_DMA_STATE_36_39 0x00000424L -#define DREG_REGID_DMA_STATE_40_43 0x00000428L -#define DREG_REGID_DMA_STATE_44_47 0x0000042CL -#define DREG_REGID_DMA_STATE_48_51 0x00000430L -#define DREG_REGID_DMA_STATE_52_55 0x00000434L -#define DREG_REGID_DMA_STATE_56_59 0x00000438L -#define DREG_REGID_DMA_STATE_60_63 0x0000043CL -#define DREG_REGID_DMA_STATE_64_67 0x00000440L -#define DREG_REGID_DMA_STATE_68_71 0x00000444L -#define DREG_REGID_DMA_STATE_72_75 0x00000448L -#define DREG_REGID_DMA_STATE_76_79 0x0000044CL -#define DREG_REGID_DMA_STATE_80_83 0x00000450L -#define DREG_REGID_DMA_STATE_84_87 0x00000454L -#define DREG_REGID_DMA_STATE_88_91 0x00000458L -#define DREG_REGID_DMA_STATE_92_95 0x0000045CL -#define DREG_REGID_TRAP_SELECT 0x00000500L -#define DREG_REGID_TRAP_WRITE_0 0x00000500L -#define DREG_REGID_TRAP_WRITE_1 0x00000501L -#define DREG_REGID_TRAP_WRITE_2 0x00000502L -#define DREG_REGID_TRAP_WRITE_3 0x00000503L -#define DREG_REGID_TRAP_WRITE_4 0x00000504L -#define DREG_REGID_TRAP_WRITE_5 0x00000505L -#define DREG_REGID_TRAP_WRITE_6 0x00000506L -#define DREG_REGID_TRAP_WRITE_7 0x00000507L -#if !defined(NO_CS4612) -#if !defined(NO_CS4615) -#define DREG_REGID_TRAP_WRITE_8 0x00000510L -#define DREG_REGID_TRAP_WRITE_9 0x00000511L -#define DREG_REGID_TRAP_WRITE_10 0x00000512L -#define DREG_REGID_TRAP_WRITE_11 0x00000513L -#define DREG_REGID_TRAP_WRITE_12 0x00000514L -#define DREG_REGID_TRAP_WRITE_13 0x00000515L -#define DREG_REGID_TRAP_WRITE_14 0x00000516L -#define DREG_REGID_TRAP_WRITE_15 0x00000517L -#define DREG_REGID_TRAP_WRITE_16 0x00000518L -#define DREG_REGID_TRAP_WRITE_17 0x00000519L -#define DREG_REGID_TRAP_WRITE_18 0x0000051AL -#define DREG_REGID_TRAP_WRITE_19 0x0000051BL -#define DREG_REGID_TRAP_WRITE_20 0x0000051CL -#define DREG_REGID_TRAP_WRITE_21 0x0000051DL -#define DREG_REGID_TRAP_WRITE_22 0x0000051EL -#define DREG_REGID_TRAP_WRITE_23 0x0000051FL -#endif -#endif -#define DREG_REGID_MAC0_ACC0_LOW 0x00000600L -#define DREG_REGID_MAC0_ACC1_LOW 0x00000601L -#define DREG_REGID_MAC0_ACC2_LOW 0x00000602L -#define DREG_REGID_MAC0_ACC3_LOW 0x00000603L -#define DREG_REGID_MAC1_ACC0_LOW 0x00000604L -#define DREG_REGID_MAC1_ACC1_LOW 0x00000605L -#define DREG_REGID_MAC1_ACC2_LOW 0x00000606L -#define DREG_REGID_MAC1_ACC3_LOW 0x00000607L -#define DREG_REGID_MAC0_ACC0_MID 0x00000608L -#define DREG_REGID_MAC0_ACC1_MID 0x00000609L -#define DREG_REGID_MAC0_ACC2_MID 0x0000060AL -#define DREG_REGID_MAC0_ACC3_MID 0x0000060BL -#define DREG_REGID_MAC1_ACC0_MID 0x0000060CL -#define DREG_REGID_MAC1_ACC1_MID 0x0000060DL -#define DREG_REGID_MAC1_ACC2_MID 0x0000060EL -#define DREG_REGID_MAC1_ACC3_MID 0x0000060FL -#define DREG_REGID_MAC0_ACC0_HIGH 0x00000610L -#define DREG_REGID_MAC0_ACC1_HIGH 0x00000611L -#define DREG_REGID_MAC0_ACC2_HIGH 0x00000612L -#define DREG_REGID_MAC0_ACC3_HIGH 0x00000613L -#define DREG_REGID_MAC1_ACC0_HIGH 0x00000614L -#define DREG_REGID_MAC1_ACC1_HIGH 0x00000615L -#define DREG_REGID_MAC1_ACC2_HIGH 0x00000616L -#define DREG_REGID_MAC1_ACC3_HIGH 0x00000617L -#define DREG_REGID_RSHOUT_LOW 0x00000620L -#define DREG_REGID_RSHOUT_MID 0x00000628L -#define DREG_REGID_RSHOUT_HIGH 0x00000630L - -//**************************************************************************** -// -// The following defines are for the flags in the AC97 S/PDIF Control register. -// -//**************************************************************************** -#define SPDIF_CONTROL_SPDIF_EN 0x00008000L -#define SPDIF_CONTROL_VAL 0x00004000L -#define SPDIF_CONTROL_COPY 0x00000004L -#define SPDIF_CONTROL_CC0 0x00000010L -#define SPDIF_CONTROL_CC1 0x00000020L -#define SPDIF_CONTROL_CC2 0x00000040L -#define SPDIF_CONTROL_CC3 0x00000080L -#define SPDIF_CONTROL_CC4 0x00000100L -#define SPDIF_CONTROL_CC5 0x00000200L -#define SPDIF_CONTROL_CC6 0x00000400L -#define SPDIF_CONTROL_L 0x00000800L - -#endif // _H_HWDEFS diff --git a/sound/oss/cs4281/cs4281_wrapper-24.c b/sound/oss/cs4281/cs4281_wrapper-24.c deleted file mode 100644 index 4559f02c9969..000000000000 --- a/sound/oss/cs4281/cs4281_wrapper-24.c +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* -* -* "cs4281_wrapper.c" -- Cirrus Logic-Crystal CS4281 linux audio driver. -* -* Copyright (C) 2000,2001 Cirrus Logic Corp. -* -- tom woller (twoller@crystal.cirrus.com) or -* (audio@crystal.cirrus.com). -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* 12/20/00 trw - new file. -* -*******************************************************************************/ - -#include - -static int cs4281_resume_null(struct pci_dev *pcidev) { return 0; } -static int cs4281_suspend_null(struct pci_dev *pcidev, pm_message_t state) { return 0; } - -#define free_dmabuf(state, dmabuf) \ - pci_free_consistent(state->pcidev, \ - PAGE_SIZE << (dmabuf)->buforder, \ - (dmabuf)->rawbuf, (dmabuf)->dmaaddr); -#define free_dmabuf2(state, dmabuf) \ - pci_free_consistent((state)->pcidev, \ - PAGE_SIZE << (state)->buforder_tmpbuff, \ - (state)->tmpbuff, (state)->dmaaddr_tmpbuff); -#define cs4x_pgoff(vma) ((vma)->vm_pgoff) - diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c deleted file mode 100644 index 0400a416dc93..000000000000 --- a/sound/oss/cs4281/cs4281m.c +++ /dev/null @@ -1,4487 +0,0 @@ -/******************************************************************************* -* -* "cs4281.c" -- Cirrus Logic-Crystal CS4281 linux audio driver. -* -* Copyright (C) 2000,2001 Cirrus Logic Corp. -* -- adapted from drivers by Thomas Sailer, -* -- but don't bug him; Problems should go to: -* -- tom woller (twoller@crystal.cirrus.com) or -* (audio@crystal.cirrus.com). -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* Module command line parameters: -* none -* -* Supported devices: -* /dev/dsp standard /dev/dsp device, (mostly) OSS compatible -* /dev/mixer standard /dev/mixer device, (mostly) OSS compatible -* /dev/midi simple MIDI UART interface, no ioctl -* -* Modification History -* 08/20/00 trw - silence and no stopping DAC until release -* 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop. -* 09/18/00 trw - added 16bit only record with conversion -* 09/24/00 trw - added Enhanced Full duplex (separate simultaneous -* capture/playback rates) -* 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin -* libOSSm.so) -* 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal) -* 11/03/00 trw - fixed interrupt loss/stutter, added debug. -* 11/10/00 bkz - added __devinit to cs4281_hw_init() -* 11/10/00 trw - fixed SMP and capture spinlock hang. -* 12/04/00 trw - cleaned up CSDEBUG flags and added "defaultorder" moduleparm. -* 12/05/00 trw - fixed polling (myth2), and added underrun swptr fix. -* 12/08/00 trw - added PM support. -* 12/14/00 trw - added wrapper code, builds under 2.4.0, 2.2.17-20, 2.2.17-8 -* (RH/Dell base), 2.2.18, 2.2.12. cleaned up code mods by ident. -* 12/19/00 trw - added PM support for 2.2 base (apm_callback). other PM cleanup. -* 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use -* defaultorder-100 as power of 2 for the buffer size. example: -* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size. -* -*******************************************************************************/ - -/* uncomment the following line to disable building PM support into the driver */ -//#define NOT_CS4281_PM 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -//#include "cs_dm.h" -#include "cs4281_hwdefs.h" -#include "cs4281pm.h" - -struct cs4281_state; - -static void stop_dac(struct cs4281_state *s); -static void stop_adc(struct cs4281_state *s); -static void start_dac(struct cs4281_state *s); -static void start_adc(struct cs4281_state *s); -#undef OSS_DOCUMENTED_MIXER_SEMANTICS - -// --------------------------------------------------------------------- - -#ifndef PCI_VENDOR_ID_CIRRUS -#define PCI_VENDOR_ID_CIRRUS 0x1013 -#endif -#ifndef PCI_DEVICE_ID_CRYSTAL_CS4281 -#define PCI_DEVICE_ID_CRYSTAL_CS4281 0x6005 -#endif - -#define CS4281_MAGIC ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS) -#define CS4281_CFLR_DEFAULT 0x00000001 /* CFLR must be in AC97 link mode */ - -// buffer order determines the size of the dma buffer for the driver. -// under Linux, a smaller buffer allows more responsiveness from many of the -// applications (e.g. games). A larger buffer allows some of the apps (esound) -// to not underrun the dma buffer as easily. As default, use 32k (order=3) -// rather than 64k as some of the games work more responsively. -// log base 2( buff sz = 32k). -static unsigned long defaultorder = 3; -module_param(defaultorder, ulong, 0); - -// -// Turn on/off debugging compilation by commenting out "#define CSDEBUG" -// -#define CSDEBUG 1 -#if CSDEBUG -#define CSDEBUG_INTERFACE 1 -#else -#undef CSDEBUG_INTERFACE -#endif -// -// cs_debugmask areas -// -#define CS_INIT 0x00000001 // initialization and probe functions -#define CS_ERROR 0x00000002 // tmp debugging bit placeholder -#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other) -#define CS_FUNCTION 0x00000008 // enter/leave functions -#define CS_WAVE_WRITE 0x00000010 // write information for wave -#define CS_WAVE_READ 0x00000020 // read information for wave -#define CS_MIDI_WRITE 0x00000040 // write information for midi -#define CS_MIDI_READ 0x00000080 // read information for midi -#define CS_MPU401_WRITE 0x00000100 // write information for mpu401 -#define CS_MPU401_READ 0x00000200 // read information for mpu401 -#define CS_OPEN 0x00000400 // all open functions in the driver -#define CS_RELEASE 0x00000800 // all release functions in the driver -#define CS_PARMS 0x00001000 // functional and operational parameters -#define CS_IOCTL 0x00002000 // ioctl (non-mixer) -#define CS_PM 0x00004000 // power management -#define CS_TMP 0x10000000 // tmp debug mask bit - -#define CS_IOCTL_CMD_SUSPEND 0x1 // suspend -#define CS_IOCTL_CMD_RESUME 0x2 // resume -// -// CSDEBUG is usual mode is set to 1, then use the -// cs_debuglevel and cs_debugmask to turn on or off debugging. -// Debug level of 1 has been defined to be kernel errors and info -// that should be printed on any released driver. -// -#if CSDEBUG -#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;} -#else -#define CS_DBGOUT(mask,level,x) -#endif - -#if CSDEBUG -static unsigned long cs_debuglevel = 1; // levels range from 1-9 -static unsigned long cs_debugmask = CS_INIT | CS_ERROR; // use CS_DBGOUT with various mask values -module_param(cs_debuglevel, ulong, 0); -module_param(cs_debugmask, ulong, 0); -#endif -#define CS_TRUE 1 -#define CS_FALSE 0 - -// MIDI buffer sizes -#define MIDIINBUF 500 -#define MIDIOUTBUF 500 - -#define FMODE_MIDI_SHIFT 3 -#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) -#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) - -#define CS4281_MAJOR_VERSION 1 -#define CS4281_MINOR_VERSION 13 -#ifdef __ia64__ -#define CS4281_ARCH 64 //architecture key -#else -#define CS4281_ARCH 32 //architecture key -#endif - -#define CS_TYPE_ADC 0 -#define CS_TYPE_DAC 1 - - -static const char invalid_magic[] = - KERN_CRIT "cs4281: invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != CS4281_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -//LIST_HEAD(cs4281_devs); -static struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs }; - -struct cs4281_state; - -#include "cs4281_wrapper-24.c" - -struct cs4281_state { - // magic - unsigned int magic; - - // we keep the cards in a linked list - struct cs4281_state *next; - - // pcidev is needed to turn off the DDMA controller at driver shutdown - struct pci_dev *pcidev; - struct list_head list; - - // soundcore stuff - int dev_audio; - int dev_mixer; - int dev_midi; - - // hardware resources - unsigned int pBA0phys, pBA1phys; - char __iomem *pBA0; - char __iomem *pBA1; - unsigned int irq; - - // mixer registers - struct { - unsigned short vol[10]; - unsigned int recsrc; - unsigned int modcnt; - unsigned short micpreamp; - } mix; - - // wave stuff - struct properties { - unsigned fmt; - unsigned fmt_original; // original requested format - unsigned channels; - unsigned rate; - unsigned char clkdiv; - } prop_dac, prop_adc; - unsigned conversion:1; // conversion from 16 to 8 bit in progress - void *tmpbuff; // tmp buffer for sample conversions - unsigned ena; - spinlock_t lock; - struct mutex open_sem; - struct mutex open_sem_adc; - struct mutex open_sem_dac; - mode_t open_mode; - wait_queue_head_t open_wait; - wait_queue_head_t open_wait_adc; - wait_queue_head_t open_wait_dac; - - dma_addr_t dmaaddr_tmpbuff; - unsigned buforder_tmpbuff; // Log base 2 of 'rawbuf' size in bytes.. - struct dmabuf { - void *rawbuf; // Physical address of - dma_addr_t dmaaddr; - unsigned buforder; // Log base 2 of 'rawbuf' size in bytes.. - unsigned numfrag; // # of 'fragments' in the buffer. - unsigned fragshift; // Log base 2 of fragment size. - unsigned hwptr, swptr; - unsigned total_bytes; // # bytes process since open. - unsigned blocks; // last returned blocks value GETOPTR - unsigned wakeup; // interrupt occurred on block - int count; - unsigned underrun; // underrun flag - unsigned error; // over/underrun - wait_queue_head_t wait; - // redundant, but makes calculations easier - unsigned fragsize; // 2**fragshift.. - unsigned dmasize; // 2**buforder. - unsigned fragsamples; - // OSS stuff - unsigned mapped:1; // Buffer mapped in cs4281_mmap()? - unsigned ready:1; // prog_dmabuf_dac()/adc() successful? - unsigned endcleared:1; - unsigned type:1; // adc or dac buffer (CS_TYPE_XXX) - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac, dma_adc; - - // midi stuff - struct { - unsigned ird, iwr, icnt; - unsigned ord, owr, ocnt; - wait_queue_head_t iwait; - wait_queue_head_t owait; - struct timer_list timer; - unsigned char ibuf[MIDIINBUF]; - unsigned char obuf[MIDIOUTBUF]; - } midi; - - struct cs4281_pm pm; - struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES]; -}; - -#include "cs4281pm-24.c" - -#if CSDEBUG - -// DEBUG ROUTINES - -#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int) -#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int) -#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int) -#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int) - -#define SOUND_MIXER_CS_APM _SIOWR('M',124, int) - - -static void cs_printioctl(unsigned int x) -{ - unsigned int i; - unsigned char vidx; - // Index of mixtable1[] member is Device ID - // and must be <= SOUND_MIXER_NRDEVICES. - // Value of array member is index into s->mix.vol[] - static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_PCM] = 1, // voice - [SOUND_MIXER_LINE1] = 2, // AUX - [SOUND_MIXER_CD] = 3, // CD - [SOUND_MIXER_LINE] = 4, // Line - [SOUND_MIXER_SYNTH] = 5, // FM - [SOUND_MIXER_MIC] = 6, // Mic - [SOUND_MIXER_SPEAKER] = 7, // Speaker - [SOUND_MIXER_RECLEV] = 8, // Recording level - [SOUND_MIXER_VOLUME] = 9 // Master Volume - }; - - switch (x) { - case SOUND_MIXER_CS_GETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_GETDBGMASK:\n")); - break; - case SOUND_MIXER_CS_GETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_GETDBGLEVEL:\n")); - break; - case SOUND_MIXER_CS_SETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_SETDBGMASK:\n")); - break; - case SOUND_MIXER_CS_SETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_SETDBGLEVEL:\n")); - break; - case OSS_GETVERSION: - CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n")); - break; - case SNDCTL_DSP_SYNC: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n")); - break; - case SNDCTL_DSP_SETDUPLEX: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n")); - break; - case SNDCTL_DSP_GETCAPS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n")); - break; - case SNDCTL_DSP_RESET: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n")); - break; - case SNDCTL_DSP_SPEED: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n")); - break; - case SNDCTL_DSP_STEREO: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n")); - break; - case SNDCTL_DSP_CHANNELS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n")); - break; - case SNDCTL_DSP_GETFMTS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n")); - break; - case SNDCTL_DSP_SETFMT: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n")); - break; - case SNDCTL_DSP_POST: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n")); - break; - case SNDCTL_DSP_GETTRIGGER: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n")); - break; - case SNDCTL_DSP_SETTRIGGER: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n")); - break; - case SNDCTL_DSP_GETOSPACE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n")); - break; - case SNDCTL_DSP_GETISPACE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n")); - break; - case SNDCTL_DSP_NONBLOCK: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n")); - break; - case SNDCTL_DSP_GETODELAY: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n")); - break; - case SNDCTL_DSP_GETIPTR: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n")); - break; - case SNDCTL_DSP_GETOPTR: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n")); - break; - case SNDCTL_DSP_GETBLKSIZE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n")); - break; - case SNDCTL_DSP_SETFRAGMENT: - CS_DBGOUT(CS_IOCTL, 4, - printk("SNDCTL_DSP_SETFRAGMENT:\n")); - break; - case SNDCTL_DSP_SUBDIVIDE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n")); - break; - case SOUND_PCM_READ_RATE: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n")); - break; - case SOUND_PCM_READ_CHANNELS: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_PCM_READ_CHANNELS:\n")); - break; - case SOUND_PCM_READ_BITS: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n")); - break; - case SOUND_PCM_WRITE_FILTER: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_PCM_WRITE_FILTER:\n")); - break; - case SNDCTL_DSP_SETSYNCRO: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n")); - break; - case SOUND_PCM_READ_FILTER: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n")); - break; - case SOUND_MIXER_PRIVATE1: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n")); - break; - case SOUND_MIXER_PRIVATE2: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n")); - break; - case SOUND_MIXER_PRIVATE3: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n")); - break; - case SOUND_MIXER_PRIVATE4: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n")); - break; - case SOUND_MIXER_PRIVATE5: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n")); - break; - case SOUND_MIXER_INFO: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n")); - break; - case SOUND_OLD_MIXER_INFO: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n")); - break; - - default: - switch (_IOC_NR(x)) { - case SOUND_MIXER_VOLUME: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_VOLUME:\n")); - break; - case SOUND_MIXER_SPEAKER: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_SPEAKER:\n")); - break; - case SOUND_MIXER_RECLEV: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECLEV:\n")); - break; - case SOUND_MIXER_MIC: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_MIC:\n")); - break; - case SOUND_MIXER_SYNTH: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_SYNTH:\n")); - break; - case SOUND_MIXER_RECSRC: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECSRC:\n")); - break; - case SOUND_MIXER_DEVMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_DEVMASK:\n")); - break; - case SOUND_MIXER_RECMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECMASK:\n")); - break; - case SOUND_MIXER_STEREODEVS: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_STEREODEVS:\n")); - break; - case SOUND_MIXER_CAPS: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:\n")); - break; - default: - i = _IOC_NR(x); - if (i >= SOUND_MIXER_NRDEVICES - || !(vidx = mixtable1[i])) { - CS_DBGOUT(CS_IOCTL, 4, printk - ("UNKNOWN IOCTL: 0x%.8x NR=%d\n", - x, i)); - } else { - CS_DBGOUT(CS_IOCTL, 4, printk - ("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n", - x, i)); - } - break; - } - } -} -#endif -static int prog_dmabuf_adc(struct cs4281_state *s); -static void prog_codec(struct cs4281_state *s, unsigned type); - -// --------------------------------------------------------------------- -// -// Hardware Interfaces For the CS4281 -// - - -//****************************************************************************** -// "delayus()-- Delay for the specified # of microseconds. -//****************************************************************************** -static void delayus(struct cs4281_state *s, u32 delay) -{ - u32 j; - if ((delay > 9999) && (s->pm.flags & CS4281_PM_IDLE)) { - j = (delay * HZ) / 1000000; /* calculate delay in jiffies */ - if (j < 1) - j = 1; /* minimum one jiffy. */ - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(j); - } else - udelay(delay); - return; -} - - -//****************************************************************************** -// "cs4281_read_ac97" -- Reads a word from the specified location in the -// CS4281's address space(based on the BA0 register). -// -// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address -// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 register, -// 0h for reads. -// 3. Write ACCTL = Control Register = 460h for initiating the write -// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h -// 5. if DCV not cleared, break and return error -// 6. Read ACSTS = Status Register = 464h, check VSTS bit -//**************************************************************************** -static int cs4281_read_ac97(struct cs4281_state *card, u32 offset, - u32 * value) -{ - u32 count, status; - - // Make sure that there is not data sitting - // around from a previous uncompleted access. - // ACSDA = Status Data Register = 47Ch - status = readl(card->pBA0 + BA0_ACSDA); - - // Setup the AC97 control registers on the CS4281 to send the - // appropriate command to the AC97 to perform the read. - // ACCAD = Command Address Register = 46Ch - // ACCDA = Command Data Register = 470h - // ACCTL = Control Register = 460h - // bit DCV - will clear when process completed - // bit CRW - Read command - // bit VFRM - valid frame enabled - // bit ESYN - ASYNC generation enabled - - // Get the actual AC97 register from the offset - writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD); - writel(0, card->pBA0 + BA0_ACCDA); - writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN, - card->pBA0 + BA0_ACCTL); - - // Wait for the read to occur. - for (count = 0; count < 10; count++) { - // First, we want to wait for a short time. - udelay(25); - - // Now, check to see if the read has completed. - // ACCTL = 460h, DCV should be reset by now and 460h = 17h - if (!(readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV)) - break; - } - - // Make sure the read completed. - if (readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV) - return 1; - - // Wait for the valid status bit to go active. - for (count = 0; count < 10; count++) { - // Read the AC97 status register. - // ACSTS = Status Register = 464h - status = readl(card->pBA0 + BA0_ACSTS); - - // See if we have valid status. - // VSTS - Valid Status - if (status & ACSTS_VSTS) - break; - // Wait for a short while. - udelay(25); - } - - // Make sure we got valid status. - if (!(status & ACSTS_VSTS)) - return 1; - - // Read the data returned from the AC97 register. - // ACSDA = Status Data Register = 474h - *value = readl(card->pBA0 + BA0_ACSDA); - - // Success. - return (0); -} - - -//**************************************************************************** -// -// "cs4281_write_ac97()"-- writes a word to the specified location in the -// CS461x's address space (based on the part's base address zero register). -// -// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address -// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 reg. -// 3. Write ACCTL = Control Register = 460h for initiating the write -// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h -// 5. if DCV not cleared, break and return error -// -//**************************************************************************** -static int cs4281_write_ac97(struct cs4281_state *card, u32 offset, - u32 value) -{ - u32 count, status=0; - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n")); - - // Setup the AC97 control registers on the CS4281 to send the - // appropriate command to the AC97 to perform the read. - // ACCAD = Command Address Register = 46Ch - // ACCDA = Command Data Register = 470h - // ACCTL = Control Register = 460h - // set DCV - will clear when process completed - // reset CRW - Write command - // set VFRM - valid frame enabled - // set ESYN - ASYNC generation enabled - // set RSTN - ARST# inactive, AC97 codec not reset - - // Get the actual AC97 register from the offset - - writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD); - writel(value, card->pBA0 + BA0_ACCDA); - writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN, - card->pBA0 + BA0_ACCTL); - - // Wait for the write to occur. - for (count = 0; count < 100; count++) { - // First, we want to wait for a short time. - udelay(25); - // Now, check to see if the write has completed. - // ACCTL = 460h, DCV should be reset by now and 460h = 07h - status = readl(card->pBA0 + BA0_ACCTL); - if (!(status & ACCTL_DCV)) - break; - } - - // Make sure the write completed. - if (status & ACCTL_DCV) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO - "cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n")); - return 1; - } - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n")); - // Success. - return 0; -} - - -//****************************************************************************** -// "Init4281()" -- Bring up the part. -//****************************************************************************** -static __devinit int cs4281_hw_init(struct cs4281_state *card) -{ - u32 ac97_slotid; - u32 temp1, temp2; - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n")); -#ifndef NOT_CS4281_PM - if(!card) - return 1; -#endif - temp2 = readl(card->pBA0 + BA0_CFLR); - CS_DBGOUT(CS_INIT | CS_ERROR | CS_PARMS, 4, printk(KERN_INFO - "cs4281: cs4281_hw_init() CFLR 0x%x\n", temp2)); - if(temp2 != CS4281_CFLR_DEFAULT) - { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO - "cs4281: cs4281_hw_init() CFLR invalid - resetting from 0x%x to 0x%x\n", - temp2,CS4281_CFLR_DEFAULT)); - writel(CS4281_CFLR_DEFAULT, card->pBA0 + BA0_CFLR); - temp2 = readl(card->pBA0 + BA0_CFLR); - if(temp2 != CS4281_CFLR_DEFAULT) - { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO - "cs4281: cs4281_hw_init() Invalid hardware - unable to configure CFLR\n")); - return 1; - } - } - - //***************************************7 - // Set up the Sound System Configuration - //*************************************** - - // Set the 'Configuration Write Protect' register - // to 4281h. Allows vendor-defined configuration - // space between 0e4h and 0ffh to be written. - - writel(0x4281, card->pBA0 + BA0_CWPR); // (3e0h) - - // (0), Blast the clock control register to zero so that the - // PLL starts out in a known state, and blast the master serial - // port control register to zero so that the serial ports also - // start out in a known state. - - writel(0, card->pBA0 + BA0_CLKCR1); // (400h) - writel(0, card->pBA0 + BA0_SERMC); // (420h) - - - // (1), Make ESYN go to zero to turn off - // the Sync pulse on the AC97 link. - - writel(0, card->pBA0 + BA0_ACCTL); - udelay(50); - - - // (2) Drive the ARST# pin low for a minimum of 1uS (as defined in - // the AC97 spec) and then drive it high. This is done for non - // AC97 modes since there might be logic external to the CS461x - // that uses the ARST# line for a reset. - - writel(0, card->pBA0 + BA0_SPMC); // (3ech) - udelay(100); - writel(SPMC_RSTN, card->pBA0 + BA0_SPMC); - delayus(card,50000); // Wait 50 ms for ABITCLK to become stable. - - // (3) Turn on the Sound System Clocks. - writel(CLKCR1_PLLP, card->pBA0 + BA0_CLKCR1); // (400h) - delayus(card,50000); // Wait for the PLL to stabilize. - // Turn on clocking of the core (CLKCR1(400h) = 0x00000030) - writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0 + BA0_CLKCR1); - - // (4) Power on everything for now.. - writel(0x7E, card->pBA0 + BA0_SSPM); // (740h) - - // (5) Wait for clock stabilization. - for (temp1 = 0; temp1 < 1000; temp1++) { - udelay(1000); - if (readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY) - break; - } - if (!(readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4281: DLLRDY failed!\n")); - return -EIO; - } - // (6) Enable ASYNC generation. - writel(ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h) - - // Now wait 'for a short while' to allow the AC97 - // part to start generating bit clock. (so we don't - // Try to start the PLL without an input clock.) - delayus(card,50000); - - // Set the serial port timing configuration, so that the - // clock control circuit gets its clock from the right place. - writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2. - - // (7) Wait for the codec ready signal from the AC97 codec. - - for (temp1 = 0; temp1 < 1000; temp1++) { - // Delay a mil to let things settle out and - // to prevent retrying the read too quickly. - udelay(1000); - if (readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY) // If ready, (464h) - break; // exit the 'for' loop. - } - if (!(readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY)) // If never came ready, - { - CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR - "cs4281: ACSTS never came ready!\n")); - return -EIO; // exit initialization. - } - // (8) Assert the 'valid frame' signal so we can - // begin sending commands to the AC97 codec. - writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h) - - // (9), Wait until CODEC calibration is finished. - // Print an error message if it doesn't. - for (temp1 = 0; temp1 < 1000; temp1++) { - delayus(card,10000); - // Read the AC97 Powerdown Control/Status Register. - cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp2); - if ((temp2 & 0x0000000F) == 0x0000000F) - break; - } - if ((temp2 & 0x0000000F) != 0x0000000F) { - CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR - "cs4281: Codec failed to calibrate. Status = %.8x.\n", - temp2)); - return -EIO; - } - // (10), Set the serial port timing configuration, so that the - // clock control circuit gets its clock from the right place. - writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2. - - - // (11) Wait until we've sampled input slots 3 & 4 as valid, meaning - // that the codec is pumping ADC data across the AC link. - for (temp1 = 0; temp1 < 1000; temp1++) { - // Delay a mil to let things settle out and - // to prevent retrying the read too quickly. - delayus(card,1000); //(test) - - // Read the input slot valid register; See - // if input slots 3 and 4 are valid yet. - if ( - (readl(card->pBA0 + BA0_ACISV) & - (ACISV_ISV3 | ACISV_ISV4)) == - (ACISV_ISV3 | ACISV_ISV4)) break; // Exit the 'for' if slots are valid. - } - // If we never got valid data, exit initialization. - if ((readl(card->pBA0 + BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) - != (ACISV_ISV3 | ACISV_ISV4)) { - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_ERR - "cs4281: Never got valid data!\n")); - return -EIO; // If no valid data, exit initialization. - } - // (12), Start digital data transfer of audio data to the codec. - writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0 + BA0_ACOSV); // (468h) - - - //************************************** - // Unmute the Master and Alternate - // (headphone) volumes. Set to max. - //************************************** - cs4281_write_ac97(card, BA0_AC97_HEADPHONE_VOLUME, 0); - cs4281_write_ac97(card, BA0_AC97_MASTER_VOLUME, 0); - - //****************************************** - // Power on the DAC(AddDACUser()from main()) - //****************************************** - cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); - cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfdff); - - // Wait until we sample a DAC ready state. - for (temp2 = 0; temp2 < 32; temp2++) { - // Let's wait a mil to let things settle. - delayus(card,1000); - // Read the current state of the power control reg. - cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); - // If the DAC ready state bit is set, stop waiting. - if (temp1 & 0x2) - break; - } - - //****************************************** - // Power on the ADC(AddADCUser()from main()) - //****************************************** - cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); - cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfeff); - - // Wait until we sample ADC ready state. - for (temp2 = 0; temp2 < 32; temp2++) { - // Let's wait a mil to let things settle. - delayus(card,1000); - // Read the current state of the power control reg. - cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); - // If the ADC ready state bit is set, stop waiting. - if (temp1 & 0x1) - break; - } - // Set up 4281 Register contents that - // don't change for boot duration. - - // For playback, we map AC97 slot 3 and 4(Left - // & Right PCM playback) to DMA Channel 0. - // Set the fifo to be 15 bytes at offset zero. - - ac97_slotid = 0x01000f00; // FCR0.RS[4:0]=1(=>slot4, right PCM playback). - // FCR0.LS[4:0]=0(=>slot3, left PCM playback). - // FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0. - writel(ac97_slotid, card->pBA0 + BA0_FCR0); // (180h) - writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0); // Turn on FIFO Enable. - - // For capture, we map AC97 slot 10 and 11(Left - // and Right PCM Record) to DMA Channel 1. - // Set the fifo to be 15 bytes at offset sixteen. - ac97_slotid = 0x0B0A0f10; // FCR1.RS[4:0]=11(=>slot11, right PCM record). - // FCR1.LS[4:0]=10(=>slot10, left PCM record). - // FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16. - writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1); // (184h) - writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1); // Turn on FIFO Enable. - - // Map the Playback SRC to the same AC97 slots(3 & 4-- - // --Playback left & right)as DMA channel 0. - // Map the record SRC to the same AC97 slots(10 & 11-- - // -- Record left & right) as DMA channel 1. - - ac97_slotid = 0x0b0a0100; // SCRSA.PRSS[4:0]=1(=>slot4, right PCM playback). - // SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback). - // SCRSA.CRSS[4:0]=11(=>slot11, right PCM record) - // SCRSA.CLSS[4:0]=10(=>slot10, left PCM record). - writel(ac97_slotid, card->pBA0 + BA0_SRCSA); // (75ch) - - // Set 'Half Terminal Count Interrupt Enable' and 'Terminal - // Count Interrupt Enable' in DMA Control Registers 0 & 1. - // Set 'MSK' flag to 1 to keep the DMA engines paused. - temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK); // (00030001h) - writel(temp1, card->pBA0 + BA0_DCR0); // (154h - writel(temp1, card->pBA0 + BA0_DCR1); // (15ch) - - // Set 'Auto-Initialize Control' to 'enabled'; For playback, - // set 'Transfer Type Control'(TR[1:0]) to 'read transfer', - // for record, set Transfer Type Control to 'write transfer'. - // All other bits set to zero; Some will be changed @ transfer start. - temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); // (20000018h) - writel(temp1, card->pBA0 + BA0_DMR0); // (150h) - temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); // (20000014h) - writel(temp1, card->pBA0 + BA0_DMR1); // (158h) - - // Enable DMA interrupts generally, and - // DMA0 & DMA1 interrupts specifically. - temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff; - writel(temp1, card->pBA0 + BA0_HIMR); - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n")); - return 0; -} - -#ifndef NOT_CS4281_PM -static void printpm(struct cs4281_state *s) -{ - CS_DBGOUT(CS_PM, 9, printk("pm struct:\n")); - CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n", - (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue)); - CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n", - s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue)); - CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n", - s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue)); - CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n", - s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue)); - CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n", - s->pm.u32SSCR,s->pm.u32SRCSA)); - CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n", - s->pm.u32DacASR,s->pm.u32AdcASR)); - CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n", - s->pm.u32DacSR,s->pm.u32AdcSR)); - CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n", - s->pm.u32MIDCR_Save)); - -} -static void printpipe(struct cs4281_pipeline *pl) -{ - - CS_DBGOUT(CS_PM, 9, printk("pm struct:\n")); - CS_DBGOUT(CS_PM, 9, printk("flags:0x%x number: 0%x\n", - (unsigned)pl->flags,pl->number)); - CS_DBGOUT(CS_PM, 9, printk("u32DBAnValue: 0%x u32DBCnValue: 0x%x\n", - pl->u32DBAnValue,pl->u32DBCnValue)); - CS_DBGOUT(CS_PM, 9, printk("u32DMRnValue: 0x%x u32DCRnValue: 0x%x\n", - pl->u32DMRnValue,pl->u32DCRnValue)); - CS_DBGOUT(CS_PM, 9, printk("u32DBAnAddress: 0x%x u32DBCnAddress: 0x%x\n", - pl->u32DBAnAddress,pl->u32DBCnAddress)); - CS_DBGOUT(CS_PM, 9, printk("u32DCAnAddress: 0x%x u32DCCnAddress: 0x%x\n", - pl->u32DCCnAddress,pl->u32DCCnAddress)); - CS_DBGOUT(CS_PM, 9, printk("u32DMRnAddress: 0x%x u32DCRnAddress: 0x%x\n", - pl->u32DMRnAddress,pl->u32DCRnAddress)); - CS_DBGOUT(CS_PM, 9, printk("u32HDSRnAddress: 0x%x u32DBAn_Save: 0x%x\n", - pl->u32HDSRnAddress,pl->u32DBAn_Save)); - CS_DBGOUT(CS_PM, 9, printk("u32DBCn_Save: 0x%x u32DMRn_Save: 0x%x\n", - pl->u32DBCn_Save,pl->u32DMRn_Save)); - CS_DBGOUT(CS_PM, 9, printk("u32DCRn_Save: 0x%x u32DCCn_Save: 0x%x\n", - pl->u32DCRn_Save,pl->u32DCCn_Save)); - CS_DBGOUT(CS_PM, 9, printk("u32DCAn_Save: 0x%x\n", - pl->u32DCAn_Save)); - CS_DBGOUT(CS_PM, 9, printk("u32FCRn_Save: 0x%x u32FSICn_Save: 0x%x\n", - pl->u32FCRn_Save,pl->u32FSICn_Save)); - CS_DBGOUT(CS_PM, 9, printk("u32FCRnValue: 0x%x u32FSICnValue: 0x%x\n", - pl->u32FCRnValue,pl->u32FSICnValue)); - CS_DBGOUT(CS_PM, 9, printk("u32FCRnAddress: 0x%x u32FSICnAddress: 0x%x\n", - pl->u32FCRnAddress,pl->u32FSICnAddress)); - CS_DBGOUT(CS_PM, 9, printk("u32FPDRnValue: 0x%x u32FPDRnAddress: 0x%x\n", - pl->u32FPDRnValue,pl->u32FPDRnAddress)); -} -static void printpipelines(struct cs4281_state *s) -{ - int i; - for(i=0;ipl[i].flags & CS4281_PIPELINE_VALID) - { - printpipe(&s->pl[i]); - } - } -} -/**************************************************************************** -* -* Suspend - save the ac97 regs, mute the outputs and power down the part. -* -****************************************************************************/ -static void cs4281_ac97_suspend(struct cs4281_state *s) -{ - int Count,i; - - CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()+\n")); -/* -* change the state, save the current hwptr, then stop the dac/adc -*/ - s->pm.flags &= ~CS4281_PM_IDLE; - s->pm.flags |= CS4281_PM_SUSPENDING; - s->pm.u32hwptr_playback = readl(s->pBA0 + BA0_DCA0); - s->pm.u32hwptr_capture = readl(s->pBA0 + BA0_DCA1); - stop_dac(s); - stop_adc(s); - - for(Count = 0x2, i=0; (Count <= CS4281_AC97_HIGHESTREGTORESTORE) - && (i < CS4281_AC97_NUMBER_RESTORE_REGS); - Count += 2, i++) - { - cs4281_read_ac97(s, BA0_AC97_RESET + Count, &s->pm.ac97[i]); - } -/* -* Save the ac97 volume registers as well as the current powerdown state. -* Now, mute the all the outputs (master, headphone, and mono), as well -* as the PCM volume, in preparation for powering down the entire part. -*/ - cs4281_read_ac97(s, BA0_AC97_MASTER_VOLUME, &s->pm.u32AC97_master_volume); - cs4281_read_ac97(s, BA0_AC97_HEADPHONE_VOLUME, &s->pm.u32AC97_headphone_volume); - cs4281_read_ac97(s, BA0_AC97_MASTER_VOLUME_MONO, &s->pm.u32AC97_master_volume_mono); - cs4281_read_ac97(s, BA0_AC97_PCM_OUT_VOLUME, &s->pm.u32AC97_pcm_out_volume); - - cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, 0x8000); - cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, 0x8000); - cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME_MONO, 0x8000); - cs4281_write_ac97(s, BA0_AC97_PCM_OUT_VOLUME, 0x8000); - - cs4281_read_ac97(s, BA0_AC97_POWERDOWN, &s->pm.u32AC97_powerdown); - cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE, &s->pm.u32AC97_general_purpose); - -/* -* And power down everything on the AC97 codec. -*/ - cs4281_write_ac97(s, BA0_AC97_POWERDOWN, 0xff00); - CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()-\n")); -} - -/**************************************************************************** -* -* Resume - power up the part and restore its registers.. -* -****************************************************************************/ -static void cs4281_ac97_resume(struct cs4281_state *s) -{ - int Count,i; - - CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_resume()+\n")); - -/* do not save the power state registers at this time - // - // If we saved away the power control registers, write them into the - // shadows so those saved values get restored instead of the current - // shadowed value. - // - if( bPowerStateSaved ) - { - PokeShadow( 0x26, ulSaveReg0x26 ); - bPowerStateSaved = FALSE; - } -*/ - -// -// First, we restore the state of the general purpose register. This -// contains the mic select (mic1 or mic2) and if we restore this after -// we restore the mic volume/boost state and mic2 was selected at -// suspend time, we will end up with a brief period of time where mic1 -// is selected with the volume/boost settings for mic2, causing -// acoustic feedback. So we restore the general purpose register -// first, thereby getting the correct mic selected before we restore -// the mic volume/boost. -// - cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE, s->pm.u32AC97_general_purpose); - -// -// Now, while the outputs are still muted, restore the state of power -// on the AC97 part. -// - cs4281_write_ac97(s, BA0_AC97_POWERDOWN, s->pm.u32AC97_powerdown); - -/* -* Restore just the first set of registers, from register number -* 0x02 to the register number that ulHighestRegToRestore specifies. -*/ - for( Count = 0x2, i=0; - (Count <= CS4281_AC97_HIGHESTREGTORESTORE) - && (i < CS4281_AC97_NUMBER_RESTORE_REGS); - Count += 2, i++) - { - cs4281_write_ac97(s, BA0_AC97_RESET + Count, s->pm.ac97[i]); - } - CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_resume()-\n")); -} - -/* do not save the power state registers at this time -**************************************************************************** -* -* SavePowerState - Save the power registers away. -* -**************************************************************************** -void -HWAC97codec::SavePowerState(void) -{ - ENTRY(TM_OBJECTCALLS, "HWAC97codec::SavePowerState()\r\n"); - - ulSaveReg0x26 = PeekShadow(0x26); - - // - // Note that we have saved registers that need to be restored during a - // resume instead of ulAC97Regs[]. - // - bPowerStateSaved = TRUE; - -} // SavePowerState -*/ - -static void cs4281_SuspendFIFO(struct cs4281_state *s, struct cs4281_pipeline *pl) -{ - /* - * We need to save the contents of the BASIC FIFO Registers. - */ - pl->u32FCRn_Save = readl(s->pBA0 + pl->u32FCRnAddress); - pl->u32FSICn_Save = readl(s->pBA0 + pl->u32FSICnAddress); -} -static void cs4281_ResumeFIFO(struct cs4281_state *s, struct cs4281_pipeline *pl) -{ - /* - * We need to restore the contents of the BASIC FIFO Registers. - */ - writel(pl->u32FCRn_Save,s->pBA0 + pl->u32FCRnAddress); - writel(pl->u32FSICn_Save,s->pBA0 + pl->u32FSICnAddress); -} -static void cs4281_SuspendDMAengine(struct cs4281_state *s, struct cs4281_pipeline *pl) -{ - // - // We need to save the contents of the BASIC DMA Registers. - // - pl->u32DBAn_Save = readl(s->pBA0 + pl->u32DBAnAddress); - pl->u32DBCn_Save = readl(s->pBA0 + pl->u32DBCnAddress); - pl->u32DMRn_Save = readl(s->pBA0 + pl->u32DMRnAddress); - pl->u32DCRn_Save = readl(s->pBA0 + pl->u32DCRnAddress); - pl->u32DCCn_Save = readl(s->pBA0 + pl->u32DCCnAddress); - pl->u32DCAn_Save = readl(s->pBA0 + pl->u32DCAnAddress); -} -static void cs4281_ResumeDMAengine(struct cs4281_state *s, struct cs4281_pipeline *pl) -{ - // - // We need to save the contents of the BASIC DMA Registers. - // - writel( pl->u32DBAn_Save, s->pBA0 + pl->u32DBAnAddress); - writel( pl->u32DBCn_Save, s->pBA0 + pl->u32DBCnAddress); - writel( pl->u32DMRn_Save, s->pBA0 + pl->u32DMRnAddress); - writel( pl->u32DCRn_Save, s->pBA0 + pl->u32DCRnAddress); - writel( pl->u32DCCn_Save, s->pBA0 + pl->u32DCCnAddress); - writel( pl->u32DCAn_Save, s->pBA0 + pl->u32DCAnAddress); -} - -static int cs4281_suspend(struct cs4281_state *s) -{ - int i; - u32 u32CLKCR1; - struct cs4281_pm *pm = &s->pm; - CS_DBGOUT(CS_PM | CS_FUNCTION, 9, - printk("cs4281: cs4281_suspend()+ flags=%d\n", - (unsigned)s->pm.flags)); -/* -* check the current state, only suspend if IDLE -*/ - if(!(s->pm.flags & CS4281_PM_IDLE)) - { - CS_DBGOUT(CS_PM | CS_ERROR, 2, - printk("cs4281: cs4281_suspend() unable to suspend, not IDLE\n")); - return 1; - } - s->pm.flags &= ~CS4281_PM_IDLE; - s->pm.flags |= CS4281_PM_SUSPENDING; - -// -// Gershwin CLKRUN - Set CKRA -// - u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1); - - pm->u32CLKCR1_SAVE = u32CLKCR1; - if(!(u32CLKCR1 & 0x00010000 ) ) - writel(u32CLKCR1 | 0x00010000, s->pBA0 + BA0_CLKCR1); - -// -// First, turn on the clocks (yikes) to the devices, so that they will -// respond when we try to save their state. -// - if(!(u32CLKCR1 & CLKCR1_SWCE)) - { - writel(u32CLKCR1 | CLKCR1_SWCE , s->pBA0 + BA0_CLKCR1); - } - - // - // Save the power state - // - pm->u32SSPMValue = readl(s->pBA0 + BA0_SSPM); - - // - // Disable interrupts. - // - writel(HICR_CHGM, s->pBA0 + BA0_HICR); - - // - // Save the PCM Playback Left and Right Volume Control. - // - pm->u32PPLVCvalue = readl(s->pBA0 + BA0_PPLVC); - pm->u32PPRVCvalue = readl(s->pBA0 + BA0_PPRVC); - - // - // Save the FM Synthesis Left and Right Volume Control. - // - pm->u32FMLVCvalue = readl(s->pBA0 + BA0_FMLVC); - pm->u32FMRVCvalue = readl(s->pBA0 + BA0_FMRVC); - - // - // Save the GPIOR value. - // - pm->u32GPIORvalue = readl(s->pBA0 + BA0_GPIOR); - - // - // Save the JSCTL value. - // - pm->u32JSCTLvalue = readl(s->pBA0 + BA0_GPIOR); - - // - // Save Sound System Control Register - // - pm->u32SSCR = readl(s->pBA0 + BA0_SSCR); - - // - // Save SRC Slot Assinment register - // - pm->u32SRCSA = readl(s->pBA0 + BA0_SRCSA); - - // - // Save sample rate - // - pm->u32DacASR = readl(s->pBA0 + BA0_PASR); - pm->u32AdcASR = readl(s->pBA0 + BA0_CASR); - pm->u32DacSR = readl(s->pBA0 + BA0_DACSR); - pm->u32AdcSR = readl(s->pBA0 + BA0_ADCSR); - - // - // Loop through all of the PipeLines - // - for(i = 0; i < CS4281_NUMBER_OF_PIPELINES; i++) - { - if(s->pl[i].flags & CS4281_PIPELINE_VALID) - { - // - // Ask the DMAengines and FIFOs to Suspend. - // - cs4281_SuspendDMAengine(s,&s->pl[i]); - cs4281_SuspendFIFO(s,&s->pl[i]); - } - } - // - // We need to save the contents of the Midi Control Register. - // - pm->u32MIDCR_Save = readl(s->pBA0 + BA0_MIDCR); -/* -* save off the AC97 part information -*/ - cs4281_ac97_suspend(s); - - // - // Turn off the serial ports. - // - writel(0, s->pBA0 + BA0_SERMC); - - // - // Power off FM, Joystick, AC link, - // - writel(0, s->pBA0 + BA0_SSPM); - - // - // DLL off. - // - writel(0, s->pBA0 + BA0_CLKCR1); - - // - // AC link off. - // - writel(0, s->pBA0 + BA0_SPMC); - - // - // Put the chip into D3(hot) state. - // - // PokeBA0(BA0_PMCS, 0x00000003); - - // - // Gershwin CLKRUN - Clear CKRA - // - u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1); - writel(u32CLKCR1 & 0xFFFEFFFF, s->pBA0 + BA0_CLKCR1); - -#ifdef CSDEBUG - printpm(s); - printpipelines(s); -#endif - - s->pm.flags &= ~CS4281_PM_SUSPENDING; - s->pm.flags |= CS4281_PM_SUSPENDED; - - CS_DBGOUT(CS_PM | CS_FUNCTION, 9, - printk("cs4281: cs4281_suspend()- flags=%d\n", - (unsigned)s->pm.flags)); - return 0; -} - -static int cs4281_resume(struct cs4281_state *s) -{ - int i; - unsigned temp1; - u32 u32CLKCR1; - struct cs4281_pm *pm = &s->pm; - CS_DBGOUT(CS_PM | CS_FUNCTION, 4, - printk( "cs4281: cs4281_resume()+ flags=%d\n", - (unsigned)s->pm.flags)); - if(!(s->pm.flags & CS4281_PM_SUSPENDED)) - { - CS_DBGOUT(CS_PM | CS_ERROR, 2, - printk("cs4281: cs4281_resume() unable to resume, not SUSPENDED\n")); - return 1; - } - s->pm.flags &= ~CS4281_PM_SUSPENDED; - s->pm.flags |= CS4281_PM_RESUMING; - -// -// Gershwin CLKRUN - Set CKRA -// - u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1); - writel(u32CLKCR1 | 0x00010000, s->pBA0 + BA0_CLKCR1); - - // - // set the power state. - // - //old PokeBA0(BA0_PMCS, 0); - - // - // Program the clock circuit and serial ports. - // - temp1 = cs4281_hw_init(s); - if (temp1) { - CS_DBGOUT(CS_ERROR | CS_INIT, 1, - printk(KERN_ERR - "cs4281: resume cs4281_hw_init() error.\n")); - return -1; - } - - // - // restore the Power state - // - writel(pm->u32SSPMValue, s->pBA0 + BA0_SSPM); - - // - // Set post SRC mix setting (FM or ALT48K) - // - writel(pm->u32SSPM_BITS, s->pBA0 + BA0_SSPM); - - // - // Loop through all of the PipeLines - // - for(i = 0; i < CS4281_NUMBER_OF_PIPELINES; i++) - { - if(s->pl[i].flags & CS4281_PIPELINE_VALID) - { - // - // Ask the DMAengines and FIFOs to Resume. - // - cs4281_ResumeDMAengine(s,&s->pl[i]); - cs4281_ResumeFIFO(s,&s->pl[i]); - } - } - // - // We need to restore the contents of the Midi Control Register. - // - writel(pm->u32MIDCR_Save, s->pBA0 + BA0_MIDCR); - - cs4281_ac97_resume(s); - // - // Restore the PCM Playback Left and Right Volume Control. - // - writel(pm->u32PPLVCvalue, s->pBA0 + BA0_PPLVC); - writel(pm->u32PPRVCvalue, s->pBA0 + BA0_PPRVC); - - // - // Restore the FM Synthesis Left and Right Volume Control. - // - writel(pm->u32FMLVCvalue, s->pBA0 + BA0_FMLVC); - writel(pm->u32FMRVCvalue, s->pBA0 + BA0_FMRVC); - - // - // Restore the JSCTL value. - // - writel(pm->u32JSCTLvalue, s->pBA0 + BA0_JSCTL); - - // - // Restore the GPIOR register value. - // - writel(pm->u32GPIORvalue, s->pBA0 + BA0_GPIOR); - - // - // Restore Sound System Control Register - // - writel(pm->u32SSCR, s->pBA0 + BA0_SSCR); - - // - // Restore SRC Slot Assignment register - // - writel(pm->u32SRCSA, s->pBA0 + BA0_SRCSA); - - // - // Restore sample rate - // - writel(pm->u32DacASR, s->pBA0 + BA0_PASR); - writel(pm->u32AdcASR, s->pBA0 + BA0_CASR); - writel(pm->u32DacSR, s->pBA0 + BA0_DACSR); - writel(pm->u32AdcSR, s->pBA0 + BA0_ADCSR); - - // - // Restore CFL1/2 registers we saved to compensate for OEM bugs. - // - // PokeBA0(BA0_CFLR, ulConfig); - - // - // Gershwin CLKRUN - Clear CKRA - // - writel(pm->u32CLKCR1_SAVE, s->pBA0 + BA0_CLKCR1); - - // - // Enable interrupts on the part. - // - writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); - -#ifdef CSDEBUG - printpm(s); - printpipelines(s); -#endif -/* -* change the state, restore the current hwptrs, then stop the dac/adc -*/ - s->pm.flags |= CS4281_PM_IDLE; - s->pm.flags &= ~(CS4281_PM_SUSPENDING | CS4281_PM_SUSPENDED - | CS4281_PM_RESUMING | CS4281_PM_RESUMED); - - writel(s->pm.u32hwptr_playback, s->pBA0 + BA0_DCA0); - writel(s->pm.u32hwptr_capture, s->pBA0 + BA0_DCA1); - start_dac(s); - start_adc(s); - - CS_DBGOUT(CS_PM | CS_FUNCTION, 9, printk("cs4281: cs4281_resume()- flags=%d\n", - (unsigned)s->pm.flags)); - return 0; -} - -#endif - -//****************************************************************************** -// "cs4281_play_rate()" -- -//****************************************************************************** -static void cs4281_play_rate(struct cs4281_state *card, u32 playrate) -{ - u32 DACSRvalue = 1; - - // Based on the sample rate, program the DACSR register. - if (playrate == 8000) - DACSRvalue = 5; - if (playrate == 11025) - DACSRvalue = 4; - else if (playrate == 22050) - DACSRvalue = 2; - else if (playrate == 44100) - DACSRvalue = 1; - else if ((playrate <= 48000) && (playrate >= 6023)) - DACSRvalue = 24576000 / (playrate * 16); - else if (playrate < 6023) - // Not allowed by open. - return; - else if (playrate > 48000) - // Not allowed by open. - return; - CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO - "cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n", - DACSRvalue, playrate)); - // Write the 'sample rate select code' - // to the 'DAC Sample Rate' register. - writel(DACSRvalue, card->pBA0 + BA0_DACSR); // (744h) -} - -//****************************************************************************** -// "cs4281_record_rate()" -- Initialize the record sample rate converter. -//****************************************************************************** -static void cs4281_record_rate(struct cs4281_state *card, u32 outrate) -{ - u32 ADCSRvalue = 1; - - // - // Based on the sample rate, program the ADCSR register - // - if (outrate == 8000) - ADCSRvalue = 5; - if (outrate == 11025) - ADCSRvalue = 4; - else if (outrate == 22050) - ADCSRvalue = 2; - else if (outrate == 44100) - ADCSRvalue = 1; - else if ((outrate <= 48000) && (outrate >= 6023)) - ADCSRvalue = 24576000 / (outrate * 16); - else if (outrate < 6023) { - // Not allowed by open. - return; - } else if (outrate > 48000) { - // Not allowed by open. - return; - } - CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO - "cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n", - ADCSRvalue, outrate)); - // Write the 'sample rate select code - // to the 'ADC Sample Rate' register. - writel(ADCSRvalue, card->pBA0 + BA0_ADCSR); // (748h) -} - - - -static void stop_dac(struct cs4281_state *s) -{ - unsigned long flags; - unsigned temp1; - - CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: stop_dac():\n")); - spin_lock_irqsave(&s->lock, flags); - s->ena &= ~FMODE_WRITE; - temp1 = readl(s->pBA0 + BA0_DCR0) | DCRn_MSK; - writel(temp1, s->pBA0 + BA0_DCR0); - - spin_unlock_irqrestore(&s->lock, flags); -} - - -static void start_dac(struct cs4281_state *s) -{ - unsigned long flags; - unsigned temp1; - - CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4281: start_dac()+\n")); - spin_lock_irqsave(&s->lock, flags); - if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || - (s->dma_dac.count > 0 - && s->dma_dac.ready)) -#ifndef NOT_CS4281_PM - && (s->pm.flags & CS4281_PM_IDLE)) -#else -) -#endif - { - s->ena |= FMODE_WRITE; - temp1 = readl(s->pBA0 + BA0_DCR0) & ~DCRn_MSK; // Clear DMA0 channel mask. - writel(temp1, s->pBA0 + BA0_DCR0); // Start DMA'ing. - writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts. - - writel(7, s->pBA0 + BA0_PPRVC); - writel(7, s->pBA0 + BA0_PPLVC); - CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO - "cs4281: start_dac(): writel 0x%x start dma\n", temp1)); - - } - spin_unlock_irqrestore(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION, 3, - printk(KERN_INFO "cs4281: start_dac()-\n")); -} - - -static void stop_adc(struct cs4281_state *s) -{ - unsigned long flags; - unsigned temp1; - - CS_DBGOUT(CS_FUNCTION, 3, - printk(KERN_INFO "cs4281: stop_adc()+\n")); - - spin_lock_irqsave(&s->lock, flags); - s->ena &= ~FMODE_READ; - - if (s->conversion == 1) { - s->conversion = 0; - s->prop_adc.fmt = s->prop_adc.fmt_original; - } - temp1 = readl(s->pBA0 + BA0_DCR1) | DCRn_MSK; - writel(temp1, s->pBA0 + BA0_DCR1); - spin_unlock_irqrestore(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION, 3, - printk(KERN_INFO "cs4281: stop_adc()-\n")); -} - - -static void start_adc(struct cs4281_state *s) -{ - unsigned long flags; - unsigned temp1; - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: start_adc()+\n")); - - if (!(s->ena & FMODE_READ) && - (s->dma_adc.mapped || s->dma_adc.count <= - (signed) (s->dma_adc.dmasize - 2 * s->dma_adc.fragsize)) - && s->dma_adc.ready -#ifndef NOT_CS4281_PM - && (s->pm.flags & CS4281_PM_IDLE)) -#else -) -#endif - { - if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) { - // - // now only use 16 bit capture, due to truncation issue - // in the chip, noticable distortion occurs. - // allocate buffer and then convert from 16 bit to - // 8 bit for the user buffer. - // - s->prop_adc.fmt_original = s->prop_adc.fmt; - if (s->prop_adc.fmt & AFMT_S8) { - s->prop_adc.fmt &= ~AFMT_S8; - s->prop_adc.fmt |= AFMT_S16_LE; - } - if (s->prop_adc.fmt & AFMT_U8) { - s->prop_adc.fmt &= ~AFMT_U8; - s->prop_adc.fmt |= AFMT_U16_LE; - } - // - // prog_dmabuf_adc performs a stop_adc() but that is - // ok since we really haven't started the DMA yet. - // - prog_codec(s, CS_TYPE_ADC); - - if (prog_dmabuf_adc(s) != 0) { - CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO - "cs4281: start_adc(): error in prog_dmabuf_adc\n")); - } - s->conversion = 1; - } - spin_lock_irqsave(&s->lock, flags); - s->ena |= FMODE_READ; - temp1 = readl(s->pBA0 + BA0_DCR1) & ~DCRn_MSK; // Clear DMA1 channel mask bit. - writel(temp1, s->pBA0 + BA0_DCR1); // Start recording - writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts. - spin_unlock_irqrestore(&s->lock, flags); - - CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO - "cs4281: start_adc(): writel 0x%x \n", temp1)); - } - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: start_adc()-\n")); - -} - - -// --------------------------------------------------------------------- - -#define DMABUF_MINORDER 1 // ==> min buffer size = 8K. - - -static void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db) -{ - struct page *map, *mapend; - - if (db->rawbuf) { - // Undo prog_dmabuf()'s marking the pages as reserved - mapend = - virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - - 1); - for (map = virt_to_page(db->rawbuf); map <= mapend; map++) - ClearPageReserved(map); - free_dmabuf(s, db); - } - if (s->tmpbuff && (db->type == CS_TYPE_ADC)) { - // Undo prog_dmabuf()'s marking the pages as reserved - mapend = - virt_to_page(s->tmpbuff + - (PAGE_SIZE << s->buforder_tmpbuff) - 1); - for (map = virt_to_page(s->tmpbuff); map <= mapend; map++) - ClearPageReserved(map); - free_dmabuf2(s, db); - } - s->tmpbuff = NULL; - db->rawbuf = NULL; - db->mapped = db->ready = 0; -} - -static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db) -{ - int order; - unsigned bytespersec, temp1; - unsigned bufs, sample_shift = 0; - struct page *map, *mapend; - unsigned long df; - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: prog_dmabuf()+\n")); - db->hwptr = db->swptr = db->total_bytes = db->count = db->error = - db->endcleared = db->blocks = db->wakeup = db->underrun = 0; -/* -* check for order within limits, but do not overwrite value, check -* later for a fractional defaultorder (i.e. 100+). -*/ - if((defaultorder > 0) && (defaultorder < 12)) - df = defaultorder; - else - df = 1; - - if (!db->rawbuf) { - db->ready = db->mapped = 0; - for (order = df; order >= DMABUF_MINORDER; order--) - if ( (db->rawbuf = (void *) pci_alloc_consistent( - s->pcidev, PAGE_SIZE << order, &db-> dmaaddr))) - break; - if (!db->rawbuf) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4281: prog_dmabuf(): unable to allocate rawbuf\n")); - return -ENOMEM; - } - db->buforder = order; - // Now mark the pages as reserved; otherwise the - // remap_pfn_range() in cs4281_mmap doesn't work. - // 1. get index to last page in mem_map array for rawbuf. - mapend = virt_to_page(db->rawbuf + - (PAGE_SIZE << db->buforder) - 1); - - // 2. mark each physical page in range as 'reserved'. - for (map = virt_to_page(db->rawbuf); map <= mapend; map++) - SetPageReserved(map); - } - if (!s->tmpbuff && (db->type == CS_TYPE_ADC)) { - for (order = df; order >= DMABUF_MINORDER; - order--) - if ( (s->tmpbuff = (void *) pci_alloc_consistent( - s->pcidev, PAGE_SIZE << order, - &s->dmaaddr_tmpbuff))) - break; - if (!s->tmpbuff) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4281: prog_dmabuf(): unable to allocate tmpbuff\n")); - return -ENOMEM; - } - s->buforder_tmpbuff = order; - // Now mark the pages as reserved; otherwise the - // remap_pfn_range() in cs4281_mmap doesn't work. - // 1. get index to last page in mem_map array for rawbuf. - mapend = virt_to_page(s->tmpbuff + - (PAGE_SIZE << s->buforder_tmpbuff) - 1); - - // 2. mark each physical page in range as 'reserved'. - for (map = virt_to_page(s->tmpbuff); map <= mapend; map++) - SetPageReserved(map); - } - if (db->type == CS_TYPE_DAC) { - if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE)) - sample_shift++; - if (s->prop_dac.channels > 1) - sample_shift++; - bytespersec = s->prop_dac.rate << sample_shift; - } else // CS_TYPE_ADC - { - if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE)) - sample_shift++; - if (s->prop_adc.channels > 1) - sample_shift++; - bytespersec = s->prop_adc.rate << sample_shift; - } - bufs = PAGE_SIZE << db->buforder; - -/* -* added fractional "defaultorder" inputs. if >100 then use -* defaultorder-100 as power of 2 for the buffer size. example: -* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size. -*/ - if(defaultorder >= 100) - { - bufs = 1 << (defaultorder-100); - } - -#define INTERRUPT_RATE_MS 100 // Interrupt rate in milliseconds. - db->numfrag = 2; -/* -* Nominal frag size(bytes/interrupt) -*/ - temp1 = bytespersec / (1000 / INTERRUPT_RATE_MS); - db->fragshift = 8; // Min 256 bytes. - while (1 << db->fragshift < temp1) // Calc power of 2 frag size. - db->fragshift += 1; - db->fragsize = 1 << db->fragshift; - db->dmasize = db->fragsize * 2; - db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment. - -// If the calculated size is larger than the allocated -// buffer, divide the allocated buffer into 2 fragments. - if (db->dmasize > bufs) { - - db->numfrag = 2; // Two fragments. - db->fragsize = bufs >> 1; // Each 1/2 the alloc'ed buffer. - db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment. - db->dmasize = bufs; // Use all the alloc'ed buffer. - - db->fragshift = 0; // Calculate 'fragshift'. - temp1 = db->fragsize; // update_ptr() uses it - while ((temp1 >>= 1) > 1) // to calc 'total-bytes' - db->fragshift += 1; // returned in DSP_GETI/OPTR. - } - CS_DBGOUT(CS_PARMS, 3, printk(KERN_INFO - "cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d bufs=%d fmt=0x%x ch=%d\n", - db->numfrag, db->fragsize, db->fragsamples, - db->fragshift, bufs, - (db->type == CS_TYPE_DAC) ? s->prop_dac.fmt : - s->prop_adc.fmt, - (db->type == CS_TYPE_DAC) ? s->prop_dac.channels : - s->prop_adc.channels)); - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: prog_dmabuf()-\n")); - return 0; -} - - -static int prog_dmabuf_adc(struct cs4281_state *s) -{ - unsigned long va; - unsigned count; - int c; - stop_adc(s); - s->dma_adc.type = CS_TYPE_ADC; - if ((c = prog_dmabuf(s, &s->dma_adc))) - return c; - - if (s->dma_adc.rawbuf) { - memset(s->dma_adc.rawbuf, - (s->prop_adc. - fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, - s->dma_adc.dmasize); - } - if (s->tmpbuff) { - memset(s->tmpbuff, - (s->prop_adc. - fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, - PAGE_SIZE << s->buforder_tmpbuff); - } - - va = virt_to_bus(s->dma_adc.rawbuf); - - count = s->dma_adc.dmasize; - - if (s->prop_adc. - fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) - count /= 2; // 16-bit. - - if (s->prop_adc.channels > 1) - count /= 2; // Assume stereo. - - CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO - "cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n", - count, (unsigned) va)); - - writel(va, s->pBA0 + BA0_DBA1); // Set buffer start address. - writel(count - 1, s->pBA0 + BA0_DBC1); // Set count. - s->dma_adc.ready = 1; - return 0; -} - - -static int prog_dmabuf_dac(struct cs4281_state *s) -{ - unsigned long va; - unsigned count; - int c; - stop_dac(s); - s->dma_dac.type = CS_TYPE_DAC; - if ((c = prog_dmabuf(s, &s->dma_dac))) - return c; - memset(s->dma_dac.rawbuf, - (s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, - s->dma_dac.dmasize); - - va = virt_to_bus(s->dma_dac.rawbuf); - - count = s->dma_dac.dmasize; - if (s->prop_dac. - fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) - count /= 2; // 16-bit. - - if (s->prop_dac.channels > 1) - count /= 2; // Assume stereo. - - writel(va, s->pBA0 + BA0_DBA0); // Set buffer start address. - writel(count - 1, s->pBA0 + BA0_DBC0); // Set count. - - CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO - "cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n", - count, (unsigned) va)); - - s->dma_dac.ready = 1; - return 0; -} - - -static void clear_advance(void *buf, unsigned bsize, unsigned bptr, - unsigned len, unsigned char c) -{ - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(((char *) buf) + bptr, c, x); - bptr = 0; - len -= x; - } - CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO - "cs4281: clear_advance(): memset %d at %p for %d size \n", - (unsigned)c, ((char *) buf) + bptr, len)); - memset(((char *) buf) + bptr, c, len); -} - - - -// call with spinlock held! -static void cs4281_update_ptr(struct cs4281_state *s, int intflag) -{ - int diff; - unsigned hwptr, va; - - // update ADC pointer - if (s->ena & FMODE_READ) { - hwptr = readl(s->pBA0 + BA0_DCA1); // Read capture DMA address. - va = virt_to_bus(s->dma_adc.rawbuf); - hwptr -= (unsigned) va; - diff = - (s->dma_adc.dmasize + hwptr - - s->dma_adc.hwptr) % s->dma_adc.dmasize; - s->dma_adc.hwptr = hwptr; - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; - if (s->dma_adc.count > s->dma_adc.dmasize) - s->dma_adc.count = s->dma_adc.dmasize; - if (s->dma_adc.mapped) { - if (s->dma_adc.count >= - (signed) s->dma_adc.fragsize) wake_up(&s-> - dma_adc. - wait); - } else { - if (s->dma_adc.count > 0) - wake_up(&s->dma_adc.wait); - } - CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO - "cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n", - s, s->dma_adc.hwptr, s->dma_adc.total_bytes, s->dma_adc.count)); - } - // update DAC pointer - // - // check for end of buffer, means that we are going to wait for another interrupt - // to allow silence to fill the fifos on the part, to keep pops down to a minimum. - // - if (s->ena & FMODE_WRITE) { - hwptr = readl(s->pBA0 + BA0_DCA0); // Read play DMA address. - va = virt_to_bus(s->dma_dac.rawbuf); - hwptr -= (unsigned) va; - diff = (s->dma_dac.dmasize + hwptr - - s->dma_dac.hwptr) % s->dma_dac.dmasize; - s->dma_dac.hwptr = hwptr; - s->dma_dac.total_bytes += diff; - if (s->dma_dac.mapped) { - s->dma_dac.count += diff; - if (s->dma_dac.count >= s->dma_dac.fragsize) { - s->dma_dac.wakeup = 1; - wake_up(&s->dma_dac.wait); - if (s->dma_dac.count > s->dma_dac.dmasize) - s->dma_dac.count &= - s->dma_dac.dmasize - 1; - } - } else { - s->dma_dac.count -= diff; - if (s->dma_dac.count <= 0) { - // - // fill with silence, and do not shut down the DAC. - // Continue to play silence until the _release. - // - CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO - "cs4281: cs4281_update_ptr(): memset %d at %p for %d size \n", - (unsigned)(s->prop_dac.fmt & - (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, - s->dma_dac.rawbuf, s->dma_dac.dmasize)); - memset(s->dma_dac.rawbuf, - (s->prop_dac. - fmt & (AFMT_U8 | AFMT_U16_LE)) ? - 0x80 : 0, s->dma_dac.dmasize); - if (s->dma_dac.count < 0) { - s->dma_dac.underrun = 1; - s->dma_dac.count = 0; - CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO - "cs4281: cs4281_update_ptr(): underrun\n")); - } - } else if (s->dma_dac.count <= - (signed) s->dma_dac.fragsize - && !s->dma_dac.endcleared) { - clear_advance(s->dma_dac.rawbuf, - s->dma_dac.dmasize, - s->dma_dac.swptr, - s->dma_dac.fragsize, - (s->prop_dac. - fmt & (AFMT_U8 | - AFMT_U16_LE)) ? 0x80 - : 0); - s->dma_dac.endcleared = 1; - } - if ( (s->dma_dac.count <= (signed) s->dma_dac.dmasize/2) || - intflag) - { - wake_up(&s->dma_dac.wait); - } - } - CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO - "cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n", - s, s->dma_dac.hwptr, s->dma_dac.total_bytes, s->dma_dac.count)); - } -} - - -// --------------------------------------------------------------------- - -static void prog_codec(struct cs4281_state *s, unsigned type) -{ - unsigned long flags; - unsigned temp1, format; - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: prog_codec()+ \n")); - - spin_lock_irqsave(&s->lock, flags); - if (type == CS_TYPE_ADC) { - temp1 = readl(s->pBA0 + BA0_DCR1); - writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR1); // Stop capture DMA, if active. - - // program sampling rates - // Note, for CS4281, capture & play rates can be set independently. - cs4281_record_rate(s, s->prop_adc.rate); - - // program ADC parameters - format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE; - if (s->prop_adc. - fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit - if (s->prop_adc.fmt & (AFMT_S16_BE | AFMT_U16_BE)) // Big-endian? - format |= DMRn_BEND; - if (s->prop_adc.fmt & (AFMT_U16_LE | AFMT_U16_BE)) - format |= DMRn_USIGN; // Unsigned. - } else - format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned - if (s->prop_adc.channels < 2) - format |= DMRn_MONO; - - writel(format, s->pBA0 + BA0_DMR1); - - CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO - "cs4281: prog_codec(): adc %s %s %s rate=%d DMR0 format=0x%.8x\n", - (format & DMRn_SIZE8) ? "8" : "16", - (format & DMRn_USIGN) ? "Unsigned" : "Signed", - (format & DMRn_MONO) ? "Mono" : "Stereo", - s->prop_adc.rate, format)); - - s->ena &= ~FMODE_READ; // not capturing data yet - } - - - if (type == CS_TYPE_DAC) { - temp1 = readl(s->pBA0 + BA0_DCR0); - writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR0); // Stop play DMA, if active. - - // program sampling rates - // Note, for CS4281, capture & play rates can be set independently. - cs4281_play_rate(s, s->prop_dac.rate); - - // program DAC parameters - format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ; - if (s->prop_dac. - fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit - if (s->prop_dac.fmt & (AFMT_S16_BE | AFMT_U16_BE)) - format |= DMRn_BEND; // Big Endian. - if (s->prop_dac.fmt & (AFMT_U16_LE | AFMT_U16_BE)) - format |= DMRn_USIGN; // Unsigned. - } else - format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned - - if (s->prop_dac.channels < 2) - format |= DMRn_MONO; - - writel(format, s->pBA0 + BA0_DMR0); - - - CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO - "cs4281: prog_codec(): dac %s %s %s rate=%d DMR0 format=0x%.8x\n", - (format & DMRn_SIZE8) ? "8" : "16", - (format & DMRn_USIGN) ? "Unsigned" : "Signed", - (format & DMRn_MONO) ? "Mono" : "Stereo", - s->prop_dac.rate, format)); - - s->ena &= ~FMODE_WRITE; // not capturing data yet - - } - spin_unlock_irqrestore(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: prog_codec()- \n")); -} - - -static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, - unsigned long arg) -{ - // Index to mixer_src[] is value of AC97 Input Mux Select Reg. - // Value of array member is recording source Device ID Mask. - static const unsigned int mixer_src[8] = { - SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1, - SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0 - }; - void __user *argp = (void __user *)arg; - - // Index of mixtable1[] member is Device ID - // and must be <= SOUND_MIXER_NRDEVICES. - // Value of array member is index into s->mix.vol[] - static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_PCM] = 1, // voice - [SOUND_MIXER_LINE1] = 2, // AUX - [SOUND_MIXER_CD] = 3, // CD - [SOUND_MIXER_LINE] = 4, // Line - [SOUND_MIXER_SYNTH] = 5, // FM - [SOUND_MIXER_MIC] = 6, // Mic - [SOUND_MIXER_SPEAKER] = 7, // Speaker - [SOUND_MIXER_RECLEV] = 8, // Recording level - [SOUND_MIXER_VOLUME] = 9 // Master Volume - }; - - - static const unsigned mixreg[] = { - BA0_AC97_PCM_OUT_VOLUME, - BA0_AC97_AUX_VOLUME, - BA0_AC97_CD_VOLUME, - BA0_AC97_LINE_IN_VOLUME - }; - unsigned char l, r, rl, rr, vidx; - unsigned char attentbl[11] = - { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 }; - unsigned temp1; - int i, val; - - VALIDATE_STATE(s); - CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO - "cs4281: mixer_ioctl(): s=%p cmd=0x%.8x\n", s, cmd)); -#if CSDEBUG - cs_printioctl(cmd); -#endif -#if CSDEBUG_INTERFACE - - if ((cmd == SOUND_MIXER_CS_GETDBGMASK) || - (cmd == SOUND_MIXER_CS_SETDBGMASK) || - (cmd == SOUND_MIXER_CS_GETDBGLEVEL) || - (cmd == SOUND_MIXER_CS_SETDBGLEVEL) || - (cmd == SOUND_MIXER_CS_APM)) - { - switch (cmd) { - - case SOUND_MIXER_CS_GETDBGMASK: - return put_user(cs_debugmask, - (unsigned long __user *) argp); - - case SOUND_MIXER_CS_GETDBGLEVEL: - return put_user(cs_debuglevel, - (unsigned long __user *) argp); - - case SOUND_MIXER_CS_SETDBGMASK: - if (get_user(val, (unsigned long __user *) argp)) - return -EFAULT; - cs_debugmask = val; - return 0; - - case SOUND_MIXER_CS_SETDBGLEVEL: - if (get_user(val, (unsigned long __user *) argp)) - return -EFAULT; - cs_debuglevel = val; - return 0; -#ifndef NOT_CS4281_PM - case SOUND_MIXER_CS_APM: - if (get_user(val, (unsigned long __user *) argp)) - return -EFAULT; - if(val == CS_IOCTL_CMD_SUSPEND) - cs4281_suspend(s); - else if(val == CS_IOCTL_CMD_RESUME) - cs4281_resume(s); - else - { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO - "cs4281: mixer_ioctl(): invalid APM cmd (%d)\n", - val)); - } - return 0; -#endif - default: - CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO - "cs4281: mixer_ioctl(): ERROR unknown debug cmd\n")); - return 0; - } - } -#endif - - if (cmd == SOUND_MIXER_PRIVATE1) { - // enable/disable/query mixer preamp - if (get_user(val, (int __user *) argp)) - return -EFAULT; - if (val != -1) { - cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1); - temp1 = val ? (temp1 | 0x40) : (temp1 & 0xffbf); - cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1); - } - cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1); - val = (temp1 & 0x40) ? 1 : 0; - return put_user(val, (int __user *) argp); - } - if (cmd == SOUND_MIXER_PRIVATE2) { - // enable/disable/query spatializer - if (get_user(val, (int __user *)argp)) - return -EFAULT; - if (val != -1) { - temp1 = (val & 0x3f) >> 2; - cs4281_write_ac97(s, BA0_AC97_3D_CONTROL, temp1); - cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE, - &temp1); - cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE, - temp1 | 0x2000); - } - cs4281_read_ac97(s, BA0_AC97_3D_CONTROL, &temp1); - return put_user((temp1 << 2) | 3, (int __user *)argp); - } - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - strlcpy(info.id, "CS4281", sizeof(info.id)); - strlcpy(info.name, "Crystal CS4281", sizeof(info.name)); - info.modify_counter = s->mix.modcnt; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - strlcpy(info.id, "CS4281", sizeof(info.id)); - strlcpy(info.name, "Crystal CS4281", sizeof(info.name)); - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int __user *) argp); - - if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - - // If ioctl has only the SIOC_READ bit(bit 31) - // on, process the only-read commands. - if (_SIOC_DIR(cmd) == _SIOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source - cs4281_read_ac97(s, BA0_AC97_RECORD_SELECT, &temp1); - return put_user(mixer_src[temp1&7], (int __user *)argp); - - case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device - return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | - SOUND_MASK_CD | SOUND_MASK_LINE | - SOUND_MASK_LINE1 | SOUND_MASK_MIC | - SOUND_MASK_VOLUME | - SOUND_MASK_RECLEV | - SOUND_MASK_SPEAKER, (int __user *)argp); - - case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source - return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | - SOUND_MASK_CD | SOUND_MASK_VOLUME | - SOUND_MASK_LINE1, (int __user *) argp); - - case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo - return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | - SOUND_MASK_CD | SOUND_MASK_LINE | - SOUND_MASK_LINE1 | SOUND_MASK_MIC | - SOUND_MASK_VOLUME | - SOUND_MASK_RECLEV, (int __user *)argp); - - case SOUND_MIXER_CAPS: - return put_user(SOUND_CAP_EXCL_INPUT, (int __user *)argp); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES - || !(vidx = mixtable1[i])) - return -EINVAL; - return put_user(s->mix.vol[vidx - 1], (int __user *)argp); - } - } - // If ioctl doesn't have both the SIOC_READ and - // the SIOC_WRITE bit set, return invalid. - if (_SIOC_DIR(cmd) != (_SIOC_READ | _SIOC_WRITE)) - return -EINVAL; - - // Increment the count of volume writes. - s->mix.modcnt++; - - // Isolate the command; it must be a write. - switch (_IOC_NR(cmd)) { - - case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source - if (get_user(val, (int __user *)argp)) - return -EFAULT; - i = hweight32(val); // i = # bits on in val. - if (i != 1) // One & only 1 bit must be on. - return 0; - for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) { - if (val == mixer_src[i]) { - temp1 = (i << 8) | i; - cs4281_write_ac97(s, - BA0_AC97_RECORD_SELECT, - temp1); - return 0; - } - } - return 0; - - case SOUND_MIXER_VOLUME: - if (get_user(val, (int __user *)argp)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; // Max soundcard.h vol is 100. - if (l < 6) { - rl = 63; - l = 0; - } else - rl = attentbl[(10 * l) / 100]; // Convert 0-100 vol to 63-0 atten. - - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; // Max right volume is 100, too - if (r < 6) { - rr = 63; - r = 0; - } else - rr = attentbl[(10 * r) / 100]; // Convert volume to attenuation. - - if ((rl > 60) && (rr > 60)) // If both l & r are 'low', - temp1 = 0x8000; // turn on the mute bit. - else - temp1 = 0; - - temp1 |= (rl << 8) | rr; - - cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, temp1); - cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[8] = ((unsigned int) r << 8) | l; -#else - s->mix.vol[8] = val; -#endif - return put_user(s->mix.vol[8], (int __user *)argp); - - case SOUND_MIXER_SPEAKER: - if (get_user(val, (int __user *)argp)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (l < 3) { - rl = 0; - l = 0; - } else { - rl = (l * 2 - 5) / 13; // Convert 0-100 range to 0-15. - l = (rl * 13 + 5) / 2; - } - - if (rl < 3) { - temp1 = 0x8000; - rl = 0; - } else - temp1 = 0; - rl = 15 - rl; // Convert volume to attenuation. - temp1 |= rl << 1; - cs4281_write_ac97(s, BA0_AC97_PC_BEEP_VOLUME, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[6] = l << 8; -#else - s->mix.vol[6] = val; -#endif - return put_user(s->mix.vol[6], (int __user *)argp); - - case SOUND_MIXER_RECLEV: - if (get_user(val, (int __user *)argp)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - rl = (l * 2 - 5) / 13; // Convert 0-100 scale to 0-15. - rr = (r * 2 - 5) / 13; - if (rl < 3 && rr < 3) - temp1 = 0x8000; - else - temp1 = 0; - - temp1 = temp1 | (rl << 8) | rr; - cs4281_write_ac97(s, BA0_AC97_RECORD_GAIN, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[7] = ((unsigned int) r << 8) | l; -#else - s->mix.vol[7] = val; -#endif - return put_user(s->mix.vol[7], (int __user *)argp); - - case SOUND_MIXER_MIC: - if (get_user(val, (int __user *)argp)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (l < 1) { - l = 0; - rl = 0; - } else { - rl = ((unsigned) l * 5 - 4) / 16; // Convert 0-100 range to 0-31. - l = (rl * 16 + 4) / 5; - } - cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1); - temp1 &= 0x40; // Isolate 20db gain bit. - if (rl < 3) { - temp1 |= 0x8000; - rl = 0; - } - rl = 31 - rl; // Convert volume to attenuation. - temp1 |= rl; - cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[5] = val << 8; -#else - s->mix.vol[5] = val; -#endif - return put_user(s->mix.vol[5], (int __user *)argp); - - - case SOUND_MIXER_SYNTH: - if (get_user(val, (int __user *)argp)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (get_user(val, (int __user *)argp)) - return -EFAULT; - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - rl = (l * 2 - 11) / 3; // Convert 0-100 range to 0-63. - rr = (r * 2 - 11) / 3; - if (rl < 3) // If l is low, turn on - temp1 = 0x0080; // the mute bit. - else - temp1 = 0; - - rl = 63 - rl; // Convert vol to attenuation. - writel(temp1 | rl, s->pBA0 + BA0_FMLVC); - if (rr < 3) // If rr is low, turn on - temp1 = 0x0080; // the mute bit. - else - temp1 = 0; - rr = 63 - rr; // Convert vol to attenuation. - writel(temp1 | rr, s->pBA0 + BA0_FMRVC); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[4] = (r << 8) | l; -#else - s->mix.vol[4] = val; -#endif - return put_user(s->mix.vol[4], (int __user *)argp); - - - default: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4281: mixer_ioctl(): default\n")); - - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) - return -EINVAL; - if (get_user(val, (int __user *)argp)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (l < 1) { - l = 0; - rl = 31; - } else - rl = (attentbl[(l * 10) / 100]) >> 1; - - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - if (r < 1) { - r = 0; - rr = 31; - } else - rr = (attentbl[(r * 10) / 100]) >> 1; - if ((rl > 30) && (rr > 30)) - temp1 = 0x8000; - else - temp1 = 0; - temp1 = temp1 | (rl << 8) | rr; - cs4281_write_ac97(s, mixreg[vidx - 1], temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[vidx - 1] = ((unsigned int) r << 8) | l; -#else - s->mix.vol[vidx - 1] = val; -#endif -#ifndef NOT_CS4281_PM - CS_DBGOUT(CS_PM, 9, printk(KERN_INFO - "write ac97 mixreg[%d]=0x%x mix.vol[]=0x%x\n", - vidx-1,temp1,s->mix.vol[vidx-1])); -#endif - return put_user(s->mix.vol[vidx - 1], (int __user *)argp); - } -} - - -// --------------------------------------------------------------------- - -static int cs4281_open_mixdev(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct cs4281_state *s=NULL; - struct list_head *entry; - - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, - printk(KERN_INFO "cs4281: cs4281_open_mixdev()+\n")); - - list_for_each(entry, &cs4281_devs) - { - s = list_entry(entry, struct cs4281_state, list); - if(s->dev_mixer == minor) - break; - } - if (!s) - { - CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, - printk(KERN_INFO "cs4281: cs4281_open_mixdev()- -ENODEV\n")); - return -ENODEV; - } - VALIDATE_STATE(s); - file->private_data = s; - - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, - printk(KERN_INFO "cs4281: cs4281_open_mixdev()- 0\n")); - - return nonseekable_open(inode, file); -} - - -static int cs4281_release_mixdev(struct inode *inode, struct file *file) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - - VALIDATE_STATE(s); - return 0; -} - - -static int cs4281_ioctl_mixdev(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return mixer_ioctl((struct cs4281_state *) file->private_data, cmd, - arg); -} - - -// ****************************************************************************************** -// Mixer file operations struct. -// ****************************************************************************************** -static /*const */ struct file_operations cs4281_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = cs4281_ioctl_mixdev, - .open = cs4281_open_mixdev, - .release = cs4281_release_mixdev, -}; - -// --------------------------------------------------------------------- - - -static int drain_adc(struct cs4281_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count; - unsigned tmo; - - if (s->dma_adc.mapped) - return 0; - add_wait_queue(&s->dma_adc.wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_adc.count; - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: drain_adc() %d\n", count)); - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) { - CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO - "cs4281: drain_adc() count<0\n")); - break; - } - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_adc.wait, &wait); - current->state = TASK_RUNNING; - return -EBUSY; - } - tmo = - 3 * HZ * (count + - s->dma_adc.fragsize) / 2 / s->prop_adc.rate; - if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE)) - tmo >>= 1; - if (s->prop_adc.channels > 1) - tmo >>= 1; - if (!schedule_timeout(tmo + 1)) - printk(KERN_DEBUG "cs4281: dma timed out??\n"); - } - remove_wait_queue(&s->dma_adc.wait, &wait); - current->state = TASK_RUNNING; - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -static int drain_dac(struct cs4281_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count; - unsigned tmo; - - if (s->dma_dac.mapped) - return 0; - add_wait_queue(&s->dma_dac.wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; - return -EBUSY; - } - tmo = - 3 * HZ * (count + - s->dma_dac.fragsize) / 2 / s->prop_dac.rate; - if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE)) - tmo >>= 1; - if (s->prop_dac.channels > 1) - tmo >>= 1; - if (!schedule_timeout(tmo + 1)) - printk(KERN_DEBUG "cs4281: dma timed out??\n"); - } - remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -//**************************************************************************** -// -// CopySamples copies 16-bit stereo samples from the source to the -// destination, possibly converting down to either 8-bit or mono or both. -// count specifies the number of output bytes to write. -// -// Arguments: -// -// dst - Pointer to a destination buffer. -// src - Pointer to a source buffer -// count - The number of bytes to copy into the destination buffer. -// iChannels - Stereo - 2 -// Mono - 1 -// fmt - AFMT_xxx (soundcard.h formats) -// -// NOTES: only call this routine for conversion to 8bit from 16bit -// -//**************************************************************************** -static void CopySamples(char *dst, char *src, int count, int iChannels, - unsigned fmt) -{ - - unsigned short *psSrc; - long lAudioSample; - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: CopySamples()+ ")); - CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO - " dst=%p src=%p count=%d iChannels=%d fmt=0x%x\n", - dst, src, (unsigned) count, (unsigned) iChannels, (unsigned) fmt)); - - // Gershwin does format conversion in hardware so normally - // we don't do any host based coversion. The data formatter - // truncates 16 bit data to 8 bit and that causes some hiss. - // We have already forced the HW to do 16 bit sampling and - // 2 channel so that we can use software to round instead - // of truncate - - // - // See if the data should be output as 8-bit unsigned stereo. - // or if the data should be output at 8-bit unsigned mono. - // - if ( ((iChannels == 2) && (fmt & AFMT_U8)) || - ((iChannels == 1) && (fmt & AFMT_U8)) ) { - // - // Convert each 16-bit unsigned stereo sample to 8-bit unsigned - // stereo using rounding. - // - psSrc = (unsigned short *) src; - count = count / 2; - while (count--) { - lAudioSample = (long) psSrc[count] + (long) 0x80; - if (lAudioSample > 0xffff) { - lAudioSample = 0xffff; - } - dst[count] = (char) (lAudioSample >> 8); - } - } - // - // check for 8-bit signed stereo. - // - else if ((iChannels == 2) && (fmt & AFMT_S8)) { - // - // Convert each 16-bit stereo sample to 8-bit stereo using rounding. - // - psSrc = (short *) src; - while (count--) { - lAudioSample = - (((long) psSrc[0] + (long) psSrc[1]) / 2); - psSrc += 2; - *dst++ = (char) ((short) lAudioSample >> 8); - } - } - // - // Otherwise, the data should be output as 8-bit signed mono. - // - else if ((iChannels == 1) && (fmt & AFMT_S8)) { - // - // Convert each 16-bit signed mono sample to 8-bit signed mono - // using rounding. - // - psSrc = (short *) src; - count = count / 2; - while (count--) { - lAudioSample = - (((long) psSrc[0] + (long) psSrc[1]) / 2); - if (lAudioSample > 0x7fff) { - lAudioSample = 0x7fff; - } - psSrc += 2; - *dst++ = (char) ((short) lAudioSample >> 8); - } - } -} - -// -// cs_copy_to_user() -// replacement for the standard copy_to_user, to allow for a conversion from -// 16 bit to 8 bit if the record conversion is active. the cs4281 has some -// issues with 8 bit capture, so the driver always captures data in 16 bit -// and then if the user requested 8 bit, converts from 16 to 8 bit. -// -static unsigned cs_copy_to_user(struct cs4281_state *s, void __user *dest, - unsigned *hwsrc, unsigned cnt, - unsigned *copied) -{ - void *src = hwsrc; //default to the standard destination buffer addr - - CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO - "cs_copy_to_user()+ fmt=0x%x fmt_o=0x%x cnt=%d dest=%p\n", - s->prop_adc.fmt, s->prop_adc.fmt_original, - (unsigned) cnt, dest)); - - if (cnt > s->dma_adc.dmasize) { - cnt = s->dma_adc.dmasize; - } - if (!cnt) { - *copied = 0; - return 0; - } - if (s->conversion) { - if (!s->tmpbuff) { - *copied = cnt / 2; - return 0; - } - CopySamples(s->tmpbuff, (void *) hwsrc, cnt, - (unsigned) s->prop_adc.channels, - s->prop_adc.fmt_original); - src = s->tmpbuff; - cnt = cnt / 2; - } - - if (copy_to_user(dest, src, cnt)) { - *copied = 0; - return -EFAULT; - } - *copied = cnt; - CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO - "cs4281: cs_copy_to_user()- copied bytes is %d \n", cnt)); - return 0; -} - -// --------------------------------------------------------------------- - -static ssize_t cs4281_read(struct file *file, char __user *buffer, size_t count, - loff_t * ppos) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - unsigned copied = 0; - - CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, - printk(KERN_INFO "cs4281: cs4281_read()+ %Zu \n", count)); - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; -// -// "count" is the amount of bytes to read (from app), is decremented each loop -// by the amount of bytes that have been returned to the user buffer. -// "cnt" is the running total of each read from the buffer (changes each loop) -// "buffer" points to the app's buffer -// "ret" keeps a running total of the amount of bytes that have been copied -// to the user buffer. -// "copied" is the total bytes copied into the user buffer for each loop. -// - while (count > 0) { - CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO - "_read() count>0 count=%Zu .count=%d .swptr=%d .hwptr=%d \n", - count, s->dma_adc.count, - s->dma_adc.swptr, s->dma_adc.hwptr)); - spin_lock_irqsave(&s->lock, flags); - - // get the current copy point of the sw buffer - swptr = s->dma_adc.swptr; - - // cnt is the amount of unread bytes from the end of the - // hw buffer to the current sw pointer - cnt = s->dma_adc.dmasize - swptr; - - // dma_adc.count is the current total bytes that have not been read. - // if the amount of unread bytes from the current sw pointer to the - // end of the buffer is greater than the current total bytes that - // have not been read, then set the "cnt" (unread bytes) to the - // amount of unread bytes. - - if (s->dma_adc.count < cnt) - cnt = s->dma_adc.count; - spin_unlock_irqrestore(&s->lock, flags); - // - // if we are converting from 8/16 then we need to copy - // twice the number of 16 bit bytes then 8 bit bytes. - // - if (s->conversion) { - if (cnt > (count * 2)) - cnt = (count * 2); - } else { - if (cnt > count) - cnt = count; - } - // - // "cnt" NOW is the smaller of the amount that will be read, - // and the amount that is requested in this read (or partial). - // if there are no bytes in the buffer to read, then start the - // ADC and wait for the interrupt handler to wake us up. - // - if (cnt <= 0) { - - // start up the dma engine and then continue back to the top of - // the loop when wake up occurs. - start_adc(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_adc.wait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; - continue; - } - // there are bytes in the buffer to read. - // copy from the hw buffer over to the user buffer. - // user buffer is designated by "buffer" - // virtual address to copy from is rawbuf+swptr - // the "cnt" is the number of bytes to read. - - CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO - "_read() copy_to cnt=%d count=%Zu ", cnt, count)); - CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO - " .dmasize=%d .count=%d buffer=%p ret=%Zd\n", - s->dma_adc.dmasize, s->dma_adc.count, buffer, ret)); - - if (cs_copy_to_user - (s, buffer, s->dma_adc.rawbuf + swptr, cnt, &copied)) - return ret ? ret : -EFAULT; - swptr = (swptr + cnt) % s->dma_adc.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_adc.swptr = swptr; - s->dma_adc.count -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= copied; - buffer += copied; - ret += copied; - start_adc(s); - } - CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, - printk(KERN_INFO "cs4281: cs4281_read()- %Zd\n", ret)); - return ret; -} - - -static ssize_t cs4281_write(struct file *file, const char __user *buffer, - size_t count, loff_t * ppos) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - ssize_t ret; - unsigned long flags; - unsigned swptr, hwptr, busaddr; - int cnt; - - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, - printk(KERN_INFO "cs4281: cs4281_write()+ count=%Zu\n", - count)); - VALIDATE_STATE(s); - - if (s->dma_dac.mapped) - return -ENXIO; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - if (s->dma_dac.count < 0) { - s->dma_dac.count = 0; - s->dma_dac.swptr = s->dma_dac.hwptr; - } - if (s->dma_dac.underrun) { - s->dma_dac.underrun = 0; - hwptr = readl(s->pBA0 + BA0_DCA0); - busaddr = virt_to_bus(s->dma_dac.rawbuf); - hwptr -= (unsigned) busaddr; - s->dma_dac.swptr = s->dma_dac.hwptr = hwptr; - } - swptr = s->dma_dac.swptr; - cnt = s->dma_dac.dmasize - swptr; - if (s->dma_dac.count + cnt > s->dma_dac.dmasize) - cnt = s->dma_dac.dmasize - s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - start_dac(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_dac.wait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; - continue; - } - if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) - return ret ? ret : -EFAULT; - swptr = (swptr + cnt) % s->dma_dac.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_dac.swptr = swptr; - s->dma_dac.count += cnt; - s->dma_dac.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - start_dac(s); - } - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, - printk(KERN_INFO "cs4281: cs4281_write()- %Zd\n", ret)); - return ret; -} - - -static unsigned int cs4281_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - unsigned long flags; - unsigned int mask = 0; - - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO "cs4281: cs4281_poll()+\n")); - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) { - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO - "cs4281: cs4281_poll() wait on FMODE_WRITE\n")); - if(!s->dma_dac.ready && prog_dmabuf_dac(s)) - return 0; - poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO - "cs4281: cs4281_poll() wait on FMODE_READ\n")); - if(!s->dma_dac.ready && prog_dmabuf_adc(s)) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= - (signed) s->dma_dac.fragsize) { - if (s->dma_dac.wakeup) - mask |= POLLOUT | POLLWRNORM; - else - mask = 0; - s->dma_dac.wakeup = 0; - } - } else { - if ((signed) (s->dma_dac.dmasize/2) >= s->dma_dac.count) - mask |= POLLOUT | POLLWRNORM; - } - } else if (file->f_mode & FMODE_READ) { - if (s->dma_adc.mapped) { - if (s->dma_adc.count >= (signed) s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } else { - if (s->dma_adc.count > 0) - mask |= POLLIN | POLLRDNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO "cs4281: cs4281_poll()- 0x%.8x\n", - mask)); - return mask; -} - - -static int cs4281_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - struct dmabuf *db; - int ret; - unsigned long size; - - CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4, - printk(KERN_INFO "cs4281: cs4281_mmap()+\n")); - - VALIDATE_STATE(s); - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf_dac(s)) != 0) - return ret; - db = &s->dma_dac; - } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf_adc(s)) != 0) - return ret; - db = &s->dma_adc; - } else - return -EINVAL; -// -// only support PLAYBACK for now -// - db = &s->dma_dac; - - if (cs4x_pgoff(vma) != 0) - return -EINVAL; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) - return -EINVAL; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - return -EAGAIN; - db->mapped = 1; - - CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4, - printk(KERN_INFO "cs4281: cs4281_mmap()- 0 size=%d\n", - (unsigned) size)); - - return 0; -} - - -static int cs4281_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int val, mapped, ret; - int __user *p = (int __user *)arg; - - CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): file=%p cmd=0x%.8x\n", file, cmd)); -#if CSDEBUG - cs_printioctl(cmd); -#endif - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): SOUND_VERSION=0x%.8x\n", - SOUND_VERSION)); - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): DSP_SYNC\n")); - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, - 0 /*file->f_flags & O_NONBLOCK */ - ); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | - DSP_CAP_TRIGGER | DSP_CAP_MMAP, - p); - - case SNDCTL_DSP_RESET: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): DSP_RESET\n")); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(s->irq); - s->dma_dac.swptr = s->dma_dac.hwptr = - s->dma_dac.count = s->dma_dac.total_bytes = - s->dma_dac.blocks = s->dma_dac.wakeup = 0; - prog_codec(s, CS_TYPE_DAC); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->irq); - s->dma_adc.swptr = s->dma_adc.hwptr = - s->dma_adc.count = s->dma_adc.total_bytes = - s->dma_adc.blocks = s->dma_dac.wakeup = 0; - prog_codec(s, CS_TYPE_ADC); - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): DSP_SPEED val=%d\n", val)); - // - // support independent capture and playback channels - // assume that the file mode bit determines the - // direction of the data flow. - // - if (file->f_mode & FMODE_READ) { - if (val >= 0) { - stop_adc(s); - s->dma_adc.ready = 0; - // program sampling rates - if (val > 48000) - val = 48000; - if (val < 6300) - val = 6300; - s->prop_adc.rate = val; - prog_codec(s, CS_TYPE_ADC); - } - } - if (file->f_mode & FMODE_WRITE) { - if (val >= 0) { - stop_dac(s); - s->dma_dac.ready = 0; - // program sampling rates - if (val > 48000) - val = 48000; - if (val < 6300) - val = 6300; - s->prop_dac.rate = val; - prog_codec(s, CS_TYPE_DAC); - } - } - - if (file->f_mode & FMODE_WRITE) - val = s->prop_dac.rate; - else if (file->f_mode & FMODE_READ) - val = s->prop_adc.rate; - - return put_user(val, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): DSP_STEREO val=%d\n", val)); - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - s->prop_adc.channels = val ? 2 : 1; - prog_codec(s, CS_TYPE_ADC); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - s->prop_dac.channels = val ? 2 : 1; - prog_codec(s, CS_TYPE_DAC); - } - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): DSP_CHANNELS val=%d\n", - val)); - if (val != 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val >= 2) - s->prop_adc.channels = 2; - else - s->prop_adc.channels = 1; - prog_codec(s, CS_TYPE_ADC); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val >= 2) - s->prop_dac.channels = 2; - else - s->prop_dac.channels = 1; - prog_codec(s, CS_TYPE_DAC); - } - } - - if (file->f_mode & FMODE_WRITE) - val = s->prop_dac.channels; - else if (file->f_mode & FMODE_READ) - val = s->prop_adc.channels; - - return put_user(val, p); - - case SNDCTL_DSP_GETFMTS: // Returns a mask - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): DSP_GETFMT val=0x%.8x\n", - AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 | - AFMT_U8)); - return put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 | - AFMT_U8, p); - - case SNDCTL_DSP_SETFMT: - if (get_user(val, p)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): DSP_SETFMT val=0x%.8x\n", - val)); - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val != AFMT_S16_LE - && val != AFMT_U16_LE && val != AFMT_S8 - && val != AFMT_U8) - val = AFMT_U8; - s->prop_adc.fmt = val; - s->prop_adc.fmt_original = s->prop_adc.fmt; - prog_codec(s, CS_TYPE_ADC); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val != AFMT_S16_LE - && val != AFMT_U16_LE && val != AFMT_S8 - && val != AFMT_U8) - val = AFMT_U8; - s->prop_dac.fmt = val; - s->prop_dac.fmt_original = s->prop_dac.fmt; - prog_codec(s, CS_TYPE_DAC); - } - } else { - if (file->f_mode & FMODE_WRITE) - val = s->prop_dac.fmt_original; - else if (file->f_mode & FMODE_READ) - val = s->prop_adc.fmt_original; - } - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): DSP_SETFMT return val=0x%.8x\n", - val)); - return put_user(val, p); - - case SNDCTL_DSP_POST: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): DSP_POST\n")); - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if (file->f_mode & s->ena & FMODE_READ) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & s->ena & FMODE_WRITE) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready - && (ret = prog_dmabuf_adc(s))) - return ret; - start_adc(s); - } else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac.ready - && (ret = prog_dmabuf_dac(s))) - return ret; - start_dac(s); - } else - stop_dac(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s))) - return val; - spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); - abinfo.fragsize = s->dma_dac.fragsize; - if (s->dma_dac.mapped) - abinfo.bytes = s->dma_dac.dmasize; - else - abinfo.bytes = - s->dma_dac.dmasize - s->dma_dac.count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO - "cs4281: cs4281_ioctl(): GETOSPACE .fragsize=%d .bytes=%d .fragstotal=%d .fragments=%d\n", - abinfo.fragsize,abinfo.bytes,abinfo.fragstotal, - abinfo.fragments)); - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(p, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s))) - return val; - spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); - if (s->conversion) { - abinfo.fragsize = s->dma_adc.fragsize / 2; - abinfo.bytes = s->dma_adc.count / 2; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = - abinfo.bytes >> (s->dma_adc.fragshift - 1); - } else { - abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = - abinfo.bytes >> s->dma_adc.fragshift; - } - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(p, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if(!s->dma_dac.ready && prog_dmabuf_dac(s)) - return 0; - spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); - val = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, p); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if(!s->dma_adc.ready && prog_dmabuf_adc(s)) - return 0; - spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); - cinfo.bytes = s->dma_adc.total_bytes; - if (s->dma_adc.mapped) { - cinfo.blocks = - (cinfo.bytes >> s->dma_adc.fragshift) - - s->dma_adc.blocks; - s->dma_adc.blocks = - cinfo.bytes >> s->dma_adc.fragshift; - } else { - if (s->conversion) { - cinfo.blocks = - s->dma_adc.count / - 2 >> (s->dma_adc.fragshift - 1); - } else - cinfo.blocks = - s->dma_adc.count >> s->dma_adc. - fragshift; - } - if (s->conversion) - cinfo.ptr = s->dma_adc.hwptr / 2; - else - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize - 1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(p, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if(!s->dma_dac.ready && prog_dmabuf_dac(s)) - return 0; - spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); - cinfo.bytes = s->dma_dac.total_bytes; - if (s->dma_dac.mapped) { - cinfo.blocks = - (cinfo.bytes >> s->dma_dac.fragshift) - - s->dma_dac.blocks; - s->dma_dac.blocks = - cinfo.bytes >> s->dma_dac.fragshift; - } else { - cinfo.blocks = - s->dma_dac.count >> s->dma_dac.fragshift; - } - cinfo.ptr = s->dma_dac.hwptr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize - 1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(p, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf_dac(s))) - return val; - return put_user(s->dma_dac.fragsize, p); - } - if ((val = prog_dmabuf_adc(s))) - return val; - if (s->conversion) - return put_user(s->dma_adc.fragsize / 2, p); - else - return put_user(s->dma_adc.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - return 0; // Say OK, but do nothing. - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) - || (file->f_mode & FMODE_WRITE - && s->dma_dac.subdivision)) return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - else if (file->f_mode & FMODE_WRITE) - s->dma_dac.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - if (file->f_mode & FMODE_READ) - return put_user(s->prop_adc.rate, p); - else if (file->f_mode & FMODE_WRITE) - return put_user(s->prop_dac.rate, p); - - case SOUND_PCM_READ_CHANNELS: - if (file->f_mode & FMODE_READ) - return put_user(s->prop_adc.channels, p); - else if (file->f_mode & FMODE_WRITE) - return put_user(s->prop_dac.channels, p); - - case SOUND_PCM_READ_BITS: - if (file->f_mode & FMODE_READ) - return - put_user( - (s->prop_adc. - fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16, - p); - else if (file->f_mode & FMODE_WRITE) - return - put_user( - (s->prop_dac. - fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16, - p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - } - return mixer_ioctl(s, cmd, arg); -} - - -static int cs4281_release(struct inode *inode, struct file *file) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - - CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk(KERN_INFO - "cs4281: cs4281_release(): inode=%p file=%p f_mode=%d\n", - inode, file, file->f_mode)); - - VALIDATE_STATE(s); - - if (file->f_mode & FMODE_WRITE) { - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_sem_dac); - stop_dac(s); - dealloc_dmabuf(s, &s->dma_dac); - s->open_mode &= ~FMODE_WRITE; - mutex_unlock(&s->open_sem_dac); - wake_up(&s->open_wait_dac); - } - if (file->f_mode & FMODE_READ) { - drain_adc(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_sem_adc); - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - s->open_mode &= ~FMODE_READ; - mutex_unlock(&s->open_sem_adc); - wake_up(&s->open_wait_adc); - } - return 0; -} - -static int cs4281_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct cs4281_state *s=NULL; - struct list_head *entry; - - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO - "cs4281: cs4281_open(): inode=%p file=%p f_mode=0x%x\n", - inode, file, file->f_mode)); - - list_for_each(entry, &cs4281_devs) - { - s = list_entry(entry, struct cs4281_state, list); - - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - if (entry == &cs4281_devs) - return -ENODEV; - if (!s) { - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO - "cs4281: cs4281_open(): Error - unable to find audio state struct\n")); - return -ENODEV; - } - VALIDATE_STATE(s); - file->private_data = s; - - // wait for device to become free - if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) { - CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO - "cs4281: cs4281_open(): Error - must open READ and/or WRITE\n")); - return -ENODEV; - } - if (file->f_mode & FMODE_WRITE) { - mutex_lock(&s->open_sem_dac); - while (s->open_mode & FMODE_WRITE) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_sem_dac); - return -EBUSY; - } - mutex_unlock(&s->open_sem_dac); - interruptible_sleep_on(&s->open_wait_dac); - - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_sem_dac); - } - } - if (file->f_mode & FMODE_READ) { - mutex_lock(&s->open_sem_adc); - while (s->open_mode & FMODE_READ) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_sem_adc); - return -EBUSY; - } - mutex_unlock(&s->open_sem_adc); - interruptible_sleep_on(&s->open_wait_adc); - - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_sem_adc); - } - } - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - if (file->f_mode & FMODE_READ) { - s->prop_adc.fmt = AFMT_U8; - s->prop_adc.fmt_original = s->prop_adc.fmt; - s->prop_adc.channels = 1; - s->prop_adc.rate = 8000; - s->prop_adc.clkdiv = 96 | 0x80; - s->conversion = 0; - s->ena &= ~FMODE_READ; - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = - s->dma_adc.subdivision = 0; - mutex_unlock(&s->open_sem_adc); - - if (prog_dmabuf_adc(s)) { - CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR - "cs4281: adc Program dmabufs failed.\n")); - cs4281_release(inode, file); - return -ENOMEM; - } - prog_codec(s, CS_TYPE_ADC); - } - if (file->f_mode & FMODE_WRITE) { - s->prop_dac.fmt = AFMT_U8; - s->prop_dac.fmt_original = s->prop_dac.fmt; - s->prop_dac.channels = 1; - s->prop_dac.rate = 8000; - s->prop_dac.clkdiv = 96 | 0x80; - s->conversion = 0; - s->ena &= ~FMODE_WRITE; - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = - s->dma_dac.subdivision = 0; - mutex_unlock(&s->open_sem_dac); - - if (prog_dmabuf_dac(s)) { - CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR - "cs4281: dac Program dmabufs failed.\n")); - cs4281_release(inode, file); - return -ENOMEM; - } - prog_codec(s, CS_TYPE_DAC); - } - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, - printk(KERN_INFO "cs4281: cs4281_open()- 0\n")); - return nonseekable_open(inode, file); -} - - -// ****************************************************************************************** -// Wave (audio) file operations struct. -// ****************************************************************************************** -static /*const */ struct file_operations cs4281_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cs4281_read, - .write = cs4281_write, - .poll = cs4281_poll, - .ioctl = cs4281_ioctl, - .mmap = cs4281_mmap, - .open = cs4281_open, - .release = cs4281_release, -}; - -// --------------------------------------------------------------------- - -// hold spinlock for the following! -static void cs4281_handle_midi(struct cs4281_state *s) -{ - unsigned char ch; - int wake; - unsigned temp1; - - wake = 0; - while (!(readl(s->pBA0 + BA0_MIDSR) & 0x80)) { - ch = readl(s->pBA0 + BA0_MIDRP); - if (s->midi.icnt < MIDIINBUF) { - s->midi.ibuf[s->midi.iwr] = ch; - s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF; - s->midi.icnt++; - } - wake = 1; - } - if (wake) - wake_up(&s->midi.iwait); - wake = 0; - while (!(readl(s->pBA0 + BA0_MIDSR) & 0x40) && s->midi.ocnt > 0) { - temp1 = (s->midi.obuf[s->midi.ord]) & 0x000000ff; - writel(temp1, s->pBA0 + BA0_MIDWP); - s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF; - s->midi.ocnt--; - if (s->midi.ocnt < MIDIOUTBUF - 16) - wake = 1; - } - if (wake) - wake_up(&s->midi.owait); -} - - - -static irqreturn_t cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct cs4281_state *s = (struct cs4281_state *) dev_id; - unsigned int temp1; - - // fastpath out, to ease interrupt sharing - temp1 = readl(s->pBA0 + BA0_HISR); // Get Int Status reg. - - CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO - "cs4281: cs4281_interrupt() BA0_HISR=0x%.8x\n", temp1)); -/* -* If not DMA or MIDI interrupt, then just return. -*/ - if (!(temp1 & (HISR_DMA0 | HISR_DMA1 | HISR_MIDI))) { - writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); - CS_DBGOUT(CS_INTERRUPT, 9, printk(KERN_INFO - "cs4281: cs4281_interrupt(): returning not cs4281 interrupt.\n")); - return IRQ_NONE; - } - - if (temp1 & HISR_DMA0) // If play interrupt, - readl(s->pBA0 + BA0_HDSR0); // clear the source. - - if (temp1 & HISR_DMA1) // Same for play. - readl(s->pBA0 + BA0_HDSR1); - writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Local EOI - - spin_lock(&s->lock); - cs4281_update_ptr(s,CS_TRUE); - cs4281_handle_midi(s); - spin_unlock(&s->lock); - return IRQ_HANDLED; -} - -// ************************************************************************** - -static void cs4281_midi_timer(unsigned long data) -{ - struct cs4281_state *s = (struct cs4281_state *) data; - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - cs4281_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - s->midi.timer.expires = jiffies + 1; - add_timer(&s->midi.timer); -} - - -// --------------------------------------------------------------------- - -static ssize_t cs4281_midi_read(struct file *file, char __user *buffer, - size_t count, loff_t * ppos) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.ird; - cnt = MIDIINBUF - ptr; - if (s->midi.icnt < cnt) - cnt = s->midi.icnt; - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->midi.iwait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; - continue; - } - if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) - return ret ? ret : -EFAULT; - ptr = (ptr + cnt) % MIDIINBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.ird = ptr; - s->midi.icnt -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - } - return ret; -} - - -static ssize_t cs4281_midi_write(struct file *file, const char __user *buffer, - size_t count, loff_t * ppos) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.owr; - cnt = MIDIOUTBUF - ptr; - if (s->midi.ocnt + cnt > MIDIOUTBUF) - cnt = MIDIOUTBUF - s->midi.ocnt; - if (cnt <= 0) - cs4281_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->midi.owait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; - continue; - } - if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) - return ret ? ret : -EFAULT; - ptr = (ptr + cnt) % MIDIOUTBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.owr = ptr; - s->midi.ocnt += cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - spin_lock_irqsave(&s->lock, flags); - cs4281_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - } - return ret; -} - - -static unsigned int cs4281_midi_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_flags & FMODE_WRITE) - poll_wait(file, &s->midi.owait, wait); - if (file->f_flags & FMODE_READ) - poll_wait(file, &s->midi.iwait, wait); - spin_lock_irqsave(&s->lock, flags); - if (file->f_flags & FMODE_READ) { - if (s->midi.icnt > 0) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_flags & FMODE_WRITE) { - if (s->midi.ocnt < MIDIOUTBUF) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - - -static int cs4281_midi_open(struct inode *inode, struct file *file) -{ - unsigned long flags, temp1; - unsigned int minor = iminor(inode); - struct cs4281_state *s=NULL; - struct list_head *entry; - list_for_each(entry, &cs4281_devs) - { - s = list_entry(entry, struct cs4281_state, list); - - if (s->dev_midi == minor) - break; - } - - if (entry == &cs4281_devs) - return -ENODEV; - if (!s) - { - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO - "cs4281: cs4281_open(): Error - unable to find audio state struct\n")); - return -ENODEV; - } - VALIDATE_STATE(s); - file->private_data = s; - // wait for device to become free - mutex_lock(&s->open_sem); - while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_sem); - return -EBUSY; - } - mutex_unlock(&s->open_sem); - interruptible_sleep_on(&s->open_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_sem); - } - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - writel(1, s->pBA0 + BA0_MIDCR); // Reset the interface. - writel(0, s->pBA0 + BA0_MIDCR); // Return to normal mode. - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - writel(0x0000000f, s->pBA0 + BA0_MIDCR); // Enable transmit, record, ints. - temp1 = readl(s->pBA0 + BA0_HIMR); - writel(temp1 & 0xffbfffff, s->pBA0 + BA0_HIMR); // Enable midi int. recognition. - writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts - init_timer(&s->midi.timer); - s->midi.timer.expires = jiffies + 1; - s->midi.timer.data = (unsigned long) s; - s->midi.timer.function = cs4281_midi_timer; - add_timer(&s->midi.timer); - } - if (file->f_mode & FMODE_READ) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - } - if (file->f_mode & FMODE_WRITE) { - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - } - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= - (file-> - f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | - FMODE_MIDI_WRITE); - mutex_unlock(&s->open_sem); - return nonseekable_open(inode, file); -} - - -static int cs4281_midi_release(struct inode *inode, struct file *file) -{ - struct cs4281_state *s = - (struct cs4281_state *) file->private_data; - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - unsigned count, tmo; - - VALIDATE_STATE(s); - - if (file->f_mode & FMODE_WRITE) { - add_wait_queue(&s->midi.owait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->midi.ocnt; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (file->f_flags & O_NONBLOCK) { - remove_wait_queue(&s->midi.owait, &wait); - current->state = TASK_RUNNING; - return -EBUSY; - } - tmo = (count * HZ) / 3100; - if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG - "cs4281: midi timed out??\n"); - } - remove_wait_queue(&s->midi.owait, &wait); - current->state = TASK_RUNNING; - } - mutex_lock(&s->open_sem); - s->open_mode &= - (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ | - FMODE_MIDI_WRITE); - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - writel(0, s->pBA0 + BA0_MIDCR); // Disable Midi interrupts. - del_timer(&s->midi.timer); - } - spin_unlock_irqrestore(&s->lock, flags); - mutex_unlock(&s->open_sem); - wake_up(&s->open_wait); - return 0; -} - -// ****************************************************************************************** -// Midi file operations struct. -// ****************************************************************************************** -static /*const */ struct file_operations cs4281_midi_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cs4281_midi_read, - .write = cs4281_midi_write, - .poll = cs4281_midi_poll, - .open = cs4281_midi_open, - .release = cs4281_midi_release, -}; - - -// --------------------------------------------------------------------- - -// maximum number of devices -#define NR_DEVICE 8 // Only eight devices supported currently. - -// --------------------------------------------------------------------- - -static struct initvol { - int mixch; - int vol; -} initvol[] __devinitdata = { - - { - SOUND_MIXER_WRITE_VOLUME, 0x4040}, { - SOUND_MIXER_WRITE_PCM, 0x4040}, { - SOUND_MIXER_WRITE_SYNTH, 0x4040}, { - SOUND_MIXER_WRITE_CD, 0x4040}, { - SOUND_MIXER_WRITE_LINE, 0x4040}, { - SOUND_MIXER_WRITE_LINE1, 0x4040}, { - SOUND_MIXER_WRITE_RECLEV, 0x0000}, { - SOUND_MIXER_WRITE_SPEAKER, 0x4040}, { - SOUND_MIXER_WRITE_MIC, 0x0000} -}; - - -#ifndef NOT_CS4281_PM -static void __devinit cs4281_BuildFIFO( - struct cs4281_pipeline *p, - struct cs4281_state *s) -{ - switch(p->number) - { - case 0: /* playback */ - { - p->u32FCRnAddress = BA0_FCR0; - p->u32FSICnAddress = BA0_FSIC0; - p->u32FPDRnAddress = BA0_FPDR0; - break; - } - case 1: /* capture */ - { - p->u32FCRnAddress = BA0_FCR1; - p->u32FSICnAddress = BA0_FSIC1; - p->u32FPDRnAddress = BA0_FPDR1; - break; - } - - case 2: - { - p->u32FCRnAddress = BA0_FCR2; - p->u32FSICnAddress = BA0_FSIC2; - p->u32FPDRnAddress = BA0_FPDR2; - break; - } - case 3: - { - p->u32FCRnAddress = BA0_FCR3; - p->u32FSICnAddress = BA0_FSIC3; - p->u32FPDRnAddress = BA0_FPDR3; - break; - } - default: - break; - } - // - // first read the hardware to initialize the member variables - // - p->u32FCRnValue = readl(s->pBA0 + p->u32FCRnAddress); - p->u32FSICnValue = readl(s->pBA0 + p->u32FSICnAddress); - p->u32FPDRnValue = readl(s->pBA0 + p->u32FPDRnAddress); - -} - -static void __devinit cs4281_BuildDMAengine( - struct cs4281_pipeline *p, - struct cs4281_state *s) -{ -/* -* initialize all the addresses of this pipeline dma info. -*/ - switch(p->number) - { - case 0: /* playback */ - { - p->u32DBAnAddress = BA0_DBA0; - p->u32DCAnAddress = BA0_DCA0; - p->u32DBCnAddress = BA0_DBC0; - p->u32DCCnAddress = BA0_DCC0; - p->u32DMRnAddress = BA0_DMR0; - p->u32DCRnAddress = BA0_DCR0; - p->u32HDSRnAddress = BA0_HDSR0; - break; - } - - case 1: /* capture */ - { - p->u32DBAnAddress = BA0_DBA1; - p->u32DCAnAddress = BA0_DCA1; - p->u32DBCnAddress = BA0_DBC1; - p->u32DCCnAddress = BA0_DCC1; - p->u32DMRnAddress = BA0_DMR1; - p->u32DCRnAddress = BA0_DCR1; - p->u32HDSRnAddress = BA0_HDSR1; - break; - } - - case 2: - { - p->u32DBAnAddress = BA0_DBA2; - p->u32DCAnAddress = BA0_DCA2; - p->u32DBCnAddress = BA0_DBC2; - p->u32DCCnAddress = BA0_DCC2; - p->u32DMRnAddress = BA0_DMR2; - p->u32DCRnAddress = BA0_DCR2; - p->u32HDSRnAddress = BA0_HDSR2; - break; - } - - case 3: - { - p->u32DBAnAddress = BA0_DBA3; - p->u32DCAnAddress = BA0_DCA3; - p->u32DBCnAddress = BA0_DBC3; - p->u32DCCnAddress = BA0_DCC3; - p->u32DMRnAddress = BA0_DMR3; - p->u32DCRnAddress = BA0_DCR3; - p->u32HDSRnAddress = BA0_HDSR3; - break; - } - default: - break; - } - -// -// Initialize the dma values for this pipeline -// - p->u32DBAnValue = readl(s->pBA0 + p->u32DBAnAddress); - p->u32DBCnValue = readl(s->pBA0 + p->u32DBCnAddress); - p->u32DMRnValue = readl(s->pBA0 + p->u32DMRnAddress); - p->u32DCRnValue = readl(s->pBA0 + p->u32DCRnAddress); - -} - -static void __devinit cs4281_InitPM(struct cs4281_state *s) -{ - int i; - struct cs4281_pipeline *p; - - for(i=0;ipl[i]; - p->number = i; - cs4281_BuildDMAengine(p,s); - cs4281_BuildFIFO(p,s); - /* - * currently only 2 pipelines are used - * so, only set the valid bit on the playback and capture. - */ - if( (i == CS4281_PLAYBACK_PIPELINE_NUMBER) || - (i == CS4281_CAPTURE_PIPELINE_NUMBER)) - p->flags |= CS4281_PIPELINE_VALID; - } - s->pm.u32SSPM_BITS = 0x7e; /* rev c, use 0x7c for rev a or b */ -} -#endif - -static int __devinit cs4281_probe(struct pci_dev *pcidev, - const struct pci_device_id *pciid) -{ - struct cs4281_state *s; - dma_addr_t dma_mask; - mm_segment_t fs; - int i, val; - unsigned int temp1, temp2; - - CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, - printk(KERN_INFO "cs4281: probe()+\n")); - - if (pci_enable_device(pcidev)) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4281: pci_enable_device() failed\n")); - return -1; - } - if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM) || - !(pci_resource_flags(pcidev, 1) & IORESOURCE_MEM)) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4281: probe()- Memory region not assigned\n")); - return -ENODEV; - } - if (pcidev->irq == 0) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4281: probe() IRQ not assigned\n")); - return -ENODEV; - } - dma_mask = 0xffffffff; /* this enables playback and recording */ - i = pci_set_dma_mask(pcidev, dma_mask); - if (i) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n")); - return i; - } - if (!(s = kmalloc(sizeof(struct cs4281_state), GFP_KERNEL))) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4281: probe() no memory for state struct.\n")); - return -1; - } - memset(s, 0, sizeof(struct cs4281_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->open_wait_adc); - init_waitqueue_head(&s->open_wait_dac); - init_waitqueue_head(&s->midi.iwait); - init_waitqueue_head(&s->midi.owait); - mutex_init(&s->open_sem); - mutex_init(&s->open_sem_adc); - mutex_init(&s->open_sem_dac); - spin_lock_init(&s->lock); - s->pBA0phys = pci_resource_start(pcidev, 0); - s->pBA1phys = pci_resource_start(pcidev, 1); - - /* Convert phys to linear. */ - s->pBA0 = ioremap_nocache(s->pBA0phys, 4096); - if (!s->pBA0) { - CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR - "cs4281: BA0 I/O mapping failed. Skipping part.\n")); - goto err_free; - } - s->pBA1 = ioremap_nocache(s->pBA1phys, 65536); - if (!s->pBA1) { - CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR - "cs4281: BA1 I/O mapping failed. Skipping part.\n")); - goto err_unmap; - } - - temp1 = readl(s->pBA0 + BA0_PCICFG00); - temp2 = readl(s->pBA0 + BA0_PCICFG04); - - CS_DBGOUT(CS_INIT, 2, - printk(KERN_INFO - "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=%p pBA1=%p \n", - (unsigned) temp1, (unsigned) temp2, s->pBA0, s->pBA1)); - CS_DBGOUT(CS_INIT, 2, - printk(KERN_INFO - "cs4281: probe() pBA0phys=0x%.8x pBA1phys=0x%.8x\n", - (unsigned) s->pBA0phys, (unsigned) s->pBA1phys)); - -#ifndef NOT_CS4281_PM - s->pm.flags = CS4281_PM_IDLE; -#endif - temp1 = cs4281_hw_init(s); - if (temp1) { - CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR - "cs4281: cs4281_hw_init() failed. Skipping part.\n")); - goto err_irq; - } - s->magic = CS4281_MAGIC; - s->pcidev = pcidev; - s->irq = pcidev->irq; - if (request_irq - (s->irq, cs4281_interrupt, IRQF_SHARED, "Crystal CS4281", s)) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, - printk(KERN_ERR "cs4281: irq %u in use\n", s->irq)); - goto err_irq; - } - if ((s->dev_audio = register_sound_dsp(&cs4281_audio_fops, -1)) < - 0) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4281: probe() register_sound_dsp() failed.\n")); - goto err_dev1; - } - if ((s->dev_mixer = register_sound_mixer(&cs4281_mixer_fops, -1)) < - 0) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4281: probe() register_sound_mixer() failed.\n")); - goto err_dev2; - } - if ((s->dev_midi = register_sound_midi(&cs4281_midi_fops, -1)) < 0) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4281: probe() register_sound_midi() failed.\n")); - goto err_dev3; - } -#ifndef NOT_CS4281_PM - cs4281_InitPM(s); - s->pm.flags |= CS4281_PM_NOT_REGISTERED; -#endif - - pci_set_master(pcidev); // enable bus mastering - - fs = get_fs(); - set_fs(KERNEL_DS); - val = SOUND_MASK_LINE; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val); - for (i = 0; i < sizeof(initvol) / sizeof(initvol[0]); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long) &val); - } - val = 1; // enable mic preamp - mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long) &val); - set_fs(fs); - - pci_set_drvdata(pcidev, s); - list_add(&s->list, &cs4281_devs); - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO - "cs4281: probe()- device allocated successfully\n")); - return 0; - - err_dev3: - unregister_sound_mixer(s->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - free_irq(s->irq, s); - err_irq: - iounmap(s->pBA1); - err_unmap: - iounmap(s->pBA0); - err_free: - kfree(s); - - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO - "cs4281: probe()- no device allocated\n")); - return -ENODEV; -} // probe_cs4281 - - -// --------------------------------------------------------------------- - -static void __devexit cs4281_remove(struct pci_dev *pci_dev) -{ - struct cs4281_state *s = pci_get_drvdata(pci_dev); - // stop DMA controller - synchronize_irq(s->irq); - free_irq(s->irq, s); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_midi(s->dev_midi); - iounmap(s->pBA1); - iounmap(s->pBA0); - pci_set_drvdata(pci_dev,NULL); - list_del(&s->list); - kfree(s); - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO - "cs4281: cs4281_remove()-: remove successful\n")); -} - -static struct pci_device_id cs4281_pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_CIRRUS, - .device = PCI_DEVICE_ID_CRYSTAL_CS4281, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, cs4281_pci_tbl); - -static struct pci_driver cs4281_pci_driver = { - .name = "cs4281", - .id_table = cs4281_pci_tbl, - .probe = cs4281_probe, - .remove = __devexit_p(cs4281_remove), - .suspend = CS4281_SUSPEND_TBL, - .resume = CS4281_RESUME_TBL, -}; - -static int __init cs4281_init_module(void) -{ - int rtn = 0; - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO - "cs4281: cs4281_init_module()+ \n")); - printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " " - __DATE__ "\n", CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION, - CS4281_ARCH); - rtn = pci_register_driver(&cs4281_pci_driver); - - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: cs4281_init_module()- (%d)\n",rtn)); - return rtn; -} - -static void __exit cs4281_cleanup_module(void) -{ - pci_unregister_driver(&cs4281_pci_driver); - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: cleanup_cs4281() finished\n")); -} -// --------------------------------------------------------------------- - -MODULE_AUTHOR("gw boynton, audio@crystal.cirrus.com"); -MODULE_DESCRIPTION("Cirrus Logic CS4281 Driver"); -MODULE_LICENSE("GPL"); - -// --------------------------------------------------------------------- - -module_init(cs4281_init_module); -module_exit(cs4281_cleanup_module); - diff --git a/sound/oss/cs4281/cs4281pm-24.c b/sound/oss/cs4281/cs4281pm-24.c deleted file mode 100644 index 90cbd7679534..000000000000 --- a/sound/oss/cs4281/cs4281pm-24.c +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* -* -* "cs4281pm.c" -- Cirrus Logic-Crystal CS4281 linux audio driver. -* -* Copyright (C) 2000,2001 Cirrus Logic Corp. -* -- tom woller (twoller@crystal.cirrus.com) or -* (audio@crystal.cirrus.com). -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* 12/22/00 trw - new file. -* -*******************************************************************************/ - -#ifndef NOT_CS4281_PM -#include - -static int cs4281_suspend(struct cs4281_state *s); -static int cs4281_resume(struct cs4281_state *s); -/* -* for now (12/22/00) only enable the pm_register PM support. -* allow these table entries to be null. -#define CS4281_SUSPEND_TBL cs4281_suspend_tbl -#define CS4281_RESUME_TBL cs4281_resume_tbl -*/ -#define CS4281_SUSPEND_TBL cs4281_suspend_null -#define CS4281_RESUME_TBL cs4281_resume_null - -#else /* CS4281_PM */ -#define CS4281_SUSPEND_TBL cs4281_suspend_null -#define CS4281_RESUME_TBL cs4281_resume_null -#endif /* CS4281_PM */ - diff --git a/sound/oss/cs4281/cs4281pm.h b/sound/oss/cs4281/cs4281pm.h deleted file mode 100644 index b44fdc9ce002..000000000000 --- a/sound/oss/cs4281/cs4281pm.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef NOT_CS4281_PM -/******************************************************************************* -* -* "cs4281pm.h" -- Cirrus Logic-Crystal CS4281 linux audio driver. -* -* Copyright (C) 2000,2001 Cirrus Logic Corp. -* -- tom woller (twoller@crystal.cirrus.com) or -* (audio@crystal.cirrus.com). -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* 12/22/00 trw - new file. -* -*******************************************************************************/ -/* general pm definitions */ -#define CS4281_AC97_HIGHESTREGTORESTORE 0x26 -#define CS4281_AC97_NUMBER_RESTORE_REGS (CS4281_AC97_HIGHESTREGTORESTORE/2-1) - -/* pipeline definitions */ -#define CS4281_NUMBER_OF_PIPELINES 4 -#define CS4281_PIPELINE_VALID 0x0001 -#define CS4281_PLAYBACK_PIPELINE_NUMBER 0x0000 -#define CS4281_CAPTURE_PIPELINE_NUMBER 0x0001 - -/* PM state defintions */ -#define CS4281_PM_NOT_REGISTERED 0x1000 -#define CS4281_PM_IDLE 0x0001 -#define CS4281_PM_SUSPENDING 0x0002 -#define CS4281_PM_SUSPENDED 0x0004 -#define CS4281_PM_RESUMING 0x0008 -#define CS4281_PM_RESUMED 0x0010 - -struct cs4281_pm { - unsigned long flags; - u32 u32CLKCR1_SAVE,u32SSPMValue,u32PPLVCvalue,u32PPRVCvalue; - u32 u32FMLVCvalue,u32FMRVCvalue,u32GPIORvalue,u32JSCTLvalue,u32SSCR; - u32 u32SRCSA,u32DacASR,u32AdcASR,u32DacSR,u32AdcSR,u32MIDCR_Save; - u32 u32SSPM_BITS; - u32 ac97[CS4281_AC97_NUMBER_RESTORE_REGS]; - u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono; - u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose; - u32 u32hwptr_playback,u32hwptr_capture; -}; - -struct cs4281_pipeline { - unsigned flags; - unsigned number; - u32 u32DBAnValue,u32DBCnValue,u32DMRnValue,u32DCRnValue; - u32 u32DBAnAddress,u32DCAnAddress,u32DBCnAddress,u32DCCnAddress; - u32 u32DMRnAddress,u32DCRnAddress,u32HDSRnAddress; - u32 u32DBAn_Save,u32DBCn_Save,u32DMRn_Save,u32DCRn_Save; - u32 u32DCCn_Save,u32DCAn_Save; -/* -* technically, these are fifo variables, but just map the -* first fifo with the first pipeline and then use the fifo -* variables inside of the pipeline struct. -*/ - u32 u32FCRn_Save,u32FSICn_Save; - u32 u32FCRnValue,u32FCRnAddress,u32FSICnValue,u32FSICnAddress; - u32 u32FPDRnValue,u32FPDRnAddress; -}; -#endif diff --git a/sound/oss/dm.h b/sound/oss/dm.h deleted file mode 100644 index 14a90593c44f..000000000000 --- a/sound/oss/dm.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef _DRIVERS_SOUND_DM_H -#define _DRIVERS_SOUND_DM_H - -/* - * Definitions of the 'direct midi sound' interface used - * by the newer commercial OSS package. We should export - * this to userland somewhere in glibc later. - */ - -/* - * Data structure composing an FM "note" or sound event. - */ - -struct dm_fm_voice -{ - u8 op; - u8 voice; - u8 am; - u8 vibrato; - u8 do_sustain; - u8 kbd_scale; - u8 harmonic; - u8 scale_level; - u8 volume; - u8 attack; - u8 decay; - u8 sustain; - u8 release; - u8 feedback; - u8 connection; - u8 left; - u8 right; - u8 waveform; -}; - -/* - * This describes an FM note by its voice, octave, frequency number (10bit) - * and key on/off. - */ - -struct dm_fm_note -{ - u8 voice; - u8 octave; - u32 fnum; - u8 key_on; -}; - -/* - * FM parameters that apply globally to all voices, and thus are not "notes" - */ - -struct dm_fm_params -{ - u8 am_depth; - u8 vib_depth; - u8 kbd_split; - u8 rhythm; - - /* This block is the percussion instrument data */ - u8 bass; - u8 snare; - u8 tomtom; - u8 cymbal; - u8 hihat; -}; - -/* - * FM mode ioctl settings - */ - -#define FM_IOCTL_RESET 0x20 -#define FM_IOCTL_PLAY_NOTE 0x21 -#define FM_IOCTL_SET_VOICE 0x22 -#define FM_IOCTL_SET_PARAMS 0x23 -#define FM_IOCTL_SET_MODE 0x24 -#define FM_IOCTL_SET_OPL 0x25 - -#endif diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c index 6c1cf74b78c5..6ff67f73cbb9 100644 --- a/sound/oss/dmabuf.c +++ b/sound/oss/dmabuf.c @@ -1155,36 +1155,6 @@ void DMAbuf_inputintr(int dev) spin_unlock_irqrestore(&dmap->lock,flags); } -int DMAbuf_open_dma(int dev) -{ - /* - * NOTE! This routine opens only the primary DMA channel (output). - */ - struct audio_operations *adev = audio_devs[dev]; - int err; - - if ((err = open_dmap(adev, OPEN_READWRITE, adev->dmap_out)) < 0) - return -EBUSY; - dma_init_buffers(adev->dmap_out); - adev->dmap_out->flags |= DMA_ALLOC_DONE; - adev->dmap_out->fragment_size = adev->dmap_out->buffsize; - - if (adev->dmap_out->dma >= 0) { - unsigned long flags; - - flags=claim_dma_lock(); - clear_dma_ff(adev->dmap_out->dma); - disable_dma(adev->dmap_out->dma); - release_dma_lock(flags); - } - return 0; -} - -void DMAbuf_close_dma(int dev) -{ - close_dmap(audio_devs[dev], audio_devs[dev]->dmap_out); -} - void DMAbuf_init(int dev, int dma1, int dma2) { struct audio_operations *adev = audio_devs[dev]; diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c deleted file mode 100644 index 13f483149737..000000000000 --- a/sound/oss/es1370.c +++ /dev/null @@ -1,2819 +0,0 @@ -/*****************************************************************************/ - -/* - * es1370.c -- Ensoniq ES1370/Asahi Kasei AK4531 audio driver. - * - * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Special thanks to David C. Niemi - * - * - * Module command line parameters: - * lineout if 1 the LINE jack is used as an output instead of an input. - * LINE then contains the unmixed dsp output. This can be used - * to make the card a four channel one: use dsp to output two - * channels to LINE and dac to output the other two channels to - * SPKR. Set the mixer to only output synth to SPKR. - * micbias sets the +5V bias to the mic if using an electretmic. - * - * - * Note: sync mode is not yet supported (i.e. running dsp and dac from the same - * clock source) - * - * Supported devices: - * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible - * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible - * /dev/dsp1 additional DAC, like /dev/dsp, but output only, - * only 5512, 11025, 22050 and 44100 samples/s, - * outputs to mixer "SYNTH" setting - * /dev/midi simple MIDI UART interface, no ioctl - * - * NOTE: the card does not have any FM/Wavetable synthesizer, it is supposed - * to be done in software. That is what /dev/dac is for. By now (Q2 1998) - * there are several MIDI to PCM (WAV) packages, one of them is timidity. - * - * Revision history - * 26.03.1998 0.1 Initial release - * 31.03.1998 0.2 Fix bug in GETOSPACE - * 04.04.1998 0.3 Make it work (again) under 2.0.33 - * Fix mixer write operation not returning the actual - * settings - * 05.04.1998 0.4 First attempt at using the new PCI stuff - * 29.04.1998 0.5 Fix hang when ^C is pressed on amp - * 07.05.1998 0.6 Don't double lock around stop_*() in *_release() - * 10.05.1998 0.7 First stab at a simple midi interface (no bells&whistles) - * 14.05.1998 0.8 Don't allow excessive interrupt rates - * 08.06.1998 0.9 First release using Alan Cox' soundcore instead of - * miscdevice - * 05.07.1998 0.10 Fixed the driver to correctly maintin OSS style volume - * settings (not sure if this should be standard) - * Fixed many references: f_flags should be f_mode - * -- Gerald Britton - * 03.08.1998 0.11 Now mixer behaviour can basically be selected between - * "OSS documented" and "OSS actual" behaviour - * Fixed mixer table thanks to Hakan.Lennestal@lu.erisoft.se - * On module startup, set DAC2 to 11kSPS instead of 5.5kSPS, - * as it produces an annoying ssssh in the lower sampling rate - * Do not include modversions.h - * 22.08.1998 0.12 Mixer registers actually have 5 instead of 4 bits - * pointed out by Itai Nahshon - * 31.08.1998 0.13 Fix realplayer problems - dac.count issues - * 08.10.1998 0.14 Joystick support fixed - * -- Oliver Neukum - * 10.12.1998 0.15 Fix drain_dac trying to wait on not yet initialized DMA - * 16.12.1998 0.16 Don't wake up app until there are fragsize bytes to read/write - * 06.01.1999 0.17 remove the silly SA_INTERRUPT flag. - * hopefully killed the egcs section type conflict - * 12.03.1999 0.18 cinfo.blocks should be reset after GETxPTR ioctl. - * reported by Johan Maes - * 22.03.1999 0.19 return EAGAIN instead of EBUSY when O_NONBLOCK - * read/write cannot be executed - * 07.04.1999 0.20 implemented the following ioctl's: SOUND_PCM_READ_RATE, - * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; - * Alpha fixes reported by Peter Jones - * Note: joystick address handling might still be wrong on archs - * other than i386 - * 10.05.1999 0.21 Added support for an electret mic for SB PCI64 - * to the Linux kernel sound driver. This mod also straighten - * out the question marks around the mic impedance setting - * (micz). From Kim.Berts@fisub.mail.abb.com - * 11.05.1999 0.22 Implemented the IMIX call to mute recording monitor. - * Guenter Geiger - * 15.06.1999 0.23 Fix bad allocation bug. - * Thanks to Deti Fliegl - * 28.06.1999 0.24 Add pci_set_master - * 02.08.1999 0.25 Added workaround for the "phantom write" bug first - * documented by Dave Sharpless from Anchor Games - * 03.08.1999 0.26 adapt to Linus' new __setup/__initcall - * added kernel command line option "es1370=joystick[,lineout[,micbias]]" - * removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge - * 12.08.1999 0.27 module_init/__setup fixes - * 19.08.1999 0.28 SOUND_MIXER_IMIX fixes, reported by Gianluca - * 31.08.1999 0.29 add spin_lock_init - * replaced current->state = x with set_current_state(x) - * 03.09.1999 0.30 change read semantics for MIDI to match - * OSS more closely; remove possible wakeup race - * 28.10.1999 0.31 More waitqueue races fixed - * 08.01.2000 0.32 Prevent some ioctl's from returning bad count values on underrun/overrun; - * Tim Janik's BSE (Bedevilled Sound Engine) found this - * 07.02.2000 0.33 Use pci_alloc_consistent and pci_register_driver - * 21.11.2000 0.34 Initialize dma buffers in poll, otherwise poll may return a bogus mask - * 12.12.2000 0.35 More dma buffer initializations, patch from - * Tjeerd Mulder - * 07.01.2001 0.36 Timeout change in wrcodec as requested by Frank Klemm - * 31.01.2001 0.37 Register/Unregister gameport - * Fix SETTRIGGER non OSS API conformity - * 03.01.2003 0.38 open_mode fixes from Georg Acher - * - * some important things missing in Ensoniq documentation: - * - * Experimental PCLKDIV results: play the same waveforms on both DAC1 and DAC2 - * and vary PCLKDIV to obtain zero beat. - * 5512sps: 254 - * 44100sps: 30 - * seems to be fs = 1411200/(PCLKDIV+2) - * - * should find out when curr_sample_ct is cleared and - * where exactly the CCB fetches data - * - * The card uses a 22.5792 MHz crystal. - * The LINEIN jack may be converted to an AOUT jack by - * setting pin 47 (XCTL0) of the ES1370 to high. - * Pin 48 (XCTL1) of the ES1370 sets the +5V bias for an electretmic - * - * - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -#define SUPPORT_JOYSTICK -#endif - -/* --------------------------------------------------------------------- */ - -#undef OSS_DOCUMENTED_MIXER_SEMANTICS -#define DBG(x) {} -/*#define DBG(x) {x}*/ - -/* --------------------------------------------------------------------- */ - -#ifndef PCI_VENDOR_ID_ENSONIQ -#define PCI_VENDOR_ID_ENSONIQ 0x1274 -#endif - -#ifndef PCI_DEVICE_ID_ENSONIQ_ES1370 -#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 -#endif - -#define ES1370_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1370) - -#define ES1370_EXTENT 0x40 -#define JOY_EXTENT 8 - -#define ES1370_REG_CONTROL 0x00 -#define ES1370_REG_STATUS 0x04 -#define ES1370_REG_UART_DATA 0x08 -#define ES1370_REG_UART_STATUS 0x09 -#define ES1370_REG_UART_CONTROL 0x09 -#define ES1370_REG_UART_TEST 0x0a -#define ES1370_REG_MEMPAGE 0x0c -#define ES1370_REG_CODEC 0x10 -#define ES1370_REG_SERIAL_CONTROL 0x20 -#define ES1370_REG_DAC1_SCOUNT 0x24 -#define ES1370_REG_DAC2_SCOUNT 0x28 -#define ES1370_REG_ADC_SCOUNT 0x2c - -#define ES1370_REG_DAC1_FRAMEADR 0xc30 -#define ES1370_REG_DAC1_FRAMECNT 0xc34 -#define ES1370_REG_DAC2_FRAMEADR 0xc38 -#define ES1370_REG_DAC2_FRAMECNT 0xc3c -#define ES1370_REG_ADC_FRAMEADR 0xd30 -#define ES1370_REG_ADC_FRAMECNT 0xd34 -#define ES1370_REG_PHANTOM_FRAMEADR 0xd38 -#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c - -#define ES1370_FMT_U8_MONO 0 -#define ES1370_FMT_U8_STEREO 1 -#define ES1370_FMT_S16_MONO 2 -#define ES1370_FMT_S16_STEREO 3 -#define ES1370_FMT_STEREO 1 -#define ES1370_FMT_S16 2 -#define ES1370_FMT_MASK 3 - -static const unsigned sample_size[] = { 1, 2, 2, 4 }; -static const unsigned sample_shift[] = { 0, 1, 1, 2 }; - -static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 }; - -#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2) -#define DAC2_DIVTOSR(x) (1411200/((x)+2)) - -#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */ -#define CTRL_XCTL1 0x40000000 /* electret mic bias */ -#define CTRL_OPEN 0x20000000 /* no function, can be read and written */ -#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */ -#define CTRL_SH_PCLKDIV 16 -#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */ -#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */ -#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */ -#define CTRL_SH_WTSRSEL 12 -#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */ -#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */ -#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = MPEG */ -#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */ -#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */ -#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */ -#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */ -#define CTRL_ADC_EN 0x00000010 /* enable ADC */ -#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */ -#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably at address 0x200) */ -#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */ -#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */ - -#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */ -#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in progress */ -#define STAT_CBUSY 0x00000200 /* 1 = codec busy */ -#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */ -#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */ -#define STAT_SH_VC 5 -#define STAT_MCCB 0x00000010 /* CCB int pending */ -#define STAT_UART 0x00000008 /* UART int pending */ -#define STAT_DAC1 0x00000004 /* DAC1 int pending */ -#define STAT_DAC2 0x00000002 /* DAC2 int pending */ -#define STAT_ADC 0x00000001 /* ADC int pending */ - -#define USTAT_RXINT 0x80 /* UART rx int pending */ -#define USTAT_TXINT 0x04 /* UART tx int pending */ -#define USTAT_TXRDY 0x02 /* UART tx ready */ -#define USTAT_RXRDY 0x01 /* UART rx ready */ - -#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */ -#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */ -#define UCTRL_ENA_TXINT 0x20 /* enable TX int */ -#define UCTRL_CNTRL 0x03 /* control field */ -#define UCTRL_CNTRL_SWR 0x03 /* software reset command */ - -#define SCTRL_P2ENDINC 0x00380000 /* */ -#define SCTRL_SH_P2ENDINC 19 -#define SCTRL_P2STINC 0x00070000 /* */ -#define SCTRL_SH_P2STINC 16 -#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */ -#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */ -#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */ -#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */ -#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */ -#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */ -#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */ -#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */ -#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */ -#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */ -#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */ -#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */ -#define SCTRL_R1FMT 0x00000030 /* format mask */ -#define SCTRL_SH_R1FMT 4 -#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */ -#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */ -#define SCTRL_P2FMT 0x0000000c /* format mask */ -#define SCTRL_SH_P2FMT 2 -#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */ -#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */ -#define SCTRL_P1FMT 0x00000003 /* format mask */ -#define SCTRL_SH_P1FMT 0 - -/* misc stuff */ - -#define FMODE_DAC 4 /* slight misuse of mode_t */ - -/* MIDI buffer sizes */ - -#define MIDIINBUF 256 -#define MIDIOUTBUF 256 - -#define FMODE_MIDI_SHIFT 3 -#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) -#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) - -/* --------------------------------------------------------------------- */ - -struct es1370_state { - /* magic */ - unsigned int magic; - - /* list of es1370 devices */ - struct list_head devs; - - /* the corresponding pci_dev structure */ - struct pci_dev *dev; - - /* soundcore stuff */ - int dev_audio; - int dev_mixer; - int dev_dac; - int dev_midi; - - /* hardware resources */ - unsigned long io; /* long for SPARC */ - unsigned int irq; - - /* mixer registers; there is no HW readback */ - struct { - unsigned short vol[10]; - unsigned int recsrc; - unsigned int modcnt; - unsigned short micpreamp; - unsigned int imix; - } mix; - - /* wave stuff */ - unsigned ctrl; - unsigned sctrl; - - spinlock_t lock; - struct mutex open_mutex; - mode_t open_mode; - wait_queue_head_t open_wait; - - struct dmabuf { - void *rawbuf; - dma_addr_t dmaaddr; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - unsigned hwptr, swptr; - unsigned total_bytes; - int count; - unsigned error; /* over/underrun */ - wait_queue_head_t wait; - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dmasize; - unsigned fragsamples; - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned endcleared:1; - unsigned enabled:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac1, dma_dac2, dma_adc; - - /* The following buffer is used to point the phantom write channel to. */ - unsigned char *bugbuf_cpu; - dma_addr_t bugbuf_dma; - - /* midi stuff */ - struct { - unsigned ird, iwr, icnt; - unsigned ord, owr, ocnt; - wait_queue_head_t iwait; - wait_queue_head_t owait; - unsigned char ibuf[MIDIINBUF]; - unsigned char obuf[MIDIOUTBUF]; - } midi; - -#ifdef SUPPORT_JOYSTICK - struct gameport *gameport; -#endif - - struct mutex mutex; -}; - -/* --------------------------------------------------------------------- */ - -static LIST_HEAD(devs); - -/* --------------------------------------------------------------------- */ - -static inline unsigned ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -/* --------------------------------------------------------------------- */ - -static void wrcodec(struct es1370_state *s, unsigned char idx, unsigned char data) -{ - unsigned long tmo = jiffies + HZ/10, j; - - do { - j = jiffies; - if (!(inl(s->io+ES1370_REG_STATUS) & STAT_CSTAT)) { - outw((((unsigned short)idx)<<8)|data, s->io+ES1370_REG_CODEC); - return; - } - schedule(); - } while ((signed)(tmo-j) > 0); - printk(KERN_ERR "es1370: write to codec register timeout\n"); -} - -/* --------------------------------------------------------------------- */ - -static inline void stop_adc(struct es1370_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ctrl &= ~CTRL_ADC_EN; - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void stop_dac1(struct es1370_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ctrl &= ~CTRL_DAC1_EN; - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void stop_dac2(struct es1370_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ctrl &= ~CTRL_DAC2_EN; - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac1(struct es1370_state *s) -{ - unsigned long flags; - unsigned fragremain, fshift; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_DAC1_EN) && (s->dma_dac1.mapped || s->dma_dac1.count > 0) - && s->dma_dac1.ready) { - s->ctrl |= CTRL_DAC1_EN; - s->sctrl = (s->sctrl & ~(SCTRL_P1LOOPSEL | SCTRL_P1PAUSE | SCTRL_P1SCTRLD)) | SCTRL_P1INTEN; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - fragremain = ((- s->dma_dac1.hwptr) & (s->dma_dac1.fragsize-1)); - fshift = sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; - if (fragremain < 2*fshift) - fragremain = s->dma_dac1.fragsize; - outl((fragremain >> fshift) - 1, s->io+ES1370_REG_DAC1_SCOUNT); - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - outl((s->dma_dac1.fragsize >> fshift) - 1, s->io+ES1370_REG_DAC1_SCOUNT); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac2(struct es1370_state *s) -{ - unsigned long flags; - unsigned fragremain, fshift; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_DAC2_EN) && (s->dma_dac2.mapped || s->dma_dac2.count > 0) - && s->dma_dac2.ready) { - s->ctrl |= CTRL_DAC2_EN; - s->sctrl = (s->sctrl & ~(SCTRL_P2LOOPSEL | SCTRL_P2PAUSE | SCTRL_P2DACSEN | - SCTRL_P2ENDINC | SCTRL_P2STINC)) | SCTRL_P2INTEN | - (((s->sctrl & SCTRL_P2FMT) ? 2 : 1) << SCTRL_SH_P2ENDINC) | - (0 << SCTRL_SH_P2STINC); - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - fragremain = ((- s->dma_dac2.hwptr) & (s->dma_dac2.fragsize-1)); - fshift = sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; - if (fragremain < 2*fshift) - fragremain = s->dma_dac2.fragsize; - outl((fragremain >> fshift) - 1, s->io+ES1370_REG_DAC2_SCOUNT); - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - outl((s->dma_dac2.fragsize >> fshift) - 1, s->io+ES1370_REG_DAC2_SCOUNT); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_adc(struct es1370_state *s) -{ - unsigned long flags; - unsigned fragremain, fshift; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) - && s->dma_adc.ready) { - s->ctrl |= CTRL_ADC_EN; - s->sctrl = (s->sctrl & ~SCTRL_R1LOOPSEL) | SCTRL_R1INTEN; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - fragremain = ((- s->dma_adc.hwptr) & (s->dma_adc.fragsize-1)); - fshift = sample_shift[(s->sctrl & SCTRL_R1FMT) >> SCTRL_SH_R1FMT]; - if (fragremain < 2*fshift) - fragremain = s->dma_adc.fragsize; - outl((fragremain >> fshift) - 1, s->io+ES1370_REG_ADC_SCOUNT); - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - outl((s->dma_adc.fragsize >> fshift) - 1, s->io+ES1370_REG_ADC_SCOUNT); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -/* --------------------------------------------------------------------- */ - -#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - -static inline void dealloc_dmabuf(struct es1370_state *s, struct dmabuf *db) -{ - struct page *page, *pend; - - if (db->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - ClearPageReserved(page); - pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); - } - db->rawbuf = NULL; - db->mapped = db->ready = 0; -} - -static int prog_dmabuf(struct es1370_state *s, struct dmabuf *db, unsigned rate, unsigned fmt, unsigned reg) -{ - int order; - unsigned bytepersec; - unsigned bufs; - struct page *page, *pend; - - db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; - if (!db->rawbuf) { - db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) - break; - if (!db->rawbuf) - return -ENOMEM; - db->buforder = order; - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - SetPageReserved(page); - } - fmt &= ES1370_FMT_MASK; - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; - memset(db->rawbuf, (fmt & ES1370_FMT_S16) ? 0 : 0x80, db->dmasize); - outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE); - outl(db->dmaaddr, s->io+(reg & 0xff)); - outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff)); - db->enabled = 1; - db->ready = 1; - return 0; -} - -static inline int prog_dmabuf_adc(struct es1370_state *s) -{ - stop_adc(s); - return prog_dmabuf(s, &s->dma_adc, DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), - (s->sctrl >> SCTRL_SH_R1FMT) & ES1370_FMT_MASK, ES1370_REG_ADC_FRAMEADR); -} - -static inline int prog_dmabuf_dac2(struct es1370_state *s) -{ - stop_dac2(s); - return prog_dmabuf(s, &s->dma_dac2, DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), - (s->sctrl >> SCTRL_SH_P2FMT) & ES1370_FMT_MASK, ES1370_REG_DAC2_FRAMEADR); -} - -static inline int prog_dmabuf_dac1(struct es1370_state *s) -{ - stop_dac1(s); - return prog_dmabuf(s, &s->dma_dac1, dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], - (s->sctrl >> SCTRL_SH_P1FMT) & ES1370_FMT_MASK, ES1370_REG_DAC1_FRAMEADR); -} - -static inline unsigned get_hwptr(struct es1370_state *s, struct dmabuf *db, unsigned reg) -{ - unsigned hwptr, diff; - - outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE); - hwptr = (inl(s->io+(reg & 0xff)) >> 14) & 0x3fffc; - diff = (db->dmasize + hwptr - db->hwptr) % db->dmasize; - db->hwptr = hwptr; - return diff; -} - -static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c) -{ - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(((char *)buf) + bptr, c, x); - bptr = 0; - len -= x; - } - memset(((char *)buf) + bptr, c, len); -} - -/* call with spinlock held! */ -static void es1370_update_ptr(struct es1370_state *s) -{ - int diff; - - /* update ADC pointer */ - if (s->ctrl & CTRL_ADC_EN) { - diff = get_hwptr(s, &s->dma_adc, ES1370_REG_ADC_FRAMECNT); - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - wake_up(&s->dma_adc.wait); - if (!s->dma_adc.mapped) { - if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { - s->ctrl &= ~CTRL_ADC_EN; - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - s->dma_adc.error++; - } - } - } - /* update DAC1 pointer */ - if (s->ctrl & CTRL_DAC1_EN) { - diff = get_hwptr(s, &s->dma_dac1, ES1370_REG_DAC1_FRAMECNT); - s->dma_dac1.total_bytes += diff; - if (s->dma_dac1.mapped) { - s->dma_dac1.count += diff; - if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize) - wake_up(&s->dma_dac1.wait); - } else { - s->dma_dac1.count -= diff; - if (s->dma_dac1.count <= 0) { - s->ctrl &= ~CTRL_DAC1_EN; - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - s->dma_dac1.error++; - } else if (s->dma_dac1.count <= (signed)s->dma_dac1.fragsize && !s->dma_dac1.endcleared) { - clear_advance(s->dma_dac1.rawbuf, s->dma_dac1.dmasize, s->dma_dac1.swptr, - s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80); - s->dma_dac1.endcleared = 1; - } - if (s->dma_dac1.count + (signed)s->dma_dac1.fragsize <= (signed)s->dma_dac1.dmasize) - wake_up(&s->dma_dac1.wait); - } - } - /* update DAC2 pointer */ - if (s->ctrl & CTRL_DAC2_EN) { - diff = get_hwptr(s, &s->dma_dac2, ES1370_REG_DAC2_FRAMECNT); - s->dma_dac2.total_bytes += diff; - if (s->dma_dac2.mapped) { - s->dma_dac2.count += diff; - if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) - wake_up(&s->dma_dac2.wait); - } else { - s->dma_dac2.count -= diff; - if (s->dma_dac2.count <= 0) { - s->ctrl &= ~CTRL_DAC2_EN; - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - s->dma_dac2.error++; - } else if (s->dma_dac2.count <= (signed)s->dma_dac2.fragsize && !s->dma_dac2.endcleared) { - clear_advance(s->dma_dac2.rawbuf, s->dma_dac2.dmasize, s->dma_dac2.swptr, - s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80); - s->dma_dac2.endcleared = 1; - } - if (s->dma_dac2.count + (signed)s->dma_dac2.fragsize <= (signed)s->dma_dac2.dmasize) - wake_up(&s->dma_dac2.wait); - } - } -} - -/* hold spinlock for the following! */ -static void es1370_handle_midi(struct es1370_state *s) -{ - unsigned char ch; - int wake; - - if (!(s->ctrl & CTRL_UART_EN)) - return; - wake = 0; - while (inb(s->io+ES1370_REG_UART_STATUS) & USTAT_RXRDY) { - ch = inb(s->io+ES1370_REG_UART_DATA); - if (s->midi.icnt < MIDIINBUF) { - s->midi.ibuf[s->midi.iwr] = ch; - s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF; - s->midi.icnt++; - } - wake = 1; - } - if (wake) - wake_up(&s->midi.iwait); - wake = 0; - while ((inb(s->io+ES1370_REG_UART_STATUS) & USTAT_TXRDY) && s->midi.ocnt > 0) { - outb(s->midi.obuf[s->midi.ord], s->io+ES1370_REG_UART_DATA); - s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF; - s->midi.ocnt--; - if (s->midi.ocnt < MIDIOUTBUF-16) - wake = 1; - } - if (wake) - wake_up(&s->midi.owait); - outb((s->midi.ocnt > 0) ? UCTRL_RXINTEN | UCTRL_ENA_TXINT : UCTRL_RXINTEN, s->io+ES1370_REG_UART_CONTROL); -} - -static irqreturn_t es1370_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct es1370_state *s = (struct es1370_state *)dev_id; - unsigned int intsrc, sctl; - - /* fastpath out, to ease interrupt sharing */ - intsrc = inl(s->io+ES1370_REG_STATUS); - if (!(intsrc & 0x80000000)) - return IRQ_NONE; - spin_lock(&s->lock); - /* clear audio interrupts first */ - sctl = s->sctrl; - if (intsrc & STAT_ADC) - sctl &= ~SCTRL_R1INTEN; - if (intsrc & STAT_DAC1) - sctl &= ~SCTRL_P1INTEN; - if (intsrc & STAT_DAC2) - sctl &= ~SCTRL_P2INTEN; - outl(sctl, s->io+ES1370_REG_SERIAL_CONTROL); - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - es1370_update_ptr(s); - es1370_handle_midi(s); - spin_unlock(&s->lock); - return IRQ_HANDLED; -} - -/* --------------------------------------------------------------------- */ - -static const char invalid_magic[] = KERN_CRIT "es1370: invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != ES1370_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -/* --------------------------------------------------------------------- */ - -static const struct { - unsigned volidx:4; - unsigned left:4; - unsigned right:4; - unsigned stereo:1; - unsigned recmask:13; - unsigned avail:1; -} mixtable[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_VOLUME] = { 0, 0x0, 0x1, 1, 0x0000, 1 }, /* master */ - [SOUND_MIXER_PCM] = { 1, 0x2, 0x3, 1, 0x0400, 1 }, /* voice */ - [SOUND_MIXER_SYNTH] = { 2, 0x4, 0x5, 1, 0x0060, 1 }, /* FM */ - [SOUND_MIXER_CD] = { 3, 0x6, 0x7, 1, 0x0006, 1 }, /* CD */ - [SOUND_MIXER_LINE] = { 4, 0x8, 0x9, 1, 0x0018, 1 }, /* Line */ - [SOUND_MIXER_LINE1] = { 5, 0xa, 0xb, 1, 0x1800, 1 }, /* AUX */ - [SOUND_MIXER_LINE2] = { 6, 0xc, 0x0, 0, 0x0100, 1 }, /* Mono1 */ - [SOUND_MIXER_LINE3] = { 7, 0xd, 0x0, 0, 0x0200, 1 }, /* Mono2 */ - [SOUND_MIXER_MIC] = { 8, 0xe, 0x0, 0, 0x0001, 1 }, /* Mic */ - [SOUND_MIXER_OGAIN] = { 9, 0xf, 0x0, 0, 0x0000, 1 } /* mono out */ -}; - -static void set_recsrc(struct es1370_state *s, unsigned int val) -{ - unsigned int i, j; - - for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (!(val & (1 << i))) - continue; - if (!mixtable[i].recmask) { - val &= ~(1 << i); - continue; - } - j |= mixtable[i].recmask; - } - s->mix.recsrc = val; - wrcodec(s, 0x12, j & 0xd5); - wrcodec(s, 0x13, j & 0xaa); - wrcodec(s, 0x14, (j >> 8) & 0x17); - wrcodec(s, 0x15, (j >> 8) & 0x0f); - i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60; - if (!s->mix.imix) { - i &= 0xff60; /* mute record and line monitor */ - } - wrcodec(s, 0x10, i); - wrcodec(s, 0x11, i >> 8); -} - -static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - int i, val; - unsigned char l, r, rl, rr; - int __user *p = (int __user *)arg; - - VALIDATE_STATE(s); - if (cmd == SOUND_MIXER_PRIVATE1) { - /* enable/disable/query mixer preamp */ - if (get_user(val, p)) - return -EFAULT; - if (val != -1) { - s->mix.micpreamp = !!val; - wrcodec(s, 0x19, s->mix.micpreamp); - } - return put_user(s->mix.micpreamp, p); - } - if (cmd == SOUND_MIXER_PRIVATE2) { - /* enable/disable/query use of linein as second lineout */ - if (get_user(val, p)) - return -EFAULT; - if (val != -1) { - spin_lock_irqsave(&s->lock, flags); - if (val) - s->ctrl |= CTRL_XCTL0; - else - s->ctrl &= ~CTRL_XCTL0; - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return put_user((s->ctrl & CTRL_XCTL0) ? 1 : 0, p); - } - if (cmd == SOUND_MIXER_PRIVATE3) { - /* enable/disable/query microphone impedance setting */ - if (get_user(val, p)) - return -EFAULT; - if (val != -1) { - spin_lock_irqsave(&s->lock, flags); - if (val) - s->ctrl |= CTRL_XCTL1; - else - s->ctrl &= ~CTRL_XCTL1; - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return put_user((s->ctrl & CTRL_XCTL1) ? 1 : 0, p); - } - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - strncpy(info.id, "ES1370", sizeof(info.id)); - strncpy(info.name, "Ensoniq ES1370", sizeof(info.name)); - info.modify_counter = s->mix.modcnt; - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - strncpy(info.id, "ES1370", sizeof(info.id)); - strncpy(info.name, "Ensoniq ES1370", sizeof(info.name)); - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, p); - if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - if (_SIOC_DIR(cmd) == _SIOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - return put_user(s->mix.recsrc, p); - - case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ - val = SOUND_MASK_IMIX; - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].avail) - val |= 1 << i; - return put_user(val, p); - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].recmask) - val |= 1 << i; - return put_user(val, p); - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].stereo) - val |= 1 << i; - return put_user(val, p); - - case SOUND_MIXER_CAPS: - return put_user(0, p); - - case SOUND_MIXER_IMIX: - return put_user(s->mix.imix, p); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail) - return -EINVAL; - return put_user(s->mix.vol[mixtable[i].volidx], p); - } - } - if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) - return -EINVAL; - s->mix.modcnt++; - switch (_IOC_NR(cmd)) { - - case SOUND_MIXER_IMIX: - if (get_user(s->mix.imix, p)) - return -EFAULT; - set_recsrc(s, s->mix.recsrc); - return 0; - - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - if (get_user(val, p)) - return -EFAULT; - set_recsrc(s, val); - return 0; - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (mixtable[i].stereo) { - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - if (l < 7) { - rl = 0x80; - l = 0; - } else { - rl = 31 - ((l - 7) / 3); - l = (31 - rl) * 3 + 7; - } - if (r < 7) { - rr = 0x80; - r = 0; - } else { - rr = 31 - ((r - 7) / 3); - r = (31 - rr) * 3 + 7; - } - wrcodec(s, mixtable[i].right, rr); - } else { - if (mixtable[i].left == 15) { - if (l < 2) { - rr = rl = 0x80; - r = l = 0; - } else { - rl = 7 - ((l - 2) / 14); - r = l = (7 - rl) * 14 + 2; - } - } else { - if (l < 7) { - rl = 0x80; - r = l = 0; - } else { - rl = 31 - ((l - 7) / 3); - r = l = (31 - rl) * 3 + 7; - } - } - } - wrcodec(s, mixtable[i].left, rl); -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[mixtable[i].volidx] = ((unsigned int)r << 8) | l; -#else - s->mix.vol[mixtable[i].volidx] = val; -#endif - return put_user(s->mix.vol[mixtable[i].volidx], p); - } -} - -/* --------------------------------------------------------------------- */ - -static int es1370_open_mixdev(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct list_head *list; - struct es1370_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1370_state, devs); - if (s->dev_mixer == minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - return nonseekable_open(inode, file); -} - -static int es1370_release_mixdev(struct inode *inode, struct file *file) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - - VALIDATE_STATE(s); - return 0; -} - -static int es1370_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - return mixer_ioctl((struct es1370_state *)file->private_data, cmd, arg); -} - -static /*const*/ struct file_operations es1370_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = es1370_ioctl_mixdev, - .open = es1370_open_mixdev, - .release = es1370_release_mixdev, -}; - -/* --------------------------------------------------------------------- */ - -static int drain_dac1(struct es1370_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count, tmo; - - if (s->dma_dac1.mapped || !s->dma_dac1.ready) - return 0; - add_wait_queue(&s->dma_dac1.wait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac1.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac1.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 - / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; - tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; - if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");) - } - remove_wait_queue(&s->dma_dac1.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -static int drain_dac2(struct es1370_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count, tmo; - - if (s->dma_dac2.mapped || !s->dma_dac2.ready) - return 0; - add_wait_queue(&s->dma_dac2.wait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac2.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac2.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 - / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV); - tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; - if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");) - } - remove_wait_queue(&s->dma_dac2.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static ssize_t es1370_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - mutex_lock(&s->mutex); - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - goto out; - - add_wait_queue(&s->dma_adc.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - swptr = s->dma_adc.swptr; - cnt = s->dma_adc.dmasize-swptr; - if (s->dma_adc.count < cnt) - cnt = s->dma_adc.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_adc.enabled) - start_adc(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->mutex); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out; - } - mutex_lock(&s->mutex); - if (s->dma_adc.mapped) - { - ret = -ENXIO; - goto out; - } - continue; - } - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { - if (!ret) - ret = -EFAULT; - goto out; - } - swptr = (swptr + cnt) % s->dma_adc.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_adc.swptr = swptr; - s->dma_adc.count -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_adc.enabled) - start_adc(s); - } -out: - mutex_unlock(&s->mutex); - remove_wait_queue(&s->dma_adc.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -static ssize_t es1370_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac2.mapped) - return -ENXIO; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - mutex_lock(&s->mutex); - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - goto out; - ret = 0; - add_wait_queue(&s->dma_dac2.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - if (s->dma_dac2.count < 0) { - s->dma_dac2.count = 0; - s->dma_dac2.swptr = s->dma_dac2.hwptr; - } - swptr = s->dma_dac2.swptr; - cnt = s->dma_dac2.dmasize-swptr; - if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize) - cnt = s->dma_dac2.dmasize - s->dma_dac2.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_dac2.enabled) - start_dac2(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->mutex); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out; - } - mutex_lock(&s->mutex); - if (s->dma_dac2.mapped) - { - ret = -ENXIO; - goto out; - } - continue; - } - if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - goto out; - } - swptr = (swptr + cnt) % s->dma_dac2.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_dac2.swptr = swptr; - s->dma_dac2.count += cnt; - s->dma_dac2.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_dac2.enabled) - start_dac2(s); - } -out: - mutex_unlock(&s->mutex); - remove_wait_queue(&s->dma_dac2.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int es1370_poll(struct file *file, struct poll_table_struct *wait) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac2.ready && prog_dmabuf_dac2(s)) - return 0; - poll_wait(file, &s->dma_dac2.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready && prog_dmabuf_adc(s)) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - spin_lock_irqsave(&s->lock, flags); - es1370_update_ptr(s); - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac2.mapped) { - if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac2.dmasize >= s->dma_dac2.count + (signed)s->dma_dac2.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int es1370_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - struct dmabuf *db; - int ret = 0; - unsigned long size; - - VALIDATE_STATE(s); - lock_kernel(); - mutex_lock(&s->mutex); - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf_dac2(s)) != 0) { - goto out; - } - db = &s->dma_dac2; - } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf_adc(s)) != 0) { - goto out; - } - db = &s->dma_adc; - } else { - ret = -EINVAL; - goto out; - } - if (vma->vm_pgoff != 0) { - ret = -EINVAL; - goto out; - } - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) { - ret = -EINVAL; - goto out; - } - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) { - ret = -EAGAIN; - goto out; - } - db->mapped = 1; -out: - mutex_unlock(&s->mutex); - unlock_kernel(); - return ret; -} - -static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, mapped, ret; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac2.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - synchronize_irq(s->irq); - s->dma_dac2.swptr = s->dma_dac2.hwptr = s->dma_dac2.count = s->dma_dac2.total_bytes = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->irq); - s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - if (s->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE)) - return -EINVAL; - if (val < 4000) - val = 4000; - if (val > 50000) - val = 50000; - stop_adc(s); - stop_dac2(s); - s->dma_adc.ready = s->dma_dac2.ready = 0; - spin_lock_irqsave(&s->lock, flags); - s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(val) << CTRL_SH_PCLKDIV); - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val) - s->sctrl |= SCTRL_R1SMB; - else - s->sctrl &= ~SCTRL_R1SMB; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val) - s->sctrl |= SCTRL_P2SMB; - else - s->sctrl &= ~SCTRL_P2SMB; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val >= 2) - s->sctrl |= SCTRL_R1SMB; - else - s->sctrl &= ~SCTRL_R1SMB; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val >= 2) - s->sctrl |= SCTRL_P2SMB; - else - s->sctrl &= ~SCTRL_P2SMB; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - } - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U8, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val == AFMT_S16_LE) - s->sctrl |= SCTRL_R1SEB; - else - s->sctrl &= ~SCTRL_R1SEB; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val == AFMT_S16_LE) - s->sctrl |= SCTRL_P2SEB; - else - s->sctrl &= ~SCTRL_P2SEB; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - } - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? - AFMT_S16_LE : AFMT_U8, p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; - s->dma_adc.enabled = 1; - start_adc(s); - } else { - s->dma_adc.enabled = 0; - stop_adc(s); - } - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; - s->dma_dac2.enabled = 1; - start_dac2(s); - } else { - s->dma_dac2.enabled = 0; - stop_dac2(s); - } - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1370_update_ptr(s); - abinfo.fragsize = s->dma_dac2.fragsize; - count = s->dma_dac2.count; - if (count < 0) - count = 0; - abinfo.bytes = s->dma_dac2.dmasize - count; - abinfo.fragstotal = s->dma_dac2.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1370_update_ptr(s); - abinfo.fragsize = s->dma_adc.fragsize; - count = s->dma_adc.count; - if (count < 0) - count = 0; - abinfo.bytes = count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1370_update_ptr(s); - count = s->dma_dac2.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - return put_user(count, p); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1370_update_ptr(s); - cinfo.bytes = s->dma_adc.total_bytes; - count = s->dma_adc.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_adc.fragshift; - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1370_update_ptr(s); - cinfo.bytes = s->dma_dac2.total_bytes; - count = s->dma_dac2.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac2.fragshift; - cinfo.ptr = s->dma_dac2.hwptr; - if (s->dma_dac2.mapped) - s->dma_dac2.count &= s->dma_dac2.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf_dac2(s))) - return val; - return put_user(s->dma_dac2.fragsize, p); - } - if ((val = prog_dmabuf_adc(s))) - return val; - return put_user(s->dma_adc.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac2.ossfragshift = val & 0xffff; - s->dma_dac2.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac2.ossfragshift < 4) - s->dma_dac2.ossfragshift = 4; - if (s->dma_dac2.ossfragshift > 15) - s->dma_dac2.ossfragshift = 15; - if (s->dma_dac2.ossmaxfrags < 4) - s->dma_dac2.ossmaxfrags = 4; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision)) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - s->dma_dac2.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? - 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? - 16 : 8, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return mixer_ioctl(s, cmd, arg); -} - -static int es1370_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct es1370_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1370_state, devs); - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_READ|FMODE_WRITE))) - s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV); - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; - s->dma_adc.enabled = 1; - s->sctrl &= ~SCTRL_R1FMT; - if ((minor & 0xf) == SND_DEV_DSP16) - s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_R1FMT; - else - s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_R1FMT; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0; - s->dma_dac2.enabled = 1; - s->sctrl &= ~SCTRL_P2FMT; - if ((minor & 0xf) == SND_DEV_DSP16) - s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P2FMT; - else - s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_P2FMT; - } - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - mutex_unlock(&s->open_mutex); - mutex_init(&s->mutex); - return nonseekable_open(inode, file); -} - -static int es1370_release(struct inode *inode, struct file *file) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - if (file->f_mode & FMODE_WRITE) - drain_dac2(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - synchronize_irq(s->irq); - dealloc_dmabuf(s, &s->dma_dac2); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - } - s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE)); - wake_up(&s->open_wait); - mutex_unlock(&s->open_mutex); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations es1370_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = es1370_read, - .write = es1370_write, - .poll = es1370_poll, - .ioctl = es1370_ioctl, - .mmap = es1370_mmap, - .open = es1370_open, - .release = es1370_release, -}; - -/* --------------------------------------------------------------------- */ - -static ssize_t es1370_write_dac(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac1.mapped) - return -ENXIO; - if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - add_wait_queue(&s->dma_dac1.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - if (s->dma_dac1.count < 0) { - s->dma_dac1.count = 0; - s->dma_dac1.swptr = s->dma_dac1.hwptr; - } - swptr = s->dma_dac1.swptr; - cnt = s->dma_dac1.dmasize-swptr; - if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize) - cnt = s->dma_dac1.dmasize - s->dma_dac1.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_dac1.enabled) - start_dac1(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - swptr = (swptr + cnt) % s->dma_dac1.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_dac1.swptr = swptr; - s->dma_dac1.count += cnt; - s->dma_dac1.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_dac1.enabled) - start_dac1(s); - } - remove_wait_queue(&s->dma_dac1.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int es1370_poll_dac(struct file *file, struct poll_table_struct *wait) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (!s->dma_dac1.ready && prog_dmabuf_dac1(s)) - return 0; - poll_wait(file, &s->dma_dac1.wait, wait); - spin_lock_irqsave(&s->lock, flags); - es1370_update_ptr(s); - if (s->dma_dac1.mapped) { - if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac1.dmasize >= s->dma_dac1.count + (signed)s->dma_dac1.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int es1370_mmap_dac(struct file *file, struct vm_area_struct *vma) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - int ret; - unsigned long size; - - VALIDATE_STATE(s); - if (!(vma->vm_flags & VM_WRITE)) - return -EINVAL; - lock_kernel(); - if ((ret = prog_dmabuf_dac1(s)) != 0) - goto out; - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << s->dma_dac1.buforder)) - goto out; - ret = -EAGAIN; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(s->dma_dac1.rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - s->dma_dac1.mapped = 1; - ret = 0; -out: - unlock_kernel(); - return ret; -} - -static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - unsigned ctrl; - int val, ret; - int __user *p = (int __user *)arg; - - VALIDATE_STATE(s); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - return drain_dac1(s, 0/*file->f_flags & O_NONBLOCK*/); - - case SNDCTL_DSP_SETDUPLEX: - return -EINVAL; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - stop_dac1(s); - synchronize_irq(s->irq); - s->dma_dac1.swptr = s->dma_dac1.hwptr = s->dma_dac1.count = s->dma_dac1.total_bytes = 0; - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - stop_dac1(s); - s->dma_dac1.ready = 0; - for (ctrl = 0; ctrl <= 2; ctrl++) - if (val < (dac1_samplerate[ctrl] + dac1_samplerate[ctrl+1]) / 2) - break; - spin_lock_irqsave(&s->lock, flags); - s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (ctrl << CTRL_SH_WTSRSEL); - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - stop_dac1(s); - s->dma_dac1.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val) - s->sctrl |= SCTRL_P1SMB; - else - s->sctrl &= ~SCTRL_P1SMB; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - if (s->dma_dac1.mapped) - return -EINVAL; - stop_dac1(s); - s->dma_dac1.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val >= 2) - s->sctrl |= SCTRL_P1SMB; - else - s->sctrl &= ~SCTRL_P1SMB; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U8, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - stop_dac1(s); - s->dma_dac1.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val == AFMT_S16_LE) - s->sctrl |= SCTRL_P1SEB; - else - s->sctrl &= ~SCTRL_P1SEB; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return put_user((s->sctrl & SCTRL_P1SEB) ? AFMT_S16_LE : AFMT_U8, p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) - return ret; - s->dma_dac1.enabled = 1; - start_dac1(s); - } else { - s->dma_dac1.enabled = 0; - stop_dac1(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1370_update_ptr(s); - abinfo.fragsize = s->dma_dac1.fragsize; - count = s->dma_dac1.count; - if (count < 0) - count = 0; - abinfo.bytes = s->dma_dac1.dmasize - count; - abinfo.fragstotal = s->dma_dac1.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1370_update_ptr(s); - count = s->dma_dac1.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - return put_user(count, p); - - case SNDCTL_DSP_GETOPTR: - if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1370_update_ptr(s); - cinfo.bytes = s->dma_dac1.total_bytes; - count = s->dma_dac1.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac1.fragshift; - cinfo.ptr = s->dma_dac1.hwptr; - if (s->dma_dac1.mapped) - s->dma_dac1.count &= s->dma_dac1.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if ((val = prog_dmabuf_dac1(s))) - return val; - return put_user(s->dma_dac1.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - s->dma_dac1.ossfragshift = val & 0xffff; - s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac1.ossfragshift < 4) - s->dma_dac1.ossfragshift = 4; - if (s->dma_dac1.ossfragshift > 15) - s->dma_dac1.ossfragshift = 15; - if (s->dma_dac1.ossmaxfrags < 4) - s->dma_dac1.ossmaxfrags = 4; - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if (s->dma_dac1.subdivision) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - s->dma_dac1.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return mixer_ioctl(s, cmd, arg); -} - -static int es1370_open_dac(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct es1370_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1370_state, devs); - if (!((s->dev_dac ^ minor) & ~0xf)) - break; - } - VALIDATE_STATE(s); - /* we allow opening with O_RDWR, most programs do it although they will only write */ -#if 0 - if (file->f_mode & FMODE_READ) - return -EPERM; -#endif - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & FMODE_DAC) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0; - s->dma_dac1.enabled = 1; - spin_lock_irqsave(&s->lock, flags); - s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (1 << CTRL_SH_WTSRSEL); - s->sctrl &= ~SCTRL_P1FMT; - if ((minor & 0xf) == SND_DEV_DSP16) - s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P1FMT; - else - s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_P1FMT; - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= FMODE_DAC; - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int es1370_release_dac(struct inode *inode, struct file *file) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - drain_dac1(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - stop_dac1(s); - dealloc_dmabuf(s, &s->dma_dac1); - s->open_mode &= ~FMODE_DAC; - wake_up(&s->open_wait); - mutex_unlock(&s->open_mutex); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations es1370_dac_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = es1370_write_dac, - .poll = es1370_poll_dac, - .ioctl = es1370_ioctl_dac, - .mmap = es1370_mmap_dac, - .open = es1370_open_dac, - .release = es1370_release_dac, -}; - -/* --------------------------------------------------------------------- */ - -static ssize_t es1370_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - if (count == 0) - return 0; - ret = 0; - add_wait_queue(&s->midi.iwait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.ird; - cnt = MIDIINBUF - ptr; - if (s->midi.icnt < cnt) - cnt = s->midi.icnt; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - ptr = (ptr + cnt) % MIDIINBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.ird = ptr; - s->midi.icnt -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - break; - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&s->midi.iwait, &wait); - return ret; -} - -static ssize_t es1370_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - if (count == 0) - return 0; - ret = 0; - add_wait_queue(&s->midi.owait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.owr; - cnt = MIDIOUTBUF - ptr; - if (s->midi.ocnt + cnt > MIDIOUTBUF) - cnt = MIDIOUTBUF - s->midi.ocnt; - if (cnt <= 0) { - __set_current_state(TASK_INTERRUPTIBLE); - es1370_handle_midi(s); - } - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - ptr = (ptr + cnt) % MIDIOUTBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.owr = ptr; - s->midi.ocnt += cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - spin_lock_irqsave(&s->lock, flags); - es1370_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&s->midi.owait, &wait); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int es1370_midi_poll(struct file *file, struct poll_table_struct *wait) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) - poll_wait(file, &s->midi.owait, wait); - if (file->f_mode & FMODE_READ) - poll_wait(file, &s->midi.iwait, wait); - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ) { - if (s->midi.icnt > 0) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->midi.ocnt < MIDIOUTBUF) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int es1370_midi_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct es1370_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1370_state, devs); - if (s->dev_midi == minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - outb(UCTRL_CNTRL_SWR, s->io+ES1370_REG_UART_CONTROL); - outb(0, s->io+ES1370_REG_UART_CONTROL); - outb(0, s->io+ES1370_REG_UART_TEST); - } - if (file->f_mode & FMODE_READ) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - } - if (file->f_mode & FMODE_WRITE) { - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - } - s->ctrl |= CTRL_UART_EN; - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - es1370_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int es1370_midi_release(struct inode *inode, struct file *file) -{ - struct es1370_state *s = (struct es1370_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - unsigned count, tmo; - - VALIDATE_STATE(s); - - lock_kernel(); - if (file->f_mode & FMODE_WRITE) { - add_wait_queue(&s->midi.owait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->midi.ocnt; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (file->f_flags & O_NONBLOCK) - break; - tmo = (count * HZ) / 3100; - if (!schedule_timeout(tmo ? : 1) && tmo) - DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");) - } - remove_wait_queue(&s->midi.owait, &wait); - set_current_state(TASK_RUNNING); - } - mutex_lock(&s->open_mutex); - s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE)); - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - s->ctrl &= ~CTRL_UART_EN; - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - } - spin_unlock_irqrestore(&s->lock, flags); - wake_up(&s->open_wait); - mutex_unlock(&s->open_mutex); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations es1370_midi_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = es1370_midi_read, - .write = es1370_midi_write, - .poll = es1370_midi_poll, - .open = es1370_midi_open, - .release = es1370_midi_release, -}; - -/* --------------------------------------------------------------------- */ - -/* maximum number of devices; only used for command line params */ -#define NR_DEVICE 5 - -static int lineout[NR_DEVICE]; -static int micbias[NR_DEVICE]; - -static unsigned int devindex; - -module_param_array(lineout, bool, NULL, 0); -MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out"); -module_param_array(micbias, bool, NULL, 0); -MODULE_PARM_DESC(micbias, "sets the +5V bias for an electret microphone"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("ES1370 AudioPCI Driver"); -MODULE_LICENSE("GPL"); - - -/* --------------------------------------------------------------------- */ - -static struct initvol { - int mixch; - int vol; -} initvol[] __devinitdata = { - { SOUND_MIXER_WRITE_VOLUME, 0x4040 }, - { SOUND_MIXER_WRITE_PCM, 0x4040 }, - { SOUND_MIXER_WRITE_SYNTH, 0x4040 }, - { SOUND_MIXER_WRITE_CD, 0x4040 }, - { SOUND_MIXER_WRITE_LINE, 0x4040 }, - { SOUND_MIXER_WRITE_LINE1, 0x4040 }, - { SOUND_MIXER_WRITE_LINE2, 0x4040 }, - { SOUND_MIXER_WRITE_LINE3, 0x4040 }, - { SOUND_MIXER_WRITE_MIC, 0x4040 }, - { SOUND_MIXER_WRITE_OGAIN, 0x4040 } -}; - -#ifdef SUPPORT_JOYSTICK - -static int __devinit es1370_register_gameport(struct es1370_state *s) -{ - struct gameport *gp; - - if (!request_region(0x200, JOY_EXTENT, "es1370")) { - printk(KERN_ERR "es1370: joystick io port 0x200 in use\n"); - return -EBUSY; - } - - s->gameport = gp = gameport_allocate_port(); - if (!gp) { - printk(KERN_ERR "es1370: can not allocate memory for gameport\n"); - release_region(0x200, JOY_EXTENT); - return -ENOMEM; - } - - gameport_set_name(gp, "ESS1370"); - gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev)); - gp->dev.parent = &s->dev->dev; - gp->io = 0x200; - - s->ctrl |= CTRL_JYSTK_EN; - outl(s->ctrl, s->io + ES1370_REG_CONTROL); - - gameport_register_port(gp); - - return 0; -} - -static inline void es1370_unregister_gameport(struct es1370_state *s) -{ - if (s->gameport) { - int gpio = s->gameport->io; - gameport_unregister_port(s->gameport); - release_region(gpio, JOY_EXTENT); - - } -} - -#else -static inline int es1370_register_gameport(struct es1370_state *s) { return -ENOSYS; } -static inline void es1370_unregister_gameport(struct es1370_state *s) { } -#endif /* SUPPORT_JOYSTICK */ - -static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) -{ - struct es1370_state *s; - mm_segment_t fs; - int i, val, ret; - - if ((ret=pci_enable_device(pcidev))) - return ret; - - if ( !(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) || - !pci_resource_start(pcidev, 0) - ) - return -ENODEV; - if (pcidev->irq == 0) - return -ENODEV; - i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); - if (i) { - printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n"); - return i; - } - if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) { - printk(KERN_WARNING "es1370: out of memory\n"); - return -ENOMEM; - } - memset(s, 0, sizeof(struct es1370_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac1.wait); - init_waitqueue_head(&s->dma_dac2.wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->midi.iwait); - init_waitqueue_head(&s->midi.owait); - mutex_init(&s->open_mutex); - spin_lock_init(&s->lock); - s->magic = ES1370_MAGIC; - s->dev = pcidev; - s->io = pci_resource_start(pcidev, 0); - s->irq = pcidev->irq; - if (!request_region(s->io, ES1370_EXTENT, "es1370")) { - printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1); - ret = -EBUSY; - goto err_region; - } - if ((ret=request_irq(s->irq, es1370_interrupt, IRQF_SHARED, "es1370",s))) { - printk(KERN_ERR "es1370: irq %u in use\n", s->irq); - goto err_irq; - } - - /* initialize codec registers */ - /* note: setting CTRL_SERR_DIS is reported to break - * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */ - s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL); - if (lineout[devindex]) - s->ctrl |= CTRL_XCTL0; - if (micbias[devindex]) - s->ctrl |= CTRL_XCTL1; - s->sctrl = 0; - printk(KERN_INFO "es1370: adapter at io %#lx irq %u, line %s, mic impedance %s\n", - s->io, s->irq, (s->ctrl & CTRL_XCTL0) ? "out" : "in", - (s->ctrl & CTRL_XCTL1) ? "1" : "0"); - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) { - ret = s->dev_audio; - goto err_dev1; - } - if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops, -1)) < 0) { - ret = s->dev_mixer; - goto err_dev2; - } - if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops, -1)) < 0) { - ret = s->dev_dac; - goto err_dev3; - } - if ((s->dev_midi = register_sound_midi(&es1370_midi_fops, -1)) < 0) { - ret = s->dev_midi; - goto err_dev4; - } - /* initialize the chips */ - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - /* point phantom write channel to "bugbuf" */ - s->bugbuf_cpu = pci_alloc_consistent(pcidev,16,&s->bugbuf_dma); - if (!s->bugbuf_cpu) { - ret = -ENOMEM; - goto err_dev5; - } - outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE); - outl(s->bugbuf_dma, s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff)); - outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff)); - pci_set_master(pcidev); /* enable bus mastering */ - wrcodec(s, 0x16, 3); /* no RST, PD */ - wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!! */ - wrcodec(s, 0x18, 0); /* recording source is mixer */ - wrcodec(s, 0x19, s->mix.micpreamp = 1); /* turn on MIC preamp */ - s->mix.imix = 1; - fs = get_fs(); - set_fs(KERNEL_DS); - val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); - } - set_fs(fs); - - es1370_register_gameport(s); - - /* store it in the driver field */ - pci_set_drvdata(pcidev, s); - /* put it into driver list */ - list_add_tail(&s->devs, &devs); - /* increment devindex */ - if (devindex < NR_DEVICE-1) - devindex++; - return 0; - - err_dev5: - unregister_sound_midi(s->dev_midi); - err_dev4: - unregister_sound_dsp(s->dev_dac); - err_dev3: - unregister_sound_mixer(s->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - printk(KERN_ERR "es1370: cannot register misc device\n"); - free_irq(s->irq, s); - err_irq: - release_region(s->io, ES1370_EXTENT); - err_region: - kfree(s); - return ret; -} - -static void __devexit es1370_remove(struct pci_dev *dev) -{ - struct es1370_state *s = pci_get_drvdata(dev); - - if (!s) - return; - list_del(&s->devs); - outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */ - outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ - synchronize_irq(s->irq); - free_irq(s->irq, s); - es1370_unregister_gameport(s); - release_region(s->io, ES1370_EXTENT); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_dsp(s->dev_dac); - unregister_sound_midi(s->dev_midi); - pci_free_consistent(dev, 16, s->bugbuf_cpu, s->bugbuf_dma); - kfree(s); - pci_set_drvdata(dev, NULL); -} - -static struct pci_device_id id_table[] = { - { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, id_table); - -static struct pci_driver es1370_driver = { - .name = "es1370", - .id_table = id_table, - .probe = es1370_probe, - .remove = __devexit_p(es1370_remove), -}; - -static int __init init_es1370(void) -{ - printk(KERN_INFO "es1370: version v0.38 time " __TIME__ " " __DATE__ "\n"); - return pci_register_driver(&es1370_driver); -} - -static void __exit cleanup_es1370(void) -{ - printk(KERN_INFO "es1370: unloading\n"); - pci_unregister_driver(&es1370_driver); -} - -module_init(init_es1370); -module_exit(cleanup_es1370); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -/* format is: es1370=lineout[,micbias]] */ - -static int __init es1370_setup(char *str) -{ - static unsigned __initdata nr_dev = 0; - - if (nr_dev >= NR_DEVICE) - return 0; - - (void) - ((get_option(&str,&lineout [nr_dev]) == 2) - && get_option(&str,&micbias [nr_dev]) - ); - - nr_dev++; - return 1; -} - -__setup("es1370=", es1370_setup); - -#endif /* MODULE */ diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c deleted file mode 100644 index 82f40a0a5c9c..000000000000 --- a/sound/oss/esssolo1.c +++ /dev/null @@ -1,2516 +0,0 @@ -/****************************************************************************/ - -/* - * esssolo1.c -- ESS Technology Solo1 (ES1946) audio driver. - * - * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module command line parameters: - * none so far - * - * Supported devices: - * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible - * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible - * /dev/midi simple MIDI UART interface, no ioctl - * - * Revision history - * 10.11.1998 0.1 Initial release (without any hardware) - * 22.03.1999 0.2 cinfo.blocks should be reset after GETxPTR ioctl. - * reported by Johan Maes - * return EAGAIN instead of EBUSY when O_NONBLOCK - * read/write cannot be executed - * 07.04.1999 0.3 implemented the following ioctl's: SOUND_PCM_READ_RATE, - * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; - * Alpha fixes reported by Peter Jones - * 15.06.1999 0.4 Fix bad allocation bug. - * Thanks to Deti Fliegl - * 28.06.1999 0.5 Add pci_set_master - * 12.08.1999 0.6 Fix MIDI UART crashing the driver - * Changed mixer semantics from OSS documented - * behaviour to OSS "code behaviour". - * Recording might actually work now. - * The real DDMA controller address register is at PCI config - * 0x60, while the register at 0x18 is used as a placeholder - * register for BIOS address allocation. This register - * is supposed to be copied into 0x60, according - * to the Solo1 datasheet. When I do that, I can access - * the DDMA registers except the mask bit, which - * is stuck at 1. When I copy the contents of 0x18 +0x10 - * to the DDMA base register, everything seems to work. - * The fun part is that the Windows Solo1 driver doesn't - * seem to do these tricks. - * Bugs remaining: plops and clicks when starting/stopping playback - * 31.08.1999 0.7 add spin_lock_init - * replaced current->state = x with set_current_state(x) - * 03.09.1999 0.8 change read semantics for MIDI to match - * OSS more closely; remove possible wakeup race - * 07.10.1999 0.9 Fix initialization; complain if sequencer writes time out - * Revised resource grabbing for the FM synthesizer - * 28.10.1999 0.10 More waitqueue races fixed - * 09.12.1999 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M) - * Disabling recording on Alpha - * 12.01.2000 0.12 Prevent some ioctl's from returning bad count values on underrun/overrun; - * Tim Janik's BSE (Bedevilled Sound Engine) found this - * Integrated (aka redid 8-)) APM support patch by Zach Brown - * 07.02.2000 0.13 Use pci_alloc_consistent and pci_register_driver - * 19.02.2000 0.14 Use pci_dma_supported to determine if recording should be disabled - * 13.03.2000 0.15 Reintroduce initialization of a couple of PCI config space registers - * 21.11.2000 0.16 Initialize dma buffers in poll, otherwise poll may return a bogus mask - * 12.12.2000 0.17 More dma buffer initializations, patch from - * Tjeerd Mulder - * 31.01.2001 0.18 Register/Unregister gameport, original patch from - * Nathaniel Daw - * Fix SETTRIGGER non OSS API conformity - * 10.03.2001 provide abs function, prevent picking up a bogus kernel macro - * for abs. Bug report by Andrew Morton - * 15.05.2001 pci_enable_device moved, return values in probe cleaned - * up. Marcus Meissner - * 22.05.2001 0.19 more cleanups, changed PM to PCI 2.4 style, got rid - * of global list of devices, using pci device data. - * Marcus Meissner - * 03.01.2003 0.20 open_mode fixes from Georg Acher - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include - -#include "dm.h" - -/* --------------------------------------------------------------------- */ - -#undef OSS_DOCUMENTED_MIXER_SEMANTICS - -/* --------------------------------------------------------------------- */ - -#ifndef PCI_VENDOR_ID_ESS -#define PCI_VENDOR_ID_ESS 0x125d -#endif -#ifndef PCI_DEVICE_ID_ESS_SOLO1 -#define PCI_DEVICE_ID_ESS_SOLO1 0x1969 -#endif - -#define SOLO1_MAGIC ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1) - -#define DDMABASE_OFFSET 0 /* chip bug workaround kludge */ -#define DDMABASE_EXTENT 16 - -#define IOBASE_EXTENT 16 -#define SBBASE_EXTENT 16 -#define VCBASE_EXTENT (DDMABASE_EXTENT+DDMABASE_OFFSET) -#define MPUBASE_EXTENT 4 -#define GPBASE_EXTENT 4 -#define GAMEPORT_EXTENT 4 - -#define FMSYNTH_EXTENT 4 - -/* MIDI buffer sizes */ - -#define MIDIINBUF 256 -#define MIDIOUTBUF 256 - -#define FMODE_MIDI_SHIFT 3 -#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) -#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) - -#define FMODE_DMFM 0x10 - -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -#define SUPPORT_JOYSTICK 1 -#endif - -static struct pci_driver solo1_driver; - -/* --------------------------------------------------------------------- */ - -struct solo1_state { - /* magic */ - unsigned int magic; - - /* the corresponding pci_dev structure */ - struct pci_dev *dev; - - /* soundcore stuff */ - int dev_audio; - int dev_mixer; - int dev_midi; - int dev_dmfm; - - /* hardware resources */ - unsigned long iobase, sbbase, vcbase, ddmabase, mpubase; /* long for SPARC */ - unsigned int irq; - - /* mixer registers */ - struct { - unsigned short vol[10]; - unsigned int recsrc; - unsigned int modcnt; - unsigned short micpreamp; - } mix; - - /* wave stuff */ - unsigned fmt; - unsigned channels; - unsigned rate; - unsigned char clkdiv; - unsigned ena; - - spinlock_t lock; - struct mutex open_mutex; - mode_t open_mode; - wait_queue_head_t open_wait; - - struct dmabuf { - void *rawbuf; - dma_addr_t dmaaddr; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - unsigned hwptr, swptr; - unsigned total_bytes; - int count; - unsigned error; /* over/underrun */ - wait_queue_head_t wait; - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dmasize; - unsigned fragsamples; - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned endcleared:1; - unsigned enabled:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac, dma_adc; - - /* midi stuff */ - struct { - unsigned ird, iwr, icnt; - unsigned ord, owr, ocnt; - wait_queue_head_t iwait; - wait_queue_head_t owait; - struct timer_list timer; - unsigned char ibuf[MIDIINBUF]; - unsigned char obuf[MIDIOUTBUF]; - } midi; - -#if SUPPORT_JOYSTICK - struct gameport *gameport; -#endif -}; - -/* --------------------------------------------------------------------- */ - -static inline void write_seq(struct solo1_state *s, unsigned char data) -{ - int i; - unsigned long flags; - - /* the local_irq_save stunt is to send the data within the command window */ - for (i = 0; i < 0xffff; i++) { - local_irq_save(flags); - if (!(inb(s->sbbase+0xc) & 0x80)) { - outb(data, s->sbbase+0xc); - local_irq_restore(flags); - return; - } - local_irq_restore(flags); - } - printk(KERN_ERR "esssolo1: write_seq timeout\n"); - outb(data, s->sbbase+0xc); -} - -static inline int read_seq(struct solo1_state *s, unsigned char *data) -{ - int i; - - if (!data) - return 0; - for (i = 0; i < 0xffff; i++) - if (inb(s->sbbase+0xe) & 0x80) { - *data = inb(s->sbbase+0xa); - return 1; - } - printk(KERN_ERR "esssolo1: read_seq timeout\n"); - return 0; -} - -static inline int reset_ctrl(struct solo1_state *s) -{ - int i; - - outb(3, s->sbbase+6); /* clear sequencer and FIFO */ - udelay(10); - outb(0, s->sbbase+6); - for (i = 0; i < 0xffff; i++) - if (inb(s->sbbase+0xe) & 0x80) - if (inb(s->sbbase+0xa) == 0xaa) { - write_seq(s, 0xc6); /* enter enhanced mode */ - return 1; - } - return 0; -} - -static void write_ctrl(struct solo1_state *s, unsigned char reg, unsigned char data) -{ - write_seq(s, reg); - write_seq(s, data); -} - -#if 0 /* unused */ -static unsigned char read_ctrl(struct solo1_state *s, unsigned char reg) -{ - unsigned char r; - - write_seq(s, 0xc0); - write_seq(s, reg); - read_seq(s, &r); - return r; -} -#endif /* unused */ - -static void write_mixer(struct solo1_state *s, unsigned char reg, unsigned char data) -{ - outb(reg, s->sbbase+4); - outb(data, s->sbbase+5); -} - -static unsigned char read_mixer(struct solo1_state *s, unsigned char reg) -{ - outb(reg, s->sbbase+4); - return inb(s->sbbase+5); -} - -/* --------------------------------------------------------------------- */ - -static inline unsigned ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -/* --------------------------------------------------------------------- */ - -static inline void stop_dac(struct solo1_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ena &= ~FMODE_WRITE; - write_mixer(s, 0x78, 0x10); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac(struct solo1_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { - s->ena |= FMODE_WRITE; - write_mixer(s, 0x78, 0x12); - udelay(10); - write_mixer(s, 0x78, 0x13); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void stop_adc(struct solo1_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ena &= ~FMODE_READ; - write_ctrl(s, 0xb8, 0xe); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_adc(struct solo1_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) - && s->dma_adc.ready) { - s->ena |= FMODE_READ; - write_ctrl(s, 0xb8, 0xf); -#if 0 - printk(KERN_DEBUG "solo1: DMAbuffer: 0x%08lx\n", (long)s->dma_adc.rawbuf); - printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n", - inb(s->ddmabase+0xf), inw(s->ddmabase+4), inl(s->ddmabase), inb(s->ddmabase+8)); -#endif - outb(0, s->ddmabase+0xd); /* master reset */ - outb(1, s->ddmabase+0xf); /* mask */ - outb(0x54/*0x14*/, s->ddmabase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */ - outl(virt_to_bus(s->dma_adc.rawbuf), s->ddmabase); - outw(s->dma_adc.dmasize-1, s->ddmabase+4); - outb(0, s->ddmabase+0xf); - } - spin_unlock_irqrestore(&s->lock, flags); -#if 0 - printk(KERN_DEBUG "solo1: start DMA: reg B8: 0x%02x SBstat: 0x%02x\n" - KERN_DEBUG "solo1: DMA: stat: 0x%02x cnt: 0x%04x mask: 0x%02x\n", - read_ctrl(s, 0xb8), inb(s->sbbase+0xc), - inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->ddmabase+0xf)); - printk(KERN_DEBUG "solo1: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n" - KERN_DEBUG "solo1: B1: 0x%02x B2: 0x%02x B4: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n", - read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), - read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb4), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), - read_ctrl(s, 0xb9)); -#endif -} - -/* --------------------------------------------------------------------- */ - -#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - -static inline void dealloc_dmabuf(struct solo1_state *s, struct dmabuf *db) -{ - struct page *page, *pend; - - if (db->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - ClearPageReserved(page); - pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); - } - db->rawbuf = NULL; - db->mapped = db->ready = 0; -} - -static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db) -{ - int order; - unsigned bytespersec; - unsigned bufs, sample_shift = 0; - struct page *page, *pend; - - db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; - if (!db->rawbuf) { - db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) - break; - if (!db->rawbuf) - return -ENOMEM; - db->buforder = order; - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - SetPageReserved(page); - } - if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE)) - sample_shift++; - if (s->channels > 1) - sample_shift++; - bytespersec = s->rate << sample_shift; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytespersec) - db->fragshift = ld2(bytespersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytespersec/100/(db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift; - db->dmasize = db->numfrag << db->fragshift; - db->enabled = 1; - return 0; -} - -static inline int prog_dmabuf_adc(struct solo1_state *s) -{ - unsigned long va; - int c; - - stop_adc(s); - /* check if PCI implementation supports 24bit busmaster DMA */ - if (s->dev->dma_mask > 0xffffff) - return -EIO; - if ((c = prog_dmabuf(s, &s->dma_adc))) - return c; - va = s->dma_adc.dmaaddr; - if ((va & ~((1<<24)-1))) - panic("solo1: buffer above 16M boundary"); - outb(0, s->ddmabase+0xd); /* clear */ - outb(1, s->ddmabase+0xf); /* mask */ - /*outb(0, s->ddmabase+8);*/ /* enable (enable is active low!) */ - outb(0x54, s->ddmabase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */ - outl(va, s->ddmabase); - outw(s->dma_adc.dmasize-1, s->ddmabase+4); - c = - s->dma_adc.fragsamples; - write_ctrl(s, 0xa4, c); - write_ctrl(s, 0xa5, c >> 8); - outb(0, s->ddmabase+0xf); - s->dma_adc.ready = 1; - return 0; -} - -static int prog_dmabuf_dac(struct solo1_state *s) -{ - unsigned long va; - int c; - - stop_dac(s); - if ((c = prog_dmabuf(s, &s->dma_dac))) - return c; - memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */ - va = s->dma_dac.dmaaddr; - if ((va ^ (va + s->dma_dac.dmasize - 1)) & ~((1<<20)-1)) - panic("solo1: buffer crosses 1M boundary"); - outl(va, s->iobase); - /* warning: s->dma_dac.dmasize & 0xffff must not be zero! i.e. this limits us to a 32k buffer */ - outw(s->dma_dac.dmasize, s->iobase+4); - c = - s->dma_dac.fragsamples; - write_mixer(s, 0x74, c); - write_mixer(s, 0x76, c >> 8); - outb(0xa, s->iobase+6); - s->dma_dac.ready = 1; - return 0; -} - -static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c) -{ - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(((char *)buf) + bptr, c, x); - bptr = 0; - len -= x; - } - memset(((char *)buf) + bptr, c, len); -} - -/* call with spinlock held! */ - -static void solo1_update_ptr(struct solo1_state *s) -{ - int diff; - unsigned hwptr; - - /* update ADC pointer */ - if (s->ena & FMODE_READ) { - hwptr = (s->dma_adc.dmasize - 1 - inw(s->ddmabase+4)) % s->dma_adc.dmasize; - diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; - s->dma_adc.hwptr = hwptr; - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; -#if 0 - printk(KERN_DEBUG "solo1: rd: hwptr %u swptr %u dmasize %u count %u\n", - s->dma_adc.hwptr, s->dma_adc.swptr, s->dma_adc.dmasize, s->dma_adc.count); -#endif - if (s->dma_adc.mapped) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - wake_up(&s->dma_adc.wait); - } else { - if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { - s->ena &= ~FMODE_READ; - write_ctrl(s, 0xb8, 0xe); - s->dma_adc.error++; - } - if (s->dma_adc.count > 0) - wake_up(&s->dma_adc.wait); - } - } - /* update DAC pointer */ - if (s->ena & FMODE_WRITE) { - hwptr = (s->dma_dac.dmasize - inw(s->iobase+4)) % s->dma_dac.dmasize; - diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; - s->dma_dac.hwptr = hwptr; - s->dma_dac.total_bytes += diff; -#if 0 - printk(KERN_DEBUG "solo1: wr: hwptr %u swptr %u dmasize %u count %u\n", - s->dma_dac.hwptr, s->dma_dac.swptr, s->dma_dac.dmasize, s->dma_dac.count); -#endif - if (s->dma_dac.mapped) { - s->dma_dac.count += diff; - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - wake_up(&s->dma_dac.wait); - } else { - s->dma_dac.count -= diff; - if (s->dma_dac.count <= 0) { - s->ena &= ~FMODE_WRITE; - write_mixer(s, 0x78, 0x12); - s->dma_dac.error++; - } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { - clear_advance(s->dma_dac.rawbuf, s->dma_dac.dmasize, s->dma_dac.swptr, - s->dma_dac.fragsize, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80); - s->dma_dac.endcleared = 1; - } - if (s->dma_dac.count < (signed)s->dma_dac.dmasize) - wake_up(&s->dma_dac.wait); - } - } -} - -/* --------------------------------------------------------------------- */ - -static void prog_codec(struct solo1_state *s) -{ - unsigned long flags; - int fdiv, filter; - unsigned char c; - - reset_ctrl(s); - write_seq(s, 0xd3); - /* program sampling rates */ - filter = s->rate * 9 / 20; /* Set filter roll-off to 90% of rate/2 */ - fdiv = 256 - 7160000 / (filter * 82); - spin_lock_irqsave(&s->lock, flags); - write_ctrl(s, 0xa1, s->clkdiv); - write_ctrl(s, 0xa2, fdiv); - write_mixer(s, 0x70, s->clkdiv); - write_mixer(s, 0x72, fdiv); - /* program ADC parameters */ - write_ctrl(s, 0xb8, 0xe); - write_ctrl(s, 0xb9, /*0x1*/0); - write_ctrl(s, 0xa8, (s->channels > 1) ? 0x11 : 0x12); - c = 0xd0; - if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE)) - c |= 0x04; - if (s->fmt & (AFMT_S16_LE | AFMT_S8)) - c |= 0x20; - if (s->channels > 1) - c ^= 0x48; - write_ctrl(s, 0xb7, (c & 0x70) | 1); - write_ctrl(s, 0xb7, c); - write_ctrl(s, 0xb1, 0x50); - write_ctrl(s, 0xb2, 0x50); - /* program DAC parameters */ - c = 0x40; - if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE)) - c |= 1; - if (s->fmt & (AFMT_S16_LE | AFMT_S8)) - c |= 4; - if (s->channels > 1) - c |= 2; - write_mixer(s, 0x7a, c); - write_mixer(s, 0x78, 0x10); - s->ena = 0; - spin_unlock_irqrestore(&s->lock, flags); -} - -/* --------------------------------------------------------------------- */ - -static const char invalid_magic[] = KERN_CRIT "solo1: invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != SOLO1_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -/* --------------------------------------------------------------------- */ - -static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long arg) -{ - static const unsigned int mixer_src[8] = { - SOUND_MASK_MIC, SOUND_MASK_MIC, SOUND_MASK_CD, SOUND_MASK_VOLUME, - SOUND_MASK_MIC, 0, SOUND_MASK_LINE, 0 - }; - static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_PCM] = 1, /* voice */ - [SOUND_MIXER_SYNTH] = 2, /* FM */ - [SOUND_MIXER_CD] = 3, /* CD */ - [SOUND_MIXER_LINE] = 4, /* Line */ - [SOUND_MIXER_LINE1] = 5, /* AUX */ - [SOUND_MIXER_MIC] = 6, /* Mic */ - [SOUND_MIXER_LINE2] = 7, /* Mono in */ - [SOUND_MIXER_SPEAKER] = 8, /* Speaker */ - [SOUND_MIXER_RECLEV] = 9, /* Recording level */ - [SOUND_MIXER_VOLUME] = 10 /* Master Volume */ - }; - static const unsigned char mixreg[] = { - 0x7c, /* voice */ - 0x36, /* FM */ - 0x38, /* CD */ - 0x3e, /* Line */ - 0x3a, /* AUX */ - 0x1a, /* Mic */ - 0x6d /* Mono in */ - }; - unsigned char l, r, rl, rr, vidx; - int i, val; - int __user *p = (int __user *)arg; - - VALIDATE_STATE(s); - - if (cmd == SOUND_MIXER_PRIVATE1) { - /* enable/disable/query mixer preamp */ - if (get_user(val, p)) - return -EFAULT; - if (val != -1) { - val = val ? 0xff : 0xf7; - write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val); - } - val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0; - return put_user(val, p); - } - if (cmd == SOUND_MIXER_PRIVATE2) { - /* enable/disable/query spatializer */ - if (get_user(val, p)) - return -EFAULT; - if (val != -1) { - val &= 0x3f; - write_mixer(s, 0x52, val); - write_mixer(s, 0x50, val ? 0x08 : 0); - } - return put_user(read_mixer(s, 0x52), p); - } - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - strncpy(info.id, "Solo1", sizeof(info.id)); - strncpy(info.name, "ESS Solo1", sizeof(info.name)); - info.modify_counter = s->mix.modcnt; - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - strncpy(info.id, "Solo1", sizeof(info.id)); - strncpy(info.name, "ESS Solo1", sizeof(info.name)); - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, p); - if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - if (_SIOC_DIR(cmd) == _SIOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - return put_user(mixer_src[read_mixer(s, 0x1c) & 7], p); - - case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ - return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD | - SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC | - SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV | - SOUND_MASK_SPEAKER, p); - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME, p); - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD | - SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC | - SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV, p); - - case SOUND_MIXER_CAPS: - return put_user(SOUND_CAP_EXCL_INPUT, p); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) - return -EINVAL; - return put_user(s->mix.vol[vidx-1], p); - } - } - if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) - return -EINVAL; - s->mix.modcnt++; - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ -#if 0 - { - static const unsigned char regs[] = { - 0x1c, 0x1a, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x60, 0x62, 0x6d, 0x7c - }; - int i; - - for (i = 0; i < sizeof(regs); i++) - printk(KERN_DEBUG "solo1: mixer reg 0x%02x: 0x%02x\n", - regs[i], read_mixer(s, regs[i])); - printk(KERN_DEBUG "solo1: ctrl reg 0x%02x: 0x%02x\n", - 0xb4, read_ctrl(s, 0xb4)); - } -#endif - if (get_user(val, p)) - return -EFAULT; - i = hweight32(val); - if (i == 0) - return 0; - else if (i > 1) - val &= ~mixer_src[read_mixer(s, 0x1c) & 7]; - for (i = 0; i < 8; i++) { - if (mixer_src[i] & val) - break; - } - if (i > 7) - return 0; - write_mixer(s, 0x1c, i); - return 0; - - case SOUND_MIXER_VOLUME: - if (get_user(val, p)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - if (l < 6) { - rl = 0x40; - l = 0; - } else { - rl = (l * 2 - 11) / 3; - l = (rl * 3 + 11) / 2; - } - if (r < 6) { - rr = 0x40; - r = 0; - } else { - rr = (r * 2 - 11) / 3; - r = (rr * 3 + 11) / 2; - } - write_mixer(s, 0x60, rl); - write_mixer(s, 0x62, rr); -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[9] = ((unsigned int)r << 8) | l; -#else - s->mix.vol[9] = val; -#endif - return put_user(s->mix.vol[9], p); - - case SOUND_MIXER_SPEAKER: - if (get_user(val, p)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - else if (l < 2) - l = 2; - rl = (l - 2) / 14; - l = rl * 14 + 2; - write_mixer(s, 0x3c, rl); -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[7] = l * 0x101; -#else - s->mix.vol[7] = val; -#endif - return put_user(s->mix.vol[7], p); - - case SOUND_MIXER_RECLEV: - if (get_user(val, p)) - return -EFAULT; - l = (val << 1) & 0x1fe; - if (l > 200) - l = 200; - else if (l < 5) - l = 5; - r = (val >> 7) & 0x1fe; - if (r > 200) - r = 200; - else if (r < 5) - r = 5; - rl = (l - 5) / 13; - rr = (r - 5) / 13; - r = (rl * 13 + 5) / 2; - l = (rr * 13 + 5) / 2; - write_ctrl(s, 0xb4, (rl << 4) | rr); -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[8] = ((unsigned int)r << 8) | l; -#else - s->mix.vol[8] = val; -#endif - return put_user(s->mix.vol[8], p); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - l = (val << 1) & 0x1fe; - if (l > 200) - l = 200; - else if (l < 5) - l = 5; - r = (val >> 7) & 0x1fe; - if (r > 200) - r = 200; - else if (r < 5) - r = 5; - rl = (l - 5) / 13; - rr = (r - 5) / 13; - r = (rl * 13 + 5) / 2; - l = (rr * 13 + 5) / 2; - write_mixer(s, mixreg[vidx-1], (rl << 4) | rr); -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l; -#else - s->mix.vol[vidx-1] = val; -#endif - return put_user(s->mix.vol[vidx-1], p); - } -} - -/* --------------------------------------------------------------------- */ - -static int solo1_open_mixdev(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct solo1_state *s = NULL; - struct pci_dev *pci_dev = NULL; - - while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { - struct pci_driver *drvr; - drvr = pci_dev_driver (pci_dev); - if (drvr != &solo1_driver) - continue; - s = (struct solo1_state*)pci_get_drvdata(pci_dev); - if (!s) - continue; - if (s->dev_mixer == minor) - break; - } - if (!s) - return -ENODEV; - VALIDATE_STATE(s); - file->private_data = s; - return nonseekable_open(inode, file); -} - -static int solo1_release_mixdev(struct inode *inode, struct file *file) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - - VALIDATE_STATE(s); - return 0; -} - -static int solo1_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - return mixer_ioctl((struct solo1_state *)file->private_data, cmd, arg); -} - -static /*const*/ struct file_operations solo1_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = solo1_ioctl_mixdev, - .open = solo1_open_mixdev, - .release = solo1_release_mixdev, -}; - -/* --------------------------------------------------------------------- */ - -static int drain_dac(struct solo1_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count; - unsigned tmo; - - if (s->dma_dac.mapped) - return 0; - add_wait_queue(&s->dma_dac.wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate; - if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE)) - tmo >>= 1; - if (s->channels > 1) - tmo >>= 1; - if (!schedule_timeout(tmo + 1)) - printk(KERN_DEBUG "solo1: dma timed out??\n"); - } - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static ssize_t solo1_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - add_wait_queue(&s->dma_adc.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - swptr = s->dma_adc.swptr; - cnt = s->dma_adc.dmasize-swptr; - if (s->dma_adc.count < cnt) - cnt = s->dma_adc.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; -#ifdef DEBUGREC - printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x cnt: %u\n", - read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt); -#endif - if (cnt <= 0) { - if (s->dma_adc.enabled) - start_adc(s); -#ifdef DEBUGREC - printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n" - KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n" - KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n" - KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n", - read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), - read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), - inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt); -#endif - if (inb(s->ddmabase+15) & 1) - printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n"); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); -#ifdef DEBUGREC - printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n" - KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n" - KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n" - KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n", - read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), - read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), - inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt); -#endif - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - swptr = (swptr + cnt) % s->dma_adc.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_adc.swptr = swptr; - s->dma_adc.count -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_adc.enabled) - start_adc(s); -#ifdef DEBUGREC - printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n", - read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc)); -#endif - } - remove_wait_queue(&s->dma_adc.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -static ssize_t solo1_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac.mapped) - return -ENXIO; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; -#if 0 - printk(KERN_DEBUG "solo1_write: reg 70: 0x%02x 71: 0x%02x 72: 0x%02x 74: 0x%02x 76: 0x%02x 78: 0x%02x 7A: 0x%02x\n" - KERN_DEBUG "solo1_write: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x SBstat: 0x%02x\n", - read_mixer(s, 0x70), read_mixer(s, 0x71), read_mixer(s, 0x72), read_mixer(s, 0x74), read_mixer(s, 0x76), - read_mixer(s, 0x78), read_mixer(s, 0x7a), inl(s->iobase), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc)); - printk(KERN_DEBUG "solo1_write: reg 78: 0x%02x reg 7A: 0x%02x DMAcnt: 0x%04x DMAstat: 0x%02x SBstat: 0x%02x\n", - read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc)); -#endif - ret = 0; - add_wait_queue(&s->dma_dac.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - if (s->dma_dac.count < 0) { - s->dma_dac.count = 0; - s->dma_dac.swptr = s->dma_dac.hwptr; - } - swptr = s->dma_dac.swptr; - cnt = s->dma_dac.dmasize-swptr; - if (s->dma_dac.count + cnt > s->dma_dac.dmasize) - cnt = s->dma_dac.dmasize - s->dma_dac.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_dac.enabled) - start_dac(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - swptr = (swptr + cnt) % s->dma_dac.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_dac.swptr = swptr; - s->dma_dac.count += cnt; - s->dma_dac.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_dac.enabled) - start_dac(s); - } - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac.ready && prog_dmabuf_dac(s)) - return 0; - poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready && prog_dmabuf_adc(s)) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - spin_lock_irqsave(&s->lock, flags); - solo1_update_ptr(s); - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.mapped) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } else { - if (s->dma_adc.count > 0) - mask |= POLLIN | POLLRDNORM; - } - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac.dmasize > s->dma_dac.count) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - - -static int solo1_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - struct dmabuf *db; - int ret = -EINVAL; - unsigned long size; - - VALIDATE_STATE(s); - lock_kernel(); - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf_dac(s)) != 0) - goto out; - db = &s->dma_dac; - } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf_adc(s)) != 0) - goto out; - db = &s->dma_adc; - } else - goto out; - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) - goto out; - ret = -EAGAIN; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - db->mapped = 1; - ret = 0; -out: - unlock_kernel(); - return ret; -} - -static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int val, mapped, ret, count; - int div1, div2; - unsigned rate1, rate2; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(s->irq); - s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->irq); - s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; - } - prog_codec(s); - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - stop_adc(s); - stop_dac(s); - s->dma_adc.ready = s->dma_dac.ready = 0; - /* program sampling rates */ - if (val > 48000) - val = 48000; - if (val < 6300) - val = 6300; - div1 = (768000 + val / 2) / val; - rate1 = (768000 + div1 / 2) / div1; - div1 = -div1; - div2 = (793800 + val / 2) / val; - rate2 = (793800 + div2 / 2) / div2; - div2 = (-div2) & 0x7f; - if (abs(val - rate2) < abs(val - rate1)) { - rate1 = rate2; - div1 = div2; - } - s->rate = rate1; - s->clkdiv = div1; - prog_codec(s); - } - return put_user(s->rate, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - stop_adc(s); - stop_dac(s); - s->dma_adc.ready = s->dma_dac.ready = 0; - /* program channels */ - s->channels = val ? 2 : 1; - prog_codec(s); - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - stop_adc(s); - stop_dac(s); - s->dma_adc.ready = s->dma_dac.ready = 0; - /* program channels */ - s->channels = (val >= 2) ? 2 : 1; - prog_codec(s); - } - return put_user(s->channels, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - stop_adc(s); - stop_dac(s); - s->dma_adc.ready = s->dma_dac.ready = 0; - /* program format */ - if (val != AFMT_S16_LE && val != AFMT_U16_LE && - val != AFMT_S8 && val != AFMT_U8) - val = AFMT_U8; - s->fmt = val; - prog_codec(s); - } - return put_user(s->fmt, p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if (file->f_mode & s->ena & FMODE_READ) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & s->ena & FMODE_WRITE) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; - s->dma_dac.enabled = 1; - start_adc(s); - if (inb(s->ddmabase+15) & 1) - printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n"); - } else { - s->dma_dac.enabled = 0; - stop_adc(s); - } - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; - s->dma_dac.enabled = 1; - start_dac(s); - } else { - s->dma_dac.enabled = 0; - stop_dac(s); - } - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - solo1_update_ptr(s); - abinfo.fragsize = s->dma_dac.fragsize; - count = s->dma_dac.count; - if (count < 0) - count = 0; - abinfo.bytes = s->dma_dac.dmasize - count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - solo1_update_ptr(s); - abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - solo1_update_ptr(s); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - return put_user(count, p); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - solo1_update_ptr(s); - cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - solo1_update_ptr(s); - cinfo.bytes = s->dma_dac.total_bytes; - count = s->dma_dac.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac.fragshift; - cinfo.ptr = s->dma_dac.hwptr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); -#if 0 - printk(KERN_DEBUG "esssolo1: GETOPTR: bytes %u blocks %u ptr %u, buforder %u numfrag %u fragshift %u\n" - KERN_DEBUG "esssolo1: swptr %u count %u fragsize %u dmasize %u fragsamples %u\n", - cinfo.bytes, cinfo.blocks, cinfo.ptr, s->dma_dac.buforder, s->dma_dac.numfrag, s->dma_dac.fragshift, - s->dma_dac.swptr, s->dma_dac.count, s->dma_dac.fragsize, s->dma_dac.dmasize, s->dma_dac.fragsamples); -#endif - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf_dac(s))) - return val; - return put_user(s->dma_dac.fragsize, p); - } - if ((val = prog_dmabuf_adc(s))) - return val; - return put_user(s->dma_adc.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - s->dma_dac.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user(s->rate, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user(s->channels, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return mixer_ioctl(s, cmd, arg); -} - -static int solo1_release(struct inode *inode, struct file *file) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - if (file->f_mode & FMODE_WRITE) - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - outb(0, s->iobase+6); /* disable DMA */ - dealloc_dmabuf(s, &s->dma_dac); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - outb(1, s->ddmabase+0xf); /* mask DMA channel */ - outb(0, s->ddmabase+0xd); /* DMA master clear */ - dealloc_dmabuf(s, &s->dma_adc); - } - s->open_mode &= ~(FMODE_READ | FMODE_WRITE); - wake_up(&s->open_wait); - mutex_unlock(&s->open_mutex); - unlock_kernel(); - return 0; -} - -static int solo1_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - struct solo1_state *s = NULL; - struct pci_dev *pci_dev = NULL; - - while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { - struct pci_driver *drvr; - - drvr = pci_dev_driver(pci_dev); - if (drvr != &solo1_driver) - continue; - s = (struct solo1_state*)pci_get_drvdata(pci_dev); - if (!s) - continue; - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - if (!s) - return -ENODEV; - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & (FMODE_READ | FMODE_WRITE)) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - s->fmt = AFMT_U8; - s->channels = 1; - s->rate = 8000; - s->clkdiv = 96 | 0x80; - s->ena = 0; - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; - s->dma_adc.enabled = 1; - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; - s->dma_dac.enabled = 1; - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - mutex_unlock(&s->open_mutex); - prog_codec(s); - return nonseekable_open(inode, file); -} - -static /*const*/ struct file_operations solo1_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = solo1_read, - .write = solo1_write, - .poll = solo1_poll, - .ioctl = solo1_ioctl, - .mmap = solo1_mmap, - .open = solo1_open, - .release = solo1_release, -}; - -/* --------------------------------------------------------------------- */ - -/* hold spinlock for the following! */ -static void solo1_handle_midi(struct solo1_state *s) -{ - unsigned char ch; - int wake; - - if (!(s->mpubase)) - return; - wake = 0; - while (!(inb(s->mpubase+1) & 0x80)) { - ch = inb(s->mpubase); - if (s->midi.icnt < MIDIINBUF) { - s->midi.ibuf[s->midi.iwr] = ch; - s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF; - s->midi.icnt++; - } - wake = 1; - } - if (wake) - wake_up(&s->midi.iwait); - wake = 0; - while (!(inb(s->mpubase+1) & 0x40) && s->midi.ocnt > 0) { - outb(s->midi.obuf[s->midi.ord], s->mpubase); - s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF; - s->midi.ocnt--; - if (s->midi.ocnt < MIDIOUTBUF-16) - wake = 1; - } - if (wake) - wake_up(&s->midi.owait); -} - -static irqreturn_t solo1_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct solo1_state *s = (struct solo1_state *)dev_id; - unsigned int intsrc; - - /* fastpath out, to ease interrupt sharing */ - intsrc = inb(s->iobase+7); /* get interrupt source(s) */ - if (!intsrc) - return IRQ_NONE; - (void)inb(s->sbbase+0xe); /* clear interrupt */ - spin_lock(&s->lock); - /* clear audio interrupts first */ - if (intsrc & 0x20) - write_mixer(s, 0x7a, read_mixer(s, 0x7a) & 0x7f); - solo1_update_ptr(s); - solo1_handle_midi(s); - spin_unlock(&s->lock); - return IRQ_HANDLED; -} - -static void solo1_midi_timer(unsigned long data) -{ - struct solo1_state *s = (struct solo1_state *)data; - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - solo1_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - s->midi.timer.expires = jiffies+1; - add_timer(&s->midi.timer); -} - -/* --------------------------------------------------------------------- */ - -static ssize_t solo1_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - if (count == 0) - return 0; - ret = 0; - add_wait_queue(&s->midi.iwait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.ird; - cnt = MIDIINBUF - ptr; - if (s->midi.icnt < cnt) - cnt = s->midi.icnt; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - ptr = (ptr + cnt) % MIDIINBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.ird = ptr; - s->midi.icnt -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - break; - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&s->midi.iwait, &wait); - return ret; -} - -static ssize_t solo1_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - if (count == 0) - return 0; - ret = 0; - add_wait_queue(&s->midi.owait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.owr; - cnt = MIDIOUTBUF - ptr; - if (s->midi.ocnt + cnt > MIDIOUTBUF) - cnt = MIDIOUTBUF - s->midi.ocnt; - if (cnt <= 0) { - __set_current_state(TASK_INTERRUPTIBLE); - solo1_handle_midi(s); - } - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - ptr = (ptr + cnt) % MIDIOUTBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.owr = ptr; - s->midi.ocnt += cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - spin_lock_irqsave(&s->lock, flags); - solo1_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&s->midi.owait, &wait); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int solo1_midi_poll(struct file *file, struct poll_table_struct *wait) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_flags & FMODE_WRITE) - poll_wait(file, &s->midi.owait, wait); - if (file->f_flags & FMODE_READ) - poll_wait(file, &s->midi.iwait, wait); - spin_lock_irqsave(&s->lock, flags); - if (file->f_flags & FMODE_READ) { - if (s->midi.icnt > 0) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_flags & FMODE_WRITE) { - if (s->midi.ocnt < MIDIOUTBUF) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int solo1_midi_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct solo1_state *s = NULL; - struct pci_dev *pci_dev = NULL; - - while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { - struct pci_driver *drvr; - - drvr = pci_dev_driver(pci_dev); - if (drvr != &solo1_driver) - continue; - s = (struct solo1_state*)pci_get_drvdata(pci_dev); - if (!s) - continue; - if (s->dev_midi == minor) - break; - } - if (!s) - return -ENODEV; - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - outb(0xff, s->mpubase+1); /* reset command */ - outb(0x3f, s->mpubase+1); /* uart command */ - if (!(inb(s->mpubase+1) & 0x80)) - inb(s->mpubase); - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - outb(0xb0, s->iobase + 7); /* enable A1, A2, MPU irq's */ - init_timer(&s->midi.timer); - s->midi.timer.expires = jiffies+1; - s->midi.timer.data = (unsigned long)s; - s->midi.timer.function = solo1_midi_timer; - add_timer(&s->midi.timer); - } - if (file->f_mode & FMODE_READ) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - } - if (file->f_mode & FMODE_WRITE) { - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - } - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int solo1_midi_release(struct inode *inode, struct file *file) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - unsigned count, tmo; - - VALIDATE_STATE(s); - - lock_kernel(); - if (file->f_mode & FMODE_WRITE) { - add_wait_queue(&s->midi.owait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->midi.ocnt; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (file->f_flags & O_NONBLOCK) - break; - tmo = (count * HZ) / 3100; - if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "solo1: midi timed out??\n"); - } - remove_wait_queue(&s->midi.owait, &wait); - set_current_state(TASK_RUNNING); - } - mutex_lock(&s->open_mutex); - s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE)); - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - outb(0x30, s->iobase + 7); /* enable A1, A2 irq's */ - del_timer(&s->midi.timer); - } - spin_unlock_irqrestore(&s->lock, flags); - wake_up(&s->open_wait); - mutex_unlock(&s->open_mutex); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations solo1_midi_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = solo1_midi_read, - .write = solo1_midi_write, - .poll = solo1_midi_poll, - .open = solo1_midi_open, - .release = solo1_midi_release, -}; - -/* --------------------------------------------------------------------- */ - -static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - static const unsigned char op_offset[18] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 - }; - struct solo1_state *s = (struct solo1_state *)file->private_data; - struct dm_fm_voice v; - struct dm_fm_note n; - struct dm_fm_params p; - unsigned int io; - unsigned int regb; - - switch (cmd) { - case FM_IOCTL_RESET: - for (regb = 0xb0; regb < 0xb9; regb++) { - outb(regb, s->sbbase); - outb(0, s->sbbase+1); - outb(regb, s->sbbase+2); - outb(0, s->sbbase+3); - } - return 0; - - case FM_IOCTL_PLAY_NOTE: - if (copy_from_user(&n, (void __user *)arg, sizeof(n))) - return -EFAULT; - if (n.voice >= 18) - return -EINVAL; - if (n.voice >= 9) { - regb = n.voice - 9; - io = s->sbbase+2; - } else { - regb = n.voice; - io = s->sbbase; - } - outb(0xa0 + regb, io); - outb(n.fnum & 0xff, io+1); - outb(0xb0 + regb, io); - outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1); - return 0; - - case FM_IOCTL_SET_VOICE: - if (copy_from_user(&v, (void __user *)arg, sizeof(v))) - return -EFAULT; - if (v.voice >= 18) - return -EINVAL; - regb = op_offset[v.voice]; - io = s->sbbase + ((v.op & 1) << 1); - outb(0x20 + regb, io); - outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) | - ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1); - outb(0x40 + regb, io); - outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1); - outb(0x60 + regb, io); - outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1); - outb(0x80 + regb, io); - outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1); - outb(0xe0 + regb, io); - outb(v.waveform & 0x7, io+1); - if (n.voice >= 9) { - regb = n.voice - 9; - io = s->sbbase+2; - } else { - regb = n.voice; - io = s->sbbase; - } - outb(0xc0 + regb, io); - outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) | - (v.connection & 1), io+1); - return 0; - - case FM_IOCTL_SET_PARAMS: - if (copy_from_user(&p, (void __user *)arg, sizeof(p))) - return -EFAULT; - outb(0x08, s->sbbase); - outb((p.kbd_split & 1) << 6, s->sbbase+1); - outb(0xbd, s->sbbase); - outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) | - ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->sbbase+1); - return 0; - - case FM_IOCTL_SET_OPL: - outb(4, s->sbbase+2); - outb(arg, s->sbbase+3); - return 0; - - case FM_IOCTL_SET_MODE: - outb(5, s->sbbase+2); - outb(arg & 1, s->sbbase+3); - return 0; - - default: - return -EINVAL; - } -} - -static int solo1_dmfm_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - struct solo1_state *s = NULL; - struct pci_dev *pci_dev = NULL; - - while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { - struct pci_driver *drvr; - - drvr = pci_dev_driver(pci_dev); - if (drvr != &solo1_driver) - continue; - s = (struct solo1_state*)pci_get_drvdata(pci_dev); - if (!s) - continue; - if (s->dev_dmfm == minor) - break; - } - if (!s) - return -ENODEV; - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & FMODE_DMFM) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - if (!request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1")) { - mutex_unlock(&s->open_mutex); - printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n"); - return -EBUSY; - } - /* init the stuff */ - outb(1, s->sbbase); - outb(0x20, s->sbbase+1); /* enable waveforms */ - outb(4, s->sbbase+2); - outb(0, s->sbbase+3); /* no 4op enabled */ - outb(5, s->sbbase+2); - outb(1, s->sbbase+3); /* enable OPL3 */ - s->open_mode |= FMODE_DMFM; - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int solo1_dmfm_release(struct inode *inode, struct file *file) -{ - struct solo1_state *s = (struct solo1_state *)file->private_data; - unsigned int regb; - - VALIDATE_STATE(s); - lock_kernel(); - mutex_lock(&s->open_mutex); - s->open_mode &= ~FMODE_DMFM; - for (regb = 0xb0; regb < 0xb9; regb++) { - outb(regb, s->sbbase); - outb(0, s->sbbase+1); - outb(regb, s->sbbase+2); - outb(0, s->sbbase+3); - } - release_region(s->sbbase, FMSYNTH_EXTENT); - wake_up(&s->open_wait); - mutex_unlock(&s->open_mutex); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations solo1_dmfm_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = solo1_dmfm_ioctl, - .open = solo1_dmfm_open, - .release = solo1_dmfm_release, -}; - -/* --------------------------------------------------------------------- */ - -static struct initvol { - int mixch; - int vol; -} initvol[] __devinitdata = { - { SOUND_MIXER_WRITE_VOLUME, 0x4040 }, - { SOUND_MIXER_WRITE_PCM, 0x4040 }, - { SOUND_MIXER_WRITE_SYNTH, 0x4040 }, - { SOUND_MIXER_WRITE_CD, 0x4040 }, - { SOUND_MIXER_WRITE_LINE, 0x4040 }, - { SOUND_MIXER_WRITE_LINE1, 0x4040 }, - { SOUND_MIXER_WRITE_LINE2, 0x4040 }, - { SOUND_MIXER_WRITE_RECLEV, 0x4040 }, - { SOUND_MIXER_WRITE_SPEAKER, 0x4040 }, - { SOUND_MIXER_WRITE_MIC, 0x4040 } -}; - -static int setup_solo1(struct solo1_state *s) -{ - struct pci_dev *pcidev = s->dev; - mm_segment_t fs; - int i, val; - - /* initialize DDMA base address */ - printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase); - pci_write_config_word(pcidev, 0x60, (s->ddmabase & (~0xf)) | 1); - /* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */ - pci_write_config_dword(pcidev, 0x50, 0); - /* disable legacy audio address decode */ - pci_write_config_word(pcidev, 0x40, 0x907f); - - /* initialize the chips */ - if (!reset_ctrl(s)) { - printk(KERN_ERR "esssolo1: cannot reset controller\n"); - return -1; - } - outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */ - - /* initialize mixer regs */ - write_mixer(s, 0x7f, 0); /* disable music digital recording */ - write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */ - write_mixer(s, 0x64, 0x45); /* volume control */ - write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */ - write_mixer(s, 0x50, 0); /* disable spatializer */ - write_mixer(s, 0x52, 0); - write_mixer(s, 0x14, 0); /* DAC1 minimum volume */ - write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */ - outb(0, s->ddmabase+0xd); /* DMA master clear */ - outb(1, s->ddmabase+0xf); /* mask channel */ - /*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */ - - pci_set_master(pcidev); /* enable bus mastering */ - - fs = get_fs(); - set_fs(KERNEL_DS); - val = SOUND_MASK_LINE; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); - } - val = 1; /* enable mic preamp */ - mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val); - set_fs(fs); - return 0; -} - -static int -solo1_suspend(struct pci_dev *pci_dev, pm_message_t state) { - struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev); - if (!s) - return 1; - outb(0, s->iobase+6); - /* DMA master clear */ - outb(0, s->ddmabase+0xd); - /* reset sequencer and FIFO */ - outb(3, s->sbbase+6); - /* turn off DDMA controller address space */ - pci_write_config_word(s->dev, 0x60, 0); - return 0; -} - -static int -solo1_resume(struct pci_dev *pci_dev) { - struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev); - if (!s) - return 1; - setup_solo1(s); - return 0; -} - -#ifdef SUPPORT_JOYSTICK -static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port) -{ - struct gameport *gp; - - if (!request_region(io_port, GAMEPORT_EXTENT, "ESS Solo1")) { - printk(KERN_ERR "solo1: gameport io ports are in use\n"); - return -EBUSY; - } - - s->gameport = gp = gameport_allocate_port(); - if (!gp) { - printk(KERN_ERR "solo1: can not allocate memory for gameport\n"); - release_region(io_port, GAMEPORT_EXTENT); - return -ENOMEM; - } - - gameport_set_name(gp, "ESS Solo1 Gameport"); - gameport_set_phys(gp, "isa%04x/gameport0", io_port); - gp->dev.parent = &s->dev->dev; - gp->io = io_port; - - gameport_register_port(gp); - - return 0; -} - -static inline void solo1_unregister_gameport(struct solo1_state *s) -{ - if (s->gameport) { - int gpio = s->gameport->io; - gameport_unregister_port(s->gameport); - release_region(gpio, GAMEPORT_EXTENT); - } -} -#else -static inline int solo1_register_gameport(struct solo1_state *s, int io_port) { return -ENOSYS; } -static inline void solo1_unregister_gameport(struct solo1_state *s) { } -#endif /* SUPPORT_JOYSTICK */ - -static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) -{ - struct solo1_state *s; - int gpio; - int ret; - - if ((ret=pci_enable_device(pcidev))) - return ret; - if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) || - !(pci_resource_flags(pcidev, 1) & IORESOURCE_IO) || - !(pci_resource_flags(pcidev, 2) & IORESOURCE_IO) || - !(pci_resource_flags(pcidev, 3) & IORESOURCE_IO)) - return -ENODEV; - if (pcidev->irq == 0) - return -ENODEV; - - /* Recording requires 24-bit DMA, so attempt to set dma mask - * to 24 bits first, then 32 bits (playback only) if that fails. - */ - if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK) && - pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) { - printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n"); - return -ENODEV; - } - - if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) { - printk(KERN_WARNING "solo1: out of memory\n"); - return -ENOMEM; - } - memset(s, 0, sizeof(struct solo1_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->midi.iwait); - init_waitqueue_head(&s->midi.owait); - mutex_init(&s->open_mutex); - spin_lock_init(&s->lock); - s->magic = SOLO1_MAGIC; - s->dev = pcidev; - s->iobase = pci_resource_start(pcidev, 0); - s->sbbase = pci_resource_start(pcidev, 1); - s->vcbase = pci_resource_start(pcidev, 2); - s->ddmabase = s->vcbase + DDMABASE_OFFSET; - s->mpubase = pci_resource_start(pcidev, 3); - gpio = pci_resource_start(pcidev, 4); - s->irq = pcidev->irq; - ret = -EBUSY; - if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) { - printk(KERN_ERR "solo1: io ports in use\n"); - goto err_region1; - } - if (!request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1")) { - printk(KERN_ERR "solo1: io ports in use\n"); - goto err_region2; - } - if (!request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1")) { - printk(KERN_ERR "solo1: io ports in use\n"); - goto err_region3; - } - if (!request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1")) { - printk(KERN_ERR "solo1: io ports in use\n"); - goto err_region4; - } - if ((ret=request_irq(s->irq,solo1_interrupt,IRQF_SHARED,"ESS Solo1",s))) { - printk(KERN_ERR "solo1: irq %u in use\n", s->irq); - goto err_irq; - } - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) { - ret = s->dev_audio; - goto err_dev1; - } - if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0) { - ret = s->dev_mixer; - goto err_dev2; - } - if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0) { - ret = s->dev_midi; - goto err_dev3; - } - if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0) { - ret = s->dev_dmfm; - goto err_dev4; - } - if (setup_solo1(s)) { - ret = -EIO; - goto err; - } - /* register gameport */ - solo1_register_gameport(s, gpio); - /* store it in the driver field */ - pci_set_drvdata(pcidev, s); - return 0; - - err: - unregister_sound_special(s->dev_dmfm); - err_dev4: - unregister_sound_midi(s->dev_midi); - err_dev3: - unregister_sound_mixer(s->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - printk(KERN_ERR "solo1: initialisation error\n"); - free_irq(s->irq, s); - err_irq: - release_region(s->mpubase, MPUBASE_EXTENT); - err_region4: - release_region(s->ddmabase, DDMABASE_EXTENT); - err_region3: - release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); - err_region2: - release_region(s->iobase, IOBASE_EXTENT); - err_region1: - kfree(s); - return ret; -} - -static void __devexit solo1_remove(struct pci_dev *dev) -{ - struct solo1_state *s = pci_get_drvdata(dev); - - if (!s) - return; - /* stop DMA controller */ - outb(0, s->iobase+6); - outb(0, s->ddmabase+0xd); /* DMA master clear */ - outb(3, s->sbbase+6); /* reset sequencer and FIFO */ - synchronize_irq(s->irq); - pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */ - free_irq(s->irq, s); - solo1_unregister_gameport(s); - release_region(s->iobase, IOBASE_EXTENT); - release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); - release_region(s->ddmabase, DDMABASE_EXTENT); - release_region(s->mpubase, MPUBASE_EXTENT); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_midi(s->dev_midi); - unregister_sound_special(s->dev_dmfm); - kfree(s); - pci_set_drvdata(dev, NULL); -} - -static struct pci_device_id id_table[] = { - { PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, id_table); - -static struct pci_driver solo1_driver = { - .name = "ESS Solo1", - .id_table = id_table, - .probe = solo1_probe, - .remove = __devexit_p(solo1_remove), - .suspend = solo1_suspend, - .resume = solo1_resume, -}; - - -static int __init init_solo1(void) -{ - printk(KERN_INFO "solo1: version v0.20 time " __TIME__ " " __DATE__ "\n"); - return pci_register_driver(&solo1_driver); -} - -/* --------------------------------------------------------------------- */ - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("ESS Solo1 Driver"); -MODULE_LICENSE("GPL"); - - -static void __exit cleanup_solo1(void) -{ - printk(KERN_INFO "solo1: unloading\n"); - pci_unregister_driver(&solo1_driver); -} - -/* --------------------------------------------------------------------- */ - -module_init(init_solo1); -module_exit(cleanup_solo1); - diff --git a/sound/oss/forte.c b/sound/oss/forte.c deleted file mode 100644 index ea1c0207aef2..000000000000 --- a/sound/oss/forte.c +++ /dev/null @@ -1,2139 +0,0 @@ -/* - * forte.c - ForteMedia FM801 OSS Driver - * - * Written by Martin K. Petersen - * Copyright (C) 2002 Hewlett-Packard Company - * Portions Copyright (C) 2003 Martin K. Petersen - * - * Latest version: http://mkp.net/forte/ - * - * Based upon the ALSA FM801 driver by Jaroslav Kysela and OSS drivers - * by Thomas Sailer, Alan Cox, Zach Brown, and Jeff Garzik. Thanks - * guys! - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include - -#define DRIVER_NAME "forte" -#define DRIVER_VERSION "$Id: forte.c,v 1.63 2003/03/01 05:32:42 mkp Exp $" -#define PFX DRIVER_NAME ": " - -#undef M_DEBUG - -#ifdef M_DEBUG -#define DPRINTK(args...) printk(KERN_WARNING args) -#else -#define DPRINTK(args...) -#endif - -/* Card capabilities */ -#define FORTE_CAPS (DSP_CAP_MMAP | DSP_CAP_TRIGGER) - -/* Supported audio formats */ -#define FORTE_FMTS (AFMT_U8 | AFMT_S16_LE) - -/* Buffers */ -#define FORTE_MIN_FRAG_SIZE 256 -#define FORTE_MAX_FRAG_SIZE PAGE_SIZE -#define FORTE_DEF_FRAG_SIZE 256 -#define FORTE_MIN_FRAGMENTS 2 -#define FORTE_MAX_FRAGMENTS 256 -#define FORTE_DEF_FRAGMENTS 2 -#define FORTE_MIN_BUF_MSECS 500 -#define FORTE_MAX_BUF_MSECS 1000 - -/* PCI BARs */ -#define FORTE_PCM_VOL 0x00 /* PCM Output Volume */ -#define FORTE_FM_VOL 0x02 /* FM Output Volume */ -#define FORTE_I2S_VOL 0x04 /* I2S Volume */ -#define FORTE_REC_SRC 0x06 /* Record Source */ -#define FORTE_PLY_CTRL 0x08 /* Playback Control */ -#define FORTE_PLY_COUNT 0x0a /* Playback Count */ -#define FORTE_PLY_BUF1 0x0c /* Playback Buffer I */ -#define FORTE_PLY_BUF2 0x10 /* Playback Buffer II */ -#define FORTE_CAP_CTRL 0x14 /* Capture Control */ -#define FORTE_CAP_COUNT 0x16 /* Capture Count */ -#define FORTE_CAP_BUF1 0x18 /* Capture Buffer I */ -#define FORTE_CAP_BUF2 0x1c /* Capture Buffer II */ -#define FORTE_CODEC_CTRL 0x22 /* Codec Control */ -#define FORTE_I2S_MODE 0x24 /* I2S Mode Control */ -#define FORTE_VOLUME 0x26 /* Volume Up/Down/Mute Status */ -#define FORTE_I2C_CTRL 0x29 /* I2C Control */ -#define FORTE_AC97_CMD 0x2a /* AC'97 Command */ -#define FORTE_AC97_DATA 0x2c /* AC'97 Data */ -#define FORTE_MPU401_DATA 0x30 /* MPU401 Data */ -#define FORTE_MPU401_CMD 0x31 /* MPU401 Command */ -#define FORTE_GPIO_CTRL 0x52 /* General Purpose I/O Control */ -#define FORTE_GEN_CTRL 0x54 /* General Control */ -#define FORTE_IRQ_MASK 0x56 /* Interrupt Mask */ -#define FORTE_IRQ_STATUS 0x5a /* Interrupt Status */ -#define FORTE_OPL3_BANK0 0x68 /* OPL3 Status Read / Bank 0 Write */ -#define FORTE_OPL3_DATA0 0x69 /* OPL3 Data 0 Write */ -#define FORTE_OPL3_BANK1 0x6a /* OPL3 Bank 1 Write */ -#define FORTE_OPL3_DATA1 0x6b /* OPL3 Bank 1 Write */ -#define FORTE_POWERDOWN 0x70 /* Blocks Power Down Control */ - -#define FORTE_CAP_OFFSET FORTE_CAP_CTRL - FORTE_PLY_CTRL - -#define FORTE_AC97_ADDR_SHIFT 10 - -/* Playback and record control register bits */ -#define FORTE_BUF1_LAST (1<<1) -#define FORTE_BUF2_LAST (1<<2) -#define FORTE_START (1<<5) -#define FORTE_PAUSE (1<<6) -#define FORTE_IMMED_STOP (1<<7) -#define FORTE_RATE_SHIFT 8 -#define FORTE_RATE_MASK (15 << FORTE_RATE_SHIFT) -#define FORTE_CHANNELS_4 (1<<12) /* Playback only */ -#define FORTE_CHANNELS_6 (2<<12) /* Playback only */ -#define FORTE_CHANNELS_6MS (3<<12) /* Playback only */ -#define FORTE_CHANNELS_MASK (3<<12) -#define FORTE_16BIT (1<<14) -#define FORTE_STEREO (1<<15) - -/* IRQ status bits */ -#define FORTE_IRQ_PLAYBACK (1<<8) -#define FORTE_IRQ_CAPTURE (1<<9) -#define FORTE_IRQ_VOLUME (1<<14) -#define FORTE_IRQ_MPU (1<<15) - -/* CODEC control */ -#define FORTE_CC_CODEC_RESET (1<<5) -#define FORTE_CC_AC97_RESET (1<<6) - -/* AC97 cmd */ -#define FORTE_AC97_WRITE (0<<7) -#define FORTE_AC97_READ (1<<7) -#define FORTE_AC97_DP_INVALID (0<<8) -#define FORTE_AC97_DP_VALID (1<<8) -#define FORTE_AC97_PORT_RDY (0<<9) -#define FORTE_AC97_PORT_BSY (1<<9) - - -struct forte_channel { - const char *name; - - unsigned short ctrl; /* Ctrl BAR contents */ - unsigned long iobase; /* Ctrl BAR address */ - - wait_queue_head_t wait; - - void *buf; /* Buffer */ - dma_addr_t buf_handle; /* Buffer handle */ - - unsigned int record; - unsigned int format; - unsigned int rate; - unsigned int stereo; - - unsigned int frag_sz; /* Current fragment size */ - unsigned int frag_num; /* Current # of fragments */ - unsigned int frag_msecs; /* Milliseconds per frag */ - unsigned int buf_sz; /* Current buffer size */ - - unsigned int hwptr; /* Tail */ - unsigned int swptr; /* Head */ - unsigned int filled_frags; /* Fragments currently full */ - unsigned int next_buf; /* Index of next buffer */ - - unsigned int active; /* Channel currently in use */ - unsigned int mapped; /* mmap */ - - unsigned int buf_pages; /* Real size of buffer */ - unsigned int nr_irqs; /* Number of interrupts */ - unsigned int bytes; /* Total bytes */ - unsigned int residue; /* Partial fragment */ -}; - - -struct forte_chip { - struct pci_dev *pci_dev; - unsigned long iobase; - int irq; - - struct mutex open_mutex; /* Device access */ - spinlock_t lock; /* State */ - - spinlock_t ac97_lock; - struct ac97_codec *ac97; - - int multichannel; - int dsp; /* OSS handle */ - int trigger; /* mmap I/O trigger */ - - struct forte_channel play; - struct forte_channel rec; -}; - - -static int channels[] = { 2, 4, 6, }; -static int rates[] = { 5500, 8000, 9600, 11025, 16000, 19200, - 22050, 32000, 38400, 44100, 48000, }; - -static struct forte_chip *forte; -static int found; - - -/* AC97 Codec -------------------------------------------------------------- */ - - -/** - * forte_ac97_wait: - * @chip: fm801 instance whose AC97 codec to wait on - * - * FIXME: - * Stop busy-waiting - */ - -static inline int -forte_ac97_wait (struct forte_chip *chip) -{ - int i = 10000; - - while ( (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_PORT_BSY) - && i-- ) - cpu_relax(); - - return i == 0; -} - - -/** - * forte_ac97_read: - * @codec: AC97 codec to read from - * @reg: register to read - */ - -static u16 -forte_ac97_read (struct ac97_codec *codec, u8 reg) -{ - u16 ret = 0; - struct forte_chip *chip = codec->private_data; - - spin_lock (&chip->ac97_lock); - - /* Knock, knock */ - if (forte_ac97_wait (chip)) { - printk (KERN_ERR PFX "ac97_read: Serial bus busy\n"); - goto out; - } - - /* Send read command */ - outw (reg | (1<<7), chip->iobase + FORTE_AC97_CMD); - - if (forte_ac97_wait (chip)) { - printk (KERN_ERR PFX "ac97_read: Bus busy reading reg 0x%x\n", - reg); - goto out; - } - - /* Sanity checking */ - if (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_DP_INVALID) { - printk (KERN_ERR PFX "ac97_read: Invalid data port"); - goto out; - } - - /* Fetch result */ - ret = inw (chip->iobase + FORTE_AC97_DATA); - - out: - spin_unlock (&chip->ac97_lock); - return ret; -} - - -/** - * forte_ac97_write: - * @codec: AC97 codec to send command to - * @reg: register to write - * @val: value to write - */ - -static void -forte_ac97_write (struct ac97_codec *codec, u8 reg, u16 val) -{ - struct forte_chip *chip = codec->private_data; - - spin_lock (&chip->ac97_lock); - - /* Knock, knock */ - if (forte_ac97_wait (chip)) { - printk (KERN_ERR PFX "ac97_write: Serial bus busy\n"); - goto out; - } - - outw (val, chip->iobase + FORTE_AC97_DATA); - outb (reg | FORTE_AC97_WRITE, chip->iobase + FORTE_AC97_CMD); - - /* Wait for completion */ - if (forte_ac97_wait (chip)) { - printk (KERN_ERR PFX "ac97_write: Bus busy after write\n"); - goto out; - } - - out: - spin_unlock (&chip->ac97_lock); -} - - -/* Mixer ------------------------------------------------------------------- */ - - -/** - * forte_mixer_open: - * @inode: - * @file: - */ - -static int -forte_mixer_open (struct inode *inode, struct file *file) -{ - struct forte_chip *chip = forte; - file->private_data = chip->ac97; - return 0; -} - - -/** - * forte_mixer_release: - * @inode: - * @file: - */ - -static int -forte_mixer_release (struct inode *inode, struct file *file) -{ - /* We will welease Wodewick */ - return 0; -} - - -/** - * forte_mixer_ioctl: - * @inode: - * @file: - */ - -static int -forte_mixer_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ac97_codec *codec = (struct ac97_codec *) file->private_data; - - return codec->mixer_ioctl (codec, cmd, arg); -} - - -static struct file_operations forte_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = forte_mixer_ioctl, - .open = forte_mixer_open, - .release = forte_mixer_release, -}; - - -/* Channel ----------------------------------------------------------------- */ - -/** - * forte_channel_reset: - * @channel: Channel to reset - * - * Locking: Must be called with lock held. - */ - -static void -forte_channel_reset (struct forte_channel *channel) -{ - if (!channel || !channel->iobase) - return; - - DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name); - - channel->ctrl &= ~FORTE_START; - outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL); - - /* We always play at least two fragments, hence these defaults */ - channel->hwptr = channel->frag_sz; - channel->next_buf = 1; - channel->swptr = 0; - channel->filled_frags = 0; - channel->active = 0; - channel->bytes = 0; - channel->nr_irqs = 0; - channel->mapped = 0; - channel->residue = 0; -} - - -/** - * forte_channel_start: - * @channel: Channel to start (record/playback) - * - * Locking: Must be called with lock held. - */ - -static void inline -forte_channel_start (struct forte_channel *channel) -{ - if (!channel || !channel->iobase || channel->active) - return; - - channel->ctrl &= ~(FORTE_PAUSE | FORTE_BUF1_LAST | FORTE_BUF2_LAST - | FORTE_IMMED_STOP); - channel->ctrl |= FORTE_START; - channel->active = 1; - outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL); -} - - -/** - * forte_channel_stop: - * @channel: Channel to stop - * - * Locking: Must be called with lock held. - */ - -static void inline -forte_channel_stop (struct forte_channel *channel) -{ - if (!channel || !channel->iobase) - return; - - channel->ctrl &= ~(FORTE_START | FORTE_PAUSE); - channel->ctrl |= FORTE_IMMED_STOP; - - channel->active = 0; - outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL); -} - - -/** - * forte_channel_pause: - * @channel: Channel to pause - * - * Locking: Must be called with lock held. - */ - -static void inline -forte_channel_pause (struct forte_channel *channel) -{ - if (!channel || !channel->iobase) - return; - - channel->ctrl |= FORTE_PAUSE; - - channel->active = 0; - outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL); -} - - -/** - * forte_channel_rate: - * @channel: Channel whose rate to set. Playback and record are - * independent. - * @rate: Channel rate in Hz - * - * Locking: Must be called with lock held. - */ - -static int -forte_channel_rate (struct forte_channel *channel, unsigned int rate) -{ - int new_rate; - - if (!channel || !channel->iobase) - return -EINVAL; - - /* The FM801 only supports a handful of fixed frequencies. - * We find the value closest to what userland requested. - */ - if (rate <= 6250) { rate = 5500; new_rate = 0; } - else if (rate <= 8800) { rate = 8000; new_rate = 1; } - else if (rate <= 10312) { rate = 9600; new_rate = 2; } - else if (rate <= 13512) { rate = 11025; new_rate = 3; } - else if (rate <= 17600) { rate = 16000; new_rate = 4; } - else if (rate <= 20625) { rate = 19200; new_rate = 5; } - else if (rate <= 27025) { rate = 22050; new_rate = 6; } - else if (rate <= 35200) { rate = 32000; new_rate = 7; } - else if (rate <= 41250) { rate = 38400; new_rate = 8; } - else if (rate <= 46050) { rate = 44100; new_rate = 9; } - else { rate = 48000; new_rate = 10; } - - channel->ctrl &= ~FORTE_RATE_MASK; - channel->ctrl |= new_rate << FORTE_RATE_SHIFT; - channel->rate = rate; - - DPRINTK ("%s: %s rate = %d\n", __FUNCTION__, channel->name, rate); - - return rate; -} - - -/** - * forte_channel_format: - * @channel: Channel whose audio format to set - * @format: OSS format ID - * - * Locking: Must be called with lock held. - */ - -static int -forte_channel_format (struct forte_channel *channel, int format) -{ - if (!channel || !channel->iobase) - return -EINVAL; - - switch (format) { - - case AFMT_QUERY: - break; - - case AFMT_U8: - channel->ctrl &= ~FORTE_16BIT; - channel->format = AFMT_U8; - break; - - case AFMT_S16_LE: - default: - channel->ctrl |= FORTE_16BIT; - channel->format = AFMT_S16_LE; - break; - } - - DPRINTK ("%s: %s want %d format, got %d\n", __FUNCTION__, channel->name, - format, channel->format); - - return channel->format; -} - - -/** - * forte_channel_stereo: - * @channel: Channel to toggle - * @stereo: 0 for Mono, 1 for Stereo - * - * Locking: Must be called with lock held. - */ - -static int -forte_channel_stereo (struct forte_channel *channel, unsigned int stereo) -{ - int ret; - - if (!channel || !channel->iobase) - return -EINVAL; - - DPRINTK ("%s: %s stereo = %d\n", __FUNCTION__, channel->name, stereo); - - switch (stereo) { - - case 0: - channel->ctrl &= ~(FORTE_STEREO | FORTE_CHANNELS_MASK); - channel-> stereo = stereo; - ret = stereo; - break; - - case 1: - channel->ctrl &= ~FORTE_CHANNELS_MASK; - channel->ctrl |= FORTE_STEREO; - channel-> stereo = stereo; - ret = stereo; - break; - - default: - DPRINTK ("Unsupported channel format"); - ret = -EINVAL; - break; - } - - return ret; -} - - -/** - * forte_channel_buffer: - * @channel: Channel whose buffer to set up - * - * Locking: Must be called with lock held. - */ - -static void -forte_channel_buffer (struct forte_channel *channel, int sz, int num) -{ - unsigned int msecs, shift; - - /* Go away, I'm busy */ - if (channel->filled_frags || channel->bytes) - return; - - /* Fragment size must be a power of 2 */ - shift = 0; sz++; - while (sz >>= 1) - shift++; - channel->frag_sz = 1 << shift; - - /* Round fragment size to something reasonable */ - if (channel->frag_sz < FORTE_MIN_FRAG_SIZE) - channel->frag_sz = FORTE_MIN_FRAG_SIZE; - - if (channel->frag_sz > FORTE_MAX_FRAG_SIZE) - channel->frag_sz = FORTE_MAX_FRAG_SIZE; - - /* Find fragment length in milliseconds */ - msecs = channel->frag_sz / - (channel->format == AFMT_S16_LE ? 2 : 1) / - (channel->stereo ? 2 : 1) / - (channel->rate / 1000); - - channel->frag_msecs = msecs; - - /* Pick a suitable number of fragments */ - if (msecs * num < FORTE_MIN_BUF_MSECS) - num = FORTE_MIN_BUF_MSECS / msecs; - - if (msecs * num > FORTE_MAX_BUF_MSECS) - num = FORTE_MAX_BUF_MSECS / msecs; - - /* Fragment number must be a power of 2 */ - shift = 0; - while (num >>= 1) - shift++; - channel->frag_num = 1 << (shift + 1); - - /* Round fragment number to something reasonable */ - if (channel->frag_num < FORTE_MIN_FRAGMENTS) - channel->frag_num = FORTE_MIN_FRAGMENTS; - - if (channel->frag_num > FORTE_MAX_FRAGMENTS) - channel->frag_num = FORTE_MAX_FRAGMENTS; - - channel->buf_sz = channel->frag_sz * channel->frag_num; - - DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d\n", - __FUNCTION__, channel->name, channel->frag_sz, - channel->frag_num, channel->buf_sz); -} - - -/** - * forte_channel_prep: - * @channel: Channel whose buffer to prepare - * - * Locking: Lock held. - */ - -static void -forte_channel_prep (struct forte_channel *channel) -{ - struct page *page; - int i; - - if (channel->buf) - return; - - forte_channel_buffer (channel, channel->frag_sz, channel->frag_num); - channel->buf_pages = channel->buf_sz >> PAGE_SHIFT; - - if (channel->buf_sz % PAGE_SIZE) - channel->buf_pages++; - - DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d, pg = %d\n", - __FUNCTION__, channel->name, channel->frag_sz, - channel->frag_num, channel->buf_sz, channel->buf_pages); - - /* DMA buffer */ - channel->buf = pci_alloc_consistent (forte->pci_dev, - channel->buf_pages * PAGE_SIZE, - &channel->buf_handle); - - if (!channel->buf || !channel->buf_handle) - BUG(); - - page = virt_to_page (channel->buf); - - /* FIXME: can this go away ? */ - for (i = 0 ; i < channel->buf_pages ; i++) - SetPageReserved(page++); - - /* Prep buffer registers */ - outw (channel->frag_sz - 1, channel->iobase + FORTE_PLY_COUNT); - outl (channel->buf_handle, channel->iobase + FORTE_PLY_BUF1); - outl (channel->buf_handle + channel->frag_sz, - channel->iobase + FORTE_PLY_BUF2); - - /* Reset hwptr */ - channel->hwptr = channel->frag_sz; - channel->next_buf = 1; - - DPRINTK ("%s: %s buffer @ %p (%p)\n", __FUNCTION__, channel->name, - channel->buf, channel->buf_handle); -} - - -/** - * forte_channel_drain: - * @chip: - * @channel: - * - * Locking: Don't hold the lock. - */ - -static inline int -forte_channel_drain (struct forte_channel *channel) -{ - DECLARE_WAITQUEUE (wait, current); - unsigned long flags; - - DPRINTK ("%s\n", __FUNCTION__); - - if (channel->mapped) { - spin_lock_irqsave (&forte->lock, flags); - forte_channel_stop (channel); - spin_unlock_irqrestore (&forte->lock, flags); - return 0; - } - - spin_lock_irqsave (&forte->lock, flags); - add_wait_queue (&channel->wait, &wait); - - for (;;) { - if (channel->active == 0 || channel->filled_frags == 1) - break; - - spin_unlock_irqrestore (&forte->lock, flags); - - __set_current_state (TASK_INTERRUPTIBLE); - schedule(); - - spin_lock_irqsave (&forte->lock, flags); - } - - forte_channel_stop (channel); - forte_channel_reset (channel); - set_current_state (TASK_RUNNING); - remove_wait_queue (&channel->wait, &wait); - spin_unlock_irqrestore (&forte->lock, flags); - - return 0; -} - - -/** - * forte_channel_init: - * @chip: Forte chip instance the channel hangs off - * @channel: Channel to initialize - * - * Description: - * Initializes a channel, sets defaults, and allocates - * buffers. - * - * Locking: No lock held. - */ - -static int -forte_channel_init (struct forte_chip *chip, struct forte_channel *channel) -{ - DPRINTK ("%s: chip iobase @ %p\n", __FUNCTION__, (void *)chip->iobase); - - spin_lock_irq (&chip->lock); - memset (channel, 0x0, sizeof (*channel)); - - if (channel == &chip->play) { - channel->name = "PCM_OUT"; - channel->iobase = chip->iobase; - DPRINTK ("%s: PCM-OUT iobase @ %p\n", __FUNCTION__, - (void *) channel->iobase); - } - else if (channel == &chip->rec) { - channel->name = "PCM_IN"; - channel->iobase = chip->iobase + FORTE_CAP_OFFSET; - channel->record = 1; - DPRINTK ("%s: PCM-IN iobase @ %p\n", __FUNCTION__, - (void *) channel->iobase); - } - else - BUG(); - - init_waitqueue_head (&channel->wait); - - /* Defaults: 48kHz, 16-bit, stereo */ - channel->ctrl = inw (channel->iobase + FORTE_PLY_CTRL); - forte_channel_reset (channel); - forte_channel_stereo (channel, 1); - forte_channel_format (channel, AFMT_S16_LE); - forte_channel_rate (channel, 48000); - channel->frag_sz = FORTE_DEF_FRAG_SIZE; - channel->frag_num = FORTE_DEF_FRAGMENTS; - - chip->trigger = 0; - spin_unlock_irq (&chip->lock); - - return 0; -} - - -/** - * forte_channel_free: - * @chip: Chip this channel hangs off - * @channel: Channel to nuke - * - * Description: - * Resets channel and frees buffers. - * - * Locking: Hold your horses. - */ - -static void -forte_channel_free (struct forte_chip *chip, struct forte_channel *channel) -{ - DPRINTK ("%s: %s\n", __FUNCTION__, channel->name); - - if (!channel->buf_handle) - return; - - pci_free_consistent (chip->pci_dev, channel->buf_pages * PAGE_SIZE, - channel->buf, channel->buf_handle); - - memset (channel, 0x0, sizeof (*channel)); -} - - -/* DSP --------------------------------------------------------------------- */ - - -/** - * forte_dsp_ioctl: - */ - -static int -forte_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ival=0, ret, rval=0, rd, wr, count; - struct forte_chip *chip; - struct audio_buf_info abi; - struct count_info cinfo; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - chip = file->private_data; - - if (file->f_mode & FMODE_WRITE) - wr = 1; - else - wr = 0; - - if (file->f_mode & FMODE_READ) - rd = 1; - else - rd = 0; - - switch (cmd) { - - case OSS_GETVERSION: - return put_user (SOUND_VERSION, p); - - case SNDCTL_DSP_GETCAPS: - DPRINTK ("%s: GETCAPS\n", __FUNCTION__); - - ival = FORTE_CAPS; /* DUPLEX */ - return put_user (ival, p); - - case SNDCTL_DSP_GETFMTS: - DPRINTK ("%s: GETFMTS\n", __FUNCTION__); - - ival = FORTE_FMTS; /* U8, 16LE */ - return put_user (ival, p); - - case SNDCTL_DSP_SETFMT: /* U8, 16LE */ - DPRINTK ("%s: SETFMT\n", __FUNCTION__); - - if (get_user (ival, p)) - return -EFAULT; - - spin_lock_irq (&chip->lock); - - if (rd) { - forte_channel_stop (&chip->rec); - rval = forte_channel_format (&chip->rec, ival); - } - - if (wr) { - forte_channel_stop (&chip->rec); - rval = forte_channel_format (&chip->play, ival); - } - - spin_unlock_irq (&chip->lock); - - return put_user (rval, p); - - case SNDCTL_DSP_STEREO: /* 0 - mono, 1 - stereo */ - DPRINTK ("%s: STEREO\n", __FUNCTION__); - - if (get_user (ival, p)) - return -EFAULT; - - spin_lock_irq (&chip->lock); - - if (rd) { - forte_channel_stop (&chip->rec); - rval = forte_channel_stereo (&chip->rec, ival); - } - - if (wr) { - forte_channel_stop (&chip->rec); - rval = forte_channel_stereo (&chip->play, ival); - } - - spin_unlock_irq (&chip->lock); - - return put_user (rval, p); - - case SNDCTL_DSP_CHANNELS: /* 1 - mono, 2 - stereo */ - DPRINTK ("%s: CHANNELS\n", __FUNCTION__); - - if (get_user (ival, p)) - return -EFAULT; - - spin_lock_irq (&chip->lock); - - if (rd) { - forte_channel_stop (&chip->rec); - rval = forte_channel_stereo (&chip->rec, ival-1) + 1; - } - - if (wr) { - forte_channel_stop (&chip->play); - rval = forte_channel_stereo (&chip->play, ival-1) + 1; - } - - spin_unlock_irq (&chip->lock); - - return put_user (rval, p); - - case SNDCTL_DSP_SPEED: - DPRINTK ("%s: SPEED\n", __FUNCTION__); - - if (get_user (ival, p)) - return -EFAULT; - - spin_lock_irq (&chip->lock); - - if (rd) { - forte_channel_stop (&chip->rec); - rval = forte_channel_rate (&chip->rec, ival); - } - - if (wr) { - forte_channel_stop (&chip->play); - rval = forte_channel_rate (&chip->play, ival); - } - - spin_unlock_irq (&chip->lock); - - return put_user(rval, p); - - case SNDCTL_DSP_GETBLKSIZE: - DPRINTK ("%s: GETBLKSIZE\n", __FUNCTION__); - - spin_lock_irq (&chip->lock); - - if (rd) - ival = chip->rec.frag_sz; - - if (wr) - ival = chip->play.frag_sz; - - spin_unlock_irq (&chip->lock); - - return put_user (ival, p); - - case SNDCTL_DSP_RESET: - DPRINTK ("%s: RESET\n", __FUNCTION__); - - spin_lock_irq (&chip->lock); - - if (rd) - forte_channel_reset (&chip->rec); - - if (wr) - forte_channel_reset (&chip->play); - - spin_unlock_irq (&chip->lock); - - return 0; - - case SNDCTL_DSP_SYNC: - DPRINTK ("%s: SYNC\n", __FUNCTION__); - - if (wr) - ret = forte_channel_drain (&chip->play); - - return 0; - - case SNDCTL_DSP_POST: - DPRINTK ("%s: POST\n", __FUNCTION__); - - if (wr) { - spin_lock_irq (&chip->lock); - - if (chip->play.filled_frags) - forte_channel_start (&chip->play); - - spin_unlock_irq (&chip->lock); - } - - return 0; - - case SNDCTL_DSP_SETFRAGMENT: - DPRINTK ("%s: SETFRAGMENT\n", __FUNCTION__); - - if (get_user (ival, p)) - return -EFAULT; - - spin_lock_irq (&chip->lock); - - if (rd) { - forte_channel_buffer (&chip->rec, ival & 0xffff, - (ival >> 16) & 0xffff); - ival = (chip->rec.frag_num << 16) + chip->rec.frag_sz; - } - - if (wr) { - forte_channel_buffer (&chip->play, ival & 0xffff, - (ival >> 16) & 0xffff); - ival = (chip->play.frag_num << 16) +chip->play.frag_sz; - } - - spin_unlock_irq (&chip->lock); - - return put_user (ival, p); - - case SNDCTL_DSP_GETISPACE: - DPRINTK ("%s: GETISPACE\n", __FUNCTION__); - - if (!rd) - return -EINVAL; - - spin_lock_irq (&chip->lock); - - abi.fragstotal = chip->rec.frag_num; - abi.fragsize = chip->rec.frag_sz; - - if (chip->rec.mapped) { - abi.fragments = chip->rec.frag_num - 2; - abi.bytes = abi.fragments * abi.fragsize; - } - else { - abi.fragments = chip->rec.filled_frags; - abi.bytes = abi.fragments * abi.fragsize; - } - - spin_unlock_irq (&chip->lock); - - return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETIPTR: - DPRINTK ("%s: GETIPTR\n", __FUNCTION__); - - if (!rd) - return -EINVAL; - - spin_lock_irq (&chip->lock); - - if (chip->rec.active) - cinfo.ptr = chip->rec.hwptr; - else - cinfo.ptr = 0; - - cinfo.bytes = chip->rec.bytes; - cinfo.blocks = chip->rec.nr_irqs; - chip->rec.nr_irqs = 0; - - spin_unlock_irq (&chip->lock); - - return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETOSPACE: - if (!wr) - return -EINVAL; - - spin_lock_irq (&chip->lock); - - abi.fragstotal = chip->play.frag_num; - abi.fragsize = chip->play.frag_sz; - - if (chip->play.mapped) { - abi.fragments = chip->play.frag_num - 2; - abi.bytes = chip->play.buf_sz; - } - else { - abi.fragments = chip->play.frag_num - - chip->play.filled_frags; - - if (chip->play.residue) - abi.fragments--; - - abi.bytes = abi.fragments * abi.fragsize + - chip->play.residue; - } - - spin_unlock_irq (&chip->lock); - - return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETOPTR: - if (!wr) - return -EINVAL; - - spin_lock_irq (&chip->lock); - - if (chip->play.active) - cinfo.ptr = chip->play.hwptr; - else - cinfo.ptr = 0; - - cinfo.bytes = chip->play.bytes; - cinfo.blocks = chip->play.nr_irqs; - chip->play.nr_irqs = 0; - - spin_unlock_irq (&chip->lock); - - return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETODELAY: - if (!wr) - return -EINVAL; - - spin_lock_irq (&chip->lock); - - if (!chip->play.active) { - ival = 0; - } - else if (chip->play.mapped) { - count = inw (chip->play.iobase + FORTE_PLY_COUNT) + 1; - ival = chip->play.frag_sz - count; - } - else { - ival = chip->play.filled_frags * chip->play.frag_sz; - - if (chip->play.residue) - ival += chip->play.frag_sz - chip->play.residue; - } - - spin_unlock_irq (&chip->lock); - - return put_user (ival, p); - - case SNDCTL_DSP_SETDUPLEX: - DPRINTK ("%s: SETDUPLEX\n", __FUNCTION__); - - return -EINVAL; - - case SNDCTL_DSP_GETTRIGGER: - DPRINTK ("%s: GETTRIGGER\n", __FUNCTION__); - - return put_user (chip->trigger, p); - - case SNDCTL_DSP_SETTRIGGER: - - if (get_user (ival, p)) - return -EFAULT; - - DPRINTK ("%s: SETTRIGGER %d\n", __FUNCTION__, ival); - - if (wr) { - spin_lock_irq (&chip->lock); - - if (ival & PCM_ENABLE_OUTPUT) - forte_channel_start (&chip->play); - else { - chip->trigger = 1; - forte_channel_prep (&chip->play); - forte_channel_stop (&chip->play); - } - - spin_unlock_irq (&chip->lock); - } - else if (rd) { - spin_lock_irq (&chip->lock); - - if (ival & PCM_ENABLE_INPUT) - forte_channel_start (&chip->rec); - else { - chip->trigger = 1; - forte_channel_prep (&chip->rec); - forte_channel_stop (&chip->rec); - } - - spin_unlock_irq (&chip->lock); - } - - return 0; - - case SOUND_PCM_READ_RATE: - DPRINTK ("%s: PCM_READ_RATE\n", __FUNCTION__); - return put_user (chip->play.rate, p); - - case SOUND_PCM_READ_CHANNELS: - DPRINTK ("%s: PCM_READ_CHANNELS\n", __FUNCTION__); - return put_user (chip->play.stereo, p); - - case SOUND_PCM_READ_BITS: - DPRINTK ("%s: PCM_READ_BITS\n", __FUNCTION__); - return put_user (chip->play.format, p); - - case SNDCTL_DSP_NONBLOCK: - DPRINTK ("%s: DSP_NONBLOCK\n", __FUNCTION__); - file->f_flags |= O_NONBLOCK; - return 0; - - default: - DPRINTK ("Unsupported ioctl: %x (%p)\n", cmd, argp); - break; - } - - return -EINVAL; -} - - -/** - * forte_dsp_open: - */ - -static int -forte_dsp_open (struct inode *inode, struct file *file) -{ - struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */ - - if (file->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&chip->open_mutex)) { - DPRINTK ("%s: returning -EAGAIN\n", __FUNCTION__); - return -EAGAIN; - } - } - else { - if (mutex_lock_interruptible(&chip->open_mutex)) { - DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__); - return -ERESTARTSYS; - } - } - - file->private_data = forte; - - DPRINTK ("%s: dsp opened by %d\n", __FUNCTION__, current->pid); - - if (file->f_mode & FMODE_WRITE) - forte_channel_init (forte, &forte->play); - - if (file->f_mode & FMODE_READ) - forte_channel_init (forte, &forte->rec); - - return nonseekable_open(inode, file); -} - - -/** - * forte_dsp_release: - */ - -static int -forte_dsp_release (struct inode *inode, struct file *file) -{ - struct forte_chip *chip = file->private_data; - int ret = 0; - - DPRINTK ("%s: chip @ %p\n", __FUNCTION__, chip); - - if (file->f_mode & FMODE_WRITE) { - forte_channel_drain (&chip->play); - - spin_lock_irq (&chip->lock); - - forte_channel_free (chip, &chip->play); - - spin_unlock_irq (&chip->lock); - } - - if (file->f_mode & FMODE_READ) { - while (chip->rec.filled_frags > 0) - interruptible_sleep_on (&chip->rec.wait); - - spin_lock_irq (&chip->lock); - - forte_channel_stop (&chip->rec); - forte_channel_free (chip, &chip->rec); - - spin_unlock_irq (&chip->lock); - } - - mutex_unlock(&chip->open_mutex); - - return ret; -} - - -/** - * forte_dsp_poll: - * - */ - -static unsigned int -forte_dsp_poll (struct file *file, struct poll_table_struct *wait) -{ - struct forte_chip *chip; - struct forte_channel *channel; - unsigned int mask = 0; - - chip = file->private_data; - - if (file->f_mode & FMODE_WRITE) { - channel = &chip->play; - - if (channel->active) - poll_wait (file, &channel->wait, wait); - - spin_lock_irq (&chip->lock); - - if (channel->frag_num - channel->filled_frags > 0) - mask |= POLLOUT | POLLWRNORM; - - spin_unlock_irq (&chip->lock); - } - - if (file->f_mode & FMODE_READ) { - channel = &chip->rec; - - if (channel->active) - poll_wait (file, &channel->wait, wait); - - spin_lock_irq (&chip->lock); - - if (channel->filled_frags > 0) - mask |= POLLIN | POLLRDNORM; - - spin_unlock_irq (&chip->lock); - } - - return mask; -} - - -/** - * forte_dsp_mmap: - */ - -static int -forte_dsp_mmap (struct file *file, struct vm_area_struct *vma) -{ - struct forte_chip *chip; - struct forte_channel *channel; - unsigned long size; - int ret; - - chip = file->private_data; - - DPRINTK ("%s: start %lXh, size %ld, pgoff %ld\n", __FUNCTION__, - vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_pgoff); - - spin_lock_irq (&chip->lock); - - if (vma->vm_flags & VM_WRITE && chip->play.active) { - ret = -EBUSY; - goto out; - } - - if (vma->vm_flags & VM_READ && chip->rec.active) { - ret = -EBUSY; - goto out; - } - - if (file->f_mode & FMODE_WRITE) - channel = &chip->play; - else if (file->f_mode & FMODE_READ) - channel = &chip->rec; - else { - ret = -EINVAL; - goto out; - } - - forte_channel_prep (channel); - channel->mapped = 1; - - if (vma->vm_pgoff != 0) { - ret = -EINVAL; - goto out; - } - - size = vma->vm_end - vma->vm_start; - - if (size > channel->buf_pages * PAGE_SIZE) { - DPRINTK ("%s: size (%ld) > buf_sz (%d) \n", __FUNCTION__, - size, channel->buf_sz); - ret = -EINVAL; - goto out; - } - - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(channel->buf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) { - DPRINTK ("%s: remap el a no worko\n", __FUNCTION__); - ret = -EAGAIN; - goto out; - } - - ret = 0; - - out: - spin_unlock_irq (&chip->lock); - return ret; -} - - -/** - * forte_dsp_write: - */ - -static ssize_t -forte_dsp_write (struct file *file, const char __user *buffer, size_t bytes, - loff_t *ppos) -{ - struct forte_chip *chip; - struct forte_channel *channel; - unsigned int i = bytes, sz = 0; - unsigned long flags; - - if (!access_ok (VERIFY_READ, buffer, bytes)) - return -EFAULT; - - chip = (struct forte_chip *) file->private_data; - - if (!chip) - BUG(); - - channel = &chip->play; - - if (!channel) - BUG(); - - spin_lock_irqsave (&chip->lock, flags); - - /* Set up buffers with the right fragment size */ - forte_channel_prep (channel); - - while (i) { - /* All fragment buffers in use -> wait */ - if (channel->frag_num - channel->filled_frags == 0) { - DECLARE_WAITQUEUE (wait, current); - - /* For trigger or non-blocking operation, get out */ - if (chip->trigger || file->f_flags & O_NONBLOCK) { - spin_unlock_irqrestore (&chip->lock, flags); - return -EAGAIN; - } - - /* Otherwise wait for buffers */ - add_wait_queue (&channel->wait, &wait); - - for (;;) { - spin_unlock_irqrestore (&chip->lock, flags); - - set_current_state (TASK_INTERRUPTIBLE); - schedule(); - - spin_lock_irqsave (&chip->lock, flags); - - if (channel->frag_num - channel->filled_frags) - break; - } - - remove_wait_queue (&channel->wait, &wait); - set_current_state (TASK_RUNNING); - - if (signal_pending (current)) { - spin_unlock_irqrestore (&chip->lock, flags); - return -ERESTARTSYS; - } - } - - if (channel->residue) - sz = channel->residue; - else if (i > channel->frag_sz) - sz = channel->frag_sz; - else - sz = i; - - spin_unlock_irqrestore (&chip->lock, flags); - - if (copy_from_user ((void *) channel->buf + channel->swptr, buffer, sz)) - return -EFAULT; - - spin_lock_irqsave (&chip->lock, flags); - - /* Advance software pointer */ - buffer += sz; - channel->swptr += sz; - channel->swptr %= channel->buf_sz; - i -= sz; - - /* Only bump filled_frags if a full fragment has been written */ - if (channel->swptr % channel->frag_sz == 0) { - channel->filled_frags++; - channel->residue = 0; - } - else - channel->residue = channel->frag_sz - sz; - - /* If playback isn't active, start it */ - if (channel->active == 0 && chip->trigger == 0) - forte_channel_start (channel); - } - - spin_unlock_irqrestore (&chip->lock, flags); - - return bytes - i; -} - - -/** - * forte_dsp_read: - */ - -static ssize_t -forte_dsp_read (struct file *file, char __user *buffer, size_t bytes, - loff_t *ppos) -{ - struct forte_chip *chip; - struct forte_channel *channel; - unsigned int i = bytes, sz; - unsigned long flags; - - if (!access_ok (VERIFY_WRITE, buffer, bytes)) - return -EFAULT; - - chip = (struct forte_chip *) file->private_data; - - if (!chip) - BUG(); - - channel = &chip->rec; - - if (!channel) - BUG(); - - spin_lock_irqsave (&chip->lock, flags); - - /* Set up buffers with the right fragment size */ - forte_channel_prep (channel); - - /* Start recording */ - if (!chip->trigger) - forte_channel_start (channel); - - while (i) { - /* No fragment buffers in use -> wait */ - if (channel->filled_frags == 0) { - DECLARE_WAITQUEUE (wait, current); - - /* For trigger mode operation, get out */ - if (chip->trigger) { - spin_unlock_irqrestore (&chip->lock, flags); - return -EAGAIN; - } - - add_wait_queue (&channel->wait, &wait); - - for (;;) { - if (channel->active == 0) - break; - - if (channel->filled_frags) - break; - - spin_unlock_irqrestore (&chip->lock, flags); - - set_current_state (TASK_INTERRUPTIBLE); - schedule(); - - spin_lock_irqsave (&chip->lock, flags); - } - - set_current_state (TASK_RUNNING); - remove_wait_queue (&channel->wait, &wait); - } - - if (i > channel->frag_sz) - sz = channel->frag_sz; - else - sz = i; - - spin_unlock_irqrestore (&chip->lock, flags); - - if (copy_to_user (buffer, (void *)channel->buf+channel->swptr, sz)) { - DPRINTK ("%s: copy_to_user failed\n", __FUNCTION__); - return -EFAULT; - } - - spin_lock_irqsave (&chip->lock, flags); - - /* Advance software pointer */ - buffer += sz; - if (channel->filled_frags > 0) - channel->filled_frags--; - channel->swptr += channel->frag_sz; - channel->swptr %= channel->buf_sz; - i -= sz; - } - - spin_unlock_irqrestore (&chip->lock, flags); - - return bytes - i; -} - - -static struct file_operations forte_dsp_fops = { - .owner = THIS_MODULE, - .llseek = &no_llseek, - .read = &forte_dsp_read, - .write = &forte_dsp_write, - .poll = &forte_dsp_poll, - .ioctl = &forte_dsp_ioctl, - .open = &forte_dsp_open, - .release = &forte_dsp_release, - .mmap = &forte_dsp_mmap, -}; - - -/* Common ------------------------------------------------------------------ */ - - -/** - * forte_interrupt: - */ - -static irqreturn_t -forte_interrupt (int irq, void *dev_id, struct pt_regs *regs) -{ - struct forte_chip *chip = dev_id; - struct forte_channel *channel = NULL; - u16 status, count; - - status = inw (chip->iobase + FORTE_IRQ_STATUS); - - /* If this is not for us, get outta here ASAP */ - if ((status & (FORTE_IRQ_PLAYBACK | FORTE_IRQ_CAPTURE)) == 0) - return IRQ_NONE; - - if (status & FORTE_IRQ_PLAYBACK) { - channel = &chip->play; - - spin_lock (&chip->lock); - - if (channel->frag_sz == 0) - goto pack; - - /* Declare a fragment done */ - if (channel->filled_frags > 0) - channel->filled_frags--; - channel->bytes += channel->frag_sz; - channel->nr_irqs++; - - /* Flip-flop between buffer I and II */ - channel->next_buf ^= 1; - - /* Advance hardware pointer by fragment size and wrap around */ - channel->hwptr += channel->frag_sz; - channel->hwptr %= channel->buf_sz; - - /* Buffer I or buffer II BAR */ - outl (channel->buf_handle + channel->hwptr, - channel->next_buf == 0 ? - channel->iobase + FORTE_PLY_BUF1 : - channel->iobase + FORTE_PLY_BUF2); - - /* If the currently playing fragment is last, schedule pause */ - if (channel->filled_frags == 1) - forte_channel_pause (channel); - - pack: - /* Acknowledge interrupt */ - outw (FORTE_IRQ_PLAYBACK, chip->iobase + FORTE_IRQ_STATUS); - - if (waitqueue_active (&channel->wait)) - wake_up_all (&channel->wait); - - spin_unlock (&chip->lock); - } - - if (status & FORTE_IRQ_CAPTURE) { - channel = &chip->rec; - spin_lock (&chip->lock); - - /* One fragment filled */ - channel->filled_frags++; - - /* Get # of completed bytes */ - count = inw (channel->iobase + FORTE_PLY_COUNT) + 1; - - if (count == 0) { - DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__, - channel->filled_frags); - channel->filled_frags = 0; - goto rack; - } - - /* Buffer I or buffer II BAR */ - outl (channel->buf_handle + channel->hwptr, - channel->next_buf == 0 ? - channel->iobase + FORTE_PLY_BUF1 : - channel->iobase + FORTE_PLY_BUF2); - - /* Flip-flop between buffer I and II */ - channel->next_buf ^= 1; - - /* Advance hardware pointer by fragment size and wrap around */ - channel->hwptr += channel->frag_sz; - channel->hwptr %= channel->buf_sz; - - /* Out of buffers */ - if (channel->filled_frags == channel->frag_num - 1) - forte_channel_stop (channel); - rack: - /* Acknowledge interrupt */ - outw (FORTE_IRQ_CAPTURE, chip->iobase + FORTE_IRQ_STATUS); - - spin_unlock (&chip->lock); - - if (waitqueue_active (&channel->wait)) - wake_up_all (&channel->wait); - } - - return IRQ_HANDLED; -} - - -/** - * forte_proc_read: - */ - -static int -forte_proc_read (char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int i = 0, p_rate, p_chan, r_rate; - unsigned short p_reg, r_reg; - - i += sprintf (page, "ForteMedia FM801 OSS Lite driver\n%s\n \n", - DRIVER_VERSION); - - if (!forte->iobase) - return i; - - p_rate = p_chan = -1; - p_reg = inw (forte->iobase + FORTE_PLY_CTRL); - p_rate = (p_reg >> 8) & 15; - p_chan = (p_reg >> 12) & 3; - - if (p_rate >= 0 || p_rate <= 10) - p_rate = rates[p_rate]; - - if (p_chan >= 0 || p_chan <= 2) - p_chan = channels[p_chan]; - - r_rate = -1; - r_reg = inw (forte->iobase + FORTE_CAP_CTRL); - r_rate = (r_reg >> 8) & 15; - - if (r_rate >= 0 || r_rate <= 10) - r_rate = rates[r_rate]; - - i += sprintf (page + i, - " Playback Capture\n" - "FIFO empty : %-3s %-3s\n" - "Buf1 Last : %-3s %-3s\n" - "Buf2 Last : %-3s %-3s\n" - "Started : %-3s %-3s\n" - "Paused : %-3s %-3s\n" - "Immed Stop : %-3s %-3s\n" - "Rate : %-5d %-5d\n" - "Channels : %-5d -\n" - "16-bit : %-3s %-3s\n" - "Stereo : %-3s %-3s\n" - " \n" - "Buffer Sz : %-6d %-6d\n" - "Frag Sz : %-6d %-6d\n" - "Frag Num : %-6d %-6d\n" - "Frag msecs : %-6d %-6d\n" - "Used Frags : %-6d %-6d\n" - "Mapped : %-3s %-3s\n", - p_reg & 1<<0 ? "yes" : "no", - r_reg & 1<<0 ? "yes" : "no", - p_reg & 1<<1 ? "yes" : "no", - r_reg & 1<<1 ? "yes" : "no", - p_reg & 1<<2 ? "yes" : "no", - r_reg & 1<<2 ? "yes" : "no", - p_reg & 1<<5 ? "yes" : "no", - r_reg & 1<<5 ? "yes" : "no", - p_reg & 1<<6 ? "yes" : "no", - r_reg & 1<<6 ? "yes" : "no", - p_reg & 1<<7 ? "yes" : "no", - r_reg & 1<<7 ? "yes" : "no", - p_rate, r_rate, - p_chan, - p_reg & 1<<14 ? "yes" : "no", - r_reg & 1<<14 ? "yes" : "no", - p_reg & 1<<15 ? "yes" : "no", - r_reg & 1<<15 ? "yes" : "no", - forte->play.buf_sz, forte->rec.buf_sz, - forte->play.frag_sz, forte->rec.frag_sz, - forte->play.frag_num, forte->rec.frag_num, - forte->play.frag_msecs, forte->rec.frag_msecs, - forte->play.filled_frags, forte->rec.filled_frags, - forte->play.mapped ? "yes" : "no", - forte->rec.mapped ? "yes" : "no" - ); - - return i; -} - - -/** - * forte_proc_init: - * - * Creates driver info entries in /proc - */ - -static int __init -forte_proc_init (void) -{ - if (!proc_mkdir ("driver/forte", NULL)) - return -EIO; - - if (!create_proc_read_entry ("driver/forte/chip", 0, NULL, forte_proc_read, forte)) { - remove_proc_entry ("driver/forte", NULL); - return -EIO; - } - - if (!create_proc_read_entry("driver/forte/ac97", 0, NULL, ac97_read_proc, forte->ac97)) { - remove_proc_entry ("driver/forte/chip", NULL); - remove_proc_entry ("driver/forte", NULL); - return -EIO; - } - - return 0; -} - - -/** - * forte_proc_remove: - * - * Removes driver info entries in /proc - */ - -static void -forte_proc_remove (void) -{ - remove_proc_entry ("driver/forte/ac97", NULL); - remove_proc_entry ("driver/forte/chip", NULL); - remove_proc_entry ("driver/forte", NULL); -} - - -/** - * forte_chip_init: - * @chip: Chip instance to initialize - * - * Description: - * Resets chip, configures codec and registers the driver with - * the sound subsystem. - * - * Press and hold Start for 8 secs, then switch on Run - * and hold for 4 seconds. Let go of Start. Numbers - * assume a properly oiled TWG. - */ - -static int __devinit -forte_chip_init (struct forte_chip *chip) -{ - u8 revision; - u16 cmdw; - struct ac97_codec *codec; - - pci_read_config_byte (chip->pci_dev, PCI_REVISION_ID, &revision); - - if (revision >= 0xB1) { - chip->multichannel = 1; - printk (KERN_INFO PFX "Multi-channel device detected.\n"); - } - - /* Reset chip */ - outw (FORTE_CC_CODEC_RESET | FORTE_CC_AC97_RESET, - chip->iobase + FORTE_CODEC_CTRL); - udelay(100); - outw (0, chip->iobase + FORTE_CODEC_CTRL); - - /* Request read from AC97 */ - outw (FORTE_AC97_READ | (0 << FORTE_AC97_ADDR_SHIFT), - chip->iobase + FORTE_AC97_CMD); - mdelay(750); - - if ((inw (chip->iobase + FORTE_AC97_CMD) & (3<<8)) != (1<<8)) { - printk (KERN_INFO PFX "AC97 codec not responding"); - return -EIO; - } - - /* Init volume */ - outw (0x0808, chip->iobase + FORTE_PCM_VOL); - outw (0x9f1f, chip->iobase + FORTE_FM_VOL); - outw (0x8808, chip->iobase + FORTE_I2S_VOL); - - /* I2S control - I2S mode */ - outw (0x0003, chip->iobase + FORTE_I2S_MODE); - - /* Interrupt setup - unmask PLAYBACK & CAPTURE */ - cmdw = inw (chip->iobase + FORTE_IRQ_MASK); - cmdw &= ~0x0003; - outw (cmdw, chip->iobase + FORTE_IRQ_MASK); - - /* Interrupt clear */ - outw (FORTE_IRQ_PLAYBACK|FORTE_IRQ_CAPTURE, - chip->iobase + FORTE_IRQ_STATUS); - - /* Set up the AC97 codec */ - if ((codec = ac97_alloc_codec()) == NULL) - return -ENOMEM; - codec->private_data = chip; - codec->codec_read = forte_ac97_read; - codec->codec_write = forte_ac97_write; - codec->id = 0; - - if (ac97_probe_codec (codec) == 0) { - printk (KERN_ERR PFX "codec probe failed\n"); - ac97_release_codec(codec); - return -1; - } - - /* Register mixer */ - if ((codec->dev_mixer = - register_sound_mixer (&forte_mixer_fops, -1)) < 0) { - printk (KERN_ERR PFX "couldn't register mixer!\n"); - ac97_release_codec(codec); - return -1; - } - - chip->ac97 = codec; - - /* Register DSP */ - if ((chip->dsp = register_sound_dsp (&forte_dsp_fops, -1) ) < 0) { - printk (KERN_ERR PFX "couldn't register dsp!\n"); - return -1; - } - - /* Register with /proc */ - if (forte_proc_init()) { - printk (KERN_ERR PFX "couldn't add entries to /proc!\n"); - return -1; - } - - return 0; -} - - -/** - * forte_probe: - * @pci_dev: PCI struct for probed device - * @pci_id: - * - * Description: - * Allocates chip instance, I/O region, and IRQ - */ -static int __init -forte_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id) -{ - struct forte_chip *chip; - int ret = 0; - - /* FIXME: Support more than one chip */ - if (found++) - return -EIO; - - /* Ignition */ - if (pci_enable_device (pci_dev)) - return -EIO; - - pci_set_master (pci_dev); - - /* Allocate chip instance and configure */ - forte = (struct forte_chip *) - kmalloc (sizeof (struct forte_chip), GFP_KERNEL); - chip = forte; - - if (chip == NULL) { - printk (KERN_WARNING PFX "Out of memory"); - return -ENOMEM; - } - - memset (chip, 0, sizeof (struct forte_chip)); - chip->pci_dev = pci_dev; - - mutex_init(&chip->open_mutex); - spin_lock_init (&chip->lock); - spin_lock_init (&chip->ac97_lock); - - if (! request_region (pci_resource_start (pci_dev, 0), - pci_resource_len (pci_dev, 0), DRIVER_NAME)) { - printk (KERN_WARNING PFX "Unable to reserve I/O space"); - ret = -ENOMEM; - goto error; - } - - chip->iobase = pci_resource_start (pci_dev, 0); - chip->irq = pci_dev->irq; - - if (request_irq (chip->irq, forte_interrupt, IRQF_SHARED, DRIVER_NAME, - chip)) { - printk (KERN_WARNING PFX "Unable to reserve IRQ"); - ret = -EIO; - goto error; - } - - pci_set_drvdata (pci_dev, chip); - - printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%16llX IRQ %u\n", - chip->iobase, (unsigned long long)pci_resource_end (pci_dev, 0), - chip->irq); - - /* Power it up */ - if ((ret = forte_chip_init (chip)) == 0) - return 0; - - error: - if (chip->irq) - free_irq (chip->irq, chip); - - if (chip->iobase) - release_region (pci_resource_start (pci_dev, 0), - pci_resource_len (pci_dev, 0)); - - kfree (chip); - - return ret; -} - - -/** - * forte_remove: - * @pci_dev: PCI device to unclaim - * - */ - -static void -forte_remove (struct pci_dev *pci_dev) -{ - struct forte_chip *chip = pci_get_drvdata (pci_dev); - - if (chip == NULL) - return; - - /* Turn volume down to avoid popping */ - outw (0x1f1f, chip->iobase + FORTE_PCM_VOL); - outw (0x1f1f, chip->iobase + FORTE_FM_VOL); - outw (0x1f1f, chip->iobase + FORTE_I2S_VOL); - - forte_proc_remove(); - free_irq (chip->irq, chip); - release_region (chip->iobase, pci_resource_len (pci_dev, 0)); - - unregister_sound_dsp (chip->dsp); - unregister_sound_mixer (chip->ac97->dev_mixer); - ac97_release_codec(chip->ac97); - kfree (chip); - - printk (KERN_INFO PFX "driver released\n"); -} - - -static struct pci_device_id forte_pci_ids[] = { - { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, - { 0, } -}; - - -static struct pci_driver forte_pci_driver = { - .name = DRIVER_NAME, - .id_table = forte_pci_ids, - .probe = forte_probe, - .remove = forte_remove, - -}; - - -/** - * forte_init_module: - * - */ - -static int __init -forte_init_module (void) -{ - printk (KERN_INFO PFX DRIVER_VERSION "\n"); - - return pci_register_driver (&forte_pci_driver); -} - - -/** - * forte_cleanup_module: - * - */ - -static void __exit -forte_cleanup_module (void) -{ - pci_unregister_driver (&forte_pci_driver); -} - - -module_init(forte_init_module); -module_exit(forte_cleanup_module); - -MODULE_AUTHOR("Martin K. Petersen "); -MODULE_DESCRIPTION("ForteMedia FM801 OSS Driver"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE (pci, forte_pci_ids); diff --git a/sound/oss/gus.h b/sound/oss/gus.h deleted file mode 100644 index 3d5271baf042..000000000000 --- a/sound/oss/gus.h +++ /dev/null @@ -1,24 +0,0 @@ - -#include "ad1848.h" - -/* From gus_card.c */ -int gus_set_midi_irq(int num); -irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs * dummy); - -/* From gus_wave.c */ -int gus_wave_detect(int baseaddr); -void gus_wave_init(struct address_info *hw_config); -void gus_wave_unload (struct address_info *hw_config); -void gus_voice_irq(void); -void gus_write8(int reg, unsigned int data); -void guswave_dma_irq(void); -void gus_delay(void); -int gus_default_mixer_ioctl (int dev, unsigned int cmd, void __user *arg); -void gus_timer_command (unsigned int addr, unsigned int val); - -/* From gus_midi.c */ -void gus_midi_init(struct address_info *hw_config); -void gus_midi_interrupt(int dummy); - -/* From ics2101.c */ -int ics2101_mixer_init(void); diff --git a/sound/oss/gus_card.c b/sound/oss/gus_card.c deleted file mode 100644 index a3d6ae33fe8b..000000000000 --- a/sound/oss/gus_card.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * sound/oss/gus_card.c - * - * Detection routine for the Gravis Ultrasound. - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * - * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious - * usage of CS4231A codec, GUS wave and MIDI for GUS MAX. - * Christoph Hellwig: Adapted to module_init/module_exit, simple cleanups. - * - * Status: - * Tested... - */ - - -#include -#include -#include -#include - -#include "sound_config.h" - -#include "gus.h" -#include "gus_hw.h" - -irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy); - -int gus_base = 0, gus_irq = 0, gus_dma = 0; -int gus_no_wave_dma = 0; -extern int gus_wave_volume; -extern int gus_pcm_volume; -extern int have_gus_max; -int gus_pnp_flag = 0; -#ifdef CONFIG_SOUND_GUS16 -static int db16; /* Has a Gus16 AD1848 on it */ -#endif - -static void __init attach_gus(struct address_info *hw_config) -{ - gus_wave_init(hw_config); - - if (sound_alloc_dma(hw_config->dma, "GUS")) - printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma); - if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) - if (sound_alloc_dma(hw_config->dma2, "GUS(2)")) - printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2); - gus_midi_init(hw_config); - if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0) - printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); - - return; -} - -static int __init probe_gus(struct address_info *hw_config) -{ - int irq; - int io_addr; - - if (hw_config->card_subtype == 1) - gus_pnp_flag = 1; - - irq = hw_config->irq; - - if (hw_config->card_subtype == 0) /* GUS/MAX/ACE */ - if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && - irq != 11 && irq != 12 && irq != 15) - { - printk(KERN_ERR "GUS: Unsupported IRQ %d\n", irq); - return 0; - } - if (gus_wave_detect(hw_config->io_base)) - return 1; - -#ifndef EXCLUDE_GUS_IODETECT - - /* - * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6) - */ - - for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) { - if (io_addr == hw_config->io_base) /* Already tested */ - continue; - if (gus_wave_detect(io_addr)) { - hw_config->io_base = io_addr; - return 1; - } - } -#endif - - printk("NO GUS card found !\n"); - return 0; -} - -static void __exit unload_gus(struct address_info *hw_config) -{ - DDB(printk("unload_gus(%x)\n", hw_config->io_base)); - - gus_wave_unload(hw_config); - - release_region(hw_config->io_base, 16); - release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */ - free_irq(hw_config->irq, hw_config); - - sound_free_dma(hw_config->dma); - - if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) - sound_free_dma(hw_config->dma2); -} - -irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy) -{ - unsigned char src; - extern int gus_timer_enabled; - int handled = 0; - -#ifdef CONFIG_SOUND_GUSMAX - if (have_gus_max) { - struct address_info *hw_config = dev_id; - adintr(irq, (void *)hw_config->slots[1], NULL); - } -#endif -#ifdef CONFIG_SOUND_GUS16 - if (db16) { - struct address_info *hw_config = dev_id; - adintr(irq, (void *)hw_config->slots[3], NULL); - } -#endif - - while (1) - { - if (!(src = inb(u_IrqStatus))) - break; - handled = 1; - if (src & DMA_TC_IRQ) - { - guswave_dma_irq(); - } - if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) - { - gus_midi_interrupt(0); - } - if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) - { - if (gus_timer_enabled) - sound_timer_interrupt(); - gus_write8(0x45, 0); /* Ack IRQ */ - gus_timer_command(4, 0x80); /* Reset IRQ flags */ - } - if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) - gus_voice_irq(); - } - return IRQ_RETVAL(handled); -} - -/* - * Some extra code for the 16 bit sampling option - */ - -#ifdef CONFIG_SOUND_GUS16 - -static int __init init_gus_db16(struct address_info *hw_config) -{ - struct resource *ports; - - ports = request_region(hw_config->io_base, 4, "ad1848"); - if (!ports) - return 0; - - if (!ad1848_detect(ports, NULL, hw_config->osp)) { - release_region(hw_config->io_base, 4); - return 0; - } - - gus_pcm_volume = 100; - gus_wave_volume = 90; - - hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", ports, - hw_config->irq, - hw_config->dma, - hw_config->dma, 0, - hw_config->osp, - THIS_MODULE); - return 1; -} - -static void __exit unload_gus_db16(struct address_info *hw_config) -{ - - ad1848_unload(hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, 0); - sound_unload_audiodev(hw_config->slots[3]); -} -#endif - -#ifdef CONFIG_SOUND_GUS16 -static int gus16; -#endif -#ifdef CONFIG_SOUND_GUSMAX -static int no_wave_dma; /* Set if no dma is to be used for the - wave table (GF1 chip) */ -#endif - - -/* - * Note DMA2 of -1 has the right meaning in the GUS driver as well - * as here. - */ - -static struct address_info cfg; - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma16 = -1; /* Set this for modules that need it */ -static int __initdata type = 0; /* 1 for PnP */ - -module_param(io, int, 0); -module_param(irq, int, 0); -module_param(dma, int, 0); -module_param(dma16, int, 0); -module_param(type, int, 0); -#ifdef CONFIG_SOUND_GUSMAX -module_param(no_wave_dma, int, 0); -#endif -#ifdef CONFIG_SOUND_GUS16 -module_param(db16, int, 0); -module_param(gus16, int, 0); -#endif -MODULE_LICENSE("GPL"); - -static int __init init_gus(void) -{ - printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma16; - cfg.card_subtype = type; -#ifdef CONFIG_SOUND_GUSMAX - gus_no_wave_dma = no_wave_dma; -#endif - - if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { - printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n"); - return -EINVAL; - } - -#ifdef CONFIG_SOUND_GUS16 - if (gus16 && init_gus_db16(&cfg)) - db16 = 1; -#endif - if (!probe_gus(&cfg)) - return -ENODEV; - attach_gus(&cfg); - - return 0; -} - -static void __exit cleanup_gus(void) -{ -#ifdef CONFIG_SOUND_GUS16 - if (db16) - unload_gus_db16(&cfg); -#endif - unload_gus(&cfg); -} - -module_init(init_gus); -module_exit(cleanup_gus); - -#ifndef MODULE -static int __init setup_gus(char *str) -{ - /* io, irq, dma, dma2 */ - int ints[5]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma16 = ints[4]; - - return 1; -} - -__setup("gus=", setup_gus); -#endif diff --git a/sound/oss/gus_hw.h b/sound/oss/gus_hw.h deleted file mode 100644 index f97a0b8670e3..000000000000 --- a/sound/oss/gus_hw.h +++ /dev/null @@ -1,50 +0,0 @@ - -/* - * I/O addresses - */ - -#define u_Base (gus_base + 0x000) -#define u_Mixer u_Base -#define u_Status (gus_base + 0x006) -#define u_TimerControl (gus_base + 0x008) -#define u_TimerData (gus_base + 0x009) -#define u_IRQDMAControl (gus_base + 0x00b) -#define u_MidiControl (gus_base + 0x100) -#define MIDI_RESET 0x03 -#define MIDI_ENABLE_XMIT 0x20 -#define MIDI_ENABLE_RCV 0x80 -#define u_MidiStatus u_MidiControl -#define MIDI_RCV_FULL 0x01 -#define MIDI_XMIT_EMPTY 0x02 -#define MIDI_FRAME_ERR 0x10 -#define MIDI_OVERRUN 0x20 -#define MIDI_IRQ_PEND 0x80 -#define u_MidiData (gus_base + 0x101) -#define u_Voice (gus_base + 0x102) -#define u_Command (gus_base + 0x103) -#define u_DataLo (gus_base + 0x104) -#define u_DataHi (gus_base + 0x105) -#define u_MixData (gus_base + 0x106) /* Rev. 3.7+ mixing */ -#define u_MixSelect (gus_base + 0x506) /* registers. */ -#define u_IrqStatus u_Status -# define MIDI_TX_IRQ 0x01 /* pending MIDI xmit IRQ */ -# define MIDI_RX_IRQ 0x02 /* pending MIDI recv IRQ */ -# define GF1_TIMER1_IRQ 0x04 /* general purpose timer */ -# define GF1_TIMER2_IRQ 0x08 /* general purpose timer */ -# define WAVETABLE_IRQ 0x20 /* pending wavetable IRQ */ -# define ENVELOPE_IRQ 0x40 /* pending volume envelope IRQ */ -# define DMA_TC_IRQ 0x80 /* pending dma tc IRQ */ - -#define ICS2101 1 -# define ICS_MIXDEVS 6 -# define DEV_MIC 0 -# define DEV_LINE 1 -# define DEV_CD 2 -# define DEV_GF1 3 -# define DEV_UNUSED 4 -# define DEV_VOL 5 - -# define CHN_LEFT 0 -# define CHN_RIGHT 1 -#define CS4231 2 -#define u_DRAMIO (gus_base + 0x107) diff --git a/sound/oss/gus_linearvol.h b/sound/oss/gus_linearvol.h deleted file mode 100644 index 7ad0c30d4fd9..000000000000 --- a/sound/oss/gus_linearvol.h +++ /dev/null @@ -1,18 +0,0 @@ -static unsigned short gus_linearvol[128] = { - 0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0, - 0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0, - 0x0cff, 0x0d10, 0x0d20, 0x0d30, 0x0d40, 0x0d50, 0x0d60, 0x0d70, - 0x0d80, 0x0d90, 0x0da0, 0x0db0, 0x0dc0, 0x0dd0, 0x0de0, 0x0df0, - 0x0dff, 0x0e08, 0x0e10, 0x0e18, 0x0e20, 0x0e28, 0x0e30, 0x0e38, - 0x0e40, 0x0e48, 0x0e50, 0x0e58, 0x0e60, 0x0e68, 0x0e70, 0x0e78, - 0x0e80, 0x0e88, 0x0e90, 0x0e98, 0x0ea0, 0x0ea8, 0x0eb0, 0x0eb8, - 0x0ec0, 0x0ec8, 0x0ed0, 0x0ed8, 0x0ee0, 0x0ee8, 0x0ef0, 0x0ef8, - 0x0eff, 0x0f04, 0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c, - 0x0f20, 0x0f24, 0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3c, - 0x0f40, 0x0f44, 0x0f48, 0x0f4c, 0x0f50, 0x0f54, 0x0f58, 0x0f5c, - 0x0f60, 0x0f64, 0x0f68, 0x0f6c, 0x0f70, 0x0f74, 0x0f78, 0x0f7c, - 0x0f80, 0x0f84, 0x0f88, 0x0f8c, 0x0f90, 0x0f94, 0x0f98, 0x0f9c, - 0x0fa0, 0x0fa4, 0x0fa8, 0x0fac, 0x0fb0, 0x0fb4, 0x0fb8, 0x0fbc, - 0x0fc0, 0x0fc4, 0x0fc8, 0x0fcc, 0x0fd0, 0x0fd4, 0x0fd8, 0x0fdc, - 0x0fe0, 0x0fe4, 0x0fe8, 0x0fec, 0x0ff0, 0x0ff4, 0x0ff8, 0x0ffc -}; diff --git a/sound/oss/gus_midi.c b/sound/oss/gus_midi.c deleted file mode 100644 index d1997a417ad0..000000000000 --- a/sound/oss/gus_midi.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * sound/oss/gus_midi.c - * - * The low level driver for the GUS Midi Interface. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes: - * 11-10-2000 Bartlomiej Zolnierkiewicz - * Added __init to gus_midi_init() - */ - -#include -#include -#include "sound_config.h" - -#include "gus.h" -#include "gus_hw.h" - -static int midi_busy, input_opened; -static int my_dev; -static int output_used; -static volatile unsigned char gus_midi_control; -static void (*midi_input_intr) (int dev, unsigned char data); - -static unsigned char tmp_queue[256]; -extern int gus_pnp_flag; -static volatile int qlen; -static volatile unsigned char qhead, qtail; -extern int gus_base, gus_irq, gus_dma; -extern int *gus_osp; -extern spinlock_t gus_lock; - -static int GUS_MIDI_STATUS(void) -{ - return inb(u_MidiStatus); -} - -static int gus_midi_open(int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev)) -{ - if (midi_busy) - { -/* printk("GUS: Midi busy\n");*/ - return -EBUSY; - } - outb((MIDI_RESET), u_MidiControl); - gus_delay(); - - gus_midi_control = 0; - input_opened = 0; - - if (mode == OPEN_READ || mode == OPEN_READWRITE) - if (!gus_pnp_flag) - { - gus_midi_control |= MIDI_ENABLE_RCV; - input_opened = 1; - } - outb((gus_midi_control), u_MidiControl); /* Enable */ - - midi_busy = 1; - qlen = qhead = qtail = output_used = 0; - midi_input_intr = input; - - return 0; -} - -static int dump_to_midi(unsigned char midi_byte) -{ - unsigned long flags; - int ok = 0; - - output_used = 1; - - spin_lock_irqsave(&gus_lock, flags); - - if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY) - { - ok = 1; - outb((midi_byte), u_MidiData); - } - else - { - /* - * Enable Midi xmit interrupts (again) - */ - gus_midi_control |= MIDI_ENABLE_XMIT; - outb((gus_midi_control), u_MidiControl); - } - - spin_unlock_irqrestore(&gus_lock,flags); - return ok; -} - -static void gus_midi_close(int dev) -{ - /* - * Reset FIFO pointers, disable intrs - */ - - outb((MIDI_RESET), u_MidiControl); - midi_busy = 0; -} - -static int gus_midi_out(int dev, unsigned char midi_byte) -{ - unsigned long flags; - - /* - * Drain the local queue first - */ - spin_lock_irqsave(&gus_lock, flags); - - while (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - spin_unlock_irqrestore(&gus_lock,flags); - - /* - * Output the byte if the local queue is empty. - */ - - if (!qlen) - if (dump_to_midi(midi_byte)) - return 1; /* - * OK - */ - - /* - * Put to the local queue - */ - - if (qlen >= 256) - return 0; /* - * Local queue full - */ - spin_lock_irqsave(&gus_lock, flags); - - tmp_queue[qtail] = midi_byte; - qlen++; - qtail++; - - spin_unlock_irqrestore(&gus_lock,flags); - return 1; -} - -static int gus_midi_start_read(int dev) -{ - return 0; -} - -static int gus_midi_end_read(int dev) -{ - return 0; -} - -static void gus_midi_kick(int dev) -{ -} - -static int gus_midi_buffer_status(int dev) -{ - unsigned long flags; - - if (!output_used) - return 0; - - spin_lock_irqsave(&gus_lock, flags); - - if (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - spin_unlock_irqrestore(&gus_lock,flags); - return (qlen > 0) || !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY); -} - -#define MIDI_SYNTH_NAME "Gravis Ultrasound Midi" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static struct midi_operations gus_midi_operations = -{ - .owner = THIS_MODULE, - .info = {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = gus_midi_open, - .close = gus_midi_close, - .outputc = gus_midi_out, - .start_read = gus_midi_start_read, - .end_read = gus_midi_end_read, - .kick = gus_midi_kick, - .buffer_status = gus_midi_buffer_status, -}; - -void __init gus_midi_init(struct address_info *hw_config) -{ - int dev = sound_alloc_mididev(); - - if (dev == -1) - { - printk(KERN_INFO "gus_midi: Too many midi devices detected\n"); - return; - } - outb((MIDI_RESET), u_MidiControl); - - std_midi_synth.midi_dev = my_dev = dev; - hw_config->slots[2] = dev; - midi_devs[dev] = &gus_midi_operations; - sequencer_init(); - return; -} - -void gus_midi_interrupt(int dummy) -{ - volatile unsigned char stat, data; - int timeout = 10; - - spin_lock(&gus_lock); - - while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY)) - { - if (stat & MIDI_RCV_FULL) - { - data = inb(u_MidiData); - if (input_opened) - midi_input_intr(my_dev, data); - } - if (stat & MIDI_XMIT_EMPTY) - { - while (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - if (!qlen) - { - /* - * Disable Midi output interrupts, since no data in the buffer - */ - gus_midi_control &= ~MIDI_ENABLE_XMIT; - outb((gus_midi_control), u_MidiControl); - outb((gus_midi_control), u_MidiControl); - } - } - } - spin_unlock(&gus_lock); -} diff --git a/sound/oss/gus_vol.c b/sound/oss/gus_vol.c deleted file mode 100644 index 6ae6924e1647..000000000000 --- a/sound/oss/gus_vol.c +++ /dev/null @@ -1,153 +0,0 @@ - -/* - * gus_vol.c - Compute volume for GUS. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -#include "sound_config.h" - -#include "gus.h" -#include "gus_linearvol.h" - -#define GUS_VOLUME gus_wave_volume - - -extern int gus_wave_volume; - -/* - * Calculate gus volume from note velocity, main volume, expression, and - * intrinsic patch volume given in patch library. Expression is multiplied - * in, so it emphasizes differences in note velocity, while main volume is - * added in -- I don't know whether this is right, but it seems reasonable to - * me. (In the previous stage, main volume controller messages were changed - * to expression controller messages, if they were found to be used for - * dynamic volume adjustments, so here, main volume can be assumed to be - * constant throughout a song.) - * - * Intrinsic patch volume is added in, but if over 64 is also multiplied in, so - * we can give a big boost to very weak voices like nylon guitar and the - * basses. The normal value is 64. Strings are assigned lower values. - */ - -unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev) -{ - int i, m, n, x; - - - /* - * A voice volume of 64 is considered neutral, so adjust the main volume if - * something other than this neutral value was assigned in the patch - * library. - */ - x = 256 + 6 * (voicev - 64); - - /* - * Boost expression by voice volume above neutral. - */ - - if (voicev > 65) - xpn += voicev - 64; - xpn += (voicev - 64) / 2; - - /* - * Combine multiplicative and level components. - */ - x = vel * xpn * 6 + (voicev / 4) * x; - -#ifdef GUS_VOLUME - /* - * Further adjustment by installation-specific master volume control - * (default 60). - */ - x = (x * GUS_VOLUME * GUS_VOLUME) / 10000; -#endif - -#ifdef GUS_USE_CHN_MAIN_VOLUME - /* - * Experimental support for the channel main volume - */ - - mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */ - x = (x * mainv * mainv) / 16384; -#endif - - if (x < 2) - return (0); - else if (x >= 65535) - return ((15 << 8) | 255); - - /* - * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit - * mantissa m. - */ - - n = x; - i = 7; - if (n < 128) - { - while (i > 0 && n < (1 << i)) - i--; - } - else - { - while (n > 255) - { - n >>= 1; - i++; - } - } - /* - * Mantissa is part of linear volume not expressed in exponent. (This is - * not quite like real logs -- I wonder if it's right.) - */ - m = x - (1 << i); - - /* - * Adjust mantissa to 8 bits. - */ - if (m > 0) - { - if (i > 8) - m >>= i - 8; - else if (i < 8) - m <<= 8 - i; - } - return ((i << 8) + m); -} - -/* - * Volume-values are interpreted as linear values. Volume is based on the - * value supplied with SEQ_START_NOTE(), channel main volume (if compiled in) - * and the volume set by the mixer-device (default 60%). - */ - -unsigned short gus_linear_vol(int vol, int mainvol) -{ - int mixer_mainvol; - - if (vol <= 0) - vol = 0; - else if (vol >= 127) - vol = 127; - -#ifdef GUS_VOLUME - mixer_mainvol = GUS_VOLUME; -#else - mixer_mainvol = 100; -#endif - -#ifdef GUS_USE_CHN_MAIN_VOLUME - if (mainvol <= 0) - mainvol = 0; - else if (mainvol >= 127) - mainvol = 127; -#else - mainvol = 127; -#endif - return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100]; -} diff --git a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c deleted file mode 100644 index 597db7aee632..000000000000 --- a/sound/oss/gus_wave.c +++ /dev/null @@ -1,3464 +0,0 @@ -/* - * sound/oss/gus_wave.c - * - * Driver for the Gravis UltraSound wave table synth. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious - * usage of CS4231A codec, GUS wave and MIDI for GUS MAX. - * Bartlomiej Zolnierkiewicz : added some __init/__exit - */ - -#include -#include -#include - -#define GUSPNP_AUTODETECT - -#include "sound_config.h" -#include - -#include "gus.h" -#include "gus_hw.h" - -#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) - -#define MAX_SAMPLE 150 -#define MAX_PATCH 256 - -#define NOT_SAMPLE 0xffff - -struct voice_info -{ - unsigned long orig_freq; - unsigned long current_freq; - unsigned long mode; - int fixed_pitch; - int bender; - int bender_range; - int panning; - int midi_volume; - unsigned int initial_volume; - unsigned int current_volume; - int loop_irq_mode, loop_irq_parm; -#define LMODE_FINISH 1 -#define LMODE_PCM 2 -#define LMODE_PCM_STOP 3 - int volume_irq_mode, volume_irq_parm; -#define VMODE_HALT 1 -#define VMODE_ENVELOPE 2 -#define VMODE_START_NOTE 3 - - int env_phase; - unsigned char env_rate[6]; - unsigned char env_offset[6]; - - /* - * Volume computation parameters for gus_adagio_vol() - */ - int main_vol, expression_vol, patch_vol; - - /* Variables for "Ultraclick" removal */ - int dev_pending, note_pending, volume_pending, - sample_pending; - char kill_pending; - long offset_pending; - -}; - -static struct voice_alloc_info *voice_alloc; -static struct address_info *gus_hw_config; -extern int gus_base; -extern int gus_irq, gus_dma; -extern int gus_pnp_flag; -extern int gus_no_wave_dma; -static int gus_dma2 = -1; -static int dual_dma_mode; -static long gus_mem_size; -static long free_mem_ptr; -static int gus_busy; -static int gus_no_dma; -static int nr_voices; -static int gus_devnum; -static int volume_base, volume_scale, volume_method; -static int gus_recmask = SOUND_MASK_MIC; -static int recording_active; -static int only_read_access; -static int only_8_bits; - -static int iw_mode = 0; -int gus_wave_volume = 60; -int gus_pcm_volume = 80; -int have_gus_max = 0; -static int gus_line_vol = 100, gus_mic_vol; -static unsigned char mix_image = 0x00; - -int gus_timer_enabled = 0; - -/* - * Current version of this driver doesn't allow synth and PCM functions - * at the same time. The active_device specifies the active driver - */ - -static int active_device; - -#define GUS_DEV_WAVE 1 /* Wave table synth */ -#define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */ -#define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer done ch. 1/2 */ - -static int gus_audio_speed; -static int gus_audio_channels; -static int gus_audio_bits; -static int gus_audio_bsize; -static char bounce_buf[8 * 1024]; /* Must match value set to max_fragment */ - -static DECLARE_WAIT_QUEUE_HEAD(dram_sleeper); - -/* - * Variables and buffers for PCM output - */ - -#define MAX_PCM_BUFFERS (128*MAX_REALTIME_FACTOR) /* Don't change */ - -static int pcm_bsize, pcm_nblk, pcm_banksize; -static int pcm_datasize[MAX_PCM_BUFFERS]; -static volatile int pcm_head, pcm_tail, pcm_qlen; -static volatile int pcm_active; -static volatile int dma_active; -static int pcm_opened; -static int pcm_current_dev; -static int pcm_current_block; -static unsigned long pcm_current_buf; -static int pcm_current_count; -static int pcm_current_intrflag; -DEFINE_SPINLOCK(gus_lock); - -extern int *gus_osp; - -static struct voice_info voices[32]; - -static int freq_div_table[] = -{ - 44100, /* 14 */ - 41160, /* 15 */ - 38587, /* 16 */ - 36317, /* 17 */ - 34300, /* 18 */ - 32494, /* 19 */ - 30870, /* 20 */ - 29400, /* 21 */ - 28063, /* 22 */ - 26843, /* 23 */ - 25725, /* 24 */ - 24696, /* 25 */ - 23746, /* 26 */ - 22866, /* 27 */ - 22050, /* 28 */ - 21289, /* 29 */ - 20580, /* 30 */ - 19916, /* 31 */ - 19293 /* 32 */ -}; - -static struct patch_info *samples; -static long sample_ptrs[MAX_SAMPLE + 1]; -static int sample_map[32]; -static int free_sample; -static int mixer_type; - - -static int patch_table[MAX_PATCH]; -static int patch_map[32]; - -static struct synth_info gus_info = { - "Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, - 0, 16, 0, MAX_PATCH -}; - -static void gus_poke(long addr, unsigned char data); -static void compute_and_set_volume(int voice, int volume, int ramp_time); -extern unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev); -extern unsigned short gus_linear_vol(int vol, int mainvol); -static void compute_volume(int voice, int volume); -static void do_volume_irq(int voice); -static void set_input_volumes(void); -static void gus_tmr_install(int io_base); - -#define INSTANT_RAMP -1 /* Instant change. No ramping */ -#define FAST_RAMP 0 /* Fastest possible ramp */ - -static void reset_sample_memory(void) -{ - int i; - - for (i = 0; i <= MAX_SAMPLE; i++) - sample_ptrs[i] = -1; - for (i = 0; i < 32; i++) - sample_map[i] = -1; - for (i = 0; i < 32; i++) - patch_map[i] = -1; - - gus_poke(0, 0); /* Put a silent sample to the beginning */ - gus_poke(1, 0); - free_mem_ptr = 2; - - free_sample = 0; - - for (i = 0; i < MAX_PATCH; i++) - patch_table[i] = NOT_SAMPLE; -} - -void gus_delay(void) -{ - int i; - - for (i = 0; i < 7; i++) - inb(u_DRAMIO); -} - -static void gus_poke(long addr, unsigned char data) -{ /* Writes a byte to the DRAM */ - outb((0x43), u_Command); - outb((addr & 0xff), u_DataLo); - outb(((addr >> 8) & 0xff), u_DataHi); - - outb((0x44), u_Command); - outb(((addr >> 16) & 0xff), u_DataHi); - outb((data), u_DRAMIO); -} - -static unsigned char gus_peek(long addr) -{ /* Reads a byte from the DRAM */ - unsigned char tmp; - - outb((0x43), u_Command); - outb((addr & 0xff), u_DataLo); - outb(((addr >> 8) & 0xff), u_DataHi); - - outb((0x44), u_Command); - outb(((addr >> 16) & 0xff), u_DataHi); - tmp = inb(u_DRAMIO); - - return tmp; -} - -void gus_write8(int reg, unsigned int data) -{ /* Writes to an indirect register (8 bit) */ - outb((reg), u_Command); - outb(((unsigned char) (data & 0xff)), u_DataHi); -} - -static unsigned char gus_read8(int reg) -{ - /* Reads from an indirect register (8 bit). Offset 0x80. */ - unsigned char val; - - outb((reg | 0x80), u_Command); - val = inb(u_DataHi); - - return val; -} - -static unsigned char gus_look8(int reg) -{ - /* Reads from an indirect register (8 bit). No additional offset. */ - unsigned char val; - - outb((reg), u_Command); - val = inb(u_DataHi); - - return val; -} - -static void gus_write16(int reg, unsigned int data) -{ - /* Writes to an indirect register (16 bit) */ - outb((reg), u_Command); - - outb(((unsigned char) (data & 0xff)), u_DataLo); - outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi); -} - -static unsigned short gus_read16(int reg) -{ - /* Reads from an indirect register (16 bit). Offset 0x80. */ - unsigned char hi, lo; - - outb((reg | 0x80), u_Command); - - lo = inb(u_DataLo); - hi = inb(u_DataHi); - - return ((hi << 8) & 0xff00) | lo; -} - -static unsigned short gus_look16(int reg) -{ - /* Reads from an indirect register (16 bit). No additional offset. */ - unsigned char hi, lo; - - outb((reg), u_Command); - - lo = inb(u_DataLo); - hi = inb(u_DataHi); - - return ((hi << 8) & 0xff00) | lo; -} - -static void gus_write_addr(int reg, unsigned long address, int frac, int is16bit) -{ - /* Writes an 24 bit memory address */ - unsigned long hold_address; - - if (is16bit) - { - if (iw_mode) - { - /* Interwave spesific address translations */ - address >>= 1; - } - else - { - /* - * Special processing required for 16 bit patches - */ - - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - } - gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff) - + (frac << 5)); - /* Could writing twice fix problems with GUS_VOICE_POS()? Let's try. */ - gus_delay(); - gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff) - + (frac << 5)); -} - -static void gus_select_voice(int voice) -{ - if (voice < 0 || voice > 31) - return; - outb((voice), u_Voice); -} - -static void gus_select_max_voices(int nvoices) -{ - if (iw_mode) - nvoices = 32; - if (nvoices < 14) - nvoices = 14; - if (nvoices > 32) - nvoices = 32; - - voice_alloc->max_voice = nr_voices = nvoices; - gus_write8(0x0e, (nvoices - 1) | 0xc0); -} - -static void gus_voice_on(unsigned int mode) -{ - gus_write8(0x00, (unsigned char) (mode & 0xfc)); - gus_delay(); - gus_write8(0x00, (unsigned char) (mode & 0xfc)); -} - -static void gus_voice_off(void) -{ - gus_write8(0x00, gus_read8(0x00) | 0x03); -} - -static void gus_voice_mode(unsigned int m) -{ - unsigned char mode = (unsigned char) (m & 0xff); - - gus_write8(0x00, (gus_read8(0x00) & 0x03) | - (mode & 0xfc)); /* Don't touch last two bits */ - gus_delay(); - gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc)); -} - -static void gus_voice_freq(unsigned long freq) -{ - unsigned long divisor = freq_div_table[nr_voices - 14]; - unsigned short fc; - - /* Interwave plays at 44100 Hz with any number of voices */ - if (iw_mode) - fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100); - else - fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor); - fc = fc << 1; - - gus_write16(0x01, fc); -} - -static void gus_voice_volume(unsigned int vol) -{ - gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */ - gus_write16(0x09, (unsigned short) (vol << 4)); -} - -static void gus_voice_balance(unsigned int balance) -{ - gus_write8(0x0c, (unsigned char) (balance & 0xff)); -} - -static void gus_ramp_range(unsigned int low, unsigned int high) -{ - gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff)); - gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff)); -} - -static void gus_ramp_rate(unsigned int scale, unsigned int rate) -{ - gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); -} - -static void gus_rampon(unsigned int m) -{ - unsigned char mode = (unsigned char) (m & 0xff); - - gus_write8(0x0d, mode & 0xfc); - gus_delay(); - gus_write8(0x0d, mode & 0xfc); -} - -static void gus_ramp_mode(unsigned int m) -{ - unsigned char mode = (unsigned char) (m & 0xff); - - gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | - (mode & 0xfc)); /* Leave the last 2 bits alone */ - gus_delay(); - gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc)); -} - -static void gus_rampoff(void) -{ - gus_write8(0x0d, 0x03); -} - -static void gus_set_voice_pos(int voice, long position) -{ - int sample_no; - - if ((sample_no = sample_map[voice]) != -1) { - if (position < samples[sample_no].len) { - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - voices[voice].offset_pending = position; - else - gus_write_addr(0x0a, sample_ptrs[sample_no] + position, 0, - samples[sample_no].mode & WAVE_16_BITS); - } - } -} - -static void gus_voice_init(int voice) -{ - unsigned long flags; - - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_voice_volume(0); - gus_voice_off(); - gus_write_addr(0x0a, 0, 0, 0); /* Set current position to 0 */ - gus_write8(0x00, 0x03); /* Voice off */ - gus_write8(0x0d, 0x03); /* Ramping off */ - voice_alloc->map[voice] = 0; - voice_alloc->alloc_times[voice] = 0; - spin_unlock_irqrestore(&gus_lock,flags); - -} - -static void gus_voice_init2(int voice) -{ - voices[voice].panning = 0; - voices[voice].mode = 0; - voices[voice].orig_freq = 20000; - voices[voice].current_freq = 20000; - voices[voice].bender = 0; - voices[voice].bender_range = 200; - voices[voice].initial_volume = 0; - voices[voice].current_volume = 0; - voices[voice].loop_irq_mode = 0; - voices[voice].loop_irq_parm = 0; - voices[voice].volume_irq_mode = 0; - voices[voice].volume_irq_parm = 0; - voices[voice].env_phase = 0; - voices[voice].main_vol = 127; - voices[voice].patch_vol = 127; - voices[voice].expression_vol = 127; - voices[voice].sample_pending = -1; - voices[voice].fixed_pitch = 0; -} - -static void step_envelope(int voice) -{ - unsigned vol, prev_vol, phase; - unsigned char rate; - unsigned long flags; - - if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) - { - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_rampoff(); - spin_unlock_irqrestore(&gus_lock,flags); - return; - /* - * Sustain phase begins. Continue envelope after receiving note off. - */ - } - if (voices[voice].env_phase >= 5) - { - /* Envelope finished. Shoot the voice down */ - gus_voice_init(voice); - return; - } - prev_vol = voices[voice].current_volume; - phase = ++voices[voice].env_phase; - compute_volume(voice, voices[voice].midi_volume); - vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; - rate = voices[voice].env_rate[phase]; - - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - - gus_voice_volume(prev_vol); - - - gus_write8(0x06, rate); /* Ramping rate */ - - voices[voice].volume_irq_mode = VMODE_ENVELOPE; - - if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ - { - spin_unlock_irqrestore(&gus_lock,flags); - step_envelope(voice); /* Continue the envelope on the next step */ - return; - } - if (vol > prev_vol) - { - if (vol >= (4096 - 64)) - vol = 4096 - 65; - gus_ramp_range(0, vol); - gus_rampon(0x20); /* Increasing volume, with IRQ */ - } - else - { - if (vol <= 64) - vol = 65; - gus_ramp_range(vol, 4030); - gus_rampon(0x60); /* Decreasing volume, with IRQ */ - } - voices[voice].current_volume = vol; - spin_unlock_irqrestore(&gus_lock,flags); -} - -static void init_envelope(int voice) -{ - voices[voice].env_phase = -1; - voices[voice].current_volume = 64; - - step_envelope(voice); -} - -static void start_release(int voice) -{ - if (gus_read8(0x00) & 0x03) - return; /* Voice already stopped */ - - voices[voice].env_phase = 2; /* Will be incremented by step_envelope */ - - voices[voice].current_volume = voices[voice].initial_volume = - gus_read16(0x09) >> 4; /* Get current volume */ - - voices[voice].mode &= ~WAVE_SUSTAIN_ON; - gus_rampoff(); - step_envelope(voice); -} - -static void gus_voice_fade(int voice) -{ - int instr_no = sample_map[voice], is16bits; - unsigned long flags; - - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - - if (instr_no < 0 || instr_no > MAX_SAMPLE) - { - gus_write8(0x00, 0x03); /* Hard stop */ - voice_alloc->map[voice] = 0; - spin_unlock_irqrestore(&gus_lock,flags); - return; - } - is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ - - if (voices[voice].mode & WAVE_ENVELOPES) - { - start_release(voice); - spin_unlock_irqrestore(&gus_lock,flags); - return; - } - /* - * Ramp the volume down but not too quickly. - */ - if ((int) (gus_read16(0x09) >> 4) < 100) /* Get current volume */ - { - gus_voice_off(); - gus_rampoff(); - gus_voice_init(voice); - spin_unlock_irqrestore(&gus_lock,flags); - return; - } - gus_ramp_range(65, 4030); - gus_ramp_rate(2, 4); - gus_rampon(0x40 | 0x20); /* Down, once, with IRQ */ - voices[voice].volume_irq_mode = VMODE_HALT; - spin_unlock_irqrestore(&gus_lock,flags); -} - -static void gus_reset(void) -{ - int i; - - gus_select_max_voices(24); - volume_base = 3071; - volume_scale = 4; - volume_method = VOL_METHOD_ADAGIO; - - for (i = 0; i < 32; i++) - { - gus_voice_init(i); /* Turn voice off */ - gus_voice_init2(i); - } -} - -static void gus_initialize(void) -{ - unsigned long flags; - unsigned char dma_image, irq_image, tmp; - - static unsigned char gus_irq_map[16] = { - 0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7 - }; - - static unsigned char gus_dma_map[8] = { - 0, 1, 0, 2, 0, 3, 4, 5 - }; - - spin_lock_irqsave(&gus_lock,flags); - gus_write8(0x4c, 0); /* Reset GF1 */ - gus_delay(); - gus_delay(); - - gus_write8(0x4c, 1); /* Release Reset */ - gus_delay(); - gus_delay(); - - /* - * Clear all interrupts - */ - - gus_write8(0x41, 0); /* DMA control */ - gus_write8(0x45, 0); /* Timer control */ - gus_write8(0x49, 0); /* Sample control */ - - gus_select_max_voices(24); - - inb(u_Status); /* Touch the status register */ - - gus_look8(0x41); /* Clear any pending DMA IRQs */ - gus_look8(0x49); /* Clear any pending sample IRQs */ - gus_read8(0x0f); /* Clear pending IRQs */ - - gus_reset(); /* Resets all voices */ - - gus_look8(0x41); /* Clear any pending DMA IRQs */ - gus_look8(0x49); /* Clear any pending sample IRQs */ - gus_read8(0x0f); /* Clear pending IRQs */ - - gus_write8(0x4c, 7); /* Master reset | DAC enable | IRQ enable */ - - /* - * Set up for Digital ASIC - */ - - outb((0x05), gus_base + 0x0f); - - mix_image |= 0x02; /* Disable line out (for a moment) */ - outb((mix_image), u_Mixer); - - outb((0x00), u_IRQDMAControl); - - outb((0x00), gus_base + 0x0f); - - /* - * Now set up the DMA and IRQ interface - * - * The GUS supports two IRQs and two DMAs. - * - * Just one DMA channel is used. This prevents simultaneous ADC and DAC. - * Adding this support requires significant changes to the dmabuf.c, dsp.c - * and audio.c also. - */ - - irq_image = 0; - tmp = gus_irq_map[gus_irq]; - if (!gus_pnp_flag && !tmp) - printk(KERN_WARNING "Warning! GUS IRQ not selected\n"); - irq_image |= tmp; - irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ - - dual_dma_mode = 1; - if (gus_dma2 == gus_dma || gus_dma2 == -1) - { - dual_dma_mode = 0; - dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ - - tmp = gus_dma_map[gus_dma]; - if (!tmp) - printk(KERN_WARNING "Warning! GUS DMA not selected\n"); - - dma_image |= tmp; - } - else - { - /* Setup dual DMA channel mode for GUS MAX */ - - dma_image = gus_dma_map[gus_dma]; - if (!dma_image) - printk(KERN_WARNING "Warning! GUS DMA not selected\n"); - - tmp = gus_dma_map[gus_dma2] << 3; - if (!tmp) - { - printk(KERN_WARNING "Warning! Invalid GUS MAX DMA\n"); - tmp = 0x40; /* Combine DMA channels */ - dual_dma_mode = 0; - } - dma_image |= tmp; - } - - /* - * For some reason the IRQ and DMA addresses must be written twice - */ - - /* - * Doing it first time - */ - - outb((mix_image), u_Mixer); /* Select DMA control */ - outb((dma_image | 0x80), u_IRQDMAControl); /* Set DMA address */ - - outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */ - outb((irq_image), u_IRQDMAControl); /* Set IRQ address */ - - /* - * Doing it second time - */ - - outb((mix_image), u_Mixer); /* Select DMA control */ - outb((dma_image), u_IRQDMAControl); /* Set DMA address */ - - outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */ - outb((irq_image), u_IRQDMAControl); /* Set IRQ address */ - - gus_select_voice(0); /* This disables writes to IRQ/DMA reg */ - - mix_image &= ~0x02; /* Enable line out */ - mix_image |= 0x08; /* Enable IRQ */ - outb((mix_image), u_Mixer); /* - * Turn mixer channels on - * Note! Mic in is left off. - */ - - gus_select_voice(0); /* This disables writes to IRQ/DMA reg */ - - gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */ - - inb(u_Status); /* Touch the status register */ - - gus_look8(0x41); /* Clear any pending DMA IRQs */ - gus_look8(0x49); /* Clear any pending sample IRQs */ - - gus_read8(0x0f); /* Clear pending IRQs */ - - if (iw_mode) - gus_write8(0x19, gus_read8(0x19) | 0x01); - spin_unlock_irqrestore(&gus_lock,flags); -} - - -static void __init pnp_mem_init(void) -{ -#include "iwmem.h" -#define CHUNK_SIZE (256*1024) -#define BANK_SIZE (4*1024*1024) -#define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE) - - int bank, chunk, addr, total = 0; - int bank_sizes[4]; - int i, j, bits = -1, testbits = -1, nbanks = 0; - - /* - * This routine determines what kind of RAM is installed in each of the four - * SIMM banks and configures the DRAM address decode logic accordingly. - */ - - /* - * Place the chip into enhanced mode - */ - gus_write8(0x19, gus_read8(0x19) | 0x01); - gus_write8(0x53, gus_look8(0x53) & ~0x02); /* Select DRAM I/O access */ - - /* - * Set memory configuration to 4 DRAM banks of 4M in each (16M total). - */ - - gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c); - - /* - * Perform the DRAM size detection for each bank individually. - */ - for (bank = 0; bank < 4; bank++) - { - int size = 0; - - addr = bank * BANK_SIZE; - - /* Clean check points of each chunk */ - for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) - { - gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); - gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); - } - - /* Write a value to each chunk point and verify the result */ - for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) - { - gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55); - gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA); - - if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 && - gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA) - { - /* OK. There is RAM. Now check for possible shadows */ - int ok = 1, chunk2; - - for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) - if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) || - gus_peek(addr + chunk2 * CHUNK_SIZE + 1L)) - ok = 0; /* Addressing wraps */ - - if (ok) - size = (chunk + 1) * CHUNK_SIZE; - } - gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); - gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); - } - bank_sizes[bank] = size; - if (size) - nbanks = bank + 1; - DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); - } - - if (nbanks == 0) /* No RAM - Give up */ - { - printk(KERN_ERR "Sound: An Interwave audio chip detected but no DRAM\n"); - printk(KERN_ERR "Sound: Unable to work with this card.\n"); - gus_write8(0x19, gus_read8(0x19) & ~0x01); - gus_mem_size = 0; - return; - } - - /* - * Now we know how much DRAM there is in each bank. The next step is - * to find a DRAM size encoding (0 to 12) which is best for the combination - * we have. - * - * First try if any of the possible alternatives matches exactly the amount - * of memory we have. - */ - - for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; - - for (j = 0; bits != -1 && j < 4; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - } - - /* - * If necessary, try to find a combination where other than the last - * bank matches our configuration and the last bank is left oversized. - * In this way we don't leave holes in the middle of memory. - */ - - if (bits == -1) /* No luck yet */ - { - for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; - - for (j = 0; bits != -1 && j < nbanks - 1; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) - bits = -1; /* The last bank is too small */ - } - } - /* - * The last resort is to search for a combination where the banks are - * smaller than the actual SIMMs. This leaves some memory in the banks - * unused but doesn't leave holes in the DRAM address space. - */ - if (bits == -1) /* No luck yet */ - { - for (i = 0; i < 13; i++) - { - testbits = i; - for (j = 0; testbits != -1 && j < nbanks - 1; j++) - if (mem_decode[i][j] > bank_sizes[j]) { - testbits = -1; - } - if(testbits > bits) bits = testbits; - } - if (bits != -1) - { - printk(KERN_INFO "Interwave: Can't use all installed RAM.\n"); - printk(KERN_INFO "Interwave: Try reordering SIMMS.\n"); - } - printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n"); - printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); - bits = 0; - } - DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits)); - - for (bank = 0; bank < 4; bank++) - { - DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024)); - - if (bank_sizes[bank] > mem_decode[bits][bank]) - total += mem_decode[bits][bank]; - else - total += bank_sizes[bank]; - } - - DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024)); - - /* - * Set the memory addressing mode. - */ - gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits); - -/* Leave the chip into enhanced mode. Disable LFO */ - gus_mem_size = total; - iw_mode = 1; - gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02); -} - -int __init gus_wave_detect(int baseaddr) -{ - unsigned long i, max_mem = 1024L; - unsigned long loc; - unsigned char val; - - if (!request_region(baseaddr, 16, "GUS")) - return 0; - if (!request_region(baseaddr + 0x100, 12, "GUS")) { /* 0x10c-> is MAX */ - release_region(baseaddr, 16); - return 0; - } - - gus_base = baseaddr; - - gus_write8(0x4c, 0); /* Reset GF1 */ - gus_delay(); - gus_delay(); - - gus_write8(0x4c, 1); /* Release Reset */ - gus_delay(); - gus_delay(); - -#ifdef GUSPNP_AUTODETECT - val = gus_look8(0x5b); /* Version number register */ - gus_write8(0x5b, ~val); /* Invert all bits */ - - if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0)) /* No change */ - { - if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */ - { - DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); - gus_pnp_flag = 1; - } - else - { - DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b))); - gus_pnp_flag = 0; - } - } - gus_write8(0x5b, val); /* Restore all bits */ -#endif - - if (gus_pnp_flag) - pnp_mem_init(); - if (iw_mode) - return 1; - - /* See if there is first block there.... */ - gus_poke(0L, 0xaa); - if (gus_peek(0L) != 0xaa) { - release_region(baseaddr + 0x100, 12); - release_region(baseaddr, 16); - return 0; - } - - /* Now zero it out so that I can check for mirroring .. */ - gus_poke(0L, 0x00); - for (i = 1L; i < max_mem; i++) - { - int n, failed; - - /* check for mirroring ... */ - if (gus_peek(0L) != 0) - break; - loc = i << 10; - - for (n = loc - 1, failed = 0; n <= loc; n++) - { - gus_poke(loc, 0xaa); - if (gus_peek(loc) != 0xaa) - failed = 1; - gus_poke(loc, 0x55); - if (gus_peek(loc) != 0x55) - failed = 1; - } - if (failed) - break; - } - gus_mem_size = i << 10; - return 1; -} - -static int guswave_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - - switch (cmd) - { - case SNDCTL_SYNTH_INFO: - gus_info.nr_voices = nr_voices; - if (copy_to_user(arg, &gus_info, sizeof(gus_info))) - return -EFAULT; - return 0; - - case SNDCTL_SEQ_RESETSAMPLES: - reset_sample_memory(); - return 0; - - case SNDCTL_SEQ_PERCMODE: - return 0; - - case SNDCTL_SYNTH_MEMAVL: - return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32; - - default: - return -EINVAL; - } -} - -static int guswave_set_instr(int dev, int voice, int instr_no) -{ - int sample_no; - - if (instr_no < 0 || instr_no > MAX_PATCH) - instr_no = 0; /* Default to acoustic piano */ - - if (voice < 0 || voice > 31) - return -EINVAL; - - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].sample_pending = instr_no; - return 0; - } - sample_no = patch_table[instr_no]; - patch_map[voice] = -1; - - if (sample_no == NOT_SAMPLE) - { -/* printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice);*/ - return -EINVAL; /* Patch not defined */ - } - if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ - { -/* printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);*/ - return -EINVAL; - } - sample_map[voice] = sample_no; - patch_map[voice] = instr_no; - return 0; -} - -static int guswave_kill_note(int dev, int voice, int note, int velocity) -{ - unsigned long flags; - - spin_lock_irqsave(&gus_lock,flags); - /* voice_alloc->map[voice] = 0xffff; */ - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].kill_pending = 1; - spin_unlock_irqrestore(&gus_lock,flags); - } - else - { - spin_unlock_irqrestore(&gus_lock,flags); - gus_voice_fade(voice); - } - - return 0; -} - -static void guswave_aftertouch(int dev, int voice, int pressure) -{ -} - -static void guswave_panning(int dev, int voice, int value) -{ - if (voice >= 0 || voice < 32) - voices[voice].panning = value; -} - -static void guswave_volume_method(int dev, int mode) -{ - if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) - volume_method = mode; -} - -static void compute_volume(int voice, int volume) -{ - if (volume < 128) - voices[voice].midi_volume = volume; - - switch (volume_method) - { - case VOL_METHOD_ADAGIO: - voices[voice].initial_volume = - gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol, - voices[voice].expression_vol, - voices[voice].patch_vol); - break; - - case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ - voices[voice].initial_volume = gus_linear_vol(volume, voices[voice].main_vol); - break; - - default: - voices[voice].initial_volume = volume_base + - (voices[voice].midi_volume * volume_scale); - } - - if (voices[voice].initial_volume > 4030) - voices[voice].initial_volume = 4030; -} - -static void compute_and_set_volume(int voice, int volume, int ramp_time) -{ - int curr, target, rate; - unsigned long flags; - - compute_volume(voice, volume); - voices[voice].current_volume = voices[voice].initial_volume; - - spin_lock_irqsave(&gus_lock,flags); - /* - * CAUTION! Interrupts disabled. Enable them before returning - */ - - gus_select_voice(voice); - - curr = gus_read16(0x09) >> 4; - target = voices[voice].initial_volume; - - if (ramp_time == INSTANT_RAMP) - { - gus_rampoff(); - gus_voice_volume(target); - spin_unlock_irqrestore(&gus_lock,flags); - return; - } - if (ramp_time == FAST_RAMP) - rate = 63; - else - rate = 16; - gus_ramp_rate(0, rate); - - if ((target - curr) / 64 == 0) /* Close enough to target. */ - { - gus_rampoff(); - gus_voice_volume(target); - spin_unlock_irqrestore(&gus_lock,flags); - return; - } - if (target > curr) - { - if (target > (4095 - 65)) - target = 4095 - 65; - gus_ramp_range(curr, target); - gus_rampon(0x00); /* Ramp up, once, no IRQ */ - } - else - { - if (target < 65) - target = 65; - - gus_ramp_range(target, curr); - gus_rampon(0x40); /* Ramp down, once, no irq */ - } - spin_unlock_irqrestore(&gus_lock,flags); -} - -static void dynamic_volume_change(int voice) -{ - unsigned char status; - unsigned long flags; - - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - status = gus_read8(0x00); /* Get voice status */ - spin_unlock_irqrestore(&gus_lock,flags); - - if (status & 0x03) - return; /* Voice was not running */ - - if (!(voices[voice].mode & WAVE_ENVELOPES)) - { - compute_and_set_volume(voice, voices[voice].midi_volume, 1); - return; - } - - /* - * Voice is running and has envelopes. - */ - - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - status = gus_read8(0x0d); /* Ramping status */ - spin_unlock_irqrestore(&gus_lock,flags); - - if (status & 0x03) /* Sustain phase? */ - { - compute_and_set_volume(voice, voices[voice].midi_volume, 1); - return; - } - if (voices[voice].env_phase < 0) - return; - - compute_volume(voice, voices[voice].midi_volume); - -} - -static void guswave_controller(int dev, int voice, int ctrl_num, int value) -{ - unsigned long flags; - unsigned long freq; - - if (voice < 0 || voice > 31) - return; - - switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - voices[voice].bender = value; - - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - { - freq = compute_finetune(voices[voice].orig_freq, value, voices[voice].bender_range, 0); - voices[voice].current_freq = freq; - - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_voice_freq(freq); - spin_unlock_irqrestore(&gus_lock,flags); - } - break; - - case CTRL_PITCH_BENDER_RANGE: - voices[voice].bender_range = value; - break; - case CTL_EXPRESSION: - value /= 128; - case CTRL_EXPRESSION: - if (volume_method == VOL_METHOD_ADAGIO) - { - voices[voice].expression_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change(voice); - } - break; - - case CTL_PAN: - voices[voice].panning = (value * 2) - 128; - break; - - case CTL_MAIN_VOLUME: - value = (value * 100) / 16383; - - case CTRL_MAIN_VOLUME: - voices[voice].main_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change(voice); - break; - - default: - break; - } -} - -static int guswave_start_note2(int dev, int voice, int note_num, int volume) -{ - int sample, best_sample, best_delta, delta_freq; - int is16bits, samplep, patch, pan; - unsigned long note_freq, base_note, freq, flags; - unsigned char mode = 0; - - if (voice < 0 || voice > 31) - { -/* printk("GUS: Invalid voice\n");*/ - return -EINVAL; - } - if (note_num == 255) - { - if (voices[voice].mode & WAVE_ENVELOPES) - { - voices[voice].midi_volume = volume; - dynamic_volume_change(voice); - return 0; - } - compute_and_set_volume(voice, volume, 1); - return 0; - } - if ((patch = patch_map[voice]) == -1) - return -EINVAL; - if ((samplep = patch_table[patch]) == NOT_SAMPLE) - { - return -EINVAL; - } - note_freq = note_to_freq(note_num); - - /* - * Find a sample within a patch so that the note_freq is between low_note - * and high_note. - */ - sample = -1; - - best_sample = samplep; - best_delta = 1000000; - while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1) - { - delta_freq = note_freq - samples[samplep].base_note; - if (delta_freq < 0) - delta_freq = -delta_freq; - if (delta_freq < best_delta) - { - best_sample = samplep; - best_delta = delta_freq; - } - if (samples[samplep].low_note <= note_freq && - note_freq <= samples[samplep].high_note) - { - sample = samplep; - } - else - samplep = samples[samplep].key; /* Link to next sample */ - } - if (sample == -1) - sample = best_sample; - - if (sample == -1) - { -/* printk("GUS: Patch %d not defined for note %d\n", patch, note_num);*/ - return 0; /* Should play default patch ??? */ - } - is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; - voices[voice].mode = samples[sample].mode; - voices[voice].patch_vol = samples[sample].volume; - - if (iw_mode) - gus_write8(0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */ - - if (voices[voice].mode & WAVE_ENVELOPES) - { - int i; - - for (i = 0; i < 6; i++) - { - voices[voice].env_rate[i] = samples[sample].env_rate[i]; - voices[voice].env_offset[i] = samples[sample].env_offset[i]; - } - } - sample_map[voice] = sample; - - if (voices[voice].fixed_pitch) /* Fixed pitch */ - { - freq = samples[sample].base_freq; - } - else - { - base_note = samples[sample].base_note / 100; - note_freq /= 100; - - freq = samples[sample].base_freq * note_freq / base_note; - } - - voices[voice].orig_freq = freq; - - /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. - */ - - freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender, - voices[voice].bender_range, 0); - voices[voice].current_freq = freq; - - pan = (samples[sample].panning + voices[voice].panning) / 32; - pan += 7; - if (pan < 0) - pan = 0; - if (pan > 15) - pan = 15; - - if (samples[sample].mode & WAVE_16_BITS) - { - mode |= 0x04; /* 16 bits */ - if ((sample_ptrs[sample] / GUS_BANK_SIZE) != - ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE)) - printk(KERN_ERR "GUS: Sample address error\n"); - } - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_voice_off(); - gus_rampoff(); - - spin_unlock_irqrestore(&gus_lock,flags); - - if (voices[voice].mode & WAVE_ENVELOPES) - { - compute_volume(voice, volume); - init_envelope(voice); - } - else - { - compute_and_set_volume(voice, volume, 0); - } - - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - - if (samples[sample].mode & WAVE_LOOP_BACK) - gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len - - voices[voice].offset_pending, 0, is16bits); /* start=end */ - else - gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, 0, is16bits); /* Sample start=begin */ - - if (samples[sample].mode & WAVE_LOOPING) - { - mode |= 0x08; - - if (samples[sample].mode & WAVE_BIDIR_LOOP) - mode |= 0x10; - - if (samples[sample].mode & WAVE_LOOP_BACK) - { - gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].loop_end - - voices[voice].offset_pending, - (samples[sample].fractions >> 4) & 0x0f, is16bits); - mode |= 0x40; - } - gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start, - samples[sample].fractions & 0x0f, is16bits); /* Loop start location */ - gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end, - (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ - } - else - { - mode |= 0x20; /* Loop IRQ at the end */ - voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ - voices[voice].loop_irq_parm = 1; - gus_write_addr(0x02, sample_ptrs[sample], 0, is16bits); /* Loop start location */ - gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1, - (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ - } - gus_voice_freq(freq); - gus_voice_balance(pan); - gus_voice_on(mode); - spin_unlock_irqrestore(&gus_lock,flags); - - return 0; -} - -/* - * New guswave_start_note by Andrew J. Robinson attempts to minimize clicking - * when the note playing on the voice is changed. It uses volume - * ramping. - */ - -static int guswave_start_note(int dev, int voice, int note_num, int volume) -{ - unsigned long flags; - int mode; - int ret_val = 0; - - spin_lock_irqsave(&gus_lock,flags); - if (note_num == 255) - { - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].volume_pending = volume; - } - else - { - ret_val = guswave_start_note2(dev, voice, note_num, volume); - } - } - else - { - gus_select_voice(voice); - mode = gus_read8(0x00); - if (mode & 0x20) - gus_write8(0x00, mode & 0xdf); /* No interrupt! */ - - voices[voice].offset_pending = 0; - voices[voice].kill_pending = 0; - voices[voice].volume_irq_mode = 0; - voices[voice].loop_irq_mode = 0; - - if (voices[voice].sample_pending >= 0) - { - spin_unlock_irqrestore(&gus_lock,flags); /* Run temporarily with interrupts enabled */ - guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending); - voices[voice].sample_pending = -1; - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); /* Reselect the voice (just to be sure) */ - } - if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065)) - { - ret_val = guswave_start_note2(dev, voice, note_num, volume); - } - else - { - voices[voice].dev_pending = dev; - voices[voice].note_pending = note_num; - voices[voice].volume_pending = volume; - voices[voice].volume_irq_mode = VMODE_START_NOTE; - - gus_rampoff(); - gus_ramp_range(2000, 4065); - gus_ramp_rate(0, 63); /* Fastest possible rate */ - gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */ - } - } - spin_unlock_irqrestore(&gus_lock,flags); - return ret_val; -} - -static void guswave_reset(int dev) -{ - int i; - - for (i = 0; i < 32; i++) - { - gus_voice_init(i); - gus_voice_init2(i); - } -} - -static int guswave_open(int dev, int mode) -{ - int err; - - if (gus_busy) - return -EBUSY; - - voice_alloc->timestamp = 0; - - if (gus_no_wave_dma) { - gus_no_dma = 1; - } else { - if ((err = DMAbuf_open_dma(gus_devnum)) < 0) - { - /* printk( "GUS: Loading samples without DMA\n"); */ - gus_no_dma = 1; /* Upload samples using PIO */ - } - else - gus_no_dma = 0; - } - - init_waitqueue_head(&dram_sleeper); - gus_busy = 1; - active_device = GUS_DEV_WAVE; - - gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */ - gus_initialize(); - gus_reset(); - gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */ - - return 0; -} - -static void guswave_close(int dev) -{ - gus_busy = 0; - active_device = 0; - gus_reset(); - - if (!gus_no_dma) - DMAbuf_close_dma(gus_devnum); -} - -static int guswave_load_patch(int dev, int format, const char __user *addr, - int offs, int count, int pmgr_flag) -{ - struct patch_info patch; - int instr; - long sizeof_patch; - - unsigned long blk_sz, blk_end, left, src_offs, target; - - sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ - - if (format != GUS_PATCH) - { -/* printk("GUS Error: Invalid patch format (key) 0x%x\n", format);*/ - return -EINVAL; - } - if (count < sizeof_patch) - { -/* printk("GUS Error: Patch header too short\n");*/ - return -EINVAL; - } - count -= sizeof_patch; - - if (free_sample >= MAX_SAMPLE) - { -/* printk("GUS: Sample table full\n");*/ - return -ENOSPC; - } - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - if (copy_from_user(&((char *) &patch)[offs], &(addr)[offs], - sizeof_patch - offs)) - return -EFAULT; - - if (patch.mode & WAVE_ROM) - return -EINVAL; - if (gus_mem_size == 0) - return -ENOSPC; - - instr = patch.instr_no; - - if (instr < 0 || instr > MAX_PATCH) - { -/* printk(KERN_ERR "GUS: Invalid patch number %d\n", instr);*/ - return -EINVAL; - } - if (count < patch.len) - { -/* printk(KERN_ERR "GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len);*/ - patch.len = count; - } - if (patch.len <= 0 || patch.len > gus_mem_size) - { -/* printk(KERN_ERR "GUS: Invalid sample length %d\n", (int) patch.len);*/ - return -EINVAL; - } - if (patch.mode & WAVE_LOOPING) - { - if (patch.loop_start < 0 || patch.loop_start >= patch.len) - { -/* printk(KERN_ERR "GUS: Invalid loop start\n");*/ - return -EINVAL; - } - if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) - { -/* printk(KERN_ERR "GUS: Invalid loop end\n");*/ - return -EINVAL; - } - } - free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ - - if (patch.mode & WAVE_16_BITS) - { - /* - * 16 bit samples must fit one 256k bank. - */ - if (patch.len >= GUS_BANK_SIZE) - { -/* printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len);*/ - return -ENOSPC; - } - if ((free_mem_ptr / GUS_BANK_SIZE) != - ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) - { - unsigned long tmp_mem = - /* Align to 256K */ - ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; - - if ((tmp_mem + patch.len) > gus_mem_size) - return -ENOSPC; - - free_mem_ptr = tmp_mem; /* This leaves unusable memory */ - } - } - if ((free_mem_ptr + patch.len) > gus_mem_size) - return -ENOSPC; - - sample_ptrs[free_sample] = free_mem_ptr; - - /* - * Tremolo is not possible with envelopes - */ - - if (patch.mode & WAVE_ENVELOPES) - patch.mode &= ~WAVE_TREMOLO; - - if (!(patch.mode & WAVE_FRACTIONS)) - { - patch.fractions = 0; - } - memcpy((char *) &samples[free_sample], &patch, sizeof_patch); - - /* - * Link this_one sample to the list of samples for patch 'instr'. - */ - - samples[free_sample].key = patch_table[instr]; - patch_table[instr] = free_sample; - - /* - * Use DMA to transfer the wave data to the DRAM - */ - - left = patch.len; - src_offs = 0; - target = free_mem_ptr; - - while (left) /* Not completely transferred yet */ - { - blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; - if (blk_sz > left) - blk_sz = left; - - /* - * DMA cannot cross bank (256k) boundaries. Check for that. - */ - - blk_end = target + blk_sz; - - if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE)) - { - /* Split the block */ - blk_end &= ~(GUS_BANK_SIZE - 1); - blk_sz = blk_end - target; - } - if (gus_no_dma) - { - /* - * For some reason the DMA is not possible. We have to use PIO. - */ - long i; - unsigned char data; - - for (i = 0; i < blk_sz; i++) - { - get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[sizeof_patch + i])); - if (patch.mode & WAVE_UNSIGNED) - if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) - data ^= 0x80; /* Convert to signed */ - gus_poke(target + i, data); - } - } - else - { - unsigned long address, hold_address; - unsigned char dma_command; - unsigned long flags; - - if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) - { - printk(KERN_ERR "GUS: DMA buffer == NULL\n"); - return -ENOSPC; - } - /* - * OK, move now. First in and then out. - */ - - if (copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf, - &(addr)[sizeof_patch + src_offs], - blk_sz)) - return -EFAULT; - - spin_lock_irqsave(&gus_lock,flags); - gus_write8(0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys, - blk_sz, DMA_MODE_WRITE); - - /* - * Set the DRAM address for the wave data - */ - - if (iw_mode) - { - /* Different address translation in enhanced mode */ - - unsigned char hi; - - if (gus_dma > 4) - address = target >> 1; /* Convert to 16 bit word address */ - else - address = target; - - hi = (unsigned char) ((address >> 16) & 0xf0); - hi += (unsigned char) (address & 0x0f); - - gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */ - gus_write8(0x50, hi); - } - else - { - address = target; - if (audio_devs[gus_devnum]->dmap_out->dma > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - } - - /* - * Start the DMA transfer - */ - - dma_command = 0x21; /* IRQ enable, DMA start */ - if (patch.mode & WAVE_UNSIGNED) - dma_command |= 0x80; /* Invert MSB */ - if (patch.mode & WAVE_16_BITS) - dma_command |= 0x40; /* 16 bit _DATA_ */ - if (audio_devs[gus_devnum]->dmap_out->dma > 3) - dma_command |= 0x04; /* 16 bit DMA _channel_ */ - - /* - * Sleep here until the DRAM DMA done interrupt is served - */ - active_device = GUS_DEV_WAVE; - gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */ - - spin_unlock_irqrestore(&gus_lock,flags); /* opens a race */ - if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ)) - printk("GUS: DMA Transfer timed out\n"); - } - - /* - * Now the next part - */ - - left -= blk_sz; - src_offs += blk_sz; - target += blk_sz; - - gus_write8(0x41, 0); /* Stop DMA */ - } - - free_mem_ptr += patch.len; - free_sample++; - return 0; -} - -static void guswave_hw_control(int dev, unsigned char *event_rec) -{ - int voice, cmd; - unsigned short p1, p2; - unsigned int plong; - unsigned long flags; - - cmd = event_rec[2]; - voice = event_rec[3]; - p1 = *(unsigned short *) &event_rec[4]; - p2 = *(unsigned short *) &event_rec[6]; - plong = *(unsigned int *) &event_rec[4]; - - if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && - (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) - do_volume_irq(voice); - - switch (cmd) - { - case _GUS_NUMVOICES: - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_select_max_voices(p1); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_VOICESAMPLE: - guswave_set_instr(dev, voice, p1); - break; - - case _GUS_VOICEON: - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_on(p1); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_VOICEOFF: - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_voice_off(); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_VOICEFADE: - gus_voice_fade(voice); - break; - - case _GUS_VOICEMODE: - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_mode(p1); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_VOICEBALA: - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_voice_balance(p1); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_VOICEFREQ: - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_voice_freq(plong); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_VOICEVOL: - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_voice_volume(p1); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_VOICEVOL2: /* Just update the software voice level */ - voices[voice].initial_volume = voices[voice].current_volume = p1; - break; - - case _GUS_RAMPRANGE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_ramp_range(p1, p2); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_RAMPRATE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NJET-NJET */ - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_ramp_rate(p1, p2); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_RAMPMODE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_ramp_mode(p1); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_RAMPON: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* EI-EI */ - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_rampon(p1); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_RAMPOFF: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NEJ-NEJ */ - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_rampoff(); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - case _GUS_VOLUME_SCALE: - volume_base = p1; - volume_scale = p2; - break; - - case _GUS_VOICE_POS: - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_set_voice_pos(voice, plong); - spin_unlock_irqrestore(&gus_lock,flags); - break; - - default: - break; - } -} - -static int gus_audio_set_speed(int speed) -{ - if (speed <= 0) - speed = gus_audio_speed; - - if (speed < 4000) - speed = 4000; - - if (speed > 44100) - speed = 44100; - - gus_audio_speed = speed; - - if (only_read_access) - { - /* Compute nearest valid recording speed and return it */ - - /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ - speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; - speed = (9878400 / (speed * 16)) - 2; - } - return speed; -} - -static int gus_audio_set_channels(int channels) -{ - if (!channels) - return gus_audio_channels; - if (channels > 2) - channels = 2; - if (channels < 1) - channels = 1; - gus_audio_channels = channels; - return channels; -} - -static int gus_audio_set_bits(int bits) -{ - if (!bits) - return gus_audio_bits; - - if (bits != 8 && bits != 16) - bits = 8; - - if (only_8_bits) - bits = 8; - - gus_audio_bits = bits; - return bits; -} - -static int gus_audio_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int val; - - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (get_user(val, (int __user*)arg)) - return -EFAULT; - val = gus_audio_set_speed(val); - break; - - case SOUND_PCM_READ_RATE: - val = gus_audio_speed; - break; - - case SNDCTL_DSP_STEREO: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = gus_audio_set_channels(val + 1) - 1; - break; - - case SOUND_PCM_WRITE_CHANNELS: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = gus_audio_set_channels(val); - break; - - case SOUND_PCM_READ_CHANNELS: - val = gus_audio_channels; - break; - - case SNDCTL_DSP_SETFMT: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = gus_audio_set_bits(val); - break; - - case SOUND_PCM_READ_BITS: - val = gus_audio_bits; - break; - - case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ - case SOUND_PCM_READ_FILTER: - val = -EINVAL; - break; - default: - return -EINVAL; - } - return put_user(val, (int __user *)arg); -} - -static void gus_audio_reset(int dev) -{ - if (recording_active) - { - gus_write8(0x49, 0x00); /* Halt recording */ - set_input_volumes(); - } -} - -static int saved_iw_mode; /* A hack hack hack */ - -static int gus_audio_open(int dev, int mode) -{ - if (gus_busy) - return -EBUSY; - - if (gus_pnp_flag && mode & OPEN_READ) - { -/* printk(KERN_ERR "GUS: Audio device #%d is playback only.\n", dev);*/ - return -EIO; - } - gus_initialize(); - - gus_busy = 1; - active_device = 0; - - saved_iw_mode = iw_mode; - if (iw_mode) - { - /* There are some problems with audio in enhanced mode so disable it */ - gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */ - iw_mode = 0; - } - - gus_reset(); - reset_sample_memory(); - gus_select_max_voices(14); - - pcm_active = 0; - dma_active = 0; - pcm_opened = 1; - if (mode & OPEN_READ) - { - recording_active = 1; - set_input_volumes(); - } - only_read_access = !(mode & OPEN_WRITE); - only_8_bits = mode & OPEN_READ; - if (only_8_bits) - audio_devs[dev]->format_mask = AFMT_U8; - else - audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE; - - return 0; -} - -static void gus_audio_close(int dev) -{ - iw_mode = saved_iw_mode; - gus_reset(); - gus_busy = 0; - pcm_opened = 0; - active_device = 0; - - if (recording_active) - { - gus_write8(0x49, 0x00); /* Halt recording */ - set_input_volumes(); - } - recording_active = 0; -} - -static void gus_audio_update_volume(void) -{ - unsigned long flags; - int voice; - - if (pcm_active && pcm_opened) - for (voice = 0; voice < gus_audio_channels; voice++) - { - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_rampoff(); - gus_voice_volume(1530 + (25 * gus_pcm_volume)); - gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); - spin_unlock_irqrestore(&gus_lock,flags); - } -} - -static void play_next_pcm_block(void) -{ - unsigned long flags; - int speed = gus_audio_speed; - int this_one, is16bits, chn; - unsigned long dram_loc; - unsigned char mode[2], ramp_mode[2]; - - if (!pcm_qlen) - return; - - this_one = pcm_head; - - for (chn = 0; chn < gus_audio_channels; chn++) - { - mode[chn] = 0x00; - ramp_mode[chn] = 0x03; /* Ramping and rollover off */ - - if (chn == 0) - { - mode[chn] |= 0x20; /* Loop IRQ */ - voices[chn].loop_irq_mode = LMODE_PCM; - } - if (gus_audio_bits != 8) - { - is16bits = 1; - mode[chn] |= 0x04; /* 16 bit data */ - } - else - is16bits = 0; - - dram_loc = this_one * pcm_bsize; - dram_loc += chn * pcm_banksize; - - if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ - { - mode[chn] |= 0x08; /* Enable loop */ - ramp_mode[chn] = 0x03; /* Disable rollover bit */ - } - else - { - if (chn == 0) - ramp_mode[chn] = 0x04; /* Enable rollover bit */ - } - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(chn); - gus_voice_freq(speed); - - if (gus_audio_channels == 1) - gus_voice_balance(7); /* mono */ - else if (chn == 0) - gus_voice_balance(0); /* left */ - else - gus_voice_balance(15); /* right */ - - if (!pcm_active) /* Playback not already active */ - { - /* - * The playback was not started yet (or there has been a pause). - * Start the voice (again) and ask for a rollover irq at the end of - * this_one block. If this_one one is last of the buffers, use just - * the normal loop with irq. - */ - - gus_voice_off(); - gus_rampoff(); - gus_voice_volume(1530 + (25 * gus_pcm_volume)); - gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); - - gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ - gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ - - if (chn != 0) - gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, - 0, is16bits); /* Loop end location */ - } - if (chn == 0) - gus_write_addr(0x04, dram_loc + pcm_bsize - 1, - 0, is16bits); /* Loop end location */ - else - mode[chn] |= 0x08; /* Enable looping */ - spin_unlock_irqrestore(&gus_lock,flags); - } - for (chn = 0; chn < gus_audio_channels; chn++) - { - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(chn); - gus_write8(0x0d, ramp_mode[chn]); - if (iw_mode) - gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */ - gus_voice_on(mode[chn]); - spin_unlock_irqrestore(&gus_lock,flags); - } - pcm_active = 1; -} - -static void gus_transfer_output_block(int dev, unsigned long buf, - int total_count, int intrflag, int chn) -{ - /* - * This routine transfers one block of audio data to the DRAM. In mono mode - * it's called just once. When in stereo mode, this_one routine is called - * once for both channels. - * - * The left/mono channel data is transferred to the beginning of dram and the - * right data to the area pointed by gus_page_size. - */ - - int this_one, count; - unsigned long flags; - unsigned char dma_command; - unsigned long address, hold_address; - - spin_lock_irqsave(&gus_lock,flags); - - count = total_count / gus_audio_channels; - - if (chn == 0) - { - if (pcm_qlen >= pcm_nblk) - printk(KERN_WARNING "GUS Warning: PCM buffers out of sync\n"); - - this_one = pcm_current_block = pcm_tail; - pcm_qlen++; - pcm_tail = (pcm_tail + 1) % pcm_nblk; - pcm_datasize[this_one] = count; - } - else - this_one = pcm_current_block; - - gus_write8(0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma(dev, buf + (chn * count), count, DMA_MODE_WRITE); - - address = this_one * pcm_bsize; - address += chn * pcm_banksize; - - if (audio_devs[dev]->dmap_out->dma > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - - dma_command = 0x21; /* IRQ enable, DMA start */ - - if (gus_audio_bits != 8) - dma_command |= 0x40; /* 16 bit _DATA_ */ - else - dma_command |= 0x80; /* Invert MSB */ - - if (audio_devs[dev]->dmap_out->dma > 3) - dma_command |= 0x04; /* 16 bit DMA channel */ - - gus_write8(0x41, dma_command); /* Kick start */ - - if (chn == (gus_audio_channels - 1)) /* Last channel */ - { - /* - * Last (right or mono) channel data - */ - dma_active = 1; /* DMA started. There is a unacknowledged buffer */ - active_device = GUS_DEV_PCM_DONE; - if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize)) - { - play_next_pcm_block(); - } - } - else - { - /* - * Left channel data. The right channel - * is transferred after DMA interrupt - */ - active_device = GUS_DEV_PCM_CONTINUE; - } - - spin_unlock_irqrestore(&gus_lock,flags); -} - -static void gus_uninterleave8(char *buf, int l) -{ -/* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */ - int i, p = 0, halfsize = l / 2; - char *buf2 = buf + halfsize, *src = bounce_buf; - - memcpy(bounce_buf, buf, l); - - for (i = 0; i < halfsize; i++) - { - buf[i] = src[p++]; /* Left channel */ - buf2[i] = src[p++]; /* Right channel */ - } -} - -static void gus_uninterleave16(short *buf, int l) -{ -/* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */ - int i, p = 0, halfsize = l / 2; - short *buf2 = buf + halfsize, *src = (short *) bounce_buf; - - memcpy(bounce_buf, (char *) buf, l * 2); - - for (i = 0; i < halfsize; i++) - { - buf[i] = src[p++]; /* Left channel */ - buf2[i] = src[p++]; /* Right channel */ - } -} - -static void gus_audio_output_block(int dev, unsigned long buf, int total_count, - int intrflag) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT; - - pcm_current_buf = buf; - pcm_current_count = total_count; - pcm_current_intrflag = intrflag; - pcm_current_dev = dev; - if (gus_audio_channels == 2) - { - char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); - - if (gus_audio_bits == 8) - gus_uninterleave8(b, total_count); - else - gus_uninterleave16((short *) b, total_count / 2); - } - gus_transfer_output_block(dev, buf, total_count, intrflag, 0); -} - -static void gus_audio_start_input(int dev, unsigned long buf, int count, - int intrflag) -{ - unsigned long flags; - unsigned char mode; - - spin_lock_irqsave(&gus_lock,flags); - - DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ); - mode = 0xa0; /* DMA IRQ enabled, invert MSB */ - - if (audio_devs[dev]->dmap_in->dma > 3) - mode |= 0x04; /* 16 bit DMA channel */ - if (gus_audio_channels > 1) - mode |= 0x02; /* Stereo */ - mode |= 0x01; /* DMA enable */ - - gus_write8(0x49, mode); - spin_unlock_irqrestore(&gus_lock,flags); -} - -static int gus_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - unsigned int rate; - - gus_audio_bsize = bsize; - audio_devs[dev]->dmap_in->flags |= DMA_NODMA; - rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; - - gus_write8(0x48, rate & 0xff); /* Set sampling rate */ - - if (gus_audio_bits != 8) - { -/* printk("GUS Error: 16 bit recording not supported\n");*/ - return -EINVAL; - } - return 0; -} - -static int gus_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - int i; - - long mem_ptr, mem_size; - - audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT; - mem_ptr = 0; - mem_size = gus_mem_size / gus_audio_channels; - - if (mem_size > (256 * 1024)) - mem_size = 256 * 1024; - - pcm_bsize = bsize / gus_audio_channels; - pcm_head = pcm_tail = pcm_qlen = 0; - - pcm_nblk = 2; /* MAX_PCM_BUFFERS; */ - if ((pcm_bsize * pcm_nblk) > mem_size) - pcm_nblk = mem_size / pcm_bsize; - - for (i = 0; i < pcm_nblk; i++) - pcm_datasize[i] = 0; - - pcm_banksize = pcm_nblk * pcm_bsize; - - if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024)) - pcm_nblk--; - gus_write8(0x41, 0); /* Disable GF1 DMA */ - return 0; -} - -static int gus_local_qlen(int dev) -{ - return pcm_qlen; -} - - -static struct audio_driver gus_audio_driver = -{ - .owner = THIS_MODULE, - .open = gus_audio_open, - .close = gus_audio_close, - .output_block = gus_audio_output_block, - .start_input = gus_audio_start_input, - .ioctl = gus_audio_ioctl, - .prepare_for_input = gus_audio_prepare_for_input, - .prepare_for_output = gus_audio_prepare_for_output, - .halt_io = gus_audio_reset, - .local_qlen = gus_local_qlen, -}; - -static void guswave_setup_voice(int dev, int voice, int chn) -{ - struct channel_info *info = &synth_devs[dev]->chn_info[chn]; - - guswave_set_instr(dev, voice, info->pgm_num); - voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just MSB */ - voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; - voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; - voices[voice].bender = 0; - voices[voice].bender_range = info->bender_range; - - if (chn == 9) - voices[voice].fixed_pitch = 1; -} - -static void guswave_bender(int dev, int voice, int value) -{ - int freq; - unsigned long flags; - - voices[voice].bender = value - 8192; - freq = compute_finetune(voices[voice].orig_freq, value - 8192, voices[voice].bender_range, 0); - voices[voice].current_freq = freq; - - spin_lock_irqsave(&gus_lock,flags); - gus_select_voice(voice); - gus_voice_freq(freq); - spin_unlock_irqrestore(&gus_lock,flags); -} - -static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) -{ - int i, p, best = -1, best_time = 0x7fffffff; - - p = alloc->ptr; - /* - * First look for a completely stopped voice - */ - - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0) - { - alloc->ptr = p; - return p; - } - if (alloc->alloc_times[p] < best_time) - { - best = p; - best_time = alloc->alloc_times[p]; - } - p = (p + 1) % alloc->max_voice; - } - - /* - * Then look for a releasing voice - */ - - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0xffff) - { - alloc->ptr = p; - return p; - } - p = (p + 1) % alloc->max_voice; - } - if (best >= 0) - p = best; - - alloc->ptr = p; - return p; -} - -static struct synth_operations guswave_operations = -{ - .owner = THIS_MODULE, - .id = "GUS", - .info = &gus_info, - .midi_dev = 0, - .synth_type = SYNTH_TYPE_SAMPLE, - .synth_subtype = SAMPLE_TYPE_GUS, - .open = guswave_open, - .close = guswave_close, - .ioctl = guswave_ioctl, - .kill_note = guswave_kill_note, - .start_note = guswave_start_note, - .set_instr = guswave_set_instr, - .reset = guswave_reset, - .hw_control = guswave_hw_control, - .load_patch = guswave_load_patch, - .aftertouch = guswave_aftertouch, - .controller = guswave_controller, - .panning = guswave_panning, - .volume_method = guswave_volume_method, - .bender = guswave_bender, - .alloc_voice = guswave_alloc, - .setup_voice = guswave_setup_voice -}; - -static void set_input_volumes(void) -{ - unsigned long flags; - unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ - - if (have_gus_max) /* Don't disturb GUS MAX */ - return; - - spin_lock_irqsave(&gus_lock,flags); - - /* - * Enable channels having vol > 10% - * Note! bit 0x01 means the line in DISABLED while 0x04 means - * the mic in ENABLED. - */ - if (gus_line_vol > 10) - mask &= ~0x01; - if (gus_mic_vol > 10) - mask |= 0x04; - - if (recording_active) - { - /* - * Disable channel, if not selected for recording - */ - if (!(gus_recmask & SOUND_MASK_LINE)) - mask |= 0x01; - if (!(gus_recmask & SOUND_MASK_MIC)) - mask &= ~0x04; - } - mix_image &= ~0x07; - mix_image |= mask & 0x07; - outb((mix_image), u_Mixer); - - spin_unlock_irqrestore(&gus_lock,flags); -} - -#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ - SOUND_MASK_SYNTH|SOUND_MASK_PCM) - -int gus_default_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int vol, val; - - if (((cmd >> 8) & 0xff) != 'M') - return -EINVAL; - - if (!access_ok(VERIFY_WRITE, arg, sizeof(int))) - return -EFAULT; - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - { - if (__get_user(val, (int __user *) arg)) - return -EFAULT; - - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - gus_recmask = val & MIX_DEVS; - if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) - gus_recmask = SOUND_MASK_MIC; - /* Note! Input volumes are updated during next open for recording */ - val = gus_recmask; - break; - - case SOUND_MIXER_MIC: - vol = val & 0xff; - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_mic_vol = vol; - set_input_volumes(); - val = vol | (vol << 8); - break; - - case SOUND_MIXER_LINE: - vol = val & 0xff; - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_line_vol = vol; - set_input_volumes(); - val = vol | (vol << 8); - break; - - case SOUND_MIXER_PCM: - gus_pcm_volume = val & 0xff; - if (gus_pcm_volume < 0) - gus_pcm_volume = 0; - if (gus_pcm_volume > 100) - gus_pcm_volume = 100; - gus_audio_update_volume(); - val = gus_pcm_volume | (gus_pcm_volume << 8); - break; - - case SOUND_MIXER_SYNTH: - gus_wave_volume = val & 0xff; - if (gus_wave_volume < 0) - gus_wave_volume = 0; - if (gus_wave_volume > 100) - gus_wave_volume = 100; - if (active_device == GUS_DEV_WAVE) - { - int voice; - for (voice = 0; voice < nr_voices; voice++) - dynamic_volume_change(voice); /* Apply the new vol */ - } - val = gus_wave_volume | (gus_wave_volume << 8); - break; - - default: - return -EINVAL; - } - } - else - { - switch (cmd & 0xff) - { - /* - * Return parameters - */ - case SOUND_MIXER_RECSRC: - val = gus_recmask; - break; - - case SOUND_MIXER_DEVMASK: - val = MIX_DEVS; - break; - - case SOUND_MIXER_STEREODEVS: - val = 0; - break; - - case SOUND_MIXER_RECMASK: - val = SOUND_MASK_MIC | SOUND_MASK_LINE; - break; - - case SOUND_MIXER_CAPS: - val = 0; - break; - - case SOUND_MIXER_MIC: - val = gus_mic_vol | (gus_mic_vol << 8); - break; - - case SOUND_MIXER_LINE: - val = gus_line_vol | (gus_line_vol << 8); - break; - - case SOUND_MIXER_PCM: - val = gus_pcm_volume | (gus_pcm_volume << 8); - break; - - case SOUND_MIXER_SYNTH: - val = gus_wave_volume | (gus_wave_volume << 8); - break; - - default: - return -EINVAL; - } - } - return __put_user(val, (int __user *)arg); -} - -static struct mixer_operations gus_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "GUS", - .name = "Gravis Ultrasound", - .ioctl = gus_default_mixer_ioctl -}; - -static int __init gus_default_mixer_init(void) -{ - int n; - - if ((n = sound_alloc_mixerdev()) != -1) - { - /* - * Don't install if there is another - * mixer - */ - mixer_devs[n] = &gus_mixer_operations; - } - if (have_gus_max) - { - /* - * Enable all mixer channels on the GF1 side. Otherwise recording will - * not be possible using GUS MAX. - */ - mix_image &= ~0x07; - mix_image |= 0x04; /* All channels enabled */ - outb((mix_image), u_Mixer); - } - return n; -} - -void __init gus_wave_init(struct address_info *hw_config) -{ - unsigned long flags; - unsigned char val; - char *model_num = "2.4"; - char tmp[64]; - int gus_type = 0x24; /* 2.4 */ - - int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2; - int sdev; - - hw_config->slots[0] = -1; /* No wave */ - hw_config->slots[1] = -1; /* No ad1848 */ - hw_config->slots[4] = -1; /* No audio */ - hw_config->slots[5] = -1; /* No mixer */ - - if (!gus_pnp_flag) - { - if (irq < 0 || irq > 15) - { - printk(KERN_ERR "ERROR! Invalid IRQ#%d. GUS Disabled", irq); - return; - } - } - - if (dma < 0 || dma > 7 || dma == 4) - { - printk(KERN_ERR "ERROR! Invalid DMA#%d. GUS Disabled", dma); - return; - } - gus_irq = irq; - gus_dma = dma; - gus_dma2 = dma2; - gus_hw_config = hw_config; - - if (gus_dma2 == -1) - gus_dma2 = dma; - - /* - * Try to identify the GUS model. - * - * Versions < 3.6 don't have the digital ASIC. Try to probe it first. - */ - - spin_lock_irqsave(&gus_lock,flags); - outb((0x20), gus_base + 0x0f); - val = inb(gus_base + 0x0f); - spin_unlock_irqrestore(&gus_lock,flags); - - if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */ - { - int ad_flags = 0; - - if (gus_pnp_flag) - ad_flags = 0x12345678; /* Interwave "magic" */ - /* - * It has the digital ASIC so the card is at least v3.4. - * Next try to detect the true model. - */ - - if (gus_pnp_flag) /* Hack hack hack */ - val = 10; - else - val = inb(u_MixSelect); - - /* - * Value 255 means pre-3.7 which don't have mixer. - * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer. - * 10 and above is GUS MAX which has the CS4231 codec/mixer. - * - */ - - if (val == 255 || val < 5) - { - model_num = "3.4"; - gus_type = 0x34; - } - else if (val < 10) - { - model_num = "3.7"; - gus_type = 0x37; - mixer_type = ICS2101; - request_region(u_MixSelect, 1, "GUS mixer"); - } - else - { - struct resource *ports; - ports = request_region(gus_base + 0x10c, 4, "ad1848"); - model_num = "MAX"; - gus_type = 0x40; - mixer_type = CS4231; -#ifdef CONFIG_SOUND_GUSMAX - { - unsigned char max_config = 0x40; /* Codec enable */ - - if (gus_dma2 == -1) - gus_dma2 = gus_dma; - - if (gus_dma > 3) - max_config |= 0x10; /* 16 bit capture DMA */ - - if (gus_dma2 > 3) - max_config |= 0x20; /* 16 bit playback DMA */ - - max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ - - outb((max_config), gus_base + 0x106); /* UltraMax control */ - } - - if (!ports) - goto no_cs4231; - - if (ad1848_detect(ports, &ad_flags, hw_config->osp)) - { - char *name = "GUS MAX"; - int old_num_mixers = num_mixers; - - if (gus_pnp_flag) - name = "GUS PnP"; - - gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; - gus_wave_volume = 90; - have_gus_max = 1; - if (hw_config->name) - name = hw_config->name; - - hw_config->slots[1] = ad1848_init(name, ports, - -irq, gus_dma2, /* Playback DMA */ - gus_dma, /* Capture DMA */ - 1, /* Share DMA channels with GF1 */ - hw_config->osp, - THIS_MODULE); - - if (num_mixers > old_num_mixers) - { - /* GUS has it's own mixer map */ - AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH); - AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); - } - } - else { - release_region(gus_base + 0x10c, 4); - no_cs4231: - printk(KERN_WARNING "GUS: No CS4231 ??"); - } -#else - printk(KERN_ERR "GUS MAX found, but not compiled in\n"); -#endif - } - } - else - { - /* - * ASIC not detected so the card must be 2.2 or 2.4. - * There could still be the 16-bit/mixer daughter card. - */ - } - - if (hw_config->name) - snprintf(tmp, sizeof(tmp), "%s (%dk)", hw_config->name, - (int) gus_mem_size / 1024); - else if (gus_pnp_flag) - snprintf(tmp, sizeof(tmp), "Gravis UltraSound PnP (%dk)", - (int) gus_mem_size / 1024); - else - snprintf(tmp, sizeof(tmp), "Gravis UltraSound %s (%dk)", model_num, - (int) gus_mem_size / 1024); - - - samples = (struct patch_info *)vmalloc((MAX_SAMPLE + 1) * sizeof(*samples)); - if (samples == NULL) - { - printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n"); - return; - } - conf_printf(tmp, hw_config); - strlcpy(gus_info.name, tmp, sizeof(gus_info.name)); - - if ((sdev = sound_alloc_synthdev()) == -1) - printk(KERN_WARNING "gus_init: Too many synthesizers\n"); - else - { - voice_alloc = &guswave_operations.alloc; - if (iw_mode) - guswave_operations.id = "IWAVE"; - hw_config->slots[0] = sdev; - synth_devs[sdev] = &guswave_operations; - sequencer_init(); - gus_tmr_install(gus_base + 8); - } - - reset_sample_memory(); - - gus_initialize(); - - if ((gus_mem_size > 0) && !gus_no_wave_dma) - { - hw_config->slots[4] = -1; - if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION, - "Ultrasound", - &gus_audio_driver, - sizeof(struct audio_driver), - NEEDS_RESTART | - ((!iw_mode && dma2 != dma && dma2 != -1) ? - DMA_DUPLEX : 0), - AFMT_U8 | AFMT_S16_LE, - NULL, dma, dma2)) < 0) - { - return; - } - - hw_config->slots[4] = gus_devnum; - audio_devs[gus_devnum]->min_fragment = 9; /* 512k */ - audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */ - audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */ - audio_devs[gus_devnum]->flags |= DMA_HARDSTOP; - } - - /* - * Mixer dependent initialization. - */ - - switch (mixer_type) - { - case ICS2101: - gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; - gus_wave_volume = 90; - request_region(u_MixSelect, 1, "GUS mixer"); - hw_config->slots[5] = ics2101_mixer_init(); - audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */ - return; - - case CS4231: - /* Initialized elsewhere (ad1848.c) */ - default: - hw_config->slots[5] = gus_default_mixer_init(); - audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */ - return; - } -} - -void __exit gus_wave_unload(struct address_info *hw_config) -{ -#ifdef CONFIG_SOUND_GUSMAX - if (have_gus_max) - { - ad1848_unload(gus_base + 0x10c, - -gus_irq, - gus_dma2, /* Playback DMA */ - gus_dma, /* Capture DMA */ - 1); /* Share DMA channels with GF1 */ - } -#endif - - if (mixer_type == ICS2101) - { - release_region(u_MixSelect, 1); - } - if (hw_config->slots[0] != -1) - sound_unload_synthdev(hw_config->slots[0]); - if (hw_config->slots[1] != -1) - sound_unload_audiodev(hw_config->slots[1]); - if (hw_config->slots[2] != -1) - sound_unload_mididev(hw_config->slots[2]); - if (hw_config->slots[4] != -1) - sound_unload_audiodev(hw_config->slots[4]); - if (hw_config->slots[5] != -1) - sound_unload_mixerdev(hw_config->slots[5]); - - vfree(samples); - samples=NULL; -} -/* called in interrupt context */ -static void do_loop_irq(int voice) -{ - unsigned char tmp; - int mode, parm; - - spin_lock(&gus_lock); - gus_select_voice(voice); - - tmp = gus_read8(0x00); - tmp &= ~0x20; /* - * Disable wave IRQ for this_one voice - */ - gus_write8(0x00, tmp); - - if (tmp & 0x03) /* Voice stopped */ - voice_alloc->map[voice] = 0; - - mode = voices[voice].loop_irq_mode; - voices[voice].loop_irq_mode = 0; - parm = voices[voice].loop_irq_parm; - - switch (mode) - { - case LMODE_FINISH: /* - * Final loop finished, shoot volume down - */ - - if ((int) (gus_read16(0x09) >> 4) < 100) /* - * Get current volume - */ - { - gus_voice_off(); - gus_rampoff(); - gus_voice_init(voice); - break; - } - gus_ramp_range(65, 4065); - gus_ramp_rate(0, 63); /* - * Fastest possible rate - */ - gus_rampon(0x20 | 0x40); /* - * Ramp down, once, irq - */ - voices[voice].volume_irq_mode = VMODE_HALT; - break; - - case LMODE_PCM_STOP: - pcm_active = 0; /* Signal to the play_next_pcm_block routine */ - case LMODE_PCM: - { - pcm_qlen--; - pcm_head = (pcm_head + 1) % pcm_nblk; - if (pcm_qlen && pcm_active) - { - play_next_pcm_block(); - } - else - { - /* Underrun. Just stop the voice */ - gus_select_voice(0); /* Left channel */ - gus_voice_off(); - gus_rampoff(); - gus_select_voice(1); /* Right channel */ - gus_voice_off(); - gus_rampoff(); - pcm_active = 0; - } - - /* - * If the queue was full before this interrupt, the DMA transfer was - * suspended. Let it continue now. - */ - - if (audio_devs[gus_devnum]->dmap_out->qlen > 0) - DMAbuf_outputintr(gus_devnum, 0); - } - break; - - default: - break; - } - spin_unlock(&gus_lock); -} - -static void do_volume_irq(int voice) -{ - unsigned char tmp; - int mode, parm; - unsigned long flags; - - spin_lock_irqsave(&gus_lock,flags); - - gus_select_voice(voice); - tmp = gus_read8(0x0d); - tmp &= ~0x20; /* - * Disable volume ramp IRQ - */ - gus_write8(0x0d, tmp); - - mode = voices[voice].volume_irq_mode; - voices[voice].volume_irq_mode = 0; - parm = voices[voice].volume_irq_parm; - - switch (mode) - { - case VMODE_HALT: /* Decay phase finished */ - if (iw_mode) - gus_write8(0x15, 0x02); /* Set voice deactivate bit of SMSI */ - spin_unlock_irqrestore(&gus_lock,flags); - gus_voice_init(voice); - break; - - case VMODE_ENVELOPE: - gus_rampoff(); - spin_unlock_irqrestore(&gus_lock,flags); - step_envelope(voice); - break; - - case VMODE_START_NOTE: - spin_unlock_irqrestore(&gus_lock,flags); - guswave_start_note2(voices[voice].dev_pending, voice, - voices[voice].note_pending, voices[voice].volume_pending); - if (voices[voice].kill_pending) - guswave_kill_note(voices[voice].dev_pending, voice, - voices[voice].note_pending, 0); - - if (voices[voice].sample_pending >= 0) - { - guswave_set_instr(voices[voice].dev_pending, voice, - voices[voice].sample_pending); - voices[voice].sample_pending = -1; - } - break; - - default: - spin_unlock_irqrestore(&gus_lock,flags); - } -} -/* called in irq context */ -void gus_voice_irq(void) -{ - unsigned long wave_ignore = 0, volume_ignore = 0; - unsigned long voice_bit; - - unsigned char src, voice; - - while (1) - { - src = gus_read8(0x0f); /* - * Get source info - */ - voice = src & 0x1f; - src &= 0xc0; - - if (src == (0x80 | 0x40)) - return; /* - * No interrupt - */ - - voice_bit = 1 << voice; - - if (!(src & 0x80)) /* - * Wave IRQ pending - */ - if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ - { - wave_ignore |= voice_bit; - do_loop_irq(voice); - } - if (!(src & 0x40)) /* - * Volume IRQ pending - */ - if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ - { - volume_ignore |= voice_bit; - do_volume_irq(voice); - } - } -} - -void guswave_dma_irq(void) -{ - unsigned char status; - - status = gus_look8(0x41); /* Get DMA IRQ Status */ - if (status & 0x40) /* DMA interrupt pending */ - switch (active_device) - { - case GUS_DEV_WAVE: - wake_up(&dram_sleeper); - break; - - case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ - gus_write8(0x41, 0); /* Disable GF1 DMA */ - gus_transfer_output_block(pcm_current_dev, pcm_current_buf, - pcm_current_count, - pcm_current_intrflag, 1); - break; - - case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ - gus_write8(0x41, 0); /* Disable GF1 DMA */ - if (pcm_qlen < pcm_nblk) - { - dma_active = 0; - if (gus_busy) - { - if (audio_devs[gus_devnum]->dmap_out->qlen > 0) - DMAbuf_outputintr(gus_devnum, 0); - } - } - break; - - default: - break; - } - status = gus_look8(0x49); /* - * Get Sampling IRQ Status - */ - if (status & 0x40) /* - * Sampling Irq pending - */ - { - DMAbuf_inputintr(gus_devnum); - } -} - -/* - * Timer stuff - */ - -static volatile int select_addr, data_addr; -static volatile int curr_timer; - -void gus_timer_command(unsigned int addr, unsigned int val) -{ - int i; - - outb(((unsigned char) (addr & 0xff)), select_addr); - - for (i = 0; i < 2; i++) - inb(select_addr); - - outb(((unsigned char) (val & 0xff)), data_addr); - - for (i = 0; i < 2; i++) - inb(select_addr); -} - -static void arm_timer(int timer, unsigned int interval) -{ - curr_timer = timer; - - if (timer == 1) - { - gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */ - gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */ - gus_timer_command(0x04, 0x01); /* Start timer 1 */ - } - else - { - gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */ - gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */ - gus_timer_command(0x04, 0x02); /* Start timer 2 */ - } - - gus_timer_enabled = 1; -} - -static unsigned int gus_tmr_start(int dev, unsigned int usecs_per_tick) -{ - int timer_no, resolution; - int divisor; - - if (usecs_per_tick > (256 * 80)) - { - timer_no = 2; - resolution = 320; /* usec */ - } - else - { - timer_no = 1; - resolution = 80; /* usec */ - } - divisor = (usecs_per_tick + (resolution / 2)) / resolution; - arm_timer(timer_no, divisor); - - return divisor * resolution; -} - -static void gus_tmr_disable(int dev) -{ - gus_write8(0x45, 0); /* Disable both timers */ - gus_timer_enabled = 0; -} - -static void gus_tmr_restart(int dev) -{ - if (curr_timer == 1) - gus_write8(0x45, 0x04); /* Start timer 1 again */ - else - gus_write8(0x45, 0x08); /* Start timer 2 again */ - gus_timer_enabled = 1; -} - -static struct sound_lowlev_timer gus_tmr = -{ - 0, - 1, - gus_tmr_start, - gus_tmr_disable, - gus_tmr_restart -}; - -static void gus_tmr_install(int io_base) -{ - struct sound_lowlev_timer *tmr; - - select_addr = io_base; - data_addr = io_base + 1; - - tmr = &gus_tmr; - -#ifdef THIS_GETS_FIXED - sound_timer_init(&gus_tmr, "GUS"); -#endif -} diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c deleted file mode 100644 index 6601b284f03a..000000000000 --- a/sound/oss/harmony.c +++ /dev/null @@ -1,1330 +0,0 @@ -/* - sound/oss/harmony.c - - This is a sound driver for ASP's and Lasi's Harmony sound chip - and is unlikely to be used for anything other than on a HP PA-RISC. - - Harmony is found in HP 712s, 715/new and many other GSC based machines. - On older 715 machines you'll find the technically identical chip - called 'Vivace'. Both Harmony and Vicace are supported by this driver. - - Copyright 2000 (c) Linuxcare Canada, Alex deVries - Copyright 2000-2003 (c) Helge Deller - Copyright 2001 (c) Matthieu Delahaye - Copyright 2001 (c) Jean-Christophe Vaugeois - Copyright 2004 (c) Stuart Brady - - -TODO: - - fix SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls to - return the real values - - add private ioctl for selecting line- or microphone input - (only one of them is available at the same time) - - add module parameters - - implement mmap functionality - - implement gain meter ? - - ... -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "sound_config.h" - - -#define PFX "harmony: " -#define HARMONY_VERSION "V0.9a" - -#undef DEBUG -#ifdef DEBUG -# define DPRINTK printk -#else -# define DPRINTK(x,...) -#endif - - -#define MAX_BUFS 10 /* maximum number of rotating buffers */ -#define HARMONY_BUF_SIZE 4096 /* needs to be a multiple of PAGE_SIZE (4096)! */ - -#define CNTL_C 0x80000000 -#define CNTL_ST 0x00000020 -#define CNTL_44100 0x00000015 /* HARMONY_SR_44KHZ */ -#define CNTL_8000 0x00000008 /* HARMONY_SR_8KHZ */ - -#define GAINCTL_HE 0x08000000 -#define GAINCTL_LE 0x04000000 -#define GAINCTL_SE 0x02000000 - -#define DSTATUS_PN 0x00000200 -#define DSTATUS_RN 0x00000002 - -#define DSTATUS_IE 0x80000000 - -#define HARMONY_DF_16BIT_LINEAR 0 -#define HARMONY_DF_8BIT_ULAW 1 -#define HARMONY_DF_8BIT_ALAW 2 - -#define HARMONY_SS_MONO 0 -#define HARMONY_SS_STEREO 1 - -#define HARMONY_SR_8KHZ 0x08 -#define HARMONY_SR_16KHZ 0x09 -#define HARMONY_SR_27KHZ 0x0A -#define HARMONY_SR_32KHZ 0x0B -#define HARMONY_SR_48KHZ 0x0E -#define HARMONY_SR_9KHZ 0x0F -#define HARMONY_SR_5KHZ 0x10 -#define HARMONY_SR_11KHZ 0x11 -#define HARMONY_SR_18KHZ 0x12 -#define HARMONY_SR_22KHZ 0x13 -#define HARMONY_SR_37KHZ 0x14 -#define HARMONY_SR_44KHZ 0x15 -#define HARMONY_SR_33KHZ 0x16 -#define HARMONY_SR_6KHZ 0x17 - -/* - * Some magics numbers used to auto-detect file formats - */ - -#define HARMONY_MAGIC_8B_ULAW 1 -#define HARMONY_MAGIC_8B_ALAW 27 -#define HARMONY_MAGIC_16B_LINEAR 3 -#define HARMONY_MAGIC_MONO 1 -#define HARMONY_MAGIC_STEREO 2 - -/* - * Channels Positions in mixer register - */ - -#define GAIN_HE_SHIFT 27 -#define GAIN_HE_MASK ( 1 << GAIN_HE_SHIFT) -#define GAIN_LE_SHIFT 26 -#define GAIN_LE_MASK ( 1 << GAIN_LE_SHIFT) -#define GAIN_SE_SHIFT 25 -#define GAIN_SE_MASK ( 1 << GAIN_SE_SHIFT) -#define GAIN_IS_SHIFT 24 -#define GAIN_IS_MASK ( 1 << GAIN_IS_SHIFT) -#define GAIN_MA_SHIFT 20 -#define GAIN_MA_MASK ( 0x0f << GAIN_MA_SHIFT) -#define GAIN_LI_SHIFT 16 -#define GAIN_LI_MASK ( 0x0f << GAIN_LI_SHIFT) -#define GAIN_RI_SHIFT 12 -#define GAIN_RI_MASK ( 0x0f << GAIN_RI_SHIFT) -#define GAIN_LO_SHIFT 6 -#define GAIN_LO_MASK ( 0x3f << GAIN_LO_SHIFT) -#define GAIN_RO_SHIFT 0 -#define GAIN_RO_MASK ( 0x3f << GAIN_RO_SHIFT) - - -#define MAX_OUTPUT_LEVEL (GAIN_RO_MASK >> GAIN_RO_SHIFT) -#define MAX_INPUT_LEVEL (GAIN_RI_MASK >> GAIN_RI_SHIFT) -#define MAX_MONITOR_LEVEL (GAIN_MA_MASK >> GAIN_MA_SHIFT) - -#define MIXER_INTERNAL SOUND_MIXER_LINE1 -#define MIXER_LINEOUT SOUND_MIXER_LINE2 -#define MIXER_HEADPHONES SOUND_MIXER_LINE3 - -#define MASK_INTERNAL SOUND_MASK_LINE1 -#define MASK_LINEOUT SOUND_MASK_LINE2 -#define MASK_HEADPHONES SOUND_MASK_LINE3 - -/* - * Channels Mask in mixer register - */ - -#define GAIN_TOTAL_SILENCE 0x00F00FFF -#define GAIN_DEFAULT 0x0FF00000 - - -struct harmony_hpa { - u8 unused000; - u8 id; - u8 teleshare_id; - u8 unused003; - u32 reset; - u32 cntl; - u32 gainctl; - u32 pnxtadd; - u32 pcuradd; - u32 rnxtadd; - u32 rcuradd; - u32 dstatus; - u32 ov; - u32 pio; - u32 unused02c; - u32 unused030[3]; - u32 diag; -}; - -struct harmony_dev { - struct harmony_hpa *hpa; - struct parisc_device *dev; - u32 current_gain; - u32 dac_rate; /* 8000 ... 48000 (Hz) */ - u8 data_format; /* HARMONY_DF_xx_BIT_xxx */ - u8 sample_rate; /* HARMONY_SR_xx_KHZ */ - u8 stereo_select; /* HARMONY_SS_MONO or HARMONY_SS_STEREO */ - int format_initialized :1; - int suspended_playing :1; - int suspended_recording :1; - - int blocked_playing :1; - int blocked_recording :1; - int audio_open :1; - int mixer_open :1; - - wait_queue_head_t wq_play, wq_record; - int first_filled_play; /* first buffer containing data (next to play) */ - int nb_filled_play; - int play_offset; - int first_filled_record; - int nb_filled_record; - - int dsp_unit, mixer_unit; -}; - - -static struct harmony_dev harmony; - - -/* - * Dynamic sound buffer allocation and DMA memory - */ - -struct harmony_buffer { - unsigned char *addr; - dma_addr_t dma_handle; - int dma_coherent; /* Zero if dma_alloc_coherent() fails */ - unsigned int len; -}; - -/* - * Harmony memory buffers - */ - -static struct harmony_buffer played_buf, recorded_buf, silent, graveyard; - - -#define CHECK_WBACK_INV_OFFSET(b,offset,len) \ - do { if (!b.dma_coherent) \ - dma_cache_wback_inv((unsigned long)b.addr+offset,len); \ - } while (0) - - -static int __init harmony_alloc_buffer(struct harmony_buffer *b, - unsigned int buffer_count) -{ - b->len = buffer_count * HARMONY_BUF_SIZE; - b->addr = dma_alloc_coherent(&harmony.dev->dev, - b->len, &b->dma_handle, GFP_KERNEL|GFP_DMA); - if (b->addr && b->dma_handle) { - b->dma_coherent = 1; - DPRINTK(KERN_INFO PFX "coherent memory: 0x%lx, played_buf: 0x%lx\n", - (unsigned long)b->dma_handle, (unsigned long)b->addr); - } else { - b->dma_coherent = 0; - /* kmalloc()ed memory will HPMC on ccio machines ! */ - b->addr = kmalloc(b->len, GFP_KERNEL); - if (!b->addr) { - printk(KERN_ERR PFX "couldn't allocate memory\n"); - return -EBUSY; - } - b->dma_handle = __pa(b->addr); - } - return 0; -} - -static void __exit harmony_free_buffer(struct harmony_buffer *b) -{ - if (!b->addr) - return; - - if (b->dma_coherent) - dma_free_coherent(&harmony.dev->dev, - b->len, b->addr, b->dma_handle); - else - kfree(b->addr); - - memset(b, 0, sizeof(*b)); -} - - - -/* - * Low-Level sound-chip programming - */ - -static void __inline__ harmony_wait_CNTL(void) -{ - /* Wait until we're out of control mode */ - while (gsc_readl(&harmony.hpa->cntl) & CNTL_C) - /* wait */ ; -} - - -static void harmony_update_control(void) -{ - u32 default_cntl; - - /* Set CNTL */ - default_cntl = (CNTL_C | /* The C bit */ - (harmony.data_format << 6) | /* Set the data format */ - (harmony.stereo_select << 5) | /* Stereo select */ - (harmony.sample_rate)); /* Set sample rate */ - harmony.format_initialized = 1; - - /* initialize CNTL */ - gsc_writel(default_cntl, &harmony.hpa->cntl); -} - -static void harmony_set_control(u8 data_format, u8 sample_rate, u8 stereo_select) -{ - harmony.sample_rate = sample_rate; - harmony.data_format = data_format; - harmony.stereo_select = stereo_select; - harmony_update_control(); -} - -static void harmony_set_rate(u8 data_rate) -{ - harmony.sample_rate = data_rate; - harmony_update_control(); -} - -static int harmony_detect_rate(int *freq) -{ - int newrate; - switch (*freq) { - case 8000: newrate = HARMONY_SR_8KHZ; break; - case 16000: newrate = HARMONY_SR_16KHZ; break; - case 27428: newrate = HARMONY_SR_27KHZ; break; - case 32000: newrate = HARMONY_SR_32KHZ; break; - case 48000: newrate = HARMONY_SR_48KHZ; break; - case 9600: newrate = HARMONY_SR_9KHZ; break; - case 5512: newrate = HARMONY_SR_5KHZ; break; - case 11025: newrate = HARMONY_SR_11KHZ; break; - case 18900: newrate = HARMONY_SR_18KHZ; break; - case 22050: newrate = HARMONY_SR_22KHZ; break; - case 37800: newrate = HARMONY_SR_37KHZ; break; - case 44100: newrate = HARMONY_SR_44KHZ; break; - case 33075: newrate = HARMONY_SR_33KHZ; break; - case 6615: newrate = HARMONY_SR_6KHZ; break; - default: newrate = HARMONY_SR_8KHZ; - *freq = 8000; break; - } - return newrate; -} - -static void harmony_set_format(u8 data_format) -{ - harmony.data_format = data_format; - harmony_update_control(); -} - -static void harmony_set_stereo(u8 stereo_select) -{ - harmony.stereo_select = stereo_select; - harmony_update_control(); -} - -static void harmony_disable_interrupts(void) -{ - harmony_wait_CNTL(); - gsc_writel(0, &harmony.hpa->dstatus); -} - -static void harmony_enable_interrupts(void) -{ - harmony_wait_CNTL(); - gsc_writel(DSTATUS_IE, &harmony.hpa->dstatus); -} - -/* - * harmony_silence() - * - * This subroutine fills in a buffer starting at location start and - * silences for length bytes. This references the current - * configuration of the audio format. - * - */ - -static void harmony_silence(struct harmony_buffer *buffer, int start, int length) -{ - u8 silence_char; - - /* Despite what you hear, silence is different in - different audio formats. */ - switch (harmony.data_format) { - case HARMONY_DF_8BIT_ULAW: silence_char = 0x55; break; - case HARMONY_DF_8BIT_ALAW: silence_char = 0xff; break; - case HARMONY_DF_16BIT_LINEAR: /* fall through */ - default: silence_char = 0; - } - - memset(buffer->addr+start, silence_char, length); -} - - -static int harmony_audio_open(struct inode *inode, struct file *file) -{ - if (harmony.audio_open) - return -EBUSY; - - harmony.audio_open = 1; - harmony.suspended_playing = harmony.suspended_recording = 1; - harmony.blocked_playing = harmony.blocked_recording = 0; - harmony.first_filled_play = harmony.first_filled_record = 0; - harmony.nb_filled_play = harmony.nb_filled_record = 0; - harmony.play_offset = 0; - init_waitqueue_head(&harmony.wq_play); - init_waitqueue_head(&harmony.wq_record); - - /* Start off in a balanced mode. */ - harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO); - harmony_update_control(); - harmony.format_initialized = 0; - - /* Clear out all the buffers and flush to cache */ - harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); - CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); - - return 0; -} - -/* - * Release (close) the audio device. - */ - -static int harmony_audio_release(struct inode *inode, struct file *file) -{ - if (!harmony.audio_open) - return -EBUSY; - - harmony.audio_open = 0; - - return 0; -} - -/* - * Read recorded data off the audio device. - */ - -static ssize_t harmony_audio_read(struct file *file, - char *buffer, - size_t size_count, - loff_t *ppos) -{ - int total_count = (int) size_count; - int count = 0; - int buf_to_read; - - while (count24) { - if (copy_from_user(file_header, buffer, sizeof(file_header))) - ret = -EFAULT; - - start_string = four_bytes_to_u32(0); - - if ((file_header[4]==0) && (start_string==0x2E736E64)) { - u32 format; - u32 nb_voices; - u32 speed; - - format = four_bytes_to_u32(12); - nb_voices = four_bytes_to_u32(20); - speed = four_bytes_to_u32(16); - - switch (format) { - case HARMONY_MAGIC_8B_ULAW: - harmony.data_format = HARMONY_DF_8BIT_ULAW; - break; - case HARMONY_MAGIC_8B_ALAW: - harmony.data_format = HARMONY_DF_8BIT_ALAW; - break; - case HARMONY_MAGIC_16B_LINEAR: - harmony.data_format = HARMONY_DF_16BIT_LINEAR; - break; - default: - harmony_set_control(HARMONY_DF_16BIT_LINEAR, - HARMONY_SR_44KHZ, HARMONY_SS_STEREO); - goto out; - } - switch (nb_voices) { - case HARMONY_MAGIC_MONO: - harmony.stereo_select = HARMONY_SS_MONO; - break; - case HARMONY_MAGIC_STEREO: - harmony.stereo_select = HARMONY_SS_STEREO; - break; - default: - harmony.stereo_select = HARMONY_SS_MONO; - break; - } - harmony_set_rate(harmony_detect_rate(&speed)); - harmony.dac_rate = speed; - goto out; - } - } - harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO); -out: - return ret; -} -#undef four_bytes_to_u32 - - -static ssize_t harmony_audio_write(struct file *file, - const char *buffer, - size_t size_count, - loff_t *ppos) -{ - int total_count = (int) size_count; - int count = 0; - int frame_size; - int buf_to_fill; - int fresh_buffer; - - if (!harmony.format_initialized) { - if (harmony_format_auto_detect(buffer, total_count)) - return -EFAULT; - } - - while (count= MAX_BUFS && !harmony.play_offset) { - harmony.blocked_playing = 1; - interruptible_sleep_on(&harmony.wq_play); - harmony.blocked_playing = 0; - } - if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) - return -EBUSY; - - - buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play); - if (harmony.play_offset) { - buf_to_fill--; - buf_to_fill += MAX_BUFS; - } - buf_to_fill %= MAX_BUFS; - - fresh_buffer = (harmony.play_offset == 0); - - /* Figure out the size of the frame */ - if ((total_count-count) >= HARMONY_BUF_SIZE - harmony.play_offset) { - frame_size = HARMONY_BUF_SIZE - harmony.play_offset; - } else { - frame_size = total_count - count; - /* Clear out the buffer, since there we'll only be - overlaying part of the old buffer with the new one */ - harmony_silence(&played_buf, - HARMONY_BUF_SIZE*buf_to_fill+frame_size+harmony.play_offset, - HARMONY_BUF_SIZE-frame_size-harmony.play_offset); - } - - /* Copy the page to an aligned buffer */ - if (copy_from_user(played_buf.addr +(HARMONY_BUF_SIZE*buf_to_fill) + harmony.play_offset, - buffer+count, frame_size)) - return -EFAULT; - CHECK_WBACK_INV_OFFSET(played_buf, (HARMONY_BUF_SIZE*buf_to_fill + harmony.play_offset), - frame_size); - - if (fresh_buffer) - harmony.nb_filled_play++; - - count += frame_size; - harmony.play_offset += frame_size; - harmony.play_offset %= HARMONY_BUF_SIZE; - if (harmony.suspended_playing && (harmony.nb_filled_play>=4)) - harmony_enable_interrupts(); - } - - return count; -} - -static unsigned int harmony_audio_poll(struct file *file, - struct poll_table_struct *wait) -{ - unsigned int mask = 0; - - if (file->f_mode & FMODE_READ) { - if (!harmony.suspended_recording) - poll_wait(file, &harmony.wq_record, wait); - if (harmony.nb_filled_record) - mask |= POLLIN | POLLRDNORM; - } - - if (file->f_mode & FMODE_WRITE) { - if (!harmony.suspended_playing) - poll_wait(file, &harmony.wq_play, wait); - if (harmony.nb_filled_play) - mask |= POLLOUT | POLLWRNORM; - } - - return mask; -} - -static int harmony_audio_ioctl(struct inode *inode, - struct file *file, - unsigned int cmd, - unsigned long arg) -{ - int ival, new_format; - int frag_size, frag_buf; - struct audio_buf_info info; - - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, (int *) arg); - - case SNDCTL_DSP_GETCAPS: - ival = DSP_CAP_DUPLEX; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_GETFMTS: - ival = (AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW ); - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_SETFMT: - if (get_user(ival, (int *) arg)) - return -EFAULT; - if (ival != AFMT_QUERY) { - switch (ival) { - case AFMT_MU_LAW: new_format = HARMONY_DF_8BIT_ULAW; break; - case AFMT_A_LAW: new_format = HARMONY_DF_8BIT_ALAW; break; - case AFMT_S16_BE: new_format = HARMONY_DF_16BIT_LINEAR; break; - default: { - DPRINTK(KERN_WARNING PFX - "unsupported sound format 0x%04x requested.\n", - ival); - ival = AFMT_S16_BE; - return put_user(ival, (int *) arg); - } - } - harmony_set_format(new_format); - return 0; - } else { - switch (harmony.data_format) { - case HARMONY_DF_8BIT_ULAW: ival = AFMT_MU_LAW; break; - case HARMONY_DF_8BIT_ALAW: ival = AFMT_A_LAW; break; - case HARMONY_DF_16BIT_LINEAR: ival = AFMT_U16_BE; break; - default: ival = 0; - } - return put_user(ival, (int *) arg); - } - - case SOUND_PCM_READ_RATE: - ival = harmony.dac_rate; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_SPEED: - if (get_user(ival, (int *) arg)) - return -EFAULT; - harmony_set_rate(harmony_detect_rate(&ival)); - harmony.dac_rate = ival; - return put_user(ival, (int*) arg); - - case SNDCTL_DSP_STEREO: - if (get_user(ival, (int *) arg)) - return -EFAULT; - if (ival != 0 && ival != 1) - return -EINVAL; - harmony_set_stereo(ival); - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(ival, (int *) arg)) - return -EFAULT; - if (ival != 1 && ival != 2) { - ival = harmony.stereo_select == HARMONY_SS_MONO ? 1 : 2; - return put_user(ival, (int *) arg); - } - harmony_set_stereo(ival-1); - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - ival = HARMONY_BUF_SIZE; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_RESET: - if (!harmony.suspended_recording) { - /* TODO: stop_recording() */ - } - return 0; - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(ival, (int *)arg)) - return -EFAULT; - frag_size = ival & 0xffff; - frag_buf = (ival>>16) & 0xffff; - /* TODO: We use hardcoded fragment sizes and numbers for now */ - frag_size = 12; /* 4096 == 2^12 */ - frag_buf = MAX_BUFS; - ival = (frag_buf << 16) + frag_size; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - info.fragstotal = MAX_BUFS; - info.fragments = MAX_BUFS - harmony.nb_filled_play; - info.fragsize = HARMONY_BUF_SIZE; - info.bytes = info.fragments * info.fragsize; - return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - info.fragstotal = MAX_BUFS; - info.fragments = /*MAX_BUFS-*/ harmony.nb_filled_record; - info.fragsize = HARMONY_BUF_SIZE; - info.bytes = info.fragments * info.fragsize; - return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0; - - case SNDCTL_DSP_SYNC: - return 0; - } - - return -EINVAL; -} - - -/* - * harmony_interrupt() - * - * harmony interruption service routine - * - */ - -static irqreturn_t harmony_interrupt(int irq, void *dev, struct pt_regs *regs) -{ - u32 dstatus; - struct harmony_hpa *hpa; - - /* Setup the hpa */ - hpa = ((struct harmony_dev *)dev)->hpa; - harmony_wait_CNTL(); - - /* Read dstatus and pcuradd (the current address) */ - dstatus = gsc_readl(&hpa->dstatus); - - /* Turn off interrupts */ - harmony_disable_interrupts(); - - /* Check if this is a request to get the next play buffer */ - if (dstatus & DSTATUS_PN) { - if (!harmony.nb_filled_play) { - harmony.suspended_playing = 1; - gsc_writel((unsigned long)silent.dma_handle, &hpa->pnxtadd); - - if (!harmony.suspended_recording) - harmony_enable_interrupts(); - } else { - harmony.suspended_playing = 0; - gsc_writel((unsigned long)played_buf.dma_handle + - (HARMONY_BUF_SIZE*harmony.first_filled_play), - &hpa->pnxtadd); - harmony.first_filled_play++; - harmony.first_filled_play %= MAX_BUFS; - harmony.nb_filled_play--; - - harmony_enable_interrupts(); - } - - if (harmony.blocked_playing) - wake_up_interruptible(&harmony.wq_play); - } - - /* Check if we're being asked to fill in a recording buffer */ - if (dstatus & DSTATUS_RN) { - if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording) - { - harmony.nb_filled_record = 0; - harmony.first_filled_record = 0; - harmony.suspended_recording = 1; - gsc_writel((unsigned long)graveyard.dma_handle, &hpa->rnxtadd); - if (!harmony.suspended_playing) - harmony_enable_interrupts(); - } else { - int buf_to_fill; - buf_to_fill = (harmony.first_filled_record+harmony.nb_filled_record) % MAX_BUFS; - CHECK_WBACK_INV_OFFSET(recorded_buf, HARMONY_BUF_SIZE*buf_to_fill, HARMONY_BUF_SIZE); - gsc_writel((unsigned long)recorded_buf.dma_handle + - HARMONY_BUF_SIZE*buf_to_fill, - &hpa->rnxtadd); - harmony.nb_filled_record++; - harmony_enable_interrupts(); - } - - if (harmony.blocked_recording && harmony.nb_filled_record>3) - wake_up_interruptible(&harmony.wq_record); - } - return IRQ_HANDLED; -} - -/* - * Sound playing functions - */ - -static struct file_operations harmony_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = harmony_audio_read, - .write = harmony_audio_write, - .poll = harmony_audio_poll, - .ioctl = harmony_audio_ioctl, - .open = harmony_audio_open, - .release = harmony_audio_release, -}; - -static int harmony_audio_init(void) -{ - /* Request that IRQ */ - if (request_irq(harmony.dev->irq, harmony_interrupt, 0 ,"harmony", &harmony)) { - printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony.dev->irq); - return -EFAULT; - } - - harmony.dsp_unit = register_sound_dsp(&harmony_audio_fops, -1); - if (harmony.dsp_unit < 0) { - printk(KERN_ERR PFX "Error registering dsp\n"); - free_irq(harmony.dev->irq, &harmony); - return -EFAULT; - } - - /* Clear the buffers so you don't end up with crap in the buffers. */ - harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); - - /* Make sure this makes it to cache */ - CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); - - /* Clear out the silent buffer and flush to cache */ - harmony_silence(&silent, 0, HARMONY_BUF_SIZE); - CHECK_WBACK_INV_OFFSET(silent, 0, HARMONY_BUF_SIZE); - - harmony.audio_open = 0; - - return 0; -} - - -/* - * mixer functions - */ - -static void harmony_mixer_set_gain(void) -{ - harmony_wait_CNTL(); - gsc_writel(harmony.current_gain, &harmony.hpa->gainctl); -} - -/* - * Read gain of selected channel. - * The OSS rate is from 0 (silent) to 100 -> need some conversions - * - * The harmony gain are attenuation for output and monitor gain. - * is amplifaction for input gain - */ -#define to_harmony_level(level,max) ((level)*max/100) -#define to_oss_level(level,max) ((level)*100/max) - -static int harmony_mixer_get_level(int channel) -{ - int left_level; - int right_level; - - switch (channel) { - case SOUND_MIXER_VOLUME: - left_level = (harmony.current_gain & GAIN_LO_MASK) >> GAIN_LO_SHIFT; - right_level = (harmony.current_gain & GAIN_RO_MASK) >> GAIN_RO_SHIFT; - left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL); - right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL); - return (right_level << 8)+left_level; - - case SOUND_MIXER_IGAIN: - left_level = (harmony.current_gain & GAIN_LI_MASK) >> GAIN_LI_SHIFT; - right_level= (harmony.current_gain & GAIN_RI_MASK) >> GAIN_RI_SHIFT; - left_level = to_oss_level(left_level, MAX_INPUT_LEVEL); - right_level= to_oss_level(right_level, MAX_INPUT_LEVEL); - return (right_level << 8)+left_level; - - case SOUND_MIXER_MONITOR: - left_level = (harmony.current_gain & GAIN_MA_MASK) >> GAIN_MA_SHIFT; - left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL); - return (left_level << 8)+left_level; - } - return -EINVAL; -} - - - -/* - * Some conversions for the same reasons. - * We give back the new real value(s) due to - * the rescale. - */ - -static int harmony_mixer_set_level(int channel, int value) -{ - int left_level; - int right_level; - int new_left_level; - int new_right_level; - - right_level = (value & 0x0000ff00) >> 8; - left_level = value & 0x000000ff; - if (right_level > 100) right_level = 100; - if (left_level > 100) left_level = 100; - - switch (channel) { - case SOUND_MIXER_VOLUME: - right_level = to_harmony_level(100-right_level, MAX_OUTPUT_LEVEL); - left_level = to_harmony_level(100-left_level, MAX_OUTPUT_LEVEL); - new_right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL); - new_left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL); - harmony.current_gain = (harmony.current_gain & ~(GAIN_LO_MASK | GAIN_RO_MASK)) - | (left_level << GAIN_LO_SHIFT) | (right_level << GAIN_RO_SHIFT); - harmony_mixer_set_gain(); - return (new_right_level << 8) + new_left_level; - - case SOUND_MIXER_IGAIN: - right_level = to_harmony_level(right_level, MAX_INPUT_LEVEL); - left_level = to_harmony_level(left_level, MAX_INPUT_LEVEL); - new_right_level = to_oss_level(right_level, MAX_INPUT_LEVEL); - new_left_level = to_oss_level(left_level, MAX_INPUT_LEVEL); - harmony.current_gain = (harmony.current_gain & ~(GAIN_LI_MASK | GAIN_RI_MASK)) - | (left_level << GAIN_LI_SHIFT) | (right_level << GAIN_RI_SHIFT); - harmony_mixer_set_gain(); - return (new_right_level << 8) + new_left_level; - - case SOUND_MIXER_MONITOR: - left_level = to_harmony_level(100-left_level, MAX_MONITOR_LEVEL); - new_left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL); - harmony.current_gain = (harmony.current_gain & ~GAIN_MA_MASK) | (left_level << GAIN_MA_SHIFT); - harmony_mixer_set_gain(); - return (new_left_level << 8) + new_left_level; - } - - return -EINVAL; -} - -#undef to_harmony_level -#undef to_oss_level - -/* - * Return the selected input device (mic or line) - */ - -static int harmony_mixer_get_recmask(void) -{ - int current_input_line; - - current_input_line = (harmony.current_gain & GAIN_IS_MASK) - >> GAIN_IS_SHIFT; - if (current_input_line) - return SOUND_MASK_MIC; - - return SOUND_MASK_LINE; -} - -/* - * Set the input (only one at time, arbitrary priority to line in) - */ - -static int harmony_mixer_set_recmask(int recmask) -{ - int new_input_line; - int new_input_mask; - int current_input_line; - - current_input_line = (harmony.current_gain & GAIN_IS_MASK) - >> GAIN_IS_SHIFT; - if ((current_input_line && ((recmask & SOUND_MASK_LINE) || !(recmask & SOUND_MASK_MIC))) || - (!current_input_line && ((recmask & SOUND_MASK_LINE) && !(recmask & SOUND_MASK_MIC)))) { - new_input_line = 0; - new_input_mask = SOUND_MASK_LINE; - } else { - new_input_line = 1; - new_input_mask = SOUND_MASK_MIC; - } - harmony.current_gain = ((harmony.current_gain & ~GAIN_IS_MASK) | - (new_input_line << GAIN_IS_SHIFT )); - harmony_mixer_set_gain(); - return new_input_mask; -} - - -/* - * give the active outlines - */ - -static int harmony_mixer_get_outmask(void) -{ - int outmask = 0; - - if (harmony.current_gain & GAIN_SE_MASK) outmask |= MASK_INTERNAL; - if (harmony.current_gain & GAIN_LE_MASK) outmask |= MASK_LINEOUT; - if (harmony.current_gain & GAIN_HE_MASK) outmask |= MASK_HEADPHONES; - - return outmask; -} - - -static int harmony_mixer_set_outmask(int outmask) -{ - if (outmask & MASK_INTERNAL) - harmony.current_gain |= GAIN_SE_MASK; - else - harmony.current_gain &= ~GAIN_SE_MASK; - - if (outmask & MASK_LINEOUT) - harmony.current_gain |= GAIN_LE_MASK; - else - harmony.current_gain &= ~GAIN_LE_MASK; - - if (outmask & MASK_HEADPHONES) - harmony.current_gain |= GAIN_HE_MASK; - else - harmony.current_gain &= ~GAIN_HE_MASK; - - harmony_mixer_set_gain(); - - return (outmask & (MASK_INTERNAL | MASK_LINEOUT | MASK_HEADPHONES)); -} - -/* - * This code is inspired from sb_mixer.c - */ - -static int harmony_mixer_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - int val; - int ret; - - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - memset(&info, 0, sizeof(info)); - strncpy(info.id, "harmony", sizeof(info.id)-1); - strncpy(info.name, "Harmony audio", sizeof(info.name)-1); - info.modify_counter = 1; /* ? */ - if (copy_to_user((void *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int *)arg); - - /* read */ - val = 0; - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - if (get_user(val, (int *)arg)) - return -EFAULT; - - switch (cmd) { - case MIXER_READ(SOUND_MIXER_CAPS): - ret = SOUND_CAP_EXCL_INPUT; - break; - case MIXER_READ(SOUND_MIXER_STEREODEVS): - ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN; - break; - - case MIXER_READ(SOUND_MIXER_RECMASK): - ret = SOUND_MASK_MIC | SOUND_MASK_LINE; - break; - case MIXER_READ(SOUND_MIXER_DEVMASK): - ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN | - SOUND_MASK_MONITOR; - break; - case MIXER_READ(SOUND_MIXER_OUTMASK): - ret = MASK_INTERNAL | MASK_LINEOUT | - MASK_HEADPHONES; - break; - - case MIXER_WRITE(SOUND_MIXER_RECSRC): - ret = harmony_mixer_set_recmask(val); - break; - case MIXER_READ(SOUND_MIXER_RECSRC): - ret = harmony_mixer_get_recmask(); - break; - - case MIXER_WRITE(SOUND_MIXER_OUTSRC): - ret = harmony_mixer_set_outmask(val); - break; - case MIXER_READ(SOUND_MIXER_OUTSRC): - ret = harmony_mixer_get_outmask(); - break; - - case MIXER_WRITE(SOUND_MIXER_VOLUME): - case MIXER_WRITE(SOUND_MIXER_IGAIN): - case MIXER_WRITE(SOUND_MIXER_MONITOR): - ret = harmony_mixer_set_level(cmd & 0xff, val); - break; - - case MIXER_READ(SOUND_MIXER_VOLUME): - case MIXER_READ(SOUND_MIXER_IGAIN): - case MIXER_READ(SOUND_MIXER_MONITOR): - ret = harmony_mixer_get_level(cmd & 0xff); - break; - - default: - return -EINVAL; - } - - if (put_user(ret, (int *)arg)) - return -EFAULT; - return 0; -} - - -static int harmony_mixer_open(struct inode *inode, struct file *file) -{ - if (harmony.mixer_open) - return -EBUSY; - harmony.mixer_open = 1; - return 0; -} - -static int harmony_mixer_release(struct inode *inode, struct file *file) -{ - if (!harmony.mixer_open) - return -EBUSY; - harmony.mixer_open = 0; - return 0; -} - -static struct file_operations harmony_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = harmony_mixer_open, - .release = harmony_mixer_release, - .ioctl = harmony_mixer_ioctl, -}; - - -/* - * Mute all the output and reset Harmony. - */ - -static void __init harmony_mixer_reset(void) -{ - harmony.current_gain = GAIN_TOTAL_SILENCE; - harmony_mixer_set_gain(); - harmony_wait_CNTL(); - gsc_writel(1, &harmony.hpa->reset); - mdelay(50); /* wait 50 ms */ - gsc_writel(0, &harmony.hpa->reset); - harmony.current_gain = GAIN_DEFAULT; - harmony_mixer_set_gain(); -} - -static int __init harmony_mixer_init(void) -{ - /* Register the device file operations */ - harmony.mixer_unit = register_sound_mixer(&harmony_mixer_fops, -1); - if (harmony.mixer_unit < 0) { - printk(KERN_WARNING PFX "Error Registering Mixer Driver\n"); - return -EFAULT; - } - - harmony_mixer_reset(); - harmony.mixer_open = 0; - - return 0; -} - - - -/* - * This is the callback that's called by the inventory hardware code - * if it finds a match to the registered driver. - */ -static int __devinit -harmony_driver_probe(struct parisc_device *dev) -{ - u8 id; - u8 rev; - u32 cntl; - int ret; - - if (harmony.hpa) { - /* We only support one Harmony at this time */ - printk(KERN_ERR PFX "driver already registered\n"); - return -EBUSY; - } - - if (!dev->irq) { - printk(KERN_ERR PFX "no irq found\n"); - return -ENODEV; - } - - /* Set the HPA of harmony */ - harmony.hpa = (struct harmony_hpa *)dev->hpa.start; - harmony.dev = dev; - - /* Grab the ID and revision from the device */ - id = gsc_readb(&harmony.hpa->id); - if ((id | 1) != 0x15) { - printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", id); - return -EBUSY; - } - cntl = gsc_readl(&harmony.hpa->cntl); - rev = (cntl>>20) & 0xff; - - printk(KERN_INFO "Lasi Harmony Audio driver " HARMONY_VERSION ", " - "h/w id %i, rev. %i at 0x%lx, IRQ %i\n", - id, rev, dev->hpa.start, harmony.dev->irq); - - /* Make sure the control bit isn't set, although I don't think it - ever is. */ - if (cntl & CNTL_C) { - printk(KERN_WARNING PFX "CNTL busy\n"); - harmony.hpa = 0; - return -EBUSY; - } - - /* Initialize the memory buffers */ - if (harmony_alloc_buffer(&played_buf, MAX_BUFS) || - harmony_alloc_buffer(&recorded_buf, MAX_BUFS) || - harmony_alloc_buffer(&graveyard, 1) || - harmony_alloc_buffer(&silent, 1)) { - ret = -EBUSY; - goto out_err; - } - - /* Initialize /dev/mixer and /dev/audio */ - if ((ret=harmony_mixer_init())) - goto out_err; - if ((ret=harmony_audio_init())) - goto out_err; - - return 0; - -out_err: - harmony.hpa = 0; - harmony_free_buffer(&played_buf); - harmony_free_buffer(&recorded_buf); - harmony_free_buffer(&graveyard); - harmony_free_buffer(&silent); - return ret; -} - - -static struct parisc_device_id harmony_tbl[] = { - /* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, Bushmaster/Flounder */ - { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */ - { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */ - { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */ - { 0, } -}; - -MODULE_DEVICE_TABLE(parisc, harmony_tbl); - -static struct parisc_driver harmony_driver = { - .name = "Lasi Harmony", - .id_table = harmony_tbl, - .probe = harmony_driver_probe, -}; - -static int __init init_harmony(void) -{ - return register_parisc_driver(&harmony_driver); -} - -static void __exit cleanup_harmony(void) -{ - free_irq(harmony.dev->irq, &harmony); - unregister_sound_mixer(harmony.mixer_unit); - unregister_sound_dsp(harmony.dsp_unit); - harmony_free_buffer(&played_buf); - harmony_free_buffer(&recorded_buf); - harmony_free_buffer(&graveyard); - harmony_free_buffer(&silent); - unregister_parisc_driver(&harmony_driver); -} - - -MODULE_AUTHOR("Alex DeVries "); -MODULE_DESCRIPTION("Harmony sound driver"); -MODULE_LICENSE("GPL"); - -module_init(init_harmony); -module_exit(cleanup_harmony); - diff --git a/sound/oss/ics2101.c b/sound/oss/ics2101.c deleted file mode 100644 index 45918df150b3..000000000000 --- a/sound/oss/ics2101.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * sound/oss/ics2101.c - * - * Driver for the ICS2101 mixer of GUS v3.7. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init() - */ -#include -#include -#include "sound_config.h" - -#include - -#include "gus.h" -#include "gus_hw.h" - -#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ - SOUND_MASK_SYNTH| \ - SOUND_MASK_CD | SOUND_MASK_VOLUME) - -extern int *gus_osp; -extern int gus_base; -extern spinlock_t gus_lock; -static int volumes[ICS_MIXDEVS]; -static int left_fix[ICS_MIXDEVS] = -{1, 1, 1, 2, 1, 2}; -static int right_fix[ICS_MIXDEVS] = -{2, 2, 2, 1, 2, 1}; - -static int scale_vol(int vol) -{ - /* - * Experimental volume scaling by Risto Kankkunen. - * This should give smoother volume response than just - * a plain multiplication. - */ - - int e; - - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - vol = (31 * vol + 50) / 100; - e = 0; - if (vol) - { - while (vol < 16) - { - vol <<= 1; - e--; - } - vol -= 16; - e += 7; - } - return ((e << 4) + vol); -} - -static void write_mix(int dev, int chn, int vol) -{ - int *selector; - unsigned long flags; - int ctrl_addr = dev << 3; - int attn_addr = dev << 3; - - vol = scale_vol(vol); - - if (chn == CHN_LEFT) - { - selector = left_fix; - ctrl_addr |= 0x00; - attn_addr |= 0x02; - } - else - { - selector = right_fix; - ctrl_addr |= 0x01; - attn_addr |= 0x03; - } - - spin_lock_irqsave(&gus_lock, flags); - outb((ctrl_addr), u_MixSelect); - outb((selector[dev]), u_MixData); - outb((attn_addr), u_MixSelect); - outb(((unsigned char) vol), u_MixData); - spin_unlock_irqrestore(&gus_lock,flags); -} - -static int set_volumes(int dev, int vol) -{ - int left = vol & 0x00ff; - int right = (vol >> 8) & 0x00ff; - - if (left < 0) - left = 0; - if (left > 100) - left = 100; - if (right < 0) - right = 0; - if (right > 100) - right = 100; - - write_mix(dev, CHN_LEFT, left); - write_mix(dev, CHN_RIGHT, right); - - vol = left + (right << 8); - volumes[dev] = vol; - return vol; -} - -static int ics2101_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int val; - - if (((cmd >> 8) & 0xff) == 'M') { - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - - if (get_user(val, (int __user *)arg)) - return -EFAULT; - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - return gus_default_mixer_ioctl(dev, cmd, arg); - - case SOUND_MIXER_MIC: - val = set_volumes(DEV_MIC, val); - break; - - case SOUND_MIXER_CD: - val = set_volumes(DEV_CD, val); - break; - - case SOUND_MIXER_LINE: - val = set_volumes(DEV_LINE, val); - break; - - case SOUND_MIXER_SYNTH: - val = set_volumes(DEV_GF1, val); - break; - - case SOUND_MIXER_VOLUME: - val = set_volumes(DEV_VOL, val); - break; - - default: - return -EINVAL; - } - return put_user(val, (int __user *)arg); - } else { - switch (cmd & 0xff) { - /* - * Return parameters - */ - case SOUND_MIXER_RECSRC: - return gus_default_mixer_ioctl(dev, cmd, arg); - - case SOUND_MIXER_DEVMASK: - val = MIX_DEVS; - break; - - case SOUND_MIXER_STEREODEVS: - val = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC; - break; - - case SOUND_MIXER_RECMASK: - val = SOUND_MASK_MIC | SOUND_MASK_LINE; - break; - - case SOUND_MIXER_CAPS: - val = 0; - break; - - case SOUND_MIXER_MIC: - val = volumes[DEV_MIC]; - break; - - case SOUND_MIXER_LINE: - val = volumes[DEV_LINE]; - break; - - case SOUND_MIXER_CD: - val = volumes[DEV_CD]; - break; - - case SOUND_MIXER_VOLUME: - val = volumes[DEV_VOL]; - break; - - case SOUND_MIXER_SYNTH: - val = volumes[DEV_GF1]; - break; - - default: - return -EINVAL; - } - return put_user(val, (int __user *)arg); - } - } - return -EINVAL; -} - -static struct mixer_operations ics2101_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "ICS2101", - .name = "ICS2101 Multimedia Mixer", - .ioctl = ics2101_mixer_ioctl -}; - -int __init ics2101_mixer_init(void) -{ - int i; - int n; - - if ((n = sound_alloc_mixerdev()) != -1) - { - mixer_devs[n] = &ics2101_mixer_operations; - - /* - * Some GUS v3.7 cards had some channels flipped. Disable - * the flipping feature if the model id is other than 5. - */ - - if (inb(u_MixSelect) != 5) - { - for (i = 0; i < ICS_MIXDEVS; i++) - left_fix[i] = 1; - for (i = 0; i < ICS_MIXDEVS; i++) - right_fix[i] = 2; - } - set_volumes(DEV_GF1, 0x5a5a); - set_volumes(DEV_CD, 0x5a5a); - set_volumes(DEV_MIC, 0x0000); - set_volumes(DEV_LINE, 0x5a5a); - set_volumes(DEV_VOL, 0x5a5a); - set_volumes(DEV_UNUSED, 0x0000); - } - return n; -} diff --git a/sound/oss/iwmem.h b/sound/oss/iwmem.h deleted file mode 100644 index 48d333c7302b..000000000000 --- a/sound/oss/iwmem.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * sound/oss/iwmem.h - * - * DRAM size encoding table for AMD Interwave chip. - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes: - * Bartlomiej Zolnierkiewicz : added __initdata to mem_decode - */ - - -#define K 1024 -#define M (1024*K) -static int mem_decode[][4] __initdata = -{ -/* Bank0 Bank1 Bank2 Bank3 Encoding bits */ - {256*K, 0, 0, 0}, /* 0 */ - {256*K, 256*K, 0, 0}, /* 1 */ - {256*K, 256*K, 256*K, 256*K}, /* 2 */ - {256*K, 1*M, 0, 0}, /* 3 */ - {256*K, 1*M, 1*M, 1*M}, /* 4 */ - {256*K, 256*K, 1*M, 0}, /* 5 */ - {256*K, 256*K, 1*M, 1*M}, /* 6 */ - {1*M, 0, 0, 0}, /* 7 */ - {1*M, 1*M, 0, 0}, /* 8 */ - {1*M, 1*M, 1*M, 1*M}, /* 9 */ - {4*M, 0, 0, 0}, /* 10 */ - {4*M, 4*M, 0, 0}, /* 11 */ - {4*M, 4*M, 4*M, 4*M} /* 12 */ -}; diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c deleted file mode 100644 index aa3c50db66c4..000000000000 --- a/sound/oss/mad16.c +++ /dev/null @@ -1,1113 +0,0 @@ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * mad16.c - * - * Initialization code for OPTi MAD16 compatible audio chips. Including - * - * OPTi 82C928 MAD16 (replaced by C929) - * OAK OTI-601D Mozart - * OAK OTI-605 Mozart (later version with MPU401 Midi) - * OPTi 82C929 MAD16 Pro - * OPTi 82C930 - * OPTi 82C924 - * - * These audio interface chips don't produce sound themselves. They just - * connect some other components (OPL-[234] and a WSS compatible codec) - * to the PC bus and perform I/O, DMA and IRQ address decoding. There is - * also a UART for the MPU-401 mode (not 82C928/Mozart). - * The Mozart chip appears to be compatible with the 82C928, although later - * issues of the card, using the OTI-605 chip, have an MPU-401 compatible Midi - * port. This port is configured differently to that of the OPTi audio chips. - * - * Changes - * - * Alan Cox Clean up, added module selections. - * - * A. Wik Added support for Opti924 PnP. - * Improved debugging support. 16-May-1998 - * Fixed bug. 16-Jun-1998 - * - * Torsten Duwe Made Opti924 PnP support non-destructive - * 23-Dec-1998 - * - * Paul Grayson Added support for Midi on later Mozart cards. - * 25-Nov-1999 - * Christoph Hellwig Adapted to module_init/module_exit. - * Arnaldo C. de Melo got rid of attach_uart401 21-Sep-2000 - * - * Pavel Rabel Clean up Nov-2000 - */ - -#include -#include -#include -#include -#include -#include "sound_config.h" - -#include "ad1848.h" -#include "sb.h" -#include "mpu401.h" - -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -#define SUPPORT_JOYSTICK 1 -#endif - -static int mad16_conf; -static int mad16_cdsel; -static DEFINE_SPINLOCK(lock); - -#define C928 1 -#define MOZART 2 -#define C929 3 -#define C930 4 -#define C924 5 - -/* - * Registers - * - * The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations). - * All ports are inactive by default. They can be activated by - * writing 0xE2 or 0xE3 to the password register. The password is valid - * only until the next I/O read or write. - * - * 82C930 uses 0xE4 as the password and indirect addressing to access - * the config registers. - */ - -#define MC0_PORT 0xf8c /* Dummy port */ -#define MC1_PORT 0xf8d /* SB address, CD-ROM interface type, joystick */ -#define MC2_PORT 0xf8e /* CD-ROM address, IRQ, DMA, plus OPL4 bit */ -#define MC3_PORT 0xf8f -#define PASSWD_REG 0xf8f -#define MC4_PORT 0xf90 -#define MC5_PORT 0xf91 -#define MC6_PORT 0xf92 -#define MC7_PORT 0xf93 -#define MC8_PORT 0xf94 -#define MC9_PORT 0xf95 -#define MC10_PORT 0xf96 -#define MC11_PORT 0xf97 -#define MC12_PORT 0xf98 - -static int board_type = C928; - -static int *mad16_osp; -static int c931_detected; /* minor differences from C930 */ -static char c924pnp; /* " " " C924 */ -static int debug; /* debugging output */ - -#ifdef DDB -#undef DDB -#endif -#define DDB(x) do {if (debug) x;} while (0) - -static unsigned char mad_read(int port) -{ - unsigned long flags; - unsigned char tmp; - - spin_lock_irqsave(&lock,flags); - - switch (board_type) /* Output password */ - { - case C928: - case MOZART: - outb((0xE2), PASSWD_REG); - break; - - case C929: - outb((0xE3), PASSWD_REG); - break; - - case C930: - /* outb(( 0xE4), PASSWD_REG); */ - break; - - case C924: - /* the c924 has its ports relocated by -128 if - PnP is enabled -aw */ - if (!c924pnp) - outb((0xE5), PASSWD_REG); else - outb((0xE5), PASSWD_REG - 0x80); - break; - } - - if (board_type == C930) - { - outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ - tmp = inb(0xe0f); /* Read from data reg */ - } - else - if (!c924pnp) - tmp = inb(port); else - tmp = inb(port-0x80); - spin_unlock_irqrestore(&lock,flags); - - return tmp; -} - -static void mad_write(int port, int value) -{ - unsigned long flags; - - spin_lock_irqsave(&lock,flags); - - switch (board_type) /* Output password */ - { - case C928: - case MOZART: - outb((0xE2), PASSWD_REG); - break; - - case C929: - outb((0xE3), PASSWD_REG); - break; - - case C930: - /* outb(( 0xE4), PASSWD_REG); */ - break; - - case C924: - if (!c924pnp) - outb((0xE5), PASSWD_REG); else - outb((0xE5), PASSWD_REG - 0x80); - break; - } - - if (board_type == C930) - { - outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ - outb(((unsigned char) (value & 0xff)), 0xe0f); - } - else - if (!c924pnp) - outb(((unsigned char) (value & 0xff)), port); else - outb(((unsigned char) (value & 0xff)), port-0x80); - spin_unlock_irqrestore(&lock,flags); -} - -static int __init detect_c930(void) -{ - unsigned char tmp = mad_read(MC1_PORT); - - if ((tmp & 0x06) != 0x06) - { - DDB(printk("Wrong C930 signature (%x)\n", tmp)); - /* return 0; */ - } - mad_write(MC1_PORT, 0); - - if (mad_read(MC1_PORT) != 0x06) - { - DDB(printk("Wrong C930 signature2 (%x)\n", tmp)); - /* return 0; */ - } - mad_write(MC1_PORT, tmp); /* Restore bits */ - - mad_write(MC7_PORT, 0); - if ((tmp = mad_read(MC7_PORT)) != 0) - { - DDB(printk("MC7 not writable (%x)\n", tmp)); - return 0; - } - mad_write(MC7_PORT, 0xcb); - if ((tmp = mad_read(MC7_PORT)) != 0xcb) - { - DDB(printk("MC7 not writable2 (%x)\n", tmp)); - return 0; - } - - tmp = mad_read(MC0_PORT+18); - if (tmp == 0xff || tmp == 0x00) - return 1; - /* We probably have a C931 */ - DDB(printk("Detected C931 config=0x%02x\n", tmp)); - c931_detected = 1; - - /* - * We cannot configure the chip if it is in PnP mode. - * If we have a CSN assigned (bit 8 in MC13) we first try - * a software reset, then a software power off, finally - * Clearing PnP mode. The last option is not - * Bit 8 in MC13 - */ - if ((mad_read(MC0_PORT+13) & 0x80) == 0) - return 1; - - /* Software reset */ - mad_write(MC9_PORT, 0x02); - mad_write(MC9_PORT, 0x00); - - if ((mad_read(MC0_PORT+13) & 0x80) == 0) - return 1; - - /* Power off, and on again */ - mad_write(MC9_PORT, 0xc2); - mad_write(MC9_PORT, 0xc0); - - if ((mad_read(MC0_PORT+13) & 0x80) == 0) - return 1; - -#if 0 - /* Force off PnP mode. This is not recommended because - * the PnP bios will not recognize the chip on the next - * warm boot and may assignd different resources to other - * PnP/PCI cards. - */ - mad_write(MC0_PORT+17, 0x04); -#endif - return 1; -} - -static int __init detect_mad16(void) -{ - unsigned char tmp, tmp2, bit; - int i, port; - - /* - * Check that reading a register doesn't return bus float (0xff) - * when the card is accessed using password. This may fail in case - * the card is in low power mode. Normally at least the power saving - * mode bit should be 0. - */ - - if ((tmp = mad_read(MC1_PORT)) == 0xff) - { - DDB(printk("MC1_PORT returned 0xff\n")); - return 0; - } - for (i = 0xf8d; i <= 0xf98; i++) - if (!c924pnp) - DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i))); - else - DDB(printk("Port %0x (init value) = %0x\n", i-0x80, mad_read(i))); - - if (board_type == C930) - return detect_c930(); - - /* - * Now check that the gate is closed on first I/O after writing - * the password. (This is how a MAD16 compatible card works). - */ - - if ((tmp2 = inb(MC1_PORT)) == tmp) /* It didn't close */ - { - DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); - return 0; - } - - bit = (c924pnp) ? 0x20 : 0x80; - port = (c924pnp) ? MC2_PORT : MC1_PORT; - - tmp = mad_read(port); - mad_write(port, tmp ^ bit); /* Toggle a bit */ - if ((tmp2 = mad_read(port)) != (tmp ^ bit)) /* Compare the bit */ - { - mad_write(port, tmp); /* Restore */ - DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); - return 0; - } - mad_write(port, tmp); /* Restore */ - return 1; /* Bingo */ -} - -static int __init wss_init(struct address_info *hw_config) -{ - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00. - */ - - if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 && - (inb(hw_config->io_base + 3) & 0x3f) != 0x00) - { - DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3))); - return 0; - } - /* - * Check that DMA0 is not in use with a 8 bit board. - */ - if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) - { - printk("MSS: Can't use DMA0 with a 8 bit card/slot\n"); - return 0; - } - if (hw_config->irq > 9 && inb(hw_config->io_base + 3) & 0x80) - printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); - return 1; -} - -static void __init init_c930(struct address_info *hw_config, int base) -{ - unsigned char cfg = 0; - - cfg |= (0x0f & mad16_conf); - - if(c931_detected) - { - /* Bit 0 has reversd meaning. Bits 1 and 2 sese - reversed on write. - Support only IDE cdrom. IDE port programmed - somewhere else. */ - cfg = (cfg & 0x09) ^ 0x07; - } - cfg |= base << 4; - mad_write(MC1_PORT, cfg); - - /* MC2 is CD configuration. Don't touch it. */ - - mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */ - - /* bit 2 of MC4 reverses it's meaning between the C930 - and the C931. */ - cfg = c931_detected ? 0x04 : 0x00; - - if(mad16_cdsel & 0x20) - mad_write(MC4_PORT, 0x62|cfg); /* opl4 */ - else - mad_write(MC4_PORT, 0x52|cfg); /* opl3 */ - - mad_write(MC5_PORT, 0x3C); /* Init it into mode2 */ - mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */ - mad_write(MC7_PORT, 0xCB); - mad_write(MC10_PORT, 0x11); -} - -static int __init chip_detect(void) -{ - int i; - - /* - * Then try to detect with the old password - */ - board_type = C924; - - DDB(printk("Detect using password = 0xE5\n")); - - if (detect_mad16()) { - return 1; - } - - board_type = C928; - - DDB(printk("Detect using password = 0xE2\n")); - - if (detect_mad16()) - { - unsigned char model; - - if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) { - DDB(printk("mad16.c: Mozart detected\n")); - board_type = MOZART; - } else { - DDB(printk("mad16.c: 82C928 detected???\n")); - board_type = C928; - } - return 1; - } - - board_type = C929; - - DDB(printk("Detect using password = 0xE3\n")); - - if (detect_mad16()) - { - DDB(printk("mad16.c: 82C929 detected\n")); - return 1; - } - - if (inb(PASSWD_REG) != 0xff) - return 0; - - /* - * First relocate MC# registers to 0xe0e/0xe0f, disable password - */ - - outb((0xE4), PASSWD_REG); - outb((0x80), PASSWD_REG); - - board_type = C930; - - DDB(printk("Detect using password = 0xE4\n")); - - for (i = 0xf8d; i <= 0xf93; i++) - DDB(printk("port %03x = %02x\n", i, mad_read(i))); - - if(detect_mad16()) { - DDB(printk("mad16.c: 82C930 detected\n")); - return 1; - } - - /* The C931 has the password reg at F8D */ - outb((0xE4), 0xF8D); - outb((0x80), 0xF8D); - DDB(printk("Detect using password = 0xE4 for C931\n")); - - if (detect_mad16()) { - return 1; - } - - board_type = C924; - c924pnp++; - DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n")); - if (detect_mad16()) { - DDB(printk("mad16.c: 82C924 PnP detected\n")); - return 1; - } - - c924pnp=0; - - return 0; -} - -static int __init probe_mad16(struct address_info *hw_config) -{ - int i; - unsigned char tmp; - unsigned char cs4231_mode = 0; - - int ad_flags = 0; - - signed char bits; - - static char dma_bits[4] = { - 1, 2, 0, 3 - }; - - int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; - int dma = hw_config->dma, dma2 = hw_config->dma2; - unsigned char dma2_bit = 0; - int base; - struct resource *ports; - - mad16_osp = hw_config->osp; - - switch (hw_config->io_base) { - case 0x530: - base = 0; - break; - case 0xe80: - base = 1; - break; - case 0xf40: - base = 2; - break; - case 0x604: - base = 3; - break; - default: - printk(KERN_ERR "MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base); - return 0; - } - - if (dma != 0 && dma != 1 && dma != 3) { - printk(KERN_ERR "MSS: Bad DMA %d\n", dma); - return 0; - } - - /* - * Check that all ports return 0xff (bus float) when no password - * is written to the password register. - */ - - DDB(printk("--- Detecting MAD16 / Mozart ---\n")); - if (!chip_detect()) - return 0; - - switch (hw_config->irq) { - case 7: - bits = 8; - break; - case 9: - bits = 0x10; - break; - case 10: - bits = 0x18; - break; - case 12: - bits = 0x20; - break; - case 5: /* Also IRQ5 is possible on C930 */ - if (board_type == C930 || c924pnp) { - bits = 0x28; - break; - } - default: - printk(KERN_ERR "MAD16/Mozart: Bad IRQ %d\n", hw_config->irq); - return 0; - } - - ports = request_region(hw_config->io_base + 4, 4, "ad1848"); - if (!ports) { - printk(KERN_ERR "MSS: I/O port conflict\n"); - return 0; - } - if (!request_region(hw_config->io_base, 4, "mad16 WSS config")) { - release_region(hw_config->io_base + 4, 4); - printk(KERN_ERR "MSS: I/O port conflict\n"); - return 0; - } - - if (board_type == C930) { - init_c930(hw_config, base); - goto got_it; - } - - for (i = 0xf8d; i <= 0xf93; i++) { - if (!c924pnp) - DDB(printk("port %03x = %02x\n", i, mad_read(i))); - else - DDB(printk("port %03x = %02x\n", i-0x80, mad_read(i))); - } - -/* - * Set the WSS address - */ - - tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */ - tmp |= base << 4; /* WSS port select bits */ - - /* - * Set optional CD-ROM and joystick settings. - */ - - tmp &= ~0x0f; - tmp |= (mad16_conf & 0x0f); /* CD-ROM and joystick bits */ - mad_write(MC1_PORT, tmp); - - tmp = mad16_cdsel; - mad_write(MC2_PORT, tmp); - mad_write(MC3_PORT, 0xf0); /* Disable SB */ - - if (board_type == C924) /* Specific C924 init values */ - { - mad_write(MC4_PORT, 0xA0); - mad_write(MC5_PORT, 0x05); - mad_write(MC6_PORT, 0x03); - } - if (!ad1848_detect(ports, &ad_flags, mad16_osp)) - goto fail; - - if (ad_flags & (AD_F_CS4231 | AD_F_CS4248)) - cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */ - - if (board_type == C929) - { - mad_write(MC4_PORT, 0xa2); - mad_write(MC5_PORT, 0xA5 | cs4231_mode); - mad_write(MC6_PORT, 0x03); /* Disable MPU401 */ - } - else - { - mad_write(MC4_PORT, 0x02); - mad_write(MC5_PORT, 0x30 | cs4231_mode); - } - - for (i = 0xf8d; i <= 0xf93; i++) { - if (!c924pnp) - DDB(printk("port %03x after init = %02x\n", i, mad_read(i))); - else - DDB(printk("port %03x after init = %02x\n", i-0x80, mad_read(i))); - } - -got_it: - ad_flags = 0; - if (!ad1848_detect(ports, &ad_flags, mad16_osp)) - goto fail; - - if (!wss_init(hw_config)) - goto fail; - - /* - * Set the IRQ and DMA addresses. - */ - - outb((bits | 0x40), config_port); - if ((inb(version_port) & 0x40) == 0) - printk(KERN_ERR "[IRQ Conflict?]\n"); - - /* - * Handle the capture DMA channel - */ - - if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) - { - if (!((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0))) - { /* Unsupported combination. Try to swap channels */ - int tmp = dma; - - dma = dma2; - dma2 = tmp; - } - if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0)) - { - dma2_bit = 0x04; /* Enable capture DMA */ - } - else - { - printk("MAD16: Invalid capture DMA\n"); - dma2 = dma; - } - } - else dma2 = dma; - - outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ - - hw_config->slots[0] = ad1848_init("mad16 WSS", ports, - hw_config->irq, - dma, - dma2, 0, - hw_config->osp, - THIS_MODULE); - return 1; - -fail: - release_region(hw_config->io_base + 4, 4); - release_region(hw_config->io_base, 4); - return 0; -} - -static int __init probe_mad16_mpu(struct address_info *hw_config) -{ - unsigned char tmp; - - if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { - -#ifdef CONFIG_MAD16_OLDCARD - - tmp = mad_read(MC3_PORT); - - /* - * MAD16 SB base is defined by the WSS base. It cannot be changed - * alone. - * Ignore configured I/O base. Use the active setting. - */ - - if (mad_read(MC1_PORT) & 0x20) - hw_config->io_base = 0x240; - else - hw_config->io_base = 0x220; - - switch (hw_config->irq) - { - case 5: - tmp = (tmp & 0x3f) | 0x80; - break; - case 7: - tmp = (tmp & 0x3f); - break; - case 11: - tmp = (tmp & 0x3f) | 0x40; - break; - default: - printk(KERN_ERR "mad16/Mozart: Invalid MIDI IRQ\n"); - return 0; - } - - mad_write(MC3_PORT, tmp | 0x04); - hw_config->driver_use_1 = SB_MIDI_ONLY; - if (!request_region(hw_config->io_base, 16, "soundblaster")) - return 0; - if (!sb_dsp_detect(hw_config, 0, 0, NULL)) { - release_region(hw_config->io_base, 16); - return 0; - } - - if (mad_read(MC1_PORT) & 0x20) - hw_config->io_base = 0x240; - else - hw_config->io_base = 0x220; - - hw_config->name = "Mad16/Mozart"; - sb_dsp_init(hw_config, THIS_MODULE); - return 1; -#else - /* assuming all later Mozart cards are identified as - * either 82C928 or Mozart. If so, following code attempts - * to set MPU register. TODO - add probing - */ - - tmp = mad_read(MC8_PORT); - - switch (hw_config->irq) - { - case 5: - tmp |= 0x08; - break; - case 7: - tmp |= 0x10; - break; - case 9: - tmp |= 0x18; - break; - case 10: - tmp |= 0x20; - break; - case 11: - tmp |= 0x28; - break; - default: - printk(KERN_ERR "mad16/MOZART: invalid mpu_irq\n"); - return 0; - } - - switch (hw_config->io_base) - { - case 0x300: - tmp |= 0x01; - break; - case 0x310: - tmp |= 0x03; - break; - case 0x320: - tmp |= 0x05; - break; - case 0x330: - tmp |= 0x07; - break; - default: - printk(KERN_ERR "mad16/MOZART: invalid mpu_io\n"); - return 0; - } - - mad_write(MC8_PORT, tmp); /* write MPU port parameters */ - goto probe_401; -#endif - } - tmp = mad_read(MC6_PORT) & 0x83; - tmp |= 0x80; /* MPU-401 enable */ - - /* Set the MPU base bits */ - - switch (hw_config->io_base) - { - case 0x300: - tmp |= 0x60; - break; - case 0x310: - tmp |= 0x40; - break; - case 0x320: - tmp |= 0x20; - break; - case 0x330: - tmp |= 0x00; - break; - default: - printk(KERN_ERR "MAD16: Invalid MIDI port 0x%x\n", hw_config->io_base); - return 0; - } - - /* Set the MPU IRQ bits */ - - switch (hw_config->irq) - { - case 5: - tmp |= 0x10; - break; - case 7: - tmp |= 0x18; - break; - case 9: - tmp |= 0x00; - break; - case 10: - tmp |= 0x08; - break; - default: - printk(KERN_ERR "MAD16: Invalid MIDI IRQ %d\n", hw_config->irq); - break; - } - - mad_write(MC6_PORT, tmp); /* Write MPU401 config */ - -#ifndef CONFIG_MAD16_OLDCARD -probe_401: -#endif - hw_config->driver_use_1 = SB_MIDI_ONLY; - hw_config->name = "Mad16/Mozart"; - return probe_uart401(hw_config, THIS_MODULE); -} - -static void __exit unload_mad16(struct address_info *hw_config) -{ - ad1848_unload(hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - hw_config->dma2, 0); - release_region(hw_config->io_base, 4); - sound_unload_audiodev(hw_config->slots[0]); -} - -static void __exit unload_mad16_mpu(struct address_info *hw_config) -{ -#ifdef CONFIG_MAD16_OLDCARD - if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { - sb_dsp_unload(hw_config, 0); - return; - } -#endif - - unload_uart401(hw_config); -} - -static struct address_info cfg; -static struct address_info cfg_mpu; - -static int found_mpu; - -static int __initdata mpu_io = 0; -static int __initdata mpu_irq = 0; -static int __initdata io = -1; -static int __initdata dma = -1; -static int __initdata dma16 = -1; /* Set this for modules that need it */ -static int __initdata irq = -1; -static int __initdata cdtype = 0; -static int __initdata cdirq = 0; -static int __initdata cdport = 0x340; -static int __initdata cddma = -1; -static int __initdata opl4 = 0; -static int __initdata joystick = 0; - -module_param(mpu_io, int, 0); -module_param(mpu_irq, int, 0); -module_param(io, int, 0); -module_param(dma, int, 0); -module_param(dma16, int, 0); -module_param(irq, int, 0); -module_param(cdtype, int, 0); -module_param(cdirq, int, 0); -module_param(cdport, int, 0); -module_param(cddma, int, 0); -module_param(opl4, int, 0); -module_param(joystick, bool, 0); -module_param(debug, bool, 0644); - -static int __initdata dma_map[2][8] = -{ - {0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02}, - {0x03, -1, 0x01, 0x00, -1, -1, -1, -1} -}; - -static int __initdata irq_map[16] = -{ - 0x00, -1, -1, 0x0A, - -1, 0x04, -1, 0x08, - -1, 0x10, 0x14, 0x18, - -1, -1, -1, -1 -}; - -#ifdef SUPPORT_JOYSTICK - -static struct gameport *gameport; - -static int __devinit mad16_register_gameport(int io_port) -{ - if (!request_region(io_port, 1, "mad16 gameport")) { - printk(KERN_ERR "mad16: gameport address 0x%#x already in use\n", io_port); - return -EBUSY; - } - - gameport = gameport_allocate_port(); - if (!gameport) { - printk(KERN_ERR "mad16: can not allocate memory for gameport\n"); - release_region(io_port, 1); - return -ENOMEM; - } - - gameport_set_name(gameport, "MAD16 Gameport"); - gameport_set_phys(gameport, "isa%04x/gameport0", io_port); - gameport->io = io_port; - - gameport_register_port(gameport); - - return 0; -} - -static inline void mad16_unregister_gameport(void) -{ - if (gameport) { - /* the gameport was initialized so we must free it up */ - gameport_unregister_port(gameport); - gameport = NULL; - release_region(0x201, 1); - } -} -#else -static inline int mad16_register_gameport(int io_port) { return -ENOSYS; } -static inline void mad16_unregister_gameport(void) { } -#endif - -static int __devinit init_mad16(void) -{ - int dmatype = 0; - - printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - - printk(KERN_INFO "CDROM "); - switch (cdtype) - { - case 0x00: - printk("Disabled"); - cdirq = 0; - break; - case 0x02: - printk("Sony CDU31A"); - dmatype = 1; - if(cddma == -1) cddma = 3; - break; - case 0x04: - printk("Mitsumi"); - dmatype = 0; - if(cddma == -1) cddma = 5; - break; - case 0x06: - printk("Panasonic Lasermate"); - dmatype = 1; - if(cddma == -1) cddma = 3; - break; - case 0x08: - printk("Secondary IDE"); - dmatype = 0; - if(cddma == -1) cddma = 5; - break; - case 0x0A: - printk("Primary IDE"); - dmatype = 0; - if(cddma == -1) cddma = 5; - break; - default: - printk("\n"); - printk(KERN_ERR "Invalid CDROM type\n"); - return -EINVAL; - } - - /* - * Build the config words - */ - - mad16_conf = (joystick ^ 1) | cdtype; - mad16_cdsel = 0; - if (opl4) - mad16_cdsel |= 0x20; - - if(cdtype){ - if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1) - { - printk("\n"); - printk(KERN_ERR "Invalid CDROM DMA\n"); - return -EINVAL; - } - if (cddma) - printk(", DMA %d", cddma); - else - printk(", no DMA"); - - if (!cdirq) - printk(", no IRQ"); - else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1) - { - printk(", invalid IRQ (disabling)"); - cdirq = 0; - } - else printk(", IRQ %d", cdirq); - - mad16_cdsel |= dma_map[dmatype][cddma]; - - if (cdtype < 0x08) - { - switch (cdport) - { - case 0x340: - mad16_cdsel |= 0x00; - break; - case 0x330: - mad16_cdsel |= 0x40; - break; - case 0x360: - mad16_cdsel |= 0x80; - break; - case 0x320: - mad16_cdsel |= 0xC0; - break; - default: - printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport); - return -EINVAL; - } - } - mad16_cdsel |= irq_map[cdirq]; - } - - printk(".\n"); - - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma16; - - if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { - printk(KERN_ERR "I/O, DMA and irq are mandatory\n"); - return -EINVAL; - } - - if (!request_region(MC0_PORT, 12, "mad16")) - return -EBUSY; - - if (!probe_mad16(&cfg)) { - release_region(MC0_PORT, 12); - return -ENODEV; - } - - cfg_mpu.io_base = mpu_io; - cfg_mpu.irq = mpu_irq; - - found_mpu = probe_mad16_mpu(&cfg_mpu); - - if (joystick) - mad16_register_gameport(0x201); - - return 0; -} - -static void __exit cleanup_mad16(void) -{ - if (found_mpu) - unload_mad16_mpu(&cfg_mpu); - mad16_unregister_gameport(); - unload_mad16(&cfg); - release_region(MC0_PORT, 12); -} - -module_init(init_mad16); -module_exit(cleanup_mad16); - -#ifndef MODULE -static int __init setup_mad16(char *str) -{ - /* io, irq */ - int ints[8]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma16 = ints[4]; - mpu_io = ints[5]; - mpu_irq = ints[6]; - joystick = ints[7]; - - return 1; -} - -__setup("mad16=", setup_mad16); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c deleted file mode 100644 index 1d98d100d739..000000000000 --- a/sound/oss/maestro.c +++ /dev/null @@ -1,3686 +0,0 @@ -/***************************************************************************** - * - * ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.[23].x - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * (c) Copyright 1999 Alan Cox - * - * Based heavily on SonicVibes.c: - * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * Heavily modified by Zach Brown based on lunch - * with ESS engineers. Many thanks to Howard Kim for providing - * contacts and hardware. Honorable mention goes to Eric - * Brombaugh for all sorts of things. Best regards to the - * proprietors of Hack Central for fine lodging. - * - * Supported devices: - * /dev/dsp0-3 standard /dev/dsp device, (mostly) OSS compatible - * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible - * - * Hardware Description - * - * A working Maestro setup contains the Maestro chip wired to a - * codec or 2. In the Maestro we have the APUs, the ASSP, and the - * Wavecache. The APUs can be though of as virtual audio routing - * channels. They can take data from a number of sources and perform - * basic encodings of the data. The wavecache is a storehouse for - * PCM data. Typically it deals with PCI and interracts with the - * APUs. The ASSP is a wacky DSP like device that ESS is loth - * to release docs on. Thankfully it isn't required on the Maestro - * until you start doing insane things like FM emulation and surround - * encoding. The codecs are almost always AC-97 compliant codecs, - * but it appears that early Maestros may have had PT101 (an ESS - * part?) wired to them. The only real difference in the Maestro - * families is external goop like docking capability, memory for - * the ASSP, and initialization differences. - * - * Driver Operation - * - * We only drive the APU/Wavecache as typical DACs and drive the - * mixers in the codecs. There are 64 APUs. We assign 6 to each - * /dev/dsp? device. 2 channels for output, and 4 channels for - * input. - * - * Each APU can do a number of things, but we only really use - * 3 basic functions. For playback we use them to convert PCM - * data fetched over PCI by the wavecahche into analog data that - * is handed to the codec. One APU for mono, and a pair for stereo. - * When in stereo, the combination of smarts in the APU and Wavecache - * decide which wavecache gets the left or right channel. - * - * For record we still use the old overly mono system. For each in - * coming channel the data comes in from the codec, through a 'input' - * APU, through another rate converter APU, and then into memory via - * the wavecache and PCI. If its stereo, we mash it back into LRLR in - * software. The pass between the 2 APUs is supposedly what requires us - * to have a 512 byte buffer sitting around in wavecache/memory. - * - * The wavecache makes our life even more fun. First off, it can - * only address the first 28 bits of PCI address space, making it - * useless on quite a few architectures. Secondly, its insane. - * It claims to fetch from 4 regions of PCI space, each 4 meg in length. - * But that doesn't really work. You can only use 1 region. So all our - * allocations have to be in 4meg of each other. Booo. Hiss. - * So we have a module parameter, dsps_order, that is the order of - * the number of dsps to provide. All their buffer space is allocated - * on open time. The sonicvibes OSS routines we inherited really want - * power of 2 buffers, so we have all those next to each other, then - * 512 byte regions for the recording wavecaches. This ends up - * wasting quite a bit of memory. The only fixes I can see would be - * getting a kernel allocator that could work in zones, or figuring out - * just how to coerce the WP into doing what we want. - * - * The indirection of the various registers means we have to spinlock - * nearly all register accesses. We have the main register indirection - * like the wave cache, maestro registers, etc. Then we have beasts - * like the APU interface that is indirect registers gotten at through - * the main maestro indirection. Ouch. We spinlock around the actual - * ports on a per card basis. This means spinlock activity at each IO - * operation, but the only IO operation clusters are in non critical - * paths and it makes the code far easier to follow. Interrupts are - * blocked while holding the locks because the int handler has to - * get at some of them :(. The mixer interface doesn't, however. - * We also have an OSS state lock that is thrown around in a few - * places. - * - * This driver has brute force APM suspend support. We catch suspend - * notifications and stop all work being done on the chip. Any people - * that try between this shutdown and the real suspend operation will - * be put to sleep. When we resume we restore our software state on - * the chip and wake up the people that were using it. The code thats - * being used now is quite dirty and assumes we're on a uni-processor - * machine. Much of it will need to be cleaned up for SMP ACPI or - * similar. - * - * We also pay attention to PCI power management now. The driver - * will power down units of the chip that it knows aren't needed. - * The WaveProcessor and company are only powered on when people - * have /dev/dsp*s open. On removal the driver will - * power down the maestro entirely. There could still be - * trouble with BIOSen that magically change power states - * themselves, but we'll see. - * - * History - * v0.15 - May 21 2001 - Marcus Meissner - * Ported to Linux 2.4 PCI API. Some clean ups, global devs list - * removed (now using pci device driver data). - * PM needs to be polished still. Bumped version. - * (still kind of v0.14) May 13 2001 - Ben Pfaff - * Add support for 978 docking and basic hardware volume control - * (still kind of v0.14) Nov 23 - Alan Cox - * Add clocking= for people with seriously warped hardware - * (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz - * add __init to maestro_ac97_init() and maestro_install() - * (still based on v0.14) Mar 29 2000 - Zach Brown - * move to 2.3 power management interface, which - * required hacking some suspend/resume/check paths - * make static compilation work - * v0.14 - Jan 28 2000 - Zach Brown - * add PCI power management through ACPI regs. - * we now shut down on machine reboot/halt - * leave scary PCI config items alone (isa stuff, mostly) - * enable 1921s, it seems only mine was broke. - * fix swapped left/right pcm dac. har har. - * up bob freq, increase buffers, fix pointers at underflow - * silly compilation problems - * v0.13 - Nov 18 1999 - Zach Brown - * fix nec Versas? man would that be cool. - * v0.12 - Nov 12 1999 - Zach Brown - * brown bag volume max fix.. - * v0.11 - Nov 11 1999 - Zach Brown - * use proper stereo apu decoding, mmap/write should work. - * make volume sliders more useful, tweak rate calculation. - * fix lame 8bit format reporting bug. duh. apm apu saving buglet also - * fix maestro 1 clock freq "bug", remove pt101 support - * v0.10 - Oct 28 1999 - Zach Brown - * aha, so, sometimes the WP writes a status word to offset 0 - * from one of the PCMBARs. rearrange allocation accordingly.. - * cheers again to Eric for being a good hacker in investigating this. - * Jeroen Hoogervorst submits 7500 fix out of nowhere. yay. :) - * v0.09 - Oct 23 1999 - Zach Brown - * added APM support. - * re-order something such that some 2Es now work. Magic! - * new codec reset routine. made some codecs come to life. - * fix clear_advance, sync some control with ESS. - * now write to all base regs to be paranoid. - * v0.08 - Oct 20 1999 - Zach Brown - * Fix initial buflen bug. I am so smart. also smp compiling.. - * I owe Eric yet another beer: fixed recmask, igain, - * muting, and adc sync consistency. Go Team. - * v0.07 - Oct 4 1999 - Zach Brown - * tweak adc/dac, formating, and stuff to allow full duplex - * allocate dsps memory at open() so we can fit in the wavecache window - * fix wavecache braindamage. again. no more scribbling? - * fix ess 1921 codec bug on some laptops. - * fix dumb pci scanning bug - * started 2.3 cleanup, redid spinlocks, little cleanups - * v0.06 - Sep 20 1999 - Zach Brown - * fix wavecache thinkos. limit to 1 /dev/dsp. - * eric is wearing his thinking toque this week. - * spotted apu mode bugs and gain ramping problem - * don't touch weird mixer regs, make recmask optional - * fixed igain inversion, defaults for mixers, clean up rec_start - * make mono recording work. - * report subsystem stuff, please send reports. - * littles: parallel out, amp now - * v0.05 - Sep 17 1999 - Zach Brown - * merged and fixed up Eric's initial recording code - * munged format handling to catch misuse, needs rewrite. - * revert ring bus init, fixup shared int, add pci busmaster setting - * fix mixer oss interface, fix mic mute and recmask - * mask off unsupported mixers, reset with all 1s, modularize defaults - * make sure bob is running while we need it - * got rid of device limit, initial minimal apm hooks - * pull out dead code/includes, only allow multimedia/audio maestros - * v0.04 - Sep 01 1999 - Zach Brown - * copied memory leak fix from sonicvibes driver - * different ac97 reset, play with 2.0 ac97, simplify ring bus setup - * bob freq code, region sanity, jitter sync fix; all from Eric - * - * TODO - * fix bob frequency - * endianness - * do smart things with ac97 2.0 bits. - * dual codecs - * leave 54->61 open - * - * it also would be fun to have a mode that would not use pci dma at all - * but would copy into the wavecache on board memory and use that - * on architectures that don't like the maestro's pci dma ickiness. - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include - -#include "maestro.h" - -static struct pci_driver maestro_pci_driver; - -/* --------------------------------------------------------------------- */ - -#define M_DEBUG 1 - -#ifdef M_DEBUG -static int debug; -#define M_printk(args...) {if (debug) printk(args);} -#else -#define M_printk(x) -#endif - -/* we try to setup 2^(dsps_order) /dev/dsp devices */ -static int dsps_order; -/* whether or not we mess around with power management */ -static int use_pm=2; /* set to 1 for force */ -/* clocking for broken hardware - a few laptops seem to use a 50Khz clock - ie insmod with clocking=50000 or so */ - -static int clocking=48000; - -MODULE_AUTHOR("Zach Brown , Alan Cox "); -MODULE_DESCRIPTION("ESS Maestro Driver"); -MODULE_LICENSE("GPL"); - -#ifdef M_DEBUG -module_param(debug, bool, 0644); -#endif -module_param(dsps_order, int, 0); -module_param(use_pm, int, 0); -module_param(clocking, int, 0); - -/* --------------------------------------------------------------------- */ -#define DRIVER_VERSION "0.15" - -#ifndef PCI_VENDOR_ESS -#define PCI_VENDOR_ESS 0x125D -#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ -#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ - -#define PCI_VENDOR_ESS_OLD 0x1285 /* Platform Tech, - the people the maestro - was bought from */ -#define PCI_DEVICE_ID_ESS_ESS0100 0x0100 /* maestro 1 */ -#endif /* PCI_VENDOR_ESS */ - -#define ESS_CHAN_HARD 0x100 - -/* NEC Versas ? */ -#define NEC_VERSA_SUBID1 0x80581033 -#define NEC_VERSA_SUBID2 0x803c1033 - - -/* changed so that I could actually find all the - references and fix them up. it's a little more readable now. */ -#define ESS_FMT_STEREO 0x01 -#define ESS_FMT_16BIT 0x02 -#define ESS_FMT_MASK 0x03 -#define ESS_DAC_SHIFT 0 -#define ESS_ADC_SHIFT 4 - -#define ESS_STATE_MAGIC 0x125D1968 -#define ESS_CARD_MAGIC 0x19283746 - -#define DAC_RUNNING 1 -#define ADC_RUNNING 2 - -#define MAX_DSP_ORDER 2 -#define MAX_DSPS (1<src buffer page */ - void *mixbuf; - -}; - -struct ess_card { - unsigned int magic; - - /* We keep maestro cards in a linked list */ - struct ess_card *next; - - int dev_mixer; - - int card_type; - - /* as most of this is static, - perhaps it should be a pointer to a global struct */ - struct mixer_goo { - int modcnt; - int supported_mixers; - int stereo_mixers; - int record_sources; - /* the caller must guarantee arg sanity before calling these */ -/* int (*read_mixer)(struct ess_card *card, int index);*/ - void (*write_mixer)(struct ess_card *card,int mixer, unsigned int left,unsigned int right); - int (*recmask_io)(struct ess_card *card,int rw,int mask); - unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; - } mix; - - int power_regs; - - int in_suspend; - wait_queue_head_t suspend_queue; - - struct ess_state channels[MAX_DSPS]; - u16 maestro_map[NR_IDRS]; /* Register map */ - /* we have to store this junk so that we can come back from a - suspend */ - u16 apu_map[NR_APUS][NR_APU_REGS]; /* contents of apu regs */ - - /* this locks around the physical registers on the card */ - spinlock_t lock; - - /* memory for this card.. wavecache limited :(*/ - void *dmapages; - int dmaorder; - - /* hardware resources */ - struct pci_dev *pcidev; - u32 iobase; - u32 irq; - - int bob_freq; - char dsps_open; - - int dock_mute_vol; -}; - -static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val ); - -static unsigned -ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - - -/* --------------------------------------------------------------------- */ - -static void check_suspend(struct ess_card *card); - -/* --------------------------------------------------------------------- */ - - -/* - * ESS Maestro AC97 codec programming interface. - */ - -static void maestro_ac97_set(struct ess_card *card, u8 cmd, u16 val) -{ - int io = card->iobase; - int i; - /* - * Wait for the codec bus to be free - */ - - check_suspend(card); - - for(i=0;i<10000;i++) - { - if(!(inb(io+ESS_AC97_INDEX)&1)) - break; - } - /* - * Write the bus - */ - outw(val, io+ESS_AC97_DATA); - mdelay(1); - outb(cmd, io+ESS_AC97_INDEX); - mdelay(1); -} - -static u16 maestro_ac97_get(struct ess_card *card, u8 cmd) -{ - int io = card->iobase; - int sanity=10000; - u16 data; - int i; - - check_suspend(card); - /* - * Wait for the codec bus to be free - */ - - for(i=0;i<10000;i++) - { - if(!(inb(io+ESS_AC97_INDEX)&1)) - break; - } - - outb(cmd|0x80, io+ESS_AC97_INDEX); - mdelay(1); - - while(inb(io+ESS_AC97_INDEX)&1) - { - sanity--; - if(!sanity) - { - printk(KERN_ERR "maestro: ac97 codec timeout reading 0x%x.\n",cmd); - return 0; - } - } - data=inw(io+ESS_AC97_DATA); - mdelay(1); - return data; -} - -/* OSS interface to the ac97s.. */ - -#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\ - SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\ - SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN) - -#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \ - SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\ - SOUND_MASK_SPEAKER) - -#define AC97_RECORD_MASK (SOUND_MASK_MIC|\ - SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\ - SOUND_MASK_PHONEIN) - -#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1<offset); - - if(AC97_STEREO_MASK & (1<> 8) & 0x7f; - right = val & 0x7f; - - if (mixer == SOUND_MIXER_IGAIN) { - right = (right * 100) / mh->scale; - left = (left * 100) / mh->scale; - } else { - right = 100 - ((right * 100) / mh->scale); - left = 100 - ((left * 100) / mh->scale); - } - - ret = left | (right << 8); - } else if (mixer == SOUND_MIXER_SPEAKER) { - ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale); - } else if (mixer == SOUND_MIXER_MIC) { - ret = 100 - (((val & 0x1f) * 100) / mh->scale); - /* the low bit is optional in the tone sliders and masking - it lets is avoid the 0xf 'bypass'.. */ - } else if (mixer == SOUND_MIXER_BASS) { - ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale); - } else if (mixer == SOUND_MIXER_TREBLE) { - ret = 100 - (((val & 0xe) * 100) / mh->scale); - } - - M_printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret); - - return ret; -} -#endif - -/* write the OSS encoded volume to the given OSS encoded mixer, - again caller's job to make sure all is well in arg land, - call with spinlock held */ - -/* linear scale -> log */ -static unsigned char lin2log[101] = -{ -0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 , -50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 , -63 , 65 , 66 , 67 , 68 , 69 , 69 , 70 , 71 , -72 , 73 , 73 , 74 , 75 , 75 , 76 , 77 , 77 , -78 , 78 , 79 , 80 , 80 , 81 , 81 , 82 , 82 , -83 , 83 , 84 , 84 , 84 , 85 , 85 , 86 , 86 , -87 , 87 , 87 , 88 , 88 , 88 , 89 , 89 , 89 , -90 , 90 , 90 , 91 , 91 , 91 , 92 , 92 , 92 , -93 , 93 , 93 , 94 , 94 , 94 , 94 , 95 , 95 , -95 , 95 , 96 , 96 , 96 , 96 , 97 , 97 , 97 , -97 , 98 , 98 , 98 , 98 , 99 , 99 , 99 , 99 , 99 -}; - -static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left, unsigned int right) -{ - u16 val=0; - struct ac97_mixer_hw *mh = &ac97_hw[mixer]; - - M_printk("wrote mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right); - - if(AC97_STEREO_MASK & (1<scale) / 100; - left = (left * mh->scale) / 100; - if ((left == 0) && (right == 0)) - val |= 0x8000; - } else if (mixer == SOUND_MIXER_PCM || mixer == SOUND_MIXER_CD) { - /* log conversion seems bad for them */ - if ((left == 0) && (right == 0)) - val = 0x8000; - right = ((100 - right) * mh->scale) / 100; - left = ((100 - left) * mh->scale) / 100; - } else { - /* log conversion for the stereo controls */ - if((left == 0) && (right == 0)) - val = 0x8000; - right = ((100 - lin2log[right]) * mh->scale) / 100; - left = ((100 - lin2log[left]) * mh->scale) / 100; - } - - val |= (left << 8) | right; - - } else if (mixer == SOUND_MIXER_SPEAKER) { - val = (((100 - left) * mh->scale) / 100) << 1; - } else if (mixer == SOUND_MIXER_MIC) { - val = maestro_ac97_get(card, mh->offset) & ~0x801f; - val |= (((100 - left) * mh->scale) / 100); - /* the low bit is optional in the tone sliders and masking - it lets is avoid the 0xf 'bypass'.. */ - } else if (mixer == SOUND_MIXER_BASS) { - val = maestro_ac97_get(card , mh->offset) & ~0x0f00; - val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00; - } else if (mixer == SOUND_MIXER_TREBLE) { - val = maestro_ac97_get(card , mh->offset) & ~0x000f; - val |= (((100 - left) * mh->scale) / 100) & 0x000e; - } - - maestro_ac97_set(card , mh->offset, val); - - M_printk(" -> %x\n",val); -} - -/* the following tables allow us to go from - OSS <-> ac97 quickly. */ - -enum ac97_recsettings { - AC97_REC_MIC=0, - AC97_REC_CD, - AC97_REC_VIDEO, - AC97_REC_AUX, - AC97_REC_LINE, - AC97_REC_STEREO, /* combination of all enabled outputs.. */ - AC97_REC_MONO, /*.. or the mono equivalent */ - AC97_REC_PHONE -}; - -static unsigned int ac97_oss_mask[] = { - [AC97_REC_MIC] = SOUND_MASK_MIC, - [AC97_REC_CD] = SOUND_MASK_CD, - [AC97_REC_VIDEO] = SOUND_MASK_VIDEO, - [AC97_REC_AUX] = SOUND_MASK_LINE1, - [AC97_REC_LINE] = SOUND_MASK_LINE, - [AC97_REC_PHONE] = SOUND_MASK_PHONEIN -}; - -/* indexed by bit position */ -static unsigned int ac97_oss_rm[] = { - [SOUND_MIXER_MIC] = AC97_REC_MIC, - [SOUND_MIXER_CD] = AC97_REC_CD, - [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, - [SOUND_MIXER_LINE1] = AC97_REC_AUX, - [SOUND_MIXER_LINE] = AC97_REC_LINE, - [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE -}; - -/* read or write the recmask - the ac97 can really have left and right recording - inputs independently set, but OSS doesn't seem to - want us to express that to the user. - the caller guarantees that we have a supported bit set, - and they must be holding the card's spinlock */ -static int -ac97_recmask_io(struct ess_card *card, int read, int mask) -{ - unsigned int val = ac97_oss_mask[ maestro_ac97_get(card, 0x1a) & 0x7 ]; - - if (read) return val; - - /* oss can have many inputs, maestro can't. try - to pick the 'new' one */ - - if (mask != val) mask &= ~val; - - val = ffs(mask) - 1; - val = ac97_oss_rm[val]; - val |= val << 8; /* set both channels */ - - M_printk("maestro: setting ac97 recmask to 0x%x\n",val); - - maestro_ac97_set(card,0x1a,val); - - return 0; -}; - -/* - * The Maestro can be wired to a standard AC97 compliant codec - * (see www.intel.com for the pdf's on this), or to a PT101 codec - * which appears to be the ES1918 (data sheet on the esstech.com.tw site) - * - * The PT101 setup is untested. - */ - -static u16 __init maestro_ac97_init(struct ess_card *card) -{ - u16 vend1, vend2, caps; - - card->mix.supported_mixers = AC97_SUPPORTED_MASK; - card->mix.stereo_mixers = AC97_STEREO_MASK; - card->mix.record_sources = AC97_RECORD_MASK; -/* card->mix.read_mixer = ac97_read_mixer;*/ - card->mix.write_mixer = ac97_write_mixer; - card->mix.recmask_io = ac97_recmask_io; - - vend1 = maestro_ac97_get(card, 0x7c); - vend2 = maestro_ac97_get(card, 0x7e); - - caps = maestro_ac97_get(card, 0x00); - - printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x caps: 0x%x pwr: 0x%x\n", - vend1,vend2,caps,maestro_ac97_get(card,0x26) & 0xf); - - if (! (caps & 0x4) ) { - /* no bass/treble nobs */ - card->mix.supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE); - } - - /* XXX endianness, dork head. */ - /* vendor specifc bits.. */ - switch ((long)(vend1 << 16) | vend2) { - case 0x545200ff: /* TriTech */ - /* no idea what this does */ - maestro_ac97_set(card,0x2a,0x0001); - maestro_ac97_set(card,0x2c,0x0000); - maestro_ac97_set(card,0x2c,0xffff); - break; -#if 0 /* i thought the problems I was seeing were with - the 1921, but apparently they were with the pci board - it was on, so this code is commented out. - lets see if this holds true. */ - case 0x83847609: /* ESS 1921 */ - /* writing to 0xe (mic) or 0x1a (recmask) seems - to hang this codec */ - card->mix.supported_mixers &= ~(SOUND_MASK_MIC); - card->mix.record_sources = 0; - card->mix.recmask_io = NULL; -#if 0 /* don't ask. I have yet to see what these actually do. */ - maestro_ac97_set(card,0x76,0xABBA); /* o/~ Take a chance on me o/~ */ - udelay(20); - maestro_ac97_set(card,0x78,0x3002); - udelay(20); - maestro_ac97_set(card,0x78,0x3802); - udelay(20); -#endif - break; -#endif - default: break; - } - - maestro_ac97_set(card, 0x1E, 0x0404); - /* null misc stuff */ - maestro_ac97_set(card, 0x20, 0x0000); - - return 0; -} - -#if 0 /* there has been 1 person on the planet with a pt101 that we - know of. If they care, they can put this back in :) */ -static u16 maestro_pt101_init(struct ess_card *card,int iobase) -{ - printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n"); - /* who knows.. */ - maestro_ac97_set(iobase, 0x2A, 0x0001); - maestro_ac97_set(iobase, 0x2C, 0x0000); - maestro_ac97_set(iobase, 0x2C, 0xFFFF); - maestro_ac97_set(iobase, 0x10, 0x9F1F); - maestro_ac97_set(iobase, 0x12, 0x0808); - maestro_ac97_set(iobase, 0x14, 0x9F1F); - maestro_ac97_set(iobase, 0x16, 0x9F1F); - maestro_ac97_set(iobase, 0x18, 0x0404); - maestro_ac97_set(iobase, 0x1A, 0x0000); - maestro_ac97_set(iobase, 0x1C, 0x0000); - maestro_ac97_set(iobase, 0x02, 0x0404); - maestro_ac97_set(iobase, 0x04, 0x0808); - maestro_ac97_set(iobase, 0x0C, 0x801F); - maestro_ac97_set(iobase, 0x0E, 0x801F); - return 0; -} -#endif - -/* this is very magic, and very slow.. */ -static void -maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev) -{ - u16 save_68; - u16 w; - u32 vend; - - outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38); - outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a); - outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c); - - /* reset the first codec */ - outw(0x0000, ioaddr+0x36); - save_68 = inw(ioaddr+0x68); - pci_read_config_word(pcidev, 0x58, &w); /* something magical with gpio and bus arb. */ - pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &vend); - if( w & 0x1) - save_68 |= 0x10; - outw(0xfffe, ioaddr + 0x64); /* tickly gpio 0.. */ - outw(0x0001, ioaddr + 0x68); - outw(0x0000, ioaddr + 0x60); - udelay(20); - outw(0x0001, ioaddr + 0x60); - mdelay(20); - - outw(save_68 | 0x1, ioaddr + 0x68); /* now restore .. */ - outw( (inw(ioaddr + 0x38) & 0xfffc)|0x1, ioaddr + 0x38); - outw( (inw(ioaddr + 0x3a) & 0xfffc)|0x1, ioaddr + 0x3a); - outw( (inw(ioaddr + 0x3c) & 0xfffc)|0x1, ioaddr + 0x3c); - - /* now the second codec */ - outw(0x0000, ioaddr+0x36); - outw(0xfff7, ioaddr + 0x64); - save_68 = inw(ioaddr+0x68); - outw(0x0009, ioaddr + 0x68); - outw(0x0001, ioaddr + 0x60); - udelay(20); - outw(0x0009, ioaddr + 0x60); - mdelay(500); /* .. ouch.. */ - outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38); - outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a); - outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c); - -#if 0 /* the loop here needs to be much better if we want it.. */ - M_printk("trying software reset\n"); - /* try and do a software reset */ - outb(0x80|0x7c, ioaddr + 0x30); - for (w=0; ; w++) { - if ((inw(ioaddr+ 0x30) & 1) == 0) { - if(inb(ioaddr + 0x32) !=0) break; - - outb(0x80|0x7d, ioaddr + 0x30); - if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break; - outb(0x80|0x7f, ioaddr + 0x30); - if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break; - } - - if( w > 10000) { - outb( inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37); /* do a software reset */ - mdelay(500); /* oh my.. */ - outb( inb(ioaddr + 0x37) & ~0x08, ioaddr + 0x37); - udelay(1); - outw( 0x80, ioaddr+0x30); - for(w = 0 ; w < 10000; w++) { - if((inw(ioaddr + 0x30) & 1) ==0) break; - } - } - } -#endif - if ( vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) { - /* turn on external amp? */ - outw(0xf9ff, ioaddr + 0x64); - outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68); - outw(0x0209, ioaddr + 0x60); - } - - /* Turn on the 978 docking chip. - First frob the "master output enable" bit, - then set most of the playback volume control registers to max. */ - outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0); - outb(0xff, ioaddr+0xc3); - outb(0xff, ioaddr+0xc4); - outb(0xff, ioaddr+0xc6); - outb(0xff, ioaddr+0xc8); - outb(0x3f, ioaddr+0xcf); - outb(0x3f, ioaddr+0xd0); -} -/* - * Indirect register access. Not all registers are readable so we - * need to keep register state ourselves - */ - -#define WRITEABLE_MAP 0xEFFFFF -#define READABLE_MAP 0x64003F - -/* - * The Maestro engineers were a little indirection happy. These indirected - * registers themselves include indirect registers at another layer - */ - -static void __maestro_write(struct ess_card *card, u16 reg, u16 data) -{ - long ioaddr = card->iobase; - - outw(reg, ioaddr+0x02); - outw(data, ioaddr+0x00); - if( reg >= NR_IDRS) printk("maestro: IDR %d out of bounds!\n",reg); - else card->maestro_map[reg]=data; - -} - -static void maestro_write(struct ess_state *s, u16 reg, u16 data) -{ - unsigned long flags; - - check_suspend(s->card); - spin_lock_irqsave(&s->card->lock,flags); - - __maestro_write(s->card,reg,data); - - spin_unlock_irqrestore(&s->card->lock,flags); -} - -static u16 __maestro_read(struct ess_card *card, u16 reg) -{ - long ioaddr = card->iobase; - - outw(reg, ioaddr+0x02); - return card->maestro_map[reg]=inw(ioaddr+0x00); -} - -static u16 maestro_read(struct ess_state *s, u16 reg) -{ - if(READABLE_MAP & (1<card); - spin_lock_irqsave(&s->card->lock,flags); - - __maestro_read(s->card,reg); - - spin_unlock_irqrestore(&s->card->lock,flags); - } - return s->card->maestro_map[reg]; -} - -/* - * These routines handle accessing the second level indirections to the - * wave ram. - */ - -/* - * The register names are the ones ESS uses (see 104T31.ZIP) - */ - -#define IDR0_DATA_PORT 0x00 -#define IDR1_CRAM_POINTER 0x01 -#define IDR2_CRAM_DATA 0x02 -#define IDR3_WAVE_DATA 0x03 -#define IDR4_WAVE_PTR_LOW 0x04 -#define IDR5_WAVE_PTR_HI 0x05 -#define IDR6_TIMER_CTRL 0x06 -#define IDR7_WAVE_ROMRAM 0x07 - -static void apu_index_set(struct ess_card *card, u16 index) -{ - int i; - __maestro_write(card, IDR1_CRAM_POINTER, index); - for(i=0;i<1000;i++) - if(__maestro_read(card, IDR1_CRAM_POINTER)==index) - return; - printk(KERN_WARNING "maestro: APU register select failed.\n"); -} - -static void apu_data_set(struct ess_card *card, u16 data) -{ - int i; - for(i=0;i<1000;i++) - { - if(__maestro_read(card, IDR0_DATA_PORT)==data) - return; - __maestro_write(card, IDR0_DATA_PORT, data); - } -} - -/* - * This is the public interface for APU manipulation. It handles the - * interlock to avoid two APU writes in parallel etc. Don't diddle - * directly with the stuff above. - */ - -static void apu_set_register(struct ess_state *s, u16 channel, u8 reg, u16 data) -{ - unsigned long flags; - - check_suspend(s->card); - - if(channel&ESS_CHAN_HARD) - channel&=~ESS_CHAN_HARD; - else - { - if(channel>5) - printk("BAD CHANNEL %d.\n",channel); - else - channel = s->apu[channel]; - /* store based on real hardware apu/reg */ - s->card->apu_map[channel][reg]=data; - } - reg|=(channel<<4); - - /* hooray for double indirection!! */ - spin_lock_irqsave(&s->card->lock,flags); - - apu_index_set(s->card, reg); - apu_data_set(s->card, data); - - spin_unlock_irqrestore(&s->card->lock,flags); -} - -static u16 apu_get_register(struct ess_state *s, u16 channel, u8 reg) -{ - unsigned long flags; - u16 v; - - check_suspend(s->card); - - if(channel&ESS_CHAN_HARD) - channel&=~ESS_CHAN_HARD; - else - channel = s->apu[channel]; - - reg|=(channel<<4); - - spin_lock_irqsave(&s->card->lock,flags); - - apu_index_set(s->card, reg); - v=__maestro_read(s->card, IDR0_DATA_PORT); - - spin_unlock_irqrestore(&s->card->lock,flags); - return v; -} - - -/* - * The wavecache buffers between the APUs and - * pci bus mastering - */ - -static void wave_set_register(struct ess_state *s, u16 reg, u16 value) -{ - long ioaddr = s->card->iobase; - unsigned long flags; - check_suspend(s->card); - - spin_lock_irqsave(&s->card->lock,flags); - - outw(reg, ioaddr+0x10); - outw(value, ioaddr+0x12); - - spin_unlock_irqrestore(&s->card->lock,flags); -} - -static u16 wave_get_register(struct ess_state *s, u16 reg) -{ - long ioaddr = s->card->iobase; - unsigned long flags; - u16 value; - check_suspend(s->card); - - spin_lock_irqsave(&s->card->lock,flags); - outw(reg, ioaddr+0x10); - value=inw(ioaddr+0x12); - spin_unlock_irqrestore(&s->card->lock,flags); - - return value; -} - -static void sound_reset(int ioaddr) -{ - outw(0x2000, 0x18+ioaddr); - udelay(1); - outw(0x0000, 0x18+ioaddr); - udelay(1); -} - -/* sets the play formats of these apus, should be passed the already shifted format */ -static void set_apu_fmt(struct ess_state *s, int apu, int mode) -{ - int apu_fmt = 0x10; - - if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20; - if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10; - s->apu_mode[apu] = apu_fmt; - s->apu_mode[apu+1] = apu_fmt; -} - -/* this only fixes the output apu mode to be later set by start_dac and - company. output apu modes are set in ess_rec_setup */ -static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data) -{ - s->fmt = (s->fmt & mask) | data; - set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK); -} - -/* this is off by a little bit.. */ -static u32 compute_rate(struct ess_state *s, u32 freq) -{ - u32 clock = clock_freq[s->card->card_type]; - - freq = (freq * clocking)/48000; - - if (freq == 48000) - return 0x10000; - - return ((freq / clock) <<16 )+ - (((freq % clock) << 16) / clock); -} - -static void set_dac_rate(struct ess_state *s, unsigned int rate) -{ - u32 freq; - int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK; - - if (rate > 48000) - rate = 48000; - if (rate < 4000) - rate = 4000; - - s->ratedac = rate; - - if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO)) - rate >>= 1; - -/* M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/ - - freq = compute_rate(s, rate); - - /* Load the frequency, turn on 6dB */ - apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 0, 3, freq>>8); - apu_set_register(s, 1, 2,(apu_get_register(s, 1, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 1, 3, freq>>8); -} - -static void set_adc_rate(struct ess_state *s, unsigned rate) -{ - u32 freq; - - /* Sample Rate conversion APUs don't like 0x10000 for their rate */ - if (rate > 47999) - rate = 47999; - if (rate < 4000) - rate = 4000; - - s->rateadc = rate; - - freq = compute_rate(s, rate); - - /* Load the frequency, turn on 6dB */ - apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 2, 3, freq>>8); - apu_set_register(s, 3, 2,(apu_get_register(s, 3, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 3, 3, freq>>8); - - /* fix mixer rate at 48khz. and its _must_ be 0x10000. */ - freq = 0x10000; - - apu_set_register(s, 4, 2,(apu_get_register(s, 4, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 4, 3, freq>>8); - apu_set_register(s, 5, 2,(apu_get_register(s, 5, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 5, 3, freq>>8); -} - -/* Stop our host of recording apus */ -static inline void stop_adc(struct ess_state *s) -{ - /* XXX lets hope we don't have to lock around this */ - if (! (s->enable & ADC_RUNNING)) return; - - s->enable &= ~ADC_RUNNING; - apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F); - apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F); - apu_set_register(s, 4, 0, apu_get_register(s, 2, 0)&0xFF0F); - apu_set_register(s, 5, 0, apu_get_register(s, 3, 0)&0xFF0F); -} - -/* stop output apus */ -static void stop_dac(struct ess_state *s) -{ - /* XXX have to lock around this? */ - if (! (s->enable & DAC_RUNNING)) return; - - s->enable &= ~DAC_RUNNING; - apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F); - apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F); -} - -static void start_dac(struct ess_state *s) -{ - /* XXX locks? */ - if ( (s->dma_dac.mapped || s->dma_dac.count > 0) && - s->dma_dac.ready && - (! (s->enable & DAC_RUNNING)) ) { - - s->enable |= DAC_RUNNING; - - apu_set_register(s, 0, 0, - (apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]); - - if((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_STEREO) - apu_set_register(s, 1, 0, - (apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]); - } -} - -static void start_adc(struct ess_state *s) -{ - /* XXX locks? */ - if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) - && s->dma_adc.ready && (! (s->enable & ADC_RUNNING)) ) { - - s->enable |= ADC_RUNNING; - apu_set_register(s, 2, 0, - (apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]); - apu_set_register(s, 4, 0, - (apu_get_register(s, 4, 0)&0xFF0F)|s->apu_mode[4]); - - if( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) { - apu_set_register(s, 3, 0, - (apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]); - apu_set_register(s, 5, 0, - (apu_get_register(s, 5, 0)&0xFF0F)|s->apu_mode[5]); - } - - } -} - - -/* - * Native play back driver - */ - -/* the mode passed should be already shifted and masked */ -static void -ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size) -{ - u32 pa; - u32 tmpval; - int high_apu = 0; - int channel; - - M_printk("mode=%d rate=%d buf=%p len=%d.\n", - mode, rate, buffer, size); - - /* all maestro sizes are in 16bit words */ - size >>=1; - - if(mode&ESS_FMT_STEREO) { - high_apu++; - /* only 16/stereo gets size divided */ - if(mode&ESS_FMT_16BIT) - size>>=1; - } - - for(channel=0; channel <= high_apu; channel++) - { - pa = virt_to_bus(buffer); - - /* set the wavecache control reg */ - tmpval = (pa - 0x10) & 0xFFF8; - if(!(mode & ESS_FMT_16BIT)) tmpval |= 4; - if(mode & ESS_FMT_STEREO) tmpval |= 2; - ess->apu_base[channel]=tmpval; - wave_set_register(ess, ess->apu[channel]<<3, tmpval); - - pa -= virt_to_bus(ess->card->dmapages); - pa>>=1; /* words */ - - /* base offset of dma calcs when reading the pointer - on the left one */ - if(!channel) ess->dma_dac.base = pa&0xFFFF; - - pa|=0x00400000; /* System RAM */ - - /* XXX the 16bit here might not be needed.. */ - if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) { - if(channel) - pa|=0x00800000; /* Stereo */ - pa>>=1; - } - -/* XXX think about endianess when writing these registers */ - M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa); - /* start of sample */ - apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8); - apu_set_register(ess, channel, 5, pa&0xFFFF); - /* sample end */ - apu_set_register(ess, channel, 6, (pa+size)&0xFFFF); - /* setting loop len == sample len */ - apu_set_register(ess, channel, 7, size); - - /* clear effects/env.. */ - apu_set_register(ess, channel, 8, 0x0000); - /* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */ - apu_set_register(ess, channel, 9, 0xD000); - - /* clear routing stuff */ - apu_set_register(ess, channel, 11, 0x0000); - /* dma on, no envelopes, filter to all 1s) */ - apu_set_register(ess, channel, 0, 0x400F); - - if(mode&ESS_FMT_16BIT) - ess->apu_mode[channel]=0x10; - else - ess->apu_mode[channel]=0x30; - - if(mode&ESS_FMT_STEREO) { - /* set panning: left or right */ - apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0 : 0x10)); - ess->apu_mode[channel] += 0x10; - } else - apu_set_register(ess, channel, 10, 0x8F08); - } - - /* clear WP interrupts */ - outw(1, ess->card->iobase+0x04); - /* enable WP ints */ - outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18); - - /* go team! */ - set_dac_rate(ess,rate); - start_dac(ess); -} - -/* - * Native record driver - */ - -/* again, passed mode is alrady shifted/masked */ -static void -ess_rec_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size) -{ - int apu_step = 2; - int channel; - - M_printk("maestro: ess_rec_setup: mode=%d rate=%d buf=0x%p len=%d.\n", - mode, rate, buffer, size); - - /* all maestro sizes are in 16bit words */ - size >>=1; - - /* we're given the full size of the buffer, but - in stereo each channel will only use its half */ - if(mode&ESS_FMT_STEREO) { - size >>=1; - apu_step = 1; - } - - /* APU assignments: 2 = mono/left SRC - 3 = right SRC - 4 = mono/left Input Mixer - 5 = right Input Mixer */ - for(channel=2;channel<6;channel+=apu_step) - { - int i; - int bsize, route; - u32 pa; - u32 tmpval; - - /* data seems to flow from the codec, through an apu into - the 'mixbuf' bit of page, then through the SRC apu - and out to the real 'buffer'. ok. sure. */ - - if(channel & 0x04) { - /* ok, we're an input mixer going from adc - through the mixbuf to the other apus */ - - if(!(channel & 0x01)) { - pa = virt_to_bus(ess->mixbuf); - } else { - pa = virt_to_bus(ess->mixbuf + (PAGE_SIZE >> 4)); - } - - /* we source from a 'magic' apu */ - bsize = PAGE_SIZE >> 5; /* half of this channels alloc, in words */ - route = 0x14 + (channel - 4); /* parallel in crap, see maestro reg 0xC [8-11] */ - ess->apu_mode[channel] = 0x90; /* Input Mixer */ - - } else { - /* we're a rate converter taking - input from the input apus and outputing it to - system memory */ - if(!(channel & 0x01)) { - pa = virt_to_bus(buffer); - } else { - /* right channel records its split half. - *2 accommodates for rampant shifting earlier */ - pa = virt_to_bus(buffer + size*2); - } - - ess->apu_mode[channel] = 0xB0; /* Sample Rate Converter */ - - bsize = size; - /* get input from inputing apu */ - route = channel + 2; - } - - M_printk("maestro: ess_rec_setup: getting pa 0x%x from %d\n",pa,channel); - - /* set the wavecache control reg */ - tmpval = (pa - 0x10) & 0xFFF8; - ess->apu_base[channel]=tmpval; - wave_set_register(ess, ess->apu[channel]<<3, tmpval); - - pa -= virt_to_bus(ess->card->dmapages); - pa>>=1; /* words */ - - /* base offset of dma calcs when reading the pointer - on this left one */ - if(channel==2) ess->dma_adc.base = pa&0xFFFF; - - pa|=0x00400000; /* bit 22 -> System RAM */ - - M_printk("maestro: ess_rec_setup: APU[%d] pa = 0x%x size = 0x%x route = 0x%x\n", - ess->apu[channel], pa, bsize, route); - - /* Begin loading the APU */ - for(i=0;i<15;i++) /* clear all PBRs */ - apu_set_register(ess, channel, i, 0x0000); - - apu_set_register(ess, channel, 0, 0x400F); - - /* need to enable subgroups.. and we should probably - have different groups for different /dev/dsps.. */ - apu_set_register(ess, channel, 2, 0x8); - - /* Load the buffer into the wave engine */ - apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8); - /* XXX reg is little endian.. */ - apu_set_register(ess, channel, 5, pa&0xFFFF); - apu_set_register(ess, channel, 6, (pa+bsize)&0xFFFF); - apu_set_register(ess, channel, 7, bsize); - - /* clear effects/env.. */ - apu_set_register(ess, channel, 8, 0x00F0); - - /* amplitude now? sure. why not. */ - apu_set_register(ess, channel, 9, 0x0000); - - /* set filter tune, radius, polar pan */ - apu_set_register(ess, channel, 10, 0x8F08); - - /* route input */ - apu_set_register(ess, channel, 11, route); - } - - /* clear WP interrupts */ - outw(1, ess->card->iobase+0x04); - /* enable WP ints */ - outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18); - - /* let 'er rip */ - set_adc_rate(ess,rate); - start_adc(ess); -} -/* --------------------------------------------------------------------- */ - -static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count) -{ - M_printk("set_dmaa??\n"); -} - -static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count) -{ - M_printk("set_dmac??\n"); -} - -/* Playback pointer */ -static inline unsigned get_dmaa(struct ess_state *s) -{ - int offset; - - offset = apu_get_register(s,0,5); - -/* M_printk("dmaa: offset: %d, base: %d\n",offset,s->dma_dac.base); */ - - offset-=s->dma_dac.base; - - return (offset&0xFFFE)<<1; /* hardware is in words */ -} - -/* Record pointer */ -static inline unsigned get_dmac(struct ess_state *s) -{ - int offset; - - offset = apu_get_register(s,2,5); - -/* M_printk("dmac: offset: %d, base: %d\n",offset,s->dma_adc.base); */ - - /* The offset is an address not a position relative to base */ - offset-=s->dma_adc.base; - - return (offset&0xFFFE)<<1; /* hardware is in words */ -} - -/* - * Meet Bob, the timer... - */ - -static irqreturn_t ess_interrupt(int irq, void *dev_id, struct pt_regs *regs); - -static void stop_bob(struct ess_state *s) -{ - /* Mask IDR 11,17 */ - maestro_write(s, 0x11, maestro_read(s, 0x11)&~1); - maestro_write(s, 0x17, maestro_read(s, 0x17)&~1); -} - -/* eventually we could be clever and limit bob ints - to the frequency at which our smallest duration - chunks may expire */ -#define ESS_SYSCLK 50000000 -static void start_bob(struct ess_state *s) -{ - int prescale; - int divide; - - /* XXX make freq selector much smarter, see calc_bob_rate */ - int freq = 200; - - /* compute ideal interrupt frequency for buffer size & play rate */ - /* first, find best prescaler value to match freq */ - for(prescale=5;prescale<12;prescale++) - if(freq > (ESS_SYSCLK>>(prescale+9))) - break; - - /* next, back off prescaler whilst getting divider into optimum range */ - divide=1; - while((prescale > 5) && (divide<32)) - { - prescale--; - divide <<=1; - } - divide>>=1; - - /* now fine-tune the divider for best match */ - for(;divide<31;divide++) - if(freq >= ((ESS_SYSCLK>>(prescale+9))/(divide+1))) - break; - - /* divide = 0 is illegal, but don't let prescale = 4! */ - if(divide == 0) - { - divide++; - if(prescale>5) - prescale--; - } - - maestro_write(s, 6, 0x9000 | (prescale<<5) | divide); /* set reg */ - - /* Now set IDR 11/17 */ - maestro_write(s, 0x11, maestro_read(s, 0x11)|1); - maestro_write(s, 0x17, maestro_read(s, 0x17)|1); -} -/* --------------------------------------------------------------------- */ - -/* this quickly calculates the frequency needed for bob - and sets it if its different than what bob is - currently running at. its called often so - needs to be fairly quick. */ -#define BOB_MIN 50 -#define BOB_MAX 400 -static void calc_bob_rate(struct ess_state *s) { -#if 0 /* this thing tries to set the frequency of bob such that - there are 2 interrupts / buffer walked by the dac/adc. That - is probably very wrong for people who actually care about - mid buffer positioning. it should be calculated as bytes/interrupt - and that needs to be decided :) so for now just use the static 150 - in start_bob.*/ - - unsigned int dac_rate=2,adc_rate=1,newrate; - static int israte=-1; - - if (s->dma_dac.fragsize == 0) dac_rate = BOB_MIN; - else { - dac_rate = (2 * s->ratedac * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) / - (s->dma_dac.fragsize) ; - } - - if (s->dma_adc.fragsize == 0) adc_rate = BOB_MIN; - else { - adc_rate = (2 * s->rateadc * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) / - (s->dma_adc.fragsize) ; - } - - if(dac_rate > adc_rate) newrate = adc_rate; - else newrate=dac_rate; - - if(newrate > BOB_MAX) newrate = BOB_MAX; - else { - if(newrate < BOB_MIN) - newrate = BOB_MIN; - } - - if( israte != newrate) { - printk("dac: %d adc: %d rate: %d\n",dac_rate,adc_rate,israte); - israte=newrate; - } -#endif - -} - -static int -prog_dmabuf(struct ess_state *s, unsigned rec) -{ - struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; - unsigned rate = rec ? s->rateadc : s->ratedac; - unsigned bytepersec; - unsigned bufs; - unsigned char fmt; - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - fmt = s->fmt; - if (rec) { - stop_adc(s); - fmt >>= ESS_ADC_SHIFT; - } else { - stop_dac(s); - fmt >>= ESS_DAC_SHIFT; - } - spin_unlock_irqrestore(&s->lock, flags); - fmt &= ESS_FMT_MASK; - - db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; - - /* this algorithm is a little nuts.. where did /1000 come from? */ - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; - - M_printk("maestro: setup oss: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize); - - memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize); - - spin_lock_irqsave(&s->lock, flags); - if (rec) - ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize); - else - ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize); - - spin_unlock_irqrestore(&s->lock, flags); - db->ready = 1; - - return 0; -} - -static __inline__ void -clear_advance(struct ess_state *s) -{ - unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80; - - unsigned char *buf = s->dma_dac.rawbuf; - unsigned bsize = s->dma_dac.dmasize; - unsigned bptr = s->dma_dac.swptr; - unsigned len = s->dma_dac.fragsize; - - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(buf + bptr, c, x); - /* account for wrapping? */ - bptr = 0; - len -= x; - } - memset(buf + bptr, c, len); -} - -/* call with spinlock held! */ -static void -ess_update_ptr(struct ess_state *s) -{ - unsigned hwptr; - int diff; - - /* update ADC pointer */ - if (s->dma_adc.ready) { - /* oh boy should this all be re-written. everything in the current code paths think - that the various counters/pointers are expressed in bytes to the user but we have - two apus doing stereo stuff so we fix it up here.. it propagates to all the various - counters from here. */ - if ( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) { - hwptr = (get_dmac(s)*2) % s->dma_adc.dmasize; - } else { - hwptr = get_dmac(s) % s->dma_adc.dmasize; - } - diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; - s->dma_adc.hwptr = hwptr; - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - wake_up(&s->dma_adc.wait); - if (!s->dma_adc.mapped) { - if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { - /* FILL ME - wrindir(s, SV_CIENABLE, s->enable); */ - stop_adc(s); - /* brute force everyone back in sync, sigh */ - s->dma_adc.count = 0; - s->dma_adc.swptr = 0; - s->dma_adc.hwptr = 0; - s->dma_adc.error++; - } - } - } - /* update DAC pointer */ - if (s->dma_dac.ready) { - hwptr = get_dmaa(s) % s->dma_dac.dmasize; - /* the apu only reports the length it has seen, not the - length of the memory that has been used (the WP - knows that) */ - if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT)) - hwptr<<=1; - - diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; -/* M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/ - s->dma_dac.hwptr = hwptr; - s->dma_dac.total_bytes += diff; - if (s->dma_dac.mapped) { - s->dma_dac.count += diff; - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) { - wake_up(&s->dma_dac.wait); - } - } else { - s->dma_dac.count -= diff; -/* M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */ - if (s->dma_dac.count <= 0) { - M_printk("underflow! diff: %d count: %d hw: %d sw: %d\n", diff, s->dma_dac.count, - hwptr, s->dma_dac.swptr); - /* FILL ME - wrindir(s, SV_CIENABLE, s->enable); */ - /* XXX how on earth can calling this with the lock held work.. */ - stop_dac(s); - /* brute force everyone back in sync, sigh */ - s->dma_dac.count = 0; - s->dma_dac.swptr = hwptr; - s->dma_dac.error++; - } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { - clear_advance(s); - s->dma_dac.endcleared = 1; - } - if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) { - wake_up(&s->dma_dac.wait); -/* printk("waking up DAC count: %d sw: %d hw: %d\n",s->dma_dac.count, s->dma_dac.swptr, - hwptr);*/ - } - } - } -} - -static irqreturn_t -ess_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct ess_state *s; - struct ess_card *c = (struct ess_card *)dev_id; - int i; - u32 event; - - if ( ! (event = inb(c->iobase+0x1A)) ) - return IRQ_NONE; - - outw(inw(c->iobase+4)&1, c->iobase+4); - -/* M_printk("maestro int: %x\n",event);*/ - if(event&(1<<6)) - { - int x; - enum {UP_EVT, DOWN_EVT, MUTE_EVT} vol_evt; - int volume; - - /* Figure out which volume control button was pushed, - based on differences from the default register - values. */ - x = inb(c->iobase+0x1c); - if (x&1) vol_evt = MUTE_EVT; - else if (((x>>1)&7) > 4) vol_evt = UP_EVT; - else vol_evt = DOWN_EVT; - - /* Reset the volume control registers. */ - outb(0x88, c->iobase+0x1c); - outb(0x88, c->iobase+0x1d); - outb(0x88, c->iobase+0x1e); - outb(0x88, c->iobase+0x1f); - - /* Deal with the button press in a hammer-handed - manner by adjusting the master mixer volume. */ - volume = c->mix.mixer_state[0] & 0xff; - if (vol_evt == UP_EVT) { - volume += 5; - if (volume > 100) - volume = 100; - } - else if (vol_evt == DOWN_EVT) { - volume -= 5; - if (volume < 0) - volume = 0; - } else { - /* vol_evt == MUTE_EVT */ - if (volume == 0) - volume = c->dock_mute_vol; - else { - c->dock_mute_vol = volume; - volume = 0; - } - } - set_mixer (c, 0, (volume << 8) | volume); - } - - /* Ack all the interrupts. */ - outb(0xFF, c->iobase+0x1A); - - /* - * Update the pointers for all APU's we are running. - */ - for(i=0;ichannels[i]; - if(s->dev_audio == -1) - break; - spin_lock(&s->lock); - ess_update_ptr(s); - spin_unlock(&s->lock); - } - return IRQ_HANDLED; -} - - -/* --------------------------------------------------------------------- */ - -static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value in %s\n"; - -#define VALIDATE_MAGIC(FOO,MAG) \ -({ \ - if (!(FOO) || (FOO)->magic != MAG) { \ - printk(invalid_magic,__FUNCTION__); \ - return -ENXIO; \ - } \ -}) - -#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,ESS_STATE_MAGIC) -#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,ESS_CARD_MAGIC) - -static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val ) -{ - unsigned int left,right; - /* cleanse input a little */ - right = ((val >> 8) & 0xff) ; - left = (val & 0xff) ; - - if(right > 100) right = 100; - if(left > 100) left = 100; - - card->mix.mixer_state[mixer]=(right << 8) | left; - card->mix.write_mixer(card,mixer,left,right); -} - -static void -mixer_push_state(struct ess_card *card) -{ - int i; - for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) { - if( ! supported_mixer(card,i)) continue; - - set_mixer(card,i,card->mix.mixer_state[i]); - } -} - -static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long arg) -{ - int i, val=0; - unsigned long flags; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_CARD(card); - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, card_names[card->card_type], sizeof(info.id)); - strlcpy(info.name, card_names[card->card_type], sizeof(info.name)); - info.modify_counter = card->mix.modcnt; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, card_names[card->card_type], sizeof(info.id)); - strlcpy(info.name, card_names[card->card_type], sizeof(info.name)); - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, p); - - if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - - if (_IOC_DIR(cmd) == _IOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* give them the current record source */ - - if(!card->mix.recmask_io) { - val = 0; - } else { - spin_lock_irqsave(&card->lock, flags); - val = card->mix.recmask_io(card,1,0); - spin_unlock_irqrestore(&card->lock, flags); - } - break; - - case SOUND_MIXER_DEVMASK: /* give them the supported mixers */ - val = card->mix.supported_mixers; - break; - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - val = card->mix.record_sources; - break; - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - val = card->mix.stereo_mixers; - break; - - case SOUND_MIXER_CAPS: - val = SOUND_CAP_EXCL_INPUT; - break; - - default: /* read a specific mixer */ - i = _IOC_NR(cmd); - - if ( ! supported_mixer(card,i)) - return -EINVAL; - - /* do we ever want to touch the hardware? */ -/* spin_lock_irqsave(&card->lock, flags); - val = card->mix.read_mixer(card,i); - spin_unlock_irqrestore(&card->lock, flags);*/ - - val = card->mix.mixer_state[i]; -/* M_printk("returned 0x%x for mixer %d\n",val,i);*/ - - break; - } - return put_user(val, p); - } - - if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ)) - return -EINVAL; - - card->mix.modcnt++; - - if (get_user(val, p)) - return -EFAULT; - - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - - if (!card->mix.recmask_io) return -EINVAL; - if(!val) return 0; - if(! (val &= card->mix.record_sources)) return -EINVAL; - - spin_lock_irqsave(&card->lock, flags); - card->mix.recmask_io(card,0,val); - spin_unlock_irqrestore(&card->lock, flags); - return 0; - - default: - i = _IOC_NR(cmd); - - if ( ! supported_mixer(card,i)) - return -EINVAL; - - spin_lock_irqsave(&card->lock, flags); - set_mixer(card,i,val); - spin_unlock_irqrestore(&card->lock, flags); - - return 0; - } -} - -/* --------------------------------------------------------------------- */ -static int ess_open_mixdev(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct ess_card *card = NULL; - struct pci_dev *pdev = NULL; - struct pci_driver *drvr; - - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - drvr = pci_dev_driver (pdev); - if (drvr == &maestro_pci_driver) { - card = (struct ess_card*)pci_get_drvdata (pdev); - if (!card) - continue; - if (card->dev_mixer == minor) - break; - } - } - if (!card) - return -ENODEV; - file->private_data = card; - return nonseekable_open(inode, file); -} - -static int ess_release_mixdev(struct inode *inode, struct file *file) -{ - struct ess_card *card = (struct ess_card *)file->private_data; - - VALIDATE_CARD(card); - - return 0; -} - -static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct ess_card *card = (struct ess_card *)file->private_data; - - VALIDATE_CARD(card); - - return mixer_ioctl(card, cmd, arg); -} - -static /*const*/ struct file_operations ess_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = ess_ioctl_mixdev, - .open = ess_open_mixdev, - .release = ess_release_mixdev, -}; - -/* --------------------------------------------------------------------- */ - -static int drain_dac(struct ess_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait,current); - unsigned long flags; - int count; - signed long tmo; - - if (s->dma_dac.mapped || !s->dma_dac.ready) - return 0; - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&s->dma_dac.wait, &wait); - for (;;) { - /* XXX uhm.. questionable locking*/ - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; - return -EBUSY; - } - tmo = (count * HZ) / s->ratedac; - tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]; - /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken. - or something. who cares. - zach */ - if (!schedule_timeout(tmo ? tmo : 1) && tmo) - M_printk(KERN_DEBUG "maestro: dma timed out?? %ld\n",jiffies); - } - remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ -/* Zach sez: "god this is gross.." */ -static int -comb_stereo(unsigned char *real_buffer,unsigned char *tmp_buffer, int offset, - int count, int bufsize) -{ - /* No such thing as stereo recording, so we - use dual input mixers. which means we have to - combine mono to stereo buffer. yuck. - - but we don't have to be able to work a byte at a time..*/ - - unsigned char *so,*left,*right; - int i; - - so = tmp_buffer; - left = real_buffer + offset; - right = real_buffer + bufsize/2 + offset; - -/* M_printk("comb_stereo writing %d to %p from %p and %p, offset: %d size: %d\n",count/2, tmp_buffer,left,right,offset,bufsize);*/ - - for(i=count/4; i ; i--) { - (*(so+2)) = *(right++); - (*(so+3)) = *(right++); - (*so) = *(left++); - (*(so+1)) = *(left++); - so+=4; - } - - return 0; -} - -/* in this loop, dma_adc.count signifies the amount of data thats waiting - to be copied to the user's buffer. it is filled by the interrupt - handler and drained by this loop. */ -static ssize_t -ess_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - unsigned char *combbuf = NULL; - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - if(!(combbuf = kmalloc(count,GFP_KERNEL))) - return -ENOMEM; - ret = 0; - - calc_bob_rate(s); - - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - /* remember, all these things are expressed in bytes to be - sent to the user.. hence the evil / 2 down below */ - swptr = s->dma_adc.swptr; - cnt = s->dma_adc.dmasize-swptr; - if (s->dma_adc.count < cnt) - cnt = s->dma_adc.count; - spin_unlock_irqrestore(&s->lock, flags); - - if (cnt > count) - cnt = count; - - if ( cnt > 0 ) cnt &= ~3; - - if (cnt <= 0) { - start_adc(s); - if (file->f_flags & O_NONBLOCK) - { - ret = ret ? ret : -EAGAIN; - goto rec_return_free; - } - if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { - if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, - s->dma_adc.hwptr, s->dma_adc.swptr); - stop_adc(s); - spin_lock_irqsave(&s->lock, flags); - set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); - /* program enhanced mode registers */ - /* FILL ME */ -/* wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); - wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); */ - s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; - spin_unlock_irqrestore(&s->lock, flags); - } - if (signal_pending(current)) - { - ret = ret ? ret : -ERESTARTSYS; - goto rec_return_free; - } - continue; - } - - if(s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) { - /* swptr/2 so that we know the real offset in each apu's buffer */ - comb_stereo(s->dma_adc.rawbuf,combbuf,swptr/2,cnt,s->dma_adc.dmasize); - if (copy_to_user(buffer, combbuf, cnt)) { - ret = ret ? ret : -EFAULT; - goto rec_return_free; - } - } else { - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { - ret = ret ? ret : -EFAULT; - goto rec_return_free; - } - } - - swptr = (swptr + cnt) % s->dma_adc.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_adc.swptr = swptr; - s->dma_adc.count -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - start_adc(s); - } - -rec_return_free: - kfree(combbuf); - return ret; -} - -static ssize_t -ess_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac.mapped) - return -ENXIO; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - - calc_bob_rate(s); - - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - - if (s->dma_dac.count < 0) { - s->dma_dac.count = 0; - s->dma_dac.swptr = s->dma_dac.hwptr; - } - swptr = s->dma_dac.swptr; - - cnt = s->dma_dac.dmasize-swptr; - - if (s->dma_dac.count + cnt > s->dma_dac.dmasize) - cnt = s->dma_dac.dmasize - s->dma_dac.count; - - spin_unlock_irqrestore(&s->lock, flags); - - if (cnt > count) - cnt = count; - - if (cnt <= 0) { - start_dac(s); - if (file->f_flags & O_NONBLOCK) { - if(!ret) ret = -EAGAIN; - goto return_free; - } - if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { - if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, - s->dma_dac.hwptr, s->dma_dac.swptr); - stop_dac(s); - spin_lock_irqsave(&s->lock, flags); - set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); - /* program enhanced mode registers */ -/* wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); - wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); */ - /* FILL ME */ - s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; - spin_unlock_irqrestore(&s->lock, flags); - } - if (signal_pending(current)) { - if (!ret) ret = -ERESTARTSYS; - goto return_free; - } - continue; - } - if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { - if (!ret) ret = -EFAULT; - goto return_free; - } -/* printk("wrote %d bytes at sw: %d cnt: %d while hw: %d\n",cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);*/ - - swptr = (swptr + cnt) % s->dma_dac.dmasize; - - spin_lock_irqsave(&s->lock, flags); - s->dma_dac.swptr = swptr; - s->dma_dac.count += cnt; - s->dma_dac.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - start_dac(s); - } -return_free: - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - -/* In 0.14 prog_dmabuf always returns success anyway ... */ - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac.ready && prog_dmabuf(s, 0)) - return 0; - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready && prog_dmabuf(s, 1)) - return 0; - } - - if (file->f_mode & FMODE_WRITE) - poll_wait(file, &s->dma_dac.wait, wait); - if (file->f_mode & FMODE_READ) - poll_wait(file, &s->dma_adc.wait, wait); - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int ess_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - struct dmabuf *db; - int ret = -EINVAL; - unsigned long size; - - VALIDATE_STATE(s); - lock_kernel(); - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf(s, 1)) != 0) - goto out; - db = &s->dma_dac; - } else -#if 0 - /* if we can have the wp/wc do the combining - we can turn this back on. */ - if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf(s, 0)) != 0) - goto out; - db = &s->dma_adc; - } else -#endif - goto out; - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) - goto out; - ret = -EAGAIN; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - db->mapped = 1; - ret = 0; -out: - unlock_kernel(); - return ret; -} - -static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int val, mapped, ret; - unsigned char fmtm, fmtd; - void __user *argp = (void __user *)arg; - int __user *p = argp; - -/* printk("maestro: ess_ioctl: cmd %d\n", cmd);*/ - - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, file->f_flags & O_NONBLOCK); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - /* XXX fix */ - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(s->card->pcidev->irq); - s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->card->pcidev->irq); - s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - set_adc_rate(s, val); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - set_dac_rate(s, val); - } - } - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val) - fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val) - fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); - } - set_fmt(s, fmtm, fmtd); - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val >= 2) - fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val >= 2) - fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); - } - set_fmt(s, fmtm, fmtd); - } - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) - : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_U8|AFMT_S16_LE, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - /* fixed at 16bit for now */ - fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT; -#if 0 - if (val == AFMT_S16_LE) - fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT; - else - fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT); -#endif - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val == AFMT_S16_LE) - fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT; - else - fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT); - } - set_fmt(s, fmtm, fmtd); - } - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? - (ESS_FMT_16BIT << ESS_ADC_SHIFT) - : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? - AFMT_S16_LE : - AFMT_U8, - p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING)) - val |= PCM_ENABLE_INPUT; - if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING)) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - start_adc(s); - } else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - start_dac(s); - } else - stop_dac(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - abinfo.fragsize = s->dma_dac.fragsize; - abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - val = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, p); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; - cinfo.ptr = s->dma_dac.hwptr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf(s, 0))) - return val; - return put_user(s->dma_dac.fragsize, p); - } - if ((val = prog_dmabuf(s, 1))) - return val; - return put_user(s->dma_adc.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - M_printk("maestro: SETFRAGMENT: %0x\n",val); - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - s->dma_dac.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) - : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) - : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return -EINVAL; -} - -static void -set_base_registers(struct ess_state *s,void *vaddr) -{ - unsigned long packed_phys = virt_to_bus(vaddr)>>12; - wave_set_register(s, 0x01FC , packed_phys); - wave_set_register(s, 0x01FD , packed_phys); - wave_set_register(s, 0x01FE , packed_phys); - wave_set_register(s, 0x01FF , packed_phys); -} - -/* - * this guy makes sure we're in the right power - * state for what we want to be doing - */ -static void maestro_power(struct ess_card *card, int tostate) -{ - u16 active_mask = acpi_state_mask[tostate]; - u8 state; - - if(!use_pm) return; - - pci_read_config_byte(card->pcidev, card->power_regs+0x4, &state); - state&=3; - - /* make sure we're in the right state */ - if(state != tostate) { - M_printk(KERN_WARNING "maestro: dev %02x:%02x.%x switching from D%d to D%d\n", - card->pcidev->bus->number, - PCI_SLOT(card->pcidev->devfn), - PCI_FUNC(card->pcidev->devfn), - state,tostate); - pci_write_config_byte(card->pcidev, card->power_regs+0x4, tostate); - } - - /* and make sure the units we care about are on - XXX we might want to do this before state flipping? */ - pci_write_config_word(card->pcidev, 0x54, ~ active_mask); - pci_write_config_word(card->pcidev, 0x56, ~ active_mask); -} - -/* we allocate a large power of two for all our memory. - this is cut up into (not to scale :): - |silly fifo word | 512byte mixbuf per adc | dac/adc * channels | -*/ -static int -allocate_buffers(struct ess_state *s) -{ - void *rawbuf=NULL; - int order,i; - struct page *page, *pend; - - /* alloc as big a chunk as we can */ - for (order = (dsps_order + (16-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--) - if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order))) - break; - - if (!rawbuf) - return 1; - - M_printk("maestro: allocated %ld (%d) bytes at %p\n",PAGE_SIZE<card->dmapages = rawbuf; - s->card->dmaorder = order; - - for(i=0;icard->channels[i]; - - if(ess->dev_audio == -1) - continue; - - ess->dma_dac.ready = s->dma_dac.mapped = 0; - ess->dma_adc.ready = s->dma_adc.mapped = 0; - ess->dma_adc.buforder = ess->dma_dac.buforder = order - 1 - dsps_order - 1; - - /* offset dac and adc buffers starting half way through and then at each [da][ad]c's - order's intervals.. */ - ess->dma_dac.rawbuf = rawbuf + (PAGE_SIZE<<(order-1)) + (i * ( PAGE_SIZE << (ess->dma_dac.buforder + 1 ))); - ess->dma_adc.rawbuf = ess->dma_dac.rawbuf + ( PAGE_SIZE << ess->dma_dac.buforder); - /* offset mixbuf by a mixbuf so that the lame status fifo can - happily scribble away.. */ - ess->mixbuf = rawbuf + (512 * (i+1)); - - M_printk("maestro: setup apu %d: dac: %p adc: %p mix: %p\n",i,ess->dma_dac.rawbuf, - ess->dma_adc.rawbuf, ess->mixbuf); - - } - - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(rawbuf); page <= pend; page++) - SetPageReserved(page); - - return 0; -} -static void -free_buffers(struct ess_state *s) -{ - struct page *page, *pend; - - s->dma_dac.rawbuf = s->dma_adc.rawbuf = NULL; - s->dma_dac.mapped = s->dma_adc.mapped = 0; - s->dma_dac.ready = s->dma_adc.ready = 0; - - M_printk("maestro: freeing %p\n",s->card->dmapages); - /* undo marking the pages as reserved */ - - pend = virt_to_page(s->card->dmapages + (PAGE_SIZE << s->card->dmaorder) - 1); - for (page = virt_to_page(s->card->dmapages); page <= pend; page++) - ClearPageReserved(page); - - free_pages((unsigned long)s->card->dmapages,s->card->dmaorder); - s->card->dmapages = NULL; -} - -static int -ess_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct ess_state *s = NULL; - unsigned char fmtm = ~0, fmts = 0; - struct pci_dev *pdev = NULL; - /* - * Scan the cards and find the channel. We only - * do this at open time so it is ok - */ - - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - struct ess_card *c; - struct pci_driver *drvr; - - drvr = pci_dev_driver (pdev); - if (drvr == &maestro_pci_driver) { - int i; - struct ess_state *sp; - - c = (struct ess_card*)pci_get_drvdata (pdev); - if (!c) - continue; - for(i=0;ichannels[i]; - if(sp->dev_audio < 0) - continue; - if((sp->dev_audio ^ minor) & ~0xf) - continue; - s=sp; - } - } - } - if (!s) - return -ENODEV; - - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EWOULDBLOCK; - } - mutex_unlock(&s->open_mutex); - interruptible_sleep_on(&s->open_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - - /* under semaphore.. */ - if ((s->card->dmapages==NULL) && allocate_buffers(s)) { - mutex_unlock(&s->open_mutex); - return -ENOMEM; - } - - /* we're covered by the open_mutex */ - if( ! s->card->dsps_open ) { - maestro_power(s->card,ACPI_D0); - start_bob(s); - } - s->card->dsps_open++; - M_printk("maestro: open, %d bobs now\n",s->card->dsps_open); - - /* ok, lets write WC base regs now that we've - powered up the chip */ - M_printk("maestro: writing 0x%lx (bus 0x%lx) to the wp\n",virt_to_bus(s->card->dmapages), - ((virt_to_bus(s->card->dmapages))&0xFFE00000)>>12); - set_base_registers(s,s->card->dmapages); - - if (file->f_mode & FMODE_READ) { -/* - fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; */ - - fmtm &= ~((ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT); - fmts = (ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT; - - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; - set_adc_rate(s, 8000); - } - if (file->f_mode & FMODE_WRITE) { - fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT; - - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; - set_dac_rate(s, 8000); - } - set_fmt(s, fmtm, fmts); - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int -ess_release(struct inode *inode, struct file *file) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - if (file->f_mode & FMODE_WRITE) - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - } - - s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); - /* we're covered by the open_mutex */ - M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1); - if( --s->card->dsps_open <= 0) { - s->card->dsps_open = 0; - stop_bob(s); - free_buffers(s); - maestro_power(s->card,ACPI_D2); - } - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static struct file_operations ess_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ess_read, - .write = ess_write, - .poll = ess_poll, - .ioctl = ess_ioctl, - .mmap = ess_mmap, - .open = ess_open, - .release = ess_release, -}; - -static int -maestro_config(struct ess_card *card) -{ - struct pci_dev *pcidev = card->pcidev; - struct ess_state *ess = &card->channels[0]; - int apu,iobase = card->iobase; - u16 w; - u32 n; - - /* We used to muck around with pci config space that - * we had no business messing with. We don't know enough - * about the machine to know which DMA mode is appropriate, - * etc. We were guessing wrong on some machines and making - * them unhappy. We now trust in the BIOS to do things right, - * which almost certainly means a new host of problems will - * arise with broken BIOS implementations. screw 'em. - * We're already intolerant of machines that don't assign - * IRQs. - */ - - /* do config work at full power */ - maestro_power(card,ACPI_D0); - - pci_read_config_word(pcidev, 0x50, &w); - - w&=~(1<<5); /* Don't swap left/right (undoc)*/ - - pci_write_config_word(pcidev, 0x50, w); - - pci_read_config_word(pcidev, 0x52, &w); - w&=~(1<<15); /* Turn off internal clock multiplier */ - /* XXX how do we know which to use? */ - w&=~(1<<14); /* External clock */ - - w|= (1<<7); /* Hardware volume control on */ - w|= (1<<6); /* Debounce off: easier to push the HWV buttons. */ - w&=~(1<<5); /* GPIO 4:5 */ - w|= (1<<4); /* Disconnect from the CHI. Enabling this made a dell 7500 work. */ - w&=~(1<<2); /* MIDI fix off (undoc) */ - w&=~(1<<1); /* reserved, always write 0 */ - pci_write_config_word(pcidev, 0x52, w); - - /* - * Legacy mode - */ - - pci_read_config_word(pcidev, 0x40, &w); - w|=(1<<15); /* legacy decode off */ - w&=~(1<<14); /* Disable SIRQ */ - w&=~(0x1f); /* disable mpu irq/io, game port, fm, SB */ - - pci_write_config_word(pcidev, 0x40, w); - - /* Set up 978 docking control chip. */ - pci_read_config_word(pcidev, 0x58, &w); - w|=1<<2; /* Enable 978. */ - w|=1<<3; /* Turn on 978 hardware volume control. */ - w&=~(1<<11); /* Turn on 978 mixer volume control. */ - pci_write_config_word(pcidev, 0x58, w); - - sound_reset(iobase); - - /* - * Ring Bus Setup - */ - - /* setup usual 0x34 stuff.. 0x36 may be chip specific */ - outw(0xC090, iobase+0x34); /* direct sound, stereo */ - udelay(20); - outw(0x3000, iobase+0x36); /* direct sound, stereo */ - udelay(20); - - - /* - * Reset the CODEC - */ - - maestro_ac97_reset(iobase,pcidev); - - /* - * Ring Bus Setup - */ - - n=inl(iobase+0x34); - n&=~0xF000; - n|=12<<12; /* Direct Sound, Stereo */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n&=~0x0F00; /* Modem off */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n&=~0x00F0; - n|=9<<4; /* DAC, Stereo */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n&=~0x000F; /* ASSP off */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n|=(1<<29); /* Enable ring bus */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n|=(1<<28); /* Enable serial bus */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n&=~0x00F00000; /* MIC off */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n&=~0x000F0000; /* I2S off */ - outl(n, iobase+0x34); - - - w=inw(iobase+0x18); - w&=~(1<<7); /* ClkRun off */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w&=~(1<<6); /* Hardware volume control interrupt off... for now. */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w&=~(1<<4); /* ASSP irq off */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w&=~(1<<3); /* ISDN irq off */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w|=(1<<2); /* Direct Sound IRQ on */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w&=~(1<<1); /* MPU401 IRQ off */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w|=(1<<0); /* SB IRQ on */ - outw(w, iobase+0x18); - - /* Set hardware volume control registers to midpoints. - We can tell which button was pushed based on how they change. */ - outb(0x88, iobase+0x1c); - outb(0x88, iobase+0x1d); - outb(0x88, iobase+0x1e); - outb(0x88, iobase+0x1f); - - /* it appears some maestros (dell 7500) only work if these are set, - regardless of whether we use the assp or not. */ - - outb(0, iobase+0xA4); - outb(3, iobase+0xA2); - outb(0, iobase+0xA6); - - for(apu=0;apu<16;apu++) - { - /* Write 0 into the buffer area 0x1E0->1EF */ - outw(0x01E0+apu, 0x10+iobase); - outw(0x0000, 0x12+iobase); - - /* - * The 1.10 test program seem to write 0 into the buffer area - * 0x1D0-0x1DF too. - */ - outw(0x01D0+apu, 0x10+iobase); - outw(0x0000, 0x12+iobase); - } - -#if 1 - wave_set_register(ess, IDR7_WAVE_ROMRAM, - (wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00)); - wave_set_register(ess, IDR7_WAVE_ROMRAM, - wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100); - wave_set_register(ess, IDR7_WAVE_ROMRAM, - wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200); - wave_set_register(ess, IDR7_WAVE_ROMRAM, - wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400); -#else - maestro_write(ess, IDR7_WAVE_ROMRAM, - (maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00)); - maestro_write(ess, IDR7_WAVE_ROMRAM, - maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100); - maestro_write(ess, IDR7_WAVE_ROMRAM, - maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200); - maestro_write(ess, IDR7_WAVE_ROMRAM, - maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400); -#endif - - maestro_write(ess, IDR2_CRAM_DATA, 0x0000); - maestro_write(ess, 0x08, 0xB004); - /* Now back to the DirectSound stuff */ - maestro_write(ess, 0x09, 0x001B); - maestro_write(ess, 0x0A, 0x8000); - maestro_write(ess, 0x0B, 0x3F37); - maestro_write(ess, 0x0C, 0x0098); - - /* parallel out ?? */ - maestro_write(ess, 0x0C, - (maestro_read(ess, 0x0C)&~0xF000)|0x8000); - /* parallel in, has something to do with recording :) */ - maestro_write(ess, 0x0C, - (maestro_read(ess, 0x0C)&~0x0F00)|0x0500); - - maestro_write(ess, 0x0D, 0x7632); - - /* Wave cache control on - test off, sg off, - enable, enable extra chans 1Mb */ - - outw(inw(0x14+iobase)|(1<<8),0x14+iobase); - outw(inw(0x14+iobase)&0xFE03,0x14+iobase); - outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase); - outw(inw(0x14+iobase)|(1<<7),0x14+iobase); - - outw(0xA1A0, 0x14+iobase); /* 0300 ? */ - - /* Now clear the APU control ram */ - for(apu=0;apupower_regs = 0; - - /* check to see if we have a capabilities list in - the config register */ - pci_read_config_word(pcidev, PCI_STATUS, &w); - if(!(w & PCI_STATUS_CAP_LIST)) return 0; - - /* walk the list, starting at the head. */ - pci_read_config_byte(pcidev,PCI_CAPABILITY_LIST,&next); - - while(next && max--) { - pci_read_config_dword(pcidev, next & ~3, &n); - if((n & 0xff) == PCI_CAP_ID_PM) { - card->power_regs = next; - break; - } - next = ((n>>8) & 0xff); - } - - return card->power_regs ? 1 : 0; -} - -static int __init -maestro_probe(struct pci_dev *pcidev,const struct pci_device_id *pdid) -{ - int card_type = pdid->driver_data; - u32 n; - int iobase; - int i, ret; - struct ess_card *card; - struct ess_state *ess; - int num = 0; - -/* when built into the kernel, we only print version if device is found */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(version); -#endif - - /* don't pick up weird modem maestros */ - if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO) - return -ENODEV; - - - if ((ret=pci_enable_device(pcidev))) - return ret; - - iobase = pci_resource_start(pcidev,0); - if (!iobase || !(pci_resource_flags(pcidev, 0 ) & IORESOURCE_IO)) - return -ENODEV; - - if(pcidev->irq == 0) - return -ENODEV; - - /* stake our claim on the iospace */ - if( request_region(iobase, 256, card_names[card_type]) == NULL ) - { - printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase); - return -EBUSY; - } - - /* just to be sure */ - pci_set_master(pcidev); - - card = kmalloc(sizeof(struct ess_card), GFP_KERNEL); - if(card == NULL) - { - printk(KERN_WARNING "maestro: out of memory\n"); - release_region(iobase, 256); - return -ENOMEM; - } - - memset(card, 0, sizeof(*card)); - card->pcidev = pcidev; - - card->iobase = iobase; - card->card_type = card_type; - card->irq = pcidev->irq; - card->magic = ESS_CARD_MAGIC; - spin_lock_init(&card->lock); - init_waitqueue_head(&card->suspend_queue); - - card->dock_mute_vol = 50; - - /* init our groups of 6 apus */ - for(i=0;ichannels[i]; - - s->index = i; - - s->card = card; - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - spin_lock_init(&s->lock); - mutex_init(&s->open_mutex); - s->magic = ESS_STATE_MAGIC; - - s->apu[0] = 6*i; - s->apu[1] = (6*i)+1; - s->apu[2] = (6*i)+2; - s->apu[3] = (6*i)+3; - s->apu[4] = (6*i)+4; - s->apu[5] = (6*i)+5; - - if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf) - printk("maestro: BOTCH!\n"); - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0) - break; - } - - num = i; - - /* clear the rest if we ran out of slots to register */ - for(;ichannels[i]; - s->dev_audio = -1; - } - - ess = &card->channels[0]; - - /* - * Ok card ready. Begin setup proper - */ - - printk(KERN_INFO "maestro: Configuring %s found at IO 0x%04X IRQ %d\n", - card_names[card_type],iobase,card->irq); - pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n); - printk(KERN_INFO "maestro: subvendor id: 0x%08x\n",n); - - /* turn off power management unless: - * - the user explicitly asks for it - * or - * - we're not a 2e, lesser chipps seem to have problems. - * - we're not on our _very_ small whitelist. some implemenetations - * really don't like the pm code, others require it. - * feel free to expand this as required. - */ -#define SUBSYSTEM_VENDOR(x) (x&0xffff) - if( (use_pm != 1) && - ((card_type != TYPE_MAESTRO2E) || (SUBSYSTEM_VENDOR(n) != 0x1028))) - use_pm = 0; - - if(!use_pm) - printk(KERN_INFO "maestro: not attempting power management.\n"); - else { - if(!parse_power(card,pcidev)) - printk(KERN_INFO "maestro: no PCI power management interface found.\n"); - else { - pci_read_config_dword(pcidev, card->power_regs, &n); - printk(KERN_INFO "maestro: PCI power management capability: 0x%x\n",n>>16); - } - } - - maestro_config(card); - - if(maestro_ac97_get(card, 0x00)==0x0080) { - printk(KERN_ERR "maestro: my goodness! you seem to have a pt101 codec, which is quite rare.\n" - "\tyou should tell someone about this.\n"); - } else { - maestro_ac97_init(card); - } - - if ((card->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) { - printk("maestro: couldn't register mixer!\n"); - } else { - memcpy(card->mix.mixer_state,mixer_defaults,sizeof(card->mix.mixer_state)); - mixer_push_state(card); - } - - if((ret=request_irq(card->irq, ess_interrupt, IRQF_SHARED, card_names[card_type], card))) - { - printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq); - unregister_sound_mixer(card->dev_mixer); - for(i=0;ichannels[i]; - if(s->dev_audio != -1) - unregister_sound_dsp(s->dev_audio); - } - release_region(card->iobase, 256); - unregister_reboot_notifier(&maestro_nb); - kfree(card); - return ret; - } - - /* Turn on hardware volume control interrupt. - This has to come after we grab the IRQ above, - or a crash will result on installation if a button has been pressed, - because in that case we'll get an immediate interrupt. */ - n = inw(iobase+0x18); - n|=(1<<6); - outw(n, iobase+0x18); - - pci_set_drvdata(pcidev,card); - /* now go to sleep 'till something interesting happens */ - maestro_power(card,ACPI_D2); - - printk(KERN_INFO "maestro: %d channels configured.\n", num); - return 0; -} - -static void maestro_remove(struct pci_dev *pcidev) { - struct ess_card *card = pci_get_drvdata(pcidev); - int i; - u32 n; - - /* XXX maybe should force stop bob, but should be all - stopped by _release by now */ - - /* Turn off hardware volume control interrupt. - This has to come before we leave the IRQ below, - or a crash results if a button is pressed ! */ - n = inw(card->iobase+0x18); - n&=~(1<<6); - outw(n, card->iobase+0x18); - - free_irq(card->irq, card); - unregister_sound_mixer(card->dev_mixer); - for(i=0;ichannels[i]; - if(ess->dev_audio != -1) - unregister_sound_dsp(ess->dev_audio); - } - /* Goodbye, Mr. Bond. */ - maestro_power(card,ACPI_D3); - release_region(card->iobase, 256); - kfree(card); - pci_set_drvdata(pcidev,NULL); -} - -static struct pci_device_id maestro_pci_tbl[] = { - {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2}, - {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2E}, - {PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO}, - {0,} -}; -MODULE_DEVICE_TABLE(pci, maestro_pci_tbl); - -static struct pci_driver maestro_pci_driver = { - .name = "maestro", - .id_table = maestro_pci_tbl, - .probe = maestro_probe, - .remove = maestro_remove, -}; - -static int __init init_maestro(void) -{ - int rc; - - rc = pci_register_driver(&maestro_pci_driver); - if (rc < 0) - return rc; - - if (register_reboot_notifier(&maestro_nb)) - printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n"); -#ifdef MODULE - printk(version); -#endif - if (dsps_order < 0) { - dsps_order = 1; - printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order); - } - else if (dsps_order > MAX_DSP_ORDER) { - dsps_order = MAX_DSP_ORDER; - printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order); - } - return 0; -} - -static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf) -{ - /* this notifier is called when the kernel is really shut down. */ - M_printk("maestro: shutting down\n"); - /* this will remove all card instances too */ - pci_unregister_driver(&maestro_pci_driver); - /* XXX dunno about power management */ - return NOTIFY_OK; -} - -/* --------------------------------------------------------------------- */ - - -static void cleanup_maestro(void) { - M_printk("maestro: unloading\n"); - pci_unregister_driver(&maestro_pci_driver); - unregister_reboot_notifier(&maestro_nb); -} - -/* --------------------------------------------------------------------- */ - -void -check_suspend(struct ess_card *card) -{ - DECLARE_WAITQUEUE(wait, current); - - if(!card->in_suspend) return; - - card->in_suspend++; - add_wait_queue(&(card->suspend_queue), &wait); - current->state = TASK_UNINTERRUPTIBLE; - schedule(); - remove_wait_queue(&(card->suspend_queue), &wait); - current->state = TASK_RUNNING; -} - -module_init(init_maestro); -module_exit(cleanup_maestro); diff --git a/sound/oss/maestro.h b/sound/oss/maestro.h deleted file mode 100644 index 023ec7f968f9..000000000000 --- a/sound/oss/maestro.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Registers for the ESS PCI cards - */ - -/* - * Memory access - */ - -#define ESS_MEM_DATA 0x00 -#define ESS_MEM_INDEX 0x02 - -/* - * AC-97 Codec port. Delay 1uS after each write. This is used to - * talk AC-97 (see intel.com). Write data then register. - */ - -#define ESS_AC97_INDEX 0x30 /* byte wide */ -#define ESS_AC97_DATA 0x32 - -/* - * Reading is a bit different. You write register|0x80 to ubdex - * delay 1uS poll the low bit of index, when it clears read the - * data value. - */ - -/* - * Control port. Not yet fully understood - * The value 0xC090 gets loaded to it then 0x0000 and 0x2800 - * to the data port. Then after 4uS the value 0x300 is written - */ - -#define RING_BUS_CTRL_L 0x34 -#define RING_BUS_CTRL_H 0x36 - -/* - * This is also used during setup. The value 0x17 is written to it - */ - -#define ESS_SETUP_18 0x18 - -/* - * And this one gets 0x000b - */ - -#define ESS_SETUP_A2 0xA2 - -/* - * And this 0x0000 - */ - -#define ESS_SETUP_A4 0xA4 -#define ESS_SETUP_A6 0xA6 - -/* - * Stuff to do with Harpo - the wave stuff - */ - -#define ESS_WAVETABLE_SIZE 0x14 -#define ESS_WAVETABLE_2M 0xA180 - diff --git a/sound/oss/maestro3.c b/sound/oss/maestro3.c deleted file mode 100644 index 5548e3cff7ce..000000000000 --- a/sound/oss/maestro3.c +++ /dev/null @@ -1,2969 +0,0 @@ -/***************************************************************************** - * - * ESS Maestro3/Allegro driver for Linux 2.4.x - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * (c) Copyright 2000 Zach Brown - * - * I need to thank many people for helping make this driver happen. - * As always, Eric Brombaugh was a hacking machine and killed many bugs - * that I was too dumb to notice. Howard Kim at ESS provided reference boards - * and as much docs as he could. Todd and Mick at Dell tested snapshots on - * an army of laptops. msw and deviant at Red Hat also humoured me by hanging - * their laptops every few hours in the name of science. - * - * Shouts go out to Mike "DJ XPCom" Ang. - * - * History - * v1.23 - Jun 5 2002 - Michael Olson - * added a module option to allow selection of GPIO pin number - * for external amp - * v1.22 - Feb 28 2001 - Zach Brown - * allocate mem at insmod/setup, rather than open - * limit pci dma addresses to 28bit, thanks guys. - * v1.21 - Feb 04 2001 - Zach Brown - * fix up really dumb notifier -> suspend oops - * v1.20 - Jan 30 2001 - Zach Brown - * get rid of pm callback and use pci_dev suspend/resume instead - * m3_probe cleanups, including pm oops think-o - * v1.10 - Jan 6 2001 - Zach Brown - * revert to lame remap_page_range mmap() just to make it work - * record mmap fixed. - * fix up incredibly broken open/release resource management - * duh. fix record format setting. - * add SMP locking and cleanup formatting here and there - * v1.00 - Dec 16 2000 - Zach Brown - * port to sexy 2.4 interfaces - * properly align instance allocations so recording works - * clean up function namespace a little :/ - * update PCI IDs based on mail from ESS - * arbitrarily bump version number to show its 2.4 now, - * 2.2 will stay 0., oss_audio port gets 2. - * v0.03 - Nov 05 2000 - Zach Brown - * disable recording but allow dsp to be opened read - * pull out most silly compat defines - * v0.02 - Nov 04 2000 - Zach Brown - * changed clocking setup for m3, slowdown fixed. - * codec reset is hopefully reliable now - * rudimentary apm/power management makes suspend/resume work - * v0.01 - Oct 31 2000 - Zach Brown - * first release - * v0.00 - Sep 09 2000 - Zach Brown - * first pass derivation from maestro.c - * - * TODO - * in/out allocated contiguously so fullduplex mmap will work? - * no beep on init (mute) - * resetup msrc data memory if freq changes? - * - * -- - * - * Allow me to ramble a bit about the m3 architecture. The core of the - * chip is the 'assp', the custom ESS dsp that runs the show. It has - * a small amount of code and data ram. ESS drops binary dsp code images - * on our heads, but we don't get to see specs on the dsp. - * - * The constant piece of code on the dsp is the 'kernel'. It also has a - * chunk of the dsp memory that is statically set aside for its control - * info. This is the KDATA defines in maestro3.h. Part of its core - * data is a list of code addresses that point to the pieces of DSP code - * that it should walk through in its loop. These other pieces of code - * do the real work. The kernel presumably jumps into each of them in turn. - * These code images tend to have their own data area, and one can have - * multiple data areas representing different states for each of the 'client - * instance' code portions. There is generally a list in the kernel data - * that points to the data instances for a given piece of code. - * - * We've only been given the binary image for the 'minisrc', mini sample - * rate converter. This is rather annoying because it limits the work - * we can do on the dsp, but it also greatly simplifies the job of managing - * dsp data memory for the code and data for our playing streams :). We - * statically allocate the minisrc code into a region we 'know' to be free - * based on the map of the binary kernel image we're loading. We also - * statically allocate the data areas for the maximum number of pcm streams - * we can be dealing with. This max is set by the length of the static list - * in the kernel data that records the number of minisrc data regions we - * can have. Thats right, all software dsp mixing with static code list - * limits. Rock. - * - * How sound goes in and out is still a relative mystery. It appears - * that the dsp has the ability to get input and output through various - * 'connections'. To do IO from or to a connection, you put the address - * of the minisrc client area in the static kernel data lists for that - * input or output. so for pcm -> dsp -> mixer, we put the minisrc data - * instance in the DMA list and also in the list for the mixer. I guess - * it Just Knows which is in/out, and we give some dma control info that - * helps. There are all sorts of cool inputs/outputs that it seems we can't - * use without dsp code images that know how to use them. - * - * So at init time we preload all the memory allocation stuff and set some - * system wide parameters. When we really get a sound to play we build - * up its minisrc header (stream parameters, buffer addresses, input/output - * settings). Then we throw its header on the various lists. We also - * tickle some KDATA settings that ask the assp to raise clock interrupts - * and do some amount of software mixing before handing data to the ac97. - * - * Sorry for the vague details. Feel free to ask Eric or myself if you - * happen to be trying to use this driver elsewhere. Please accept my - * apologies for the quality of the OSS support code, its passed through - * too many hands now and desperately wants to be rethought. - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include - -#include "maestro3.h" - -#define M_DEBUG 1 - -#define DRIVER_VERSION "1.23" -#define M3_MODULE_NAME "maestro3" -#define PFX M3_MODULE_NAME ": " - -#define M3_STATE_MAGIC 0x734d724d -#define M3_CARD_MAGIC 0x646e6f50 - -#define ESS_FMT_STEREO 0x01 -#define ESS_FMT_16BIT 0x02 -#define ESS_FMT_MASK 0x03 -#define ESS_DAC_SHIFT 0 -#define ESS_ADC_SHIFT 4 - -#define DAC_RUNNING 1 -#define ADC_RUNNING 2 - -#define SND_DEV_DSP16 5 - -#ifdef M_DEBUG -static int debug; -#define DPMOD 1 /* per module load */ -#define DPSTR 2 /* per 'stream' */ -#define DPSYS 3 /* per syscall */ -#define DPCRAP 4 /* stuff the user shouldn't see unless they're really debuggin */ -#define DPINT 5 /* per interrupt, LOTS */ -#define DPRINTK(DP, args...) {if (debug >= (DP)) printk(KERN_DEBUG PFX args);} -#else -#define DPRINTK(x) -#endif - -struct m3_list { - int curlen; - u16 mem_addr; - int max; -}; - -static int external_amp = 1; -static int gpio_pin = -1; - -struct m3_state { - unsigned int magic; - struct m3_card *card; - unsigned char fmt, enable; - - int index; - - /* this locks around the oss state in the driver */ - /* no, this lock is removed - only use card->lock */ - /* otherwise: against what are you protecting on SMP - when irqhandler uses s->lock - and m3_assp_read uses card->lock ? - */ - struct mutex open_mutex; - wait_queue_head_t open_wait; - mode_t open_mode; - - int dev_audio; - - struct assp_instance { - u16 code, data; - } dac_inst, adc_inst; - - /* should be in dmabuf */ - unsigned int rateadc, ratedac; - - struct dmabuf { - void *rawbuf; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - unsigned hwptr, swptr; - unsigned total_bytes; - int count; - unsigned error; /* over/underrun */ - wait_queue_head_t wait; - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dmasize; - unsigned fragsamples; - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned endcleared:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - /* new in m3 */ - int mixer_index, dma_index, msrc_index, adc1_index; - int in_lists; - /* 2.4.. */ - dma_addr_t handle; - - } dma_dac, dma_adc; -}; - -struct m3_card { - unsigned int magic; - - struct m3_card *next; - - struct ac97_codec *ac97; - spinlock_t ac97_lock; - - int card_type; - -#define NR_DSPS 1 -#define MAX_DSPS NR_DSPS - struct m3_state channels[MAX_DSPS]; - - /* this locks around the physical registers on the card */ - spinlock_t lock; - - /* hardware resources */ - struct pci_dev *pcidev; - u32 iobase; - u32 irq; - - int dacs_active; - - int timer_users; - - struct m3_list msrc_list, - mixer_list, - adc1_list, - dma_list; - - /* for storing reset state..*/ - u8 reset_state; - - u16 *suspend_mem; - int in_suspend; - wait_queue_head_t suspend_queue; -}; - -/* - * an arbitrary volume we set the internal - * volume settings to so that the ac97 volume - * range is a little less insane. 0x7fff is - * max. - */ -#define ARB_VOLUME ( 0x6800 ) - -static const unsigned sample_shift[] = { 0, 1, 1, 2 }; - -enum { - ESS_ALLEGRO, - ESS_MAESTRO3, - /* - * a maestro3 with 'hardware strapping', only - * found inside ESS? - */ - ESS_MAESTRO3HW, -}; - -static char *card_names[] = { - [ESS_ALLEGRO] = "Allegro", - [ESS_MAESTRO3] = "Maestro3(i)", - [ESS_MAESTRO3HW] = "Maestro3(i)hw" -}; - -#ifndef PCI_VENDOR_ESS -#define PCI_VENDOR_ESS 0x125D -#endif - -#define M3_DEVICE(DEV, TYPE) \ -{ \ -.vendor = PCI_VENDOR_ESS, \ -.device = DEV, \ -.subvendor = PCI_ANY_ID, \ -.subdevice = PCI_ANY_ID, \ -.class = PCI_CLASS_MULTIMEDIA_AUDIO << 8, \ -.class_mask = 0xffff << 8, \ -.driver_data = TYPE, \ -} - -static struct pci_device_id m3_id_table[] = { - M3_DEVICE(0x1988, ESS_ALLEGRO), - M3_DEVICE(0x1998, ESS_MAESTRO3), - M3_DEVICE(0x199a, ESS_MAESTRO3HW), - {0,} -}; - -MODULE_DEVICE_TABLE (pci, m3_id_table); - -/* - * reports seem to indicate that the m3 is limited - * to 28bit bus addresses. aaaargggh... - */ -#define M3_PCI_DMA_MASK 0x0fffffff - -static unsigned -ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -static struct m3_card *devs; - -/* - * I'm not very good at laying out functions in a file :) - */ -static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf); -static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state); -static void check_suspend(struct m3_card *card); - -static struct notifier_block m3_reboot_nb = { - .notifier_call = m3_notifier, -}; - -static void m3_outw(struct m3_card *card, - u16 value, unsigned long reg) -{ - check_suspend(card); - outw(value, card->iobase + reg); -} - -static u16 m3_inw(struct m3_card *card, unsigned long reg) -{ - check_suspend(card); - return inw(card->iobase + reg); -} -static void m3_outb(struct m3_card *card, - u8 value, unsigned long reg) -{ - check_suspend(card); - outb(value, card->iobase + reg); -} -static u8 m3_inb(struct m3_card *card, unsigned long reg) -{ - check_suspend(card); - return inb(card->iobase + reg); -} - -/* - * access 16bit words to the code or data regions of the dsp's memory. - * index addresses 16bit words. - */ -static u16 __m3_assp_read(struct m3_card *card, u16 region, u16 index) -{ - m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE); - m3_outw(card, index, DSP_PORT_MEMORY_INDEX); - return m3_inw(card, DSP_PORT_MEMORY_DATA); -} -static u16 m3_assp_read(struct m3_card *card, u16 region, u16 index) -{ - unsigned long flags; - u16 ret; - - spin_lock_irqsave(&(card->lock), flags); - ret = __m3_assp_read(card, region, index); - spin_unlock_irqrestore(&(card->lock), flags); - - return ret; -} - -static void __m3_assp_write(struct m3_card *card, - u16 region, u16 index, u16 data) -{ - m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE); - m3_outw(card, index, DSP_PORT_MEMORY_INDEX); - m3_outw(card, data, DSP_PORT_MEMORY_DATA); -} -static void m3_assp_write(struct m3_card *card, - u16 region, u16 index, u16 data) -{ - unsigned long flags; - - spin_lock_irqsave(&(card->lock), flags); - __m3_assp_write(card, region, index, data); - spin_unlock_irqrestore(&(card->lock), flags); -} - -static void m3_assp_halt(struct m3_card *card) -{ - card->reset_state = m3_inb(card, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK; - mdelay(10); - m3_outb(card, card->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B); -} - -static void m3_assp_continue(struct m3_card *card) -{ - m3_outb(card, card->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B); -} - -/* - * This makes me sad. the maestro3 has lists - * internally that must be packed.. 0 terminates, - * apparently, or maybe all unused entries have - * to be 0, the lists have static lengths set - * by the binary code images. - */ - -static int m3_add_list(struct m3_card *card, - struct m3_list *list, u16 val) -{ - DPRINTK(DPSTR, "adding val 0x%x to list 0x%p at pos %d\n", - val, list, list->curlen); - - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - list->mem_addr + list->curlen, - val); - - return list->curlen++; - -} - -static void m3_remove_list(struct m3_card *card, - struct m3_list *list, int index) -{ - u16 val; - int lastindex = list->curlen - 1; - - DPRINTK(DPSTR, "removing ind %d from list 0x%p\n", - index, list); - - if(index != lastindex) { - val = m3_assp_read(card, MEMTYPE_INTERNAL_DATA, - list->mem_addr + lastindex); - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - list->mem_addr + index, - val); - } - - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - list->mem_addr + lastindex, - 0); - - list->curlen--; -} - -static void set_fmt(struct m3_state *s, unsigned char mask, unsigned char data) -{ - int tmp; - - s->fmt = (s->fmt & mask) | data; - - tmp = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK; - - /* write to 'mono' word */ - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + SRC3_DIRECTION_OFFSET + 1, - (tmp & ESS_FMT_STEREO) ? 0 : 1); - /* write to '8bit' word */ - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + SRC3_DIRECTION_OFFSET + 2, - (tmp & ESS_FMT_16BIT) ? 0 : 1); - - tmp = (s->fmt >> ESS_ADC_SHIFT) & ESS_FMT_MASK; - - /* write to 'mono' word */ - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + SRC3_DIRECTION_OFFSET + 1, - (tmp & ESS_FMT_STEREO) ? 0 : 1); - /* write to '8bit' word */ - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + SRC3_DIRECTION_OFFSET + 2, - (tmp & ESS_FMT_16BIT) ? 0 : 1); -} - -static void set_dac_rate(struct m3_state *s, unsigned int rate) -{ - u32 freq; - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - - s->ratedac = rate; - - freq = ((rate << 15) + 24000 ) / 48000; - if(freq) - freq--; - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_FREQUENCY, - freq); -} - -static void set_adc_rate(struct m3_state *s, unsigned int rate) -{ - u32 freq; - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - - s->rateadc = rate; - - freq = ((rate << 15) + 24000 ) / 48000; - if(freq) - freq--; - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_FREQUENCY, - freq); -} - -static void inc_timer_users(struct m3_card *card) -{ - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - - card->timer_users++; - DPRINTK(DPSYS, "inc timer users now %d\n", - card->timer_users); - if(card->timer_users != 1) - goto out; - - __m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_TIMER_COUNT_RELOAD, - 240 ) ; - - __m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_TIMER_COUNT_CURRENT, - 240 ) ; - - m3_outw(card, - m3_inw(card, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE, - HOST_INT_CTRL); -out: - spin_unlock_irqrestore(&card->lock, flags); -} - -static void dec_timer_users(struct m3_card *card) -{ - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - - card->timer_users--; - DPRINTK(DPSYS, "dec timer users now %d\n", - card->timer_users); - if(card->timer_users > 0 ) - goto out; - - __m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_TIMER_COUNT_RELOAD, - 0 ) ; - - __m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_TIMER_COUNT_CURRENT, - 0 ) ; - - m3_outw(card, m3_inw(card, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE, - HOST_INT_CTRL); -out: - spin_unlock_irqrestore(&card->lock, flags); -} - -/* - * {start,stop}_{adc,dac} should be called - * while holding the 'state' lock and they - * will try to grab the 'card' lock.. - */ -static void stop_adc(struct m3_state *s) -{ - if (! (s->enable & ADC_RUNNING)) - return; - - s->enable &= ~ADC_RUNNING; - dec_timer_users(s->card); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_INSTANCE_READY, 0); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - KDATA_ADC1_REQUEST, 0); -} - -static void stop_dac(struct m3_state *s) -{ - if (! (s->enable & DAC_RUNNING)) - return; - - DPRINTK(DPSYS, "stop_dac()\n"); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_INSTANCE_READY, 0); - - s->enable &= ~DAC_RUNNING; - s->card->dacs_active--; - dec_timer_users(s->card); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - KDATA_MIXER_TASK_NUMBER, - s->card->dacs_active ) ; -} - -static void start_dac(struct m3_state *s) -{ - if( (!s->dma_dac.mapped && s->dma_dac.count < 1) || - !s->dma_dac.ready || - (s->enable & DAC_RUNNING)) - return; - - DPRINTK(DPSYS, "start_dac()\n"); - - s->enable |= DAC_RUNNING; - s->card->dacs_active++; - inc_timer_users(s->card); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_INSTANCE_READY, 1); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - KDATA_MIXER_TASK_NUMBER, - s->card->dacs_active ) ; -} - -static void start_adc(struct m3_state *s) -{ - if ((! s->dma_adc.mapped && - s->dma_adc.count >= (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) - || !s->dma_adc.ready - || (s->enable & ADC_RUNNING) ) - return; - - DPRINTK(DPSYS, "start_adc()\n"); - - s->enable |= ADC_RUNNING; - inc_timer_users(s->card); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - KDATA_ADC1_REQUEST, 1); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_INSTANCE_READY, 1); -} - -static struct play_vals { - u16 addr, val; -} pv[] = { - {CDATA_LEFT_VOLUME, ARB_VOLUME}, - {CDATA_RIGHT_VOLUME, ARB_VOLUME}, - {SRC3_DIRECTION_OFFSET, 0} , - /* +1, +2 are stereo/16 bit */ - {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */ - {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */ - {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */ - {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */ - {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */ - {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */ - {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */ - {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */ - {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */ - {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */ - {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */ - {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */ - {SRC3_DIRECTION_OFFSET + 16, 8}, /* numin */ - {SRC3_DIRECTION_OFFSET + 17, 50*2}, /* numout */ - {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, /* numstage */ - {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */ - {SRC3_DIRECTION_OFFSET + 21, 0} /* booster */ -}; - - -/* the mode passed should be already shifted and masked */ -static void m3_play_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size) -{ - int dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2); - int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2); - int dsp_in_buffer = s->dac_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2); - int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1; - struct dmabuf *db = &s->dma_dac; - int i; - - DPRINTK(DPSTR, "mode=%d rate=%d buf=%p len=%d.\n", - mode, rate, buffer, size); - -#define LO(x) ((x) & 0xffff) -#define HI(x) LO((x) >> 16) - - /* host dma buffer pointers */ - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_HOST_SRC_ADDRL, - LO(virt_to_bus(buffer))); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_HOST_SRC_ADDRH, - HI(virt_to_bus(buffer))); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1L, - LO(virt_to_bus(buffer) + size)); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1H, - HI(virt_to_bus(buffer) + size)); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_HOST_SRC_CURRENTL, - LO(virt_to_bus(buffer))); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_HOST_SRC_CURRENTH, - HI(virt_to_bus(buffer))); -#undef LO -#undef HI - - /* dsp buffers */ - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_IN_BUF_BEGIN, - dsp_in_buffer); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_IN_BUF_END_PLUS_1, - dsp_in_buffer + (dsp_in_size / 2)); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_IN_BUF_HEAD, - dsp_in_buffer); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_IN_BUF_TAIL, - dsp_in_buffer); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_OUT_BUF_BEGIN, - dsp_out_buffer); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_OUT_BUF_END_PLUS_1, - dsp_out_buffer + (dsp_out_size / 2)); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_OUT_BUF_HEAD, - dsp_out_buffer); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_OUT_BUF_TAIL, - dsp_out_buffer); - - /* - * some per client initializers - */ - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + SRC3_DIRECTION_OFFSET + 12, - s->dac_inst.data + 40 + 8); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + SRC3_DIRECTION_OFFSET + 19, - s->dac_inst.code + MINISRC_COEF_LOC); - - /* enable or disable low pass filter? */ - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + SRC3_DIRECTION_OFFSET + 22, - s->ratedac > 45000 ? 0xff : 0 ); - - /* tell it which way dma is going? */ - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + CDATA_DMA_CONTROL, - DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR); - - /* - * set an armload of static initializers - */ - for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++) - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->dac_inst.data + pv[i].addr, pv[i].val); - - /* - * put us in the lists if we're not already there - */ - - if(db->in_lists == 0) { - - db->msrc_index = m3_add_list(s->card, &s->card->msrc_list, - s->dac_inst.data >> DP_SHIFT_COUNT); - - db->dma_index = m3_add_list(s->card, &s->card->dma_list, - s->dac_inst.data >> DP_SHIFT_COUNT); - - db->mixer_index = m3_add_list(s->card, &s->card->mixer_list, - s->dac_inst.data >> DP_SHIFT_COUNT); - - db->in_lists = 1; - } - - set_dac_rate(s,rate); - start_dac(s); -} - -/* - * Native record driver - */ -static struct rec_vals { - u16 addr, val; -} rv[] = { - {CDATA_LEFT_VOLUME, ARB_VOLUME}, - {CDATA_RIGHT_VOLUME, ARB_VOLUME}, - {SRC3_DIRECTION_OFFSET, 1} , - /* +1, +2 are stereo/16 bit */ - {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */ - {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */ - {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */ - {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */ - {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */ - {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */ - {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */ - {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */ - {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */ - {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */ - {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */ - {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */ - {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */ - {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */ - {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */ - {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */ - {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */ - {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */ - {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */ -}; - -/* again, passed mode is alrady shifted/masked */ -static void m3_rec_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size) -{ - int dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2); - int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2); - int dsp_in_buffer = s->adc_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2); - int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1; - struct dmabuf *db = &s->dma_adc; - int i; - - DPRINTK(DPSTR, "rec_setup mode=%d rate=%d buf=%p len=%d.\n", - mode, rate, buffer, size); - -#define LO(x) ((x) & 0xffff) -#define HI(x) LO((x) >> 16) - - /* host dma buffer pointers */ - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_HOST_SRC_ADDRL, - LO(virt_to_bus(buffer))); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_HOST_SRC_ADDRH, - HI(virt_to_bus(buffer))); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1L, - LO(virt_to_bus(buffer) + size)); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1H, - HI(virt_to_bus(buffer) + size)); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_HOST_SRC_CURRENTL, - LO(virt_to_bus(buffer))); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_HOST_SRC_CURRENTH, - HI(virt_to_bus(buffer))); -#undef LO -#undef HI - - /* dsp buffers */ - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_IN_BUF_BEGIN, - dsp_in_buffer); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_IN_BUF_END_PLUS_1, - dsp_in_buffer + (dsp_in_size / 2)); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_IN_BUF_HEAD, - dsp_in_buffer); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_IN_BUF_TAIL, - dsp_in_buffer); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_OUT_BUF_BEGIN, - dsp_out_buffer); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_OUT_BUF_END_PLUS_1, - dsp_out_buffer + (dsp_out_size / 2)); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_OUT_BUF_HEAD, - dsp_out_buffer); - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_OUT_BUF_TAIL, - dsp_out_buffer); - - /* - * some per client initializers - */ - - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + SRC3_DIRECTION_OFFSET + 12, - s->adc_inst.data + 40 + 8); - - /* tell it which way dma is going? */ - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + CDATA_DMA_CONTROL, - DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT + - DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR); - - /* - * set an armload of static initializers - */ - for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++) - m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, - s->adc_inst.data + rv[i].addr, rv[i].val); - - /* - * put us in the lists if we're not already there - */ - - if(db->in_lists == 0) { - - db->adc1_index = m3_add_list(s->card, &s->card->adc1_list, - s->adc_inst.data >> DP_SHIFT_COUNT); - - db->dma_index = m3_add_list(s->card, &s->card->dma_list, - s->adc_inst.data >> DP_SHIFT_COUNT); - - db->msrc_index = m3_add_list(s->card, &s->card->msrc_list, - s->adc_inst.data >> DP_SHIFT_COUNT); - - db->in_lists = 1; - } - - set_adc_rate(s,rate); - start_adc(s); -} -/* --------------------------------------------------------------------- */ - -static void set_dmaa(struct m3_state *s, unsigned int addr, unsigned int count) -{ - DPRINTK(DPINT,"set_dmaa??\n"); -} - -static void set_dmac(struct m3_state *s, unsigned int addr, unsigned int count) -{ - DPRINTK(DPINT,"set_dmac??\n"); -} - -static u32 get_dma_pos(struct m3_card *card, - int instance_addr) -{ - u16 hi = 0, lo = 0; - int retry = 10; - - /* - * try and get a valid answer - */ - while(retry--) { - hi = m3_assp_read(card, MEMTYPE_INTERNAL_DATA, - instance_addr + CDATA_HOST_SRC_CURRENTH); - - lo = m3_assp_read(card, MEMTYPE_INTERNAL_DATA, - instance_addr + CDATA_HOST_SRC_CURRENTL); - - if(hi == m3_assp_read(card, MEMTYPE_INTERNAL_DATA, - instance_addr + CDATA_HOST_SRC_CURRENTH)) - break; - } - return lo | (hi<<16); -} - -static u32 get_dmaa(struct m3_state *s) -{ - u32 offset; - - offset = get_dma_pos(s->card, s->dac_inst.data) - - virt_to_bus(s->dma_dac.rawbuf); - - DPRINTK(DPINT,"get_dmaa: 0x%08x\n",offset); - - return offset; -} - -static u32 get_dmac(struct m3_state *s) -{ - u32 offset; - - offset = get_dma_pos(s->card, s->adc_inst.data) - - virt_to_bus(s->dma_adc.rawbuf); - - DPRINTK(DPINT,"get_dmac: 0x%08x\n",offset); - - return offset; - -} - -static int -prog_dmabuf(struct m3_state *s, unsigned rec) -{ - struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; - unsigned rate = rec ? s->rateadc : s->ratedac; - unsigned bytepersec; - unsigned bufs; - unsigned char fmt; - unsigned long flags; - - spin_lock_irqsave(&s->card->lock, flags); - - fmt = s->fmt; - if (rec) { - stop_adc(s); - fmt >>= ESS_ADC_SHIFT; - } else { - stop_dac(s); - fmt >>= ESS_DAC_SHIFT; - } - fmt &= ESS_FMT_MASK; - - db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; - - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; - - DPRINTK(DPSTR,"prog_dmabuf: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize); - - memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize); - - if (rec) - m3_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize); - else - m3_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize); - - db->ready = 1; - - spin_unlock_irqrestore(&s->card->lock, flags); - - return 0; -} - -static void clear_advance(struct m3_state *s) -{ - unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80; - - unsigned char *buf = s->dma_dac.rawbuf; - unsigned bsize = s->dma_dac.dmasize; - unsigned bptr = s->dma_dac.swptr; - unsigned len = s->dma_dac.fragsize; - - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(buf + bptr, c, x); - /* account for wrapping? */ - bptr = 0; - len -= x; - } - memset(buf + bptr, c, len); -} - -/* call with spinlock held! */ -static void m3_update_ptr(struct m3_state *s) -{ - unsigned hwptr; - int diff; - - /* update ADC pointer */ - if (s->dma_adc.ready) { - hwptr = get_dmac(s) % s->dma_adc.dmasize; - diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; - s->dma_adc.hwptr = hwptr; - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - wake_up(&s->dma_adc.wait); - if (!s->dma_adc.mapped) { - if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { - stop_adc(s); - /* brute force everyone back in sync, sigh */ - s->dma_adc.count = 0; - s->dma_adc.swptr = 0; - s->dma_adc.hwptr = 0; - s->dma_adc.error++; - } - } - } - /* update DAC pointer */ - if (s->dma_dac.ready) { - hwptr = get_dmaa(s) % s->dma_dac.dmasize; - diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; - - DPRINTK(DPINT,"updating dac: hwptr: %6d diff: %6d count: %6d\n", - hwptr,diff,s->dma_dac.count); - - s->dma_dac.hwptr = hwptr; - s->dma_dac.total_bytes += diff; - - if (s->dma_dac.mapped) { - - s->dma_dac.count += diff; - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) { - wake_up(&s->dma_dac.wait); - } - } else { - - s->dma_dac.count -= diff; - - if (s->dma_dac.count <= 0) { - DPRINTK(DPCRAP,"underflow! diff: %d (0x%x) count: %d (0x%x) hw: %d (0x%x) sw: %d (0x%x)\n", - diff, diff, - s->dma_dac.count, - s->dma_dac.count, - hwptr, hwptr, - s->dma_dac.swptr, - s->dma_dac.swptr); - stop_dac(s); - /* brute force everyone back in sync, sigh */ - s->dma_dac.count = 0; - s->dma_dac.swptr = hwptr; - s->dma_dac.error++; - } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { - clear_advance(s); - s->dma_dac.endcleared = 1; - } - if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) { - wake_up(&s->dma_dac.wait); - DPRINTK(DPINT,"waking up DAC count: %d sw: %d hw: %d\n", - s->dma_dac.count, s->dma_dac.swptr, hwptr); - } - } - } -} - -static irqreturn_t m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct m3_card *c = (struct m3_card *)dev_id; - struct m3_state *s = &c->channels[0]; - u8 status; - - status = inb(c->iobase+0x1A); - - if(status == 0xff) - return IRQ_NONE; - - /* presumably acking the ints? */ - outw(status, c->iobase+0x1A); - - if(c->in_suspend) - return IRQ_HANDLED; - - /* - * ack an assp int if its running - * and has an int pending - */ - if( status & ASSP_INT_PENDING) { - u8 ctl = inb(c->iobase + ASSP_CONTROL_B); - if( !(ctl & STOP_ASSP_CLOCK)) { - ctl = inb(c->iobase + ASSP_HOST_INT_STATUS ); - if(ctl & DSP2HOST_REQ_TIMER) { - outb( DSP2HOST_REQ_TIMER, c->iobase + ASSP_HOST_INT_STATUS); - /* update adc/dac info if it was a timer int */ - spin_lock(&c->lock); - m3_update_ptr(s); - spin_unlock(&c->lock); - } - } - } - - /* XXX is this needed? */ - if(status & 0x40) - outb(0x40, c->iobase+0x1A); - return IRQ_HANDLED; -} - - -/* --------------------------------------------------------------------- */ - -static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value in %s\n"; - -#define VALIDATE_MAGIC(FOO,MAG) \ -({ \ - if (!(FOO) || (FOO)->magic != MAG) { \ - printk(invalid_magic,__FUNCTION__); \ - return -ENXIO; \ - } \ -}) - -#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,M3_STATE_MAGIC) -#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,M3_CARD_MAGIC) - -/* --------------------------------------------------------------------- */ - -static int drain_dac(struct m3_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait,current); - unsigned long flags; - int count; - signed long tmo; - - if (s->dma_dac.mapped || !s->dma_dac.ready) - return 0; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&s->dma_dac.wait, &wait); - for (;;) { - spin_lock_irqsave(&s->card->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->card->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = (count * HZ) / s->ratedac; - tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]; - /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken. - or something. who cares. - zach */ - if (!schedule_timeout(tmo ? tmo : 1) && tmo) - DPRINTK(DPCRAP,"dma timed out?? %ld\n",jiffies); - } - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -static ssize_t m3_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct m3_state *s = (struct m3_state *)file->private_data; - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - - spin_lock_irqsave(&s->card->lock, flags); - - while (count > 0) { - int timed_out; - - swptr = s->dma_adc.swptr; - cnt = s->dma_adc.dmasize-swptr; - if (s->dma_adc.count < cnt) - cnt = s->dma_adc.count; - - if (cnt > count) - cnt = count; - - if (cnt <= 0) { - start_adc(s); - if (file->f_flags & O_NONBLOCK) - { - ret = ret ? ret : -EAGAIN; - goto out; - } - - spin_unlock_irqrestore(&s->card->lock, flags); - timed_out = interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ) == 0; - spin_lock_irqsave(&s->card->lock, flags); - - if(timed_out) { - printk("read: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n", - s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, - s->dma_adc.hwptr, s->dma_adc.swptr); - stop_adc(s); - set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); - s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; - } - if (signal_pending(current)) - { - ret = ret ? ret : -ERESTARTSYS; - goto out; - } - continue; - } - - spin_unlock_irqrestore(&s->card->lock, flags); - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { - ret = ret ? ret : -EFAULT; - return ret; - } - spin_lock_irqsave(&s->card->lock, flags); - - swptr = (swptr + cnt) % s->dma_adc.dmasize; - s->dma_adc.swptr = swptr; - s->dma_adc.count -= cnt; - count -= cnt; - buffer += cnt; - ret += cnt; - start_adc(s); - } - -out: - spin_unlock_irqrestore(&s->card->lock, flags); - return ret; -} - -static ssize_t m3_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct m3_state *s = (struct m3_state *)file->private_data; - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac.mapped) - return -ENXIO; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - - spin_lock_irqsave(&s->card->lock, flags); - - while (count > 0) { - int timed_out; - - if (s->dma_dac.count < 0) { - s->dma_dac.count = 0; - s->dma_dac.swptr = s->dma_dac.hwptr; - } - swptr = s->dma_dac.swptr; - - cnt = s->dma_dac.dmasize-swptr; - - if (s->dma_dac.count + cnt > s->dma_dac.dmasize) - cnt = s->dma_dac.dmasize - s->dma_dac.count; - - - if (cnt > count) - cnt = count; - - if (cnt <= 0) { - start_dac(s); - if (file->f_flags & O_NONBLOCK) { - if(!ret) ret = -EAGAIN; - goto out; - } - spin_unlock_irqrestore(&s->card->lock, flags); - timed_out = interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ) == 0; - spin_lock_irqsave(&s->card->lock, flags); - if(timed_out) { - DPRINTK(DPCRAP,"write: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n", - s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, - s->dma_dac.hwptr, s->dma_dac.swptr); - stop_dac(s); - set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); - s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; - } - if (signal_pending(current)) { - if (!ret) ret = -ERESTARTSYS; - goto out; - } - continue; - } - spin_unlock_irqrestore(&s->card->lock, flags); - if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { - if (!ret) ret = -EFAULT; - return ret; - } - spin_lock_irqsave(&s->card->lock, flags); - - DPRINTK(DPSYS,"wrote %6d bytes at sw: %6d cnt: %6d while hw: %6d\n", - cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr); - - swptr = (swptr + cnt) % s->dma_dac.dmasize; - - s->dma_dac.swptr = swptr; - s->dma_dac.count += cnt; - s->dma_dac.endcleared = 0; - count -= cnt; - buffer += cnt; - ret += cnt; - start_dac(s); - } -out: - spin_unlock_irqrestore(&s->card->lock, flags); - return ret; -} - -static unsigned int m3_poll(struct file *file, struct poll_table_struct *wait) -{ - struct m3_state *s = (struct m3_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) - poll_wait(file, &s->dma_dac.wait, wait); - if (file->f_mode & FMODE_READ) - poll_wait(file, &s->dma_adc.wait, wait); - - spin_lock_irqsave(&s->card->lock, flags); - m3_update_ptr(s); - - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - - spin_unlock_irqrestore(&s->card->lock, flags); - return mask; -} - -static int m3_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct m3_state *s = (struct m3_state *)file->private_data; - unsigned long max_size, size, start, offset; - struct dmabuf *db; - int ret = -EINVAL; - - VALIDATE_STATE(s); - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf(s, 0)) != 0) - return ret; - db = &s->dma_dac; - } else - if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf(s, 1)) != 0) - return ret; - db = &s->dma_adc; - } else - return -EINVAL; - - max_size = db->dmasize; - - start = vma->vm_start; - offset = (vma->vm_pgoff << PAGE_SHIFT); - size = vma->vm_end - vma->vm_start; - - if(size > max_size) - goto out; - if(offset > max_size - size) - goto out; - - /* - * this will be ->nopage() once I can - * ask Jeff what the hell I'm doing wrong. - */ - ret = -EAGAIN; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - - db->mapped = 1; - ret = 0; - -out: - return ret; -} - -/* - * this function is a disaster.. - */ -#define get_user_ret(x, ptr, ret) ({ if(get_user(x, ptr)) return ret; }) -static int m3_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct m3_state *s = (struct m3_state *)file->private_data; - struct m3_card *card=s->card; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int val, mapped, ret; - unsigned char fmtm, fmtd; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_STATE(s); - - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - - DPRINTK(DPSYS,"m3_ioctl: cmd %d\n", cmd); - - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, file->f_flags & O_NONBLOCK); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - /* XXX fix */ - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - spin_lock_irqsave(&card->lock, flags); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(s->card->pcidev->irq); - s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->card->pcidev->irq); - s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; - } - spin_unlock_irqrestore(&card->lock, flags); - return 0; - - case SNDCTL_DSP_SPEED: - get_user_ret(val, p, -EFAULT); - spin_lock_irqsave(&card->lock, flags); - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - set_adc_rate(s, val); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - set_dac_rate(s, val); - } - } - spin_unlock_irqrestore(&card->lock, flags); - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SNDCTL_DSP_STEREO: - get_user_ret(val, p, -EFAULT); - spin_lock_irqsave(&card->lock, flags); - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val) - fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val) - fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); - } - set_fmt(s, fmtm, fmtd); - spin_unlock_irqrestore(&card->lock, flags); - return 0; - - case SNDCTL_DSP_CHANNELS: - get_user_ret(val, p, -EFAULT); - spin_lock_irqsave(&card->lock, flags); - if (val != 0) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val >= 2) - fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val >= 2) - fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); - } - set_fmt(s, fmtm, fmtd); - } - spin_unlock_irqrestore(&card->lock, flags); - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) - : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_U8|AFMT_S16_LE, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, p, -EFAULT); - spin_lock_irqsave(&card->lock, flags); - if (val != AFMT_QUERY) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val == AFMT_S16_LE) - fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT; - else - fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val == AFMT_S16_LE) - fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT; - else - fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT); - } - set_fmt(s, fmtm, fmtd); - } - spin_unlock_irqrestore(&card->lock, flags); - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? - (ESS_FMT_16BIT << ESS_ADC_SHIFT) - : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? - AFMT_S16_LE : - AFMT_U8, - p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING)) - val |= PCM_ENABLE_INPUT; - if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING)) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, p, -EFAULT); - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - start_adc(s); - } else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - start_dac(s); - } else - stop_dac(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0) - return val; - spin_lock_irqsave(&card->lock, flags); - m3_update_ptr(s); - abinfo.fragsize = s->dma_dac.fragsize; - abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - spin_unlock_irqrestore(&card->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!(s->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0) - return val; - spin_lock_irqsave(&card->lock, flags); - m3_update_ptr(s); - abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&card->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&card->lock, flags); - m3_update_ptr(s); - val = s->dma_dac.count; - spin_unlock_irqrestore(&card->lock, flags); - return put_user(val, p); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&card->lock, flags); - m3_update_ptr(s); - cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&card->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&card->lock, flags); - m3_update_ptr(s); - cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; - cinfo.ptr = s->dma_dac.hwptr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize-1; - spin_unlock_irqrestore(&card->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf(s, 0))) - return val; - return put_user(s->dma_dac.fragsize, p); - } - if ((val = prog_dmabuf(s, 1))) - return val; - return put_user(s->dma_adc.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, p, -EFAULT); - spin_lock_irqsave(&card->lock, flags); - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - } - spin_unlock_irqrestore(&card->lock, flags); - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - get_user_ret(val, p, -EFAULT); - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - s->dma_dac.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) - : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) - : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return -EINVAL; -} - -static int -allocate_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db) -{ - int order; - - DPRINTK(DPSTR,"allocating for dmabuf %p\n", db); - - /* - * alloc as big a chunk as we can, start with - * 64k 'cause we're insane. based on order cause - * the amazingly complicated prog_dmabuf wants it. - * - * pci_alloc_sonsistent guarantees that it won't cross a natural - * boundary; the m3 hardware can't have dma cross a 64k bus - * address boundary. - */ - for (order = 16-PAGE_SHIFT; order >= 1; order--) { - db->rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order, - &(db->handle)); - if(db->rawbuf) - break; - } - - if (!db->rawbuf) - return 1; - - DPRINTK(DPSTR,"allocated %ld (%d) bytes at %p\n", - PAGE_SIZE<rawbuf); - - { - struct page *page, *pend; - - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - SetPageReserved(page); - } - - - db->buforder = order; - db->ready = 0; - db->mapped = 0; - - return 0; -} - -static void -nuke_lists(struct m3_card *card, struct dmabuf *db) -{ - m3_remove_list(card, &(card->dma_list), db->dma_index); - m3_remove_list(card, &(card->msrc_list), db->msrc_index); - db->in_lists = 0; -} - -static void -free_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db) -{ - if(db->rawbuf == NULL) - return; - - DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db); - - { - struct page *page, *pend; - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - ClearPageReserved(page); - } - - - pci_free_consistent(pci_dev, PAGE_SIZE << db->buforder, - db->rawbuf, db->handle); - - db->rawbuf = NULL; - db->buforder = 0; - db->mapped = 0; - db->ready = 0; -} - -static int m3_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct m3_card *c; - struct m3_state *s = NULL; - int i; - unsigned char fmtm = ~0, fmts = 0; - unsigned long flags; - - /* - * Scan the cards and find the channel. We only - * do this at open time so it is ok - */ - for(c = devs ; c != NULL ; c = c->next) { - - for(i=0;ichannels[i].dev_audio < 0) - continue; - if((c->channels[i].dev_audio ^ minor) & ~0xf) - continue; - - s = &c->channels[i]; - break; - } - } - - if (!s) - return -ENODEV; - - VALIDATE_STATE(s); - - file->private_data = s; - - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EWOULDBLOCK; - } - mutex_unlock(&s->open_mutex); - interruptible_sleep_on(&s->open_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - - spin_lock_irqsave(&c->lock, flags); - - if (file->f_mode & FMODE_READ) { - fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; - - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; - set_adc_rate(s, 8000); - } - if (file->f_mode & FMODE_WRITE) { - fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT; - - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; - set_dac_rate(s, 8000); - } - set_fmt(s, fmtm, fmts); - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - - mutex_unlock(&s->open_mutex); - spin_unlock_irqrestore(&c->lock, flags); - return nonseekable_open(inode, file); -} - -static int m3_release(struct inode *inode, struct file *file) -{ - struct m3_state *s = (struct m3_state *)file->private_data; - struct m3_card *card=s->card; - unsigned long flags; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) - drain_dac(s, file->f_flags & O_NONBLOCK); - - mutex_lock(&s->open_mutex); - spin_lock_irqsave(&card->lock, flags); - - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - if(s->dma_dac.in_lists) { - m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index); - nuke_lists(s->card, &(s->dma_dac)); - } - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - if(s->dma_adc.in_lists) { - m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index); - nuke_lists(s->card, &(s->dma_adc)); - } - } - - s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); - - spin_unlock_irqrestore(&card->lock, flags); - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - - return 0; -} - -/* - * Wait for the ac97 serial bus to be free. - * return nonzero if the bus is still busy. - */ -static int m3_ac97_wait(struct m3_card *card) -{ - int i = 10000; - - while( (m3_inb(card, 0x30) & 1) && i--) ; - - return i == 0; -} - -static u16 m3_ac97_read(struct ac97_codec *codec, u8 reg) -{ - u16 ret = 0; - struct m3_card *card = codec->private_data; - - spin_lock(&card->ac97_lock); - - if(m3_ac97_wait(card)) { - printk(KERN_ERR PFX "serial bus busy reading reg 0x%x\n",reg); - goto out; - } - - m3_outb(card, 0x80 | (reg & 0x7f), 0x30); - - if(m3_ac97_wait(card)) { - printk(KERN_ERR PFX "serial bus busy finishing read reg 0x%x\n",reg); - goto out; - } - - ret = m3_inw(card, 0x32); - DPRINTK(DPCRAP,"reading 0x%04x from 0x%02x\n",ret, reg); - -out: - spin_unlock(&card->ac97_lock); - return ret; -} - -static void m3_ac97_write(struct ac97_codec *codec, u8 reg, u16 val) -{ - struct m3_card *card = codec->private_data; - - spin_lock(&card->ac97_lock); - - if(m3_ac97_wait(card)) { - printk(KERN_ERR PFX "serial bus busy writing 0x%x to 0x%x\n",val, reg); - goto out; - } - DPRINTK(DPCRAP,"writing 0x%04x to 0x%02x\n", val, reg); - - m3_outw(card, val, 0x32); - m3_outb(card, reg & 0x7f, 0x30); -out: - spin_unlock(&card->ac97_lock); -} -/* OSS /dev/mixer file operation methods */ -static int m3_open_mixdev(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct m3_card *card = devs; - - for (card = devs; card != NULL; card = card->next) { - if((card->ac97 != NULL) && (card->ac97->dev_mixer == minor)) - break; - } - - if (!card) { - return -ENODEV; - } - - file->private_data = card->ac97; - - return nonseekable_open(inode, file); -} - -static int m3_release_mixdev(struct inode *inode, struct file *file) -{ - return 0; -} - -static int m3_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct ac97_codec *codec = (struct ac97_codec *)file->private_data; - - return codec->mixer_ioctl(codec, cmd, arg); -} - -static struct file_operations m3_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = m3_ioctl_mixdev, - .open = m3_open_mixdev, - .release = m3_release_mixdev, -}; - -static void remote_codec_config(int io, int isremote) -{ - isremote = isremote ? 1 : 0; - - outw( (inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote, - io + RING_BUS_CTRL_B); - outw( (inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote, - io + SDO_OUT_DEST_CTRL); - outw( (inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote, - io + SDO_IN_DEST_CTRL); -} - -/* - * hack, returns non zero on err - */ -static int try_read_vendor(struct m3_card *card) -{ - u16 ret; - - if(m3_ac97_wait(card)) - return 1; - - m3_outb(card, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30); - - if(m3_ac97_wait(card)) - return 1; - - ret = m3_inw(card, 0x32); - - return (ret == 0) || (ret == 0xffff); -} - -static void m3_codec_reset(struct m3_card *card, int busywait) -{ - u16 dir; - int delay1 = 0, delay2 = 0, i; - int io = card->iobase; - - switch (card->card_type) { - /* - * the onboard codec on the allegro seems - * to want to wait a very long time before - * coming back to life - */ - case ESS_ALLEGRO: - delay1 = 50; - delay2 = 800; - break; - case ESS_MAESTRO3: - case ESS_MAESTRO3HW: - delay1 = 20; - delay2 = 500; - break; - } - - for(i = 0; i < 5; i ++) { - dir = inw(io + GPIO_DIRECTION); - dir |= 0x10; /* assuming pci bus master? */ - - remote_codec_config(io, 0); - - outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A); - udelay(20); - - outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION); - outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK); - outw(0, io + GPIO_DATA); - outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION); - - if(busywait) { - mdelay(delay1); - } else { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((delay1 * HZ) / 1000); - } - - outw(GPO_PRIMARY_AC97, io + GPIO_DATA); - udelay(5); - /* ok, bring back the ac-link */ - outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A); - outw(~0, io + GPIO_MASK); - - if(busywait) { - mdelay(delay2); - } else { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((delay2 * HZ) / 1000); - } - if(! try_read_vendor(card)) - break; - - delay1 += 10; - delay2 += 100; - - DPRINTK(DPMOD, "retrying codec reset with delays of %d and %d ms\n", - delay1, delay2); - } - -#if 0 - /* more gung-ho reset that doesn't - * seem to work anywhere :) - */ - tmp = inw(io + RING_BUS_CTRL_A); - outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A); - mdelay(20); - outw(tmp, io + RING_BUS_CTRL_A); - mdelay(50); -#endif -} - -static int __devinit m3_codec_install(struct m3_card *card) -{ - struct ac97_codec *codec; - - if ((codec = ac97_alloc_codec()) == NULL) - return -ENOMEM; - - codec->private_data = card; - codec->codec_read = m3_ac97_read; - codec->codec_write = m3_ac97_write; - /* someday we should support secondary codecs.. */ - codec->id = 0; - - if (ac97_probe_codec(codec) == 0) { - printk(KERN_ERR PFX "codec probe failed\n"); - ac97_release_codec(codec); - return -1; - } - - if ((codec->dev_mixer = register_sound_mixer(&m3_mixer_fops, -1)) < 0) { - printk(KERN_ERR PFX "couldn't register mixer!\n"); - ac97_release_codec(codec); - return -1; - } - - card->ac97 = codec; - - return 0; -} - - -#define MINISRC_LPF_LEN 10 -static u16 minisrc_lpf[MINISRC_LPF_LEN] = { - 0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C, - 0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F -}; -static void m3_assp_init(struct m3_card *card) -{ - int i; - - /* zero kernel data */ - for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++) - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_BASE_ADDR + i, 0); - - /* zero mixer data? */ - for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++) - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_BASE_ADDR2 + i, 0); - - /* init dma pointer */ - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_CURRENT_DMA, - KDATA_DMA_XFER0); - - /* write kernel into code memory.. */ - for(i = 0 ; i < sizeof(assp_kernel_image) / 2; i++) { - m3_assp_write(card, MEMTYPE_INTERNAL_CODE, - REV_B_CODE_MEMORY_BEGIN + i, - assp_kernel_image[i]); - } - - /* - * We only have this one client and we know that 0x400 - * is free in our kernel's mem map, so lets just - * drop it there. It seems that the minisrc doesn't - * need vectors, so we won't bother with them.. - */ - for(i = 0 ; i < sizeof(assp_minisrc_image) / 2; i++) { - m3_assp_write(card, MEMTYPE_INTERNAL_CODE, - 0x400 + i, - assp_minisrc_image[i]); - } - - /* - * write the coefficients for the low pass filter? - */ - for(i = 0; i < MINISRC_LPF_LEN ; i++) { - m3_assp_write(card, MEMTYPE_INTERNAL_CODE, - 0x400 + MINISRC_COEF_LOC + i, - minisrc_lpf[i]); - } - - m3_assp_write(card, MEMTYPE_INTERNAL_CODE, - 0x400 + MINISRC_COEF_LOC + MINISRC_LPF_LEN, - 0x8000); - - /* - * the minisrc is the only thing on - * our task list.. - */ - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_TASK0, - 0x400); - - /* - * init the mixer number.. - */ - - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_MIXER_TASK_NUMBER,0); - - /* - * EXTREME KERNEL MASTER VOLUME - */ - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_DAC_LEFT_VOLUME, ARB_VOLUME); - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME); - - card->mixer_list.mem_addr = KDATA_MIXER_XFER0; - card->mixer_list.max = MAX_VIRTUAL_MIXER_CHANNELS; - card->adc1_list.mem_addr = KDATA_ADC1_XFER0; - card->adc1_list.max = MAX_VIRTUAL_ADC1_CHANNELS; - card->dma_list.mem_addr = KDATA_DMA_XFER0; - card->dma_list.max = MAX_VIRTUAL_DMA_CHANNELS; - card->msrc_list.mem_addr = KDATA_INSTANCE0_MINISRC; - card->msrc_list.max = MAX_INSTANCE_MINISRC; -} - -static int setup_msrc(struct m3_card *card, - struct assp_instance *inst, int index) -{ - int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 + - MINISRC_IN_BUFFER_SIZE / 2 + - 1 + MINISRC_OUT_BUFFER_SIZE / 2 + 1 ); - int address, i; - - /* - * the revb memory map has 0x1100 through 0x1c00 - * free. - */ - - /* - * align instance address to 256 bytes so that it's - * shifted list address is aligned. - * list address = (mem address >> 1) >> 7; - */ - data_bytes = (data_bytes + 255) & ~255; - address = 0x1100 + ((data_bytes/2) * index); - - if((address + (data_bytes/2)) >= 0x1c00) { - printk(KERN_ERR PFX "no memory for %d bytes at ind %d (addr 0x%x)\n", - data_bytes, index, address); - return -1; - } - - for(i = 0; i < data_bytes/2 ; i++) - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - address + i, 0); - - inst->code = 0x400; - inst->data = address; - - return 0; -} - -static int m3_assp_client_init(struct m3_state *s) -{ - setup_msrc(s->card, &(s->dac_inst), s->index * 2); - setup_msrc(s->card, &(s->adc_inst), (s->index * 2) + 1); - - return 0; -} - -static void m3_amp_enable(struct m3_card *card, int enable) -{ - /* - * this works for the reference board, have to find - * out about others - * - * this needs more magic for 4 speaker, but.. - */ - int io = card->iobase; - u16 gpo, polarity_port, polarity; - - if(!external_amp) - return; - - if (gpio_pin >= 0 && gpio_pin <= 15) { - polarity_port = 0x1000 + (0x100 * gpio_pin); - } else { - switch (card->card_type) { - case ESS_ALLEGRO: - polarity_port = 0x1800; - break; - default: - polarity_port = 0x1100; - /* Panasonic toughbook CF72 has to be different... */ - if(card->pcidev->subsystem_vendor == 0x10F7 && card->pcidev->subsystem_device == 0x833D) - polarity_port = 0x1D00; - break; - } - } - - gpo = (polarity_port >> 8) & 0x0F; - polarity = polarity_port >> 12; - if ( enable ) - polarity = !polarity; - polarity = polarity << gpo; - gpo = 1 << gpo; - - outw(~gpo , io + GPIO_MASK); - - outw( inw(io + GPIO_DIRECTION) | gpo , - io + GPIO_DIRECTION); - - outw( (GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity) , - io + GPIO_DATA); - - outw(0xffff , io + GPIO_MASK); -} - -static int -maestro_config(struct m3_card *card) -{ - struct pci_dev *pcidev = card->pcidev; - u32 n; - u8 t; /* makes as much sense as 'n', no? */ - - pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); - n &= REDUCED_DEBOUNCE; - n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; - pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); - - outb(RESET_ASSP, card->iobase + ASSP_CONTROL_B); - pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); - n &= ~INT_CLK_SELECT; - if(card->card_type >= ESS_MAESTRO3) { - n &= ~INT_CLK_MULT_ENABLE; - n |= INT_CLK_SRC_NOT_PCI; - } - n &= ~( CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2 ); - pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); - - if(card->card_type <= ESS_ALLEGRO) { - pci_read_config_dword(pcidev, PCI_USER_CONFIG, &n); - n |= IN_CLK_12MHZ_SELECT; - pci_write_config_dword(pcidev, PCI_USER_CONFIG, n); - } - - t = inb(card->iobase + ASSP_CONTROL_A); - t &= ~( DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT); - t |= ASSP_CLK_49MHZ_SELECT; - t |= ASSP_0_WS_ENABLE; - outb(t, card->iobase + ASSP_CONTROL_A); - - outb(RUN_ASSP, card->iobase + ASSP_CONTROL_B); - - return 0; -} - -static void m3_enable_ints(struct m3_card *card) -{ - unsigned long io = card->iobase; - - outw(ASSP_INT_ENABLE, io + HOST_INT_CTRL); - outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, - io + ASSP_CONTROL_C); -} - -static struct file_operations m3_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = m3_read, - .write = m3_write, - .poll = m3_poll, - .ioctl = m3_ioctl, - .mmap = m3_mmap, - .open = m3_open, - .release = m3_release, -}; - -#ifdef CONFIG_PM -static int alloc_dsp_suspendmem(struct m3_card *card) -{ - int len = sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH); - - if( (card->suspend_mem = vmalloc(len)) == NULL) - return 1; - - return 0; -} - -#else -#define alloc_dsp_suspendmem(args...) 0 -#endif - -/* - * great day! this function is ugly as hell. - */ -static int __devinit m3_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) -{ - u32 n; - int i; - struct m3_card *card = NULL; - int ret = 0; - int card_type = pci_id->driver_data; - - DPRINTK(DPMOD, "in maestro_install\n"); - - if (pci_enable_device(pci_dev)) - return -EIO; - - if (pci_set_dma_mask(pci_dev, M3_PCI_DMA_MASK)) { - printk(KERN_ERR PFX "architecture does not support limiting to 28bit PCI bus addresses\n"); - return -ENODEV; - } - - pci_set_master(pci_dev); - - if( (card = kmalloc(sizeof(struct m3_card), GFP_KERNEL)) == NULL) { - printk(KERN_WARNING PFX "out of memory\n"); - return -ENOMEM; - } - memset(card, 0, sizeof(struct m3_card)); - card->pcidev = pci_dev; - init_waitqueue_head(&card->suspend_queue); - - if ( ! request_region(pci_resource_start(pci_dev, 0), - pci_resource_len (pci_dev, 0), M3_MODULE_NAME)) { - - printk(KERN_WARNING PFX "unable to reserve I/O space.\n"); - ret = -EBUSY; - goto out; - } - - card->iobase = pci_resource_start(pci_dev, 0); - - if(alloc_dsp_suspendmem(card)) { - printk(KERN_WARNING PFX "couldn't alloc %d bytes for saving dsp state on suspend\n", - REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH); - ret = -ENOMEM; - goto out; - } - - card->card_type = card_type; - card->irq = pci_dev->irq; - card->next = devs; - card->magic = M3_CARD_MAGIC; - spin_lock_init(&card->lock); - spin_lock_init(&card->ac97_lock); - devs = card; - for(i = 0; ichannels[i]); - s->dev_audio = -1; - } - - printk(KERN_INFO PFX "Configuring ESS %s found at IO 0x%04X IRQ %d\n", - card_names[card->card_type], card->iobase, card->irq); - - pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &n); - printk(KERN_INFO PFX " subvendor id: 0x%08x\n",n); - - maestro_config(card); - m3_assp_halt(card); - - m3_codec_reset(card, 0); - - if(m3_codec_install(card)) { - ret = -EIO; - goto out; - } - - m3_assp_init(card); - m3_amp_enable(card, 1); - - for(i=0;ichannels[i]; - - s->index = i; - - s->card = card; - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - mutex_init(&(s->open_mutex)); - s->magic = M3_STATE_MAGIC; - - m3_assp_client_init(s); - - if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf) - printk(KERN_WARNING PFX "initing a dsp device that is already in use?\n"); - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&m3_audio_fops, -1)) < 0) { - break; - } - - if( allocate_dmabuf(card->pcidev, &(s->dma_adc)) || - allocate_dmabuf(card->pcidev, &(s->dma_dac))) { - ret = -ENOMEM; - goto out; - } - } - - if(request_irq(card->irq, m3_interrupt, IRQF_SHARED, card_names[card->card_type], card)) { - - printk(KERN_ERR PFX "unable to allocate irq %d,\n", card->irq); - - ret = -EIO; - goto out; - } - - pci_set_drvdata(pci_dev, card); - - m3_enable_ints(card); - m3_assp_continue(card); - -out: - if(ret) { - if(card->iobase) - release_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); - vfree(card->suspend_mem); - if(card->ac97) { - unregister_sound_mixer(card->ac97->dev_mixer); - kfree(card->ac97); - } - for(i=0;ichannels[i]; - if(s->dev_audio != -1) - unregister_sound_dsp(s->dev_audio); - } - kfree(card); - } - - return ret; -} - -static void m3_remove(struct pci_dev *pci_dev) -{ - struct m3_card *card; - - unregister_reboot_notifier(&m3_reboot_nb); - - while ((card = devs)) { - int i; - devs = devs->next; - - free_irq(card->irq, card); - unregister_sound_mixer(card->ac97->dev_mixer); - kfree(card->ac97); - - for(i=0;ichannels[i]; - if(s->dev_audio < 0) - continue; - - unregister_sound_dsp(s->dev_audio); - free_dmabuf(card->pcidev, &s->dma_adc); - free_dmabuf(card->pcidev, &s->dma_dac); - } - - release_region(card->iobase, 256); - vfree(card->suspend_mem); - kfree(card); - } - devs = NULL; -} - -/* - * some bioses like the sound chip to be powered down - * at shutdown. We're just calling _suspend to - * achieve that.. - */ -static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf) -{ - struct m3_card *card; - - DPRINTK(DPMOD, "notifier suspending all cards\n"); - - for(card = devs; card != NULL; card = card->next) { - if(!card->in_suspend) - m3_suspend(card->pcidev, PMSG_SUSPEND); /* XXX legal? */ - } - return 0; -} - -static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state) -{ - unsigned long flags; - int i; - struct m3_card *card = pci_get_drvdata(pci_dev); - - /* must be a better way.. */ - spin_lock_irqsave(&card->lock, flags); - - DPRINTK(DPMOD, "pm in dev %p\n",card); - - for(i=0;ichannels[i]; - - if(s->dev_audio == -1) - continue; - - DPRINTK(DPMOD, "stop_adc/dac() device %d\n",i); - stop_dac(s); - stop_adc(s); - } - - mdelay(10); /* give the assp a chance to idle.. */ - - m3_assp_halt(card); - - if(card->suspend_mem) { - int index = 0; - - DPRINTK(DPMOD, "saving code\n"); - for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++) - card->suspend_mem[index++] = - m3_assp_read(card, MEMTYPE_INTERNAL_CODE, i); - DPRINTK(DPMOD, "saving data\n"); - for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++) - card->suspend_mem[index++] = - m3_assp_read(card, MEMTYPE_INTERNAL_DATA, i); - } - - DPRINTK(DPMOD, "powering down apci regs\n"); - m3_outw(card, 0xffff, 0x54); - m3_outw(card, 0xffff, 0x56); - - card->in_suspend = 1; - - spin_unlock_irqrestore(&card->lock, flags); - - return 0; -} - -static int m3_resume(struct pci_dev *pci_dev) -{ - unsigned long flags; - int index; - int i; - struct m3_card *card = pci_get_drvdata(pci_dev); - - spin_lock_irqsave(&card->lock, flags); - card->in_suspend = 0; - - DPRINTK(DPMOD, "resuming\n"); - - /* first lets just bring everything back. .*/ - - DPRINTK(DPMOD, "bringing power back on card 0x%p\n",card); - m3_outw(card, 0, 0x54); - m3_outw(card, 0, 0x56); - - DPRINTK(DPMOD, "restoring pci configs and reseting codec\n"); - maestro_config(card); - m3_assp_halt(card); - m3_codec_reset(card, 1); - - DPRINTK(DPMOD, "restoring dsp code card\n"); - index = 0; - for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++) - m3_assp_write(card, MEMTYPE_INTERNAL_CODE, i, - card->suspend_mem[index++]); - for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++) - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, i, - card->suspend_mem[index++]); - - /* tell the dma engine to restart itself */ - m3_assp_write(card, MEMTYPE_INTERNAL_DATA, - KDATA_DMA_ACTIVE, 0); - - DPRINTK(DPMOD, "resuming dsp\n"); - m3_assp_continue(card); - - DPRINTK(DPMOD, "enabling ints\n"); - m3_enable_ints(card); - - /* bring back the old school flavor */ - for(i = 0; i < SOUND_MIXER_NRDEVICES ; i++) { - int state = card->ac97->mixer_state[i]; - if (!supported_mixer(card->ac97, i)) - continue; - - card->ac97->write_mixer(card->ac97, i, - state & 0xff, (state >> 8) & 0xff); - } - - m3_amp_enable(card, 1); - - /* - * now we flip on the music - */ - for(i=0;ichannels[i]; - if(s->dev_audio == -1) - continue; - /* - * db->ready makes it so these guys can be - * called unconditionally.. - */ - DPRINTK(DPMOD, "turning on dacs ind %d\n",i); - start_dac(s); - start_adc(s); - } - - spin_unlock_irqrestore(&card->lock, flags); - - /* - * all right, we think things are ready, - * wake up people who were using the device - * when we suspended - */ - wake_up(&card->suspend_queue); - - return 0; -} - -MODULE_AUTHOR("Zach Brown "); -MODULE_DESCRIPTION("ESS Maestro3/Allegro Driver"); -MODULE_LICENSE("GPL"); - -#ifdef M_DEBUG -module_param(debug, int, 0); -#endif -module_param(external_amp, int, 0); -module_param(gpio_pin, int, 0); - -static struct pci_driver m3_pci_driver = { - .name = "ess_m3_audio", - .id_table = m3_id_table, - .probe = m3_probe, - .remove = m3_remove, - .suspend = m3_suspend, - .resume = m3_resume, -}; - -static int __init m3_init_module(void) -{ - printk(KERN_INFO PFX "version " DRIVER_VERSION " built at " __TIME__ " " __DATE__ "\n"); - - if (register_reboot_notifier(&m3_reboot_nb)) { - printk(KERN_WARNING PFX "reboot notifier registration failed\n"); - return -ENODEV; /* ? */ - } - - if (pci_register_driver(&m3_pci_driver)) { - unregister_reboot_notifier(&m3_reboot_nb); - return -ENODEV; - } - return 0; -} - -static void __exit m3_cleanup_module(void) -{ - pci_unregister_driver(&m3_pci_driver); -} - -module_init(m3_init_module); -module_exit(m3_cleanup_module); - -void check_suspend(struct m3_card *card) -{ - DECLARE_WAITQUEUE(wait, current); - - if(!card->in_suspend) - return; - - card->in_suspend++; - add_wait_queue(&card->suspend_queue, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule(); - remove_wait_queue(&card->suspend_queue, &wait); - set_current_state(TASK_RUNNING); -} diff --git a/sound/oss/maestro3.h b/sound/oss/maestro3.h deleted file mode 100644 index dde29862c572..000000000000 --- a/sound/oss/maestro3.h +++ /dev/null @@ -1,821 +0,0 @@ -/* - * ESS Technology allegro audio driver. - * - * Copyright (C) 1992-2000 Don Kim (don.kim@esstech.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Hacked for the maestro3 driver by zab - */ - -// Allegro PCI configuration registers -#define PCI_LEGACY_AUDIO_CTRL 0x40 -#define SOUND_BLASTER_ENABLE 0x00000001 -#define FM_SYNTHESIS_ENABLE 0x00000002 -#define GAME_PORT_ENABLE 0x00000004 -#define MPU401_IO_ENABLE 0x00000008 -#define MPU401_IRQ_ENABLE 0x00000010 -#define ALIAS_10BIT_IO 0x00000020 -#define SB_DMA_MASK 0x000000C0 -#define SB_DMA_0 0x00000040 -#define SB_DMA_1 0x00000040 -#define SB_DMA_R 0x00000080 -#define SB_DMA_3 0x000000C0 -#define SB_IRQ_MASK 0x00000700 -#define SB_IRQ_5 0x00000000 -#define SB_IRQ_7 0x00000100 -#define SB_IRQ_9 0x00000200 -#define SB_IRQ_10 0x00000300 -#define MIDI_IRQ_MASK 0x00003800 -#define SERIAL_IRQ_ENABLE 0x00004000 -#define DISABLE_LEGACY 0x00008000 - -#define PCI_ALLEGRO_CONFIG 0x50 -#define SB_ADDR_240 0x00000004 -#define MPU_ADDR_MASK 0x00000018 -#define MPU_ADDR_330 0x00000000 -#define MPU_ADDR_300 0x00000008 -#define MPU_ADDR_320 0x00000010 -#define MPU_ADDR_340 0x00000018 -#define USE_PCI_TIMING 0x00000040 -#define POSTED_WRITE_ENABLE 0x00000080 -#define DMA_POLICY_MASK 0x00000700 -#define DMA_DDMA 0x00000000 -#define DMA_TDMA 0x00000100 -#define DMA_PCPCI 0x00000200 -#define DMA_WBDMA16 0x00000400 -#define DMA_WBDMA4 0x00000500 -#define DMA_WBDMA2 0x00000600 -#define DMA_WBDMA1 0x00000700 -#define DMA_SAFE_GUARD 0x00000800 -#define HI_PERF_GP_ENABLE 0x00001000 -#define PIC_SNOOP_MODE_0 0x00002000 -#define PIC_SNOOP_MODE_1 0x00004000 -#define SOUNDBLASTER_IRQ_MASK 0x00008000 -#define RING_IN_ENABLE 0x00010000 -#define SPDIF_TEST_MODE 0x00020000 -#define CLK_MULT_MODE_SELECT_2 0x00040000 -#define EEPROM_WRITE_ENABLE 0x00080000 -#define CODEC_DIR_IN 0x00100000 -#define HV_BUTTON_FROM_GD 0x00200000 -#define REDUCED_DEBOUNCE 0x00400000 -#define HV_CTRL_ENABLE 0x00800000 -#define SPDIF_ENABLE 0x01000000 -#define CLK_DIV_SELECT 0x06000000 -#define CLK_DIV_BY_48 0x00000000 -#define CLK_DIV_BY_49 0x02000000 -#define CLK_DIV_BY_50 0x04000000 -#define CLK_DIV_RESERVED 0x06000000 -#define PM_CTRL_ENABLE 0x08000000 -#define CLK_MULT_MODE_SELECT 0x30000000 -#define CLK_MULT_MODE_SHIFT 28 -#define CLK_MULT_MODE_0 0x00000000 -#define CLK_MULT_MODE_1 0x10000000 -#define CLK_MULT_MODE_2 0x20000000 -#define CLK_MULT_MODE_3 0x30000000 -#define INT_CLK_SELECT 0x40000000 -#define INT_CLK_MULT_RESET 0x80000000 - -// M3 -#define INT_CLK_SRC_NOT_PCI 0x00100000 -#define INT_CLK_MULT_ENABLE 0x80000000 - -#define PCI_ACPI_CONTROL 0x54 -#define PCI_ACPI_D0 0x00000000 -#define PCI_ACPI_D1 0xB4F70000 -#define PCI_ACPI_D2 0xB4F7B4F7 - -#define PCI_USER_CONFIG 0x58 -#define EXT_PCI_MASTER_ENABLE 0x00000001 -#define SPDIF_OUT_SELECT 0x00000002 -#define TEST_PIN_DIR_CTRL 0x00000004 -#define AC97_CODEC_TEST 0x00000020 -#define TRI_STATE_BUFFER 0x00000080 -#define IN_CLK_12MHZ_SELECT 0x00000100 -#define MULTI_FUNC_DISABLE 0x00000200 -#define EXT_MASTER_PAIR_SEL 0x00000400 -#define PCI_MASTER_SUPPORT 0x00000800 -#define STOP_CLOCK_ENABLE 0x00001000 -#define EAPD_DRIVE_ENABLE 0x00002000 -#define REQ_TRI_STATE_ENABLE 0x00004000 -#define REQ_LOW_ENABLE 0x00008000 -#define MIDI_1_ENABLE 0x00010000 -#define MIDI_2_ENABLE 0x00020000 -#define SB_AUDIO_SYNC 0x00040000 -#define HV_CTRL_TEST 0x00100000 -#define SOUNDBLASTER_TEST 0x00400000 - -#define PCI_USER_CONFIG_C 0x5C - -#define PCI_DDMA_CTRL 0x60 -#define DDMA_ENABLE 0x00000001 - - -// Allegro registers -#define HOST_INT_CTRL 0x18 -#define SB_INT_ENABLE 0x0001 -#define MPU401_INT_ENABLE 0x0002 -#define ASSP_INT_ENABLE 0x0010 -#define RING_INT_ENABLE 0x0020 -#define HV_INT_ENABLE 0x0040 -#define CLKRUN_GEN_ENABLE 0x0100 -#define HV_CTRL_TO_PME 0x0400 -#define SOFTWARE_RESET_ENABLE 0x8000 - -/* - * should be using the above defines, probably. - */ -#define REGB_ENABLE_RESET 0x01 -#define REGB_STOP_CLOCK 0x10 - -#define HOST_INT_STATUS 0x1A -#define SB_INT_PENDING 0x01 -#define MPU401_INT_PENDING 0x02 -#define ASSP_INT_PENDING 0x10 -#define RING_INT_PENDING 0x20 -#define HV_INT_PENDING 0x40 - -#define HARDWARE_VOL_CTRL 0x1B -#define SHADOW_MIX_REG_VOICE 0x1C -#define HW_VOL_COUNTER_VOICE 0x1D -#define SHADOW_MIX_REG_MASTER 0x1E -#define HW_VOL_COUNTER_MASTER 0x1F - -#define CODEC_COMMAND 0x30 -#define CODEC_READ_B 0x80 - -#define CODEC_STATUS 0x30 -#define CODEC_BUSY_B 0x01 - -#define CODEC_DATA 0x32 - -#define RING_BUS_CTRL_A 0x36 -#define RAC_PME_ENABLE 0x0100 -#define RAC_SDFS_ENABLE 0x0200 -#define LAC_PME_ENABLE 0x0400 -#define LAC_SDFS_ENABLE 0x0800 -#define SERIAL_AC_LINK_ENABLE 0x1000 -#define IO_SRAM_ENABLE 0x2000 -#define IIS_INPUT_ENABLE 0x8000 - -#define RING_BUS_CTRL_B 0x38 -#define SECOND_CODEC_ID_MASK 0x0003 -#define SPDIF_FUNC_ENABLE 0x0010 -#define SECOND_AC_ENABLE 0x0020 -#define SB_MODULE_INTF_ENABLE 0x0040 -#define SSPE_ENABLE 0x0040 -#define M3I_DOCK_ENABLE 0x0080 - -#define SDO_OUT_DEST_CTRL 0x3A -#define COMMAND_ADDR_OUT 0x0003 -#define PCM_LR_OUT_LOCAL 0x0000 -#define PCM_LR_OUT_REMOTE 0x0004 -#define PCM_LR_OUT_MUTE 0x0008 -#define PCM_LR_OUT_BOTH 0x000C -#define LINE1_DAC_OUT_LOCAL 0x0000 -#define LINE1_DAC_OUT_REMOTE 0x0010 -#define LINE1_DAC_OUT_MUTE 0x0020 -#define LINE1_DAC_OUT_BOTH 0x0030 -#define PCM_CLS_OUT_LOCAL 0x0000 -#define PCM_CLS_OUT_REMOTE 0x0040 -#define PCM_CLS_OUT_MUTE 0x0080 -#define PCM_CLS_OUT_BOTH 0x00C0 -#define PCM_RLF_OUT_LOCAL 0x0000 -#define PCM_RLF_OUT_REMOTE 0x0100 -#define PCM_RLF_OUT_MUTE 0x0200 -#define PCM_RLF_OUT_BOTH 0x0300 -#define LINE2_DAC_OUT_LOCAL 0x0000 -#define LINE2_DAC_OUT_REMOTE 0x0400 -#define LINE2_DAC_OUT_MUTE 0x0800 -#define LINE2_DAC_OUT_BOTH 0x0C00 -#define HANDSET_OUT_LOCAL 0x0000 -#define HANDSET_OUT_REMOTE 0x1000 -#define HANDSET_OUT_MUTE 0x2000 -#define HANDSET_OUT_BOTH 0x3000 -#define IO_CTRL_OUT_LOCAL 0x0000 -#define IO_CTRL_OUT_REMOTE 0x4000 -#define IO_CTRL_OUT_MUTE 0x8000 -#define IO_CTRL_OUT_BOTH 0xC000 - -#define SDO_IN_DEST_CTRL 0x3C -#define STATUS_ADDR_IN 0x0003 -#define PCM_LR_IN_LOCAL 0x0000 -#define PCM_LR_IN_REMOTE 0x0004 -#define PCM_LR_RESERVED 0x0008 -#define PCM_LR_IN_BOTH 0x000C -#define LINE1_ADC_IN_LOCAL 0x0000 -#define LINE1_ADC_IN_REMOTE 0x0010 -#define LINE1_ADC_IN_MUTE 0x0020 -#define MIC_ADC_IN_LOCAL 0x0000 -#define MIC_ADC_IN_REMOTE 0x0040 -#define MIC_ADC_IN_MUTE 0x0080 -#define LINE2_DAC_IN_LOCAL 0x0000 -#define LINE2_DAC_IN_REMOTE 0x0400 -#define LINE2_DAC_IN_MUTE 0x0800 -#define HANDSET_IN_LOCAL 0x0000 -#define HANDSET_IN_REMOTE 0x1000 -#define HANDSET_IN_MUTE 0x2000 -#define IO_STATUS_IN_LOCAL 0x0000 -#define IO_STATUS_IN_REMOTE 0x4000 - -#define SPDIF_IN_CTRL 0x3E -#define SPDIF_IN_ENABLE 0x0001 - -#define GPIO_DATA 0x60 -#define GPIO_DATA_MASK 0x0FFF -#define GPIO_HV_STATUS 0x3000 -#define GPIO_PME_STATUS 0x4000 - -#define GPIO_MASK 0x64 -#define GPIO_DIRECTION 0x68 -#define GPO_PRIMARY_AC97 0x0001 -#define GPI_LINEOUT_SENSE 0x0004 -#define GPO_SECONDARY_AC97 0x0008 -#define GPI_VOL_DOWN 0x0010 -#define GPI_VOL_UP 0x0020 -#define GPI_IIS_CLK 0x0040 -#define GPI_IIS_LRCLK 0x0080 -#define GPI_IIS_DATA 0x0100 -#define GPI_DOCKING_STATUS 0x0100 -#define GPI_HEADPHONE_SENSE 0x0200 -#define GPO_EXT_AMP_SHUTDOWN 0x1000 - -// M3 -#define GPO_M3_EXT_AMP_SHUTDN 0x0002 - -#define ASSP_INDEX_PORT 0x80 -#define ASSP_MEMORY_PORT 0x82 -#define ASSP_DATA_PORT 0x84 - -#define MPU401_DATA_PORT 0x98 -#define MPU401_STATUS_PORT 0x99 - -#define CLK_MULT_DATA_PORT 0x9C - -#define ASSP_CONTROL_A 0xA2 -#define ASSP_0_WS_ENABLE 0x01 -#define ASSP_CTRL_A_RESERVED1 0x02 -#define ASSP_CTRL_A_RESERVED2 0x04 -#define ASSP_CLK_49MHZ_SELECT 0x08 -#define FAST_PLU_ENABLE 0x10 -#define ASSP_CTRL_A_RESERVED3 0x20 -#define DSP_CLK_36MHZ_SELECT 0x40 - -#define ASSP_CONTROL_B 0xA4 -#define RESET_ASSP 0x00 -#define RUN_ASSP 0x01 -#define ENABLE_ASSP_CLOCK 0x00 -#define STOP_ASSP_CLOCK 0x10 -#define RESET_TOGGLE 0x40 - -#define ASSP_CONTROL_C 0xA6 -#define ASSP_HOST_INT_ENABLE 0x01 -#define FM_ADDR_REMAP_DISABLE 0x02 -#define HOST_WRITE_PORT_ENABLE 0x08 - -#define ASSP_HOST_INT_STATUS 0xAC -#define DSP2HOST_REQ_PIORECORD 0x01 -#define DSP2HOST_REQ_I2SRATE 0x02 -#define DSP2HOST_REQ_TIMER 0x04 - -// AC97 registers -// XXX fix this crap up -/*#define AC97_RESET 0x00*/ - -#define AC97_VOL_MUTE_B 0x8000 -#define AC97_VOL_M 0x1F -#define AC97_LEFT_VOL_S 8 - -#define AC97_MASTER_VOL 0x02 -#define AC97_LINE_LEVEL_VOL 0x04 -#define AC97_MASTER_MONO_VOL 0x06 -#define AC97_PC_BEEP_VOL 0x0A -#define AC97_PC_BEEP_VOL_M 0x0F -#define AC97_SROUND_MASTER_VOL 0x38 -#define AC97_PC_BEEP_VOL_S 1 - -/*#define AC97_PHONE_VOL 0x0C -#define AC97_MIC_VOL 0x0E*/ -#define AC97_MIC_20DB_ENABLE 0x40 - -/*#define AC97_LINEIN_VOL 0x10 -#define AC97_CD_VOL 0x12 -#define AC97_VIDEO_VOL 0x14 -#define AC97_AUX_VOL 0x16*/ -#define AC97_PCM_OUT_VOL 0x18 -/*#define AC97_RECORD_SELECT 0x1A*/ -#define AC97_RECORD_MIC 0x00 -#define AC97_RECORD_CD 0x01 -#define AC97_RECORD_VIDEO 0x02 -#define AC97_RECORD_AUX 0x03 -#define AC97_RECORD_MONO_MUX 0x02 -#define AC97_RECORD_DIGITAL 0x03 -#define AC97_RECORD_LINE 0x04 -#define AC97_RECORD_STEREO 0x05 -#define AC97_RECORD_MONO 0x06 -#define AC97_RECORD_PHONE 0x07 - -/*#define AC97_RECORD_GAIN 0x1C*/ -#define AC97_RECORD_VOL_M 0x0F - -/*#define AC97_GENERAL_PURPOSE 0x20*/ -#define AC97_POWER_DOWN_CTRL 0x26 -#define AC97_ADC_READY 0x0001 -#define AC97_DAC_READY 0x0002 -#define AC97_ANALOG_READY 0x0004 -#define AC97_VREF_ON 0x0008 -#define AC97_PR0 0x0100 -#define AC97_PR1 0x0200 -#define AC97_PR2 0x0400 -#define AC97_PR3 0x0800 -#define AC97_PR4 0x1000 - -#define AC97_RESERVED1 0x28 - -#define AC97_VENDOR_TEST 0x5A - -#define AC97_CLOCK_DELAY 0x5C -#define AC97_LINEOUT_MUX_SEL 0x0001 -#define AC97_MONO_MUX_SEL 0x0002 -#define AC97_CLOCK_DELAY_SEL 0x1F -#define AC97_DAC_CDS_SHIFT 6 -#define AC97_ADC_CDS_SHIFT 11 - -#define AC97_MULTI_CHANNEL_SEL 0x74 - -/*#define AC97_VENDOR_ID1 0x7C -#define AC97_VENDOR_ID2 0x7E*/ - -/* - * ASSP control regs - */ -#define DSP_PORT_TIMER_COUNT 0x06 - -#define DSP_PORT_MEMORY_INDEX 0x80 - -#define DSP_PORT_MEMORY_TYPE 0x82 -#define MEMTYPE_INTERNAL_CODE 0x0002 -#define MEMTYPE_INTERNAL_DATA 0x0003 -#define MEMTYPE_MASK 0x0003 - -#define DSP_PORT_MEMORY_DATA 0x84 - -#define DSP_PORT_CONTROL_REG_A 0xA2 -#define DSP_PORT_CONTROL_REG_B 0xA4 -#define DSP_PORT_CONTROL_REG_C 0xA6 - -#define REV_A_CODE_MEMORY_BEGIN 0x0000 -#define REV_A_CODE_MEMORY_END 0x0FFF -#define REV_A_CODE_MEMORY_UNIT_LENGTH 0x0040 -#define REV_A_CODE_MEMORY_LENGTH (REV_A_CODE_MEMORY_END - REV_A_CODE_MEMORY_BEGIN + 1) - -#define REV_B_CODE_MEMORY_BEGIN 0x0000 -#define REV_B_CODE_MEMORY_END 0x0BFF -#define REV_B_CODE_MEMORY_UNIT_LENGTH 0x0040 -#define REV_B_CODE_MEMORY_LENGTH (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1) - -#define REV_A_DATA_MEMORY_BEGIN 0x1000 -#define REV_A_DATA_MEMORY_END 0x2FFF -#define REV_A_DATA_MEMORY_UNIT_LENGTH 0x0080 -#define REV_A_DATA_MEMORY_LENGTH (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1) - -#define REV_B_DATA_MEMORY_BEGIN 0x1000 -#define REV_B_DATA_MEMORY_END 0x2BFF -#define REV_B_DATA_MEMORY_UNIT_LENGTH 0x0080 -#define REV_B_DATA_MEMORY_LENGTH (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1) - - -#define NUM_UNITS_KERNEL_CODE 16 -#define NUM_UNITS_KERNEL_DATA 2 - -#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16 -#define NUM_UNITS_KERNEL_DATA_WITH_HSP 5 - -/* - * Kernel data layout - */ - -#define DP_SHIFT_COUNT 7 - -#define KDATA_BASE_ADDR 0x1000 -#define KDATA_BASE_ADDR2 0x1080 - -#define KDATA_TASK0 (KDATA_BASE_ADDR + 0x0000) -#define KDATA_TASK1 (KDATA_BASE_ADDR + 0x0001) -#define KDATA_TASK2 (KDATA_BASE_ADDR + 0x0002) -#define KDATA_TASK3 (KDATA_BASE_ADDR + 0x0003) -#define KDATA_TASK4 (KDATA_BASE_ADDR + 0x0004) -#define KDATA_TASK5 (KDATA_BASE_ADDR + 0x0005) -#define KDATA_TASK6 (KDATA_BASE_ADDR + 0x0006) -#define KDATA_TASK7 (KDATA_BASE_ADDR + 0x0007) -#define KDATA_TASK_ENDMARK (KDATA_BASE_ADDR + 0x0008) - -#define KDATA_CURRENT_TASK (KDATA_BASE_ADDR + 0x0009) -#define KDATA_TASK_SWITCH (KDATA_BASE_ADDR + 0x000A) - -#define KDATA_INSTANCE0_POS3D (KDATA_BASE_ADDR + 0x000B) -#define KDATA_INSTANCE1_POS3D (KDATA_BASE_ADDR + 0x000C) -#define KDATA_INSTANCE2_POS3D (KDATA_BASE_ADDR + 0x000D) -#define KDATA_INSTANCE3_POS3D (KDATA_BASE_ADDR + 0x000E) -#define KDATA_INSTANCE4_POS3D (KDATA_BASE_ADDR + 0x000F) -#define KDATA_INSTANCE5_POS3D (KDATA_BASE_ADDR + 0x0010) -#define KDATA_INSTANCE6_POS3D (KDATA_BASE_ADDR + 0x0011) -#define KDATA_INSTANCE7_POS3D (KDATA_BASE_ADDR + 0x0012) -#define KDATA_INSTANCE8_POS3D (KDATA_BASE_ADDR + 0x0013) -#define KDATA_INSTANCE_POS3D_ENDMARK (KDATA_BASE_ADDR + 0x0014) - -#define KDATA_INSTANCE0_SPKVIRT (KDATA_BASE_ADDR + 0x0015) -#define KDATA_INSTANCE_SPKVIRT_ENDMARK (KDATA_BASE_ADDR + 0x0016) - -#define KDATA_INSTANCE0_SPDIF (KDATA_BASE_ADDR + 0x0017) -#define KDATA_INSTANCE_SPDIF_ENDMARK (KDATA_BASE_ADDR + 0x0018) - -#define KDATA_INSTANCE0_MODEM (KDATA_BASE_ADDR + 0x0019) -#define KDATA_INSTANCE_MODEM_ENDMARK (KDATA_BASE_ADDR + 0x001A) - -#define KDATA_INSTANCE0_SRC (KDATA_BASE_ADDR + 0x001B) -#define KDATA_INSTANCE1_SRC (KDATA_BASE_ADDR + 0x001C) -#define KDATA_INSTANCE_SRC_ENDMARK (KDATA_BASE_ADDR + 0x001D) - -#define KDATA_INSTANCE0_MINISRC (KDATA_BASE_ADDR + 0x001E) -#define KDATA_INSTANCE1_MINISRC (KDATA_BASE_ADDR + 0x001F) -#define KDATA_INSTANCE2_MINISRC (KDATA_BASE_ADDR + 0x0020) -#define KDATA_INSTANCE3_MINISRC (KDATA_BASE_ADDR + 0x0021) -#define KDATA_INSTANCE_MINISRC_ENDMARK (KDATA_BASE_ADDR + 0x0022) - -#define KDATA_INSTANCE0_CPYTHRU (KDATA_BASE_ADDR + 0x0023) -#define KDATA_INSTANCE1_CPYTHRU (KDATA_BASE_ADDR + 0x0024) -#define KDATA_INSTANCE_CPYTHRU_ENDMARK (KDATA_BASE_ADDR + 0x0025) - -#define KDATA_CURRENT_DMA (KDATA_BASE_ADDR + 0x0026) -#define KDATA_DMA_SWITCH (KDATA_BASE_ADDR + 0x0027) -#define KDATA_DMA_ACTIVE (KDATA_BASE_ADDR + 0x0028) - -#define KDATA_DMA_XFER0 (KDATA_BASE_ADDR + 0x0029) -#define KDATA_DMA_XFER1 (KDATA_BASE_ADDR + 0x002A) -#define KDATA_DMA_XFER2 (KDATA_BASE_ADDR + 0x002B) -#define KDATA_DMA_XFER3 (KDATA_BASE_ADDR + 0x002C) -#define KDATA_DMA_XFER4 (KDATA_BASE_ADDR + 0x002D) -#define KDATA_DMA_XFER5 (KDATA_BASE_ADDR + 0x002E) -#define KDATA_DMA_XFER6 (KDATA_BASE_ADDR + 0x002F) -#define KDATA_DMA_XFER7 (KDATA_BASE_ADDR + 0x0030) -#define KDATA_DMA_XFER8 (KDATA_BASE_ADDR + 0x0031) -#define KDATA_DMA_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0032) - -#define KDATA_I2S_SAMPLE_COUNT (KDATA_BASE_ADDR + 0x0033) -#define KDATA_I2S_INT_METER (KDATA_BASE_ADDR + 0x0034) -#define KDATA_I2S_ACTIVE (KDATA_BASE_ADDR + 0x0035) - -#define KDATA_TIMER_COUNT_RELOAD (KDATA_BASE_ADDR + 0x0036) -#define KDATA_TIMER_COUNT_CURRENT (KDATA_BASE_ADDR + 0x0037) - -#define KDATA_HALT_SYNCH_CLIENT (KDATA_BASE_ADDR + 0x0038) -#define KDATA_HALT_SYNCH_DMA (KDATA_BASE_ADDR + 0x0039) -#define KDATA_HALT_ACKNOWLEDGE (KDATA_BASE_ADDR + 0x003A) - -#define KDATA_ADC1_XFER0 (KDATA_BASE_ADDR + 0x003B) -#define KDATA_ADC1_XFER_ENDMARK (KDATA_BASE_ADDR + 0x003C) -#define KDATA_ADC1_LEFT_VOLUME (KDATA_BASE_ADDR + 0x003D) -#define KDATA_ADC1_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x003E) -#define KDATA_ADC1_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x003F) -#define KDATA_ADC1_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0040) - -#define KDATA_ADC2_XFER0 (KDATA_BASE_ADDR + 0x0041) -#define KDATA_ADC2_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0042) -#define KDATA_ADC2_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0043) -#define KDATA_ADC2_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x0044) -#define KDATA_ADC2_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x0045) -#define KDATA_ADC2_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0046) - -#define KDATA_CD_XFER0 (KDATA_BASE_ADDR + 0x0047) -#define KDATA_CD_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0048) -#define KDATA_CD_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0049) -#define KDATA_CD_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x004A) -#define KDATA_CD_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x004B) -#define KDATA_CD_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x004C) - -#define KDATA_MIC_XFER0 (KDATA_BASE_ADDR + 0x004D) -#define KDATA_MIC_XFER_ENDMARK (KDATA_BASE_ADDR + 0x004E) -#define KDATA_MIC_VOLUME (KDATA_BASE_ADDR + 0x004F) -#define KDATA_MIC_SUR_VOL (KDATA_BASE_ADDR + 0x0050) - -#define KDATA_I2S_XFER0 (KDATA_BASE_ADDR + 0x0051) -#define KDATA_I2S_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0052) - -#define KDATA_CHI_XFER0 (KDATA_BASE_ADDR + 0x0053) -#define KDATA_CHI_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0054) - -#define KDATA_SPDIF_XFER (KDATA_BASE_ADDR + 0x0055) -#define KDATA_SPDIF_CURRENT_FRAME (KDATA_BASE_ADDR + 0x0056) -#define KDATA_SPDIF_FRAME0 (KDATA_BASE_ADDR + 0x0057) -#define KDATA_SPDIF_FRAME1 (KDATA_BASE_ADDR + 0x0058) -#define KDATA_SPDIF_FRAME2 (KDATA_BASE_ADDR + 0x0059) - -#define KDATA_SPDIF_REQUEST (KDATA_BASE_ADDR + 0x005A) -#define KDATA_SPDIF_TEMP (KDATA_BASE_ADDR + 0x005B) - -#define KDATA_SPDIFIN_XFER0 (KDATA_BASE_ADDR + 0x005C) -#define KDATA_SPDIFIN_XFER_ENDMARK (KDATA_BASE_ADDR + 0x005D) -#define KDATA_SPDIFIN_INT_METER (KDATA_BASE_ADDR + 0x005E) - -#define KDATA_DSP_RESET_COUNT (KDATA_BASE_ADDR + 0x005F) -#define KDATA_DEBUG_OUTPUT (KDATA_BASE_ADDR + 0x0060) - -#define KDATA_KERNEL_ISR_LIST (KDATA_BASE_ADDR + 0x0061) - -#define KDATA_KERNEL_ISR_CBSR1 (KDATA_BASE_ADDR + 0x0062) -#define KDATA_KERNEL_ISR_CBER1 (KDATA_BASE_ADDR + 0x0063) -#define KDATA_KERNEL_ISR_CBCR (KDATA_BASE_ADDR + 0x0064) -#define KDATA_KERNEL_ISR_AR0 (KDATA_BASE_ADDR + 0x0065) -#define KDATA_KERNEL_ISR_AR1 (KDATA_BASE_ADDR + 0x0066) -#define KDATA_KERNEL_ISR_AR2 (KDATA_BASE_ADDR + 0x0067) -#define KDATA_KERNEL_ISR_AR3 (KDATA_BASE_ADDR + 0x0068) -#define KDATA_KERNEL_ISR_AR4 (KDATA_BASE_ADDR + 0x0069) -#define KDATA_KERNEL_ISR_AR5 (KDATA_BASE_ADDR + 0x006A) -#define KDATA_KERNEL_ISR_BRCR (KDATA_BASE_ADDR + 0x006B) -#define KDATA_KERNEL_ISR_PASR (KDATA_BASE_ADDR + 0x006C) -#define KDATA_KERNEL_ISR_PAER (KDATA_BASE_ADDR + 0x006D) - -#define KDATA_CLIENT_SCRATCH0 (KDATA_BASE_ADDR + 0x006E) -#define KDATA_CLIENT_SCRATCH1 (KDATA_BASE_ADDR + 0x006F) -#define KDATA_KERNEL_SCRATCH (KDATA_BASE_ADDR + 0x0070) -#define KDATA_KERNEL_ISR_SCRATCH (KDATA_BASE_ADDR + 0x0071) - -#define KDATA_OUEUE_LEFT (KDATA_BASE_ADDR + 0x0072) -#define KDATA_QUEUE_RIGHT (KDATA_BASE_ADDR + 0x0073) - -#define KDATA_ADC1_REQUEST (KDATA_BASE_ADDR + 0x0074) -#define KDATA_ADC2_REQUEST (KDATA_BASE_ADDR + 0x0075) -#define KDATA_CD_REQUEST (KDATA_BASE_ADDR + 0x0076) -#define KDATA_MIC_REQUEST (KDATA_BASE_ADDR + 0x0077) - -#define KDATA_ADC1_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0078) -#define KDATA_ADC2_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0079) -#define KDATA_CD_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007A) -#define KDATA_MIC_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007B) -#define KDATA_MIC_SYNC_COUNTER (KDATA_BASE_ADDR + 0x007C) - -/* - * second 'segment' (?) reserved for mixer - * buffers.. - */ - -#define KDATA_MIXER_WORD0 (KDATA_BASE_ADDR2 + 0x0000) -#define KDATA_MIXER_WORD1 (KDATA_BASE_ADDR2 + 0x0001) -#define KDATA_MIXER_WORD2 (KDATA_BASE_ADDR2 + 0x0002) -#define KDATA_MIXER_WORD3 (KDATA_BASE_ADDR2 + 0x0003) -#define KDATA_MIXER_WORD4 (KDATA_BASE_ADDR2 + 0x0004) -#define KDATA_MIXER_WORD5 (KDATA_BASE_ADDR2 + 0x0005) -#define KDATA_MIXER_WORD6 (KDATA_BASE_ADDR2 + 0x0006) -#define KDATA_MIXER_WORD7 (KDATA_BASE_ADDR2 + 0x0007) -#define KDATA_MIXER_WORD8 (KDATA_BASE_ADDR2 + 0x0008) -#define KDATA_MIXER_WORD9 (KDATA_BASE_ADDR2 + 0x0009) -#define KDATA_MIXER_WORDA (KDATA_BASE_ADDR2 + 0x000A) -#define KDATA_MIXER_WORDB (KDATA_BASE_ADDR2 + 0x000B) -#define KDATA_MIXER_WORDC (KDATA_BASE_ADDR2 + 0x000C) -#define KDATA_MIXER_WORDD (KDATA_BASE_ADDR2 + 0x000D) -#define KDATA_MIXER_WORDE (KDATA_BASE_ADDR2 + 0x000E) -#define KDATA_MIXER_WORDF (KDATA_BASE_ADDR2 + 0x000F) - -#define KDATA_MIXER_XFER0 (KDATA_BASE_ADDR2 + 0x0010) -#define KDATA_MIXER_XFER1 (KDATA_BASE_ADDR2 + 0x0011) -#define KDATA_MIXER_XFER2 (KDATA_BASE_ADDR2 + 0x0012) -#define KDATA_MIXER_XFER3 (KDATA_BASE_ADDR2 + 0x0013) -#define KDATA_MIXER_XFER4 (KDATA_BASE_ADDR2 + 0x0014) -#define KDATA_MIXER_XFER5 (KDATA_BASE_ADDR2 + 0x0015) -#define KDATA_MIXER_XFER6 (KDATA_BASE_ADDR2 + 0x0016) -#define KDATA_MIXER_XFER7 (KDATA_BASE_ADDR2 + 0x0017) -#define KDATA_MIXER_XFER8 (KDATA_BASE_ADDR2 + 0x0018) -#define KDATA_MIXER_XFER9 (KDATA_BASE_ADDR2 + 0x0019) -#define KDATA_MIXER_XFER_ENDMARK (KDATA_BASE_ADDR2 + 0x001A) - -#define KDATA_MIXER_TASK_NUMBER (KDATA_BASE_ADDR2 + 0x001B) -#define KDATA_CURRENT_MIXER (KDATA_BASE_ADDR2 + 0x001C) -#define KDATA_MIXER_ACTIVE (KDATA_BASE_ADDR2 + 0x001D) -#define KDATA_MIXER_BANK_STATUS (KDATA_BASE_ADDR2 + 0x001E) -#define KDATA_DAC_LEFT_VOLUME (KDATA_BASE_ADDR2 + 0x001F) -#define KDATA_DAC_RIGHT_VOLUME (KDATA_BASE_ADDR2 + 0x0020) - -#define MAX_INSTANCE_MINISRC (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC) -#define MAX_VIRTUAL_DMA_CHANNELS (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0) -#define MAX_VIRTUAL_MIXER_CHANNELS (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0) -#define MAX_VIRTUAL_ADC1_CHANNELS (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0) - -/* - * client data area offsets - */ -#define CDATA_INSTANCE_READY 0x00 - -#define CDATA_HOST_SRC_ADDRL 0x01 -#define CDATA_HOST_SRC_ADDRH 0x02 -#define CDATA_HOST_SRC_END_PLUS_1L 0x03 -#define CDATA_HOST_SRC_END_PLUS_1H 0x04 -#define CDATA_HOST_SRC_CURRENTL 0x05 -#define CDATA_HOST_SRC_CURRENTH 0x06 - -#define CDATA_IN_BUF_CONNECT 0x07 -#define CDATA_OUT_BUF_CONNECT 0x08 - -#define CDATA_IN_BUF_BEGIN 0x09 -#define CDATA_IN_BUF_END_PLUS_1 0x0A -#define CDATA_IN_BUF_HEAD 0x0B -#define CDATA_IN_BUF_TAIL 0x0C -#define CDATA_OUT_BUF_BEGIN 0x0D -#define CDATA_OUT_BUF_END_PLUS_1 0x0E -#define CDATA_OUT_BUF_HEAD 0x0F -#define CDATA_OUT_BUF_TAIL 0x10 - -#define CDATA_DMA_CONTROL 0x11 -#define CDATA_RESERVED 0x12 - -#define CDATA_FREQUENCY 0x13 -#define CDATA_LEFT_VOLUME 0x14 -#define CDATA_RIGHT_VOLUME 0x15 -#define CDATA_LEFT_SUR_VOL 0x16 -#define CDATA_RIGHT_SUR_VOL 0x17 - -#define CDATA_HEADER_LEN 0x18 - -#define SRC3_DIRECTION_OFFSET CDATA_HEADER_LEN -#define SRC3_MODE_OFFSET (CDATA_HEADER_LEN + 1) -#define SRC3_WORD_LENGTH_OFFSET (CDATA_HEADER_LEN + 2) -#define SRC3_PARAMETER_OFFSET (CDATA_HEADER_LEN + 3) -#define SRC3_COEFF_ADDR_OFFSET (CDATA_HEADER_LEN + 8) -#define SRC3_FILTAP_ADDR_OFFSET (CDATA_HEADER_LEN + 10) -#define SRC3_TEMP_INBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 16) -#define SRC3_TEMP_OUTBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 17) - -#define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 ) -#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) -#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) -#define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 ) -#define MINISRC_BIQUAD_STAGE 2 -#define MINISRC_COEF_LOC 0X175 - -#define DMACONTROL_BLOCK_MASK 0x000F -#define DMAC_BLOCK0_SELECTOR 0x0000 -#define DMAC_BLOCK1_SELECTOR 0x0001 -#define DMAC_BLOCK2_SELECTOR 0x0002 -#define DMAC_BLOCK3_SELECTOR 0x0003 -#define DMAC_BLOCK4_SELECTOR 0x0004 -#define DMAC_BLOCK5_SELECTOR 0x0005 -#define DMAC_BLOCK6_SELECTOR 0x0006 -#define DMAC_BLOCK7_SELECTOR 0x0007 -#define DMAC_BLOCK8_SELECTOR 0x0008 -#define DMAC_BLOCK9_SELECTOR 0x0009 -#define DMAC_BLOCKA_SELECTOR 0x000A -#define DMAC_BLOCKB_SELECTOR 0x000B -#define DMAC_BLOCKC_SELECTOR 0x000C -#define DMAC_BLOCKD_SELECTOR 0x000D -#define DMAC_BLOCKE_SELECTOR 0x000E -#define DMAC_BLOCKF_SELECTOR 0x000F -#define DMACONTROL_PAGE_MASK 0x00F0 -#define DMAC_PAGE0_SELECTOR 0x0030 -#define DMAC_PAGE1_SELECTOR 0x0020 -#define DMAC_PAGE2_SELECTOR 0x0010 -#define DMAC_PAGE3_SELECTOR 0x0000 -#define DMACONTROL_AUTOREPEAT 0x1000 -#define DMACONTROL_STOPPED 0x2000 -#define DMACONTROL_DIRECTION 0x0100 - - -/* - * DSP Code images - */ - -static u16 assp_kernel_image[] = { - 0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4, - 0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, - 0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, - 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x0063, 0x7980, 0x006B, 0x7980, 0x03B4, 0x7980, 0x03B4, - 0xBF80, 0x2C7C, 0x8806, 0x8804, 0xBE40, 0xBC20, 0xAE09, 0x1000, 0xAE0A, 0x0001, 0x6938, 0xEB08, - 0x0053, 0x695A, 0xEB08, 0x00D6, 0x0009, 0x8B88, 0x6980, 0xE388, 0x0036, 0xBE30, 0xBC20, 0x6909, - 0xB801, 0x9009, 0xBE41, 0xBE41, 0x6928, 0xEB88, 0x0078, 0xBE41, 0xBE40, 0x7980, 0x0038, 0xBE41, - 0xBE41, 0x903A, 0x6938, 0xE308, 0x0056, 0x903A, 0xBE41, 0xBE40, 0xEF00, 0x903A, 0x6939, 0xE308, - 0x005E, 0x903A, 0xEF00, 0x690B, 0x660C, 0xEF8C, 0x690A, 0x660C, 0x620B, 0x6609, 0xEF00, 0x6910, - 0x660F, 0xEF04, 0xE388, 0x0075, 0x690E, 0x660F, 0x6210, 0x660D, 0xEF00, 0x690E, 0x660D, 0xEF00, - 0xAE70, 0x0001, 0xBC20, 0xAE27, 0x0001, 0x6939, 0xEB08, 0x005D, 0x6926, 0xB801, 0x9026, 0x0026, - 0x8B88, 0x6980, 0xE388, 0x00CB, 0x9028, 0x0D28, 0x4211, 0xE100, 0x007A, 0x4711, 0xE100, 0x00A0, - 0x7A80, 0x0063, 0xB811, 0x660A, 0x6209, 0xE304, 0x007A, 0x0C0B, 0x4005, 0x100A, 0xBA01, 0x9012, - 0x0C12, 0x4002, 0x7980, 0x00AF, 0x7A80, 0x006B, 0xBE02, 0x620E, 0x660D, 0xBA10, 0xE344, 0x007A, - 0x0C10, 0x4005, 0x100E, 0xBA01, 0x9012, 0x0C12, 0x4002, 0x1003, 0xBA02, 0x9012, 0x0C12, 0x4000, - 0x1003, 0xE388, 0x00BA, 0x1004, 0x7980, 0x00BC, 0x1004, 0xBA01, 0x9012, 0x0C12, 0x4001, 0x0C05, - 0x4003, 0x0C06, 0x4004, 0x1011, 0xBFB0, 0x01FF, 0x9012, 0x0C12, 0x4006, 0xBC20, 0xEF00, 0xAE26, - 0x1028, 0x6970, 0xBFD0, 0x0001, 0x9070, 0xE388, 0x007A, 0xAE28, 0x0000, 0xEF00, 0xAE70, 0x0300, - 0x0C70, 0xB00C, 0xAE5A, 0x0000, 0xEF00, 0x7A80, 0x038A, 0x697F, 0xB801, 0x907F, 0x0056, 0x8B88, - 0x0CA0, 0xB008, 0xAF71, 0xB000, 0x4E71, 0xE200, 0x00F3, 0xAE56, 0x1057, 0x0056, 0x0CA0, 0xB008, - 0x8056, 0x7980, 0x03A1, 0x0810, 0xBFA0, 0x1059, 0xE304, 0x03A1, 0x8056, 0x7980, 0x03A1, 0x7A80, - 0x038A, 0xBF01, 0xBE43, 0xBE59, 0x907C, 0x6937, 0xE388, 0x010D, 0xBA01, 0xE308, 0x010C, 0xAE71, - 0x0004, 0x0C71, 0x5000, 0x6936, 0x9037, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 0xBF0A, - 0x0560, 0xF500, 0xBF0A, 0x0520, 0xB900, 0xBB17, 0x90A0, 0x6917, 0xE388, 0x0148, 0x0D17, 0xE100, - 0x0127, 0xBF0C, 0x0578, 0xBF0D, 0x057C, 0x7980, 0x012B, 0xBF0C, 0x0538, 0xBF0D, 0x053C, 0x6900, - 0xE308, 0x0135, 0x8B8C, 0xBE59, 0xBB07, 0x90A0, 0xBC20, 0x7980, 0x0157, 0x030C, 0x8B8B, 0xB903, - 0x8809, 0xBEC6, 0x013E, 0x69AC, 0x90AB, 0x69AD, 0x90AB, 0x0813, 0x660A, 0xE344, 0x0144, 0x0309, - 0x830C, 0xBC20, 0x7980, 0x0157, 0x6955, 0xE388, 0x0157, 0x7C38, 0xBF0B, 0x0578, 0xF500, 0xBF0B, - 0x0538, 0xB907, 0x8809, 0xBEC6, 0x0156, 0x10AB, 0x90AA, 0x6974, 0xE388, 0x0163, 0xAE72, 0x0540, - 0xF500, 0xAE72, 0x0500, 0xAE61, 0x103B, 0x7A80, 0x02F6, 0x6978, 0xE388, 0x0182, 0x8B8C, 0xBF0C, - 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA20, 0x8812, 0x733D, 0x7A80, 0x0380, 0x733E, 0x7A80, 0x0380, - 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA2C, 0x8812, 0x733F, 0x7A80, 0x0380, 0x7340, - 0x7A80, 0x0380, 0x6975, 0xE388, 0x018E, 0xAE72, 0x0548, 0xF500, 0xAE72, 0x0508, 0xAE61, 0x1041, - 0x7A80, 0x02F6, 0x6979, 0xE388, 0x01AD, 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA18, - 0x8812, 0x7343, 0x7A80, 0x0380, 0x7344, 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, - 0x0814, 0xBA24, 0x8812, 0x7345, 0x7A80, 0x0380, 0x7346, 0x7A80, 0x0380, 0x6976, 0xE388, 0x01B9, - 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x1047, 0x7A80, 0x02F6, 0x697A, 0xE388, 0x01D8, - 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA08, 0x8812, 0x7349, 0x7A80, 0x0380, 0x734A, - 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA14, 0x8812, 0x734B, 0x7A80, - 0x0380, 0x734C, 0x7A80, 0x0380, 0xBC21, 0xAE1C, 0x1090, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, - 0x0812, 0xB804, 0x8813, 0x8B8D, 0xBF0D, 0x056C, 0xE500, 0x7C40, 0x0815, 0xB804, 0x8811, 0x7A80, - 0x034A, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, 0x731F, 0xB903, 0x8809, 0xBEC6, 0x01F9, 0x548A, - 0xBE03, 0x98A0, 0x7320, 0xB903, 0x8809, 0xBEC6, 0x0201, 0x548A, 0xBE03, 0x98A0, 0x1F20, 0x2F1F, - 0x9826, 0xBC20, 0x6935, 0xE388, 0x03A1, 0x6933, 0xB801, 0x9033, 0xBFA0, 0x02EE, 0xE308, 0x03A1, - 0x9033, 0xBF00, 0x6951, 0xE388, 0x021F, 0x7334, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 0xBE59, 0x9034, - 0x697E, 0x0D51, 0x9013, 0xBC20, 0x695C, 0xE388, 0x03A1, 0x735E, 0xBE80, 0x5760, 0xBE03, 0x9F7E, - 0xBE59, 0x905E, 0x697E, 0x0D5C, 0x9013, 0x7980, 0x03A1, 0x7A80, 0x038A, 0xBF01, 0xBE43, 0x6977, - 0xE388, 0x024E, 0xAE61, 0x104D, 0x0061, 0x8B88, 0x6980, 0xE388, 0x024E, 0x9071, 0x0D71, 0x000B, - 0xAFA0, 0x8010, 0xAFA0, 0x8010, 0x0810, 0x660A, 0xE308, 0x0249, 0x0009, 0x0810, 0x660C, 0xE388, - 0x024E, 0x800B, 0xBC20, 0x697B, 0xE388, 0x03A1, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, - 0xE100, 0x0266, 0x697C, 0xBF90, 0x0560, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0564, 0x9073, 0x0473, - 0x7980, 0x0270, 0x697C, 0xBF90, 0x0520, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0524, 0x9073, 0x0473, - 0x697C, 0xB801, 0x907C, 0xBF0A, 0x10FD, 0x8B8A, 0xAF80, 0x8010, 0x734F, 0x548A, 0xBE03, 0x9880, - 0xBC21, 0x7326, 0x548B, 0xBE03, 0x618B, 0x988C, 0xBE03, 0x6180, 0x9880, 0x7980, 0x03A1, 0x7A80, - 0x038A, 0x0D28, 0x4711, 0xE100, 0x02BE, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 0x02B6, - 0xBFA0, 0x0800, 0xE388, 0x02B2, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02A3, 0x6909, - 0x900B, 0x7980, 0x02A5, 0xAF0B, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 0x02ED, - 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x6909, 0x900B, 0x7980, 0x02B8, 0xAF0B, 0x4005, - 0xAF05, 0x4003, 0xAF06, 0x4004, 0x7980, 0x02ED, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, - 0x02E7, 0xBFA0, 0x0800, 0xE388, 0x02E3, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02D4, - 0x690D, 0x9010, 0x7980, 0x02D6, 0xAF10, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, - 0x02ED, 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x690D, 0x9010, 0x7980, 0x02E9, 0xAF10, - 0x4005, 0xAF05, 0x4003, 0xAF06, 0x4004, 0xBC20, 0x6970, 0x9071, 0x7A80, 0x0078, 0x6971, 0x9070, - 0x7980, 0x03A1, 0xBC20, 0x0361, 0x8B8B, 0x6980, 0xEF88, 0x0272, 0x0372, 0x7804, 0x9071, 0x0D71, - 0x8B8A, 0x000B, 0xB903, 0x8809, 0xBEC6, 0x0309, 0x69A8, 0x90AB, 0x69A8, 0x90AA, 0x0810, 0x660A, - 0xE344, 0x030F, 0x0009, 0x0810, 0x660C, 0xE388, 0x0314, 0x800B, 0xBC20, 0x6961, 0xB801, 0x9061, - 0x7980, 0x02F7, 0x7A80, 0x038A, 0x5D35, 0x0001, 0x6934, 0xB801, 0x9034, 0xBF0A, 0x109E, 0x8B8A, - 0xAF80, 0x8014, 0x4880, 0xAE72, 0x0550, 0xF500, 0xAE72, 0x0510, 0xAE61, 0x1051, 0x7A80, 0x02F6, - 0x7980, 0x03A1, 0x7A80, 0x038A, 0x5D35, 0x0002, 0x695E, 0xB801, 0x905E, 0xBF0A, 0x109E, 0x8B8A, - 0xAF80, 0x8014, 0x4780, 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x105C, 0x7A80, 0x02F6, - 0x7980, 0x03A1, 0x001C, 0x8B88, 0x6980, 0xEF88, 0x901D, 0x0D1D, 0x100F, 0x6610, 0xE38C, 0x0358, - 0x690E, 0x6610, 0x620F, 0x660D, 0xBA0F, 0xE301, 0x037A, 0x0410, 0x8B8A, 0xB903, 0x8809, 0xBEC6, - 0x036C, 0x6A8C, 0x61AA, 0x98AB, 0x6A8C, 0x61AB, 0x98AD, 0x6A8C, 0x61AD, 0x98A9, 0x6A8C, 0x61A9, - 0x98AA, 0x7C04, 0x8B8B, 0x7C04, 0x8B8D, 0x7C04, 0x8B89, 0x7C04, 0x0814, 0x660E, 0xE308, 0x0379, - 0x040D, 0x8410, 0xBC21, 0x691C, 0xB801, 0x901C, 0x7980, 0x034A, 0xB903, 0x8809, 0x8B8A, 0xBEC6, - 0x0388, 0x54AC, 0xBE03, 0x618C, 0x98AA, 0xEF00, 0xBC20, 0xBE46, 0x0809, 0x906B, 0x080A, 0x906C, - 0x080B, 0x906D, 0x081A, 0x9062, 0x081B, 0x9063, 0x081E, 0x9064, 0xBE59, 0x881E, 0x8065, 0x8166, - 0x8267, 0x8368, 0x8469, 0x856A, 0xEF00, 0xBC20, 0x696B, 0x8809, 0x696C, 0x880A, 0x696D, 0x880B, - 0x6962, 0x881A, 0x6963, 0x881B, 0x6964, 0x881E, 0x0065, 0x0166, 0x0267, 0x0368, 0x0469, 0x056A, - 0xBE3A, -}; - -/* - * Mini sample rate converter code image - * that is to be loaded at 0x400 on the DSP. - */ -static u16 assp_minisrc_image[] = { - - 0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412, - 0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41, - 0x7A80, 0x002A, 0xBE40, 0x3029, 0xEFCC, 0xBE41, 0x7A80, 0x0028, 0xBE40, 0x3028, 0xEFCC, 0x6907, - 0xE308, 0x042A, 0x6909, 0x902C, 0x7980, 0x042C, 0x690D, 0x902C, 0x1009, 0x881A, 0x100A, 0xBA01, - 0x881B, 0x100D, 0x881C, 0x100E, 0xBA01, 0x881D, 0xBF80, 0x00ED, 0x881E, 0x050C, 0x0124, 0xB904, - 0x9027, 0x6918, 0xE308, 0x04B3, 0x902D, 0x6913, 0xBFA0, 0x7598, 0xF704, 0xAE2D, 0x00FF, 0x8B8D, - 0x6919, 0xE308, 0x0463, 0x691A, 0xE308, 0x0456, 0xB907, 0x8809, 0xBEC6, 0x0453, 0x10A9, 0x90AD, - 0x7980, 0x047C, 0xB903, 0x8809, 0xBEC6, 0x0460, 0x1889, 0x6C22, 0x90AD, 0x10A9, 0x6E23, 0x6C22, - 0x90AD, 0x7980, 0x047C, 0x101A, 0xE308, 0x046F, 0xB903, 0x8809, 0xBEC6, 0x046C, 0x10A9, 0x90A0, - 0x90AD, 0x7980, 0x047C, 0xB901, 0x8809, 0xBEC6, 0x047B, 0x1889, 0x6C22, 0x90A0, 0x90AD, 0x10A9, - 0x6E23, 0x6C22, 0x90A0, 0x90AD, 0x692D, 0xE308, 0x049C, 0x0124, 0xB703, 0xB902, 0x8818, 0x8B89, - 0x022C, 0x108A, 0x7C04, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99A0, - 0x108A, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99AF, 0x7B99, 0x0484, - 0x0124, 0x060F, 0x101B, 0x2013, 0x901B, 0xBFA0, 0x7FFF, 0xE344, 0x04AC, 0x901B, 0x8B89, 0x7A80, - 0x051A, 0x6927, 0xBA01, 0x9027, 0x7A80, 0x0523, 0x6927, 0xE308, 0x049E, 0x7980, 0x050F, 0x0624, - 0x1026, 0x2013, 0x9026, 0xBFA0, 0x7FFF, 0xE304, 0x04C0, 0x8B8D, 0x7A80, 0x051A, 0x7980, 0x04B4, - 0x9026, 0x1013, 0x3026, 0x901B, 0x8B8D, 0x7A80, 0x051A, 0x7A80, 0x0523, 0x1027, 0xBA01, 0x9027, - 0xE308, 0x04B4, 0x0124, 0x060F, 0x8B89, 0x691A, 0xE308, 0x04EA, 0x6919, 0xE388, 0x04E0, 0xB903, - 0x8809, 0xBEC6, 0x04DD, 0x1FA0, 0x2FAE, 0x98A9, 0x7980, 0x050F, 0xB901, 0x8818, 0xB907, 0x8809, - 0xBEC6, 0x04E7, 0x10EE, 0x90A9, 0x7980, 0x050F, 0x6919, 0xE308, 0x04FE, 0xB903, 0x8809, 0xBE46, - 0xBEC6, 0x04FA, 0x17A0, 0xBE1E, 0x1FAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0xBE47, - 0x7980, 0x050F, 0xB901, 0x8809, 0xBEC6, 0x050E, 0x16A0, 0x26A0, 0xBFB7, 0xFF00, 0xBE1E, 0x1EA0, - 0x2EAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0x850C, 0x860F, 0x6907, 0xE388, 0x0516, - 0x0D07, 0x8510, 0xBE59, 0x881E, 0xBE4A, 0xEF00, 0x101E, 0x901C, 0x101F, 0x901D, 0x10A0, 0x901E, - 0x10A0, 0x901F, 0xEF00, 0x101E, 0x301C, 0x9020, 0x731B, 0x5420, 0xBE03, 0x9825, 0x1025, 0x201C, - 0x9025, 0x7325, 0x5414, 0xBE03, 0x8B8E, 0x9880, 0x692F, 0xE388, 0x0539, 0xBE59, 0xBB07, 0x6180, - 0x9880, 0x8BA0, 0x101F, 0x301D, 0x9021, 0x731B, 0x5421, 0xBE03, 0x982E, 0x102E, 0x201D, 0x902E, - 0x732E, 0x5415, 0xBE03, 0x9880, 0x692F, 0xE388, 0x054F, 0xBE59, 0xBB07, 0x6180, 0x9880, 0x8BA0, - 0x6918, 0xEF08, 0x7325, 0x5416, 0xBE03, 0x98A0, 0x732E, 0x5417, 0xBE03, 0x98A0, 0xEF00, 0x8BA0, - 0xBEC6, 0x056B, 0xBE59, 0xBB04, 0xAA90, 0xBE04, 0xBE1E, 0x99E0, 0x8BE0, 0x69A0, 0x90D0, 0x69A0, - 0x90D0, 0x081F, 0xB805, 0x881F, 0x8B90, 0x69A0, 0x90D0, 0x69A0, 0x9090, 0x8BD0, 0x8BD8, 0xBE1F, - 0xEF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -}; - diff --git a/sound/oss/maui.c b/sound/oss/maui.c deleted file mode 100644 index 317f22589a05..000000000000 --- a/sound/oss/maui.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * sound/oss/maui.c - * - * The low level driver for Turtle Beach Maui and Tropez. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes: - * Alan Cox General clean up, use kernel IRQ - * system - * Christoph Hellwig Adapted to module_init/module_exit - * Bartlomiej Zolnierkiewicz - * Added __init to download_code() - * - * Status: - * Andrew J. Kroll Tested 06/01/1999 with: - * * OSWF.MOT File Version: 1.15 - * * OSWF.MOT File Dated: 09/12/94 - * * Older versions will cause problems. - */ - -#include -#include -#include -#include - -#define USE_SEQ_MACROS -#define USE_SIMPLE_MACROS - -#include "sound_config.h" -#include "sound_firmware.h" - -#include "mpu401.h" - -static int maui_base = 0x330; - -static volatile int irq_ok; -static int *maui_osp; - -#define HOST_DATA_PORT (maui_base + 2) -#define HOST_STAT_PORT (maui_base + 3) -#define HOST_CTRL_PORT (maui_base + 3) - -#define STAT_TX_INTR 0x40 -#define STAT_TX_AVAIL 0x20 -#define STAT_TX_IENA 0x10 -#define STAT_RX_INTR 0x04 -#define STAT_RX_AVAIL 0x02 -#define STAT_RX_IENA 0x01 - -static int (*orig_load_patch)(int dev, int format, const char __user *addr, - int offs, int count, int pmgr_flag) = NULL; - -#include "maui_boot.h" - -static int maui_wait(int mask) -{ - int i; - - /* - * Perform a short initial wait without sleeping - */ - - for (i = 0; i < 100; i++) - if (inb(HOST_STAT_PORT) & mask) - return 1; - - /* - * Wait up to 15 seconds with sleeping - */ - - for (i = 0; i < 150; i++) { - if (inb(HOST_STAT_PORT) & mask) - return 1; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ / 10); - if (signal_pending(current)) - return 0; - } - return 0; -} - -static int maui_read(void) -{ - if (maui_wait(STAT_RX_AVAIL)) - return inb(HOST_DATA_PORT); - return -1; -} - -static int maui_write(unsigned char data) -{ - if (maui_wait(STAT_TX_AVAIL)) { - outb((data), HOST_DATA_PORT); - return 1; - } - printk(KERN_WARNING "Maui: Write timeout\n"); - return 0; -} - -static irqreturn_t mauiintr(int irq, void *dev_id, struct pt_regs *dummy) -{ - irq_ok = 1; - return IRQ_HANDLED; -} - -static int __init download_code(void) -{ - int i, lines = 0; - int eol_seen = 0, done = 0; - int skip = 1; - - printk(KERN_INFO "Code download (%d bytes): ", maui_osLen); - - for (i = 0; i < maui_osLen; i++) { - if (maui_os[i] != '\r') { - if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) { - skip = 0; - - if (maui_os[i] == '\n') - eol_seen = skip = 1; - else if (maui_os[i] == 'S') { - if (maui_os[i + 1] == '8') - done = 1; - if (!maui_write(0xF1)) - goto failure; - if (!maui_write('S')) - goto failure; - } else { - if (!maui_write(maui_os[i])) - goto failure; - } - - if (eol_seen) { - int c = 0; - int n; - - eol_seen = 0; - - for (n = 0; n < 2; n++) { - if (maui_wait(STAT_RX_AVAIL)) { - c = inb(HOST_DATA_PORT); - break; - } - } - if (c != 0x80) { - printk("Download not acknowledged\n"); - return 0; - } - else if (!(lines++ % 10)) - printk("."); - - if (done) { - printk("\n"); - printk(KERN_INFO "Download complete\n"); - return 1; - } - } - } - } - } - -failure: - printk("\n"); - printk(KERN_ERR "Download failed!!!\n"); - return 0; -} - -static int __init maui_init(int irq) -{ - unsigned char bits; - - switch (irq) { - case 9: - bits = 0x00; - break; - case 5: - bits = 0x08; - break; - case 12: - bits = 0x10; - break; - case 15: - bits = 0x18; - break; - - default: - printk(KERN_ERR "Maui: Invalid IRQ %d\n", irq); - return 0; - } - outb((0x00), HOST_CTRL_PORT); /* Reset */ - outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */ - outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */ - outb((0x80), HOST_CTRL_PORT); /* Leave reset */ - outb((0x80), HOST_CTRL_PORT); /* Leave reset */ - outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */ - -#ifdef CONFIG_SMP - { - int i; - for (i = 0; i < 1000000 && !irq_ok; i++) - ; - if (!irq_ok) - return 0; - } -#endif - outb((0x80), HOST_CTRL_PORT); /* Leave reset */ - - printk(KERN_INFO "Turtle Beach Maui initialization\n"); - - if (!download_code()) - return 0; - - outb((0xE0), HOST_CTRL_PORT); /* Normal operation */ - - /* Select mpu401 mode */ - - maui_write(0xf0); - maui_write(1); - if (maui_read() != 0x80) { - maui_write(0xf0); - maui_write(1); - if (maui_read() != 0x80) - printk(KERN_ERR "Maui didn't acknowledge set HW mode command\n"); - } - printk(KERN_INFO "Maui initialized OK\n"); - return 1; -} - -static int maui_short_wait(int mask) { - int i; - - for (i = 0; i < 1000; i++) { - if (inb(HOST_STAT_PORT) & mask) { - return 1; - } - } - return 0; -} - -static int maui_load_patch(int dev, int format, const char __user *addr, - int offs, int count, int pmgr_flag) -{ - - struct sysex_info header; - unsigned long left, src_offs; - int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header; - int i; - - if (format == SYSEX_PATCH) /* Handled by midi_synth.c */ - return orig_load_patch(dev, format, addr, offs, count, pmgr_flag); - - if (format != MAUI_PATCH) - { - printk(KERN_WARNING "Maui: Unknown patch format\n"); - } - if (count < hdr_size) { -/* printk("Maui error: Patch header too short\n");*/ - return -EINVAL; - } - count -= hdr_size; - - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs)) - return -EFAULT; - - if (count < header.len) { - printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len); - header.len = count; - } - left = header.len; - src_offs = 0; - - for (i = 0; i < left; i++) { - unsigned char data; - - if(get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i]))) - return -EFAULT; - if (i == 0 && !(data & 0x80)) - return -EINVAL; - - if (maui_write(data) == -1) - return -EIO; - } - - if ((i = maui_read()) != 0x80) { - if (i != -1) - printk("Maui: Error status %02x\n", i); - return -EIO; - } - return 0; -} - -static int __init probe_maui(struct address_info *hw_config) -{ - struct resource *ports; - int this_dev; - int i; - int tmp1, tmp2, ret; - - ports = request_region(hw_config->io_base, 2, "mpu401"); - if (!ports) - return 0; - - if (!request_region(hw_config->io_base + 2, 6, "Maui")) - goto out; - - maui_base = hw_config->io_base; - maui_osp = hw_config->osp; - - if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0) - goto out2; - - /* - * Initialize the processor if necessary - */ - - if (maui_osLen > 0) { - if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) || - !maui_write(0x9F) || /* Report firmware version */ - !maui_short_wait(STAT_RX_AVAIL) || - maui_read() == -1 || maui_read() == -1) - if (!maui_init(hw_config->irq)) - goto out3; - } - if (!maui_write(0xCF)) /* Report hardware version */ { - printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); - goto out3; - } - if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) { - printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); - goto out3; - } - if (tmp1 == 0xff || tmp2 == 0xff) - goto out3; - printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2); - - if (!maui_write(0x9F)) /* Report firmware version */ - goto out3; - if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) - goto out3; - - printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2); - - if (!maui_write(0x85)) /* Report free DRAM */ - goto out3; - tmp1 = 0; - for (i = 0; i < 4; i++) { - tmp1 |= maui_read() << (7 * i); - } - printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024); - - for (i = 0; i < 1000; i++) - if (probe_mpu401(hw_config, ports)) - break; - - ret = probe_mpu401(hw_config, ports); - if (!ret) - goto out3; - - conf_printf("Maui", hw_config); - - hw_config->irq *= -1; - hw_config->name = "Maui"; - attach_mpu401(hw_config, THIS_MODULE); - - if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ { - struct synth_operations *synth; - - this_dev = hw_config->slots[1]; - - /* - * Intercept patch loading calls so that they can be handled - * by the Maui driver. - */ - - synth = midi_devs[this_dev]->converter; - if (synth != NULL) { - synth->id = "MAUI"; - orig_load_patch = synth->load_patch; - synth->load_patch = &maui_load_patch; - } else - printk(KERN_ERR "Maui: Can't install patch loader\n"); - } - return 1; - -out3: - free_irq(hw_config->irq, NULL); -out2: - release_region(hw_config->io_base + 2, 6); -out: - release_region(hw_config->io_base, 2); - return 0; -} - -static void __exit unload_maui(struct address_info *hw_config) -{ - int irq = hw_config->irq; - release_region(hw_config->io_base + 2, 6); - unload_mpu401(hw_config); - - if (irq < 0) - irq = -irq; - if (irq > 0) - free_irq(irq, NULL); -} - -static int fw_load; - -static struct address_info cfg; - -static int __initdata io = -1; -static int __initdata irq = -1; - -module_param(io, int, 0); -module_param(irq, int, 0); - -/* - * Install a Maui card. Needs mpu401 loaded already. - */ - -static int __init init_maui(void) -{ - printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n"); - - cfg.io_base = io; - cfg.irq = irq; - - if (cfg.io_base == -1 || cfg.irq == -1) { - printk(KERN_INFO "maui: irq and io must be set.\n"); - return -EINVAL; - } - - if (maui_os == NULL) { - fw_load = 1; - maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os); - } - if (probe_maui(&cfg) == 0) - return -ENODEV; - - return 0; -} - -static void __exit cleanup_maui(void) -{ - if (fw_load && maui_os) - vfree(maui_os); - unload_maui(&cfg); -} - -module_init(init_maui); -module_exit(cleanup_maui); - -#ifndef MODULE -static int __init setup_maui(char *str) -{ - /* io, irq */ - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - - return 1; -} - -__setup("maui=", setup_maui); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index 321f4c4b5a7b..162d07cc489f 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -432,16 +432,7 @@ static void mpu401_input_loop(struct mpu_config *devc) devc->m_busy = 0; } -int intchk_mpu401(void *dev_id) -{ - struct mpu_config *devc; - int dev = (int) dev_id; - - devc = &dev_conf[dev]; - return input_avail(devc); -} - -irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs *dummy) +static irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs *dummy) { struct mpu_config *devc; int dev = (int) dev_id; @@ -1761,8 +1752,6 @@ static int mpu_timer_init(int midi_dev) EXPORT_SYMBOL(probe_mpu401); EXPORT_SYMBOL(attach_mpu401); EXPORT_SYMBOL(unload_mpu401); -EXPORT_SYMBOL(intchk_mpu401); -EXPORT_SYMBOL(mpuintr); static struct address_info cfg; diff --git a/sound/oss/mpu401.h b/sound/oss/mpu401.h index bdc5bde641e6..84c0e9522ef7 100644 --- a/sound/oss/mpu401.h +++ b/sound/oss/mpu401.h @@ -10,5 +10,3 @@ int probe_mpu401(struct address_info *hw_config, struct resource *ports); int attach_mpu401(struct address_info * hw_config, struct module *owner); void unload_mpu401(struct address_info *hw_info); -int intchk_mpu401(void *dev_id); -irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs * dummy); diff --git a/sound/oss/opl3sa.c b/sound/oss/opl3sa.c deleted file mode 100644 index 2535ed0b5fbf..000000000000 --- a/sound/oss/opl3sa.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * sound/oss/opl3sa.c - * - * Low level driver for Yamaha YMF701B aka OPL3-SA chip - * - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes: - * Alan Cox Modularisation - * Christoph Hellwig Adapted to module_init/module_exit - * Arnaldo C. de Melo got rid of attach_uart401 - * - * FIXME: - * Check for install of mpu etc is wrong, should check result of the mss stuff - */ - -#include -#include -#include - -#undef SB_OK - -#include "sound_config.h" - -#include "ad1848.h" -#include "mpu401.h" - -#ifdef SB_OK -#include "sb.h" -static int sb_initialized; -#endif - -static DEFINE_SPINLOCK(lock); - -static unsigned char opl3sa_read(int addr) -{ - unsigned long flags; - unsigned char tmp; - - spin_lock_irqsave(&lock,flags); - outb((0x1d), 0xf86); /* password */ - outb(((unsigned char) addr), 0xf86); /* address */ - tmp = inb(0xf87); /* data */ - spin_unlock_irqrestore(&lock,flags); - - return tmp; -} - -static void opl3sa_write(int addr, int data) -{ - unsigned long flags; - - spin_lock_irqsave(&lock,flags); - outb((0x1d), 0xf86); /* password */ - outb(((unsigned char) addr), 0xf86); /* address */ - outb(((unsigned char) data), 0xf87); /* data */ - spin_unlock_irqrestore(&lock,flags); -} - -static int __init opl3sa_detect(void) -{ - int tmp; - - if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04) - { - DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01))); - /* return 0; */ - } - - /* - * Check that the password feature has any effect - */ - - if (inb(0xf87) == tmp) - { - DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87))); - return 0; - } - tmp = (opl3sa_read(0x04) & 0xe0) >> 5; - - if (tmp != 0 && tmp != 1) - { - DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp)); - return 0; - } - DDB(printk("OPL3-SA mode %x detected\n", tmp)); - - opl3sa_write(0x01, 0x00); /* Disable MSS */ - opl3sa_write(0x02, 0x00); /* Disable SB */ - opl3sa_write(0x03, 0x00); /* Disable MPU */ - - return 1; -} - -/* - * Probe and attach routines for the Windows Sound System mode of - * OPL3-SA - */ - -static int __init probe_opl3sa_wss(struct address_info *hw_config, struct resource *ports) -{ - unsigned char tmp = 0x24; /* WSS enable */ - - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (OPL3-SA for example) - * return 0x00. - */ - - if (!opl3sa_detect()) - { - printk(KERN_ERR "OSS: OPL3-SA chip not found\n"); - return 0; - } - - switch (hw_config->io_base) - { - case 0x530: - tmp |= 0x00; - break; - case 0xe80: - tmp |= 0x08; - break; - case 0xf40: - tmp |= 0x10; - break; - case 0x604: - tmp |= 0x18; - break; - default: - printk(KERN_ERR "OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base); - return 0; - } - - opl3sa_write(0x01, tmp); /* WSS setup register */ - - return probe_ms_sound(hw_config, ports); -} - -static void __init attach_opl3sa_wss(struct address_info *hw_config, struct resource *ports) -{ - int nm = num_mixers; - - /* FIXME */ - attach_ms_sound(hw_config, ports, THIS_MODULE); - if (num_mixers > nm) /* A mixer was installed */ - { - AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); - AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH); - AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); - } -} - - -static int __init probe_opl3sa_mpu(struct address_info *hw_config) -{ - unsigned char conf; - static signed char irq_bits[] = { - -1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4 - }; - - if (hw_config->irq > 10) - { - printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - if (irq_bits[hw_config->irq] == -1) - { - printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - switch (hw_config->io_base) - { - case 0x330: - conf = 0x00; - break; - case 0x332: - conf = 0x20; - break; - case 0x334: - conf = 0x40; - break; - case 0x300: - conf = 0x60; - break; - default: - return 0; /* Invalid port */ - } - - conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */ - conf |= irq_bits[hw_config->irq] << 2; - - opl3sa_write(0x03, conf); - - hw_config->name = "OPL3-SA (MPU401)"; - - return probe_uart401(hw_config, THIS_MODULE); -} - -static void __exit unload_opl3sa_wss(struct address_info *hw_config) -{ - int dma2 = hw_config->dma2; - - if (dma2 == -1) - dma2 = hw_config->dma; - - release_region(0xf86, 2); - release_region(hw_config->io_base, 4); - - ad1848_unload(hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - dma2, - 0); - sound_unload_audiodev(hw_config->slots[0]); -} - -static inline void __exit unload_opl3sa_mpu(struct address_info *hw_config) -{ - unload_uart401(hw_config); -} - -#ifdef SB_OK -static inline void __exit unload_opl3sa_sb(struct address_info *hw_config) -{ - sb_dsp_unload(hw_config); -} -#endif - -static int found_mpu; - -static struct address_info cfg; -static struct address_info cfg_mpu; - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma2 = -1; -static int __initdata mpu_io = -1; -static int __initdata mpu_irq = -1; - -module_param(io, int, 0); -module_param(irq, int, 0); -module_param(dma, int, 0); -module_param(dma2, int, 0); -module_param(mpu_io, int, 0); -module_param(mpu_irq, int, 0); - -static int __init init_opl3sa(void) -{ - struct resource *ports; - if (io == -1 || irq == -1 || dma == -1) { - printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n"); - return -EINVAL; - } - - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma2; - - cfg_mpu.io_base = mpu_io; - cfg_mpu.irq = mpu_irq; - - ports = request_region(io + 4, 4, "ad1848"); - if (!ports) - return -EBUSY; - - if (!request_region(0xf86, 2, "OPL3-SA"))/* Control port is busy */ { - release_region(io + 4, 4); - return 0; - } - - if (!request_region(io, 4, "WSS config")) { - release_region(0x86, 2); - release_region(io + 4, 4); - return 0; - } - - if (probe_opl3sa_wss(&cfg, ports) == 0) { - release_region(0xf86, 2); - release_region(io, 4); - release_region(io + 4, 4); - return -ENODEV; - } - - found_mpu=probe_opl3sa_mpu(&cfg_mpu); - - attach_opl3sa_wss(&cfg, ports); - return 0; -} - -static void __exit cleanup_opl3sa(void) -{ - if(found_mpu) - unload_opl3sa_mpu(&cfg_mpu); - unload_opl3sa_wss(&cfg); -} - -module_init(init_opl3sa); -module_exit(cleanup_opl3sa); - -#ifndef MODULE -static int __init setup_opl3sa(char *str) -{ - /* io, irq, dma, dma2, mpu_io, mpu_irq */ - int ints[7]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma2 = ints[4]; - mpu_io = ints[5]; - mpu_irq = ints[6]; - - return 1; -} - -__setup("opl3sa=", setup_opl3sa); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c deleted file mode 100644 index f17d25b6f836..000000000000 --- a/sound/oss/rme96xx.c +++ /dev/null @@ -1,1857 +0,0 @@ -/* (C) 2000 Guenter Geiger - with copy/pastes from the driver of Winfried Ritsch - based on es1370.c - - - - * 10 Jan 2001: 0.1 initial version - * 19 Jan 2001: 0.2 fixed bug in select() - * 27 Apr 2001: 0.3 more than one card usable - * 11 May 2001: 0.4 fixed for SMP, included into kernel source tree - * 17 May 2001: 0.5 draining code didn't work on new cards - * 18 May 2001: 0.6 remove synchronize_irq() call - * 17 Jul 2001: 0.7 updated xrmectrl to make it work for newer cards - * 2 feb 2002: 0.8 fixed pci device handling, see below for patches from Heiko (Thanks!) - Marcus Meissner - - Modifications - Heiko Purnhagen - HP20020108 fixed handling of "large" read() - HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c - HP20020118 made mixer ioctl and handling of devices>1 more safe - HP20020201 fixed handling of "large" read() properly - added REV 1.5 S/P-DIF receiver support - SNDCTL_DSP_SPEED now returns the actual speed - * 10 Aug 2002: added synchronize_irq() again - -TODO: - - test more than one card --- done - - check for pci IOREGION (see es1370) in rme96xx_probe ?? - - error detection - - mmap interface - - mixer mmap interface - - mixer ioctl - - get rid of noise upon first open (why ??) - - allow multiple open (at least for read) - - allow multiple open for non overlapping regions - - recheck the multiple devices part (offsets of different devices, etc) - - do decent draining in _release --- done - - SMP support - - what about using fragstotal>2 for small fragsize? (HP20020118) - - add support for AFMT_S32_LE -*/ - -#ifndef RMEVERSION -#define RMEVERSION "0.8" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "rme96xx.h" - -#define NR_DEVICE 2 - -static int devices = 1; -module_param(devices, int, 0); -MODULE_PARM_DESC(devices, "number of dsp devices allocated by the driver"); - - -MODULE_AUTHOR("Guenter Geiger, geiger@debian.org"); -MODULE_DESCRIPTION("RME9652/36 \"Hammerfall\" Driver"); -MODULE_LICENSE("GPL"); - - -#ifdef DEBUG -#define DBG(x) printk("RME_DEBUG:");x -#define COMM(x) printk("RME_COMM: " x "\n"); -#else -#define DBG(x) while (0) {} -#define COMM(x) -#endif - -/*-------------------------------------------------------------------------- - Preporcessor Macros and Definitions - --------------------------------------------------------------------------*/ - -#define RME96xx_MAGIC 0x6473 - -/* Registers-Space in offsets from base address with 16MByte size */ - -#define RME96xx_IO_EXTENT 16l*1024l*1024l -#define RME96xx_CHANNELS_PER_CARD 26 - -/* Write - Register */ - -/* 0,4,8,12,16,20,24,28 ... hardware init (erasing fifo-pointer intern) */ -#define RME96xx_num_of_init_regs 8 - -#define RME96xx_init_buffer (0/4) -#define RME96xx_play_buffer (32/4) /* pointer to 26x64kBit RAM from mainboard */ -#define RME96xx_rec_buffer (36/4) /* pointer to 26x64kBit RAM from mainboard */ -#define RME96xx_control_register (64/4) /* exact meaning see below */ -#define RME96xx_irq_clear (96/4) /* irq acknowledge */ -#define RME96xx_time_code (100/4) /* if used with alesis adat */ -#define RME96xx_thru_base (128/4) /* 132...228 Thru for 26 channels */ -#define RME96xx_thru_channels RME96xx_CHANNELS_PER_CARD - -/* Read Register */ - -#define RME96xx_status_register 0 /* meaning see below */ - - - -/* Status Register: */ -/* ------------------------------------------------------------------------ */ -#define RME96xx_IRQ 0x0000001 /* IRQ is High if not reset by RMExx_irq_clear */ -#define RME96xx_lock_2 0x0000002 /* ADAT 3-PLL: 1=locked, 0=unlocked */ -#define RME96xx_lock_1 0x0000004 /* ADAT 2-PLL: 1=locked, 0=unlocked */ -#define RME96xx_lock_0 0x0000008 /* ADAT 1-PLL: 1=locked, 0=unlocked */ - -#define RME96xx_fs48 0x0000010 /* sample rate 0 ...44.1/88.2, 1 ... 48/96 Khz */ -#define RME96xx_wsel_rd 0x0000020 /* if Word-Clock is used and valid then 1 */ -#define RME96xx_buf_pos1 0x0000040 /* Bit 6..15 : Position of buffer-pointer in 64Bytes-blocks */ -#define RME96xx_buf_pos2 0x0000080 /* resolution +/- 1 64Byte/block (since 64Bytes bursts) */ - -#define RME96xx_buf_pos3 0x0000100 /* 10 bits = 1024 values */ -#define RME96xx_buf_pos4 0x0000200 /* if we mask off the first 6 bits, we can take the status */ -#define RME96xx_buf_pos5 0x0000400 /* register as sample counter in the hardware buffer */ -#define RME96xx_buf_pos6 0x0000800 - -#define RME96xx_buf_pos7 0x0001000 -#define RME96xx_buf_pos8 0x0002000 -#define RME96xx_buf_pos9 0x0004000 -#define RME96xx_buf_pos10 0x0008000 - -#define RME96xx_sync_2 0x0010000 /* if ADAT-IN3 synced to system clock */ -#define RME96xx_sync_1 0x0020000 /* if ADAT-IN2 synced to system clock */ -#define RME96xx_sync_0 0x0040000 /* if ADAT-IN1 synced to system clock */ -#define RME96xx_DS_rd 0x0080000 /* 1=Double Speed, 0=Normal Speed */ - -#define RME96xx_tc_busy 0x0100000 /* 1=time-code copy in progress (960ms) */ -#define RME96xx_tc_out 0x0200000 /* time-code out bit */ -#define RME96xx_F_0 0x0400000 /* 000=64kHz, 100=88.2kHz, 011=96kHz */ -#define RME96xx_F_1 0x0800000 /* 111=32kHz, 110=44.1kHz, 101=48kHz, */ - -#define RME96xx_F_2 0x1000000 /* 001=Rev 1.5+ external Crystal Chip */ -#define RME96xx_ERF 0x2000000 /* Error-Flag of SDPIF Receiver (1=No Lock)*/ -#define RME96xx_buffer_id 0x4000000 /* toggles by each interrupt on rec/play */ -#define RME96xx_tc_valid 0x8000000 /* 1 = a signal is detected on time-code input */ -#define RME96xx_SPDIF_READ 0x10000000 /* byte available from Rev 1.5+ SPDIF interface */ - -/* Status Register Fields */ - -#define RME96xx_lock (RME96xx_lock_0|RME96xx_lock_1|RME96xx_lock_2) -#define RME96xx_sync (RME96xx_sync_0|RME96xx_sync_1|RME96xx_sync_2) -#define RME96xx_F (RME96xx_F_0|RME96xx_F_1|RME96xx_F_2) -#define rme96xx_decode_spdif_rate(x) ((x)>>22) - -/* Bit 6..15 : h/w buffer pointer */ -#define RME96xx_buf_pos 0x000FFC0 -/* Bits 31,30,29 are bits 5,4,3 of h/w pointer position on later - Rev G EEPROMS and Rev 1.5 cards or later. -*/ -#define RME96xx_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME96xx_buf_pos)) - - -/* Control-Register: */ -/*--------------------------------------------------------------------------------*/ - -#define RME96xx_start_bit 0x0001 /* start record/play */ -#define RME96xx_latency0 0x0002 /* Buffer size / latency */ -#define RME96xx_latency1 0x0004 /* buffersize = 512Bytes * 2^n */ -#define RME96xx_latency2 0x0008 /* 0=64samples ... 7=8192samples */ - -#define RME96xx_Master 0x0010 /* Clock Mode 1=Master, 0=Slave/Auto */ -#define RME96xx_IE 0x0020 /* Interupt Enable */ -#define RME96xx_freq 0x0040 /* samplerate 0=44.1/88.2, 1=48/96 kHz*/ -#define RME96xx_freq1 0x0080 /* samplerate 0=32 kHz, 1=other rates ??? (from ALSA, but may be wrong) */ -#define RME96xx_DS 0x0100 /* double speed 0=44.1/48, 1=88.2/96 Khz */ -#define RME96xx_PRO 0x0200 /* SPDIF-OUT 0=consumer, 1=professional */ -#define RME96xx_EMP 0x0400 /* SPDIF-OUT emphasis 0=off, 1=on */ -#define RME96xx_Dolby 0x0800 /* SPDIF-OUT non-audio bit 1=set, 0=unset */ - -#define RME96xx_opt_out 0x1000 /* use 1st optical OUT as SPDIF: 1=yes, 0=no */ -#define RME96xx_wsel 0x2000 /* use Wordclock as sync (overwrites master) */ -#define RME96xx_inp_0 0x4000 /* SPDIF-IN 00=optical (ADAT1), */ -#define RME96xx_inp_1 0x8000 /* 01=coaxial (Cinch), 10=internal CDROM */ - -#define RME96xx_SyncRef0 0x10000 /* preferred sync-source in autosync */ -#define RME96xx_SyncRef1 0x20000 /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */ - -#define RME96xx_SPDIF_RESET (1<<18) /* Rev 1.5+: h/w SPDIF receiver */ -#define RME96xx_SPDIF_SELECT (1<<19) -#define RME96xx_SPDIF_CLOCK (1<<20) -#define RME96xx_SPDIF_WRITE (1<<21) -#define RME96xx_ADAT1_INTERNAL (1<<22) /* Rev 1.5+: if set, internal CD connector carries ADAT */ - - -#define RME96xx_ctrl_init (RME96xx_latency0 |\ - RME96xx_Master |\ - RME96xx_inp_1) - - - -/* Control register fields and shortcuts */ - -#define RME96xx_latency (RME96xx_latency0|RME96xx_latency1|RME96xx_latency2) -#define RME96xx_inp (RME96xx_inp_0|RME96xx_inp_1) -#define RME96xx_SyncRef (RME96xx_SyncRef0|RME96xx_SyncRef1) -#define RME96xx_mixer_allowed (RME96xx_Master|RME96xx_PRO|RME96xx_EMP|RME96xx_Dolby|RME96xx_opt_out|RME96xx_wsel|RME96xx_inp|RME96xx_SyncRef|RME96xx_ADAT1_INTERNAL) - -/* latency = 512Bytes * 2^n, where n is made from Bit3 ... Bit1 (??? HP20020201) */ - -#define RME96xx_SET_LATENCY(x) (((x)&0x7)<<1) -#define RME96xx_GET_LATENCY(x) (((x)>>1)&0x7) -#define RME96xx_SET_inp(x) (((x)&0x3)<<14) -#define RME96xx_GET_inp(x) (((x)>>14)&0x3) -#define RME96xx_SET_SyncRef(x) (((x)&0x3)<<17) -#define RME96xx_GET_SyncRef(x) (((x)>>17)&0x3) - - -/* buffer sizes */ -#define RME96xx_BYTES_PER_SAMPLE 4 /* sizeof(u32) */ -#define RME_16K 16*1024 - -#define RME96xx_DMA_MAX_SAMPLES (RME_16K) -#define RME96xx_DMA_MAX_SIZE (RME_16K * RME96xx_BYTES_PER_SAMPLE) -#define RME96xx_DMA_MAX_SIZE_ALL (RME96xx_DMA_MAX_SIZE * RME96xx_CHANNELS_PER_CARD) - -#define RME96xx_NUM_OF_FRAGMENTS 2 -#define RME96xx_FRAGMENT_MAX_SIZE (RME96xx_DMA_MAX_SIZE/2) -#define RME96xx_FRAGMENT_MAX_SAMPLES (RME96xx_DMA_MAX_SAMPLES/2) -#define RME96xx_MAX_LATENCY 7 /* 16k samples */ - - -#define RME96xx_MAX_DEVS 4 /* we provide some OSS stereodevs */ -#define RME96xx_MASK_DEVS 0x3 /* RME96xx_MAX_DEVS-1 */ - -#define RME_MESS "rme96xx:" -/*------------------------------------------------------------------------ - Types, struct and function declarations - ------------------------------------------------------------------------*/ - - -/* --------------------------------------------------------------------- */ - -static const char invalid_magic[] = KERN_CRIT RME_MESS" invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != RME96xx_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -/* --------------------------------------------------------------------- */ - - -static struct file_operations rme96xx_audio_fops; -static struct file_operations rme96xx_mixer_fops; -static int numcards; - -typedef int32_t raw_sample_t; - -typedef struct _rme96xx_info { - - /* hardware settings */ - int magic; - struct pci_dev * pcidev; /* pci_dev structure */ - unsigned long __iomem *iobase; - unsigned int irq; - - /* list of rme96xx devices */ - struct list_head devs; - - spinlock_t lock; - - u32 *recbuf; /* memory for rec buffer */ - u32 *playbuf; /* memory for play buffer */ - - u32 control_register; - - u32 thru_bits; /* thru 1=on, 0=off channel 1=Bit1... channel 26= Bit26 */ - - int hw_rev; /* h/w rev * 10 (i.e. 1.5 has hw_rev = 15) */ - char *card_name; /* hammerfall or hammerfall light names */ - - int open_count; /* unused ??? HP20020201 */ - - int rate; - int latency; - unsigned int fragsize; - int started; - - int hwptr; /* can be negativ because of pci burst offset */ - unsigned int hwbufid; /* set by interrupt, buffer which is written/read now */ - - struct dmabuf { - - unsigned int format; - int formatshift; - int inchannels; /* number of channels for device */ - int outchannels; /* number of channels for device */ - int mono; /* if true, we play mono on 2 channels */ - int inoffset; /* which channel is considered the first one */ - int outoffset; - - /* state */ - int opened; /* open() made */ - int started; /* first write/read */ - int mmapped; /* mmap */ - int open_mode; - - struct _rme96xx_info *s; - - /* pointer to read/write position in buffer */ - unsigned readptr; - unsigned writeptr; - - unsigned error; /* over/underruns cleared on sync again */ - - /* waiting and locking */ - wait_queue_head_t wait; - struct mutex open_mutex; - wait_queue_head_t open_wait; - - } dma[RME96xx_MAX_DEVS]; - - int dspnum[RME96xx_MAX_DEVS]; /* register with sound subsystem */ - int mixer; /* register with sound subsystem */ -} rme96xx_info; - - -/* fiddling with the card (first level hardware control) */ - -static inline void rme96xx_set_ctrl(rme96xx_info* s,int mask) -{ - - s->control_register|=mask; - writel(s->control_register,s->iobase + RME96xx_control_register); - -} - -static inline void rme96xx_unset_ctrl(rme96xx_info* s,int mask) -{ - - s->control_register&=(~mask); - writel(s->control_register,s->iobase + RME96xx_control_register); - -} - -static inline int rme96xx_get_sample_rate_status(rme96xx_info* s) -{ - int val; - u32 status; - status = readl(s->iobase + RME96xx_status_register); - val = (status & RME96xx_fs48) ? 48000 : 44100; - if (status & RME96xx_DS_rd) - val *= 2; - return val; -} - -static inline int rme96xx_get_sample_rate_ctrl(rme96xx_info* s) -{ - int val; - val = (s->control_register & RME96xx_freq) ? 48000 : 44100; - if (s->control_register & RME96xx_DS) - val *= 2; - return val; -} - - -/* code from ALSA card-rme9652.c for rev 1.5 SPDIF receiver HP 20020201 */ - -static void rme96xx_spdif_set_bit (rme96xx_info* s, int mask, int onoff) -{ - if (onoff) - s->control_register |= mask; - else - s->control_register &= ~mask; - - writel(s->control_register,s->iobase + RME96xx_control_register); -} - -static void rme96xx_spdif_write_byte (rme96xx_info* s, const int val) -{ - long mask; - long i; - - for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) { - if (val & mask) - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 1); - else - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 0); - - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1); - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0); - } -} - -static int rme96xx_spdif_read_byte (rme96xx_info* s) -{ - long mask; - long val; - long i; - - val = 0; - - for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) { - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1); - if (readl(s->iobase + RME96xx_status_register) & RME96xx_SPDIF_READ) - val |= mask; - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0); - } - - return val; -} - -static void rme96xx_write_spdif_codec (rme96xx_info* s, const int address, const int data) -{ - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1); - rme96xx_spdif_write_byte (s, 0x20); - rme96xx_spdif_write_byte (s, address); - rme96xx_spdif_write_byte (s, data); - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0); -} - - -static int rme96xx_spdif_read_codec (rme96xx_info* s, const int address) -{ - int ret; - - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1); - rme96xx_spdif_write_byte (s, 0x20); - rme96xx_spdif_write_byte (s, address); - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0); - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1); - - rme96xx_spdif_write_byte (s, 0x21); - ret = rme96xx_spdif_read_byte (s); - rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0); - - return ret; -} - -static void rme96xx_initialize_spdif_receiver (rme96xx_info* s) -{ - /* XXX what unsets this ? */ - /* no idea ??? HP 20020201 */ - - s->control_register |= RME96xx_SPDIF_RESET; - - rme96xx_write_spdif_codec (s, 4, 0x40); - rme96xx_write_spdif_codec (s, 17, 0x13); - rme96xx_write_spdif_codec (s, 6, 0x02); -} - -static inline int rme96xx_spdif_sample_rate (rme96xx_info *s, int *spdifrate) -{ - unsigned int rate_bits; - - *spdifrate = 0x1; - if (readl(s->iobase + RME96xx_status_register) & RME96xx_ERF) { - return -1; /* error condition */ - } - - if (s->hw_rev == 15) { - - int x, y, ret; - - x = rme96xx_spdif_read_codec (s, 30); - - if (x != 0) - y = 48000 * 64 / x; - else - y = 0; - - if (y > 30400 && y < 33600) {ret = 32000; *spdifrate = 0x7;} - else if (y > 41900 && y < 46000) {ret = 44100; *spdifrate = 0x6;} - else if (y > 46000 && y < 50400) {ret = 48000; *spdifrate = 0x5;} - else if (y > 60800 && y < 67200) {ret = 64000; *spdifrate = 0x0;} - else if (y > 83700 && y < 92000) {ret = 88200; *spdifrate = 0x4;} - else if (y > 92000 && y < 100000) {ret = 96000; *spdifrate = 0x3;} - else {ret = 0; *spdifrate = 0x1;} - return ret; - } - - rate_bits = readl(s->iobase + RME96xx_status_register) & RME96xx_F; - - switch (*spdifrate = rme96xx_decode_spdif_rate(rate_bits)) { - case 0x7: - return 32000; - break; - - case 0x6: - return 44100; - break; - - case 0x5: - return 48000; - break; - - case 0x4: - return 88200; - break; - - case 0x3: - return 96000; - break; - - case 0x0: - return 64000; - break; - - default: - /* was an ALSA warning ... - snd_printk("%s: unknown S/PDIF input rate (bits = 0x%x)\n", - s->card_name, rate_bits); - */ - return 0; - break; - } -} - -/* end of code from ALSA card-rme9652.c */ - - - -/* the hwbuf in the status register seems to have some jitter, to get rid of - it, we first only let the numbers grow, to be on the secure side we - subtract a certain amount RME96xx_BURSTBYTES from the resulting number */ - -/* the function returns the hardware pointer in bytes */ -#define RME96xx_BURSTBYTES -64 /* bytes by which hwptr could be off */ - -static inline int rme96xx_gethwptr(rme96xx_info* s,int exact) -{ - unsigned long flags; - if (exact) { - unsigned int hwp; -/* the hwptr seems to be rather unreliable :(, so we don't use it */ - spin_lock_irqsave(&s->lock,flags); - - hwp = readl(s->iobase + RME96xx_status_register) & 0xffc0; - s->hwptr = (hwp < s->hwptr) ? s->hwptr : hwp; -// s->hwptr = hwp; - - spin_unlock_irqrestore(&s->lock,flags); - return (s->hwptr+RME96xx_BURSTBYTES) & ((s->fragsize<<1)-1); - } - return (s->hwbufid ? s->fragsize : 0); -} - -static inline void rme96xx_setlatency(rme96xx_info* s,int l) -{ - s->latency = l; - s->fragsize = 1<<(8+l); - rme96xx_unset_ctrl(s,RME96xx_latency); - rme96xx_set_ctrl(s,RME96xx_SET_LATENCY(l)); -} - - -static void rme96xx_clearbufs(struct dmabuf* dma) -{ - int i,j; - unsigned long flags; - - /* clear dmabufs */ - for(i=0;ioutchannels + dma->mono;j++) - memset(&dma->s->playbuf[(dma->outoffset + j)*RME96xx_DMA_MAX_SAMPLES], - 0, RME96xx_DMA_MAX_SIZE); - } - spin_lock_irqsave(&dma->s->lock,flags); - dma->writeptr = 0; - dma->readptr = 0; - spin_unlock_irqrestore(&dma->s->lock,flags); -} - -static int rme96xx_startcard(rme96xx_info *s,int stop) -{ - int i; - unsigned long flags; - - COMM ("startcard"); - if(s->control_register & RME96xx_IE){ - /* disable interrupt first */ - - rme96xx_unset_ctrl( s,RME96xx_start_bit ); - udelay(10); - rme96xx_unset_ctrl( s,RME96xx_IE); - spin_lock_irqsave(&s->lock,flags); /* timing is critical */ - s->started = 0; - spin_unlock_irqrestore(&s->lock,flags); - if (stop) { - COMM("Sound card stopped"); - return 1; - } - } - COMM ("interrupt disabled"); - /* first initialize all pointers on card */ - for(i=0;iiobase + i); - udelay(10); /* ?? */ - } - COMM ("regs cleaned"); - - spin_lock_irqsave(&s->lock,flags); /* timing is critical */ - udelay(10); - s->started = 1; - s->hwptr = 0; - spin_unlock_irqrestore(&s->lock,flags); - - rme96xx_set_ctrl( s, RME96xx_IE | RME96xx_start_bit); - - - COMM("Sound card started"); - - return 1; -} - - -static inline int rme96xx_getospace(struct dmabuf * dma, unsigned int hwp) -{ - int cnt; - int swptr; - unsigned long flags; - - spin_lock_irqsave(&dma->s->lock,flags); - swptr = dma->writeptr; - cnt = (hwp - swptr); - - if (cnt < 0) { - cnt = ((dma->s->fragsize<<1) - swptr); - } - spin_unlock_irqrestore(&dma->s->lock,flags); - return cnt; -} - -static inline int rme96xx_getispace(struct dmabuf * dma, unsigned int hwp) -{ - int cnt; - int swptr; - unsigned long flags; - - spin_lock_irqsave(&dma->s->lock,flags); - swptr = dma->readptr; - cnt = (hwp - swptr); - - if (cnt < 0) { - cnt = ((dma->s->fragsize<<1) - swptr); - } - spin_unlock_irqrestore(&dma->s->lock,flags); - return cnt; -} - - -static inline int rme96xx_copyfromuser(struct dmabuf* dma,const char __user * buffer,int count,int hop) -{ - int swptr = dma->writeptr; - switch (dma->format) { - case AFMT_S32_BLOCKED: - { - char __user * buf = (char __user *)buffer; - int cnt = count/dma->outchannels; - int i; - for (i=0;i < dma->outchannels;i++) { - char* hwbuf =(char*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES]; - hwbuf+=swptr; - - if (copy_from_user(hwbuf,buf, cnt)) - return -1; - buf+=hop; - } - swptr+=cnt; - break; - } - case AFMT_S16_LE: - { - int i,j; - int cnt = count/dma->outchannels; - for (i=0;i < dma->outchannels + dma->mono;i++) { - short __user * sbuf = (short __user *)buffer + i*(!dma->mono); - short* hwbuf =(short*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES]; - hwbuf+=(swptr>>1); - for (j=0;j<(cnt>>1);j++) { - hwbuf++; /* skip the low 16 bits */ - __get_user(*hwbuf++,sbuf++); - sbuf+=(dma->outchannels-1); - } - } - swptr += (cnt<<1); - break; - } - default: - printk(RME_MESS" unsupported format\n"); - return -1; - } /* switch */ - - swptr&=((dma->s->fragsize<<1) -1); - dma->writeptr = swptr; - - return 0; -} - -/* The count argument is the number of bytes */ -static inline int rme96xx_copytouser(struct dmabuf* dma,const char __user* buffer,int count,int hop) -{ - int swptr = dma->readptr; - switch (dma->format) { - case AFMT_S32_BLOCKED: - { - char __user * buf = (char __user *)buffer; - int cnt = count/dma->inchannels; - int i; - - for (i=0;i < dma->inchannels;i++) { - char* hwbuf =(char*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES]; - hwbuf+=swptr; - - if (copy_to_user(buf,hwbuf,cnt)) - return -1; - buf+=hop; - } - swptr+=cnt; - break; - } - case AFMT_S16_LE: - { - int i,j; - int cnt = count/dma->inchannels; - for (i=0;i < dma->inchannels;i++) { - short __user * sbuf = (short __user *)buffer + i; - short* hwbuf =(short*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES]; - hwbuf+=(swptr>>1); - for (j=0;j<(cnt>>1);j++) { - hwbuf++; - __put_user(*hwbuf++,sbuf++); - sbuf+=(dma->inchannels-1); - } - } - swptr += (cnt<<1); - break; - } - default: - printk(RME_MESS" unsupported format\n"); - return -1; - } /* switch */ - - swptr&=((dma->s->fragsize<<1) -1); - dma->readptr = swptr; - return 0; -} - - -static irqreturn_t rme96xx_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - int i; - rme96xx_info *s = (rme96xx_info *)dev_id; - struct dmabuf *db; - u32 status; - unsigned long flags; - - status = readl(s->iobase + RME96xx_status_register); - if (!(status & RME96xx_IRQ)) { - return IRQ_NONE; - } - - spin_lock_irqsave(&s->lock,flags); - writel(0,s->iobase + RME96xx_irq_clear); - - s->hwbufid = (status & RME96xx_buffer_id)>>26; - if ((status & 0xffc0) <= 256) s->hwptr = 0; - for(i=0;idma[i]); - if(db->started > 0) - wake_up(&(db->wait)); - } - spin_unlock_irqrestore(&s->lock,flags); - return IRQ_HANDLED; -} - - - -/*---------------------------------------------------------------------------- - PCI detection and module initialization stuff - ----------------------------------------------------------------------------*/ - -static void* busmaster_malloc(int size) { - int pg; /* 2 s exponent of memory size */ - char *buf; - - DBG(printk("kernel malloc pages ..\n")); - - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - - buf = (char *) __get_free_pages(GFP_KERNEL | GFP_DMA, pg); - - if (buf) { - struct page* page, *last_page; - - page = virt_to_page(buf); - last_page = page + (1 << pg); - DBG(printk("setting reserved bit\n")); - while (page < last_page) { - SetPageReserved(page); - page++; - } - return buf; - } - DBG(printk("allocated %ld",(long)buf)); - return NULL; -} - -static void busmaster_free(void* ptr,int size) { - int pg; - struct page* page, *last_page; - - if (ptr == NULL) - return; - - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - - page = virt_to_page(ptr); - last_page = page + (1 << pg); - while (page < last_page) { - ClearPageReserved(page); - page++; - } - DBG(printk("freeing pages\n")); - free_pages((unsigned long) ptr, pg); - DBG(printk("done\n")); -} - -/* initialize those parts of the info structure which are not pci detectable resources */ - -static int rme96xx_dmabuf_init(rme96xx_info * s,struct dmabuf* dma,int ioffset,int ooffset) { - - mutex_init(&dma->open_mutex); - init_waitqueue_head(&dma->open_wait); - init_waitqueue_head(&dma->wait); - dma->s = s; - dma->error = 0; - - dma->format = AFMT_S32_BLOCKED; - dma->formatshift = 0; - dma->inchannels = dma->outchannels = 1; - dma->inoffset = ioffset; - dma->outoffset = ooffset; - - dma->opened=0; - dma->started=0; - dma->mmapped=0; - dma->open_mode=0; - dma->mono=0; - - rme96xx_clearbufs(dma); - return 0; -} - - -static int rme96xx_init(rme96xx_info* s) -{ - int i; - int status; - unsigned short rev; - - DBG(printk("%s\n", __FUNCTION__)); - numcards++; - - s->magic = RME96xx_MAGIC; - - spin_lock_init(&s->lock); - - COMM ("setup busmaster memory") - s->recbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL); - s->playbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL); - - if (!s->recbuf || !s->playbuf) { - printk(KERN_ERR RME_MESS" Unable to allocate busmaster memory\n"); - return -ENODEV; - } - - COMM ("setting rec and playbuffers") - - writel((u32) virt_to_bus(s->recbuf),s->iobase + RME96xx_rec_buffer); - writel((u32) virt_to_bus(s->playbuf),s->iobase + RME96xx_play_buffer); - - COMM ("initializing control register") - rme96xx_unset_ctrl(s,0xffffffff); - rme96xx_set_ctrl(s,RME96xx_ctrl_init); - - - COMM ("setup devices") - for (i=0;i < devices;i++) { - struct dmabuf * dma = &s->dma[i]; - rme96xx_dmabuf_init(s,dma,2*i,2*i); - } - - /* code from ALSA card-rme9652.c HP 20020201 */ - /* Determine the h/w rev level of the card. This seems like - a particularly kludgy way to encode it, but its what RME - chose to do, so we follow them ... - */ - - status = readl(s->iobase + RME96xx_status_register); - if (rme96xx_decode_spdif_rate(status&RME96xx_F) == 1) { - s->hw_rev = 15; - } else { - s->hw_rev = 11; - } - - /* Differentiate between the standard Hammerfall, and the - "Light", which does not have the expansion board. This - method comes from information received from Mathhias - Clausen at RME. Display the EEPROM and h/w revID where - relevant. - */ - - pci_read_config_word(s->pcidev, PCI_CLASS_REVISION, &rev); - switch (rev & 0xff) { - case 8: /* original eprom */ - if (s->hw_rev == 15) { - s->card_name = "RME Digi9636 (Rev 1.5)"; - } else { - s->card_name = "RME Digi9636"; - } - break; - case 9: /* W36_G EPROM */ - s->card_name = "RME Digi9636 (Rev G)"; - break; - case 4: /* W52_G EPROM */ - s->card_name = "RME Digi9652 (Rev G)"; - break; - default: - case 3: /* original eprom */ - if (s->hw_rev == 15) { - s->card_name = "RME Digi9652 (Rev 1.5)"; - } else { - s->card_name = "RME Digi9652"; - } - break; - } - - printk(KERN_INFO RME_MESS" detected %s (hw_rev %d)\n",s->card_name,s->hw_rev); - - if (s->hw_rev == 15) - rme96xx_initialize_spdif_receiver (s); - - s->started = 0; - rme96xx_setlatency(s,7); - - printk(KERN_INFO RME_MESS" card %d initialized\n",numcards); - return 0; -} - - -/* open uses this to figure out which device was opened .. this seems to be - unnecessary complex */ - -static LIST_HEAD(devs); - -static int __devinit rme96xx_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) -{ - int i; - rme96xx_info *s; - - DBG(printk("%s\n", __FUNCTION__)); - - if (pcidev->irq == 0) - return -1; - if (!pci_dma_supported(pcidev, 0xffffffff)) { - printk(KERN_WARNING RME_MESS" architecture does not support 32bit PCI busmaster DMA\n"); - return -1; - } - if (!(s = kmalloc(sizeof(rme96xx_info), GFP_KERNEL))) { - printk(KERN_WARNING RME_MESS" out of memory\n"); - return -1; - } - memset(s, 0, sizeof(rme96xx_info)); - - s->pcidev = pcidev; - s->iobase = ioremap(pci_resource_start(pcidev, 0),RME96xx_IO_EXTENT); - s->irq = pcidev->irq; - - DBG(printk("remapped iobase: %lx irq %d\n",(long)s->iobase,s->irq)); - - if (pci_enable_device(pcidev)) - goto err_irq; - if (request_irq(s->irq, rme96xx_interrupt, IRQF_SHARED, "rme96xx", s)) { - printk(KERN_ERR RME_MESS" irq %u in use\n", s->irq); - goto err_irq; - } - - /* initialize the card */ - - i = 0; - if (rme96xx_init(s) < 0) { - printk(KERN_ERR RME_MESS" initialization failed\n"); - goto err_devices; - } - for (i=0;idspnum[i] = register_sound_dsp(&rme96xx_audio_fops, -1)) < 0) - goto err_devices; - } - - if ((s->mixer = register_sound_mixer(&rme96xx_mixer_fops, -1)) < 0) - goto err_devices; - - pci_set_drvdata(pcidev, s); - pcidev->dma_mask = 0xffffffff; /* ????? */ - /* put it into driver list */ - list_add_tail(&s->devs, &devs); - - DBG(printk("initialization successful\n")); - return 0; - - /* error handler */ - err_devices: - while (i--) - unregister_sound_dsp(s->dspnum[i]); - free_irq(s->irq,s); - err_irq: - kfree(s); - return -1; -} - - -static void __devexit rme96xx_remove(struct pci_dev *dev) -{ - int i; - rme96xx_info *s = pci_get_drvdata(dev); - - if (!s) { - printk(KERN_ERR"device structure not valid\n"); - return ; - } - - if (s->started) rme96xx_startcard(s,0); - - i = devices; - while (i) { - i--; - unregister_sound_dsp(s->dspnum[i]); - } - - unregister_sound_mixer(s->mixer); - synchronize_irq(s->irq); - free_irq(s->irq,s); - busmaster_free(s->recbuf,RME96xx_DMA_MAX_SIZE_ALL); - busmaster_free(s->playbuf,RME96xx_DMA_MAX_SIZE_ALL); - kfree(s); - pci_set_drvdata(dev, NULL); -} - - -#ifndef PCI_VENDOR_ID_RME -#define PCI_VENDOR_ID_RME 0x10ee -#endif -#ifndef PCI_DEVICE_ID_RME9652 -#define PCI_DEVICE_ID_RME9652 0x3fc4 -#endif -#ifndef PCI_ANY_ID -#define PCI_ANY_ID 0 -#endif - -static struct pci_device_id id_table[] = { - { - .vendor = PCI_VENDOR_ID_RME, - .device = PCI_DEVICE_ID_RME9652, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, id_table); - -static struct pci_driver rme96xx_driver = { - .name = "rme96xx", - .id_table = id_table, - .probe = rme96xx_probe, - .remove = __devexit_p(rme96xx_remove), -}; - -static int __init init_rme96xx(void) -{ - printk(KERN_INFO RME_MESS" version "RMEVERSION" time " __TIME__ " " __DATE__ "\n"); - devices = ((devices-1) & RME96xx_MASK_DEVS) + 1; - printk(KERN_INFO RME_MESS" reserving %d dsp device(s)\n",devices); - numcards = 0; - return pci_register_driver(&rme96xx_driver); -} - -static void __exit cleanup_rme96xx(void) -{ - printk(KERN_INFO RME_MESS" unloading\n"); - pci_unregister_driver(&rme96xx_driver); -} - -module_init(init_rme96xx); -module_exit(cleanup_rme96xx); - - - - - -/*-------------------------------------------------------------------------- - Implementation of file operations ----------------------------------------------------------------------------*/ - -#define RME96xx_FMT (AFMT_S16_LE|AFMT_U8|AFMT_S32_BLOCKED) -/* AFTM_U8 is not (yet?) supported ... HP20020201 */ - -static int rme96xx_ioctl(struct inode *in, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct dmabuf * dma = (struct dmabuf *)file->private_data; - rme96xx_info *s = dma->s; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val = 0; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_STATE(s); - - DBG(printk("ioctl %ud\n",cmd)); - - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: -#if 0 - if (file->f_mode & FMODE_WRITE) - return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/); -#endif - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: -// rme96xx_clearbufs(dma); - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { -/* generally it's not a problem if we change the speed - if (dma->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE)) - return -EINVAL; -*/ - spin_lock_irqsave(&s->lock, flags); - - switch (val) { - case 44100: - case 88200: - rme96xx_unset_ctrl(s,RME96xx_freq); - break; - case 48000: - case 96000: - rme96xx_set_ctrl(s,RME96xx_freq); - break; - /* just report current rate as default - e.g. use 0 to "select" current digital input rate - default: - rme96xx_unset_ctrl(s,RME96xx_freq); - val = 44100; - */ - } - if (val > 50000) - rme96xx_set_ctrl(s,RME96xx_DS); - else - rme96xx_unset_ctrl(s,RME96xx_DS); - /* set val to actual value HP 20020201 */ - /* NOTE: if not "Sync Master", reported rate might be not yet "updated" ... but I don't want to insert a long udelay() here */ - if ((s->control_register & RME96xx_Master) && !(s->control_register & RME96xx_wsel)) - val = rme96xx_get_sample_rate_ctrl(s); - else - val = rme96xx_get_sample_rate_status(s); - s->rate = val; - spin_unlock_irqrestore(&s->lock, flags); - } - DBG(printk("speed set to %d\n",val)); - return put_user(val, p); - - case SNDCTL_DSP_STEREO: /* this plays a mono file on two channels */ - if (get_user(val, p)) - return -EFAULT; - - if (!val) { - DBG(printk("setting to mono\n")); - dma->mono=1; - dma->inchannels = 1; - dma->outchannels = 1; - } - else { - DBG(printk("setting to stereo\n")); - dma->mono = 0; - dma->inchannels = 2; - dma->outchannels = 2; - } - return 0; - case SNDCTL_DSP_CHANNELS: - /* remember to check for resonable offset/channel pairs here */ - if (get_user(val, p)) - return -EFAULT; - - if (file->f_mode & FMODE_WRITE) { - if (val > 0 && (dma->outoffset + val) <= RME96xx_CHANNELS_PER_CARD) - dma->outchannels = val; - else - dma->outchannels = val = 2; - DBG(printk("setting to outchannels %d\n",val)); - } - if (file->f_mode & FMODE_READ) { - if (val > 0 && (dma->inoffset + val) <= RME96xx_CHANNELS_PER_CARD) - dma->inchannels = val; - else - dma->inchannels = val = 2; - DBG(printk("setting to inchannels %d\n",val)); - } - - dma->mono=0; - - return put_user(val, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(RME96xx_FMT, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - DBG(printk("setting to format %x\n",val)); - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (val & RME96xx_FMT) - dma->format = val; - switch (dma->format) { - case AFMT_S16_LE: - dma->formatshift=1; - break; - case AFMT_S32_BLOCKED: - dma->formatshift=0; - break; - } - } - return put_user(dma->format, p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; -#if 0 - if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN) - val |= PCM_ENABLE_OUTPUT; -#endif - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; -#if 0 - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; - start_adc(s); - } else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; - start_dac2(s); - } else - stop_dac2(s); - } -#endif - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - - val = rme96xx_gethwptr(dma->s,0); - - - count = rme96xx_getospace(dma,val); - if (!s->started) count = s->fragsize*2; - abinfo.fragsize =(s->fragsize*dma->outchannels)>>dma->formatshift; - abinfo.bytes = (count*dma->outchannels)>>dma->formatshift; - abinfo.fragstotal = 2; - abinfo.fragments = (count > s->fragsize); - - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - - val = rme96xx_gethwptr(dma->s,0); - - count = rme96xx_getispace(dma,val); - - abinfo.fragsize = (s->fragsize*dma->inchannels)>>dma->formatshift; - abinfo.bytes = (count*dma->inchannels)>>dma->formatshift; - abinfo.fragstotal = 2; - abinfo.fragments = count > s->fragsize; - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: /* What should this exactly do ? , - ATM it is just abinfo.bytes */ - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - - val = rme96xx_gethwptr(dma->s,0); - count = val - dma->readptr; - if (count < 0) - count += s->fragsize<<1; - - return put_user(count, p); - - -/* check out how to use mmaped mode (can only be blocked !!!) */ - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - val = rme96xx_gethwptr(dma->s,0); - spin_lock_irqsave(&s->lock,flags); - cinfo.bytes = s->fragsize<<1; - count = val - dma->readptr; - if (count < 0) - count += s->fragsize<<1; - - cinfo.blocks = (count > s->fragsize); - cinfo.ptr = val; - if (dma->mmapped) - dma->readptr &= s->fragsize<<1; - spin_unlock_irqrestore(&s->lock,flags); - - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - val = rme96xx_gethwptr(dma->s,0); - spin_lock_irqsave(&s->lock,flags); - cinfo.bytes = s->fragsize<<1; - count = val - dma->writeptr; - if (count < 0) - count += s->fragsize<<1; - - cinfo.blocks = (count > s->fragsize); - cinfo.ptr = val; - if (dma->mmapped) - dma->writeptr &= s->fragsize<<1; - spin_unlock_irqrestore(&s->lock,flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - case SNDCTL_DSP_GETBLKSIZE: - return put_user(s->fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - val&=0xffff; - val -= 7; - if (val < 0) val = 0; - if (val > 7) val = 7; - rme96xx_setlatency(s,val); - return 0; - - case SNDCTL_DSP_SUBDIVIDE: -#if 0 - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision)) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - s->dma_dac2.subdivision = val; -#endif - return 0; - - case SOUND_PCM_READ_RATE: - /* HP20020201 */ - s->rate = rme96xx_get_sample_rate_status(s); - return put_user(s->rate, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user(dma->outchannels, p); - - case SOUND_PCM_READ_BITS: - switch (dma->format) { - case AFMT_S32_BLOCKED: - val = 32; - break; - case AFMT_S16_LE: - val = 16; - break; - } - return put_user(val, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - - - return -ENODEV; -} - - - -static int rme96xx_open(struct inode *in, struct file *f) -{ - int minor = iminor(in); - struct list_head *list; - int devnum; - rme96xx_info *s; - struct dmabuf* dma; - DECLARE_WAITQUEUE(wait, current); - - DBG(printk("device num %d open\n",devnum)); - - nonseekable_open(in, f); - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, rme96xx_info, devs); - for (devnum=0; devnumdspnum[devnum] ^ minor) & ~0xf)) - break; - if (devnumdma[devnum]; - f->private_data = dma; - /* wait for device to become free */ - mutex_lock(&dma->open_mutex); - while (dma->open_mode & f->f_mode) { - if (f->f_flags & O_NONBLOCK) { - mutex_unlock(&dma->open_mutex); - return -EBUSY; - } - add_wait_queue(&dma->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&dma->open_mutex); - schedule(); - remove_wait_queue(&dma->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&dma->open_mutex); - } - - COMM ("hardware open") - - if (!dma->opened) rme96xx_dmabuf_init(dma->s,dma,dma->inoffset,dma->outoffset); - - dma->open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE)); - dma->opened = 1; - mutex_unlock(&dma->open_mutex); - - DBG(printk("device num %d open finished\n",devnum)); - return 0; -} - -static int rme96xx_release(struct inode *in, struct file *file) -{ - struct dmabuf * dma = (struct dmabuf*) file->private_data; - /* int hwp; ... was unused HP20020201 */ - DBG(printk("%s\n", __FUNCTION__)); - - COMM ("draining") - if (dma->open_mode & FMODE_WRITE) { -#if 0 /* Why doesn't this work with some cards ?? */ - hwp = rme96xx_gethwptr(dma->s,0); - while (rme96xx_getospace(dma,hwp)) { - interruptible_sleep_on(&(dma->wait)); - hwp = rme96xx_gethwptr(dma->s,0); - } -#endif - rme96xx_clearbufs(dma); - } - - dma->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); - - if (!(dma->open_mode & (FMODE_READ|FMODE_WRITE))) { - dma->opened = 0; - if (dma->s->started) rme96xx_startcard(dma->s,1); - } - - wake_up(&dma->open_wait); - mutex_unlock(&dma->open_mutex); - - return 0; -} - - -static ssize_t rme96xx_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct dmabuf *dma = (struct dmabuf *)file->private_data; - ssize_t ret = 0; - int cnt; /* number of bytes from "buffer" that will/can be used */ - int hop = count/dma->outchannels; - int hwp; - int exact = (file->f_flags & O_NONBLOCK); - - - if(dma == NULL || (dma->s) == NULL) - return -ENXIO; - - if (dma->mmapped || !dma->opened) - return -ENXIO; - - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - - if (! (dma->open_mode & FMODE_WRITE)) - return -ENXIO; - - if (!dma->s->started) rme96xx_startcard(dma->s,exact); - hwp = rme96xx_gethwptr(dma->s,0); - - if(!(dma->started)){ - COMM ("first write") - - dma->readptr = hwp; - dma->writeptr = hwp; - dma->started = 1; - } - - while (count > 0) { - cnt = rme96xx_getospace(dma,hwp); - cnt>>=dma->formatshift; - cnt*=dma->outchannels; - if (cnt > count) - cnt = count; - - if (cnt != 0) { - if (rme96xx_copyfromuser(dma,buffer,cnt,hop)) - return ret ? ret : -EFAULT; - count -= cnt; - buffer += cnt; - ret += cnt; - if (count == 0) return ret; - } - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - - if ((hwp - dma->writeptr) <= 0) { - interruptible_sleep_on(&(dma->wait)); - - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; - } - - hwp = rme96xx_gethwptr(dma->s,exact); - - }; /* count > 0 */ - - return ret; -} - -static ssize_t rme96xx_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct dmabuf *dma = (struct dmabuf *)file->private_data; - ssize_t ret = 0; - int cnt; /* number of bytes from "buffer" that will/can be used */ - int hop = count/dma->inchannels; - int hwp; - int exact = (file->f_flags & O_NONBLOCK); - - - if(dma == NULL || (dma->s) == NULL) - return -ENXIO; - - if (dma->mmapped || !dma->opened) - return -ENXIO; - - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - - if (! (dma->open_mode & FMODE_READ)) - return -ENXIO; - - if (!dma->s->started) rme96xx_startcard(dma->s,exact); - hwp = rme96xx_gethwptr(dma->s,0); - - if(!(dma->started)){ - COMM ("first read") - - dma->writeptr = hwp; - dma->readptr = hwp; - dma->started = 1; - } - - while (count > 0) { - cnt = rme96xx_getispace(dma,hwp); - cnt>>=dma->formatshift; - cnt*=dma->inchannels; - - if (cnt > count) - cnt = count; - - if (cnt != 0) { - - if (rme96xx_copytouser(dma,buffer,cnt,hop)) - return ret ? ret : -EFAULT; - - count -= cnt; - buffer += cnt; - ret += cnt; - if (count == 0) return ret; - } - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - - if ((hwp - dma->readptr) <= 0) { - interruptible_sleep_on(&(dma->wait)); - - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; - } - hwp = rme96xx_gethwptr(dma->s,exact); - - }; /* count > 0 */ - - return ret; -} - -static int rm96xx_mmap(struct file *file, struct vm_area_struct *vma) { - struct dmabuf *dma = (struct dmabuf *)file->private_data; - rme96xx_info* s = dma->s; - unsigned long size; - - VALIDATE_STATE(s); - lock_kernel(); - - if (vma->vm_pgoff != 0) { - unlock_kernel(); - return -EINVAL; - } - size = vma->vm_end - vma->vm_start; - if (size > RME96xx_DMA_MAX_SIZE) { - unlock_kernel(); - return -EINVAL; - } - - - if (vma->vm_flags & VM_WRITE) { - if (!s->started) rme96xx_startcard(s,1); - - if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) { - unlock_kernel(); - return -EAGAIN; - } - } - else if (vma->vm_flags & VM_READ) { - if (!s->started) rme96xx_startcard(s,1); - if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) { - unlock_kernel(); - return -EAGAIN; - } - } else { - unlock_kernel(); - return -EINVAL; - } - - -/* this is the mapping */ - vma->vm_flags &= ~VM_IO; - dma->mmapped = 1; - unlock_kernel(); - return 0; -} - -static unsigned int rme96xx_poll(struct file *file, struct poll_table_struct *wait) -{ - struct dmabuf *dma = (struct dmabuf *)file->private_data; - rme96xx_info* s = dma->s; - unsigned int mask = 0; - unsigned int hwp,cnt; - - DBG(printk("rme96xx poll_wait ...\n")); - VALIDATE_STATE(s); - - if (!s->started) { - mask |= POLLOUT | POLLWRNORM; - } - poll_wait(file, &dma->wait, wait); - - hwp = rme96xx_gethwptr(dma->s,0); - - DBG(printk("rme96xx poll: ..cnt %d > %d\n",cnt,s->fragsize)); - - cnt = rme96xx_getispace(dma,hwp); - - if (file->f_mode & FMODE_READ) - if (cnt > 0) - mask |= POLLIN | POLLRDNORM; - - - - cnt = rme96xx_getospace(dma,hwp); - - if (file->f_mode & FMODE_WRITE) - if (cnt > 0) - mask |= POLLOUT | POLLWRNORM; - - -// printk("rme96xx poll_wait ...%d > %d\n",rme96xx_getospace(dma,hwp),rme96xx_getispace(dma,hwp)); - - return mask; -} - - -static struct file_operations rme96xx_audio_fops = { - .owner = THIS_MODULE, - .read = rme96xx_read, - .write = rme96xx_write, - .poll = rme96xx_poll, - .ioctl = rme96xx_ioctl, - .mmap = rm96xx_mmap, - .open = rme96xx_open, - .release = rme96xx_release -}; - -static int rme96xx_mixer_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct list_head *list; - rme96xx_info *s; - - COMM ("mixer open"); - - nonseekable_open(inode, file); - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, rme96xx_info, devs); - if (s->mixer== minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - - COMM ("mixer opened") - return 0; -} - -static int rme96xx_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - rme96xx_info *s = (rme96xx_info *)file->private_data; - u32 status; - int spdifrate; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - status = readl(s->iobase + RME96xx_status_register); - /* hack to convert rev 1.5 SPDIF rate to "crystalrate" format HP 20020201 */ - rme96xx_spdif_sample_rate(s,&spdifrate); - status = (status & ~RME96xx_F) | ((spdifrate<<22) & RME96xx_F); - - VALIDATE_STATE(s); - if (cmd == SOUND_MIXER_PRIVATE1) { - rme_mixer mixer; - if (copy_from_user(&mixer,argp,sizeof(mixer))) - return -EFAULT; - - mixer.devnr &= RME96xx_MASK_DEVS; - if (mixer.devnr >= devices) - mixer.devnr = devices-1; - if (file->f_mode & FMODE_WRITE && !s->dma[mixer.devnr].opened) { - /* modify only if device not open */ - if (mixer.o_offset < 0) - mixer.o_offset = 0; - if (mixer.o_offset >= RME96xx_CHANNELS_PER_CARD) - mixer.o_offset = RME96xx_CHANNELS_PER_CARD-1; - if (mixer.i_offset < 0) - mixer.i_offset = 0; - if (mixer.i_offset >= RME96xx_CHANNELS_PER_CARD) - mixer.i_offset = RME96xx_CHANNELS_PER_CARD-1; - s->dma[mixer.devnr].outoffset = mixer.o_offset; - s->dma[mixer.devnr].inoffset = mixer.i_offset; - } - - mixer.o_offset = s->dma[mixer.devnr].outoffset; - mixer.i_offset = s->dma[mixer.devnr].inoffset; - - return copy_to_user(argp, &mixer, sizeof(mixer)) ? -EFAULT : 0; - } - if (cmd == SOUND_MIXER_PRIVATE2) { - return put_user(status, p); - } - if (cmd == SOUND_MIXER_PRIVATE3) { - u32 control; - if (copy_from_user(&control,argp,sizeof(control))) - return -EFAULT; - if (file->f_mode & FMODE_WRITE) { - s->control_register &= ~RME96xx_mixer_allowed; - s->control_register |= control & RME96xx_mixer_allowed; - writel(control,s->iobase + RME96xx_control_register); - } - - return put_user(s->control_register, p); - } - return -1; -} - - - -static int rme96xx_mixer_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static /*const*/ struct file_operations rme96xx_mixer_fops = { - .owner = THIS_MODULE, - .ioctl = rme96xx_mixer_ioctl, - .open = rme96xx_mixer_open, - .release = rme96xx_mixer_release, -}; diff --git a/sound/oss/rme96xx.h b/sound/oss/rme96xx.h deleted file mode 100644 index 7a3c188ea0a8..000000000000 --- a/sound/oss/rme96xx.h +++ /dev/null @@ -1,78 +0,0 @@ -/* (C) 2000 Guenter Geiger - with copy/pastes from the driver of Winfried Ritsch - -Modifications - Heiko Purnhagen - HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c - HP20020201 completed? - -A text/graphic control panel (rmectrl/xrmectrl) is available from - http://gige.xdv.org/pages/soft/pages/rme -*/ - - -#ifndef AFMT_S32_BLOCKED -#define AFMT_S32_BLOCKED 0x0000400 -#endif - -/* AFMT_S16_BLOCKED not yet supported */ -#ifndef AFMT_S16_BLOCKED -#define AFMT_S16_BLOCKED 0x0000800 -#endif - - -typedef struct rme_status { - unsigned int irq:1; - unsigned int lockmask:3; /* ADAT input PLLs locked */ - /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */ - unsigned int sr48:1; /* sample rate: 0=44.1/88.2 1=48/96 kHz */ - unsigned int wclock:1; /* 1=wordclock used */ - unsigned int bufpoint:10; - unsigned int syncmask:3; /* ADAT input in sync with system clock */ - /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */ - unsigned int doublespeed:1; /* sample rate: 0=44.1/48 1=88.2/96 kHz */ - unsigned int tc_busy:1; - unsigned int tc_out:1; - unsigned int crystalrate:3; /* spdif input sample rate: */ - /* 000=64kHz, 100=88.2kHz, 011=96kHz */ - /* 111=32kHz, 110=44.1kHz, 101=48kHz */ - unsigned int spdif_error:1; /* 1=no spdif lock */ - unsigned int bufid:1; - unsigned int tc_valid:1; /* 1=timecode input detected */ - unsigned int spdif_read:1; -} rme_status_t; - - -/* only fields marked W: can be modified by writing to SOUND_MIXER_PRIVATE3 */ -typedef struct rme_control { - unsigned int start:1; - unsigned int latency:3; /* buffer size / latency [samples]: */ - /* 0=64 ... 7=8192 */ - unsigned int master:1; /* W: clock mode: 1=master 0=slave/auto */ - unsigned int ie:1; - unsigned int sr48:1; /* samplerate 0=44.1/88.2, 1=48/96 kHz */ - unsigned int spare:1; - unsigned int doublespeed:1; /* double speed 0=44.1/48, 1=88.2/96 Khz */ - unsigned int pro:1; /* W: SPDIF-OUT 0=consumer, 1=professional */ - unsigned int emphasis:1; /* W: SPDIF-OUT emphasis 0=off, 1=on */ - unsigned int dolby:1; /* W: SPDIF-OUT non-audio bit 1=set, 0=unset */ - unsigned int opt_out:1; /* W: use 1st optical OUT as SPDIF: 1=yes, 0=no */ - unsigned int wordclock:1; /* W: use Wordclock as sync (overwrites master) */ - unsigned int spdif_in:2; /* W: SPDIF-IN: */ - /* 00=optical (ADAT1), 01=coaxial (Cinch), 10=internal CDROM */ - unsigned int sync_ref:2; /* W: preferred sync-source in autosync */ - /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */ - unsigned int spdif_reset:1; - unsigned int spdif_select:1; - unsigned int spdif_clock:1; - unsigned int spdif_write:1; - unsigned int adat1_cd:1; /* W: Rev 1.5+: if set, internal CD connector carries ADAT */ -} rme_ctrl_t; - - -typedef struct _rme_mixer { - int i_offset; - int o_offset; - int devnr; - int spare[8]; -} rme_mixer; - diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c index 0ce4e4ef6fe9..23922377250d 100644 --- a/sound/oss/sequencer.c +++ b/sound/oss/sequencer.c @@ -16,7 +16,6 @@ */ #include #include -#define SEQUENCER_C #include "sound_config.h" #include "midi_ctrl.h" diff --git a/sound/oss/sequencer_syms.c b/sound/oss/sequencer_syms.c index 5d008798c310..118525638bd3 100644 --- a/sound/oss/sequencer_syms.c +++ b/sound/oss/sequencer_syms.c @@ -20,10 +20,3 @@ EXPORT_SYMBOL(sound_timer_init); EXPORT_SYMBOL(sound_timer_interrupt); EXPORT_SYMBOL(sound_timer_syncinterval); -/* Tuning */ - -#define _SEQUENCER_C_ -#include "tuning.h" - -EXPORT_SYMBOL(cent_tuning); -EXPORT_SYMBOL(semitone_tuning); diff --git a/sound/oss/sgalaxy.c b/sound/oss/sgalaxy.c deleted file mode 100644 index 0bcff6735319..000000000000 --- a/sound/oss/sgalaxy.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * sound/oss/sgalaxy.c - * - * Low level driver for Aztech Sound Galaxy cards. - * Copyright 1998 Artur Skawina - * - * Supported cards: - * Aztech Sound Galaxy Waverider Pro 32 - 3D - * Aztech Sound Galaxy Washington 16 - * - * Based on cs4232.c by Hannu Savolainen and Alan Cox. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes: - * 11-10-2000 Bartlomiej Zolnierkiewicz - * Added __init to sb_rst() and sb_cmd() - */ - -#include -#include - -#include "sound_config.h" -#include "ad1848.h" - -static void sleep( unsigned howlong ) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(howlong); -} - -#define DPORT 0x80 - -/* Sound Blaster regs */ - -#define SBDSP_RESET 0x6 -#define SBDSP_READ 0xA -#define SBDSP_COMMAND 0xC -#define SBDSP_STATUS SBDSP_COMMAND -#define SBDSP_DATA_AVAIL 0xE - -static int __init sb_rst(int base) -{ - int i; - - outb( 1, base+SBDSP_RESET ); /* reset the DSP */ - outb( 0, base+SBDSP_RESET ); - - for ( i=0; i<500; i++ ) /* delay */ - inb(DPORT); - - for ( i=0; i<100000; i++ ) - { - if ( inb( base+SBDSP_DATA_AVAIL )&0x80 ) - break; - } - - if ( inb( base+SBDSP_READ )!=0xAA ) - return 0; - - return 1; -} - -static int __init sb_cmd( int base, unsigned char val ) -{ - int i; - - for ( i=100000; i; i-- ) - { - if ( (inb( base+SBDSP_STATUS )&0x80)==0 ) - { - outb( val, base+SBDSP_COMMAND ); - break; - } - } - return i; /* i>0 == success */ -} - - -#define ai_sgbase driver_use_1 - -static int __init probe_sgalaxy( struct address_info *ai ) -{ - struct resource *ports; - int n; - - if (!request_region(ai->io_base, 4, "WSS config")) { - printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base); - return 0; - } - - ports = request_region(ai->io_base + 4, 4, "ad1848"); - if (!ports) { - printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base); - release_region(ai->io_base, 4); - return 0; - } - - if (!request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB")) { - printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase); - release_region(ai->io_base + 4, 4); - release_region(ai->io_base, 4); - return 0; - } - - if (ad1848_detect(ports, NULL, ai->osp)) - goto out; /* The card is already active, check irq etc... */ - - /* switch to MSS/WSS mode */ - - sb_rst( ai->ai_sgbase ); - - sb_cmd( ai->ai_sgbase, 9 ); - sb_cmd( ai->ai_sgbase, 0 ); - - sleep( HZ/10 ); - -out: - if (!probe_ms_sound(ai, ports)) { - release_region(ai->io_base + 4, 4); - release_region(ai->io_base, 4); - release_region(ai->ai_sgbase, 0x10); - return 0; - } - - attach_ms_sound(ai, ports, THIS_MODULE); - n=ai->slots[0]; - - if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) { - AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE ); /* Line-in */ - AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH ); /* FM+Wavetable*/ - AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD ); /* CD */ - } - return 1; -} - -static void __exit unload_sgalaxy( struct address_info *ai ) -{ - unload_ms_sound( ai ); - release_region( ai->ai_sgbase, 0x10 ); -} - -static struct address_info cfg; - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma2 = -1; -static int __initdata sgbase = -1; - -module_param(io, int, 0); -module_param(irq, int, 0); -module_param(dma, int, 0); -module_param(dma2, int, 0); -module_param(sgbase, int, 0); - -static int __init init_sgalaxy(void) -{ - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma2; - cfg.ai_sgbase = sgbase; - - if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.ai_sgbase == -1 ) { - printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n"); - return -EINVAL; - } - - if ( probe_sgalaxy(&cfg) == 0 ) - return -ENODEV; - - return 0; -} - -static void __exit cleanup_sgalaxy(void) -{ - unload_sgalaxy(&cfg); -} - -module_init(init_sgalaxy); -module_exit(cleanup_sgalaxy); - -#ifndef MODULE -static int __init setup_sgalaxy(char *str) -{ - /* io, irq, dma, dma2, sgbase */ - int ints[6]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma2 = ints[4]; - sgbase = ints[5]; - - return 1; -} - -__setup("sgalaxy=", setup_sgalaxy); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c deleted file mode 100644 index 8ea532d40198..000000000000 --- a/sound/oss/sonicvibes.c +++ /dev/null @@ -1,2792 +0,0 @@ -/*****************************************************************************/ - -/* - * sonicvibes.c -- S3 Sonic Vibes audio driver. - * - * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Special thanks to David C. Niemi - * - * - * Module command line parameters: - * none so far - * - * - * Supported devices: - * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible - * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible - * /dev/midi simple MIDI UART interface, no ioctl - * - * The card has both an FM and a Wavetable synth, but I have to figure - * out first how to drive them... - * - * Revision history - * 06.05.1998 0.1 Initial release - * 10.05.1998 0.2 Fixed many bugs, esp. ADC rate calculation - * First stab at a simple midi interface (no bells&whistles) - * 13.05.1998 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of - * set_dac_rate in the FMODE_WRITE case in sv_open - * Fix hwptr out of bounds (now mpg123 works) - * 14.05.1998 0.4 Don't allow excessive interrupt rates - * 08.06.1998 0.5 First release using Alan Cox' soundcore instead of miscdevice - * 03.08.1998 0.6 Do not include modversions.h - * Now mixer behaviour can basically be selected between - * "OSS documented" and "OSS actual" behaviour - * 31.08.1998 0.7 Fix realplayer problems - dac.count issues - * 10.12.1998 0.8 Fix drain_dac trying to wait on not yet initialized DMA - * 16.12.1998 0.9 Fix a few f_file & FMODE_ bugs - * 06.01.1999 0.10 remove the silly SA_INTERRUPT flag. - * hopefully killed the egcs section type conflict - * 12.03.1999 0.11 cinfo.blocks should be reset after GETxPTR ioctl. - * reported by Johan Maes - * 22.03.1999 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK - * read/write cannot be executed - * 05.04.1999 0.13 added code to sv_read and sv_write which should detect - * lockups of the sound chip and revive it. This is basically - * an ugly hack, but at least applications using this driver - * won't hang forever. I don't know why these lockups happen, - * it might well be the motherboard chipset (an early 486 PCI - * board with ALI chipset), since every busmastering 100MB - * ethernet card I've tried (Realtek 8139 and Macronix tulip clone) - * exhibit similar behaviour (they work for a couple of packets - * and then lock up and can be revived by ifconfig down/up). - * 07.04.1999 0.14 implemented the following ioctl's: SOUND_PCM_READ_RATE, - * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; - * Alpha fixes reported by Peter Jones - * Note: dmaio hack might still be wrong on archs other than i386 - * 15.06.1999 0.15 Fix bad allocation bug. - * Thanks to Deti Fliegl - * 28.06.1999 0.16 Add pci_set_master - * 03.08.1999 0.17 adapt to Linus' new __setup/__initcall - * added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr" - * 12.08.1999 0.18 module_init/__setup fixes - * 24.08.1999 0.19 get rid of the dmaio kludge, replace with allocate_resource - * 31.08.1999 0.20 add spin_lock_init - * use new resource allocation to allocate DDMA IO space - * replaced current->state = x with set_current_state(x) - * 03.09.1999 0.21 change read semantics for MIDI to match - * OSS more closely; remove possible wakeup race - * 28.10.1999 0.22 More waitqueue races fixed - * 01.12.1999 0.23 New argument to allocate_resource - * 07.12.1999 0.24 More allocate_resource semantics change - * 08.01.2000 0.25 Prevent some ioctl's from returning bad count values on underrun/overrun; - * Tim Janik's BSE (Bedevilled Sound Engine) found this - * use Martin Mares' pci_assign_resource - * 07.02.2000 0.26 Use pci_alloc_consistent and pci_register_driver - * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask - * 12.12.2000 0.28 More dma buffer initializations, patch from - * Tjeerd Mulder - * 31.01.2001 0.29 Register/Unregister gameport - * Fix SETTRIGGER non OSS API conformity - * 18.05.2001 0.30 PCI probing and error values cleaned up by Marcus - * Meissner - * 03.01.2003 0.31 open_mode fixes from Georg Acher - * - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include - -#include "dm.h" - -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -#define SUPPORT_JOYSTICK 1 -#endif - -/* --------------------------------------------------------------------- */ - -#undef OSS_DOCUMENTED_MIXER_SEMANTICS - -/* --------------------------------------------------------------------- */ - -#ifndef PCI_VENDOR_ID_S3 -#define PCI_VENDOR_ID_S3 0x5333 -#endif -#ifndef PCI_DEVICE_ID_S3_SONICVIBES -#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00 -#endif - -#define SV_MAGIC ((PCI_VENDOR_ID_S3<<16)|PCI_DEVICE_ID_S3_SONICVIBES) - -#define SV_EXTENT_SB 0x10 -#define SV_EXTENT_ENH 0x10 -#define SV_EXTENT_SYNTH 0x4 -#define SV_EXTENT_MIDI 0x4 -#define SV_EXTENT_GAME 0x8 -#define SV_EXTENT_DMA 0x10 - -/* - * we are not a bridge and thus use a resource for DDMA that is used for bridges but - * left empty for normal devices - */ -#define RESOURCE_SB 0 -#define RESOURCE_ENH 1 -#define RESOURCE_SYNTH 2 -#define RESOURCE_MIDI 3 -#define RESOURCE_GAME 4 -#define RESOURCE_DDMA 7 - -#define SV_MIDI_DATA 0 -#define SV_MIDI_COMMAND 1 -#define SV_MIDI_STATUS 1 - -#define SV_DMA_ADDR0 0 -#define SV_DMA_ADDR1 1 -#define SV_DMA_ADDR2 2 -#define SV_DMA_ADDR3 3 -#define SV_DMA_COUNT0 4 -#define SV_DMA_COUNT1 5 -#define SV_DMA_COUNT2 6 -#define SV_DMA_MODE 0xb -#define SV_DMA_RESET 0xd -#define SV_DMA_MASK 0xf - -/* - * DONT reset the DMA controllers unless you understand - * the reset semantics. Assuming reset semantics as in - * the 8237 does not work. - */ - -#define DMA_MODE_AUTOINIT 0x10 -#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ -#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ - -#define SV_CODEC_CONTROL 0 -#define SV_CODEC_INTMASK 1 -#define SV_CODEC_STATUS 2 -#define SV_CODEC_IADDR 4 -#define SV_CODEC_IDATA 5 - -#define SV_CCTRL_RESET 0x80 -#define SV_CCTRL_INTADRIVE 0x20 -#define SV_CCTRL_WAVETABLE 0x08 -#define SV_CCTRL_REVERB 0x04 -#define SV_CCTRL_ENHANCED 0x01 - -#define SV_CINTMASK_DMAA 0x01 -#define SV_CINTMASK_DMAC 0x04 -#define SV_CINTMASK_SPECIAL 0x08 -#define SV_CINTMASK_UPDOWN 0x40 -#define SV_CINTMASK_MIDI 0x80 - -#define SV_CSTAT_DMAA 0x01 -#define SV_CSTAT_DMAC 0x04 -#define SV_CSTAT_SPECIAL 0x08 -#define SV_CSTAT_UPDOWN 0x40 -#define SV_CSTAT_MIDI 0x80 - -#define SV_CIADDR_TRD 0x80 -#define SV_CIADDR_MCE 0x40 - -/* codec indirect registers */ -#define SV_CIMIX_ADCINL 0x00 -#define SV_CIMIX_ADCINR 0x01 -#define SV_CIMIX_AUX1INL 0x02 -#define SV_CIMIX_AUX1INR 0x03 -#define SV_CIMIX_CDINL 0x04 -#define SV_CIMIX_CDINR 0x05 -#define SV_CIMIX_LINEINL 0x06 -#define SV_CIMIX_LINEINR 0x07 -#define SV_CIMIX_MICIN 0x08 -#define SV_CIMIX_SYNTHINL 0x0A -#define SV_CIMIX_SYNTHINR 0x0B -#define SV_CIMIX_AUX2INL 0x0C -#define SV_CIMIX_AUX2INR 0x0D -#define SV_CIMIX_ANALOGINL 0x0E -#define SV_CIMIX_ANALOGINR 0x0F -#define SV_CIMIX_PCMINL 0x10 -#define SV_CIMIX_PCMINR 0x11 - -#define SV_CIGAMECONTROL 0x09 -#define SV_CIDATAFMT 0x12 -#define SV_CIENABLE 0x13 -#define SV_CIUPDOWN 0x14 -#define SV_CIREVISION 0x15 -#define SV_CIADCOUTPUT 0x16 -#define SV_CIDMAABASECOUNT1 0x18 -#define SV_CIDMAABASECOUNT0 0x19 -#define SV_CIDMACBASECOUNT1 0x1c -#define SV_CIDMACBASECOUNT0 0x1d -#define SV_CIPCMSR0 0x1e -#define SV_CIPCMSR1 0x1f -#define SV_CISYNTHSR0 0x20 -#define SV_CISYNTHSR1 0x21 -#define SV_CIADCCLKSOURCE 0x22 -#define SV_CIADCALTSR 0x23 -#define SV_CIADCPLLM 0x24 -#define SV_CIADCPLLN 0x25 -#define SV_CISYNTHPLLM 0x26 -#define SV_CISYNTHPLLN 0x27 -#define SV_CIUARTCONTROL 0x2a -#define SV_CIDRIVECONTROL 0x2b -#define SV_CISRSSPACE 0x2c -#define SV_CISRSCENTER 0x2d -#define SV_CIWAVETABLESRC 0x2e -#define SV_CIANALOGPWRDOWN 0x30 -#define SV_CIDIGITALPWRDOWN 0x31 - - -#define SV_CIMIX_ADCSRC_CD 0x20 -#define SV_CIMIX_ADCSRC_DAC 0x40 -#define SV_CIMIX_ADCSRC_AUX2 0x60 -#define SV_CIMIX_ADCSRC_LINE 0x80 -#define SV_CIMIX_ADCSRC_AUX1 0xa0 -#define SV_CIMIX_ADCSRC_MIC 0xc0 -#define SV_CIMIX_ADCSRC_MIXOUT 0xe0 -#define SV_CIMIX_ADCSRC_MASK 0xe0 - -#define SV_CFMT_STEREO 0x01 -#define SV_CFMT_16BIT 0x02 -#define SV_CFMT_MASK 0x03 -#define SV_CFMT_ASHIFT 0 -#define SV_CFMT_CSHIFT 4 - -static const unsigned sample_size[] = { 1, 2, 2, 4 }; -static const unsigned sample_shift[] = { 0, 1, 1, 2 }; - -#define SV_CENABLE_PPE 0x4 -#define SV_CENABLE_RE 0x2 -#define SV_CENABLE_PE 0x1 - - -/* MIDI buffer sizes */ - -#define MIDIINBUF 256 -#define MIDIOUTBUF 256 - -#define FMODE_MIDI_SHIFT 2 -#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) -#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) - -#define FMODE_DMFM 0x10 - -/* --------------------------------------------------------------------- */ - -struct sv_state { - /* magic */ - unsigned int magic; - - /* list of sonicvibes devices */ - struct list_head devs; - - /* the corresponding pci_dev structure */ - struct pci_dev *dev; - - /* soundcore stuff */ - int dev_audio; - int dev_mixer; - int dev_midi; - int dev_dmfm; - - /* hardware resources */ - unsigned long iosb, ioenh, iosynth, iomidi; /* long for SPARC */ - unsigned int iodmaa, iodmac, irq; - - /* mixer stuff */ - struct { - unsigned int modcnt; -#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS - unsigned short vol[13]; -#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - } mix; - - /* wave stuff */ - unsigned int rateadc, ratedac; - unsigned char fmt, enable; - - spinlock_t lock; - struct mutex open_mutex; - mode_t open_mode; - wait_queue_head_t open_wait; - - struct dmabuf { - void *rawbuf; - dma_addr_t dmaaddr; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - unsigned hwptr, swptr; - unsigned total_bytes; - int count; - unsigned error; /* over/underrun */ - wait_queue_head_t wait; - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dmasize; - unsigned fragsamples; - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned endcleared:1; - unsigned enabled:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac, dma_adc; - - /* midi stuff */ - struct { - unsigned ird, iwr, icnt; - unsigned ord, owr, ocnt; - wait_queue_head_t iwait; - wait_queue_head_t owait; - struct timer_list timer; - unsigned char ibuf[MIDIINBUF]; - unsigned char obuf[MIDIOUTBUF]; - } midi; - -#if SUPPORT_JOYSTICK - struct gameport *gameport; -#endif -}; - -/* --------------------------------------------------------------------- */ - -static LIST_HEAD(devs); -static unsigned long wavetable_mem; - -/* --------------------------------------------------------------------- */ - -static inline unsigned ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -/* --------------------------------------------------------------------- */ - -/* - * Why use byte IO? Nobody knows, but S3 does it also in their Windows driver. - */ - -#undef DMABYTEIO - -static void set_dmaa(struct sv_state *s, unsigned int addr, unsigned int count) -{ -#ifdef DMABYTEIO - unsigned io = s->iodmaa, u; - - count--; - for (u = 4; u > 0; u--, addr >>= 8, io++) - outb(addr & 0xff, io); - for (u = 3; u > 0; u--, count >>= 8, io++) - outb(count & 0xff, io); -#else /* DMABYTEIO */ - count--; - outl(addr, s->iodmaa + SV_DMA_ADDR0); - outl(count, s->iodmaa + SV_DMA_COUNT0); -#endif /* DMABYTEIO */ - outb(0x18, s->iodmaa + SV_DMA_MODE); -} - -static void set_dmac(struct sv_state *s, unsigned int addr, unsigned int count) -{ -#ifdef DMABYTEIO - unsigned io = s->iodmac, u; - - count >>= 1; - count--; - for (u = 4; u > 0; u--, addr >>= 8, io++) - outb(addr & 0xff, io); - for (u = 3; u > 0; u--, count >>= 8, io++) - outb(count & 0xff, io); -#else /* DMABYTEIO */ - count >>= 1; - count--; - outl(addr, s->iodmac + SV_DMA_ADDR0); - outl(count, s->iodmac + SV_DMA_COUNT0); -#endif /* DMABYTEIO */ - outb(0x14, s->iodmac + SV_DMA_MODE); -} - -static inline unsigned get_dmaa(struct sv_state *s) -{ -#ifdef DMABYTEIO - unsigned io = s->iodmaa+6, v = 0, u; - - for (u = 3; u > 0; u--, io--) { - v <<= 8; - v |= inb(io); - } - return v + 1; -#else /* DMABYTEIO */ - return (inl(s->iodmaa + SV_DMA_COUNT0) & 0xffffff) + 1; -#endif /* DMABYTEIO */ -} - -static inline unsigned get_dmac(struct sv_state *s) -{ -#ifdef DMABYTEIO - unsigned io = s->iodmac+6, v = 0, u; - - for (u = 3; u > 0; u--, io--) { - v <<= 8; - v |= inb(io); - } - return (v + 1) << 1; -#else /* DMABYTEIO */ - return ((inl(s->iodmac + SV_DMA_COUNT0) & 0xffffff) + 1) << 1; -#endif /* DMABYTEIO */ -} - -static void wrindir(struct sv_state *s, unsigned char idx, unsigned char data) -{ - outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR); - udelay(10); - outb(data, s->ioenh + SV_CODEC_IDATA); - udelay(10); -} - -static unsigned char rdindir(struct sv_state *s, unsigned char idx) -{ - unsigned char v; - - outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR); - udelay(10); - v = inb(s->ioenh + SV_CODEC_IDATA); - udelay(10); - return v; -} - -static void set_fmt(struct sv_state *s, unsigned char mask, unsigned char data) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - outb(SV_CIDATAFMT | SV_CIADDR_MCE, s->ioenh + SV_CODEC_IADDR); - if (mask) { - s->fmt = inb(s->ioenh + SV_CODEC_IDATA); - udelay(10); - } - s->fmt = (s->fmt & mask) | data; - outb(s->fmt, s->ioenh + SV_CODEC_IDATA); - udelay(10); - outb(0, s->ioenh + SV_CODEC_IADDR); - spin_unlock_irqrestore(&s->lock, flags); - udelay(10); -} - -static void frobindir(struct sv_state *s, unsigned char idx, unsigned char mask, unsigned char data) -{ - outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR); - udelay(10); - outb((inb(s->ioenh + SV_CODEC_IDATA) & mask) ^ data, s->ioenh + SV_CODEC_IDATA); - udelay(10); -} - -#define REFFREQUENCY 24576000 -#define ADCMULT 512 -#define FULLRATE 48000 - -static unsigned setpll(struct sv_state *s, unsigned char reg, unsigned rate) -{ - unsigned long flags; - unsigned char r, m=0, n=0; - unsigned xm, xn, xr, xd, metric = ~0U; - /* the warnings about m and n used uninitialized are bogus and may safely be ignored */ - - if (rate < 625000/ADCMULT) - rate = 625000/ADCMULT; - if (rate > 150000000/ADCMULT) - rate = 150000000/ADCMULT; - /* slight violation of specs, needed for continuous sampling rates */ - for (r = 0; rate < 75000000/ADCMULT; r += 0x20, rate <<= 1); - for (xn = 3; xn < 35; xn++) - for (xm = 3; xm < 130; xm++) { - xr = REFFREQUENCY/ADCMULT * xm / xn; - xd = abs((signed)(xr - rate)); - if (xd < metric) { - metric = xd; - m = xm - 2; - n = xn - 2; - } - } - reg &= 0x3f; - spin_lock_irqsave(&s->lock, flags); - outb(reg, s->ioenh + SV_CODEC_IADDR); - udelay(10); - outb(m, s->ioenh + SV_CODEC_IDATA); - udelay(10); - outb(reg+1, s->ioenh + SV_CODEC_IADDR); - udelay(10); - outb(r | n, s->ioenh + SV_CODEC_IDATA); - spin_unlock_irqrestore(&s->lock, flags); - udelay(10); - return (REFFREQUENCY/ADCMULT * (m + 2) / (n + 2)) >> ((r >> 5) & 7); -} - -#if 0 - -static unsigned getpll(struct sv_state *s, unsigned char reg) -{ - unsigned long flags; - unsigned char m, n; - - reg &= 0x3f; - spin_lock_irqsave(&s->lock, flags); - outb(reg, s->ioenh + SV_CODEC_IADDR); - udelay(10); - m = inb(s->ioenh + SV_CODEC_IDATA); - udelay(10); - outb(reg+1, s->ioenh + SV_CODEC_IADDR); - udelay(10); - n = inb(s->ioenh + SV_CODEC_IDATA); - spin_unlock_irqrestore(&s->lock, flags); - udelay(10); - return (REFFREQUENCY/ADCMULT * (m + 2) / ((n & 0x1f) + 2)) >> ((n >> 5) & 7); -} - -#endif - -static void set_dac_rate(struct sv_state *s, unsigned rate) -{ - unsigned div; - unsigned long flags; - - if (rate > 48000) - rate = 48000; - if (rate < 4000) - rate = 4000; - div = (rate * 65536 + FULLRATE/2) / FULLRATE; - if (div > 65535) - div = 65535; - spin_lock_irqsave(&s->lock, flags); - wrindir(s, SV_CIPCMSR1, div >> 8); - wrindir(s, SV_CIPCMSR0, div); - spin_unlock_irqrestore(&s->lock, flags); - s->ratedac = (div * FULLRATE + 32768) / 65536; -} - -static void set_adc_rate(struct sv_state *s, unsigned rate) -{ - unsigned long flags; - unsigned rate1, rate2, div; - - if (rate > 48000) - rate = 48000; - if (rate < 4000) - rate = 4000; - rate1 = setpll(s, SV_CIADCPLLM, rate); - div = (48000 + rate/2) / rate; - if (div > 8) - div = 8; - rate2 = (48000 + div/2) / div; - spin_lock_irqsave(&s->lock, flags); - wrindir(s, SV_CIADCALTSR, (div-1) << 4); - if (abs((signed)(rate-rate2)) <= abs((signed)(rate-rate1))) { - wrindir(s, SV_CIADCCLKSOURCE, 0x10); - s->rateadc = rate2; - } else { - wrindir(s, SV_CIADCCLKSOURCE, 0x00); - s->rateadc = rate1; - } - spin_unlock_irqrestore(&s->lock, flags); -} - -/* --------------------------------------------------------------------- */ - -static inline void stop_adc(struct sv_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->enable &= ~SV_CENABLE_RE; - wrindir(s, SV_CIENABLE, s->enable); - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void stop_dac(struct sv_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->enable &= ~(SV_CENABLE_PPE | SV_CENABLE_PE); - wrindir(s, SV_CIENABLE, s->enable); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac(struct sv_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { - s->enable = (s->enable & ~SV_CENABLE_PPE) | SV_CENABLE_PE; - wrindir(s, SV_CIENABLE, s->enable); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_adc(struct sv_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) - && s->dma_adc.ready) { - s->enable |= SV_CENABLE_RE; - wrindir(s, SV_CIENABLE, s->enable); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -/* --------------------------------------------------------------------- */ - -#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - -static void dealloc_dmabuf(struct sv_state *s, struct dmabuf *db) -{ - struct page *page, *pend; - - if (db->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - ClearPageReserved(page); - pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); - } - db->rawbuf = NULL; - db->mapped = db->ready = 0; -} - - -/* DMAA is used for playback, DMAC is used for recording */ - -static int prog_dmabuf(struct sv_state *s, unsigned rec) -{ - struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; - unsigned rate = rec ? s->rateadc : s->ratedac; - int order; - unsigned bytepersec; - unsigned bufs; - struct page *page, *pend; - unsigned char fmt; - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - fmt = s->fmt; - if (rec) { - s->enable &= ~SV_CENABLE_RE; - fmt >>= SV_CFMT_CSHIFT; - } else { - s->enable &= ~SV_CENABLE_PE; - fmt >>= SV_CFMT_ASHIFT; - } - wrindir(s, SV_CIENABLE, s->enable); - spin_unlock_irqrestore(&s->lock, flags); - fmt &= SV_CFMT_MASK; - db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; - if (!db->rawbuf) { - db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) - break; - if (!db->rawbuf) - return -ENOMEM; - db->buforder = order; - if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff) - printk(KERN_DEBUG "sv: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n", - virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); - if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff) - printk(KERN_DEBUG "sv: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n", - virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - SetPageReserved(page); - } - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; - memset(db->rawbuf, (fmt & SV_CFMT_16BIT) ? 0 : 0x80, db->dmasize); - spin_lock_irqsave(&s->lock, flags); - if (rec) { - set_dmac(s, db->dmaaddr, db->numfrag << db->fragshift); - /* program enhanced mode registers */ - wrindir(s, SV_CIDMACBASECOUNT1, (db->fragsamples-1) >> 8); - wrindir(s, SV_CIDMACBASECOUNT0, db->fragsamples-1); - } else { - set_dmaa(s, db->dmaaddr, db->numfrag << db->fragshift); - /* program enhanced mode registers */ - wrindir(s, SV_CIDMAABASECOUNT1, (db->fragsamples-1) >> 8); - wrindir(s, SV_CIDMAABASECOUNT0, db->fragsamples-1); - } - spin_unlock_irqrestore(&s->lock, flags); - db->enabled = 1; - db->ready = 1; - return 0; -} - -static inline void clear_advance(struct sv_state *s) -{ - unsigned char c = (s->fmt & (SV_CFMT_16BIT << SV_CFMT_ASHIFT)) ? 0 : 0x80; - unsigned char *buf = s->dma_dac.rawbuf; - unsigned bsize = s->dma_dac.dmasize; - unsigned bptr = s->dma_dac.swptr; - unsigned len = s->dma_dac.fragsize; - - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(buf + bptr, c, x); - bptr = 0; - len -= x; - } - memset(buf + bptr, c, len); -} - -/* call with spinlock held! */ -static void sv_update_ptr(struct sv_state *s) -{ - unsigned hwptr; - int diff; - - /* update ADC pointer */ - if (s->dma_adc.ready) { - hwptr = (s->dma_adc.dmasize - get_dmac(s)) % s->dma_adc.dmasize; - diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; - s->dma_adc.hwptr = hwptr; - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - wake_up(&s->dma_adc.wait); - if (!s->dma_adc.mapped) { - if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { - s->enable &= ~SV_CENABLE_RE; - wrindir(s, SV_CIENABLE, s->enable); - s->dma_adc.error++; - } - } - } - /* update DAC pointer */ - if (s->dma_dac.ready) { - hwptr = (s->dma_dac.dmasize - get_dmaa(s)) % s->dma_dac.dmasize; - diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; - s->dma_dac.hwptr = hwptr; - s->dma_dac.total_bytes += diff; - if (s->dma_dac.mapped) { - s->dma_dac.count += diff; - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - wake_up(&s->dma_dac.wait); - } else { - s->dma_dac.count -= diff; - if (s->dma_dac.count <= 0) { - s->enable &= ~SV_CENABLE_PE; - wrindir(s, SV_CIENABLE, s->enable); - s->dma_dac.error++; - } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { - clear_advance(s); - s->dma_dac.endcleared = 1; - } - if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) - wake_up(&s->dma_dac.wait); - } - } -} - -/* hold spinlock for the following! */ -static void sv_handle_midi(struct sv_state *s) -{ - unsigned char ch; - int wake; - - wake = 0; - while (!(inb(s->iomidi+1) & 0x80)) { - ch = inb(s->iomidi); - if (s->midi.icnt < MIDIINBUF) { - s->midi.ibuf[s->midi.iwr] = ch; - s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF; - s->midi.icnt++; - } - wake = 1; - } - if (wake) - wake_up(&s->midi.iwait); - wake = 0; - while (!(inb(s->iomidi+1) & 0x40) && s->midi.ocnt > 0) { - outb(s->midi.obuf[s->midi.ord], s->iomidi); - s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF; - s->midi.ocnt--; - if (s->midi.ocnt < MIDIOUTBUF-16) - wake = 1; - } - if (wake) - wake_up(&s->midi.owait); -} - -static irqreturn_t sv_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct sv_state *s = (struct sv_state *)dev_id; - unsigned int intsrc; - - /* fastpath out, to ease interrupt sharing */ - intsrc = inb(s->ioenh + SV_CODEC_STATUS); - if (!(intsrc & (SV_CSTAT_DMAA | SV_CSTAT_DMAC | SV_CSTAT_MIDI))) - return IRQ_NONE; - spin_lock(&s->lock); - sv_update_ptr(s); - sv_handle_midi(s); - spin_unlock(&s->lock); - return IRQ_HANDLED; -} - -static void sv_midi_timer(unsigned long data) -{ - struct sv_state *s = (struct sv_state *)data; - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - sv_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - s->midi.timer.expires = jiffies+1; - add_timer(&s->midi.timer); -} - -/* --------------------------------------------------------------------- */ - -static const char invalid_magic[] = KERN_CRIT "sv: invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != SV_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -/* --------------------------------------------------------------------- */ - -#define MT_4 1 -#define MT_5MUTE 2 -#define MT_4MUTEMONO 3 -#define MT_6MUTE 4 - -static const struct { - unsigned left:5; - unsigned right:5; - unsigned type:3; - unsigned rec:3; -} mixtable[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_RECLEV] = { SV_CIMIX_ADCINL, SV_CIMIX_ADCINR, MT_4, 0 }, - [SOUND_MIXER_LINE1] = { SV_CIMIX_AUX1INL, SV_CIMIX_AUX1INR, MT_5MUTE, 5 }, - [SOUND_MIXER_CD] = { SV_CIMIX_CDINL, SV_CIMIX_CDINR, MT_5MUTE, 1 }, - [SOUND_MIXER_LINE] = { SV_CIMIX_LINEINL, SV_CIMIX_LINEINR, MT_5MUTE, 4 }, - [SOUND_MIXER_MIC] = { SV_CIMIX_MICIN, SV_CIMIX_ADCINL, MT_4MUTEMONO, 6 }, - [SOUND_MIXER_SYNTH] = { SV_CIMIX_SYNTHINL, SV_CIMIX_SYNTHINR, MT_5MUTE, 2 }, - [SOUND_MIXER_LINE2] = { SV_CIMIX_AUX2INL, SV_CIMIX_AUX2INR, MT_5MUTE, 3 }, - [SOUND_MIXER_VOLUME] = { SV_CIMIX_ANALOGINL, SV_CIMIX_ANALOGINR, MT_5MUTE, 7 }, - [SOUND_MIXER_PCM] = { SV_CIMIX_PCMINL, SV_CIMIX_PCMINR, MT_6MUTE, 0 } -}; - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - -static int return_mixval(struct sv_state *s, unsigned i, int *arg) -{ - unsigned long flags; - unsigned char l, r, rl, rr; - - spin_lock_irqsave(&s->lock, flags); - l = rdindir(s, mixtable[i].left); - r = rdindir(s, mixtable[i].right); - spin_unlock_irqrestore(&s->lock, flags); - switch (mixtable[i].type) { - case MT_4: - r &= 0xf; - l &= 0xf; - rl = 10 + 6 * (l & 15); - rr = 10 + 6 * (r & 15); - break; - - case MT_4MUTEMONO: - rl = 55 - 3 * (l & 15); - if (r & 0x10) - rl += 45; - rr = rl; - r = l; - break; - - case MT_5MUTE: - default: - rl = 100 - 3 * (l & 31); - rr = 100 - 3 * (r & 31); - break; - - case MT_6MUTE: - rl = 100 - 3 * (l & 63) / 2; - rr = 100 - 3 * (r & 63) / 2; - break; - } - if (l & 0x80) - rl = 0; - if (r & 0x80) - rr = 0; - return put_user((rr << 8) | rl, arg); -} - -#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - -static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = -{ - [SOUND_MIXER_RECLEV] = 1, - [SOUND_MIXER_LINE1] = 2, - [SOUND_MIXER_CD] = 3, - [SOUND_MIXER_LINE] = 4, - [SOUND_MIXER_MIC] = 5, - [SOUND_MIXER_SYNTH] = 6, - [SOUND_MIXER_LINE2] = 7, - [SOUND_MIXER_VOLUME] = 8, - [SOUND_MIXER_PCM] = 9 -}; - -#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - -static unsigned mixer_recmask(struct sv_state *s) -{ - unsigned long flags; - int i, j; - - spin_lock_irqsave(&s->lock, flags); - j = rdindir(s, SV_CIMIX_ADCINL) >> 5; - spin_unlock_irqrestore(&s->lock, flags); - j &= 7; - for (i = 0; i < SOUND_MIXER_NRDEVICES && mixtable[i].rec != j; i++); - return 1 << i; -} - -static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - int i, val; - unsigned char l, r, rl, rr; - int __user *p = (int __user *)arg; - - VALIDATE_STATE(s); - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, "SonicVibes", sizeof(info.id)); - strlcpy(info.name, "S3 SonicVibes", sizeof(info.name)); - info.modify_counter = s->mix.modcnt; - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, "SonicVibes", sizeof(info.id)); - strlcpy(info.name, "S3 SonicVibes", sizeof(info.name)); - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, p); - if (cmd == SOUND_MIXER_PRIVATE1) { /* SRS settings */ - if (get_user(val, p)) - return -EFAULT; - spin_lock_irqsave(&s->lock, flags); - if (val & 1) { - if (val & 2) { - l = 4 - ((val >> 2) & 7); - if (l & ~3) - l = 4; - r = 4 - ((val >> 5) & 7); - if (r & ~3) - r = 4; - wrindir(s, SV_CISRSSPACE, l); - wrindir(s, SV_CISRSCENTER, r); - } else - wrindir(s, SV_CISRSSPACE, 0x80); - } - l = rdindir(s, SV_CISRSSPACE); - r = rdindir(s, SV_CISRSCENTER); - spin_unlock_irqrestore(&s->lock, flags); - if (l & 0x80) - return put_user(0, p); - return put_user(((4 - (l & 7)) << 2) | ((4 - (r & 7)) << 5) | 2, p); - } - if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - if (_SIOC_DIR(cmd) == _SIOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - return put_user(mixer_recmask(s), p); - - case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ - for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].type) - val |= 1 << i; - return put_user(val, p); - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].rec) - val |= 1 << i; - return put_user(val, p); - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO) - val |= 1 << i; - return put_user(val, p); - - case SOUND_MIXER_CAPS: - return put_user(SOUND_CAP_EXCL_INPUT, p); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) - return -EINVAL; -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - return return_mixval(s, i, p); -#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - if (!volidx[i]) - return -EINVAL; - return put_user(s->mix.vol[volidx[i]-1], p); -#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - } - } - if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) - return -EINVAL; - s->mix.modcnt++; - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - if (get_user(val, p)) - return -EFAULT; - i = hweight32(val); - if (i == 0) - return 0; /*val = mixer_recmask(s);*/ - else if (i > 1) - val &= ~mixer_recmask(s); - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (!(val & (1 << i))) - continue; - if (mixtable[i].rec) - break; - } - if (i == SOUND_MIXER_NRDEVICES) - return 0; - spin_lock_irqsave(&s->lock, flags); - frobindir(s, SV_CIMIX_ADCINL, 0x1f, mixtable[i].rec << 5); - frobindir(s, SV_CIMIX_ADCINR, 0x1f, mixtable[i].rec << 5); - spin_unlock_irqrestore(&s->lock, flags); - return 0; - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - l = val & 0xff; - r = (val >> 8) & 0xff; - if (mixtable[i].type == MT_4MUTEMONO) - l = (r + l) / 2; - if (l > 100) - l = 100; - if (r > 100) - r = 100; - spin_lock_irqsave(&s->lock, flags); - switch (mixtable[i].type) { - case MT_4: - if (l >= 10) - l -= 10; - if (r >= 10) - r -= 10; - frobindir(s, mixtable[i].left, 0xf0, l / 6); - frobindir(s, mixtable[i].right, 0xf0, l / 6); - break; - - case MT_4MUTEMONO: - rr = 0; - if (l < 10) - rl = 0x80; - else { - if (l >= 55) { - rr = 0x10; - l -= 45; - } - rl = (55 - l) / 3; - } - wrindir(s, mixtable[i].left, rl); - frobindir(s, mixtable[i].right, ~0x10, rr); - break; - - case MT_5MUTE: - if (l < 7) - rl = 0x80; - else - rl = (100 - l) / 3; - if (r < 7) - rr = 0x80; - else - rr = (100 - r) / 3; - wrindir(s, mixtable[i].left, rl); - wrindir(s, mixtable[i].right, rr); - break; - - case MT_6MUTE: - if (l < 6) - rl = 0x80; - else - rl = (100 - l) * 2 / 3; - if (r < 6) - rr = 0x80; - else - rr = (100 - r) * 2 / 3; - wrindir(s, mixtable[i].left, rl); - wrindir(s, mixtable[i].right, rr); - break; - } - spin_unlock_irqrestore(&s->lock, flags); -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - return return_mixval(s, i, p); -#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - if (!volidx[i]) - return -EINVAL; - s->mix.vol[volidx[i]-1] = val; - return put_user(s->mix.vol[volidx[i]-1], p); -#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - } -} - -/* --------------------------------------------------------------------- */ - -static int sv_open_mixdev(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct list_head *list; - struct sv_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct sv_state, devs); - if (s->dev_mixer == minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - return nonseekable_open(inode, file); -} - -static int sv_release_mixdev(struct inode *inode, struct file *file) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - - VALIDATE_STATE(s); - return 0; -} - -static int sv_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - return mixer_ioctl((struct sv_state *)file->private_data, cmd, arg); -} - -static /*const*/ struct file_operations sv_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = sv_ioctl_mixdev, - .open = sv_open_mixdev, - .release = sv_release_mixdev, -}; - -/* --------------------------------------------------------------------- */ - -static int drain_dac(struct sv_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count, tmo; - - if (s->dma_dac.mapped || !s->dma_dac.ready) - return 0; - add_wait_queue(&s->dma_dac.wait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac; - tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK]; - if (!schedule_timeout(tmo + 1)) - printk(KERN_DEBUG "sv: dma timed out??\n"); - } - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static ssize_t sv_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; -#if 0 - spin_lock_irqsave(&s->lock, flags); - sv_update_ptr(s); - spin_unlock_irqrestore(&s->lock, flags); -#endif - add_wait_queue(&s->dma_adc.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - swptr = s->dma_adc.swptr; - cnt = s->dma_adc.dmasize-swptr; - if (s->dma_adc.count < cnt) - cnt = s->dma_adc.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_adc.enabled) - start_adc(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - if (!schedule_timeout(HZ)) { - printk(KERN_DEBUG "sv: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, - s->dma_adc.hwptr, s->dma_adc.swptr); - stop_adc(s); - spin_lock_irqsave(&s->lock, flags); - set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); - /* program enhanced mode registers */ - wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); - wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); - s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; - spin_unlock_irqrestore(&s->lock, flags); - } - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - swptr = (swptr + cnt) % s->dma_adc.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_adc.swptr = swptr; - s->dma_adc.count -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_adc.enabled) - start_adc(s); - } - remove_wait_queue(&s->dma_adc.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -static ssize_t sv_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac.mapped) - return -ENXIO; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; -#if 0 - spin_lock_irqsave(&s->lock, flags); - sv_update_ptr(s); - spin_unlock_irqrestore(&s->lock, flags); -#endif - add_wait_queue(&s->dma_dac.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - if (s->dma_dac.count < 0) { - s->dma_dac.count = 0; - s->dma_dac.swptr = s->dma_dac.hwptr; - } - swptr = s->dma_dac.swptr; - cnt = s->dma_dac.dmasize-swptr; - if (s->dma_dac.count + cnt > s->dma_dac.dmasize) - cnt = s->dma_dac.dmasize - s->dma_dac.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_dac.enabled) - start_dac(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - if (!schedule_timeout(HZ)) { - printk(KERN_DEBUG "sv: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, - s->dma_dac.hwptr, s->dma_dac.swptr); - stop_dac(s); - spin_lock_irqsave(&s->lock, flags); - set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); - /* program enhanced mode registers */ - wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); - wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); - s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; - spin_unlock_irqrestore(&s->lock, flags); - } - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - swptr = (swptr + cnt) % s->dma_dac.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_dac.swptr = swptr; - s->dma_dac.count += cnt; - s->dma_dac.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_dac.enabled) - start_dac(s); - } - remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int sv_poll(struct file *file, struct poll_table_struct *wait) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac.ready && prog_dmabuf(s, 1)) - return 0; - poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready && prog_dmabuf(s, 0)) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - spin_lock_irqsave(&s->lock, flags); - sv_update_ptr(s); - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int sv_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - struct dmabuf *db; - int ret = -EINVAL; - unsigned long size; - - VALIDATE_STATE(s); - lock_kernel(); - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf(s, 1)) != 0) - goto out; - db = &s->dma_dac; - } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf(s, 0)) != 0) - goto out; - db = &s->dma_adc; - } else - goto out; - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) - goto out; - ret = -EAGAIN; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - db->mapped = 1; - ret = 0; -out: - unlock_kernel(); - return ret; -} - -static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, mapped, ret; - unsigned char fmtm, fmtd; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(s->irq); - s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->irq); - s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - set_adc_rate(s, val); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - set_dac_rate(s, val); - } - } - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val) - fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT; - else - fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val) - fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT; - else - fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT); - } - set_fmt(s, fmtm, fmtd); - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val >= 2) - fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT; - else - fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val >= 2) - fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT; - else - fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT); - } - set_fmt(s, fmtm, fmtd); - } - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT) - : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U8, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val == AFMT_S16_LE) - fmtd |= SV_CFMT_16BIT << SV_CFMT_CSHIFT; - else - fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_CSHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val == AFMT_S16_LE) - fmtd |= SV_CFMT_16BIT << SV_CFMT_ASHIFT; - else - fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_ASHIFT); - } - set_fmt(s, fmtm, fmtd); - } - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT) - : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? AFMT_S16_LE : AFMT_U8, p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if (file->f_mode & FMODE_READ && s->enable & SV_CENABLE_RE) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && s->enable & SV_CENABLE_PE) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - s->dma_adc.enabled = 1; - start_adc(s); - } else { - s->dma_adc.enabled = 0; - stop_adc(s); - } - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - s->dma_dac.enabled = 1; - start_dac(s); - } else { - s->dma_dac.enabled = 0; - stop_dac(s); - } - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - sv_update_ptr(s); - abinfo.fragsize = s->dma_dac.fragsize; - count = s->dma_dac.count; - if (count < 0) - count = 0; - abinfo.bytes = s->dma_dac.dmasize - count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - sv_update_ptr(s); - abinfo.fragsize = s->dma_adc.fragsize; - count = s->dma_adc.count; - if (count < 0) - count = 0; - abinfo.bytes = count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - sv_update_ptr(s); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - return put_user(count, p); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - sv_update_ptr(s); - cinfo.bytes = s->dma_adc.total_bytes; - count = s->dma_adc.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_adc.fragshift; - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - sv_update_ptr(s); - cinfo.bytes = s->dma_dac.total_bytes; - count = s->dma_dac.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac.fragshift; - cinfo.ptr = s->dma_dac.hwptr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf(s, 0))) - return val; - return put_user(s->dma_dac.fragsize, p); - } - if ((val = prog_dmabuf(s, 1))) - return val; - return put_user(s->dma_adc.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - s->dma_dac.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT) - : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT) - : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? 16 : 8, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return mixer_ioctl(s, cmd, arg); -} - -static int sv_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned char fmtm = ~0, fmts = 0; - struct list_head *list; - struct sv_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct sv_state, devs); - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - if (file->f_mode & FMODE_READ) { - fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_CSHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= SV_CFMT_16BIT << SV_CFMT_CSHIFT; - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; - s->dma_adc.enabled = 1; - set_adc_rate(s, 8000); - } - if (file->f_mode & FMODE_WRITE) { - fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_ASHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= SV_CFMT_16BIT << SV_CFMT_ASHIFT; - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; - s->dma_dac.enabled = 1; - set_dac_rate(s, 8000); - } - set_fmt(s, fmtm, fmts); - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int sv_release(struct inode *inode, struct file *file) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - if (file->f_mode & FMODE_WRITE) - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - dealloc_dmabuf(s, &s->dma_dac); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - } - s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE)); - wake_up(&s->open_wait); - mutex_unlock(&s->open_mutex); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations sv_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = sv_read, - .write = sv_write, - .poll = sv_poll, - .ioctl = sv_ioctl, - .mmap = sv_mmap, - .open = sv_open, - .release = sv_release, -}; - -/* --------------------------------------------------------------------- */ - -static ssize_t sv_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - if (count == 0) - return 0; - ret = 0; - add_wait_queue(&s->midi.iwait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.ird; - cnt = MIDIINBUF - ptr; - if (s->midi.icnt < cnt) - cnt = s->midi.icnt; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - ptr = (ptr + cnt) % MIDIINBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.ird = ptr; - s->midi.icnt -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - break; - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&s->midi.iwait, &wait); - return ret; -} - -static ssize_t sv_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - if (count == 0) - return 0; - ret = 0; - add_wait_queue(&s->midi.owait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.owr; - cnt = MIDIOUTBUF - ptr; - if (s->midi.ocnt + cnt > MIDIOUTBUF) - cnt = MIDIOUTBUF - s->midi.ocnt; - if (cnt <= 0) { - __set_current_state(TASK_INTERRUPTIBLE); - sv_handle_midi(s); - } - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - ptr = (ptr + cnt) % MIDIOUTBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.owr = ptr; - s->midi.ocnt += cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - spin_lock_irqsave(&s->lock, flags); - sv_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&s->midi.owait, &wait); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int sv_midi_poll(struct file *file, struct poll_table_struct *wait) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) - poll_wait(file, &s->midi.owait, wait); - if (file->f_mode & FMODE_READ) - poll_wait(file, &s->midi.iwait, wait); - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ) { - if (s->midi.icnt > 0) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->midi.ocnt < MIDIOUTBUF) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int sv_midi_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct sv_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct sv_state, devs); - if (s->dev_midi == minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - //outb(inb(s->ioenh + SV_CODEC_CONTROL) | SV_CCTRL_WAVETABLE, s->ioenh + SV_CODEC_CONTROL); - outb(inb(s->ioenh + SV_CODEC_INTMASK) | SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK); - wrindir(s, SV_CIUARTCONTROL, 5); /* output MIDI data to external and internal synth */ - wrindir(s, SV_CIWAVETABLESRC, 1); /* Wavetable in PC RAM */ - outb(0xff, s->iomidi+1); /* reset command */ - outb(0x3f, s->iomidi+1); /* uart command */ - if (!(inb(s->iomidi+1) & 0x80)) - inb(s->iomidi); - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - init_timer(&s->midi.timer); - s->midi.timer.expires = jiffies+1; - s->midi.timer.data = (unsigned long)s; - s->midi.timer.function = sv_midi_timer; - add_timer(&s->midi.timer); - } - if (file->f_mode & FMODE_READ) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - } - if (file->f_mode & FMODE_WRITE) { - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - } - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int sv_midi_release(struct inode *inode, struct file *file) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - unsigned count, tmo; - - VALIDATE_STATE(s); - - lock_kernel(); - if (file->f_mode & FMODE_WRITE) { - add_wait_queue(&s->midi.owait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->midi.ocnt; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (file->f_flags & O_NONBLOCK) { - remove_wait_queue(&s->midi.owait, &wait); - set_current_state(TASK_RUNNING); - unlock_kernel(); - return -EBUSY; - } - tmo = (count * HZ) / 3100; - if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "sv: midi timed out??\n"); - } - remove_wait_queue(&s->midi.owait, &wait); - set_current_state(TASK_RUNNING); - } - mutex_lock(&s->open_mutex); - s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE)); - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - outb(inb(s->ioenh + SV_CODEC_INTMASK) & ~SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK); - del_timer(&s->midi.timer); - } - spin_unlock_irqrestore(&s->lock, flags); - wake_up(&s->open_wait); - mutex_unlock(&s->open_mutex); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations sv_midi_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = sv_midi_read, - .write = sv_midi_write, - .poll = sv_midi_poll, - .open = sv_midi_open, - .release = sv_midi_release, -}; - -/* --------------------------------------------------------------------- */ - -static int sv_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - static const unsigned char op_offset[18] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 - }; - struct sv_state *s = (struct sv_state *)file->private_data; - struct dm_fm_voice v; - struct dm_fm_note n; - struct dm_fm_params p; - unsigned int io; - unsigned int regb; - - switch (cmd) { - case FM_IOCTL_RESET: - for (regb = 0xb0; regb < 0xb9; regb++) { - outb(regb, s->iosynth); - outb(0, s->iosynth+1); - outb(regb, s->iosynth+2); - outb(0, s->iosynth+3); - } - return 0; - - case FM_IOCTL_PLAY_NOTE: - if (copy_from_user(&n, (void __user *)arg, sizeof(n))) - return -EFAULT; - if (n.voice >= 18) - return -EINVAL; - if (n.voice >= 9) { - regb = n.voice - 9; - io = s->iosynth+2; - } else { - regb = n.voice; - io = s->iosynth; - } - outb(0xa0 + regb, io); - outb(n.fnum & 0xff, io+1); - outb(0xb0 + regb, io); - outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1); - return 0; - - case FM_IOCTL_SET_VOICE: - if (copy_from_user(&v, (void __user *)arg, sizeof(v))) - return -EFAULT; - if (v.voice >= 18) - return -EINVAL; - regb = op_offset[v.voice]; - io = s->iosynth + ((v.op & 1) << 1); - outb(0x20 + regb, io); - outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) | - ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1); - outb(0x40 + regb, io); - outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1); - outb(0x60 + regb, io); - outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1); - outb(0x80 + regb, io); - outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1); - outb(0xe0 + regb, io); - outb(v.waveform & 0x7, io+1); - if (n.voice >= 9) { - regb = n.voice - 9; - io = s->iosynth+2; - } else { - regb = n.voice; - io = s->iosynth; - } - outb(0xc0 + regb, io); - outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) | - (v.connection & 1), io+1); - return 0; - - case FM_IOCTL_SET_PARAMS: - if (copy_from_user(&p, (void *__user )arg, sizeof(p))) - return -EFAULT; - outb(0x08, s->iosynth); - outb((p.kbd_split & 1) << 6, s->iosynth+1); - outb(0xbd, s->iosynth); - outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) | - ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->iosynth+1); - return 0; - - case FM_IOCTL_SET_OPL: - outb(4, s->iosynth+2); - outb(arg, s->iosynth+3); - return 0; - - case FM_IOCTL_SET_MODE: - outb(5, s->iosynth+2); - outb(arg & 1, s->iosynth+3); - return 0; - - default: - return -EINVAL; - } -} - -static int sv_dmfm_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - struct list_head *list; - struct sv_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct sv_state, devs); - if (s->dev_dmfm == minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & FMODE_DMFM) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - /* init the stuff */ - outb(1, s->iosynth); - outb(0x20, s->iosynth+1); /* enable waveforms */ - outb(4, s->iosynth+2); - outb(0, s->iosynth+3); /* no 4op enabled */ - outb(5, s->iosynth+2); - outb(1, s->iosynth+3); /* enable OPL3 */ - s->open_mode |= FMODE_DMFM; - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int sv_dmfm_release(struct inode *inode, struct file *file) -{ - struct sv_state *s = (struct sv_state *)file->private_data; - unsigned int regb; - - VALIDATE_STATE(s); - lock_kernel(); - mutex_lock(&s->open_mutex); - s->open_mode &= ~FMODE_DMFM; - for (regb = 0xb0; regb < 0xb9; regb++) { - outb(regb, s->iosynth); - outb(0, s->iosynth+1); - outb(regb, s->iosynth+2); - outb(0, s->iosynth+3); - } - wake_up(&s->open_wait); - mutex_unlock(&s->open_mutex); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations sv_dmfm_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = sv_dmfm_ioctl, - .open = sv_dmfm_open, - .release = sv_dmfm_release, -}; - -/* --------------------------------------------------------------------- */ - -/* maximum number of devices; only used for command line params */ -#define NR_DEVICE 5 - -static int reverb[NR_DEVICE]; - -#if 0 -static int wavetable[NR_DEVICE]; -#endif - -static unsigned int devindex; - -module_param_array(reverb, bool, NULL, 0); -MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM"); -#if 0 -MODULE_PARM(wavetable, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled"); -#endif - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("S3 SonicVibes Driver"); -MODULE_LICENSE("GPL"); - - -/* --------------------------------------------------------------------- */ - -static struct initvol { - int mixch; - int vol; -} initvol[] __devinitdata = { - { SOUND_MIXER_WRITE_RECLEV, 0x4040 }, - { SOUND_MIXER_WRITE_LINE1, 0x4040 }, - { SOUND_MIXER_WRITE_CD, 0x4040 }, - { SOUND_MIXER_WRITE_LINE, 0x4040 }, - { SOUND_MIXER_WRITE_MIC, 0x4040 }, - { SOUND_MIXER_WRITE_SYNTH, 0x4040 }, - { SOUND_MIXER_WRITE_LINE2, 0x4040 }, - { SOUND_MIXER_WRITE_VOLUME, 0x4040 }, - { SOUND_MIXER_WRITE_PCM, 0x4040 } -}; - -#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \ - (pci_resource_flags((dev), (num)) & IORESOURCE_IO)) - -#ifdef SUPPORT_JOYSTICK -static int __devinit sv_register_gameport(struct sv_state *s, int io_port) -{ - struct gameport *gp; - - if (!request_region(io_port, SV_EXTENT_GAME, "S3 SonicVibes Gameport")) { - printk(KERN_ERR "sv: gameport io ports are in use\n"); - return -EBUSY; - } - - s->gameport = gp = gameport_allocate_port(); - if (!gp) { - printk(KERN_ERR "sv: can not allocate memory for gameport\n"); - release_region(io_port, SV_EXTENT_GAME); - return -ENOMEM; - } - - gameport_set_name(gp, "S3 SonicVibes Gameport"); - gameport_set_phys(gp, "isa%04x/gameport0", io_port); - gp->dev.parent = &s->dev->dev; - gp->io = io_port; - - gameport_register_port(gp); - - return 0; -} - -static inline void sv_unregister_gameport(struct sv_state *s) -{ - if (s->gameport) { - int gpio = s->gameport->io; - gameport_unregister_port(s->gameport); - release_region(gpio, SV_EXTENT_GAME); - } -} -#else -static inline int sv_register_gameport(struct sv_state *s, int io_port) { return -ENOSYS; } -static inline void sv_unregister_gameport(struct sv_state *s) { } -#endif /* SUPPORT_JOYSTICK */ - -static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) -{ - static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller"; - struct sv_state *s; - mm_segment_t fs; - int i, val, ret; - int gpio; - char *ddmaname; - unsigned ddmanamelen; - - if ((ret=pci_enable_device(pcidev))) - return ret; - - if (!RSRCISIOREGION(pcidev, RESOURCE_SB) || - !RSRCISIOREGION(pcidev, RESOURCE_ENH) || - !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) || - !RSRCISIOREGION(pcidev, RESOURCE_MIDI) || - !RSRCISIOREGION(pcidev, RESOURCE_GAME)) - return -ENODEV; - if (pcidev->irq == 0) - return -ENODEV; - if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK)) { - printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n"); - return -ENODEV; - } - /* try to allocate a DDMA resource if not already available */ - if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) { - pcidev->resource[RESOURCE_DDMA].start = 0; - pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1; - pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO; - ddmanamelen = strlen(sv_ddma_name)+1; - if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL))) - return -1; - memcpy(ddmaname, sv_ddma_name, ddmanamelen); - pcidev->resource[RESOURCE_DDMA].name = ddmaname; - if (pci_assign_resource(pcidev, RESOURCE_DDMA)) { - pcidev->resource[RESOURCE_DDMA].name = NULL; - kfree(ddmaname); - printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n"); - return -EBUSY; - } - } - if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) { - printk(KERN_WARNING "sv: out of memory\n"); - return -ENOMEM; - } - memset(s, 0, sizeof(struct sv_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->midi.iwait); - init_waitqueue_head(&s->midi.owait); - mutex_init(&s->open_mutex); - spin_lock_init(&s->lock); - s->magic = SV_MAGIC; - s->dev = pcidev; - s->iosb = pci_resource_start(pcidev, RESOURCE_SB); - s->ioenh = pci_resource_start(pcidev, RESOURCE_ENH); - s->iosynth = pci_resource_start(pcidev, RESOURCE_SYNTH); - s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI); - s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA); - s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA; - gpio = pci_resource_start(pcidev, RESOURCE_GAME); - pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */ - pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */ - printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#x %#x %#x\n", - s->iosb, s->ioenh, s->iosynth, s->iomidi, gpio, s->iodmaa, s->iodmac); - s->irq = pcidev->irq; - - /* hack */ - pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */ - - ret = -EBUSY; - if (!request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM")) { - printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1); - goto err_region5; - } - if (!request_region(s->iodmaa, SV_EXTENT_DMA, "S3 SonicVibes DMAA")) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmaa, s->iodmaa+SV_EXTENT_DMA-1); - goto err_region4; - } - if (!request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC")) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmac, s->iodmac+SV_EXTENT_DMA-1); - goto err_region3; - } - if (!request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi")) { - printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1); - goto err_region2; - } - if (!request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth")) { - printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); - goto err_region1; - } - - /* initialize codec registers */ - outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */ - udelay(50); - outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */ - udelay(50); - outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */ - | (reverb[devindex] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL); - inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */ - wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */ - wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */ - outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK); - /* outb(0xff, s->iodmaa + SV_DMA_RESET); */ - /* outb(0xff, s->iodmac + SV_DMA_RESET); */ - inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ - wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */ - wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */ - wrindir(s, SV_CIDIGITALPWRDOWN, 0); /* power up the digital parts of the device */ - setpll(s, SV_CIADCPLLM, 8000); - wrindir(s, SV_CISRSSPACE, 0x80); /* SRS off */ - wrindir(s, SV_CIPCMSR0, (8000 * 65536 / FULLRATE) & 0xff); - wrindir(s, SV_CIPCMSR1, ((8000 * 65536 / FULLRATE) >> 8) & 0xff); - wrindir(s, SV_CIADCOUTPUT, 0); - /* request irq */ - if ((ret=request_irq(s->irq,sv_interrupt,IRQF_SHARED,"S3 SonicVibes",s))) { - printk(KERN_ERR "sv: irq %u in use\n", s->irq); - goto err_irq; - } - printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n", - s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION)); - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0) { - ret = s->dev_audio; - goto err_dev1; - } - if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops, -1)) < 0) { - ret = s->dev_mixer; - goto err_dev2; - } - if ((s->dev_midi = register_sound_midi(&sv_midi_fops, -1)) < 0) { - ret = s->dev_midi; - goto err_dev3; - } - if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0) { - ret = s->dev_dmfm; - goto err_dev4; - } - pci_set_master(pcidev); /* enable bus mastering */ - /* initialize the chips */ - fs = get_fs(); - set_fs(KERNEL_DS); - val = SOUND_MASK_LINE|SOUND_MASK_SYNTH; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); - } - set_fs(fs); - /* register gameport */ - sv_register_gameport(s, gpio); - /* store it in the driver field */ - pci_set_drvdata(pcidev, s); - /* put it into driver list */ - list_add_tail(&s->devs, &devs); - /* increment devindex */ - if (devindex < NR_DEVICE-1) - devindex++; - return 0; - - err_dev4: - unregister_sound_midi(s->dev_midi); - err_dev3: - unregister_sound_mixer(s->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - printk(KERN_ERR "sv: cannot register misc device\n"); - free_irq(s->irq, s); - err_irq: - release_region(s->iosynth, SV_EXTENT_SYNTH); - err_region1: - release_region(s->iomidi, SV_EXTENT_MIDI); - err_region2: - release_region(s->iodmac, SV_EXTENT_DMA); - err_region3: - release_region(s->iodmaa, SV_EXTENT_DMA); - err_region4: - release_region(s->ioenh, SV_EXTENT_ENH); - err_region5: - kfree(s); - return ret; -} - -static void __devexit sv_remove(struct pci_dev *dev) -{ - struct sv_state *s = pci_get_drvdata(dev); - - if (!s) - return; - list_del(&s->devs); - outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ - synchronize_irq(s->irq); - inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ - wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ - /*outb(0, s->iodmaa + SV_DMA_RESET);*/ - /*outb(0, s->iodmac + SV_DMA_RESET);*/ - free_irq(s->irq, s); - sv_unregister_gameport(s); - release_region(s->iodmac, SV_EXTENT_DMA); - release_region(s->iodmaa, SV_EXTENT_DMA); - release_region(s->ioenh, SV_EXTENT_ENH); - release_region(s->iomidi, SV_EXTENT_MIDI); - release_region(s->iosynth, SV_EXTENT_SYNTH); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_midi(s->dev_midi); - unregister_sound_special(s->dev_dmfm); - kfree(s); - pci_set_drvdata(dev, NULL); -} - -static struct pci_device_id id_table[] = { - { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, id_table); - -static struct pci_driver sv_driver = { - .name = "sonicvibes", - .id_table = id_table, - .probe = sv_probe, - .remove = __devexit_p(sv_remove), -}; - -static int __init init_sonicvibes(void) -{ - printk(KERN_INFO "sv: version v0.31 time " __TIME__ " " __DATE__ "\n"); -#if 0 - if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) - printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); -#endif - return pci_register_driver(&sv_driver); -} - -static void __exit cleanup_sonicvibes(void) -{ - printk(KERN_INFO "sv: unloading\n"); - pci_unregister_driver(&sv_driver); - if (wavetable_mem) - free_pages(wavetable_mem, 20-PAGE_SHIFT); -} - -module_init(init_sonicvibes); -module_exit(cleanup_sonicvibes); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -/* format is: sonicvibes=[reverb] sonicvibesdmaio=dmaioaddr */ - -static int __init sonicvibes_setup(char *str) -{ - static unsigned __initdata nr_dev = 0; - - if (nr_dev >= NR_DEVICE) - return 0; -#if 0 - if (get_option(&str, &reverb[nr_dev]) == 2) - (void)get_option(&str, &wavetable[nr_dev]); -#else - (void)get_option(&str, &reverb[nr_dev]); -#endif - - nr_dev++; - return 1; -} - -__setup("sonicvibes=", sonicvibes_setup); - -#endif /* MODULE */ diff --git a/sound/oss/sound_calls.h b/sound/oss/sound_calls.h index 1ae07509664f..cd335ba81450 100644 --- a/sound/oss/sound_calls.h +++ b/sound/oss/sound_calls.h @@ -13,8 +13,6 @@ int DMAbuf_move_wrpointer(int dev, int l); void DMAbuf_init(int dev, int dma1, int dma2); void DMAbuf_deinit(int dev); int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); -int DMAbuf_open_dma (int dev); -void DMAbuf_close_dma (int dev); void DMAbuf_inputintr(int dev); void DMAbuf_outputintr(int dev, int underflow_flag); struct dma_buffparms; diff --git a/sound/oss/tuning.h b/sound/oss/tuning.h index 858e1fe6c618..a73e3dd39f9a 100644 --- a/sound/oss/tuning.h +++ b/sound/oss/tuning.h @@ -1,13 +1,11 @@ -#ifdef SEQUENCER_C - -unsigned short semitone_tuning[24] = +static unsigned short semitone_tuning[24] = { /* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983, /* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784, /* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755 }; -unsigned short cent_tuning[100] = +static unsigned short cent_tuning[100] = { /* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041, /* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087, @@ -23,7 +21,3 @@ unsigned short cent_tuning[100] = /* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564, /* 96 */ 10570, 10576, 10582, 10589 }; -#else -extern unsigned short semitone_tuning[24]; -extern unsigned short cent_tuning[100]; -#endif diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c deleted file mode 100644 index 1dec3958cc7b..000000000000 --- a/sound/oss/wavfront.c +++ /dev/null @@ -1,3554 +0,0 @@ -/* -*- linux-c -*- - * - * sound/wavfront.c - * - * A Linux driver for Turtle Beach WaveFront Series (Maui, Tropez, Tropez Plus) - * - * This driver supports the onboard wavetable synthesizer (an ICS2115), - * including patch, sample and program loading and unloading, conversion - * of GUS patches during loading, and full user-level access to all - * WaveFront commands. It tries to provide semi-intelligent patch and - * sample management as well. - * - * It also provides support for the ICS emulation of an MPU-401. Full - * support for the ICS emulation's "virtual MIDI mode" is provided in - * wf_midi.c. - * - * Support is also provided for the Tropez Plus' onboard FX processor, - * a Yamaha YSS225. Currently, code exists to configure the YSS225, - * and there is an interface allowing tweaking of any of its memory - * addresses. However, I have been unable to decipher the logical - * positioning of the configuration info for various effects, so for - * now, you just get the YSS225 in the same state as Turtle Beach's - * "SETUPSND.EXE" utility leaves it. - * - * The boards' DAC/ADC (a Crystal CS4232) is supported by cs4232.[co], - * This chip also controls the configuration of the card: the wavefront - * synth is logical unit 4. - * - * - * Supported devices: - * - * /dev/dsp - using cs4232+ad1848 modules, OSS compatible - * /dev/midiNN and /dev/midiNN+1 - using wf_midi code, OSS compatible - * /dev/synth00 - raw synth interface - * - ********************************************************************** - * - * Copyright (C) by Paul Barton-Davis 1998 - * - * Some portions of this file are taken from work that is - * copyright (C) by Hannu Savolainen 1993-1996 - * - * Although the relevant code here is all new, the handling of - * sample/alias/multi- samples is entirely based on a driver by Matt - * Martin and Rutger Nijlunsing which demonstrated how to get things - * to work correctly. The GUS patch loading code has been almost - * unaltered by me, except to fit formatting and function names in the - * rest of the file. Many thanks to them. - * - * Appreciation and thanks to Hannu Savolainen for his early work on the Maui - * driver, and answering a few questions while this one was developed. - * - * Absolutely NO thanks to Turtle Beach/Voyetra and Yamaha for their - * complete lack of help in developing this driver, and in particular - * for their utter silence in response to questions about undocumented - * aspects of configuring a WaveFront soundcard, particularly the - * effects processor. - * - * $Id: wavfront.c,v 0.7 1998/09/09 15:47:36 pbd Exp $ - * - * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes: - * 11-10-2000 Bartlomiej Zolnierkiewicz - * Added some __init and __initdata to entries in yss225.c - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "sound_config.h" - -#include - -#define _MIDI_SYNTH_C_ -#define MIDI_SYNTH_NAME "WaveFront MIDI" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -/* Compile-time control of the extent to which OSS is supported. - - I consider /dev/sequencer to be an anachronism, but given its - widespread usage by various Linux MIDI software, it seems worth - offering support to it if it's not too painful. Instead of using - /dev/sequencer, I recommend: - - for synth programming and patch loading: /dev/synthNN - for kernel-synchronized MIDI sequencing: the ALSA sequencer - for direct MIDI control: /dev/midiNN - - I have never tried static compilation into the kernel. The #if's - for this are really just notes to myself about what the code is - for. -*/ - -#define OSS_SUPPORT_SEQ 0x1 /* use of /dev/sequencer */ -#define OSS_SUPPORT_STATIC_INSTALL 0x2 /* static compilation into kernel */ - -#define OSS_SUPPORT_LEVEL 0x1 /* just /dev/sequencer for now */ - -#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ -static int (*midi_load_patch) (int devno, int format, const char __user *addr, - int offs, int count, int pmgr_flag) = NULL; -#endif /* OSS_SUPPORT_SEQ */ - -/* if WF_DEBUG not defined, no run-time debugging messages will - be available via the debug flag setting. Given the current - beta state of the driver, this will remain set until a future - version. -*/ - -#define WF_DEBUG 1 - -#ifdef WF_DEBUG - -/* Thank goodness for gcc's preprocessor ... */ - -#define DPRINT(cond, format, args...) \ - if ((dev.debug & (cond)) == (cond)) { \ - printk (KERN_DEBUG LOGNAME format, ## args); \ - } -#else -#define DPRINT(cond, format, args...) -#endif - -#define LOGNAME "WaveFront: " - -/* bitmasks for WaveFront status port value */ - -#define STAT_RINTR_ENABLED 0x01 -#define STAT_CAN_READ 0x02 -#define STAT_INTR_READ 0x04 -#define STAT_WINTR_ENABLED 0x10 -#define STAT_CAN_WRITE 0x20 -#define STAT_INTR_WRITE 0x40 - -/*** Module-accessible parameters ***************************************/ - -static int wf_raw; /* we normally check for "raw state" to firmware - loading. if set, then during driver loading, the - state of the board is ignored, and we reset the - board and load the firmware anyway. - */ - -static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in - whatever state it is when the driver is loaded. - The default is to download the microprogram and - associated coefficients to set it up for "default" - operation, whatever that means. - */ - -static int debug_default; /* you can set this to control debugging - during driver loading. it takes any combination - of the WF_DEBUG_* flags defined in - wavefront.h - */ - -/* XXX this needs to be made firmware and hardware version dependent */ - -static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed - version of the WaveFront OS - */ - -static int wait_polls = 2000; /* This is a number of tries we poll the - status register before resorting to sleeping. - WaveFront being an ISA card each poll takes - about 1.2us. So before going to - sleep we wait up to 2.4ms in a loop. - */ - -static int sleep_length = HZ/100; /* This says how long we're going to - sleep between polls. - 10ms sounds reasonable for fast response. - */ - -static int sleep_tries = 50; /* Wait for status 0.5 seconds total. */ - -static int reset_time = 2; /* hundreths of a second we wait after a HW reset for - the expected interrupt. - */ - -static int ramcheck_time = 20; /* time in seconds to wait while ROM code - checks on-board RAM. - */ - -static int osrun_time = 10; /* time in seconds we wait for the OS to - start running. - */ - -module_param(wf_raw, int, 0); -module_param(fx_raw, int, 0); -module_param(debug_default, int, 0); -module_param(wait_polls, int, 0); -module_param(sleep_length, int, 0); -module_param(sleep_tries, int, 0); -module_param(ospath, charp, 0); -module_param(reset_time, int, 0); -module_param(ramcheck_time, int, 0); -module_param(osrun_time, int, 0); - -/***************************************************************************/ - -/* Note: because this module doesn't export any symbols, this really isn't - a global variable, even if it looks like one. I was quite confused by - this when I started writing this as a (newer) module -- pbd. -*/ - -struct wf_config { - int devno; /* device number from kernel */ - int irq; /* "you were one, one of the few ..." */ - int base; /* low i/o port address */ - -#define mpu_data_port base -#define mpu_command_port base + 1 /* write semantics */ -#define mpu_status_port base + 1 /* read semantics */ -#define data_port base + 2 -#define status_port base + 3 /* read semantics */ -#define control_port base + 3 /* write semantics */ -#define block_port base + 4 /* 16 bit, writeonly */ -#define last_block_port base + 6 /* 16 bit, writeonly */ - - /* FX ports. These are mapped through the ICS2115 to the YS225. - The ICS2115 takes care of flipping the relevant pins on the - YS225 so that access to each of these ports does the right - thing. Note: these are NOT documented by Turtle Beach. - */ - -#define fx_status base + 8 -#define fx_op base + 8 -#define fx_lcr base + 9 -#define fx_dsp_addr base + 0xa -#define fx_dsp_page base + 0xb -#define fx_dsp_lsb base + 0xc -#define fx_dsp_msb base + 0xd -#define fx_mod_addr base + 0xe -#define fx_mod_data base + 0xf - - volatile int irq_ok; /* set by interrupt handler */ - volatile int irq_cnt; /* ditto */ - int opened; /* flag, holds open(2) mode */ - char debug; /* debugging flags */ - int freemem; /* installed RAM, in bytes */ - - int synth_dev; /* devno for "raw" synth */ - int mididev; /* devno for internal MIDI */ - int ext_mididev; /* devno for external MIDI */ - int fx_mididev; /* devno for FX MIDI interface */ -#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ - int oss_dev; /* devno for OSS sequencer synth */ -#endif /* OSS_SUPPORT_SEQ */ - - char fw_version[2]; /* major = [0], minor = [1] */ - char hw_version[2]; /* major = [0], minor = [1] */ - char israw; /* needs Motorola microcode */ - char has_fx; /* has FX processor (Tropez+) */ - char prog_status[WF_MAX_PROGRAM]; /* WF_SLOT_* */ - char patch_status[WF_MAX_PATCH]; /* WF_SLOT_* */ - char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */ - int samples_used; /* how many */ - char interrupts_on; /* h/w MPU interrupts enabled ? */ - char rom_samples_rdonly; /* can we write on ROM samples */ - wait_queue_head_t interrupt_sleeper; -} dev; - -static DEFINE_SPINLOCK(lock); -static int detect_wffx(void); -static int wffx_ioctl (wavefront_fx_info *); -static int wffx_init (void); - -static int wavefront_delete_sample (int sampnum); -static int wavefront_find_free_sample (void); - -/* From wf_midi.c */ - -extern int virtual_midi_enable (void); -extern int virtual_midi_disable (void); -extern int detect_wf_mpu (int, int); -extern int install_wf_mpu (void); -extern int uninstall_wf_mpu (void); - -typedef struct { - int cmd; - char *action; - unsigned int read_cnt; - unsigned int write_cnt; - int need_ack; -} wavefront_command; - -static struct { - int errno; - const char *errstr; -} wavefront_errors[] = { - { 0x01, "Bad sample number" }, - { 0x02, "Out of sample memory" }, - { 0x03, "Bad patch number" }, - { 0x04, "Error in number of voices" }, - { 0x06, "Sample load already in progress" }, - { 0x0B, "No sample load request pending" }, - { 0x0E, "Bad MIDI channel number" }, - { 0x10, "Download Record Error" }, - { 0x80, "Success" }, - { 0 } -}; - -#define NEEDS_ACK 1 - -static wavefront_command wavefront_commands[] = { - { WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK }, - { WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0}, - { WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK }, - { WFC_GET_NVOICES, "get number of voices", 1, 0, 0 }, - { WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK }, - { WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 }, - { WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK }, - { WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK }, - { WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 }, - { WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK }, - { WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK }, - { WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK }, - { WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK }, - { WFC_MIDI_STATUS, "report midi status", 1, 0, 0 }, - { WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 }, - { WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 }, - { WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 }, - { WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 }, - { WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 }, - { WFC_DOWNLOAD_SAMPLE, "download sample", - 0, WF_SAMPLE_BYTES, NEEDS_ACK }, - { WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK}, - { WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header", - 0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK }, - { WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 }, - - /* This command requires a variable number of bytes to be written. - There is a hack in wavefront_cmd() to support this. The actual - count is passed in as the read buffer ptr, cast appropriately. - Ugh. - */ - - { WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK }, - - /* This one is a hack as well. We just read the first byte of the - response, don't fetch an ACK, and leave the rest to the - calling function. Ugly, ugly, ugly. - */ - - { WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 }, - { WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias", - 0, WF_ALIAS_BYTES, NEEDS_ACK }, - { WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0}, - { WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK }, - { WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 }, - { WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" }, - { WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 }, - { WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK }, - { WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 }, - { WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK }, - { WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 }, - { WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9, - NEEDS_ACK}, - { WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0}, - { WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel", - 0, 1, NEEDS_ACK }, - { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK }, - { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers", - 32, 0, 0 }, - { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK }, - { 0x00 } -}; - -static const char * -wavefront_errorstr (int errnum) - -{ - int i; - - for (i = 0; wavefront_errors[i].errstr; i++) { - if (wavefront_errors[i].errno == errnum) { - return wavefront_errors[i].errstr; - } - } - - return "Unknown WaveFront error"; -} - -static wavefront_command * -wavefront_get_command (int cmd) - -{ - int i; - - for (i = 0; wavefront_commands[i].cmd != 0; i++) { - if (cmd == wavefront_commands[i].cmd) { - return &wavefront_commands[i]; - } - } - - return (wavefront_command *) 0; -} - -static inline int -wavefront_status (void) - -{ - return inb (dev.status_port); -} - -static int -wavefront_wait (int mask) - -{ - int i; - - for (i = 0; i < wait_polls; i++) - if (wavefront_status() & mask) - return 1; - - for (i = 0; i < sleep_tries; i++) { - - if (wavefront_status() & mask) { - set_current_state(TASK_RUNNING); - return 1; - } - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(sleep_length); - if (signal_pending(current)) - break; - } - - set_current_state(TASK_RUNNING); - return 0; -} - -static int -wavefront_read (void) - -{ - if (wavefront_wait (STAT_CAN_READ)) - return inb (dev.data_port); - - DPRINT (WF_DEBUG_DATA, "read timeout.\n"); - - return -1; -} - -static int -wavefront_write (unsigned char data) - -{ - if (wavefront_wait (STAT_CAN_WRITE)) { - outb (data, dev.data_port); - return 0; - } - - DPRINT (WF_DEBUG_DATA, "write timeout.\n"); - - return -1; -} - -static int -wavefront_cmd (int cmd, unsigned char *rbuf, unsigned char *wbuf) - -{ - int ack; - int i; - int c; - wavefront_command *wfcmd; - - if ((wfcmd = wavefront_get_command (cmd)) == (wavefront_command *) 0) { - printk (KERN_WARNING LOGNAME "command 0x%x not supported.\n", - cmd); - return 1; - } - - /* Hack to handle the one variable-size write command. See - wavefront_send_multisample() for the other half of this - gross and ugly strategy. - */ - - if (cmd == WFC_DOWNLOAD_MULTISAMPLE) { - wfcmd->write_cnt = (unsigned int) rbuf; - rbuf = NULL; - } - - DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n", - cmd, wfcmd->action, wfcmd->read_cnt, - wfcmd->write_cnt, wfcmd->need_ack); - - if (wavefront_write (cmd)) { - DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request " - "0x%x [%s].\n", - cmd, wfcmd->action); - return 1; - } - - if (wfcmd->write_cnt > 0) { - DPRINT (WF_DEBUG_DATA, "writing %d bytes " - "for 0x%x\n", - wfcmd->write_cnt, cmd); - - for (i = 0; i < wfcmd->write_cnt; i++) { - if (wavefront_write (wbuf[i])) { - DPRINT (WF_DEBUG_IO, "bad write for byte " - "%d of 0x%x [%s].\n", - i, cmd, wfcmd->action); - return 1; - } - - DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n", - i, wbuf[i]); - } - } - - if (wfcmd->read_cnt > 0) { - DPRINT (WF_DEBUG_DATA, "reading %d ints " - "for 0x%x\n", - wfcmd->read_cnt, cmd); - - for (i = 0; i < wfcmd->read_cnt; i++) { - - if ((c = wavefront_read()) == -1) { - DPRINT (WF_DEBUG_IO, "bad read for byte " - "%d of 0x%x [%s].\n", - i, cmd, wfcmd->action); - return 1; - } - - /* Now handle errors. Lots of special cases here */ - - if (c == 0xff) { - if ((c = wavefront_read ()) == -1) { - DPRINT (WF_DEBUG_IO, "bad read for " - "error byte at " - "read byte %d " - "of 0x%x [%s].\n", - i, cmd, - wfcmd->action); - return 1; - } - - /* Can you believe this madness ? */ - - if (c == 1 && - wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) { - rbuf[0] = WF_ST_EMPTY; - return (0); - - } else if (c == 3 && - wfcmd->cmd == WFC_UPLOAD_PATCH) { - - return 3; - - } else if (c == 1 && - wfcmd->cmd == WFC_UPLOAD_PROGRAM) { - - return 1; - - } else { - - DPRINT (WF_DEBUG_IO, "error %d (%s) " - "during " - "read for byte " - "%d of 0x%x " - "[%s].\n", - c, - wavefront_errorstr (c), - i, cmd, - wfcmd->action); - return 1; - - } - - } else { - rbuf[i] = c; - } - - DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]); - } - } - - if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) { - - DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd); - - /* Some commands need an ACK, but return zero instead - of the standard value. - */ - - if ((ack = wavefront_read()) == 0) { - ack = WF_ACK; - } - - if (ack != WF_ACK) { - if (ack == -1) { - DPRINT (WF_DEBUG_IO, "cannot read ack for " - "0x%x [%s].\n", - cmd, wfcmd->action); - return 1; - - } else { - int err = -1; /* something unknown */ - - if (ack == 0xff) { /* explicit error */ - - if ((err = wavefront_read ()) == -1) { - DPRINT (WF_DEBUG_DATA, - "cannot read err " - "for 0x%x [%s].\n", - cmd, wfcmd->action); - } - } - - DPRINT (WF_DEBUG_IO, "0x%x [%s] " - "failed (0x%x, 0x%x, %s)\n", - cmd, wfcmd->action, ack, err, - wavefront_errorstr (err)); - - return -err; - } - } - - DPRINT (WF_DEBUG_DATA, "ack received " - "for 0x%x [%s]\n", - cmd, wfcmd->action); - } else { - - DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need " - "ACK (%d,%d,%d)\n", - cmd, wfcmd->action, wfcmd->read_cnt, - wfcmd->write_cnt, wfcmd->need_ack); - } - - return 0; - -} - -/*********************************************************************** -WaveFront: data munging - -Things here are weird. All data written to the board cannot -have its most significant bit set. Any data item with values -potentially > 0x7F (127) must be split across multiple bytes. - -Sometimes, we need to munge numeric values that are represented on -the x86 side as 8-32 bit values. Sometimes, we need to munge data -that is represented on the x86 side as an array of bytes. The most -efficient approach to handling both cases seems to be to use 2 -different functions for munging and 2 for de-munging. This avoids -weird casting and worrying about bit-level offsets. - -**********************************************************************/ - -static -unsigned char * -munge_int32 (unsigned int src, - unsigned char *dst, - unsigned int dst_size) -{ - int i; - - for (i = 0;i < dst_size; i++) { - *dst = src & 0x7F; /* Mask high bit of LSB */ - src = src >> 7; /* Rotate Right 7 bits */ - /* Note: we leave the upper bits in place */ - - dst++; - }; - return dst; -}; - -static int -demunge_int32 (unsigned char* src, int src_size) - -{ - int i; - int outval = 0; - - for (i = src_size - 1; i >= 0; i--) { - outval=(outval<<7)+src[i]; - } - - return outval; -}; - -static -unsigned char * -munge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size) - -{ - int i; - unsigned int last = dst_size / 2; - - for (i = 0; i < last; i++) { - *dst++ = src[i] & 0x7f; - *dst++ = src[i] >> 7; - } - return dst; -} - -static -unsigned char * -demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes) - -{ - int i; - unsigned char *end = src + src_bytes; - - end = src + src_bytes; - - /* NOTE: src and dst *CAN* point to the same address */ - - for (i = 0; src != end; i++) { - dst[i] = *src++; - dst[i] |= (*src++)<<7; - } - - return dst; -} - -/*********************************************************************** -WaveFront: sample, patch and program management. -***********************************************************************/ - -static int -wavefront_delete_sample (int sample_num) - -{ - unsigned char wbuf[2]; - int x; - - wbuf[0] = sample_num & 0x7f; - wbuf[1] = sample_num >> 7; - - if ((x = wavefront_cmd (WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) { - dev.sample_status[sample_num] = WF_ST_EMPTY; - } - - return x; -} - -static int -wavefront_get_sample_status (int assume_rom) - -{ - int i; - unsigned char rbuf[32], wbuf[32]; - unsigned int sc_real, sc_alias, sc_multi; - - /* check sample status */ - - if (wavefront_cmd (WFC_GET_NSAMPLES, rbuf, wbuf)) { - printk (KERN_WARNING LOGNAME "cannot request sample count.\n"); - return -1; - } - - sc_real = sc_alias = sc_multi = dev.samples_used = 0; - - for (i = 0; i < WF_MAX_SAMPLE; i++) { - - wbuf[0] = i & 0x7f; - wbuf[1] = i >> 7; - - if (wavefront_cmd (WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) { - printk (KERN_WARNING LOGNAME - "cannot identify sample " - "type of slot %d\n", i); - dev.sample_status[i] = WF_ST_EMPTY; - continue; - } - - dev.sample_status[i] = (WF_SLOT_FILLED|rbuf[0]); - - if (assume_rom) { - dev.sample_status[i] |= WF_SLOT_ROM; - } - - switch (rbuf[0] & WF_ST_MASK) { - case WF_ST_SAMPLE: - sc_real++; - break; - case WF_ST_MULTISAMPLE: - sc_multi++; - break; - case WF_ST_ALIAS: - sc_alias++; - break; - case WF_ST_EMPTY: - break; - - default: - printk (KERN_WARNING LOGNAME "unknown sample type for " - "slot %d (0x%x)\n", - i, rbuf[0]); - } - - if (rbuf[0] != WF_ST_EMPTY) { - dev.samples_used++; - } - } - - printk (KERN_INFO LOGNAME - "%d samples used (%d real, %d aliases, %d multi), " - "%d empty\n", dev.samples_used, sc_real, sc_alias, sc_multi, - WF_MAX_SAMPLE - dev.samples_used); - - - return (0); - -} - -static int -wavefront_get_patch_status (void) - -{ - unsigned char patchbuf[WF_PATCH_BYTES]; - unsigned char patchnum[2]; - wavefront_patch *p; - int i, x, cnt, cnt2; - - for (i = 0; i < WF_MAX_PATCH; i++) { - patchnum[0] = i & 0x7f; - patchnum[1] = i >> 7; - - if ((x = wavefront_cmd (WFC_UPLOAD_PATCH, patchbuf, - patchnum)) == 0) { - - dev.patch_status[i] |= WF_SLOT_FILLED; - p = (wavefront_patch *) patchbuf; - dev.sample_status - [p->sample_number|(p->sample_msb<<7)] |= - WF_SLOT_USED; - - } else if (x == 3) { /* Bad patch number */ - dev.patch_status[i] = 0; - } else { - printk (KERN_ERR LOGNAME "upload patch " - "error 0x%x\n", x); - dev.patch_status[i] = 0; - return 1; - } - } - - /* program status has already filled in slot_used bits */ - - for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) { - if (dev.patch_status[i] & WF_SLOT_FILLED) { - cnt++; - } - if (dev.patch_status[i] & WF_SLOT_USED) { - cnt2++; - } - - } - printk (KERN_INFO LOGNAME - "%d patch slots filled, %d in use\n", cnt, cnt2); - - return (0); -} - -static int -wavefront_get_program_status (void) - -{ - unsigned char progbuf[WF_PROGRAM_BYTES]; - wavefront_program prog; - unsigned char prognum; - int i, x, l, cnt; - - for (i = 0; i < WF_MAX_PROGRAM; i++) { - prognum = i; - - if ((x = wavefront_cmd (WFC_UPLOAD_PROGRAM, progbuf, - &prognum)) == 0) { - - dev.prog_status[i] |= WF_SLOT_USED; - - demunge_buf (progbuf, (unsigned char *) &prog, - WF_PROGRAM_BYTES); - - for (l = 0; l < WF_NUM_LAYERS; l++) { - if (prog.layer[l].mute) { - dev.patch_status - [prog.layer[l].patch_number] |= - WF_SLOT_USED; - } - } - } else if (x == 1) { /* Bad program number */ - dev.prog_status[i] = 0; - } else { - printk (KERN_ERR LOGNAME "upload program " - "error 0x%x\n", x); - dev.prog_status[i] = 0; - } - } - - for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) { - if (dev.prog_status[i]) { - cnt++; - } - } - - printk (KERN_INFO LOGNAME "%d programs slots in use\n", cnt); - - return (0); -} - -static int -wavefront_send_patch (wavefront_patch_info *header) - -{ - unsigned char buf[WF_PATCH_BYTES+2]; - unsigned char *bptr; - - DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n", - header->number); - - dev.patch_status[header->number] |= WF_SLOT_FILLED; - - bptr = buf; - bptr = munge_int32 (header->number, buf, 2); - munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES); - - if (wavefront_cmd (WFC_DOWNLOAD_PATCH, NULL, buf)) { - printk (KERN_ERR LOGNAME "download patch failed\n"); - return -(EIO); - } - - return (0); -} - -static int -wavefront_send_program (wavefront_patch_info *header) - -{ - unsigned char buf[WF_PROGRAM_BYTES+1]; - int i; - - DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n", - header->number); - - dev.prog_status[header->number] = WF_SLOT_USED; - - /* XXX need to zero existing SLOT_USED bit for program_status[i] - where `i' is the program that's being (potentially) overwritten. - */ - - for (i = 0; i < WF_NUM_LAYERS; i++) { - if (header->hdr.pr.layer[i].mute) { - dev.patch_status[header->hdr.pr.layer[i].patch_number] |= - WF_SLOT_USED; - - /* XXX need to mark SLOT_USED for sample used by - patch_number, but this means we have to load it. Ick. - */ - } - } - - buf[0] = header->number; - munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES); - - if (wavefront_cmd (WFC_DOWNLOAD_PROGRAM, NULL, buf)) { - printk (KERN_WARNING LOGNAME "download patch failed\n"); - return -(EIO); - } - - return (0); -} - -static int -wavefront_freemem (void) - -{ - char rbuf[8]; - - if (wavefront_cmd (WFC_REPORT_FREE_MEMORY, rbuf, NULL)) { - printk (KERN_WARNING LOGNAME "can't get memory stats.\n"); - return -1; - } else { - return demunge_int32 (rbuf, 4); - } -} - -static int -wavefront_send_sample (wavefront_patch_info *header, - UINT16 __user *dataptr, - int data_is_unsigned) - -{ - /* samples are downloaded via a 16-bit wide i/o port - (you could think of it as 2 adjacent 8-bit wide ports - but its less efficient that way). therefore, all - the blocksizes and so forth listed in the documentation, - and used conventionally to refer to sample sizes, - which are given in 8-bit units (bytes), need to be - divided by 2. - */ - - UINT16 sample_short; - UINT32 length; - UINT16 __user *data_end = NULL; - unsigned int i; - const int max_blksize = 4096/2; - unsigned int written; - unsigned int blocksize; - int dma_ack; - int blocknum; - unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES]; - unsigned char *shptr; - int skip = 0; - int initial_skip = 0; - - DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, " - "type %d, %d bytes from %p\n", - header->size ? "" : "header ", - header->number, header->subkey, - header->size, - header->dataptr); - - if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) { - int x; - - if ((x = wavefront_find_free_sample ()) < 0) { - return -ENOMEM; - } - printk (KERN_DEBUG LOGNAME "unspecified sample => %d\n", x); - header->number = x; - } - - if (header->size) { - - /* XXX it's a debatable point whether or not RDONLY semantics - on the ROM samples should cover just the sample data or - the sample header. For now, it only covers the sample data, - so anyone is free at all times to rewrite sample headers. - - My reason for this is that we have the sample headers - available in the WFB file for General MIDI, and so these - can always be reset if needed. The sample data, however, - cannot be recovered without a complete reset and firmware - reload of the ICS2115, which is a very expensive operation. - - So, doing things this way allows us to honor the notion of - "RESETSAMPLES" reasonably cheaply. Note however, that this - is done purely at user level: there is no WFB parser in - this driver, and so a complete reset (back to General MIDI, - or theoretically some other configuration) is the - responsibility of the user level library. - - To try to do this in the kernel would be a little - crazy: we'd need 158K of kernel space just to hold - a copy of the patch/program/sample header data. - */ - - if (dev.rom_samples_rdonly) { - if (dev.sample_status[header->number] & WF_SLOT_ROM) { - printk (KERN_ERR LOGNAME "sample slot %d " - "write protected\n", - header->number); - return -EACCES; - } - } - - wavefront_delete_sample (header->number); - } - - if (header->size) { - dev.freemem = wavefront_freemem (); - - if (dev.freemem < header->size) { - printk (KERN_ERR LOGNAME - "insufficient memory to " - "load %d byte sample.\n", - header->size); - return -ENOMEM; - } - - } - - skip = WF_GET_CHANNEL(&header->hdr.s); - - if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) { - printk (KERN_ERR LOGNAME "channel selection only " - "possible on 16-bit samples"); - return -(EINVAL); - } - - switch (skip) { - case 0: - initial_skip = 0; - skip = 1; - break; - case 1: - initial_skip = 0; - skip = 2; - break; - case 2: - initial_skip = 1; - skip = 2; - break; - case 3: - initial_skip = 2; - skip = 3; - break; - case 4: - initial_skip = 3; - skip = 4; - break; - case 5: - initial_skip = 4; - skip = 5; - break; - case 6: - initial_skip = 5; - skip = 6; - break; - } - - DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => " - "initial skip = %d, skip = %d\n", - WF_GET_CHANNEL (&header->hdr.s), - initial_skip, skip); - - /* Be safe, and zero the "Unused" bits ... */ - - WF_SET_CHANNEL(&header->hdr.s, 0); - - /* adjust size for 16 bit samples by dividing by two. We always - send 16 bits per write, even for 8 bit samples, so the length - is always half the size of the sample data in bytes. - */ - - length = header->size / 2; - - /* the data we're sent has not been munged, and in fact, the - header we have to send isn't just a munged copy either. - so, build the sample header right here. - */ - - shptr = &sample_hdr[0]; - - shptr = munge_int32 (header->number, shptr, 2); - - if (header->size) { - shptr = munge_int32 (length, shptr, 4); - } - - /* Yes, a 4 byte result doesn't contain all of the offset bits, - but the offset only uses 24 bits. - */ - - shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleStartOffset), - shptr, 4); - shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopStartOffset), - shptr, 4); - shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopEndOffset), - shptr, 4); - shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset), - shptr, 4); - - /* This one is truly weird. What kind of weirdo decided that in - a system dominated by 16 and 32 bit integers, they would use - a just 12 bits ? - */ - - shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); - - /* Why is this nybblified, when the MSB is *always* zero ? - Anyway, we can't take address of bitfield, so make a - good-faith guess at where it starts. - */ - - shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1), - shptr, 2); - - if (wavefront_cmd (header->size ? - WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER, - NULL, sample_hdr)) { - printk (KERN_WARNING LOGNAME "sample %sdownload refused.\n", - header->size ? "" : "header "); - return -(EIO); - } - - if (header->size == 0) { - goto sent; /* Sorry. Just had to have one somewhere */ - } - - data_end = dataptr + length; - - /* Do any initial skip over an unused channel's data */ - - dataptr += initial_skip; - - for (written = 0, blocknum = 0; - written < length; written += max_blksize, blocknum++) { - - if ((length - written) > max_blksize) { - blocksize = max_blksize; - } else { - /* round to nearest 16-byte value */ - blocksize = ((length-written+7)&~0x7); - } - - if (wavefront_cmd (WFC_DOWNLOAD_BLOCK, NULL, NULL)) { - printk (KERN_WARNING LOGNAME "download block " - "request refused.\n"); - return -(EIO); - } - - for (i = 0; i < blocksize; i++) { - - if (dataptr < data_end) { - - __get_user (sample_short, dataptr); - dataptr += skip; - - if (data_is_unsigned) { /* GUS ? */ - - if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) { - - /* 8 bit sample - resolution, sign - extend both bytes. - */ - - ((unsigned char*) - &sample_short)[0] += 0x7f; - ((unsigned char*) - &sample_short)[1] += 0x7f; - - } else { - - /* 16 bit sample - resolution, sign - extend the MSB. - */ - - sample_short += 0x7fff; - } - } - - } else { - - /* In padding section of final block: - - Don't fetch unsupplied data from - user space, just continue with - whatever the final value was. - */ - } - - if (i < blocksize - 1) { - outw (sample_short, dev.block_port); - } else { - outw (sample_short, dev.last_block_port); - } - } - - /* Get "DMA page acknowledge", even though its really - nothing to do with DMA at all. - */ - - if ((dma_ack = wavefront_read ()) != WF_DMA_ACK) { - if (dma_ack == -1) { - printk (KERN_ERR LOGNAME "upload sample " - "DMA ack timeout\n"); - return -(EIO); - } else { - printk (KERN_ERR LOGNAME "upload sample " - "DMA ack error 0x%x\n", - dma_ack); - return -(EIO); - } - } - } - - dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE); - - /* Note, label is here because sending the sample header shouldn't - alter the sample_status info at all. - */ - - sent: - return (0); -} - -static int -wavefront_send_alias (wavefront_patch_info *header) - -{ - unsigned char alias_hdr[WF_ALIAS_BYTES]; - - DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is " - "alias for %d\n", - header->number, - header->hdr.a.OriginalSample); - - munge_int32 (header->number, &alias_hdr[0], 2); - munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2); - munge_int32 (*((unsigned int *)&header->hdr.a.sampleStartOffset), - &alias_hdr[4], 4); - munge_int32 (*((unsigned int *)&header->hdr.a.loopStartOffset), - &alias_hdr[8], 4); - munge_int32 (*((unsigned int *)&header->hdr.a.loopEndOffset), - &alias_hdr[12], 4); - munge_int32 (*((unsigned int *)&header->hdr.a.sampleEndOffset), - &alias_hdr[16], 4); - munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3); - munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2); - - if (wavefront_cmd (WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) { - printk (KERN_ERR LOGNAME "download alias failed.\n"); - return -(EIO); - } - - dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS); - - return (0); -} - -static int -wavefront_send_multisample (wavefront_patch_info *header) -{ - int i; - int num_samples; - unsigned char msample_hdr[WF_MSAMPLE_BYTES]; - - munge_int32 (header->number, &msample_hdr[0], 2); - - /* You'll recall at this point that the "number of samples" value - in a wavefront_multisample struct is actually the log2 of the - real number of samples. - */ - - num_samples = (1<<(header->hdr.ms.NumberOfSamples&7)); - msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples; - - DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n", - header->number, - header->hdr.ms.NumberOfSamples, - num_samples); - - for (i = 0; i < num_samples; i++) { - DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n", - i, header->hdr.ms.SampleNumber[i]); - munge_int32 (header->hdr.ms.SampleNumber[i], - &msample_hdr[3+(i*2)], 2); - } - - /* Need a hack here to pass in the number of bytes - to be written to the synth. This is ugly, and perhaps - one day, I'll fix it. - */ - - if (wavefront_cmd (WFC_DOWNLOAD_MULTISAMPLE, - (unsigned char *) ((num_samples*2)+3), - msample_hdr)) { - printk (KERN_ERR LOGNAME "download of multisample failed.\n"); - return -(EIO); - } - - dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE); - - return (0); -} - -static int -wavefront_fetch_multisample (wavefront_patch_info *header) -{ - int i; - unsigned char log_ns[1]; - unsigned char number[2]; - int num_samples; - - munge_int32 (header->number, number, 2); - - if (wavefront_cmd (WFC_UPLOAD_MULTISAMPLE, log_ns, number)) { - printk (KERN_ERR LOGNAME "upload multisample failed.\n"); - return -(EIO); - } - - DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n", - header->number, log_ns[0]); - - header->hdr.ms.NumberOfSamples = log_ns[0]; - - /* get the number of samples ... */ - - num_samples = (1 << log_ns[0]); - - for (i = 0; i < num_samples; i++) { - s8 d[2]; - - if ((d[0] = wavefront_read ()) == -1) { - printk (KERN_ERR LOGNAME "upload multisample failed " - "during sample loop.\n"); - return -(EIO); - } - - if ((d[1] = wavefront_read ()) == -1) { - printk (KERN_ERR LOGNAME "upload multisample failed " - "during sample loop.\n"); - return -(EIO); - } - - header->hdr.ms.SampleNumber[i] = - demunge_int32 ((unsigned char *) d, 2); - - DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n", - i, header->hdr.ms.SampleNumber[i]); - } - - return (0); -} - - -static int -wavefront_send_drum (wavefront_patch_info *header) - -{ - unsigned char drumbuf[WF_DRUM_BYTES]; - wavefront_drum *drum = &header->hdr.d; - int i; - - DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI " - "note %d, patch = %d\n", - header->number, drum->PatchNumber); - - drumbuf[0] = header->number & 0x7f; - - for (i = 0; i < 4; i++) { - munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2); - } - - if (wavefront_cmd (WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) { - printk (KERN_ERR LOGNAME "download drum failed.\n"); - return -(EIO); - } - - return (0); -} - -static int -wavefront_find_free_sample (void) - -{ - int i; - - for (i = 0; i < WF_MAX_SAMPLE; i++) { - if (!(dev.sample_status[i] & WF_SLOT_FILLED)) { - return i; - } - } - printk (KERN_WARNING LOGNAME "no free sample slots!\n"); - return -1; -} - -static int -wavefront_find_free_patch (void) - -{ - int i; - - for (i = 0; i < WF_MAX_PATCH; i++) { - if (!(dev.patch_status[i] & WF_SLOT_FILLED)) { - return i; - } - } - printk (KERN_WARNING LOGNAME "no free patch slots!\n"); - return -1; -} - -static int -log2_2048(int n) - -{ - int tbl[]={0, 0, 2048, 3246, 4096, 4755, 5294, 5749, 6143, - 6492, 6803, 7084, 7342, 7578, 7797, 8001, 8192, - 8371, 8540, 8699, 8851, 8995, 9132, 9264, 9390, - 9510, 9626, 9738, 9845, 9949, 10049, 10146}; - int i; - - /* Returns 2048*log2(n) */ - - /* FIXME: this is like doing integer math - on quantum particles (RuN) */ - - i=0; - while(n>=32*256) { - n>>=8; - i+=2048*8; - } - while(n>=32) { - n>>=1; - i+=2048; - } - i+=tbl[n]; - return(i); -} - -static int -wavefront_load_gus_patch (int devno, int format, const char __user *addr, - int offs, int count, int pmgr_flag) -{ - struct patch_info guspatch; - wavefront_patch_info *samp, *pat, *prog; - wavefront_patch *patp; - wavefront_sample *sampp; - wavefront_program *progp; - - int i,base_note; - long sizeof_patch; - int rc = -ENOMEM; - - samp = kmalloc(3 * sizeof(wavefront_patch_info), GFP_KERNEL); - if (!samp) - goto free_fail; - pat = samp + 1; - prog = pat + 1; - - /* Copy in the header of the GUS patch */ - - sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch; - if (copy_from_user(&((char *) &guspatch)[offs], - &(addr)[offs], sizeof_patch - offs)) { - rc = -EFAULT; - goto free_fail; - } - - if ((i = wavefront_find_free_patch ()) == -1) { - rc = -EBUSY; - goto free_fail; - } - pat->number = i; - pat->subkey = WF_ST_PATCH; - patp = &pat->hdr.p; - - if ((i = wavefront_find_free_sample ()) == -1) { - rc = -EBUSY; - goto free_fail; - } - samp->number = i; - samp->subkey = WF_ST_SAMPLE; - samp->size = guspatch.len; - sampp = &samp->hdr.s; - - prog->number = guspatch.instr_no; - progp = &prog->hdr.pr; - - /* Setup the patch structure */ - - patp->amplitude_bias=guspatch.volume; - patp->portamento=0; - patp->sample_number= samp->number & 0xff; - patp->sample_msb= samp->number >> 8; - patp->pitch_bend= /*12*/ 0; - patp->mono=1; - patp->retrigger=1; - patp->nohold=(guspatch.mode & WAVE_SUSTAIN_ON) ? 0:1; - patp->frequency_bias=0; - patp->restart=0; - patp->reuse=0; - patp->reset_lfo=1; - patp->fm_src2=0; - patp->fm_src1=WF_MOD_MOD_WHEEL; - patp->am_src=WF_MOD_PRESSURE; - patp->am_amount=127; - patp->fc1_mod_amount=0; - patp->fc2_mod_amount=0; - patp->fm_amount1=0; - patp->fm_amount2=0; - patp->envelope1.attack_level=127; - patp->envelope1.decay1_level=127; - patp->envelope1.decay2_level=127; - patp->envelope1.sustain_level=127; - patp->envelope1.release_level=0; - patp->envelope2.attack_velocity=127; - patp->envelope2.attack_level=127; - patp->envelope2.decay1_level=127; - patp->envelope2.decay2_level=127; - patp->envelope2.sustain_level=127; - patp->envelope2.release_level=0; - patp->envelope2.attack_velocity=127; - patp->randomizer=0; - - /* Program for this patch */ - - progp->layer[0].patch_number= pat->number; /* XXX is this right ? */ - progp->layer[0].mute=1; - progp->layer[0].pan_or_mod=1; - progp->layer[0].pan=7; - progp->layer[0].mix_level=127 /* guspatch.volume */; - progp->layer[0].split_type=0; - progp->layer[0].split_point=0; - progp->layer[0].play_below=0; - - for (i = 1; i < 4; i++) { - progp->layer[i].mute=0; - } - - /* Sample data */ - - sampp->SampleResolution=((~guspatch.mode & WAVE_16_BITS)<<1); - - for (base_note=0; - note_to_freq (base_note) < guspatch.base_note; - base_note++); - - if ((guspatch.base_note-note_to_freq(base_note)) - >(note_to_freq(base_note)-guspatch.base_note)) - base_note++; - - printk(KERN_DEBUG "ref freq=%d,base note=%d\n", - guspatch.base_freq, - base_note); - - sampp->FrequencyBias = (29550 - log2_2048(guspatch.base_freq) - + base_note*171); - printk(KERN_DEBUG "Freq Bias is %d\n", sampp->FrequencyBias); - sampp->Loop=(guspatch.mode & WAVE_LOOPING) ? 1:0; - sampp->sampleStartOffset.Fraction=0; - sampp->sampleStartOffset.Integer=0; - sampp->loopStartOffset.Fraction=0; - sampp->loopStartOffset.Integer=guspatch.loop_start - >>((guspatch.mode&WAVE_16_BITS) ? 1:0); - sampp->loopEndOffset.Fraction=0; - sampp->loopEndOffset.Integer=guspatch.loop_end - >>((guspatch.mode&WAVE_16_BITS) ? 1:0); - sampp->sampleEndOffset.Fraction=0; - sampp->sampleEndOffset.Integer=guspatch.len >> (guspatch.mode&1); - sampp->Bidirectional=(guspatch.mode&WAVE_BIDIR_LOOP) ? 1:0; - sampp->Reverse=(guspatch.mode&WAVE_LOOP_BACK) ? 1:0; - - /* Now ship it down */ - - wavefront_send_sample (samp, - (unsigned short __user *) &(addr)[sizeof_patch], - (guspatch.mode & WAVE_UNSIGNED) ? 1:0); - wavefront_send_patch (pat); - wavefront_send_program (prog); - - /* Now pan as best we can ... use the slave/internal MIDI device - number if it exists (since it talks to the WaveFront), or the - master otherwise. - */ - - if (dev.mididev > 0) { - midi_synth_controller (dev.mididev, guspatch.instr_no, 10, - ((guspatch.panning << 4) > 127) ? - 127 : (guspatch.panning << 4)); - } - rc = 0; - -free_fail: - kfree(samp); - return rc; -} - -static int -wavefront_load_patch (const char __user *addr) - - -{ - wavefront_patch_info header; - - if (copy_from_user (&header, addr, sizeof(wavefront_patch_info) - - sizeof(wavefront_any))) { - printk (KERN_WARNING LOGNAME "bad address for load patch.\n"); - return -EFAULT; - } - - DPRINT (WF_DEBUG_LOAD_PATCH, "download " - "Sample type: %d " - "Sample number: %d " - "Sample size: %d\n", - header.subkey, - header.number, - header.size); - - switch (header.subkey) { - case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */ - - if (copy_from_user((unsigned char *) &header.hdr.s, - (unsigned char __user *) header.hdrptr, - sizeof (wavefront_sample))) - return -EFAULT; - - return wavefront_send_sample (&header, header.dataptr, 0); - - case WF_ST_MULTISAMPLE: - - if (copy_from_user(&header.hdr.s, header.hdrptr, - sizeof(wavefront_multisample))) - return -EFAULT; - - return wavefront_send_multisample (&header); - - - case WF_ST_ALIAS: - - if (copy_from_user(&header.hdr.a, header.hdrptr, - sizeof (wavefront_alias))) - return -EFAULT; - - return wavefront_send_alias (&header); - - case WF_ST_DRUM: - if (copy_from_user(&header.hdr.d, header.hdrptr, - sizeof (wavefront_drum))) - return -EFAULT; - - return wavefront_send_drum (&header); - - case WF_ST_PATCH: - if (copy_from_user(&header.hdr.p, header.hdrptr, - sizeof (wavefront_patch))) - return -EFAULT; - - return wavefront_send_patch (&header); - - case WF_ST_PROGRAM: - if (copy_from_user(&header.hdr.pr, header.hdrptr, - sizeof (wavefront_program))) - return -EFAULT; - - return wavefront_send_program (&header); - - default: - printk (KERN_ERR LOGNAME "unknown patch type %d.\n", - header.subkey); - return -(EINVAL); - } - - return 0; -} - -/*********************************************************************** -WaveFront: /dev/sequencer{,2} and other hardware-dependent interfaces -***********************************************************************/ - -static void -process_sample_hdr (UCHAR8 *buf) - -{ - wavefront_sample s; - UCHAR8 *ptr; - - ptr = buf; - - /* The board doesn't send us an exact copy of a "wavefront_sample" - in response to an Upload Sample Header command. Instead, we - have to convert the data format back into our data structure, - just as in the Download Sample command, where we have to do - something very similar in the reverse direction. - */ - - *((UINT32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4; - *((UINT32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4; - *((UINT32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4; - *((UINT32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4; - *((UINT32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3; - - s.SampleResolution = *ptr & 0x3; - s.Loop = *ptr & 0x8; - s.Bidirectional = *ptr & 0x10; - s.Reverse = *ptr & 0x40; - - /* Now copy it back to where it came from */ - - memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample)); -} - -static int -wavefront_synth_control (int cmd, wavefront_control *wc) - -{ - unsigned char patchnumbuf[2]; - int i; - - DPRINT (WF_DEBUG_CMD, "synth control with " - "cmd 0x%x\n", wc->cmd); - - /* Pre-handling of or for various commands */ - - switch (wc->cmd) { - case WFC_DISABLE_INTERRUPTS: - printk (KERN_INFO LOGNAME "interrupts disabled.\n"); - outb (0x80|0x20, dev.control_port); - dev.interrupts_on = 0; - return 0; - - case WFC_ENABLE_INTERRUPTS: - printk (KERN_INFO LOGNAME "interrupts enabled.\n"); - outb (0x80|0x40|0x20, dev.control_port); - dev.interrupts_on = 1; - return 0; - - case WFC_INTERRUPT_STATUS: - wc->rbuf[0] = dev.interrupts_on; - return 0; - - case WFC_ROMSAMPLES_RDONLY: - dev.rom_samples_rdonly = wc->wbuf[0]; - wc->status = 0; - return 0; - - case WFC_IDENTIFY_SLOT_TYPE: - i = wc->wbuf[0] | (wc->wbuf[1] << 7); - if (i <0 || i >= WF_MAX_SAMPLE) { - printk (KERN_WARNING LOGNAME "invalid slot ID %d\n", - i); - wc->status = EINVAL; - return 0; - } - wc->rbuf[0] = dev.sample_status[i]; - wc->status = 0; - return 0; - - case WFC_DEBUG_DRIVER: - dev.debug = wc->wbuf[0]; - printk (KERN_INFO LOGNAME "debug = 0x%x\n", dev.debug); - return 0; - - case WFC_FX_IOCTL: - wffx_ioctl ((wavefront_fx_info *) &wc->wbuf[0]); - return 0; - - case WFC_UPLOAD_PATCH: - munge_int32 (*((UINT32 *) wc->wbuf), patchnumbuf, 2); - memcpy (wc->wbuf, patchnumbuf, 2); - break; - - case WFC_UPLOAD_MULTISAMPLE: - /* multisamples have to be handled differently, and - cannot be dealt with properly by wavefront_cmd() alone. - */ - wc->status = wavefront_fetch_multisample - ((wavefront_patch_info *) wc->rbuf); - return 0; - - case WFC_UPLOAD_SAMPLE_ALIAS: - printk (KERN_INFO LOGNAME "support for sample alias upload " - "being considered.\n"); - wc->status = EINVAL; - return -EINVAL; - } - - wc->status = wavefront_cmd (wc->cmd, wc->rbuf, wc->wbuf); - - /* Post-handling of certain commands. - - In particular, if the command was an upload, demunge the data - so that the user-level doesn't have to think about it. - */ - - if (wc->status == 0) { - switch (wc->cmd) { - /* intercept any freemem requests so that we know - we are always current with the user-level view - of things. - */ - - case WFC_REPORT_FREE_MEMORY: - dev.freemem = demunge_int32 (wc->rbuf, 4); - break; - - case WFC_UPLOAD_PATCH: - demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES); - break; - - case WFC_UPLOAD_PROGRAM: - demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES); - break; - - case WFC_UPLOAD_EDRUM_PROGRAM: - demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1); - break; - - case WFC_UPLOAD_SAMPLE_HEADER: - process_sample_hdr (wc->rbuf); - break; - - case WFC_UPLOAD_SAMPLE_ALIAS: - printk (KERN_INFO LOGNAME "support for " - "sample aliases still " - "being considered.\n"); - break; - - case WFC_VMIDI_OFF: - if (virtual_midi_disable () < 0) { - return -(EIO); - } - break; - - case WFC_VMIDI_ON: - if (virtual_midi_enable () < 0) { - return -(EIO); - } - break; - } - } - - return 0; -} - - -/***********************************************************************/ -/* WaveFront: Linux file system interface (for access via raw synth) */ -/***********************************************************************/ - -static int -wavefront_open (struct inode *inode, struct file *file) -{ - /* XXX fix me */ - dev.opened = file->f_flags; - return 0; -} - -static int -wavefront_release(struct inode *inode, struct file *file) -{ - lock_kernel(); - dev.opened = 0; - dev.debug = 0; - unlock_kernel(); - return 0; -} - -static int -wavefront_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - wavefront_control wc; - int err; - - switch (cmd) { - - case WFCTL_WFCMD: - if (copy_from_user(&wc, (void __user *) arg, sizeof (wc))) - return -EFAULT; - - if ((err = wavefront_synth_control (cmd, &wc)) == 0) { - if (copy_to_user ((void __user *) arg, &wc, sizeof (wc))) - return -EFAULT; - } - - return err; - - case WFCTL_LOAD_SPP: - return wavefront_load_patch ((const char __user *) arg); - - default: - printk (KERN_WARNING LOGNAME "invalid ioctl %#x\n", cmd); - return -(EINVAL); - - } - return 0; -} - -static /*const*/ struct file_operations wavefront_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = wavefront_ioctl, - .open = wavefront_open, - .release = wavefront_release, -}; - - -/***********************************************************************/ -/* WaveFront: OSS installation and support interface */ -/***********************************************************************/ - -#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ - -static struct synth_info wavefront_info = -{"Turtle Beach WaveFront", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_WAVEFRONT, - 0, 32, 0, 0, SYNTH_CAP_INPUT}; - -static int -wavefront_oss_open (int devno, int mode) - -{ - dev.opened = mode; - return 0; -} - -static void -wavefront_oss_close (int devno) - -{ - dev.opened = 0; - dev.debug = 0; - return; -} - -static int -wavefront_oss_ioctl (int devno, unsigned int cmd, void __user * arg) - -{ - wavefront_control wc; - int err; - - switch (cmd) { - case SNDCTL_SYNTH_INFO: - if(copy_to_user(arg, &wavefront_info, sizeof (wavefront_info))) - return -EFAULT; - return 0; - - case SNDCTL_SEQ_RESETSAMPLES: -// printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n"); - return 0; /* don't force an error */ - - case SNDCTL_SEQ_PERCMODE: - return 0; /* don't force an error */ - - case SNDCTL_SYNTH_MEMAVL: - if ((dev.freemem = wavefront_freemem ()) < 0) { - printk (KERN_ERR LOGNAME "cannot get memory size\n"); - return -EIO; - } else { - return dev.freemem; - } - break; - - case SNDCTL_SYNTH_CONTROL: - if(copy_from_user (&wc, arg, sizeof (wc))) - err = -EFAULT; - else if ((err = wavefront_synth_control (cmd, &wc)) == 0) { - if(copy_to_user (arg, &wc, sizeof (wc))) - err = -EFAULT; - } - - return err; - - default: - return -(EINVAL); - } -} - -static int -wavefront_oss_load_patch (int devno, int format, const char __user *addr, - int offs, int count, int pmgr_flag) -{ - - if (format == SYSEX_PATCH) { /* Handled by midi_synth.c */ - if (midi_load_patch == NULL) { - printk (KERN_ERR LOGNAME - "SYSEX not loadable: " - "no midi patch loader!\n"); - return -(EINVAL); - } - - return midi_load_patch (devno, format, addr, - offs, count, pmgr_flag); - - } else if (format == GUS_PATCH) { - return wavefront_load_gus_patch (devno, format, - addr, offs, count, pmgr_flag); - - } else if (format != WAVEFRONT_PATCH) { - printk (KERN_ERR LOGNAME "unknown patch format %d\n", format); - return -(EINVAL); - } - - if (count < sizeof (wavefront_patch_info)) { - printk (KERN_ERR LOGNAME "sample header too short\n"); - return -(EINVAL); - } - - /* "addr" points to a user-space wavefront_patch_info */ - - return wavefront_load_patch (addr); -} - -static struct synth_operations wavefront_operations = -{ - .owner = THIS_MODULE, - .id = "WaveFront", - .info = &wavefront_info, - .midi_dev = 0, - .synth_type = SYNTH_TYPE_SAMPLE, - .synth_subtype = SAMPLE_TYPE_WAVEFRONT, - .open = wavefront_oss_open, - .close = wavefront_oss_close, - .ioctl = wavefront_oss_ioctl, - .kill_note = midi_synth_kill_note, - .start_note = midi_synth_start_note, - .set_instr = midi_synth_set_instr, - .reset = midi_synth_reset, - .load_patch = midi_synth_load_patch, - .aftertouch = midi_synth_aftertouch, - .controller = midi_synth_controller, - .panning = midi_synth_panning, - .bender = midi_synth_bender, - .setup_voice = midi_synth_setup_voice -}; -#endif /* OSS_SUPPORT_SEQ */ - -#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALL - -static void __init attach_wavefront (struct address_info *hw_config) -{ - (void) install_wavefront (); -} - -static int __init probe_wavefront (struct address_info *hw_config) -{ - return !detect_wavefront (hw_config->irq, hw_config->io_base); -} - -static void __exit unload_wavefront (struct address_info *hw_config) -{ - (void) uninstall_wavefront (); -} - -#endif /* OSS_SUPPORT_STATIC_INSTALL */ - -/***********************************************************************/ -/* WaveFront: Linux modular sound kernel installation interface */ -/***********************************************************************/ - -static irqreturn_t -wavefrontintr(int irq, void *dev_id, struct pt_regs *dummy) -{ - struct wf_config *hw = dev_id; - - /* - Some comments on interrupts. I attempted a version of this - driver that used interrupts throughout the code instead of - doing busy and/or sleep-waiting. Alas, it appears that once - the Motorola firmware is downloaded, the card *never* - generates an RX interrupt. These are successfully generated - during firmware loading, and after that wavefront_status() - reports that an interrupt is pending on the card from time - to time, but it never seems to be delivered to this - driver. Note also that wavefront_status() continues to - report that RX interrupts are enabled, suggesting that I - didn't goof up and disable them by mistake. - - Thus, I stepped back to a prior version of - wavefront_wait(), the only place where this really - matters. Its sad, but I've looked through the code to check - on things, and I really feel certain that the Motorola - firmware prevents RX-ready interrupts. - */ - - if ((wavefront_status() & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) { - return IRQ_NONE; - } - - hw->irq_ok = 1; - hw->irq_cnt++; - wake_up_interruptible (&hw->interrupt_sleeper); - return IRQ_HANDLED; -} - -/* STATUS REGISTER - -0 Host Rx Interrupt Enable (1=Enabled) -1 Host Rx Register Full (1=Full) -2 Host Rx Interrupt Pending (1=Interrupt) -3 Unused -4 Host Tx Interrupt (1=Enabled) -5 Host Tx Register empty (1=Empty) -6 Host Tx Interrupt Pending (1=Interrupt) -7 Unused -*/ - -static int -wavefront_interrupt_bits (int irq) - -{ - int bits; - - switch (irq) { - case 9: - bits = 0x00; - break; - case 5: - bits = 0x08; - break; - case 12: - bits = 0x10; - break; - case 15: - bits = 0x18; - break; - - default: - printk (KERN_WARNING LOGNAME "invalid IRQ %d\n", irq); - bits = -1; - } - - return bits; -} - -static void -wavefront_should_cause_interrupt (int val, int port, int timeout) - -{ - unsigned long flags; - - /* this will not help on SMP - but at least it compiles */ - spin_lock_irqsave(&lock, flags); - dev.irq_ok = 0; - outb (val,port); - interruptible_sleep_on_timeout (&dev.interrupt_sleeper, timeout); - spin_unlock_irqrestore(&lock,flags); -} - -static int __init wavefront_hw_reset (void) -{ - int bits; - int hwv[2]; - unsigned long irq_mask; - short reported_irq; - - /* IRQ already checked in init_module() */ - - bits = wavefront_interrupt_bits (dev.irq); - - printk (KERN_DEBUG LOGNAME "autodetecting WaveFront IRQ\n"); - - irq_mask = probe_irq_on (); - - outb (0x0, dev.control_port); - outb (0x80 | 0x40 | bits, dev.data_port); - wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1, - dev.control_port, - (reset_time*HZ)/100); - - reported_irq = probe_irq_off (irq_mask); - - if (reported_irq != dev.irq) { - if (reported_irq == 0) { - printk (KERN_ERR LOGNAME - "No unassigned interrupts detected " - "after h/w reset\n"); - } else if (reported_irq < 0) { - printk (KERN_ERR LOGNAME - "Multiple unassigned interrupts detected " - "after h/w reset\n"); - } else { - printk (KERN_ERR LOGNAME "autodetected IRQ %d not the " - "value provided (%d)\n", reported_irq, - dev.irq); - } - dev.irq = -1; - return 1; - } else { - printk (KERN_INFO LOGNAME "autodetected IRQ at %d\n", - reported_irq); - } - - if (request_irq (dev.irq, wavefrontintr, - IRQF_DISABLED|IRQF_SHARED, - "wavefront synth", &dev) < 0) { - printk (KERN_WARNING LOGNAME "IRQ %d not available!\n", - dev.irq); - return 1; - } - - /* try reset of port */ - - outb (0x0, dev.control_port); - - /* At this point, the board is in reset, and the H/W initialization - register is accessed at the same address as the data port. - - Bit 7 - Enable IRQ Driver - 0 - Tri-state the Wave-Board drivers for the PC Bus IRQs - 1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus. - - Bit 6 - MIDI Interface Select - - 0 - Use the MIDI Input from the 26-pin WaveBlaster - compatible header as the serial MIDI source - 1 - Use the MIDI Input from the 9-pin D connector as the - serial MIDI source. - - Bits 5:3 - IRQ Selection - 0 0 0 - IRQ 2/9 - 0 0 1 - IRQ 5 - 0 1 0 - IRQ 12 - 0 1 1 - IRQ 15 - 1 0 0 - Reserved - 1 0 1 - Reserved - 1 1 0 - Reserved - 1 1 1 - Reserved - - Bits 2:1 - Reserved - Bit 0 - Disable Boot ROM - 0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM - 1 - memory accesses to 03FC30-03FFFFH are directed to external - storage. - - */ - - /* configure hardware: IRQ, enable interrupts, - plus external 9-pin MIDI interface selected - */ - - outb (0x80 | 0x40 | bits, dev.data_port); - - /* CONTROL REGISTER - - 0 Host Rx Interrupt Enable (1=Enabled) 0x1 - 1 Unused 0x2 - 2 Unused 0x4 - 3 Unused 0x8 - 4 Host Tx Interrupt Enable 0x10 - 5 Mute (0=Mute; 1=Play) 0x20 - 6 Master Interrupt Enable (1=Enabled) 0x40 - 7 Master Reset (0=Reset; 1=Run) 0x80 - - Take us out of reset, mute output, master + TX + RX interrupts on. - - We'll get an interrupt presumably to tell us that the TX - register is clear. - */ - - wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1, - dev.control_port, - (reset_time*HZ)/100); - - /* Note: data port is now the data port, not the h/w initialization - port. - */ - - if (!dev.irq_ok) { - printk (KERN_WARNING LOGNAME - "intr not received after h/w un-reset.\n"); - goto gone_bad; - } - - dev.interrupts_on = 1; - - /* Note: data port is now the data port, not the h/w initialization - port. - - At this point, only "HW VERSION" or "DOWNLOAD OS" commands - will work. So, issue one of them, and wait for TX - interrupt. This can take a *long* time after a cold boot, - while the ISC ROM does its RAM test. The SDK says up to 4 - seconds - with 12MB of RAM on a Tropez+, it takes a lot - longer than that (~16secs). Note that the card understands - the difference between a warm and a cold boot, so - subsequent ISC2115 reboots (say, caused by module - reloading) will get through this much faster. - - XXX Interesting question: why is no RX interrupt received first ? - */ - - wavefront_should_cause_interrupt(WFC_HARDWARE_VERSION, - dev.data_port, ramcheck_time*HZ); - - if (!dev.irq_ok) { - printk (KERN_WARNING LOGNAME - "post-RAM-check interrupt not received.\n"); - goto gone_bad; - } - - if (!wavefront_wait (STAT_CAN_READ)) { - printk (KERN_WARNING LOGNAME - "no response to HW version cmd.\n"); - goto gone_bad; - } - - if ((hwv[0] = wavefront_read ()) == -1) { - printk (KERN_WARNING LOGNAME - "board not responding correctly.\n"); - goto gone_bad; - } - - if (hwv[0] == 0xFF) { /* NAK */ - - /* Board's RAM test failed. Try to read error code, - and tell us about it either way. - */ - - if ((hwv[0] = wavefront_read ()) == -1) { - printk (KERN_WARNING LOGNAME "on-board RAM test failed " - "(bad error code).\n"); - } else { - printk (KERN_WARNING LOGNAME "on-board RAM test failed " - "(error code: 0x%x).\n", - hwv[0]); - } - goto gone_bad; - } - - /* We're OK, just get the next byte of the HW version response */ - - if ((hwv[1] = wavefront_read ()) == -1) { - printk (KERN_WARNING LOGNAME "incorrect h/w response.\n"); - goto gone_bad; - } - - printk (KERN_INFO LOGNAME "hardware version %d.%d\n", - hwv[0], hwv[1]); - - return 0; - - - gone_bad: - if (dev.irq >= 0) { - free_irq (dev.irq, &dev); - dev.irq = -1; - } - return (1); -} - -static int __init detect_wavefront (int irq, int io_base) -{ - unsigned char rbuf[4], wbuf[4]; - - /* TB docs say the device takes up 8 ports, but we know that - if there is an FX device present (i.e. a Tropez+) it really - consumes 16. - */ - - if (!request_region (io_base, 16, "wavfront")) { - printk (KERN_ERR LOGNAME "IO address range 0x%x - 0x%x " - "already in use - ignored\n", dev.base, - dev.base+15); - return -1; - } - - dev.irq = irq; - dev.base = io_base; - dev.israw = 0; - dev.debug = debug_default; - dev.interrupts_on = 0; - dev.irq_cnt = 0; - dev.rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */ - - if (wavefront_cmd (WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) { - - dev.fw_version[0] = rbuf[0]; - dev.fw_version[1] = rbuf[1]; - printk (KERN_INFO LOGNAME - "firmware %d.%d already loaded.\n", - rbuf[0], rbuf[1]); - - /* check that a command actually works */ - - if (wavefront_cmd (WFC_HARDWARE_VERSION, - rbuf, wbuf) == 0) { - dev.hw_version[0] = rbuf[0]; - dev.hw_version[1] = rbuf[1]; - } else { - printk (KERN_WARNING LOGNAME "not raw, but no " - "hardware version!\n"); - release_region (io_base, 16); - return 0; - } - - if (!wf_raw) { - /* will re-acquire region in install_wavefront() */ - release_region (io_base, 16); - return 1; - } else { - printk (KERN_INFO LOGNAME - "reloading firmware anyway.\n"); - dev.israw = 1; - } - - } else { - - dev.israw = 1; - printk (KERN_INFO LOGNAME - "no response to firmware probe, assume raw.\n"); - - } - - init_waitqueue_head (&dev.interrupt_sleeper); - - if (wavefront_hw_reset ()) { - printk (KERN_WARNING LOGNAME "hardware reset failed\n"); - release_region (io_base, 16); - return 0; - } - - /* Check for FX device, present only on Tropez+ */ - - dev.has_fx = (detect_wffx () == 0); - - /* will re-acquire region in install_wavefront() */ - release_region (io_base, 16); - return 1; -} - -#include "os.h" -#include -#include -#include -#include - - -static int -wavefront_download_firmware (char *path) - -{ - unsigned char section[WF_SECTION_MAX]; - char section_length; /* yes, just a char; max value is WF_SECTION_MAX */ - int section_cnt_downloaded = 0; - int fd; - int c; - int i; - mm_segment_t fs; - - /* This tries to be a bit cleverer than the stuff Alan Cox did for - the generic sound firmware, in that it actually knows - something about the structure of the Motorola firmware. In - particular, it uses a version that has been stripped of the - 20K of useless header information, and had section lengths - added, making it possible to load the entire OS without any - [kv]malloc() activity, since the longest entity we ever read is - 42 bytes (well, WF_SECTION_MAX) long. - */ - - fs = get_fs(); - set_fs (get_ds()); - - if ((fd = sys_open (path, 0, 0)) < 0) { - printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n", - path); - return 1; - } - - while (1) { - int x; - - if ((x = sys_read (fd, §ion_length, sizeof (section_length))) != - sizeof (section_length)) { - printk (KERN_ERR LOGNAME "firmware read error.\n"); - goto failure; - } - - if (section_length == 0) { - break; - } - - if (sys_read (fd, section, section_length) != section_length) { - printk (KERN_ERR LOGNAME "firmware section " - "read error.\n"); - goto failure; - } - - /* Send command */ - - if (wavefront_write (WFC_DOWNLOAD_OS)) { - goto failure; - } - - for (i = 0; i < section_length; i++) { - if (wavefront_write (section[i])) { - goto failure; - } - } - - /* get ACK */ - - if (wavefront_wait (STAT_CAN_READ)) { - - if ((c = inb (dev.data_port)) != WF_ACK) { - - printk (KERN_ERR LOGNAME "download " - "of section #%d not " - "acknowledged, ack = 0x%x\n", - section_cnt_downloaded + 1, c); - goto failure; - - } - - } else { - printk (KERN_ERR LOGNAME "time out for firmware ACK.\n"); - goto failure; - } - - } - - sys_close (fd); - set_fs (fs); - return 0; - - failure: - sys_close (fd); - set_fs (fs); - printk (KERN_ERR "\nWaveFront: firmware download failed!!!\n"); - return 1; -} - -static int __init wavefront_config_midi (void) -{ - unsigned char rbuf[4], wbuf[4]; - - if (detect_wf_mpu (dev.irq, dev.base) < 0) { - printk (KERN_WARNING LOGNAME - "could not find working MIDI device\n"); - return -1; - } - - if ((dev.mididev = install_wf_mpu ()) < 0) { - printk (KERN_WARNING LOGNAME - "MIDI interfaces not configured\n"); - return -1; - } - - /* Route external MIDI to WaveFront synth (by default) */ - - if (wavefront_cmd (WFC_MISYNTH_ON, rbuf, wbuf)) { - printk (KERN_WARNING LOGNAME - "cannot enable MIDI-IN to synth routing.\n"); - /* XXX error ? */ - } - - -#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ - /* Get the regular MIDI patch loading function, so we can - use it if we ever get handed a SYSEX patch. This is - unlikely, because its so damn slow, but we may as well - leave this functionality from maui.c behind, since it - could be useful for sequencer applications that can - only use MIDI to do patch loading. - */ - - if (midi_devs[dev.mididev]->converter != NULL) { - midi_load_patch = midi_devs[dev.mididev]->converter->load_patch; - midi_devs[dev.mididev]->converter->load_patch = - &wavefront_oss_load_patch; - } - -#endif /* OSS_SUPPORT_SEQ */ - - /* Turn on Virtual MIDI, but first *always* turn it off, - since otherwise consectutive reloads of the driver will - never cause the hardware to generate the initial "internal" or - "external" source bytes in the MIDI data stream. This - is pretty important, since the internal hardware generally will - be used to generate none or very little MIDI output, and - thus the only source of MIDI data is actually external. Without - the switch bytes, the driver will think it all comes from - the internal interface. Duh. - */ - - if (wavefront_cmd (WFC_VMIDI_OFF, rbuf, wbuf)) { - printk (KERN_WARNING LOGNAME - "virtual MIDI mode not disabled\n"); - return 0; /* We're OK, but missing the external MIDI dev */ - } - - if ((dev.ext_mididev = virtual_midi_enable ()) < 0) { - printk (KERN_WARNING LOGNAME "no virtual MIDI access.\n"); - } else { - if (wavefront_cmd (WFC_VMIDI_ON, rbuf, wbuf)) { - printk (KERN_WARNING LOGNAME - "cannot enable virtual MIDI mode.\n"); - virtual_midi_disable (); - } - } - - return 0; -} - -static int __init wavefront_do_reset (int atboot) -{ - char voices[1]; - - if (!atboot && wavefront_hw_reset ()) { - printk (KERN_WARNING LOGNAME "hw reset failed.\n"); - goto gone_bad; - } - - if (dev.israw) { - if (wavefront_download_firmware (ospath)) { - goto gone_bad; - } - - dev.israw = 0; - - /* Wait for the OS to get running. The protocol for - this is non-obvious, and was determined by - using port-IO tracing in DOSemu and some - experimentation here. - - Rather than using timed waits, use interrupts creatively. - */ - - wavefront_should_cause_interrupt (WFC_NOOP, - dev.data_port, - (osrun_time*HZ)); - - if (!dev.irq_ok) { - printk (KERN_WARNING LOGNAME - "no post-OS interrupt.\n"); - goto gone_bad; - } - - /* Now, do it again ! */ - - wavefront_should_cause_interrupt (WFC_NOOP, - dev.data_port, (10*HZ)); - - if (!dev.irq_ok) { - printk (KERN_WARNING LOGNAME - "no post-OS interrupt(2).\n"); - goto gone_bad; - } - - /* OK, no (RX/TX) interrupts any more, but leave mute - in effect. - */ - - outb (0x80|0x40, dev.control_port); - - /* No need for the IRQ anymore */ - - free_irq (dev.irq, &dev); - - } - - if (dev.has_fx && fx_raw) { - wffx_init (); - } - - /* SETUPSND.EXE asks for sample memory config here, but since i - have no idea how to interpret the result, we'll forget - about it. - */ - - if ((dev.freemem = wavefront_freemem ()) < 0) { - goto gone_bad; - } - - printk (KERN_INFO LOGNAME "available DRAM %dk\n", dev.freemem / 1024); - - if (wavefront_write (0xf0) || - wavefront_write (1) || - (wavefront_read () < 0)) { - dev.debug = 0; - printk (KERN_WARNING LOGNAME "MPU emulation mode not set.\n"); - goto gone_bad; - } - - voices[0] = 32; - - if (wavefront_cmd (WFC_SET_NVOICES, NULL, voices)) { - printk (KERN_WARNING LOGNAME - "cannot set number of voices to 32.\n"); - goto gone_bad; - } - - - return 0; - - gone_bad: - /* reset that sucker so that it doesn't bother us. */ - - outb (0x0, dev.control_port); - dev.interrupts_on = 0; - if (dev.irq >= 0) { - free_irq (dev.irq, &dev); - } - return 1; -} - -static int __init wavefront_init (int atboot) -{ - int samples_are_from_rom; - - if (dev.israw) { - samples_are_from_rom = 1; - } else { - /* XXX is this always true ? */ - samples_are_from_rom = 0; - } - - if (dev.israw || fx_raw) { - if (wavefront_do_reset (atboot)) { - return -1; - } - } - - wavefront_get_sample_status (samples_are_from_rom); - wavefront_get_program_status (); - wavefront_get_patch_status (); - - /* Start normal operation: unreset, master interrupt enabled, no mute - */ - - outb (0x80|0x40|0x20, dev.control_port); - - return (0); -} - -static int __init install_wavefront (void) -{ - if (!request_region (dev.base+2, 6, "wavefront synth")) - return -1; - - if (dev.has_fx) { - if (!request_region (dev.base+8, 8, "wavefront fx")) { - release_region (dev.base+2, 6); - return -1; - } - } - - if ((dev.synth_dev = register_sound_synth (&wavefront_fops, -1)) < 0) { - printk (KERN_ERR LOGNAME "cannot register raw synth\n"); - goto err_out; - } - -#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ - if ((dev.oss_dev = sound_alloc_synthdev()) == -1) { - printk (KERN_ERR LOGNAME "Too many sequencers\n"); - /* FIXME: leak: should unregister sound synth */ - goto err_out; - } else { - synth_devs[dev.oss_dev] = &wavefront_operations; - } -#endif /* OSS_SUPPORT_SEQ */ - - if (wavefront_init (1) < 0) { - printk (KERN_WARNING LOGNAME "initialization failed.\n"); - -#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ - sound_unload_synthdev (dev.oss_dev); -#endif /* OSS_SUPPORT_SEQ */ - - goto err_out; - } - - if (wavefront_config_midi ()) { - printk (KERN_WARNING LOGNAME "could not initialize MIDI.\n"); - } - - return dev.oss_dev; - -err_out: - release_region (dev.base+2, 6); - if (dev.has_fx) - release_region (dev.base+8, 8); - return -1; -} - -static void __exit uninstall_wavefront (void) -{ - /* the first two i/o addresses are freed by the wf_mpu code */ - release_region (dev.base+2, 6); - - if (dev.has_fx) { - release_region (dev.base+8, 8); - } - - unregister_sound_synth (dev.synth_dev); - -#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ - sound_unload_synthdev (dev.oss_dev); -#endif /* OSS_SUPPORT_SEQ */ - uninstall_wf_mpu (); -} - -/***********************************************************************/ -/* WaveFront FX control */ -/***********************************************************************/ - -#include "yss225.h" - -/* Control bits for the Load Control Register - */ - -#define FX_LSB_TRANSFER 0x01 /* transfer after DSP LSB byte written */ -#define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */ -#define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */ - -static int -wffx_idle (void) - -{ - int i; - unsigned int x = 0x80; - - for (i = 0; i < 1000; i++) { - x = inb (dev.fx_status); - if ((x & 0x80) == 0) { - break; - } - } - - if (x & 0x80) { - printk (KERN_ERR LOGNAME "FX device never idle.\n"); - return 0; - } - - return (1); -} - -int __init detect_wffx (void) -{ - /* This is a crude check, but its the best one I have for now. - Certainly on the Maui and the Tropez, wffx_idle() will - report "never idle", which suggests that this test should - work OK. - */ - - if (inb (dev.fx_status) & 0x80) { - printk (KERN_INFO LOGNAME "Hmm, probably a Maui or Tropez.\n"); - return -1; - } - - return 0; -} - -static void -wffx_mute (int onoff) - -{ - if (!wffx_idle()) { - return; - } - - outb (onoff ? 0x02 : 0x00, dev.fx_op); -} - -static int -wffx_memset (int page, - int addr, int cnt, unsigned short *data) -{ - if (page < 0 || page > 7) { - printk (KERN_ERR LOGNAME "FX memset: " - "page must be >= 0 and <= 7\n"); - return -(EINVAL); - } - - if (addr < 0 || addr > 0x7f) { - printk (KERN_ERR LOGNAME "FX memset: " - "addr must be >= 0 and <= 7f\n"); - return -(EINVAL); - } - - if (cnt == 1) { - - outb (FX_LSB_TRANSFER, dev.fx_lcr); - outb (page, dev.fx_dsp_page); - outb (addr, dev.fx_dsp_addr); - outb ((data[0] >> 8), dev.fx_dsp_msb); - outb ((data[0] & 0xff), dev.fx_dsp_lsb); - - printk (KERN_INFO LOGNAME "FX: addr %d:%x set to 0x%x\n", - page, addr, data[0]); - - } else { - int i; - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (page, dev.fx_dsp_page); - outb (addr, dev.fx_dsp_addr); - - for (i = 0; i < cnt; i++) { - outb ((data[i] >> 8), dev.fx_dsp_msb); - outb ((data[i] & 0xff), dev.fx_dsp_lsb); - if (!wffx_idle ()) { - break; - } - } - - if (i != cnt) { - printk (KERN_WARNING LOGNAME - "FX memset " - "(0x%x, 0x%x, %p, %d) incomplete\n", - page, addr, data, cnt); - return -(EIO); - } - } - - return 0; -} - -static int -wffx_ioctl (wavefront_fx_info *r) - -{ - unsigned short page_data[256]; - unsigned short *pd; - - switch (r->request) { - case WFFX_MUTE: - wffx_mute (r->data[0]); - return 0; - - case WFFX_MEMSET: - - if (r->data[2] <= 0) { - printk (KERN_ERR LOGNAME "cannot write " - "<= 0 bytes to FX\n"); - return -(EINVAL); - } else if (r->data[2] == 1) { - pd = (unsigned short *) &r->data[3]; - } else { - if (r->data[2] > sizeof (page_data)) { - printk (KERN_ERR LOGNAME "cannot write " - "> 255 bytes to FX\n"); - return -(EINVAL); - } - if (copy_from_user(page_data, - (unsigned char __user *)r->data[3], - r->data[2])) - return -EFAULT; - pd = page_data; - } - - return wffx_memset (r->data[0], /* page */ - r->data[1], /* addr */ - r->data[2], /* cnt */ - pd); - - default: - printk (KERN_WARNING LOGNAME - "FX: ioctl %d not yet supported\n", - r->request); - return -(EINVAL); - } -} - -/* YSS225 initialization. - - This code was developed using DOSEMU. The Turtle Beach SETUPSND - utility was run with I/O tracing in DOSEMU enabled, and a reconstruction - of the port I/O done, using the Yamaha faxback document as a guide - to add more logic to the code. Its really pretty weird. - - There was an alternative approach of just dumping the whole I/O - sequence as a series of port/value pairs and a simple loop - that output it. However, I hope that eventually I'll get more - control over what this code does, and so I tried to stick with - a somewhat "algorithmic" approach. -*/ - -static int __init wffx_init (void) -{ - int i; - int j; - - /* Set all bits for all channels on the MOD unit to zero */ - /* XXX But why do this twice ? */ - - for (j = 0; j < 2; j++) { - for (i = 0x10; i <= 0xff; i++) { - - if (!wffx_idle ()) { - return (-1); - } - - outb (i, dev.fx_mod_addr); - outb (0x0, dev.fx_mod_data); - } - } - - if (!wffx_idle()) return (-1); - outb (0x02, dev.fx_op); /* mute on */ - - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x44, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x42, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x43, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x7c, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x7e, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x46, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x49, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x47, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x4a, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - - /* either because of stupidity by TB's programmers, or because it - actually does something, rezero the MOD page. - */ - for (i = 0x10; i <= 0xff; i++) { - - if (!wffx_idle ()) { - return (-1); - } - - outb (i, dev.fx_mod_addr); - outb (0x0, dev.fx_mod_data); - } - /* load page zero */ - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x00, dev.fx_dsp_page); - outb (0x00, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_zero); i += 2) { - outb (page_zero[i], dev.fx_dsp_msb); - outb (page_zero[i+1], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - /* Now load page one */ - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x01, dev.fx_dsp_page); - outb (0x00, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_one); i += 2) { - outb (page_one[i], dev.fx_dsp_msb); - outb (page_one[i+1], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x02, dev.fx_dsp_page); - outb (0x00, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_two); i++) { - outb (page_two[i], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x03, dev.fx_dsp_page); - outb (0x00, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_three); i++) { - outb (page_three[i], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x04, dev.fx_dsp_page); - outb (0x00, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_four); i++) { - outb (page_four[i], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - /* Load memory area (page six) */ - - outb (FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x06, dev.fx_dsp_page); - - for (i = 0; i < sizeof (page_six); i += 3) { - outb (page_six[i], dev.fx_dsp_addr); - outb (page_six[i+1], dev.fx_dsp_msb); - outb (page_six[i+2], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x07, dev.fx_dsp_page); - outb (0x00, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_seven); i += 2) { - outb (page_seven[i], dev.fx_dsp_msb); - outb (page_seven[i+1], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - /* Now setup the MOD area. We do this algorithmically in order to - save a little data space. It could be done in the same fashion - as the "pages". - */ - - for (i = 0x00; i <= 0x0f; i++) { - outb (0x01, dev.fx_mod_addr); - outb (i, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - outb (0x02, dev.fx_mod_addr); - outb (0x00, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - for (i = 0xb0; i <= 0xbf; i++) { - outb (i, dev.fx_mod_addr); - outb (0x20, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - for (i = 0xf0; i <= 0xff; i++) { - outb (i, dev.fx_mod_addr); - outb (0x20, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - for (i = 0x10; i <= 0x1d; i++) { - outb (i, dev.fx_mod_addr); - outb (0xff, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - outb (0x1e, dev.fx_mod_addr); - outb (0x40, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - - for (i = 0x1f; i <= 0x2d; i++) { - outb (i, dev.fx_mod_addr); - outb (0xff, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - outb (0x2e, dev.fx_mod_addr); - outb (0x00, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - - for (i = 0x2f; i <= 0x3e; i++) { - outb (i, dev.fx_mod_addr); - outb (0x00, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - outb (0x3f, dev.fx_mod_addr); - outb (0x20, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - - for (i = 0x40; i <= 0x4d; i++) { - outb (i, dev.fx_mod_addr); - outb (0x00, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - outb (0x4e, dev.fx_mod_addr); - outb (0x0e, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - outb (0x4f, dev.fx_mod_addr); - outb (0x0e, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - - - for (i = 0x50; i <= 0x6b; i++) { - outb (i, dev.fx_mod_addr); - outb (0x00, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - outb (0x6c, dev.fx_mod_addr); - outb (0x40, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - - outb (0x6d, dev.fx_mod_addr); - outb (0x00, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - - outb (0x6e, dev.fx_mod_addr); - outb (0x40, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - - outb (0x6f, dev.fx_mod_addr); - outb (0x40, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - - for (i = 0x70; i <= 0x7f; i++) { - outb (i, dev.fx_mod_addr); - outb (0xc0, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - for (i = 0x80; i <= 0xaf; i++) { - outb (i, dev.fx_mod_addr); - outb (0x00, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - for (i = 0xc0; i <= 0xdd; i++) { - outb (i, dev.fx_mod_addr); - outb (0x00, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - outb (0xde, dev.fx_mod_addr); - outb (0x10, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - outb (0xdf, dev.fx_mod_addr); - outb (0x10, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - - for (i = 0xe0; i <= 0xef; i++) { - outb (i, dev.fx_mod_addr); - outb (0x00, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - for (i = 0x00; i <= 0x0f; i++) { - outb (0x01, dev.fx_mod_addr); - outb (i, dev.fx_mod_data); - outb (0x02, dev.fx_mod_addr); - outb (0x01, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - outb (0x02, dev.fx_op); /* mute on */ - - /* Now set the coefficients and so forth for the programs above */ - - for (i = 0; i < sizeof (coefficients); i += 4) { - outb (coefficients[i], dev.fx_dsp_page); - outb (coefficients[i+1], dev.fx_dsp_addr); - outb (coefficients[i+2], dev.fx_dsp_msb); - outb (coefficients[i+3], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - /* Some settings (?) that are too small to bundle into loops */ - - if (!wffx_idle()) return (-1); - outb (0x1e, dev.fx_mod_addr); - outb (0x14, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - outb (0xde, dev.fx_mod_addr); - outb (0x20, dev.fx_mod_data); - if (!wffx_idle()) return (-1); - outb (0xdf, dev.fx_mod_addr); - outb (0x20, dev.fx_mod_data); - - /* some more coefficients */ - - if (!wffx_idle()) return (-1); - outb (0x06, dev.fx_dsp_page); - outb (0x78, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x40, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x03, dev.fx_dsp_addr); - outb (0x0f, dev.fx_dsp_msb); - outb (0xff, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x0b, dev.fx_dsp_addr); - outb (0x0f, dev.fx_dsp_msb); - outb (0xff, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x02, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x0a, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x46, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - outb (0x07, dev.fx_dsp_page); - outb (0x49, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - - /* Now, for some strange reason, lets reload every page - and all the coefficients over again. I have *NO* idea - why this is done. I do know that no sound is produced - is this phase is omitted. - */ - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x00, dev.fx_dsp_page); - outb (0x10, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_zero_v2); i += 2) { - outb (page_zero_v2[i], dev.fx_dsp_msb); - outb (page_zero_v2[i+1], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x01, dev.fx_dsp_page); - outb (0x10, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_one_v2); i += 2) { - outb (page_one_v2[i], dev.fx_dsp_msb); - outb (page_one_v2[i+1], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - if (!wffx_idle()) return (-1); - if (!wffx_idle()) return (-1); - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x02, dev.fx_dsp_page); - outb (0x10, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_two_v2); i++) { - outb (page_two_v2[i], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x03, dev.fx_dsp_page); - outb (0x10, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_three_v2); i++) { - outb (page_three_v2[i], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x04, dev.fx_dsp_page); - outb (0x10, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_four_v2); i++) { - outb (page_four_v2[i], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - outb (FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x06, dev.fx_dsp_page); - - /* Page six v.2 is algorithmic */ - - for (i = 0x10; i <= 0x3e; i += 2) { - outb (i, dev.fx_dsp_addr); - outb (0x00, dev.fx_dsp_msb); - outb (0x00, dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); - outb (0x07, dev.fx_dsp_page); - outb (0x10, dev.fx_dsp_addr); - - for (i = 0; i < sizeof (page_seven_v2); i += 2) { - outb (page_seven_v2[i], dev.fx_dsp_msb); - outb (page_seven_v2[i+1], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - for (i = 0x00; i < sizeof(mod_v2); i += 2) { - outb (mod_v2[i], dev.fx_mod_addr); - outb (mod_v2[i+1], dev.fx_mod_data); - if (!wffx_idle()) return (-1); - } - - for (i = 0; i < sizeof (coefficients2); i += 4) { - outb (coefficients2[i], dev.fx_dsp_page); - outb (coefficients2[i+1], dev.fx_dsp_addr); - outb (coefficients2[i+2], dev.fx_dsp_msb); - outb (coefficients2[i+3], dev.fx_dsp_lsb); - if (!wffx_idle()) return (-1); - } - - for (i = 0; i < sizeof (coefficients3); i += 2) { - int x; - - outb (0x07, dev.fx_dsp_page); - x = (i % 4) ? 0x4e : 0x4c; - outb (x, dev.fx_dsp_addr); - outb (coefficients3[i], dev.fx_dsp_msb); - outb (coefficients3[i+1], dev.fx_dsp_lsb); - } - - outb (0x00, dev.fx_op); /* mute off */ - if (!wffx_idle()) return (-1); - - return (0); -} - -static int io = -1; -static int irq = -1; - -MODULE_AUTHOR ("Paul Barton-Davis "); -MODULE_DESCRIPTION ("Turtle Beach WaveFront Linux Driver"); -MODULE_LICENSE("GPL"); -module_param (io, int, 0); -module_param (irq, int, 0); - -static int __init init_wavfront (void) -{ - printk ("Turtle Beach WaveFront Driver\n" - "Copyright (C) by Hannu Solvainen, " - "Paul Barton-Davis 1993-1998.\n"); - - /* XXX t'would be lovely to ask the CS4232 for these values, eh ? */ - - if (io == -1 || irq == -1) { - printk (KERN_INFO LOGNAME "irq and io options must be set.\n"); - return -EINVAL; - } - - if (wavefront_interrupt_bits (irq) < 0) { - printk (KERN_INFO LOGNAME - "IRQ must be 9, 5, 12 or 15 (not %d)\n", irq); - return -ENODEV; - } - - if (detect_wavefront (irq, io) < 0) { - return -ENODEV; - } - - if (install_wavefront () < 0) { - return -EIO; - } - - return 0; -} - -static void __exit cleanup_wavfront (void) -{ - uninstall_wavefront (); -} - -module_init(init_wavfront); -module_exit(cleanup_wavfront); diff --git a/sound/oss/wf_midi.c b/sound/oss/wf_midi.c deleted file mode 100644 index 75c0c143a759..000000000000 --- a/sound/oss/wf_midi.c +++ /dev/null @@ -1,880 +0,0 @@ -/* - * sound/oss/wf_midi.c - * - * The low level driver for the WaveFront ICS2115 MIDI interface(s) - * Note that there is also an MPU-401 emulation (actually, a UART-401 - * emulation) on the CS4232 on the Tropez Plus. This code has nothing - * to do with that interface at all. - * - * The interface is essentially just a UART-401, but is has the - * interesting property of supporting what Turtle Beach called - * "Virtual MIDI" mode. In this mode, there are effectively *two* - * MIDI buses accessible via the interface, one that is routed - * solely to/from the external WaveFront synthesizer and the other - * corresponding to the pin/socket connector used to link external - * MIDI devices to the board. - * - * This driver fully supports this mode, allowing two distinct - * midi devices (/dev/midiNN and /dev/midiNN+1) to be used - * completely independently, giving 32 channels of MIDI routing, - * 16 to the WaveFront synth and 16 to the external MIDI bus. - * - * Switching between the two is accomplished externally by the driver - * using the two otherwise unused MIDI bytes. See the code for more details. - * - * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see wavefront.c) - * - * The main reason to turn off Virtual MIDI mode is when you want to - * tightly couple the WaveFront synth with an external MIDI - * device. You won't be able to distinguish the source of any MIDI - * data except via SysEx ID, but thats probably OK, since for the most - * part, the WaveFront won't be sending any MIDI data at all. - * - * The main reason to turn on Virtual MIDI Mode is to provide two - * completely independent 16-channel MIDI buses, one to the - * WaveFront and one to any external MIDI devices. Given the 32 - * voice nature of the WaveFront, its pretty easy to find a use - * for all 16 channels driving just that synth. - * - */ - -/* - * Copyright (C) by Paul Barton-Davis 1998 - * Some portions of this file are derived from work that is: - * - * CopyriGht (C) by Hannu Savolainen 1993-1996 - * - * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - -#include -#include -#include -#include "sound_config.h" - -#include - -#ifdef MODULE - -struct wf_mpu_config { - int base; -#define DATAPORT(d) (d)->base -#define COMDPORT(d) (d)->base+1 -#define STATPORT(d) (d)->base+1 - - int irq; - int opened; - int devno; - int synthno; - int mode; -#define MODE_MIDI 1 -#define MODE_SYNTH 2 - - void (*inputintr) (int dev, unsigned char data); - char isvirtual; /* do virtual I/O stuff */ -}; - -static struct wf_mpu_config devs[2]; -static struct wf_mpu_config *phys_dev = &devs[0]; -static struct wf_mpu_config *virt_dev = &devs[1]; - -static void start_uart_mode (void); -static DEFINE_SPINLOCK(lock); - -#define OUTPUT_READY 0x40 -#define INPUT_AVAIL 0x80 -#define MPU_ACK 0xFE -#define UART_MODE_ON 0x3F - -static inline int wf_mpu_status (void) -{ - return inb (STATPORT (phys_dev)); -} - -static inline int input_avail (void) -{ - return !(wf_mpu_status() & INPUT_AVAIL); -} - -static inline int output_ready (void) -{ - return !(wf_mpu_status() & OUTPUT_READY); -} - -static inline int read_data (void) -{ - return inb (DATAPORT (phys_dev)); -} - -static inline void write_data (unsigned char byte) -{ - outb (byte, DATAPORT (phys_dev)); -} - -/* - * States for the input scanner (should be in dev_table.h) - */ - -#define MST_SYSMSG 100 /* System message (sysx etc). */ -#define MST_MTC 102 /* Midi Time Code (MTC) qframe msg */ -#define MST_SONGSEL 103 /* Song select */ -#define MST_SONGPOS 104 /* Song position pointer */ -#define MST_TIMED 105 /* Leading timing byte rcvd */ - -/* buffer space check for input scanner */ - -#define BUFTEST(mi) if (mi->m_ptr >= MI_MAX || mi->m_ptr < 0) \ -{printk(KERN_ERR "WF-MPU: Invalid buffer pointer %d/%d, s=%d\n", \ - mi->m_ptr, mi->m_left, mi->m_state);mi->m_ptr--;} - -static unsigned char len_tab[] = /* # of data bytes following a status - */ -{ - 2, /* 8x */ - 2, /* 9x */ - 2, /* Ax */ - 2, /* Bx */ - 1, /* Cx */ - 1, /* Dx */ - 2, /* Ex */ - 0 /* Fx */ -}; - -static int -wf_mpu_input_scanner (int devno, int synthdev, unsigned char midic) - -{ - struct midi_input_info *mi = &midi_devs[devno]->in_info; - - switch (mi->m_state) { - case MST_INIT: - switch (midic) { - case 0xf8: - /* Timer overflow */ - break; - - case 0xfc: - break; - - case 0xfd: - /* XXX do something useful with this. If there is - an external MIDI timer (e.g. a hardware sequencer, - a useful timer can be derived ... - - For now, no timer support. - */ - break; - - case 0xfe: - return MPU_ACK; - break; - - case 0xf0: - case 0xf1: - case 0xf2: - case 0xf3: - case 0xf4: - case 0xf5: - case 0xf6: - case 0xf7: - break; - - case 0xf9: - break; - - case 0xff: - mi->m_state = MST_SYSMSG; - break; - - default: - if (midic <= 0xef) { - mi->m_state = MST_TIMED; - } - else - printk (KERN_ERR " ", - midic); - } - break; - - case MST_TIMED: - { - int msg = ((int) (midic & 0xf0) >> 4); - - mi->m_state = MST_DATA; - - if (msg < 8) { /* Data byte */ - - msg = ((int) (mi->m_prev_status & 0xf0) >> 4); - msg -= 8; - mi->m_left = len_tab[msg] - 1; - - mi->m_ptr = 2; - mi->m_buf[0] = mi->m_prev_status; - mi->m_buf[1] = midic; - - if (mi->m_left <= 0) { - mi->m_state = MST_INIT; - do_midi_msg (synthdev, mi->m_buf, mi->m_ptr); - mi->m_ptr = 0; - } - } else if (msg == 0xf) { /* MPU MARK */ - - mi->m_state = MST_INIT; - - switch (midic) { - case 0xf8: - break; - - case 0xf9: - break; - - case 0xfc: - break; - - default: - break; - } - } else { - mi->m_prev_status = midic; - msg -= 8; - mi->m_left = len_tab[msg]; - - mi->m_ptr = 1; - mi->m_buf[0] = midic; - - if (mi->m_left <= 0) { - mi->m_state = MST_INIT; - do_midi_msg (synthdev, mi->m_buf, mi->m_ptr); - mi->m_ptr = 0; - } - } - } - break; - - case MST_SYSMSG: - switch (midic) { - case 0xf0: - mi->m_state = MST_SYSEX; - break; - - case 0xf1: - mi->m_state = MST_MTC; - break; - - case 0xf2: - mi->m_state = MST_SONGPOS; - mi->m_ptr = 0; - break; - - case 0xf3: - mi->m_state = MST_SONGSEL; - break; - - case 0xf6: - mi->m_state = MST_INIT; - - /* - * Real time messages - */ - case 0xf8: - /* midi clock */ - mi->m_state = MST_INIT; - /* XXX need ext MIDI timer support */ - break; - - case 0xfA: - mi->m_state = MST_INIT; - /* XXX need ext MIDI timer support */ - break; - - case 0xFB: - mi->m_state = MST_INIT; - /* XXX need ext MIDI timer support */ - break; - - case 0xFC: - mi->m_state = MST_INIT; - /* XXX need ext MIDI timer support */ - break; - - case 0xFE: - /* active sensing */ - mi->m_state = MST_INIT; - break; - - case 0xff: - mi->m_state = MST_INIT; - break; - - default: - printk (KERN_ERR "unknown MIDI sysmsg %0x\n", midic); - mi->m_state = MST_INIT; - } - break; - - case MST_MTC: - mi->m_state = MST_INIT; - break; - - case MST_SYSEX: - if (midic == 0xf7) { - mi->m_state = MST_INIT; - } else { - /* XXX fix me */ - } - break; - - case MST_SONGPOS: - BUFTEST (mi); - mi->m_buf[mi->m_ptr++] = midic; - if (mi->m_ptr == 2) { - mi->m_state = MST_INIT; - mi->m_ptr = 0; - /* XXX need ext MIDI timer support */ - } - break; - - case MST_DATA: - BUFTEST (mi); - mi->m_buf[mi->m_ptr++] = midic; - if ((--mi->m_left) <= 0) { - mi->m_state = MST_INIT; - do_midi_msg (synthdev, mi->m_buf, mi->m_ptr); - mi->m_ptr = 0; - } - break; - - default: - printk (KERN_ERR "Bad state %d ", mi->m_state); - mi->m_state = MST_INIT; - } - - return 1; -} - -static irqreturn_t -wf_mpuintr(int irq, void *dev_id, struct pt_regs *dummy) - -{ - struct wf_mpu_config *physical_dev = dev_id; - static struct wf_mpu_config *input_dev; - struct midi_input_info *mi = &midi_devs[physical_dev->devno]->in_info; - int n; - - if (!input_avail()) { /* not for us */ - return IRQ_NONE; - } - - if (mi->m_busy) - return IRQ_HANDLED; - spin_lock(&lock); - mi->m_busy = 1; - - if (!input_dev) { - input_dev = physical_dev; - } - - n = 50; /* XXX why ? */ - - do { - unsigned char c = read_data (); - - if (phys_dev->isvirtual) { - - if (c == WF_EXTERNAL_SWITCH) { - input_dev = virt_dev; - continue; - } else if (c == WF_INTERNAL_SWITCH) { - input_dev = phys_dev; - continue; - } /* else just leave it as it is */ - - } else { - input_dev = phys_dev; - } - - if (input_dev->mode == MODE_SYNTH) { - - wf_mpu_input_scanner (input_dev->devno, - input_dev->synthno, c); - - } else if (input_dev->opened & OPEN_READ) { - - if (input_dev->inputintr) { - input_dev->inputintr (input_dev->devno, c); - } - } - - } while (input_avail() && n-- > 0); - - mi->m_busy = 0; - spin_unlock(&lock); - return IRQ_HANDLED; -} - -static int -wf_mpu_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) - ) -{ - struct wf_mpu_config *devc; - - if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL) - return -(ENXIO); - - if (phys_dev->devno == dev) { - devc = phys_dev; - } else if (phys_dev->isvirtual && virt_dev->devno == dev) { - devc = virt_dev; - } else { - printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev); - return -(EINVAL); - } - - if (devc->opened) { - return -(EBUSY); - } - - devc->mode = MODE_MIDI; - devc->opened = mode; - devc->synthno = 0; - - devc->inputintr = input; - return 0; -} - -static void -wf_mpu_close (int dev) -{ - struct wf_mpu_config *devc; - - if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL) - return; - - if (phys_dev->devno == dev) { - devc = phys_dev; - } else if (phys_dev->isvirtual && virt_dev->devno == dev) { - devc = virt_dev; - } else { - printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev); - return; - } - - devc->mode = 0; - devc->inputintr = NULL; - devc->opened = 0; -} - -static int -wf_mpu_out (int dev, unsigned char midi_byte) -{ - int timeout; - unsigned long flags; - static int lastoutdev = -1; - unsigned char switchch; - - if (phys_dev->isvirtual && lastoutdev != dev) { - - if (dev == phys_dev->devno) { - switchch = WF_INTERNAL_SWITCH; - } else if (dev == virt_dev->devno) { - switchch = WF_EXTERNAL_SWITCH; - } else { - printk (KERN_ERR "WF-MPU: bad device number %d", dev); - return (0); - } - - /* XXX fix me */ - - for (timeout = 30000; timeout > 0 && !output_ready (); - timeout--); - - spin_lock_irqsave(&lock,flags); - - if (!output_ready ()) { - printk (KERN_WARNING "WF-MPU: Send switch " - "byte timeout\n"); - spin_unlock_irqrestore(&lock,flags); - return 0; - } - - write_data (switchch); - spin_unlock_irqrestore(&lock,flags); - } - - lastoutdev = dev; - - /* - * Sometimes it takes about 30000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - /* XXX fix me */ - - for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); - - spin_lock_irqsave(&lock,flags); - if (!output_ready ()) { - spin_unlock_irqrestore(&lock,flags); - printk (KERN_WARNING "WF-MPU: Send data timeout\n"); - return 0; - } - - write_data (midi_byte); - spin_unlock_irqrestore(&lock,flags); - - return 1; -} - -static inline int wf_mpu_start_read (int dev) { - return 0; -} - -static inline int wf_mpu_end_read (int dev) { - return 0; -} - -static int wf_mpu_ioctl (int dev, unsigned cmd, void __user *arg) -{ - printk (KERN_WARNING - "WF-MPU: Intelligent mode not supported by hardware.\n"); - return -(EINVAL); -} - -static int wf_mpu_buffer_status (int dev) -{ - return 0; -} - -static struct synth_operations wf_mpu_synth_operations[2]; -static struct midi_operations wf_mpu_midi_operations[2]; - -static struct midi_operations wf_mpu_midi_proto = -{ - .owner = THIS_MODULE, - .info = {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, - .in_info = {0}, /* in_info */ - .open = wf_mpu_open, - .close = wf_mpu_close, - .ioctl = wf_mpu_ioctl, - .outputc = wf_mpu_out, - .start_read = wf_mpu_start_read, - .end_read = wf_mpu_end_read, - .buffer_status = wf_mpu_buffer_status, -}; - -static struct synth_info wf_mpu_synth_info_proto = -{"WaveFront MPU-401 interface", 0, - SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT}; - -static struct synth_info wf_mpu_synth_info[2]; - -static int -wf_mpu_synth_ioctl (int dev, unsigned int cmd, void __user *arg) -{ - int midi_dev; - int index; - - midi_dev = synth_devs[dev]->midi_dev; - - if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) - return -(ENXIO); - - if (midi_dev == phys_dev->devno) { - index = 0; - } else if (phys_dev->isvirtual && midi_dev == virt_dev->devno) { - index = 1; - } else { - return -(EINVAL); - } - - switch (cmd) { - - case SNDCTL_SYNTH_INFO: - if (copy_to_user(arg, - &wf_mpu_synth_info[index], - sizeof (struct synth_info))) - return -EFAULT; - return 0; - - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - - default: - return -EINVAL; - } -} - -static int -wf_mpu_synth_open (int dev, int mode) -{ - int midi_dev; - struct wf_mpu_config *devc; - - midi_dev = synth_devs[dev]->midi_dev; - - if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) { - return -(ENXIO); - } - - if (phys_dev->devno == midi_dev) { - devc = phys_dev; - } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) { - devc = virt_dev; - } else { - printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev); - return -(EINVAL); - } - - if (devc->opened) { - return -(EBUSY); - } - - devc->mode = MODE_SYNTH; - devc->synthno = dev; - devc->opened = mode; - devc->inputintr = NULL; - return 0; -} - -static void -wf_mpu_synth_close (int dev) -{ - int midi_dev; - struct wf_mpu_config *devc; - - midi_dev = synth_devs[dev]->midi_dev; - - if (phys_dev->devno == midi_dev) { - devc = phys_dev; - } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) { - devc = virt_dev; - } else { - printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev); - return; - } - - devc->inputintr = NULL; - devc->opened = 0; - devc->mode = 0; -} - -#define _MIDI_SYNTH_C_ -#define MIDI_SYNTH_NAME "WaveFront (MIDI)" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static struct synth_operations wf_mpu_synth_proto = -{ - .owner = THIS_MODULE, - .id = "WaveFront (ICS2115)", - .info = NULL, /* info field, filled in during configuration */ - .midi_dev = 0, /* MIDI dev XXX should this be -1 ? */ - .synth_type = SYNTH_TYPE_MIDI, - .synth_subtype = SAMPLE_TYPE_WAVEFRONT, - .open = wf_mpu_synth_open, - .close = wf_mpu_synth_close, - .ioctl = wf_mpu_synth_ioctl, - .kill_note = midi_synth_kill_note, - .start_note = midi_synth_start_note, - .set_instr = midi_synth_set_instr, - .reset = midi_synth_reset, - .hw_control = midi_synth_hw_control, - .load_patch = midi_synth_load_patch, - .aftertouch = midi_synth_aftertouch, - .controller = midi_synth_controller, - .panning = midi_synth_panning, - .bender = midi_synth_bender, - .setup_voice = midi_synth_setup_voice, - .send_sysex = midi_synth_send_sysex -}; - -static int -config_wf_mpu (struct wf_mpu_config *dev) - -{ - int is_external; - char *name; - int index; - - if (dev == phys_dev) { - name = "WaveFront internal MIDI"; - is_external = 0; - index = 0; - memcpy ((char *) &wf_mpu_synth_operations[index], - (char *) &wf_mpu_synth_proto, - sizeof (struct synth_operations)); - } else { - name = "WaveFront external MIDI"; - is_external = 1; - index = 1; - /* no synth operations for an external MIDI interface */ - } - - memcpy ((char *) &wf_mpu_synth_info[dev->devno], - (char *) &wf_mpu_synth_info_proto, - sizeof (struct synth_info)); - - strcpy (wf_mpu_synth_info[index].name, name); - - wf_mpu_synth_operations[index].midi_dev = dev->devno; - wf_mpu_synth_operations[index].info = &wf_mpu_synth_info[index]; - - memcpy ((char *) &wf_mpu_midi_operations[index], - (char *) &wf_mpu_midi_proto, - sizeof (struct midi_operations)); - - if (is_external) { - wf_mpu_midi_operations[index].converter = NULL; - } else { - wf_mpu_midi_operations[index].converter = - &wf_mpu_synth_operations[index]; - } - - strcpy (wf_mpu_midi_operations[index].info.name, name); - - midi_devs[dev->devno] = &wf_mpu_midi_operations[index]; - midi_devs[dev->devno]->in_info.m_busy = 0; - midi_devs[dev->devno]->in_info.m_state = MST_INIT; - midi_devs[dev->devno]->in_info.m_ptr = 0; - midi_devs[dev->devno]->in_info.m_left = 0; - midi_devs[dev->devno]->in_info.m_prev_status = 0; - - devs[index].opened = 0; - devs[index].mode = 0; - - return (0); -} - -int virtual_midi_enable (void) - -{ - if ((virt_dev->devno < 0) && - (virt_dev->devno = sound_alloc_mididev()) == -1) { - printk (KERN_ERR - "WF-MPU: too many midi devices detected\n"); - return -1; - } - - config_wf_mpu (virt_dev); - - phys_dev->isvirtual = 1; - return virt_dev->devno; -} - -int -virtual_midi_disable (void) - -{ - unsigned long flags; - - spin_lock_irqsave(&lock,flags); - - wf_mpu_close (virt_dev->devno); - /* no synth on virt_dev, so no need to call wf_mpu_synth_close() */ - phys_dev->isvirtual = 0; - - spin_unlock_irqrestore(&lock,flags); - - return 0; -} - -int __init detect_wf_mpu (int irq, int io_base) -{ - if (!request_region(io_base, 2, "wavefront midi")) { - printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n", - io_base); - return -1; - } - - phys_dev->base = io_base; - phys_dev->irq = irq; - phys_dev->devno = -1; - virt_dev->devno = -1; - - return 0; -} - -int __init install_wf_mpu (void) -{ - if ((phys_dev->devno = sound_alloc_mididev()) < 0){ - - printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n"); - release_region(phys_dev->base, 2); - return -1; - } - - phys_dev->isvirtual = 0; - - if (config_wf_mpu (phys_dev)) { - - printk (KERN_WARNING - "WF-MPU: configuration for MIDI device %d failed\n", - phys_dev->devno); - sound_unload_mididev (phys_dev->devno); - - } - - /* OK, now we're configured to handle an interrupt ... */ - - if (request_irq (phys_dev->irq, wf_mpuintr, IRQF_DISABLED|IRQF_SHARED, - "wavefront midi", phys_dev) < 0) { - - printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n", - phys_dev->irq); - return -1; - - } - - /* This being a WaveFront (ICS-2115) emulated MPU-401, we have - to switch it into UART (dumb) mode, because otherwise, it - won't do anything at all. - */ - - start_uart_mode (); - - return phys_dev->devno; -} - -void -uninstall_wf_mpu (void) - -{ - release_region (phys_dev->base, 2); - free_irq (phys_dev->irq, phys_dev); - sound_unload_mididev (phys_dev->devno); - - if (virt_dev->devno >= 0) { - sound_unload_mididev (virt_dev->devno); - } -} - -static void -start_uart_mode (void) - -{ - int ok, i; - unsigned long flags; - - spin_lock_irqsave(&lock,flags); - - /* XXX fix me */ - - for (i = 0; i < 30000 && !output_ready (); i++); - - outb (UART_MODE_ON, COMDPORT(phys_dev)); - - for (ok = 0, i = 50000; i > 0 && !ok; i--) { - if (input_avail ()) { - if (read_data () == MPU_ACK) { - ok = 1; - } - } - } - - spin_unlock_irqrestore(&lock,flags); -} -#endif diff --git a/sound/oss/ymfpci.c b/sound/oss/ymfpci.c deleted file mode 100644 index 6e22472df952..000000000000 --- a/sound/oss/ymfpci.c +++ /dev/null @@ -1,2692 +0,0 @@ -/* - * Copyright 1999 Jaroslav Kysela - * Copyright 2000 Alan Cox - * Copyright 2001 Kai Germaschewski - * Copyright 2002 Pete Zaitcev - * - * Yamaha YMF7xx driver. - * - * This code is a result of high-speed collision - * between ymfpci.c of ALSA and cs46xx.c of Linux. - * -- Pete Zaitcev ; 2000/09/18 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * TODO: - * - Use P44Slot for 44.1 playback (beware of idle buzzing in P44Slot). - * - 96KHz playback for DVD - use pitch of 2.0. - * - Retain DMA buffer on close, do not wait the end of frame. - * - Resolve XXX tagged questions. - * - Cannot play 5133Hz. - * - 2001/01/07 Consider if we can remove voice_lock, like so: - * : Allocate/deallocate voices in open/close under semafore. - * : We access voices in interrupt, that only for pcms that open. - * voice_lock around playback_prepare closes interrupts for insane duration. - * - Revisit the way voice_alloc is done - too confusing, overcomplicated. - * Should support various channel types, however. - * - Remove prog_dmabuf from read/write, leave it in open. - * - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with - * native synthesizer through a playback slot. - * - 2001/11/29 ac97_save_state - * Talk to Kai to remove ac97_save_state before it's too late! - * - Second AC97 - * - Restore S/PDIF - Toshibas have it. - * - * Kai used pci_alloc_consistent for DMA buffer, which sounds a little - * unconventional. However, given how small our fragments can be, - * a little uncached access is perhaps better than endless flushing. - * On i386 and other I/O-coherent architectures pci_alloc_consistent - * is entirely harmless. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef CONFIG_SOUND_YMFPCI_LEGACY -# include "sound_config.h" -# include "mpu401.h" -#endif -#include "ymfpci.h" - -/* - * I do not believe in debug levels as I never can guess what - * part of the code is going to be problematic in the future. - * Don't forget to run your klogd with -c 8. - * - * Example (do not remove): - * #define YMFDBG(fmt, arg...) do{ printk(KERN_DEBUG fmt, ##arg); }while(0) - */ -#define YMFDBGW(fmt, arg...) /* */ /* write counts */ -#define YMFDBGI(fmt, arg...) /* */ /* interrupts */ -#define YMFDBGX(fmt, arg...) /* */ /* ioctl */ - -static int ymf_playback_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd); -static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd); -static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice); -static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank); -static int ymf_playback_prepare(struct ymf_state *state); -static int ymf_capture_prepare(struct ymf_state *state); -static struct ymf_state *ymf_state_alloc(ymfpci_t *unit); - -static void ymfpci_aclink_reset(struct pci_dev * pci); -static void ymfpci_disable_dsp(ymfpci_t *unit); -static void ymfpci_download_image(ymfpci_t *codec); -static void ymf_memload(ymfpci_t *unit); - -static DEFINE_SPINLOCK(ymf_devs_lock); -static LIST_HEAD(ymf_devs); - -/* - * constants - */ - -static struct pci_device_id ymf_id_tbl[] = { -#define DEV(dev, data) \ - { PCI_VENDOR_ID_YAMAHA, dev, PCI_ANY_ID, PCI_ANY_ID, 0, 0, \ - (unsigned long)data } - DEV (PCI_DEVICE_ID_YAMAHA_724, "YMF724"), - DEV (PCI_DEVICE_ID_YAMAHA_724F, "YMF724F"), - DEV (PCI_DEVICE_ID_YAMAHA_740, "YMF740"), - DEV (PCI_DEVICE_ID_YAMAHA_740C, "YMF740C"), - DEV (PCI_DEVICE_ID_YAMAHA_744, "YMF744"), - DEV (PCI_DEVICE_ID_YAMAHA_754, "YMF754"), -#undef DEV - { } -}; -MODULE_DEVICE_TABLE(pci, ymf_id_tbl); - -/* - * common I/O routines - */ - -static inline void ymfpci_writeb(ymfpci_t *codec, u32 offset, u8 val) -{ - writeb(val, codec->reg_area_virt + offset); -} - -static inline u16 ymfpci_readw(ymfpci_t *codec, u32 offset) -{ - return readw(codec->reg_area_virt + offset); -} - -static inline void ymfpci_writew(ymfpci_t *codec, u32 offset, u16 val) -{ - writew(val, codec->reg_area_virt + offset); -} - -static inline u32 ymfpci_readl(ymfpci_t *codec, u32 offset) -{ - return readl(codec->reg_area_virt + offset); -} - -static inline void ymfpci_writel(ymfpci_t *codec, u32 offset, u32 val) -{ - writel(val, codec->reg_area_virt + offset); -} - -static int ymfpci_codec_ready(ymfpci_t *codec, int secondary, int sched) -{ - signed long end_time; - u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR; - - end_time = jiffies + 3 * (HZ / 4); - do { - if ((ymfpci_readw(codec, reg) & 0x8000) == 0) - return 0; - if (sched) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } - } while (end_time - (signed long)jiffies >= 0); - printk(KERN_ERR "ymfpci_codec_ready: codec %i is not ready [0x%x]\n", - secondary, ymfpci_readw(codec, reg)); - return -EBUSY; -} - -static void ymfpci_codec_write(struct ac97_codec *dev, u8 reg, u16 val) -{ - ymfpci_t *codec = dev->private_data; - u32 cmd; - - spin_lock(&codec->ac97_lock); - /* XXX Do make use of dev->id */ - ymfpci_codec_ready(codec, 0, 0); - cmd = ((YDSXG_AC97WRITECMD | reg) << 16) | val; - ymfpci_writel(codec, YDSXGR_AC97CMDDATA, cmd); - spin_unlock(&codec->ac97_lock); -} - -static u16 _ymfpci_codec_read(ymfpci_t *unit, u8 reg) -{ - int i; - - if (ymfpci_codec_ready(unit, 0, 0)) - return ~0; - ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg); - if (ymfpci_codec_ready(unit, 0, 0)) - return ~0; - if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) { - for (i = 0; i < 600; i++) - ymfpci_readw(unit, YDSXGR_PRISTATUSDATA); - } - return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA); -} - -static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg) -{ - ymfpci_t *unit = dev->private_data; - u16 ret; - - spin_lock(&unit->ac97_lock); - ret = _ymfpci_codec_read(unit, reg); - spin_unlock(&unit->ac97_lock); - - return ret; -} - -/* - * Misc routines - */ - -/* - * Calculate the actual sampling rate relatetively to the base clock (48kHz). - */ -static u32 ymfpci_calc_delta(u32 rate) -{ - switch (rate) { - case 8000: return 0x02aaab00; - case 11025: return 0x03accd00; - case 16000: return 0x05555500; - case 22050: return 0x07599a00; - case 32000: return 0x0aaaab00; - case 44100: return 0x0eb33300; - default: return ((rate << 16) / 48000) << 12; - } -} - -static u32 def_rate[8] = { - 100, 2000, 8000, 11025, 16000, 22050, 32000, 48000 -}; - -static u32 ymfpci_calc_lpfK(u32 rate) -{ - u32 i; - static u32 val[8] = { - 0x00570000, 0x06AA0000, 0x18B20000, 0x20930000, - 0x2B9A0000, 0x35A10000, 0x3EAA0000, 0x40000000 - }; - - if (rate == 44100) - return 0x40000000; /* FIXME: What's the right value? */ - for (i = 0; i < 8; i++) - if (rate <= def_rate[i]) - return val[i]; - return val[0]; -} - -static u32 ymfpci_calc_lpfQ(u32 rate) -{ - u32 i; - static u32 val[8] = { - 0x35280000, 0x34A70000, 0x32020000, 0x31770000, - 0x31390000, 0x31C90000, 0x33D00000, 0x40000000 - }; - - if (rate == 44100) - return 0x370A0000; - for (i = 0; i < 8; i++) - if (rate <= def_rate[i]) - return val[i]; - return val[0]; -} - -static u32 ymf_calc_lend(u32 rate) -{ - return (rate * YMF_SAMPF) / 48000; -} - -/* - * We ever allow only a few formats, but let's be generic, for smaller surprise. - */ -static int ymf_pcm_format_width(int format) -{ - static int mask16 = AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE; - - if ((format & (format-1)) != 0) { - printk(KERN_ERR "ymfpci: format 0x%x is not a power of 2\n", format); - return 8; - } - - if (format == AFMT_IMA_ADPCM) return 4; - if ((format & mask16) != 0) return 16; - return 8; -} - -static void ymf_pcm_update_shift(struct ymf_pcm_format *f) -{ - f->shift = 0; - if (f->voices == 2) - f->shift++; - if (ymf_pcm_format_width(f->format) == 16) - f->shift++; -} - -/* Are you sure 32K is not too much? See if mpg123 skips on loaded systems. */ -#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - -/* - * Allocate DMA buffer - */ -static int alloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf) -{ - void *rawbuf = NULL; - dma_addr_t dma_addr; - int order; - struct page *map, *mapend; - - /* alloc as big a chunk as we can */ - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) { - rawbuf = pci_alloc_consistent(unit->pci, PAGE_SIZE << order, &dma_addr); - if (rawbuf) - break; - } - if (!rawbuf) - return -ENOMEM; - -#if 0 - printk(KERN_DEBUG "ymfpci: allocated %ld (order = %d) bytes at %p\n", - PAGE_SIZE << order, order, rawbuf); -#endif - - dmabuf->ready = dmabuf->mapped = 0; - dmabuf->rawbuf = rawbuf; - dmabuf->dma_addr = dma_addr; - dmabuf->buforder = order; - - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - mapend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); - for (map = virt_to_page(rawbuf); map <= mapend; map++) - set_bit(PG_reserved, &map->flags); - - return 0; -} - -/* - * Free DMA buffer - */ -static void dealloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf) -{ - struct page *map, *mapend; - - if (dmabuf->rawbuf) { - /* undo marking the pages as reserved */ - mapend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); - for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++) - clear_bit(PG_reserved, &map->flags); - - pci_free_consistent(unit->pci, PAGE_SIZE << dmabuf->buforder, - dmabuf->rawbuf, dmabuf->dma_addr); - } - dmabuf->rawbuf = NULL; - dmabuf->mapped = dmabuf->ready = 0; -} - -static int prog_dmabuf(struct ymf_state *state, int rec) -{ - struct ymf_dmabuf *dmabuf; - int w_16; - unsigned bufsize; - unsigned long flags; - int redzone, redfrags; - int ret; - - w_16 = ymf_pcm_format_width(state->format.format) == 16; - dmabuf = rec ? &state->rpcm.dmabuf : &state->wpcm.dmabuf; - - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->hwptr = dmabuf->swptr = 0; - dmabuf->total_bytes = 0; - dmabuf->count = 0; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - - /* allocate DMA buffer if not allocated yet */ - if (!dmabuf->rawbuf) - if ((ret = alloc_dmabuf(state->unit, dmabuf))) - return ret; - - /* - * Create fake fragment sizes and numbers for OSS ioctls. - * Import what Doom might have set with SNDCTL_DSP_SETFRAGMENT. - */ - bufsize = PAGE_SIZE << dmabuf->buforder; - /* By default we give 4 big buffers. */ - dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT - 2); - if (dmabuf->ossfragshift > 3 && - dmabuf->ossfragshift < dmabuf->fragshift) { - /* If OSS set smaller fragments, give more smaller buffers. */ - dmabuf->fragshift = dmabuf->ossfragshift; - } - dmabuf->fragsize = 1 << dmabuf->fragshift; - - dmabuf->numfrag = bufsize >> dmabuf->fragshift; - dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; - - if (dmabuf->ossmaxfrags >= 2) { - redzone = ymf_calc_lend(state->format.rate); - redzone <<= state->format.shift; - redzone *= 3; - redfrags = (redzone + dmabuf->fragsize-1) >> dmabuf->fragshift; - - if (dmabuf->ossmaxfrags + redfrags < dmabuf->numfrag) { - dmabuf->numfrag = dmabuf->ossmaxfrags + redfrags; - dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; - } - } - - memset(dmabuf->rawbuf, w_16 ? 0 : 0x80, dmabuf->dmasize); - - /* - * Now set up the ring - */ - - /* XXX ret = rec? cap_pre(): pbk_pre(); */ - spin_lock_irqsave(&state->unit->voice_lock, flags); - if (rec) { - if ((ret = ymf_capture_prepare(state)) != 0) { - spin_unlock_irqrestore(&state->unit->voice_lock, flags); - return ret; - } - } else { - if ((ret = ymf_playback_prepare(state)) != 0) { - spin_unlock_irqrestore(&state->unit->voice_lock, flags); - return ret; - } - } - spin_unlock_irqrestore(&state->unit->voice_lock, flags); - - /* set the ready flag for the dma buffer (this comment is not stupid) */ - dmabuf->ready = 1; - -#if 0 - printk(KERN_DEBUG "prog_dmabuf: rate %d format 0x%x," - " numfrag %d fragsize %d dmasize %d\n", - state->format.rate, state->format.format, dmabuf->numfrag, - dmabuf->fragsize, dmabuf->dmasize); -#endif - - return 0; -} - -static void ymf_start_dac(struct ymf_state *state) -{ - ymf_playback_trigger(state->unit, &state->wpcm, 1); -} - -// static void ymf_start_adc(struct ymf_state *state) -// { -// ymf_capture_trigger(state->unit, &state->rpcm, 1); -// } - -/* - * Wait until output is drained. - * This does not kill the hardware for the sake of ioctls. - */ -static void ymf_wait_dac(struct ymf_state *state) -{ - struct ymf_unit *unit = state->unit; - struct ymf_pcm *ypcm = &state->wpcm; - DECLARE_WAITQUEUE(waita, current); - unsigned long flags; - - add_wait_queue(&ypcm->dmabuf.wait, &waita); - - spin_lock_irqsave(&unit->reg_lock, flags); - if (ypcm->dmabuf.count != 0 && !ypcm->running) { - ymf_playback_trigger(unit, ypcm, 1); - } - -#if 0 - if (file->f_flags & O_NONBLOCK) { - /* - * XXX Our mistake is to attach DMA buffer to state - * rather than to some per-device structure. - * Cannot skip waiting, can only make it shorter. - */ - } -#endif - - set_current_state(TASK_UNINTERRUPTIBLE); - while (ypcm->running) { - spin_unlock_irqrestore(&unit->reg_lock, flags); - schedule(); - spin_lock_irqsave(&unit->reg_lock, flags); - set_current_state(TASK_UNINTERRUPTIBLE); - } - spin_unlock_irqrestore(&unit->reg_lock, flags); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&ypcm->dmabuf.wait, &waita); - - /* - * This function may take up to 4 seconds to reach this point - * (32K circular buffer, 8000 Hz). User notices. - */ -} - -/* Can just stop, without wait. Or can we? */ -static void ymf_stop_adc(struct ymf_state *state) -{ - struct ymf_unit *unit = state->unit; - unsigned long flags; - - spin_lock_irqsave(&unit->reg_lock, flags); - ymf_capture_trigger(unit, &state->rpcm, 0); - spin_unlock_irqrestore(&unit->reg_lock, flags); -} - -/* - * Hardware start management - */ - -static void ymfpci_hw_start(ymfpci_t *unit) -{ - unsigned long flags; - - spin_lock_irqsave(&unit->reg_lock, flags); - if (unit->start_count++ == 0) { - ymfpci_writel(unit, YDSXGR_MODE, - ymfpci_readl(unit, YDSXGR_MODE) | 3); - unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1; - } - spin_unlock_irqrestore(&unit->reg_lock, flags); -} - -static void ymfpci_hw_stop(ymfpci_t *unit) -{ - unsigned long flags; - long timeout = 1000; - - spin_lock_irqsave(&unit->reg_lock, flags); - if (--unit->start_count == 0) { - ymfpci_writel(unit, YDSXGR_MODE, - ymfpci_readl(unit, YDSXGR_MODE) & ~3); - while (timeout-- > 0) { - if ((ymfpci_readl(unit, YDSXGR_STATUS) & 2) == 0) - break; - } - } - spin_unlock_irqrestore(&unit->reg_lock, flags); -} - -/* - * Playback voice management - */ - -static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfpci_voice_t *rvoice[]) -{ - ymfpci_voice_t *voice, *voice2; - int idx; - - for (idx = 0; idx < YDSXG_PLAYBACK_VOICES; idx += pair ? 2 : 1) { - voice = &codec->voices[idx]; - voice2 = pair ? &codec->voices[idx+1] : NULL; - if (voice->use || (voice2 && voice2->use)) - continue; - voice->use = 1; - if (voice2) - voice2->use = 1; - switch (type) { - case YMFPCI_PCM: - voice->pcm = 1; - if (voice2) - voice2->pcm = 1; - break; - case YMFPCI_SYNTH: - voice->synth = 1; - break; - case YMFPCI_MIDI: - voice->midi = 1; - break; - } - ymfpci_hw_start(codec); - rvoice[0] = voice; - if (voice2) { - ymfpci_hw_start(codec); - rvoice[1] = voice2; - } - return 0; - } - return -EBUSY; /* Your audio channel is open by someone else. */ -} - -static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice) -{ - ymfpci_hw_stop(unit); - pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0; - pvoice->ypcm = NULL; -} - -/* - */ - -static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice) -{ - struct ymf_pcm *ypcm; - int redzone; - int pos, delta, swptr; - int played, distance; - struct ymf_state *state; - struct ymf_dmabuf *dmabuf; - char silence; - - if ((ypcm = voice->ypcm) == NULL) { - return; - } - if ((state = ypcm->state) == NULL) { - ypcm->running = 0; // lock it - return; - } - dmabuf = &ypcm->dmabuf; - spin_lock(&codec->reg_lock); - if (ypcm->running) { - YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n", - voice->number, codec->active_bank, dmabuf->count, - le32_to_cpu(voice->bank[0].start), - le32_to_cpu(voice->bank[1].start)); - silence = (ymf_pcm_format_width(state->format.format) == 16) ? - 0 : 0x80; - /* We need actual left-hand-side redzone size here. */ - redzone = ymf_calc_lend(state->format.rate); - redzone <<= (state->format.shift + 1); - swptr = dmabuf->swptr; - - pos = le32_to_cpu(voice->bank[codec->active_bank].start); - pos <<= state->format.shift; - if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */ - printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n", - codec->dev_audio, voice->number, - dmabuf->hwptr, pos, dmabuf->dmasize); - pos = 0; - } - if (pos < dmabuf->hwptr) { - delta = dmabuf->dmasize - dmabuf->hwptr; - memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta); - delta += pos; - memset(dmabuf->rawbuf, silence, pos); - } else { - delta = pos - dmabuf->hwptr; - memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta); - } - dmabuf->hwptr = pos; - - if (dmabuf->count == 0) { - printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n", - codec->dev_audio, voice->number, dmabuf->hwptr); - ymf_playback_trigger(codec, ypcm, 0); - } - - if (swptr <= pos) { - distance = pos - swptr; - } else { - distance = dmabuf->dmasize - (swptr - pos); - } - if (distance < redzone) { - /* - * hwptr inside redzone => DMA ran out of samples. - */ - if (delta < dmabuf->count) { - /* - * Lost interrupt or other screwage. - */ - printk(KERN_ERR "ymfpci%d: %d: lost: delta %d" - " hwptr %d swptr %d distance %d count %d\n", - codec->dev_audio, voice->number, delta, - dmabuf->hwptr, swptr, distance, dmabuf->count); - } else { - /* - * Normal end of DMA. - */ - YMFDBGI("ymfpci%d: %d: done: delta %d" - " hwptr %d swptr %d distance %d count %d\n", - codec->dev_audio, voice->number, delta, - dmabuf->hwptr, swptr, distance, dmabuf->count); - } - played = dmabuf->count; - if (ypcm->running) { - ymf_playback_trigger(codec, ypcm, 0); - } - } else { - /* - * hwptr is chipping away towards a remote swptr. - * Calculate other distance and apply it to count. - */ - if (swptr >= pos) { - distance = swptr - pos; - } else { - distance = dmabuf->dmasize - (pos - swptr); - } - if (distance < dmabuf->count) { - played = dmabuf->count - distance; - } else { - played = 0; - } - } - - dmabuf->total_bytes += played; - dmabuf->count -= played; - if (dmabuf->count < dmabuf->dmasize / 2) { - wake_up(&dmabuf->wait); - } - } - spin_unlock(&codec->reg_lock); -} - -static void ymf_cap_interrupt(ymfpci_t *unit, struct ymf_capture *cap) -{ - struct ymf_pcm *ypcm; - int redzone; - struct ymf_state *state; - struct ymf_dmabuf *dmabuf; - int pos, delta; - int cnt; - - if ((ypcm = cap->ypcm) == NULL) { - return; - } - if ((state = ypcm->state) == NULL) { - ypcm->running = 0; // lock it - return; - } - dmabuf = &ypcm->dmabuf; - spin_lock(&unit->reg_lock); - if (ypcm->running) { - redzone = ymf_calc_lend(state->format.rate); - redzone <<= (state->format.shift + 1); - - pos = le32_to_cpu(cap->bank[unit->active_bank].start); - // pos <<= state->format.shift; - if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */ - printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n", - unit->dev_audio, ypcm->capture_bank_number, - dmabuf->hwptr, pos, dmabuf->dmasize); - pos = 0; - } - if (pos < dmabuf->hwptr) { - delta = dmabuf->dmasize - dmabuf->hwptr; - delta += pos; - } else { - delta = pos - dmabuf->hwptr; - } - dmabuf->hwptr = pos; - - cnt = dmabuf->count; - cnt += delta; - if (cnt + redzone > dmabuf->dmasize) { - /* Overflow - bump swptr */ - dmabuf->count = dmabuf->dmasize - redzone; - dmabuf->swptr = dmabuf->hwptr + redzone; - if (dmabuf->swptr >= dmabuf->dmasize) { - dmabuf->swptr -= dmabuf->dmasize; - } - } else { - dmabuf->count = cnt; - } - - dmabuf->total_bytes += delta; - if (dmabuf->count) { /* && is_sleeping XXX */ - wake_up(&dmabuf->wait); - } - } - spin_unlock(&unit->reg_lock); -} - -static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd) -{ - - if (ypcm->voices[0] == NULL) { - return -EINVAL; - } - if (cmd != 0) { - codec->ctrl_playback[ypcm->voices[0]->number + 1] = - cpu_to_le32(ypcm->voices[0]->bank_ba); - if (ypcm->voices[1] != NULL) - codec->ctrl_playback[ypcm->voices[1]->number + 1] = - cpu_to_le32(ypcm->voices[1]->bank_ba); - ypcm->running = 1; - } else { - codec->ctrl_playback[ypcm->voices[0]->number + 1] = 0; - if (ypcm->voices[1] != NULL) - codec->ctrl_playback[ypcm->voices[1]->number + 1] = 0; - ypcm->running = 0; - } - return 0; -} - -static void ymf_capture_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd) -{ - u32 tmp; - - if (cmd != 0) { - tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number); - ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp); - ypcm->running = 1; - } else { - tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number); - ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp); - ypcm->running = 0; - } -} - -static int ymfpci_pcm_voice_alloc(struct ymf_pcm *ypcm, int voices) -{ - struct ymf_unit *unit; - int err; - - unit = ypcm->state->unit; - if (ypcm->voices[1] != NULL && voices < 2) { - ymfpci_voice_free(unit, ypcm->voices[1]); - ypcm->voices[1] = NULL; - } - if (voices == 1 && ypcm->voices[0] != NULL) - return 0; /* already allocated */ - if (voices == 2 && ypcm->voices[0] != NULL && ypcm->voices[1] != NULL) - return 0; /* already allocated */ - if (voices > 1) { - if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) { - ymfpci_voice_free(unit, ypcm->voices[0]); - ypcm->voices[0] = NULL; - } - if ((err = voice_alloc(unit, YMFPCI_PCM, 1, ypcm->voices)) < 0) - return err; - ypcm->voices[0]->ypcm = ypcm; - ypcm->voices[1]->ypcm = ypcm; - } else { - if ((err = voice_alloc(unit, YMFPCI_PCM, 0, ypcm->voices)) < 0) - return err; - ypcm->voices[0]->ypcm = ypcm; - } - return 0; -} - -static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo, - int rate, int w_16, unsigned long addr, unsigned int end, int spdif) -{ - u32 format; - u32 delta = ymfpci_calc_delta(rate); - u32 lpfQ = ymfpci_calc_lpfQ(rate); - u32 lpfK = ymfpci_calc_lpfK(rate); - ymfpci_playback_bank_t *bank; - int nbank; - - /* - * The gain is a floating point number. According to the manual, - * bit 31 indicates a sign bit, bit 30 indicates an integer part, - * and bits [29:15] indicate a decimal fraction part. Thus, - * for a gain of 1.0 the constant of 0x40000000 is loaded. - */ - unsigned default_gain = cpu_to_le32(0x40000000); - - format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000); - if (stereo) - end >>= 1; - if (w_16) - end >>= 1; - for (nbank = 0; nbank < 2; nbank++) { - bank = &voice->bank[nbank]; - bank->format = cpu_to_le32(format); - bank->loop_default = 0; /* 0-loops forever, otherwise count */ - bank->base = cpu_to_le32(addr); - bank->loop_start = 0; - bank->loop_end = cpu_to_le32(end); - bank->loop_frac = 0; - bank->eg_gain_end = default_gain; - bank->lpfQ = cpu_to_le32(lpfQ); - bank->status = 0; - bank->num_of_frames = 0; - bank->loop_count = 0; - bank->start = 0; - bank->start_frac = 0; - bank->delta = - bank->delta_end = cpu_to_le32(delta); - bank->lpfK = - bank->lpfK_end = cpu_to_le32(lpfK); - bank->eg_gain = default_gain; - bank->lpfD1 = - bank->lpfD2 = 0; - - bank->left_gain = - bank->right_gain = - bank->left_gain_end = - bank->right_gain_end = - bank->eff1_gain = - bank->eff2_gain = - bank->eff3_gain = - bank->eff1_gain_end = - bank->eff2_gain_end = - bank->eff3_gain_end = 0; - - if (!stereo) { - if (!spdif) { - bank->left_gain = - bank->right_gain = - bank->left_gain_end = - bank->right_gain_end = default_gain; - } else { - bank->eff2_gain = - bank->eff2_gain_end = - bank->eff3_gain = - bank->eff3_gain_end = default_gain; - } - } else { - if (!spdif) { - if ((voice->number & 1) == 0) { - bank->left_gain = - bank->left_gain_end = default_gain; - } else { - bank->format |= cpu_to_le32(1); - bank->right_gain = - bank->right_gain_end = default_gain; - } - } else { - if ((voice->number & 1) == 0) { - bank->eff2_gain = - bank->eff2_gain_end = default_gain; - } else { - bank->format |= cpu_to_le32(1); - bank->eff3_gain = - bank->eff3_gain_end = default_gain; - } - } - } - } -} - -/* - * XXX Capture channel allocation is entirely fake at the moment. - * We use only one channel and mark it busy as required. - */ -static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank) -{ - struct ymf_capture *cap; - int cbank; - - cbank = 1; /* Only ADC slot is used for now. */ - cap = &unit->capture[cbank]; - if (cap->use) - return -EBUSY; - cap->use = 1; - *pbank = cbank; - return 0; -} - -static int ymf_playback_prepare(struct ymf_state *state) -{ - struct ymf_pcm *ypcm = &state->wpcm; - int err, nvoice; - - if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) { - /* Somebody started 32 mpg123's in parallel? */ - printk(KERN_INFO "ymfpci%d: cannot allocate voice\n", - state->unit->dev_audio); - return err; - } - - for (nvoice = 0; nvoice < state->format.voices; nvoice++) { - ymf_pcm_init_voice(ypcm->voices[nvoice], - state->format.voices == 2, state->format.rate, - ymf_pcm_format_width(state->format.format) == 16, - ypcm->dmabuf.dma_addr, ypcm->dmabuf.dmasize, - ypcm->spdif); - } - return 0; -} - -static int ymf_capture_prepare(struct ymf_state *state) -{ - ymfpci_t *unit = state->unit; - struct ymf_pcm *ypcm = &state->rpcm; - ymfpci_capture_bank_t * bank; - /* XXX This is confusing, gotta rename one of them banks... */ - int nbank; /* flip-flop bank */ - int cbank; /* input [super-]bank */ - struct ymf_capture *cap; - u32 rate, format; - - if (ypcm->capture_bank_number == -1) { - if (ymf_capture_alloc(unit, &cbank) != 0) - return -EBUSY; - - ypcm->capture_bank_number = cbank; - - cap = &unit->capture[cbank]; - cap->bank = unit->bank_capture[cbank][0]; - cap->ypcm = ypcm; - ymfpci_hw_start(unit); - } - - // ypcm->frag_size = snd_pcm_lib_transfer_fragment(substream); - // frag_size is replaced with nonfragged byte-aligned rolling buffer - rate = ((48000 * 4096) / state->format.rate) - 1; - format = 0; - if (state->format.voices == 2) - format |= 2; - if (ymf_pcm_format_width(state->format.format) == 8) - format |= 1; - switch (ypcm->capture_bank_number) { - case 0: - ymfpci_writel(unit, YDSXGR_RECFORMAT, format); - ymfpci_writel(unit, YDSXGR_RECSLOTSR, rate); - break; - case 1: - ymfpci_writel(unit, YDSXGR_ADCFORMAT, format); - ymfpci_writel(unit, YDSXGR_ADCSLOTSR, rate); - break; - } - for (nbank = 0; nbank < 2; nbank++) { - bank = unit->bank_capture[ypcm->capture_bank_number][nbank]; - bank->base = cpu_to_le32(ypcm->dmabuf.dma_addr); - // bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift; - bank->loop_end = cpu_to_le32(ypcm->dmabuf.dmasize); - bank->start = 0; - bank->num_of_loops = 0; - } -#if 0 /* s/pdif */ - if (state->digital.dig_valid) - /*state->digital.type == SND_PCM_DIG_AES_IEC958*/ - ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS, - state->digital.dig_status[0] | (state->digital.dig_status[1] << 8)); -#endif - return 0; -} - -static irqreturn_t ymf_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - ymfpci_t *codec = dev_id; - u32 status, nvoice, mode; - struct ymf_voice *voice; - struct ymf_capture *cap; - - status = ymfpci_readl(codec, YDSXGR_STATUS); - if (status & 0x80000000) { - codec->active_bank = ymfpci_readl(codec, YDSXGR_CTRLSELECT) & 1; - spin_lock(&codec->voice_lock); - for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) { - voice = &codec->voices[nvoice]; - if (voice->use) - ymf_pcm_interrupt(codec, voice); - } - for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) { - cap = &codec->capture[nvoice]; - if (cap->use) - ymf_cap_interrupt(codec, cap); - } - spin_unlock(&codec->voice_lock); - spin_lock(&codec->reg_lock); - ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000); - mode = ymfpci_readl(codec, YDSXGR_MODE) | 2; - ymfpci_writel(codec, YDSXGR_MODE, mode); - spin_unlock(&codec->reg_lock); - } - - status = ymfpci_readl(codec, YDSXGR_INTFLAG); - if (status & 1) { - /* timer handler */ - ymfpci_writel(codec, YDSXGR_INTFLAG, ~0); - } - return IRQ_HANDLED; -} - -static void ymf_pcm_free_substream(struct ymf_pcm *ypcm) -{ - unsigned long flags; - struct ymf_unit *unit; - - unit = ypcm->state->unit; - - if (ypcm->type == PLAYBACK_VOICE) { - spin_lock_irqsave(&unit->voice_lock, flags); - if (ypcm->voices[1]) - ymfpci_voice_free(unit, ypcm->voices[1]); - if (ypcm->voices[0]) - ymfpci_voice_free(unit, ypcm->voices[0]); - spin_unlock_irqrestore(&unit->voice_lock, flags); - } else { - if (ypcm->capture_bank_number != -1) { - unit->capture[ypcm->capture_bank_number].use = 0; - ypcm->capture_bank_number = -1; - ymfpci_hw_stop(unit); - } - } -} - -static struct ymf_state *ymf_state_alloc(ymfpci_t *unit) -{ - struct ymf_pcm *ypcm; - struct ymf_state *state; - - if ((state = kmalloc(sizeof(struct ymf_state), GFP_KERNEL)) == NULL) { - goto out0; - } - memset(state, 0, sizeof(struct ymf_state)); - - ypcm = &state->wpcm; - ypcm->state = state; - ypcm->type = PLAYBACK_VOICE; - ypcm->capture_bank_number = -1; - init_waitqueue_head(&ypcm->dmabuf.wait); - - ypcm = &state->rpcm; - ypcm->state = state; - ypcm->type = CAPTURE_AC97; - ypcm->capture_bank_number = -1; - init_waitqueue_head(&ypcm->dmabuf.wait); - - state->unit = unit; - - state->format.format = AFMT_U8; - state->format.rate = 8000; - state->format.voices = 1; - ymf_pcm_update_shift(&state->format); - - return state; - -out0: - return NULL; -} - -/* AES/IEC958 channel status bits */ -#define SND_PCM_AES0_PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */ -#define SND_PCM_AES0_NONAUDIO (1<<1) /* 0 = audio, 1 = non-audio */ -#define SND_PCM_AES0_PRO_EMPHASIS (7<<2) /* mask - emphasis */ -#define SND_PCM_AES0_PRO_EMPHASIS_NOTID (0<<2) /* emphasis not indicated */ -#define SND_PCM_AES0_PRO_EMPHASIS_NONE (1<<2) /* none emphasis */ -#define SND_PCM_AES0_PRO_EMPHASIS_5015 (3<<2) /* 50/15us emphasis */ -#define SND_PCM_AES0_PRO_EMPHASIS_CCITT (7<<2) /* CCITT J.17 emphasis */ -#define SND_PCM_AES0_PRO_FREQ_UNLOCKED (1<<5) /* source sample frequency: 0 = locked, 1 = unlocked */ -#define SND_PCM_AES0_PRO_FS (3<<6) /* mask - sample frequency */ -#define SND_PCM_AES0_PRO_FS_NOTID (0<<6) /* fs not indicated */ -#define SND_PCM_AES0_PRO_FS_44100 (1<<6) /* 44.1kHz */ -#define SND_PCM_AES0_PRO_FS_48000 (2<<6) /* 48kHz */ -#define SND_PCM_AES0_PRO_FS_32000 (3<<6) /* 32kHz */ -#define SND_PCM_AES0_CON_NOT_COPYRIGHT (1<<2) /* 0 = copyright, 1 = not copyright */ -#define SND_PCM_AES0_CON_EMPHASIS (7<<3) /* mask - emphasis */ -#define SND_PCM_AES0_CON_EMPHASIS_NONE (0<<3) /* none emphasis */ -#define SND_PCM_AES0_CON_EMPHASIS_5015 (1<<3) /* 50/15us emphasis */ -#define SND_PCM_AES0_CON_MODE (3<<6) /* mask - mode */ -#define SND_PCM_AES1_PRO_MODE (15<<0) /* mask - channel mode */ -#define SND_PCM_AES1_PRO_MODE_NOTID (0<<0) /* not indicated */ -#define SND_PCM_AES1_PRO_MODE_STEREOPHONIC (2<<0) /* stereophonic - ch A is left */ -#define SND_PCM_AES1_PRO_MODE_SINGLE (4<<0) /* single channel */ -#define SND_PCM_AES1_PRO_MODE_TWO (8<<0) /* two channels */ -#define SND_PCM_AES1_PRO_MODE_PRIMARY (12<<0) /* primary/secondary */ -#define SND_PCM_AES1_PRO_MODE_BYTE3 (15<<0) /* vector to byte 3 */ -#define SND_PCM_AES1_PRO_USERBITS (15<<4) /* mask - user bits */ -#define SND_PCM_AES1_PRO_USERBITS_NOTID (0<<4) /* not indicated */ -#define SND_PCM_AES1_PRO_USERBITS_192 (8<<4) /* 192-bit structure */ -#define SND_PCM_AES1_PRO_USERBITS_UDEF (12<<4) /* user defined application */ -#define SND_PCM_AES1_CON_CATEGORY 0x7f -#define SND_PCM_AES1_CON_GENERAL 0x00 -#define SND_PCM_AES1_CON_EXPERIMENTAL 0x40 -#define SND_PCM_AES1_CON_SOLIDMEM_MASK 0x0f -#define SND_PCM_AES1_CON_SOLIDMEM_ID 0x08 -#define SND_PCM_AES1_CON_BROADCAST1_MASK 0x07 -#define SND_PCM_AES1_CON_BROADCAST1_ID 0x04 -#define SND_PCM_AES1_CON_DIGDIGCONV_MASK 0x07 -#define SND_PCM_AES1_CON_DIGDIGCONV_ID 0x02 -#define SND_PCM_AES1_CON_ADC_COPYRIGHT_MASK 0x1f -#define SND_PCM_AES1_CON_ADC_COPYRIGHT_ID 0x06 -#define SND_PCM_AES1_CON_ADC_MASK 0x1f -#define SND_PCM_AES1_CON_ADC_ID 0x16 -#define SND_PCM_AES1_CON_BROADCAST2_MASK 0x0f -#define SND_PCM_AES1_CON_BROADCAST2_ID 0x0e -#define SND_PCM_AES1_CON_LASEROPT_MASK 0x07 -#define SND_PCM_AES1_CON_LASEROPT_ID 0x01 -#define SND_PCM_AES1_CON_MUSICAL_MASK 0x07 -#define SND_PCM_AES1_CON_MUSICAL_ID 0x05 -#define SND_PCM_AES1_CON_MAGNETIC_MASK 0x07 -#define SND_PCM_AES1_CON_MAGNETIC_ID 0x03 -#define SND_PCM_AES1_CON_IEC908_CD (SND_PCM_AES1_CON_LASEROPT_ID|0x00) -#define SND_PCM_AES1_CON_NON_IEC908_CD (SND_PCM_AES1_CON_LASEROPT_ID|0x08) -#define SND_PCM_AES1_CON_PCM_CODER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x00) -#define SND_PCM_AES1_CON_SAMPLER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x20) -#define SND_PCM_AES1_CON_MIXER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x10) -#define SND_PCM_AES1_CON_RATE_CONVERTER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x18) -#define SND_PCM_AES1_CON_SYNTHESIZER (SND_PCM_AES1_CON_MUSICAL_ID|0x00) -#define SND_PCM_AES1_CON_MICROPHONE (SND_PCM_AES1_CON_MUSICAL_ID|0x08) -#define SND_PCM_AES1_CON_DAT (SND_PCM_AES1_CON_MAGNETIC_ID|0x00) -#define SND_PCM_AES1_CON_VCR (SND_PCM_AES1_CON_MAGNETIC_ID|0x08) -#define SND_PCM_AES1_CON_ORIGINAL (1<<7) /* this bits depends on the category code */ -#define SND_PCM_AES2_PRO_SBITS (7<<0) /* mask - sample bits */ -#define SND_PCM_AES2_PRO_SBITS_20 (2<<0) /* 20-bit - coordination */ -#define SND_PCM_AES2_PRO_SBITS_24 (4<<0) /* 24-bit - main audio */ -#define SND_PCM_AES2_PRO_SBITS_UDEF (6<<0) /* user defined application */ -#define SND_PCM_AES2_PRO_WORDLEN (7<<3) /* mask - source word length */ -#define SND_PCM_AES2_PRO_WORDLEN_NOTID (0<<3) /* not indicated */ -#define SND_PCM_AES2_PRO_WORDLEN_22_18 (2<<3) /* 22-bit or 18-bit */ -#define SND_PCM_AES2_PRO_WORDLEN_23_19 (4<<3) /* 23-bit or 19-bit */ -#define SND_PCM_AES2_PRO_WORDLEN_24_20 (5<<3) /* 24-bit or 20-bit */ -#define SND_PCM_AES2_PRO_WORDLEN_20_16 (6<<3) /* 20-bit or 16-bit */ -#define SND_PCM_AES2_CON_SOURCE (15<<0) /* mask - source number */ -#define SND_PCM_AES2_CON_SOURCE_UNSPEC (0<<0) /* unspecified */ -#define SND_PCM_AES2_CON_CHANNEL (15<<4) /* mask - channel number */ -#define SND_PCM_AES2_CON_CHANNEL_UNSPEC (0<<4) /* unspecified */ -#define SND_PCM_AES3_CON_FS (15<<0) /* mask - sample frequency */ -#define SND_PCM_AES3_CON_FS_44100 (0<<0) /* 44.1kHz */ -#define SND_PCM_AES3_CON_FS_48000 (2<<0) /* 48kHz */ -#define SND_PCM_AES3_CON_FS_32000 (3<<0) /* 32kHz */ -#define SND_PCM_AES3_CON_CLOCK (3<<4) /* mask - clock accuracy */ -#define SND_PCM_AES3_CON_CLOCK_1000PPM (0<<4) /* 1000 ppm */ -#define SND_PCM_AES3_CON_CLOCK_50PPM (1<<4) /* 50 ppm */ -#define SND_PCM_AES3_CON_CLOCK_VARIABLE (2<<4) /* variable pitch */ - -/* - * User interface - */ - -/* - * in this loop, dmabuf.count signifies the amount of data that is - * waiting to be copied to the user's buffer. it is filled by the dma - * machine and drained by this loop. - */ -static ssize_t -ymf_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct ymf_state *state = (struct ymf_state *)file->private_data; - struct ymf_dmabuf *dmabuf = &state->rpcm.dmabuf; - struct ymf_unit *unit = state->unit; - DECLARE_WAITQUEUE(waita, current); - ssize_t ret; - unsigned long flags; - unsigned int swptr; - int cnt; /* This many to go in this revolution */ - - if (dmabuf->mapped) - return -ENXIO; - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; - ret = 0; - - add_wait_queue(&dmabuf->wait, &waita); - set_current_state(TASK_INTERRUPTIBLE); - while (count > 0) { - spin_lock_irqsave(&unit->reg_lock, flags); - if (unit->suspended) { - spin_unlock_irqrestore(&unit->reg_lock, flags); - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - if (!ret) ret = -EAGAIN; - break; - } - continue; - } - swptr = dmabuf->swptr; - cnt = dmabuf->dmasize - swptr; - if (dmabuf->count < cnt) - cnt = dmabuf->count; - spin_unlock_irqrestore(&unit->reg_lock, flags); - - if (cnt > count) - cnt = count; - if (cnt <= 0) { - unsigned long tmo; - /* buffer is empty, start the dma machine and wait for data to be - recorded */ - spin_lock_irqsave(&state->unit->reg_lock, flags); - if (!state->rpcm.running) { - ymf_capture_trigger(state->unit, &state->rpcm, 1); - } - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - if (file->f_flags & O_NONBLOCK) { - if (!ret) ret = -EAGAIN; - break; - } - /* This isnt strictly right for the 810 but it'll do */ - tmo = (dmabuf->dmasize * HZ) / (state->format.rate * 2); - tmo >>= state->format.shift; - /* There are two situations when sleep_on_timeout returns, one is when - the interrupt is serviced correctly and the process is waked up by - ISR ON TIME. Another is when timeout is expired, which means that - either interrupt is NOT serviced correctly (pending interrupt) or it - is TOO LATE for the process to be scheduled to run (scheduler latency) - which results in a (potential) buffer overrun. And worse, there is - NOTHING we can do to prevent it. */ - tmo = schedule_timeout(tmo); - spin_lock_irqsave(&state->unit->reg_lock, flags); - set_current_state(TASK_INTERRUPTIBLE); - if (tmo == 0 && dmabuf->count == 0) { - printk(KERN_ERR "ymfpci%d: recording schedule timeout, " - "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - state->unit->dev_audio, - dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, - dmabuf->hwptr, dmabuf->swptr); - } - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - if (signal_pending(current)) { - if (!ret) ret = -ERESTARTSYS; - break; - } - continue; - } - - if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { - if (!ret) ret = -EFAULT; - break; - } - - swptr = (swptr + cnt) % dmabuf->dmasize; - - spin_lock_irqsave(&unit->reg_lock, flags); - if (unit->suspended) { - spin_unlock_irqrestore(&unit->reg_lock, flags); - continue; - } - - dmabuf->swptr = swptr; - dmabuf->count -= cnt; - // spin_unlock_irqrestore(&unit->reg_lock, flags); - - count -= cnt; - buffer += cnt; - ret += cnt; - // spin_lock_irqsave(&unit->reg_lock, flags); - if (!state->rpcm.running) { - ymf_capture_trigger(unit, &state->rpcm, 1); - } - spin_unlock_irqrestore(&unit->reg_lock, flags); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&dmabuf->wait, &waita); - - return ret; -} - -static ssize_t -ymf_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct ymf_state *state = (struct ymf_state *)file->private_data; - struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf; - struct ymf_unit *unit = state->unit; - DECLARE_WAITQUEUE(waita, current); - ssize_t ret; - unsigned long flags; - unsigned int swptr; - int cnt; /* This many to go in this revolution */ - int redzone; - int delay; - - YMFDBGW("ymf_write: count %d\n", count); - - if (dmabuf->mapped) - return -ENXIO; - if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) - return ret; - ret = 0; - - /* - * Alan's cs46xx works without a red zone - marvel of ingenuity. - * We are not so brilliant... Red zone does two things: - * 1. allows for safe start after a pause as we have no way - * to know what the actual, relentlessly advancing, hwptr is. - * 2. makes computations in ymf_pcm_interrupt simpler. - */ - redzone = ymf_calc_lend(state->format.rate) << state->format.shift; - redzone *= 3; /* 2 redzone + 1 possible uncertainty reserve. */ - - add_wait_queue(&dmabuf->wait, &waita); - set_current_state(TASK_INTERRUPTIBLE); - while (count > 0) { - spin_lock_irqsave(&unit->reg_lock, flags); - if (unit->suspended) { - spin_unlock_irqrestore(&unit->reg_lock, flags); - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - if (!ret) ret = -EAGAIN; - break; - } - continue; - } - if (dmabuf->count < 0) { - printk(KERN_ERR - "ymf_write: count %d, was legal in cs46xx\n", - dmabuf->count); - dmabuf->count = 0; - } - if (dmabuf->count == 0) { - swptr = dmabuf->hwptr; - if (state->wpcm.running) { - /* - * Add uncertainty reserve. - */ - cnt = ymf_calc_lend(state->format.rate); - cnt <<= state->format.shift; - if ((swptr += cnt) >= dmabuf->dmasize) { - swptr -= dmabuf->dmasize; - } - } - dmabuf->swptr = swptr; - } else { - /* - * XXX This is not right if dmabuf->count is small - - * about 2*x frame size or less. We cannot count on - * on appending and not causing an artefact. - * Should use a variation of the count==0 case above. - */ - swptr = dmabuf->swptr; - } - cnt = dmabuf->dmasize - swptr; - if (dmabuf->count + cnt > dmabuf->dmasize - redzone) - cnt = (dmabuf->dmasize - redzone) - dmabuf->count; - spin_unlock_irqrestore(&unit->reg_lock, flags); - - if (cnt > count) - cnt = count; - if (cnt <= 0) { - YMFDBGW("ymf_write: full, count %d swptr %d\n", - dmabuf->count, dmabuf->swptr); - /* - * buffer is full, start the dma machine and - * wait for data to be played - */ - spin_lock_irqsave(&unit->reg_lock, flags); - if (!state->wpcm.running) { - ymf_playback_trigger(unit, &state->wpcm, 1); - } - spin_unlock_irqrestore(&unit->reg_lock, flags); - if (file->f_flags & O_NONBLOCK) { - if (!ret) ret = -EAGAIN; - break; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - if (!ret) ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { - if (!ret) ret = -EFAULT; - break; - } - - if ((swptr += cnt) >= dmabuf->dmasize) { - swptr -= dmabuf->dmasize; - } - - spin_lock_irqsave(&unit->reg_lock, flags); - if (unit->suspended) { - spin_unlock_irqrestore(&unit->reg_lock, flags); - continue; - } - dmabuf->swptr = swptr; - dmabuf->count += cnt; - - /* - * Start here is a bad idea - may cause startup click - * in /bin/play when dmabuf is not full yet. - * However, some broken applications do not make - * any use of SNDCTL_DSP_SYNC (Doom is the worst). - * One frame is about 5.3ms, Doom write size is 46ms. - */ - delay = state->format.rate / 20; /* 50ms */ - delay <<= state->format.shift; - if (dmabuf->count >= delay && !state->wpcm.running) { - ymf_playback_trigger(unit, &state->wpcm, 1); - } - - spin_unlock_irqrestore(&unit->reg_lock, flags); - - count -= cnt; - buffer += cnt; - ret += cnt; - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&dmabuf->wait, &waita); - - YMFDBGW("ymf_write: ret %d dmabuf.count %d\n", ret, dmabuf->count); - return ret; -} - -static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait) -{ - struct ymf_state *state = (struct ymf_state *)file->private_data; - struct ymf_dmabuf *dmabuf; - int redzone; - unsigned long flags; - unsigned int mask = 0; - - if (file->f_mode & FMODE_WRITE) - poll_wait(file, &state->wpcm.dmabuf.wait, wait); - if (file->f_mode & FMODE_READ) - poll_wait(file, &state->rpcm.dmabuf.wait, wait); - - spin_lock_irqsave(&state->unit->reg_lock, flags); - if (file->f_mode & FMODE_READ) { - dmabuf = &state->rpcm.dmabuf; - if (dmabuf->count >= (signed)dmabuf->fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - redzone = ymf_calc_lend(state->format.rate); - redzone <<= state->format.shift; - redzone *= 3; - - dmabuf = &state->wpcm.dmabuf; - if (dmabuf->mapped) { - if (dmabuf->count >= (signed)dmabuf->fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - /* - * Don't select unless a full fragment is available. - * Otherwise artsd does GETOSPACE, sees 0, and loops. - */ - if (dmabuf->count + redzone + dmabuf->fragsize - <= dmabuf->dmasize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - - return mask; -} - -static int ymf_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct ymf_state *state = (struct ymf_state *)file->private_data; - struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf; - int ret; - unsigned long size; - - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf(state, 0)) != 0) - return ret; - } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf(state, 1)) != 0) - return ret; - } else - return -EINVAL; - - if (vma->vm_pgoff != 0) - return -EINVAL; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << dmabuf->buforder)) - return -EINVAL; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - return -EAGAIN; - dmabuf->mapped = 1; - -/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n"); - return 0; -} - -static int ymf_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ymf_state *state = (struct ymf_state *)file->private_data; - struct ymf_dmabuf *dmabuf; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int redzone; - int val; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - switch (cmd) { - case OSS_GETVERSION: - YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg); - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_RESET: - YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd); - if (file->f_mode & FMODE_WRITE) { - ymf_wait_dac(state); - dmabuf = &state->wpcm.dmabuf; - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->ready = 0; - dmabuf->swptr = dmabuf->hwptr; - dmabuf->count = dmabuf->total_bytes = 0; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } - if (file->f_mode & FMODE_READ) { - ymf_stop_adc(state); - dmabuf = &state->rpcm.dmabuf; - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->ready = 0; - dmabuf->swptr = dmabuf->hwptr; - dmabuf->count = dmabuf->total_bytes = 0; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } - return 0; - - case SNDCTL_DSP_SYNC: - YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd); - if (file->f_mode & FMODE_WRITE) { - dmabuf = &state->wpcm.dmabuf; - if (file->f_flags & O_NONBLOCK) { - spin_lock_irqsave(&state->unit->reg_lock, flags); - if (dmabuf->count != 0 && !state->wpcm.running) { - ymf_start_dac(state); - } - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } else { - ymf_wait_dac(state); - } - } - /* XXX What does this do for reading? dmabuf->count=0; ? */ - return 0; - - case SNDCTL_DSP_SPEED: /* set smaple rate */ - if (get_user(val, p)) - return -EFAULT; - YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val); - if (val >= 8000 && val <= 48000) { - if (file->f_mode & FMODE_WRITE) { - ymf_wait_dac(state); - dmabuf = &state->wpcm.dmabuf; - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->ready = 0; - state->format.rate = val; - ymf_pcm_update_shift(&state->format); - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } - if (file->f_mode & FMODE_READ) { - ymf_stop_adc(state); - dmabuf = &state->rpcm.dmabuf; - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->ready = 0; - state->format.rate = val; - ymf_pcm_update_shift(&state->format); - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } - } - return put_user(state->format.rate, p); - - /* - * OSS manual does not mention SNDCTL_DSP_STEREO at all. - * All channels are mono and if you want stereo, you - * play into two channels with SNDCTL_DSP_CHANNELS. - * However, mpg123 calls it. I wonder, why Michael Hipp used it. - */ - case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ - if (get_user(val, p)) - return -EFAULT; - YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val); - if (file->f_mode & FMODE_WRITE) { - ymf_wait_dac(state); - dmabuf = &state->wpcm.dmabuf; - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->ready = 0; - state->format.voices = val ? 2 : 1; - ymf_pcm_update_shift(&state->format); - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } - if (file->f_mode & FMODE_READ) { - ymf_stop_adc(state); - dmabuf = &state->rpcm.dmabuf; - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->ready = 0; - state->format.voices = val ? 2 : 1; - ymf_pcm_update_shift(&state->format); - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd); - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf(state, 0))) - return val; - val = state->wpcm.dmabuf.fragsize; - YMFDBGX("ymf_ioctl: GETBLK w %d\n", val); - return put_user(val, p); - } - if (file->f_mode & FMODE_READ) { - if ((val = prog_dmabuf(state, 1))) - return val; - val = state->rpcm.dmabuf.fragsize; - YMFDBGX("ymf_ioctl: GETBLK r %d\n", val); - return put_user(val, p); - } - return -EINVAL; - - case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ - YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd); - return put_user(AFMT_S16_LE|AFMT_U8, p); - - case SNDCTL_DSP_SETFMT: /* Select sample format */ - if (get_user(val, p)) - return -EFAULT; - YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val); - if (val == AFMT_S16_LE || val == AFMT_U8) { - if (file->f_mode & FMODE_WRITE) { - ymf_wait_dac(state); - dmabuf = &state->wpcm.dmabuf; - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->ready = 0; - state->format.format = val; - ymf_pcm_update_shift(&state->format); - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } - if (file->f_mode & FMODE_READ) { - ymf_stop_adc(state); - dmabuf = &state->rpcm.dmabuf; - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->ready = 0; - state->format.format = val; - ymf_pcm_update_shift(&state->format); - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } - } - return put_user(state->format.format, p); - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val); - if (val != 0) { - if (file->f_mode & FMODE_WRITE) { - ymf_wait_dac(state); - if (val == 1 || val == 2) { - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf = &state->wpcm.dmabuf; - dmabuf->ready = 0; - state->format.voices = val; - ymf_pcm_update_shift(&state->format); - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } - } - if (file->f_mode & FMODE_READ) { - ymf_stop_adc(state); - if (val == 1 || val == 2) { - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf = &state->rpcm.dmabuf; - dmabuf->ready = 0; - state->format.voices = val; - ymf_pcm_update_shift(&state->format); - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - } - } - } - return put_user(state->format.voices, p); - - case SNDCTL_DSP_POST: - YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd); - /* - * Quoting OSS PG: - * The ioctl SNDCTL_DSP_POST is a lightweight version of - * SNDCTL_DSP_SYNC. It just tells to the driver that there - * is likely to be a pause in the output. This makes it - * possible for the device to handle the pause more - * intelligently. This ioctl doesn't block the application. - * - * The paragraph above is a clumsy way to say "flush ioctl". - * This ioctl is used by mpg123. - */ - spin_lock_irqsave(&state->unit->reg_lock, flags); - if (state->wpcm.dmabuf.count != 0 && !state->wpcm.running) { - ymf_start_dac(state); - } - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - return 0; - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n", - cmd, - (val >> 16) & 0xFFFF, val & 0xFFFF, - (val >> 16) & 0xFFFF, val & 0xFFFF); - dmabuf = &state->wpcm.dmabuf; - dmabuf->ossfragshift = val & 0xffff; - dmabuf->ossmaxfrags = (val >> 16) & 0xffff; - if (dmabuf->ossfragshift < 4) - dmabuf->ossfragshift = 4; - if (dmabuf->ossfragshift > 15) - dmabuf->ossfragshift = 15; - return 0; - - case SNDCTL_DSP_GETOSPACE: - YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd); - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - dmabuf = &state->wpcm.dmabuf; - if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - return val; - redzone = ymf_calc_lend(state->format.rate); - redzone <<= state->format.shift; - redzone *= 3; - spin_lock_irqsave(&state->unit->reg_lock, flags); - abinfo.fragsize = dmabuf->fragsize; - abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone; - abinfo.fragstotal = dmabuf->numfrag; - abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd); - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - dmabuf = &state->rpcm.dmabuf; - if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) - return val; - spin_lock_irqsave(&state->unit->reg_lock, flags); - abinfo.fragsize = dmabuf->fragsize; - abinfo.bytes = dmabuf->count; - abinfo.fragstotal = dmabuf->numfrag; - abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd); - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETCAPS: - YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd); - /* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, - p); */ - return put_user(0, p); - - case SNDCTL_DSP_GETIPTR: - YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd); - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - dmabuf = &state->rpcm.dmabuf; - spin_lock_irqsave(&state->unit->reg_lock, flags); - cinfo.bytes = dmabuf->total_bytes; - cinfo.blocks = dmabuf->count >> dmabuf->fragshift; - cinfo.ptr = dmabuf->hwptr; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n", - cinfo.ptr, cinfo.bytes); - return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETOPTR: - YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd); - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - dmabuf = &state->wpcm.dmabuf; - spin_lock_irqsave(&state->unit->reg_lock, flags); - cinfo.bytes = dmabuf->total_bytes; - cinfo.blocks = dmabuf->count >> dmabuf->fragshift; - cinfo.ptr = dmabuf->hwptr; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n", - cinfo.ptr, cinfo.bytes); - return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_SETDUPLEX: - YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd); - return 0; /* Always duplex */ - - case SOUND_PCM_READ_RATE: - YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd); - return put_user(state->format.rate, p); - - case SOUND_PCM_READ_CHANNELS: - YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd); - return put_user(state->format.voices, p); - - case SOUND_PCM_READ_BITS: - YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd); - return put_user(AFMT_S16_LE, p); - - case SNDCTL_DSP_MAPINBUF: - case SNDCTL_DSP_MAPOUTBUF: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_WRITE_FILTER: - case SOUND_PCM_READ_FILTER: - YMFDBGX("ymf_ioctl: cmd 0x%x unsupported\n", cmd); - return -ENOTTY; - - default: - /* - * Some programs mix up audio devices and ioctls - * or perhaps they expect "universal" ioctls, - * for instance we get SNDCTL_TMR_CONTINUE here. - * (mpg123 -g 100 ends here too - to be fixed.) - */ - YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd); - break; - } - return -ENOTTY; -} - -/* - * open(2) - * We use upper part of the minor to distinguish between soundcards. - * Channels are opened with a clone open. - */ -static int ymf_open(struct inode *inode, struct file *file) -{ - struct list_head *list; - ymfpci_t *unit = NULL; - int minor; - struct ymf_state *state; - int err; - - minor = iminor(inode); - if ((minor & 0x0F) == 3) { /* /dev/dspN */ - ; - } else { - return -ENXIO; - } - - unit = NULL; /* gcc warns */ - spin_lock(&ymf_devs_lock); - list_for_each(list, &ymf_devs) { - unit = list_entry(list, ymfpci_t, ymf_devs); - if (((unit->dev_audio ^ minor) & ~0x0F) == 0) - break; - } - spin_unlock(&ymf_devs_lock); - if (unit == NULL) - return -ENODEV; - - mutex_lock(&unit->open_mutex); - - if ((state = ymf_state_alloc(unit)) == NULL) { - mutex_unlock(&unit->open_mutex); - return -ENOMEM; - } - list_add_tail(&state->chain, &unit->states); - - file->private_data = state; - - /* - * ymf_read and ymf_write that we borrowed from cs46xx - * allocate buffers with prog_dmabuf(). We call prog_dmabuf - * here so that in case of DMA memory exhaustion open - * fails rather than write. - * - * XXX prog_dmabuf allocates voice. Should allocate explicitly, above. - */ - if (file->f_mode & FMODE_WRITE) { - if (!state->wpcm.dmabuf.ready) { - if ((err = prog_dmabuf(state, 0)) != 0) { - goto out_nodma; - } - } - } - if (file->f_mode & FMODE_READ) { - if (!state->rpcm.dmabuf.ready) { - if ((err = prog_dmabuf(state, 1)) != 0) { - goto out_nodma; - } - } - } - -#if 0 /* test if interrupts work */ - ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */ - ymfpci_writeb(unit, YDSXGR_TIMERCTRL, - (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN)); -#endif - mutex_unlock(&unit->open_mutex); - - return nonseekable_open(inode, file); - -out_nodma: - /* - * XXX Broken custom: "goto out_xxx" in other place is - * a nestable exception, but here it is not nestable due to semaphore. - * XXX Doubtful technique of self-describing objects.... - */ - dealloc_dmabuf(unit, &state->wpcm.dmabuf); - dealloc_dmabuf(unit, &state->rpcm.dmabuf); - ymf_pcm_free_substream(&state->wpcm); - ymf_pcm_free_substream(&state->rpcm); - - list_del(&state->chain); - kfree(state); - - mutex_unlock(&unit->open_mutex); - return err; -} - -static int ymf_release(struct inode *inode, struct file *file) -{ - struct ymf_state *state = (struct ymf_state *)file->private_data; - ymfpci_t *unit = state->unit; - -#if 0 /* test if interrupts work */ - ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0); -#endif - - mutex_lock(&unit->open_mutex); - - /* - * XXX Solve the case of O_NONBLOCK close - don't deallocate here. - * Deallocate when unloading the driver and we can wait. - */ - ymf_wait_dac(state); - ymf_stop_adc(state); /* fortunately, it's immediate */ - dealloc_dmabuf(unit, &state->wpcm.dmabuf); - dealloc_dmabuf(unit, &state->rpcm.dmabuf); - ymf_pcm_free_substream(&state->wpcm); - ymf_pcm_free_substream(&state->rpcm); - - list_del(&state->chain); - file->private_data = NULL; /* Can you tell I programmed Solaris */ - kfree(state); - - mutex_unlock(&unit->open_mutex); - - return 0; -} - -/* - * Mixer operations are based on cs46xx. - */ -static int ymf_open_mixdev(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct list_head *list; - ymfpci_t *unit; - int i; - - spin_lock(&ymf_devs_lock); - list_for_each(list, &ymf_devs) { - unit = list_entry(list, ymfpci_t, ymf_devs); - for (i = 0; i < NR_AC97; i++) { - if (unit->ac97_codec[i] != NULL && - unit->ac97_codec[i]->dev_mixer == minor) { - spin_unlock(&ymf_devs_lock); - goto match; - } - } - } - spin_unlock(&ymf_devs_lock); - return -ENODEV; - - match: - file->private_data = unit->ac97_codec[i]; - - return nonseekable_open(inode, file); -} - -static int ymf_ioctl_mixdev(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ac97_codec *codec = (struct ac97_codec *)file->private_data; - - return codec->mixer_ioctl(codec, cmd, arg); -} - -static int ymf_release_mixdev(struct inode *inode, struct file *file) -{ - return 0; -} - -static /*const*/ struct file_operations ymf_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ymf_read, - .write = ymf_write, - .poll = ymf_poll, - .ioctl = ymf_ioctl, - .mmap = ymf_mmap, - .open = ymf_open, - .release = ymf_release, -}; - -static /*const*/ struct file_operations ymf_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = ymf_ioctl_mixdev, - .open = ymf_open_mixdev, - .release = ymf_release_mixdev, -}; - -/* - */ - -static int ymf_suspend(struct pci_dev *pcidev, pm_message_t unused) -{ - struct ymf_unit *unit = pci_get_drvdata(pcidev); - unsigned long flags; - struct ymf_dmabuf *dmabuf; - struct list_head *p; - struct ymf_state *state; - struct ac97_codec *codec; - int i; - - spin_lock_irqsave(&unit->reg_lock, flags); - - unit->suspended = 1; - - for (i = 0; i < NR_AC97; i++) { - if ((codec = unit->ac97_codec[i]) != NULL) - ac97_save_state(codec); - } - - list_for_each(p, &unit->states) { - state = list_entry(p, struct ymf_state, chain); - - dmabuf = &state->wpcm.dmabuf; - dmabuf->hwptr = dmabuf->swptr = 0; - dmabuf->total_bytes = 0; - dmabuf->count = 0; - - dmabuf = &state->rpcm.dmabuf; - dmabuf->hwptr = dmabuf->swptr = 0; - dmabuf->total_bytes = 0; - dmabuf->count = 0; - } - - ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0); - ymfpci_disable_dsp(unit); - - spin_unlock_irqrestore(&unit->reg_lock, flags); - - return 0; -} - -static int ymf_resume(struct pci_dev *pcidev) -{ - struct ymf_unit *unit = pci_get_drvdata(pcidev); - unsigned long flags; - struct list_head *p; - struct ymf_state *state; - struct ac97_codec *codec; - int i; - - ymfpci_aclink_reset(unit->pci); - ymfpci_codec_ready(unit, 0, 1); /* prints diag if not ready. */ - -#ifdef CONFIG_SOUND_YMFPCI_LEGACY - /* XXX At this time the legacy registers are probably deprogrammed. */ -#endif - - ymfpci_download_image(unit); - - ymf_memload(unit); - - spin_lock_irqsave(&unit->reg_lock, flags); - - if (unit->start_count) { - ymfpci_writel(unit, YDSXGR_MODE, 3); - unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1; - } - - for (i = 0; i < NR_AC97; i++) { - if ((codec = unit->ac97_codec[i]) != NULL) - ac97_restore_state(codec); - } - - unit->suspended = 0; - list_for_each(p, &unit->states) { - state = list_entry(p, struct ymf_state, chain); - wake_up(&state->wpcm.dmabuf.wait); - wake_up(&state->rpcm.dmabuf.wait); - } - - spin_unlock_irqrestore(&unit->reg_lock, flags); - return 0; -} - -/* - * initialization routines - */ - -#ifdef CONFIG_SOUND_YMFPCI_LEGACY - -static int ymfpci_setup_legacy(ymfpci_t *unit, struct pci_dev *pcidev) -{ - int v; - int mpuio = -1, oplio = -1; - - switch (unit->iomidi) { - case 0x330: - mpuio = 0; - break; - case 0x300: - mpuio = 1; - break; - case 0x332: - mpuio = 2; - break; - case 0x334: - mpuio = 3; - break; - default: ; - } - - switch (unit->iosynth) { - case 0x388: - oplio = 0; - break; - case 0x398: - oplio = 1; - break; - case 0x3a0: - oplio = 2; - break; - case 0x3a8: - oplio = 3; - break; - default: ; - } - - if (mpuio >= 0 || oplio >= 0) { - /* 0x0020: 1 - 10 bits of I/O address decoded, 0 - 16 bits. */ - v = 0x001e; - pci_write_config_word(pcidev, PCIR_LEGCTRL, v); - - switch (pcidev->device) { - case PCI_DEVICE_ID_YAMAHA_724: - case PCI_DEVICE_ID_YAMAHA_740: - case PCI_DEVICE_ID_YAMAHA_724F: - case PCI_DEVICE_ID_YAMAHA_740C: - v = 0x8800; - if (mpuio >= 0) { v |= mpuio<<4; } - if (oplio >= 0) { v |= oplio; } - pci_write_config_word(pcidev, PCIR_ELEGCTRL, v); - break; - - case PCI_DEVICE_ID_YAMAHA_744: - case PCI_DEVICE_ID_YAMAHA_754: - v = 0x8800; - pci_write_config_word(pcidev, PCIR_ELEGCTRL, v); - if (oplio >= 0) { - pci_write_config_word(pcidev, PCIR_OPLADR, unit->iosynth); - } - if (mpuio >= 0) { - pci_write_config_word(pcidev, PCIR_MPUADR, unit->iomidi); - } - break; - - default: - printk(KERN_ERR "ymfpci: Unknown device ID: 0x%x\n", - pcidev->device); - return -EINVAL; - } - } - - return 0; -} -#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ - -static void ymfpci_aclink_reset(struct pci_dev * pci) -{ - u8 cmd; - - /* - * In the 744, 754 only 0x01 exists, 0x02 is undefined. - * It does not seem to hurt to trip both regardless of revision. - */ - pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd); - pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc); - pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03); - pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc); - - pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0); - pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0); -} - -static void ymfpci_enable_dsp(ymfpci_t *codec) -{ - ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000001); -} - -static void ymfpci_disable_dsp(ymfpci_t *codec) -{ - u32 val; - int timeout = 1000; - - val = ymfpci_readl(codec, YDSXGR_CONFIG); - if (val) - ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000000); - while (timeout-- > 0) { - val = ymfpci_readl(codec, YDSXGR_STATUS); - if ((val & 0x00000002) == 0) - break; - } -} - -#include "ymfpci_image.h" - -static void ymfpci_download_image(ymfpci_t *codec) -{ - int i, ver_1e; - u16 ctrl; - - ymfpci_writel(codec, YDSXGR_NATIVEDACOUTVOL, 0x00000000); - ymfpci_disable_dsp(codec); - ymfpci_writel(codec, YDSXGR_MODE, 0x00010000); - ymfpci_writel(codec, YDSXGR_MODE, 0x00000000); - ymfpci_writel(codec, YDSXGR_MAPOFREC, 0x00000000); - ymfpci_writel(codec, YDSXGR_MAPOFEFFECT, 0x00000000); - ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0x00000000); - ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0x00000000); - ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0x00000000); - ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL); - ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); - - /* setup DSP instruction code */ - for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) - ymfpci_writel(codec, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]); - - switch (codec->pci->device) { - case PCI_DEVICE_ID_YAMAHA_724F: - case PCI_DEVICE_ID_YAMAHA_740C: - case PCI_DEVICE_ID_YAMAHA_744: - case PCI_DEVICE_ID_YAMAHA_754: - ver_1e = 1; - break; - default: - ver_1e = 0; - } - - if (ver_1e) { - /* setup control instruction code */ - for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) - ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst1E[i]); - } else { - for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) - ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst[i]); - } - - ymfpci_enable_dsp(codec); - - /* 0.02s sounds not too bad, we may do schedule_timeout() later. */ - mdelay(20); /* seems we need some delay after downloading image.. */ -} - -static int ymfpci_memalloc(ymfpci_t *codec) -{ - unsigned int playback_ctrl_size; - unsigned int bank_size_playback; - unsigned int bank_size_capture; - unsigned int bank_size_effect; - unsigned int size; - unsigned int off; - char *ptr; - dma_addr_t pba; - int voice, bank; - - playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES; - bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2; - bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2; - bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2; - codec->work_size = YDSXG_DEFAULT_WORK_SIZE; - - size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) + - ((bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) + - ((bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) + - ((bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) + - codec->work_size; - - ptr = pci_alloc_consistent(codec->pci, size + 0xff, &pba); - if (ptr == NULL) - return -ENOMEM; - codec->dma_area_va = ptr; - codec->dma_area_ba = pba; - codec->dma_area_size = size + 0xff; - - off = (unsigned long)ptr & 0xff; - if (off) { - ptr += 0x100 - off; - pba += 0x100 - off; - } - - /* - * Hardware requires only ptr[playback_ctrl_size] zeroed, - * but in our judgement it is a wrong kind of savings, so clear it all. - */ - memset(ptr, 0, size); - - codec->ctrl_playback = (u32 *)ptr; - codec->ctrl_playback_ba = pba; - codec->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES); - ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff; - pba += (playback_ctrl_size + 0x00ff) & ~0x00ff; - - off = 0; - for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) { - codec->voices[voice].number = voice; - codec->voices[voice].bank = - (ymfpci_playback_bank_t *) (ptr + off); - codec->voices[voice].bank_ba = pba + off; - off += 2 * bank_size_playback; /* 2 banks */ - } - off = (off + 0xff) & ~0xff; - ptr += off; - pba += off; - - off = 0; - codec->bank_base_capture = pba; - for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++) - for (bank = 0; bank < 2; bank++) { - codec->bank_capture[voice][bank] = - (ymfpci_capture_bank_t *) (ptr + off); - off += bank_size_capture; - } - off = (off + 0xff) & ~0xff; - ptr += off; - pba += off; - - off = 0; - codec->bank_base_effect = pba; - for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++) - for (bank = 0; bank < 2; bank++) { - codec->bank_effect[voice][bank] = - (ymfpci_effect_bank_t *) (ptr + off); - off += bank_size_effect; - } - off = (off + 0xff) & ~0xff; - ptr += off; - pba += off; - - codec->work_base = pba; - - return 0; -} - -static void ymfpci_memfree(ymfpci_t *codec) -{ - ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0); - ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0); - ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0); - ymfpci_writel(codec, YDSXGR_WORKBASE, 0); - ymfpci_writel(codec, YDSXGR_WORKSIZE, 0); - pci_free_consistent(codec->pci, - codec->dma_area_size, codec->dma_area_va, codec->dma_area_ba); -} - -static void ymf_memload(ymfpci_t *unit) -{ - - ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, unit->ctrl_playback_ba); - ymfpci_writel(unit, YDSXGR_RECCTRLBASE, unit->bank_base_capture); - ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, unit->bank_base_effect); - ymfpci_writel(unit, YDSXGR_WORKBASE, unit->work_base); - ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2); - - /* S/PDIF output initialization */ - ymfpci_writew(unit, YDSXGR_SPDIFOUTCTRL, 0); - ymfpci_writew(unit, YDSXGR_SPDIFOUTSTATUS, - SND_PCM_AES0_CON_EMPHASIS_NONE | - (SND_PCM_AES1_CON_ORIGINAL << 8) | - (SND_PCM_AES1_CON_PCM_CODER << 8)); - - /* S/PDIF input initialization */ - ymfpci_writew(unit, YDSXGR_SPDIFINCTRL, 0); - - /* move this volume setup to mixer */ - ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff); - ymfpci_writel(unit, YDSXGR_BUF441OUTVOL, 0); - ymfpci_writel(unit, YDSXGR_NATIVEADCINVOL, 0x3fff3fff); - ymfpci_writel(unit, YDSXGR_NATIVEDACINVOL, 0x3fff3fff); -} - -static int ymf_ac97_init(ymfpci_t *unit, int num_ac97) -{ - struct ac97_codec *codec; - u16 eid; - - if ((codec = ac97_alloc_codec()) == NULL) - return -ENOMEM; - - /* initialize some basic codec information, other fields will be filled - in ac97_probe_codec */ - codec->private_data = unit; - codec->id = num_ac97; - - codec->codec_read = ymfpci_codec_read; - codec->codec_write = ymfpci_codec_write; - - if (ac97_probe_codec(codec) == 0) { - printk(KERN_ERR "ymfpci: ac97_probe_codec failed\n"); - goto out_kfree; - } - - eid = ymfpci_codec_read(codec, AC97_EXTENDED_ID); - if (eid==0xFFFF) { - printk(KERN_WARNING "ymfpci: no codec attached ?\n"); - goto out_kfree; - } - - unit->ac97_features = eid; - - if ((codec->dev_mixer = register_sound_mixer(&ymf_mixer_fops, -1)) < 0) { - printk(KERN_ERR "ymfpci: couldn't register mixer!\n"); - goto out_kfree; - } - - unit->ac97_codec[num_ac97] = codec; - - return 0; - out_kfree: - ac97_release_codec(codec); - return -ENODEV; -} - -#ifdef CONFIG_SOUND_YMFPCI_LEGACY -# ifdef MODULE -static int mpu_io; -static int synth_io; -module_param(mpu_io, int, 0); -module_param(synth_io, int, 0); -# else -static int mpu_io = 0x330; -static int synth_io = 0x388; -# endif -static int assigned; -#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ - -static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent) -{ - u16 ctrl; - unsigned long base; - ymfpci_t *codec; - - int err; - - if ((err = pci_enable_device(pcidev)) != 0) { - printk(KERN_ERR "ymfpci: pci_enable_device failed\n"); - return err; - } - base = pci_resource_start(pcidev, 0); - - if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) { - printk(KERN_ERR "ymfpci: no core\n"); - return -ENOMEM; - } - memset(codec, 0, sizeof(*codec)); - - spin_lock_init(&codec->reg_lock); - spin_lock_init(&codec->voice_lock); - spin_lock_init(&codec->ac97_lock); - mutex_init(&codec->open_mutex); - INIT_LIST_HEAD(&codec->states); - codec->pci = pcidev; - - pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev); - - if (request_mem_region(base, 0x8000, "ymfpci") == NULL) { - printk(KERN_ERR "ymfpci: unable to request mem region\n"); - goto out_free; - } - - if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) { - printk(KERN_ERR "ymfpci: unable to map registers\n"); - goto out_release_region; - } - - pci_set_master(pcidev); - - printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n", - (char *)ent->driver_data, base, pcidev->irq); - - ymfpci_aclink_reset(pcidev); - if (ymfpci_codec_ready(codec, 0, 1) < 0) - goto out_unmap; - -#ifdef CONFIG_SOUND_YMFPCI_LEGACY - if (assigned == 0) { - codec->iomidi = mpu_io; - codec->iosynth = synth_io; - if (ymfpci_setup_legacy(codec, pcidev) < 0) - goto out_unmap; - assigned = 1; - } -#endif - - ymfpci_download_image(codec); - - if (ymfpci_memalloc(codec) < 0) - goto out_disable_dsp; - ymf_memload(codec); - - if (request_irq(pcidev->irq, ymf_interrupt, IRQF_SHARED, "ymfpci", codec) != 0) { - printk(KERN_ERR "ymfpci: unable to request IRQ %d\n", - pcidev->irq); - goto out_memfree; - } - - /* register /dev/dsp */ - if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) { - printk(KERN_ERR "ymfpci: unable to register dsp\n"); - goto out_free_irq; - } - - /* - * Poke just the primary for the moment. - */ - if ((err = ymf_ac97_init(codec, 0)) != 0) - goto out_unregister_sound_dsp; - -#ifdef CONFIG_SOUND_YMFPCI_LEGACY - codec->opl3_data.name = "ymfpci"; - codec->mpu_data.name = "ymfpci"; - - codec->opl3_data.io_base = codec->iosynth; - codec->opl3_data.irq = -1; - - codec->mpu_data.io_base = codec->iomidi; - codec->mpu_data.irq = -1; /* May be different from our PCI IRQ. */ - - if (codec->iomidi) { - if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) { - codec->iomidi = 0; /* XXX kludge */ - } - } -#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ - - /* put it into driver list */ - spin_lock(&ymf_devs_lock); - list_add_tail(&codec->ymf_devs, &ymf_devs); - spin_unlock(&ymf_devs_lock); - pci_set_drvdata(pcidev, codec); - - return 0; - - out_unregister_sound_dsp: - unregister_sound_dsp(codec->dev_audio); - out_free_irq: - free_irq(pcidev->irq, codec); - out_memfree: - ymfpci_memfree(codec); - out_disable_dsp: - ymfpci_disable_dsp(codec); - ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL); - ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); - ymfpci_writel(codec, YDSXGR_STATUS, ~0); - out_unmap: - iounmap(codec->reg_area_virt); - out_release_region: - release_mem_region(pci_resource_start(pcidev, 0), 0x8000); - out_free: - if (codec->ac97_codec[0]) - ac97_release_codec(codec->ac97_codec[0]); - return -ENODEV; -} - -static void __devexit ymf_remove_one(struct pci_dev *pcidev) -{ - __u16 ctrl; - ymfpci_t *codec = pci_get_drvdata(pcidev); - - /* remove from list of devices */ - spin_lock(&ymf_devs_lock); - list_del(&codec->ymf_devs); - spin_unlock(&ymf_devs_lock); - - unregister_sound_mixer(codec->ac97_codec[0]->dev_mixer); - ac97_release_codec(codec->ac97_codec[0]); - unregister_sound_dsp(codec->dev_audio); - free_irq(pcidev->irq, codec); - ymfpci_memfree(codec); - ymfpci_writel(codec, YDSXGR_STATUS, ~0); - ymfpci_disable_dsp(codec); - ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL); - ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); - iounmap(codec->reg_area_virt); - release_mem_region(pci_resource_start(pcidev, 0), 0x8000); -#ifdef CONFIG_SOUND_YMFPCI_LEGACY - if (codec->iomidi) { - unload_uart401(&codec->mpu_data); - } -#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ -} - -MODULE_AUTHOR("Jaroslav Kysela"); -MODULE_DESCRIPTION("Yamaha YMF7xx PCI Audio"); -MODULE_LICENSE("GPL"); - -static struct pci_driver ymfpci_driver = { - .name = "ymfpci", - .id_table = ymf_id_tbl, - .probe = ymf_probe_one, - .remove = __devexit_p(ymf_remove_one), - .suspend = ymf_suspend, - .resume = ymf_resume -}; - -static int __init ymf_init_module(void) -{ - return pci_register_driver(&ymfpci_driver); -} - -static void __exit ymf_cleanup_module (void) -{ - pci_unregister_driver(&ymfpci_driver); -} - -module_init(ymf_init_module); -module_exit(ymf_cleanup_module); diff --git a/sound/oss/ymfpci.h b/sound/oss/ymfpci.h deleted file mode 100644 index ac1785f2b7e7..000000000000 --- a/sound/oss/ymfpci.h +++ /dev/null @@ -1,361 +0,0 @@ -#ifndef __YMFPCI_H -#define __YMFPCI_H - -/* - * Copyright (c) by Jaroslav Kysela - * Definitions for Yahama YMF724/740/744/754 chips - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ -#include -#include - -/* - * Direct registers - */ - -/* #define YMFREG(codec, reg) (codec->port + YDSXGR_##reg) */ - -#define YDSXGR_INTFLAG 0x0004 -#define YDSXGR_ACTIVITY 0x0006 -#define YDSXGR_GLOBALCTRL 0x0008 -#define YDSXGR_ZVCTRL 0x000A -#define YDSXGR_TIMERCTRL 0x0010 -#define YDSXGR_TIMERCTRL_TEN 0x0001 -#define YDSXGR_TIMERCTRL_TIEN 0x0002 -#define YDSXGR_TIMERCOUNT 0x0012 -#define YDSXGR_SPDIFOUTCTRL 0x0018 -#define YDSXGR_SPDIFOUTSTATUS 0x001C -#define YDSXGR_EEPROMCTRL 0x0020 -#define YDSXGR_SPDIFINCTRL 0x0034 -#define YDSXGR_SPDIFINSTATUS 0x0038 -#define YDSXGR_DSPPROGRAMDL 0x0048 -#define YDSXGR_DLCNTRL 0x004C -#define YDSXGR_GPIOININTFLAG 0x0050 -#define YDSXGR_GPIOININTENABLE 0x0052 -#define YDSXGR_GPIOINSTATUS 0x0054 -#define YDSXGR_GPIOOUTCTRL 0x0056 -#define YDSXGR_GPIOFUNCENABLE 0x0058 -#define YDSXGR_GPIOTYPECONFIG 0x005A -#define YDSXGR_AC97CMDDATA 0x0060 -#define YDSXGR_AC97CMDADR 0x0062 -#define YDSXGR_PRISTATUSDATA 0x0064 -#define YDSXGR_PRISTATUSADR 0x0066 -#define YDSXGR_SECSTATUSDATA 0x0068 -#define YDSXGR_SECSTATUSADR 0x006A -#define YDSXGR_SECCONFIG 0x0070 -#define YDSXGR_LEGACYOUTVOL 0x0080 -#define YDSXGR_LEGACYOUTVOLL 0x0080 -#define YDSXGR_LEGACYOUTVOLR 0x0082 -#define YDSXGR_NATIVEDACOUTVOL 0x0084 -#define YDSXGR_NATIVEDACOUTVOLL 0x0084 -#define YDSXGR_NATIVEDACOUTVOLR 0x0086 -#define YDSXGR_SPDIFOUTVOL 0x0088 -#define YDSXGR_SPDIFOUTVOLL 0x0088 -#define YDSXGR_SPDIFOUTVOLR 0x008A -#define YDSXGR_AC3OUTVOL 0x008C -#define YDSXGR_AC3OUTVOLL 0x008C -#define YDSXGR_AC3OUTVOLR 0x008E -#define YDSXGR_PRIADCOUTVOL 0x0090 -#define YDSXGR_PRIADCOUTVOLL 0x0090 -#define YDSXGR_PRIADCOUTVOLR 0x0092 -#define YDSXGR_LEGACYLOOPVOL 0x0094 -#define YDSXGR_LEGACYLOOPVOLL 0x0094 -#define YDSXGR_LEGACYLOOPVOLR 0x0096 -#define YDSXGR_NATIVEDACLOOPVOL 0x0098 -#define YDSXGR_NATIVEDACLOOPVOLL 0x0098 -#define YDSXGR_NATIVEDACLOOPVOLR 0x009A -#define YDSXGR_SPDIFLOOPVOL 0x009C -#define YDSXGR_SPDIFLOOPVOLL 0x009E -#define YDSXGR_SPDIFLOOPVOLR 0x009E -#define YDSXGR_AC3LOOPVOL 0x00A0 -#define YDSXGR_AC3LOOPVOLL 0x00A0 -#define YDSXGR_AC3LOOPVOLR 0x00A2 -#define YDSXGR_PRIADCLOOPVOL 0x00A4 -#define YDSXGR_PRIADCLOOPVOLL 0x00A4 -#define YDSXGR_PRIADCLOOPVOLR 0x00A6 -#define YDSXGR_NATIVEADCINVOL 0x00A8 -#define YDSXGR_NATIVEADCINVOLL 0x00A8 -#define YDSXGR_NATIVEADCINVOLR 0x00AA -#define YDSXGR_NATIVEDACINVOL 0x00AC -#define YDSXGR_NATIVEDACINVOLL 0x00AC -#define YDSXGR_NATIVEDACINVOLR 0x00AE -#define YDSXGR_BUF441OUTVOL 0x00B0 -#define YDSXGR_BUF441OUTVOLL 0x00B0 -#define YDSXGR_BUF441OUTVOLR 0x00B2 -#define YDSXGR_BUF441LOOPVOL 0x00B4 -#define YDSXGR_BUF441LOOPVOLL 0x00B4 -#define YDSXGR_BUF441LOOPVOLR 0x00B6 -#define YDSXGR_SPDIFOUTVOL2 0x00B8 -#define YDSXGR_SPDIFOUTVOL2L 0x00B8 -#define YDSXGR_SPDIFOUTVOL2R 0x00BA -#define YDSXGR_SPDIFLOOPVOL2 0x00BC -#define YDSXGR_SPDIFLOOPVOL2L 0x00BC -#define YDSXGR_SPDIFLOOPVOL2R 0x00BE -#define YDSXGR_ADCSLOTSR 0x00C0 -#define YDSXGR_RECSLOTSR 0x00C4 -#define YDSXGR_ADCFORMAT 0x00C8 -#define YDSXGR_RECFORMAT 0x00CC -#define YDSXGR_P44SLOTSR 0x00D0 -#define YDSXGR_STATUS 0x0100 -#define YDSXGR_CTRLSELECT 0x0104 -#define YDSXGR_MODE 0x0108 -#define YDSXGR_SAMPLECOUNT 0x010C -#define YDSXGR_NUMOFSAMPLES 0x0110 -#define YDSXGR_CONFIG 0x0114 -#define YDSXGR_PLAYCTRLSIZE 0x0140 -#define YDSXGR_RECCTRLSIZE 0x0144 -#define YDSXGR_EFFCTRLSIZE 0x0148 -#define YDSXGR_WORKSIZE 0x014C -#define YDSXGR_MAPOFREC 0x0150 -#define YDSXGR_MAPOFEFFECT 0x0154 -#define YDSXGR_PLAYCTRLBASE 0x0158 -#define YDSXGR_RECCTRLBASE 0x015C -#define YDSXGR_EFFCTRLBASE 0x0160 -#define YDSXGR_WORKBASE 0x0164 -#define YDSXGR_DSPINSTRAM 0x1000 -#define YDSXGR_CTRLINSTRAM 0x4000 - -#define YDSXG_AC97READCMD 0x8000 -#define YDSXG_AC97WRITECMD 0x0000 - -#define PCIR_LEGCTRL 0x40 -#define PCIR_ELEGCTRL 0x42 -#define PCIR_DSXGCTRL 0x48 -#define PCIR_DSXPWRCTRL1 0x4a -#define PCIR_DSXPWRCTRL2 0x4e -#define PCIR_OPLADR 0x60 -#define PCIR_SBADR 0x62 -#define PCIR_MPUADR 0x64 - -#define YDSXG_DSPLENGTH 0x0080 -#define YDSXG_CTRLLENGTH 0x3000 - -#define YDSXG_DEFAULT_WORK_SIZE 0x0400 - -#define YDSXG_PLAYBACK_VOICES 64 -#define YDSXG_CAPTURE_VOICES 2 -#define YDSXG_EFFECT_VOICES 5 - -/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ -#define NR_AC97 2 - -#define YMF_SAMPF 256 /* Samples per frame @48000 */ - -/* - * The slot/voice control bank (2 of these per voice) - */ - -typedef struct stru_ymfpci_playback_bank { - u32 format; - u32 loop_default; - u32 base; /* 32-bit address */ - u32 loop_start; /* 32-bit offset */ - u32 loop_end; /* 32-bit offset */ - u32 loop_frac; /* 8-bit fraction - loop_start */ - u32 delta_end; /* pitch delta end */ - u32 lpfK_end; - u32 eg_gain_end; - u32 left_gain_end; - u32 right_gain_end; - u32 eff1_gain_end; - u32 eff2_gain_end; - u32 eff3_gain_end; - u32 lpfQ; - u32 status; /* P3: Always 0 for some reason. */ - u32 num_of_frames; - u32 loop_count; - u32 start; /* P3: J. reads this to know where chip is. */ - u32 start_frac; - u32 delta; - u32 lpfK; - u32 eg_gain; - u32 left_gain; - u32 right_gain; - u32 eff1_gain; - u32 eff2_gain; - u32 eff3_gain; - u32 lpfD1; - u32 lpfD2; -} ymfpci_playback_bank_t; - -typedef struct stru_ymfpci_capture_bank { - u32 base; /* 32-bit address (aligned at 4) */ - u32 loop_end; /* size in BYTES (aligned at 4) */ - u32 start; /* 32-bit offset */ - u32 num_of_loops; /* counter */ -} ymfpci_capture_bank_t; - -typedef struct stru_ymfpci_effect_bank { - u32 base; /* 32-bit address */ - u32 loop_end; /* 32-bit offset */ - u32 start; /* 32-bit offset */ - u32 temp; -} ymfpci_effect_bank_t; - -typedef struct ymf_voice ymfpci_voice_t; -/* - * Throughout the code Yaroslav names YMF unit pointer "codec" - * even though it does not correspond to any codec. Must be historic. - * We replace it with "unit" over time. - * AC97 parts use "codec" to denote a codec, naturally. - */ -typedef struct ymf_unit ymfpci_t; - -typedef enum { - YMFPCI_PCM, - YMFPCI_SYNTH, - YMFPCI_MIDI -} ymfpci_voice_type_t; - -struct ymf_voice { - // ymfpci_t *codec; - int number; - char use, pcm, synth, midi; // bool - ymfpci_playback_bank_t *bank; - struct ymf_pcm *ypcm; - dma_addr_t bank_ba; -}; - -struct ymf_capture { - // struct ymf_unit *unit; - int use; - ymfpci_capture_bank_t *bank; - struct ymf_pcm *ypcm; -}; - -struct ymf_unit { - u8 rev; /* PCI revision */ - void __iomem *reg_area_virt; - void *dma_area_va; - dma_addr_t dma_area_ba; - unsigned int dma_area_size; - - dma_addr_t bank_base_capture; - dma_addr_t bank_base_effect; - dma_addr_t work_base; - unsigned int work_size; - - u32 *ctrl_playback; - dma_addr_t ctrl_playback_ba; - ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2]; - ymfpci_capture_bank_t *bank_capture[YDSXG_CAPTURE_VOICES][2]; - ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2]; - - int start_count; - int suspended; - - u32 active_bank; - struct ymf_voice voices[YDSXG_PLAYBACK_VOICES]; - struct ymf_capture capture[YDSXG_CAPTURE_VOICES]; - - struct ac97_codec *ac97_codec[NR_AC97]; - u16 ac97_features; - - struct pci_dev *pci; - -#ifdef CONFIG_SOUND_YMFPCI_LEGACY - /* legacy hardware resources */ - unsigned int iosynth, iomidi; - struct address_info opl3_data, mpu_data; -#endif - - spinlock_t reg_lock; - spinlock_t voice_lock; - spinlock_t ac97_lock; - - /* soundcore stuff */ - int dev_audio; - struct mutex open_mutex; - - struct list_head ymf_devs; - struct list_head states; /* List of states for this unit */ -}; - -struct ymf_dmabuf { - dma_addr_t dma_addr; - void *rawbuf; - unsigned buforder; - - /* OSS buffer management stuff */ - unsigned numfrag; - unsigned fragshift; - - /* our buffer acts like a circular ring */ - unsigned hwptr; /* where dma last started */ - unsigned swptr; /* where driver last clear/filled */ - int count; /* fill count */ - unsigned total_bytes; /* total bytes dmaed by hardware */ - - wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */ - - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dmasize; /* Total rawbuf[] size */ - - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; -}; - -struct ymf_pcm_format { - int format; /* OSS format */ - int rate; /* rate in Hz */ - int voices; /* number of voices */ - int shift; /* redundant, computed from the above */ -}; - -typedef enum { - PLAYBACK_VOICE, - CAPTURE_REC, - CAPTURE_AC97, - EFFECT_DRY_LEFT, - EFFECT_DRY_RIGHT, - EFFECT_EFF1, - EFFECT_EFF2, - EFFECT_EFF3 -} ymfpci_pcm_type_t; - -/* This is variant record, but we hate unions. Little waste on pointers []. */ -struct ymf_pcm { - ymfpci_pcm_type_t type; - struct ymf_state *state; - - ymfpci_voice_t *voices[2]; - int capture_bank_number; - - struct ymf_dmabuf dmabuf; - int running; - int spdif; -}; - -/* - * "Software" or virtual channel, an instance of opened /dev/dsp. - * It may have two physical channels (pcms) for duplex operations. - */ - -struct ymf_state { - struct list_head chain; - struct ymf_unit *unit; /* backpointer */ - struct ymf_pcm rpcm, wpcm; - struct ymf_pcm_format format; -}; - -#endif /* __YMFPCI_H */ diff --git a/sound/oss/ymfpci_image.h b/sound/oss/ymfpci_image.h deleted file mode 100644 index 112f2fff6c8e..000000000000 --- a/sound/oss/ymfpci_image.h +++ /dev/null @@ -1,1565 +0,0 @@ -#ifndef _HWMCODE_ -#define _HWMCODE_ - -static u32 DspInst[YDSXG_DSPLENGTH / 4] = { - 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, - 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, - 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, - 0x0000c07b, 0x00050c3f, 0x0121503c, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000 -}; - -static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = { - 0x000007, 0x240007, 0x0C0007, 0x1C0007, - 0x060007, 0x700002, 0x000020, 0x030040, - 0x007104, 0x004286, 0x030040, 0x000F0D, - 0x000810, 0x20043A, 0x000282, 0x00020D, - 0x000810, 0x20043A, 0x001282, 0x200E82, - 0x001A82, 0x032D0D, 0x000810, 0x10043A, - 0x02D38D, 0x000810, 0x18043A, 0x00010D, - 0x020015, 0x0000FD, 0x000020, 0x038860, - 0x039060, 0x038060, 0x038040, 0x038040, - 0x038040, 0x018040, 0x000A7D, 0x038040, - 0x038040, 0x018040, 0x200402, 0x000882, - 0x08001A, 0x000904, 0x015986, 0x000007, - 0x260007, 0x000007, 0x000007, 0x018A06, - 0x000007, 0x030C8D, 0x000810, 0x18043A, - 0x260007, 0x00087D, 0x018042, 0x00160A, - 0x04A206, 0x000007, 0x00218D, 0x000810, - 0x08043A, 0x21C206, 0x000007, 0x0007FD, - 0x018042, 0x08000A, 0x000904, 0x029386, - 0x000195, 0x090D04, 0x000007, 0x000820, - 0x0000F5, 0x000B7D, 0x01F060, 0x0000FD, - 0x032206, 0x018040, 0x000A7D, 0x038042, - 0x13804A, 0x18000A, 0x001820, 0x059060, - 0x058860, 0x018040, 0x0000FD, 0x018042, - 0x70000A, 0x000115, 0x071144, 0x032386, - 0x030000, 0x007020, 0x034A06, 0x018040, - 0x00348D, 0x000810, 0x08043A, 0x21EA06, - 0x000007, 0x02D38D, 0x000810, 0x18043A, - 0x018206, 0x000007, 0x240007, 0x000F8D, - 0x000810, 0x00163A, 0x002402, 0x005C02, - 0x0028FD, 0x000020, 0x018040, 0x08000D, - 0x000815, 0x510984, 0x000007, 0x00004D, - 0x000E5D, 0x000E02, 0x00418D, 0x000810, - 0x08043A, 0x2C8A06, 0x000007, 0x00008D, - 0x000924, 0x000F02, 0x00458D, 0x000810, - 0x08043A, 0x2C8A06, 0x000007, 0x00387D, - 0x018042, 0x08000A, 0x001015, 0x010984, - 0x018386, 0x000007, 0x01AA06, 0x000007, - 0x0008FD, 0x018042, 0x18000A, 0x001904, - 0x218086, 0x280007, 0x001810, 0x28043A, - 0x280C02, 0x00000D, 0x000810, 0x28143A, - 0x08808D, 0x000820, 0x0002FD, 0x018040, - 0x200007, 0x00020D, 0x189904, 0x000007, - 0x00402D, 0x0000BD, 0x0002FD, 0x018042, - 0x08000A, 0x000904, 0x055A86, 0x000007, - 0x000100, 0x000A20, 0x00047D, 0x018040, - 0x018042, 0x20000A, 0x003015, 0x012144, - 0x034986, 0x000007, 0x002104, 0x034986, - 0x000007, 0x000F8D, 0x000810, 0x280C3A, - 0x023944, 0x06C986, 0x000007, 0x001810, - 0x28043A, 0x08810D, 0x000820, 0x0002FD, - 0x018040, 0x200007, 0x002810, 0x78003A, - 0x00688D, 0x000810, 0x08043A, 0x288A06, - 0x000007, 0x00400D, 0x001015, 0x189904, - 0x292904, 0x393904, 0x000007, 0x060206, - 0x000007, 0x0004F5, 0x00007D, 0x000020, - 0x00008D, 0x010860, 0x018040, 0x00047D, - 0x038042, 0x21804A, 0x18000A, 0x021944, - 0x215886, 0x000007, 0x004075, 0x71F104, - 0x000007, 0x010042, 0x28000A, 0x002904, - 0x212086, 0x000007, 0x003C0D, 0x30A904, - 0x000007, 0x00077D, 0x018042, 0x08000A, - 0x000904, 0x07DA86, 0x00057D, 0x002820, - 0x03B060, 0x07F206, 0x018040, 0x003020, - 0x03A860, 0x018040, 0x0002FD, 0x018042, - 0x08000A, 0x000904, 0x07FA86, 0x000007, - 0x00057D, 0x018042, 0x28040A, 0x000E8D, - 0x000810, 0x280C3A, 0x00000D, 0x000810, - 0x28143A, 0x09000D, 0x000820, 0x0002FD, - 0x018040, 0x200007, 0x003DFD, 0x000020, - 0x018040, 0x00107D, 0x008D8D, 0x000810, - 0x08043A, 0x288A06, 0x000007, 0x000815, - 0x08001A, 0x010984, 0x095186, 0x00137D, - 0x200500, 0x280F20, 0x338F60, 0x3B8F60, - 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60, - 0x038A60, 0x018040, 0x007FBD, 0x383DC4, - 0x000007, 0x001A7D, 0x001375, 0x018042, - 0x09004A, 0x10000A, 0x0B8D04, 0x139504, - 0x000007, 0x000820, 0x019060, 0x001104, - 0x212086, 0x010040, 0x0017FD, 0x018042, - 0x08000A, 0x000904, 0x212286, 0x000007, - 0x00197D, 0x038042, 0x09804A, 0x10000A, - 0x000924, 0x001664, 0x0011FD, 0x038042, - 0x2B804A, 0x19804A, 0x00008D, 0x218944, - 0x000007, 0x002244, 0x0AE186, 0x000007, - 0x001A64, 0x002A24, 0x00197D, 0x080102, - 0x100122, 0x000820, 0x039060, 0x018040, - 0x003DFD, 0x00008D, 0x000820, 0x018040, - 0x001375, 0x001A7D, 0x010042, 0x09804A, - 0x10000A, 0x00021D, 0x0189E4, 0x2992E4, - 0x309144, 0x000007, 0x00060D, 0x000A15, - 0x000C1D, 0x001025, 0x00A9E4, 0x012BE4, - 0x000464, 0x01B3E4, 0x0232E4, 0x000464, - 0x000464, 0x000464, 0x000464, 0x00040D, - 0x08B1C4, 0x000007, 0x000820, 0x000BF5, - 0x030040, 0x00197D, 0x038042, 0x09804A, - 0x000A24, 0x08000A, 0x080E64, 0x000007, - 0x100122, 0x000820, 0x031060, 0x010040, - 0x0064AC, 0x00027D, 0x000020, 0x018040, - 0x00107D, 0x018042, 0x0011FD, 0x3B804A, - 0x09804A, 0x20000A, 0x000095, 0x1A1144, - 0x00A144, 0x0D2086, 0x00040D, 0x00B984, - 0x0D2186, 0x0018FD, 0x018042, 0x0010FD, - 0x09804A, 0x28000A, 0x000095, 0x010924, - 0x002A64, 0x0D1186, 0x000007, 0x002904, - 0x0D2286, 0x000007, 0x0D2A06, 0x080002, - 0x00008D, 0x00387D, 0x000820, 0x018040, - 0x00127D, 0x018042, 0x10000A, 0x003904, - 0x0DD186, 0x00080D, 0x7FFFB5, 0x00B984, - 0x0DA186, 0x000025, 0x0E7A06, 0x00002D, - 0x000015, 0x00082D, 0x02C78D, 0x000820, - 0x0EC206, 0x00000D, 0x7F8035, 0x00B984, - 0x0E7186, 0x400025, 0x00008D, 0x110944, - 0x000007, 0x00018D, 0x109504, 0x000007, - 0x009164, 0x000424, 0x000424, 0x000424, - 0x100102, 0x280002, 0x02C68D, 0x000820, - 0x0EC206, 0x00018D, 0x00042D, 0x00008D, - 0x109504, 0x000007, 0x00020D, 0x109184, - 0x000007, 0x02C70D, 0x000820, 0x00008D, - 0x0038FD, 0x018040, 0x003BFD, 0x001020, - 0x03A860, 0x000815, 0x313184, 0x212184, - 0x000007, 0x03B060, 0x03A060, 0x018040, - 0x0022FD, 0x000095, 0x010924, 0x000424, - 0x000424, 0x001264, 0x100102, 0x000820, - 0x039060, 0x018040, 0x001924, 0x00FB8D, - 0x00397D, 0x000820, 0x058040, 0x038042, - 0x09844A, 0x000606, 0x08040A, 0x000424, - 0x000424, 0x00117D, 0x018042, 0x08000A, - 0x000A24, 0x280502, 0x280C02, 0x09800D, - 0x000820, 0x0002FD, 0x018040, 0x200007, - 0x0022FD, 0x018042, 0x08000A, 0x000095, - 0x280DC4, 0x011924, 0x00197D, 0x018042, - 0x0011FD, 0x09804A, 0x10000A, 0x0000B5, - 0x113144, 0x0A8D04, 0x000007, 0x080A44, - 0x129504, 0x000007, 0x0023FD, 0x001020, - 0x038040, 0x101244, 0x000007, 0x000820, - 0x039060, 0x018040, 0x0002FD, 0x018042, - 0x08000A, 0x000904, 0x10FA86, 0x000007, - 0x003BFD, 0x000100, 0x000A10, 0x0B807A, - 0x13804A, 0x090984, 0x000007, 0x000095, - 0x013D04, 0x118086, 0x10000A, 0x100002, - 0x090984, 0x000007, 0x038042, 0x11804A, - 0x090D04, 0x000007, 0x10000A, 0x090D84, - 0x000007, 0x00257D, 0x000820, 0x018040, - 0x00010D, 0x000810, 0x28143A, 0x00127D, - 0x018042, 0x20000A, 0x00197D, 0x018042, - 0x00117D, 0x31804A, 0x10000A, 0x003124, - 0x01280D, 0x00397D, 0x000820, 0x058040, - 0x038042, 0x09844A, 0x000606, 0x08040A, - 0x300102, 0x003124, 0x000424, 0x000424, - 0x001224, 0x280502, 0x001A4C, 0x130186, - 0x700002, 0x00002D, 0x030000, 0x00387D, - 0x018042, 0x10000A, 0x132A06, 0x002124, - 0x0000AD, 0x100002, 0x00010D, 0x000924, - 0x006B24, 0x01368D, 0x00397D, 0x000820, - 0x058040, 0x038042, 0x09844A, 0x000606, - 0x08040A, 0x003264, 0x00008D, 0x000A24, - 0x001020, 0x00227D, 0x018040, 0x013C0D, - 0x000810, 0x08043A, 0x29D206, 0x000007, - 0x002820, 0x00207D, 0x018040, 0x00117D, - 0x038042, 0x13804A, 0x33800A, 0x00387D, - 0x018042, 0x08000A, 0x000904, 0x163A86, - 0x000007, 0x00008D, 0x030964, 0x01478D, - 0x00397D, 0x000820, 0x058040, 0x038042, - 0x09844A, 0x000606, 0x08040A, 0x380102, - 0x000424, 0x000424, 0x001224, 0x0002FD, - 0x018042, 0x08000A, 0x000904, 0x14A286, - 0x000007, 0x280502, 0x001A4C, 0x163986, - 0x000007, 0x032164, 0x00632C, 0x003DFD, - 0x018042, 0x08000A, 0x000095, 0x090904, - 0x000007, 0x000820, 0x001A4C, 0x156186, - 0x018040, 0x030000, 0x157A06, 0x002124, - 0x00010D, 0x000924, 0x006B24, 0x015B8D, - 0x00397D, 0x000820, 0x058040, 0x038042, - 0x09844A, 0x000606, 0x08040A, 0x003A64, - 0x000095, 0x001224, 0x0002FD, 0x018042, - 0x08000A, 0x000904, 0x15DA86, 0x000007, - 0x01628D, 0x000810, 0x08043A, 0x29D206, - 0x000007, 0x14D206, 0x000007, 0x007020, - 0x08010A, 0x10012A, 0x0020FD, 0x038860, - 0x039060, 0x018040, 0x00227D, 0x018042, - 0x003DFD, 0x08000A, 0x31844A, 0x000904, - 0x16D886, 0x18008B, 0x00008D, 0x189904, - 0x00312C, 0x17AA06, 0x000007, 0x00324C, - 0x173386, 0x000007, 0x001904, 0x173086, - 0x000007, 0x000095, 0x199144, 0x00222C, - 0x003124, 0x00636C, 0x000E3D, 0x001375, - 0x000BFD, 0x010042, 0x09804A, 0x10000A, - 0x038AEC, 0x0393EC, 0x00224C, 0x17A986, - 0x000007, 0x00008D, 0x189904, 0x00226C, - 0x00322C, 0x30050A, 0x301DAB, 0x002083, - 0x0018FD, 0x018042, 0x08000A, 0x018924, - 0x300502, 0x001083, 0x001875, 0x010042, - 0x10000A, 0x00008D, 0x010924, 0x001375, - 0x330542, 0x330CCB, 0x332CCB, 0x3334CB, - 0x333CCB, 0x3344CB, 0x334CCB, 0x3354CB, - 0x305C8B, 0x006083, 0x0002F5, 0x010042, - 0x08000A, 0x000904, 0x187A86, 0x000007, - 0x001E2D, 0x0005FD, 0x018042, 0x08000A, - 0x028924, 0x280502, 0x00060D, 0x000810, - 0x280C3A, 0x00008D, 0x000810, 0x28143A, - 0x0A808D, 0x000820, 0x0002F5, 0x010040, - 0x220007, 0x001275, 0x030042, 0x21004A, - 0x00008D, 0x1A0944, 0x000007, 0x01980D, - 0x000810, 0x08043A, 0x2B2206, 0x000007, - 0x0001F5, 0x030042, 0x0D004A, 0x10000A, - 0x089144, 0x000007, 0x000820, 0x010040, - 0x0025F5, 0x0A3144, 0x000007, 0x000820, - 0x032860, 0x030040, 0x00217D, 0x038042, - 0x0B804A, 0x10000A, 0x000820, 0x031060, - 0x030040, 0x00008D, 0x000124, 0x00012C, - 0x000E64, 0x001A64, 0x00636C, 0x08010A, - 0x10012A, 0x000820, 0x031060, 0x030040, - 0x0020FD, 0x018042, 0x08000A, 0x00227D, - 0x018042, 0x10000A, 0x000820, 0x031060, - 0x030040, 0x00197D, 0x018042, 0x08000A, - 0x0022FD, 0x038042, 0x10000A, 0x000820, - 0x031060, 0x030040, 0x090D04, 0x000007, - 0x000820, 0x030040, 0x038042, 0x0B804A, - 0x10000A, 0x000820, 0x031060, 0x030040, - 0x038042, 0x13804A, 0x19804A, 0x110D04, - 0x198D04, 0x000007, 0x08000A, 0x001020, - 0x031860, 0x030860, 0x030040, 0x00008D, - 0x0B0944, 0x000007, 0x000820, 0x010040, - 0x0005F5, 0x030042, 0x08000A, 0x000820, - 0x010040, 0x0000F5, 0x010042, 0x08000A, - 0x000904, 0x1C6086, 0x001E75, 0x030042, - 0x01044A, 0x000C0A, 0x1C7206, 0x000007, - 0x000402, 0x000C02, 0x00177D, 0x001AF5, - 0x018042, 0x03144A, 0x031C4A, 0x03244A, - 0x032C4A, 0x03344A, 0x033C4A, 0x03444A, - 0x004C0A, 0x00043D, 0x0013F5, 0x001AFD, - 0x030042, 0x0B004A, 0x1B804A, 0x13804A, - 0x20000A, 0x089144, 0x19A144, 0x0389E4, - 0x0399EC, 0x005502, 0x005D0A, 0x030042, - 0x0B004A, 0x1B804A, 0x13804A, 0x20000A, - 0x089144, 0x19A144, 0x0389E4, 0x0399EC, - 0x006502, 0x006D0A, 0x030042, 0x0B004A, - 0x19004A, 0x2B804A, 0x13804A, 0x21804A, - 0x30000A, 0x089144, 0x19A144, 0x2AB144, - 0x0389E4, 0x0399EC, 0x007502, 0x007D0A, - 0x03A9E4, 0x000702, 0x00107D, 0x000415, - 0x018042, 0x08000A, 0x0109E4, 0x000F02, - 0x002AF5, 0x0019FD, 0x010042, 0x09804A, - 0x10000A, 0x000934, 0x001674, 0x0029F5, - 0x010042, 0x10000A, 0x00917C, 0x002075, - 0x010042, 0x08000A, 0x000904, 0x1ED286, - 0x0026F5, 0x0027F5, 0x030042, 0x09004A, - 0x10000A, 0x000A3C, 0x00167C, 0x001A75, - 0x000BFD, 0x010042, 0x51804A, 0x48000A, - 0x160007, 0x001075, 0x010042, 0x282C0A, - 0x281D12, 0x282512, 0x001F32, 0x1E0007, - 0x0E0007, 0x001975, 0x010042, 0x002DF5, - 0x0D004A, 0x10000A, 0x009144, 0x1FB286, - 0x010042, 0x28340A, 0x000E5D, 0x00008D, - 0x000375, 0x000820, 0x010040, 0x05D2F4, - 0x54D104, 0x00735C, 0x205386, 0x000007, - 0x0C0007, 0x080007, 0x0A0007, 0x02040D, - 0x000810, 0x08043A, 0x332206, 0x000007, - 0x205A06, 0x000007, 0x080007, 0x002275, - 0x010042, 0x20000A, 0x002104, 0x212086, - 0x001E2D, 0x0002F5, 0x010042, 0x08000A, - 0x000904, 0x209286, 0x000007, 0x002010, - 0x30043A, 0x00057D, 0x0180C3, 0x08000A, - 0x028924, 0x280502, 0x280C02, 0x0A810D, - 0x000820, 0x0002F5, 0x010040, 0x220007, - 0x0004FD, 0x018042, 0x70000A, 0x030000, - 0x007020, 0x06FA06, 0x018040, 0x02180D, - 0x000810, 0x08043A, 0x2B2206, 0x000007, - 0x0002FD, 0x018042, 0x08000A, 0x000904, - 0x218A86, 0x000007, 0x01F206, 0x000007, - 0x000875, 0x0009FD, 0x00010D, 0x220A06, - 0x000295, 0x000B75, 0x00097D, 0x00000D, - 0x000515, 0x010042, 0x18000A, 0x001904, - 0x287886, 0x0006F5, 0x001020, 0x010040, - 0x0004F5, 0x000820, 0x010040, 0x000775, - 0x010042, 0x09804A, 0x10000A, 0x001124, - 0x000904, 0x22BA86, 0x000815, 0x080102, - 0x101204, 0x22DA06, 0x000575, 0x081204, - 0x000007, 0x100102, 0x000575, 0x000425, - 0x021124, 0x100102, 0x000820, 0x031060, - 0x010040, 0x001924, 0x287886, 0x00008D, - 0x000464, 0x009D04, 0x278886, 0x180102, - 0x000575, 0x010042, 0x28040A, 0x00018D, - 0x000924, 0x280D02, 0x00000D, 0x000924, - 0x281502, 0x10000D, 0x000820, 0x0002F5, - 0x010040, 0x200007, 0x001175, 0x0002FD, - 0x018042, 0x08000A, 0x000904, 0x23C286, - 0x000007, 0x000100, 0x080B20, 0x130B60, - 0x1B0B60, 0x030A60, 0x010040, 0x050042, - 0x3D004A, 0x35004A, 0x2D004A, 0x20000A, - 0x0006F5, 0x010042, 0x28140A, 0x0004F5, - 0x010042, 0x08000A, 0x000315, 0x010D04, - 0x24CA86, 0x004015, 0x000095, 0x010D04, - 0x24B886, 0x100022, 0x10002A, 0x24E206, - 0x000007, 0x333104, 0x2AA904, 0x000007, - 0x032124, 0x280502, 0x001124, 0x000424, - 0x000424, 0x003224, 0x00292C, 0x00636C, - 0x25F386, 0x000007, 0x02B164, 0x000464, - 0x000464, 0x00008D, 0x000A64, 0x280D02, - 0x10008D, 0x000820, 0x0002F5, 0x010040, - 0x220007, 0x00008D, 0x38B904, 0x000007, - 0x03296C, 0x30010A, 0x0002F5, 0x010042, - 0x08000A, 0x000904, 0x25BA86, 0x000007, - 0x02312C, 0x28050A, 0x00008D, 0x01096C, - 0x280D0A, 0x10010D, 0x000820, 0x0002F5, - 0x010040, 0x220007, 0x001124, 0x000424, - 0x000424, 0x003224, 0x300102, 0x032944, - 0x267A86, 0x000007, 0x300002, 0x0004F5, - 0x010042, 0x08000A, 0x000315, 0x010D04, - 0x26C086, 0x003124, 0x000464, 0x300102, - 0x0002F5, 0x010042, 0x08000A, 0x000904, - 0x26CA86, 0x000007, 0x003124, 0x300502, - 0x003924, 0x300583, 0x000883, 0x0005F5, - 0x010042, 0x28040A, 0x00008D, 0x008124, - 0x280D02, 0x00008D, 0x008124, 0x281502, - 0x10018D, 0x000820, 0x0002F5, 0x010040, - 0x220007, 0x001025, 0x000575, 0x030042, - 0x09004A, 0x10000A, 0x0A0904, 0x121104, - 0x000007, 0x001020, 0x050860, 0x050040, - 0x0006FD, 0x018042, 0x09004A, 0x10000A, - 0x0000A5, 0x0A0904, 0x121104, 0x000007, - 0x000820, 0x019060, 0x010040, 0x0002F5, - 0x010042, 0x08000A, 0x000904, 0x284286, - 0x000007, 0x230A06, 0x000007, 0x000606, - 0x000007, 0x0002F5, 0x010042, 0x08000A, - 0x000904, 0x289286, 0x000007, 0x000100, - 0x080B20, 0x138B60, 0x1B8B60, 0x238B60, - 0x2B8B60, 0x338B60, 0x3B8B60, 0x438B60, - 0x4B8B60, 0x538B60, 0x5B8B60, 0x638B60, - 0x6B8B60, 0x738B60, 0x7B8B60, 0x038F60, - 0x0B8F60, 0x138F60, 0x1B8F60, 0x238F60, - 0x2B8F60, 0x338F60, 0x3B8F60, 0x438F60, - 0x4B8F60, 0x538F60, 0x5B8F60, 0x638F60, - 0x6B8F60, 0x738F60, 0x7B8F60, 0x038A60, - 0x000606, 0x018040, 0x00008D, 0x000A64, - 0x280D02, 0x000A24, 0x00027D, 0x018042, - 0x10000A, 0x001224, 0x0003FD, 0x018042, - 0x08000A, 0x000904, 0x2A8286, 0x000007, - 0x00018D, 0x000A24, 0x000464, 0x000464, - 0x080102, 0x000924, 0x000424, 0x000424, - 0x100102, 0x02000D, 0x009144, 0x2AD986, - 0x000007, 0x0001FD, 0x018042, 0x08000A, - 0x000A44, 0x2ABB86, 0x018042, 0x0A000D, - 0x000820, 0x0002FD, 0x018040, 0x200007, - 0x00027D, 0x001020, 0x000606, 0x018040, - 0x0002F5, 0x010042, 0x08000A, 0x000904, - 0x2B2A86, 0x000007, 0x00037D, 0x018042, - 0x08000A, 0x000904, 0x2B5A86, 0x000007, - 0x000075, 0x002E7D, 0x010042, 0x0B804A, - 0x000020, 0x000904, 0x000686, 0x010040, - 0x31844A, 0x30048B, 0x000883, 0x00008D, - 0x000810, 0x28143A, 0x00008D, 0x000810, - 0x280C3A, 0x000675, 0x010042, 0x08000A, - 0x003815, 0x010924, 0x280502, 0x0B000D, - 0x000820, 0x0002F5, 0x010040, 0x000606, - 0x220007, 0x000464, 0x000464, 0x000606, - 0x000007, 0x000134, 0x007F8D, 0x00093C, - 0x281D12, 0x282512, 0x001F32, 0x0E0007, - 0x00010D, 0x00037D, 0x000820, 0x018040, - 0x05D2F4, 0x000007, 0x080007, 0x00037D, - 0x018042, 0x08000A, 0x000904, 0x2D0286, - 0x000007, 0x000606, 0x000007, 0x000007, - 0x000012, 0x100007, 0x320007, 0x600007, - 0x100080, 0x48001A, 0x004904, 0x2D6186, - 0x000007, 0x001210, 0x58003A, 0x000145, - 0x5C5D04, 0x000007, 0x000080, 0x48001A, - 0x004904, 0x2DB186, 0x000007, 0x001210, - 0x50003A, 0x005904, 0x2E0886, 0x000045, - 0x0000C5, 0x7FFFF5, 0x7FFF7D, 0x07D524, - 0x004224, 0x500102, 0x200502, 0x000082, - 0x40001A, 0x004104, 0x2E3986, 0x000007, - 0x003865, 0x40001A, 0x004020, 0x00104D, - 0x04C184, 0x301B86, 0x000040, 0x040007, - 0x000165, 0x000145, 0x004020, 0x000040, - 0x000765, 0x080080, 0x40001A, 0x004104, - 0x2EC986, 0x000007, 0x001210, 0x40003A, - 0x004104, 0x2F2286, 0x00004D, 0x0000CD, - 0x004810, 0x20043A, 0x000882, 0x40001A, - 0x004104, 0x2F3186, 0x000007, 0x004820, - 0x005904, 0x300886, 0x000040, 0x0007E5, - 0x200480, 0x2816A0, 0x3216E0, 0x3A16E0, - 0x4216E0, 0x021260, 0x000040, 0x000032, - 0x400075, 0x00007D, 0x07D574, 0x200512, - 0x000082, 0x40001A, 0x004104, 0x2FE186, - 0x000007, 0x037206, 0x640007, 0x060007, - 0x0000E5, 0x000020, 0x000040, 0x000A65, - 0x000020, 0x020040, 0x020040, 0x000040, - 0x000165, 0x000042, 0x70000A, 0x007104, - 0x30A286, 0x000007, 0x018206, 0x640007, - 0x050000, 0x007020, 0x000040, 0x037206, - 0x640007, 0x000007, 0x00306D, 0x028860, - 0x029060, 0x08000A, 0x028860, 0x008040, - 0x100012, 0x00100D, 0x009184, 0x314186, - 0x000E0D, 0x009184, 0x325186, 0x000007, - 0x300007, 0x001020, 0x003B6D, 0x008040, - 0x000080, 0x08001A, 0x000904, 0x316186, - 0x000007, 0x001220, 0x000DED, 0x008040, - 0x008042, 0x10000A, 0x40000D, 0x109544, - 0x000007, 0x001020, 0x000DED, 0x008040, - 0x008042, 0x20040A, 0x000082, 0x08001A, - 0x000904, 0x31F186, 0x000007, 0x003B6D, - 0x008042, 0x08000A, 0x000E15, 0x010984, - 0x329B86, 0x600007, 0x08001A, 0x000C15, - 0x010984, 0x328386, 0x000020, 0x1A0007, - 0x0002ED, 0x008040, 0x620007, 0x00306D, - 0x028042, 0x0A804A, 0x000820, 0x0A804A, - 0x000606, 0x10804A, 0x000007, 0x282512, - 0x001F32, 0x05D2F4, 0x54D104, 0x00735C, - 0x000786, 0x000007, 0x0C0007, 0x0A0007, - 0x1C0007, 0x003465, 0x020040, 0x004820, - 0x025060, 0x40000A, 0x024060, 0x000040, - 0x454944, 0x000007, 0x004020, 0x003AE5, - 0x000040, 0x0028E5, 0x000042, 0x48000A, - 0x004904, 0x386886, 0x002C65, 0x000042, - 0x40000A, 0x0000D5, 0x454104, 0x000007, - 0x000655, 0x054504, 0x34F286, 0x0001D5, - 0x054504, 0x34F086, 0x002B65, 0x000042, - 0x003AE5, 0x50004A, 0x40000A, 0x45C3D4, - 0x000007, 0x454504, 0x000007, 0x0000CD, - 0x444944, 0x000007, 0x454504, 0x000007, - 0x00014D, 0x554944, 0x000007, 0x045144, - 0x34E986, 0x002C65, 0x000042, 0x48000A, - 0x4CD104, 0x000007, 0x04C144, 0x34F386, - 0x000007, 0x160007, 0x002CE5, 0x040042, - 0x40000A, 0x004020, 0x000040, 0x002965, - 0x000042, 0x40000A, 0x004104, 0x356086, - 0x000007, 0x002402, 0x36A206, 0x005C02, - 0x0025E5, 0x000042, 0x40000A, 0x004274, - 0x002AE5, 0x000042, 0x40000A, 0x004274, - 0x500112, 0x0029E5, 0x000042, 0x40000A, - 0x004234, 0x454104, 0x000007, 0x004020, - 0x000040, 0x003EE5, 0x000020, 0x000040, - 0x002DE5, 0x400152, 0x50000A, 0x045144, - 0x364A86, 0x0000C5, 0x003EE5, 0x004020, - 0x000040, 0x002BE5, 0x000042, 0x40000A, - 0x404254, 0x000007, 0x002AE5, 0x004020, - 0x000040, 0x500132, 0x040134, 0x005674, - 0x0029E5, 0x020042, 0x42000A, 0x000042, - 0x50000A, 0x05417C, 0x0028E5, 0x000042, - 0x48000A, 0x0000C5, 0x4CC144, 0x371086, - 0x0026E5, 0x0027E5, 0x020042, 0x40004A, - 0x50000A, 0x00423C, 0x00567C, 0x0028E5, - 0x004820, 0x000040, 0x281D12, 0x282512, - 0x001F72, 0x002965, 0x000042, 0x40000A, - 0x004104, 0x37AA86, 0x0E0007, 0x160007, - 0x1E0007, 0x003EE5, 0x000042, 0x40000A, - 0x004104, 0x37E886, 0x002D65, 0x000042, - 0x28340A, 0x003465, 0x020042, 0x42004A, - 0x004020, 0x4A004A, 0x50004A, 0x05D2F4, - 0x54D104, 0x00735C, 0x385186, 0x000007, - 0x000606, 0x080007, 0x0C0007, 0x080007, - 0x0A0007, 0x0001E5, 0x020045, 0x004020, - 0x000060, 0x000365, 0x000040, 0x002E65, - 0x001A20, 0x0A1A60, 0x000040, 0x003465, - 0x020042, 0x42004A, 0x004020, 0x4A004A, - 0x000606, 0x50004A, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000 -}; - -// -------------------------------------------- -// DS-1E Controller InstructionRAM Code -// 1999/06/21 -// Buf441 slot is Enabled. -// -------------------------------------------- -// 04/09 creat -// 04/12 stop nise fix -// 06/21 WorkingOff timming -static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = { - 0x000007, 0x240007, 0x0C0007, 0x1C0007, - 0x060007, 0x700002, 0x000020, 0x030040, - 0x007104, 0x004286, 0x030040, 0x000F0D, - 0x000810, 0x20043A, 0x000282, 0x00020D, - 0x000810, 0x20043A, 0x001282, 0x200E82, - 0x00800D, 0x000810, 0x20043A, 0x001A82, - 0x03460D, 0x000810, 0x10043A, 0x02EC0D, - 0x000810, 0x18043A, 0x00010D, 0x020015, - 0x0000FD, 0x000020, 0x038860, 0x039060, - 0x038060, 0x038040, 0x038040, 0x038040, - 0x018040, 0x000A7D, 0x038040, 0x038040, - 0x018040, 0x200402, 0x000882, 0x08001A, - 0x000904, 0x017186, 0x000007, 0x260007, - 0x400007, 0x000007, 0x03258D, 0x000810, - 0x18043A, 0x260007, 0x284402, 0x00087D, - 0x018042, 0x00160A, 0x05A206, 0x000007, - 0x440007, 0x00230D, 0x000810, 0x08043A, - 0x22FA06, 0x000007, 0x0007FD, 0x018042, - 0x08000A, 0x000904, 0x02AB86, 0x000195, - 0x090D04, 0x000007, 0x000820, 0x0000F5, - 0x000B7D, 0x01F060, 0x0000FD, 0x033A06, - 0x018040, 0x000A7D, 0x038042, 0x13804A, - 0x18000A, 0x001820, 0x059060, 0x058860, - 0x018040, 0x0000FD, 0x018042, 0x70000A, - 0x000115, 0x071144, 0x033B86, 0x030000, - 0x007020, 0x036206, 0x018040, 0x00360D, - 0x000810, 0x08043A, 0x232206, 0x000007, - 0x02EC0D, 0x000810, 0x18043A, 0x019A06, - 0x000007, 0x240007, 0x000F8D, 0x000810, - 0x00163A, 0x002402, 0x005C02, 0x0028FD, - 0x000020, 0x018040, 0x08000D, 0x000815, - 0x510984, 0x000007, 0x00004D, 0x000E5D, - 0x000E02, 0x00430D, 0x000810, 0x08043A, - 0x2E1206, 0x000007, 0x00008D, 0x000924, - 0x000F02, 0x00470D, 0x000810, 0x08043A, - 0x2E1206, 0x000007, 0x480480, 0x001210, - 0x28043A, 0x00778D, 0x000810, 0x280C3A, - 0x00068D, 0x000810, 0x28143A, 0x284402, - 0x03258D, 0x000810, 0x18043A, 0x07FF8D, - 0x000820, 0x0002FD, 0x018040, 0x260007, - 0x200007, 0x0002FD, 0x018042, 0x08000A, - 0x000904, 0x051286, 0x000007, 0x240007, - 0x02EC0D, 0x000810, 0x18043A, 0x00387D, - 0x018042, 0x08000A, 0x001015, 0x010984, - 0x019B86, 0x000007, 0x01B206, 0x000007, - 0x0008FD, 0x018042, 0x18000A, 0x001904, - 0x22B886, 0x280007, 0x001810, 0x28043A, - 0x280C02, 0x00000D, 0x000810, 0x28143A, - 0x08808D, 0x000820, 0x0002FD, 0x018040, - 0x200007, 0x00020D, 0x189904, 0x000007, - 0x00402D, 0x0000BD, 0x0002FD, 0x018042, - 0x08000A, 0x000904, 0x065A86, 0x000007, - 0x000100, 0x000A20, 0x00047D, 0x018040, - 0x018042, 0x20000A, 0x003015, 0x012144, - 0x036186, 0x000007, 0x002104, 0x036186, - 0x000007, 0x000F8D, 0x000810, 0x280C3A, - 0x023944, 0x07C986, 0x000007, 0x001810, - 0x28043A, 0x08810D, 0x000820, 0x0002FD, - 0x018040, 0x200007, 0x002810, 0x78003A, - 0x00788D, 0x000810, 0x08043A, 0x2A1206, - 0x000007, 0x00400D, 0x001015, 0x189904, - 0x292904, 0x393904, 0x000007, 0x070206, - 0x000007, 0x0004F5, 0x00007D, 0x000020, - 0x00008D, 0x010860, 0x018040, 0x00047D, - 0x038042, 0x21804A, 0x18000A, 0x021944, - 0x229086, 0x000007, 0x004075, 0x71F104, - 0x000007, 0x010042, 0x28000A, 0x002904, - 0x225886, 0x000007, 0x003C0D, 0x30A904, - 0x000007, 0x00077D, 0x018042, 0x08000A, - 0x000904, 0x08DA86, 0x00057D, 0x002820, - 0x03B060, 0x08F206, 0x018040, 0x003020, - 0x03A860, 0x018040, 0x0002FD, 0x018042, - 0x08000A, 0x000904, 0x08FA86, 0x000007, - 0x00057D, 0x018042, 0x28040A, 0x000E8D, - 0x000810, 0x280C3A, 0x00000D, 0x000810, - 0x28143A, 0x09000D, 0x000820, 0x0002FD, - 0x018040, 0x200007, 0x003DFD, 0x000020, - 0x018040, 0x00107D, 0x009D8D, 0x000810, - 0x08043A, 0x2A1206, 0x000007, 0x000815, - 0x08001A, 0x010984, 0x0A5186, 0x00137D, - 0x200500, 0x280F20, 0x338F60, 0x3B8F60, - 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60, - 0x038A60, 0x018040, 0x00107D, 0x018042, - 0x08000A, 0x000215, 0x010984, 0x3A8186, - 0x000007, 0x007FBD, 0x383DC4, 0x000007, - 0x001A7D, 0x001375, 0x018042, 0x09004A, - 0x10000A, 0x0B8D04, 0x139504, 0x000007, - 0x000820, 0x019060, 0x001104, 0x225886, - 0x010040, 0x0017FD, 0x018042, 0x08000A, - 0x000904, 0x225A86, 0x000007, 0x00197D, - 0x038042, 0x09804A, 0x10000A, 0x000924, - 0x001664, 0x0011FD, 0x038042, 0x2B804A, - 0x19804A, 0x00008D, 0x218944, 0x000007, - 0x002244, 0x0C1986, 0x000007, 0x001A64, - 0x002A24, 0x00197D, 0x080102, 0x100122, - 0x000820, 0x039060, 0x018040, 0x003DFD, - 0x00008D, 0x000820, 0x018040, 0x001375, - 0x001A7D, 0x010042, 0x09804A, 0x10000A, - 0x00021D, 0x0189E4, 0x2992E4, 0x309144, - 0x000007, 0x00060D, 0x000A15, 0x000C1D, - 0x001025, 0x00A9E4, 0x012BE4, 0x000464, - 0x01B3E4, 0x0232E4, 0x000464, 0x000464, - 0x000464, 0x000464, 0x00040D, 0x08B1C4, - 0x000007, 0x000820, 0x000BF5, 0x030040, - 0x00197D, 0x038042, 0x09804A, 0x000A24, - 0x08000A, 0x080E64, 0x000007, 0x100122, - 0x000820, 0x031060, 0x010040, 0x0064AC, - 0x00027D, 0x000020, 0x018040, 0x00107D, - 0x018042, 0x0011FD, 0x3B804A, 0x09804A, - 0x20000A, 0x000095, 0x1A1144, 0x00A144, - 0x0E5886, 0x00040D, 0x00B984, 0x0E5986, - 0x0018FD, 0x018042, 0x0010FD, 0x09804A, - 0x28000A, 0x000095, 0x010924, 0x002A64, - 0x0E4986, 0x000007, 0x002904, 0x0E5A86, - 0x000007, 0x0E6206, 0x080002, 0x00008D, - 0x00387D, 0x000820, 0x018040, 0x00127D, - 0x018042, 0x10000A, 0x003904, 0x0F0986, - 0x00080D, 0x7FFFB5, 0x00B984, 0x0ED986, - 0x000025, 0x0FB206, 0x00002D, 0x000015, - 0x00082D, 0x02E00D, 0x000820, 0x0FFA06, - 0x00000D, 0x7F8035, 0x00B984, 0x0FA986, - 0x400025, 0x00008D, 0x110944, 0x000007, - 0x00018D, 0x109504, 0x000007, 0x009164, - 0x000424, 0x000424, 0x000424, 0x100102, - 0x280002, 0x02DF0D, 0x000820, 0x0FFA06, - 0x00018D, 0x00042D, 0x00008D, 0x109504, - 0x000007, 0x00020D, 0x109184, 0x000007, - 0x02DF8D, 0x000820, 0x00008D, 0x0038FD, - 0x018040, 0x003BFD, 0x001020, 0x03A860, - 0x000815, 0x313184, 0x212184, 0x000007, - 0x03B060, 0x03A060, 0x018040, 0x0022FD, - 0x000095, 0x010924, 0x000424, 0x000424, - 0x001264, 0x100102, 0x000820, 0x039060, - 0x018040, 0x001924, 0x010F0D, 0x00397D, - 0x000820, 0x058040, 0x038042, 0x09844A, - 0x000606, 0x08040A, 0x000424, 0x000424, - 0x00117D, 0x018042, 0x08000A, 0x000A24, - 0x280502, 0x280C02, 0x09800D, 0x000820, - 0x0002FD, 0x018040, 0x200007, 0x0022FD, - 0x018042, 0x08000A, 0x000095, 0x280DC4, - 0x011924, 0x00197D, 0x018042, 0x0011FD, - 0x09804A, 0x10000A, 0x0000B5, 0x113144, - 0x0A8D04, 0x000007, 0x080A44, 0x129504, - 0x000007, 0x0023FD, 0x001020, 0x038040, - 0x101244, 0x000007, 0x000820, 0x039060, - 0x018040, 0x0002FD, 0x018042, 0x08000A, - 0x000904, 0x123286, 0x000007, 0x003BFD, - 0x000100, 0x000A10, 0x0B807A, 0x13804A, - 0x090984, 0x000007, 0x000095, 0x013D04, - 0x12B886, 0x10000A, 0x100002, 0x090984, - 0x000007, 0x038042, 0x11804A, 0x090D04, - 0x000007, 0x10000A, 0x090D84, 0x000007, - 0x00257D, 0x000820, 0x018040, 0x00010D, - 0x000810, 0x28143A, 0x00127D, 0x018042, - 0x20000A, 0x00197D, 0x018042, 0x00117D, - 0x31804A, 0x10000A, 0x003124, 0x013B8D, - 0x00397D, 0x000820, 0x058040, 0x038042, - 0x09844A, 0x000606, 0x08040A, 0x300102, - 0x003124, 0x000424, 0x000424, 0x001224, - 0x280502, 0x001A4C, 0x143986, 0x700002, - 0x00002D, 0x030000, 0x00387D, 0x018042, - 0x10000A, 0x146206, 0x002124, 0x0000AD, - 0x100002, 0x00010D, 0x000924, 0x006B24, - 0x014A0D, 0x00397D, 0x000820, 0x058040, - 0x038042, 0x09844A, 0x000606, 0x08040A, - 0x003264, 0x00008D, 0x000A24, 0x001020, - 0x00227D, 0x018040, 0x014F8D, 0x000810, - 0x08043A, 0x2B5A06, 0x000007, 0x002820, - 0x00207D, 0x018040, 0x00117D, 0x038042, - 0x13804A, 0x33800A, 0x00387D, 0x018042, - 0x08000A, 0x000904, 0x177286, 0x000007, - 0x00008D, 0x030964, 0x015B0D, 0x00397D, - 0x000820, 0x058040, 0x038042, 0x09844A, - 0x000606, 0x08040A, 0x380102, 0x000424, - 0x000424, 0x001224, 0x0002FD, 0x018042, - 0x08000A, 0x000904, 0x15DA86, 0x000007, - 0x280502, 0x001A4C, 0x177186, 0x000007, - 0x032164, 0x00632C, 0x003DFD, 0x018042, - 0x08000A, 0x000095, 0x090904, 0x000007, - 0x000820, 0x001A4C, 0x169986, 0x018040, - 0x030000, 0x16B206, 0x002124, 0x00010D, - 0x000924, 0x006B24, 0x016F0D, 0x00397D, - 0x000820, 0x058040, 0x038042, 0x09844A, - 0x000606, 0x08040A, 0x003A64, 0x000095, - 0x001224, 0x0002FD, 0x018042, 0x08000A, - 0x000904, 0x171286, 0x000007, 0x01760D, - 0x000810, 0x08043A, 0x2B5A06, 0x000007, - 0x160A06, 0x000007, 0x007020, 0x08010A, - 0x10012A, 0x0020FD, 0x038860, 0x039060, - 0x018040, 0x00227D, 0x018042, 0x003DFD, - 0x08000A, 0x31844A, 0x000904, 0x181086, - 0x18008B, 0x00008D, 0x189904, 0x00312C, - 0x18E206, 0x000007, 0x00324C, 0x186B86, - 0x000007, 0x001904, 0x186886, 0x000007, - 0x000095, 0x199144, 0x00222C, 0x003124, - 0x00636C, 0x000E3D, 0x001375, 0x000BFD, - 0x010042, 0x09804A, 0x10000A, 0x038AEC, - 0x0393EC, 0x00224C, 0x18E186, 0x000007, - 0x00008D, 0x189904, 0x00226C, 0x00322C, - 0x30050A, 0x301DAB, 0x002083, 0x0018FD, - 0x018042, 0x08000A, 0x018924, 0x300502, - 0x001083, 0x001875, 0x010042, 0x10000A, - 0x00008D, 0x010924, 0x001375, 0x330542, - 0x330CCB, 0x332CCB, 0x3334CB, 0x333CCB, - 0x3344CB, 0x334CCB, 0x3354CB, 0x305C8B, - 0x006083, 0x0002F5, 0x010042, 0x08000A, - 0x000904, 0x19B286, 0x000007, 0x001E2D, - 0x0005FD, 0x018042, 0x08000A, 0x028924, - 0x280502, 0x00060D, 0x000810, 0x280C3A, - 0x00008D, 0x000810, 0x28143A, 0x0A808D, - 0x000820, 0x0002F5, 0x010040, 0x220007, - 0x001275, 0x030042, 0x21004A, 0x00008D, - 0x1A0944, 0x000007, 0x01AB8D, 0x000810, - 0x08043A, 0x2CAA06, 0x000007, 0x0001F5, - 0x030042, 0x0D004A, 0x10000A, 0x089144, - 0x000007, 0x000820, 0x010040, 0x0025F5, - 0x0A3144, 0x000007, 0x000820, 0x032860, - 0x030040, 0x00217D, 0x038042, 0x0B804A, - 0x10000A, 0x000820, 0x031060, 0x030040, - 0x00008D, 0x000124, 0x00012C, 0x000E64, - 0x001A64, 0x00636C, 0x08010A, 0x10012A, - 0x000820, 0x031060, 0x030040, 0x0020FD, - 0x018042, 0x08000A, 0x00227D, 0x018042, - 0x10000A, 0x000820, 0x031060, 0x030040, - 0x00197D, 0x018042, 0x08000A, 0x0022FD, - 0x038042, 0x10000A, 0x000820, 0x031060, - 0x030040, 0x090D04, 0x000007, 0x000820, - 0x030040, 0x038042, 0x0B804A, 0x10000A, - 0x000820, 0x031060, 0x030040, 0x038042, - 0x13804A, 0x19804A, 0x110D04, 0x198D04, - 0x000007, 0x08000A, 0x001020, 0x031860, - 0x030860, 0x030040, 0x00008D, 0x0B0944, - 0x000007, 0x000820, 0x010040, 0x0005F5, - 0x030042, 0x08000A, 0x000820, 0x010040, - 0x0000F5, 0x010042, 0x08000A, 0x000904, - 0x1D9886, 0x001E75, 0x030042, 0x01044A, - 0x000C0A, 0x1DAA06, 0x000007, 0x000402, - 0x000C02, 0x00177D, 0x001AF5, 0x018042, - 0x03144A, 0x031C4A, 0x03244A, 0x032C4A, - 0x03344A, 0x033C4A, 0x03444A, 0x004C0A, - 0x00043D, 0x0013F5, 0x001AFD, 0x030042, - 0x0B004A, 0x1B804A, 0x13804A, 0x20000A, - 0x089144, 0x19A144, 0x0389E4, 0x0399EC, - 0x005502, 0x005D0A, 0x030042, 0x0B004A, - 0x1B804A, 0x13804A, 0x20000A, 0x089144, - 0x19A144, 0x0389E4, 0x0399EC, 0x006502, - 0x006D0A, 0x030042, 0x0B004A, 0x19004A, - 0x2B804A, 0x13804A, 0x21804A, 0x30000A, - 0x089144, 0x19A144, 0x2AB144, 0x0389E4, - 0x0399EC, 0x007502, 0x007D0A, 0x03A9E4, - 0x000702, 0x00107D, 0x000415, 0x018042, - 0x08000A, 0x0109E4, 0x000F02, 0x002AF5, - 0x0019FD, 0x010042, 0x09804A, 0x10000A, - 0x000934, 0x001674, 0x0029F5, 0x010042, - 0x10000A, 0x00917C, 0x002075, 0x010042, - 0x08000A, 0x000904, 0x200A86, 0x0026F5, - 0x0027F5, 0x030042, 0x09004A, 0x10000A, - 0x000A3C, 0x00167C, 0x001A75, 0x000BFD, - 0x010042, 0x51804A, 0x48000A, 0x160007, - 0x001075, 0x010042, 0x282C0A, 0x281D12, - 0x282512, 0x001F32, 0x1E0007, 0x0E0007, - 0x001975, 0x010042, 0x002DF5, 0x0D004A, - 0x10000A, 0x009144, 0x20EA86, 0x010042, - 0x28340A, 0x000E5D, 0x00008D, 0x000375, - 0x000820, 0x010040, 0x05D2F4, 0x54D104, - 0x00735C, 0x218B86, 0x000007, 0x0C0007, - 0x080007, 0x0A0007, 0x02178D, 0x000810, - 0x08043A, 0x34B206, 0x000007, 0x219206, - 0x000007, 0x080007, 0x002275, 0x010042, - 0x20000A, 0x002104, 0x225886, 0x001E2D, - 0x0002F5, 0x010042, 0x08000A, 0x000904, - 0x21CA86, 0x000007, 0x002010, 0x30043A, - 0x00057D, 0x0180C3, 0x08000A, 0x028924, - 0x280502, 0x280C02, 0x0A810D, 0x000820, - 0x0002F5, 0x010040, 0x220007, 0x0004FD, - 0x018042, 0x70000A, 0x030000, 0x007020, - 0x07FA06, 0x018040, 0x022B8D, 0x000810, - 0x08043A, 0x2CAA06, 0x000007, 0x0002FD, - 0x018042, 0x08000A, 0x000904, 0x22C286, - 0x000007, 0x020206, 0x000007, 0x000875, - 0x0009FD, 0x00010D, 0x234206, 0x000295, - 0x000B75, 0x00097D, 0x00000D, 0x000515, - 0x010042, 0x18000A, 0x001904, 0x2A0086, - 0x0006F5, 0x001020, 0x010040, 0x0004F5, - 0x000820, 0x010040, 0x000775, 0x010042, - 0x09804A, 0x10000A, 0x001124, 0x000904, - 0x23F286, 0x000815, 0x080102, 0x101204, - 0x241206, 0x000575, 0x081204, 0x000007, - 0x100102, 0x000575, 0x000425, 0x021124, - 0x100102, 0x000820, 0x031060, 0x010040, - 0x001924, 0x2A0086, 0x00008D, 0x000464, - 0x009D04, 0x291086, 0x180102, 0x000575, - 0x010042, 0x28040A, 0x00018D, 0x000924, - 0x280D02, 0x00000D, 0x000924, 0x281502, - 0x10000D, 0x000820, 0x0002F5, 0x010040, - 0x200007, 0x001175, 0x0002FD, 0x018042, - 0x08000A, 0x000904, 0x24FA86, 0x000007, - 0x000100, 0x080B20, 0x130B60, 0x1B0B60, - 0x030A60, 0x010040, 0x050042, 0x3D004A, - 0x35004A, 0x2D004A, 0x20000A, 0x0006F5, - 0x010042, 0x28140A, 0x0004F5, 0x010042, - 0x08000A, 0x000315, 0x010D04, 0x260286, - 0x004015, 0x000095, 0x010D04, 0x25F086, - 0x100022, 0x10002A, 0x261A06, 0x000007, - 0x333104, 0x2AA904, 0x000007, 0x032124, - 0x280502, 0x284402, 0x001124, 0x400102, - 0x000424, 0x000424, 0x003224, 0x00292C, - 0x00636C, 0x277386, 0x000007, 0x02B164, - 0x000464, 0x000464, 0x00008D, 0x000A64, - 0x280D02, 0x10008D, 0x000820, 0x0002F5, - 0x010040, 0x220007, 0x00008D, 0x38B904, - 0x000007, 0x03296C, 0x30010A, 0x0002F5, - 0x010042, 0x08000A, 0x000904, 0x270286, - 0x000007, 0x00212C, 0x28050A, 0x00316C, - 0x00046C, 0x00046C, 0x28450A, 0x001124, - 0x006B64, 0x100102, 0x00008D, 0x01096C, - 0x280D0A, 0x10010D, 0x000820, 0x0002F5, - 0x010040, 0x220007, 0x004124, 0x000424, - 0x000424, 0x003224, 0x300102, 0x032944, - 0x27FA86, 0x000007, 0x300002, 0x0004F5, - 0x010042, 0x08000A, 0x000315, 0x010D04, - 0x284086, 0x003124, 0x000464, 0x300102, - 0x0002F5, 0x010042, 0x08000A, 0x000904, - 0x284A86, 0x000007, 0x284402, 0x003124, - 0x300502, 0x003924, 0x300583, 0x000883, - 0x0005F5, 0x010042, 0x28040A, 0x00008D, - 0x008124, 0x280D02, 0x00008D, 0x008124, - 0x281502, 0x10018D, 0x000820, 0x0002F5, - 0x010040, 0x220007, 0x001025, 0x000575, - 0x030042, 0x09004A, 0x10000A, 0x0A0904, - 0x121104, 0x000007, 0x001020, 0x050860, - 0x050040, 0x0006FD, 0x018042, 0x09004A, - 0x10000A, 0x0000A5, 0x0A0904, 0x121104, - 0x000007, 0x000820, 0x019060, 0x010040, - 0x0002F5, 0x010042, 0x08000A, 0x000904, - 0x29CA86, 0x000007, 0x244206, 0x000007, - 0x000606, 0x000007, 0x0002F5, 0x010042, - 0x08000A, 0x000904, 0x2A1A86, 0x000007, - 0x000100, 0x080B20, 0x138B60, 0x1B8B60, - 0x238B60, 0x2B8B60, 0x338B60, 0x3B8B60, - 0x438B60, 0x4B8B60, 0x538B60, 0x5B8B60, - 0x638B60, 0x6B8B60, 0x738B60, 0x7B8B60, - 0x038F60, 0x0B8F60, 0x138F60, 0x1B8F60, - 0x238F60, 0x2B8F60, 0x338F60, 0x3B8F60, - 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60, - 0x638F60, 0x6B8F60, 0x738F60, 0x7B8F60, - 0x038A60, 0x000606, 0x018040, 0x00008D, - 0x000A64, 0x280D02, 0x000A24, 0x00027D, - 0x018042, 0x10000A, 0x001224, 0x0003FD, - 0x018042, 0x08000A, 0x000904, 0x2C0A86, - 0x000007, 0x00018D, 0x000A24, 0x000464, - 0x000464, 0x080102, 0x000924, 0x000424, - 0x000424, 0x100102, 0x02000D, 0x009144, - 0x2C6186, 0x000007, 0x0001FD, 0x018042, - 0x08000A, 0x000A44, 0x2C4386, 0x018042, - 0x0A000D, 0x000820, 0x0002FD, 0x018040, - 0x200007, 0x00027D, 0x001020, 0x000606, - 0x018040, 0x0002F5, 0x010042, 0x08000A, - 0x000904, 0x2CB286, 0x000007, 0x00037D, - 0x018042, 0x08000A, 0x000904, 0x2CE286, - 0x000007, 0x000075, 0x002E7D, 0x010042, - 0x0B804A, 0x000020, 0x000904, 0x000686, - 0x010040, 0x31844A, 0x30048B, 0x000883, - 0x00008D, 0x000810, 0x28143A, 0x00008D, - 0x000810, 0x280C3A, 0x000675, 0x010042, - 0x08000A, 0x003815, 0x010924, 0x280502, - 0x0B000D, 0x000820, 0x0002F5, 0x010040, - 0x000606, 0x220007, 0x000464, 0x000464, - 0x000606, 0x000007, 0x000134, 0x007F8D, - 0x00093C, 0x281D12, 0x282512, 0x001F32, - 0x0E0007, 0x00010D, 0x00037D, 0x000820, - 0x018040, 0x05D2F4, 0x000007, 0x080007, - 0x00037D, 0x018042, 0x08000A, 0x000904, - 0x2E8A86, 0x000007, 0x000606, 0x000007, - 0x000007, 0x000012, 0x100007, 0x320007, - 0x600007, 0x460007, 0x100080, 0x48001A, - 0x004904, 0x2EF186, 0x000007, 0x001210, - 0x58003A, 0x000145, 0x5C5D04, 0x000007, - 0x000080, 0x48001A, 0x004904, 0x2F4186, - 0x000007, 0x001210, 0x50003A, 0x005904, - 0x2F9886, 0x000045, 0x0000C5, 0x7FFFF5, - 0x7FFF7D, 0x07D524, 0x004224, 0x500102, - 0x200502, 0x000082, 0x40001A, 0x004104, - 0x2FC986, 0x000007, 0x003865, 0x40001A, - 0x004020, 0x00104D, 0x04C184, 0x31AB86, - 0x000040, 0x040007, 0x000165, 0x000145, - 0x004020, 0x000040, 0x000765, 0x080080, - 0x40001A, 0x004104, 0x305986, 0x000007, - 0x001210, 0x40003A, 0x004104, 0x30B286, - 0x00004D, 0x0000CD, 0x004810, 0x20043A, - 0x000882, 0x40001A, 0x004104, 0x30C186, - 0x000007, 0x004820, 0x005904, 0x319886, - 0x000040, 0x0007E5, 0x200480, 0x2816A0, - 0x3216E0, 0x3A16E0, 0x4216E0, 0x021260, - 0x000040, 0x000032, 0x400075, 0x00007D, - 0x07D574, 0x200512, 0x000082, 0x40001A, - 0x004104, 0x317186, 0x000007, 0x038A06, - 0x640007, 0x0000E5, 0x000020, 0x000040, - 0x000A65, 0x000020, 0x020040, 0x020040, - 0x000040, 0x000165, 0x000042, 0x70000A, - 0x007104, 0x323286, 0x000007, 0x060007, - 0x019A06, 0x640007, 0x050000, 0x007020, - 0x000040, 0x038A06, 0x640007, 0x000007, - 0x00306D, 0x028860, 0x029060, 0x08000A, - 0x028860, 0x008040, 0x100012, 0x00100D, - 0x009184, 0x32D186, 0x000E0D, 0x009184, - 0x33E186, 0x000007, 0x300007, 0x001020, - 0x003B6D, 0x008040, 0x000080, 0x08001A, - 0x000904, 0x32F186, 0x000007, 0x001220, - 0x000DED, 0x008040, 0x008042, 0x10000A, - 0x40000D, 0x109544, 0x000007, 0x001020, - 0x000DED, 0x008040, 0x008042, 0x20040A, - 0x000082, 0x08001A, 0x000904, 0x338186, - 0x000007, 0x003B6D, 0x008042, 0x08000A, - 0x000E15, 0x010984, 0x342B86, 0x600007, - 0x08001A, 0x000C15, 0x010984, 0x341386, - 0x000020, 0x1A0007, 0x0002ED, 0x008040, - 0x620007, 0x00306D, 0x028042, 0x0A804A, - 0x000820, 0x0A804A, 0x000606, 0x10804A, - 0x000007, 0x282512, 0x001F32, 0x05D2F4, - 0x54D104, 0x00735C, 0x000786, 0x000007, - 0x0C0007, 0x0A0007, 0x1C0007, 0x003465, - 0x020040, 0x004820, 0x025060, 0x40000A, - 0x024060, 0x000040, 0x454944, 0x000007, - 0x004020, 0x003AE5, 0x000040, 0x0028E5, - 0x000042, 0x48000A, 0x004904, 0x39F886, - 0x002C65, 0x000042, 0x40000A, 0x0000D5, - 0x454104, 0x000007, 0x000655, 0x054504, - 0x368286, 0x0001D5, 0x054504, 0x368086, - 0x002B65, 0x000042, 0x003AE5, 0x50004A, - 0x40000A, 0x45C3D4, 0x000007, 0x454504, - 0x000007, 0x0000CD, 0x444944, 0x000007, - 0x454504, 0x000007, 0x00014D, 0x554944, - 0x000007, 0x045144, 0x367986, 0x002C65, - 0x000042, 0x48000A, 0x4CD104, 0x000007, - 0x04C144, 0x368386, 0x000007, 0x160007, - 0x002CE5, 0x040042, 0x40000A, 0x004020, - 0x000040, 0x002965, 0x000042, 0x40000A, - 0x004104, 0x36F086, 0x000007, 0x002402, - 0x383206, 0x005C02, 0x0025E5, 0x000042, - 0x40000A, 0x004274, 0x002AE5, 0x000042, - 0x40000A, 0x004274, 0x500112, 0x0029E5, - 0x000042, 0x40000A, 0x004234, 0x454104, - 0x000007, 0x004020, 0x000040, 0x003EE5, - 0x000020, 0x000040, 0x002DE5, 0x400152, - 0x50000A, 0x045144, 0x37DA86, 0x0000C5, - 0x003EE5, 0x004020, 0x000040, 0x002BE5, - 0x000042, 0x40000A, 0x404254, 0x000007, - 0x002AE5, 0x004020, 0x000040, 0x500132, - 0x040134, 0x005674, 0x0029E5, 0x020042, - 0x42000A, 0x000042, 0x50000A, 0x05417C, - 0x0028E5, 0x000042, 0x48000A, 0x0000C5, - 0x4CC144, 0x38A086, 0x0026E5, 0x0027E5, - 0x020042, 0x40004A, 0x50000A, 0x00423C, - 0x00567C, 0x0028E5, 0x004820, 0x000040, - 0x281D12, 0x282512, 0x001F72, 0x002965, - 0x000042, 0x40000A, 0x004104, 0x393A86, - 0x0E0007, 0x160007, 0x1E0007, 0x003EE5, - 0x000042, 0x40000A, 0x004104, 0x397886, - 0x002D65, 0x000042, 0x28340A, 0x003465, - 0x020042, 0x42004A, 0x004020, 0x4A004A, - 0x50004A, 0x05D2F4, 0x54D104, 0x00735C, - 0x39E186, 0x000007, 0x000606, 0x080007, - 0x0C0007, 0x080007, 0x0A0007, 0x0001E5, - 0x020045, 0x004020, 0x000060, 0x000365, - 0x000040, 0x002E65, 0x001A20, 0x0A1A60, - 0x000040, 0x003465, 0x020042, 0x42004A, - 0x004020, 0x4A004A, 0x000606, 0x50004A, - 0x0017FD, 0x018042, 0x08000A, 0x000904, - 0x225A86, 0x000007, 0x00107D, 0x018042, - 0x0011FD, 0x33804A, 0x19804A, 0x20000A, - 0x000095, 0x2A1144, 0x01A144, 0x3B9086, - 0x00040D, 0x00B184, 0x3B9186, 0x0018FD, - 0x018042, 0x0010FD, 0x09804A, 0x38000A, - 0x000095, 0x010924, 0x003A64, 0x3B8186, - 0x000007, 0x003904, 0x3B9286, 0x000007, - 0x3B9A06, 0x00000D, 0x00008D, 0x000820, - 0x00387D, 0x018040, 0x700002, 0x00117D, - 0x018042, 0x00197D, 0x29804A, 0x30000A, - 0x380002, 0x003124, 0x000424, 0x000424, - 0x002A24, 0x280502, 0x00068D, 0x000810, - 0x28143A, 0x00750D, 0x00B124, 0x002264, - 0x3D0386, 0x284402, 0x000810, 0x280C3A, - 0x0B800D, 0x000820, 0x0002FD, 0x018040, - 0x200007, 0x00758D, 0x00B124, 0x100102, - 0x012144, 0x3E4986, 0x001810, 0x10003A, - 0x00387D, 0x018042, 0x08000A, 0x000904, - 0x3E4886, 0x030000, 0x3E4A06, 0x0000BD, - 0x00008D, 0x023164, 0x000A64, 0x280D02, - 0x0B808D, 0x000820, 0x0002FD, 0x018040, - 0x200007, 0x00387D, 0x018042, 0x08000A, - 0x000904, 0x3E3286, 0x030000, 0x0002FD, - 0x018042, 0x08000A, 0x000904, 0x3D8286, - 0x000007, 0x002810, 0x28043A, 0x00750D, - 0x030924, 0x002264, 0x280D02, 0x02316C, - 0x28450A, 0x0B810D, 0x000820, 0x0002FD, - 0x018040, 0x200007, 0x00008D, 0x000A24, - 0x3E4A06, 0x100102, 0x001810, 0x10003A, - 0x0000BD, 0x003810, 0x30043A, 0x00187D, - 0x018042, 0x0018FD, 0x09804A, 0x20000A, - 0x0000AD, 0x028924, 0x07212C, 0x001010, - 0x300583, 0x300D8B, 0x3014BB, 0x301C83, - 0x002083, 0x00137D, 0x038042, 0x33844A, - 0x33ACCB, 0x33B4CB, 0x33BCCB, 0x33C4CB, - 0x33CCCB, 0x33D4CB, 0x305C8B, 0x006083, - 0x001E0D, 0x0005FD, 0x018042, 0x20000A, - 0x020924, 0x00068D, 0x00A96C, 0x00009D, - 0x0002FD, 0x018042, 0x08000A, 0x000904, - 0x3F6A86, 0x000007, 0x280502, 0x280D0A, - 0x284402, 0x001810, 0x28143A, 0x0C008D, - 0x000820, 0x0002FD, 0x018040, 0x220007, - 0x003904, 0x225886, 0x001E0D, 0x00057D, - 0x018042, 0x20000A, 0x020924, 0x0000A5, - 0x0002FD, 0x018042, 0x08000A, 0x000904, - 0x402A86, 0x000007, 0x280502, 0x280C02, - 0x002010, 0x28143A, 0x0C010D, 0x000820, - 0x0002FD, 0x018040, 0x225A06, 0x220007, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000 -}; - -#endif //_HWMCODE_ diff --git a/sound/oss/yss225.c b/sound/oss/yss225.c deleted file mode 100644 index e700400576d8..000000000000 --- a/sound/oss/yss225.c +++ /dev/null @@ -1,319 +0,0 @@ -#include - -unsigned char page_zero[] __initdata = { -0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00, -0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00, -0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00, -0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19, -0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01, -0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00, -0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02, -0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, -0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00, -0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00, -0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02, -0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40, -0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02, -0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, -0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00, -0x1d, 0x02, 0xdf -}; - -unsigned char page_one[] __initdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00, -0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00, -0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, -0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00, -0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7, -0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, -0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0, -0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00, -0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0, -0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, -0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, -0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, -0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02, -0x60, 0x00, 0x1b -}; - -unsigned char page_two[] __initdata = { -0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4, -0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07, -0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46, -0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46, -0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, -0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05, -0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05, -0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44 -}; - -unsigned char page_three[] __initdata = { -0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06, -0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, -0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, -0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40, -0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, -0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, -0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00, -0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40 -}; - -unsigned char page_four[] __initdata = { -0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, -0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00, -0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, -0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, -0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22, -0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01 -}; - -unsigned char page_six[] __initdata = { -0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, -0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e, -0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00, -0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00, -0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24, -0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00, -0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00, -0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a, -0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00, -0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d, -0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50, -0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00, -0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17, -0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66, -0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c, -0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00, -0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c, -0x80, 0x00, 0x7e, 0x80, 0x80 -}; - -unsigned char page_seven[] __initdata = { -0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, -0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, -0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, -0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, -0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f, -0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38, -0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06, -0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b, -0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06, -0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, -0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14, -0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93, -0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x02, 0x00 -}; - -unsigned char page_zero_v2[] __initdata = { -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -unsigned char page_one_v2[] __initdata = { -0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -unsigned char page_two_v2[] __initdata = { -0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 -}; -unsigned char page_three_v2[] __initdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 -}; -unsigned char page_four_v2[] __initdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 -}; - -unsigned char page_seven_v2[] __initdata = { -0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -unsigned char mod_v2[] __initdata = { -0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02, -0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05, -0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0, -0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20, -0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3, -0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff, -0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16, -0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff, -0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31, -0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, -0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, -0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00, -0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, -0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, -0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72, -0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0, -0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, -0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, -0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0, -0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, -0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, -0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00, -0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, -0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00, -0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02, -0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03, -0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01, -0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01 -}; -unsigned char coefficients[] __initdata = { -0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03, -0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, -0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01, -0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00, -0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00, -0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47, -0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07, -0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00, -0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01, -0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, -0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07, -0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, -0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02, -0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44, -0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, -0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40, -0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a, -0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56, -0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07, -0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda, -0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05, -0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79, -0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07, -0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52, -0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03, -0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a, -0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06, -0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3, -0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20, -0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c, -0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06, -0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48, -0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02, -0xba -}; -unsigned char coefficients2[] __initdata = { -0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f, -0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d, -0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07, -0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, -0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00 -}; -unsigned char coefficients3[] __initdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00, -0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc, -0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01, -0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99, -0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02, -0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f, -0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03, -0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c, -0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03, -0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51, -0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04, -0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e, -0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05, -0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14, -0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06, -0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1, -0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07, -0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7, -0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08, -0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3, -0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09, -0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99, -0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a, -0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66, -0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a, -0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c, -0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b, -0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28, -0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c, -0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e, -0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d, -0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb, -0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e, -0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1, -0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f, -0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae, -0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff -}; - diff --git a/sound/oss/yss225.h b/sound/oss/yss225.h deleted file mode 100644 index 56d8b6b5e432..000000000000 --- a/sound/oss/yss225.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __yss255_h__ -#define __yss255_h__ - -extern unsigned char page_zero[256]; -extern unsigned char page_one[256]; -extern unsigned char page_two[128]; -extern unsigned char page_three[128]; -extern unsigned char page_four[128]; -extern unsigned char page_six[192]; -extern unsigned char page_seven[256]; -extern unsigned char page_zero_v2[96]; -extern unsigned char page_one_v2[96]; -extern unsigned char page_two_v2[48]; -extern unsigned char page_three_v2[48]; -extern unsigned char page_four_v2[48]; -extern unsigned char page_seven_v2[96]; -extern unsigned char mod_v2[304]; -extern unsigned char coefficients[364]; -extern unsigned char coefficients2[56]; -extern unsigned char coefficients3[404]; - - -#endif /* __ys225_h__ */ - diff --git a/sound/sound_core.c b/sound/sound_core.c index 0b0a016ca6d6..5322c50c9617 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -365,25 +365,6 @@ int register_sound_dsp(const struct file_operations *fops, int dev) EXPORT_SYMBOL(register_sound_dsp); -/** - * register_sound_synth - register a synth device - * @fops: File operations for the driver - * @dev: Unit number to allocate - * - * Allocate a synth device. Unit is the number of the synth device requested. - * Pass -1 to request the next free synth unit. On success the allocated - * number is returned, on failure a negative error code is returned. - */ - - -int register_sound_synth(const struct file_operations *fops, int dev) -{ - return sound_insert_unit(&chains[9], fops, dev, 9, 137, - "synth", S_IRUSR | S_IWUSR, NULL); -} - -EXPORT_SYMBOL(register_sound_synth); - /** * unregister_sound_special - unregister a special sound device * @unit: unit number to allocate @@ -449,21 +430,6 @@ void unregister_sound_dsp(int unit) EXPORT_SYMBOL(unregister_sound_dsp); -/** - * unregister_sound_synth - unregister a synth device - * @unit: unit number to allocate - * - * Release a sound device that was allocated with register_sound_synth(). - * The unit passed is the return value from the register function. - */ - -void unregister_sound_synth(int unit) -{ - return sound_remove_unit(&chains[9], unit); -} - -EXPORT_SYMBOL(unregister_sound_synth); - /* * Now our file operations */ -- cgit v1.2.3 From c4710e65c005339b5979fa258bf89940dc2a700b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 4 Oct 2006 17:32:21 +0100 Subject: [MIPS] Remove remaining reference to ite_gpio.h from Kbuild Signed-off-by: David Woodhouse Signed-off-by: Ralf Baechle --- include/linux/Kbuild | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index ea005c0a79fd..5114ff18101d 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -100,7 +100,6 @@ header-y += ipx.h header-y += irda.h header-y += isdn_divertif.h header-y += iso_fs.h -header-y += ite_gpio.h header-y += ixjuser.h header-y += jffs2.h header-y += keyctl.h -- cgit v1.2.3 From 9ab4f88b7ffdf338773e7755f923bc6b9e079834 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Oct 2006 16:02:06 +0200 Subject: [PATCH] serial: Rename PORT_AT91 -> PORT_ATMEL The at91_serial driver can be used with both AT32 and AT91 devices from Atmel and has therefore been renamed atmel_serial. The only thing left is to rename PORT_AT91 PORT_ATMEL. Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Linus Torvalds --- drivers/serial/atmel_serial.c | 6 +++--- include/linux/serial_core.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 7397d5df6d9f..2c5b72ccc4be 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -581,7 +581,7 @@ static void atmel_set_termios(struct uart_port *port, struct termios * termios, */ static const char *atmel_type(struct uart_port *port) { - return (port->type == PORT_AT91) ? "ATMEL_SERIAL" : NULL; + return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL; } /* @@ -628,7 +628,7 @@ static int atmel_request_port(struct uart_port *port) static void atmel_config_port(struct uart_port *port, int flags) { if (flags & UART_CONFIG_TYPE) { - port->type = PORT_AT91; + port->type = PORT_ATMEL; atmel_request_port(port); } } @@ -639,7 +639,7 @@ static void atmel_config_port(struct uart_port *port, int flags) static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser) { int ret = 0; - if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91) + if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL) ret = -EINVAL; if (port->irq != ser->irq) ret = -EINVAL; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index de2e68159d96..b661c19f3f72 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -67,8 +67,8 @@ /* Parisc type numbers. */ #define PORT_MUX 48 -/* Atmel AT91xxx SoC */ -#define PORT_AT91 49 +/* Atmel AT91 / AT32 SoC */ +#define PORT_ATMEL 49 /* Macintosh Zilog type numbers */ #define PORT_MAC_ZILOG 50 /* m68k : not yet implemented */ -- cgit v1.2.3 From f583f4924d669d36de677e0cc2422ee95203d444 Mon Sep 17 00:00:00 2001 From: David C Somayajulu Date: Wed, 4 Oct 2006 08:27:25 +0200 Subject: [PATCH] helper function for retrieving scsi_cmd given host based block layer tag This was necessitated by the need for a function to get back to a scsi_cmnd, when an hba the posts its (corresponding) completion interrupt with a block layer tag as its reference. Signed-off-by: Mike Christie Signed-off-by: David Somayajulu Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 7 +------ include/linux/blkdev.h | 8 ++++++++ include/scsi/scsi_tcq.h | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 83425fb3c8db..c847e17e5caa 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -840,12 +840,7 @@ EXPORT_SYMBOL(blk_queue_dma_alignment); **/ struct request *blk_queue_find_tag(request_queue_t *q, int tag) { - struct blk_queue_tag *bqt = q->queue_tags; - - if (unlikely(bqt == NULL || tag >= bqt->real_max_depth)) - return NULL; - - return bqt->tag_index[tag]; + return blk_map_queue_find_tag(q->queue_tags, tag); } EXPORT_SYMBOL(blk_queue_find_tag); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1d79b8d4ca6d..26f7856ff812 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -769,6 +769,14 @@ extern struct blk_queue_tag *blk_init_tags(int); extern void blk_free_tags(struct blk_queue_tag *); extern void blk_congestion_end(int rw); +static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, + int tag) +{ + if (unlikely(bqt == NULL || tag >= bqt->real_max_depth)) + return NULL; + return bqt->tag_index[tag]; +} + extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *); extern int blkdev_issue_flush(struct block_device *, sector_t *); diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h index c247a28259bc..cf4c219c0b5c 100644 --- a/include/scsi/scsi_tcq.h +++ b/include/scsi/scsi_tcq.h @@ -144,5 +144,25 @@ static inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth) return shost->bqt ? 0 : -ENOMEM; } +/** + * scsi_host_find_tag - find the tagged command by host + * @shost: pointer to scsi_host + * @tag: tag of the scsi_cmnd + * + * Notes: + * Only works with tags allocated by the generic blk layer. + **/ +static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost, + int tag) +{ + struct request *req; + + if (tag != SCSI_NO_TAG) { + req = blk_map_queue_find_tag(shost->bqt, tag); + return req ? (struct scsi_cmnd *)req->special : NULL; + } + return NULL; +} + #endif /* CONFIG_BLOCK */ #endif /* _SCSI_SCSI_TCQ_H */ -- cgit v1.2.3 From 2c2345c2b4fec30d12e1e1a6ee153a80af101e32 Mon Sep 17 00:00:00 2001 From: Roger Gammans Date: Wed, 4 Oct 2006 13:37:45 +0200 Subject: [PATCH] Document bi_sector and sector_t Signed-Off-By: Roger Gammans Signed-off-by: Jens Axboe --- include/linux/bio.h | 3 ++- include/linux/types.h | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bio.h b/include/linux/bio.h index 711c321a7011..092dbd0e7658 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -70,7 +70,8 @@ typedef void (bio_destructor_t) (struct bio *); * stacking drivers) */ struct bio { - sector_t bi_sector; + sector_t bi_sector; /* device address in 512 byte + sectors */ struct bio *bi_next; /* request queue link */ struct block_device *bi_bdev; unsigned long bi_flags; /* status, command, etc */ diff --git a/include/linux/types.h b/include/linux/types.h index 406d4ae57631..750f085fa564 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -129,8 +129,12 @@ typedef __s64 int64_t; /* this is a special 64bit data type that is 8-byte aligned */ #define aligned_u64 unsigned long long __attribute__((aligned(8))) -/* +/** * The type used for indexing onto a disc or disc partition. + * + * Linux always considers sectors to be 512 bytes long independently + * of the devices real block size. + * * If required, asm/types.h can override it and define * HAVE_SECTOR_T */ -- cgit v1.2.3 From ed542bed126caeefc6546b276e4af852d4d34f33 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Oct 2006 07:05:11 -0400 Subject: [SCSI] raid class: handle component-add errors Signed-off-by: Jeff Garzik Signed-off-by: James Bottomley --- drivers/scsi/raid_class.c | 20 ++++++++++++++++---- include/linux/raid_class.h | 5 +++-- 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index 327b33a57b0a..86e13183c9ba 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -215,18 +215,19 @@ static void raid_component_release(struct class_device *cdev) kfree(rc); } -void raid_component_add(struct raid_template *r,struct device *raid_dev, - struct device *component_dev) +int raid_component_add(struct raid_template *r,struct device *raid_dev, + struct device *component_dev) { struct class_device *cdev = attribute_container_find_class_device(&r->raid_attrs.ac, raid_dev); struct raid_component *rc; struct raid_data *rd = class_get_devdata(cdev); + int err; rc = kzalloc(sizeof(*rc), GFP_KERNEL); if (!rc) - return; + return -ENOMEM; INIT_LIST_HEAD(&rc->node); class_device_initialize(&rc->cdev); @@ -239,7 +240,18 @@ void raid_component_add(struct raid_template *r,struct device *raid_dev, list_add_tail(&rc->node, &rd->component_list); rc->cdev.parent = cdev; rc->cdev.class = &raid_class.class; - class_device_add(&rc->cdev); + err = class_device_add(&rc->cdev); + if (err) + goto err_out; + + return 0; + +err_out: + list_del(&rc->node); + rd->component_count--; + put_device(component_dev); + kfree(rc); + return err; } EXPORT_SYMBOL(raid_component_add); diff --git a/include/linux/raid_class.h b/include/linux/raid_class.h index d0dd38b3a2fd..d22ad392242a 100644 --- a/include/linux/raid_class.h +++ b/include/linux/raid_class.h @@ -77,5 +77,6 @@ DEFINE_RAID_ATTRIBUTE(enum raid_state, state) struct raid_template *raid_class_attach(struct raid_function_template *); void raid_class_release(struct raid_template *); -void raid_component_add(struct raid_template *, struct device *, - struct device *); +int __must_check raid_component_add(struct raid_template *, struct device *, + struct device *); + -- cgit v1.2.3 From 57a58a9435aef3e0342ba4b2c97e0ddfea6f2c7f Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Oct 2006 13:06:34 +0100 Subject: IRQ: Typedef the IRQ flow handler function type Typedef the IRQ flow handler function type. Signed-Off-By: David Howells (cherry picked from 8e973fbdf5716b93a0a8c0365be33a31ca0fa351 commit) --- include/linux/irq.h | 30 ++++++++++++------------------ kernel/irq/chip.c | 12 +++--------- 2 files changed, 15 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 6f463606c318..b947d46e4b18 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -22,6 +22,12 @@ #include #include +struct irq_desc; +typedef void fastcall (*irq_flow_handler_t)(unsigned int irq, + struct irq_desc *desc, + struct pt_regs *regs); + + /* * IRQ line status. * @@ -139,9 +145,7 @@ struct irq_chip { * Pad this out to 32 bytes for cache and indexing reasons. */ struct irq_desc { - void fastcall (*handle_irq)(unsigned int irq, - struct irq_desc *desc, - struct pt_regs *regs); + irq_flow_handler_t handle_irq; struct irq_chip *chip; void *handler_data; void *chip_data; @@ -281,9 +285,7 @@ handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs); * Get a descriptive string for the highlevel handler, for * /proc/interrupts output: */ -extern const char * -handle_irq_name(void fastcall (*handle)(unsigned int, struct irq_desc *, - struct pt_regs *)); +extern const char *handle_irq_name(irq_flow_handler_t handle); /* * Monolithic do_IRQ implementation. @@ -335,22 +337,15 @@ extern struct irq_chip dummy_irq_chip; extern void set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, - void fastcall (*handle)(unsigned int, - struct irq_desc *, - struct pt_regs *)); + irq_flow_handler_t handle); extern void -__set_irq_handler(unsigned int irq, - void fastcall (*handle)(unsigned int, struct irq_desc *, - struct pt_regs *), - int is_chained); +__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained); /* * Set a highlevel flow handler for a given IRQ: */ static inline void -set_irq_handler(unsigned int irq, - void fastcall (*handle)(unsigned int, struct irq_desc *, - struct pt_regs *)) +set_irq_handler(unsigned int irq, irq_flow_handler_t handle) { __set_irq_handler(irq, handle, 0); } @@ -362,8 +357,7 @@ set_irq_handler(unsigned int irq, */ static inline void set_irq_chained_handler(unsigned int irq, - void fastcall (*handle)(unsigned int, struct irq_desc *, - struct pt_regs *)) + irq_flow_handler_t handle) { __set_irq_handler(irq, handle, 1); } diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 4cf65f5c6a74..53e9dce6c657 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -505,10 +505,7 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) #endif /* CONFIG_SMP */ void -__set_irq_handler(unsigned int irq, - void fastcall (*handle)(unsigned int, irq_desc_t *, - struct pt_regs *), - int is_chained) +__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained) { struct irq_desc *desc; unsigned long flags; @@ -561,9 +558,7 @@ __set_irq_handler(unsigned int irq, void set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, - void fastcall (*handle)(unsigned int, - struct irq_desc *, - struct pt_regs *)) + irq_flow_handler_t handle) { set_irq_chip(irq, chip); __set_irq_handler(irq, handle, 0); @@ -574,8 +569,7 @@ set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, * /proc/interrupts output: */ const char * -handle_irq_name(void fastcall (*handle)(unsigned int, struct irq_desc *, - struct pt_regs *)) +handle_irq_name(irq_flow_handler_t handle) { if (handle == handle_level_irq) return "level "; -- cgit v1.2.3 From da482792a6d1a3fbaaa25fae867b343fb4db3246 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Oct 2006 13:06:34 +0100 Subject: IRQ: Typedef the IRQ handler function type Typedef the IRQ handler function type. Signed-Off-By: David Howells (cherry picked from 1356d1e5fd256997e3d3dce0777ab787d0515c7a commit) --- include/linux/interrupt.h | 7 ++++--- kernel/irq/manage.c | 4 +--- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 1f97e3d92639..19782350dcc8 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -64,8 +64,10 @@ #define SA_TRIGGER_RISING IRQF_TRIGGER_RISING #define SA_TRIGGER_MASK IRQF_TRIGGER_MASK +typedef irqreturn_t (*irq_handler_t)(int, void *, struct pt_regs *); + struct irqaction { - irqreturn_t (*handler)(int, void *, struct pt_regs *); + irq_handler_t handler; unsigned long flags; cpumask_t mask; const char *name; @@ -76,8 +78,7 @@ struct irqaction { }; extern irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs); -extern int request_irq(unsigned int, - irqreturn_t (*handler)(int, void *, struct pt_regs *), +extern int request_irq(unsigned int, irq_handler_t handler, unsigned long, const char *, void *); extern void free_irq(unsigned int, void *); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 92be519eff26..6879202afe9a 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -427,8 +427,7 @@ EXPORT_SYMBOL(free_irq); * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy * */ -int request_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), +int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id) { struct irqaction *action; @@ -475,4 +474,3 @@ int request_irq(unsigned int irq, return retval; } EXPORT_SYMBOL(request_irq); - -- cgit v1.2.3 From 7d12e780e003f93433d49ce78cfedf4b4c52adc5 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Oct 2006 14:55:46 +0100 Subject: IRQ: Maintain regs pointer globally rather than passing to IRQ handlers Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit) --- arch/frv/kernel/dma.c | 5 +- arch/frv/kernel/irq-mb93091.c | 4 +- arch/frv/kernel/irq-mb93093.c | 4 +- arch/frv/kernel/irq-mb93493.c | 4 +- arch/frv/kernel/irq.c | 2 +- arch/frv/kernel/time.c | 8 +- arch/i386/kernel/apic.c | 18 +-- arch/i386/kernel/i8259.c | 4 +- arch/i386/kernel/irq.c | 12 +- arch/i386/kernel/smp.c | 6 + arch/i386/kernel/time.c | 6 +- arch/i386/kernel/time_hpet.c | 4 +- arch/i386/kernel/vm86.c | 2 +- arch/i386/mach-visws/visws_apic.c | 4 +- arch/i386/mach-voyager/voyager_basic.c | 2 +- arch/i386/mach-voyager/voyager_smp.c | 28 +++-- arch/ia64/kernel/irq_ia64.c | 4 +- arch/ia64/kernel/machvec.c | 2 +- arch/ia64/kernel/mca.c | 32 +++-- arch/ia64/kernel/time.c | 8 +- arch/ia64/sn/pci/tioca_provider.c | 3 +- arch/ia64/sn/pci/tioce_provider.c | 3 +- arch/mips/kernel/irq.c | 4 +- arch/mips/kernel/time.c | 24 ++-- arch/mips/sgi-ip22/ip22-reset.c | 2 +- arch/mips/sgi-ip22/ip22-time.c | 4 +- arch/powerpc/kernel/irq.c | 6 +- arch/powerpc/kernel/misc_64.S | 6 +- arch/powerpc/kernel/smp.c | 6 +- arch/powerpc/kernel/time.c | 6 +- arch/powerpc/platforms/cell/interrupt.c | 4 +- arch/powerpc/platforms/cell/spider-pic.c | 5 +- arch/powerpc/platforms/powermac/low_i2c.c | 2 +- arch/powerpc/platforms/powermac/pfunc_base.c | 2 +- arch/powerpc/platforms/powermac/pic.c | 7 +- arch/powerpc/platforms/pseries/ras.c | 14 +-- arch/powerpc/platforms/pseries/setup.c | 7 +- arch/powerpc/platforms/pseries/xics.c | 18 +-- arch/powerpc/platforms/pseries/xics.h | 3 +- arch/powerpc/sysdev/mpic.c | 4 +- arch/powerpc/xmon/xmon.c | 6 +- arch/x86_64/kernel/apic.c | 12 +- arch/x86_64/kernel/irq.c | 7 +- arch/x86_64/kernel/time.c | 20 ++-- drivers/acorn/block/mfmhd.c | 2 +- drivers/acpi/osl.c | 2 +- drivers/ata/ahci.c | 4 +- drivers/ata/libata-core.c | 3 +- drivers/ata/pdc_adma.c | 5 +- drivers/ata/sata_mv.c | 6 +- drivers/ata/sata_nv.c | 18 +-- drivers/ata/sata_promise.c | 4 +- drivers/ata/sata_qstor.c | 4 +- drivers/ata/sata_sil.c | 6 +- drivers/ata/sata_sil24.c | 4 +- drivers/ata/sata_sx4.c | 4 +- drivers/ata/sata_vsc.c | 3 +- drivers/atm/ambassador.c | 4 +- drivers/atm/eni.c | 2 +- drivers/atm/firestream.c | 2 +- drivers/atm/fore200e.c | 2 +- drivers/atm/he.c | 4 +- drivers/atm/horizon.c | 4 +- drivers/atm/idt77252.c | 2 +- drivers/atm/iphase.c | 2 +- drivers/atm/lanai.c | 4 +- drivers/atm/nicstar.c | 4 +- drivers/atm/zatm.c | 2 +- drivers/block/DAC960.c | 24 ++-- drivers/block/DAC960.h | 14 +-- drivers/block/acsi.c | 4 +- drivers/block/acsi_slm.c | 4 +- drivers/block/amiflop.c | 4 +- drivers/block/ataflop.c | 4 +- drivers/block/cciss.c | 6 +- drivers/block/cpqarray.c | 4 +- drivers/block/floppy.c | 4 +- drivers/block/ps2esdi.c | 6 +- drivers/block/swim3.c | 8 +- drivers/block/swim_iop.c | 4 +- drivers/block/sx8.c | 2 +- drivers/block/ub.c | 6 +- drivers/block/umem.c | 2 +- drivers/block/xd.c | 3 +- drivers/block/xd.h | 3 +- drivers/bluetooth/bcm203x.c | 2 +- drivers/bluetooth/bfusb.c | 8 +- drivers/bluetooth/bluecard_cs.c | 2 +- drivers/bluetooth/bpa10x.c | 2 +- drivers/bluetooth/bt3c_cs.c | 2 +- drivers/bluetooth/btuart_cs.c | 2 +- drivers/bluetooth/dtl1_cs.c | 2 +- drivers/bluetooth/hci_usb.c | 8 +- drivers/cdrom/cdu31a.c | 2 +- drivers/cdrom/cm206.c | 2 +- drivers/cdrom/mcdx.c | 2 +- drivers/cdrom/sonycd535.c | 2 +- drivers/char/amiserial.c | 6 +- drivers/char/applicom.c | 4 +- drivers/char/cyclades.c | 4 +- drivers/char/drm/drm_os_linux.h | 2 +- drivers/char/ec3104_keyb.c | 2 +- drivers/char/esp.c | 3 +- drivers/char/ftape/lowlevel/fdc-io.c | 2 +- drivers/char/hangcheck-timer.c | 2 +- drivers/char/hpet.c | 2 +- drivers/char/hvc_console.c | 4 +- drivers/char/hvcs.c | 6 +- drivers/char/hvsi.c | 6 +- drivers/char/ip2/ip2main.c | 9 +- drivers/char/ipmi/ipmi_si_intf.c | 6 +- drivers/char/ipmi/ipmi_watchdog.c | 2 +- drivers/char/isicom.c | 2 +- drivers/char/keyboard.c | 135 +++++++++++----------- drivers/char/mbcs.c | 3 +- drivers/char/mmtimer.c | 3 +- drivers/char/mwave/tp3780i.c | 4 +- drivers/char/mxser.c | 4 +- drivers/char/nwbutton.c | 2 +- drivers/char/nwbutton.h | 2 +- drivers/char/pcmcia/synclink_cs.c | 5 +- drivers/char/ppdev.c | 2 +- drivers/char/qtronix.c | 4 +- drivers/char/rio/rio_linux.c | 4 +- drivers/char/riscom8.c | 2 +- drivers/char/rtc.c | 8 +- drivers/char/ser_a2232.c | 4 +- drivers/char/serial167.c | 8 +- drivers/char/snsc.c | 2 +- drivers/char/snsc_event.c | 2 +- drivers/char/sonypi.c | 2 +- drivers/char/specialix.c | 4 +- drivers/char/stallion.c | 5 +- drivers/char/sx.c | 4 +- drivers/char/synclink.c | 3 +- drivers/char/synclink_gt.c | 5 +- drivers/char/synclinkmp.c | 3 +- drivers/char/sysrq.c | 62 ++++------ drivers/char/tlclk.c | 4 +- drivers/char/tpm/tpm_tis.c | 4 +- drivers/char/vme_scc.c | 18 +-- drivers/char/vr41xx_giu.c | 2 +- drivers/char/watchdog/eurotechwdt.c | 2 +- drivers/char/watchdog/mpcore_wdt.c | 2 +- drivers/char/watchdog/pcwd_usb.c | 2 +- drivers/char/watchdog/s3c2410_wdt.c | 3 +- drivers/char/watchdog/wdt.c | 3 +- drivers/char/watchdog/wdt285.c | 2 +- drivers/char/watchdog/wdt_pci.c | 3 +- drivers/dma/ioatdma.c | 2 +- drivers/fc4/soc.c | 2 +- drivers/fc4/socal.c | 2 +- drivers/i2c/busses/i2c-elektor.c | 2 +- drivers/i2c/busses/i2c-ibm_iic.c | 2 +- drivers/i2c/busses/i2c-iop3xx.c | 2 +- drivers/i2c/busses/i2c-ite.c | 3 +- drivers/i2c/busses/i2c-mpc.c | 2 +- drivers/i2c/busses/i2c-mv64xxx.c | 2 +- drivers/i2c/busses/i2c-ocores.c | 2 +- drivers/i2c/busses/i2c-omap.c | 4 +- drivers/i2c/busses/i2c-pca-isa.c | 2 +- drivers/i2c/busses/i2c-pxa.c | 2 +- drivers/i2c/busses/i2c-rpx.c | 4 +- drivers/i2c/busses/i2c-s3c2410.c | 3 +- drivers/i2c/chips/isp1301_omap.c | 4 +- drivers/i2c/chips/tps65010.c | 2 +- drivers/ide/ide-io.c | 2 +- drivers/ide/legacy/hd.c | 2 +- drivers/ide/legacy/macide.c | 2 +- drivers/ieee1394/ohci1394.c | 3 +- drivers/ieee1394/pcilynx.c | 3 +- drivers/infiniband/hw/amso1100/c2.c | 4 +- drivers/infiniband/hw/ehca/ehca_irq.c | 4 +- drivers/infiniband/hw/ehca/ehca_irq.h | 4 +- drivers/infiniband/hw/ipath/ipath_intr.c | 2 +- drivers/infiniband/hw/ipath/ipath_kernel.h | 2 +- drivers/infiniband/hw/mthca/mthca_eq.c | 10 +- drivers/input/joystick/amijoy.c | 4 +- drivers/input/joystick/iforce/iforce-packets.c | 6 +- drivers/input/joystick/iforce/iforce-serio.c | 4 +- drivers/input/joystick/iforce/iforce-usb.c | 8 +- drivers/input/joystick/iforce/iforce.h | 2 +- drivers/input/joystick/magellan.c | 8 +- drivers/input/joystick/spaceball.c | 8 +- drivers/input/joystick/spaceorb.c | 8 +- drivers/input/joystick/stinger.c | 8 +- drivers/input/joystick/twidjoy.c | 8 +- drivers/input/joystick/warrior.c | 10 +- drivers/input/keyboard/amikbd.c | 4 +- drivers/input/keyboard/atkbd.c | 4 +- drivers/input/keyboard/corgikbd.c | 9 +- drivers/input/keyboard/hil_kbd.c | 2 +- drivers/input/keyboard/hilkbd.c | 2 +- drivers/input/keyboard/lkkbd.c | 5 +- drivers/input/keyboard/locomokbd.c | 8 +- drivers/input/keyboard/newtonkbd.c | 3 +- drivers/input/keyboard/omap-keypad.c | 3 +- drivers/input/keyboard/spitzkbd.c | 10 +- drivers/input/keyboard/stowaway.c | 3 +- drivers/input/keyboard/sunkbd.c | 3 +- drivers/input/keyboard/xtkbd.c | 3 +- drivers/input/misc/ixp4xx-beeper.c | 2 +- drivers/input/mouse/alps.c | 10 +- drivers/input/mouse/amimouse.c | 4 +- drivers/input/mouse/hil_ptr.c | 2 +- drivers/input/mouse/inport.c | 4 +- drivers/input/mouse/lifebook.c | 4 +- drivers/input/mouse/logibm.c | 3 +- drivers/input/mouse/logips2pp.c | 4 +- drivers/input/mouse/pc110pad.c | 9 +- drivers/input/mouse/psmouse-base.c | 16 ++- drivers/input/mouse/psmouse.h | 2 +- drivers/input/mouse/rpcmouse.c | 4 +- drivers/input/mouse/sermouse.c | 14 +-- drivers/input/mouse/synaptics.c | 15 +-- drivers/input/mouse/vsxxxaa.c | 22 ++-- drivers/input/serio/ambakmi.c | 4 +- drivers/input/serio/ct82c710.c | 4 +- drivers/input/serio/gscps2.c | 6 +- drivers/input/serio/hp_sdc.c | 4 +- drivers/input/serio/i8042.c | 12 +- drivers/input/serio/maceps2.c | 5 +- drivers/input/serio/parkbd.c | 4 +- drivers/input/serio/pcips2.c | 4 +- drivers/input/serio/q40kbd.c | 4 +- drivers/input/serio/rpckbd.c | 6 +- drivers/input/serio/sa1111ps2.c | 6 +- drivers/input/serio/serio.c | 4 +- drivers/input/serio/serio_raw.c | 2 +- drivers/input/serio/serport.c | 5 +- drivers/input/touchscreen/ads7846.c | 2 +- drivers/input/touchscreen/corgi_ts.c | 13 +-- drivers/input/touchscreen/elo.c | 17 ++- drivers/input/touchscreen/gunze.c | 7 +- drivers/input/touchscreen/h3600_ts_input.c | 14 +-- drivers/input/touchscreen/hp680_ts_input.c | 2 +- drivers/input/touchscreen/mk712.c | 3 +- drivers/input/touchscreen/mtouch.c | 11 +- drivers/input/touchscreen/penmount.c | 3 +- drivers/input/touchscreen/touchright.c | 3 +- drivers/input/touchscreen/touchwin.c | 3 +- drivers/isdn/act2000/act2000_isa.c | 2 +- drivers/isdn/gigaset/bas-gigaset.c | 12 +- drivers/isdn/gigaset/usb-gigaset.c | 4 +- drivers/isdn/hardware/avm/avmcard.h | 4 +- drivers/isdn/hardware/avm/b1.c | 2 +- drivers/isdn/hardware/avm/b1dma.c | 2 +- drivers/isdn/hardware/avm/c4.c | 2 +- drivers/isdn/hardware/avm/t1isa.c | 2 +- drivers/isdn/hardware/eicon/diva.c | 4 +- drivers/isdn/hardware/eicon/divasmain.c | 3 +- drivers/isdn/hisax/amd7930_fn.c | 2 +- drivers/isdn/hisax/asuscom.c | 4 +- drivers/isdn/hisax/avm_a1.c | 2 +- drivers/isdn/hisax/avm_a1p.c | 2 +- drivers/isdn/hisax/avm_pci.c | 2 +- drivers/isdn/hisax/bkm_a4t.c | 2 +- drivers/isdn/hisax/bkm_a8.c | 2 +- drivers/isdn/hisax/diva.c | 8 +- drivers/isdn/hisax/elsa.c | 4 +- drivers/isdn/hisax/enternow_pci.c | 2 +- drivers/isdn/hisax/gazel.c | 4 +- drivers/isdn/hisax/hfc4s8s_l1.c | 2 +- drivers/isdn/hisax/hfc_pci.c | 2 +- drivers/isdn/hisax/hfc_sx.c | 2 +- drivers/isdn/hisax/hfc_usb.c | 8 +- drivers/isdn/hisax/hfcscard.c | 2 +- drivers/isdn/hisax/hisax.h | 2 +- drivers/isdn/hisax/hisax_fcpcipnp.c | 4 +- drivers/isdn/hisax/icc.c | 2 +- drivers/isdn/hisax/isac.c | 2 +- drivers/isdn/hisax/isurf.c | 2 +- drivers/isdn/hisax/ix1_micro.c | 2 +- drivers/isdn/hisax/mic.c | 2 +- drivers/isdn/hisax/netjet.h | 2 +- drivers/isdn/hisax/niccy.c | 3 +- drivers/isdn/hisax/nj_s.c | 2 +- drivers/isdn/hisax/nj_u.c | 2 +- drivers/isdn/hisax/s0box.c | 2 +- drivers/isdn/hisax/saphir.c | 2 +- drivers/isdn/hisax/sedlbauer.c | 6 +- drivers/isdn/hisax/sportster.c | 2 +- drivers/isdn/hisax/st5481_b.c | 2 +- drivers/isdn/hisax/st5481_d.c | 2 +- drivers/isdn/hisax/st5481_usb.c | 6 +- drivers/isdn/hisax/teleint.c | 2 +- drivers/isdn/hisax/teles0.c | 2 +- drivers/isdn/hisax/teles3.c | 2 +- drivers/isdn/hisax/telespci.c | 2 +- drivers/isdn/hisax/w6692.c | 4 +- drivers/isdn/hysdn/boardergo.c | 2 +- drivers/isdn/pcbit/layer2.c | 2 +- drivers/isdn/pcbit/layer2.h | 2 +- drivers/isdn/sc/init.c | 2 +- drivers/isdn/sc/interrupt.c | 2 +- drivers/macintosh/adb-iop.c | 8 +- drivers/macintosh/adb.c | 10 +- drivers/macintosh/adbhid.c | 20 ++-- drivers/macintosh/macio-adb.c | 7 +- drivers/macintosh/smu.c | 6 +- drivers/macintosh/via-cuda.c | 12 +- drivers/macintosh/via-macii.c | 7 +- drivers/macintosh/via-maciisi.c | 12 +- drivers/macintosh/via-pmu.c | 32 ++--- drivers/macintosh/via-pmu68k.c | 13 +-- drivers/media/common/saa7146_core.c | 2 +- drivers/media/dvb/b2c2/flexcop-pci.c | 2 +- drivers/media/dvb/b2c2/flexcop-usb.c | 2 +- drivers/media/dvb/bt8xx/bt878.c | 2 +- drivers/media/dvb/cinergyT2/cinergyT2.c | 4 +- drivers/media/dvb/dvb-usb/usb-urb.c | 2 +- drivers/media/dvb/pluto2/pluto2.c | 2 +- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 2 +- drivers/media/dvb/ttusb-dec/ttusb_dec.c | 4 +- drivers/media/video/arv.c | 2 +- drivers/media/video/bt8xx/bttv-driver.c | 2 +- drivers/media/video/cpia2/cpia2_usb.c | 4 +- drivers/media/video/cpia_usb.c | 2 +- drivers/media/video/cx88/cx88-alsa.c | 2 +- drivers/media/video/cx88/cx88-mpeg.c | 2 +- drivers/media/video/cx88/cx88-video.c | 2 +- drivers/media/video/dabusb.c | 2 +- drivers/media/video/em28xx/em28xx-core.c | 6 +- drivers/media/video/et61x251/et61x251_core.c | 2 +- drivers/media/video/meye.c | 2 +- drivers/media/video/ov511.c | 2 +- drivers/media/video/planb.c | 4 +- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 4 +- drivers/media/video/pvrusb2/pvrusb2-io.c | 2 +- drivers/media/video/pwc/pwc-if.c | 2 +- drivers/media/video/saa7134/saa7134-alsa.c | 2 +- drivers/media/video/saa7134/saa7134-core.c | 2 +- drivers/media/video/saa7134/saa7134-oss.c | 2 +- drivers/media/video/se401.c | 4 +- drivers/media/video/sn9c102/sn9c102_core.c | 2 +- drivers/media/video/stradis.c | 2 +- drivers/media/video/stv680.c | 2 +- drivers/media/video/usbvideo/konicawc.c | 2 +- drivers/media/video/usbvideo/quickcam_messenger.c | 4 +- drivers/media/video/usbvideo/usbvideo.c | 2 +- drivers/media/video/vino.c | 2 +- drivers/media/video/w9968cf.c | 4 +- drivers/media/video/zc0301/zc0301_core.c | 2 +- drivers/media/video/zoran_device.c | 3 +- drivers/media/video/zoran_device.h | 4 +- drivers/media/video/zr36120.c | 4 +- drivers/message/fusion/mptbase.c | 5 +- drivers/message/i2o/pci.c | 3 +- drivers/mfd/ucb1x00-core.c | 2 +- drivers/misc/ibmasm/ibmasm.h | 4 +- drivers/misc/ibmasm/lowlevel.c | 4 +- drivers/misc/ibmasm/remote.c | 14 +-- drivers/misc/lkdtm.c | 5 +- drivers/misc/tifm_7xx1.c | 2 +- drivers/mmc/at91_mci.c | 4 +- drivers/mmc/au1xmmc.c | 2 +- drivers/mmc/imxmmc.c | 4 +- drivers/mmc/mmci.c | 4 +- drivers/mmc/omap.c | 4 +- drivers/mmc/pxamci.c | 6 +- drivers/mmc/sdhci.c | 2 +- drivers/mmc/wbsd.c | 2 +- drivers/net/3c501.c | 3 +- drivers/net/3c501.h | 2 +- drivers/net/3c505.c | 2 +- drivers/net/3c507.c | 4 +- drivers/net/3c509.c | 6 +- drivers/net/3c515.c | 6 +- drivers/net/3c523.c | 6 +- drivers/net/3c527.c | 4 +- drivers/net/3c59x.c | 14 +-- drivers/net/7990.c | 2 +- drivers/net/8139cp.c | 5 +- drivers/net/8139too.c | 8 +- drivers/net/82596.c | 8 +- drivers/net/8390.c | 5 +- drivers/net/8390.h | 2 +- drivers/net/a2065.c | 3 +- drivers/net/acenic.c | 2 +- drivers/net/acenic.h | 2 +- drivers/net/amd8111e.c | 4 +- drivers/net/apne.c | 6 +- drivers/net/appletalk/cops.c | 4 +- drivers/net/appletalk/ltpc.c | 2 +- drivers/net/arcnet/arcnet.c | 2 +- drivers/net/ariadne.c | 4 +- drivers/net/arm/am79c961a.c | 4 +- drivers/net/arm/at91_ether.c | 4 +- drivers/net/arm/ep93xx_eth.c | 2 +- drivers/net/arm/ether1.c | 4 +- drivers/net/arm/ether3.c | 4 +- drivers/net/at1700.c | 5 +- drivers/net/atari_bionet.c | 2 +- drivers/net/atari_pamsnet.c | 3 +- drivers/net/atarilance.c | 4 +- drivers/net/atp.c | 5 +- drivers/net/au1000_eth.c | 4 +- drivers/net/b44.c | 4 +- drivers/net/bmac.c | 14 +-- drivers/net/bnx2.c | 6 +- drivers/net/cassini.c | 8 +- drivers/net/chelsio/cxgb2.c | 2 +- drivers/net/chelsio/sge.c | 6 +- drivers/net/chelsio/sge.h | 9 +- drivers/net/cris/eth_v10.c | 8 +- drivers/net/cs89x0.c | 6 +- drivers/net/de600.c | 2 +- drivers/net/de600.h | 2 +- drivers/net/de620.c | 4 +- drivers/net/declance.c | 6 +- drivers/net/defxx.c | 6 +- drivers/net/depca.c | 4 +- drivers/net/dgrs.c | 2 +- drivers/net/dl2k.c | 4 +- drivers/net/dm9000.c | 4 +- drivers/net/e100.c | 4 +- drivers/net/e1000/e1000_ethtool.c | 3 +- drivers/net/e1000/e1000_main.c | 7 +- drivers/net/eepro.c | 4 +- drivers/net/eepro100.c | 6 +- drivers/net/eexpress.c | 4 +- drivers/net/ehea/ehea_main.c | 12 +- drivers/net/epic100.c | 4 +- drivers/net/eth16i.c | 4 +- drivers/net/ewrk3.c | 4 +- drivers/net/fealnx.c | 4 +- drivers/net/fec.c | 10 +- drivers/net/fec_8xx/fec_main.c | 4 +- drivers/net/forcedeth.c | 20 ++-- drivers/net/fs_enet/fs_enet-main.c | 4 +- drivers/net/gianfar.c | 22 ++-- drivers/net/gianfar.h | 2 +- drivers/net/hamachi.c | 4 +- drivers/net/hamradio/baycom_epp.c | 2 +- drivers/net/hamradio/baycom_par.c | 2 +- drivers/net/hamradio/baycom_ser_fdx.c | 2 +- drivers/net/hamradio/baycom_ser_hdx.c | 2 +- drivers/net/hamradio/dmascc.c | 4 +- drivers/net/hamradio/scc.c | 4 +- drivers/net/hamradio/yam.c | 2 +- drivers/net/hp100.c | 4 +- drivers/net/ibm_emac/ibm_emac_core.c | 4 +- drivers/net/ibm_emac/ibm_emac_debug.c | 3 +- drivers/net/ibm_emac/ibm_emac_mal.c | 10 +- drivers/net/ibmlana.c | 2 +- drivers/net/ibmveth.c | 8 +- drivers/net/ioc3-eth.c | 2 +- drivers/net/irda/ali-ircc.c | 3 +- drivers/net/irda/au1k_ir.c | 4 +- drivers/net/irda/donauboe.c | 4 +- drivers/net/irda/irda-usb.c | 12 +- drivers/net/irda/irport.c | 8 +- drivers/net/irda/irport.h | 2 +- drivers/net/irda/mcs7780.c | 4 +- drivers/net/irda/mcs7780.h | 4 +- drivers/net/irda/nsc-ircc.c | 3 +- drivers/net/irda/pxaficp_ir.c | 8 +- drivers/net/irda/sa1100_ir.c | 2 +- drivers/net/irda/smsc-ircc2.c | 6 +- drivers/net/irda/stir4200.c | 2 +- drivers/net/irda/via-ircc.c | 8 +- drivers/net/irda/vlsi_ir.c | 3 +- drivers/net/irda/w83977af_ir.c | 3 +- drivers/net/isa-skeleton.c | 4 +- drivers/net/iseries_veth.c | 2 +- drivers/net/ixgb/ixgb_main.c | 7 +- drivers/net/ixp2000/ixpdev.c | 2 +- drivers/net/lance.c | 5 +- drivers/net/lasi_82596.c | 6 +- drivers/net/lp486e.c | 4 +- drivers/net/mac89x0.c | 4 +- drivers/net/mace.c | 12 +- drivers/net/macmace.c | 8 +- drivers/net/meth.c | 4 +- drivers/net/mipsnet.c | 3 +- drivers/net/mv643xx_eth.c | 3 +- drivers/net/myri10ge/myri10ge.c | 2 +- drivers/net/myri_sbus.c | 2 +- drivers/net/natsemi.c | 6 +- drivers/net/netx-eth.c | 2 +- drivers/net/ni5010.c | 4 +- drivers/net/ni52.c | 4 +- drivers/net/ni65.c | 4 +- drivers/net/ns83820.c | 2 +- drivers/net/pci-skeleton.c | 6 +- drivers/net/pcmcia/3c574_cs.c | 6 +- drivers/net/pcmcia/3c589_cs.c | 6 +- drivers/net/pcmcia/axnet_cs.c | 12 +- drivers/net/pcmcia/fmvj18x_cs.c | 4 +- drivers/net/pcmcia/nmclan_cs.c | 4 +- drivers/net/pcmcia/pcnet_cs.c | 8 +- drivers/net/pcmcia/smc91c92_cs.c | 6 +- drivers/net/pcmcia/xirc2ps_cs.c | 4 +- drivers/net/pcnet32.c | 6 +- drivers/net/phy/phy.c | 2 +- drivers/net/plip.c | 6 +- drivers/net/qla3xxx.c | 2 +- drivers/net/r8169.c | 7 +- drivers/net/rrunner.c | 2 +- drivers/net/rrunner.h | 2 +- drivers/net/s2io.c | 12 +- drivers/net/s2io.h | 8 +- drivers/net/saa9730.c | 3 +- drivers/net/sb1000.c | 4 +- drivers/net/sb1250-mac.c | 4 +- drivers/net/seeq8005.c | 4 +- drivers/net/sgiseeq.c | 2 +- drivers/net/sis190.c | 4 +- drivers/net/sis900.c | 6 +- drivers/net/sk98lin/skge.c | 10 +- drivers/net/sk_mca.c | 2 +- drivers/net/skfp/skfddi.c | 5 +- drivers/net/skge.c | 4 +- drivers/net/sky2.c | 5 +- drivers/net/smc-ultra.c | 2 +- drivers/net/smc911x.c | 6 +- drivers/net/smc9194.c | 4 +- drivers/net/smc91x.c | 2 +- drivers/net/smc91x.h | 2 +- drivers/net/sonic.c | 2 +- drivers/net/sonic.h | 2 +- drivers/net/spider_net.c | 4 +- drivers/net/starfire.c | 4 +- drivers/net/sun3_82586.c | 4 +- drivers/net/sun3lance.c | 4 +- drivers/net/sunbmac.c | 2 +- drivers/net/sundance.c | 4 +- drivers/net/sungem.c | 4 +- drivers/net/sunhme.c | 4 +- drivers/net/sunlance.c | 2 +- drivers/net/sunqe.c | 2 +- drivers/net/tc35815.c | 4 +- drivers/net/tg3.c | 15 ++- drivers/net/tlan.c | 7 +- drivers/net/tokenring/3c359.c | 4 +- drivers/net/tokenring/ibmtr.c | 6 +- drivers/net/tokenring/lanstreamer.c | 5 +- drivers/net/tokenring/madgemc.c | 6 +- drivers/net/tokenring/olympic.c | 4 +- drivers/net/tokenring/smctr.c | 4 +- drivers/net/tokenring/tms380tr.c | 2 +- drivers/net/tokenring/tms380tr.h | 2 +- drivers/net/tulip/de2104x.c | 2 +- drivers/net/tulip/de4x5.c | 4 +- drivers/net/tulip/dmfe.c | 6 +- drivers/net/tulip/interrupt.c | 2 +- drivers/net/tulip/tulip.h | 2 +- drivers/net/tulip/tulip_core.c | 2 +- drivers/net/tulip/uli526x.c | 4 +- drivers/net/tulip/winbond-840.c | 4 +- drivers/net/tulip/xircom_cb.c | 6 +- drivers/net/tulip/xircom_tulip_cb.c | 4 +- drivers/net/typhoon.c | 2 +- drivers/net/ucc_geth.c | 5 +- drivers/net/via-rhine.c | 6 +- drivers/net/via-velocity.c | 5 +- drivers/net/wan/cosa.c | 4 +- drivers/net/wan/cycx_main.c | 4 +- drivers/net/wan/dscc4.c | 4 +- drivers/net/wan/farsync.c | 2 +- drivers/net/wan/hd6457x.c | 2 +- drivers/net/wan/lmc/lmc_main.c | 4 +- drivers/net/wan/pc300_drv.c | 4 +- drivers/net/wan/sbni.c | 4 +- drivers/net/wan/sdla.c | 2 +- drivers/net/wan/wanxl.c | 2 +- drivers/net/wan/z85230.c | 2 +- drivers/net/wan/z85230.h | 2 +- drivers/net/wireless/airo.c | 5 +- drivers/net/wireless/arlan-main.c | 4 +- drivers/net/wireless/atmel.c | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 +- drivers/net/wireless/hostap/hostap_hw.c | 2 +- drivers/net/wireless/ipw2100.c | 2 +- drivers/net/wireless/ipw2200.c | 2 +- drivers/net/wireless/netwave_cs.c | 6 +- drivers/net/wireless/orinoco.c | 2 +- drivers/net/wireless/orinoco.h | 2 +- drivers/net/wireless/prism54/islpci_dev.c | 2 +- drivers/net/wireless/prism54/islpci_dev.h | 2 +- drivers/net/wireless/ray_cs.c | 4 +- drivers/net/wireless/wavelan.c | 2 +- drivers/net/wireless/wavelan.p.h | 3 +- drivers/net/wireless/wavelan_cs.c | 3 +- drivers/net/wireless/wavelan_cs.p.h | 3 +- drivers/net/wireless/wl3501_cs.c | 3 +- drivers/net/wireless/zd1201.c | 6 +- drivers/net/wireless/zd1211rw/zd_usb.c | 6 +- drivers/net/yellowfin.c | 4 +- drivers/net/znet.c | 4 +- drivers/parisc/dino.c | 3 +- drivers/parisc/eisa.c | 4 +- drivers/parisc/gsc.c | 4 +- drivers/parisc/gsc.h | 2 +- drivers/parisc/power.c | 2 +- drivers/parisc/superio.c | 4 +- drivers/parport/daisy.c | 2 +- drivers/parport/ieee1284.c | 2 +- drivers/parport/parport_amiga.c | 4 +- drivers/parport/parport_atari.c | 4 +- drivers/parport/parport_ax88796.c | 4 +- drivers/parport/parport_gsc.c | 4 +- drivers/parport/parport_ip32.c | 11 +- drivers/parport/parport_mfc3.c | 2 +- drivers/parport/parport_pc.c | 4 +- drivers/parport/parport_sunbpp.c | 2 +- drivers/parport/share.c | 2 +- drivers/pci/hotplug/cpci_hotplug_core.c | 2 +- drivers/pci/hotplug/cpqphp.h | 2 +- drivers/pci/hotplug/cpqphp_ctrl.c | 2 +- drivers/pci/hotplug/pciehp_hpc.c | 6 +- drivers/pci/hotplug/shpchp_hpc.c | 6 +- drivers/pci/pcie/aer/aerdrv.c | 3 +- drivers/pcmcia/at91_cf.c | 2 +- drivers/pcmcia/hd64465_ss.c | 2 +- drivers/pcmcia/i82092.c | 2 +- drivers/pcmcia/i82092aa.h | 2 +- drivers/pcmcia/i82365.c | 9 +- drivers/pcmcia/m32r_cfc.c | 7 +- drivers/pcmcia/m32r_pcc.c | 4 +- drivers/pcmcia/m8xx_pcmcia.c | 4 +- drivers/pcmcia/omap_cf.c | 2 +- drivers/pcmcia/pcmcia_resource.c | 2 +- drivers/pcmcia/pd6729.c | 6 +- drivers/pcmcia/soc_common.c | 2 +- drivers/pcmcia/tcic.c | 10 +- drivers/pcmcia/vrc4171_card.c | 2 +- drivers/pcmcia/vrc4173_cardu.c | 2 +- drivers/pcmcia/yenta_socket.c | 6 +- drivers/pnp/resource.c | 2 +- drivers/rtc/rtc-at91.c | 3 +- drivers/rtc/rtc-ds1553.c | 3 +- drivers/rtc/rtc-pl031.c | 2 +- drivers/rtc/rtc-s3c.c | 4 +- drivers/rtc/rtc-sa1100.c | 6 +- drivers/rtc/rtc-sh.c | 4 +- drivers/rtc/rtc-vr41xx.c | 4 +- drivers/sbus/char/aurora.c | 4 +- drivers/sbus/char/bbc_i2c.c | 2 +- drivers/sbus/char/cpwatchdog.c | 4 +- drivers/sbus/char/uctrl.c | 2 +- drivers/scsi/3w-9xxx.c | 2 +- drivers/scsi/3w-xxxx.c | 3 +- drivers/scsi/53c700.c | 2 +- drivers/scsi/53c700.h | 2 +- drivers/scsi/53c7xx.c | 6 +- drivers/scsi/BusLogic.c | 2 +- drivers/scsi/BusLogic.h | 2 +- drivers/scsi/NCR5380.c | 6 +- drivers/scsi/NCR5380.h | 2 +- drivers/scsi/NCR53C9x.c | 6 +- drivers/scsi/NCR53C9x.h | 2 +- drivers/scsi/NCR53c406a.c | 11 +- drivers/scsi/NCR_D700.c | 4 +- drivers/scsi/NCR_Q720.c | 4 +- drivers/scsi/a100u2w.c | 2 +- drivers/scsi/a2091.c | 2 +- drivers/scsi/a3000.c | 2 +- drivers/scsi/aacraid/rx.c | 4 +- drivers/scsi/aacraid/sa.c | 2 +- drivers/scsi/advansys.c | 4 +- drivers/scsi/aha152x.c | 6 +- drivers/scsi/aha1542.c | 12 +- drivers/scsi/aha1740.c | 3 +- drivers/scsi/aic7xxx/aic79xx_osm.c | 2 +- drivers/scsi/aic7xxx/aic79xx_osm.h | 2 +- drivers/scsi/aic7xxx/aic7xxx_osm.c | 2 +- drivers/scsi/aic7xxx/aic7xxx_osm.h | 2 +- drivers/scsi/aic7xxx_old.c | 12 +- drivers/scsi/aic94xx/aic94xx_hwi.c | 3 +- drivers/scsi/aic94xx/aic94xx_hwi.h | 2 +- drivers/scsi/amiga7xx.h | 2 +- drivers/scsi/arcmsr/arcmsr_hba.c | 3 +- drivers/scsi/arm/acornscsi.c | 5 +- drivers/scsi/arm/cumana_2.c | 3 +- drivers/scsi/arm/eesox.c | 3 +- drivers/scsi/arm/powertec.c | 4 +- drivers/scsi/atari_NCR5380.c | 2 +- drivers/scsi/atari_dma_emul.c | 4 +- drivers/scsi/atari_scsi.c | 10 +- drivers/scsi/atp870u.c | 2 +- drivers/scsi/bvme6000.h | 2 +- drivers/scsi/dc395x.c | 3 +- drivers/scsi/dec_esp.c | 12 +- drivers/scsi/dpt_i2o.c | 2 +- drivers/scsi/dpti.h | 2 +- drivers/scsi/eata.c | 5 +- drivers/scsi/eata_pio.c | 7 +- drivers/scsi/esp.c | 4 +- drivers/scsi/fd_mcs.c | 4 +- drivers/scsi/fdomain.c | 6 +- drivers/scsi/gdth.c | 6 +- drivers/scsi/gvp11.c | 2 +- drivers/scsi/hptiop.c | 2 +- drivers/scsi/ibmmca.c | 3 +- drivers/scsi/ibmvscsi/rpa_vscsi.c | 5 +- drivers/scsi/in2000.c | 2 +- drivers/scsi/initio.c | 2 +- drivers/scsi/ipr.c | 3 +- drivers/scsi/ips.c | 4 +- drivers/scsi/lpfc/lpfc_crtn.h | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 2 +- drivers/scsi/mac53c94.c | 10 +- drivers/scsi/mac_esp.c | 14 +-- drivers/scsi/megaraid.c | 6 +- drivers/scsi/megaraid.h | 4 +- drivers/scsi/megaraid/megaraid_mbox.c | 4 +- drivers/scsi/megaraid/megaraid_sas.c | 2 +- drivers/scsi/mesh.c | 8 +- drivers/scsi/mvme147.c | 2 +- drivers/scsi/mvme16x.h | 2 +- drivers/scsi/ncr53c8xx.c | 2 +- drivers/scsi/ncr53c8xx.h | 2 +- drivers/scsi/nsp32.c | 4 +- drivers/scsi/pcmcia/nsp_cs.c | 2 +- drivers/scsi/pcmcia/nsp_cs.h | 2 +- drivers/scsi/pcmcia/sym53c500_cs.c | 2 +- drivers/scsi/psi240i.c | 7 +- drivers/scsi/qla1280.c | 2 +- drivers/scsi/qla2xxx/qla_def.h | 2 +- drivers/scsi/qla2xxx/qla_gbl.h | 6 +- drivers/scsi/qla2xxx/qla_inline.h | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 9 +- drivers/scsi/qla4xxx/ql4_glbl.h | 2 +- drivers/scsi/qla4xxx/ql4_isr.c | 3 +- drivers/scsi/qlogicfas408.c | 6 +- drivers/scsi/qlogicfas408.h | 2 +- drivers/scsi/qlogicpti.c | 4 +- drivers/scsi/seagate.c | 11 +- drivers/scsi/sgiwd93.c | 2 +- drivers/scsi/stex.c | 2 +- drivers/scsi/sun3_NCR5380.c | 2 +- drivers/scsi/sun3_scsi.c | 6 +- drivers/scsi/sun3_scsi_vme.c | 6 +- drivers/scsi/sym53c416.c | 3 +- drivers/scsi/sym53c8xx_2/sym_glue.c | 2 +- drivers/scsi/tmscsim.c | 6 +- drivers/scsi/u14-34f.c | 5 +- drivers/scsi/ultrastor.c | 13 +-- drivers/scsi/wd7000.c | 2 +- drivers/serial/21285.c | 4 +- drivers/serial/68328serial.c | 9 +- drivers/serial/68360serial.c | 2 +- drivers/serial/8250.c | 14 +-- drivers/serial/amba-pl010.c | 15 +-- drivers/serial/amba-pl011.c | 15 +-- drivers/serial/atmel_serial.c | 8 +- drivers/serial/clps711x.c | 6 +- drivers/serial/cpm_uart/cpm_uart_core.c | 16 +-- drivers/serial/crisv10.c | 6 +- drivers/serial/dz.c | 2 +- drivers/serial/icom.c | 3 +- drivers/serial/imx.c | 8 +- drivers/serial/ioc3_serial.c | 10 +- drivers/serial/ioc4_serial.c | 3 +- drivers/serial/ip22zilog.c | 18 ++- drivers/serial/jsm/jsm.h | 2 +- drivers/serial/jsm/jsm_neo.c | 2 +- drivers/serial/m32r_sio.c | 14 +-- drivers/serial/mcfserial.c | 2 +- drivers/serial/mpc52xx_uart.c | 10 +- drivers/serial/mpsc.c | 8 +- drivers/serial/netx-serial.c | 8 +- drivers/serial/pmac_zilog.c | 17 ++- drivers/serial/pxa.c | 10 +- drivers/serial/s3c2410.c | 6 +- drivers/serial/sa1100.c | 8 +- drivers/serial/serial_lh7a40x.c | 16 +-- drivers/serial/serial_txx9.c | 8 +- drivers/serial/sh-sci.c | 33 +++--- drivers/serial/sn_console.c | 11 +- drivers/serial/sunhv.c | 10 +- drivers/serial/sunsab.c | 13 +-- drivers/serial/sunsu.c | 19 ++- drivers/serial/sunzilog.c | 31 +++-- drivers/serial/v850e_uart.c | 4 +- drivers/serial/vr41xx_siu.c | 9 +- drivers/sn/ioc3.c | 12 +- drivers/spi/pxa2xx_spi.c | 4 +- drivers/spi/spi_mpc83xx.c | 3 +- drivers/spi/spi_s3c24xx.c | 2 +- drivers/tc/zs.c | 6 +- drivers/usb/atm/cxacru.c | 2 +- drivers/usb/atm/speedtch.c | 2 +- drivers/usb/atm/ueagle-atm.c | 2 +- drivers/usb/atm/usbatm.c | 2 +- drivers/usb/class/cdc-acm.c | 6 +- drivers/usb/class/usblp.c | 4 +- drivers/usb/core/devio.c | 2 +- drivers/usb/core/hcd.c | 15 ++- drivers/usb/core/hcd.h | 9 +- drivers/usb/core/hub.c | 2 +- drivers/usb/core/message.c | 4 +- drivers/usb/gadget/at91_udc.c | 4 +- drivers/usb/gadget/goku_udc.c | 2 +- drivers/usb/gadget/lh7a40x_udc.c | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 9 +- drivers/usb/gadget/pxa2xx_udc.c | 11 +- drivers/usb/host/ehci-hcd.c | 26 ++--- drivers/usb/host/ehci-hub.c | 4 +- drivers/usb/host/ehci-pci.c | 4 +- drivers/usb/host/ehci-q.c | 21 ++-- drivers/usb/host/ehci-sched.c | 21 ++-- drivers/usb/host/hc_crisv10.c | 12 +- drivers/usb/host/isp116x-hcd.c | 16 +-- drivers/usb/host/ohci-hcd.c | 14 +-- drivers/usb/host/ohci-hub.c | 8 +- drivers/usb/host/ohci-q.c | 16 +-- drivers/usb/host/sl811-hcd.c | 21 ++-- drivers/usb/host/u132-hcd.c | 8 +- drivers/usb/host/uhci-hcd.c | 8 +- drivers/usb/host/uhci-hub.c | 2 +- drivers/usb/host/uhci-q.c | 15 ++- drivers/usb/image/mdc800.c | 6 +- drivers/usb/image/microtek.c | 10 +- drivers/usb/input/acecad.c | 2 +- drivers/usb/input/aiptek.c | 13 +-- drivers/usb/input/appletouch.c | 2 +- drivers/usb/input/ati_remote.c | 17 ++- drivers/usb/input/ati_remote2.c | 14 +-- drivers/usb/input/hid-core.c | 28 ++--- drivers/usb/input/hid-input.c | 4 +- drivers/usb/input/hid.h | 4 +- drivers/usb/input/hiddev.c | 2 +- drivers/usb/input/itmtouch.c | 4 +- drivers/usb/input/kbtab.c | 2 +- drivers/usb/input/keyspan_remote.c | 7 +- drivers/usb/input/mtouchusb.c | 3 +- drivers/usb/input/powermate.c | 7 +- drivers/usb/input/touchkitusb.c | 15 +-- drivers/usb/input/usbkbd.c | 6 +- drivers/usb/input/usbmouse.c | 4 +- drivers/usb/input/usbtouchscreen.c | 15 +-- drivers/usb/input/wacom.h | 4 +- drivers/usb/input/wacom_sys.c | 9 +- drivers/usb/input/wacom_wac.c | 9 -- drivers/usb/input/xpad.c | 8 +- drivers/usb/input/yealink.c | 9 +- drivers/usb/misc/adutux.c | 4 +- drivers/usb/misc/appledisplay.c | 2 +- drivers/usb/misc/auerswald.c | 30 ++--- drivers/usb/misc/ftdi-elan.c | 2 +- drivers/usb/misc/ldusb.c | 4 +- drivers/usb/misc/legousbtower.c | 8 +- drivers/usb/misc/phidgetkit.c | 2 +- drivers/usb/misc/phidgetmotorcontrol.c | 2 +- drivers/usb/misc/sisusbvga/sisusb.c | 4 +- drivers/usb/misc/usblcd.c | 2 +- drivers/usb/misc/usbtest.c | 8 +- drivers/usb/misc/uss720.c | 4 +- drivers/usb/net/asix.c | 2 +- drivers/usb/net/catc.c | 8 +- drivers/usb/net/gl620a.c | 2 +- drivers/usb/net/kaweth.c | 10 +- drivers/usb/net/net1080.c | 2 +- drivers/usb/net/pegasus.c | 14 +-- drivers/usb/net/rtl8150.c | 12 +- drivers/usb/net/usbnet.c | 10 +- drivers/usb/serial/aircable.c | 4 +- drivers/usb/serial/airprime.c | 4 +- drivers/usb/serial/belkin_sa.c | 4 +- drivers/usb/serial/cyberjack.c | 12 +- drivers/usb/serial/cypress_m8.c | 8 +- drivers/usb/serial/digi_acceleport.c | 8 +- drivers/usb/serial/empeg.c | 8 +- drivers/usb/serial/ftdi_sio.c | 8 +- drivers/usb/serial/garmin_gps.c | 6 +- drivers/usb/serial/generic.c | 4 +- drivers/usb/serial/io_edgeport.c | 16 +-- drivers/usb/serial/io_ti.c | 6 +- drivers/usb/serial/ipaq.c | 8 +- drivers/usb/serial/ipw.c | 4 +- drivers/usb/serial/ir-usb.c | 8 +- drivers/usb/serial/keyspan.c | 52 ++++----- drivers/usb/serial/keyspan_pda.c | 4 +- drivers/usb/serial/kl5kusb105.c | 8 +- drivers/usb/serial/kobil_sct.c | 8 +- drivers/usb/serial/mct_u232.c | 4 +- drivers/usb/serial/mos7840.c | 9 +- drivers/usb/serial/navman.c | 2 +- drivers/usb/serial/omninet.c | 8 +- drivers/usb/serial/option.c | 10 +- drivers/usb/serial/pl2303.c | 6 +- drivers/usb/serial/safe_serial.c | 2 +- drivers/usb/serial/ti_usb_3410_5052.c | 12 +- drivers/usb/serial/visor.c | 12 +- drivers/usb/serial/whiteheat.c | 16 +-- drivers/usb/storage/onetouch.c | 3 +- drivers/usb/storage/transport.c | 2 +- drivers/usb/usb-skeleton.c | 2 +- drivers/video/amifb.c | 4 +- drivers/video/arcfb.c | 3 +- drivers/video/atafb.c | 2 +- drivers/video/aty/atyfb_base.c | 2 +- drivers/video/au1200fb.c | 2 +- drivers/video/console/fbcon.c | 4 +- drivers/video/intelfb/intelfbhw.c | 2 +- drivers/video/matrox/matroxfb_base.c | 2 +- drivers/video/pvr2fb.c | 4 +- drivers/video/pxafb.c | 2 +- drivers/video/s3c2410fb.c | 2 +- drivers/video/sa1100fb.c | 2 +- fs/proc/proc_misc.c | 2 +- include/asm-frv/dma.h | 5 +- include/asm-frv/irq_regs.h | 27 +++++ include/asm-frv/ptrace.h | 1 + include/asm-generic/irq_regs.h | 37 ++++++ include/asm-i386/apic.h | 4 +- include/asm-i386/arch_hooks.h | 2 +- include/asm-i386/floppy.h | 6 +- include/asm-i386/hpet.h | 2 +- include/asm-i386/hw_irq.h | 2 +- include/asm-i386/irq_regs.h | 1 + include/asm-i386/mach-default/do_timer.h | 8 +- include/asm-i386/mach-visws/do_timer.h | 8 +- include/asm-i386/mach-voyager/do_timer.h | 6 +- include/asm-i386/voyager.h | 4 +- include/asm-ia64/irq_regs.h | 1 + include/asm-ia64/machvec.h | 4 +- include/asm-mips/irq_regs.h | 1 + include/asm-mips/time.h | 4 +- include/asm-powerpc/irq.h | 2 +- include/asm-powerpc/irq_regs.h | 2 + include/asm-powerpc/smp.h | 3 +- include/asm-x86_64/apic.h | 2 +- include/asm-x86_64/floppy.h | 6 +- include/asm-x86_64/irq_regs.h | 1 + include/asm-x86_64/proto.h | 4 +- include/linux/adb.h | 4 +- include/linux/arcdevice.h | 2 +- include/linux/hiddev.h | 4 +- include/linux/ide.h | 2 +- include/linux/input.h | 7 -- include/linux/interrupt.h | 4 +- include/linux/ioc3.h | 2 +- include/linux/irq.h | 40 +++---- include/linux/libata.h | 4 +- include/linux/parport.h | 16 ++- include/linux/profile.h | 2 +- include/linux/rtc.h | 2 +- include/linux/serial_core.h | 7 +- include/linux/serio.h | 5 +- include/linux/sysrq.h | 6 +- include/linux/usb.h | 3 +- include/linux/usb/serial.h | 12 +- include/sound/cs4231.h | 2 +- include/sound/emu10k1.h | 2 +- include/sound/gus.h | 2 +- include/sound/initval.h | 2 +- include/sound/mpu401.h | 6 +- include/sound/sb.h | 6 +- include/sound/vx_core.h | 2 +- kernel/irq/chip.c | 36 +++--- kernel/irq/handle.c | 19 ++- kernel/irq/spurious.c | 10 +- kernel/power/poweroff.c | 3 +- kernel/profile.c | 5 +- lib/Makefile | 2 +- lib/irq_regs.c | 15 +++ sound/aoa/core/snd-aoa-gpio-feature.c | 4 +- sound/aoa/soundbus/i2sbus/i2sbus-core.c | 5 +- sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | 4 +- sound/aoa/soundbus/i2sbus/i2sbus.h | 4 +- sound/arm/aaci.c | 2 +- sound/arm/pxa2xx-ac97.c | 2 +- sound/arm/pxa2xx-pcm.c | 2 +- sound/drivers/mpu401/mpu401_uart.c | 8 +- sound/drivers/mtpav.c | 2 +- sound/drivers/mts64.c | 2 +- sound/drivers/serial-u16550.c | 2 +- sound/drivers/vx/vx_core.c | 2 +- sound/isa/ad1816a/ad1816a_lib.c | 2 +- sound/isa/ad1848/ad1848_lib.c | 2 +- sound/isa/cs423x/cs4231_lib.c | 2 +- sound/isa/es1688/es1688_lib.c | 2 +- sound/isa/es18xx.c | 4 +- sound/isa/gus/gus_irq.c | 2 +- sound/isa/gus/gusmax.c | 6 +- sound/isa/gus/interwave.c | 6 +- sound/isa/opl3sa2.c | 6 +- sound/isa/opti9xx/opti92x-ad1848.c | 2 +- sound/isa/sb/es968.c | 3 +- sound/isa/sb/sb16_main.c | 4 +- sound/isa/sb/sb8.c | 2 +- sound/isa/sb/sb_common.c | 2 +- sound/isa/sgalaxy.c | 2 +- sound/isa/wavefront/wavefront.c | 4 +- sound/mips/au1x00.c | 2 +- sound/oss/ad1816.c | 2 +- sound/oss/ad1848.c | 4 +- sound/oss/ad1889.c | 2 +- sound/oss/btaudio.c | 2 +- sound/oss/cs46xx.c | 2 +- sound/oss/dmasound/dmasound_atari.c | 4 +- sound/oss/dmasound/dmasound_awacs.c | 14 +-- sound/oss/dmasound/dmasound_paula.c | 4 +- sound/oss/dmasound/dmasound_q40.c | 8 +- sound/oss/emu10k1/irqmgr.c | 2 +- sound/oss/emu10k1/main.c | 2 +- sound/oss/es1371.c | 2 +- sound/oss/hal2.c | 2 +- sound/oss/i810_audio.c | 2 +- sound/oss/mpu401.c | 2 +- sound/oss/mpu401.h | 3 +- sound/oss/msnd_pinnacle.c | 2 +- sound/oss/nec_vrc5477.c | 2 +- sound/oss/nm256.h | 2 +- sound/oss/nm256_audio.c | 8 +- sound/oss/pas2_card.c | 2 +- sound/oss/sb_common.c | 4 +- sound/oss/sh_dac_audio.c | 2 +- sound/oss/swarm_cs4297a.c | 2 +- sound/oss/trident.c | 2 +- sound/oss/uart401.c | 2 +- sound/oss/uart6850.c | 2 +- sound/oss/via82cxxx_audio.c | 6 +- sound/oss/vidc.h | 2 +- sound/oss/vwsnd.c | 4 +- sound/oss/waveartist.c | 2 +- sound/parisc/harmony.c | 2 +- sound/pci/ad1889.c | 4 +- sound/pci/ali5451/ali5451.c | 4 +- sound/pci/als300.c | 6 +- sound/pci/als4000.c | 4 +- sound/pci/atiixp.c | 2 +- sound/pci/atiixp_modem.c | 2 +- sound/pci/au88x0/au88x0.h | 3 +- sound/pci/au88x0/au88x0_core.c | 4 +- sound/pci/azt3328.c | 4 +- sound/pci/bt87x.c | 2 +- sound/pci/ca0106/ca0106_main.c | 3 +- sound/pci/cmipci.c | 4 +- sound/pci/cs4281.c | 4 +- sound/pci/cs46xx/cs46xx_lib.c | 2 +- sound/pci/cs5535audio/cs5535audio.c | 3 +- sound/pci/echoaudio/echoaudio.c | 3 +- sound/pci/emu10k1/emu10k1x.c | 3 +- sound/pci/emu10k1/irq.c | 2 +- sound/pci/ens1370.c | 4 +- sound/pci/es1938.c | 6 +- sound/pci/es1968.c | 6 +- sound/pci/fm801.c | 4 +- sound/pci/hda/hda_intel.c | 2 +- sound/pci/ice1712/ice1712.c | 6 +- sound/pci/ice1712/ice1724.c | 4 +- sound/pci/intel8x0.c | 2 +- sound/pci/intel8x0m.c | 2 +- sound/pci/korg1212/korg1212.c | 2 +- sound/pci/maestro3.c | 3 +- sound/pci/mixart/mixart_core.c | 2 +- sound/pci/mixart/mixart_core.h | 2 +- sound/pci/nm256/nm256.c | 6 +- sound/pci/pcxhr/pcxhr_core.c | 2 +- sound/pci/pcxhr/pcxhr_core.h | 2 +- sound/pci/riptide/riptide.c | 5 +- sound/pci/rme32.c | 3 +- sound/pci/rme96.c | 3 +- sound/pci/rme9652/hdsp.c | 2 +- sound/pci/rme9652/hdspm.c | 3 +- sound/pci/rme9652/rme9652.c | 2 +- sound/pci/sonicvibes.c | 4 +- sound/pci/trident/trident_main.c | 7 +- sound/pci/via82xx.c | 6 +- sound/pci/via82xx_modem.c | 2 +- sound/pci/ymfpci/ymfpci_main.c | 4 +- sound/pcmcia/pdaudiocf/pdaudiocf.h | 2 +- sound/pcmcia/pdaudiocf/pdaudiocf_irq.c | 4 +- sound/ppc/pmac.c | 6 +- sound/ppc/tumbler.c | 2 +- sound/sparc/amd7930.c | 2 +- sound/sparc/cs4231.c | 2 +- sound/sparc/dbri.c | 3 +- sound/usb/usbaudio.c | 4 +- sound/usb/usbmidi.c | 4 +- sound/usb/usbmixer.c | 5 +- sound/usb/usx2y/usbusx2y.c | 4 +- sound/usb/usx2y/usbusx2yaudio.c | 10 +- sound/usb/usx2y/usx2yhwdeppcm.c | 6 +- 1079 files changed, 2621 insertions(+), 2976 deletions(-) create mode 100644 include/asm-frv/irq_regs.h create mode 100644 include/asm-generic/irq_regs.h create mode 100644 include/asm-i386/irq_regs.h create mode 100644 include/asm-ia64/irq_regs.h create mode 100644 include/asm-mips/irq_regs.h create mode 100644 include/asm-powerpc/irq_regs.h create mode 100644 include/asm-x86_64/irq_regs.h create mode 100644 lib/irq_regs.c (limited to 'include/linux') diff --git a/arch/frv/kernel/dma.c b/arch/frv/kernel/dma.c index f5de6cf7df4e..156184e17e57 100644 --- a/arch/frv/kernel/dma.c +++ b/arch/frv/kernel/dma.c @@ -121,15 +121,14 @@ unsigned long frv_dma_inprogress; /* * DMA irq handler - determine channel involved, grab status and call real handler */ -static irqreturn_t dma_irq_handler(int irq, void *_channel, struct pt_regs *regs) +static irqreturn_t dma_irq_handler(int irq, void *_channel) { struct frv_dma_channel *channel = _channel; frv_clear_dma_inprogress(channel - frv_dma_channels); return channel->handler(channel - frv_dma_channels, __get_DMAC(channel->ioaddr, CSTR), - channel->data, - regs); + channel->data); } /* end dma_irq_handler() */ diff --git a/arch/frv/kernel/irq-mb93091.c b/arch/frv/kernel/irq-mb93091.c index 369bc0a7443d..ad753c1e9b8f 100644 --- a/arch/frv/kernel/irq-mb93091.c +++ b/arch/frv/kernel/irq-mb93091.c @@ -80,7 +80,7 @@ static struct irq_chip frv_fpga_pic = { /* * FPGA PIC interrupt handler */ -static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs) +static irqreturn_t fpga_interrupt(int irq, void *_mask) { uint16_t imr, mask = (unsigned long) _mask; @@ -95,7 +95,7 @@ static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs) irq = 31 - irq; mask &= ~(1 << irq); - generic_handle_irq(IRQ_BASE_FPGA + irq, regs); + generic_handle_irq(IRQ_BASE_FPGA + irq); } return IRQ_HANDLED; diff --git a/arch/frv/kernel/irq-mb93093.c b/arch/frv/kernel/irq-mb93093.c index a43a22158956..e0983f6926ed 100644 --- a/arch/frv/kernel/irq-mb93093.c +++ b/arch/frv/kernel/irq-mb93093.c @@ -79,7 +79,7 @@ static struct irq_chip frv_fpga_pic = { /* * FPGA PIC interrupt handler */ -static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs) +static irqreturn_t fpga_interrupt(int irq, void *_mask) { uint16_t imr, mask = (unsigned long) _mask; @@ -94,7 +94,7 @@ static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs) irq = 31 - irq; mask &= ~(1 << irq); - generic_irq_handle(IRQ_BASE_FPGA + irq, regs); + generic_irq_handle(IRQ_BASE_FPGA + irq); } return IRQ_HANDLED; diff --git a/arch/frv/kernel/irq-mb93493.c b/arch/frv/kernel/irq-mb93493.c index 39c0188a3498..c157eeff871d 100644 --- a/arch/frv/kernel/irq-mb93493.c +++ b/arch/frv/kernel/irq-mb93493.c @@ -90,7 +90,7 @@ static struct irq_chip frv_mb93493_pic = { /* * MB93493 PIC interrupt handler */ -static irqreturn_t mb93493_interrupt(int irq, void *_piqsr, struct pt_regs *regs) +static irqreturn_t mb93493_interrupt(int irq, void *_piqsr) { volatile void *piqsr = _piqsr; uint32_t iqsr; @@ -106,7 +106,7 @@ static irqreturn_t mb93493_interrupt(int irq, void *_piqsr, struct pt_regs *regs irq = 31 - irq; iqsr &= ~(1 << irq); - generic_handle_irq(IRQ_BASE_MB93493 + irq, regs); + generic_handle_irq(IRQ_BASE_MB93493 + irq); } return IRQ_HANDLED; diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c index 5ac041c7c0a4..87f360a4ea27 100644 --- a/arch/frv/kernel/irq.c +++ b/arch/frv/kernel/irq.c @@ -143,7 +143,7 @@ static struct irq_chip frv_cpu_pic = { asmlinkage void do_IRQ(void) { irq_enter(); - generic_handle_irq(__get_IRL(), __frame); + generic_handle_irq(__get_IRL()); irq_exit(); } diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c index 44a9aebc4f5a..ed588d73d7d8 100644 --- a/arch/frv/kernel/time.c +++ b/arch/frv/kernel/time.c @@ -40,7 +40,7 @@ unsigned long __nongprelbss __dsu_clock_speed_HZ; unsigned long __nongprelbss __serial_clock_speed_HZ; unsigned long __delay_loops_MHz; -static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs *regs); +static irqreturn_t timer_interrupt(int irq, void *dummy); static struct irqaction timer_irq = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL @@ -55,7 +55,7 @@ static inline int set_rtc_mmss(unsigned long nowtime) * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ -static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) +static irqreturn_t timer_interrupt(int irq, void *dummy) { /* last time the cmos clock got updated */ static long last_rtc_update = 0; @@ -70,8 +70,8 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) write_seqlock(&xtime_lock); do_timer(1); - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); /* * If we have an externally synchronized Linux clock, then update diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 90faae5c5d30..7d500da0e63b 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -1193,11 +1193,11 @@ EXPORT_SYMBOL(switch_ipi_to_APIC_timer); * value into /proc/profile. */ -inline void smp_local_timer_interrupt(struct pt_regs * regs) +inline void smp_local_timer_interrupt(void) { - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); #ifdef CONFIG_SMP - update_process_times(user_mode_vm(regs)); + update_process_times(user_mode_vm(irq_regs)); #endif /* @@ -1223,6 +1223,7 @@ inline void smp_local_timer_interrupt(struct pt_regs * regs) fastcall void smp_apic_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); int cpu = smp_processor_id(); /* @@ -1241,12 +1242,13 @@ fastcall void smp_apic_timer_interrupt(struct pt_regs *regs) * interrupt lock, which is the WrongThing (tm) to do. */ irq_enter(); - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); irq_exit(); + set_irq_regs(old_regs); } #ifndef CONFIG_SMP -static void up_apic_timer_interrupt_call(struct pt_regs *regs) +static void up_apic_timer_interrupt_call(void) { int cpu = smp_processor_id(); @@ -1255,11 +1257,11 @@ static void up_apic_timer_interrupt_call(struct pt_regs *regs) */ per_cpu(irq_stat, cpu).apic_timer_irqs++; - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); } #endif -void smp_send_timer_broadcast_ipi(struct pt_regs *regs) +void smp_send_timer_broadcast_ipi(void) { cpumask_t mask; @@ -1272,7 +1274,7 @@ void smp_send_timer_broadcast_ipi(struct pt_regs *regs) * We can directly call the apic timer interrupt handler * in UP case. Minus all irq related functions */ - up_apic_timer_interrupt_call(regs); + up_apic_timer_interrupt_call(); #endif } } diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index d07ed31f11e3..d53eafb6daa7 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -335,13 +335,13 @@ void init_8259A(int auto_eoi) */ -static irqreturn_t math_error_irq(int cpl, void *dev_id, struct pt_regs *regs) +static irqreturn_t math_error_irq(int cpl, void *dev_id) { extern void math_error(void __user *); outb(0,0xF0); if (ignore_fpu_irq || !boot_cpu_data.hard_math) return IRQ_NONE; - math_error((void __user *)regs->eip); + math_error((void __user *)get_irq_regs()->eip); return IRQ_HANDLED; } diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 3dd2e180151b..8cfc7dbec7b9 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -53,6 +53,7 @@ static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; */ fastcall unsigned int do_IRQ(struct pt_regs *regs) { + struct pt_regs *old_regs; /* high bit used in ret_from_ code */ int irq = ~regs->orig_eax; struct irq_desc *desc = irq_desc + irq; @@ -67,6 +68,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) BUG(); } + old_regs = set_irq_regs(regs); irq_enter(); #ifdef CONFIG_DEBUG_STACKOVERFLOW /* Debugging check for stack overflow: is there less than 1KB free? */ @@ -95,7 +97,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) * current stack (which is the irq stack already after all) */ if (curctx != irqctx) { - int arg1, arg2, arg3, ebx; + int arg1, arg2, ebx; /* build the stack frame on the IRQ stack */ isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); @@ -114,17 +116,17 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) " xchgl %%ebx,%%esp \n" " call *%%edi \n" " movl %%ebx,%%esp \n" - : "=a" (arg1), "=d" (arg2), "=c" (arg3), "=b" (ebx) - : "0" (irq), "1" (desc), "2" (regs), "3" (isp), + : "=a" (arg1), "=d" (arg2), "=b" (ebx) + : "0" (irq), "1" (desc), "2" (isp), "D" (desc->handle_irq) : "memory", "cc" ); } else #endif - desc->handle_irq(irq, desc, regs); + desc->handle_irq(irq, desc); irq_exit(); - + set_irq_regs(old_regs); return 1; } diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 1b080ab8a49f..31e5c6573aae 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -321,6 +321,7 @@ static inline void leave_mm (unsigned long cpu) fastcall void smp_invalidate_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); unsigned long cpu; cpu = get_cpu(); @@ -351,6 +352,7 @@ fastcall void smp_invalidate_interrupt(struct pt_regs *regs) smp_mb__after_clear_bit(); out: put_cpu_no_resched(); + set_irq_regs(old_regs); } static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, @@ -605,11 +607,14 @@ void smp_send_stop(void) */ fastcall void smp_reschedule_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); ack_APIC_irq(); + set_irq_regs(old_regs); } fastcall void smp_call_function_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); void (*func) (void *info) = call_data->func; void *info = call_data->info; int wait = call_data->wait; @@ -632,6 +637,7 @@ fastcall void smp_call_function_interrupt(struct pt_regs *regs) mb(); atomic_inc(&call_data->finished); } + set_irq_regs(old_regs); } /* diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 58a2d5582419..3f221f5eb47e 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -161,7 +161,7 @@ EXPORT_SYMBOL(profile_pc); * Time Stamp Counter value at the time of the timer interrupt, so that * we later on can estimate the time of day more exactly. */ -irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t timer_interrupt(int irq, void *dev_id) { /* * Here we are in the timer irq handler. We just have irqs locally @@ -188,7 +188,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) } #endif - do_timer_interrupt_hook(regs); + do_timer_interrupt_hook(); if (MCA_bus) { @@ -209,7 +209,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) #ifdef CONFIG_X86_LOCAL_APIC if (using_apic_timer) - smp_send_timer_broadcast_ipi(regs); + smp_send_timer_broadcast_ipi(); #endif return IRQ_HANDLED; diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c index 6bf14a4e995e..1a2a979cf6a3 100644 --- a/arch/i386/kernel/time_hpet.c +++ b/arch/i386/kernel/time_hpet.c @@ -441,7 +441,7 @@ int hpet_rtc_dropped_irq(void) return 1; } -irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) { struct rtc_time curr_time; unsigned long rtc_int_flag = 0; @@ -480,7 +480,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) } if (call_rtc_interrupt) { rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); - rtc_interrupt(rtc_int_flag, dev_id, regs); + rtc_interrupt(rtc_int_flag, dev_id); } return IRQ_HANDLED; } diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index 8355d8d87d18..cbcd61d6120b 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -714,7 +714,7 @@ static int irqbits; | (1 << SIGUSR1) | (1 << SIGUSR2) | (1 << SIGIO) | (1 << SIGURG) \ | (1 << SIGUNUSED) ) -static irqreturn_t irq_handler(int intno, void *dev_id, struct pt_regs * regs) +static irqreturn_t irq_handler(int intno, void *dev_id) { int irq_bit; unsigned long flags; diff --git a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c index 5929f884d79b..07097ed48890 100644 --- a/arch/i386/mach-visws/visws_apic.c +++ b/arch/i386/mach-visws/visws_apic.c @@ -191,7 +191,7 @@ static struct hw_interrupt_type piix4_virtual_irq_type = { * enable_irq gets the right irq. This 'master' irq is never directly * manipulated by any driver. */ -static irqreturn_t piix4_master_intr(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t piix4_master_intr(int irq, void *dev_id) { int realirq; irq_desc_t *desc; @@ -244,7 +244,7 @@ static irqreturn_t piix4_master_intr(int irq, void *dev_id, struct pt_regs * reg kstat_cpu(smp_processor_id()).irqs[realirq]++; if (likely(desc->action != NULL)) - handle_IRQ_event(realirq, regs, desc->action); + handle_IRQ_event(realirq, desc->action); if (!(desc->status & IRQ_DISABLED)) enable_8259A_irq(realirq); diff --git a/arch/i386/mach-voyager/voyager_basic.c b/arch/i386/mach-voyager/voyager_basic.c index 80b7f2fc4f46..c639d30d8bdc 100644 --- a/arch/i386/mach-voyager/voyager_basic.c +++ b/arch/i386/mach-voyager/voyager_basic.c @@ -87,7 +87,7 @@ voyager_detect(struct voyager_bios_info *bios) } void -voyager_system_interrupt(int cpl, void *dev_id, struct pt_regs *regs) +voyager_system_interrupt(int cpl, void *dev_id) { printk("Voyager: detected system interrupt\n"); } diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c index 856c73fcb7e7..d42422fc4af3 100644 --- a/arch/i386/mach-voyager/voyager_smp.c +++ b/arch/i386/mach-voyager/voyager_smp.c @@ -126,10 +126,10 @@ send_QIC_CPI(__u32 cpuset, __u8 cpi) } static inline void -wrapper_smp_local_timer_interrupt(struct pt_regs *regs) +wrapper_smp_local_timer_interrupt(void) { irq_enter(); - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); irq_exit(); } @@ -786,7 +786,7 @@ fastcall void smp_vic_sys_interrupt(struct pt_regs *regs) { ack_CPI(VIC_SYS_INT); - printk("Voyager SYSTEM INTERRUPT\n"); + printk("Voyager SYSTEM INTERRUPT\n"); } /* Handle a voyager CMN_INT; These interrupts occur either because of @@ -1135,7 +1135,9 @@ EXPORT_SYMBOL(smp_call_function); fastcall void smp_apic_timer_interrupt(struct pt_regs *regs) { - wrapper_smp_local_timer_interrupt(regs); + struct pt_regs *old_regs = set_irq_regs(regs); + wrapper_smp_local_timer_interrupt(); + set_irq_regs(old_regs); } /* All of the QUAD interrupt GATES */ @@ -1143,7 +1145,9 @@ fastcall void smp_qic_timer_interrupt(struct pt_regs *regs) { ack_QIC_CPI(QIC_TIMER_CPI); - wrapper_smp_local_timer_interrupt(regs); + struct pt_regs *old_regs = set_irq_regs(regs); + wrapper_smp_local_timer_interrupt(void); + set_irq_regs(old_regs); } fastcall void @@ -1177,6 +1181,7 @@ smp_qic_call_function_interrupt(struct pt_regs *regs) fastcall void smp_vic_cpi_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); __u8 cpu = smp_processor_id(); if(is_cpu_quad()) @@ -1185,7 +1190,7 @@ smp_vic_cpi_interrupt(struct pt_regs *regs) ack_VIC_CPI(VIC_CPI_LEVEL0); if(test_and_clear_bit(VIC_TIMER_CPI, &vic_cpi_mailbox[cpu])) - wrapper_smp_local_timer_interrupt(regs); + wrapper_smp_local_timer_interrupt(); if(test_and_clear_bit(VIC_INVALIDATE_CPI, &vic_cpi_mailbox[cpu])) smp_invalidate_interrupt(); if(test_and_clear_bit(VIC_RESCHEDULE_CPI, &vic_cpi_mailbox[cpu])) @@ -1194,6 +1199,7 @@ smp_vic_cpi_interrupt(struct pt_regs *regs) smp_enable_irq_interrupt(); if(test_and_clear_bit(VIC_CALL_FUNCTION_CPI, &vic_cpi_mailbox[cpu])) smp_call_function_interrupt(); + set_irq_regs(old_regs); } static void @@ -1266,8 +1272,10 @@ smp_send_stop(void) void smp_vic_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); send_CPI_allbutself(VIC_TIMER_CPI); - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); + set_irq_regs(old_regs); } /* local (per CPU) timer interrupt. It does both profiling and @@ -1279,12 +1287,12 @@ smp_vic_timer_interrupt(struct pt_regs *regs) * value into /proc/profile. */ void -smp_local_timer_interrupt(struct pt_regs * regs) +smp_local_timer_interrupt(void) { int cpu = smp_processor_id(); long weight; - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); if (--per_cpu(prof_counter, cpu) <= 0) { /* * The multiplier may have changed since the last time we got @@ -1302,7 +1310,7 @@ smp_local_timer_interrupt(struct pt_regs * regs) per_cpu(prof_counter, cpu); } - update_process_times(user_mode_vm(regs)); + update_process_times(user_mode_vm(irq_regs)); } if( ((1<itm_next; @@ -61,10 +61,10 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", ia64_get_itc(), new_itm); - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); while (1) { - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); new_itm += local_cpu_data->itm_delta; diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c index c36b0f5affb3..8a2cb4e691fd 100644 --- a/arch/ia64/sn/pci/tioca_provider.c +++ b/arch/ia64/sn/pci/tioca_provider.c @@ -550,13 +550,12 @@ tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags) * tioca_error_intr_handler - SGI TIO CA error interrupt handler * @irq: unused * @arg: pointer to tioca_common struct for the given CA - * @pt: unused * * Handle a CA error interrupt. Simply a wrapper around a SAL call which * defers processing to the SGI prom. */ static irqreturn_t -tioca_error_intr_handler(int irq, void *arg, struct pt_regs *pt) +tioca_error_intr_handler(int irq, void *arg) { struct tioca_common *soft = arg; struct ia64_sal_retval ret_stuff; diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c index af7171adcd2c..0e81f68aaf8e 100644 --- a/arch/ia64/sn/pci/tioce_provider.c +++ b/arch/ia64/sn/pci/tioce_provider.c @@ -666,12 +666,11 @@ tioce_dma_consistent(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma * tioce_error_intr_handler - SGI TIO CE error interrupt handler * @irq: unused * @arg: pointer to tioce_common struct for the given CE - * @pt: unused * * Handle a CE error interrupt. Simply a wrapper around a SAL call which * defers processing to the SGI prom. */ static irqreturn_t -tioce_error_intr_handler(int irq, void *arg, struct pt_regs *pt) +tioce_error_intr_handler(int irq, void *arg) { struct tioce_common *soft = arg; struct ia64_sal_retval ret_stuff; diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index d955aaefbb8e..a00b0e7ab9b1 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -55,13 +55,15 @@ unsigned long irq_hwmask[NR_IRQS]; */ asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); irq_enter(); __DO_IRQ_SMTC_HOOK(); - __do_IRQ(irq, regs); + __do_IRQ(irq); irq_exit(); + set_irq_regs(old_regs); return 1; } diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index a8340802f2d7..d349eb9e4ffb 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -322,18 +322,18 @@ static long last_rtc_update; * a broadcasted inter-processor interrupt which itself is triggered * by the global timer interrupt. */ -void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +void local_timer_interrupt(int irq, void *dev_id) { if (current->pid) - profile_tick(CPU_PROFILING, regs); - update_process_times(user_mode(regs)); + profile_tick(CPU_PROFILING); + update_process_times(user_mode(get_irq_regs())); } /* * High-level timer interrupt service routines. This function * is set as irqaction->handler and is invoked through do_IRQ. */ -irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t timer_interrupt(int irq, void *dev_id) { unsigned long j; unsigned int count; @@ -419,23 +419,24 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * In SMP mode, local_timer_interrupt() is invoked by appropriate * low-level local timer interrupt handler. */ - local_timer_interrupt(irq, dev_id, regs); + local_timer_interrupt(irq, dev_id); return IRQ_HANDLED; } -int null_perf_irq(struct pt_regs *regs) +int null_perf_irq(void) { return 0; } -int (*perf_irq)(struct pt_regs *regs) = null_perf_irq; +int (*perf_irq)(void) = null_perf_irq; EXPORT_SYMBOL(null_perf_irq); EXPORT_SYMBOL(perf_irq); asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); int r2 = cpu_has_mips_r2; irq_enter(); @@ -448,27 +449,30 @@ asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs) * performance counter interrupt handler anyway. */ if (!r2 || (read_c0_cause() & (1 << 26))) - if (perf_irq(regs)) + if (perf_irq()) goto out; /* we keep interrupt disabled all the time */ if (!r2 || (read_c0_cause() & (1 << 30))) - timer_interrupt(irq, NULL, regs); + timer_interrupt(irq, NULL); out: irq_exit(); + set_irq_regs(old_regs); } asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); irq_enter(); if (smp_processor_id() != 0) kstat_this_cpu.irqs[irq]++; /* we keep interrupt disabled all the time */ - local_timer_interrupt(irq, NULL, regs); + local_timer_interrupt(irq, NULL); irq_exit(); + set_irq_regs(old_regs); } /* diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c index 7a941ecff3bb..66df5ac8f089 100644 --- a/arch/mips/sgi-ip22/ip22-reset.c +++ b/arch/mips/sgi-ip22/ip22-reset.c @@ -169,7 +169,7 @@ static inline void volume_down_button(unsigned long data) } } -static irqreturn_t panel_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t panel_int(int irq, void *dev_id) { unsigned int buttons; diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index 0e061890f797..3462b0d98def 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -191,12 +191,14 @@ void indy_8254timer_irq(struct pt_regs *regs) void indy_r4k_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); int irq = SGI_TIMER_IRQ; irq_enter(); kstat_this_cpu.irqs[irq]++; - timer_interrupt(irq, NULL, regs); + timer_interrupt(irq, NULL); irq_exit(); + set_irq_regs(old_regs); } void __init plat_timer_setup(struct irqaction *irq) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index c3f58f2f9f52..5deaab3090b4 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -187,6 +187,7 @@ void fixup_irqs(cpumask_t map) void do_IRQ(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); unsigned int irq; #ifdef CONFIG_IRQSTACKS struct thread_info *curtp, *irqtp; @@ -230,18 +231,19 @@ void do_IRQ(struct pt_regs *regs) handler = &__do_IRQ; irqtp->task = curtp->task; irqtp->flags = 0; - call_handle_irq(irq, desc, regs, irqtp, handler); + call_handle_irq(irq, desc, irqtp, handler); irqtp->task = NULL; if (irqtp->flags) set_bits(irqtp->flags, &curtp->flags); } else #endif - generic_handle_irq(irq, regs); + generic_handle_irq(irq); } else if (irq != NO_IRQ_IGNORE) /* That's not SMP safe ... but who cares ? */ ppc_spurious_interrupts++; irq_exit(); + set_irq_regs(old_regs); #ifdef CONFIG_PPC_ISERIES if (get_lppaca()->int_dword.fields.decr_int) { diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 41521b30c3cd..c70e20708a1f 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -52,12 +52,12 @@ _GLOBAL(call_do_softirq) blr _GLOBAL(call_handle_irq) - ld r8,0(r7) + ld r8,0(r6) mflr r0 std r0,16(r1) mtctr r8 - stdu r1,THREAD_SIZE-112(r6) - mr r1,r6 + stdu r1,THREAD_SIZE-112(r5) + mr r1,r5 bctrl ld r1,0(r1) ld r0,16(r1) diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 6a9bc9ce54e0..35c6309bdb76 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -115,7 +115,7 @@ void __devinit smp_generic_kick_cpu(int nr) } #endif -void smp_message_recv(int msg, struct pt_regs *regs) +void smp_message_recv(int msg) { switch(msg) { case PPC_MSG_CALL_FUNCTION: @@ -127,11 +127,11 @@ void smp_message_recv(int msg, struct pt_regs *regs) break; case PPC_MSG_DEBUGGER_BREAK: if (crash_ipi_function_ptr) { - crash_ipi_function_ptr(regs); + crash_ipi_function_ptr(get_irq_regs()); break; } #ifdef CONFIG_DEBUGGER - debugger_ipi(regs); + debugger_ipi(get_irq_regs()); break; #endif /* CONFIG_DEBUGGER */ /* FALLTHROUGH */ diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 85b9244a098c..d210d0a5006b 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -643,6 +644,7 @@ static void iSeries_tb_recal(void) */ void timer_interrupt(struct pt_regs * regs) { + struct pt_regs *old_regs; int next_dec; int cpu = smp_processor_id(); unsigned long ticks; @@ -653,9 +655,10 @@ void timer_interrupt(struct pt_regs * regs) do_IRQ(regs); #endif + old_regs = set_irq_regs(regs); irq_enter(); - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); calculate_steal_time(); #ifdef CONFIG_PPC_ISERIES @@ -715,6 +718,7 @@ void timer_interrupt(struct pt_regs * regs) #endif irq_exit(); + set_irq_regs(old_regs); } void wakeup_decrementer(void) diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 8533f13a5ed1..434fb934dd20 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -190,11 +190,11 @@ struct irq_host *iic_get_irq_host(int node) EXPORT_SYMBOL_GPL(iic_get_irq_host); -static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t iic_ipi_action(int irq, void *dev_id) { int ipi = (int)(long)dev_id; - smp_message_recv(ipi, regs); + smp_message_recv(ipi); return IRQ_HANDLED; } diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index b0e95d594c51..21a9ebd4978e 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -213,8 +213,7 @@ static struct irq_host_ops spider_host_ops = { .xlate = spider_host_xlate, }; -static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc) { struct spider_pic *pic = desc->handler_data; unsigned int cs, virq; @@ -225,7 +224,7 @@ static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc, else virq = irq_linear_revmap(pic->host, cs); if (virq != NO_IRQ) - generic_handle_irq(virq, regs); + generic_handle_irq(virq); desc->chip->eoi(irq); } diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index c2c7cf75dd5f..bfc4829162f1 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -342,7 +342,7 @@ static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr) } /* Interrupt handler */ -static irqreturn_t kw_i2c_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t kw_i2c_irq(int irq, void *dev_id) { struct pmac_i2c_host_kw *host = dev_id; unsigned long flags; diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c index ee3b223ab17a..5c6c15c5f9a3 100644 --- a/arch/powerpc/platforms/powermac/pfunc_base.c +++ b/arch/powerpc/platforms/powermac/pfunc_base.c @@ -15,7 +15,7 @@ #define DBG(fmt...) #endif -static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs) +static irqreturn_t macio_gpio_irq(int irq, void *data) { pmf_do_irq(data); diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 39f7ddb554ea..e93a115961aa 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -440,14 +440,13 @@ static void __init pmac_pic_probe_oldstyle(void) } #endif /* CONFIG_PPC32 */ -static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc) { struct mpic *mpic = desc->handler_data; - unsigned int cascade_irq = mpic_get_one_irq(mpic, regs); + unsigned int cascade_irq = mpic_get_one_irq(mpic, get_irq_regs()); if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq, regs); + generic_handle_irq(cascade_irq); desc->chip->eoi(irq); } diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 311ed1993fc0..b1d3d161249e 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -65,16 +65,14 @@ static int ras_check_exception_token; #define EPOW_SENSOR_INDEX 0 #define RAS_VECTOR_OFFSET 0x500 -static irqreturn_t ras_epow_interrupt(int irq, void *dev_id, - struct pt_regs * regs); -static irqreturn_t ras_error_interrupt(int irq, void *dev_id, - struct pt_regs * regs); +static irqreturn_t ras_epow_interrupt(int irq, void *dev_id); +static irqreturn_t ras_error_interrupt(int irq, void *dev_id); /* #define DEBUG */ static void request_ras_irqs(struct device_node *np, - irqreturn_t (*handler)(int, void *, struct pt_regs *), + irq_handler_t handler, const char *name) { int i, index, count = 0; @@ -166,8 +164,7 @@ __initcall(init_ras_IRQ); * to examine the type of power failure and take appropriate action where * the time horizon permits something useful to be done. */ -static irqreturn_t -ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t ras_epow_interrupt(int irq, void *dev_id) { int status = 0xdeadbeef; int state = 0; @@ -210,8 +207,7 @@ ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) * For nonrecoverable errors, an error is logged and we stop all processing * as quickly as possible in order to prevent propagation of the failure. */ -static irqreturn_t -ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t ras_error_interrupt(int irq, void *dev_id) { struct rtas_error_log *rtas_elog; int status = 0xdeadbeef; diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index f82b13e531a3..ad9aec2c6fee 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -121,12 +121,11 @@ static void __init fwnmi_init(void) fwnmi_active = 1; } -void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc) { - unsigned int cascade_irq = i8259_irq(regs); + unsigned int cascade_irq = i8259_irq(get_irq_regs()); if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq, regs); + generic_handle_irq(cascade_irq); desc->chip->eoi(irq); } diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 253972e5479f..f6bd2f285153 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -324,7 +324,7 @@ static unsigned int xics_get_irq_lpar(struct pt_regs *regs) #ifdef CONFIG_SMP -static irqreturn_t xics_ipi_dispatch(int cpu, struct pt_regs *regs) +static irqreturn_t xics_ipi_dispatch(int cpu) { WARN_ON(cpu_is_offline(cpu)); @@ -332,47 +332,47 @@ static irqreturn_t xics_ipi_dispatch(int cpu, struct pt_regs *regs) if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, &xics_ipi_message[cpu].value)) { mb(); - smp_message_recv(PPC_MSG_CALL_FUNCTION, regs); + smp_message_recv(PPC_MSG_CALL_FUNCTION); } if (test_and_clear_bit(PPC_MSG_RESCHEDULE, &xics_ipi_message[cpu].value)) { mb(); - smp_message_recv(PPC_MSG_RESCHEDULE, regs); + smp_message_recv(PPC_MSG_RESCHEDULE); } #if 0 if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK, &xics_ipi_message[cpu].value)) { mb(); - smp_message_recv(PPC_MSG_MIGRATE_TASK, regs); + smp_message_recv(PPC_MSG_MIGRATE_TASK); } #endif #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, &xics_ipi_message[cpu].value)) { mb(); - smp_message_recv(PPC_MSG_DEBUGGER_BREAK, regs); + smp_message_recv(PPC_MSG_DEBUGGER_BREAK); } #endif } return IRQ_HANDLED; } -static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id) { int cpu = smp_processor_id(); direct_qirr_info(cpu, 0xff); - return xics_ipi_dispatch(cpu, regs); + return xics_ipi_dispatch(cpu); } -static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) { int cpu = smp_processor_id(); lpar_qirr_info(cpu, 0xff); - return xics_ipi_dispatch(cpu, regs); + return xics_ipi_dispatch(cpu); } void xics_cause_IPI(int cpu) diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h index 6ee1055b0ffb..db0ec3ba3ae2 100644 --- a/arch/powerpc/platforms/pseries/xics.h +++ b/arch/powerpc/platforms/pseries/xics.h @@ -31,7 +31,6 @@ struct xics_ipi_struct { extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; struct irq_desc; -extern void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs); +extern void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc); #endif /* _POWERPC_KERNEL_XICS_H */ diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 3ee03a9a98fa..195215560fd7 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -489,9 +489,9 @@ static inline void mpic_eoi(struct mpic *mpic) } #ifdef CONFIG_SMP -static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mpic_ipi_action(int irq, void *dev_id) { - smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0, regs); + smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0); return IRQ_HANDLED; } #endif /* CONFIG_SMP */ diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 708236f34746..5a854f36383c 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -2577,12 +2578,11 @@ void xmon_init(int enable) } #ifdef CONFIG_MAGIC_SYSRQ -static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_xmon(int key, struct tty_struct *tty) { /* ensure xmon is enabled */ xmon_init(1); - debugger(pt_regs); + debugger(get_irq_regs()); } static struct sysrq_key_op sysrq_xmon_op = diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 6472e321cad7..af4a1c71a80d 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -885,14 +885,14 @@ void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector, * value into /proc/profile. */ -void smp_local_timer_interrupt(struct pt_regs *regs) +void smp_local_timer_interrupt(void) { - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); #ifdef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id) - main_timer_handler(regs); + main_timer_handler(); /* * We take the 'long' return path, and there every subsystem * grabs the appropriate locks (kernel lock/ irq lock). @@ -913,7 +913,7 @@ void smp_local_timer_interrupt(struct pt_regs *regs) * [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ -void smp_apic_timer_interrupt(struct pt_regs *regs) +void smp_apic_timer_interrupt(void) { /* * the NMI deadlock-detector uses this. @@ -932,7 +932,7 @@ void smp_apic_timer_interrupt(struct pt_regs *regs) */ exit_idle(); irq_enter(); - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); irq_exit(); } diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index 506f27c85ca5..b8a407fcd5d5 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -103,7 +103,9 @@ skip: * handlers). */ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) -{ +{ + struct pt_regs *old_regs = set_irq_regs(regs); + /* high bit used in ret_from_ code */ unsigned vector = ~regs->orig_rax; unsigned irq; @@ -121,9 +123,10 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) #ifdef CONFIG_DEBUG_STACKOVERFLOW stack_overflow_check(regs); #endif - generic_handle_irq(irq, regs); + generic_handle_irq(irq); irq_exit(); + set_irq_regs(old_regs); return 1; } diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 557e92af7bea..1ba5a442ac32 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -302,20 +302,20 @@ unsigned long long monotonic_clock(void) } EXPORT_SYMBOL(monotonic_clock); -static noinline void handle_lost_ticks(int lost, struct pt_regs *regs) +static noinline void handle_lost_ticks(int lost) { static long lost_count; static int warned; if (report_lost_ticks) { printk(KERN_WARNING "time.c: Lost %d timer tick(s)! ", lost); - print_symbol("rip %s)\n", regs->rip); + print_symbol("rip %s)\n", get_irq_regs()->rip); } if (lost_count == 1000 && !warned) { printk(KERN_WARNING "warning: many lost ticks.\n" KERN_WARNING "Your time source seems to be instable or " "some driver is hogging interupts\n"); - print_symbol("rip %s\n", regs->rip); + print_symbol("rip %s\n", get_irq_regs()->rip); if (vxtime.mode == VXTIME_TSC && vxtime.hpet_address) { printk(KERN_WARNING "Falling back to HPET\n"); if (hpet_use_timer) @@ -339,7 +339,7 @@ static noinline void handle_lost_ticks(int lost, struct pt_regs *regs) #endif } -void main_timer_handler(struct pt_regs *regs) +void main_timer_handler(void) { static unsigned long rtc_update = 0; unsigned long tsc; @@ -411,7 +411,7 @@ void main_timer_handler(struct pt_regs *regs) } if (lost > 0) - handle_lost_ticks(lost, regs); + handle_lost_ticks(lost); else lost = 0; @@ -421,7 +421,7 @@ void main_timer_handler(struct pt_regs *regs) do_timer(lost + 1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif /* @@ -431,7 +431,7 @@ void main_timer_handler(struct pt_regs *regs) */ if (!using_apic_timer) - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); /* * If we have an externally synchronized Linux clock, then update CMOS clock @@ -450,11 +450,11 @@ void main_timer_handler(struct pt_regs *regs) write_sequnlock(&xtime_lock); } -static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t timer_interrupt(int irq, void *dev_id) { if (apic_runs_main_timer > 1) return IRQ_HANDLED; - main_timer_handler(regs); + main_timer_handler(); if (using_apic_timer) smp_send_timer_broadcast_ipi(); return IRQ_HANDLED; @@ -1337,7 +1337,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) } if (call_rtc_interrupt) { rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); - rtc_interrupt(rtc_int_flag, dev_id, regs); + rtc_interrupt(rtc_int_flag, dev_id); } return IRQ_HANDLED; } diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index 1bace29f4b6a..7fde8f4daebf 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -938,7 +938,7 @@ static void do_mfm_request(request_queue_t *q) mfm_request(); } -static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs) +static void mfm_interrupt_handler(int unused, void *dev_id) { void (*handler) (void) = do_mfm; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 20beea778ea2..068fe4f100b0 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -237,7 +237,7 @@ acpi_os_table_override(struct acpi_table_header * existing_table, return AE_OK; } -static irqreturn_t acpi_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t acpi_irq(int irq, void *dev_id) { return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE; } diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 54e1f38ce301..25929123ffff 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -204,7 +204,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); -static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t ahci_interrupt (int irq, void *dev_instance); static void ahci_irq_clear(struct ata_port *ap); static int ahci_port_start(struct ata_port *ap); static void ahci_port_stop(struct ata_port *ap); @@ -1059,7 +1059,7 @@ static void ahci_irq_clear(struct ata_port *ap) /* TODO */ } -static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t ahci_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; struct ahci_host_priv *hpriv; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index dce65651d858..77138a39eb04 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4857,7 +4857,6 @@ idle_irq: * ata_interrupt - Default ATA host interrupt handler * @irq: irq line (unused) * @dev_instance: pointer to our ata_host information structure - * @regs: unused * * Default interrupt handler for PCI IDE devices. Calls * ata_host_intr() for each port that is not disabled. @@ -4869,7 +4868,7 @@ idle_irq: * IRQ_NONE or IRQ_HANDLED. */ -irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +irqreturn_t ata_interrupt (int irq, void *dev_instance) { struct ata_host *host = dev_instance; unsigned int i; diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 81f3d219e70e..9021e34d2096 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -124,8 +124,7 @@ struct adma_port_priv { static int adma_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static irqreturn_t adma_intr (int irq, void *dev_instance, - struct pt_regs *regs); +static irqreturn_t adma_intr (int irq, void *dev_instance); static int adma_port_start(struct ata_port *ap); static void adma_host_stop(struct ata_host *host); static void adma_port_stop(struct ata_port *ap); @@ -508,7 +507,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) return handled; } -static irqreturn_t adma_intr(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t adma_intr(int irq, void *dev_instance) { struct ata_host *host = dev_instance; unsigned int handled = 0; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index e6aa1a86d5cf..1b8e0eb9e032 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -348,8 +348,7 @@ static void mv_port_stop(struct ata_port *ap); static void mv_qc_prep(struct ata_queued_cmd *qc); static void mv_qc_prep_iie(struct ata_queued_cmd *qc); static unsigned int mv_qc_issue(struct ata_queued_cmd *qc); -static irqreturn_t mv_interrupt(int irq, void *dev_instance, - struct pt_regs *regs); +static irqreturn_t mv_interrupt(int irq, void *dev_instance); static void mv_eng_timeout(struct ata_port *ap); static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); @@ -1448,8 +1447,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) * This routine holds the host lock while processing pending * interrupts. */ -static irqreturn_t mv_interrupt(int irq, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t mv_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; unsigned int hc, handled = 0, n_hcs; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index d09d20a17790..323b60710806 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -82,12 +82,9 @@ enum { static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void nv_ck804_host_stop(struct ata_host *host); -static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance, - struct pt_regs *regs); -static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance, - struct pt_regs *regs); -static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance, - struct pt_regs *regs); +static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance); +static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance); +static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance); static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); @@ -276,8 +273,7 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, nv_pci_tbl); MODULE_VERSION(DRV_VERSION); -static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; unsigned int i; @@ -357,8 +353,7 @@ static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat) return IRQ_RETVAL(handled); } -static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; u8 irq_stat; @@ -372,8 +367,7 @@ static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance, return ret; } -static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; u8 irq_stat; diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 15c9437710fc..d636ede064aa 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -93,7 +93,7 @@ struct pdc_host_priv { static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t pdc_interrupt (int irq, void *dev_instance); static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); @@ -498,7 +498,7 @@ static void pdc_irq_clear(struct ata_port *ap) readl(mmio + PDC_INT_SEQMASK); } -static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t pdc_interrupt (int irq, void *dev_instance) { struct ata_host *host = dev_instance; struct ata_port *ap; diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 7f6cc3c07de5..710909df4eaf 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -114,7 +114,7 @@ struct qs_port_priv { static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg); static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t qs_intr (int irq, void *dev_instance); static int qs_port_start(struct ata_port *ap); static void qs_host_stop(struct ata_host *host); static void qs_port_stop(struct ata_port *ap); @@ -454,7 +454,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host) return handled; } -static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t qs_intr(int irq, void *dev_instance) { struct ata_host *host = dev_instance; unsigned int handled = 0; diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 3d9fa1cc834d..ae5edb80ea9a 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -116,8 +116,7 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev); static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void sil_post_set_mode (struct ata_port *ap); -static irqreturn_t sil_interrupt(int irq, void *dev_instance, - struct pt_regs *regs); +static irqreturn_t sil_interrupt(int irq, void *dev_instance); static void sil_freeze(struct ata_port *ap); static void sil_thaw(struct ata_port *ap); @@ -437,8 +436,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) ata_port_freeze(ap); } -static irqreturn_t sil_interrupt(int irq, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t sil_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; void __iomem *mmio_base = host->mmio_base; diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index a951f40c2f21..169e200a6a71 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -330,7 +330,7 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static void sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); static void sil24_irq_clear(struct ata_port *ap); -static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t sil24_interrupt(int irq, void *dev_instance); static void sil24_freeze(struct ata_port *ap); static void sil24_thaw(struct ata_port *ap); static void sil24_error_handler(struct ata_port *ap); @@ -870,7 +870,7 @@ static inline void sil24_host_intr(struct ata_port *ap) slot_stat, ap->active_tag, ap->sactive); } -static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t sil24_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; struct sil24_host_priv *hpriv = host->private_data; diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 8c74f2ff4344..ae7992de4b08 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -152,7 +152,7 @@ struct pdc_host_priv { static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance); static void pdc_eng_timeout(struct ata_port *ap); static void pdc_20621_phy_reset (struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); @@ -788,7 +788,7 @@ static void pdc20621_irq_clear(struct ata_port *ap) readl(mmio + PDC_20621_SEQMASK); } -static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance) { struct ata_host *host = dev_instance; struct ata_port *ap; diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 273d88fcf980..e654b990b905 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -203,8 +203,7 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) * * Read the interrupt register and process for the devices that have them pending. */ -static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance) { struct ata_host *host = dev_instance; unsigned int i; diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index da599e6e9d34..8ff5c4e50823 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -861,10 +861,8 @@ static inline void interrupts_off (amb_dev * dev) { /********** interrupt handling **********/ -static irqreturn_t interrupt_handler(int irq, void *dev_id, - struct pt_regs *pt_regs) { +static irqreturn_t interrupt_handler(int irq, void *dev_id) { amb_dev * dev = (amb_dev *) dev_id; - (void) pt_regs; PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id); diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index df359a6c14f6..bc1b13c8f5d7 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1488,7 +1488,7 @@ static void bug_int(struct atm_dev *dev,unsigned long reason) } -static irqreturn_t eni_int(int irq,void *dev_id,struct pt_regs *regs) +static irqreturn_t eni_int(int irq,void *dev_id) { struct atm_dev *dev; struct eni_dev *eni_dev; diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 5f25e5efefcd..40ab9b65fae9 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -1546,7 +1546,7 @@ static void __devexit free_freepool (struct fs_dev *dev, struct freepool *fp) -static irqreturn_t fs_irq (int irq, void *dev_id, struct pt_regs * pt_regs) +static irqreturn_t fs_irq (int irq, void *dev_id) { int i; u32 status; diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 98622130de5b..3a7b21ff30a5 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -1328,7 +1328,7 @@ fore200e_irq(struct fore200e* fore200e) static irqreturn_t -fore200e_interrupt(int irq, void* dev, struct pt_regs* regs) +fore200e_interrupt(int irq, void* dev) { struct fore200e* fore200e = FORE200E_DEV((struct atm_dev*)dev); diff --git a/drivers/atm/he.c b/drivers/atm/he.c index b22a9142b240..c7314a79da0f 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -109,7 +109,7 @@ static int he_open(struct atm_vcc *vcc); static void he_close(struct atm_vcc *vcc); static int he_send(struct atm_vcc *vcc, struct sk_buff *skb); static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg); -static irqreturn_t he_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t he_irq_handler(int irq, void *dev_id); static void he_tasklet(unsigned long data); static int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page); static int he_start(struct atm_dev *dev); @@ -2216,7 +2216,7 @@ he_tasklet(unsigned long data) } static irqreturn_t -he_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +he_irq_handler(int irq, void *dev_id) { unsigned long flags; struct he_dev *he_dev = (struct he_dev * )dev_id; diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 209dba1c70da..33e9ee47392b 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -1382,12 +1382,10 @@ static inline void rx_data_av_handler (hrz_dev * dev) { /********** interrupt handler **********/ -static irqreturn_t interrupt_handler(int irq, void *dev_id, - struct pt_regs *pt_regs) { +static irqreturn_t interrupt_handler(int irq, void *dev_id) { hrz_dev * dev = (hrz_dev *) dev_id; u32 int_source; unsigned int irq_ok; - (void) pt_regs; PRINTD (DBG_FLOW, "interrupt_handler: %p", dev_id); diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 7487f0ad68e9..87b17c33b3f9 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -2774,7 +2774,7 @@ idt77252_collect_stat(struct idt77252_dev *card) } static irqreturn_t -idt77252_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) +idt77252_interrupt(int irq, void *dev_id) { struct idt77252_dev *card = dev_id; u32 stat; diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index f20b0b2c06c6..9ed1c60048f0 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -2195,7 +2195,7 @@ err_out: return -ENOMEM; } -static irqreturn_t ia_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ia_int(int irq, void *dev_id) { struct atm_dev *dev; IADEV *iadev; diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index b9568e10965a..8895f026bea7 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -1890,12 +1890,12 @@ static inline void lanai_int_1(struct lanai_dev *lanai, u32 reason) reg_write(lanai, ack, IntAck_Reg); } -static irqreturn_t lanai_int(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t lanai_int(int irq, void *devid) { struct lanai_dev *lanai = (struct lanai_dev *) devid; u32 reason; - (void) irq; (void) regs; /* unused variables */ + (void) irq; /* unused variables */ #ifdef USE_POWERDOWN /* diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index b8036899e56f..632ede552761 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -214,7 +214,7 @@ static void __devinit ns_init_card_error(ns_dev *card, int error); static scq_info *get_scq(int size, u32 scd); static void free_scq(scq_info *scq, struct atm_vcc *vcc); static void push_rxbufs(ns_dev *, struct sk_buff *); -static irqreturn_t ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t ns_irq_handler(int irq, void *dev_id); static int ns_open(struct atm_vcc *vcc); static void ns_close(struct atm_vcc *vcc); static void fill_tst(ns_dev *card, int n, vc_map *vc); @@ -1194,7 +1194,7 @@ static void push_rxbufs(ns_dev *card, struct sk_buff *skb) -static irqreturn_t ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ns_irq_handler(int irq, void *dev_id) { u32 stat_r; ns_dev *card; diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 083c5d3f2e18..7df0f373188e 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1012,7 +1012,7 @@ static int start_tx(struct atm_dev *dev) /*------------------------------- interrupts --------------------------------*/ -static irqreturn_t zatm_int(int irq,void *dev_id,struct pt_regs *regs) +static irqreturn_t zatm_int(int irq,void *dev_id) { struct atm_dev *dev; struct zatm_dev *zatm_dev; diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index b3f639fbf220..3e8ab84b9447 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -2698,8 +2698,7 @@ DAC960_DetectController(struct pci_dev *PCI_Device, { struct DAC960_privdata *privdata = (struct DAC960_privdata *)entry->driver_data; - irqreturn_t (*InterruptHandler)(int, void *, struct pt_regs *) = - privdata->InterruptHandler; + irq_handler_t InterruptHandler = privdata->InterruptHandler; unsigned int MemoryWindowSize = privdata->MemoryWindowSize; DAC960_Controller_T *Controller = NULL; unsigned char DeviceFunction = PCI_Device->devfn; @@ -5253,8 +5252,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) */ static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5295,8 +5293,7 @@ static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5338,8 +5335,7 @@ static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5381,8 +5377,7 @@ static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5420,8 +5415,7 @@ static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5459,8 +5453,7 @@ static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5498,8 +5491,7 @@ static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_P_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index f9217c34bc2b..cec539e601fe 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -2175,7 +2175,7 @@ static char struct DAC960_privdata { DAC960_HardwareType_T HardwareType; DAC960_FirmwareType_T FirmwareType; - irqreturn_t (*InterruptHandler)(int, void *, struct pt_regs *); + irq_handler_t InterruptHandler; unsigned int MemoryWindowSize; }; @@ -4412,12 +4412,12 @@ static void DAC960_FinalizeController(DAC960_Controller_T *); static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *); static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *); static void DAC960_RequestFunction(struct request_queue *); -static irqreturn_t DAC960_BA_InterruptHandler(int, void *, struct pt_regs *); -static irqreturn_t DAC960_LP_InterruptHandler(int, void *, struct pt_regs *); -static irqreturn_t DAC960_LA_InterruptHandler(int, void *, struct pt_regs *); -static irqreturn_t DAC960_PG_InterruptHandler(int, void *, struct pt_regs *); -static irqreturn_t DAC960_PD_InterruptHandler(int, void *, struct pt_regs *); -static irqreturn_t DAC960_P_InterruptHandler(int, void *, struct pt_regs *); +static irqreturn_t DAC960_BA_InterruptHandler(int, void *); +static irqreturn_t DAC960_LP_InterruptHandler(int, void *); +static irqreturn_t DAC960_LA_InterruptHandler(int, void *); +static irqreturn_t DAC960_PG_InterruptHandler(int, void *); +static irqreturn_t DAC960_PD_InterruptHandler(int, void *); +static irqreturn_t DAC960_P_InterruptHandler(int, void *); static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *); static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *); static void DAC960_MonitoringTimerFunction(unsigned long); diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index 0b80fbb8dbfd..706cdc6a69ec 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -346,7 +346,7 @@ static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, int enable); static int acsi_reqsense( char *buffer, int targ, int lun); static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip); -static irqreturn_t acsi_interrupt (int irq, void *data, struct pt_regs *fp); +static irqreturn_t acsi_interrupt (int irq, void *data); static void unexpected_acsi_interrupt( void ); static void bad_rw_intr( void ); static void read_intr( void ); @@ -726,7 +726,7 @@ static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struc * *******************************************************************/ -static irqreturn_t acsi_interrupt(int irq, void *data, struct pt_regs *fp ) +static irqreturn_t acsi_interrupt(int irq, void *data ) { void (*acsi_irq_handler)(void) = do_acsi; diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c index 4030a8fd1187..8e41c87b026e 100644 --- a/drivers/block/acsi_slm.c +++ b/drivers/block/acsi_slm.c @@ -246,7 +246,7 @@ static int slm_getstats( char *buffer, int device ); static ssize_t slm_read( struct file* file, char *buf, size_t count, loff_t *ppos ); static void start_print( int device ); -static irqreturn_t slm_interrupt(int irc, void *data, struct pt_regs *fp); +static irqreturn_t slm_interrupt(int irc, void *data); static void slm_test_ready( unsigned long dummy ); static void set_dma_addr( unsigned long paddr ); static unsigned long get_dma_addr( void ); @@ -452,7 +452,7 @@ static void start_print( int device ) /* Only called when an error happened or at the end of a page */ -static irqreturn_t slm_interrupt(int irc, void *data, struct pt_regs *fp) +static irqreturn_t slm_interrupt(int irc, void *data) { unsigned long addr; int stat; diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 2641597c6549..5d254b714509 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -209,7 +209,7 @@ static int fd_device[4] = { 0, 0, 0, 0 }; /* Milliseconds timer */ -static irqreturn_t ms_isr(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t ms_isr(int irq, void *dummy) { ms_busy = -1; wake_up(&ms_wait); @@ -560,7 +560,7 @@ static unsigned long fd_get_drive_id(int drive) return (id); } -static irqreturn_t fd_block_done(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t fd_block_done(int irq, void *dummy) { if (block_flag) custom.dsklen = 0x4000; diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index c39650920bdf..14d6b9492750 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -342,7 +342,7 @@ static void fd_select_drive( int drive ); static void fd_deselect( void ); static void fd_motor_off_timer( unsigned long dummy ); static void check_change( unsigned long dummy ); -static irqreturn_t floppy_irq (int irq, void *dummy, struct pt_regs *fp); +static irqreturn_t floppy_irq (int irq, void *dummy); static void fd_error( void ); static int do_format(int drive, int type, struct atari_format_descr *desc); static void do_fd_action( int drive ); @@ -573,7 +573,7 @@ static inline void copy_buffer(void *from, void *to) static void (*FloppyIRQHandler)( int status ) = NULL; -static irqreturn_t floppy_irq (int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t floppy_irq (int irq, void *dummy) { unsigned char status; void (*handler)( int ); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 36b88f6c5f82..dcccaf2782f3 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -130,7 +130,7 @@ static struct board_type products[] = { static ctlr_info_t *hba[MAX_CTLR]; static void do_cciss_request(request_queue_t *q); -static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t do_cciss_intr(int irq, void *dev_id); static int cciss_open(struct inode *inode, struct file *filep); static int cciss_release(struct inode *inode, struct file *filep); static int cciss_ioctl(struct inode *inode, struct file *filep, @@ -2300,7 +2300,7 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use #ifdef CONFIG_CISS_SCSI_TAPE /* if we saved some commands for later, process them now. */ if (info_p->scsi_rejects.ncompletions > 0) - do_cciss_intr(0, info_p, NULL); + do_cciss_intr(0, info_p); #endif cmd_free(info_p, c, 1); return status; @@ -2652,7 +2652,7 @@ static inline long interrupt_not_for_us(ctlr_info_t *h) #endif } -static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t do_cciss_intr(int irq, void *dev_id) { ctlr_info_t *h = dev_id; CommandList_struct *c; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index ada68e65b5ff..570d2f049323 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -169,7 +169,7 @@ static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c); static inline void complete_buffers(struct bio *bio, int ok); static inline void complete_command(cmdlist_t *cmd, int timeout); -static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t do_ida_intr(int irq, void *dev_id); static void ida_timer(unsigned long tdata); static int ida_revalidate(struct gendisk *disk); static int revalidate_allvol(ctlr_info_t *host); @@ -1042,7 +1042,7 @@ static inline void complete_command(cmdlist_t *cmd, int timeout) * Find the command on the completion queue, remove it, tell the OS and * try to queue up more IO */ -static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t do_ida_intr(int irq, void *dev_id) { ctlr_info_t *h = dev_id; cmdlist_t *c; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 629c5769d994..9e6d3a87cbe3 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -221,7 +221,7 @@ static DEFINE_SPINLOCK(floppy_lock); static struct completion device_release; static unsigned short virtual_dma_port = 0x3f0; -irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t floppy_interrupt(int irq, void *dev_id); static int set_dor(int fdc, char mask, char data); #define K_64 0x10000 /* 64KB */ @@ -1726,7 +1726,7 @@ static void print_result(char *message, int inr) } /* interrupt handler. Note that this can be called externally on the Sparc */ -irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t floppy_interrupt(int irq, void *dev_id) { void (*handler) (void) = do_floppy; int do_print; diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 5537974fb242..688a4fb0dc99 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -75,8 +75,7 @@ static int ps2esdi_out_cmd_blk(u_short * cmd_blk); static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode); -static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id); static void (*current_int_handler) (u_int) = NULL; static void ps2esdi_normal_interrupt_handler(u_int); static void ps2esdi_initial_reset_int_handler(u_int); @@ -687,8 +686,7 @@ static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode) -static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id) { u_int int_ret_code; diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index fdc8f892eb86..1a65979f1f0f 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -238,8 +238,8 @@ static void scan_timeout(unsigned long data); static void seek_timeout(unsigned long data); static void settle_timeout(unsigned long data); static void xfer_timeout(unsigned long data); -static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs); -/*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/ +static irqreturn_t swim3_interrupt(int irq, void *dev_id); +/*static void fd_dma_interrupt(int irq, void *dev_id);*/ static int grab_drive(struct floppy_state *fs, enum swim_state state, int interruptible); static void release_drive(struct floppy_state *fs); @@ -624,7 +624,7 @@ static void xfer_timeout(unsigned long data) start_request(fs); } -static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t swim3_interrupt(int irq, void *dev_id) { struct floppy_state *fs = (struct floppy_state *) dev_id; struct swim3 __iomem *sw = fs->swim3; @@ -777,7 +777,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs) } /* -static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void fd_dma_interrupt(int irq, void *dev_id) { } */ diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c index dfda796eba56..ed7b06cf3e68 100644 --- a/drivers/block/swim_iop.c +++ b/drivers/block/swim_iop.c @@ -94,7 +94,7 @@ static char *drive_names[7] = { int swimiop_init(void); static void swimiop_init_request(struct swim_iop_req *); static int swimiop_send_request(struct swim_iop_req *); -static void swimiop_receive(struct iop_msg *, struct pt_regs *); +static void swimiop_receive(struct iop_msg *); static void swimiop_status_update(int, struct swim_drvstatus *); static int swimiop_eject(struct floppy_state *fs); @@ -257,7 +257,7 @@ static int swimiop_send_request(struct swim_iop_req *req) * 2. An unsolicited message was received from the IOP. */ -void swimiop_receive(struct iop_msg *msg, struct pt_regs *regs) +void swimiop_receive(struct iop_msg *msg) { struct swim_iop_req *req; struct swimmsg_status *sm; diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index c6beee18a07c..47d6975268ff 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1200,7 +1200,7 @@ static inline void carm_handle_responses(struct carm_host *host) host->resp_idx += work; } -static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs) +static irqreturn_t carm_interrupt(int irq, void *__host) { struct carm_host *host = __host; void __iomem *mmio; diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 45a8f402b07b..0d5c73f07265 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -362,7 +362,7 @@ static void ub_end_rq(struct request *rq, unsigned int status); static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, struct ub_request *urq, struct ub_scsi_cmd *cmd); static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_urb_complete(struct urb *urb, struct pt_regs *pt); +static void ub_urb_complete(struct urb *urb); static void ub_scsi_action(unsigned long _dev); static void ub_scsi_dispatch(struct ub_dev *sc); static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd); @@ -959,7 +959,7 @@ static void ub_urb_timeout(unsigned long arg) * the sc->lock taken) and from an interrupt (while we do NOT have * the sc->lock taken). Therefore, bounce this off to a tasklet. */ -static void ub_urb_complete(struct urb *urb, struct pt_regs *pt) +static void ub_urb_complete(struct urb *urb) { struct ub_dev *sc = urb->context; @@ -1923,7 +1923,7 @@ err_alloc: /* */ -static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt) +static void ub_probe_urb_complete(struct urb *urb) { struct completion *cop = urb->context; complete(cop); diff --git a/drivers/block/umem.c b/drivers/block/umem.c index cbb9d0f21acc..30f16bd83650 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -571,7 +571,7 @@ static int mm_make_request(request_queue_t *q, struct bio *bio) -- mm_interrupt ----------------------------------------------------------------------------------- */ -static irqreturn_t mm_interrupt(int irq, void *__card, struct pt_regs *regs) +static irqreturn_t mm_interrupt(int irq, void *__card) { struct cardinfo *card = (struct cardinfo *) __card; unsigned int dma_status; diff --git a/drivers/block/xd.c b/drivers/block/xd.c index ebf3025721d1..10cc38783bdf 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -462,8 +462,7 @@ static void xd_recalibrate (u_char drive) } /* xd_interrupt_handler: interrupt service routine */ -static irqreturn_t xd_interrupt_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t xd_interrupt_handler(int irq, void *dev_id) { if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */ #ifdef DEBUG_OTHER diff --git a/drivers/block/xd.h b/drivers/block/xd.h index 71ac2e3dffc8..82e090fea957 100644 --- a/drivers/block/xd.h +++ b/drivers/block/xd.h @@ -109,8 +109,7 @@ static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsi static int xd_readwrite (u_char operation,XD_INFO *disk,char *buffer,u_int block,u_int count); static void xd_recalibrate (u_char drive); -static irqreturn_t xd_interrupt_handler(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t xd_interrupt_handler(int irq, void *dev_id); static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count); static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control); static void xd_watchdog (unsigned long unused); diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 13ba729cdd57..67cdda43f229 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -82,7 +82,7 @@ struct bcm203x_data { unsigned int fw_sent; }; -static void bcm203x_complete(struct urb *urb, struct pt_regs *regs) +static void bcm203x_complete(struct urb *urb) { struct bcm203x_data *data = urb->context; struct usb_device *udev = urb->dev; diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index efcc28ec9d9a..31ade991aa91 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -95,8 +95,8 @@ struct bfusb_data_scb { struct urb *urb; }; -static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs); -static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs); +static void bfusb_tx_complete(struct urb *urb); +static void bfusb_rx_complete(struct urb *urb); static struct urb *bfusb_get_completed(struct bfusb_data *data) { @@ -190,7 +190,7 @@ static void bfusb_tx_wakeup(struct bfusb_data *data) clear_bit(BFUSB_TX_PROCESS, &data->state); } -static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs) +static void bfusb_tx_complete(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct bfusb_data *data = (struct bfusb_data *) skb->dev; @@ -349,7 +349,7 @@ static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned ch return 0; } -static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs) +static void bfusb_rx_complete(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct bfusb_data *data = (struct bfusb_data *) skb->dev; diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 8eebf9ca3786..845b8680032a 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -497,7 +497,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset) } -static irqreturn_t bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) +static irqreturn_t bluecard_interrupt(int irq, void *dev_inst) { bluecard_info_t *info = dev_inst; unsigned int iobase; diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index e0231dc2cb1a..9fca6513562d 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -263,7 +263,7 @@ static void bpa10x_wakeup(struct bpa10x_data *data) } } -static void bpa10x_complete(struct urb *urb, struct pt_regs *regs) +static void bpa10x_complete(struct urb *urb) { struct bpa10x_data *data = urb->context; unsigned char *buf = urb->transfer_buffer; diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index df7bb016df49..3a96a0babc6a 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -338,7 +338,7 @@ static void bt3c_receive(bt3c_info_t *info) } -static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) +static irqreturn_t bt3c_interrupt(int irq, void *dev_inst) { bt3c_info_t *info = dev_inst; unsigned int iobase; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 746ccca97f6f..3b29086b7c3f 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -288,7 +288,7 @@ static void btuart_receive(btuart_info_t *info) } -static irqreturn_t btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) +static irqreturn_t btuart_interrupt(int irq, void *dev_inst) { btuart_info_t *info = dev_inst; unsigned int iobase; diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 0e99def8a1e3..e7c800f4c3ad 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -291,7 +291,7 @@ static void dtl1_receive(dtl1_info_t *info) } -static irqreturn_t dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) +static irqreturn_t dtl1_interrupt(int irq, void *dev_inst) { dtl1_info_t *info = dev_inst; unsigned int iobase; diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 0801af4ad2b9..7565642a007a 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -176,8 +176,8 @@ static struct _urb *_urb_dequeue(struct _urb_queue *q) return _urb; } -static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs); -static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs); +static void hci_usb_rx_complete(struct urb *urb); +static void hci_usb_tx_complete(struct urb *urb); #define __pending_tx(husb, type) (&husb->pending_tx[type-1]) #define __pending_q(husb, type) (&husb->pending_q[type-1]) @@ -732,7 +732,7 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c return 0; } -static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs) +static void hci_usb_rx_complete(struct urb *urb) { struct _urb *_urb = container_of(urb, struct _urb, urb); struct hci_usb *husb = (void *) urb->context; @@ -786,7 +786,7 @@ unlock: read_unlock(&husb->completion_lock); } -static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs) +static void hci_usb_tx_complete(struct urb *urb) { struct _urb *_urb = container_of(urb, struct _urb, urb); struct hci_usb *husb = (void *) urb->context; diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index ccd91c1a84bd..2157c58755e0 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -513,7 +513,7 @@ static inline void write_cmd(unsigned char cmd) outb(cmd, sony_cd_cmd_reg); } -static irqreturn_t cdu31a_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cdu31a_interrupt(int irq, void *dev_id) { unsigned char val; diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c index 9b05ddd23141..e6d8e9ededea 100644 --- a/drivers/cdrom/cm206.c +++ b/drivers/cdrom/cm206.c @@ -359,7 +359,7 @@ static struct tasklet_struct cm206_tasklet; as there seems so reason for this to happen. */ -static irqreturn_t cm206_interrupt(int sig, void *dev_id, struct pt_regs *regs) +static irqreturn_t cm206_interrupt(int sig, void *dev_id) { volatile ush fool; cd->intr_ds = inw(r_data_status); /* resets data_ready, data_error, diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index dcd1ab684f3e..60e1978ec0ea 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -845,7 +845,7 @@ static void mcdx_delay(struct s_drive_stuff *stuff, long jifs) } } -static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mcdx_intr(int irq, void *dev_id) { struct s_drive_stuff *stuffp = dev_id; unsigned char b; diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c index 30ab56258a92..f77ada933ea0 100644 --- a/drivers/cdrom/sonycd535.c +++ b/drivers/cdrom/sonycd535.c @@ -322,7 +322,7 @@ disable_interrupts(void) } static irqreturn_t -cdu535_interrupt(int irq, void *dev_id, struct pt_regs *regs) +cdu535_interrupt(int irq, void *dev_id) { disable_interrupts(); if (waitqueue_active(&cdu535_irq_wait)) { diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 486f97c3f4e5..66086fa2d59a 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -447,7 +447,7 @@ static void check_modem_status(struct async_struct *info) } } -static irqreturn_t ser_vbl_int( int irq, void *data, struct pt_regs *regs) +static irqreturn_t ser_vbl_int( int irq, void *data) { /* vbl is just a periodic interrupt we tie into to update modem status */ struct async_struct * info = IRQ_ports; @@ -460,7 +460,7 @@ static irqreturn_t ser_vbl_int( int irq, void *data, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t ser_rx_int(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t ser_rx_int(int irq, void *dev_id) { struct async_struct * info; @@ -480,7 +480,7 @@ static irqreturn_t ser_rx_int(int irq, void *dev_id, struct pt_regs * regs) return IRQ_HANDLED; } -static irqreturn_t ser_tx_int(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t ser_tx_int(int irq, void *dev_id) { struct async_struct * info; diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 10a389dafd60..1f0b752e5de1 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -110,7 +110,7 @@ static ssize_t ac_read (struct file *, char __user *, size_t, loff_t *); static ssize_t ac_write (struct file *, const char __user *, size_t, loff_t *); static int ac_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -static irqreturn_t ac_interrupt(int, void *, struct pt_regs *); +static irqreturn_t ac_interrupt(int, void *); static const struct file_operations ac_fops = { .owner = THIS_MODULE, @@ -617,7 +617,7 @@ static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_ } } -static irqreturn_t ac_interrupt(int vec, void *dev_instance, struct pt_regs *regs) +static irqreturn_t ac_interrupt(int vec, void *dev_instance) { unsigned int i; unsigned int FlagInt; diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 87b2fb510871..e608dadece2f 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -1057,7 +1057,7 @@ detect_isa_irq(void __iomem *address) received, out buffer empty, modem change, etc. */ static irqreturn_t -cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +cyy_interrupt(int irq, void *dev_id) { struct tty_struct *tty; int status; @@ -1802,7 +1802,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo) #ifdef CONFIG_CYZ_INTR static irqreturn_t -cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs) +cyz_interrupt(int irq, void *dev_id) { struct cyclades_card *cinfo; diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h index 695115d70382..2908b72daa6e 100644 --- a/drivers/char/drm/drm_os_linux.h +++ b/drivers/char/drm/drm_os_linux.h @@ -38,7 +38,7 @@ drm_device_t *dev = priv->head->dev /** IRQ handler arguments and return type and values */ -#define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs +#define DRM_IRQ_ARGS int irq, void *arg /** AGP types */ #if __OS_HAS_AGP diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c index abac18b1871c..77f58ed6d59a 100644 --- a/drivers/char/ec3104_keyb.c +++ b/drivers/char/ec3104_keyb.c @@ -370,7 +370,7 @@ static void e5_receive(struct e5_struct *k) } } -static void ec3104_keyb_interrupt(int irq, void *data, struct pt_regs *regs) +static void ec3104_keyb_interrupt(int irq, void *data) { struct e5_struct *k = &ec3104_keyb; u8 msr, lsr; diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 05788c75d7fc..15a4ea896328 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -615,8 +615,7 @@ static inline void check_modem_status(struct esp_struct *info) /* * This is the serial driver's interrupt routine */ -static irqreturn_t rs_interrupt_single(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t rs_interrupt_single(int irq, void *dev_id) { struct esp_struct * info; unsigned err_status; diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c index 216532445652..bbcf918f056f 100644 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ b/drivers/char/ftape/lowlevel/fdc-io.c @@ -1243,7 +1243,7 @@ static int fdc_config(void) TRACE_EXIT 0; } -static irqreturn_t ftape_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ftape_interrupt(int irq, void *dev_id) { void (*handler) (void) = *fdc.hook; int handled = 0; diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index d69f2ad9a67d..1aa93a752a9c 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -159,7 +159,7 @@ static void hangcheck_fire(unsigned long data) if (hangcheck_dump_tasks) { printk(KERN_CRIT "Hangcheck: Task state:\n"); #ifdef CONFIG_MAGIC_SYSRQ - handle_sysrq('t', NULL, NULL); + handle_sysrq('t', NULL); #endif /* CONFIG_MAGIC_SYSRQ */ } if (hangcheck_reboot) { diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 58b0eb581114..091a11cd878c 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -116,7 +116,7 @@ static inline void writeq(unsigned long long v, void __iomem *addr) } #endif -static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t hpet_interrupt(int irq, void *data) { struct hpet_dev *devp; unsigned long isr; diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 4053d1cd393f..9902ffad3b12 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -294,7 +294,7 @@ static int hvc_poll(struct hvc_struct *hp); * NOTE: This API isn't used if the console adapter doesn't support interrupts. * In this case the console is poll driven. */ -static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance) { /* if hvc_poll request a repoll, then kick the hvcd thread */ if (hvc_poll(dev_instance)) @@ -621,7 +621,7 @@ static int hvc_poll(struct hvc_struct *hp) sysrq_pressed = 1; continue; } else if (sysrq_pressed) { - handle_sysrq(buf[i], NULL, tty); + handle_sysrq(buf[i], tty); sysrq_pressed = 0; continue; } diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 0b89bcde8c52..8728255c9463 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -313,8 +313,7 @@ static DEFINE_SPINLOCK(hvcs_structs_lock); static void hvcs_unthrottle(struct tty_struct *tty); static void hvcs_throttle(struct tty_struct *tty); -static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance, - struct pt_regs *regs); +static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance); static int hvcs_write(struct tty_struct *tty, const unsigned char *buf, int count); @@ -387,8 +386,7 @@ static void hvcs_throttle(struct tty_struct *tty) * handler taking any further interrupts because they are disabled which means * the hvcs_struct will always be valid in this handler. */ -static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance) { struct hvcs_struct *hvcsd = dev_instance; diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index c07dc58d5c1d..2cf63e7305a3 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -406,7 +406,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) hp->sysrq = 1; continue; } else if (hp->sysrq) { - handle_sysrq(c, NULL, hp->tty); + handle_sysrq(c, hp->tty); hp->sysrq = 0; continue; } @@ -555,7 +555,7 @@ static void hvsi_send_overflow(struct hvsi_struct *hp) * must get all pending data because we only get an irq on empty->non-empty * transition */ -static irqreturn_t hvsi_interrupt(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t hvsi_interrupt(int irq, void *arg) { struct hvsi_struct *hp = (struct hvsi_struct *)arg; struct tty_struct *flip; @@ -616,7 +616,7 @@ static int __init poll_for_state(struct hvsi_struct *hp, int state) unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; for (;;) { - hvsi_interrupt(hp->virq, (void *)hp, NULL); /* get pending data */ + hvsi_interrupt(hp->virq, (void *)hp); /* get pending data */ if (hp->state == state) return 0; diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 62ef511d143b..858ba5432c99 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -190,7 +190,7 @@ static int ip2_tiocmset(struct tty_struct *tty, struct file *file, static void set_irq(int, int); static void ip2_interrupt_bh(i2eBordStrPtr pB); -static irqreturn_t ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t ip2_interrupt(int irq, void *dev_id); static void ip2_poll(unsigned long arg); static inline void service_all_boards(void); static void do_input(void *p); @@ -1154,10 +1154,9 @@ ip2_interrupt_bh(i2eBordStrPtr pB) /******************************************************************************/ -/* Function: ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs) */ +/* Function: ip2_interrupt(int irq, void *dev_id) */ /* Parameters: irq - interrupt number */ /* pointer to optional device ID structure */ -/* pointer to register structure */ /* Returns: Nothing */ /* */ /* Description: */ @@ -1173,7 +1172,7 @@ ip2_interrupt_bh(i2eBordStrPtr pB) /* */ /******************************************************************************/ static irqreturn_t -ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs) +ip2_interrupt(int irq, void *dev_id) { int i; i2eBordStrPtr pB; @@ -1237,7 +1236,7 @@ ip2_poll(unsigned long arg) // Just polled boards, IRQ = 0 will hit all non-interrupt boards. // It will NOT poll boards handled by hard interrupts. // The issue of queued BH interrups is handled in ip2_interrupt(). - ip2_interrupt(0, NULL, NULL); + ip2_interrupt(0, NULL); PollTimer.expires = POLL_TIMEOUT; add_timer( &PollTimer ); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index b106c45abfc9..24825bdca8f4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -872,7 +872,7 @@ static void smi_timeout(unsigned long data) add_timer(&(smi_info->si_timer)); } -static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs) +static irqreturn_t si_irq_handler(int irq, void *data) { struct smi_info *smi_info = data; unsigned long flags; @@ -899,14 +899,14 @@ static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t si_bt_irq_handler(int irq, void *data, struct pt_regs *regs) +static irqreturn_t si_bt_irq_handler(int irq, void *data) { struct smi_info *smi_info = data; /* We need to clear the IRQ flag for the BT interface. */ smi_info->io.outputb(&smi_info->io, IPMI_BT_INTMASK_REG, IPMI_BT_INTMASK_CLEAR_IRQ_BIT | IPMI_BT_INTMASK_ENABLE_IRQ_BIT); - return si_irq_handler(irq, data, regs); + return si_irq_handler(irq, data); } static int smi_start_processing(void *send_info, diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index accaaf1a6b69..73f759eaa5a6 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -903,7 +903,7 @@ static void ipmi_register_watchdog(int ipmi_intf) #ifdef HAVE_NMI_HANDLER static int -ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled) +ipmi_nmi(void *dev_id, int cpu, int handled) { /* If we are not expecting a timeout, ignore it. */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index ea2bbf80ad33..e9e9bf31c369 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -546,7 +546,7 @@ static void isicom_bottomhalf(void *data) * Main interrupt handler routine */ -static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t isicom_interrupt(int irq, void *dev_id) { struct isi_board *card = dev_id; struct isi_port *port; diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index e2011669c7bb..20b6c8b30248 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -77,7 +78,7 @@ void compute_shiftstate(void); k_slock, k_dead2, k_brl, k_ignore typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, - char up_flag, struct pt_regs *regs); + char up_flag); static k_handler_fn K_HANDLERS; static k_handler_fn *k_handler[16] = { K_HANDLERS }; @@ -88,7 +89,7 @@ static k_handler_fn *k_handler[16] = { K_HANDLERS }; fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num -typedef void (fn_handler_fn)(struct vc_data *vc, struct pt_regs *regs); +typedef void (fn_handler_fn)(struct vc_data *vc); static fn_handler_fn FN_HANDLERS; static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; @@ -428,7 +429,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) /* * Special function handlers */ -static void fn_enter(struct vc_data *vc, struct pt_regs *regs) +static void fn_enter(struct vc_data *vc) { if (diacr) { if (kbd->kbdmode == VC_UNICODE) @@ -442,27 +443,28 @@ static void fn_enter(struct vc_data *vc, struct pt_regs *regs) put_queue(vc, 10); } -static void fn_caps_toggle(struct vc_data *vc, struct pt_regs *regs) +static void fn_caps_toggle(struct vc_data *vc) { if (rep) return; chg_vc_kbd_led(kbd, VC_CAPSLOCK); } -static void fn_caps_on(struct vc_data *vc, struct pt_regs *regs) +static void fn_caps_on(struct vc_data *vc) { if (rep) return; set_vc_kbd_led(kbd, VC_CAPSLOCK); } -static void fn_show_ptregs(struct vc_data *vc, struct pt_regs *regs) +static void fn_show_ptregs(struct vc_data *vc) { + struct pt_regs *regs = get_irq_regs(); if (regs) show_regs(regs); } -static void fn_hold(struct vc_data *vc, struct pt_regs *regs) +static void fn_hold(struct vc_data *vc) { struct tty_struct *tty = vc->vc_tty; @@ -480,12 +482,12 @@ static void fn_hold(struct vc_data *vc, struct pt_regs *regs) stop_tty(tty); } -static void fn_num(struct vc_data *vc, struct pt_regs *regs) +static void fn_num(struct vc_data *vc) { if (vc_kbd_mode(kbd,VC_APPLIC)) applkey(vc, 'P', 1); else - fn_bare_num(vc, regs); + fn_bare_num(vc); } /* @@ -494,19 +496,19 @@ static void fn_num(struct vc_data *vc, struct pt_regs *regs) * Bind this to NumLock if you prefer that the NumLock key always * changes the NumLock flag. */ -static void fn_bare_num(struct vc_data *vc, struct pt_regs *regs) +static void fn_bare_num(struct vc_data *vc) { if (!rep) chg_vc_kbd_led(kbd, VC_NUMLOCK); } -static void fn_lastcons(struct vc_data *vc, struct pt_regs *regs) +static void fn_lastcons(struct vc_data *vc) { /* switch to the last used console, ChN */ set_console(last_console); } -static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs) +static void fn_dec_console(struct vc_data *vc) { int i, cur = fg_console; @@ -523,7 +525,7 @@ static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs) set_console(i); } -static void fn_inc_console(struct vc_data *vc, struct pt_regs *regs) +static void fn_inc_console(struct vc_data *vc) { int i, cur = fg_console; @@ -540,7 +542,7 @@ static void fn_inc_console(struct vc_data *vc, struct pt_regs *regs) set_console(i); } -static void fn_send_intr(struct vc_data *vc, struct pt_regs *regs) +static void fn_send_intr(struct vc_data *vc) { struct tty_struct *tty = vc->vc_tty; @@ -550,37 +552,37 @@ static void fn_send_intr(struct vc_data *vc, struct pt_regs *regs) con_schedule_flip(tty); } -static void fn_scroll_forw(struct vc_data *vc, struct pt_regs *regs) +static void fn_scroll_forw(struct vc_data *vc) { scrollfront(vc, 0); } -static void fn_scroll_back(struct vc_data *vc, struct pt_regs *regs) +static void fn_scroll_back(struct vc_data *vc) { scrollback(vc, 0); } -static void fn_show_mem(struct vc_data *vc, struct pt_regs *regs) +static void fn_show_mem(struct vc_data *vc) { show_mem(); } -static void fn_show_state(struct vc_data *vc, struct pt_regs *regs) +static void fn_show_state(struct vc_data *vc) { show_state(); } -static void fn_boot_it(struct vc_data *vc, struct pt_regs *regs) +static void fn_boot_it(struct vc_data *vc) { ctrl_alt_del(); } -static void fn_compose(struct vc_data *vc, struct pt_regs *regs) +static void fn_compose(struct vc_data *vc) { dead_key_next = 1; } -static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs) +static void fn_spawn_con(struct vc_data *vc) { spin_lock(&vt_spawn_con.lock); if (vt_spawn_con.pid) @@ -591,7 +593,7 @@ static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs) spin_unlock(&vt_spawn_con.lock); } -static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) +static void fn_SAK(struct vc_data *vc) { struct tty_struct *tty = vc->vc_tty; @@ -604,7 +606,7 @@ static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) reset_vc(vc); } -static void fn_null(struct vc_data *vc, struct pt_regs *regs) +static void fn_null(struct vc_data *vc) { compute_shiftstate(); } @@ -612,11 +614,11 @@ static void fn_null(struct vc_data *vc, struct pt_regs *regs) /* * Special key handlers */ -static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag) { } -static void k_spec(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; @@ -626,15 +628,15 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag, struct kbd->kbdmode == VC_MEDIUMRAW) && value != KVAL(K_SAK)) return; /* SAK is allowed even in raw mode */ - fn_handler[value](vc, regs); + fn_handler[value](vc); } -static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) { printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); } -static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs) +static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) { if (up_flag) return; /* no action, if this is a key release */ @@ -658,41 +660,41 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag, stru * dead keys modifying the same character. Very useful * for Vietnamese. */ -static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs) +static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag) { if (up_flag) return; diacr = (diacr ? handle_diacr(vc, value) : value); } -static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_self(struct vc_data *vc, unsigned char value, char up_flag) { - k_unicode(vc, value, up_flag, regs); + k_unicode(vc, value, up_flag); } -static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) { - k_deadunicode(vc, value, up_flag, regs); + k_deadunicode(vc, value, up_flag); } /* * Obsolete - for backwards compatibility only */ -static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) { static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; value = ret_diacr[value]; - k_deadunicode(vc, value, up_flag, regs); + k_deadunicode(vc, value, up_flag); } -static void k_cons(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_cons(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; set_console(value); } -static void k_fn(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) { unsigned v; @@ -706,7 +708,7 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag, struct p printk(KERN_ERR "k_fn called with value=%d\n", value); } -static void k_cur(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) { static const char *cur_chars = "BDCA"; @@ -715,7 +717,7 @@ static void k_cur(struct vc_data *vc, unsigned char value, char up_flag, struct applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE)); } -static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) { static const char pad_chars[] = "0123456789+-*/\015,.?()#"; static const char app_map[] = "pqrstuvwxylSRQMnnmPQS"; @@ -733,34 +735,34 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct switch (value) { case KVAL(K_PCOMMA): case KVAL(K_PDOT): - k_fn(vc, KVAL(K_REMOVE), 0, regs); + k_fn(vc, KVAL(K_REMOVE), 0); return; case KVAL(K_P0): - k_fn(vc, KVAL(K_INSERT), 0, regs); + k_fn(vc, KVAL(K_INSERT), 0); return; case KVAL(K_P1): - k_fn(vc, KVAL(K_SELECT), 0, regs); + k_fn(vc, KVAL(K_SELECT), 0); return; case KVAL(K_P2): - k_cur(vc, KVAL(K_DOWN), 0, regs); + k_cur(vc, KVAL(K_DOWN), 0); return; case KVAL(K_P3): - k_fn(vc, KVAL(K_PGDN), 0, regs); + k_fn(vc, KVAL(K_PGDN), 0); return; case KVAL(K_P4): - k_cur(vc, KVAL(K_LEFT), 0, regs); + k_cur(vc, KVAL(K_LEFT), 0); return; case KVAL(K_P6): - k_cur(vc, KVAL(K_RIGHT), 0, regs); + k_cur(vc, KVAL(K_RIGHT), 0); return; case KVAL(K_P7): - k_fn(vc, KVAL(K_FIND), 0, regs); + k_fn(vc, KVAL(K_FIND), 0); return; case KVAL(K_P8): - k_cur(vc, KVAL(K_UP), 0, regs); + k_cur(vc, KVAL(K_UP), 0); return; case KVAL(K_P9): - k_fn(vc, KVAL(K_PGUP), 0, regs); + k_fn(vc, KVAL(K_PGUP), 0); return; case KVAL(K_P5): applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC)); @@ -772,7 +774,7 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct put_queue(vc, 10); } -static void k_shift(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) { int old_state = shift_state; @@ -813,7 +815,7 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag, struc } } -static void k_meta(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; @@ -825,7 +827,7 @@ static void k_meta(struct vc_data *vc, unsigned char value, char up_flag, struct put_queue(vc, value | 0x80); } -static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) { int base; @@ -847,16 +849,16 @@ static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag, struc npadch = npadch * base + value; } -static void k_lock(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag || rep) return; chg_vc_kbd_lock(kbd, value); } -static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_slock(struct vc_data *vc, unsigned char value, char up_flag) { - k_shift(vc, value, up_flag, regs); + k_shift(vc, value, up_flag); if (up_flag || rep) return; chg_vc_kbd_slock(kbd, value); @@ -876,25 +878,25 @@ static unsigned brl_nbchords = 1; MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)"); module_param(brl_nbchords, uint, 0644); -static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag, struct pt_regs *regs) +static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag) { static unsigned long chords; static unsigned committed; if (!brl_nbchords) - k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag, regs); + k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag); else { committed |= pattern; chords++; if (chords == brl_nbchords) { - k_unicode(vc, BRL_UC_ROW | committed, up_flag, regs); + k_unicode(vc, BRL_UC_ROW | committed, up_flag); chords = 0; committed = 0; } } } -static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) { static unsigned pressed,committing; static unsigned long releasestart; @@ -906,7 +908,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct } if (!value) { - k_unicode(vc, BRL_UC_ROW, up_flag, regs); + k_unicode(vc, BRL_UC_ROW, up_flag); return; } @@ -923,13 +925,13 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pressed &= ~(1 << (value - 1)); if (!pressed) { if (committing) { - k_brlcommit(vc, committing, 0, regs); + k_brlcommit(vc, committing, 0); committing = 0; } } } else { if (committing) { - k_brlcommit(vc, committing, 0, regs); + k_brlcommit(vc, committing, 0); committing = 0; } pressed &= ~(1 << (value - 1)); @@ -1133,8 +1135,7 @@ static void kbd_rawcode(unsigned char data) put_queue(vc, data); } -static void kbd_keycode(unsigned int keycode, int down, - int hw_raw, struct pt_regs *regs) +static void kbd_keycode(unsigned int keycode, int down, int hw_raw) { struct vc_data *vc = vc_cons[fg_console].d; unsigned short keysym, *key_map; @@ -1181,7 +1182,7 @@ static void kbd_keycode(unsigned int keycode, int down, if (sysrq_down && !down && keycode == sysrq_alt_use) sysrq_down = 0; if (sysrq_down && down && !rep) { - handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); + handle_sysrq(kbd_sysrq_xlate[keycode], tty); return; } #endif @@ -1267,7 +1268,7 @@ static void kbd_keycode(unsigned int keycode, int down, } } - (*k_handler[type])(vc, keysym & 0xff, !down, regs); + (*k_handler[type])(vc, keysym & 0xff, !down); if (type != KT_SLOCK) kbd->slockstate = 0; @@ -1279,7 +1280,7 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) kbd_rawcode(value); if (event_type == EV_KEY) - kbd_keycode(event_code, value, HW_RAW(handle->dev), handle->dev->regs); + kbd_keycode(event_code, value, HW_RAW(handle->dev)); tasklet_schedule(&keyboard_tasklet); do_poke_blanked_console = 1; schedule_console_callback(); diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 636354722658..0afb7ba999cf 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -516,11 +516,10 @@ int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma) * mbcs_completion_intr_handler - Primary completion handler. * @irq: irq * @arg: soft struct for device - * @ep: regs * */ static irqreturn_t -mbcs_completion_intr_handler(int irq, void *arg, struct pt_regs *ep) +mbcs_completion_intr_handler(int irq, void *arg) { struct mbcs_soft *soft = (struct mbcs_soft *)arg; void *mmr_base; diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index 1f0f2b6dae26..22b9905c1e52 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -422,7 +422,6 @@ static int inline reschedule_periodic_timer(mmtimer_t *x) * mmtimer_interrupt - timer interrupt handler * @irq: irq received * @dev_id: device the irq came from - * @regs: register state upon receipt of the interrupt * * Called when one of the comarators matches the counter, This * routine will send signals to processes that have requested @@ -433,7 +432,7 @@ static int inline reschedule_periodic_timer(mmtimer_t *x) * registers. */ static irqreturn_t -mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +mmtimer_interrupt(int irq, void *dev_id) { int i; unsigned long expires = 0; diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c index cc3e54dd7234..f282976daaac 100644 --- a/drivers/char/mwave/tp3780i.c +++ b/drivers/char/mwave/tp3780i.c @@ -95,14 +95,14 @@ static void EnableSRAM(THINKPAD_BD_DATA * pBDData) } -static irqreturn_t UartInterrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t UartInterrupt(int irq, void *dev_id) { PRINTK_3(TRACE_TP3780I, "tp3780i::UartInterrupt entry irq %x dev_id %p\n", irq, dev_id); return IRQ_HANDLED; } -static irqreturn_t DspInterrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t DspInterrupt(int irq, void *dev_id) { pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd; DSP_3780I_CONFIG_SETTINGS *pSettings = &pDrvData->rBDData.rDspSettings; diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 8253fca8efd5..048d91142c17 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -407,7 +407,7 @@ static void mxser_stop(struct tty_struct *); static void mxser_start(struct tty_struct *); static void mxser_hangup(struct tty_struct *); static void mxser_rs_break(struct tty_struct *, int); -static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *); +static irqreturn_t mxser_interrupt(int, void *); static void mxser_receive_chars(struct mxser_struct *, int *); static void mxser_transmit_chars(struct mxser_struct *); static void mxser_check_modem_status(struct mxser_struct *, int); @@ -1916,7 +1916,7 @@ static void mxser_rs_break(struct tty_struct *tty, int break_state) /* * This is the serial driver's generic interrupt routine */ -static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mxser_interrupt(int irq, void *dev_id) { int status, iir, i; struct mxser_struct *info; diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index ea1aa7764f8e..2d264971d839 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -144,7 +144,7 @@ static void button_sequence_finished (unsigned long parameters) * increments the counter. */ -static irqreturn_t button_handler (int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t button_handler (int irq, void *dev_id) { if (button_press_count) { del_timer (&button_timer); diff --git a/drivers/char/nwbutton.h b/drivers/char/nwbutton.h index ddb7b928dcbb..c3ebc16ce8a7 100644 --- a/drivers/char/nwbutton.h +++ b/drivers/char/nwbutton.h @@ -25,7 +25,7 @@ struct button_callback { /* Function prototypes: */ static void button_sequence_finished (unsigned long parameters); -static irqreturn_t button_handler (int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t button_handler (int irq, void *dev_id); int button_init (void); int button_add_callback (void (*callback) (void), int count); int button_del_callback (void (*callback) (void)); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 73e324209913..1a0bc30b79d1 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -416,7 +416,7 @@ static void rx_reset_buffers(MGSLPC_INFO *info); static int rx_alloc_buffers(MGSLPC_INFO *info); static void rx_free_buffers(MGSLPC_INFO *info); -static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t mgslpc_isr(int irq, void *dev_id); /* * Bottom half interrupt handlers @@ -1234,9 +1234,8 @@ static void ri_change(MGSLPC_INFO *info) * * irq interrupt number that caused interrupt * dev_id device ID supplied during interrupt registration - * regs interrupted processor context */ -static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t mgslpc_isr(int irq, void *dev_id) { MGSLPC_INFO * info = (MGSLPC_INFO *)dev_id; unsigned short isr; diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 520d2cf82bc0..efc485edad1c 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -269,7 +269,7 @@ static ssize_t pp_write (struct file * file, const char __user * buf, return bytes_written; } -static void pp_irq (int irq, void * private, struct pt_regs * unused) +static void pp_irq (int irq, void * private) { struct pp_struct * pp = (struct pp_struct *) private; diff --git a/drivers/char/qtronix.c b/drivers/char/qtronix.c index 9d134e98d2a0..5c9477741a30 100644 --- a/drivers/char/qtronix.c +++ b/drivers/char/qtronix.c @@ -93,7 +93,7 @@ struct cir_port *cir; static unsigned char kbdbytes[5]; static unsigned char cir_data[32]; /* we only need 16 chars */ -static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs); +static void kbd_int_handler(int irq, void *dev_id); static int handle_data(unsigned char *p_data); static inline void handle_mouse_event(unsigned char scancode); static inline void handle_keyboard_event(unsigned char scancode, int down); @@ -197,7 +197,7 @@ int CheckSumOk(u_int8_t byte1, u_int8_t byte2, } -static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs) +static void kbd_int_handler(int irq, void *dev_id) { struct cir_port *cir; int j; diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 202a3b0945b7..3bea594600d4 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -363,7 +363,7 @@ static void rio_reset_interrupt(struct Host *HostP) } -static irqreturn_t rio_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t rio_interrupt(int irq, void *ptr) { struct Host *HostP; func_enter(); @@ -417,7 +417,7 @@ static void rio_pollfunc(unsigned long data) { func_enter(); - rio_interrupt(0, &p->RIOHosts[data], NULL); + rio_interrupt(0, &p->RIOHosts[data]); p->RIOHosts[data].timer.expires = jiffies + rio_poll; add_timer(&p->RIOHosts[data].timer); diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index b0ab3f28cc6a..be68cfb0ae69 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -550,7 +550,7 @@ static inline void rc_check_modem(struct riscom_board const * bp) } /* The main interrupt processing routine */ -static irqreturn_t rc_interrupt(int irq, void * dev_id, struct pt_regs * regs) +static irqreturn_t rc_interrupt(int irq, void * dev_id) { unsigned char status; unsigned char ack; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 656f8c0ca52e..abee7a339462 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -113,9 +113,9 @@ static int rtc_has_irq = 1; #define hpet_set_rtc_irq_bit(arg) 0 #define hpet_rtc_timer_init() do { } while (0) #define hpet_rtc_dropped_irq() 0 -static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) {return 0;} +static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) {return 0;} #else -extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); #endif /* @@ -229,7 +229,7 @@ static inline unsigned char rtc_is_updating(void) * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) */ -irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t rtc_interrupt(int irq, void *dev_id) { /* * Can be an alarm interrupt, update complete interrupt, @@ -915,7 +915,7 @@ static const struct file_operations rtc_proc_fops = { }; #if defined(RTC_IRQ) && !defined(__sparc__) -static irqreturn_t (*rtc_int_handler_ptr)(int irq, void *dev_id, struct pt_regs *regs); +static irq_handler_t rtc_int_handler_ptr; #endif static int __init rtc_init(void) diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 65c751d0d643..4217d38caef9 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -111,7 +111,7 @@ /***************************** Prototypes ***************************/ /* The interrupt service routine */ -static irqreturn_t a2232_vbl_inter(int irq, void *data, struct pt_regs *fp); +static irqreturn_t a2232_vbl_inter(int irq, void *data); /* Initialize the port structures */ static void a2232_init_portstructs(void); /* Initialize and register TTY drivers. */ @@ -504,7 +504,7 @@ static int a2232_open(struct tty_struct * tty, struct file * filp) } /*** END OF FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/ -static irqreturn_t a2232_vbl_inter(int irq, void *data, struct pt_regs *fp) +static irqreturn_t a2232_vbl_inter(int irq, void *data) { #if A2232_IOBUFLEN != 256 #error "Re-Implement a2232_vbl_inter()!" diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index f4809c8183cc..6f13f98e3171 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -370,7 +370,7 @@ cy_sched_event(struct cyclades_port *info, int event) received, out buffer empty, modem change, etc. */ static irqreturn_t -cd2401_rxerr_interrupt(int irq, void *dev_id, struct pt_regs *fp) +cd2401_rxerr_interrupt(int irq, void *dev_id) { struct tty_struct *tty; struct cyclades_port *info; @@ -451,7 +451,7 @@ cd2401_rxerr_interrupt(int irq, void *dev_id, struct pt_regs *fp) } /* cy_rxerr_interrupt */ static irqreturn_t -cd2401_modem_interrupt(int irq, void *dev_id, struct pt_regs *fp) +cd2401_modem_interrupt(int irq, void *dev_id) { struct cyclades_port *info; volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; @@ -506,7 +506,7 @@ cd2401_modem_interrupt(int irq, void *dev_id, struct pt_regs *fp) } /* cy_modem_interrupt */ static irqreturn_t -cd2401_tx_interrupt(int irq, void *dev_id, struct pt_regs *fp) +cd2401_tx_interrupt(int irq, void *dev_id) { struct cyclades_port *info; volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; @@ -626,7 +626,7 @@ cd2401_tx_interrupt(int irq, void *dev_id, struct pt_regs *fp) } /* cy_tx_interrupt */ static irqreturn_t -cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp) +cd2401_rx_interrupt(int irq, void *dev_id) { struct tty_struct *tty; struct cyclades_port *info; diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 07e0b75f2338..52753e723eaa 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -34,7 +34,7 @@ #define SCDRV_TIMEOUT 1000 static irqreturn_t -scdrv_interrupt(int irq, void *subch_data, struct pt_regs *regs) +scdrv_interrupt(int irq, void *subch_data) { struct subch_data_s *sd = subch_data; unsigned long flags; diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index 864854c58866..2f56e8c54897 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -36,7 +36,7 @@ DECLARE_TASKLET(sn_sysctl_event, scdrv_event, 0); * destination. */ static irqreturn_t -scdrv_event_interrupt(int irq, void *subch_data, struct pt_regs *regs) +scdrv_event_interrupt(int irq, void *subch_data) { struct subch_data_s *sd = subch_data; unsigned long flags; diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index d4e434d694b7..c084149153de 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -826,7 +826,7 @@ static void sonypi_report_input_event(u8 event) } /* Interrupt handler: some event is available */ -static irqreturn_t sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sonypi_irq(int irq, void *dev_id) { u8 v1, v2, event = 0; int i, j; diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 902c48dca3bc..6022495571ae 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -200,7 +200,7 @@ static struct specialix_port sx_port[SX_NBOARD * SX_NPORT]; #ifdef SPECIALIX_TIMER static struct timer_list missed_irq_timer; -static irqreturn_t sx_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static irqreturn_t sx_interrupt(int irq, void * dev_id); #endif @@ -897,7 +897,7 @@ static inline void sx_check_modem(struct specialix_board * bp) /* The main interrupt processing routine */ -static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sx_interrupt(int irq, void *dev_id) { unsigned char status; unsigned char ack; diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index bd711537ec4e..522e88e395cc 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -1927,13 +1927,12 @@ stl_readdone: * calls off to the approrpriate board interrupt handlers. */ -static irqreturn_t stl_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t stl_intr(int irq, void *dev_id) { stlbrd_t *brdp = (stlbrd_t *) dev_id; #ifdef DEBUG - printk("stl_intr(brdp=%x,irq=%d,regs=%x)\n", (int) brdp, irq, - (int) regs); + printk("stl_intr(brdp=%x,irq=%d)\n", (int) brdp, irq); #endif return IRQ_RETVAL((* brdp->isr)(brdp)); diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 8fd71a5fc619..5fec626598cd 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -1192,7 +1192,7 @@ static inline void sx_check_modem_signals (struct sx_port *port) * Small, elegant, clear. */ -static irqreturn_t sx_interrupt (int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sx_interrupt (int irq, void *ptr) { struct sx_board *board = ptr; struct sx_port *port; @@ -1300,7 +1300,7 @@ static void sx_pollfunc (unsigned long data) func_enter (); - sx_interrupt (0, board, NULL); + sx_interrupt (0, board); init_timer(&board->timer); diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index a4150c4519c4..f2864cc64240 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1698,11 +1698,10 @@ static void mgsl_isr_transmit_dma( struct mgsl_struct *info ) * * irq interrupt number that caused interrupt * dev_id device ID supplied during interrupt registration - * regs interrupted processor context * * Return Value: None */ -static irqreturn_t mgsl_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t mgsl_interrupt(int irq, void *dev_id) { struct mgsl_struct * info; u16 UscVector; diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index bdc7cb248b8f..d4334c79f8d4 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -491,7 +491,7 @@ static void isr_serial(struct slgt_info *info); static void isr_rdma(struct slgt_info *info); static void isr_txeom(struct slgt_info *info, unsigned short status); static void isr_tdma(struct slgt_info *info); -static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t slgt_interrupt(int irq, void *dev_id); static int alloc_dma_bufs(struct slgt_info *info); static void free_dma_bufs(struct slgt_info *info); @@ -2217,9 +2217,8 @@ static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int * * irq interrupt number * dev_id device ID supplied during interrupt registration - * regs interrupted processor context */ -static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t slgt_interrupt(int irq, void *dev_id) { struct slgt_info *info; unsigned int gsr; diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 6eb75dcd7961..3e932b681371 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -2596,8 +2596,7 @@ void isr_io_pin( SLMP_INFO *info, u16 status ) * dev_id device ID supplied during interrupt registration * regs interrupted processor context */ -static irqreturn_t synclinkmp_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t synclinkmp_interrupt(int irq, void *dev_id) { SLMP_INFO * info; unsigned char status, status0, status1=0; diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 6b4d4d1e343d..4c0e08685705 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -35,14 +35,14 @@ #include #include #include +#include #include /* Whether we react on sysrq keys or just ignore them */ int sysrq_enabled = 1; -static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_loglevel(int key, struct tty_struct *tty) { int i; i = key - '0'; @@ -58,8 +58,7 @@ static struct sysrq_key_op sysrq_loglevel_op = { }; #ifdef CONFIG_VT -static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_SAK(int key, struct tty_struct *tty) { if (tty) do_SAK(tty); @@ -76,8 +75,7 @@ static struct sysrq_key_op sysrq_SAK_op = { #endif #ifdef CONFIG_VT -static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_unraw(int key, struct tty_struct *tty) { struct kbd_struct *kbd = &kbd_table[fg_console]; @@ -95,10 +93,9 @@ static struct sysrq_key_op sysrq_unraw_op = { #endif /* CONFIG_VT */ #ifdef CONFIG_KEXEC -static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_crashdump(int key, struct tty_struct *tty) { - crash_kexec(pt_regs); + crash_kexec(get_irq_regs()); } static struct sysrq_key_op sysrq_crashdump_op = { .handler = sysrq_handle_crashdump, @@ -110,8 +107,7 @@ static struct sysrq_key_op sysrq_crashdump_op = { #define sysrq_crashdump_op (*(struct sysrq_key_op *)0) #endif -static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_reboot(int key, struct tty_struct *tty) { lockdep_off(); local_irq_enable(); @@ -124,8 +120,7 @@ static struct sysrq_key_op sysrq_reboot_op = { .enable_mask = SYSRQ_ENABLE_BOOT, }; -static void sysrq_handle_sync(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_sync(int key, struct tty_struct *tty) { emergency_sync(); } @@ -136,8 +131,7 @@ static struct sysrq_key_op sysrq_sync_op = { .enable_mask = SYSRQ_ENABLE_SYNC, }; -static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_mountro(int key, struct tty_struct *tty) { emergency_remount(); } @@ -149,8 +143,7 @@ static struct sysrq_key_op sysrq_mountro_op = { }; #ifdef CONFIG_LOCKDEP -static void sysrq_handle_showlocks(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_showlocks(int key, struct tty_struct *tty) { debug_show_all_locks(); } @@ -164,11 +157,11 @@ static struct sysrq_key_op sysrq_showlocks_op = { #define sysrq_showlocks_op (*(struct sysrq_key_op *)0) #endif -static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_showregs(int key, struct tty_struct *tty) { - if (pt_regs) - show_regs(pt_regs); + struct pt_regs *regs = get_irq_regs(); + if (regs) + show_regs(regs); } static struct sysrq_key_op sysrq_showregs_op = { .handler = sysrq_handle_showregs, @@ -177,8 +170,7 @@ static struct sysrq_key_op sysrq_showregs_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; -static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_showstate(int key, struct tty_struct *tty) { show_state(); } @@ -189,8 +181,7 @@ static struct sysrq_key_op sysrq_showstate_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; -static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_showmem(int key, struct tty_struct *tty) { show_mem(); } @@ -215,8 +206,7 @@ static void send_sig_all(int sig) } } -static void sysrq_handle_term(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_term(int key, struct tty_struct *tty) { send_sig_all(SIGTERM); console_loglevel = 8; @@ -236,8 +226,7 @@ static void moom_callback(void *ignored) static DECLARE_WORK(moom_work, moom_callback, NULL); -static void sysrq_handle_moom(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_moom(int key, struct tty_struct *tty) { schedule_work(&moom_work); } @@ -247,8 +236,7 @@ static struct sysrq_key_op sysrq_moom_op = { .action_msg = "Manual OOM execution", }; -static void sysrq_handle_kill(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_kill(int key, struct tty_struct *tty) { send_sig_all(SIGKILL); console_loglevel = 8; @@ -260,8 +248,7 @@ static struct sysrq_key_op sysrq_kill_op = { .enable_mask = SYSRQ_ENABLE_SIGNAL, }; -static void sysrq_handle_unrt(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_unrt(int key, struct tty_struct *tty) { normalize_rt_tasks(); } @@ -361,8 +348,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) * This is the non-locking version of handle_sysrq. It must/can only be called * by sysrq key handlers, as they are inside of the lock */ -void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, - int check_mask) +void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) { struct sysrq_key_op *op_p; int orig_log_level; @@ -384,7 +370,7 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, (sysrq_enabled & op_p->enable_mask)) { printk("%s\n", op_p->action_msg); console_loglevel = orig_log_level; - op_p->handler(key, pt_regs, tty); + op_p->handler(key, tty); } else { printk("This sysrq operation is disabled.\n"); } @@ -413,11 +399,11 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, * This function is called by the keyboard handler when SysRq is pressed * and any other keycode arrives. */ -void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) +void handle_sysrq(int key, struct tty_struct *tty) { if (!sysrq_enabled) return; - __handle_sysrq(key, pt_regs, tty, 1); + __handle_sysrq(key, tty, 1); } EXPORT_SYMBOL(handle_sysrq); diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index d2c5ba4e83b8..2444a0e24b31 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -193,7 +193,7 @@ static DEFINE_SPINLOCK(event_lock); static int tlclk_major = TLCLK_MAJOR; -static irqreturn_t tlclk_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t tlclk_interrupt(int irq, void *dev_id); static DECLARE_WAIT_QUEUE_HEAD(wq); @@ -856,7 +856,7 @@ static void switchover_timeout(unsigned long data) wake_up(&wq); } -static irqreturn_t tlclk_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t tlclk_interrupt(int irq, void *dev_id) { unsigned long flags; diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index ee7ac6f43c65..483f3f60013c 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -377,7 +377,7 @@ static struct tpm_vendor_specific tpm_tis = { .fops = &tis_ops,}, }; -static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t tis_int_probe(int irq, void *dev_id) { struct tpm_chip *chip = (struct tpm_chip *) dev_id; u32 interrupt; @@ -397,7 +397,7 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t tis_int_handler(int irq, void *dev_id) { struct tpm_chip *chip = (struct tpm_chip *) dev_id; u32 interrupt; diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index c2ca31eb850b..0cdbaa70cf9f 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -81,10 +81,10 @@ static int scc_ioctl(struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg); static void scc_throttle(struct tty_struct *tty); static void scc_unthrottle(struct tty_struct *tty); -static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp); -static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp); -static irqreturn_t scc_stat_int(int irq, void *data, struct pt_regs *fp); -static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp); +static irqreturn_t scc_tx_int(int irq, void *data); +static irqreturn_t scc_rx_int(int irq, void *data); +static irqreturn_t scc_stat_int(int irq, void *data); +static irqreturn_t scc_spcond_int(int irq, void *data); static void scc_setsignals(struct scc_port *port, int dtr, int rts); static void scc_break_ctl(struct tty_struct *tty, int break_state); @@ -419,7 +419,7 @@ module_init(vme_scc_init); * Interrupt handlers *--------------------------------------------------------------------------*/ -static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp) +static irqreturn_t scc_rx_int(int irq, void *data) { unsigned char ch; struct scc_port *port = data; @@ -440,7 +440,7 @@ static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp) */ if (SCCread(INT_PENDING_REG) & (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) { - scc_spcond_int (irq, data, fp); + scc_spcond_int (irq, data); return IRQ_HANDLED; } @@ -451,7 +451,7 @@ static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp) } -static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp) +static irqreturn_t scc_spcond_int(int irq, void *data) { struct scc_port *port = data; struct tty_struct *tty = port->gs.tty; @@ -496,7 +496,7 @@ static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp) } -static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp) +static irqreturn_t scc_tx_int(int irq, void *data) { struct scc_port *port = data; SCC_ACCESS_INIT(port); @@ -538,7 +538,7 @@ static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp) } -static irqreturn_t scc_stat_int(int irq, void *data, struct pt_regs *fp) +static irqreturn_t scc_stat_int(int irq, void *data) { struct scc_port *port = data; unsigned channel = port->channel; diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c index 8116a47b80f4..8e7949305171 100644 --- a/drivers/char/vr41xx_giu.c +++ b/drivers/char/vr41xx_giu.c @@ -221,7 +221,7 @@ static struct hw_interrupt_type giuint_high_irq_type = { .end = end_giuint_high_irq, }; -static int giu_get_irq(unsigned int irq, struct pt_regs *regs) +static int giu_get_irq(unsigned int irq) { uint16_t pendl, pendh, maskl, maskh; int i; diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c index 4f4269754c46..e228d6e173ce 100644 --- a/drivers/char/watchdog/eurotechwdt.c +++ b/drivers/char/watchdog/eurotechwdt.c @@ -153,7 +153,7 @@ static void eurwdt_activate_timer(void) * Kernel methods. */ -static irqreturn_t eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t eurwdt_interrupt(int irq, void *dev_id) { printk(KERN_CRIT "timeout WDT timeout\n"); diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index 02d336ace504..3404a9c67f08 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c @@ -64,7 +64,7 @@ MODULE_PARM_DESC(mpcore_noboot, "MPcore watchdog action, set to 1 to ignore rebo * This is the interrupt handler. Note that we only use this * in testing mode, so don't actually do a reboot here. */ -static irqreturn_t mpcore_wdt_fire(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t mpcore_wdt_fire(int irq, void *arg) { struct mpcore_wdt *wdt = arg; diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index 77662cb0ac46..bda45334d802 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c @@ -158,7 +158,7 @@ static struct usb_driver usb_pcwd_driver = { }; -static void usb_pcwd_intr_done(struct urb *urb, struct pt_regs *regs) +static void usb_pcwd_intr_done(struct urb *urb) { struct usb_pcwd_private *usb_pcwd = (struct usb_pcwd_private *)urb->context; unsigned char *data = usb_pcwd->intr_buffer; diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index b36a04ae9ab8..68b1ca976d53 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -336,8 +336,7 @@ static struct miscdevice s3c2410wdt_miscdev = { /* interrupt handler code */ -static irqreturn_t s3c2410wdt_irq(int irqno, void *param, - struct pt_regs *regs) +static irqreturn_t s3c2410wdt_irq(int irqno, void *param) { printk(KERN_INFO PFX "Watchdog timer expired!\n"); diff --git a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c index 13f23f4a2233..517fbd8643f8 100644 --- a/drivers/char/watchdog/wdt.c +++ b/drivers/char/watchdog/wdt.c @@ -225,14 +225,13 @@ static int wdt_get_temperature(int *temperature) * wdt_interrupt: * @irq: Interrupt number * @dev_id: Unused as we don't allow multiple devices. - * @regs: Unused. * * Handle an interrupt from the board. These are raised when the status * map changes in what the board considers an interesting way. That means * a failure condition occurring. */ -static irqreturn_t wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t wdt_interrupt(int irq, void *dev_id) { /* * Read the status register see what is up and diff --git a/drivers/char/watchdog/wdt285.c b/drivers/char/watchdog/wdt285.c index 89a249e23fde..e4cf661dc890 100644 --- a/drivers/char/watchdog/wdt285.c +++ b/drivers/char/watchdog/wdt285.c @@ -46,7 +46,7 @@ static unsigned long timer_alive; /* * If the timer expires.. */ -static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs) +static void watchdog_fire(int irq, void *dev_id) { printk(KERN_CRIT "Watchdog: Would Reboot.\n"); *CSR_TIMER4_CNTL = 0; diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c index 74d8cf836e13..ce1261c5cbce 100644 --- a/drivers/char/watchdog/wdt_pci.c +++ b/drivers/char/watchdog/wdt_pci.c @@ -270,14 +270,13 @@ static int wdtpci_get_temperature(int *temperature) * wdtpci_interrupt: * @irq: Interrupt number * @dev_id: Unused as we don't allow multiple devices. - * @regs: Unused. * * Handle an interrupt from the board. These are raised when the status * map changes in what the board considers an interesting way. That means * a failure condition occurring. */ -static irqreturn_t wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t wdtpci_interrupt(int irq, void *dev_id) { /* * Read the status register see what is up and diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c index dbd4d6c3698e..f3bf1e230bca 100644 --- a/drivers/dma/ioatdma.c +++ b/drivers/dma/ioatdma.c @@ -563,7 +563,7 @@ static struct pci_driver ioat_pci_drv = { .remove = __devexit_p(ioat_remove), }; -static irqreturn_t ioat_do_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t ioat_do_interrupt(int irq, void *data) { struct ioat_device *instance = data; unsigned long attnstatus; diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c index 3b07e0ca81cd..b09dfc78e5a2 100644 --- a/drivers/fc4/soc.c +++ b/drivers/fc4/soc.c @@ -334,7 +334,7 @@ update_out: } } -static irqreturn_t soc_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t soc_intr(int irq, void *dev_id) { u32 cmd; unsigned long flags; diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c index 2b75edc5859d..a6b1ae256e16 100644 --- a/drivers/fc4/socal.c +++ b/drivers/fc4/socal.c @@ -404,7 +404,7 @@ update_out: } } -static irqreturn_t socal_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t socal_intr(int irq, void *dev_id) { u32 cmd; unsigned long flags; diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index caa8e5c8bfbb..a591fe685f06 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -131,7 +131,7 @@ static void pcf_isa_waitforpin(void) { } -static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) { +static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) { spin_lock(&lock); pcf_pending = 1; spin_unlock(&lock); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 80d4ba1bdfec..781a99c1647a 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -320,7 +320,7 @@ err: /* * IIC interrupt handler */ -static irqreturn_t iic_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t iic_handler(int irq, void *dev_id) { struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id; volatile struct iic_regs __iomem *iic = dev->vaddr; diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 4436c89be58e..d108ab4974cc 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -120,7 +120,7 @@ iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap) * Then it passes the SR flags of interest to BH via adap data */ static irqreturn_t -iop3xx_i2c_irq_handler(int this_irq, void *dev_id, struct pt_regs *regs) +iop3xx_i2c_irq_handler(int this_irq, void *dev_id) { struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id; u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET); diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c index 559a62b04ee9..f7d71869b3b9 100644 --- a/drivers/i2c/busses/i2c-ite.c +++ b/drivers/i2c/busses/i2c-ite.c @@ -140,8 +140,7 @@ static void iic_ite_waitforpin(void) { } -static irqreturn_t iic_ite_handler(int this_irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t iic_ite_handler(int this_irq, void *dev_id) { spin_lock(&lock); iic_pending = 1; diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 155a986de516..ee65aa1be13a 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -63,7 +63,7 @@ static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x) writeb(x, i2c->base + MPC_I2C_CR); } -static irqreturn_t mpc_i2c_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mpc_i2c_isr(int irq, void *dev_id) { struct mpc_i2c *i2c = dev_id; if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) { diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index eacbaf745b64..bbc8e3a7ff55 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -278,7 +278,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) } static int -mv64xxx_i2c_intr(int irq, void *dev_id, struct pt_regs *regs) +mv64xxx_i2c_intr(int irq, void *dev_id) { struct mv64xxx_i2c_data *drv_data = dev_id; unsigned long flags; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 3e276e958ef7..f28a76d1c0af 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -143,7 +143,7 @@ static void ocores_process(struct ocores_i2c *i2c) } } -static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ocores_isr(int irq, void *dev_id) { struct ocores_i2c *i2c = dev_id; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 81d87d2c2a2d..dec04da0455c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -400,7 +400,7 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat) } static irqreturn_t -omap_i2c_rev1_isr(int this_irq, void *dev_id, struct pt_regs *regs) +omap_i2c_rev1_isr(int this_irq, void *dev_id) { struct omap_i2c_dev *dev = dev_id; u16 iv, w; @@ -452,7 +452,7 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id, struct pt_regs *regs) } static irqreturn_t -omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs) +omap_i2c_isr(int this_irq, void *dev_id) { struct omap_i2c_dev *dev = dev_id; u16 bits; diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index d9b4ddbad7e0..407840b6a260 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -99,7 +99,7 @@ static int pca_isa_waitforinterrupt(struct i2c_algo_pca_data *adap) return ret; } -static irqreturn_t pca_handler(int this_irq, void *dev_id, struct pt_regs *regs) { +static irqreturn_t pca_handler(int this_irq, void *dev_id) { wake_up_interruptible(&pca_wait); return IRQ_HANDLED; } diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index cd4ad98ad517..81050d3c9b21 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -850,7 +850,7 @@ static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr) ICR = icr; } -static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) { struct pxa_i2c *i2c = dev_id; u32 isr = ISR; diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c index 0ebec3c1a54e..8764df06f51d 100644 --- a/drivers/i2c/busses/i2c-rpx.c +++ b/drivers/i2c/busses/i2c-rpx.c @@ -55,10 +55,10 @@ rpx_iic_init(struct i2c_algo_8xx_data *data) data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c); } -static int rpx_install_isr(int irq, void (*func)(void *, void *), void *data) +static int rpx_install_isr(int irq, void (*func)(void *), void *data) { /* install interrupt handler */ - cpm_install_handler(irq, (void (*)(void *, struct pt_regs *)) func, data); + cpm_install_handler(irq, func, data); return 0; } diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 9ebe429a0a0f..4ca6de209b8b 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -423,8 +423,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) * top level IRQ servicing routine */ -static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id, - struct pt_regs *regs) +static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id) { struct s3c24xx_i2c *i2c = dev_id; unsigned long status; diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index 182f04953466..ccdf3e90862b 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -669,7 +669,7 @@ pulldown: dump_regs(isp, "otg->isp1301"); } -static irqreturn_t omap_otg_irq(int irq, void *_isp, struct pt_regs *regs) +static irqreturn_t omap_otg_irq(int irq, void *_isp) { u16 otg_irq = OTG_IRQ_SRC_REG; u32 otg_ctrl; @@ -1181,7 +1181,7 @@ isp1301_work(void *data) isp->working = 0; } -static irqreturn_t isp1301_irq(int irq, void *isp, struct pt_regs *regs) +static irqreturn_t isp1301_irq(int irq, void *isp) { isp1301_defer_work(isp, WORK_UPDATE_OTG); return IRQ_HANDLED; diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index 6a7578217177..60bef94cd25f 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -446,7 +446,7 @@ static void tps65010_work(void *_tps) mutex_unlock(&tps->lock); } -static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs) +static irqreturn_t tps65010_irq(int irq, void *_tps) { struct tps65010 *tps = _tps; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index ba6039b55b41..2614f41b5074 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -1562,7 +1562,7 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) * on the hwgroup and the process begins again. */ -irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t ide_intr (int irq, void *dev_id) { unsigned long flags; ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id; diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c index 4ab931145673..b1d5291531b7 100644 --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c @@ -673,7 +673,7 @@ static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo) * be forgotten about... */ -static irqreturn_t hd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t hd_interrupt(int irq, void *dev_id) { void (*handler)(void) = do_hd; diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c index d655da749144..b1730d7e414c 100644 --- a/drivers/ide/legacy/macide.c +++ b/drivers/ide/legacy/macide.c @@ -78,7 +78,7 @@ int macide_ack_intr(ide_hwif_t* hwif) } #ifdef CONFIG_BLK_DEV_MAC_MEDIABAY -static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void macide_mediabay_interrupt(int irq, void *dev_id) { int state = baboon->mb_status & 0x04; diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 8fd0030475ba..dea13525df88 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -2301,8 +2301,7 @@ static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci, spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); } -static irqreturn_t ohci_irq_handler(int irq, void *dev_id, - struct pt_regs *regs_are_unused) +static irqreturn_t ohci_irq_handler(int irq, void *dev_id) { quadlet_t event, node_id; struct ti_ohci *ohci = (struct ti_ohci *)dev_id; diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index b4f146f2c951..0a7412e27eb4 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -839,8 +839,7 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) ********************************************************/ -static irqreturn_t lynx_irq_handler(int irq, void *dev_id, - struct pt_regs *regs_are_unused) +static irqreturn_t lynx_irq_handler(int irq, void *dev_id) { struct ti_lynx *lynx = (struct ti_lynx *)dev_id; struct hpsb_host *host = lynx->host; diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index 9e9120f36019..dc1ebeac35c7 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -72,7 +72,7 @@ static int c2_down(struct net_device *netdev); static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev); static void c2_tx_interrupt(struct net_device *netdev); static void c2_rx_interrupt(struct net_device *netdev); -static irqreturn_t c2_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t c2_interrupt(int irq, void *dev_id); static void c2_tx_timeout(struct net_device *netdev); static int c2_change_mtu(struct net_device *netdev, int new_mtu); static void c2_reset(struct c2_port *c2_port); @@ -544,7 +544,7 @@ static void c2_rx_interrupt(struct net_device *netdev) /* * Handle netisr0 TX & RX interrupts. */ -static irqreturn_t c2_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t c2_interrupt(int irq, void *dev_id) { unsigned int netisr0, dmaisr; int handled = 0; diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 2a65b5be1979..048cc443d1e7 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -360,7 +360,7 @@ static inline void reset_eq_pending(struct ehca_cq *cq) return; } -irqreturn_t ehca_interrupt_neq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t ehca_interrupt_neq(int irq, void *dev_id) { struct ehca_shca *shca = (struct ehca_shca*)dev_id; @@ -393,7 +393,7 @@ void ehca_tasklet_neq(unsigned long data) return; } -irqreturn_t ehca_interrupt_eq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t ehca_interrupt_eq(int irq, void *dev_id) { struct ehca_shca *shca = (struct ehca_shca*)dev_id; diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h index 85bf1fe16fe4..be579cc0adf6 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.h +++ b/drivers/infiniband/hw/ehca/ehca_irq.h @@ -51,10 +51,10 @@ struct ehca_shca; int ehca_error_data(struct ehca_shca *shca, void *data, u64 resource); -irqreturn_t ehca_interrupt_neq(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t ehca_interrupt_neq(int irq, void *dev_id); void ehca_tasklet_neq(unsigned long data); -irqreturn_t ehca_interrupt_eq(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t ehca_interrupt_eq(int irq, void *dev_id); void ehca_tasklet_eq(unsigned long data); struct ehca_cpu_comp_task { diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 6bee53ce5f33..d9079ee12030 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -839,7 +839,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) } } -irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs) +irqreturn_t ipath_intr(int irq, void *data) { struct ipath_devdata *dd = data; u32 istat, chk0rcv = 0; diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index d7540b71b451..7c436697d0e4 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -606,7 +606,7 @@ struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd, gfp_t); extern int ipath_diag_inuse; -irqreturn_t ipath_intr(int irq, void *devid, struct pt_regs *regs); +irqreturn_t ipath_intr(int irq, void *devid); void ipath_decode_err(char *buf, size_t blen, ipath_err_t err); #if __IPATH_INFO || __IPATH_DBG extern const char *ipath_ibcstatus_str[]; diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index a29b1b6d82b1..e284e0613a94 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -405,7 +405,7 @@ static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq) return eqes_found; } -static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr, struct pt_regs *regs) +static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr) { struct mthca_dev *dev = dev_ptr; u32 ecr; @@ -432,8 +432,7 @@ static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr, struct pt_regs return IRQ_HANDLED; } -static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr, - struct pt_regs *regs) +static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr) { struct mthca_eq *eq = eq_ptr; struct mthca_dev *dev = eq->dev; @@ -446,7 +445,7 @@ static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr, return IRQ_HANDLED; } -static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr, struct pt_regs *regs) +static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr) { struct mthca_dev *dev = dev_ptr; int work = 0; @@ -467,8 +466,7 @@ static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr, struct pt_regs return IRQ_RETVAL(work); } -static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr, - struct pt_regs *regs) +static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr) { struct mthca_eq *eq = eq_ptr; struct mthca_dev *dev = eq->dev; diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index 7249d324297b..650acf3a30b7 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -57,7 +57,7 @@ static DEFINE_MUTEX(amijoy_mutex); static struct input_dev *amijoy_dev[2]; static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; -static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t amijoy_interrupt(int irq, void *dummy) { int i, data = 0, button = 0; @@ -69,8 +69,6 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp) case 1: data = ~amiga_custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break; } - input_regs(amijoy_dev[i], fp); - input_report_key(amijoy_dev[i], BTN_TRIGGER, button); input_report_abs(amijoy_dev[i], ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1)); diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 8632d47a7fbe..808f05932a6f 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -155,7 +155,7 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) return -1; } -void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs) +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) { struct input_dev *dev = iforce->dev; int i; @@ -183,9 +183,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, case 0x01: /* joystick position data */ case 0x03: /* wheel position data */ - - input_regs(dev, regs); - if (HI(cmd) == 1) { input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); @@ -224,7 +221,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, break; case 0x02: /* status report */ - input_regs(dev, regs); input_report_key(dev, BTN_DEAD, data[0] & 0x02); input_sync(dev); diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 64a78c515484..ca08f45c2040 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -81,7 +81,7 @@ static void iforce_serio_write_wakeup(struct serio *serio) } static irqreturn_t iforce_serio_irq(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct iforce *iforce = serio_get_drvdata(serio); @@ -115,7 +115,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, } if (iforce->idx == iforce->len) { - iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data, regs); + iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); iforce->pkt = 0; iforce->id = 0; iforce->len = 0; diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index fe79d158456d..105112fb7b57 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -74,7 +74,7 @@ void iforce_usb_xmit(struct iforce *iforce) spin_unlock_irqrestore(&iforce->xmit_lock, flags); } -static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs) +static void iforce_usb_irq(struct urb *urb) { struct iforce *iforce = urb->context; int status; @@ -96,7 +96,7 @@ static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs) } iforce_process_packet(iforce, - (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1, regs); + (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); exit: status = usb_submit_urb (urb, GFP_ATOMIC); @@ -105,7 +105,7 @@ exit: __FUNCTION__, status); } -static void iforce_usb_out(struct urb *urb, struct pt_regs *regs) +static void iforce_usb_out(struct urb *urb) { struct iforce *iforce = urb->context; @@ -119,7 +119,7 @@ static void iforce_usb_out(struct urb *urb, struct pt_regs *regs) wake_up(&iforce->wait); } -static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs) +static void iforce_usb_ctrl(struct urb *urb) { struct iforce *iforce = urb->context; if (urb->status) return; diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 947df2739843..ffaeaefa1a42 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -160,7 +160,7 @@ void iforce_delete_device(struct iforce *iforce); /* iforce-packets.c */ int iforce_control_playback(struct iforce*, u16 id, unsigned int); -void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs); +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; int iforce_get_id_packet(struct iforce *iforce, char *packet); diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index 168b1061a03b..e3d19444ba2e 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c @@ -82,7 +82,7 @@ static int magellan_crunch_nibbles(unsigned char *data, int count) return 0; } -static void magellan_process_packet(struct magellan* magellan, struct pt_regs *regs) +static void magellan_process_packet(struct magellan* magellan) { struct input_dev *dev = magellan->dev; unsigned char *data = magellan->data; @@ -90,8 +90,6 @@ static void magellan_process_packet(struct magellan* magellan, struct pt_regs *r if (!magellan->idx) return; - input_regs(dev, regs); - switch (magellan->data[0]) { case 'd': /* Axis data */ @@ -115,12 +113,12 @@ static void magellan_process_packet(struct magellan* magellan, struct pt_regs *r } static irqreturn_t magellan_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct magellan* magellan = serio_get_drvdata(serio); if (data == '\r') { - magellan_process_packet(magellan, regs); + magellan_process_packet(magellan); magellan->idx = 0; } else { if (magellan->idx < MAGELLAN_MAX_LENGTH) diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index 7a19ee052972..2a9808cf826f 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -82,7 +82,7 @@ struct spaceball { * SpaceBall. */ -static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs *regs) +static void spaceball_process_packet(struct spaceball* spaceball) { struct input_dev *dev = spaceball->dev; unsigned char *data = spaceball->data; @@ -90,8 +90,6 @@ static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs if (spaceball->idx < 2) return; - input_regs(dev, regs); - switch (spaceball->data[0]) { case 'D': /* Ball data */ @@ -151,13 +149,13 @@ static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs */ static irqreturn_t spaceball_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct spaceball *spaceball = serio_get_drvdata(serio); switch (data) { case 0xd: - spaceball_process_packet(spaceball, regs); + spaceball_process_packet(spaceball); spaceball->idx = 0; spaceball->escape = 0; break; diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index 3e2782e79834..c4db0247c5fb 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c @@ -74,7 +74,7 @@ static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive * SpaceOrb. */ -static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *regs) +static void spaceorb_process_packet(struct spaceorb *spaceorb) { struct input_dev *dev = spaceorb->dev; unsigned char *data = spaceorb->data; @@ -86,8 +86,6 @@ static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *r for (i = 0; i < spaceorb->idx; i++) c ^= data[i]; if (c) return; - input_regs(dev, regs); - switch (data[0]) { case 'R': /* Reset packet */ @@ -131,12 +129,12 @@ static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *r } static irqreturn_t spaceorb_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct spaceorb* spaceorb = serio_get_drvdata(serio); if (~data & 0x80) { - if (spaceorb->idx) spaceorb_process_packet(spaceorb, regs); + if (spaceorb->idx) spaceorb_process_packet(spaceorb); spaceorb->idx = 0; } if (spaceorb->idx < SPACEORB_MAX_LENGTH) diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index 011ec4858e15..1ffb03223311 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c @@ -64,15 +64,13 @@ struct stinger { * Stinger. It updates the data accordingly. */ -static void stinger_process_packet(struct stinger *stinger, struct pt_regs *regs) +static void stinger_process_packet(struct stinger *stinger) { struct input_dev *dev = stinger->dev; unsigned char *data = stinger->data; if (!stinger->idx) return; - input_regs(dev, regs); - input_report_key(dev, BTN_A, ((data[0] & 0x20) >> 5)); input_report_key(dev, BTN_B, ((data[0] & 0x10) >> 4)); input_report_key(dev, BTN_C, ((data[0] & 0x08) >> 3)); @@ -99,7 +97,7 @@ static void stinger_process_packet(struct stinger *stinger, struct pt_regs *regs */ static irqreturn_t stinger_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct stinger *stinger = serio_get_drvdata(serio); @@ -109,7 +107,7 @@ static irqreturn_t stinger_interrupt(struct serio *serio, stinger->data[stinger->idx++] = data; if (stinger->idx == 4) { - stinger_process_packet(stinger, regs); + stinger_process_packet(stinger); stinger->idx = 0; } diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index 076f237d9654..49085df2d631 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c @@ -104,7 +104,7 @@ struct twidjoy { * Twiddler. It updates the data accordingly. */ -static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs) +static void twidjoy_process_packet(struct twidjoy *twidjoy) { struct input_dev *dev = twidjoy->dev; unsigned char *data = twidjoy->data; @@ -113,8 +113,6 @@ static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f); - input_regs(dev, regs); - for (bp = twidjoy_buttons; bp->bitmask; bp++) { int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift; int i; @@ -141,7 +139,7 @@ static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs * packet processing routine. */ -static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs) +static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { struct twidjoy *twidjoy = serio_get_drvdata(serio); @@ -158,7 +156,7 @@ static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, un twidjoy->data[twidjoy->idx++] = data; if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { - twidjoy_process_packet(twidjoy, regs); + twidjoy_process_packet(twidjoy); twidjoy->idx = 0; } diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index f9c1a03214eb..35edea1ab955 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c @@ -64,15 +64,13 @@ struct warrior { * Warrior. It updates the data accordingly. */ -static void warrior_process_packet(struct warrior *warrior, struct pt_regs *regs) +static void warrior_process_packet(struct warrior *warrior) { struct input_dev *dev = warrior->dev; unsigned char *data = warrior->data; if (!warrior->idx) return; - input_regs(dev, regs); - switch ((data[0] >> 4) & 7) { case 1: /* Button data */ input_report_key(dev, BTN_TRIGGER, data[3] & 1); @@ -101,12 +99,12 @@ static void warrior_process_packet(struct warrior *warrior, struct pt_regs *regs */ static irqreturn_t warrior_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct warrior *warrior = serio_get_drvdata(serio); if (data & 0x80) { - if (warrior->idx) warrior_process_packet(warrior, regs); + if (warrior->idx) warrior_process_packet(warrior); warrior->idx = 0; warrior->len = warrior_lengths[(data >> 4) & 7]; } @@ -115,7 +113,7 @@ static irqreturn_t warrior_interrupt(struct serio *serio, warrior->data[warrior->idx++] = data; if (warrior->idx == warrior->len) { - if (warrior->idx) warrior_process_packet(warrior, regs); + if (warrior->idx) warrior_process_packet(warrior); warrior->idx = 0; warrior->len = 0; } diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index f1f9db9d282c..8abdbd0ee8f9 100644 --- a/drivers/input/keyboard/amikbd.c +++ b/drivers/input/keyboard/amikbd.c @@ -158,7 +158,7 @@ static const char *amikbd_messages[8] = { static struct input_dev *amikbd_dev; -static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t amikbd_interrupt(int irq, void *dummy) { unsigned char scancode, down; @@ -171,8 +171,6 @@ static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) scancode >>= 1; if (scancode < 0x78) { /* scancodes < 0x78 are keys */ - input_regs(amikbd_dev, fp); - if (scancode == 98) { /* CapsLock is a toggle switch key on Amiga */ input_report_key(amikbd_dev, scancode, 1); input_report_key(amikbd_dev, scancode, 0); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 40244d4ce0f1..b6ef9eaad1dc 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -318,7 +318,7 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code */ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, - unsigned int flags, struct pt_regs *regs) + unsigned int flags) { struct atkbd *atkbd = serio_get_drvdata(serio); struct input_dev *dev = atkbd->dev; @@ -458,7 +458,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2; } - input_regs(dev, regs); input_event(dev, EV_KEY, keycode, value); input_sync(dev); @@ -469,7 +468,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, } if (atkbd->scroll) { - input_regs(dev, regs); if (click != -1) input_report_key(dev, BTN_MIDDLE, click); input_report_rel(dev, REL_WHEEL, scroll); diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 1e03153b9bca..cb70970625b5 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -129,7 +129,7 @@ static inline void corgikbd_reset_col(int col) */ /* Scan the hardware keyboard and push any changes up through the input layer */ -static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs) +static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data) { unsigned int row, col, rowd; unsigned long flags; @@ -140,9 +140,6 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs spin_lock_irqsave(&corgikbd_data->lock, flags); - if (regs) - input_regs(corgikbd_data->input, regs); - num_pressed = 0; for (col = 0; col < KB_COLS; col++) { /* @@ -191,14 +188,14 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs /* * corgi keyboard interrupt handler. */ -static irqreturn_t corgikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t corgikbd_interrupt(int irq, void *dev_id) { struct corgikbd *corgikbd_data = dev_id; if (!timer_pending(&corgikbd_data->timer)) { /** wait chattering delay **/ udelay(20); - corgikbd_scankeyboard(corgikbd_data, regs); + corgikbd_scankeyboard(corgikbd_data); } return IRQ_HANDLED; diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index 2e4abdc26367..c9b0b8978cd8 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -198,7 +198,7 @@ static void hil_kbd_process_err(struct hil_kbd *kbd) { } static irqreturn_t hil_kbd_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct hil_kbd *kbd; hil_packet packet; diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index d22c7c624296..54bc569db4b0 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -150,7 +150,7 @@ static inline void handle_data(unsigned char s, unsigned char c) /* * Handle HIL interrupts. */ -static irqreturn_t hil_interrupt(int irq, void *handle, struct pt_regs *regs) +static irqreturn_t hil_interrupt(int irq, void *handle) { unsigned char s, c; diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 5174224cadb4..708d5a1bc3d2 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -453,8 +453,7 @@ lkkbd_detection_done (struct lkkbd *lk) * is received. */ static irqreturn_t -lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, - struct pt_regs *regs) +lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags) { struct lkkbd *lk = serio_get_drvdata (serio); int i; @@ -473,7 +472,6 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, switch (data) { case LK_ALL_KEYS_UP: - input_regs (lk->dev, regs); for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) if (lk->keycode[i] != KEY_RESERVED) input_report_key (lk->dev, lk->keycode[i], 0); @@ -501,7 +499,6 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, default: if (lk->keycode[data] != KEY_RESERVED) { - input_regs (lk->dev, regs); if (!test_bit (lk->keycode[data], lk->dev->key)) input_report_key (lk->dev, lk->keycode[data], 1); else diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index 83906f80ba21..fd33c9cc3272 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -126,7 +126,7 @@ static inline void locomokbd_reset_col(unsigned long membase, int col) */ /* Scan the hardware keyboard and push any changes up through the input layer */ -static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs) +static void locomokbd_scankeyboard(struct locomokbd *locomokbd) { unsigned int row, col, rowd, scancode; unsigned long flags; @@ -135,8 +135,6 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs * spin_lock_irqsave(&locomokbd->lock, flags); - input_regs(locomokbd->input, regs); - locomokbd_charge_all(membase); num_pressed = 0; @@ -171,13 +169,13 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs * /* * LoCoMo keyboard interrupt handler. */ -static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t locomokbd_interrupt(int irq, void *dev_id) { struct locomokbd *locomokbd = dev_id; /** wait chattering delay **/ udelay(100); - locomokbd_scankeyboard(locomokbd, regs); + locomokbd_scankeyboard(locomokbd); return IRQ_HANDLED; } diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c index 40a3f551247e..9282e4e082bd 100644 --- a/drivers/input/keyboard/newtonkbd.c +++ b/drivers/input/keyboard/newtonkbd.c @@ -65,13 +65,12 @@ struct nkbd { }; static irqreturn_t nkbd_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct nkbd *nkbd = serio_get_drvdata(serio); /* invalid scan codes are probably the init sequence, so we ignore them */ if (nkbd->keycode[data & NKBD_KEY]) { - input_regs(nkbd->dev, regs); input_report_key(nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS); input_sync(nkbd->dev); } diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index d436287d1d2e..5680a6d95b2b 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -97,8 +97,7 @@ static u8 get_row_gpio_val(struct omap_kp *omap_kp) #define get_row_gpio_val(x) 0 #endif -static irqreturn_t omap_kp_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t omap_kp_interrupt(int irq, void *dev_id) { struct omap_kp *omap_kp = dev_id; diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index e385710233f4..8b18c009e3e0 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -176,7 +176,7 @@ static inline int spitzkbd_get_row_status(int col) */ /* Scan the hardware keyboard and push any changes up through the input layer */ -static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs *regs) +static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data) { unsigned int row, col, rowd; unsigned long flags; @@ -187,8 +187,6 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs spin_lock_irqsave(&spitzkbd_data->lock, flags); - input_regs(spitzkbd_data->input, regs); - num_pressed = 0; for (col = 0; col < KB_COLS; col++) { /* @@ -239,14 +237,14 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs /* * spitz keyboard interrupt handler. */ -static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id) { struct spitzkbd *spitzkbd_data = dev_id; if (!timer_pending(&spitzkbd_data->timer)) { /** wait chattering delay **/ udelay(20); - spitzkbd_scankeyboard(spitzkbd_data, regs); + spitzkbd_scankeyboard(spitzkbd_data); } return IRQ_HANDLED; @@ -267,7 +265,7 @@ static void spitzkbd_timer_callback(unsigned long data) * We debounce the switches and pass them to the input system. */ -static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id) { struct spitzkbd *spitzkbd_data = dev_id; diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c index 04c54c57f25c..e60937d17b1c 100644 --- a/drivers/input/keyboard/stowaway.c +++ b/drivers/input/keyboard/stowaway.c @@ -71,13 +71,12 @@ struct skbd { }; static irqreturn_t skbd_interrupt(struct serio *serio, unsigned char data, - unsigned int flags, struct pt_regs *regs) + unsigned int flags) { struct skbd *skbd = serio_get_drvdata(serio); struct input_dev *dev = skbd->dev; if (skbd->keycode[data & SKBD_KEY_MASK]) { - input_regs(dev, regs); input_report_key(dev, skbd->keycode[data & SKBD_KEY_MASK], !(data & SKBD_RELEASE)); input_sync(dev); diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 9dbd7b85686d..cac4781103c3 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -94,7 +94,7 @@ struct sunkbd { */ static irqreturn_t sunkbd_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct sunkbd* sunkbd = serio_get_drvdata(serio); @@ -129,7 +129,6 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio, break; if (sunkbd->keycode[data & SUNKBD_KEY]) { - input_regs(sunkbd->dev, regs); input_report_key(sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); input_sync(sunkbd->dev); } else { diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index 0821d53cf0c1..8c11dc935454 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -64,7 +64,7 @@ struct xtkbd { }; static irqreturn_t xtkbd_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct xtkbd *xtkbd = serio_get_drvdata(serio); @@ -75,7 +75,6 @@ static irqreturn_t xtkbd_interrupt(struct serio *serio, default: if (xtkbd->keycode[data & XTKBD_KEY]) { - input_regs(xtkbd->dev, regs); input_report_key(xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); input_sync(xtkbd->dev); } else { diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index 805b636e73d9..105c6fc27823 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -79,7 +79,7 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned return 0; } -static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id) { /* clear interrupt */ *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND; diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 450b68a619fd..4e71a66fc7fc 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -76,7 +76,7 @@ static const struct alps_model_info alps_model_data[] = { * on a dualpoint, etc. */ -static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) +static void alps_process_packet(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; unsigned char *packet = psmouse->packet; @@ -85,8 +85,6 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) int x, y, z, ges, fin, left, right, middle; int back = 0, forward = 0; - input_regs(dev, regs); - if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */ input_report_key(dev2, BTN_LEFT, packet[0] & 1); input_report_key(dev2, BTN_RIGHT, packet[0] & 2); @@ -181,13 +179,13 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) input_sync(dev); } -static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs) +static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ if (psmouse->pktcnt == 3) { - alps_process_packet(psmouse, regs); + alps_process_packet(psmouse); return PSMOUSE_FULL_PACKET; } return PSMOUSE_GOOD_DATA; @@ -202,7 +200,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs * return PSMOUSE_BAD_DATA; if (psmouse->pktcnt == 6) { - alps_process_packet(psmouse, regs); + alps_process_packet(psmouse); return PSMOUSE_FULL_PACKET; } diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c index c8b2cc9f184c..599a7b2dc519 100644 --- a/drivers/input/mouse/amimouse.c +++ b/drivers/input/mouse/amimouse.c @@ -36,7 +36,7 @@ MODULE_LICENSE("GPL"); static int amimouse_lastx, amimouse_lasty; static struct input_dev *amimouse_dev; -static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t amimouse_interrupt(int irq, void *dummy) { unsigned short joy0dat, potgor; int nx, ny, dx, dy; @@ -59,8 +59,6 @@ static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp) potgor = amiga_custom.potgor; - input_regs(amimouse_dev, fp); - input_report_rel(amimouse_dev, REL_X, dx); input_report_rel(amimouse_dev, REL_Y, dy); diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c index 69f02178c528..402b057e986e 100644 --- a/drivers/input/mouse/hil_ptr.c +++ b/drivers/input/mouse/hil_ptr.c @@ -190,7 +190,7 @@ static void hil_ptr_process_err(struct hil_ptr *ptr) { } static irqreturn_t hil_ptr_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct hil_ptr *ptr; hil_packet packet; diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c index 50f1fed10be4..e1252fa9a107 100644 --- a/drivers/input/mouse/inport.c +++ b/drivers/input/mouse/inport.c @@ -88,15 +88,13 @@ __obsolete_setup("inport_irq="); static struct input_dev *inport_dev; -static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t inport_interrupt(int irq, void *dev_id) { unsigned char buttons; outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); - input_regs(inport_dev, regs); - outb(INPORT_REG_X, INPORT_CONTROL_PORT); input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT)); diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 5e9d25067513..c57e8853b949 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -62,7 +62,7 @@ static struct dmi_system_id lifebook_dmi_table[] = { }; -static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs) +static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) { unsigned char *packet = psmouse->packet; struct input_dev *dev = psmouse->dev; @@ -70,8 +70,6 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_re if (psmouse->pktcnt != 3) return PSMOUSE_GOOD_DATA; - input_regs(dev, regs); - /* calculate X and Y */ if ((packet[0] & 0x08) == 0x00) { input_report_abs(dev, ABS_X, diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c index 9c7ce38806d7..8e9c2f3d69a8 100644 --- a/drivers/input/mouse/logibm.c +++ b/drivers/input/mouse/logibm.c @@ -79,7 +79,7 @@ __obsolete_setup("logibm_irq="); static struct input_dev *logibm_dev; -static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t logibm_interrupt(int irq, void *dev_id) { char dx, dy; unsigned char buttons; @@ -95,7 +95,6 @@ static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs) dy |= (buttons & 0xf) << 4; buttons = ~buttons >> 5; - input_regs(logibm_dev, regs); input_report_rel(logibm_dev, REL_X, dx); input_report_rel(logibm_dev, REL_Y, dy); input_report_key(logibm_dev, BTN_RIGHT, buttons & 1); diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 7972eecbcfe4..8a4f862709e7 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -39,7 +39,7 @@ struct ps2pp_info { * Process a PS2++ or PS2T++ packet. */ -static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse, struct pt_regs *regs) +static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; unsigned char *packet = psmouse->packet; @@ -51,8 +51,6 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse, struct pt_regs * Full packet accumulated, process it */ - input_regs(dev, regs); - if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) { /* Logitech extended packet */ diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c index d284ea712151..8c075aa7223b 100644 --- a/drivers/input/mouse/pc110pad.c +++ b/drivers/input/mouse/pc110pad.c @@ -57,7 +57,7 @@ static struct input_dev *pc110pad_dev; static int pc110pad_data[3]; static int pc110pad_count; -static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t pc110pad_interrupt(int irq, void *ptr) { int value = inb_p(pc110pad_io); int handshake = inb_p(pc110pad_io + 2); @@ -71,7 +71,6 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs) if (pc110pad_count < 3) return IRQ_HANDLED; - input_regs(pc110pad_dev, regs); input_report_key(pc110pad_dev, BTN_TOUCH, pc110pad_data[0] & 0x01); input_report_abs(pc110pad_dev, ABS_X, @@ -91,9 +90,9 @@ static void pc110pad_close(struct input_dev *dev) static int pc110pad_open(struct input_dev *dev) { - pc110pad_interrupt(0, NULL, NULL); - pc110pad_interrupt(0, NULL, NULL); - pc110pad_interrupt(0, NULL, NULL); + pc110pad_interrupt(0, NULL); + pc110pad_interrupt(0, NULL); + pc110pad_interrupt(0, NULL); outb(PC110PAD_ON, pc110pad_io + 2); pc110pad_count = 0; diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 9fb7eb6b0f71..6f9b2c7cc9c2 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -124,7 +124,7 @@ struct psmouse_protocol { * relevant events to the input module once full packet has arrived. */ -static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs) +static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; unsigned char *packet = psmouse->packet; @@ -136,8 +136,6 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_reg * Full packet accumulated, process it */ - input_regs(dev, regs); - /* * Scroll wheel on IntelliMice, scroll buttons on NetMice */ @@ -231,9 +229,9 @@ static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_st * by calling corresponding protocol handler. */ -static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs) +static int psmouse_handle_byte(struct psmouse *psmouse) { - psmouse_ret_t rc = psmouse->protocol_handler(psmouse, regs); + psmouse_ret_t rc = psmouse->protocol_handler(psmouse); switch (rc) { case PSMOUSE_BAD_DATA: @@ -271,7 +269,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs) */ static irqreturn_t psmouse_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct psmouse *psmouse = serio_get_drvdata(serio); @@ -327,7 +325,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, * Not a new device, try processing first byte normally */ psmouse->pktcnt = 1; - if (psmouse_handle_byte(psmouse, regs)) + if (psmouse_handle_byte(psmouse)) goto out; psmouse->packet[psmouse->pktcnt++] = data; @@ -346,7 +344,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, } psmouse->last = jiffies; - psmouse_handle_byte(psmouse, regs); + psmouse_handle_byte(psmouse); out: return IRQ_HANDLED; @@ -940,7 +938,7 @@ static void psmouse_resync(void *p) psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); for (i = 0; i < psmouse->pktsize; i++) { psmouse->pktcnt++; - rc = psmouse->protocol_handler(psmouse, NULL); + rc = psmouse->protocol_handler(psmouse); if (rc != PSMOUSE_GOOD_DATA) break; } diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 4d9107fba6a1..1b74cae8a556 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -62,7 +62,7 @@ struct psmouse { unsigned int resync_time; unsigned int smartscroll; /* Logitech only */ - psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); + psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse); void (*set_rate)(struct psmouse *psmouse, unsigned int rate); void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution); diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c index 872b30bf7aad..ea0468569610 100644 --- a/drivers/input/mouse/rpcmouse.c +++ b/drivers/input/mouse/rpcmouse.c @@ -36,7 +36,7 @@ MODULE_LICENSE("GPL"); static short rpcmouse_lastx, rpcmouse_lasty; static struct input_dev *rpcmouse_dev; -static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t rpcmouse_irq(int irq, void *dev_id) { struct input_dev *dev = dev_id; short x, y, dx, dy, b; @@ -51,8 +51,6 @@ static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs) rpcmouse_lastx = x; rpcmouse_lasty = y; - input_regs(dev, regs); - input_report_rel(dev, REL_X, dx); input_report_rel(dev, REL_Y, -dy); diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index 680b32353884..2a272c5daf08 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c @@ -61,13 +61,11 @@ struct sermouse { * second, which is as good as a PS/2 or USB mouse. */ -static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs) +static void sermouse_process_msc(struct sermouse *sermouse, signed char data) { struct input_dev *dev = sermouse->dev; signed char *buf = sermouse->buf; - input_regs(dev, regs); - switch (sermouse->count) { case 0: @@ -104,15 +102,13 @@ static void sermouse_process_msc(struct sermouse *sermouse, signed char data, st * standard 3-byte packets and 1200 bps. */ -static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs) +static void sermouse_process_ms(struct sermouse *sermouse, signed char data) { struct input_dev *dev = sermouse->dev; signed char *buf = sermouse->buf; if (data & 0x40) sermouse->count = 0; - input_regs(dev, regs); - switch (sermouse->count) { case 0: @@ -206,7 +202,7 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data, str */ static irqreturn_t sermouse_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct sermouse *sermouse = serio_get_drvdata(serio); @@ -214,9 +210,9 @@ static irqreturn_t sermouse_interrupt(struct serio *serio, sermouse->last = jiffies; if (sermouse->type > SERIO_SUN) - sermouse_process_ms(sermouse, data, regs); + sermouse_process_ms(sermouse, data); else - sermouse_process_msc(sermouse, data, regs); + sermouse_process_msc(sermouse, data); return IRQ_HANDLED; } diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 392108c436ba..49ac696d6cff 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -216,13 +216,13 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet struct psmouse *child = serio_get_drvdata(ptport); if (child && child->state == PSMOUSE_ACTIVATED) { - serio_interrupt(ptport, packet[1], 0, NULL); - serio_interrupt(ptport, packet[4], 0, NULL); - serio_interrupt(ptport, packet[5], 0, NULL); + serio_interrupt(ptport, packet[1], 0); + serio_interrupt(ptport, packet[4], 0); + serio_interrupt(ptport, packet[5], 0); if (child->pktsize == 4) - serio_interrupt(ptport, packet[2], 0, NULL); + serio_interrupt(ptport, packet[2], 0); } else - serio_interrupt(ptport, packet[1], 0, NULL); + serio_interrupt(ptport, packet[1], 0); } static void synaptics_pt_activate(struct psmouse *psmouse) @@ -469,13 +469,10 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) return SYN_NEWABS_STRICT; } -static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) +static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) { - struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; - input_regs(dev, regs); - if (psmouse->pktcnt >= 6) { /* Full packet received */ if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index 47edcfd022ba..ffdb50eee93d 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -211,7 +211,7 @@ vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t le } static void -vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) +vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse) { struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; @@ -258,7 +258,6 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) /* * Report what we've found so far... */ - input_regs (dev, regs); input_report_key (dev, BTN_LEFT, left); input_report_key (dev, BTN_MIDDLE, middle); input_report_key (dev, BTN_RIGHT, right); @@ -269,7 +268,7 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) } static void -vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) +vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse) { struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; @@ -312,7 +311,6 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) /* * Report what we've found so far... */ - input_regs (dev, regs); input_report_key (dev, BTN_LEFT, left); input_report_key (dev, BTN_MIDDLE, middle); input_report_key (dev, BTN_RIGHT, right); @@ -323,7 +321,7 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) } static void -vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) +vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse) { struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; @@ -367,7 +365,6 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) if (error <= 0x1f) { /* No (serious) error. Report buttons */ - input_regs (dev, regs); input_report_key (dev, BTN_LEFT, left); input_report_key (dev, BTN_MIDDLE, middle); input_report_key (dev, BTN_RIGHT, right); @@ -395,7 +392,7 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) } static void -vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs) +vsxxxaa_parse_buffer (struct vsxxxaa *mouse) { unsigned char *buf = mouse->buf; int stray_bytes; @@ -432,7 +429,7 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs) continue; } - vsxxxaa_handle_REL_packet (mouse, regs); + vsxxxaa_handle_REL_packet (mouse); continue; /* More to parse? */ } @@ -446,7 +443,7 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs) continue; } - vsxxxaa_handle_ABS_packet (mouse, regs); + vsxxxaa_handle_ABS_packet (mouse); continue; /* More to parse? */ } @@ -460,7 +457,7 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs) continue; } - vsxxxaa_handle_POR_packet (mouse, regs); + vsxxxaa_handle_POR_packet (mouse); continue; /* More to parse? */ } @@ -469,13 +466,12 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs) } static irqreturn_t -vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags, - struct pt_regs *regs) +vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags) { struct vsxxxaa *mouse = serio_get_drvdata (serio); vsxxxaa_queue_byte (mouse, data); - vsxxxaa_parse_buffer (mouse, regs); + vsxxxaa_parse_buffer (mouse); return IRQ_HANDLED; } diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 3df5eedf8f31..5a7b49c35539 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -37,14 +37,14 @@ struct amba_kmi_port { unsigned int open; }; -static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t amba_kmi_int(int irq, void *dev_id) { struct amba_kmi_port *kmi = dev_id; unsigned int status = readb(KMIIR); int handled = IRQ_NONE; while (status & KMIIR_RXINTR) { - serio_interrupt(kmi->io, readb(KMIDATA), 0, regs); + serio_interrupt(kmi->io, readb(KMIDATA), 0); status = readb(KMIIR); handled = IRQ_HANDLED; } diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index bc6e87add093..0d35018c23a9 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -71,9 +71,9 @@ static struct resource ct82c710_iores; * is waiting in the 82C710. */ -static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) +static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id) { - return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0, regs); + return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0); } /* diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index cde036a92168..081fdc3c7737 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -82,7 +82,7 @@ MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); #define GSC_ID_MOUSE 1 -static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs); +static irqreturn_t gscps2_interrupt(int irq, void *dev); #define BUFFER_SIZE 0x0f @@ -226,7 +226,7 @@ static LIST_HEAD(ps2port_list); * later. */ -static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t gscps2_interrupt(int irq, void *dev) { struct gscps2port *ps2port; @@ -267,7 +267,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); - serio_interrupt(ps2port->port, data, rxflags, regs); + serio_interrupt(ps2port->port, data, rxflags); } /* while() */ diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index a10348bb25e9..ba7b920347e3 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -202,7 +202,7 @@ static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) { } } -static irqreturn_t hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) { +static irqreturn_t hp_sdc_isr(int irq, void *dev_id) { uint8_t status, data; status = hp_sdc_status_in8(); @@ -253,7 +253,7 @@ static irqreturn_t hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) { } -static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id, struct pt_regs * regs) { +static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) { int status; status = hp_sdc_status_in8(); diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 1bb0c76a9259..09b06e605b50 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -108,7 +108,7 @@ static unsigned char i8042_kbd_irq_registered; static unsigned char i8042_aux_irq_registered; static struct platform_device *i8042_platform_device; -static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t i8042_interrupt(int irq, void *dev_id); /* * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to @@ -271,7 +271,7 @@ static int i8042_aux_write(struct serio *serio, unsigned char c) * characters later. */ - i8042_interrupt(0, NULL, NULL); + i8042_interrupt(0, NULL); return retval; } @@ -309,7 +309,7 @@ static void i8042_stop(struct serio *serio) * to the upper layers. */ -static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t i8042_interrupt(int irq, void *dev_id) { struct i8042_port *port; unsigned long flags; @@ -379,7 +379,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) dfl & SERIO_TIMEOUT ? ", timeout" : ""); if (likely(port->exists)) - serio_interrupt(port->serio, data, dfl, regs); + serio_interrupt(port->serio, data, dfl); ret = 1; out: @@ -519,7 +519,7 @@ static int __devinit i8042_check_mux(void) static struct completion i8042_aux_irq_delivered __devinitdata; static int i8042_irq_being_tested __devinitdata; -static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id) { unsigned long flags; unsigned char str, data; @@ -905,7 +905,7 @@ static int i8042_resume(struct platform_device *dev) if (i8042_ports[I8042_KBD_PORT_NO].serio) i8042_enable_kbd_port(); - i8042_interrupt(0, NULL, NULL); + i8042_interrupt(0, NULL); return 0; } diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index f08a5d0cd5fa..558200e96d0f 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -72,8 +72,7 @@ static int maceps2_write(struct serio *dev, unsigned char val) return -1; } -static irqreturn_t maceps2_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t maceps2_interrupt(int irq, void *dev_id) { struct serio *dev = dev_id; struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; @@ -81,7 +80,7 @@ static irqreturn_t maceps2_interrupt(int irq, void *dev_id, if (port->status & PS2_STATUS_RX_FULL) { byte = port->rx; - serio_interrupt(dev, byte & 0xff, 0, regs); + serio_interrupt(dev, byte & 0xff, 0); } return IRQ_HANDLED; diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index a5c1fb3a4a51..688610e86a3e 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -102,7 +102,7 @@ static int parkbd_write(struct serio *port, unsigned char c) return 0; } -static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void parkbd_interrupt(int irq, void *dev_id) { if (parkbd_writing) { @@ -134,7 +134,7 @@ static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; if (parkbd_counter == parkbd_mode + 10) - serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); + serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0); } parkbd_last = jiffies; diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index fb727c665253..ea5e3c6ddb62 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -58,7 +58,7 @@ static int pcips2_write(struct serio *io, unsigned char val) return 0; } -static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t pcips2_interrupt(int irq, void *devid) { struct pcips2_data *ps2if = devid; unsigned char status, scancode; @@ -80,7 +80,7 @@ static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs) if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; - serio_interrupt(ps2if->io, scancode, flag, regs); + serio_interrupt(ps2if->io, scancode, flag); } while (1); return IRQ_RETVAL(handled); } diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index d3827c5fe119..cb89aff2e160 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -53,14 +53,14 @@ DEFINE_SPINLOCK(q40kbd_lock); static struct serio *q40kbd_port; static struct platform_device *q40kbd_device; -static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t q40kbd_interrupt(int irq, void *dev_id) { unsigned long flags; spin_lock_irqsave(&q40kbd_lock, flags); if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) - serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs); + serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0); master_outb(-1, KEYBOARD_UNLOCK_REG); diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index 513d37fc1acf..49f84315cb32 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -56,7 +56,7 @@ static int rpckbd_write(struct serio *port, unsigned char val) return 0; } -static irqreturn_t rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t rpckbd_rx(int irq, void *dev_id) { struct serio *port = dev_id; unsigned int byte; @@ -65,13 +65,13 @@ static irqreturn_t rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs) while (iomd_readb(IOMD_KCTRL) & (1 << 5)) { byte = iomd_readb(IOMD_KARTRX); - serio_interrupt(port, byte, 0, regs); + serio_interrupt(port, byte, 0); handled = IRQ_HANDLED; } return handled; } -static irqreturn_t rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t rpckbd_tx(int irq, void *dev_id) { return IRQ_HANDLED; } diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index ebd9976fc811..559508795af1 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -40,7 +40,7 @@ struct ps2if { * at the most one, but we loop for safety. If there was a * framing error, we have to manually clear the status. */ -static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ps2_rxint(int irq, void *dev_id) { struct ps2if *ps2if = dev_id; unsigned int scancode, flag, status; @@ -58,7 +58,7 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs) if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; - serio_interrupt(ps2if->io, scancode, flag, regs); + serio_interrupt(ps2if->io, scancode, flag); status = sa1111_readl(ps2if->base + SA1111_PS2STAT); } @@ -69,7 +69,7 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs) /* * Completion of ps2 write */ -static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ps2_txint(int irq, void *dev_id) { struct ps2if *ps2if = dev_id; unsigned int status; diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 3e76ad71c9a0..960fae3c3cea 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -911,7 +911,7 @@ void serio_close(struct serio *serio) } irqreturn_t serio_interrupt(struct serio *serio, - unsigned char data, unsigned int dfl, struct pt_regs *regs) + unsigned char data, unsigned int dfl) { unsigned long flags; irqreturn_t ret = IRQ_NONE; @@ -919,7 +919,7 @@ irqreturn_t serio_interrupt(struct serio *serio, spin_lock_irqsave(&serio->lock, flags); if (likely(serio->drv)) { - ret = serio->drv->interrupt(serio, data, dfl, regs); + ret = serio->drv->interrupt(serio, data, dfl); } else if (!dfl && serio->registered) { serio_rescan(serio); ret = IRQ_HANDLED; diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 71a8eea816cb..ba2a2035d648 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -250,7 +250,7 @@ static struct file_operations serio_raw_fops = { *********************************************************************/ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, - unsigned int dfl, struct pt_regs *regs) + unsigned int dfl) { struct serio_raw *serio_raw = serio_get_drvdata(serio); struct serio_raw_list *list; diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 54a680cc704d..e1a3a79ab3f9 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -117,9 +117,6 @@ static void serport_ldisc_close(struct tty_struct *tty) * serport_ldisc_receive() is called by the low level tty driver when characters * are ready for us. We forward the characters, one by one to the 'interrupt' * routine. - * - * FIXME: We should get pt_regs from the tty layer and forward them to - * serio_interrupt here. */ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) @@ -134,7 +131,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c goto out; for (i = 0; i < count; i++) - serio_interrupt(serport->serio, cp[i], 0, NULL); + serio_interrupt(serport->serio, cp[i], 0); out: spin_unlock_irqrestore(&serport->lock, flags); diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 66e411badf70..f56d6a0f0624 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -487,7 +487,7 @@ static void ads7846_timer(unsigned long handle) spin_unlock_irq(&ts->lock); } -static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) +static irqreturn_t ads7846_irq(int irq, void *handle) { struct ads7846 *ts = handle; unsigned long flags; diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 9b66271d3ba8..ca79b2246195 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -173,7 +173,7 @@ static int read_xydata(struct corgi_ts *corgi_ts) return 1; } -static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs) +static void new_data(struct corgi_ts *corgi_ts) { if (corgi_ts->power_mode != PWR_MODE_ACTIVE) return; @@ -181,7 +181,6 @@ static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs) if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0) return; - input_regs(corgi_ts->input, regs); input_report_abs(corgi_ts->input, ABS_X, corgi_ts->tc.x); input_report_abs(corgi_ts->input, ABS_Y, corgi_ts->tc.y); input_report_abs(corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure); @@ -189,14 +188,14 @@ static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs) input_sync(corgi_ts->input); } -static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs) +static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer) { if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) { /* Disable Interrupt */ set_irq_type(corgi_ts->irq_gpio, IRQT_NOEDGE); if (read_xydata(corgi_ts)) { corgi_ts->pendown = 1; - new_data(corgi_ts, regs); + new_data(corgi_ts); } mod_timer(&corgi_ts->timer, jiffies + HZ / 100); } else { @@ -208,7 +207,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_ if (corgi_ts->pendown) { corgi_ts->tc.pressure = 0; - new_data(corgi_ts, regs); + new_data(corgi_ts); } /* Enable Falling Edge */ @@ -223,10 +222,10 @@ static void corgi_ts_timer(unsigned long data) ts_interrupt_main(corgits_data, 1, NULL); } -static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ts_interrupt(int irq, void *dev_id) { struct corgi_ts *corgits_data = dev_id; - ts_interrupt_main(corgits_data, 0, regs); + ts_interrupt_main(corgits_data, 0); return IRQ_HANDLED; } diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index ab565335ee44..913e1b73bb0e 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -67,7 +67,7 @@ struct elo { char phys[32]; }; -static void elo_process_data_10(struct elo *elo, unsigned char data, struct pt_regs *regs) +static void elo_process_data_10(struct elo *elo, unsigned char data) { struct input_dev *dev = elo->dev; @@ -95,7 +95,6 @@ static void elo_process_data_10(struct elo *elo, unsigned char data, struct pt_r break; } if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) { - input_regs(dev, regs); input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); if (elo->data[2] & ELO10_PRESSURE) @@ -116,7 +115,7 @@ static void elo_process_data_10(struct elo *elo, unsigned char data, struct pt_r elo->csum += data; } -static void elo_process_data_6(struct elo *elo, unsigned char data, struct pt_regs *regs) +static void elo_process_data_6(struct elo *elo, unsigned char data) { struct input_dev *dev = elo->dev; @@ -134,7 +133,6 @@ static void elo_process_data_6(struct elo *elo, unsigned char data, struct pt_re break; } - input_regs(dev, regs); input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f)); input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f)); @@ -164,7 +162,7 @@ static void elo_process_data_6(struct elo *elo, unsigned char data, struct pt_re } } -static void elo_process_data_3(struct elo *elo, unsigned char data, struct pt_regs *regs) +static void elo_process_data_3(struct elo *elo, unsigned char data) { struct input_dev *dev = elo->dev; @@ -177,7 +175,6 @@ static void elo_process_data_3(struct elo *elo, unsigned char data, struct pt_re elo->idx = 0; break; case 2: - input_regs(dev, regs); input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80)); input_report_abs(dev, ABS_X, elo->data[1]); input_report_abs(dev, ABS_Y, elo->data[2]); @@ -188,22 +185,22 @@ static void elo_process_data_3(struct elo *elo, unsigned char data, struct pt_re } static irqreturn_t elo_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct elo *elo = serio_get_drvdata(serio); switch(elo->id) { case 0: - elo_process_data_10(elo, data, regs); + elo_process_data_10(elo, data); break; case 1: case 2: - elo_process_data_6(elo, data, regs); + elo_process_data_6(elo, data); break; case 3: - elo_process_data_3(elo, data, regs); + elo_process_data_3(elo, data); break; } diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index b769b21973b7..817c2198933d 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -60,7 +60,7 @@ struct gunze { char phys[32]; }; -static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs) +static void gunze_process_packet(struct gunze* gunze) { struct input_dev *dev = gunze->dev; @@ -70,7 +70,6 @@ static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs) return; } - input_regs(dev, regs); input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10)); input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10)); input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T'); @@ -78,12 +77,12 @@ static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs) } static irqreturn_t gunze_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct gunze* gunze = serio_get_drvdata(serio); if (data == '\r') { - gunze_process_packet(gunze, regs); + gunze_process_packet(gunze); gunze->idx = 0; } else { if (gunze->idx < GUNZE_MAX_LENGTH) diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index e2b910018773..d9e61ee05ea9 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -106,19 +106,18 @@ struct h3600_dev { char phys[32]; }; -static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t action_button_handler(int irq, void *dev_id) { int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1; struct input_dev *dev = (struct input_dev *) dev_id; - input_regs(dev, regs); input_report_key(dev, KEY_ENTER, down); input_sync(dev); return IRQ_HANDLED; } -static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t npower_button_handler(int irq, void *dev_id) { int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1; struct input_dev *dev = (struct input_dev *) dev_id; @@ -127,7 +126,6 @@ static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs * * This interrupt is only called when we release the key. So we have * to fake a key press. */ - input_regs(dev, regs); input_report_key(dev, KEY_SUSPEND, 1); input_report_key(dev, KEY_SUSPEND, down); input_sync(dev); @@ -165,14 +163,12 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr) * packets. Some packets coming from serial are not touchscreen related. In * this case we send them off to be processed elsewhere. */ -static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) +static void h3600ts_process_packet(struct h3600_dev *ts) { struct input_dev *dev = ts->dev; static int touched = 0; int key, down = 0; - input_regs(dev, regs); - switch (ts->event) { /* Buttons - returned as a single byte @@ -301,7 +297,7 @@ static int state; #define STATE_EOF 3 /* state where we decode checksum or EOF */ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data, - unsigned int flags, struct pt_regs *regs) + unsigned int flags) { struct h3600_dev *ts = serio_get_drvdata(serio); @@ -333,7 +329,7 @@ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data, case STATE_EOF: state = STATE_SOF; if (data == CHAR_EOF || data == ts->chksum) - h3600ts_process_packet(ts, regs); + h3600ts_process_packet(ts); break; default: printk("Error3\n"); diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c index ee6c2f40cdf6..e31c6c55b2e2 100644 --- a/drivers/input/touchscreen/hp680_ts_input.c +++ b/drivers/input/touchscreen/hp680_ts_input.c @@ -66,7 +66,7 @@ static void do_softint(void *data) enable_irq(HP680_TS_IRQ); } -static irqreturn_t hp680_ts_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t hp680_ts_interrupt(int irq, void *dev) { disable_irq_nosync(irq); schedule_delayed_work(&work, HZ / 20); diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c index 3226830eea08..4cbcaa6a71e5 100644 --- a/drivers/input/touchscreen/mk712.c +++ b/drivers/input/touchscreen/mk712.c @@ -80,7 +80,7 @@ MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller"); static struct input_dev *mk712_dev; static DEFINE_SPINLOCK(mk712_lock); -static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mk712_interrupt(int irq, void *dev_id) { unsigned char status; static int debounce = 1; @@ -88,7 +88,6 @@ static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) static unsigned short last_y; spin_lock(&mk712_lock); - input_regs(mk712_dev, regs); status = inb(mk712_io + MK712_STATUS); diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c index 8647a905df80..3b4c61664b63 100644 --- a/drivers/input/touchscreen/mtouch.c +++ b/drivers/input/touchscreen/mtouch.c @@ -63,12 +63,11 @@ struct mtouch { char phys[32]; }; -static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *regs) +static void mtouch_process_format_tablet(struct mtouch *mtouch) { struct input_dev *dev = mtouch->dev; if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) { - input_regs(dev, regs); input_report_abs(dev, ABS_X, MTOUCH_GET_XC(mtouch->data)); input_report_abs(dev, ABS_Y, MTOUCH_MAX_YC - MTOUCH_GET_YC(mtouch->data)); input_report_key(dev, BTN_TOUCH, MTOUCH_GET_TOUCHED(mtouch->data)); @@ -78,7 +77,7 @@ static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs * } } -static void mtouch_process_response(struct mtouch *mtouch, struct pt_regs *regs) +static void mtouch_process_response(struct mtouch *mtouch) { if (MTOUCH_RESPONSE_END_BYTE == mtouch->data[mtouch->idx++]) { /* FIXME - process response */ @@ -90,16 +89,16 @@ static void mtouch_process_response(struct mtouch *mtouch, struct pt_regs *regs) } static irqreturn_t mtouch_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct mtouch* mtouch = serio_get_drvdata(serio); mtouch->data[mtouch->idx] = data; if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0]) - mtouch_process_format_tablet(mtouch, regs); + mtouch_process_format_tablet(mtouch); else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0]) - mtouch_process_response(mtouch, regs); + mtouch_process_response(mtouch); else printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]); diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index f7370109d43e..6c7d0c2c76cc 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -46,7 +46,7 @@ struct pm { }; static irqreturn_t pm_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct pm *pm = serio_get_drvdata(serio); struct input_dev *dev = pm->dev; @@ -55,7 +55,6 @@ static irqreturn_t pm_interrupt(struct serio *serio, if (pm->data[0] & 0x80) { if (PM_MAX_LENGTH == ++pm->idx) { - input_regs(dev, regs); input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]); input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]); input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c index 1c89fa538651..c74f74e57af0 100644 --- a/drivers/input/touchscreen/touchright.c +++ b/drivers/input/touchscreen/touchright.c @@ -56,7 +56,7 @@ struct tr { }; static irqreturn_t tr_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct tr *tr = serio_get_drvdata(serio); struct input_dev *dev = tr->dev; @@ -65,7 +65,6 @@ static irqreturn_t tr_interrupt(struct serio *serio, if ((tr->data[0] & TR_FORMAT_STATUS_MASK) == TR_FORMAT_STATUS_BYTE) { if (++tr->idx == TR_LENGTH) { - input_regs(dev, regs); input_report_abs(dev, ABS_X, (tr->data[1] << 5) | (tr->data[2] >> 1)); input_report_abs(dev, ABS_Y, diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c index a7b4c755958e..9911820fa2fe 100644 --- a/drivers/input/touchscreen/touchwin.c +++ b/drivers/input/touchscreen/touchwin.c @@ -60,7 +60,7 @@ struct tw { }; static irqreturn_t tw_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int flags) { struct tw *tw = serio_get_drvdata(serio); struct input_dev *dev = tw->dev; @@ -70,7 +70,6 @@ static irqreturn_t tw_interrupt(struct serio *serio, tw->data[tw->idx++] = data; /* verify length and that the two Y's are the same */ if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) { - input_regs(dev, regs); input_report_abs(dev, ABS_X, tw->data[0]); input_report_abs(dev, ABS_Y, tw->data[1]); input_report_key(dev, BTN_TOUCH, 1); diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c index bc98d77c5ecd..3014495b7ff7 100644 --- a/drivers/isdn/act2000/act2000_isa.c +++ b/drivers/isdn/act2000/act2000_isa.c @@ -63,7 +63,7 @@ act2000_isa_detect(unsigned short portbase) } static irqreturn_t -act2000_isa_interrupt(int irq, void *dev_id, struct pt_regs *regs) +act2000_isa_interrupt(int irq, void *dev_id) { act2000_card *card = irq2card_map[irq]; u_char istatus; diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 5cfbe6a38010..0c937325a1b3 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -454,7 +454,7 @@ inline static int update_basstate(struct bas_cardstate *ucs, * urb USB request block * urb->context = inbuf structure for controller state */ -static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) +static void read_ctrl_callback(struct urb *urb) { struct inbuf_t *inbuf = urb->context; struct cardstate *cs = inbuf->cs; @@ -596,7 +596,7 @@ static int atread_submit(struct cardstate *cs, int timeout) * urb USB request block * urb->context = controller state structure */ -static void read_int_callback(struct urb *urb, struct pt_regs *regs) +static void read_int_callback(struct urb *urb) { struct cardstate *cs = urb->context; struct bas_cardstate *ucs = cs->hw.bas; @@ -762,7 +762,7 @@ resubmit: * urb USB request block of completed request * urb->context = bc_state structure */ -static void read_iso_callback(struct urb *urb, struct pt_regs *regs) +static void read_iso_callback(struct urb *urb) { struct bc_state *bcs; struct bas_bc_state *ubc; @@ -827,7 +827,7 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs) * urb USB request block of completed request * urb->context = isow_urbctx_t structure */ -static void write_iso_callback(struct urb *urb, struct pt_regs *regs) +static void write_iso_callback(struct urb *urb) { struct isow_urbctx_t *ucx; struct bas_bc_state *ubc; @@ -1415,7 +1415,7 @@ static void req_timeout(unsigned long data) * urb USB request block of completed request * urb->context = hardware specific controller state structure */ -static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) +static void write_ctrl_callback(struct urb *urb) { struct bas_cardstate *ucs = urb->context; int rc; @@ -1661,7 +1661,7 @@ static void complete_cb(struct cardstate *cs) * urb USB request block of completed request * urb->context = controller state structure */ -static void write_command_callback(struct urb *urb, struct pt_regs *regs) +static void write_command_callback(struct urb *urb) { struct cardstate *cs = urb->context; struct bas_cardstate *ucs = cs->hw.bas; diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 6e05d9d4a51a..4ffa9eb1c28e 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -362,7 +362,7 @@ static void gigaset_modem_fill(unsigned long data) * * It is called if the data was received from the device. */ -static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs) +static void gigaset_read_int_callback(struct urb *urb) { struct inbuf_t *inbuf = urb->context; struct cardstate *cs = inbuf->cs; @@ -420,7 +420,7 @@ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs) /* This callback routine is called when data was transmitted to the device. */ -static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void gigaset_write_bulk_callback(struct urb *urb) { struct cardstate *cs = urb->context; unsigned long flags; diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h index 3b431723c7cb..d964f07e4a56 100644 --- a/drivers/isdn/hardware/avm/avmcard.h +++ b/drivers/isdn/hardware/avm/avmcard.h @@ -554,7 +554,7 @@ void b1_register_appl(struct capi_ctr *ctrl, u16 appl, void b1_release_appl(struct capi_ctr *ctrl, u16 appl); u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); void b1_parse_version(avmctrl_info *card); -irqreturn_t b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs); +irqreturn_t b1_interrupt(int interrupt, void *devptr); int b1ctl_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl); @@ -567,7 +567,7 @@ void avmcard_dma_free(avmcard_dmainfo *); int b1pciv4_detect(avmcard *card); int t1pci_detect(avmcard *card); void b1dma_reset(avmcard *card); -irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs); +irqreturn_t b1dma_interrupt(int interrupt, void *devptr); int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data); void b1dma_reset_ctr(struct capi_ctr *ctrl); diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index 0c7061d55027..da2729247713 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -485,7 +485,7 @@ void b1_parse_version(avmctrl_info *cinfo) /* ------------------------------------------------------------- */ -irqreturn_t b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +irqreturn_t b1_interrupt(int interrupt, void *devptr) { avmcard *card = devptr; avmctrl_info *cinfo = &card->ctrlinfo[0]; diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index a4beeb46c859..ddd47cdfdb1f 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -628,7 +628,7 @@ static void b1dma_handle_interrupt(avmcard *card) spin_unlock(&card->lock); } -irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +irqreturn_t b1dma_interrupt(int interrupt, void *devptr) { avmcard *card = devptr; diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 6c3d5f5f1f4b..2a3eb38f0ebb 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -713,7 +713,7 @@ static irqreturn_t c4_handle_interrupt(avmcard *card) return IRQ_HANDLED; } -static irqreturn_t c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +static irqreturn_t c4_interrupt(int interrupt, void *devptr) { avmcard *card = devptr; diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index 5a2f854d55b5..e47c60b0a8ec 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -131,7 +131,7 @@ static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr) return 0; } -static irqreturn_t t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +static irqreturn_t t1isa_interrupt(int interrupt, void *devptr) { avmcard *card = devptr; avmctrl_info *cinfo = &card->ctrlinfo[0]; diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c index 8ab8027f33c0..ffa2afa77c2f 100644 --- a/drivers/isdn/hardware/eicon/diva.c +++ b/drivers/isdn/hardware/eicon/diva.c @@ -71,8 +71,6 @@ DivaIdiReqFunc(29) DivaIdiReqFunc(30) DivaIdiReqFunc(31) -struct pt_regs; - /* ** LOCALS */ @@ -515,7 +513,7 @@ diva_xdi_read(void *adapter, void *os_handle, void __user *dst, } -irqreturn_t diva_os_irq_wrapper(int irq, void *context, struct pt_regs *regs) +irqreturn_t diva_os_irq_wrapper(int irq, void *context) { diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context; diva_xdi_clear_interrupts_proc_t clear_int_proc; diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index b7dadba13e82..dae2e83dd5e8 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -58,8 +58,7 @@ static char *DRIVERLNAME = "divas"; static char *DEVNAME = "Divas"; char *DRIVERRELEASE_DIVAS = "2.0"; -extern irqreturn_t diva_os_irq_wrapper(int irq, void *context, - struct pt_regs *regs); +extern irqreturn_t diva_os_irq_wrapper(int irq, void *context); extern int create_divas_proc(void); extern void remove_divas_proc(void); extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf); diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index 8ae08c41c853..bec59010bc66 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -733,7 +733,7 @@ dbusy_timer_handler(struct IsdnCardState *cs) wByteAMD(cs, 0x21, 0x82); wByteAMD(cs, 0x21, 0x02); spin_unlock_irqrestore(&cs->lock, flags); - cs->irq_func(cs->irq, cs, NULL); + cs->irq_func(cs->irq, cs); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset"); diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c index 93ff941c48f1..61e69e9c4aa9 100644 --- a/drivers/isdn/hisax/asuscom.c +++ b/drivers/isdn/hisax/asuscom.c @@ -156,7 +156,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs) +asuscom_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; @@ -194,7 +194,7 @@ asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs) } static irqreturn_t -asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +asuscom_interrupt_ipac(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char ista, val, icnt = 5; diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c index 729e906bdc61..d9028e9b9b8f 100644 --- a/drivers/isdn/hisax/avm_a1.c +++ b/drivers/isdn/hisax/avm_a1.c @@ -101,7 +101,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs) +avm_a1_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val, sval; diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c index 574e252dfa43..c87fa3f9b298 100644 --- a/drivers/isdn/hisax/avm_a1p.c +++ b/drivers/isdn/hisax/avm_a1p.c @@ -140,7 +140,7 @@ WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size) #include "hscx_irq.c" static irqreturn_t -avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs) +avm_a1p_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val, sval; diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 369afd3a3a4b..b04a178e5021 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -651,7 +651,7 @@ inithdlc(struct IsdnCardState *cs) } static irqreturn_t -avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs) +avm_pcipnp_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_long flags; diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c index 87a630128a6c..871310d56a6e 100644 --- a/drivers/isdn/hisax/bkm_a4t.c +++ b/drivers/isdn/hisax/bkm_a4t.c @@ -125,7 +125,7 @@ WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value) #include "jade_irq.c" static irqreturn_t -bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs) +bkm_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val = 0; diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index dae090a9a489..340310645346 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -140,7 +140,7 @@ set_ipac_active(struct IsdnCardState *cs, u_int active) #include "hscx_irq.c" static irqreturn_t -bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +bkm_interrupt_ipac(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char ista, val, icnt = 5; diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index e294fa3918f3..7e95f04f13da 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -289,7 +289,7 @@ MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char val #include "hscx_irq.c" static irqreturn_t -diva_interrupt(int intno, void *dev_id, struct pt_regs *regs) +diva_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val, sval; @@ -319,7 +319,7 @@ diva_interrupt(int intno, void *dev_id, struct pt_regs *regs) } static irqreturn_t -diva_irq_ipac_isa(int intno, void *dev_id, struct pt_regs *regs) +diva_irq_ipac_isa(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char ista,val; @@ -630,7 +630,7 @@ Memhscx_int_main(struct IsdnCardState *cs, u_char val) } static irqreturn_t -diva_irq_ipac_pci(int intno, void *dev_id, struct pt_regs *regs) +diva_irq_ipac_pci(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char ista,val; @@ -685,7 +685,7 @@ Start_IPACPCI: } static irqreturn_t -diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs) +diva_irq_ipacx_pci(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 3b3e318f6076..fab3e4ea0595 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -282,7 +282,7 @@ TimerRun(struct IsdnCardState *cs) #include "hscx_irq.c" static irqreturn_t -elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) +elsa_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_long flags; @@ -361,7 +361,7 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) } static irqreturn_t -elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +elsa_interrupt_ipac(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_long flags; diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c index 76c7d29d1b2f..b45de9d408d1 100644 --- a/drivers/isdn/hisax/enternow_pci.c +++ b/drivers/isdn/hisax/enternow_pci.c @@ -240,7 +240,7 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) } static irqreturn_t -enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) +enpci_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; unsigned char s0val, s1val, ir; diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c index fe2937267777..3efa719b6d29 100644 --- a/drivers/isdn/hisax/gazel.c +++ b/drivers/isdn/hisax/gazel.c @@ -243,7 +243,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -gazel_interrupt(int intno, void *dev_id, struct pt_regs *regs) +gazel_interrupt(int intno, void *dev_id) { #define MAXCOUNT 5 struct IsdnCardState *cs = dev_id; @@ -274,7 +274,7 @@ gazel_interrupt(int intno, void *dev_id, struct pt_regs *regs) static irqreturn_t -gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +gazel_interrupt_ipac(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char ista, val; diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index 0ca5e66d2f5a..d852c9d998b2 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -1268,7 +1268,7 @@ hfc4s8s_bh(hfc4s8s_hw * hw) /* interrupt handler */ /*********************/ static irqreturn_t -hfc4s8s_interrupt(int intno, void *dev_id, struct pt_regs *regs) +hfc4s8s_interrupt(int intno, void *dev_id) { hfc4s8s_hw *hw = dev_id; u_char b, ovr; diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 1df60ca9481f..93f60b563515 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -931,7 +931,7 @@ receive_emsg(struct IsdnCardState *cs) /* Interrupt handler */ /*********************/ static irqreturn_t -hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) +hfcpci_interrupt(int intno, void *dev_id) { u_long flags; struct IsdnCardState *cs = dev_id; diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index b7e8e23be337..954d1536db1f 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -691,7 +691,7 @@ receive_emsg(struct IsdnCardState *cs) /* Interrupt handler */ /*********************/ static irqreturn_t -hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs) +hfcsx_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char exval; diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 6b88ecb5047d..7105b043add8 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -276,7 +276,7 @@ control_action_handler(hfcusb_data * hfc, int reg, int val, int action) /* control completion routine handling background control cmds */ /***************************************************************/ static void -ctrl_complete(struct urb *urb, struct pt_regs *regs) +ctrl_complete(struct urb *urb) { hfcusb_data *hfc = (hfcusb_data *) urb->context; ctrl_buft *buf; @@ -603,7 +603,7 @@ static int iso_packets[8] = /* transmit completion routine for all ISO tx fifos */ /*****************************************************/ static void -tx_iso_complete(struct urb *urb, struct pt_regs *regs) +tx_iso_complete(struct urb *urb) { iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; usb_fifo *fifo = context_iso_urb->owner_fifo; @@ -726,7 +726,7 @@ tx_iso_complete(struct urb *urb, struct pt_regs *regs) /* receive completion routine for all ISO tx fifos */ /*****************************************************/ static void -rx_iso_complete(struct urb *urb, struct pt_regs *regs) +rx_iso_complete(struct urb *urb) { iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; usb_fifo *fifo = context_iso_urb->owner_fifo; @@ -919,7 +919,7 @@ collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish) /* receive completion routine for all rx fifos */ /***********************************************/ static void -rx_complete(struct urb *urb, struct pt_regs *regs) +rx_complete(struct urb *urb) { int len; int status; diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c index 4e7f472877e9..57670dc5034d 100644 --- a/drivers/isdn/hisax/hfcscard.c +++ b/drivers/isdn/hisax/hfcscard.c @@ -21,7 +21,7 @@ extern const char *CardType[]; static const char *hfcs_revision = "$Revision: 1.10.2.4 $"; static irqreturn_t -hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs) +hfcs_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val, stat; diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 2f9d5118ceaf..159c5896061e 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -941,7 +941,7 @@ struct IsdnCardState { int (*cardmsg) (struct IsdnCardState *, int, void *); void (*setstack_d) (struct PStack *, struct IsdnCardState *); void (*DC_Close) (struct IsdnCardState *); - int (*irq_func) (int, void *, struct pt_regs *); + int (*irq_func) (int, void *); int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *); struct Channel channel[2+MAX_WAITING_CALLS]; struct BCState bcs[2+MAX_WAITING_CALLS]; diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c index 881a4165cfb4..f6db55a752c4 100644 --- a/drivers/isdn/hisax/hisax_fcpcipnp.c +++ b/drivers/isdn/hisax/hisax_fcpcipnp.c @@ -651,7 +651,7 @@ static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg) // ---------------------------------------------------------------------- static irqreturn_t -fcpci2_irq(int intno, void *dev, struct pt_regs *regs) +fcpci2_irq(int intno, void *dev) { struct fritz_adapter *adapter = dev; unsigned char val; @@ -671,7 +671,7 @@ fcpci2_irq(int intno, void *dev, struct pt_regs *regs) } static irqreturn_t -fcpci_irq(int intno, void *dev, struct pt_regs *regs) +fcpci_irq(int intno, void *dev) { struct fritz_adapter *adapter = dev; unsigned char sval; diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index 2cf7b665609e..da706925d54d 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -608,7 +608,7 @@ dbusy_timer_handler(struct IsdnCardState *cs) debugl1(cs, "D-Channel Busy no skb"); } cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */ - cs->irq_func(cs->irq, cs, NULL); + cs->irq_func(cs->irq, cs); } } } diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 565b7892c267..282f349408bc 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -609,7 +609,7 @@ dbusy_timer_handler(struct IsdnCardState *cs) debugl1(cs, "D-Channel Busy no skb"); } cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */ - cs->irq_func(cs->irq, cs, NULL); + cs->irq_func(cs->irq, cs); } } } diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c index 715a1a8cd694..55de06953540 100644 --- a/drivers/isdn/hisax/isurf.c +++ b/drivers/isdn/hisax/isurf.c @@ -83,7 +83,7 @@ WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) } static irqreturn_t -isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs) +isurf_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c index 39717506c678..252d79de5e5e 100644 --- a/drivers/isdn/hisax/ix1_micro.c +++ b/drivers/isdn/hisax/ix1_micro.c @@ -125,7 +125,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs) +ix1micro_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c index 8c82519593a8..a81d175d9f64 100644 --- a/drivers/isdn/hisax/mic.c +++ b/drivers/isdn/hisax/mic.c @@ -120,7 +120,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -mic_interrupt(int intno, void *dev_id, struct pt_regs *regs) +mic_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; diff --git a/drivers/isdn/hisax/netjet.h b/drivers/isdn/hisax/netjet.h index 1080508f3c6a..4d89d3ea4173 100644 --- a/drivers/isdn/hisax/netjet.h +++ b/drivers/isdn/hisax/netjet.h @@ -66,7 +66,7 @@ void read_tiger(struct IsdnCardState *cs); void write_tiger(struct IsdnCardState *cs); void netjet_fill_dma(struct BCState *bcs); -void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs); +void netjet_interrupt(int intno, void *dev_id); void inittiger(struct IsdnCardState *cs); void release_io_netjet(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index 0945336c28da..e5918c6fe73d 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -122,8 +122,7 @@ static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, #include "hscx_irq.c" -static irqreturn_t niccy_interrupt(int intno, void *dev_id, - struct pt_regs *regs) +static irqreturn_t niccy_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c index 80025fd890f4..c09ffb135330 100644 --- a/drivers/isdn/hisax/nj_s.c +++ b/drivers/isdn/hisax/nj_s.c @@ -26,7 +26,7 @@ static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value } static irqreturn_t -netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs) +netjet_s_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val, s1val, s0val; diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c index 37497162d539..8202cf34ecae 100644 --- a/drivers/isdn/hisax/nj_u.c +++ b/drivers/isdn/hisax/nj_u.c @@ -26,7 +26,7 @@ static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value } static irqreturn_t -netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs) +netjet_u_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val, sval; diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c index e76042d323ea..150ef68b4ae2 100644 --- a/drivers/isdn/hisax/s0box.c +++ b/drivers/isdn/hisax/s0box.c @@ -141,7 +141,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs) +s0box_interrupt(int intno, void *dev_id) { #define MAXCOUNT 5 struct IsdnCardState *cs = dev_id; diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c index d943d365890b..c99b16690fb3 100644 --- a/drivers/isdn/hisax/saphir.c +++ b/drivers/isdn/hisax/saphir.c @@ -117,7 +117,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs) +saphir_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index 8d8e8a299892..9522141f4351 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -260,7 +260,7 @@ WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs) +sedlbauer_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; @@ -306,7 +306,7 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs) } static irqreturn_t -sedlbauer_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +sedlbauer_interrupt_ipac(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char ista, val, icnt = 5; @@ -353,7 +353,7 @@ Start_IPAC: } static irqreturn_t -sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs) +sedlbauer_interrupt_isar(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c index a49b694eb730..02209500b3b7 100644 --- a/drivers/isdn/hisax/sportster.c +++ b/drivers/isdn/hisax/sportster.c @@ -99,7 +99,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs) +sportster_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c index aca2a3954b14..75d0f248e4ee 100644 --- a/drivers/isdn/hisax/st5481_b.c +++ b/drivers/isdn/hisax/st5481_b.c @@ -161,7 +161,7 @@ static void led_blink(struct st5481_adapter *adapter) st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, leds, NULL, NULL); } -static void usb_b_out_complete(struct urb *urb, struct pt_regs *regs) +static void usb_b_out_complete(struct urb *urb) { struct st5481_bcs *bcs = urb->context; struct st5481_b_out *b_out = &bcs->b_out; diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c index 98adec440590..1d8c2618366c 100644 --- a/drivers/isdn/hisax/st5481_d.c +++ b/drivers/isdn/hisax/st5481_d.c @@ -370,7 +370,7 @@ static void fifo_reseted(void *context) FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL); } -static void usb_d_out_complete(struct urb *urb, struct pt_regs *regs) +static void usb_d_out_complete(struct urb *urb) { struct st5481_adapter *adapter = urb->context; struct st5481_d_out *d_out = &adapter->d_out; diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index b096b64b0253..ff1595122048 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -125,7 +125,7 @@ void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command) * Call the user provided completion routine and try * to send the next request. */ -static void usb_ctrl_complete(struct urb *urb, struct pt_regs *regs) +static void usb_ctrl_complete(struct urb *urb) { struct st5481_adapter *adapter = urb->context; struct st5481_ctrl *ctrl = &adapter->ctrl; @@ -179,7 +179,7 @@ static void usb_ctrl_complete(struct urb *urb, struct pt_regs *regs) * Decode the register values and schedule a private event. * Called at interrupt. */ -static void usb_int_complete(struct urb *urb, struct pt_regs *regs) +static void usb_int_complete(struct urb *urb) { u8 *data = urb->transfer_buffer; u8 irqbyte; @@ -483,7 +483,7 @@ void st5481_release_isocpipes(struct urb* urb[2]) * called 50 times per second with 20 ISOC descriptors. * Called at interrupt. */ -static void usb_in_complete(struct urb *urb, struct pt_regs *regs) +static void usb_in_complete(struct urb *urb) { struct st5481_in *in = urb->context; unsigned char *ptr; diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c index e94dc6f5bd62..0909662b7458 100644 --- a/drivers/isdn/hisax/teleint.c +++ b/drivers/isdn/hisax/teleint.c @@ -157,7 +157,7 @@ WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value) } static irqreturn_t -TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs) +TeleInt_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c index f94af0930a17..48581335f43c 100644 --- a/drivers/isdn/hisax/teles0.c +++ b/drivers/isdn/hisax/teles0.c @@ -144,7 +144,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs) +teles0_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val; diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c index 5cb712437da4..6a5e379e0774 100644 --- a/drivers/isdn/hisax/teles3.c +++ b/drivers/isdn/hisax/teles3.c @@ -101,7 +101,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs) +teles3_interrupt(int intno, void *dev_id) { #define MAXCOUNT 5 struct IsdnCardState *cs = dev_id; diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index dca446865f24..d09f6d033f15 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -226,7 +226,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) #include "hscx_irq.c" static irqreturn_t -telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs) +telespci_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char hval, ival; diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 0595293b8659..1655341797a9 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -400,7 +400,7 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) } static irqreturn_t -W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs) +W6692_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val, exval, v1; @@ -715,7 +715,7 @@ dbusy_timer_handler(struct IsdnCardState *cs) } cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); /* Transmitter reset */ spin_unlock_irqrestore(&cs->lock, flags); - cs->irq_func(cs->irq, cs, NULL); + cs->irq_func(cs->irq, cs); return; } } diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c index 73afebdf80bd..160f22fa5941 100644 --- a/drivers/isdn/hysdn/boardergo.c +++ b/drivers/isdn/hysdn/boardergo.c @@ -33,7 +33,7 @@ /* The cards interrupt handler. Called from system */ /***************************************************/ static irqreturn_t -ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs) +ergo_interrupt(int intno, void *dev_id) { hysdn_card *card = dev_id; /* parameter from irq */ tErgDpram *dpr; diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index ba766930f088..13e7d219d1c7 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -512,7 +512,7 @@ pcbit_firmware_bug(struct pcbit_dev *dev) } irqreturn_t -pcbit_irq_handler(int interrupt, void *devptr, struct pt_regs *regs) +pcbit_irq_handler(int interrupt, void *devptr) { struct pcbit_dev *dev; u_char info, diff --git a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h index 0d99da3a3e2b..2ac295e1a6e5 100644 --- a/drivers/isdn/pcbit/layer2.h +++ b/drivers/isdn/pcbit/layer2.h @@ -124,7 +124,7 @@ struct frame_buf { extern int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum, struct sk_buff *skb, unsigned short hdr_len); -extern irqreturn_t pcbit_irq_handler(int interrupt, void *, struct pt_regs *regs); +extern irqreturn_t pcbit_irq_handler(int interrupt, void *); extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS]; diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index a627e68023f6..222ca7c08baa 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -35,7 +35,7 @@ module_param_array(irq, int, NULL, 0); module_param_array(ram, int, NULL, 0); module_param(do_reset, bool, 0); -extern irqreturn_t interrupt_handler(int, void *, struct pt_regs *); +extern irqreturn_t interrupt_handler(int, void *); extern int sndpkt(int, int, int, struct sk_buff *); extern int command(isdn_ctrl *); extern int indicate_status(int, int, ulong, char*); diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c index ae6263125ac2..cd17de18cb76 100644 --- a/drivers/isdn/sc/interrupt.c +++ b/drivers/isdn/sc/interrupt.c @@ -45,7 +45,7 @@ static int get_card_from_irq(int irq) /* * */ -irqreturn_t interrupt_handler(int interrupt, void *cardptr, struct pt_regs *regs) +irqreturn_t interrupt_handler(int interrupt, void *cardptr) { RspMessage rcvmsg; diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c index d56d400b6aaa..1ffee7aaff20 100644 --- a/drivers/macintosh/adb-iop.c +++ b/drivers/macintosh/adb-iop.c @@ -30,7 +30,7 @@ /*#define DEBUG_ADB_IOP*/ -extern void iop_ism_irq(int, void *, struct pt_regs *); +extern void iop_ism_irq(int, void *); static struct adb_request *current_req; static struct adb_request *last_req; @@ -78,7 +78,7 @@ static void adb_iop_end_req(struct adb_request *req, int state) * This will be called when a packet has been successfully sent. */ -static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs) +static void adb_iop_complete(struct iop_msg *msg) { struct adb_request *req; uint flags; @@ -100,7 +100,7 @@ static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs) * commands or autopoll packets) are received. */ -static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs) +static void adb_iop_listen(struct iop_msg *msg) { struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message; struct adb_request *req; @@ -143,7 +143,7 @@ static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs) req->reply_len = amsg->count + 1; memcpy(req->reply, &amsg->cmd, req->reply_len); } else { - adb_input(&amsg->cmd, amsg->count + 1, regs, + adb_input(&amsg->cmd, amsg->count + 1, amsg->flags & ADB_IOP_AUTOPOLL); } memcpy(msg->reply, msg->message, IOP_MSG_LEN); diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 360f93f6fcdb..be0bd34ff6f9 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -103,7 +103,7 @@ static void adbdev_init(void); static int try_handler_change(int, int); static struct adb_handler { - void (*handler)(unsigned char *, int, struct pt_regs *, int); + void (*handler)(unsigned char *, int, int); int original_address; int handler_id; int busy; @@ -522,7 +522,7 @@ bail: the handler_id id it doesn't match. */ int adb_register(int default_id, int handler_id, struct adb_ids *ids, - void (*handler)(unsigned char *, int, struct pt_regs *, int)) + void (*handler)(unsigned char *, int, int)) { int i; @@ -570,13 +570,13 @@ adb_unregister(int index) } void -adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll) +adb_input(unsigned char *buf, int nb, int autopoll) { int i, id; static int dump_adb_input = 0; unsigned long flags; - void (*handler)(unsigned char *, int, struct pt_regs *, int); + void (*handler)(unsigned char *, int, int); /* We skip keystrokes and mouse moves when the sleep process * has been started. We stop autopoll, but this is another security @@ -597,7 +597,7 @@ adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll) adb_handler[id].busy = 1; write_unlock_irqrestore(&adb_handler_lock, flags); if (handler != NULL) { - (*handler)(buf, nb, regs, autopoll); + (*handler)(buf, nb, autopoll); wmb(); adb_handler[id].busy = 0; } diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index b7fb367808d8..5066e7a8ea9c 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -222,7 +222,7 @@ static struct adbhid *adbhid[16]; static void adbhid_probe(void); -static void adbhid_input_keycode(int, int, int, struct pt_regs *); +static void adbhid_input_keycode(int, int, int); static void init_trackpad(int id); static void init_trackball(int id); @@ -253,7 +253,7 @@ static struct adb_ids buttons_ids; #define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */ static void -adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll) +adbhid_keyboard_input(unsigned char *data, int nb, int apoll) { int id = (data[0] >> 4) & 0x0f; @@ -266,13 +266,13 @@ adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apo /* first check this is from register 0 */ if (nb != 3 || (data[0] & 3) != KEYB_KEYREG) return; /* ignore it */ - adbhid_input_keycode(id, data[1], 0, regs); + adbhid_input_keycode(id, data[1], 0); if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f))) - adbhid_input_keycode(id, data[2], 0, regs); + adbhid_input_keycode(id, data[2], 0); } static void -adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs) +adbhid_input_keycode(int id, int keycode, int repeat) { struct adbhid *ahid = adbhid[id]; int up_flag; @@ -282,7 +282,6 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs) switch (keycode) { case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */ - input_regs(ahid->input, regs); input_report_key(ahid->input, KEY_CAPSLOCK, 1); input_report_key(ahid->input, KEY_CAPSLOCK, 0); input_sync(ahid->input); @@ -338,7 +337,6 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs) } if (adbhid[id]->keycode[keycode]) { - input_regs(adbhid[id]->input, regs); input_report_key(adbhid[id]->input, adbhid[id]->keycode[keycode], !up_flag); input_sync(adbhid[id]->input); @@ -349,7 +347,7 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs) } static void -adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +adbhid_mouse_input(unsigned char *data, int nb, int autopoll) { int id = (data[0] >> 4) & 0x0f; @@ -432,8 +430,6 @@ adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopo break; } - input_regs(adbhid[id]->input, regs); - input_report_key(adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); input_report_key(adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); @@ -449,7 +445,7 @@ adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopo } static void -adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +adbhid_buttons_input(unsigned char *data, int nb, int autopoll) { int id = (data[0] >> 4) & 0x0f; @@ -458,8 +454,6 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto return; } - input_regs(adbhid[id]->input, regs); - switch (adbhid[id]->original_handler_id) { default: case 0x02: /* Adjustable keyboard button device */ diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index 4b08852c35ee..57ccc19cbdbf 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -64,7 +64,7 @@ static DEFINE_SPINLOCK(macio_lock); static int macio_probe(void); static int macio_init(void); -static irqreturn_t macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs); +static irqreturn_t macio_adb_interrupt(int irq, void *arg); static int macio_send_request(struct adb_request *req, int sync); static int macio_adb_autopoll(int devs); static void macio_adb_poll(void); @@ -189,8 +189,7 @@ static int macio_send_request(struct adb_request *req, int sync) return 0; } -static irqreturn_t macio_adb_interrupt(int irq, void *arg, - struct pt_regs *regs) +static irqreturn_t macio_adb_interrupt(int irq, void *arg) { int i, n, err; struct adb_request *req = NULL; @@ -260,7 +259,7 @@ static irqreturn_t macio_adb_interrupt(int irq, void *arg, (*done)(req); } if (ibuf_len) - adb_input(ibuf, ibuf_len, regs, autopoll); + adb_input(ibuf, ibuf_len, autopoll); return IRQ_RETVAL(handled); } diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index c0f9d82e4662..ade25b3fbb35 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -145,7 +145,7 @@ static void smu_start_cmd(void) } -static irqreturn_t smu_db_intr(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t smu_db_intr(int irq, void *arg) { unsigned long flags; struct smu_cmd *cmd; @@ -224,7 +224,7 @@ static irqreturn_t smu_db_intr(int irq, void *arg, struct pt_regs *regs) } -static irqreturn_t smu_msg_intr(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t smu_msg_intr(int irq, void *arg) { /* I don't quite know what to do with this one, we seem to never * receive it, so I suspect we have to arm it someway in the SMU @@ -309,7 +309,7 @@ void smu_poll(void) gpio = pmac_do_feature_call(PMAC_FTR_READ_GPIO, NULL, smu->doorbell); if ((gpio & 7) == 7) - smu_db_intr(smu->db_irq, smu, NULL); + smu_db_intr(smu->db_irq, smu); } EXPORT_SYMBOL(smu_poll); diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 7512d1c15207..64a07ccfe369 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -98,8 +98,8 @@ static int cuda_reset_adb_bus(void); static int cuda_init_via(void); static void cuda_start(void); -static irqreturn_t cuda_interrupt(int irq, void *arg, struct pt_regs *regs); -static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs); +static irqreturn_t cuda_interrupt(int irq, void *arg); +static void cuda_input(unsigned char *buf, int nb); void cuda_poll(void); static int cuda_write(struct adb_request *req); @@ -442,7 +442,7 @@ cuda_poll(void) } static irqreturn_t -cuda_interrupt(int irq, void *arg, struct pt_regs *regs) +cuda_interrupt(int irq, void *arg) { int status; struct adb_request *req = NULL; @@ -594,12 +594,12 @@ cuda_interrupt(int irq, void *arg, struct pt_regs *regs) (*done)(req); } if (ibuf_len) - cuda_input(ibuf, ibuf_len, regs); + cuda_input(ibuf, ibuf_len); return IRQ_HANDLED; } static void -cuda_input(unsigned char *buf, int nb, struct pt_regs *regs) +cuda_input(unsigned char *buf, int nb) { int i; @@ -615,7 +615,7 @@ cuda_input(unsigned char *buf, int nb, struct pt_regs *regs) } #endif /* CONFIG_XMON */ #ifdef CONFIG_ADB - adb_input(buf+2, nb-2, regs, buf[1] & 0x40); + adb_input(buf+2, nb-2, buf[1] & 0x40); #endif /* CONFIG_ADB */ break; diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index 2a2ffe060169..ad4bd579f610 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -77,7 +77,7 @@ static volatile unsigned char *via; static int macii_init_via(void); static void macii_start(void); -static irqreturn_t macii_interrupt(int irq, void *arg, struct pt_regs *regs); +static irqreturn_t macii_interrupt(int irq, void *arg); static void macii_retransmit(int); static void macii_queue_poll(void); @@ -410,7 +410,7 @@ static void macii_start(void) * Note: As of 21/10/97, the MacII ADB part works including timeout detection * and retransmit (Talk to the last active device). */ -static irqreturn_t macii_interrupt(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t macii_interrupt(int irq, void *arg) { int x, adbdir; unsigned long flags; @@ -602,8 +602,7 @@ static irqreturn_t macii_interrupt(int irq, void *arg, struct pt_regs *regs) current_req = req->next; if (req->done) (*req->done)(req); } else { - adb_input(reply_buf, reply_ptr - reply_buf, - regs, 0); + adb_input(reply_buf, reply_ptr - reply_buf, 0); } /* diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c index 0129fcc3b183..789ee52086fe 100644 --- a/drivers/macintosh/via-maciisi.c +++ b/drivers/macintosh/via-maciisi.c @@ -84,8 +84,8 @@ static int maciisi_init(void); static int maciisi_send_request(struct adb_request* req, int sync); static void maciisi_sync(struct adb_request *req); static int maciisi_write(struct adb_request* req); -static irqreturn_t maciisi_interrupt(int irq, void* arg, struct pt_regs* regs); -static void maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs); +static irqreturn_t maciisi_interrupt(int irq, void* arg); +static void maciisi_input(unsigned char *buf, int nb); static int maciisi_init_via(void); static void maciisi_poll(void); static int maciisi_start(void); @@ -433,7 +433,7 @@ maciisi_poll(void) register is either full or empty. In practice, I have no idea what it means :( */ static irqreturn_t -maciisi_interrupt(int irq, void* arg, struct pt_regs* regs) +maciisi_interrupt(int irq, void* arg) { int status; struct adb_request *req; @@ -612,7 +612,7 @@ maciisi_interrupt(int irq, void* arg, struct pt_regs* regs) /* Obviously, we got it */ reading_reply = 0; } else { - maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf, regs); + maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf); } maciisi_state = idle; status = via[B] & (TIP|TREQ); @@ -657,7 +657,7 @@ maciisi_interrupt(int irq, void* arg, struct pt_regs* regs) } static void -maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs) +maciisi_input(unsigned char *buf, int nb) { #ifdef DEBUG_MACIISI_ADB int i; @@ -665,7 +665,7 @@ maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs) switch (buf[0]) { case ADB_PACKET: - adb_input(buf+2, nb-2, regs, buf[1] & 0x40); + adb_input(buf+2, nb-2, buf[1] & 0x40); break; default: #ifdef DEBUG_MACIISI_ADB diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 4f04fd0956a0..e63ea1c1f3c1 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -191,8 +191,8 @@ static int pmu_adb_reset_bus(void); static int init_pmu(void); static void pmu_start(void); -static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs); -static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); +static irqreturn_t via_pmu_interrupt(int irq, void *arg); +static irqreturn_t gpio1_interrupt(int irq, void *arg); static int proc_get_info(char *page, char **start, off_t off, int count, int *eof, void *data); static int proc_get_irqstats(char *page, char **start, off_t off, @@ -555,7 +555,7 @@ init_pmu(void) } if (pmu_state == idle) adb_int_pending = 1; - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); udelay(10); } @@ -1215,7 +1215,7 @@ pmu_poll(void) return; if (disable_poll) return; - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); } void @@ -1228,7 +1228,7 @@ pmu_poll_adb(void) /* Kicks ADB read when PMU is suspended */ adb_int_pending = 1; do { - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); } while (pmu_suspended && (adb_int_pending || pmu_state != idle || req_awaiting_reply)); } @@ -1239,7 +1239,7 @@ pmu_wait_complete(struct adb_request *req) if (!via) return; while((pmu_state != idle && pmu_state != locked) || !req->complete) - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); } /* This function loops until the PMU is idle and prevents it from @@ -1268,7 +1268,7 @@ pmu_suspend(void) spin_unlock_irqrestore(&pmu_lock, flags); if (req_awaiting_reply) adb_int_pending = 1; - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); spin_lock_irqsave(&pmu_lock, flags); if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) { #ifdef SUSPEND_USES_PMU @@ -1318,7 +1318,7 @@ pmu_resume(void) /* Interrupt data could be the result data from an ADB cmd */ static void -pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) +pmu_handle_data(unsigned char *data, int len) { unsigned char ints, pirq; int i = 0; @@ -1393,7 +1393,7 @@ next: if (!(pmu_kind == PMU_OHARE_BASED && len == 4 && data[1] == 0x2c && data[3] == 0xff && (data[2] & ~1) == 0xf4)) - adb_input(data+1, len-1, regs, 1); + adb_input(data+1, len-1, 1); #endif /* CONFIG_ADB */ } } @@ -1431,7 +1431,7 @@ next: } static struct adb_request* -pmu_sr_intr(struct pt_regs *regs) +pmu_sr_intr(void) { struct adb_request *req; int bite = 0; @@ -1537,7 +1537,7 @@ pmu_sr_intr(struct pt_regs *regs) } static irqreturn_t -via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) +via_pmu_interrupt(int irq, void *arg) { unsigned long flags; int intr; @@ -1567,7 +1567,7 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) pmu_irq_stats[0]++; } if (intr & SR_INT) { - req = pmu_sr_intr(regs); + req = pmu_sr_intr(); if (req) break; } @@ -1613,7 +1613,7 @@ no_free_slot: /* Deal with interrupt datas outside of the lock */ if (int_data >= 0) { - pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data], regs); + pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data]); spin_lock_irqsave(&pmu_lock, flags); ++disable_poll; int_data_state[int_data] = int_data_empty; @@ -1638,7 +1638,7 @@ pmu_unlock(void) static irqreturn_t -gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) +gpio1_interrupt(int irq, void *arg) { unsigned long flags; @@ -1651,7 +1651,7 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) pmu_irq_stats[1]++; adb_int_pending = 1; spin_unlock_irqrestore(&pmu_lock, flags); - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); return IRQ_HANDLED; } return IRQ_NONE; @@ -2116,7 +2116,7 @@ pmac_wakeup_devices(void) /* Force a poll of ADB interrupts */ adb_int_pending = 1; - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); /* Restart jiffies & scheduling */ wakeup_decrementer(); diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index 9f4eff1d1a0f..98ec915d0409 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -107,7 +107,7 @@ BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); static int pmu_probe(void); static int pmu_init(void); static void pmu_start(void); -static irqreturn_t pmu_interrupt(int irq, void *arg, struct pt_regs *regs); +static irqreturn_t pmu_interrupt(int irq, void *arg); static int pmu_send_request(struct adb_request *req, int sync); static int pmu_autopoll(int devs); void pmu_poll(void); @@ -118,8 +118,7 @@ static void pmu_start(void); static void send_byte(int x); static void recv_byte(void); static void pmu_done(struct adb_request *req); -static void pmu_handle_data(unsigned char *data, int len, - struct pt_regs *regs); +static void pmu_handle_data(unsigned char *data, int len); static void set_volume(int level); static void pmu_enable_backlight(int on); static void pmu_set_brightness(int level); @@ -573,7 +572,7 @@ pmu_poll(void) } static irqreturn_t -pmu_interrupt(int irq, void *dev_id, struct pt_regs *regs) +pmu_interrupt(int irq, void *dev_id) { struct adb_request *req; int timeout, bite = 0; /* to prevent compiler warning */ @@ -657,7 +656,7 @@ pmu_interrupt(int irq, void *dev_id, struct pt_regs *regs) } if (pmu_state == reading_intr) { - pmu_handle_data(interrupt_data, data_index, regs); + pmu_handle_data(interrupt_data, data_index); } else { req = current_req; current_req = req->next; @@ -701,7 +700,7 @@ pmu_done(struct adb_request *req) /* Interrupt data could be the result data from an ADB cmd */ static void -pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) +pmu_handle_data(unsigned char *data, int len) { static int show_pmu_ints = 1; @@ -726,7 +725,7 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) } pmu_done(req); } else { - adb_input(data+1, len-1, regs, 1); + adb_input(data+1, len-1, 1); } } else { if (data[0] == 0x08 && len == 3) { diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index b88451e33c09..86cbdbcf9d7d 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -230,7 +230,7 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt /********************************************************************************/ /* interrupt handler */ -static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t interrupt_hw(int irq, void *dev_id) { struct saa7146_dev *dev = dev_id; u32 isr = 0; diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index eb2e6432c8c2..06893243f3d4 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -122,7 +122,7 @@ static void flexcop_pci_irq_check_work(void *data) /* When PID filtering is turned on, we use the timer IRQ, because small amounts * of data need to be passed to the user space instantly as well. When PID * filtering is turned off, we use the page-change-IRQ */ -static irqreturn_t flexcop_pci_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) { struct flexcop_pci *fc_pci = dev_id; struct flexcop_device *fc = fc_pci->fc_dev; diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c index 515954f96c9a..2853ea1bdaf1 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ b/drivers/media/dvb/b2c2/flexcop-usb.c @@ -328,7 +328,7 @@ static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, in fc_usb->tmp_buffer_length = l; } -static void flexcop_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) +static void flexcop_usb_urb_complete(struct urb *urb) { struct flexcop_usb *fc_usb = urb->context; int i; diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 755822ee6e9b..329a51c18562 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -266,7 +266,7 @@ EXPORT_SYMBOL(bt878_stop); /* Interrupt service routine */ /*****************************/ -static irqreturn_t bt878_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t bt878_irq(int irq, void *dev_id) { u32 stat, astat, mask; int count; diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 410fa6d620ff..ff7d4f56ced3 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -238,7 +238,7 @@ static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep) cinergyt2->sleeping = sleep; } -static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs); +static void cinergyt2_stream_irq (struct urb *urb); static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb) { @@ -258,7 +258,7 @@ static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb return err; } -static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs) +static void cinergyt2_stream_irq (struct urb *urb) { struct cinergyt2 *cinergyt2 = urb->context; diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c index 572b2d9aa66a..78035ee824ca 100644 --- a/drivers/media/dvb/dvb-usb/usb-urb.c +++ b/drivers/media/dvb/dvb-usb/usb-urb.c @@ -11,7 +11,7 @@ #include "dvb-usb-common.h" /* URB stuff for streaming */ -static void usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) +static void usb_urb_complete(struct urb *urb) { struct usb_data_stream *stream = urb->context; int ptype = usb_pipetype(urb->pipe); diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index 2310b2bfed4e..8e4ce101eb22 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -306,7 +306,7 @@ static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) TS_DMA_BYTES, PCI_DMA_FROMDEVICE); } -static irqreturn_t pluto_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pluto_irq(int irq, void *dev_id) { struct pluto *pluto = dev_id; u32 tscr; diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 234199875f53..60820deb900b 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -732,7 +732,7 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len) } } -static void ttusb_iso_irq(struct urb *urb, struct pt_regs *ptregs) +static void ttusb_iso_irq(struct urb *urb) { struct ttusb *ttusb = urb->context; diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index de077a757192..a1c9fa9919ea 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -203,7 +203,7 @@ static u16 rc_keys[] = { static void ttusb_dec_set_model(struct ttusb_dec *dec, enum ttusb_dec_model model); -static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs) +static void ttusb_dec_handle_irq( struct urb *urb) { struct ttusb_dec * dec = urb->context; char *buffer = dec->irq_buffer; @@ -755,7 +755,7 @@ static void ttusb_dec_process_urb_frame_list(unsigned long data) } } -static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs) +static void ttusb_dec_process_urb(struct urb *urb) { struct ttusb_dec *dec = urb->context; diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 5c5e682a3004..4861799eb430 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -549,7 +549,7 @@ static int ar_ioctl(struct inode *inode, struct file *file, unsigned int cmd, /* * Interrupt handler */ -static void ar_interrupt(int irq, void *dev, struct pt_regs *regs) +static void ar_interrupt(int irq, void *dev) { struct ar_device *ar = dev; unsigned int line_count; diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 50dde82844ec..6e1ddad9f0c1 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3753,7 +3753,7 @@ bttv_irq_switch_vbi(struct bttv *btv) spin_unlock(&btv->s_lock); } -static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t bttv_irq(int irq, void *dev_id) { u32 stat,astat; u32 dstat; diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c index f4da02941493..28dc6a1a1e43 100644 --- a/drivers/media/video/cpia2/cpia2_usb.c +++ b/drivers/media/video/cpia2/cpia2_usb.c @@ -49,7 +49,7 @@ static int frame_sizes[] = { #define FRAME_SIZE_PER_DESC frame_sizes[cam->cur_alt] static void process_frame(struct camera_data *cam); -static void cpia2_usb_complete(struct urb *urb, struct pt_regs *); +static void cpia2_usb_complete(struct urb *urb); static int cpia2_usb_probe(struct usb_interface *intf, const struct usb_device_id *id); static void cpia2_usb_disconnect(struct usb_interface *intf); @@ -199,7 +199,7 @@ static void add_COM(struct camera_data *cam) * * callback when incoming packet is received *****************************************************************************/ -static void cpia2_usb_complete(struct urb *urb, struct pt_regs *regs) +static void cpia2_usb_complete(struct urb *urb) { int i; unsigned char *cdata; diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c index 2ee34a3b9280..9da4726eb9b9 100644 --- a/drivers/media/video/cpia_usb.c +++ b/drivers/media/video/cpia_usb.c @@ -109,7 +109,7 @@ static struct cpia_camera_ops cpia_usb_ops = { static LIST_HEAD(cam_list); static spinlock_t cam_list_lock_usb; -static void cpia_usb_complete(struct urb *urb, struct pt_regs *regs) +static void cpia_usb_complete(struct urb *urb) { int i; char *cdata; diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index f0340662e078..e4355fdc3b6d 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -262,7 +262,7 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) /* * BOARD Specific: Handles IRQ calls */ -static irqreturn_t cx8801_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cx8801_irq(int irq, void *dev_id) { snd_cx88_card_t *chip = dev_id; struct cx88_core *core = chip->core; diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index d6d980774c21..6b23a4e6f66d 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -376,7 +376,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) #define MAX_IRQ_LOOP 10 -static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cx8802_irq(int irq, void *dev_id) { struct cx8802_dev *dev = dev_id; struct cx88_core *core = dev->core; diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index cb0c0eea20f9..90e298d074d1 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1744,7 +1744,7 @@ static void cx8800_vid_irq(struct cx8800_dev *dev) } } -static irqreturn_t cx8800_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cx8800_irq(int irq, void *dev_id) { struct cx8800_dev *dev = dev_id; struct cx88_core *core = dev->core; diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c index b9ba95f5e026..b1012e92ee04 100644 --- a/drivers/media/video/dabusb.c +++ b/drivers/media/video/dabusb.c @@ -166,7 +166,7 @@ static int dabusb_free_buffers (pdabusb_t s) return 0; } /*-------------------------------------------------------------------*/ -static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs) +static void dabusb_iso_complete (struct urb *purb) { pbuff_t b = purb->context; pdabusb_t s = b->s; diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 4350cc75b025..255a47dfb84f 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -382,7 +382,7 @@ int em28xx_resolution_set(struct em28xx *dev) /******************* isoc transfer handling ****************************/ #ifdef ENABLE_DEBUG_ISOC_FRAMES -static void em28xx_isoc_dump(struct urb *urb, struct pt_regs *regs) +static void em28xx_isoc_dump(struct urb *urb) { int len = 0; int ntrans = 0; @@ -534,7 +534,7 @@ static inline void em28xx_isoc_video_copy(struct em28xx *dev, * em28xx_isoIrq() * handles the incoming isoc urbs and fills the frames from our inqueue */ -static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs) +static void em28xx_isocIrq(struct urb *urb) { struct em28xx *dev = urb->context; int i, status; @@ -545,7 +545,7 @@ static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs) return; #ifdef ENABLE_DEBUG_ISOC_FRAMES if (isoc_debug>1) - em28xx_isoc_dump(urb, regs); + em28xx_isoc_dump(urb); #endif if (urb->status == -ENOENT) diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 8992b6e62b9f..bc544cc7ccb8 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -398,7 +398,7 @@ int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value) /*****************************************************************************/ -static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs) +static void et61x251_urb_complete(struct urb *urb) { struct et61x251_device* cam = urb->context; struct et61x251_frame_t** f; diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index e278753f8f25..b083338823df 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -786,7 +786,7 @@ static void mchip_cont_compression_start(void) /* Interrupt handling */ /****************************************************************************/ -static irqreturn_t meye_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t meye_irq(int irq, void *dev_id) { u32 v; int reqnr; diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index 5d8cd283fcd8..ce4886f1528d 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -3503,7 +3503,7 @@ check_middle: } static void -ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs) +ov51x_isoc_irq(struct urb *urb) { int i; struct usb_ov511 *ov; diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c index 3484e36b6801..368d6e219fa4 100644 --- a/drivers/media/video/planb.c +++ b/drivers/media/video/planb.c @@ -91,7 +91,7 @@ static void planb_close(struct video_device *); static int planb_ioctl(struct video_device *, unsigned int, void *); static int planb_init_done(struct video_device *); static int planb_mmap(struct video_device *, const char *, unsigned long); -static void planb_irq(int, void *, struct pt_regs *); +static void planb_irq(int, void *); static void release_planb(void); int init_planbs(struct video_init *); @@ -1316,7 +1316,7 @@ cmd_tab_data_end: return c1; } -static void planb_irq(int irq, void *dev_id, struct pt_regs * regs) +static void planb_irq(int irq, void *dev_id) { unsigned int stat, astat; struct planb *pb = (struct planb *)dev_id; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 3d8cd0daf6a9..f920e0ccacd3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2552,7 +2552,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v) } -static void pvr2_ctl_write_complete(struct urb *urb, struct pt_regs *regs) +static void pvr2_ctl_write_complete(struct urb *urb) { struct pvr2_hdw *hdw = urb->context; hdw->ctl_write_pend_flag = 0; @@ -2561,7 +2561,7 @@ static void pvr2_ctl_write_complete(struct urb *urb, struct pt_regs *regs) } -static void pvr2_ctl_read_complete(struct urb *urb, struct pt_regs *regs) +static void pvr2_ctl_read_complete(struct urb *urb) { struct pvr2_hdw *hdw = urb->context; hdw->ctl_read_pend_flag = 0; diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c index 1e393762546c..70aa63eba0cb 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-io.c +++ b/drivers/media/video/pvrusb2/pvrusb2-io.c @@ -429,7 +429,7 @@ static void pvr2_stream_done(struct pvr2_stream *sp) } while (0); mutex_unlock(&sp->mutex); } -static void buffer_complete(struct urb *urb, struct pt_regs *regs) +static void buffer_complete(struct urb *urb) { struct pvr2_buffer *bp = urb->context; struct pvr2_stream *sp; diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 53c4b5790d5c..c77b85cf3d80 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -682,7 +682,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_ /* This gets called for the Isochronous pipe (video). This is done in * interrupt time, so it has to be fast, not crash, and not stall. Neat. */ -static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) +static void pwc_isoc_handler(struct urb *urb) { struct pwc_device *pdev; int i, fst, flen; diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index a39e0136ce3b..4abf5c03a740 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -212,7 +212,7 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev, * */ -static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id) { struct saa7134_dmasound *dmasound = dev_id; struct saa7134_dev *dev = dmasound->priv_data; diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 09aa62f61af7..5c9e63dfbea6 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -495,7 +495,7 @@ static void print_irqstatus(struct saa7134_dev *dev, int loop, printk("\n"); } -static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t saa7134_irq(int irq, void *dev_id) { struct saa7134_dev *dev = (struct saa7134_dev*) dev_id; unsigned long report,status; diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 2e3ba5f31453..bfcb860d14cc 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -814,7 +814,7 @@ struct file_operations saa7134_mixer_fops = { /* ------------------------------------------------------------------ */ -static irqreturn_t saa7134_oss_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t saa7134_oss_irq(int irq, void *dev_id) { struct saa7134_dmasound *dmasound = dev_id; struct saa7134_dev *dev = dmasound->priv_data; diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index 67987baee77a..7aeec574d7ce 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c @@ -282,7 +282,7 @@ static void se401_auto_resetlevel(struct usb_se401 *se401) } /* irq handler for snapshot button */ -static void se401_button_irq(struct urb *urb, struct pt_regs *regs) +static void se401_button_irq(struct urb *urb) { struct usb_se401 *se401 = urb->context; int status; @@ -318,7 +318,7 @@ exit: __FUNCTION__, status); } -static void se401_video_irq(struct urb *urb, struct pt_regs *regs) +static void se401_video_irq(struct urb *urb) { struct usb_se401 *se401 = urb->context; int length = urb->actual_length; diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 48d138a7c723..3e0ff8a78468 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -518,7 +518,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) } -static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs) +static void sn9c102_urb_complete(struct urb *urb) { struct sn9c102_device* cam = urb->context; struct sn9c102_frame_t** f; diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index 5686547ba76a..525d81288d55 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c @@ -406,7 +406,7 @@ static void send_osd_data(struct saa7146 *saa) } } -static irqreturn_t saa7146_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t saa7146_irq(int irq, void *dev_id) { struct saa7146 *saa = dev_id; u32 stat, astat; diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 2ba2991a214f..87e11300181d 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -582,7 +582,7 @@ static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p) return 0; } -static void stv680_video_irq (struct urb *urb, struct pt_regs *regs) +static void stv680_video_irq (struct urb *urb) { struct usb_stv *stv680 = urb->context; int length = urb->actual_length; diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c index 4eee8be88314..abe214619092 100644 --- a/drivers/media/video/usbvideo/konicawc.c +++ b/drivers/media/video/usbvideo/konicawc.c @@ -387,7 +387,7 @@ static void resubmit_urb(struct uvd *uvd, struct urb *urb) } -static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs) +static void konicawc_isoc_irq(struct urb *urb) { struct uvd *uvd = urb->context; struct konicawc *cam = (struct konicawc *)uvd->user_data; diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c index 56e01b622417..9a26b9484aae 100644 --- a/drivers/media/video/usbvideo/quickcam_messenger.c +++ b/drivers/media/video/usbvideo/quickcam_messenger.c @@ -125,7 +125,7 @@ static void qcm_report_buttonstat(struct qcm *cam) } } -static void qcm_int_irq(struct urb *urb, struct pt_regs *regs) +static void qcm_int_irq(struct urb *urb) { int ret; struct uvd *uvd = urb->context; @@ -606,7 +606,7 @@ static void resubmit_urb(struct uvd *uvd, struct urb *urb) err("usb_submit_urb error (%d)", ret); } -static void qcm_isoc_irq(struct urb *urb, struct pt_regs *regs) +static void qcm_isoc_irq(struct urb *urb) { int len; struct uvd *uvd = urb->context; diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c index 13b37c8c0d56..d8b88024bc2f 100644 --- a/drivers/media/video/usbvideo/usbvideo.c +++ b/drivers/media/video/usbvideo/usbvideo.c @@ -1680,7 +1680,7 @@ static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb) return totlen; } -static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs) +static void usbvideo_IsocIrq(struct urb *urb) { int i, ret, len; struct uvd *uvd = urb->context; diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index d1e04f7c530b..6b6dff4d236a 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -2325,7 +2325,7 @@ static void vino_capture_tasklet(unsigned long channel) { } } -static irqreturn_t vino_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t vino_interrupt(int irq, void *dev_id) { u32 ctrl, intr; unsigned int fc_a, fc_b; diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 2912326a5aef..ddce2fb83424 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -417,7 +417,7 @@ static int w9968cf_write_fsb(struct w9968cf_device*, u16* data); static int w9968cf_write_sb(struct w9968cf_device*, u16 value); static int w9968cf_read_sb(struct w9968cf_device*); static int w9968cf_upload_quantizationtables(struct w9968cf_device*); -static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs); +static void w9968cf_urb_complete(struct urb *urb); /* Low-level I2C (SMBus) I/O */ static int w9968cf_smbus_start(struct w9968cf_device*); @@ -781,7 +781,7 @@ static int w9968cf_allocate_memory(struct w9968cf_device* cam) If there are no requested frames in the FIFO list, packets are collected into a temporary buffer. --------------------------------------------------------------------------*/ -static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs) +static void w9968cf_urb_complete(struct urb *urb) { struct w9968cf_device* cam = (struct w9968cf_device*)urb->context; struct w9968cf_frame_t** f; diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 1b2be2d2a3ec..5b5563424422 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -303,7 +303,7 @@ int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value) /*****************************************************************************/ -static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs) +static void zc0301_urb_complete(struct urb *urb) { struct zc0301_device* cam = urb->context; struct zc0301_frame_t** f; diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index 3cbac2e8aed3..d9d5020a2224 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -1408,8 +1408,7 @@ error_handler (struct zoran *zr, irqreturn_t zoran_irq (int irq, - void *dev_id, - struct pt_regs *regs) + void *dev_id) { u32 stat, astat; int count; diff --git a/drivers/media/video/zoran_device.h b/drivers/media/video/zoran_device.h index f19705cbdb39..37fa86a34083 100644 --- a/drivers/media/video/zoran_device.h +++ b/drivers/media/video/zoran_device.h @@ -64,9 +64,7 @@ extern int wait_grab_pending(struct zoran *zr); /* interrupts */ extern void print_interrupts(struct zoran *zr); extern void clear_interrupt_counters(struct zoran *zr); -extern irqreturn_t zoran_irq(int irq, - void *dev_id, - struct pt_regs *regs); +extern irqreturn_t zoran_irq(int irq, void *dev_id); /* JPEG codec access */ extern void jpeg_start(struct zoran *zr); diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c index b5ffe53c40d8..0cbf564388a6 100644 --- a/drivers/media/video/zr36120.c +++ b/drivers/media/video/zr36120.c @@ -335,13 +335,13 @@ DEBUG(printk(CARD_DEBUG "turning off\n",CARD)); } static -void zoran_irq(int irq, void *dev_id, struct pt_regs * regs) +void zoran_irq(int irq, void *dev_id) { u32 stat,estat; int count = 0; struct zoran *ztv = dev_id; - UNUSED(irq); UNUSED(regs); + UNUSED(irq); for (;;) { /* get/clear interrupt status bits */ stat=zrread(ZORAN_ISR); diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 29d0635cce1d..e5c72719debc 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -122,7 +122,7 @@ static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); /* * Forward protos... */ -static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r); +static irqreturn_t mpt_interrupt(int irq, void *bus_id); static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, @@ -351,7 +351,6 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. * @irq: irq number (not used) * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure - * @r: pt_regs pointer (not used) * * This routine is registered via the request_irq() kernel API call, * and handles all interrupts generated from a specific MPT adapter @@ -365,7 +364,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) * the protocol-specific details of the MPT request completion. */ static irqreturn_t -mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) +mpt_interrupt(int irq, void *bus_id) { MPT_ADAPTER *ioc = bus_id; u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c index dec41cc89937..62f1ac08332c 100644 --- a/drivers/message/i2o/pci.c +++ b/drivers/message/i2o/pci.c @@ -224,12 +224,11 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c) * i2o_pci_interrupt - Interrupt handler for I2O controller * @irq: interrupt line * @dev_id: pointer to the I2O controller - * @r: pointer to registers * * Handle an interrupt from a PCI based I2O controller. This turns out * to be rather simple. We keep the controller pointer in the cookie. */ -static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r) +static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id) { struct i2o_controller *c = dev_id; u32 m; diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index 2bf32721eb53..149810a084f5 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -203,7 +203,7 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb) * SIBCLK to talk to the chip. We leave the clock running until * we have finished processing all interrupts from the chip. */ -static irqreturn_t ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs) +static irqreturn_t ucb1x00_irq(int irqnr, void *devid) { struct ucb1x00 *ucb = devid; struct ucb1x00_irq *irq; diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h index 634d538ccd14..48d5abebfc30 100644 --- a/drivers/misc/ibmasm/ibmasm.h +++ b/drivers/misc/ibmasm/ibmasm.h @@ -196,10 +196,10 @@ extern int ibmasm_send_os_state(struct service_processor *sp, int os_state); /* low level message processing */ extern int ibmasm_send_i2o_message(struct service_processor *sp); -extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs); +extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id); /* remote console */ -extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp, struct pt_regs *regs); +extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp); extern int ibmasm_init_remote_input_dev(struct service_processor *sp); extern void ibmasm_free_remote_input_dev(struct service_processor *sp); diff --git a/drivers/misc/ibmasm/lowlevel.c b/drivers/misc/ibmasm/lowlevel.c index 47949a2c7e94..a3c589b7cbfa 100644 --- a/drivers/misc/ibmasm/lowlevel.c +++ b/drivers/misc/ibmasm/lowlevel.c @@ -54,7 +54,7 @@ int ibmasm_send_i2o_message(struct service_processor *sp) return 0; } -irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs) +irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id) { u32 mfa; struct service_processor *sp = (struct service_processor *)dev_id; @@ -67,7 +67,7 @@ irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *reg dbg("respond to interrupt at %s\n", get_timestamp(tsbuf)); if (mouse_interrupt_pending(sp)) { - ibmasm_handle_mouse_interrupt(sp, regs); + ibmasm_handle_mouse_interrupt(sp); clear_mouse_interrupt(sp); } diff --git a/drivers/misc/ibmasm/remote.c b/drivers/misc/ibmasm/remote.c index 0f9e3aa34d07..a40fda6c402c 100644 --- a/drivers/misc/ibmasm/remote.c +++ b/drivers/misc/ibmasm/remote.c @@ -158,12 +158,10 @@ static void print_input(struct remote_input *input) } } -static void send_mouse_event(struct input_dev *dev, struct pt_regs *regs, - struct remote_input *input) +static void send_mouse_event(struct input_dev *dev, struct remote_input *input) { unsigned char buttons = input->mouse_buttons; - input_regs(dev, regs); input_report_abs(dev, ABS_X, input->data.mouse.x); input_report_abs(dev, ABS_Y, input->data.mouse.y); input_report_key(dev, BTN_LEFT, buttons & REMOTE_BUTTON_LEFT); @@ -172,7 +170,7 @@ static void send_mouse_event(struct input_dev *dev, struct pt_regs *regs, input_sync(dev); } -static void send_keyboard_event(struct input_dev *dev, struct pt_regs *regs, +static void send_keyboard_event(struct input_dev *dev, struct remote_input *input) { unsigned int key; @@ -182,13 +180,11 @@ static void send_keyboard_event(struct input_dev *dev, struct pt_regs *regs, key = xlate_high[code & 0xff]; else key = xlate[code]; - input_regs(dev, regs); input_report_key(dev, key, (input->data.keyboard.key_down) ? 1 : 0); input_sync(dev); } -void ibmasm_handle_mouse_interrupt(struct service_processor *sp, - struct pt_regs *regs) +void ibmasm_handle_mouse_interrupt(struct service_processor *sp) { unsigned long reader; unsigned long writer; @@ -203,9 +199,9 @@ void ibmasm_handle_mouse_interrupt(struct service_processor *sp, print_input(&input); if (input.type == INPUT_TYPE_MOUSE) { - send_mouse_event(sp->remote.mouse_dev, regs, &input); + send_mouse_event(sp->remote.mouse_dev, &input); } else if (input.type == INPUT_TYPE_KEYBOARD) { - send_keyboard_event(sp->remote.keybd_dev, regs, &input); + send_keyboard_event(sp->remote.keybd_dev, &input); } else break; diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index e689ee94ac3d..bbdba7b37e11 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -127,15 +127,14 @@ module_param(cpoint_count, int, 06444); MODULE_PARM_DESC(cpoint_count, "Crash Point Count, number of times the \ crash point is to be hit to trigger action"); -unsigned int jp_do_irq(unsigned int irq, struct pt_regs *regs) +unsigned int jp_do_irq(unsigned int irq) { lkdtm_handler(); jprobe_return(); return 0; } -irqreturn_t jp_handle_irq_event(unsigned int irq, struct pt_regs *regs, - struct irqaction *action) +irqreturn_t jp_handle_irq_event(unsigned int irq, struct irqaction *action) { lkdtm_handler(); jprobe_return(); diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index a7ed30446185..b1748669e05b 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -67,7 +67,7 @@ static void tifm_7xx1_remove_media(void *adapter) class_device_put(&fm->cdev); } -static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) { struct tifm_adapter *fm = dev_id; unsigned int irq_status; diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index cb142a66098c..494b23fb0a01 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -661,7 +661,7 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) /* * Handle an interrupt */ -static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t at91_mci_irq(int irq, void *devid) { struct at91mci_host *host = devid; int completed = 0; @@ -754,7 +754,7 @@ static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t at91_mmc_det_irq(int irq, void *_host, struct pt_regs *regs) +static irqreturn_t at91_mmc_det_irq(int irq, void *_host) { struct at91mci_host *host = _host; int present = !at91_get_gpio_value(irq); diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index 61268da13957..53ffcbb14a97 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -750,7 +750,7 @@ static void au1xmmc_dma_callback(int irq, void *dev_id) #define STATUS_DATA_IN (SD_STATUS_NE) #define STATUS_DATA_OUT (SD_STATUS_TH) -static irqreturn_t au1xmmc_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t au1xmmc_irq(int irq, void *dev_id) { u32 status; diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index 1b79dd271aae..659d4a822cc5 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -635,7 +635,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat) return trans_done; } -static void imxmci_dma_irq(int dma, void *devid, struct pt_regs *regs) +static void imxmci_dma_irq(int dma, void *devid) { struct imxmci_host *host = devid; uint32_t stat = MMC_STATUS; @@ -646,7 +646,7 @@ static void imxmci_dma_irq(int dma, void *devid, struct pt_regs *regs) tasklet_schedule(&host->tasklet); } -static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t imxmci_irq(int irq, void *devid) { struct imxmci_host *host = devid; uint32_t stat = MMC_STATUS; diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 2b5a0cc9ea56..828503c4ee62 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -261,7 +261,7 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem /* * PIO data transfer IRQ handler. */ -static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mmci_pio_irq(int irq, void *dev_id) { struct mmci_host *host = dev_id; void __iomem *base = host->base; @@ -347,7 +347,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) /* * Handle completion of command and data transfers. */ -static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mmci_irq(int irq, void *dev_id) { struct mmci_host *host = dev_id; u32 status; diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c index 52c9e52e6b78..762fa2895891 100644 --- a/drivers/mmc/omap.c +++ b/drivers/mmc/omap.c @@ -377,7 +377,7 @@ static inline void mmc_omap_report_irq(u16 status) } } -static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mmc_omap_irq(int irq, void *dev_id) { struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id; u16 status; @@ -514,7 +514,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id) { struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id; diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index ef350908478c..a526698b8c91 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -299,7 +299,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) return 1; } -static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t pxamci_irq(int irq, void *devid) { struct pxamci_host *host = devid; unsigned int ireg; @@ -399,13 +399,13 @@ static struct mmc_host_ops pxamci_ops = { .set_ios = pxamci_set_ios, }; -static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs) +static void pxamci_dma_irq(int dma, void *devid) { printk(KERN_ERR "DMA%d: IRQ???\n", dma); DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; } -static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t pxamci_detect_irq(int irq, void *devid) { struct pxamci_host *host = mmc_priv(devid); diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 20711acb0120..6d024342b2fd 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -985,7 +985,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } } -static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sdhci_irq(int irq, void *dev_id) { irqreturn_t result; struct sdhci_host* host = dev_id; diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 88c6f0b129f5..ced309b37a8f 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1256,7 +1256,7 @@ end: * Interrupt handling */ -static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t wbsd_irq(int irq, void *dev_id) { struct wbsd_host *host = dev_id; int isr; diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 1b82bccd8c71..11d170afa9c3 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -496,7 +496,6 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) * el_interrupt: * @irq: Interrupt number * @dev_id: The 3c501 that burped - * @regs: Register data (surplus to our requirements) * * Handle the ether interface interrupts. The 3c501 needs a lot more * hand holding than most cards. In particular we get a transmit interrupt @@ -515,7 +514,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) * TCP window. */ -static irqreturn_t el_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t el_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct net_local *lp; diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h index 39d332474750..c56a2c62f7de 100644 --- a/drivers/net/3c501.h +++ b/drivers/net/3c501.h @@ -7,7 +7,7 @@ static int el1_probe1(struct net_device *dev, int ioaddr); static int el_open(struct net_device *dev); static void el_timeout(struct net_device *dev); static int el_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t el_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t el_interrupt(int irq, void *dev_id); static void el_receive(struct net_device *dev); static void el_reset(struct net_device *dev); static int el1_close(struct net_device *dev); diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index ab8230a68bea..458cb9cbe915 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -649,7 +649,7 @@ static void receive_packet(struct net_device *dev, int len) * ******************************************************/ -static irqreturn_t elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr) +static irqreturn_t elp_interrupt(int irq, void *dev_id) { int len; int dlen; diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 8205a535c5b7..aa43563610ae 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -286,7 +286,7 @@ static unsigned short init_words[] = { static int el16_probe1(struct net_device *dev, int ioaddr); static int el16_open(struct net_device *dev); static int el16_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t el16_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t el16_interrupt(int irq, void *dev_id); static void el16_rx(struct net_device *dev); static int el16_close(struct net_device *dev); static struct net_device_stats *el16_get_stats(struct net_device *dev); @@ -543,7 +543,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev) /* The typical workload of the driver: Handle the network interface interrupts. */ -static irqreturn_t el16_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t el16_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct net_local *lp; diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index b936373ab2a5..7ad0a54779c4 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -191,7 +191,7 @@ static ushort id_read_eeprom(int index); static ushort read_eeprom(int ioaddr, int index); static int el3_open(struct net_device *dev); static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t el3_interrupt(int irq, void *dev_id); static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); static int el3_rx(struct net_device *dev); @@ -910,7 +910,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev) /* The EL3 interrupt handler. */ static irqreturn_t -el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +el3_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct el3_private *lp; @@ -1006,7 +1006,7 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void el3_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - el3_interrupt(dev->irq, dev, NULL); + el3_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 91f2232e6050..c307ce66145c 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -373,8 +373,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, static int corkscrew_rx(struct net_device *dev); static void corkscrew_timeout(struct net_device *dev); static int boomerang_rx(struct net_device *dev); -static irqreturn_t corkscrew_interrupt(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t corkscrew_interrupt(int irq, void *dev_id); static int corkscrew_close(struct net_device *dev); static void update_stats(int addr, struct net_device *dev); static struct net_device_stats *corkscrew_get_stats(struct net_device *dev); @@ -1116,8 +1115,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t corkscrew_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) { /* Use the now-standard shared IRQ implementation. */ struct net_device *dev = dev_id; diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index cf8a0bc3bf34..1c97271112d0 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -180,7 +180,7 @@ sizeof(nop_cmd) = 8; dev->name,__LINE__); \ elmc_id_reset586(); } } } -static irqreturn_t elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr); +static irqreturn_t elmc_interrupt(int irq, void *dev_id); static int elmc_open(struct net_device *dev); static int elmc_close(struct net_device *dev); static int elmc_send_packet(struct sk_buff *, struct net_device *); @@ -900,14 +900,14 @@ static void *alloc_rfa(struct net_device *dev, void *ptr) */ static irqreturn_t -elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr) +elmc_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; unsigned short stat; struct priv *p; if (dev == NULL) { - printk(KERN_ERR "elmc-interrupt: irq %d for unknown device.\n", (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2)); + printk(KERN_ERR "elmc-interrupt: irq %d for unknown device.\n", irq); return IRQ_NONE; } else if (!netif_running(dev)) { /* The 3c523 has this habit of generating interrupts during the diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 625e57dc3b4a..d516c3225ca4 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -217,7 +217,7 @@ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int le static int mc32_open(struct net_device *dev); static void mc32_timeout(struct net_device *dev); static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t mc32_interrupt(int irq, void *dev_id); static int mc32_close(struct net_device *dev); static struct net_device_stats *mc32_get_stats(struct net_device *dev); static void mc32_set_multicast_list(struct net_device *dev); @@ -1316,7 +1316,7 @@ static void mc32_tx_ring(struct net_device *dev) * */ -static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t mc32_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct mc32_local *lp; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index df42e28cc80f..80bdcf846234 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -717,8 +717,8 @@ static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev); static int vortex_rx(struct net_device *dev); static int boomerang_rx(struct net_device *dev); -static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t vortex_interrupt(int irq, void *dev_id); +static irqreturn_t boomerang_interrupt(int irq, void *dev_id); static int vortex_close(struct net_device *dev); static void dump_tx_ring(struct net_device *dev); static void update_stats(void __iomem *ioaddr, struct net_device *dev); @@ -794,7 +794,7 @@ static void poll_vortex(struct net_device *dev) unsigned long flags; local_save_flags(flags); local_irq_disable(); - (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL); + (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev); local_irq_restore(flags); } #endif @@ -1849,9 +1849,9 @@ static void vortex_tx_timeout(struct net_device *dev) unsigned long flags; local_irq_save(flags); if (vp->full_bus_master_tx) - boomerang_interrupt(dev->irq, dev, NULL); + boomerang_interrupt(dev->irq, dev); else - vortex_interrupt(dev->irq, dev, NULL); + vortex_interrupt(dev->irq, dev); local_irq_restore(flags); } } @@ -2149,7 +2149,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) */ static irqreturn_t -vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) +vortex_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct vortex_private *vp = netdev_priv(dev); @@ -2254,7 +2254,7 @@ handler_exit: */ static irqreturn_t -boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) +boomerang_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct vortex_private *vp = netdev_priv(dev); diff --git a/drivers/net/7990.c b/drivers/net/7990.c index db7b19a5cd59..8e996b4a34ea 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -438,7 +438,7 @@ static int lance_tx (struct net_device *dev) } static irqreturn_t -lance_interrupt (int irq, void *dev_id, struct pt_regs *regs) +lance_interrupt (int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct lance_private *lp = netdev_priv(dev); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 5a4990ae3730..458dd9f830c4 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -631,8 +631,7 @@ rx_next: return 1; /* not done */ } -static irqreturn_t -cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t cp_interrupt (int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct cp_private *cp; @@ -696,7 +695,7 @@ cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs) static void cp_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - cp_interrupt(dev->irq, dev, NULL); + cp_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index dbc5c0b1b96c..d02ed51abfcc 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -629,8 +629,7 @@ static int rtl8139_poll(struct net_device *dev, int *budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void rtl8139_poll_controller(struct net_device *dev); #endif -static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance, - struct pt_regs *regs); +static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance); static int rtl8139_close (struct net_device *dev); static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); @@ -2146,8 +2145,7 @@ static int rtl8139_poll(struct net_device *dev, int *budget) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance) { struct net_device *dev = (struct net_device *) dev_instance; struct rtl8139_private *tp = netdev_priv(dev); @@ -2219,7 +2217,7 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance, static void rtl8139_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - rtl8139_interrupt(dev->irq, dev, NULL); + rtl8139_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/net/82596.c b/drivers/net/82596.c index c9e4dca9d410..8236f26ffd46 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -357,7 +357,7 @@ static char init_setup[] = static int i596_open(struct net_device *dev); static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t i596_interrupt(int irq, void *dev_id); static int i596_close(struct net_device *dev); static struct net_device_stats *i596_get_stats(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); @@ -501,7 +501,7 @@ static void i596_display_data(struct net_device *dev) #if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET) -static irqreturn_t i596_error(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t i596_error(int irq, void *dev_id) { struct net_device *dev = dev_id; #ifdef ENABLE_MVME16x_NET @@ -1283,7 +1283,7 @@ out: return ERR_PTR(err); } -static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t i596_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct i596_private *lp; @@ -1294,7 +1294,7 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs) #ifdef ENABLE_BVME6000_NET if (MACH_IS_BVME6000) { if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) { - i596_error(irq, dev_id, regs); + i596_error(irq, dev_id); return IRQ_HANDLED; } } diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 9d34056147ad..fa3442cb1a49 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -391,7 +391,6 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) * ei_interrupt - handle the interrupts from an 8390 * @irq: interrupt number * @dev_id: a pointer to the net_device - * @regs: unused * * Handle the ether interface interrupts. We pull packets from * the 8390 via the card specific functions and fire them at the networking @@ -400,7 +399,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) * needed. */ -irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) +irqreturn_t ei_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; long e8390_base; @@ -506,7 +505,7 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) void ei_poll(struct net_device *dev) { disable_irq_lockdep(dev->irq); - ei_interrupt(dev->irq, dev, NULL); + ei_interrupt(dev->irq, dev); enable_irq_lockdep(dev->irq); } #endif diff --git a/drivers/net/8390.h b/drivers/net/8390.h index ca4eb0ccf8cf..f44f1220b3a5 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -35,7 +35,7 @@ extern void ei_poll(struct net_device *dev); extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); -extern irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t ei_interrupt(int irq, void *dev_id); extern struct net_device *__alloc_ei_netdev(int size); static inline struct net_device *alloc_ei_netdev(void) { diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 5f7258fea19d..d76548e75350 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -425,8 +425,7 @@ static int lance_tx (struct net_device *dev) return 0; } -static irqreturn_t -lance_interrupt (int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t lance_interrupt (int irq, void *dev_id) { struct net_device *dev; struct lance_private *lp; diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 71a4f60f7325..33c6645455ae 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2144,7 +2144,7 @@ static inline void ace_tx_int(struct net_device *dev, } -static irqreturn_t ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) +static irqreturn_t ace_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct ace_private *ap = netdev_priv(dev); diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h index efb14b9f4d90..8ca8534d70bf 100644 --- a/drivers/net/acenic.h +++ b/drivers/net/acenic.h @@ -769,7 +769,7 @@ static int ace_init(struct net_device *dev); static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs); static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs); static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs); -static irqreturn_t ace_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t ace_interrupt(int irq, void *dev_id); static int ace_load_firmware(struct net_device *dev); static int ace_open(struct net_device *dev); static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev); diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 28855a01ed7b..ef65e5917c8f 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1257,7 +1257,7 @@ static int amd8111e_calc_coalesce(struct net_device *dev) /* This is device interrupt function. It handles transmit, receive,link change and hardware timer interrupts. */ -static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t amd8111e_interrupt(int irq, void *dev_id) { struct net_device * dev = (struct net_device *) dev_id; @@ -1336,7 +1336,7 @@ static void amd8111e_poll(struct net_device *dev) unsigned long flags; local_save_flags(flags); local_irq_disable(); - amd8111e_interrupt(0, dev, NULL); + amd8111e_interrupt(0, dev); local_irq_restore(flags); } #endif diff --git a/drivers/net/apne.c b/drivers/net/apne.c index 643b08cc7403..9164d8cd670e 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -88,7 +88,7 @@ static void apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset); static void apne_block_output(struct net_device *dev, const int count, const unsigned char *buf, const int start_page); -static irqreturn_t apne_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t apne_interrupt(int irq, void *dev_id); static int init_pcmcia(void); @@ -543,7 +543,7 @@ apne_block_output(struct net_device *dev, int count, return; } -static irqreturn_t apne_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t apne_interrupt(int irq, void *dev_id) { unsigned char pcmcia_intreq; @@ -559,7 +559,7 @@ static irqreturn_t apne_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (ei_debug > 3) printk("pcmcia intreq = %x\n", pcmcia_intreq); pcmcia_disable_irq(); /* to get rid of the sti() within ei_interrupt */ - ei_interrupt(irq, dev_id, regs); + ei_interrupt(irq, dev_id); pcmcia_ack_int(pcmcia_get_intreq()); pcmcia_enable_irq(); return IRQ_HANDLED; diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index ae7f828344d9..cc1a27ed197f 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -188,7 +188,7 @@ static void cops_reset (struct net_device *dev, int sleep); static void cops_load (struct net_device *dev); static int cops_nodeid (struct net_device *dev, int nodeid); -static irqreturn_t cops_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t cops_interrupt (int irq, void *dev_id); static void cops_poll (unsigned long ltdev); static void cops_timeout(struct net_device *dev); static void cops_rx (struct net_device *dev); @@ -721,7 +721,7 @@ static void cops_poll(unsigned long ltdev) * The typical workload of the driver: * Handle the network interface interrupts. */ -static irqreturn_t cops_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t cops_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct cops_local *lp; diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index d5666c37cb0d..2ea44ce49810 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -790,7 +790,7 @@ static int sendup_buffer (struct net_device *dev) /* the handler for the board interrupt */ static irqreturn_t -ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr) +ltpc_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 5a95005253fa..4e91dab1f17f 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -752,7 +752,7 @@ static void arcnet_timeout(struct net_device *dev) * interrupts. Establish which device needs attention, and call the correct * chipset interrupt handler. */ -irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t arcnet_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct arcnet_local *lp; diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 3aef3c10d56f..9dfc09b181c1 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -120,7 +120,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev); static void ariadne_tx_timeout(struct net_device *dev); static int ariadne_rx(struct net_device *dev); static void ariadne_reset(struct net_device *dev); -static irqreturn_t ariadne_interrupt(int irq, void *data, struct pt_regs *fp); +static irqreturn_t ariadne_interrupt(int irq, void *data); static int ariadne_close(struct net_device *dev); static struct net_device_stats *ariadne_get_stats(struct net_device *dev); #ifdef HAVE_MULTICAST @@ -416,7 +416,7 @@ static inline void ariadne_reset(struct net_device *dev) } -static irqreturn_t ariadne_interrupt(int irq, void *data, struct pt_regs *fp) +static irqreturn_t ariadne_interrupt(int irq, void *data) { struct net_device *dev = (struct net_device *)data; volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 09d5c3f26985..ddd12d44ff22 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -38,7 +38,7 @@ #include "am79c961a.h" static irqreturn_t -am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs); +am79c961_interrupt (int irq, void *dev_id); static unsigned int net_debug = NET_DEBUG; @@ -596,7 +596,7 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv) } static irqreturn_t -am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) +am79c961_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct dev_priv *priv = netdev_priv(dev); diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 3ecf2cc53a7c..b54b857e357e 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -196,7 +196,7 @@ static void update_linkspeed(struct net_device *dev, int silent) /* * Handle interrupts from the PHY */ -static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct at91_private *lp = (struct at91_private *) dev->priv; @@ -888,7 +888,7 @@ static void at91ether_rx(struct net_device *dev) /* * MAC interrupt handler */ -static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t at91ether_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct at91_private *lp = (struct at91_private *) dev->priv; diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index d231efa624d4..127561c782fd 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -435,7 +435,7 @@ static void ep93xx_tx_complete(struct net_device *dev) netif_wake_queue(dev); } -static irqreturn_t ep93xx_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ep93xx_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; struct ep93xx_priv *ep = netdev_priv(dev); diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index 312955d07b28..f3478a30e778 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -68,7 +68,7 @@ static unsigned int net_debug = NET_DEBUG; static int ether1_open(struct net_device *dev); static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t ether1_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t ether1_interrupt(int irq, void *dev_id); static int ether1_close(struct net_device *dev); static struct net_device_stats *ether1_getstats(struct net_device *dev); static void ether1_setmulticastlist(struct net_device *dev); @@ -908,7 +908,7 @@ ether1_recv_done (struct net_device *dev) } static irqreturn_t -ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs) +ether1_interrupt (int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; int status; diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 081074180e62..84686c8a5bc2 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -81,7 +81,7 @@ static int ether3_rx(struct net_device *dev, unsigned int maxcnt); static void ether3_tx(struct net_device *dev); static int ether3_open (struct net_device *dev); static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev); -static irqreturn_t ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t ether3_interrupt (int irq, void *dev_id); static int ether3_close (struct net_device *dev); static struct net_device_stats *ether3_getstats (struct net_device *dev); static void ether3_setmulticastlist (struct net_device *dev); @@ -568,7 +568,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) } static irqreturn_t -ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +ether3_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; unsigned int status, handled = IRQ_NONE; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 4aeca11f3ee2..8620a5b470f5 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -161,7 +161,7 @@ static int at1700_probe1(struct net_device *dev, int ioaddr); static int read_eeprom(long ioaddr, int location); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t net_interrupt(int irq, void *dev_id); static void net_rx(struct net_device *dev); static int net_close(struct net_device *dev); static struct net_device_stats *net_get_stats(struct net_device *dev); @@ -648,8 +648,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev) /* The typical workload of the driver: Handle the network interface interrupts. */ -static irqreturn_t -net_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t net_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct net_local *lp; diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c index 92b52138acad..4e3bf6a1f22c 100644 --- a/drivers/net/atari_bionet.c +++ b/drivers/net/atari_bionet.c @@ -220,7 +220,7 @@ gsend: } static irqreturn_t -bionet_intr(int irq, void *data, struct pt_regs *fp) { +bionet_intr(int irq, void *data) { return IRQ_HANDLED; } diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c index a1026251b933..3b5436149286 100644 --- a/drivers/net/atari_pamsnet.c +++ b/drivers/net/atari_pamsnet.c @@ -163,7 +163,7 @@ static int pamsnet_close(struct net_device *dev); static struct net_device_stats *net_get_stats(struct net_device *dev); static void pamsnet_tick(unsigned long); -static irqreturn_t pamsnet_intr(int irq, void *data, struct pt_regs *fp); +static irqreturn_t pamsnet_intr(int irq, void *data); static DEFINE_TIMER(pamsnet_timer, pamsnet_tick, 0, 0); @@ -494,7 +494,6 @@ static irqreturn_t pamsnet_intr(irq, data, fp) int irq; void *data; - struct pt_regs *fp; { return IRQ_HANDLED; } diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index b6570ca6ada7..d79489e46249 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -344,7 +344,7 @@ static unsigned long lance_probe1( struct net_device *dev, struct lance_addr static int lance_open( struct net_device *dev ); static void lance_init_ring( struct net_device *dev ); static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); -static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp ); +static irqreturn_t lance_interrupt( int irq, void *dev_id ); static int lance_rx( struct net_device *dev ); static int lance_close( struct net_device *dev ); static struct net_device_stats *lance_get_stats( struct net_device *dev ); @@ -866,7 +866,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) /* The LANCE interrupt handler. */ -static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t lance_interrupt( int irq, void *dev_id ) { struct net_device *dev = dev_id; struct lance_private *lp; diff --git a/drivers/net/atp.c b/drivers/net/atp.c index f2c8e0d5497b..062f80e20874 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -203,7 +203,7 @@ static void hardware_init(struct net_device *dev); static void write_packet(long ioaddr, int length, unsigned char *packet, int pad, int mode); static void trigger_send(long ioaddr, int length); static int atp_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t atp_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t atp_interrupt(int irq, void *dev_id); static void net_rx(struct net_device *dev); static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode); static int net_close(struct net_device *dev); @@ -596,8 +596,7 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) /* The typical workload of the driver: Handle the network interface interrupts. */ -static irqreturn_t -atp_interrupt(int irq, void *dev_instance, struct pt_regs * regs) +static irqreturn_t atp_interrupt(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *)dev_instance; struct net_local *lp; diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index ac33b1b9cf4a..4873dc610d22 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -89,7 +89,7 @@ static int au1000_open(struct net_device *); static int au1000_close(struct net_device *); static int au1000_tx(struct sk_buff *, struct net_device *); static int au1000_rx(struct net_device *); -static irqreturn_t au1000_interrupt(int, void *, struct pt_regs *); +static irqreturn_t au1000_interrupt(int, void *); static void au1000_tx_timeout(struct net_device *); static void set_rx_mode(struct net_device *); static struct net_device_stats *au1000_get_stats(struct net_device *); @@ -1253,7 +1253,7 @@ static int au1000_rx(struct net_device *dev) /* * Au1000 interrupt service routine. */ -static irqreturn_t au1000_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t au1000_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index e891ea2ecc3c..b124eee4eb10 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -896,7 +896,7 @@ static int b44_poll(struct net_device *netdev, int *budget) return (done ? 0 : 1); } -static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t b44_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct b44 *bp = netdev_priv(dev); @@ -1461,7 +1461,7 @@ out: static void b44_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - b44_interrupt(dev->irq, dev, NULL); + b44_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 4adfe7b77031..4528ce9c4e43 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -152,9 +152,9 @@ static void bmac_init_chip(struct net_device *dev); static void bmac_init_registers(struct net_device *dev); static void bmac_enable_and_reset_chip(struct net_device *dev); static int bmac_set_address(struct net_device *dev, void *addr); -static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t bmac_misc_intr(int irq, void *dev_id); +static irqreturn_t bmac_txdma_intr(int irq, void *dev_id); +static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id); static void bmac_set_timeout(struct net_device *dev); static void bmac_tx_timeout(unsigned long data); static int bmac_output(struct sk_buff *skb, struct net_device *dev); @@ -688,7 +688,7 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev) static int rxintcount; -static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct bmac_data *bp = netdev_priv(dev); @@ -765,7 +765,7 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) static int txintcount; -static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t bmac_txdma_intr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct bmac_data *bp = netdev_priv(dev); @@ -1082,7 +1082,7 @@ static void bmac_set_multicast(struct net_device *dev) static int miscintcount; -static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t bmac_misc_intr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct bmac_data *bp = netdev_priv(dev); @@ -1091,7 +1091,7 @@ static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs) XXDEBUG(("bmac_misc_intr\n")); } /* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */ - /* bmac_txdma_intr_inner(irq, dev_id, regs); */ + /* bmac_txdma_intr_inner(irq, dev_id); */ /* if (status & FrameReceived) bp->stats.rx_dropped++; */ if (status & RxErrorMask) bp->stats.rx_errors++; if (status & RxCRCCntExp) bp->stats.rx_crc_errors++; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 6b4edb63c4c4..01b76d3aa42f 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -1888,7 +1888,7 @@ next_rx: * is that the MSI interrupt is always serviced. */ static irqreturn_t -bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs) +bnx2_msi(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct bnx2 *bp = netdev_priv(dev); @@ -1908,7 +1908,7 @@ bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs) } static irqreturn_t -bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +bnx2_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct bnx2 *bp = netdev_priv(dev); @@ -5554,7 +5554,7 @@ poll_bnx2(struct net_device *dev) struct bnx2 *bp = netdev_priv(dev); disable_irq(bp->pdev->irq); - bnx2_interrupt(bp->pdev->irq, dev, NULL); + bnx2_interrupt(bp->pdev->irq, dev); enable_irq(bp->pdev->irq); } #endif diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 7694365092f8..521c5b71023c 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2469,7 +2469,7 @@ static inline void cas_handle_irqN(struct net_device *dev, cas_post_rxcs_ringN(dev, cp, ring); } -static irqreturn_t cas_interruptN(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cas_interruptN(int irq, void *dev_id) { struct net_device *dev = dev_id; struct cas *cp = netdev_priv(dev); @@ -2522,7 +2522,7 @@ static inline void cas_handle_irq1(struct cas *cp, const u32 status) } /* ring 2 handles a few more events than 3 and 4 */ -static irqreturn_t cas_interrupt1(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cas_interrupt1(int irq, void *dev_id) { struct net_device *dev = dev_id; struct cas *cp = netdev_priv(dev); @@ -2574,7 +2574,7 @@ static inline void cas_handle_irq(struct net_device *dev, cas_post_rxcs_ringN(dev, cp, 0); } -static irqreturn_t cas_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cas_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct cas *cp = netdev_priv(dev); @@ -2689,7 +2689,7 @@ static void cas_netpoll(struct net_device *dev) struct cas *cp = netdev_priv(dev); cas_disable_irq(cp, 0); - cas_interrupt(cp->pdev->irq, dev, NULL); + cas_interrupt(cp->pdev->irq, dev); cas_enable_irq(cp, 0); #ifdef USE_PCI_INTB diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 5f1b06753462..ad7ff9641a7e 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -918,7 +918,7 @@ static void t1_netpoll(struct net_device *dev) struct adapter *adapter = dev->priv; local_irq_save(flags); - t1_select_intr_handler(adapter)(adapter->pdev->irq, adapter, NULL); + t1_select_intr_handler(adapter)(adapter->pdev->irq, adapter); local_irq_restore(flags); } #endif diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index ddd0bdb498f4..9799c12380fc 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1217,7 +1217,7 @@ static inline int napi_is_scheduled(struct net_device *dev) /* * NAPI version of the main interrupt handler. */ -static irqreturn_t t1_interrupt_napi(int irq, void *data, struct pt_regs *regs) +static irqreturn_t t1_interrupt_napi(int irq, void *data) { int handled; struct adapter *adapter = data; @@ -1279,7 +1279,7 @@ static irqreturn_t t1_interrupt_napi(int irq, void *data, struct pt_regs *regs) * 5. If we took an interrupt, but no valid respQ descriptors was found we * let the slow_intr_handler run and do error handling. */ -static irqreturn_t t1_interrupt(int irq, void *cookie, struct pt_regs *regs) +static irqreturn_t t1_interrupt(int irq, void *cookie) { int work_done; struct respQ_e *e; @@ -1312,7 +1312,7 @@ static irqreturn_t t1_interrupt(int irq, void *cookie, struct pt_regs *regs) return IRQ_RETVAL(work_done != 0); } -intr_handler_t t1_select_intr_handler(adapter_t *adapter) +irq_handler_t t1_select_intr_handler(adapter_t *adapter) { return adapter->params.sge.polling ? t1_interrupt_napi : t1_interrupt; } diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h index 6d0d24a6364f..91af47bab7be 100644 --- a/drivers/net/chelsio/sge.h +++ b/drivers/net/chelsio/sge.h @@ -43,13 +43,6 @@ #include #include -#ifndef IRQ_RETVAL -#define IRQ_RETVAL(x) -typedef void irqreturn_t; -#endif - -typedef irqreturn_t (*intr_handler_t)(int, void *, struct pt_regs *); - struct sge_intr_counts { unsigned int respQ_empty; /* # times respQ empty */ unsigned int respQ_overflow; /* # respQ overflow (fatal) */ @@ -88,7 +81,7 @@ struct sge *t1_sge_create(struct adapter *, struct sge_params *); int t1_sge_configure(struct sge *, struct sge_params *); int t1_sge_set_coalesce_params(struct sge *, struct sge_params *); void t1_sge_destroy(struct sge *); -intr_handler_t t1_select_intr_handler(adapter_t *adapter); +irq_handler_t t1_select_intr_handler(adapter_t *adapter); int t1_start_xmit(struct sk_buff *skb, struct net_device *dev); void t1_set_vlan_accel(struct adapter *adapter, int on_off); void t1_sge_start(struct sge *); diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index f1501b6f247e..966b563e42bb 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -403,8 +403,8 @@ static int etrax_ethernet_init(void); static int e100_open(struct net_device *dev); static int e100_set_mac_address(struct net_device *dev, void *addr); static int e100_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id); +static irqreturn_t e100nw_interrupt(int irq, void *dev_id); static void e100_rx(struct net_device *dev); static int e100_close(struct net_device *dev); static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); @@ -1197,7 +1197,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev) */ static irqreturn_t -e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs) +e100rxtx_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct net_local *np = (struct net_local *)dev->priv; @@ -1264,7 +1264,7 @@ e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs) } static irqreturn_t -e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs) +e100nw_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct net_local *np = (struct net_local *)dev->priv; diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index e4d50f0de930..4ffc9b44a8e1 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -249,7 +249,7 @@ struct net_local { static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t net_interrupt(int irq, void *dev_id); static void set_multicast_list(struct net_device *dev); static void net_timeout(struct net_device *dev); static void net_rx(struct net_device *dev); @@ -495,7 +495,7 @@ get_eeprom_cksum(int off, int len, int *buffer) static void net_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - net_interrupt(dev->irq, dev, NULL); + net_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif @@ -1573,7 +1573,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) /* The typical workload of the driver: Handle the network interface interrupts. */ -static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t net_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct net_local *lp; diff --git a/drivers/net/de600.c b/drivers/net/de600.c index 0b930da5d47d..d9b006c9e367 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -258,7 +258,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) * Handle the network interface interrupts. */ -static irqreturn_t de600_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t de600_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; u8 irq_status; diff --git a/drivers/net/de600.h b/drivers/net/de600.h index e4073015dcd8..1288e48ba704 100644 --- a/drivers/net/de600.h +++ b/drivers/net/de600.h @@ -125,7 +125,7 @@ static struct net_device_stats *get_stats(struct net_device *dev); static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev); /* Dispatch from interrupts. */ -static irqreturn_t de600_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t de600_interrupt(int irq, void *dev_id); static int de600_tx_intr(struct net_device *dev, int irq_status); static void de600_rx_intr(struct net_device *dev); diff --git a/drivers/net/de620.c b/drivers/net/de620.c index a18d4d14b665..b6ad0cb50552 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -221,7 +221,7 @@ static void de620_set_multicast_list(struct net_device *); static int de620_start_xmit(struct sk_buff *, struct net_device *); /* Dispatch from interrupts. */ -static irqreturn_t de620_interrupt(int, void *, struct pt_regs *); +static irqreturn_t de620_interrupt(int, void *); static int de620_rx_intr(struct net_device *); /* Initialization */ @@ -591,7 +591,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) * */ static irqreturn_t -de620_interrupt(int irq_in, void *dev_id, struct pt_regs *regs) +de620_interrupt(int irq_in, void *dev_id) { struct net_device *dev = dev_id; byte irq_status; diff --git a/drivers/net/declance.c b/drivers/net/declance.c index bbccd741cdbf..e179aa1c1ba0 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -694,8 +694,7 @@ out: spin_unlock(&lp->lock); } -static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; @@ -703,8 +702,7 @@ static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id, return IRQ_HANDLED; } -static irqreturn_t lance_interrupt(const int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t lance_interrupt(const int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct lance_private *lp = netdev_priv(dev); diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index ae9680552b82..8f514cc0debd 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -248,8 +248,7 @@ static int dfx_close(struct net_device *dev); static void dfx_int_pr_halt_id(DFX_board_t *bp); static void dfx_int_type_0_process(DFX_board_t *bp); static void dfx_int_common(struct net_device *dev); -static irqreturn_t dfx_interrupt(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t dfx_interrupt(int irq, void *dev_id); static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev); static void dfx_ctl_set_multicast_list(struct net_device *dev); @@ -1693,7 +1692,6 @@ static void dfx_int_common(struct net_device *dev) * Arguments: * irq - interrupt vector * dev_id - pointer to device information - * regs - pointer to registers structure * * Functional Description: * This routine calls the interrupt processing routine for this adapter. It @@ -1716,7 +1714,7 @@ static void dfx_int_common(struct net_device *dev) * Interrupts are disabled, then reenabled at the adapter. */ -static irqreturn_t dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dfx_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; DFX_board_t *bp; /* private board structure pointer */ diff --git a/drivers/net/depca.c b/drivers/net/depca.c index af594664df51..f87f6e3dc721 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -518,7 +518,7 @@ struct depca_private { */ static int depca_open(struct net_device *dev); static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t depca_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t depca_interrupt(int irq, void *dev_id); static int depca_close(struct net_device *dev); static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void depca_tx_timeout(struct net_device *dev); @@ -965,7 +965,7 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev) /* ** The DEPCA interrupt handler. */ -static irqreturn_t depca_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t depca_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct depca_private *lp; diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index d0842527b369..6b1234b09fb3 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -895,7 +895,7 @@ static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd) * dev, priv will always refer to the 0th device in Multi-NIC mode. */ -static irqreturn_t dgrs_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dgrs_intr(int irq, void *dev_id) { struct net_device *dev0 = (struct net_device *) dev_id; DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 7e95cf1a4872..9d446a0fe0bf 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -60,7 +60,7 @@ static void rio_timer (unsigned long data); static void rio_tx_timeout (struct net_device *dev); static void alloc_list (struct net_device *dev); static int start_xmit (struct sk_buff *skb, struct net_device *dev); -static irqreturn_t rio_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t rio_interrupt (int irq, void *dev_instance); static void rio_free_tx (struct net_device *dev, int irq); static void tx_error (struct net_device *dev, int tx_status); static int receive_packet (struct net_device *dev); @@ -665,7 +665,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) } static irqreturn_t -rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs) +rio_interrupt (int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct netdev_private *np; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index a860ebbbf815..3641f3b4a2cc 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -159,7 +159,7 @@ static void dm9000_init_dm9000(struct net_device *); static struct net_device_stats *dm9000_get_stats(struct net_device *); -static irqreturn_t dm9000_interrupt(int, void *, struct pt_regs *); +static irqreturn_t dm9000_interrupt(int, void *); static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg); static void dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, @@ -804,7 +804,7 @@ dm9000_tx_done(struct net_device *dev, board_info_t * db) } static irqreturn_t -dm9000_interrupt(int irq, void *dev_id, struct pt_regs *regs) +dm9000_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; board_info_t *db; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 26073c345213..27d5d2f02533 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1949,7 +1949,7 @@ static int e100_rx_alloc_list(struct nic *nic) return 0; } -static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t e100_intr(int irq, void *dev_id) { struct net_device *netdev = dev_id; struct nic *nic = netdev_priv(netdev); @@ -2005,7 +2005,7 @@ static void e100_netpoll(struct net_device *netdev) struct nic *nic = netdev_priv(netdev); e100_disable_irq(nic); - e100_intr(nic->pdev->irq, netdev, NULL); + e100_intr(nic->pdev->irq, netdev); e100_tx_clean(nic); e100_enable_irq(nic); } diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 778ede3c0216..773821e4cf57 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -883,8 +883,7 @@ e1000_eeprom_test(struct e1000_adapter *adapter, uint64_t *data) static irqreturn_t e1000_test_intr(int irq, - void *data, - struct pt_regs *regs) + void *data) { struct net_device *netdev = (struct net_device *) data; struct e1000_adapter *adapter = netdev_priv(netdev); diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7dca38fba6a1..ce0d35fe3947 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -153,7 +153,7 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev); static struct net_device_stats * e1000_get_stats(struct net_device *netdev); static int e1000_change_mtu(struct net_device *netdev, int new_mtu); static int e1000_set_mac(struct net_device *netdev, void *p); -static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs); +static irqreturn_t e1000_intr(int irq, void *data); static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring); #ifdef CONFIG_E1000_NAPI @@ -3436,11 +3436,10 @@ e1000_update_stats(struct e1000_adapter *adapter) * e1000_intr - Interrupt Handler * @irq: interrupt number * @data: pointer to a network interface device structure - * @pt_regs: CPU registers structure **/ static irqreturn_t -e1000_intr(int irq, void *data, struct pt_regs *regs) +e1000_intr(int irq, void *data) { struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); @@ -4862,7 +4861,7 @@ e1000_netpoll(struct net_device *netdev) struct e1000_adapter *adapter = netdev_priv(netdev); disable_irq(adapter->pdev->irq); - e1000_intr(adapter->pdev->irq, netdev, NULL); + e1000_intr(adapter->pdev->irq, netdev); e1000_clean_tx_irq(adapter, adapter->tx_ring); #ifndef CONFIG_E1000_NAPI adapter->clean_rx(adapter, adapter->rx_ring); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 09ff9b9418f4..aae454aaa1c6 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -311,7 +311,7 @@ struct eepro_local { static int eepro_probe1(struct net_device *dev, int autoprobe); static int eepro_open(struct net_device *dev); static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t eepro_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t eepro_interrupt(int irq, void *dev_id); static void eepro_rx(struct net_device *dev); static void eepro_transmit_interrupt(struct net_device *dev); static int eepro_close(struct net_device *dev); @@ -1196,7 +1196,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) Handle the network interface interrupts. */ static irqreturn_t -eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs) +eepro_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; /* (struct net_device *)(irq2dev_map[irq]);*/ diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 499e93b31f54..e28bb1e38f8d 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -488,7 +488,7 @@ static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev); static void speedo_refill_rx_buffers(struct net_device *dev, int force); static int speedo_rx(struct net_device *dev); static void speedo_tx_buffer_gc(struct net_device *dev); -static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t speedo_interrupt(int irq, void *dev_instance); static int speedo_close(struct net_device *dev); static struct net_device_stats *speedo_get_stats(struct net_device *dev); static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -606,7 +606,7 @@ static void poll_speedo (struct net_device *dev) /* disable_irq is not very nice, but with the funny lockless design we have no other choice. */ disable_irq(dev->irq); - speedo_interrupt (dev->irq, dev, NULL); + speedo_interrupt (dev->irq, dev); enable_irq(dev->irq); } #endif @@ -1541,7 +1541,7 @@ static void speedo_tx_buffer_gc(struct net_device *dev) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t speedo_interrupt(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *)dev_instance; struct speedo_private *sp; diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 9cb05d99ee1b..05ca730fe81e 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -249,7 +249,7 @@ static void eexp_timeout(struct net_device *dev); static struct net_device_stats *eexp_stats(struct net_device *dev); static int eexp_xmit(struct sk_buff *buf, struct net_device *dev); -static irqreturn_t eexp_irq(int irq, void *dev_addr, struct pt_regs *regs); +static irqreturn_t eexp_irq(int irq, void *dev_addr); static void eexp_set_multicast(struct net_device *dev); /* @@ -789,7 +789,7 @@ static void eexp_cmd_clear(struct net_device *dev) } } -static irqreturn_t eexp_irq(int irq, void *dev_info, struct pt_regs *regs) +static irqreturn_t eexp_irq(int irq, void *dev_info) { struct net_device *dev = dev_info; struct net_local *lp; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 263d1c5b3f23..c6b31775e26b 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -536,16 +536,14 @@ void ehea_send_irq_tasklet(unsigned long data) tasklet_hi_schedule(&pr->send_comp_task); } -static irqreturn_t ehea_send_irq_handler(int irq, void *param, - struct pt_regs *regs) +static irqreturn_t ehea_send_irq_handler(int irq, void *param) { struct ehea_port_res *pr = param; tasklet_hi_schedule(&pr->send_comp_task); return IRQ_HANDLED; } -static irqreturn_t ehea_recv_irq_handler(int irq, void *param, - struct pt_regs *regs) +static irqreturn_t ehea_recv_irq_handler(int irq, void *param) { struct ehea_port_res *pr = param; struct ehea_port *port = pr->port; @@ -553,8 +551,7 @@ static irqreturn_t ehea_recv_irq_handler(int irq, void *param, return IRQ_HANDLED; } -static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param, - struct pt_regs *regs) +static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) { struct ehea_port *port = param; struct ehea_eqe *eqe; @@ -850,8 +847,7 @@ static void ehea_neq_tasklet(unsigned long data) adapter->neq->fw_handle, event_mask); } -static irqreturn_t ehea_interrupt_neq(int irq, void *param, - struct pt_regs *regs) +static irqreturn_t ehea_interrupt_neq(int irq, void *param) { struct ehea_adapter *adapter = param; tasklet_hi_schedule(&adapter->neq_tasklet); diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index ba2565ee0439..3a6a83d3ee1c 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -297,7 +297,7 @@ static void epic_init_ring(struct net_device *dev); static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev); static int epic_rx(struct net_device *dev, int budget); static int epic_poll(struct net_device *dev, int *budget); -static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t epic_interrupt(int irq, void *dev_instance); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops netdev_ethtool_ops; static int epic_close(struct net_device *dev); @@ -1081,7 +1081,7 @@ static void epic_tx(struct net_device *dev, struct epic_private *ep) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t epic_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct epic_private *ep = dev->priv; diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index f16b6a5aaa34..8cc3c331aca8 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -410,7 +410,7 @@ static int eth16i_close(struct net_device *dev); static int eth16i_tx(struct sk_buff *skb, struct net_device *dev); static void eth16i_rx(struct net_device *dev); static void eth16i_timeout(struct net_device *dev); -static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t eth16i_interrupt(int irq, void *dev_id); static void eth16i_reset(struct net_device *dev); static void eth16i_timeout(struct net_device *dev); static void eth16i_skip_packet(struct net_device *dev); @@ -1226,7 +1226,7 @@ static void eth16i_rx(struct net_device *dev) } /* while */ } -static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t eth16i_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct eth16i_local *lp; diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 75a43f7c70cf..c8c41f0a47d6 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -300,7 +300,7 @@ struct ewrk3_private { */ static int ewrk3_open(struct net_device *dev); static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t ewrk3_interrupt(int irq, void *dev_id); static int ewrk3_close(struct net_device *dev); static struct net_device_stats *ewrk3_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -884,7 +884,7 @@ err_out: /* ** The EWRK3 interrupt handler. */ -static irqreturn_t ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ewrk3_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct ewrk3_private *lp; diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 191bd429076a..38a13f440530 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -434,7 +434,7 @@ static void reset_timer(unsigned long data); static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t intr_handler(int irq, void *dev_instance); static int netdev_rx(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static void __set_rx_mode(struct net_device *dev); @@ -1453,7 +1453,7 @@ static void reset_rx_descriptors(struct net_device *dev) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +static irqreturn_t intr_handler(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *) dev_instance; struct netdev_private *np = netdev_priv(dev); diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 55d86bc4c104..6764281b4531 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -229,7 +229,7 @@ struct fec_enet_private { static int fec_enet_open(struct net_device *dev); static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); static void fec_enet_mii(struct net_device *dev); -static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); static void fec_enet_tx(struct net_device *dev); static void fec_enet_rx(struct net_device *dev); static int fec_enet_close(struct net_device *dev); @@ -450,7 +450,7 @@ fec_timeout(struct net_device *dev) * This is called from the MPC core interrupt. */ static irqreturn_t -fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +fec_enet_interrupt(int irq, void * dev_id) { struct net_device *dev = dev_id; volatile fec_t *fecp; @@ -1236,7 +1236,7 @@ static void mii_link_interrupt(void *dev_id); #else static irqreturn_t -mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs); +mii_link_interrupt(int irq, void * dev_id); #endif #endif @@ -1251,7 +1251,7 @@ static void __inline__ fec_request_intrs(struct net_device *dev) static const struct idesc { char *name; unsigned short irq; - irqreturn_t (*handler)(int, void *, struct pt_regs *); + irq_handler_t handler; } *idp, id[] = { { "fec(RX)", 86, fec_enet_interrupt }, { "fec(TX)", 87, fec_enet_interrupt }, @@ -2117,7 +2117,7 @@ static void mii_link_interrupt(void *dev_id) #else static irqreturn_t -mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) +mii_link_interrupt(int irq, void * dev_id) #endif { struct net_device *dev = dev_id; diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c index e17a1449ee10..8e7a56fadfd2 100644 --- a/drivers/net/fec_8xx/fec_main.c +++ b/drivers/net/fec_8xx/fec_main.c @@ -708,7 +708,7 @@ static void fec_enet_tx(struct net_device *dev) * This is called from the MPC core interrupt. */ static irqreturn_t -fec_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +fec_enet_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct fec_enet_private *fep; @@ -768,7 +768,7 @@ fec_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* This interrupt occurs when the PHY detects a link change. */ static irqreturn_t -fec_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs) +fec_mii_link_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct fec_enet_private *fep; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index eea1d66c530e..99b7a411db28 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -2397,7 +2397,7 @@ static void nv_link_irq(struct net_device *dev) dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name); } -static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) +static irqreturn_t nv_nic_irq(int foo, void *data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); @@ -2490,7 +2490,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) return IRQ_RETVAL(i); } -static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) +static irqreturn_t nv_nic_irq_tx(int foo, void *data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); @@ -2576,7 +2576,7 @@ static int nv_napi_poll(struct net_device *dev, int *budget) #endif #ifdef CONFIG_FORCEDETH_NAPI -static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) +static irqreturn_t nv_nic_irq_rx(int foo, void *data) { struct net_device *dev = (struct net_device *) data; u8 __iomem *base = get_hwbase(dev); @@ -2594,7 +2594,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) return IRQ_HANDLED; } #else -static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) +static irqreturn_t nv_nic_irq_rx(int foo, void *data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); @@ -2641,7 +2641,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) } #endif -static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) +static irqreturn_t nv_nic_irq_other(int foo, void *data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); @@ -2695,7 +2695,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) return IRQ_RETVAL(i); } -static irqreturn_t nv_nic_irq_test(int foo, void *data, struct pt_regs *regs) +static irqreturn_t nv_nic_irq_test(int foo, void *data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); @@ -2905,22 +2905,22 @@ static void nv_do_nic_poll(unsigned long data) pci_push(base); if (!using_multi_irqs(dev)) { - nv_nic_irq(0, dev, NULL); + nv_nic_irq(0, dev); if (np->msi_flags & NV_MSI_X_ENABLED) enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); else enable_irq_lockdep(dev->irq); } else { if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) { - nv_nic_irq_rx(0, dev, NULL); + nv_nic_irq_rx(0, dev); enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); } if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) { - nv_nic_irq_tx(0, dev, NULL); + nv_nic_irq_tx(0, dev); enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); } if (np->nic_poll_irq & NVREG_IRQ_OTHER) { - nv_nic_irq_other(0, dev, NULL); + nv_nic_irq_other(0, dev); enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); } } diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index d01870619a4a..cb3958704a87 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -441,7 +441,7 @@ static void fs_enet_tx(struct net_device *dev) * This is called from the MPC core interrupt. */ static irqreturn_t -fs_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +fs_enet_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct fs_enet_private *fep; @@ -667,7 +667,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) } static int fs_request_irq(struct net_device *dev, int irq, const char *name, - irqreturn_t (*irqf)(int irq, void *dev_id, struct pt_regs *regs)) + irq_handler_t irqf) { struct fs_enet_private *fep = netdev_priv(dev); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 280b114e253f..a06d8d1aaceb 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -119,9 +119,9 @@ struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp); static struct net_device_stats *gfar_get_stats(struct net_device *dev); static int gfar_set_mac_address(struct net_device *dev); static int gfar_change_mtu(struct net_device *dev, int new_mtu); -static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t gfar_error(int irq, void *dev_id); +static irqreturn_t gfar_transmit(int irq, void *dev_id); +static irqreturn_t gfar_interrupt(int irq, void *dev_id); static void adjust_link(struct net_device *dev); static void init_registers(struct net_device *dev); static int init_phy(struct net_device *dev); @@ -1173,7 +1173,7 @@ static void gfar_timeout(struct net_device *dev) } /* Interrupt Handler for Transmit complete */ -static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t gfar_transmit(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct gfar_private *priv = netdev_priv(dev); @@ -1305,7 +1305,7 @@ static inline void count_errors(unsigned short status, struct gfar_private *priv } } -irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t gfar_receive(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct gfar_private *priv = netdev_priv(dev); @@ -1537,7 +1537,7 @@ static int gfar_poll(struct net_device *dev, int *budget) #endif /* The interrupt handler for devices with one interrupt */ -static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t gfar_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct gfar_private *priv = netdev_priv(dev); @@ -1550,11 +1550,11 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* Check for reception */ if ((events & IEVENT_RXF0) || (events & IEVENT_RXB0)) - gfar_receive(irq, dev_id, regs); + gfar_receive(irq, dev_id); /* Check for transmit completion */ if ((events & IEVENT_TXF) || (events & IEVENT_TXB)) - gfar_transmit(irq, dev_id, regs); + gfar_transmit(irq, dev_id); /* Update error statistics */ if (events & IEVENT_TXE) { @@ -1578,7 +1578,7 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs) priv->stats.rx_errors++; priv->extra_stats.rx_bsy++; - gfar_receive(irq, dev_id, regs); + gfar_receive(irq, dev_id); #ifndef CONFIG_GFAR_NAPI /* Clear the halt bit in RSTAT */ @@ -1857,7 +1857,7 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr) } /* GFAR error interrupt handler */ -static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t gfar_error(int irq, void *dev_id) { struct net_device *dev = dev_id; struct gfar_private *priv = netdev_priv(dev); @@ -1898,7 +1898,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs) priv->stats.rx_errors++; priv->extra_stats.rx_bsy++; - gfar_receive(irq, dev_id, regs); + gfar_receive(irq, dev_id); #ifndef CONFIG_GFAR_NAPI /* Clear the halt bit in RSTAT */ diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index c35d47c40c39..9e81a50cf2be 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -754,7 +754,7 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val) out_be32(addr, val); } -extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t gfar_receive(int irq, void *dev_id); extern int startup_gfar(struct net_device *dev); extern void stop_gfar(struct net_device *dev); extern void gfar_halt(struct net_device *dev); diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 5c89ae78a519..c3c0d67fc383 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -556,7 +556,7 @@ static void hamachi_timer(unsigned long data); static void hamachi_tx_timeout(struct net_device *dev); static void hamachi_init_ring(struct net_device *dev); static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t hamachi_interrupt(int irq, void *dev_instance); static int hamachi_rx(struct net_device *dev); static inline int hamachi_tx(struct net_device *dev); static void hamachi_error(struct net_device *dev, int intr_status); @@ -1376,7 +1376,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) +static irqreturn_t hamachi_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct hamachi_private *hmp = netdev_priv(dev); diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 9220de9f4fe7..1ed9cccd3c11 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -323,7 +323,7 @@ static int eppconfig(struct baycom_state *bc) /* ---------------------------------------------------------------------- */ -static void epp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void epp_interrupt(int irq, void *dev_id) { } diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c index 77411a00d1ee..5930aeb35015 100644 --- a/drivers/net/hamradio/baycom_par.c +++ b/drivers/net/hamradio/baycom_par.c @@ -270,7 +270,7 @@ static __inline__ void par96_rx(struct net_device *dev, struct baycom_state *bc) /* --------------------------------------------------------------------- */ -static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void par96_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct baycom_state *bc = netdev_priv(dev); diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c index 55906c7b4bb1..59214e74b9cf 100644 --- a/drivers/net/hamradio/baycom_ser_fdx.c +++ b/drivers/net/hamradio/baycom_ser_fdx.c @@ -279,7 +279,7 @@ static __inline__ void ser12_rx(struct net_device *dev, struct baycom_state *bc, /* --------------------------------------------------------------------- */ -static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ser12_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct baycom_state *bc = netdev_priv(dev); diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c index de95de8983da..3bcc57acbe6d 100644 --- a/drivers/net/hamradio/baycom_ser_hdx.c +++ b/drivers/net/hamradio/baycom_ser_hdx.c @@ -373,7 +373,7 @@ static inline void ser12_rx(struct net_device *dev, struct baycom_state *bc) /* --------------------------------------------------------------------- */ -static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ser12_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct baycom_state *bc = netdev_priv(dev); diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index c9a46b89942a..0f8b9afd55b4 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -249,7 +249,7 @@ static void start_timer(struct scc_priv *priv, int t, int r15); static inline unsigned char random(void); static inline void z8530_isr(struct scc_info *info); -static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t scc_isr(int irq, void *dev_id); static void rx_isr(struct scc_priv *priv); static void special_condition(struct scc_priv *priv, int rc); static void rx_bh(void *arg); @@ -1142,7 +1142,7 @@ static inline void z8530_isr(struct scc_info *info) } -static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t scc_isr(int irq, void *dev_id) { struct scc_info *info = dev_id; diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index df4b68142ac7..ec9b6d9b6f05 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -200,7 +200,7 @@ static void z8530_init(void); static void init_channel(struct scc_channel *scc); static void scc_key_trx (struct scc_channel *scc, char tx); -static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t scc_isr(int irq, void *dev_id); static void scc_init_timer(struct scc_channel *scc); static int scc_net_alloc(const char *name, struct scc_channel *scc); @@ -626,7 +626,7 @@ static void scc_isr_dispatch(struct scc_channel *scc, int vector) #define SCC_IRQTIMEOUT 30000 -static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t scc_isr(int irq, void *dev_id) { unsigned char vector; struct scc_channel *scc; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index f98f5777dfbb..3c4455bd466d 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -702,7 +702,7 @@ static void yam_tx_byte(struct net_device *dev, struct yam_port *yp) * ISR routine ************************************************************************************/ -static irqreturn_t yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t yam_interrupt(int irq, void *dev_id) { struct net_device *dev; struct yam_port *yp; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index ae8ad4f763bf..844c136e9920 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -249,7 +249,7 @@ static void hp100_misc_interrupt(struct net_device *dev); static void hp100_update_stats(struct net_device *dev); static void hp100_clear_stats(struct hp100_private *lp, int ioaddr); static void hp100_set_multicast_list(struct net_device *dev); -static irqreturn_t hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t hp100_interrupt(int irq, void *dev_id); static void hp100_start_interface(struct net_device *dev); static void hp100_stop_interface(struct net_device *dev); static void hp100_load_eeprom(struct net_device *dev, u_short ioaddr); @@ -2187,7 +2187,7 @@ static void hp100_set_multicast_list(struct net_device *dev) * hardware interrupt handling */ -static irqreturn_t hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t hp100_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct hp100_private *lp = netdev_priv(dev); diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index d52e3bd01301..ffeafb28f782 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -184,7 +184,7 @@ static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { "tx_errors" }; -static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t emac_irq(int irq, void *dev_instance); static void emac_clean_tx_ring(struct ocp_enet_private *dev); static inline int emac_phy_supports_gige(int phy_mode) @@ -1515,7 +1515,7 @@ static void emac_rxde(void *param) } /* Hard IRQ */ -static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t emac_irq(int irq, void *dev_instance) { struct ocp_enet_private *dev = dev_instance; struct emac_regs __iomem *p = dev->emacp; diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c index c3645908034d..92f970d402df 100644 --- a/drivers/net/ibm_emac/ibm_emac_debug.c +++ b/drivers/net/ibm_emac/ibm_emac_debug.c @@ -179,8 +179,7 @@ void emac_dbg_dump_all(void) } #if defined(CONFIG_MAGIC_SYSRQ) -static void emac_sysrq_handler(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void emac_sysrq_handler(int key, struct tty_struct *tty) { emac_dbg_dump_all(); } diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c index af50e7b2e0d7..6c0f071e4052 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ b/drivers/net/ibm_emac/ibm_emac_mal.c @@ -168,7 +168,7 @@ static inline void mal_disable_eob_irq(struct ibm_ocp_mal *mal) MAL_DBG2("%d: disable_irq" NL, mal->def->index); } -static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t mal_serr(int irq, void *dev_instance) { struct ibm_ocp_mal *mal = dev_instance; u32 esr = get_mal_dcrn(mal, MAL_ESR); @@ -216,7 +216,7 @@ static inline void mal_schedule_poll(struct ibm_ocp_mal *mal) MAL_DBG2("%d: already in poll" NL, mal->def->index); } -static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t mal_txeob(int irq, void *dev_instance) { struct ibm_ocp_mal *mal = dev_instance; u32 r = get_mal_dcrn(mal, MAL_TXEOBISR); @@ -226,7 +226,7 @@ static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t mal_rxeob(int irq, void *dev_instance) { struct ibm_ocp_mal *mal = dev_instance; u32 r = get_mal_dcrn(mal, MAL_RXEOBISR); @@ -236,7 +236,7 @@ static irqreturn_t mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t mal_txde(int irq, void *dev_instance) { struct ibm_ocp_mal *mal = dev_instance; u32 deir = get_mal_dcrn(mal, MAL_TXDEIR); @@ -252,7 +252,7 @@ static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t mal_rxde(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t mal_rxde(int irq, void *dev_instance) { struct ibm_ocp_mal *mal = dev_instance; struct list_head *l; diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 2a95d72fa593..3f946c811511 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -705,7 +705,7 @@ static void irqtxerr_handler(struct net_device *dev) /* general interrupt entry */ -static irqreturn_t irq_handler(int irq, void *device, struct pt_regs *regs) +static irqreturn_t irq_handler(int irq, void *device) { struct net_device *dev = (struct net_device *) device; u16 ival; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 767203d35bc2..4bac3cd8f235 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -93,7 +93,7 @@ static void ibmveth_proc_register_driver(void); static void ibmveth_proc_unregister_driver(void); static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); -static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance); static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); static struct kobj_type ktype_veth_pool; @@ -543,7 +543,7 @@ static int ibmveth_open(struct net_device *netdev) } ibmveth_debug_printk("initial replenish cycle\n"); - ibmveth_interrupt(netdev->irq, netdev, NULL); + ibmveth_interrupt(netdev->irq, netdev); netif_start_queue(netdev); @@ -816,7 +816,7 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) return 0; } -static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance) { struct net_device *netdev = dev_instance; struct ibmveth_adapter *adapter = netdev->priv; @@ -1261,7 +1261,7 @@ const char * buf, size_t count) } /* kick the interrupt handler to allocate/deallocate pools */ - ibmveth_interrupt(netdev->irq, netdev, NULL); + ibmveth_interrupt(netdev->irq, netdev); return count; } diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 87650237dc5c..e963dbf816be 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -750,7 +750,7 @@ static void ioc3_error(struct ioc3_private *ip, u32 eisr) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs) +static irqreturn_t ioc3_interrupt(int irq, void *_dev) { struct net_device *dev = (struct net_device *)_dev; struct ioc3_private *ip = netdev_priv(dev); diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 68d4c418cb98..971e2dee1e6b 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -660,8 +660,7 @@ static int ali_ircc_read_dongle_id (int i, chipio_t *info) * An interrupt from the chip has arrived. Time to do some work * */ -static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct ali_ircc_cb *self; diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index 7b2b4135bb23..37914dc5b90e 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -51,7 +51,7 @@ static int au1k_irda_start(struct net_device *); static int au1k_irda_stop(struct net_device *dev); static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *); static int au1k_irda_rx(struct net_device *); -static void au1k_irda_interrupt(int, void *, struct pt_regs *); +static void au1k_irda_interrupt(int, void *); static void au1k_tx_timeout(struct net_device *); static struct net_device_stats *au1k_irda_stats(struct net_device *); static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int); @@ -627,7 +627,7 @@ static int au1k_irda_rx(struct net_device *dev) } -void au1k_irda_interrupt(int irq, void *dev_id, struct pt_regs *regs) +void au1k_irda_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 33c07d5275da..7a9128181e68 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -709,7 +709,7 @@ stuff_byte (__u8 byte, __u8 * buf) } static irqreturn_t -toshoboe_probeinterrupt (int irq, void *dev_id, struct pt_regs *regs) +toshoboe_probeinterrupt (int irq, void *dev_id) { struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id; __u8 irqstat; @@ -1161,7 +1161,7 @@ dumpbufs(skb->data,skb->len,'>'); /*interrupt handler */ static irqreturn_t -toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs) +toshoboe_interrupt (int irq, void *dev_id) { struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id; __u8 irqstat; diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 383cef1f5999..14bda765c2fa 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -114,9 +114,9 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev); static int irda_usb_open(struct irda_usb_cb *self); static void irda_usb_close(struct irda_usb_cb *self); -static void speed_bulk_callback(struct urb *urb, struct pt_regs *regs); -static void write_bulk_callback(struct urb *urb, struct pt_regs *regs); -static void irda_usb_receive(struct urb *urb, struct pt_regs *regs); +static void speed_bulk_callback(struct urb *urb); +static void write_bulk_callback(struct urb *urb); +static void irda_usb_receive(struct urb *urb); static void irda_usb_rx_defer_expired(unsigned long data); static int irda_usb_net_open(struct net_device *dev); static int irda_usb_net_close(struct net_device *dev); @@ -343,7 +343,7 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) * Speed URB callback * Now, we can only get called for the speed URB. */ -static void speed_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void speed_bulk_callback(struct urb *urb) { struct irda_usb_cb *self = urb->context; @@ -562,7 +562,7 @@ drop: /* * Note : this function will be called only for tx_urb... */ -static void write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void write_bulk_callback(struct urb *urb) { unsigned long flags; struct sk_buff *skb = urb->context; @@ -809,7 +809,7 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struc * Called by the USB subsystem when a frame has been received * */ -static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) +static void irda_usb_receive(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct irda_usb_cb *self; diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index ba4f3eb988b3..6ea78ececca7 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -87,8 +87,7 @@ static struct net_device_stats *irport_net_get_stats(struct net_device *dev); static int irport_change_speed_complete(struct irda_task *task); static void irport_timeout(struct net_device *dev); -static irqreturn_t irport_interrupt(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t irport_interrupt(int irq, void *dev_id); static int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev); static void irport_change_speed(void *priv, __u32 speed); static int irport_net_open(struct net_device *dev); @@ -761,12 +760,11 @@ static inline void irport_receive(struct irport_cb *self) } /* - * Function irport_interrupt (irq, dev_id, regs) + * Function irport_interrupt (irq, dev_id) * * Interrupt handler */ -static irqreturn_t irport_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t irport_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct irport_cb *self; diff --git a/drivers/net/irda/irport.h b/drivers/net/irda/irport.h index fc89c8c3dd7f..4393168347e3 100644 --- a/drivers/net/irda/irport.h +++ b/drivers/net/irda/irport.h @@ -74,7 +74,7 @@ struct irport_cb { /* For piggyback drivers */ void *priv; void (*change_speed)(void *priv, __u32 speed); - int (*interrupt)(int irq, void *dev_id, struct pt_regs *regs); + int (*interrupt)(int irq, void *dev_id); }; #endif /* IRPORT_H */ diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 415ba8dc94ce..b32c52ed19d7 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -764,7 +764,7 @@ static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev) } /* Receive callback function. */ -static void mcs_receive_irq(struct urb *urb, struct pt_regs *regs) +static void mcs_receive_irq(struct urb *urb) { __u8 *bytes; struct mcs_cb *mcs = urb->context; @@ -813,7 +813,7 @@ static void mcs_receive_irq(struct urb *urb, struct pt_regs *regs) } /* Transmit callback funtion. */ -static void mcs_send_irq(struct urb *urb, struct pt_regs *regs) +static void mcs_send_irq(struct urb *urb) { struct mcs_cb *mcs = urb->context; struct net_device *ndev = mcs->netdev; diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h index 1a723d725c2a..b18148cee638 100644 --- a/drivers/net/irda/mcs7780.h +++ b/drivers/net/irda/mcs7780.h @@ -156,8 +156,8 @@ static int mcs_net_close(struct net_device *netdev); static int mcs_net_open(struct net_device *netdev); static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev); -static void mcs_receive_irq(struct urb *urb, struct pt_regs *regs); -static void mcs_send_irq(struct urb *urb, struct pt_regs *regs); +static void mcs_receive_irq(struct urb *urb); +static void mcs_send_irq(struct urb *urb); static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *netdev); static int mcs_probe(struct usb_interface *intf, diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 7185a4ee3c1e..ea12e999814a 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -2066,8 +2066,7 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, * An interrupt from the chip has arrived. Time to do some work * */ -static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct nsc_ircc_cb *self; diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index afb19e8d95c8..f9a1c88a4283 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -199,7 +199,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed) } /* SIR interrupt service routine. */ -static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; struct pxa_irda *si = netdev_priv(dev); @@ -281,7 +281,7 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id, struct pt_regs *regs) } /* FIR Receive DMA interrupt handler */ -static void pxa_irda_fir_dma_rx_irq(int channel, void *data, struct pt_regs *regs) +static void pxa_irda_fir_dma_rx_irq(int channel, void *data) { int dcsr = DCSR(channel); @@ -291,7 +291,7 @@ static void pxa_irda_fir_dma_rx_irq(int channel, void *data, struct pt_regs *reg } /* FIR Transmit DMA interrupt handler */ -static void pxa_irda_fir_dma_tx_irq(int channel, void *data, struct pt_regs *regs) +static void pxa_irda_fir_dma_tx_irq(int channel, void *data) { struct net_device *dev = data; struct pxa_irda *si = netdev_priv(dev); @@ -388,7 +388,7 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev) } /* FIR interrupt handler */ -static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; struct pxa_irda *si = netdev_priv(dev); diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 8d5a288d7976..937372d00398 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -579,7 +579,7 @@ static void sa1100_irda_fir_irq(struct net_device *dev) sa1100_irda_rx_dma_start(si); } -static irqreturn_t sa1100_irda_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; if (IS_FIR(((struct sa1100_irda *)dev->priv))) diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 22358ff68c4c..31c623381ea8 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -196,7 +196,7 @@ static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs); static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self); static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed); static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, u32 speed); -static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id); static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev); static void smsc_ircc_sir_start(struct smsc_ircc_cb *self); #if SMSC_IRCC2_C_SIR_STOP @@ -1455,7 +1455,7 @@ static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self) * An interrupt from the chip has arrived. Time to do some work * */ -static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct smsc_ircc_cb *self; @@ -1520,7 +1520,7 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *re } /* - * Function irport_interrupt_sir (irq, dev_id, regs) + * Function irport_interrupt_sir (irq, dev_id) * * Interrupt handler for SIR modes */ diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 12103c93f7ef..be8a66e702b0 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -804,7 +804,7 @@ static int stir_transmit_thread(void *arg) * Wakes up every ms (usb round trip) with wrapped * data. */ -static void stir_rcv_irq(struct urb *urb, struct pt_regs *regs) +static void stir_rcv_irq(struct urb *urb) { struct stir_cb *stir = urb->context; int err; diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index d916e1257c47..c3ed9b3067e5 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -93,8 +93,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); static void via_hw_init(struct via_ircc_cb *self); static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 baud); -static irqreturn_t via_ircc_interrupt(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t via_ircc_interrupt(int irq, void *dev_id); static int via_ircc_is_receiving(struct via_ircc_cb *self); static int via_ircc_read_dongle_id(int iobase); @@ -1345,13 +1344,12 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) /* - * Function via_ircc_interrupt (irq, dev_id, regs) + * Function via_ircc_interrupt (irq, dev_id) * * An interrupt from the chip has arrived. Time to do some work * */ -static irqreturn_t via_ircc_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t via_ircc_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct via_ircc_cb *self; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 92d646cc9edc..18c68193bf14 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1455,8 +1455,7 @@ static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) /********************************************************/ -static irqreturn_t vlsi_interrupt(int irq, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t vlsi_interrupt(int irq, void *dev_instance) { struct net_device *ndev = dev_instance; vlsi_irda_dev_t *idev = ndev->priv; diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 7de1afdeec3d..b4fb92a7baa8 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -1111,8 +1111,7 @@ static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr) * An interrupt from the chip has arrived. Time to do some work * */ -static irqreturn_t w83977af_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t w83977af_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct w83977af_ir *self; diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 984c31d1b3fb..0343f12d2ffb 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -107,7 +107,7 @@ struct net_local { static int netcard_probe1(struct net_device *dev, int ioaddr); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t net_interrupt(int irq, void *dev_id); static void net_rx(struct net_device *dev); static int net_close(struct net_device *dev); static struct net_device_stats *net_get_stats(struct net_device *dev); @@ -504,7 +504,7 @@ void net_tx(struct net_device *dev) * The typical workload of the driver: * Handle the network interface interrupts. */ -static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t net_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct net_local *np; diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 41b1d08fd57b..2284e2ce1692 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -586,7 +586,7 @@ static void veth_handle_int(struct veth_lpevent *event) }; } -static void veth_handle_event(struct HvLpEvent *event, struct pt_regs *regs) +static void veth_handle_event(struct HvLpEvent *event) { struct veth_lpevent *veth_event = (struct veth_lpevent *)event; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index cfde7c2569bb..e09f575a3a38 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -93,7 +93,7 @@ static int ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev); static struct net_device_stats *ixgb_get_stats(struct net_device *netdev); static int ixgb_change_mtu(struct net_device *netdev, int new_mtu); static int ixgb_set_mac(struct net_device *netdev, void *p); -static irqreturn_t ixgb_intr(int irq, void *data, struct pt_regs *regs); +static irqreturn_t ixgb_intr(int irq, void *data); static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter); #ifdef CONFIG_IXGB_NAPI @@ -1687,11 +1687,10 @@ ixgb_update_stats(struct ixgb_adapter *adapter) * ixgb_intr - Interrupt Handler * @irq: interrupt number * @data: pointer to a network interface device structure - * @pt_regs: CPU registers structure **/ static irqreturn_t -ixgb_intr(int irq, void *data, struct pt_regs *regs) +ixgb_intr(int irq, void *data) { struct net_device *netdev = data; struct ixgb_adapter *adapter = netdev_priv(netdev); @@ -2213,7 +2212,7 @@ static void ixgb_netpoll(struct net_device *dev) struct ixgb_adapter *adapter = netdev_priv(dev); disable_irq(adapter->pdev->irq); - ixgb_intr(adapter->pdev->irq, dev, NULL); + ixgb_intr(adapter->pdev->irq, dev); enable_irq(adapter->pdev->irq); } #endif diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 6eeb965b4d72..a4eccb11d677 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -188,7 +188,7 @@ static void ixpdev_tx_complete(void) } } -static irqreturn_t ixpdev_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ixpdev_interrupt(int irq, void *dev_id) { u32 status; diff --git a/drivers/net/lance.c b/drivers/net/lance.c index f349e88e0ddf..7afac47e59ad 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -301,7 +301,7 @@ static int lance_open(struct net_device *dev); static void lance_init_ring(struct net_device *dev, gfp_t mode); static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lance_rx(struct net_device *dev); -static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t lance_interrupt(int irq, void *dev_id); static int lance_close(struct net_device *dev); static struct net_device_stats *lance_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -1012,8 +1012,7 @@ out: } /* The LANCE interrupt handler. */ -static irqreturn_t -lance_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t lance_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct lance_private *lp; diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index da1eedef0b55..8cbd940f0ac2 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -403,7 +403,7 @@ static char init_setup[] = static int i596_open(struct net_device *dev); static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t i596_interrupt(int irq, void *dev_id); static int i596_close(struct net_device *dev); static struct net_device_stats *i596_get_stats(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); @@ -527,7 +527,7 @@ static void i596_display_data(struct net_device *dev) #if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET) -static void i596_error(int irq, void *dev_id, struct pt_regs *regs) +static void i596_error(int irq, void *dev_id) { struct net_device *dev = dev_id; volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; @@ -1257,7 +1257,7 @@ static void i596_poll_controller(struct net_device *dev) } #endif -static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t i596_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct i596_private *lp; diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 0258aaca9ed3..b833016f1825 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -379,7 +379,7 @@ static char init_setup[14] = { static int i596_open(struct net_device *dev); static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t i596_interrupt(int irq, void *dev_id); static int i596_close(struct net_device *dev); static struct net_device_stats *i596_get_stats(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); @@ -1151,7 +1151,7 @@ i596_handle_CU_completion(struct net_device *dev, } static irqreturn_t -i596_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { +i596_interrupt (int irq, void *dev_instance) { struct net_device *dev = (struct net_device *) dev_instance; struct i596_private *lp; unsigned short status, ack_cmd = 0; diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 8472b71641da..e960138011c0 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -129,7 +129,7 @@ extern void reset_chip(struct net_device *dev); #endif static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t net_interrupt(int irq, void *dev_id); static void set_multicast_list(struct net_device *dev); static void net_rx(struct net_device *dev); static int net_close(struct net_device *dev); @@ -431,7 +431,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) /* The typical workload of the driver: Handle the network interface interrupts. */ -static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t net_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct net_local *lp; diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 27c24eaa2414..2907cfb12ada 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -82,9 +82,9 @@ static struct net_device_stats *mace_stats(struct net_device *dev); static void mace_set_multicast(struct net_device *dev); static void mace_reset(struct net_device *dev); static int mace_set_address(struct net_device *dev, void *addr); -static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t mace_interrupt(int irq, void *dev_id); +static irqreturn_t mace_txdma_intr(int irq, void *dev_id); +static irqreturn_t mace_rxdma_intr(int irq, void *dev_id); static void mace_set_timeout(struct net_device *dev); static void mace_tx_timeout(unsigned long data); static inline void dbdma_reset(volatile struct dbdma_regs __iomem *dma); @@ -678,7 +678,7 @@ static void mace_handle_misc_intrs(struct mace_data *mp, int intr) printk(KERN_DEBUG "mace: jabbering transceiver\n"); } -static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mace_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct mace_data *mp = (struct mace_data *) dev->priv; @@ -890,12 +890,12 @@ out: spin_unlock_irqrestore(&mp->lock, flags); } -static irqreturn_t mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mace_txdma_intr(int irq, void *dev_id) { return IRQ_HANDLED; } -static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct mace_data *mp = (struct mace_data *) dev->priv; diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 696d5513e558..464e4a6f3d5f 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -77,8 +77,8 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *mace_stats(struct net_device *dev); static void mace_set_multicast(struct net_device *dev); static int mace_set_address(struct net_device *dev, void *addr); -static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t mace_interrupt(int irq, void *dev_id); +static irqreturn_t mace_dma_intr(int irq, void *dev_id); static void mace_tx_timeout(struct net_device *dev); /* Bit-reverse one byte of an ethernet hardware address. */ @@ -573,7 +573,7 @@ static void mace_recv_interrupt(struct net_device *dev) * Process the chip interrupt */ -static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mace_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct mace_data *mp = (struct mace_data *) dev->priv; @@ -645,7 +645,7 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) * The PSC has passed us a DMA interrupt event. */ -static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mace_dma_intr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct mace_data *mp = (struct mace_data *) dev->priv; diff --git a/drivers/net/meth.c b/drivers/net/meth.c index 55b1495a70d6..c1aa60b9a982 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -92,7 +92,7 @@ struct meth_private { }; static void meth_tx_timeout(struct net_device *dev); -static irqreturn_t meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs); +static irqreturn_t meth_interrupt(int irq, void *dev_id); /* global, initialized in ip32-setup.c */ char o2meth_eaddr[8]={0,0,0,0,0,0,0,0}; @@ -569,7 +569,7 @@ static void meth_error(struct net_device* dev, unsigned status) /* * The typical interrupt entry point */ -static irqreturn_t meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs) +static irqreturn_t meth_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct meth_private *priv = (struct meth_private *) dev->priv; diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index 07e58f4a2916..c9469985bd71 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -116,8 +116,7 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) return count; } -static irqreturn_t -mipsnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mipsnet_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 7f8e5ad1b704..d26a819a9735 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -507,8 +507,7 @@ static void mv643xx_eth_update_pscr(struct net_device *dev, * Output : N/A */ -static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct mv643xx_private *mp = netdev_priv(dev); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 4330197994df..fdbb0d7213b0 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1148,7 +1148,7 @@ static int myri10ge_poll(struct net_device *netdev, int *budget) return 1; } -static irqreturn_t myri10ge_intr(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t myri10ge_intr(int irq, void *arg) { struct myri10ge_priv *mgp = arg; struct mcp_irq_data *stats = mgp->fw_stats; diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index a925bc9db4ac..466b484c9fa4 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -536,7 +536,7 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) } } -static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t myri_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct myri_eth *mp = (struct myri_eth *) dev->priv; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index d7b241f7d7bc..ffa0afd2eddc 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -623,7 +623,7 @@ static void free_ring(struct net_device *dev); static void reinit_ring(struct net_device *dev); static void init_registers(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int natsemi_poll(struct net_device *dev, int *budget); static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do); @@ -2088,7 +2088,7 @@ static void netdev_tx_done(struct net_device *dev) /* The interrupt handler doesn't actually handle interrupts itself, it * schedules a NAPI poll if there is anything to do. */ -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +static irqreturn_t intr_handler(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct netdev_private *np = netdev_priv(dev); @@ -2373,7 +2373,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) static void natsemi_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - intr_handler(dev->irq, dev, NULL); + intr_handler(dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 30ed9a5a40e0..a53644f6a29b 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -176,7 +176,7 @@ static void netx_eth_receive(struct net_device *ndev) } static irqreturn_t -netx_eth_interrupt(int irq, void *dev_id, struct pt_regs *regs) +netx_eth_interrupt(int irq, void *dev_id) { struct net_device *ndev = dev_id; struct netx_eth_priv *priv = netdev_priv(ndev); diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 383c690eefec..8be0d030d6f4 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -99,7 +99,7 @@ struct ni5010_local { static int ni5010_probe1(struct net_device *dev, int ioaddr); static int ni5010_open(struct net_device *dev); static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t ni5010_interrupt(int irq, void *dev_id); static void ni5010_rx(struct net_device *dev); static void ni5010_timeout(struct net_device *dev); static int ni5010_close(struct net_device *dev); @@ -468,7 +468,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev) * The typical workload of the driver: * Handle the network interface interrupts. */ -static irqreturn_t ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ni5010_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct ni5010_local *lp; diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index e8889235996e..26e42f6e9fb1 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -195,7 +195,7 @@ sizeof(nop_cmd) = 8; #define NI52_ADDR2 0x01 static int ni52_probe1(struct net_device *dev,int ioaddr); -static irqreturn_t ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr); +static irqreturn_t ni52_interrupt(int irq,void *dev_id); static int ni52_open(struct net_device *dev); static int ni52_close(struct net_device *dev); static int ni52_send_packet(struct sk_buff *,struct net_device *); @@ -837,7 +837,7 @@ static void *alloc_rfa(struct net_device *dev,void *ptr) * Interrupt Handler ... */ -static irqreturn_t ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr) +static irqreturn_t ni52_interrupt(int irq,void *dev_id) { struct net_device *dev = dev_id; unsigned short stat; diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index fab3c8593ac1..340ad0d5388a 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -248,7 +248,7 @@ struct priv }; static int ni65_probe1(struct net_device *dev,int); -static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs *regs); +static irqreturn_t ni65_interrupt(int irq, void * dev_id); static void ni65_recv_intr(struct net_device *dev,int); static void ni65_xmit_intr(struct net_device *dev,int); static int ni65_open(struct net_device *dev); @@ -871,7 +871,7 @@ static int ni65_lance_reinit(struct net_device *dev) /* * interrupt handler */ -static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs) +static irqreturn_t ni65_interrupt(int irq, void * dev_id) { int csr0 = 0; struct net_device *dev = dev_id; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index e10da1aa3d30..b0127c71a5b6 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1288,7 +1288,7 @@ static void ns83820_mib_isr(struct ns83820 *dev) } static void ns83820_do_isr(struct net_device *ndev, u32 isr); -static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs) +static irqreturn_t ns83820_irq(int foo, void *data) { struct net_device *ndev = data; struct ns83820 *dev = PRIV(ndev); diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 2687e747657d..00ca0fdb837b 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -502,8 +502,7 @@ static void netdrv_tx_timeout (struct net_device *dev); static void netdrv_init_ring (struct net_device *dev); static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev); -static irqreturn_t netdrv_interrupt (int irq, void *dev_instance, - struct pt_regs *regs); +static irqreturn_t netdrv_interrupt (int irq, void *dev_instance); static int netdrv_close (struct net_device *dev); static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *netdrv_get_stats (struct net_device *dev); @@ -1654,8 +1653,7 @@ static void netdrv_weird_interrupt (struct net_device *dev, /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t netdrv_interrupt (int irq, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t netdrv_interrupt (int irq, void *dev_instance) { struct net_device *dev = (struct net_device *) dev_instance; struct netdrv_private *tp = dev->priv; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 2418cdb9d317..046009928526 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -238,7 +238,7 @@ static void tc574_reset(struct net_device *dev); static void media_check(unsigned long arg); static int el3_open(struct net_device *dev); static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t el3_interrupt(int irq, void *dev_id); static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); static int el3_rx(struct net_device *dev, int worklimit); @@ -817,7 +817,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* The EL3 interrupt handler. */ -static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t el3_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct el3_private *lp = netdev_priv(dev); @@ -927,7 +927,7 @@ static void media_check(unsigned long arg) if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) { if (!lp->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - el3_interrupt(dev->irq, lp, NULL); + el3_interrupt(dev->irq, lp); lp->fast_poll = HZ; } if (lp->fast_poll) { diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index a0e2b01c027c..231fa2c9ec6c 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -151,7 +151,7 @@ static void media_check(unsigned long arg); static int el3_config(struct net_device *dev, struct ifmap *map); static int el3_open(struct net_device *dev); static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t el3_interrupt(int irq, void *dev_id); static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); static int el3_rx(struct net_device *dev); @@ -645,7 +645,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* The EL3 interrupt handler. */ -static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t el3_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct el3_private *lp = netdev_priv(dev); @@ -748,7 +748,7 @@ static void media_check(unsigned long arg) (inb(ioaddr + EL3_TIMER) == 0xff)) { if (!lp->fast_poll) printk(KERN_WARNING "%s: interrupt(s) dropped!\n", dev->name); - el3_interrupt(dev->irq, lp, NULL); + el3_interrupt(dev->irq, lp); lp->fast_poll = HZ; } if (lp->fast_poll) { diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index a8891a9000ac..e5f366910914 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -92,7 +92,7 @@ static int axnet_open(struct net_device *dev); static int axnet_close(struct net_device *dev); static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops netdev_ethtool_ops; -static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t ei_irq_wrapper(int irq, void *dev_id); static void ei_watchdog(u_long arg); static void axnet_reset_8390(struct net_device *dev); @@ -112,7 +112,7 @@ static void axdev_setup(struct net_device *dev); static void AX88190_init(struct net_device *dev, int startp); static int ax_open(struct net_device *dev); static int ax_close(struct net_device *dev); -static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t ax_interrupt(int irq, void *dev_id); /*====================================================================*/ @@ -599,11 +599,11 @@ static void axnet_reset_8390(struct net_device *dev) /*====================================================================*/ -static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ei_irq_wrapper(int irq, void *dev_id) { struct net_device *dev = dev_id; PRIV(dev)->stale = 0; - return ax_interrupt(irq, dev_id, regs); + return ax_interrupt(irq, dev_id); } static void ei_watchdog(u_long arg) @@ -621,7 +621,7 @@ static void ei_watchdog(u_long arg) if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) { if (!info->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - ei_irq_wrapper(dev->irq, dev, NULL); + ei_irq_wrapper(dev->irq, dev); info->fast_poll = HZ; } if (info->fast_poll) { @@ -1193,7 +1193,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) * needed. */ -static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t ax_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; long e8390_base; diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index d682f30dea6e..65f6fdf43725 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -97,7 +97,7 @@ static int fjn_config(struct net_device *dev, struct ifmap *map); static int fjn_open(struct net_device *dev); static int fjn_close(struct net_device *dev); static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t fjn_interrupt(int irq, void *dev_id); static void fjn_rx(struct net_device *dev); static void fjn_reset(struct net_device *dev); static struct net_device_stats *fjn_get_stats(struct net_device *dev); @@ -733,7 +733,7 @@ module_exit(exit_fmvj18x_cs); /*====================================================================*/ -static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t fjn_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; local_info_t *lp = netdev_priv(dev); diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 7d5687e94607..e77110e4c288 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -426,7 +426,7 @@ static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev); static void mace_tx_timeout(struct net_device *dev); -static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t mace_interrupt(int irq, void *dev_id); static struct net_device_stats *mace_get_stats(struct net_device *dev); static int mace_rx(struct net_device *dev, unsigned char RxCnt); static void restore_multicast_list(struct net_device *dev); @@ -1002,7 +1002,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev) mace_interrupt The interrupt handler. ---------------------------------------------------------------------------- */ -static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mace_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; mace_private *lp = netdev_priv(dev); diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index a09c22840f63..0c00d182e7fd 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -109,7 +109,7 @@ static int pcnet_open(struct net_device *dev); static int pcnet_close(struct net_device *dev); static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops netdev_ethtool_ops; -static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t ei_irq_wrapper(int irq, void *dev_id); static void ei_watchdog(u_long arg); static void pcnet_reset_8390(struct net_device *dev); static int set_config(struct net_device *dev, struct ifmap *map); @@ -1071,11 +1071,11 @@ static int set_config(struct net_device *dev, struct ifmap *map) /*====================================================================*/ -static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ei_irq_wrapper(int irq, void *dev_id) { struct net_device *dev = dev_id; pcnet_dev_t *info; - irqreturn_t ret = ei_interrupt(irq, dev_id, regs); + irqreturn_t ret = ei_interrupt(irq, dev_id); if (ret == IRQ_HANDLED) { info = PRIV(dev); @@ -1100,7 +1100,7 @@ static void ei_watchdog(u_long arg) if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) { if (!info->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - ei_irq_wrapper(dev->irq, dev, NULL); + ei_irq_wrapper(dev->irq, dev); info->fast_poll = HZ; } if (info->fast_poll) { diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index a2f3a0e2a005..20fcc3576202 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -287,7 +287,7 @@ static int smc_close(struct net_device *dev); static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void smc_tx_timeout(struct net_device *dev); static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t smc_interrupt(int irq, void *dev_id); static void smc_rx(struct net_device *dev); static struct net_device_stats *smc_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); @@ -1545,7 +1545,7 @@ static void smc_eph_irq(struct net_device *dev) /*====================================================================*/ -static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t smc_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct smc_private *smc = netdev_priv(dev); @@ -1966,7 +1966,7 @@ static void media_check(u_long arg) if (smc->watchdog++ && ((i>>8) & i)) { if (!smc->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - smc_interrupt(dev->irq, smc, NULL); + smc_interrupt(dev->irq, smc); smc->fast_poll = HZ; } if (smc->fast_poll) { diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 62664c01eb45..f3914f58d67f 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -308,7 +308,7 @@ static void xirc2ps_detach(struct pcmcia_device *p_dev); * less on other parts of the kernel. */ -static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id); /**************** * A linked list of "instances" of the device. Each actual @@ -1121,7 +1121,7 @@ static int xirc2ps_resume(struct pcmcia_device *link) * This is the Interrupt service route. */ static irqreturn_t -xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs) +xirc2ps_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; local_info_t *lp = netdev_priv(dev); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index a43e24245b7e..c73e2f210774 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -304,7 +304,7 @@ static int pcnet32_open(struct net_device *); static int pcnet32_init_ring(struct net_device *); static int pcnet32_start_xmit(struct sk_buff *, struct net_device *); static void pcnet32_tx_timeout(struct net_device *dev); -static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *); +static irqreturn_t pcnet32_interrupt(int, void *); static int pcnet32_close(struct net_device *); static struct net_device_stats *pcnet32_get_stats(struct net_device *); static void pcnet32_load_multicast(struct net_device *dev); @@ -674,7 +674,7 @@ static void pcnet32_purge_rx_ring(struct net_device *dev) static void pcnet32_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - pcnet32_interrupt(0, dev, NULL); + pcnet32_interrupt(0, dev); enable_irq(dev->irq); } #endif @@ -2561,7 +2561,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) /* The PCNET32 interrupt handler. */ static irqreturn_t -pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs) +pcnet32_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct pcnet32_private *lp; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f5aad77288f9..3af9fcf76c81 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -480,7 +480,7 @@ void phy_error(struct phy_device *phydev) * description: When a PHY interrupt occurs, the handler disables * interrupts, and schedules a work task to clear the interrupt. */ -static irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs) +static irqreturn_t phy_interrupt(int irq, void *phy_dat) { struct phy_device *phydev = phy_dat; diff --git a/drivers/net/plip.c b/drivers/net/plip.c index d4f54e9798cd..c0b333d2917a 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -143,7 +143,7 @@ static void plip_bh(struct net_device *dev); static void plip_timer_bh(struct net_device *dev); /* Interrupt handler */ -static void plip_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void plip_interrupt(int irq, void *dev_id); /* Functions for DEV methods */ static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev); @@ -385,7 +385,7 @@ plip_timer_bh(struct net_device *dev) struct net_local *nl = netdev_priv(dev); if (!(atomic_read (&nl->kill_timer))) { - plip_interrupt (-1, dev, NULL); + plip_interrupt (-1, dev); schedule_delayed_work(&nl->timer, 1); } @@ -902,7 +902,7 @@ plip_error(struct net_device *dev, struct net_local *nl, /* Handle the parallel port interrupts. */ static void -plip_interrupt(int irq, void *dev_id, struct pt_regs * regs) +plip_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct net_local *nl; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 157471846349..ec640f6229ae 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -1965,7 +1965,7 @@ quit_polling: return 1; } -static irqreturn_t ql3xxx_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ql3xxx_isr(int irq, void *dev_id) { struct net_device *ndev = dev_id; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 4c47c5b10ba0..f1c75751cab7 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -473,8 +473,7 @@ MODULE_VERSION(RTL8169_VERSION); static int rtl8169_open(struct net_device *dev); static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance, - struct pt_regs *regs); +static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance); static int rtl8169_init_ring(struct net_device *dev); static void rtl8169_hw_start(struct net_device *dev); static int rtl8169_close(struct net_device *dev); @@ -1392,7 +1391,7 @@ static void rtl8169_netpoll(struct net_device *dev) struct pci_dev *pdev = tp->pci_dev; disable_irq(pdev->irq); - rtl8169_interrupt(pdev->irq, dev, NULL); + rtl8169_interrupt(pdev->irq, dev); enable_irq(pdev->irq); } #endif @@ -2592,7 +2591,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static irqreturn_t -rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +rtl8169_interrupt(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *) dev_instance; struct rtl8169_private *tp = netdev_priv(dev); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 6108bac8d56a..d81536f90df6 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1053,7 +1053,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) } -static irqreturn_t rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) +static irqreturn_t rr_interrupt(int irq, void *dev_id) { struct rr_private *rrpriv; struct rr_regs __iomem *regs; diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h index 99451b523399..9f3e050c4dc6 100644 --- a/drivers/net/rrunner.h +++ b/drivers/net/rrunner.h @@ -829,7 +829,7 @@ struct rr_private */ static int rr_init(struct net_device *dev); static int rr_init1(struct net_device *dev); -static irqreturn_t rr_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t rr_interrupt(int irq, void *dev_id); static int rr_open(struct net_device *dev); static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 1bf23e41f580..a231ab7d28dd 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -4029,8 +4029,7 @@ static int s2io_chk_rx_buffers(nic_t *sp, int rng_n) return 0; } -static irqreturn_t -s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t s2io_msi_handle(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; nic_t *sp = dev->priv; @@ -4063,8 +4062,7 @@ s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t -s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) { ring_info_t *ring = (ring_info_t *)dev_id; nic_t *sp = ring->nic; @@ -4078,8 +4076,7 @@ s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t -s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id) { fifo_info_t *fifo = (fifo_info_t *)dev_id; nic_t *sp = fifo->nic; @@ -4155,7 +4152,6 @@ static void s2io_txpic_intr_handle(nic_t *sp) * s2io_isr - ISR handler of the device . * @irq: the irq of the device. * @dev_id: a void pointer to the dev structure of the NIC. - * @pt_regs: pointer to the registers pushed on the stack. * Description: This function is the ISR handler of the device. It * identifies the reason for the interrupt and calls the relevant * service routines. As a contongency measure, this ISR allocates the @@ -4165,7 +4161,7 @@ static void s2io_txpic_intr_handle(nic_t *sp) * IRQ_HANDLED: will be returned if IRQ was handled by this routine * IRQ_NONE: will be returned if interrupt is not from our device */ -static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t s2io_isr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; nic_t *sp = dev->priv; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 3afd9126a591..72f52dc98f53 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -992,12 +992,12 @@ static void s2io_init_pci(nic_t * sp); static int s2io_set_mac_addr(struct net_device *dev, u8 * addr); static void s2io_alarm_handle(unsigned long data); static int s2io_enable_msi(nic_t *nic); -static irqreturn_t s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t s2io_msi_handle(int irq, void *dev_id); static irqreturn_t -s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs); +s2io_msix_ring_handle(int irq, void *dev_id); static irqreturn_t -s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs); +s2io_msix_fifo_handle(int irq, void *dev_id); +static irqreturn_t s2io_isr(int irq, void *dev_id); static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); static const struct ethtool_ops netdev_ethtool_ops; static void s2io_set_link(unsigned long data); diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c index c479b07be788..c9efad8a917e 100644 --- a/drivers/net/saa9730.c +++ b/drivers/net/saa9730.c @@ -745,8 +745,7 @@ static int lan_saa9730_rx(struct net_device *dev) return 0; } -static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct lan_saa9730_private *lp = netdev_priv(dev); diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index a1789ae59278..dc30dee5537f 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -84,7 +84,7 @@ extern int sb1000_probe(struct net_device *dev); static int sb1000_open(struct net_device *dev); static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); static int sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t sb1000_interrupt(int irq, void *dev_id); static struct net_device_stats *sb1000_stats(struct net_device *dev); static int sb1000_close(struct net_device *dev); @@ -1079,7 +1079,7 @@ sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* SB1000 interrupt handler. */ -static irqreturn_t sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sb1000_interrupt(int irq, void *dev_id) { char *name; unsigned char st; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index e4c8896b76cb..db2324939b69 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -294,7 +294,7 @@ static void sbmac_channel_stop(struct sbmac_softc *s); static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t); static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff); static uint64_t sbmac_addr2reg(unsigned char *ptr); -static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs); +static irqreturn_t sbmac_intr(int irq,void *dev_instance); static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); static void sbmac_setmulti(struct sbmac_softc *sc); static int sbmac_init(struct net_device *dev, int idx); @@ -2049,7 +2049,7 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc * Return value: * nothing ********************************************************************* */ -static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) +static irqreturn_t sbmac_intr(int irq,void *dev_instance) { struct net_device *dev = (struct net_device *) dev_instance; struct sbmac_softc *sc = netdev_priv(dev); diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 20afdc7f2b97..d9d0a3a3c558 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -83,7 +83,7 @@ static int seeq8005_probe1(struct net_device *dev, int ioaddr); static int seeq8005_open(struct net_device *dev); static void seeq8005_timeout(struct net_device *dev); static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t seeq8005_interrupt(int irq, void *dev_id); static void seeq8005_rx(struct net_device *dev); static int seeq8005_close(struct net_device *dev); static struct net_device_stats *seeq8005_get_stats(struct net_device *dev); @@ -437,7 +437,7 @@ inline void wait_for_buffer(struct net_device * dev) /* The typical workload of the driver: Handle the network interface interrupts. */ -static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t seeq8005_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct net_local *lp; diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index f95a5b0223fb..a833e7f9757f 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -432,7 +432,7 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp } } -static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct sgiseeq_private *sp = netdev_priv(dev); diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index e8f26b79bbaf..aaba458584fb 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -713,7 +713,7 @@ static void sis190_tx_interrupt(struct net_device *dev, * The interrupt handler does all of the Rx thread work and cleans up after * the Tx thread. */ -static irqreturn_t sis190_interrupt(int irq, void *__dev, struct pt_regs *regs) +static irqreturn_t sis190_interrupt(int irq, void *__dev) { struct net_device *dev = __dev; struct sis190_private *tp = netdev_priv(dev); @@ -758,7 +758,7 @@ static void sis190_netpoll(struct net_device *dev) struct pci_dev *pdev = tp->pci_dev; disable_irq(pdev->irq); - sis190_interrupt(pdev->irq, dev, NULL); + sis190_interrupt(pdev->irq, dev); enable_irq(pdev->irq); } #endif diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 28606e20df1c..fb2b53051635 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -218,7 +218,7 @@ static void sis900_init_rx_ring(struct net_device *net_dev); static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev); static int sis900_rx(struct net_device *net_dev); static void sis900_finish_xmit (struct net_device *net_dev); -static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t sis900_interrupt(int irq, void *dev_instance); static int sis900_close(struct net_device *net_dev); static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd); static struct net_device_stats *sis900_get_stats(struct net_device *net_dev); @@ -988,7 +988,7 @@ static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr) static void sis900_poll(struct net_device *dev) { disable_irq(dev->irq); - sis900_interrupt(dev->irq, dev, NULL); + sis900_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif @@ -1642,7 +1642,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) * and cleans up after the Tx thread */ -static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t sis900_interrupt(int irq, void *dev_instance) { struct net_device *net_dev = dev_instance; struct sis900_private *sis_priv = net_dev->priv; diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 99e92627642c..d4913c3de2a1 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -196,8 +196,8 @@ static SK_BOOL BoardAllocMem(SK_AC *pAC); static void BoardFreeMem(SK_AC *pAC); static void BoardInitMem(SK_AC *pAC); static void SetupRing(SK_AC*, void*, uintptr_t, RXD**, RXD**, RXD**, int*, SK_BOOL); -static SkIsrRetVar SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs); -static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs); +static SkIsrRetVar SkGeIsr(int irq, void *dev_id); +static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id); static int SkGeOpen(struct SK_NET_DEVICE *dev); static int SkGeClose(struct SK_NET_DEVICE *dev); static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev); @@ -880,7 +880,7 @@ int PortIndex) /* index of the port for which to re-init */ * Returns: N/A * */ -static SkIsrRetVar SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs) +static SkIsrRetVar SkGeIsr(int irq, void *dev_id) { struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id; DEV_NET *pNet; @@ -1029,7 +1029,7 @@ SK_U32 IntSrc; /* interrupts source register contents */ * Returns: N/A * */ -static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs) +static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id) { struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id; DEV_NET *pNet; @@ -1140,7 +1140,7 @@ SK_U32 IntSrc; /* interrupts source register contents */ static void SkGePollController(struct net_device *dev) { disable_irq(dev->irq); - SkGeIsr(dev->irq, dev, NULL); + SkGeIsr(dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c index 37b88da1abe5..96e06c51b75d 100644 --- a/drivers/net/sk_mca.c +++ b/drivers/net/sk_mca.c @@ -732,7 +732,7 @@ static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0) /* general interrupt entry */ -static irqreturn_t irq_handler(int irq, void *device, struct pt_regs *regs) +static irqreturn_t irq_handler(int irq, void *device) { struct net_device *dev = (struct net_device *) device; u16 csr0val; diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 8e4d18440a56..06ea2626c6f4 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -101,7 +101,7 @@ static const char * const boot_msg = static int skfp_driver_init(struct net_device *dev); static int skfp_open(struct net_device *dev); static int skfp_close(struct net_device *dev); -static irqreturn_t skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t skfp_interrupt(int irq, void *dev_id); static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev); static void skfp_ctl_set_multicast_list(struct net_device *dev); static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev); @@ -593,7 +593,6 @@ static int skfp_close(struct net_device *dev) * Arguments: * irq - interrupt vector * dev_id - pointer to device information - * regs - pointer to registers structure * * Functional Description: * This routine calls the interrupt processing routine for this adapter. It @@ -615,7 +614,7 @@ static int skfp_close(struct net_device *dev) * Interrupts are disabled, then reenabled at the adapter. */ -irqreturn_t skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t skfp_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct s_smc *smc; /* private board structure pointer */ diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 705e9a8fa30f..a4a58e4e93a1 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3051,7 +3051,7 @@ static void skge_extirq(void *arg) spin_unlock_irq(&hw->hw_lock); } -static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t skge_intr(int irq, void *dev_id) { struct skge_hw *hw = dev_id; u32 status; @@ -3125,7 +3125,7 @@ static void skge_netpoll(struct net_device *dev) struct skge_port *skge = netdev_priv(dev); disable_irq(dev->irq); - skge_intr(dev->irq, skge->hw, NULL); + skge_intr(dev->irq, skge->hw); enable_irq(dev->irq); } #endif diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 396e7df3c61b..459c845d6648 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2364,7 +2364,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) } } -static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sky2_intr(int irq, void *dev_id) { struct sky2_hw *hw = dev_id; struct net_device *dev0 = hw->dev[0]; @@ -3298,8 +3298,7 @@ static void __devinit sky2_show_addr(struct net_device *dev) } /* Handle software interrupt used during MSI test */ -static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id) { struct sky2_hw *hw = dev_id; u32 status = sky2_read32(hw, B0_Y2_SP_ISRC2); diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index 7986514883ac..889ef0d7c374 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -127,7 +127,7 @@ MODULE_DEVICE_TABLE(isapnp, ultra_device_ids); static void ultra_poll(struct net_device *dev) { disable_irq(dev->irq); - ei_interrupt(dev->irq, dev, NULL); + ei_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index a621b17456e5..2c4343395a4d 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1074,7 +1074,7 @@ static void smc911x_phy_interrupt(struct net_device *dev) * This is the main routine of the driver, to handle the device when * it needs some attention. */ -static irqreturn_t smc911x_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t smc911x_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; unsigned long ioaddr = dev->base_addr; @@ -1251,7 +1251,7 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id, struct pt_regs *regs #ifdef SMC_USE_DMA static void -smc911x_tx_dma_irq(int dma, void *data, struct pt_regs *regs) +smc911x_tx_dma_irq(int dma, void *data) { struct net_device *dev = (struct net_device *)data; struct smc911x_local *lp = netdev_priv(dev); @@ -1285,7 +1285,7 @@ smc911x_tx_dma_irq(int dma, void *data, struct pt_regs *regs) "%s: TX DMA irq completed\n", dev->name); } static void -smc911x_rx_dma_irq(int dma, void *data, struct pt_regs *regs) +smc911x_rx_dma_irq(int dma, void *data) { struct net_device *dev = (struct net_device *)data; unsigned long ioaddr = dev->base_addr; diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 5506a0d3efe2..c0d13d650913 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -270,7 +270,7 @@ static void smc_set_multicast_list(struct net_device *dev); /* . Handles the actual interrupt */ -static irqreturn_t smc_interrupt(int irq, void *, struct pt_regs *regs); +static irqreturn_t smc_interrupt(int irq, void *); /* . This is a separate procedure to handle the receipt of a packet, to . leave the interrupt code looking slightly cleaner @@ -1391,7 +1391,7 @@ static void smc_tx( struct net_device * dev ) . ---------------------------------------------------------------------*/ -static irqreturn_t smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) +static irqreturn_t smc_interrupt(int irq, void * dev_id) { struct net_device *dev = dev_id; int ioaddr = dev->base_addr; diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index d7e56438b5d6..506807fa5268 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1284,7 +1284,7 @@ static void smc_eph_interrupt(struct net_device *dev) * This is the main routine of the driver, to handle the device when * it needs some attention. */ -static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t smc_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct smc_local *lp = netdev_priv(dev); diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index fedd1a37bc3e..636dbfcdf8cb 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -507,7 +507,7 @@ smc_pxa_dma_insw(void __iomem *ioaddr, u_long physaddr, int reg, int dma, #endif static void -smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs) +smc_pxa_dma_irq(int dma, void *dummy) { DCSR(dma) = 0; } diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 870cf6b07389..cfece9676aff 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -293,7 +293,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) * The typical workload of the driver: * Handle the network interface interrupts. */ -static irqreturn_t sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sonic_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct sonic_local *lp = netdev_priv(dev); diff --git a/drivers/net/sonic.h b/drivers/net/sonic.h index 7f886e8ae28f..7db13e4a7ea5 100644 --- a/drivers/net/sonic.h +++ b/drivers/net/sonic.h @@ -328,7 +328,7 @@ struct sonic_local { static int sonic_open(struct net_device *dev); static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t sonic_interrupt(int irq, void *dev_id); static void sonic_rx(struct net_device *dev); static int sonic_close(struct net_device *dev); static struct net_device_stats *sonic_get_stats(struct net_device *dev); diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 1397fc55cf68..46a009085f7c 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1445,7 +1445,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) * interrupts for this device and makes the stack poll the driver */ static irqreturn_t -spider_net_interrupt(int irq, void *ptr, struct pt_regs *regs) +spider_net_interrupt(int irq, void *ptr) { struct net_device *netdev = ptr; struct spider_net_card *card = netdev_priv(netdev); @@ -1481,7 +1481,7 @@ static void spider_net_poll_controller(struct net_device *netdev) { disable_irq(netdev->irq); - spider_net_interrupt(netdev->irq, netdev, NULL); + spider_net_interrupt(netdev->irq, netdev); enable_irq(netdev->irq); } #endif /* CONFIG_NET_POLL_CONTROLLER */ diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 3d617e8f54b5..7a0aee6c869d 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -632,7 +632,7 @@ static void check_duplex(struct net_device *dev); static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int __netdev_rx(struct net_device *dev, int *quota); static void refill_rx_ring(struct net_device *dev); @@ -1307,7 +1307,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +static irqreturn_t intr_handler(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct netdev_private *np = netdev_priv(dev); diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index 0605461bc56d..d1d1885b0295 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -122,7 +122,7 @@ sizeof(nop_cmd) = 8; DELAY_16(); DELAY_16(); } } static int sun3_82586_probe1(struct net_device *dev,int ioaddr); -static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr); +static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id); static int sun3_82586_open(struct net_device *dev); static int sun3_82586_close(struct net_device *dev); static int sun3_82586_send_packet(struct sk_buff *,struct net_device *); @@ -678,7 +678,7 @@ static void *alloc_rfa(struct net_device *dev,void *ptr) * Interrupt Handler ... */ -static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr) +static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id) { struct net_device *dev = dev_id; unsigned short stat; diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 61a832ce7ccf..91c76544e4dd 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -237,7 +237,7 @@ static int lance_probe( struct net_device *dev); static int lance_open( struct net_device *dev ); static void lance_init_ring( struct net_device *dev ); static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); -static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp ); +static irqreturn_t lance_interrupt( int irq, void *dev_id); static int lance_rx( struct net_device *dev ); static int lance_close( struct net_device *dev ); static struct net_device_stats *lance_get_stats( struct net_device *dev ); @@ -642,7 +642,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) /* The LANCE interrupt handler. */ -static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t lance_interrupt( int irq, void *dev_id) { struct net_device *dev = dev_id; struct lance_private *lp = netdev_priv(dev); diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 9e4be86495a0..6439b0cef1e4 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -888,7 +888,7 @@ static void bigmac_rx(struct bigmac *bp) printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", bp->dev->name); } -static irqreturn_t bigmac_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t bigmac_interrupt(int irq, void *dev_id) { struct bigmac *bp = (struct bigmac *) dev_id; u32 qec_status, bmac_status; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 6b8f4baf87fd..41c503d8bac4 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -420,7 +420,7 @@ static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static int reset_tx (struct net_device *dev); -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t intr_handler(int irq, void *dev_instance); static void rx_poll(unsigned long data); static void tx_poll(unsigned long data); static void refill_rx (struct net_device *dev); @@ -1102,7 +1102,7 @@ reset_tx (struct net_device *dev) /* The interrupt handler cleans up after the Tx thread, and schedule a Rx thread work */ -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +static irqreturn_t intr_handler(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *)dev_instance; struct netdev_private *np = netdev_priv(dev); diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 0975695ae31b..253e96e7ad20 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -932,7 +932,7 @@ static int gem_poll(struct net_device *dev, int *budget) return 0; } -static irqreturn_t gem_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t gem_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct gem *gp = dev->priv; @@ -975,7 +975,7 @@ static void gem_poll_controller(struct net_device *dev) /* gem_interrupt is safe to reentrance so no need * to disable_irq here. */ - gem_interrupt(dev->irq, dev, NULL); + gem_interrupt(dev->irq, dev); } #endif diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index f05eea53623b..45d07faf7b96 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2093,7 +2093,7 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) RXD((">")); } -static irqreturn_t happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t happy_meal_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct happy_meal *hp = dev->priv; @@ -2132,7 +2132,7 @@ out: } #ifdef CONFIG_SBUS -static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs) +static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie) { struct quattro *qp = (struct quattro *) cookie; int i; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index feb42db10ee1..9207e19cac34 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -820,7 +820,7 @@ out: spin_unlock(&lp->lock); } -static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t lance_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct lance_private *lp = netdev_priv(dev); diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 9202a1c369dd..020e78170595 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -466,7 +466,7 @@ static void qe_tx_reclaim(struct sunqe *qep); * so we just run through each qe and check to see who is signaling * and thus needs to be serviced. */ -static irqreturn_t qec_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t qec_interrupt(int irq, void *dev_id) { struct sunqec *qecp = (struct sunqec *) dev_id; u32 qec_status; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 60f026509487..81ed82f0b520 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -453,7 +453,7 @@ static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr static int tc35815_open(struct net_device *dev); static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); static void tc35815_tx_timeout(struct net_device *dev); -static irqreturn_t tc35815_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t tc35815_interrupt(int irq, void *dev_id); static void tc35815_rx(struct net_device *dev); static void tc35815_txdone(struct net_device *dev); static int tc35815_close(struct net_device *dev); @@ -1044,7 +1044,7 @@ static void tc35815_fatal_error_interrupt(struct net_device *dev, int status) * The typical workload of the driver: * Handle the network interface interrupts. */ -static irqreturn_t tc35815_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t tc35815_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct tc35815_regs *tr; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c25ba273b745..327836b1014e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3481,7 +3481,7 @@ static inline void tg3_full_unlock(struct tg3 *tp) /* One-shot MSI handler - Chip automatically disables interrupt * after sending MSI so driver doesn't have to do it. */ -static irqreturn_t tg3_msi_1shot(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) { struct net_device *dev = dev_id; struct tg3 *tp = netdev_priv(dev); @@ -3499,7 +3499,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id, struct pt_regs *regs) * flush status block and interrupt mailbox. PCI ordering rules * guarantee that MSI will arrive after the status block. */ -static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t tg3_msi(int irq, void *dev_id) { struct net_device *dev = dev_id; struct tg3 *tp = netdev_priv(dev); @@ -3520,7 +3520,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs) return IRQ_RETVAL(1); } -static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t tg3_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct tg3 *tp = netdev_priv(dev); @@ -3563,7 +3563,7 @@ out: return IRQ_RETVAL(handled); } -static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) { struct net_device *dev = dev_id; struct tg3 *tp = netdev_priv(dev); @@ -3606,8 +3606,7 @@ out: } /* ISR for interrupt test */ -static irqreturn_t tg3_test_isr(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t tg3_test_isr(int irq, void *dev_id) { struct net_device *dev = dev_id; struct tg3 *tp = netdev_priv(dev); @@ -3651,7 +3650,7 @@ static void tg3_poll_controller(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - tg3_interrupt(tp->pdev->irq, dev, NULL); + tg3_interrupt(tp->pdev->irq, dev); } #endif @@ -6838,7 +6837,7 @@ restart_timer: static int tg3_request_irq(struct tg3 *tp) { - irqreturn_t (*fn)(int, void *, struct pt_regs *); + irq_handler_t fn; unsigned long flags; struct net_device *dev = tp->dev; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 8d807bf603a0..e14f5a00f65a 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -289,7 +289,7 @@ static void TLan_Eisa_Cleanup( void ); static int TLan_Init( struct net_device * ); static int TLan_Open( struct net_device *dev ); static int TLan_StartTx( struct sk_buff *, struct net_device *); -static irqreturn_t TLan_HandleInterrupt( int, void *, struct pt_regs *); +static irqreturn_t TLan_HandleInterrupt( int, void *); static int TLan_Close( struct net_device *); static struct net_device_stats *TLan_GetStats( struct net_device *); static void TLan_SetMulticastList( struct net_device *); @@ -824,7 +824,7 @@ static void __init TLan_EisaProbe (void) static void TLan_Poll(struct net_device *dev) { disable_irq(dev->irq); - TLan_HandleInterrupt(dev->irq, dev, NULL); + TLan_HandleInterrupt(dev->irq, dev); enable_irq(dev->irq); } #endif @@ -1151,7 +1151,6 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) * occurred. * dev_id A pointer to the device assigned to * this irq line. - * regs ??? * * This function handles an interrupt generated by its * assigned TLAN adapter. The function deactivates @@ -1162,7 +1161,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) * **************************************************************/ -static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id) { u32 ack; struct net_device *dev; diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 412390ba142e..7580bdeacadc 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -130,7 +130,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev); static void xl_dn_comp(struct net_device *dev); static int xl_close(struct net_device *dev); static void xl_set_rx_mode(struct net_device *dev); -static irqreturn_t xl_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t xl_interrupt(int irq, void *dev_id); static struct net_device_stats * xl_get_stats(struct net_device *dev); static int xl_set_mac_address(struct net_device *dev, void *addr) ; static void xl_arb_cmd(struct net_device *dev); @@ -1042,7 +1042,7 @@ static void xl_freemem(struct net_device *dev) return ; } -static irqreturn_t xl_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t xl_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct xl_private *xl_priv =(struct xl_private *)dev->priv; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 4470025ff7f8..bfe59865b1dd 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -197,7 +197,7 @@ static void open_sap(unsigned char type, struct net_device *dev); static void tok_set_multicast_list(struct net_device *dev); static int tok_send_packet(struct sk_buff *skb, struct net_device *dev); static int tok_close(struct net_device *dev); -static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t tok_interrupt(int irq, void *dev_id); static void initial_tok_int(struct net_device *dev); static void tr_tx(struct net_device *dev); static void tr_rx(struct net_device *dev); @@ -1166,7 +1166,7 @@ static void dir_open_adapter (struct net_device *dev) /******************************************************************************/ -static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t tok_interrupt(int irq, void *dev_id) { unsigned char status; /* unsigned char status_even ; */ @@ -1178,7 +1178,7 @@ static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs) dev = dev_id; #if TR_VERBOSE - DPRINTK("Int from tok_driver, dev : %p irq%d regs=%p\n", dev,irq,regs); + DPRINTK("Int from tok_driver, dev : %p irq%d\n", dev,irq); #endif ti = (struct tok_info *) dev->priv; if (ti->sram_phys & 1) diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index bfc8c3eae9a1..e999feb8c0bb 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -206,8 +206,7 @@ static int streamer_open(struct net_device *dev); static int streamer_xmit(struct sk_buff *skb, struct net_device *dev); static int streamer_close(struct net_device *dev); static void streamer_set_rx_mode(struct net_device *dev); -static irqreturn_t streamer_interrupt(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t streamer_interrupt(int irq, void *dev_id); static struct net_device_stats *streamer_get_stats(struct net_device *dev); static int streamer_set_mac_address(struct net_device *dev, void *addr); static void streamer_arb_cmd(struct net_device *dev); @@ -1028,7 +1027,7 @@ static void streamer_rx(struct net_device *dev) } /* end for all completed rx descriptors */ } -static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t streamer_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct streamer_private *streamer_priv = diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 666bbaaae82f..ed274d6909d0 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -70,7 +70,7 @@ static void madgemc_setregpage(struct net_device *dev, int page); static void madgemc_setsifsel(struct net_device *dev, int val); static void madgemc_setint(struct net_device *dev, int val); -static irqreturn_t madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t madgemc_interrupt(int irq, void *dev_id); /* * These work around paging, however they don't guarentee you're on the @@ -417,7 +417,7 @@ getout: * exhausted all contiguous interrupts. * */ -static irqreturn_t madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t madgemc_interrupt(int irq, void *dev_id) { int pending,reg1; struct net_device *dev; @@ -451,7 +451,7 @@ static irqreturn_t madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs outb(reg1, dev->base_addr + MC_CONTROL_REG1); /* Continue handling as normal */ - tms380tr_interrupt(irq, dev_id, regs); + tms380tr_interrupt(irq, dev_id); pending = SIFREADW(SIFSTS); /* restart - the SIF way */ diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 85831484bc40..cd142d0302bc 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -185,7 +185,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev); static int olympic_close(struct net_device *dev); static void olympic_set_rx_mode(struct net_device *dev); static void olympic_freemem(struct net_device *dev) ; -static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t olympic_interrupt(int irq, void *dev_id); static struct net_device_stats * olympic_get_stats(struct net_device *dev); static int olympic_set_mac_address(struct net_device *dev, void *addr) ; static void olympic_arb_cmd(struct net_device *dev); @@ -925,7 +925,7 @@ static void olympic_freemem(struct net_device *dev) return ; } -static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t olympic_interrupt(int irq, void *dev_id) { struct net_device *dev= (struct net_device *)dev_id; struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 85a7f797d343..9bd4cba87872 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -141,7 +141,7 @@ static int smctr_init_shared_memory(struct net_device *dev); static int smctr_init_tx_bdbs(struct net_device *dev); static int smctr_init_tx_fcbs(struct net_device *dev); static int smctr_internal_self_test(struct net_device *dev); -static irqreturn_t smctr_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t smctr_interrupt(int irq, void *dev_id); static int smctr_issue_enable_int_cmd(struct net_device *dev, __u16 interrupt_enable_mask); static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code, @@ -1980,7 +1980,7 @@ static int smctr_internal_self_test(struct net_device *dev) /* * The typical workload of the driver: Handle the network interface interrupts. */ -static irqreturn_t smctr_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t smctr_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct net_local *tp; diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index c1925590a0e1..c0ab6e44eb1f 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -744,7 +744,7 @@ static void tms380tr_timer_chk(unsigned long data) /* * The typical workload of the driver: Handle the network interface interrupts. */ -irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t tms380tr_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct net_local *tp; diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h index 30452c67bb68..2a16078ac3fd 100644 --- a/drivers/net/tokenring/tms380tr.h +++ b/drivers/net/tokenring/tms380tr.h @@ -16,7 +16,7 @@ /* module prototypes */ int tms380tr_open(struct net_device *dev); int tms380tr_close(struct net_device *dev); -irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t tms380tr_interrupt(int irq, void *dev_id); int tmsdev_init(struct net_device *dev, struct device *pdev); void tmsdev_term(struct net_device *dev); void tms380tr_wait(unsigned long time); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index e1b48bd86646..2cfd9634895a 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -484,7 +484,7 @@ rx_next: de->rx_tail = rx_tail; } -static irqreturn_t de_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t de_interrupt (int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct de_private *de = dev->priv; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index fb5fa7d68888..e17f9779ead2 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -896,7 +896,7 @@ static struct { */ static int de4x5_open(struct net_device *dev); static int de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t de4x5_interrupt(int irq, void *dev_id); static int de4x5_close(struct net_device *dev); static struct net_device_stats *de4x5_get_stats(struct net_device *dev); static void de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len); @@ -1538,7 +1538,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) ** interrupt is asserted and this routine entered. */ static irqreturn_t -de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs) +de4x5_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct de4x5_private *lp; diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index ccf2c225f084..4dd8a0bae860 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -300,7 +300,7 @@ static struct net_device_stats * dmfe_get_stats(struct DEVICE *); static void dmfe_set_filter_mode(struct DEVICE *); static const struct ethtool_ops netdev_ethtool_ops; static u16 read_srom_word(long ,int); -static irqreturn_t dmfe_interrupt(int , void *, struct pt_regs *); +static irqreturn_t dmfe_interrupt(int , void *); #ifdef CONFIG_NET_POLL_CONTROLLER static void poll_dmfe (struct net_device *dev); #endif @@ -735,7 +735,7 @@ static int dmfe_stop(struct DEVICE *dev) * receive the packet to upper layer, free the transmitted packet */ -static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dmfe_interrupt(int irq, void *dev_id) { struct DEVICE *dev = dev_id; struct dmfe_board_info *db = netdev_priv(dev); @@ -806,7 +806,7 @@ static void poll_dmfe (struct net_device *dev) /* disable_irq here is not very nice, but with the lockless interrupt handler we have no other choice. */ disable_irq(dev->irq); - dmfe_interrupt (dev->irq, dev, NULL); + dmfe_interrupt (dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 7f8f5d42a761..e3488d7b8ede 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -496,7 +496,7 @@ static inline unsigned int phy_interrupt (struct net_device *dev) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +irqreturn_t tulip_interrupt(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *)dev_instance; struct tulip_private *tp = netdev_priv(dev); diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 25668ddb1f7e..ad107f45c7b1 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -424,7 +424,7 @@ int tulip_read_eeprom(struct net_device *dev, int location, int addr_len); /* interrupt.c */ extern unsigned int tulip_max_interrupt_work; extern int tulip_rx_copybreak; -irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +irqreturn_t tulip_interrupt(int irq, void *dev_instance); int tulip_refill_rx(struct net_device *dev); #ifdef CONFIG_TULIP_NAPI int tulip_poll(struct net_device *dev, int *budget); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 831919a81918..0aee618f883c 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1823,7 +1823,7 @@ static void poll_tulip (struct net_device *dev) /* disable_irq here is not very nice, but with the lockless interrupt handler we have no other choice. */ disable_irq(dev->irq); - tulip_interrupt (dev->irq, dev, NULL); + tulip_interrupt (dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 0b176be51eb3..229158e8e4be 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -224,7 +224,7 @@ static struct net_device_stats * uli526x_get_stats(struct net_device *); static void uli526x_set_filter_mode(struct net_device *); static const struct ethtool_ops netdev_ethtool_ops; static u16 read_srom_word(long, int); -static irqreturn_t uli526x_interrupt(int, void *, struct pt_regs *); +static irqreturn_t uli526x_interrupt(int, void *); static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long); static void allocate_rx_buffer(struct uli526x_board_info *); static void update_cr6(u32, unsigned long); @@ -659,7 +659,7 @@ static int uli526x_stop(struct net_device *dev) * receive the packet to upper layer, free the transmitted packet */ -static irqreturn_t uli526x_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t uli526x_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct uli526x_board_info *db = netdev_priv(dev); diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 2fca1ee24f5a..002a05e0722f 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -332,7 +332,7 @@ static void tx_timeout(struct net_device *dev); static int alloc_ringdesc(struct net_device *dev); static void free_ringdesc(struct netdev_private *np); static int start_tx(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int netdev_rx(struct net_device *dev); static u32 __set_rx_mode(struct net_device *dev); @@ -1110,7 +1110,7 @@ static void netdev_tx_done(struct net_device *dev) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +static irqreturn_t intr_handler(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *)dev_instance; struct netdev_private *np = netdev_priv(dev); diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 629eac645289..61d313049dd0 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -114,7 +114,7 @@ struct xircom_private { /* Function prototypes */ static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void xircom_remove(struct pci_dev *pdev); -static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t xircom_interrupt(int irq, void *dev_instance); static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev); static int xircom_open(struct net_device *dev); static int xircom_close(struct net_device *dev); @@ -334,7 +334,7 @@ static void __devexit xircom_remove(struct pci_dev *pdev) leave("xircom_remove"); } -static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t xircom_interrupt(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *) dev_instance; struct xircom_private *card = netdev_priv(dev); @@ -513,7 +513,7 @@ static struct net_device_stats *xircom_get_stats(struct net_device *dev) static void xircom_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - xircom_interrupt(dev->irq, dev, NULL); + xircom_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c index 312788caa4c6..a998c5d0ae9c 100644 --- a/drivers/net/tulip/xircom_tulip_cb.c +++ b/drivers/net/tulip/xircom_tulip_cb.c @@ -328,7 +328,7 @@ static void xircom_init_ring(struct net_device *dev); static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev); static int xircom_rx(struct net_device *dev); static void xircom_media_change(struct net_device *dev); -static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t xircom_interrupt(int irq, void *dev_instance); static int xircom_close(struct net_device *dev); static struct net_device_stats *xircom_get_stats(struct net_device *dev); static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -1044,7 +1044,7 @@ static void check_duplex(struct net_device *dev) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t xircom_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct xircom_private *tp = netdev_priv(dev); diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index d5c32e9caa97..3bf9e630404f 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1826,7 +1826,7 @@ typhoon_poll(struct net_device *dev, int *total_budget) } static irqreturn_t -typhoon_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) +typhoon_interrupt(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *) dev_instance; struct typhoon *tp = dev->priv; diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 700ebd7d1457..12cd7b561f35 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3844,8 +3844,7 @@ static int ucc_geth_poll(struct net_device *dev, int *budget) } #endif /* CONFIG_UGETH_NAPI */ -static irqreturn_t ucc_geth_irq_handler(int irq, void *info, - struct pt_regs *regs) +static irqreturn_t ucc_geth_irq_handler(int irq, void *info) { struct net_device *dev = (struct net_device *)info; ucc_geth_private_t *ugeth = netdev_priv(dev); @@ -3910,7 +3909,7 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info, return IRQ_HANDLED; } -static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t phy_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; ucc_geth_private_t *ugeth = netdev_priv(dev); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index cbebf1b96e9d..ebbda1d8f542 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -404,7 +404,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val static int rhine_open(struct net_device *dev); static void rhine_tx_timeout(struct net_device *dev); static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t rhine_interrupt(int irq, void *dev_instance); static void rhine_tx(struct net_device *dev); static int rhine_rx(struct net_device *dev, int limit); static void rhine_error(struct net_device *dev, int intr_status); @@ -569,7 +569,7 @@ static void __devinit rhine_reload_eeprom(long pioaddr, struct net_device *dev) static void rhine_poll(struct net_device *dev) { disable_irq(dev->irq); - rhine_interrupt(dev->irq, (void *)dev, NULL); + rhine_interrupt(dev->irq, (void *)dev); enable_irq(dev->irq); } #endif @@ -1290,7 +1290,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) +static irqreturn_t rhine_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct rhine_private *rp = netdev_priv(dev); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 7d8808ce541f..74f894795a1b 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -236,7 +236,7 @@ static void velocity_print_info(struct velocity_info *vptr); static int velocity_open(struct net_device *dev); static int velocity_change_mtu(struct net_device *dev, int mtu); static int velocity_xmit(struct sk_buff *skb, struct net_device *dev); -static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs); +static int velocity_intr(int irq, void *dev_instance); static void velocity_set_multi(struct net_device *dev); static struct net_device_stats *velocity_get_stats(struct net_device *dev); static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -2036,7 +2036,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) * velocity_intr - interrupt callback * @irq: interrupt number * @dev_instance: interrupting device - * @pt_regs: CPU register state at interrupt * * Called whenever an interrupt is generated by the velocity * adapter IRQ line. We may not be the source of the interrupt @@ -2044,7 +2043,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) * efficiently as possible. */ -static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs) +static int velocity_intr(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct velocity_info *vptr = netdev_priv(dev); diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 1f95b4864ea1..e1bf8b93f958 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -345,7 +345,7 @@ static void put_driver_status(struct cosa_data *cosa); static void put_driver_status_nolock(struct cosa_data *cosa); /* Interrupt handling */ -static irqreturn_t cosa_interrupt(int irq, void *cosa, struct pt_regs *regs); +static irqreturn_t cosa_interrupt(int irq, void *cosa); /* I/O ops debugging */ #ifdef DEBUG_IO @@ -1972,7 +1972,7 @@ out: spin_unlock_irqrestore(&cosa->lock, flags); } -static irqreturn_t cosa_interrupt(int irq, void *cosa_, struct pt_regs *regs) +static irqreturn_t cosa_interrupt(int irq, void *cosa_) { unsigned status; int count = 0; diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index a5e7ce1bd16a..12363e056b63 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c @@ -74,7 +74,7 @@ static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf); static int cycx_wan_shutdown(struct wan_device *wandev); /* Miscellaneous functions */ -static irqreturn_t cycx_isr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t cycx_isr(int irq, void *dev_id); /* Global Data * Note: All data must be explicitly initialized!!! @@ -301,7 +301,7 @@ out: return ret; * o acknowledge Cyclom 2X hardware interrupt. * o call protocol-specific interrupt service routine, if any. */ -static irqreturn_t cycx_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cycx_isr(int irq, void *dev_id) { struct cycx_device *card = (struct cycx_device *)dev_id; diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index af4d4155905b..25021a7992a9 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -365,7 +365,7 @@ static int dscc4_init_ring(struct net_device *); static void dscc4_release_ring(struct dscc4_dev_priv *); static void dscc4_timer(unsigned long); static void dscc4_tx_timeout(struct net_device *); -static irqreturn_t dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs); +static irqreturn_t dscc4_irq(int irq, void *dev_id); static int dscc4_hdlc_attach(struct net_device *, unsigned short, unsigned short); static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *); #ifdef DSCC4_POLLING @@ -1476,7 +1476,7 @@ static int dscc4_set_iface(struct dscc4_dev_priv *dpriv, struct net_device *dev) return ret; } -static irqreturn_t dscc4_irq(int irq, void *token, struct pt_regs *ptregs) +static irqreturn_t dscc4_irq(int irq, void *token) { struct dscc4_dev_priv *root = token; struct dscc4_pci_priv *priv; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 564351aafa41..c45d6a83339d 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -1498,7 +1498,7 @@ do_bottom_half_rx(struct fst_card_info *card) * Dev_id is our fst_card_info pointer */ static irqreturn_t -fst_intr(int irq, void *dev_id, struct pt_regs *regs) +fst_intr(int irq, void *dev_id) { struct fst_card_info *card; struct fst_port_info *port; diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c index dce2bb317b82..8d0a1f2f00e5 100644 --- a/drivers/net/wan/hd6457x.c +++ b/drivers/net/wan/hd6457x.c @@ -424,7 +424,7 @@ static inline void sca_tx_intr(port_t *port) -static irqreturn_t sca_intr(int irq, void* dev_id, struct pt_regs *regs) +static irqreturn_t sca_intr(int irq, void* dev_id) { card_t *card = dev_id; int i; diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 7b5d81deb028..2b54f1bc3a0d 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -100,7 +100,7 @@ static int lmc_rx (struct net_device *dev); static int lmc_open(struct net_device *dev); static int lmc_close(struct net_device *dev); static struct net_device_stats *lmc_get_stats(struct net_device *dev); -static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t lmc_interrupt(int irq, void *dev_instance); static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size); static void lmc_softreset(lmc_softc_t * const); static void lmc_running_reset(struct net_device *dev); @@ -1273,7 +1273,7 @@ static int lmc_ifdown (struct net_device *dev) /*fold00*/ /* Interrupt handling routine. This will take an incoming packet, or clean * up after a trasmit. */ -static irqreturn_t lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/ +static irqreturn_t lmc_interrupt (int irq, void *dev_instance) /*fold00*/ { struct net_device *dev = (struct net_device *) dev_instance; lmc_softc_t *sc; diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 8d9b959bf15b..5823e3bca178 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -284,7 +284,7 @@ static void rx_dma_buf_pt_init(pc300_t *, int); static void rx_dma_buf_init(pc300_t *, int); static void tx_dma_buf_check(pc300_t *, int); static void rx_dma_buf_check(pc300_t *, int); -static irqreturn_t cpc_intr(int, void *, struct pt_regs *); +static irqreturn_t cpc_intr(int, void *); static struct net_device_stats *cpc_get_stats(struct net_device *); static int clock_rate_calc(uclong, uclong, int *); static uclong detect_ram(pc300_t *); @@ -2363,7 +2363,7 @@ static void falc_intr(pc300_t * card) } } -static irqreturn_t cpc_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cpc_intr(int irq, void *dev_id) { pc300_t *card; volatile ucchar plx_status; diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index fc75bec19029..fc5c0c611ffd 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -119,7 +119,7 @@ static int sbni_ioctl( struct net_device *, struct ifreq *, int ); static struct net_device_stats *sbni_get_stats( struct net_device * ); static void set_multicast_list( struct net_device * ); -static irqreturn_t sbni_interrupt( int, void *, struct pt_regs * ); +static irqreturn_t sbni_interrupt( int, void * ); static void handle_channel( struct net_device * ); static int recv_frame( struct net_device * ); static void send_frame( struct net_device * ); @@ -501,7 +501,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) */ static irqreturn_t -sbni_interrupt( int irq, void *dev_id, struct pt_regs *regs ) +sbni_interrupt( int irq, void *dev_id ) { struct net_device *dev = (struct net_device *) dev_id; struct net_local *nl = (struct net_local *) dev->priv; diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 0ba018f8382b..5715d25271f1 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -867,7 +867,7 @@ static void sdla_receive(struct net_device *dev) spin_unlock_irqrestore(&sdla_lock, flags); } -static irqreturn_t sdla_isr(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t sdla_isr(int irq, void *dev_id) { struct net_device *dev; struct frad_local *flp; diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index ec68f7dfd93f..c73601574334 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -244,7 +244,7 @@ static inline void wanxl_rx_intr(card_t *card) -static irqreturn_t wanxl_intr(int irq, void* dev_id, struct pt_regs *regs) +static irqreturn_t wanxl_intr(int irq, void* dev_id) { card_t *card = dev_id; int i; diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index caa48f12fd0f..59ddd21c3958 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -728,7 +728,7 @@ EXPORT_SYMBOL(z8530_nop); * channel). c->lock for both channels points to dev->lock */ -irqreturn_t z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t z8530_interrupt(int irq, void *dev_id) { struct z8530_dev *dev=dev_id; u8 intr; diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h index 77e53208045f..158aea7b8eac 100644 --- a/drivers/net/wan/z85230.h +++ b/drivers/net/wan/z85230.h @@ -396,7 +396,7 @@ struct z8530_dev extern u8 z8530_dead_port[]; extern u8 z8530_hdlc_kilostream_85230[]; extern u8 z8530_hdlc_kilostream[]; -extern irqreturn_t z8530_interrupt(int, void *, struct pt_regs *); +extern irqreturn_t z8530_interrupt(int, void *); extern void z8530_describe(struct z8530_dev *, char *mapping, unsigned long io); extern int z8530_init(struct z8530_dev *); extern int z8530_shutdown(struct z8530_dev *); diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 39d09345027c..0a33c8a56e13 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1120,8 +1120,7 @@ static void mpi_receive_802_3(struct airo_info *ai); static void mpi_receive_802_11(struct airo_info *ai); static int waitbusy (struct airo_info *ai); -static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs - *regs); +static irqreturn_t airo_interrupt( int irq, void* dev_id); static int airo_thread(void *data); static void timer_func( struct net_device *dev ); static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -3151,7 +3150,7 @@ static int airo_thread(void *data) { return 0; } -static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) { +static irqreturn_t airo_interrupt ( int irq, void* dev_id) { struct net_device *dev = (struct net_device *)dev_id; u16 status; u16 fid; diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index bb6bea4f3233..4688e56b69c7 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -78,7 +78,7 @@ static int arlans_found; static int arlan_open(struct net_device *dev); static int arlan_tx(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t arlan_interrupt(int irq, void *dev_id); static int arlan_close(struct net_device *dev); static struct net_device_stats * arlan_statistics (struct net_device *dev); @@ -1651,7 +1651,7 @@ end_int_process: return; } -static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t arlan_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct arlan_private *priv = netdev_priv(dev); diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 0fc267d626dc..31eed85de60f 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1145,7 +1145,7 @@ next: } } -static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t service_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct atmel_private *priv = netdev_priv(dev); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index eb65db7393ba..bad3452ea893 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1834,7 +1834,7 @@ static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason) } /* Interrupt handler top-half */ -static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id) { irqreturn_t ret = IRQ_HANDLED; struct bcm43xx_private *bcm = dev_id; @@ -3963,7 +3963,7 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev) local_irq_save(flags); if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) - bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); + bcm43xx_interrupt_handler(bcm->irq, bcm); local_irq_restore(flags); } #endif /* CONFIG_NET_POLL_CONTROLLER */ diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index d500012fdc7a..ed00ebb6e7f4 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -2622,7 +2622,7 @@ static void prism2_check_magic(local_info_t *local) /* Called only from hardware IRQ */ -static irqreturn_t prism2_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t prism2_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct hostap_interface *iface; diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 599e2fe76188..4e4eaa2a99ca 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -3255,7 +3255,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) IPW_DEBUG_ISR("exit\n"); } -static irqreturn_t ipw2100_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t ipw2100_interrupt(int irq, void *data) { struct ipw2100_priv *priv = data; u32 inta, inta_mask; diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 5685d7ba55bb..1f742814a01c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -10467,7 +10467,7 @@ static const struct ethtool_ops ipw_ethtool_ops = { .set_eeprom = ipw_ethtool_set_eeprom, }; -static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) +static irqreturn_t ipw_isr(int irq, void *data) { struct ipw_priv *priv = data; u32 inta, inta_mask; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 36b5e004305e..6714e0dfa8d6 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -207,7 +207,7 @@ static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev); static int netwave_rx( struct net_device *dev); /* Interrupt routines */ -static irqreturn_t netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t netwave_interrupt(int irq, void *dev_id); static void netwave_watchdog(struct net_device *); /* Statistics */ @@ -1072,7 +1072,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { } /* netwave_start_xmit */ /* - * Function netwave_interrupt (irq, dev_id, regs) + * Function netwave_interrupt (irq, dev_id) * * This function is the interrupt handler for the Netwave card. This * routine will be called whenever: @@ -1081,7 +1081,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { * ready to transmit another packet. * 3. A command has completed execution. */ -static irqreturn_t netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) +static irqreturn_t netwave_interrupt(int irq, void* dev_id) { kio_addr_t iobase; u_char __iomem *ramBase; diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 9e19a963febc..793da5f69344 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1952,7 +1952,7 @@ static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) dev->name); } -irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t orinoco_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct orinoco_private *priv = netdev_priv(dev); diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index fb5700d6c454..4720fb20d66d 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -128,7 +128,7 @@ extern void free_orinocodev(struct net_device *dev); extern int __orinoco_up(struct net_device *dev); extern int __orinoco_down(struct net_device *dev); extern int orinoco_reinit_firmware(struct net_device *dev); -extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs); +extern irqreturn_t orinoco_interrupt(int irq, void * dev_id); /********************************************************************/ /* Locking and synchronization functions */ diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index ab3c5a27efd9..ec1c00f19eb3 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -182,7 +182,7 @@ isl_upload_firmware(islpci_private *priv) ******************************************************************************/ irqreturn_t -islpci_interrupt(int irq, void *config, struct pt_regs *regs) +islpci_interrupt(int irq, void *config) { u32 reg; islpci_private *priv = config; diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index 5049f37455b1..2f7e525d0cf6 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -198,7 +198,7 @@ islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state); #define ISLPCI_TX_TIMEOUT (2*HZ) -irqreturn_t islpci_interrupt(int, void *, struct pt_regs *); +irqreturn_t islpci_interrupt(int, void *); int prism54_post_setup(islpci_private *, int); int islpci_reset(islpci_private *, int); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index e82548ea609a..0b381d77015c 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -130,7 +130,7 @@ static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, i static void verify_dl_startup(u_long); /* Prototypes for interrpt time functions **********************************/ -static irqreturn_t ray_interrupt (int reg, void *dev_id, struct pt_regs *regs); +static irqreturn_t ray_interrupt (int reg, void *dev_id); static void clear_interrupt(ray_dev_t *local); static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, unsigned int pkt_addr, int rx_len); @@ -1940,7 +1940,7 @@ static void set_multicast_list(struct net_device *dev) /*============================================================================= * All routines below here are run at interrupt time. =============================================================================*/ -static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t ray_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct pcmcia_device *link; diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 5b69befdab74..24221e476cd3 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -3768,7 +3768,7 @@ static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac) * This function is the interrupt handler for the WaveLAN card. This * routine will be called whenever: */ -static irqreturn_t wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t wavelan_interrupt(int irq, void *dev_id) { struct net_device *dev; unsigned long ioaddr; diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h index 5cb0bc8bb128..72b646c77d5a 100644 --- a/drivers/net/wireless/wavelan.p.h +++ b/drivers/net/wireless/wavelan.p.h @@ -642,8 +642,7 @@ static int /* ---------------------- INTERRUPT HANDLING ---------------------- */ static irqreturn_t wavelan_interrupt(int, /* interrupt handler */ - void *, - struct pt_regs *); + void *); static void wavelan_watchdog(struct net_device *); /* transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 0065f057bb1c..cadfe132db84 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -4117,8 +4117,7 @@ wv_pcmcia_release(struct pcmcia_device *link) */ static irqreturn_t wavelan_interrupt(int irq, - void * dev_id, - struct pt_regs * regs) + void * dev_id) { struct net_device * dev; net_local * lp; diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index f34a36b0c7b0..4d1c4905c749 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -738,8 +738,7 @@ static void /* ---------------------- INTERRUPT HANDLING ---------------------- */ static irqreturn_t wavelan_interrupt(int, /* Interrupt handler */ - void *, - struct pt_regs *); + void *); static void wavelan_watchdog(struct net_device *); /* Transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index e3ae5f60d5be..a1430352169b 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1145,7 +1145,6 @@ static inline void wl3501_ack_interrupt(struct wl3501_card *this) * wl3501_interrupt - Hardware interrupt from card. * @irq - Interrupt number * @dev_id - net_device - * @regs - registers * * We must acknowledge the interrupt as soon as possible, and block the * interrupt from the same card immediately to prevent re-entry. @@ -1154,7 +1153,7 @@ static inline void wl3501_ack_interrupt(struct wl3501_card *this) * On the other hand, to prevent SUTRO from malfunctioning, we must * unlock the SUTRO as soon as possible. */ -static irqreturn_t wl3501_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t wl3501_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct wl3501_card *this; diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 80af9a9fcbb3..30057a335a7b 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -112,7 +112,7 @@ exit: return err; } -static void zd1201_usbfree(struct urb *urb, struct pt_regs *regs) +static void zd1201_usbfree(struct urb *urb) { struct zd1201 *zd = urb->context; @@ -177,7 +177,7 @@ static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, } /* Callback after sending out a packet */ -static void zd1201_usbtx(struct urb *urb, struct pt_regs *regs) +static void zd1201_usbtx(struct urb *urb) { struct zd1201 *zd = urb->context; netif_wake_queue(zd->dev); @@ -185,7 +185,7 @@ static void zd1201_usbtx(struct urb *urb, struct pt_regs *regs) } /* Incoming data */ -static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs) +static void zd1201_usbrx(struct urb *urb) { struct zd1201 *zd = urb->context; int free = 0; diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 5c265ad0485a..3faaeb2b7c89 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -408,7 +408,7 @@ static inline void handle_retry_failed_int(struct urb *urb) } -static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs) +static void int_urb_complete(struct urb *urb) { int r; struct usb_int_header *hdr; @@ -609,7 +609,7 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, } } -static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) +static void rx_urb_complete(struct urb *urb) { struct zd_usb *usb; struct zd_usb_rx *rx; @@ -779,7 +779,7 @@ void zd_usb_disable_rx(struct zd_usb *usb) spin_unlock_irqrestore(&rx->lock, flags); } -static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) +static void tx_urb_complete(struct urb *urb) { int r; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index a4c4953f1365..ac600212d9a9 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -350,7 +350,7 @@ static void yellowfin_timer(unsigned long data); static void yellowfin_tx_timeout(struct net_device *dev); static void yellowfin_init_ring(struct net_device *dev); static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance); static int yellowfin_rx(struct net_device *dev); static void yellowfin_error(struct net_device *dev, int intr_status); static int yellowfin_close(struct net_device *dev); @@ -888,7 +888,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct yellowfin_private *yp; diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 656d5a02908b..2068a109a86c 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -158,7 +158,7 @@ struct netidblk { static int znet_open(struct net_device *dev); static int znet_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t znet_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t znet_interrupt(int irq, void *dev_id); static void znet_rx(struct net_device *dev); static int znet_close(struct net_device *dev); static struct net_device_stats *net_get_stats(struct net_device *dev); @@ -602,7 +602,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) } /* The ZNET interrupt handler. */ -static irqreturn_t znet_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t znet_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct znet_private *znet = dev->priv; diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 0d96c50ffe9c..a0a8fd8d2124 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -368,8 +368,7 @@ static struct hw_interrupt_type dino_interrupt_type = { * ilr_loop counter is a kluge to prevent a "stuck" IRQ line from * wedging the CPU. Could be removed or made optional at some point. */ -static irqreturn_t -dino_isr(int irq, void *intr_dev, struct pt_regs *regs) +static irqreturn_t dino_isr(int irq, void *intr_dev) { struct dino_device *dino_dev = intr_dev; u32 mask; diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index 884965cedec9..094562e044f3 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -199,7 +199,7 @@ static struct hw_interrupt_type eisa_interrupt_type = { .end = no_end_irq, }; -static irqreturn_t eisa_irq(int wax_irq, void *intr_dev, struct pt_regs *regs) +static irqreturn_t eisa_irq(int wax_irq, void *intr_dev) { int irq = gsc_readb(0xfc01f000); /* EISA supports 16 irqs */ unsigned long flags; @@ -249,7 +249,7 @@ static irqreturn_t eisa_irq(int wax_irq, void *intr_dev, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t dummy_irq2_handler(int _, void *dev, struct pt_regs *regs) +static irqreturn_t dummy_irq2_handler(int _, void *dev) { printk(KERN_ALERT "eisa: uhh, irq2?\n"); return IRQ_HANDLED; diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index b45aa5c675a0..1b3e3fd12d95 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c @@ -73,7 +73,7 @@ EXPORT_SYMBOL(gsc_alloc_irq); EXPORT_SYMBOL(gsc_claim_irq); /* Common interrupt demultiplexer used by Asp, Lasi & Wax. */ -irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev, struct pt_regs *regs) +irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev) { unsigned long irr; struct gsc_asic *gsc_asic = dev; @@ -87,7 +87,7 @@ irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev, struct pt_regs *regs) do { int local_irq = __ffs(irr); unsigned int irq = gsc_asic->global_irq[local_irq]; - __do_IRQ(irq, regs); + __do_IRQ(irq); irr &= ~(1 << local_irq); } while (irr); diff --git a/drivers/parisc/gsc.h b/drivers/parisc/gsc.h index a3dc456709d7..762a1babad60 100644 --- a/drivers/parisc/gsc.h +++ b/drivers/parisc/gsc.h @@ -44,4 +44,4 @@ void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl, void (*choose)(struct parisc_device *child, void *ctrl)); void gsc_asic_assign_irq(struct gsc_asic *asic, int local_irq, int *irqp); -irqreturn_t gsc_asic_intr(int irq, void *dev, struct pt_regs *regs); +irqreturn_t gsc_asic_intr(int irq, void *dev); diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c index 2eb3577a88c5..97e9dc066f95 100644 --- a/drivers/parisc/power.c +++ b/drivers/parisc/power.c @@ -188,7 +188,7 @@ static void polling_tasklet_func(unsigned long soft_power_reg) * powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2) */ #if 0 -static void powerfail_interrupt(int code, void *x, struct pt_regs *regs) +static void powerfail_interrupt(int code, void *x) { printk(KERN_CRIT "POWERFAIL INTERRUPTION !\n"); poweroff(); diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index 4ee26a6d9e25..1fd97f7c8b98 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -94,7 +94,7 @@ static struct superio_device sio_dev; #define PFX SUPERIO ": " static irqreturn_t -superio_interrupt(int parent_irq, void *devp, struct pt_regs *regs) +superio_interrupt(int parent_irq, void *devp) { u8 results; u8 local_irq; @@ -138,7 +138,7 @@ superio_interrupt(int parent_irq, void *devp, struct pt_regs *regs) } /* Call the appropriate device's interrupt */ - __do_IRQ(local_irq, regs); + __do_IRQ(local_irq); /* set EOI - forces a new interrupt if a lower priority device * still needs service. diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c index 83ee095ec6e2..ff9f34453530 100644 --- a/drivers/parport/daisy.c +++ b/drivers/parport/daisy.c @@ -216,7 +216,7 @@ void parport_daisy_fini(struct parport *port) struct pardevice *parport_open(int devnum, const char *name, int (*pf) (void *), void (*kf) (void *), - void (*irqf) (int, void *, struct pt_regs *), + void (*irqf) (int, void *), int flags, void *handle) { struct daisydev *p = topology; diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index 7ff09f0f858f..5accaa7bde31 100644 --- a/drivers/parport/ieee1284.c +++ b/drivers/parport/ieee1284.c @@ -571,7 +571,7 @@ static int parport_ieee1284_ack_data_avail (struct parport *port) #endif /* IEEE1284 support */ /* Handle an interrupt. */ -void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs) +void parport_ieee1284_interrupt (int which, void *handle) { struct parport *port = handle; parport_ieee1284_wakeup (port); diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c index 5126e74ac2ec..a0afaee5ebe5 100644 --- a/drivers/parport/parport_amiga.c +++ b/drivers/parport/parport_amiga.c @@ -138,9 +138,9 @@ static unsigned char amiga_read_status(struct parport *p) } /* as this ports irq handling is already done, we use a generic funktion */ -static irqreturn_t amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t amiga_interrupt(int irq, void *dev_id) { - parport_generic_irq(irq, (struct parport *) dev_id, regs); + parport_generic_irq(irq, (struct parport *) dev_id); return IRQ_HANDLED; } diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c index 78c3f34108bc..6ea9929b8c7f 100644 --- a/drivers/parport/parport_atari.c +++ b/drivers/parport/parport_atari.c @@ -104,9 +104,9 @@ parport_atari_restore_state(struct parport *p, struct parport_state *s) } static irqreturn_t -parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs) +parport_atari_interrupt(int irq, void *dev_id) { - parport_generic_irq(irq, (struct parport *) dev_id, regs); + parport_generic_irq(irq, (struct parport *) dev_id); return IRQ_HANDLED; } diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c index 1850632590fd..74f4e9742c6c 100644 --- a/drivers/parport/parport_ax88796.c +++ b/drivers/parport/parport_ax88796.c @@ -233,9 +233,9 @@ parport_ax88796_restore_state(struct parport *p, struct parport_state *s) } static irqreturn_t -parport_ax88796_interrupt(int irq, void *dev_id, struct pt_regs *regs) +parport_ax88796_interrupt(int irq, void *dev_id) { - parport_generic_irq(irq, dev_id, regs); + parport_generic_irq(irq, dev_id); return IRQ_HANDLED; } diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index 7352104f7b30..a7c5ead9a3d3 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -81,9 +81,9 @@ static int clear_epp_timeout(struct parport *pb) * of these are in parport_gsc.h. */ -static irqreturn_t parport_gsc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t parport_gsc_interrupt(int irq, void *dev_id) { - parport_generic_irq(irq, (struct parport *) dev_id, regs); + parport_generic_irq(irq, (struct parport *) dev_id); return IRQ_HANDLED; } diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c index 46e06e596d73..e3e19277030a 100644 --- a/drivers/parport/parport_ip32.c +++ b/drivers/parport/parport_ip32.c @@ -548,10 +548,8 @@ static void parport_ip32_dma_setup_context(unsigned int limit) * parport_ip32_dma_interrupt - DMA interrupt handler * @irq: interrupt number * @dev_id: unused - * @regs: pointer to &struct pt_regs */ -static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id) { if (parport_ip32_dma.left) pr_trace(NULL, "(%d): ctx=%d", irq, parport_ip32_dma.ctx); @@ -560,8 +558,7 @@ static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id, } #if DEBUG_PARPORT_IP32 -static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id) { pr_trace1(NULL, "(%d)", irq); return IRQ_HANDLED; @@ -772,13 +769,11 @@ static inline void parport_ip32_wakeup(struct parport *p) * parport_ip32_interrupt - interrupt handler * @irq: interrupt number * @dev_id: pointer to &struct parport - * @regs: pointer to &struct pt_regs * * Caught interrupts are forwarded to the upper parport layer if IRQ_mode is * %PARPORT_IP32_IRQ_FWD. */ -static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id) { struct parport * const p = dev_id; struct parport_ip32_private * const priv = p->physport->private_data; diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c index b2b8092a2b39..6541cde4df00 100644 --- a/drivers/parport/parport_mfc3.c +++ b/drivers/parport/parport_mfc3.c @@ -211,7 +211,7 @@ static void mfc3_change_mode( struct parport *p, int m) static int use_cnt = 0; -static irqreturn_t mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mfc3_interrupt(int irq, void *dev_id) { int i; diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index fe800dc0be9f..39c96641bc72 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -270,9 +270,9 @@ static int clear_epp_timeout(struct parport *pb) * of these are in parport_pc.h. */ -static irqreturn_t parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t parport_pc_interrupt(int irq, void *dev_id) { - parport_generic_irq(irq, (struct parport *) dev_id, regs); + parport_generic_irq(irq, (struct parport *) dev_id); /* FIXME! Was it really ours? */ return IRQ_HANDLED; } diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index fac333b279bf..d758c90c86af 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -46,7 +46,7 @@ #define dprintk(x) #endif -static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id) { parport_generic_irq(irq, (struct parport *) dev_id, regs); return IRQ_HANDLED; diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 94dc506b83d1..fd9129e424f9 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -519,7 +519,7 @@ void parport_remove_port(struct parport *port) struct pardevice * parport_register_device(struct parport *port, const char *name, int (*pf)(void *), void (*kf)(void *), - void (*irq_func)(int, void *, struct pt_regs *), + void (*irq_func)(int, void *), int flags, void *handle) { struct pardevice *tmp; diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index d5df5871cfa2..d06ab4045134 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -342,7 +342,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus) /* This is the interrupt mode interrupt handler */ static irqreturn_t -cpci_hp_intr(int irq, void *data, struct pt_regs *regs) +cpci_hp_intr(int irq, void *data) { dbg("entered cpci_hp_intr"); diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index c74e9e37e76b..ea040c32f47d 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -409,7 +409,7 @@ extern void cpqhp_remove_debugfs_files (struct controller *ctrl); /* controller functions */ extern void cpqhp_pushbutton_thread (unsigned long event_pointer); -extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data, struct pt_regs *regs); +extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data); extern int cpqhp_find_available_resources (struct controller *ctrl, void __iomem *rom_start); extern int cpqhp_event_start_thread (void); extern void cpqhp_event_stop_thread (void); diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index ae2dd36efef2..3ec2ad7db49a 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -889,7 +889,7 @@ int cpqhp_resource_sort_and_combine(struct pci_resource **head) } -irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs) +irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data) { struct controller *ctrl = data; u8 schedule_flag = 0; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 6ab3b6cd2b54..703a64a39fe8 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -222,7 +222,7 @@ static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ static int ctlr_seq_num = 0; /* Controller sequence # */ static spinlock_t list_lock; -static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs); +static irqreturn_t pcie_isr(int IRQ, void *dev_id); static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); @@ -239,7 +239,7 @@ static void int_poll_timeout(unsigned long lphp_ctlr) } /* Poll for interrupt events. regs == NULL => polling */ - pcie_isr( 0, (void *)php_ctlr, NULL ); + pcie_isr( 0, (void *)php_ctlr ); init_timer(&php_ctlr->int_poll_timer); @@ -863,7 +863,7 @@ static int hpc_power_off_slot(struct slot * slot) return retval; } -static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) +static irqreturn_t pcie_isr(int IRQ, void *dev_id) { struct controller *ctrl = NULL; struct php_ctlr_state_s *php_ctlr; diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 0f9798df4704..4d8aee119134 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -218,7 +218,7 @@ static spinlock_t list_lock; static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); -static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t shpc_isr(int irq, void *dev_id); static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec); static int hpc_check_cmd_status(struct controller *ctrl); @@ -276,7 +276,7 @@ static void int_poll_timeout(unsigned long lphp_ctlr) DBG_ENTER_ROUTINE /* Poll for interrupt events. regs == NULL => polling */ - shpc_isr(0, php_ctlr->callback_instance_id, NULL); + shpc_isr(0, php_ctlr->callback_instance_id); init_timer(&php_ctlr->int_poll_timer); if (!shpchp_poll_time) @@ -870,7 +870,7 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) return retval; } -static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t shpc_isr(int irq, void *dev_id) { struct controller *ctrl = (struct controller *)dev_id; struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 0d4ac027d53e..04c43ef529ac 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -85,11 +85,10 @@ static struct pcie_port_service_driver aerdrv = { * aer_irq - Root Port's ISR * @irq: IRQ assigned to Root Port * @context: pointer to Root Port data structure - * @r: pointer struct pt_regs * * Invoked when Root Port detects AER messages. **/ -static irqreturn_t aer_irq(int irq, void *context, struct pt_regs * r) +static irqreturn_t aer_irq(int irq, void *context) { unsigned int status, id; struct pcie_device *pdev = (struct pcie_device *)context; diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index 40569f40e90e..991e084db2d6 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -64,7 +64,7 @@ static int at91_cf_ss_init(struct pcmcia_socket *s) return 0; } -static irqreturn_t at91_cf_irq(int irq, void *_cf, struct pt_regs *r) +static irqreturn_t at91_cf_irq(int irq, void *_cf) { struct at91_cf_socket *cf = (struct at91_cf_socket *) _cf; diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index ad02629c8be2..db3c26b5de14 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c @@ -671,7 +671,7 @@ static int hs_irq_demux(int irq, void *dev) * Interrupt handling routine. */ -static irqreturn_t hs_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t hs_interrupt(int irq, void *dev) { hs_socket_t *sp = (hs_socket_t *)dev; u_int events = 0; diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index 2163aa75a257..82715f448957 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -315,7 +315,7 @@ static int to_cycles(int ns) /* Interrupt handler functionality */ -static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t i82092aa_interrupt(int irq, void *dev) { int i; int loopcount = 0; diff --git a/drivers/pcmcia/i82092aa.h b/drivers/pcmcia/i82092aa.h index 9c14599d0673..b0d453303c5d 100644 --- a/drivers/pcmcia/i82092aa.h +++ b/drivers/pcmcia/i82092aa.h @@ -23,7 +23,7 @@ static int i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id); static void i82092aa_pci_remove(struct pci_dev *dev); static int card_present(int socketno); -static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs); +static irqreturn_t i82092aa_interrupt(int irq, void *dev); diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 1cc2682394b1..ea74f98a7350 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -80,7 +80,7 @@ module_param(pc_debug, int, 0644); #define debug(lvl, fmt, arg...) do { } while (0) #endif -static irqreturn_t i365_count_irq(int, void *, struct pt_regs *); +static irqreturn_t i365_count_irq(int, void *); static inline int _check_irq(int irq, int flags) { if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0) @@ -498,7 +498,7 @@ static u_int __init set_bridge_opts(u_short s, u_short ns) static volatile u_int irq_hits; static u_short irq_sock; -static irqreturn_t i365_count_irq(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t i365_count_irq(int irq, void *dev) { i365_get(irq_sock, I365_CSC); irq_hits++; @@ -848,8 +848,7 @@ static void __init isa_probe(void) /*====================================================================*/ -static irqreturn_t pcic_interrupt(int irq, void *dev, - struct pt_regs *regs) +static irqreturn_t pcic_interrupt(int irq, void *dev) { int i, j, csc; u_int events, active; @@ -898,7 +897,7 @@ static irqreturn_t pcic_interrupt(int irq, void *dev, static void pcic_interrupt_wrapper(u_long data) { - pcic_interrupt(0, NULL, NULL); + pcic_interrupt(0, NULL); poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer); } diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 9e768eaef17a..36fdaa58458c 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -254,7 +254,7 @@ static pcc_t pcc[] = { #endif /* CONFIG_PLAT_USRV */ }; -static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *); +static irqreturn_t pcc_interrupt(int, void *); /*====================================================================*/ @@ -372,14 +372,13 @@ static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr /*====================================================================*/ -static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t pcc_interrupt(int irq, void *dev) { int i; u_int events = 0; int handled = 0; - debug(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p, regs=%p\n", - irq, dev, regs); + debug(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p\n", irq, dev); for (i = 0; i < pcc_sockets; i++) { if (socket[i].cs_irq1 != irq && socket[i].cs_irq2 != irq) continue; diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 61d50b5620dd..0964fd76bfe3 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -267,7 +267,7 @@ static pcc_t pcc[] = { { "xnux2", 0 }, { "xnux2", 0 }, }; -static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *); +static irqreturn_t pcc_interrupt(int, void *); /*====================================================================*/ @@ -352,7 +352,7 @@ static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr /*====================================================================*/ -static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t pcc_interrupt(int irq, void *dev) { int i, j, irc; u_int events, active; diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index d0f68ab8f041..e070a2896769 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -266,7 +266,7 @@ static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] = /* ------------------------------------------------------------------------- */ -static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs); +static irqreturn_t m8xx_interrupt(int irq, void *dev); #define PCMCIA_BMT_LIMIT (15*4) /* Bus Monitor Timeout value */ @@ -646,7 +646,7 @@ static struct platform_device m8xx_device = { static u32 pending_events[PCMCIA_SOCKETS_NO]; static DEFINE_SPINLOCK(pending_event_lock); -static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t m8xx_interrupt(int irq, void *dev) { struct socket_info *s; struct event_table *e; diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 01be47e72730..c8e838c69766 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -102,7 +102,7 @@ static void omap_cf_timer(unsigned long _cf) * claim the card's IRQ. It may also detect some card insertions, but * not removals; it can't always eliminate timer irqs. */ -static irqreturn_t omap_cf_irq(int irq, void *_cf, struct pt_regs *r) +static irqreturn_t omap_cf_irq(int irq, void *_cf) { omap_cf_timer((unsigned long)_cf); return IRQ_HANDLED; diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index c8323399e9e4..74cebd424032 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -784,7 +784,7 @@ EXPORT_SYMBOL(pcmcia_request_io); */ #ifdef CONFIG_PCMCIA_PROBE -static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs) +static irqreturn_t test_action(int cpl, void *dev_id) { return IRQ_NONE; } diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 22c5e7427ddd..c83a0a6b158f 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -182,7 +182,7 @@ static void indirect_write16(struct pd6729_socket *socket, unsigned short reg, /* Interrupt handler functionality */ -static irqreturn_t pd6729_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t pd6729_interrupt(int irq, void *dev) { struct pd6729_socket *socket = (struct pd6729_socket *)dev; int i; @@ -249,7 +249,7 @@ static void pd6729_interrupt_wrapper(unsigned long data) { struct pd6729_socket *socket = (struct pd6729_socket *) data; - pd6729_interrupt(0, (void *)socket, NULL); + pd6729_interrupt(0, (void *)socket); mod_timer(&socket->poll_timer, jiffies + HZ); } @@ -575,7 +575,7 @@ static struct pccard_operations pd6729_operations = { .set_mem_map = pd6729_set_mem_map, }; -static irqreturn_t pd6729_test(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t pd6729_test(int irq, void *dev) { dprintk("-> hit on irq %d\n", irq); return IRQ_HANDLED; diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index ecaa132fa592..3627e52e0c27 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -256,7 +256,7 @@ static void soc_common_pcmcia_poll_event(unsigned long dummy) * handling code performs scheduling operations which cannot be * executed from within an interrupt context. */ -static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev) { struct soc_pcmcia_socket *skt = dev; diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index 65a60671659f..2d2f415f80a8 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -116,7 +116,7 @@ module_param(cycle_time, int, 0444); /*====================================================================*/ -static irqreturn_t tcic_interrupt(int irq, void *dev, struct pt_regs *regs); +static irqreturn_t tcic_interrupt(int irq, void *dev); static void tcic_timer(u_long data); static struct pccard_operations tcic_operations; @@ -218,7 +218,7 @@ static int to_cycles(int ns) static volatile u_int irq_hits; -static irqreturn_t __init tcic_irq_count(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t __init tcic_irq_count(int irq, void *dev) { irq_hits++; return IRQ_HANDLED; @@ -505,7 +505,7 @@ static int __init init_tcic(void) } /* jump start interrupt handler, if needed */ - tcic_interrupt(0, NULL, NULL); + tcic_interrupt(0, NULL); platform_device_register(&tcic_device); @@ -547,7 +547,7 @@ static void __exit exit_tcic(void) /*====================================================================*/ -static irqreturn_t tcic_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t tcic_interrupt(int irq, void *dev) { int i, quick = 0; u_char latch, sstat; @@ -606,7 +606,7 @@ static void tcic_timer(u_long data) { debug(2, "tcic_timer()\n"); tcic_timer_pending = 0; - tcic_interrupt(0, NULL, NULL); + tcic_interrupt(0, NULL); } /* tcic_timer */ /*====================================================================*/ diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index e076a13db555..e90d8e8c5fd6 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -514,7 +514,7 @@ static inline unsigned int get_events(int slot) return events; } -static irqreturn_t pccard_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pccard_interrupt(int irq, void *dev_id) { vrc4171_socket_t *socket; unsigned int events; diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c index d19a9138135f..812f038e9bda 100644 --- a/drivers/pcmcia/vrc4173_cardu.c +++ b/drivers/pcmcia/vrc4173_cardu.c @@ -440,7 +440,7 @@ static uint16_t get_events(vrc4173_socket_t *socket) return events; } -static void cardu_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void cardu_interrupt(int irq, void *dev_id) { vrc4173_socket_t *socket = (vrc4173_socket_t *)dev_id; uint16_t events; diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 1344746381e8..26229d9da762 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -442,7 +442,7 @@ static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map * -static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t yenta_interrupt(int irq, void *dev_id) { unsigned int events; struct yenta_socket *socket = (struct yenta_socket *) dev_id; @@ -478,7 +478,7 @@ static void yenta_interrupt_wrapper(unsigned long data) { struct yenta_socket *socket = (struct yenta_socket *) data; - yenta_interrupt(0, (void *)socket, NULL); + yenta_interrupt(0, (void *)socket); socket->poll_timer.expires = jiffies + HZ; add_timer(&socket->poll_timer); } @@ -896,7 +896,7 @@ static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mas #ifdef CONFIG_YENTA_TI /* interrupt handler, only used during probing */ -static irqreturn_t yenta_probe_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t yenta_probe_handler(int irq, void *dev_id) { struct yenta_socket *socket = (struct yenta_socket *) dev_id; u8 csc; diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index 5c8ec21e1086..a685fbec4604 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -348,7 +348,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx) return 1; } -static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pnp_test_handler(int irq, void *dev_id) { return IRQ_HANDLED; } diff --git a/drivers/rtc/rtc-at91.c b/drivers/rtc/rtc-at91.c index c0714da44920..bd61e99540a3 100644 --- a/drivers/rtc/rtc-at91.c +++ b/drivers/rtc/rtc-at91.c @@ -238,8 +238,7 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq) /* * IRQ handler for the RTC */ -static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) { struct platform_device *pdev = dev_id; struct rtc_device *rtc = platform_get_drvdata(pdev); diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 9647188fee2c..78552e6e76aa 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -189,8 +189,7 @@ static int ds1553_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) return 0; } -static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id) { struct platform_device *pdev = dev_id; struct rtc_plat_data *pdata = platform_get_drvdata(pdev); diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 739d1a6e14eb..f13daa9fecaa 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -47,7 +47,7 @@ struct pl031_local { void __iomem *base; }; -static irqreturn_t pl031_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pl031_interrupt(int irq, void *dev_id) { struct rtc_device *rtc = dev_id; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 625dad2eeb4f..e301dea57bb3 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -46,7 +46,7 @@ static unsigned int tick_count; /* IRQ Handlers */ -static irqreturn_t s3c_rtc_alarmirq(int irq, void *id, struct pt_regs *r) +static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) { struct rtc_device *rdev = id; @@ -54,7 +54,7 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id, struct pt_regs *r) return IRQ_HANDLED; } -static irqreturn_t s3c_rtc_tickirq(int irq, void *id, struct pt_regs *r) +static irqreturn_t s3c_rtc_tickirq(int irq, void *id) { struct rtc_device *rdev = id; diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 439c41aea31c..bd4d7d174ef4 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -68,8 +68,7 @@ static int rtc_update_alarm(struct rtc_time *alrm) return ret; } -static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) { struct platform_device *pdev = to_platform_device(dev_id); struct rtc_device *rtc = platform_get_drvdata(pdev); @@ -106,8 +105,7 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id, static int rtc_timer1_count; -static irqreturn_t timer1_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t timer1_interrupt(int irq, void *dev_id) { struct platform_device *pdev = to_platform_device(dev_id); struct rtc_device *rtc = platform_get_drvdata(pdev); diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index d2ce0c8bb8f3..8b6efcc05058 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -73,7 +73,7 @@ struct sh_rtc { spinlock_t lock; }; -static irqreturn_t sh_rtc_interrupt(int irq, void *id, struct pt_regs *regs) +static irqreturn_t sh_rtc_interrupt(int irq, void *id) { struct platform_device *pdev = id; struct sh_rtc *rtc = platform_get_drvdata(pdev); @@ -97,7 +97,7 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t sh_rtc_periodic(int irq, void *id, struct pt_regs *regs) +static irqreturn_t sh_rtc_periodic(int irq, void *id) { struct sh_rtc *rtc = dev_get_drvdata(id); diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 58e5ed0aa127..e40322b71938 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -268,7 +268,7 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long return 0; } -static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id) { struct platform_device *pdev = (struct platform_device *)dev_id; struct rtc_device *rtc = platform_get_drvdata(pdev); @@ -280,7 +280,7 @@ static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs * return IRQ_HANDLED; } -static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t rtclong1_interrupt(int irq, void *dev_id) { struct platform_device *pdev = (struct platform_device *)dev_id; struct rtc_device *rtc = platform_get_drvdata(pdev); diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c index a305d4091547..a54b4ac67568 100644 --- a/drivers/sbus/char/aurora.c +++ b/drivers/sbus/char/aurora.c @@ -254,7 +254,7 @@ for(i=0;ihost_lock, flags); - NCR53c406a_intr(0, dev_id, regs); + NCR53c406a_intr(0, dev_id); spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED; } -static void NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs) +static void NCR53c406a_intr(int unused, void *dev_id) { DEB(unsigned char fifo_size; ) diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index d05681f9d81a..9859cd17fc57 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c @@ -226,14 +226,14 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq, } static int -NCR_D700_intr(int irq, void *data, struct pt_regs *regs) +NCR_D700_intr(int irq, void *data) { struct NCR_D700_private *p = (struct NCR_D700_private *)data; int i, found = 0; for (i = 0; i < 2; i++) if (p->hosts[i] && - NCR_700_intr(irq, p->hosts[i], regs) == IRQ_HANDLED) + NCR_700_intr(irq, p->hosts[i]) == IRQ_HANDLED) found++; return found ? IRQ_HANDLED : IRQ_NONE; diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c index c39ffbb86e39..778844c3544a 100644 --- a/drivers/scsi/NCR_Q720.c +++ b/drivers/scsi/NCR_Q720.c @@ -54,7 +54,7 @@ static struct scsi_host_template NCR_Q720_tpnt = { }; static irqreturn_t -NCR_Q720_intr(int irq, void *data, struct pt_regs * regs) +NCR_Q720_intr(int irq, void *data) { struct NCR_Q720_private *p = (struct NCR_Q720_private *)data; __u8 sir = (readb(p->mem_base + 0x0d) & 0xf0) >> 4; @@ -68,7 +68,7 @@ NCR_Q720_intr(int irq, void *data, struct pt_regs * regs) while((siop = ffz(sir)) < p->siops) { sir |= 1<hosts[siop], regs); + ncr53c8xx_intr(irq, p->hosts[siop]); } return IRQ_HANDLED; } diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index 2684150917e6..2650a5d0a161 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -1013,7 +1013,7 @@ static void inia100SCBPost(BYTE * pHcb, BYTE * pScb) /* * Interrupt handler (main routine of the driver) */ -static irqreturn_t inia100_intr(int irqno, void *devid, struct pt_regs *regs) +static irqreturn_t inia100_intr(int irqno, void *devid) { struct Scsi_Host *host = (struct Scsi_Host *)devid; ORC_HCS *pHcb = (ORC_HCS *)host->hostdata; diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index 085406928605..f77016d31cab 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -24,7 +24,7 @@ #define DMA(ptr) ((a2091_scsiregs *)((ptr)->base)) #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) -static irqreturn_t a2091_intr (int irq, void *_instance, struct pt_regs *fp) +static irqreturn_t a2091_intr (int irq, void *_instance) { unsigned long flags; unsigned int status; diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 7bf46d40b561..1299bc8edef1 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -26,7 +26,7 @@ static struct Scsi_Host *a3000_host = NULL; -static irqreturn_t a3000_intr (int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t a3000_intr (int irq, void *dummy) { unsigned long flags; unsigned int status = DMA(a3000_host)->ISTR; diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index a1d214d770eb..dcc8b0ea7a9d 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -46,11 +46,11 @@ #include "aacraid.h" -static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t aac_rx_intr(int irq, void *dev_id) { struct aac_dev *dev = dev_id; - dprintk((KERN_DEBUG "aac_rx_intr(%d,%p,%p)\n", irq, dev_id, regs)); + dprintk((KERN_DEBUG "aac_rx_intr(%d,%p)\n", irq, dev_id)); if (dev->new_comm_interface) { u32 Index = rx_readl(dev, MUnit.OutboundQueue); if (Index == 0xFFFFFFFFL) diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index f906ead239dd..511b0a938fb1 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -46,7 +46,7 @@ #include "aacraid.h" -static irqreturn_t aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t aac_sa_intr(int irq, void *dev_id) { struct aac_dev *dev = dev_id; unsigned short intstat, mask; diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 773f02e3b10b..83695416b2c9 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -3999,7 +3999,7 @@ STATIC PortAddr _asc_def_iop_base[]; * advansys.h contains function prototypes for functions global to Linux. */ -STATIC irqreturn_t advansys_interrupt(int, void *, struct pt_regs *); +STATIC irqreturn_t advansys_interrupt(int, void *); STATIC int advansys_slave_configure(struct scsi_device *); STATIC void asc_scsi_done_list(struct scsi_cmnd *); STATIC int asc_execute_scsi_cmnd(struct scsi_cmnd *); @@ -5997,7 +5997,7 @@ static struct scsi_host_template driver_template = { * an AdvanSys adapter. */ STATIC irqreturn_t -advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs) +advansys_interrupt(int irq, void *dev_id) { ulong flags; int i; diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index fb6a476eb873..e04c2bc1932b 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -673,7 +673,7 @@ static struct { }; /* setup & interrupt */ -static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *); +static irqreturn_t intr(int irq, void *dev_id); static void reset_ports(struct Scsi_Host *shpnt); static void aha152x_error(struct Scsi_Host *shpnt, char *msg); static void done(struct Scsi_Host *shpnt, int error); @@ -757,7 +757,7 @@ static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp) return ptr; } -static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs) +static irqreturn_t swintr(int irqno, void *dev_id) { struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id; @@ -1463,7 +1463,7 @@ static void run(void) * Interrupt handler * */ -static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs) +static irqreturn_t intr(int irqno, void *dev_id) { struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id; unsigned long flags; diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 24f0f5461792..d7a61a6bdaae 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -174,9 +174,8 @@ static DEFINE_SPINLOCK(aha1542_lock); static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt); static int aha1542_restart(struct Scsi_Host *shost); -static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs); -static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id, - struct pt_regs *regs); +static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id); +static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id); #define aha1542_intr_reset(base) outb(IRST, CONTROL(base)) @@ -416,8 +415,7 @@ fail: } /* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */ -static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id) { unsigned long flags; struct Scsi_Host *shost; @@ -427,13 +425,13 @@ static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id, panic("Splunge!"); spin_lock_irqsave(shost->host_lock, flags); - aha1542_intr_handle(shost, dev_id, regs); + aha1542_intr_handle(shost, dev_id); spin_unlock_irqrestore(shost->host_lock, flags); return IRQ_HANDLED; } /* A "high" level interrupt handler */ -static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs) +static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id) { void (*my_done) (Scsi_Cmnd *) = NULL; int errstatus, mbi, mbo, mbistatus; diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index 6b35ed8301e0..c3c38a7e8d32 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -223,8 +223,7 @@ static int aha1740_test_port(unsigned int base) } /* A "high" level interrupt handler */ -static irqreturn_t aha1740_intr_handle(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t aha1740_intr_handle(int irq, void *dev_id) { struct Scsi_Host *host = (struct Scsi_Host *) dev_id; void (*my_done)(Scsi_Cmnd *); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 1faa008b5b81..f8e60486167d 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1557,7 +1557,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, * SCSI controller interrupt handler. */ irqreturn_t -ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) +ahd_linux_isr(int irq, void *dev_id) { struct ahd_softc *ahd; u_long flags; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 601340d84410..fb3d4dd54413 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -862,7 +862,7 @@ int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); irqreturn_t - ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs); + ahd_linux_isr(int irq, void *dev_id); void ahd_done(struct ahd_softc*, struct scb*); void ahd_send_async(struct ahd_softc *, char channel, u_int target, u_int lun, ac_code); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 339b85cb61cd..43ab753d2739 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1608,7 +1608,7 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev, * SCSI controller interrupt handler. */ irqreturn_t -ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) +ahc_linux_isr(int irq, void *dev_id) { struct ahc_softc *ahc; u_long flags; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index d42a71ee076d..a87a4ce090df 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -830,7 +830,7 @@ int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); irqreturn_t - ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs); + ahc_linux_isr(int irq, void *dev_id); void ahc_platform_flushwork(struct ahc_softc *ahc); void ahc_done(struct ahc_softc*, struct scb*); void ahc_send_async(struct ahc_softc *, char channel, diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 3eae8062a02e..7f0adf9c4c7e 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -6345,7 +6345,7 @@ aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p) * SCSI controller interrupt handler. *-F*************************************************************************/ static void -aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) +aic7xxx_isr(int irq, void *dev_id) { struct aic7xxx_host *p; unsigned char intstat; @@ -6477,7 +6477,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) * anything like it, please inform the Gross Hack Police immediately *-F*************************************************************************/ static irqreturn_t -do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) +do_aic7xxx_isr(int irq, void *dev_id) { unsigned long cpu_flags; struct aic7xxx_host *p; @@ -6489,7 +6489,7 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) p->flags |= AHC_IN_ISR; do { - aic7xxx_isr(irq, dev_id, regs); + aic7xxx_isr(irq, dev_id); } while ( (aic_inb(p, INTSTAT) & INT_PEND) ); aic7xxx_done_cmds_complete(p); aic7xxx_run_waiting_queues(p); @@ -10377,7 +10377,7 @@ static int __aic7xxx_bus_device_reset(struct scsi_cmnd *cmd) hscb = scb->hscb; - aic7xxx_isr(p->irq, (void *)p, NULL); + aic7xxx_isr(p->irq, (void *)p); aic7xxx_done_cmds_complete(p); /* If the command was already complete or just completed, then we didn't * do a reset, return FAILED */ @@ -10608,7 +10608,7 @@ static int __aic7xxx_abort(struct scsi_cmnd *cmd) else return FAILED; - aic7xxx_isr(p->irq, (void *)p, NULL); + aic7xxx_isr(p->irq, (void *)p); aic7xxx_done_cmds_complete(p); /* If the command was already complete or just completed, then we didn't * do a reset, return FAILED */ @@ -10863,7 +10863,7 @@ static int aic7xxx_reset(struct scsi_cmnd *cmd) while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) { - aic7xxx_isr(p->irq, p, (void *)NULL ); + aic7xxx_isr(p->irq, p); pause_sequencer(p); } aic7xxx_done_cmds_complete(p); diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index 1d8c5e5f442e..3c2d7a379931 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -996,11 +996,10 @@ static inline void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha) * asd_hw_isr -- host adapter interrupt service routine * @irq: ignored * @dev_id: pointer to host adapter structure - * @regs: ignored * * The ISR processes done list entries and level 3 error handling. */ -irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t asd_hw_isr(int irq, void *dev_id) { struct asd_ha_struct *asd_ha = dev_id; u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT); diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h index 8498144aa5e1..14319d1d6804 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.h +++ b/drivers/scsi/aic94xx/aic94xx_hwi.h @@ -371,7 +371,7 @@ static inline void asd_ascb_free_list(struct asd_ascb *ascb_list) /* ---------- Function declarations ---------- */ int asd_init_hw(struct asd_ha_struct *asd_ha); -irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t asd_hw_isr(int irq, void *dev_id); struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h index 1b637592d5ae..7cd63a996886 100644 --- a/drivers/scsi/amiga7xx.h +++ b/drivers/scsi/amiga7xx.h @@ -8,7 +8,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int NCR53c7xx_abort(Scsi_Cmnd *); int NCR53c7x0_release (struct Scsi_Host *); int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int); -void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs); +void NCR53c7x0_intr(int irq, void *dev_id); #ifndef CMD_PER_LUN #define CMD_PER_LUN 3 diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 475f978ff8f0..086cc97eee8c 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -147,8 +147,7 @@ static struct pci_driver arcmsr_pci_driver = { .shutdown = arcmsr_shutdown }; -static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) { irqreturn_t handle_state; struct AdapterControlBlock *acb; diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index 0525d672e1e6..9cf902b7a126 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -2461,14 +2461,13 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) } /* - * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs) + * Prototype: void acornscsi_intr(int irq, void *dev_id) * Purpose : handle interrupts from Acorn SCSI card * Params : irq - interrupt number * dev_id - device specific data (AS_Host structure) - * regs - processor registers when interrupt occurred */ static irqreturn_t -acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs) +acornscsi_intr(int irq, void *dev_id) { AS_Host *host = (AS_Host *)dev_id; intr_ret_t ret; diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index 719af0dcc0e5..19edd9c853d9 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -137,10 +137,9 @@ cumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off) * Purpose : handle interrupts from Cumana SCSI 2 card * Params : irq - interrupt number * dev_id - user-defined (Scsi_Host structure) - * regs - processor registers at interrupt */ static irqreturn_t -cumanascsi_2_intr(int irq, void *dev_id, struct pt_regs *regs) +cumanascsi_2_intr(int irq, void *dev_id) { struct cumanascsi2_info *info = dev_id; diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index dcbb4b2b3fe0..3f876fb75469 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -138,10 +138,9 @@ eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off) * Purpose : handle interrupts from EESOX SCSI card * Params : irq - interrupt number * dev_id - user-defined (Scsi_Host structure) - * regs - processor registers at interrupt */ static irqreturn_t -eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs) +eesoxscsi_intr(int irq, void *dev_id) { struct eesoxscsi_info *info = dev_id; diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index b2c346a47052..ce159c15bc86 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -112,10 +112,8 @@ powertecscsi_terminator_ctl(struct Scsi_Host *host, int on_off) * Purpose : handle interrupts from Powertec SCSI card * Params : irq - interrupt number * dev_id - user-defined (Scsi_Host structure) - * regs - processor registers at interrupt */ -static irqreturn_t -powertecscsi_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t powertecscsi_intr(int irq, void *dev_id) { struct powertec_info *info = dev_id; diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index e397129c90d1..0f920c84ac0f 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -1262,7 +1262,7 @@ static void NCR5380_dma_complete( struct Scsi_Host *instance ) * */ -static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t NCR5380_intr (int irq, void *dev_id) { struct Scsi_Host *instance = first_instance; int done = 1, handled = 0; diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c index 8d5d2a5da961..cdc710ea00fa 100644 --- a/drivers/scsi/atari_dma_emul.c +++ b/drivers/scsi/atari_dma_emul.c @@ -110,7 +110,7 @@ static inline void set_restdata_reg(unsigned char *cur_addr) } /* - * void hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp) + * void hades_dma_emulator(int irq, void *dummy) * * This code emulates TT SCSI DMA on the Hades. * @@ -140,7 +140,7 @@ static inline void set_restdata_reg(unsigned char *cur_addr) * increased with one. */ -static irqreturn_t hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t hades_dma_emulator(int irq, void *dummy) { unsigned long dma_base; register unsigned long dma_cnt asm ("d3"); diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index e1be4a4387cd..dfb1bcfae82e 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -194,8 +194,8 @@ static int falcon_classify_cmd( Scsi_Cmnd *cmd ); static unsigned long atari_dma_xfer_len( unsigned long wanted_len, Scsi_Cmnd *cmd, int write_flag ); #endif -static irqreturn_t scsi_tt_intr( int irq, void *dummy, struct pt_regs *fp); -static irqreturn_t scsi_falcon_intr( int irq, void *dummy, struct pt_regs *fp); +static irqreturn_t scsi_tt_intr( int irq, void *dummy); +static irqreturn_t scsi_falcon_intr( int irq, void *dummy); static void falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ); static void falcon_get_lock( void ); @@ -285,7 +285,7 @@ static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ) * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has * to clear the DMA int pending bit before it allows other level 6 interrupts. */ -static void scsi_dma_buserr (int irq, void *dummy, struct pt_regs *fp) +static void scsi_dma_buserr (int irq, void *dummy) { unsigned char dma_stat = tt_scsi_dma.dma_ctrl; @@ -314,7 +314,7 @@ static void scsi_dma_buserr (int irq, void *dummy, struct pt_regs *fp) #endif -static irqreturn_t scsi_tt_intr (int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t scsi_tt_intr (int irq, void *dummy) { #ifdef REAL_DMA int dma_stat; @@ -406,7 +406,7 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy, struct pt_regs *fp) } -static irqreturn_t scsi_falcon_intr (int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t scsi_falcon_intr (int irq, void *dummy) { #ifdef REAL_DMA int dma_stat; diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 0ec41f34f462..fec58cc47f1c 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -44,7 +44,7 @@ static void send_s870(struct atp_unit *dev,unsigned char c); static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c); static void tscam_885(void); -static irqreturn_t atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t atp870u_intr_handle(int irq, void *dev_id) { unsigned long flags; unsigned short int tmpcip, id; diff --git a/drivers/scsi/bvme6000.h b/drivers/scsi/bvme6000.h index 7c9c0366cc08..ea3e4b2b9220 100644 --- a/drivers/scsi/bvme6000.h +++ b/drivers/scsi/bvme6000.h @@ -9,7 +9,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int NCR53c7xx_abort(Scsi_Cmnd *); int NCR53c7x0_release (struct Scsi_Host *); int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int); -void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs); +void NCR53c7x0_intr(int irq, void *dev_id); #ifndef CMD_PER_LUN #define CMD_PER_LUN 3 diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index c6118d99385e..81e3ee51d897 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1813,8 +1813,7 @@ static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, } -static irqreturn_t dc395x_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t dc395x_interrupt(int irq, void *dev_id) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)dev_id; u16 scsi_status; diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c index eb32062f7e68..c29ccbc44693 100644 --- a/drivers/scsi/dec_esp.c +++ b/drivers/scsi/dec_esp.c @@ -94,9 +94,9 @@ volatile unsigned char pmaz_cmd_buffer[16]; * via PIO. */ -static irqreturn_t scsi_dma_merr_int(int, void *, struct pt_regs *); -static irqreturn_t scsi_dma_err_int(int, void *, struct pt_regs *); -static irqreturn_t scsi_dma_int(int, void *, struct pt_regs *); +static irqreturn_t scsi_dma_merr_int(int, void *); +static irqreturn_t scsi_dma_err_int(int, void *); +static irqreturn_t scsi_dma_int(int, void *); static int dec_esp_detect(struct scsi_host_template * tpnt); @@ -307,7 +307,7 @@ err_dealloc: } /************************************************************* DMA Functions */ -static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id) { printk("Got unexpected SCSI DMA Interrupt! < "); printk("SCSI_DMA_MEMRDERR "); @@ -316,14 +316,14 @@ static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id, struct pt_regs *regs return IRQ_HANDLED; } -static irqreturn_t scsi_dma_err_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t scsi_dma_err_int(int irq, void *dev_id) { /* empty */ return IRQ_HANDLED; } -static irqreturn_t scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t scsi_dma_int(int irq, void *dev_id) { u32 scsi_next_ptr; diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index b20b37661d6f..60b1b434eba7 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -1989,7 +1989,7 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, } -static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t adpt_isr(int irq, void *dev_id) { struct scsi_cmnd* cmd; adpt_hba* pHba = dev_id; diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h index 289983264929..fd79068c5869 100644 --- a/drivers/scsi/dpti.h +++ b/drivers/scsi/dpti.h @@ -263,7 +263,7 @@ struct sg_simple_element { static void adpt_i2o_sys_shutdown(void); static int adpt_init(void); static int adpt_i2o_build_sys_table(void); -static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t adpt_isr(int irq, void *dev_id); #ifdef REBOOT_NOTIFIER static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p); #endif diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index a5ff43b1b263..2d38025861a5 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -875,7 +875,7 @@ static unsigned long io_port[] = { /* But transfer orientation from the 16 bit data register is Little Endian */ #define REG2H(x) le16_to_cpu(x) -static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *); +static irqreturn_t do_interrupt_handler(int, void *); static void flush_dev(struct scsi_device *, unsigned long, struct hostdata *, unsigned int); static int do_trace = 0; @@ -2555,8 +2555,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost) return IRQ_NONE; } -static irqreturn_t do_interrupt_handler(int irq, void *shap, - struct pt_regs *regs) +static irqreturn_t do_interrupt_handler(int irq, void *shap) { struct Scsi_Host *shost; unsigned int j; diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index d312633db92b..811d8840707e 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -194,10 +194,9 @@ static void IncStat(struct scsi_pointer *SCp, unsigned int Increment) } } -static irqreturn_t eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t eata_pio_int_handler(int irq, void *dev_id); -static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id) { unsigned long flags; struct Scsi_Host *dev = dev_id; @@ -209,7 +208,7 @@ static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id, return ret; } -static irqreturn_t eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t eata_pio_int_handler(int irq, void *dev_id) { unsigned int eata_stat = 0xfffff; struct scsi_cmnd *cmd; diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 5630868c1b25..2c2fe80bc42a 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -184,7 +184,7 @@ enum { }; /* Forward declarations. */ -static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs); +static irqreturn_t esp_intr(int irq, void *dev_id); /* Debugging routines */ struct esp_cmdstrings { @@ -4282,7 +4282,7 @@ state_machine: } /* Service only the ESP described by dev_id. */ -static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs) +static irqreturn_t esp_intr(int irq, void *dev_id) { struct esp *esp = dev_id; unsigned long flags; diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c index dde3edf35c03..ef8285c326e4 100644 --- a/drivers/scsi/fd_mcs.c +++ b/drivers/scsi/fd_mcs.c @@ -281,7 +281,7 @@ static struct fd_mcs_adapters_struct fd_mcs_adapters[] = { #define FD_BRDS ARRAY_SIZE(fd_mcs_adapters) -static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t fd_mcs_intr(int irq, void *dev_id); static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 }; static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; @@ -617,7 +617,7 @@ static void my_done(struct Scsi_Host *shpnt, int error) } /* only my_done needs to be protected */ -static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t fd_mcs_intr(int irq, void *dev_id) { unsigned long flags; int status; diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index b0694dcce246..41b05fc45380 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -403,8 +403,7 @@ static volatile int in_interrupt_flag; static int FIFO_Size = 0x2000; /* 8k FIFO for pre-tmc18c30 chips */ -static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id, - struct pt_regs * regs ); +static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id ); /* Allow insmod parameters to be like LILO parameters. For example: insmod fdomain fdomain=0x140,11 */ static char * fdomain = NULL; @@ -1094,8 +1093,7 @@ static void my_done(int error) #endif } -static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id, - struct pt_regs * regs ) +static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id) { unsigned long flags; int status; diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 0f3eb22b979a..4bc14ad92e22 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -424,7 +424,7 @@ static void gdth_delay(int milliseconds); static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs); -static irqreturn_t gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t gdth_interrupt(int irq, void *dev_id); static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp); static int gdth_async_event(int hanum); static void gdth_log_event(gdth_evt_data *dvr, char *buffer); @@ -1804,7 +1804,7 @@ static int gdth_wait(int hanum,int index,ulong32 time) gdth_from_wait = TRUE; do { - gdth_interrupt((int)ha->irq,ha,NULL); + gdth_interrupt((int)ha->irq,ha); if (wait_hanum==hanum && wait_index==index) { answer_found = TRUE; break; @@ -3406,7 +3406,7 @@ static void gdth_clear_events(void) /* SCSI interface functions */ -static irqreturn_t gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs) +static irqreturn_t gdth_interrupt(int irq,void *dev_id) { gdth_ha_str *ha2 = (gdth_ha_str *)dev_id; register gdth_ha_str *ha; diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index 18dbe5c27dac..2f6c1137a6e5 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -24,7 +24,7 @@ #define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base)) #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) -static irqreturn_t gvp11_intr (int irq, void *_instance, struct pt_regs *fp) +static irqreturn_t gvp11_intr (int irq, void *_instance) { unsigned long flags; unsigned int status; diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 28bfb8f9f81d..bec83cbee59a 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -431,7 +431,7 @@ void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag) writel(tag, &hba->iop->outbound_queue); } -static irqreturn_t hptiop_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t hptiop_intr(int irq, void *dev_id) { struct hptiop_hba *hba = dev_id; int handled; diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 2be1dc5d852a..0e57fb6964d5 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -497,8 +497,7 @@ static int option_setup(char *); static int ldn_access_load(int, int); static int ldn_access_total_read_write(int); -static irqreturn_t interrupt_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t interrupt_handler(int irq, void *dev_id) { int host_index, ihost_index; unsigned int intr_reg; diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index 01b8ac641eb8..227c0f2f4d74 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -45,14 +45,11 @@ static unsigned int partition_number = -1; * ibmvscsi_handle_event: - Interrupt handler for crq events * @irq: number of irq to handle, not used * @dev_instance: ibmvscsi_host_data of host that received interrupt - * @regs: pt_regs with registers * * Disables interrupts and schedules srp_task * Always returns IRQ_HANDLED */ -static irqreturn_t ibmvscsi_handle_event(int irq, - void *dev_instance, - struct pt_regs *regs) +static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance) { struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)dev_instance; diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c index 59a4097f1254..312190a69389 100644 --- a/drivers/scsi/in2000.c +++ b/drivers/scsi/in2000.c @@ -829,7 +829,7 @@ static void transfer_bytes(Scsi_Cmnd * cmd, int data_in_dir) * but it _does_ need to be able to compile and run in an SMP kernel.) */ -static irqreturn_t in2000_intr(int irqnum, void *dev_id, struct pt_regs *ptregs) +static irqreturn_t in2000_intr(int irqnum, void *dev_id) { struct Scsi_Host *instance = dev_id; struct IN2000_hostdata *hostdata; diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index 9e10dac61cfd..911f2ff4a1f2 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -2748,7 +2748,7 @@ int tul_wait_done_disc(HCS * pCurHcb) return (tul_bad_seq(pCurHcb)); } -static irqreturn_t i91u_intr(int irqno, void *dev_id, struct pt_regs *regs) +static irqreturn_t i91u_intr(int irqno, void *dev_id) { struct Scsi_Host *dev = dev_id; unsigned long flags; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index e1fe9494125b..2dde821025f3 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3880,12 +3880,11 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, * ipr_isr - Interrupt service routine * @irq: irq number * @devp: pointer to ioa config struct - * @regs: pt_regs struct * * Return value: * IRQ_NONE / IRQ_HANDLED **/ -static irqreturn_t ipr_isr(int irq, void *devp, struct pt_regs *regs) +static irqreturn_t ipr_isr(int irq, void *devp) { struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; unsigned long lock_flags = 0; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 9a9ab297cf17..f06a06ae6092 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -248,7 +248,7 @@ static int ips_eh_abort(struct scsi_cmnd *); static int ips_eh_reset(struct scsi_cmnd *); static int ips_queue(struct scsi_cmnd *, void (*)(struct scsi_cmnd *)); static const char *ips_info(struct Scsi_Host *); -static irqreturn_t do_ipsintr(int, void *, struct pt_regs *); +static irqreturn_t do_ipsintr(int, void *); static int ips_hainit(ips_ha_t *); static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *); static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int); @@ -1328,7 +1328,7 @@ ips_slave_configure(struct scsi_device * SDptr) /* */ /****************************************************************************/ static irqreturn_t -do_ipsintr(int irq, void *dev_id, struct pt_regs * regs) +do_ipsintr(int irq, void *dev_id) { ips_ha_t *ha; unsigned long cpu_flags; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 3d684496acde..1251788ce2a3 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -120,7 +120,7 @@ int lpfc_sli_queue_setup(struct lpfc_hba *); void lpfc_handle_eratt(struct lpfc_hba *); void lpfc_handle_latt(struct lpfc_hba *); -irqreturn_t lpfc_intr_handler(int, void *, struct pt_regs *); +irqreturn_t lpfc_intr_handler(int, void *); void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 70f4d5a1348e..24a1779b9af4 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -3119,7 +3119,7 @@ lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba) } irqreturn_t -lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs) +lpfc_intr_handler(int irq, void *dev_id) { struct lpfc_hba *phba; uint32_t ha_copy; diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 6422de72bf43..753d88306cd1 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -60,8 +60,8 @@ struct fsc_state { static void mac53c94_init(struct fsc_state *); static void mac53c94_start(struct fsc_state *); -static void mac53c94_interrupt(int, void *, struct pt_regs *); -static irqreturn_t do_mac53c94_interrupt(int, void *, struct pt_regs *); +static void mac53c94_interrupt(int, void *); +static irqreturn_t do_mac53c94_interrupt(int, void *); static void cmd_done(struct fsc_state *, int result); static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *); @@ -177,18 +177,18 @@ static void mac53c94_start(struct fsc_state *state) set_dma_cmds(state, cmd); } -static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) +static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id) { unsigned long flags; struct Scsi_Host *dev = ((struct fsc_state *) dev_id)->current_req->device->host; spin_lock_irqsave(dev->host_lock, flags); - mac53c94_interrupt(irq, dev_id, ptregs); + mac53c94_interrupt(irq, dev_id); spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED; } -static void mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) +static void mac53c94_interrupt(int irq, void *dev_id) { struct fsc_state *state = (struct fsc_state *) dev_id; struct mac53c94_regs __iomem *regs = state->regs; diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 118206d68c6c..3586fac9be9a 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -44,7 +44,7 @@ /* #define DEBUG_MAC_ESP */ extern void esp_handle(struct NCR_ESP *esp); -extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs); +extern void mac_esp_intr(int irq, void *dev_id); static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count); static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp); @@ -88,7 +88,7 @@ static int setup_hostid = -1; * set up properly! */ -void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs) +void mac_esp_intr(int irq, void *dev_id) { struct NCR_ESP *esp = (struct NCR_ESP *) dev_id; int irq_p = 0; @@ -122,24 +122,24 @@ void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs) * acknowledge on the various machines */ -void scsi_esp_polled(int irq, void *dev_id, struct pt_regs *pregs) +void scsi_esp_polled(int irq, void *dev_id) { if (esp_initialized == 0) return; - mac_esp_intr(irq, dev_id, pregs); + mac_esp_intr(irq, dev_id); } -void fake_intr(int irq, void *dev_id, struct pt_regs *pregs) +void fake_intr(int irq, void *dev_id) { #ifdef DEBUG_MAC_ESP printk("mac_esp: got irq\n"); #endif - mac_esp_intr(irq, dev_id, pregs); + mac_esp_intr(irq, dev_id); } -irqreturn_t fake_drq(int irq, void *dev_id, struct pt_regs *pregs) +irqreturn_t fake_drq(int irq, void *dev_id) { printk("mac_esp: got drq\n"); return IRQ_HANDLED; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index b87bef69ba0f..86099fde1b2a 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1256,14 +1256,13 @@ bug_blocked_mailbox: * megaraid_isr_iomapped() * @irq - irq * @devp - pointer to our soft state - * @regs - unused * * Interrupt service routine for io-mapped controllers. * Find out if our device is interrupting. If yes, acknowledge the interrupt * and service the completed commands. */ static irqreturn_t -megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs) +megaraid_isr_iomapped(int irq, void *devp) { adapter_t *adapter = devp; unsigned long flags; @@ -1333,14 +1332,13 @@ megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs) * megaraid_isr_memmapped() * @irq - irq * @devp - pointer to our soft state - * @regs - unused * * Interrupt service routine for memory-mapped controllers. * Find out if our device is interrupting. If yes, acknowledge the interrupt * and service the completed commands. */ static irqreturn_t -megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs) +megaraid_isr_memmapped(int irq, void *devp) { adapter_t *adapter = devp; unsigned long flags; diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index 4b75fe619d9c..66529f11d23c 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -991,8 +991,8 @@ static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *); static void __mega_runpendq(adapter_t *); static int issue_scb_block(adapter_t *, u_char *); -static irqreturn_t megaraid_isr_memmapped(int, void *, struct pt_regs *); -static irqreturn_t megaraid_isr_iomapped(int, void *, struct pt_regs *); +static irqreturn_t megaraid_isr_memmapped(int, void *); +static irqreturn_t megaraid_isr_iomapped(int, void *); static void mega_free_scb(adapter_t *, scb_t *); diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 266b3910846b..c0edb662d863 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -120,7 +120,7 @@ static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *, static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *, struct scsi_cmnd *); -static irqreturn_t megaraid_isr(int, void *, struct pt_regs *); +static irqreturn_t megaraid_isr(int, void *); static void megaraid_mbox_dpc(unsigned long); @@ -2231,7 +2231,7 @@ megaraid_ack_sequence(adapter_t *adapter) * Interrupt service routine for memory-mapped mailbox controllers. */ static irqreturn_t -megaraid_isr(int irq, void *devp, struct pt_regs *regs) +megaraid_isr(int irq, void *devp) { adapter_t *adapter = devp; int handled; diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 977b6e8d8525..7e4262f2af96 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -1293,7 +1293,7 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status) /** * megasas_isr - isr entry point */ -static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs) +static irqreturn_t megasas_isr(int irq, void *devp) { return megasas_deplete_reply_queue((struct megasas_instance *)devp, DID_OK); diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 683fc7ae4b8f..c773e35dace7 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -185,7 +185,7 @@ struct mesh_state { * Driver is too messy, we need a few prototypes... */ static void mesh_done(struct mesh_state *ms, int start_next); -static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs); +static void mesh_interrupt(int irq, void *dev_id); static void cmd_complete(struct mesh_state *ms); static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd); static void halt_dma(struct mesh_state *ms); @@ -1015,13 +1015,13 @@ static void handle_reset(struct mesh_state *ms) out_8(&mr->sequence, SEQ_ENBRESEL); } -static irqreturn_t do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) +static irqreturn_t do_mesh_interrupt(int irq, void *dev_id) { unsigned long flags; struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host; spin_lock_irqsave(dev->host_lock, flags); - mesh_interrupt(irq, dev_id, ptregs); + mesh_interrupt(irq, dev_id); spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED; } @@ -1661,7 +1661,7 @@ static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) * handler (do_mesh_interrupt) or by other functions in * exceptional circumstances */ -static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) +static void mesh_interrupt(int irq, void *dev_id) { struct mesh_state *ms = (struct mesh_state *) dev_id; volatile struct mesh_regs __iomem *mr = ms->mesh; diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c index 9b991b746d1e..1ddd7a11a958 100644 --- a/drivers/scsi/mvme147.c +++ b/drivers/scsi/mvme147.c @@ -20,7 +20,7 @@ static struct Scsi_Host *mvme147_host = NULL; -static irqreturn_t mvme147_intr (int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t mvme147_intr (int irq, void *dummy) { if (irq == MVME147_IRQ_SCSI_PORT) wd33c93_intr (mvme147_host); diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h index c7a12533fb2c..73e33b37a3f8 100644 --- a/drivers/scsi/mvme16x.h +++ b/drivers/scsi/mvme16x.h @@ -9,7 +9,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int NCR53c7xx_abort(Scsi_Cmnd *); int NCR53c7x0_release (struct Scsi_Host *); int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int); -void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs); +void NCR53c7x0_intr(int irq, void *dev_id); #ifndef CMD_PER_LUN #define CMD_PER_LUN 3 diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index b28712df0b77..6cc2bc2f62be 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -8111,7 +8111,7 @@ printk("ncr53c8xx : command successfully queued\n"); return sts; } -irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) +irqreturn_t ncr53c8xx_intr(int irq, void *dev_id) { unsigned long flags; struct Scsi_Host *shost = (struct Scsi_Host *)dev_id; diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h index 78818b6684f8..cb8b7701431e 100644 --- a/drivers/scsi/ncr53c8xx.h +++ b/drivers/scsi/ncr53c8xx.h @@ -1322,7 +1322,7 @@ struct ncr_device { extern struct Scsi_Host *ncr_attach(struct scsi_host_template *tpnt, int unit, struct ncr_device *device); extern int ncr53c8xx_release(struct Scsi_Host *host); -irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); +irqreturn_t ncr53c8xx_intr(int irq, void *dev_id); extern int ncr53c8xx_init(void); extern void ncr53c8xx_exit(void); diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 1c624ce81897..7c13f6f4a4c6 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -256,7 +256,7 @@ static void nsp32_sack_negate (nsp32_hw_data *); static void nsp32_do_bus_reset(nsp32_hw_data *); /* hardware interrupt handler */ -static irqreturn_t do_nsp32_isr(int, void *, struct pt_regs *); +static irqreturn_t do_nsp32_isr(int, void *); /* initialize hardware */ static int nsp32hw_init(nsp32_hw_data *); @@ -1201,7 +1201,7 @@ static int nsp32hw_init(nsp32_hw_data *data) /* interrupt routine */ -static irqreturn_t do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t do_nsp32_isr(int irq, void *dev_id) { nsp32_hw_data *data = dev_id; unsigned int base = data->BaseAddress; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 053303d36118..b1d346049525 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -948,7 +948,7 @@ static int nsp_nexus(Scsi_Cmnd *SCpnt) /* * interrupt handler */ -static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t nspintr(int irq, void *dev_id) { unsigned int base; unsigned char irq_status, irq_phase, phase; diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index 8908b8e5b78a..a88714f4c05b 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h @@ -346,7 +346,7 @@ static int nsp_reselected (Scsi_Cmnd *SCpnt); static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht); /* Interrupt handler */ -//static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs); +//static irqreturn_t nspintr(int irq, void *dev_id); /* Module entry point*/ static int __init nsp_cs_init(void); diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 0b65099acb1a..72fe5d055de1 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -363,7 +363,7 @@ SYM53C500_pio_write(int fast_pio, int base, unsigned char *request, unsigned int } static irqreturn_t -SYM53C500_intr(int irq, void *dev_id, struct pt_regs *regs) +SYM53C500_intr(int irq, void *dev_id) { unsigned long flags; struct Scsi_Host *dev = dev_id; diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c index 5c2cdf523c3b..a720c9265e66 100644 --- a/drivers/scsi/psi240i.c +++ b/drivers/scsi/psi240i.c @@ -247,12 +247,11 @@ static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status) * * Parameters: irq - Hardware IRQ number. * dev_id - - * regs - * * Returns: TRUE if drive is not ready in time. * ****************************************************************/ -static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs) +static void Irq_Handler (int irq, void *dev_id) { struct Scsi_Host *shost; // Pointer to host data block PADAPTER240I padapter; // Pointer to adapter control structure @@ -368,13 +367,13 @@ irqerror:; SCpnt->scsi_done (SCpnt); } -static irqreturn_t do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t do_Irq_Handler (int irq, void *dev_id) { unsigned long flags; struct Scsi_Host *dev = dev_id; spin_lock_irqsave(dev->host_lock, flags); - Irq_Handler(irq, dev_id, regs); + Irq_Handler(irq, dev_id); spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED; } diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 9f33e5946c0d..2521d548dd59 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1113,7 +1113,7 @@ qla1280_enable_intrs(struct scsi_qla_host *ha) * Handles the H/W interrupt **************************************************************************/ static irqreturn_t -qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +qla1280_intr_handler(int irq, void *dev_id) { struct scsi_qla_host *ha; struct device_reg __iomem *reg; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c37a30aa2146..bab33f6d0bdb 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2009,7 +2009,7 @@ struct isp_operations { char * (*pci_info_str) (struct scsi_qla_host *, char *); char * (*fw_version_str) (struct scsi_qla_host *, char *); - irqreturn_t (*intr_handler) (int, void *, struct pt_regs *); + irq_handler_t intr_handler; void (*enable_intrs) (struct scsi_qla_host *); void (*disable_intrs) (struct scsi_qla_host *); diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index bef7011378c6..75138109b139 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -217,9 +217,9 @@ qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); /* * Global Function Prototypes in qla_isr.c source file. */ -extern irqreturn_t qla2100_intr_handler(int, void *, struct pt_regs *); -extern irqreturn_t qla2300_intr_handler(int, void *, struct pt_regs *); -extern irqreturn_t qla24xx_intr_handler(int, void *, struct pt_regs *); +extern irqreturn_t qla2100_intr_handler(int, void *); +extern irqreturn_t qla2300_intr_handler(int, void *); +extern irqreturn_t qla24xx_intr_handler(int, void *); extern void qla2x00_process_response_queue(struct scsi_qla_host *); extern void qla24xx_process_response_queue(struct scsi_qla_host *); diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 45007ee58067..d3023338628f 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -104,7 +104,7 @@ static __inline__ void qla2x00_poll(scsi_qla_host_t *); static inline void qla2x00_poll(scsi_qla_host_t *ha) { - ha->isp_ops.intr_handler(0, ha, NULL); + ha->isp_ops.intr_handler(0, ha); } static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 5fa933cda992..626c7178a434 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -20,14 +20,13 @@ static void qla24xx_ms_entry(scsi_qla_host_t *, struct ct_entry_24xx *); * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. * @irq: * @dev_id: SCSI driver HA context - * @regs: * * Called by system whenever the host adapter generates an interrupt. * * Returns handled flag. */ irqreturn_t -qla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +qla2100_intr_handler(int irq, void *dev_id) { scsi_qla_host_t *ha; struct device_reg_2xxx __iomem *reg; @@ -100,14 +99,13 @@ qla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs) * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. * @irq: * @dev_id: SCSI driver HA context - * @regs: * * Called by system whenever the host adapter generates an interrupt. * * Returns handled flag. */ irqreturn_t -qla2300_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +qla2300_intr_handler(int irq, void *dev_id) { scsi_qla_host_t *ha; struct device_reg_2xxx __iomem *reg; @@ -1338,14 +1336,13 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha) * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. * @irq: * @dev_id: SCSI driver HA context - * @regs: * * Called by system whenever the host adapter generates an interrupt. * * Returns handled flag. */ irqreturn_t -qla24xx_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +qla24xx_intr_handler(int irq, void *dev_id) { scsi_qla_host_t *ha; struct device_reg_24xx __iomem *reg; diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 418fb7a13a65..1de08002c43f 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -13,7 +13,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb); int qla4xxx_initialize_adapter(struct scsi_qla_host * ha, uint8_t renew_ddb_list); int qla4xxx_soft_reset(struct scsi_qla_host *ha); -irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id); void qla4xxx_free_ddb_list(struct scsi_qla_host * ha); void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen); diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index b584317608d1..1e283321a59d 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -610,9 +610,8 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, * qla4xxx_intr_handler - hardware interrupt handler. * @irq: Unused * @dev_id: Pointer to host adapter structure - * @regs: Unused **/ -irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) { struct scsi_qla_host *ha; uint32_t intr_status; diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c index 52fb2ec3da70..1a7de3bd796f 100644 --- a/drivers/scsi/qlogicfas408.c +++ b/drivers/scsi/qlogicfas408.c @@ -405,7 +405,7 @@ static unsigned int ql_pcmd(Scsi_Cmnd * cmd) * Interrupt handler */ -static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) +static void ql_ihandl(int irq, void *dev_id) { Scsi_Cmnd *icmd; struct Scsi_Host *host = (struct Scsi_Host *)dev_id; @@ -432,13 +432,13 @@ static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) (icmd->scsi_done) (icmd); } -irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id) { unsigned long flags; struct Scsi_Host *host = dev_id; spin_lock_irqsave(host->host_lock, flags); - ql_ihandl(irq, dev_id, regs); + ql_ihandl(irq, dev_id); spin_unlock_irqrestore(host->host_lock, flags); return IRQ_HANDLED; } diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h index 4b3df2003660..8fd5555c75b1 100644 --- a/drivers/scsi/qlogicfas408.h +++ b/drivers/scsi/qlogicfas408.h @@ -102,7 +102,7 @@ struct qlogicfas408_priv { #define get_priv_by_cmd(x) (struct qlogicfas408_priv *)&((x)->device->host->hostdata[0]) #define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0]) -irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id); int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); int qlogicfas408_biosparam(struct scsi_device * disk, struct block_device *dev, diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 5b2f0741a55b..ed58bb489889 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -649,7 +649,7 @@ static int qlogicpti_verify_tmon(struct qlogicpti *qpti) return 0; } -static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t qpti_intr(int irq, void *dev_id); static void __init qpti_chain_add(struct qlogicpti *qpti) { @@ -1297,7 +1297,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) return done_queue; } -static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t qpti_intr(int irq, void *dev_id) { struct qlogicpti *qpti = dev_id; unsigned long flags; diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 4e6666ceae26..8ff1f2866f7b 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -320,8 +320,8 @@ static Signature __initdata signatures[] = { */ static int hostno = -1; -static void seagate_reconnect_intr (int, void *, struct pt_regs *); -static irqreturn_t do_seagate_reconnect_intr (int, void *, struct pt_regs *); +static void seagate_reconnect_intr (int, void *); +static irqreturn_t do_seagate_reconnect_intr (int, void *); static int seagate_st0x_bus_reset(struct scsi_cmnd *); #ifdef FAST @@ -619,19 +619,18 @@ static int should_reconnect = 0; * asserting SEL. */ -static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id) { unsigned long flags; struct Scsi_Host *dev = dev_id; spin_lock_irqsave (dev->host_lock, flags); - seagate_reconnect_intr (irq, dev_id, regs); + seagate_reconnect_intr (irq, dev_id); spin_unlock_irqrestore (dev->host_lock, flags); return IRQ_HANDLED; } -static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs) +static void seagate_reconnect_intr (int irq, void *dev_id) { int temp; struct scsi_cmnd *SCtmp; diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index 4f1db6f2aae8..e81f97a35bc8 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -84,7 +84,7 @@ static inline unsigned long read_wd33c93_count(const wd33c93_regs regs) return value; } -static irqreturn_t sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sgiwd93_intr(int irq, void *dev_id) { struct Scsi_Host * host = (struct Scsi_Host *) dev_id; unsigned long flags; diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index a54e6c1026b7..185c270bb043 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -871,7 +871,7 @@ update_status: readl(base + IMR1); /* flush */ } -static irqreturn_t stex_intr(int irq, void *__hba, struct pt_regs *regs) +static irqreturn_t stex_intr(int irq, void *__hba) { struct st_hba *hba = __hba; void __iomem *base = hba->mmio_base; diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index 7f9bcef6adfa..5ec5af8e3379 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -1252,7 +1252,7 @@ static void NCR5380_dma_complete( struct Scsi_Host *instance ) * */ -static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t NCR5380_intr (int irq, void *dev_id) { struct Scsi_Host *instance = first_instance; int done = 1, handled = 0; diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 44a99aeb8180..e625b4c5833a 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -102,7 +102,7 @@ static void NCR5380_print(struct Scsi_Host *instance); #define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI ); -static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp); +static irqreturn_t scsi_sun3_intr(int irq, void *dummy); static inline unsigned char sun3scsi_read(int reg); static inline void sun3scsi_write(int reg, int value); @@ -371,7 +371,7 @@ const char * sun3scsi_info (struct Scsi_Host *spnt) { // safe bits for the CSR #define CSR_GOOD 0x060f -static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t scsi_sun3_intr(int irq, void *dummy) { unsigned short csr = dregs->csr; int handled = 0; @@ -388,7 +388,7 @@ static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp) } if(csr & (CSR_SDB_INT | CSR_DMA_INT)) { - NCR5380_intr(irq, dummy, fp); + NCR5380_intr(irq, dummy); handled = 1; } diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index f5742b84b27a..e8faab16567b 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -67,7 +67,7 @@ extern int sun3_map_test(unsigned long, char *); #define ENABLE_IRQ() -static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp); +static irqreturn_t scsi_sun3_intr(int irq, void *dummy); static inline unsigned char sun3scsi_read(int reg); static inline void sun3scsi_write(int reg, int value); @@ -340,7 +340,7 @@ static const char * sun3scsi_info (struct Scsi_Host *spnt) { // safe bits for the CSR #define CSR_GOOD 0x060f -static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t scsi_sun3_intr(int irq, void *dummy) { unsigned short csr = dregs->csr; int handled = 0; @@ -371,7 +371,7 @@ static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp) } if(csr & (CSR_SDB_INT | CSR_DMA_INT)) { - NCR5380_intr(irq, dummy, fp); + NCR5380_intr(irq, dummy); handled = 1; } diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index 8640253d6215..32c883f1efa1 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -326,8 +326,7 @@ static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, return orig_len - len; } -static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id) { struct Scsi_Host *dev = dev_id; int base = 0; diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 739d3ef46a40..4d78c7e87cca 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -652,7 +652,7 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd, /* * Linux entry point of the interrupt handler. */ -static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t sym53c8xx_intr(int irq, void *dev_id) { unsigned long flags; struct sym_hcb *np = (struct sym_hcb *)dev_id; diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 028d5f641cc6..0f0ac925d319 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -700,7 +700,7 @@ dc390_InvalidCmd(struct dc390_acb* pACB) static irqreturn_t __inline__ -DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs) +DC390_Interrupt(int irq, void *dev_id) { struct dc390_acb *pACB = (struct dc390_acb*)dev_id; struct dc390_dcb *pDCB; @@ -811,12 +811,12 @@ DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t do_DC390_Interrupt( int irq, void *dev_id) { irqreturn_t ret; DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq)); /* Locking is done in DC390_Interrupt */ - ret = DC390_Interrupt(irq, dev_id, regs); + ret = DC390_Interrupt(irq, dev_id); DEBUG1(printk (".. IRQ returned\n")); return ret; } diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 57449611e714..3de08a15de40 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -634,7 +634,7 @@ static unsigned long io_port[] = { #define H2DEV(x) cpu_to_le32(x) #define DEV2H(x) le32_to_cpu(x) -static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *); +static irqreturn_t do_interrupt_handler(int, void *); static void flush_dev(struct scsi_device *, unsigned long, unsigned int, unsigned int); static int do_trace = FALSE; static int setup_done = FALSE; @@ -1932,8 +1932,7 @@ none: return IRQ_NONE; } -static irqreturn_t do_interrupt_handler(int irq, void *shap, - struct pt_regs *regs) { +static irqreturn_t do_interrupt_handler(int irq, void *shap) { unsigned int j; unsigned long spin_flags; irqreturn_t ret; diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index 0372aa9fa190..107f0fc34949 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -287,8 +287,8 @@ static const unsigned short ultrastor_ports_14f[] = { }; #endif -static void ultrastor_interrupt(int, void *, struct pt_regs *); -static irqreturn_t do_ultrastor_interrupt(int, void *, struct pt_regs *); +static void ultrastor_interrupt(int, void *); +static irqreturn_t do_ultrastor_interrupt(int, void *); static inline void build_sg_list(struct mscp *, struct scsi_cmnd *SCpnt); @@ -893,7 +893,7 @@ static int ultrastor_abort(struct scsi_cmnd *SCpnt) spin_lock_irqsave(host->host_lock, flags); /* FIXME: Ewww... need to think about passing host around properly */ - ultrastor_interrupt(0, NULL, NULL); + ultrastor_interrupt(0, NULL); spin_unlock_irqrestore(host->host_lock, flags); return SUCCESS; } @@ -1039,7 +1039,7 @@ int ultrastor_biosparam(struct scsi_device *sdev, struct block_device *bdev, return 0; } -static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void ultrastor_interrupt(int irq, void *dev_id) { unsigned int status; #if ULTRASTOR_MAX_CMDS > 1 @@ -1171,14 +1171,13 @@ static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs) #endif } -static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id) { unsigned long flags; struct Scsi_Host *dev = dev_id; spin_lock_irqsave(dev->host_lock, flags); - ultrastor_interrupt(irq, dev_id, regs); + ultrastor_interrupt(irq, dev_id); spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED; } diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index a0b61af48f1c..331e1cf159b0 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -998,7 +998,7 @@ static int make_code(unsigned hosterr, unsigned scsierr) #define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK) -static irqreturn_t wd7000_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t wd7000_intr(int irq, void *dev_id) { Adapter *host = (Adapter *) dev_id; int flag, icmb, errstatus, icmb_status; diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index 76d83ade9857..6a1a568ca649 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -85,7 +85,7 @@ static void serial21285_enable_ms(struct uart_port *port) { } -static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; struct tty_struct *tty = port->info->tty; @@ -123,7 +123,7 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r return IRQ_HANDLED; } -static irqreturn_t serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t serial21285_tx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; struct circ_buf *xmit = &port->info->xmit; diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index bac853c5abb5..9b8b585513ec 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -275,8 +275,7 @@ static void status_handle(struct m68k_serial *info, unsigned short status) return; } -static void receive_chars(struct m68k_serial *info, struct pt_regs *regs, - unsigned short rx) +static void receive_chars(struct m68k_serial *info, unsigned short rx) { struct tty_struct *tty = info->tty; m68328_uart *uart = &uart_addr[info->line]; @@ -377,7 +376,7 @@ clear_and_return: /* * This is the serial driver's generic interrupt routine */ -irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) +irqreturn_t rs_interrupt(int irq, void *dev_id) { struct m68k_serial * info; m68328_uart *uart; @@ -394,10 +393,10 @@ irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) #ifdef USE_INTS tx = uart->utx.w; - if (rx & URX_DATA_READY) receive_chars(info, regs, rx); + if (rx & URX_DATA_READY) receive_chars(info, rx); if (tx & UTX_TX_AVAIL) transmit_chars(info); #else - receive_chars(info, regs, rx); + receive_chars(info, rx); #endif return IRQ_HANDLED; } diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index 1b299e8c57cd..4e56ec803861 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -612,7 +612,7 @@ static _INLINE_ void check_modem_status(struct async_struct *info) * This is the serial driver's interrupt routine for a single port */ /* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */ -static void rs_360_interrupt(int vec, void *dev_id, struct pt_regs *fp) +static void rs_360_interrupt(int vec, void *dev_id) { u_char events; int idx; diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index cc2a205d4230..e34bd03cfce7 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1175,7 +1175,7 @@ static void serial8250_enable_ms(struct uart_port *port) } static void -receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) +receive_chars(struct uart_8250_port *up, int *status) { struct tty_struct *tty = up->port.info->tty; unsigned char ch, lsr = *status; @@ -1233,7 +1233,7 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) else if (lsr & UART_LSR_FE) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch, regs)) + if (uart_handle_sysrq_char(&up->port, ch)) goto ignore_char; uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); @@ -1309,7 +1309,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) * This handles the interrupt from one port. */ static inline void -serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) +serial8250_handle_port(struct uart_8250_port *up) { unsigned int status; @@ -1320,7 +1320,7 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) DEBUG_INTR("status = %x...", status); if (status & UART_LSR_DR) - receive_chars(up, &status, regs); + receive_chars(up, &status); check_modem_status(up); if (status & UART_LSR_THRE) transmit_chars(up); @@ -1342,7 +1342,7 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) * This means we need to loop through all ports. checking that they * don't have an interrupt pending. */ -static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t serial8250_interrupt(int irq, void *dev_id) { struct irq_info *i = dev_id; struct list_head *l, *end = NULL; @@ -1361,7 +1361,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *r iir = serial_in(up, UART_IIR); if (!(iir & UART_IIR_NO_INT)) { - serial8250_handle_port(up, regs); + serial8250_handle_port(up); handled = 1; @@ -1461,7 +1461,7 @@ static void serial8250_timeout(unsigned long data) iir = serial_in(up, UART_IIR); if (!(iir & UART_IIR_NO_INT)) - serial8250_handle_port(up, NULL); + serial8250_handle_port(up); timeout = up->port.timeout; timeout = timeout > 6 ? (timeout / 2 - 2) : 1; diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 7311d8487c96..4213fabc62bf 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -111,12 +111,7 @@ static void pl010_enable_ms(struct uart_port *port) writel(cr, port->membase + UART010_CR); } -static void -#ifdef SUPPORT_SYSRQ -pl010_rx_chars(struct uart_port *port, struct pt_regs *regs) -#else -pl010_rx_chars(struct uart_port *port) -#endif +static void pl010_rx_chars(struct uart_port *port) { struct tty_struct *tty = port->info->tty; unsigned int status, ch, flag, rsr, max_count = 256; @@ -156,7 +151,7 @@ pl010_rx_chars(struct uart_port *port) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(port, ch, regs)) + if (uart_handle_sysrq_char(port, ch)) goto ignore_char; uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag); @@ -227,7 +222,7 @@ static void pl010_modem_status(struct uart_port *port) wake_up_interruptible(&uap->port.info->delta_msr_wait); } -static irqreturn_t pl010_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pl010_int(int irq, void *dev_id) { struct uart_port *port = dev_id; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; @@ -239,11 +234,7 @@ static irqreturn_t pl010_int(int irq, void *dev_id, struct pt_regs *regs) if (status) { do { if (status & (UART010_IIR_RTIS | UART010_IIR_RIS)) -#ifdef SUPPORT_SYSRQ - pl010_rx_chars(port, regs); -#else pl010_rx_chars(port); -#endif if (status & UART010_IIR_MIS) pl010_modem_status(port); if (status & UART010_IIR_TIS) diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index a8d7124e84a1..d503625730df 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -107,12 +107,7 @@ static void pl011_enable_ms(struct uart_port *port) writew(uap->im, uap->port.membase + UART011_IMSC); } -static void -#ifdef SUPPORT_SYSRQ -pl011_rx_chars(struct uart_amba_port *uap, struct pt_regs *regs) -#else -pl011_rx_chars(struct uart_amba_port *uap) -#endif +static void pl011_rx_chars(struct uart_amba_port *uap) { struct tty_struct *tty = uap->port.info->tty; unsigned int status, ch, flag, max_count = 256; @@ -150,7 +145,7 @@ pl011_rx_chars(struct uart_amba_port *uap) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&uap->port, ch & 255, regs)) + if (uart_handle_sysrq_char(&uap->port, ch & 255)) goto ignore_char; uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); @@ -218,7 +213,7 @@ static void pl011_modem_status(struct uart_amba_port *uap) wake_up_interruptible(&uap->port.info->delta_msr_wait); } -static irqreturn_t pl011_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pl011_int(int irq, void *dev_id) { struct uart_amba_port *uap = dev_id; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; @@ -234,11 +229,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id, struct pt_regs *regs) uap->port.membase + UART011_ICR); if (status & (UART011_RTIS|UART011_RXIS)) -#ifdef SUPPORT_SYSRQ - pl011_rx_chars(uap, regs); -#else pl011_rx_chars(uap); -#endif if (status & (UART011_DSRMIS|UART011_DCDMIS| UART011_CTSMIS|UART011_RIMIS)) pl011_modem_status(uap); diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 955c46da5800..391a1f4167a4 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -249,7 +249,7 @@ static void atmel_break_ctl(struct uart_port *port, int break_state) /* * Characters received (called from interrupt handler) */ -static void atmel_rx_chars(struct uart_port *port, struct pt_regs *regs) +static void atmel_rx_chars(struct uart_port *port) { struct tty_struct *tty = port->info->tty; unsigned int status, ch, flg; @@ -291,7 +291,7 @@ static void atmel_rx_chars(struct uart_port *port, struct pt_regs *regs) flg = TTY_FRAME; } - if (uart_handle_sysrq_char(port, ch, regs)) + if (uart_handle_sysrq_char(port, ch)) goto ignore_char; uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg); @@ -339,7 +339,7 @@ static void atmel_tx_chars(struct uart_port *port) /* * Interrupt handler */ -static irqreturn_t atmel_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t atmel_interrupt(int irq, void *dev_id) { struct uart_port *port = dev_id; struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; @@ -350,7 +350,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id, struct pt_regs *regs) while (pending) { /* Interrupt receive */ if (pending & ATMEL_US_RXRDY) - atmel_rx_chars(port, regs); + atmel_rx_chars(port); // TODO: All reads to CSR will clear these interrupts! if (pending & ATMEL_US_RIIC) port->icount.rng++; diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index f27d852ce50d..598012714882 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -93,7 +93,7 @@ static void clps711xuart_enable_ms(struct uart_port *port) { } -static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id) { struct uart_port *port = dev_id; struct tty_struct *tty = port->info->tty; @@ -131,7 +131,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re #endif } - if (uart_handle_sysrq_char(port, ch, regs)) + if (uart_handle_sysrq_char(port, ch)) goto ignore_char; /* @@ -147,7 +147,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re return IRQ_HANDLED; } -static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id) { struct uart_port *port = dev_id; struct circ_buf *xmit = &port->info->xmit; diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index a0d6136deb9b..0abb544ae63d 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -248,7 +248,7 @@ static void cpm_uart_break_ctl(struct uart_port *port, int break_state) /* * Transmit characters, refill buffer descriptor, if possible */ -static void cpm_uart_int_tx(struct uart_port *port, struct pt_regs *regs) +static void cpm_uart_int_tx(struct uart_port *port) { pr_debug("CPM uart[%d]:TX INT\n", port->line); @@ -258,7 +258,7 @@ static void cpm_uart_int_tx(struct uart_port *port, struct pt_regs *regs) /* * Receive characters */ -static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) +static void cpm_uart_int_rx(struct uart_port *port) { int i; unsigned char ch, *cp; @@ -304,7 +304,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) if (status & (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) goto handle_error; - if (uart_handle_sysrq_char(port, ch, regs)) + if (uart_handle_sysrq_char(port, ch)) continue; error_return: @@ -373,7 +373,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) /* * Asynchron mode interrupt handler */ -static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs) +static irqreturn_t cpm_uart_int(int irq, void *data) { u8 events; struct uart_port *port = (struct uart_port *)data; @@ -389,18 +389,18 @@ static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs) if (events & SMCM_BRKE) uart_handle_break(port); if (events & SMCM_RX) - cpm_uart_int_rx(port, regs); + cpm_uart_int_rx(port); if (events & SMCM_TX) - cpm_uart_int_tx(port, regs); + cpm_uart_int_tx(port); } else { events = sccp->scc_scce; sccp->scc_scce = events; if (events & UART_SCCM_BRKE) uart_handle_break(port); if (events & UART_SCCM_RX) - cpm_uart_int_rx(port, regs); + cpm_uart_int_rx(port); if (events & UART_SCCM_TX) - cpm_uart_int_tx(port, regs); + cpm_uart_int_tx(port); } return (events) ? IRQ_HANDLED : IRQ_NONE; } diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 9851d9eff022..7a24e53546c7 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -2346,7 +2346,7 @@ start_receive(struct e100_serial *info) */ static irqreturn_t -tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) +tr_interrupt(int irq, void *dev_id) { struct e100_serial *info; unsigned long ireg; @@ -2395,7 +2395,7 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) /* dma input channel interrupt handler */ static irqreturn_t -rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) +rec_interrupt(int irq, void *dev_id) { struct e100_serial *info; unsigned long ireg; @@ -3054,7 +3054,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info) * ser_int duration: just sending: 8-15 us normally, up to 73 us */ static irqreturn_t -ser_interrupt(int irq, void *dev_id, struct pt_regs *regs) +ser_interrupt(int irq, void *dev_id) { static volatile int tx_started = 0; struct e100_serial *info; diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index 8a98aae80e22..53662b33b841 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -339,7 +339,7 @@ static inline void check_modem_status(struct dz_port *dport) * It deals with the multiple ports. * ------------------------------------------------------------ */ -static irqreturn_t dz_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t dz_interrupt(int irq, void *dev) { struct dz_port *dport; unsigned short status; diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index a3c00a252149..8aa0f641866b 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -844,8 +844,7 @@ static void process_interrupt(u16 port_int_reg, spin_unlock(&icom_port->uart_port.lock); } -static irqreturn_t icom_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t icom_interrupt(int irq, void *dev_id) { void __iomem * int_reg; u32 adapter_interrupts; diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 4a142d6b8f38..ee5c782597dd 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -182,7 +182,7 @@ static void imx_start_tx(struct uart_port *port) imx_transmit_buffer(sport); } -static irqreturn_t imx_rtsint(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t imx_rtsint(int irq, void *dev_id) { struct imx_port *sport = (struct imx_port *)dev_id; unsigned int val = USR1((u32)sport->port.membase)&USR1_RTSS; @@ -198,7 +198,7 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t imx_txint(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t imx_txint(int irq, void *dev_id) { struct imx_port *sport = (struct imx_port *)dev_id; struct circ_buf *xmit = &sport->port.info->xmit; @@ -227,7 +227,7 @@ out: return IRQ_HANDLED; } -static irqreturn_t imx_rxint(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t imx_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned int rx,flg,ignored = 0; @@ -248,7 +248,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id, struct pt_regs *regs) } if (uart_handle_sysrq_char - (&sport->port, (unsigned char)rx, regs)) + (&sport->port, (unsigned char)rx)) goto ignore_char; if( rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c index 8097cd91f16b..2308d26c8629 100644 --- a/drivers/serial/ioc3_serial.c +++ b/drivers/serial/ioc3_serial.c @@ -1428,13 +1428,12 @@ static int receive_chars(struct uart_port *the_port) * @is : submodule * @idd: driver data * @pending: interrupts to handle - * @regs: pt_regs */ static int inline ioc3uart_intr_one(struct ioc3_submodule *is, struct ioc3_driver_data *idd, - unsigned int pending, struct pt_regs *regs) + unsigned int pending) { int port_num = GET_PORT_FROM_SIO_IR(pending); struct port_hooks *hooks; @@ -1628,13 +1627,12 @@ ioc3uart_intr_one(struct ioc3_submodule *is, * @is : submodule * @idd: driver data * @pending: interrupts to handle - * @regs: pt_regs * */ static int ioc3uart_intr(struct ioc3_submodule *is, struct ioc3_driver_data *idd, - unsigned int pending, struct pt_regs *regs) + unsigned int pending) { int ret = 0; @@ -1644,9 +1642,9 @@ static int ioc3uart_intr(struct ioc3_submodule *is, */ if (pending & SIO_IR_SA) - ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA, regs); + ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA); if (pending & SIO_IR_SB) - ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB, regs); + ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB); return ret; } diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index 5ec4716c99bf..98ce88d80207 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -987,10 +987,9 @@ intr_connect(struct ioc4_soft *soft, int type, * ioc4_intr - Top level IOC4 interrupt handler. * @irq: irq value * @arg: handler arg - * @regs: registers */ -static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t ioc4_intr(int irq, void *arg) { struct ioc4_soft *soft; uint32_t this_ir, this_mir; diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index dbf13c03a1bb..dca6c1bde8f9 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c @@ -252,8 +252,7 @@ static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up, } static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up, - struct zilog_channel *channel, - struct pt_regs *regs) + struct zilog_channel *channel) { struct tty_struct *tty = up->port.info->tty; /* XXX info==NULL? */ @@ -319,7 +318,7 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up, else if (r1 & CRC_ERR) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch, regs)) + if (uart_handle_sysrq_char(&up->port, ch)) goto next_char; if (up->port.ignore_status_mask == 0xff || @@ -339,8 +338,7 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up, } static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, - struct zilog_channel *channel, - struct pt_regs *regs) + struct zilog_channel *channel) { unsigned char status; @@ -443,7 +441,7 @@ ack_tx_int: ZS_WSYNC(channel); } -static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) { struct uart_ip22zilog_port *up = dev_id; @@ -462,9 +460,9 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *re ZS_WSYNC(channel); if (r3 & CHARxIP) - ip22zilog_receive_chars(up, channel, regs); + ip22zilog_receive_chars(up, channel); if (r3 & CHAEXT) - ip22zilog_status_handle(up, channel, regs); + ip22zilog_status_handle(up, channel); if (r3 & CHATxIP) ip22zilog_transmit_chars(up, channel); } @@ -481,9 +479,9 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *re ZS_WSYNC(channel); if (r3 & CHBRxIP) - ip22zilog_receive_chars(up, channel, regs); + ip22zilog_receive_chars(up, channel); if (r3 & CHBEXT) - ip22zilog_status_handle(up, channel, regs); + ip22zilog_status_handle(up, channel); if (r3 & CHBTxIP) ip22zilog_transmit_chars(up, channel); } diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h index 043f50b1d10c..12c934a1f274 100644 --- a/drivers/serial/jsm/jsm.h +++ b/drivers/serial/jsm/jsm.h @@ -99,7 +99,7 @@ struct jsm_channel; * Per board operations structure * ************************************************************************/ struct board_ops { - irqreturn_t (*intr) (int irq, void *voidbrd, struct pt_regs *regs); + irq_handler_t intr; void (*uart_init) (struct jsm_channel *ch); void (*uart_off) (struct jsm_channel *ch); void (*param) (struct jsm_channel *ch); diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c index a5fc589d6ef5..8fa31e68989a 100644 --- a/drivers/serial/jsm/jsm_neo.c +++ b/drivers/serial/jsm/jsm_neo.c @@ -1114,7 +1114,7 @@ static void neo_param(struct jsm_channel *ch) * * Neo specific interrupt handler. */ -static irqreturn_t neo_intr(int irq, void *voidbrd, struct pt_regs *regs) +static irqreturn_t neo_intr(int irq, void *voidbrd) { struct jsm_board *brd = (struct jsm_board *) voidbrd; struct jsm_channel *ch; diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c index 28c9ce6f0bdc..c85ac1a77608 100644 --- a/drivers/serial/m32r_sio.c +++ b/drivers/serial/m32r_sio.c @@ -323,8 +323,7 @@ static void m32r_sio_enable_ms(struct uart_port *port) serial_out(up, UART_IER, up->ier); } -static void receive_chars(struct uart_sio_port *up, int *status, - struct pt_regs *regs) +static void receive_chars(struct uart_sio_port *up, int *status) { struct tty_struct *tty = up->port.info->tty; unsigned char ch; @@ -378,7 +377,7 @@ static void receive_chars(struct uart_sio_port *up, int *status, else if (*status & UART_LSR_FE) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch, regs)) + if (uart_handle_sysrq_char(&up->port, ch)) goto ignore_char; if ((*status & up->port.ignore_status_mask) == 0) tty_insert_flip_char(tty, ch, flag); @@ -439,12 +438,12 @@ static void transmit_chars(struct uart_sio_port *up) * This handles the interrupt from one port. */ static inline void m32r_sio_handle_port(struct uart_sio_port *up, - unsigned int status, struct pt_regs *regs) + unsigned int status) { DEBUG_INTR("status = %x...", status); if (status & 0x04) - receive_chars(up, &status, regs); + receive_chars(up, &status); if (status & 0x01) transmit_chars(up); } @@ -463,8 +462,7 @@ static inline void m32r_sio_handle_port(struct uart_sio_port *up, * This means we need to loop through all ports. checking that they * don't have an interrupt pending. */ -static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id) { struct irq_info *i = dev_id; struct list_head *l, *end = NULL; @@ -492,7 +490,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id, sts = sio_in(up, SIOSTS); if (sts & 0x5) { spin_lock(&up->port.lock); - m32r_sio_handle_port(up, sts, regs); + m32r_sio_handle_port(up, sts); spin_unlock(&up->port.lock); end = NULL; diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 00d7859c167e..aee1b31f1a1c 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -385,7 +385,7 @@ static inline void transmit_chars(struct mcf_serial *info) /* * This is the serial driver's generic interrupt routine */ -irqreturn_t mcfrs_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t mcfrs_interrupt(int irq, void *dev_id) { struct mcf_serial *info; unsigned char isr; diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index dbad0e31e005..039c2fd6d496 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -85,7 +85,7 @@ static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM]; /* Forward declaration of the interruption handling routine */ -static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id,struct pt_regs *regs); +static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id); /* Simple macro to test if a port is console or not. This one is taken @@ -410,7 +410,7 @@ static struct uart_ops mpc52xx_uart_ops = { /* ======================================================================== */ static inline int -mpc52xx_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs) +mpc52xx_uart_int_rx_chars(struct uart_port *port) { struct tty_struct *tty = port->info->tty; unsigned char ch, flag; @@ -425,7 +425,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs) /* Handle sysreq char */ #ifdef SUPPORT_SYSRQ - if (uart_handle_sysrq_char(port, ch, regs)) { + if (uart_handle_sysrq_char(port, ch)) { port->sysrq = 0; continue; } @@ -510,7 +510,7 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) } static irqreturn_t -mpc52xx_uart_int(int irq, void *dev_id, struct pt_regs *regs) +mpc52xx_uart_int(int irq, void *dev_id) { struct uart_port *port = (struct uart_port *) dev_id; unsigned long pass = ISR_PASS_LIMIT; @@ -539,7 +539,7 @@ mpc52xx_uart_int(int irq, void *dev_id, struct pt_regs *regs) /* Do we need to receive chars ? */ /* For this RX interrupts must be on and some chars waiting */ if ( status & MPC52xx_PSC_IMR_RXRDY ) - keepgoing |= mpc52xx_uart_int_rx_chars(port, regs); + keepgoing |= mpc52xx_uart_int_rx_chars(port); /* Do we need to send chars ? */ /* For this, TX must be ready and TX interrupt enabled */ diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index 704243c9f78a..8eea69f29989 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -992,7 +992,7 @@ mpsc_make_ready(struct mpsc_port_info *pi) */ static inline int -mpsc_rx_intr(struct mpsc_port_info *pi, struct pt_regs *regs) +mpsc_rx_intr(struct mpsc_port_info *pi) { struct mpsc_rx_desc *rxre; struct tty_struct *tty = pi->port.info->tty; @@ -1072,7 +1072,7 @@ mpsc_rx_intr(struct mpsc_port_info *pi, struct pt_regs *regs) flag = TTY_PARITY; } - if (uart_handle_sysrq_char(&pi->port, *bp, regs)) { + if (uart_handle_sysrq_char(&pi->port, *bp)) { bp++; bytes_in--; goto next_frame; @@ -1257,7 +1257,7 @@ mpsc_tx_intr(struct mpsc_port_info *pi) * handling those descriptors, we restart the Rx/Tx engines if they're stopped. */ static irqreturn_t -mpsc_sdma_intr(int irq, void *dev_id, struct pt_regs *regs) +mpsc_sdma_intr(int irq, void *dev_id) { struct mpsc_port_info *pi = dev_id; ulong iflags; @@ -1267,7 +1267,7 @@ mpsc_sdma_intr(int irq, void *dev_id, struct pt_regs *regs) spin_lock_irqsave(&pi->port.lock, iflags); mpsc_sdma_intr_ack(pi); - if (mpsc_rx_intr(pi, regs)) + if (mpsc_rx_intr(pi)) rc = IRQ_HANDLED; if (mpsc_tx_intr(pi)) rc = IRQ_HANDLED; diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c index 7502109d37f0..e92d7e1c22cf 100644 --- a/drivers/serial/netx-serial.c +++ b/drivers/serial/netx-serial.c @@ -200,7 +200,7 @@ static void netx_txint(struct uart_port *port) uart_write_wakeup(port); } -static void netx_rxint(struct uart_port *port, struct pt_regs *regs) +static void netx_rxint(struct uart_port *port) { unsigned char rx, flg, status; struct tty_struct *tty = port->info->tty; @@ -235,7 +235,7 @@ static void netx_rxint(struct uart_port *port, struct pt_regs *regs) flg = TTY_FRAME; } - if (uart_handle_sysrq_char(port, rx, regs)) + if (uart_handle_sysrq_char(port, rx)) continue; uart_insert_char(port, status, SR_OE, rx, flg); @@ -245,7 +245,7 @@ static void netx_rxint(struct uart_port *port, struct pt_regs *regs) return; } -static irqreturn_t netx_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t netx_int(int irq, void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; unsigned long flags; @@ -256,7 +256,7 @@ static irqreturn_t netx_int(int irq, void *dev_id, struct pt_regs *regs) status = readl(port->membase + UART_IIR) & IIR_MASK; while (status) { if (status & IIR_RIS) - netx_rxint(port, regs); + netx_rxint(port); if (status & IIR_TIS) netx_txint(port); if (status & IIR_MIS) { diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index a3b99caf80e6..bf9809ed9c0b 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -204,8 +204,7 @@ static void pmz_maybe_update_regs(struct uart_pmac_port *uap) } } -static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap, - struct pt_regs *regs) +static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) { struct tty_struct *tty = NULL; unsigned char ch, r1, drop, error, flag; @@ -267,7 +266,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap, if (uap->port.sysrq) { int swallow; spin_unlock(&uap->port.lock); - swallow = uart_handle_sysrq_char(&uap->port, ch, regs); + swallow = uart_handle_sysrq_char(&uap->port, ch); spin_lock(&uap->port.lock); if (swallow) goto next_char; @@ -335,7 +334,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap, return tty; } -static void pmz_status_handle(struct uart_pmac_port *uap, struct pt_regs *regs) +static void pmz_status_handle(struct uart_pmac_port *uap) { unsigned char status; @@ -438,7 +437,7 @@ ack_tx_int: } /* Hrm... we register that twice, fixme later.... */ -static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pmz_interrupt(int irq, void *dev_id) { struct uart_pmac_port *uap = dev_id; struct uart_pmac_port *uap_a; @@ -462,9 +461,9 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs) write_zsreg(uap_a, R0, RES_H_IUS); zssync(uap_a); if (r3 & CHAEXT) - pmz_status_handle(uap_a, regs); + pmz_status_handle(uap_a); if (r3 & CHARxIP) - tty = pmz_receive_chars(uap_a, regs); + tty = pmz_receive_chars(uap_a); if (r3 & CHATxIP) pmz_transmit_chars(uap_a); rc = IRQ_HANDLED; @@ -482,9 +481,9 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs) write_zsreg(uap_b, R0, RES_H_IUS); zssync(uap_b); if (r3 & CHBEXT) - pmz_status_handle(uap_b, regs); + pmz_status_handle(uap_b); if (r3 & CHBRxIP) - tty = pmz_receive_chars(uap_b, regs); + tty = pmz_receive_chars(uap_b); if (r3 & CHBTxIP) pmz_transmit_chars(uap_b); rc = IRQ_HANDLED; diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index a720953a404e..846089f222d4 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -98,8 +98,7 @@ static void serial_pxa_stop_rx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } -static inline void -receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs) +static inline void receive_chars(struct uart_pxa_port *up, int *status) { struct tty_struct *tty = up->port.info->tty; unsigned int ch, flag; @@ -153,7 +152,7 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch, regs)) + if (uart_handle_sysrq_char(&up->port, ch)) goto ignore_char; uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); @@ -231,8 +230,7 @@ static inline void check_modem_status(struct uart_pxa_port *up) /* * This handles the interrupt from one port. */ -static inline irqreturn_t -serial_pxa_irq(int irq, void *dev_id, struct pt_regs *regs) +static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) { struct uart_pxa_port *up = (struct uart_pxa_port *)dev_id; unsigned int iir, lsr; @@ -242,7 +240,7 @@ serial_pxa_irq(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; lsr = serial_in(up, UART_LSR); if (lsr & UART_LSR_DR) - receive_chars(up, &lsr, regs); + receive_chars(up, &lsr); check_modem_status(up); if (lsr & UART_LSR_THRE) transmit_chars(up); diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 95738a19cde7..8dfc2dd058ca 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -310,7 +310,7 @@ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport, #define S3C2410_UERSTAT_PARITY (0x1000) static irqreturn_t -s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs) +s3c24xx_serial_rx_chars(int irq, void *dev_id) { struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; @@ -379,7 +379,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(port, ch, regs)) + if (uart_handle_sysrq_char(port, ch)) goto ignore_char; uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag); @@ -393,7 +393,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id, struct pt_regs *regs) +static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) { struct s3c24xx_uart_port *ourport = id; struct uart_port *port = &ourport->port; diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index db3486d33870..d4065266b6fc 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -190,7 +190,7 @@ static void sa1100_enable_ms(struct uart_port *port) } static void -sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs) +sa1100_rx_chars(struct sa1100_port *sport) { struct tty_struct *tty = sport->port.info->tty; unsigned int status, ch, flg; @@ -228,7 +228,7 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs) #endif } - if (uart_handle_sysrq_char(&sport->port, ch, regs)) + if (uart_handle_sysrq_char(&sport->port, ch)) goto ignore_char; uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg); @@ -281,7 +281,7 @@ static void sa1100_tx_chars(struct sa1100_port *sport) sa1100_stop_tx(&sport->port); } -static irqreturn_t sa1100_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sa1100_int(int irq, void *dev_id) { struct sa1100_port *sport = dev_id; unsigned int status, pass_counter = 0; @@ -294,7 +294,7 @@ static irqreturn_t sa1100_int(int irq, void *dev_id, struct pt_regs *regs) /* Clear the receiver idle bit, if set */ if (status & UTSR0_RID) UART_PUT_UTSR0(sport, UTSR0_RID); - sa1100_rx_chars(sport, regs); + sa1100_rx_chars(sport); } /* Clear the relevant break bits */ diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index 23ddedbaec08..5e1ac356bbb0 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c @@ -135,12 +135,7 @@ static void lh7a40xuart_enable_ms (struct uart_port* port) BIT_SET (port, UART_R_INTEN, ModemInt); } -static void -#ifdef SUPPORT_SYSRQ -lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs) -#else -lh7a40xuart_rx_chars (struct uart_port* port) -#endif +static void lh7a40xuart_rx_chars (struct uart_port* port) { struct tty_struct* tty = port->info->tty; int cbRxMax = 256; /* (Gross) limit on receive */ @@ -177,7 +172,7 @@ lh7a40xuart_rx_chars (struct uart_port* port) flag = TTY_FRAME; } - if (uart_handle_sysrq_char (port, (unsigned char) data, regs)) + if (uart_handle_sysrq_char (port, (unsigned char) data)) continue; uart_insert_char(port, data, RxOverrunError, data, flag); @@ -248,8 +243,7 @@ static void lh7a40xuart_modem_status (struct uart_port* port) wake_up_interruptible (&port->info->delta_msr_wait); } -static irqreturn_t lh7a40xuart_int (int irq, void* dev_id, - struct pt_regs* regs) +static irqreturn_t lh7a40xuart_int (int irq, void* dev_id) { struct uart_port* port = dev_id; unsigned int cLoopLimit = ISR_LOOP_LIMIT; @@ -258,11 +252,7 @@ static irqreturn_t lh7a40xuart_int (int irq, void* dev_id, do { if (isr & (RxInt | RxTimeoutInt)) -#ifdef SUPPORT_SYSRQ - lh7a40xuart_rx_chars(port, regs); -#else lh7a40xuart_rx_chars(port); -#endif if (isr & ModemInt) lh7a40xuart_modem_status (port); if (isr & TxInt) diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index ebd8d2bb17fd..2a48289ac722 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -283,7 +283,7 @@ static void serial_txx9_enable_ms(struct uart_port *port) } static inline void -receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *regs) +receive_chars(struct uart_txx9_port *up, unsigned int *status) { struct tty_struct *tty = up->port.info->tty; unsigned char ch; @@ -344,7 +344,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r else if (disr & TXX9_SIDISR_UFER) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch, regs)) + if (uart_handle_sysrq_char(&up->port, ch)) goto ignore_char; uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag); @@ -391,7 +391,7 @@ static inline void transmit_chars(struct uart_txx9_port *up) serial_txx9_stop_tx(&up->port); } -static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) { int pass_counter = 0; struct uart_txx9_port *up = dev_id; @@ -409,7 +409,7 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id, struct pt_regs * } if (status & TXX9_SIDISR_RDIS) - receive_chars(up, &status, regs); + receive_chars(up, &status); if (status & TXX9_SIDISR_TDIS) transmit_chars(up); /* Clear TX/RX Int. Status */ diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 5c025d1190c1..266aa325569e 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -446,8 +446,7 @@ static void sci_transmit_chars(struct uart_port *port) /* On SH3, SCIF may read end-of-break as a space->mark char */ #define STEPFN(c) ({int __c=(c); (((__c-1)|(__c)) == -1); }) -static inline void sci_receive_chars(struct uart_port *port, - struct pt_regs *regs) +static inline void sci_receive_chars(struct uart_port *port) { struct sci_port *sci_port = (struct sci_port *)port; struct tty_struct *tty = port->info->tty; @@ -476,7 +475,7 @@ static inline void sci_receive_chars(struct uart_port *port, if (port->type == PORT_SCI) { char c = sci_in(port, SCxRDR); - if (uart_handle_sysrq_char(port, c, regs) || sci_port->break_flag) + if (uart_handle_sysrq_char(port, c) || sci_port->break_flag) count = 0; else { tty_insert_flip_char(tty, c, TTY_NORMAL); @@ -504,7 +503,7 @@ static inline void sci_receive_chars(struct uart_port *port, } } #endif /* CONFIG_CPU_SH3 */ - if (uart_handle_sysrq_char(port, c, regs)) { + if (uart_handle_sysrq_char(port, c)) { count--; i--; continue; } @@ -652,18 +651,18 @@ static inline int sci_handle_breaks(struct uart_port *port) return copied; } -static irqreturn_t sci_rx_interrupt(int irq, void *port, struct pt_regs *regs) +static irqreturn_t sci_rx_interrupt(int irq, void *port) { /* I think sci_receive_chars has to be called irrespective * of whether the I_IXOFF is set, otherwise, how is the interrupt * to be disabled? */ - sci_receive_chars(port, regs); + sci_receive_chars(port); return IRQ_HANDLED; } -static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sci_tx_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; @@ -674,7 +673,7 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sci_er_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; @@ -696,18 +695,18 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) pr_debug("scif: overrun error\n"); } #endif - sci_rx_interrupt(irq, ptr, regs); + sci_rx_interrupt(irq, ptr); } sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ - sci_tx_interrupt(irq, ptr, regs); + sci_tx_interrupt(irq, ptr); return IRQ_HANDLED; } -static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sci_br_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; @@ -724,7 +723,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) { unsigned short ssr_status, scr_status; struct uart_port *port = ptr; @@ -734,16 +733,16 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs) /* Tx Interrupt */ if ((ssr_status & 0x0020) && (scr_status & 0x0080)) - sci_tx_interrupt(irq, ptr, regs); + sci_tx_interrupt(irq, ptr); /* Rx Interrupt */ if ((ssr_status & 0x0002) && (scr_status & 0x0040)) - sci_rx_interrupt(irq, ptr, regs); + sci_rx_interrupt(irq, ptr); /* Error Interrupt */ if ((ssr_status & 0x0080) && (scr_status & 0x0400)) - sci_er_interrupt(irq, ptr, regs); + sci_er_interrupt(irq, ptr); /* Break Interrupt */ if ((ssr_status & 0x0010) && (scr_status & 0x0200)) - sci_br_interrupt(irq, ptr, regs); + sci_br_interrupt(irq, ptr); return IRQ_HANDLED; } @@ -795,7 +794,7 @@ static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; static int sci_request_irq(struct sci_port *port) { int i; - irqreturn_t (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = { + irqreturn_t (*handlers[4])(int irq, void *ptr) = { sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, sci_br_interrupt, }; diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index 2f148e5b9255..709f93a6c18c 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -447,7 +447,6 @@ static int sn_debug_printf(const char *fmt, ...) /** * sn_receive_chars - Grab characters, pass them to tty layer * @port: Port to operate on - * @regs: Saved registers (needed by uart_handle_sysrq_char) * @flags: irq flags * * Note: If we're not registered with the serial core infrastructure yet, @@ -455,8 +454,7 @@ static int sn_debug_printf(const char *fmt, ...) * */ static void -sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs, - unsigned long flags) +sn_receive_chars(struct sn_cons_port *port, unsigned long flags) { int ch; struct tty_struct *tty; @@ -494,7 +492,7 @@ sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs, sysrq_requested = 0; if (ch && time_before(jiffies, sysrq_timeout)) { spin_unlock_irqrestore(&port->sc_port.lock, flags); - handle_sysrq(ch, regs, NULL); + handle_sysrq(ch, NULL); spin_lock_irqsave(&port->sc_port.lock, flags); /* ignore actual sysrq command char */ continue; @@ -615,10 +613,9 @@ static void sn_transmit_chars(struct sn_cons_port *port, int raw) * sn_sal_interrupt - Handle console interrupts * @irq: irq #, useful for debug statements * @dev_id: our pointer to our port (sn_cons_port which contains the uart port) - * @regs: Saved registers, used by sn_receive_chars for uart_handle_sysrq_char * */ -static irqreturn_t sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sn_sal_interrupt(int irq, void *dev_id) { struct sn_cons_port *port = (struct sn_cons_port *)dev_id; unsigned long flags; @@ -629,7 +626,7 @@ static irqreturn_t sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_lock_irqsave(&port->sc_port.lock, flags); if (status & SAL_CONSOLE_INTR_RECV) { - sn_receive_chars(port, regs, flags); + sn_receive_chars(port, flags); } if (status & SAL_CONSOLE_INTR_XMIT) { sn_transmit_chars(port, TRANSMIT_BUFFERED); diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index f851f0f44f9b..03941d27d15d 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -73,7 +73,7 @@ static inline long hypervisor_con_putchar(long ch) static int hung_up = 0; -static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs *regs) +static struct tty_struct *receive_chars(struct uart_port *port) { struct tty_struct *tty = NULL; int saw_console_brk = 0; @@ -106,7 +106,7 @@ static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs * } if (tty == NULL) { - uart_handle_sysrq_char(port, c, regs); + uart_handle_sysrq_char(port, c); continue; } @@ -119,7 +119,7 @@ static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs * flag = TTY_BREAK; } - if (uart_handle_sysrq_char(port, c, regs)) + if (uart_handle_sysrq_char(port, c)) continue; if ((port->ignore_status_mask & IGNORE_ALL) || @@ -161,14 +161,14 @@ static void transmit_chars(struct uart_port *port) uart_write_wakeup(port); } -static irqreturn_t sunhv_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sunhv_interrupt(int irq, void *dev_id) { struct uart_port *port = dev_id; struct tty_struct *tty; unsigned long flags; spin_lock_irqsave(&port->lock, flags); - tty = receive_chars(port, regs); + tty = receive_chars(port); transmit_chars(port); spin_unlock_irqrestore(&port->lock, flags); diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index cfe20f730436..08a7cd6a3a0c 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -108,8 +108,7 @@ static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up) static struct tty_struct * receive_chars(struct uart_sunsab_port *up, - union sab82532_irq_status *stat, - struct pt_regs *regs) + union sab82532_irq_status *stat) { struct tty_struct *tty = NULL; unsigned char buf[32]; @@ -161,7 +160,7 @@ receive_chars(struct uart_sunsab_port *up, unsigned char ch = buf[i], flag; if (tty == NULL) { - uart_handle_sysrq_char(&up->port, ch, regs); + uart_handle_sysrq_char(&up->port, ch); continue; } @@ -208,7 +207,7 @@ receive_chars(struct uart_sunsab_port *up, flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch, regs)) + if (uart_handle_sysrq_char(&up->port, ch)) continue; if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 && @@ -301,7 +300,7 @@ static void check_status(struct uart_sunsab_port *up, wake_up_interruptible(&up->port.info->delta_msr_wait); } -static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sunsab_interrupt(int irq, void *dev_id) { struct uart_sunsab_port *up = dev_id; struct tty_struct *tty; @@ -321,7 +320,7 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs) if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) || (status.sreg.isr1 & SAB82532_ISR1_BRK)) - tty = receive_chars(up, &status, regs); + tty = receive_chars(up, &status); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & SAB82532_ISR1_CSC)) check_status(up, &status); @@ -350,7 +349,7 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs) SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) || (status.sreg.isr1 & SAB82532_ISR1_BRK)) - tty = receive_chars(up, &status, regs); + tty = receive_chars(up, &status); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC))) check_status(up, &status); diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 9b3b9aaa6b90..c577faea60e8 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -310,7 +310,7 @@ static void sunsu_enable_ms(struct uart_port *port) } static struct tty_struct * -receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs *regs) +receive_chars(struct uart_sunsu_port *up, unsigned char *status) { struct tty_struct *tty = up->port.info->tty; unsigned char ch, flag; @@ -367,7 +367,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs else if (*status & UART_LSR_FE) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch, regs)) + if (uart_handle_sysrq_char(&up->port, ch)) goto ignore_char; if ((*status & up->port.ignore_status_mask) == 0) tty_insert_flip_char(tty, ch, flag); @@ -445,7 +445,7 @@ static void check_modem_status(struct uart_sunsu_port *up) wake_up_interruptible(&up->port.info->delta_msr_wait); } -static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) { struct uart_sunsu_port *up = dev_id; unsigned long flags; @@ -459,7 +459,7 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id, struct pt_regs status = serial_inp(up, UART_LSR); tty = NULL; if (status & UART_LSR_DR) - tty = receive_chars(up, &status, regs); + tty = receive_chars(up, &status); check_modem_status(up); if (status & UART_LSR_THRE) transmit_chars(up); @@ -497,7 +497,7 @@ static void sunsu_change_mouse_baud(struct uart_sunsu_port *up) sunsu_change_speed(&up->port, up->cflag, 0, quot); } -static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *regs, int is_break) +static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break) { do { unsigned char ch = serial_inp(up, UART_RX); @@ -505,7 +505,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg /* Stop-A is handled by drivers/char/keyboard.c now. */ if (up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(&up->serio, ch, 0); #endif } else if (up->su_type == SU_PORT_MS) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -519,7 +519,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg case 0: #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(&up->serio, ch, 0); #endif break; }; @@ -527,7 +527,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg } while (serial_in(up, UART_LSR) & UART_LSR_DR); } -static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id) { struct uart_sunsu_port *up = dev_id; @@ -535,8 +535,7 @@ static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs unsigned char status = serial_inp(up, UART_LSR); if ((status & UART_LSR_DR) || (status & UART_LSR_BI)) - receive_kbd_ms_chars(up, regs, - (status & UART_LSR_BI) != 0); + receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0); } return IRQ_HANDLED; diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 0da3ebfff82d..b11f6dea2704 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -277,14 +277,13 @@ static void sunzilog_change_mouse_baud(struct uart_sunzilog_port *up) } static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, - unsigned char ch, int is_break, - struct pt_regs *regs) + unsigned char ch, int is_break) { if (ZS_IS_KEYB(up)) { /* Stop-A is handled by drivers/char/keyboard.c now. */ #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(&up->serio, ch, 0); #endif } else if (ZS_IS_MOUSE(up)) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -299,7 +298,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, case 0: #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(&up->serio, ch, 0); #endif break; }; @@ -308,8 +307,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, static struct tty_struct * sunzilog_receive_chars(struct uart_sunzilog_port *up, - struct zilog_channel __iomem *channel, - struct pt_regs *regs) + struct zilog_channel __iomem *channel) { struct tty_struct *tty; unsigned char ch, r1, flag; @@ -346,12 +344,12 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, ch &= up->parity_mask; if (unlikely(ZS_IS_KEYB(up)) || unlikely(ZS_IS_MOUSE(up))) { - sunzilog_kbdms_receive_chars(up, ch, 0, regs); + sunzilog_kbdms_receive_chars(up, ch, 0); continue; } if (tty == NULL) { - uart_handle_sysrq_char(&up->port, ch, regs); + uart_handle_sysrq_char(&up->port, ch); continue; } @@ -379,7 +377,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, else if (r1 & CRC_ERR) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch, regs)) + if (uart_handle_sysrq_char(&up->port, ch)) continue; if (up->port.ignore_status_mask == 0xff || @@ -394,8 +392,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, } static void sunzilog_status_handle(struct uart_sunzilog_port *up, - struct zilog_channel __iomem *channel, - struct pt_regs *regs) + struct zilog_channel __iomem *channel) { unsigned char status; @@ -408,7 +405,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, if (status & BRK_ABRT) { if (ZS_IS_MOUSE(up)) - sunzilog_kbdms_receive_chars(up, 0, 1, regs); + sunzilog_kbdms_receive_chars(up, 0, 1); if (ZS_IS_CONS(up)) { /* Wait for BREAK to deassert to avoid potentially * confusing the PROM. @@ -517,7 +514,7 @@ ack_tx_int: ZS_WSYNC(channel); } -static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) { struct uart_sunzilog_port *up = dev_id; @@ -538,9 +535,9 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg ZS_WSYNC(channel); if (r3 & CHARxIP) - tty = sunzilog_receive_chars(up, channel, regs); + tty = sunzilog_receive_chars(up, channel); if (r3 & CHAEXT) - sunzilog_status_handle(up, channel, regs); + sunzilog_status_handle(up, channel); if (r3 & CHATxIP) sunzilog_transmit_chars(up, channel); } @@ -561,9 +558,9 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg ZS_WSYNC(channel); if (r3 & CHBRxIP) - tty = sunzilog_receive_chars(up, channel, regs); + tty = sunzilog_receive_chars(up, channel); if (r3 & CHBEXT) - sunzilog_status_handle(up, channel, regs); + sunzilog_status_handle(up, channel); if (r3 & CHBTxIP) sunzilog_transmit_chars(up, channel); } diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c index f802867c95c5..28f3bbff87bf 100644 --- a/drivers/serial/v850e_uart.c +++ b/drivers/serial/v850e_uart.c @@ -271,14 +271,14 @@ void v850e_uart_tx (struct uart_port *port) v850e_uart_stop_tx (port, stopped); } -static irqreturn_t v850e_uart_tx_irq(int irq, void *data, struct pt_regs *regs) +static irqreturn_t v850e_uart_tx_irq(int irq, void *data) { struct uart_port *port = data; v850e_uart_tx (port); return IRQ_HANDLED; } -static irqreturn_t v850e_uart_rx_irq(int irq, void *data, struct pt_regs *regs) +static irqreturn_t v850e_uart_rx_irq(int irq, void *data) { struct uart_port *port = data; unsigned ch_stat = TTY_NORMAL; diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 6c8b0ea83c3c..fd51f8182dec 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -359,8 +359,7 @@ static void siu_break_ctl(struct uart_port *port, int ctl) spin_unlock_irqrestore(&port->lock, flags); } -static inline void receive_chars(struct uart_port *port, uint8_t *status, - struct pt_regs *regs) +static inline void receive_chars(struct uart_port *port, uint8_t *status) { struct tty_struct *tty; uint8_t lsr, ch; @@ -405,7 +404,7 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status, flag = TTY_PARITY; } - if (uart_handle_sysrq_char(port, ch, regs)) + if (uart_handle_sysrq_char(port, ch)) goto ignore_char; uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); @@ -472,7 +471,7 @@ static inline void transmit_chars(struct uart_port *port) siu_stop_tx(port); } -static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t siu_interrupt(int irq, void *dev_id) { struct uart_port *port; uint8_t iir, lsr; @@ -485,7 +484,7 @@ static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs) lsr = siu_read(port, UART_LSR); if (lsr & UART_LSR_DR) - receive_chars(port, &lsr, regs); + receive_chars(port, &lsr); check_modem_status(port); diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c index 6c7e0352d561..3d91b6b9287d 100644 --- a/drivers/sn/ioc3.c +++ b/drivers/sn/ioc3.c @@ -398,7 +398,7 @@ static inline uint32_t get_pending_intrs(struct ioc3_driver_data *idd) return intrs; } -static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t ioc3_intr_io(int irq, void *arg) { unsigned long flags; struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg; @@ -412,7 +412,7 @@ static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs) if(ioc3_ethernet && idd->active[ioc3_ethernet->id] && ioc3_ethernet->intr) { handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, - idd, 0, regs); + idd, 0); } } pending = get_pending_intrs(idd); /* look at the IO IRQs */ @@ -424,8 +424,7 @@ static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs) write_ireg(idd, ioc3_submodules[id]->irq_mask, IOC3_W_IEC); if(!ioc3_submodules[id]->intr(ioc3_submodules[id], - idd, pending & ioc3_submodules[id]->irq_mask, - regs)) + idd, pending & ioc3_submodules[id]->irq_mask)) pending &= ~ioc3_submodules[id]->irq_mask; if (ioc3_submodules[id]->reset_mask) write_ireg(idd, ioc3_submodules[id]->irq_mask, @@ -442,7 +441,7 @@ static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs) return handled?IRQ_HANDLED:IRQ_NONE; } -static irqreturn_t ioc3_intr_eth(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t ioc3_intr_eth(int irq, void *arg) { unsigned long flags; struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg; @@ -453,8 +452,7 @@ static irqreturn_t ioc3_intr_eth(int irq, void *arg, struct pt_regs *regs) read_lock_irqsave(&ioc3_submodules_lock, flags); if(ioc3_ethernet && idd->active[ioc3_ethernet->id] && ioc3_ethernet->intr) - handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0, - regs); + handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0); read_unlock_irqrestore(&ioc3_submodules_lock, flags); return handled?IRQ_HANDLED:IRQ_NONE; } diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 29aec77f98be..77122edeb206 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -409,7 +409,7 @@ static int wait_dma_channel_stop(int channel) return limit; } -static void dma_handler(int channel, void *data, struct pt_regs *regs) +static void dma_handler(int channel, void *data) { struct driver_data *drv_data = data; struct spi_message *msg = drv_data->cur_msg; @@ -667,7 +667,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) return IRQ_HANDLED; } -static irqreturn_t ssp_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ssp_int(int irq, void *dev_id) { struct driver_data *drv_data = (struct driver_data *)dev_id; void *reg = drv_data->ioaddr; diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c index 5d92a7e5cb41..ff0b04895db0 100644 --- a/drivers/spi/spi_mpc83xx.c +++ b/drivers/spi/spi_mpc83xx.c @@ -296,8 +296,7 @@ static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t) return t->len - mpc83xx_spi->count; } -irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data, - struct pt_regs * ptregs) +irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data) { struct mpc83xx_spi *mpc83xx_spi = context_data; u32 event; diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index 20eb6e95a3a0..2ebe1fc4c398 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -196,7 +196,7 @@ static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) return hw->count; } -static irqreturn_t s3c24xx_spi_irq(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t s3c24xx_spi_irq(int irq, void *dev) { struct s3c24xx_spi *hw = dev; unsigned int spsta = readb(hw->regs + S3C2410_SPSTA); diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 622881f26761..7c0fe1dc96a9 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -347,7 +347,7 @@ static void rs_sched_event(struct dec_serial *info, int event) tasklet_schedule(&info->tlet); } -static void receive_chars(struct dec_serial *info, struct pt_regs *regs) +static void receive_chars(struct dec_serial *info) { struct tty_struct *tty = info->tty; unsigned char ch, stat, flag; @@ -490,7 +490,7 @@ static void status_handle(struct dec_serial *info) /* * This is the serial driver's generic interrupt routine */ -static irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t rs_interrupt(int irq, void *dev_id) { struct dec_serial *info = (struct dec_serial *) dev_id; irqreturn_t status = IRQ_NONE; @@ -518,7 +518,7 @@ static irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs *regs) status = IRQ_HANDLED; if (zs_intreg & CHBRxIP) { - receive_chars(info, regs); + receive_chars(info); } if (zs_intreg & CHBTxIP) { transmit_chars(info); diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 04631dcbabbc..3892a9e9aee3 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -171,7 +171,7 @@ struct cxacru_data { }; /* the following three functions are stolen from drivers/usb/core/message.c */ -static void cxacru_blocking_completion(struct urb *urb, struct pt_regs *regs) +static void cxacru_blocking_completion(struct urb *urb) { complete((struct completion *)urb->context); } diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 956b7a1e8af9..7c7b507af29d 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -547,7 +547,7 @@ static void speedtch_resubmit_int(unsigned long data) } } -static void speedtch_handle_int(struct urb *int_urb, struct pt_regs *regs) +static void speedtch_handle_int(struct urb *int_urb) { struct speedtch_instance_data *instance = int_urb->context; struct usbatm_data *usbatm = instance->usbatm; diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 465961a26e4a..f5434b1cbb1e 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -1297,7 +1297,7 @@ bad1: /* * interrupt handler */ -static void uea_intr(struct urb *urb, struct pt_regs *regs) +static void uea_intr(struct urb *urb) { struct uea_softc *sc = urb->context; struct intr_pkt *intr = urb->transfer_buffer; diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index a38701c742c3..309073f6433a 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -254,7 +254,7 @@ static int usbatm_submit_urb(struct urb *urb) return ret; } -static void usbatm_complete(struct urb *urb, struct pt_regs *regs) +static void usbatm_complete(struct urb *urb) { struct usbatm_channel *channel = urb->context; unsigned long flags; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 71288295df2f..ec4d1d756725 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -218,7 +218,7 @@ static int acm_write_start(struct acm *acm) */ /* control interface reports status changes with "interrupt" transfers */ -static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs) +static void acm_ctrl_irq(struct urb *urb) { struct acm *acm = urb->context; struct usb_cdc_notification *dr = urb->transfer_buffer; @@ -285,7 +285,7 @@ exit: } /* data interface returns incoming bytes, or we got unthrottled */ -static void acm_read_bulk(struct urb *urb, struct pt_regs *regs) +static void acm_read_bulk(struct urb *urb) { struct acm_rb *buf; struct acm_ru *rcv = urb->context; @@ -409,7 +409,7 @@ urbs: } /* data interface wrote those outgoing bytes */ -static void acm_write_bulk(struct urb *urb, struct pt_regs *regs) +static void acm_write_bulk(struct urb *urb) { struct acm *acm = (struct acm *)urb->context; diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 9cac11ca1bb7..a161d70e1e42 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -271,7 +271,7 @@ static int proto_bias = -1; * URB callback. */ -static void usblp_bulk_read(struct urb *urb, struct pt_regs *regs) +static void usblp_bulk_read(struct urb *urb) { struct usblp *usblp = urb->context; @@ -288,7 +288,7 @@ unplug: wake_up_interruptible(&usblp->wait); } -static void usblp_bulk_write(struct urb *urb, struct pt_regs *regs) +static void usblp_bulk_write(struct urb *urb) { struct usblp *usblp = urb->context; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 3f509beb88e4..2c9c9462d899 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -304,7 +304,7 @@ static void snoop_urb(struct urb *urb, void __user *userurb) printk("\n"); } -static void async_completed(struct urb *urb, struct pt_regs *regs) +static void async_completed(struct urb *urb) { struct async *as = urb->context; struct dev_state *ps = as->ps; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e658089f7b50..afa2dd203329 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -522,7 +522,7 @@ error: if (urb->status == -EINPROGRESS) urb->status = status; spin_unlock (&urb->lock); - usb_hcd_giveback_urb (hcd, urb, NULL); + usb_hcd_giveback_urb (hcd, urb); local_irq_restore (flags); return 0; } @@ -572,7 +572,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) /* local irqs are always blocked in completions */ if (length > 0) - usb_hcd_giveback_urb (hcd, urb, NULL); + usb_hcd_giveback_urb (hcd, urb); else hcd->poll_pending = 1; local_irq_restore (flags); @@ -656,7 +656,7 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) urb = NULL; /* wasn't fully queued */ spin_unlock (&hcd_root_hub_lock); if (urb) - usb_hcd_giveback_urb (hcd, urb, NULL); + usb_hcd_giveback_urb (hcd, urb); local_irq_restore (flags); } @@ -1498,7 +1498,6 @@ EXPORT_SYMBOL (usb_bus_start_enum); * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB * @urb: urb being returned to the USB device driver. - * @regs: pt_regs, passed down to the URB completion handler * Context: in_interrupt() * * This hands the URB from HCD to its USB device driver, using its @@ -1507,7 +1506,7 @@ EXPORT_SYMBOL (usb_bus_start_enum); * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. */ -void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) +void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { int at_root_hub; @@ -1534,7 +1533,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs usbmon_urb_complete (&hcd->self, urb); /* pass ownership to the completion handler */ - urb->complete (urb, regs); + urb->complete (urb); atomic_dec (&urb->use_count); if (unlikely (urb->reject)) wake_up (&usb_kill_urb_queue); @@ -1553,7 +1552,7 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb); * If the controller isn't HALTed, calls the driver's irq handler. * Checks whether the controller is now dead. */ -irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) +irqreturn_t usb_hcd_irq (int irq, void *__hcd) { struct usb_hcd *hcd = __hcd; int start = hcd->state; @@ -1561,7 +1560,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) if (unlikely(start == HC_STATE_HALT || !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) return IRQ_NONE; - if (hcd->driver->irq (hcd, r) == IRQ_NONE) + if (hcd->driver->irq (hcd) == IRQ_NONE) return IRQ_NONE; set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 676877c15f81..8f8df0d4382e 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -143,15 +143,13 @@ struct hcd_timeout { /* timeouts we allocate */ /*-------------------------------------------------------------------------*/ -struct pt_regs; - struct hc_driver { const char *description; /* "ehci-hcd" etc */ const char *product_desc; /* product/vendor string */ size_t hcd_priv_size; /* size of private data */ /* irq handler */ - irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs); + irqreturn_t (*irq) (struct usb_hcd *hcd); int flags; #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ @@ -205,8 +203,7 @@ struct hc_driver { extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); -extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, - struct pt_regs *regs); +extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); extern void usb_hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep); extern int usb_hcd_get_frame_number (struct usb_device *udev); @@ -248,7 +245,7 @@ void hcd_buffer_free (struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); /* generic bus glue, needed for host controllers that don't use PCI */ -extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r); +extern irqreturn_t usb_hcd_irq (int irq, void *__hcd); extern void usb_hc_died (struct usb_hcd *hcd); extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7676690a0386..66bff184a30c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -291,7 +291,7 @@ void usb_kick_khubd(struct usb_device *hdev) /* completion function, fires on port status changes and various faults */ -static void hub_irq(struct urb *urb, struct pt_regs *regs) +static void hub_irq(struct urb *urb) { struct usb_hub *hub = urb->context; int status; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 85b1cd18336f..fccd1952bad3 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -17,7 +17,7 @@ #include "hcd.h" /* for usbcore internals */ #include "usb.h" -static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) +static void usb_api_blocking_completion(struct urb *urb) { complete((struct completion *)urb->context); } @@ -246,7 +246,7 @@ static void sg_clean (struct usb_sg_request *io) io->dev = NULL; } -static void sg_complete (struct urb *urb, struct pt_regs *regs) +static void sg_complete (struct urb *urb) { struct usb_sg_request *io = urb->context; diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 77beba485a84..72f3db99ff94 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1366,7 +1366,7 @@ static void handle_ep0(struct at91_udc *udc) } } -static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r) +static irqreturn_t at91_udc_irq (int irq, void *_udc) { struct at91_udc *udc = _udc; u32 rescans = 5; @@ -1552,7 +1552,7 @@ static struct at91_udc controller = { /* ep6 and ep7 are also reserved (custom silicon might use them) */ }; -static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r) +static irqreturn_t at91_vbus_irq(int irq, void *_udc) { struct at91_udc *udc = _udc; unsigned value; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 7cf2999e8616..a3076da3f4eb 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1628,7 +1628,7 @@ stall: handled = 1; \ } -static irqreturn_t goku_irq(int irq, void *_dev, struct pt_regs *r) +static irqreturn_t goku_irq(int irq, void *_dev) { struct goku_udc *dev = _dev; struct goku_udc_regs __iomem *regs = dev->regs; diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 36db72579377..179259664c18 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -922,7 +922,7 @@ static void lh7a40x_reset_intr(struct lh7a40x_udc *dev) /* * lh7a40x usb client interrupt handler. */ -static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev, struct pt_regs *r) +static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev) { struct lh7a40x_udc *dev = _dev; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 3bda37f9a35f..d954daa8e9e0 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2753,7 +2753,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) DEBUG (dev, "unhandled irqstat1 %08x\n", stat); } -static irqreturn_t net2280_irq (int irq, void *_dev, struct pt_regs * r) +static irqreturn_t net2280_irq (int irq, void *_dev) { struct net2280 *dev = _dev; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 8c18df869833..48a09fd89d18 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -1815,8 +1815,7 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src) UDC_IRQ_SRC_REG = UDC_DS_CHG; } -static irqreturn_t -omap_udc_irq(int irq, void *_udc, struct pt_regs *r) +static irqreturn_t omap_udc_irq(int irq, void *_udc) { struct omap_udc *udc = _udc; u16 irq_src; @@ -1888,8 +1887,7 @@ static void pio_out_timer(unsigned long _ep) spin_unlock_irqrestore(&ep->udc->lock, flags); } -static irqreturn_t -omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r) +static irqreturn_t omap_udc_pio_irq(int irq, void *_dev) { u16 epn_stat, irq_src; irqreturn_t status = IRQ_NONE; @@ -1968,8 +1966,7 @@ omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r) } #ifdef USE_ISO -static irqreturn_t -omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r) +static irqreturn_t omap_udc_iso_irq(int irq, void *_dev) { struct omap_udc *udc = _dev; struct omap_ep *ep; diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index f1adcf8b2023..f42c00ef0bca 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -110,7 +110,7 @@ static int use_dma = 1; module_param(use_dma, bool, 0); MODULE_PARM_DESC (use_dma, "true to use dma"); -static void dma_nodesc_handler (int dmach, void *_ep, struct pt_regs *r); +static void dma_nodesc_handler (int dmach, void *_ep); static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req); #ifdef USE_OUT_DMA @@ -828,7 +828,7 @@ static void cancel_dma(struct pxa2xx_ep *ep) } /* dma channel stopped ... normal tx end (IN), or on error (IN/OUT) */ -static void dma_nodesc_handler(int dmach, void *_ep, struct pt_regs *r) +static void dma_nodesc_handler(int dmach, void *_ep) { struct pxa2xx_ep *ep = _ep; struct pxa2xx_request *req; @@ -1724,7 +1724,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver); */ static irqreturn_t -lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r) +lubbock_vbus_irq(int irq, void *_dev) { struct pxa2xx_udc *dev = _dev; int vbus; @@ -1754,8 +1754,7 @@ lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r) #endif -static irqreturn_t -udc_vbus_irq(int irq, void *_dev, struct pt_regs *r) +static irqreturn_t udc_vbus_irq(int irq, void *_dev) { struct pxa2xx_udc *dev = _dev; int vbus = pxa_gpio_get(dev->mach->gpio_vbus); @@ -2084,7 +2083,7 @@ static void handle_ep(struct pxa2xx_ep *ep) * could cause usb protocol errors. */ static irqreturn_t -pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r) +pxa2xx_udc_irq(int irq, void *_dev) { struct pxa2xx_udc *dev = _dev; int handled; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 5ac918591131..aac6ec5dd7cf 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -254,8 +254,8 @@ static void ehci_quiesce (struct ehci_hcd *ehci) /*-------------------------------------------------------------------------*/ -static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs); -static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs); +static void end_unlink_async (struct ehci_hcd *ehci); +static void ehci_work(struct ehci_hcd *ehci); #include "ehci-hub.c" #include "ehci-mem.c" @@ -280,7 +280,7 @@ static void ehci_iaa_watchdog (unsigned long param) ehci_vdbg (ehci, "lost IAA\n"); COUNT (ehci->stats.lost_iaa); writel (STS_IAA, &ehci->regs->status); - end_unlink_async (ehci, NULL); + end_unlink_async (ehci); } } @@ -299,7 +299,7 @@ static void ehci_watchdog (unsigned long param) start_unlink_async (ehci, ehci->async); /* ehci could run by timer, without IRQs ... */ - ehci_work (ehci, NULL); + ehci_work (ehci); spin_unlock_irqrestore (&ehci->lock, flags); } @@ -342,7 +342,7 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) * ehci_work is called from some interrupts, timers, and so on. * it calls driver completion functions, after dropping ehci->lock. */ -static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) +static void ehci_work (struct ehci_hcd *ehci) { timer_action_done (ehci, TIMER_IO_WATCHDOG); @@ -353,9 +353,9 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) if (ehci->scanning) return; ehci->scanning = 1; - scan_async (ehci, regs); + scan_async (ehci); if (ehci->next_uframe != -1) - scan_periodic (ehci, regs); + scan_periodic (ehci); ehci->scanning = 0; /* the IO watchdog guards against hardware or driver bugs that @@ -397,7 +397,7 @@ static void ehci_stop (struct usb_hcd *hcd) /* root hub is shut down separately (first, when possible) */ spin_lock_irq (&ehci->lock); if (ehci->async) - ehci_work (ehci, NULL); + ehci_work (ehci); spin_unlock_irq (&ehci->lock); ehci_mem_cleanup (ehci); @@ -573,7 +573,7 @@ static int ehci_run (struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) +static irqreturn_t ehci_irq (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 status; @@ -619,7 +619,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { COUNT (ehci->stats.reclaim); - end_unlink_async (ehci, regs); + end_unlink_async (ehci); bh = 1; } @@ -670,7 +670,7 @@ dead: } if (bh) - ehci_work (ehci, regs); + ehci_work (ehci); spin_unlock (&ehci->lock); return IRQ_HANDLED; } @@ -727,7 +727,7 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) /* failfast */ if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) - end_unlink_async (ehci, NULL); + end_unlink_async (ehci); /* defer till later if busy */ else if (ehci->reclaim) { @@ -787,7 +787,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) intr_deschedule (ehci, qh); /* FALL THROUGH */ case QH_STATE_IDLE: - qh_completions (ehci, qh, NULL); + qh_completions (ehci, qh); break; default: ehci_dbg (ehci, "bogus qh %p state %d\n", diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index b2ee13c58517..2012213c0a25 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -48,8 +48,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } ehci->command = readl (&ehci->regs->command); if (ehci->reclaim) - end_unlink_async (ehci, NULL); - ehci_work(ehci, NULL); + end_unlink_async (ehci); + ehci_work(ehci); /* suspend any active/unsuspended ports, maybe allow wakeup */ while (port--) { diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 08d0472d4f57..35e3fab6fc4e 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -303,8 +303,8 @@ restart: /* emptying the schedule aborts any urbs */ spin_lock_irq(&ehci->lock); if (ehci->reclaim) - end_unlink_async (ehci, NULL); - ehci_work(ehci, NULL); + end_unlink_async (ehci); + ehci_work(ehci); spin_unlock_irq(&ehci->lock); /* restart; khubd will disconnect devices */ diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 7fc25b6bd7d2..46327272f614 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -214,7 +214,7 @@ static void qtd_copy_status ( } static void -ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs) +ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb) __releases(ehci->lock) __acquires(ehci->lock) { @@ -262,7 +262,7 @@ __acquires(ehci->lock) /* complete() can reenter this HCD */ spin_unlock (&ehci->lock); - usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb, regs); + usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); spin_lock (&ehci->lock); } @@ -279,7 +279,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); */ #define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT) static unsigned -qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) +qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) { struct ehci_qtd *last = NULL, *end = qh->dummy; struct list_head *entry, *tmp; @@ -317,7 +317,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) /* clean up any state from previous QTD ...*/ if (last) { if (likely (last->urb != urb)) { - ehci_urb_done (ehci, last->urb, regs); + ehci_urb_done (ehci, last->urb); count++; } ehci_qtd_free (ehci, last); @@ -407,7 +407,7 @@ halt: /* last urb's completion might still need calling */ if (likely (last != NULL)) { - ehci_urb_done (ehci, last->urb, regs); + ehci_urb_done (ehci, last->urb); count++; ehci_qtd_free (ehci, last); } @@ -962,7 +962,7 @@ submit_async ( /* the async qh for the qtds being reclaimed are now unlinked from the HC */ -static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) +static void end_unlink_async (struct ehci_hcd *ehci) { struct ehci_qh *qh = ehci->reclaim; struct ehci_qh *next; @@ -979,7 +979,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) ehci->reclaim = next; qh->reclaim = NULL; - qh_completions (ehci, qh, regs); + qh_completions (ehci, qh); if (!list_empty (&qh->qtd_list) && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) @@ -1047,7 +1047,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) /* if (unlikely (qh->reclaim != 0)) * this will recurse, probably not much */ - end_unlink_async (ehci, NULL); + end_unlink_async (ehci); return; } @@ -1059,8 +1059,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) /*-------------------------------------------------------------------------*/ -static void -scan_async (struct ehci_hcd *ehci, struct pt_regs *regs) +static void scan_async (struct ehci_hcd *ehci) { struct ehci_qh *qh; enum ehci_timer_action action = TIMER_IO_WATCHDOG; @@ -1084,7 +1083,7 @@ rescan: */ qh = qh_get (qh); qh->stamp = ehci->stamp; - temp = qh_completions (ehci, qh, regs); + temp = qh_completions (ehci, qh); qh_put (qh); if (temp != 0) { goto rescan; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e5e9c653c907..65c402a0fa7a 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1553,8 +1553,7 @@ itd_link_urb ( static unsigned itd_complete ( struct ehci_hcd *ehci, - struct ehci_itd *itd, - struct pt_regs *regs + struct ehci_itd *itd ) { struct urb *urb = itd->urb; struct usb_iso_packet_descriptor *desc; @@ -1613,7 +1612,7 @@ itd_complete ( /* give urb back to the driver ... can be out-of-order */ dev = urb->dev; - ehci_urb_done (ehci, urb, regs); + ehci_urb_done (ehci, urb); urb = NULL; /* defer stopping schedule; completion can submit */ @@ -1930,8 +1929,7 @@ sitd_link_urb ( static unsigned sitd_complete ( struct ehci_hcd *ehci, - struct ehci_sitd *sitd, - struct pt_regs *regs + struct ehci_sitd *sitd ) { struct urb *urb = sitd->urb; struct usb_iso_packet_descriptor *desc; @@ -1978,7 +1976,7 @@ sitd_complete ( /* give urb back to the driver */ dev = urb->dev; - ehci_urb_done (ehci, urb, regs); + ehci_urb_done (ehci, urb); urb = NULL; /* defer stopping schedule; completion can submit */ @@ -2065,8 +2063,7 @@ sitd_submit (struct ehci_hcd *ehci, struct urb *urb, gfp_t mem_flags) static inline unsigned sitd_complete ( struct ehci_hcd *ehci, - struct ehci_sitd *sitd, - struct pt_regs *regs + struct ehci_sitd *sitd ) { ehci_err (ehci, "sitd_complete %p?\n", sitd); return 0; @@ -2077,7 +2074,7 @@ sitd_complete ( /*-------------------------------------------------------------------------*/ static void -scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) +scan_periodic (struct ehci_hcd *ehci) { unsigned frame, clock, now_uframe, mod; unsigned modified; @@ -2131,7 +2128,7 @@ restart: temp.qh = qh_get (q.qh); type = Q_NEXT_TYPE (q.qh->hw_next); q = q.qh->qh_next; - modified = qh_completions (ehci, temp.qh, regs); + modified = qh_completions (ehci, temp.qh); if (unlikely (list_empty (&temp.qh->qtd_list))) intr_deschedule (ehci, temp.qh); qh_put (temp.qh); @@ -2169,7 +2166,7 @@ restart: *hw_p = q.itd->hw_next; type = Q_NEXT_TYPE (q.itd->hw_next); wmb(); - modified = itd_complete (ehci, q.itd, regs); + modified = itd_complete (ehci, q.itd); q = *q_p; break; case Q_TYPE_SITD: @@ -2185,7 +2182,7 @@ restart: *hw_p = q.sitd->hw_next; type = Q_NEXT_TYPE (q.sitd->hw_next); wmb(); - modified = sitd_complete (ehci, q.sitd, regs); + modified = sitd_complete (ehci, q.sitd); q = *q_p; break; default: diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 61e571782cf7..87eca6aeacf2 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -478,9 +478,9 @@ static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags); static int etrax_usb_unlink_urb(struct urb *urb, int status); static int etrax_usb_get_frame_number(struct usb_device *usb_dev); -static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs); -static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs); -static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs); +static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc); +static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc); +static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc); static void etrax_usb_hc_interrupt_bottom_half(void *data); static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data); @@ -1573,7 +1573,7 @@ static int etrax_usb_get_frame_number(struct usb_device *usb_dev) return (*R_USB_FM_NUMBER & 0x7ff); } -static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs) +static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc) { DBFENTER; @@ -1839,7 +1839,7 @@ static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data) -static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs) +static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc) { struct urb *urb; etrax_urb_priv_t *urb_priv; @@ -3280,7 +3280,7 @@ static void etrax_usb_complete_urb(struct urb *urb, int status) -static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs) +static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc) { usb_interrupt_registers_t *reg; unsigned long flags; diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index a72e041df8e7..2718b5dc4ec1 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -418,7 +418,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) processed urbs. */ static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, - struct urb *urb, struct pt_regs *regs) + struct urb *urb) __releases(isp116x->lock) __acquires(isp116x->lock) { unsigned i; @@ -432,7 +432,7 @@ __releases(isp116x->lock) __acquires(isp116x->lock) urb_dbg(urb, "Finish"); spin_unlock(&isp116x->lock); - usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, regs); + usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); spin_lock(&isp116x->lock); /* take idle endpoints out of the schedule */ @@ -568,7 +568,7 @@ static void start_atl_transfers(struct isp116x *isp116x) /* Finish the processed transfers */ -static void finish_atl_transfers(struct isp116x *isp116x, struct pt_regs *regs) +static void finish_atl_transfers(struct isp116x *isp116x) { struct isp116x_ep *ep; struct urb *urb; @@ -590,12 +590,12 @@ static void finish_atl_transfers(struct isp116x *isp116x, struct pt_regs *regs) occured, while URB_SHORT_NOT_OK was set */ if (urb && urb->status != -EINPROGRESS && ep->nextpid != USB_PID_ACK) - finish_request(isp116x, ep, urb, regs); + finish_request(isp116x, ep, urb); } atomic_dec(&isp116x->atl_finishing); } -static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs) +static irqreturn_t isp116x_irq(struct usb_hcd *hcd) { struct isp116x *isp116x = hcd_to_isp116x(hcd); u16 irqstat; @@ -608,7 +608,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs) if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) { ret = IRQ_HANDLED; - finish_atl_transfers(isp116x, regs); + finish_atl_transfers(isp116x); } if (irqstat & HCuPINT_OPR) { @@ -824,7 +824,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, spin_lock(&urb->lock); if (urb->status != -EINPROGRESS) { spin_unlock(&urb->lock); - finish_request(isp116x, ep, urb, NULL); + finish_request(isp116x, ep, urb); ret = 0; goto fail; } @@ -870,7 +870,7 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) } if (urb) - finish_request(isp116x, ep, urb, NULL); + finish_request(isp116x, ep, urb); spin_unlock_irqrestore(&isp116x->lock, flags); return 0; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index d1d68c402251..9be6b303e784 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -261,7 +261,7 @@ static int ohci_urb_enqueue ( if (urb->status != -EINPROGRESS) { spin_unlock (&urb->lock); urb->hcpriv = urb_priv; - finish_urb (ohci, urb, NULL); + finish_urb (ohci, urb); retval = 0; goto fail; } @@ -337,7 +337,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) * any more ... just clean up every urb's memory. */ if (urb->hcpriv) - finish_urb (ohci, urb, NULL); + finish_urb (ohci, urb); } spin_unlock_irqrestore (&ohci->lock, flags); return 0; @@ -369,7 +369,7 @@ rescan: if (!HC_IS_RUNNING (hcd->state)) { sanitize: ed->state = ED_IDLE; - finish_unlinks (ohci, 0, NULL); + finish_unlinks (ohci, 0); } switch (ed->state) { @@ -691,7 +691,7 @@ retry: /* an interrupt happens */ -static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) +static irqreturn_t ohci_irq (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_regs __iomem *regs = ohci->regs; @@ -747,7 +747,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) if (HC_IS_RUNNING(hcd->state)) ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable); spin_lock (&ohci->lock); - dl_done_list (ohci, ptregs); + dl_done_list (ohci); spin_unlock (&ohci->lock); if (HC_IS_RUNNING(hcd->state)) ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); @@ -760,7 +760,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) */ spin_lock (&ohci->lock); if (ohci->ed_rm_list) - finish_unlinks (ohci, ohci_frame_no(ohci), ptregs); + finish_unlinks (ohci, ohci_frame_no(ohci)); if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list && HC_IS_RUNNING(hcd->state)) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); @@ -852,7 +852,7 @@ static int ohci_restart (struct ohci_hcd *ohci) urb->status = -ESHUTDOWN; spin_unlock (&urb->lock); } - finish_unlinks (ohci, 0, NULL); + finish_unlinks (ohci, 0); spin_unlock_irq(&ohci->lock); /* paranoia, in case that didn't work: */ diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index ec75774abeac..6f113596af66 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -47,8 +47,8 @@ static void ohci_rhsc_enable (struct usb_hcd *hcd) #define OHCI_SCHED_ENABLES \ (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) -static void dl_done_list (struct ohci_hcd *, struct pt_regs *); -static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); +static void dl_done_list (struct ohci_hcd *); +static void finish_unlinks (struct ohci_hcd *, u16); static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) __releases(ohci->lock) @@ -94,8 +94,8 @@ __acquires(ohci->lock) msleep (8); spin_lock_irq (&ohci->lock); } - dl_done_list (ohci, NULL); - finish_unlinks (ohci, ohci_frame_no(ohci), NULL); + dl_done_list (ohci); + finish_unlinks (ohci, ohci_frame_no(ohci)); /* maybe resume can wake root hub */ if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) || diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index e372306ed0da..e08d1a2664e6 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -7,6 +7,8 @@ * This file is licenced under the GPL. */ +#include + static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) { int last = urb_priv->length - 1; @@ -34,7 +36,7 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) * PRECONDITION: ohci lock held, irqs blocked. */ static void -finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs) +finish_urb (struct ohci_hcd *ohci, struct urb *urb) __releases(ohci->lock) __acquires(ohci->lock) { @@ -73,7 +75,7 @@ __acquires(ohci->lock) /* urb->complete() can reenter this HCD */ spin_unlock (&ohci->lock); - usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb, regs); + usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); spin_lock (&ohci->lock); /* stop periodic dma if it's not needed */ @@ -910,7 +912,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) /* there are some urbs/eds to unlink; called in_irq(), with HCD locked */ static void -finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs) +finish_unlinks (struct ohci_hcd *ohci, u16 tick) { struct ed *ed, **last; @@ -923,7 +925,7 @@ rescan_all: /* only take off EDs that the HC isn't using, accounting for * frame counter wraps and EDs with partially retired TDs */ - if (likely (regs && HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) { + if (likely (get_irq_regs() && HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) { if (tick_before (tick, ed->tick)) { skip_ed: last = &ed->ed_next; @@ -990,7 +992,7 @@ rescan_this: /* if URB is done, clean up */ if (urb_priv->td_cnt == urb_priv->length) { modified = completed = 1; - finish_urb (ohci, urb, regs); + finish_urb (ohci, urb); } } if (completed && !list_empty (&ed->td_list)) @@ -1068,7 +1070,7 @@ rescan_this: * scanning the (re-reversed) donelist as this does. */ static void -dl_done_list (struct ohci_hcd *ohci, struct pt_regs *regs) +dl_done_list (struct ohci_hcd *ohci) { struct td *td = dl_reverse_done_list (ohci); @@ -1084,7 +1086,7 @@ dl_done_list (struct ohci_hcd *ohci, struct pt_regs *regs) /* If all this urb's TDs are done, call complete() */ if (urb_priv->td_cnt == urb_priv->length) - finish_urb (ohci, urb, regs); + finish_urb (ohci, urb); /* clean schedule: unlink EDs that are no longer busy */ if (list_empty (&ed->td_list)) { diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 3a586aab3939..5fa5647ea095 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -428,7 +428,6 @@ static void finish_request( struct sl811 *sl811, struct sl811h_ep *ep, struct urb *urb, - struct pt_regs *regs, int status ) __releases(sl811->lock) __acquires(sl811->lock) { @@ -444,7 +443,7 @@ static void finish_request( spin_unlock(&urb->lock); spin_unlock(&sl811->lock); - usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, regs); + usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); spin_lock(&sl811->lock); /* leave active endpoints in the schedule */ @@ -484,7 +483,7 @@ static void finish_request( } static void -done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs) +done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) { u8 status; struct urb *urb; @@ -608,7 +607,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs) } if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS)) - finish_request(sl811, ep, urb, regs, urbstat); + finish_request(sl811, ep, urb, urbstat); } static inline u8 checkdone(struct sl811 *sl811) @@ -641,7 +640,7 @@ static inline u8 checkdone(struct sl811 *sl811) return irqstat; } -static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs) +static irqreturn_t sl811h_irq(struct usb_hcd *hcd) { struct sl811 *sl811 = hcd_to_sl811(hcd); u8 irqstat; @@ -670,13 +669,13 @@ retry: * issued ... that's fine if they're different endpoints. */ if (irqstat & SL11H_INTMASK_DONE_A) { - done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF), regs); + done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF)); sl811->active_a = NULL; sl811->stat_a++; } #ifdef USE_B if (irqstat & SL11H_INTMASK_DONE_B) { - done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF), regs); + done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF)); sl811->active_b = NULL; sl811->stat_b++; } @@ -723,7 +722,7 @@ retry: container_of(sl811->active_a ->hep->urb_list.next, struct urb, urb_list), - NULL, -ESHUTDOWN); + -ESHUTDOWN); sl811->active_a = NULL; } #ifdef USE_B @@ -957,7 +956,7 @@ static int sl811h_urb_enqueue( spin_lock(&urb->lock); if (urb->status != -EINPROGRESS) { spin_unlock(&urb->lock); - finish_request(sl811, ep, urb, NULL, 0); + finish_request(sl811, ep, urb, 0); retval = 0; goto fail; } @@ -1026,7 +1025,7 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) } if (urb) - finish_request(sl811, ep, urb, NULL, 0); + finish_request(sl811, ep, urb, 0); else VDBG("dequeue, urb %p active %s; wait4irq\n", urb, (sl811->active_a == ep) ? "A" : "B"); @@ -1083,7 +1082,7 @@ sl811h_hub_status_data(struct usb_hcd *hcd, char *buf) */ local_irq_save(flags); if (!timer_pending(&sl811->timer)) { - if (sl811h_irq( /* ~0, */ hcd, NULL) != IRQ_NONE) + if (sl811h_irq( /* ~0, */ hcd) != IRQ_NONE) sl811->stat_lost++; } local_irq_restore(flags); diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 0a315200b331..32c635ecbf31 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -557,7 +557,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, u132_ring_queue_work(u132, ring, 0); up(&u132->scheduler_lock); u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb, NULL); + usb_hcd_giveback_urb(hcd, urb); return; } @@ -590,7 +590,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, endp->active = 0; spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } usb_hcd_giveback_urb(hcd, urb, NULL); + } usb_hcd_giveback_urb(hcd, urb); return; } @@ -2434,7 +2434,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132, endp->queue_size -= 1; urb->error_count = 0; urb->hcpriv = NULL; - usb_hcd_giveback_urb(hcd, urb, NULL); + usb_hcd_giveback_urb(hcd, urb); return 0; } else continue; @@ -2512,7 +2512,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, kfree(urbq); } urb->error_count = 0; urb->hcpriv = NULL; - usb_hcd_giveback_urb(hcd, urb, NULL); + usb_hcd_giveback_urb(hcd, urb); return 0; } else if (list_empty(&endp->urb_more)) { dev_err(&u132->platform_dev->dev, "urb=%p not found in " diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index eb4eab98e8bf..45ee6920a850 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -252,7 +252,7 @@ __acquires(uhci->lock) uhci->is_stopped = UHCI_IS_STOPPED; uhci_to_hcd(uhci)->poll_rh = !int_enable; - uhci_scan_schedule(uhci, NULL); + uhci_scan_schedule(uhci); uhci_fsbr_off(uhci); } @@ -309,7 +309,7 @@ __acquires(uhci->lock) mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); } -static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) +static irqreturn_t uhci_irq(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned short status; @@ -358,7 +358,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) usb_hcd_poll_rh_status(hcd); else { spin_lock_irqsave(&uhci->lock, flags); - uhci_scan_schedule(uhci, regs); + uhci_scan_schedule(uhci); spin_unlock_irqrestore(&uhci->lock, flags); } @@ -671,7 +671,7 @@ static void uhci_stop(struct usb_hcd *hcd) spin_lock_irq(&uhci->lock); if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && !uhci->dead) uhci_hc_died(uhci); - uhci_scan_schedule(uhci, NULL); + uhci_scan_schedule(uhci); spin_unlock_irq(&uhci->lock); del_timer_sync(&uhci->fsbr_timer); diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 16fb72eb6fc9..f8347f1a10b6 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -176,7 +176,7 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) spin_lock_irqsave(&uhci->lock, flags); - uhci_scan_schedule(uhci, NULL); + uhci_scan_schedule(uhci); if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) goto done; uhci_check_ports(uhci); diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 431e8f31f1a9..06115f22a4fa 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1244,7 +1244,7 @@ done: * Finish unlinking an URB and give it back */ static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh, - struct urb *urb, struct pt_regs *regs) + struct urb *urb) __releases(uhci->lock) __acquires(uhci->lock) { @@ -1293,7 +1293,7 @@ __acquires(uhci->lock) } spin_unlock(&uhci->lock); - usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, regs); + usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); spin_lock(&uhci->lock); /* If the queue is now empty, we can unlink the QH and give up its @@ -1313,8 +1313,7 @@ __acquires(uhci->lock) (qh->state == QH_STATE_UNLINKING && \ uhci->frame_number + uhci->is_stopped != qh->unlink_frame) -static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh, - struct pt_regs *regs) +static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { struct urb_priv *urbp; struct urb *urb; @@ -1347,7 +1346,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh, return; } - uhci_giveback_urb(uhci, qh, urb, regs); + uhci_giveback_urb(uhci, qh, urb); if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC) break; } @@ -1372,7 +1371,7 @@ restart: qh->is_stopped = 0; return; } - uhci_giveback_urb(uhci, qh, urb, regs); + uhci_giveback_urb(uhci, qh, urb); goto restart; } } @@ -1487,7 +1486,7 @@ done: /* * Process events in the schedule, but only in one thread at a time */ -static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) +static void uhci_scan_schedule(struct uhci_hcd *uhci) { int i; struct uhci_qh *qh; @@ -1515,7 +1514,7 @@ rescan: struct uhci_qh, node); if (uhci_advance_check(uhci, qh)) { - uhci_scan_qh(uhci, qh, regs); + uhci_scan_qh(uhci, qh); if (qh->state == QH_STATE_ACTIVE) { uhci_urbp_wants_fsbr(uhci, list_entry(qh->queue.next, struct urb_priv, node)); diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index ca6305c1d64c..63a84bbc310d 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -280,7 +280,7 @@ static int mdc800_isReady (char *ch) /* * USB IRQ Handler for InputLine */ -static void mdc800_usb_irq (struct urb *urb, struct pt_regs *res) +static void mdc800_usb_irq (struct urb *urb) { int data_received=0, wake_up; unsigned char* b=urb->transfer_buffer; @@ -374,7 +374,7 @@ static int mdc800_usb_waitForIRQ (int mode, int msec) /* * The write_urb callback function */ -static void mdc800_usb_write_notify (struct urb *urb, struct pt_regs *res) +static void mdc800_usb_write_notify (struct urb *urb) { struct mdc800_data* mdc800=urb->context; @@ -394,7 +394,7 @@ static void mdc800_usb_write_notify (struct urb *urb, struct pt_regs *res) /* * The download_urb callback function */ -static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res) +static void mdc800_usb_download_notify (struct urb *urb) { struct mdc800_data* mdc800=urb->context; diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 5f861331932a..3038ed0700d3 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -370,7 +370,7 @@ static int mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback); static void mts_transfer_cleanup( struct urb *transfer ); -static void mts_do_sg(struct urb * transfer, struct pt_regs *regs); +static void mts_do_sg(struct urb * transfer); static inline void mts_int_submit_urb (struct urb* transfer, @@ -417,7 +417,7 @@ static void mts_transfer_cleanup( struct urb *transfer ) } -static void mts_transfer_done( struct urb *transfer, struct pt_regs *regs ) +static void mts_transfer_done( struct urb *transfer ) { MTS_INT_INIT(); @@ -443,7 +443,7 @@ static void mts_get_status( struct urb *transfer ) mts_transfer_done ); } -static void mts_data_done( struct urb* transfer, struct pt_regs *regs ) +static void mts_data_done( struct urb* transfer ) /* Interrupt context! */ { MTS_INT_INIT(); @@ -460,7 +460,7 @@ static void mts_data_done( struct urb* transfer, struct pt_regs *regs ) } -static void mts_command_done( struct urb *transfer, struct pt_regs *regs ) +static void mts_command_done( struct urb *transfer ) /* Interrupt context! */ { MTS_INT_INIT(); @@ -501,7 +501,7 @@ static void mts_command_done( struct urb *transfer, struct pt_regs *regs ) return; } -static void mts_do_sg (struct urb* transfer, struct pt_regs *regs) +static void mts_do_sg (struct urb* transfer) { struct scatterlist * sg; MTS_INT_INIT(); diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c index d83603ba40ae..0096373b5f98 100644 --- a/drivers/usb/input/acecad.c +++ b/drivers/usb/input/acecad.c @@ -58,7 +58,7 @@ struct usb_acecad { dma_addr_t data_dma; }; -static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs) +static void usb_acecad_irq(struct urb *urb) { struct usb_acecad *acecad = urb->context; unsigned char *data = acecad->data; diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index b138dae2b055..bf428184608f 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -396,7 +396,7 @@ static int aiptek_convert_from_2s_complement(unsigned char c) * replaced with the input_sync() method (which emits EV_SYN.) */ -static void aiptek_irq(struct urb *urb, struct pt_regs *regs) +static void aiptek_irq(struct urb *urb) { struct aiptek *aiptek = urb->context; unsigned char *data = aiptek->data; @@ -442,8 +442,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE; } else { - input_regs(inputdev, regs); - x = aiptek_convert_from_2s_complement(data[2]); y = aiptek_convert_from_2s_complement(data[3]); @@ -488,8 +486,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) (aiptek->curSetting.pointerMode)) { aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; } else { - input_regs(inputdev, regs); - x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); z = le16_to_cpu(get_unaligned((__le16 *) (data + 6))); @@ -568,7 +564,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) (aiptek->curSetting.pointerMode)) { aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; } else { - input_regs(inputdev, regs); x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); @@ -631,8 +626,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) z = le16_to_cpu(get_unaligned((__le16 *) (data + 4))); if (dv != 0) { - input_regs(inputdev, regs); - /* If we've not already sent a tool_button_?? code, do * so now. Then set FIRED_BIT so it won't be resent unless * the user forces FIRED_BIT off. @@ -681,8 +674,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) macro = data[3]; if (dv != 0) { - input_regs(inputdev, regs); - /* If we've not already sent a tool_button_?? code, do * so now. Then set FIRED_BIT so it won't be resent unless * the user forces FIRED_BIT off. @@ -726,8 +717,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) */ else if (data[0] == 6) { macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); - input_regs(inputdev, regs); - if (macro > 0) { input_report_key(inputdev, macroKeyEvents[macro - 1], 0); diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c index 0aa9cc2bfd69..4c213513484d 100644 --- a/drivers/usb/input/appletouch.c +++ b/drivers/usb/input/appletouch.c @@ -210,7 +210,7 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers) input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2); } -static void atp_complete(struct urb* urb, struct pt_regs* regs) +static void atp_complete(struct urb* urb) { int x, y, x_z, y_z, x_f, y_f; int retval, i, j; diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 3558d7ed99b9..f659f3028ad2 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -283,9 +283,9 @@ static void ati_remote_dump (unsigned char *data, unsigned int actual_length); static int ati_remote_open (struct input_dev *inputdev); static void ati_remote_close (struct input_dev *inputdev); static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); -static void ati_remote_irq_out (struct urb *urb, struct pt_regs *regs); -static void ati_remote_irq_in (struct urb *urb, struct pt_regs *regs); -static void ati_remote_input_report (struct urb *urb, struct pt_regs *regs); +static void ati_remote_irq_out (struct urb *urb); +static void ati_remote_irq_in (struct urb *urb); +static void ati_remote_input_report (struct urb *urb); static int ati_remote_initialize (struct ati_remote *ati_remote); static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id); static void ati_remote_disconnect (struct usb_interface *interface); @@ -344,7 +344,7 @@ static void ati_remote_close(struct input_dev *inputdev) /* * ati_remote_irq_out */ -static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs) +static void ati_remote_irq_out(struct urb *urb) { struct ati_remote *ati_remote = urb->context; @@ -453,7 +453,7 @@ static int ati_remote_compute_accel(struct ati_remote *ati_remote) /* * ati_remote_report_input */ -static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) +static void ati_remote_input_report(struct urb *urb) { struct ati_remote *ati_remote = urb->context; unsigned char *data= ati_remote->inbuf; @@ -491,7 +491,6 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) remote_num, data[1], data[2], index, ati_remote_tbl[index].code); if (ati_remote_tbl[index].kind == KIND_LITERAL) { - input_regs(dev, regs); input_event(dev, ati_remote_tbl[index].type, ati_remote_tbl[index].code, ati_remote_tbl[index].value); @@ -520,7 +519,6 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) return; - input_regs(dev, regs); input_event(dev, ati_remote_tbl[index].type, ati_remote_tbl[index].code, 1); input_sync(dev); @@ -537,7 +535,6 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) */ acc = ati_remote_compute_accel(ati_remote); - input_regs(dev, regs); switch (ati_remote_tbl[index].kind) { case KIND_ACCEL: input_event(dev, ati_remote_tbl[index].type, @@ -575,14 +572,14 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) /* * ati_remote_irq_in */ -static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs) +static void ati_remote_irq_in(struct urb *urb) { struct ati_remote *ati_remote = urb->context; int retval; switch (urb->status) { case 0: /* success */ - ati_remote_input_report(urb, regs); + ati_remote_input_report(urb); break; case -ECONNRESET: /* unlink */ case -ENOENT: diff --git a/drivers/usb/input/ati_remote2.c b/drivers/usb/input/ati_remote2.c index ea71de81ca6b..f982a2b4a7f9 100644 --- a/drivers/usb/input/ati_remote2.c +++ b/drivers/usb/input/ati_remote2.c @@ -142,7 +142,7 @@ static void ati_remote2_close(struct input_dev *idev) usb_kill_urb(ar2->urb[1]); } -static void ati_remote2_input_mouse(struct ati_remote2 *ar2, struct pt_regs *regs) +static void ati_remote2_input_mouse(struct ati_remote2 *ar2) { struct input_dev *idev = ar2->idev; u8 *data = ar2->buf[0]; @@ -157,7 +157,6 @@ static void ati_remote2_input_mouse(struct ati_remote2 *ar2, struct pt_regs *reg if (!((1 << data[0]) & mode_mask)) return; - input_regs(idev, regs); input_event(idev, EV_REL, REL_X, (s8) data[1]); input_event(idev, EV_REL, REL_Y, (s8) data[2]); input_sync(idev); @@ -174,7 +173,7 @@ static int ati_remote2_lookup(unsigned int hw_code) return -1; } -static void ati_remote2_input_key(struct ati_remote2 *ar2, struct pt_regs *regs) +static void ati_remote2_input_key(struct ati_remote2 *ar2) { struct input_dev *idev = ar2->idev; u8 *data = ar2->buf[1]; @@ -245,19 +244,18 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2, struct pt_regs *regs) return; } - input_regs(idev, regs); input_event(idev, EV_KEY, ati_remote2_key_table[index].key_code, data[1]); input_sync(idev); } -static void ati_remote2_complete_mouse(struct urb *urb, struct pt_regs *regs) +static void ati_remote2_complete_mouse(struct urb *urb) { struct ati_remote2 *ar2 = urb->context; int r; switch (urb->status) { case 0: - ati_remote2_input_mouse(ar2, regs); + ati_remote2_input_mouse(ar2); break; case -ENOENT: case -EILSEQ: @@ -277,14 +275,14 @@ static void ati_remote2_complete_mouse(struct urb *urb, struct pt_regs *regs) "%s(): usb_submit_urb() = %d\n", __FUNCTION__, r); } -static void ati_remote2_complete_key(struct urb *urb, struct pt_regs *regs) +static void ati_remote2_complete_key(struct urb *urb) { struct ati_remote2 *ar2 = urb->context; int r; switch (urb->status) { case 0: - ati_remote2_input_key(ar2, regs); + ati_remote2_input_key(ar2); break; case -ENOENT: case -EILSEQ: diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index e0fd11605b43..a6738a83ff5b 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -780,13 +780,13 @@ static __inline__ int search(__s32 *array, __s32 value, unsigned n) return -1; } -static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt, struct pt_regs *regs) +static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt) { hid_dump_input(usage, value); if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_hid_event(hid, field, usage, value, regs); + hidinput_hid_event(hid, field, usage, value); if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt) - hiddev_hid_event(hid, field, usage, value, regs); + hiddev_hid_event(hid, field, usage, value); } /* @@ -795,7 +795,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s * reporting to the layer). */ -static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt, struct pt_regs *regs) +static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt) { unsigned n; unsigned count = field->report_count; @@ -822,19 +822,19 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u for (n = 0; n < count; n++) { if (HID_MAIN_ITEM_VARIABLE & field->flags) { - hid_process_event(hid, field, &field->usage[n], value[n], interrupt, regs); + hid_process_event(hid, field, &field->usage[n], value[n], interrupt); continue; } if (field->value[n] >= min && field->value[n] <= max && field->usage[field->value[n] - min].hid && search(value, field->value[n], count)) - hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt, regs); + hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); if (value[n] >= min && value[n] <= max && field->usage[value[n] - min].hid && search(field->value, value[n], count)) - hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt, regs); + hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); } memcpy(field->value, value, count * sizeof(__s32)); @@ -842,7 +842,7 @@ exit: kfree(value); } -static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_regs *regs) +static int hid_input_report(int type, struct urb *urb, int interrupt) { struct hid_device *hid = urb->context; struct hid_report_enum *report_enum = hid->report_enum + type; @@ -892,7 +892,7 @@ static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_ hiddev_report_event(hid, report); for (n = 0; n < report->maxfield; n++) - hid_input_field(hid, report->field[n], data, interrupt, regs); + hid_input_field(hid, report->field[n], data, interrupt); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_report_event(hid, report); @@ -1004,7 +1004,7 @@ done: * Input interrupt completion handler. */ -static void hid_irq_in(struct urb *urb, struct pt_regs *regs) +static void hid_irq_in(struct urb *urb) { struct hid_device *hid = urb->context; int status; @@ -1012,7 +1012,7 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs) switch (urb->status) { case 0: /* success */ hid->retry_delay = 0; - hid_input_report(HID_INPUT_REPORT, urb, 1, regs); + hid_input_report(HID_INPUT_REPORT, urb, 1); break; case -ECONNRESET: /* unlink */ case -ENOENT: @@ -1193,7 +1193,7 @@ static int hid_submit_ctrl(struct hid_device *hid) * Output interrupt completion handler. */ -static void hid_irq_out(struct urb *urb, struct pt_regs *regs) +static void hid_irq_out(struct urb *urb) { struct hid_device *hid = urb->context; unsigned long flags; @@ -1238,7 +1238,7 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs) * Control pipe completion handler. */ -static void hid_ctrl(struct urb *urb, struct pt_regs *regs) +static void hid_ctrl(struct urb *urb) { struct hid_device *hid = urb->context; unsigned long flags; @@ -1249,7 +1249,7 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs) switch (urb->status) { case 0: /* success */ if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) - hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs); + hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0); break; case -ESHUTDOWN: /* unplug */ unplug = 1; diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 4c62afbeb430..9a808a3b4d37 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -613,7 +613,7 @@ ignore: return; } -void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs) +void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct input_dev *input; int *quirks = &hid->quirks; @@ -623,8 +623,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct input = field->hidinput->input; - input_regs(input, regs); - if (!usage->type) return; diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index b03fd9b075df..9b50effef758 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -499,13 +499,13 @@ struct hid_descriptor { /* Applications from HID Usage Tables 4/8/99 Version 1.1 */ /* We ignore a few input applications that are not widely used */ #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001)) -extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32, struct pt_regs *regs); +extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); extern int hidinput_connect(struct hid_device *); extern void hidinput_disconnect(struct hid_device *); #else #define IS_INPUT_APPLICATION(a) (0) -static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs) { } +static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { } static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { } static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; } static inline void hidinput_disconnect(struct hid_device *hid) { } diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index a2b419d13740..7dc14d0cacc1 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -179,7 +179,7 @@ static void hiddev_send_event(struct hid_device *hid, * the interrupt pipe */ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value, struct pt_regs *regs) + struct hid_usage *usage, __s32 value) { unsigned type = field->report_type; struct hiddev_usage_ref uref; diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c index f3e3080de5b5..aac968aab860 100644 --- a/drivers/usb/input/itmtouch.c +++ b/drivers/usb/input/itmtouch.c @@ -80,7 +80,7 @@ static struct usb_device_id itmtouch_ids [] = { { } }; -static void itmtouch_irq(struct urb *urb, struct pt_regs *regs) +static void itmtouch_irq(struct urb *urb) { struct itmtouch_dev *itmtouch = urb->context; unsigned char *data = urb->transfer_buffer; @@ -109,8 +109,6 @@ static void itmtouch_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - input_regs(dev, regs); - /* if pressure has been released, then don't report X/Y */ if (!(data[7] & 0x20)) { input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F)); diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index 604ade356ead..fedbcb127c21 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -41,7 +41,7 @@ struct kbtab { char phys[32]; }; -static void kbtab_irq(struct urb *urb, struct pt_regs *regs) +static void kbtab_irq(struct urb *urb) { struct kbtab *kbtab = urb->context; unsigned char *data = kbtab->data; diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c index a90359551575..50aa8108a50b 100644 --- a/drivers/usb/input/keyspan_remote.c +++ b/drivers/usb/input/keyspan_remote.c @@ -176,7 +176,7 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) /* * Routine that handles all the logic needed to parse out the message from the remote. */ -static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs) +static void keyspan_check_data(struct usb_keyspan *remote) { int i; int found = 0; @@ -311,7 +311,6 @@ static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs) __FUNCTION__, message.system, message.button, message.toggle); if (message.toggle != remote->toggle) { - input_regs(remote->input, regs); input_report_key(remote->input, keyspan_key_table[message.button], 1); input_report_key(remote->input, keyspan_key_table[message.button], 0); input_sync(remote->input); @@ -361,7 +360,7 @@ static int keyspan_setup(struct usb_device* dev) /* * Routine used to handle a new message that has come in. */ -static void keyspan_irq_recv(struct urb *urb, struct pt_regs *regs) +static void keyspan_irq_recv(struct urb *urb) { struct usb_keyspan *dev = urb->context; int retval; @@ -385,7 +384,7 @@ static void keyspan_irq_recv(struct urb *urb, struct pt_regs *regs) if (debug) keyspan_print(dev); - keyspan_check_data(dev, regs); + keyspan_check_data(dev); resubmit: retval = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index 5dce951f2751..79a85d46cb13 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -98,7 +98,7 @@ static struct usb_device_id mtouchusb_devices[] = { { } }; -static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) +static void mtouchusb_irq(struct urb *urb) { struct mtouch_usb *mtouch = urb->context; int retval; @@ -125,7 +125,6 @@ static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - input_regs(mtouch->input, regs); input_report_key(mtouch->input, BTN_TOUCH, MTOUCHUSB_GET_TOUCHED(mtouch->data)); input_report_abs(mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data)); diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index f0f8db6810a2..0bf91778c40d 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c @@ -80,10 +80,10 @@ struct powermate_device { static char pm_name_powermate[] = "Griffin PowerMate"; static char pm_name_soundknob[] = "Griffin SoundKnob"; -static void powermate_config_complete(struct urb *urb, struct pt_regs *regs); +static void powermate_config_complete(struct urb *urb); /* Callback for data arriving from the PowerMate over the USB interrupt pipe */ -static void powermate_irq(struct urb *urb, struct pt_regs *regs) +static void powermate_irq(struct urb *urb) { struct powermate_device *pm = urb->context; int retval; @@ -104,7 +104,6 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs) } /* handle updates to device state */ - input_regs(pm->input, regs); input_report_key(pm->input, BTN_0, pm->data[0] & 0x01); input_report_rel(pm->input, REL_DIAL, pm->data[1]); input_sync(pm->input); @@ -191,7 +190,7 @@ static void powermate_sync_state(struct powermate_device *pm) } /* Called when our asynchronous control message completes. We may need to issue another immediately */ -static void powermate_config_complete(struct urb *urb, struct pt_regs *regs) +static void powermate_config_complete(struct urb *urb) { struct powermate_device *pm = urb->context; unsigned long flags; diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index 30b9f820e7a8..05c0d1ca39ab 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c @@ -92,8 +92,7 @@ static inline int touchkit_get_y(char *data) /* processes one input packet. */ -static void touchkit_process_pkt(struct touchkit_usb *touchkit, - struct pt_regs *regs, char *pkt) +static void touchkit_process_pkt(struct touchkit_usb *touchkit, char *pkt) { int x, y; @@ -109,7 +108,6 @@ static void touchkit_process_pkt(struct touchkit_usb *touchkit, y = touchkit_get_y(pkt); } - input_regs(touchkit->input, regs); input_report_key(touchkit->input, BTN_TOUCH, touchkit_get_touched(pkt)); input_report_abs(touchkit->input, ABS_X, x); input_report_abs(touchkit->input, ABS_Y, y); @@ -130,8 +128,7 @@ static int touchkit_get_pkt_len(char *buf) return 0; } -static void touchkit_process(struct touchkit_usb *touchkit, int len, - struct pt_regs *regs) +static void touchkit_process(struct touchkit_usb *touchkit, int len) { char *buffer; int pkt_len, buf_len, pos; @@ -153,7 +150,7 @@ static void touchkit_process(struct touchkit_usb *touchkit, int len, /* append, process */ tmp = pkt_len - touchkit->buf_len; memcpy(touchkit->buffer + touchkit->buf_len, touchkit->data, tmp); - touchkit_process_pkt(touchkit, regs, touchkit->buffer); + touchkit_process_pkt(touchkit, touchkit->buffer); buffer = touchkit->data + tmp; buf_len = len - tmp; @@ -181,7 +178,7 @@ static void touchkit_process(struct touchkit_usb *touchkit, int len, /* full packet: process */ if (likely(pkt_len <= buf_len)) { - touchkit_process_pkt(touchkit, regs, buffer + pos); + touchkit_process_pkt(touchkit, buffer + pos); } else { /* incomplete packet: save in buffer */ memcpy(touchkit->buffer, buffer + pos, buf_len - pos); @@ -192,7 +189,7 @@ static void touchkit_process(struct touchkit_usb *touchkit, int len, } -static void touchkit_irq(struct urb *urb, struct pt_regs *regs) +static void touchkit_irq(struct urb *urb) { struct touchkit_usb *touchkit = urb->context; int retval; @@ -219,7 +216,7 @@ static void touchkit_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - touchkit_process(touchkit, urb->actual_length, regs); + touchkit_process(touchkit, urb->actual_length); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index 5067a6ae650f..c73285cf8558 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -80,7 +80,7 @@ struct usb_kbd { dma_addr_t leds_dma; }; -static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs) +static void usb_kbd_irq(struct urb *urb) { struct usb_kbd *kbd = urb->context; int i; @@ -97,8 +97,6 @@ static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs) goto resubmit; } - input_regs(kbd->dev, regs); - for (i = 0; i < 8; i++) input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); @@ -158,7 +156,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type, return 0; } -static void usb_kbd_led(struct urb *urb, struct pt_regs *regs) +static void usb_kbd_led(struct urb *urb) { struct usb_kbd *kbd = urb->context; diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index 0fb792be95ef..cbbbea332ed7 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -55,7 +55,7 @@ struct usb_mouse { dma_addr_t data_dma; }; -static void usb_mouse_irq(struct urb *urb, struct pt_regs *regs) +static void usb_mouse_irq(struct urb *urb) { struct usb_mouse *mouse = urb->context; signed char *data = mouse->data; @@ -74,8 +74,6 @@ static void usb_mouse_irq(struct urb *urb, struct pt_regs *regs) goto resubmit; } - input_regs(dev, regs); - input_report_key(dev, BTN_LEFT, data[0] & 0x01); input_report_key(dev, BTN_RIGHT, data[0] & 0x02); input_report_key(dev, BTN_MIDDLE, data[0] & 0x04); diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index 923e22db18d4..f26c1cd1129f 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -61,7 +61,7 @@ struct usbtouch_device_info { int rept_size; int flags; - void (*process_pkt) (struct usbtouch_usb *usbtouch, struct pt_regs *regs, unsigned char *pkt, int len); + void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len); int (*get_pkt_len) (unsigned char *pkt, int len); int (*read_data) (unsigned char *pkt, int *x, int *y, int *touch, int *press); int (*init) (struct usbtouch_usb *usbtouch); @@ -91,7 +91,6 @@ struct usbtouch_usb { #ifdef MULTI_PACKET static void usbtouch_process_multi(struct usbtouch_usb *usbtouch, - struct pt_regs *regs, unsigned char *pkt, int len); #endif @@ -397,7 +396,7 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { * Generic Part */ static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, - struct pt_regs *regs, unsigned char *pkt, int len) + unsigned char *pkt, int len) { int x, y, touch, press; struct usbtouch_device_info *type = usbtouch->type; @@ -405,7 +404,6 @@ static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, if (!type->read_data(pkt, &x, &y, &touch, &press)) return; - input_regs(usbtouch->input, regs); input_report_key(usbtouch->input, BTN_TOUCH, touch); if (swap_xy) { @@ -423,7 +421,6 @@ static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, #ifdef MULTI_PACKET static void usbtouch_process_multi(struct usbtouch_usb *usbtouch, - struct pt_regs *regs, unsigned char *pkt, int len) { unsigned char *buffer; @@ -460,7 +457,7 @@ static void usbtouch_process_multi(struct usbtouch_usb *usbtouch, if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size) goto out_flush_buf; memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp); - usbtouch_process_pkt(usbtouch, regs, usbtouch->buffer, pkt_len); + usbtouch_process_pkt(usbtouch, usbtouch->buffer, pkt_len); buffer = pkt + tmp; buf_len = len - tmp; @@ -481,7 +478,7 @@ static void usbtouch_process_multi(struct usbtouch_usb *usbtouch, /* full packet: process */ if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) { - usbtouch_process_pkt(usbtouch, regs, buffer + pos, pkt_len); + usbtouch_process_pkt(usbtouch, buffer + pos, pkt_len); } else { /* incomplete packet: save in buffer */ memcpy(usbtouch->buffer, buffer + pos, buf_len - pos); @@ -498,7 +495,7 @@ out_flush_buf: #endif -static void usbtouch_irq(struct urb *urb, struct pt_regs *regs) +static void usbtouch_irq(struct urb *urb) { struct usbtouch_usb *usbtouch = urb->context; int retval; @@ -525,7 +522,7 @@ static void usbtouch_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - usbtouch->type->process_pkt(usbtouch, regs, usbtouch->data, urb->actual_length); + usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/usb/input/wacom.h b/drivers/usb/input/wacom.h index 832737b658cf..7b3840e378a8 100644 --- a/drivers/usb/input/wacom.h +++ b/drivers/usb/input/wacom.h @@ -106,16 +106,14 @@ struct wacom { struct wacom_combo { struct wacom * wacom; struct urb * urb; - struct pt_regs *regs; }; extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo); -extern void wacom_sys_irq(struct urb *urb, struct pt_regs *regs); +extern void wacom_sys_irq(struct urb *urb); extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data); extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data); extern void wacom_report_key(void *wcombo, unsigned int key_type, int key_data); extern void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value); -extern void wacom_input_regs(void *wcombo); extern void wacom_input_sync(void *wcombo); extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c index 7c3b52bdd9d6..d233c37bd533 100644 --- a/drivers/usb/input/wacom_sys.c +++ b/drivers/usb/input/wacom_sys.c @@ -42,7 +42,7 @@ static struct input_dev * get_input_dev(struct wacom_combo *wcombo) return wcombo->wacom->dev; } -void wacom_sys_irq(struct urb *urb, struct pt_regs *regs) +void wacom_sys_irq(struct urb *urb) { struct wacom *wacom = urb->context; struct wacom_combo wcombo; @@ -65,7 +65,6 @@ void wacom_sys_irq(struct urb *urb, struct pt_regs *regs) wcombo.wacom = wacom; wcombo.urb = urb; - wcombo.regs = regs; if (wacom_wac_irq(wacom->wacom_wac, (void *)&wcombo)) input_sync(get_input_dev(&wcombo)); @@ -115,12 +114,6 @@ __u16 wacom_le16_to_cpu(unsigned char *data) return value; } -void wacom_input_regs(void *wcombo) -{ - input_regs(get_input_dev((struct wacom_combo *)wcombo), ((struct wacom_combo *)wcombo)->regs); - return; -} - void wacom_input_sync(void *wcombo) { input_sync(get_input_dev((struct wacom_combo *)wcombo)); diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c index 85d458c98b6e..aa31d22d4f05 100644 --- a/drivers/usb/input/wacom_wac.c +++ b/drivers/usb/input/wacom_wac.c @@ -20,7 +20,6 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo) switch (data[0]) { case 1: - wacom_input_regs(wcombo); if (data[5] & 0x80) { wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID; @@ -39,7 +38,6 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo) } break; case 2: - wacom_input_regs(wcombo); wacom_report_key(wcombo, BTN_TOOL_PEN, 1); wacom_report_abs(wcombo, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1])); @@ -67,8 +65,6 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo) prox = data[1] & 0x40; - wacom_input_regs(wcombo); - id = ERASER_DEVICE_ID; if (prox) { @@ -138,7 +134,6 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo) return 0; } - wacom_input_regs(wcombo); if (data[1] & 0x04) { wacom_report_key(wcombo, BTN_TOOL_RUBBER, data[1] & 0x20); wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x08); @@ -167,8 +162,6 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) return 0; } - wacom_input_regs(wcombo); - id = STYLUS_DEVICE_ID; if (data[1] & 0x10) { /* in prox */ @@ -369,8 +362,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) return 0; } - wacom_input_regs(wcombo); - /* tool number */ idx = data[1] & 0x01; diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index 9889b1cda05b..cebb6c463bfb 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -120,12 +120,10 @@ struct usb_xpad { * http://euc.jp/periphs/xbox-controller.ja.html */ -static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data, struct pt_regs *regs) +static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) { struct input_dev *dev = xpad->dev; - input_regs(dev, regs); - /* left stick */ input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12])); input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14])); @@ -161,7 +159,7 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d input_sync(dev); } -static void xpad_irq_in(struct urb *urb, struct pt_regs *regs) +static void xpad_irq_in(struct urb *urb) { struct usb_xpad *xpad = urb->context; int retval; @@ -181,7 +179,7 @@ static void xpad_irq_in(struct urb *urb, struct pt_regs *regs) goto exit; } - xpad_process_packet(xpad, 0, xpad->idata, regs); + xpad_process_packet(xpad, 0, xpad->idata); exit: retval = usb_submit_urb (urb, GFP_ATOMIC); diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c index 7291e7a2717b..905bf6398257 100644 --- a/drivers/usb/input/yealink.c +++ b/drivers/usb/input/yealink.c @@ -233,11 +233,10 @@ static int map_p1k_to_key(int scancode) * * The key parameter can be cascaded: key2 << 8 | key1 */ -static void report_key(struct yealink_dev *yld, int key, struct pt_regs *regs) +static void report_key(struct yealink_dev *yld, int key) { struct input_dev *idev = yld->idev; - input_regs(idev, regs); if (yld->key_code >= 0) { /* old key up */ input_report_key(idev, yld->key_code & 0xff, 0); @@ -422,7 +421,7 @@ send_update: * error,start * */ -static void urb_irq_callback(struct urb *urb, struct pt_regs *regs) +static void urb_irq_callback(struct urb *urb) { struct yealink_dev *yld = urb->context; int ret; @@ -439,7 +438,7 @@ static void urb_irq_callback(struct urb *urb, struct pt_regs *regs) case CMD_SCANCODE: dbg("get scancode %x", yld->irq_data->data[0]); - report_key(yld, map_p1k_to_key(yld->irq_data->data[0]), regs); + report_key(yld, map_p1k_to_key(yld->irq_data->data[0])); break; default: @@ -453,7 +452,7 @@ static void urb_irq_callback(struct urb *urb, struct pt_regs *regs) err("%s - usb_submit_urb failed %d", __FUNCTION__, ret); } -static void urb_ctl_callback(struct urb *urb, struct pt_regs *regs) +static void urb_ctl_callback(struct urb *urb) { struct yealink_dev *yld = urb->context; int ret; diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index d3963199b6ec..aecd633fe9f6 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -177,7 +177,7 @@ static void adu_delete(struct adu_device *dev) dbg(2, "%s : leave", __FUNCTION__); } -static void adu_interrupt_in_callback(struct urb *urb, struct pt_regs *regs) +static void adu_interrupt_in_callback(struct urb *urb) { struct adu_device *dev = urb->context; @@ -221,7 +221,7 @@ exit: dbg(4," %s : leave, status %d", __FUNCTION__, urb->status); } -static void adu_interrupt_out_callback(struct urb *urb, struct pt_regs *regs) +static void adu_interrupt_out_callback(struct urb *urb) { struct adu_device *dev = urb->context; diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index fc6cc147996f..6b23a1def9fe 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -84,7 +84,7 @@ struct appledisplay { static atomic_t count_displays = ATOMIC_INIT(0); static struct workqueue_struct *wq; -static void appledisplay_complete(struct urb *urb, struct pt_regs *regs) +static void appledisplay_complete(struct urb *urb) { struct appledisplay *pdata = urb->context; unsigned long flags; diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 4fd2110b3411..0be9d62d62ae 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -267,7 +267,7 @@ typedef struct /*-------------------------------------------------------------------*/ /* Forwards */ -static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs); +static void auerswald_ctrlread_complete (struct urb * urb); static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp); static struct usb_driver auerswald_driver; @@ -277,7 +277,7 @@ static struct usb_driver auerswald_driver; /* -------------------------- */ /* completion function for chained urbs */ -static void auerchain_complete (struct urb * urb, struct pt_regs *regs) +static void auerchain_complete (struct urb * urb) { unsigned long flags; int result; @@ -296,7 +296,7 @@ static void auerchain_complete (struct urb * urb, struct pt_regs *regs) NOTE: this function may lead to more urbs submitted into the chain. (no chain lock at calling complete()!) acp->active != NULL is protecting us against recursion.*/ - urb->complete (urb, regs); + urb->complete (urb); /* detach element from chain data structure */ spin_lock_irqsave (&acp->lock, flags); @@ -331,7 +331,7 @@ static void auerchain_complete (struct urb * urb, struct pt_regs *regs) urb->status = result; dbg("auerchain_complete: usb_submit_urb with error code %d", result); /* and do error handling via *this* completion function (recursive) */ - auerchain_complete( urb, NULL); + auerchain_complete( urb); } } else { /* simple return without submitting a new urb. @@ -408,7 +408,7 @@ static int auerchain_submit_urb_list (pauerchain_t acp, struct urb * urb, int ea urb->status = result; dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result); /* and do error handling via completion function */ - auerchain_complete( urb, NULL); + auerchain_complete( urb); } } @@ -448,7 +448,7 @@ static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb) spin_unlock_irqrestore (&acp->lock, flags); dbg ("unlink waiting urb"); urb->status = -ENOENT; - urb->complete (urb, NULL); + urb->complete (urb); return 0; } } @@ -505,7 +505,7 @@ static void auerchain_unlink_all (pauerchain_t acp) spin_unlock_irqrestore (&acp->lock, flags); dbg ("unlink waiting urb"); urbp->status = -ENOENT; - urbp->complete (urbp, NULL); + urbp->complete (urbp); spin_lock_irqsave (&acp->lock, flags); } spin_unlock_irqrestore (&acp->lock, flags); @@ -591,7 +591,7 @@ ac_fail:/* free the elements */ /* completion handler for synchronous chained URBs */ -static void auerchain_blocking_completion (struct urb *urb, struct pt_regs *regs) +static void auerchain_blocking_completion (struct urb *urb) { pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context; pchs->done = 1; @@ -846,7 +846,7 @@ static int auerswald_status_retry (int status) } /* Completion of asynchronous write block */ -static void auerchar_ctrlwrite_complete (struct urb * urb, struct pt_regs *regs) +static void auerchar_ctrlwrite_complete (struct urb * urb) { pauerbuf_t bp = (pauerbuf_t) urb->context; pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); @@ -859,7 +859,7 @@ static void auerchar_ctrlwrite_complete (struct urb * urb, struct pt_regs *regs) } /* Completion handler for dummy retry packet */ -static void auerswald_ctrlread_wretcomplete (struct urb * urb, struct pt_regs *regs) +static void auerswald_ctrlread_wretcomplete (struct urb * urb) { pauerbuf_t bp = (pauerbuf_t) urb->context; pauerswald_t cp; @@ -893,12 +893,12 @@ static void auerswald_ctrlread_wretcomplete (struct urb * urb, struct pt_regs *r if (ret) { dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret); bp->urbp->status = ret; - auerswald_ctrlread_complete (bp->urbp, NULL); + auerswald_ctrlread_complete (bp->urbp); } } /* completion handler for receiving of control messages */ -static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs) +static void auerswald_ctrlread_complete (struct urb * urb) { unsigned int serviceid; pauerswald_t cp; @@ -941,7 +941,7 @@ static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs) if (ret) { dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret); bp->urbp->status = ret; - auerswald_ctrlread_wretcomplete (bp->urbp, regs); + auerswald_ctrlread_wretcomplete (bp->urbp); } return; } @@ -970,7 +970,7 @@ static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs) messages from the USB device. */ /* int completion handler. */ -static void auerswald_int_complete (struct urb * urb, struct pt_regs *regs) +static void auerswald_int_complete (struct urb * urb) { unsigned long flags; unsigned int channelid; @@ -1070,7 +1070,7 @@ static void auerswald_int_complete (struct urb * urb, struct pt_regs *regs) if (ret) { dbg ("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret); bp->urbp->status = ret; - auerswald_ctrlread_complete( bp->urbp, NULL); + auerswald_ctrlread_complete( bp->urbp); /* here applies the same problem as above: device locking! */ } exit: diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index c6f2f488a40f..0eb26a26115b 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -758,7 +758,7 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer, return bytes_read; } -static void ftdi_elan_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void ftdi_elan_write_bulk_callback(struct urb *urb) { struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context; if (urb->status && !(urb->status == -ENOENT || urb->status == diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 10b640339d8d..788a11e6772f 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -212,7 +212,7 @@ static void ld_usb_delete(struct ld_usb *dev) /** * ld_usb_interrupt_in_callback */ -static void ld_usb_interrupt_in_callback(struct urb *urb, struct pt_regs *regs) +static void ld_usb_interrupt_in_callback(struct urb *urb) { struct ld_usb *dev = urb->context; size_t *actual_buffer; @@ -264,7 +264,7 @@ exit: /** * ld_usb_interrupt_out_callback */ -static void ld_usb_interrupt_out_callback(struct urb *urb, struct pt_regs *regs) +static void ld_usb_interrupt_out_callback(struct urb *urb) { struct ld_usb *dev = urb->context; diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 77c36e63c7bf..27089497e717 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -248,8 +248,8 @@ static loff_t tower_llseek (struct file *file, loff_t off, int whence); static void tower_abort_transfers (struct lego_usb_tower *dev); static void tower_check_for_read_packet (struct lego_usb_tower *dev); -static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs *regs); -static void tower_interrupt_out_callback (struct urb *urb, struct pt_regs *regs); +static void tower_interrupt_in_callback (struct urb *urb); +static void tower_interrupt_out_callback (struct urb *urb); static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id); static void tower_disconnect (struct usb_interface *interface); @@ -755,7 +755,7 @@ exit: /** * tower_interrupt_in_callback */ -static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs *regs) +static void tower_interrupt_in_callback (struct urb *urb) { struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context; int retval; @@ -811,7 +811,7 @@ exit: /** * tower_interrupt_out_callback */ -static void tower_interrupt_out_callback (struct urb *urb, struct pt_regs *regs) +static void tower_interrupt_out_callback (struct urb *urb) { struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context; diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index 78e419904abf..abb4dcd811ac 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -300,7 +300,7 @@ out: static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files); -static void interfacekit_irq(struct urb *urb, struct pt_regs *regs) +static void interfacekit_irq(struct urb *urb) { struct interfacekit *kit = urb->context; unsigned char *buffer = kit->data; diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c index 6b59b620d616..5c780cab92e0 100644 --- a/drivers/usb/misc/phidgetmotorcontrol.c +++ b/drivers/usb/misc/phidgetmotorcontrol.c @@ -90,7 +90,7 @@ static int set_motor(struct motorcontrol *mc, int motor) return retval < 0 ? retval : 0; } -static void motorcontrol_irq(struct urb *urb, struct pt_regs *regs) +static void motorcontrol_irq(struct urb *urb) { struct motorcontrol *mc = urb->context; unsigned char *buffer = mc->data; diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index a287836e39f1..b99ca9c79821 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -209,7 +209,7 @@ sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index) /* completion callback */ static void -sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs) +sisusb_bulk_completeout(struct urb *urb) { struct sisusb_urb_context *context = urb->context; struct sisusb_usb_data *sisusb; @@ -288,7 +288,7 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, /* completion callback */ static void -sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs) +sisusb_bulk_completein(struct urb *urb) { struct sisusb_usb_data *sisusb = urb->context; diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index dbaca9f1efad..ada2ebc464ae 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -165,7 +165,7 @@ static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u return 0; } -static void lcd_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void lcd_write_bulk_callback(struct urb *urb) { struct usb_lcd *dev; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 983e104dd452..7c2cbdf81d20 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -198,7 +198,7 @@ found: * them with non-zero test data (or test for it) when appropriate. */ -static void simple_callback (struct urb *urb, struct pt_regs *regs) +static void simple_callback (struct urb *urb) { complete ((struct completion *) urb->context); } @@ -730,7 +730,7 @@ struct subcase { int expected; }; -static void ctrl_complete (struct urb *urb, struct pt_regs *regs) +static void ctrl_complete (struct urb *urb) { struct ctrl_ctx *ctx = urb->context; struct usb_ctrlrequest *reqp; @@ -1035,7 +1035,7 @@ cleanup: /*-------------------------------------------------------------------------*/ -static void unlink1_callback (struct urb *urb, struct pt_regs *regs) +static void unlink1_callback (struct urb *urb) { int status = urb->status; @@ -1343,7 +1343,7 @@ struct iso_context { struct usbtest_dev *dev; }; -static void iso_callback (struct urb *urb, struct pt_regs *regs) +static void iso_callback (struct urb *urb) { struct iso_context *ctx = urb->context; diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 4081990b7d1a..7e8a0acd52ee 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -106,7 +106,7 @@ static void destroy_async(struct kref *kref) /* --------------------------------------------------------------------- */ -static void async_complete(struct urb *urb, struct pt_regs *ptregs) +static void async_complete(struct urb *urb) { struct uss720_async_request *rq; struct parport *pp; @@ -127,7 +127,7 @@ static void async_complete(struct urb *urb, struct pt_regs *ptregs) #endif /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */ if (rq->reg[2] & rq->reg[1] & 0x10 && pp) - parport_generic_irq(0, pp, NULL); + parport_generic_irq(0, pp); } complete(&rq->compl); kref_put(&rq->ref_count, destroy_async); diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 9c0eacf7055c..c73dd224aa76 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -214,7 +214,7 @@ static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, USB_CTRL_SET_TIMEOUT); } -static void asix_async_cmd_callback(struct urb *urb, struct pt_regs *regs) +static void asix_async_cmd_callback(struct urb *urb) { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c index be5f5e142dd0..f740325abac4 100644 --- a/drivers/usb/net/catc.c +++ b/drivers/usb/net/catc.c @@ -223,7 +223,7 @@ struct catc { * Receive routines. */ -static void catc_rx_done(struct urb *urb, struct pt_regs *regs) +static void catc_rx_done(struct urb *urb) { struct catc *catc = urb->context; u8 *pkt_start = urb->transfer_buffer; @@ -289,7 +289,7 @@ static void catc_rx_done(struct urb *urb, struct pt_regs *regs) } } -static void catc_irq_done(struct urb *urb, struct pt_regs *regs) +static void catc_irq_done(struct urb *urb) { struct catc *catc = urb->context; u8 *data = urb->transfer_buffer; @@ -376,7 +376,7 @@ static void catc_tx_run(struct catc *catc) catc->netdev->trans_start = jiffies; } -static void catc_tx_done(struct urb *urb, struct pt_regs *regs) +static void catc_tx_done(struct urb *urb) { struct catc *catc = urb->context; unsigned long flags; @@ -486,7 +486,7 @@ static void catc_ctrl_run(struct catc *catc) err("submit(ctrl_urb) status %d", status); } -static void catc_ctrl_done(struct urb *urb, struct pt_regs *regs) +static void catc_ctrl_done(struct urb *urb) { struct catc *catc = urb->context; struct ctrl_queue *q; diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c index 3155f25f1d48..a3242be21959 100644 --- a/drivers/usb/net/gl620a.c +++ b/drivers/usb/net/gl620a.c @@ -106,7 +106,7 @@ static inline int gl_control_write(struct usbnet *dev, u8 request, u16 value) return retval; } -static void gl_interrupt_complete(struct urb *urb, struct pt_regs *regs) +static void gl_interrupt_complete(struct urb *urb) { int status = urb->status; diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 544d41fe9b92..957d4ad316f9 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -475,7 +475,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) return result; } -static void kaweth_usb_receive(struct urb *, struct pt_regs *regs); +static void kaweth_usb_receive(struct urb *); static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t); /**************************************************************** @@ -500,7 +500,7 @@ static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) kaweth->dev->devpath, status); } -static void int_callback(struct urb *u, struct pt_regs *regs) +static void int_callback(struct urb *u) { struct kaweth_device *kaweth = u->context; int act_state; @@ -581,7 +581,7 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth); /**************************************************************** * kaweth_usb_receive ****************************************************************/ -static void kaweth_usb_receive(struct urb *urb, struct pt_regs *regs) +static void kaweth_usb_receive(struct urb *urb) { struct kaweth_device *kaweth = urb->context; struct net_device *net = kaweth->net; @@ -725,7 +725,7 @@ static struct ethtool_ops ops = { /**************************************************************** * kaweth_usb_transmit_complete ****************************************************************/ -static void kaweth_usb_transmit_complete(struct urb *urb, struct pt_regs *regs) +static void kaweth_usb_transmit_complete(struct urb *urb) { struct kaweth_device *kaweth = urb->context; struct sk_buff *skb = kaweth->tx_skb; @@ -1154,7 +1154,7 @@ struct usb_api_data { /*-------------------------------------------------------------------* * completion handler for compatibility wrappers (sync control/bulk) * *-------------------------------------------------------------------*/ -static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) +static void usb_api_blocking_completion(struct urb *urb) { struct usb_api_data *awd = (struct usb_api_data *)urb->context; diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c index 301baa72bac7..ce00de8f13a1 100644 --- a/drivers/usb/net/net1080.c +++ b/drivers/usb/net/net1080.c @@ -368,7 +368,7 @@ static int net1080_check_connect(struct usbnet *dev) return 0; } -static void nc_flush_complete(struct urb *urb, struct pt_regs *regs) +static void nc_flush_complete(struct urb *urb) { kfree(urb->context); usb_free_urb(urb); diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 918cf5a77c08..33abbd2176b6 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -96,7 +96,7 @@ MODULE_DEVICE_TABLE(usb, pegasus_ids); static int update_eth_regs_async(pegasus_t *); /* Aargh!!! I _really_ hate such tweaks */ -static void ctrl_callback(struct urb *urb, struct pt_regs *regs) +static void ctrl_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; @@ -605,7 +605,7 @@ static inline struct sk_buff *pull_skb(pegasus_t * pegasus) return NULL; } -static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void read_bulk_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; struct net_device *net; @@ -764,7 +764,7 @@ done: spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags); } -static void write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void write_bulk_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; struct net_device *net = pegasus->net; @@ -801,7 +801,7 @@ static void write_bulk_callback(struct urb *urb, struct pt_regs *regs) netif_wake_queue(net); } -static void intr_callback(struct urb *urb, struct pt_regs *regs) +static void intr_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; struct net_device *net; @@ -1226,7 +1226,7 @@ static void pegasus_set_multicast(struct net_device *net) } pegasus->flags |= ETH_REGS_CHANGE; - ctrl_callback(pegasus->ctrl_urb, NULL); + ctrl_callback(pegasus->ctrl_urb); } static __u8 mii_phy_probe(pegasus_t * pegasus) @@ -1433,11 +1433,11 @@ static int pegasus_resume (struct usb_interface *intf) if (netif_running(pegasus->net)) { pegasus->rx_urb->status = 0; pegasus->rx_urb->actual_length = 0; - read_bulk_callback(pegasus->rx_urb, NULL); + read_bulk_callback(pegasus->rx_urb); pegasus->intr_urb->status = 0; pegasus->intr_urb->actual_length = 0; - intr_callback(pegasus->intr_urb, NULL); + intr_callback(pegasus->intr_urb); } queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, CARRIER_CHECK_DELAY); diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 2364c2099387..72171f94ded4 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -208,7 +208,7 @@ static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) indx, 0, data, size, 500); } -static void ctrl_callback(struct urb *urb, struct pt_regs *regs) +static void ctrl_callback(struct urb *urb) { rtl8150_t *dev; @@ -415,7 +415,7 @@ static inline struct sk_buff *pull_skb(rtl8150_t *dev) return NULL; } -static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void read_bulk_callback(struct urb *urb) { rtl8150_t *dev; unsigned pkt_len, res; @@ -525,7 +525,7 @@ tlsched: tasklet_schedule(&dev->tl); } -static void write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void write_bulk_callback(struct urb *urb) { rtl8150_t *dev; @@ -541,7 +541,7 @@ static void write_bulk_callback(struct urb *urb, struct pt_regs *regs) netif_wake_queue(dev->netdev); } -static void intr_callback(struct urb *urb, struct pt_regs *regs) +static void intr_callback(struct urb *urb) { rtl8150_t *dev; __u8 *d; @@ -617,11 +617,11 @@ static int rtl8150_resume(struct usb_interface *intf) if (netif_running(dev->netdev)) { dev->rx_urb->status = 0; dev->rx_urb->actual_length = 0; - read_bulk_callback(dev->rx_urb, NULL); + read_bulk_callback(dev->rx_urb); dev->intr_urb->status = 0; dev->intr_urb->actual_length = 0; - intr_callback(dev->intr_urb, NULL); + intr_callback(dev->intr_urb); } return 0; } diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 98a522f1e264..24bd3486ee63 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -158,7 +158,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) } EXPORT_SYMBOL_GPL(usbnet_get_endpoints); -static void intr_complete (struct urb *urb, struct pt_regs *regs); +static void intr_complete (struct urb *urb); static int init_status (struct usbnet *dev, struct usb_interface *intf) { @@ -295,7 +295,7 @@ EXPORT_SYMBOL_GPL(usbnet_defer_kevent); /*-------------------------------------------------------------------------*/ -static void rx_complete (struct urb *urb, struct pt_regs *regs); +static void rx_complete (struct urb *urb); static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) { @@ -383,7 +383,7 @@ error: /*-------------------------------------------------------------------------*/ -static void rx_complete (struct urb *urb, struct pt_regs *regs) +static void rx_complete (struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct skb_data *entry = (struct skb_data *) skb->cb; @@ -467,7 +467,7 @@ block: devdbg (dev, "no read resubmitted"); } -static void intr_complete (struct urb *urb, struct pt_regs *regs) +static void intr_complete (struct urb *urb) { struct usbnet *dev = urb->context; int status = urb->status; @@ -797,7 +797,7 @@ kevent (void *data) /*-------------------------------------------------------------------------*/ -static void tx_complete (struct urb *urb, struct pt_regs *regs) +static void tx_complete (struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; struct skb_data *entry = (struct skb_data *) skb->cb; diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 2ccd9ded52a5..812275509137 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -403,7 +403,7 @@ static int aircable_write(struct usb_serial_port *port, } -static void aircable_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void aircable_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; int result; @@ -444,7 +444,7 @@ static void aircable_write_bulk_callback(struct urb *urb, struct pt_regs *regs) aircable_send(port); } -static void aircable_read_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void aircable_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct aircable_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 6e1a84a858d4..2c19f19b255c 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -46,7 +46,7 @@ struct airprime_private { struct urb *read_urbp[NUM_READ_URBS]; }; -static void airprime_read_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void airprime_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; @@ -80,7 +80,7 @@ static void airprime_read_bulk_callback(struct urb *urb, struct pt_regs *regs) return; } -static void airprime_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void airprime_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct airprime_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 70ece9e01ce4..8835bb58ca9b 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -91,7 +91,7 @@ static int belkin_sa_startup (struct usb_serial *serial); static void belkin_sa_shutdown (struct usb_serial *serial); static int belkin_sa_open (struct usb_serial_port *port, struct file *filp); static void belkin_sa_close (struct usb_serial_port *port, struct file *filp); -static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs); +static void belkin_sa_read_int_callback (struct urb *urb); static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old); static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state ); @@ -248,7 +248,7 @@ static void belkin_sa_close (struct usb_serial_port *port, struct file *filp) } /* belkin_sa_close */ -static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs) +static void belkin_sa_read_int_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct belkin_sa_private *priv; diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index d954ec34b018..a63c3286caa0 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -63,9 +63,9 @@ static int cyberjack_open (struct usb_serial_port *port, struct file *filp); static void cyberjack_close (struct usb_serial_port *port, struct file *filp); static int cyberjack_write (struct usb_serial_port *port, const unsigned char *buf, int count); static int cyberjack_write_room( struct usb_serial_port *port ); -static void cyberjack_read_int_callback (struct urb *urb, struct pt_regs *regs); -static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs); +static void cyberjack_read_int_callback (struct urb *urb); +static void cyberjack_read_bulk_callback (struct urb *urb); +static void cyberjack_write_bulk_callback (struct urb *urb); static struct usb_device_id id_table [] = { { USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) }, @@ -299,7 +299,7 @@ static int cyberjack_write_room( struct usb_serial_port *port ) return CYBERJACK_LOCAL_BUF_SIZE; } -static void cyberjack_read_int_callback( struct urb *urb, struct pt_regs *regs ) +static void cyberjack_read_int_callback( struct urb *urb ) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); @@ -356,7 +356,7 @@ resubmit: dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); } -static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void cyberjack_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); @@ -406,7 +406,7 @@ static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs) } } -static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void cyberjack_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index e1173c1aee37..f2e89a083659 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -172,8 +172,8 @@ static int cypress_chars_in_buffer (struct usb_serial_port *port); static void cypress_throttle (struct usb_serial_port *port); static void cypress_unthrottle (struct usb_serial_port *port); static void cypress_set_dead (struct usb_serial_port *port); -static void cypress_read_int_callback (struct urb *urb, struct pt_regs *regs); -static void cypress_write_int_callback (struct urb *urb, struct pt_regs *regs); +static void cypress_read_int_callback (struct urb *urb); +static void cypress_write_int_callback (struct urb *urb); /* baud helper functions */ static int mask_to_rate (unsigned mask); static unsigned rate_to_mask (int rate); @@ -1275,7 +1275,7 @@ static void cypress_unthrottle (struct usb_serial_port *port) } -static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs) +static void cypress_read_int_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct cypress_private *priv = usb_get_serial_port_data(port); @@ -1426,7 +1426,7 @@ continue_read: } /* cypress_read_int_callback */ -static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs) +static void cypress_write_int_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct cypress_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 9b225183fc7a..bdb58100fc1d 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -456,7 +456,7 @@ static int digi_tiocmget( struct usb_serial_port *port, struct file *file ); static int digi_tiocmset( struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear ); static int digi_write( struct usb_serial_port *port, const unsigned char *buf, int count ); -static void digi_write_bulk_callback( struct urb *urb, struct pt_regs *regs ); +static void digi_write_bulk_callback( struct urb *urb ); static int digi_write_room( struct usb_serial_port *port ); static int digi_chars_in_buffer( struct usb_serial_port *port ); static int digi_open( struct usb_serial_port *port, struct file *filp ); @@ -464,7 +464,7 @@ static void digi_close( struct usb_serial_port *port, struct file *filp ); static int digi_startup_device( struct usb_serial *serial ); static int digi_startup( struct usb_serial *serial ); static void digi_shutdown( struct usb_serial *serial ); -static void digi_read_bulk_callback( struct urb *urb, struct pt_regs *regs ); +static void digi_read_bulk_callback( struct urb *urb ); static int digi_read_inb_callback( struct urb *urb ); static int digi_read_oob_callback( struct urb *urb ); @@ -1336,7 +1336,7 @@ dbg( "digi_write: returning %d", ret ); } -static void digi_write_bulk_callback( struct urb *urb, struct pt_regs *regs ) +static void digi_write_bulk_callback( struct urb *urb ) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -1754,7 +1754,7 @@ dbg( "digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt() ); } -static void digi_read_bulk_callback( struct urb *urb, struct pt_regs *regs ) +static void digi_read_bulk_callback( struct urb *urb ) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index daafe405d86d..4ce10a831953 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -93,8 +93,8 @@ static int empeg_ioctl (struct usb_serial_port *port, unsigned int cmd, unsigned long arg); static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios); -static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs); +static void empeg_write_bulk_callback (struct urb *urb); +static void empeg_read_bulk_callback (struct urb *urb); static struct usb_device_id id_table [] = { { USB_DEVICE(EMPEG_VENDOR_ID, EMPEG_PRODUCT_ID) }, @@ -323,7 +323,7 @@ static int empeg_chars_in_buffer (struct usb_serial_port *port) } -static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void empeg_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -338,7 +338,7 @@ static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs) } -static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void empeg_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct tty_struct *tty; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index e774a27c6c98..d3dc1a15ec6c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -589,8 +589,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp); static int ftdi_write (struct usb_serial_port *port, const unsigned char *buf, int count); static int ftdi_write_room (struct usb_serial_port *port); static int ftdi_chars_in_buffer (struct usb_serial_port *port); -static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs); +static void ftdi_write_bulk_callback (struct urb *urb); +static void ftdi_read_bulk_callback (struct urb *urb); static void ftdi_process_read (void *param); static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old); static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file); @@ -1508,7 +1508,7 @@ static int ftdi_write (struct usb_serial_port *port, /* This function may get called when the device is closed */ -static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void ftdi_write_bulk_callback (struct urb *urb) { unsigned long flags; struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -1591,7 +1591,7 @@ static int ftdi_chars_in_buffer (struct usb_serial_port *port) -static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void ftdi_read_bulk_callback (struct urb *urb) { /* ftdi_read_bulk_callback */ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct tty_struct *tty; diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 4b1196a8b09e..4543152a9966 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1031,7 +1031,7 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp) } -static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void garmin_write_bulk_callback (struct urb *urb) { unsigned long flags; struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -1274,7 +1274,7 @@ static void garmin_read_process(struct garmin_data * garmin_data_p, } -static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void garmin_read_bulk_callback (struct urb *urb) { unsigned long flags; struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -1330,7 +1330,7 @@ static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs) } -static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs) +static void garmin_read_int_callback (struct urb *urb) { unsigned long flags; int status; diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 21cbaa0fb96b..36042937e77f 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -248,7 +248,7 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port) return (chars); } -void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +void usb_serial_generic_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; @@ -287,7 +287,7 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *reg } EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); -void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +void usb_serial_generic_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index c49976c3ad52..91bd3014ef1e 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -216,10 +216,10 @@ static int CmdUrbs = 0; /* Number of outstanding Command Write Urbs */ /* local function prototypes */ /* function prototypes for all URB callbacks */ -static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs); -static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs); -static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs); -static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs); +static void edge_interrupt_callback (struct urb *urb); +static void edge_bulk_in_callback (struct urb *urb); +static void edge_bulk_out_data_callback (struct urb *urb); +static void edge_bulk_out_cmd_callback (struct urb *urb); /* function prototypes for the usbserial callbacks */ static int edge_open (struct usb_serial_port *port, struct file *filp); @@ -534,7 +534,7 @@ static void get_product_info(struct edgeport_serial *edge_serial) * this is the callback function for when we have received data on the * interrupt endpoint. *****************************************************************************/ -static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs) +static void edge_interrupt_callback (struct urb *urb) { struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context; struct edgeport_port *edge_port; @@ -631,7 +631,7 @@ exit: * this is the callback function for when we have received data on the * bulk in endpoint. *****************************************************************************/ -static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs) +static void edge_bulk_in_callback (struct urb *urb) { struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context; unsigned char *data = urb->transfer_buffer; @@ -687,7 +687,7 @@ static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs) * this is the callback function for when we have finished sending serial data * on the bulk out endpoint. *****************************************************************************/ -static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs) +static void edge_bulk_out_data_callback (struct urb *urb) { struct edgeport_port *edge_port = (struct edgeport_port *)urb->context; struct tty_struct *tty; @@ -718,7 +718,7 @@ static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs) * this is the callback function for when we have finished sending a command * on the bulk out endpoint. *****************************************************************************/ -static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs) +static void edge_bulk_out_cmd_callback (struct urb *urb) { struct edgeport_port *edge_port = (struct edgeport_port *)urb->context; struct tty_struct *tty; diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 17c5b1d2311a..ee0c921e1520 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1697,7 +1697,7 @@ static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8 } -static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs) +static void edge_interrupt_callback (struct urb *urb) { struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context; struct usb_serial_port *port; @@ -1787,7 +1787,7 @@ exit: __FUNCTION__, status); } -static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs) +static void edge_bulk_in_callback (struct urb *urb) { struct edgeport_port *edge_port = (struct edgeport_port *)urb->context; unsigned char *data = urb->transfer_buffer; @@ -1879,7 +1879,7 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned c tty_flip_buffer_push(tty); } -static void edge_bulk_out_callback (struct urb *urb, struct pt_regs *regs) +static void edge_bulk_out_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct edgeport_port *edge_port = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index cbc725a6c58e..6238aff1e772 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -83,8 +83,8 @@ static int ipaq_write(struct usb_serial_port *port, const unsigned char *buf, static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *buf, int count); static void ipaq_write_gather(struct usb_serial_port *port); -static void ipaq_read_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs); +static void ipaq_read_bulk_callback (struct urb *urb); +static void ipaq_write_bulk_callback(struct urb *urb); static int ipaq_write_room(struct usb_serial_port *port); static int ipaq_chars_in_buffer(struct usb_serial_port *port); static void ipaq_destroy_lists(struct usb_serial_port *port); @@ -721,7 +721,7 @@ static void ipaq_close(struct usb_serial_port *port, struct file *filp) /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ } -static void ipaq_read_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void ipaq_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct tty_struct *tty; @@ -859,7 +859,7 @@ static void ipaq_write_gather(struct usb_serial_port *port) return; } -static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void ipaq_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct ipaq_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 812bc213a963..2a4bb66691ad 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -161,7 +161,7 @@ static struct usb_driver usb_ipw_driver = { static int debug; -static void ipw_read_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void ipw_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; @@ -367,7 +367,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp) usb_kill_urb(port->write_urb); } -static void ipw_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void ipw_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 1b348df388ed..331bf81556fc 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -105,8 +105,8 @@ static int ir_startup (struct usb_serial *serial); static int ir_open (struct usb_serial_port *port, struct file *filep); static void ir_close (struct usb_serial_port *port, struct file *filep); static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int count); -static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs); +static void ir_write_bulk_callback (struct urb *urb); +static void ir_read_bulk_callback (struct urb *urb); static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios); static u8 ir_baud = 0; @@ -388,7 +388,7 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int return result; } -static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void ir_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -410,7 +410,7 @@ static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs) usb_serial_port_softint(port); } -static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void ir_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct tty_struct *tty; diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 015ad6cc1bbb..53be824eb1bf 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -412,7 +412,7 @@ static int keyspan_write(struct usb_serial_port *port, return count - left; } -static void usa26_indat_callback(struct urb *urb, struct pt_regs *regs) +static void usa26_indat_callback(struct urb *urb) { int i, err; int endpoint; @@ -470,7 +470,7 @@ static void usa26_indat_callback(struct urb *urb, struct pt_regs *regs) } /* Outdat handling is common for all devices */ -static void usa2x_outdat_callback(struct urb *urb, struct pt_regs *regs) +static void usa2x_outdat_callback(struct urb *urb) { struct usb_serial_port *port; struct keyspan_port_private *p_priv; @@ -483,13 +483,13 @@ static void usa2x_outdat_callback(struct urb *urb, struct pt_regs *regs) usb_serial_port_softint(port); } -static void usa26_inack_callback(struct urb *urb, struct pt_regs *regs) +static void usa26_inack_callback(struct urb *urb) { dbg ("%s", __FUNCTION__); } -static void usa26_outcont_callback(struct urb *urb, struct pt_regs *regs) +static void usa26_outcont_callback(struct urb *urb) { struct usb_serial_port *port; struct keyspan_port_private *p_priv; @@ -503,7 +503,7 @@ static void usa26_outcont_callback(struct urb *urb, struct pt_regs *regs) } } -static void usa26_instat_callback(struct urb *urb, struct pt_regs *regs) +static void usa26_instat_callback(struct urb *urb) { unsigned char *data = urb->transfer_buffer; struct keyspan_usa26_portStatusMessage *msg; @@ -565,14 +565,14 @@ static void usa26_instat_callback(struct urb *urb, struct pt_regs *regs) exit: ; } -static void usa26_glocont_callback(struct urb *urb, struct pt_regs *regs) +static void usa26_glocont_callback(struct urb *urb) { dbg ("%s", __FUNCTION__); } -static void usa28_indat_callback(struct urb *urb, struct pt_regs *regs) +static void usa28_indat_callback(struct urb *urb) { int i, err; struct usb_serial_port *port; @@ -620,12 +620,12 @@ static void usa28_indat_callback(struct urb *urb, struct pt_regs *regs) } while (urb->status != -EINPROGRESS); } -static void usa28_inack_callback(struct urb *urb, struct pt_regs *regs) +static void usa28_inack_callback(struct urb *urb) { dbg ("%s", __FUNCTION__); } -static void usa28_outcont_callback(struct urb *urb, struct pt_regs *regs) +static void usa28_outcont_callback(struct urb *urb) { struct usb_serial_port *port; struct keyspan_port_private *p_priv; @@ -639,7 +639,7 @@ static void usa28_outcont_callback(struct urb *urb, struct pt_regs *regs) } } -static void usa28_instat_callback(struct urb *urb, struct pt_regs *regs) +static void usa28_instat_callback(struct urb *urb) { int err; unsigned char *data = urb->transfer_buffer; @@ -700,13 +700,13 @@ static void usa28_instat_callback(struct urb *urb, struct pt_regs *regs) exit: ; } -static void usa28_glocont_callback(struct urb *urb, struct pt_regs *regs) +static void usa28_glocont_callback(struct urb *urb) { dbg ("%s", __FUNCTION__); } -static void usa49_glocont_callback(struct urb *urb, struct pt_regs *regs) +static void usa49_glocont_callback(struct urb *urb) { struct usb_serial *serial; struct usb_serial_port *port; @@ -730,7 +730,7 @@ static void usa49_glocont_callback(struct urb *urb, struct pt_regs *regs) /* This is actually called glostat in the Keyspan doco */ -static void usa49_instat_callback(struct urb *urb, struct pt_regs *regs) +static void usa49_instat_callback(struct urb *urb) { int err; unsigned char *data = urb->transfer_buffer; @@ -793,12 +793,12 @@ static void usa49_instat_callback(struct urb *urb, struct pt_regs *regs) exit: ; } -static void usa49_inack_callback(struct urb *urb, struct pt_regs *regs) +static void usa49_inack_callback(struct urb *urb) { dbg ("%s", __FUNCTION__); } -static void usa49_indat_callback(struct urb *urb, struct pt_regs *regs) +static void usa49_indat_callback(struct urb *urb) { int i, err; int endpoint; @@ -851,12 +851,12 @@ static void usa49_indat_callback(struct urb *urb, struct pt_regs *regs) } /* not used, usa-49 doesn't have per-port control endpoints */ -static void usa49_outcont_callback(struct urb *urb, struct pt_regs *regs) +static void usa49_outcont_callback(struct urb *urb) { dbg ("%s", __FUNCTION__); } -static void usa90_indat_callback(struct urb *urb, struct pt_regs *regs) +static void usa90_indat_callback(struct urb *urb) { int i, err; int endpoint; @@ -930,7 +930,7 @@ static void usa90_indat_callback(struct urb *urb, struct pt_regs *regs) } -static void usa90_instat_callback(struct urb *urb, struct pt_regs *regs) +static void usa90_instat_callback(struct urb *urb) { unsigned char *data = urb->transfer_buffer; struct keyspan_usa90_portStatusMessage *msg; @@ -981,7 +981,7 @@ exit: ; } -static void usa90_outcont_callback(struct urb *urb, struct pt_regs *regs) +static void usa90_outcont_callback(struct urb *urb) { struct usb_serial_port *port; struct keyspan_port_private *p_priv; @@ -1277,7 +1277,7 @@ static int keyspan_fake_startup (struct usb_serial *serial) /* Helper functions used by keyspan_setup_urbs */ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint, int dir, void *ctx, char *buf, int len, - void (*callback)(struct urb *, struct pt_regs *regs)) + void (*callback)(struct urb *)) { struct urb *urb; @@ -1300,12 +1300,12 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint, } static struct callbacks { - void (*instat_callback)(struct urb *, struct pt_regs *regs); - void (*glocont_callback)(struct urb *, struct pt_regs *regs); - void (*indat_callback)(struct urb *, struct pt_regs *regs); - void (*outdat_callback)(struct urb *, struct pt_regs *regs); - void (*inack_callback)(struct urb *, struct pt_regs *regs); - void (*outcont_callback)(struct urb *, struct pt_regs *regs); + void (*instat_callback)(struct urb *); + void (*glocont_callback)(struct urb *); + void (*indat_callback)(struct urb *); + void (*outdat_callback)(struct urb *); + void (*inack_callback)(struct urb *); + void (*outcont_callback)(struct urb *); } keyspan_callbacks[] = { { /* msg_usa26 callbacks */ diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 59e777f1e8fd..909005107ea2 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -210,7 +210,7 @@ static void keyspan_pda_request_unthrottle( struct usb_serial *serial ) } -static void keyspan_pda_rx_interrupt (struct urb *urb, struct pt_regs *regs) +static void keyspan_pda_rx_interrupt (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct tty_struct *tty = port->tty; @@ -601,7 +601,7 @@ exit: } -static void keyspan_pda_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void keyspan_pda_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct keyspan_pda_private *priv; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 2a2f3e2da055..17e205699c2b 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -80,11 +80,11 @@ static void klsi_105_close (struct usb_serial_port *port, static int klsi_105_write (struct usb_serial_port *port, const unsigned char *buf, int count); -static void klsi_105_write_bulk_callback (struct urb *urb, struct pt_regs *regs); +static void klsi_105_write_bulk_callback (struct urb *urb); static int klsi_105_chars_in_buffer (struct usb_serial_port *port); static int klsi_105_write_room (struct usb_serial_port *port); -static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs); +static void klsi_105_read_bulk_callback (struct urb *urb); static void klsi_105_set_termios (struct usb_serial_port *port, struct termios * old); static int klsi_105_ioctl (struct usb_serial_port *port, @@ -556,7 +556,7 @@ exit: return bytes_sent; /* that's how much we wrote */ } /* klsi_105_write */ -static void klsi_105_write_bulk_callback ( struct urb *urb, struct pt_regs *regs) +static void klsi_105_write_bulk_callback ( struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -616,7 +616,7 @@ static int klsi_105_write_room (struct usb_serial_port *port) -static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void klsi_105_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct klsi_105_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index d50dce034958..ff03331e0bcf 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -80,8 +80,8 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, static int kobil_tiocmget(struct usb_serial_port *port, struct file *file); static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); -static void kobil_read_int_callback( struct urb *urb, struct pt_regs *regs ); -static void kobil_write_callback( struct urb *purb, struct pt_regs *regs ); +static void kobil_read_int_callback( struct urb *urb ); +static void kobil_write_callback( struct urb *purb ); static struct usb_device_id id_table [] = { @@ -360,7 +360,7 @@ static void kobil_close (struct usb_serial_port *port, struct file *filp) } -static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs) +static void kobil_read_int_callback( struct urb *purb) { int result; struct usb_serial_port *port = (struct usb_serial_port *) purb->context; @@ -405,7 +405,7 @@ static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs) } -static void kobil_write_callback( struct urb *purb, struct pt_regs *regs ) +static void kobil_write_callback( struct urb *purb ) { } diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index f4d4305c2c02..b7582cc496dc 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -96,7 +96,7 @@ static int mct_u232_open (struct usb_serial_port *port, struct file *filp); static void mct_u232_close (struct usb_serial_port *port, struct file *filp); -static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs); +static void mct_u232_read_int_callback (struct urb *urb); static void mct_u232_set_termios (struct usb_serial_port *port, struct termios * old); static int mct_u232_ioctl (struct usb_serial_port *port, @@ -466,7 +466,7 @@ static void mct_u232_close (struct usb_serial_port *port, struct file *filp) } /* mct_u232_close */ -static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs) +static void mct_u232_read_int_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct mct_u232_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 95bf57166c59..2306d493e55b 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -421,7 +421,7 @@ static int mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr) /************************************************************************/ /************************************************************************/ -static void mos7840_control_callback(struct urb *urb, struct pt_regs *regs) +static void mos7840_control_callback(struct urb *urb) { unsigned char *data; struct moschip_port *mos7840_port; @@ -497,7 +497,7 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, * interrupt endpoint. *****************************************************************************/ -static void mos7840_interrupt_callback(struct urb *urb, struct pt_regs *regs) +static void mos7840_interrupt_callback(struct urb *urb) { int result; int length; @@ -647,7 +647,7 @@ static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port, * bulk in endpoint. *****************************************************************************/ -static void mos7840_bulk_in_callback(struct urb *urb, struct pt_regs *regs) +static void mos7840_bulk_in_callback(struct urb *urb) { int status; unsigned char *data; @@ -726,8 +726,7 @@ static void mos7840_bulk_in_callback(struct urb *urb, struct pt_regs *regs) * on the bulk out endpoint. *****************************************************************************/ -static void mos7840_bulk_out_data_callback(struct urb *urb, - struct pt_regs *regs) +static void mos7840_bulk_out_data_callback(struct urb *urb) { struct moschip_port *mos7840_port; struct tty_struct *tty; diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index ac3f8b5d2c49..0610409a6568 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -32,7 +32,7 @@ static struct usb_driver navman_driver = { .no_dynamic_id = 1, }; -static void navman_read_int_callback(struct urb *urb, struct pt_regs *regs) +static void navman_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index a764ff4e326c..bc91d3b726fc 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -64,8 +64,8 @@ static int debug; /* function prototypes */ static int omninet_open (struct usb_serial_port *port, struct file *filp); static void omninet_close (struct usb_serial_port *port, struct file *filp); -static void omninet_read_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs); +static void omninet_read_bulk_callback (struct urb *urb); +static void omninet_write_bulk_callback (struct urb *urb); static int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count); static int omninet_write_room (struct usb_serial_port *port); static void omninet_shutdown (struct usb_serial *serial); @@ -194,7 +194,7 @@ static void omninet_close (struct usb_serial_port *port, struct file * filp) #define OMNINET_HEADERLEN sizeof(struct omninet_header) #define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN) -static void omninet_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void omninet_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; unsigned char *data = urb->transfer_buffer; @@ -306,7 +306,7 @@ static int omninet_write_room (struct usb_serial_port *port) return (room); } -static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void omninet_write_bulk_callback (struct urb *urb) { /* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */ struct usb_serial_port *port = (struct usb_serial_port *) urb->context; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index c856e6f40e22..130afbbd3fca 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -50,7 +50,7 @@ static void option_rx_throttle(struct usb_serial_port *port); static void option_rx_unthrottle(struct usb_serial_port *port); static int option_write_room(struct usb_serial_port *port); -static void option_instat_callback(struct urb *urb, struct pt_regs *regs); +static void option_instat_callback(struct urb *urb); static int option_write(struct usb_serial_port *port, const unsigned char *buf, int count); @@ -337,7 +337,7 @@ static int option_write(struct usb_serial_port *port, return count; } -static void option_indat_callback(struct urb *urb, struct pt_regs *regs) +static void option_indat_callback(struct urb *urb) { int err; int endpoint; @@ -374,7 +374,7 @@ static void option_indat_callback(struct urb *urb, struct pt_regs *regs) return; } -static void option_outdat_callback(struct urb *urb, struct pt_regs *regs) +static void option_outdat_callback(struct urb *urb) { struct usb_serial_port *port; @@ -385,7 +385,7 @@ static void option_outdat_callback(struct urb *urb, struct pt_regs *regs) usb_serial_port_softint(port); } -static void option_instat_callback(struct urb *urb, struct pt_regs *regs) +static void option_instat_callback(struct urb *urb) { int err; struct usb_serial_port *port = (struct usb_serial_port *) urb->context; @@ -565,7 +565,7 @@ static void option_close(struct usb_serial_port *port, struct file *filp) /* Helper functions used by option_setup_urbs */ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint, int dir, void *ctx, char *buf, int len, - void (*callback)(struct urb *, struct pt_regs *regs)) + void (*callback)(struct urb *)) { struct urb *urb; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 9c18173e33fb..bc800c8787a8 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -948,7 +948,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port, wake_up_interruptible(&priv->delta_msr_wait); } -static void pl2303_read_int_callback(struct urb *urb, struct pt_regs *regs) +static void pl2303_read_int_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *) urb->context; unsigned char *data = urb->transfer_buffer; @@ -987,7 +987,7 @@ exit: __FUNCTION__, status); } -static void pl2303_read_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void pl2303_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *) urb->context; struct pl2303_private *priv = usb_get_serial_port_data(port); @@ -1070,7 +1070,7 @@ static void pl2303_read_bulk_callback(struct urb *urb, struct pt_regs *regs) return; } -static void pl2303_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void pl2303_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *) urb->context; struct pl2303_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 1e07dfad6853..30b7ebc8d45d 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -204,7 +204,7 @@ static __u16 __inline__ fcs_compute10 (unsigned char *sp, int len, __u16 fcs) return fcs; } -static void safe_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void safe_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *) urb->context; unsigned char *data = urb->transfer_buffer; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index ac9b8ee52d44..07400c0c8a8c 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -166,9 +166,9 @@ static int ti_tiocmget(struct usb_serial_port *port, struct file *file); static int ti_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static void ti_break(struct usb_serial_port *port, int break_state); -static void ti_interrupt_callback(struct urb *urb, struct pt_regs *regs); -static void ti_bulk_in_callback(struct urb *urb, struct pt_regs *regs); -static void ti_bulk_out_callback(struct urb *urb, struct pt_regs *regs); +static void ti_interrupt_callback(struct urb *urb); +static void ti_bulk_in_callback(struct urb *urb); +static void ti_bulk_out_callback(struct urb *urb); static void ti_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length); @@ -1098,7 +1098,7 @@ static void ti_break(struct usb_serial_port *port, int break_state) } -static void ti_interrupt_callback(struct urb *urb, struct pt_regs *regs) +static void ti_interrupt_callback(struct urb *urb) { struct ti_device *tdev = (struct ti_device *)urb->context; struct usb_serial_port *port; @@ -1178,7 +1178,7 @@ exit: } -static void ti_bulk_in_callback(struct urb *urb, struct pt_regs *regs) +static void ti_bulk_in_callback(struct urb *urb) { struct ti_port *tport = (struct ti_port *)urb->context; struct usb_serial_port *port = tport->tp_port; @@ -1241,7 +1241,7 @@ exit: } -static void ti_bulk_out_callback(struct urb *urb, struct pt_regs *regs) +static void ti_bulk_out_callback(struct urb *urb) { struct ti_port *tport = (struct ti_port *)urb->context; struct usb_serial_port *port = tport->tp_port; diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 88949f7884ca..befe2e11a041 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -47,9 +47,9 @@ static int visor_calc_num_ports(struct usb_serial *serial); static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios); -static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void visor_read_int_callback (struct urb *urb, struct pt_regs *regs); +static void visor_write_bulk_callback (struct urb *urb); +static void visor_read_bulk_callback (struct urb *urb); +static void visor_read_int_callback (struct urb *urb); static int clie_3_5_startup (struct usb_serial *serial); static int treo_attach (struct usb_serial *serial); static int clie_5_attach (struct usb_serial *serial); @@ -471,7 +471,7 @@ static int visor_chars_in_buffer (struct usb_serial_port *port) } -static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void visor_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct visor_private *priv = usb_get_serial_port_data(port); @@ -494,7 +494,7 @@ static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs) } -static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +static void visor_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct visor_private *priv = usb_get_serial_port_data(port); @@ -539,7 +539,7 @@ static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs) return; } -static void visor_read_int_callback (struct urb *urb, struct pt_regs *regs) +static void visor_read_int_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; int result; diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 6e6c7934be32..4d1cd7aeccd3 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -152,8 +152,8 @@ static void whiteheat_break_ctl (struct usb_serial_port *port, int break_state) static int whiteheat_chars_in_buffer (struct usb_serial_port *port); static void whiteheat_throttle (struct usb_serial_port *port); static void whiteheat_unthrottle (struct usb_serial_port *port); -static void whiteheat_read_callback (struct urb *urb, struct pt_regs *regs); -static void whiteheat_write_callback (struct urb *urb, struct pt_regs *regs); +static void whiteheat_read_callback (struct urb *urb); +static void whiteheat_write_callback (struct urb *urb); static struct usb_serial_driver whiteheat_fake_device = { .driver = { @@ -235,8 +235,8 @@ struct whiteheat_private { /* local function prototypes */ static int start_command_port(struct usb_serial *serial); static void stop_command_port(struct usb_serial *serial); -static void command_port_write_callback(struct urb *urb, struct pt_regs *regs); -static void command_port_read_callback(struct urb *urb, struct pt_regs *regs); +static void command_port_write_callback(struct urb *urb); +static void command_port_read_callback(struct urb *urb); static int start_port_read(struct usb_serial_port *port); static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, struct list_head *head); @@ -958,7 +958,7 @@ static void whiteheat_unthrottle (struct usb_serial_port *port) /***************************************************************************** * Connect Tech's White Heat callback routines *****************************************************************************/ -static void command_port_write_callback (struct urb *urb, struct pt_regs *regs) +static void command_port_write_callback (struct urb *urb) { dbg("%s", __FUNCTION__); @@ -969,7 +969,7 @@ static void command_port_write_callback (struct urb *urb, struct pt_regs *regs) } -static void command_port_read_callback (struct urb *urb, struct pt_regs *regs) +static void command_port_read_callback (struct urb *urb) { struct usb_serial_port *command_port = (struct usb_serial_port *)urb->context; struct whiteheat_command_private *command_info; @@ -1019,7 +1019,7 @@ static void command_port_read_callback (struct urb *urb, struct pt_regs *regs) } -static void whiteheat_read_callback(struct urb *urb, struct pt_regs *regs) +static void whiteheat_read_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct whiteheat_urb_wrap *wrap; @@ -1061,7 +1061,7 @@ static void whiteheat_read_callback(struct urb *urb, struct pt_regs *regs) } -static void whiteheat_write_callback(struct urb *urb, struct pt_regs *regs) +static void whiteheat_write_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct whiteheat_private *info = usb_get_serial_port_data(port); diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index f843a0bcf107..3baf448e300d 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -53,7 +53,7 @@ struct usb_onetouch { unsigned int is_open:1; }; -static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs) +static void usb_onetouch_irq(struct urb *urb) { struct usb_onetouch *onetouch = urb->context; signed char *data = onetouch->data; @@ -72,7 +72,6 @@ static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs) goto resubmit; } - input_regs(dev, regs); input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02); input_sync(dev); diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index f23514c4e649..47644b5b6155 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -108,7 +108,7 @@ /* This is the completion handler which will wake us up when an URB * completes. */ -static void usb_stor_blocking_completion(struct urb *urb, struct pt_regs *regs) +static void usb_stor_blocking_completion(struct urb *urb) { struct completion *urb_done_ptr = (struct completion *)urb->context; diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 1b51d3187a95..296b091cf168 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -158,7 +158,7 @@ exit: return retval; } -static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void skel_write_bulk_callback(struct urb *urb) { struct usb_skel *dev; diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index f1ba54f4fc39..a4e3fca05891 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -1144,7 +1144,7 @@ static void amifb_deinit(void); */ static int flash_cursor(void); -static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp); +static irqreturn_t amifb_interrupt(int irq, void *dev_id); static u_long chipalloc(u_long size); static void chipfree(void); @@ -2492,7 +2492,7 @@ static int flash_cursor(void) * VBlank Display Interrupt */ -static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t amifb_interrupt(int irq, void *dev_id) { if (do_vmode_pan || do_vmode_full) ami_update_display(); diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index 70dd8115a4d8..ab34b96acc31 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c @@ -218,8 +218,7 @@ static int arcfb_pan_display(struct fb_var_screeninfo *var, return -EINVAL; } -static irqreturn_t arcfb_interrupt(int vec, void *dev_instance, - struct pt_regs *regs) +static irqreturn_t arcfb_interrupt(int vec, void *dev_instance) { struct fb_info *info = dev_instance; unsigned char ctl2status; diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 5831893bf7a0..02c41a626fa2 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -1521,7 +1521,7 @@ static void falcon_set_par( struct atafb_par *par ) } -static irqreturn_t falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp ) +static irqreturn_t falcon_vbl_switcher( int irq, void *dummy ) { struct falcon_hw *hw = &f_new_mode; diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index b45c9fd1b330..b77b30923928 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -1532,7 +1532,7 @@ static int atyfb_open(struct fb_info *info, int user) return (0); } -static irqreturn_t aty_irq(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t aty_irq(int irq, void *dev_id) { struct atyfb_par *par = dev_id; int handled = 0; diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index c6a5f0ccc107..dbf4ec3f6d57 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -1545,7 +1545,7 @@ static struct fb_ops au1200fb_fb_ops = { /*-------------------------------------------------------------------------*/ -static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs) +static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id) { /* Nothing to do for now, just clear any pending interrupt */ lcd->intstatus = lcd->intstatus; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 8c041daa3a15..302174b8e477 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -204,7 +204,7 @@ static struct class_device *fbcon_class_device; */ static int vbl_detected; -static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t fb_vbl_detect(int irq, void *dummy) { vbl_detected++; return IRQ_HANDLED; @@ -414,7 +414,7 @@ static void fb_flashcursor(void *private) #if defined(CONFIG_ATARI) || defined(CONFIG_MAC) static int cursor_blink_rate; -static irqreturn_t fb_vbl_handler(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t fb_vbl_handler(int irq, void *dev_id) { struct fb_info *info = dev_id; diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index f887f1efd3fe..eeeeff9a09eb 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -1952,7 +1952,7 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) { } static irqreturn_t -intelfbhw_irq(int irq, void *dev_id, struct pt_regs *fp) { +intelfbhw_irq(int irq, void *dev_id) { int handled = 0; u16 tmp; struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 7acf01c181ee..e9b4115fcad0 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -198,7 +198,7 @@ static void matroxfb_crtc1_panpos(WPMINFO2) { } } -static irqreturn_t matrox_irq(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t matrox_irq(int irq, void *dev_id) { u_int32_t status; int handled = 0; diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 78dc59a1751b..c7bc80921f16 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -209,7 +209,7 @@ static int pvr2fb_set_par(struct fb_info *info); static void pvr2_update_display(struct fb_info *info); static void pvr2_init_display(struct fb_info *info); static void pvr2_do_blank(void); -static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp); +static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id); static int pvr2_init_cable(void); static int pvr2_get_param(const struct pvr2_params *p, const char *s, int val, int size); @@ -626,7 +626,7 @@ static void pvr2_do_blank(void) is_blanked = do_blank > 0 ? do_blank : 0; } -static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp) +static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id) { struct fb_info *info = dev_id; diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 3bc5da4a57ca..8a8ae55a7403 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -846,7 +846,7 @@ static void pxafb_disable_controller(struct pxafb_info *fbi) /* * pxafb_handle_irq: Handle 'LCD DONE' interrupts. */ -static irqreturn_t pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pxafb_handle_irq(int irq, void *dev_id) { struct pxafb_info *fbi = dev_id; unsigned int lcsr = LCSR; diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index ad3bdd6f1ac1..59407343cc73 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -614,7 +614,7 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi) } } -static irqreturn_t s3c2410fb_irq(int irq, void *dev_id, struct pt_regs *r) +static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) { struct s3c2410fb_info *fbi = dev_id; unsigned long lcdirq = readl(S3C2410_LCDINTPND); diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index a2e6e7205d7e..cd10b18150b8 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -1085,7 +1085,7 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi) /* * sa1100fb_handle_irq: Handle 'LCD DONE' interrupts. */ -static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id) { struct sa1100fb_info *fbi = dev_id; unsigned int lcsr = LCSR; diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 8d88e58ed5cc..93c43b676e59 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -647,7 +647,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, if (get_user(c, buf)) return -EFAULT; - __handle_sysrq(c, NULL, NULL, 0); + __handle_sysrq(c, NULL, 0); } return count; } diff --git a/include/asm-frv/dma.h b/include/asm-frv/dma.h index 18d6bb8f84fc..683c47d48a5b 100644 --- a/include/asm-frv/dma.h +++ b/include/asm-frv/dma.h @@ -24,10 +24,7 @@ /* * FRV DMA controller management */ -struct pt_regs; - -typedef irqreturn_t (*dma_irq_handler_t)(int dmachan, unsigned long cstr, void *data, - struct pt_regs *regs); +typedef irqreturn_t (*dma_irq_handler_t)(int dmachan, unsigned long cstr, void *data); extern void frv_dma_init(void); diff --git a/include/asm-frv/irq_regs.h b/include/asm-frv/irq_regs.h new file mode 100644 index 000000000000..d22e83289ad1 --- /dev/null +++ b/include/asm-frv/irq_regs.h @@ -0,0 +1,27 @@ +/* FRV per-CPU frame pointer holder + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ASM_IRQ_REGS_H +#define _ASM_IRQ_REGS_H + +/* + * Per-cpu current frame pointer - the location of the last exception frame on + * the stack + * - on FRV, GR28 is dedicated to keeping a pointer to the current exception + * frame + */ +#define ARCH_HAS_OWN_IRQ_REGS + +#ifndef __ASSEMBLY__ +#define get_irq_regs() (__frame) +#endif + +#endif /* _ASM_IRQ_REGS_H */ diff --git a/include/asm-frv/ptrace.h b/include/asm-frv/ptrace.h index 7ff525162a72..9a2241b8eb1e 100644 --- a/include/asm-frv/ptrace.h +++ b/include/asm-frv/ptrace.h @@ -12,6 +12,7 @@ #define _ASM_PTRACE_H #include +#include #define in_syscall(regs) (((regs)->tbr & TBR_TT) == TBR_TT_TRAP0) diff --git a/include/asm-generic/irq_regs.h b/include/asm-generic/irq_regs.h new file mode 100644 index 000000000000..5ae1d07d4a12 --- /dev/null +++ b/include/asm-generic/irq_regs.h @@ -0,0 +1,37 @@ +/* Fallback per-CPU frame pointer holder + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ASM_GENERIC_IRQ_REGS_H +#define _ASM_GENERIC_IRQ_REGS_H + +#include + +/* + * Per-cpu current frame pointer - the location of the last exception frame on + * the stack + */ +DECLARE_PER_CPU(struct pt_regs *, __irq_regs); + +static inline struct pt_regs *get_irq_regs(void) +{ + return __get_cpu_var(__irq_regs); +} + +static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs) +{ + struct pt_regs *old_regs, **pp_regs = &__get_cpu_var(__irq_regs); + + old_regs = *pp_regs; + *pp_regs = new_regs; + return old_regs; +} + +#endif /* _ASM_GENERIC_IRQ_REGS_H */ diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index 3a42b7d6fc92..b9529578fc37 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -98,7 +98,7 @@ extern void sync_Arb_IDs (void); extern void init_bsp_APIC (void); extern void setup_local_APIC (void); extern void init_apic_mappings (void); -extern void smp_local_timer_interrupt (struct pt_regs * regs); +extern void smp_local_timer_interrupt (void); extern void setup_boot_APIC_clock (void); extern void setup_secondary_APIC_clock (void); extern int APIC_init_uniprocessor (void); @@ -107,7 +107,7 @@ extern void enable_APIC_timer(void); extern void enable_NMI_through_LVT0 (void * dummy); -void smp_send_timer_broadcast_ipi(struct pt_regs *regs); +void smp_send_timer_broadcast_ipi(void); void switch_APIC_timer_to_ipi(void *cpumask); void switch_ipi_to_APIC_timer(void *cpumask); #define ARCH_APICTIMER_STOPS_ON_C3 1 diff --git a/include/asm-i386/arch_hooks.h b/include/asm-i386/arch_hooks.h index 238cf4275b96..a8c1fca9726d 100644 --- a/include/asm-i386/arch_hooks.h +++ b/include/asm-i386/arch_hooks.h @@ -14,7 +14,7 @@ extern void init_ISA_irqs(void); extern void apic_intr_init(void); extern void smp_intr_init(void); -extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t timer_interrupt(int irq, void *dev_id); /* these are the defined hooks */ extern void intr_init_hook(void); diff --git a/include/asm-i386/floppy.h b/include/asm-i386/floppy.h index 359ead60b718..44ef2f55a8e9 100644 --- a/include/asm-i386/floppy.h +++ b/include/asm-i386/floppy.h @@ -51,7 +51,7 @@ static char *virtual_dma_addr; static int virtual_dma_mode; static int doing_pdma; -static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t floppy_hardint(int irq, void *dev_id) { register unsigned char st; @@ -63,7 +63,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) static int dma_wait=0; #endif if (!doing_pdma) - return floppy_interrupt(irq, dev_id, regs); + return floppy_interrupt(irq, dev_id); #ifdef TRACE_FLPY_INT if(!calls) @@ -106,7 +106,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) dma_wait=0; #endif doing_pdma = 0; - floppy_interrupt(irq, dev_id, regs); + floppy_interrupt(irq, dev_id); return IRQ_HANDLED; } #ifdef TRACE_FLPY_INT diff --git a/include/asm-i386/hpet.h b/include/asm-i386/hpet.h index af5d435519d1..e47be9a56cc2 100644 --- a/include/asm-i386/hpet.h +++ b/include/asm-i386/hpet.h @@ -108,7 +108,7 @@ extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned ch extern int hpet_set_periodic_freq(unsigned long freq); extern int hpet_rtc_dropped_irq(void); extern int hpet_rtc_timer_init(void); -extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); #endif /* CONFIG_HPET_EMULATE_RTC */ #endif /* CONFIG_HPET_TIMER */ #endif /* _I386_HPET_H */ diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 88f02a073561..8806c7e002a7 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h @@ -41,7 +41,7 @@ fastcall void call_function_interrupt(void); fastcall void apic_timer_interrupt(void); fastcall void error_interrupt(void); fastcall void spurious_interrupt(void); -fastcall void thermal_interrupt(struct pt_regs *); +fastcall void thermal_interrupt(void); #define platform_legacy_irq(irq) ((irq) < 16) #endif diff --git a/include/asm-i386/irq_regs.h b/include/asm-i386/irq_regs.h new file mode 100644 index 000000000000..3dd9c0b70270 --- /dev/null +++ b/include/asm-i386/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-i386/mach-default/do_timer.h b/include/asm-i386/mach-default/do_timer.h index 4182c347ef85..7d606e3364ae 100644 --- a/include/asm-i386/mach-default/do_timer.h +++ b/include/asm-i386/mach-default/do_timer.h @@ -14,11 +14,11 @@ * timer interrupt as a means of triggering reschedules etc. **/ -static inline void do_timer_interrupt_hook(struct pt_regs *regs) +static inline void do_timer_interrupt_hook(void) { do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode_vm(regs)); + update_process_times(user_mode_vm(get_irq_regs())); #endif /* * In the SMP case we use the local APIC timer interrupt to do the @@ -26,10 +26,10 @@ static inline void do_timer_interrupt_hook(struct pt_regs *regs) * system, in that case we have to call the local interrupt handler. */ #ifndef CONFIG_X86_LOCAL_APIC - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); #else if (!using_apic_timer) - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); #endif } diff --git a/include/asm-i386/mach-visws/do_timer.h b/include/asm-i386/mach-visws/do_timer.h index 8db618c5a72b..21cd696d4d0f 100644 --- a/include/asm-i386/mach-visws/do_timer.h +++ b/include/asm-i386/mach-visws/do_timer.h @@ -4,14 +4,14 @@ #include #include "cobalt.h" -static inline void do_timer_interrupt_hook(struct pt_regs *regs) +static inline void do_timer_interrupt_hook(void) { /* Clear the interrupt */ co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR); do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode_vm(regs)); + update_process_times(user_mode_vm(irq_regs)); #endif /* * In the SMP case we use the local APIC timer interrupt to do the @@ -19,10 +19,10 @@ static inline void do_timer_interrupt_hook(struct pt_regs *regs) * system, in that case we have to call the local interrupt handler. */ #ifndef CONFIG_X86_LOCAL_APIC - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); #else if (!using_apic_timer) - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); #endif } diff --git a/include/asm-i386/mach-voyager/do_timer.h b/include/asm-i386/mach-voyager/do_timer.h index 099fe9f5c1b2..04e69c104a74 100644 --- a/include/asm-i386/mach-voyager/do_timer.h +++ b/include/asm-i386/mach-voyager/do_timer.h @@ -1,14 +1,14 @@ /* defines for inline arch setup functions */ #include -static inline void do_timer_interrupt_hook(struct pt_regs *regs) +static inline void do_timer_interrupt_hook(void) { do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode_vm(regs)); + update_process_times(user_mode_vm(irq_regs)); #endif - voyager_timer_interrupt(regs); + voyager_timer_interrupt(); } static inline int do_timer_overflow(int count) diff --git a/include/asm-i386/voyager.h b/include/asm-i386/voyager.h index aaf432dd7673..e74c54aa757f 100644 --- a/include/asm-i386/voyager.h +++ b/include/asm-i386/voyager.h @@ -505,8 +505,8 @@ extern int voyager_memory_detect(int region, __u32 *addr, __u32 *length); extern void voyager_smp_intr_init(void); extern __u8 voyager_extended_cmos_read(__u16 cmos_address); extern void voyager_smp_dump(void); -extern void voyager_timer_interrupt(struct pt_regs *regs); -extern void smp_local_timer_interrupt(struct pt_regs * regs); +extern void voyager_timer_interrupt(void); +extern void smp_local_timer_interrupt(void); extern void voyager_power_off(void); extern void smp_voyager_power_off(void *dummy); extern void voyager_restart(void); diff --git a/include/asm-ia64/irq_regs.h b/include/asm-ia64/irq_regs.h new file mode 100644 index 000000000000..3dd9c0b70270 --- /dev/null +++ b/include/asm-ia64/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h index 90cba967df35..7ffbddf5306f 100644 --- a/include/asm-ia64/machvec.h +++ b/include/asm-ia64/machvec.h @@ -26,7 +26,7 @@ typedef void ia64_mv_setup_t (char **); typedef void ia64_mv_cpu_init_t (void); typedef void ia64_mv_irq_init_t (void); typedef void ia64_mv_send_ipi_t (int, int, int, int); -typedef void ia64_mv_timer_interrupt_t (int, void *, struct pt_regs *); +typedef void ia64_mv_timer_interrupt_t (int, void *); typedef void ia64_mv_global_tlb_purge_t (struct mm_struct *, unsigned long, unsigned long, unsigned long); typedef void ia64_mv_tlb_migrate_finish_t (struct mm_struct *); typedef unsigned int ia64_mv_local_vector_to_irq (u8); @@ -96,7 +96,7 @@ machvec_noop_task (struct task_struct *task) } extern void machvec_setup (char **); -extern void machvec_timer_interrupt (int, void *, struct pt_regs *); +extern void machvec_timer_interrupt (int, void *); extern void machvec_dma_sync_single (struct device *, dma_addr_t, size_t, int); extern void machvec_dma_sync_sg (struct device *, struct scatterlist *, int, int); extern void machvec_tlb_migrate_finish (struct mm_struct *); diff --git a/include/asm-mips/irq_regs.h b/include/asm-mips/irq_regs.h new file mode 100644 index 000000000000..3dd9c0b70270 --- /dev/null +++ b/include/asm-mips/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index 2d543735668b..30f21df39253 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h @@ -67,7 +67,7 @@ extern unsigned long (*do_gettimeoffset)(void); /* * high-level timer interrupt routines. */ -extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t timer_interrupt(int irq, void *dev_id); /* * the corresponding low-level timer interrupt routine. @@ -77,7 +77,7 @@ extern asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs); /* * profiling and process accouting is done separately in local_timer_interrupt */ -extern void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern void local_timer_interrupt(int irq, void *dev_id); extern asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs); /* diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h index 89ed545b446b..f960f5346f40 100644 --- a/include/asm-powerpc/irq.h +++ b/include/asm-powerpc/irq.h @@ -825,7 +825,7 @@ extern struct thread_info *softirq_ctx[NR_CPUS]; extern void irq_ctx_init(void); extern void call_do_softirq(struct thread_info *tp); -extern int call_handle_irq(int irq, void *p1, void *p2, +extern int call_handle_irq(int irq, void *p1, struct thread_info *tp, void *func); #else #define irq_ctx_init() diff --git a/include/asm-powerpc/irq_regs.h b/include/asm-powerpc/irq_regs.h new file mode 100644 index 000000000000..ba94b51a0a70 --- /dev/null +++ b/include/asm-powerpc/irq_regs.h @@ -0,0 +1,2 @@ +#include + diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h index 068f119aa298..20ea7c70bc38 100644 --- a/include/asm-powerpc/smp.h +++ b/include/asm-powerpc/smp.h @@ -34,8 +34,7 @@ extern void cpu_die(void); #ifdef CONFIG_SMP extern void smp_send_debugger_break(int cpu); -struct pt_regs; -extern void smp_message_recv(int, struct pt_regs *); +extern void smp_message_recv(int); #ifdef CONFIG_HOTPLUG_CPU extern void fixup_irqs(cpumask_t map); diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h index 9e66d32330c9..e81d0f289f0b 100644 --- a/include/asm-x86_64/apic.h +++ b/include/asm-x86_64/apic.h @@ -77,7 +77,7 @@ extern void sync_Arb_IDs (void); extern void init_bsp_APIC (void); extern void setup_local_APIC (void); extern void init_apic_mappings (void); -extern void smp_local_timer_interrupt (struct pt_regs * regs); +extern void smp_local_timer_interrupt (void); extern void setup_boot_APIC_clock (void); extern void setup_secondary_APIC_clock (void); extern int APIC_init_uniprocessor (void); diff --git a/include/asm-x86_64/floppy.h b/include/asm-x86_64/floppy.h index 32ff5d132714..6ea13c3806f3 100644 --- a/include/asm-x86_64/floppy.h +++ b/include/asm-x86_64/floppy.h @@ -51,7 +51,7 @@ static char *virtual_dma_addr; static int virtual_dma_mode; static int doing_pdma; -static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t floppy_hardint(int irq, void *dev_id) { register unsigned char st; @@ -63,7 +63,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) static int dma_wait=0; #endif if (!doing_pdma) - return floppy_interrupt(irq, dev_id, regs); + return floppy_interrupt(irq, dev_id); #ifdef TRACE_FLPY_INT if(!calls) @@ -106,7 +106,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) dma_wait=0; #endif doing_pdma = 0; - floppy_interrupt(irq, dev_id, regs); + floppy_interrupt(irq, dev_id); return IRQ_HANDLED; } #ifdef TRACE_FLPY_INT diff --git a/include/asm-x86_64/irq_regs.h b/include/asm-x86_64/irq_regs.h new file mode 100644 index 000000000000..3dd9c0b70270 --- /dev/null +++ b/include/asm-x86_64/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index c28fc2db2171..c181fef786e4 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -66,7 +66,7 @@ extern void free_bootmem_generic(unsigned long phys, unsigned len); extern void load_gs_index(unsigned gs); extern void stop_timer_interrupt(void); -extern void main_timer_handler(struct pt_regs *regs); +extern void main_timer_handler(void); extern unsigned long end_pfn_map; @@ -124,7 +124,7 @@ extern int notsc_setup(char *); extern int gsi_irq_sharing(int gsi); -extern void smp_local_timer_interrupt(struct pt_regs * regs); +extern void smp_local_timer_interrupt(void); long do_arch_prctl(struct task_struct *task, int code, unsigned long addr); diff --git a/include/linux/adb.h b/include/linux/adb.h index b7305b178279..64d8878e1444 100644 --- a/include/linux/adb.h +++ b/include/linux/adb.h @@ -90,10 +90,10 @@ extern struct blocking_notifier_head adb_client_list; int adb_request(struct adb_request *req, void (*done)(struct adb_request *), int flags, int nbytes, ...); int adb_register(int default_id,int handler_id,struct adb_ids *ids, - void (*handler)(unsigned char *, int, struct pt_regs *, int)); + void (*handler)(unsigned char *, int, int)); int adb_unregister(int index); void adb_poll(void); -void adb_input(unsigned char *, int, struct pt_regs *, int); +void adb_input(unsigned char *, int, int); int adb_reset_bus(void); int adb_try_handler_change(int address, int new_id); diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index 231ba090ae34..2f85049cfb3d 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -334,7 +334,7 @@ void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc); #endif void arcnet_unregister_proto(struct ArcProto *proto); -irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t arcnet_interrupt(int irq, void *dev_id); struct net_device *alloc_arcdev(char *name); #endif /* __KERNEL__ */ diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h index 945ba1ad14ac..acbdae6d7ae1 100644 --- a/include/linux/hiddev.h +++ b/include/linux/hiddev.h @@ -222,7 +222,7 @@ struct hid_report; int hiddev_connect(struct hid_device *); void hiddev_disconnect(struct hid_device *); void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value, struct pt_regs *regs); + struct hid_usage *usage, __s32 value); void hiddev_report_event(struct hid_device *hid, struct hid_report *report); int __init hiddev_init(void); void hiddev_exit(void); @@ -230,7 +230,7 @@ void hiddev_exit(void); static inline int hiddev_connect(struct hid_device *hid) { return -1; } static inline void hiddev_disconnect(struct hid_device *hid) { } static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value, struct pt_regs *regs) { } + struct hid_usage *usage, __s32 value) { } static inline void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { } static inline int hiddev_init(void) { return 0; } static inline void hiddev_exit(void) { } diff --git a/include/linux/ide.h b/include/linux/ide.h index 07d8d725541f..9c2050293f17 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1185,7 +1185,7 @@ extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout); extern int ide_spin_wait_hwgroup(ide_drive_t *); extern void ide_timer_expiry(unsigned long); -extern irqreturn_t ide_intr(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t ide_intr(int irq, void *dev_id); extern void do_ide_request(request_queue_t *); void ide_init_disk(struct gendisk *, ide_drive_t *); diff --git a/include/linux/input.h b/include/linux/input.h index 5770105471dd..c38507ba38b5 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -953,7 +953,6 @@ struct input_dev { unsigned int repeat_key; struct timer_list timer; - struct pt_regs *regs; int state; int sync; @@ -1149,15 +1148,9 @@ static inline void input_report_switch(struct input_dev *dev, unsigned int code, input_event(dev, EV_SW, code, !!value); } -static inline void input_regs(struct input_dev *dev, struct pt_regs *regs) -{ - dev->regs = regs; -} - static inline void input_sync(struct input_dev *dev) { input_event(dev, EV_SYN, SYN_REPORT, 0); - dev->regs = NULL; } static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 19782350dcc8..5b83e7b59621 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -64,7 +64,7 @@ #define SA_TRIGGER_RISING IRQF_TRIGGER_RISING #define SA_TRIGGER_MASK IRQF_TRIGGER_MASK -typedef irqreturn_t (*irq_handler_t)(int, void *, struct pt_regs *); +typedef irqreturn_t (*irq_handler_t)(int, void *); struct irqaction { irq_handler_t handler; @@ -77,7 +77,7 @@ struct irqaction { struct proc_dir_entry *dir; }; -extern irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs); +extern irqreturn_t no_action(int cpl, void *dev_id); extern int request_irq(unsigned int, irq_handler_t handler, unsigned long, const char *, void *); extern void free_irq(unsigned int, void *); diff --git a/include/linux/ioc3.h b/include/linux/ioc3.h index da7c09e4ede6..38b286e9a46c 100644 --- a/include/linux/ioc3.h +++ b/include/linux/ioc3.h @@ -63,7 +63,7 @@ struct ioc3_submodule { /* IRQ stuff */ unsigned int irq_mask; /* IOC3 IRQ mask, leave clear for Ethernet */ int reset_mask; /* non-zero if you want the ioc3.c module to reset interrupts */ - int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int, struct pt_regs *); + int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int); /* private submodule data */ void *data; /* assigned by submodule */ }; diff --git a/include/linux/irq.h b/include/linux/irq.h index b947d46e4b18..c64f3cc7e870 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -21,11 +21,11 @@ #include #include +#include struct irq_desc; typedef void fastcall (*irq_flow_handler_t)(unsigned int irq, - struct irq_desc *desc, - struct pt_regs *regs); + struct irq_desc *desc); /* @@ -258,28 +258,18 @@ static inline int select_smp_affinity(unsigned int irq) extern int no_irq_affinity; /* Handle irq action chains: */ -extern int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, - struct irqaction *action); +extern int handle_IRQ_event(unsigned int irq, struct irqaction *action); /* * Built-in IRQ handlers for various IRQ types, * callable via desc->chip->handle_irq() */ -extern void fastcall -handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs); -extern void fastcall -handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs); -extern void fastcall -handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs); -extern void fastcall -handle_simple_irq(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs); -extern void fastcall -handle_percpu_irq(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs); -extern void fastcall -handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs); +extern void fastcall handle_level_irq(unsigned int irq, struct irq_desc *desc); +extern void fastcall handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc); +extern void fastcall handle_edge_irq(unsigned int irq, struct irq_desc *desc); +extern void fastcall handle_simple_irq(unsigned int irq, struct irq_desc *desc); +extern void fastcall handle_percpu_irq(unsigned int irq, struct irq_desc *desc); +extern void fastcall handle_bad_irq(unsigned int irq, struct irq_desc *desc); /* * Get a descriptive string for the highlevel handler, for @@ -292,7 +282,7 @@ extern const char *handle_irq_name(irq_flow_handler_t handle); * (is an explicit fastcall, because i386 4KSTACKS calls it from assembly) */ #ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ -extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); +extern fastcall unsigned int __do_IRQ(unsigned int irq); #endif /* @@ -301,23 +291,23 @@ extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); * irqchip-style controller then we call the ->handle_irq() handler, * and it calls __do_IRQ() if it's attached to an irqtype-style controller. */ -static inline void generic_handle_irq(unsigned int irq, struct pt_regs *regs) +static inline void generic_handle_irq(unsigned int irq) { struct irq_desc *desc = irq_desc + irq; #ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ - desc->handle_irq(irq, desc, regs); + desc->handle_irq(irq, desc); #else if (likely(desc->handle_irq)) - desc->handle_irq(irq, desc, regs); + desc->handle_irq(irq, desc); else - __do_IRQ(irq, regs); + __do_IRQ(irq); #endif } /* Handling of unhandled and spurious interrupts: */ extern void note_interrupt(unsigned int irq, struct irq_desc *desc, - int action_ret, struct pt_regs *regs); + int action_ret); /* Resending of interrupts :*/ void check_irq_resend(struct irq_desc *desc, unsigned int irq); diff --git a/include/linux/libata.h b/include/linux/libata.h index d1af1dbeaeb4..d0a7ad5ed518 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -628,7 +628,7 @@ struct ata_port_operations { void (*error_handler) (struct ata_port *ap); void (*post_internal_cmd) (struct ata_queued_cmd *qc); - irqreturn_t (*irq_handler)(int, void *, struct pt_regs *); + irq_handler_t irq_handler; void (*irq_clear) (struct ata_port *); u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg); @@ -769,7 +769,7 @@ extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) extern int ata_port_start (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap); extern void ata_host_stop (struct ata_host *host); -extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +extern irqreturn_t ata_interrupt (int irq, void *dev_instance); extern void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data); extern void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, diff --git a/include/linux/parport.h b/include/linux/parport.h index 5bf321e82c99..80682aaa8f18 100644 --- a/include/linux/parport.h +++ b/include/linux/parport.h @@ -229,7 +229,7 @@ struct pardevice { int (*preempt)(void *); void (*wakeup)(void *); void *private; - void (*irq_func)(int, void *, struct pt_regs *); + void (*irq_func)(int, void *); unsigned int flags; struct pardevice *next; struct pardevice *prev; @@ -375,7 +375,7 @@ extern void parport_put_port (struct parport *); struct pardevice *parport_register_device(struct parport *port, const char *name, int (*pf)(void *), void (*kf)(void *), - void (*irq_func)(int, void *, struct pt_regs *), + void (*irq_func)(int, void *), int flags, void *handle); /* parport_unregister unlinks a device from the chain. */ @@ -457,7 +457,7 @@ static __inline__ int parport_yield_blocking(struct pardevice *dev) #define PARPORT_FLAG_EXCL (1<<1) /* EXCL driver registered. */ /* IEEE1284 functions */ -extern void parport_ieee1284_interrupt (int, void *, struct pt_regs *); +extern void parport_ieee1284_interrupt (int, void *); extern int parport_negotiate (struct parport *, int mode); extern ssize_t parport_write (struct parport *, const void *buf, size_t len); extern ssize_t parport_read (struct parport *, void *buf, size_t len); @@ -502,8 +502,7 @@ extern void parport_daisy_fini (struct parport *port); extern struct pardevice *parport_open (int devnum, const char *name, int (*pf) (void *), void (*kf) (void *), - void (*irqf) (int, void *, - struct pt_regs *), + void (*irqf) (int, void *), int flags, void *handle); extern void parport_close (struct pardevice *dev); extern ssize_t parport_device_id (int devnum, char *buffer, size_t len); @@ -512,13 +511,12 @@ extern void parport_daisy_deselect_all (struct parport *port); extern int parport_daisy_select (struct parport *port, int daisy, int mode); /* Lowlevel drivers _can_ call this support function to handle irqs. */ -static __inline__ void parport_generic_irq(int irq, struct parport *port, - struct pt_regs *regs) +static __inline__ void parport_generic_irq(int irq, struct parport *port) { - parport_ieee1284_interrupt (irq, port, regs); + parport_ieee1284_interrupt (irq, port); read_lock(&port->cad_lock); if (port->cad && port->cad->irq_func) - port->cad->irq_func(irq, port->cad->private, regs); + port->cad->irq_func(irq, port->cad->private); read_unlock(&port->cad_lock); } diff --git a/include/linux/profile.h b/include/linux/profile.h index e633004ae052..acce53fd38b6 100644 --- a/include/linux/profile.h +++ b/include/linux/profile.h @@ -17,7 +17,7 @@ struct notifier_block; /* init basic kernel profiler */ void __init profile_init(void); -void profile_tick(int, struct pt_regs *); +void profile_tick(int); void profile_hit(int, void *); #ifdef CONFIG_PROC_FS void create_prof_cpu_mask(struct proc_dir_entry *); diff --git a/include/linux/rtc.h b/include/linux/rtc.h index b89f09357054..09ff4c3e2713 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -208,7 +208,7 @@ int rtc_register(rtc_task_t *task); int rtc_unregister(rtc_task_t *task); int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg); void rtc_get_rtc_time(struct rtc_time *rtc_tm); -irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t rtc_interrupt(int irq, void *dev_id); #endif /* __KERNEL__ */ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index b661c19f3f72..463ab953b092 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -409,13 +409,12 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port); * The following are helper functions for the low level drivers. */ static inline int -uart_handle_sysrq_char(struct uart_port *port, unsigned int ch, - struct pt_regs *regs) +uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) { #ifdef SUPPORT_SYSRQ if (port->sysrq) { if (ch && time_before(jiffies, port->sysrq)) { - handle_sysrq(ch, regs, port->info->tty); + handle_sysrq(ch, port->info->tty); port->sysrq = 0; return 1; } @@ -425,7 +424,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch, return 0; } #ifndef SUPPORT_SYSRQ -#define uart_handle_sysrq_char(port,ch,regs) uart_handle_sysrq_char(port, 0, NULL) +#define uart_handle_sysrq_char(port,ch) uart_handle_sysrq_char(port, 0) #endif /* diff --git a/include/linux/serio.h b/include/linux/serio.h index c9069310b6ac..3a697cc6ecae 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -60,8 +60,7 @@ struct serio_driver { unsigned int manual_bind; void (*write_wakeup)(struct serio *); - irqreturn_t (*interrupt)(struct serio *, unsigned char, - unsigned int, struct pt_regs *); + irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int); int (*connect)(struct serio *, struct serio_driver *drv); int (*reconnect)(struct serio *); void (*disconnect)(struct serio *); @@ -75,7 +74,7 @@ int serio_open(struct serio *serio, struct serio_driver *drv); void serio_close(struct serio *serio); void serio_rescan(struct serio *serio); void serio_reconnect(struct serio *serio); -irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs); +irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags); void __serio_register_port(struct serio *serio, struct module *owner); static inline void serio_register_port(struct serio *serio) diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index e657e523b9bf..9df8833670cb 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h @@ -29,7 +29,7 @@ struct tty_struct; #define SYSRQ_ENABLE_RTNICE 0x0100 struct sysrq_key_op { - void (*handler)(int, struct pt_regs *, struct tty_struct *); + void (*handler)(int, struct tty_struct *); char *help_msg; char *action_msg; int enable_mask; @@ -42,8 +42,8 @@ struct sysrq_key_op { * are available -- else NULL's). */ -void handle_sysrq(int, struct pt_regs *, struct tty_struct *); -void __handle_sysrq(int, struct pt_regs *, struct tty_struct *, int check_mask); +void handle_sysrq(int, struct tty_struct *); +void __handle_sysrq(int, struct tty_struct *, int check_mask); int register_sysrq_key(int, struct sysrq_key_op *); int unregister_sysrq_key(int, struct sysrq_key_op *); struct sysrq_key_op *__sysrq_get_key_op(int key); diff --git a/include/linux/usb.h b/include/linux/usb.h index 190cc1b78fe2..5482bfb3303d 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -764,9 +764,8 @@ struct usb_iso_packet_descriptor { }; struct urb; -struct pt_regs; -typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); +typedef void (*usb_complete_t)(struct urb *); /** * struct urb - USB Request Block diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 91c983eef899..91b3ea2bbb14 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -226,10 +226,10 @@ struct usb_serial_driver { int (*tiocmget) (struct usb_serial_port *port, struct file *file); int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); - void (*read_int_callback)(struct urb *urb, struct pt_regs *regs); - void (*write_int_callback)(struct urb *urb, struct pt_regs *regs); - void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs); - void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs); + void (*read_int_callback)(struct urb *urb); + void (*write_int_callback)(struct urb *urb); + void (*read_bulk_callback)(struct urb *urb); + void (*write_bulk_callback)(struct urb *urb); }; #define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver) @@ -262,8 +262,8 @@ extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigne extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp); extern int usb_serial_generic_write_room (struct usb_serial_port *port); extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port); -extern void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs); -extern void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs); +extern void usb_serial_generic_read_bulk_callback (struct urb *urb); +extern void usb_serial_generic_write_bulk_callback (struct urb *urb); extern void usb_serial_generic_shutdown (struct usb_serial *serial); extern int usb_serial_generic_register (int debug); extern void usb_serial_generic_deregister (void); diff --git a/include/sound/cs4231.h b/include/sound/cs4231.h index 60b5b92a1319..ab51ce1ba9a5 100644 --- a/include/sound/cs4231.h +++ b/include/sound/cs4231.h @@ -273,7 +273,7 @@ unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg); void snd_cs4231_mce_up(struct snd_cs4231 *chip); void snd_cs4231_mce_down(struct snd_cs4231 *chip); -irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id); const char *snd_cs4231_chip_id(struct snd_cs4231 *chip); diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 892e310c504d..3d3c1514cf71 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1194,7 +1194,7 @@ int snd_emu10k1_mixer(struct snd_emu10k1 * emu, int pcm_device, int multi_device int snd_emu10k1_timer(struct snd_emu10k1 * emu, int device); int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep); -irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id); void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int voice); int snd_emu10k1_init_efx(struct snd_emu10k1 *emu); diff --git a/include/sound/gus.h b/include/sound/gus.h index 68a664ab97f3..c49ea57db8cc 100644 --- a/include/sound/gus.h +++ b/include/sound/gus.h @@ -638,7 +638,7 @@ int snd_gus_initialize(struct snd_gus_card * gus); /* gus_irq.c */ -irqreturn_t snd_gus_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t snd_gus_interrupt(int irq, void *dev_id); #ifdef CONFIG_SND_DEBUG void snd_gus_irq_profile_init(struct snd_gus_card *gus); #endif diff --git a/include/sound/initval.h b/include/sound/initval.h index 2ae76efc696f..e85b90750a59 100644 --- a/include/sound/initval.h +++ b/include/sound/initval.h @@ -53,7 +53,7 @@ #ifdef SNDRV_LEGACY_FIND_FREE_IRQ #include -static irqreturn_t snd_legacy_empty_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_legacy_empty_irq_handler(int irq, void *dev_id) { return IRQ_HANDLED; } diff --git a/include/sound/mpu401.h b/include/sound/mpu401.h index ac504321ea56..8c88267e9bea 100644 --- a/include/sound/mpu401.h +++ b/include/sound/mpu401.h @@ -106,10 +106,8 @@ struct snd_mpu401 { */ -irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, - struct pt_regs *regs); -irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id, - struct pt_regs *regs); +irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id); +irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id); int snd_mpu401_uart_new(struct snd_card *card, int device, diff --git a/include/sound/sb.h b/include/sound/sb.h index 431d06675e36..2dd5c8e5b4fe 100644 --- a/include/sound/sb.h +++ b/include/sound/sb.h @@ -100,7 +100,7 @@ struct snd_sb { struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *midi_substream_input; struct snd_rawmidi_substream *midi_substream_output; - irqreturn_t (*rmidi_callback)(int irq, void *dev_id, struct pt_regs *regs); + irq_handler_t rmidi_callback; spinlock_t reg_lock; spinlock_t open_lock; @@ -286,7 +286,7 @@ int snd_sbdsp_reset(struct snd_sb *chip); int snd_sbdsp_create(struct snd_card *card, unsigned long port, int irq, - irqreturn_t (*irq_handler)(int, void *, struct pt_regs *), + irq_handler_t irq_handler, int dma8, int dma16, unsigned short hardware, struct snd_sb **r_chip); @@ -316,7 +316,7 @@ int snd_sb16dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm); const struct snd_pcm_ops *snd_sb16dsp_get_pcm_ops(int direction); int snd_sb16dsp_configure(struct snd_sb *chip); /* sb16.c */ -irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id); /* exported mixer stuffs */ enum { diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h index dbca14170615..217394652090 100644 --- a/include/sound/vx_core.h +++ b/include/sound/vx_core.h @@ -228,7 +228,7 @@ void snd_vx_free_firmware(struct vx_core *chip); /* * interrupt handler; exported for pcmcia */ -irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs); +irqreturn_t snd_vx_irq_handler(int irq, void *dev); /* * lowlevel functions diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 53e9dce6c657..11c99697acfe 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -249,7 +249,6 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) * handle_simple_irq - Simple and software-decoded IRQs. * @irq: the interrupt number * @desc: the interrupt description structure for this irq - * @regs: pointer to a register structure * * Simple interrupts are either sent from a demultiplexing interrupt * handler or come from hardware, where no interrupt hardware control @@ -259,7 +258,7 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) * unmask issues if necessary. */ void fastcall -handle_simple_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) +handle_simple_irq(unsigned int irq, struct irq_desc *desc) { struct irqaction *action; irqreturn_t action_ret; @@ -279,9 +278,9 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) desc->status |= IRQ_INPROGRESS; spin_unlock(&desc->lock); - action_ret = handle_IRQ_event(irq, regs, action); + action_ret = handle_IRQ_event(irq, action); if (!noirqdebug) - note_interrupt(irq, desc, action_ret, regs); + note_interrupt(irq, desc, action_ret); spin_lock(&desc->lock); desc->status &= ~IRQ_INPROGRESS; @@ -293,7 +292,6 @@ out_unlock: * handle_level_irq - Level type irq handler * @irq: the interrupt number * @desc: the interrupt description structure for this irq - * @regs: pointer to a register structure * * Level type interrupts are active as long as the hardware line has * the active level. This may require to mask the interrupt and unmask @@ -301,7 +299,7 @@ out_unlock: * interrupt line is back to inactive. */ void fastcall -handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) +handle_level_irq(unsigned int irq, struct irq_desc *desc) { unsigned int cpu = smp_processor_id(); struct irqaction *action; @@ -329,9 +327,9 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) desc->status &= ~IRQ_PENDING; spin_unlock(&desc->lock); - action_ret = handle_IRQ_event(irq, regs, action); + action_ret = handle_IRQ_event(irq, action); if (!noirqdebug) - note_interrupt(irq, desc, action_ret, regs); + note_interrupt(irq, desc, action_ret); spin_lock(&desc->lock); desc->status &= ~IRQ_INPROGRESS; @@ -345,7 +343,6 @@ out_unlock: * handle_fasteoi_irq - irq handler for transparent controllers * @irq: the interrupt number * @desc: the interrupt description structure for this irq - * @regs: pointer to a register structure * * Only a single callback will be issued to the chip: an ->eoi() * call when the interrupt has been serviced. This enables support @@ -353,8 +350,7 @@ out_unlock: * details in hardware, transparently. */ void fastcall -handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) { unsigned int cpu = smp_processor_id(); struct irqaction *action; @@ -382,9 +378,9 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc, desc->status &= ~IRQ_PENDING; spin_unlock(&desc->lock); - action_ret = handle_IRQ_event(irq, regs, action); + action_ret = handle_IRQ_event(irq, action); if (!noirqdebug) - note_interrupt(irq, desc, action_ret, regs); + note_interrupt(irq, desc, action_ret); spin_lock(&desc->lock); desc->status &= ~IRQ_INPROGRESS; @@ -398,7 +394,6 @@ out: * handle_edge_irq - edge type IRQ handler * @irq: the interrupt number * @desc: the interrupt description structure for this irq - * @regs: pointer to a register structure * * Interrupt occures on the falling and/or rising edge of a hardware * signal. The occurence is latched into the irq controller hardware @@ -412,7 +407,7 @@ out: * loop is left. */ void fastcall -handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) +handle_edge_irq(unsigned int irq, struct irq_desc *desc) { const unsigned int cpu = smp_processor_id(); @@ -463,9 +458,9 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) desc->status &= ~IRQ_PENDING; spin_unlock(&desc->lock); - action_ret = handle_IRQ_event(irq, regs, action); + action_ret = handle_IRQ_event(irq, action); if (!noirqdebug) - note_interrupt(irq, desc, action_ret, regs); + note_interrupt(irq, desc, action_ret); spin_lock(&desc->lock); } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING); @@ -480,12 +475,11 @@ out_unlock: * handle_percpu_IRQ - Per CPU local irq handler * @irq: the interrupt number * @desc: the interrupt description structure for this irq - * @regs: pointer to a register structure * * Per CPU interrupts on SMP machines without locking requirements */ void fastcall -handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) +handle_percpu_irq(unsigned int irq, struct irq_desc *desc) { irqreturn_t action_ret; @@ -494,9 +488,9 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) if (desc->chip->ack) desc->chip->ack(irq); - action_ret = handle_IRQ_event(irq, regs, desc->action); + action_ret = handle_IRQ_event(irq, desc->action); if (!noirqdebug) - note_interrupt(irq, desc, action_ret, regs); + note_interrupt(irq, desc, action_ret); if (desc->chip->eoi) desc->chip->eoi(irq); diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 4c6cdbaed661..42aa6f1a3f0f 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -27,7 +27,7 @@ * Handles spurious and unhandled IRQ's. It also prints a debugmessage. */ void fastcall -handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) +handle_bad_irq(unsigned int irq, struct irq_desc *desc) { print_irq_desc(irq, desc); kstat_this_cpu.irqs[irq]++; @@ -115,7 +115,7 @@ struct irq_chip dummy_irq_chip = { /* * Special, empty irq handler: */ -irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) +irqreturn_t no_action(int cpl, void *dev_id) { return IRQ_NONE; } @@ -123,13 +123,11 @@ irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) /** * handle_IRQ_event - irq action chain handler * @irq: the interrupt number - * @regs: pointer to a register structure * @action: the interrupt action chain for this irq * * Handles the action chain of an irq event */ -irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs, - struct irqaction *action) +irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) { irqreturn_t ret, retval = IRQ_NONE; unsigned int status = 0; @@ -140,7 +138,7 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs, local_irq_enable_in_hardirq(); do { - ret = action->handler(irq, action->dev_id, regs); + ret = action->handler(irq, action->dev_id); if (ret == IRQ_HANDLED) status |= action->flags; retval |= ret; @@ -158,7 +156,6 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs, /** * __do_IRQ - original all in one highlevel IRQ handler * @irq: the interrupt number - * @regs: pointer to a register structure * * __do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific @@ -167,7 +164,7 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs, * This is the original x86 implementation which is used for every * interrupt type. */ -fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) +fastcall unsigned int __do_IRQ(unsigned int irq) { struct irq_desc *desc = irq_desc + irq; struct irqaction *action; @@ -182,7 +179,7 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) */ if (desc->chip->ack) desc->chip->ack(irq); - action_ret = handle_IRQ_event(irq, regs, desc->action); + action_ret = handle_IRQ_event(irq, desc->action); desc->chip->end(irq); return 1; } @@ -233,11 +230,11 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) spin_unlock(&desc->lock); - action_ret = handle_IRQ_event(irq, regs, action); + action_ret = handle_IRQ_event(irq, action); spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret, regs); + note_interrupt(irq, desc, action_ret); if (likely(!(desc->status & IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index 417e98092cf2..543ea2e5ad93 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -16,7 +16,7 @@ static int irqfixup __read_mostly; /* * Recovery handler for misrouted interrupts. */ -static int misrouted_irq(int irq, struct pt_regs *regs) +static int misrouted_irq(int irq) { int i; int ok = 0; @@ -49,7 +49,7 @@ static int misrouted_irq(int irq, struct pt_regs *regs) while (action) { /* Only shared IRQ handlers are safe to call */ if (action->flags & IRQF_SHARED) { - if (action->handler(i, action->dev_id, regs) == + if (action->handler(i, action->dev_id) == IRQ_HANDLED) ok = 1; } @@ -70,7 +70,7 @@ static int misrouted_irq(int irq, struct pt_regs *regs) */ work = 1; spin_unlock(&desc->lock); - handle_IRQ_event(i, regs, action); + handle_IRQ_event(i, action); spin_lock(&desc->lock); desc->status &= ~IRQ_PENDING; } @@ -136,7 +136,7 @@ report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret) } void note_interrupt(unsigned int irq, struct irq_desc *desc, - irqreturn_t action_ret, struct pt_regs *regs) + irqreturn_t action_ret) { if (unlikely(action_ret != IRQ_HANDLED)) { desc->irqs_unhandled++; @@ -147,7 +147,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, if (unlikely(irqfixup)) { /* Don't punish working computers */ if ((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) { - int ok = misrouted_irq(irq, regs); + int ok = misrouted_irq(irq); if (action_ret == IRQ_NONE) desc->irqs_unhandled -= ok; } diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c index 7a4144ba3afd..f1f900ac3164 100644 --- a/kernel/power/poweroff.c +++ b/kernel/power/poweroff.c @@ -23,8 +23,7 @@ static void do_poweroff(void *dummy) static DECLARE_WORK(poweroff_work, do_poweroff, NULL); -static void handle_poweroff(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void handle_poweroff(int key, struct tty_struct *tty) { schedule_work(&poweroff_work); } diff --git a/kernel/profile.c b/kernel/profile.c index fb660c7d35ba..857300a2afec 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -25,6 +25,7 @@ #include #include #include +#include struct profile_hit { u32 pc, hits; @@ -366,8 +367,10 @@ void profile_hit(int type, void *__pc) } #endif /* !CONFIG_SMP */ -void profile_tick(int type, struct pt_regs *regs) +void profile_tick(int type) { + struct pt_regs *regs = get_irq_regs(); + if (type == CPU_PROFILING && timer_hook) timer_hook(regs); if (!user_mode(regs) && cpu_isset(smp_processor_id(), prof_cpu_mask)) diff --git a/lib/Makefile b/lib/Makefile index b0361756e22e..8e6662bb9c37 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,7 +5,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \ - sha1.o + sha1.o irq_regs.o lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o diff --git a/lib/irq_regs.c b/lib/irq_regs.c new file mode 100644 index 000000000000..101b1a4f9b14 --- /dev/null +++ b/lib/irq_regs.c @@ -0,0 +1,15 @@ +/* saved per-CPU IRQ register pointer + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include + +#ifndef ARCH_HAS_OWN_IRQ_REGS +DEFINE_PER_CPU(struct pt_regs *, __irq_regs); +#endif diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c index 7c26089527f6..40eb47eccf9a 100644 --- a/sound/aoa/core/snd-aoa-gpio-feature.c +++ b/sound/aoa/core/snd-aoa-gpio-feature.c @@ -283,9 +283,7 @@ static void ftr_gpio_exit(struct gpio_runtime *rt) mutex_destroy(&rt->line_out_notify.mutex); } -static irqreturn_t ftr_handle_notify_irq(int xx, - void *data, - struct pt_regs *regs) +static irqreturn_t ftr_handle_notify_irq(int xx, void *data) { struct gpio_notification *notif = data; diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c index 23190aa6bc7b..e593a1333fe3 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c @@ -93,7 +93,7 @@ static void i2sbus_release_dev(struct device *dev) kfree(i2sdev); } -static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t i2sbus_bus_intr(int irq, void *devid) { struct i2sbus_dev *dev = devid; u32 intreg; @@ -165,8 +165,7 @@ static int i2sbus_add_dev(struct macio_dev *macio, static const char *rnames[] = { "i2sbus: %s (control)", "i2sbus: %s (tx)", "i2sbus: %s (rx)" }; - static irqreturn_t (*ints[])(int irq, void *devid, - struct pt_regs *regs) = { + static irq_handler_t ints[] = { i2sbus_bus_intr, i2sbus_tx_intr, i2sbus_rx_intr diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c index 3049015a04f1..5eff30b10201 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c @@ -642,13 +642,13 @@ static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) spin_unlock(&i2sdev->low_lock); } -irqreturn_t i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs) +irqreturn_t i2sbus_tx_intr(int irq, void *devid) { handle_interrupt((struct i2sbus_dev *)devid, 0); return IRQ_HANDLED; } -irqreturn_t i2sbus_rx_intr(int irq, void *devid, struct pt_regs * regs) +irqreturn_t i2sbus_rx_intr(int irq, void *devid) { handle_interrupt((struct i2sbus_dev *)devid, 1); return IRQ_HANDLED; diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h index 0c69d209be50..ec20ee615d7f 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus.h +++ b/sound/aoa/soundbus/i2sbus/i2sbus.h @@ -97,9 +97,9 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, extern void i2sbus_detach_codec(struct soundbus_dev *dev, void *data); extern irqreturn_t -i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs); +i2sbus_tx_intr(int irq, void *devid); extern irqreturn_t -i2sbus_rx_intr(int irq, void *devid, struct pt_regs *regs); +i2sbus_rx_intr(int irq, void *devid); /* control specific functions */ extern int i2sbus_control_init(struct macio_dev* dev, diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 8435fdd1c87c..53675cf4de44 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -221,7 +221,7 @@ static void aaci_fifo_irq(struct aaci *aaci, u32 mask) } } -static irqreturn_t aaci_irq(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t aaci_irq(int irq, void *devid) { struct aaci *aaci = devid; u32 mask; diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 599aff8290e8..dede954b2c65 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -152,7 +152,7 @@ static void pxa2xx_ac97_reset(struct snd_ac97 *ac97) GCR |= GCR_SDONE_IE|GCR_CDONE_IE; } -static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) { long status; diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c index 4938ef10b813..e8cf904b8358 100644 --- a/sound/arm/pxa2xx-pcm.c +++ b/sound/arm/pxa2xx-pcm.c @@ -137,7 +137,7 @@ static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id, struct pt_regs *regs) +static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) { struct snd_pcm_substream *substream = dev_id; struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 4bf07ca9b17d..3daa9fa56c0b 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -125,12 +125,10 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler * @irq: the irq number * @dev_id: mpu401 instance - * @regs: the reigster * * Processes the interrupt for MPU401-UART i/o. */ -irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id) { struct snd_mpu401 *mpu = dev_id; @@ -146,12 +144,10 @@ EXPORT_SYMBOL(snd_mpu401_uart_interrupt); * snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler * @irq: the irq number * @dev_id: mpu401 instance - * @regs: the reigster * * Processes the interrupt for MPU401-UART output. */ -irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id, - struct pt_regs *regs) +irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id) { struct snd_mpu401 *mpu = dev_id; diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index e064d6c5685b..a9ff391258e7 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -570,7 +570,7 @@ static void snd_mtpav_read_bytes(struct mtpav *mcrd) } while (sbyt & SIGS_BYTE); } -static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id) { struct mtpav *mcard = dev_id; diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index ab8d4effcf9e..5327c6f841f4 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -838,7 +838,7 @@ static int __devinit snd_mts64_rawmidi_create(struct snd_card *card) /********************************************************************* * parport stuff *********************************************************************/ -static void snd_mts64_interrupt(int irq, void *private, struct pt_regs *r) +static void snd_mts64_interrupt(int irq, void *private) { struct mts64 *mts = ((struct snd_card*)private)->private_data; u16 ret; diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 52afb4bd2079..74028b2219c2 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -292,7 +292,7 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) * Note that some devices need OUT2 to be set before they will generate * interrupts at all. (Possibly tied to an internal pull-up on CTS?) */ -static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id) { snd_uart16550_t *uart; diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index a60168268ddd..ed19bc17400b 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -537,7 +537,7 @@ static void vx_interrupt(unsigned long private_data) /** * snd_vx_irq_handler - interrupt handler */ -irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs) +irqreturn_t snd_vx_irq_handler(int irq, void *dev) { struct vx_core *chip = dev; diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index fd9b61eda0f3..b524e0d9ee44 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -315,7 +315,7 @@ static snd_pcm_uframes_t snd_ad1816a_capture_pointer(struct snd_pcm_substream *s } -static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id) { struct snd_ad1816a *chip = dev_id; unsigned char status; diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index a6fbd5d1d62f..666b3bcc19f0 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c @@ -583,7 +583,7 @@ static int snd_ad1848_capture_prepare(struct snd_pcm_substream *substream) return 0; } -static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id) { struct snd_ad1848 *chip = dev_id; diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index fbb20176cca4..75c7c5f01989 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c @@ -920,7 +920,7 @@ static void snd_cs4231_overrange(struct snd_cs4231 *chip) chip->capture_substream->runtime->overrange++; } -irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id) { struct snd_cs4231 *chip = dev_id; unsigned char status; diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 7e985d3bc510..a2ab99f2ac35 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -479,7 +479,7 @@ static int snd_es1688_capture_trigger(struct snd_pcm_substream *substream, return snd_es1688_trigger(chip, cmd, 0x0f); } -static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id) { struct snd_es1688 *chip = dev_id; diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 85818200333f..2398d2c55feb 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -754,7 +754,7 @@ static int snd_es18xx_playback_trigger(struct snd_pcm_substream *substream, return snd_es18xx_playback2_trigger(chip, substream, cmd); } -static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) { struct snd_es18xx *chip = dev_id; unsigned char status; @@ -799,7 +799,7 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *r /* MPU */ if ((status & MPU_IRQ) && chip->rmidi) - snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); /* Hardware volume */ if (status & HWV_IRQ) { diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c index 42db37552efb..537d3cfe41f3 100644 --- a/sound/isa/gus/gus_irq.c +++ b/sound/isa/gus/gus_irq.c @@ -30,7 +30,7 @@ #define STAT_ADD(x) while (0) { ; } #endif -irqreturn_t snd_gus_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t snd_gus_interrupt(int irq, void *dev_id) { struct snd_gus_card * gus = dev_id; unsigned char status; diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index ac11cae8589a..52498c9d411e 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -105,7 +105,7 @@ static int __init snd_gusmax_detect(struct snd_gus_card * gus) return 0; } -static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id) { struct snd_gusmax *maxcard = (struct snd_gusmax *) dev_id; int loop, max = 5; @@ -115,12 +115,12 @@ static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id, struct pt_regs *r loop = 0; if (inb(maxcard->gus_status_reg)) { handled = 1; - snd_gus_interrupt(irq, maxcard->gus, regs); + snd_gus_interrupt(irq, maxcard->gus); loop++; } if (inb(maxcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */ handled = 1; - snd_cs4231_interrupt(irq, maxcard->cs4231, regs); + snd_cs4231_interrupt(irq, maxcard->cs4231); loop++; } } while (loop && --max > 0); diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index ea69f25506fb..5c474b831edc 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -299,7 +299,7 @@ static int __devinit snd_interwave_detect(struct snd_interwave *iwcard, return -ENODEV; } -static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id) { struct snd_interwave *iwcard = (struct snd_interwave *) dev_id; int loop, max = 5; @@ -309,12 +309,12 @@ static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id, struct pt_regs loop = 0; if (inb(iwcard->gus_status_reg)) { handled = 1; - snd_gus_interrupt(irq, iwcard->gus, regs); + snd_gus_interrupt(irq, iwcard->gus); loop++; } if (inb(iwcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */ handled = 1; - snd_cs4231_interrupt(irq, iwcard->cs4231, regs); + snd_cs4231_interrupt(irq, iwcard->cs4231); loop++; } } while (loop && --max > 0); diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index da92bf6c392b..419b4ebbf00e 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -294,7 +294,7 @@ static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip) return 0; } -static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id) { unsigned short status; struct snd_opl3sa2 *chip = dev_id; @@ -312,12 +312,12 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs * if ((status & 0x10) && chip->rmidi != NULL) { handled = 1; - snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); } if (status & 0x07) { /* TI,CI,PI */ handled = 1; - snd_cs4231_interrupt(irq, chip->cs4231, regs); + snd_cs4231_interrupt(irq, chip->cs4231); } if (status & 0x40) { /* hardware volume change */ diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 9d528ae00bff..a1ad39a8cdce 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -1090,7 +1090,7 @@ static void snd_opti93x_overrange(struct snd_opti93x *chip) spin_unlock_irqrestore(&chip->lock, flags); } -static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) { struct snd_opti93x *codec = dev_id; unsigned char status; diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c index d4d65b84265a..d4b218726ce7 100644 --- a/sound/isa/sb/es968.c +++ b/sound/isa/sb/es968.c @@ -70,8 +70,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_es968_pnpids); #define DRIVER_NAME "snd-card-es968" -static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id) { struct snd_sb *chip = dev_id; diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index f183f1845a36..383911b9e74d 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -395,7 +395,7 @@ static int snd_sb16_capture_trigger(struct snd_pcm_substream *substream, return result; } -irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id) { struct snd_sb *chip = dev_id; unsigned char status; @@ -405,7 +405,7 @@ irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs) status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS); spin_unlock(&chip->mixer_lock); if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback) - chip->rmidi_callback(irq, chip->rmidi->private_data, regs); + chip->rmidi_callback(irq, chip->rmidi->private_data); if (status & SB_IRQTYPE_8BIT) { ok = 0; if (chip->mode & SB_MODE_PLAYBACK_8) { diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 141400c01426..268ebd34703e 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -63,7 +63,7 @@ struct snd_sb8 { struct snd_sb *chip; }; -static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id) { struct snd_sb *chip = dev_id; diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index f17de2bdd9e0..c62a9e3d2ae4 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -205,7 +205,7 @@ static int snd_sbdsp_dev_free(struct snd_device *device) int snd_sbdsp_create(struct snd_card *card, unsigned long port, int irq, - irqreturn_t (*irq_handler)(int, void *, struct pt_regs *), + irq_handler_t irq_handler, int dma8, int dma16, unsigned short hardware, diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c index 8742fa517491..4fcd0f4e868c 100644 --- a/sound/isa/sgalaxy.c +++ b/sound/isa/sgalaxy.c @@ -109,7 +109,7 @@ static int __init snd_sgalaxy_sbdsp_command(unsigned long port, unsigned char va return 0; } -static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id) { return IRQ_NONE; } diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index a8f8d2fa9d76..85db535aea9b 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -263,9 +263,7 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c #endif /* CONFIG_PNP */ -static irqreturn_t snd_wavefront_ics2115_interrupt(int irq, - void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_wavefront_ics2115_interrupt(int irq, void *dev_id) { snd_wavefront_card_t *acard; diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c index ff6e6fc198a1..8a61a1191861 100644 --- a/sound/mips/au1x00.c +++ b/sound/mips/au1x00.c @@ -220,7 +220,7 @@ au1000_dma_start(struct audio_stream *stream) } static irqreturn_t -au1000_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +au1000_dma_interrupt(int irq, void *dev_id) { struct audio_stream *stream = (struct audio_stream *) dev_id; struct snd_pcm_substream *substream = stream->substream; diff --git a/sound/oss/ad1816.c b/sound/oss/ad1816.c index 29057836c644..caabf31193f7 100644 --- a/sound/oss/ad1816.c +++ b/sound/oss/ad1816.c @@ -521,7 +521,7 @@ static struct audio_driver ad1816_audio_driver = /* Interrupt handler */ -static irqreturn_t ad1816_interrupt (int irq, void *dev_id, struct pt_regs *dummy) +static irqreturn_t ad1816_interrupt (int irq, void *dev_id) { unsigned char status; ad1816_info *devc = (ad1816_info *)dev_id; diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c index 257b7536fb18..0ffa9970bf0f 100644 --- a/sound/oss/ad1848.c +++ b/sound/oss/ad1848.c @@ -195,7 +195,7 @@ static void ad1848_halt(int dev); static void ad1848_halt_input(int dev); static void ad1848_halt_output(int dev); static void ad1848_trigger(int dev, int bits); -static irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy); +static irqreturn_t adintr(int irq, void *dev_id); #ifndef EXCLUDE_TIMERS static int ad1848_tmr_install(int dev); @@ -2196,7 +2196,7 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base); } -static irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy) +static irqreturn_t adintr(int irq, void *dev_id) { unsigned char status; ad1848_info *devc; diff --git a/sound/oss/ad1889.c b/sound/oss/ad1889.c index f56f870b4840..09263d72a519 100644 --- a/sound/oss/ad1889.c +++ b/sound/oss/ad1889.c @@ -929,7 +929,7 @@ static struct pci_device_id ad1889_id_tbl[] = { }; MODULE_DEVICE_TABLE(pci, ad1889_id_tbl); -static irqreturn_t ad1889_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t ad1889_interrupt(int irq, void *dev_id) { u32 stat; ad1889_dev_t *dev = (ad1889_dev_t *)dev_id; diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c index 324a81fd3a3b..6ad384114239 100644 --- a/sound/oss/btaudio.c +++ b/sound/oss/btaudio.c @@ -824,7 +824,7 @@ static char *irq_name[] = { "", "", "", "OFLOW", "", "", "", "", "", "", "", "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR", "RIPERR", "PABORT", "OCERR", "SCERR" }; -static irqreturn_t btaudio_irq(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t btaudio_irq(int irq, void *dev_id) { int count = 0; u32 stat,astat; diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c index 43193581f836..6e3c41f530e6 100644 --- a/sound/oss/cs46xx.c +++ b/sound/oss/cs46xx.c @@ -1613,7 +1613,7 @@ static void cs_handle_midi(struct cs_card *card) wake_up(&card->midi.owait); } -static irqreturn_t cs_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cs_interrupt(int irq, void *dev_id) { struct cs_card *card = (struct cs_card *)dev_id; /* Single channel card */ diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c index dc31373069a5..285239d64b82 100644 --- a/sound/oss/dmasound/dmasound_atari.c +++ b/sound/oss/dmasound/dmasound_atari.c @@ -133,7 +133,7 @@ static int FalconSetFormat(int format); static int FalconSetVolume(int volume); static void AtaPlayNextFrame(int index); static void AtaPlay(void); -static irqreturn_t AtaInterrupt(int irq, void *dummy, struct pt_regs *fp); +static irqreturn_t AtaInterrupt(int irq, void *dummy); /*** Mid level stuff *********************************************************/ @@ -1257,7 +1257,7 @@ static void AtaPlay(void) } -static irqreturn_t AtaInterrupt(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t AtaInterrupt(int irq, void *dummy) { #if 0 /* ++TeSche: if you should want to test this... */ diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index 9ae659f82430..3bd19c36fcd9 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c @@ -281,9 +281,9 @@ static int PMacSetFormat(int format); static int PMacSetVolume(int volume); static void PMacPlay(void); static void PMacRecord(void); -static irqreturn_t pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs); -static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs); -static irqreturn_t pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs); +static irqreturn_t pmac_awacs_tx_intr(int irq, void *devid); +static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid); +static irqreturn_t pmac_awacs_intr(int irq, void *devid); static void awacs_write(int val); static int awacs_get_volume(int reg, int lshift); static int awacs_volume_setter(int volume, int n, int mute, int lshift); @@ -398,7 +398,7 @@ read_audio_gpio(int gpio_addr) * Headphone interrupt via GPIO (Tumbler, Snapper, DACA) */ static irqreturn_t -headphone_intr(int irq, void *devid, struct pt_regs *regs) +headphone_intr(int irq, void *devid) { unsigned long flags; @@ -1037,7 +1037,7 @@ static void PMacRecord(void) */ static irqreturn_t -pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs) +pmac_awacs_tx_intr(int irq, void *devid) { int i = write_sq.front; int stat; @@ -1129,7 +1129,7 @@ printk("dmasound_pmac: tx-irq: xfer died - patching it up...\n") ; static irqreturn_t -pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs) +pmac_awacs_rx_intr(int irq, void *devid) { int stat ; /* For some reason on my PowerBook G3, I get one interrupt @@ -1212,7 +1212,7 @@ printk("dmasound_pmac: rx-irq: DIED - attempting resurection\n"); static irqreturn_t -pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs) +pmac_awacs_intr(int irq, void *devid) { int ctrl; int status; diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c index 68e1d8f6c359..90fc058e1159 100644 --- a/sound/oss/dmasound/dmasound_paula.c +++ b/sound/oss/dmasound/dmasound_paula.c @@ -82,7 +82,7 @@ static int AmiSetVolume(int volume); static int AmiSetTreble(int treble); static void AmiPlayNextFrame(int index); static void AmiPlay(void); -static irqreturn_t AmiInterrupt(int irq, void *dummy, struct pt_regs *fp); +static irqreturn_t AmiInterrupt(int irq, void *dummy); #ifdef CONFIG_HEARTBEAT @@ -556,7 +556,7 @@ static void AmiPlay(void) } -static irqreturn_t AmiInterrupt(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t AmiInterrupt(int irq, void *dummy) { int minframes = 1; diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c index e2081f32b0c4..b3379dd7ca5e 100644 --- a/sound/oss/dmasound/dmasound_q40.c +++ b/sound/oss/dmasound/dmasound_q40.c @@ -48,8 +48,8 @@ static int Q40SetFormat(int format); static int Q40SetVolume(int volume); static void Q40PlayNextFrame(int index); static void Q40Play(void); -static irqreturn_t Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp); -static irqreturn_t Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp); +static irqreturn_t Q40StereoInterrupt(int irq, void *dummy); +static irqreturn_t Q40MonoInterrupt(int irq, void *dummy); static void Q40Interrupt(void); @@ -451,7 +451,7 @@ static void Q40Play(void) spin_unlock_irqrestore(&dmasound.lock, flags); } -static irqreturn_t Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t Q40StereoInterrupt(int irq, void *dummy) { spin_lock(&dmasound.lock); if (q40_sc>1){ @@ -463,7 +463,7 @@ static irqreturn_t Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp) spin_unlock(&dmasound.lock); return IRQ_HANDLED; } -static irqreturn_t Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t Q40MonoInterrupt(int irq, void *dummy) { spin_lock(&dmasound.lock); if (q40_sc>0){ diff --git a/sound/oss/emu10k1/irqmgr.c b/sound/oss/emu10k1/irqmgr.c index d19b464ba01b..fb2ce638f01c 100644 --- a/sound/oss/emu10k1/irqmgr.c +++ b/sound/oss/emu10k1/irqmgr.c @@ -37,7 +37,7 @@ /* Interrupt handler */ -irqreturn_t emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t emu10k1_interrupt(int irq, void *dev_id) { struct emu10k1_card *card = (struct emu10k1_card *) dev_id; u32 irqstatus, irqstatus_tmp; diff --git a/sound/oss/emu10k1/main.c b/sound/oss/emu10k1/main.c index c4ce94d6e10c..6c59df7b0001 100644 --- a/sound/oss/emu10k1/main.c +++ b/sound/oss/emu10k1/main.c @@ -167,7 +167,7 @@ extern struct file_operations emu10k1_midi_fops; static struct midi_operations emu10k1_midi_operations; #endif -extern irqreturn_t emu10k1_interrupt(int, void *, struct pt_regs *s); +extern irqreturn_t emu10k1_interrupt(int, void *); static int __devinit emu10k1_audio_init(struct emu10k1_card *card) { diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c index a2ffe723dad5..2562f4769b90 100644 --- a/sound/oss/es1371.c +++ b/sound/oss/es1371.c @@ -1100,7 +1100,7 @@ static void es1371_handle_midi(struct es1371_state *s) outb((s->midi.ocnt > 0) ? UCTRL_RXINTEN | UCTRL_ENA_TXINT : UCTRL_RXINTEN, s->io+ES1371_REG_UART_CONTROL); } -static irqreturn_t es1371_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t es1371_interrupt(int irq, void *dev_id) { struct es1371_state *s = (struct es1371_state *)dev_id; unsigned int intsrc, sctl; diff --git a/sound/oss/hal2.c b/sound/oss/hal2.c index 80ab402dae9a..7807abac0625 100644 --- a/sound/oss/hal2.c +++ b/sound/oss/hal2.c @@ -370,7 +370,7 @@ static void hal2_adc_interrupt(struct hal2_codec *adc) wake_up(&adc->dma_wait); } -static irqreturn_t hal2_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t hal2_interrupt(int irq, void *dev_id) { struct hal2_card *hal2 = (struct hal2_card*)dev_id; irqreturn_t ret = IRQ_NONE; diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c index ddcddc2347f7..a48af879b466 100644 --- a/sound/oss/i810_audio.c +++ b/sound/oss/i810_audio.c @@ -1523,7 +1523,7 @@ static void i810_channel_interrupt(struct i810_card *card) #endif } -static irqreturn_t i810_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t i810_interrupt(int irq, void *dev_id) { struct i810_card *card = (struct i810_card *)dev_id; u32 status; diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index 162d07cc489f..58d4a5d05a27 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -432,7 +432,7 @@ static void mpu401_input_loop(struct mpu_config *devc) devc->m_busy = 0; } -static irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs *dummy) +static irqreturn_t mpuintr(int irq, void *dev_id) { struct mpu_config *devc; int dev = (int) dev_id; diff --git a/sound/oss/mpu401.h b/sound/oss/mpu401.h index 84c0e9522ef7..0ad1e9ee74f7 100644 --- a/sound/oss/mpu401.h +++ b/sound/oss/mpu401.h @@ -3,10 +3,9 @@ int probe_uart401 (struct address_info *hw_config, struct module *owner); void unload_uart401 (struct address_info *hw_config); -irqreturn_t uart401intr (int irq, void *dev_id, struct pt_regs * dummy); +irqreturn_t uart401intr (int irq, void *dev_id); /* From mpu401.c */ int probe_mpu401(struct address_info *hw_config, struct resource *ports); int attach_mpu401(struct address_info * hw_config, struct module *owner); void unload_mpu401(struct address_info *hw_info); - diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index 6d7763dae895..d5146790f5e3 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c @@ -1087,7 +1087,7 @@ static __inline__ void eval_dsp_msg(register WORD wMessage) } } -static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t intr(int irq, void *dev_id) { /* Send ack to DSP */ msnd_inb(dev.io + HP_RXL); diff --git a/sound/oss/nec_vrc5477.c b/sound/oss/nec_vrc5477.c index 6f7f2f0423e4..da9728e17727 100644 --- a/sound/oss/nec_vrc5477.c +++ b/sound/oss/nec_vrc5477.c @@ -848,7 +848,7 @@ static inline void vrc5477_ac97_dac_interrupt(struct vrc5477_ac97_state *s) wake_up_interruptible(&dac->wait); } -static irqreturn_t vrc5477_ac97_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t vrc5477_ac97_interrupt(int irq, void *dev_id) { struct vrc5477_ac97_state *s = (struct vrc5477_ac97_state *)dev_id; u32 irqStatus; diff --git a/sound/oss/nm256.h b/sound/oss/nm256.h index 21e07b5081f2..1dade9033995 100644 --- a/sound/oss/nm256.h +++ b/sound/oss/nm256.h @@ -115,7 +115,7 @@ struct nm256_info int has_irq; /* The card interrupt service routine. */ - irqreturn_t (*introutine) (int, void *, struct pt_regs *); + irq_handler_t introutine; /* Current audio config, cached. */ struct sinfo { diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c index 7760dddf2b32..44cd15505001 100644 --- a/sound/oss/nm256_audio.c +++ b/sound/oss/nm256_audio.c @@ -45,8 +45,8 @@ static struct audio_driver nm256_audio_driver; static int nm256_grabInterrupt (struct nm256_info *card); static int nm256_releaseInterrupt (struct nm256_info *card); -static irqreturn_t nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy); -static irqreturn_t nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy); +static irqreturn_t nm256_interrupt (int irq, void *dev_id); +static irqreturn_t nm256_interrupt_zx (int irq, void *dev_id); /* These belong in linux/pci.h. */ #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 @@ -526,7 +526,7 @@ nm256_initHw (struct nm256_info *card) */ static irqreturn_t -nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy) +nm256_interrupt (int irq, void *dev_id) { struct nm256_info *card = (struct nm256_info *)dev_id; u16 status; @@ -629,7 +629,7 @@ nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy) */ static irqreturn_t -nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy) +nm256_interrupt_zx (int irq, void *dev_id) { struct nm256_info *card = (struct nm256_info *)dev_id; u32 status; diff --git a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c index 4ebb9638746e..25f3a22c52ee 100644 --- a/sound/oss/pas2_card.c +++ b/sound/oss/pas2_card.c @@ -88,7 +88,7 @@ void pas_write(unsigned char data, int ioaddr) /******************* Begin of the Interrupt Handler ********************/ -static irqreturn_t pasintr(int irq, void *dev_id, struct pt_regs *dummy) +static irqreturn_t pasintr(int irq, void *dev_id) { int status; diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c index bbe5b7596d0e..440537c72604 100644 --- a/sound/oss/sb_common.c +++ b/sound/oss/sb_common.c @@ -132,7 +132,7 @@ static void sb_intr (sb_devc *devc) if (src & 4) /* MPU401 interrupt */ if(devc->midi_irq_cookie) - uart401intr(devc->irq, devc->midi_irq_cookie, NULL); + uart401intr(devc->irq, devc->midi_irq_cookie); if (!(src & 3)) return; /* Not a DSP interrupt */ @@ -200,7 +200,7 @@ static void pci_intr(sb_devc *devc) sb_intr(devc); } -static irqreturn_t sbintr(int irq, void *dev_id, struct pt_regs *dummy) +static irqreturn_t sbintr(int irq, void *dev_id) { sb_devc *devc = dev_id; diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c index 83ff8a71f716..3b3b4da8cfd3 100644 --- a/sound/oss/sh_dac_audio.c +++ b/sound/oss/sh_dac_audio.c @@ -263,7 +263,7 @@ struct file_operations dac_audio_fops = { .release = dac_audio_release, }; -static irqreturn_t timer1_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t timer1_interrupt(int irq, void *dev) { unsigned long timer_status; diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index 3edf8d4ac998..471c274c5000 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c @@ -2505,7 +2505,7 @@ static /*const */ struct file_operations cs4297a_audio_fops = { .release = cs4297a_release, }; -static void cs4297a_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void cs4297a_interrupt(int irq, void *dev_id) { struct cs4297a_state *s = (struct cs4297a_state *) dev_id; u32 status; diff --git a/sound/oss/trident.c b/sound/oss/trident.c index 147c816a1f22..7a363a178afd 100644 --- a/sound/oss/trident.c +++ b/sound/oss/trident.c @@ -1811,7 +1811,7 @@ cyber_address_interrupt(struct trident_card *card) } static irqreturn_t -trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) +trident_interrupt(int irq, void *dev_id) { struct trident_card *card = (struct trident_card *) dev_id; u32 event; diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c index 8e18b6e25818..a446b826d5fc 100644 --- a/sound/oss/uart401.c +++ b/sound/oss/uart401.c @@ -96,7 +96,7 @@ static void uart401_input_loop(uart401_devc * devc) printk(KERN_WARNING "Too much work in interrupt on uart401 (0x%X). UART jabbering ??\n", devc->base); } -irqreturn_t uart401intr(int irq, void *dev_id, struct pt_regs *dummy) +irqreturn_t uart401intr(int irq, void *dev_id) { uart401_devc *devc = dev_id; diff --git a/sound/oss/uart6850.c b/sound/oss/uart6850.c index 501d3e654a67..f3f914aa92ee 100644 --- a/sound/oss/uart6850.c +++ b/sound/oss/uart6850.c @@ -104,7 +104,7 @@ static void uart6850_input_loop(void) } } -static irqreturn_t m6850intr(int irq, void *dev_id, struct pt_regs *dummy) +static irqreturn_t m6850intr(int irq, void *dev_id) { if (input_avail()) uart6850_input_loop(); diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c index 2fec42fc3482..17837d4b5ed3 100644 --- a/sound/oss/via82cxxx_audio.c +++ b/sound/oss/via82cxxx_audio.c @@ -1912,7 +1912,7 @@ static void via_intr_channel (struct via_info *card, struct via_channel *chan) } -static irqreturn_t via_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t via_interrupt(int irq, void *dev_id) { struct via_info *card = dev_id; u32 status32; @@ -1927,7 +1927,7 @@ static irqreturn_t via_interrupt(int irq, void *dev_id, struct pt_regs *regs) { #ifdef CONFIG_MIDI_VIA82CXXX if (card->midi_devc) - uart401intr(irq, card->midi_devc, regs); + uart401intr(irq, card->midi_devc); #endif return IRQ_HANDLED; } @@ -1950,7 +1950,7 @@ static irqreturn_t via_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t via_new_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t via_new_interrupt(int irq, void *dev_id) { struct via_info *card = dev_id; u32 status32; diff --git a/sound/oss/vidc.h b/sound/oss/vidc.h index d5b8064dc565..0d1424751ecd 100644 --- a/sound/oss/vidc.h +++ b/sound/oss/vidc.h @@ -33,7 +33,7 @@ extern unsigned long vidc_fill_2x16_s(unsigned long ibuf, unsigned long iend, * DMA Interrupt handler */ -extern irqreturn_t vidc_sound_dma_irq(int irqnr, void *ref, struct pt_regs *regs); +extern irqreturn_t vidc_sound_dma_irq(int irqnr, void *ref); /* * Filler routine pointer diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c index 5f140c7586b3..0cd4d6ec9862 100644 --- a/sound/oss/vwsnd.c +++ b/sound/oss/vwsnd.c @@ -2233,12 +2233,12 @@ static void vwsnd_audio_write_intr(vwsnd_dev_t *devc, unsigned int status) pcm_output(devc, underflown, 0); } -static irqreturn_t vwsnd_audio_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t vwsnd_audio_intr(int irq, void *dev_id) { vwsnd_dev_t *devc = (vwsnd_dev_t *) dev_id; unsigned int status; - DBGEV("(irq=%d, dev_id=0x%p, regs=0x%p)\n", irq, dev_id, regs); + DBGEV("(irq=%d, dev_id=0x%p)\n", irq, dev_id); status = li_get_clear_intr_status(&devc->lith); vwsnd_audio_read_intr(devc, status); diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c index 59a2f28eb5a5..c5bf363d32c2 100644 --- a/sound/oss/waveartist.c +++ b/sound/oss/waveartist.c @@ -833,7 +833,7 @@ static struct audio_driver waveartist_audio_driver = { static irqreturn_t -waveartist_intr(int irq, void *dev_id, struct pt_regs *regs) +waveartist_intr(int irq, void *dev_id) { wavnc_info *devc = (wavnc_info *)dev_id; int irqstatus, status; diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index ce73f3eae78c..cf603337b321 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -193,7 +193,7 @@ harmony_set_control(struct snd_harmony *h) } static irqreturn_t -snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs) +snd_harmony_interrupt(int irq, void *dev) { u32 dstatus; struct snd_harmony *h = dev; diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 0786d0edaca5..cbf8331c3d33 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -596,9 +596,7 @@ static struct snd_pcm_ops snd_ad1889_capture_ops = { }; static irqreturn_t -snd_ad1889_interrupt(int irq, - void *dev_id, - struct pt_regs *regs) +snd_ad1889_interrupt(int irq, void *dev_id) { unsigned long st; struct snd_ad1889 *chip = dev_id; diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 74668398eac5..13a8cefa7749 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1047,9 +1047,7 @@ static void snd_ali_interrupt(struct snd_ali * codec) } -static irqreturn_t snd_ali_card_interrupt(int irq, - void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_ali_card_interrupt(int irq, void *dev_id) { struct snd_ali *codec = dev_id; diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 96cfb8ae5055..9b16c299f0a9 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -204,8 +204,7 @@ static int snd_als300_dev_free(struct snd_device *device) return snd_als300_free(chip); } -static irqreturn_t snd_als300_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_als300_interrupt(int irq, void *dev_id) { u8 status; struct snd_als300 *chip = dev_id; @@ -236,8 +235,7 @@ static irqreturn_t snd_als300_interrupt(int irq, void *dev_id, return IRQ_HANDLED; } -static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id) { u8 general, mpu, dram; struct snd_als300 *chip = dev_id; diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 9e596f750cbd..15fc3929b5f7 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -385,7 +385,7 @@ static snd_pcm_uframes_t snd_als4000_playback_pointer(struct snd_pcm_substream * * SB IRQ status. * And do we *really* need the lock here for *reading* SB_DSP4_IRQSTATUS?? * */ -static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id) { struct snd_sb *chip = dev_id; unsigned gcr_status; @@ -399,7 +399,7 @@ static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs * if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */ snd_pcm_period_elapsed(chip->capture_substream); if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */ - snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); /* release the gcr */ outb(gcr_status, chip->alt_port + 0xe); diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 347e25ff073d..3e8fc5a0006a 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1300,7 +1300,7 @@ static int __devinit snd_atiixp_pcm_new(struct atiixp *chip) /* * interrupt handler */ -static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id) { struct atiixp *chip = dev_id; unsigned int status; diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index a89d67c4598b..c5dda1bf3d46 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1017,7 +1017,7 @@ static int __devinit snd_atiixp_pcm_new(struct atiixp_modem *chip) /* * interrupt handler */ -static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id) { struct atiixp_modem *chip = dev_id; unsigned int status; diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index b1cfc3c79d07..5ccf0b1ec670 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h @@ -236,8 +236,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode); static int vortex_core_init(vortex_t * card); static int vortex_core_shutdown(vortex_t * card); static void vortex_enable_int(vortex_t * card); -static irqreturn_t vortex_interrupt(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t vortex_interrupt(int irq, void *dev_id); static int vortex_alsafmt_aspfmt(int alsafmt); /* Connection stuff. */ diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 5299cce583d3..4a336eaae9d2 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2385,7 +2385,7 @@ static void vortex_disable_int(vortex_t * card) hwread(card->mmio, VORTEX_CTRL) & ~CTRL_IRQ_ENABLE); } -static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t vortex_interrupt(int irq, void *dev_id) { vortex_t *vortex = dev_id; int i, handled; @@ -2462,7 +2462,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) } if (source & IRQ_MIDI) { snd_mpu401_uart_interrupt(vortex->irq, - vortex->rmidi->private_data, regs); + vortex->rmidi->private_data); handled = 1; } diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index bac8e9cfd921..692f203d65d8 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1191,7 +1191,7 @@ snd_azf3328_capture_pointer(struct snd_pcm_substream *substream) } static irqreturn_t -snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs) +snd_azf3328_interrupt(int irq, void *dev_id) { struct snd_azf3328 *chip = dev_id; u8 status, which; @@ -1256,7 +1256,7 @@ snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* MPU401 has less critical IRQ requirements * than timer and playback/recording, right? */ if (status & IRQ_MPU401) { - snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); /* hmm, do we have to ack the IRQ here somehow? * If so, then I don't know how... */ diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 97a280a246cb..d33a37086df9 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -269,7 +269,7 @@ static void snd_bt87x_pci_error(struct snd_bt87x *chip, unsigned int status) } } -static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id) { struct snd_bt87x *chip = dev_id; unsigned int status, irq_status; diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 12bbbb6afd2d..6fa4a302f7de 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1058,8 +1058,7 @@ static int snd_ca0106_dev_free(struct snd_device *device) return snd_ca0106_free(chip); } -static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) { unsigned int status; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 876b64464b6f..1f7e71083069 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -1294,7 +1294,7 @@ static int snd_cmipci_capture_spdif_hw_free(struct snd_pcm_substream *subs) /* * interrupt handler */ -static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id) { struct cmipci *cm = dev_id; unsigned int status, mask = 0; @@ -1315,7 +1315,7 @@ static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id, struct pt_regs *r spin_unlock(&cm->reg_lock); if (cm->rmidi && (status & CM_UARTINT)) - snd_mpu401_uart_interrupt(irq, cm->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, cm->rmidi->private_data); if (cm->pcm) { if ((status & CM_CHINT0) && cm->channel[0].running) diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 1990430a21c1..d54924e60bb1 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -493,7 +493,7 @@ struct cs4281 { }; -static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id); static struct pci_device_id snd_cs4281_ids[] = { { 0x1013, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CS4281 */ @@ -1814,7 +1814,7 @@ static int __devinit snd_cs4281_midi(struct cs4281 * chip, int device, * Interrupt handler */ -static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id) { struct cs4281 *chip = dev_id; unsigned int status, dma, val; diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 4851847180d2..16d4ebf2a33f 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1149,7 +1149,7 @@ static int snd_cs46xx_capture_prepare(struct snd_pcm_substream *substream) return 0; } -static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id) { struct snd_cs46xx *chip = dev_id; u32 status1; diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 64c7826e8b8c..2441238f2004 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -203,8 +203,7 @@ static void process_bm1_irq(struct cs5535audio *cs5535au) } } -static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id) { u16 acc_irq_stat; u8 bm_stat; diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index c3dafa29054f..e5e88fe54de0 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1818,8 +1818,7 @@ static struct snd_kcontrol_new snd_echo_channels_info __devinitdata = { IRQ Handler ******************************************************************************/ -static irqreturn_t snd_echo_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_echo_interrupt(int irq, void *dev_id) { struct echoaudio *chip = dev_id; struct snd_pcm_substream *substream; diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index da1610a571b8..c46905a11175 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -780,8 +780,7 @@ static int snd_emu10k1x_dev_free(struct snd_device *device) return snd_emu10k1x_free(chip); } -static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id) { unsigned int status; diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index 1076af4c3669..4f18f7e8bcfb 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c @@ -30,7 +30,7 @@ #include #include -irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) { struct snd_emu10k1 *emu = dev_id; unsigned int status, status2, orig_status, orig_status2; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index a8a601fc781f..8cb4fb2412db 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -444,7 +444,7 @@ struct ensoniq { #endif }; -static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id); static struct pci_device_id snd_audiopci_ids[] = { #ifdef CHIP1370 @@ -2404,7 +2404,7 @@ static int __devinit snd_ensoniq_midi(struct ensoniq * ensoniq, int device, * Interrupt handler */ -static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id) { struct ensoniq *ensoniq = dev_id; unsigned int status, sctrl; diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 3ce5a4e7e31f..2da988f78ba7 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -241,7 +241,7 @@ struct es1938 { #endif }; -static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); static struct pci_device_id snd_es1938_ids[] = { { 0x125d, 0x1969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Solo-1 */ @@ -1642,7 +1642,7 @@ static int __devinit snd_es1938_create(struct snd_card *card, /* -------------------------------------------------------------------- * Interrupt handler * -------------------------------------------------------------------- */ -static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id) { struct es1938 *chip = dev_id; unsigned char status, audiostatus; @@ -1714,7 +1714,7 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *r // snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0); /* ack? */ if (chip->rmidi) { handled = 1; - snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); } } return IRQ_RETVAL(handled); diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index f3c40385c87d..b9d723c7e1db 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -590,7 +590,7 @@ struct es1968 { #endif }; -static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); static struct pci_device_id snd_es1968_ids[] = { /* Maestro 1 */ @@ -1962,7 +1962,7 @@ static void es1968_update_hw_volume(unsigned long private_data) /* * interrupt handler */ -static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) { struct es1968 *chip = dev_id; u32 event; @@ -1979,7 +1979,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *r outb(0xFF, chip->io_port + 0x1A); if ((event & ESM_MPU401_IRQ) && chip->rmidi) { - snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); } if (event & ESM_SOUND_IRQ) { diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index bdfda1997d5b..3ec7d7ee04dd 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -520,7 +520,7 @@ static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *sub return bytes_to_frames(substream->runtime, ptr); } -static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) { struct fm801 *chip = dev_id; unsigned short status; @@ -561,7 +561,7 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id, struct pt_regs *re snd_pcm_period_elapsed(chip->capture_substream); } if (chip->rmidi && (status & FM801_IRQ_MPU)) - snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); if (status & FM801_IRQ_VOLUME) ;/* TODO */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e9d4cb4d07e1..a76a778d0a1f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -811,7 +811,7 @@ static void azx_init_chip(struct azx *chip) /* * interrupt handler */ -static irqreturn_t azx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t azx_interrupt(int irq, void *dev_id) { struct azx *chip = dev_id; struct azx_dev *azx_dev; diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index dc69392eafa3..8a576b78bee5 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -420,7 +420,7 @@ static void snd_ice1712_set_input_clock_source(struct snd_ice1712 *ice, int spdi * Interrupt handler */ -static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id) { struct snd_ice1712 *ice = dev_id; unsigned char status; @@ -433,7 +433,7 @@ static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id, struct pt_regs * handled = 1; if (status & ICE1712_IRQ_MPU1) { if (ice->rmidi[0]) - snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data, regs); + snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data); outb(ICE1712_IRQ_MPU1, ICEREG(ice, IRQSTAT)); status &= ~ICE1712_IRQ_MPU1; } @@ -441,7 +441,7 @@ static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id, struct pt_regs * outb(ICE1712_IRQ_TIMER, ICEREG(ice, IRQSTAT)); if (status & ICE1712_IRQ_MPU2) { if (ice->rmidi[1]) - snd_mpu401_uart_interrupt(irq, ice->rmidi[1]->private_data, regs); + snd_mpu401_uart_interrupt(irq, ice->rmidi[1]->private_data); outb(ICE1712_IRQ_MPU2, ICEREG(ice, IRQSTAT)); status &= ~ICE1712_IRQ_MPU2; } diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 71d6aedc0749..e9cbfdf37059 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -218,7 +218,7 @@ static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice) * Interrupt handler */ -static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) { struct snd_ice1712 *ice = dev_id; unsigned char status; @@ -236,7 +236,7 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id, struct pt_regs *r */ if ((status & VT1724_IRQ_MPU_RX)||(status & VT1724_IRQ_MPU_TX)) { if (ice->rmidi[0]) - snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data, regs); + snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data); outb(status & (VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX), ICEREG1724(ice, IRQSTAT)); status &= ~(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX); } diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 72dbaedcbdf5..f4319b8d4644 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -801,7 +801,7 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich status & (ICH_FIFOE | ICH_BCIS | ICH_LVBCI)); } -static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id) { struct intel8x0 *chip = dev_id; struct ichdev *ichdev; diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 268e2f7241ea..6703f5cb5569 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -511,7 +511,7 @@ static inline void snd_intel8x0_update(struct intel8x0m *chip, struct ichdev *ic iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); } -static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id) { struct intel8x0m *chip = dev_id; struct ichdev *ichdev; diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index cfea51f44784..398aa10a06e8 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -1119,7 +1119,7 @@ static void snd_korg1212_OnDSPDownloadComplete(struct snd_korg1212 *korg1212) snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_COMPLETE); } -static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id) { u32 doorbellValue; struct snd_korg1212 *korg1212 = dev_id; diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 45214b3b81be..05605f474a72 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1685,8 +1685,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data) spin_unlock_irqrestore(&chip->ac97_lock, flags); } -static irqreturn_t -snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) { struct snd_m3 *chip = dev_id; u8 status; diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index 406ac3a9d42a..d54457317b14 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -408,7 +408,7 @@ void snd_mixart_msg_tasklet(unsigned long arg) } -irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) { struct mixart_mgr *mgr = dev_id; int err; diff --git a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h index 1fe2bcfcc57c..c919b734756f 100644 --- a/sound/pci/mixart/mixart_core.h +++ b/sound/pci/mixart/mixart_core.h @@ -563,7 +563,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, struct mixart_msg *request, u32 notif_event); int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request); -irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t snd_mixart_interrupt(int irq, void *dev_id); void snd_mixart_msg_tasklet(unsigned long arg); void snd_mixart_reset_board(struct mixart_mgr *mgr); diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 101eee0aa018..b1bbdb9e3b7b 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -236,7 +236,7 @@ struct nm256 { int irq; int irq_acks; - irqreturn_t (*interrupt)(int, void *, struct pt_regs *); + irq_handler_t interrupt; int badintrcount; /* counter to check bogus interrupts */ struct mutex irq_mutex; @@ -1004,7 +1004,7 @@ snd_nm256_intr_check(struct nm256 *chip) */ static irqreturn_t -snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy) +snd_nm256_interrupt(int irq, void *dev_id) { struct nm256 *chip = dev_id; u16 status; @@ -1069,7 +1069,7 @@ snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy) */ static irqreturn_t -snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy) +snd_nm256_interrupt_zx(int irq, void *dev_id) { struct nm256 *chip = dev_id; u32 status; diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index c40f59062684..0ff8dc36fde3 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -1131,7 +1131,7 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, } -irqreturn_t pcxhr_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t pcxhr_interrupt(int irq, void *dev_id) { struct pcxhr_mgr *mgr = dev_id; unsigned int reg; diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h index e7415d6d1826..d9a4ab609875 100644 --- a/sound/pci/pcxhr/pcxhr_core.h +++ b/sound/pci/pcxhr/pcxhr_core.h @@ -194,7 +194,7 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, /* interrupt handling */ -irqreturn_t pcxhr_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t pcxhr_interrupt(int irq, void *dev_id); void pcxhr_msg_tasklet(unsigned long arg); #endif /* __SOUND_PCXHR_CORE_H */ diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index fe210c853442..ec4899147e1d 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1736,7 +1736,7 @@ snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm) } static irqreturn_t -snd_riptide_interrupt(int irq, void *dev_id, struct pt_regs *regs) +snd_riptide_interrupt(int irq, void *dev_id) { struct snd_riptide *chip = dev_id; struct cmdif *cif = chip->cif; @@ -1751,8 +1751,7 @@ snd_riptide_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (chip->rmidi && IS_MPUIRQ(cif->hwport)) { chip->handled_irqs++; snd_mpu401_uart_interrupt(irq, - chip->rmidi->private_data, - regs); + chip->rmidi->private_data); } SET_AIACK(cif->hwport); } diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 2a71499242fa..dc8d1302e22d 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -818,8 +818,7 @@ static void snd_rme32_pcm_stop(struct rme32 * rme32, int to_pause) writel(0, rme32->iobase + RME32_IO_RESET_POS); } -static irqreturn_t -snd_rme32_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_rme32_interrupt(int irq, void *dev_id) { struct rme32 *rme32 = (struct rme32 *) dev_id; diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index f8de7c997017..106110a89a4c 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -1117,8 +1117,7 @@ snd_rme96_capture_stop(struct rme96 *rme96) static irqreturn_t snd_rme96_interrupt(int irq, - void *dev_id, - struct pt_regs *regs) + void *dev_id) { struct rme96 *rme96 = (struct rme96 *)dev_id; diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index d3e07de433b0..694aa057ed49 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3603,7 +3603,7 @@ static void hdsp_midi_tasklet(unsigned long arg) snd_hdsp_midi_input_read (&hdsp->midi[1]); } -static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id) { struct hdsp *hdsp = (struct hdsp *) dev_id; unsigned int status; diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 7d03ae066d53..7055d893855d 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2556,8 +2556,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) interupt ------------------------------------------------------------*/ -static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) { struct hdspm *hdspm = (struct hdspm *) dev_id; unsigned int status; diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index fc15f61ad5d1..cf0427b4bfde 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1882,7 +1882,7 @@ static void snd_rme9652_set_defaults(struct snd_rme9652 *rme9652) rme9652_set_rate(rme9652, 48000); } -static irqreturn_t snd_rme9652_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_rme9652_interrupt(int irq, void *dev_id) { struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) dev_id; diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index e5d4def1aa6f..f9b8afabda9c 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -580,7 +580,7 @@ static int snd_sonicvibes_trigger(struct sonicvibes * sonic, int what, int cmd) return result; } -static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id) { struct sonicvibes *sonic = dev_id; unsigned char status; @@ -601,7 +601,7 @@ static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id, struct pt_reg } if (sonic->rmidi) { if (status & SV_MIDI_IRQ) - snd_mpu401_uart_interrupt(irq, sonic->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, sonic->rmidi->private_data); } if (status & SV_UD_IRQ) { unsigned char udreg; diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index ebbe12d78d8c..0d478871808d 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -52,8 +52,7 @@ static int snd_trident_pcm_mixer_build(struct snd_trident *trident, static int snd_trident_pcm_mixer_free(struct snd_trident *trident, struct snd_trident_voice * voice, struct snd_pcm_substream *substream); -static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t snd_trident_interrupt(int irq, void *dev_id); static int snd_trident_sis_reset(struct snd_trident *trident); static void snd_trident_clear_voices(struct snd_trident * trident, @@ -3737,7 +3736,7 @@ static int snd_trident_free(struct snd_trident *trident) ---------------------------------------------------------------------------*/ -static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_trident_interrupt(int irq, void *dev_id) { struct snd_trident *trident = dev_id; unsigned int audio_int, chn_int, stimer, channel, mask, tmp; @@ -3825,7 +3824,7 @@ static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs * } if (audio_int & MPU401_IRQ) { if (trident->rmidi) { - snd_mpu401_uart_interrupt(irq, trident->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, trident->rmidi->private_data); } else { inb(TRID_REG(trident, T4D_MPUR0)); } diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 6db3d4cc4d8d..e6990e0bbf23 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -613,7 +613,7 @@ static void snd_via82xx_channel_reset(struct via82xx *chip, struct viadev *viade * Interrupt handler * Used for 686 and 8233A */ -static irqreturn_t snd_via686_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_via686_interrupt(int irq, void *dev_id) { struct via82xx *chip = dev_id; unsigned int status; @@ -623,7 +623,7 @@ static irqreturn_t snd_via686_interrupt(int irq, void *dev_id, struct pt_regs *r if (! (status & chip->intr_mask)) { if (chip->rmidi) /* check mpu401 interrupt */ - return snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + return snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); return IRQ_NONE; } @@ -659,7 +659,7 @@ static irqreturn_t snd_via686_interrupt(int irq, void *dev_id, struct pt_regs *r /* * Interrupt handler */ -static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id) { struct via82xx *chip = dev_id; unsigned int status; diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 016f9dac253f..5ab1cf3d434b 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -475,7 +475,7 @@ static void snd_via82xx_channel_reset(struct via82xx_modem *chip, struct viadev * Interrupt handler */ -static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id) { struct via82xx_modem *chip = dev_id; unsigned int status; diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 24f6fc52f898..ebc6da89edf3 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -753,7 +753,7 @@ static void snd_ymfpci_irq_wait(struct snd_ymfpci *chip) } } -static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id) { struct snd_ymfpci *chip = dev_id; u32 status, nvoice, mode; @@ -799,7 +799,7 @@ static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id, struct pt_regs *r snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status); if (chip->rawmidi) - snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data); return IRQ_HANDLED; } diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h index 9a14a4f64bd3..206e2f5a113f 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.h +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h @@ -138,7 +138,7 @@ int snd_pdacf_suspend(struct snd_pdacf *chip, pm_message_t state); int snd_pdacf_resume(struct snd_pdacf *chip); #endif int snd_pdacf_pcm_new(struct snd_pdacf *chip); -irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs); +irqreturn_t pdacf_interrupt(int irq, void *dev); void pdacf_tasklet(unsigned long private_data); void pdacf_reinit(struct snd_pdacf *chip, int resume); diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c index 7c5f21e45cb4..732263e4a437 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c @@ -26,7 +26,7 @@ /* * */ -irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs) +irqreturn_t pdacf_interrupt(int irq, void *dev) { struct snd_pdacf *chip = dev; unsigned short stat; @@ -45,7 +45,7 @@ irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs) if (!(stat & PDAUDIOCF_IRQAKM)) stat |= PDAUDIOCF_IRQAKM; /* check rate */ } - if (regs != NULL) + if (get_irq_regs() != NULL) snd_ak4117_check_rate_and_errors(chip->ak4117, 0); return IRQ_HANDLED; } diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 641430631505..c64af55865d4 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -713,7 +713,7 @@ void snd_pmac_beep_dma_stop(struct snd_pmac *chip) * interrupt handlers */ static irqreturn_t -snd_pmac_tx_intr(int irq, void *devid, struct pt_regs *regs) +snd_pmac_tx_intr(int irq, void *devid) { struct snd_pmac *chip = devid; snd_pmac_pcm_update(chip, &chip->playback); @@ -722,7 +722,7 @@ snd_pmac_tx_intr(int irq, void *devid, struct pt_regs *regs) static irqreturn_t -snd_pmac_rx_intr(int irq, void *devid, struct pt_regs *regs) +snd_pmac_rx_intr(int irq, void *devid) { struct snd_pmac *chip = devid; snd_pmac_pcm_update(chip, &chip->capture); @@ -731,7 +731,7 @@ snd_pmac_rx_intr(int irq, void *devid, struct pt_regs *regs) static irqreturn_t -snd_pmac_ctrl_intr(int irq, void *devid, struct pt_regs *regs) +snd_pmac_ctrl_intr(int irq, void *devid) { struct snd_pmac *chip = devid; int ctrl = in_le32(&chip->awacs->control); diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index cdff53e4a17e..2fbe1d183fce 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -1017,7 +1017,7 @@ static void tumbler_update_automute(struct snd_pmac *chip, int do_notify) /* interrupt - headphone plug changed */ -static irqreturn_t headphone_intr(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t headphone_intr(int irq, void *devid) { struct snd_pmac *chip = devid; if (chip->update_automute && chip->initialized) { diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index be0bd503f013..c899786f30f5 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -491,7 +491,7 @@ static void __amd7930_update_map(struct snd_amd7930 *amd) __amd7930_write_map(amd); } -static irqreturn_t snd_amd7930_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_amd7930_interrupt(int irq, void *dev_id) { struct snd_amd7930 *amd = dev_id; unsigned int elapsed; diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 9a06c3bd6944..edeb3d3c4c7e 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -1753,7 +1753,7 @@ out_err: #ifdef SBUS_SUPPORT -static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id) { unsigned long flags; unsigned char status; diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 5a97be689b40..4ceb09d215d8 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -1903,8 +1903,7 @@ static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) } } -static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id) { struct snd_dbri *dbri = dev_id; static int errcnt = 0; diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a42acf6d7b68..c82b01c7ad3a 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -653,7 +653,7 @@ static struct snd_urb_ops audio_urb_ops_high_speed[2] = { /* * complete callback from data urb */ -static void snd_complete_urb(struct urb *urb, struct pt_regs *regs) +static void snd_complete_urb(struct urb *urb) { struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; struct snd_usb_substream *subs = ctx->subs; @@ -676,7 +676,7 @@ static void snd_complete_urb(struct urb *urb, struct pt_regs *regs) /* * complete callback from sync urb */ -static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs) +static void snd_complete_sync_urb(struct urb *urb) { struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; struct snd_usb_substream *subs = ctx->subs; diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 0dcf78adb99a..b7c5e59b2299 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -223,7 +223,7 @@ static void dump_urb(const char *type, const u8 *data, int length) /* * Processes the data read from the device. */ -static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs) +static void snd_usbmidi_in_urb_complete(struct urb* urb) { struct snd_usb_midi_in_endpoint* ep = urb->context; @@ -247,7 +247,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs) snd_usbmidi_submit_urb(urb, GFP_ATOMIC); } -static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs) +static void snd_usbmidi_out_urb_complete(struct urb* urb) { struct snd_usb_midi_out_endpoint* ep = urb->context; diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index e516d6adbb22..1024c178f5c0 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -1710,7 +1710,7 @@ static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, } } -static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) +static void snd_usb_mixer_status_complete(struct urb *urb) { struct usb_mixer_interface *mixer = urb->context; @@ -1772,8 +1772,7 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) return 0; } -static void snd_usb_soundblaster_remote_complete(struct urb *urb, - struct pt_regs *regs) +static void snd_usb_soundblaster_remote_complete(struct urb *urb) { struct usb_mixer_interface *mixer = urb->context; const struct rc_config *rc = mixer->rc_cfg; diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index cfec38d7839b..e011fcacce92 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -172,7 +172,7 @@ static void snd_usX2Y_card_private_free(struct snd_card *card); /* * pipe 4 is used for switching the lamps, setting samplerate, volumes .... */ -static void i_usX2Y_Out04Int(struct urb *urb, struct pt_regs *regs) +static void i_usX2Y_Out04Int(struct urb *urb) { #ifdef CONFIG_SND_DEBUG if (urb->status) { @@ -184,7 +184,7 @@ static void i_usX2Y_Out04Int(struct urb *urb, struct pt_regs *regs) #endif } -static void i_usX2Y_In04Int(struct urb *urb, struct pt_regs *regs) +static void i_usX2Y_In04Int(struct urb *urb) { int err = 0; struct usX2Ydev *usX2Y = urb->context; diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index f6bd0dee563c..e662281a751a 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -306,7 +306,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, usX2Y_clients_stop(usX2Y); } -static void i_usX2Y_urb_complete(struct urb *urb, struct pt_regs *regs) +static void i_usX2Y_urb_complete(struct urb *urb) { struct snd_usX2Y_substream *subs = urb->context; struct usX2Ydev *usX2Y = subs->usX2Y; @@ -350,7 +350,7 @@ static void i_usX2Y_urb_complete(struct urb *urb, struct pt_regs *regs) } static void usX2Y_urbs_set_complete(struct usX2Ydev * usX2Y, - void (*complete)(struct urb *, struct pt_regs *)) + void (*complete)(struct urb *)) { int s, u; for (s = 0; s < 4; s++) { @@ -370,7 +370,7 @@ static void usX2Y_subs_startup_finish(struct usX2Ydev * usX2Y) usX2Y->prepare_subs = NULL; } -static void i_usX2Y_subs_startup(struct urb *urb, struct pt_regs *regs) +static void i_usX2Y_subs_startup(struct urb *urb) { struct snd_usX2Y_substream *subs = urb->context; struct usX2Ydev *usX2Y = subs->usX2Y; @@ -382,7 +382,7 @@ static void i_usX2Y_subs_startup(struct urb *urb, struct pt_regs *regs) wake_up(&usX2Y->prepare_wait_queue); } - i_usX2Y_urb_complete(urb, regs); + i_usX2Y_urb_complete(urb); } static void usX2Y_subs_prepare(struct snd_usX2Y_substream *subs) @@ -663,7 +663,7 @@ static struct s_c2 SetRate48000[] = }; #define NOOF_SETRATE_URBS ARRAY_SIZE(SetRate48000) -static void i_usX2Y_04Int(struct urb *urb, struct pt_regs *regs) +static void i_usX2Y_04Int(struct urb *urb) { struct usX2Ydev *usX2Y = urb->context; diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 88b72b52590f..9acef9d90543 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -226,7 +226,7 @@ static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream *cap } -static void i_usX2Y_usbpcm_urb_complete(struct urb *urb, struct pt_regs *regs) +static void i_usX2Y_usbpcm_urb_complete(struct urb *urb) { struct snd_usX2Y_substream *subs = urb->context; struct usX2Ydev *usX2Y = subs->usX2Y; @@ -294,7 +294,7 @@ static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y) usX2Y->prepare_subs = NULL; } -static void i_usX2Y_usbpcm_subs_startup(struct urb *urb, struct pt_regs *regs) +static void i_usX2Y_usbpcm_subs_startup(struct urb *urb) { struct snd_usX2Y_substream *subs = urb->context; struct usX2Ydev *usX2Y = subs->usX2Y; @@ -311,7 +311,7 @@ static void i_usX2Y_usbpcm_subs_startup(struct urb *urb, struct pt_regs *regs) wake_up(&usX2Y->prepare_wait_queue); } - i_usX2Y_usbpcm_urb_complete(urb, regs); + i_usX2Y_usbpcm_urb_complete(urb); } /* -- cgit v1.2.3 From 7f7bbbe50b8a28f4dfaa4cea939ddb50198c4a99 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 6 Oct 2006 00:43:53 -0700 Subject: [PATCH] page fault retry with NOPAGE_REFAULT Add a way for a no_page() handler to request a retry of the faulting instruction. It goes back to userland on page faults and just tries again in get_user_pages(). I added a cond_resched() in the loop in that later case. The problem I have with signal and spufs is an actual bug affecting apps and I don't see other ways of fixing it. In addition, we are having issues with infiniband and 64k pages (related to the way the hypervisor deals with some HV cards) that will require us to muck around with the MMU from within the IB driver's no_page() (it's a pSeries specific driver) and return to the caller the same way using NOPAGE_REFAULT. And to add to this, the graphics folks have been following a new approach of memory management that involves transparently swapping objects between video ram and main meory. To do that, they need installing PTEs from a no_page() handler as well and that also requires returning with NOPAGE_REFAULT. (For the later, they are currently using io_remap_pfn_range to install one PTE from no_page() which is a bit racy, we need to add a check for the PTE having already been installed afer taking the lock, but that's ok, they are only at the proof-of-concept stage. I'll send a patch adding a "clean" function to do that, we can use that from spufs too and get rid of the sparsemem hacks we do to create struct page for SPEs. Basically, that provides a generic solution for being able to have no_page() map hardware devices, which is something that I think sound driver folks have been asking for some time too). All of these things depend on having the NOPAGE_REFAULT exit path from no_page() handlers. Signed-off-by: Benjamin Herrenchmidt Cc: Hugh Dickins Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 1 + mm/memory.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index b7966ab8cb6a..26146623be2f 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -593,6 +593,7 @@ static inline int page_mapped(struct page *page) */ #define NOPAGE_SIGBUS (NULL) #define NOPAGE_OOM ((struct page *) (-1)) +#define NOPAGE_REFAULT ((struct page *) (-2)) /* Return to userspace, rerun */ /* * Error return values for the *_nopfn functions diff --git a/mm/memory.c b/mm/memory.c index 9cf3f341a28a..b5a4aadd961a 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1086,6 +1086,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, default: BUG(); } + cond_resched(); } if (pages) { pages[i] = page; @@ -2169,11 +2170,13 @@ retry: * after the next truncate_count read. */ - /* no page was available -- either SIGBUS or OOM */ - if (new_page == NOPAGE_SIGBUS) + /* no page was available -- either SIGBUS, OOM or REFAULT */ + if (unlikely(new_page == NOPAGE_SIGBUS)) return VM_FAULT_SIGBUS; - if (new_page == NOPAGE_OOM) + else if (unlikely(new_page == NOPAGE_OOM)) return VM_FAULT_OOM; + else if (unlikely(new_page == NOPAGE_REFAULT)) + return VM_FAULT_MINOR; /* * Should we do an early C-O-W break? -- cgit v1.2.3 From 7236e978a3883406ca06ee79e0739743c7c92a85 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 6 Oct 2006 00:43:54 -0700 Subject: [PATCH] provide tickadj define Provide a tickadj compatibility define for archs still using it. Signed-off-by: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/timex.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/timex.h b/include/linux/timex.h index 049dfe4a11f2..db501dc23c29 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -293,6 +293,9 @@ extern void second_overflow(void); extern void update_ntp_one_tick(void); extern int do_adjtimex(struct timex *); +/* Don't use! Compatibility define for existing users. */ +#define tickadj (500/HZ ? : 1) + #endif /* KERNEL */ #endif /* LINUX_TIMEX_H */ -- cgit v1.2.3 From a666ecfbf512dbd63a60f65d2ad6733a9a1b12ee Mon Sep 17 00:00:00 2001 From: Jan Blunck Date: Fri, 6 Oct 2006 00:43:58 -0700 Subject: [PATCH] Fix typo in "syntax error if percpu macros are incorrectly used" patch Trivial typo fix in the "syntax error if percpu macros are incorrectly used" patch. I misspelled "identifier" in all places. D'Oh! Thanks to Dirk Mueller to point this out. Signed-off-by: Jan Blunck Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-generic/percpu.h | 2 +- include/asm-s390/percpu.h | 4 ++-- include/asm-x86_64/percpu.h | 6 +++--- include/linux/percpu.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index 6d45ee5472af..196376262240 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h @@ -15,7 +15,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS]; /* var is in discarded region: offset to particular copy we want */ #define per_cpu(var, cpu) (*({ \ - extern int simple_indentifier_##var(void); \ + extern int simple_identifier_##var(void); \ RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]); })) #define __get_cpu_var(var) per_cpu(var, smp_processor_id()) #define __raw_get_cpu_var(var) per_cpu(var, raw_smp_processor_id()) diff --git a/include/asm-s390/percpu.h b/include/asm-s390/percpu.h index 495ad99c7635..9ea7f1023e57 100644 --- a/include/asm-s390/percpu.h +++ b/include/asm-s390/percpu.h @@ -16,7 +16,7 @@ #if defined(__s390x__) && defined(MODULE) #define __reloc_hide(var,offset) (*({ \ - extern int simple_indentifier_##var(void); \ + extern int simple_identifier_##var(void); \ unsigned long *__ptr; \ asm ( "larl %0,per_cpu__"#var"@GOTENT" \ : "=a" (__ptr) : "X" (per_cpu__##var) ); \ @@ -25,7 +25,7 @@ #else #define __reloc_hide(var, offset) (*({ \ - extern int simple_indentifier_##var(void); \ + extern int simple_identifier_##var(void); \ unsigned long __ptr; \ asm ( "" : "=a" (__ptr) : "0" (&per_cpu__##var) ); \ (typeof(&per_cpu__##var)) (__ptr + (offset)); })) diff --git a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h index 285756010c51..5ed0ef340842 100644 --- a/include/asm-x86_64/percpu.h +++ b/include/asm-x86_64/percpu.h @@ -32,13 +32,13 @@ /* var is in discarded region: offset to particular copy we want */ #define per_cpu(var, cpu) (*({ \ - extern int simple_indentifier_##var(void); \ + extern int simple_identifier_##var(void); \ RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)); })) #define __get_cpu_var(var) (*({ \ - extern int simple_indentifier_##var(void); \ + extern int simple_identifier_##var(void); \ RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()); })) #define __raw_get_cpu_var(var) (*({ \ - extern int simple_indentifier_##var(void); \ + extern int simple_identifier_##var(void); \ RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()); })) /* A macro to avoid #include hell... */ diff --git a/include/linux/percpu.h b/include/linux/percpu.h index 46ec72fa2c84..600e3d387ffc 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -19,7 +19,7 @@ * we force a syntax error here if it isn't. */ #define get_cpu_var(var) (*({ \ - extern int simple_indentifier_##var(void); \ + extern int simple_identifier_##var(void); \ preempt_disable(); \ &__get_cpu_var(var); })) #define put_cpu_var(var) preempt_enable() -- cgit v1.2.3 From 3260259f0084e51ce21503b130473b78871e7077 Mon Sep 17 00:00:00 2001 From: Henne Date: Fri, 6 Oct 2006 00:44:01 -0700 Subject: [PATCH] sched: fix a kerneldoc error on is_init() Fix a kerneldoc warning and reorderd the description for is_init(). Signed-off-by: Henrik Kretzschmar Cc: "Randy.Dunlap" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 331f4502e92b..6735c1cf334c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1065,9 +1065,10 @@ static inline int pid_alive(struct task_struct *p) } /** - * is_init - check if a task structure is the first user space - * task the kernel created. - * @p: Task structure to be checked. + * is_init - check if a task structure is init + * @tsk: Task structure to be checked. + * + * Check if a task structure is the first user space task the kernel created. */ static inline int is_init(struct task_struct *tsk) { -- cgit v1.2.3 From ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 6 Oct 2006 00:44:03 -0700 Subject: [PATCH] mmc: multi sector write transfers SD cards extend the protocol by allowing the host to query a card how many blocks were successfully stored on the medium. This allows us to safely write chunks of blocks at once. Signed-off-by: Pierre Ossman Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/mmc_block.c | 104 +++++++++++++++++++++++++++++++++++++++---- include/linux/mmc/protocol.h | 1 + 2 files changed, 96 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index c1293f1bda87..f9027c8db792 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -154,6 +155,71 @@ static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req) return stat; } +static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) +{ + int err; + u32 blocks; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + unsigned int timeout_us; + + struct scatterlist sg; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_APP_CMD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &cmd, 0); + if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) + return (u32)-1; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_APP_SEND_NUM_WR_BLKS; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + data.timeout_ns = card->csd.tacc_ns * 100; + data.timeout_clks = card->csd.tacc_clks * 100; + + timeout_us = data.timeout_ns / 1000; + timeout_us += data.timeout_clks * 1000 / + (card->host->ios.clock / 1000); + + if (timeout_us > 100000) { + data.timeout_ns = 100000000; + data.timeout_clks = 0; + } + + data.blksz = 4; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, &blocks, 4); + + mmc_wait_for_req(card->host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) + return (u32)-1; + + blocks = ntohl(blocks); + + return blocks; +} + static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; @@ -184,10 +250,13 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) /* * If the host doesn't support multiple block writes, force - * block writes to single block. + * block writes to single block. SD cards are excepted from + * this rule as they support querying the number of + * successfully written sectors. */ if (rq_data_dir(req) != READ && - !(card->host->caps & MMC_CAP_MULTIWRITE)) + !(card->host->caps & MMC_CAP_MULTIWRITE) && + !mmc_card_sd(card)) brq.data.blocks = 1; if (brq.data.blocks > 1) { @@ -276,24 +345,41 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) return 1; cmd_err: - mmc_card_release_host(card); - ret = 1; - /* - * For writes and where the host claims to support proper - * error reporting, we first ok the successful blocks. + /* + * If this is an SD card and we're writing, we can first + * mark the known good sectors as ok. + * + * If the card is not SD, we can still ok written sectors + * if the controller can do proper error reporting. * * For reads we just fail the entire chunk as that should * be safe in all cases. */ - if (rq_data_dir(req) != READ && - (card->host->caps & MMC_CAP_MULTIWRITE)) { + if (rq_data_dir(req) != READ && mmc_card_sd(card)) { + u32 blocks; + unsigned int bytes; + + blocks = mmc_sd_num_wr_blocks(card); + if (blocks != (u32)-1) { + if (card->csd.write_partial) + bytes = blocks << md->block_bits; + else + bytes = blocks << 9; + spin_lock_irq(&md->lock); + ret = end_that_request_chunk(req, 1, bytes); + spin_unlock_irq(&md->lock); + } + } else if (rq_data_dir(req) != READ && + (card->host->caps & MMC_CAP_MULTIWRITE)) { spin_lock_irq(&md->lock); ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); spin_unlock_irq(&md->lock); } + mmc_card_release_host(card); + spin_lock_irq(&md->lock); while (ret) { ret = end_that_request_chunk(req, 0, diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 81c3f77f652c..08dec8d9e703 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -83,6 +83,7 @@ /* Application commands */ #define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ +#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */ #define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ #define SD_APP_SEND_SCR 51 /* adtc R1 */ -- cgit v1.2.3 From c6b0a9f87b82f25fa35206ec04b5160372eabab4 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 6 Oct 2006 00:44:05 -0700 Subject: [PATCH] knfsd: tidy up up meaning of 'buffer size' in nfsd/sunrpc There is some confusion about the meaning of 'bufsz' for a sunrpc server. In some cases it is the largest message that can be sent or received. In other cases it is the largest 'payload' that can be included in a NFS message. In either case, it is not possible for both the request and the reply to be this large. One of the request or reply may only be one page long, which fits nicely with NFS. So we remove 'bufsz' and replace it with two numbers: 'max_payload' and 'max_mesg'. Max_payload is the size that the server requests. It is used by the server to check the max size allowed on a particular connection: depending on the protocol a lower limit might be used. max_mesg is the largest single message that can be sent or received. It is calculated as the max_payload, rounded up to a multiple of PAGE_SIZE, and with PAGE_SIZE added to overhead. Only one of the request and reply may be this size. The other must be at most one page. Cc: Greg Banks Cc: "J. Bruce Fields" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfssvc.c | 2 +- include/linux/sunrpc/svc.h | 3 ++- net/sunrpc/svc.c | 17 ++++++++++------- net/sunrpc/svcsock.c | 28 ++++++++++++++-------------- 4 files changed, 27 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 6fa6340a5fb8..013b38996e64 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -217,7 +217,7 @@ int nfsd_create_serv(void) atomic_set(&nfsd_busy, 0); nfsd_serv = svc_create_pooled(&nfsd_program, - NFSD_BUFSIZE - NFSSVC_MAXBLKSIZE + nfsd_max_blksize, + nfsd_max_blksize, nfsd_last_thread, nfsd, SIG_NOCLEAN, THIS_MODULE); if (nfsd_serv == NULL) diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index d6288e89fd9d..9c9a8ad92477 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -57,7 +57,8 @@ struct svc_serv { struct svc_stat * sv_stats; /* RPC statistics */ spinlock_t sv_lock; unsigned int sv_nrthreads; /* # of server threads */ - unsigned int sv_bufsz; /* datagram buffer size */ + unsigned int sv_max_payload; /* datagram payload size */ + unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */ unsigned int sv_xdrsize; /* XDR buffer size */ struct list_head sv_permsocks; /* all permanent sockets */ diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index c2c8bb20d07f..2807fa0eab40 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -282,7 +282,10 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, serv->sv_program = prog; serv->sv_nrthreads = 1; serv->sv_stats = prog->pg_stats; - serv->sv_bufsz = bufsize? bufsize : 4096; + if (bufsize > RPCSVC_MAXPAYLOAD) + bufsize = RPCSVC_MAXPAYLOAD; + serv->sv_max_payload = bufsize? bufsize : 4096; + serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE); serv->sv_shutdown = shutdown; xdrsize = 0; while (prog) { @@ -414,9 +417,9 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size) int pages; int arghi; - if (size > RPCSVC_MAXPAYLOAD) - size = RPCSVC_MAXPAYLOAD; - pages = 2 + (size+ PAGE_SIZE -1) / PAGE_SIZE; + pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply. + * We assume one is at most one page + */ arghi = 0; BUG_ON(pages > RPCSVC_MAXPAGES); while (pages) { @@ -463,7 +466,7 @@ __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, if (!(rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL)) || !(rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL)) - || !svc_init_buffer(rqstp, serv->sv_bufsz)) + || !svc_init_buffer(rqstp, serv->sv_max_mesg)) goto out_thread; serv->sv_nrthreads++; @@ -938,8 +941,8 @@ u32 svc_max_payload(const struct svc_rqst *rqstp) if (rqstp->rq_sock->sk_sock->type == SOCK_DGRAM) max = RPCSVC_MAXPAYLOAD_UDP; - if (rqstp->rq_server->sv_bufsz < max) - max = rqstp->rq_server->sv_bufsz; + if (rqstp->rq_server->sv_max_payload < max) + max = rqstp->rq_server->sv_max_payload; return max; } EXPORT_SYMBOL_GPL(svc_max_payload); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index b39e7e2b648f..61e307cca13d 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -192,13 +192,13 @@ svc_sock_enqueue(struct svc_sock *svsk) svsk->sk_pool = pool; set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); - if (((atomic_read(&svsk->sk_reserved) + serv->sv_bufsz)*2 + if (((atomic_read(&svsk->sk_reserved) + serv->sv_max_mesg)*2 > svc_sock_wspace(svsk)) && !test_bit(SK_CLOSE, &svsk->sk_flags) && !test_bit(SK_CONN, &svsk->sk_flags)) { /* Don't enqueue while not enough space for reply */ dprintk("svc: socket %p no space, %d*2 > %ld, not enqueued\n", - svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_bufsz, + svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_max_mesg, svc_sock_wspace(svsk)); svsk->sk_pool = NULL; clear_bit(SK_BUSY, &svsk->sk_flags); @@ -220,7 +220,7 @@ svc_sock_enqueue(struct svc_sock *svsk) rqstp, rqstp->rq_sock); rqstp->rq_sock = svsk; atomic_inc(&svsk->sk_inuse); - rqstp->rq_reserved = serv->sv_bufsz; + rqstp->rq_reserved = serv->sv_max_mesg; atomic_add(rqstp->rq_reserved, &svsk->sk_reserved); BUG_ON(svsk->sk_pool != pool); wake_up(&rqstp->rq_wait); @@ -639,8 +639,8 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) * which will access the socket. */ svc_sock_setbufsize(svsk->sk_sock, - (serv->sv_nrthreads+3) * serv->sv_bufsz, - (serv->sv_nrthreads+3) * serv->sv_bufsz); + (serv->sv_nrthreads+3) * serv->sv_max_mesg, + (serv->sv_nrthreads+3) * serv->sv_max_mesg); if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk))) { svc_sock_received(svsk); @@ -749,8 +749,8 @@ svc_udp_init(struct svc_sock *svsk) * svc_udp_recvfrom will re-adjust if necessary */ svc_sock_setbufsize(svsk->sk_sock, - 3 * svsk->sk_server->sv_bufsz, - 3 * svsk->sk_server->sv_bufsz); + 3 * svsk->sk_server->sv_max_mesg, + 3 * svsk->sk_server->sv_max_mesg); set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */ set_bit(SK_CHNGBUF, &svsk->sk_flags); @@ -993,8 +993,8 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp) * as soon a a complete request arrives. */ svc_sock_setbufsize(svsk->sk_sock, - (serv->sv_nrthreads+3) * serv->sv_bufsz, - 3 * serv->sv_bufsz); + (serv->sv_nrthreads+3) * serv->sv_max_mesg, + 3 * serv->sv_max_mesg); clear_bit(SK_DATA, &svsk->sk_flags); @@ -1032,7 +1032,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp) } svsk->sk_reclen &= 0x7fffffff; dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen); - if (svsk->sk_reclen > serv->sv_bufsz) { + if (svsk->sk_reclen > serv->sv_max_mesg) { printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (large)\n", (unsigned long) svsk->sk_reclen); goto err_delete; @@ -1171,8 +1171,8 @@ svc_tcp_init(struct svc_sock *svsk) * svc_tcp_recvfrom will re-adjust if necessary */ svc_sock_setbufsize(svsk->sk_sock, - 3 * svsk->sk_server->sv_bufsz, - 3 * svsk->sk_server->sv_bufsz); + 3 * svsk->sk_server->sv_max_mesg, + 3 * svsk->sk_server->sv_max_mesg); set_bit(SK_CHNGBUF, &svsk->sk_flags); set_bit(SK_DATA, &svsk->sk_flags); @@ -1234,7 +1234,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout) /* now allocate needed pages. If we get a failure, sleep briefly */ - pages = 2 + (serv->sv_bufsz + PAGE_SIZE -1) / PAGE_SIZE; + pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE; for (i=0; i < pages ; i++) while (rqstp->rq_pages[i] == NULL) { struct page *p = alloc_page(GFP_KERNEL); @@ -1263,7 +1263,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout) if ((svsk = svc_sock_dequeue(pool)) != NULL) { rqstp->rq_sock = svsk; atomic_inc(&svsk->sk_inuse); - rqstp->rq_reserved = serv->sv_bufsz; + rqstp->rq_reserved = serv->sv_max_mesg; atomic_add(rqstp->rq_reserved, &svsk->sk_reserved); } else { /* No data pending. Go to sleep */ -- cgit v1.2.3 From a8f47c45aee6efa5ef7ec209b90681b091bd3d2c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 15:04:15 +0100 Subject: [PATCH] missing include of scatterlist.h Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/tifm.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/tifm.h b/include/linux/tifm.h index 203dd5e11ecb..dfb8052eee5e 100644 --- a/include/linux/tifm.h +++ b/include/linux/tifm.h @@ -17,6 +17,7 @@ #include #include #include +#include /* Host registers (relative to pci base address): */ enum { -- cgit v1.2.3 From cb1055fb1b79775d398038ad8dcd2c7581f141d8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Oct 2006 15:08:45 +0100 Subject: [PATCH] linux/io.h needs types.h Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/io.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/io.h b/include/linux/io.h index aa3f5af670b5..2ad96c3f0e4e 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -18,6 +18,7 @@ #ifndef _LINUX_IO_H #define _LINUX_IO_H +#include #include #include -- cgit v1.2.3 From 659564c8adfe1765476beee8d55cd18986946892 Mon Sep 17 00:00:00 2001 From: Bill Nottingham Date: Mon, 9 Oct 2006 16:10:48 -0400 Subject: [PATCH] Introduce vfs_listxattr This patch moves code out of fs/xattr.c:listxattr into a new function - vfs_listxattr. The code for vfs_listxattr was originally submitted by Bill Nottingham to Unionfs. Sorry about that. The reason for this submission is to make the listxattr code in fs/xattr.c a little cleaner (as well as to clean up some code in Unionfs.) Currently, Unionfs has vfs_listxattr defined in its code. I think that's very ugly, and I'd like to see it (re)moved. The logical place to put it, is along side of all the other vfs_*xattr functions. Overall, I think this patch is benefitial for both kernel.org kernel and Unionfs. Signed-off-by: Josef "Jeff" Sipek Acked-by: Al Viro Signed-off-by: Linus Torvalds --- fs/xattr.c | 33 +++++++++++++++++++++------------ include/linux/xattr.h | 1 + 2 files changed, 22 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/fs/xattr.c b/fs/xattr.c index c32f15b5f60f..395635100f77 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -135,6 +135,26 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size) } EXPORT_SYMBOL_GPL(vfs_getxattr); +ssize_t +vfs_listxattr(struct dentry *d, char *list, size_t size) +{ + ssize_t error; + + error = security_inode_listxattr(d); + if (error) + return error; + error = -EOPNOTSUPP; + if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { + error = d->d_inode->i_op->listxattr(d, list, size); + } else { + error = security_inode_listsecurity(d->d_inode, list, size); + if (size && error > size) + error = -ERANGE; + } + return error; +} +EXPORT_SYMBOL_GPL(vfs_listxattr); + int vfs_removexattr(struct dentry *dentry, char *name) { @@ -346,17 +366,7 @@ listxattr(struct dentry *d, char __user *list, size_t size) return -ENOMEM; } - error = security_inode_listxattr(d); - if (error) - goto out; - error = -EOPNOTSUPP; - if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { - error = d->d_inode->i_op->listxattr(d, klist, size); - } else { - error = security_inode_listsecurity(d->d_inode, klist, size); - if (size && error > size) - error = -ERANGE; - } + error = vfs_listxattr(d, klist, size); if (error > 0) { if (size && copy_to_user(list, klist, error)) error = -EFAULT; @@ -365,7 +375,6 @@ listxattr(struct dentry *d, char __user *list, size_t size) than XATTR_LIST_MAX bytes. Not possible. */ error = -E2BIG; } -out: kfree(klist); return error; } diff --git a/include/linux/xattr.h b/include/linux/xattr.h index cda8a96e2fa0..0e7f1e20ea45 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -41,6 +41,7 @@ struct xattr_handler { }; ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t); +ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); int vfs_setxattr(struct dentry *, char *, void *, size_t, int); int vfs_removexattr(struct dentry *, char *); -- cgit v1.2.3 From b0ac3f50b8f2cd992ffd36d22c82eabdf075e9c4 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 9 Oct 2006 19:13:51 -0400 Subject: [HEADERS] Put linux/config.h out of its misery. Signed-off-by: Dave Jones --- arch/powerpc/platforms/82xx/mpc82xx.c | 1 - arch/powerpc/platforms/82xx/mpc82xx_ads.c | 2 -- arch/powerpc/platforms/82xx/pq2ads.h | 2 -- arch/powerpc/sysdev/qe_lib/qe_io.c | 1 - include/linux/config.h | 9 --------- 5 files changed, 15 deletions(-) delete mode 100644 include/linux/config.h (limited to 'include/linux') diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c index 89d702de4863..0f5b30dc60da 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx.c +++ b/arch/powerpc/platforms/82xx/mpc82xx.c @@ -11,7 +11,6 @@ * option) any later version. */ -#include #include #include #include diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 0cea42a8053d..bb9acbb98176 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -12,8 +12,6 @@ * option) any later version. */ - -#include #include #include #include diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h index a7348213508f..fb2f92bcd770 100644 --- a/arch/powerpc/platforms/82xx/pq2ads.h +++ b/arch/powerpc/platforms/82xx/pq2ads.h @@ -22,8 +22,6 @@ #ifndef __MACH_ADS8260_DEFS #define __MACH_ADS8260_DEFS -#include - #include /* For our show_cpuinfo hooks. */ diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c index aea435970389..0afe6bfe3714 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_io.c +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -14,7 +14,6 @@ * option) any later version. */ -#include #include #include #include diff --git a/include/linux/config.h b/include/linux/config.h deleted file mode 100644 index 479ffb0a22d8..000000000000 --- a/include/linux/config.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _LINUX_CONFIG_H -#define _LINUX_CONFIG_H -/* This file is no longer in use and kept only for backward compatibility. - * autoconf.h is now included via -imacros on the commandline - */ -#warning Including config.h is deprecated. -#include - -#endif -- cgit v1.2.3 From 1acc04cd4c0b54ada85d0dd5d7c5efc3441261bf Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:44:37 +0100 Subject: [PATCH] dccp __user annotations Signed-off-by: Al Viro Acked-by: David S. Miller Signed-off-by: Linus Torvalds --- include/linux/dccp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index d6f4ec467a4b..53553c99cad6 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -191,7 +191,7 @@ enum { /* this structure is argument to DCCP_SOCKOPT_CHANGE_X */ struct dccp_so_feat { __u8 dccpsf_feat; - __u8 *dccpsf_val; + __u8 __user *dccpsf_val; __u8 dccpsf_len; }; -- cgit v1.2.3 From ba46df984b8e8114c3cf19c51670fab084bd4196 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:46:07 +0100 Subject: [PATCH] __user annotations: futex Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/compat.h | 2 +- include/linux/syscalls.h | 2 +- kernel/futex.c | 15 ++++++++------- kernel/futex_compat.c | 12 ++++++------ 4 files changed, 16 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/compat.h b/include/linux/compat.h index ef5cd192784c..f4ebf96f5308 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -163,7 +163,7 @@ asmlinkage long compat_sys_set_robust_list(struct compat_robust_list_head __user *head, compat_size_t len); asmlinkage long -compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr, +compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, compat_size_t __user *len_ptr); long compat_sys_semctl(int first, int second, int third, void __user *uptr); diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 3efcfc7e9c6c..b0ace3fd7eb9 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -593,7 +593,7 @@ asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags); asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, unsigned int flags); asmlinkage long sys_get_robust_list(int pid, - struct robust_list_head __user **head_ptr, + struct robust_list_head __user * __user *head_ptr, size_t __user *len_ptr); asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len); diff --git a/kernel/futex.c b/kernel/futex.c index 4aaf91951a43..b364e0026191 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1612,10 +1612,10 @@ sys_set_robust_list(struct robust_list_head __user *head, * @len_ptr: pointer to a length field, the kernel fills in the header size */ asmlinkage long -sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr, +sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr, size_t __user *len_ptr) { - struct robust_list_head *head; + struct robust_list_head __user *head; unsigned long ret; if (!pid) @@ -1694,14 +1694,15 @@ retry: * Fetch a robust-list pointer. Bit 0 signals PI futexes: */ static inline int fetch_robust_entry(struct robust_list __user **entry, - struct robust_list __user **head, int *pi) + struct robust_list __user * __user *head, + int *pi) { unsigned long uentry; - if (get_user(uentry, (unsigned long *)head)) + if (get_user(uentry, (unsigned long __user *)head)) return -EFAULT; - *entry = (void *)(uentry & ~1UL); + *entry = (void __user *)(uentry & ~1UL); *pi = uentry & 1; return 0; @@ -1739,7 +1740,7 @@ void exit_robust_list(struct task_struct *curr) return; if (pending) - handle_futex_death((void *)pending + futex_offset, curr, pip); + handle_futex_death((void __user *)pending + futex_offset, curr, pip); while (entry != &head->list) { /* @@ -1747,7 +1748,7 @@ void exit_robust_list(struct task_struct *curr) * don't process it twice: */ if (entry != pending) - if (handle_futex_death((void *)entry + futex_offset, + if (handle_futex_death((void __user *)entry + futex_offset, curr, pi)) return; /* diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index c5cca3f65cb7..50f24eea6cd0 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c @@ -18,7 +18,7 @@ */ static inline int fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry, - compat_uptr_t *head, int *pi) + compat_uptr_t __user *head, int *pi) { if (get_user(*uentry, head)) return -EFAULT; @@ -62,7 +62,7 @@ void compat_exit_robust_list(struct task_struct *curr) &head->list_op_pending, &pip)) return; if (upending) - handle_futex_death((void *)pending + futex_offset, curr, pip); + handle_futex_death((void __user *)pending + futex_offset, curr, pip); while (compat_ptr(uentry) != &head->list) { /* @@ -70,7 +70,7 @@ void compat_exit_robust_list(struct task_struct *curr) * dont process it twice: */ if (entry != pending) - if (handle_futex_death((void *)entry + futex_offset, + if (handle_futex_death((void __user *)entry + futex_offset, curr, pi)) return; @@ -78,7 +78,7 @@ void compat_exit_robust_list(struct task_struct *curr) * Fetch the next entry in the list: */ if (fetch_robust_entry(&uentry, &entry, - (compat_uptr_t *)&entry->next, &pi)) + (compat_uptr_t __user *)&entry->next, &pi)) return; /* * Avoid excessively long or circular lists: @@ -103,10 +103,10 @@ compat_sys_set_robust_list(struct compat_robust_list_head __user *head, } asmlinkage long -compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr, +compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, compat_size_t __user *len_ptr) { - struct compat_robust_list_head *head; + struct compat_robust_list_head __user *head; unsigned long ret; if (!pid) -- cgit v1.2.3 From fb136e97840872638cb08588c4c9b9fff7f7c456 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:46:47 +0100 Subject: [PATCH] fix misannotation in ioc4.h Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/ioc4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/ioc4.h b/include/linux/ioc4.h index de73a3289cc2..51e2b9fb6372 100644 --- a/include/linux/ioc4.h +++ b/include/linux/ioc4.h @@ -157,7 +157,7 @@ struct ioc4_driver_data { unsigned long idd_bar0; struct pci_dev *idd_pdev; const struct pci_device_id *idd_pci_id; - struct __iomem ioc4_misc_regs *idd_misc_regs; + struct ioc4_misc_regs __iomem *idd_misc_regs; unsigned long count_period; void *idd_serial_data; unsigned int idd_variant; -- cgit v1.2.3 From 29756fa3287ff702535e459e7ca8c6038f6e9ae3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 10 Oct 2006 22:47:27 +0100 Subject: [PATCH] trivial iomem annotations: istallion Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/char/istallion.c | 58 +++++++++++++++++++++++------------------------ include/linux/istallion.h | 4 ++-- 2 files changed, 31 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index d6e031542c6b..ffdf9df1a67a 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -686,37 +686,37 @@ static stlibrd_t *stli_allocbrd(void); static void stli_ecpinit(stlibrd_t *brdp); static void stli_ecpenable(stlibrd_t *brdp); static void stli_ecpdisable(stlibrd_t *brdp); -static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); +static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); static void stli_ecpreset(stlibrd_t *brdp); static void stli_ecpintr(stlibrd_t *brdp); static void stli_ecpeiinit(stlibrd_t *brdp); static void stli_ecpeienable(stlibrd_t *brdp); static void stli_ecpeidisable(stlibrd_t *brdp); -static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line); +static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line); static void stli_ecpeireset(stlibrd_t *brdp); static void stli_ecpmcenable(stlibrd_t *brdp); static void stli_ecpmcdisable(stlibrd_t *brdp); -static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); +static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); static void stli_ecpmcreset(stlibrd_t *brdp); static void stli_ecppciinit(stlibrd_t *brdp); -static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line); +static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line); static void stli_ecppcireset(stlibrd_t *brdp); static void stli_onbinit(stlibrd_t *brdp); static void stli_onbenable(stlibrd_t *brdp); static void stli_onbdisable(stlibrd_t *brdp); -static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); +static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); static void stli_onbreset(stlibrd_t *brdp); static void stli_onbeinit(stlibrd_t *brdp); static void stli_onbeenable(stlibrd_t *brdp); static void stli_onbedisable(stlibrd_t *brdp); -static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line); +static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line); static void stli_onbereset(stlibrd_t *brdp); static void stli_bbyinit(stlibrd_t *brdp); -static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line); +static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line); static void stli_bbyreset(stlibrd_t *brdp); static void stli_stalinit(stlibrd_t *brdp); -static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); +static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); static void stli_stalreset(stlibrd_t *brdp); static stliport_t *stli_getport(int brdnr, int panelnr, int portnr); @@ -1566,7 +1566,7 @@ static void stli_flushchars(struct tty_struct *tty) len = MIN(len, cooksize); count = 0; - shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset); + shbuf = EBRDGETMEMPTR(brdp, portp->txoffset); buf = stli_txcookbuf; while (len > 0) { @@ -2948,9 +2948,9 @@ static void stli_ecpdisable(stlibrd_t *brdp) /*****************************************************************************/ -static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) { - void *ptr; + void __iomem *ptr; unsigned char val; if (offset > brdp->memsize) { @@ -3022,9 +3022,9 @@ static void stli_ecpeidisable(stlibrd_t *brdp) /*****************************************************************************/ -static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line) { - void *ptr; + void __iomem *ptr; unsigned char val; if (offset > brdp->memsize) { @@ -3074,9 +3074,9 @@ static void stli_ecpmcdisable(stlibrd_t *brdp) /*****************************************************************************/ -static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) { - void *ptr; + void __iomem *ptr; unsigned char val; if (offset > brdp->memsize) { @@ -3119,9 +3119,9 @@ static void stli_ecppciinit(stlibrd_t *brdp) /*****************************************************************************/ -static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line) { - void *ptr; + void __iomem *ptr; unsigned char val; if (offset > brdp->memsize) { @@ -3185,9 +3185,9 @@ static void stli_onbdisable(stlibrd_t *brdp) /*****************************************************************************/ -static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) { - void *ptr; + void __iomem *ptr; if (offset > brdp->memsize) { printk(KERN_ERR "STALLION: shared memory pointer=%x out of " @@ -3250,9 +3250,9 @@ static void stli_onbedisable(stlibrd_t *brdp) /*****************************************************************************/ -static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line) { - void *ptr; + void __iomem *ptr; unsigned char val; if (offset > brdp->memsize) { @@ -3300,9 +3300,9 @@ static void stli_bbyinit(stlibrd_t *brdp) /*****************************************************************************/ -static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line) { - void *ptr; + void __iomem *ptr; unsigned char val; BUG_ON(offset > brdp->memsize); @@ -3337,7 +3337,7 @@ static void stli_stalinit(stlibrd_t *brdp) /*****************************************************************************/ -static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) { BUG_ON(offset > brdp->memsize); return brdp->membase + (offset % STAL_PAGESIZE); @@ -3876,7 +3876,7 @@ static int stli_eisamemprobe(stlibrd_t *brdp) continue; if (brdp->brdtype == BRD_ECPE) { - ecpsigp = (cdkecpsig_t __iomem *) stli_ecpeigetmemptr(brdp, + ecpsigp = stli_ecpeigetmemptr(brdp, CDK_SIGADDR, __LINE__); memcpy_fromio(&ecpsig, ecpsigp, sizeof(cdkecpsig_t)); if (ecpsig.magic == cpu_to_le32(ECP_MAGIC)) @@ -4184,7 +4184,7 @@ static int stli_initbrds(void) static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp) { unsigned long flags; - void *memptr; + void __iomem *memptr; stlibrd_t *brdp; int brdnr, size, n; void *p; @@ -4214,7 +4214,7 @@ static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, lof while (size > 0) { spin_lock_irqsave(&brd_lock, flags); EBRDENABLE(brdp); - memptr = (void *) EBRDGETMEMPTR(brdp, off); + memptr = EBRDGETMEMPTR(brdp, off); n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize))); n = MIN(n, PAGE_SIZE); memcpy_fromio(p, memptr, n); @@ -4247,7 +4247,7 @@ out: static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp) { unsigned long flags; - void *memptr; + void __iomem *memptr; stlibrd_t *brdp; char __user *chbuf; int brdnr, size, n; @@ -4287,7 +4287,7 @@ static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t cou } spin_lock_irqsave(&brd_lock, flags); EBRDENABLE(brdp); - memptr = (void *) EBRDGETMEMPTR(brdp, off); + memptr = EBRDGETMEMPTR(brdp, off); memcpy_toio(memptr, p, n); EBRDDISABLE(brdp); spin_unlock_irqrestore(&brd_lock, flags); diff --git a/include/linux/istallion.h b/include/linux/istallion.h index 1f996621bc9c..b55e2a035605 100644 --- a/include/linux/istallion.h +++ b/include/linux/istallion.h @@ -100,7 +100,7 @@ typedef struct stlibrd { unsigned int iobase; int iosize; unsigned long memaddr; - void *membase; + void __iomem *membase; int memsize; int pagesize; int hostoffset; @@ -113,7 +113,7 @@ typedef struct stlibrd { void (*enable)(struct stlibrd *brdp); void (*reenable)(struct stlibrd *brdp); void (*disable)(struct stlibrd *brdp); - char *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line); + void __iomem *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line); void (*intr)(struct stlibrd *brdp); void (*reset)(struct stlibrd *brdp); stliport_t *ports[STL_MAXPORTS]; -- cgit v1.2.3 From 56052d525a05ba9e53d4f11be2d5deee64924514 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 1 Dec 2005 17:10:40 -0500 Subject: [PATCH] cdrom: add endianness annotations Signed-off-by: Alexey Dobriyan Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/cdrom/cdrom.c | 6 +++--- include/linux/cdrom.h | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 2a0c50d84fc5..7ea0f48f8fa6 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -703,7 +703,7 @@ static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi) { struct packet_command cgc; char buffer[16]; - __u16 *feature_code; + __be16 *feature_code; int ret; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); @@ -716,7 +716,7 @@ static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi) if ((ret = cdi->ops->generic_packet(cdi, &cgc))) return ret; - feature_code = (__u16 *) &buffer[sizeof(struct feature_header)]; + feature_code = (__be16 *) &buffer[sizeof(struct feature_header)]; if (be16_to_cpu(*feature_code) == CDF_HWDM) return 0; @@ -2963,7 +2963,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, how much data is available for transfer. buffer[1] is unfortunately ambigious and the only reliable way seem to be to simply skip over the block descriptor... */ - offset = 8 + be16_to_cpu(*(unsigned short *)(buffer+6)); + offset = 8 + be16_to_cpu(*(__be16 *)(buffer+6)); if (offset + 16 > sizeof(buffer)) return -E2BIG; diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h index 3c9b0bc05123..bbbe7b4da0bb 100644 --- a/include/linux/cdrom.h +++ b/include/linux/cdrom.h @@ -749,7 +749,7 @@ struct request_sense { #define MRW_MODE_PC 0x03 struct mrw_feature_desc { - __u16 feature_code; + __be16 feature_code; #if defined(__BIG_ENDIAN_BITFIELD) __u8 reserved1 : 2; __u8 feature_version : 4; @@ -776,7 +776,7 @@ struct mrw_feature_desc { /* cf. mmc4r02g.pdf 5.3.10 Random Writable Feature (0020h) pg 197 of 635 */ struct rwrt_feature_desc { - __u16 feature_code; + __be16 feature_code; #if defined(__BIG_ENDIAN_BITFIELD) __u8 reserved1 : 2; __u8 feature_version : 4; @@ -803,7 +803,7 @@ struct rwrt_feature_desc { }; typedef struct { - __u16 disc_information_length; + __be16 disc_information_length; #if defined(__BIG_ENDIAN_BITFIELD) __u8 reserved1 : 3; __u8 erasable : 1; @@ -849,7 +849,7 @@ typedef struct { } disc_information; typedef struct { - __u16 track_information_length; + __be16 track_information_length; __u8 track_lsb; __u8 session_lsb; __u8 reserved1; @@ -880,12 +880,12 @@ typedef struct { __u8 lra_v : 1; __u8 reserved3 : 6; #endif - __u32 track_start; - __u32 next_writable; - __u32 free_blocks; - __u32 fixed_packet_size; - __u32 track_size; - __u32 last_rec_address; + __be32 track_start; + __be32 next_writable; + __be32 free_blocks; + __be32 fixed_packet_size; + __be32 track_size; + __be32 last_rec_address; } track_information; struct feature_header { @@ -896,12 +896,12 @@ struct feature_header { }; struct mode_page_header { - __u16 mode_data_length; + __be16 mode_data_length; __u8 medium_type; __u8 reserved1; __u8 reserved2; __u8 reserved3; - __u16 desc_length; + __be16 desc_length; }; #ifdef __KERNEL__ @@ -1106,7 +1106,7 @@ typedef struct { #endif __u8 session_format; __u8 reserved6; - __u32 packet_size; + __be32 packet_size; __u16 audio_pause; __u8 mcn[16]; __u8 isrc[16]; @@ -1151,7 +1151,7 @@ typedef struct { } rpc_state_t; struct event_header { - __u16 data_len; + __be16 data_len; #if defined(__BIG_ENDIAN_BITFIELD) __u8 nea : 1; __u8 reserved1 : 4; -- cgit v1.2.3 From 6ca1584173d0320f47464092eb180a17259cc3f9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 24 Dec 2005 14:32:38 -0500 Subject: [PATCH] smbfs endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/smb_fs.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h index 367d6c3e8ed4..13b3af547864 100644 --- a/include/linux/smb_fs.h +++ b/include/linux/smb_fs.h @@ -43,17 +43,17 @@ static inline struct smb_inode_info *SMB_I(struct inode *inode) /* macro names are short for word, double-word, long value (?) */ #define WVAL(buf,pos) \ - (le16_to_cpu(get_unaligned((u16 *)((u8 *)(buf) + (pos))))) + (le16_to_cpu(get_unaligned((__le16 *)((u8 *)(buf) + (pos))))) #define DVAL(buf,pos) \ - (le32_to_cpu(get_unaligned((u32 *)((u8 *)(buf) + (pos))))) + (le32_to_cpu(get_unaligned((__le32 *)((u8 *)(buf) + (pos))))) #define LVAL(buf,pos) \ - (le64_to_cpu(get_unaligned((u64 *)((u8 *)(buf) + (pos))))) + (le64_to_cpu(get_unaligned((__le64 *)((u8 *)(buf) + (pos))))) #define WSET(buf,pos,val) \ - put_unaligned(cpu_to_le16((u16)(val)), (u16 *)((u8 *)(buf) + (pos))) + put_unaligned(cpu_to_le16((u16)(val)), (__le16 *)((u8 *)(buf) + (pos))) #define DSET(buf,pos,val) \ - put_unaligned(cpu_to_le32((u32)(val)), (u32 *)((u8 *)(buf) + (pos))) + put_unaligned(cpu_to_le32((u32)(val)), (__le32 *)((u8 *)(buf) + (pos))) #define LSET(buf,pos,val) \ - put_unaligned(cpu_to_le64((u64)(val)), (u64 *)((u8 *)(buf) + (pos))) + put_unaligned(cpu_to_le64((u64)(val)), (__le64 *)((u8 *)(buf) + (pos))) /* where to find the base of the SMB packet proper */ #define smb_base(buf) ((u8 *)(((u8 *)(buf))+4)) -- cgit v1.2.3 From d136fe7243081a45a141bb297a7b7a627ab60fa9 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 28 Dec 2005 22:27:10 +0300 Subject: [PATCH] Finish annotations of struct vlan_ethhdr Signed-off-by: Alexey Dobriyan Signed-off-by: Al Viro Acked-by: David S. Miller Signed-off-by: Linus Torvalds --- include/linux/if_vlan.h | 2 +- net/8021q/vlan_dev.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index ab2740832742..35cb38573583 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -44,7 +44,7 @@ struct vlan_ethhdr { unsigned char h_source[ETH_ALEN]; /* source ether addr */ __be16 h_vlan_proto; /* Should always be 0x8100 */ __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */ - unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ + __be16 h_vlan_encapsulated_proto; /* packet type ID field (or len) */ }; #include diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index da9cfe927158..60a508eb1945 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -62,7 +62,7 @@ int vlan_dev_rebuild_header(struct sk_buff *skb) default: printk(VLAN_DBG "%s: unable to resolve type %X addresses.\n", - dev->name, (int)veth->h_vlan_encapsulated_proto); + dev->name, ntohs(veth->h_vlan_encapsulated_proto)); memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); break; -- cgit v1.2.3 From 44aa5359be589f9cbe9cf0d5c97e22b27a04c7d3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Aug 2006 01:54:30 -0400 Subject: [PATCH] ufs endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/ufs/util.c | 14 ++++++-------- include/linux/ufs_fs.h | 10 +++++++++- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/fs/ufs/util.c b/fs/ufs/util.c index 22f820a9b15c..17437574f79c 100644 --- a/fs/ufs/util.c +++ b/fs/ufs/util.c @@ -184,14 +184,13 @@ void _ubh_memcpyubh_(struct ufs_sb_private_info * uspi, dev_t ufs_get_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi) { - __fs32 fs32; + __u32 fs32; dev_t dev; if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86) - fs32 = ufsi->i_u1.i_data[1]; + fs32 = fs32_to_cpu(sb, ufsi->i_u1.i_data[1]); else - fs32 = ufsi->i_u1.i_data[0]; - fs32 = fs32_to_cpu(sb, fs32); + fs32 = fs32_to_cpu(sb, ufsi->i_u1.i_data[0]); switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { case UFS_ST_SUNx86: case UFS_ST_SUN: @@ -212,7 +211,7 @@ ufs_get_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi) void ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev) { - __fs32 fs32; + __u32 fs32; switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { case UFS_ST_SUNx86: @@ -227,11 +226,10 @@ ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev fs32 = old_encode_dev(dev); break; } - fs32 = cpu_to_fs32(sb, fs32); if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86) - ufsi->i_u1.i_data[1] = fs32; + ufsi->i_u1.i_data[1] = cpu_to_fs32(sb, fs32); else - ufsi->i_u1.i_data[0] = fs32; + ufsi->i_u1.i_data[0] = cpu_to_fs32(sb, fs32); } /** diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h index fc62887c5206..61eef508b041 100644 --- a/include/linux/ufs_fs.h +++ b/include/linux/ufs_fs.h @@ -351,6 +351,14 @@ struct ufs2_csum_total { __fs64 cs_spare[3]; /* future expansion */ }; +struct ufs_csum_core { + __u64 cs_ndir; /* number of directories */ + __u64 cs_nbfree; /* number of free blocks */ + __u64 cs_nifree; /* number of free inodes */ + __u64 cs_nffree; /* number of free frags */ + __u64 cs_numclusters; /* number of free clusters */ +}; + /* * File system flags */ @@ -715,7 +723,7 @@ struct ufs_cg_private_info { struct ufs_sb_private_info { struct ufs_buffer_head s_ubh; /* buffer containing super block */ - struct ufs2_csum_total cs_total; + struct ufs_csum_core cs_total; __u32 s_sblkno; /* offset of super-blocks in filesys */ __u32 s_cblkno; /* offset of cg-block in filesys */ __u32 s_iblkno; /* offset of inode-blocks in filesys */ -- cgit v1.2.3 From 4dfbb9d8c6cbfc32faa5c71145bd2a43e1f8237c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 11 Oct 2006 01:45:14 -0400 Subject: Lockdep: add lockdep_set_class_and_subclass() and lockdep_set_subclass() This annotation makes it possible to assign a subclass on lock init. This annotation is meant to reduce the _nested() annotations by assigning a default subclass. One could do without this annotation and rely on lockdep_set_class() exclusively, but that would require a manual stack of struct lock_class_key objects. Signed-off-by: Peter Zijlstra Signed-off-by: Dmitry Torokhov --- include/linux/lockdep.h | 15 +++++++++++---- kernel/lockdep.c | 10 ++++++---- kernel/mutex-debug.c | 2 +- lib/rwsem-spinlock.c | 2 +- lib/rwsem.c | 2 +- lib/spinlock_debug.c | 4 ++-- net/core/sock.c | 2 +- 7 files changed, 23 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 1314ca0f29be..14fec2a23b2e 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -202,7 +202,7 @@ extern int lockdep_internal(void); */ extern void lockdep_init_map(struct lockdep_map *lock, const char *name, - struct lock_class_key *key); + struct lock_class_key *key, int subclass); /* * Reinitialize a lock key - for cases where there is special locking or @@ -211,9 +211,14 @@ extern void lockdep_init_map(struct lockdep_map *lock, const char *name, * or they are too narrow (they suffer from a false class-split): */ #define lockdep_set_class(lock, key) \ - lockdep_init_map(&(lock)->dep_map, #key, key) + lockdep_init_map(&(lock)->dep_map, #key, key, 0) #define lockdep_set_class_and_name(lock, key, name) \ - lockdep_init_map(&(lock)->dep_map, name, key) + lockdep_init_map(&(lock)->dep_map, name, key, 0) +#define lockdep_set_class_and_subclass(lock, key, sub) \ + lockdep_init_map(&(lock)->dep_map, #key, key, sub) +#define lockdep_set_subclass(lock, sub) \ + lockdep_init_map(&(lock)->dep_map, #lock, \ + (lock)->dep_map.key, sub) /* * Acquire a lock. @@ -257,10 +262,12 @@ static inline int lockdep_internal(void) # define lock_release(l, n, i) do { } while (0) # define lockdep_init() do { } while (0) # define lockdep_info() do { } while (0) -# define lockdep_init_map(lock, name, key) do { (void)(key); } while (0) +# define lockdep_init_map(lock, name, key, sub) do { (void)(key); } while (0) # define lockdep_set_class(lock, key) do { (void)(key); } while (0) # define lockdep_set_class_and_name(lock, key, name) \ do { (void)(key); } while (0) +#define lockdep_set_class_and_subclass(lock, key, sub) \ + do { (void)(key); } while (0) # define INIT_LOCKDEP # define lockdep_reset() do { debug_locks = 1; } while (0) # define lockdep_free_key_range(start, size) do { } while (0) diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 4c0553461000..ba7156ac70c1 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -1177,7 +1177,7 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass) * itself, so actual lookup of the hash should be once per lock object. */ static inline struct lock_class * -register_lock_class(struct lockdep_map *lock, unsigned int subclass) +register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) { struct lockdep_subclass_key *key; struct list_head *hash_head; @@ -1249,7 +1249,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass) out_unlock_set: __raw_spin_unlock(&hash_lock); - if (!subclass) + if (!subclass || force) lock->class_cache = class; DEBUG_LOCKS_WARN_ON(class->subclass != subclass); @@ -1937,7 +1937,7 @@ void trace_softirqs_off(unsigned long ip) * Initialize a lock instance's lock-class mapping info: */ void lockdep_init_map(struct lockdep_map *lock, const char *name, - struct lock_class_key *key) + struct lock_class_key *key, int subclass) { if (unlikely(!debug_locks)) return; @@ -1957,6 +1957,8 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name, lock->name = name; lock->key = key; lock->class_cache = NULL; + if (subclass) + register_lock_class(lock, subclass, 1); } EXPORT_SYMBOL_GPL(lockdep_init_map); @@ -1995,7 +1997,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, * Not cached yet or subclass? */ if (unlikely(!class)) { - class = register_lock_class(lock, subclass); + class = register_lock_class(lock, subclass, 0); if (!class) return 0; } diff --git a/kernel/mutex-debug.c b/kernel/mutex-debug.c index e3203c654dda..18651641a7b5 100644 --- a/kernel/mutex-debug.c +++ b/kernel/mutex-debug.c @@ -91,7 +91,7 @@ void debug_mutex_init(struct mutex *lock, const char *name, * Make sure we are not reinitializing a held lock: */ debug_check_no_locks_freed((void *)lock, sizeof(*lock)); - lockdep_init_map(&lock->dep_map, name, key); + lockdep_init_map(&lock->dep_map, name, key, 0); #endif lock->owner = NULL; lock->magic = lock; diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c index db4fed74b940..c4cfd6c0342f 100644 --- a/lib/rwsem-spinlock.c +++ b/lib/rwsem-spinlock.c @@ -28,7 +28,7 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name, * Make sure we are not reinitializing a held semaphore: */ debug_check_no_locks_freed((void *)sem, sizeof(*sem)); - lockdep_init_map(&sem->dep_map, name, key); + lockdep_init_map(&sem->dep_map, name, key, 0); #endif sem->activity = 0; spin_lock_init(&sem->wait_lock); diff --git a/lib/rwsem.c b/lib/rwsem.c index 901d0e7da892..cdb4e3d05607 100644 --- a/lib/rwsem.c +++ b/lib/rwsem.c @@ -19,7 +19,7 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name, * Make sure we are not reinitializing a held semaphore: */ debug_check_no_locks_freed((void *)sem, sizeof(*sem)); - lockdep_init_map(&sem->dep_map, name, key); + lockdep_init_map(&sem->dep_map, name, key, 0); #endif sem->count = RWSEM_UNLOCKED_VALUE; spin_lock_init(&sem->wait_lock); diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c index dafaf1de2491..b6c4f898197c 100644 --- a/lib/spinlock_debug.c +++ b/lib/spinlock_debug.c @@ -20,7 +20,7 @@ void __spin_lock_init(spinlock_t *lock, const char *name, * Make sure we are not reinitializing a held lock: */ debug_check_no_locks_freed((void *)lock, sizeof(*lock)); - lockdep_init_map(&lock->dep_map, name, key); + lockdep_init_map(&lock->dep_map, name, key, 0); #endif lock->raw_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; lock->magic = SPINLOCK_MAGIC; @@ -38,7 +38,7 @@ void __rwlock_init(rwlock_t *lock, const char *name, * Make sure we are not reinitializing a held lock: */ debug_check_no_locks_freed((void *)lock, sizeof(*lock)); - lockdep_init_map(&lock->dep_map, name, key); + lockdep_init_map(&lock->dep_map, name, key, 0); #endif lock->raw_lock = (raw_rwlock_t) __RAW_RW_LOCK_UNLOCKED; lock->magic = RWLOCK_MAGIC; diff --git a/net/core/sock.c b/net/core/sock.c index b77e155cbe6c..d472db4776c3 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -823,7 +823,7 @@ static void inline sock_lock_init(struct sock *sk) af_family_slock_key_strings[sk->sk_family]); lockdep_init_map(&sk->sk_lock.dep_map, af_family_key_strings[sk->sk_family], - af_family_keys + sk->sk_family); + af_family_keys + sk->sk_family, 0); } /** -- cgit v1.2.3 From 88aa0103e408616e433c209e80169ab8d6eda99e Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 11 Oct 2006 01:45:31 -0400 Subject: Input: serio - add lockdep annotations Signed-off-by: Jiri Kosina Acked-by: Peter Zijlstra Signed-off-by: Dmitry Torokhov --- drivers/input/serio/libps2.c | 3 ++- drivers/input/serio/serio.c | 6 +++++- include/linux/serio.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index dcb16b5cbec0..e5b1b60757bb 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -189,7 +189,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) return -1; } - mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING); + mutex_lock(&ps2dev->cmd_mutex); serio_pause_rx(ps2dev->serio); ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; @@ -296,6 +296,7 @@ EXPORT_SYMBOL(ps2_schedule_command); void ps2_init(struct ps2dev *ps2dev, struct serio *serio) { mutex_init(&ps2dev->cmd_mutex); + lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth); init_waitqueue_head(&ps2dev->wait); ps2dev->serio = serio; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 960fae3c3cea..480fdc5d20b3 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -538,8 +538,12 @@ static void serio_init_port(struct serio *serio) "serio%ld", (long)atomic_inc_return(&serio_no) - 1); serio->dev.bus = &serio_bus; serio->dev.release = serio_release_port; - if (serio->parent) + if (serio->parent) { serio->dev.parent = &serio->parent->dev; + serio->depth = serio->parent->depth + 1; + } else + serio->depth = 0; + lockdep_set_subclass(&serio->lock, serio->depth); } /* diff --git a/include/linux/serio.h b/include/linux/serio.h index 3a697cc6ecae..b99c5ca9708d 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -41,6 +41,7 @@ struct serio { void (*stop)(struct serio *); struct serio *parent, *child; + unsigned int depth; /* level of nesting in serio hierarchy */ struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */ struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */ -- cgit v1.2.3 From 502717f4e112b18d9c37753a32f675bec9f2838b Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" Date: Wed, 11 Oct 2006 01:20:46 -0700 Subject: [PATCH] hugetlb: fix linked list corruption in unmap_hugepage_range() commit fe1668ae5bf0145014c71797febd9ad5670d5d05 causes kernel to oops with libhugetlbfs test suite. The problem is that hugetlb pages can be shared by multiple mappings. Multiple threads can fight over page->lru in the unmap path and bad things happen. We now serialize __unmap_hugepage_range to void concurrent linked list manipulation. Such serialization is also needed for shared page table page on hugetlb area. This patch will fixed the bug and also serve as a prepatch for shared page table. Signed-off-by: Ken Chen Cc: Hugh Dickins Cc: David Gibson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hugetlbfs/inode.c | 2 +- include/linux/hugetlb.h | 1 + mm/hugetlb.c | 22 ++++++++++++++++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 5e03b2f67b93..4ee3f006b861 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -293,7 +293,7 @@ hugetlb_vmtruncate_list(struct prio_tree_root *root, unsigned long h_pgoff) if (h_vm_pgoff >= h_pgoff) v_offset = 0; - unmap_hugepage_range(vma, + __unmap_hugepage_range(vma, vma->vm_start + v_offset, vma->vm_end); } } diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index c25a38d8f600..5081d27bfa27 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -17,6 +17,7 @@ int hugetlb_sysctl_handler(struct ctl_table *, int, struct file *, void __user * int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *); int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int); void unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long); +void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long); int hugetlb_prefault(struct address_space *, struct vm_area_struct *); int hugetlb_report_meminfo(char *); int hugetlb_report_node_meminfo(int, char *); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 1d709ff528e1..2dbec90dc3ba 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -356,8 +356,8 @@ nomem: return -ENOMEM; } -void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, - unsigned long end) +void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) { struct mm_struct *mm = vma->vm_mm; unsigned long address; @@ -398,6 +398,24 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, } } +void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + /* + * It is undesirable to test vma->vm_file as it should be non-null + * for valid hugetlb area. However, vm_file will be NULL in the error + * cleanup path of do_mmap_pgoff. When hugetlbfs ->mmap method fails, + * do_mmap_pgoff() nullifies vma->vm_file before calling this function + * to clean up. Since no pte has actually been setup, it is safe to + * do nothing in this case. + */ + if (vma->vm_file) { + spin_lock(&vma->vm_file->f_mapping->i_mmap_lock); + __unmap_hugepage_range(vma, start, end); + spin_unlock(&vma->vm_file->f_mapping->i_mmap_lock); + } +} + static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *ptep, pte_t pte) { -- cgit v1.2.3 From ac27a0ec112a089f1a5102bc8dffc79c8c815571 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 11 Oct 2006 01:20:50 -0700 Subject: [PATCH] ext4: initial copy of files from ext3 Start of the ext4 patch series. See Documentation/filesystems/ext4.txt for details. This is a simple copy of the files in fs/ext3 to fs/ext4 and /usr/incude/linux/ext3* to /usr/include/ex4* Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/Makefile | 12 + fs/ext4/acl.c | 551 ++++++++ fs/ext4/acl.h | 81 ++ fs/ext4/balloc.c | 1818 +++++++++++++++++++++++++ fs/ext4/bitmap.c | 32 + fs/ext4/dir.c | 518 +++++++ fs/ext4/file.c | 139 ++ fs/ext4/fsync.c | 88 ++ fs/ext4/hash.c | 152 +++ fs/ext4/ialloc.c | 758 +++++++++++ fs/ext4/inode.c | 3219 ++++++++++++++++++++++++++++++++++++++++++++ fs/ext4/ioctl.c | 307 +++++ fs/ext4/namei.c | 2397 +++++++++++++++++++++++++++++++++ fs/ext4/namei.h | 8 + fs/ext4/resize.c | 1042 ++++++++++++++ fs/ext4/super.c | 2754 +++++++++++++++++++++++++++++++++++++ fs/ext4/symlink.c | 54 + fs/ext4/xattr.c | 1317 ++++++++++++++++++ fs/ext4/xattr.h | 145 ++ fs/ext4/xattr_security.c | 77 ++ fs/ext4/xattr_trusted.c | 62 + fs/ext4/xattr_user.c | 64 + include/linux/ext4_fs.h | 885 ++++++++++++ include/linux/ext4_fs_i.h | 147 ++ include/linux/ext4_fs_sb.h | 83 ++ include/linux/ext4_jbd.h | 268 ++++ 26 files changed, 16978 insertions(+) create mode 100644 fs/ext4/Makefile create mode 100644 fs/ext4/acl.c create mode 100644 fs/ext4/acl.h create mode 100644 fs/ext4/balloc.c create mode 100644 fs/ext4/bitmap.c create mode 100644 fs/ext4/dir.c create mode 100644 fs/ext4/file.c create mode 100644 fs/ext4/fsync.c create mode 100644 fs/ext4/hash.c create mode 100644 fs/ext4/ialloc.c create mode 100644 fs/ext4/inode.c create mode 100644 fs/ext4/ioctl.c create mode 100644 fs/ext4/namei.c create mode 100644 fs/ext4/namei.h create mode 100644 fs/ext4/resize.c create mode 100644 fs/ext4/super.c create mode 100644 fs/ext4/symlink.c create mode 100644 fs/ext4/xattr.c create mode 100644 fs/ext4/xattr.h create mode 100644 fs/ext4/xattr_security.c create mode 100644 fs/ext4/xattr_trusted.c create mode 100644 fs/ext4/xattr_user.c create mode 100644 include/linux/ext4_fs.h create mode 100644 include/linux/ext4_fs_i.h create mode 100644 include/linux/ext4_fs_sb.h create mode 100644 include/linux/ext4_jbd.h (limited to 'include/linux') diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile new file mode 100644 index 000000000000..704cd44a40c2 --- /dev/null +++ b/fs/ext4/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the linux ext3-filesystem routines. +# + +obj-$(CONFIG_EXT3_FS) += ext3.o + +ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ + ioctl.o namei.o super.o symlink.o hash.o resize.o + +ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o +ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o +ext3-$(CONFIG_EXT3_FS_SECURITY) += xattr_security.o diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c new file mode 100644 index 000000000000..1e5038d9a01b --- /dev/null +++ b/fs/ext4/acl.c @@ -0,0 +1,551 @@ +/* + * linux/fs/ext3/acl.c + * + * Copyright (C) 2001-2003 Andreas Gruenbacher, + */ + +#include +#include +#include +#include +#include +#include +#include +#include "xattr.h" +#include "acl.h" + +/* + * Convert from filesystem to in-memory representation. + */ +static struct posix_acl * +ext3_acl_from_disk(const void *value, size_t size) +{ + const char *end = (char *)value + size; + int n, count; + struct posix_acl *acl; + + if (!value) + return NULL; + if (size < sizeof(ext3_acl_header)) + return ERR_PTR(-EINVAL); + if (((ext3_acl_header *)value)->a_version != + cpu_to_le32(EXT3_ACL_VERSION)) + return ERR_PTR(-EINVAL); + value = (char *)value + sizeof(ext3_acl_header); + count = ext3_acl_count(size); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + acl = posix_acl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + for (n=0; n < count; n++) { + ext3_acl_entry *entry = + (ext3_acl_entry *)value; + if ((char *)value + sizeof(ext3_acl_entry_short) > end) + goto fail; + acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); + acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); + switch(acl->a_entries[n].e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + value = (char *)value + + sizeof(ext3_acl_entry_short); + acl->a_entries[n].e_id = ACL_UNDEFINED_ID; + break; + + case ACL_USER: + case ACL_GROUP: + value = (char *)value + sizeof(ext3_acl_entry); + if ((char *)value > end) + goto fail; + acl->a_entries[n].e_id = + le32_to_cpu(entry->e_id); + break; + + default: + goto fail; + } + } + if (value != end) + goto fail; + return acl; + +fail: + posix_acl_release(acl); + return ERR_PTR(-EINVAL); +} + +/* + * Convert from in-memory to filesystem representation. + */ +static void * +ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) +{ + ext3_acl_header *ext_acl; + char *e; + size_t n; + + *size = ext3_acl_size(acl->a_count); + ext_acl = kmalloc(sizeof(ext3_acl_header) + acl->a_count * + sizeof(ext3_acl_entry), GFP_KERNEL); + if (!ext_acl) + return ERR_PTR(-ENOMEM); + ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION); + e = (char *)ext_acl + sizeof(ext3_acl_header); + for (n=0; n < acl->a_count; n++) { + ext3_acl_entry *entry = (ext3_acl_entry *)e; + entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); + entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); + switch(acl->a_entries[n].e_tag) { + case ACL_USER: + case ACL_GROUP: + entry->e_id = + cpu_to_le32(acl->a_entries[n].e_id); + e += sizeof(ext3_acl_entry); + break; + + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + e += sizeof(ext3_acl_entry_short); + break; + + default: + goto fail; + } + } + return (char *)ext_acl; + +fail: + kfree(ext_acl); + return ERR_PTR(-EINVAL); +} + +static inline struct posix_acl * +ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl) +{ + struct posix_acl *acl = EXT3_ACL_NOT_CACHED; + + spin_lock(&inode->i_lock); + if (*i_acl != EXT3_ACL_NOT_CACHED) + acl = posix_acl_dup(*i_acl); + spin_unlock(&inode->i_lock); + + return acl; +} + +static inline void +ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl, + struct posix_acl *acl) +{ + spin_lock(&inode->i_lock); + if (*i_acl != EXT3_ACL_NOT_CACHED) + posix_acl_release(*i_acl); + *i_acl = posix_acl_dup(acl); + spin_unlock(&inode->i_lock); +} + +/* + * Inode operation get_posix_acl(). + * + * inode->i_mutex: don't care + */ +static struct posix_acl * +ext3_get_acl(struct inode *inode, int type) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + int name_index; + char *value = NULL; + struct posix_acl *acl; + int retval; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return NULL; + + switch(type) { + case ACL_TYPE_ACCESS: + acl = ext3_iget_acl(inode, &ei->i_acl); + if (acl != EXT3_ACL_NOT_CACHED) + return acl; + name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; + break; + + case ACL_TYPE_DEFAULT: + acl = ext3_iget_acl(inode, &ei->i_default_acl); + if (acl != EXT3_ACL_NOT_CACHED) + return acl; + name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; + break; + + default: + return ERR_PTR(-EINVAL); + } + retval = ext3_xattr_get(inode, name_index, "", NULL, 0); + if (retval > 0) { + value = kmalloc(retval, GFP_KERNEL); + if (!value) + return ERR_PTR(-ENOMEM); + retval = ext3_xattr_get(inode, name_index, "", value, retval); + } + if (retval > 0) + acl = ext3_acl_from_disk(value, retval); + else if (retval == -ENODATA || retval == -ENOSYS) + acl = NULL; + else + acl = ERR_PTR(retval); + kfree(value); + + if (!IS_ERR(acl)) { + switch(type) { + case ACL_TYPE_ACCESS: + ext3_iset_acl(inode, &ei->i_acl, acl); + break; + + case ACL_TYPE_DEFAULT: + ext3_iset_acl(inode, &ei->i_default_acl, acl); + break; + } + } + return acl; +} + +/* + * Set the access or default ACL of an inode. + * + * inode->i_mutex: down unless called from ext3_new_inode + */ +static int +ext3_set_acl(handle_t *handle, struct inode *inode, int type, + struct posix_acl *acl) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + int name_index; + void *value = NULL; + size_t size = 0; + int error; + + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + + switch(type) { + case ACL_TYPE_ACCESS: + name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; + if (acl) { + mode_t mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); + if (error < 0) + return error; + else { + inode->i_mode = mode; + ext3_mark_inode_dirty(handle, inode); + if (error == 0) + acl = NULL; + } + } + break; + + case ACL_TYPE_DEFAULT: + name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; + if (!S_ISDIR(inode->i_mode)) + return acl ? -EACCES : 0; + break; + + default: + return -EINVAL; + } + if (acl) { + value = ext3_acl_to_disk(acl, &size); + if (IS_ERR(value)) + return (int)PTR_ERR(value); + } + + error = ext3_xattr_set_handle(handle, inode, name_index, "", + value, size, 0); + + kfree(value); + if (!error) { + switch(type) { + case ACL_TYPE_ACCESS: + ext3_iset_acl(inode, &ei->i_acl, acl); + break; + + case ACL_TYPE_DEFAULT: + ext3_iset_acl(inode, &ei->i_default_acl, acl); + break; + } + } + return error; +} + +static int +ext3_check_acl(struct inode *inode, int mask) +{ + struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); + + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { + int error = posix_acl_permission(inode, acl, mask); + posix_acl_release(acl); + return error; + } + + return -EAGAIN; +} + +int +ext3_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + return generic_permission(inode, mask, ext3_check_acl); +} + +/* + * Initialize the ACLs of a new inode. Called from ext3_new_inode. + * + * dir->i_mutex: down + * inode->i_mutex: up (access to inode is still exclusive) + */ +int +ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) +{ + struct posix_acl *acl = NULL; + int error = 0; + + if (!S_ISLNK(inode->i_mode)) { + if (test_opt(dir->i_sb, POSIX_ACL)) { + acl = ext3_get_acl(dir, ACL_TYPE_DEFAULT); + if (IS_ERR(acl)) + return PTR_ERR(acl); + } + if (!acl) + inode->i_mode &= ~current->fs->umask; + } + if (test_opt(inode->i_sb, POSIX_ACL) && acl) { + struct posix_acl *clone; + mode_t mode; + + if (S_ISDIR(inode->i_mode)) { + error = ext3_set_acl(handle, inode, + ACL_TYPE_DEFAULT, acl); + if (error) + goto cleanup; + } + clone = posix_acl_clone(acl, GFP_KERNEL); + error = -ENOMEM; + if (!clone) + goto cleanup; + + mode = inode->i_mode; + error = posix_acl_create_masq(clone, &mode); + if (error >= 0) { + inode->i_mode = mode; + if (error > 0) { + /* This is an extended ACL */ + error = ext3_set_acl(handle, inode, + ACL_TYPE_ACCESS, clone); + } + } + posix_acl_release(clone); + } +cleanup: + posix_acl_release(acl); + return error; +} + +/* + * Does chmod for an inode that may have an Access Control List. The + * inode->i_mode field must be updated to the desired value by the caller + * before calling this function. + * Returns 0 on success, or a negative error number. + * + * We change the ACL rather than storing some ACL entries in the file + * mode permission bits (which would be more efficient), because that + * would break once additional permissions (like ACL_APPEND, ACL_DELETE + * for directories) are added. There are no more bits available in the + * file mode. + * + * inode->i_mutex: down + */ +int +ext3_acl_chmod(struct inode *inode) +{ + struct posix_acl *acl, *clone; + int error; + + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(acl) || !acl) + return PTR_ERR(acl); + clone = posix_acl_clone(acl, GFP_KERNEL); + posix_acl_release(acl); + if (!clone) + return -ENOMEM; + error = posix_acl_chmod_masq(clone, inode->i_mode); + if (!error) { + handle_t *handle; + int retries = 0; + + retry: + handle = ext3_journal_start(inode, + EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); + if (IS_ERR(handle)) { + error = PTR_ERR(handle); + ext3_std_error(inode->i_sb, error); + goto out; + } + error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone); + ext3_journal_stop(handle); + if (error == -ENOSPC && + ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; + } +out: + posix_acl_release(clone); + return error; +} + +/* + * Extended attribute handlers + */ +static size_t +ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len, + const char *name, size_t name_len) +{ + const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + if (list && size <= list_len) + memcpy(list, POSIX_ACL_XATTR_ACCESS, size); + return size; +} + +static size_t +ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len, + const char *name, size_t name_len) +{ + const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + if (list && size <= list_len) + memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); + return size; +} + +static int +ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size) +{ + struct posix_acl *acl; + int error; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return -EOPNOTSUPP; + + acl = ext3_get_acl(inode, type); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl == NULL) + return -ENODATA; + error = posix_acl_to_xattr(acl, buffer, size); + posix_acl_release(acl); + + return error; +} + +static int +ext3_xattr_get_acl_access(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext3_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); +} + +static int +ext3_xattr_get_acl_default(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext3_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); +} + +static int +ext3_xattr_set_acl(struct inode *inode, int type, const void *value, + size_t size) +{ + handle_t *handle; + struct posix_acl *acl; + int error, retries = 0; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return -EOPNOTSUPP; + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + + if (value) { + acl = posix_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + else if (acl) { + error = posix_acl_valid(acl); + if (error) + goto release_and_out; + } + } else + acl = NULL; + +retry: + handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + error = ext3_set_acl(handle, inode, type, acl); + ext3_journal_stop(handle); + if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; + +release_and_out: + posix_acl_release(acl); + return error; +} + +static int +ext3_xattr_set_acl_access(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext3_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); +} + +static int +ext3_xattr_set_acl_default(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext3_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); +} + +struct xattr_handler ext3_xattr_acl_access_handler = { + .prefix = POSIX_ACL_XATTR_ACCESS, + .list = ext3_xattr_list_acl_access, + .get = ext3_xattr_get_acl_access, + .set = ext3_xattr_set_acl_access, +}; + +struct xattr_handler ext3_xattr_acl_default_handler = { + .prefix = POSIX_ACL_XATTR_DEFAULT, + .list = ext3_xattr_list_acl_default, + .get = ext3_xattr_get_acl_default, + .set = ext3_xattr_set_acl_default, +}; diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h new file mode 100644 index 000000000000..0d1e6279cbfd --- /dev/null +++ b/fs/ext4/acl.h @@ -0,0 +1,81 @@ +/* + File: fs/ext3/acl.h + + (C) 2001 Andreas Gruenbacher, +*/ + +#include + +#define EXT3_ACL_VERSION 0x0001 + +typedef struct { + __le16 e_tag; + __le16 e_perm; + __le32 e_id; +} ext3_acl_entry; + +typedef struct { + __le16 e_tag; + __le16 e_perm; +} ext3_acl_entry_short; + +typedef struct { + __le32 a_version; +} ext3_acl_header; + +static inline size_t ext3_acl_size(int count) +{ + if (count <= 4) { + return sizeof(ext3_acl_header) + + count * sizeof(ext3_acl_entry_short); + } else { + return sizeof(ext3_acl_header) + + 4 * sizeof(ext3_acl_entry_short) + + (count - 4) * sizeof(ext3_acl_entry); + } +} + +static inline int ext3_acl_count(size_t size) +{ + ssize_t s; + size -= sizeof(ext3_acl_header); + s = size - 4 * sizeof(ext3_acl_entry_short); + if (s < 0) { + if (size % sizeof(ext3_acl_entry_short)) + return -1; + return size / sizeof(ext3_acl_entry_short); + } else { + if (s % sizeof(ext3_acl_entry)) + return -1; + return s / sizeof(ext3_acl_entry) + 4; + } +} + +#ifdef CONFIG_EXT3_FS_POSIX_ACL + +/* Value for inode->u.ext3_i.i_acl and inode->u.ext3_i.i_default_acl + if the ACL has not been cached */ +#define EXT3_ACL_NOT_CACHED ((void *)-1) + +/* acl.c */ +extern int ext3_permission (struct inode *, int, struct nameidata *); +extern int ext3_acl_chmod (struct inode *); +extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); + +#else /* CONFIG_EXT3_FS_POSIX_ACL */ +#include +#define ext3_permission NULL + +static inline int +ext3_acl_chmod(struct inode *inode) +{ + return 0; +} + +static inline int +ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) +{ + return 0; +} +#endif /* CONFIG_EXT3_FS_POSIX_ACL */ + diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c new file mode 100644 index 000000000000..b41a7d7e20f0 --- /dev/null +++ b/fs/ext4/balloc.c @@ -0,0 +1,1818 @@ +/* + * linux/fs/ext3/balloc.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * Enhanced block allocation by Stephen Tweedie (sct@redhat.com), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * balloc.c contains the blocks allocation and deallocation routines + */ + +/* + * The free blocks are managed by bitmaps. A file system contains several + * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap + * block for inodes, N blocks for the inode table and data blocks. + * + * The file system contains group descriptors which are located after the + * super block. Each descriptor contains the number of the bitmap block and + * the free blocks count in the block. The descriptors are loaded in memory + * when a file system is mounted (see ext3_read_super). + */ + + +#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) + +/** + * ext3_get_group_desc() -- load group descriptor from disk + * @sb: super block + * @block_group: given block group + * @bh: pointer to the buffer head to store the block + * group descriptor + */ +struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh) +{ + unsigned long group_desc; + unsigned long offset; + struct ext3_group_desc * desc; + struct ext3_sb_info *sbi = EXT3_SB(sb); + + if (block_group >= sbi->s_groups_count) { + ext3_error (sb, "ext3_get_group_desc", + "block_group >= groups_count - " + "block_group = %d, groups_count = %lu", + block_group, sbi->s_groups_count); + + return NULL; + } + smp_rmb(); + + group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(sb); + offset = block_group & (EXT3_DESC_PER_BLOCK(sb) - 1); + if (!sbi->s_group_desc[group_desc]) { + ext3_error (sb, "ext3_get_group_desc", + "Group descriptor not loaded - " + "block_group = %d, group_desc = %lu, desc = %lu", + block_group, group_desc, offset); + return NULL; + } + + desc = (struct ext3_group_desc *) sbi->s_group_desc[group_desc]->b_data; + if (bh) + *bh = sbi->s_group_desc[group_desc]; + return desc + offset; +} + +/** + * read_block_bitmap() + * @sb: super block + * @block_group: given block group + * + * Read the bitmap for a given block_group, reading into the specified + * slot in the superblock's bitmap cache. + * + * Return buffer_head on success or NULL in case of failure. + */ +static struct buffer_head * +read_block_bitmap(struct super_block *sb, unsigned int block_group) +{ + struct ext3_group_desc * desc; + struct buffer_head * bh = NULL; + + desc = ext3_get_group_desc (sb, block_group, NULL); + if (!desc) + goto error_out; + bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); + if (!bh) + ext3_error (sb, "read_block_bitmap", + "Cannot read block bitmap - " + "block_group = %d, block_bitmap = %u", + block_group, le32_to_cpu(desc->bg_block_bitmap)); +error_out: + return bh; +} +/* + * The reservation window structure operations + * -------------------------------------------- + * Operations include: + * dump, find, add, remove, is_empty, find_next_reservable_window, etc. + * + * We use a red-black tree to represent per-filesystem reservation + * windows. + * + */ + +/** + * __rsv_window_dump() -- Dump the filesystem block allocation reservation map + * @rb_root: root of per-filesystem reservation rb tree + * @verbose: verbose mode + * @fn: function which wishes to dump the reservation map + * + * If verbose is turned on, it will print the whole block reservation + * windows(start, end). Otherwise, it will only print out the "bad" windows, + * those windows that overlap with their immediate neighbors. + */ +#if 1 +static void __rsv_window_dump(struct rb_root *root, int verbose, + const char *fn) +{ + struct rb_node *n; + struct ext3_reserve_window_node *rsv, *prev; + int bad; + +restart: + n = rb_first(root); + bad = 0; + prev = NULL; + + printk("Block Allocation Reservation Windows Map (%s):\n", fn); + while (n) { + rsv = list_entry(n, struct ext3_reserve_window_node, rsv_node); + if (verbose) + printk("reservation window 0x%p " + "start: %lu, end: %lu\n", + rsv, rsv->rsv_start, rsv->rsv_end); + if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) { + printk("Bad reservation %p (start >= end)\n", + rsv); + bad = 1; + } + if (prev && prev->rsv_end >= rsv->rsv_start) { + printk("Bad reservation %p (prev->end >= start)\n", + rsv); + bad = 1; + } + if (bad) { + if (!verbose) { + printk("Restarting reservation walk in verbose mode\n"); + verbose = 1; + goto restart; + } + } + n = rb_next(n); + prev = rsv; + } + printk("Window map complete.\n"); + if (bad) + BUG(); +} +#define rsv_window_dump(root, verbose) \ + __rsv_window_dump((root), (verbose), __FUNCTION__) +#else +#define rsv_window_dump(root, verbose) do {} while (0) +#endif + +/** + * goal_in_my_reservation() + * @rsv: inode's reservation window + * @grp_goal: given goal block relative to the allocation block group + * @group: the current allocation block group + * @sb: filesystem super block + * + * Test if the given goal block (group relative) is within the file's + * own block reservation window range. + * + * If the reservation window is outside the goal allocation group, return 0; + * grp_goal (given goal block) could be -1, which means no specific + * goal block. In this case, always return 1. + * If the goal block is within the reservation window, return 1; + * otherwise, return 0; + */ +static int +goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal, + unsigned int group, struct super_block * sb) +{ + ext3_fsblk_t group_first_block, group_last_block; + + group_first_block = ext3_group_first_block_no(sb, group); + group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); + + if ((rsv->_rsv_start > group_last_block) || + (rsv->_rsv_end < group_first_block)) + return 0; + if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start) + || (grp_goal + group_first_block > rsv->_rsv_end))) + return 0; + return 1; +} + +/** + * search_reserve_window() + * @rb_root: root of reservation tree + * @goal: target allocation block + * + * Find the reserved window which includes the goal, or the previous one + * if the goal is not in any window. + * Returns NULL if there are no windows or if all windows start after the goal. + */ +static struct ext3_reserve_window_node * +search_reserve_window(struct rb_root *root, ext3_fsblk_t goal) +{ + struct rb_node *n = root->rb_node; + struct ext3_reserve_window_node *rsv; + + if (!n) + return NULL; + + do { + rsv = rb_entry(n, struct ext3_reserve_window_node, rsv_node); + + if (goal < rsv->rsv_start) + n = n->rb_left; + else if (goal > rsv->rsv_end) + n = n->rb_right; + else + return rsv; + } while (n); + /* + * We've fallen off the end of the tree: the goal wasn't inside + * any particular node. OK, the previous node must be to one + * side of the interval containing the goal. If it's the RHS, + * we need to back up one. + */ + if (rsv->rsv_start > goal) { + n = rb_prev(&rsv->rsv_node); + rsv = rb_entry(n, struct ext3_reserve_window_node, rsv_node); + } + return rsv; +} + +/** + * ext3_rsv_window_add() -- Insert a window to the block reservation rb tree. + * @sb: super block + * @rsv: reservation window to add + * + * Must be called with rsv_lock hold. + */ +void ext3_rsv_window_add(struct super_block *sb, + struct ext3_reserve_window_node *rsv) +{ + struct rb_root *root = &EXT3_SB(sb)->s_rsv_window_root; + struct rb_node *node = &rsv->rsv_node; + ext3_fsblk_t start = rsv->rsv_start; + + struct rb_node ** p = &root->rb_node; + struct rb_node * parent = NULL; + struct ext3_reserve_window_node *this; + + while (*p) + { + parent = *p; + this = rb_entry(parent, struct ext3_reserve_window_node, rsv_node); + + if (start < this->rsv_start) + p = &(*p)->rb_left; + else if (start > this->rsv_end) + p = &(*p)->rb_right; + else { + rsv_window_dump(root, 1); + BUG(); + } + } + + rb_link_node(node, parent, p); + rb_insert_color(node, root); +} + +/** + * ext3_rsv_window_remove() -- unlink a window from the reservation rb tree + * @sb: super block + * @rsv: reservation window to remove + * + * Mark the block reservation window as not allocated, and unlink it + * from the filesystem reservation window rb tree. Must be called with + * rsv_lock hold. + */ +static void rsv_window_remove(struct super_block *sb, + struct ext3_reserve_window_node *rsv) +{ + rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_alloc_hit = 0; + rb_erase(&rsv->rsv_node, &EXT3_SB(sb)->s_rsv_window_root); +} + +/* + * rsv_is_empty() -- Check if the reservation window is allocated. + * @rsv: given reservation window to check + * + * returns 1 if the end block is EXT3_RESERVE_WINDOW_NOT_ALLOCATED. + */ +static inline int rsv_is_empty(struct ext3_reserve_window *rsv) +{ + /* a valid reservation end block could not be 0 */ + return rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED; +} + +/** + * ext3_init_block_alloc_info() + * @inode: file inode structure + * + * Allocate and initialize the reservation window structure, and + * link the window to the ext3 inode structure at last + * + * The reservation window structure is only dynamically allocated + * and linked to ext3 inode the first time the open file + * needs a new block. So, before every ext3_new_block(s) call, for + * regular files, we should check whether the reservation window + * structure exists or not. In the latter case, this function is called. + * Fail to do so will result in block reservation being turned off for that + * open file. + * + * This function is called from ext3_get_blocks_handle(), also called + * when setting the reservation window size through ioctl before the file + * is open for write (needs block allocation). + * + * Needs truncate_mutex protection prior to call this function. + */ +void ext3_init_block_alloc_info(struct inode *inode) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info; + struct super_block *sb = inode->i_sb; + + block_i = kmalloc(sizeof(*block_i), GFP_NOFS); + if (block_i) { + struct ext3_reserve_window_node *rsv = &block_i->rsv_window_node; + + rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + + /* + * if filesystem is mounted with NORESERVATION, the goal + * reservation window size is set to zero to indicate + * block reservation is off + */ + if (!test_opt(sb, RESERVATION)) + rsv->rsv_goal_size = 0; + else + rsv->rsv_goal_size = EXT3_DEFAULT_RESERVE_BLOCKS; + rsv->rsv_alloc_hit = 0; + block_i->last_alloc_logical_block = 0; + block_i->last_alloc_physical_block = 0; + } + ei->i_block_alloc_info = block_i; +} + +/** + * ext3_discard_reservation() + * @inode: inode + * + * Discard(free) block reservation window on last file close, or truncate + * or at last iput(). + * + * It is being called in three cases: + * ext3_release_file(): last writer close the file + * ext3_clear_inode(): last iput(), when nobody link to this file. + * ext3_truncate(): when the block indirect map is about to change. + * + */ +void ext3_discard_reservation(struct inode *inode) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info; + struct ext3_reserve_window_node *rsv; + spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock; + + if (!block_i) + return; + + rsv = &block_i->rsv_window_node; + if (!rsv_is_empty(&rsv->rsv_window)) { + spin_lock(rsv_lock); + if (!rsv_is_empty(&rsv->rsv_window)) + rsv_window_remove(inode->i_sb, rsv); + spin_unlock(rsv_lock); + } +} + +/** + * ext3_free_blocks_sb() -- Free given blocks and update quota + * @handle: handle to this transaction + * @sb: super block + * @block: start physcial block to free + * @count: number of blocks to free + * @pdquot_freed_blocks: pointer to quota + */ +void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb, + ext3_fsblk_t block, unsigned long count, + unsigned long *pdquot_freed_blocks) +{ + struct buffer_head *bitmap_bh = NULL; + struct buffer_head *gd_bh; + unsigned long block_group; + ext3_grpblk_t bit; + unsigned long i; + unsigned long overflow; + struct ext3_group_desc * desc; + struct ext3_super_block * es; + struct ext3_sb_info *sbi; + int err = 0, ret; + ext3_grpblk_t group_freed; + + *pdquot_freed_blocks = 0; + sbi = EXT3_SB(sb); + es = sbi->s_es; + if (block < le32_to_cpu(es->s_first_data_block) || + block + count < block || + block + count > le32_to_cpu(es->s_blocks_count)) { + ext3_error (sb, "ext3_free_blocks", + "Freeing blocks not in datazone - " + "block = "E3FSBLK", count = %lu", block, count); + goto error_return; + } + + ext3_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1); + +do_more: + overflow = 0; + block_group = (block - le32_to_cpu(es->s_first_data_block)) / + EXT3_BLOCKS_PER_GROUP(sb); + bit = (block - le32_to_cpu(es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb); + /* + * Check to see if we are freeing blocks across a group + * boundary. + */ + if (bit + count > EXT3_BLOCKS_PER_GROUP(sb)) { + overflow = bit + count - EXT3_BLOCKS_PER_GROUP(sb); + count -= overflow; + } + brelse(bitmap_bh); + bitmap_bh = read_block_bitmap(sb, block_group); + if (!bitmap_bh) + goto error_return; + desc = ext3_get_group_desc (sb, block_group, &gd_bh); + if (!desc) + goto error_return; + + if (in_range (le32_to_cpu(desc->bg_block_bitmap), block, count) || + in_range (le32_to_cpu(desc->bg_inode_bitmap), block, count) || + in_range (block, le32_to_cpu(desc->bg_inode_table), + sbi->s_itb_per_group) || + in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table), + sbi->s_itb_per_group)) + ext3_error (sb, "ext3_free_blocks", + "Freeing blocks in system zones - " + "Block = "E3FSBLK", count = %lu", + block, count); + + /* + * We are about to start releasing blocks in the bitmap, + * so we need undo access. + */ + /* @@@ check errors */ + BUFFER_TRACE(bitmap_bh, "getting undo access"); + err = ext3_journal_get_undo_access(handle, bitmap_bh); + if (err) + goto error_return; + + /* + * We are about to modify some metadata. Call the journal APIs + * to unshare ->b_data if a currently-committing transaction is + * using it + */ + BUFFER_TRACE(gd_bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, gd_bh); + if (err) + goto error_return; + + jbd_lock_bh_state(bitmap_bh); + + for (i = 0, group_freed = 0; i < count; i++) { + /* + * An HJ special. This is expensive... + */ +#ifdef CONFIG_JBD_DEBUG + jbd_unlock_bh_state(bitmap_bh); + { + struct buffer_head *debug_bh; + debug_bh = sb_find_get_block(sb, block + i); + if (debug_bh) { + BUFFER_TRACE(debug_bh, "Deleted!"); + if (!bh2jh(bitmap_bh)->b_committed_data) + BUFFER_TRACE(debug_bh, + "No commited data in bitmap"); + BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap"); + __brelse(debug_bh); + } + } + jbd_lock_bh_state(bitmap_bh); +#endif + if (need_resched()) { + jbd_unlock_bh_state(bitmap_bh); + cond_resched(); + jbd_lock_bh_state(bitmap_bh); + } + /* @@@ This prevents newly-allocated data from being + * freed and then reallocated within the same + * transaction. + * + * Ideally we would want to allow that to happen, but to + * do so requires making journal_forget() capable of + * revoking the queued write of a data block, which + * implies blocking on the journal lock. *forget() + * cannot block due to truncate races. + * + * Eventually we can fix this by making journal_forget() + * return a status indicating whether or not it was able + * to revoke the buffer. On successful revoke, it is + * safe not to set the allocation bit in the committed + * bitmap, because we know that there is no outstanding + * activity on the buffer any more and so it is safe to + * reallocate it. + */ + BUFFER_TRACE(bitmap_bh, "set in b_committed_data"); + J_ASSERT_BH(bitmap_bh, + bh2jh(bitmap_bh)->b_committed_data != NULL); + ext3_set_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i, + bh2jh(bitmap_bh)->b_committed_data); + + /* + * We clear the bit in the bitmap after setting the committed + * data bit, because this is the reverse order to that which + * the allocator uses. + */ + BUFFER_TRACE(bitmap_bh, "clear bit"); + if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group), + bit + i, bitmap_bh->b_data)) { + jbd_unlock_bh_state(bitmap_bh); + ext3_error(sb, __FUNCTION__, + "bit already cleared for block "E3FSBLK, + block + i); + jbd_lock_bh_state(bitmap_bh); + BUFFER_TRACE(bitmap_bh, "bit already cleared"); + } else { + group_freed++; + } + } + jbd_unlock_bh_state(bitmap_bh); + + spin_lock(sb_bgl_lock(sbi, block_group)); + desc->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) + + group_freed); + spin_unlock(sb_bgl_lock(sbi, block_group)); + percpu_counter_mod(&sbi->s_freeblocks_counter, count); + + /* We dirtied the bitmap block */ + BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); + err = ext3_journal_dirty_metadata(handle, bitmap_bh); + + /* And the group descriptor block */ + BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); + ret = ext3_journal_dirty_metadata(handle, gd_bh); + if (!err) err = ret; + *pdquot_freed_blocks += group_freed; + + if (overflow && !err) { + block += count; + count = overflow; + goto do_more; + } + sb->s_dirt = 1; +error_return: + brelse(bitmap_bh); + ext3_std_error(sb, err); + return; +} + +/** + * ext3_free_blocks() -- Free given blocks and update quota + * @handle: handle for this transaction + * @inode: inode + * @block: start physical block to free + * @count: number of blocks to count + */ +void ext3_free_blocks(handle_t *handle, struct inode *inode, + ext3_fsblk_t block, unsigned long count) +{ + struct super_block * sb; + unsigned long dquot_freed_blocks; + + sb = inode->i_sb; + if (!sb) { + printk ("ext3_free_blocks: nonexistent device"); + return; + } + ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks); + if (dquot_freed_blocks) + DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); + return; +} + +/** + * ext3_test_allocatable() + * @nr: given allocation block group + * @bh: bufferhead contains the bitmap of the given block group + * + * For ext3 allocations, we must not reuse any blocks which are + * allocated in the bitmap buffer's "last committed data" copy. This + * prevents deletes from freeing up the page for reuse until we have + * committed the delete transaction. + * + * If we didn't do this, then deleting something and reallocating it as + * data would allow the old block to be overwritten before the + * transaction committed (because we force data to disk before commit). + * This would lead to corruption if we crashed between overwriting the + * data and committing the delete. + * + * @@@ We may want to make this allocation behaviour conditional on + * data-writes at some point, and disable it for metadata allocations or + * sync-data inodes. + */ +static int ext3_test_allocatable(ext3_grpblk_t nr, struct buffer_head *bh) +{ + int ret; + struct journal_head *jh = bh2jh(bh); + + if (ext3_test_bit(nr, bh->b_data)) + return 0; + + jbd_lock_bh_state(bh); + if (!jh->b_committed_data) + ret = 1; + else + ret = !ext3_test_bit(nr, jh->b_committed_data); + jbd_unlock_bh_state(bh); + return ret; +} + +/** + * bitmap_search_next_usable_block() + * @start: the starting block (group relative) of the search + * @bh: bufferhead contains the block group bitmap + * @maxblocks: the ending block (group relative) of the reservation + * + * The bitmap search --- search forward alternately through the actual + * bitmap on disk and the last-committed copy in journal, until we find a + * bit free in both bitmaps. + */ +static ext3_grpblk_t +bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, + ext3_grpblk_t maxblocks) +{ + ext3_grpblk_t next; + struct journal_head *jh = bh2jh(bh); + + while (start < maxblocks) { + next = ext3_find_next_zero_bit(bh->b_data, maxblocks, start); + if (next >= maxblocks) + return -1; + if (ext3_test_allocatable(next, bh)) + return next; + jbd_lock_bh_state(bh); + if (jh->b_committed_data) + start = ext3_find_next_zero_bit(jh->b_committed_data, + maxblocks, next); + jbd_unlock_bh_state(bh); + } + return -1; +} + +/** + * find_next_usable_block() + * @start: the starting block (group relative) to find next + * allocatable block in bitmap. + * @bh: bufferhead contains the block group bitmap + * @maxblocks: the ending block (group relative) for the search + * + * Find an allocatable block in a bitmap. We honor both the bitmap and + * its last-committed copy (if that exists), and perform the "most + * appropriate allocation" algorithm of looking for a free block near + * the initial goal; then for a free byte somewhere in the bitmap; then + * for any free bit in the bitmap. + */ +static ext3_grpblk_t +find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, + ext3_grpblk_t maxblocks) +{ + ext3_grpblk_t here, next; + char *p, *r; + + if (start > 0) { + /* + * The goal was occupied; search forward for a free + * block within the next XX blocks. + * + * end_goal is more or less random, but it has to be + * less than EXT3_BLOCKS_PER_GROUP. Aligning up to the + * next 64-bit boundary is simple.. + */ + ext3_grpblk_t end_goal = (start + 63) & ~63; + if (end_goal > maxblocks) + end_goal = maxblocks; + here = ext3_find_next_zero_bit(bh->b_data, end_goal, start); + if (here < end_goal && ext3_test_allocatable(here, bh)) + return here; + ext3_debug("Bit not found near goal\n"); + } + + here = start; + if (here < 0) + here = 0; + + p = ((char *)bh->b_data) + (here >> 3); + r = memscan(p, 0, (maxblocks - here + 7) >> 3); + next = (r - ((char *)bh->b_data)) << 3; + + if (next < maxblocks && next >= start && ext3_test_allocatable(next, bh)) + return next; + + /* + * The bitmap search --- search forward alternately through the actual + * bitmap and the last-committed copy until we find a bit free in + * both + */ + here = bitmap_search_next_usable_block(here, bh, maxblocks); + return here; +} + +/** + * claim_block() + * @block: the free block (group relative) to allocate + * @bh: the bufferhead containts the block group bitmap + * + * We think we can allocate this block in this bitmap. Try to set the bit. + * If that succeeds then check that nobody has allocated and then freed the + * block since we saw that is was not marked in b_committed_data. If it _was_ + * allocated and freed then clear the bit in the bitmap again and return + * zero (failure). + */ +static inline int +claim_block(spinlock_t *lock, ext3_grpblk_t block, struct buffer_head *bh) +{ + struct journal_head *jh = bh2jh(bh); + int ret; + + if (ext3_set_bit_atomic(lock, block, bh->b_data)) + return 0; + jbd_lock_bh_state(bh); + if (jh->b_committed_data && ext3_test_bit(block,jh->b_committed_data)) { + ext3_clear_bit_atomic(lock, block, bh->b_data); + ret = 0; + } else { + ret = 1; + } + jbd_unlock_bh_state(bh); + return ret; +} + +/** + * ext3_try_to_allocate() + * @sb: superblock + * @handle: handle to this transaction + * @group: given allocation block group + * @bitmap_bh: bufferhead holds the block bitmap + * @grp_goal: given target block within the group + * @count: target number of blocks to allocate + * @my_rsv: reservation window + * + * Attempt to allocate blocks within a give range. Set the range of allocation + * first, then find the first free bit(s) from the bitmap (within the range), + * and at last, allocate the blocks by claiming the found free bit as allocated. + * + * To set the range of this allocation: + * if there is a reservation window, only try to allocate block(s) from the + * file's own reservation window; + * Otherwise, the allocation range starts from the give goal block, ends at + * the block group's last block. + * + * If we failed to allocate the desired block then we may end up crossing to a + * new bitmap. In that case we must release write access to the old one via + * ext3_journal_release_buffer(), else we'll run out of credits. + */ +static ext3_grpblk_t +ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group, + struct buffer_head *bitmap_bh, ext3_grpblk_t grp_goal, + unsigned long *count, struct ext3_reserve_window *my_rsv) +{ + ext3_fsblk_t group_first_block; + ext3_grpblk_t start, end; + unsigned long num = 0; + + /* we do allocation within the reservation window if we have a window */ + if (my_rsv) { + group_first_block = ext3_group_first_block_no(sb, group); + if (my_rsv->_rsv_start >= group_first_block) + start = my_rsv->_rsv_start - group_first_block; + else + /* reservation window cross group boundary */ + start = 0; + end = my_rsv->_rsv_end - group_first_block + 1; + if (end > EXT3_BLOCKS_PER_GROUP(sb)) + /* reservation window crosses group boundary */ + end = EXT3_BLOCKS_PER_GROUP(sb); + if ((start <= grp_goal) && (grp_goal < end)) + start = grp_goal; + else + grp_goal = -1; + } else { + if (grp_goal > 0) + start = grp_goal; + else + start = 0; + end = EXT3_BLOCKS_PER_GROUP(sb); + } + + BUG_ON(start > EXT3_BLOCKS_PER_GROUP(sb)); + +repeat: + if (grp_goal < 0 || !ext3_test_allocatable(grp_goal, bitmap_bh)) { + grp_goal = find_next_usable_block(start, bitmap_bh, end); + if (grp_goal < 0) + goto fail_access; + if (!my_rsv) { + int i; + + for (i = 0; i < 7 && grp_goal > start && + ext3_test_allocatable(grp_goal - 1, + bitmap_bh); + i++, grp_goal--) + ; + } + } + start = grp_goal; + + if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), + grp_goal, bitmap_bh)) { + /* + * The block was allocated by another thread, or it was + * allocated and then freed by another thread + */ + start++; + grp_goal++; + if (start >= end) + goto fail_access; + goto repeat; + } + num++; + grp_goal++; + while (num < *count && grp_goal < end + && ext3_test_allocatable(grp_goal, bitmap_bh) + && claim_block(sb_bgl_lock(EXT3_SB(sb), group), + grp_goal, bitmap_bh)) { + num++; + grp_goal++; + } + *count = num; + return grp_goal - num; +fail_access: + *count = num; + return -1; +} + +/** + * find_next_reservable_window(): + * find a reservable space within the given range. + * It does not allocate the reservation window for now: + * alloc_new_reservation() will do the work later. + * + * @search_head: the head of the searching list; + * This is not necessarily the list head of the whole filesystem + * + * We have both head and start_block to assist the search + * for the reservable space. The list starts from head, + * but we will shift to the place where start_block is, + * then start from there, when looking for a reservable space. + * + * @size: the target new reservation window size + * + * @group_first_block: the first block we consider to start + * the real search from + * + * @last_block: + * the maximum block number that our goal reservable space + * could start from. This is normally the last block in this + * group. The search will end when we found the start of next + * possible reservable space is out of this boundary. + * This could handle the cross boundary reservation window + * request. + * + * basically we search from the given range, rather than the whole + * reservation double linked list, (start_block, last_block) + * to find a free region that is of my size and has not + * been reserved. + * + */ +static int find_next_reservable_window( + struct ext3_reserve_window_node *search_head, + struct ext3_reserve_window_node *my_rsv, + struct super_block * sb, + ext3_fsblk_t start_block, + ext3_fsblk_t last_block) +{ + struct rb_node *next; + struct ext3_reserve_window_node *rsv, *prev; + ext3_fsblk_t cur; + int size = my_rsv->rsv_goal_size; + + /* TODO: make the start of the reservation window byte-aligned */ + /* cur = *start_block & ~7;*/ + cur = start_block; + rsv = search_head; + if (!rsv) + return -1; + + while (1) { + if (cur <= rsv->rsv_end) + cur = rsv->rsv_end + 1; + + /* TODO? + * in the case we could not find a reservable space + * that is what is expected, during the re-search, we could + * remember what's the largest reservable space we could have + * and return that one. + * + * For now it will fail if we could not find the reservable + * space with expected-size (or more)... + */ + if (cur > last_block) + return -1; /* fail */ + + prev = rsv; + next = rb_next(&rsv->rsv_node); + rsv = list_entry(next,struct ext3_reserve_window_node,rsv_node); + + /* + * Reached the last reservation, we can just append to the + * previous one. + */ + if (!next) + break; + + if (cur + size <= rsv->rsv_start) { + /* + * Found a reserveable space big enough. We could + * have a reservation across the group boundary here + */ + break; + } + } + /* + * we come here either : + * when we reach the end of the whole list, + * and there is empty reservable space after last entry in the list. + * append it to the end of the list. + * + * or we found one reservable space in the middle of the list, + * return the reservation window that we could append to. + * succeed. + */ + + if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window))) + rsv_window_remove(sb, my_rsv); + + /* + * Let's book the whole avaliable window for now. We will check the + * disk bitmap later and then, if there are free blocks then we adjust + * the window size if it's larger than requested. + * Otherwise, we will remove this node from the tree next time + * call find_next_reservable_window. + */ + my_rsv->rsv_start = cur; + my_rsv->rsv_end = cur + size - 1; + my_rsv->rsv_alloc_hit = 0; + + if (prev != my_rsv) + ext3_rsv_window_add(sb, my_rsv); + + return 0; +} + +/** + * alloc_new_reservation()--allocate a new reservation window + * + * To make a new reservation, we search part of the filesystem + * reservation list (the list that inside the group). We try to + * allocate a new reservation window near the allocation goal, + * or the beginning of the group, if there is no goal. + * + * We first find a reservable space after the goal, then from + * there, we check the bitmap for the first free block after + * it. If there is no free block until the end of group, then the + * whole group is full, we failed. Otherwise, check if the free + * block is inside the expected reservable space, if so, we + * succeed. + * If the first free block is outside the reservable space, then + * start from the first free block, we search for next available + * space, and go on. + * + * on succeed, a new reservation will be found and inserted into the list + * It contains at least one free block, and it does not overlap with other + * reservation windows. + * + * failed: we failed to find a reservation window in this group + * + * @rsv: the reservation + * + * @grp_goal: The goal (group-relative). It is where the search for a + * free reservable space should start from. + * if we have a grp_goal(grp_goal >0 ), then start from there, + * no grp_goal(grp_goal = -1), we start from the first block + * of the group. + * + * @sb: the super block + * @group: the group we are trying to allocate in + * @bitmap_bh: the block group block bitmap + * + */ +static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, + ext3_grpblk_t grp_goal, struct super_block *sb, + unsigned int group, struct buffer_head *bitmap_bh) +{ + struct ext3_reserve_window_node *search_head; + ext3_fsblk_t group_first_block, group_end_block, start_block; + ext3_grpblk_t first_free_block; + struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root; + unsigned long size; + int ret; + spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; + + group_first_block = ext3_group_first_block_no(sb, group); + group_end_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); + + if (grp_goal < 0) + start_block = group_first_block; + else + start_block = grp_goal + group_first_block; + + size = my_rsv->rsv_goal_size; + + if (!rsv_is_empty(&my_rsv->rsv_window)) { + /* + * if the old reservation is cross group boundary + * and if the goal is inside the old reservation window, + * we will come here when we just failed to allocate from + * the first part of the window. We still have another part + * that belongs to the next group. In this case, there is no + * point to discard our window and try to allocate a new one + * in this group(which will fail). we should + * keep the reservation window, just simply move on. + * + * Maybe we could shift the start block of the reservation + * window to the first block of next group. + */ + + if ((my_rsv->rsv_start <= group_end_block) && + (my_rsv->rsv_end > group_end_block) && + (start_block >= my_rsv->rsv_start)) + return -1; + + if ((my_rsv->rsv_alloc_hit > + (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) { + /* + * if the previously allocation hit ratio is + * greater than 1/2, then we double the size of + * the reservation window the next time, + * otherwise we keep the same size window + */ + size = size * 2; + if (size > EXT3_MAX_RESERVE_BLOCKS) + size = EXT3_MAX_RESERVE_BLOCKS; + my_rsv->rsv_goal_size= size; + } + } + + spin_lock(rsv_lock); + /* + * shift the search start to the window near the goal block + */ + search_head = search_reserve_window(fs_rsv_root, start_block); + + /* + * find_next_reservable_window() simply finds a reservable window + * inside the given range(start_block, group_end_block). + * + * To make sure the reservation window has a free bit inside it, we + * need to check the bitmap after we found a reservable window. + */ +retry: + ret = find_next_reservable_window(search_head, my_rsv, sb, + start_block, group_end_block); + + if (ret == -1) { + if (!rsv_is_empty(&my_rsv->rsv_window)) + rsv_window_remove(sb, my_rsv); + spin_unlock(rsv_lock); + return -1; + } + + /* + * On success, find_next_reservable_window() returns the + * reservation window where there is a reservable space after it. + * Before we reserve this reservable space, we need + * to make sure there is at least a free block inside this region. + * + * searching the first free bit on the block bitmap and copy of + * last committed bitmap alternatively, until we found a allocatable + * block. Search start from the start block of the reservable space + * we just found. + */ + spin_unlock(rsv_lock); + first_free_block = bitmap_search_next_usable_block( + my_rsv->rsv_start - group_first_block, + bitmap_bh, group_end_block - group_first_block + 1); + + if (first_free_block < 0) { + /* + * no free block left on the bitmap, no point + * to reserve the space. return failed. + */ + spin_lock(rsv_lock); + if (!rsv_is_empty(&my_rsv->rsv_window)) + rsv_window_remove(sb, my_rsv); + spin_unlock(rsv_lock); + return -1; /* failed */ + } + + start_block = first_free_block + group_first_block; + /* + * check if the first free block is within the + * free space we just reserved + */ + if (start_block >= my_rsv->rsv_start && start_block < my_rsv->rsv_end) + return 0; /* success */ + /* + * if the first free bit we found is out of the reservable space + * continue search for next reservable space, + * start from where the free block is, + * we also shift the list head to where we stopped last time + */ + search_head = my_rsv; + spin_lock(rsv_lock); + goto retry; +} + +/** + * try_to_extend_reservation() + * @my_rsv: given reservation window + * @sb: super block + * @size: the delta to extend + * + * Attempt to expand the reservation window large enough to have + * required number of free blocks + * + * Since ext3_try_to_allocate() will always allocate blocks within + * the reservation window range, if the window size is too small, + * multiple blocks allocation has to stop at the end of the reservation + * window. To make this more efficient, given the total number of + * blocks needed and the current size of the window, we try to + * expand the reservation window size if necessary on a best-effort + * basis before ext3_new_blocks() tries to allocate blocks, + */ +static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv, + struct super_block *sb, int size) +{ + struct ext3_reserve_window_node *next_rsv; + struct rb_node *next; + spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; + + if (!spin_trylock(rsv_lock)) + return; + + next = rb_next(&my_rsv->rsv_node); + + if (!next) + my_rsv->rsv_end += size; + else { + next_rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node); + + if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size) + my_rsv->rsv_end += size; + else + my_rsv->rsv_end = next_rsv->rsv_start - 1; + } + spin_unlock(rsv_lock); +} + +/** + * ext3_try_to_allocate_with_rsv() + * @sb: superblock + * @handle: handle to this transaction + * @group: given allocation block group + * @bitmap_bh: bufferhead holds the block bitmap + * @grp_goal: given target block within the group + * @count: target number of blocks to allocate + * @my_rsv: reservation window + * @errp: pointer to store the error code + * + * This is the main function used to allocate a new block and its reservation + * window. + * + * Each time when a new block allocation is need, first try to allocate from + * its own reservation. If it does not have a reservation window, instead of + * looking for a free bit on bitmap first, then look up the reservation list to + * see if it is inside somebody else's reservation window, we try to allocate a + * reservation window for it starting from the goal first. Then do the block + * allocation within the reservation window. + * + * This will avoid keeping on searching the reservation list again and + * again when somebody is looking for a free block (without + * reservation), and there are lots of free blocks, but they are all + * being reserved. + * + * We use a red-black tree for the per-filesystem reservation list. + * + */ +static ext3_grpblk_t +ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, + unsigned int group, struct buffer_head *bitmap_bh, + ext3_grpblk_t grp_goal, + struct ext3_reserve_window_node * my_rsv, + unsigned long *count, int *errp) +{ + ext3_fsblk_t group_first_block, group_last_block; + ext3_grpblk_t ret = 0; + int fatal; + unsigned long num = *count; + + *errp = 0; + + /* + * Make sure we use undo access for the bitmap, because it is critical + * that we do the frozen_data COW on bitmap buffers in all cases even + * if the buffer is in BJ_Forget state in the committing transaction. + */ + BUFFER_TRACE(bitmap_bh, "get undo access for new block"); + fatal = ext3_journal_get_undo_access(handle, bitmap_bh); + if (fatal) { + *errp = fatal; + return -1; + } + + /* + * we don't deal with reservation when + * filesystem is mounted without reservation + * or the file is not a regular file + * or last attempt to allocate a block with reservation turned on failed + */ + if (my_rsv == NULL ) { + ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, + grp_goal, count, NULL); + goto out; + } + /* + * grp_goal is a group relative block number (if there is a goal) + * 0 < grp_goal < EXT3_BLOCKS_PER_GROUP(sb) + * first block is a filesystem wide block number + * first block is the block number of the first block in this group + */ + group_first_block = ext3_group_first_block_no(sb, group); + group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); + + /* + * Basically we will allocate a new block from inode's reservation + * window. + * + * We need to allocate a new reservation window, if: + * a) inode does not have a reservation window; or + * b) last attempt to allocate a block from existing reservation + * failed; or + * c) we come here with a goal and with a reservation window + * + * We do not need to allocate a new reservation window if we come here + * at the beginning with a goal and the goal is inside the window, or + * we don't have a goal but already have a reservation window. + * then we could go to allocate from the reservation window directly. + */ + while (1) { + if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) || + !goal_in_my_reservation(&my_rsv->rsv_window, + grp_goal, group, sb)) { + if (my_rsv->rsv_goal_size < *count) + my_rsv->rsv_goal_size = *count; + ret = alloc_new_reservation(my_rsv, grp_goal, sb, + group, bitmap_bh); + if (ret < 0) + break; /* failed */ + + if (!goal_in_my_reservation(&my_rsv->rsv_window, + grp_goal, group, sb)) + grp_goal = -1; + } else if (grp_goal > 0 && + (my_rsv->rsv_end-grp_goal+1) < *count) + try_to_extend_reservation(my_rsv, sb, + *count-my_rsv->rsv_end + grp_goal - 1); + + if ((my_rsv->rsv_start > group_last_block) || + (my_rsv->rsv_end < group_first_block)) { + rsv_window_dump(&EXT3_SB(sb)->s_rsv_window_root, 1); + BUG(); + } + ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, + grp_goal, &num, &my_rsv->rsv_window); + if (ret >= 0) { + my_rsv->rsv_alloc_hit += num; + *count = num; + break; /* succeed */ + } + num = *count; + } +out: + if (ret >= 0) { + BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for " + "bitmap block"); + fatal = ext3_journal_dirty_metadata(handle, bitmap_bh); + if (fatal) { + *errp = fatal; + return -1; + } + return ret; + } + + BUFFER_TRACE(bitmap_bh, "journal_release_buffer"); + ext3_journal_release_buffer(handle, bitmap_bh); + return ret; +} + +/** + * ext3_has_free_blocks() + * @sbi: in-core super block structure. + * + * Check if filesystem has at least 1 free block available for allocation. + */ +static int ext3_has_free_blocks(struct ext3_sb_info *sbi) +{ + ext3_fsblk_t free_blocks, root_blocks; + + free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); + root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); + if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && + sbi->s_resuid != current->fsuid && + (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { + return 0; + } + return 1; +} + +/** + * ext3_should_retry_alloc() + * @sb: super block + * @retries number of attemps has been made + * + * ext3_should_retry_alloc() is called when ENOSPC is returned, and if + * it is profitable to retry the operation, this function will wait + * for the current or commiting transaction to complete, and then + * return TRUE. + * + * if the total number of retries exceed three times, return FALSE. + */ +int ext3_should_retry_alloc(struct super_block *sb, int *retries) +{ + if (!ext3_has_free_blocks(EXT3_SB(sb)) || (*retries)++ > 3) + return 0; + + jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id); + + return journal_force_commit_nested(EXT3_SB(sb)->s_journal); +} + +/** + * ext3_new_blocks() -- core block(s) allocation function + * @handle: handle to this transaction + * @inode: file inode + * @goal: given target block(filesystem wide) + * @count: target number of blocks to allocate + * @errp: error code + * + * ext3_new_blocks uses a goal block to assist allocation. It tries to + * allocate block(s) from the block group contains the goal block first. If that + * fails, it will try to allocate block(s) from other block groups without + * any specific goal block. + * + */ +ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode, + ext3_fsblk_t goal, unsigned long *count, int *errp) +{ + struct buffer_head *bitmap_bh = NULL; + struct buffer_head *gdp_bh; + int group_no; + int goal_group; + ext3_grpblk_t grp_target_blk; /* blockgroup relative goal block */ + ext3_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/ + ext3_fsblk_t ret_block; /* filesyetem-wide allocated block */ + int bgi; /* blockgroup iteration index */ + int fatal = 0, err; + int performed_allocation = 0; + ext3_grpblk_t free_blocks; /* number of free blocks in a group */ + struct super_block *sb; + struct ext3_group_desc *gdp; + struct ext3_super_block *es; + struct ext3_sb_info *sbi; + struct ext3_reserve_window_node *my_rsv = NULL; + struct ext3_block_alloc_info *block_i; + unsigned short windowsz = 0; +#ifdef EXT3FS_DEBUG + static int goal_hits, goal_attempts; +#endif + unsigned long ngroups; + unsigned long num = *count; + + *errp = -ENOSPC; + sb = inode->i_sb; + if (!sb) { + printk("ext3_new_block: nonexistent device"); + return 0; + } + + /* + * Check quota for allocation of this block. + */ + if (DQUOT_ALLOC_BLOCK(inode, num)) { + *errp = -EDQUOT; + return 0; + } + + sbi = EXT3_SB(sb); + es = EXT3_SB(sb)->s_es; + ext3_debug("goal=%lu.\n", goal); + /* + * Allocate a block from reservation only when + * filesystem is mounted with reservation(default,-o reservation), and + * it's a regular file, and + * the desired window size is greater than 0 (One could use ioctl + * command EXT3_IOC_SETRSVSZ to set the window size to 0 to turn off + * reservation on that particular file) + */ + block_i = EXT3_I(inode)->i_block_alloc_info; + if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0)) + my_rsv = &block_i->rsv_window_node; + + if (!ext3_has_free_blocks(sbi)) { + *errp = -ENOSPC; + goto out; + } + + /* + * First, test whether the goal block is free. + */ + if (goal < le32_to_cpu(es->s_first_data_block) || + goal >= le32_to_cpu(es->s_blocks_count)) + goal = le32_to_cpu(es->s_first_data_block); + group_no = (goal - le32_to_cpu(es->s_first_data_block)) / + EXT3_BLOCKS_PER_GROUP(sb); + goal_group = group_no; +retry_alloc: + gdp = ext3_get_group_desc(sb, group_no, &gdp_bh); + if (!gdp) + goto io_error; + + free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); + /* + * if there is not enough free blocks to make a new resevation + * turn off reservation for this allocation + */ + if (my_rsv && (free_blocks < windowsz) + && (rsv_is_empty(&my_rsv->rsv_window))) + my_rsv = NULL; + + if (free_blocks > 0) { + grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb)); + bitmap_bh = read_block_bitmap(sb, group_no); + if (!bitmap_bh) + goto io_error; + grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle, + group_no, bitmap_bh, grp_target_blk, + my_rsv, &num, &fatal); + if (fatal) + goto out; + if (grp_alloc_blk >= 0) + goto allocated; + } + + ngroups = EXT3_SB(sb)->s_groups_count; + smp_rmb(); + + /* + * Now search the rest of the groups. We assume that + * i and gdp correctly point to the last group visited. + */ + for (bgi = 0; bgi < ngroups; bgi++) { + group_no++; + if (group_no >= ngroups) + group_no = 0; + gdp = ext3_get_group_desc(sb, group_no, &gdp_bh); + if (!gdp) { + *errp = -EIO; + goto out; + } + free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); + /* + * skip this group if the number of + * free blocks is less than half of the reservation + * window size. + */ + if (free_blocks <= (windowsz/2)) + continue; + + brelse(bitmap_bh); + bitmap_bh = read_block_bitmap(sb, group_no); + if (!bitmap_bh) + goto io_error; + /* + * try to allocate block(s) from this group, without a goal(-1). + */ + grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle, + group_no, bitmap_bh, -1, my_rsv, + &num, &fatal); + if (fatal) + goto out; + if (grp_alloc_blk >= 0) + goto allocated; + } + /* + * We may end up a bogus ealier ENOSPC error due to + * filesystem is "full" of reservations, but + * there maybe indeed free blocks avaliable on disk + * In this case, we just forget about the reservations + * just do block allocation as without reservations. + */ + if (my_rsv) { + my_rsv = NULL; + group_no = goal_group; + goto retry_alloc; + } + /* No space left on the device */ + *errp = -ENOSPC; + goto out; + +allocated: + + ext3_debug("using block group %d(%d)\n", + group_no, gdp->bg_free_blocks_count); + + BUFFER_TRACE(gdp_bh, "get_write_access"); + fatal = ext3_journal_get_write_access(handle, gdp_bh); + if (fatal) + goto out; + + ret_block = grp_alloc_blk + ext3_group_first_block_no(sb, group_no); + + if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) || + in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) || + in_range(ret_block, le32_to_cpu(gdp->bg_inode_table), + EXT3_SB(sb)->s_itb_per_group) || + in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table), + EXT3_SB(sb)->s_itb_per_group)) + ext3_error(sb, "ext3_new_block", + "Allocating block in system zone - " + "blocks from "E3FSBLK", length %lu", + ret_block, num); + + performed_allocation = 1; + +#ifdef CONFIG_JBD_DEBUG + { + struct buffer_head *debug_bh; + + /* Record bitmap buffer state in the newly allocated block */ + debug_bh = sb_find_get_block(sb, ret_block); + if (debug_bh) { + BUFFER_TRACE(debug_bh, "state when allocated"); + BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state"); + brelse(debug_bh); + } + } + jbd_lock_bh_state(bitmap_bh); + spin_lock(sb_bgl_lock(sbi, group_no)); + if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) { + int i; + + for (i = 0; i < num; i++) { + if (ext3_test_bit(grp_alloc_blk+i, + bh2jh(bitmap_bh)->b_committed_data)) { + printk("%s: block was unexpectedly set in " + "b_committed_data\n", __FUNCTION__); + } + } + } + ext3_debug("found bit %d\n", grp_alloc_blk); + spin_unlock(sb_bgl_lock(sbi, group_no)); + jbd_unlock_bh_state(bitmap_bh); +#endif + + if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) { + ext3_error(sb, "ext3_new_block", + "block("E3FSBLK") >= blocks count(%d) - " + "block_group = %d, es == %p ", ret_block, + le32_to_cpu(es->s_blocks_count), group_no, es); + goto out; + } + + /* + * It is up to the caller to add the new buffer to a journal + * list of some description. We don't know in advance whether + * the caller wants to use it as metadata or data. + */ + ext3_debug("allocating block %lu. Goal hits %d of %d.\n", + ret_block, goal_hits, goal_attempts); + + spin_lock(sb_bgl_lock(sbi, group_no)); + gdp->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num); + spin_unlock(sb_bgl_lock(sbi, group_no)); + percpu_counter_mod(&sbi->s_freeblocks_counter, -num); + + BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); + err = ext3_journal_dirty_metadata(handle, gdp_bh); + if (!fatal) + fatal = err; + + sb->s_dirt = 1; + if (fatal) + goto out; + + *errp = 0; + brelse(bitmap_bh); + DQUOT_FREE_BLOCK(inode, *count-num); + *count = num; + return ret_block; + +io_error: + *errp = -EIO; +out: + if (fatal) { + *errp = fatal; + ext3_std_error(sb, fatal); + } + /* + * Undo the block allocation + */ + if (!performed_allocation) + DQUOT_FREE_BLOCK(inode, *count); + brelse(bitmap_bh); + return 0; +} + +ext3_fsblk_t ext3_new_block(handle_t *handle, struct inode *inode, + ext3_fsblk_t goal, int *errp) +{ + unsigned long count = 1; + + return ext3_new_blocks(handle, inode, goal, &count, errp); +} + +/** + * ext3_count_free_blocks() -- count filesystem free blocks + * @sb: superblock + * + * Adds up the number of free blocks from each block group. + */ +ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb) +{ + ext3_fsblk_t desc_count; + struct ext3_group_desc *gdp; + int i; + unsigned long ngroups = EXT3_SB(sb)->s_groups_count; +#ifdef EXT3FS_DEBUG + struct ext3_super_block *es; + ext3_fsblk_t bitmap_count; + unsigned long x; + struct buffer_head *bitmap_bh = NULL; + + es = EXT3_SB(sb)->s_es; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + + smp_rmb(); + for (i = 0; i < ngroups; i++) { + gdp = ext3_get_group_desc(sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_blocks_count); + brelse(bitmap_bh); + bitmap_bh = read_block_bitmap(sb, i); + if (bitmap_bh == NULL) + continue; + + x = ext3_count_free(bitmap_bh, sb->s_blocksize); + printk("group %d: stored = %d, counted = %lu\n", + i, le16_to_cpu(gdp->bg_free_blocks_count), x); + bitmap_count += x; + } + brelse(bitmap_bh); + printk("ext3_count_free_blocks: stored = "E3FSBLK + ", computed = "E3FSBLK", "E3FSBLK"\n", + le32_to_cpu(es->s_free_blocks_count), + desc_count, bitmap_count); + return bitmap_count; +#else + desc_count = 0; + smp_rmb(); + for (i = 0; i < ngroups; i++) { + gdp = ext3_get_group_desc(sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_blocks_count); + } + + return desc_count; +#endif +} + +static inline int +block_in_use(ext3_fsblk_t block, struct super_block *sb, unsigned char *map) +{ + return ext3_test_bit ((block - + le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb), map); +} + +static inline int test_root(int a, int b) +{ + int num = b; + + while (a > num) + num *= b; + return num == a; +} + +static int ext3_group_sparse(int group) +{ + if (group <= 1) + return 1; + if (!(group & 1)) + return 0; + return (test_root(group, 7) || test_root(group, 5) || + test_root(group, 3)); +} + +/** + * ext3_bg_has_super - number of blocks used by the superblock in group + * @sb: superblock for filesystem + * @group: group number to check + * + * Return the number of blocks used by the superblock (primary or backup) + * in this group. Currently this will be only 0 or 1. + */ +int ext3_bg_has_super(struct super_block *sb, int group) +{ + if (EXT3_HAS_RO_COMPAT_FEATURE(sb, + EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) && + !ext3_group_sparse(group)) + return 0; + return 1; +} + +static unsigned long ext3_bg_num_gdb_meta(struct super_block *sb, int group) +{ + unsigned long metagroup = group / EXT3_DESC_PER_BLOCK(sb); + unsigned long first = metagroup * EXT3_DESC_PER_BLOCK(sb); + unsigned long last = first + EXT3_DESC_PER_BLOCK(sb) - 1; + + if (group == first || group == first + 1 || group == last) + return 1; + return 0; +} + +static unsigned long ext3_bg_num_gdb_nometa(struct super_block *sb, int group) +{ + if (EXT3_HAS_RO_COMPAT_FEATURE(sb, + EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) && + !ext3_group_sparse(group)) + return 0; + return EXT3_SB(sb)->s_gdb_count; +} + +/** + * ext3_bg_num_gdb - number of blocks used by the group table in group + * @sb: superblock for filesystem + * @group: group number to check + * + * Return the number of blocks used by the group descriptor table + * (primary or backup) in this group. In the future there may be a + * different number of descriptor blocks in each group. + */ +unsigned long ext3_bg_num_gdb(struct super_block *sb, int group) +{ + unsigned long first_meta_bg = + le32_to_cpu(EXT3_SB(sb)->s_es->s_first_meta_bg); + unsigned long metagroup = group / EXT3_DESC_PER_BLOCK(sb); + + if (!EXT3_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_META_BG) || + metagroup < first_meta_bg) + return ext3_bg_num_gdb_nometa(sb,group); + + return ext3_bg_num_gdb_meta(sb,group); + +} diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c new file mode 100644 index 000000000000..b9176eed98d1 --- /dev/null +++ b/fs/ext4/bitmap.c @@ -0,0 +1,32 @@ +/* + * linux/fs/ext3/bitmap.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include +#include +#include + +#ifdef EXT3FS_DEBUG + +static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; + +unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars) +{ + unsigned int i; + unsigned long sum = 0; + + if (!map) + return (0); + for (i = 0; i < numchars; i++) + sum += nibblemap[map->b_data[i] & 0xf] + + nibblemap[(map->b_data[i] >> 4) & 0xf]; + return (sum); +} + +#endif /* EXT3FS_DEBUG */ + diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c new file mode 100644 index 000000000000..d0b54f30b914 --- /dev/null +++ b/fs/ext4/dir.c @@ -0,0 +1,518 @@ +/* + * linux/fs/ext3/dir.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/dir.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext3 directory handling functions + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + * + * Hash Tree Directory indexing (c) 2001 Daniel Phillips + * + */ + +#include +#include +#include +#include +#include +#include +#include + +static unsigned char ext3_filetype_table[] = { + DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK +}; + +static int ext3_readdir(struct file *, void *, filldir_t); +static int ext3_dx_readdir(struct file * filp, + void * dirent, filldir_t filldir); +static int ext3_release_dir (struct inode * inode, + struct file * filp); + +const struct file_operations ext3_dir_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .readdir = ext3_readdir, /* we take BKL. needed?*/ + .ioctl = ext3_ioctl, /* BKL held */ +#ifdef CONFIG_COMPAT + .compat_ioctl = ext3_compat_ioctl, +#endif + .fsync = ext3_sync_file, /* BKL held */ +#ifdef CONFIG_EXT3_INDEX + .release = ext3_release_dir, +#endif +}; + + +static unsigned char get_dtype(struct super_block *sb, int filetype) +{ + if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_FILETYPE) || + (filetype >= EXT3_FT_MAX)) + return DT_UNKNOWN; + + return (ext3_filetype_table[filetype]); +} + + +int ext3_check_dir_entry (const char * function, struct inode * dir, + struct ext3_dir_entry_2 * de, + struct buffer_head * bh, + unsigned long offset) +{ + const char * error_msg = NULL; + const int rlen = le16_to_cpu(de->rec_len); + + if (rlen < EXT3_DIR_REC_LEN(1)) + error_msg = "rec_len is smaller than minimal"; + else if (rlen % 4 != 0) + error_msg = "rec_len % 4 != 0"; + else if (rlen < EXT3_DIR_REC_LEN(de->name_len)) + error_msg = "rec_len is too small for name_len"; + else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) + error_msg = "directory entry across blocks"; + else if (le32_to_cpu(de->inode) > + le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count)) + error_msg = "inode out of bounds"; + + if (error_msg != NULL) + ext3_error (dir->i_sb, function, + "bad entry in directory #%lu: %s - " + "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", + dir->i_ino, error_msg, offset, + (unsigned long) le32_to_cpu(de->inode), + rlen, de->name_len); + return error_msg == NULL ? 1 : 0; +} + +static int ext3_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + int error = 0; + unsigned long offset; + int i, stored; + struct ext3_dir_entry_2 *de; + struct super_block *sb; + int err; + struct inode *inode = filp->f_dentry->d_inode; + int ret = 0; + + sb = inode->i_sb; + +#ifdef CONFIG_EXT3_INDEX + if (EXT3_HAS_COMPAT_FEATURE(inode->i_sb, + EXT3_FEATURE_COMPAT_DIR_INDEX) && + ((EXT3_I(inode)->i_flags & EXT3_INDEX_FL) || + ((inode->i_size >> sb->s_blocksize_bits) == 1))) { + err = ext3_dx_readdir(filp, dirent, filldir); + if (err != ERR_BAD_DX_DIR) { + ret = err; + goto out; + } + /* + * We don't set the inode dirty flag since it's not + * critical that it get flushed back to the disk. + */ + EXT3_I(filp->f_dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL; + } +#endif + stored = 0; + offset = filp->f_pos & (sb->s_blocksize - 1); + + while (!error && !stored && filp->f_pos < inode->i_size) { + unsigned long blk = filp->f_pos >> EXT3_BLOCK_SIZE_BITS(sb); + struct buffer_head map_bh; + struct buffer_head *bh = NULL; + + map_bh.b_state = 0; + err = ext3_get_blocks_handle(NULL, inode, blk, 1, + &map_bh, 0, 0); + if (err > 0) { + page_cache_readahead(sb->s_bdev->bd_inode->i_mapping, + &filp->f_ra, + filp, + map_bh.b_blocknr >> + (PAGE_CACHE_SHIFT - inode->i_blkbits), + 1); + bh = ext3_bread(NULL, inode, blk, 0, &err); + } + + /* + * We ignore I/O errors on directories so users have a chance + * of recovering data when there's a bad sector + */ + if (!bh) { + ext3_error (sb, "ext3_readdir", + "directory #%lu contains a hole at offset %lu", + inode->i_ino, (unsigned long)filp->f_pos); + filp->f_pos += sb->s_blocksize - offset; + continue; + } + +revalidate: + /* If the dir block has changed since the last call to + * readdir(2), then we might be pointing to an invalid + * dirent right now. Scan from the start of the block + * to make sure. */ + if (filp->f_version != inode->i_version) { + for (i = 0; i < sb->s_blocksize && i < offset; ) { + de = (struct ext3_dir_entry_2 *) + (bh->b_data + i); + /* It's too expensive to do a full + * dirent test each time round this + * loop, but we do have to test at + * least that it is non-zero. A + * failure will be detected in the + * dirent test below. */ + if (le16_to_cpu(de->rec_len) < + EXT3_DIR_REC_LEN(1)) + break; + i += le16_to_cpu(de->rec_len); + } + offset = i; + filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) + | offset; + filp->f_version = inode->i_version; + } + + while (!error && filp->f_pos < inode->i_size + && offset < sb->s_blocksize) { + de = (struct ext3_dir_entry_2 *) (bh->b_data + offset); + if (!ext3_check_dir_entry ("ext3_readdir", inode, de, + bh, offset)) { + /* On error, skip the f_pos to the + next block. */ + filp->f_pos = (filp->f_pos | + (sb->s_blocksize - 1)) + 1; + brelse (bh); + ret = stored; + goto out; + } + offset += le16_to_cpu(de->rec_len); + if (le32_to_cpu(de->inode)) { + /* We might block in the next section + * if the data destination is + * currently swapped out. So, use a + * version stamp to detect whether or + * not the directory has been modified + * during the copy operation. + */ + unsigned long version = filp->f_version; + + error = filldir(dirent, de->name, + de->name_len, + filp->f_pos, + le32_to_cpu(de->inode), + get_dtype(sb, de->file_type)); + if (error) + break; + if (version != filp->f_version) + goto revalidate; + stored ++; + } + filp->f_pos += le16_to_cpu(de->rec_len); + } + offset = 0; + brelse (bh); + } +out: + return ret; +} + +#ifdef CONFIG_EXT3_INDEX +/* + * These functions convert from the major/minor hash to an f_pos + * value. + * + * Currently we only use major hash numer. This is unfortunate, but + * on 32-bit machines, the same VFS interface is used for lseek and + * llseek, so if we use the 64 bit offset, then the 32-bit versions of + * lseek/telldir/seekdir will blow out spectacularly, and from within + * the ext2 low-level routine, we don't know if we're being called by + * a 64-bit version of the system call or the 32-bit version of the + * system call. Worse yet, NFSv2 only allows for a 32-bit readdir + * cookie. Sigh. + */ +#define hash2pos(major, minor) (major >> 1) +#define pos2maj_hash(pos) ((pos << 1) & 0xffffffff) +#define pos2min_hash(pos) (0) + +/* + * This structure holds the nodes of the red-black tree used to store + * the directory entry in hash order. + */ +struct fname { + __u32 hash; + __u32 minor_hash; + struct rb_node rb_hash; + struct fname *next; + __u32 inode; + __u8 name_len; + __u8 file_type; + char name[0]; +}; + +/* + * This functoin implements a non-recursive way of freeing all of the + * nodes in the red-black tree. + */ +static void free_rb_tree_fname(struct rb_root *root) +{ + struct rb_node *n = root->rb_node; + struct rb_node *parent; + struct fname *fname; + + while (n) { + /* Do the node's children first */ + if ((n)->rb_left) { + n = n->rb_left; + continue; + } + if (n->rb_right) { + n = n->rb_right; + continue; + } + /* + * The node has no children; free it, and then zero + * out parent's link to it. Finally go to the + * beginning of the loop and try to free the parent + * node. + */ + parent = rb_parent(n); + fname = rb_entry(n, struct fname, rb_hash); + while (fname) { + struct fname * old = fname; + fname = fname->next; + kfree (old); + } + if (!parent) + root->rb_node = NULL; + else if (parent->rb_left == n) + parent->rb_left = NULL; + else if (parent->rb_right == n) + parent->rb_right = NULL; + n = parent; + } + root->rb_node = NULL; +} + + +static struct dir_private_info *create_dir_info(loff_t pos) +{ + struct dir_private_info *p; + + p = kmalloc(sizeof(struct dir_private_info), GFP_KERNEL); + if (!p) + return NULL; + p->root.rb_node = NULL; + p->curr_node = NULL; + p->extra_fname = NULL; + p->last_pos = 0; + p->curr_hash = pos2maj_hash(pos); + p->curr_minor_hash = pos2min_hash(pos); + p->next_hash = 0; + return p; +} + +void ext3_htree_free_dir_info(struct dir_private_info *p) +{ + free_rb_tree_fname(&p->root); + kfree(p); +} + +/* + * Given a directory entry, enter it into the fname rb tree. + */ +int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, + __u32 minor_hash, + struct ext3_dir_entry_2 *dirent) +{ + struct rb_node **p, *parent = NULL; + struct fname * fname, *new_fn; + struct dir_private_info *info; + int len; + + info = (struct dir_private_info *) dir_file->private_data; + p = &info->root.rb_node; + + /* Create and allocate the fname structure */ + len = sizeof(struct fname) + dirent->name_len + 1; + new_fn = kzalloc(len, GFP_KERNEL); + if (!new_fn) + return -ENOMEM; + new_fn->hash = hash; + new_fn->minor_hash = minor_hash; + new_fn->inode = le32_to_cpu(dirent->inode); + new_fn->name_len = dirent->name_len; + new_fn->file_type = dirent->file_type; + memcpy(new_fn->name, dirent->name, dirent->name_len); + new_fn->name[dirent->name_len] = 0; + + while (*p) { + parent = *p; + fname = rb_entry(parent, struct fname, rb_hash); + + /* + * If the hash and minor hash match up, then we put + * them on a linked list. This rarely happens... + */ + if ((new_fn->hash == fname->hash) && + (new_fn->minor_hash == fname->minor_hash)) { + new_fn->next = fname->next; + fname->next = new_fn; + return 0; + } + + if (new_fn->hash < fname->hash) + p = &(*p)->rb_left; + else if (new_fn->hash > fname->hash) + p = &(*p)->rb_right; + else if (new_fn->minor_hash < fname->minor_hash) + p = &(*p)->rb_left; + else /* if (new_fn->minor_hash > fname->minor_hash) */ + p = &(*p)->rb_right; + } + + rb_link_node(&new_fn->rb_hash, parent, p); + rb_insert_color(&new_fn->rb_hash, &info->root); + return 0; +} + + + +/* + * This is a helper function for ext3_dx_readdir. It calls filldir + * for all entres on the fname linked list. (Normally there is only + * one entry on the linked list, unless there are 62 bit hash collisions.) + */ +static int call_filldir(struct file * filp, void * dirent, + filldir_t filldir, struct fname *fname) +{ + struct dir_private_info *info = filp->private_data; + loff_t curr_pos; + struct inode *inode = filp->f_dentry->d_inode; + struct super_block * sb; + int error; + + sb = inode->i_sb; + + if (!fname) { + printk("call_filldir: called with null fname?!?\n"); + return 0; + } + curr_pos = hash2pos(fname->hash, fname->minor_hash); + while (fname) { + error = filldir(dirent, fname->name, + fname->name_len, curr_pos, + fname->inode, + get_dtype(sb, fname->file_type)); + if (error) { + filp->f_pos = curr_pos; + info->extra_fname = fname->next; + return error; + } + fname = fname->next; + } + return 0; +} + +static int ext3_dx_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + struct dir_private_info *info = filp->private_data; + struct inode *inode = filp->f_dentry->d_inode; + struct fname *fname; + int ret; + + if (!info) { + info = create_dir_info(filp->f_pos); + if (!info) + return -ENOMEM; + filp->private_data = info; + } + + if (filp->f_pos == EXT3_HTREE_EOF) + return 0; /* EOF */ + + /* Some one has messed with f_pos; reset the world */ + if (info->last_pos != filp->f_pos) { + free_rb_tree_fname(&info->root); + info->curr_node = NULL; + info->extra_fname = NULL; + info->curr_hash = pos2maj_hash(filp->f_pos); + info->curr_minor_hash = pos2min_hash(filp->f_pos); + } + + /* + * If there are any leftover names on the hash collision + * chain, return them first. + */ + if (info->extra_fname && + call_filldir(filp, dirent, filldir, info->extra_fname)) + goto finished; + + if (!info->curr_node) + info->curr_node = rb_first(&info->root); + + while (1) { + /* + * Fill the rbtree if we have no more entries, + * or the inode has changed since we last read in the + * cached entries. + */ + if ((!info->curr_node) || + (filp->f_version != inode->i_version)) { + info->curr_node = NULL; + free_rb_tree_fname(&info->root); + filp->f_version = inode->i_version; + ret = ext3_htree_fill_tree(filp, info->curr_hash, + info->curr_minor_hash, + &info->next_hash); + if (ret < 0) + return ret; + if (ret == 0) { + filp->f_pos = EXT3_HTREE_EOF; + break; + } + info->curr_node = rb_first(&info->root); + } + + fname = rb_entry(info->curr_node, struct fname, rb_hash); + info->curr_hash = fname->hash; + info->curr_minor_hash = fname->minor_hash; + if (call_filldir(filp, dirent, filldir, fname)) + break; + + info->curr_node = rb_next(info->curr_node); + if (!info->curr_node) { + if (info->next_hash == ~0) { + filp->f_pos = EXT3_HTREE_EOF; + break; + } + info->curr_hash = info->next_hash; + info->curr_minor_hash = 0; + } + } +finished: + info->last_pos = filp->f_pos; + return 0; +} + +static int ext3_release_dir (struct inode * inode, struct file * filp) +{ + if (filp->private_data) + ext3_htree_free_dir_info(filp->private_data); + + return 0; +} + +#endif diff --git a/fs/ext4/file.c b/fs/ext4/file.c new file mode 100644 index 000000000000..e96c388047e0 --- /dev/null +++ b/fs/ext4/file.c @@ -0,0 +1,139 @@ +/* + * linux/fs/ext3/file.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/file.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext3 fs regular file handling primitives + * + * 64-bit file support on 64-bit platforms by Jakub Jelinek + * (jj@sunsite.ms.mff.cuni.cz) + */ + +#include +#include +#include +#include +#include +#include "xattr.h" +#include "acl.h" + +/* + * Called when an inode is released. Note that this is different + * from ext3_file_open: open gets called at every open, but release + * gets called only when /all/ the files are closed. + */ +static int ext3_release_file (struct inode * inode, struct file * filp) +{ + /* if we are the last writer on the inode, drop the block reservation */ + if ((filp->f_mode & FMODE_WRITE) && + (atomic_read(&inode->i_writecount) == 1)) + { + mutex_lock(&EXT3_I(inode)->truncate_mutex); + ext3_discard_reservation(inode); + mutex_unlock(&EXT3_I(inode)->truncate_mutex); + } + if (is_dx(inode) && filp->private_data) + ext3_htree_free_dir_info(filp->private_data); + + return 0; +} + +static ssize_t +ext3_file_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_dentry->d_inode; + ssize_t ret; + int err; + + ret = generic_file_aio_write(iocb, iov, nr_segs, pos); + + /* + * Skip flushing if there was an error, or if nothing was written. + */ + if (ret <= 0) + return ret; + + /* + * If the inode is IS_SYNC, or is O_SYNC and we are doing data + * journalling then we need to make sure that we force the transaction + * to disk to keep all metadata uptodate synchronously. + */ + if (file->f_flags & O_SYNC) { + /* + * If we are non-data-journaled, then the dirty data has + * already been flushed to backing store by generic_osync_inode, + * and the inode has been flushed too if there have been any + * modifications other than mere timestamp updates. + * + * Open question --- do we care about flushing timestamps too + * if the inode is IS_SYNC? + */ + if (!ext3_should_journal_data(inode)) + return ret; + + goto force_commit; + } + + /* + * So we know that there has been no forced data flush. If the inode + * is marked IS_SYNC, we need to force one ourselves. + */ + if (!IS_SYNC(inode)) + return ret; + + /* + * Open question #2 --- should we force data to disk here too? If we + * don't, the only impact is that data=writeback filesystems won't + * flush data to disk automatically on IS_SYNC, only metadata (but + * historically, that is what ext2 has done.) + */ + +force_commit: + err = ext3_force_commit(inode->i_sb); + if (err) + return err; + return ret; +} + +const struct file_operations ext3_file_operations = { + .llseek = generic_file_llseek, + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = ext3_file_write, + .ioctl = ext3_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ext3_compat_ioctl, +#endif + .mmap = generic_file_mmap, + .open = generic_file_open, + .release = ext3_release_file, + .fsync = ext3_sync_file, + .sendfile = generic_file_sendfile, + .splice_read = generic_file_splice_read, + .splice_write = generic_file_splice_write, +}; + +struct inode_operations ext3_file_inode_operations = { + .truncate = ext3_truncate, + .setattr = ext3_setattr, +#ifdef CONFIG_EXT3_FS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ext3_listxattr, + .removexattr = generic_removexattr, +#endif + .permission = ext3_permission, +}; + diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c new file mode 100644 index 000000000000..dd1fd3c0fc05 --- /dev/null +++ b/fs/ext4/fsync.c @@ -0,0 +1,88 @@ +/* + * linux/fs/ext3/fsync.c + * + * Copyright (C) 1993 Stephen Tweedie (sct@redhat.com) + * from + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * from + * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds + * + * ext3fs fsync primitive + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + * + * Removed unnecessary code duplication for little endian machines + * and excessive __inline__s. + * Andi Kleen, 1997 + * + * Major simplications and cleanup - we only need to do the metadata, because + * we can depend on generic_block_fdatasync() to sync the data blocks. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * akpm: A new design for ext3_sync_file(). + * + * This is only called from sys_fsync(), sys_fdatasync() and sys_msync(). + * There cannot be a transaction open by this task. + * Another task could have dirtied this inode. Its data can be in any + * state in the journalling system. + * + * What we do is just kick off a commit and wait on it. This will snapshot the + * inode to disk. + */ + +int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) +{ + struct inode *inode = dentry->d_inode; + int ret = 0; + + J_ASSERT(ext3_journal_current_handle() == 0); + + /* + * data=writeback: + * The caller's filemap_fdatawrite()/wait will sync the data. + * sync_inode() will sync the metadata + * + * data=ordered: + * The caller's filemap_fdatawrite() will write the data and + * sync_inode() will write the inode if it is dirty. Then the caller's + * filemap_fdatawait() will wait on the pages. + * + * data=journal: + * filemap_fdatawrite won't do anything (the buffers are clean). + * ext3_force_commit will write the file data into the journal and + * will wait on that. + * filemap_fdatawait() will encounter a ton of newly-dirtied pages + * (they were dirtied by commit). But that's OK - the blocks are + * safe in-journal, which is all fsync() needs to ensure. + */ + if (ext3_should_journal_data(inode)) { + ret = ext3_force_commit(inode->i_sb); + goto out; + } + + /* + * The VFS has written the file data. If the inode is unaltered + * then we need not start a commit. + */ + if (inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC)) { + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 0, /* sys_fsync did this */ + }; + ret = sync_inode(inode, &wbc); + } +out: + return ret; +} diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c new file mode 100644 index 000000000000..deeb27b5ba83 --- /dev/null +++ b/fs/ext4/hash.c @@ -0,0 +1,152 @@ +/* + * linux/fs/ext3/hash.c + * + * Copyright (C) 2002 by Theodore Ts'o + * + * This file is released under the GPL v2. + * + * This file may be redistributed under the terms of the GNU Public + * License. + */ + +#include +#include +#include +#include +#include + +#define DELTA 0x9E3779B9 + +static void TEA_transform(__u32 buf[4], __u32 const in[]) +{ + __u32 sum = 0; + __u32 b0 = buf[0], b1 = buf[1]; + __u32 a = in[0], b = in[1], c = in[2], d = in[3]; + int n = 16; + + do { + sum += DELTA; + b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); + b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); + } while(--n); + + buf[0] += b0; + buf[1] += b1; +} + + +/* The old legacy hash */ +static __u32 dx_hack_hash (const char *name, int len) +{ + __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; + while (len--) { + __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373)); + + if (hash & 0x80000000) hash -= 0x7fffffff; + hash1 = hash0; + hash0 = hash; + } + return (hash0 << 1); +} + +static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) +{ + __u32 pad, val; + int i; + + pad = (__u32)len | ((__u32)len << 8); + pad |= pad << 16; + + val = pad; + if (len > num*4) + len = num * 4; + for (i=0; i < len; i++) { + if ((i % 4) == 0) + val = pad; + val = msg[i] + (val << 8); + if ((i % 4) == 3) { + *buf++ = val; + val = pad; + num--; + } + } + if (--num >= 0) + *buf++ = val; + while (--num >= 0) + *buf++ = pad; +} + +/* + * Returns the hash of a filename. If len is 0 and name is NULL, then + * this function can be used to test whether or not a hash version is + * supported. + * + * The seed is an 4 longword (32 bits) "secret" which can be used to + * uniquify a hash. If the seed is all zero's, then some default seed + * may be used. + * + * A particular hash version specifies whether or not the seed is + * represented, and whether or not the returned hash is 32 bits or 64 + * bits. 32 bit hashes will return 0 for the minor hash. + */ +int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) +{ + __u32 hash; + __u32 minor_hash = 0; + const char *p; + int i; + __u32 in[8], buf[4]; + + /* Initialize the default seed for the hash checksum functions */ + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + + /* Check to see if the seed is all zero's */ + if (hinfo->seed) { + for (i=0; i < 4; i++) { + if (hinfo->seed[i]) + break; + } + if (i < 4) + memcpy(buf, hinfo->seed, sizeof(buf)); + } + + switch (hinfo->hash_version) { + case DX_HASH_LEGACY: + hash = dx_hack_hash(name, len); + break; + case DX_HASH_HALF_MD4: + p = name; + while (len > 0) { + str2hashbuf(p, len, in, 8); + half_md4_transform(buf, in); + len -= 32; + p += 32; + } + minor_hash = buf[2]; + hash = buf[1]; + break; + case DX_HASH_TEA: + p = name; + while (len > 0) { + str2hashbuf(p, len, in, 4); + TEA_transform(buf, in); + len -= 16; + p += 16; + } + hash = buf[0]; + minor_hash = buf[1]; + break; + default: + hinfo->hash = 0; + return -1; + } + hash = hash & ~1; + if (hash == (EXT3_HTREE_EOF << 1)) + hash = (EXT3_HTREE_EOF-1) << 1; + hinfo->hash = hash; + hinfo->minor_hash = minor_hash; + return 0; +} diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c new file mode 100644 index 000000000000..e45dbd651736 --- /dev/null +++ b/fs/ext4/ialloc.c @@ -0,0 +1,758 @@ +/* + * linux/fs/ext3/ialloc.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * BSD ufs-inspired inode and directory allocation by + * Stephen Tweedie (sct@redhat.com), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "xattr.h" +#include "acl.h" + +/* + * ialloc.c contains the inodes allocation and deallocation routines + */ + +/* + * The free inodes are managed by bitmaps. A file system contains several + * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap + * block for inodes, N blocks for the inode table and data blocks. + * + * The file system contains group descriptors which are located after the + * super block. Each descriptor contains the number of the bitmap block and + * the free blocks count in the block. + */ + + +/* + * Read the inode allocation bitmap for a given block_group, reading + * into the specified slot in the superblock's bitmap cache. + * + * Return buffer_head of bitmap on success or NULL. + */ +static struct buffer_head * +read_inode_bitmap(struct super_block * sb, unsigned long block_group) +{ + struct ext3_group_desc *desc; + struct buffer_head *bh = NULL; + + desc = ext3_get_group_desc(sb, block_group, NULL); + if (!desc) + goto error_out; + + bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap)); + if (!bh) + ext3_error(sb, "read_inode_bitmap", + "Cannot read inode bitmap - " + "block_group = %lu, inode_bitmap = %u", + block_group, le32_to_cpu(desc->bg_inode_bitmap)); +error_out: + return bh; +} + +/* + * NOTE! When we get the inode, we're the only people + * that have access to it, and as such there are no + * race conditions we have to worry about. The inode + * is not on the hash-lists, and it cannot be reached + * through the filesystem because the directory entry + * has been deleted earlier. + * + * HOWEVER: we must make sure that we get no aliases, + * which means that we have to call "clear_inode()" + * _before_ we mark the inode not in use in the inode + * bitmaps. Otherwise a newly created file might use + * the same inode number (not actually the same pointer + * though), and then we'd have two inodes sharing the + * same inode number and space on the harddisk. + */ +void ext3_free_inode (handle_t *handle, struct inode * inode) +{ + struct super_block * sb = inode->i_sb; + int is_directory; + unsigned long ino; + struct buffer_head *bitmap_bh = NULL; + struct buffer_head *bh2; + unsigned long block_group; + unsigned long bit; + struct ext3_group_desc * gdp; + struct ext3_super_block * es; + struct ext3_sb_info *sbi; + int fatal = 0, err; + + if (atomic_read(&inode->i_count) > 1) { + printk ("ext3_free_inode: inode has count=%d\n", + atomic_read(&inode->i_count)); + return; + } + if (inode->i_nlink) { + printk ("ext3_free_inode: inode has nlink=%d\n", + inode->i_nlink); + return; + } + if (!sb) { + printk("ext3_free_inode: inode on nonexistent device\n"); + return; + } + sbi = EXT3_SB(sb); + + ino = inode->i_ino; + ext3_debug ("freeing inode %lu\n", ino); + + /* + * Note: we must free any quota before locking the superblock, + * as writing the quota to disk may need the lock as well. + */ + DQUOT_INIT(inode); + ext3_xattr_delete_inode(handle, inode); + DQUOT_FREE_INODE(inode); + DQUOT_DROP(inode); + + is_directory = S_ISDIR(inode->i_mode); + + /* Do this BEFORE marking the inode not in use or returning an error */ + clear_inode (inode); + + es = EXT3_SB(sb)->s_es; + if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { + ext3_error (sb, "ext3_free_inode", + "reserved or nonexistent inode %lu", ino); + goto error_return; + } + block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); + bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb); + bitmap_bh = read_inode_bitmap(sb, block_group); + if (!bitmap_bh) + goto error_return; + + BUFFER_TRACE(bitmap_bh, "get_write_access"); + fatal = ext3_journal_get_write_access(handle, bitmap_bh); + if (fatal) + goto error_return; + + /* Ok, now we can actually update the inode bitmaps.. */ + if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group), + bit, bitmap_bh->b_data)) + ext3_error (sb, "ext3_free_inode", + "bit already cleared for inode %lu", ino); + else { + gdp = ext3_get_group_desc (sb, block_group, &bh2); + + BUFFER_TRACE(bh2, "get_write_access"); + fatal = ext3_journal_get_write_access(handle, bh2); + if (fatal) goto error_return; + + if (gdp) { + spin_lock(sb_bgl_lock(sbi, block_group)); + gdp->bg_free_inodes_count = cpu_to_le16( + le16_to_cpu(gdp->bg_free_inodes_count) + 1); + if (is_directory) + gdp->bg_used_dirs_count = cpu_to_le16( + le16_to_cpu(gdp->bg_used_dirs_count) - 1); + spin_unlock(sb_bgl_lock(sbi, block_group)); + percpu_counter_inc(&sbi->s_freeinodes_counter); + if (is_directory) + percpu_counter_dec(&sbi->s_dirs_counter); + + } + BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh2); + if (!fatal) fatal = err; + } + BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bitmap_bh); + if (!fatal) + fatal = err; + sb->s_dirt = 1; +error_return: + brelse(bitmap_bh); + ext3_std_error(sb, fatal); +} + +/* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of + * the groups with above-average free space, that group with the fewest + * directories already is chosen. + * + * For other inodes, search forward from the parent directory\'s block + * group to find a free inode. + */ +static int find_group_dir(struct super_block *sb, struct inode *parent) +{ + int ngroups = EXT3_SB(sb)->s_groups_count; + unsigned int freei, avefreei; + struct ext3_group_desc *desc, *best_desc = NULL; + struct buffer_head *bh; + int group, best_group = -1; + + freei = percpu_counter_read_positive(&EXT3_SB(sb)->s_freeinodes_counter); + avefreei = freei / ngroups; + + for (group = 0; group < ngroups; group++) { + desc = ext3_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) + continue; + if (!best_desc || + (le16_to_cpu(desc->bg_free_blocks_count) > + le16_to_cpu(best_desc->bg_free_blocks_count))) { + best_group = group; + best_desc = desc; + } + } + return best_group; +} + +/* + * Orlov's allocator for directories. + * + * We always try to spread first-level directories. + * + * If there are blockgroups with both free inodes and free blocks counts + * not worse than average we return one with smallest directory count. + * Otherwise we simply return a random group. + * + * For the rest rules look so: + * + * It's OK to put directory into a group unless + * it has too many directories already (max_dirs) or + * it has too few free inodes left (min_inodes) or + * it has too few free blocks left (min_blocks) or + * it's already running too large debt (max_debt). + * Parent's group is prefered, if it doesn't satisfy these + * conditions we search cyclically through the rest. If none + * of the groups look good we just look for a group with more + * free inodes than average (starting at parent's group). + * + * Debt is incremented each time we allocate a directory and decremented + * when we allocate an inode, within 0--255. + */ + +#define INODE_COST 64 +#define BLOCK_COST 256 + +static int find_group_orlov(struct super_block *sb, struct inode *parent) +{ + int parent_group = EXT3_I(parent)->i_block_group; + struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext3_super_block *es = sbi->s_es; + int ngroups = sbi->s_groups_count; + int inodes_per_group = EXT3_INODES_PER_GROUP(sb); + unsigned int freei, avefreei; + ext3_fsblk_t freeb, avefreeb; + ext3_fsblk_t blocks_per_dir; + unsigned int ndirs; + int max_debt, max_dirs, min_inodes; + ext3_grpblk_t min_blocks; + int group = -1, i; + struct ext3_group_desc *desc; + struct buffer_head *bh; + + freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); + avefreei = freei / ngroups; + freeb = percpu_counter_read_positive(&sbi->s_freeblocks_counter); + avefreeb = freeb / ngroups; + ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); + + if ((parent == sb->s_root->d_inode) || + (EXT3_I(parent)->i_flags & EXT3_TOPDIR_FL)) { + int best_ndir = inodes_per_group; + int best_group = -1; + + get_random_bytes(&group, sizeof(group)); + parent_group = (unsigned)group % ngroups; + for (i = 0; i < ngroups; i++) { + group = (parent_group + i) % ngroups; + desc = ext3_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) + continue; + if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb) + continue; + best_group = group; + best_ndir = le16_to_cpu(desc->bg_used_dirs_count); + } + if (best_group >= 0) + return best_group; + goto fallback; + } + + blocks_per_dir = (le32_to_cpu(es->s_blocks_count) - freeb) / ndirs; + + max_dirs = ndirs / ngroups + inodes_per_group / 16; + min_inodes = avefreei - inodes_per_group / 4; + min_blocks = avefreeb - EXT3_BLOCKS_PER_GROUP(sb) / 4; + + max_debt = EXT3_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, (ext3_fsblk_t)BLOCK_COST); + if (max_debt * INODE_COST > inodes_per_group) + max_debt = inodes_per_group / INODE_COST; + if (max_debt > 255) + max_debt = 255; + if (max_debt == 0) + max_debt = 1; + + for (i = 0; i < ngroups; i++) { + group = (parent_group + i) % ngroups; + desc = ext3_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) < min_inodes) + continue; + if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks) + continue; + return group; + } + +fallback: + for (i = 0; i < ngroups; i++) { + group = (parent_group + i) % ngroups; + desc = ext3_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) + return group; + } + + if (avefreei) { + /* + * The free-inodes counter is approximate, and for really small + * filesystems the above test can fail to find any blockgroups + */ + avefreei = 0; + goto fallback; + } + + return -1; +} + +static int find_group_other(struct super_block *sb, struct inode *parent) +{ + int parent_group = EXT3_I(parent)->i_block_group; + int ngroups = EXT3_SB(sb)->s_groups_count; + struct ext3_group_desc *desc; + struct buffer_head *bh; + int group, i; + + /* + * Try to place the inode in its parent directory + */ + group = parent_group; + desc = ext3_get_group_desc (sb, group, &bh); + if (desc && le16_to_cpu(desc->bg_free_inodes_count) && + le16_to_cpu(desc->bg_free_blocks_count)) + return group; + + /* + * We're going to place this inode in a different blockgroup from its + * parent. We want to cause files in a common directory to all land in + * the same blockgroup. But we want files which are in a different + * directory which shares a blockgroup with our parent to land in a + * different blockgroup. + * + * So add our directory's i_ino into the starting point for the hash. + */ + group = (group + parent->i_ino) % ngroups; + + /* + * Use a quadratic hash to find a group with a free inode and some free + * blocks. + */ + for (i = 1; i < ngroups; i <<= 1) { + group += i; + if (group >= ngroups) + group -= ngroups; + desc = ext3_get_group_desc (sb, group, &bh); + if (desc && le16_to_cpu(desc->bg_free_inodes_count) && + le16_to_cpu(desc->bg_free_blocks_count)) + return group; + } + + /* + * That failed: try linear search for a free inode, even if that group + * has no free blocks. + */ + group = parent_group; + for (i = 0; i < ngroups; i++) { + if (++group >= ngroups) + group = 0; + desc = ext3_get_group_desc (sb, group, &bh); + if (desc && le16_to_cpu(desc->bg_free_inodes_count)) + return group; + } + + return -1; +} + +/* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of + * the groups with above-average free space, that group with the fewest + * directories already is chosen. + * + * For other inodes, search forward from the parent directory's block + * group to find a free inode. + */ +struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) +{ + struct super_block *sb; + struct buffer_head *bitmap_bh = NULL; + struct buffer_head *bh2; + int group; + unsigned long ino = 0; + struct inode * inode; + struct ext3_group_desc * gdp = NULL; + struct ext3_super_block * es; + struct ext3_inode_info *ei; + struct ext3_sb_info *sbi; + int err = 0; + struct inode *ret; + int i; + + /* Cannot create files in a deleted directory */ + if (!dir || !dir->i_nlink) + return ERR_PTR(-EPERM); + + sb = dir->i_sb; + inode = new_inode(sb); + if (!inode) + return ERR_PTR(-ENOMEM); + ei = EXT3_I(inode); + + sbi = EXT3_SB(sb); + es = sbi->s_es; + if (S_ISDIR(mode)) { + if (test_opt (sb, OLDALLOC)) + group = find_group_dir(sb, dir); + else + group = find_group_orlov(sb, dir); + } else + group = find_group_other(sb, dir); + + err = -ENOSPC; + if (group == -1) + goto out; + + for (i = 0; i < sbi->s_groups_count; i++) { + err = -EIO; + + gdp = ext3_get_group_desc(sb, group, &bh2); + if (!gdp) + goto fail; + + brelse(bitmap_bh); + bitmap_bh = read_inode_bitmap(sb, group); + if (!bitmap_bh) + goto fail; + + ino = 0; + +repeat_in_this_group: + ino = ext3_find_next_zero_bit((unsigned long *) + bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb), ino); + if (ino < EXT3_INODES_PER_GROUP(sb)) { + + BUFFER_TRACE(bitmap_bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, bitmap_bh); + if (err) + goto fail; + + if (!ext3_set_bit_atomic(sb_bgl_lock(sbi, group), + ino, bitmap_bh->b_data)) { + /* we won it */ + BUFFER_TRACE(bitmap_bh, + "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, + bitmap_bh); + if (err) + goto fail; + goto got; + } + /* we lost it */ + journal_release_buffer(handle, bitmap_bh); + + if (++ino < EXT3_INODES_PER_GROUP(sb)) + goto repeat_in_this_group; + } + + /* + * This case is possible in concurrent environment. It is very + * rare. We cannot repeat the find_group_xxx() call because + * that will simply return the same blockgroup, because the + * group descriptor metadata has not yet been updated. + * So we just go onto the next blockgroup. + */ + if (++group == sbi->s_groups_count) + group = 0; + } + err = -ENOSPC; + goto out; + +got: + ino += group * EXT3_INODES_PER_GROUP(sb) + 1; + if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { + ext3_error (sb, "ext3_new_inode", + "reserved inode or inode > inodes count - " + "block_group = %d, inode=%lu", group, ino); + err = -EIO; + goto fail; + } + + BUFFER_TRACE(bh2, "get_write_access"); + err = ext3_journal_get_write_access(handle, bh2); + if (err) goto fail; + spin_lock(sb_bgl_lock(sbi, group)); + gdp->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1); + if (S_ISDIR(mode)) { + gdp->bg_used_dirs_count = + cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1); + } + spin_unlock(sb_bgl_lock(sbi, group)); + BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh2); + if (err) goto fail; + + percpu_counter_dec(&sbi->s_freeinodes_counter); + if (S_ISDIR(mode)) + percpu_counter_inc(&sbi->s_dirs_counter); + sb->s_dirt = 1; + + inode->i_uid = current->fsuid; + if (test_opt (sb, GRPID)) + inode->i_gid = dir->i_gid; + else if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } else + inode->i_gid = current->fsgid; + inode->i_mode = mode; + + inode->i_ino = ino; + /* This is the optimal IO size (for stat), not the fs block size */ + inode->i_blocks = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; + + memset(ei->i_data, 0, sizeof(ei->i_data)); + ei->i_dir_start_lookup = 0; + ei->i_disksize = 0; + + ei->i_flags = EXT3_I(dir)->i_flags & ~EXT3_INDEX_FL; + if (S_ISLNK(mode)) + ei->i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL); + /* dirsync only applies to directories */ + if (!S_ISDIR(mode)) + ei->i_flags &= ~EXT3_DIRSYNC_FL; +#ifdef EXT3_FRAGMENTS + ei->i_faddr = 0; + ei->i_frag_no = 0; + ei->i_frag_size = 0; +#endif + ei->i_file_acl = 0; + ei->i_dir_acl = 0; + ei->i_dtime = 0; + ei->i_block_alloc_info = NULL; + ei->i_block_group = group; + + ext3_set_inode_flags(inode); + if (IS_DIRSYNC(inode)) + handle->h_sync = 1; + insert_inode_hash(inode); + spin_lock(&sbi->s_next_gen_lock); + inode->i_generation = sbi->s_next_generation++; + spin_unlock(&sbi->s_next_gen_lock); + + ei->i_state = EXT3_STATE_NEW; + ei->i_extra_isize = + (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ? + sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE : 0; + + ret = inode; + if(DQUOT_ALLOC_INODE(inode)) { + err = -EDQUOT; + goto fail_drop; + } + + err = ext3_init_acl(handle, inode, dir); + if (err) + goto fail_free_drop; + + err = ext3_init_security(handle,inode, dir); + if (err) + goto fail_free_drop; + + err = ext3_mark_inode_dirty(handle, inode); + if (err) { + ext3_std_error(sb, err); + goto fail_free_drop; + } + + ext3_debug("allocating inode %lu\n", inode->i_ino); + goto really_out; +fail: + ext3_std_error(sb, err); +out: + iput(inode); + ret = ERR_PTR(err); +really_out: + brelse(bitmap_bh); + return ret; + +fail_free_drop: + DQUOT_FREE_INODE(inode); + +fail_drop: + DQUOT_DROP(inode); + inode->i_flags |= S_NOQUOTA; + inode->i_nlink = 0; + iput(inode); + brelse(bitmap_bh); + return ERR_PTR(err); +} + +/* Verify that we are loading a valid orphan from disk */ +struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino) +{ + unsigned long max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count); + unsigned long block_group; + int bit; + struct buffer_head *bitmap_bh = NULL; + struct inode *inode = NULL; + + /* Error cases - e2fsck has already cleaned up for us */ + if (ino > max_ino) { + ext3_warning(sb, __FUNCTION__, + "bad orphan ino %lu! e2fsck was run?", ino); + goto out; + } + + block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); + bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb); + bitmap_bh = read_inode_bitmap(sb, block_group); + if (!bitmap_bh) { + ext3_warning(sb, __FUNCTION__, + "inode bitmap error for orphan %lu", ino); + goto out; + } + + /* Having the inode bit set should be a 100% indicator that this + * is a valid orphan (no e2fsck run on fs). Orphans also include + * inodes that were being truncated, so we can't check i_nlink==0. + */ + if (!ext3_test_bit(bit, bitmap_bh->b_data) || + !(inode = iget(sb, ino)) || is_bad_inode(inode) || + NEXT_ORPHAN(inode) > max_ino) { + ext3_warning(sb, __FUNCTION__, + "bad orphan inode %lu! e2fsck was run?", ino); + printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n", + bit, (unsigned long long)bitmap_bh->b_blocknr, + ext3_test_bit(bit, bitmap_bh->b_data)); + printk(KERN_NOTICE "inode=%p\n", inode); + if (inode) { + printk(KERN_NOTICE "is_bad_inode(inode)=%d\n", + is_bad_inode(inode)); + printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n", + NEXT_ORPHAN(inode)); + printk(KERN_NOTICE "max_ino=%lu\n", max_ino); + } + /* Avoid freeing blocks if we got a bad deleted inode */ + if (inode && inode->i_nlink == 0) + inode->i_blocks = 0; + iput(inode); + inode = NULL; + } +out: + brelse(bitmap_bh); + return inode; +} + +unsigned long ext3_count_free_inodes (struct super_block * sb) +{ + unsigned long desc_count; + struct ext3_group_desc *gdp; + int i; +#ifdef EXT3FS_DEBUG + struct ext3_super_block *es; + unsigned long bitmap_count, x; + struct buffer_head *bitmap_bh = NULL; + + es = EXT3_SB(sb)->s_es; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { + gdp = ext3_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_inodes_count); + brelse(bitmap_bh); + bitmap_bh = read_inode_bitmap(sb, i); + if (!bitmap_bh) + continue; + + x = ext3_count_free(bitmap_bh, EXT3_INODES_PER_GROUP(sb) / 8); + printk("group %d: stored = %d, counted = %lu\n", + i, le16_to_cpu(gdp->bg_free_inodes_count), x); + bitmap_count += x; + } + brelse(bitmap_bh); + printk("ext3_count_free_inodes: stored = %u, computed = %lu, %lu\n", + le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count); + return desc_count; +#else + desc_count = 0; + for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { + gdp = ext3_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_inodes_count); + cond_resched(); + } + return desc_count; +#endif +} + +/* Called at mount-time, super-block is locked */ +unsigned long ext3_count_dirs (struct super_block * sb) +{ + unsigned long count = 0; + int i; + + for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { + struct ext3_group_desc *gdp = ext3_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + count += le16_to_cpu(gdp->bg_used_dirs_count); + } + return count; +} + diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c new file mode 100644 index 000000000000..03ba5bcab186 --- /dev/null +++ b/fs/ext4/inode.c @@ -0,0 +1,3219 @@ +/* + * linux/fs/ext3/inode.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Goal-directed block allocation by Stephen Tweedie + * (sct@redhat.com), 1993, 1998 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + * 64-bit file support on 64-bit platforms by Jakub Jelinek + * (jj@sunsite.ms.mff.cuni.cz) + * + * Assorted race fixes, rewrite of ext3_get_block() by Al Viro, 2000 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xattr.h" +#include "acl.h" + +static int ext3_writepage_trans_blocks(struct inode *inode); + +/* + * Test whether an inode is a fast symlink. + */ +static int ext3_inode_is_fast_symlink(struct inode *inode) +{ + int ea_blocks = EXT3_I(inode)->i_file_acl ? + (inode->i_sb->s_blocksize >> 9) : 0; + + return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0); +} + +/* + * The ext3 forget function must perform a revoke if we are freeing data + * which has been journaled. Metadata (eg. indirect blocks) must be + * revoked in all cases. + * + * "bh" may be NULL: a metadata block may have been freed from memory + * but there may still be a record of it in the journal, and that record + * still needs to be revoked. + */ +int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode, + struct buffer_head *bh, ext3_fsblk_t blocknr) +{ + int err; + + might_sleep(); + + BUFFER_TRACE(bh, "enter"); + + jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " + "data mode %lx\n", + bh, is_metadata, inode->i_mode, + test_opt(inode->i_sb, DATA_FLAGS)); + + /* Never use the revoke function if we are doing full data + * journaling: there is no need to, and a V1 superblock won't + * support it. Otherwise, only skip the revoke on un-journaled + * data blocks. */ + + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA || + (!is_metadata && !ext3_should_journal_data(inode))) { + if (bh) { + BUFFER_TRACE(bh, "call journal_forget"); + return ext3_journal_forget(handle, bh); + } + return 0; + } + + /* + * data!=journal && (is_metadata || should_journal_data(inode)) + */ + BUFFER_TRACE(bh, "call ext3_journal_revoke"); + err = ext3_journal_revoke(handle, blocknr, bh); + if (err) + ext3_abort(inode->i_sb, __FUNCTION__, + "error %d when attempting revoke", err); + BUFFER_TRACE(bh, "exit"); + return err; +} + +/* + * Work out how many blocks we need to proceed with the next chunk of a + * truncate transaction. + */ +static unsigned long blocks_for_truncate(struct inode *inode) +{ + unsigned long needed; + + needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); + + /* Give ourselves just enough room to cope with inodes in which + * i_blocks is corrupt: we've seen disk corruptions in the past + * which resulted in random data in an inode which looked enough + * like a regular file for ext3 to try to delete it. Things + * will go a bit crazy if that happens, but at least we should + * try not to panic the whole kernel. */ + if (needed < 2) + needed = 2; + + /* But we need to bound the transaction so we don't overflow the + * journal. */ + if (needed > EXT3_MAX_TRANS_DATA) + needed = EXT3_MAX_TRANS_DATA; + + return EXT3_DATA_TRANS_BLOCKS(inode->i_sb) + needed; +} + +/* + * Truncate transactions can be complex and absolutely huge. So we need to + * be able to restart the transaction at a conventient checkpoint to make + * sure we don't overflow the journal. + * + * start_transaction gets us a new handle for a truncate transaction, + * and extend_transaction tries to extend the existing one a bit. If + * extend fails, we need to propagate the failure up and restart the + * transaction in the top-level truncate loop. --sct + */ +static handle_t *start_transaction(struct inode *inode) +{ + handle_t *result; + + result = ext3_journal_start(inode, blocks_for_truncate(inode)); + if (!IS_ERR(result)) + return result; + + ext3_std_error(inode->i_sb, PTR_ERR(result)); + return result; +} + +/* + * Try to extend this transaction for the purposes of truncation. + * + * Returns 0 if we managed to create more room. If we can't create more + * room, and the transaction must be restarted we return 1. + */ +static int try_to_extend_transaction(handle_t *handle, struct inode *inode) +{ + if (handle->h_buffer_credits > EXT3_RESERVE_TRANS_BLOCKS) + return 0; + if (!ext3_journal_extend(handle, blocks_for_truncate(inode))) + return 0; + return 1; +} + +/* + * Restart the transaction associated with *handle. This does a commit, + * so before we call here everything must be consistently dirtied against + * this transaction. + */ +static int ext3_journal_test_restart(handle_t *handle, struct inode *inode) +{ + jbd_debug(2, "restarting handle %p\n", handle); + return ext3_journal_restart(handle, blocks_for_truncate(inode)); +} + +/* + * Called at the last iput() if i_nlink is zero. + */ +void ext3_delete_inode (struct inode * inode) +{ + handle_t *handle; + + truncate_inode_pages(&inode->i_data, 0); + + if (is_bad_inode(inode)) + goto no_delete; + + handle = start_transaction(inode); + if (IS_ERR(handle)) { + /* + * If we're going to skip the normal cleanup, we still need to + * make sure that the in-core orphan linked list is properly + * cleaned up. + */ + ext3_orphan_del(NULL, inode); + goto no_delete; + } + + if (IS_SYNC(inode)) + handle->h_sync = 1; + inode->i_size = 0; + if (inode->i_blocks) + ext3_truncate(inode); + /* + * Kill off the orphan record which ext3_truncate created. + * AKPM: I think this can be inside the above `if'. + * Note that ext3_orphan_del() has to be able to cope with the + * deletion of a non-existent orphan - this is because we don't + * know if ext3_truncate() actually created an orphan record. + * (Well, we could do this if we need to, but heck - it works) + */ + ext3_orphan_del(handle, inode); + EXT3_I(inode)->i_dtime = get_seconds(); + + /* + * One subtle ordering requirement: if anything has gone wrong + * (transaction abort, IO errors, whatever), then we can still + * do these next steps (the fs will already have been marked as + * having errors), but we can't free the inode if the mark_dirty + * fails. + */ + if (ext3_mark_inode_dirty(handle, inode)) + /* If that failed, just do the required in-core inode clear. */ + clear_inode(inode); + else + ext3_free_inode(handle, inode); + ext3_journal_stop(handle); + return; +no_delete: + clear_inode(inode); /* We must guarantee clearing of inode... */ +} + +typedef struct { + __le32 *p; + __le32 key; + struct buffer_head *bh; +} Indirect; + +static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) +{ + p->key = *(p->p = v); + p->bh = bh; +} + +static int verify_chain(Indirect *from, Indirect *to) +{ + while (from <= to && from->key == *from->p) + from++; + return (from > to); +} + +/** + * ext3_block_to_path - parse the block number into array of offsets + * @inode: inode in question (we are only interested in its superblock) + * @i_block: block number to be parsed + * @offsets: array to store the offsets in + * @boundary: set this non-zero if the referred-to block is likely to be + * followed (on disk) by an indirect block. + * + * To store the locations of file's data ext3 uses a data structure common + * for UNIX filesystems - tree of pointers anchored in the inode, with + * data blocks at leaves and indirect blocks in intermediate nodes. + * This function translates the block number into path in that tree - + * return value is the path length and @offsets[n] is the offset of + * pointer to (n+1)th node in the nth one. If @block is out of range + * (negative or too large) warning is printed and zero returned. + * + * Note: function doesn't find node addresses, so no IO is needed. All + * we need to know is the capacity of indirect blocks (taken from the + * inode->i_sb). + */ + +/* + * Portability note: the last comparison (check that we fit into triple + * indirect block) is spelled differently, because otherwise on an + * architecture with 32-bit longs and 8Kb pages we might get into trouble + * if our filesystem had 8Kb blocks. We might use long long, but that would + * kill us on x86. Oh, well, at least the sign propagation does not matter - + * i_block would have to be negative in the very beginning, so we would not + * get there at all. + */ + +static int ext3_block_to_path(struct inode *inode, + long i_block, int offsets[4], int *boundary) +{ + int ptrs = EXT3_ADDR_PER_BLOCK(inode->i_sb); + int ptrs_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb); + const long direct_blocks = EXT3_NDIR_BLOCKS, + indirect_blocks = ptrs, + double_blocks = (1 << (ptrs_bits * 2)); + int n = 0; + int final = 0; + + if (i_block < 0) { + ext3_warning (inode->i_sb, "ext3_block_to_path", "block < 0"); + } else if (i_block < direct_blocks) { + offsets[n++] = i_block; + final = direct_blocks; + } else if ( (i_block -= direct_blocks) < indirect_blocks) { + offsets[n++] = EXT3_IND_BLOCK; + offsets[n++] = i_block; + final = ptrs; + } else if ((i_block -= indirect_blocks) < double_blocks) { + offsets[n++] = EXT3_DIND_BLOCK; + offsets[n++] = i_block >> ptrs_bits; + offsets[n++] = i_block & (ptrs - 1); + final = ptrs; + } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { + offsets[n++] = EXT3_TIND_BLOCK; + offsets[n++] = i_block >> (ptrs_bits * 2); + offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); + offsets[n++] = i_block & (ptrs - 1); + final = ptrs; + } else { + ext3_warning(inode->i_sb, "ext3_block_to_path", "block > big"); + } + if (boundary) + *boundary = final - 1 - (i_block & (ptrs - 1)); + return n; +} + +/** + * ext3_get_branch - read the chain of indirect blocks leading to data + * @inode: inode in question + * @depth: depth of the chain (1 - direct pointer, etc.) + * @offsets: offsets of pointers in inode/indirect blocks + * @chain: place to store the result + * @err: here we store the error value + * + * Function fills the array of triples and returns %NULL + * if everything went OK or the pointer to the last filled triple + * (incomplete one) otherwise. Upon the return chain[i].key contains + * the number of (i+1)-th block in the chain (as it is stored in memory, + * i.e. little-endian 32-bit), chain[i].p contains the address of that + * number (it points into struct inode for i==0 and into the bh->b_data + * for i>0) and chain[i].bh points to the buffer_head of i-th indirect + * block for i>0 and NULL for i==0. In other words, it holds the block + * numbers of the chain, addresses they were taken from (and where we can + * verify that chain did not change) and buffer_heads hosting these + * numbers. + * + * Function stops when it stumbles upon zero pointer (absent block) + * (pointer to last triple returned, *@err == 0) + * or when it gets an IO error reading an indirect block + * (ditto, *@err == -EIO) + * or when it notices that chain had been changed while it was reading + * (ditto, *@err == -EAGAIN) + * or when it reads all @depth-1 indirect blocks successfully and finds + * the whole chain, all way to the data (returns %NULL, *err == 0). + */ +static Indirect *ext3_get_branch(struct inode *inode, int depth, int *offsets, + Indirect chain[4], int *err) +{ + struct super_block *sb = inode->i_sb; + Indirect *p = chain; + struct buffer_head *bh; + + *err = 0; + /* i_data is not going away, no lock needed */ + add_chain (chain, NULL, EXT3_I(inode)->i_data + *offsets); + if (!p->key) + goto no_block; + while (--depth) { + bh = sb_bread(sb, le32_to_cpu(p->key)); + if (!bh) + goto failure; + /* Reader: pointers */ + if (!verify_chain(chain, p)) + goto changed; + add_chain(++p, bh, (__le32*)bh->b_data + *++offsets); + /* Reader: end */ + if (!p->key) + goto no_block; + } + return NULL; + +changed: + brelse(bh); + *err = -EAGAIN; + goto no_block; +failure: + *err = -EIO; +no_block: + return p; +} + +/** + * ext3_find_near - find a place for allocation with sufficient locality + * @inode: owner + * @ind: descriptor of indirect block. + * + * This function returns the prefered place for block allocation. + * It is used when heuristic for sequential allocation fails. + * Rules are: + * + if there is a block to the left of our position - allocate near it. + * + if pointer will live in indirect block - allocate near that block. + * + if pointer will live in inode - allocate in the same + * cylinder group. + * + * In the latter case we colour the starting block by the callers PID to + * prevent it from clashing with concurrent allocations for a different inode + * in the same block group. The PID is used here so that functionally related + * files will be close-by on-disk. + * + * Caller must make sure that @ind is valid and will stay that way. + */ +static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + __le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data; + __le32 *p; + ext3_fsblk_t bg_start; + ext3_grpblk_t colour; + + /* Try to find previous block */ + for (p = ind->p - 1; p >= start; p--) { + if (*p) + return le32_to_cpu(*p); + } + + /* No such thing, so let's try location of indirect block */ + if (ind->bh) + return ind->bh->b_blocknr; + + /* + * It is going to be referred to from the inode itself? OK, just put it + * into the same cylinder group then. + */ + bg_start = ext3_group_first_block_no(inode->i_sb, ei->i_block_group); + colour = (current->pid % 16) * + (EXT3_BLOCKS_PER_GROUP(inode->i_sb) / 16); + return bg_start + colour; +} + +/** + * ext3_find_goal - find a prefered place for allocation. + * @inode: owner + * @block: block we want + * @chain: chain of indirect blocks + * @partial: pointer to the last triple within a chain + * @goal: place to store the result. + * + * Normally this function find the prefered place for block allocation, + * stores it in *@goal and returns zero. + */ + +static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block, + Indirect chain[4], Indirect *partial) +{ + struct ext3_block_alloc_info *block_i; + + block_i = EXT3_I(inode)->i_block_alloc_info; + + /* + * try the heuristic for sequential allocation, + * failing that at least try to get decent locality. + */ + if (block_i && (block == block_i->last_alloc_logical_block + 1) + && (block_i->last_alloc_physical_block != 0)) { + return block_i->last_alloc_physical_block + 1; + } + + return ext3_find_near(inode, partial); +} + +/** + * ext3_blks_to_allocate: Look up the block map and count the number + * of direct blocks need to be allocated for the given branch. + * + * @branch: chain of indirect blocks + * @k: number of blocks need for indirect blocks + * @blks: number of data blocks to be mapped. + * @blocks_to_boundary: the offset in the indirect block + * + * return the total number of blocks to be allocate, including the + * direct and indirect blocks. + */ +static int ext3_blks_to_allocate(Indirect *branch, int k, unsigned long blks, + int blocks_to_boundary) +{ + unsigned long count = 0; + + /* + * Simple case, [t,d]Indirect block(s) has not allocated yet + * then it's clear blocks on that path have not allocated + */ + if (k > 0) { + /* right now we don't handle cross boundary allocation */ + if (blks < blocks_to_boundary + 1) + count += blks; + else + count += blocks_to_boundary + 1; + return count; + } + + count++; + while (count < blks && count <= blocks_to_boundary && + le32_to_cpu(*(branch[0].p + count)) == 0) { + count++; + } + return count; +} + +/** + * ext3_alloc_blocks: multiple allocate blocks needed for a branch + * @indirect_blks: the number of blocks need to allocate for indirect + * blocks + * + * @new_blocks: on return it will store the new block numbers for + * the indirect blocks(if needed) and the first direct block, + * @blks: on return it will store the total number of allocated + * direct blocks + */ +static int ext3_alloc_blocks(handle_t *handle, struct inode *inode, + ext3_fsblk_t goal, int indirect_blks, int blks, + ext3_fsblk_t new_blocks[4], int *err) +{ + int target, i; + unsigned long count = 0; + int index = 0; + ext3_fsblk_t current_block = 0; + int ret = 0; + + /* + * Here we try to allocate the requested multiple blocks at once, + * on a best-effort basis. + * To build a branch, we should allocate blocks for + * the indirect blocks(if not allocated yet), and at least + * the first direct block of this branch. That's the + * minimum number of blocks need to allocate(required) + */ + target = blks + indirect_blks; + + while (1) { + count = target; + /* allocating blocks for indirect blocks and direct blocks */ + current_block = ext3_new_blocks(handle,inode,goal,&count,err); + if (*err) + goto failed_out; + + target -= count; + /* allocate blocks for indirect blocks */ + while (index < indirect_blks && count) { + new_blocks[index++] = current_block++; + count--; + } + + if (count > 0) + break; + } + + /* save the new block number for the first direct block */ + new_blocks[index] = current_block; + + /* total number of blocks allocated for direct blocks */ + ret = count; + *err = 0; + return ret; +failed_out: + for (i = 0; i key). Upon the exit we have the same + * picture as after the successful ext3_get_block(), except that in one + * place chain is disconnected - *branch->p is still zero (we did not + * set the last link), but branch->key contains the number that should + * be placed into *branch->p to fill that gap. + * + * If allocation fails we free all blocks we've allocated (and forget + * their buffer_heads) and return the error value the from failed + * ext3_alloc_block() (normally -ENOSPC). Otherwise we set the chain + * as described above and return 0. + */ +static int ext3_alloc_branch(handle_t *handle, struct inode *inode, + int indirect_blks, int *blks, ext3_fsblk_t goal, + int *offsets, Indirect *branch) +{ + int blocksize = inode->i_sb->s_blocksize; + int i, n = 0; + int err = 0; + struct buffer_head *bh; + int num; + ext3_fsblk_t new_blocks[4]; + ext3_fsblk_t current_block; + + num = ext3_alloc_blocks(handle, inode, goal, indirect_blks, + *blks, new_blocks, &err); + if (err) + return err; + + branch[0].key = cpu_to_le32(new_blocks[0]); + /* + * metadata blocks and data blocks are allocated. + */ + for (n = 1; n <= indirect_blks; n++) { + /* + * Get buffer_head for parent block, zero it out + * and set the pointer to new one, then send + * parent to disk. + */ + bh = sb_getblk(inode->i_sb, new_blocks[n-1]); + branch[n].bh = bh; + lock_buffer(bh); + BUFFER_TRACE(bh, "call get_create_access"); + err = ext3_journal_get_create_access(handle, bh); + if (err) { + unlock_buffer(bh); + brelse(bh); + goto failed; + } + + memset(bh->b_data, 0, blocksize); + branch[n].p = (__le32 *) bh->b_data + offsets[n]; + branch[n].key = cpu_to_le32(new_blocks[n]); + *branch[n].p = branch[n].key; + if ( n == indirect_blks) { + current_block = new_blocks[n]; + /* + * End of chain, update the last new metablock of + * the chain to point to the new allocated + * data blocks numbers + */ + for (i=1; i < num; i++) + *(branch[n].p + i) = cpu_to_le32(++current_block); + } + BUFFER_TRACE(bh, "marking uptodate"); + set_buffer_uptodate(bh); + unlock_buffer(bh); + + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh); + if (err) + goto failed; + } + *blks = num; + return err; +failed: + /* Allocation failed, free what we already allocated */ + for (i = 1; i <= n ; i++) { + BUFFER_TRACE(branch[i].bh, "call journal_forget"); + ext3_journal_forget(handle, branch[i].bh); + } + for (i = 0; i i_blocks, etc.). In case of success we end up with the full + * chain to new block and return 0. + */ +static int ext3_splice_branch(handle_t *handle, struct inode *inode, + long block, Indirect *where, int num, int blks) +{ + int i; + int err = 0; + struct ext3_block_alloc_info *block_i; + ext3_fsblk_t current_block; + + block_i = EXT3_I(inode)->i_block_alloc_info; + /* + * If we're splicing into a [td]indirect block (as opposed to the + * inode) then we need to get write access to the [td]indirect block + * before the splice. + */ + if (where->bh) { + BUFFER_TRACE(where->bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, where->bh); + if (err) + goto err_out; + } + /* That's it */ + + *where->p = where->key; + + /* + * Update the host buffer_head or inode to point to more just allocated + * direct blocks blocks + */ + if (num == 0 && blks > 1) { + current_block = le32_to_cpu(where->key) + 1; + for (i = 1; i < blks; i++) + *(where->p + i ) = cpu_to_le32(current_block++); + } + + /* + * update the most recently allocated logical & physical block + * in i_block_alloc_info, to assist find the proper goal block for next + * allocation + */ + if (block_i) { + block_i->last_alloc_logical_block = block + blks - 1; + block_i->last_alloc_physical_block = + le32_to_cpu(where[num].key) + blks - 1; + } + + /* We are done with atomic stuff, now do the rest of housekeeping */ + + inode->i_ctime = CURRENT_TIME_SEC; + ext3_mark_inode_dirty(handle, inode); + + /* had we spliced it onto indirect block? */ + if (where->bh) { + /* + * If we spliced it onto an indirect block, we haven't + * altered the inode. Note however that if it is being spliced + * onto an indirect block at the very end of the file (the + * file is growing) then we *will* alter the inode to reflect + * the new i_size. But that is not done here - it is done in + * generic_commit_write->__mark_inode_dirty->ext3_dirty_inode. + */ + jbd_debug(5, "splicing indirect only\n"); + BUFFER_TRACE(where->bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, where->bh); + if (err) + goto err_out; + } else { + /* + * OK, we spliced it into the inode itself on a direct block. + * Inode was dirtied above. + */ + jbd_debug(5, "splicing direct\n"); + } + return err; + +err_out: + for (i = 1; i <= num; i++) { + BUFFER_TRACE(where[i].bh, "call journal_forget"); + ext3_journal_forget(handle, where[i].bh); + ext3_free_blocks(handle,inode,le32_to_cpu(where[i-1].key),1); + } + ext3_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks); + + return err; +} + +/* + * Allocation strategy is simple: if we have to allocate something, we will + * have to go the whole way to leaf. So let's do it before attaching anything + * to tree, set linkage between the newborn blocks, write them if sync is + * required, recheck the path, free and repeat if check fails, otherwise + * set the last missing link (that will protect us from any truncate-generated + * removals - all blocks on the path are immune now) and possibly force the + * write on the parent block. + * That has a nice additional property: no special recovery from the failed + * allocations is needed - we simply release blocks and do not touch anything + * reachable from inode. + * + * `handle' can be NULL if create == 0. + * + * The BKL may not be held on entry here. Be sure to take it early. + * return > 0, # of blocks mapped or allocated. + * return = 0, if plain lookup failed. + * return < 0, error case. + */ +int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, + sector_t iblock, unsigned long maxblocks, + struct buffer_head *bh_result, + int create, int extend_disksize) +{ + int err = -EIO; + int offsets[4]; + Indirect chain[4]; + Indirect *partial; + ext3_fsblk_t goal; + int indirect_blks; + int blocks_to_boundary = 0; + int depth; + struct ext3_inode_info *ei = EXT3_I(inode); + int count = 0; + ext3_fsblk_t first_block = 0; + + + J_ASSERT(handle != NULL || create == 0); + depth = ext3_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + + if (depth == 0) + goto out; + + partial = ext3_get_branch(inode, depth, offsets, chain, &err); + + /* Simplest case - block found, no allocation needed */ + if (!partial) { + first_block = le32_to_cpu(chain[depth - 1].key); + clear_buffer_new(bh_result); + count++; + /*map more blocks*/ + while (count < maxblocks && count <= blocks_to_boundary) { + ext3_fsblk_t blk; + + if (!verify_chain(chain, partial)) { + /* + * Indirect block might be removed by + * truncate while we were reading it. + * Handling of that case: forget what we've + * got now. Flag the err as EAGAIN, so it + * will reread. + */ + err = -EAGAIN; + count = 0; + break; + } + blk = le32_to_cpu(*(chain[depth-1].p + count)); + + if (blk == first_block + count) + count++; + else + break; + } + if (err != -EAGAIN) + goto got_it; + } + + /* Next simple case - plain lookup or failed read of indirect block */ + if (!create || err == -EIO) + goto cleanup; + + mutex_lock(&ei->truncate_mutex); + + /* + * If the indirect block is missing while we are reading + * the chain(ext3_get_branch() returns -EAGAIN err), or + * if the chain has been changed after we grab the semaphore, + * (either because another process truncated this branch, or + * another get_block allocated this branch) re-grab the chain to see if + * the request block has been allocated or not. + * + * Since we already block the truncate/other get_block + * at this point, we will have the current copy of the chain when we + * splice the branch into the tree. + */ + if (err == -EAGAIN || !verify_chain(chain, partial)) { + while (partial > chain) { + brelse(partial->bh); + partial--; + } + partial = ext3_get_branch(inode, depth, offsets, chain, &err); + if (!partial) { + count++; + mutex_unlock(&ei->truncate_mutex); + if (err) + goto cleanup; + clear_buffer_new(bh_result); + goto got_it; + } + } + + /* + * Okay, we need to do block allocation. Lazily initialize the block + * allocation info here if necessary + */ + if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) + ext3_init_block_alloc_info(inode); + + goal = ext3_find_goal(inode, iblock, chain, partial); + + /* the number of blocks need to allocate for [d,t]indirect blocks */ + indirect_blks = (chain + depth) - partial - 1; + + /* + * Next look up the indirect map to count the totoal number of + * direct blocks to allocate for this branch. + */ + count = ext3_blks_to_allocate(partial, indirect_blks, + maxblocks, blocks_to_boundary); + /* + * Block out ext3_truncate while we alter the tree + */ + err = ext3_alloc_branch(handle, inode, indirect_blks, &count, goal, + offsets + (partial - chain), partial); + + /* + * The ext3_splice_branch call will free and forget any buffers + * on the new chain if there is a failure, but that risks using + * up transaction credits, especially for bitmaps where the + * credits cannot be returned. Can we handle this somehow? We + * may need to return -EAGAIN upwards in the worst case. --sct + */ + if (!err) + err = ext3_splice_branch(handle, inode, iblock, + partial, indirect_blks, count); + /* + * i_disksize growing is protected by truncate_mutex. Don't forget to + * protect it if you're about to implement concurrent + * ext3_get_block() -bzzz + */ + if (!err && extend_disksize && inode->i_size > ei->i_disksize) + ei->i_disksize = inode->i_size; + mutex_unlock(&ei->truncate_mutex); + if (err) + goto cleanup; + + set_buffer_new(bh_result); +got_it: + map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); + if (count > blocks_to_boundary) + set_buffer_boundary(bh_result); + err = count; + /* Clean up and exit */ + partial = chain + depth - 1; /* the whole chain */ +cleanup: + while (partial > chain) { + BUFFER_TRACE(partial->bh, "call brelse"); + brelse(partial->bh); + partial--; + } + BUFFER_TRACE(bh_result, "returned"); +out: + return err; +} + +#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32) + +static int ext3_get_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + handle_t *handle = journal_current_handle(); + int ret = 0; + unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; + + if (!create) + goto get_block; /* A read */ + + if (max_blocks == 1) + goto get_block; /* A single block get */ + + if (handle->h_transaction->t_state == T_LOCKED) { + /* + * Huge direct-io writes can hold off commits for long + * periods of time. Let this commit run. + */ + ext3_journal_stop(handle); + handle = ext3_journal_start(inode, DIO_CREDITS); + if (IS_ERR(handle)) + ret = PTR_ERR(handle); + goto get_block; + } + + if (handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) { + /* + * Getting low on buffer credits... + */ + ret = ext3_journal_extend(handle, DIO_CREDITS); + if (ret > 0) { + /* + * Couldn't extend the transaction. Start a new one. + */ + ret = ext3_journal_restart(handle, DIO_CREDITS); + } + } + +get_block: + if (ret == 0) { + ret = ext3_get_blocks_handle(handle, inode, iblock, + max_blocks, bh_result, create, 0); + if (ret > 0) { + bh_result->b_size = (ret << inode->i_blkbits); + ret = 0; + } + } + return ret; +} + +/* + * `handle' can be NULL if create is zero + */ +struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode, + long block, int create, int *errp) +{ + struct buffer_head dummy; + int fatal = 0, err; + + J_ASSERT(handle != NULL || create == 0); + + dummy.b_state = 0; + dummy.b_blocknr = -1000; + buffer_trace_init(&dummy.b_history); + err = ext3_get_blocks_handle(handle, inode, block, 1, + &dummy, create, 1); + /* + * ext3_get_blocks_handle() returns number of blocks + * mapped. 0 in case of a HOLE. + */ + if (err > 0) { + if (err > 1) + WARN_ON(1); + err = 0; + } + *errp = err; + if (!err && buffer_mapped(&dummy)) { + struct buffer_head *bh; + bh = sb_getblk(inode->i_sb, dummy.b_blocknr); + if (!bh) { + *errp = -EIO; + goto err; + } + if (buffer_new(&dummy)) { + J_ASSERT(create != 0); + J_ASSERT(handle != 0); + + /* + * Now that we do not always journal data, we should + * keep in mind whether this should always journal the + * new buffer as metadata. For now, regular file + * writes use ext3_get_block instead, so it's not a + * problem. + */ + lock_buffer(bh); + BUFFER_TRACE(bh, "call get_create_access"); + fatal = ext3_journal_get_create_access(handle, bh); + if (!fatal && !buffer_uptodate(bh)) { + memset(bh->b_data,0,inode->i_sb->s_blocksize); + set_buffer_uptodate(bh); + } + unlock_buffer(bh); + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh); + if (!fatal) + fatal = err; + } else { + BUFFER_TRACE(bh, "not a new buffer"); + } + if (fatal) { + *errp = fatal; + brelse(bh); + bh = NULL; + } + return bh; + } +err: + return NULL; +} + +struct buffer_head *ext3_bread(handle_t *handle, struct inode *inode, + int block, int create, int *err) +{ + struct buffer_head * bh; + + bh = ext3_getblk(handle, inode, block, create, err); + if (!bh) + return bh; + if (buffer_uptodate(bh)) + return bh; + ll_rw_block(READ_META, 1, &bh); + wait_on_buffer(bh); + if (buffer_uptodate(bh)) + return bh; + put_bh(bh); + *err = -EIO; + return NULL; +} + +static int walk_page_buffers( handle_t *handle, + struct buffer_head *head, + unsigned from, + unsigned to, + int *partial, + int (*fn)( handle_t *handle, + struct buffer_head *bh)) +{ + struct buffer_head *bh; + unsigned block_start, block_end; + unsigned blocksize = head->b_size; + int err, ret = 0; + struct buffer_head *next; + + for ( bh = head, block_start = 0; + ret == 0 && (bh != head || !block_start); + block_start = block_end, bh = next) + { + next = bh->b_this_page; + block_end = block_start + blocksize; + if (block_end <= from || block_start >= to) { + if (partial && !buffer_uptodate(bh)) + *partial = 1; + continue; + } + err = (*fn)(handle, bh); + if (!ret) + ret = err; + } + return ret; +} + +/* + * To preserve ordering, it is essential that the hole instantiation and + * the data write be encapsulated in a single transaction. We cannot + * close off a transaction and start a new one between the ext3_get_block() + * and the commit_write(). So doing the journal_start at the start of + * prepare_write() is the right place. + * + * Also, this function can nest inside ext3_writepage() -> + * block_write_full_page(). In that case, we *know* that ext3_writepage() + * has generated enough buffer credits to do the whole page. So we won't + * block on the journal in that case, which is good, because the caller may + * be PF_MEMALLOC. + * + * By accident, ext3 can be reentered when a transaction is open via + * quota file writes. If we were to commit the transaction while thus + * reentered, there can be a deadlock - we would be holding a quota + * lock, and the commit would never complete if another thread had a + * transaction open and was blocking on the quota lock - a ranking + * violation. + * + * So what we do is to rely on the fact that journal_stop/journal_start + * will _not_ run commit under these circumstances because handle->h_ref + * is elevated. We'll still have enough credits for the tiny quotafile + * write. + */ +static int do_journal_get_write_access(handle_t *handle, + struct buffer_head *bh) +{ + if (!buffer_mapped(bh) || buffer_freed(bh)) + return 0; + return ext3_journal_get_write_access(handle, bh); +} + +static int ext3_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct inode *inode = page->mapping->host; + int ret, needed_blocks = ext3_writepage_trans_blocks(inode); + handle_t *handle; + int retries = 0; + +retry: + handle = ext3_journal_start(inode, needed_blocks); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } + if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) + ret = nobh_prepare_write(page, from, to, ext3_get_block); + else + ret = block_prepare_write(page, from, to, ext3_get_block); + if (ret) + goto prepare_write_failed; + + if (ext3_should_journal_data(inode)) { + ret = walk_page_buffers(handle, page_buffers(page), + from, to, NULL, do_journal_get_write_access); + } +prepare_write_failed: + if (ret) + ext3_journal_stop(handle); + if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; +out: + return ret; +} + +int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) +{ + int err = journal_dirty_data(handle, bh); + if (err) + ext3_journal_abort_handle(__FUNCTION__, __FUNCTION__, + bh, handle,err); + return err; +} + +/* For commit_write() in data=journal mode */ +static int commit_write_fn(handle_t *handle, struct buffer_head *bh) +{ + if (!buffer_mapped(bh) || buffer_freed(bh)) + return 0; + set_buffer_uptodate(bh); + return ext3_journal_dirty_metadata(handle, bh); +} + +/* + * We need to pick up the new inode size which generic_commit_write gave us + * `file' can be NULL - eg, when called from page_symlink(). + * + * ext3 never places buffers on inode->i_mapping->private_list. metadata + * buffers are managed internally. + */ +static int ext3_ordered_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + handle_t *handle = ext3_journal_current_handle(); + struct inode *inode = page->mapping->host; + int ret = 0, ret2; + + ret = walk_page_buffers(handle, page_buffers(page), + from, to, NULL, ext3_journal_dirty_data); + + if (ret == 0) { + /* + * generic_commit_write() will run mark_inode_dirty() if i_size + * changes. So let's piggyback the i_disksize mark_inode_dirty + * into that. + */ + loff_t new_i_size; + + new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + if (new_i_size > EXT3_I(inode)->i_disksize) + EXT3_I(inode)->i_disksize = new_i_size; + ret = generic_commit_write(file, page, from, to); + } + ret2 = ext3_journal_stop(handle); + if (!ret) + ret = ret2; + return ret; +} + +static int ext3_writeback_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + handle_t *handle = ext3_journal_current_handle(); + struct inode *inode = page->mapping->host; + int ret = 0, ret2; + loff_t new_i_size; + + new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + if (new_i_size > EXT3_I(inode)->i_disksize) + EXT3_I(inode)->i_disksize = new_i_size; + + if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) + ret = nobh_commit_write(file, page, from, to); + else + ret = generic_commit_write(file, page, from, to); + + ret2 = ext3_journal_stop(handle); + if (!ret) + ret = ret2; + return ret; +} + +static int ext3_journalled_commit_write(struct file *file, + struct page *page, unsigned from, unsigned to) +{ + handle_t *handle = ext3_journal_current_handle(); + struct inode *inode = page->mapping->host; + int ret = 0, ret2; + int partial = 0; + loff_t pos; + + /* + * Here we duplicate the generic_commit_write() functionality + */ + pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + + ret = walk_page_buffers(handle, page_buffers(page), from, + to, &partial, commit_write_fn); + if (!partial) + SetPageUptodate(page); + if (pos > inode->i_size) + i_size_write(inode, pos); + EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; + if (inode->i_size > EXT3_I(inode)->i_disksize) { + EXT3_I(inode)->i_disksize = inode->i_size; + ret2 = ext3_mark_inode_dirty(handle, inode); + if (!ret) + ret = ret2; + } + ret2 = ext3_journal_stop(handle); + if (!ret) + ret = ret2; + return ret; +} + +/* + * bmap() is special. It gets used by applications such as lilo and by + * the swapper to find the on-disk block of a specific piece of data. + * + * Naturally, this is dangerous if the block concerned is still in the + * journal. If somebody makes a swapfile on an ext3 data-journaling + * filesystem and enables swap, then they may get a nasty shock when the + * data getting swapped to that swapfile suddenly gets overwritten by + * the original zero's written out previously to the journal and + * awaiting writeback in the kernel's buffer cache. + * + * So, if we see any bmap calls here on a modified, data-journaled file, + * take extra steps to flush any blocks which might be in the cache. + */ +static sector_t ext3_bmap(struct address_space *mapping, sector_t block) +{ + struct inode *inode = mapping->host; + journal_t *journal; + int err; + + if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) { + /* + * This is a REALLY heavyweight approach, but the use of + * bmap on dirty files is expected to be extremely rare: + * only if we run lilo or swapon on a freshly made file + * do we expect this to happen. + * + * (bmap requires CAP_SYS_RAWIO so this does not + * represent an unprivileged user DOS attack --- we'd be + * in trouble if mortal users could trigger this path at + * will.) + * + * NB. EXT3_STATE_JDATA is not set on files other than + * regular files. If somebody wants to bmap a directory + * or symlink and gets confused because the buffer + * hasn't yet been flushed to disk, they deserve + * everything they get. + */ + + EXT3_I(inode)->i_state &= ~EXT3_STATE_JDATA; + journal = EXT3_JOURNAL(inode); + journal_lock_updates(journal); + err = journal_flush(journal); + journal_unlock_updates(journal); + + if (err) + return 0; + } + + return generic_block_bmap(mapping,block,ext3_get_block); +} + +static int bget_one(handle_t *handle, struct buffer_head *bh) +{ + get_bh(bh); + return 0; +} + +static int bput_one(handle_t *handle, struct buffer_head *bh) +{ + put_bh(bh); + return 0; +} + +static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) +{ + if (buffer_mapped(bh)) + return ext3_journal_dirty_data(handle, bh); + return 0; +} + +/* + * Note that we always start a transaction even if we're not journalling + * data. This is to preserve ordering: any hole instantiation within + * __block_write_full_page -> ext3_get_block() should be journalled + * along with the data so we don't crash and then get metadata which + * refers to old data. + * + * In all journalling modes block_write_full_page() will start the I/O. + * + * Problem: + * + * ext3_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() -> + * ext3_writepage() + * + * Similar for: + * + * ext3_file_write() -> generic_file_write() -> __alloc_pages() -> ... + * + * Same applies to ext3_get_block(). We will deadlock on various things like + * lock_journal and i_truncate_mutex. + * + * Setting PF_MEMALLOC here doesn't work - too many internal memory + * allocations fail. + * + * 16May01: If we're reentered then journal_current_handle() will be + * non-zero. We simply *return*. + * + * 1 July 2001: @@@ FIXME: + * In journalled data mode, a data buffer may be metadata against the + * current transaction. But the same file is part of a shared mapping + * and someone does a writepage() on it. + * + * We will move the buffer onto the async_data list, but *after* it has + * been dirtied. So there's a small window where we have dirty data on + * BJ_Metadata. + * + * Note that this only applies to the last partial page in the file. The + * bit which block_write_full_page() uses prepare/commit for. (That's + * broken code anyway: it's wrong for msync()). + * + * It's a rare case: affects the final partial page, for journalled data + * where the file is subject to bith write() and writepage() in the same + * transction. To fix it we'll need a custom block_write_full_page(). + * We'll probably need that anyway for journalling writepage() output. + * + * We don't honour synchronous mounts for writepage(). That would be + * disastrous. Any write() or metadata operation will sync the fs for + * us. + * + * AKPM2: if all the page's buffers are mapped to disk and !data=journal, + * we don't need to open a transaction here. + */ +static int ext3_ordered_writepage(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + struct buffer_head *page_bufs; + handle_t *handle = NULL; + int ret = 0; + int err; + + J_ASSERT(PageLocked(page)); + + /* + * We give up here if we're reentered, because it might be for a + * different filesystem. + */ + if (ext3_journal_current_handle()) + goto out_fail; + + handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out_fail; + } + + if (!page_has_buffers(page)) { + create_empty_buffers(page, inode->i_sb->s_blocksize, + (1 << BH_Dirty)|(1 << BH_Uptodate)); + } + page_bufs = page_buffers(page); + walk_page_buffers(handle, page_bufs, 0, + PAGE_CACHE_SIZE, NULL, bget_one); + + ret = block_write_full_page(page, ext3_get_block, wbc); + + /* + * The page can become unlocked at any point now, and + * truncate can then come in and change things. So we + * can't touch *page from now on. But *page_bufs is + * safe due to elevated refcount. + */ + + /* + * And attach them to the current transaction. But only if + * block_write_full_page() succeeded. Otherwise they are unmapped, + * and generally junk. + */ + if (ret == 0) { + err = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, + NULL, journal_dirty_data_fn); + if (!ret) + ret = err; + } + walk_page_buffers(handle, page_bufs, 0, + PAGE_CACHE_SIZE, NULL, bput_one); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; + +out_fail: + redirty_page_for_writepage(wbc, page); + unlock_page(page); + return ret; +} + +static int ext3_writeback_writepage(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + handle_t *handle = NULL; + int ret = 0; + int err; + + if (ext3_journal_current_handle()) + goto out_fail; + + handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out_fail; + } + + if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) + ret = nobh_writepage(page, ext3_get_block, wbc); + else + ret = block_write_full_page(page, ext3_get_block, wbc); + + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; + +out_fail: + redirty_page_for_writepage(wbc, page); + unlock_page(page); + return ret; +} + +static int ext3_journalled_writepage(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + handle_t *handle = NULL; + int ret = 0; + int err; + + if (ext3_journal_current_handle()) + goto no_write; + + handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto no_write; + } + + if (!page_has_buffers(page) || PageChecked(page)) { + /* + * It's mmapped pagecache. Add buffers and journal it. There + * doesn't seem much point in redirtying the page here. + */ + ClearPageChecked(page); + ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE, + ext3_get_block); + if (ret != 0) { + ext3_journal_stop(handle); + goto out_unlock; + } + ret = walk_page_buffers(handle, page_buffers(page), 0, + PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); + + err = walk_page_buffers(handle, page_buffers(page), 0, + PAGE_CACHE_SIZE, NULL, commit_write_fn); + if (ret == 0) + ret = err; + EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; + unlock_page(page); + } else { + /* + * It may be a page full of checkpoint-mode buffers. We don't + * really know unless we go poke around in the buffer_heads. + * But block_write_full_page will do the right thing. + */ + ret = block_write_full_page(page, ext3_get_block, wbc); + } + err = ext3_journal_stop(handle); + if (!ret) + ret = err; +out: + return ret; + +no_write: + redirty_page_for_writepage(wbc, page); +out_unlock: + unlock_page(page); + goto out; +} + +static int ext3_readpage(struct file *file, struct page *page) +{ + return mpage_readpage(page, ext3_get_block); +} + +static int +ext3_readpages(struct file *file, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages) +{ + return mpage_readpages(mapping, pages, nr_pages, ext3_get_block); +} + +static void ext3_invalidatepage(struct page *page, unsigned long offset) +{ + journal_t *journal = EXT3_JOURNAL(page->mapping->host); + + /* + * If it's a full truncate we just forget about the pending dirtying + */ + if (offset == 0) + ClearPageChecked(page); + + journal_invalidatepage(journal, page, offset); +} + +static int ext3_releasepage(struct page *page, gfp_t wait) +{ + journal_t *journal = EXT3_JOURNAL(page->mapping->host); + + WARN_ON(PageChecked(page)); + if (!page_has_buffers(page)) + return 0; + return journal_try_to_free_buffers(journal, page, wait); +} + +/* + * If the O_DIRECT write will extend the file then add this inode to the + * orphan list. So recovery will truncate it back to the original size + * if the machine crashes during the write. + * + * If the O_DIRECT write is intantiating holes inside i_size and the machine + * crashes then stale disk data _may_ be exposed inside the file. + */ +static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, loff_t offset, + unsigned long nr_segs) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; + struct ext3_inode_info *ei = EXT3_I(inode); + handle_t *handle = NULL; + ssize_t ret; + int orphan = 0; + size_t count = iov_length(iov, nr_segs); + + if (rw == WRITE) { + loff_t final_size = offset + count; + + handle = ext3_journal_start(inode, DIO_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } + if (final_size > inode->i_size) { + ret = ext3_orphan_add(handle, inode); + if (ret) + goto out_stop; + orphan = 1; + ei->i_disksize = inode->i_size; + } + } + + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, + ext3_get_block, NULL); + + /* + * Reacquire the handle: ext3_get_block() can restart the transaction + */ + handle = journal_current_handle(); + +out_stop: + if (handle) { + int err; + + if (orphan && inode->i_nlink) + ext3_orphan_del(handle, inode); + if (orphan && ret > 0) { + loff_t end = offset + ret; + if (end > inode->i_size) { + ei->i_disksize = end; + i_size_write(inode, end); + /* + * We're going to return a positive `ret' + * here due to non-zero-length I/O, so there's + * no way of reporting error returns from + * ext3_mark_inode_dirty() to userspace. So + * ignore it. + */ + ext3_mark_inode_dirty(handle, inode); + } + } + err = ext3_journal_stop(handle); + if (ret == 0) + ret = err; + } +out: + return ret; +} + +/* + * Pages can be marked dirty completely asynchronously from ext3's journalling + * activity. By filemap_sync_pte(), try_to_unmap_one(), etc. We cannot do + * much here because ->set_page_dirty is called under VFS locks. The page is + * not necessarily locked. + * + * We cannot just dirty the page and leave attached buffers clean, because the + * buffers' dirty state is "definitive". We cannot just set the buffers dirty + * or jbddirty because all the journalling code will explode. + * + * So what we do is to mark the page "pending dirty" and next time writepage + * is called, propagate that into the buffers appropriately. + */ +static int ext3_journalled_set_page_dirty(struct page *page) +{ + SetPageChecked(page); + return __set_page_dirty_nobuffers(page); +} + +static const struct address_space_operations ext3_ordered_aops = { + .readpage = ext3_readpage, + .readpages = ext3_readpages, + .writepage = ext3_ordered_writepage, + .sync_page = block_sync_page, + .prepare_write = ext3_prepare_write, + .commit_write = ext3_ordered_commit_write, + .bmap = ext3_bmap, + .invalidatepage = ext3_invalidatepage, + .releasepage = ext3_releasepage, + .direct_IO = ext3_direct_IO, + .migratepage = buffer_migrate_page, +}; + +static const struct address_space_operations ext3_writeback_aops = { + .readpage = ext3_readpage, + .readpages = ext3_readpages, + .writepage = ext3_writeback_writepage, + .sync_page = block_sync_page, + .prepare_write = ext3_prepare_write, + .commit_write = ext3_writeback_commit_write, + .bmap = ext3_bmap, + .invalidatepage = ext3_invalidatepage, + .releasepage = ext3_releasepage, + .direct_IO = ext3_direct_IO, + .migratepage = buffer_migrate_page, +}; + +static const struct address_space_operations ext3_journalled_aops = { + .readpage = ext3_readpage, + .readpages = ext3_readpages, + .writepage = ext3_journalled_writepage, + .sync_page = block_sync_page, + .prepare_write = ext3_prepare_write, + .commit_write = ext3_journalled_commit_write, + .set_page_dirty = ext3_journalled_set_page_dirty, + .bmap = ext3_bmap, + .invalidatepage = ext3_invalidatepage, + .releasepage = ext3_releasepage, +}; + +void ext3_set_aops(struct inode *inode) +{ + if (ext3_should_order_data(inode)) + inode->i_mapping->a_ops = &ext3_ordered_aops; + else if (ext3_should_writeback_data(inode)) + inode->i_mapping->a_ops = &ext3_writeback_aops; + else + inode->i_mapping->a_ops = &ext3_journalled_aops; +} + +/* + * ext3_block_truncate_page() zeroes out a mapping from file offset `from' + * up to the end of the block which corresponds to `from'. + * This required during truncate. We need to physically zero the tail end + * of that block so it doesn't yield old data if the file is later grown. + */ +static int ext3_block_truncate_page(handle_t *handle, struct page *page, + struct address_space *mapping, loff_t from) +{ + ext3_fsblk_t index = from >> PAGE_CACHE_SHIFT; + unsigned offset = from & (PAGE_CACHE_SIZE-1); + unsigned blocksize, iblock, length, pos; + struct inode *inode = mapping->host; + struct buffer_head *bh; + int err = 0; + void *kaddr; + + blocksize = inode->i_sb->s_blocksize; + length = blocksize - (offset & (blocksize - 1)); + iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); + + /* + * For "nobh" option, we can only work if we don't need to + * read-in the page - otherwise we create buffers to do the IO. + */ + if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) && + ext3_should_writeback_data(inode) && PageUptodate(page)) { + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + offset, 0, length); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + set_page_dirty(page); + goto unlock; + } + + if (!page_has_buffers(page)) + create_empty_buffers(page, blocksize, 0); + + /* Find the buffer that contains "offset" */ + bh = page_buffers(page); + pos = blocksize; + while (offset >= pos) { + bh = bh->b_this_page; + iblock++; + pos += blocksize; + } + + err = 0; + if (buffer_freed(bh)) { + BUFFER_TRACE(bh, "freed: skip"); + goto unlock; + } + + if (!buffer_mapped(bh)) { + BUFFER_TRACE(bh, "unmapped"); + ext3_get_block(inode, iblock, bh, 0); + /* unmapped? It's a hole - nothing to do */ + if (!buffer_mapped(bh)) { + BUFFER_TRACE(bh, "still unmapped"); + goto unlock; + } + } + + /* Ok, it's mapped. Make sure it's up-to-date */ + if (PageUptodate(page)) + set_buffer_uptodate(bh); + + if (!buffer_uptodate(bh)) { + err = -EIO; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + /* Uhhuh. Read error. Complain and punt. */ + if (!buffer_uptodate(bh)) + goto unlock; + } + + if (ext3_should_journal_data(inode)) { + BUFFER_TRACE(bh, "get write access"); + err = ext3_journal_get_write_access(handle, bh); + if (err) + goto unlock; + } + + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + offset, 0, length); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + + BUFFER_TRACE(bh, "zeroed end of block"); + + err = 0; + if (ext3_should_journal_data(inode)) { + err = ext3_journal_dirty_metadata(handle, bh); + } else { + if (ext3_should_order_data(inode)) + err = ext3_journal_dirty_data(handle, bh); + mark_buffer_dirty(bh); + } + +unlock: + unlock_page(page); + page_cache_release(page); + return err; +} + +/* + * Probably it should be a library function... search for first non-zero word + * or memcmp with zero_page, whatever is better for particular architecture. + * Linus? + */ +static inline int all_zeroes(__le32 *p, __le32 *q) +{ + while (p < q) + if (*p++) + return 0; + return 1; +} + +/** + * ext3_find_shared - find the indirect blocks for partial truncation. + * @inode: inode in question + * @depth: depth of the affected branch + * @offsets: offsets of pointers in that branch (see ext3_block_to_path) + * @chain: place to store the pointers to partial indirect blocks + * @top: place to the (detached) top of branch + * + * This is a helper function used by ext3_truncate(). + * + * When we do truncate() we may have to clean the ends of several + * indirect blocks but leave the blocks themselves alive. Block is + * partially truncated if some data below the new i_size is refered + * from it (and it is on the path to the first completely truncated + * data block, indeed). We have to free the top of that path along + * with everything to the right of the path. Since no allocation + * past the truncation point is possible until ext3_truncate() + * finishes, we may safely do the latter, but top of branch may + * require special attention - pageout below the truncation point + * might try to populate it. + * + * We atomically detach the top of branch from the tree, store the + * block number of its root in *@top, pointers to buffer_heads of + * partially truncated blocks - in @chain[].bh and pointers to + * their last elements that should not be removed - in + * @chain[].p. Return value is the pointer to last filled element + * of @chain. + * + * The work left to caller to do the actual freeing of subtrees: + * a) free the subtree starting from *@top + * b) free the subtrees whose roots are stored in + * (@chain[i].p+1 .. end of @chain[i].bh->b_data) + * c) free the subtrees growing from the inode past the @chain[0]. + * (no partially truncated stuff there). */ + +static Indirect *ext3_find_shared(struct inode *inode, int depth, + int offsets[4], Indirect chain[4], __le32 *top) +{ + Indirect *partial, *p; + int k, err; + + *top = 0; + /* Make k index the deepest non-null offest + 1 */ + for (k = depth; k > 1 && !offsets[k-1]; k--) + ; + partial = ext3_get_branch(inode, k, offsets, chain, &err); + /* Writer: pointers */ + if (!partial) + partial = chain + k-1; + /* + * If the branch acquired continuation since we've looked at it - + * fine, it should all survive and (new) top doesn't belong to us. + */ + if (!partial->key && *partial->p) + /* Writer: end */ + goto no_top; + for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--) + ; + /* + * OK, we've found the last block that must survive. The rest of our + * branch should be detached before unlocking. However, if that rest + * of branch is all ours and does not grow immediately from the inode + * it's easier to cheat and just decrement partial->p. + */ + if (p == chain + k - 1 && p > chain) { + p->p--; + } else { + *top = *p->p; + /* Nope, don't do this in ext3. Must leave the tree intact */ +#if 0 + *p->p = 0; +#endif + } + /* Writer: end */ + + while(partial > p) { + brelse(partial->bh); + partial--; + } +no_top: + return partial; +} + +/* + * Zero a number of block pointers in either an inode or an indirect block. + * If we restart the transaction we must again get write access to the + * indirect block for further modification. + * + * We release `count' blocks on disk, but (last - first) may be greater + * than `count' because there can be holes in there. + */ +static void ext3_clear_blocks(handle_t *handle, struct inode *inode, + struct buffer_head *bh, ext3_fsblk_t block_to_free, + unsigned long count, __le32 *first, __le32 *last) +{ + __le32 *p; + if (try_to_extend_transaction(handle, inode)) { + if (bh) { + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, bh); + } + ext3_mark_inode_dirty(handle, inode); + ext3_journal_test_restart(handle, inode); + if (bh) { + BUFFER_TRACE(bh, "retaking write access"); + ext3_journal_get_write_access(handle, bh); + } + } + + /* + * Any buffers which are on the journal will be in memory. We find + * them on the hash table so journal_revoke() will run journal_forget() + * on them. We've already detached each block from the file, so + * bforget() in journal_forget() should be safe. + * + * AKPM: turn on bforget in journal_forget()!!! + */ + for (p = first; p < last; p++) { + u32 nr = le32_to_cpu(*p); + if (nr) { + struct buffer_head *bh; + + *p = 0; + bh = sb_find_get_block(inode->i_sb, nr); + ext3_forget(handle, 0, inode, bh, nr); + } + } + + ext3_free_blocks(handle, inode, block_to_free, count); +} + +/** + * ext3_free_data - free a list of data blocks + * @handle: handle for this transaction + * @inode: inode we are dealing with + * @this_bh: indirect buffer_head which contains *@first and *@last + * @first: array of block numbers + * @last: points immediately past the end of array + * + * We are freeing all blocks refered from that array (numbers are stored as + * little-endian 32-bit) and updating @inode->i_blocks appropriately. + * + * We accumulate contiguous runs of blocks to free. Conveniently, if these + * blocks are contiguous then releasing them at one time will only affect one + * or two bitmap blocks (+ group descriptor(s) and superblock) and we won't + * actually use a lot of journal space. + * + * @this_bh will be %NULL if @first and @last point into the inode's direct + * block pointers. + */ +static void ext3_free_data(handle_t *handle, struct inode *inode, + struct buffer_head *this_bh, + __le32 *first, __le32 *last) +{ + ext3_fsblk_t block_to_free = 0; /* Starting block # of a run */ + unsigned long count = 0; /* Number of blocks in the run */ + __le32 *block_to_free_p = NULL; /* Pointer into inode/ind + corresponding to + block_to_free */ + ext3_fsblk_t nr; /* Current block # */ + __le32 *p; /* Pointer into inode/ind + for current block */ + int err; + + if (this_bh) { /* For indirect block */ + BUFFER_TRACE(this_bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, this_bh); + /* Important: if we can't update the indirect pointers + * to the blocks, we can't free them. */ + if (err) + return; + } + + for (p = first; p < last; p++) { + nr = le32_to_cpu(*p); + if (nr) { + /* accumulate blocks to free if they're contiguous */ + if (count == 0) { + block_to_free = nr; + block_to_free_p = p; + count = 1; + } else if (nr == block_to_free + count) { + count++; + } else { + ext3_clear_blocks(handle, inode, this_bh, + block_to_free, + count, block_to_free_p, p); + block_to_free = nr; + block_to_free_p = p; + count = 1; + } + } + } + + if (count > 0) + ext3_clear_blocks(handle, inode, this_bh, block_to_free, + count, block_to_free_p, p); + + if (this_bh) { + BUFFER_TRACE(this_bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, this_bh); + } +} + +/** + * ext3_free_branches - free an array of branches + * @handle: JBD handle for this transaction + * @inode: inode we are dealing with + * @parent_bh: the buffer_head which contains *@first and *@last + * @first: array of block numbers + * @last: pointer immediately past the end of array + * @depth: depth of the branches to free + * + * We are freeing all blocks refered from these branches (numbers are + * stored as little-endian 32-bit) and updating @inode->i_blocks + * appropriately. + */ +static void ext3_free_branches(handle_t *handle, struct inode *inode, + struct buffer_head *parent_bh, + __le32 *first, __le32 *last, int depth) +{ + ext3_fsblk_t nr; + __le32 *p; + + if (is_handle_aborted(handle)) + return; + + if (depth--) { + struct buffer_head *bh; + int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb); + p = last; + while (--p >= first) { + nr = le32_to_cpu(*p); + if (!nr) + continue; /* A hole */ + + /* Go read the buffer for the next level down */ + bh = sb_bread(inode->i_sb, nr); + + /* + * A read failure? Report error and clear slot + * (should be rare). + */ + if (!bh) { + ext3_error(inode->i_sb, "ext3_free_branches", + "Read failure, inode=%lu, block="E3FSBLK, + inode->i_ino, nr); + continue; + } + + /* This zaps the entire block. Bottom up. */ + BUFFER_TRACE(bh, "free child branches"); + ext3_free_branches(handle, inode, bh, + (__le32*)bh->b_data, + (__le32*)bh->b_data + addr_per_block, + depth); + + /* + * We've probably journalled the indirect block several + * times during the truncate. But it's no longer + * needed and we now drop it from the transaction via + * journal_revoke(). + * + * That's easy if it's exclusively part of this + * transaction. But if it's part of the committing + * transaction then journal_forget() will simply + * brelse() it. That means that if the underlying + * block is reallocated in ext3_get_block(), + * unmap_underlying_metadata() will find this block + * and will try to get rid of it. damn, damn. + * + * If this block has already been committed to the + * journal, a revoke record will be written. And + * revoke records must be emitted *before* clearing + * this block's bit in the bitmaps. + */ + ext3_forget(handle, 1, inode, bh, bh->b_blocknr); + + /* + * Everything below this this pointer has been + * released. Now let this top-of-subtree go. + * + * We want the freeing of this indirect block to be + * atomic in the journal with the updating of the + * bitmap block which owns it. So make some room in + * the journal. + * + * We zero the parent pointer *after* freeing its + * pointee in the bitmaps, so if extend_transaction() + * for some reason fails to put the bitmap changes and + * the release into the same transaction, recovery + * will merely complain about releasing a free block, + * rather than leaking blocks. + */ + if (is_handle_aborted(handle)) + return; + if (try_to_extend_transaction(handle, inode)) { + ext3_mark_inode_dirty(handle, inode); + ext3_journal_test_restart(handle, inode); + } + + ext3_free_blocks(handle, inode, nr, 1); + + if (parent_bh) { + /* + * The block which we have just freed is + * pointed to by an indirect block: journal it + */ + BUFFER_TRACE(parent_bh, "get_write_access"); + if (!ext3_journal_get_write_access(handle, + parent_bh)){ + *p = 0; + BUFFER_TRACE(parent_bh, + "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, + parent_bh); + } + } + } + } else { + /* We have reached the bottom of the tree. */ + BUFFER_TRACE(parent_bh, "free data blocks"); + ext3_free_data(handle, inode, parent_bh, first, last); + } +} + +/* + * ext3_truncate() + * + * We block out ext3_get_block() block instantiations across the entire + * transaction, and VFS/VM ensures that ext3_truncate() cannot run + * simultaneously on behalf of the same inode. + * + * As we work through the truncate and commmit bits of it to the journal there + * is one core, guiding principle: the file's tree must always be consistent on + * disk. We must be able to restart the truncate after a crash. + * + * The file's tree may be transiently inconsistent in memory (although it + * probably isn't), but whenever we close off and commit a journal transaction, + * the contents of (the filesystem + the journal) must be consistent and + * restartable. It's pretty simple, really: bottom up, right to left (although + * left-to-right works OK too). + * + * Note that at recovery time, journal replay occurs *before* the restart of + * truncate against the orphan inode list. + * + * The committed inode has the new, desired i_size (which is the same as + * i_disksize in this case). After a crash, ext3_orphan_cleanup() will see + * that this inode's truncate did not complete and it will again call + * ext3_truncate() to have another go. So there will be instantiated blocks + * to the right of the truncation point in a crashed ext3 filesystem. But + * that's fine - as long as they are linked from the inode, the post-crash + * ext3_truncate() run will find them and release them. + */ +void ext3_truncate(struct inode *inode) +{ + handle_t *handle; + struct ext3_inode_info *ei = EXT3_I(inode); + __le32 *i_data = ei->i_data; + int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb); + struct address_space *mapping = inode->i_mapping; + int offsets[4]; + Indirect chain[4]; + Indirect *partial; + __le32 nr = 0; + int n; + long last_block; + unsigned blocksize = inode->i_sb->s_blocksize; + struct page *page; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + if (ext3_inode_is_fast_symlink(inode)) + return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + + /* + * We have to lock the EOF page here, because lock_page() nests + * outside journal_start(). + */ + if ((inode->i_size & (blocksize - 1)) == 0) { + /* Block boundary? Nothing to do */ + page = NULL; + } else { + page = grab_cache_page(mapping, + inode->i_size >> PAGE_CACHE_SHIFT); + if (!page) + return; + } + + handle = start_transaction(inode); + if (IS_ERR(handle)) { + if (page) { + clear_highpage(page); + flush_dcache_page(page); + unlock_page(page); + page_cache_release(page); + } + return; /* AKPM: return what? */ + } + + last_block = (inode->i_size + blocksize-1) + >> EXT3_BLOCK_SIZE_BITS(inode->i_sb); + + if (page) + ext3_block_truncate_page(handle, page, mapping, inode->i_size); + + n = ext3_block_to_path(inode, last_block, offsets, NULL); + if (n == 0) + goto out_stop; /* error */ + + /* + * OK. This truncate is going to happen. We add the inode to the + * orphan list, so that if this truncate spans multiple transactions, + * and we crash, we will resume the truncate when the filesystem + * recovers. It also marks the inode dirty, to catch the new size. + * + * Implication: the file must always be in a sane, consistent + * truncatable state while each transaction commits. + */ + if (ext3_orphan_add(handle, inode)) + goto out_stop; + + /* + * The orphan list entry will now protect us from any crash which + * occurs before the truncate completes, so it is now safe to propagate + * the new, shorter inode size (held for now in i_size) into the + * on-disk inode. We do this via i_disksize, which is the value which + * ext3 *really* writes onto the disk inode. + */ + ei->i_disksize = inode->i_size; + + /* + * From here we block out all ext3_get_block() callers who want to + * modify the block allocation tree. + */ + mutex_lock(&ei->truncate_mutex); + + if (n == 1) { /* direct blocks */ + ext3_free_data(handle, inode, NULL, i_data+offsets[0], + i_data + EXT3_NDIR_BLOCKS); + goto do_indirects; + } + + partial = ext3_find_shared(inode, n, offsets, chain, &nr); + /* Kill the top of shared branch (not detached) */ + if (nr) { + if (partial == chain) { + /* Shared branch grows from the inode */ + ext3_free_branches(handle, inode, NULL, + &nr, &nr+1, (chain+n-1) - partial); + *partial->p = 0; + /* + * We mark the inode dirty prior to restart, + * and prior to stop. No need for it here. + */ + } else { + /* Shared branch grows from an indirect block */ + BUFFER_TRACE(partial->bh, "get_write_access"); + ext3_free_branches(handle, inode, partial->bh, + partial->p, + partial->p+1, (chain+n-1) - partial); + } + } + /* Clear the ends of indirect blocks on the shared branch */ + while (partial > chain) { + ext3_free_branches(handle, inode, partial->bh, partial->p + 1, + (__le32*)partial->bh->b_data+addr_per_block, + (chain+n-1) - partial); + BUFFER_TRACE(partial->bh, "call brelse"); + brelse (partial->bh); + partial--; + } +do_indirects: + /* Kill the remaining (whole) subtrees */ + switch (offsets[0]) { + default: + nr = i_data[EXT3_IND_BLOCK]; + if (nr) { + ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 1); + i_data[EXT3_IND_BLOCK] = 0; + } + case EXT3_IND_BLOCK: + nr = i_data[EXT3_DIND_BLOCK]; + if (nr) { + ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 2); + i_data[EXT3_DIND_BLOCK] = 0; + } + case EXT3_DIND_BLOCK: + nr = i_data[EXT3_TIND_BLOCK]; + if (nr) { + ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 3); + i_data[EXT3_TIND_BLOCK] = 0; + } + case EXT3_TIND_BLOCK: + ; + } + + ext3_discard_reservation(inode); + + mutex_unlock(&ei->truncate_mutex); + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; + ext3_mark_inode_dirty(handle, inode); + + /* + * In a multi-transaction truncate, we only make the final transaction + * synchronous + */ + if (IS_SYNC(inode)) + handle->h_sync = 1; +out_stop: + /* + * If this was a simple ftruncate(), and the file will remain alive + * then we need to clear up the orphan record which we created above. + * However, if this was a real unlink then we were called by + * ext3_delete_inode(), and we allow that function to clean up the + * orphan info for us. + */ + if (inode->i_nlink) + ext3_orphan_del(handle, inode); + + ext3_journal_stop(handle); +} + +static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb, + unsigned long ino, struct ext3_iloc *iloc) +{ + unsigned long desc, group_desc, block_group; + unsigned long offset; + ext3_fsblk_t block; + struct buffer_head *bh; + struct ext3_group_desc * gdp; + + if (!ext3_valid_inum(sb, ino)) { + /* + * This error is already checked for in namei.c unless we are + * looking at an NFS filehandle, in which case no error + * report is needed + */ + return 0; + } + + block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); + if (block_group >= EXT3_SB(sb)->s_groups_count) { + ext3_error(sb,"ext3_get_inode_block","group >= groups count"); + return 0; + } + smp_rmb(); + group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(sb); + desc = block_group & (EXT3_DESC_PER_BLOCK(sb) - 1); + bh = EXT3_SB(sb)->s_group_desc[group_desc]; + if (!bh) { + ext3_error (sb, "ext3_get_inode_block", + "Descriptor not loaded"); + return 0; + } + + gdp = (struct ext3_group_desc *)bh->b_data; + /* + * Figure out the offset within the block group inode table + */ + offset = ((ino - 1) % EXT3_INODES_PER_GROUP(sb)) * + EXT3_INODE_SIZE(sb); + block = le32_to_cpu(gdp[desc].bg_inode_table) + + (offset >> EXT3_BLOCK_SIZE_BITS(sb)); + + iloc->block_group = block_group; + iloc->offset = offset & (EXT3_BLOCK_SIZE(sb) - 1); + return block; +} + +/* + * ext3_get_inode_loc returns with an extra refcount against the inode's + * underlying buffer_head on success. If 'in_mem' is true, we have all + * data in memory that is needed to recreate the on-disk version of this + * inode. + */ +static int __ext3_get_inode_loc(struct inode *inode, + struct ext3_iloc *iloc, int in_mem) +{ + ext3_fsblk_t block; + struct buffer_head *bh; + + block = ext3_get_inode_block(inode->i_sb, inode->i_ino, iloc); + if (!block) + return -EIO; + + bh = sb_getblk(inode->i_sb, block); + if (!bh) { + ext3_error (inode->i_sb, "ext3_get_inode_loc", + "unable to read inode block - " + "inode=%lu, block="E3FSBLK, + inode->i_ino, block); + return -EIO; + } + if (!buffer_uptodate(bh)) { + lock_buffer(bh); + if (buffer_uptodate(bh)) { + /* someone brought it uptodate while we waited */ + unlock_buffer(bh); + goto has_buffer; + } + + /* + * If we have all information of the inode in memory and this + * is the only valid inode in the block, we need not read the + * block. + */ + if (in_mem) { + struct buffer_head *bitmap_bh; + struct ext3_group_desc *desc; + int inodes_per_buffer; + int inode_offset, i; + int block_group; + int start; + + block_group = (inode->i_ino - 1) / + EXT3_INODES_PER_GROUP(inode->i_sb); + inodes_per_buffer = bh->b_size / + EXT3_INODE_SIZE(inode->i_sb); + inode_offset = ((inode->i_ino - 1) % + EXT3_INODES_PER_GROUP(inode->i_sb)); + start = inode_offset & ~(inodes_per_buffer - 1); + + /* Is the inode bitmap in cache? */ + desc = ext3_get_group_desc(inode->i_sb, + block_group, NULL); + if (!desc) + goto make_io; + + bitmap_bh = sb_getblk(inode->i_sb, + le32_to_cpu(desc->bg_inode_bitmap)); + if (!bitmap_bh) + goto make_io; + + /* + * If the inode bitmap isn't in cache then the + * optimisation may end up performing two reads instead + * of one, so skip it. + */ + if (!buffer_uptodate(bitmap_bh)) { + brelse(bitmap_bh); + goto make_io; + } + for (i = start; i < start + inodes_per_buffer; i++) { + if (i == inode_offset) + continue; + if (ext3_test_bit(i, bitmap_bh->b_data)) + break; + } + brelse(bitmap_bh); + if (i == start + inodes_per_buffer) { + /* all other inodes are free, so skip I/O */ + memset(bh->b_data, 0, bh->b_size); + set_buffer_uptodate(bh); + unlock_buffer(bh); + goto has_buffer; + } + } + +make_io: + /* + * There are other valid inodes in the buffer, this inode + * has in-inode xattrs, or we don't have this inode in memory. + * Read the block from disk. + */ + get_bh(bh); + bh->b_end_io = end_buffer_read_sync; + submit_bh(READ_META, bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { + ext3_error(inode->i_sb, "ext3_get_inode_loc", + "unable to read inode block - " + "inode=%lu, block="E3FSBLK, + inode->i_ino, block); + brelse(bh); + return -EIO; + } + } +has_buffer: + iloc->bh = bh; + return 0; +} + +int ext3_get_inode_loc(struct inode *inode, struct ext3_iloc *iloc) +{ + /* We have all inode data except xattrs in memory here. */ + return __ext3_get_inode_loc(inode, iloc, + !(EXT3_I(inode)->i_state & EXT3_STATE_XATTR)); +} + +void ext3_set_inode_flags(struct inode *inode) +{ + unsigned int flags = EXT3_I(inode)->i_flags; + + inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); + if (flags & EXT3_SYNC_FL) + inode->i_flags |= S_SYNC; + if (flags & EXT3_APPEND_FL) + inode->i_flags |= S_APPEND; + if (flags & EXT3_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & EXT3_NOATIME_FL) + inode->i_flags |= S_NOATIME; + if (flags & EXT3_DIRSYNC_FL) + inode->i_flags |= S_DIRSYNC; +} + +void ext3_read_inode(struct inode * inode) +{ + struct ext3_iloc iloc; + struct ext3_inode *raw_inode; + struct ext3_inode_info *ei = EXT3_I(inode); + struct buffer_head *bh; + int block; + +#ifdef CONFIG_EXT3_FS_POSIX_ACL + ei->i_acl = EXT3_ACL_NOT_CACHED; + ei->i_default_acl = EXT3_ACL_NOT_CACHED; +#endif + ei->i_block_alloc_info = NULL; + + if (__ext3_get_inode_loc(inode, &iloc, 0)) + goto bad_inode; + bh = iloc.bh; + raw_inode = ext3_raw_inode(&iloc); + inode->i_mode = le16_to_cpu(raw_inode->i_mode); + inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); + inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); + if(!(test_opt (inode->i_sb, NO_UID32))) { + inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; + inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; + } + inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); + inode->i_size = le32_to_cpu(raw_inode->i_size); + inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime); + inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->i_ctime); + inode->i_mtime.tv_sec = le32_to_cpu(raw_inode->i_mtime); + inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0; + + ei->i_state = 0; + ei->i_dir_start_lookup = 0; + ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); + /* We now have enough fields to check if the inode was active or not. + * This is needed because nfsd might try to access dead inodes + * the test is that same one that e2fsck uses + * NeilBrown 1999oct15 + */ + if (inode->i_nlink == 0) { + if (inode->i_mode == 0 || + !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ORPHAN_FS)) { + /* this inode is deleted */ + brelse (bh); + goto bad_inode; + } + /* The only unlinked inodes we let through here have + * valid i_mode and are being read by the orphan + * recovery code: that's fine, we're about to complete + * the process of deleting those. */ + } + inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); + ei->i_flags = le32_to_cpu(raw_inode->i_flags); +#ifdef EXT3_FRAGMENTS + ei->i_faddr = le32_to_cpu(raw_inode->i_faddr); + ei->i_frag_no = raw_inode->i_frag; + ei->i_frag_size = raw_inode->i_fsize; +#endif + ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl); + if (!S_ISREG(inode->i_mode)) { + ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); + } else { + inode->i_size |= + ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; + } + ei->i_disksize = inode->i_size; + inode->i_generation = le32_to_cpu(raw_inode->i_generation); + ei->i_block_group = iloc.block_group; + /* + * NOTE! The in-memory inode i_data array is in little-endian order + * even on big-endian machines: we do NOT byteswap the block numbers! + */ + for (block = 0; block < EXT3_N_BLOCKS; block++) + ei->i_data[block] = raw_inode->i_block[block]; + INIT_LIST_HEAD(&ei->i_orphan); + + if (inode->i_ino >= EXT3_FIRST_INO(inode->i_sb) + 1 && + EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) { + /* + * When mke2fs creates big inodes it does not zero out + * the unused bytes above EXT3_GOOD_OLD_INODE_SIZE, + * so ignore those first few inodes. + */ + ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); + if (EXT3_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > + EXT3_INODE_SIZE(inode->i_sb)) + goto bad_inode; + if (ei->i_extra_isize == 0) { + /* The extra space is currently unused. Use it. */ + ei->i_extra_isize = sizeof(struct ext3_inode) - + EXT3_GOOD_OLD_INODE_SIZE; + } else { + __le32 *magic = (void *)raw_inode + + EXT3_GOOD_OLD_INODE_SIZE + + ei->i_extra_isize; + if (*magic == cpu_to_le32(EXT3_XATTR_MAGIC)) + ei->i_state |= EXT3_STATE_XATTR; + } + } else + ei->i_extra_isize = 0; + + if (S_ISREG(inode->i_mode)) { + inode->i_op = &ext3_file_inode_operations; + inode->i_fop = &ext3_file_operations; + ext3_set_aops(inode); + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &ext3_dir_inode_operations; + inode->i_fop = &ext3_dir_operations; + } else if (S_ISLNK(inode->i_mode)) { + if (ext3_inode_is_fast_symlink(inode)) + inode->i_op = &ext3_fast_symlink_inode_operations; + else { + inode->i_op = &ext3_symlink_inode_operations; + ext3_set_aops(inode); + } + } else { + inode->i_op = &ext3_special_inode_operations; + if (raw_inode->i_block[0]) + init_special_inode(inode, inode->i_mode, + old_decode_dev(le32_to_cpu(raw_inode->i_block[0]))); + else + init_special_inode(inode, inode->i_mode, + new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); + } + brelse (iloc.bh); + ext3_set_inode_flags(inode); + return; + +bad_inode: + make_bad_inode(inode); + return; +} + +/* + * Post the struct inode info into an on-disk inode location in the + * buffer-cache. This gobbles the caller's reference to the + * buffer_head in the inode location struct. + * + * The caller must have write access to iloc->bh. + */ +static int ext3_do_update_inode(handle_t *handle, + struct inode *inode, + struct ext3_iloc *iloc) +{ + struct ext3_inode *raw_inode = ext3_raw_inode(iloc); + struct ext3_inode_info *ei = EXT3_I(inode); + struct buffer_head *bh = iloc->bh; + int err = 0, rc, block; + + /* For fields not not tracking in the in-memory inode, + * initialise them to zero for new inodes. */ + if (ei->i_state & EXT3_STATE_NEW) + memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size); + + raw_inode->i_mode = cpu_to_le16(inode->i_mode); + if(!(test_opt(inode->i_sb, NO_UID32))) { + raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); + raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); +/* + * Fix up interoperability with old kernels. Otherwise, old inodes get + * re-used with the upper 16 bits of the uid/gid intact + */ + if(!ei->i_dtime) { + raw_inode->i_uid_high = + cpu_to_le16(high_16_bits(inode->i_uid)); + raw_inode->i_gid_high = + cpu_to_le16(high_16_bits(inode->i_gid)); + } else { + raw_inode->i_uid_high = 0; + raw_inode->i_gid_high = 0; + } + } else { + raw_inode->i_uid_low = + cpu_to_le16(fs_high2lowuid(inode->i_uid)); + raw_inode->i_gid_low = + cpu_to_le16(fs_high2lowgid(inode->i_gid)); + raw_inode->i_uid_high = 0; + raw_inode->i_gid_high = 0; + } + raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); + raw_inode->i_size = cpu_to_le32(ei->i_disksize); + raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); + raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); + raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); + raw_inode->i_blocks = cpu_to_le32(inode->i_blocks); + raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); + raw_inode->i_flags = cpu_to_le32(ei->i_flags); +#ifdef EXT3_FRAGMENTS + raw_inode->i_faddr = cpu_to_le32(ei->i_faddr); + raw_inode->i_frag = ei->i_frag_no; + raw_inode->i_fsize = ei->i_frag_size; +#endif + raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl); + if (!S_ISREG(inode->i_mode)) { + raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl); + } else { + raw_inode->i_size_high = + cpu_to_le32(ei->i_disksize >> 32); + if (ei->i_disksize > 0x7fffffffULL) { + struct super_block *sb = inode->i_sb; + if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, + EXT3_FEATURE_RO_COMPAT_LARGE_FILE) || + EXT3_SB(sb)->s_es->s_rev_level == + cpu_to_le32(EXT3_GOOD_OLD_REV)) { + /* If this is the first large file + * created, add a flag to the superblock. + */ + err = ext3_journal_get_write_access(handle, + EXT3_SB(sb)->s_sbh); + if (err) + goto out_brelse; + ext3_update_dynamic_rev(sb); + EXT3_SET_RO_COMPAT_FEATURE(sb, + EXT3_FEATURE_RO_COMPAT_LARGE_FILE); + sb->s_dirt = 1; + handle->h_sync = 1; + err = ext3_journal_dirty_metadata(handle, + EXT3_SB(sb)->s_sbh); + } + } + } + raw_inode->i_generation = cpu_to_le32(inode->i_generation); + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { + if (old_valid_dev(inode->i_rdev)) { + raw_inode->i_block[0] = + cpu_to_le32(old_encode_dev(inode->i_rdev)); + raw_inode->i_block[1] = 0; + } else { + raw_inode->i_block[0] = 0; + raw_inode->i_block[1] = + cpu_to_le32(new_encode_dev(inode->i_rdev)); + raw_inode->i_block[2] = 0; + } + } else for (block = 0; block < EXT3_N_BLOCKS; block++) + raw_inode->i_block[block] = ei->i_data[block]; + + if (ei->i_extra_isize) + raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); + + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + rc = ext3_journal_dirty_metadata(handle, bh); + if (!err) + err = rc; + ei->i_state &= ~EXT3_STATE_NEW; + +out_brelse: + brelse (bh); + ext3_std_error(inode->i_sb, err); + return err; +} + +/* + * ext3_write_inode() + * + * We are called from a few places: + * + * - Within generic_file_write() for O_SYNC files. + * Here, there will be no transaction running. We wait for any running + * trasnaction to commit. + * + * - Within sys_sync(), kupdate and such. + * We wait on commit, if tol to. + * + * - Within prune_icache() (PF_MEMALLOC == true) + * Here we simply return. We can't afford to block kswapd on the + * journal commit. + * + * In all cases it is actually safe for us to return without doing anything, + * because the inode has been copied into a raw inode buffer in + * ext3_mark_inode_dirty(). This is a correctness thing for O_SYNC and for + * knfsd. + * + * Note that we are absolutely dependent upon all inode dirtiers doing the + * right thing: they *must* call mark_inode_dirty() after dirtying info in + * which we are interested. + * + * It would be a bug for them to not do this. The code: + * + * mark_inode_dirty(inode) + * stuff(); + * inode->i_size = expr; + * + * is in error because a kswapd-driven write_inode() could occur while + * `stuff()' is running, and the new i_size will be lost. Plus the inode + * will no longer be on the superblock's dirty inode list. + */ +int ext3_write_inode(struct inode *inode, int wait) +{ + if (current->flags & PF_MEMALLOC) + return 0; + + if (ext3_journal_current_handle()) { + jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n"); + dump_stack(); + return -EIO; + } + + if (!wait) + return 0; + + return ext3_force_commit(inode->i_sb); +} + +/* + * ext3_setattr() + * + * Called from notify_change. + * + * We want to trap VFS attempts to truncate the file as soon as + * possible. In particular, we want to make sure that when the VFS + * shrinks i_size, we put the inode on the orphan list and modify + * i_disksize immediately, so that during the subsequent flushing of + * dirty pages and freeing of disk blocks, we can guarantee that any + * commit will leave the blocks being flushed in an unused state on + * disk. (On recovery, the inode will get truncated and the blocks will + * be freed, so we have a strong guarantee that no future commit will + * leave these blocks visible to the user.) + * + * Called with inode->sem down. + */ +int ext3_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + int error, rc = 0; + const unsigned int ia_valid = attr->ia_valid; + + error = inode_change_ok(inode, attr); + if (error) + return error; + + if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || + (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { + handle_t *handle; + + /* (user+group)*(old+new) structure, inode write (sb, + * inode block, ? - but truncate inode update has it) */ + handle = ext3_journal_start(inode, 2*(EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)+ + EXT3_QUOTA_DEL_BLOCKS(inode->i_sb))+3); + if (IS_ERR(handle)) { + error = PTR_ERR(handle); + goto err_out; + } + error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; + if (error) { + ext3_journal_stop(handle); + return error; + } + /* Update corresponding info in inode so that everything is in + * one transaction */ + if (attr->ia_valid & ATTR_UID) + inode->i_uid = attr->ia_uid; + if (attr->ia_valid & ATTR_GID) + inode->i_gid = attr->ia_gid; + error = ext3_mark_inode_dirty(handle, inode); + ext3_journal_stop(handle); + } + + if (S_ISREG(inode->i_mode) && + attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { + handle_t *handle; + + handle = ext3_journal_start(inode, 3); + if (IS_ERR(handle)) { + error = PTR_ERR(handle); + goto err_out; + } + + error = ext3_orphan_add(handle, inode); + EXT3_I(inode)->i_disksize = attr->ia_size; + rc = ext3_mark_inode_dirty(handle, inode); + if (!error) + error = rc; + ext3_journal_stop(handle); + } + + rc = inode_setattr(inode, attr); + + /* If inode_setattr's call to ext3_truncate failed to get a + * transaction handle at all, we need to clean up the in-core + * orphan list manually. */ + if (inode->i_nlink) + ext3_orphan_del(NULL, inode); + + if (!rc && (ia_valid & ATTR_MODE)) + rc = ext3_acl_chmod(inode); + +err_out: + ext3_std_error(inode->i_sb, error); + if (!error) + error = rc; + return error; +} + + +/* + * How many blocks doth make a writepage()? + * + * With N blocks per page, it may be: + * N data blocks + * 2 indirect block + * 2 dindirect + * 1 tindirect + * N+5 bitmap blocks (from the above) + * N+5 group descriptor summary blocks + * 1 inode block + * 1 superblock. + * 2 * EXT3_SINGLEDATA_TRANS_BLOCKS for the quote files + * + * 3 * (N + 5) + 2 + 2 * EXT3_SINGLEDATA_TRANS_BLOCKS + * + * With ordered or writeback data it's the same, less the N data blocks. + * + * If the inode's direct blocks can hold an integral number of pages then a + * page cannot straddle two indirect blocks, and we can only touch one indirect + * and dindirect block, and the "5" above becomes "3". + * + * This still overestimates under most circumstances. If we were to pass the + * start and end offsets in here as well we could do block_to_path() on each + * block and work out the exact number of indirects which are touched. Pah. + */ + +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; + int ret; + + if (ext3_should_journal_data(inode)) + ret = 3 * (bpp + indirects) + 2; + else + ret = 2 * (bpp + indirects) + 2; + +#ifdef CONFIG_QUOTA + /* We know that structure was already allocated during DQUOT_INIT so + * we will be updating only the data blocks + inodes */ + ret += 2*EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb); +#endif + + return ret; +} + +/* + * The caller must have previously called ext3_reserve_inode_write(). + * Give this, we know that the caller already has write access to iloc->bh. + */ +int ext3_mark_iloc_dirty(handle_t *handle, + struct inode *inode, struct ext3_iloc *iloc) +{ + int err = 0; + + /* the do_update_inode consumes one bh->b_count */ + get_bh(iloc->bh); + + /* ext3_do_update_inode() does journal_dirty_metadata */ + err = ext3_do_update_inode(handle, inode, iloc); + put_bh(iloc->bh); + return err; +} + +/* + * On success, We end up with an outstanding reference count against + * iloc->bh. This _must_ be cleaned up later. + */ + +int +ext3_reserve_inode_write(handle_t *handle, struct inode *inode, + struct ext3_iloc *iloc) +{ + int err = 0; + if (handle) { + err = ext3_get_inode_loc(inode, iloc); + if (!err) { + BUFFER_TRACE(iloc->bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, iloc->bh); + if (err) { + brelse(iloc->bh); + iloc->bh = NULL; + } + } + } + ext3_std_error(inode->i_sb, err); + return err; +} + +/* + * What we do here is to mark the in-core inode as clean with respect to inode + * dirtiness (it may still be data-dirty). + * This means that the in-core inode may be reaped by prune_icache + * without having to perform any I/O. This is a very good thing, + * because *any* task may call prune_icache - even ones which + * have a transaction open against a different journal. + * + * Is this cheating? Not really. Sure, we haven't written the + * inode out, but prune_icache isn't a user-visible syncing function. + * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync) + * we start and wait on commits. + * + * Is this efficient/effective? Well, we're being nice to the system + * by cleaning up our inodes proactively so they can be reaped + * without I/O. But we are potentially leaving up to five seconds' + * worth of inodes floating about which prune_icache wants us to + * write out. One way to fix that would be to get prune_icache() + * to do a write_super() to free up some memory. It has the desired + * effect. + */ +int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode) +{ + struct ext3_iloc iloc; + int err; + + might_sleep(); + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (!err) + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + return err; +} + +/* + * ext3_dirty_inode() is called from __mark_inode_dirty() + * + * We're really interested in the case where a file is being extended. + * i_size has been changed by generic_commit_write() and we thus need + * to include the updated inode in the current transaction. + * + * Also, DQUOT_ALLOC_SPACE() will always dirty the inode when blocks + * are allocated to the file. + * + * If the inode is marked synchronous, we don't honour that here - doing + * so would cause a commit on atime updates, which we don't bother doing. + * We handle synchronous inodes at the highest possible level. + */ +void ext3_dirty_inode(struct inode *inode) +{ + handle_t *current_handle = ext3_journal_current_handle(); + handle_t *handle; + + handle = ext3_journal_start(inode, 2); + if (IS_ERR(handle)) + goto out; + if (current_handle && + current_handle->h_transaction != handle->h_transaction) { + /* This task has a transaction open against a different fs */ + printk(KERN_EMERG "%s: transactions do not match!\n", + __FUNCTION__); + } else { + jbd_debug(5, "marking dirty. outer handle=%p\n", + current_handle); + ext3_mark_inode_dirty(handle, inode); + } + ext3_journal_stop(handle); +out: + return; +} + +#if 0 +/* + * Bind an inode's backing buffer_head into this transaction, to prevent + * it from being flushed to disk early. Unlike + * ext3_reserve_inode_write, this leaves behind no bh reference and + * returns no iloc structure, so the caller needs to repeat the iloc + * lookup to mark the inode dirty later. + */ +static int ext3_pin_inode(handle_t *handle, struct inode *inode) +{ + struct ext3_iloc iloc; + + int err = 0; + if (handle) { + err = ext3_get_inode_loc(inode, &iloc); + if (!err) { + BUFFER_TRACE(iloc.bh, "get_write_access"); + err = journal_get_write_access(handle, iloc.bh); + if (!err) + err = ext3_journal_dirty_metadata(handle, + iloc.bh); + brelse(iloc.bh); + } + } + ext3_std_error(inode->i_sb, err); + return err; +} +#endif + +int ext3_change_inode_journal_flag(struct inode *inode, int val) +{ + journal_t *journal; + handle_t *handle; + int err; + + /* + * We have to be very careful here: changing a data block's + * journaling status dynamically is dangerous. If we write a + * data block to the journal, change the status and then delete + * that block, we risk forgetting to revoke the old log record + * from the journal and so a subsequent replay can corrupt data. + * So, first we make sure that the journal is empty and that + * nobody is changing anything. + */ + + journal = EXT3_JOURNAL(inode); + if (is_journal_aborted(journal) || IS_RDONLY(inode)) + return -EROFS; + + journal_lock_updates(journal); + journal_flush(journal); + + /* + * OK, there are no updates running now, and all cached data is + * synced to disk. We are now in a completely consistent state + * which doesn't have anything in the journal, and we know that + * no filesystem updates are running, so it is safe to modify + * the inode's in-core data-journaling state flag now. + */ + + if (val) + EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL; + else + EXT3_I(inode)->i_flags &= ~EXT3_JOURNAL_DATA_FL; + ext3_set_aops(inode); + + journal_unlock_updates(journal); + + /* Finally we can mark the inode as dirty. */ + + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + err = ext3_mark_inode_dirty(handle, inode); + handle->h_sync = 1; + ext3_journal_stop(handle); + ext3_std_error(inode->i_sb, err); + + return err; +} diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c new file mode 100644 index 000000000000..12daa6869572 --- /dev/null +++ b/fs/ext4/ioctl.c @@ -0,0 +1,307 @@ +/* + * linux/fs/ext3/ioctl.c + * + * Copyright (C) 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + unsigned long arg) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + unsigned int flags; + unsigned short rsv_window_size; + + ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); + + switch (cmd) { + case EXT3_IOC_GETFLAGS: + flags = ei->i_flags & EXT3_FL_USER_VISIBLE; + return put_user(flags, (int __user *) arg); + case EXT3_IOC_SETFLAGS: { + handle_t *handle = NULL; + int err; + struct ext3_iloc iloc; + unsigned int oldflags; + unsigned int jflag; + + if (IS_RDONLY(inode)) + return -EROFS; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EACCES; + + if (get_user(flags, (int __user *) arg)) + return -EFAULT; + + if (!S_ISDIR(inode->i_mode)) + flags &= ~EXT3_DIRSYNC_FL; + + mutex_lock(&inode->i_mutex); + oldflags = ei->i_flags; + + /* The JOURNAL_DATA flag is modifiable only by root */ + jflag = flags & EXT3_JOURNAL_DATA_FL; + + /* + * The IMMUTABLE and APPEND_ONLY flags can only be changed by + * the relevant capability. + * + * This test looks nicer. Thanks to Pauline Middelink + */ + if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { + if (!capable(CAP_LINUX_IMMUTABLE)) { + mutex_unlock(&inode->i_mutex); + return -EPERM; + } + } + + /* + * The JOURNAL_DATA flag can only be changed by + * the relevant capability. + */ + if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { + if (!capable(CAP_SYS_RESOURCE)) { + mutex_unlock(&inode->i_mutex); + return -EPERM; + } + } + + + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) { + mutex_unlock(&inode->i_mutex); + return PTR_ERR(handle); + } + if (IS_SYNC(inode)) + handle->h_sync = 1; + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + goto flags_err; + + flags = flags & EXT3_FL_USER_MODIFIABLE; + flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE; + ei->i_flags = flags; + + ext3_set_inode_flags(inode); + inode->i_ctime = CURRENT_TIME_SEC; + + err = ext3_mark_iloc_dirty(handle, inode, &iloc); +flags_err: + ext3_journal_stop(handle); + if (err) { + mutex_unlock(&inode->i_mutex); + return err; + } + + if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) + err = ext3_change_inode_journal_flag(inode, jflag); + mutex_unlock(&inode->i_mutex); + return err; + } + case EXT3_IOC_GETVERSION: + case EXT3_IOC_GETVERSION_OLD: + return put_user(inode->i_generation, (int __user *) arg); + case EXT3_IOC_SETVERSION: + case EXT3_IOC_SETVERSION_OLD: { + handle_t *handle; + struct ext3_iloc iloc; + __u32 generation; + int err; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + if (get_user(generation, (int __user *) arg)) + return -EFAULT; + + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err == 0) { + inode->i_ctime = CURRENT_TIME_SEC; + inode->i_generation = generation; + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + } + ext3_journal_stop(handle); + return err; + } +#ifdef CONFIG_JBD_DEBUG + case EXT3_IOC_WAIT_FOR_READONLY: + /* + * This is racy - by the time we're woken up and running, + * the superblock could be released. And the module could + * have been unloaded. So sue me. + * + * Returns 1 if it slept, else zero. + */ + { + struct super_block *sb = inode->i_sb; + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait); + if (timer_pending(&EXT3_SB(sb)->turn_ro_timer)) { + schedule(); + ret = 1; + } + remove_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait); + return ret; + } +#endif + case EXT3_IOC_GETRSVSZ: + if (test_opt(inode->i_sb, RESERVATION) + && S_ISREG(inode->i_mode) + && ei->i_block_alloc_info) { + rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; + return put_user(rsv_window_size, (int __user *)arg); + } + return -ENOTTY; + case EXT3_IOC_SETRSVSZ: { + + if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) + return -ENOTTY; + + if (IS_RDONLY(inode)) + return -EROFS; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EACCES; + + if (get_user(rsv_window_size, (int __user *)arg)) + return -EFAULT; + + if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) + rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; + + /* + * need to allocate reservation structure for this inode + * before set the window size + */ + mutex_lock(&ei->truncate_mutex); + if (!ei->i_block_alloc_info) + ext3_init_block_alloc_info(inode); + + if (ei->i_block_alloc_info){ + struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; + rsv->rsv_goal_size = rsv_window_size; + } + mutex_unlock(&ei->truncate_mutex); + return 0; + } + case EXT3_IOC_GROUP_EXTEND: { + ext3_fsblk_t n_blocks_count; + struct super_block *sb = inode->i_sb; + int err; + + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; + + if (IS_RDONLY(inode)) + return -EROFS; + + if (get_user(n_blocks_count, (__u32 __user *)arg)) + return -EFAULT; + + err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count); + journal_lock_updates(EXT3_SB(sb)->s_journal); + journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + + return err; + } + case EXT3_IOC_GROUP_ADD: { + struct ext3_new_group_data input; + struct super_block *sb = inode->i_sb; + int err; + + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; + + if (IS_RDONLY(inode)) + return -EROFS; + + if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg, + sizeof(input))) + return -EFAULT; + + err = ext3_group_add(sb, &input); + journal_lock_updates(EXT3_SB(sb)->s_journal); + journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + + return err; + } + + + default: + return -ENOTTY; + } +} + +#ifdef CONFIG_COMPAT +long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = file->f_dentry->d_inode; + int ret; + + /* These are just misnamed, they actually get/put from/to user an int */ + switch (cmd) { + case EXT3_IOC32_GETFLAGS: + cmd = EXT3_IOC_GETFLAGS; + break; + case EXT3_IOC32_SETFLAGS: + cmd = EXT3_IOC_SETFLAGS; + break; + case EXT3_IOC32_GETVERSION: + cmd = EXT3_IOC_GETVERSION; + break; + case EXT3_IOC32_SETVERSION: + cmd = EXT3_IOC_SETVERSION; + break; + case EXT3_IOC32_GROUP_EXTEND: + cmd = EXT3_IOC_GROUP_EXTEND; + break; + case EXT3_IOC32_GETVERSION_OLD: + cmd = EXT3_IOC_GETVERSION_OLD; + break; + case EXT3_IOC32_SETVERSION_OLD: + cmd = EXT3_IOC_SETVERSION_OLD; + break; +#ifdef CONFIG_JBD_DEBUG + case EXT3_IOC32_WAIT_FOR_READONLY: + cmd = EXT3_IOC_WAIT_FOR_READONLY; + break; +#endif + case EXT3_IOC32_GETRSVSZ: + cmd = EXT3_IOC_GETRSVSZ; + break; + case EXT3_IOC32_SETRSVSZ: + cmd = EXT3_IOC_SETRSVSZ; + break; + case EXT3_IOC_GROUP_ADD: + break; + default: + return -ENOIOCTLCMD; + } + lock_kernel(); + ret = ext3_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); + unlock_kernel(); + return ret; +} +#endif diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c new file mode 100644 index 000000000000..906731a20f1a --- /dev/null +++ b/fs/ext4/namei.c @@ -0,0 +1,2397 @@ +/* + * linux/fs/ext3/namei.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/namei.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + * Directory entry file type support and forward compatibility hooks + * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998 + * Hash Tree Directory indexing (c) + * Daniel Phillips, 2001 + * Hash Tree Directory indexing porting + * Christopher Li, 2002 + * Hash Tree Directory indexing cleanup + * Theodore Ts'o, 2002 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "namei.h" +#include "xattr.h" +#include "acl.h" + +/* + * define how far ahead to read directories while searching them. + */ +#define NAMEI_RA_CHUNKS 2 +#define NAMEI_RA_BLOCKS 4 +#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) +#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) + +static struct buffer_head *ext3_append(handle_t *handle, + struct inode *inode, + u32 *block, int *err) +{ + struct buffer_head *bh; + + *block = inode->i_size >> inode->i_sb->s_blocksize_bits; + + if ((bh = ext3_bread(handle, inode, *block, 1, err))) { + inode->i_size += inode->i_sb->s_blocksize; + EXT3_I(inode)->i_disksize = inode->i_size; + ext3_journal_get_write_access(handle,bh); + } + return bh; +} + +#ifndef assert +#define assert(test) J_ASSERT(test) +#endif + +#ifndef swap +#define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0) +#endif + +#ifdef DX_DEBUG +#define dxtrace(command) command +#else +#define dxtrace(command) +#endif + +struct fake_dirent +{ + __le32 inode; + __le16 rec_len; + u8 name_len; + u8 file_type; +}; + +struct dx_countlimit +{ + __le16 limit; + __le16 count; +}; + +struct dx_entry +{ + __le32 hash; + __le32 block; +}; + +/* + * dx_root_info is laid out so that if it should somehow get overlaid by a + * dirent the two low bits of the hash version will be zero. Therefore, the + * hash version mod 4 should never be 0. Sincerely, the paranoia department. + */ + +struct dx_root +{ + struct fake_dirent dot; + char dot_name[4]; + struct fake_dirent dotdot; + char dotdot_name[4]; + struct dx_root_info + { + __le32 reserved_zero; + u8 hash_version; + u8 info_length; /* 8 */ + u8 indirect_levels; + u8 unused_flags; + } + info; + struct dx_entry entries[0]; +}; + +struct dx_node +{ + struct fake_dirent fake; + struct dx_entry entries[0]; +}; + + +struct dx_frame +{ + struct buffer_head *bh; + struct dx_entry *entries; + struct dx_entry *at; +}; + +struct dx_map_entry +{ + u32 hash; + u32 offs; +}; + +#ifdef CONFIG_EXT3_INDEX +static inline unsigned dx_get_block (struct dx_entry *entry); +static void dx_set_block (struct dx_entry *entry, unsigned value); +static inline unsigned dx_get_hash (struct dx_entry *entry); +static void dx_set_hash (struct dx_entry *entry, unsigned value); +static unsigned dx_get_count (struct dx_entry *entries); +static unsigned dx_get_limit (struct dx_entry *entries); +static void dx_set_count (struct dx_entry *entries, unsigned value); +static void dx_set_limit (struct dx_entry *entries, unsigned value); +static unsigned dx_root_limit (struct inode *dir, unsigned infosize); +static unsigned dx_node_limit (struct inode *dir); +static struct dx_frame *dx_probe(struct dentry *dentry, + struct inode *dir, + struct dx_hash_info *hinfo, + struct dx_frame *frame, + int *err); +static void dx_release (struct dx_frame *frames); +static int dx_make_map (struct ext3_dir_entry_2 *de, int size, + struct dx_hash_info *hinfo, struct dx_map_entry map[]); +static void dx_sort_map(struct dx_map_entry *map, unsigned count); +static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to, + struct dx_map_entry *offsets, int count); +static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size); +static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block); +static int ext3_htree_next_block(struct inode *dir, __u32 hash, + struct dx_frame *frame, + struct dx_frame *frames, + __u32 *start_hash); +static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, + struct ext3_dir_entry_2 **res_dir, int *err); +static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, + struct inode *inode); + +/* + * Future: use high four bits of block for coalesce-on-delete flags + * Mask them off for now. + */ + +static inline unsigned dx_get_block (struct dx_entry *entry) +{ + return le32_to_cpu(entry->block) & 0x00ffffff; +} + +static inline void dx_set_block (struct dx_entry *entry, unsigned value) +{ + entry->block = cpu_to_le32(value); +} + +static inline unsigned dx_get_hash (struct dx_entry *entry) +{ + return le32_to_cpu(entry->hash); +} + +static inline void dx_set_hash (struct dx_entry *entry, unsigned value) +{ + entry->hash = cpu_to_le32(value); +} + +static inline unsigned dx_get_count (struct dx_entry *entries) +{ + return le16_to_cpu(((struct dx_countlimit *) entries)->count); +} + +static inline unsigned dx_get_limit (struct dx_entry *entries) +{ + return le16_to_cpu(((struct dx_countlimit *) entries)->limit); +} + +static inline void dx_set_count (struct dx_entry *entries, unsigned value) +{ + ((struct dx_countlimit *) entries)->count = cpu_to_le16(value); +} + +static inline void dx_set_limit (struct dx_entry *entries, unsigned value) +{ + ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value); +} + +static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize) +{ + unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1) - + EXT3_DIR_REC_LEN(2) - infosize; + return 0? 20: entry_space / sizeof(struct dx_entry); +} + +static inline unsigned dx_node_limit (struct inode *dir) +{ + unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0); + return 0? 22: entry_space / sizeof(struct dx_entry); +} + +/* + * Debug + */ +#ifdef DX_DEBUG +static void dx_show_index (char * label, struct dx_entry *entries) +{ + int i, n = dx_get_count (entries); + printk("%s index ", label); + for (i = 0; i < n; i++) + { + printk("%x->%u ", i? dx_get_hash(entries + i): 0, dx_get_block(entries + i)); + } + printk("\n"); +} + +struct stats +{ + unsigned names; + unsigned space; + unsigned bcount; +}; + +static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_entry_2 *de, + int size, int show_names) +{ + unsigned names = 0, space = 0; + char *base = (char *) de; + struct dx_hash_info h = *hinfo; + + printk("names: "); + while ((char *) de < base + size) + { + if (de->inode) + { + if (show_names) + { + int len = de->name_len; + char *name = de->name; + while (len--) printk("%c", *name++); + ext3fs_dirhash(de->name, de->name_len, &h); + printk(":%x.%u ", h.hash, + ((char *) de - base)); + } + space += EXT3_DIR_REC_LEN(de->name_len); + names++; + } + de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); + } + printk("(%i)\n", names); + return (struct stats) { names, space, 1 }; +} + +struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir, + struct dx_entry *entries, int levels) +{ + unsigned blocksize = dir->i_sb->s_blocksize; + unsigned count = dx_get_count (entries), names = 0, space = 0, i; + unsigned bcount = 0; + struct buffer_head *bh; + int err; + printk("%i indexed blocks...\n", count); + for (i = 0; i < count; i++, entries++) + { + u32 block = dx_get_block(entries), hash = i? dx_get_hash(entries): 0; + u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash; + struct stats stats; + printk("%s%3u:%03u hash %8x/%8x ",levels?"":" ", i, block, hash, range); + if (!(bh = ext3_bread (NULL,dir, block, 0,&err))) continue; + stats = levels? + dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1): + dx_show_leaf(hinfo, (struct ext3_dir_entry_2 *) bh->b_data, blocksize, 0); + names += stats.names; + space += stats.space; + bcount += stats.bcount; + brelse (bh); + } + if (bcount) + printk("%snames %u, fullness %u (%u%%)\n", levels?"":" ", + names, space/bcount,(space/bcount)*100/blocksize); + return (struct stats) { names, space, bcount}; +} +#endif /* DX_DEBUG */ + +/* + * Probe for a directory leaf block to search. + * + * dx_probe can return ERR_BAD_DX_DIR, which means there was a format + * error in the directory index, and the caller should fall back to + * searching the directory normally. The callers of dx_probe **MUST** + * check for this error code, and make sure it never gets reflected + * back to userspace. + */ +static struct dx_frame * +dx_probe(struct dentry *dentry, struct inode *dir, + struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err) +{ + unsigned count, indirect; + struct dx_entry *at, *entries, *p, *q, *m; + struct dx_root *root; + struct buffer_head *bh; + struct dx_frame *frame = frame_in; + u32 hash; + + frame->bh = NULL; + if (dentry) + dir = dentry->d_parent->d_inode; + if (!(bh = ext3_bread (NULL,dir, 0, 0, err))) + goto fail; + root = (struct dx_root *) bh->b_data; + if (root->info.hash_version != DX_HASH_TEA && + root->info.hash_version != DX_HASH_HALF_MD4 && + root->info.hash_version != DX_HASH_LEGACY) { + ext3_warning(dir->i_sb, __FUNCTION__, + "Unrecognised inode hash code %d", + root->info.hash_version); + brelse(bh); + *err = ERR_BAD_DX_DIR; + goto fail; + } + hinfo->hash_version = root->info.hash_version; + hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed; + if (dentry) + ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo); + hash = hinfo->hash; + + if (root->info.unused_flags & 1) { + ext3_warning(dir->i_sb, __FUNCTION__, + "Unimplemented inode hash flags: %#06x", + root->info.unused_flags); + brelse(bh); + *err = ERR_BAD_DX_DIR; + goto fail; + } + + if ((indirect = root->info.indirect_levels) > 1) { + ext3_warning(dir->i_sb, __FUNCTION__, + "Unimplemented inode hash depth: %#06x", + root->info.indirect_levels); + brelse(bh); + *err = ERR_BAD_DX_DIR; + goto fail; + } + + entries = (struct dx_entry *) (((char *)&root->info) + + root->info.info_length); + assert(dx_get_limit(entries) == dx_root_limit(dir, + root->info.info_length)); + dxtrace (printk("Look up %x", hash)); + while (1) + { + count = dx_get_count(entries); + assert (count && count <= dx_get_limit(entries)); + p = entries + 1; + q = entries + count - 1; + while (p <= q) + { + m = p + (q - p)/2; + dxtrace(printk(".")); + if (dx_get_hash(m) > hash) + q = m - 1; + else + p = m + 1; + } + + if (0) // linear search cross check + { + unsigned n = count - 1; + at = entries; + while (n--) + { + dxtrace(printk(",")); + if (dx_get_hash(++at) > hash) + { + at--; + break; + } + } + assert (at == p - 1); + } + + at = p - 1; + dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at))); + frame->bh = bh; + frame->entries = entries; + frame->at = at; + if (!indirect--) return frame; + if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err))) + goto fail2; + at = entries = ((struct dx_node *) bh->b_data)->entries; + assert (dx_get_limit(entries) == dx_node_limit (dir)); + frame++; + } +fail2: + while (frame >= frame_in) { + brelse(frame->bh); + frame--; + } +fail: + return NULL; +} + +static void dx_release (struct dx_frame *frames) +{ + if (frames[0].bh == NULL) + return; + + if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels) + brelse(frames[1].bh); + brelse(frames[0].bh); +} + +/* + * This function increments the frame pointer to search the next leaf + * block, and reads in the necessary intervening nodes if the search + * should be necessary. Whether or not the search is necessary is + * controlled by the hash parameter. If the hash value is even, then + * the search is only continued if the next block starts with that + * hash value. This is used if we are searching for a specific file. + * + * If the hash value is HASH_NB_ALWAYS, then always go to the next block. + * + * This function returns 1 if the caller should continue to search, + * or 0 if it should not. If there is an error reading one of the + * index blocks, it will a negative error code. + * + * If start_hash is non-null, it will be filled in with the starting + * hash of the next page. + */ +static int ext3_htree_next_block(struct inode *dir, __u32 hash, + struct dx_frame *frame, + struct dx_frame *frames, + __u32 *start_hash) +{ + struct dx_frame *p; + struct buffer_head *bh; + int err, num_frames = 0; + __u32 bhash; + + p = frame; + /* + * Find the next leaf page by incrementing the frame pointer. + * If we run out of entries in the interior node, loop around and + * increment pointer in the parent node. When we break out of + * this loop, num_frames indicates the number of interior + * nodes need to be read. + */ + while (1) { + if (++(p->at) < p->entries + dx_get_count(p->entries)) + break; + if (p == frames) + return 0; + num_frames++; + p--; + } + + /* + * If the hash is 1, then continue only if the next page has a + * continuation hash of any value. This is used for readdir + * handling. Otherwise, check to see if the hash matches the + * desired contiuation hash. If it doesn't, return since + * there's no point to read in the successive index pages. + */ + bhash = dx_get_hash(p->at); + if (start_hash) + *start_hash = bhash; + if ((hash & 1) == 0) { + if ((bhash & ~1) != hash) + return 0; + } + /* + * If the hash is HASH_NB_ALWAYS, we always go to the next + * block so no check is necessary + */ + while (num_frames--) { + if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at), + 0, &err))) + return err; /* Failure */ + p++; + brelse (p->bh); + p->bh = bh; + p->at = p->entries = ((struct dx_node *) bh->b_data)->entries; + } + return 1; +} + + +/* + * p is at least 6 bytes before the end of page + */ +static inline struct ext3_dir_entry_2 *ext3_next_entry(struct ext3_dir_entry_2 *p) +{ + return (struct ext3_dir_entry_2 *)((char*)p + le16_to_cpu(p->rec_len)); +} + +/* + * This function fills a red-black tree with information from a + * directory block. It returns the number directory entries loaded + * into the tree. If there is an error it is returned in err. + */ +static int htree_dirblock_to_tree(struct file *dir_file, + struct inode *dir, int block, + struct dx_hash_info *hinfo, + __u32 start_hash, __u32 start_minor_hash) +{ + struct buffer_head *bh; + struct ext3_dir_entry_2 *de, *top; + int err, count = 0; + + dxtrace(printk("In htree dirblock_to_tree: block %d\n", block)); + if (!(bh = ext3_bread (NULL, dir, block, 0, &err))) + return err; + + de = (struct ext3_dir_entry_2 *) bh->b_data; + top = (struct ext3_dir_entry_2 *) ((char *) de + + dir->i_sb->s_blocksize - + EXT3_DIR_REC_LEN(0)); + for (; de < top; de = ext3_next_entry(de)) { + ext3fs_dirhash(de->name, de->name_len, hinfo); + if ((hinfo->hash < start_hash) || + ((hinfo->hash == start_hash) && + (hinfo->minor_hash < start_minor_hash))) + continue; + if (de->inode == 0) + continue; + if ((err = ext3_htree_store_dirent(dir_file, + hinfo->hash, hinfo->minor_hash, de)) != 0) { + brelse(bh); + return err; + } + count++; + } + brelse(bh); + return count; +} + + +/* + * This function fills a red-black tree with information from a + * directory. We start scanning the directory in hash order, starting + * at start_hash and start_minor_hash. + * + * This function returns the number of entries inserted into the tree, + * or a negative error code. + */ +int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, + __u32 start_minor_hash, __u32 *next_hash) +{ + struct dx_hash_info hinfo; + struct ext3_dir_entry_2 *de; + struct dx_frame frames[2], *frame; + struct inode *dir; + int block, err; + int count = 0; + int ret; + __u32 hashval; + + dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash, + start_minor_hash)); + dir = dir_file->f_dentry->d_inode; + if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) { + hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; + hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed; + count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo, + start_hash, start_minor_hash); + *next_hash = ~0; + return count; + } + hinfo.hash = start_hash; + hinfo.minor_hash = 0; + frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err); + if (!frame) + return err; + + /* Add '.' and '..' from the htree header */ + if (!start_hash && !start_minor_hash) { + de = (struct ext3_dir_entry_2 *) frames[0].bh->b_data; + if ((err = ext3_htree_store_dirent(dir_file, 0, 0, de)) != 0) + goto errout; + count++; + } + if (start_hash < 2 || (start_hash ==2 && start_minor_hash==0)) { + de = (struct ext3_dir_entry_2 *) frames[0].bh->b_data; + de = ext3_next_entry(de); + if ((err = ext3_htree_store_dirent(dir_file, 2, 0, de)) != 0) + goto errout; + count++; + } + + while (1) { + block = dx_get_block(frame->at); + ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo, + start_hash, start_minor_hash); + if (ret < 0) { + err = ret; + goto errout; + } + count += ret; + hashval = ~0; + ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS, + frame, frames, &hashval); + *next_hash = hashval; + if (ret < 0) { + err = ret; + goto errout; + } + /* + * Stop if: (a) there are no more entries, or + * (b) we have inserted at least one entry and the + * next hash value is not a continuation + */ + if ((ret == 0) || + (count && ((hashval & 1) == 0))) + break; + } + dx_release(frames); + dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n", + count, *next_hash)); + return count; +errout: + dx_release(frames); + return (err); +} + + +/* + * Directory block splitting, compacting + */ + +static int dx_make_map (struct ext3_dir_entry_2 *de, int size, + struct dx_hash_info *hinfo, struct dx_map_entry *map_tail) +{ + int count = 0; + char *base = (char *) de; + struct dx_hash_info h = *hinfo; + + while ((char *) de < base + size) + { + if (de->name_len && de->inode) { + ext3fs_dirhash(de->name, de->name_len, &h); + map_tail--; + map_tail->hash = h.hash; + map_tail->offs = (u32) ((char *) de - base); + count++; + cond_resched(); + } + /* XXX: do we need to check rec_len == 0 case? -Chris */ + de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); + } + return count; +} + +static void dx_sort_map (struct dx_map_entry *map, unsigned count) +{ + struct dx_map_entry *p, *q, *top = map + count - 1; + int more; + /* Combsort until bubble sort doesn't suck */ + while (count > 2) + { + count = count*10/13; + if (count - 9 < 2) /* 9, 10 -> 11 */ + count = 11; + for (p = top, q = p - count; q >= map; p--, q--) + if (p->hash < q->hash) + swap(*p, *q); + } + /* Garden variety bubble sort */ + do { + more = 0; + q = top; + while (q-- > map) + { + if (q[1].hash >= q[0].hash) + continue; + swap(*(q+1), *q); + more = 1; + } + } while(more); +} + +static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block) +{ + struct dx_entry *entries = frame->entries; + struct dx_entry *old = frame->at, *new = old + 1; + int count = dx_get_count(entries); + + assert(count < dx_get_limit(entries)); + assert(old < entries + count); + memmove(new + 1, new, (char *)(entries + count) - (char *)(new)); + dx_set_hash(new, hash); + dx_set_block(new, block); + dx_set_count(entries, count + 1); +} +#endif + + +static void ext3_update_dx_flag(struct inode *inode) +{ + if (!EXT3_HAS_COMPAT_FEATURE(inode->i_sb, + EXT3_FEATURE_COMPAT_DIR_INDEX)) + EXT3_I(inode)->i_flags &= ~EXT3_INDEX_FL; +} + +/* + * NOTE! unlike strncmp, ext3_match returns 1 for success, 0 for failure. + * + * `len <= EXT3_NAME_LEN' is guaranteed by caller. + * `de != NULL' is guaranteed by caller. + */ +static inline int ext3_match (int len, const char * const name, + struct ext3_dir_entry_2 * de) +{ + if (len != de->name_len) + return 0; + if (!de->inode) + return 0; + return !memcmp(name, de->name, len); +} + +/* + * Returns 0 if not found, -1 on failure, and 1 on success + */ +static inline int search_dirblock(struct buffer_head * bh, + struct inode *dir, + struct dentry *dentry, + unsigned long offset, + struct ext3_dir_entry_2 ** res_dir) +{ + struct ext3_dir_entry_2 * de; + char * dlimit; + int de_len; + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; + + de = (struct ext3_dir_entry_2 *) bh->b_data; + dlimit = bh->b_data + dir->i_sb->s_blocksize; + while ((char *) de < dlimit) { + /* this code is executed quadratically often */ + /* do minimal checking `by hand' */ + + if ((char *) de + namelen <= dlimit && + ext3_match (namelen, name, de)) { + /* found a match - just to be sure, do a full check */ + if (!ext3_check_dir_entry("ext3_find_entry", + dir, de, bh, offset)) + return -1; + *res_dir = de; + return 1; + } + /* prevent looping on a bad block */ + de_len = le16_to_cpu(de->rec_len); + if (de_len <= 0) + return -1; + offset += de_len; + de = (struct ext3_dir_entry_2 *) ((char *) de + de_len); + } + return 0; +} + + +/* + * ext3_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + * + * The returned buffer_head has ->b_count elevated. The caller is expected + * to brelse() it when appropriate. + */ +static struct buffer_head * ext3_find_entry (struct dentry *dentry, + struct ext3_dir_entry_2 ** res_dir) +{ + struct super_block * sb; + struct buffer_head * bh_use[NAMEI_RA_SIZE]; + struct buffer_head * bh, *ret = NULL; + unsigned long start, block, b; + int ra_max = 0; /* Number of bh's in the readahead + buffer, bh_use[] */ + int ra_ptr = 0; /* Current index into readahead + buffer */ + int num = 0; + int nblocks, i, err; + struct inode *dir = dentry->d_parent->d_inode; + int namelen; + const u8 *name; + unsigned blocksize; + + *res_dir = NULL; + sb = dir->i_sb; + blocksize = sb->s_blocksize; + namelen = dentry->d_name.len; + name = dentry->d_name.name; + if (namelen > EXT3_NAME_LEN) + return NULL; +#ifdef CONFIG_EXT3_INDEX + if (is_dx(dir)) { + bh = ext3_dx_find_entry(dentry, res_dir, &err); + /* + * On success, or if the error was file not found, + * return. Otherwise, fall back to doing a search the + * old fashioned way. + */ + if (bh || (err != ERR_BAD_DX_DIR)) + return bh; + dxtrace(printk("ext3_find_entry: dx failed, falling back\n")); + } +#endif + nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb); + start = EXT3_I(dir)->i_dir_start_lookup; + if (start >= nblocks) + start = 0; + block = start; +restart: + do { + /* + * We deal with the read-ahead logic here. + */ + if (ra_ptr >= ra_max) { + /* Refill the readahead buffer */ + ra_ptr = 0; + b = block; + for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) { + /* + * Terminate if we reach the end of the + * directory and must wrap, or if our + * search has finished at this block. + */ + if (b >= nblocks || (num && block == start)) { + bh_use[ra_max] = NULL; + break; + } + num++; + bh = ext3_getblk(NULL, dir, b++, 0, &err); + bh_use[ra_max] = bh; + if (bh) + ll_rw_block(READ_META, 1, &bh); + } + } + if ((bh = bh_use[ra_ptr++]) == NULL) + goto next; + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { + /* read error, skip block & hope for the best */ + ext3_error(sb, __FUNCTION__, "reading directory #%lu " + "offset %lu", dir->i_ino, block); + brelse(bh); + goto next; + } + i = search_dirblock(bh, dir, dentry, + block << EXT3_BLOCK_SIZE_BITS(sb), res_dir); + if (i == 1) { + EXT3_I(dir)->i_dir_start_lookup = block; + ret = bh; + goto cleanup_and_exit; + } else { + brelse(bh); + if (i < 0) + goto cleanup_and_exit; + } + next: + if (++block >= nblocks) + block = 0; + } while (block != start); + + /* + * If the directory has grown while we were searching, then + * search the last part of the directory before giving up. + */ + block = nblocks; + nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb); + if (block < nblocks) { + start = 0; + goto restart; + } + +cleanup_and_exit: + /* Clean up the read-ahead blocks */ + for (; ra_ptr < ra_max; ra_ptr++) + brelse (bh_use[ra_ptr]); + return ret; +} + +#ifdef CONFIG_EXT3_INDEX +static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, + struct ext3_dir_entry_2 **res_dir, int *err) +{ + struct super_block * sb; + struct dx_hash_info hinfo; + u32 hash; + struct dx_frame frames[2], *frame; + struct ext3_dir_entry_2 *de, *top; + struct buffer_head *bh; + unsigned long block; + int retval; + int namelen = dentry->d_name.len; + const u8 *name = dentry->d_name.name; + struct inode *dir = dentry->d_parent->d_inode; + + sb = dir->i_sb; + /* NFS may look up ".." - look at dx_root directory block */ + if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){ + if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err))) + return NULL; + } else { + frame = frames; + frame->bh = NULL; /* for dx_release() */ + frame->at = (struct dx_entry *)frames; /* hack for zero entry*/ + dx_set_block(frame->at, 0); /* dx_root block is 0 */ + } + hash = hinfo.hash; + do { + block = dx_get_block(frame->at); + if (!(bh = ext3_bread (NULL,dir, block, 0, err))) + goto errout; + de = (struct ext3_dir_entry_2 *) bh->b_data; + top = (struct ext3_dir_entry_2 *) ((char *) de + sb->s_blocksize - + EXT3_DIR_REC_LEN(0)); + for (; de < top; de = ext3_next_entry(de)) + if (ext3_match (namelen, name, de)) { + if (!ext3_check_dir_entry("ext3_find_entry", + dir, de, bh, + (block<b_data))) { + brelse (bh); + goto errout; + } + *res_dir = de; + dx_release (frames); + return bh; + } + brelse (bh); + /* Check to see if we should continue to search */ + retval = ext3_htree_next_block(dir, hash, frame, + frames, NULL); + if (retval < 0) { + ext3_warning(sb, __FUNCTION__, + "error reading index page in directory #%lu", + dir->i_ino); + *err = retval; + goto errout; + } + } while (retval == 1); + + *err = -ENOENT; +errout: + dxtrace(printk("%s not found\n", name)); + dx_release (frames); + return NULL; +} +#endif + +static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) +{ + struct inode * inode; + struct ext3_dir_entry_2 * de; + struct buffer_head * bh; + + if (dentry->d_name.len > EXT3_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + bh = ext3_find_entry(dentry, &de); + inode = NULL; + if (bh) { + unsigned long ino = le32_to_cpu(de->inode); + brelse (bh); + if (!ext3_valid_inum(dir->i_sb, ino)) { + ext3_error(dir->i_sb, "ext3_lookup", + "bad inode number: %lu", ino); + inode = NULL; + } else + inode = iget(dir->i_sb, ino); + + if (!inode) + return ERR_PTR(-EACCES); + } + return d_splice_alias(inode, dentry); +} + + +struct dentry *ext3_get_parent(struct dentry *child) +{ + unsigned long ino; + struct dentry *parent; + struct inode *inode; + struct dentry dotdot; + struct ext3_dir_entry_2 * de; + struct buffer_head *bh; + + dotdot.d_name.name = ".."; + dotdot.d_name.len = 2; + dotdot.d_parent = child; /* confusing, isn't it! */ + + bh = ext3_find_entry(&dotdot, &de); + inode = NULL; + if (!bh) + return ERR_PTR(-ENOENT); + ino = le32_to_cpu(de->inode); + brelse(bh); + + if (!ext3_valid_inum(child->d_inode->i_sb, ino)) { + ext3_error(child->d_inode->i_sb, "ext3_get_parent", + "bad inode number: %lu", ino); + inode = NULL; + } else + inode = iget(child->d_inode->i_sb, ino); + + if (!inode) + return ERR_PTR(-EACCES); + + parent = d_alloc_anon(inode); + if (!parent) { + iput(inode); + parent = ERR_PTR(-ENOMEM); + } + return parent; +} + +#define S_SHIFT 12 +static unsigned char ext3_type_by_mode[S_IFMT >> S_SHIFT] = { + [S_IFREG >> S_SHIFT] = EXT3_FT_REG_FILE, + [S_IFDIR >> S_SHIFT] = EXT3_FT_DIR, + [S_IFCHR >> S_SHIFT] = EXT3_FT_CHRDEV, + [S_IFBLK >> S_SHIFT] = EXT3_FT_BLKDEV, + [S_IFIFO >> S_SHIFT] = EXT3_FT_FIFO, + [S_IFSOCK >> S_SHIFT] = EXT3_FT_SOCK, + [S_IFLNK >> S_SHIFT] = EXT3_FT_SYMLINK, +}; + +static inline void ext3_set_de_type(struct super_block *sb, + struct ext3_dir_entry_2 *de, + umode_t mode) { + if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) + de->file_type = ext3_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; +} + +#ifdef CONFIG_EXT3_INDEX +static struct ext3_dir_entry_2 * +dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count) +{ + unsigned rec_len = 0; + + while (count--) { + struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) (from + map->offs); + rec_len = EXT3_DIR_REC_LEN(de->name_len); + memcpy (to, de, rec_len); + ((struct ext3_dir_entry_2 *) to)->rec_len = + cpu_to_le16(rec_len); + de->inode = 0; + map++; + to += rec_len; + } + return (struct ext3_dir_entry_2 *) (to - rec_len); +} + +static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size) +{ + struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base; + unsigned rec_len = 0; + + prev = to = de; + while ((char*)de < base + size) { + next = (struct ext3_dir_entry_2 *) ((char *) de + + le16_to_cpu(de->rec_len)); + if (de->inode && de->name_len) { + rec_len = EXT3_DIR_REC_LEN(de->name_len); + if (de > to) + memmove(to, de, rec_len); + to->rec_len = cpu_to_le16(rec_len); + prev = to; + to = (struct ext3_dir_entry_2 *) (((char *) to) + rec_len); + } + de = next; + } + return prev; +} + +static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, + struct buffer_head **bh,struct dx_frame *frame, + struct dx_hash_info *hinfo, int *error) +{ + unsigned blocksize = dir->i_sb->s_blocksize; + unsigned count, continued; + struct buffer_head *bh2; + u32 newblock; + u32 hash2; + struct dx_map_entry *map; + char *data1 = (*bh)->b_data, *data2; + unsigned split; + struct ext3_dir_entry_2 *de = NULL, *de2; + int err; + + bh2 = ext3_append (handle, dir, &newblock, error); + if (!(bh2)) { + brelse(*bh); + *bh = NULL; + goto errout; + } + + BUFFER_TRACE(*bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, *bh); + if (err) { + journal_error: + brelse(*bh); + brelse(bh2); + *bh = NULL; + ext3_std_error(dir->i_sb, err); + goto errout; + } + BUFFER_TRACE(frame->bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, frame->bh); + if (err) + goto journal_error; + + data2 = bh2->b_data; + + /* create map in the end of data2 block */ + map = (struct dx_map_entry *) (data2 + blocksize); + count = dx_make_map ((struct ext3_dir_entry_2 *) data1, + blocksize, hinfo, map); + map -= count; + split = count/2; // need to adjust to actual middle + dx_sort_map (map, count); + hash2 = map[split].hash; + continued = hash2 == map[split - 1].hash; + dxtrace(printk("Split block %i at %x, %i/%i\n", + dx_get_block(frame->at), hash2, split, count-split)); + + /* Fancy dance to stay within two buffers */ + de2 = dx_move_dirents(data1, data2, map + split, count - split); + de = dx_pack_dirents(data1,blocksize); + de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de); + de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2); + dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1)); + dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1)); + + /* Which block gets the new entry? */ + if (hinfo->hash >= hash2) + { + swap(*bh, bh2); + de = de2; + } + dx_insert_block (frame, hash2 + continued, newblock); + err = ext3_journal_dirty_metadata (handle, bh2); + if (err) + goto journal_error; + err = ext3_journal_dirty_metadata (handle, frame->bh); + if (err) + goto journal_error; + brelse (bh2); + dxtrace(dx_show_index ("frame", frame->entries)); +errout: + return de; +} +#endif + + +/* + * Add a new entry into a directory (leaf) block. If de is non-NULL, + * it points to a directory entry which is guaranteed to be large + * enough for new directory entry. If de is NULL, then + * add_dirent_to_buf will attempt search the directory block for + * space. It will return -ENOSPC if no space is available, and -EIO + * and -EEXIST if directory entry already exists. + * + * NOTE! bh is NOT released in the case where ENOSPC is returned. In + * all other cases bh is released. + */ +static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, + struct inode *inode, struct ext3_dir_entry_2 *de, + struct buffer_head * bh) +{ + struct inode *dir = dentry->d_parent->d_inode; + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; + unsigned long offset = 0; + unsigned short reclen; + int nlen, rlen, err; + char *top; + + reclen = EXT3_DIR_REC_LEN(namelen); + if (!de) { + de = (struct ext3_dir_entry_2 *)bh->b_data; + top = bh->b_data + dir->i_sb->s_blocksize - reclen; + while ((char *) de <= top) { + if (!ext3_check_dir_entry("ext3_add_entry", dir, de, + bh, offset)) { + brelse (bh); + return -EIO; + } + if (ext3_match (namelen, name, de)) { + brelse (bh); + return -EEXIST; + } + nlen = EXT3_DIR_REC_LEN(de->name_len); + rlen = le16_to_cpu(de->rec_len); + if ((de->inode? rlen - nlen: rlen) >= reclen) + break; + de = (struct ext3_dir_entry_2 *)((char *)de + rlen); + offset += rlen; + } + if ((char *) de > top) + return -ENOSPC; + } + BUFFER_TRACE(bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, bh); + if (err) { + ext3_std_error(dir->i_sb, err); + brelse(bh); + return err; + } + + /* By now the buffer is marked for journaling */ + nlen = EXT3_DIR_REC_LEN(de->name_len); + rlen = le16_to_cpu(de->rec_len); + if (de->inode) { + struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen); + de1->rec_len = cpu_to_le16(rlen - nlen); + de->rec_len = cpu_to_le16(nlen); + de = de1; + } + de->file_type = EXT3_FT_UNKNOWN; + if (inode) { + de->inode = cpu_to_le32(inode->i_ino); + ext3_set_de_type(dir->i_sb, de, inode->i_mode); + } else + de->inode = 0; + de->name_len = namelen; + memcpy (de->name, name, namelen); + /* + * XXX shouldn't update any times until successful + * completion of syscall, but too many callers depend + * on this. + * + * XXX similarly, too many callers depend on + * ext3_new_inode() setting the times, but error + * recovery deletes the inode, so the worst that can + * happen is that the times are slightly out of date + * and/or different from the directory change time. + */ + dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; + ext3_update_dx_flag(dir); + dir->i_version++; + ext3_mark_inode_dirty(handle, dir); + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh); + if (err) + ext3_std_error(dir->i_sb, err); + brelse(bh); + return 0; +} + +#ifdef CONFIG_EXT3_INDEX +/* + * This converts a one block unindexed directory to a 3 block indexed + * directory, and adds the dentry to the indexed directory. + */ +static int make_indexed_dir(handle_t *handle, struct dentry *dentry, + struct inode *inode, struct buffer_head *bh) +{ + struct inode *dir = dentry->d_parent->d_inode; + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; + struct buffer_head *bh2; + struct dx_root *root; + struct dx_frame frames[2], *frame; + struct dx_entry *entries; + struct ext3_dir_entry_2 *de, *de2; + char *data1, *top; + unsigned len; + int retval; + unsigned blocksize; + struct dx_hash_info hinfo; + u32 block; + struct fake_dirent *fde; + + blocksize = dir->i_sb->s_blocksize; + dxtrace(printk("Creating index\n")); + retval = ext3_journal_get_write_access(handle, bh); + if (retval) { + ext3_std_error(dir->i_sb, retval); + brelse(bh); + return retval; + } + root = (struct dx_root *) bh->b_data; + + bh2 = ext3_append (handle, dir, &block, &retval); + if (!(bh2)) { + brelse(bh); + return retval; + } + EXT3_I(dir)->i_flags |= EXT3_INDEX_FL; + data1 = bh2->b_data; + + /* The 0th block becomes the root, move the dirents out */ + fde = &root->dotdot; + de = (struct ext3_dir_entry_2 *)((char *)fde + le16_to_cpu(fde->rec_len)); + len = ((char *) root) + blocksize - (char *) de; + memcpy (data1, de, len); + de = (struct ext3_dir_entry_2 *) data1; + top = data1 + len; + while ((char *)(de2=(void*)de+le16_to_cpu(de->rec_len)) < top) + de = de2; + de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de); + /* Initialize the root; the dot dirents already exist */ + de = (struct ext3_dir_entry_2 *) (&root->dotdot); + de->rec_len = cpu_to_le16(blocksize - EXT3_DIR_REC_LEN(2)); + memset (&root->info, 0, sizeof(root->info)); + root->info.info_length = sizeof(root->info); + root->info.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; + entries = root->entries; + dx_set_block (entries, 1); + dx_set_count (entries, 1); + dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info))); + + /* Initialize as for dx_probe */ + hinfo.hash_version = root->info.hash_version; + hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed; + ext3fs_dirhash(name, namelen, &hinfo); + frame = frames; + frame->entries = entries; + frame->at = entries; + frame->bh = bh; + bh = bh2; + de = do_split(handle,dir, &bh, frame, &hinfo, &retval); + dx_release (frames); + if (!(de)) + return retval; + + return add_dirent_to_buf(handle, dentry, inode, de, bh); +} +#endif + +/* + * ext3_add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as ext3_find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static int ext3_add_entry (handle_t *handle, struct dentry *dentry, + struct inode *inode) +{ + struct inode *dir = dentry->d_parent->d_inode; + unsigned long offset; + struct buffer_head * bh; + struct ext3_dir_entry_2 *de; + struct super_block * sb; + int retval; +#ifdef CONFIG_EXT3_INDEX + int dx_fallback=0; +#endif + unsigned blocksize; + u32 block, blocks; + + sb = dir->i_sb; + blocksize = sb->s_blocksize; + if (!dentry->d_name.len) + return -EINVAL; +#ifdef CONFIG_EXT3_INDEX + if (is_dx(dir)) { + retval = ext3_dx_add_entry(handle, dentry, inode); + if (!retval || (retval != ERR_BAD_DX_DIR)) + return retval; + EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL; + dx_fallback++; + ext3_mark_inode_dirty(handle, dir); + } +#endif + blocks = dir->i_size >> sb->s_blocksize_bits; + for (block = 0, offset = 0; block < blocks; block++) { + bh = ext3_bread(handle, dir, block, 0, &retval); + if(!bh) + return retval; + retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); + if (retval != -ENOSPC) + return retval; + +#ifdef CONFIG_EXT3_INDEX + if (blocks == 1 && !dx_fallback && + EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX)) + return make_indexed_dir(handle, dentry, inode, bh); +#endif + brelse(bh); + } + bh = ext3_append(handle, dir, &block, &retval); + if (!bh) + return retval; + de = (struct ext3_dir_entry_2 *) bh->b_data; + de->inode = 0; + de->rec_len = cpu_to_le16(blocksize); + return add_dirent_to_buf(handle, dentry, inode, de, bh); +} + +#ifdef CONFIG_EXT3_INDEX +/* + * Returns 0 for success, or a negative error value + */ +static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, + struct inode *inode) +{ + struct dx_frame frames[2], *frame; + struct dx_entry *entries, *at; + struct dx_hash_info hinfo; + struct buffer_head * bh; + struct inode *dir = dentry->d_parent->d_inode; + struct super_block * sb = dir->i_sb; + struct ext3_dir_entry_2 *de; + int err; + + frame = dx_probe(dentry, NULL, &hinfo, frames, &err); + if (!frame) + return err; + entries = frame->entries; + at = frame->at; + + if (!(bh = ext3_bread(handle,dir, dx_get_block(frame->at), 0, &err))) + goto cleanup; + + BUFFER_TRACE(bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, bh); + if (err) + goto journal_error; + + err = add_dirent_to_buf(handle, dentry, inode, NULL, bh); + if (err != -ENOSPC) { + bh = NULL; + goto cleanup; + } + + /* Block full, should compress but for now just split */ + dxtrace(printk("using %u of %u node entries\n", + dx_get_count(entries), dx_get_limit(entries))); + /* Need to split index? */ + if (dx_get_count(entries) == dx_get_limit(entries)) { + u32 newblock; + unsigned icount = dx_get_count(entries); + int levels = frame - frames; + struct dx_entry *entries2; + struct dx_node *node2; + struct buffer_head *bh2; + + if (levels && (dx_get_count(frames->entries) == + dx_get_limit(frames->entries))) { + ext3_warning(sb, __FUNCTION__, + "Directory index full!"); + err = -ENOSPC; + goto cleanup; + } + bh2 = ext3_append (handle, dir, &newblock, &err); + if (!(bh2)) + goto cleanup; + node2 = (struct dx_node *)(bh2->b_data); + entries2 = node2->entries; + node2->fake.rec_len = cpu_to_le16(sb->s_blocksize); + node2->fake.inode = 0; + BUFFER_TRACE(frame->bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, frame->bh); + if (err) + goto journal_error; + if (levels) { + unsigned icount1 = icount/2, icount2 = icount - icount1; + unsigned hash2 = dx_get_hash(entries + icount1); + dxtrace(printk("Split index %i/%i\n", icount1, icount2)); + + BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ + err = ext3_journal_get_write_access(handle, + frames[0].bh); + if (err) + goto journal_error; + + memcpy ((char *) entries2, (char *) (entries + icount1), + icount2 * sizeof(struct dx_entry)); + dx_set_count (entries, icount1); + dx_set_count (entries2, icount2); + dx_set_limit (entries2, dx_node_limit(dir)); + + /* Which index block gets the new entry? */ + if (at - entries >= icount1) { + frame->at = at = at - entries - icount1 + entries2; + frame->entries = entries = entries2; + swap(frame->bh, bh2); + } + dx_insert_block (frames + 0, hash2, newblock); + dxtrace(dx_show_index ("node", frames[1].entries)); + dxtrace(dx_show_index ("node", + ((struct dx_node *) bh2->b_data)->entries)); + err = ext3_journal_dirty_metadata(handle, bh2); + if (err) + goto journal_error; + brelse (bh2); + } else { + dxtrace(printk("Creating second level index...\n")); + memcpy((char *) entries2, (char *) entries, + icount * sizeof(struct dx_entry)); + dx_set_limit(entries2, dx_node_limit(dir)); + + /* Set up root */ + dx_set_count(entries, 1); + dx_set_block(entries + 0, newblock); + ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1; + + /* Add new access path frame */ + frame = frames + 1; + frame->at = at = at - entries + entries2; + frame->entries = entries = entries2; + frame->bh = bh2; + err = ext3_journal_get_write_access(handle, + frame->bh); + if (err) + goto journal_error; + } + ext3_journal_dirty_metadata(handle, frames[0].bh); + } + de = do_split(handle, dir, &bh, frame, &hinfo, &err); + if (!de) + goto cleanup; + err = add_dirent_to_buf(handle, dentry, inode, de, bh); + bh = NULL; + goto cleanup; + +journal_error: + ext3_std_error(dir->i_sb, err); +cleanup: + if (bh) + brelse(bh); + dx_release(frames); + return err; +} +#endif + +/* + * ext3_delete_entry deletes a directory entry by merging it with the + * previous entry + */ +static int ext3_delete_entry (handle_t *handle, + struct inode * dir, + struct ext3_dir_entry_2 * de_del, + struct buffer_head * bh) +{ + struct ext3_dir_entry_2 * de, * pde; + int i; + + i = 0; + pde = NULL; + de = (struct ext3_dir_entry_2 *) bh->b_data; + while (i < bh->b_size) { + if (!ext3_check_dir_entry("ext3_delete_entry", dir, de, bh, i)) + return -EIO; + if (de == de_del) { + BUFFER_TRACE(bh, "get_write_access"); + ext3_journal_get_write_access(handle, bh); + if (pde) + pde->rec_len = + cpu_to_le16(le16_to_cpu(pde->rec_len) + + le16_to_cpu(de->rec_len)); + else + de->inode = 0; + dir->i_version++; + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, bh); + return 0; + } + i += le16_to_cpu(de->rec_len); + pde = de; + de = (struct ext3_dir_entry_2 *) + ((char *) de + le16_to_cpu(de->rec_len)); + } + return -ENOENT; +} + +/* + * ext3_mark_inode_dirty is somewhat expensive, so unlike ext2 we + * do not perform it in these functions. We perform it at the call site, + * if it is needed. + */ +static inline void ext3_inc_count(handle_t *handle, struct inode *inode) +{ + inc_nlink(inode); +} + +static inline void ext3_dec_count(handle_t *handle, struct inode *inode) +{ + drop_nlink(inode); +} + +static int ext3_add_nondir(handle_t *handle, + struct dentry *dentry, struct inode *inode) +{ + int err = ext3_add_entry(handle, dentry, inode); + if (!err) { + ext3_mark_inode_dirty(handle, inode); + d_instantiate(dentry, inode); + return 0; + } + ext3_dec_count(handle, inode); + iput(inode); + return err; +} + +/* + * By the time this is called, we already have created + * the directory cache entry for the new file, but it + * is so far negative - it has no inode. + * + * If the create succeeds, we fill in the inode information + * with d_instantiate(). + */ +static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, + struct nameidata *nd) +{ + handle_t *handle; + struct inode * inode; + int err, retries = 0; + +retry: + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + + 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + + inode = ext3_new_inode (handle, dir, mode); + err = PTR_ERR(inode); + if (!IS_ERR(inode)) { + inode->i_op = &ext3_file_inode_operations; + inode->i_fop = &ext3_file_operations; + ext3_set_aops(inode); + err = ext3_add_nondir(handle, dentry, inode); + } + ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; + return err; +} + +static int ext3_mknod (struct inode * dir, struct dentry *dentry, + int mode, dev_t rdev) +{ + handle_t *handle; + struct inode *inode; + int err, retries = 0; + + if (!new_valid_dev(rdev)) + return -EINVAL; + +retry: + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + + 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + + inode = ext3_new_inode (handle, dir, mode); + err = PTR_ERR(inode); + if (!IS_ERR(inode)) { + init_special_inode(inode, inode->i_mode, rdev); +#ifdef CONFIG_EXT3_FS_XATTR + inode->i_op = &ext3_special_inode_operations; +#endif + err = ext3_add_nondir(handle, dentry, inode); + } + ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; + return err; +} + +static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) +{ + handle_t *handle; + struct inode * inode; + struct buffer_head * dir_block; + struct ext3_dir_entry_2 * de; + int err, retries = 0; + + if (dir->i_nlink >= EXT3_LINK_MAX) + return -EMLINK; + +retry: + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + + 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + + inode = ext3_new_inode (handle, dir, S_IFDIR | mode); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_stop; + + inode->i_op = &ext3_dir_inode_operations; + inode->i_fop = &ext3_dir_operations; + inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize; + dir_block = ext3_bread (handle, inode, 0, 1, &err); + if (!dir_block) { + drop_nlink(inode); /* is this nlink == 0? */ + ext3_mark_inode_dirty(handle, inode); + iput (inode); + goto out_stop; + } + BUFFER_TRACE(dir_block, "get_write_access"); + ext3_journal_get_write_access(handle, dir_block); + de = (struct ext3_dir_entry_2 *) dir_block->b_data; + de->inode = cpu_to_le32(inode->i_ino); + de->name_len = 1; + de->rec_len = cpu_to_le16(EXT3_DIR_REC_LEN(de->name_len)); + strcpy (de->name, "."); + ext3_set_de_type(dir->i_sb, de, S_IFDIR); + de = (struct ext3_dir_entry_2 *) + ((char *) de + le16_to_cpu(de->rec_len)); + de->inode = cpu_to_le32(dir->i_ino); + de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT3_DIR_REC_LEN(1)); + de->name_len = 2; + strcpy (de->name, ".."); + ext3_set_de_type(dir->i_sb, de, S_IFDIR); + inode->i_nlink = 2; + BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, dir_block); + brelse (dir_block); + ext3_mark_inode_dirty(handle, inode); + err = ext3_add_entry (handle, dentry, inode); + if (err) { + inode->i_nlink = 0; + ext3_mark_inode_dirty(handle, inode); + iput (inode); + goto out_stop; + } + inc_nlink(dir); + ext3_update_dx_flag(dir); + ext3_mark_inode_dirty(handle, dir); + d_instantiate(dentry, inode); +out_stop: + ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; + return err; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir (struct inode * inode) +{ + unsigned long offset; + struct buffer_head * bh; + struct ext3_dir_entry_2 * de, * de1; + struct super_block * sb; + int err = 0; + + sb = inode->i_sb; + if (inode->i_size < EXT3_DIR_REC_LEN(1) + EXT3_DIR_REC_LEN(2) || + !(bh = ext3_bread (NULL, inode, 0, 0, &err))) { + if (err) + ext3_error(inode->i_sb, __FUNCTION__, + "error %d reading directory #%lu offset 0", + err, inode->i_ino); + else + ext3_warning(inode->i_sb, __FUNCTION__, + "bad directory (dir #%lu) - no data block", + inode->i_ino); + return 1; + } + de = (struct ext3_dir_entry_2 *) bh->b_data; + de1 = (struct ext3_dir_entry_2 *) + ((char *) de + le16_to_cpu(de->rec_len)); + if (le32_to_cpu(de->inode) != inode->i_ino || + !le32_to_cpu(de1->inode) || + strcmp (".", de->name) || + strcmp ("..", de1->name)) { + ext3_warning (inode->i_sb, "empty_dir", + "bad directory (dir #%lu) - no `.' or `..'", + inode->i_ino); + brelse (bh); + return 1; + } + offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len); + de = (struct ext3_dir_entry_2 *) + ((char *) de1 + le16_to_cpu(de1->rec_len)); + while (offset < inode->i_size ) { + if (!bh || + (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { + err = 0; + brelse (bh); + bh = ext3_bread (NULL, inode, + offset >> EXT3_BLOCK_SIZE_BITS(sb), 0, &err); + if (!bh) { + if (err) + ext3_error(sb, __FUNCTION__, + "error %d reading directory" + " #%lu offset %lu", + err, inode->i_ino, offset); + offset += sb->s_blocksize; + continue; + } + de = (struct ext3_dir_entry_2 *) bh->b_data; + } + if (!ext3_check_dir_entry("empty_dir", inode, de, bh, offset)) { + de = (struct ext3_dir_entry_2 *)(bh->b_data + + sb->s_blocksize); + offset = (offset | (sb->s_blocksize - 1)) + 1; + continue; + } + if (le32_to_cpu(de->inode)) { + brelse (bh); + return 0; + } + offset += le16_to_cpu(de->rec_len); + de = (struct ext3_dir_entry_2 *) + ((char *) de + le16_to_cpu(de->rec_len)); + } + brelse (bh); + return 1; +} + +/* ext3_orphan_add() links an unlinked or truncated inode into a list of + * such inodes, starting at the superblock, in case we crash before the + * file is closed/deleted, or in case the inode truncate spans multiple + * transactions and the last transaction is not recovered after a crash. + * + * At filesystem recovery time, we walk this list deleting unlinked + * inodes and truncating linked inodes in ext3_orphan_cleanup(). + */ +int ext3_orphan_add(handle_t *handle, struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + struct ext3_iloc iloc; + int err = 0, rc; + + lock_super(sb); + if (!list_empty(&EXT3_I(inode)->i_orphan)) + goto out_unlock; + + /* Orphan handling is only valid for files with data blocks + * being truncated, or files being unlinked. */ + + /* @@@ FIXME: Observation from aviro: + * I think I can trigger J_ASSERT in ext3_orphan_add(). We block + * here (on lock_super()), so race with ext3_link() which might bump + * ->i_nlink. For, say it, character device. Not a regular file, + * not a directory, not a symlink and ->i_nlink > 0. + */ + J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); + + BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get_write_access"); + err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); + if (err) + goto out_unlock; + + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + goto out_unlock; + + /* Insert this inode at the head of the on-disk orphan list... */ + NEXT_ORPHAN(inode) = le32_to_cpu(EXT3_SB(sb)->s_es->s_last_orphan); + EXT3_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); + err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + rc = ext3_mark_iloc_dirty(handle, inode, &iloc); + if (!err) + err = rc; + + /* Only add to the head of the in-memory list if all the + * previous operations succeeded. If the orphan_add is going to + * fail (possibly taking the journal offline), we can't risk + * leaving the inode on the orphan list: stray orphan-list + * entries can cause panics at unmount time. + * + * This is safe: on error we're going to ignore the orphan list + * anyway on the next recovery. */ + if (!err) + list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan); + + jbd_debug(4, "superblock will point to %lu\n", inode->i_ino); + jbd_debug(4, "orphan inode %lu will point to %d\n", + inode->i_ino, NEXT_ORPHAN(inode)); +out_unlock: + unlock_super(sb); + ext3_std_error(inode->i_sb, err); + return err; +} + +/* + * ext3_orphan_del() removes an unlinked or truncated inode from the list + * of such inodes stored on disk, because it is finally being cleaned up. + */ +int ext3_orphan_del(handle_t *handle, struct inode *inode) +{ + struct list_head *prev; + struct ext3_inode_info *ei = EXT3_I(inode); + struct ext3_sb_info *sbi; + unsigned long ino_next; + struct ext3_iloc iloc; + int err = 0; + + lock_super(inode->i_sb); + if (list_empty(&ei->i_orphan)) { + unlock_super(inode->i_sb); + return 0; + } + + ino_next = NEXT_ORPHAN(inode); + prev = ei->i_orphan.prev; + sbi = EXT3_SB(inode->i_sb); + + jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino); + + list_del_init(&ei->i_orphan); + + /* If we're on an error path, we may not have a valid + * transaction handle with which to update the orphan list on + * disk, but we still need to remove the inode from the linked + * list in memory. */ + if (!handle) + goto out; + + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + goto out_err; + + if (prev == &sbi->s_orphan) { + jbd_debug(4, "superblock will point to %lu\n", ino_next); + BUFFER_TRACE(sbi->s_sbh, "get_write_access"); + err = ext3_journal_get_write_access(handle, sbi->s_sbh); + if (err) + goto out_brelse; + sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); + err = ext3_journal_dirty_metadata(handle, sbi->s_sbh); + } else { + struct ext3_iloc iloc2; + struct inode *i_prev = + &list_entry(prev, struct ext3_inode_info, i_orphan)->vfs_inode; + + jbd_debug(4, "orphan inode %lu will point to %lu\n", + i_prev->i_ino, ino_next); + err = ext3_reserve_inode_write(handle, i_prev, &iloc2); + if (err) + goto out_brelse; + NEXT_ORPHAN(i_prev) = ino_next; + err = ext3_mark_iloc_dirty(handle, i_prev, &iloc2); + } + if (err) + goto out_brelse; + NEXT_ORPHAN(inode) = 0; + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + +out_err: + ext3_std_error(inode->i_sb, err); +out: + unlock_super(inode->i_sb); + return err; + +out_brelse: + brelse(iloc.bh); + goto out_err; +} + +static int ext3_rmdir (struct inode * dir, struct dentry *dentry) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext3_dir_entry_2 * de; + handle_t *handle; + + /* Initialize quotas before so that eventual writes go in + * separate transaction */ + DQUOT_INIT(dentry->d_inode); + handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + retval = -ENOENT; + bh = ext3_find_entry (dentry, &de); + if (!bh) + goto end_rmdir; + + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + + inode = dentry->d_inode; + + retval = -EIO; + if (le32_to_cpu(de->inode) != inode->i_ino) + goto end_rmdir; + + retval = -ENOTEMPTY; + if (!empty_dir (inode)) + goto end_rmdir; + + retval = ext3_delete_entry(handle, dir, de, bh); + if (retval) + goto end_rmdir; + if (inode->i_nlink != 2) + ext3_warning (inode->i_sb, "ext3_rmdir", + "empty directory has nlink!=2 (%d)", + inode->i_nlink); + inode->i_version++; + clear_nlink(inode); + /* There's no need to set i_disksize: the fact that i_nlink is + * zero will ensure that the right thing happens during any + * recovery. */ + inode->i_size = 0; + ext3_orphan_add(handle, inode); + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; + ext3_mark_inode_dirty(handle, inode); + drop_nlink(dir); + ext3_update_dx_flag(dir); + ext3_mark_inode_dirty(handle, dir); + +end_rmdir: + ext3_journal_stop(handle); + brelse (bh); + return retval; +} + +static int ext3_unlink(struct inode * dir, struct dentry *dentry) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext3_dir_entry_2 * de; + handle_t *handle; + + /* Initialize quotas before so that eventual writes go + * in separate transaction */ + DQUOT_INIT(dentry->d_inode); + handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + + retval = -ENOENT; + bh = ext3_find_entry (dentry, &de); + if (!bh) + goto end_unlink; + + inode = dentry->d_inode; + + retval = -EIO; + if (le32_to_cpu(de->inode) != inode->i_ino) + goto end_unlink; + + if (!inode->i_nlink) { + ext3_warning (inode->i_sb, "ext3_unlink", + "Deleting nonexistent file (%lu), %d", + inode->i_ino, inode->i_nlink); + inode->i_nlink = 1; + } + retval = ext3_delete_entry(handle, dir, de, bh); + if (retval) + goto end_unlink; + dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; + ext3_update_dx_flag(dir); + ext3_mark_inode_dirty(handle, dir); + drop_nlink(inode); + if (!inode->i_nlink) + ext3_orphan_add(handle, inode); + inode->i_ctime = dir->i_ctime; + ext3_mark_inode_dirty(handle, inode); + retval = 0; + +end_unlink: + ext3_journal_stop(handle); + brelse (bh); + return retval; +} + +static int ext3_symlink (struct inode * dir, + struct dentry *dentry, const char * symname) +{ + handle_t *handle; + struct inode * inode; + int l, err, retries = 0; + + l = strlen(symname)+1; + if (l > dir->i_sb->s_blocksize) + return -ENAMETOOLONG; + +retry: + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 + + 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + + inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_stop; + + if (l > sizeof (EXT3_I(inode)->i_data)) { + inode->i_op = &ext3_symlink_inode_operations; + ext3_set_aops(inode); + /* + * page_symlink() calls into ext3_prepare/commit_write. + * We have a transaction open. All is sweetness. It also sets + * i_size in generic_commit_write(). + */ + err = __page_symlink(inode, symname, l, + mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); + if (err) { + ext3_dec_count(handle, inode); + ext3_mark_inode_dirty(handle, inode); + iput (inode); + goto out_stop; + } + } else { + inode->i_op = &ext3_fast_symlink_inode_operations; + memcpy((char*)&EXT3_I(inode)->i_data,symname,l); + inode->i_size = l-1; + } + EXT3_I(inode)->i_disksize = inode->i_size; + err = ext3_add_nondir(handle, dentry, inode); +out_stop: + ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; + return err; +} + +static int ext3_link (struct dentry * old_dentry, + struct inode * dir, struct dentry *dentry) +{ + handle_t *handle; + struct inode *inode = old_dentry->d_inode; + int err, retries = 0; + + if (inode->i_nlink >= EXT3_LINK_MAX) + return -EMLINK; + +retry: + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + + EXT3_INDEX_EXTRA_TRANS_BLOCKS); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + + inode->i_ctime = CURRENT_TIME_SEC; + ext3_inc_count(handle, inode); + atomic_inc(&inode->i_count); + + err = ext3_add_nondir(handle, dentry, inode); + ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; + return err; +} + +#define PARENT_INO(buffer) \ + ((struct ext3_dir_entry_2 *) ((char *) buffer + \ + le16_to_cpu(((struct ext3_dir_entry_2 *) buffer)->rec_len)))->inode + +/* + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, + struct inode * new_dir,struct dentry *new_dentry) +{ + handle_t *handle; + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct ext3_dir_entry_2 * old_de, * new_de; + int retval; + + old_bh = new_bh = dir_bh = NULL; + + /* Initialize quotas before so that eventual writes go + * in separate transaction */ + if (new_dentry->d_inode) + DQUOT_INIT(new_dentry->d_inode); + handle = ext3_journal_start(old_dir, 2 * + EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) + + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) + handle->h_sync = 1; + + old_bh = ext3_find_entry (old_dentry, &old_de); + /* + * Check for inode number is _not_ due to possible IO errors. + * We might rmdir the source, keep it as pwd of some process + * and merrily kill the link to whatever was created under the + * same name. Goodbye sticky bit ;-< + */ + old_inode = old_dentry->d_inode; + retval = -ENOENT; + if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino) + goto end_rename; + + new_inode = new_dentry->d_inode; + new_bh = ext3_find_entry (new_dentry, &new_de); + if (new_bh) { + if (!new_inode) { + brelse (new_bh); + new_bh = NULL; + } + } + if (S_ISDIR(old_inode->i_mode)) { + if (new_inode) { + retval = -ENOTEMPTY; + if (!empty_dir (new_inode)) + goto end_rename; + } + retval = -EIO; + dir_bh = ext3_bread (handle, old_inode, 0, 0, &retval); + if (!dir_bh) + goto end_rename; + if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino) + goto end_rename; + retval = -EMLINK; + if (!new_inode && new_dir!=old_dir && + new_dir->i_nlink >= EXT3_LINK_MAX) + goto end_rename; + } + if (!new_bh) { + retval = ext3_add_entry (handle, new_dentry, old_inode); + if (retval) + goto end_rename; + } else { + BUFFER_TRACE(new_bh, "get write access"); + ext3_journal_get_write_access(handle, new_bh); + new_de->inode = cpu_to_le32(old_inode->i_ino); + if (EXT3_HAS_INCOMPAT_FEATURE(new_dir->i_sb, + EXT3_FEATURE_INCOMPAT_FILETYPE)) + new_de->file_type = old_de->file_type; + new_dir->i_version++; + BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, new_bh); + brelse(new_bh); + new_bh = NULL; + } + + /* + * Like most other Unix systems, set the ctime for inodes on a + * rename. + */ + old_inode->i_ctime = CURRENT_TIME_SEC; + ext3_mark_inode_dirty(handle, old_inode); + + /* + * ok, that's it + */ + if (le32_to_cpu(old_de->inode) != old_inode->i_ino || + old_de->name_len != old_dentry->d_name.len || + strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) || + (retval = ext3_delete_entry(handle, old_dir, + old_de, old_bh)) == -ENOENT) { + /* old_de could have moved from under us during htree split, so + * make sure that we are deleting the right entry. We might + * also be pointing to a stale entry in the unused part of + * old_bh so just checking inum and the name isn't enough. */ + struct buffer_head *old_bh2; + struct ext3_dir_entry_2 *old_de2; + + old_bh2 = ext3_find_entry(old_dentry, &old_de2); + if (old_bh2) { + retval = ext3_delete_entry(handle, old_dir, + old_de2, old_bh2); + brelse(old_bh2); + } + } + if (retval) { + ext3_warning(old_dir->i_sb, "ext3_rename", + "Deleting old file (%lu), %d, error=%d", + old_dir->i_ino, old_dir->i_nlink, retval); + } + + if (new_inode) { + drop_nlink(new_inode); + new_inode->i_ctime = CURRENT_TIME_SEC; + } + old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; + ext3_update_dx_flag(old_dir); + if (dir_bh) { + BUFFER_TRACE(dir_bh, "get_write_access"); + ext3_journal_get_write_access(handle, dir_bh); + PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino); + BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, dir_bh); + drop_nlink(old_dir); + if (new_inode) { + drop_nlink(new_inode); + } else { + inc_nlink(new_dir); + ext3_update_dx_flag(new_dir); + ext3_mark_inode_dirty(handle, new_dir); + } + } + ext3_mark_inode_dirty(handle, old_dir); + if (new_inode) { + ext3_mark_inode_dirty(handle, new_inode); + if (!new_inode->i_nlink) + ext3_orphan_add(handle, new_inode); + } + retval = 0; + +end_rename: + brelse (dir_bh); + brelse (old_bh); + brelse (new_bh); + ext3_journal_stop(handle); + return retval; +} + +/* + * directories can handle most operations... + */ +struct inode_operations ext3_dir_inode_operations = { + .create = ext3_create, + .lookup = ext3_lookup, + .link = ext3_link, + .unlink = ext3_unlink, + .symlink = ext3_symlink, + .mkdir = ext3_mkdir, + .rmdir = ext3_rmdir, + .mknod = ext3_mknod, + .rename = ext3_rename, + .setattr = ext3_setattr, +#ifdef CONFIG_EXT3_FS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ext3_listxattr, + .removexattr = generic_removexattr, +#endif + .permission = ext3_permission, +}; + +struct inode_operations ext3_special_inode_operations = { + .setattr = ext3_setattr, +#ifdef CONFIG_EXT3_FS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ext3_listxattr, + .removexattr = generic_removexattr, +#endif + .permission = ext3_permission, +}; diff --git a/fs/ext4/namei.h b/fs/ext4/namei.h new file mode 100644 index 000000000000..f2ce2b0065c9 --- /dev/null +++ b/fs/ext4/namei.h @@ -0,0 +1,8 @@ +/* linux/fs/ext3/namei.h + * + * Copyright (C) 2005 Simtec Electronics + * Ben Dooks + * +*/ + +extern struct dentry *ext3_get_parent(struct dentry *child); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c new file mode 100644 index 000000000000..b73cba12f79c --- /dev/null +++ b/fs/ext4/resize.c @@ -0,0 +1,1042 @@ +/* + * linux/fs/ext3/resize.c + * + * Support for resizing an ext3 filesystem while it is mounted. + * + * Copyright (C) 2001, 2002 Andreas Dilger + * + * This could probably be made into a module, because it is not often in use. + */ + + +#define EXT3FS_DEBUG + +#include +#include +#include + +#include +#include + + +#define outside(b, first, last) ((b) < (first) || (b) >= (last)) +#define inside(b, first, last) ((b) >= (first) && (b) < (last)) + +static int verify_group_input(struct super_block *sb, + struct ext3_new_group_data *input) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext3_super_block *es = sbi->s_es; + ext3_fsblk_t start = le32_to_cpu(es->s_blocks_count); + ext3_fsblk_t end = start + input->blocks_count; + unsigned group = input->group; + ext3_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; + unsigned overhead = ext3_bg_has_super(sb, group) ? + (1 + ext3_bg_num_gdb(sb, group) + + le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; + ext3_fsblk_t metaend = start + overhead; + struct buffer_head *bh = NULL; + ext3_grpblk_t free_blocks_count; + int err = -EINVAL; + + input->free_blocks_count = free_blocks_count = + input->blocks_count - 2 - overhead - sbi->s_itb_per_group; + + if (test_opt(sb, DEBUG)) + printk(KERN_DEBUG "EXT3-fs: adding %s group %u: %u blocks " + "(%d free, %u reserved)\n", + ext3_bg_has_super(sb, input->group) ? "normal" : + "no-super", input->group, input->blocks_count, + free_blocks_count, input->reserved_blocks); + + if (group != sbi->s_groups_count) + ext3_warning(sb, __FUNCTION__, + "Cannot add at group %u (only %lu groups)", + input->group, sbi->s_groups_count); + else if ((start - le32_to_cpu(es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb)) + ext3_warning(sb, __FUNCTION__, "Last group not full"); + else if (input->reserved_blocks > input->blocks_count / 5) + ext3_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)", + input->reserved_blocks); + else if (free_blocks_count < 0) + ext3_warning(sb, __FUNCTION__, "Bad blocks count %u", + input->blocks_count); + else if (!(bh = sb_bread(sb, end - 1))) + ext3_warning(sb, __FUNCTION__, + "Cannot read last block ("E3FSBLK")", + end - 1); + else if (outside(input->block_bitmap, start, end)) + ext3_warning(sb, __FUNCTION__, + "Block bitmap not in group (block %u)", + input->block_bitmap); + else if (outside(input->inode_bitmap, start, end)) + ext3_warning(sb, __FUNCTION__, + "Inode bitmap not in group (block %u)", + input->inode_bitmap); + else if (outside(input->inode_table, start, end) || + outside(itend - 1, start, end)) + ext3_warning(sb, __FUNCTION__, + "Inode table not in group (blocks %u-"E3FSBLK")", + input->inode_table, itend - 1); + else if (input->inode_bitmap == input->block_bitmap) + ext3_warning(sb, __FUNCTION__, + "Block bitmap same as inode bitmap (%u)", + input->block_bitmap); + else if (inside(input->block_bitmap, input->inode_table, itend)) + ext3_warning(sb, __FUNCTION__, + "Block bitmap (%u) in inode table (%u-"E3FSBLK")", + input->block_bitmap, input->inode_table, itend-1); + else if (inside(input->inode_bitmap, input->inode_table, itend)) + ext3_warning(sb, __FUNCTION__, + "Inode bitmap (%u) in inode table (%u-"E3FSBLK")", + input->inode_bitmap, input->inode_table, itend-1); + else if (inside(input->block_bitmap, start, metaend)) + ext3_warning(sb, __FUNCTION__, + "Block bitmap (%u) in GDT table" + " ("E3FSBLK"-"E3FSBLK")", + input->block_bitmap, start, metaend - 1); + else if (inside(input->inode_bitmap, start, metaend)) + ext3_warning(sb, __FUNCTION__, + "Inode bitmap (%u) in GDT table" + " ("E3FSBLK"-"E3FSBLK")", + input->inode_bitmap, start, metaend - 1); + else if (inside(input->inode_table, start, metaend) || + inside(itend - 1, start, metaend)) + ext3_warning(sb, __FUNCTION__, + "Inode table (%u-"E3FSBLK") overlaps" + "GDT table ("E3FSBLK"-"E3FSBLK")", + input->inode_table, itend - 1, start, metaend - 1); + else + err = 0; + brelse(bh); + + return err; +} + +static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, + ext3_fsblk_t blk) +{ + struct buffer_head *bh; + int err; + + bh = sb_getblk(sb, blk); + if (!bh) + return ERR_PTR(-EIO); + if ((err = ext3_journal_get_write_access(handle, bh))) { + brelse(bh); + bh = ERR_PTR(err); + } else { + lock_buffer(bh); + memset(bh->b_data, 0, sb->s_blocksize); + set_buffer_uptodate(bh); + unlock_buffer(bh); + } + + return bh; +} + +/* + * To avoid calling the atomic setbit hundreds or thousands of times, we only + * need to use it within a single byte (to ensure we get endianness right). + * We can use memset for the rest of the bitmap as there are no other users. + */ +static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap) +{ + int i; + + if (start_bit >= end_bit) + return; + + ext3_debug("mark end bits +%d through +%d used\n", start_bit, end_bit); + for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) + ext3_set_bit(i, bitmap); + if (i < end_bit) + memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); +} + +/* + * Set up the block and inode bitmaps, and the inode table for the new group. + * This doesn't need to be part of the main transaction, since we are only + * changing blocks outside the actual filesystem. We still do journaling to + * ensure the recovery is correct in case of a failure just after resize. + * If any part of this fails, we simply abort the resize. + */ +static int setup_new_group_blocks(struct super_block *sb, + struct ext3_new_group_data *input) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + ext3_fsblk_t start = ext3_group_first_block_no(sb, input->group); + int reserved_gdb = ext3_bg_has_super(sb, input->group) ? + le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0; + unsigned long gdblocks = ext3_bg_num_gdb(sb, input->group); + struct buffer_head *bh; + handle_t *handle; + ext3_fsblk_t block; + ext3_grpblk_t bit; + int i; + int err = 0, err2; + + handle = ext3_journal_start_sb(sb, reserved_gdb + gdblocks + + 2 + sbi->s_itb_per_group); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + lock_super(sb); + if (input->group != sbi->s_groups_count) { + err = -EBUSY; + goto exit_journal; + } + + if (IS_ERR(bh = bclean(handle, sb, input->block_bitmap))) { + err = PTR_ERR(bh); + goto exit_journal; + } + + if (ext3_bg_has_super(sb, input->group)) { + ext3_debug("mark backup superblock %#04lx (+0)\n", start); + ext3_set_bit(0, bh->b_data); + } + + /* Copy all of the GDT blocks into the backup in this group */ + for (i = 0, bit = 1, block = start + 1; + i < gdblocks; i++, block++, bit++) { + struct buffer_head *gdb; + + ext3_debug("update backup group %#04lx (+%d)\n", block, bit); + + gdb = sb_getblk(sb, block); + if (!gdb) { + err = -EIO; + goto exit_bh; + } + if ((err = ext3_journal_get_write_access(handle, gdb))) { + brelse(gdb); + goto exit_bh; + } + lock_buffer(bh); + memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, bh->b_size); + set_buffer_uptodate(gdb); + unlock_buffer(bh); + ext3_journal_dirty_metadata(handle, gdb); + ext3_set_bit(bit, bh->b_data); + brelse(gdb); + } + + /* Zero out all of the reserved backup group descriptor table blocks */ + for (i = 0, bit = gdblocks + 1, block = start + bit; + i < reserved_gdb; i++, block++, bit++) { + struct buffer_head *gdb; + + ext3_debug("clear reserved block %#04lx (+%d)\n", block, bit); + + if (IS_ERR(gdb = bclean(handle, sb, block))) { + err = PTR_ERR(bh); + goto exit_bh; + } + ext3_journal_dirty_metadata(handle, gdb); + ext3_set_bit(bit, bh->b_data); + brelse(gdb); + } + ext3_debug("mark block bitmap %#04x (+%ld)\n", input->block_bitmap, + input->block_bitmap - start); + ext3_set_bit(input->block_bitmap - start, bh->b_data); + ext3_debug("mark inode bitmap %#04x (+%ld)\n", input->inode_bitmap, + input->inode_bitmap - start); + ext3_set_bit(input->inode_bitmap - start, bh->b_data); + + /* Zero out all of the inode table blocks */ + for (i = 0, block = input->inode_table, bit = block - start; + i < sbi->s_itb_per_group; i++, bit++, block++) { + struct buffer_head *it; + + ext3_debug("clear inode block %#04lx (+%d)\n", block, bit); + if (IS_ERR(it = bclean(handle, sb, block))) { + err = PTR_ERR(it); + goto exit_bh; + } + ext3_journal_dirty_metadata(handle, it); + brelse(it); + ext3_set_bit(bit, bh->b_data); + } + mark_bitmap_end(input->blocks_count, EXT3_BLOCKS_PER_GROUP(sb), + bh->b_data); + ext3_journal_dirty_metadata(handle, bh); + brelse(bh); + + /* Mark unused entries in inode bitmap used */ + ext3_debug("clear inode bitmap %#04x (+%ld)\n", + input->inode_bitmap, input->inode_bitmap - start); + if (IS_ERR(bh = bclean(handle, sb, input->inode_bitmap))) { + err = PTR_ERR(bh); + goto exit_journal; + } + + mark_bitmap_end(EXT3_INODES_PER_GROUP(sb), EXT3_BLOCKS_PER_GROUP(sb), + bh->b_data); + ext3_journal_dirty_metadata(handle, bh); +exit_bh: + brelse(bh); + +exit_journal: + unlock_super(sb); + if ((err2 = ext3_journal_stop(handle)) && !err) + err = err2; + + return err; +} + +/* + * Iterate through the groups which hold BACKUP superblock/GDT copies in an + * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before + * calling this for the first time. In a sparse filesystem it will be the + * 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, ... + */ +static unsigned ext3_list_backups(struct super_block *sb, unsigned *three, + unsigned *five, unsigned *seven) +{ + unsigned *min = three; + int mult = 3; + unsigned ret; + + if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, + EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { + ret = *min; + *min += 1; + return ret; + } + + if (*five < *min) { + min = five; + mult = 5; + } + if (*seven < *min) { + min = seven; + mult = 7; + } + + ret = *min; + *min *= mult; + + return ret; +} + +/* + * Check that all of the backup GDT blocks are held in the primary GDT block. + * It is assumed that they are stored in group order. Returns the number of + * groups in current filesystem that have BACKUPS, or -ve error code. + */ +static int verify_reserved_gdb(struct super_block *sb, + struct buffer_head *primary) +{ + const ext3_fsblk_t blk = primary->b_blocknr; + const unsigned long end = EXT3_SB(sb)->s_groups_count; + unsigned three = 1; + unsigned five = 5; + unsigned seven = 7; + unsigned grp; + __le32 *p = (__le32 *)primary->b_data; + int gdbackups = 0; + + while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) { + if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){ + ext3_warning(sb, __FUNCTION__, + "reserved GDT "E3FSBLK + " missing grp %d ("E3FSBLK")", + blk, grp, + grp * EXT3_BLOCKS_PER_GROUP(sb) + blk); + return -EINVAL; + } + if (++gdbackups > EXT3_ADDR_PER_BLOCK(sb)) + return -EFBIG; + } + + return gdbackups; +} + +/* + * Called when we need to bring a reserved group descriptor table block into + * use from the resize inode. The primary copy of the new GDT block currently + * is an indirect block (under the double indirect block in the resize inode). + * The new backup GDT blocks will be stored as leaf blocks in this indirect + * block, in group order. Even though we know all the block numbers we need, + * we check to ensure that the resize inode has actually reserved these blocks. + * + * Don't need to update the block bitmaps because the blocks are still in use. + * + * We get all of the error cases out of the way, so that we are sure to not + * fail once we start modifying the data on disk, because JBD has no rollback. + */ +static int add_new_gdb(handle_t *handle, struct inode *inode, + struct ext3_new_group_data *input, + struct buffer_head **primary) +{ + struct super_block *sb = inode->i_sb; + struct ext3_super_block *es = EXT3_SB(sb)->s_es; + unsigned long gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); + ext3_fsblk_t gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num; + struct buffer_head **o_group_desc, **n_group_desc; + struct buffer_head *dind; + int gdbackups; + struct ext3_iloc iloc; + __le32 *data; + int err; + + if (test_opt(sb, DEBUG)) + printk(KERN_DEBUG + "EXT3-fs: ext3_add_new_gdb: adding group block %lu\n", + gdb_num); + + /* + * If we are not using the primary superblock/GDT copy don't resize, + * because the user tools have no way of handling this. Probably a + * bad time to do it anyways. + */ + if (EXT3_SB(sb)->s_sbh->b_blocknr != + le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) { + ext3_warning(sb, __FUNCTION__, + "won't resize using backup superblock at %llu", + (unsigned long long)EXT3_SB(sb)->s_sbh->b_blocknr); + return -EPERM; + } + + *primary = sb_bread(sb, gdblock); + if (!*primary) + return -EIO; + + if ((gdbackups = verify_reserved_gdb(sb, *primary)) < 0) { + err = gdbackups; + goto exit_bh; + } + + data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; + dind = sb_bread(sb, le32_to_cpu(*data)); + if (!dind) { + err = -EIO; + goto exit_bh; + } + + data = (__le32 *)dind->b_data; + if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) { + ext3_warning(sb, __FUNCTION__, + "new group %u GDT block "E3FSBLK" not reserved", + input->group, gdblock); + err = -EINVAL; + goto exit_dind; + } + + if ((err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh))) + goto exit_dind; + + if ((err = ext3_journal_get_write_access(handle, *primary))) + goto exit_sbh; + + if ((err = ext3_journal_get_write_access(handle, dind))) + goto exit_primary; + + /* ext3_reserve_inode_write() gets a reference on the iloc */ + if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) + goto exit_dindj; + + n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *), + GFP_KERNEL); + if (!n_group_desc) { + err = -ENOMEM; + ext3_warning (sb, __FUNCTION__, + "not enough memory for %lu groups", gdb_num + 1); + goto exit_inode; + } + + /* + * Finally, we have all of the possible failures behind us... + * + * Remove new GDT block from inode double-indirect block and clear out + * the new GDT block for use (which also "frees" the backup GDT blocks + * from the reserved inode). We don't need to change the bitmaps for + * these blocks, because they are marked as in-use from being in the + * reserved inode, and will become GDT blocks (primary and backup). + */ + data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)] = 0; + ext3_journal_dirty_metadata(handle, dind); + brelse(dind); + inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9; + ext3_mark_iloc_dirty(handle, inode, &iloc); + memset((*primary)->b_data, 0, sb->s_blocksize); + ext3_journal_dirty_metadata(handle, *primary); + + o_group_desc = EXT3_SB(sb)->s_group_desc; + memcpy(n_group_desc, o_group_desc, + EXT3_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); + n_group_desc[gdb_num] = *primary; + EXT3_SB(sb)->s_group_desc = n_group_desc; + EXT3_SB(sb)->s_gdb_count++; + kfree(o_group_desc); + + es->s_reserved_gdt_blocks = + cpu_to_le16(le16_to_cpu(es->s_reserved_gdt_blocks) - 1); + ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + + return 0; + +exit_inode: + //ext3_journal_release_buffer(handle, iloc.bh); + brelse(iloc.bh); +exit_dindj: + //ext3_journal_release_buffer(handle, dind); +exit_primary: + //ext3_journal_release_buffer(handle, *primary); +exit_sbh: + //ext3_journal_release_buffer(handle, *primary); +exit_dind: + brelse(dind); +exit_bh: + brelse(*primary); + + ext3_debug("leaving with error %d\n", err); + return err; +} + +/* + * Called when we are adding a new group which has a backup copy of each of + * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks. + * We need to add these reserved backup GDT blocks to the resize inode, so + * that they are kept for future resizing and not allocated to files. + * + * Each reserved backup GDT block will go into a different indirect block. + * The indirect blocks are actually the primary reserved GDT blocks, + * so we know in advance what their block numbers are. We only get the + * double-indirect block to verify it is pointing to the primary reserved + * GDT blocks so we don't overwrite a data block by accident. The reserved + * backup GDT blocks are stored in their reserved primary GDT block. + */ +static int reserve_backup_gdb(handle_t *handle, struct inode *inode, + struct ext3_new_group_data *input) +{ + struct super_block *sb = inode->i_sb; + int reserved_gdb =le16_to_cpu(EXT3_SB(sb)->s_es->s_reserved_gdt_blocks); + struct buffer_head **primary; + struct buffer_head *dind; + struct ext3_iloc iloc; + ext3_fsblk_t blk; + __le32 *data, *end; + int gdbackups = 0; + int res, i; + int err; + + primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_KERNEL); + if (!primary) + return -ENOMEM; + + data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; + dind = sb_bread(sb, le32_to_cpu(*data)); + if (!dind) { + err = -EIO; + goto exit_free; + } + + blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count; + data = (__le32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count; + end = (__le32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb); + + /* Get each reserved primary GDT block and verify it holds backups */ + for (res = 0; res < reserved_gdb; res++, blk++) { + if (le32_to_cpu(*data) != blk) { + ext3_warning(sb, __FUNCTION__, + "reserved block "E3FSBLK + " not at offset %ld", + blk, + (long)(data - (__le32 *)dind->b_data)); + err = -EINVAL; + goto exit_bh; + } + primary[res] = sb_bread(sb, blk); + if (!primary[res]) { + err = -EIO; + goto exit_bh; + } + if ((gdbackups = verify_reserved_gdb(sb, primary[res])) < 0) { + brelse(primary[res]); + err = gdbackups; + goto exit_bh; + } + if (++data >= end) + data = (__le32 *)dind->b_data; + } + + for (i = 0; i < reserved_gdb; i++) { + if ((err = ext3_journal_get_write_access(handle, primary[i]))) { + /* + int j; + for (j = 0; j < i; j++) + ext3_journal_release_buffer(handle, primary[j]); + */ + goto exit_bh; + } + } + + if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) + goto exit_bh; + + /* + * Finally we can add each of the reserved backup GDT blocks from + * the new group to its reserved primary GDT block. + */ + blk = input->group * EXT3_BLOCKS_PER_GROUP(sb); + for (i = 0; i < reserved_gdb; i++) { + int err2; + data = (__le32 *)primary[i]->b_data; + /* printk("reserving backup %lu[%u] = %lu\n", + primary[i]->b_blocknr, gdbackups, + blk + primary[i]->b_blocknr); */ + data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr); + err2 = ext3_journal_dirty_metadata(handle, primary[i]); + if (!err) + err = err2; + } + inode->i_blocks += reserved_gdb * sb->s_blocksize >> 9; + ext3_mark_iloc_dirty(handle, inode, &iloc); + +exit_bh: + while (--res >= 0) + brelse(primary[res]); + brelse(dind); + +exit_free: + kfree(primary); + + return err; +} + +/* + * Update the backup copies of the ext3 metadata. These don't need to be part + * of the main resize transaction, because e2fsck will re-write them if there + * is a problem (basically only OOM will cause a problem). However, we + * _should_ update the backups if possible, in case the primary gets trashed + * for some reason and we need to run e2fsck from a backup superblock. The + * important part is that the new block and inode counts are in the backup + * superblocks, and the location of the new group metadata in the GDT backups. + * + * We do not need lock_super() for this, because these blocks are not + * otherwise touched by the filesystem code when it is mounted. We don't + * need to worry about last changing from sbi->s_groups_count, because the + * worst that can happen is that we do not copy the full number of backups + * at this time. The resize which changed s_groups_count will backup again. + */ +static void update_backups(struct super_block *sb, + int blk_off, char *data, int size) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + const unsigned long last = sbi->s_groups_count; + const int bpg = EXT3_BLOCKS_PER_GROUP(sb); + unsigned three = 1; + unsigned five = 5; + unsigned seven = 7; + unsigned group; + int rest = sb->s_blocksize - size; + handle_t *handle; + int err = 0, err2; + + handle = ext3_journal_start_sb(sb, EXT3_MAX_TRANS_DATA); + if (IS_ERR(handle)) { + group = 1; + err = PTR_ERR(handle); + goto exit_err; + } + + while ((group = ext3_list_backups(sb, &three, &five, &seven)) < last) { + struct buffer_head *bh; + + /* Out of journal space, and can't get more - abort - so sad */ + if (handle->h_buffer_credits == 0 && + ext3_journal_extend(handle, EXT3_MAX_TRANS_DATA) && + (err = ext3_journal_restart(handle, EXT3_MAX_TRANS_DATA))) + break; + + bh = sb_getblk(sb, group * bpg + blk_off); + if (!bh) { + err = -EIO; + break; + } + ext3_debug("update metadata backup %#04lx\n", + (unsigned long)bh->b_blocknr); + if ((err = ext3_journal_get_write_access(handle, bh))) + break; + lock_buffer(bh); + memcpy(bh->b_data, data, size); + if (rest) + memset(bh->b_data + size, 0, rest); + set_buffer_uptodate(bh); + unlock_buffer(bh); + ext3_journal_dirty_metadata(handle, bh); + brelse(bh); + } + if ((err2 = ext3_journal_stop(handle)) && !err) + err = err2; + + /* + * Ugh! Need to have e2fsck write the backup copies. It is too + * late to revert the resize, we shouldn't fail just because of + * the backup copies (they are only needed in case of corruption). + * + * However, if we got here we have a journal problem too, so we + * can't really start a transaction to mark the superblock. + * Chicken out and just set the flag on the hope it will be written + * to disk, and if not - we will simply wait until next fsck. + */ +exit_err: + if (err) { + ext3_warning(sb, __FUNCTION__, + "can't update backup for group %d (err %d), " + "forcing fsck on next reboot", group, err); + sbi->s_mount_state &= ~EXT3_VALID_FS; + sbi->s_es->s_state &= cpu_to_le16(~EXT3_VALID_FS); + mark_buffer_dirty(sbi->s_sbh); + } +} + +/* Add group descriptor data to an existing or new group descriptor block. + * Ensure we handle all possible error conditions _before_ we start modifying + * the filesystem, because we cannot abort the transaction and not have it + * write the data to disk. + * + * If we are on a GDT block boundary, we need to get the reserved GDT block. + * Otherwise, we may need to add backup GDT blocks for a sparse group. + * + * We only need to hold the superblock lock while we are actually adding + * in the new group's counts to the superblock. Prior to that we have + * not really "added" the group at all. We re-check that we are still + * adding in the last group in case things have changed since verifying. + */ +int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext3_super_block *es = sbi->s_es; + int reserved_gdb = ext3_bg_has_super(sb, input->group) ? + le16_to_cpu(es->s_reserved_gdt_blocks) : 0; + struct buffer_head *primary = NULL; + struct ext3_group_desc *gdp; + struct inode *inode = NULL; + handle_t *handle; + int gdb_off, gdb_num; + int err, err2; + + gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); + gdb_off = input->group % EXT3_DESC_PER_BLOCK(sb); + + if (gdb_off == 0 && !EXT3_HAS_RO_COMPAT_FEATURE(sb, + EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { + ext3_warning(sb, __FUNCTION__, + "Can't resize non-sparse filesystem further"); + return -EPERM; + } + + if (le32_to_cpu(es->s_blocks_count) + input->blocks_count < + le32_to_cpu(es->s_blocks_count)) { + ext3_warning(sb, __FUNCTION__, "blocks_count overflow\n"); + return -EINVAL; + } + + if (le32_to_cpu(es->s_inodes_count) + EXT3_INODES_PER_GROUP(sb) < + le32_to_cpu(es->s_inodes_count)) { + ext3_warning(sb, __FUNCTION__, "inodes_count overflow\n"); + return -EINVAL; + } + + if (reserved_gdb || gdb_off == 0) { + if (!EXT3_HAS_COMPAT_FEATURE(sb, + EXT3_FEATURE_COMPAT_RESIZE_INODE)){ + ext3_warning(sb, __FUNCTION__, + "No reserved GDT blocks, can't resize"); + return -EPERM; + } + inode = iget(sb, EXT3_RESIZE_INO); + if (!inode || is_bad_inode(inode)) { + ext3_warning(sb, __FUNCTION__, + "Error opening resize inode"); + iput(inode); + return -ENOENT; + } + } + + if ((err = verify_group_input(sb, input))) + goto exit_put; + + if ((err = setup_new_group_blocks(sb, input))) + goto exit_put; + + /* + * We will always be modifying at least the superblock and a GDT + * block. If we are adding a group past the last current GDT block, + * we will also modify the inode and the dindirect block. If we + * are adding a group with superblock/GDT backups we will also + * modify each of the reserved GDT dindirect blocks. + */ + handle = ext3_journal_start_sb(sb, + ext3_bg_has_super(sb, input->group) ? + 3 + reserved_gdb : 4); + if (IS_ERR(handle)) { + err = PTR_ERR(handle); + goto exit_put; + } + + lock_super(sb); + if (input->group != sbi->s_groups_count) { + ext3_warning(sb, __FUNCTION__, + "multiple resizers run on filesystem!"); + err = -EBUSY; + goto exit_journal; + } + + if ((err = ext3_journal_get_write_access(handle, sbi->s_sbh))) + goto exit_journal; + + /* + * We will only either add reserved group blocks to a backup group + * or remove reserved blocks for the first group in a new group block. + * Doing both would be mean more complex code, and sane people don't + * use non-sparse filesystems anymore. This is already checked above. + */ + if (gdb_off) { + primary = sbi->s_group_desc[gdb_num]; + if ((err = ext3_journal_get_write_access(handle, primary))) + goto exit_journal; + + if (reserved_gdb && ext3_bg_num_gdb(sb, input->group) && + (err = reserve_backup_gdb(handle, inode, input))) + goto exit_journal; + } else if ((err = add_new_gdb(handle, inode, input, &primary))) + goto exit_journal; + + /* + * OK, now we've set up the new group. Time to make it active. + * + * Current kernels don't lock all allocations via lock_super(), + * so we have to be safe wrt. concurrent accesses the group + * data. So we need to be careful to set all of the relevant + * group descriptor data etc. *before* we enable the group. + * + * The key field here is sbi->s_groups_count: as long as + * that retains its old value, nobody is going to access the new + * group. + * + * So first we update all the descriptor metadata for the new + * group; then we update the total disk blocks count; then we + * update the groups count to enable the group; then finally we + * update the free space counts so that the system can start + * using the new disk blocks. + */ + + /* Update group descriptor block for new group */ + gdp = (struct ext3_group_desc *)primary->b_data + gdb_off; + + gdp->bg_block_bitmap = cpu_to_le32(input->block_bitmap); + gdp->bg_inode_bitmap = cpu_to_le32(input->inode_bitmap); + gdp->bg_inode_table = cpu_to_le32(input->inode_table); + gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); + gdp->bg_free_inodes_count = cpu_to_le16(EXT3_INODES_PER_GROUP(sb)); + + /* + * Make the new blocks and inodes valid next. We do this before + * increasing the group count so that once the group is enabled, + * all of its blocks and inodes are already valid. + * + * We always allocate group-by-group, then block-by-block or + * inode-by-inode within a group, so enabling these + * blocks/inodes before the group is live won't actually let us + * allocate the new space yet. + */ + es->s_blocks_count = cpu_to_le32(le32_to_cpu(es->s_blocks_count) + + input->blocks_count); + es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) + + EXT3_INODES_PER_GROUP(sb)); + + /* + * We need to protect s_groups_count against other CPUs seeing + * inconsistent state in the superblock. + * + * The precise rules we use are: + * + * * Writers of s_groups_count *must* hold lock_super + * AND + * * Writers must perform a smp_wmb() after updating all dependent + * data and before modifying the groups count + * + * * Readers must hold lock_super() over the access + * OR + * * Readers must perform an smp_rmb() after reading the groups count + * and before reading any dependent data. + * + * NB. These rules can be relaxed when checking the group count + * while freeing data, as we can only allocate from a block + * group after serialising against the group count, and we can + * only then free after serialising in turn against that + * allocation. + */ + smp_wmb(); + + /* Update the global fs size fields */ + sbi->s_groups_count++; + + ext3_journal_dirty_metadata(handle, primary); + + /* Update the reserved block counts only once the new group is + * active. */ + es->s_r_blocks_count = cpu_to_le32(le32_to_cpu(es->s_r_blocks_count) + + input->reserved_blocks); + + /* Update the free space counts */ + percpu_counter_mod(&sbi->s_freeblocks_counter, + input->free_blocks_count); + percpu_counter_mod(&sbi->s_freeinodes_counter, + EXT3_INODES_PER_GROUP(sb)); + + ext3_journal_dirty_metadata(handle, sbi->s_sbh); + sb->s_dirt = 1; + +exit_journal: + unlock_super(sb); + if ((err2 = ext3_journal_stop(handle)) && !err) + err = err2; + if (!err) { + update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, + sizeof(struct ext3_super_block)); + update_backups(sb, primary->b_blocknr, primary->b_data, + primary->b_size); + } +exit_put: + iput(inode); + return err; +} /* ext3_group_add */ + +/* Extend the filesystem to the new number of blocks specified. This entry + * point is only used to extend the current filesystem to the end of the last + * existing group. It can be accessed via ioctl, or by "remount,resize=" + * for emergencies (because it has no dependencies on reserved blocks). + * + * If we _really_ wanted, we could use default values to call ext3_group_add() + * allow the "remount" trick to work for arbitrary resizing, assuming enough + * GDT blocks are reserved to grow to the desired size. + */ +int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, + ext3_fsblk_t n_blocks_count) +{ + ext3_fsblk_t o_blocks_count; + unsigned long o_groups_count; + ext3_grpblk_t last; + ext3_grpblk_t add; + struct buffer_head * bh; + handle_t *handle; + int err; + unsigned long freed_blocks; + + /* We don't need to worry about locking wrt other resizers just + * yet: we're going to revalidate es->s_blocks_count after + * taking lock_super() below. */ + o_blocks_count = le32_to_cpu(es->s_blocks_count); + o_groups_count = EXT3_SB(sb)->s_groups_count; + + if (test_opt(sb, DEBUG)) + printk(KERN_DEBUG "EXT3-fs: extending last group from "E3FSBLK" uto "E3FSBLK" blocks\n", + o_blocks_count, n_blocks_count); + + if (n_blocks_count == 0 || n_blocks_count == o_blocks_count) + return 0; + + if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { + printk(KERN_ERR "EXT3-fs: filesystem on %s:" + " too large to resize to %lu blocks safely\n", + sb->s_id, n_blocks_count); + if (sizeof(sector_t) < 8) + ext3_warning(sb, __FUNCTION__, + "CONFIG_LBD not enabled\n"); + return -EINVAL; + } + + if (n_blocks_count < o_blocks_count) { + ext3_warning(sb, __FUNCTION__, + "can't shrink FS - resize aborted"); + return -EBUSY; + } + + /* Handle the remaining blocks in the last group only. */ + last = (o_blocks_count - le32_to_cpu(es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb); + + if (last == 0) { + ext3_warning(sb, __FUNCTION__, + "need to use ext2online to resize further"); + return -EPERM; + } + + add = EXT3_BLOCKS_PER_GROUP(sb) - last; + + if (o_blocks_count + add < o_blocks_count) { + ext3_warning(sb, __FUNCTION__, "blocks_count overflow"); + return -EINVAL; + } + + if (o_blocks_count + add > n_blocks_count) + add = n_blocks_count - o_blocks_count; + + if (o_blocks_count + add < n_blocks_count) + ext3_warning(sb, __FUNCTION__, + "will only finish group ("E3FSBLK + " blocks, %u new)", + o_blocks_count + add, add); + + /* See if the device is actually as big as what was requested */ + bh = sb_bread(sb, o_blocks_count + add -1); + if (!bh) { + ext3_warning(sb, __FUNCTION__, + "can't read last block, resize aborted"); + return -ENOSPC; + } + brelse(bh); + + /* We will update the superblock, one block bitmap, and + * one group descriptor via ext3_free_blocks(). + */ + handle = ext3_journal_start_sb(sb, 3); + if (IS_ERR(handle)) { + err = PTR_ERR(handle); + ext3_warning(sb, __FUNCTION__, "error %d on journal start",err); + goto exit_put; + } + + lock_super(sb); + if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) { + ext3_warning(sb, __FUNCTION__, + "multiple resizers run on filesystem!"); + unlock_super(sb); + err = -EBUSY; + goto exit_put; + } + + if ((err = ext3_journal_get_write_access(handle, + EXT3_SB(sb)->s_sbh))) { + ext3_warning(sb, __FUNCTION__, + "error %d on journal write access", err); + unlock_super(sb); + ext3_journal_stop(handle); + goto exit_put; + } + es->s_blocks_count = cpu_to_le32(o_blocks_count + add); + ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + sb->s_dirt = 1; + unlock_super(sb); + ext3_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count, + o_blocks_count + add); + ext3_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks); + ext3_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n", o_blocks_count, + o_blocks_count + add); + if ((err = ext3_journal_stop(handle))) + goto exit_put; + if (test_opt(sb, DEBUG)) + printk(KERN_DEBUG "EXT3-fs: extended group to %u blocks\n", + le32_to_cpu(es->s_blocks_count)); + update_backups(sb, EXT3_SB(sb)->s_sbh->b_blocknr, (char *)es, + sizeof(struct ext3_super_block)); +exit_put: + return err; +} /* ext3_group_extend */ diff --git a/fs/ext4/super.c b/fs/ext4/super.c new file mode 100644 index 000000000000..8bfd56ef18ca --- /dev/null +++ b/fs/ext4/super.c @@ -0,0 +1,2754 @@ +/* + * linux/fs/ext3/super.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "xattr.h" +#include "acl.h" +#include "namei.h" + +static int ext3_load_journal(struct super_block *, struct ext3_super_block *, + unsigned long journal_devnum); +static int ext3_create_journal(struct super_block *, struct ext3_super_block *, + unsigned int); +static void ext3_commit_super (struct super_block * sb, + struct ext3_super_block * es, + int sync); +static void ext3_mark_recovery_complete(struct super_block * sb, + struct ext3_super_block * es); +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 dentry * dentry, 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. + * + * The only special thing we need to do here is to make sure that all + * journal_end calls result in the superblock being marked dirty, so + * that sync() will call the filesystem's write_super callback if + * appropriate. + */ +handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks) +{ + journal_t *journal; + + if (sb->s_flags & MS_RDONLY) + return ERR_PTR(-EROFS); + + /* Special case here: if the journal has aborted behind our + * backs (eg. EIO in the commit thread), then we still need to + * take the FS itself readonly cleanly. */ + journal = EXT3_SB(sb)->s_journal; + if (is_journal_aborted(journal)) { + ext3_abort(sb, __FUNCTION__, + "Detected aborted journal"); + return ERR_PTR(-EROFS); + } + + return journal_start(journal, nblocks); +} + +/* + * The only special thing we need to do here is to make sure that all + * journal_stop calls result in the superblock being marked dirty, so + * that sync() will call the filesystem's write_super callback if + * appropriate. + */ +int __ext3_journal_stop(const char *where, handle_t *handle) +{ + struct super_block *sb; + int err; + int rc; + + sb = handle->h_transaction->t_journal->j_private; + err = handle->h_err; + rc = journal_stop(handle); + + if (!err) + err = rc; + if (err) + __ext3_std_error(sb, where, err); + return err; +} + +void ext3_journal_abort_handle(const char *caller, const char *err_fn, + struct buffer_head *bh, handle_t *handle, int err) +{ + char nbuf[16]; + const char *errstr = ext3_decode_error(NULL, err, nbuf); + + if (bh) + BUFFER_TRACE(bh, "abort"); + + if (!handle->h_err) + handle->h_err = err; + + if (is_handle_aborted(handle)) + return; + + printk(KERN_ERR "%s: aborting transaction: %s in %s\n", + caller, errstr, err_fn); + + journal_abort_handle(handle); +} + +/* Deal with the reporting of failure conditions on a filesystem such as + * inconsistencies detected or read IO failures. + * + * On ext2, we can store the error state of the filesystem in the + * superblock. That is not possible on ext3, because we may have other + * write ordering constraints on the superblock which prevent us from + * writing it out straight away; and given that the journal is about to + * be aborted, we can't rely on the current, or future, transactions to + * write out the superblock safely. + * + * We'll just use the journal_abort() error code to record an error in + * the journal instead. On recovery, the journal will compain about + * that error until we've noted it down and cleared it. + */ + +static void ext3_handle_error(struct super_block *sb) +{ + struct ext3_super_block *es = EXT3_SB(sb)->s_es; + + EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; + es->s_state |= cpu_to_le16(EXT3_ERROR_FS); + + if (sb->s_flags & MS_RDONLY) + return; + + if (!test_opt (sb, ERRORS_CONT)) { + journal_t *journal = EXT3_SB(sb)->s_journal; + + EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT; + if (journal) + journal_abort(journal, -EIO); + } + if (test_opt (sb, ERRORS_RO)) { + printk (KERN_CRIT "Remounting filesystem read-only\n"); + sb->s_flags |= MS_RDONLY; + } + ext3_commit_super(sb, es, 1); + if (test_opt(sb, ERRORS_PANIC)) + panic("EXT3-fs (device %s): panic forced after error\n", + sb->s_id); +} + +void ext3_error (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); + + ext3_handle_error(sb); +} + +static const char *ext3_decode_error(struct super_block * sb, int errno, + char nbuf[16]) +{ + char *errstr = NULL; + + switch (errno) { + case -EIO: + errstr = "IO failure"; + break; + case -ENOMEM: + errstr = "Out of memory"; + break; + case -EROFS: + if (!sb || EXT3_SB(sb)->s_journal->j_flags & JFS_ABORT) + errstr = "Journal has aborted"; + else + errstr = "Readonly filesystem"; + break; + default: + /* If the caller passed in an extra buffer for unknown + * errors, textualise them now. Else we just return + * NULL. */ + if (nbuf) { + /* Check for truncated error codes... */ + if (snprintf(nbuf, 16, "error %d", -errno) >= 0) + errstr = nbuf; + } + break; + } + + return errstr; +} + +/* __ext3_std_error decodes expected errors from journaling functions + * automatically and invokes the appropriate error response. */ + +void __ext3_std_error (struct super_block * sb, const char * function, + int errno) +{ + char nbuf[16]; + const char *errstr; + + /* Special case: if the error is EROFS, and we're not already + * inside a transaction, then there's really no point in logging + * an error. */ + if (errno == -EROFS && journal_current_handle() == NULL && + (sb->s_flags & MS_RDONLY)) + return; + + errstr = ext3_decode_error(sb, errno, nbuf); + printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n", + sb->s_id, function, errstr); + + ext3_handle_error(sb); +} + +/* + * ext3_abort is a much stronger failure handler than ext3_error. The + * abort function may be used to deal with unrecoverable failures such + * as journal IO errors or ENOMEM at a critical moment in log management. + * + * We unconditionally force the filesystem into an ABORT|READONLY state, + * unless the error response on the fs has been set to panic in which + * case we take the easy way out and panic immediately. + */ + +void ext3_abort (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + printk (KERN_CRIT "ext3_abort called.\n"); + + 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); + + if (test_opt(sb, ERRORS_PANIC)) + panic("EXT3-fs panic from previous error\n"); + + if (sb->s_flags & MS_RDONLY) + return; + + printk(KERN_CRIT "Remounting filesystem read-only\n"); + EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; + sb->s_flags |= MS_RDONLY; + EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT; + journal_abort(EXT3_SB(sb)->s_journal, -EIO); +} + +void ext3_warning (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + va_start(args, fmt); + printk(KERN_WARNING "EXT3-fs warning (device %s): %s: ", + sb->s_id, function); + vprintk(fmt, args); + printk("\n"); + va_end(args); +} + +void ext3_update_dynamic_rev(struct super_block *sb) +{ + struct ext3_super_block *es = EXT3_SB(sb)->s_es; + + if (le32_to_cpu(es->s_rev_level) > EXT3_GOOD_OLD_REV) + return; + + ext3_warning(sb, __FUNCTION__, + "updating to rev %d because of new feature flag, " + "running e2fsck is recommended", + EXT3_DYNAMIC_REV); + + es->s_first_ino = cpu_to_le32(EXT3_GOOD_OLD_FIRST_INO); + es->s_inode_size = cpu_to_le16(EXT3_GOOD_OLD_INODE_SIZE); + es->s_rev_level = cpu_to_le32(EXT3_DYNAMIC_REV); + /* leave es->s_feature_*compat flags alone */ + /* es->s_uuid will be set by e2fsck if empty */ + + /* + * The rest of the superblock fields should be zero, and if not it + * means they are likely already in use, so leave them alone. We + * can leave it up to e2fsck to clean up any inconsistencies there. + */ +} + +/* + * Open the external journal device + */ +static struct block_device *ext3_blkdev_get(dev_t dev) +{ + struct block_device *bdev; + char b[BDEVNAME_SIZE]; + + bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); + if (IS_ERR(bdev)) + goto fail; + return bdev; + +fail: + printk(KERN_ERR "EXT3: failed to open journal device %s: %ld\n", + __bdevname(dev, b), PTR_ERR(bdev)); + return NULL; +} + +/* + * Release the journal device + */ +static int ext3_blkdev_put(struct block_device *bdev) +{ + bd_release(bdev); + return blkdev_put(bdev); +} + +static int ext3_blkdev_remove(struct ext3_sb_info *sbi) +{ + struct block_device *bdev; + int ret = -ENODEV; + + bdev = sbi->journal_bdev; + if (bdev) { + ret = ext3_blkdev_put(bdev); + sbi->journal_bdev = NULL; + } + return ret; +} + +static inline struct inode *orphan_list_entry(struct list_head *l) +{ + return &list_entry(l, struct ext3_inode_info, i_orphan)->vfs_inode; +} + +static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi) +{ + struct list_head *l; + + printk(KERN_ERR "sb orphan head is %d\n", + le32_to_cpu(sbi->s_es->s_last_orphan)); + + printk(KERN_ERR "sb_info orphan list:\n"); + list_for_each(l, &sbi->s_orphan) { + struct inode *inode = orphan_list_entry(l); + printk(KERN_ERR " " + "inode %s:%lu at %p: mode %o, nlink %d, next %d\n", + inode->i_sb->s_id, inode->i_ino, inode, + inode->i_mode, inode->i_nlink, + NEXT_ORPHAN(inode)); + } +} + +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; + int i; + + ext3_xattr_put_super(sb); + journal_destroy(sbi->s_journal); + if (!(sb->s_flags & MS_RDONLY)) { + EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + es->s_state = cpu_to_le16(sbi->s_mount_state); + BUFFER_TRACE(sbi->s_sbh, "marking dirty"); + mark_buffer_dirty(sbi->s_sbh); + ext3_commit_super(sb, es, 1); + } + + for (i = 0; i < sbi->s_gdb_count; i++) + brelse(sbi->s_group_desc[i]); + kfree(sbi->s_group_desc); + percpu_counter_destroy(&sbi->s_freeblocks_counter); + percpu_counter_destroy(&sbi->s_freeinodes_counter); + percpu_counter_destroy(&sbi->s_dirs_counter); + brelse(sbi->s_sbh); +#ifdef CONFIG_QUOTA + for (i = 0; i < MAXQUOTAS; i++) + kfree(sbi->s_qf_names[i]); +#endif + + /* Debugging code just in case the in-memory inode orphan list + * isn't empty. The on-disk one can be non-empty if we've + * detected an error and taken the fs readonly, but the + * in-memory list had better be clean by this point. */ + if (!list_empty(&sbi->s_orphan)) + dump_orphan_list(sb, sbi); + J_ASSERT(list_empty(&sbi->s_orphan)); + + invalidate_bdev(sb->s_bdev, 0); + if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) { + /* + * Invalidate the journal device's buffers. We don't want them + * floating about in memory - the physical journal device may + * hotswapped, and it breaks the `ro-after' testing code. + */ + sync_blockdev(sbi->journal_bdev); + invalidate_bdev(sbi->journal_bdev, 0); + ext3_blkdev_remove(sbi); + } + sb->s_fs_info = NULL; + kfree(sbi); + return; +} + +static kmem_cache_t *ext3_inode_cachep; + +/* + * Called inside transaction, so use GFP_NOFS + */ +static struct inode *ext3_alloc_inode(struct super_block *sb) +{ + struct ext3_inode_info *ei; + + ei = kmem_cache_alloc(ext3_inode_cachep, SLAB_NOFS); + if (!ei) + return NULL; +#ifdef CONFIG_EXT3_FS_POSIX_ACL + ei->i_acl = EXT3_ACL_NOT_CACHED; + ei->i_default_acl = EXT3_ACL_NOT_CACHED; +#endif + ei->i_block_alloc_info = NULL; + ei->vfs_inode.i_version = 1; + return &ei->vfs_inode; +} + +static void ext3_destroy_inode(struct inode *inode) +{ + kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); +} + +static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +{ + struct ext3_inode_info *ei = (struct ext3_inode_info *) foo; + + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) { + INIT_LIST_HEAD(&ei->i_orphan); +#ifdef CONFIG_EXT3_FS_XATTR + init_rwsem(&ei->xattr_sem); +#endif + mutex_init(&ei->truncate_mutex); + inode_init_once(&ei->vfs_inode); + } +} + +static int init_inodecache(void) +{ + ext3_inode_cachep = kmem_cache_create("ext3_inode_cache", + sizeof(struct ext3_inode_info), + 0, (SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD), + init_once, NULL); + if (ext3_inode_cachep == NULL) + return -ENOMEM; + return 0; +} + +static void destroy_inodecache(void) +{ + kmem_cache_destroy(ext3_inode_cachep); +} + +static void ext3_clear_inode(struct inode *inode) +{ + struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info; +#ifdef CONFIG_EXT3_FS_POSIX_ACL + if (EXT3_I(inode)->i_acl && + EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) { + posix_acl_release(EXT3_I(inode)->i_acl); + EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED; + } + if (EXT3_I(inode)->i_default_acl && + EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) { + posix_acl_release(EXT3_I(inode)->i_default_acl); + EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED; + } +#endif + ext3_discard_reservation(inode); + EXT3_I(inode)->i_block_alloc_info = NULL; + if (unlikely(rsv)) + kfree(rsv); +} + +static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb) +{ +#if defined(CONFIG_QUOTA) + struct ext3_sb_info *sbi = EXT3_SB(sb); + + if (sbi->s_jquota_fmt) + seq_printf(seq, ",jqfmt=%s", + (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0"); + + if (sbi->s_qf_names[USRQUOTA]) + seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]); + + if (sbi->s_qf_names[GRPQUOTA]) + seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); + + if (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA) + seq_puts(seq, ",usrquota"); + + if (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) + seq_puts(seq, ",grpquota"); +#endif +} + +static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) +{ + struct super_block *sb = vfs->mnt_sb; + + if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) + seq_puts(seq, ",data=journal"); + else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA) + seq_puts(seq, ",data=ordered"); + else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) + seq_puts(seq, ",data=writeback"); + + ext3_show_quota_options(seq, sb); + + return 0; +} + + +static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp) +{ + __u32 *objp = vobjp; + unsigned long ino = objp[0]; + __u32 generation = objp[1]; + struct inode *inode; + struct dentry *result; + + if (ino < EXT3_FIRST_INO(sb) && ino != EXT3_ROOT_INO) + return ERR_PTR(-ESTALE); + if (ino > le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)) + return ERR_PTR(-ESTALE); + + /* iget isn't really right if the inode is currently unallocated!! + * + * ext3_read_inode will return a bad_inode if the inode had been + * deleted, so we should be safe. + * + * Currently we don't know the generation for parent directory, so + * a generation of 0 means "accept any" + */ + inode = iget(sb, ino); + if (inode == NULL) + return ERR_PTR(-ENOMEM); + if (is_bad_inode(inode) || + (generation && inode->i_generation != generation)) { + iput(inode); + return ERR_PTR(-ESTALE); + } + /* now to find a dentry. + * If possible, get a well-connected one + */ + result = d_alloc_anon(inode); + if (!result) { + iput(inode); + return ERR_PTR(-ENOMEM); + } + return result; +} + +#ifdef CONFIG_QUOTA +#define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group") +#define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) + +static int ext3_dquot_initialize(struct inode *inode, int type); +static int ext3_dquot_drop(struct inode *inode); +static int ext3_write_dquot(struct dquot *dquot); +static int ext3_acquire_dquot(struct dquot *dquot); +static int ext3_release_dquot(struct dquot *dquot); +static int ext3_mark_dquot_dirty(struct dquot *dquot); +static int ext3_write_info(struct super_block *sb, int type); +static int ext3_quota_on(struct super_block *sb, int type, int format_id, char *path); +static int ext3_quota_on_mount(struct super_block *sb, int type); +static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, + size_t len, loff_t off); +static ssize_t ext3_quota_write(struct super_block *sb, int type, + const char *data, size_t len, loff_t off); + +static struct dquot_operations ext3_quota_operations = { + .initialize = ext3_dquot_initialize, + .drop = ext3_dquot_drop, + .alloc_space = dquot_alloc_space, + .alloc_inode = dquot_alloc_inode, + .free_space = dquot_free_space, + .free_inode = dquot_free_inode, + .transfer = dquot_transfer, + .write_dquot = ext3_write_dquot, + .acquire_dquot = ext3_acquire_dquot, + .release_dquot = ext3_release_dquot, + .mark_dirty = ext3_mark_dquot_dirty, + .write_info = ext3_write_info +}; + +static struct quotactl_ops ext3_qctl_operations = { + .quota_on = ext3_quota_on, + .quota_off = vfs_quota_off, + .quota_sync = vfs_quota_sync, + .get_info = vfs_get_dqinfo, + .set_info = vfs_set_dqinfo, + .get_dqblk = vfs_get_dqblk, + .set_dqblk = vfs_set_dqblk +}; +#endif + +static struct super_operations ext3_sops = { + .alloc_inode = ext3_alloc_inode, + .destroy_inode = ext3_destroy_inode, + .read_inode = ext3_read_inode, + .write_inode = ext3_write_inode, + .dirty_inode = ext3_dirty_inode, + .delete_inode = ext3_delete_inode, + .put_super = ext3_put_super, + .write_super = ext3_write_super, + .sync_fs = ext3_sync_fs, + .write_super_lockfs = ext3_write_super_lockfs, + .unlockfs = ext3_unlockfs, + .statfs = ext3_statfs, + .remount_fs = ext3_remount, + .clear_inode = ext3_clear_inode, + .show_options = ext3_show_options, +#ifdef CONFIG_QUOTA + .quota_read = ext3_quota_read, + .quota_write = ext3_quota_write, +#endif +}; + +static struct export_operations ext3_export_ops = { + .get_parent = ext3_get_parent, + .get_dentry = ext3_get_dentry, +}; + +enum { + Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, + Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, + Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, + Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, + Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh, + Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev, + Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, + Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, + Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, + Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota, + Opt_grpquota +}; + +static match_table_t tokens = { + {Opt_bsd_df, "bsddf"}, + {Opt_minix_df, "minixdf"}, + {Opt_grpid, "grpid"}, + {Opt_grpid, "bsdgroups"}, + {Opt_nogrpid, "nogrpid"}, + {Opt_nogrpid, "sysvgroups"}, + {Opt_resgid, "resgid=%u"}, + {Opt_resuid, "resuid=%u"}, + {Opt_sb, "sb=%u"}, + {Opt_err_cont, "errors=continue"}, + {Opt_err_panic, "errors=panic"}, + {Opt_err_ro, "errors=remount-ro"}, + {Opt_nouid32, "nouid32"}, + {Opt_nocheck, "nocheck"}, + {Opt_nocheck, "check=none"}, + {Opt_debug, "debug"}, + {Opt_oldalloc, "oldalloc"}, + {Opt_orlov, "orlov"}, + {Opt_user_xattr, "user_xattr"}, + {Opt_nouser_xattr, "nouser_xattr"}, + {Opt_acl, "acl"}, + {Opt_noacl, "noacl"}, + {Opt_reservation, "reservation"}, + {Opt_noreservation, "noreservation"}, + {Opt_noload, "noload"}, + {Opt_nobh, "nobh"}, + {Opt_bh, "bh"}, + {Opt_commit, "commit=%u"}, + {Opt_journal_update, "journal=update"}, + {Opt_journal_inum, "journal=%u"}, + {Opt_journal_dev, "journal_dev=%u"}, + {Opt_abort, "abort"}, + {Opt_data_journal, "data=journal"}, + {Opt_data_ordered, "data=ordered"}, + {Opt_data_writeback, "data=writeback"}, + {Opt_offusrjquota, "usrjquota="}, + {Opt_usrjquota, "usrjquota=%s"}, + {Opt_offgrpjquota, "grpjquota="}, + {Opt_grpjquota, "grpjquota=%s"}, + {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, + {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, + {Opt_grpquota, "grpquota"}, + {Opt_noquota, "noquota"}, + {Opt_quota, "quota"}, + {Opt_usrquota, "usrquota"}, + {Opt_barrier, "barrier=%u"}, + {Opt_err, NULL}, + {Opt_resize, "resize"}, +}; + +static ext3_fsblk_t get_sb_block(void **data) +{ + ext3_fsblk_t sb_block; + char *options = (char *) *data; + + if (!options || strncmp(options, "sb=", 3) != 0) + return 1; /* Default location */ + options += 3; + /*todo: use simple_strtoll with >32bit ext3 */ + sb_block = simple_strtoul(options, &options, 0); + if (*options && *options != ',') { + printk("EXT3-fs: Invalid sb specification: %s\n", + (char *) *data); + return 1; + } + if (*options == ',') + options++; + *data = (void *) options; + return sb_block; +} + +static int parse_options (char *options, struct super_block *sb, + unsigned int *inum, unsigned long *journal_devnum, + ext3_fsblk_t *n_blocks_count, int is_remount) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + char * p; + substring_t args[MAX_OPT_ARGS]; + int data_opt = 0; + int option; +#ifdef CONFIG_QUOTA + int qtype; + char *qname; +#endif + + if (!options) + return 1; + + while ((p = strsep (&options, ",")) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case Opt_bsd_df: + clear_opt (sbi->s_mount_opt, MINIX_DF); + break; + case Opt_minix_df: + set_opt (sbi->s_mount_opt, MINIX_DF); + break; + case Opt_grpid: + set_opt (sbi->s_mount_opt, GRPID); + break; + case Opt_nogrpid: + clear_opt (sbi->s_mount_opt, GRPID); + break; + case Opt_resuid: + if (match_int(&args[0], &option)) + return 0; + sbi->s_resuid = option; + break; + case Opt_resgid: + if (match_int(&args[0], &option)) + return 0; + sbi->s_resgid = option; + break; + case Opt_sb: + /* handled by get_sb_block() instead of here */ + /* *sb_block = match_int(&args[0]); */ + break; + case Opt_err_panic: + clear_opt (sbi->s_mount_opt, ERRORS_CONT); + clear_opt (sbi->s_mount_opt, ERRORS_RO); + set_opt (sbi->s_mount_opt, ERRORS_PANIC); + break; + case Opt_err_ro: + clear_opt (sbi->s_mount_opt, ERRORS_CONT); + clear_opt (sbi->s_mount_opt, ERRORS_PANIC); + set_opt (sbi->s_mount_opt, ERRORS_RO); + break; + case Opt_err_cont: + clear_opt (sbi->s_mount_opt, ERRORS_RO); + clear_opt (sbi->s_mount_opt, ERRORS_PANIC); + set_opt (sbi->s_mount_opt, ERRORS_CONT); + break; + case Opt_nouid32: + set_opt (sbi->s_mount_opt, NO_UID32); + break; + case Opt_nocheck: + clear_opt (sbi->s_mount_opt, CHECK); + break; + case Opt_debug: + set_opt (sbi->s_mount_opt, DEBUG); + break; + case Opt_oldalloc: + set_opt (sbi->s_mount_opt, OLDALLOC); + break; + case Opt_orlov: + clear_opt (sbi->s_mount_opt, OLDALLOC); + break; +#ifdef CONFIG_EXT3_FS_XATTR + case Opt_user_xattr: + set_opt (sbi->s_mount_opt, XATTR_USER); + break; + case Opt_nouser_xattr: + clear_opt (sbi->s_mount_opt, XATTR_USER); + break; +#else + case Opt_user_xattr: + case Opt_nouser_xattr: + printk("EXT3 (no)user_xattr options not supported\n"); + break; +#endif +#ifdef CONFIG_EXT3_FS_POSIX_ACL + case Opt_acl: + set_opt(sbi->s_mount_opt, POSIX_ACL); + break; + case Opt_noacl: + clear_opt(sbi->s_mount_opt, POSIX_ACL); + break; +#else + case Opt_acl: + case Opt_noacl: + printk("EXT3 (no)acl options not supported\n"); + break; +#endif + case Opt_reservation: + set_opt(sbi->s_mount_opt, RESERVATION); + break; + case Opt_noreservation: + clear_opt(sbi->s_mount_opt, RESERVATION); + break; + case Opt_journal_update: + /* @@@ FIXME */ + /* Eventually we will want to be able to create + a journal file here. For now, only allow the + user to specify an existing inode to be the + journal file. */ + if (is_remount) { + printk(KERN_ERR "EXT3-fs: cannot specify " + "journal on remount\n"); + return 0; + } + set_opt (sbi->s_mount_opt, UPDATE_JOURNAL); + break; + case Opt_journal_inum: + if (is_remount) { + printk(KERN_ERR "EXT3-fs: cannot specify " + "journal on remount\n"); + return 0; + } + if (match_int(&args[0], &option)) + return 0; + *inum = option; + break; + case Opt_journal_dev: + if (is_remount) { + printk(KERN_ERR "EXT3-fs: cannot specify " + "journal on remount\n"); + return 0; + } + if (match_int(&args[0], &option)) + return 0; + *journal_devnum = option; + break; + case Opt_noload: + set_opt (sbi->s_mount_opt, NOLOAD); + break; + case Opt_commit: + if (match_int(&args[0], &option)) + return 0; + if (option < 0) + return 0; + if (option == 0) + option = JBD_DEFAULT_MAX_COMMIT_AGE; + sbi->s_commit_interval = HZ * option; + break; + case Opt_data_journal: + data_opt = EXT3_MOUNT_JOURNAL_DATA; + goto datacheck; + case Opt_data_ordered: + data_opt = EXT3_MOUNT_ORDERED_DATA; + goto datacheck; + case Opt_data_writeback: + data_opt = EXT3_MOUNT_WRITEBACK_DATA; + datacheck: + if (is_remount) { + if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS) + != data_opt) { + printk(KERN_ERR + "EXT3-fs: cannot change data " + "mode on remount\n"); + return 0; + } + } else { + sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS; + sbi->s_mount_opt |= data_opt; + } + break; +#ifdef CONFIG_QUOTA + case Opt_usrjquota: + qtype = USRQUOTA; + goto set_qf_name; + case Opt_grpjquota: + qtype = GRPQUOTA; +set_qf_name: + if (sb_any_quota_enabled(sb)) { + printk(KERN_ERR + "EXT3-fs: Cannot change journalled " + "quota options when quota turned on.\n"); + return 0; + } + qname = match_strdup(&args[0]); + if (!qname) { + printk(KERN_ERR + "EXT3-fs: not enough memory for " + "storing quotafile name.\n"); + return 0; + } + if (sbi->s_qf_names[qtype] && + strcmp(sbi->s_qf_names[qtype], qname)) { + printk(KERN_ERR + "EXT3-fs: %s quota file already " + "specified.\n", QTYPE2NAME(qtype)); + kfree(qname); + return 0; + } + sbi->s_qf_names[qtype] = qname; + if (strchr(sbi->s_qf_names[qtype], '/')) { + printk(KERN_ERR + "EXT3-fs: quotafile must be on " + "filesystem root.\n"); + kfree(sbi->s_qf_names[qtype]); + sbi->s_qf_names[qtype] = NULL; + return 0; + } + set_opt(sbi->s_mount_opt, QUOTA); + break; + case Opt_offusrjquota: + qtype = USRQUOTA; + goto clear_qf_name; + case Opt_offgrpjquota: + qtype = GRPQUOTA; +clear_qf_name: + if (sb_any_quota_enabled(sb)) { + printk(KERN_ERR "EXT3-fs: Cannot change " + "journalled quota options when " + "quota turned on.\n"); + return 0; + } + /* + * The space will be released later when all options + * are confirmed to be correct + */ + sbi->s_qf_names[qtype] = NULL; + break; + case Opt_jqfmt_vfsold: + sbi->s_jquota_fmt = QFMT_VFS_OLD; + break; + case Opt_jqfmt_vfsv0: + sbi->s_jquota_fmt = QFMT_VFS_V0; + break; + case Opt_quota: + case Opt_usrquota: + set_opt(sbi->s_mount_opt, QUOTA); + set_opt(sbi->s_mount_opt, USRQUOTA); + break; + case Opt_grpquota: + set_opt(sbi->s_mount_opt, QUOTA); + set_opt(sbi->s_mount_opt, GRPQUOTA); + break; + case Opt_noquota: + if (sb_any_quota_enabled(sb)) { + printk(KERN_ERR "EXT3-fs: Cannot change quota " + "options when quota turned on.\n"); + return 0; + } + clear_opt(sbi->s_mount_opt, QUOTA); + clear_opt(sbi->s_mount_opt, USRQUOTA); + clear_opt(sbi->s_mount_opt, GRPQUOTA); + break; +#else + case Opt_quota: + case Opt_usrquota: + case Opt_grpquota: + case Opt_usrjquota: + case Opt_grpjquota: + case Opt_offusrjquota: + case Opt_offgrpjquota: + case Opt_jqfmt_vfsold: + case Opt_jqfmt_vfsv0: + printk(KERN_ERR + "EXT3-fs: journalled quota options not " + "supported.\n"); + break; + case Opt_noquota: + break; +#endif + case Opt_abort: + set_opt(sbi->s_mount_opt, ABORT); + break; + case Opt_barrier: + if (match_int(&args[0], &option)) + return 0; + if (option) + set_opt(sbi->s_mount_opt, BARRIER); + else + clear_opt(sbi->s_mount_opt, BARRIER); + break; + case Opt_ignore: + break; + case Opt_resize: + if (!is_remount) { + printk("EXT3-fs: resize option only available " + "for remount\n"); + return 0; + } + if (match_int(&args[0], &option) != 0) + return 0; + *n_blocks_count = option; + break; + case Opt_nobh: + set_opt(sbi->s_mount_opt, NOBH); + break; + case Opt_bh: + clear_opt(sbi->s_mount_opt, NOBH); + break; + default: + printk (KERN_ERR + "EXT3-fs: Unrecognized mount option \"%s\" " + "or missing value\n", p); + return 0; + } + } +#ifdef CONFIG_QUOTA + if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) { + if ((sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA) && + sbi->s_qf_names[USRQUOTA]) + clear_opt(sbi->s_mount_opt, USRQUOTA); + + if ((sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) && + sbi->s_qf_names[GRPQUOTA]) + clear_opt(sbi->s_mount_opt, GRPQUOTA); + + if ((sbi->s_qf_names[USRQUOTA] && + (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)) || + (sbi->s_qf_names[GRPQUOTA] && + (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA))) { + printk(KERN_ERR "EXT3-fs: old and new quota " + "format mixing.\n"); + return 0; + } + + if (!sbi->s_jquota_fmt) { + printk(KERN_ERR "EXT3-fs: journalled quota format " + "not specified.\n"); + return 0; + } + } else { + if (sbi->s_jquota_fmt) { + printk(KERN_ERR "EXT3-fs: journalled quota format " + "specified with no journalling " + "enabled.\n"); + return 0; + } + } +#endif + return 1; +} + +static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, + int read_only) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + int res = 0; + + if (le32_to_cpu(es->s_rev_level) > EXT3_MAX_SUPP_REV) { + printk (KERN_ERR "EXT3-fs warning: revision level too high, " + "forcing read-only mode\n"); + res = MS_RDONLY; + } + if (read_only) + return res; + if (!(sbi->s_mount_state & EXT3_VALID_FS)) + printk (KERN_WARNING "EXT3-fs warning: mounting unchecked fs, " + "running e2fsck is recommended\n"); + else if ((sbi->s_mount_state & EXT3_ERROR_FS)) + printk (KERN_WARNING + "EXT3-fs warning: mounting fs with errors, " + "running e2fsck is recommended\n"); + else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && + le16_to_cpu(es->s_mnt_count) >= + (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) + printk (KERN_WARNING + "EXT3-fs warning: maximal mount count reached, " + "running e2fsck is recommended\n"); + else if (le32_to_cpu(es->s_checkinterval) && + (le32_to_cpu(es->s_lastcheck) + + le32_to_cpu(es->s_checkinterval) <= get_seconds())) + printk (KERN_WARNING + "EXT3-fs warning: checktime reached, " + "running e2fsck is recommended\n"); +#if 0 + /* @@@ We _will_ want to clear the valid bit if we find + inconsistencies, to force a fsck at reboot. But for + a plain journaled filesystem we can keep it set as + valid forever! :) */ + es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT3_VALID_FS); +#endif + if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) + es->s_max_mnt_count = cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT); + es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); + es->s_mtime = cpu_to_le32(get_seconds()); + ext3_update_dynamic_rev(sb); + EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + + ext3_commit_super(sb, es, 1); + if (test_opt(sb, DEBUG)) + printk(KERN_INFO "[EXT3 FS bs=%lu, gc=%lu, " + "bpg=%lu, ipg=%lu, mo=%04lx]\n", + sb->s_blocksize, + sbi->s_groups_count, + EXT3_BLOCKS_PER_GROUP(sb), + EXT3_INODES_PER_GROUP(sb), + sbi->s_mount_opt); + + printk(KERN_INFO "EXT3 FS on %s, ", sb->s_id); + if (EXT3_SB(sb)->s_journal->j_inode == NULL) { + char b[BDEVNAME_SIZE]; + + printk("external journal on %s\n", + bdevname(EXT3_SB(sb)->s_journal->j_dev, b)); + } else { + printk("internal journal\n"); + } + return res; +} + +/* Called at mount-time, super-block is locked */ +static int ext3_check_descriptors (struct super_block * sb) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); + ext3_fsblk_t last_block; + struct ext3_group_desc * gdp = NULL; + int desc_block = 0; + int i; + + ext3_debug ("Checking group descriptors"); + + for (i = 0; i < sbi->s_groups_count; i++) + { + if (i == sbi->s_groups_count - 1) + last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; + else + last_block = first_block + + (EXT3_BLOCKS_PER_GROUP(sb) - 1); + + if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0) + gdp = (struct ext3_group_desc *) + sbi->s_group_desc[desc_block++]->b_data; + if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || + le32_to_cpu(gdp->bg_block_bitmap) > last_block) + { + ext3_error (sb, "ext3_check_descriptors", + "Block bitmap for group %d" + " not in group (block %lu)!", + i, (unsigned long) + le32_to_cpu(gdp->bg_block_bitmap)); + return 0; + } + if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || + le32_to_cpu(gdp->bg_inode_bitmap) > last_block) + { + ext3_error (sb, "ext3_check_descriptors", + "Inode bitmap for group %d" + " not in group (block %lu)!", + i, (unsigned long) + le32_to_cpu(gdp->bg_inode_bitmap)); + return 0; + } + if (le32_to_cpu(gdp->bg_inode_table) < first_block || + le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group > + last_block) + { + ext3_error (sb, "ext3_check_descriptors", + "Inode table for group %d" + " not in group (block %lu)!", + i, (unsigned long) + le32_to_cpu(gdp->bg_inode_table)); + return 0; + } + first_block += EXT3_BLOCKS_PER_GROUP(sb); + gdp++; + } + + sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb)); + sbi->s_es->s_free_inodes_count=cpu_to_le32(ext3_count_free_inodes(sb)); + return 1; +} + + +/* ext3_orphan_cleanup() walks a singly-linked list of inodes (starting at + * the superblock) which were deleted from all directories, but held open by + * a process at the time of a crash. We walk the list and try to delete these + * inodes at recovery time (only with a read-write filesystem). + * + * In order to keep the orphan inode chain consistent during traversal (in + * case of crash during recovery), we link each inode into the superblock + * orphan list_head and handle it the same way as an inode deletion during + * normal operation (which journals the operations for us). + * + * We only do an iget() and an iput() on each inode, which is very safe if we + * accidentally point at an in-use or already deleted inode. The worst that + * can happen in this case is that we get a "bit already cleared" message from + * ext3_free_inode(). The only reason we would point at a wrong inode is if + * e2fsck was run on this filesystem, and it must have already done the orphan + * inode cleanup for us, so we can safely abort without any further action. + */ +static void ext3_orphan_cleanup (struct super_block * sb, + struct ext3_super_block * es) +{ + unsigned int s_flags = sb->s_flags; + int nr_orphans = 0, nr_truncates = 0; +#ifdef CONFIG_QUOTA + int i; +#endif + if (!es->s_last_orphan) { + jbd_debug(4, "no orphan inodes to clean up\n"); + return; + } + + if (EXT3_SB(sb)->s_mount_state & EXT3_ERROR_FS) { + if (es->s_last_orphan) + jbd_debug(1, "Errors on filesystem, " + "clearing orphan list.\n"); + es->s_last_orphan = 0; + jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); + return; + } + + if (s_flags & MS_RDONLY) { + printk(KERN_INFO "EXT3-fs: %s: orphan cleanup on readonly fs\n", + sb->s_id); + sb->s_flags &= ~MS_RDONLY; + } +#ifdef CONFIG_QUOTA + /* Needed for iput() to work correctly and not trash data */ + sb->s_flags |= MS_ACTIVE; + /* Turn on quotas so that they are updated correctly */ + for (i = 0; i < MAXQUOTAS; i++) { + if (EXT3_SB(sb)->s_qf_names[i]) { + int ret = ext3_quota_on_mount(sb, i); + if (ret < 0) + printk(KERN_ERR + "EXT3-fs: Cannot turn on journalled " + "quota: error %d\n", ret); + } + } +#endif + + while (es->s_last_orphan) { + struct inode *inode; + + if (!(inode = + ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) { + es->s_last_orphan = 0; + break; + } + + list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan); + DQUOT_INIT(inode); + if (inode->i_nlink) { + printk(KERN_DEBUG + "%s: truncating inode %lu to %Ld bytes\n", + __FUNCTION__, inode->i_ino, inode->i_size); + jbd_debug(2, "truncating inode %lu to %Ld bytes\n", + inode->i_ino, inode->i_size); + ext3_truncate(inode); + nr_truncates++; + } else { + printk(KERN_DEBUG + "%s: deleting unreferenced inode %lu\n", + __FUNCTION__, inode->i_ino); + jbd_debug(2, "deleting unreferenced inode %lu\n", + inode->i_ino); + nr_orphans++; + } + iput(inode); /* The delete magic happens here! */ + } + +#define PLURAL(x) (x), ((x)==1) ? "" : "s" + + if (nr_orphans) + printk(KERN_INFO "EXT3-fs: %s: %d orphan inode%s deleted\n", + sb->s_id, PLURAL(nr_orphans)); + if (nr_truncates) + printk(KERN_INFO "EXT3-fs: %s: %d truncate%s cleaned up\n", + sb->s_id, PLURAL(nr_truncates)); +#ifdef CONFIG_QUOTA + /* Turn quotas off */ + for (i = 0; i < MAXQUOTAS; i++) { + if (sb_dqopt(sb)->files[i]) + vfs_quota_off(sb, i); + } +#endif + sb->s_flags = s_flags; /* Restore MS_RDONLY status */ +} + +#define log2(n) ffz(~(n)) + +/* + * Maximal file size. There is a direct, and {,double-,triple-}indirect + * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. + * We need to be 1 filesystem block less than the 2^32 sector limit. + */ +static loff_t ext3_max_size(int bits) +{ + loff_t res = EXT3_NDIR_BLOCKS; + /* This constant is calculated to be the largest file size for a + * dense, 4k-blocksize file such that the total number of + * sectors in the file, including data and all indirect blocks, + * does not exceed 2^32. */ + const loff_t upper_limit = 0x1ff7fffd000LL; + + res += 1LL << (bits-2); + res += 1LL << (2*(bits-2)); + res += 1LL << (3*(bits-2)); + res <<= bits; + if (res > upper_limit) + res = upper_limit; + return res; +} + +static ext3_fsblk_t descriptor_loc(struct super_block *sb, + ext3_fsblk_t logic_sb_block, + int nr) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + unsigned long bg, first_meta_bg; + int has_super = 0; + + first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); + + if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) || + nr < first_meta_bg) + return (logic_sb_block + nr + 1); + bg = sbi->s_desc_per_block * nr; + if (ext3_bg_has_super(sb, bg)) + has_super = 1; + return (has_super + ext3_group_first_block_no(sb, bg)); +} + + +static int ext3_fill_super (struct super_block *sb, void *data, int silent) +{ + struct buffer_head * bh; + struct ext3_super_block *es = NULL; + struct ext3_sb_info *sbi; + ext3_fsblk_t block; + ext3_fsblk_t sb_block = get_sb_block(&data); + ext3_fsblk_t logic_sb_block; + unsigned long offset = 0; + unsigned int journal_inum = 0; + unsigned long journal_devnum = 0; + unsigned long def_mount_opts; + struct inode *root; + int blocksize; + int hblock; + int db_count; + int i; + int needs_recovery; + __le32 features; + + sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); + if (!sbi) + return -ENOMEM; + sb->s_fs_info = sbi; + sbi->s_mount_opt = 0; + sbi->s_resuid = EXT3_DEF_RESUID; + sbi->s_resgid = EXT3_DEF_RESGID; + + unlock_kernel(); + + blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); + if (!blocksize) { + printk(KERN_ERR "EXT3-fs: unable to set blocksize\n"); + goto out_fail; + } + + /* + * The ext3 superblock will not be buffer aligned for other than 1kB + * block sizes. We need to calculate the offset from buffer start. + */ + if (blocksize != EXT3_MIN_BLOCK_SIZE) { + logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; + offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; + } else { + logic_sb_block = sb_block; + } + + if (!(bh = sb_bread(sb, logic_sb_block))) { + printk (KERN_ERR "EXT3-fs: unable to read superblock\n"); + goto out_fail; + } + /* + * Note: s_es must be initialized as soon as possible because + * some ext3 macro-instructions depend on its value + */ + es = (struct ext3_super_block *) (((char *)bh->b_data) + offset); + sbi->s_es = es; + sb->s_magic = le16_to_cpu(es->s_magic); + if (sb->s_magic != EXT3_SUPER_MAGIC) + goto cantfind_ext3; + + /* Set defaults before we parse the mount options */ + def_mount_opts = le32_to_cpu(es->s_default_mount_opts); + if (def_mount_opts & EXT3_DEFM_DEBUG) + set_opt(sbi->s_mount_opt, DEBUG); + if (def_mount_opts & EXT3_DEFM_BSDGROUPS) + set_opt(sbi->s_mount_opt, GRPID); + if (def_mount_opts & EXT3_DEFM_UID16) + set_opt(sbi->s_mount_opt, NO_UID32); + if (def_mount_opts & EXT3_DEFM_XATTR_USER) + set_opt(sbi->s_mount_opt, XATTR_USER); + if (def_mount_opts & EXT3_DEFM_ACL) + set_opt(sbi->s_mount_opt, POSIX_ACL); + if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_DATA) + sbi->s_mount_opt |= EXT3_MOUNT_JOURNAL_DATA; + else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_ORDERED) + sbi->s_mount_opt |= EXT3_MOUNT_ORDERED_DATA; + else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_WBACK) + sbi->s_mount_opt |= EXT3_MOUNT_WRITEBACK_DATA; + + if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC) + set_opt(sbi->s_mount_opt, ERRORS_PANIC); + else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO) + set_opt(sbi->s_mount_opt, ERRORS_RO); + + sbi->s_resuid = le16_to_cpu(es->s_def_resuid); + sbi->s_resgid = le16_to_cpu(es->s_def_resgid); + + set_opt(sbi->s_mount_opt, RESERVATION); + + if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum, + NULL, 0)) + goto failed_mount; + + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | + ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); + + if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV && + (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) || + EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) || + EXT3_HAS_INCOMPAT_FEATURE(sb, ~0U))) + printk(KERN_WARNING + "EXT3-fs warning: feature flags set on rev 0 fs, " + "running e2fsck is recommended\n"); + /* + * Check feature flags regardless of the revision level, since we + * previously didn't change the revision level when setting the flags, + * so there is a chance incompat flags are set on a rev 0 filesystem. + */ + features = EXT3_HAS_INCOMPAT_FEATURE(sb, ~EXT3_FEATURE_INCOMPAT_SUPP); + if (features) { + printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of " + "unsupported optional features (%x).\n", + sb->s_id, le32_to_cpu(features)); + goto failed_mount; + } + features = EXT3_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP); + if (!(sb->s_flags & MS_RDONLY) && features) { + printk(KERN_ERR "EXT3-fs: %s: couldn't mount RDWR because of " + "unsupported optional features (%x).\n", + sb->s_id, le32_to_cpu(features)); + goto failed_mount; + } + blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); + + if (blocksize < EXT3_MIN_BLOCK_SIZE || + blocksize > EXT3_MAX_BLOCK_SIZE) { + printk(KERN_ERR + "EXT3-fs: Unsupported filesystem blocksize %d on %s.\n", + blocksize, sb->s_id); + goto failed_mount; + } + + hblock = bdev_hardsect_size(sb->s_bdev); + if (sb->s_blocksize != blocksize) { + /* + * Make sure the blocksize for the filesystem is larger + * than the hardware sectorsize for the machine. + */ + if (blocksize < hblock) { + printk(KERN_ERR "EXT3-fs: blocksize %d too small for " + "device blocksize %d.\n", blocksize, hblock); + goto failed_mount; + } + + brelse (bh); + sb_set_blocksize(sb, blocksize); + logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; + offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; + bh = sb_bread(sb, logic_sb_block); + if (!bh) { + printk(KERN_ERR + "EXT3-fs: Can't read superblock on 2nd try.\n"); + goto failed_mount; + } + es = (struct ext3_super_block *)(((char *)bh->b_data) + offset); + sbi->s_es = es; + if (es->s_magic != cpu_to_le16(EXT3_SUPER_MAGIC)) { + printk (KERN_ERR + "EXT3-fs: Magic mismatch, very weird !\n"); + goto failed_mount; + } + } + + sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits); + + if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV) { + sbi->s_inode_size = EXT3_GOOD_OLD_INODE_SIZE; + sbi->s_first_ino = EXT3_GOOD_OLD_FIRST_INO; + } else { + sbi->s_inode_size = le16_to_cpu(es->s_inode_size); + sbi->s_first_ino = le32_to_cpu(es->s_first_ino); + if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) || + (sbi->s_inode_size & (sbi->s_inode_size - 1)) || + (sbi->s_inode_size > blocksize)) { + printk (KERN_ERR + "EXT3-fs: unsupported inode size: %d\n", + sbi->s_inode_size); + goto failed_mount; + } + } + sbi->s_frag_size = EXT3_MIN_FRAG_SIZE << + le32_to_cpu(es->s_log_frag_size); + if (blocksize != sbi->s_frag_size) { + printk(KERN_ERR + "EXT3-fs: fragsize %lu != blocksize %u (unsupported)\n", + sbi->s_frag_size, blocksize); + goto failed_mount; + } + sbi->s_frags_per_block = 1; + sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); + sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); + sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); + if (EXT3_INODE_SIZE(sb) == 0) + goto cantfind_ext3; + sbi->s_inodes_per_block = blocksize / EXT3_INODE_SIZE(sb); + if (sbi->s_inodes_per_block == 0) + goto cantfind_ext3; + sbi->s_itb_per_group = sbi->s_inodes_per_group / + sbi->s_inodes_per_block; + sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc); + sbi->s_sbh = bh; + sbi->s_mount_state = le16_to_cpu(es->s_state); + sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb)); + sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb)); + for (i=0; i < 4; i++) + sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); + sbi->s_def_hash_version = es->s_def_hash_version; + + if (sbi->s_blocks_per_group > blocksize * 8) { + printk (KERN_ERR + "EXT3-fs: #blocks per group too big: %lu\n", + sbi->s_blocks_per_group); + goto failed_mount; + } + if (sbi->s_frags_per_group > blocksize * 8) { + printk (KERN_ERR + "EXT3-fs: #fragments per group too big: %lu\n", + sbi->s_frags_per_group); + goto failed_mount; + } + if (sbi->s_inodes_per_group > blocksize * 8) { + printk (KERN_ERR + "EXT3-fs: #inodes per group too big: %lu\n", + sbi->s_inodes_per_group); + goto failed_mount; + } + + if (le32_to_cpu(es->s_blocks_count) > + (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { + printk(KERN_ERR "EXT3-fs: filesystem on %s:" + " too large to mount safely\n", sb->s_id); + if (sizeof(sector_t) < 8) + printk(KERN_WARNING "EXT3-fs: CONFIG_LBD not " + "enabled\n"); + goto failed_mount; + } + + if (EXT3_BLOCKS_PER_GROUP(sb) == 0) + goto cantfind_ext3; + sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - + le32_to_cpu(es->s_first_data_block) - 1) + / EXT3_BLOCKS_PER_GROUP(sb)) + 1; + db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) / + EXT3_DESC_PER_BLOCK(sb); + sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), + GFP_KERNEL); + if (sbi->s_group_desc == NULL) { + printk (KERN_ERR "EXT3-fs: not enough memory\n"); + goto failed_mount; + } + + bgl_lock_init(&sbi->s_blockgroup_lock); + + for (i = 0; i < db_count; i++) { + block = descriptor_loc(sb, logic_sb_block, i); + sbi->s_group_desc[i] = sb_bread(sb, block); + if (!sbi->s_group_desc[i]) { + printk (KERN_ERR "EXT3-fs: " + "can't read group descriptor %d\n", i); + db_count = i; + goto failed_mount2; + } + } + if (!ext3_check_descriptors (sb)) { + printk(KERN_ERR "EXT3-fs: group descriptors corrupted!\n"); + goto failed_mount2; + } + sbi->s_gdb_count = db_count; + get_random_bytes(&sbi->s_next_generation, sizeof(u32)); + spin_lock_init(&sbi->s_next_gen_lock); + + percpu_counter_init(&sbi->s_freeblocks_counter, + ext3_count_free_blocks(sb)); + percpu_counter_init(&sbi->s_freeinodes_counter, + ext3_count_free_inodes(sb)); + percpu_counter_init(&sbi->s_dirs_counter, + ext3_count_dirs(sb)); + + /* per fileystem reservation list head & lock */ + spin_lock_init(&sbi->s_rsv_window_lock); + sbi->s_rsv_window_root = RB_ROOT; + /* Add a single, static dummy reservation to the start of the + * reservation window list --- it gives us a placeholder for + * append-at-start-of-list which makes the allocation logic + * _much_ simpler. */ + sbi->s_rsv_window_head.rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + sbi->s_rsv_window_head.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + sbi->s_rsv_window_head.rsv_alloc_hit = 0; + sbi->s_rsv_window_head.rsv_goal_size = 0; + ext3_rsv_window_add(sb, &sbi->s_rsv_window_head); + + /* + * set up enough so that it can read an inode + */ + sb->s_op = &ext3_sops; + sb->s_export_op = &ext3_export_ops; + sb->s_xattr = ext3_xattr_handlers; +#ifdef CONFIG_QUOTA + sb->s_qcop = &ext3_qctl_operations; + sb->dq_op = &ext3_quota_operations; +#endif + INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ + + sb->s_root = NULL; + + needs_recovery = (es->s_last_orphan != 0 || + EXT3_HAS_INCOMPAT_FEATURE(sb, + EXT3_FEATURE_INCOMPAT_RECOVER)); + + /* + * The first inode we look at is the journal inode. Don't try + * root first: it may be modified in the journal! + */ + if (!test_opt(sb, NOLOAD) && + EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { + if (ext3_load_journal(sb, es, journal_devnum)) + goto failed_mount3; + } else if (journal_inum) { + if (ext3_create_journal(sb, es, journal_inum)) + goto failed_mount3; + } else { + if (!silent) + printk (KERN_ERR + "ext3: No journal on filesystem on %s\n", + sb->s_id); + goto failed_mount3; + } + + /* We have now updated the journal if required, so we can + * validate the data journaling mode. */ + switch (test_opt(sb, DATA_FLAGS)) { + case 0: + /* No mode set, assume a default based on the journal + capabilities: ORDERED_DATA if the journal can + cope, else JOURNAL_DATA */ + if (journal_check_available_features + (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) + set_opt(sbi->s_mount_opt, ORDERED_DATA); + else + set_opt(sbi->s_mount_opt, JOURNAL_DATA); + break; + + case EXT3_MOUNT_ORDERED_DATA: + case EXT3_MOUNT_WRITEBACK_DATA: + if (!journal_check_available_features + (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) { + printk(KERN_ERR "EXT3-fs: Journal does not support " + "requested data journaling mode\n"); + goto failed_mount4; + } + default: + break; + } + + if (test_opt(sb, NOBH)) { + if (!(test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)) { + printk(KERN_WARNING "EXT3-fs: Ignoring nobh option - " + "its supported only with writeback mode\n"); + clear_opt(sbi->s_mount_opt, NOBH); + } + } + /* + * The journal_load will have done any necessary log recovery, + * so we can safely mount the rest of the filesystem now. + */ + + root = iget(sb, EXT3_ROOT_INO); + sb->s_root = d_alloc_root(root); + if (!sb->s_root) { + printk(KERN_ERR "EXT3-fs: get root inode failed\n"); + iput(root); + goto failed_mount4; + } + if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { + dput(sb->s_root); + sb->s_root = NULL; + printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n"); + goto failed_mount4; + } + + ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY); + /* + * akpm: core read_super() calls in here with the superblock locked. + * That deadlocks, because orphan cleanup needs to lock the superblock + * in numerous places. Here we just pop the lock - it's relatively + * harmless, because we are now ready to accept write_super() requests, + * and aviro says that's the only reason for hanging onto the + * superblock lock. + */ + EXT3_SB(sb)->s_mount_state |= EXT3_ORPHAN_FS; + ext3_orphan_cleanup(sb, es); + EXT3_SB(sb)->s_mount_state &= ~EXT3_ORPHAN_FS; + if (needs_recovery) + printk (KERN_INFO "EXT3-fs: recovery complete.\n"); + ext3_mark_recovery_complete(sb, es); + printk (KERN_INFO "EXT3-fs: mounted filesystem with %s data mode.\n", + test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal": + test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": + "writeback"); + + lock_kernel(); + return 0; + +cantfind_ext3: + if (!silent) + printk(KERN_ERR "VFS: Can't find ext3 filesystem on dev %s.\n", + sb->s_id); + goto failed_mount; + +failed_mount4: + journal_destroy(sbi->s_journal); +failed_mount3: + percpu_counter_destroy(&sbi->s_freeblocks_counter); + percpu_counter_destroy(&sbi->s_freeinodes_counter); + percpu_counter_destroy(&sbi->s_dirs_counter); +failed_mount2: + for (i = 0; i < db_count; i++) + brelse(sbi->s_group_desc[i]); + kfree(sbi->s_group_desc); +failed_mount: +#ifdef CONFIG_QUOTA + for (i = 0; i < MAXQUOTAS; i++) + kfree(sbi->s_qf_names[i]); +#endif + ext3_blkdev_remove(sbi); + brelse(bh); +out_fail: + sb->s_fs_info = NULL; + kfree(sbi); + lock_kernel(); + return -EINVAL; +} + +/* + * Setup any per-fs journal parameters now. We'll do this both on + * initial mount, once the journal has been initialised but before we've + * done any recovery; and again on any subsequent remount. + */ +static void ext3_init_journal_params(struct super_block *sb, journal_t *journal) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + + if (sbi->s_commit_interval) + journal->j_commit_interval = sbi->s_commit_interval; + /* We could also set up an ext3-specific default for the commit + * interval here, but for now we'll just fall back to the jbd + * default. */ + + spin_lock(&journal->j_state_lock); + if (test_opt(sb, BARRIER)) + journal->j_flags |= JFS_BARRIER; + else + journal->j_flags &= ~JFS_BARRIER; + spin_unlock(&journal->j_state_lock); +} + +static journal_t *ext3_get_journal(struct super_block *sb, + unsigned int journal_inum) +{ + struct inode *journal_inode; + journal_t *journal; + + /* First, test for the existence of a valid inode on disk. Bad + * things happen if we iget() an unused inode, as the subsequent + * iput() will try to delete it. */ + + journal_inode = iget(sb, journal_inum); + if (!journal_inode) { + printk(KERN_ERR "EXT3-fs: no journal found.\n"); + return NULL; + } + if (!journal_inode->i_nlink) { + make_bad_inode(journal_inode); + iput(journal_inode); + printk(KERN_ERR "EXT3-fs: journal inode is deleted.\n"); + return NULL; + } + + jbd_debug(2, "Journal inode found at %p: %Ld bytes\n", + journal_inode, journal_inode->i_size); + if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) { + printk(KERN_ERR "EXT3-fs: invalid journal inode.\n"); + iput(journal_inode); + return NULL; + } + + journal = journal_init_inode(journal_inode); + if (!journal) { + printk(KERN_ERR "EXT3-fs: Could not load journal inode\n"); + iput(journal_inode); + return NULL; + } + journal->j_private = sb; + ext3_init_journal_params(sb, journal); + return journal; +} + +static journal_t *ext3_get_dev_journal(struct super_block *sb, + dev_t j_dev) +{ + struct buffer_head * bh; + journal_t *journal; + ext3_fsblk_t start; + ext3_fsblk_t len; + int hblock, blocksize; + ext3_fsblk_t sb_block; + unsigned long offset; + struct ext3_super_block * es; + struct block_device *bdev; + + bdev = ext3_blkdev_get(j_dev); + if (bdev == NULL) + return NULL; + + if (bd_claim(bdev, sb)) { + printk(KERN_ERR + "EXT3: failed to claim external journal device.\n"); + blkdev_put(bdev); + return NULL; + } + + blocksize = sb->s_blocksize; + hblock = bdev_hardsect_size(bdev); + if (blocksize < hblock) { + printk(KERN_ERR + "EXT3-fs: blocksize too small for journal device.\n"); + goto out_bdev; + } + + sb_block = EXT3_MIN_BLOCK_SIZE / blocksize; + offset = EXT3_MIN_BLOCK_SIZE % blocksize; + set_blocksize(bdev, blocksize); + if (!(bh = __bread(bdev, sb_block, blocksize))) { + printk(KERN_ERR "EXT3-fs: couldn't read superblock of " + "external journal\n"); + goto out_bdev; + } + + es = (struct ext3_super_block *) (((char *)bh->b_data) + offset); + if ((le16_to_cpu(es->s_magic) != EXT3_SUPER_MAGIC) || + !(le32_to_cpu(es->s_feature_incompat) & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { + printk(KERN_ERR "EXT3-fs: external journal has " + "bad superblock\n"); + brelse(bh); + goto out_bdev; + } + + if (memcmp(EXT3_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) { + printk(KERN_ERR "EXT3-fs: journal UUID does not match\n"); + brelse(bh); + goto out_bdev; + } + + len = le32_to_cpu(es->s_blocks_count); + start = sb_block + 1; + brelse(bh); /* we're done with the superblock */ + + journal = journal_init_dev(bdev, sb->s_bdev, + start, len, blocksize); + if (!journal) { + printk(KERN_ERR "EXT3-fs: failed to create device journal\n"); + goto out_bdev; + } + journal->j_private = sb; + ll_rw_block(READ, 1, &journal->j_sb_buffer); + wait_on_buffer(journal->j_sb_buffer); + if (!buffer_uptodate(journal->j_sb_buffer)) { + printk(KERN_ERR "EXT3-fs: I/O error on journal device\n"); + goto out_journal; + } + if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) { + printk(KERN_ERR "EXT3-fs: External journal has more than one " + "user (unsupported) - %d\n", + be32_to_cpu(journal->j_superblock->s_nr_users)); + goto out_journal; + } + EXT3_SB(sb)->journal_bdev = bdev; + ext3_init_journal_params(sb, journal); + return journal; +out_journal: + journal_destroy(journal); +out_bdev: + ext3_blkdev_put(bdev); + return NULL; +} + +static int ext3_load_journal(struct super_block *sb, + struct ext3_super_block *es, + unsigned long journal_devnum) +{ + journal_t *journal; + unsigned int journal_inum = le32_to_cpu(es->s_journal_inum); + dev_t journal_dev; + int err = 0; + int really_read_only; + + if (journal_devnum && + journal_devnum != le32_to_cpu(es->s_journal_dev)) { + printk(KERN_INFO "EXT3-fs: external journal device major/minor " + "numbers have changed\n"); + journal_dev = new_decode_dev(journal_devnum); + } else + journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev)); + + really_read_only = bdev_read_only(sb->s_bdev); + + /* + * Are we loading a blank journal or performing recovery after a + * crash? For recovery, we need to check in advance whether we + * can get read-write access to the device. + */ + + if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) { + if (sb->s_flags & MS_RDONLY) { + printk(KERN_INFO "EXT3-fs: INFO: recovery " + "required on readonly filesystem.\n"); + if (really_read_only) { + printk(KERN_ERR "EXT3-fs: write access " + "unavailable, cannot proceed.\n"); + return -EROFS; + } + printk (KERN_INFO "EXT3-fs: write access will " + "be enabled during recovery.\n"); + } + } + + if (journal_inum && journal_dev) { + printk(KERN_ERR "EXT3-fs: filesystem has both journal " + "and inode journals!\n"); + return -EINVAL; + } + + if (journal_inum) { + if (!(journal = ext3_get_journal(sb, journal_inum))) + return -EINVAL; + } else { + if (!(journal = ext3_get_dev_journal(sb, journal_dev))) + return -EINVAL; + } + + if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) { + err = journal_update_format(journal); + if (err) { + printk(KERN_ERR "EXT3-fs: error updating journal.\n"); + journal_destroy(journal); + return err; + } + } + + if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) + err = journal_wipe(journal, !really_read_only); + if (!err) + err = journal_load(journal); + + if (err) { + printk(KERN_ERR "EXT3-fs: error loading journal.\n"); + journal_destroy(journal); + return err; + } + + EXT3_SB(sb)->s_journal = journal; + ext3_clear_journal_err(sb, es); + + if (journal_devnum && + journal_devnum != le32_to_cpu(es->s_journal_dev)) { + es->s_journal_dev = cpu_to_le32(journal_devnum); + sb->s_dirt = 1; + + /* Make sure we flush the recovery flag to disk. */ + ext3_commit_super(sb, es, 1); + } + + return 0; +} + +static int ext3_create_journal(struct super_block * sb, + struct ext3_super_block * es, + unsigned int journal_inum) +{ + journal_t *journal; + + if (sb->s_flags & MS_RDONLY) { + printk(KERN_ERR "EXT3-fs: readonly filesystem when trying to " + "create journal.\n"); + return -EROFS; + } + + if (!(journal = ext3_get_journal(sb, journal_inum))) + return -EINVAL; + + printk(KERN_INFO "EXT3-fs: creating new journal on inode %u\n", + journal_inum); + + if (journal_create(journal)) { + printk(KERN_ERR "EXT3-fs: error creating journal.\n"); + journal_destroy(journal); + return -EIO; + } + + EXT3_SB(sb)->s_journal = journal; + + ext3_update_dynamic_rev(sb); + EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL); + + es->s_journal_inum = cpu_to_le32(journal_inum); + sb->s_dirt = 1; + + /* Make sure we flush the recovery flag to disk. */ + ext3_commit_super(sb, es, 1); + + return 0; +} + +static void ext3_commit_super (struct super_block * sb, + struct ext3_super_block * es, + int sync) +{ + struct buffer_head *sbh = EXT3_SB(sb)->s_sbh; + + if (!sbh) + return; + es->s_wtime = cpu_to_le32(get_seconds()); + es->s_free_blocks_count = cpu_to_le32(ext3_count_free_blocks(sb)); + es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb)); + BUFFER_TRACE(sbh, "marking dirty"); + mark_buffer_dirty(sbh); + if (sync) + sync_dirty_buffer(sbh); +} + + +/* + * Have we just finished recovery? If so, and if we are mounting (or + * remounting) the filesystem readonly, then we will end up with a + * consistent fs on disk. Record that fact. + */ +static void ext3_mark_recovery_complete(struct super_block * sb, + struct ext3_super_block * es) +{ + journal_t *journal = EXT3_SB(sb)->s_journal; + + journal_lock_updates(journal); + journal_flush(journal); + if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) && + sb->s_flags & MS_RDONLY) { + EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + sb->s_dirt = 0; + ext3_commit_super(sb, es, 1); + } + journal_unlock_updates(journal); +} + +/* + * If we are mounting (or read-write remounting) a filesystem whose journal + * has recorded an error from a previous lifetime, move that error to the + * main filesystem now. + */ +static void ext3_clear_journal_err(struct super_block * sb, + struct ext3_super_block * es) +{ + journal_t *journal; + int j_errno; + const char *errstr; + + journal = EXT3_SB(sb)->s_journal; + + /* + * Now check for any error status which may have been recorded in the + * journal by a prior ext3_error() or ext3_abort() + */ + + j_errno = journal_errno(journal); + if (j_errno) { + char nbuf[16]; + + errstr = ext3_decode_error(sb, j_errno, nbuf); + ext3_warning(sb, __FUNCTION__, "Filesystem error recorded " + "from previous mount: %s", errstr); + ext3_warning(sb, __FUNCTION__, "Marking fs in need of " + "filesystem check."); + + EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; + es->s_state |= cpu_to_le16(EXT3_ERROR_FS); + ext3_commit_super (sb, es, 1); + + journal_clear_err(journal); + } +} + +/* + * Force the running and committing transactions to commit, + * and wait on the commit. + */ +int ext3_force_commit(struct super_block *sb) +{ + journal_t *journal; + int ret; + + if (sb->s_flags & MS_RDONLY) + return 0; + + journal = EXT3_SB(sb)->s_journal; + sb->s_dirt = 0; + ret = ext3_journal_force_commit(journal); + return ret; +} + +/* + * Ext3 always journals updates to the superblock itself, so we don't + * have to propagate any other updates to the superblock on disk at this + * point. Just start an async writeback to get the buffers on their way + * to the disk. + * + * This implicitly triggers the writebehind on sync(). + */ + +static void ext3_write_super (struct super_block * sb) +{ + if (mutex_trylock(&sb->s_lock) != 0) + BUG(); + sb->s_dirt = 0; +} + +static int ext3_sync_fs(struct super_block *sb, int wait) +{ + tid_t target; + + sb->s_dirt = 0; + if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) { + if (wait) + log_wait_commit(EXT3_SB(sb)->s_journal, target); + } + return 0; +} + +/* + * 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. + */ +static void ext3_write_super_lockfs(struct super_block *sb) +{ + sb->s_dirt = 0; + + if (!(sb->s_flags & MS_RDONLY)) { + journal_t *journal = EXT3_SB(sb)->s_journal; + + /* Now we set up the journal barrier. */ + journal_lock_updates(journal); + journal_flush(journal); + + /* Journal blocked and flushed, clear needs_recovery flag. */ + EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); + } +} + +/* + * 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. + */ +static void ext3_unlockfs(struct super_block *sb) +{ + if (!(sb->s_flags & MS_RDONLY)) { + lock_super(sb); + /* Reser the needs_recovery flag before the fs is unlocked. */ + EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); + unlock_super(sb); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + } +} + +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); + ext3_fsblk_t n_blocks_count = 0; + unsigned long old_sb_flags; + struct ext3_mount_options old_opts; + int err; +#ifdef CONFIG_QUOTA + int i; +#endif + + /* Store the original options */ + old_sb_flags = sb->s_flags; + old_opts.s_mount_opt = sbi->s_mount_opt; + old_opts.s_resuid = sbi->s_resuid; + old_opts.s_resgid = sbi->s_resgid; + old_opts.s_commit_interval = sbi->s_commit_interval; +#ifdef CONFIG_QUOTA + old_opts.s_jquota_fmt = sbi->s_jquota_fmt; + for (i = 0; i < MAXQUOTAS; i++) + old_opts.s_qf_names[i] = sbi->s_qf_names[i]; +#endif + + /* + * Allow the "check" option to be passed as a remount option. + */ + if (!parse_options(data, sb, NULL, NULL, &n_blocks_count, 1)) { + err = -EINVAL; + goto restore_opts; + } + + if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) + ext3_abort(sb, __FUNCTION__, "Abort forced by user"); + + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | + ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); + + es = sbi->s_es; + + ext3_init_journal_params(sb, sbi->s_journal); + + if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || + n_blocks_count > le32_to_cpu(es->s_blocks_count)) { + if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) { + err = -EROFS; + goto restore_opts; + } + + if (*flags & MS_RDONLY) { + /* + * First of all, the unconditional stuff we have to do + * to disable replay of the journal when we next remount + */ + sb->s_flags |= MS_RDONLY; + + /* + * OK, test if we are remounting a valid rw partition + * readonly, and if so set the rdonly flag and then + * mark the partition as valid again. + */ + if (!(es->s_state & cpu_to_le16(EXT3_VALID_FS)) && + (sbi->s_mount_state & EXT3_VALID_FS)) + es->s_state = cpu_to_le16(sbi->s_mount_state); + + ext3_mark_recovery_complete(sb, es); + } else { + __le32 ret; + if ((ret = EXT3_HAS_RO_COMPAT_FEATURE(sb, + ~EXT3_FEATURE_RO_COMPAT_SUPP))) { + printk(KERN_WARNING "EXT3-fs: %s: couldn't " + "remount RDWR because of unsupported " + "optional features (%x).\n", + sb->s_id, le32_to_cpu(ret)); + err = -EROFS; + goto restore_opts; + } + /* + * Mounting a RDONLY partition read-write, so reread + * and store the current valid flag. (It may have + * been changed by e2fsck since we originally mounted + * the partition.) + */ + ext3_clear_journal_err(sb, es); + sbi->s_mount_state = le16_to_cpu(es->s_state); + if ((err = ext3_group_extend(sb, es, n_blocks_count))) + goto restore_opts; + if (!ext3_setup_super (sb, es, 0)) + sb->s_flags &= ~MS_RDONLY; + } + } +#ifdef CONFIG_QUOTA + /* Release old quota file names */ + for (i = 0; i < MAXQUOTAS; i++) + if (old_opts.s_qf_names[i] && + old_opts.s_qf_names[i] != sbi->s_qf_names[i]) + kfree(old_opts.s_qf_names[i]); +#endif + return 0; +restore_opts: + sb->s_flags = old_sb_flags; + sbi->s_mount_opt = old_opts.s_mount_opt; + sbi->s_resuid = old_opts.s_resuid; + sbi->s_resgid = old_opts.s_resgid; + sbi->s_commit_interval = old_opts.s_commit_interval; +#ifdef CONFIG_QUOTA + sbi->s_jquota_fmt = old_opts.s_jquota_fmt; + for (i = 0; i < MAXQUOTAS; i++) { + if (sbi->s_qf_names[i] && + old_opts.s_qf_names[i] != sbi->s_qf_names[i]) + kfree(sbi->s_qf_names[i]); + sbi->s_qf_names[i] = old_opts.s_qf_names[i]; + } +#endif + return err; +} + +static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) +{ + struct super_block *sb = dentry->d_sb; + struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext3_super_block *es = sbi->s_es; + ext3_fsblk_t overhead; + int i; + + if (test_opt (sb, MINIX_DF)) + overhead = 0; + else { + unsigned long ngroups; + ngroups = EXT3_SB(sb)->s_groups_count; + smp_rmb(); + + /* + * Compute the overhead (FS structures) + */ + + /* + * All of the blocks before first_data_block are + * overhead + */ + overhead = le32_to_cpu(es->s_first_data_block); + + /* + * Add the overhead attributed to the superblock and + * block group descriptors. If the sparse superblocks + * feature is turned on, then not all groups have this. + */ + for (i = 0; i < ngroups; i++) { + overhead += ext3_bg_has_super(sb, i) + + ext3_bg_num_gdb(sb, i); + cond_resched(); + } + + /* + * Every block group has an inode bitmap, a block + * bitmap, and an inode table. + */ + overhead += (ngroups * (2 + EXT3_SB(sb)->s_itb_per_group)); + } + + buf->f_type = EXT3_SUPER_MAGIC; + buf->f_bsize = sb->s_blocksize; + buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead; + buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); + buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count); + if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count)) + buf->f_bavail = 0; + buf->f_files = le32_to_cpu(es->s_inodes_count); + buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); + buf->f_namelen = EXT3_NAME_LEN; + return 0; +} + +/* Helper function for writing quotas on sync - we need to start transaction before quota file + * is locked for write. Otherwise the are possible deadlocks: + * Process 1 Process 2 + * ext3_create() quota_sync() + * journal_start() write_dquot() + * DQUOT_INIT() down(dqio_mutex) + * down(dqio_mutex) journal_start() + * + */ + +#ifdef CONFIG_QUOTA + +static inline struct inode *dquot_to_inode(struct dquot *dquot) +{ + return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; +} + +static int ext3_dquot_initialize(struct inode *inode, int type) +{ + handle_t *handle; + int ret, err; + + /* We may create quota structure so we need to reserve enough blocks */ + handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + ret = dquot_initialize(inode, type); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; +} + +static int ext3_dquot_drop(struct inode *inode) +{ + handle_t *handle; + int ret, err; + + /* We may delete quota structure so we need to reserve enough blocks */ + handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + ret = dquot_drop(inode); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; +} + +static int ext3_write_dquot(struct dquot *dquot) +{ + int ret, err; + handle_t *handle; + struct inode *inode; + + inode = dquot_to_inode(dquot); + handle = ext3_journal_start(inode, + EXT3_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + ret = dquot_commit(dquot); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; +} + +static int ext3_acquire_dquot(struct dquot *dquot) +{ + int ret, err; + handle_t *handle; + + handle = ext3_journal_start(dquot_to_inode(dquot), + EXT3_QUOTA_INIT_BLOCKS(dquot->dq_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + ret = dquot_acquire(dquot); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; +} + +static int ext3_release_dquot(struct dquot *dquot) +{ + int ret, err; + handle_t *handle; + + handle = ext3_journal_start(dquot_to_inode(dquot), + EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + ret = dquot_release(dquot); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; +} + +static int ext3_mark_dquot_dirty(struct dquot *dquot) +{ + /* Are we journalling quotas? */ + if (EXT3_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || + EXT3_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { + dquot_mark_dquot_dirty(dquot); + return ext3_write_dquot(dquot); + } else { + return dquot_mark_dquot_dirty(dquot); + } +} + +static int ext3_write_info(struct super_block *sb, int type) +{ + int ret, err; + handle_t *handle; + + /* Data block + inode block */ + handle = ext3_journal_start(sb->s_root->d_inode, 2); + if (IS_ERR(handle)) + return PTR_ERR(handle); + ret = dquot_commit_info(sb, type); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; +} + +/* + * Turn on quotas during mount time - we need to find + * the quota file and such... + */ +static int ext3_quota_on_mount(struct super_block *sb, int type) +{ + return vfs_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type], + EXT3_SB(sb)->s_jquota_fmt, type); +} + +/* + * Standard function to be called on quota_on + */ +static int ext3_quota_on(struct super_block *sb, int type, int format_id, + char *path) +{ + int err; + struct nameidata nd; + + if (!test_opt(sb, QUOTA)) + return -EINVAL; + /* Not journalling quota? */ + if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] && + !EXT3_SB(sb)->s_qf_names[GRPQUOTA]) + return vfs_quota_on(sb, type, format_id, path); + err = path_lookup(path, LOOKUP_FOLLOW, &nd); + if (err) + return err; + /* Quotafile not on the same filesystem? */ + if (nd.mnt->mnt_sb != sb) { + path_release(&nd); + return -EXDEV; + } + /* Quotafile not of fs root? */ + if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode) + printk(KERN_WARNING + "EXT3-fs: Quota file not on filesystem root. " + "Journalled quota will not work.\n"); + path_release(&nd); + return vfs_quota_on(sb, type, format_id, path); +} + +/* Read data from quotafile - avoid pagecache and such because we cannot afford + * acquiring the locks... As quota files are never truncated and quota code + * itself serializes the operations (and noone else should touch the files) + * we don't have to be afraid of races */ +static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, + size_t len, loff_t off) +{ + struct inode *inode = sb_dqopt(sb)->files[type]; + sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb); + int err = 0; + int offset = off & (sb->s_blocksize - 1); + int tocopy; + size_t toread; + struct buffer_head *bh; + loff_t i_size = i_size_read(inode); + + if (off > i_size) + return 0; + if (off+len > i_size) + len = i_size-off; + toread = len; + while (toread > 0) { + tocopy = sb->s_blocksize - offset < toread ? + sb->s_blocksize - offset : toread; + bh = ext3_bread(NULL, inode, blk, 0, &err); + if (err) + return err; + if (!bh) /* A hole? */ + memset(data, 0, tocopy); + else + memcpy(data, bh->b_data+offset, tocopy); + brelse(bh); + offset = 0; + toread -= tocopy; + data += tocopy; + blk++; + } + return len; +} + +/* Write to quotafile (we know the transaction is already started and has + * enough credits) */ +static ssize_t ext3_quota_write(struct super_block *sb, int type, + const char *data, size_t len, loff_t off) +{ + struct inode *inode = sb_dqopt(sb)->files[type]; + sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb); + int err = 0; + int offset = off & (sb->s_blocksize - 1); + int tocopy; + int journal_quota = EXT3_SB(sb)->s_qf_names[type] != NULL; + size_t towrite = len; + struct buffer_head *bh; + handle_t *handle = journal_current_handle(); + + mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); + while (towrite > 0) { + tocopy = sb->s_blocksize - offset < towrite ? + sb->s_blocksize - offset : towrite; + bh = ext3_bread(handle, inode, blk, 1, &err); + if (!bh) + goto out; + if (journal_quota) { + err = ext3_journal_get_write_access(handle, bh); + if (err) { + brelse(bh); + goto out; + } + } + lock_buffer(bh); + memcpy(bh->b_data+offset, data, tocopy); + flush_dcache_page(bh->b_page); + unlock_buffer(bh); + if (journal_quota) + err = ext3_journal_dirty_metadata(handle, bh); + else { + /* Always do at least ordered writes for quotas */ + err = ext3_journal_dirty_data(handle, bh); + mark_buffer_dirty(bh); + } + brelse(bh); + if (err) + goto out; + offset = 0; + towrite -= tocopy; + data += tocopy; + blk++; + } +out: + if (len == towrite) + return err; + if (inode->i_size < off+len-towrite) { + i_size_write(inode, off+len-towrite); + EXT3_I(inode)->i_disksize = inode->i_size; + } + inode->i_version++; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + ext3_mark_inode_dirty(handle, inode); + mutex_unlock(&inode->i_mutex); + return len - towrite; +} + +#endif + +static int ext3_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super, mnt); +} + +static struct file_system_type ext3_fs_type = { + .owner = THIS_MODULE, + .name = "ext3", + .get_sb = ext3_get_sb, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, +}; + +static int __init init_ext3_fs(void) +{ + int err = init_ext3_xattr(); + if (err) + return err; + err = init_inodecache(); + if (err) + goto out1; + err = register_filesystem(&ext3_fs_type); + if (err) + goto out; + return 0; +out: + destroy_inodecache(); +out1: + exit_ext3_xattr(); + return err; +} + +static void __exit exit_ext3_fs(void) +{ + unregister_filesystem(&ext3_fs_type); + destroy_inodecache(); + exit_ext3_xattr(); +} + +MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); +MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions"); +MODULE_LICENSE("GPL"); +module_init(init_ext3_fs) +module_exit(exit_ext3_fs) diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c new file mode 100644 index 000000000000..4f79122cde67 --- /dev/null +++ b/fs/ext4/symlink.c @@ -0,0 +1,54 @@ +/* + * linux/fs/ext3/symlink.c + * + * Only fast symlinks left here - the rest is done by generic code. AV, 1999 + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/symlink.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext3 symlink handling code + */ + +#include +#include +#include +#include +#include "xattr.h" + +static void * ext3_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct ext3_inode_info *ei = EXT3_I(dentry->d_inode); + nd_set_link(nd, (char*)ei->i_data); + return NULL; +} + +struct inode_operations ext3_symlink_inode_operations = { + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, +#ifdef CONFIG_EXT3_FS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ext3_listxattr, + .removexattr = generic_removexattr, +#endif +}; + +struct inode_operations ext3_fast_symlink_inode_operations = { + .readlink = generic_readlink, + .follow_link = ext3_follow_link, +#ifdef CONFIG_EXT3_FS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ext3_listxattr, + .removexattr = generic_removexattr, +#endif +}; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c new file mode 100644 index 000000000000..f86f2482f01d --- /dev/null +++ b/fs/ext4/xattr.c @@ -0,0 +1,1317 @@ +/* + * linux/fs/ext3/xattr.c + * + * Copyright (C) 2001-2003 Andreas Gruenbacher, + * + * Fix by Harrison Xing . + * Ext3 code with a lot of help from Eric Jarman . + * Extended attributes for symlinks and special files added per + * suggestion of Luka Renko . + * xattr consolidation Copyright (c) 2004 James Morris , + * Red Hat Inc. + * ea-in-inode support by Alex Tomas aka bzzz + * and Andreas Gruenbacher . + */ + +/* + * Extended attributes are stored directly in inodes (on file systems with + * inodes bigger than 128 bytes) and on additional disk blocks. The i_file_acl + * field contains the block number if an inode uses an additional block. All + * attributes must fit in the inode and one additional block. Blocks that + * contain the identical set of attributes may be shared among several inodes. + * Identical blocks are detected by keeping a cache of blocks that have + * recently been accessed. + * + * The attributes in inodes and on blocks have a different header; the entries + * are stored in the same format: + * + * +------------------+ + * | header | + * | entry 1 | | + * | entry 2 | | growing downwards + * | entry 3 | v + * | four null bytes | + * | . . . | + * | value 1 | ^ + * | value 3 | | growing upwards + * | value 2 | | + * +------------------+ + * + * The header is followed by multiple entry descriptors. In disk blocks, the + * entry descriptors are kept sorted. In inodes, they are unsorted. The + * attribute values are aligned to the end of the block in no specific order. + * + * Locking strategy + * ---------------- + * EXT3_I(inode)->i_file_acl is protected by EXT3_I(inode)->xattr_sem. + * EA blocks are only changed if they are exclusive to an inode, so + * holding xattr_sem also means that nothing but the EA block's reference + * count can change. Multiple writers to the same block are synchronized + * by the buffer lock. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "xattr.h" +#include "acl.h" + +#define BHDR(bh) ((struct ext3_xattr_header *)((bh)->b_data)) +#define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr)) +#define BFIRST(bh) ENTRY(BHDR(bh)+1) +#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) + +#define IHDR(inode, raw_inode) \ + ((struct ext3_xattr_ibody_header *) \ + ((void *)raw_inode + \ + EXT3_GOOD_OLD_INODE_SIZE + \ + EXT3_I(inode)->i_extra_isize)) +#define IFIRST(hdr) ((struct ext3_xattr_entry *)((hdr)+1)) + +#ifdef EXT3_XATTR_DEBUG +# define ea_idebug(inode, f...) do { \ + printk(KERN_DEBUG "inode %s:%lu: ", \ + inode->i_sb->s_id, inode->i_ino); \ + printk(f); \ + printk("\n"); \ + } while (0) +# define ea_bdebug(bh, f...) do { \ + char b[BDEVNAME_SIZE]; \ + printk(KERN_DEBUG "block %s:%lu: ", \ + bdevname(bh->b_bdev, b), \ + (unsigned long) bh->b_blocknr); \ + printk(f); \ + printk("\n"); \ + } while (0) +#else +# define ea_idebug(f...) +# define ea_bdebug(f...) +#endif + +static void ext3_xattr_cache_insert(struct buffer_head *); +static struct buffer_head *ext3_xattr_cache_find(struct inode *, + struct ext3_xattr_header *, + struct mb_cache_entry **); +static void ext3_xattr_rehash(struct ext3_xattr_header *, + struct ext3_xattr_entry *); + +static struct mb_cache *ext3_xattr_cache; + +static struct xattr_handler *ext3_xattr_handler_map[] = { + [EXT3_XATTR_INDEX_USER] = &ext3_xattr_user_handler, +#ifdef CONFIG_EXT3_FS_POSIX_ACL + [EXT3_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext3_xattr_acl_access_handler, + [EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext3_xattr_acl_default_handler, +#endif + [EXT3_XATTR_INDEX_TRUSTED] = &ext3_xattr_trusted_handler, +#ifdef CONFIG_EXT3_FS_SECURITY + [EXT3_XATTR_INDEX_SECURITY] = &ext3_xattr_security_handler, +#endif +}; + +struct xattr_handler *ext3_xattr_handlers[] = { + &ext3_xattr_user_handler, + &ext3_xattr_trusted_handler, +#ifdef CONFIG_EXT3_FS_POSIX_ACL + &ext3_xattr_acl_access_handler, + &ext3_xattr_acl_default_handler, +#endif +#ifdef CONFIG_EXT3_FS_SECURITY + &ext3_xattr_security_handler, +#endif + NULL +}; + +static inline struct xattr_handler * +ext3_xattr_handler(int name_index) +{ + struct xattr_handler *handler = NULL; + + if (name_index > 0 && name_index < ARRAY_SIZE(ext3_xattr_handler_map)) + handler = ext3_xattr_handler_map[name_index]; + return handler; +} + +/* + * Inode operation listxattr() + * + * dentry->d_inode->i_mutex: don't care + */ +ssize_t +ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + return ext3_xattr_list(dentry->d_inode, buffer, size); +} + +static int +ext3_xattr_check_names(struct ext3_xattr_entry *entry, void *end) +{ + while (!IS_LAST_ENTRY(entry)) { + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(entry); + if ((void *)next >= end) + return -EIO; + entry = next; + } + return 0; +} + +static inline int +ext3_xattr_check_block(struct buffer_head *bh) +{ + int error; + + if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || + BHDR(bh)->h_blocks != cpu_to_le32(1)) + return -EIO; + error = ext3_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); + return error; +} + +static inline int +ext3_xattr_check_entry(struct ext3_xattr_entry *entry, size_t size) +{ + size_t value_size = le32_to_cpu(entry->e_value_size); + + if (entry->e_value_block != 0 || value_size > size || + le16_to_cpu(entry->e_value_offs) + value_size > size) + return -EIO; + return 0; +} + +static int +ext3_xattr_find_entry(struct ext3_xattr_entry **pentry, int name_index, + const char *name, size_t size, int sorted) +{ + struct ext3_xattr_entry *entry; + size_t name_len; + int cmp = 1; + + if (name == NULL) + return -EINVAL; + name_len = strlen(name); + entry = *pentry; + for (; !IS_LAST_ENTRY(entry); entry = EXT3_XATTR_NEXT(entry)) { + cmp = name_index - entry->e_name_index; + if (!cmp) + cmp = name_len - entry->e_name_len; + if (!cmp) + cmp = memcmp(name, entry->e_name, name_len); + if (cmp <= 0 && (sorted || cmp == 0)) + break; + } + *pentry = entry; + if (!cmp && ext3_xattr_check_entry(entry, size)) + return -EIO; + return cmp ? -ENODATA : 0; +} + +static int +ext3_xattr_block_get(struct inode *inode, int name_index, const char *name, + void *buffer, size_t buffer_size) +{ + struct buffer_head *bh = NULL; + struct ext3_xattr_entry *entry; + size_t size; + int error; + + ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", + name_index, name, buffer, (long)buffer_size); + + error = -ENODATA; + if (!EXT3_I(inode)->i_file_acl) + goto cleanup; + ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl); + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + if (!bh) + goto cleanup; + ea_bdebug(bh, "b_count=%d, refcount=%d", + atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); + if (ext3_xattr_check_block(bh)) { +bad_block: ext3_error(inode->i_sb, __FUNCTION__, + "inode %lu: bad block "E3FSBLK, inode->i_ino, + EXT3_I(inode)->i_file_acl); + error = -EIO; + goto cleanup; + } + ext3_xattr_cache_insert(bh); + entry = BFIRST(bh); + error = ext3_xattr_find_entry(&entry, name_index, name, bh->b_size, 1); + if (error == -EIO) + goto bad_block; + if (error) + goto cleanup; + size = le32_to_cpu(entry->e_value_size); + if (buffer) { + error = -ERANGE; + if (size > buffer_size) + goto cleanup; + memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), + size); + } + error = size; + +cleanup: + brelse(bh); + return error; +} + +static int +ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name, + void *buffer, size_t buffer_size) +{ + struct ext3_xattr_ibody_header *header; + struct ext3_xattr_entry *entry; + struct ext3_inode *raw_inode; + struct ext3_iloc iloc; + size_t size; + void *end; + int error; + + if (!(EXT3_I(inode)->i_state & EXT3_STATE_XATTR)) + return -ENODATA; + error = ext3_get_inode_loc(inode, &iloc); + if (error) + return error; + raw_inode = ext3_raw_inode(&iloc); + header = IHDR(inode, raw_inode); + entry = IFIRST(header); + end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; + error = ext3_xattr_check_names(entry, end); + if (error) + goto cleanup; + error = ext3_xattr_find_entry(&entry, name_index, name, + end - (void *)entry, 0); + if (error) + goto cleanup; + size = le32_to_cpu(entry->e_value_size); + if (buffer) { + error = -ERANGE; + if (size > buffer_size) + goto cleanup; + memcpy(buffer, (void *)IFIRST(header) + + le16_to_cpu(entry->e_value_offs), size); + } + error = size; + +cleanup: + brelse(iloc.bh); + return error; +} + +/* + * ext3_xattr_get() + * + * Copy an extended attribute into the buffer + * provided, or compute the buffer size required. + * Buffer is NULL to compute the size of the buffer required. + * + * Returns a negative error number on failure, or the number of bytes + * used / required on success. + */ +int +ext3_xattr_get(struct inode *inode, int name_index, const char *name, + void *buffer, size_t buffer_size) +{ + int error; + + down_read(&EXT3_I(inode)->xattr_sem); + error = ext3_xattr_ibody_get(inode, name_index, name, buffer, + buffer_size); + if (error == -ENODATA) + error = ext3_xattr_block_get(inode, name_index, name, buffer, + buffer_size); + up_read(&EXT3_I(inode)->xattr_sem); + return error; +} + +static int +ext3_xattr_list_entries(struct inode *inode, struct ext3_xattr_entry *entry, + char *buffer, size_t buffer_size) +{ + size_t rest = buffer_size; + + for (; !IS_LAST_ENTRY(entry); entry = EXT3_XATTR_NEXT(entry)) { + struct xattr_handler *handler = + ext3_xattr_handler(entry->e_name_index); + + if (handler) { + size_t size = handler->list(inode, buffer, rest, + entry->e_name, + entry->e_name_len); + if (buffer) { + if (size > rest) + return -ERANGE; + buffer += size; + } + rest -= size; + } + } + return buffer_size - rest; +} + +static int +ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size) +{ + struct buffer_head *bh = NULL; + int error; + + ea_idebug(inode, "buffer=%p, buffer_size=%ld", + buffer, (long)buffer_size); + + error = 0; + if (!EXT3_I(inode)->i_file_acl) + goto cleanup; + ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl); + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + error = -EIO; + if (!bh) + goto cleanup; + ea_bdebug(bh, "b_count=%d, refcount=%d", + atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); + if (ext3_xattr_check_block(bh)) { + ext3_error(inode->i_sb, __FUNCTION__, + "inode %lu: bad block "E3FSBLK, inode->i_ino, + EXT3_I(inode)->i_file_acl); + error = -EIO; + goto cleanup; + } + ext3_xattr_cache_insert(bh); + error = ext3_xattr_list_entries(inode, BFIRST(bh), buffer, buffer_size); + +cleanup: + brelse(bh); + + return error; +} + +static int +ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size) +{ + struct ext3_xattr_ibody_header *header; + struct ext3_inode *raw_inode; + struct ext3_iloc iloc; + void *end; + int error; + + if (!(EXT3_I(inode)->i_state & EXT3_STATE_XATTR)) + return 0; + error = ext3_get_inode_loc(inode, &iloc); + if (error) + return error; + raw_inode = ext3_raw_inode(&iloc); + header = IHDR(inode, raw_inode); + end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; + error = ext3_xattr_check_names(IFIRST(header), end); + if (error) + goto cleanup; + error = ext3_xattr_list_entries(inode, IFIRST(header), + buffer, buffer_size); + +cleanup: + brelse(iloc.bh); + return error; +} + +/* + * ext3_xattr_list() + * + * Copy a list of attribute names into the buffer + * provided, or compute the buffer size required. + * Buffer is NULL to compute the size of the buffer required. + * + * Returns a negative error number on failure, or the number of bytes + * used / required on success. + */ +int +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) +{ + int i_error, b_error; + + down_read(&EXT3_I(inode)->xattr_sem); + i_error = ext3_xattr_ibody_list(inode, buffer, buffer_size); + if (i_error < 0) { + b_error = 0; + } else { + if (buffer) { + buffer += i_error; + buffer_size -= i_error; + } + b_error = ext3_xattr_block_list(inode, buffer, buffer_size); + if (b_error < 0) + i_error = 0; + } + up_read(&EXT3_I(inode)->xattr_sem); + return i_error + b_error; +} + +/* + * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is + * not set, set it. + */ +static void ext3_xattr_update_super_block(handle_t *handle, + struct super_block *sb) +{ + if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR)) + return; + + lock_super(sb); + if (ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh) == 0) { + EXT3_SB(sb)->s_es->s_feature_compat |= + cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR); + sb->s_dirt = 1; + ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + } + unlock_super(sb); +} + +/* + * Release the xattr block BH: If the reference count is > 1, decrement + * it; otherwise free the block. + */ +static void +ext3_xattr_release_block(handle_t *handle, struct inode *inode, + struct buffer_head *bh) +{ + struct mb_cache_entry *ce = NULL; + + ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_bdev, bh->b_blocknr); + if (BHDR(bh)->h_refcount == cpu_to_le32(1)) { + ea_bdebug(bh, "refcount now=0; freeing"); + if (ce) + mb_cache_entry_free(ce); + ext3_free_blocks(handle, inode, bh->b_blocknr, 1); + get_bh(bh); + ext3_forget(handle, 1, inode, bh, bh->b_blocknr); + } else { + if (ext3_journal_get_write_access(handle, bh) == 0) { + lock_buffer(bh); + BHDR(bh)->h_refcount = cpu_to_le32( + le32_to_cpu(BHDR(bh)->h_refcount) - 1); + ext3_journal_dirty_metadata(handle, bh); + if (IS_SYNC(inode)) + handle->h_sync = 1; + DQUOT_FREE_BLOCK(inode, 1); + unlock_buffer(bh); + ea_bdebug(bh, "refcount now=%d; releasing", + le32_to_cpu(BHDR(bh)->h_refcount)); + } + if (ce) + mb_cache_entry_release(ce); + } +} + +struct ext3_xattr_info { + int name_index; + const char *name; + const void *value; + size_t value_len; +}; + +struct ext3_xattr_search { + struct ext3_xattr_entry *first; + void *base; + void *end; + struct ext3_xattr_entry *here; + int not_found; +}; + +static int +ext3_xattr_set_entry(struct ext3_xattr_info *i, struct ext3_xattr_search *s) +{ + struct ext3_xattr_entry *last; + size_t free, min_offs = s->end - s->base, name_len = strlen(i->name); + + /* Compute min_offs and last. */ + last = s->first; + for (; !IS_LAST_ENTRY(last); last = EXT3_XATTR_NEXT(last)) { + if (!last->e_value_block && last->e_value_size) { + size_t offs = le16_to_cpu(last->e_value_offs); + if (offs < min_offs) + min_offs = offs; + } + } + free = min_offs - ((void *)last - s->base) - sizeof(__u32); + if (!s->not_found) { + if (!s->here->e_value_block && s->here->e_value_size) { + size_t size = le32_to_cpu(s->here->e_value_size); + free += EXT3_XATTR_SIZE(size); + } + free += EXT3_XATTR_LEN(name_len); + } + if (i->value) { + if (free < EXT3_XATTR_SIZE(i->value_len) || + free < EXT3_XATTR_LEN(name_len) + + EXT3_XATTR_SIZE(i->value_len)) + return -ENOSPC; + } + + if (i->value && s->not_found) { + /* Insert the new name. */ + size_t size = EXT3_XATTR_LEN(name_len); + size_t rest = (void *)last - (void *)s->here + sizeof(__u32); + memmove((void *)s->here + size, s->here, rest); + memset(s->here, 0, size); + s->here->e_name_index = i->name_index; + s->here->e_name_len = name_len; + memcpy(s->here->e_name, i->name, name_len); + } else { + if (!s->here->e_value_block && s->here->e_value_size) { + void *first_val = s->base + min_offs; + size_t offs = le16_to_cpu(s->here->e_value_offs); + void *val = s->base + offs; + size_t size = EXT3_XATTR_SIZE( + le32_to_cpu(s->here->e_value_size)); + + if (i->value && size == EXT3_XATTR_SIZE(i->value_len)) { + /* The old and the new value have the same + size. Just replace. */ + s->here->e_value_size = + cpu_to_le32(i->value_len); + memset(val + size - EXT3_XATTR_PAD, 0, + EXT3_XATTR_PAD); /* Clear pad bytes. */ + memcpy(val, i->value, i->value_len); + return 0; + } + + /* Remove the old value. */ + memmove(first_val + size, first_val, val - first_val); + memset(first_val, 0, size); + s->here->e_value_size = 0; + s->here->e_value_offs = 0; + min_offs += size; + + /* Adjust all value offsets. */ + last = s->first; + while (!IS_LAST_ENTRY(last)) { + size_t o = le16_to_cpu(last->e_value_offs); + if (!last->e_value_block && + last->e_value_size && o < offs) + last->e_value_offs = + cpu_to_le16(o + size); + last = EXT3_XATTR_NEXT(last); + } + } + if (!i->value) { + /* Remove the old name. */ + size_t size = EXT3_XATTR_LEN(name_len); + last = ENTRY((void *)last - size); + memmove(s->here, (void *)s->here + size, + (void *)last - (void *)s->here + sizeof(__u32)); + memset(last, 0, size); + } + } + + if (i->value) { + /* Insert the new value. */ + s->here->e_value_size = cpu_to_le32(i->value_len); + if (i->value_len) { + size_t size = EXT3_XATTR_SIZE(i->value_len); + void *val = s->base + min_offs - size; + s->here->e_value_offs = cpu_to_le16(min_offs - size); + memset(val + size - EXT3_XATTR_PAD, 0, + EXT3_XATTR_PAD); /* Clear the pad bytes. */ + memcpy(val, i->value, i->value_len); + } + } + return 0; +} + +struct ext3_xattr_block_find { + struct ext3_xattr_search s; + struct buffer_head *bh; +}; + +static int +ext3_xattr_block_find(struct inode *inode, struct ext3_xattr_info *i, + struct ext3_xattr_block_find *bs) +{ + struct super_block *sb = inode->i_sb; + int error; + + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", + i->name_index, i->name, i->value, (long)i->value_len); + + if (EXT3_I(inode)->i_file_acl) { + /* The inode already has an extended attribute block. */ + bs->bh = sb_bread(sb, EXT3_I(inode)->i_file_acl); + error = -EIO; + if (!bs->bh) + goto cleanup; + ea_bdebug(bs->bh, "b_count=%d, refcount=%d", + atomic_read(&(bs->bh->b_count)), + le32_to_cpu(BHDR(bs->bh)->h_refcount)); + if (ext3_xattr_check_block(bs->bh)) { + ext3_error(sb, __FUNCTION__, + "inode %lu: bad block "E3FSBLK, inode->i_ino, + EXT3_I(inode)->i_file_acl); + error = -EIO; + goto cleanup; + } + /* Find the named attribute. */ + bs->s.base = BHDR(bs->bh); + bs->s.first = BFIRST(bs->bh); + bs->s.end = bs->bh->b_data + bs->bh->b_size; + bs->s.here = bs->s.first; + error = ext3_xattr_find_entry(&bs->s.here, i->name_index, + i->name, bs->bh->b_size, 1); + if (error && error != -ENODATA) + goto cleanup; + bs->s.not_found = error; + } + error = 0; + +cleanup: + return error; +} + +static int +ext3_xattr_block_set(handle_t *handle, struct inode *inode, + struct ext3_xattr_info *i, + struct ext3_xattr_block_find *bs) +{ + struct super_block *sb = inode->i_sb; + struct buffer_head *new_bh = NULL; + struct ext3_xattr_search *s = &bs->s; + struct mb_cache_entry *ce = NULL; + int error; + +#define header(x) ((struct ext3_xattr_header *)(x)) + + if (i->value && i->value_len > sb->s_blocksize) + return -ENOSPC; + if (s->base) { + ce = mb_cache_entry_get(ext3_xattr_cache, bs->bh->b_bdev, + bs->bh->b_blocknr); + if (header(s->base)->h_refcount == cpu_to_le32(1)) { + if (ce) { + mb_cache_entry_free(ce); + ce = NULL; + } + ea_bdebug(bs->bh, "modifying in-place"); + error = ext3_journal_get_write_access(handle, bs->bh); + if (error) + goto cleanup; + lock_buffer(bs->bh); + error = ext3_xattr_set_entry(i, s); + if (!error) { + if (!IS_LAST_ENTRY(s->first)) + ext3_xattr_rehash(header(s->base), + s->here); + ext3_xattr_cache_insert(bs->bh); + } + unlock_buffer(bs->bh); + if (error == -EIO) + goto bad_block; + if (!error) + error = ext3_journal_dirty_metadata(handle, + bs->bh); + if (error) + goto cleanup; + goto inserted; + } else { + int offset = (char *)s->here - bs->bh->b_data; + + if (ce) { + mb_cache_entry_release(ce); + ce = NULL; + } + ea_bdebug(bs->bh, "cloning"); + s->base = kmalloc(bs->bh->b_size, GFP_KERNEL); + error = -ENOMEM; + if (s->base == NULL) + goto cleanup; + memcpy(s->base, BHDR(bs->bh), bs->bh->b_size); + s->first = ENTRY(header(s->base)+1); + header(s->base)->h_refcount = cpu_to_le32(1); + s->here = ENTRY(s->base + offset); + s->end = s->base + bs->bh->b_size; + } + } else { + /* Allocate a buffer where we construct the new block. */ + s->base = kmalloc(sb->s_blocksize, GFP_KERNEL); + /* assert(header == s->base) */ + error = -ENOMEM; + if (s->base == NULL) + goto cleanup; + memset(s->base, 0, sb->s_blocksize); + header(s->base)->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); + header(s->base)->h_blocks = cpu_to_le32(1); + header(s->base)->h_refcount = cpu_to_le32(1); + s->first = ENTRY(header(s->base)+1); + s->here = ENTRY(header(s->base)+1); + s->end = s->base + sb->s_blocksize; + } + + error = ext3_xattr_set_entry(i, s); + if (error == -EIO) + goto bad_block; + if (error) + goto cleanup; + if (!IS_LAST_ENTRY(s->first)) + ext3_xattr_rehash(header(s->base), s->here); + +inserted: + if (!IS_LAST_ENTRY(s->first)) { + new_bh = ext3_xattr_cache_find(inode, header(s->base), &ce); + if (new_bh) { + /* We found an identical block in the cache. */ + if (new_bh == bs->bh) + ea_bdebug(new_bh, "keeping"); + else { + /* The old block is released after updating + the inode. */ + error = -EDQUOT; + if (DQUOT_ALLOC_BLOCK(inode, 1)) + goto cleanup; + error = ext3_journal_get_write_access(handle, + new_bh); + if (error) + goto cleanup_dquot; + lock_buffer(new_bh); + BHDR(new_bh)->h_refcount = cpu_to_le32(1 + + le32_to_cpu(BHDR(new_bh)->h_refcount)); + ea_bdebug(new_bh, "reusing; refcount now=%d", + le32_to_cpu(BHDR(new_bh)->h_refcount)); + unlock_buffer(new_bh); + error = ext3_journal_dirty_metadata(handle, + new_bh); + if (error) + goto cleanup_dquot; + } + mb_cache_entry_release(ce); + ce = NULL; + } else if (bs->bh && s->base == bs->bh->b_data) { + /* We were modifying this block in-place. */ + ea_bdebug(bs->bh, "keeping this block"); + new_bh = bs->bh; + get_bh(new_bh); + } else { + /* We need to allocate a new block */ + ext3_fsblk_t goal = le32_to_cpu( + EXT3_SB(sb)->s_es->s_first_data_block) + + (ext3_fsblk_t)EXT3_I(inode)->i_block_group * + EXT3_BLOCKS_PER_GROUP(sb); + ext3_fsblk_t block = ext3_new_block(handle, inode, + goal, &error); + if (error) + goto cleanup; + ea_idebug(inode, "creating block %d", block); + + new_bh = sb_getblk(sb, block); + if (!new_bh) { +getblk_failed: + ext3_free_blocks(handle, inode, block, 1); + error = -EIO; + goto cleanup; + } + lock_buffer(new_bh); + error = ext3_journal_get_create_access(handle, new_bh); + if (error) { + unlock_buffer(new_bh); + goto getblk_failed; + } + memcpy(new_bh->b_data, s->base, new_bh->b_size); + set_buffer_uptodate(new_bh); + unlock_buffer(new_bh); + ext3_xattr_cache_insert(new_bh); + error = ext3_journal_dirty_metadata(handle, new_bh); + if (error) + goto cleanup; + } + } + + /* Update the inode. */ + EXT3_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; + + /* Drop the previous xattr block. */ + if (bs->bh && bs->bh != new_bh) + ext3_xattr_release_block(handle, inode, bs->bh); + error = 0; + +cleanup: + if (ce) + mb_cache_entry_release(ce); + brelse(new_bh); + if (!(bs->bh && s->base == bs->bh->b_data)) + kfree(s->base); + + return error; + +cleanup_dquot: + DQUOT_FREE_BLOCK(inode, 1); + goto cleanup; + +bad_block: + ext3_error(inode->i_sb, __FUNCTION__, + "inode %lu: bad block "E3FSBLK, inode->i_ino, + EXT3_I(inode)->i_file_acl); + goto cleanup; + +#undef header +} + +struct ext3_xattr_ibody_find { + struct ext3_xattr_search s; + struct ext3_iloc iloc; +}; + +static int +ext3_xattr_ibody_find(struct inode *inode, struct ext3_xattr_info *i, + struct ext3_xattr_ibody_find *is) +{ + struct ext3_xattr_ibody_header *header; + struct ext3_inode *raw_inode; + int error; + + if (EXT3_I(inode)->i_extra_isize == 0) + return 0; + raw_inode = ext3_raw_inode(&is->iloc); + header = IHDR(inode, raw_inode); + is->s.base = is->s.first = IFIRST(header); + is->s.here = is->s.first; + is->s.end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; + if (EXT3_I(inode)->i_state & EXT3_STATE_XATTR) { + error = ext3_xattr_check_names(IFIRST(header), is->s.end); + if (error) + return error; + /* Find the named attribute. */ + error = ext3_xattr_find_entry(&is->s.here, i->name_index, + i->name, is->s.end - + (void *)is->s.base, 0); + if (error && error != -ENODATA) + return error; + is->s.not_found = error; + } + return 0; +} + +static int +ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, + struct ext3_xattr_info *i, + struct ext3_xattr_ibody_find *is) +{ + struct ext3_xattr_ibody_header *header; + struct ext3_xattr_search *s = &is->s; + int error; + + if (EXT3_I(inode)->i_extra_isize == 0) + return -ENOSPC; + error = ext3_xattr_set_entry(i, s); + if (error) + return error; + header = IHDR(inode, ext3_raw_inode(&is->iloc)); + if (!IS_LAST_ENTRY(s->first)) { + header->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); + EXT3_I(inode)->i_state |= EXT3_STATE_XATTR; + } else { + header->h_magic = cpu_to_le32(0); + EXT3_I(inode)->i_state &= ~EXT3_STATE_XATTR; + } + 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) +{ + struct ext3_xattr_info i = { + .name_index = name_index, + .name = name, + .value = value, + .value_len = value_len, + + }; + struct ext3_xattr_ibody_find is = { + .s = { .not_found = -ENODATA, }, + }; + struct ext3_xattr_block_find bs = { + .s = { .not_found = -ENODATA, }, + }; + int error; + + if (!name) + return -EINVAL; + if (strlen(name) > 255) + return -ERANGE; + down_write(&EXT3_I(inode)->xattr_sem); + error = ext3_get_inode_loc(inode, &is.iloc); + if (error) + goto cleanup; + + if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) { + struct ext3_inode *raw_inode = ext3_raw_inode(&is.iloc); + memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size); + EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW; + } + + error = ext3_xattr_ibody_find(inode, &i, &is); + if (error) + goto cleanup; + if (is.s.not_found) + error = ext3_xattr_block_find(inode, &i, &bs); + if (error) + goto cleanup; + if (is.s.not_found && bs.s.not_found) { + error = -ENODATA; + if (flags & XATTR_REPLACE) + goto cleanup; + error = 0; + if (!value) + goto cleanup; + } else { + error = -EEXIST; + if (flags & XATTR_CREATE) + goto cleanup; + } + error = ext3_journal_get_write_access(handle, is.iloc.bh); + if (error) + goto cleanup; + if (!value) { + if (!is.s.not_found) + error = ext3_xattr_ibody_set(handle, inode, &i, &is); + else if (!bs.s.not_found) + error = ext3_xattr_block_set(handle, inode, &i, &bs); + } else { + error = ext3_xattr_ibody_set(handle, inode, &i, &is); + if (!error && !bs.s.not_found) { + i.value = NULL; + error = ext3_xattr_block_set(handle, inode, &i, &bs); + } else if (error == -ENOSPC) { + error = ext3_xattr_block_set(handle, inode, &i, &bs); + if (error) + goto cleanup; + if (!is.s.not_found) { + i.value = NULL; + error = ext3_xattr_ibody_set(handle, inode, &i, + &is); + } + } + } + if (!error) { + ext3_xattr_update_super_block(handle, inode->i_sb); + inode->i_ctime = CURRENT_TIME_SEC; + error = ext3_mark_iloc_dirty(handle, inode, &is.iloc); + /* + * The bh is consumed by ext3_mark_iloc_dirty, even with + * error != 0. + */ + is.iloc.bh = NULL; + if (IS_SYNC(inode)) + handle->h_sync = 1; + } + +cleanup: + brelse(is.iloc.bh); + brelse(bs.bh); + up_write(&EXT3_I(inode)->xattr_sem); + return error; +} + +/* + * ext3_xattr_set() + * + * Like ext3_xattr_set_handle, but start from an inode. This extended + * attribute modification is a filesystem transaction by itself. + * + * Returns 0, or a negative error number on failure. + */ +int +ext3_xattr_set(struct inode *inode, int name_index, const char *name, + const void *value, size_t value_len, int flags) +{ + handle_t *handle; + int error, retries = 0; + +retry: + handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); + if (IS_ERR(handle)) { + error = PTR_ERR(handle); + } else { + int error2; + + error = ext3_xattr_set_handle(handle, inode, name_index, name, + value, value_len, flags); + error2 = ext3_journal_stop(handle); + if (error == -ENOSPC && + ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; + if (error == 0) + error = error2; + } + + return error; +} + +/* + * ext3_xattr_delete_inode() + * + * Free extended attribute resources associated with this inode. This + * is called immediately before an inode is freed. We have exclusive + * access to the inode. + */ +void +ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) +{ + struct buffer_head *bh = NULL; + + if (!EXT3_I(inode)->i_file_acl) + goto cleanup; + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + if (!bh) { + ext3_error(inode->i_sb, __FUNCTION__, + "inode %lu: block "E3FSBLK" read error", inode->i_ino, + EXT3_I(inode)->i_file_acl); + goto cleanup; + } + if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || + BHDR(bh)->h_blocks != cpu_to_le32(1)) { + ext3_error(inode->i_sb, __FUNCTION__, + "inode %lu: bad block "E3FSBLK, inode->i_ino, + EXT3_I(inode)->i_file_acl); + goto cleanup; + } + ext3_xattr_release_block(handle, inode, bh); + EXT3_I(inode)->i_file_acl = 0; + +cleanup: + brelse(bh); +} + +/* + * ext3_xattr_put_super() + * + * This is called when a file system is unmounted. + */ +void +ext3_xattr_put_super(struct super_block *sb) +{ + mb_cache_shrink(sb->s_bdev); +} + +/* + * ext3_xattr_cache_insert() + * + * Create a new entry in the extended attribute cache, and insert + * it unless such an entry is already in the cache. + * + * Returns 0, or a negative error number on failure. + */ +static void +ext3_xattr_cache_insert(struct buffer_head *bh) +{ + __u32 hash = le32_to_cpu(BHDR(bh)->h_hash); + struct mb_cache_entry *ce; + int error; + + ce = mb_cache_entry_alloc(ext3_xattr_cache); + if (!ce) { + ea_bdebug(bh, "out of memory"); + return; + } + error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash); + if (error) { + mb_cache_entry_free(ce); + if (error == -EBUSY) { + ea_bdebug(bh, "already in cache"); + error = 0; + } + } else { + ea_bdebug(bh, "inserting [%x]", (int)hash); + mb_cache_entry_release(ce); + } +} + +/* + * ext3_xattr_cmp() + * + * Compare two extended attribute blocks for equality. + * + * Returns 0 if the blocks are equal, 1 if they differ, and + * a negative error number on errors. + */ +static int +ext3_xattr_cmp(struct ext3_xattr_header *header1, + struct ext3_xattr_header *header2) +{ + struct ext3_xattr_entry *entry1, *entry2; + + entry1 = ENTRY(header1+1); + entry2 = ENTRY(header2+1); + while (!IS_LAST_ENTRY(entry1)) { + if (IS_LAST_ENTRY(entry2)) + return 1; + if (entry1->e_hash != entry2->e_hash || + entry1->e_name_index != entry2->e_name_index || + entry1->e_name_len != entry2->e_name_len || + entry1->e_value_size != entry2->e_value_size || + memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) + return 1; + if (entry1->e_value_block != 0 || entry2->e_value_block != 0) + return -EIO; + if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), + (char *)header2 + le16_to_cpu(entry2->e_value_offs), + le32_to_cpu(entry1->e_value_size))) + return 1; + + entry1 = EXT3_XATTR_NEXT(entry1); + entry2 = EXT3_XATTR_NEXT(entry2); + } + if (!IS_LAST_ENTRY(entry2)) + return 1; + return 0; +} + +/* + * ext3_xattr_cache_find() + * + * Find an identical extended attribute block. + * + * Returns a pointer to the block found, or NULL if such a block was + * not found or an error occurred. + */ +static struct buffer_head * +ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header, + struct mb_cache_entry **pce) +{ + __u32 hash = le32_to_cpu(header->h_hash); + struct mb_cache_entry *ce; + + if (!header->h_hash) + return NULL; /* never share */ + ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); +again: + ce = mb_cache_entry_find_first(ext3_xattr_cache, 0, + inode->i_sb->s_bdev, hash); + while (ce) { + struct buffer_head *bh; + + if (IS_ERR(ce)) { + if (PTR_ERR(ce) == -EAGAIN) + goto again; + break; + } + bh = sb_bread(inode->i_sb, ce->e_block); + if (!bh) { + ext3_error(inode->i_sb, __FUNCTION__, + "inode %lu: block %lu read error", + inode->i_ino, (unsigned long) ce->e_block); + } else if (le32_to_cpu(BHDR(bh)->h_refcount) >= + EXT3_XATTR_REFCOUNT_MAX) { + ea_idebug(inode, "block %lu refcount %d>=%d", + (unsigned long) ce->e_block, + le32_to_cpu(BHDR(bh)->h_refcount), + EXT3_XATTR_REFCOUNT_MAX); + } else if (ext3_xattr_cmp(header, BHDR(bh)) == 0) { + *pce = ce; + return bh; + } + brelse(bh); + ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash); + } + return NULL; +} + +#define NAME_HASH_SHIFT 5 +#define VALUE_HASH_SHIFT 16 + +/* + * ext3_xattr_hash_entry() + * + * Compute the hash of an extended attribute. + */ +static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header, + struct ext3_xattr_entry *entry) +{ + __u32 hash = 0; + char *name = entry->e_name; + int n; + + for (n=0; n < entry->e_name_len; n++) { + hash = (hash << NAME_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ + *name++; + } + + if (entry->e_value_block == 0 && entry->e_value_size != 0) { + __le32 *value = (__le32 *)((char *)header + + le16_to_cpu(entry->e_value_offs)); + for (n = (le32_to_cpu(entry->e_value_size) + + EXT3_XATTR_ROUND) >> EXT3_XATTR_PAD_BITS; n; n--) { + hash = (hash << VALUE_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ + le32_to_cpu(*value++); + } + } + entry->e_hash = cpu_to_le32(hash); +} + +#undef NAME_HASH_SHIFT +#undef VALUE_HASH_SHIFT + +#define BLOCK_HASH_SHIFT 16 + +/* + * ext3_xattr_rehash() + * + * Re-compute the extended attribute hash value after an entry has changed. + */ +static void ext3_xattr_rehash(struct ext3_xattr_header *header, + struct ext3_xattr_entry *entry) +{ + struct ext3_xattr_entry *here; + __u32 hash = 0; + + ext3_xattr_hash_entry(header, entry); + here = ENTRY(header+1); + while (!IS_LAST_ENTRY(here)) { + if (!here->e_hash) { + /* Block is not shared if an entry's hash value == 0 */ + hash = 0; + break; + } + hash = (hash << BLOCK_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ + le32_to_cpu(here->e_hash); + here = EXT3_XATTR_NEXT(here); + } + header->h_hash = cpu_to_le32(hash); +} + +#undef BLOCK_HASH_SHIFT + +int __init +init_ext3_xattr(void) +{ + ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL, + sizeof(struct mb_cache_entry) + + sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6); + if (!ext3_xattr_cache) + return -ENOMEM; + return 0; +} + +void +exit_ext3_xattr(void) +{ + if (ext3_xattr_cache) + mb_cache_destroy(ext3_xattr_cache); + ext3_xattr_cache = NULL; +} diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h new file mode 100644 index 000000000000..6b1ae1c6182c --- /dev/null +++ b/fs/ext4/xattr.h @@ -0,0 +1,145 @@ +/* + File: fs/ext3/xattr.h + + On-disk format of extended attributes for the ext3 filesystem. + + (C) 2001 Andreas Gruenbacher, +*/ + +#include + +/* Magic value in attribute blocks */ +#define EXT3_XATTR_MAGIC 0xEA020000 + +/* Maximum number of references to one attribute block */ +#define EXT3_XATTR_REFCOUNT_MAX 1024 + +/* Name indexes */ +#define EXT3_XATTR_INDEX_USER 1 +#define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS 2 +#define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT 3 +#define EXT3_XATTR_INDEX_TRUSTED 4 +#define EXT3_XATTR_INDEX_LUSTRE 5 +#define EXT3_XATTR_INDEX_SECURITY 6 + +struct ext3_xattr_header { + __le32 h_magic; /* magic number for identification */ + __le32 h_refcount; /* reference count */ + __le32 h_blocks; /* number of disk blocks used */ + __le32 h_hash; /* hash value of all attributes */ + __u32 h_reserved[4]; /* zero right now */ +}; + +struct ext3_xattr_ibody_header { + __le32 h_magic; /* magic number for identification */ +}; + +struct ext3_xattr_entry { + __u8 e_name_len; /* length of name */ + __u8 e_name_index; /* attribute name index */ + __le16 e_value_offs; /* offset in disk block of value */ + __le32 e_value_block; /* disk block attribute is stored on (n/i) */ + __le32 e_value_size; /* size of attribute value */ + __le32 e_hash; /* hash value of name and value */ + char e_name[0]; /* attribute name */ +}; + +#define EXT3_XATTR_PAD_BITS 2 +#define EXT3_XATTR_PAD (1<e_name_len)) ) +#define EXT3_XATTR_SIZE(size) \ + (((size) + EXT3_XATTR_ROUND) & ~EXT3_XATTR_ROUND) + +# ifdef CONFIG_EXT3_FS_XATTR + +extern struct xattr_handler ext3_xattr_user_handler; +extern struct xattr_handler ext3_xattr_trusted_handler; +extern struct xattr_handler ext3_xattr_acl_access_handler; +extern struct xattr_handler ext3_xattr_acl_default_handler; +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 void ext3_xattr_delete_inode(handle_t *, struct inode *); +extern void ext3_xattr_put_super(struct super_block *); + +extern int init_ext3_xattr(void); +extern void exit_ext3_xattr(void); + +extern struct xattr_handler *ext3_xattr_handlers[]; + +# else /* CONFIG_EXT3_FS_XATTR */ + +static inline int +ext3_xattr_get(struct inode *inode, int name_index, const char *name, + void *buffer, size_t size, int flags) +{ + 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) +{ + return -EOPNOTSUPP; +} + +static inline int +ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, + const char *name, const void *value, size_t size, int flags) +{ + return -EOPNOTSUPP; +} + +static inline void +ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) +{ +} + +static inline void +ext3_xattr_put_super(struct super_block *sb) +{ +} + +static inline int +init_ext3_xattr(void) +{ + return 0; +} + +static inline void +exit_ext3_xattr(void) +{ +} + +#define ext3_xattr_handlers NULL + +# endif /* CONFIG_EXT3_FS_XATTR */ + +#ifdef CONFIG_EXT3_FS_SECURITY +extern int ext3_init_security(handle_t *handle, struct inode *inode, + struct inode *dir); +#else +static inline int ext3_init_security(handle_t *handle, struct inode *inode, + struct inode *dir) +{ + return 0; +} +#endif diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c new file mode 100644 index 000000000000..b9c40c15647b --- /dev/null +++ b/fs/ext4/xattr_security.c @@ -0,0 +1,77 @@ +/* + * linux/fs/ext3/xattr_security.c + * Handler for storing security labels as extended attributes. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "xattr.h" + +static size_t +ext3_xattr_security_list(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) +{ + const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1; + const size_t total_len = prefix_len + name_len + 1; + + + if (list && total_len <= list_size) { + memcpy(list, XATTR_SECURITY_PREFIX, prefix_len); + memcpy(list+prefix_len, name, name_len); + list[prefix_len + name_len] = '\0'; + } + return total_len; +} + +static int +ext3_xattr_security_get(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return ext3_xattr_get(inode, EXT3_XATTR_INDEX_SECURITY, name, + buffer, size); +} + +static int +ext3_xattr_security_set(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return ext3_xattr_set(inode, EXT3_XATTR_INDEX_SECURITY, name, + value, size, flags); +} + +int +ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir) +{ + int err; + size_t len; + void *value; + char *name; + + err = security_inode_init_security(inode, dir, &name, &value, &len); + if (err) { + if (err == -EOPNOTSUPP) + return 0; + return err; + } + err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY, + name, value, len, 0); + kfree(name); + kfree(value); + return err; +} + +struct xattr_handler ext3_xattr_security_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .list = ext3_xattr_security_list, + .get = ext3_xattr_security_get, + .set = ext3_xattr_security_set, +}; diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c new file mode 100644 index 000000000000..86d91f1186dc --- /dev/null +++ b/fs/ext4/xattr_trusted.c @@ -0,0 +1,62 @@ +/* + * linux/fs/ext3/xattr_trusted.c + * Handler for trusted extended attributes. + * + * Copyright (C) 2003 by Andreas Gruenbacher, + */ + +#include +#include +#include +#include +#include +#include +#include +#include "xattr.h" + +#define XATTR_TRUSTED_PREFIX "trusted." + +static size_t +ext3_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) +{ + const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX)-1; + const size_t total_len = prefix_len + name_len + 1; + + if (!capable(CAP_SYS_ADMIN)) + return 0; + + if (list && total_len <= list_size) { + memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len); + memcpy(list+prefix_len, name, name_len); + list[prefix_len + name_len] = '\0'; + } + return total_len; +} + +static int +ext3_xattr_trusted_get(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return ext3_xattr_get(inode, EXT3_XATTR_INDEX_TRUSTED, name, + buffer, size); +} + +static int +ext3_xattr_trusted_set(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return ext3_xattr_set(inode, EXT3_XATTR_INDEX_TRUSTED, name, + value, size, flags); +} + +struct xattr_handler ext3_xattr_trusted_handler = { + .prefix = XATTR_TRUSTED_PREFIX, + .list = ext3_xattr_trusted_list, + .get = ext3_xattr_trusted_get, + .set = ext3_xattr_trusted_set, +}; diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c new file mode 100644 index 000000000000..a85a0a17c4fd --- /dev/null +++ b/fs/ext4/xattr_user.c @@ -0,0 +1,64 @@ +/* + * linux/fs/ext3/xattr_user.c + * Handler for extended user attributes. + * + * Copyright (C) 2001 by Andreas Gruenbacher, + */ + +#include +#include +#include +#include +#include +#include +#include "xattr.h" + +#define XATTR_USER_PREFIX "user." + +static size_t +ext3_xattr_user_list(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) +{ + const size_t prefix_len = sizeof(XATTR_USER_PREFIX)-1; + const size_t total_len = prefix_len + name_len + 1; + + if (!test_opt(inode->i_sb, XATTR_USER)) + return 0; + + if (list && total_len <= list_size) { + memcpy(list, XATTR_USER_PREFIX, prefix_len); + memcpy(list+prefix_len, name, name_len); + list[prefix_len + name_len] = '\0'; + } + return total_len; +} + +static int +ext3_xattr_user_get(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + if (!test_opt(inode->i_sb, XATTR_USER)) + return -EOPNOTSUPP; + return ext3_xattr_get(inode, EXT3_XATTR_INDEX_USER, name, buffer, size); +} + +static int +ext3_xattr_user_set(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + if (!test_opt(inode->i_sb, XATTR_USER)) + return -EOPNOTSUPP; + return ext3_xattr_set(inode, EXT3_XATTR_INDEX_USER, name, + value, size, flags); +} + +struct xattr_handler ext3_xattr_user_handler = { + .prefix = XATTR_USER_PREFIX, + .list = ext3_xattr_user_list, + .get = ext3_xattr_user_get, + .set = ext3_xattr_user_set, +}; diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h new file mode 100644 index 000000000000..11cca1bdc0c7 --- /dev/null +++ b/include/linux/ext4_fs.h @@ -0,0 +1,885 @@ +/* + * linux/include/linux/ext3_fs.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT3_FS_H +#define _LINUX_EXT3_FS_H + +#include +#include + +/* + * The second extended filesystem constants/structures + */ + +/* + * Define EXT3FS_DEBUG to produce debug messages + */ +#undef EXT3FS_DEBUG + +/* + * Define EXT3_RESERVATION to reserve data blocks for expanding files + */ +#define EXT3_DEFAULT_RESERVE_BLOCKS 8 +/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */ +#define EXT3_MAX_RESERVE_BLOCKS 1027 +#define EXT3_RESERVE_WINDOW_NOT_ALLOCATED 0 +/* + * Always enable hashed directories + */ +#define CONFIG_EXT3_INDEX + +/* + * Debug code + */ +#ifdef EXT3FS_DEBUG +#define ext3_debug(f, a...) \ + do { \ + printk (KERN_DEBUG "EXT3-fs DEBUG (%s, %d): %s:", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (KERN_DEBUG f, ## a); \ + } while (0) +#else +#define ext3_debug(f, a...) do {} while (0) +#endif + +/* + * Special inodes numbers + */ +#define EXT3_BAD_INO 1 /* Bad blocks inode */ +#define EXT3_ROOT_INO 2 /* Root inode */ +#define EXT3_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT3_UNDEL_DIR_INO 6 /* Undelete directory inode */ +#define EXT3_RESIZE_INO 7 /* Reserved group descriptors inode */ +#define EXT3_JOURNAL_INO 8 /* Journal inode */ + +/* First non-reserved inode for old ext3 filesystems */ +#define EXT3_GOOD_OLD_FIRST_INO 11 + +/* + * Maximal count of links to a file + */ +#define EXT3_LINK_MAX 32000 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT3_MIN_BLOCK_SIZE 1024 +#define EXT3_MAX_BLOCK_SIZE 4096 +#define EXT3_MIN_BLOCK_LOG_SIZE 10 +#ifdef __KERNEL__ +# define EXT3_BLOCK_SIZE(s) ((s)->s_blocksize) +#else +# define EXT3_BLOCK_SIZE(s) (EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#endif +#define EXT3_ADDR_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (__u32)) +#ifdef __KERNEL__ +# define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) +#else +# define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#endif +#ifdef __KERNEL__ +#define EXT3_ADDR_PER_BLOCK_BITS(s) (EXT3_SB(s)->s_addr_per_block_bits) +#define EXT3_INODE_SIZE(s) (EXT3_SB(s)->s_inode_size) +#define EXT3_FIRST_INO(s) (EXT3_SB(s)->s_first_ino) +#else +#define EXT3_INODE_SIZE(s) (((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \ + EXT3_GOOD_OLD_INODE_SIZE : \ + (s)->s_inode_size) +#define EXT3_FIRST_INO(s) (((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \ + EXT3_GOOD_OLD_FIRST_INO : \ + (s)->s_first_ino) +#endif + +/* + * Macro-instructions used to manage fragments + */ +#define EXT3_MIN_FRAG_SIZE 1024 +#define EXT3_MAX_FRAG_SIZE 4096 +#define EXT3_MIN_FRAG_LOG_SIZE 10 +#ifdef __KERNEL__ +# define EXT3_FRAG_SIZE(s) (EXT3_SB(s)->s_frag_size) +# define EXT3_FRAGS_PER_BLOCK(s) (EXT3_SB(s)->s_frags_per_block) +#else +# define EXT3_FRAG_SIZE(s) (EXT3_MIN_FRAG_SIZE << (s)->s_log_frag_size) +# define EXT3_FRAGS_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / EXT3_FRAG_SIZE(s)) +#endif + +/* + * Structure of a blocks group descriptor + */ +struct ext3_group_desc +{ + __le32 bg_block_bitmap; /* Blocks bitmap block */ + __le32 bg_inode_bitmap; /* Inodes bitmap block */ + __le32 bg_inode_table; /* Inodes table block */ + __le16 bg_free_blocks_count; /* Free blocks count */ + __le16 bg_free_inodes_count; /* Free inodes count */ + __le16 bg_used_dirs_count; /* Directories count */ + __u16 bg_pad; + __le32 bg_reserved[3]; +}; + +/* + * Macro-instructions used to manage group descriptors + */ +#ifdef __KERNEL__ +# define EXT3_BLOCKS_PER_GROUP(s) (EXT3_SB(s)->s_blocks_per_group) +# define EXT3_DESC_PER_BLOCK(s) (EXT3_SB(s)->s_desc_per_block) +# define EXT3_INODES_PER_GROUP(s) (EXT3_SB(s)->s_inodes_per_group) +# define EXT3_DESC_PER_BLOCK_BITS(s) (EXT3_SB(s)->s_desc_per_block_bits) +#else +# define EXT3_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +# define EXT3_DESC_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_group_desc)) +# define EXT3_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) +#endif + +/* + * Constants relative to the data blocks + */ +#define EXT3_NDIR_BLOCKS 12 +#define EXT3_IND_BLOCK EXT3_NDIR_BLOCKS +#define EXT3_DIND_BLOCK (EXT3_IND_BLOCK + 1) +#define EXT3_TIND_BLOCK (EXT3_DIND_BLOCK + 1) +#define EXT3_N_BLOCKS (EXT3_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define EXT3_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT3_UNRM_FL 0x00000002 /* Undelete */ +#define EXT3_COMPR_FL 0x00000004 /* Compress file */ +#define EXT3_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT3_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT3_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT3_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT3_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define EXT3_DIRTY_FL 0x00000100 +#define EXT3_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define EXT3_NOCOMPR_FL 0x00000400 /* Don't compress */ +#define EXT3_ECOMPR_FL 0x00000800 /* Compression error */ +/* End compression flags --- maybe not all used */ +#define EXT3_INDEX_FL 0x00001000 /* hash-indexed directory */ +#define EXT3_IMAGIC_FL 0x00002000 /* AFS directory */ +#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */ +#define EXT3_NOTAIL_FL 0x00008000 /* file tail should not be merged */ +#define EXT3_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ +#define EXT3_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define EXT3_RESERVED_FL 0x80000000 /* reserved for ext3 lib */ + +#define EXT3_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ +#define EXT3_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ + +/* + * Inode dynamic state flags + */ +#define EXT3_STATE_JDATA 0x00000001 /* journaled data exists */ +#define EXT3_STATE_NEW 0x00000002 /* inode is newly created */ +#define EXT3_STATE_XATTR 0x00000004 /* has in-inode xattrs */ + +/* Used to pass group descriptor data when online resize is done */ +struct ext3_new_group_input { + __u32 group; /* Group number for this data */ + __u32 block_bitmap; /* Absolute block number of block bitmap */ + __u32 inode_bitmap; /* Absolute block number of inode bitmap */ + __u32 inode_table; /* Absolute block number of inode table start */ + __u32 blocks_count; /* Total number of blocks in this group */ + __u16 reserved_blocks; /* Number of reserved blocks in this group */ + __u16 unused; +}; + +/* The struct ext3_new_group_input in kernel space, with free_blocks_count */ +struct ext3_new_group_data { + __u32 group; + __u32 block_bitmap; + __u32 inode_bitmap; + __u32 inode_table; + __u32 blocks_count; + __u16 reserved_blocks; + __u16 unused; + __u32 free_blocks_count; +}; + + +/* + * ioctl commands + */ +#define EXT3_IOC_GETFLAGS FS_IOC_GETFLAGS +#define EXT3_IOC_SETFLAGS FS_IOC_SETFLAGS +#define EXT3_IOC_GETVERSION _IOR('f', 3, long) +#define EXT3_IOC_SETVERSION _IOW('f', 4, long) +#define EXT3_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) +#define EXT3_IOC_GROUP_ADD _IOW('f', 8,struct ext3_new_group_input) +#define EXT3_IOC_GETVERSION_OLD FS_IOC_GETVERSION +#define EXT3_IOC_SETVERSION_OLD FS_IOC_SETVERSION +#ifdef CONFIG_JBD_DEBUG +#define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long) +#endif +#define EXT3_IOC_GETRSVSZ _IOR('f', 5, long) +#define EXT3_IOC_SETRSVSZ _IOW('f', 6, long) + +/* + * ioctl commands in 32 bit emulation + */ +#define EXT3_IOC32_GETFLAGS FS_IOC32_GETFLAGS +#define EXT3_IOC32_SETFLAGS FS_IOC32_SETFLAGS +#define EXT3_IOC32_GETVERSION _IOR('f', 3, int) +#define EXT3_IOC32_SETVERSION _IOW('f', 4, int) +#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int) +#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int) +#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int) +#ifdef CONFIG_JBD_DEBUG +#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int) +#endif +#define EXT3_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION +#define EXT3_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION + + +/* + * Mount options + */ +struct ext3_mount_options { + unsigned long s_mount_opt; + uid_t s_resuid; + gid_t s_resgid; + unsigned long s_commit_interval; +#ifdef CONFIG_QUOTA + int s_jquota_fmt; + char *s_qf_names[MAXQUOTAS]; +#endif +}; + +/* + * Structure of an inode on the disk + */ +struct ext3_inode { + __le16 i_mode; /* File mode */ + __le16 i_uid; /* Low 16 bits of Owner Uid */ + __le32 i_size; /* Size in bytes */ + __le32 i_atime; /* Access time */ + __le32 i_ctime; /* Creation time */ + __le32 i_mtime; /* Modification time */ + __le32 i_dtime; /* Deletion Time */ + __le16 i_gid; /* Low 16 bits of Group Id */ + __le16 i_links_count; /* Links count */ + __le32 i_blocks; /* Blocks count */ + __le32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_reserved1; + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + struct { + __u32 m_i_reserved1; + } masix1; + } osd1; /* OS dependent 1 */ + __le32 i_block[EXT3_N_BLOCKS];/* Pointers to blocks */ + __le32 i_generation; /* File version (for NFS) */ + __le32 i_file_acl; /* File ACL */ + __le32 i_dir_acl; /* Directory ACL */ + __le32 i_faddr; /* Fragment address */ + union { + struct { + __u8 l_i_frag; /* Fragment number */ + __u8 l_i_fsize; /* Fragment size */ + __u16 i_pad1; + __le16 l_i_uid_high; /* these 2 fields */ + __le16 l_i_gid_high; /* were reserved2[0] */ + __u32 l_i_reserved2; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + struct { + __u8 m_i_frag; /* Fragment number */ + __u8 m_i_fsize; /* Fragment size */ + __u16 m_pad1; + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ + __le16 i_extra_isize; + __le16 i_pad1; +}; + +#define i_size_high i_dir_acl + +#if defined(__KERNEL__) || defined(__linux__) +#define i_reserved1 osd1.linux1.l_i_reserved1 +#define i_frag osd2.linux2.l_i_frag +#define i_fsize osd2.linux2.l_i_fsize +#define i_uid_low i_uid +#define i_gid_low i_gid +#define i_uid_high osd2.linux2.l_i_uid_high +#define i_gid_high osd2.linux2.l_i_gid_high +#define i_reserved2 osd2.linux2.l_i_reserved2 + +#elif defined(__GNU__) + +#define i_translator osd1.hurd1.h_i_translator +#define i_frag osd2.hurd2.h_i_frag; +#define i_fsize osd2.hurd2.h_i_fsize; +#define i_uid_high osd2.hurd2.h_i_uid_high +#define i_gid_high osd2.hurd2.h_i_gid_high +#define i_author osd2.hurd2.h_i_author + +#elif defined(__masix__) + +#define i_reserved1 osd1.masix1.m_i_reserved1 +#define i_frag osd2.masix2.m_i_frag +#define i_fsize osd2.masix2.m_i_fsize +#define i_reserved2 osd2.masix2.m_i_reserved2 + +#endif /* defined(__KERNEL__) || defined(__linux__) */ + +/* + * File system states + */ +#define EXT3_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT3_ERROR_FS 0x0002 /* Errors detected */ +#define EXT3_ORPHAN_FS 0x0004 /* Orphans being recovered */ + +/* + * Mount flags + */ +#define EXT3_MOUNT_CHECK 0x00001 /* Do mount-time checks */ +#define EXT3_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */ +#define EXT3_MOUNT_GRPID 0x00004 /* Create files with directory's group */ +#define EXT3_MOUNT_DEBUG 0x00008 /* Some debugging messages */ +#define EXT3_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ +#define EXT3_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */ +#define EXT3_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ +#define EXT3_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ +#define EXT3_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ +#define EXT3_MOUNT_ABORT 0x00200 /* Fatal error detected */ +#define EXT3_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ +#define EXT3_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ +#define EXT3_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ +#define EXT3_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */ +#define EXT3_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */ +#define EXT3_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */ +#define EXT3_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */ +#define EXT3_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */ +#define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */ +#define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */ +#define EXT3_MOUNT_NOBH 0x40000 /* No bufferheads */ +#define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */ +#define EXT3_MOUNT_USRQUOTA 0x100000 /* "old" user quota */ +#define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ + +/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ +#ifndef _LINUX_EXT2_FS_H +#define clear_opt(o, opt) o &= ~EXT3_MOUNT_##opt +#define set_opt(o, opt) o |= EXT3_MOUNT_##opt +#define test_opt(sb, opt) (EXT3_SB(sb)->s_mount_opt & \ + EXT3_MOUNT_##opt) +#else +#define EXT2_MOUNT_NOLOAD EXT3_MOUNT_NOLOAD +#define EXT2_MOUNT_ABORT EXT3_MOUNT_ABORT +#define EXT2_MOUNT_DATA_FLAGS EXT3_MOUNT_DATA_FLAGS +#endif + +#define ext3_set_bit ext2_set_bit +#define ext3_set_bit_atomic ext2_set_bit_atomic +#define ext3_clear_bit ext2_clear_bit +#define ext3_clear_bit_atomic ext2_clear_bit_atomic +#define ext3_test_bit ext2_test_bit +#define ext3_find_first_zero_bit ext2_find_first_zero_bit +#define ext3_find_next_zero_bit ext2_find_next_zero_bit + +/* + * Maximal mount counts between two filesystem checks + */ +#define EXT3_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ +#define EXT3_DFL_CHECKINTERVAL 0 /* Don't use interval check */ + +/* + * Behaviour when detecting errors + */ +#define EXT3_ERRORS_CONTINUE 1 /* Continue execution */ +#define EXT3_ERRORS_RO 2 /* Remount fs read-only */ +#define EXT3_ERRORS_PANIC 3 /* Panic */ +#define EXT3_ERRORS_DEFAULT EXT3_ERRORS_CONTINUE + +/* + * Structure of the super block + */ +struct ext3_super_block { +/*00*/ __le32 s_inodes_count; /* Inodes count */ + __le32 s_blocks_count; /* Blocks count */ + __le32 s_r_blocks_count; /* Reserved blocks count */ + __le32 s_free_blocks_count; /* Free blocks count */ +/*10*/ __le32 s_free_inodes_count; /* Free inodes count */ + __le32 s_first_data_block; /* First Data Block */ + __le32 s_log_block_size; /* Block size */ + __le32 s_log_frag_size; /* Fragment size */ +/*20*/ __le32 s_blocks_per_group; /* # Blocks per group */ + __le32 s_frags_per_group; /* # Fragments per group */ + __le32 s_inodes_per_group; /* # Inodes per group */ + __le32 s_mtime; /* Mount time */ +/*30*/ __le32 s_wtime; /* Write time */ + __le16 s_mnt_count; /* Mount count */ + __le16 s_max_mnt_count; /* Maximal mount count */ + __le16 s_magic; /* Magic signature */ + __le16 s_state; /* File system state */ + __le16 s_errors; /* Behaviour when detecting errors */ + __le16 s_minor_rev_level; /* minor revision level */ +/*40*/ __le32 s_lastcheck; /* time of last check */ + __le32 s_checkinterval; /* max. time between checks */ + __le32 s_creator_os; /* OS */ + __le32 s_rev_level; /* Revision level */ +/*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */ + __le16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT3_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __le32 s_first_ino; /* First non-reserved inode */ + __le16 s_inode_size; /* size of inode structure */ + __le16 s_block_group_nr; /* block group # of this superblock */ + __le32 s_feature_compat; /* compatible feature set */ +/*60*/ __le32 s_feature_incompat; /* incompatible feature set */ + __le32 s_feature_ro_compat; /* readonly-compatible feature set */ +/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */ +/*78*/ char s_volume_name[16]; /* volume name */ +/*88*/ char s_last_mounted[64]; /* directory where last mounted */ +/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT3_FEATURE_COMPAT_DIR_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */ + /* + * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. + */ +/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ +/*E0*/ __le32 s_journal_inum; /* inode number of journal file */ + __le32 s_journal_dev; /* device number of journal file */ + __le32 s_last_orphan; /* start of list of inodes to delete */ + __le32 s_hash_seed[4]; /* HTREE hash seed */ + __u8 s_def_hash_version; /* Default hash version to use */ + __u8 s_reserved_char_pad; + __u16 s_reserved_word_pad; + __le32 s_default_mount_opts; + __le32 s_first_meta_bg; /* First metablock block group */ + __u32 s_reserved[190]; /* Padding to the end of the block */ +}; + +#ifdef __KERNEL__ +#include +#include +static inline struct ext3_sb_info * EXT3_SB(struct super_block *sb) +{ + return sb->s_fs_info; +} +static inline struct ext3_inode_info *EXT3_I(struct inode *inode) +{ + return container_of(inode, struct ext3_inode_info, vfs_inode); +} + +static inline int ext3_valid_inum(struct super_block *sb, unsigned long ino) +{ + return ino == EXT3_ROOT_INO || + ino == EXT3_JOURNAL_INO || + ino == EXT3_RESIZE_INO || + (ino >= EXT3_FIRST_INO(sb) && + ino <= le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)); +} +#else +/* Assume that user mode programs are passing in an ext3fs superblock, not + * a kernel struct super_block. This will allow us to call the feature-test + * macros from user land. */ +#define EXT3_SB(sb) (sb) +#endif + +#define NEXT_ORPHAN(inode) EXT3_I(inode)->i_dtime + +/* + * Codes for operating systems + */ +#define EXT3_OS_LINUX 0 +#define EXT3_OS_HURD 1 +#define EXT3_OS_MASIX 2 +#define EXT3_OS_FREEBSD 3 +#define EXT3_OS_LITES 4 + +/* + * Revision levels + */ +#define EXT3_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT3_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT3_CURRENT_REV EXT3_GOOD_OLD_REV +#define EXT3_MAX_SUPP_REV EXT3_DYNAMIC_REV + +#define EXT3_GOOD_OLD_INODE_SIZE 128 + +/* + * Feature set definitions + */ + +#define EXT3_HAS_COMPAT_FEATURE(sb,mask) \ + ( EXT3_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) +#define EXT3_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( EXT3_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) +#define EXT3_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( EXT3_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) +#define EXT3_SET_COMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) +#define EXT3_SET_RO_COMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) +#define EXT3_SET_INCOMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) +#define EXT3_CLEAR_COMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) +#define EXT3_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) +#define EXT3_CLEAR_INCOMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) + +#define EXT3_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT3_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT3_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT3_FEATURE_COMPAT_RESIZE_INODE 0x0010 +#define EXT3_FEATURE_COMPAT_DIR_INDEX 0x0020 + +#define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT3_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT3_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 + +#define EXT3_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT3_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ +#define EXT3_FEATURE_INCOMPAT_META_BG 0x0010 + +#define EXT3_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR +#define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \ + EXT3_FEATURE_INCOMPAT_RECOVER| \ + EXT3_FEATURE_INCOMPAT_META_BG) +#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT3_FEATURE_RO_COMPAT_BTREE_DIR) + +/* + * Default values for user and/or group using reserved blocks + */ +#define EXT3_DEF_RESUID 0 +#define EXT3_DEF_RESGID 0 + +/* + * Default mount options + */ +#define EXT3_DEFM_DEBUG 0x0001 +#define EXT3_DEFM_BSDGROUPS 0x0002 +#define EXT3_DEFM_XATTR_USER 0x0004 +#define EXT3_DEFM_ACL 0x0008 +#define EXT3_DEFM_UID16 0x0010 +#define EXT3_DEFM_JMODE 0x0060 +#define EXT3_DEFM_JMODE_DATA 0x0020 +#define EXT3_DEFM_JMODE_ORDERED 0x0040 +#define EXT3_DEFM_JMODE_WBACK 0x0060 + +/* + * Structure of a directory entry + */ +#define EXT3_NAME_LEN 255 + +struct ext3_dir_entry { + __le32 inode; /* Inode number */ + __le16 rec_len; /* Directory entry length */ + __le16 name_len; /* Name length */ + char name[EXT3_NAME_LEN]; /* File name */ +}; + +/* + * The new version of the directory entry. Since EXT3 structures are + * stored in intel byte order, and the name_len field could never be + * bigger than 255 chars, it's safe to reclaim the extra byte for the + * file_type field. + */ +struct ext3_dir_entry_2 { + __le32 inode; /* Inode number */ + __le16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[EXT3_NAME_LEN]; /* File name */ +}; + +/* + * Ext3 directory file types. Only the low 3 bits are used. The + * other bits are reserved for now. + */ +#define EXT3_FT_UNKNOWN 0 +#define EXT3_FT_REG_FILE 1 +#define EXT3_FT_DIR 2 +#define EXT3_FT_CHRDEV 3 +#define EXT3_FT_BLKDEV 4 +#define EXT3_FT_FIFO 5 +#define EXT3_FT_SOCK 6 +#define EXT3_FT_SYMLINK 7 + +#define EXT3_FT_MAX 8 + +/* + * EXT3_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT3_DIR_PAD 4 +#define EXT3_DIR_ROUND (EXT3_DIR_PAD - 1) +#define EXT3_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT3_DIR_ROUND) & \ + ~EXT3_DIR_ROUND) +/* + * Hash Tree Directory indexing + * (c) Daniel Phillips, 2001 + */ + +#ifdef CONFIG_EXT3_INDEX + #define is_dx(dir) (EXT3_HAS_COMPAT_FEATURE(dir->i_sb, \ + EXT3_FEATURE_COMPAT_DIR_INDEX) && \ + (EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) +#define EXT3_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT3_LINK_MAX) +#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1) +#else + #define is_dx(dir) 0 +#define EXT3_DIR_LINK_MAX(dir) ((dir)->i_nlink >= EXT3_LINK_MAX) +#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2) +#endif + +/* Legal values for the dx_root hash_version field: */ + +#define DX_HASH_LEGACY 0 +#define DX_HASH_HALF_MD4 1 +#define DX_HASH_TEA 2 + +#ifdef __KERNEL__ + +/* hash info structure used by the directory hash */ +struct dx_hash_info +{ + u32 hash; + u32 minor_hash; + int hash_version; + u32 *seed; +}; + +#define EXT3_HTREE_EOF 0x7fffffff + +/* + * Control parameters used by ext3_htree_next_block + */ +#define HASH_NB_ALWAYS 1 + + +/* + * Describe an inode's exact location on disk and in memory + */ +struct ext3_iloc +{ + struct buffer_head *bh; + unsigned long offset; + unsigned long block_group; +}; + +static inline struct ext3_inode *ext3_raw_inode(struct ext3_iloc *iloc) +{ + return (struct ext3_inode *) (iloc->bh->b_data + iloc->offset); +} + +/* + * This structure is stuffed into the struct file's private_data field + * for directories. It is where we put information so that we can do + * readdir operations in hash tree order. + */ +struct dir_private_info { + struct rb_root root; + struct rb_node *curr_node; + struct fname *extra_fname; + loff_t last_pos; + __u32 curr_hash; + __u32 curr_minor_hash; + __u32 next_hash; +}; + +/* calculate the first block number of the group */ +static inline ext3_fsblk_t +ext3_group_first_block_no(struct super_block *sb, unsigned long group_no) +{ + return group_no * (ext3_fsblk_t)EXT3_BLOCKS_PER_GROUP(sb) + + le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block); +} + +/* + * Special error return code only used by dx_probe() and its callers. + */ +#define ERR_BAD_DX_DIR -75000 + +/* + * Function prototypes + */ + +/* + * Ok, these declarations are also in but none of the + * ext3 source programs needs to include it so they are duplicated here. + */ +# define NORET_TYPE /**/ +# define ATTRIB_NORET __attribute__((noreturn)) +# define NORET_AND noreturn, + +/* balloc.c */ +extern int ext3_bg_has_super(struct super_block *sb, int group); +extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group); +extern ext3_fsblk_t ext3_new_block (handle_t *handle, struct inode *inode, + ext3_fsblk_t goal, int *errp); +extern ext3_fsblk_t ext3_new_blocks (handle_t *handle, struct inode *inode, + ext3_fsblk_t goal, unsigned long *count, int *errp); +extern void ext3_free_blocks (handle_t *handle, struct inode *inode, + ext3_fsblk_t block, unsigned long count); +extern void ext3_free_blocks_sb (handle_t *handle, struct super_block *sb, + ext3_fsblk_t block, unsigned long count, + unsigned long *pdquot_freed_blocks); +extern ext3_fsblk_t ext3_count_free_blocks (struct super_block *); +extern void ext3_check_blocks_bitmap (struct super_block *); +extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh); +extern int ext3_should_retry_alloc(struct super_block *sb, int *retries); +extern void ext3_init_block_alloc_info(struct inode *); +extern void ext3_rsv_window_add(struct super_block *sb, struct ext3_reserve_window_node *rsv); + +/* dir.c */ +extern int ext3_check_dir_entry(const char *, struct inode *, + struct ext3_dir_entry_2 *, + struct buffer_head *, unsigned long); +extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, + __u32 minor_hash, + struct ext3_dir_entry_2 *dirent); +extern void ext3_htree_free_dir_info(struct dir_private_info *p); + +/* fsync.c */ +extern int ext3_sync_file (struct file *, struct dentry *, int); + +/* hash.c */ +extern int ext3fs_dirhash(const char *name, int len, struct + dx_hash_info *hinfo); + +/* ialloc.c */ +extern struct inode * ext3_new_inode (handle_t *, struct inode *, int); +extern void ext3_free_inode (handle_t *, struct inode *); +extern struct inode * ext3_orphan_get (struct super_block *, unsigned long); +extern unsigned long ext3_count_free_inodes (struct super_block *); +extern unsigned long ext3_count_dirs (struct super_block *); +extern void ext3_check_inodes_bitmap (struct super_block *); +extern unsigned long ext3_count_free (struct buffer_head *, unsigned); + + +/* inode.c */ +int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode, + struct buffer_head *bh, ext3_fsblk_t blocknr); +struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *); +struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *); +int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, + sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result, + int create, int extend_disksize); + +extern void ext3_read_inode (struct inode *); +extern int ext3_write_inode (struct inode *, int); +extern int ext3_setattr (struct dentry *, struct iattr *); +extern void ext3_delete_inode (struct inode *); +extern int ext3_sync_inode (handle_t *, struct inode *); +extern void ext3_discard_reservation (struct inode *); +extern void ext3_dirty_inode(struct inode *); +extern int ext3_change_inode_journal_flag(struct inode *, int); +extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *); +extern void ext3_truncate (struct inode *); +extern void ext3_set_inode_flags(struct inode *); +extern void ext3_set_aops(struct inode *inode); + +/* ioctl.c */ +extern int ext3_ioctl (struct inode *, struct file *, unsigned int, + unsigned long); +extern long ext3_compat_ioctl (struct file *, unsigned int, unsigned long); + +/* namei.c */ +extern int ext3_orphan_add(handle_t *, struct inode *); +extern int ext3_orphan_del(handle_t *, struct inode *); +extern int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, + __u32 start_minor_hash, __u32 *next_hash); + +/* resize.c */ +extern int ext3_group_add(struct super_block *sb, + struct ext3_new_group_data *input); +extern int ext3_group_extend(struct super_block *sb, + struct ext3_super_block *es, + ext3_fsblk_t n_blocks_count); + +/* super.c */ +extern void ext3_error (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +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 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); + +#define ext3_std_error(sb, errno) \ +do { \ + if ((errno)) \ + __ext3_std_error((sb), __FUNCTION__, (errno)); \ +} while (0) + +/* + * Inodes and files operations + */ + +/* dir.c */ +extern const struct file_operations ext3_dir_operations; + +/* file.c */ +extern struct inode_operations ext3_file_inode_operations; +extern const struct file_operations ext3_file_operations; + +/* namei.c */ +extern struct inode_operations ext3_dir_inode_operations; +extern struct inode_operations ext3_special_inode_operations; + +/* symlink.c */ +extern struct inode_operations ext3_symlink_inode_operations; +extern struct inode_operations ext3_fast_symlink_inode_operations; + + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_EXT3_FS_H */ diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h new file mode 100644 index 000000000000..4395e5206746 --- /dev/null +++ b/include/linux/ext4_fs_i.h @@ -0,0 +1,147 @@ +/* + * linux/include/linux/ext3_fs_i.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs_i.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT3_FS_I +#define _LINUX_EXT3_FS_I + +#include +#include +#include +#include + +/* data type for block offset of block group */ +typedef int ext3_grpblk_t; + +/* data type for filesystem-wide blocks number */ +typedef unsigned long ext3_fsblk_t; + +#define E3FSBLK "%lu" + +struct ext3_reserve_window { + ext3_fsblk_t _rsv_start; /* First byte reserved */ + ext3_fsblk_t _rsv_end; /* Last byte reserved or 0 */ +}; + +struct ext3_reserve_window_node { + struct rb_node rsv_node; + __u32 rsv_goal_size; + __u32 rsv_alloc_hit; + struct ext3_reserve_window rsv_window; +}; + +struct ext3_block_alloc_info { + /* information about reservation window */ + struct ext3_reserve_window_node rsv_window_node; + /* + * was i_next_alloc_block in ext3_inode_info + * is the logical (file-relative) number of the + * most-recently-allocated block in this file. + * We use this for detecting linearly ascending allocation requests. + */ + __u32 last_alloc_logical_block; + /* + * Was i_next_alloc_goal in ext3_inode_info + * is the *physical* companion to i_next_alloc_block. + * it the the physical block number of the block which was most-recentl + * allocated to this file. This give us the goal (target) for the next + * allocation when we detect linearly ascending requests. + */ + ext3_fsblk_t last_alloc_physical_block; +}; + +#define rsv_start rsv_window._rsv_start +#define rsv_end rsv_window._rsv_end + +/* + * third extended file system inode data in memory + */ +struct ext3_inode_info { + __le32 i_data[15]; /* unconverted */ + __u32 i_flags; +#ifdef EXT3_FRAGMENTS + __u32 i_faddr; + __u8 i_frag_no; + __u8 i_frag_size; +#endif + ext3_fsblk_t i_file_acl; + __u32 i_dir_acl; + __u32 i_dtime; + + /* + * i_block_group is the number of the block group which contains + * this file's inode. Constant across the lifetime of the inode, + * it is ued for making block allocation decisions - we try to + * place a file's data blocks near its inode block, and new inodes + * near to their parent directory's inode. + */ + __u32 i_block_group; + __u32 i_state; /* Dynamic state flags for ext3 */ + + /* block reservation info */ + struct ext3_block_alloc_info *i_block_alloc_info; + + __u32 i_dir_start_lookup; +#ifdef CONFIG_EXT3_FS_XATTR + /* + * Extended attributes can be read independently of the main file + * data. Taking i_mutex even when reading would cause contention + * between readers of EAs and writers of regular file data, so + * instead we synchronize on xattr_sem when reading or changing + * EAs. + */ + struct rw_semaphore xattr_sem; +#endif +#ifdef CONFIG_EXT3_FS_POSIX_ACL + struct posix_acl *i_acl; + struct posix_acl *i_default_acl; +#endif + + struct list_head i_orphan; /* unlinked but open inodes */ + + /* + * i_disksize keeps track of what the inode size is ON DISK, not + * in memory. During truncate, i_size is set to the new size by + * the VFS prior to calling ext3_truncate(), but the filesystem won't + * set i_disksize to 0 until the truncate is actually under way. + * + * The intent is that i_disksize always represents the blocks which + * are used by this file. This allows recovery to restart truncate + * on orphans if we crash during truncate. We actually write i_disksize + * into the on-disk inode when writing inodes out, instead of i_size. + * + * The only time when i_disksize and i_size may be different is when + * a truncate is in progress. The only things which change i_disksize + * are ext3_get_block (growth) and ext3_truncate (shrinkth). + */ + loff_t i_disksize; + + /* on-disk additional length */ + __u16 i_extra_isize; + + /* + * truncate_mutex is for serialising ext3_truncate() against + * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's + * data tree are chopped off during truncate. We can't do that in + * ext3 because whenever we perform intermediate commits during + * truncate, the inode and all the metadata blocks *must* be in a + * consistent state which allows truncation of the orphans to restart + * during recovery. Hence we must fix the get_block-vs-truncate race + * by other means, so we have truncate_mutex. + */ + struct mutex truncate_mutex; + struct inode vfs_inode; +}; + +#endif /* _LINUX_EXT3_FS_I */ diff --git a/include/linux/ext4_fs_sb.h b/include/linux/ext4_fs_sb.h new file mode 100644 index 000000000000..f61309c81cc4 --- /dev/null +++ b/include/linux/ext4_fs_sb.h @@ -0,0 +1,83 @@ +/* + * linux/include/linux/ext3_fs_sb.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs_sb.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT3_FS_SB +#define _LINUX_EXT3_FS_SB + +#ifdef __KERNEL__ +#include +#include +#include +#include +#endif +#include + +/* + * third extended-fs super-block data in memory + */ +struct ext3_sb_info { + unsigned long s_frag_size; /* Size of a fragment in bytes */ + unsigned long s_frags_per_block;/* Number of fragments per block */ + unsigned long s_inodes_per_block;/* Number of inodes per block */ + unsigned long s_frags_per_group;/* Number of fragments in a group */ + unsigned long s_blocks_per_group;/* Number of blocks in a group */ + unsigned long s_inodes_per_group;/* Number of inodes in a group */ + unsigned long s_itb_per_group; /* Number of inode table blocks per group */ + unsigned long s_gdb_count; /* Number of group descriptor blocks */ + unsigned long s_desc_per_block; /* Number of group descriptors per block */ + unsigned long s_groups_count; /* Number of groups in the fs */ + struct buffer_head * s_sbh; /* Buffer containing the super block */ + struct ext3_super_block * s_es; /* Pointer to the super block in the buffer */ + struct buffer_head ** s_group_desc; + unsigned long s_mount_opt; + uid_t s_resuid; + gid_t s_resgid; + unsigned short s_mount_state; + unsigned short s_pad; + int s_addr_per_block_bits; + int s_desc_per_block_bits; + int s_inode_size; + int s_first_ino; + spinlock_t s_next_gen_lock; + u32 s_next_generation; + u32 s_hash_seed[4]; + int s_def_hash_version; + struct percpu_counter s_freeblocks_counter; + struct percpu_counter s_freeinodes_counter; + struct percpu_counter s_dirs_counter; + struct blockgroup_lock s_blockgroup_lock; + + /* root of the per fs reservation window tree */ + spinlock_t s_rsv_window_lock; + struct rb_root s_rsv_window_root; + struct ext3_reserve_window_node s_rsv_window_head; + + /* Journaling */ + struct inode * s_journal_inode; + struct journal_s * s_journal; + struct list_head s_orphan; + unsigned long s_commit_interval; + struct block_device *journal_bdev; +#ifdef CONFIG_JBD_DEBUG + struct timer_list turn_ro_timer; /* For turning read-only (crash simulation) */ + wait_queue_head_t ro_wait_queue; /* For people waiting for the fs to go read-only */ +#endif +#ifdef CONFIG_QUOTA + char *s_qf_names[MAXQUOTAS]; /* Names of quota files with journalled quota */ + int s_jquota_fmt; /* Format of quota to use */ +#endif +}; + +#endif /* _LINUX_EXT3_FS_SB */ diff --git a/include/linux/ext4_jbd.h b/include/linux/ext4_jbd.h new file mode 100644 index 000000000000..ce0e6109aff0 --- /dev/null +++ b/include/linux/ext4_jbd.h @@ -0,0 +1,268 @@ +/* + * linux/include/linux/ext3_jbd.h + * + * Written by Stephen C. Tweedie , 1999 + * + * Copyright 1998--1999 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Ext3-specific journaling extensions. + */ + +#ifndef _LINUX_EXT3_JBD_H +#define _LINUX_EXT3_JBD_H + +#include +#include +#include + +#define EXT3_JOURNAL(inode) (EXT3_SB((inode)->i_sb)->s_journal) + +/* Define the number of blocks we need to account to a transaction to + * modify one block of data. + * + * We may have to touch one inode, one bitmap buffer, up to three + * indirection blocks, the group and superblock summaries, and the data + * block to complete the transaction. */ + +#define EXT3_SINGLEDATA_TRANS_BLOCKS 8U + +/* Extended attribute operations touch at most two data buffers, + * two bitmap buffers, and two group summaries, in addition to the inode + * and the superblock, which are already accounted for. */ + +#define EXT3_XATTR_TRANS_BLOCKS 6U + +/* Define the minimum size for a transaction which modifies data. This + * needs to take into account the fact that we may end up modifying two + * quota files too (one for the group, one for the user quota). The + * superblock only gets updated once, of course, so don't bother + * counting that again for the quota updates. */ + +#define EXT3_DATA_TRANS_BLOCKS(sb) (EXT3_SINGLEDATA_TRANS_BLOCKS + \ + EXT3_XATTR_TRANS_BLOCKS - 2 + \ + 2*EXT3_QUOTA_TRANS_BLOCKS(sb)) + +/* 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. */ + +#define EXT3_DELETE_TRANS_BLOCKS(sb) (2 * EXT3_DATA_TRANS_BLOCKS(sb) + 64) + +/* Define an arbitrary limit for the amount of data we will anticipate + * writing to any given transaction. For unbounded transactions such as + * write(2) and truncate(2) we can write more than this, but we always + * start off at the maximum transaction size and grow the transaction + * optimistically as we go. */ + +#define EXT3_MAX_TRANS_DATA 64U + +/* We break up a large truncate or write transaction once the handle's + * buffer credits gets this low, we need either to extend the + * transaction or to start a new one. Reserve enough space here for + * inode, bitmap, superblock, group and indirection updates for at least + * one block, plus two quota updates. Quota allocations are not + * needed. */ + +#define EXT3_RESERVE_TRANS_BLOCKS 12U + +#define EXT3_INDEX_EXTRA_TRANS_BLOCKS 8 + +#ifdef CONFIG_QUOTA +/* Amount of blocks needed for quota update - we know that the structure was + * allocated so we need to update only inode+data */ +#define EXT3_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0) +/* Amount of blocks needed for quota insert/delete - we do some block writes + * but inode, sb and group updates are done only once */ +#define EXT3_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ + (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0) +#define EXT3_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ + (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0) +#else +#define EXT3_QUOTA_TRANS_BLOCKS(sb) 0 +#define EXT3_QUOTA_INIT_BLOCKS(sb) 0 +#define EXT3_QUOTA_DEL_BLOCKS(sb) 0 +#endif + +int +ext3_mark_iloc_dirty(handle_t *handle, + struct inode *inode, + struct ext3_iloc *iloc); + +/* + * On success, We end up with an outstanding reference count against + * iloc->bh. This _must_ be cleaned up later. + */ + +int ext3_reserve_inode_write(handle_t *handle, struct inode *inode, + struct ext3_iloc *iloc); + +int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode); + +/* + * Wrapper functions with which ext3 calls into JBD. The intent here is + * to allow these to be turned into appropriate stubs so ext3 can control + * ext2 filesystems, so ext2+ext3 systems only nee one fs. This work hasn't + * been done yet. + */ + +void ext3_journal_abort_handle(const char *caller, const char *err_fn, + struct buffer_head *bh, handle_t *handle, int err); + +static inline int +__ext3_journal_get_undo_access(const char *where, handle_t *handle, + struct buffer_head *bh) +{ + int err = journal_get_undo_access(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext3_journal_get_write_access(const char *where, handle_t *handle, + struct buffer_head *bh) +{ + int err = journal_get_write_access(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline void +ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh) +{ + journal_release_buffer(handle, bh); +} + +static inline int +__ext3_journal_forget(const char *where, handle_t *handle, struct buffer_head *bh) +{ + int err = journal_forget(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext3_journal_revoke(const char *where, handle_t *handle, + unsigned long blocknr, struct buffer_head *bh) +{ + int err = journal_revoke(handle, blocknr, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext3_journal_get_create_access(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = journal_get_create_access(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext3_journal_dirty_metadata(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = journal_dirty_metadata(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + + +#define ext3_journal_get_undo_access(handle, bh) \ + __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh)) +#define ext3_journal_get_write_access(handle, bh) \ + __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh)) +#define ext3_journal_revoke(handle, blocknr, bh) \ + __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh)) +#define ext3_journal_get_create_access(handle, bh) \ + __ext3_journal_get_create_access(__FUNCTION__, (handle), (bh)) +#define ext3_journal_dirty_metadata(handle, bh) \ + __ext3_journal_dirty_metadata(__FUNCTION__, (handle), (bh)) +#define ext3_journal_forget(handle, bh) \ + __ext3_journal_forget(__FUNCTION__, (handle), (bh)) + +int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh); + +handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks); +int __ext3_journal_stop(const char *where, handle_t *handle); + +static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks) +{ + return ext3_journal_start_sb(inode->i_sb, nblocks); +} + +#define ext3_journal_stop(handle) \ + __ext3_journal_stop(__FUNCTION__, (handle)) + +static inline handle_t *ext3_journal_current_handle(void) +{ + return journal_current_handle(); +} + +static inline int ext3_journal_extend(handle_t *handle, int nblocks) +{ + return journal_extend(handle, nblocks); +} + +static inline int ext3_journal_restart(handle_t *handle, int nblocks) +{ + return journal_restart(handle, nblocks); +} + +static inline int ext3_journal_blocks_per_page(struct inode *inode) +{ + return journal_blocks_per_page(inode); +} + +static inline int ext3_journal_force_commit(journal_t *journal) +{ + return journal_force_commit(journal); +} + +/* super.c */ +int ext3_force_commit(struct super_block *sb); + +static inline int ext3_should_journal_data(struct inode *inode) +{ + if (!S_ISREG(inode->i_mode)) + return 1; + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) + return 1; + if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL) + return 1; + return 0; +} + +static inline int ext3_should_order_data(struct inode *inode) +{ + if (!S_ISREG(inode->i_mode)) + return 0; + if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL) + return 0; + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA) + return 1; + return 0; +} + +static inline int ext3_should_writeback_data(struct inode *inode) +{ + if (!S_ISREG(inode->i_mode)) + return 0; + if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL) + return 0; + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) + return 1; + return 0; +} + +#endif /* _LINUX_EXT3_JBD_H */ -- cgit v1.2.3 From 617ba13b31fbf505cc21799826639ef24ed94af0 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:20:53 -0700 Subject: [PATCH] ext4: rename ext4 symbols to avoid duplication of ext3 symbols Mingming Cao originally did this work, and Shaggy reproduced it using some scripts from her. Signed-off-by: Mingming Cao Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/Makefile | 12 +- fs/ext4/acl.c | 188 ++++---- fs/ext4/acl.h | 58 +-- fs/ext4/balloc.c | 536 ++++++++++----------- fs/ext4/bitmap.c | 10 +- fs/ext4/dir.c | 102 ++-- fs/ext4/file.c | 50 +- fs/ext4/fsync.c | 20 +- fs/ext4/hash.c | 10 +- fs/ext4/ialloc.c | 230 ++++----- fs/ext4/inode.c | 1020 ++++++++++++++++++++-------------------- fs/ext4/ioctl.c | 156 +++---- fs/ext4/namei.c | 830 ++++++++++++++++----------------- fs/ext4/namei.h | 4 +- fs/ext4/resize.c | 412 ++++++++-------- fs/ext4/super.c | 1114 ++++++++++++++++++++++---------------------- fs/ext4/symlink.c | 24 +- fs/ext4/xattr.c | 560 +++++++++++----------- fs/ext4/xattr.h | 110 ++--- fs/ext4/xattr_security.c | 28 +- fs/ext4/xattr_trusted.c | 24 +- fs/ext4/xattr_user.c | 24 +- include/linux/ext4_fs.h | 702 ++++++++++++++-------------- include/linux/ext4_fs_i.h | 56 +-- include/linux/ext4_fs_sb.h | 14 +- include/linux/ext4_jbd.h | 160 +++---- 26 files changed, 3227 insertions(+), 3227 deletions(-) (limited to 'include/linux') diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 704cd44a40c2..09c487893e4a 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -1,12 +1,12 @@ # -# Makefile for the linux ext3-filesystem routines. +# Makefile for the linux ext4-filesystem routines. # -obj-$(CONFIG_EXT3_FS) += ext3.o +obj-$(CONFIG_EXT4DEV_FS) += ext4dev.o -ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ +ext4dev-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ ioctl.o namei.o super.o symlink.o hash.o resize.o -ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o -ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o -ext3-$(CONFIG_EXT3_FS_SECURITY) += xattr_security.o +ext4dev-$(CONFIG_EXT4DEV_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o +ext4dev-$(CONFIG_EXT4DEV_FS_POSIX_ACL) += acl.o +ext4dev-$(CONFIG_EXT4DEV_FS_SECURITY) += xattr_security.o diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 1e5038d9a01b..d143489aeb4c 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/acl.c + * linux/fs/ext4/acl.c * * Copyright (C) 2001-2003 Andreas Gruenbacher, */ @@ -9,8 +9,8 @@ #include #include #include -#include -#include +#include +#include #include "xattr.h" #include "acl.h" @@ -18,7 +18,7 @@ * Convert from filesystem to in-memory representation. */ static struct posix_acl * -ext3_acl_from_disk(const void *value, size_t size) +ext4_acl_from_disk(const void *value, size_t size) { const char *end = (char *)value + size; int n, count; @@ -26,13 +26,13 @@ ext3_acl_from_disk(const void *value, size_t size) if (!value) return NULL; - if (size < sizeof(ext3_acl_header)) + if (size < sizeof(ext4_acl_header)) return ERR_PTR(-EINVAL); - if (((ext3_acl_header *)value)->a_version != - cpu_to_le32(EXT3_ACL_VERSION)) + if (((ext4_acl_header *)value)->a_version != + cpu_to_le32(EXT4_ACL_VERSION)) return ERR_PTR(-EINVAL); - value = (char *)value + sizeof(ext3_acl_header); - count = ext3_acl_count(size); + value = (char *)value + sizeof(ext4_acl_header); + count = ext4_acl_count(size); if (count < 0) return ERR_PTR(-EINVAL); if (count == 0) @@ -41,9 +41,9 @@ ext3_acl_from_disk(const void *value, size_t size) if (!acl) return ERR_PTR(-ENOMEM); for (n=0; n < count; n++) { - ext3_acl_entry *entry = - (ext3_acl_entry *)value; - if ((char *)value + sizeof(ext3_acl_entry_short) > end) + ext4_acl_entry *entry = + (ext4_acl_entry *)value; + if ((char *)value + sizeof(ext4_acl_entry_short) > end) goto fail; acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); @@ -53,13 +53,13 @@ ext3_acl_from_disk(const void *value, size_t size) case ACL_MASK: case ACL_OTHER: value = (char *)value + - sizeof(ext3_acl_entry_short); + sizeof(ext4_acl_entry_short); acl->a_entries[n].e_id = ACL_UNDEFINED_ID; break; case ACL_USER: case ACL_GROUP: - value = (char *)value + sizeof(ext3_acl_entry); + value = (char *)value + sizeof(ext4_acl_entry); if ((char *)value > end) goto fail; acl->a_entries[n].e_id = @@ -83,21 +83,21 @@ fail: * Convert from in-memory to filesystem representation. */ static void * -ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) +ext4_acl_to_disk(const struct posix_acl *acl, size_t *size) { - ext3_acl_header *ext_acl; + ext4_acl_header *ext_acl; char *e; size_t n; - *size = ext3_acl_size(acl->a_count); - ext_acl = kmalloc(sizeof(ext3_acl_header) + acl->a_count * - sizeof(ext3_acl_entry), GFP_KERNEL); + *size = ext4_acl_size(acl->a_count); + ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count * + sizeof(ext4_acl_entry), GFP_KERNEL); if (!ext_acl) return ERR_PTR(-ENOMEM); - ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION); - e = (char *)ext_acl + sizeof(ext3_acl_header); + ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION); + e = (char *)ext_acl + sizeof(ext4_acl_header); for (n=0; n < acl->a_count; n++) { - ext3_acl_entry *entry = (ext3_acl_entry *)e; + ext4_acl_entry *entry = (ext4_acl_entry *)e; entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); switch(acl->a_entries[n].e_tag) { @@ -105,14 +105,14 @@ ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) case ACL_GROUP: entry->e_id = cpu_to_le32(acl->a_entries[n].e_id); - e += sizeof(ext3_acl_entry); + e += sizeof(ext4_acl_entry); break; case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_MASK: case ACL_OTHER: - e += sizeof(ext3_acl_entry_short); + e += sizeof(ext4_acl_entry_short); break; default: @@ -127,12 +127,12 @@ fail: } static inline struct posix_acl * -ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl) +ext4_iget_acl(struct inode *inode, struct posix_acl **i_acl) { - struct posix_acl *acl = EXT3_ACL_NOT_CACHED; + struct posix_acl *acl = EXT4_ACL_NOT_CACHED; spin_lock(&inode->i_lock); - if (*i_acl != EXT3_ACL_NOT_CACHED) + if (*i_acl != EXT4_ACL_NOT_CACHED) acl = posix_acl_dup(*i_acl); spin_unlock(&inode->i_lock); @@ -140,11 +140,11 @@ ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl) } static inline void -ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl, +ext4_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl) { spin_lock(&inode->i_lock); - if (*i_acl != EXT3_ACL_NOT_CACHED) + if (*i_acl != EXT4_ACL_NOT_CACHED) posix_acl_release(*i_acl); *i_acl = posix_acl_dup(acl); spin_unlock(&inode->i_lock); @@ -156,9 +156,9 @@ ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl, * inode->i_mutex: don't care */ static struct posix_acl * -ext3_get_acl(struct inode *inode, int type) +ext4_get_acl(struct inode *inode, int type) { - struct ext3_inode_info *ei = EXT3_I(inode); + struct ext4_inode_info *ei = EXT4_I(inode); int name_index; char *value = NULL; struct posix_acl *acl; @@ -169,31 +169,31 @@ ext3_get_acl(struct inode *inode, int type) switch(type) { case ACL_TYPE_ACCESS: - acl = ext3_iget_acl(inode, &ei->i_acl); - if (acl != EXT3_ACL_NOT_CACHED) + acl = ext4_iget_acl(inode, &ei->i_acl); + if (acl != EXT4_ACL_NOT_CACHED) return acl; - name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; + name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; break; case ACL_TYPE_DEFAULT: - acl = ext3_iget_acl(inode, &ei->i_default_acl); - if (acl != EXT3_ACL_NOT_CACHED) + acl = ext4_iget_acl(inode, &ei->i_default_acl); + if (acl != EXT4_ACL_NOT_CACHED) return acl; - name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; + name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; break; default: return ERR_PTR(-EINVAL); } - retval = ext3_xattr_get(inode, name_index, "", NULL, 0); + retval = ext4_xattr_get(inode, name_index, "", NULL, 0); if (retval > 0) { value = kmalloc(retval, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); - retval = ext3_xattr_get(inode, name_index, "", value, retval); + retval = ext4_xattr_get(inode, name_index, "", value, retval); } if (retval > 0) - acl = ext3_acl_from_disk(value, retval); + acl = ext4_acl_from_disk(value, retval); else if (retval == -ENODATA || retval == -ENOSYS) acl = NULL; else @@ -203,11 +203,11 @@ ext3_get_acl(struct inode *inode, int type) if (!IS_ERR(acl)) { switch(type) { case ACL_TYPE_ACCESS: - ext3_iset_acl(inode, &ei->i_acl, acl); + ext4_iset_acl(inode, &ei->i_acl, acl); break; case ACL_TYPE_DEFAULT: - ext3_iset_acl(inode, &ei->i_default_acl, acl); + ext4_iset_acl(inode, &ei->i_default_acl, acl); break; } } @@ -217,13 +217,13 @@ ext3_get_acl(struct inode *inode, int type) /* * Set the access or default ACL of an inode. * - * inode->i_mutex: down unless called from ext3_new_inode + * inode->i_mutex: down unless called from ext4_new_inode */ static int -ext3_set_acl(handle_t *handle, struct inode *inode, int type, +ext4_set_acl(handle_t *handle, struct inode *inode, int type, struct posix_acl *acl) { - struct ext3_inode_info *ei = EXT3_I(inode); + struct ext4_inode_info *ei = EXT4_I(inode); int name_index; void *value = NULL; size_t size = 0; @@ -234,7 +234,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, switch(type) { case ACL_TYPE_ACCESS: - name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; + name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); @@ -242,7 +242,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, return error; else { inode->i_mode = mode; - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); if (error == 0) acl = NULL; } @@ -250,7 +250,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, break; case ACL_TYPE_DEFAULT: - name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; + name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; @@ -259,23 +259,23 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, return -EINVAL; } if (acl) { - value = ext3_acl_to_disk(acl, &size); + value = ext4_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); } - error = ext3_xattr_set_handle(handle, inode, name_index, "", + error = ext4_xattr_set_handle(handle, inode, name_index, "", value, size, 0); kfree(value); if (!error) { switch(type) { case ACL_TYPE_ACCESS: - ext3_iset_acl(inode, &ei->i_acl, acl); + ext4_iset_acl(inode, &ei->i_acl, acl); break; case ACL_TYPE_DEFAULT: - ext3_iset_acl(inode, &ei->i_default_acl, acl); + ext4_iset_acl(inode, &ei->i_default_acl, acl); break; } } @@ -283,9 +283,9 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, } static int -ext3_check_acl(struct inode *inode, int mask) +ext4_check_acl(struct inode *inode, int mask) { - struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); + struct posix_acl *acl = ext4_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl)) return PTR_ERR(acl); @@ -299,26 +299,26 @@ ext3_check_acl(struct inode *inode, int mask) } int -ext3_permission(struct inode *inode, int mask, struct nameidata *nd) +ext4_permission(struct inode *inode, int mask, struct nameidata *nd) { - return generic_permission(inode, mask, ext3_check_acl); + return generic_permission(inode, mask, ext4_check_acl); } /* - * Initialize the ACLs of a new inode. Called from ext3_new_inode. + * Initialize the ACLs of a new inode. Called from ext4_new_inode. * * dir->i_mutex: down * inode->i_mutex: up (access to inode is still exclusive) */ int -ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) +ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; int error = 0; if (!S_ISLNK(inode->i_mode)) { if (test_opt(dir->i_sb, POSIX_ACL)) { - acl = ext3_get_acl(dir, ACL_TYPE_DEFAULT); + acl = ext4_get_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); } @@ -330,7 +330,7 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) mode_t mode; if (S_ISDIR(inode->i_mode)) { - error = ext3_set_acl(handle, inode, + error = ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT, acl); if (error) goto cleanup; @@ -346,7 +346,7 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) inode->i_mode = mode; if (error > 0) { /* This is an extended ACL */ - error = ext3_set_acl(handle, inode, + error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, clone); } } @@ -372,7 +372,7 @@ cleanup: * inode->i_mutex: down */ int -ext3_acl_chmod(struct inode *inode) +ext4_acl_chmod(struct inode *inode) { struct posix_acl *acl, *clone; int error; @@ -381,7 +381,7 @@ ext3_acl_chmod(struct inode *inode) return -EOPNOTSUPP; if (!test_opt(inode->i_sb, POSIX_ACL)) return 0; - acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); + acl = ext4_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); clone = posix_acl_clone(acl, GFP_KERNEL); @@ -394,17 +394,17 @@ ext3_acl_chmod(struct inode *inode) int retries = 0; retry: - handle = ext3_journal_start(inode, - EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); + handle = ext4_journal_start(inode, + EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); if (IS_ERR(handle)) { error = PTR_ERR(handle); - ext3_std_error(inode->i_sb, error); + ext4_std_error(inode->i_sb, error); goto out; } - error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone); - ext3_journal_stop(handle); + error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, clone); + ext4_journal_stop(handle); if (error == -ENOSPC && - ext3_should_retry_alloc(inode->i_sb, &retries)) + ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; } out: @@ -416,7 +416,7 @@ out: * Extended attribute handlers */ static size_t -ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len, +ext4_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len, const char *name, size_t name_len) { const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); @@ -429,7 +429,7 @@ ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len, } static size_t -ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len, +ext4_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len, const char *name, size_t name_len) { const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); @@ -442,7 +442,7 @@ ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len, } static int -ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size) +ext4_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size) { struct posix_acl *acl; int error; @@ -450,7 +450,7 @@ ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size) if (!test_opt(inode->i_sb, POSIX_ACL)) return -EOPNOTSUPP; - acl = ext3_get_acl(inode, type); + acl = ext4_get_acl(inode, type); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl == NULL) @@ -462,25 +462,25 @@ ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size) } static int -ext3_xattr_get_acl_access(struct inode *inode, const char *name, +ext4_xattr_get_acl_access(struct inode *inode, const char *name, void *buffer, size_t size) { if (strcmp(name, "") != 0) return -EINVAL; - return ext3_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); + return ext4_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); } static int -ext3_xattr_get_acl_default(struct inode *inode, const char *name, +ext4_xattr_get_acl_default(struct inode *inode, const char *name, void *buffer, size_t size) { if (strcmp(name, "") != 0) return -EINVAL; - return ext3_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); + return ext4_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); } static int -ext3_xattr_set_acl(struct inode *inode, int type, const void *value, +ext4_xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) { handle_t *handle; @@ -505,12 +505,12 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value, acl = NULL; retry: - handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); + handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); - error = ext3_set_acl(handle, inode, type, acl); - ext3_journal_stop(handle); - if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) + error = ext4_set_acl(handle, inode, type, acl); + ext4_journal_stop(handle); + if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; release_and_out: @@ -519,33 +519,33 @@ release_and_out: } static int -ext3_xattr_set_acl_access(struct inode *inode, const char *name, +ext4_xattr_set_acl_access(struct inode *inode, const char *name, const void *value, size_t size, int flags) { if (strcmp(name, "") != 0) return -EINVAL; - return ext3_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); + return ext4_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); } static int -ext3_xattr_set_acl_default(struct inode *inode, const char *name, +ext4_xattr_set_acl_default(struct inode *inode, const char *name, const void *value, size_t size, int flags) { if (strcmp(name, "") != 0) return -EINVAL; - return ext3_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); + return ext4_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); } -struct xattr_handler ext3_xattr_acl_access_handler = { +struct xattr_handler ext4_xattr_acl_access_handler = { .prefix = POSIX_ACL_XATTR_ACCESS, - .list = ext3_xattr_list_acl_access, - .get = ext3_xattr_get_acl_access, - .set = ext3_xattr_set_acl_access, + .list = ext4_xattr_list_acl_access, + .get = ext4_xattr_get_acl_access, + .set = ext4_xattr_set_acl_access, }; -struct xattr_handler ext3_xattr_acl_default_handler = { +struct xattr_handler ext4_xattr_acl_default_handler = { .prefix = POSIX_ACL_XATTR_DEFAULT, - .list = ext3_xattr_list_acl_default, - .get = ext3_xattr_get_acl_default, - .set = ext3_xattr_set_acl_default, + .list = ext4_xattr_list_acl_default, + .get = ext4_xattr_get_acl_default, + .set = ext4_xattr_set_acl_default, }; diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h index 0d1e6279cbfd..26a5c1abf147 100644 --- a/fs/ext4/acl.h +++ b/fs/ext4/acl.h @@ -1,81 +1,81 @@ /* - File: fs/ext3/acl.h + File: fs/ext4/acl.h (C) 2001 Andreas Gruenbacher, */ #include -#define EXT3_ACL_VERSION 0x0001 +#define EXT4_ACL_VERSION 0x0001 typedef struct { __le16 e_tag; __le16 e_perm; __le32 e_id; -} ext3_acl_entry; +} ext4_acl_entry; typedef struct { __le16 e_tag; __le16 e_perm; -} ext3_acl_entry_short; +} ext4_acl_entry_short; typedef struct { __le32 a_version; -} ext3_acl_header; +} ext4_acl_header; -static inline size_t ext3_acl_size(int count) +static inline size_t ext4_acl_size(int count) { if (count <= 4) { - return sizeof(ext3_acl_header) + - count * sizeof(ext3_acl_entry_short); + return sizeof(ext4_acl_header) + + count * sizeof(ext4_acl_entry_short); } else { - return sizeof(ext3_acl_header) + - 4 * sizeof(ext3_acl_entry_short) + - (count - 4) * sizeof(ext3_acl_entry); + return sizeof(ext4_acl_header) + + 4 * sizeof(ext4_acl_entry_short) + + (count - 4) * sizeof(ext4_acl_entry); } } -static inline int ext3_acl_count(size_t size) +static inline int ext4_acl_count(size_t size) { ssize_t s; - size -= sizeof(ext3_acl_header); - s = size - 4 * sizeof(ext3_acl_entry_short); + size -= sizeof(ext4_acl_header); + s = size - 4 * sizeof(ext4_acl_entry_short); if (s < 0) { - if (size % sizeof(ext3_acl_entry_short)) + if (size % sizeof(ext4_acl_entry_short)) return -1; - return size / sizeof(ext3_acl_entry_short); + return size / sizeof(ext4_acl_entry_short); } else { - if (s % sizeof(ext3_acl_entry)) + if (s % sizeof(ext4_acl_entry)) return -1; - return s / sizeof(ext3_acl_entry) + 4; + return s / sizeof(ext4_acl_entry) + 4; } } -#ifdef CONFIG_EXT3_FS_POSIX_ACL +#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL -/* Value for inode->u.ext3_i.i_acl and inode->u.ext3_i.i_default_acl +/* Value for inode->u.ext4_i.i_acl and inode->u.ext4_i.i_default_acl if the ACL has not been cached */ -#define EXT3_ACL_NOT_CACHED ((void *)-1) +#define EXT4_ACL_NOT_CACHED ((void *)-1) /* acl.c */ -extern int ext3_permission (struct inode *, int, struct nameidata *); -extern int ext3_acl_chmod (struct inode *); -extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); +extern int ext4_permission (struct inode *, int, struct nameidata *); +extern int ext4_acl_chmod (struct inode *); +extern int ext4_init_acl (handle_t *, struct inode *, struct inode *); -#else /* CONFIG_EXT3_FS_POSIX_ACL */ +#else /* CONFIG_EXT4DEV_FS_POSIX_ACL */ #include -#define ext3_permission NULL +#define ext4_permission NULL static inline int -ext3_acl_chmod(struct inode *inode) +ext4_acl_chmod(struct inode *inode) { return 0; } static inline int -ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) +ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) { return 0; } -#endif /* CONFIG_EXT3_FS_POSIX_ACL */ +#endif /* CONFIG_EXT4DEV_FS_POSIX_ACL */ diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index b41a7d7e20f0..357e4e50374a 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/balloc.c + * linux/fs/ext4/balloc.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -32,30 +32,30 @@ * The file system contains group descriptors which are located after the * super block. Each descriptor contains the number of the bitmap block and * the free blocks count in the block. The descriptors are loaded in memory - * when a file system is mounted (see ext3_read_super). + * when a file system is mounted (see ext4_read_super). */ #define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) /** - * ext3_get_group_desc() -- load group descriptor from disk + * ext4_get_group_desc() -- load group descriptor from disk * @sb: super block * @block_group: given block group * @bh: pointer to the buffer head to store the block * group descriptor */ -struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, +struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, unsigned int block_group, struct buffer_head ** bh) { unsigned long group_desc; unsigned long offset; - struct ext3_group_desc * desc; - struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext4_group_desc * desc; + struct ext4_sb_info *sbi = EXT4_SB(sb); if (block_group >= sbi->s_groups_count) { - ext3_error (sb, "ext3_get_group_desc", + ext4_error (sb, "ext4_get_group_desc", "block_group >= groups_count - " "block_group = %d, groups_count = %lu", block_group, sbi->s_groups_count); @@ -64,17 +64,17 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, } smp_rmb(); - group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(sb); - offset = block_group & (EXT3_DESC_PER_BLOCK(sb) - 1); + group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); + offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); if (!sbi->s_group_desc[group_desc]) { - ext3_error (sb, "ext3_get_group_desc", + ext4_error (sb, "ext4_get_group_desc", "Group descriptor not loaded - " "block_group = %d, group_desc = %lu, desc = %lu", block_group, group_desc, offset); return NULL; } - desc = (struct ext3_group_desc *) sbi->s_group_desc[group_desc]->b_data; + desc = (struct ext4_group_desc *) sbi->s_group_desc[group_desc]->b_data; if (bh) *bh = sbi->s_group_desc[group_desc]; return desc + offset; @@ -93,15 +93,15 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, static struct buffer_head * read_block_bitmap(struct super_block *sb, unsigned int block_group) { - struct ext3_group_desc * desc; + struct ext4_group_desc * desc; struct buffer_head * bh = NULL; - desc = ext3_get_group_desc (sb, block_group, NULL); + desc = ext4_get_group_desc (sb, block_group, NULL); if (!desc) goto error_out; bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); if (!bh) - ext3_error (sb, "read_block_bitmap", + ext4_error (sb, "read_block_bitmap", "Cannot read block bitmap - " "block_group = %d, block_bitmap = %u", block_group, le32_to_cpu(desc->bg_block_bitmap)); @@ -134,7 +134,7 @@ static void __rsv_window_dump(struct rb_root *root, int verbose, const char *fn) { struct rb_node *n; - struct ext3_reserve_window_node *rsv, *prev; + struct ext4_reserve_window_node *rsv, *prev; int bad; restart: @@ -144,7 +144,7 @@ restart: printk("Block Allocation Reservation Windows Map (%s):\n", fn); while (n) { - rsv = list_entry(n, struct ext3_reserve_window_node, rsv_node); + rsv = list_entry(n, struct ext4_reserve_window_node, rsv_node); if (verbose) printk("reservation window 0x%p " "start: %lu, end: %lu\n", @@ -196,13 +196,13 @@ restart: * otherwise, return 0; */ static int -goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal, +goal_in_my_reservation(struct ext4_reserve_window *rsv, ext4_grpblk_t grp_goal, unsigned int group, struct super_block * sb) { - ext3_fsblk_t group_first_block, group_last_block; + ext4_fsblk_t group_first_block, group_last_block; - group_first_block = ext3_group_first_block_no(sb, group); - group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); + group_first_block = ext4_group_first_block_no(sb, group); + group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1); if ((rsv->_rsv_start > group_last_block) || (rsv->_rsv_end < group_first_block)) @@ -222,17 +222,17 @@ goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal, * if the goal is not in any window. * Returns NULL if there are no windows or if all windows start after the goal. */ -static struct ext3_reserve_window_node * -search_reserve_window(struct rb_root *root, ext3_fsblk_t goal) +static struct ext4_reserve_window_node * +search_reserve_window(struct rb_root *root, ext4_fsblk_t goal) { struct rb_node *n = root->rb_node; - struct ext3_reserve_window_node *rsv; + struct ext4_reserve_window_node *rsv; if (!n) return NULL; do { - rsv = rb_entry(n, struct ext3_reserve_window_node, rsv_node); + rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node); if (goal < rsv->rsv_start) n = n->rb_left; @@ -249,33 +249,33 @@ search_reserve_window(struct rb_root *root, ext3_fsblk_t goal) */ if (rsv->rsv_start > goal) { n = rb_prev(&rsv->rsv_node); - rsv = rb_entry(n, struct ext3_reserve_window_node, rsv_node); + rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node); } return rsv; } /** - * ext3_rsv_window_add() -- Insert a window to the block reservation rb tree. + * ext4_rsv_window_add() -- Insert a window to the block reservation rb tree. * @sb: super block * @rsv: reservation window to add * * Must be called with rsv_lock hold. */ -void ext3_rsv_window_add(struct super_block *sb, - struct ext3_reserve_window_node *rsv) +void ext4_rsv_window_add(struct super_block *sb, + struct ext4_reserve_window_node *rsv) { - struct rb_root *root = &EXT3_SB(sb)->s_rsv_window_root; + struct rb_root *root = &EXT4_SB(sb)->s_rsv_window_root; struct rb_node *node = &rsv->rsv_node; - ext3_fsblk_t start = rsv->rsv_start; + ext4_fsblk_t start = rsv->rsv_start; struct rb_node ** p = &root->rb_node; struct rb_node * parent = NULL; - struct ext3_reserve_window_node *this; + struct ext4_reserve_window_node *this; while (*p) { parent = *p; - this = rb_entry(parent, struct ext3_reserve_window_node, rsv_node); + this = rb_entry(parent, struct ext4_reserve_window_node, rsv_node); if (start < this->rsv_start) p = &(*p)->rb_left; @@ -292,7 +292,7 @@ void ext3_rsv_window_add(struct super_block *sb, } /** - * ext3_rsv_window_remove() -- unlink a window from the reservation rb tree + * ext4_rsv_window_remove() -- unlink a window from the reservation rb tree * @sb: super block * @rsv: reservation window to remove * @@ -301,59 +301,59 @@ void ext3_rsv_window_add(struct super_block *sb, * rsv_lock hold. */ static void rsv_window_remove(struct super_block *sb, - struct ext3_reserve_window_node *rsv) + struct ext4_reserve_window_node *rsv) { - rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; rsv->rsv_alloc_hit = 0; - rb_erase(&rsv->rsv_node, &EXT3_SB(sb)->s_rsv_window_root); + rb_erase(&rsv->rsv_node, &EXT4_SB(sb)->s_rsv_window_root); } /* * rsv_is_empty() -- Check if the reservation window is allocated. * @rsv: given reservation window to check * - * returns 1 if the end block is EXT3_RESERVE_WINDOW_NOT_ALLOCATED. + * returns 1 if the end block is EXT4_RESERVE_WINDOW_NOT_ALLOCATED. */ -static inline int rsv_is_empty(struct ext3_reserve_window *rsv) +static inline int rsv_is_empty(struct ext4_reserve_window *rsv) { /* a valid reservation end block could not be 0 */ - return rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + return rsv->_rsv_end == EXT4_RESERVE_WINDOW_NOT_ALLOCATED; } /** - * ext3_init_block_alloc_info() + * ext4_init_block_alloc_info() * @inode: file inode structure * * Allocate and initialize the reservation window structure, and - * link the window to the ext3 inode structure at last + * link the window to the ext4 inode structure at last * * The reservation window structure is only dynamically allocated - * and linked to ext3 inode the first time the open file - * needs a new block. So, before every ext3_new_block(s) call, for + * and linked to ext4 inode the first time the open file + * needs a new block. So, before every ext4_new_block(s) call, for * regular files, we should check whether the reservation window * structure exists or not. In the latter case, this function is called. * Fail to do so will result in block reservation being turned off for that * open file. * - * This function is called from ext3_get_blocks_handle(), also called + * This function is called from ext4_get_blocks_handle(), also called * when setting the reservation window size through ioctl before the file * is open for write (needs block allocation). * * Needs truncate_mutex protection prior to call this function. */ -void ext3_init_block_alloc_info(struct inode *inode) +void ext4_init_block_alloc_info(struct inode *inode) { - struct ext3_inode_info *ei = EXT3_I(inode); - struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info; + struct ext4_inode_info *ei = EXT4_I(inode); + struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info; struct super_block *sb = inode->i_sb; block_i = kmalloc(sizeof(*block_i), GFP_NOFS); if (block_i) { - struct ext3_reserve_window_node *rsv = &block_i->rsv_window_node; + struct ext4_reserve_window_node *rsv = &block_i->rsv_window_node; - rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; /* * if filesystem is mounted with NORESERVATION, the goal @@ -363,7 +363,7 @@ void ext3_init_block_alloc_info(struct inode *inode) if (!test_opt(sb, RESERVATION)) rsv->rsv_goal_size = 0; else - rsv->rsv_goal_size = EXT3_DEFAULT_RESERVE_BLOCKS; + rsv->rsv_goal_size = EXT4_DEFAULT_RESERVE_BLOCKS; rsv->rsv_alloc_hit = 0; block_i->last_alloc_logical_block = 0; block_i->last_alloc_physical_block = 0; @@ -372,24 +372,24 @@ void ext3_init_block_alloc_info(struct inode *inode) } /** - * ext3_discard_reservation() + * ext4_discard_reservation() * @inode: inode * * Discard(free) block reservation window on last file close, or truncate * or at last iput(). * * It is being called in three cases: - * ext3_release_file(): last writer close the file - * ext3_clear_inode(): last iput(), when nobody link to this file. - * ext3_truncate(): when the block indirect map is about to change. + * ext4_release_file(): last writer close the file + * ext4_clear_inode(): last iput(), when nobody link to this file. + * ext4_truncate(): when the block indirect map is about to change. * */ -void ext3_discard_reservation(struct inode *inode) +void ext4_discard_reservation(struct inode *inode) { - struct ext3_inode_info *ei = EXT3_I(inode); - struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info; - struct ext3_reserve_window_node *rsv; - spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock; + struct ext4_inode_info *ei = EXT4_I(inode); + struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info; + struct ext4_reserve_window_node *rsv; + spinlock_t *rsv_lock = &EXT4_SB(inode->i_sb)->s_rsv_window_lock; if (!block_i) return; @@ -404,62 +404,62 @@ void ext3_discard_reservation(struct inode *inode) } /** - * ext3_free_blocks_sb() -- Free given blocks and update quota + * ext4_free_blocks_sb() -- Free given blocks and update quota * @handle: handle to this transaction * @sb: super block * @block: start physcial block to free * @count: number of blocks to free * @pdquot_freed_blocks: pointer to quota */ -void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb, - ext3_fsblk_t block, unsigned long count, +void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, + ext4_fsblk_t block, unsigned long count, unsigned long *pdquot_freed_blocks) { struct buffer_head *bitmap_bh = NULL; struct buffer_head *gd_bh; unsigned long block_group; - ext3_grpblk_t bit; + ext4_grpblk_t bit; unsigned long i; unsigned long overflow; - struct ext3_group_desc * desc; - struct ext3_super_block * es; - struct ext3_sb_info *sbi; + struct ext4_group_desc * desc; + struct ext4_super_block * es; + struct ext4_sb_info *sbi; int err = 0, ret; - ext3_grpblk_t group_freed; + ext4_grpblk_t group_freed; *pdquot_freed_blocks = 0; - sbi = EXT3_SB(sb); + sbi = EXT4_SB(sb); es = sbi->s_es; if (block < le32_to_cpu(es->s_first_data_block) || block + count < block || block + count > le32_to_cpu(es->s_blocks_count)) { - ext3_error (sb, "ext3_free_blocks", + ext4_error (sb, "ext4_free_blocks", "Freeing blocks not in datazone - " "block = "E3FSBLK", count = %lu", block, count); goto error_return; } - ext3_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1); + ext4_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1); do_more: overflow = 0; block_group = (block - le32_to_cpu(es->s_first_data_block)) / - EXT3_BLOCKS_PER_GROUP(sb); + EXT4_BLOCKS_PER_GROUP(sb); bit = (block - le32_to_cpu(es->s_first_data_block)) % - EXT3_BLOCKS_PER_GROUP(sb); + EXT4_BLOCKS_PER_GROUP(sb); /* * Check to see if we are freeing blocks across a group * boundary. */ - if (bit + count > EXT3_BLOCKS_PER_GROUP(sb)) { - overflow = bit + count - EXT3_BLOCKS_PER_GROUP(sb); + if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) { + overflow = bit + count - EXT4_BLOCKS_PER_GROUP(sb); count -= overflow; } brelse(bitmap_bh); bitmap_bh = read_block_bitmap(sb, block_group); if (!bitmap_bh) goto error_return; - desc = ext3_get_group_desc (sb, block_group, &gd_bh); + desc = ext4_get_group_desc (sb, block_group, &gd_bh); if (!desc) goto error_return; @@ -469,7 +469,7 @@ do_more: sbi->s_itb_per_group) || in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table), sbi->s_itb_per_group)) - ext3_error (sb, "ext3_free_blocks", + ext4_error (sb, "ext4_free_blocks", "Freeing blocks in system zones - " "Block = "E3FSBLK", count = %lu", block, count); @@ -480,7 +480,7 @@ do_more: */ /* @@@ check errors */ BUFFER_TRACE(bitmap_bh, "getting undo access"); - err = ext3_journal_get_undo_access(handle, bitmap_bh); + err = ext4_journal_get_undo_access(handle, bitmap_bh); if (err) goto error_return; @@ -490,7 +490,7 @@ do_more: * using it */ BUFFER_TRACE(gd_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, gd_bh); + err = ext4_journal_get_write_access(handle, gd_bh); if (err) goto error_return; @@ -542,7 +542,7 @@ do_more: BUFFER_TRACE(bitmap_bh, "set in b_committed_data"); J_ASSERT_BH(bitmap_bh, bh2jh(bitmap_bh)->b_committed_data != NULL); - ext3_set_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i, + ext4_set_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i, bh2jh(bitmap_bh)->b_committed_data); /* @@ -551,10 +551,10 @@ do_more: * the allocator uses. */ BUFFER_TRACE(bitmap_bh, "clear bit"); - if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group), + if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i, bitmap_bh->b_data)) { jbd_unlock_bh_state(bitmap_bh); - ext3_error(sb, __FUNCTION__, + ext4_error(sb, __FUNCTION__, "bit already cleared for block "E3FSBLK, block + i); jbd_lock_bh_state(bitmap_bh); @@ -574,11 +574,11 @@ do_more: /* We dirtied the bitmap block */ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); - err = ext3_journal_dirty_metadata(handle, bitmap_bh); + err = ext4_journal_dirty_metadata(handle, bitmap_bh); /* And the group descriptor block */ BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); - ret = ext3_journal_dirty_metadata(handle, gd_bh); + ret = ext4_journal_dirty_metadata(handle, gd_bh); if (!err) err = ret; *pdquot_freed_blocks += group_freed; @@ -590,40 +590,40 @@ do_more: sb->s_dirt = 1; error_return: brelse(bitmap_bh); - ext3_std_error(sb, err); + ext4_std_error(sb, err); return; } /** - * ext3_free_blocks() -- Free given blocks and update quota + * ext4_free_blocks() -- Free given blocks and update quota * @handle: handle for this transaction * @inode: inode * @block: start physical block to free * @count: number of blocks to count */ -void ext3_free_blocks(handle_t *handle, struct inode *inode, - ext3_fsblk_t block, unsigned long count) +void ext4_free_blocks(handle_t *handle, struct inode *inode, + ext4_fsblk_t block, unsigned long count) { struct super_block * sb; unsigned long dquot_freed_blocks; sb = inode->i_sb; if (!sb) { - printk ("ext3_free_blocks: nonexistent device"); + printk ("ext4_free_blocks: nonexistent device"); return; } - ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks); + ext4_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks); if (dquot_freed_blocks) DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); return; } /** - * ext3_test_allocatable() + * ext4_test_allocatable() * @nr: given allocation block group * @bh: bufferhead contains the bitmap of the given block group * - * For ext3 allocations, we must not reuse any blocks which are + * For ext4 allocations, we must not reuse any blocks which are * allocated in the bitmap buffer's "last committed data" copy. This * prevents deletes from freeing up the page for reuse until we have * committed the delete transaction. @@ -638,19 +638,19 @@ void ext3_free_blocks(handle_t *handle, struct inode *inode, * data-writes at some point, and disable it for metadata allocations or * sync-data inodes. */ -static int ext3_test_allocatable(ext3_grpblk_t nr, struct buffer_head *bh) +static int ext4_test_allocatable(ext4_grpblk_t nr, struct buffer_head *bh) { int ret; struct journal_head *jh = bh2jh(bh); - if (ext3_test_bit(nr, bh->b_data)) + if (ext4_test_bit(nr, bh->b_data)) return 0; jbd_lock_bh_state(bh); if (!jh->b_committed_data) ret = 1; else - ret = !ext3_test_bit(nr, jh->b_committed_data); + ret = !ext4_test_bit(nr, jh->b_committed_data); jbd_unlock_bh_state(bh); return ret; } @@ -665,22 +665,22 @@ static int ext3_test_allocatable(ext3_grpblk_t nr, struct buffer_head *bh) * bitmap on disk and the last-committed copy in journal, until we find a * bit free in both bitmaps. */ -static ext3_grpblk_t -bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, - ext3_grpblk_t maxblocks) +static ext4_grpblk_t +bitmap_search_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh, + ext4_grpblk_t maxblocks) { - ext3_grpblk_t next; + ext4_grpblk_t next; struct journal_head *jh = bh2jh(bh); while (start < maxblocks) { - next = ext3_find_next_zero_bit(bh->b_data, maxblocks, start); + next = ext4_find_next_zero_bit(bh->b_data, maxblocks, start); if (next >= maxblocks) return -1; - if (ext3_test_allocatable(next, bh)) + if (ext4_test_allocatable(next, bh)) return next; jbd_lock_bh_state(bh); if (jh->b_committed_data) - start = ext3_find_next_zero_bit(jh->b_committed_data, + start = ext4_find_next_zero_bit(jh->b_committed_data, maxblocks, next); jbd_unlock_bh_state(bh); } @@ -700,11 +700,11 @@ bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, * the initial goal; then for a free byte somewhere in the bitmap; then * for any free bit in the bitmap. */ -static ext3_grpblk_t -find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, - ext3_grpblk_t maxblocks) +static ext4_grpblk_t +find_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh, + ext4_grpblk_t maxblocks) { - ext3_grpblk_t here, next; + ext4_grpblk_t here, next; char *p, *r; if (start > 0) { @@ -713,16 +713,16 @@ find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, * block within the next XX blocks. * * end_goal is more or less random, but it has to be - * less than EXT3_BLOCKS_PER_GROUP. Aligning up to the + * less than EXT4_BLOCKS_PER_GROUP. Aligning up to the * next 64-bit boundary is simple.. */ - ext3_grpblk_t end_goal = (start + 63) & ~63; + ext4_grpblk_t end_goal = (start + 63) & ~63; if (end_goal > maxblocks) end_goal = maxblocks; - here = ext3_find_next_zero_bit(bh->b_data, end_goal, start); - if (here < end_goal && ext3_test_allocatable(here, bh)) + here = ext4_find_next_zero_bit(bh->b_data, end_goal, start); + if (here < end_goal && ext4_test_allocatable(here, bh)) return here; - ext3_debug("Bit not found near goal\n"); + ext4_debug("Bit not found near goal\n"); } here = start; @@ -733,7 +733,7 @@ find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, r = memscan(p, 0, (maxblocks - here + 7) >> 3); next = (r - ((char *)bh->b_data)) << 3; - if (next < maxblocks && next >= start && ext3_test_allocatable(next, bh)) + if (next < maxblocks && next >= start && ext4_test_allocatable(next, bh)) return next; /* @@ -757,16 +757,16 @@ find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, * zero (failure). */ static inline int -claim_block(spinlock_t *lock, ext3_grpblk_t block, struct buffer_head *bh) +claim_block(spinlock_t *lock, ext4_grpblk_t block, struct buffer_head *bh) { struct journal_head *jh = bh2jh(bh); int ret; - if (ext3_set_bit_atomic(lock, block, bh->b_data)) + if (ext4_set_bit_atomic(lock, block, bh->b_data)) return 0; jbd_lock_bh_state(bh); - if (jh->b_committed_data && ext3_test_bit(block,jh->b_committed_data)) { - ext3_clear_bit_atomic(lock, block, bh->b_data); + if (jh->b_committed_data && ext4_test_bit(block,jh->b_committed_data)) { + ext4_clear_bit_atomic(lock, block, bh->b_data); ret = 0; } else { ret = 1; @@ -776,7 +776,7 @@ claim_block(spinlock_t *lock, ext3_grpblk_t block, struct buffer_head *bh) } /** - * ext3_try_to_allocate() + * ext4_try_to_allocate() * @sb: superblock * @handle: handle to this transaction * @group: given allocation block group @@ -797,29 +797,29 @@ claim_block(spinlock_t *lock, ext3_grpblk_t block, struct buffer_head *bh) * * If we failed to allocate the desired block then we may end up crossing to a * new bitmap. In that case we must release write access to the old one via - * ext3_journal_release_buffer(), else we'll run out of credits. + * ext4_journal_release_buffer(), else we'll run out of credits. */ -static ext3_grpblk_t -ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group, - struct buffer_head *bitmap_bh, ext3_grpblk_t grp_goal, - unsigned long *count, struct ext3_reserve_window *my_rsv) +static ext4_grpblk_t +ext4_try_to_allocate(struct super_block *sb, handle_t *handle, int group, + struct buffer_head *bitmap_bh, ext4_grpblk_t grp_goal, + unsigned long *count, struct ext4_reserve_window *my_rsv) { - ext3_fsblk_t group_first_block; - ext3_grpblk_t start, end; + ext4_fsblk_t group_first_block; + ext4_grpblk_t start, end; unsigned long num = 0; /* we do allocation within the reservation window if we have a window */ if (my_rsv) { - group_first_block = ext3_group_first_block_no(sb, group); + group_first_block = ext4_group_first_block_no(sb, group); if (my_rsv->_rsv_start >= group_first_block) start = my_rsv->_rsv_start - group_first_block; else /* reservation window cross group boundary */ start = 0; end = my_rsv->_rsv_end - group_first_block + 1; - if (end > EXT3_BLOCKS_PER_GROUP(sb)) + if (end > EXT4_BLOCKS_PER_GROUP(sb)) /* reservation window crosses group boundary */ - end = EXT3_BLOCKS_PER_GROUP(sb); + end = EXT4_BLOCKS_PER_GROUP(sb); if ((start <= grp_goal) && (grp_goal < end)) start = grp_goal; else @@ -829,13 +829,13 @@ ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group, start = grp_goal; else start = 0; - end = EXT3_BLOCKS_PER_GROUP(sb); + end = EXT4_BLOCKS_PER_GROUP(sb); } - BUG_ON(start > EXT3_BLOCKS_PER_GROUP(sb)); + BUG_ON(start > EXT4_BLOCKS_PER_GROUP(sb)); repeat: - if (grp_goal < 0 || !ext3_test_allocatable(grp_goal, bitmap_bh)) { + if (grp_goal < 0 || !ext4_test_allocatable(grp_goal, bitmap_bh)) { grp_goal = find_next_usable_block(start, bitmap_bh, end); if (grp_goal < 0) goto fail_access; @@ -843,7 +843,7 @@ repeat: int i; for (i = 0; i < 7 && grp_goal > start && - ext3_test_allocatable(grp_goal - 1, + ext4_test_allocatable(grp_goal - 1, bitmap_bh); i++, grp_goal--) ; @@ -851,7 +851,7 @@ repeat: } start = grp_goal; - if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), + if (!claim_block(sb_bgl_lock(EXT4_SB(sb), group), grp_goal, bitmap_bh)) { /* * The block was allocated by another thread, or it was @@ -866,8 +866,8 @@ repeat: num++; grp_goal++; while (num < *count && grp_goal < end - && ext3_test_allocatable(grp_goal, bitmap_bh) - && claim_block(sb_bgl_lock(EXT3_SB(sb), group), + && ext4_test_allocatable(grp_goal, bitmap_bh) + && claim_block(sb_bgl_lock(EXT4_SB(sb), group), grp_goal, bitmap_bh)) { num++; grp_goal++; @@ -913,15 +913,15 @@ fail_access: * */ static int find_next_reservable_window( - struct ext3_reserve_window_node *search_head, - struct ext3_reserve_window_node *my_rsv, + struct ext4_reserve_window_node *search_head, + struct ext4_reserve_window_node *my_rsv, struct super_block * sb, - ext3_fsblk_t start_block, - ext3_fsblk_t last_block) + ext4_fsblk_t start_block, + ext4_fsblk_t last_block) { struct rb_node *next; - struct ext3_reserve_window_node *rsv, *prev; - ext3_fsblk_t cur; + struct ext4_reserve_window_node *rsv, *prev; + ext4_fsblk_t cur; int size = my_rsv->rsv_goal_size; /* TODO: make the start of the reservation window byte-aligned */ @@ -949,7 +949,7 @@ static int find_next_reservable_window( prev = rsv; next = rb_next(&rsv->rsv_node); - rsv = list_entry(next,struct ext3_reserve_window_node,rsv_node); + rsv = list_entry(next,struct ext4_reserve_window_node,rsv_node); /* * Reached the last reservation, we can just append to the @@ -992,7 +992,7 @@ static int find_next_reservable_window( my_rsv->rsv_alloc_hit = 0; if (prev != my_rsv) - ext3_rsv_window_add(sb, my_rsv); + ext4_rsv_window_add(sb, my_rsv); return 0; } @@ -1034,20 +1034,20 @@ static int find_next_reservable_window( * @bitmap_bh: the block group block bitmap * */ -static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, - ext3_grpblk_t grp_goal, struct super_block *sb, +static int alloc_new_reservation(struct ext4_reserve_window_node *my_rsv, + ext4_grpblk_t grp_goal, struct super_block *sb, unsigned int group, struct buffer_head *bitmap_bh) { - struct ext3_reserve_window_node *search_head; - ext3_fsblk_t group_first_block, group_end_block, start_block; - ext3_grpblk_t first_free_block; - struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root; + struct ext4_reserve_window_node *search_head; + ext4_fsblk_t group_first_block, group_end_block, start_block; + ext4_grpblk_t first_free_block; + struct rb_root *fs_rsv_root = &EXT4_SB(sb)->s_rsv_window_root; unsigned long size; int ret; - spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; + spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock; - group_first_block = ext3_group_first_block_no(sb, group); - group_end_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); + group_first_block = ext4_group_first_block_no(sb, group); + group_end_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1); if (grp_goal < 0) start_block = group_first_block; @@ -1085,8 +1085,8 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, * otherwise we keep the same size window */ size = size * 2; - if (size > EXT3_MAX_RESERVE_BLOCKS) - size = EXT3_MAX_RESERVE_BLOCKS; + if (size > EXT4_MAX_RESERVE_BLOCKS) + size = EXT4_MAX_RESERVE_BLOCKS; my_rsv->rsv_goal_size= size; } } @@ -1170,20 +1170,20 @@ retry: * Attempt to expand the reservation window large enough to have * required number of free blocks * - * Since ext3_try_to_allocate() will always allocate blocks within + * Since ext4_try_to_allocate() will always allocate blocks within * the reservation window range, if the window size is too small, * multiple blocks allocation has to stop at the end of the reservation * window. To make this more efficient, given the total number of * blocks needed and the current size of the window, we try to * expand the reservation window size if necessary on a best-effort - * basis before ext3_new_blocks() tries to allocate blocks, + * basis before ext4_new_blocks() tries to allocate blocks, */ -static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv, +static void try_to_extend_reservation(struct ext4_reserve_window_node *my_rsv, struct super_block *sb, int size) { - struct ext3_reserve_window_node *next_rsv; + struct ext4_reserve_window_node *next_rsv; struct rb_node *next; - spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; + spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock; if (!spin_trylock(rsv_lock)) return; @@ -1193,7 +1193,7 @@ static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv, if (!next) my_rsv->rsv_end += size; else { - next_rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node); + next_rsv = list_entry(next, struct ext4_reserve_window_node, rsv_node); if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size) my_rsv->rsv_end += size; @@ -1204,7 +1204,7 @@ static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv, } /** - * ext3_try_to_allocate_with_rsv() + * ext4_try_to_allocate_with_rsv() * @sb: superblock * @handle: handle to this transaction * @group: given allocation block group @@ -1232,15 +1232,15 @@ static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv, * We use a red-black tree for the per-filesystem reservation list. * */ -static ext3_grpblk_t -ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, +static ext4_grpblk_t +ext4_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, unsigned int group, struct buffer_head *bitmap_bh, - ext3_grpblk_t grp_goal, - struct ext3_reserve_window_node * my_rsv, + ext4_grpblk_t grp_goal, + struct ext4_reserve_window_node * my_rsv, unsigned long *count, int *errp) { - ext3_fsblk_t group_first_block, group_last_block; - ext3_grpblk_t ret = 0; + ext4_fsblk_t group_first_block, group_last_block; + ext4_grpblk_t ret = 0; int fatal; unsigned long num = *count; @@ -1252,7 +1252,7 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, * if the buffer is in BJ_Forget state in the committing transaction. */ BUFFER_TRACE(bitmap_bh, "get undo access for new block"); - fatal = ext3_journal_get_undo_access(handle, bitmap_bh); + fatal = ext4_journal_get_undo_access(handle, bitmap_bh); if (fatal) { *errp = fatal; return -1; @@ -1265,18 +1265,18 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, * or last attempt to allocate a block with reservation turned on failed */ if (my_rsv == NULL ) { - ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, + ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh, grp_goal, count, NULL); goto out; } /* * grp_goal is a group relative block number (if there is a goal) - * 0 < grp_goal < EXT3_BLOCKS_PER_GROUP(sb) + * 0 < grp_goal < EXT4_BLOCKS_PER_GROUP(sb) * first block is a filesystem wide block number * first block is the block number of the first block in this group */ - group_first_block = ext3_group_first_block_no(sb, group); - group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); + group_first_block = ext4_group_first_block_no(sb, group); + group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1); /* * Basically we will allocate a new block from inode's reservation @@ -1314,10 +1314,10 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, if ((my_rsv->rsv_start > group_last_block) || (my_rsv->rsv_end < group_first_block)) { - rsv_window_dump(&EXT3_SB(sb)->s_rsv_window_root, 1); + rsv_window_dump(&EXT4_SB(sb)->s_rsv_window_root, 1); BUG(); } - ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, + ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh, grp_goal, &num, &my_rsv->rsv_window); if (ret >= 0) { my_rsv->rsv_alloc_hit += num; @@ -1330,7 +1330,7 @@ out: if (ret >= 0) { BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for " "bitmap block"); - fatal = ext3_journal_dirty_metadata(handle, bitmap_bh); + fatal = ext4_journal_dirty_metadata(handle, bitmap_bh); if (fatal) { *errp = fatal; return -1; @@ -1339,19 +1339,19 @@ out: } BUFFER_TRACE(bitmap_bh, "journal_release_buffer"); - ext3_journal_release_buffer(handle, bitmap_bh); + ext4_journal_release_buffer(handle, bitmap_bh); return ret; } /** - * ext3_has_free_blocks() + * ext4_has_free_blocks() * @sbi: in-core super block structure. * * Check if filesystem has at least 1 free block available for allocation. */ -static int ext3_has_free_blocks(struct ext3_sb_info *sbi) +static int ext4_has_free_blocks(struct ext4_sb_info *sbi) { - ext3_fsblk_t free_blocks, root_blocks; + ext4_fsblk_t free_blocks, root_blocks; free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); @@ -1364,63 +1364,63 @@ static int ext3_has_free_blocks(struct ext3_sb_info *sbi) } /** - * ext3_should_retry_alloc() + * ext4_should_retry_alloc() * @sb: super block * @retries number of attemps has been made * - * ext3_should_retry_alloc() is called when ENOSPC is returned, and if + * ext4_should_retry_alloc() is called when ENOSPC is returned, and if * it is profitable to retry the operation, this function will wait * for the current or commiting transaction to complete, and then * return TRUE. * * if the total number of retries exceed three times, return FALSE. */ -int ext3_should_retry_alloc(struct super_block *sb, int *retries) +int ext4_should_retry_alloc(struct super_block *sb, int *retries) { - if (!ext3_has_free_blocks(EXT3_SB(sb)) || (*retries)++ > 3) + if (!ext4_has_free_blocks(EXT4_SB(sb)) || (*retries)++ > 3) return 0; jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id); - return journal_force_commit_nested(EXT3_SB(sb)->s_journal); + return journal_force_commit_nested(EXT4_SB(sb)->s_journal); } /** - * ext3_new_blocks() -- core block(s) allocation function + * ext4_new_blocks() -- core block(s) allocation function * @handle: handle to this transaction * @inode: file inode * @goal: given target block(filesystem wide) * @count: target number of blocks to allocate * @errp: error code * - * ext3_new_blocks uses a goal block to assist allocation. It tries to + * ext4_new_blocks uses a goal block to assist allocation. It tries to * allocate block(s) from the block group contains the goal block first. If that * fails, it will try to allocate block(s) from other block groups without * any specific goal block. * */ -ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode, - ext3_fsblk_t goal, unsigned long *count, int *errp) +ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, + ext4_fsblk_t goal, unsigned long *count, int *errp) { struct buffer_head *bitmap_bh = NULL; struct buffer_head *gdp_bh; int group_no; int goal_group; - ext3_grpblk_t grp_target_blk; /* blockgroup relative goal block */ - ext3_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/ - ext3_fsblk_t ret_block; /* filesyetem-wide allocated block */ + ext4_grpblk_t grp_target_blk; /* blockgroup relative goal block */ + ext4_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/ + ext4_fsblk_t ret_block; /* filesyetem-wide allocated block */ int bgi; /* blockgroup iteration index */ int fatal = 0, err; int performed_allocation = 0; - ext3_grpblk_t free_blocks; /* number of free blocks in a group */ + ext4_grpblk_t free_blocks; /* number of free blocks in a group */ struct super_block *sb; - struct ext3_group_desc *gdp; - struct ext3_super_block *es; - struct ext3_sb_info *sbi; - struct ext3_reserve_window_node *my_rsv = NULL; - struct ext3_block_alloc_info *block_i; + struct ext4_group_desc *gdp; + struct ext4_super_block *es; + struct ext4_sb_info *sbi; + struct ext4_reserve_window_node *my_rsv = NULL; + struct ext4_block_alloc_info *block_i; unsigned short windowsz = 0; -#ifdef EXT3FS_DEBUG +#ifdef EXT4FS_DEBUG static int goal_hits, goal_attempts; #endif unsigned long ngroups; @@ -1429,7 +1429,7 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode, *errp = -ENOSPC; sb = inode->i_sb; if (!sb) { - printk("ext3_new_block: nonexistent device"); + printk("ext4_new_block: nonexistent device"); return 0; } @@ -1441,22 +1441,22 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode, return 0; } - sbi = EXT3_SB(sb); - es = EXT3_SB(sb)->s_es; - ext3_debug("goal=%lu.\n", goal); + sbi = EXT4_SB(sb); + es = EXT4_SB(sb)->s_es; + ext4_debug("goal=%lu.\n", goal); /* * Allocate a block from reservation only when * filesystem is mounted with reservation(default,-o reservation), and * it's a regular file, and * the desired window size is greater than 0 (One could use ioctl - * command EXT3_IOC_SETRSVSZ to set the window size to 0 to turn off + * command EXT4_IOC_SETRSVSZ to set the window size to 0 to turn off * reservation on that particular file) */ - block_i = EXT3_I(inode)->i_block_alloc_info; + block_i = EXT4_I(inode)->i_block_alloc_info; if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0)) my_rsv = &block_i->rsv_window_node; - if (!ext3_has_free_blocks(sbi)) { + if (!ext4_has_free_blocks(sbi)) { *errp = -ENOSPC; goto out; } @@ -1468,10 +1468,10 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode, goal >= le32_to_cpu(es->s_blocks_count)) goal = le32_to_cpu(es->s_first_data_block); group_no = (goal - le32_to_cpu(es->s_first_data_block)) / - EXT3_BLOCKS_PER_GROUP(sb); + EXT4_BLOCKS_PER_GROUP(sb); goal_group = group_no; retry_alloc: - gdp = ext3_get_group_desc(sb, group_no, &gdp_bh); + gdp = ext4_get_group_desc(sb, group_no, &gdp_bh); if (!gdp) goto io_error; @@ -1486,11 +1486,11 @@ retry_alloc: if (free_blocks > 0) { grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) % - EXT3_BLOCKS_PER_GROUP(sb)); + EXT4_BLOCKS_PER_GROUP(sb)); bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) goto io_error; - grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle, + grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle, group_no, bitmap_bh, grp_target_blk, my_rsv, &num, &fatal); if (fatal) @@ -1499,7 +1499,7 @@ retry_alloc: goto allocated; } - ngroups = EXT3_SB(sb)->s_groups_count; + ngroups = EXT4_SB(sb)->s_groups_count; smp_rmb(); /* @@ -1510,7 +1510,7 @@ retry_alloc: group_no++; if (group_no >= ngroups) group_no = 0; - gdp = ext3_get_group_desc(sb, group_no, &gdp_bh); + gdp = ext4_get_group_desc(sb, group_no, &gdp_bh); if (!gdp) { *errp = -EIO; goto out; @@ -1531,7 +1531,7 @@ retry_alloc: /* * try to allocate block(s) from this group, without a goal(-1). */ - grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle, + grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle, group_no, bitmap_bh, -1, my_rsv, &num, &fatal); if (fatal) @@ -1557,23 +1557,23 @@ retry_alloc: allocated: - ext3_debug("using block group %d(%d)\n", + ext4_debug("using block group %d(%d)\n", group_no, gdp->bg_free_blocks_count); BUFFER_TRACE(gdp_bh, "get_write_access"); - fatal = ext3_journal_get_write_access(handle, gdp_bh); + fatal = ext4_journal_get_write_access(handle, gdp_bh); if (fatal) goto out; - ret_block = grp_alloc_blk + ext3_group_first_block_no(sb, group_no); + ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no); if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) || in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) || in_range(ret_block, le32_to_cpu(gdp->bg_inode_table), - EXT3_SB(sb)->s_itb_per_group) || + EXT4_SB(sb)->s_itb_per_group) || in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table), - EXT3_SB(sb)->s_itb_per_group)) - ext3_error(sb, "ext3_new_block", + EXT4_SB(sb)->s_itb_per_group)) + ext4_error(sb, "ext4_new_block", "Allocating block in system zone - " "blocks from "E3FSBLK", length %lu", ret_block, num); @@ -1598,20 +1598,20 @@ allocated: int i; for (i = 0; i < num; i++) { - if (ext3_test_bit(grp_alloc_blk+i, + if (ext4_test_bit(grp_alloc_blk+i, bh2jh(bitmap_bh)->b_committed_data)) { printk("%s: block was unexpectedly set in " "b_committed_data\n", __FUNCTION__); } } } - ext3_debug("found bit %d\n", grp_alloc_blk); + ext4_debug("found bit %d\n", grp_alloc_blk); spin_unlock(sb_bgl_lock(sbi, group_no)); jbd_unlock_bh_state(bitmap_bh); #endif if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) { - ext3_error(sb, "ext3_new_block", + ext4_error(sb, "ext4_new_block", "block("E3FSBLK") >= blocks count(%d) - " "block_group = %d, es == %p ", ret_block, le32_to_cpu(es->s_blocks_count), group_no, es); @@ -1623,7 +1623,7 @@ allocated: * list of some description. We don't know in advance whether * the caller wants to use it as metadata or data. */ - ext3_debug("allocating block %lu. Goal hits %d of %d.\n", + ext4_debug("allocating block %lu. Goal hits %d of %d.\n", ret_block, goal_hits, goal_attempts); spin_lock(sb_bgl_lock(sbi, group_no)); @@ -1633,7 +1633,7 @@ allocated: percpu_counter_mod(&sbi->s_freeblocks_counter, -num); BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); - err = ext3_journal_dirty_metadata(handle, gdp_bh); + err = ext4_journal_dirty_metadata(handle, gdp_bh); if (!fatal) fatal = err; @@ -1652,7 +1652,7 @@ io_error: out: if (fatal) { *errp = fatal; - ext3_std_error(sb, fatal); + ext4_std_error(sb, fatal); } /* * Undo the block allocation @@ -1663,40 +1663,40 @@ out: return 0; } -ext3_fsblk_t ext3_new_block(handle_t *handle, struct inode *inode, - ext3_fsblk_t goal, int *errp) +ext4_fsblk_t ext4_new_block(handle_t *handle, struct inode *inode, + ext4_fsblk_t goal, int *errp) { unsigned long count = 1; - return ext3_new_blocks(handle, inode, goal, &count, errp); + return ext4_new_blocks(handle, inode, goal, &count, errp); } /** - * ext3_count_free_blocks() -- count filesystem free blocks + * ext4_count_free_blocks() -- count filesystem free blocks * @sb: superblock * * Adds up the number of free blocks from each block group. */ -ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb) +ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb) { - ext3_fsblk_t desc_count; - struct ext3_group_desc *gdp; + ext4_fsblk_t desc_count; + struct ext4_group_desc *gdp; int i; - unsigned long ngroups = EXT3_SB(sb)->s_groups_count; -#ifdef EXT3FS_DEBUG - struct ext3_super_block *es; - ext3_fsblk_t bitmap_count; + unsigned long ngroups = EXT4_SB(sb)->s_groups_count; +#ifdef EXT4FS_DEBUG + struct ext4_super_block *es; + ext4_fsblk_t bitmap_count; unsigned long x; struct buffer_head *bitmap_bh = NULL; - es = EXT3_SB(sb)->s_es; + es = EXT4_SB(sb)->s_es; desc_count = 0; bitmap_count = 0; gdp = NULL; smp_rmb(); for (i = 0; i < ngroups; i++) { - gdp = ext3_get_group_desc(sb, i, NULL); + gdp = ext4_get_group_desc(sb, i, NULL); if (!gdp) continue; desc_count += le16_to_cpu(gdp->bg_free_blocks_count); @@ -1705,13 +1705,13 @@ ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb) if (bitmap_bh == NULL) continue; - x = ext3_count_free(bitmap_bh, sb->s_blocksize); + x = ext4_count_free(bitmap_bh, sb->s_blocksize); printk("group %d: stored = %d, counted = %lu\n", i, le16_to_cpu(gdp->bg_free_blocks_count), x); bitmap_count += x; } brelse(bitmap_bh); - printk("ext3_count_free_blocks: stored = "E3FSBLK + printk("ext4_count_free_blocks: stored = "E3FSBLK ", computed = "E3FSBLK", "E3FSBLK"\n", le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count); @@ -1720,7 +1720,7 @@ ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb) desc_count = 0; smp_rmb(); for (i = 0; i < ngroups; i++) { - gdp = ext3_get_group_desc(sb, i, NULL); + gdp = ext4_get_group_desc(sb, i, NULL); if (!gdp) continue; desc_count += le16_to_cpu(gdp->bg_free_blocks_count); @@ -1731,11 +1731,11 @@ ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb) } static inline int -block_in_use(ext3_fsblk_t block, struct super_block *sb, unsigned char *map) +block_in_use(ext4_fsblk_t block, struct super_block *sb, unsigned char *map) { - return ext3_test_bit ((block - - le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) % - EXT3_BLOCKS_PER_GROUP(sb), map); + return ext4_test_bit ((block - + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) % + EXT4_BLOCKS_PER_GROUP(sb), map); } static inline int test_root(int a, int b) @@ -1747,7 +1747,7 @@ static inline int test_root(int a, int b) return num == a; } -static int ext3_group_sparse(int group) +static int ext4_group_sparse(int group) { if (group <= 1) return 1; @@ -1758,44 +1758,44 @@ static int ext3_group_sparse(int group) } /** - * ext3_bg_has_super - number of blocks used by the superblock in group + * ext4_bg_has_super - number of blocks used by the superblock in group * @sb: superblock for filesystem * @group: group number to check * * Return the number of blocks used by the superblock (primary or backup) * in this group. Currently this will be only 0 or 1. */ -int ext3_bg_has_super(struct super_block *sb, int group) +int ext4_bg_has_super(struct super_block *sb, int group) { - if (EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) && - !ext3_group_sparse(group)) + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, + EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) && + !ext4_group_sparse(group)) return 0; return 1; } -static unsigned long ext3_bg_num_gdb_meta(struct super_block *sb, int group) +static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb, int group) { - unsigned long metagroup = group / EXT3_DESC_PER_BLOCK(sb); - unsigned long first = metagroup * EXT3_DESC_PER_BLOCK(sb); - unsigned long last = first + EXT3_DESC_PER_BLOCK(sb) - 1; + unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb); + unsigned long first = metagroup * EXT4_DESC_PER_BLOCK(sb); + unsigned long last = first + EXT4_DESC_PER_BLOCK(sb) - 1; if (group == first || group == first + 1 || group == last) return 1; return 0; } -static unsigned long ext3_bg_num_gdb_nometa(struct super_block *sb, int group) +static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb, int group) { - if (EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) && - !ext3_group_sparse(group)) + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, + EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) && + !ext4_group_sparse(group)) return 0; - return EXT3_SB(sb)->s_gdb_count; + return EXT4_SB(sb)->s_gdb_count; } /** - * ext3_bg_num_gdb - number of blocks used by the group table in group + * ext4_bg_num_gdb - number of blocks used by the group table in group * @sb: superblock for filesystem * @group: group number to check * @@ -1803,16 +1803,16 @@ static unsigned long ext3_bg_num_gdb_nometa(struct super_block *sb, int group) * (primary or backup) in this group. In the future there may be a * different number of descriptor blocks in each group. */ -unsigned long ext3_bg_num_gdb(struct super_block *sb, int group) +unsigned long ext4_bg_num_gdb(struct super_block *sb, int group) { unsigned long first_meta_bg = - le32_to_cpu(EXT3_SB(sb)->s_es->s_first_meta_bg); - unsigned long metagroup = group / EXT3_DESC_PER_BLOCK(sb); + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg); + unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb); - if (!EXT3_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_META_BG) || + if (!EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) || metagroup < first_meta_bg) - return ext3_bg_num_gdb_nometa(sb,group); + return ext4_bg_num_gdb_nometa(sb,group); - return ext3_bg_num_gdb_meta(sb,group); + return ext4_bg_num_gdb_meta(sb,group); } diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c index b9176eed98d1..f4b35706f39c 100644 --- a/fs/ext4/bitmap.c +++ b/fs/ext4/bitmap.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/bitmap.c + * linux/fs/ext4/bitmap.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -9,13 +9,13 @@ #include #include -#include +#include -#ifdef EXT3FS_DEBUG +#ifdef EXT4FS_DEBUG static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; -unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars) +unsigned long ext4_count_free (struct buffer_head * map, unsigned int numchars) { unsigned int i; unsigned long sum = 0; @@ -28,5 +28,5 @@ unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars) return (sum); } -#endif /* EXT3FS_DEBUG */ +#endif /* EXT4FS_DEBUG */ diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index d0b54f30b914..ec114d7886cc 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/dir.c + * linux/fs/ext4/dir.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -12,7 +12,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * - * ext3 directory handling functions + * ext4 directory handling functions * * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 @@ -23,69 +23,69 @@ #include #include -#include +#include #include #include #include #include -static unsigned char ext3_filetype_table[] = { +static unsigned char ext4_filetype_table[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK }; -static int ext3_readdir(struct file *, void *, filldir_t); -static int ext3_dx_readdir(struct file * filp, +static int ext4_readdir(struct file *, void *, filldir_t); +static int ext4_dx_readdir(struct file * filp, void * dirent, filldir_t filldir); -static int ext3_release_dir (struct inode * inode, +static int ext4_release_dir (struct inode * inode, struct file * filp); -const struct file_operations ext3_dir_operations = { +const struct file_operations ext4_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, - .readdir = ext3_readdir, /* we take BKL. needed?*/ - .ioctl = ext3_ioctl, /* BKL held */ + .readdir = ext4_readdir, /* we take BKL. needed?*/ + .ioctl = ext4_ioctl, /* BKL held */ #ifdef CONFIG_COMPAT - .compat_ioctl = ext3_compat_ioctl, + .compat_ioctl = ext4_compat_ioctl, #endif - .fsync = ext3_sync_file, /* BKL held */ -#ifdef CONFIG_EXT3_INDEX - .release = ext3_release_dir, + .fsync = ext4_sync_file, /* BKL held */ +#ifdef CONFIG_EXT4_INDEX + .release = ext4_release_dir, #endif }; static unsigned char get_dtype(struct super_block *sb, int filetype) { - if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_FILETYPE) || - (filetype >= EXT3_FT_MAX)) + if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) || + (filetype >= EXT4_FT_MAX)) return DT_UNKNOWN; - return (ext3_filetype_table[filetype]); + return (ext4_filetype_table[filetype]); } -int ext3_check_dir_entry (const char * function, struct inode * dir, - struct ext3_dir_entry_2 * de, +int ext4_check_dir_entry (const char * function, struct inode * dir, + struct ext4_dir_entry_2 * de, struct buffer_head * bh, unsigned long offset) { const char * error_msg = NULL; const int rlen = le16_to_cpu(de->rec_len); - if (rlen < EXT3_DIR_REC_LEN(1)) + if (rlen < EXT4_DIR_REC_LEN(1)) error_msg = "rec_len is smaller than minimal"; else if (rlen % 4 != 0) error_msg = "rec_len % 4 != 0"; - else if (rlen < EXT3_DIR_REC_LEN(de->name_len)) + else if (rlen < EXT4_DIR_REC_LEN(de->name_len)) error_msg = "rec_len is too small for name_len"; else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) error_msg = "directory entry across blocks"; else if (le32_to_cpu(de->inode) > - le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count)) + le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count)) error_msg = "inode out of bounds"; if (error_msg != NULL) - ext3_error (dir->i_sb, function, + ext4_error (dir->i_sb, function, "bad entry in directory #%lu: %s - " "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", dir->i_ino, error_msg, offset, @@ -94,13 +94,13 @@ int ext3_check_dir_entry (const char * function, struct inode * dir, return error_msg == NULL ? 1 : 0; } -static int ext3_readdir(struct file * filp, +static int ext4_readdir(struct file * filp, void * dirent, filldir_t filldir) { int error = 0; unsigned long offset; int i, stored; - struct ext3_dir_entry_2 *de; + struct ext4_dir_entry_2 *de; struct super_block *sb; int err; struct inode *inode = filp->f_dentry->d_inode; @@ -108,12 +108,12 @@ static int ext3_readdir(struct file * filp, sb = inode->i_sb; -#ifdef CONFIG_EXT3_INDEX - if (EXT3_HAS_COMPAT_FEATURE(inode->i_sb, - EXT3_FEATURE_COMPAT_DIR_INDEX) && - ((EXT3_I(inode)->i_flags & EXT3_INDEX_FL) || +#ifdef CONFIG_EXT4_INDEX + if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb, + EXT4_FEATURE_COMPAT_DIR_INDEX) && + ((EXT4_I(inode)->i_flags & EXT4_INDEX_FL) || ((inode->i_size >> sb->s_blocksize_bits) == 1))) { - err = ext3_dx_readdir(filp, dirent, filldir); + err = ext4_dx_readdir(filp, dirent, filldir); if (err != ERR_BAD_DX_DIR) { ret = err; goto out; @@ -122,19 +122,19 @@ static int ext3_readdir(struct file * filp, * We don't set the inode dirty flag since it's not * critical that it get flushed back to the disk. */ - EXT3_I(filp->f_dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL; + EXT4_I(filp->f_dentry->d_inode)->i_flags &= ~EXT4_INDEX_FL; } #endif stored = 0; offset = filp->f_pos & (sb->s_blocksize - 1); while (!error && !stored && filp->f_pos < inode->i_size) { - unsigned long blk = filp->f_pos >> EXT3_BLOCK_SIZE_BITS(sb); + unsigned long blk = filp->f_pos >> EXT4_BLOCK_SIZE_BITS(sb); struct buffer_head map_bh; struct buffer_head *bh = NULL; map_bh.b_state = 0; - err = ext3_get_blocks_handle(NULL, inode, blk, 1, + err = ext4_get_blocks_handle(NULL, inode, blk, 1, &map_bh, 0, 0); if (err > 0) { page_cache_readahead(sb->s_bdev->bd_inode->i_mapping, @@ -143,7 +143,7 @@ static int ext3_readdir(struct file * filp, map_bh.b_blocknr >> (PAGE_CACHE_SHIFT - inode->i_blkbits), 1); - bh = ext3_bread(NULL, inode, blk, 0, &err); + bh = ext4_bread(NULL, inode, blk, 0, &err); } /* @@ -151,7 +151,7 @@ static int ext3_readdir(struct file * filp, * of recovering data when there's a bad sector */ if (!bh) { - ext3_error (sb, "ext3_readdir", + ext4_error (sb, "ext4_readdir", "directory #%lu contains a hole at offset %lu", inode->i_ino, (unsigned long)filp->f_pos); filp->f_pos += sb->s_blocksize - offset; @@ -165,7 +165,7 @@ revalidate: * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { - de = (struct ext3_dir_entry_2 *) + de = (struct ext4_dir_entry_2 *) (bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this @@ -174,7 +174,7 @@ revalidate: * failure will be detected in the * dirent test below. */ if (le16_to_cpu(de->rec_len) < - EXT3_DIR_REC_LEN(1)) + EXT4_DIR_REC_LEN(1)) break; i += le16_to_cpu(de->rec_len); } @@ -186,8 +186,8 @@ revalidate: while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { - de = (struct ext3_dir_entry_2 *) (bh->b_data + offset); - if (!ext3_check_dir_entry ("ext3_readdir", inode, de, + de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); + if (!ext4_check_dir_entry ("ext4_readdir", inode, de, bh, offset)) { /* On error, skip the f_pos to the next block. */ @@ -228,7 +228,7 @@ out: return ret; } -#ifdef CONFIG_EXT3_INDEX +#ifdef CONFIG_EXT4_INDEX /* * These functions convert from the major/minor hash to an f_pos * value. @@ -323,7 +323,7 @@ static struct dir_private_info *create_dir_info(loff_t pos) return p; } -void ext3_htree_free_dir_info(struct dir_private_info *p) +void ext4_htree_free_dir_info(struct dir_private_info *p) { free_rb_tree_fname(&p->root); kfree(p); @@ -332,9 +332,9 @@ void ext3_htree_free_dir_info(struct dir_private_info *p) /* * Given a directory entry, enter it into the fname rb tree. */ -int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, +int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, __u32 minor_hash, - struct ext3_dir_entry_2 *dirent) + struct ext4_dir_entry_2 *dirent) { struct rb_node **p, *parent = NULL; struct fname * fname, *new_fn; @@ -390,7 +390,7 @@ int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, /* - * This is a helper function for ext3_dx_readdir. It calls filldir + * This is a helper function for ext4_dx_readdir. It calls filldir * for all entres on the fname linked list. (Normally there is only * one entry on the linked list, unless there are 62 bit hash collisions.) */ @@ -425,7 +425,7 @@ static int call_filldir(struct file * filp, void * dirent, return 0; } -static int ext3_dx_readdir(struct file * filp, +static int ext4_dx_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct dir_private_info *info = filp->private_data; @@ -440,7 +440,7 @@ static int ext3_dx_readdir(struct file * filp, filp->private_data = info; } - if (filp->f_pos == EXT3_HTREE_EOF) + if (filp->f_pos == EXT4_HTREE_EOF) return 0; /* EOF */ /* Some one has messed with f_pos; reset the world */ @@ -474,13 +474,13 @@ static int ext3_dx_readdir(struct file * filp, info->curr_node = NULL; free_rb_tree_fname(&info->root); filp->f_version = inode->i_version; - ret = ext3_htree_fill_tree(filp, info->curr_hash, + ret = ext4_htree_fill_tree(filp, info->curr_hash, info->curr_minor_hash, &info->next_hash); if (ret < 0) return ret; if (ret == 0) { - filp->f_pos = EXT3_HTREE_EOF; + filp->f_pos = EXT4_HTREE_EOF; break; } info->curr_node = rb_first(&info->root); @@ -495,7 +495,7 @@ static int ext3_dx_readdir(struct file * filp, info->curr_node = rb_next(info->curr_node); if (!info->curr_node) { if (info->next_hash == ~0) { - filp->f_pos = EXT3_HTREE_EOF; + filp->f_pos = EXT4_HTREE_EOF; break; } info->curr_hash = info->next_hash; @@ -507,10 +507,10 @@ finished: return 0; } -static int ext3_release_dir (struct inode * inode, struct file * filp) +static int ext4_release_dir (struct inode * inode, struct file * filp) { if (filp->private_data) - ext3_htree_free_dir_info(filp->private_data); + ext4_htree_free_dir_info(filp->private_data); return 0; } diff --git a/fs/ext4/file.c b/fs/ext4/file.c index e96c388047e0..d938fbe1e08b 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/file.c + * linux/fs/ext4/file.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -12,7 +12,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * - * ext3 fs regular file handling primitives + * ext4 fs regular file handling primitives * * 64-bit file support on 64-bit platforms by Jakub Jelinek * (jj@sunsite.ms.mff.cuni.cz) @@ -21,34 +21,34 @@ #include #include #include -#include -#include +#include +#include #include "xattr.h" #include "acl.h" /* * Called when an inode is released. Note that this is different - * from ext3_file_open: open gets called at every open, but release + * from ext4_file_open: open gets called at every open, but release * gets called only when /all/ the files are closed. */ -static int ext3_release_file (struct inode * inode, struct file * filp) +static int ext4_release_file (struct inode * inode, struct file * filp) { /* if we are the last writer on the inode, drop the block reservation */ if ((filp->f_mode & FMODE_WRITE) && (atomic_read(&inode->i_writecount) == 1)) { - mutex_lock(&EXT3_I(inode)->truncate_mutex); - ext3_discard_reservation(inode); - mutex_unlock(&EXT3_I(inode)->truncate_mutex); + mutex_lock(&EXT4_I(inode)->truncate_mutex); + ext4_discard_reservation(inode); + mutex_unlock(&EXT4_I(inode)->truncate_mutex); } if (is_dx(inode) && filp->private_data) - ext3_htree_free_dir_info(filp->private_data); + ext4_htree_free_dir_info(filp->private_data); return 0; } static ssize_t -ext3_file_write(struct kiocb *iocb, const struct iovec *iov, +ext4_file_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { struct file *file = iocb->ki_filp; @@ -79,7 +79,7 @@ ext3_file_write(struct kiocb *iocb, const struct iovec *iov, * Open question --- do we care about flushing timestamps too * if the inode is IS_SYNC? */ - if (!ext3_should_journal_data(inode)) + if (!ext4_should_journal_data(inode)) return ret; goto force_commit; @@ -100,40 +100,40 @@ ext3_file_write(struct kiocb *iocb, const struct iovec *iov, */ force_commit: - err = ext3_force_commit(inode->i_sb); + err = ext4_force_commit(inode->i_sb); if (err) return err; return ret; } -const struct file_operations ext3_file_operations = { +const struct file_operations ext4_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, - .aio_write = ext3_file_write, - .ioctl = ext3_ioctl, + .aio_write = ext4_file_write, + .ioctl = ext4_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = ext3_compat_ioctl, + .compat_ioctl = ext4_compat_ioctl, #endif .mmap = generic_file_mmap, .open = generic_file_open, - .release = ext3_release_file, - .fsync = ext3_sync_file, + .release = ext4_release_file, + .fsync = ext4_sync_file, .sendfile = generic_file_sendfile, .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, }; -struct inode_operations ext3_file_inode_operations = { - .truncate = ext3_truncate, - .setattr = ext3_setattr, -#ifdef CONFIG_EXT3_FS_XATTR +struct inode_operations ext4_file_inode_operations = { + .truncate = ext4_truncate, + .setattr = ext4_setattr, +#ifdef CONFIG_EXT4DEV_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, - .listxattr = ext3_listxattr, + .listxattr = ext4_listxattr, .removexattr = generic_removexattr, #endif - .permission = ext3_permission, + .permission = ext4_permission, }; diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index dd1fd3c0fc05..272faa27761d 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/fsync.c + * linux/fs/ext4/fsync.c * * Copyright (C) 1993 Stephen Tweedie (sct@redhat.com) * from @@ -9,7 +9,7 @@ * from * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds * - * ext3fs fsync primitive + * ext4fs fsync primitive * * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 @@ -27,11 +27,11 @@ #include #include #include -#include -#include +#include +#include /* - * akpm: A new design for ext3_sync_file(). + * akpm: A new design for ext4_sync_file(). * * This is only called from sys_fsync(), sys_fdatasync() and sys_msync(). * There cannot be a transaction open by this task. @@ -42,12 +42,12 @@ * inode to disk. */ -int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) +int ext4_sync_file(struct file * file, struct dentry *dentry, int datasync) { struct inode *inode = dentry->d_inode; int ret = 0; - J_ASSERT(ext3_journal_current_handle() == 0); + J_ASSERT(ext4_journal_current_handle() == 0); /* * data=writeback: @@ -61,14 +61,14 @@ int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) * * data=journal: * filemap_fdatawrite won't do anything (the buffers are clean). - * ext3_force_commit will write the file data into the journal and + * ext4_force_commit will write the file data into the journal and * will wait on that. * filemap_fdatawait() will encounter a ton of newly-dirtied pages * (they were dirtied by commit). But that's OK - the blocks are * safe in-journal, which is all fsync() needs to ensure. */ - if (ext3_should_journal_data(inode)) { - ret = ext3_force_commit(inode->i_sb); + if (ext4_should_journal_data(inode)) { + ret = ext4_force_commit(inode->i_sb); goto out; } diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index deeb27b5ba83..d15bb4274428 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/hash.c + * linux/fs/ext4/hash.c * * Copyright (C) 2002 by Theodore Ts'o * @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #define DELTA 0x9E3779B9 @@ -89,7 +89,7 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) * represented, and whether or not the returned hash is 32 bits or 64 * bits. 32 bit hashes will return 0 for the minor hash. */ -int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) +int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) { __u32 hash; __u32 minor_hash = 0; @@ -144,8 +144,8 @@ int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) return -1; } hash = hash & ~1; - if (hash == (EXT3_HTREE_EOF << 1)) - hash = (EXT3_HTREE_EOF-1) << 1; + if (hash == (EXT4_HTREE_EOF << 1)) + hash = (EXT4_HTREE_EOF-1) << 1; hinfo->hash = hash; hinfo->minor_hash = minor_hash; return 0; diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index e45dbd651736..4b92066ca08f 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/ialloc.c + * linux/fs/ext4/ialloc.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -15,8 +15,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -53,16 +53,16 @@ static struct buffer_head * read_inode_bitmap(struct super_block * sb, unsigned long block_group) { - struct ext3_group_desc *desc; + struct ext4_group_desc *desc; struct buffer_head *bh = NULL; - desc = ext3_get_group_desc(sb, block_group, NULL); + desc = ext4_get_group_desc(sb, block_group, NULL); if (!desc) goto error_out; bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap)); if (!bh) - ext3_error(sb, "read_inode_bitmap", + ext4_error(sb, "read_inode_bitmap", "Cannot read inode bitmap - " "block_group = %lu, inode_bitmap = %u", block_group, le32_to_cpu(desc->bg_inode_bitmap)); @@ -86,7 +86,7 @@ error_out: * though), and then we'd have two inodes sharing the * same inode number and space on the harddisk. */ -void ext3_free_inode (handle_t *handle, struct inode * inode) +void ext4_free_inode (handle_t *handle, struct inode * inode) { struct super_block * sb = inode->i_sb; int is_directory; @@ -95,36 +95,36 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) struct buffer_head *bh2; unsigned long block_group; unsigned long bit; - struct ext3_group_desc * gdp; - struct ext3_super_block * es; - struct ext3_sb_info *sbi; + struct ext4_group_desc * gdp; + struct ext4_super_block * es; + struct ext4_sb_info *sbi; int fatal = 0, err; if (atomic_read(&inode->i_count) > 1) { - printk ("ext3_free_inode: inode has count=%d\n", + printk ("ext4_free_inode: inode has count=%d\n", atomic_read(&inode->i_count)); return; } if (inode->i_nlink) { - printk ("ext3_free_inode: inode has nlink=%d\n", + printk ("ext4_free_inode: inode has nlink=%d\n", inode->i_nlink); return; } if (!sb) { - printk("ext3_free_inode: inode on nonexistent device\n"); + printk("ext4_free_inode: inode on nonexistent device\n"); return; } - sbi = EXT3_SB(sb); + sbi = EXT4_SB(sb); ino = inode->i_ino; - ext3_debug ("freeing inode %lu\n", ino); + ext4_debug ("freeing inode %lu\n", ino); /* * Note: we must free any quota before locking the superblock, * as writing the quota to disk may need the lock as well. */ DQUOT_INIT(inode); - ext3_xattr_delete_inode(handle, inode); + ext4_xattr_delete_inode(handle, inode); DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); @@ -133,33 +133,33 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) /* Do this BEFORE marking the inode not in use or returning an error */ clear_inode (inode); - es = EXT3_SB(sb)->s_es; - if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { - ext3_error (sb, "ext3_free_inode", + es = EXT4_SB(sb)->s_es; + if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { + ext4_error (sb, "ext4_free_inode", "reserved or nonexistent inode %lu", ino); goto error_return; } - block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); - bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb); + block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); + bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); bitmap_bh = read_inode_bitmap(sb, block_group); if (!bitmap_bh) goto error_return; BUFFER_TRACE(bitmap_bh, "get_write_access"); - fatal = ext3_journal_get_write_access(handle, bitmap_bh); + fatal = ext4_journal_get_write_access(handle, bitmap_bh); if (fatal) goto error_return; /* Ok, now we can actually update the inode bitmaps.. */ - if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group), + if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group), bit, bitmap_bh->b_data)) - ext3_error (sb, "ext3_free_inode", + ext4_error (sb, "ext4_free_inode", "bit already cleared for inode %lu", ino); else { - gdp = ext3_get_group_desc (sb, block_group, &bh2); + gdp = ext4_get_group_desc (sb, block_group, &bh2); BUFFER_TRACE(bh2, "get_write_access"); - fatal = ext3_journal_get_write_access(handle, bh2); + fatal = ext4_journal_get_write_access(handle, bh2); if (fatal) goto error_return; if (gdp) { @@ -175,18 +175,18 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) percpu_counter_dec(&sbi->s_dirs_counter); } - BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh2); + BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, bh2); if (!fatal) fatal = err; } - BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bitmap_bh); + BUFFER_TRACE(bitmap_bh, "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, bitmap_bh); if (!fatal) fatal = err; sb->s_dirt = 1; error_return: brelse(bitmap_bh); - ext3_std_error(sb, fatal); + ext4_std_error(sb, fatal); } /* @@ -201,17 +201,17 @@ error_return: */ static int find_group_dir(struct super_block *sb, struct inode *parent) { - int ngroups = EXT3_SB(sb)->s_groups_count; + int ngroups = EXT4_SB(sb)->s_groups_count; unsigned int freei, avefreei; - struct ext3_group_desc *desc, *best_desc = NULL; + struct ext4_group_desc *desc, *best_desc = NULL; struct buffer_head *bh; int group, best_group = -1; - freei = percpu_counter_read_positive(&EXT3_SB(sb)->s_freeinodes_counter); + freei = percpu_counter_read_positive(&EXT4_SB(sb)->s_freeinodes_counter); avefreei = freei / ngroups; for (group = 0; group < ngroups; group++) { - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, &bh); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) @@ -256,19 +256,19 @@ static int find_group_dir(struct super_block *sb, struct inode *parent) static int find_group_orlov(struct super_block *sb, struct inode *parent) { - int parent_group = EXT3_I(parent)->i_block_group; - struct ext3_sb_info *sbi = EXT3_SB(sb); - struct ext3_super_block *es = sbi->s_es; + int parent_group = EXT4_I(parent)->i_block_group; + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; int ngroups = sbi->s_groups_count; - int inodes_per_group = EXT3_INODES_PER_GROUP(sb); + int inodes_per_group = EXT4_INODES_PER_GROUP(sb); unsigned int freei, avefreei; - ext3_fsblk_t freeb, avefreeb; - ext3_fsblk_t blocks_per_dir; + ext4_fsblk_t freeb, avefreeb; + ext4_fsblk_t blocks_per_dir; unsigned int ndirs; int max_debt, max_dirs, min_inodes; - ext3_grpblk_t min_blocks; + ext4_grpblk_t min_blocks; int group = -1, i; - struct ext3_group_desc *desc; + struct ext4_group_desc *desc; struct buffer_head *bh; freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); @@ -278,7 +278,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); if ((parent == sb->s_root->d_inode) || - (EXT3_I(parent)->i_flags & EXT3_TOPDIR_FL)) { + (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL)) { int best_ndir = inodes_per_group; int best_group = -1; @@ -286,7 +286,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) parent_group = (unsigned)group % ngroups; for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, &bh); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) @@ -307,9 +307,9 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) max_dirs = ndirs / ngroups + inodes_per_group / 16; min_inodes = avefreei - inodes_per_group / 4; - min_blocks = avefreeb - EXT3_BLOCKS_PER_GROUP(sb) / 4; + min_blocks = avefreeb - EXT4_BLOCKS_PER_GROUP(sb) / 4; - max_debt = EXT3_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, (ext3_fsblk_t)BLOCK_COST); + max_debt = EXT4_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, (ext4_fsblk_t)BLOCK_COST); if (max_debt * INODE_COST > inodes_per_group) max_debt = inodes_per_group / INODE_COST; if (max_debt > 255) @@ -319,7 +319,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, &bh); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) @@ -334,7 +334,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) fallback: for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, &bh); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) @@ -355,9 +355,9 @@ fallback: static int find_group_other(struct super_block *sb, struct inode *parent) { - int parent_group = EXT3_I(parent)->i_block_group; - int ngroups = EXT3_SB(sb)->s_groups_count; - struct ext3_group_desc *desc; + int parent_group = EXT4_I(parent)->i_block_group; + int ngroups = EXT4_SB(sb)->s_groups_count; + struct ext4_group_desc *desc; struct buffer_head *bh; int group, i; @@ -365,7 +365,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) * Try to place the inode in its parent directory */ group = parent_group; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, &bh); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) return group; @@ -389,7 +389,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) group += i; if (group >= ngroups) group -= ngroups; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, &bh); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) return group; @@ -403,7 +403,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) for (i = 0; i < ngroups; i++) { if (++group >= ngroups) group = 0; - desc = ext3_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, &bh); if (desc && le16_to_cpu(desc->bg_free_inodes_count)) return group; } @@ -421,7 +421,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) * For other inodes, search forward from the parent directory's block * group to find a free inode. */ -struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) +struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode) { struct super_block *sb; struct buffer_head *bitmap_bh = NULL; @@ -429,10 +429,10 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) int group; unsigned long ino = 0; struct inode * inode; - struct ext3_group_desc * gdp = NULL; - struct ext3_super_block * es; - struct ext3_inode_info *ei; - struct ext3_sb_info *sbi; + struct ext4_group_desc * gdp = NULL; + struct ext4_super_block * es; + struct ext4_inode_info *ei; + struct ext4_sb_info *sbi; int err = 0; struct inode *ret; int i; @@ -445,9 +445,9 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM); - ei = EXT3_I(inode); + ei = EXT4_I(inode); - sbi = EXT3_SB(sb); + sbi = EXT4_SB(sb); es = sbi->s_es; if (S_ISDIR(mode)) { if (test_opt (sb, OLDALLOC)) @@ -464,7 +464,7 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) for (i = 0; i < sbi->s_groups_count; i++) { err = -EIO; - gdp = ext3_get_group_desc(sb, group, &bh2); + gdp = ext4_get_group_desc(sb, group, &bh2); if (!gdp) goto fail; @@ -476,21 +476,21 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) ino = 0; repeat_in_this_group: - ino = ext3_find_next_zero_bit((unsigned long *) - bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb), ino); - if (ino < EXT3_INODES_PER_GROUP(sb)) { + ino = ext4_find_next_zero_bit((unsigned long *) + bitmap_bh->b_data, EXT4_INODES_PER_GROUP(sb), ino); + if (ino < EXT4_INODES_PER_GROUP(sb)) { BUFFER_TRACE(bitmap_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, bitmap_bh); + err = ext4_journal_get_write_access(handle, bitmap_bh); if (err) goto fail; - if (!ext3_set_bit_atomic(sb_bgl_lock(sbi, group), + if (!ext4_set_bit_atomic(sb_bgl_lock(sbi, group), ino, bitmap_bh->b_data)) { /* we won it */ BUFFER_TRACE(bitmap_bh, - "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, + "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, bitmap_bh); if (err) goto fail; @@ -499,7 +499,7 @@ repeat_in_this_group: /* we lost it */ journal_release_buffer(handle, bitmap_bh); - if (++ino < EXT3_INODES_PER_GROUP(sb)) + if (++ino < EXT4_INODES_PER_GROUP(sb)) goto repeat_in_this_group; } @@ -517,9 +517,9 @@ repeat_in_this_group: goto out; got: - ino += group * EXT3_INODES_PER_GROUP(sb) + 1; - if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { - ext3_error (sb, "ext3_new_inode", + ino += group * EXT4_INODES_PER_GROUP(sb) + 1; + if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { + ext4_error (sb, "ext4_new_inode", "reserved inode or inode > inodes count - " "block_group = %d, inode=%lu", group, ino); err = -EIO; @@ -527,7 +527,7 @@ got: } BUFFER_TRACE(bh2, "get_write_access"); - err = ext3_journal_get_write_access(handle, bh2); + err = ext4_journal_get_write_access(handle, bh2); if (err) goto fail; spin_lock(sb_bgl_lock(sbi, group)); gdp->bg_free_inodes_count = @@ -537,8 +537,8 @@ got: cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1); } spin_unlock(sb_bgl_lock(sbi, group)); - BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh2); + BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, bh2); if (err) goto fail; percpu_counter_dec(&sbi->s_freeinodes_counter); @@ -566,13 +566,13 @@ got: ei->i_dir_start_lookup = 0; ei->i_disksize = 0; - ei->i_flags = EXT3_I(dir)->i_flags & ~EXT3_INDEX_FL; + ei->i_flags = EXT4_I(dir)->i_flags & ~EXT4_INDEX_FL; if (S_ISLNK(mode)) - ei->i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL); + ei->i_flags &= ~(EXT4_IMMUTABLE_FL|EXT4_APPEND_FL); /* dirsync only applies to directories */ if (!S_ISDIR(mode)) - ei->i_flags &= ~EXT3_DIRSYNC_FL; -#ifdef EXT3_FRAGMENTS + ei->i_flags &= ~EXT4_DIRSYNC_FL; +#ifdef EXT4_FRAGMENTS ei->i_faddr = 0; ei->i_frag_no = 0; ei->i_frag_size = 0; @@ -583,7 +583,7 @@ got: ei->i_block_alloc_info = NULL; ei->i_block_group = group; - ext3_set_inode_flags(inode); + ext4_set_inode_flags(inode); if (IS_DIRSYNC(inode)) handle->h_sync = 1; insert_inode_hash(inode); @@ -591,10 +591,10 @@ got: inode->i_generation = sbi->s_next_generation++; spin_unlock(&sbi->s_next_gen_lock); - ei->i_state = EXT3_STATE_NEW; + ei->i_state = EXT4_STATE_NEW; ei->i_extra_isize = - (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ? - sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE : 0; + (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) ? + sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE : 0; ret = inode; if(DQUOT_ALLOC_INODE(inode)) { @@ -602,24 +602,24 @@ got: goto fail_drop; } - err = ext3_init_acl(handle, inode, dir); + err = ext4_init_acl(handle, inode, dir); if (err) goto fail_free_drop; - err = ext3_init_security(handle,inode, dir); + err = ext4_init_security(handle,inode, dir); if (err) goto fail_free_drop; - err = ext3_mark_inode_dirty(handle, inode); + err = ext4_mark_inode_dirty(handle, inode); if (err) { - ext3_std_error(sb, err); + ext4_std_error(sb, err); goto fail_free_drop; } - ext3_debug("allocating inode %lu\n", inode->i_ino); + ext4_debug("allocating inode %lu\n", inode->i_ino); goto really_out; fail: - ext3_std_error(sb, err); + ext4_std_error(sb, err); out: iput(inode); ret = ERR_PTR(err); @@ -640,9 +640,9 @@ fail_drop: } /* Verify that we are loading a valid orphan from disk */ -struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino) +struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) { - unsigned long max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count); + unsigned long max_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count); unsigned long block_group; int bit; struct buffer_head *bitmap_bh = NULL; @@ -650,16 +650,16 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino) /* Error cases - e2fsck has already cleaned up for us */ if (ino > max_ino) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "bad orphan ino %lu! e2fsck was run?", ino); goto out; } - block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); - bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb); + block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); + bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); bitmap_bh = read_inode_bitmap(sb, block_group); if (!bitmap_bh) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "inode bitmap error for orphan %lu", ino); goto out; } @@ -668,14 +668,14 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino) * is a valid orphan (no e2fsck run on fs). Orphans also include * inodes that were being truncated, so we can't check i_nlink==0. */ - if (!ext3_test_bit(bit, bitmap_bh->b_data) || + if (!ext4_test_bit(bit, bitmap_bh->b_data) || !(inode = iget(sb, ino)) || is_bad_inode(inode) || NEXT_ORPHAN(inode) > max_ino) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "bad orphan inode %lu! e2fsck was run?", ino); - printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n", + printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n", bit, (unsigned long long)bitmap_bh->b_blocknr, - ext3_test_bit(bit, bitmap_bh->b_data)); + ext4_test_bit(bit, bitmap_bh->b_data)); printk(KERN_NOTICE "inode=%p\n", inode); if (inode) { printk(KERN_NOTICE "is_bad_inode(inode)=%d\n", @@ -695,22 +695,22 @@ out: return inode; } -unsigned long ext3_count_free_inodes (struct super_block * sb) +unsigned long ext4_count_free_inodes (struct super_block * sb) { unsigned long desc_count; - struct ext3_group_desc *gdp; + struct ext4_group_desc *gdp; int i; -#ifdef EXT3FS_DEBUG - struct ext3_super_block *es; +#ifdef EXT4FS_DEBUG + struct ext4_super_block *es; unsigned long bitmap_count, x; struct buffer_head *bitmap_bh = NULL; - es = EXT3_SB(sb)->s_es; + es = EXT4_SB(sb)->s_es; desc_count = 0; bitmap_count = 0; gdp = NULL; - for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { - gdp = ext3_get_group_desc (sb, i, NULL); + for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) { + gdp = ext4_get_group_desc (sb, i, NULL); if (!gdp) continue; desc_count += le16_to_cpu(gdp->bg_free_inodes_count); @@ -719,19 +719,19 @@ unsigned long ext3_count_free_inodes (struct super_block * sb) if (!bitmap_bh) continue; - x = ext3_count_free(bitmap_bh, EXT3_INODES_PER_GROUP(sb) / 8); + x = ext4_count_free(bitmap_bh, EXT4_INODES_PER_GROUP(sb) / 8); printk("group %d: stored = %d, counted = %lu\n", i, le16_to_cpu(gdp->bg_free_inodes_count), x); bitmap_count += x; } brelse(bitmap_bh); - printk("ext3_count_free_inodes: stored = %u, computed = %lu, %lu\n", + printk("ext4_count_free_inodes: stored = %u, computed = %lu, %lu\n", le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count); return desc_count; #else desc_count = 0; - for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { - gdp = ext3_get_group_desc (sb, i, NULL); + for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) { + gdp = ext4_get_group_desc (sb, i, NULL); if (!gdp) continue; desc_count += le16_to_cpu(gdp->bg_free_inodes_count); @@ -742,13 +742,13 @@ unsigned long ext3_count_free_inodes (struct super_block * sb) } /* Called at mount-time, super-block is locked */ -unsigned long ext3_count_dirs (struct super_block * sb) +unsigned long ext4_count_dirs (struct super_block * sb) { unsigned long count = 0; int i; - for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { - struct ext3_group_desc *gdp = ext3_get_group_desc (sb, i, NULL); + for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) { + struct ext4_group_desc *gdp = ext4_get_group_desc (sb, i, NULL); if (!gdp) continue; count += le16_to_cpu(gdp->bg_used_dirs_count); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 03ba5bcab186..7275d60dcc59 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/inode.c + * linux/fs/ext4/inode.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -19,13 +19,13 @@ * 64-bit file support on 64-bit platforms by Jakub Jelinek * (jj@sunsite.ms.mff.cuni.cz) * - * Assorted race fixes, rewrite of ext3_get_block() by Al Viro, 2000 + * Assorted race fixes, rewrite of ext4_get_block() by Al Viro, 2000 */ #include #include #include -#include +#include #include #include #include @@ -40,21 +40,21 @@ #include "xattr.h" #include "acl.h" -static int ext3_writepage_trans_blocks(struct inode *inode); +static int ext4_writepage_trans_blocks(struct inode *inode); /* * Test whether an inode is a fast symlink. */ -static int ext3_inode_is_fast_symlink(struct inode *inode) +static int ext4_inode_is_fast_symlink(struct inode *inode) { - int ea_blocks = EXT3_I(inode)->i_file_acl ? + int ea_blocks = EXT4_I(inode)->i_file_acl ? (inode->i_sb->s_blocksize >> 9) : 0; return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0); } /* - * The ext3 forget function must perform a revoke if we are freeing data + * The ext4 forget function must perform a revoke if we are freeing data * which has been journaled. Metadata (eg. indirect blocks) must be * revoked in all cases. * @@ -62,8 +62,8 @@ static int ext3_inode_is_fast_symlink(struct inode *inode) * but there may still be a record of it in the journal, and that record * still needs to be revoked. */ -int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode, - struct buffer_head *bh, ext3_fsblk_t blocknr) +int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, + struct buffer_head *bh, ext4_fsblk_t blocknr) { int err; @@ -81,11 +81,11 @@ int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode, * support it. Otherwise, only skip the revoke on un-journaled * data blocks. */ - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA || - (!is_metadata && !ext3_should_journal_data(inode))) { + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || + (!is_metadata && !ext4_should_journal_data(inode))) { if (bh) { BUFFER_TRACE(bh, "call journal_forget"); - return ext3_journal_forget(handle, bh); + return ext4_journal_forget(handle, bh); } return 0; } @@ -93,10 +93,10 @@ int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode, /* * data!=journal && (is_metadata || should_journal_data(inode)) */ - BUFFER_TRACE(bh, "call ext3_journal_revoke"); - err = ext3_journal_revoke(handle, blocknr, bh); + BUFFER_TRACE(bh, "call ext4_journal_revoke"); + err = ext4_journal_revoke(handle, blocknr, bh); if (err) - ext3_abort(inode->i_sb, __FUNCTION__, + ext4_abort(inode->i_sb, __FUNCTION__, "error %d when attempting revoke", err); BUFFER_TRACE(bh, "exit"); return err; @@ -115,7 +115,7 @@ static unsigned long blocks_for_truncate(struct inode *inode) /* Give ourselves just enough room to cope with inodes in which * i_blocks is corrupt: we've seen disk corruptions in the past * which resulted in random data in an inode which looked enough - * like a regular file for ext3 to try to delete it. Things + * like a regular file for ext4 to try to delete it. Things * will go a bit crazy if that happens, but at least we should * try not to panic the whole kernel. */ if (needed < 2) @@ -123,10 +123,10 @@ static unsigned long blocks_for_truncate(struct inode *inode) /* But we need to bound the transaction so we don't overflow the * journal. */ - if (needed > EXT3_MAX_TRANS_DATA) - needed = EXT3_MAX_TRANS_DATA; + if (needed > EXT4_MAX_TRANS_DATA) + needed = EXT4_MAX_TRANS_DATA; - return EXT3_DATA_TRANS_BLOCKS(inode->i_sb) + needed; + return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed; } /* @@ -143,11 +143,11 @@ static handle_t *start_transaction(struct inode *inode) { handle_t *result; - result = ext3_journal_start(inode, blocks_for_truncate(inode)); + result = ext4_journal_start(inode, blocks_for_truncate(inode)); if (!IS_ERR(result)) return result; - ext3_std_error(inode->i_sb, PTR_ERR(result)); + ext4_std_error(inode->i_sb, PTR_ERR(result)); return result; } @@ -159,9 +159,9 @@ static handle_t *start_transaction(struct inode *inode) */ static int try_to_extend_transaction(handle_t *handle, struct inode *inode) { - if (handle->h_buffer_credits > EXT3_RESERVE_TRANS_BLOCKS) + if (handle->h_buffer_credits > EXT4_RESERVE_TRANS_BLOCKS) return 0; - if (!ext3_journal_extend(handle, blocks_for_truncate(inode))) + if (!ext4_journal_extend(handle, blocks_for_truncate(inode))) return 0; return 1; } @@ -171,16 +171,16 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode) * so before we call here everything must be consistently dirtied against * this transaction. */ -static int ext3_journal_test_restart(handle_t *handle, struct inode *inode) +static int ext4_journal_test_restart(handle_t *handle, struct inode *inode) { jbd_debug(2, "restarting handle %p\n", handle); - return ext3_journal_restart(handle, blocks_for_truncate(inode)); + return ext4_journal_restart(handle, blocks_for_truncate(inode)); } /* * Called at the last iput() if i_nlink is zero. */ -void ext3_delete_inode (struct inode * inode) +void ext4_delete_inode (struct inode * inode) { handle_t *handle; @@ -196,7 +196,7 @@ void ext3_delete_inode (struct inode * inode) * make sure that the in-core orphan linked list is properly * cleaned up. */ - ext3_orphan_del(NULL, inode); + ext4_orphan_del(NULL, inode); goto no_delete; } @@ -204,17 +204,17 @@ void ext3_delete_inode (struct inode * inode) handle->h_sync = 1; inode->i_size = 0; if (inode->i_blocks) - ext3_truncate(inode); + ext4_truncate(inode); /* - * Kill off the orphan record which ext3_truncate created. + * Kill off the orphan record which ext4_truncate created. * AKPM: I think this can be inside the above `if'. - * Note that ext3_orphan_del() has to be able to cope with the + * Note that ext4_orphan_del() has to be able to cope with the * deletion of a non-existent orphan - this is because we don't - * know if ext3_truncate() actually created an orphan record. + * know if ext4_truncate() actually created an orphan record. * (Well, we could do this if we need to, but heck - it works) */ - ext3_orphan_del(handle, inode); - EXT3_I(inode)->i_dtime = get_seconds(); + ext4_orphan_del(handle, inode); + EXT4_I(inode)->i_dtime = get_seconds(); /* * One subtle ordering requirement: if anything has gone wrong @@ -223,12 +223,12 @@ void ext3_delete_inode (struct inode * inode) * having errors), but we can't free the inode if the mark_dirty * fails. */ - if (ext3_mark_inode_dirty(handle, inode)) + if (ext4_mark_inode_dirty(handle, inode)) /* If that failed, just do the required in-core inode clear. */ clear_inode(inode); else - ext3_free_inode(handle, inode); - ext3_journal_stop(handle); + ext4_free_inode(handle, inode); + ext4_journal_stop(handle); return; no_delete: clear_inode(inode); /* We must guarantee clearing of inode... */ @@ -254,14 +254,14 @@ static int verify_chain(Indirect *from, Indirect *to) } /** - * ext3_block_to_path - parse the block number into array of offsets + * ext4_block_to_path - parse the block number into array of offsets * @inode: inode in question (we are only interested in its superblock) * @i_block: block number to be parsed * @offsets: array to store the offsets in * @boundary: set this non-zero if the referred-to block is likely to be * followed (on disk) by an indirect block. * - * To store the locations of file's data ext3 uses a data structure common + * To store the locations of file's data ext4 uses a data structure common * for UNIX filesystems - tree of pointers anchored in the inode, with * data blocks at leaves and indirect blocks in intermediate nodes. * This function translates the block number into path in that tree - @@ -284,39 +284,39 @@ static int verify_chain(Indirect *from, Indirect *to) * get there at all. */ -static int ext3_block_to_path(struct inode *inode, +static int ext4_block_to_path(struct inode *inode, long i_block, int offsets[4], int *boundary) { - int ptrs = EXT3_ADDR_PER_BLOCK(inode->i_sb); - int ptrs_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb); - const long direct_blocks = EXT3_NDIR_BLOCKS, + int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb); + int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb); + const long direct_blocks = EXT4_NDIR_BLOCKS, indirect_blocks = ptrs, double_blocks = (1 << (ptrs_bits * 2)); int n = 0; int final = 0; if (i_block < 0) { - ext3_warning (inode->i_sb, "ext3_block_to_path", "block < 0"); + ext4_warning (inode->i_sb, "ext4_block_to_path", "block < 0"); } else if (i_block < direct_blocks) { offsets[n++] = i_block; final = direct_blocks; } else if ( (i_block -= direct_blocks) < indirect_blocks) { - offsets[n++] = EXT3_IND_BLOCK; + offsets[n++] = EXT4_IND_BLOCK; offsets[n++] = i_block; final = ptrs; } else if ((i_block -= indirect_blocks) < double_blocks) { - offsets[n++] = EXT3_DIND_BLOCK; + offsets[n++] = EXT4_DIND_BLOCK; offsets[n++] = i_block >> ptrs_bits; offsets[n++] = i_block & (ptrs - 1); final = ptrs; } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { - offsets[n++] = EXT3_TIND_BLOCK; + offsets[n++] = EXT4_TIND_BLOCK; offsets[n++] = i_block >> (ptrs_bits * 2); offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); offsets[n++] = i_block & (ptrs - 1); final = ptrs; } else { - ext3_warning(inode->i_sb, "ext3_block_to_path", "block > big"); + ext4_warning(inode->i_sb, "ext4_block_to_path", "block > big"); } if (boundary) *boundary = final - 1 - (i_block & (ptrs - 1)); @@ -324,7 +324,7 @@ static int ext3_block_to_path(struct inode *inode, } /** - * ext3_get_branch - read the chain of indirect blocks leading to data + * ext4_get_branch - read the chain of indirect blocks leading to data * @inode: inode in question * @depth: depth of the chain (1 - direct pointer, etc.) * @offsets: offsets of pointers in inode/indirect blocks @@ -352,7 +352,7 @@ static int ext3_block_to_path(struct inode *inode, * or when it reads all @depth-1 indirect blocks successfully and finds * the whole chain, all way to the data (returns %NULL, *err == 0). */ -static Indirect *ext3_get_branch(struct inode *inode, int depth, int *offsets, +static Indirect *ext4_get_branch(struct inode *inode, int depth, int *offsets, Indirect chain[4], int *err) { struct super_block *sb = inode->i_sb; @@ -361,7 +361,7 @@ static Indirect *ext3_get_branch(struct inode *inode, int depth, int *offsets, *err = 0; /* i_data is not going away, no lock needed */ - add_chain (chain, NULL, EXT3_I(inode)->i_data + *offsets); + add_chain (chain, NULL, EXT4_I(inode)->i_data + *offsets); if (!p->key) goto no_block; while (--depth) { @@ -389,7 +389,7 @@ no_block: } /** - * ext3_find_near - find a place for allocation with sufficient locality + * ext4_find_near - find a place for allocation with sufficient locality * @inode: owner * @ind: descriptor of indirect block. * @@ -408,13 +408,13 @@ no_block: * * Caller must make sure that @ind is valid and will stay that way. */ -static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind) +static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind) { - struct ext3_inode_info *ei = EXT3_I(inode); + struct ext4_inode_info *ei = EXT4_I(inode); __le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data; __le32 *p; - ext3_fsblk_t bg_start; - ext3_grpblk_t colour; + ext4_fsblk_t bg_start; + ext4_grpblk_t colour; /* Try to find previous block */ for (p = ind->p - 1; p >= start; p--) { @@ -430,14 +430,14 @@ static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind) * It is going to be referred to from the inode itself? OK, just put it * into the same cylinder group then. */ - bg_start = ext3_group_first_block_no(inode->i_sb, ei->i_block_group); + bg_start = ext4_group_first_block_no(inode->i_sb, ei->i_block_group); colour = (current->pid % 16) * - (EXT3_BLOCKS_PER_GROUP(inode->i_sb) / 16); + (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16); return bg_start + colour; } /** - * ext3_find_goal - find a prefered place for allocation. + * ext4_find_goal - find a prefered place for allocation. * @inode: owner * @block: block we want * @chain: chain of indirect blocks @@ -448,12 +448,12 @@ static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind) * stores it in *@goal and returns zero. */ -static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block, +static ext4_fsblk_t ext4_find_goal(struct inode *inode, long block, Indirect chain[4], Indirect *partial) { - struct ext3_block_alloc_info *block_i; + struct ext4_block_alloc_info *block_i; - block_i = EXT3_I(inode)->i_block_alloc_info; + block_i = EXT4_I(inode)->i_block_alloc_info; /* * try the heuristic for sequential allocation, @@ -464,11 +464,11 @@ static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block, return block_i->last_alloc_physical_block + 1; } - return ext3_find_near(inode, partial); + return ext4_find_near(inode, partial); } /** - * ext3_blks_to_allocate: Look up the block map and count the number + * ext4_blks_to_allocate: Look up the block map and count the number * of direct blocks need to be allocated for the given branch. * * @branch: chain of indirect blocks @@ -479,7 +479,7 @@ static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block, * return the total number of blocks to be allocate, including the * direct and indirect blocks. */ -static int ext3_blks_to_allocate(Indirect *branch, int k, unsigned long blks, +static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned long blks, int blocks_to_boundary) { unsigned long count = 0; @@ -506,7 +506,7 @@ static int ext3_blks_to_allocate(Indirect *branch, int k, unsigned long blks, } /** - * ext3_alloc_blocks: multiple allocate blocks needed for a branch + * ext4_alloc_blocks: multiple allocate blocks needed for a branch * @indirect_blks: the number of blocks need to allocate for indirect * blocks * @@ -515,14 +515,14 @@ static int ext3_blks_to_allocate(Indirect *branch, int k, unsigned long blks, * @blks: on return it will store the total number of allocated * direct blocks */ -static int ext3_alloc_blocks(handle_t *handle, struct inode *inode, - ext3_fsblk_t goal, int indirect_blks, int blks, - ext3_fsblk_t new_blocks[4], int *err) +static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, + ext4_fsblk_t goal, int indirect_blks, int blks, + ext4_fsblk_t new_blocks[4], int *err) { int target, i; unsigned long count = 0; int index = 0; - ext3_fsblk_t current_block = 0; + ext4_fsblk_t current_block = 0; int ret = 0; /* @@ -538,7 +538,7 @@ static int ext3_alloc_blocks(handle_t *handle, struct inode *inode, while (1) { count = target; /* allocating blocks for indirect blocks and direct blocks */ - current_block = ext3_new_blocks(handle,inode,goal,&count,err); + current_block = ext4_new_blocks(handle,inode,goal,&count,err); if (*err) goto failed_out; @@ -562,12 +562,12 @@ static int ext3_alloc_blocks(handle_t *handle, struct inode *inode, return ret; failed_out: for (i = 0; i key). Upon the exit we have the same - * picture as after the successful ext3_get_block(), except that in one + * picture as after the successful ext4_get_block(), except that in one * place chain is disconnected - *branch->p is still zero (we did not * set the last link), but branch->key contains the number that should * be placed into *branch->p to fill that gap. * * If allocation fails we free all blocks we've allocated (and forget * their buffer_heads) and return the error value the from failed - * ext3_alloc_block() (normally -ENOSPC). Otherwise we set the chain + * ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain * as described above and return 0. */ -static int ext3_alloc_branch(handle_t *handle, struct inode *inode, - int indirect_blks, int *blks, ext3_fsblk_t goal, +static int ext4_alloc_branch(handle_t *handle, struct inode *inode, + int indirect_blks, int *blks, ext4_fsblk_t goal, int *offsets, Indirect *branch) { int blocksize = inode->i_sb->s_blocksize; @@ -600,10 +600,10 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, int err = 0; struct buffer_head *bh; int num; - ext3_fsblk_t new_blocks[4]; - ext3_fsblk_t current_block; + ext4_fsblk_t new_blocks[4]; + ext4_fsblk_t current_block; - num = ext3_alloc_blocks(handle, inode, goal, indirect_blks, + num = ext4_alloc_blocks(handle, inode, goal, indirect_blks, *blks, new_blocks, &err); if (err) return err; @@ -622,7 +622,7 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, branch[n].bh = bh; lock_buffer(bh); BUFFER_TRACE(bh, "call get_create_access"); - err = ext3_journal_get_create_access(handle, bh); + err = ext4_journal_get_create_access(handle, bh); if (err) { unlock_buffer(bh); brelse(bh); @@ -647,8 +647,8 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, set_buffer_uptodate(bh); unlock_buffer(bh); - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh); + BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, bh); if (err) goto failed; } @@ -658,22 +658,22 @@ failed: /* Allocation failed, free what we already allocated */ for (i = 1; i <= n ; i++) { BUFFER_TRACE(branch[i].bh, "call journal_forget"); - ext3_journal_forget(handle, branch[i].bh); + ext4_journal_forget(handle, branch[i].bh); } for (i = 0; i i_blocks, etc.). In case of success we end up with the full * chain to new block and return 0. */ -static int ext3_splice_branch(handle_t *handle, struct inode *inode, +static int ext4_splice_branch(handle_t *handle, struct inode *inode, long block, Indirect *where, int num, int blks) { int i; int err = 0; - struct ext3_block_alloc_info *block_i; - ext3_fsblk_t current_block; + struct ext4_block_alloc_info *block_i; + ext4_fsblk_t current_block; - block_i = EXT3_I(inode)->i_block_alloc_info; + block_i = EXT4_I(inode)->i_block_alloc_info; /* * If we're splicing into a [td]indirect block (as opposed to the * inode) then we need to get write access to the [td]indirect block @@ -698,7 +698,7 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, */ if (where->bh) { BUFFER_TRACE(where->bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, where->bh); + err = ext4_journal_get_write_access(handle, where->bh); if (err) goto err_out; } @@ -730,7 +730,7 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, /* We are done with atomic stuff, now do the rest of housekeeping */ inode->i_ctime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); /* had we spliced it onto indirect block? */ if (where->bh) { @@ -740,11 +740,11 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, * onto an indirect block at the very end of the file (the * file is growing) then we *will* alter the inode to reflect * the new i_size. But that is not done here - it is done in - * generic_commit_write->__mark_inode_dirty->ext3_dirty_inode. + * generic_commit_write->__mark_inode_dirty->ext4_dirty_inode. */ jbd_debug(5, "splicing indirect only\n"); - BUFFER_TRACE(where->bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, where->bh); + BUFFER_TRACE(where->bh, "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, where->bh); if (err) goto err_out; } else { @@ -759,10 +759,10 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, err_out: for (i = 1; i <= num; i++) { BUFFER_TRACE(where[i].bh, "call journal_forget"); - ext3_journal_forget(handle, where[i].bh); - ext3_free_blocks(handle,inode,le32_to_cpu(where[i-1].key),1); + ext4_journal_forget(handle, where[i].bh); + ext4_free_blocks(handle,inode,le32_to_cpu(where[i-1].key),1); } - ext3_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks); + ext4_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks); return err; } @@ -786,7 +786,7 @@ err_out: * return = 0, if plain lookup failed. * return < 0, error case. */ -int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, +int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result, int create, int extend_disksize) @@ -795,22 +795,22 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, int offsets[4]; Indirect chain[4]; Indirect *partial; - ext3_fsblk_t goal; + ext4_fsblk_t goal; int indirect_blks; int blocks_to_boundary = 0; int depth; - struct ext3_inode_info *ei = EXT3_I(inode); + struct ext4_inode_info *ei = EXT4_I(inode); int count = 0; - ext3_fsblk_t first_block = 0; + ext4_fsblk_t first_block = 0; J_ASSERT(handle != NULL || create == 0); - depth = ext3_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + depth = ext4_block_to_path(inode,iblock,offsets,&blocks_to_boundary); if (depth == 0) goto out; - partial = ext3_get_branch(inode, depth, offsets, chain, &err); + partial = ext4_get_branch(inode, depth, offsets, chain, &err); /* Simplest case - block found, no allocation needed */ if (!partial) { @@ -819,7 +819,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, count++; /*map more blocks*/ while (count < maxblocks && count <= blocks_to_boundary) { - ext3_fsblk_t blk; + ext4_fsblk_t blk; if (!verify_chain(chain, partial)) { /* @@ -852,7 +852,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, /* * If the indirect block is missing while we are reading - * the chain(ext3_get_branch() returns -EAGAIN err), or + * the chain(ext4_get_branch() returns -EAGAIN err), or * if the chain has been changed after we grab the semaphore, * (either because another process truncated this branch, or * another get_block allocated this branch) re-grab the chain to see if @@ -867,7 +867,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, brelse(partial->bh); partial--; } - partial = ext3_get_branch(inode, depth, offsets, chain, &err); + partial = ext4_get_branch(inode, depth, offsets, chain, &err); if (!partial) { count++; mutex_unlock(&ei->truncate_mutex); @@ -883,9 +883,9 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, * allocation info here if necessary */ if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) - ext3_init_block_alloc_info(inode); + ext4_init_block_alloc_info(inode); - goal = ext3_find_goal(inode, iblock, chain, partial); + goal = ext4_find_goal(inode, iblock, chain, partial); /* the number of blocks need to allocate for [d,t]indirect blocks */ indirect_blks = (chain + depth) - partial - 1; @@ -894,28 +894,28 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, * Next look up the indirect map to count the totoal number of * direct blocks to allocate for this branch. */ - count = ext3_blks_to_allocate(partial, indirect_blks, + count = ext4_blks_to_allocate(partial, indirect_blks, maxblocks, blocks_to_boundary); /* - * Block out ext3_truncate while we alter the tree + * Block out ext4_truncate while we alter the tree */ - err = ext3_alloc_branch(handle, inode, indirect_blks, &count, goal, + err = ext4_alloc_branch(handle, inode, indirect_blks, &count, goal, offsets + (partial - chain), partial); /* - * The ext3_splice_branch call will free and forget any buffers + * The ext4_splice_branch call will free and forget any buffers * on the new chain if there is a failure, but that risks using * up transaction credits, especially for bitmaps where the * credits cannot be returned. Can we handle this somehow? We * may need to return -EAGAIN upwards in the worst case. --sct */ if (!err) - err = ext3_splice_branch(handle, inode, iblock, + err = ext4_splice_branch(handle, inode, iblock, partial, indirect_blks, count); /* * i_disksize growing is protected by truncate_mutex. Don't forget to * protect it if you're about to implement concurrent - * ext3_get_block() -bzzz + * ext4_get_block() -bzzz */ if (!err && extend_disksize && inode->i_size > ei->i_disksize) ei->i_disksize = inode->i_size; @@ -942,9 +942,9 @@ out: return err; } -#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32) +#define DIO_CREDITS (EXT4_RESERVE_TRANS_BLOCKS + 32) -static int ext3_get_block(struct inode *inode, sector_t iblock, +static int ext4_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { handle_t *handle = journal_current_handle(); @@ -962,29 +962,29 @@ static int ext3_get_block(struct inode *inode, sector_t iblock, * Huge direct-io writes can hold off commits for long * periods of time. Let this commit run. */ - ext3_journal_stop(handle); - handle = ext3_journal_start(inode, DIO_CREDITS); + ext4_journal_stop(handle); + handle = ext4_journal_start(inode, DIO_CREDITS); if (IS_ERR(handle)) ret = PTR_ERR(handle); goto get_block; } - if (handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) { + if (handle->h_buffer_credits <= EXT4_RESERVE_TRANS_BLOCKS) { /* * Getting low on buffer credits... */ - ret = ext3_journal_extend(handle, DIO_CREDITS); + ret = ext4_journal_extend(handle, DIO_CREDITS); if (ret > 0) { /* * Couldn't extend the transaction. Start a new one. */ - ret = ext3_journal_restart(handle, DIO_CREDITS); + ret = ext4_journal_restart(handle, DIO_CREDITS); } } get_block: if (ret == 0) { - ret = ext3_get_blocks_handle(handle, inode, iblock, + ret = ext4_get_blocks_handle(handle, inode, iblock, max_blocks, bh_result, create, 0); if (ret > 0) { bh_result->b_size = (ret << inode->i_blkbits); @@ -997,7 +997,7 @@ get_block: /* * `handle' can be NULL if create is zero */ -struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode, +struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, long block, int create, int *errp) { struct buffer_head dummy; @@ -1008,10 +1008,10 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode, dummy.b_state = 0; dummy.b_blocknr = -1000; buffer_trace_init(&dummy.b_history); - err = ext3_get_blocks_handle(handle, inode, block, 1, + err = ext4_get_blocks_handle(handle, inode, block, 1, &dummy, create, 1); /* - * ext3_get_blocks_handle() returns number of blocks + * ext4_get_blocks_handle() returns number of blocks * mapped. 0 in case of a HOLE. */ if (err > 0) { @@ -1035,19 +1035,19 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode, * Now that we do not always journal data, we should * keep in mind whether this should always journal the * new buffer as metadata. For now, regular file - * writes use ext3_get_block instead, so it's not a + * writes use ext4_get_block instead, so it's not a * problem. */ lock_buffer(bh); BUFFER_TRACE(bh, "call get_create_access"); - fatal = ext3_journal_get_create_access(handle, bh); + fatal = ext4_journal_get_create_access(handle, bh); if (!fatal && !buffer_uptodate(bh)) { memset(bh->b_data,0,inode->i_sb->s_blocksize); set_buffer_uptodate(bh); } unlock_buffer(bh); - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh); + BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, bh); if (!fatal) fatal = err; } else { @@ -1064,12 +1064,12 @@ err: return NULL; } -struct buffer_head *ext3_bread(handle_t *handle, struct inode *inode, +struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode, int block, int create, int *err) { struct buffer_head * bh; - bh = ext3_getblk(handle, inode, block, create, err); + bh = ext4_getblk(handle, inode, block, create, err); if (!bh) return bh; if (buffer_uptodate(bh)) @@ -1118,17 +1118,17 @@ static int walk_page_buffers( handle_t *handle, /* * To preserve ordering, it is essential that the hole instantiation and * the data write be encapsulated in a single transaction. We cannot - * close off a transaction and start a new one between the ext3_get_block() + * close off a transaction and start a new one between the ext4_get_block() * and the commit_write(). So doing the journal_start at the start of * prepare_write() is the right place. * - * Also, this function can nest inside ext3_writepage() -> - * block_write_full_page(). In that case, we *know* that ext3_writepage() + * Also, this function can nest inside ext4_writepage() -> + * block_write_full_page(). In that case, we *know* that ext4_writepage() * has generated enough buffer credits to do the whole page. So we won't * block on the journal in that case, which is good, because the caller may * be PF_MEMALLOC. * - * By accident, ext3 can be reentered when a transaction is open via + * By accident, ext4 can be reentered when a transaction is open via * quota file writes. If we were to commit the transaction while thus * reentered, there can be a deadlock - we would be holding a quota * lock, and the commit would never complete if another thread had a @@ -1145,48 +1145,48 @@ static int do_journal_get_write_access(handle_t *handle, { if (!buffer_mapped(bh) || buffer_freed(bh)) return 0; - return ext3_journal_get_write_access(handle, bh); + return ext4_journal_get_write_access(handle, bh); } -static int ext3_prepare_write(struct file *file, struct page *page, +static int ext4_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { struct inode *inode = page->mapping->host; - int ret, needed_blocks = ext3_writepage_trans_blocks(inode); + int ret, needed_blocks = ext4_writepage_trans_blocks(inode); handle_t *handle; int retries = 0; retry: - handle = ext3_journal_start(inode, needed_blocks); + handle = ext4_journal_start(inode, needed_blocks); if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto out; } - if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) - ret = nobh_prepare_write(page, from, to, ext3_get_block); + if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) + ret = nobh_prepare_write(page, from, to, ext4_get_block); else - ret = block_prepare_write(page, from, to, ext3_get_block); + ret = block_prepare_write(page, from, to, ext4_get_block); if (ret) goto prepare_write_failed; - if (ext3_should_journal_data(inode)) { + if (ext4_should_journal_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), from, to, NULL, do_journal_get_write_access); } prepare_write_failed: if (ret) - ext3_journal_stop(handle); - if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) + ext4_journal_stop(handle); + if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; out: return ret; } -int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) +int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh) { int err = journal_dirty_data(handle, bh); if (err) - ext3_journal_abort_handle(__FUNCTION__, __FUNCTION__, + ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__, bh, handle,err); return err; } @@ -1197,25 +1197,25 @@ static int commit_write_fn(handle_t *handle, struct buffer_head *bh) if (!buffer_mapped(bh) || buffer_freed(bh)) return 0; set_buffer_uptodate(bh); - return ext3_journal_dirty_metadata(handle, bh); + return ext4_journal_dirty_metadata(handle, bh); } /* * We need to pick up the new inode size which generic_commit_write gave us * `file' can be NULL - eg, when called from page_symlink(). * - * ext3 never places buffers on inode->i_mapping->private_list. metadata + * ext4 never places buffers on inode->i_mapping->private_list. metadata * buffers are managed internally. */ -static int ext3_ordered_commit_write(struct file *file, struct page *page, +static int ext4_ordered_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { - handle_t *handle = ext3_journal_current_handle(); + handle_t *handle = ext4_journal_current_handle(); struct inode *inode = page->mapping->host; int ret = 0, ret2; ret = walk_page_buffers(handle, page_buffers(page), - from, to, NULL, ext3_journal_dirty_data); + from, to, NULL, ext4_journal_dirty_data); if (ret == 0) { /* @@ -1226,43 +1226,43 @@ static int ext3_ordered_commit_write(struct file *file, struct page *page, loff_t new_i_size; new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - if (new_i_size > EXT3_I(inode)->i_disksize) - EXT3_I(inode)->i_disksize = new_i_size; + if (new_i_size > EXT4_I(inode)->i_disksize) + EXT4_I(inode)->i_disksize = new_i_size; ret = generic_commit_write(file, page, from, to); } - ret2 = ext3_journal_stop(handle); + ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; return ret; } -static int ext3_writeback_commit_write(struct file *file, struct page *page, +static int ext4_writeback_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { - handle_t *handle = ext3_journal_current_handle(); + handle_t *handle = ext4_journal_current_handle(); struct inode *inode = page->mapping->host; int ret = 0, ret2; loff_t new_i_size; new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - if (new_i_size > EXT3_I(inode)->i_disksize) - EXT3_I(inode)->i_disksize = new_i_size; + if (new_i_size > EXT4_I(inode)->i_disksize) + EXT4_I(inode)->i_disksize = new_i_size; - if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) + if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) ret = nobh_commit_write(file, page, from, to); else ret = generic_commit_write(file, page, from, to); - ret2 = ext3_journal_stop(handle); + ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; return ret; } -static int ext3_journalled_commit_write(struct file *file, +static int ext4_journalled_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { - handle_t *handle = ext3_journal_current_handle(); + handle_t *handle = ext4_journal_current_handle(); struct inode *inode = page->mapping->host; int ret = 0, ret2; int partial = 0; @@ -1279,14 +1279,14 @@ static int ext3_journalled_commit_write(struct file *file, SetPageUptodate(page); if (pos > inode->i_size) i_size_write(inode, pos); - EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; - if (inode->i_size > EXT3_I(inode)->i_disksize) { - EXT3_I(inode)->i_disksize = inode->i_size; - ret2 = ext3_mark_inode_dirty(handle, inode); + EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; + if (inode->i_size > EXT4_I(inode)->i_disksize) { + EXT4_I(inode)->i_disksize = inode->i_size; + ret2 = ext4_mark_inode_dirty(handle, inode); if (!ret) ret = ret2; } - ret2 = ext3_journal_stop(handle); + ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; return ret; @@ -1297,7 +1297,7 @@ static int ext3_journalled_commit_write(struct file *file, * the swapper to find the on-disk block of a specific piece of data. * * Naturally, this is dangerous if the block concerned is still in the - * journal. If somebody makes a swapfile on an ext3 data-journaling + * journal. If somebody makes a swapfile on an ext4 data-journaling * filesystem and enables swap, then they may get a nasty shock when the * data getting swapped to that swapfile suddenly gets overwritten by * the original zero's written out previously to the journal and @@ -1306,13 +1306,13 @@ static int ext3_journalled_commit_write(struct file *file, * So, if we see any bmap calls here on a modified, data-journaled file, * take extra steps to flush any blocks which might be in the cache. */ -static sector_t ext3_bmap(struct address_space *mapping, sector_t block) +static sector_t ext4_bmap(struct address_space *mapping, sector_t block) { struct inode *inode = mapping->host; journal_t *journal; int err; - if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) { + if (EXT4_I(inode)->i_state & EXT4_STATE_JDATA) { /* * This is a REALLY heavyweight approach, but the use of * bmap on dirty files is expected to be extremely rare: @@ -1324,15 +1324,15 @@ static sector_t ext3_bmap(struct address_space *mapping, sector_t block) * in trouble if mortal users could trigger this path at * will.) * - * NB. EXT3_STATE_JDATA is not set on files other than + * NB. EXT4_STATE_JDATA is not set on files other than * regular files. If somebody wants to bmap a directory * or symlink and gets confused because the buffer * hasn't yet been flushed to disk, they deserve * everything they get. */ - EXT3_I(inode)->i_state &= ~EXT3_STATE_JDATA; - journal = EXT3_JOURNAL(inode); + EXT4_I(inode)->i_state &= ~EXT4_STATE_JDATA; + journal = EXT4_JOURNAL(inode); journal_lock_updates(journal); err = journal_flush(journal); journal_unlock_updates(journal); @@ -1341,7 +1341,7 @@ static sector_t ext3_bmap(struct address_space *mapping, sector_t block) return 0; } - return generic_block_bmap(mapping,block,ext3_get_block); + return generic_block_bmap(mapping,block,ext4_get_block); } static int bget_one(handle_t *handle, struct buffer_head *bh) @@ -1359,14 +1359,14 @@ static int bput_one(handle_t *handle, struct buffer_head *bh) static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) { if (buffer_mapped(bh)) - return ext3_journal_dirty_data(handle, bh); + return ext4_journal_dirty_data(handle, bh); return 0; } /* * Note that we always start a transaction even if we're not journalling * data. This is to preserve ordering: any hole instantiation within - * __block_write_full_page -> ext3_get_block() should be journalled + * __block_write_full_page -> ext4_get_block() should be journalled * along with the data so we don't crash and then get metadata which * refers to old data. * @@ -1374,14 +1374,14 @@ static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) * * Problem: * - * ext3_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() -> - * ext3_writepage() + * ext4_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() -> + * ext4_writepage() * * Similar for: * - * ext3_file_write() -> generic_file_write() -> __alloc_pages() -> ... + * ext4_file_write() -> generic_file_write() -> __alloc_pages() -> ... * - * Same applies to ext3_get_block(). We will deadlock on various things like + * Same applies to ext4_get_block(). We will deadlock on various things like * lock_journal and i_truncate_mutex. * * Setting PF_MEMALLOC here doesn't work - too many internal memory @@ -1415,7 +1415,7 @@ static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) * AKPM2: if all the page's buffers are mapped to disk and !data=journal, * we don't need to open a transaction here. */ -static int ext3_ordered_writepage(struct page *page, +static int ext4_ordered_writepage(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; @@ -1430,10 +1430,10 @@ static int ext3_ordered_writepage(struct page *page, * We give up here if we're reentered, because it might be for a * different filesystem. */ - if (ext3_journal_current_handle()) + if (ext4_journal_current_handle()) goto out_fail; - handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode)); if (IS_ERR(handle)) { ret = PTR_ERR(handle); @@ -1448,7 +1448,7 @@ static int ext3_ordered_writepage(struct page *page, walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, NULL, bget_one); - ret = block_write_full_page(page, ext3_get_block, wbc); + ret = block_write_full_page(page, ext4_get_block, wbc); /* * The page can become unlocked at any point now, and @@ -1470,7 +1470,7 @@ static int ext3_ordered_writepage(struct page *page, } walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, NULL, bput_one); - err = ext3_journal_stop(handle); + err = ext4_journal_stop(handle); if (!ret) ret = err; return ret; @@ -1481,7 +1481,7 @@ out_fail: return ret; } -static int ext3_writeback_writepage(struct page *page, +static int ext4_writeback_writepage(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; @@ -1489,21 +1489,21 @@ static int ext3_writeback_writepage(struct page *page, int ret = 0; int err; - if (ext3_journal_current_handle()) + if (ext4_journal_current_handle()) goto out_fail; - handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode)); if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto out_fail; } - if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) - ret = nobh_writepage(page, ext3_get_block, wbc); + if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) + ret = nobh_writepage(page, ext4_get_block, wbc); else - ret = block_write_full_page(page, ext3_get_block, wbc); + ret = block_write_full_page(page, ext4_get_block, wbc); - err = ext3_journal_stop(handle); + err = ext4_journal_stop(handle); if (!ret) ret = err; return ret; @@ -1514,7 +1514,7 @@ out_fail: return ret; } -static int ext3_journalled_writepage(struct page *page, +static int ext4_journalled_writepage(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; @@ -1522,10 +1522,10 @@ static int ext3_journalled_writepage(struct page *page, int ret = 0; int err; - if (ext3_journal_current_handle()) + if (ext4_journal_current_handle()) goto no_write; - handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode)); if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto no_write; @@ -1538,9 +1538,9 @@ static int ext3_journalled_writepage(struct page *page, */ ClearPageChecked(page); ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE, - ext3_get_block); + ext4_get_block); if (ret != 0) { - ext3_journal_stop(handle); + ext4_journal_stop(handle); goto out_unlock; } ret = walk_page_buffers(handle, page_buffers(page), 0, @@ -1550,7 +1550,7 @@ static int ext3_journalled_writepage(struct page *page, PAGE_CACHE_SIZE, NULL, commit_write_fn); if (ret == 0) ret = err; - EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; + EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; unlock_page(page); } else { /* @@ -1558,9 +1558,9 @@ static int ext3_journalled_writepage(struct page *page, * really know unless we go poke around in the buffer_heads. * But block_write_full_page will do the right thing. */ - ret = block_write_full_page(page, ext3_get_block, wbc); + ret = block_write_full_page(page, ext4_get_block, wbc); } - err = ext3_journal_stop(handle); + err = ext4_journal_stop(handle); if (!ret) ret = err; out: @@ -1573,21 +1573,21 @@ out_unlock: goto out; } -static int ext3_readpage(struct file *file, struct page *page) +static int ext4_readpage(struct file *file, struct page *page) { - return mpage_readpage(page, ext3_get_block); + return mpage_readpage(page, ext4_get_block); } static int -ext3_readpages(struct file *file, struct address_space *mapping, +ext4_readpages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { - return mpage_readpages(mapping, pages, nr_pages, ext3_get_block); + return mpage_readpages(mapping, pages, nr_pages, ext4_get_block); } -static void ext3_invalidatepage(struct page *page, unsigned long offset) +static void ext4_invalidatepage(struct page *page, unsigned long offset) { - journal_t *journal = EXT3_JOURNAL(page->mapping->host); + journal_t *journal = EXT4_JOURNAL(page->mapping->host); /* * If it's a full truncate we just forget about the pending dirtying @@ -1598,9 +1598,9 @@ static void ext3_invalidatepage(struct page *page, unsigned long offset) journal_invalidatepage(journal, page, offset); } -static int ext3_releasepage(struct page *page, gfp_t wait) +static int ext4_releasepage(struct page *page, gfp_t wait) { - journal_t *journal = EXT3_JOURNAL(page->mapping->host); + journal_t *journal = EXT4_JOURNAL(page->mapping->host); WARN_ON(PageChecked(page)); if (!page_has_buffers(page)) @@ -1616,13 +1616,13 @@ static int ext3_releasepage(struct page *page, gfp_t wait) * If the O_DIRECT write is intantiating holes inside i_size and the machine * crashes then stale disk data _may_ be exposed inside the file. */ -static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, +static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct ext3_inode_info *ei = EXT3_I(inode); + struct ext4_inode_info *ei = EXT4_I(inode); handle_t *handle = NULL; ssize_t ret; int orphan = 0; @@ -1631,13 +1631,13 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, if (rw == WRITE) { loff_t final_size = offset + count; - handle = ext3_journal_start(inode, DIO_CREDITS); + handle = ext4_journal_start(inode, DIO_CREDITS); if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto out; } if (final_size > inode->i_size) { - ret = ext3_orphan_add(handle, inode); + ret = ext4_orphan_add(handle, inode); if (ret) goto out_stop; orphan = 1; @@ -1647,10 +1647,10 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, - ext3_get_block, NULL); + ext4_get_block, NULL); /* - * Reacquire the handle: ext3_get_block() can restart the transaction + * Reacquire the handle: ext4_get_block() can restart the transaction */ handle = journal_current_handle(); @@ -1659,7 +1659,7 @@ out_stop: int err; if (orphan && inode->i_nlink) - ext3_orphan_del(handle, inode); + ext4_orphan_del(handle, inode); if (orphan && ret > 0) { loff_t end = offset + ret; if (end > inode->i_size) { @@ -1669,13 +1669,13 @@ out_stop: * We're going to return a positive `ret' * here due to non-zero-length I/O, so there's * no way of reporting error returns from - * ext3_mark_inode_dirty() to userspace. So + * ext4_mark_inode_dirty() to userspace. So * ignore it. */ - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); } } - err = ext3_journal_stop(handle); + err = ext4_journal_stop(handle); if (ret == 0) ret = err; } @@ -1684,7 +1684,7 @@ out: } /* - * Pages can be marked dirty completely asynchronously from ext3's journalling + * Pages can be marked dirty completely asynchronously from ext4's journalling * activity. By filemap_sync_pte(), try_to_unmap_one(), etc. We cannot do * much here because ->set_page_dirty is called under VFS locks. The page is * not necessarily locked. @@ -1696,73 +1696,73 @@ out: * So what we do is to mark the page "pending dirty" and next time writepage * is called, propagate that into the buffers appropriately. */ -static int ext3_journalled_set_page_dirty(struct page *page) +static int ext4_journalled_set_page_dirty(struct page *page) { SetPageChecked(page); return __set_page_dirty_nobuffers(page); } -static const struct address_space_operations ext3_ordered_aops = { - .readpage = ext3_readpage, - .readpages = ext3_readpages, - .writepage = ext3_ordered_writepage, +static const struct address_space_operations ext4_ordered_aops = { + .readpage = ext4_readpage, + .readpages = ext4_readpages, + .writepage = ext4_ordered_writepage, .sync_page = block_sync_page, - .prepare_write = ext3_prepare_write, - .commit_write = ext3_ordered_commit_write, - .bmap = ext3_bmap, - .invalidatepage = ext3_invalidatepage, - .releasepage = ext3_releasepage, - .direct_IO = ext3_direct_IO, + .prepare_write = ext4_prepare_write, + .commit_write = ext4_ordered_commit_write, + .bmap = ext4_bmap, + .invalidatepage = ext4_invalidatepage, + .releasepage = ext4_releasepage, + .direct_IO = ext4_direct_IO, .migratepage = buffer_migrate_page, }; -static const struct address_space_operations ext3_writeback_aops = { - .readpage = ext3_readpage, - .readpages = ext3_readpages, - .writepage = ext3_writeback_writepage, +static const struct address_space_operations ext4_writeback_aops = { + .readpage = ext4_readpage, + .readpages = ext4_readpages, + .writepage = ext4_writeback_writepage, .sync_page = block_sync_page, - .prepare_write = ext3_prepare_write, - .commit_write = ext3_writeback_commit_write, - .bmap = ext3_bmap, - .invalidatepage = ext3_invalidatepage, - .releasepage = ext3_releasepage, - .direct_IO = ext3_direct_IO, + .prepare_write = ext4_prepare_write, + .commit_write = ext4_writeback_commit_write, + .bmap = ext4_bmap, + .invalidatepage = ext4_invalidatepage, + .releasepage = ext4_releasepage, + .direct_IO = ext4_direct_IO, .migratepage = buffer_migrate_page, }; -static const struct address_space_operations ext3_journalled_aops = { - .readpage = ext3_readpage, - .readpages = ext3_readpages, - .writepage = ext3_journalled_writepage, +static const struct address_space_operations ext4_journalled_aops = { + .readpage = ext4_readpage, + .readpages = ext4_readpages, + .writepage = ext4_journalled_writepage, .sync_page = block_sync_page, - .prepare_write = ext3_prepare_write, - .commit_write = ext3_journalled_commit_write, - .set_page_dirty = ext3_journalled_set_page_dirty, - .bmap = ext3_bmap, - .invalidatepage = ext3_invalidatepage, - .releasepage = ext3_releasepage, + .prepare_write = ext4_prepare_write, + .commit_write = ext4_journalled_commit_write, + .set_page_dirty = ext4_journalled_set_page_dirty, + .bmap = ext4_bmap, + .invalidatepage = ext4_invalidatepage, + .releasepage = ext4_releasepage, }; -void ext3_set_aops(struct inode *inode) +void ext4_set_aops(struct inode *inode) { - if (ext3_should_order_data(inode)) - inode->i_mapping->a_ops = &ext3_ordered_aops; - else if (ext3_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext3_writeback_aops; + if (ext4_should_order_data(inode)) + inode->i_mapping->a_ops = &ext4_ordered_aops; + else if (ext4_should_writeback_data(inode)) + inode->i_mapping->a_ops = &ext4_writeback_aops; else - inode->i_mapping->a_ops = &ext3_journalled_aops; + inode->i_mapping->a_ops = &ext4_journalled_aops; } /* - * ext3_block_truncate_page() zeroes out a mapping from file offset `from' + * ext4_block_truncate_page() zeroes out a mapping from file offset `from' * up to the end of the block which corresponds to `from'. * This required during truncate. We need to physically zero the tail end * of that block so it doesn't yield old data if the file is later grown. */ -static int ext3_block_truncate_page(handle_t *handle, struct page *page, +static int ext4_block_truncate_page(handle_t *handle, struct page *page, struct address_space *mapping, loff_t from) { - ext3_fsblk_t index = from >> PAGE_CACHE_SHIFT; + ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT; unsigned offset = from & (PAGE_CACHE_SIZE-1); unsigned blocksize, iblock, length, pos; struct inode *inode = mapping->host; @@ -1779,7 +1779,7 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page, * read-in the page - otherwise we create buffers to do the IO. */ if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) && - ext3_should_writeback_data(inode) && PageUptodate(page)) { + ext4_should_writeback_data(inode) && PageUptodate(page)) { kaddr = kmap_atomic(page, KM_USER0); memset(kaddr + offset, 0, length); flush_dcache_page(page); @@ -1808,7 +1808,7 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page, if (!buffer_mapped(bh)) { BUFFER_TRACE(bh, "unmapped"); - ext3_get_block(inode, iblock, bh, 0); + ext4_get_block(inode, iblock, bh, 0); /* unmapped? It's a hole - nothing to do */ if (!buffer_mapped(bh)) { BUFFER_TRACE(bh, "still unmapped"); @@ -1829,9 +1829,9 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page, goto unlock; } - if (ext3_should_journal_data(inode)) { + if (ext4_should_journal_data(inode)) { BUFFER_TRACE(bh, "get write access"); - err = ext3_journal_get_write_access(handle, bh); + err = ext4_journal_get_write_access(handle, bh); if (err) goto unlock; } @@ -1844,11 +1844,11 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page, BUFFER_TRACE(bh, "zeroed end of block"); err = 0; - if (ext3_should_journal_data(inode)) { - err = ext3_journal_dirty_metadata(handle, bh); + if (ext4_should_journal_data(inode)) { + err = ext4_journal_dirty_metadata(handle, bh); } else { - if (ext3_should_order_data(inode)) - err = ext3_journal_dirty_data(handle, bh); + if (ext4_should_order_data(inode)) + err = ext4_journal_dirty_data(handle, bh); mark_buffer_dirty(bh); } @@ -1872,14 +1872,14 @@ static inline int all_zeroes(__le32 *p, __le32 *q) } /** - * ext3_find_shared - find the indirect blocks for partial truncation. + * ext4_find_shared - find the indirect blocks for partial truncation. * @inode: inode in question * @depth: depth of the affected branch - * @offsets: offsets of pointers in that branch (see ext3_block_to_path) + * @offsets: offsets of pointers in that branch (see ext4_block_to_path) * @chain: place to store the pointers to partial indirect blocks * @top: place to the (detached) top of branch * - * This is a helper function used by ext3_truncate(). + * This is a helper function used by ext4_truncate(). * * When we do truncate() we may have to clean the ends of several * indirect blocks but leave the blocks themselves alive. Block is @@ -1887,7 +1887,7 @@ static inline int all_zeroes(__le32 *p, __le32 *q) * from it (and it is on the path to the first completely truncated * data block, indeed). We have to free the top of that path along * with everything to the right of the path. Since no allocation - * past the truncation point is possible until ext3_truncate() + * past the truncation point is possible until ext4_truncate() * finishes, we may safely do the latter, but top of branch may * require special attention - pageout below the truncation point * might try to populate it. @@ -1906,7 +1906,7 @@ static inline int all_zeroes(__le32 *p, __le32 *q) * c) free the subtrees growing from the inode past the @chain[0]. * (no partially truncated stuff there). */ -static Indirect *ext3_find_shared(struct inode *inode, int depth, +static Indirect *ext4_find_shared(struct inode *inode, int depth, int offsets[4], Indirect chain[4], __le32 *top) { Indirect *partial, *p; @@ -1916,7 +1916,7 @@ static Indirect *ext3_find_shared(struct inode *inode, int depth, /* Make k index the deepest non-null offest + 1 */ for (k = depth; k > 1 && !offsets[k-1]; k--) ; - partial = ext3_get_branch(inode, k, offsets, chain, &err); + partial = ext4_get_branch(inode, k, offsets, chain, &err); /* Writer: pointers */ if (!partial) partial = chain + k-1; @@ -1939,7 +1939,7 @@ static Indirect *ext3_find_shared(struct inode *inode, int depth, p->p--; } else { *top = *p->p; - /* Nope, don't do this in ext3. Must leave the tree intact */ + /* Nope, don't do this in ext4. Must leave the tree intact */ #if 0 *p->p = 0; #endif @@ -1962,21 +1962,21 @@ no_top: * We release `count' blocks on disk, but (last - first) may be greater * than `count' because there can be holes in there. */ -static void ext3_clear_blocks(handle_t *handle, struct inode *inode, - struct buffer_head *bh, ext3_fsblk_t block_to_free, +static void ext4_clear_blocks(handle_t *handle, struct inode *inode, + struct buffer_head *bh, ext4_fsblk_t block_to_free, unsigned long count, __le32 *first, __le32 *last) { __le32 *p; if (try_to_extend_transaction(handle, inode)) { if (bh) { - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - ext3_journal_dirty_metadata(handle, bh); + BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); + ext4_journal_dirty_metadata(handle, bh); } - ext3_mark_inode_dirty(handle, inode); - ext3_journal_test_restart(handle, inode); + ext4_mark_inode_dirty(handle, inode); + ext4_journal_test_restart(handle, inode); if (bh) { BUFFER_TRACE(bh, "retaking write access"); - ext3_journal_get_write_access(handle, bh); + ext4_journal_get_write_access(handle, bh); } } @@ -1995,15 +1995,15 @@ static void ext3_clear_blocks(handle_t *handle, struct inode *inode, *p = 0; bh = sb_find_get_block(inode->i_sb, nr); - ext3_forget(handle, 0, inode, bh, nr); + ext4_forget(handle, 0, inode, bh, nr); } } - ext3_free_blocks(handle, inode, block_to_free, count); + ext4_free_blocks(handle, inode, block_to_free, count); } /** - * ext3_free_data - free a list of data blocks + * ext4_free_data - free a list of data blocks * @handle: handle for this transaction * @inode: inode we are dealing with * @this_bh: indirect buffer_head which contains *@first and *@last @@ -2021,23 +2021,23 @@ static void ext3_clear_blocks(handle_t *handle, struct inode *inode, * @this_bh will be %NULL if @first and @last point into the inode's direct * block pointers. */ -static void ext3_free_data(handle_t *handle, struct inode *inode, +static void ext4_free_data(handle_t *handle, struct inode *inode, struct buffer_head *this_bh, __le32 *first, __le32 *last) { - ext3_fsblk_t block_to_free = 0; /* Starting block # of a run */ + ext4_fsblk_t block_to_free = 0; /* Starting block # of a run */ unsigned long count = 0; /* Number of blocks in the run */ __le32 *block_to_free_p = NULL; /* Pointer into inode/ind corresponding to block_to_free */ - ext3_fsblk_t nr; /* Current block # */ + ext4_fsblk_t nr; /* Current block # */ __le32 *p; /* Pointer into inode/ind for current block */ int err; if (this_bh) { /* For indirect block */ BUFFER_TRACE(this_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, this_bh); + err = ext4_journal_get_write_access(handle, this_bh); /* Important: if we can't update the indirect pointers * to the blocks, we can't free them. */ if (err) @@ -2055,7 +2055,7 @@ static void ext3_free_data(handle_t *handle, struct inode *inode, } else if (nr == block_to_free + count) { count++; } else { - ext3_clear_blocks(handle, inode, this_bh, + ext4_clear_blocks(handle, inode, this_bh, block_to_free, count, block_to_free_p, p); block_to_free = nr; @@ -2066,17 +2066,17 @@ static void ext3_free_data(handle_t *handle, struct inode *inode, } if (count > 0) - ext3_clear_blocks(handle, inode, this_bh, block_to_free, + ext4_clear_blocks(handle, inode, this_bh, block_to_free, count, block_to_free_p, p); if (this_bh) { - BUFFER_TRACE(this_bh, "call ext3_journal_dirty_metadata"); - ext3_journal_dirty_metadata(handle, this_bh); + BUFFER_TRACE(this_bh, "call ext4_journal_dirty_metadata"); + ext4_journal_dirty_metadata(handle, this_bh); } } /** - * ext3_free_branches - free an array of branches + * ext4_free_branches - free an array of branches * @handle: JBD handle for this transaction * @inode: inode we are dealing with * @parent_bh: the buffer_head which contains *@first and *@last @@ -2088,11 +2088,11 @@ static void ext3_free_data(handle_t *handle, struct inode *inode, * stored as little-endian 32-bit) and updating @inode->i_blocks * appropriately. */ -static void ext3_free_branches(handle_t *handle, struct inode *inode, +static void ext4_free_branches(handle_t *handle, struct inode *inode, struct buffer_head *parent_bh, __le32 *first, __le32 *last, int depth) { - ext3_fsblk_t nr; + ext4_fsblk_t nr; __le32 *p; if (is_handle_aborted(handle)) @@ -2100,7 +2100,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, if (depth--) { struct buffer_head *bh; - int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb); + int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); p = last; while (--p >= first) { nr = le32_to_cpu(*p); @@ -2115,7 +2115,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, * (should be rare). */ if (!bh) { - ext3_error(inode->i_sb, "ext3_free_branches", + ext4_error(inode->i_sb, "ext4_free_branches", "Read failure, inode=%lu, block="E3FSBLK, inode->i_ino, nr); continue; @@ -2123,7 +2123,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, /* This zaps the entire block. Bottom up. */ BUFFER_TRACE(bh, "free child branches"); - ext3_free_branches(handle, inode, bh, + ext4_free_branches(handle, inode, bh, (__le32*)bh->b_data, (__le32*)bh->b_data + addr_per_block, depth); @@ -2138,7 +2138,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, * transaction. But if it's part of the committing * transaction then journal_forget() will simply * brelse() it. That means that if the underlying - * block is reallocated in ext3_get_block(), + * block is reallocated in ext4_get_block(), * unmap_underlying_metadata() will find this block * and will try to get rid of it. damn, damn. * @@ -2147,7 +2147,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, * revoke records must be emitted *before* clearing * this block's bit in the bitmaps. */ - ext3_forget(handle, 1, inode, bh, bh->b_blocknr); + ext4_forget(handle, 1, inode, bh, bh->b_blocknr); /* * Everything below this this pointer has been @@ -2168,11 +2168,11 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, if (is_handle_aborted(handle)) return; if (try_to_extend_transaction(handle, inode)) { - ext3_mark_inode_dirty(handle, inode); - ext3_journal_test_restart(handle, inode); + ext4_mark_inode_dirty(handle, inode); + ext4_journal_test_restart(handle, inode); } - ext3_free_blocks(handle, inode, nr, 1); + ext4_free_blocks(handle, inode, nr, 1); if (parent_bh) { /* @@ -2180,12 +2180,12 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, * pointed to by an indirect block: journal it */ BUFFER_TRACE(parent_bh, "get_write_access"); - if (!ext3_journal_get_write_access(handle, + if (!ext4_journal_get_write_access(handle, parent_bh)){ *p = 0; BUFFER_TRACE(parent_bh, - "call ext3_journal_dirty_metadata"); - ext3_journal_dirty_metadata(handle, + "call ext4_journal_dirty_metadata"); + ext4_journal_dirty_metadata(handle, parent_bh); } } @@ -2193,15 +2193,15 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, } else { /* We have reached the bottom of the tree. */ BUFFER_TRACE(parent_bh, "free data blocks"); - ext3_free_data(handle, inode, parent_bh, first, last); + ext4_free_data(handle, inode, parent_bh, first, last); } } /* - * ext3_truncate() + * ext4_truncate() * - * We block out ext3_get_block() block instantiations across the entire - * transaction, and VFS/VM ensures that ext3_truncate() cannot run + * We block out ext4_get_block() block instantiations across the entire + * transaction, and VFS/VM ensures that ext4_truncate() cannot run * simultaneously on behalf of the same inode. * * As we work through the truncate and commmit bits of it to the journal there @@ -2218,19 +2218,19 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, * truncate against the orphan inode list. * * The committed inode has the new, desired i_size (which is the same as - * i_disksize in this case). After a crash, ext3_orphan_cleanup() will see + * i_disksize in this case). After a crash, ext4_orphan_cleanup() will see * that this inode's truncate did not complete and it will again call - * ext3_truncate() to have another go. So there will be instantiated blocks - * to the right of the truncation point in a crashed ext3 filesystem. But + * ext4_truncate() to have another go. So there will be instantiated blocks + * to the right of the truncation point in a crashed ext4 filesystem. But * that's fine - as long as they are linked from the inode, the post-crash - * ext3_truncate() run will find them and release them. + * ext4_truncate() run will find them and release them. */ -void ext3_truncate(struct inode *inode) +void ext4_truncate(struct inode *inode) { handle_t *handle; - struct ext3_inode_info *ei = EXT3_I(inode); + struct ext4_inode_info *ei = EXT4_I(inode); __le32 *i_data = ei->i_data; - int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb); + int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); struct address_space *mapping = inode->i_mapping; int offsets[4]; Indirect chain[4]; @@ -2244,7 +2244,7 @@ void ext3_truncate(struct inode *inode) if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return; - if (ext3_inode_is_fast_symlink(inode)) + if (ext4_inode_is_fast_symlink(inode)) return; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return; @@ -2275,12 +2275,12 @@ void ext3_truncate(struct inode *inode) } last_block = (inode->i_size + blocksize-1) - >> EXT3_BLOCK_SIZE_BITS(inode->i_sb); + >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); if (page) - ext3_block_truncate_page(handle, page, mapping, inode->i_size); + ext4_block_truncate_page(handle, page, mapping, inode->i_size); - n = ext3_block_to_path(inode, last_block, offsets, NULL); + n = ext4_block_to_path(inode, last_block, offsets, NULL); if (n == 0) goto out_stop; /* error */ @@ -2293,7 +2293,7 @@ void ext3_truncate(struct inode *inode) * Implication: the file must always be in a sane, consistent * truncatable state while each transaction commits. */ - if (ext3_orphan_add(handle, inode)) + if (ext4_orphan_add(handle, inode)) goto out_stop; /* @@ -2301,28 +2301,28 @@ void ext3_truncate(struct inode *inode) * occurs before the truncate completes, so it is now safe to propagate * the new, shorter inode size (held for now in i_size) into the * on-disk inode. We do this via i_disksize, which is the value which - * ext3 *really* writes onto the disk inode. + * ext4 *really* writes onto the disk inode. */ ei->i_disksize = inode->i_size; /* - * From here we block out all ext3_get_block() callers who want to + * From here we block out all ext4_get_block() callers who want to * modify the block allocation tree. */ mutex_lock(&ei->truncate_mutex); if (n == 1) { /* direct blocks */ - ext3_free_data(handle, inode, NULL, i_data+offsets[0], - i_data + EXT3_NDIR_BLOCKS); + ext4_free_data(handle, inode, NULL, i_data+offsets[0], + i_data + EXT4_NDIR_BLOCKS); goto do_indirects; } - partial = ext3_find_shared(inode, n, offsets, chain, &nr); + partial = ext4_find_shared(inode, n, offsets, chain, &nr); /* Kill the top of shared branch (not detached) */ if (nr) { if (partial == chain) { /* Shared branch grows from the inode */ - ext3_free_branches(handle, inode, NULL, + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, (chain+n-1) - partial); *partial->p = 0; /* @@ -2332,14 +2332,14 @@ void ext3_truncate(struct inode *inode) } else { /* Shared branch grows from an indirect block */ BUFFER_TRACE(partial->bh, "get_write_access"); - ext3_free_branches(handle, inode, partial->bh, + ext4_free_branches(handle, inode, partial->bh, partial->p, partial->p+1, (chain+n-1) - partial); } } /* Clear the ends of indirect blocks on the shared branch */ while (partial > chain) { - ext3_free_branches(handle, inode, partial->bh, partial->p + 1, + ext4_free_branches(handle, inode, partial->bh, partial->p + 1, (__le32*)partial->bh->b_data+addr_per_block, (chain+n-1) - partial); BUFFER_TRACE(partial->bh, "call brelse"); @@ -2350,32 +2350,32 @@ do_indirects: /* Kill the remaining (whole) subtrees */ switch (offsets[0]) { default: - nr = i_data[EXT3_IND_BLOCK]; + nr = i_data[EXT4_IND_BLOCK]; if (nr) { - ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 1); - i_data[EXT3_IND_BLOCK] = 0; + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); + i_data[EXT4_IND_BLOCK] = 0; } - case EXT3_IND_BLOCK: - nr = i_data[EXT3_DIND_BLOCK]; + case EXT4_IND_BLOCK: + nr = i_data[EXT4_DIND_BLOCK]; if (nr) { - ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 2); - i_data[EXT3_DIND_BLOCK] = 0; + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); + i_data[EXT4_DIND_BLOCK] = 0; } - case EXT3_DIND_BLOCK: - nr = i_data[EXT3_TIND_BLOCK]; + case EXT4_DIND_BLOCK: + nr = i_data[EXT4_TIND_BLOCK]; if (nr) { - ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 3); - i_data[EXT3_TIND_BLOCK] = 0; + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); + i_data[EXT4_TIND_BLOCK] = 0; } - case EXT3_TIND_BLOCK: + case EXT4_TIND_BLOCK: ; } - ext3_discard_reservation(inode); + ext4_discard_reservation(inode); mutex_unlock(&ei->truncate_mutex); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); /* * In a multi-transaction truncate, we only make the final transaction @@ -2388,25 +2388,25 @@ out_stop: * If this was a simple ftruncate(), and the file will remain alive * then we need to clear up the orphan record which we created above. * However, if this was a real unlink then we were called by - * ext3_delete_inode(), and we allow that function to clean up the + * ext4_delete_inode(), and we allow that function to clean up the * orphan info for us. */ if (inode->i_nlink) - ext3_orphan_del(handle, inode); + ext4_orphan_del(handle, inode); - ext3_journal_stop(handle); + ext4_journal_stop(handle); } -static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb, - unsigned long ino, struct ext3_iloc *iloc) +static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb, + unsigned long ino, struct ext4_iloc *iloc) { unsigned long desc, group_desc, block_group; unsigned long offset; - ext3_fsblk_t block; + ext4_fsblk_t block; struct buffer_head *bh; - struct ext3_group_desc * gdp; + struct ext4_group_desc * gdp; - if (!ext3_valid_inum(sb, ino)) { + if (!ext4_valid_inum(sb, ino)) { /* * This error is already checked for in namei.c unless we are * looking at an NFS filehandle, in which case no error @@ -2415,54 +2415,54 @@ static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb, return 0; } - block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); - if (block_group >= EXT3_SB(sb)->s_groups_count) { - ext3_error(sb,"ext3_get_inode_block","group >= groups count"); + block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); + if (block_group >= EXT4_SB(sb)->s_groups_count) { + ext4_error(sb,"ext4_get_inode_block","group >= groups count"); return 0; } smp_rmb(); - group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(sb); - desc = block_group & (EXT3_DESC_PER_BLOCK(sb) - 1); - bh = EXT3_SB(sb)->s_group_desc[group_desc]; + group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); + desc = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); + bh = EXT4_SB(sb)->s_group_desc[group_desc]; if (!bh) { - ext3_error (sb, "ext3_get_inode_block", + ext4_error (sb, "ext4_get_inode_block", "Descriptor not loaded"); return 0; } - gdp = (struct ext3_group_desc *)bh->b_data; + gdp = (struct ext4_group_desc *)bh->b_data; /* * Figure out the offset within the block group inode table */ - offset = ((ino - 1) % EXT3_INODES_PER_GROUP(sb)) * - EXT3_INODE_SIZE(sb); + offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) * + EXT4_INODE_SIZE(sb); block = le32_to_cpu(gdp[desc].bg_inode_table) + - (offset >> EXT3_BLOCK_SIZE_BITS(sb)); + (offset >> EXT4_BLOCK_SIZE_BITS(sb)); iloc->block_group = block_group; - iloc->offset = offset & (EXT3_BLOCK_SIZE(sb) - 1); + iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1); return block; } /* - * ext3_get_inode_loc returns with an extra refcount against the inode's + * ext4_get_inode_loc returns with an extra refcount against the inode's * underlying buffer_head on success. If 'in_mem' is true, we have all * data in memory that is needed to recreate the on-disk version of this * inode. */ -static int __ext3_get_inode_loc(struct inode *inode, - struct ext3_iloc *iloc, int in_mem) +static int __ext4_get_inode_loc(struct inode *inode, + struct ext4_iloc *iloc, int in_mem) { - ext3_fsblk_t block; + ext4_fsblk_t block; struct buffer_head *bh; - block = ext3_get_inode_block(inode->i_sb, inode->i_ino, iloc); + block = ext4_get_inode_block(inode->i_sb, inode->i_ino, iloc); if (!block) return -EIO; bh = sb_getblk(inode->i_sb, block); if (!bh) { - ext3_error (inode->i_sb, "ext3_get_inode_loc", + ext4_error (inode->i_sb, "ext4_get_inode_loc", "unable to read inode block - " "inode=%lu, block="E3FSBLK, inode->i_ino, block); @@ -2483,22 +2483,22 @@ static int __ext3_get_inode_loc(struct inode *inode, */ if (in_mem) { struct buffer_head *bitmap_bh; - struct ext3_group_desc *desc; + struct ext4_group_desc *desc; int inodes_per_buffer; int inode_offset, i; int block_group; int start; block_group = (inode->i_ino - 1) / - EXT3_INODES_PER_GROUP(inode->i_sb); + EXT4_INODES_PER_GROUP(inode->i_sb); inodes_per_buffer = bh->b_size / - EXT3_INODE_SIZE(inode->i_sb); + EXT4_INODE_SIZE(inode->i_sb); inode_offset = ((inode->i_ino - 1) % - EXT3_INODES_PER_GROUP(inode->i_sb)); + EXT4_INODES_PER_GROUP(inode->i_sb)); start = inode_offset & ~(inodes_per_buffer - 1); /* Is the inode bitmap in cache? */ - desc = ext3_get_group_desc(inode->i_sb, + desc = ext4_get_group_desc(inode->i_sb, block_group, NULL); if (!desc) goto make_io; @@ -2520,7 +2520,7 @@ static int __ext3_get_inode_loc(struct inode *inode, for (i = start; i < start + inodes_per_buffer; i++) { if (i == inode_offset) continue; - if (ext3_test_bit(i, bitmap_bh->b_data)) + if (ext4_test_bit(i, bitmap_bh->b_data)) break; } brelse(bitmap_bh); @@ -2544,7 +2544,7 @@ make_io: submit_bh(READ_META, bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { - ext3_error(inode->i_sb, "ext3_get_inode_loc", + ext4_error(inode->i_sb, "ext4_get_inode_loc", "unable to read inode block - " "inode=%lu, block="E3FSBLK, inode->i_ino, block); @@ -2557,48 +2557,48 @@ has_buffer: return 0; } -int ext3_get_inode_loc(struct inode *inode, struct ext3_iloc *iloc) +int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc) { /* We have all inode data except xattrs in memory here. */ - return __ext3_get_inode_loc(inode, iloc, - !(EXT3_I(inode)->i_state & EXT3_STATE_XATTR)); + return __ext4_get_inode_loc(inode, iloc, + !(EXT4_I(inode)->i_state & EXT4_STATE_XATTR)); } -void ext3_set_inode_flags(struct inode *inode) +void ext4_set_inode_flags(struct inode *inode) { - unsigned int flags = EXT3_I(inode)->i_flags; + unsigned int flags = EXT4_I(inode)->i_flags; inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); - if (flags & EXT3_SYNC_FL) + if (flags & EXT4_SYNC_FL) inode->i_flags |= S_SYNC; - if (flags & EXT3_APPEND_FL) + if (flags & EXT4_APPEND_FL) inode->i_flags |= S_APPEND; - if (flags & EXT3_IMMUTABLE_FL) + if (flags & EXT4_IMMUTABLE_FL) inode->i_flags |= S_IMMUTABLE; - if (flags & EXT3_NOATIME_FL) + if (flags & EXT4_NOATIME_FL) inode->i_flags |= S_NOATIME; - if (flags & EXT3_DIRSYNC_FL) + if (flags & EXT4_DIRSYNC_FL) inode->i_flags |= S_DIRSYNC; } -void ext3_read_inode(struct inode * inode) +void ext4_read_inode(struct inode * inode) { - struct ext3_iloc iloc; - struct ext3_inode *raw_inode; - struct ext3_inode_info *ei = EXT3_I(inode); + struct ext4_iloc iloc; + struct ext4_inode *raw_inode; + struct ext4_inode_info *ei = EXT4_I(inode); struct buffer_head *bh; int block; -#ifdef CONFIG_EXT3_FS_POSIX_ACL - ei->i_acl = EXT3_ACL_NOT_CACHED; - ei->i_default_acl = EXT3_ACL_NOT_CACHED; +#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL + ei->i_acl = EXT4_ACL_NOT_CACHED; + ei->i_default_acl = EXT4_ACL_NOT_CACHED; #endif ei->i_block_alloc_info = NULL; - if (__ext3_get_inode_loc(inode, &iloc, 0)) + if (__ext4_get_inode_loc(inode, &iloc, 0)) goto bad_inode; bh = iloc.bh; - raw_inode = ext3_raw_inode(&iloc); + raw_inode = ext4_raw_inode(&iloc); inode->i_mode = le16_to_cpu(raw_inode->i_mode); inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); @@ -2623,7 +2623,7 @@ void ext3_read_inode(struct inode * inode) */ if (inode->i_nlink == 0) { if (inode->i_mode == 0 || - !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ORPHAN_FS)) { + !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) { /* this inode is deleted */ brelse (bh); goto bad_inode; @@ -2635,7 +2635,7 @@ void ext3_read_inode(struct inode * inode) } inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); ei->i_flags = le32_to_cpu(raw_inode->i_flags); -#ifdef EXT3_FRAGMENTS +#ifdef EXT4_FRAGMENTS ei->i_faddr = le32_to_cpu(raw_inode->i_faddr); ei->i_frag_no = raw_inode->i_frag; ei->i_frag_size = raw_inode->i_fsize; @@ -2654,51 +2654,51 @@ void ext3_read_inode(struct inode * inode) * NOTE! The in-memory inode i_data array is in little-endian order * even on big-endian machines: we do NOT byteswap the block numbers! */ - for (block = 0; block < EXT3_N_BLOCKS; block++) + for (block = 0; block < EXT4_N_BLOCKS; block++) ei->i_data[block] = raw_inode->i_block[block]; INIT_LIST_HEAD(&ei->i_orphan); - if (inode->i_ino >= EXT3_FIRST_INO(inode->i_sb) + 1 && - EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) { + if (inode->i_ino >= EXT4_FIRST_INO(inode->i_sb) + 1 && + EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { /* * When mke2fs creates big inodes it does not zero out - * the unused bytes above EXT3_GOOD_OLD_INODE_SIZE, + * the unused bytes above EXT4_GOOD_OLD_INODE_SIZE, * so ignore those first few inodes. */ ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); - if (EXT3_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > - EXT3_INODE_SIZE(inode->i_sb)) + if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > + EXT4_INODE_SIZE(inode->i_sb)) goto bad_inode; if (ei->i_extra_isize == 0) { /* The extra space is currently unused. Use it. */ - ei->i_extra_isize = sizeof(struct ext3_inode) - - EXT3_GOOD_OLD_INODE_SIZE; + ei->i_extra_isize = sizeof(struct ext4_inode) - + EXT4_GOOD_OLD_INODE_SIZE; } else { __le32 *magic = (void *)raw_inode + - EXT3_GOOD_OLD_INODE_SIZE + + EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize; - if (*magic == cpu_to_le32(EXT3_XATTR_MAGIC)) - ei->i_state |= EXT3_STATE_XATTR; + if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) + ei->i_state |= EXT4_STATE_XATTR; } } else ei->i_extra_isize = 0; if (S_ISREG(inode->i_mode)) { - inode->i_op = &ext3_file_inode_operations; - inode->i_fop = &ext3_file_operations; - ext3_set_aops(inode); + inode->i_op = &ext4_file_inode_operations; + inode->i_fop = &ext4_file_operations; + ext4_set_aops(inode); } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &ext3_dir_inode_operations; - inode->i_fop = &ext3_dir_operations; + inode->i_op = &ext4_dir_inode_operations; + inode->i_fop = &ext4_dir_operations; } else if (S_ISLNK(inode->i_mode)) { - if (ext3_inode_is_fast_symlink(inode)) - inode->i_op = &ext3_fast_symlink_inode_operations; + if (ext4_inode_is_fast_symlink(inode)) + inode->i_op = &ext4_fast_symlink_inode_operations; else { - inode->i_op = &ext3_symlink_inode_operations; - ext3_set_aops(inode); + inode->i_op = &ext4_symlink_inode_operations; + ext4_set_aops(inode); } } else { - inode->i_op = &ext3_special_inode_operations; + inode->i_op = &ext4_special_inode_operations; if (raw_inode->i_block[0]) init_special_inode(inode, inode->i_mode, old_decode_dev(le32_to_cpu(raw_inode->i_block[0]))); @@ -2707,7 +2707,7 @@ void ext3_read_inode(struct inode * inode) new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); } brelse (iloc.bh); - ext3_set_inode_flags(inode); + ext4_set_inode_flags(inode); return; bad_inode: @@ -2722,19 +2722,19 @@ bad_inode: * * The caller must have write access to iloc->bh. */ -static int ext3_do_update_inode(handle_t *handle, +static int ext4_do_update_inode(handle_t *handle, struct inode *inode, - struct ext3_iloc *iloc) + struct ext4_iloc *iloc) { - struct ext3_inode *raw_inode = ext3_raw_inode(iloc); - struct ext3_inode_info *ei = EXT3_I(inode); + struct ext4_inode *raw_inode = ext4_raw_inode(iloc); + struct ext4_inode_info *ei = EXT4_I(inode); struct buffer_head *bh = iloc->bh; int err = 0, rc, block; /* For fields not not tracking in the in-memory inode, * initialise them to zero for new inodes. */ - if (ei->i_state & EXT3_STATE_NEW) - memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size); + if (ei->i_state & EXT4_STATE_NEW) + memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); raw_inode->i_mode = cpu_to_le16(inode->i_mode); if(!(test_opt(inode->i_sb, NO_UID32))) { @@ -2769,7 +2769,7 @@ static int ext3_do_update_inode(handle_t *handle, raw_inode->i_blocks = cpu_to_le32(inode->i_blocks); raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); raw_inode->i_flags = cpu_to_le32(ei->i_flags); -#ifdef EXT3_FRAGMENTS +#ifdef EXT4_FRAGMENTS raw_inode->i_faddr = cpu_to_le32(ei->i_faddr); raw_inode->i_frag = ei->i_frag_no; raw_inode->i_fsize = ei->i_frag_size; @@ -2782,24 +2782,24 @@ static int ext3_do_update_inode(handle_t *handle, cpu_to_le32(ei->i_disksize >> 32); if (ei->i_disksize > 0x7fffffffULL) { struct super_block *sb = inode->i_sb; - if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_LARGE_FILE) || - EXT3_SB(sb)->s_es->s_rev_level == - cpu_to_le32(EXT3_GOOD_OLD_REV)) { + if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, + EXT4_FEATURE_RO_COMPAT_LARGE_FILE) || + EXT4_SB(sb)->s_es->s_rev_level == + cpu_to_le32(EXT4_GOOD_OLD_REV)) { /* If this is the first large file * created, add a flag to the superblock. */ - err = ext3_journal_get_write_access(handle, - EXT3_SB(sb)->s_sbh); + err = ext4_journal_get_write_access(handle, + EXT4_SB(sb)->s_sbh); if (err) goto out_brelse; - ext3_update_dynamic_rev(sb); - EXT3_SET_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_LARGE_FILE); + ext4_update_dynamic_rev(sb); + EXT4_SET_RO_COMPAT_FEATURE(sb, + EXT4_FEATURE_RO_COMPAT_LARGE_FILE); sb->s_dirt = 1; handle->h_sync = 1; - err = ext3_journal_dirty_metadata(handle, - EXT3_SB(sb)->s_sbh); + err = ext4_journal_dirty_metadata(handle, + EXT4_SB(sb)->s_sbh); } } } @@ -2815,26 +2815,26 @@ static int ext3_do_update_inode(handle_t *handle, cpu_to_le32(new_encode_dev(inode->i_rdev)); raw_inode->i_block[2] = 0; } - } else for (block = 0; block < EXT3_N_BLOCKS; block++) + } else for (block = 0; block < EXT4_N_BLOCKS; block++) raw_inode->i_block[block] = ei->i_data[block]; if (ei->i_extra_isize) raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - rc = ext3_journal_dirty_metadata(handle, bh); + BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); + rc = ext4_journal_dirty_metadata(handle, bh); if (!err) err = rc; - ei->i_state &= ~EXT3_STATE_NEW; + ei->i_state &= ~EXT4_STATE_NEW; out_brelse: brelse (bh); - ext3_std_error(inode->i_sb, err); + ext4_std_error(inode->i_sb, err); return err; } /* - * ext3_write_inode() + * ext4_write_inode() * * We are called from a few places: * @@ -2851,7 +2851,7 @@ out_brelse: * * In all cases it is actually safe for us to return without doing anything, * because the inode has been copied into a raw inode buffer in - * ext3_mark_inode_dirty(). This is a correctness thing for O_SYNC and for + * ext4_mark_inode_dirty(). This is a correctness thing for O_SYNC and for * knfsd. * * Note that we are absolutely dependent upon all inode dirtiers doing the @@ -2868,12 +2868,12 @@ out_brelse: * `stuff()' is running, and the new i_size will be lost. Plus the inode * will no longer be on the superblock's dirty inode list. */ -int ext3_write_inode(struct inode *inode, int wait) +int ext4_write_inode(struct inode *inode, int wait) { if (current->flags & PF_MEMALLOC) return 0; - if (ext3_journal_current_handle()) { + if (ext4_journal_current_handle()) { jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n"); dump_stack(); return -EIO; @@ -2882,11 +2882,11 @@ int ext3_write_inode(struct inode *inode, int wait) if (!wait) return 0; - return ext3_force_commit(inode->i_sb); + return ext4_force_commit(inode->i_sb); } /* - * ext3_setattr() + * ext4_setattr() * * Called from notify_change. * @@ -2902,7 +2902,7 @@ int ext3_write_inode(struct inode *inode, int wait) * * Called with inode->sem down. */ -int ext3_setattr(struct dentry *dentry, struct iattr *attr) +int ext4_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; int error, rc = 0; @@ -2918,15 +2918,15 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) /* (user+group)*(old+new) structure, inode write (sb, * inode block, ? - but truncate inode update has it) */ - handle = ext3_journal_start(inode, 2*(EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)+ - EXT3_QUOTA_DEL_BLOCKS(inode->i_sb))+3); + handle = ext4_journal_start(inode, 2*(EXT4_QUOTA_INIT_BLOCKS(inode->i_sb)+ + EXT4_QUOTA_DEL_BLOCKS(inode->i_sb))+3); if (IS_ERR(handle)) { error = PTR_ERR(handle); goto err_out; } error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; if (error) { - ext3_journal_stop(handle); + ext4_journal_stop(handle); return error; } /* Update corresponding info in inode so that everything is in @@ -2935,41 +2935,41 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) inode->i_uid = attr->ia_uid; if (attr->ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; - error = ext3_mark_inode_dirty(handle, inode); - ext3_journal_stop(handle); + error = ext4_mark_inode_dirty(handle, inode); + ext4_journal_stop(handle); } if (S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { handle_t *handle; - handle = ext3_journal_start(inode, 3); + handle = ext4_journal_start(inode, 3); if (IS_ERR(handle)) { error = PTR_ERR(handle); goto err_out; } - error = ext3_orphan_add(handle, inode); - EXT3_I(inode)->i_disksize = attr->ia_size; - rc = ext3_mark_inode_dirty(handle, inode); + error = ext4_orphan_add(handle, inode); + EXT4_I(inode)->i_disksize = attr->ia_size; + rc = ext4_mark_inode_dirty(handle, inode); if (!error) error = rc; - ext3_journal_stop(handle); + ext4_journal_stop(handle); } rc = inode_setattr(inode, attr); - /* If inode_setattr's call to ext3_truncate failed to get a + /* If inode_setattr's call to ext4_truncate failed to get a * transaction handle at all, we need to clean up the in-core * orphan list manually. */ if (inode->i_nlink) - ext3_orphan_del(NULL, inode); + ext4_orphan_del(NULL, inode); if (!rc && (ia_valid & ATTR_MODE)) - rc = ext3_acl_chmod(inode); + rc = ext4_acl_chmod(inode); err_out: - ext3_std_error(inode->i_sb, error); + ext4_std_error(inode->i_sb, error); if (!error) error = rc; return error; @@ -2988,9 +2988,9 @@ err_out: * N+5 group descriptor summary blocks * 1 inode block * 1 superblock. - * 2 * EXT3_SINGLEDATA_TRANS_BLOCKS for the quote files + * 2 * EXT4_SINGLEDATA_TRANS_BLOCKS for the quote files * - * 3 * (N + 5) + 2 + 2 * EXT3_SINGLEDATA_TRANS_BLOCKS + * 3 * (N + 5) + 2 + 2 * EXT4_SINGLEDATA_TRANS_BLOCKS * * With ordered or writeback data it's the same, less the N data blocks. * @@ -3003,13 +3003,13 @@ err_out: * block and work out the exact number of indirects which are touched. Pah. */ -static int ext3_writepage_trans_blocks(struct inode *inode) +static int ext4_writepage_trans_blocks(struct inode *inode) { - int bpp = ext3_journal_blocks_per_page(inode); - int indirects = (EXT3_NDIR_BLOCKS % bpp) ? 5 : 3; + int bpp = ext4_journal_blocks_per_page(inode); + int indirects = (EXT4_NDIR_BLOCKS % bpp) ? 5 : 3; int ret; - if (ext3_should_journal_data(inode)) + if (ext4_should_journal_data(inode)) ret = 3 * (bpp + indirects) + 2; else ret = 2 * (bpp + indirects) + 2; @@ -3017,26 +3017,26 @@ static int ext3_writepage_trans_blocks(struct inode *inode) #ifdef CONFIG_QUOTA /* We know that structure was already allocated during DQUOT_INIT so * we will be updating only the data blocks + inodes */ - ret += 2*EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb); + ret += 2*EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); #endif return ret; } /* - * The caller must have previously called ext3_reserve_inode_write(). + * The caller must have previously called ext4_reserve_inode_write(). * Give this, we know that the caller already has write access to iloc->bh. */ -int ext3_mark_iloc_dirty(handle_t *handle, - struct inode *inode, struct ext3_iloc *iloc) +int ext4_mark_iloc_dirty(handle_t *handle, + struct inode *inode, struct ext4_iloc *iloc) { int err = 0; /* the do_update_inode consumes one bh->b_count */ get_bh(iloc->bh); - /* ext3_do_update_inode() does journal_dirty_metadata */ - err = ext3_do_update_inode(handle, inode, iloc); + /* ext4_do_update_inode() does journal_dirty_metadata */ + err = ext4_do_update_inode(handle, inode, iloc); put_bh(iloc->bh); return err; } @@ -3047,22 +3047,22 @@ int ext3_mark_iloc_dirty(handle_t *handle, */ int -ext3_reserve_inode_write(handle_t *handle, struct inode *inode, - struct ext3_iloc *iloc) +ext4_reserve_inode_write(handle_t *handle, struct inode *inode, + struct ext4_iloc *iloc) { int err = 0; if (handle) { - err = ext3_get_inode_loc(inode, iloc); + err = ext4_get_inode_loc(inode, iloc); if (!err) { BUFFER_TRACE(iloc->bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, iloc->bh); + err = ext4_journal_get_write_access(handle, iloc->bh); if (err) { brelse(iloc->bh); iloc->bh = NULL; } } } - ext3_std_error(inode->i_sb, err); + ext4_std_error(inode->i_sb, err); return err; } @@ -3087,20 +3087,20 @@ ext3_reserve_inode_write(handle_t *handle, struct inode *inode, * to do a write_super() to free up some memory. It has the desired * effect. */ -int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode) +int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) { - struct ext3_iloc iloc; + struct ext4_iloc iloc; int err; might_sleep(); - err = ext3_reserve_inode_write(handle, inode, &iloc); + err = ext4_reserve_inode_write(handle, inode, &iloc); if (!err) - err = ext3_mark_iloc_dirty(handle, inode, &iloc); + err = ext4_mark_iloc_dirty(handle, inode, &iloc); return err; } /* - * ext3_dirty_inode() is called from __mark_inode_dirty() + * ext4_dirty_inode() is called from __mark_inode_dirty() * * We're really interested in the case where a file is being extended. * i_size has been changed by generic_commit_write() and we thus need @@ -3113,12 +3113,12 @@ int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode) * so would cause a commit on atime updates, which we don't bother doing. * We handle synchronous inodes at the highest possible level. */ -void ext3_dirty_inode(struct inode *inode) +void ext4_dirty_inode(struct inode *inode) { - handle_t *current_handle = ext3_journal_current_handle(); + handle_t *current_handle = ext4_journal_current_handle(); handle_t *handle; - handle = ext3_journal_start(inode, 2); + handle = ext4_journal_start(inode, 2); if (IS_ERR(handle)) goto out; if (current_handle && @@ -3129,9 +3129,9 @@ void ext3_dirty_inode(struct inode *inode) } else { jbd_debug(5, "marking dirty. outer handle=%p\n", current_handle); - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); } - ext3_journal_stop(handle); + ext4_journal_stop(handle); out: return; } @@ -3140,32 +3140,32 @@ out: /* * Bind an inode's backing buffer_head into this transaction, to prevent * it from being flushed to disk early. Unlike - * ext3_reserve_inode_write, this leaves behind no bh reference and + * ext4_reserve_inode_write, this leaves behind no bh reference and * returns no iloc structure, so the caller needs to repeat the iloc * lookup to mark the inode dirty later. */ -static int ext3_pin_inode(handle_t *handle, struct inode *inode) +static int ext4_pin_inode(handle_t *handle, struct inode *inode) { - struct ext3_iloc iloc; + struct ext4_iloc iloc; int err = 0; if (handle) { - err = ext3_get_inode_loc(inode, &iloc); + err = ext4_get_inode_loc(inode, &iloc); if (!err) { BUFFER_TRACE(iloc.bh, "get_write_access"); err = journal_get_write_access(handle, iloc.bh); if (!err) - err = ext3_journal_dirty_metadata(handle, + err = ext4_journal_dirty_metadata(handle, iloc.bh); brelse(iloc.bh); } } - ext3_std_error(inode->i_sb, err); + ext4_std_error(inode->i_sb, err); return err; } #endif -int ext3_change_inode_journal_flag(struct inode *inode, int val) +int ext4_change_inode_journal_flag(struct inode *inode, int val) { journal_t *journal; handle_t *handle; @@ -3181,7 +3181,7 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val) * nobody is changing anything. */ - journal = EXT3_JOURNAL(inode); + journal = EXT4_JOURNAL(inode); if (is_journal_aborted(journal) || IS_RDONLY(inode)) return -EROFS; @@ -3197,23 +3197,23 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val) */ if (val) - EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL; + EXT4_I(inode)->i_flags |= EXT4_JOURNAL_DATA_FL; else - EXT3_I(inode)->i_flags &= ~EXT3_JOURNAL_DATA_FL; - ext3_set_aops(inode); + EXT4_I(inode)->i_flags &= ~EXT4_JOURNAL_DATA_FL; + ext4_set_aops(inode); journal_unlock_updates(journal); /* Finally we can mark the inode as dirty. */ - handle = ext3_journal_start(inode, 1); + handle = ext4_journal_start(inode, 1); if (IS_ERR(handle)) return PTR_ERR(handle); - err = ext3_mark_inode_dirty(handle, inode); + err = ext4_mark_inode_dirty(handle, inode); handle->h_sync = 1; - ext3_journal_stop(handle); - ext3_std_error(inode->i_sb, err); + ext4_journal_stop(handle); + ext4_std_error(inode->i_sb, err); return err; } diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 12daa6869572..a567af161b06 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/ioctl.c + * linux/fs/ext4/ioctl.c * * Copyright (C) 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -10,30 +10,30 @@ #include #include #include -#include -#include +#include +#include #include #include #include #include -int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, +int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { - struct ext3_inode_info *ei = EXT3_I(inode); + struct ext4_inode_info *ei = EXT4_I(inode); unsigned int flags; unsigned short rsv_window_size; - ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); + ext4_debug ("cmd = %u, arg = %lu\n", cmd, arg); switch (cmd) { - case EXT3_IOC_GETFLAGS: - flags = ei->i_flags & EXT3_FL_USER_VISIBLE; + case EXT4_IOC_GETFLAGS: + flags = ei->i_flags & EXT4_FL_USER_VISIBLE; return put_user(flags, (int __user *) arg); - case EXT3_IOC_SETFLAGS: { + case EXT4_IOC_SETFLAGS: { handle_t *handle = NULL; int err; - struct ext3_iloc iloc; + struct ext4_iloc iloc; unsigned int oldflags; unsigned int jflag; @@ -47,13 +47,13 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, return -EFAULT; if (!S_ISDIR(inode->i_mode)) - flags &= ~EXT3_DIRSYNC_FL; + flags &= ~EXT4_DIRSYNC_FL; mutex_lock(&inode->i_mutex); oldflags = ei->i_flags; /* The JOURNAL_DATA flag is modifiable only by root */ - jflag = flags & EXT3_JOURNAL_DATA_FL; + jflag = flags & EXT4_JOURNAL_DATA_FL; /* * The IMMUTABLE and APPEND_ONLY flags can only be changed by @@ -61,7 +61,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, * * This test looks nicer. Thanks to Pauline Middelink */ - if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { + if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { if (!capable(CAP_LINUX_IMMUTABLE)) { mutex_unlock(&inode->i_mutex); return -EPERM; @@ -72,7 +72,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, * The JOURNAL_DATA flag can only be changed by * the relevant capability. */ - if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { if (!capable(CAP_SYS_RESOURCE)) { mutex_unlock(&inode->i_mutex); return -EPERM; @@ -80,44 +80,44 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, } - handle = ext3_journal_start(inode, 1); + handle = ext4_journal_start(inode, 1); if (IS_ERR(handle)) { mutex_unlock(&inode->i_mutex); return PTR_ERR(handle); } if (IS_SYNC(inode)) handle->h_sync = 1; - err = ext3_reserve_inode_write(handle, inode, &iloc); + err = ext4_reserve_inode_write(handle, inode, &iloc); if (err) goto flags_err; - flags = flags & EXT3_FL_USER_MODIFIABLE; - flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE; + flags = flags & EXT4_FL_USER_MODIFIABLE; + flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE; ei->i_flags = flags; - ext3_set_inode_flags(inode); + ext4_set_inode_flags(inode); inode->i_ctime = CURRENT_TIME_SEC; - err = ext3_mark_iloc_dirty(handle, inode, &iloc); + err = ext4_mark_iloc_dirty(handle, inode, &iloc); flags_err: - ext3_journal_stop(handle); + ext4_journal_stop(handle); if (err) { mutex_unlock(&inode->i_mutex); return err; } - if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) - err = ext3_change_inode_journal_flag(inode, jflag); + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) + err = ext4_change_inode_journal_flag(inode, jflag); mutex_unlock(&inode->i_mutex); return err; } - case EXT3_IOC_GETVERSION: - case EXT3_IOC_GETVERSION_OLD: + case EXT4_IOC_GETVERSION: + case EXT4_IOC_GETVERSION_OLD: return put_user(inode->i_generation, (int __user *) arg); - case EXT3_IOC_SETVERSION: - case EXT3_IOC_SETVERSION_OLD: { + case EXT4_IOC_SETVERSION: + case EXT4_IOC_SETVERSION_OLD: { handle_t *handle; - struct ext3_iloc iloc; + struct ext4_iloc iloc; __u32 generation; int err; @@ -128,20 +128,20 @@ flags_err: if (get_user(generation, (int __user *) arg)) return -EFAULT; - handle = ext3_journal_start(inode, 1); + handle = ext4_journal_start(inode, 1); if (IS_ERR(handle)) return PTR_ERR(handle); - err = ext3_reserve_inode_write(handle, inode, &iloc); + err = ext4_reserve_inode_write(handle, inode, &iloc); if (err == 0) { inode->i_ctime = CURRENT_TIME_SEC; inode->i_generation = generation; - err = ext3_mark_iloc_dirty(handle, inode, &iloc); + err = ext4_mark_iloc_dirty(handle, inode, &iloc); } - ext3_journal_stop(handle); + ext4_journal_stop(handle); return err; } #ifdef CONFIG_JBD_DEBUG - case EXT3_IOC_WAIT_FOR_READONLY: + case EXT4_IOC_WAIT_FOR_READONLY: /* * This is racy - by the time we're woken up and running, * the superblock could be released. And the module could @@ -155,16 +155,16 @@ flags_err: int ret = 0; set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait); - if (timer_pending(&EXT3_SB(sb)->turn_ro_timer)) { + add_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); + if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) { schedule(); ret = 1; } - remove_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait); + remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); return ret; } #endif - case EXT3_IOC_GETRSVSZ: + case EXT4_IOC_GETRSVSZ: if (test_opt(inode->i_sb, RESERVATION) && S_ISREG(inode->i_mode) && ei->i_block_alloc_info) { @@ -172,7 +172,7 @@ flags_err: return put_user(rsv_window_size, (int __user *)arg); } return -ENOTTY; - case EXT3_IOC_SETRSVSZ: { + case EXT4_IOC_SETRSVSZ: { if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) return -ENOTTY; @@ -186,8 +186,8 @@ flags_err: if (get_user(rsv_window_size, (int __user *)arg)) return -EFAULT; - if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) - rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; + if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS) + rsv_window_size = EXT4_MAX_RESERVE_BLOCKS; /* * need to allocate reservation structure for this inode @@ -195,17 +195,17 @@ flags_err: */ mutex_lock(&ei->truncate_mutex); if (!ei->i_block_alloc_info) - ext3_init_block_alloc_info(inode); + ext4_init_block_alloc_info(inode); if (ei->i_block_alloc_info){ - struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; + struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; rsv->rsv_goal_size = rsv_window_size; } mutex_unlock(&ei->truncate_mutex); return 0; } - case EXT3_IOC_GROUP_EXTEND: { - ext3_fsblk_t n_blocks_count; + case EXT4_IOC_GROUP_EXTEND: { + ext4_fsblk_t n_blocks_count; struct super_block *sb = inode->i_sb; int err; @@ -218,15 +218,15 @@ flags_err: if (get_user(n_blocks_count, (__u32 __user *)arg)) return -EFAULT; - err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count); - journal_lock_updates(EXT3_SB(sb)->s_journal); - journal_flush(EXT3_SB(sb)->s_journal); - journal_unlock_updates(EXT3_SB(sb)->s_journal); + err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); + journal_lock_updates(EXT4_SB(sb)->s_journal); + journal_flush(EXT4_SB(sb)->s_journal); + journal_unlock_updates(EXT4_SB(sb)->s_journal); return err; } - case EXT3_IOC_GROUP_ADD: { - struct ext3_new_group_data input; + case EXT4_IOC_GROUP_ADD: { + struct ext4_new_group_data input; struct super_block *sb = inode->i_sb; int err; @@ -236,14 +236,14 @@ flags_err: if (IS_RDONLY(inode)) return -EROFS; - if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg, + if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, sizeof(input))) return -EFAULT; - err = ext3_group_add(sb, &input); - journal_lock_updates(EXT3_SB(sb)->s_journal); - journal_flush(EXT3_SB(sb)->s_journal); - journal_unlock_updates(EXT3_SB(sb)->s_journal); + err = ext4_group_add(sb, &input); + journal_lock_updates(EXT4_SB(sb)->s_journal); + journal_flush(EXT4_SB(sb)->s_journal); + journal_unlock_updates(EXT4_SB(sb)->s_journal); return err; } @@ -255,52 +255,52 @@ flags_err: } #ifdef CONFIG_COMPAT -long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct inode *inode = file->f_dentry->d_inode; int ret; /* These are just misnamed, they actually get/put from/to user an int */ switch (cmd) { - case EXT3_IOC32_GETFLAGS: - cmd = EXT3_IOC_GETFLAGS; + case EXT4_IOC32_GETFLAGS: + cmd = EXT4_IOC_GETFLAGS; break; - case EXT3_IOC32_SETFLAGS: - cmd = EXT3_IOC_SETFLAGS; + case EXT4_IOC32_SETFLAGS: + cmd = EXT4_IOC_SETFLAGS; break; - case EXT3_IOC32_GETVERSION: - cmd = EXT3_IOC_GETVERSION; + case EXT4_IOC32_GETVERSION: + cmd = EXT4_IOC_GETVERSION; break; - case EXT3_IOC32_SETVERSION: - cmd = EXT3_IOC_SETVERSION; + case EXT4_IOC32_SETVERSION: + cmd = EXT4_IOC_SETVERSION; break; - case EXT3_IOC32_GROUP_EXTEND: - cmd = EXT3_IOC_GROUP_EXTEND; + case EXT4_IOC32_GROUP_EXTEND: + cmd = EXT4_IOC_GROUP_EXTEND; break; - case EXT3_IOC32_GETVERSION_OLD: - cmd = EXT3_IOC_GETVERSION_OLD; + case EXT4_IOC32_GETVERSION_OLD: + cmd = EXT4_IOC_GETVERSION_OLD; break; - case EXT3_IOC32_SETVERSION_OLD: - cmd = EXT3_IOC_SETVERSION_OLD; + case EXT4_IOC32_SETVERSION_OLD: + cmd = EXT4_IOC_SETVERSION_OLD; break; #ifdef CONFIG_JBD_DEBUG - case EXT3_IOC32_WAIT_FOR_READONLY: - cmd = EXT3_IOC_WAIT_FOR_READONLY; + case EXT4_IOC32_WAIT_FOR_READONLY: + cmd = EXT4_IOC_WAIT_FOR_READONLY; break; #endif - case EXT3_IOC32_GETRSVSZ: - cmd = EXT3_IOC_GETRSVSZ; + case EXT4_IOC32_GETRSVSZ: + cmd = EXT4_IOC_GETRSVSZ; break; - case EXT3_IOC32_SETRSVSZ: - cmd = EXT3_IOC_SETRSVSZ; + case EXT4_IOC32_SETRSVSZ: + cmd = EXT4_IOC_SETRSVSZ; break; - case EXT3_IOC_GROUP_ADD: + case EXT4_IOC_GROUP_ADD: break; default: return -ENOIOCTLCMD; } lock_kernel(); - ret = ext3_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); + ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); unlock_kernel(); return ret; } diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 906731a20f1a..956b38113f62 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/namei.c + * linux/fs/ext4/namei.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -28,8 +28,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -50,7 +50,7 @@ #define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) #define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) -static struct buffer_head *ext3_append(handle_t *handle, +static struct buffer_head *ext4_append(handle_t *handle, struct inode *inode, u32 *block, int *err) { @@ -58,10 +58,10 @@ static struct buffer_head *ext3_append(handle_t *handle, *block = inode->i_size >> inode->i_sb->s_blocksize_bits; - if ((bh = ext3_bread(handle, inode, *block, 1, err))) { + if ((bh = ext4_bread(handle, inode, *block, 1, err))) { inode->i_size += inode->i_sb->s_blocksize; - EXT3_I(inode)->i_disksize = inode->i_size; - ext3_journal_get_write_access(handle,bh); + EXT4_I(inode)->i_disksize = inode->i_size; + ext4_journal_get_write_access(handle,bh); } return bh; } @@ -144,7 +144,7 @@ struct dx_map_entry u32 offs; }; -#ifdef CONFIG_EXT3_INDEX +#ifdef CONFIG_EXT4_INDEX static inline unsigned dx_get_block (struct dx_entry *entry); static void dx_set_block (struct dx_entry *entry, unsigned value); static inline unsigned dx_get_hash (struct dx_entry *entry); @@ -161,20 +161,20 @@ static struct dx_frame *dx_probe(struct dentry *dentry, struct dx_frame *frame, int *err); static void dx_release (struct dx_frame *frames); -static int dx_make_map (struct ext3_dir_entry_2 *de, int size, +static int dx_make_map (struct ext4_dir_entry_2 *de, int size, struct dx_hash_info *hinfo, struct dx_map_entry map[]); static void dx_sort_map(struct dx_map_entry *map, unsigned count); -static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to, +static struct ext4_dir_entry_2 *dx_move_dirents (char *from, char *to, struct dx_map_entry *offsets, int count); -static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size); +static struct ext4_dir_entry_2* dx_pack_dirents (char *base, int size); static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block); -static int ext3_htree_next_block(struct inode *dir, __u32 hash, +static int ext4_htree_next_block(struct inode *dir, __u32 hash, struct dx_frame *frame, struct dx_frame *frames, __u32 *start_hash); -static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, - struct ext3_dir_entry_2 **res_dir, int *err); -static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, +static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, + struct ext4_dir_entry_2 **res_dir, int *err); +static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, struct inode *inode); /* @@ -224,14 +224,14 @@ static inline void dx_set_limit (struct dx_entry *entries, unsigned value) static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize) { - unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1) - - EXT3_DIR_REC_LEN(2) - infosize; + unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) - + EXT4_DIR_REC_LEN(2) - infosize; return 0? 20: entry_space / sizeof(struct dx_entry); } static inline unsigned dx_node_limit (struct inode *dir) { - unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0); + unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0); return 0? 22: entry_space / sizeof(struct dx_entry); } @@ -257,7 +257,7 @@ struct stats unsigned bcount; }; -static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_entry_2 *de, +static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_entry_2 *de, int size, int show_names) { unsigned names = 0, space = 0; @@ -274,14 +274,14 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_ent int len = de->name_len; char *name = de->name; while (len--) printk("%c", *name++); - ext3fs_dirhash(de->name, de->name_len, &h); + ext4fs_dirhash(de->name, de->name_len, &h); printk(":%x.%u ", h.hash, ((char *) de - base)); } - space += EXT3_DIR_REC_LEN(de->name_len); + space += EXT4_DIR_REC_LEN(de->name_len); names++; } - de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); + de = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); } printk("(%i)\n", names); return (struct stats) { names, space, 1 }; @@ -302,10 +302,10 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir, u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash; struct stats stats; printk("%s%3u:%03u hash %8x/%8x ",levels?"":" ", i, block, hash, range); - if (!(bh = ext3_bread (NULL,dir, block, 0,&err))) continue; + if (!(bh = ext4_bread (NULL,dir, block, 0,&err))) continue; stats = levels? dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1): - dx_show_leaf(hinfo, (struct ext3_dir_entry_2 *) bh->b_data, blocksize, 0); + dx_show_leaf(hinfo, (struct ext4_dir_entry_2 *) bh->b_data, blocksize, 0); names += stats.names; space += stats.space; bcount += stats.bcount; @@ -341,13 +341,13 @@ dx_probe(struct dentry *dentry, struct inode *dir, frame->bh = NULL; if (dentry) dir = dentry->d_parent->d_inode; - if (!(bh = ext3_bread (NULL,dir, 0, 0, err))) + if (!(bh = ext4_bread (NULL,dir, 0, 0, err))) goto fail; root = (struct dx_root *) bh->b_data; if (root->info.hash_version != DX_HASH_TEA && root->info.hash_version != DX_HASH_HALF_MD4 && root->info.hash_version != DX_HASH_LEGACY) { - ext3_warning(dir->i_sb, __FUNCTION__, + ext4_warning(dir->i_sb, __FUNCTION__, "Unrecognised inode hash code %d", root->info.hash_version); brelse(bh); @@ -355,13 +355,13 @@ dx_probe(struct dentry *dentry, struct inode *dir, goto fail; } hinfo->hash_version = root->info.hash_version; - hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed; + hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; if (dentry) - ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo); + ext4fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo); hash = hinfo->hash; if (root->info.unused_flags & 1) { - ext3_warning(dir->i_sb, __FUNCTION__, + ext4_warning(dir->i_sb, __FUNCTION__, "Unimplemented inode hash flags: %#06x", root->info.unused_flags); brelse(bh); @@ -370,7 +370,7 @@ dx_probe(struct dentry *dentry, struct inode *dir, } if ((indirect = root->info.indirect_levels) > 1) { - ext3_warning(dir->i_sb, __FUNCTION__, + ext4_warning(dir->i_sb, __FUNCTION__, "Unimplemented inode hash depth: %#06x", root->info.indirect_levels); brelse(bh); @@ -421,7 +421,7 @@ dx_probe(struct dentry *dentry, struct inode *dir, frame->entries = entries; frame->at = at; if (!indirect--) return frame; - if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err))) + if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err))) goto fail2; at = entries = ((struct dx_node *) bh->b_data)->entries; assert (dx_get_limit(entries) == dx_node_limit (dir)); @@ -463,7 +463,7 @@ static void dx_release (struct dx_frame *frames) * If start_hash is non-null, it will be filled in with the starting * hash of the next page. */ -static int ext3_htree_next_block(struct inode *dir, __u32 hash, +static int ext4_htree_next_block(struct inode *dir, __u32 hash, struct dx_frame *frame, struct dx_frame *frames, __u32 *start_hash) @@ -509,7 +509,7 @@ static int ext3_htree_next_block(struct inode *dir, __u32 hash, * block so no check is necessary */ while (num_frames--) { - if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at), + if (!(bh = ext4_bread(NULL, dir, dx_get_block(p->at), 0, &err))) return err; /* Failure */ p++; @@ -524,9 +524,9 @@ static int ext3_htree_next_block(struct inode *dir, __u32 hash, /* * p is at least 6 bytes before the end of page */ -static inline struct ext3_dir_entry_2 *ext3_next_entry(struct ext3_dir_entry_2 *p) +static inline struct ext4_dir_entry_2 *ext4_next_entry(struct ext4_dir_entry_2 *p) { - return (struct ext3_dir_entry_2 *)((char*)p + le16_to_cpu(p->rec_len)); + return (struct ext4_dir_entry_2 *)((char*)p + le16_to_cpu(p->rec_len)); } /* @@ -540,26 +540,26 @@ static int htree_dirblock_to_tree(struct file *dir_file, __u32 start_hash, __u32 start_minor_hash) { struct buffer_head *bh; - struct ext3_dir_entry_2 *de, *top; + struct ext4_dir_entry_2 *de, *top; int err, count = 0; dxtrace(printk("In htree dirblock_to_tree: block %d\n", block)); - if (!(bh = ext3_bread (NULL, dir, block, 0, &err))) + if (!(bh = ext4_bread (NULL, dir, block, 0, &err))) return err; - de = (struct ext3_dir_entry_2 *) bh->b_data; - top = (struct ext3_dir_entry_2 *) ((char *) de + + de = (struct ext4_dir_entry_2 *) bh->b_data; + top = (struct ext4_dir_entry_2 *) ((char *) de + dir->i_sb->s_blocksize - - EXT3_DIR_REC_LEN(0)); - for (; de < top; de = ext3_next_entry(de)) { - ext3fs_dirhash(de->name, de->name_len, hinfo); + EXT4_DIR_REC_LEN(0)); + for (; de < top; de = ext4_next_entry(de)) { + ext4fs_dirhash(de->name, de->name_len, hinfo); if ((hinfo->hash < start_hash) || ((hinfo->hash == start_hash) && (hinfo->minor_hash < start_minor_hash))) continue; if (de->inode == 0) continue; - if ((err = ext3_htree_store_dirent(dir_file, + if ((err = ext4_htree_store_dirent(dir_file, hinfo->hash, hinfo->minor_hash, de)) != 0) { brelse(bh); return err; @@ -579,11 +579,11 @@ static int htree_dirblock_to_tree(struct file *dir_file, * This function returns the number of entries inserted into the tree, * or a negative error code. */ -int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, +int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, __u32 start_minor_hash, __u32 *next_hash) { struct dx_hash_info hinfo; - struct ext3_dir_entry_2 *de; + struct ext4_dir_entry_2 *de; struct dx_frame frames[2], *frame; struct inode *dir; int block, err; @@ -594,9 +594,9 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash, start_minor_hash)); dir = dir_file->f_dentry->d_inode; - if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) { - hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; - hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed; + if (!(EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) { + hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version; + hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo, start_hash, start_minor_hash); *next_hash = ~0; @@ -610,15 +610,15 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, /* Add '.' and '..' from the htree header */ if (!start_hash && !start_minor_hash) { - de = (struct ext3_dir_entry_2 *) frames[0].bh->b_data; - if ((err = ext3_htree_store_dirent(dir_file, 0, 0, de)) != 0) + de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data; + if ((err = ext4_htree_store_dirent(dir_file, 0, 0, de)) != 0) goto errout; count++; } if (start_hash < 2 || (start_hash ==2 && start_minor_hash==0)) { - de = (struct ext3_dir_entry_2 *) frames[0].bh->b_data; - de = ext3_next_entry(de); - if ((err = ext3_htree_store_dirent(dir_file, 2, 0, de)) != 0) + de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data; + de = ext4_next_entry(de); + if ((err = ext4_htree_store_dirent(dir_file, 2, 0, de)) != 0) goto errout; count++; } @@ -633,7 +633,7 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, } count += ret; hashval = ~0; - ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS, + ret = ext4_htree_next_block(dir, HASH_NB_ALWAYS, frame, frames, &hashval); *next_hash = hashval; if (ret < 0) { @@ -663,7 +663,7 @@ errout: * Directory block splitting, compacting */ -static int dx_make_map (struct ext3_dir_entry_2 *de, int size, +static int dx_make_map (struct ext4_dir_entry_2 *de, int size, struct dx_hash_info *hinfo, struct dx_map_entry *map_tail) { int count = 0; @@ -673,7 +673,7 @@ static int dx_make_map (struct ext3_dir_entry_2 *de, int size, while ((char *) de < base + size) { if (de->name_len && de->inode) { - ext3fs_dirhash(de->name, de->name_len, &h); + ext4fs_dirhash(de->name, de->name_len, &h); map_tail--; map_tail->hash = h.hash; map_tail->offs = (u32) ((char *) de - base); @@ -681,7 +681,7 @@ static int dx_make_map (struct ext3_dir_entry_2 *de, int size, cond_resched(); } /* XXX: do we need to check rec_len == 0 case? -Chris */ - de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); + de = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); } return count; } @@ -730,21 +730,21 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block) #endif -static void ext3_update_dx_flag(struct inode *inode) +static void ext4_update_dx_flag(struct inode *inode) { - if (!EXT3_HAS_COMPAT_FEATURE(inode->i_sb, - EXT3_FEATURE_COMPAT_DIR_INDEX)) - EXT3_I(inode)->i_flags &= ~EXT3_INDEX_FL; + if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb, + EXT4_FEATURE_COMPAT_DIR_INDEX)) + EXT4_I(inode)->i_flags &= ~EXT4_INDEX_FL; } /* - * NOTE! unlike strncmp, ext3_match returns 1 for success, 0 for failure. + * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure. * - * `len <= EXT3_NAME_LEN' is guaranteed by caller. + * `len <= EXT4_NAME_LEN' is guaranteed by caller. * `de != NULL' is guaranteed by caller. */ -static inline int ext3_match (int len, const char * const name, - struct ext3_dir_entry_2 * de) +static inline int ext4_match (int len, const char * const name, + struct ext4_dir_entry_2 * de) { if (len != de->name_len) return 0; @@ -760,24 +760,24 @@ static inline int search_dirblock(struct buffer_head * bh, struct inode *dir, struct dentry *dentry, unsigned long offset, - struct ext3_dir_entry_2 ** res_dir) + struct ext4_dir_entry_2 ** res_dir) { - struct ext3_dir_entry_2 * de; + struct ext4_dir_entry_2 * de; char * dlimit; int de_len; const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; - de = (struct ext3_dir_entry_2 *) bh->b_data; + de = (struct ext4_dir_entry_2 *) bh->b_data; dlimit = bh->b_data + dir->i_sb->s_blocksize; while ((char *) de < dlimit) { /* this code is executed quadratically often */ /* do minimal checking `by hand' */ if ((char *) de + namelen <= dlimit && - ext3_match (namelen, name, de)) { + ext4_match (namelen, name, de)) { /* found a match - just to be sure, do a full check */ - if (!ext3_check_dir_entry("ext3_find_entry", + if (!ext4_check_dir_entry("ext4_find_entry", dir, de, bh, offset)) return -1; *res_dir = de; @@ -788,14 +788,14 @@ static inline int search_dirblock(struct buffer_head * bh, if (de_len <= 0) return -1; offset += de_len; - de = (struct ext3_dir_entry_2 *) ((char *) de + de_len); + de = (struct ext4_dir_entry_2 *) ((char *) de + de_len); } return 0; } /* - * ext3_find_entry() + * ext4_find_entry() * * finds an entry in the specified directory with the wanted name. It * returns the cache buffer in which the entry was found, and the entry @@ -805,8 +805,8 @@ static inline int search_dirblock(struct buffer_head * bh, * The returned buffer_head has ->b_count elevated. The caller is expected * to brelse() it when appropriate. */ -static struct buffer_head * ext3_find_entry (struct dentry *dentry, - struct ext3_dir_entry_2 ** res_dir) +static struct buffer_head * ext4_find_entry (struct dentry *dentry, + struct ext4_dir_entry_2 ** res_dir) { struct super_block * sb; struct buffer_head * bh_use[NAMEI_RA_SIZE]; @@ -828,11 +828,11 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry, blocksize = sb->s_blocksize; namelen = dentry->d_name.len; name = dentry->d_name.name; - if (namelen > EXT3_NAME_LEN) + if (namelen > EXT4_NAME_LEN) return NULL; -#ifdef CONFIG_EXT3_INDEX +#ifdef CONFIG_EXT4_INDEX if (is_dx(dir)) { - bh = ext3_dx_find_entry(dentry, res_dir, &err); + bh = ext4_dx_find_entry(dentry, res_dir, &err); /* * On success, or if the error was file not found, * return. Otherwise, fall back to doing a search the @@ -840,11 +840,11 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry, */ if (bh || (err != ERR_BAD_DX_DIR)) return bh; - dxtrace(printk("ext3_find_entry: dx failed, falling back\n")); + dxtrace(printk("ext4_find_entry: dx failed, falling back\n")); } #endif - nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb); - start = EXT3_I(dir)->i_dir_start_lookup; + nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); + start = EXT4_I(dir)->i_dir_start_lookup; if (start >= nblocks) start = 0; block = start; @@ -868,7 +868,7 @@ restart: break; } num++; - bh = ext3_getblk(NULL, dir, b++, 0, &err); + bh = ext4_getblk(NULL, dir, b++, 0, &err); bh_use[ra_max] = bh; if (bh) ll_rw_block(READ_META, 1, &bh); @@ -879,15 +879,15 @@ restart: wait_on_buffer(bh); if (!buffer_uptodate(bh)) { /* read error, skip block & hope for the best */ - ext3_error(sb, __FUNCTION__, "reading directory #%lu " + ext4_error(sb, __FUNCTION__, "reading directory #%lu " "offset %lu", dir->i_ino, block); brelse(bh); goto next; } i = search_dirblock(bh, dir, dentry, - block << EXT3_BLOCK_SIZE_BITS(sb), res_dir); + block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); if (i == 1) { - EXT3_I(dir)->i_dir_start_lookup = block; + EXT4_I(dir)->i_dir_start_lookup = block; ret = bh; goto cleanup_and_exit; } else { @@ -905,7 +905,7 @@ restart: * search the last part of the directory before giving up. */ block = nblocks; - nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb); + nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); if (block < nblocks) { start = 0; goto restart; @@ -918,15 +918,15 @@ cleanup_and_exit: return ret; } -#ifdef CONFIG_EXT3_INDEX -static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, - struct ext3_dir_entry_2 **res_dir, int *err) +#ifdef CONFIG_EXT4_INDEX +static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, + struct ext4_dir_entry_2 **res_dir, int *err) { struct super_block * sb; struct dx_hash_info hinfo; u32 hash; struct dx_frame frames[2], *frame; - struct ext3_dir_entry_2 *de, *top; + struct ext4_dir_entry_2 *de, *top; struct buffer_head *bh; unsigned long block; int retval; @@ -948,16 +948,16 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, hash = hinfo.hash; do { block = dx_get_block(frame->at); - if (!(bh = ext3_bread (NULL,dir, block, 0, err))) + if (!(bh = ext4_bread (NULL,dir, block, 0, err))) goto errout; - de = (struct ext3_dir_entry_2 *) bh->b_data; - top = (struct ext3_dir_entry_2 *) ((char *) de + sb->s_blocksize - - EXT3_DIR_REC_LEN(0)); - for (; de < top; de = ext3_next_entry(de)) - if (ext3_match (namelen, name, de)) { - if (!ext3_check_dir_entry("ext3_find_entry", + de = (struct ext4_dir_entry_2 *) bh->b_data; + top = (struct ext4_dir_entry_2 *) ((char *) de + sb->s_blocksize - + EXT4_DIR_REC_LEN(0)); + for (; de < top; de = ext4_next_entry(de)) + if (ext4_match (namelen, name, de)) { + if (!ext4_check_dir_entry("ext4_find_entry", dir, de, bh, - (block<b_data))) { brelse (bh); goto errout; @@ -968,10 +968,10 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, } brelse (bh); /* Check to see if we should continue to search */ - retval = ext3_htree_next_block(dir, hash, frame, + retval = ext4_htree_next_block(dir, hash, frame, frames, NULL); if (retval < 0) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "error reading index page in directory #%lu", dir->i_ino); *err = retval; @@ -987,22 +987,22 @@ errout: } #endif -static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) +static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode; - struct ext3_dir_entry_2 * de; + struct ext4_dir_entry_2 * de; struct buffer_head * bh; - if (dentry->d_name.len > EXT3_NAME_LEN) + if (dentry->d_name.len > EXT4_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); - bh = ext3_find_entry(dentry, &de); + bh = ext4_find_entry(dentry, &de); inode = NULL; if (bh) { unsigned long ino = le32_to_cpu(de->inode); brelse (bh); - if (!ext3_valid_inum(dir->i_sb, ino)) { - ext3_error(dir->i_sb, "ext3_lookup", + if (!ext4_valid_inum(dir->i_sb, ino)) { + ext4_error(dir->i_sb, "ext4_lookup", "bad inode number: %lu", ino); inode = NULL; } else @@ -1015,28 +1015,28 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str } -struct dentry *ext3_get_parent(struct dentry *child) +struct dentry *ext4_get_parent(struct dentry *child) { unsigned long ino; struct dentry *parent; struct inode *inode; struct dentry dotdot; - struct ext3_dir_entry_2 * de; + struct ext4_dir_entry_2 * de; struct buffer_head *bh; dotdot.d_name.name = ".."; dotdot.d_name.len = 2; dotdot.d_parent = child; /* confusing, isn't it! */ - bh = ext3_find_entry(&dotdot, &de); + bh = ext4_find_entry(&dotdot, &de); inode = NULL; if (!bh) return ERR_PTR(-ENOENT); ino = le32_to_cpu(de->inode); brelse(bh); - if (!ext3_valid_inum(child->d_inode->i_sb, ino)) { - ext3_error(child->d_inode->i_sb, "ext3_get_parent", + if (!ext4_valid_inum(child->d_inode->i_sb, ino)) { + ext4_error(child->d_inode->i_sb, "ext4_get_parent", "bad inode number: %lu", ino); inode = NULL; } else @@ -1054,65 +1054,65 @@ struct dentry *ext3_get_parent(struct dentry *child) } #define S_SHIFT 12 -static unsigned char ext3_type_by_mode[S_IFMT >> S_SHIFT] = { - [S_IFREG >> S_SHIFT] = EXT3_FT_REG_FILE, - [S_IFDIR >> S_SHIFT] = EXT3_FT_DIR, - [S_IFCHR >> S_SHIFT] = EXT3_FT_CHRDEV, - [S_IFBLK >> S_SHIFT] = EXT3_FT_BLKDEV, - [S_IFIFO >> S_SHIFT] = EXT3_FT_FIFO, - [S_IFSOCK >> S_SHIFT] = EXT3_FT_SOCK, - [S_IFLNK >> S_SHIFT] = EXT3_FT_SYMLINK, +static unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = { + [S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE, + [S_IFDIR >> S_SHIFT] = EXT4_FT_DIR, + [S_IFCHR >> S_SHIFT] = EXT4_FT_CHRDEV, + [S_IFBLK >> S_SHIFT] = EXT4_FT_BLKDEV, + [S_IFIFO >> S_SHIFT] = EXT4_FT_FIFO, + [S_IFSOCK >> S_SHIFT] = EXT4_FT_SOCK, + [S_IFLNK >> S_SHIFT] = EXT4_FT_SYMLINK, }; -static inline void ext3_set_de_type(struct super_block *sb, - struct ext3_dir_entry_2 *de, +static inline void ext4_set_de_type(struct super_block *sb, + struct ext4_dir_entry_2 *de, umode_t mode) { - if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) - de->file_type = ext3_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE)) + de->file_type = ext4_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; } -#ifdef CONFIG_EXT3_INDEX -static struct ext3_dir_entry_2 * +#ifdef CONFIG_EXT4_INDEX +static struct ext4_dir_entry_2 * dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count) { unsigned rec_len = 0; while (count--) { - struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) (from + map->offs); - rec_len = EXT3_DIR_REC_LEN(de->name_len); + struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) (from + map->offs); + rec_len = EXT4_DIR_REC_LEN(de->name_len); memcpy (to, de, rec_len); - ((struct ext3_dir_entry_2 *) to)->rec_len = + ((struct ext4_dir_entry_2 *) to)->rec_len = cpu_to_le16(rec_len); de->inode = 0; map++; to += rec_len; } - return (struct ext3_dir_entry_2 *) (to - rec_len); + return (struct ext4_dir_entry_2 *) (to - rec_len); } -static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size) +static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size) { - struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base; + struct ext4_dir_entry_2 *next, *to, *prev, *de = (struct ext4_dir_entry_2 *) base; unsigned rec_len = 0; prev = to = de; while ((char*)de < base + size) { - next = (struct ext3_dir_entry_2 *) ((char *) de + + next = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); if (de->inode && de->name_len) { - rec_len = EXT3_DIR_REC_LEN(de->name_len); + rec_len = EXT4_DIR_REC_LEN(de->name_len); if (de > to) memmove(to, de, rec_len); to->rec_len = cpu_to_le16(rec_len); prev = to; - to = (struct ext3_dir_entry_2 *) (((char *) to) + rec_len); + to = (struct ext4_dir_entry_2 *) (((char *) to) + rec_len); } de = next; } return prev; } -static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, +static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, struct buffer_head **bh,struct dx_frame *frame, struct dx_hash_info *hinfo, int *error) { @@ -1124,10 +1124,10 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, struct dx_map_entry *map; char *data1 = (*bh)->b_data, *data2; unsigned split; - struct ext3_dir_entry_2 *de = NULL, *de2; + struct ext4_dir_entry_2 *de = NULL, *de2; int err; - bh2 = ext3_append (handle, dir, &newblock, error); + bh2 = ext4_append (handle, dir, &newblock, error); if (!(bh2)) { brelse(*bh); *bh = NULL; @@ -1135,17 +1135,17 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, } BUFFER_TRACE(*bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, *bh); + err = ext4_journal_get_write_access(handle, *bh); if (err) { journal_error: brelse(*bh); brelse(bh2); *bh = NULL; - ext3_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); goto errout; } BUFFER_TRACE(frame->bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, frame->bh); + err = ext4_journal_get_write_access(handle, frame->bh); if (err) goto journal_error; @@ -1153,7 +1153,7 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, /* create map in the end of data2 block */ map = (struct dx_map_entry *) (data2 + blocksize); - count = dx_make_map ((struct ext3_dir_entry_2 *) data1, + count = dx_make_map ((struct ext4_dir_entry_2 *) data1, blocksize, hinfo, map); map -= count; split = count/2; // need to adjust to actual middle @@ -1168,8 +1168,8 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, de = dx_pack_dirents(data1,blocksize); de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de); de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2); - dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1)); - dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1)); + dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1)); + dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1)); /* Which block gets the new entry? */ if (hinfo->hash >= hash2) @@ -1178,10 +1178,10 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, de = de2; } dx_insert_block (frame, hash2 + continued, newblock); - err = ext3_journal_dirty_metadata (handle, bh2); + err = ext4_journal_dirty_metadata (handle, bh2); if (err) goto journal_error; - err = ext3_journal_dirty_metadata (handle, frame->bh); + err = ext4_journal_dirty_metadata (handle, frame->bh); if (err) goto journal_error; brelse (bh2); @@ -1204,7 +1204,7 @@ errout: * all other cases bh is released. */ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, - struct inode *inode, struct ext3_dir_entry_2 *de, + struct inode *inode, struct ext4_dir_entry_2 *de, struct buffer_head * bh) { struct inode *dir = dentry->d_parent->d_inode; @@ -1215,51 +1215,51 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, int nlen, rlen, err; char *top; - reclen = EXT3_DIR_REC_LEN(namelen); + reclen = EXT4_DIR_REC_LEN(namelen); if (!de) { - de = (struct ext3_dir_entry_2 *)bh->b_data; + de = (struct ext4_dir_entry_2 *)bh->b_data; top = bh->b_data + dir->i_sb->s_blocksize - reclen; while ((char *) de <= top) { - if (!ext3_check_dir_entry("ext3_add_entry", dir, de, + if (!ext4_check_dir_entry("ext4_add_entry", dir, de, bh, offset)) { brelse (bh); return -EIO; } - if (ext3_match (namelen, name, de)) { + if (ext4_match (namelen, name, de)) { brelse (bh); return -EEXIST; } - nlen = EXT3_DIR_REC_LEN(de->name_len); + nlen = EXT4_DIR_REC_LEN(de->name_len); rlen = le16_to_cpu(de->rec_len); if ((de->inode? rlen - nlen: rlen) >= reclen) break; - de = (struct ext3_dir_entry_2 *)((char *)de + rlen); + de = (struct ext4_dir_entry_2 *)((char *)de + rlen); offset += rlen; } if ((char *) de > top) return -ENOSPC; } BUFFER_TRACE(bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, bh); + err = ext4_journal_get_write_access(handle, bh); if (err) { - ext3_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); brelse(bh); return err; } /* By now the buffer is marked for journaling */ - nlen = EXT3_DIR_REC_LEN(de->name_len); + nlen = EXT4_DIR_REC_LEN(de->name_len); rlen = le16_to_cpu(de->rec_len); if (de->inode) { - struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen); + struct ext4_dir_entry_2 *de1 = (struct ext4_dir_entry_2 *)((char *)de + nlen); de1->rec_len = cpu_to_le16(rlen - nlen); de->rec_len = cpu_to_le16(nlen); de = de1; } - de->file_type = EXT3_FT_UNKNOWN; + de->file_type = EXT4_FT_UNKNOWN; if (inode) { de->inode = cpu_to_le32(inode->i_ino); - ext3_set_de_type(dir->i_sb, de, inode->i_mode); + ext4_set_de_type(dir->i_sb, de, inode->i_mode); } else de->inode = 0; de->name_len = namelen; @@ -1270,24 +1270,24 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, * on this. * * XXX similarly, too many callers depend on - * ext3_new_inode() setting the times, but error + * ext4_new_inode() setting the times, but error * recovery deletes the inode, so the worst that can * happen is that the times are slightly out of date * and/or different from the directory change time. */ dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; - ext3_update_dx_flag(dir); + ext4_update_dx_flag(dir); dir->i_version++; - ext3_mark_inode_dirty(handle, dir); - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh); + ext4_mark_inode_dirty(handle, dir); + BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, bh); if (err) - ext3_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); brelse(bh); return 0; } -#ifdef CONFIG_EXT3_INDEX +#ifdef CONFIG_EXT4_INDEX /* * This converts a one block unindexed directory to a 3 block indexed * directory, and adds the dentry to the indexed directory. @@ -1302,7 +1302,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, struct dx_root *root; struct dx_frame frames[2], *frame; struct dx_entry *entries; - struct ext3_dir_entry_2 *de, *de2; + struct ext4_dir_entry_2 *de, *de2; char *data1, *top; unsigned len; int retval; @@ -1313,38 +1313,38 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, blocksize = dir->i_sb->s_blocksize; dxtrace(printk("Creating index\n")); - retval = ext3_journal_get_write_access(handle, bh); + retval = ext4_journal_get_write_access(handle, bh); if (retval) { - ext3_std_error(dir->i_sb, retval); + ext4_std_error(dir->i_sb, retval); brelse(bh); return retval; } root = (struct dx_root *) bh->b_data; - bh2 = ext3_append (handle, dir, &block, &retval); + bh2 = ext4_append (handle, dir, &block, &retval); if (!(bh2)) { brelse(bh); return retval; } - EXT3_I(dir)->i_flags |= EXT3_INDEX_FL; + EXT4_I(dir)->i_flags |= EXT4_INDEX_FL; data1 = bh2->b_data; /* The 0th block becomes the root, move the dirents out */ fde = &root->dotdot; - de = (struct ext3_dir_entry_2 *)((char *)fde + le16_to_cpu(fde->rec_len)); + de = (struct ext4_dir_entry_2 *)((char *)fde + le16_to_cpu(fde->rec_len)); len = ((char *) root) + blocksize - (char *) de; memcpy (data1, de, len); - de = (struct ext3_dir_entry_2 *) data1; + de = (struct ext4_dir_entry_2 *) data1; top = data1 + len; while ((char *)(de2=(void*)de+le16_to_cpu(de->rec_len)) < top) de = de2; de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de); /* Initialize the root; the dot dirents already exist */ - de = (struct ext3_dir_entry_2 *) (&root->dotdot); - de->rec_len = cpu_to_le16(blocksize - EXT3_DIR_REC_LEN(2)); + de = (struct ext4_dir_entry_2 *) (&root->dotdot); + de->rec_len = cpu_to_le16(blocksize - EXT4_DIR_REC_LEN(2)); memset (&root->info, 0, sizeof(root->info)); root->info.info_length = sizeof(root->info); - root->info.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; + root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version; entries = root->entries; dx_set_block (entries, 1); dx_set_count (entries, 1); @@ -1352,8 +1352,8 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, /* Initialize as for dx_probe */ hinfo.hash_version = root->info.hash_version; - hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed; - ext3fs_dirhash(name, namelen, &hinfo); + hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; + ext4fs_dirhash(name, namelen, &hinfo); frame = frames; frame->entries = entries; frame->at = entries; @@ -1369,25 +1369,25 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, #endif /* - * ext3_add_entry() + * ext4_add_entry() * * adds a file entry to the specified directory, using the same - * semantics as ext3_find_entry(). It returns NULL if it failed. + * semantics as ext4_find_entry(). It returns NULL if it failed. * * NOTE!! The inode part of 'de' is left at 0 - which means you * may not sleep between calling this and putting something into * the entry, as someone else might have used it while you slept. */ -static int ext3_add_entry (handle_t *handle, struct dentry *dentry, +static int ext4_add_entry (handle_t *handle, struct dentry *dentry, struct inode *inode) { struct inode *dir = dentry->d_parent->d_inode; unsigned long offset; struct buffer_head * bh; - struct ext3_dir_entry_2 *de; + struct ext4_dir_entry_2 *de; struct super_block * sb; int retval; -#ifdef CONFIG_EXT3_INDEX +#ifdef CONFIG_EXT4_INDEX int dx_fallback=0; #endif unsigned blocksize; @@ -1397,46 +1397,46 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry, blocksize = sb->s_blocksize; if (!dentry->d_name.len) return -EINVAL; -#ifdef CONFIG_EXT3_INDEX +#ifdef CONFIG_EXT4_INDEX if (is_dx(dir)) { - retval = ext3_dx_add_entry(handle, dentry, inode); + retval = ext4_dx_add_entry(handle, dentry, inode); if (!retval || (retval != ERR_BAD_DX_DIR)) return retval; - EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL; + EXT4_I(dir)->i_flags &= ~EXT4_INDEX_FL; dx_fallback++; - ext3_mark_inode_dirty(handle, dir); + ext4_mark_inode_dirty(handle, dir); } #endif blocks = dir->i_size >> sb->s_blocksize_bits; for (block = 0, offset = 0; block < blocks; block++) { - bh = ext3_bread(handle, dir, block, 0, &retval); + bh = ext4_bread(handle, dir, block, 0, &retval); if(!bh) return retval; retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); if (retval != -ENOSPC) return retval; -#ifdef CONFIG_EXT3_INDEX +#ifdef CONFIG_EXT4_INDEX if (blocks == 1 && !dx_fallback && - EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX)) + EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) return make_indexed_dir(handle, dentry, inode, bh); #endif brelse(bh); } - bh = ext3_append(handle, dir, &block, &retval); + bh = ext4_append(handle, dir, &block, &retval); if (!bh) return retval; - de = (struct ext3_dir_entry_2 *) bh->b_data; + de = (struct ext4_dir_entry_2 *) bh->b_data; de->inode = 0; de->rec_len = cpu_to_le16(blocksize); return add_dirent_to_buf(handle, dentry, inode, de, bh); } -#ifdef CONFIG_EXT3_INDEX +#ifdef CONFIG_EXT4_INDEX /* * Returns 0 for success, or a negative error value */ -static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, +static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, struct inode *inode) { struct dx_frame frames[2], *frame; @@ -1445,7 +1445,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, struct buffer_head * bh; struct inode *dir = dentry->d_parent->d_inode; struct super_block * sb = dir->i_sb; - struct ext3_dir_entry_2 *de; + struct ext4_dir_entry_2 *de; int err; frame = dx_probe(dentry, NULL, &hinfo, frames, &err); @@ -1454,11 +1454,11 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, entries = frame->entries; at = frame->at; - if (!(bh = ext3_bread(handle,dir, dx_get_block(frame->at), 0, &err))) + if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err))) goto cleanup; BUFFER_TRACE(bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, bh); + err = ext4_journal_get_write_access(handle, bh); if (err) goto journal_error; @@ -1482,12 +1482,12 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, if (levels && (dx_get_count(frames->entries) == dx_get_limit(frames->entries))) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Directory index full!"); err = -ENOSPC; goto cleanup; } - bh2 = ext3_append (handle, dir, &newblock, &err); + bh2 = ext4_append (handle, dir, &newblock, &err); if (!(bh2)) goto cleanup; node2 = (struct dx_node *)(bh2->b_data); @@ -1495,7 +1495,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, node2->fake.rec_len = cpu_to_le16(sb->s_blocksize); node2->fake.inode = 0; BUFFER_TRACE(frame->bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, frame->bh); + err = ext4_journal_get_write_access(handle, frame->bh); if (err) goto journal_error; if (levels) { @@ -1504,7 +1504,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, dxtrace(printk("Split index %i/%i\n", icount1, icount2)); BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ - err = ext3_journal_get_write_access(handle, + err = ext4_journal_get_write_access(handle, frames[0].bh); if (err) goto journal_error; @@ -1525,7 +1525,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, dxtrace(dx_show_index ("node", frames[1].entries)); dxtrace(dx_show_index ("node", ((struct dx_node *) bh2->b_data)->entries)); - err = ext3_journal_dirty_metadata(handle, bh2); + err = ext4_journal_dirty_metadata(handle, bh2); if (err) goto journal_error; brelse (bh2); @@ -1545,12 +1545,12 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, frame->at = at = at - entries + entries2; frame->entries = entries = entries2; frame->bh = bh2; - err = ext3_journal_get_write_access(handle, + err = ext4_journal_get_write_access(handle, frame->bh); if (err) goto journal_error; } - ext3_journal_dirty_metadata(handle, frames[0].bh); + ext4_journal_dirty_metadata(handle, frames[0].bh); } de = do_split(handle, dir, &bh, frame, &hinfo, &err); if (!de) @@ -1560,7 +1560,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, goto cleanup; journal_error: - ext3_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); cleanup: if (bh) brelse(bh); @@ -1570,26 +1570,26 @@ cleanup: #endif /* - * ext3_delete_entry deletes a directory entry by merging it with the + * ext4_delete_entry deletes a directory entry by merging it with the * previous entry */ -static int ext3_delete_entry (handle_t *handle, +static int ext4_delete_entry (handle_t *handle, struct inode * dir, - struct ext3_dir_entry_2 * de_del, + struct ext4_dir_entry_2 * de_del, struct buffer_head * bh) { - struct ext3_dir_entry_2 * de, * pde; + struct ext4_dir_entry_2 * de, * pde; int i; i = 0; pde = NULL; - de = (struct ext3_dir_entry_2 *) bh->b_data; + de = (struct ext4_dir_entry_2 *) bh->b_data; while (i < bh->b_size) { - if (!ext3_check_dir_entry("ext3_delete_entry", dir, de, bh, i)) + if (!ext4_check_dir_entry("ext4_delete_entry", dir, de, bh, i)) return -EIO; if (de == de_del) { BUFFER_TRACE(bh, "get_write_access"); - ext3_journal_get_write_access(handle, bh); + ext4_journal_get_write_access(handle, bh); if (pde) pde->rec_len = cpu_to_le16(le16_to_cpu(pde->rec_len) + @@ -1597,43 +1597,43 @@ static int ext3_delete_entry (handle_t *handle, else de->inode = 0; dir->i_version++; - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - ext3_journal_dirty_metadata(handle, bh); + BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); + ext4_journal_dirty_metadata(handle, bh); return 0; } i += le16_to_cpu(de->rec_len); pde = de; - de = (struct ext3_dir_entry_2 *) + de = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); } return -ENOENT; } /* - * ext3_mark_inode_dirty is somewhat expensive, so unlike ext2 we + * ext4_mark_inode_dirty is somewhat expensive, so unlike ext2 we * do not perform it in these functions. We perform it at the call site, * if it is needed. */ -static inline void ext3_inc_count(handle_t *handle, struct inode *inode) +static inline void ext4_inc_count(handle_t *handle, struct inode *inode) { inc_nlink(inode); } -static inline void ext3_dec_count(handle_t *handle, struct inode *inode) +static inline void ext4_dec_count(handle_t *handle, struct inode *inode) { drop_nlink(inode); } -static int ext3_add_nondir(handle_t *handle, +static int ext4_add_nondir(handle_t *handle, struct dentry *dentry, struct inode *inode) { - int err = ext3_add_entry(handle, dentry, inode); + int err = ext4_add_entry(handle, dentry, inode); if (!err) { - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); d_instantiate(dentry, inode); return 0; } - ext3_dec_count(handle, inode); + ext4_dec_count(handle, inode); iput(inode); return err; } @@ -1646,7 +1646,7 @@ static int ext3_add_nondir(handle_t *handle, * If the create succeeds, we fill in the inode information * with d_instantiate(). */ -static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, +static int ext4_create (struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd) { handle_t *handle; @@ -1654,30 +1654,30 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, int err, retries = 0; retry: - handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + - 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); + handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + + 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext3_new_inode (handle, dir, mode); + inode = ext4_new_inode (handle, dir, mode); err = PTR_ERR(inode); if (!IS_ERR(inode)) { - inode->i_op = &ext3_file_inode_operations; - inode->i_fop = &ext3_file_operations; - ext3_set_aops(inode); - err = ext3_add_nondir(handle, dentry, inode); + inode->i_op = &ext4_file_inode_operations; + inode->i_fop = &ext4_file_operations; + ext4_set_aops(inode); + err = ext4_add_nondir(handle, dentry, inode); } - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + ext4_journal_stop(handle); + if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) goto retry; return err; } -static int ext3_mknod (struct inode * dir, struct dentry *dentry, +static int ext4_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev) { handle_t *handle; @@ -1688,100 +1688,100 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry, return -EINVAL; retry: - handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + - 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); + handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + + 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext3_new_inode (handle, dir, mode); + inode = ext4_new_inode (handle, dir, mode); err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, inode->i_mode, rdev); -#ifdef CONFIG_EXT3_FS_XATTR - inode->i_op = &ext3_special_inode_operations; +#ifdef CONFIG_EXT4DEV_FS_XATTR + inode->i_op = &ext4_special_inode_operations; #endif - err = ext3_add_nondir(handle, dentry, inode); + err = ext4_add_nondir(handle, dentry, inode); } - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + ext4_journal_stop(handle); + if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) goto retry; return err; } -static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) +static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode) { handle_t *handle; struct inode * inode; struct buffer_head * dir_block; - struct ext3_dir_entry_2 * de; + struct ext4_dir_entry_2 * de; int err, retries = 0; - if (dir->i_nlink >= EXT3_LINK_MAX) + if (dir->i_nlink >= EXT4_LINK_MAX) return -EMLINK; retry: - handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + - 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); + handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + + 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext3_new_inode (handle, dir, S_IFDIR | mode); + inode = ext4_new_inode (handle, dir, S_IFDIR | mode); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_stop; - inode->i_op = &ext3_dir_inode_operations; - inode->i_fop = &ext3_dir_operations; - inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize; - dir_block = ext3_bread (handle, inode, 0, 1, &err); + inode->i_op = &ext4_dir_inode_operations; + inode->i_fop = &ext4_dir_operations; + inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize; + dir_block = ext4_bread (handle, inode, 0, 1, &err); if (!dir_block) { drop_nlink(inode); /* is this nlink == 0? */ - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); iput (inode); goto out_stop; } BUFFER_TRACE(dir_block, "get_write_access"); - ext3_journal_get_write_access(handle, dir_block); - de = (struct ext3_dir_entry_2 *) dir_block->b_data; + ext4_journal_get_write_access(handle, dir_block); + de = (struct ext4_dir_entry_2 *) dir_block->b_data; de->inode = cpu_to_le32(inode->i_ino); de->name_len = 1; - de->rec_len = cpu_to_le16(EXT3_DIR_REC_LEN(de->name_len)); + de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(de->name_len)); strcpy (de->name, "."); - ext3_set_de_type(dir->i_sb, de, S_IFDIR); - de = (struct ext3_dir_entry_2 *) + ext4_set_de_type(dir->i_sb, de, S_IFDIR); + de = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); de->inode = cpu_to_le32(dir->i_ino); - de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT3_DIR_REC_LEN(1)); + de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT4_DIR_REC_LEN(1)); de->name_len = 2; strcpy (de->name, ".."); - ext3_set_de_type(dir->i_sb, de, S_IFDIR); + ext4_set_de_type(dir->i_sb, de, S_IFDIR); inode->i_nlink = 2; - BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata"); - ext3_journal_dirty_metadata(handle, dir_block); + BUFFER_TRACE(dir_block, "call ext4_journal_dirty_metadata"); + ext4_journal_dirty_metadata(handle, dir_block); brelse (dir_block); - ext3_mark_inode_dirty(handle, inode); - err = ext3_add_entry (handle, dentry, inode); + ext4_mark_inode_dirty(handle, inode); + err = ext4_add_entry (handle, dentry, inode); if (err) { inode->i_nlink = 0; - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); iput (inode); goto out_stop; } inc_nlink(dir); - ext3_update_dx_flag(dir); - ext3_mark_inode_dirty(handle, dir); + ext4_update_dx_flag(dir); + ext4_mark_inode_dirty(handle, dir); d_instantiate(dentry, inode); out_stop: - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + ext4_journal_stop(handle); + if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) goto retry; return err; } @@ -1793,59 +1793,59 @@ static int empty_dir (struct inode * inode) { unsigned long offset; struct buffer_head * bh; - struct ext3_dir_entry_2 * de, * de1; + struct ext4_dir_entry_2 * de, * de1; struct super_block * sb; int err = 0; sb = inode->i_sb; - if (inode->i_size < EXT3_DIR_REC_LEN(1) + EXT3_DIR_REC_LEN(2) || - !(bh = ext3_bread (NULL, inode, 0, 0, &err))) { + if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) || + !(bh = ext4_bread (NULL, inode, 0, 0, &err))) { if (err) - ext3_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __FUNCTION__, "error %d reading directory #%lu offset 0", err, inode->i_ino); else - ext3_warning(inode->i_sb, __FUNCTION__, + ext4_warning(inode->i_sb, __FUNCTION__, "bad directory (dir #%lu) - no data block", inode->i_ino); return 1; } - de = (struct ext3_dir_entry_2 *) bh->b_data; - de1 = (struct ext3_dir_entry_2 *) + de = (struct ext4_dir_entry_2 *) bh->b_data; + de1 = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) || strcmp (".", de->name) || strcmp ("..", de1->name)) { - ext3_warning (inode->i_sb, "empty_dir", + ext4_warning (inode->i_sb, "empty_dir", "bad directory (dir #%lu) - no `.' or `..'", inode->i_ino); brelse (bh); return 1; } offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len); - de = (struct ext3_dir_entry_2 *) + de = (struct ext4_dir_entry_2 *) ((char *) de1 + le16_to_cpu(de1->rec_len)); while (offset < inode->i_size ) { if (!bh || (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { err = 0; brelse (bh); - bh = ext3_bread (NULL, inode, - offset >> EXT3_BLOCK_SIZE_BITS(sb), 0, &err); + bh = ext4_bread (NULL, inode, + offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err); if (!bh) { if (err) - ext3_error(sb, __FUNCTION__, + ext4_error(sb, __FUNCTION__, "error %d reading directory" " #%lu offset %lu", err, inode->i_ino, offset); offset += sb->s_blocksize; continue; } - de = (struct ext3_dir_entry_2 *) bh->b_data; + de = (struct ext4_dir_entry_2 *) bh->b_data; } - if (!ext3_check_dir_entry("empty_dir", inode, de, bh, offset)) { - de = (struct ext3_dir_entry_2 *)(bh->b_data + + if (!ext4_check_dir_entry("empty_dir", inode, de, bh, offset)) { + de = (struct ext4_dir_entry_2 *)(bh->b_data + sb->s_blocksize); offset = (offset | (sb->s_blocksize - 1)) + 1; continue; @@ -1855,57 +1855,57 @@ static int empty_dir (struct inode * inode) return 0; } offset += le16_to_cpu(de->rec_len); - de = (struct ext3_dir_entry_2 *) + de = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); } brelse (bh); return 1; } -/* ext3_orphan_add() links an unlinked or truncated inode into a list of +/* ext4_orphan_add() links an unlinked or truncated inode into a list of * such inodes, starting at the superblock, in case we crash before the * file is closed/deleted, or in case the inode truncate spans multiple * transactions and the last transaction is not recovered after a crash. * * At filesystem recovery time, we walk this list deleting unlinked - * inodes and truncating linked inodes in ext3_orphan_cleanup(). + * inodes and truncating linked inodes in ext4_orphan_cleanup(). */ -int ext3_orphan_add(handle_t *handle, struct inode *inode) +int ext4_orphan_add(handle_t *handle, struct inode *inode) { struct super_block *sb = inode->i_sb; - struct ext3_iloc iloc; + struct ext4_iloc iloc; int err = 0, rc; lock_super(sb); - if (!list_empty(&EXT3_I(inode)->i_orphan)) + if (!list_empty(&EXT4_I(inode)->i_orphan)) goto out_unlock; /* Orphan handling is only valid for files with data blocks * being truncated, or files being unlinked. */ /* @@@ FIXME: Observation from aviro: - * I think I can trigger J_ASSERT in ext3_orphan_add(). We block - * here (on lock_super()), so race with ext3_link() which might bump + * I think I can trigger J_ASSERT in ext4_orphan_add(). We block + * here (on lock_super()), so race with ext4_link() which might bump * ->i_nlink. For, say it, character device. Not a regular file, * not a directory, not a symlink and ->i_nlink > 0. */ J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get_write_access"); - err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); + BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); + err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); if (err) goto out_unlock; - err = ext3_reserve_inode_write(handle, inode, &iloc); + err = ext4_reserve_inode_write(handle, inode, &iloc); if (err) goto out_unlock; /* Insert this inode at the head of the on-disk orphan list... */ - NEXT_ORPHAN(inode) = le32_to_cpu(EXT3_SB(sb)->s_es->s_last_orphan); - EXT3_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); - err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - rc = ext3_mark_iloc_dirty(handle, inode, &iloc); + NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan); + EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); + err = ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); + rc = ext4_mark_iloc_dirty(handle, inode, &iloc); if (!err) err = rc; @@ -1918,28 +1918,28 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode) * This is safe: on error we're going to ignore the orphan list * anyway on the next recovery. */ if (!err) - list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan); + list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan); jbd_debug(4, "superblock will point to %lu\n", inode->i_ino); jbd_debug(4, "orphan inode %lu will point to %d\n", inode->i_ino, NEXT_ORPHAN(inode)); out_unlock: unlock_super(sb); - ext3_std_error(inode->i_sb, err); + ext4_std_error(inode->i_sb, err); return err; } /* - * ext3_orphan_del() removes an unlinked or truncated inode from the list + * ext4_orphan_del() removes an unlinked or truncated inode from the list * of such inodes stored on disk, because it is finally being cleaned up. */ -int ext3_orphan_del(handle_t *handle, struct inode *inode) +int ext4_orphan_del(handle_t *handle, struct inode *inode) { struct list_head *prev; - struct ext3_inode_info *ei = EXT3_I(inode); - struct ext3_sb_info *sbi; + struct ext4_inode_info *ei = EXT4_I(inode); + struct ext4_sb_info *sbi; unsigned long ino_next; - struct ext3_iloc iloc; + struct ext4_iloc iloc; int err = 0; lock_super(inode->i_sb); @@ -1950,7 +1950,7 @@ int ext3_orphan_del(handle_t *handle, struct inode *inode) ino_next = NEXT_ORPHAN(inode); prev = ei->i_orphan.prev; - sbi = EXT3_SB(inode->i_sb); + sbi = EXT4_SB(inode->i_sb); jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino); @@ -1963,38 +1963,38 @@ int ext3_orphan_del(handle_t *handle, struct inode *inode) if (!handle) goto out; - err = ext3_reserve_inode_write(handle, inode, &iloc); + err = ext4_reserve_inode_write(handle, inode, &iloc); if (err) goto out_err; if (prev == &sbi->s_orphan) { jbd_debug(4, "superblock will point to %lu\n", ino_next); BUFFER_TRACE(sbi->s_sbh, "get_write_access"); - err = ext3_journal_get_write_access(handle, sbi->s_sbh); + err = ext4_journal_get_write_access(handle, sbi->s_sbh); if (err) goto out_brelse; sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); - err = ext3_journal_dirty_metadata(handle, sbi->s_sbh); + err = ext4_journal_dirty_metadata(handle, sbi->s_sbh); } else { - struct ext3_iloc iloc2; + struct ext4_iloc iloc2; struct inode *i_prev = - &list_entry(prev, struct ext3_inode_info, i_orphan)->vfs_inode; + &list_entry(prev, struct ext4_inode_info, i_orphan)->vfs_inode; jbd_debug(4, "orphan inode %lu will point to %lu\n", i_prev->i_ino, ino_next); - err = ext3_reserve_inode_write(handle, i_prev, &iloc2); + err = ext4_reserve_inode_write(handle, i_prev, &iloc2); if (err) goto out_brelse; NEXT_ORPHAN(i_prev) = ino_next; - err = ext3_mark_iloc_dirty(handle, i_prev, &iloc2); + err = ext4_mark_iloc_dirty(handle, i_prev, &iloc2); } if (err) goto out_brelse; NEXT_ORPHAN(inode) = 0; - err = ext3_mark_iloc_dirty(handle, inode, &iloc); + err = ext4_mark_iloc_dirty(handle, inode, &iloc); out_err: - ext3_std_error(inode->i_sb, err); + ext4_std_error(inode->i_sb, err); out: unlock_super(inode->i_sb); return err; @@ -2004,23 +2004,23 @@ out_brelse: goto out_err; } -static int ext3_rmdir (struct inode * dir, struct dentry *dentry) +static int ext4_rmdir (struct inode * dir, struct dentry *dentry) { int retval; struct inode * inode; struct buffer_head * bh; - struct ext3_dir_entry_2 * de; + struct ext4_dir_entry_2 * de; handle_t *handle; /* Initialize quotas before so that eventual writes go in * separate transaction */ DQUOT_INIT(dentry->d_inode); - handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); + handle = ext4_journal_start(dir, EXT4_DELETE_TRANS_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); retval = -ENOENT; - bh = ext3_find_entry (dentry, &de); + bh = ext4_find_entry (dentry, &de); if (!bh) goto end_rmdir; @@ -2037,11 +2037,11 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) if (!empty_dir (inode)) goto end_rmdir; - retval = ext3_delete_entry(handle, dir, de, bh); + retval = ext4_delete_entry(handle, dir, de, bh); if (retval) goto end_rmdir; if (inode->i_nlink != 2) - ext3_warning (inode->i_sb, "ext3_rmdir", + ext4_warning (inode->i_sb, "ext4_rmdir", "empty directory has nlink!=2 (%d)", inode->i_nlink); inode->i_version++; @@ -2050,31 +2050,31 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) * zero will ensure that the right thing happens during any * recovery. */ inode->i_size = 0; - ext3_orphan_add(handle, inode); + ext4_orphan_add(handle, inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); drop_nlink(dir); - ext3_update_dx_flag(dir); - ext3_mark_inode_dirty(handle, dir); + ext4_update_dx_flag(dir); + ext4_mark_inode_dirty(handle, dir); end_rmdir: - ext3_journal_stop(handle); + ext4_journal_stop(handle); brelse (bh); return retval; } -static int ext3_unlink(struct inode * dir, struct dentry *dentry) +static int ext4_unlink(struct inode * dir, struct dentry *dentry) { int retval; struct inode * inode; struct buffer_head * bh; - struct ext3_dir_entry_2 * de; + struct ext4_dir_entry_2 * de; handle_t *handle; /* Initialize quotas before so that eventual writes go * in separate transaction */ DQUOT_INIT(dentry->d_inode); - handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); + handle = ext4_journal_start(dir, EXT4_DELETE_TRANS_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -2082,7 +2082,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) handle->h_sync = 1; retval = -ENOENT; - bh = ext3_find_entry (dentry, &de); + bh = ext4_find_entry (dentry, &de); if (!bh) goto end_unlink; @@ -2093,31 +2093,31 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) goto end_unlink; if (!inode->i_nlink) { - ext3_warning (inode->i_sb, "ext3_unlink", + ext4_warning (inode->i_sb, "ext4_unlink", "Deleting nonexistent file (%lu), %d", inode->i_ino, inode->i_nlink); inode->i_nlink = 1; } - retval = ext3_delete_entry(handle, dir, de, bh); + retval = ext4_delete_entry(handle, dir, de, bh); if (retval) goto end_unlink; dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; - ext3_update_dx_flag(dir); - ext3_mark_inode_dirty(handle, dir); + ext4_update_dx_flag(dir); + ext4_mark_inode_dirty(handle, dir); drop_nlink(inode); if (!inode->i_nlink) - ext3_orphan_add(handle, inode); + ext4_orphan_add(handle, inode); inode->i_ctime = dir->i_ctime; - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); retval = 0; end_unlink: - ext3_journal_stop(handle); + ext4_journal_stop(handle); brelse (bh); return retval; } -static int ext3_symlink (struct inode * dir, +static int ext4_symlink (struct inode * dir, struct dentry *dentry, const char * symname) { handle_t *handle; @@ -2129,63 +2129,63 @@ static int ext3_symlink (struct inode * dir, return -ENAMETOOLONG; retry: - handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 + - 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); + handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 5 + + 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO); + inode = ext4_new_inode (handle, dir, S_IFLNK|S_IRWXUGO); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_stop; - if (l > sizeof (EXT3_I(inode)->i_data)) { - inode->i_op = &ext3_symlink_inode_operations; - ext3_set_aops(inode); + if (l > sizeof (EXT4_I(inode)->i_data)) { + inode->i_op = &ext4_symlink_inode_operations; + ext4_set_aops(inode); /* - * page_symlink() calls into ext3_prepare/commit_write. + * page_symlink() calls into ext4_prepare/commit_write. * We have a transaction open. All is sweetness. It also sets * i_size in generic_commit_write(). */ err = __page_symlink(inode, symname, l, mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); if (err) { - ext3_dec_count(handle, inode); - ext3_mark_inode_dirty(handle, inode); + ext4_dec_count(handle, inode); + ext4_mark_inode_dirty(handle, inode); iput (inode); goto out_stop; } } else { - inode->i_op = &ext3_fast_symlink_inode_operations; - memcpy((char*)&EXT3_I(inode)->i_data,symname,l); + inode->i_op = &ext4_fast_symlink_inode_operations; + memcpy((char*)&EXT4_I(inode)->i_data,symname,l); inode->i_size = l-1; } - EXT3_I(inode)->i_disksize = inode->i_size; - err = ext3_add_nondir(handle, dentry, inode); + EXT4_I(inode)->i_disksize = inode->i_size; + err = ext4_add_nondir(handle, dentry, inode); out_stop: - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + ext4_journal_stop(handle); + if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) goto retry; return err; } -static int ext3_link (struct dentry * old_dentry, +static int ext4_link (struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { handle_t *handle; struct inode *inode = old_dentry->d_inode; int err, retries = 0; - if (inode->i_nlink >= EXT3_LINK_MAX) + if (inode->i_nlink >= EXT4_LINK_MAX) return -EMLINK; retry: - handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS); + handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + + EXT4_INDEX_EXTRA_TRANS_BLOCKS); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -2193,31 +2193,31 @@ retry: handle->h_sync = 1; inode->i_ctime = CURRENT_TIME_SEC; - ext3_inc_count(handle, inode); + ext4_inc_count(handle, inode); atomic_inc(&inode->i_count); - err = ext3_add_nondir(handle, dentry, inode); - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + err = ext4_add_nondir(handle, dentry, inode); + ext4_journal_stop(handle); + if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) goto retry; return err; } #define PARENT_INO(buffer) \ - ((struct ext3_dir_entry_2 *) ((char *) buffer + \ - le16_to_cpu(((struct ext3_dir_entry_2 *) buffer)->rec_len)))->inode + ((struct ext4_dir_entry_2 *) ((char *) buffer + \ + le16_to_cpu(((struct ext4_dir_entry_2 *) buffer)->rec_len)))->inode /* * Anybody can rename anything with this: the permission checks are left to the * higher-level routines. */ -static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, +static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry) { handle_t *handle; struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; - struct ext3_dir_entry_2 * old_de, * new_de; + struct ext4_dir_entry_2 * old_de, * new_de; int retval; old_bh = new_bh = dir_bh = NULL; @@ -2226,16 +2226,16 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, * in separate transaction */ if (new_dentry->d_inode) DQUOT_INIT(new_dentry->d_inode); - handle = ext3_journal_start(old_dir, 2 * - EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); + handle = ext4_journal_start(old_dir, 2 * + EXT4_DATA_TRANS_BLOCKS(old_dir->i_sb) + + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2); if (IS_ERR(handle)) return PTR_ERR(handle); if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) handle->h_sync = 1; - old_bh = ext3_find_entry (old_dentry, &old_de); + old_bh = ext4_find_entry (old_dentry, &old_de); /* * Check for inode number is _not_ due to possible IO errors. * We might rmdir the source, keep it as pwd of some process @@ -2248,7 +2248,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, goto end_rename; new_inode = new_dentry->d_inode; - new_bh = ext3_find_entry (new_dentry, &new_de); + new_bh = ext4_find_entry (new_dentry, &new_de); if (new_bh) { if (!new_inode) { brelse (new_bh); @@ -2262,30 +2262,30 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, goto end_rename; } retval = -EIO; - dir_bh = ext3_bread (handle, old_inode, 0, 0, &retval); + dir_bh = ext4_bread (handle, old_inode, 0, 0, &retval); if (!dir_bh) goto end_rename; if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino) goto end_rename; retval = -EMLINK; if (!new_inode && new_dir!=old_dir && - new_dir->i_nlink >= EXT3_LINK_MAX) + new_dir->i_nlink >= EXT4_LINK_MAX) goto end_rename; } if (!new_bh) { - retval = ext3_add_entry (handle, new_dentry, old_inode); + retval = ext4_add_entry (handle, new_dentry, old_inode); if (retval) goto end_rename; } else { BUFFER_TRACE(new_bh, "get write access"); - ext3_journal_get_write_access(handle, new_bh); + ext4_journal_get_write_access(handle, new_bh); new_de->inode = cpu_to_le32(old_inode->i_ino); - if (EXT3_HAS_INCOMPAT_FEATURE(new_dir->i_sb, - EXT3_FEATURE_INCOMPAT_FILETYPE)) + if (EXT4_HAS_INCOMPAT_FEATURE(new_dir->i_sb, + EXT4_FEATURE_INCOMPAT_FILETYPE)) new_de->file_type = old_de->file_type; new_dir->i_version++; - BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata"); - ext3_journal_dirty_metadata(handle, new_bh); + BUFFER_TRACE(new_bh, "call ext4_journal_dirty_metadata"); + ext4_journal_dirty_metadata(handle, new_bh); brelse(new_bh); new_bh = NULL; } @@ -2295,7 +2295,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, * rename. */ old_inode->i_ctime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, old_inode); + ext4_mark_inode_dirty(handle, old_inode); /* * ok, that's it @@ -2303,24 +2303,24 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, if (le32_to_cpu(old_de->inode) != old_inode->i_ino || old_de->name_len != old_dentry->d_name.len || strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) || - (retval = ext3_delete_entry(handle, old_dir, + (retval = ext4_delete_entry(handle, old_dir, old_de, old_bh)) == -ENOENT) { /* old_de could have moved from under us during htree split, so * make sure that we are deleting the right entry. We might * also be pointing to a stale entry in the unused part of * old_bh so just checking inum and the name isn't enough. */ struct buffer_head *old_bh2; - struct ext3_dir_entry_2 *old_de2; + struct ext4_dir_entry_2 *old_de2; - old_bh2 = ext3_find_entry(old_dentry, &old_de2); + old_bh2 = ext4_find_entry(old_dentry, &old_de2); if (old_bh2) { - retval = ext3_delete_entry(handle, old_dir, + retval = ext4_delete_entry(handle, old_dir, old_de2, old_bh2); brelse(old_bh2); } } if (retval) { - ext3_warning(old_dir->i_sb, "ext3_rename", + ext4_warning(old_dir->i_sb, "ext4_rename", "Deleting old file (%lu), %d, error=%d", old_dir->i_ino, old_dir->i_nlink, retval); } @@ -2330,27 +2330,27 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, new_inode->i_ctime = CURRENT_TIME_SEC; } old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; - ext3_update_dx_flag(old_dir); + ext4_update_dx_flag(old_dir); if (dir_bh) { BUFFER_TRACE(dir_bh, "get_write_access"); - ext3_journal_get_write_access(handle, dir_bh); + ext4_journal_get_write_access(handle, dir_bh); PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino); - BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata"); - ext3_journal_dirty_metadata(handle, dir_bh); + BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata"); + ext4_journal_dirty_metadata(handle, dir_bh); drop_nlink(old_dir); if (new_inode) { drop_nlink(new_inode); } else { inc_nlink(new_dir); - ext3_update_dx_flag(new_dir); - ext3_mark_inode_dirty(handle, new_dir); + ext4_update_dx_flag(new_dir); + ext4_mark_inode_dirty(handle, new_dir); } } - ext3_mark_inode_dirty(handle, old_dir); + ext4_mark_inode_dirty(handle, old_dir); if (new_inode) { - ext3_mark_inode_dirty(handle, new_inode); + ext4_mark_inode_dirty(handle, new_inode); if (!new_inode->i_nlink) - ext3_orphan_add(handle, new_inode); + ext4_orphan_add(handle, new_inode); } retval = 0; @@ -2358,40 +2358,40 @@ end_rename: brelse (dir_bh); brelse (old_bh); brelse (new_bh); - ext3_journal_stop(handle); + ext4_journal_stop(handle); return retval; } /* * directories can handle most operations... */ -struct inode_operations ext3_dir_inode_operations = { - .create = ext3_create, - .lookup = ext3_lookup, - .link = ext3_link, - .unlink = ext3_unlink, - .symlink = ext3_symlink, - .mkdir = ext3_mkdir, - .rmdir = ext3_rmdir, - .mknod = ext3_mknod, - .rename = ext3_rename, - .setattr = ext3_setattr, -#ifdef CONFIG_EXT3_FS_XATTR +struct inode_operations ext4_dir_inode_operations = { + .create = ext4_create, + .lookup = ext4_lookup, + .link = ext4_link, + .unlink = ext4_unlink, + .symlink = ext4_symlink, + .mkdir = ext4_mkdir, + .rmdir = ext4_rmdir, + .mknod = ext4_mknod, + .rename = ext4_rename, + .setattr = ext4_setattr, +#ifdef CONFIG_EXT4DEV_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, - .listxattr = ext3_listxattr, + .listxattr = ext4_listxattr, .removexattr = generic_removexattr, #endif - .permission = ext3_permission, + .permission = ext4_permission, }; -struct inode_operations ext3_special_inode_operations = { - .setattr = ext3_setattr, -#ifdef CONFIG_EXT3_FS_XATTR +struct inode_operations ext4_special_inode_operations = { + .setattr = ext4_setattr, +#ifdef CONFIG_EXT4DEV_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, - .listxattr = ext3_listxattr, + .listxattr = ext4_listxattr, .removexattr = generic_removexattr, #endif - .permission = ext3_permission, + .permission = ext4_permission, }; diff --git a/fs/ext4/namei.h b/fs/ext4/namei.h index f2ce2b0065c9..5e4dfff36a00 100644 --- a/fs/ext4/namei.h +++ b/fs/ext4/namei.h @@ -1,8 +1,8 @@ -/* linux/fs/ext3/namei.h +/* linux/fs/ext4/namei.h * * Copyright (C) 2005 Simtec Electronics * Ben Dooks * */ -extern struct dentry *ext3_get_parent(struct dentry *child); +extern struct dentry *ext4_get_parent(struct dentry *child); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index b73cba12f79c..4a47895d9d6d 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -1,7 +1,7 @@ /* - * linux/fs/ext3/resize.c + * linux/fs/ext4/resize.c * - * Support for resizing an ext3 filesystem while it is mounted. + * Support for resizing an ext4 filesystem while it is mounted. * * Copyright (C) 2001, 2002 Andreas Dilger * @@ -9,11 +9,11 @@ */ -#define EXT3FS_DEBUG +#define EXT4FS_DEBUG #include #include -#include +#include #include #include @@ -23,87 +23,87 @@ #define inside(b, first, last) ((b) >= (first) && (b) < (last)) static int verify_group_input(struct super_block *sb, - struct ext3_new_group_data *input) + struct ext4_new_group_data *input) { - struct ext3_sb_info *sbi = EXT3_SB(sb); - struct ext3_super_block *es = sbi->s_es; - ext3_fsblk_t start = le32_to_cpu(es->s_blocks_count); - ext3_fsblk_t end = start + input->blocks_count; + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; + ext4_fsblk_t start = le32_to_cpu(es->s_blocks_count); + ext4_fsblk_t end = start + input->blocks_count; unsigned group = input->group; - ext3_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; - unsigned overhead = ext3_bg_has_super(sb, group) ? - (1 + ext3_bg_num_gdb(sb, group) + + ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; + unsigned overhead = ext4_bg_has_super(sb, group) ? + (1 + ext4_bg_num_gdb(sb, group) + le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; - ext3_fsblk_t metaend = start + overhead; + ext4_fsblk_t metaend = start + overhead; struct buffer_head *bh = NULL; - ext3_grpblk_t free_blocks_count; + ext4_grpblk_t free_blocks_count; int err = -EINVAL; input->free_blocks_count = free_blocks_count = input->blocks_count - 2 - overhead - sbi->s_itb_per_group; if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT3-fs: adding %s group %u: %u blocks " + printk(KERN_DEBUG "EXT4-fs: adding %s group %u: %u blocks " "(%d free, %u reserved)\n", - ext3_bg_has_super(sb, input->group) ? "normal" : + ext4_bg_has_super(sb, input->group) ? "normal" : "no-super", input->group, input->blocks_count, free_blocks_count, input->reserved_blocks); if (group != sbi->s_groups_count) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Cannot add at group %u (only %lu groups)", input->group, sbi->s_groups_count); else if ((start - le32_to_cpu(es->s_first_data_block)) % - EXT3_BLOCKS_PER_GROUP(sb)) - ext3_warning(sb, __FUNCTION__, "Last group not full"); + EXT4_BLOCKS_PER_GROUP(sb)) + ext4_warning(sb, __FUNCTION__, "Last group not full"); else if (input->reserved_blocks > input->blocks_count / 5) - ext3_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)", + ext4_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)", input->reserved_blocks); else if (free_blocks_count < 0) - ext3_warning(sb, __FUNCTION__, "Bad blocks count %u", + ext4_warning(sb, __FUNCTION__, "Bad blocks count %u", input->blocks_count); else if (!(bh = sb_bread(sb, end - 1))) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Cannot read last block ("E3FSBLK")", end - 1); else if (outside(input->block_bitmap, start, end)) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Block bitmap not in group (block %u)", input->block_bitmap); else if (outside(input->inode_bitmap, start, end)) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Inode bitmap not in group (block %u)", input->inode_bitmap); else if (outside(input->inode_table, start, end) || outside(itend - 1, start, end)) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Inode table not in group (blocks %u-"E3FSBLK")", input->inode_table, itend - 1); else if (input->inode_bitmap == input->block_bitmap) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Block bitmap same as inode bitmap (%u)", input->block_bitmap); else if (inside(input->block_bitmap, input->inode_table, itend)) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Block bitmap (%u) in inode table (%u-"E3FSBLK")", input->block_bitmap, input->inode_table, itend-1); else if (inside(input->inode_bitmap, input->inode_table, itend)) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Inode bitmap (%u) in inode table (%u-"E3FSBLK")", input->inode_bitmap, input->inode_table, itend-1); else if (inside(input->block_bitmap, start, metaend)) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Block bitmap (%u) in GDT table" " ("E3FSBLK"-"E3FSBLK")", input->block_bitmap, start, metaend - 1); else if (inside(input->inode_bitmap, start, metaend)) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Inode bitmap (%u) in GDT table" " ("E3FSBLK"-"E3FSBLK")", input->inode_bitmap, start, metaend - 1); else if (inside(input->inode_table, start, metaend) || inside(itend - 1, start, metaend)) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Inode table (%u-"E3FSBLK") overlaps" "GDT table ("E3FSBLK"-"E3FSBLK")", input->inode_table, itend - 1, start, metaend - 1); @@ -115,7 +115,7 @@ static int verify_group_input(struct super_block *sb, } static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, - ext3_fsblk_t blk) + ext4_fsblk_t blk) { struct buffer_head *bh; int err; @@ -123,7 +123,7 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, bh = sb_getblk(sb, blk); if (!bh) return ERR_PTR(-EIO); - if ((err = ext3_journal_get_write_access(handle, bh))) { + if ((err = ext4_journal_get_write_access(handle, bh))) { brelse(bh); bh = ERR_PTR(err); } else { @@ -148,9 +148,9 @@ static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap) if (start_bit >= end_bit) return; - ext3_debug("mark end bits +%d through +%d used\n", start_bit, end_bit); + ext4_debug("mark end bits +%d through +%d used\n", start_bit, end_bit); for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) - ext3_set_bit(i, bitmap); + ext4_set_bit(i, bitmap); if (i < end_bit) memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); } @@ -163,21 +163,21 @@ static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap) * If any part of this fails, we simply abort the resize. */ static int setup_new_group_blocks(struct super_block *sb, - struct ext3_new_group_data *input) + struct ext4_new_group_data *input) { - struct ext3_sb_info *sbi = EXT3_SB(sb); - ext3_fsblk_t start = ext3_group_first_block_no(sb, input->group); - int reserved_gdb = ext3_bg_has_super(sb, input->group) ? + struct ext4_sb_info *sbi = EXT4_SB(sb); + ext4_fsblk_t start = ext4_group_first_block_no(sb, input->group); + int reserved_gdb = ext4_bg_has_super(sb, input->group) ? le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0; - unsigned long gdblocks = ext3_bg_num_gdb(sb, input->group); + unsigned long gdblocks = ext4_bg_num_gdb(sb, input->group); struct buffer_head *bh; handle_t *handle; - ext3_fsblk_t block; - ext3_grpblk_t bit; + ext4_fsblk_t block; + ext4_grpblk_t bit; int i; int err = 0, err2; - handle = ext3_journal_start_sb(sb, reserved_gdb + gdblocks + + handle = ext4_journal_start_sb(sb, reserved_gdb + gdblocks + 2 + sbi->s_itb_per_group); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -193,9 +193,9 @@ static int setup_new_group_blocks(struct super_block *sb, goto exit_journal; } - if (ext3_bg_has_super(sb, input->group)) { - ext3_debug("mark backup superblock %#04lx (+0)\n", start); - ext3_set_bit(0, bh->b_data); + if (ext4_bg_has_super(sb, input->group)) { + ext4_debug("mark backup superblock %#04lx (+0)\n", start); + ext4_set_bit(0, bh->b_data); } /* Copy all of the GDT blocks into the backup in this group */ @@ -203,14 +203,14 @@ static int setup_new_group_blocks(struct super_block *sb, i < gdblocks; i++, block++, bit++) { struct buffer_head *gdb; - ext3_debug("update backup group %#04lx (+%d)\n", block, bit); + ext4_debug("update backup group %#04lx (+%d)\n", block, bit); gdb = sb_getblk(sb, block); if (!gdb) { err = -EIO; goto exit_bh; } - if ((err = ext3_journal_get_write_access(handle, gdb))) { + if ((err = ext4_journal_get_write_access(handle, gdb))) { brelse(gdb); goto exit_bh; } @@ -218,8 +218,8 @@ static int setup_new_group_blocks(struct super_block *sb, memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, bh->b_size); set_buffer_uptodate(gdb); unlock_buffer(bh); - ext3_journal_dirty_metadata(handle, gdb); - ext3_set_bit(bit, bh->b_data); + ext4_journal_dirty_metadata(handle, gdb); + ext4_set_bit(bit, bh->b_data); brelse(gdb); } @@ -228,59 +228,59 @@ static int setup_new_group_blocks(struct super_block *sb, i < reserved_gdb; i++, block++, bit++) { struct buffer_head *gdb; - ext3_debug("clear reserved block %#04lx (+%d)\n", block, bit); + ext4_debug("clear reserved block %#04lx (+%d)\n", block, bit); if (IS_ERR(gdb = bclean(handle, sb, block))) { err = PTR_ERR(bh); goto exit_bh; } - ext3_journal_dirty_metadata(handle, gdb); - ext3_set_bit(bit, bh->b_data); + ext4_journal_dirty_metadata(handle, gdb); + ext4_set_bit(bit, bh->b_data); brelse(gdb); } - ext3_debug("mark block bitmap %#04x (+%ld)\n", input->block_bitmap, + ext4_debug("mark block bitmap %#04x (+%ld)\n", input->block_bitmap, input->block_bitmap - start); - ext3_set_bit(input->block_bitmap - start, bh->b_data); - ext3_debug("mark inode bitmap %#04x (+%ld)\n", input->inode_bitmap, + ext4_set_bit(input->block_bitmap - start, bh->b_data); + ext4_debug("mark inode bitmap %#04x (+%ld)\n", input->inode_bitmap, input->inode_bitmap - start); - ext3_set_bit(input->inode_bitmap - start, bh->b_data); + ext4_set_bit(input->inode_bitmap - start, bh->b_data); /* Zero out all of the inode table blocks */ for (i = 0, block = input->inode_table, bit = block - start; i < sbi->s_itb_per_group; i++, bit++, block++) { struct buffer_head *it; - ext3_debug("clear inode block %#04lx (+%d)\n", block, bit); + ext4_debug("clear inode block %#04lx (+%d)\n", block, bit); if (IS_ERR(it = bclean(handle, sb, block))) { err = PTR_ERR(it); goto exit_bh; } - ext3_journal_dirty_metadata(handle, it); + ext4_journal_dirty_metadata(handle, it); brelse(it); - ext3_set_bit(bit, bh->b_data); + ext4_set_bit(bit, bh->b_data); } - mark_bitmap_end(input->blocks_count, EXT3_BLOCKS_PER_GROUP(sb), + mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb), bh->b_data); - ext3_journal_dirty_metadata(handle, bh); + ext4_journal_dirty_metadata(handle, bh); brelse(bh); /* Mark unused entries in inode bitmap used */ - ext3_debug("clear inode bitmap %#04x (+%ld)\n", + ext4_debug("clear inode bitmap %#04x (+%ld)\n", input->inode_bitmap, input->inode_bitmap - start); if (IS_ERR(bh = bclean(handle, sb, input->inode_bitmap))) { err = PTR_ERR(bh); goto exit_journal; } - mark_bitmap_end(EXT3_INODES_PER_GROUP(sb), EXT3_BLOCKS_PER_GROUP(sb), + mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb), bh->b_data); - ext3_journal_dirty_metadata(handle, bh); + ext4_journal_dirty_metadata(handle, bh); exit_bh: brelse(bh); exit_journal: unlock_super(sb); - if ((err2 = ext3_journal_stop(handle)) && !err) + if ((err2 = ext4_journal_stop(handle)) && !err) err = err2; return err; @@ -288,20 +288,20 @@ exit_journal: /* * Iterate through the groups which hold BACKUP superblock/GDT copies in an - * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before + * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before * calling this for the first time. In a sparse filesystem it will be the * 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, ... */ -static unsigned ext3_list_backups(struct super_block *sb, unsigned *three, +static unsigned ext4_list_backups(struct super_block *sb, unsigned *three, unsigned *five, unsigned *seven) { unsigned *min = three; int mult = 3; unsigned ret; - if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { + if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, + EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) { ret = *min; *min += 1; return ret; @@ -330,8 +330,8 @@ static unsigned ext3_list_backups(struct super_block *sb, unsigned *three, static int verify_reserved_gdb(struct super_block *sb, struct buffer_head *primary) { - const ext3_fsblk_t blk = primary->b_blocknr; - const unsigned long end = EXT3_SB(sb)->s_groups_count; + const ext4_fsblk_t blk = primary->b_blocknr; + const unsigned long end = EXT4_SB(sb)->s_groups_count; unsigned three = 1; unsigned five = 5; unsigned seven = 7; @@ -339,16 +339,16 @@ static int verify_reserved_gdb(struct super_block *sb, __le32 *p = (__le32 *)primary->b_data; int gdbackups = 0; - while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) { - if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){ - ext3_warning(sb, __FUNCTION__, + while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) { + if (le32_to_cpu(*p++) != grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){ + ext4_warning(sb, __FUNCTION__, "reserved GDT "E3FSBLK " missing grp %d ("E3FSBLK")", blk, grp, - grp * EXT3_BLOCKS_PER_GROUP(sb) + blk); + grp * EXT4_BLOCKS_PER_GROUP(sb) + blk); return -EINVAL; } - if (++gdbackups > EXT3_ADDR_PER_BLOCK(sb)) + if (++gdbackups > EXT4_ADDR_PER_BLOCK(sb)) return -EFBIG; } @@ -369,23 +369,23 @@ static int verify_reserved_gdb(struct super_block *sb, * fail once we start modifying the data on disk, because JBD has no rollback. */ static int add_new_gdb(handle_t *handle, struct inode *inode, - struct ext3_new_group_data *input, + struct ext4_new_group_data *input, struct buffer_head **primary) { struct super_block *sb = inode->i_sb; - struct ext3_super_block *es = EXT3_SB(sb)->s_es; - unsigned long gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); - ext3_fsblk_t gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num; + struct ext4_super_block *es = EXT4_SB(sb)->s_es; + unsigned long gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb); + ext4_fsblk_t gdblock = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num; struct buffer_head **o_group_desc, **n_group_desc; struct buffer_head *dind; int gdbackups; - struct ext3_iloc iloc; + struct ext4_iloc iloc; __le32 *data; int err; if (test_opt(sb, DEBUG)) printk(KERN_DEBUG - "EXT3-fs: ext3_add_new_gdb: adding group block %lu\n", + "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n", gdb_num); /* @@ -393,11 +393,11 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, * because the user tools have no way of handling this. Probably a * bad time to do it anyways. */ - if (EXT3_SB(sb)->s_sbh->b_blocknr != - le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) { - ext3_warning(sb, __FUNCTION__, + if (EXT4_SB(sb)->s_sbh->b_blocknr != + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) { + ext4_warning(sb, __FUNCTION__, "won't resize using backup superblock at %llu", - (unsigned long long)EXT3_SB(sb)->s_sbh->b_blocknr); + (unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr); return -EPERM; } @@ -410,7 +410,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, goto exit_bh; } - data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; + data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK; dind = sb_bread(sb, le32_to_cpu(*data)); if (!dind) { err = -EIO; @@ -418,32 +418,32 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, } data = (__le32 *)dind->b_data; - if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) { - ext3_warning(sb, __FUNCTION__, + if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) { + ext4_warning(sb, __FUNCTION__, "new group %u GDT block "E3FSBLK" not reserved", input->group, gdblock); err = -EINVAL; goto exit_dind; } - if ((err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh))) + if ((err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh))) goto exit_dind; - if ((err = ext3_journal_get_write_access(handle, *primary))) + if ((err = ext4_journal_get_write_access(handle, *primary))) goto exit_sbh; - if ((err = ext3_journal_get_write_access(handle, dind))) + if ((err = ext4_journal_get_write_access(handle, dind))) goto exit_primary; - /* ext3_reserve_inode_write() gets a reference on the iloc */ - if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) + /* ext4_reserve_inode_write() gets a reference on the iloc */ + if ((err = ext4_reserve_inode_write(handle, inode, &iloc))) goto exit_dindj; n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *), GFP_KERNEL); if (!n_group_desc) { err = -ENOMEM; - ext3_warning (sb, __FUNCTION__, + ext4_warning (sb, __FUNCTION__, "not enough memory for %lu groups", gdb_num + 1); goto exit_inode; } @@ -457,43 +457,43 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, * these blocks, because they are marked as in-use from being in the * reserved inode, and will become GDT blocks (primary and backup). */ - data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)] = 0; - ext3_journal_dirty_metadata(handle, dind); + data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)] = 0; + ext4_journal_dirty_metadata(handle, dind); brelse(dind); inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9; - ext3_mark_iloc_dirty(handle, inode, &iloc); + ext4_mark_iloc_dirty(handle, inode, &iloc); memset((*primary)->b_data, 0, sb->s_blocksize); - ext3_journal_dirty_metadata(handle, *primary); + ext4_journal_dirty_metadata(handle, *primary); - o_group_desc = EXT3_SB(sb)->s_group_desc; + o_group_desc = EXT4_SB(sb)->s_group_desc; memcpy(n_group_desc, o_group_desc, - EXT3_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); + EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); n_group_desc[gdb_num] = *primary; - EXT3_SB(sb)->s_group_desc = n_group_desc; - EXT3_SB(sb)->s_gdb_count++; + EXT4_SB(sb)->s_group_desc = n_group_desc; + EXT4_SB(sb)->s_gdb_count++; kfree(o_group_desc); es->s_reserved_gdt_blocks = cpu_to_le16(le16_to_cpu(es->s_reserved_gdt_blocks) - 1); - ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); return 0; exit_inode: - //ext3_journal_release_buffer(handle, iloc.bh); + //ext4_journal_release_buffer(handle, iloc.bh); brelse(iloc.bh); exit_dindj: - //ext3_journal_release_buffer(handle, dind); + //ext4_journal_release_buffer(handle, dind); exit_primary: - //ext3_journal_release_buffer(handle, *primary); + //ext4_journal_release_buffer(handle, *primary); exit_sbh: - //ext3_journal_release_buffer(handle, *primary); + //ext4_journal_release_buffer(handle, *primary); exit_dind: brelse(dind); exit_bh: brelse(*primary); - ext3_debug("leaving with error %d\n", err); + ext4_debug("leaving with error %d\n", err); return err; } @@ -511,14 +511,14 @@ exit_bh: * backup GDT blocks are stored in their reserved primary GDT block. */ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, - struct ext3_new_group_data *input) + struct ext4_new_group_data *input) { struct super_block *sb = inode->i_sb; - int reserved_gdb =le16_to_cpu(EXT3_SB(sb)->s_es->s_reserved_gdt_blocks); + int reserved_gdb =le16_to_cpu(EXT4_SB(sb)->s_es->s_reserved_gdt_blocks); struct buffer_head **primary; struct buffer_head *dind; - struct ext3_iloc iloc; - ext3_fsblk_t blk; + struct ext4_iloc iloc; + ext4_fsblk_t blk; __le32 *data, *end; int gdbackups = 0; int res, i; @@ -528,21 +528,21 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, if (!primary) return -ENOMEM; - data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; + data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK; dind = sb_bread(sb, le32_to_cpu(*data)); if (!dind) { err = -EIO; goto exit_free; } - blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count; - data = (__le32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count; - end = (__le32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb); + blk = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + EXT4_SB(sb)->s_gdb_count; + data = (__le32 *)dind->b_data + EXT4_SB(sb)->s_gdb_count; + end = (__le32 *)dind->b_data + EXT4_ADDR_PER_BLOCK(sb); /* Get each reserved primary GDT block and verify it holds backups */ for (res = 0; res < reserved_gdb; res++, blk++) { if (le32_to_cpu(*data) != blk) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "reserved block "E3FSBLK " not at offset %ld", blk, @@ -565,24 +565,24 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, } for (i = 0; i < reserved_gdb; i++) { - if ((err = ext3_journal_get_write_access(handle, primary[i]))) { + if ((err = ext4_journal_get_write_access(handle, primary[i]))) { /* int j; for (j = 0; j < i; j++) - ext3_journal_release_buffer(handle, primary[j]); + ext4_journal_release_buffer(handle, primary[j]); */ goto exit_bh; } } - if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) + if ((err = ext4_reserve_inode_write(handle, inode, &iloc))) goto exit_bh; /* * Finally we can add each of the reserved backup GDT blocks from * the new group to its reserved primary GDT block. */ - blk = input->group * EXT3_BLOCKS_PER_GROUP(sb); + blk = input->group * EXT4_BLOCKS_PER_GROUP(sb); for (i = 0; i < reserved_gdb; i++) { int err2; data = (__le32 *)primary[i]->b_data; @@ -590,12 +590,12 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, primary[i]->b_blocknr, gdbackups, blk + primary[i]->b_blocknr); */ data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr); - err2 = ext3_journal_dirty_metadata(handle, primary[i]); + err2 = ext4_journal_dirty_metadata(handle, primary[i]); if (!err) err = err2; } inode->i_blocks += reserved_gdb * sb->s_blocksize >> 9; - ext3_mark_iloc_dirty(handle, inode, &iloc); + ext4_mark_iloc_dirty(handle, inode, &iloc); exit_bh: while (--res >= 0) @@ -609,7 +609,7 @@ exit_free: } /* - * Update the backup copies of the ext3 metadata. These don't need to be part + * Update the backup copies of the ext4 metadata. These don't need to be part * of the main resize transaction, because e2fsck will re-write them if there * is a problem (basically only OOM will cause a problem). However, we * _should_ update the backups if possible, in case the primary gets trashed @@ -626,9 +626,9 @@ exit_free: static void update_backups(struct super_block *sb, int blk_off, char *data, int size) { - struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext4_sb_info *sbi = EXT4_SB(sb); const unsigned long last = sbi->s_groups_count; - const int bpg = EXT3_BLOCKS_PER_GROUP(sb); + const int bpg = EXT4_BLOCKS_PER_GROUP(sb); unsigned three = 1; unsigned five = 5; unsigned seven = 7; @@ -637,20 +637,20 @@ static void update_backups(struct super_block *sb, handle_t *handle; int err = 0, err2; - handle = ext3_journal_start_sb(sb, EXT3_MAX_TRANS_DATA); + handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA); if (IS_ERR(handle)) { group = 1; err = PTR_ERR(handle); goto exit_err; } - while ((group = ext3_list_backups(sb, &three, &five, &seven)) < last) { + while ((group = ext4_list_backups(sb, &three, &five, &seven)) < last) { struct buffer_head *bh; /* Out of journal space, and can't get more - abort - so sad */ if (handle->h_buffer_credits == 0 && - ext3_journal_extend(handle, EXT3_MAX_TRANS_DATA) && - (err = ext3_journal_restart(handle, EXT3_MAX_TRANS_DATA))) + ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA) && + (err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) break; bh = sb_getblk(sb, group * bpg + blk_off); @@ -658,9 +658,9 @@ static void update_backups(struct super_block *sb, err = -EIO; break; } - ext3_debug("update metadata backup %#04lx\n", + ext4_debug("update metadata backup %#04lx\n", (unsigned long)bh->b_blocknr); - if ((err = ext3_journal_get_write_access(handle, bh))) + if ((err = ext4_journal_get_write_access(handle, bh))) break; lock_buffer(bh); memcpy(bh->b_data, data, size); @@ -668,10 +668,10 @@ static void update_backups(struct super_block *sb, memset(bh->b_data + size, 0, rest); set_buffer_uptodate(bh); unlock_buffer(bh); - ext3_journal_dirty_metadata(handle, bh); + ext4_journal_dirty_metadata(handle, bh); brelse(bh); } - if ((err2 = ext3_journal_stop(handle)) && !err) + if ((err2 = ext4_journal_stop(handle)) && !err) err = err2; /* @@ -686,11 +686,11 @@ static void update_backups(struct super_block *sb, */ exit_err: if (err) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "can't update backup for group %d (err %d), " "forcing fsck on next reboot", group, err); - sbi->s_mount_state &= ~EXT3_VALID_FS; - sbi->s_es->s_state &= cpu_to_le16(~EXT3_VALID_FS); + sbi->s_mount_state &= ~EXT4_VALID_FS; + sbi->s_es->s_state &= cpu_to_le16(~EXT4_VALID_FS); mark_buffer_dirty(sbi->s_sbh); } } @@ -708,51 +708,51 @@ exit_err: * not really "added" the group at all. We re-check that we are still * adding in the last group in case things have changed since verifying. */ -int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) +int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) { - struct ext3_sb_info *sbi = EXT3_SB(sb); - struct ext3_super_block *es = sbi->s_es; - int reserved_gdb = ext3_bg_has_super(sb, input->group) ? + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; + int reserved_gdb = ext4_bg_has_super(sb, input->group) ? le16_to_cpu(es->s_reserved_gdt_blocks) : 0; struct buffer_head *primary = NULL; - struct ext3_group_desc *gdp; + struct ext4_group_desc *gdp; struct inode *inode = NULL; handle_t *handle; int gdb_off, gdb_num; int err, err2; - gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); - gdb_off = input->group % EXT3_DESC_PER_BLOCK(sb); + gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb); + gdb_off = input->group % EXT4_DESC_PER_BLOCK(sb); - if (gdb_off == 0 && !EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { - ext3_warning(sb, __FUNCTION__, + if (gdb_off == 0 && !EXT4_HAS_RO_COMPAT_FEATURE(sb, + EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) { + ext4_warning(sb, __FUNCTION__, "Can't resize non-sparse filesystem further"); return -EPERM; } if (le32_to_cpu(es->s_blocks_count) + input->blocks_count < le32_to_cpu(es->s_blocks_count)) { - ext3_warning(sb, __FUNCTION__, "blocks_count overflow\n"); + ext4_warning(sb, __FUNCTION__, "blocks_count overflow\n"); return -EINVAL; } - if (le32_to_cpu(es->s_inodes_count) + EXT3_INODES_PER_GROUP(sb) < + if (le32_to_cpu(es->s_inodes_count) + EXT4_INODES_PER_GROUP(sb) < le32_to_cpu(es->s_inodes_count)) { - ext3_warning(sb, __FUNCTION__, "inodes_count overflow\n"); + ext4_warning(sb, __FUNCTION__, "inodes_count overflow\n"); return -EINVAL; } if (reserved_gdb || gdb_off == 0) { - if (!EXT3_HAS_COMPAT_FEATURE(sb, - EXT3_FEATURE_COMPAT_RESIZE_INODE)){ - ext3_warning(sb, __FUNCTION__, + if (!EXT4_HAS_COMPAT_FEATURE(sb, + EXT4_FEATURE_COMPAT_RESIZE_INODE)){ + ext4_warning(sb, __FUNCTION__, "No reserved GDT blocks, can't resize"); return -EPERM; } - inode = iget(sb, EXT3_RESIZE_INO); + inode = iget(sb, EXT4_RESIZE_INO); if (!inode || is_bad_inode(inode)) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "Error opening resize inode"); iput(inode); return -ENOENT; @@ -772,8 +772,8 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) * are adding a group with superblock/GDT backups we will also * modify each of the reserved GDT dindirect blocks. */ - handle = ext3_journal_start_sb(sb, - ext3_bg_has_super(sb, input->group) ? + handle = ext4_journal_start_sb(sb, + ext4_bg_has_super(sb, input->group) ? 3 + reserved_gdb : 4); if (IS_ERR(handle)) { err = PTR_ERR(handle); @@ -782,13 +782,13 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) lock_super(sb); if (input->group != sbi->s_groups_count) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "multiple resizers run on filesystem!"); err = -EBUSY; goto exit_journal; } - if ((err = ext3_journal_get_write_access(handle, sbi->s_sbh))) + if ((err = ext4_journal_get_write_access(handle, sbi->s_sbh))) goto exit_journal; /* @@ -799,10 +799,10 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) */ if (gdb_off) { primary = sbi->s_group_desc[gdb_num]; - if ((err = ext3_journal_get_write_access(handle, primary))) + if ((err = ext4_journal_get_write_access(handle, primary))) goto exit_journal; - if (reserved_gdb && ext3_bg_num_gdb(sb, input->group) && + if (reserved_gdb && ext4_bg_num_gdb(sb, input->group) && (err = reserve_backup_gdb(handle, inode, input))) goto exit_journal; } else if ((err = add_new_gdb(handle, inode, input, &primary))) @@ -828,13 +828,13 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) */ /* Update group descriptor block for new group */ - gdp = (struct ext3_group_desc *)primary->b_data + gdb_off; + gdp = (struct ext4_group_desc *)primary->b_data + gdb_off; gdp->bg_block_bitmap = cpu_to_le32(input->block_bitmap); gdp->bg_inode_bitmap = cpu_to_le32(input->inode_bitmap); gdp->bg_inode_table = cpu_to_le32(input->inode_table); gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); - gdp->bg_free_inodes_count = cpu_to_le16(EXT3_INODES_PER_GROUP(sb)); + gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb)); /* * Make the new blocks and inodes valid next. We do this before @@ -849,7 +849,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) es->s_blocks_count = cpu_to_le32(le32_to_cpu(es->s_blocks_count) + input->blocks_count); es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) + - EXT3_INODES_PER_GROUP(sb)); + EXT4_INODES_PER_GROUP(sb)); /* * We need to protect s_groups_count against other CPUs seeing @@ -878,7 +878,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) /* Update the global fs size fields */ sbi->s_groups_count++; - ext3_journal_dirty_metadata(handle, primary); + ext4_journal_dirty_metadata(handle, primary); /* Update the reserved block counts only once the new group is * active. */ @@ -889,42 +889,42 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) percpu_counter_mod(&sbi->s_freeblocks_counter, input->free_blocks_count); percpu_counter_mod(&sbi->s_freeinodes_counter, - EXT3_INODES_PER_GROUP(sb)); + EXT4_INODES_PER_GROUP(sb)); - ext3_journal_dirty_metadata(handle, sbi->s_sbh); + ext4_journal_dirty_metadata(handle, sbi->s_sbh); sb->s_dirt = 1; exit_journal: unlock_super(sb); - if ((err2 = ext3_journal_stop(handle)) && !err) + if ((err2 = ext4_journal_stop(handle)) && !err) err = err2; if (!err) { update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, - sizeof(struct ext3_super_block)); + sizeof(struct ext4_super_block)); update_backups(sb, primary->b_blocknr, primary->b_data, primary->b_size); } exit_put: iput(inode); return err; -} /* ext3_group_add */ +} /* ext4_group_add */ /* Extend the filesystem to the new number of blocks specified. This entry * point is only used to extend the current filesystem to the end of the last * existing group. It can be accessed via ioctl, or by "remount,resize=" * for emergencies (because it has no dependencies on reserved blocks). * - * If we _really_ wanted, we could use default values to call ext3_group_add() + * If we _really_ wanted, we could use default values to call ext4_group_add() * allow the "remount" trick to work for arbitrary resizing, assuming enough * GDT blocks are reserved to grow to the desired size. */ -int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, - ext3_fsblk_t n_blocks_count) +int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, + ext4_fsblk_t n_blocks_count) { - ext3_fsblk_t o_blocks_count; + ext4_fsblk_t o_blocks_count; unsigned long o_groups_count; - ext3_grpblk_t last; - ext3_grpblk_t add; + ext4_grpblk_t last; + ext4_grpblk_t add; struct buffer_head * bh; handle_t *handle; int err; @@ -934,45 +934,45 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, * yet: we're going to revalidate es->s_blocks_count after * taking lock_super() below. */ o_blocks_count = le32_to_cpu(es->s_blocks_count); - o_groups_count = EXT3_SB(sb)->s_groups_count; + o_groups_count = EXT4_SB(sb)->s_groups_count; if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT3-fs: extending last group from "E3FSBLK" uto "E3FSBLK" blocks\n", + printk(KERN_DEBUG "EXT4-fs: extending last group from "E3FSBLK" uto "E3FSBLK" blocks\n", o_blocks_count, n_blocks_count); if (n_blocks_count == 0 || n_blocks_count == o_blocks_count) return 0; if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { - printk(KERN_ERR "EXT3-fs: filesystem on %s:" + printk(KERN_ERR "EXT4-fs: filesystem on %s:" " too large to resize to %lu blocks safely\n", sb->s_id, n_blocks_count); if (sizeof(sector_t) < 8) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "CONFIG_LBD not enabled\n"); return -EINVAL; } if (n_blocks_count < o_blocks_count) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "can't shrink FS - resize aborted"); return -EBUSY; } /* Handle the remaining blocks in the last group only. */ last = (o_blocks_count - le32_to_cpu(es->s_first_data_block)) % - EXT3_BLOCKS_PER_GROUP(sb); + EXT4_BLOCKS_PER_GROUP(sb); if (last == 0) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "need to use ext2online to resize further"); return -EPERM; } - add = EXT3_BLOCKS_PER_GROUP(sb) - last; + add = EXT4_BLOCKS_PER_GROUP(sb) - last; if (o_blocks_count + add < o_blocks_count) { - ext3_warning(sb, __FUNCTION__, "blocks_count overflow"); + ext4_warning(sb, __FUNCTION__, "blocks_count overflow"); return -EINVAL; } @@ -980,7 +980,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, add = n_blocks_count - o_blocks_count; if (o_blocks_count + add < n_blocks_count) - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "will only finish group ("E3FSBLK " blocks, %u new)", o_blocks_count + add, add); @@ -988,55 +988,55 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, /* See if the device is actually as big as what was requested */ bh = sb_bread(sb, o_blocks_count + add -1); if (!bh) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "can't read last block, resize aborted"); return -ENOSPC; } brelse(bh); /* We will update the superblock, one block bitmap, and - * one group descriptor via ext3_free_blocks(). + * one group descriptor via ext4_free_blocks(). */ - handle = ext3_journal_start_sb(sb, 3); + handle = ext4_journal_start_sb(sb, 3); if (IS_ERR(handle)) { err = PTR_ERR(handle); - ext3_warning(sb, __FUNCTION__, "error %d on journal start",err); + ext4_warning(sb, __FUNCTION__, "error %d on journal start",err); goto exit_put; } lock_super(sb); if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) { - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "multiple resizers run on filesystem!"); unlock_super(sb); err = -EBUSY; goto exit_put; } - if ((err = ext3_journal_get_write_access(handle, - EXT3_SB(sb)->s_sbh))) { - ext3_warning(sb, __FUNCTION__, + if ((err = ext4_journal_get_write_access(handle, + EXT4_SB(sb)->s_sbh))) { + ext4_warning(sb, __FUNCTION__, "error %d on journal write access", err); unlock_super(sb); - ext3_journal_stop(handle); + ext4_journal_stop(handle); goto exit_put; } es->s_blocks_count = cpu_to_le32(o_blocks_count + add); - ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); sb->s_dirt = 1; unlock_super(sb); - ext3_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count, + ext4_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count, o_blocks_count + add); - ext3_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks); - ext3_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n", o_blocks_count, + ext4_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks); + ext4_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n", o_blocks_count, o_blocks_count + add); - if ((err = ext3_journal_stop(handle))) + if ((err = ext4_journal_stop(handle))) goto exit_put; if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT3-fs: extended group to %u blocks\n", + printk(KERN_DEBUG "EXT4-fs: extended group to %u blocks\n", le32_to_cpu(es->s_blocks_count)); - update_backups(sb, EXT3_SB(sb)->s_sbh->b_blocknr, (char *)es, - sizeof(struct ext3_super_block)); + update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, (char *)es, + sizeof(struct ext4_super_block)); exit_put: return err; -} /* ext3_group_extend */ +} /* ext4_group_extend */ diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 8bfd56ef18ca..9e32a2a8d286 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/super.c + * linux/fs/ext4/super.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -21,8 +21,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -42,25 +42,25 @@ #include "acl.h" #include "namei.h" -static int ext3_load_journal(struct super_block *, struct ext3_super_block *, +static int ext4_load_journal(struct super_block *, struct ext4_super_block *, unsigned long journal_devnum); -static int ext3_create_journal(struct super_block *, struct ext3_super_block *, +static int ext4_create_journal(struct super_block *, struct ext4_super_block *, unsigned int); -static void ext3_commit_super (struct super_block * sb, - struct ext3_super_block * es, +static void ext4_commit_super (struct super_block * sb, + struct ext4_super_block * es, int sync); -static void ext3_mark_recovery_complete(struct super_block * sb, - struct ext3_super_block * es); -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, +static void ext4_mark_recovery_complete(struct super_block * sb, + struct ext4_super_block * es); +static void ext4_clear_journal_err(struct super_block * sb, + struct ext4_super_block * es); +static int ext4_sync_fs(struct super_block *sb, int wait); +static const char *ext4_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 dentry * dentry, 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); +static int ext4_remount (struct super_block * sb, int * flags, char * data); +static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf); +static void ext4_unlockfs(struct super_block *sb); +static void ext4_write_super (struct super_block * sb); +static void ext4_write_super_lockfs(struct super_block *sb); /* * Wrappers for journal_start/end. @@ -70,7 +70,7 @@ static void ext3_write_super_lockfs(struct super_block *sb); * that sync() will call the filesystem's write_super callback if * appropriate. */ -handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks) +handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) { journal_t *journal; @@ -80,9 +80,9 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks) /* Special case here: if the journal has aborted behind our * backs (eg. EIO in the commit thread), then we still need to * take the FS itself readonly cleanly. */ - journal = EXT3_SB(sb)->s_journal; + journal = EXT4_SB(sb)->s_journal; if (is_journal_aborted(journal)) { - ext3_abort(sb, __FUNCTION__, + ext4_abort(sb, __FUNCTION__, "Detected aborted journal"); return ERR_PTR(-EROFS); } @@ -96,7 +96,7 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks) * that sync() will call the filesystem's write_super callback if * appropriate. */ -int __ext3_journal_stop(const char *where, handle_t *handle) +int __ext4_journal_stop(const char *where, handle_t *handle) { struct super_block *sb; int err; @@ -109,15 +109,15 @@ int __ext3_journal_stop(const char *where, handle_t *handle) if (!err) err = rc; if (err) - __ext3_std_error(sb, where, err); + __ext4_std_error(sb, where, err); return err; } -void ext3_journal_abort_handle(const char *caller, const char *err_fn, +void ext4_journal_abort_handle(const char *caller, const char *err_fn, struct buffer_head *bh, handle_t *handle, int err) { char nbuf[16]; - const char *errstr = ext3_decode_error(NULL, err, nbuf); + const char *errstr = ext4_decode_error(NULL, err, nbuf); if (bh) BUFFER_TRACE(bh, "abort"); @@ -138,7 +138,7 @@ void ext3_journal_abort_handle(const char *caller, const char *err_fn, * inconsistencies detected or read IO failures. * * On ext2, we can store the error state of the filesystem in the - * superblock. That is not possible on ext3, because we may have other + * superblock. That is not possible on ext4, because we may have other * write ordering constraints on the superblock which prevent us from * writing it out straight away; and given that the journal is about to * be aborted, we can't rely on the current, or future, transactions to @@ -149,20 +149,20 @@ void ext3_journal_abort_handle(const char *caller, const char *err_fn, * that error until we've noted it down and cleared it. */ -static void ext3_handle_error(struct super_block *sb) +static void ext4_handle_error(struct super_block *sb) { - struct ext3_super_block *es = EXT3_SB(sb)->s_es; + struct ext4_super_block *es = EXT4_SB(sb)->s_es; - EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; - es->s_state |= cpu_to_le16(EXT3_ERROR_FS); + EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; + es->s_state |= cpu_to_le16(EXT4_ERROR_FS); if (sb->s_flags & MS_RDONLY) return; if (!test_opt (sb, ERRORS_CONT)) { - journal_t *journal = EXT3_SB(sb)->s_journal; + journal_t *journal = EXT4_SB(sb)->s_journal; - EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT; + EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; if (journal) journal_abort(journal, -EIO); } @@ -170,27 +170,27 @@ static void ext3_handle_error(struct super_block *sb) printk (KERN_CRIT "Remounting filesystem read-only\n"); sb->s_flags |= MS_RDONLY; } - ext3_commit_super(sb, es, 1); + ext4_commit_super(sb, es, 1); if (test_opt(sb, ERRORS_PANIC)) - panic("EXT3-fs (device %s): panic forced after error\n", + panic("EXT4-fs (device %s): panic forced after error\n", sb->s_id); } -void ext3_error (struct super_block * sb, const char * function, +void ext4_error (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); + printk(KERN_CRIT "EXT4-fs error (device %s): %s: ",sb->s_id, function); vprintk(fmt, args); printk("\n"); va_end(args); - ext3_handle_error(sb); + ext4_handle_error(sb); } -static const char *ext3_decode_error(struct super_block * sb, int errno, +static const char *ext4_decode_error(struct super_block * sb, int errno, char nbuf[16]) { char *errstr = NULL; @@ -203,7 +203,7 @@ static const char *ext3_decode_error(struct super_block * sb, int errno, errstr = "Out of memory"; break; case -EROFS: - if (!sb || EXT3_SB(sb)->s_journal->j_flags & JFS_ABORT) + if (!sb || EXT4_SB(sb)->s_journal->j_flags & JFS_ABORT) errstr = "Journal has aborted"; else errstr = "Readonly filesystem"; @@ -223,10 +223,10 @@ static const char *ext3_decode_error(struct super_block * sb, int errno, return errstr; } -/* __ext3_std_error decodes expected errors from journaling functions +/* __ext4_std_error decodes expected errors from journaling functions * automatically and invokes the appropriate error response. */ -void __ext3_std_error (struct super_block * sb, const char * function, +void __ext4_std_error (struct super_block * sb, const char * function, int errno) { char nbuf[16]; @@ -239,15 +239,15 @@ void __ext3_std_error (struct super_block * sb, const char * function, (sb->s_flags & MS_RDONLY)) return; - errstr = ext3_decode_error(sb, errno, nbuf); - printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n", + errstr = ext4_decode_error(sb, errno, nbuf); + printk (KERN_CRIT "EXT4-fs error (device %s) in %s: %s\n", sb->s_id, function, errstr); - ext3_handle_error(sb); + ext4_handle_error(sb); } /* - * ext3_abort is a much stronger failure handler than ext3_error. The + * ext4_abort is a much stronger failure handler than ext4_error. The * abort function may be used to deal with unrecoverable failures such * as journal IO errors or ENOMEM at a critical moment in log management. * @@ -256,60 +256,60 @@ void __ext3_std_error (struct super_block * sb, const char * function, * case we take the easy way out and panic immediately. */ -void ext3_abort (struct super_block * sb, const char * function, +void ext4_abort (struct super_block * sb, const char * function, const char * fmt, ...) { va_list args; - printk (KERN_CRIT "ext3_abort called.\n"); + printk (KERN_CRIT "ext4_abort called.\n"); va_start(args, fmt); - printk(KERN_CRIT "EXT3-fs error (device %s): %s: ",sb->s_id, function); + printk(KERN_CRIT "EXT4-fs error (device %s): %s: ",sb->s_id, function); vprintk(fmt, args); printk("\n"); va_end(args); if (test_opt(sb, ERRORS_PANIC)) - panic("EXT3-fs panic from previous error\n"); + panic("EXT4-fs panic from previous error\n"); if (sb->s_flags & MS_RDONLY) return; printk(KERN_CRIT "Remounting filesystem read-only\n"); - EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; + EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; sb->s_flags |= MS_RDONLY; - EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT; - journal_abort(EXT3_SB(sb)->s_journal, -EIO); + EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; + journal_abort(EXT4_SB(sb)->s_journal, -EIO); } -void ext3_warning (struct super_block * sb, const char * function, +void ext4_warning (struct super_block * sb, const char * function, const char * fmt, ...) { va_list args; va_start(args, fmt); - printk(KERN_WARNING "EXT3-fs warning (device %s): %s: ", + printk(KERN_WARNING "EXT4-fs warning (device %s): %s: ", sb->s_id, function); vprintk(fmt, args); printk("\n"); va_end(args); } -void ext3_update_dynamic_rev(struct super_block *sb) +void ext4_update_dynamic_rev(struct super_block *sb) { - struct ext3_super_block *es = EXT3_SB(sb)->s_es; + struct ext4_super_block *es = EXT4_SB(sb)->s_es; - if (le32_to_cpu(es->s_rev_level) > EXT3_GOOD_OLD_REV) + if (le32_to_cpu(es->s_rev_level) > EXT4_GOOD_OLD_REV) return; - ext3_warning(sb, __FUNCTION__, + ext4_warning(sb, __FUNCTION__, "updating to rev %d because of new feature flag, " "running e2fsck is recommended", - EXT3_DYNAMIC_REV); + EXT4_DYNAMIC_REV); - es->s_first_ino = cpu_to_le32(EXT3_GOOD_OLD_FIRST_INO); - es->s_inode_size = cpu_to_le16(EXT3_GOOD_OLD_INODE_SIZE); - es->s_rev_level = cpu_to_le32(EXT3_DYNAMIC_REV); + es->s_first_ino = cpu_to_le32(EXT4_GOOD_OLD_FIRST_INO); + es->s_inode_size = cpu_to_le16(EXT4_GOOD_OLD_INODE_SIZE); + es->s_rev_level = cpu_to_le32(EXT4_DYNAMIC_REV); /* leave es->s_feature_*compat flags alone */ /* es->s_uuid will be set by e2fsck if empty */ @@ -323,7 +323,7 @@ void ext3_update_dynamic_rev(struct super_block *sb) /* * Open the external journal device */ -static struct block_device *ext3_blkdev_get(dev_t dev) +static struct block_device *ext4_blkdev_get(dev_t dev) { struct block_device *bdev; char b[BDEVNAME_SIZE]; @@ -334,7 +334,7 @@ static struct block_device *ext3_blkdev_get(dev_t dev) return bdev; fail: - printk(KERN_ERR "EXT3: failed to open journal device %s: %ld\n", + printk(KERN_ERR "EXT4: failed to open journal device %s: %ld\n", __bdevname(dev, b), PTR_ERR(bdev)); return NULL; } @@ -342,20 +342,20 @@ fail: /* * Release the journal device */ -static int ext3_blkdev_put(struct block_device *bdev) +static int ext4_blkdev_put(struct block_device *bdev) { bd_release(bdev); return blkdev_put(bdev); } -static int ext3_blkdev_remove(struct ext3_sb_info *sbi) +static int ext4_blkdev_remove(struct ext4_sb_info *sbi) { struct block_device *bdev; int ret = -ENODEV; bdev = sbi->journal_bdev; if (bdev) { - ret = ext3_blkdev_put(bdev); + ret = ext4_blkdev_put(bdev); sbi->journal_bdev = NULL; } return ret; @@ -363,10 +363,10 @@ static int ext3_blkdev_remove(struct ext3_sb_info *sbi) static inline struct inode *orphan_list_entry(struct list_head *l) { - return &list_entry(l, struct ext3_inode_info, i_orphan)->vfs_inode; + return &list_entry(l, struct ext4_inode_info, i_orphan)->vfs_inode; } -static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi) +static void dump_orphan_list(struct super_block *sb, struct ext4_sb_info *sbi) { struct list_head *l; @@ -384,20 +384,20 @@ static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi) } } -static void ext3_put_super (struct super_block * sb) +static void ext4_put_super (struct super_block * sb) { - struct ext3_sb_info *sbi = EXT3_SB(sb); - struct ext3_super_block *es = sbi->s_es; + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; int i; - ext3_xattr_put_super(sb); + ext4_xattr_put_super(sb); journal_destroy(sbi->s_journal); if (!(sb->s_flags & MS_RDONLY)) { - EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); es->s_state = cpu_to_le16(sbi->s_mount_state); BUFFER_TRACE(sbi->s_sbh, "marking dirty"); mark_buffer_dirty(sbi->s_sbh); - ext3_commit_super(sb, es, 1); + ext4_commit_super(sb, es, 1); } for (i = 0; i < sbi->s_gdb_count; i++) @@ -429,47 +429,47 @@ static void ext3_put_super (struct super_block * sb) */ sync_blockdev(sbi->journal_bdev); invalidate_bdev(sbi->journal_bdev, 0); - ext3_blkdev_remove(sbi); + ext4_blkdev_remove(sbi); } sb->s_fs_info = NULL; kfree(sbi); return; } -static kmem_cache_t *ext3_inode_cachep; +static kmem_cache_t *ext4_inode_cachep; /* * Called inside transaction, so use GFP_NOFS */ -static struct inode *ext3_alloc_inode(struct super_block *sb) +static struct inode *ext4_alloc_inode(struct super_block *sb) { - struct ext3_inode_info *ei; + struct ext4_inode_info *ei; - ei = kmem_cache_alloc(ext3_inode_cachep, SLAB_NOFS); + ei = kmem_cache_alloc(ext4_inode_cachep, SLAB_NOFS); if (!ei) return NULL; -#ifdef CONFIG_EXT3_FS_POSIX_ACL - ei->i_acl = EXT3_ACL_NOT_CACHED; - ei->i_default_acl = EXT3_ACL_NOT_CACHED; +#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL + ei->i_acl = EXT4_ACL_NOT_CACHED; + ei->i_default_acl = EXT4_ACL_NOT_CACHED; #endif ei->i_block_alloc_info = NULL; ei->vfs_inode.i_version = 1; return &ei->vfs_inode; } -static void ext3_destroy_inode(struct inode *inode) +static void ext4_destroy_inode(struct inode *inode) { - kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); + kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); } static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) { - struct ext3_inode_info *ei = (struct ext3_inode_info *) foo; + struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { INIT_LIST_HEAD(&ei->i_orphan); -#ifdef CONFIG_EXT3_FS_XATTR +#ifdef CONFIG_EXT4DEV_FS_XATTR init_rwsem(&ei->xattr_sem); #endif mutex_init(&ei->truncate_mutex); @@ -479,46 +479,46 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) static int init_inodecache(void) { - ext3_inode_cachep = kmem_cache_create("ext3_inode_cache", - sizeof(struct ext3_inode_info), + ext4_inode_cachep = kmem_cache_create("ext4_inode_cache", + sizeof(struct ext4_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), init_once, NULL); - if (ext3_inode_cachep == NULL) + if (ext4_inode_cachep == NULL) return -ENOMEM; return 0; } static void destroy_inodecache(void) { - kmem_cache_destroy(ext3_inode_cachep); + kmem_cache_destroy(ext4_inode_cachep); } -static void ext3_clear_inode(struct inode *inode) +static void ext4_clear_inode(struct inode *inode) { - struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info; -#ifdef CONFIG_EXT3_FS_POSIX_ACL - if (EXT3_I(inode)->i_acl && - EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) { - posix_acl_release(EXT3_I(inode)->i_acl); - EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED; - } - if (EXT3_I(inode)->i_default_acl && - EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) { - posix_acl_release(EXT3_I(inode)->i_default_acl); - EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED; + struct ext4_block_alloc_info *rsv = EXT4_I(inode)->i_block_alloc_info; +#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL + if (EXT4_I(inode)->i_acl && + EXT4_I(inode)->i_acl != EXT4_ACL_NOT_CACHED) { + posix_acl_release(EXT4_I(inode)->i_acl); + EXT4_I(inode)->i_acl = EXT4_ACL_NOT_CACHED; + } + if (EXT4_I(inode)->i_default_acl && + EXT4_I(inode)->i_default_acl != EXT4_ACL_NOT_CACHED) { + posix_acl_release(EXT4_I(inode)->i_default_acl); + EXT4_I(inode)->i_default_acl = EXT4_ACL_NOT_CACHED; } #endif - ext3_discard_reservation(inode); - EXT3_I(inode)->i_block_alloc_info = NULL; + ext4_discard_reservation(inode); + EXT4_I(inode)->i_block_alloc_info = NULL; if (unlikely(rsv)) kfree(rsv); } -static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb) +static inline void ext4_show_quota_options(struct seq_file *seq, struct super_block *sb) { #if defined(CONFIG_QUOTA) - struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext4_sb_info *sbi = EXT4_SB(sb); if (sbi->s_jquota_fmt) seq_printf(seq, ",jqfmt=%s", @@ -530,32 +530,32 @@ static inline void ext3_show_quota_options(struct seq_file *seq, struct super_bl if (sbi->s_qf_names[GRPQUOTA]) seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); - if (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA) + if (sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA) seq_puts(seq, ",usrquota"); - if (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) + if (sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA) seq_puts(seq, ",grpquota"); #endif } -static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) +static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) { struct super_block *sb = vfs->mnt_sb; - if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) + if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) seq_puts(seq, ",data=journal"); - else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA) + else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) seq_puts(seq, ",data=ordered"); - else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) + else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) seq_puts(seq, ",data=writeback"); - ext3_show_quota_options(seq, sb); + ext4_show_quota_options(seq, sb); return 0; } -static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp) +static struct dentry *ext4_get_dentry(struct super_block *sb, void *vobjp) { __u32 *objp = vobjp; unsigned long ino = objp[0]; @@ -563,14 +563,14 @@ static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp) struct inode *inode; struct dentry *result; - if (ino < EXT3_FIRST_INO(sb) && ino != EXT3_ROOT_INO) + if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO) return ERR_PTR(-ESTALE); - if (ino > le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)) + if (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)) return ERR_PTR(-ESTALE); /* iget isn't really right if the inode is currently unallocated!! * - * ext3_read_inode will return a bad_inode if the inode had been + * ext4_read_inode will return a bad_inode if the inode had been * deleted, so we should be safe. * * Currently we don't know the generation for parent directory, so @@ -599,37 +599,37 @@ static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp) #define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group") #define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) -static int ext3_dquot_initialize(struct inode *inode, int type); -static int ext3_dquot_drop(struct inode *inode); -static int ext3_write_dquot(struct dquot *dquot); -static int ext3_acquire_dquot(struct dquot *dquot); -static int ext3_release_dquot(struct dquot *dquot); -static int ext3_mark_dquot_dirty(struct dquot *dquot); -static int ext3_write_info(struct super_block *sb, int type); -static int ext3_quota_on(struct super_block *sb, int type, int format_id, char *path); -static int ext3_quota_on_mount(struct super_block *sb, int type); -static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, +static int ext4_dquot_initialize(struct inode *inode, int type); +static int ext4_dquot_drop(struct inode *inode); +static int ext4_write_dquot(struct dquot *dquot); +static int ext4_acquire_dquot(struct dquot *dquot); +static int ext4_release_dquot(struct dquot *dquot); +static int ext4_mark_dquot_dirty(struct dquot *dquot); +static int ext4_write_info(struct super_block *sb, int type); +static int ext4_quota_on(struct super_block *sb, int type, int format_id, char *path); +static int ext4_quota_on_mount(struct super_block *sb, int type); +static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off); -static ssize_t ext3_quota_write(struct super_block *sb, int type, +static ssize_t ext4_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off); -static struct dquot_operations ext3_quota_operations = { - .initialize = ext3_dquot_initialize, - .drop = ext3_dquot_drop, +static struct dquot_operations ext4_quota_operations = { + .initialize = ext4_dquot_initialize, + .drop = ext4_dquot_drop, .alloc_space = dquot_alloc_space, .alloc_inode = dquot_alloc_inode, .free_space = dquot_free_space, .free_inode = dquot_free_inode, .transfer = dquot_transfer, - .write_dquot = ext3_write_dquot, - .acquire_dquot = ext3_acquire_dquot, - .release_dquot = ext3_release_dquot, - .mark_dirty = ext3_mark_dquot_dirty, - .write_info = ext3_write_info + .write_dquot = ext4_write_dquot, + .acquire_dquot = ext4_acquire_dquot, + .release_dquot = ext4_release_dquot, + .mark_dirty = ext4_mark_dquot_dirty, + .write_info = ext4_write_info }; -static struct quotactl_ops ext3_qctl_operations = { - .quota_on = ext3_quota_on, +static struct quotactl_ops ext4_qctl_operations = { + .quota_on = ext4_quota_on, .quota_off = vfs_quota_off, .quota_sync = vfs_quota_sync, .get_info = vfs_get_dqinfo, @@ -639,31 +639,31 @@ static struct quotactl_ops ext3_qctl_operations = { }; #endif -static struct super_operations ext3_sops = { - .alloc_inode = ext3_alloc_inode, - .destroy_inode = ext3_destroy_inode, - .read_inode = ext3_read_inode, - .write_inode = ext3_write_inode, - .dirty_inode = ext3_dirty_inode, - .delete_inode = ext3_delete_inode, - .put_super = ext3_put_super, - .write_super = ext3_write_super, - .sync_fs = ext3_sync_fs, - .write_super_lockfs = ext3_write_super_lockfs, - .unlockfs = ext3_unlockfs, - .statfs = ext3_statfs, - .remount_fs = ext3_remount, - .clear_inode = ext3_clear_inode, - .show_options = ext3_show_options, +static struct super_operations ext4_sops = { + .alloc_inode = ext4_alloc_inode, + .destroy_inode = ext4_destroy_inode, + .read_inode = ext4_read_inode, + .write_inode = ext4_write_inode, + .dirty_inode = ext4_dirty_inode, + .delete_inode = ext4_delete_inode, + .put_super = ext4_put_super, + .write_super = ext4_write_super, + .sync_fs = ext4_sync_fs, + .write_super_lockfs = ext4_write_super_lockfs, + .unlockfs = ext4_unlockfs, + .statfs = ext4_statfs, + .remount_fs = ext4_remount, + .clear_inode = ext4_clear_inode, + .show_options = ext4_show_options, #ifdef CONFIG_QUOTA - .quota_read = ext3_quota_read, - .quota_write = ext3_quota_write, + .quota_read = ext4_quota_read, + .quota_write = ext4_quota_write, #endif }; -static struct export_operations ext3_export_ops = { - .get_parent = ext3_get_parent, - .get_dentry = ext3_get_dentry, +static struct export_operations ext4_export_ops = { + .get_parent = ext4_get_parent, + .get_dentry = ext4_get_dentry, }; enum { @@ -731,18 +731,18 @@ static match_table_t tokens = { {Opt_resize, "resize"}, }; -static ext3_fsblk_t get_sb_block(void **data) +static ext4_fsblk_t get_sb_block(void **data) { - ext3_fsblk_t sb_block; + ext4_fsblk_t sb_block; char *options = (char *) *data; if (!options || strncmp(options, "sb=", 3) != 0) return 1; /* Default location */ options += 3; - /*todo: use simple_strtoll with >32bit ext3 */ + /*todo: use simple_strtoll with >32bit ext4 */ sb_block = simple_strtoul(options, &options, 0); if (*options && *options != ',') { - printk("EXT3-fs: Invalid sb specification: %s\n", + printk("EXT4-fs: Invalid sb specification: %s\n", (char *) *data); return 1; } @@ -754,9 +754,9 @@ static ext3_fsblk_t get_sb_block(void **data) static int parse_options (char *options, struct super_block *sb, unsigned int *inum, unsigned long *journal_devnum, - ext3_fsblk_t *n_blocks_count, int is_remount) + ext4_fsblk_t *n_blocks_count, int is_remount) { - struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext4_sb_info *sbi = EXT4_SB(sb); char * p; substring_t args[MAX_OPT_ARGS]; int data_opt = 0; @@ -832,7 +832,7 @@ static int parse_options (char *options, struct super_block *sb, case Opt_orlov: clear_opt (sbi->s_mount_opt, OLDALLOC); break; -#ifdef CONFIG_EXT3_FS_XATTR +#ifdef CONFIG_EXT4DEV_FS_XATTR case Opt_user_xattr: set_opt (sbi->s_mount_opt, XATTR_USER); break; @@ -842,10 +842,10 @@ static int parse_options (char *options, struct super_block *sb, #else case Opt_user_xattr: case Opt_nouser_xattr: - printk("EXT3 (no)user_xattr options not supported\n"); + printk("EXT4 (no)user_xattr options not supported\n"); break; #endif -#ifdef CONFIG_EXT3_FS_POSIX_ACL +#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL case Opt_acl: set_opt(sbi->s_mount_opt, POSIX_ACL); break; @@ -855,7 +855,7 @@ static int parse_options (char *options, struct super_block *sb, #else case Opt_acl: case Opt_noacl: - printk("EXT3 (no)acl options not supported\n"); + printk("EXT4 (no)acl options not supported\n"); break; #endif case Opt_reservation: @@ -871,7 +871,7 @@ static int parse_options (char *options, struct super_block *sb, user to specify an existing inode to be the journal file. */ if (is_remount) { - printk(KERN_ERR "EXT3-fs: cannot specify " + printk(KERN_ERR "EXT4-fs: cannot specify " "journal on remount\n"); return 0; } @@ -879,7 +879,7 @@ static int parse_options (char *options, struct super_block *sb, break; case Opt_journal_inum: if (is_remount) { - printk(KERN_ERR "EXT3-fs: cannot specify " + printk(KERN_ERR "EXT4-fs: cannot specify " "journal on remount\n"); return 0; } @@ -889,7 +889,7 @@ static int parse_options (char *options, struct super_block *sb, break; case Opt_journal_dev: if (is_remount) { - printk(KERN_ERR "EXT3-fs: cannot specify " + printk(KERN_ERR "EXT4-fs: cannot specify " "journal on remount\n"); return 0; } @@ -910,24 +910,24 @@ static int parse_options (char *options, struct super_block *sb, sbi->s_commit_interval = HZ * option; break; case Opt_data_journal: - data_opt = EXT3_MOUNT_JOURNAL_DATA; + data_opt = EXT4_MOUNT_JOURNAL_DATA; goto datacheck; case Opt_data_ordered: - data_opt = EXT3_MOUNT_ORDERED_DATA; + data_opt = EXT4_MOUNT_ORDERED_DATA; goto datacheck; case Opt_data_writeback: - data_opt = EXT3_MOUNT_WRITEBACK_DATA; + data_opt = EXT4_MOUNT_WRITEBACK_DATA; datacheck: if (is_remount) { - if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS) + if ((sbi->s_mount_opt & EXT4_MOUNT_DATA_FLAGS) != data_opt) { printk(KERN_ERR - "EXT3-fs: cannot change data " + "EXT4-fs: cannot change data " "mode on remount\n"); return 0; } } else { - sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS; + sbi->s_mount_opt &= ~EXT4_MOUNT_DATA_FLAGS; sbi->s_mount_opt |= data_opt; } break; @@ -940,21 +940,21 @@ static int parse_options (char *options, struct super_block *sb, set_qf_name: if (sb_any_quota_enabled(sb)) { printk(KERN_ERR - "EXT3-fs: Cannot change journalled " + "EXT4-fs: Cannot change journalled " "quota options when quota turned on.\n"); return 0; } qname = match_strdup(&args[0]); if (!qname) { printk(KERN_ERR - "EXT3-fs: not enough memory for " + "EXT4-fs: not enough memory for " "storing quotafile name.\n"); return 0; } if (sbi->s_qf_names[qtype] && strcmp(sbi->s_qf_names[qtype], qname)) { printk(KERN_ERR - "EXT3-fs: %s quota file already " + "EXT4-fs: %s quota file already " "specified.\n", QTYPE2NAME(qtype)); kfree(qname); return 0; @@ -962,7 +962,7 @@ set_qf_name: sbi->s_qf_names[qtype] = qname; if (strchr(sbi->s_qf_names[qtype], '/')) { printk(KERN_ERR - "EXT3-fs: quotafile must be on " + "EXT4-fs: quotafile must be on " "filesystem root.\n"); kfree(sbi->s_qf_names[qtype]); sbi->s_qf_names[qtype] = NULL; @@ -977,7 +977,7 @@ set_qf_name: qtype = GRPQUOTA; clear_qf_name: if (sb_any_quota_enabled(sb)) { - printk(KERN_ERR "EXT3-fs: Cannot change " + printk(KERN_ERR "EXT4-fs: Cannot change " "journalled quota options when " "quota turned on.\n"); return 0; @@ -1005,7 +1005,7 @@ clear_qf_name: break; case Opt_noquota: if (sb_any_quota_enabled(sb)) { - printk(KERN_ERR "EXT3-fs: Cannot change quota " + printk(KERN_ERR "EXT4-fs: Cannot change quota " "options when quota turned on.\n"); return 0; } @@ -1024,7 +1024,7 @@ clear_qf_name: case Opt_jqfmt_vfsold: case Opt_jqfmt_vfsv0: printk(KERN_ERR - "EXT3-fs: journalled quota options not " + "EXT4-fs: journalled quota options not " "supported.\n"); break; case Opt_noquota: @@ -1045,7 +1045,7 @@ clear_qf_name: break; case Opt_resize: if (!is_remount) { - printk("EXT3-fs: resize option only available " + printk("EXT4-fs: resize option only available " "for remount\n"); return 0; } @@ -1061,38 +1061,38 @@ clear_qf_name: break; default: printk (KERN_ERR - "EXT3-fs: Unrecognized mount option \"%s\" " + "EXT4-fs: Unrecognized mount option \"%s\" " "or missing value\n", p); return 0; } } #ifdef CONFIG_QUOTA if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) { - if ((sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA) && + if ((sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA) && sbi->s_qf_names[USRQUOTA]) clear_opt(sbi->s_mount_opt, USRQUOTA); - if ((sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) && + if ((sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA) && sbi->s_qf_names[GRPQUOTA]) clear_opt(sbi->s_mount_opt, GRPQUOTA); if ((sbi->s_qf_names[USRQUOTA] && - (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)) || + (sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA)) || (sbi->s_qf_names[GRPQUOTA] && - (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA))) { - printk(KERN_ERR "EXT3-fs: old and new quota " + (sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA))) { + printk(KERN_ERR "EXT4-fs: old and new quota " "format mixing.\n"); return 0; } if (!sbi->s_jquota_fmt) { - printk(KERN_ERR "EXT3-fs: journalled quota format " + printk(KERN_ERR "EXT4-fs: journalled quota format " "not specified.\n"); return 0; } } else { if (sbi->s_jquota_fmt) { - printk(KERN_ERR "EXT3-fs: journalled quota format " + printk(KERN_ERR "EXT4-fs: journalled quota format " "specified with no journalling " "enabled.\n"); return 0; @@ -1102,68 +1102,68 @@ clear_qf_name: return 1; } -static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, +static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, int read_only) { - struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext4_sb_info *sbi = EXT4_SB(sb); int res = 0; - if (le32_to_cpu(es->s_rev_level) > EXT3_MAX_SUPP_REV) { - printk (KERN_ERR "EXT3-fs warning: revision level too high, " + if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) { + printk (KERN_ERR "EXT4-fs warning: revision level too high, " "forcing read-only mode\n"); res = MS_RDONLY; } if (read_only) return res; - if (!(sbi->s_mount_state & EXT3_VALID_FS)) - printk (KERN_WARNING "EXT3-fs warning: mounting unchecked fs, " + if (!(sbi->s_mount_state & EXT4_VALID_FS)) + printk (KERN_WARNING "EXT4-fs warning: mounting unchecked fs, " "running e2fsck is recommended\n"); - else if ((sbi->s_mount_state & EXT3_ERROR_FS)) + else if ((sbi->s_mount_state & EXT4_ERROR_FS)) printk (KERN_WARNING - "EXT3-fs warning: mounting fs with errors, " + "EXT4-fs warning: mounting fs with errors, " "running e2fsck is recommended\n"); else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && le16_to_cpu(es->s_mnt_count) >= (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) printk (KERN_WARNING - "EXT3-fs warning: maximal mount count reached, " + "EXT4-fs warning: maximal mount count reached, " "running e2fsck is recommended\n"); else if (le32_to_cpu(es->s_checkinterval) && (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= get_seconds())) printk (KERN_WARNING - "EXT3-fs warning: checktime reached, " + "EXT4-fs warning: checktime reached, " "running e2fsck is recommended\n"); #if 0 /* @@@ We _will_ want to clear the valid bit if we find inconsistencies, to force a fsck at reboot. But for a plain journaled filesystem we can keep it set as valid forever! :) */ - es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT3_VALID_FS); + es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT4_VALID_FS); #endif if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) - es->s_max_mnt_count = cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT); + es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT); es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); es->s_mtime = cpu_to_le32(get_seconds()); - ext3_update_dynamic_rev(sb); - EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + ext4_update_dynamic_rev(sb); + EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); - ext3_commit_super(sb, es, 1); + ext4_commit_super(sb, es, 1); if (test_opt(sb, DEBUG)) - printk(KERN_INFO "[EXT3 FS bs=%lu, gc=%lu, " + printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%lu, " "bpg=%lu, ipg=%lu, mo=%04lx]\n", sb->s_blocksize, sbi->s_groups_count, - EXT3_BLOCKS_PER_GROUP(sb), - EXT3_INODES_PER_GROUP(sb), + EXT4_BLOCKS_PER_GROUP(sb), + EXT4_INODES_PER_GROUP(sb), sbi->s_mount_opt); - printk(KERN_INFO "EXT3 FS on %s, ", sb->s_id); - if (EXT3_SB(sb)->s_journal->j_inode == NULL) { + printk(KERN_INFO "EXT4 FS on %s, ", sb->s_id); + if (EXT4_SB(sb)->s_journal->j_inode == NULL) { char b[BDEVNAME_SIZE]; printk("external journal on %s\n", - bdevname(EXT3_SB(sb)->s_journal->j_dev, b)); + bdevname(EXT4_SB(sb)->s_journal->j_dev, b)); } else { printk("internal journal\n"); } @@ -1171,16 +1171,16 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, } /* Called at mount-time, super-block is locked */ -static int ext3_check_descriptors (struct super_block * sb) +static int ext4_check_descriptors (struct super_block * sb) { - struct ext3_sb_info *sbi = EXT3_SB(sb); - ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); - ext3_fsblk_t last_block; - struct ext3_group_desc * gdp = NULL; + struct ext4_sb_info *sbi = EXT4_SB(sb); + ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); + ext4_fsblk_t last_block; + struct ext4_group_desc * gdp = NULL; int desc_block = 0; int i; - ext3_debug ("Checking group descriptors"); + ext4_debug ("Checking group descriptors"); for (i = 0; i < sbi->s_groups_count; i++) { @@ -1188,15 +1188,15 @@ static int ext3_check_descriptors (struct super_block * sb) last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; else last_block = first_block + - (EXT3_BLOCKS_PER_GROUP(sb) - 1); + (EXT4_BLOCKS_PER_GROUP(sb) - 1); - if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0) - gdp = (struct ext3_group_desc *) + if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0) + gdp = (struct ext4_group_desc *) sbi->s_group_desc[desc_block++]->b_data; if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || le32_to_cpu(gdp->bg_block_bitmap) > last_block) { - ext3_error (sb, "ext3_check_descriptors", + ext4_error (sb, "ext4_check_descriptors", "Block bitmap for group %d" " not in group (block %lu)!", i, (unsigned long) @@ -1206,7 +1206,7 @@ static int ext3_check_descriptors (struct super_block * sb) if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || le32_to_cpu(gdp->bg_inode_bitmap) > last_block) { - ext3_error (sb, "ext3_check_descriptors", + ext4_error (sb, "ext4_check_descriptors", "Inode bitmap for group %d" " not in group (block %lu)!", i, (unsigned long) @@ -1217,24 +1217,24 @@ static int ext3_check_descriptors (struct super_block * sb) le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group > last_block) { - ext3_error (sb, "ext3_check_descriptors", + ext4_error (sb, "ext4_check_descriptors", "Inode table for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_inode_table)); return 0; } - first_block += EXT3_BLOCKS_PER_GROUP(sb); + first_block += EXT4_BLOCKS_PER_GROUP(sb); gdp++; } - sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb)); - sbi->s_es->s_free_inodes_count=cpu_to_le32(ext3_count_free_inodes(sb)); + sbi->s_es->s_free_blocks_count=cpu_to_le32(ext4_count_free_blocks(sb)); + sbi->s_es->s_free_inodes_count=cpu_to_le32(ext4_count_free_inodes(sb)); return 1; } -/* ext3_orphan_cleanup() walks a singly-linked list of inodes (starting at +/* ext4_orphan_cleanup() walks a singly-linked list of inodes (starting at * the superblock) which were deleted from all directories, but held open by * a process at the time of a crash. We walk the list and try to delete these * inodes at recovery time (only with a read-write filesystem). @@ -1247,12 +1247,12 @@ static int ext3_check_descriptors (struct super_block * sb) * We only do an iget() and an iput() on each inode, which is very safe if we * accidentally point at an in-use or already deleted inode. The worst that * can happen in this case is that we get a "bit already cleared" message from - * ext3_free_inode(). The only reason we would point at a wrong inode is if + * ext4_free_inode(). The only reason we would point at a wrong inode is if * e2fsck was run on this filesystem, and it must have already done the orphan * inode cleanup for us, so we can safely abort without any further action. */ -static void ext3_orphan_cleanup (struct super_block * sb, - struct ext3_super_block * es) +static void ext4_orphan_cleanup (struct super_block * sb, + struct ext4_super_block * es) { unsigned int s_flags = sb->s_flags; int nr_orphans = 0, nr_truncates = 0; @@ -1264,7 +1264,7 @@ static void ext3_orphan_cleanup (struct super_block * sb, return; } - if (EXT3_SB(sb)->s_mount_state & EXT3_ERROR_FS) { + if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { if (es->s_last_orphan) jbd_debug(1, "Errors on filesystem, " "clearing orphan list.\n"); @@ -1274,7 +1274,7 @@ static void ext3_orphan_cleanup (struct super_block * sb, } if (s_flags & MS_RDONLY) { - printk(KERN_INFO "EXT3-fs: %s: orphan cleanup on readonly fs\n", + printk(KERN_INFO "EXT4-fs: %s: orphan cleanup on readonly fs\n", sb->s_id); sb->s_flags &= ~MS_RDONLY; } @@ -1283,11 +1283,11 @@ static void ext3_orphan_cleanup (struct super_block * sb, sb->s_flags |= MS_ACTIVE; /* Turn on quotas so that they are updated correctly */ for (i = 0; i < MAXQUOTAS; i++) { - if (EXT3_SB(sb)->s_qf_names[i]) { - int ret = ext3_quota_on_mount(sb, i); + if (EXT4_SB(sb)->s_qf_names[i]) { + int ret = ext4_quota_on_mount(sb, i); if (ret < 0) printk(KERN_ERR - "EXT3-fs: Cannot turn on journalled " + "EXT4-fs: Cannot turn on journalled " "quota: error %d\n", ret); } } @@ -1297,12 +1297,12 @@ static void ext3_orphan_cleanup (struct super_block * sb, struct inode *inode; if (!(inode = - ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) { + ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) { es->s_last_orphan = 0; break; } - list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan); + list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan); DQUOT_INIT(inode); if (inode->i_nlink) { printk(KERN_DEBUG @@ -1310,7 +1310,7 @@ static void ext3_orphan_cleanup (struct super_block * sb, __FUNCTION__, inode->i_ino, inode->i_size); jbd_debug(2, "truncating inode %lu to %Ld bytes\n", inode->i_ino, inode->i_size); - ext3_truncate(inode); + ext4_truncate(inode); nr_truncates++; } else { printk(KERN_DEBUG @@ -1326,10 +1326,10 @@ static void ext3_orphan_cleanup (struct super_block * sb, #define PLURAL(x) (x), ((x)==1) ? "" : "s" if (nr_orphans) - printk(KERN_INFO "EXT3-fs: %s: %d orphan inode%s deleted\n", + printk(KERN_INFO "EXT4-fs: %s: %d orphan inode%s deleted\n", sb->s_id, PLURAL(nr_orphans)); if (nr_truncates) - printk(KERN_INFO "EXT3-fs: %s: %d truncate%s cleaned up\n", + printk(KERN_INFO "EXT4-fs: %s: %d truncate%s cleaned up\n", sb->s_id, PLURAL(nr_truncates)); #ifdef CONFIG_QUOTA /* Turn quotas off */ @@ -1348,9 +1348,9 @@ static void ext3_orphan_cleanup (struct super_block * sb, * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. * We need to be 1 filesystem block less than the 2^32 sector limit. */ -static loff_t ext3_max_size(int bits) +static loff_t ext4_max_size(int bits) { - loff_t res = EXT3_NDIR_BLOCKS; + loff_t res = EXT4_NDIR_BLOCKS; /* This constant is calculated to be the largest file size for a * dense, 4k-blocksize file such that the total number of * sectors in the file, including data and all indirect blocks, @@ -1366,34 +1366,34 @@ static loff_t ext3_max_size(int bits) return res; } -static ext3_fsblk_t descriptor_loc(struct super_block *sb, - ext3_fsblk_t logic_sb_block, +static ext4_fsblk_t descriptor_loc(struct super_block *sb, + ext4_fsblk_t logic_sb_block, int nr) { - struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext4_sb_info *sbi = EXT4_SB(sb); unsigned long bg, first_meta_bg; int has_super = 0; first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); - if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) || + if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) || nr < first_meta_bg) return (logic_sb_block + nr + 1); bg = sbi->s_desc_per_block * nr; - if (ext3_bg_has_super(sb, bg)) + if (ext4_bg_has_super(sb, bg)) has_super = 1; - return (has_super + ext3_group_first_block_no(sb, bg)); + return (has_super + ext4_group_first_block_no(sb, bg)); } -static int ext3_fill_super (struct super_block *sb, void *data, int silent) +static int ext4_fill_super (struct super_block *sb, void *data, int silent) { struct buffer_head * bh; - struct ext3_super_block *es = NULL; - struct ext3_sb_info *sbi; - ext3_fsblk_t block; - ext3_fsblk_t sb_block = get_sb_block(&data); - ext3_fsblk_t logic_sb_block; + struct ext4_super_block *es = NULL; + struct ext4_sb_info *sbi; + ext4_fsblk_t block; + ext4_fsblk_t sb_block = get_sb_block(&data); + ext4_fsblk_t logic_sb_block; unsigned long offset = 0; unsigned int journal_inum = 0; unsigned long journal_devnum = 0; @@ -1411,64 +1411,64 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) return -ENOMEM; sb->s_fs_info = sbi; sbi->s_mount_opt = 0; - sbi->s_resuid = EXT3_DEF_RESUID; - sbi->s_resgid = EXT3_DEF_RESGID; + sbi->s_resuid = EXT4_DEF_RESUID; + sbi->s_resgid = EXT4_DEF_RESGID; unlock_kernel(); - blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); + blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE); if (!blocksize) { - printk(KERN_ERR "EXT3-fs: unable to set blocksize\n"); + printk(KERN_ERR "EXT4-fs: unable to set blocksize\n"); goto out_fail; } /* - * The ext3 superblock will not be buffer aligned for other than 1kB + * The ext4 superblock will not be buffer aligned for other than 1kB * block sizes. We need to calculate the offset from buffer start. */ - if (blocksize != EXT3_MIN_BLOCK_SIZE) { - logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; - offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; + if (blocksize != EXT4_MIN_BLOCK_SIZE) { + logic_sb_block = (sb_block * EXT4_MIN_BLOCK_SIZE) / blocksize; + offset = (sb_block * EXT4_MIN_BLOCK_SIZE) % blocksize; } else { logic_sb_block = sb_block; } if (!(bh = sb_bread(sb, logic_sb_block))) { - printk (KERN_ERR "EXT3-fs: unable to read superblock\n"); + printk (KERN_ERR "EXT4-fs: unable to read superblock\n"); goto out_fail; } /* * Note: s_es must be initialized as soon as possible because - * some ext3 macro-instructions depend on its value + * some ext4 macro-instructions depend on its value */ - es = (struct ext3_super_block *) (((char *)bh->b_data) + offset); + es = (struct ext4_super_block *) (((char *)bh->b_data) + offset); sbi->s_es = es; sb->s_magic = le16_to_cpu(es->s_magic); - if (sb->s_magic != EXT3_SUPER_MAGIC) - goto cantfind_ext3; + if (sb->s_magic != EXT4_SUPER_MAGIC) + goto cantfind_ext4; /* Set defaults before we parse the mount options */ def_mount_opts = le32_to_cpu(es->s_default_mount_opts); - if (def_mount_opts & EXT3_DEFM_DEBUG) + if (def_mount_opts & EXT4_DEFM_DEBUG) set_opt(sbi->s_mount_opt, DEBUG); - if (def_mount_opts & EXT3_DEFM_BSDGROUPS) + if (def_mount_opts & EXT4_DEFM_BSDGROUPS) set_opt(sbi->s_mount_opt, GRPID); - if (def_mount_opts & EXT3_DEFM_UID16) + if (def_mount_opts & EXT4_DEFM_UID16) set_opt(sbi->s_mount_opt, NO_UID32); - if (def_mount_opts & EXT3_DEFM_XATTR_USER) + if (def_mount_opts & EXT4_DEFM_XATTR_USER) set_opt(sbi->s_mount_opt, XATTR_USER); - if (def_mount_opts & EXT3_DEFM_ACL) + if (def_mount_opts & EXT4_DEFM_ACL) set_opt(sbi->s_mount_opt, POSIX_ACL); - if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_DATA) - sbi->s_mount_opt |= EXT3_MOUNT_JOURNAL_DATA; - else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_ORDERED) - sbi->s_mount_opt |= EXT3_MOUNT_ORDERED_DATA; - else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_WBACK) - sbi->s_mount_opt |= EXT3_MOUNT_WRITEBACK_DATA; - - if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC) + if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA) + sbi->s_mount_opt |= EXT4_MOUNT_JOURNAL_DATA; + else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED) + sbi->s_mount_opt |= EXT4_MOUNT_ORDERED_DATA; + else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_WBACK) + sbi->s_mount_opt |= EXT4_MOUNT_WRITEBACK_DATA; + + if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC) set_opt(sbi->s_mount_opt, ERRORS_PANIC); - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO) + else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_RO) set_opt(sbi->s_mount_opt, ERRORS_RO); sbi->s_resuid = le16_to_cpu(es->s_def_resuid); @@ -1481,40 +1481,40 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) goto failed_mount; sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); + ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); - if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV && - (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) || - EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) || - EXT3_HAS_INCOMPAT_FEATURE(sb, ~0U))) + if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV && + (EXT4_HAS_COMPAT_FEATURE(sb, ~0U) || + EXT4_HAS_RO_COMPAT_FEATURE(sb, ~0U) || + EXT4_HAS_INCOMPAT_FEATURE(sb, ~0U))) printk(KERN_WARNING - "EXT3-fs warning: feature flags set on rev 0 fs, " + "EXT4-fs warning: feature flags set on rev 0 fs, " "running e2fsck is recommended\n"); /* * Check feature flags regardless of the revision level, since we * previously didn't change the revision level when setting the flags, * so there is a chance incompat flags are set on a rev 0 filesystem. */ - features = EXT3_HAS_INCOMPAT_FEATURE(sb, ~EXT3_FEATURE_INCOMPAT_SUPP); + features = EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP); if (features) { - printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of " + printk(KERN_ERR "EXT4-fs: %s: couldn't mount because of " "unsupported optional features (%x).\n", sb->s_id, le32_to_cpu(features)); goto failed_mount; } - features = EXT3_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP); + features = EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP); if (!(sb->s_flags & MS_RDONLY) && features) { - printk(KERN_ERR "EXT3-fs: %s: couldn't mount RDWR because of " + printk(KERN_ERR "EXT4-fs: %s: couldn't mount RDWR because of " "unsupported optional features (%x).\n", sb->s_id, le32_to_cpu(features)); goto failed_mount; } blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); - if (blocksize < EXT3_MIN_BLOCK_SIZE || - blocksize > EXT3_MAX_BLOCK_SIZE) { + if (blocksize < EXT4_MIN_BLOCK_SIZE || + blocksize > EXT4_MAX_BLOCK_SIZE) { printk(KERN_ERR - "EXT3-fs: Unsupported filesystem blocksize %d on %s.\n", + "EXT4-fs: Unsupported filesystem blocksize %d on %s.\n", blocksize, sb->s_id); goto failed_mount; } @@ -1526,52 +1526,52 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) * than the hardware sectorsize for the machine. */ if (blocksize < hblock) { - printk(KERN_ERR "EXT3-fs: blocksize %d too small for " + printk(KERN_ERR "EXT4-fs: blocksize %d too small for " "device blocksize %d.\n", blocksize, hblock); goto failed_mount; } brelse (bh); sb_set_blocksize(sb, blocksize); - logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; - offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; + logic_sb_block = (sb_block * EXT4_MIN_BLOCK_SIZE) / blocksize; + offset = (sb_block * EXT4_MIN_BLOCK_SIZE) % blocksize; bh = sb_bread(sb, logic_sb_block); if (!bh) { printk(KERN_ERR - "EXT3-fs: Can't read superblock on 2nd try.\n"); + "EXT4-fs: Can't read superblock on 2nd try.\n"); goto failed_mount; } - es = (struct ext3_super_block *)(((char *)bh->b_data) + offset); + es = (struct ext4_super_block *)(((char *)bh->b_data) + offset); sbi->s_es = es; - if (es->s_magic != cpu_to_le16(EXT3_SUPER_MAGIC)) { + if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) { printk (KERN_ERR - "EXT3-fs: Magic mismatch, very weird !\n"); + "EXT4-fs: Magic mismatch, very weird !\n"); goto failed_mount; } } - sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits); + sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits); - if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV) { - sbi->s_inode_size = EXT3_GOOD_OLD_INODE_SIZE; - sbi->s_first_ino = EXT3_GOOD_OLD_FIRST_INO; + if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { + sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; + sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO; } else { sbi->s_inode_size = le16_to_cpu(es->s_inode_size); sbi->s_first_ino = le32_to_cpu(es->s_first_ino); - if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) || + if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || (sbi->s_inode_size & (sbi->s_inode_size - 1)) || (sbi->s_inode_size > blocksize)) { printk (KERN_ERR - "EXT3-fs: unsupported inode size: %d\n", + "EXT4-fs: unsupported inode size: %d\n", sbi->s_inode_size); goto failed_mount; } } - sbi->s_frag_size = EXT3_MIN_FRAG_SIZE << + sbi->s_frag_size = EXT4_MIN_FRAG_SIZE << le32_to_cpu(es->s_log_frag_size); if (blocksize != sbi->s_frag_size) { printk(KERN_ERR - "EXT3-fs: fragsize %lu != blocksize %u (unsupported)\n", + "EXT4-fs: fragsize %lu != blocksize %u (unsupported)\n", sbi->s_frag_size, blocksize); goto failed_mount; } @@ -1579,62 +1579,62 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); - if (EXT3_INODE_SIZE(sb) == 0) - goto cantfind_ext3; - sbi->s_inodes_per_block = blocksize / EXT3_INODE_SIZE(sb); + if (EXT4_INODE_SIZE(sb) == 0) + goto cantfind_ext4; + sbi->s_inodes_per_block = blocksize / EXT4_INODE_SIZE(sb); if (sbi->s_inodes_per_block == 0) - goto cantfind_ext3; + goto cantfind_ext4; sbi->s_itb_per_group = sbi->s_inodes_per_group / sbi->s_inodes_per_block; - sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc); + sbi->s_desc_per_block = blocksize / sizeof(struct ext4_group_desc); sbi->s_sbh = bh; sbi->s_mount_state = le16_to_cpu(es->s_state); - sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb)); - sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb)); + sbi->s_addr_per_block_bits = log2(EXT4_ADDR_PER_BLOCK(sb)); + sbi->s_desc_per_block_bits = log2(EXT4_DESC_PER_BLOCK(sb)); for (i=0; i < 4; i++) sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); sbi->s_def_hash_version = es->s_def_hash_version; if (sbi->s_blocks_per_group > blocksize * 8) { printk (KERN_ERR - "EXT3-fs: #blocks per group too big: %lu\n", + "EXT4-fs: #blocks per group too big: %lu\n", sbi->s_blocks_per_group); goto failed_mount; } if (sbi->s_frags_per_group > blocksize * 8) { printk (KERN_ERR - "EXT3-fs: #fragments per group too big: %lu\n", + "EXT4-fs: #fragments per group too big: %lu\n", sbi->s_frags_per_group); goto failed_mount; } if (sbi->s_inodes_per_group > blocksize * 8) { printk (KERN_ERR - "EXT3-fs: #inodes per group too big: %lu\n", + "EXT4-fs: #inodes per group too big: %lu\n", sbi->s_inodes_per_group); goto failed_mount; } if (le32_to_cpu(es->s_blocks_count) > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { - printk(KERN_ERR "EXT3-fs: filesystem on %s:" + printk(KERN_ERR "EXT4-fs: filesystem on %s:" " too large to mount safely\n", sb->s_id); if (sizeof(sector_t) < 8) - printk(KERN_WARNING "EXT3-fs: CONFIG_LBD not " + printk(KERN_WARNING "EXT4-fs: CONFIG_LBD not " "enabled\n"); goto failed_mount; } - if (EXT3_BLOCKS_PER_GROUP(sb) == 0) - goto cantfind_ext3; + if (EXT4_BLOCKS_PER_GROUP(sb) == 0) + goto cantfind_ext4; sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - le32_to_cpu(es->s_first_data_block) - 1) - / EXT3_BLOCKS_PER_GROUP(sb)) + 1; - db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) / - EXT3_DESC_PER_BLOCK(sb); + / EXT4_BLOCKS_PER_GROUP(sb)) + 1; + db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / + EXT4_DESC_PER_BLOCK(sb); sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), GFP_KERNEL); if (sbi->s_group_desc == NULL) { - printk (KERN_ERR "EXT3-fs: not enough memory\n"); + printk (KERN_ERR "EXT4-fs: not enough memory\n"); goto failed_mount; } @@ -1644,14 +1644,14 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) block = descriptor_loc(sb, logic_sb_block, i); sbi->s_group_desc[i] = sb_bread(sb, block); if (!sbi->s_group_desc[i]) { - printk (KERN_ERR "EXT3-fs: " + printk (KERN_ERR "EXT4-fs: " "can't read group descriptor %d\n", i); db_count = i; goto failed_mount2; } } - if (!ext3_check_descriptors (sb)) { - printk(KERN_ERR "EXT3-fs: group descriptors corrupted!\n"); + if (!ext4_check_descriptors (sb)) { + printk(KERN_ERR "EXT4-fs: group descriptors corrupted!\n"); goto failed_mount2; } sbi->s_gdb_count = db_count; @@ -1659,11 +1659,11 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) spin_lock_init(&sbi->s_next_gen_lock); percpu_counter_init(&sbi->s_freeblocks_counter, - ext3_count_free_blocks(sb)); + ext4_count_free_blocks(sb)); percpu_counter_init(&sbi->s_freeinodes_counter, - ext3_count_free_inodes(sb)); + ext4_count_free_inodes(sb)); percpu_counter_init(&sbi->s_dirs_counter, - ext3_count_dirs(sb)); + ext4_count_dirs(sb)); /* per fileystem reservation list head & lock */ spin_lock_init(&sbi->s_rsv_window_lock); @@ -1672,45 +1672,45 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) * reservation window list --- it gives us a placeholder for * append-at-start-of-list which makes the allocation logic * _much_ simpler. */ - sbi->s_rsv_window_head.rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - sbi->s_rsv_window_head.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + sbi->s_rsv_window_head.rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; + sbi->s_rsv_window_head.rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; sbi->s_rsv_window_head.rsv_alloc_hit = 0; sbi->s_rsv_window_head.rsv_goal_size = 0; - ext3_rsv_window_add(sb, &sbi->s_rsv_window_head); + ext4_rsv_window_add(sb, &sbi->s_rsv_window_head); /* * set up enough so that it can read an inode */ - sb->s_op = &ext3_sops; - sb->s_export_op = &ext3_export_ops; - sb->s_xattr = ext3_xattr_handlers; + sb->s_op = &ext4_sops; + sb->s_export_op = &ext4_export_ops; + sb->s_xattr = ext4_xattr_handlers; #ifdef CONFIG_QUOTA - sb->s_qcop = &ext3_qctl_operations; - sb->dq_op = &ext3_quota_operations; + sb->s_qcop = &ext4_qctl_operations; + sb->dq_op = &ext4_quota_operations; #endif INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ sb->s_root = NULL; needs_recovery = (es->s_last_orphan != 0 || - EXT3_HAS_INCOMPAT_FEATURE(sb, - EXT3_FEATURE_INCOMPAT_RECOVER)); + EXT4_HAS_INCOMPAT_FEATURE(sb, + EXT4_FEATURE_INCOMPAT_RECOVER)); /* * The first inode we look at is the journal inode. Don't try * root first: it may be modified in the journal! */ if (!test_opt(sb, NOLOAD) && - EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { - if (ext3_load_journal(sb, es, journal_devnum)) + EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) { + if (ext4_load_journal(sb, es, journal_devnum)) goto failed_mount3; } else if (journal_inum) { - if (ext3_create_journal(sb, es, journal_inum)) + if (ext4_create_journal(sb, es, journal_inum)) goto failed_mount3; } else { if (!silent) printk (KERN_ERR - "ext3: No journal on filesystem on %s\n", + "ext4: No journal on filesystem on %s\n", sb->s_id); goto failed_mount3; } @@ -1729,11 +1729,11 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) set_opt(sbi->s_mount_opt, JOURNAL_DATA); break; - case EXT3_MOUNT_ORDERED_DATA: - case EXT3_MOUNT_WRITEBACK_DATA: + case EXT4_MOUNT_ORDERED_DATA: + case EXT4_MOUNT_WRITEBACK_DATA: if (!journal_check_available_features (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) { - printk(KERN_ERR "EXT3-fs: Journal does not support " + printk(KERN_ERR "EXT4-fs: Journal does not support " "requested data journaling mode\n"); goto failed_mount4; } @@ -1742,8 +1742,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) } if (test_opt(sb, NOBH)) { - if (!(test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)) { - printk(KERN_WARNING "EXT3-fs: Ignoring nobh option - " + if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) { + printk(KERN_WARNING "EXT4-fs: Ignoring nobh option - " "its supported only with writeback mode\n"); clear_opt(sbi->s_mount_opt, NOBH); } @@ -1753,21 +1753,21 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) * so we can safely mount the rest of the filesystem now. */ - root = iget(sb, EXT3_ROOT_INO); + root = iget(sb, EXT4_ROOT_INO); sb->s_root = d_alloc_root(root); if (!sb->s_root) { - printk(KERN_ERR "EXT3-fs: get root inode failed\n"); + printk(KERN_ERR "EXT4-fs: get root inode failed\n"); iput(root); goto failed_mount4; } if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { dput(sb->s_root); sb->s_root = NULL; - printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n"); + printk(KERN_ERR "EXT4-fs: corrupt root inode, run e2fsck\n"); goto failed_mount4; } - ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY); + ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY); /* * akpm: core read_super() calls in here with the superblock locked. * That deadlocks, because orphan cleanup needs to lock the superblock @@ -1776,23 +1776,23 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) * and aviro says that's the only reason for hanging onto the * superblock lock. */ - EXT3_SB(sb)->s_mount_state |= EXT3_ORPHAN_FS; - ext3_orphan_cleanup(sb, es); - EXT3_SB(sb)->s_mount_state &= ~EXT3_ORPHAN_FS; + EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS; + ext4_orphan_cleanup(sb, es); + EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS; if (needs_recovery) - printk (KERN_INFO "EXT3-fs: recovery complete.\n"); - ext3_mark_recovery_complete(sb, es); - printk (KERN_INFO "EXT3-fs: mounted filesystem with %s data mode.\n", - test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal": - test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": + printk (KERN_INFO "EXT4-fs: recovery complete.\n"); + ext4_mark_recovery_complete(sb, es); + printk (KERN_INFO "EXT4-fs: mounted filesystem with %s data mode.\n", + test_opt(sb,DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ? "journal": + test_opt(sb,DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered": "writeback"); lock_kernel(); return 0; -cantfind_ext3: +cantfind_ext4: if (!silent) - printk(KERN_ERR "VFS: Can't find ext3 filesystem on dev %s.\n", + printk(KERN_ERR "VFS: Can't find ext4 filesystem on dev %s.\n", sb->s_id); goto failed_mount; @@ -1811,7 +1811,7 @@ failed_mount: for (i = 0; i < MAXQUOTAS; i++) kfree(sbi->s_qf_names[i]); #endif - ext3_blkdev_remove(sbi); + ext4_blkdev_remove(sbi); brelse(bh); out_fail: sb->s_fs_info = NULL; @@ -1825,13 +1825,13 @@ out_fail: * initial mount, once the journal has been initialised but before we've * done any recovery; and again on any subsequent remount. */ -static void ext3_init_journal_params(struct super_block *sb, journal_t *journal) +static void ext4_init_journal_params(struct super_block *sb, journal_t *journal) { - struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext4_sb_info *sbi = EXT4_SB(sb); if (sbi->s_commit_interval) journal->j_commit_interval = sbi->s_commit_interval; - /* We could also set up an ext3-specific default for the commit + /* We could also set up an ext4-specific default for the commit * interval here, but for now we'll just fall back to the jbd * default. */ @@ -1843,7 +1843,7 @@ static void ext3_init_journal_params(struct super_block *sb, journal_t *journal) spin_unlock(&journal->j_state_lock); } -static journal_t *ext3_get_journal(struct super_block *sb, +static journal_t *ext4_get_journal(struct super_block *sb, unsigned int journal_inum) { struct inode *journal_inode; @@ -1855,55 +1855,55 @@ static journal_t *ext3_get_journal(struct super_block *sb, journal_inode = iget(sb, journal_inum); if (!journal_inode) { - printk(KERN_ERR "EXT3-fs: no journal found.\n"); + printk(KERN_ERR "EXT4-fs: no journal found.\n"); return NULL; } if (!journal_inode->i_nlink) { make_bad_inode(journal_inode); iput(journal_inode); - printk(KERN_ERR "EXT3-fs: journal inode is deleted.\n"); + printk(KERN_ERR "EXT4-fs: journal inode is deleted.\n"); return NULL; } jbd_debug(2, "Journal inode found at %p: %Ld bytes\n", journal_inode, journal_inode->i_size); if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) { - printk(KERN_ERR "EXT3-fs: invalid journal inode.\n"); + printk(KERN_ERR "EXT4-fs: invalid journal inode.\n"); iput(journal_inode); return NULL; } journal = journal_init_inode(journal_inode); if (!journal) { - printk(KERN_ERR "EXT3-fs: Could not load journal inode\n"); + printk(KERN_ERR "EXT4-fs: Could not load journal inode\n"); iput(journal_inode); return NULL; } journal->j_private = sb; - ext3_init_journal_params(sb, journal); + ext4_init_journal_params(sb, journal); return journal; } -static journal_t *ext3_get_dev_journal(struct super_block *sb, +static journal_t *ext4_get_dev_journal(struct super_block *sb, dev_t j_dev) { struct buffer_head * bh; journal_t *journal; - ext3_fsblk_t start; - ext3_fsblk_t len; + ext4_fsblk_t start; + ext4_fsblk_t len; int hblock, blocksize; - ext3_fsblk_t sb_block; + ext4_fsblk_t sb_block; unsigned long offset; - struct ext3_super_block * es; + struct ext4_super_block * es; struct block_device *bdev; - bdev = ext3_blkdev_get(j_dev); + bdev = ext4_blkdev_get(j_dev); if (bdev == NULL) return NULL; if (bd_claim(bdev, sb)) { printk(KERN_ERR - "EXT3: failed to claim external journal device.\n"); + "EXT4: failed to claim external journal device.\n"); blkdev_put(bdev); return NULL; } @@ -1912,31 +1912,31 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb, hblock = bdev_hardsect_size(bdev); if (blocksize < hblock) { printk(KERN_ERR - "EXT3-fs: blocksize too small for journal device.\n"); + "EXT4-fs: blocksize too small for journal device.\n"); goto out_bdev; } - sb_block = EXT3_MIN_BLOCK_SIZE / blocksize; - offset = EXT3_MIN_BLOCK_SIZE % blocksize; + sb_block = EXT4_MIN_BLOCK_SIZE / blocksize; + offset = EXT4_MIN_BLOCK_SIZE % blocksize; set_blocksize(bdev, blocksize); if (!(bh = __bread(bdev, sb_block, blocksize))) { - printk(KERN_ERR "EXT3-fs: couldn't read superblock of " + printk(KERN_ERR "EXT4-fs: couldn't read superblock of " "external journal\n"); goto out_bdev; } - es = (struct ext3_super_block *) (((char *)bh->b_data) + offset); - if ((le16_to_cpu(es->s_magic) != EXT3_SUPER_MAGIC) || + es = (struct ext4_super_block *) (((char *)bh->b_data) + offset); + if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) || !(le32_to_cpu(es->s_feature_incompat) & - EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { - printk(KERN_ERR "EXT3-fs: external journal has " + EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) { + printk(KERN_ERR "EXT4-fs: external journal has " "bad superblock\n"); brelse(bh); goto out_bdev; } - if (memcmp(EXT3_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) { - printk(KERN_ERR "EXT3-fs: journal UUID does not match\n"); + if (memcmp(EXT4_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) { + printk(KERN_ERR "EXT4-fs: journal UUID does not match\n"); brelse(bh); goto out_bdev; } @@ -1948,34 +1948,34 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb, journal = journal_init_dev(bdev, sb->s_bdev, start, len, blocksize); if (!journal) { - printk(KERN_ERR "EXT3-fs: failed to create device journal\n"); + printk(KERN_ERR "EXT4-fs: failed to create device journal\n"); goto out_bdev; } journal->j_private = sb; ll_rw_block(READ, 1, &journal->j_sb_buffer); wait_on_buffer(journal->j_sb_buffer); if (!buffer_uptodate(journal->j_sb_buffer)) { - printk(KERN_ERR "EXT3-fs: I/O error on journal device\n"); + printk(KERN_ERR "EXT4-fs: I/O error on journal device\n"); goto out_journal; } if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) { - printk(KERN_ERR "EXT3-fs: External journal has more than one " + printk(KERN_ERR "EXT4-fs: External journal has more than one " "user (unsupported) - %d\n", be32_to_cpu(journal->j_superblock->s_nr_users)); goto out_journal; } - EXT3_SB(sb)->journal_bdev = bdev; - ext3_init_journal_params(sb, journal); + EXT4_SB(sb)->journal_bdev = bdev; + ext4_init_journal_params(sb, journal); return journal; out_journal: journal_destroy(journal); out_bdev: - ext3_blkdev_put(bdev); + ext4_blkdev_put(bdev); return NULL; } -static int ext3_load_journal(struct super_block *sb, - struct ext3_super_block *es, +static int ext4_load_journal(struct super_block *sb, + struct ext4_super_block *es, unsigned long journal_devnum) { journal_t *journal; @@ -1986,7 +1986,7 @@ static int ext3_load_journal(struct super_block *sb, if (journal_devnum && journal_devnum != le32_to_cpu(es->s_journal_dev)) { - printk(KERN_INFO "EXT3-fs: external journal device major/minor " + printk(KERN_INFO "EXT4-fs: external journal device major/minor " "numbers have changed\n"); journal_dev = new_decode_dev(journal_devnum); } else @@ -2000,56 +2000,56 @@ static int ext3_load_journal(struct super_block *sb, * can get read-write access to the device. */ - if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) { + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) { if (sb->s_flags & MS_RDONLY) { - printk(KERN_INFO "EXT3-fs: INFO: recovery " + printk(KERN_INFO "EXT4-fs: INFO: recovery " "required on readonly filesystem.\n"); if (really_read_only) { - printk(KERN_ERR "EXT3-fs: write access " + printk(KERN_ERR "EXT4-fs: write access " "unavailable, cannot proceed.\n"); return -EROFS; } - printk (KERN_INFO "EXT3-fs: write access will " + printk (KERN_INFO "EXT4-fs: write access will " "be enabled during recovery.\n"); } } if (journal_inum && journal_dev) { - printk(KERN_ERR "EXT3-fs: filesystem has both journal " + printk(KERN_ERR "EXT4-fs: filesystem has both journal " "and inode journals!\n"); return -EINVAL; } if (journal_inum) { - if (!(journal = ext3_get_journal(sb, journal_inum))) + if (!(journal = ext4_get_journal(sb, journal_inum))) return -EINVAL; } else { - if (!(journal = ext3_get_dev_journal(sb, journal_dev))) + if (!(journal = ext4_get_dev_journal(sb, journal_dev))) return -EINVAL; } if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) { err = journal_update_format(journal); if (err) { - printk(KERN_ERR "EXT3-fs: error updating journal.\n"); + printk(KERN_ERR "EXT4-fs: error updating journal.\n"); journal_destroy(journal); return err; } } - if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) + if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) err = journal_wipe(journal, !really_read_only); if (!err) err = journal_load(journal); if (err) { - printk(KERN_ERR "EXT3-fs: error loading journal.\n"); + printk(KERN_ERR "EXT4-fs: error loading journal.\n"); journal_destroy(journal); return err; } - EXT3_SB(sb)->s_journal = journal; - ext3_clear_journal_err(sb, es); + EXT4_SB(sb)->s_journal = journal; + ext4_clear_journal_err(sb, es); if (journal_devnum && journal_devnum != le32_to_cpu(es->s_journal_dev)) { @@ -2057,62 +2057,62 @@ static int ext3_load_journal(struct super_block *sb, sb->s_dirt = 1; /* Make sure we flush the recovery flag to disk. */ - ext3_commit_super(sb, es, 1); + ext4_commit_super(sb, es, 1); } return 0; } -static int ext3_create_journal(struct super_block * sb, - struct ext3_super_block * es, +static int ext4_create_journal(struct super_block * sb, + struct ext4_super_block * es, unsigned int journal_inum) { journal_t *journal; if (sb->s_flags & MS_RDONLY) { - printk(KERN_ERR "EXT3-fs: readonly filesystem when trying to " + printk(KERN_ERR "EXT4-fs: readonly filesystem when trying to " "create journal.\n"); return -EROFS; } - if (!(journal = ext3_get_journal(sb, journal_inum))) + if (!(journal = ext4_get_journal(sb, journal_inum))) return -EINVAL; - printk(KERN_INFO "EXT3-fs: creating new journal on inode %u\n", + printk(KERN_INFO "EXT4-fs: creating new journal on inode %u\n", journal_inum); if (journal_create(journal)) { - printk(KERN_ERR "EXT3-fs: error creating journal.\n"); + printk(KERN_ERR "EXT4-fs: error creating journal.\n"); journal_destroy(journal); return -EIO; } - EXT3_SB(sb)->s_journal = journal; + EXT4_SB(sb)->s_journal = journal; - ext3_update_dynamic_rev(sb); - EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); - EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL); + ext4_update_dynamic_rev(sb); + EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); + EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL); es->s_journal_inum = cpu_to_le32(journal_inum); sb->s_dirt = 1; /* Make sure we flush the recovery flag to disk. */ - ext3_commit_super(sb, es, 1); + ext4_commit_super(sb, es, 1); return 0; } -static void ext3_commit_super (struct super_block * sb, - struct ext3_super_block * es, +static void ext4_commit_super (struct super_block * sb, + struct ext4_super_block * es, int sync) { - struct buffer_head *sbh = EXT3_SB(sb)->s_sbh; + struct buffer_head *sbh = EXT4_SB(sb)->s_sbh; if (!sbh) return; es->s_wtime = cpu_to_le32(get_seconds()); - es->s_free_blocks_count = cpu_to_le32(ext3_count_free_blocks(sb)); - es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb)); + es->s_free_blocks_count = cpu_to_le32(ext4_count_free_blocks(sb)); + es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb)); BUFFER_TRACE(sbh, "marking dirty"); mark_buffer_dirty(sbh); if (sync) @@ -2125,18 +2125,18 @@ static void ext3_commit_super (struct super_block * sb, * remounting) the filesystem readonly, then we will end up with a * consistent fs on disk. Record that fact. */ -static void ext3_mark_recovery_complete(struct super_block * sb, - struct ext3_super_block * es) +static void ext4_mark_recovery_complete(struct super_block * sb, + struct ext4_super_block * es) { - journal_t *journal = EXT3_SB(sb)->s_journal; + journal_t *journal = EXT4_SB(sb)->s_journal; journal_lock_updates(journal); journal_flush(journal); - if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) && + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) && sb->s_flags & MS_RDONLY) { - EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); sb->s_dirt = 0; - ext3_commit_super(sb, es, 1); + ext4_commit_super(sb, es, 1); } journal_unlock_updates(journal); } @@ -2146,33 +2146,33 @@ static void ext3_mark_recovery_complete(struct super_block * sb, * has recorded an error from a previous lifetime, move that error to the * main filesystem now. */ -static void ext3_clear_journal_err(struct super_block * sb, - struct ext3_super_block * es) +static void ext4_clear_journal_err(struct super_block * sb, + struct ext4_super_block * es) { journal_t *journal; int j_errno; const char *errstr; - journal = EXT3_SB(sb)->s_journal; + journal = EXT4_SB(sb)->s_journal; /* * Now check for any error status which may have been recorded in the - * journal by a prior ext3_error() or ext3_abort() + * journal by a prior ext4_error() or ext4_abort() */ j_errno = journal_errno(journal); if (j_errno) { char nbuf[16]; - errstr = ext3_decode_error(sb, j_errno, nbuf); - ext3_warning(sb, __FUNCTION__, "Filesystem error recorded " + errstr = ext4_decode_error(sb, j_errno, nbuf); + ext4_warning(sb, __FUNCTION__, "Filesystem error recorded " "from previous mount: %s", errstr); - ext3_warning(sb, __FUNCTION__, "Marking fs in need of " + ext4_warning(sb, __FUNCTION__, "Marking fs in need of " "filesystem check."); - EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; - es->s_state |= cpu_to_le16(EXT3_ERROR_FS); - ext3_commit_super (sb, es, 1); + EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; + es->s_state |= cpu_to_le16(EXT4_ERROR_FS); + ext4_commit_super (sb, es, 1); journal_clear_err(journal); } @@ -2182,7 +2182,7 @@ static void ext3_clear_journal_err(struct super_block * sb, * Force the running and committing transactions to commit, * and wait on the commit. */ -int ext3_force_commit(struct super_block *sb) +int ext4_force_commit(struct super_block *sb) { journal_t *journal; int ret; @@ -2190,14 +2190,14 @@ int ext3_force_commit(struct super_block *sb) if (sb->s_flags & MS_RDONLY) return 0; - journal = EXT3_SB(sb)->s_journal; + journal = EXT4_SB(sb)->s_journal; sb->s_dirt = 0; - ret = ext3_journal_force_commit(journal); + ret = ext4_journal_force_commit(journal); return ret; } /* - * Ext3 always journals updates to the superblock itself, so we don't + * Ext4 always journals updates to the superblock itself, so we don't * have to propagate any other updates to the superblock on disk at this * point. Just start an async writeback to get the buffers on their way * to the disk. @@ -2205,21 +2205,21 @@ int ext3_force_commit(struct super_block *sb) * This implicitly triggers the writebehind on sync(). */ -static void ext3_write_super (struct super_block * sb) +static void ext4_write_super (struct super_block * sb) { if (mutex_trylock(&sb->s_lock) != 0) BUG(); sb->s_dirt = 0; } -static int ext3_sync_fs(struct super_block *sb, int wait) +static int ext4_sync_fs(struct super_block *sb, int wait) { tid_t target; sb->s_dirt = 0; - if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) { + if (journal_start_commit(EXT4_SB(sb)->s_journal, &target)) { if (wait) - log_wait_commit(EXT3_SB(sb)->s_journal, target); + log_wait_commit(EXT4_SB(sb)->s_journal, target); } return 0; } @@ -2228,20 +2228,20 @@ 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. */ -static void ext3_write_super_lockfs(struct super_block *sb) +static void ext4_write_super_lockfs(struct super_block *sb) { sb->s_dirt = 0; if (!(sb->s_flags & MS_RDONLY)) { - journal_t *journal = EXT3_SB(sb)->s_journal; + journal_t *journal = EXT4_SB(sb)->s_journal; /* Now we set up the journal barrier. */ journal_lock_updates(journal); journal_flush(journal); /* Journal blocked and flushed, clear needs_recovery flag. */ - EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); - ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); + EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); + ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1); } } @@ -2249,25 +2249,25 @@ static 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. */ -static void ext3_unlockfs(struct super_block *sb) +static void ext4_unlockfs(struct super_block *sb) { if (!(sb->s_flags & MS_RDONLY)) { lock_super(sb); /* Reser the needs_recovery flag before the fs is unlocked. */ - EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); - ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); + EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); + ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1); unlock_super(sb); - journal_unlock_updates(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT4_SB(sb)->s_journal); } } -static int ext3_remount (struct super_block * sb, int * flags, char * data) +static int ext4_remount (struct super_block * sb, int * flags, char * data) { - struct ext3_super_block * es; - struct ext3_sb_info *sbi = EXT3_SB(sb); - ext3_fsblk_t n_blocks_count = 0; + struct ext4_super_block * es; + struct ext4_sb_info *sbi = EXT4_SB(sb); + ext4_fsblk_t n_blocks_count = 0; unsigned long old_sb_flags; - struct ext3_mount_options old_opts; + struct ext4_mount_options old_opts; int err; #ifdef CONFIG_QUOTA int i; @@ -2293,19 +2293,19 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) goto restore_opts; } - if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) - ext3_abort(sb, __FUNCTION__, "Abort forced by user"); + if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) + ext4_abort(sb, __FUNCTION__, "Abort forced by user"); sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); + ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); es = sbi->s_es; - ext3_init_journal_params(sb, sbi->s_journal); + ext4_init_journal_params(sb, sbi->s_journal); if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || n_blocks_count > le32_to_cpu(es->s_blocks_count)) { - if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) { + if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) { err = -EROFS; goto restore_opts; } @@ -2322,16 +2322,16 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) * readonly, and if so set the rdonly flag and then * mark the partition as valid again. */ - if (!(es->s_state & cpu_to_le16(EXT3_VALID_FS)) && - (sbi->s_mount_state & EXT3_VALID_FS)) + if (!(es->s_state & cpu_to_le16(EXT4_VALID_FS)) && + (sbi->s_mount_state & EXT4_VALID_FS)) es->s_state = cpu_to_le16(sbi->s_mount_state); - ext3_mark_recovery_complete(sb, es); + ext4_mark_recovery_complete(sb, es); } else { __le32 ret; - if ((ret = EXT3_HAS_RO_COMPAT_FEATURE(sb, - ~EXT3_FEATURE_RO_COMPAT_SUPP))) { - printk(KERN_WARNING "EXT3-fs: %s: couldn't " + if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb, + ~EXT4_FEATURE_RO_COMPAT_SUPP))) { + printk(KERN_WARNING "EXT4-fs: %s: couldn't " "remount RDWR because of unsupported " "optional features (%x).\n", sb->s_id, le32_to_cpu(ret)); @@ -2344,11 +2344,11 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) * been changed by e2fsck since we originally mounted * the partition.) */ - ext3_clear_journal_err(sb, es); + ext4_clear_journal_err(sb, es); sbi->s_mount_state = le16_to_cpu(es->s_state); - if ((err = ext3_group_extend(sb, es, n_blocks_count))) + if ((err = ext4_group_extend(sb, es, n_blocks_count))) goto restore_opts; - if (!ext3_setup_super (sb, es, 0)) + if (!ext4_setup_super (sb, es, 0)) sb->s_flags &= ~MS_RDONLY; } } @@ -2378,19 +2378,19 @@ restore_opts: return err; } -static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) +static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf) { struct super_block *sb = dentry->d_sb; - struct ext3_sb_info *sbi = EXT3_SB(sb); - struct ext3_super_block *es = sbi->s_es; - ext3_fsblk_t overhead; + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; + ext4_fsblk_t overhead; int i; if (test_opt (sb, MINIX_DF)) overhead = 0; else { unsigned long ngroups; - ngroups = EXT3_SB(sb)->s_groups_count; + ngroups = EXT4_SB(sb)->s_groups_count; smp_rmb(); /* @@ -2409,8 +2409,8 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) * feature is turned on, then not all groups have this. */ for (i = 0; i < ngroups; i++) { - overhead += ext3_bg_has_super(sb, i) + - ext3_bg_num_gdb(sb, i); + overhead += ext4_bg_has_super(sb, i) + + ext4_bg_num_gdb(sb, i); cond_resched(); } @@ -2418,10 +2418,10 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) * Every block group has an inode bitmap, a block * bitmap, and an inode table. */ - overhead += (ngroups * (2 + EXT3_SB(sb)->s_itb_per_group)); + overhead += (ngroups * (2 + EXT4_SB(sb)->s_itb_per_group)); } - buf->f_type = EXT3_SUPER_MAGIC; + buf->f_type = EXT4_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead; buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); @@ -2430,14 +2430,14 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) buf->f_bavail = 0; buf->f_files = le32_to_cpu(es->s_inodes_count); buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); - buf->f_namelen = EXT3_NAME_LEN; + buf->f_namelen = EXT4_NAME_LEN; return 0; } /* Helper function for writing quotas on sync - we need to start transaction before quota file * is locked for write. Otherwise the are possible deadlocks: * Process 1 Process 2 - * ext3_create() quota_sync() + * ext4_create() quota_sync() * journal_start() write_dquot() * DQUOT_INIT() down(dqio_mutex) * down(dqio_mutex) journal_start() @@ -2451,111 +2451,111 @@ static inline struct inode *dquot_to_inode(struct dquot *dquot) return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; } -static int ext3_dquot_initialize(struct inode *inode, int type) +static int ext4_dquot_initialize(struct inode *inode, int type) { handle_t *handle; int ret, err; /* We may create quota structure so we need to reserve enough blocks */ - handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)); + handle = ext4_journal_start(inode, 2*EXT4_QUOTA_INIT_BLOCKS(inode->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_initialize(inode, type); - err = ext3_journal_stop(handle); + err = ext4_journal_stop(handle); if (!ret) ret = err; return ret; } -static int ext3_dquot_drop(struct inode *inode) +static int ext4_dquot_drop(struct inode *inode) { handle_t *handle; int ret, err; /* We may delete quota structure so we need to reserve enough blocks */ - handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb)); + handle = ext4_journal_start(inode, 2*EXT4_QUOTA_DEL_BLOCKS(inode->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_drop(inode); - err = ext3_journal_stop(handle); + err = ext4_journal_stop(handle); if (!ret) ret = err; return ret; } -static int ext3_write_dquot(struct dquot *dquot) +static int ext4_write_dquot(struct dquot *dquot) { int ret, err; handle_t *handle; struct inode *inode; inode = dquot_to_inode(dquot); - handle = ext3_journal_start(inode, - EXT3_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); + handle = ext4_journal_start(inode, + EXT4_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_commit(dquot); - err = ext3_journal_stop(handle); + err = ext4_journal_stop(handle); if (!ret) ret = err; return ret; } -static int ext3_acquire_dquot(struct dquot *dquot) +static int ext4_acquire_dquot(struct dquot *dquot) { int ret, err; handle_t *handle; - handle = ext3_journal_start(dquot_to_inode(dquot), - EXT3_QUOTA_INIT_BLOCKS(dquot->dq_sb)); + handle = ext4_journal_start(dquot_to_inode(dquot), + EXT4_QUOTA_INIT_BLOCKS(dquot->dq_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_acquire(dquot); - err = ext3_journal_stop(handle); + err = ext4_journal_stop(handle); if (!ret) ret = err; return ret; } -static int ext3_release_dquot(struct dquot *dquot) +static int ext4_release_dquot(struct dquot *dquot) { int ret, err; handle_t *handle; - handle = ext3_journal_start(dquot_to_inode(dquot), - EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb)); + handle = ext4_journal_start(dquot_to_inode(dquot), + EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_release(dquot); - err = ext3_journal_stop(handle); + err = ext4_journal_stop(handle); if (!ret) ret = err; return ret; } -static int ext3_mark_dquot_dirty(struct dquot *dquot) +static int ext4_mark_dquot_dirty(struct dquot *dquot) { /* Are we journalling quotas? */ - if (EXT3_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || - EXT3_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { + if (EXT4_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || + EXT4_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { dquot_mark_dquot_dirty(dquot); - return ext3_write_dquot(dquot); + return ext4_write_dquot(dquot); } else { return dquot_mark_dquot_dirty(dquot); } } -static int ext3_write_info(struct super_block *sb, int type) +static int ext4_write_info(struct super_block *sb, int type) { int ret, err; handle_t *handle; /* Data block + inode block */ - handle = ext3_journal_start(sb->s_root->d_inode, 2); + handle = ext4_journal_start(sb->s_root->d_inode, 2); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_commit_info(sb, type); - err = ext3_journal_stop(handle); + err = ext4_journal_stop(handle); if (!ret) ret = err; return ret; @@ -2565,16 +2565,16 @@ static int ext3_write_info(struct super_block *sb, int type) * Turn on quotas during mount time - we need to find * the quota file and such... */ -static int ext3_quota_on_mount(struct super_block *sb, int type) +static int ext4_quota_on_mount(struct super_block *sb, int type) { - return vfs_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type], - EXT3_SB(sb)->s_jquota_fmt, type); + return vfs_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type], + EXT4_SB(sb)->s_jquota_fmt, type); } /* * Standard function to be called on quota_on */ -static int ext3_quota_on(struct super_block *sb, int type, int format_id, +static int ext4_quota_on(struct super_block *sb, int type, int format_id, char *path) { int err; @@ -2583,8 +2583,8 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, if (!test_opt(sb, QUOTA)) return -EINVAL; /* Not journalling quota? */ - if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] && - !EXT3_SB(sb)->s_qf_names[GRPQUOTA]) + if (!EXT4_SB(sb)->s_qf_names[USRQUOTA] && + !EXT4_SB(sb)->s_qf_names[GRPQUOTA]) return vfs_quota_on(sb, type, format_id, path); err = path_lookup(path, LOOKUP_FOLLOW, &nd); if (err) @@ -2597,7 +2597,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, /* Quotafile not of fs root? */ if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode) printk(KERN_WARNING - "EXT3-fs: Quota file not on filesystem root. " + "EXT4-fs: Quota file not on filesystem root. " "Journalled quota will not work.\n"); path_release(&nd); return vfs_quota_on(sb, type, format_id, path); @@ -2607,11 +2607,11 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, * acquiring the locks... As quota files are never truncated and quota code * itself serializes the operations (and noone else should touch the files) * we don't have to be afraid of races */ -static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, +static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off) { struct inode *inode = sb_dqopt(sb)->files[type]; - sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb); + sector_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb); int err = 0; int offset = off & (sb->s_blocksize - 1); int tocopy; @@ -2627,7 +2627,7 @@ static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, while (toread > 0) { tocopy = sb->s_blocksize - offset < toread ? sb->s_blocksize - offset : toread; - bh = ext3_bread(NULL, inode, blk, 0, &err); + bh = ext4_bread(NULL, inode, blk, 0, &err); if (err) return err; if (!bh) /* A hole? */ @@ -2645,15 +2645,15 @@ static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, /* Write to quotafile (we know the transaction is already started and has * enough credits) */ -static ssize_t ext3_quota_write(struct super_block *sb, int type, +static ssize_t ext4_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off) { struct inode *inode = sb_dqopt(sb)->files[type]; - sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb); + sector_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb); int err = 0; int offset = off & (sb->s_blocksize - 1); int tocopy; - int journal_quota = EXT3_SB(sb)->s_qf_names[type] != NULL; + int journal_quota = EXT4_SB(sb)->s_qf_names[type] != NULL; size_t towrite = len; struct buffer_head *bh; handle_t *handle = journal_current_handle(); @@ -2662,11 +2662,11 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type, while (towrite > 0) { tocopy = sb->s_blocksize - offset < towrite ? sb->s_blocksize - offset : towrite; - bh = ext3_bread(handle, inode, blk, 1, &err); + bh = ext4_bread(handle, inode, blk, 1, &err); if (!bh) goto out; if (journal_quota) { - err = ext3_journal_get_write_access(handle, bh); + err = ext4_journal_get_write_access(handle, bh); if (err) { brelse(bh); goto out; @@ -2677,10 +2677,10 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type, flush_dcache_page(bh->b_page); unlock_buffer(bh); if (journal_quota) - err = ext3_journal_dirty_metadata(handle, bh); + err = ext4_journal_dirty_metadata(handle, bh); else { /* Always do at least ordered writes for quotas */ - err = ext3_journal_dirty_data(handle, bh); + err = ext4_journal_dirty_data(handle, bh); mark_buffer_dirty(bh); } brelse(bh); @@ -2696,59 +2696,59 @@ out: return err; if (inode->i_size < off+len-towrite) { i_size_write(inode, off+len-towrite); - EXT3_I(inode)->i_disksize = inode->i_size; + EXT4_I(inode)->i_disksize = inode->i_size; } inode->i_version++; inode->i_mtime = inode->i_ctime = CURRENT_TIME; - ext3_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode); mutex_unlock(&inode->i_mutex); return len - towrite; } #endif -static int ext3_get_sb(struct file_system_type *fs_type, +static int ext4_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super, mnt); + return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt); } -static struct file_system_type ext3_fs_type = { +static struct file_system_type ext4dev_fs_type = { .owner = THIS_MODULE, - .name = "ext3", - .get_sb = ext3_get_sb, + .name = "ext4dev", + .get_sb = ext4_get_sb, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; -static int __init init_ext3_fs(void) +static int __init init_ext4_fs(void) { - int err = init_ext3_xattr(); + int err = init_ext4_xattr(); if (err) return err; err = init_inodecache(); if (err) goto out1; - err = register_filesystem(&ext3_fs_type); + err = register_filesystem(&ext4dev_fs_type); if (err) goto out; return 0; out: destroy_inodecache(); out1: - exit_ext3_xattr(); + exit_ext4_xattr(); return err; } -static void __exit exit_ext3_fs(void) +static void __exit exit_ext4_fs(void) { - unregister_filesystem(&ext3_fs_type); + unregister_filesystem(&ext4dev_fs_type); destroy_inodecache(); - exit_ext3_xattr(); + exit_ext4_xattr(); } MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); -MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions"); +MODULE_DESCRIPTION("Fourth Extended Filesystem with extents"); MODULE_LICENSE("GPL"); -module_init(init_ext3_fs) -module_exit(exit_ext3_fs) +module_init(init_ext4_fs) +module_exit(exit_ext4_fs) diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index 4f79122cde67..9e4c75f912f7 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/symlink.c + * linux/fs/ext4/symlink.c * * Only fast symlinks left here - the rest is done by generic code. AV, 1999 * @@ -14,41 +14,41 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * - * ext3 symlink handling code + * ext4 symlink handling code */ #include #include -#include +#include #include #include "xattr.h" -static void * ext3_follow_link(struct dentry *dentry, struct nameidata *nd) +static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct ext3_inode_info *ei = EXT3_I(dentry->d_inode); + struct ext4_inode_info *ei = EXT4_I(dentry->d_inode); nd_set_link(nd, (char*)ei->i_data); return NULL; } -struct inode_operations ext3_symlink_inode_operations = { +struct inode_operations ext4_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, -#ifdef CONFIG_EXT3_FS_XATTR +#ifdef CONFIG_EXT4DEV_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, - .listxattr = ext3_listxattr, + .listxattr = ext4_listxattr, .removexattr = generic_removexattr, #endif }; -struct inode_operations ext3_fast_symlink_inode_operations = { +struct inode_operations ext4_fast_symlink_inode_operations = { .readlink = generic_readlink, - .follow_link = ext3_follow_link, -#ifdef CONFIG_EXT3_FS_XATTR + .follow_link = ext4_follow_link, +#ifdef CONFIG_EXT4DEV_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, - .listxattr = ext3_listxattr, + .listxattr = ext4_listxattr, .removexattr = generic_removexattr, #endif }; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index f86f2482f01d..d3a408154101 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1,10 +1,10 @@ /* - * linux/fs/ext3/xattr.c + * linux/fs/ext4/xattr.c * * Copyright (C) 2001-2003 Andreas Gruenbacher, * * Fix by Harrison Xing . - * Ext3 code with a lot of help from Eric Jarman . + * Ext4 code with a lot of help from Eric Jarman . * Extended attributes for symlinks and special files added per * suggestion of Luka Renko . * xattr consolidation Copyright (c) 2004 James Morris , @@ -43,7 +43,7 @@ * * Locking strategy * ---------------- - * EXT3_I(inode)->i_file_acl is protected by EXT3_I(inode)->xattr_sem. + * EXT4_I(inode)->i_file_acl is protected by EXT4_I(inode)->xattr_sem. * EA blocks are only changed if they are exclusive to an inode, so * holding xattr_sem also means that nothing but the EA block's reference * count can change. Multiple writers to the same block are synchronized @@ -53,27 +53,27 @@ #include #include #include -#include -#include +#include +#include #include #include #include #include "xattr.h" #include "acl.h" -#define BHDR(bh) ((struct ext3_xattr_header *)((bh)->b_data)) -#define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr)) +#define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data)) +#define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr)) #define BFIRST(bh) ENTRY(BHDR(bh)+1) #define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) #define IHDR(inode, raw_inode) \ - ((struct ext3_xattr_ibody_header *) \ + ((struct ext4_xattr_ibody_header *) \ ((void *)raw_inode + \ - EXT3_GOOD_OLD_INODE_SIZE + \ - EXT3_I(inode)->i_extra_isize)) -#define IFIRST(hdr) ((struct ext3_xattr_entry *)((hdr)+1)) + EXT4_GOOD_OLD_INODE_SIZE + \ + EXT4_I(inode)->i_extra_isize)) +#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) -#ifdef EXT3_XATTR_DEBUG +#ifdef EXT4_XATTR_DEBUG # define ea_idebug(inode, f...) do { \ printk(KERN_DEBUG "inode %s:%lu: ", \ inode->i_sb->s_id, inode->i_ino); \ @@ -93,47 +93,47 @@ # define ea_bdebug(f...) #endif -static void ext3_xattr_cache_insert(struct buffer_head *); -static struct buffer_head *ext3_xattr_cache_find(struct inode *, - struct ext3_xattr_header *, +static void ext4_xattr_cache_insert(struct buffer_head *); +static struct buffer_head *ext4_xattr_cache_find(struct inode *, + struct ext4_xattr_header *, struct mb_cache_entry **); -static void ext3_xattr_rehash(struct ext3_xattr_header *, - struct ext3_xattr_entry *); +static void ext4_xattr_rehash(struct ext4_xattr_header *, + struct ext4_xattr_entry *); -static struct mb_cache *ext3_xattr_cache; +static struct mb_cache *ext4_xattr_cache; -static struct xattr_handler *ext3_xattr_handler_map[] = { - [EXT3_XATTR_INDEX_USER] = &ext3_xattr_user_handler, -#ifdef CONFIG_EXT3_FS_POSIX_ACL - [EXT3_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext3_xattr_acl_access_handler, - [EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext3_xattr_acl_default_handler, +static struct xattr_handler *ext4_xattr_handler_map[] = { + [EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler, +#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL + [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext4_xattr_acl_access_handler, + [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext4_xattr_acl_default_handler, #endif - [EXT3_XATTR_INDEX_TRUSTED] = &ext3_xattr_trusted_handler, -#ifdef CONFIG_EXT3_FS_SECURITY - [EXT3_XATTR_INDEX_SECURITY] = &ext3_xattr_security_handler, + [EXT4_XATTR_INDEX_TRUSTED] = &ext4_xattr_trusted_handler, +#ifdef CONFIG_EXT4DEV_FS_SECURITY + [EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler, #endif }; -struct xattr_handler *ext3_xattr_handlers[] = { - &ext3_xattr_user_handler, - &ext3_xattr_trusted_handler, -#ifdef CONFIG_EXT3_FS_POSIX_ACL - &ext3_xattr_acl_access_handler, - &ext3_xattr_acl_default_handler, +struct xattr_handler *ext4_xattr_handlers[] = { + &ext4_xattr_user_handler, + &ext4_xattr_trusted_handler, +#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL + &ext4_xattr_acl_access_handler, + &ext4_xattr_acl_default_handler, #endif -#ifdef CONFIG_EXT3_FS_SECURITY - &ext3_xattr_security_handler, +#ifdef CONFIG_EXT4DEV_FS_SECURITY + &ext4_xattr_security_handler, #endif NULL }; static inline struct xattr_handler * -ext3_xattr_handler(int name_index) +ext4_xattr_handler(int name_index) { struct xattr_handler *handler = NULL; - if (name_index > 0 && name_index < ARRAY_SIZE(ext3_xattr_handler_map)) - handler = ext3_xattr_handler_map[name_index]; + if (name_index > 0 && name_index < ARRAY_SIZE(ext4_xattr_handler_map)) + handler = ext4_xattr_handler_map[name_index]; return handler; } @@ -143,16 +143,16 @@ ext3_xattr_handler(int name_index) * dentry->d_inode->i_mutex: don't care */ ssize_t -ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) +ext4_listxattr(struct dentry *dentry, char *buffer, size_t size) { - return ext3_xattr_list(dentry->d_inode, buffer, size); + return ext4_xattr_list(dentry->d_inode, buffer, size); } static int -ext3_xattr_check_names(struct ext3_xattr_entry *entry, void *end) +ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end) { while (!IS_LAST_ENTRY(entry)) { - struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(entry); + struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry); if ((void *)next >= end) return -EIO; entry = next; @@ -161,19 +161,19 @@ ext3_xattr_check_names(struct ext3_xattr_entry *entry, void *end) } static inline int -ext3_xattr_check_block(struct buffer_head *bh) +ext4_xattr_check_block(struct buffer_head *bh) { int error; - if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || + if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || BHDR(bh)->h_blocks != cpu_to_le32(1)) return -EIO; - error = ext3_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); + error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); return error; } static inline int -ext3_xattr_check_entry(struct ext3_xattr_entry *entry, size_t size) +ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size) { size_t value_size = le32_to_cpu(entry->e_value_size); @@ -184,10 +184,10 @@ ext3_xattr_check_entry(struct ext3_xattr_entry *entry, size_t size) } static int -ext3_xattr_find_entry(struct ext3_xattr_entry **pentry, int name_index, +ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index, const char *name, size_t size, int sorted) { - struct ext3_xattr_entry *entry; + struct ext4_xattr_entry *entry; size_t name_len; int cmp = 1; @@ -195,7 +195,7 @@ ext3_xattr_find_entry(struct ext3_xattr_entry **pentry, int name_index, return -EINVAL; name_len = strlen(name); entry = *pentry; - for (; !IS_LAST_ENTRY(entry); entry = EXT3_XATTR_NEXT(entry)) { + for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { cmp = name_index - entry->e_name_index; if (!cmp) cmp = name_len - entry->e_name_len; @@ -205,17 +205,17 @@ ext3_xattr_find_entry(struct ext3_xattr_entry **pentry, int name_index, break; } *pentry = entry; - if (!cmp && ext3_xattr_check_entry(entry, size)) + if (!cmp && ext4_xattr_check_entry(entry, size)) return -EIO; return cmp ? -ENODATA : 0; } static int -ext3_xattr_block_get(struct inode *inode, int name_index, const char *name, +ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, void *buffer, size_t buffer_size) { struct buffer_head *bh = NULL; - struct ext3_xattr_entry *entry; + struct ext4_xattr_entry *entry; size_t size; int error; @@ -223,24 +223,24 @@ ext3_xattr_block_get(struct inode *inode, int name_index, const char *name, name_index, name, buffer, (long)buffer_size); error = -ENODATA; - if (!EXT3_I(inode)->i_file_acl) + if (!EXT4_I(inode)->i_file_acl) goto cleanup; - ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl); - bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + ea_idebug(inode, "reading block %u", EXT4_I(inode)->i_file_acl); + bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); if (!bh) goto cleanup; ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); - if (ext3_xattr_check_block(bh)) { -bad_block: ext3_error(inode->i_sb, __FUNCTION__, + if (ext4_xattr_check_block(bh)) { +bad_block: ext4_error(inode->i_sb, __FUNCTION__, "inode %lu: bad block "E3FSBLK, inode->i_ino, - EXT3_I(inode)->i_file_acl); + EXT4_I(inode)->i_file_acl); error = -EIO; goto cleanup; } - ext3_xattr_cache_insert(bh); + ext4_xattr_cache_insert(bh); entry = BFIRST(bh); - error = ext3_xattr_find_entry(&entry, name_index, name, bh->b_size, 1); + error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1); if (error == -EIO) goto bad_block; if (error) @@ -261,30 +261,30 @@ cleanup: } static int -ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name, +ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, void *buffer, size_t buffer_size) { - struct ext3_xattr_ibody_header *header; - struct ext3_xattr_entry *entry; - struct ext3_inode *raw_inode; - struct ext3_iloc iloc; + struct ext4_xattr_ibody_header *header; + struct ext4_xattr_entry *entry; + struct ext4_inode *raw_inode; + struct ext4_iloc iloc; size_t size; void *end; int error; - if (!(EXT3_I(inode)->i_state & EXT3_STATE_XATTR)) + if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR)) return -ENODATA; - error = ext3_get_inode_loc(inode, &iloc); + error = ext4_get_inode_loc(inode, &iloc); if (error) return error; - raw_inode = ext3_raw_inode(&iloc); + raw_inode = ext4_raw_inode(&iloc); header = IHDR(inode, raw_inode); entry = IFIRST(header); - end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; - error = ext3_xattr_check_names(entry, end); + end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; + error = ext4_xattr_check_names(entry, end); if (error) goto cleanup; - error = ext3_xattr_find_entry(&entry, name_index, name, + error = ext4_xattr_find_entry(&entry, name_index, name, end - (void *)entry, 0); if (error) goto cleanup; @@ -304,7 +304,7 @@ cleanup: } /* - * ext3_xattr_get() + * ext4_xattr_get() * * Copy an extended attribute into the buffer * provided, or compute the buffer size required. @@ -314,30 +314,30 @@ cleanup: * used / required on success. */ int -ext3_xattr_get(struct inode *inode, int name_index, const char *name, +ext4_xattr_get(struct inode *inode, int name_index, const char *name, void *buffer, size_t buffer_size) { int error; - down_read(&EXT3_I(inode)->xattr_sem); - error = ext3_xattr_ibody_get(inode, name_index, name, buffer, + down_read(&EXT4_I(inode)->xattr_sem); + error = ext4_xattr_ibody_get(inode, name_index, name, buffer, buffer_size); if (error == -ENODATA) - error = ext3_xattr_block_get(inode, name_index, name, buffer, + error = ext4_xattr_block_get(inode, name_index, name, buffer, buffer_size); - up_read(&EXT3_I(inode)->xattr_sem); + up_read(&EXT4_I(inode)->xattr_sem); return error; } static int -ext3_xattr_list_entries(struct inode *inode, struct ext3_xattr_entry *entry, +ext4_xattr_list_entries(struct inode *inode, struct ext4_xattr_entry *entry, char *buffer, size_t buffer_size) { size_t rest = buffer_size; - for (; !IS_LAST_ENTRY(entry); entry = EXT3_XATTR_NEXT(entry)) { + for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { struct xattr_handler *handler = - ext3_xattr_handler(entry->e_name_index); + ext4_xattr_handler(entry->e_name_index); if (handler) { size_t size = handler->list(inode, buffer, rest, @@ -355,7 +355,7 @@ ext3_xattr_list_entries(struct inode *inode, struct ext3_xattr_entry *entry, } static int -ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size) +ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size) { struct buffer_head *bh = NULL; int error; @@ -364,24 +364,24 @@ ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size) buffer, (long)buffer_size); error = 0; - if (!EXT3_I(inode)->i_file_acl) + if (!EXT4_I(inode)->i_file_acl) goto cleanup; - ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl); - bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + ea_idebug(inode, "reading block %u", EXT4_I(inode)->i_file_acl); + bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); error = -EIO; if (!bh) goto cleanup; ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); - if (ext3_xattr_check_block(bh)) { - ext3_error(inode->i_sb, __FUNCTION__, + if (ext4_xattr_check_block(bh)) { + ext4_error(inode->i_sb, __FUNCTION__, "inode %lu: bad block "E3FSBLK, inode->i_ino, - EXT3_I(inode)->i_file_acl); + EXT4_I(inode)->i_file_acl); error = -EIO; goto cleanup; } - ext3_xattr_cache_insert(bh); - error = ext3_xattr_list_entries(inode, BFIRST(bh), buffer, buffer_size); + ext4_xattr_cache_insert(bh); + error = ext4_xattr_list_entries(inode, BFIRST(bh), buffer, buffer_size); cleanup: brelse(bh); @@ -390,26 +390,26 @@ cleanup: } static int -ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size) +ext4_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size) { - struct ext3_xattr_ibody_header *header; - struct ext3_inode *raw_inode; - struct ext3_iloc iloc; + struct ext4_xattr_ibody_header *header; + struct ext4_inode *raw_inode; + struct ext4_iloc iloc; void *end; int error; - if (!(EXT3_I(inode)->i_state & EXT3_STATE_XATTR)) + if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR)) return 0; - error = ext3_get_inode_loc(inode, &iloc); + error = ext4_get_inode_loc(inode, &iloc); if (error) return error; - raw_inode = ext3_raw_inode(&iloc); + raw_inode = ext4_raw_inode(&iloc); header = IHDR(inode, raw_inode); - end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; - error = ext3_xattr_check_names(IFIRST(header), end); + end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; + error = ext4_xattr_check_names(IFIRST(header), end); if (error) goto cleanup; - error = ext3_xattr_list_entries(inode, IFIRST(header), + error = ext4_xattr_list_entries(inode, IFIRST(header), buffer, buffer_size); cleanup: @@ -418,7 +418,7 @@ cleanup: } /* - * ext3_xattr_list() + * ext4_xattr_list() * * Copy a list of attribute names into the buffer * provided, or compute the buffer size required. @@ -428,12 +428,12 @@ cleanup: * used / required on success. */ int -ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) +ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) { int i_error, b_error; - down_read(&EXT3_I(inode)->xattr_sem); - i_error = ext3_xattr_ibody_list(inode, buffer, buffer_size); + down_read(&EXT4_I(inode)->xattr_sem); + i_error = ext4_xattr_ibody_list(inode, buffer, buffer_size); if (i_error < 0) { b_error = 0; } else { @@ -441,30 +441,30 @@ ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) buffer += i_error; buffer_size -= i_error; } - b_error = ext3_xattr_block_list(inode, buffer, buffer_size); + b_error = ext4_xattr_block_list(inode, buffer, buffer_size); if (b_error < 0) i_error = 0; } - up_read(&EXT3_I(inode)->xattr_sem); + up_read(&EXT4_I(inode)->xattr_sem); return i_error + b_error; } /* - * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is + * If the EXT4_FEATURE_COMPAT_EXT_ATTR feature of this file system is * not set, set it. */ -static void ext3_xattr_update_super_block(handle_t *handle, +static void ext4_xattr_update_super_block(handle_t *handle, struct super_block *sb) { - if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR)) + if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR)) return; lock_super(sb); - if (ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh) == 0) { - EXT3_SB(sb)->s_es->s_feature_compat |= - cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR); + if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) { + EXT4_SB(sb)->s_es->s_feature_compat |= + cpu_to_le32(EXT4_FEATURE_COMPAT_EXT_ATTR); sb->s_dirt = 1; - ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); } unlock_super(sb); } @@ -474,25 +474,25 @@ static void ext3_xattr_update_super_block(handle_t *handle, * it; otherwise free the block. */ static void -ext3_xattr_release_block(handle_t *handle, struct inode *inode, +ext4_xattr_release_block(handle_t *handle, struct inode *inode, struct buffer_head *bh) { struct mb_cache_entry *ce = NULL; - ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_bdev, bh->b_blocknr); + ce = mb_cache_entry_get(ext4_xattr_cache, bh->b_bdev, bh->b_blocknr); if (BHDR(bh)->h_refcount == cpu_to_le32(1)) { ea_bdebug(bh, "refcount now=0; freeing"); if (ce) mb_cache_entry_free(ce); - ext3_free_blocks(handle, inode, bh->b_blocknr, 1); + ext4_free_blocks(handle, inode, bh->b_blocknr, 1); get_bh(bh); - ext3_forget(handle, 1, inode, bh, bh->b_blocknr); + ext4_forget(handle, 1, inode, bh, bh->b_blocknr); } else { - if (ext3_journal_get_write_access(handle, bh) == 0) { + if (ext4_journal_get_write_access(handle, bh) == 0) { lock_buffer(bh); BHDR(bh)->h_refcount = cpu_to_le32( le32_to_cpu(BHDR(bh)->h_refcount) - 1); - ext3_journal_dirty_metadata(handle, bh); + ext4_journal_dirty_metadata(handle, bh); if (IS_SYNC(inode)) handle->h_sync = 1; DQUOT_FREE_BLOCK(inode, 1); @@ -505,30 +505,30 @@ ext3_xattr_release_block(handle_t *handle, struct inode *inode, } } -struct ext3_xattr_info { +struct ext4_xattr_info { int name_index; const char *name; const void *value; size_t value_len; }; -struct ext3_xattr_search { - struct ext3_xattr_entry *first; +struct ext4_xattr_search { + struct ext4_xattr_entry *first; void *base; void *end; - struct ext3_xattr_entry *here; + struct ext4_xattr_entry *here; int not_found; }; static int -ext3_xattr_set_entry(struct ext3_xattr_info *i, struct ext3_xattr_search *s) +ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) { - struct ext3_xattr_entry *last; + struct ext4_xattr_entry *last; size_t free, min_offs = s->end - s->base, name_len = strlen(i->name); /* Compute min_offs and last. */ last = s->first; - for (; !IS_LAST_ENTRY(last); last = EXT3_XATTR_NEXT(last)) { + for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { if (!last->e_value_block && last->e_value_size) { size_t offs = le16_to_cpu(last->e_value_offs); if (offs < min_offs) @@ -539,20 +539,20 @@ ext3_xattr_set_entry(struct ext3_xattr_info *i, struct ext3_xattr_search *s) if (!s->not_found) { if (!s->here->e_value_block && s->here->e_value_size) { size_t size = le32_to_cpu(s->here->e_value_size); - free += EXT3_XATTR_SIZE(size); + free += EXT4_XATTR_SIZE(size); } - free += EXT3_XATTR_LEN(name_len); + free += EXT4_XATTR_LEN(name_len); } if (i->value) { - if (free < EXT3_XATTR_SIZE(i->value_len) || - free < EXT3_XATTR_LEN(name_len) + - EXT3_XATTR_SIZE(i->value_len)) + if (free < EXT4_XATTR_SIZE(i->value_len) || + free < EXT4_XATTR_LEN(name_len) + + EXT4_XATTR_SIZE(i->value_len)) return -ENOSPC; } if (i->value && s->not_found) { /* Insert the new name. */ - size_t size = EXT3_XATTR_LEN(name_len); + size_t size = EXT4_XATTR_LEN(name_len); size_t rest = (void *)last - (void *)s->here + sizeof(__u32); memmove((void *)s->here + size, s->here, rest); memset(s->here, 0, size); @@ -564,16 +564,16 @@ ext3_xattr_set_entry(struct ext3_xattr_info *i, struct ext3_xattr_search *s) void *first_val = s->base + min_offs; size_t offs = le16_to_cpu(s->here->e_value_offs); void *val = s->base + offs; - size_t size = EXT3_XATTR_SIZE( + size_t size = EXT4_XATTR_SIZE( le32_to_cpu(s->here->e_value_size)); - if (i->value && size == EXT3_XATTR_SIZE(i->value_len)) { + if (i->value && size == EXT4_XATTR_SIZE(i->value_len)) { /* The old and the new value have the same size. Just replace. */ s->here->e_value_size = cpu_to_le32(i->value_len); - memset(val + size - EXT3_XATTR_PAD, 0, - EXT3_XATTR_PAD); /* Clear pad bytes. */ + memset(val + size - EXT4_XATTR_PAD, 0, + EXT4_XATTR_PAD); /* Clear pad bytes. */ memcpy(val, i->value, i->value_len); return 0; } @@ -593,12 +593,12 @@ ext3_xattr_set_entry(struct ext3_xattr_info *i, struct ext3_xattr_search *s) last->e_value_size && o < offs) last->e_value_offs = cpu_to_le16(o + size); - last = EXT3_XATTR_NEXT(last); + last = EXT4_XATTR_NEXT(last); } } if (!i->value) { /* Remove the old name. */ - size_t size = EXT3_XATTR_LEN(name_len); + size_t size = EXT4_XATTR_LEN(name_len); last = ENTRY((void *)last - size); memmove(s->here, (void *)s->here + size, (void *)last - (void *)s->here + sizeof(__u32)); @@ -610,25 +610,25 @@ ext3_xattr_set_entry(struct ext3_xattr_info *i, struct ext3_xattr_search *s) /* Insert the new value. */ s->here->e_value_size = cpu_to_le32(i->value_len); if (i->value_len) { - size_t size = EXT3_XATTR_SIZE(i->value_len); + size_t size = EXT4_XATTR_SIZE(i->value_len); void *val = s->base + min_offs - size; s->here->e_value_offs = cpu_to_le16(min_offs - size); - memset(val + size - EXT3_XATTR_PAD, 0, - EXT3_XATTR_PAD); /* Clear the pad bytes. */ + memset(val + size - EXT4_XATTR_PAD, 0, + EXT4_XATTR_PAD); /* Clear the pad bytes. */ memcpy(val, i->value, i->value_len); } } return 0; } -struct ext3_xattr_block_find { - struct ext3_xattr_search s; +struct ext4_xattr_block_find { + struct ext4_xattr_search s; struct buffer_head *bh; }; static int -ext3_xattr_block_find(struct inode *inode, struct ext3_xattr_info *i, - struct ext3_xattr_block_find *bs) +ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i, + struct ext4_xattr_block_find *bs) { struct super_block *sb = inode->i_sb; int error; @@ -636,19 +636,19 @@ ext3_xattr_block_find(struct inode *inode, struct ext3_xattr_info *i, ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", i->name_index, i->name, i->value, (long)i->value_len); - if (EXT3_I(inode)->i_file_acl) { + if (EXT4_I(inode)->i_file_acl) { /* The inode already has an extended attribute block. */ - bs->bh = sb_bread(sb, EXT3_I(inode)->i_file_acl); + bs->bh = sb_bread(sb, EXT4_I(inode)->i_file_acl); error = -EIO; if (!bs->bh) goto cleanup; ea_bdebug(bs->bh, "b_count=%d, refcount=%d", atomic_read(&(bs->bh->b_count)), le32_to_cpu(BHDR(bs->bh)->h_refcount)); - if (ext3_xattr_check_block(bs->bh)) { - ext3_error(sb, __FUNCTION__, + if (ext4_xattr_check_block(bs->bh)) { + ext4_error(sb, __FUNCTION__, "inode %lu: bad block "E3FSBLK, inode->i_ino, - EXT3_I(inode)->i_file_acl); + EXT4_I(inode)->i_file_acl); error = -EIO; goto cleanup; } @@ -657,7 +657,7 @@ ext3_xattr_block_find(struct inode *inode, struct ext3_xattr_info *i, bs->s.first = BFIRST(bs->bh); bs->s.end = bs->bh->b_data + bs->bh->b_size; bs->s.here = bs->s.first; - error = ext3_xattr_find_entry(&bs->s.here, i->name_index, + error = ext4_xattr_find_entry(&bs->s.here, i->name_index, i->name, bs->bh->b_size, 1); if (error && error != -ENODATA) goto cleanup; @@ -670,22 +670,22 @@ cleanup: } static int -ext3_xattr_block_set(handle_t *handle, struct inode *inode, - struct ext3_xattr_info *i, - struct ext3_xattr_block_find *bs) +ext4_xattr_block_set(handle_t *handle, struct inode *inode, + struct ext4_xattr_info *i, + struct ext4_xattr_block_find *bs) { struct super_block *sb = inode->i_sb; struct buffer_head *new_bh = NULL; - struct ext3_xattr_search *s = &bs->s; + struct ext4_xattr_search *s = &bs->s; struct mb_cache_entry *ce = NULL; int error; -#define header(x) ((struct ext3_xattr_header *)(x)) +#define header(x) ((struct ext4_xattr_header *)(x)) if (i->value && i->value_len > sb->s_blocksize) return -ENOSPC; if (s->base) { - ce = mb_cache_entry_get(ext3_xattr_cache, bs->bh->b_bdev, + ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev, bs->bh->b_blocknr); if (header(s->base)->h_refcount == cpu_to_le32(1)) { if (ce) { @@ -693,22 +693,22 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, ce = NULL; } ea_bdebug(bs->bh, "modifying in-place"); - error = ext3_journal_get_write_access(handle, bs->bh); + error = ext4_journal_get_write_access(handle, bs->bh); if (error) goto cleanup; lock_buffer(bs->bh); - error = ext3_xattr_set_entry(i, s); + error = ext4_xattr_set_entry(i, s); if (!error) { if (!IS_LAST_ENTRY(s->first)) - ext3_xattr_rehash(header(s->base), + ext4_xattr_rehash(header(s->base), s->here); - ext3_xattr_cache_insert(bs->bh); + ext4_xattr_cache_insert(bs->bh); } unlock_buffer(bs->bh); if (error == -EIO) goto bad_block; if (!error) - error = ext3_journal_dirty_metadata(handle, + error = ext4_journal_dirty_metadata(handle, bs->bh); if (error) goto cleanup; @@ -739,7 +739,7 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, if (s->base == NULL) goto cleanup; memset(s->base, 0, sb->s_blocksize); - header(s->base)->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); + header(s->base)->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); header(s->base)->h_blocks = cpu_to_le32(1); header(s->base)->h_refcount = cpu_to_le32(1); s->first = ENTRY(header(s->base)+1); @@ -747,17 +747,17 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, s->end = s->base + sb->s_blocksize; } - error = ext3_xattr_set_entry(i, s); + error = ext4_xattr_set_entry(i, s); if (error == -EIO) goto bad_block; if (error) goto cleanup; if (!IS_LAST_ENTRY(s->first)) - ext3_xattr_rehash(header(s->base), s->here); + ext4_xattr_rehash(header(s->base), s->here); inserted: if (!IS_LAST_ENTRY(s->first)) { - new_bh = ext3_xattr_cache_find(inode, header(s->base), &ce); + new_bh = ext4_xattr_cache_find(inode, header(s->base), &ce); if (new_bh) { /* We found an identical block in the cache. */ if (new_bh == bs->bh) @@ -768,7 +768,7 @@ inserted: error = -EDQUOT; if (DQUOT_ALLOC_BLOCK(inode, 1)) goto cleanup; - error = ext3_journal_get_write_access(handle, + error = ext4_journal_get_write_access(handle, new_bh); if (error) goto cleanup_dquot; @@ -778,7 +778,7 @@ inserted: ea_bdebug(new_bh, "reusing; refcount now=%d", le32_to_cpu(BHDR(new_bh)->h_refcount)); unlock_buffer(new_bh); - error = ext3_journal_dirty_metadata(handle, + error = ext4_journal_dirty_metadata(handle, new_bh); if (error) goto cleanup_dquot; @@ -792,11 +792,11 @@ inserted: get_bh(new_bh); } else { /* We need to allocate a new block */ - ext3_fsblk_t goal = le32_to_cpu( - EXT3_SB(sb)->s_es->s_first_data_block) + - (ext3_fsblk_t)EXT3_I(inode)->i_block_group * - EXT3_BLOCKS_PER_GROUP(sb); - ext3_fsblk_t block = ext3_new_block(handle, inode, + ext4_fsblk_t goal = le32_to_cpu( + EXT4_SB(sb)->s_es->s_first_data_block) + + (ext4_fsblk_t)EXT4_I(inode)->i_block_group * + EXT4_BLOCKS_PER_GROUP(sb); + ext4_fsblk_t block = ext4_new_block(handle, inode, goal, &error); if (error) goto cleanup; @@ -805,12 +805,12 @@ inserted: new_bh = sb_getblk(sb, block); if (!new_bh) { getblk_failed: - ext3_free_blocks(handle, inode, block, 1); + ext4_free_blocks(handle, inode, block, 1); error = -EIO; goto cleanup; } lock_buffer(new_bh); - error = ext3_journal_get_create_access(handle, new_bh); + error = ext4_journal_get_create_access(handle, new_bh); if (error) { unlock_buffer(new_bh); goto getblk_failed; @@ -818,19 +818,19 @@ getblk_failed: memcpy(new_bh->b_data, s->base, new_bh->b_size); set_buffer_uptodate(new_bh); unlock_buffer(new_bh); - ext3_xattr_cache_insert(new_bh); - error = ext3_journal_dirty_metadata(handle, new_bh); + ext4_xattr_cache_insert(new_bh); + error = ext4_journal_dirty_metadata(handle, new_bh); if (error) goto cleanup; } } /* Update the inode. */ - EXT3_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; + EXT4_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; /* Drop the previous xattr block. */ if (bs->bh && bs->bh != new_bh) - ext3_xattr_release_block(handle, inode, bs->bh); + ext4_xattr_release_block(handle, inode, bs->bh); error = 0; cleanup: @@ -847,40 +847,40 @@ cleanup_dquot: goto cleanup; bad_block: - ext3_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __FUNCTION__, "inode %lu: bad block "E3FSBLK, inode->i_ino, - EXT3_I(inode)->i_file_acl); + EXT4_I(inode)->i_file_acl); goto cleanup; #undef header } -struct ext3_xattr_ibody_find { - struct ext3_xattr_search s; - struct ext3_iloc iloc; +struct ext4_xattr_ibody_find { + struct ext4_xattr_search s; + struct ext4_iloc iloc; }; static int -ext3_xattr_ibody_find(struct inode *inode, struct ext3_xattr_info *i, - struct ext3_xattr_ibody_find *is) +ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, + struct ext4_xattr_ibody_find *is) { - struct ext3_xattr_ibody_header *header; - struct ext3_inode *raw_inode; + struct ext4_xattr_ibody_header *header; + struct ext4_inode *raw_inode; int error; - if (EXT3_I(inode)->i_extra_isize == 0) + if (EXT4_I(inode)->i_extra_isize == 0) return 0; - raw_inode = ext3_raw_inode(&is->iloc); + raw_inode = ext4_raw_inode(&is->iloc); header = IHDR(inode, raw_inode); is->s.base = is->s.first = IFIRST(header); is->s.here = is->s.first; - is->s.end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; - if (EXT3_I(inode)->i_state & EXT3_STATE_XATTR) { - error = ext3_xattr_check_names(IFIRST(header), is->s.end); + is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; + if (EXT4_I(inode)->i_state & EXT4_STATE_XATTR) { + error = ext4_xattr_check_names(IFIRST(header), is->s.end); if (error) return error; /* Find the named attribute. */ - error = ext3_xattr_find_entry(&is->s.here, i->name_index, + error = ext4_xattr_find_entry(&is->s.here, i->name_index, i->name, is->s.end - (void *)is->s.base, 0); if (error && error != -ENODATA) @@ -891,32 +891,32 @@ ext3_xattr_ibody_find(struct inode *inode, struct ext3_xattr_info *i, } static int -ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, - struct ext3_xattr_info *i, - struct ext3_xattr_ibody_find *is) +ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, + struct ext4_xattr_info *i, + struct ext4_xattr_ibody_find *is) { - struct ext3_xattr_ibody_header *header; - struct ext3_xattr_search *s = &is->s; + struct ext4_xattr_ibody_header *header; + struct ext4_xattr_search *s = &is->s; int error; - if (EXT3_I(inode)->i_extra_isize == 0) + if (EXT4_I(inode)->i_extra_isize == 0) return -ENOSPC; - error = ext3_xattr_set_entry(i, s); + error = ext4_xattr_set_entry(i, s); if (error) return error; - header = IHDR(inode, ext3_raw_inode(&is->iloc)); + header = IHDR(inode, ext4_raw_inode(&is->iloc)); if (!IS_LAST_ENTRY(s->first)) { - header->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); - EXT3_I(inode)->i_state |= EXT3_STATE_XATTR; + header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); + EXT4_I(inode)->i_state |= EXT4_STATE_XATTR; } else { header->h_magic = cpu_to_le32(0); - EXT3_I(inode)->i_state &= ~EXT3_STATE_XATTR; + EXT4_I(inode)->i_state &= ~EXT4_STATE_XATTR; } return 0; } /* - * ext3_xattr_set_handle() + * ext4_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 @@ -928,21 +928,21 @@ ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, * Returns 0, or a negative error number on failure. */ int -ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, +ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, const char *name, const void *value, size_t value_len, int flags) { - struct ext3_xattr_info i = { + struct ext4_xattr_info i = { .name_index = name_index, .name = name, .value = value, .value_len = value_len, }; - struct ext3_xattr_ibody_find is = { + struct ext4_xattr_ibody_find is = { .s = { .not_found = -ENODATA, }, }; - struct ext3_xattr_block_find bs = { + struct ext4_xattr_block_find bs = { .s = { .not_found = -ENODATA, }, }; int error; @@ -951,22 +951,22 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, return -EINVAL; if (strlen(name) > 255) return -ERANGE; - down_write(&EXT3_I(inode)->xattr_sem); - error = ext3_get_inode_loc(inode, &is.iloc); + down_write(&EXT4_I(inode)->xattr_sem); + error = ext4_get_inode_loc(inode, &is.iloc); if (error) goto cleanup; - if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) { - struct ext3_inode *raw_inode = ext3_raw_inode(&is.iloc); - memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size); - EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW; + if (EXT4_I(inode)->i_state & EXT4_STATE_NEW) { + struct ext4_inode *raw_inode = ext4_raw_inode(&is.iloc); + memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); + EXT4_I(inode)->i_state &= ~EXT4_STATE_NEW; } - error = ext3_xattr_ibody_find(inode, &i, &is); + error = ext4_xattr_ibody_find(inode, &i, &is); if (error) goto cleanup; if (is.s.not_found) - error = ext3_xattr_block_find(inode, &i, &bs); + error = ext4_xattr_block_find(inode, &i, &bs); if (error) goto cleanup; if (is.s.not_found && bs.s.not_found) { @@ -981,36 +981,36 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, if (flags & XATTR_CREATE) goto cleanup; } - error = ext3_journal_get_write_access(handle, is.iloc.bh); + error = ext4_journal_get_write_access(handle, is.iloc.bh); if (error) goto cleanup; if (!value) { if (!is.s.not_found) - error = ext3_xattr_ibody_set(handle, inode, &i, &is); + error = ext4_xattr_ibody_set(handle, inode, &i, &is); else if (!bs.s.not_found) - error = ext3_xattr_block_set(handle, inode, &i, &bs); + error = ext4_xattr_block_set(handle, inode, &i, &bs); } else { - error = ext3_xattr_ibody_set(handle, inode, &i, &is); + error = ext4_xattr_ibody_set(handle, inode, &i, &is); if (!error && !bs.s.not_found) { i.value = NULL; - error = ext3_xattr_block_set(handle, inode, &i, &bs); + error = ext4_xattr_block_set(handle, inode, &i, &bs); } else if (error == -ENOSPC) { - error = ext3_xattr_block_set(handle, inode, &i, &bs); + error = ext4_xattr_block_set(handle, inode, &i, &bs); if (error) goto cleanup; if (!is.s.not_found) { i.value = NULL; - error = ext3_xattr_ibody_set(handle, inode, &i, + error = ext4_xattr_ibody_set(handle, inode, &i, &is); } } } if (!error) { - ext3_xattr_update_super_block(handle, inode->i_sb); + ext4_xattr_update_super_block(handle, inode->i_sb); inode->i_ctime = CURRENT_TIME_SEC; - error = ext3_mark_iloc_dirty(handle, inode, &is.iloc); + error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); /* - * The bh is consumed by ext3_mark_iloc_dirty, even with + * The bh is consumed by ext4_mark_iloc_dirty, even with * error != 0. */ is.iloc.bh = NULL; @@ -1021,37 +1021,37 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, cleanup: brelse(is.iloc.bh); brelse(bs.bh); - up_write(&EXT3_I(inode)->xattr_sem); + up_write(&EXT4_I(inode)->xattr_sem); return error; } /* - * ext3_xattr_set() + * ext4_xattr_set() * - * Like ext3_xattr_set_handle, but start from an inode. This extended + * Like ext4_xattr_set_handle, but start from an inode. This extended * attribute modification is a filesystem transaction by itself. * * Returns 0, or a negative error number on failure. */ int -ext3_xattr_set(struct inode *inode, int name_index, const char *name, +ext4_xattr_set(struct inode *inode, int name_index, const char *name, const void *value, size_t value_len, int flags) { handle_t *handle; int error, retries = 0; retry: - handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); + handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); if (IS_ERR(handle)) { error = PTR_ERR(handle); } else { int error2; - error = ext3_xattr_set_handle(handle, inode, name_index, name, + error = ext4_xattr_set_handle(handle, inode, name_index, name, value, value_len, flags); - error2 = ext3_journal_stop(handle); + error2 = ext4_journal_stop(handle); if (error == -ENOSPC && - ext3_should_retry_alloc(inode->i_sb, &retries)) + ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; if (error == 0) error = error2; @@ -1061,53 +1061,53 @@ retry: } /* - * ext3_xattr_delete_inode() + * ext4_xattr_delete_inode() * * Free extended attribute resources associated with this inode. This * is called immediately before an inode is freed. We have exclusive * access to the inode. */ void -ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) +ext4_xattr_delete_inode(handle_t *handle, struct inode *inode) { struct buffer_head *bh = NULL; - if (!EXT3_I(inode)->i_file_acl) + if (!EXT4_I(inode)->i_file_acl) goto cleanup; - bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); if (!bh) { - ext3_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __FUNCTION__, "inode %lu: block "E3FSBLK" read error", inode->i_ino, - EXT3_I(inode)->i_file_acl); + EXT4_I(inode)->i_file_acl); goto cleanup; } - if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || + if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || BHDR(bh)->h_blocks != cpu_to_le32(1)) { - ext3_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __FUNCTION__, "inode %lu: bad block "E3FSBLK, inode->i_ino, - EXT3_I(inode)->i_file_acl); + EXT4_I(inode)->i_file_acl); goto cleanup; } - ext3_xattr_release_block(handle, inode, bh); - EXT3_I(inode)->i_file_acl = 0; + ext4_xattr_release_block(handle, inode, bh); + EXT4_I(inode)->i_file_acl = 0; cleanup: brelse(bh); } /* - * ext3_xattr_put_super() + * ext4_xattr_put_super() * * This is called when a file system is unmounted. */ void -ext3_xattr_put_super(struct super_block *sb) +ext4_xattr_put_super(struct super_block *sb) { mb_cache_shrink(sb->s_bdev); } /* - * ext3_xattr_cache_insert() + * ext4_xattr_cache_insert() * * Create a new entry in the extended attribute cache, and insert * it unless such an entry is already in the cache. @@ -1115,13 +1115,13 @@ ext3_xattr_put_super(struct super_block *sb) * Returns 0, or a negative error number on failure. */ static void -ext3_xattr_cache_insert(struct buffer_head *bh) +ext4_xattr_cache_insert(struct buffer_head *bh) { __u32 hash = le32_to_cpu(BHDR(bh)->h_hash); struct mb_cache_entry *ce; int error; - ce = mb_cache_entry_alloc(ext3_xattr_cache); + ce = mb_cache_entry_alloc(ext4_xattr_cache); if (!ce) { ea_bdebug(bh, "out of memory"); return; @@ -1140,7 +1140,7 @@ ext3_xattr_cache_insert(struct buffer_head *bh) } /* - * ext3_xattr_cmp() + * ext4_xattr_cmp() * * Compare two extended attribute blocks for equality. * @@ -1148,10 +1148,10 @@ ext3_xattr_cache_insert(struct buffer_head *bh) * a negative error number on errors. */ static int -ext3_xattr_cmp(struct ext3_xattr_header *header1, - struct ext3_xattr_header *header2) +ext4_xattr_cmp(struct ext4_xattr_header *header1, + struct ext4_xattr_header *header2) { - struct ext3_xattr_entry *entry1, *entry2; + struct ext4_xattr_entry *entry1, *entry2; entry1 = ENTRY(header1+1); entry2 = ENTRY(header2+1); @@ -1171,8 +1171,8 @@ ext3_xattr_cmp(struct ext3_xattr_header *header1, le32_to_cpu(entry1->e_value_size))) return 1; - entry1 = EXT3_XATTR_NEXT(entry1); - entry2 = EXT3_XATTR_NEXT(entry2); + entry1 = EXT4_XATTR_NEXT(entry1); + entry2 = EXT4_XATTR_NEXT(entry2); } if (!IS_LAST_ENTRY(entry2)) return 1; @@ -1180,7 +1180,7 @@ ext3_xattr_cmp(struct ext3_xattr_header *header1, } /* - * ext3_xattr_cache_find() + * ext4_xattr_cache_find() * * Find an identical extended attribute block. * @@ -1188,7 +1188,7 @@ ext3_xattr_cmp(struct ext3_xattr_header *header1, * not found or an error occurred. */ static struct buffer_head * -ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header, +ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header, struct mb_cache_entry **pce) { __u32 hash = le32_to_cpu(header->h_hash); @@ -1198,7 +1198,7 @@ ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header, return NULL; /* never share */ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); again: - ce = mb_cache_entry_find_first(ext3_xattr_cache, 0, + ce = mb_cache_entry_find_first(ext4_xattr_cache, 0, inode->i_sb->s_bdev, hash); while (ce) { struct buffer_head *bh; @@ -1210,16 +1210,16 @@ again: } bh = sb_bread(inode->i_sb, ce->e_block); if (!bh) { - ext3_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __FUNCTION__, "inode %lu: block %lu read error", inode->i_ino, (unsigned long) ce->e_block); } else if (le32_to_cpu(BHDR(bh)->h_refcount) >= - EXT3_XATTR_REFCOUNT_MAX) { + EXT4_XATTR_REFCOUNT_MAX) { ea_idebug(inode, "block %lu refcount %d>=%d", (unsigned long) ce->e_block, le32_to_cpu(BHDR(bh)->h_refcount), - EXT3_XATTR_REFCOUNT_MAX); - } else if (ext3_xattr_cmp(header, BHDR(bh)) == 0) { + EXT4_XATTR_REFCOUNT_MAX); + } else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) { *pce = ce; return bh; } @@ -1233,12 +1233,12 @@ again: #define VALUE_HASH_SHIFT 16 /* - * ext3_xattr_hash_entry() + * ext4_xattr_hash_entry() * * Compute the hash of an extended attribute. */ -static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header, - struct ext3_xattr_entry *entry) +static inline void ext4_xattr_hash_entry(struct ext4_xattr_header *header, + struct ext4_xattr_entry *entry) { __u32 hash = 0; char *name = entry->e_name; @@ -1254,7 +1254,7 @@ static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header, __le32 *value = (__le32 *)((char *)header + le16_to_cpu(entry->e_value_offs)); for (n = (le32_to_cpu(entry->e_value_size) + - EXT3_XATTR_ROUND) >> EXT3_XATTR_PAD_BITS; n; n--) { + EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) { hash = (hash << VALUE_HASH_SHIFT) ^ (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ le32_to_cpu(*value++); @@ -1269,17 +1269,17 @@ static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header, #define BLOCK_HASH_SHIFT 16 /* - * ext3_xattr_rehash() + * ext4_xattr_rehash() * * Re-compute the extended attribute hash value after an entry has changed. */ -static void ext3_xattr_rehash(struct ext3_xattr_header *header, - struct ext3_xattr_entry *entry) +static void ext4_xattr_rehash(struct ext4_xattr_header *header, + struct ext4_xattr_entry *entry) { - struct ext3_xattr_entry *here; + struct ext4_xattr_entry *here; __u32 hash = 0; - ext3_xattr_hash_entry(header, entry); + ext4_xattr_hash_entry(header, entry); here = ENTRY(header+1); while (!IS_LAST_ENTRY(here)) { if (!here->e_hash) { @@ -1290,7 +1290,7 @@ static void ext3_xattr_rehash(struct ext3_xattr_header *header, hash = (hash << BLOCK_HASH_SHIFT) ^ (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ le32_to_cpu(here->e_hash); - here = EXT3_XATTR_NEXT(here); + here = EXT4_XATTR_NEXT(here); } header->h_hash = cpu_to_le32(hash); } @@ -1298,20 +1298,20 @@ static void ext3_xattr_rehash(struct ext3_xattr_header *header, #undef BLOCK_HASH_SHIFT int __init -init_ext3_xattr(void) +init_ext4_xattr(void) { - ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL, + ext4_xattr_cache = mb_cache_create("ext4_xattr", NULL, sizeof(struct mb_cache_entry) + sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6); - if (!ext3_xattr_cache) + if (!ext4_xattr_cache) return -ENOMEM; return 0; } void -exit_ext3_xattr(void) +exit_ext4_xattr(void) { - if (ext3_xattr_cache) - mb_cache_destroy(ext3_xattr_cache); - ext3_xattr_cache = NULL; + if (ext4_xattr_cache) + mb_cache_destroy(ext4_xattr_cache); + ext4_xattr_cache = NULL; } diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index 6b1ae1c6182c..79432b35398f 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -1,7 +1,7 @@ /* - File: fs/ext3/xattr.h + File: fs/ext4/xattr.h - On-disk format of extended attributes for the ext3 filesystem. + On-disk format of extended attributes for the ext4 filesystem. (C) 2001 Andreas Gruenbacher, */ @@ -9,20 +9,20 @@ #include /* Magic value in attribute blocks */ -#define EXT3_XATTR_MAGIC 0xEA020000 +#define EXT4_XATTR_MAGIC 0xEA020000 /* Maximum number of references to one attribute block */ -#define EXT3_XATTR_REFCOUNT_MAX 1024 +#define EXT4_XATTR_REFCOUNT_MAX 1024 /* Name indexes */ -#define EXT3_XATTR_INDEX_USER 1 -#define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS 2 -#define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT 3 -#define EXT3_XATTR_INDEX_TRUSTED 4 -#define EXT3_XATTR_INDEX_LUSTRE 5 -#define EXT3_XATTR_INDEX_SECURITY 6 - -struct ext3_xattr_header { +#define EXT4_XATTR_INDEX_USER 1 +#define EXT4_XATTR_INDEX_POSIX_ACL_ACCESS 2 +#define EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT 3 +#define EXT4_XATTR_INDEX_TRUSTED 4 +#define EXT4_XATTR_INDEX_LUSTRE 5 +#define EXT4_XATTR_INDEX_SECURITY 6 + +struct ext4_xattr_header { __le32 h_magic; /* magic number for identification */ __le32 h_refcount; /* reference count */ __le32 h_blocks; /* number of disk blocks used */ @@ -30,11 +30,11 @@ struct ext3_xattr_header { __u32 h_reserved[4]; /* zero right now */ }; -struct ext3_xattr_ibody_header { +struct ext4_xattr_ibody_header { __le32 h_magic; /* magic number for identification */ }; -struct ext3_xattr_entry { +struct ext4_xattr_entry { __u8 e_name_len; /* length of name */ __u8 e_name_index; /* attribute name index */ __le16 e_value_offs; /* offset in disk block of value */ @@ -44,100 +44,100 @@ struct ext3_xattr_entry { char e_name[0]; /* attribute name */ }; -#define EXT3_XATTR_PAD_BITS 2 -#define EXT3_XATTR_PAD (1<e_name_len)) ) -#define EXT3_XATTR_SIZE(size) \ - (((size) + EXT3_XATTR_ROUND) & ~EXT3_XATTR_ROUND) +#define EXT4_XATTR_PAD_BITS 2 +#define EXT4_XATTR_PAD (1<e_name_len)) ) +#define EXT4_XATTR_SIZE(size) \ + (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND) -# ifdef CONFIG_EXT3_FS_XATTR +# ifdef CONFIG_EXT4DEV_FS_XATTR -extern struct xattr_handler ext3_xattr_user_handler; -extern struct xattr_handler ext3_xattr_trusted_handler; -extern struct xattr_handler ext3_xattr_acl_access_handler; -extern struct xattr_handler ext3_xattr_acl_default_handler; -extern struct xattr_handler ext3_xattr_security_handler; +extern struct xattr_handler ext4_xattr_user_handler; +extern struct xattr_handler ext4_xattr_trusted_handler; +extern struct xattr_handler ext4_xattr_acl_access_handler; +extern struct xattr_handler ext4_xattr_acl_default_handler; +extern struct xattr_handler ext4_xattr_security_handler; -extern ssize_t ext3_listxattr(struct dentry *, char *, size_t); +extern ssize_t ext4_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 ext4_xattr_get(struct inode *, int, const char *, void *, size_t); +extern int ext4_xattr_list(struct inode *, char *, size_t); +extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int); +extern int ext4_xattr_set_handle(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 *); +extern void ext4_xattr_delete_inode(handle_t *, struct inode *); +extern void ext4_xattr_put_super(struct super_block *); -extern int init_ext3_xattr(void); -extern void exit_ext3_xattr(void); +extern int init_ext4_xattr(void); +extern void exit_ext4_xattr(void); -extern struct xattr_handler *ext3_xattr_handlers[]; +extern struct xattr_handler *ext4_xattr_handlers[]; -# else /* CONFIG_EXT3_FS_XATTR */ +# else /* CONFIG_EXT4DEV_FS_XATTR */ static inline int -ext3_xattr_get(struct inode *inode, int name_index, const char *name, +ext4_xattr_get(struct inode *inode, int name_index, const char *name, void *buffer, size_t size, int flags) { return -EOPNOTSUPP; } static inline int -ext3_xattr_list(struct inode *inode, void *buffer, size_t size) +ext4_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, +ext4_xattr_set(struct inode *inode, int name_index, const char *name, const void *value, size_t size, int flags) { return -EOPNOTSUPP; } static inline int -ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, +ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, const char *name, const void *value, size_t size, int flags) { return -EOPNOTSUPP; } static inline void -ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) +ext4_xattr_delete_inode(handle_t *handle, struct inode *inode) { } static inline void -ext3_xattr_put_super(struct super_block *sb) +ext4_xattr_put_super(struct super_block *sb) { } static inline int -init_ext3_xattr(void) +init_ext4_xattr(void) { return 0; } static inline void -exit_ext3_xattr(void) +exit_ext4_xattr(void) { } -#define ext3_xattr_handlers NULL +#define ext4_xattr_handlers NULL -# endif /* CONFIG_EXT3_FS_XATTR */ +# endif /* CONFIG_EXT4DEV_FS_XATTR */ -#ifdef CONFIG_EXT3_FS_SECURITY -extern int ext3_init_security(handle_t *handle, struct inode *inode, +#ifdef CONFIG_EXT4DEV_FS_SECURITY +extern int ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir); #else -static inline int ext3_init_security(handle_t *handle, struct inode *inode, +static inline int ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir) { return 0; diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c index b9c40c15647b..d84b1dabeb16 100644 --- a/fs/ext4/xattr_security.c +++ b/fs/ext4/xattr_security.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/xattr_security.c + * linux/fs/ext4/xattr_security.c * Handler for storing security labels as extended attributes. */ @@ -7,13 +7,13 @@ #include #include #include -#include -#include +#include +#include #include #include "xattr.h" static size_t -ext3_xattr_security_list(struct inode *inode, char *list, size_t list_size, +ext4_xattr_security_list(struct inode *inode, char *list, size_t list_size, const char *name, size_t name_len) { const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1; @@ -29,27 +29,27 @@ ext3_xattr_security_list(struct inode *inode, char *list, size_t list_size, } static int -ext3_xattr_security_get(struct inode *inode, const char *name, +ext4_xattr_security_get(struct inode *inode, const char *name, void *buffer, size_t size) { if (strcmp(name, "") == 0) return -EINVAL; - return ext3_xattr_get(inode, EXT3_XATTR_INDEX_SECURITY, name, + return ext4_xattr_get(inode, EXT4_XATTR_INDEX_SECURITY, name, buffer, size); } static int -ext3_xattr_security_set(struct inode *inode, const char *name, +ext4_xattr_security_set(struct inode *inode, const char *name, const void *value, size_t size, int flags) { if (strcmp(name, "") == 0) return -EINVAL; - return ext3_xattr_set(inode, EXT3_XATTR_INDEX_SECURITY, name, + return ext4_xattr_set(inode, EXT4_XATTR_INDEX_SECURITY, name, value, size, flags); } int -ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir) +ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir) { int err; size_t len; @@ -62,16 +62,16 @@ ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir) return 0; return err; } - err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY, + err = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_SECURITY, name, value, len, 0); kfree(name); kfree(value); return err; } -struct xattr_handler ext3_xattr_security_handler = { +struct xattr_handler ext4_xattr_security_handler = { .prefix = XATTR_SECURITY_PREFIX, - .list = ext3_xattr_security_list, - .get = ext3_xattr_security_get, - .set = ext3_xattr_security_set, + .list = ext4_xattr_security_list, + .get = ext4_xattr_security_get, + .set = ext4_xattr_security_set, }; diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c index 86d91f1186dc..11bd58c95a61 100644 --- a/fs/ext4/xattr_trusted.c +++ b/fs/ext4/xattr_trusted.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/xattr_trusted.c + * linux/fs/ext4/xattr_trusted.c * Handler for trusted extended attributes. * * Copyright (C) 2003 by Andreas Gruenbacher, @@ -10,14 +10,14 @@ #include #include #include -#include -#include +#include +#include #include "xattr.h" #define XATTR_TRUSTED_PREFIX "trusted." static size_t -ext3_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, +ext4_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, const char *name, size_t name_len) { const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX)-1; @@ -35,28 +35,28 @@ ext3_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, } static int -ext3_xattr_trusted_get(struct inode *inode, const char *name, +ext4_xattr_trusted_get(struct inode *inode, const char *name, void *buffer, size_t size) { if (strcmp(name, "") == 0) return -EINVAL; - return ext3_xattr_get(inode, EXT3_XATTR_INDEX_TRUSTED, name, + return ext4_xattr_get(inode, EXT4_XATTR_INDEX_TRUSTED, name, buffer, size); } static int -ext3_xattr_trusted_set(struct inode *inode, const char *name, +ext4_xattr_trusted_set(struct inode *inode, const char *name, const void *value, size_t size, int flags) { if (strcmp(name, "") == 0) return -EINVAL; - return ext3_xattr_set(inode, EXT3_XATTR_INDEX_TRUSTED, name, + return ext4_xattr_set(inode, EXT4_XATTR_INDEX_TRUSTED, name, value, size, flags); } -struct xattr_handler ext3_xattr_trusted_handler = { +struct xattr_handler ext4_xattr_trusted_handler = { .prefix = XATTR_TRUSTED_PREFIX, - .list = ext3_xattr_trusted_list, - .get = ext3_xattr_trusted_get, - .set = ext3_xattr_trusted_set, + .list = ext4_xattr_trusted_list, + .get = ext4_xattr_trusted_get, + .set = ext4_xattr_trusted_set, }; diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c index a85a0a17c4fd..9c5a665e0837 100644 --- a/fs/ext4/xattr_user.c +++ b/fs/ext4/xattr_user.c @@ -1,5 +1,5 @@ /* - * linux/fs/ext3/xattr_user.c + * linux/fs/ext4/xattr_user.c * Handler for extended user attributes. * * Copyright (C) 2001 by Andreas Gruenbacher, @@ -9,14 +9,14 @@ #include #include #include -#include -#include +#include +#include #include "xattr.h" #define XATTR_USER_PREFIX "user." static size_t -ext3_xattr_user_list(struct inode *inode, char *list, size_t list_size, +ext4_xattr_user_list(struct inode *inode, char *list, size_t list_size, const char *name, size_t name_len) { const size_t prefix_len = sizeof(XATTR_USER_PREFIX)-1; @@ -34,31 +34,31 @@ ext3_xattr_user_list(struct inode *inode, char *list, size_t list_size, } static int -ext3_xattr_user_get(struct inode *inode, const char *name, +ext4_xattr_user_get(struct inode *inode, const char *name, void *buffer, size_t size) { if (strcmp(name, "") == 0) return -EINVAL; if (!test_opt(inode->i_sb, XATTR_USER)) return -EOPNOTSUPP; - return ext3_xattr_get(inode, EXT3_XATTR_INDEX_USER, name, buffer, size); + return ext4_xattr_get(inode, EXT4_XATTR_INDEX_USER, name, buffer, size); } static int -ext3_xattr_user_set(struct inode *inode, const char *name, +ext4_xattr_user_set(struct inode *inode, const char *name, const void *value, size_t size, int flags) { if (strcmp(name, "") == 0) return -EINVAL; if (!test_opt(inode->i_sb, XATTR_USER)) return -EOPNOTSUPP; - return ext3_xattr_set(inode, EXT3_XATTR_INDEX_USER, name, + return ext4_xattr_set(inode, EXT4_XATTR_INDEX_USER, name, value, size, flags); } -struct xattr_handler ext3_xattr_user_handler = { +struct xattr_handler ext4_xattr_user_handler = { .prefix = XATTR_USER_PREFIX, - .list = ext3_xattr_user_list, - .get = ext3_xattr_user_get, - .set = ext3_xattr_user_set, + .list = ext4_xattr_user_list, + .get = ext4_xattr_user_get, + .set = ext4_xattr_user_set, }; diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index 11cca1bdc0c7..f582cd762caf 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/ext3_fs.h + * linux/include/linux/ext4_fs.h * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -13,8 +13,8 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#ifndef _LINUX_EXT3_FS_H -#define _LINUX_EXT3_FS_H +#ifndef _LINUX_EXT4_FS_H +#define _LINUX_EXT4_FS_H #include #include @@ -24,102 +24,102 @@ */ /* - * Define EXT3FS_DEBUG to produce debug messages + * Define EXT4FS_DEBUG to produce debug messages */ -#undef EXT3FS_DEBUG +#undef EXT4FS_DEBUG /* - * Define EXT3_RESERVATION to reserve data blocks for expanding files + * Define EXT4_RESERVATION to reserve data blocks for expanding files */ -#define EXT3_DEFAULT_RESERVE_BLOCKS 8 +#define EXT4_DEFAULT_RESERVE_BLOCKS 8 /*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */ -#define EXT3_MAX_RESERVE_BLOCKS 1027 -#define EXT3_RESERVE_WINDOW_NOT_ALLOCATED 0 +#define EXT4_MAX_RESERVE_BLOCKS 1027 +#define EXT4_RESERVE_WINDOW_NOT_ALLOCATED 0 /* * Always enable hashed directories */ -#define CONFIG_EXT3_INDEX +#define CONFIG_EXT4_INDEX /* * Debug code */ -#ifdef EXT3FS_DEBUG -#define ext3_debug(f, a...) \ +#ifdef EXT4FS_DEBUG +#define ext4_debug(f, a...) \ do { \ - printk (KERN_DEBUG "EXT3-fs DEBUG (%s, %d): %s:", \ + printk (KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:", \ __FILE__, __LINE__, __FUNCTION__); \ printk (KERN_DEBUG f, ## a); \ } while (0) #else -#define ext3_debug(f, a...) do {} while (0) +#define ext4_debug(f, a...) do {} while (0) #endif /* * Special inodes numbers */ -#define EXT3_BAD_INO 1 /* Bad blocks inode */ -#define EXT3_ROOT_INO 2 /* Root inode */ -#define EXT3_BOOT_LOADER_INO 5 /* Boot loader inode */ -#define EXT3_UNDEL_DIR_INO 6 /* Undelete directory inode */ -#define EXT3_RESIZE_INO 7 /* Reserved group descriptors inode */ -#define EXT3_JOURNAL_INO 8 /* Journal inode */ +#define EXT4_BAD_INO 1 /* Bad blocks inode */ +#define EXT4_ROOT_INO 2 /* Root inode */ +#define EXT4_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */ +#define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */ +#define EXT4_JOURNAL_INO 8 /* Journal inode */ -/* First non-reserved inode for old ext3 filesystems */ -#define EXT3_GOOD_OLD_FIRST_INO 11 +/* First non-reserved inode for old ext4 filesystems */ +#define EXT4_GOOD_OLD_FIRST_INO 11 /* * Maximal count of links to a file */ -#define EXT3_LINK_MAX 32000 +#define EXT4_LINK_MAX 32000 /* * Macro-instructions used to manage several block sizes */ -#define EXT3_MIN_BLOCK_SIZE 1024 -#define EXT3_MAX_BLOCK_SIZE 4096 -#define EXT3_MIN_BLOCK_LOG_SIZE 10 +#define EXT4_MIN_BLOCK_SIZE 1024 +#define EXT4_MAX_BLOCK_SIZE 4096 +#define EXT4_MIN_BLOCK_LOG_SIZE 10 #ifdef __KERNEL__ -# define EXT3_BLOCK_SIZE(s) ((s)->s_blocksize) +# define EXT4_BLOCK_SIZE(s) ((s)->s_blocksize) #else -# define EXT3_BLOCK_SIZE(s) (EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size) +# define EXT4_BLOCK_SIZE(s) (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size) #endif -#define EXT3_ADDR_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (__u32)) +#define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof (__u32)) #ifdef __KERNEL__ -# define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) +# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) #else -# define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) #endif #ifdef __KERNEL__ -#define EXT3_ADDR_PER_BLOCK_BITS(s) (EXT3_SB(s)->s_addr_per_block_bits) -#define EXT3_INODE_SIZE(s) (EXT3_SB(s)->s_inode_size) -#define EXT3_FIRST_INO(s) (EXT3_SB(s)->s_first_ino) +#define EXT4_ADDR_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_addr_per_block_bits) +#define EXT4_INODE_SIZE(s) (EXT4_SB(s)->s_inode_size) +#define EXT4_FIRST_INO(s) (EXT4_SB(s)->s_first_ino) #else -#define EXT3_INODE_SIZE(s) (((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \ - EXT3_GOOD_OLD_INODE_SIZE : \ +#define EXT4_INODE_SIZE(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \ + EXT4_GOOD_OLD_INODE_SIZE : \ (s)->s_inode_size) -#define EXT3_FIRST_INO(s) (((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \ - EXT3_GOOD_OLD_FIRST_INO : \ +#define EXT4_FIRST_INO(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \ + EXT4_GOOD_OLD_FIRST_INO : \ (s)->s_first_ino) #endif /* * Macro-instructions used to manage fragments */ -#define EXT3_MIN_FRAG_SIZE 1024 -#define EXT3_MAX_FRAG_SIZE 4096 -#define EXT3_MIN_FRAG_LOG_SIZE 10 +#define EXT4_MIN_FRAG_SIZE 1024 +#define EXT4_MAX_FRAG_SIZE 4096 +#define EXT4_MIN_FRAG_LOG_SIZE 10 #ifdef __KERNEL__ -# define EXT3_FRAG_SIZE(s) (EXT3_SB(s)->s_frag_size) -# define EXT3_FRAGS_PER_BLOCK(s) (EXT3_SB(s)->s_frags_per_block) +# define EXT4_FRAG_SIZE(s) (EXT4_SB(s)->s_frag_size) +# define EXT4_FRAGS_PER_BLOCK(s) (EXT4_SB(s)->s_frags_per_block) #else -# define EXT3_FRAG_SIZE(s) (EXT3_MIN_FRAG_SIZE << (s)->s_log_frag_size) -# define EXT3_FRAGS_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / EXT3_FRAG_SIZE(s)) +# define EXT4_FRAG_SIZE(s) (EXT4_MIN_FRAG_SIZE << (s)->s_log_frag_size) +# define EXT4_FRAGS_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_FRAG_SIZE(s)) #endif /* * Structure of a blocks group descriptor */ -struct ext3_group_desc +struct ext4_group_desc { __le32 bg_block_bitmap; /* Blocks bitmap block */ __le32 bg_inode_bitmap; /* Inodes bitmap block */ @@ -135,62 +135,62 @@ struct ext3_group_desc * Macro-instructions used to manage group descriptors */ #ifdef __KERNEL__ -# define EXT3_BLOCKS_PER_GROUP(s) (EXT3_SB(s)->s_blocks_per_group) -# define EXT3_DESC_PER_BLOCK(s) (EXT3_SB(s)->s_desc_per_block) -# define EXT3_INODES_PER_GROUP(s) (EXT3_SB(s)->s_inodes_per_group) -# define EXT3_DESC_PER_BLOCK_BITS(s) (EXT3_SB(s)->s_desc_per_block_bits) +# define EXT4_BLOCKS_PER_GROUP(s) (EXT4_SB(s)->s_blocks_per_group) +# define EXT4_DESC_PER_BLOCK(s) (EXT4_SB(s)->s_desc_per_block) +# define EXT4_INODES_PER_GROUP(s) (EXT4_SB(s)->s_inodes_per_group) +# define EXT4_DESC_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_desc_per_block_bits) #else -# define EXT3_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) -# define EXT3_DESC_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_group_desc)) -# define EXT3_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) +# define EXT4_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +# define EXT4_DESC_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof (struct ext4_group_desc)) +# define EXT4_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) #endif /* * Constants relative to the data blocks */ -#define EXT3_NDIR_BLOCKS 12 -#define EXT3_IND_BLOCK EXT3_NDIR_BLOCKS -#define EXT3_DIND_BLOCK (EXT3_IND_BLOCK + 1) -#define EXT3_TIND_BLOCK (EXT3_DIND_BLOCK + 1) -#define EXT3_N_BLOCKS (EXT3_TIND_BLOCK + 1) +#define EXT4_NDIR_BLOCKS 12 +#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS +#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1) +#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1) +#define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1) /* * Inode flags */ -#define EXT3_SECRM_FL 0x00000001 /* Secure deletion */ -#define EXT3_UNRM_FL 0x00000002 /* Undelete */ -#define EXT3_COMPR_FL 0x00000004 /* Compress file */ -#define EXT3_SYNC_FL 0x00000008 /* Synchronous updates */ -#define EXT3_IMMUTABLE_FL 0x00000010 /* Immutable file */ -#define EXT3_APPEND_FL 0x00000020 /* writes to file may only append */ -#define EXT3_NODUMP_FL 0x00000040 /* do not dump file */ -#define EXT3_NOATIME_FL 0x00000080 /* do not update atime */ +#define EXT4_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT4_UNRM_FL 0x00000002 /* Undelete */ +#define EXT4_COMPR_FL 0x00000004 /* Compress file */ +#define EXT4_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT4_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT4_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT4_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT4_NOATIME_FL 0x00000080 /* do not update atime */ /* Reserved for compression usage... */ -#define EXT3_DIRTY_FL 0x00000100 -#define EXT3_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ -#define EXT3_NOCOMPR_FL 0x00000400 /* Don't compress */ -#define EXT3_ECOMPR_FL 0x00000800 /* Compression error */ +#define EXT4_DIRTY_FL 0x00000100 +#define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define EXT4_NOCOMPR_FL 0x00000400 /* Don't compress */ +#define EXT4_ECOMPR_FL 0x00000800 /* Compression error */ /* End compression flags --- maybe not all used */ -#define EXT3_INDEX_FL 0x00001000 /* hash-indexed directory */ -#define EXT3_IMAGIC_FL 0x00002000 /* AFS directory */ -#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */ -#define EXT3_NOTAIL_FL 0x00008000 /* file tail should not be merged */ -#define EXT3_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ -#define EXT3_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ -#define EXT3_RESERVED_FL 0x80000000 /* reserved for ext3 lib */ +#define EXT4_INDEX_FL 0x00001000 /* hash-indexed directory */ +#define EXT4_IMAGIC_FL 0x00002000 /* AFS directory */ +#define EXT4_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */ +#define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */ +#define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ +#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ -#define EXT3_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ -#define EXT3_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ +#define EXT4_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ +#define EXT4_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ /* * Inode dynamic state flags */ -#define EXT3_STATE_JDATA 0x00000001 /* journaled data exists */ -#define EXT3_STATE_NEW 0x00000002 /* inode is newly created */ -#define EXT3_STATE_XATTR 0x00000004 /* has in-inode xattrs */ +#define EXT4_STATE_JDATA 0x00000001 /* journaled data exists */ +#define EXT4_STATE_NEW 0x00000002 /* inode is newly created */ +#define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */ /* Used to pass group descriptor data when online resize is done */ -struct ext3_new_group_input { +struct ext4_new_group_input { __u32 group; /* Group number for this data */ __u32 block_bitmap; /* Absolute block number of block bitmap */ __u32 inode_bitmap; /* Absolute block number of inode bitmap */ @@ -200,8 +200,8 @@ struct ext3_new_group_input { __u16 unused; }; -/* The struct ext3_new_group_input in kernel space, with free_blocks_count */ -struct ext3_new_group_data { +/* The struct ext4_new_group_input in kernel space, with free_blocks_count */ +struct ext4_new_group_data { __u32 group; __u32 block_bitmap; __u32 inode_bitmap; @@ -216,41 +216,41 @@ struct ext3_new_group_data { /* * ioctl commands */ -#define EXT3_IOC_GETFLAGS FS_IOC_GETFLAGS -#define EXT3_IOC_SETFLAGS FS_IOC_SETFLAGS -#define EXT3_IOC_GETVERSION _IOR('f', 3, long) -#define EXT3_IOC_SETVERSION _IOW('f', 4, long) -#define EXT3_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) -#define EXT3_IOC_GROUP_ADD _IOW('f', 8,struct ext3_new_group_input) -#define EXT3_IOC_GETVERSION_OLD FS_IOC_GETVERSION -#define EXT3_IOC_SETVERSION_OLD FS_IOC_SETVERSION +#define EXT4_IOC_GETFLAGS FS_IOC_GETFLAGS +#define EXT4_IOC_SETFLAGS FS_IOC_SETFLAGS +#define EXT4_IOC_GETVERSION _IOR('f', 3, long) +#define EXT4_IOC_SETVERSION _IOW('f', 4, long) +#define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) +#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input) +#define EXT4_IOC_GETVERSION_OLD FS_IOC_GETVERSION +#define EXT4_IOC_SETVERSION_OLD FS_IOC_SETVERSION #ifdef CONFIG_JBD_DEBUG -#define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long) +#define EXT4_IOC_WAIT_FOR_READONLY _IOR('f', 99, long) #endif -#define EXT3_IOC_GETRSVSZ _IOR('f', 5, long) -#define EXT3_IOC_SETRSVSZ _IOW('f', 6, long) +#define EXT4_IOC_GETRSVSZ _IOR('f', 5, long) +#define EXT4_IOC_SETRSVSZ _IOW('f', 6, long) /* * ioctl commands in 32 bit emulation */ -#define EXT3_IOC32_GETFLAGS FS_IOC32_GETFLAGS -#define EXT3_IOC32_SETFLAGS FS_IOC32_SETFLAGS -#define EXT3_IOC32_GETVERSION _IOR('f', 3, int) -#define EXT3_IOC32_SETVERSION _IOW('f', 4, int) -#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int) -#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int) -#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int) +#define EXT4_IOC32_GETFLAGS FS_IOC32_GETFLAGS +#define EXT4_IOC32_SETFLAGS FS_IOC32_SETFLAGS +#define EXT4_IOC32_GETVERSION _IOR('f', 3, int) +#define EXT4_IOC32_SETVERSION _IOW('f', 4, int) +#define EXT4_IOC32_GETRSVSZ _IOR('f', 5, int) +#define EXT4_IOC32_SETRSVSZ _IOW('f', 6, int) +#define EXT4_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int) #ifdef CONFIG_JBD_DEBUG -#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int) +#define EXT4_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int) #endif -#define EXT3_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION -#define EXT3_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION +#define EXT4_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION +#define EXT4_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION /* * Mount options */ -struct ext3_mount_options { +struct ext4_mount_options { unsigned long s_mount_opt; uid_t s_resuid; gid_t s_resgid; @@ -264,7 +264,7 @@ struct ext3_mount_options { /* * Structure of an inode on the disk */ -struct ext3_inode { +struct ext4_inode { __le16 i_mode; /* File mode */ __le16 i_uid; /* Low 16 bits of Owner Uid */ __le32 i_size; /* Size in bytes */ @@ -287,7 +287,7 @@ struct ext3_inode { __u32 m_i_reserved1; } masix1; } osd1; /* OS dependent 1 */ - __le32 i_block[EXT3_N_BLOCKS];/* Pointers to blocks */ + __le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */ __le32 i_generation; /* File version (for NFS) */ __le32 i_file_acl; /* File ACL */ __le32 i_dir_acl; /* Directory ACL */ @@ -353,76 +353,76 @@ struct ext3_inode { /* * File system states */ -#define EXT3_VALID_FS 0x0001 /* Unmounted cleanly */ -#define EXT3_ERROR_FS 0x0002 /* Errors detected */ -#define EXT3_ORPHAN_FS 0x0004 /* Orphans being recovered */ +#define EXT4_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT4_ERROR_FS 0x0002 /* Errors detected */ +#define EXT4_ORPHAN_FS 0x0004 /* Orphans being recovered */ /* * Mount flags */ -#define EXT3_MOUNT_CHECK 0x00001 /* Do mount-time checks */ -#define EXT3_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */ -#define EXT3_MOUNT_GRPID 0x00004 /* Create files with directory's group */ -#define EXT3_MOUNT_DEBUG 0x00008 /* Some debugging messages */ -#define EXT3_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ -#define EXT3_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */ -#define EXT3_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ -#define EXT3_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ -#define EXT3_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ -#define EXT3_MOUNT_ABORT 0x00200 /* Fatal error detected */ -#define EXT3_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ -#define EXT3_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ -#define EXT3_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ -#define EXT3_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */ -#define EXT3_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */ -#define EXT3_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */ -#define EXT3_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */ -#define EXT3_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */ -#define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */ -#define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */ -#define EXT3_MOUNT_NOBH 0x40000 /* No bufferheads */ -#define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */ -#define EXT3_MOUNT_USRQUOTA 0x100000 /* "old" user quota */ -#define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ - -/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ +#define EXT4_MOUNT_CHECK 0x00001 /* Do mount-time checks */ +#define EXT4_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */ +#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */ +#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */ +#define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ +#define EXT4_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */ +#define EXT4_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ +#define EXT4_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ +#define EXT4_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ +#define EXT4_MOUNT_ABORT 0x00200 /* Fatal error detected */ +#define EXT4_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ +#define EXT4_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ +#define EXT4_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ +#define EXT4_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */ +#define EXT4_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */ +#define EXT4_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */ +#define EXT4_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */ +#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */ +#define EXT4_MOUNT_RESERVATION 0x10000 /* Preallocation */ +#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */ +#define EXT4_MOUNT_NOBH 0x40000 /* No bufferheads */ +#define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */ +#define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */ +#define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ + +/* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H -#define clear_opt(o, opt) o &= ~EXT3_MOUNT_##opt -#define set_opt(o, opt) o |= EXT3_MOUNT_##opt -#define test_opt(sb, opt) (EXT3_SB(sb)->s_mount_opt & \ - EXT3_MOUNT_##opt) +#define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt +#define set_opt(o, opt) o |= EXT4_MOUNT_##opt +#define test_opt(sb, opt) (EXT4_SB(sb)->s_mount_opt & \ + EXT4_MOUNT_##opt) #else -#define EXT2_MOUNT_NOLOAD EXT3_MOUNT_NOLOAD -#define EXT2_MOUNT_ABORT EXT3_MOUNT_ABORT -#define EXT2_MOUNT_DATA_FLAGS EXT3_MOUNT_DATA_FLAGS +#define EXT2_MOUNT_NOLOAD EXT4_MOUNT_NOLOAD +#define EXT2_MOUNT_ABORT EXT4_MOUNT_ABORT +#define EXT2_MOUNT_DATA_FLAGS EXT4_MOUNT_DATA_FLAGS #endif -#define ext3_set_bit ext2_set_bit -#define ext3_set_bit_atomic ext2_set_bit_atomic -#define ext3_clear_bit ext2_clear_bit -#define ext3_clear_bit_atomic ext2_clear_bit_atomic -#define ext3_test_bit ext2_test_bit -#define ext3_find_first_zero_bit ext2_find_first_zero_bit -#define ext3_find_next_zero_bit ext2_find_next_zero_bit +#define ext4_set_bit ext2_set_bit +#define ext4_set_bit_atomic ext2_set_bit_atomic +#define ext4_clear_bit ext2_clear_bit +#define ext4_clear_bit_atomic ext2_clear_bit_atomic +#define ext4_test_bit ext2_test_bit +#define ext4_find_first_zero_bit ext2_find_first_zero_bit +#define ext4_find_next_zero_bit ext2_find_next_zero_bit /* * Maximal mount counts between two filesystem checks */ -#define EXT3_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ -#define EXT3_DFL_CHECKINTERVAL 0 /* Don't use interval check */ +#define EXT4_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ +#define EXT4_DFL_CHECKINTERVAL 0 /* Don't use interval check */ /* * Behaviour when detecting errors */ -#define EXT3_ERRORS_CONTINUE 1 /* Continue execution */ -#define EXT3_ERRORS_RO 2 /* Remount fs read-only */ -#define EXT3_ERRORS_PANIC 3 /* Panic */ -#define EXT3_ERRORS_DEFAULT EXT3_ERRORS_CONTINUE +#define EXT4_ERRORS_CONTINUE 1 /* Continue execution */ +#define EXT4_ERRORS_RO 2 /* Remount fs read-only */ +#define EXT4_ERRORS_PANIC 3 /* Panic */ +#define EXT4_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE /* * Structure of the super block */ -struct ext3_super_block { +struct ext4_super_block { /*00*/ __le32 s_inodes_count; /* Inodes count */ __le32 s_blocks_count; /* Blocks count */ __le32 s_r_blocks_count; /* Reserved blocks count */ @@ -449,7 +449,7 @@ struct ext3_super_block { /*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */ __le16 s_def_resgid; /* Default gid for reserved blocks */ /* - * These fields are for EXT3_DYNAMIC_REV superblocks only. + * These fields are for EXT4_DYNAMIC_REV superblocks only. * * Note: the difference between the compatible feature set and * the incompatible feature set is that if there is a bit set @@ -473,13 +473,13 @@ struct ext3_super_block { /*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */ /* * Performance hints. Directory preallocation should only - * happen if the EXT3_FEATURE_COMPAT_DIR_PREALLOC flag is on. + * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on. */ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */ /* - * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. + * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set. */ /*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ /*E0*/ __le32 s_journal_inum; /* inode number of journal file */ @@ -495,186 +495,186 @@ struct ext3_super_block { }; #ifdef __KERNEL__ -#include -#include -static inline struct ext3_sb_info * EXT3_SB(struct super_block *sb) +#include +#include +static inline struct ext4_sb_info * EXT4_SB(struct super_block *sb) { return sb->s_fs_info; } -static inline struct ext3_inode_info *EXT3_I(struct inode *inode) +static inline struct ext4_inode_info *EXT4_I(struct inode *inode) { - return container_of(inode, struct ext3_inode_info, vfs_inode); + return container_of(inode, struct ext4_inode_info, vfs_inode); } -static inline int ext3_valid_inum(struct super_block *sb, unsigned long ino) +static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) { - return ino == EXT3_ROOT_INO || - ino == EXT3_JOURNAL_INO || - ino == EXT3_RESIZE_INO || - (ino >= EXT3_FIRST_INO(sb) && - ino <= le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)); + return ino == EXT4_ROOT_INO || + ino == EXT4_JOURNAL_INO || + ino == EXT4_RESIZE_INO || + (ino >= EXT4_FIRST_INO(sb) && + ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)); } #else -/* Assume that user mode programs are passing in an ext3fs superblock, not +/* Assume that user mode programs are passing in an ext4fs superblock, not * a kernel struct super_block. This will allow us to call the feature-test * macros from user land. */ -#define EXT3_SB(sb) (sb) +#define EXT4_SB(sb) (sb) #endif -#define NEXT_ORPHAN(inode) EXT3_I(inode)->i_dtime +#define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime /* * Codes for operating systems */ -#define EXT3_OS_LINUX 0 -#define EXT3_OS_HURD 1 -#define EXT3_OS_MASIX 2 -#define EXT3_OS_FREEBSD 3 -#define EXT3_OS_LITES 4 +#define EXT4_OS_LINUX 0 +#define EXT4_OS_HURD 1 +#define EXT4_OS_MASIX 2 +#define EXT4_OS_FREEBSD 3 +#define EXT4_OS_LITES 4 /* * Revision levels */ -#define EXT3_GOOD_OLD_REV 0 /* The good old (original) format */ -#define EXT3_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ +#define EXT4_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT4_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ -#define EXT3_CURRENT_REV EXT3_GOOD_OLD_REV -#define EXT3_MAX_SUPP_REV EXT3_DYNAMIC_REV +#define EXT4_CURRENT_REV EXT4_GOOD_OLD_REV +#define EXT4_MAX_SUPP_REV EXT4_DYNAMIC_REV -#define EXT3_GOOD_OLD_INODE_SIZE 128 +#define EXT4_GOOD_OLD_INODE_SIZE 128 /* * Feature set definitions */ -#define EXT3_HAS_COMPAT_FEATURE(sb,mask) \ - ( EXT3_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) -#define EXT3_HAS_RO_COMPAT_FEATURE(sb,mask) \ - ( EXT3_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) -#define EXT3_HAS_INCOMPAT_FEATURE(sb,mask) \ - ( EXT3_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) -#define EXT3_SET_COMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) -#define EXT3_SET_RO_COMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) -#define EXT3_SET_INCOMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) -#define EXT3_CLEAR_COMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) -#define EXT3_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) -#define EXT3_CLEAR_INCOMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) - -#define EXT3_FEATURE_COMPAT_DIR_PREALLOC 0x0001 -#define EXT3_FEATURE_COMPAT_IMAGIC_INODES 0x0002 -#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 -#define EXT3_FEATURE_COMPAT_EXT_ATTR 0x0008 -#define EXT3_FEATURE_COMPAT_RESIZE_INODE 0x0010 -#define EXT3_FEATURE_COMPAT_DIR_INDEX 0x0020 - -#define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 -#define EXT3_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 -#define EXT3_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 - -#define EXT3_FEATURE_INCOMPAT_COMPRESSION 0x0001 -#define EXT3_FEATURE_INCOMPAT_FILETYPE 0x0002 -#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ -#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ -#define EXT3_FEATURE_INCOMPAT_META_BG 0x0010 - -#define EXT3_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR -#define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \ - EXT3_FEATURE_INCOMPAT_RECOVER| \ - EXT3_FEATURE_INCOMPAT_META_BG) -#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \ - EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \ - EXT3_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT4_HAS_COMPAT_FEATURE(sb,mask) \ + ( EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) +#define EXT4_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) +#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) +#define EXT4_SET_COMPAT_FEATURE(sb,mask) \ + EXT4_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) +#define EXT4_SET_RO_COMPAT_FEATURE(sb,mask) \ + EXT4_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) +#define EXT4_SET_INCOMPAT_FEATURE(sb,mask) \ + EXT4_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) +#define EXT4_CLEAR_COMPAT_FEATURE(sb,mask) \ + EXT4_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) +#define EXT4_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ + EXT4_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) +#define EXT4_CLEAR_INCOMPAT_FEATURE(sb,mask) \ + EXT4_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) + +#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010 +#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020 + +#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 + +#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ +#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ +#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 + +#define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR +#define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ + EXT4_FEATURE_INCOMPAT_RECOVER| \ + EXT4_FEATURE_INCOMPAT_META_BG) +#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT4_FEATURE_RO_COMPAT_BTREE_DIR) /* * Default values for user and/or group using reserved blocks */ -#define EXT3_DEF_RESUID 0 -#define EXT3_DEF_RESGID 0 +#define EXT4_DEF_RESUID 0 +#define EXT4_DEF_RESGID 0 /* * Default mount options */ -#define EXT3_DEFM_DEBUG 0x0001 -#define EXT3_DEFM_BSDGROUPS 0x0002 -#define EXT3_DEFM_XATTR_USER 0x0004 -#define EXT3_DEFM_ACL 0x0008 -#define EXT3_DEFM_UID16 0x0010 -#define EXT3_DEFM_JMODE 0x0060 -#define EXT3_DEFM_JMODE_DATA 0x0020 -#define EXT3_DEFM_JMODE_ORDERED 0x0040 -#define EXT3_DEFM_JMODE_WBACK 0x0060 +#define EXT4_DEFM_DEBUG 0x0001 +#define EXT4_DEFM_BSDGROUPS 0x0002 +#define EXT4_DEFM_XATTR_USER 0x0004 +#define EXT4_DEFM_ACL 0x0008 +#define EXT4_DEFM_UID16 0x0010 +#define EXT4_DEFM_JMODE 0x0060 +#define EXT4_DEFM_JMODE_DATA 0x0020 +#define EXT4_DEFM_JMODE_ORDERED 0x0040 +#define EXT4_DEFM_JMODE_WBACK 0x0060 /* * Structure of a directory entry */ -#define EXT3_NAME_LEN 255 +#define EXT4_NAME_LEN 255 -struct ext3_dir_entry { +struct ext4_dir_entry { __le32 inode; /* Inode number */ __le16 rec_len; /* Directory entry length */ __le16 name_len; /* Name length */ - char name[EXT3_NAME_LEN]; /* File name */ + char name[EXT4_NAME_LEN]; /* File name */ }; /* - * The new version of the directory entry. Since EXT3 structures are + * The new version of the directory entry. Since EXT4 structures are * stored in intel byte order, and the name_len field could never be * bigger than 255 chars, it's safe to reclaim the extra byte for the * file_type field. */ -struct ext3_dir_entry_2 { +struct ext4_dir_entry_2 { __le32 inode; /* Inode number */ __le16 rec_len; /* Directory entry length */ __u8 name_len; /* Name length */ __u8 file_type; - char name[EXT3_NAME_LEN]; /* File name */ + char name[EXT4_NAME_LEN]; /* File name */ }; /* - * Ext3 directory file types. Only the low 3 bits are used. The + * Ext4 directory file types. Only the low 3 bits are used. The * other bits are reserved for now. */ -#define EXT3_FT_UNKNOWN 0 -#define EXT3_FT_REG_FILE 1 -#define EXT3_FT_DIR 2 -#define EXT3_FT_CHRDEV 3 -#define EXT3_FT_BLKDEV 4 -#define EXT3_FT_FIFO 5 -#define EXT3_FT_SOCK 6 -#define EXT3_FT_SYMLINK 7 +#define EXT4_FT_UNKNOWN 0 +#define EXT4_FT_REG_FILE 1 +#define EXT4_FT_DIR 2 +#define EXT4_FT_CHRDEV 3 +#define EXT4_FT_BLKDEV 4 +#define EXT4_FT_FIFO 5 +#define EXT4_FT_SOCK 6 +#define EXT4_FT_SYMLINK 7 -#define EXT3_FT_MAX 8 +#define EXT4_FT_MAX 8 /* - * EXT3_DIR_PAD defines the directory entries boundaries + * EXT4_DIR_PAD defines the directory entries boundaries * * NOTE: It must be a multiple of 4 */ -#define EXT3_DIR_PAD 4 -#define EXT3_DIR_ROUND (EXT3_DIR_PAD - 1) -#define EXT3_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT3_DIR_ROUND) & \ - ~EXT3_DIR_ROUND) +#define EXT4_DIR_PAD 4 +#define EXT4_DIR_ROUND (EXT4_DIR_PAD - 1) +#define EXT4_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT4_DIR_ROUND) & \ + ~EXT4_DIR_ROUND) /* * Hash Tree Directory indexing * (c) Daniel Phillips, 2001 */ -#ifdef CONFIG_EXT3_INDEX - #define is_dx(dir) (EXT3_HAS_COMPAT_FEATURE(dir->i_sb, \ - EXT3_FEATURE_COMPAT_DIR_INDEX) && \ - (EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) -#define EXT3_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT3_LINK_MAX) -#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1) +#ifdef CONFIG_EXT4_INDEX + #define is_dx(dir) (EXT4_HAS_COMPAT_FEATURE(dir->i_sb, \ + EXT4_FEATURE_COMPAT_DIR_INDEX) && \ + (EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) +#define EXT4_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT4_LINK_MAX) +#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1) #else #define is_dx(dir) 0 -#define EXT3_DIR_LINK_MAX(dir) ((dir)->i_nlink >= EXT3_LINK_MAX) -#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2) +#define EXT4_DIR_LINK_MAX(dir) ((dir)->i_nlink >= EXT4_LINK_MAX) +#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2) #endif /* Legal values for the dx_root hash_version field: */ @@ -694,10 +694,10 @@ struct dx_hash_info u32 *seed; }; -#define EXT3_HTREE_EOF 0x7fffffff +#define EXT4_HTREE_EOF 0x7fffffff /* - * Control parameters used by ext3_htree_next_block + * Control parameters used by ext4_htree_next_block */ #define HASH_NB_ALWAYS 1 @@ -705,16 +705,16 @@ struct dx_hash_info /* * Describe an inode's exact location on disk and in memory */ -struct ext3_iloc +struct ext4_iloc { struct buffer_head *bh; unsigned long offset; unsigned long block_group; }; -static inline struct ext3_inode *ext3_raw_inode(struct ext3_iloc *iloc) +static inline struct ext4_inode *ext4_raw_inode(struct ext4_iloc *iloc) { - return (struct ext3_inode *) (iloc->bh->b_data + iloc->offset); + return (struct ext4_inode *) (iloc->bh->b_data + iloc->offset); } /* @@ -733,11 +733,11 @@ struct dir_private_info { }; /* calculate the first block number of the group */ -static inline ext3_fsblk_t -ext3_group_first_block_no(struct super_block *sb, unsigned long group_no) +static inline ext4_fsblk_t +ext4_group_first_block_no(struct super_block *sb, unsigned long group_no) { - return group_no * (ext3_fsblk_t)EXT3_BLOCKS_PER_GROUP(sb) + - le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block); + return group_no * (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) + + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); } /* @@ -751,113 +751,113 @@ ext3_group_first_block_no(struct super_block *sb, unsigned long group_no) /* * Ok, these declarations are also in but none of the - * ext3 source programs needs to include it so they are duplicated here. + * ext4 source programs needs to include it so they are duplicated here. */ # define NORET_TYPE /**/ # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, /* balloc.c */ -extern int ext3_bg_has_super(struct super_block *sb, int group); -extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group); -extern ext3_fsblk_t ext3_new_block (handle_t *handle, struct inode *inode, - ext3_fsblk_t goal, int *errp); -extern ext3_fsblk_t ext3_new_blocks (handle_t *handle, struct inode *inode, - ext3_fsblk_t goal, unsigned long *count, int *errp); -extern void ext3_free_blocks (handle_t *handle, struct inode *inode, - ext3_fsblk_t block, unsigned long count); -extern void ext3_free_blocks_sb (handle_t *handle, struct super_block *sb, - ext3_fsblk_t block, unsigned long count, +extern int ext4_bg_has_super(struct super_block *sb, int group); +extern unsigned long ext4_bg_num_gdb(struct super_block *sb, int group); +extern ext4_fsblk_t ext4_new_block (handle_t *handle, struct inode *inode, + ext4_fsblk_t goal, int *errp); +extern ext4_fsblk_t ext4_new_blocks (handle_t *handle, struct inode *inode, + ext4_fsblk_t goal, unsigned long *count, int *errp); +extern void ext4_free_blocks (handle_t *handle, struct inode *inode, + ext4_fsblk_t block, unsigned long count); +extern void ext4_free_blocks_sb (handle_t *handle, struct super_block *sb, + ext4_fsblk_t block, unsigned long count, unsigned long *pdquot_freed_blocks); -extern ext3_fsblk_t ext3_count_free_blocks (struct super_block *); -extern void ext3_check_blocks_bitmap (struct super_block *); -extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, +extern ext4_fsblk_t ext4_count_free_blocks (struct super_block *); +extern void ext4_check_blocks_bitmap (struct super_block *); +extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, unsigned int block_group, struct buffer_head ** bh); -extern int ext3_should_retry_alloc(struct super_block *sb, int *retries); -extern void ext3_init_block_alloc_info(struct inode *); -extern void ext3_rsv_window_add(struct super_block *sb, struct ext3_reserve_window_node *rsv); +extern int ext4_should_retry_alloc(struct super_block *sb, int *retries); +extern void ext4_init_block_alloc_info(struct inode *); +extern void ext4_rsv_window_add(struct super_block *sb, struct ext4_reserve_window_node *rsv); /* dir.c */ -extern int ext3_check_dir_entry(const char *, struct inode *, - struct ext3_dir_entry_2 *, +extern int ext4_check_dir_entry(const char *, struct inode *, + struct ext4_dir_entry_2 *, struct buffer_head *, unsigned long); -extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, +extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, __u32 minor_hash, - struct ext3_dir_entry_2 *dirent); -extern void ext3_htree_free_dir_info(struct dir_private_info *p); + struct ext4_dir_entry_2 *dirent); +extern void ext4_htree_free_dir_info(struct dir_private_info *p); /* fsync.c */ -extern int ext3_sync_file (struct file *, struct dentry *, int); +extern int ext4_sync_file (struct file *, struct dentry *, int); /* hash.c */ -extern int ext3fs_dirhash(const char *name, int len, struct +extern int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo); /* ialloc.c */ -extern struct inode * ext3_new_inode (handle_t *, struct inode *, int); -extern void ext3_free_inode (handle_t *, struct inode *); -extern struct inode * ext3_orphan_get (struct super_block *, unsigned long); -extern unsigned long ext3_count_free_inodes (struct super_block *); -extern unsigned long ext3_count_dirs (struct super_block *); -extern void ext3_check_inodes_bitmap (struct super_block *); -extern unsigned long ext3_count_free (struct buffer_head *, unsigned); +extern struct inode * ext4_new_inode (handle_t *, struct inode *, int); +extern void ext4_free_inode (handle_t *, struct inode *); +extern struct inode * ext4_orphan_get (struct super_block *, unsigned long); +extern unsigned long ext4_count_free_inodes (struct super_block *); +extern unsigned long ext4_count_dirs (struct super_block *); +extern void ext4_check_inodes_bitmap (struct super_block *); +extern unsigned long ext4_count_free (struct buffer_head *, unsigned); /* inode.c */ -int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode, - struct buffer_head *bh, ext3_fsblk_t blocknr); -struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *); -struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *); -int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, +int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, + struct buffer_head *bh, ext4_fsblk_t blocknr); +struct buffer_head * ext4_getblk (handle_t *, struct inode *, long, int, int *); +struct buffer_head * ext4_bread (handle_t *, struct inode *, int, int, int *); +int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result, int create, int extend_disksize); -extern void ext3_read_inode (struct inode *); -extern int ext3_write_inode (struct inode *, int); -extern int ext3_setattr (struct dentry *, struct iattr *); -extern void ext3_delete_inode (struct inode *); -extern int ext3_sync_inode (handle_t *, struct inode *); -extern void ext3_discard_reservation (struct inode *); -extern void ext3_dirty_inode(struct inode *); -extern int ext3_change_inode_journal_flag(struct inode *, int); -extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *); -extern void ext3_truncate (struct inode *); -extern void ext3_set_inode_flags(struct inode *); -extern void ext3_set_aops(struct inode *inode); +extern void ext4_read_inode (struct inode *); +extern int ext4_write_inode (struct inode *, int); +extern int ext4_setattr (struct dentry *, struct iattr *); +extern void ext4_delete_inode (struct inode *); +extern int ext4_sync_inode (handle_t *, struct inode *); +extern void ext4_discard_reservation (struct inode *); +extern void ext4_dirty_inode(struct inode *); +extern int ext4_change_inode_journal_flag(struct inode *, int); +extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *); +extern void ext4_truncate (struct inode *); +extern void ext4_set_inode_flags(struct inode *); +extern void ext4_set_aops(struct inode *inode); /* ioctl.c */ -extern int ext3_ioctl (struct inode *, struct file *, unsigned int, +extern int ext4_ioctl (struct inode *, struct file *, unsigned int, unsigned long); -extern long ext3_compat_ioctl (struct file *, unsigned int, unsigned long); +extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long); /* namei.c */ -extern int ext3_orphan_add(handle_t *, struct inode *); -extern int ext3_orphan_del(handle_t *, struct inode *); -extern int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, +extern int ext4_orphan_add(handle_t *, struct inode *); +extern int ext4_orphan_del(handle_t *, struct inode *); +extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, __u32 start_minor_hash, __u32 *next_hash); /* resize.c */ -extern int ext3_group_add(struct super_block *sb, - struct ext3_new_group_data *input); -extern int ext3_group_extend(struct super_block *sb, - struct ext3_super_block *es, - ext3_fsblk_t n_blocks_count); +extern int ext4_group_add(struct super_block *sb, + struct ext4_new_group_data *input); +extern int ext4_group_extend(struct super_block *sb, + struct ext4_super_block *es, + ext4_fsblk_t n_blocks_count); /* super.c */ -extern void ext3_error (struct super_block *, const char *, const char *, ...) +extern void ext4_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); -extern void __ext3_std_error (struct super_block *, const char *, int); -extern void ext3_abort (struct super_block *, const char *, const char *, ...) +extern void __ext4_std_error (struct super_block *, const char *, int); +extern void ext4_abort (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); -extern void ext3_warning (struct super_block *, const char *, const char *, ...) +extern void ext4_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 ext4_update_dynamic_rev (struct super_block *sb); -#define ext3_std_error(sb, errno) \ +#define ext4_std_error(sb, errno) \ do { \ if ((errno)) \ - __ext3_std_error((sb), __FUNCTION__, (errno)); \ + __ext4_std_error((sb), __FUNCTION__, (errno)); \ } while (0) /* @@ -865,21 +865,21 @@ do { \ */ /* dir.c */ -extern const struct file_operations ext3_dir_operations; +extern const struct file_operations ext4_dir_operations; /* file.c */ -extern struct inode_operations ext3_file_inode_operations; -extern const struct file_operations ext3_file_operations; +extern struct inode_operations ext4_file_inode_operations; +extern const struct file_operations ext4_file_operations; /* namei.c */ -extern struct inode_operations ext3_dir_inode_operations; -extern struct inode_operations ext3_special_inode_operations; +extern struct inode_operations ext4_dir_inode_operations; +extern struct inode_operations ext4_special_inode_operations; /* symlink.c */ -extern struct inode_operations ext3_symlink_inode_operations; -extern struct inode_operations ext3_fast_symlink_inode_operations; +extern struct inode_operations ext4_symlink_inode_operations; +extern struct inode_operations ext4_fast_symlink_inode_operations; #endif /* __KERNEL__ */ -#endif /* _LINUX_EXT3_FS_H */ +#endif /* _LINUX_EXT4_FS_H */ diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h index 4395e5206746..18a6ce98537f 100644 --- a/include/linux/ext4_fs_i.h +++ b/include/linux/ext4_fs_i.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/ext3_fs_i.h + * linux/include/linux/ext4_fs_i.h * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -13,8 +13,8 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#ifndef _LINUX_EXT3_FS_I -#define _LINUX_EXT3_FS_I +#ifndef _LINUX_EXT4_FS_I +#define _LINUX_EXT4_FS_I #include #include @@ -22,43 +22,43 @@ #include /* data type for block offset of block group */ -typedef int ext3_grpblk_t; +typedef int ext4_grpblk_t; /* data type for filesystem-wide blocks number */ -typedef unsigned long ext3_fsblk_t; +typedef unsigned long ext4_fsblk_t; #define E3FSBLK "%lu" -struct ext3_reserve_window { - ext3_fsblk_t _rsv_start; /* First byte reserved */ - ext3_fsblk_t _rsv_end; /* Last byte reserved or 0 */ +struct ext4_reserve_window { + ext4_fsblk_t _rsv_start; /* First byte reserved */ + ext4_fsblk_t _rsv_end; /* Last byte reserved or 0 */ }; -struct ext3_reserve_window_node { +struct ext4_reserve_window_node { struct rb_node rsv_node; __u32 rsv_goal_size; __u32 rsv_alloc_hit; - struct ext3_reserve_window rsv_window; + struct ext4_reserve_window rsv_window; }; -struct ext3_block_alloc_info { +struct ext4_block_alloc_info { /* information about reservation window */ - struct ext3_reserve_window_node rsv_window_node; + struct ext4_reserve_window_node rsv_window_node; /* - * was i_next_alloc_block in ext3_inode_info + * was i_next_alloc_block in ext4_inode_info * is the logical (file-relative) number of the * most-recently-allocated block in this file. * We use this for detecting linearly ascending allocation requests. */ __u32 last_alloc_logical_block; /* - * Was i_next_alloc_goal in ext3_inode_info + * Was i_next_alloc_goal in ext4_inode_info * is the *physical* companion to i_next_alloc_block. * it the the physical block number of the block which was most-recentl * allocated to this file. This give us the goal (target) for the next * allocation when we detect linearly ascending requests. */ - ext3_fsblk_t last_alloc_physical_block; + ext4_fsblk_t last_alloc_physical_block; }; #define rsv_start rsv_window._rsv_start @@ -67,15 +67,15 @@ struct ext3_block_alloc_info { /* * third extended file system inode data in memory */ -struct ext3_inode_info { +struct ext4_inode_info { __le32 i_data[15]; /* unconverted */ __u32 i_flags; -#ifdef EXT3_FRAGMENTS +#ifdef EXT4_FRAGMENTS __u32 i_faddr; __u8 i_frag_no; __u8 i_frag_size; #endif - ext3_fsblk_t i_file_acl; + ext4_fsblk_t i_file_acl; __u32 i_dir_acl; __u32 i_dtime; @@ -87,13 +87,13 @@ struct ext3_inode_info { * near to their parent directory's inode. */ __u32 i_block_group; - __u32 i_state; /* Dynamic state flags for ext3 */ + __u32 i_state; /* Dynamic state flags for ext4 */ /* block reservation info */ - struct ext3_block_alloc_info *i_block_alloc_info; + struct ext4_block_alloc_info *i_block_alloc_info; __u32 i_dir_start_lookup; -#ifdef CONFIG_EXT3_FS_XATTR +#ifdef CONFIG_EXT4DEV_FS_XATTR /* * Extended attributes can be read independently of the main file * data. Taking i_mutex even when reading would cause contention @@ -103,7 +103,7 @@ struct ext3_inode_info { */ struct rw_semaphore xattr_sem; #endif -#ifdef CONFIG_EXT3_FS_POSIX_ACL +#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl; #endif @@ -113,7 +113,7 @@ struct ext3_inode_info { /* * i_disksize keeps track of what the inode size is ON DISK, not * in memory. During truncate, i_size is set to the new size by - * the VFS prior to calling ext3_truncate(), but the filesystem won't + * the VFS prior to calling ext4_truncate(), but the filesystem won't * set i_disksize to 0 until the truncate is actually under way. * * The intent is that i_disksize always represents the blocks which @@ -123,7 +123,7 @@ struct ext3_inode_info { * * The only time when i_disksize and i_size may be different is when * a truncate is in progress. The only things which change i_disksize - * are ext3_get_block (growth) and ext3_truncate (shrinkth). + * are ext4_get_block (growth) and ext4_truncate (shrinkth). */ loff_t i_disksize; @@ -131,10 +131,10 @@ struct ext3_inode_info { __u16 i_extra_isize; /* - * truncate_mutex is for serialising ext3_truncate() against - * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's + * truncate_mutex is for serialising ext4_truncate() against + * ext4_getblock(). In the 2.4 ext2 design, great chunks of inode's * data tree are chopped off during truncate. We can't do that in - * ext3 because whenever we perform intermediate commits during + * ext4 because whenever we perform intermediate commits during * truncate, the inode and all the metadata blocks *must* be in a * consistent state which allows truncation of the orphans to restart * during recovery. Hence we must fix the get_block-vs-truncate race @@ -144,4 +144,4 @@ struct ext3_inode_info { struct inode vfs_inode; }; -#endif /* _LINUX_EXT3_FS_I */ +#endif /* _LINUX_EXT4_FS_I */ diff --git a/include/linux/ext4_fs_sb.h b/include/linux/ext4_fs_sb.h index f61309c81cc4..ce4856d70100 100644 --- a/include/linux/ext4_fs_sb.h +++ b/include/linux/ext4_fs_sb.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/ext3_fs_sb.h + * linux/include/linux/ext4_fs_sb.h * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -13,8 +13,8 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#ifndef _LINUX_EXT3_FS_SB -#define _LINUX_EXT3_FS_SB +#ifndef _LINUX_EXT4_FS_SB +#define _LINUX_EXT4_FS_SB #ifdef __KERNEL__ #include @@ -27,7 +27,7 @@ /* * third extended-fs super-block data in memory */ -struct ext3_sb_info { +struct ext4_sb_info { unsigned long s_frag_size; /* Size of a fragment in bytes */ unsigned long s_frags_per_block;/* Number of fragments per block */ unsigned long s_inodes_per_block;/* Number of inodes per block */ @@ -39,7 +39,7 @@ struct ext3_sb_info { unsigned long s_desc_per_block; /* Number of group descriptors per block */ unsigned long s_groups_count; /* Number of groups in the fs */ struct buffer_head * s_sbh; /* Buffer containing the super block */ - struct ext3_super_block * s_es; /* Pointer to the super block in the buffer */ + struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */ struct buffer_head ** s_group_desc; unsigned long s_mount_opt; uid_t s_resuid; @@ -62,7 +62,7 @@ struct ext3_sb_info { /* root of the per fs reservation window tree */ spinlock_t s_rsv_window_lock; struct rb_root s_rsv_window_root; - struct ext3_reserve_window_node s_rsv_window_head; + struct ext4_reserve_window_node s_rsv_window_head; /* Journaling */ struct inode * s_journal_inode; @@ -80,4 +80,4 @@ struct ext3_sb_info { #endif }; -#endif /* _LINUX_EXT3_FS_SB */ +#endif /* _LINUX_EXT4_FS_SB */ diff --git a/include/linux/ext4_jbd.h b/include/linux/ext4_jbd.h index ce0e6109aff0..3dbf6c779037 100644 --- a/include/linux/ext4_jbd.h +++ b/include/linux/ext4_jbd.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/ext3_jbd.h + * linux/include/linux/ext4_jbd.h * * Written by Stephen C. Tweedie , 1999 * @@ -9,17 +9,17 @@ * the terms of the GNU General Public License, version 2, or at your * option, any later version, incorporated herein by reference. * - * Ext3-specific journaling extensions. + * Ext4-specific journaling extensions. */ -#ifndef _LINUX_EXT3_JBD_H -#define _LINUX_EXT3_JBD_H +#ifndef _LINUX_EXT4_JBD_H +#define _LINUX_EXT4_JBD_H #include #include -#include +#include -#define EXT3_JOURNAL(inode) (EXT3_SB((inode)->i_sb)->s_journal) +#define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal) /* Define the number of blocks we need to account to a transaction to * modify one block of data. @@ -28,13 +28,13 @@ * indirection blocks, the group and superblock summaries, and the data * block to complete the transaction. */ -#define EXT3_SINGLEDATA_TRANS_BLOCKS 8U +#define EXT4_SINGLEDATA_TRANS_BLOCKS 8U /* Extended attribute operations touch at most two data buffers, * two bitmap buffers, and two group summaries, in addition to the inode * and the superblock, which are already accounted for. */ -#define EXT3_XATTR_TRANS_BLOCKS 6U +#define EXT4_XATTR_TRANS_BLOCKS 6U /* Define the minimum size for a transaction which modifies data. This * needs to take into account the fact that we may end up modifying two @@ -42,15 +42,15 @@ * superblock only gets updated once, of course, so don't bother * counting that again for the quota updates. */ -#define EXT3_DATA_TRANS_BLOCKS(sb) (EXT3_SINGLEDATA_TRANS_BLOCKS + \ - EXT3_XATTR_TRANS_BLOCKS - 2 + \ - 2*EXT3_QUOTA_TRANS_BLOCKS(sb)) +#define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS + \ + EXT4_XATTR_TRANS_BLOCKS - 2 + \ + 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) /* 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. */ -#define EXT3_DELETE_TRANS_BLOCKS(sb) (2 * EXT3_DATA_TRANS_BLOCKS(sb) + 64) +#define EXT4_DELETE_TRANS_BLOCKS(sb) (2 * EXT4_DATA_TRANS_BLOCKS(sb) + 64) /* Define an arbitrary limit for the amount of data we will anticipate * writing to any given transaction. For unbounded transactions such as @@ -58,7 +58,7 @@ * start off at the maximum transaction size and grow the transaction * optimistically as we go. */ -#define EXT3_MAX_TRANS_DATA 64U +#define EXT4_MAX_TRANS_DATA 64U /* We break up a large truncate or write transaction once the handle's * buffer credits gets this low, we need either to extend the @@ -67,202 +67,202 @@ * one block, plus two quota updates. Quota allocations are not * needed. */ -#define EXT3_RESERVE_TRANS_BLOCKS 12U +#define EXT4_RESERVE_TRANS_BLOCKS 12U -#define EXT3_INDEX_EXTRA_TRANS_BLOCKS 8 +#define EXT4_INDEX_EXTRA_TRANS_BLOCKS 8 #ifdef CONFIG_QUOTA /* Amount of blocks needed for quota update - we know that the structure was * allocated so we need to update only inode+data */ -#define EXT3_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0) +#define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0) /* Amount of blocks needed for quota insert/delete - we do some block writes * but inode, sb and group updates are done only once */ -#define EXT3_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ - (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0) -#define EXT3_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ - (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0) +#define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ + (EXT4_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0) +#define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ + (EXT4_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0) #else -#define EXT3_QUOTA_TRANS_BLOCKS(sb) 0 -#define EXT3_QUOTA_INIT_BLOCKS(sb) 0 -#define EXT3_QUOTA_DEL_BLOCKS(sb) 0 +#define EXT4_QUOTA_TRANS_BLOCKS(sb) 0 +#define EXT4_QUOTA_INIT_BLOCKS(sb) 0 +#define EXT4_QUOTA_DEL_BLOCKS(sb) 0 #endif int -ext3_mark_iloc_dirty(handle_t *handle, +ext4_mark_iloc_dirty(handle_t *handle, struct inode *inode, - struct ext3_iloc *iloc); + struct ext4_iloc *iloc); /* * On success, We end up with an outstanding reference count against * iloc->bh. This _must_ be cleaned up later. */ -int ext3_reserve_inode_write(handle_t *handle, struct inode *inode, - struct ext3_iloc *iloc); +int ext4_reserve_inode_write(handle_t *handle, struct inode *inode, + struct ext4_iloc *iloc); -int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode); +int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode); /* - * Wrapper functions with which ext3 calls into JBD. The intent here is - * to allow these to be turned into appropriate stubs so ext3 can control - * ext2 filesystems, so ext2+ext3 systems only nee one fs. This work hasn't + * Wrapper functions with which ext4 calls into JBD. The intent here is + * to allow these to be turned into appropriate stubs so ext4 can control + * ext2 filesystems, so ext2+ext4 systems only nee one fs. This work hasn't * been done yet. */ -void ext3_journal_abort_handle(const char *caller, const char *err_fn, +void ext4_journal_abort_handle(const char *caller, const char *err_fn, struct buffer_head *bh, handle_t *handle, int err); static inline int -__ext3_journal_get_undo_access(const char *where, handle_t *handle, +__ext4_journal_get_undo_access(const char *where, handle_t *handle, struct buffer_head *bh) { int err = journal_get_undo_access(handle, bh); if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; } static inline int -__ext3_journal_get_write_access(const char *where, handle_t *handle, +__ext4_journal_get_write_access(const char *where, handle_t *handle, struct buffer_head *bh) { int err = journal_get_write_access(handle, bh); if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; } static inline void -ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh) +ext4_journal_release_buffer(handle_t *handle, struct buffer_head *bh) { journal_release_buffer(handle, bh); } static inline int -__ext3_journal_forget(const char *where, handle_t *handle, struct buffer_head *bh) +__ext4_journal_forget(const char *where, handle_t *handle, struct buffer_head *bh) { int err = journal_forget(handle, bh); if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; } static inline int -__ext3_journal_revoke(const char *where, handle_t *handle, +__ext4_journal_revoke(const char *where, handle_t *handle, unsigned long blocknr, struct buffer_head *bh) { int err = journal_revoke(handle, blocknr, bh); if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; } static inline int -__ext3_journal_get_create_access(const char *where, +__ext4_journal_get_create_access(const char *where, handle_t *handle, struct buffer_head *bh) { int err = journal_get_create_access(handle, bh); if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; } static inline int -__ext3_journal_dirty_metadata(const char *where, +__ext4_journal_dirty_metadata(const char *where, handle_t *handle, struct buffer_head *bh) { int err = journal_dirty_metadata(handle, bh); if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; } -#define ext3_journal_get_undo_access(handle, bh) \ - __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh)) -#define ext3_journal_get_write_access(handle, bh) \ - __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh)) -#define ext3_journal_revoke(handle, blocknr, bh) \ - __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh)) -#define ext3_journal_get_create_access(handle, bh) \ - __ext3_journal_get_create_access(__FUNCTION__, (handle), (bh)) -#define ext3_journal_dirty_metadata(handle, bh) \ - __ext3_journal_dirty_metadata(__FUNCTION__, (handle), (bh)) -#define ext3_journal_forget(handle, bh) \ - __ext3_journal_forget(__FUNCTION__, (handle), (bh)) +#define ext4_journal_get_undo_access(handle, bh) \ + __ext4_journal_get_undo_access(__FUNCTION__, (handle), (bh)) +#define ext4_journal_get_write_access(handle, bh) \ + __ext4_journal_get_write_access(__FUNCTION__, (handle), (bh)) +#define ext4_journal_revoke(handle, blocknr, bh) \ + __ext4_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh)) +#define ext4_journal_get_create_access(handle, bh) \ + __ext4_journal_get_create_access(__FUNCTION__, (handle), (bh)) +#define ext4_journal_dirty_metadata(handle, bh) \ + __ext4_journal_dirty_metadata(__FUNCTION__, (handle), (bh)) +#define ext4_journal_forget(handle, bh) \ + __ext4_journal_forget(__FUNCTION__, (handle), (bh)) -int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh); +int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh); -handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks); -int __ext3_journal_stop(const char *where, handle_t *handle); +handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); +int __ext4_journal_stop(const char *where, handle_t *handle); -static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks) +static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks) { - return ext3_journal_start_sb(inode->i_sb, nblocks); + return ext4_journal_start_sb(inode->i_sb, nblocks); } -#define ext3_journal_stop(handle) \ - __ext3_journal_stop(__FUNCTION__, (handle)) +#define ext4_journal_stop(handle) \ + __ext4_journal_stop(__FUNCTION__, (handle)) -static inline handle_t *ext3_journal_current_handle(void) +static inline handle_t *ext4_journal_current_handle(void) { return journal_current_handle(); } -static inline int ext3_journal_extend(handle_t *handle, int nblocks) +static inline int ext4_journal_extend(handle_t *handle, int nblocks) { return journal_extend(handle, nblocks); } -static inline int ext3_journal_restart(handle_t *handle, int nblocks) +static inline int ext4_journal_restart(handle_t *handle, int nblocks) { return journal_restart(handle, nblocks); } -static inline int ext3_journal_blocks_per_page(struct inode *inode) +static inline int ext4_journal_blocks_per_page(struct inode *inode) { return journal_blocks_per_page(inode); } -static inline int ext3_journal_force_commit(journal_t *journal) +static inline int ext4_journal_force_commit(journal_t *journal) { return journal_force_commit(journal); } /* super.c */ -int ext3_force_commit(struct super_block *sb); +int ext4_force_commit(struct super_block *sb); -static inline int ext3_should_journal_data(struct inode *inode) +static inline int ext4_should_journal_data(struct inode *inode) { if (!S_ISREG(inode->i_mode)) return 1; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) return 1; - if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL) + if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) return 1; return 0; } -static inline int ext3_should_order_data(struct inode *inode) +static inline int ext4_should_order_data(struct inode *inode) { if (!S_ISREG(inode->i_mode)) return 0; - if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL) + if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) return 0; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA) + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) return 1; return 0; } -static inline int ext3_should_writeback_data(struct inode *inode) +static inline int ext4_should_writeback_data(struct inode *inode) { if (!S_ISREG(inode->i_mode)) return 0; - if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL) + if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) return 0; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) return 1; return 0; } -#endif /* _LINUX_EXT3_JBD_H */ +#endif /* _LINUX_EXT4_JBD_H */ -- cgit v1.2.3 From 02ea2104c55b625cf5b5d9ba8586a4fc17920f5c Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:20:56 -0700 Subject: [PATCH] ext4: enable building of ext4 Originally part of a patch from Mingming Cao and Randy Dunlap. Reorganized by Shaggy. Signed-off-by: Randy Dunlap Signed-off-by: Mingming Cao Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/Kconfig | 75 ++++++++++++++++++++++++++++++++++++++++++++++++--- fs/Makefile | 1 + include/linux/magic.h | 1 + 3 files changed, 73 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/fs/Kconfig b/fs/Kconfig index 599de54451af..ac9ba1c30935 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -140,6 +140,73 @@ config EXT3_FS_SECURITY If you are not using a security module that requires using extended attributes for file security labels, say N. +config EXT4DEV_FS + tristate "Ext4dev/ext4 extended fs support development (EXPERIMENTAL)" + depends on EXPERIMENTAL + select JBD + help + Ext4dev is a predecessor filesystem of the next generation + extended fs ext4, based on ext3 filesystem code. It will be + renamed ext4 fs later, once ext4dev is mature and stabilized. + + Unlike the change from ext2 filesystem to ext3 filesystem, + the on-disk format of ext4dev is not the same as ext3 any more: + it is based on extent maps and it supports 48-bit physical block + numbers. These combined on-disk format changes will allow + ext4dev/ext4 to handle more than 16 TB filesystem volumes -- + a hard limit that ext3 cannot overcome without changing the + on-disk format. + + Other than extent maps and 48-bit block numbers, ext4dev also is + likely to have other new features such as persistent preallocation, + high resolution time stamps, and larger file support etc. These + features will be added to ext4dev gradually. + + To compile this file system support as a module, choose M here. The + module will be called ext4dev. Be aware, however, that the filesystem + of your root partition (the one containing the directory /) cannot + be compiled as a module, and so this could be dangerous. + + If unsure, say N. + +config EXT4DEV_FS_XATTR + bool "Ext4dev extended attributes" + depends on EXT4DEV_FS + default y + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + for details). + + If unsure, say N. + + You need this for POSIX ACL support on ext4dev/ext4. + +config EXT4DEV_FS_POSIX_ACL + bool "Ext4dev POSIX Access Control Lists" + depends on EXT4DEV_FS_XATTR + select FS_POSIX_ACL + help + POSIX Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the POSIX ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N + +config EXT4DEV_FS_SECURITY + bool "Ext4dev Security Labels" + depends on EXT4DEV_FS_XATTR + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the ext4dev/ext4 filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. + config JBD tristate help @@ -173,11 +240,11 @@ config JBD_DEBUG "echo 0 > /proc/sys/fs/jbd-debug". config FS_MBCACHE -# Meta block cache for Extended Attributes (ext2/ext3) +# Meta block cache for Extended Attributes (ext2/ext3/ext4) tristate - depends on EXT2_FS_XATTR || EXT3_FS_XATTR - default y if EXT2_FS=y || EXT3_FS=y - default m if EXT2_FS=m || EXT3_FS=m + depends on EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4DEV_FS_XATTR + default y if EXT2_FS=y || EXT3_FS=y || EXT4DEV_FS=y + default m if EXT2_FS=m || EXT3_FS=m || EXT4DEV_FS=m config REISERFS_FS tristate "Reiserfs support" diff --git a/fs/Makefile b/fs/Makefile index df614eacee86..64396af37b2a 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_DLM) += dlm/ # Do not add any filesystems before this line obj-$(CONFIG_REISERFS_FS) += reiserfs/ obj-$(CONFIG_EXT3_FS) += ext3/ # Before ext2 so root fs can be ext3 +obj-$(CONFIG_EXT4DEV_FS) += ext4/ # Before ext2 so root fs can be ext4dev obj-$(CONFIG_JBD) += jbd/ obj-$(CONFIG_EXT2_FS) += ext2/ obj-$(CONFIG_CRAMFS) += cramfs/ diff --git a/include/linux/magic.h b/include/linux/magic.h index 22036dd2ba36..156c40fc664e 100644 --- a/include/linux/magic.h +++ b/include/linux/magic.h @@ -8,6 +8,7 @@ #define EFS_SUPER_MAGIC 0x414A53 #define EXT2_SUPER_MAGIC 0xEF53 #define EXT3_SUPER_MAGIC 0xEF53 +#define EXT4_SUPER_MAGIC 0xEF53 #define HPFS_SUPER_MAGIC 0xf995e849 #define ISOFS_SUPER_MAGIC 0x9660 #define JFFS2_SUPER_MAGIC 0x72b6 -- cgit v1.2.3 From 470decc613ab2048b619a01028072d932d9086ee Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 11 Oct 2006 01:20:57 -0700 Subject: [PATCH] jbd2: initial copy of files from jbd This is a simple copy of the files in fs/jbd to fs/jbd2 and /usr/incude/linux/[ext4_]jbd.h to /usr/include/[ext4_]jbd2.h Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd2/Makefile | 7 + fs/jbd2/checkpoint.c | 697 +++++++++++++++ fs/jbd2/commit.c | 911 ++++++++++++++++++++ fs/jbd2/journal.c | 2072 ++++++++++++++++++++++++++++++++++++++++++++ fs/jbd2/recovery.c | 592 +++++++++++++ fs/jbd2/revoke.c | 703 +++++++++++++++ fs/jbd2/transaction.c | 2080 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/ext4_jbd2.h | 268 ++++++ include/linux/jbd2.h | 1098 ++++++++++++++++++++++++ 9 files changed, 8428 insertions(+) create mode 100644 fs/jbd2/Makefile create mode 100644 fs/jbd2/checkpoint.c create mode 100644 fs/jbd2/commit.c create mode 100644 fs/jbd2/journal.c create mode 100644 fs/jbd2/recovery.c create mode 100644 fs/jbd2/revoke.c create mode 100644 fs/jbd2/transaction.c create mode 100644 include/linux/ext4_jbd2.h create mode 100644 include/linux/jbd2.h (limited to 'include/linux') diff --git a/fs/jbd2/Makefile b/fs/jbd2/Makefile new file mode 100644 index 000000000000..54aca4868a36 --- /dev/null +++ b/fs/jbd2/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the linux journaling routines. +# + +obj-$(CONFIG_JBD) += jbd.o + +jbd-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c new file mode 100644 index 000000000000..0208cc7ac5d0 --- /dev/null +++ b/fs/jbd2/checkpoint.c @@ -0,0 +1,697 @@ +/* + * linux/fs/checkpoint.c + * + * Written by Stephen C. Tweedie , 1999 + * + * Copyright 1999 Red Hat Software --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Checkpoint routines for the generic filesystem journaling code. + * Part of the ext2fs journaling system. + * + * Checkpointing is the process of ensuring that a section of the log is + * committed fully to disk, so that that portion of the log can be + * reused. + */ + +#include +#include +#include +#include +#include + +/* + * Unlink a buffer from a transaction checkpoint list. + * + * Called with j_list_lock held. + */ +static inline void __buffer_unlink_first(struct journal_head *jh) +{ + transaction_t *transaction = jh->b_cp_transaction; + + jh->b_cpnext->b_cpprev = jh->b_cpprev; + jh->b_cpprev->b_cpnext = jh->b_cpnext; + if (transaction->t_checkpoint_list == jh) { + transaction->t_checkpoint_list = jh->b_cpnext; + if (transaction->t_checkpoint_list == jh) + transaction->t_checkpoint_list = NULL; + } +} + +/* + * Unlink a buffer from a transaction checkpoint(io) list. + * + * Called with j_list_lock held. + */ +static inline void __buffer_unlink(struct journal_head *jh) +{ + transaction_t *transaction = jh->b_cp_transaction; + + __buffer_unlink_first(jh); + if (transaction->t_checkpoint_io_list == jh) { + transaction->t_checkpoint_io_list = jh->b_cpnext; + if (transaction->t_checkpoint_io_list == jh) + transaction->t_checkpoint_io_list = NULL; + } +} + +/* + * Move a buffer from the checkpoint list to the checkpoint io list + * + * Called with j_list_lock held + */ +static inline void __buffer_relink_io(struct journal_head *jh) +{ + transaction_t *transaction = jh->b_cp_transaction; + + __buffer_unlink_first(jh); + + if (!transaction->t_checkpoint_io_list) { + jh->b_cpnext = jh->b_cpprev = jh; + } else { + jh->b_cpnext = transaction->t_checkpoint_io_list; + jh->b_cpprev = transaction->t_checkpoint_io_list->b_cpprev; + jh->b_cpprev->b_cpnext = jh; + jh->b_cpnext->b_cpprev = jh; + } + transaction->t_checkpoint_io_list = jh; +} + +/* + * Try to release a checkpointed buffer from its transaction. + * Returns 1 if we released it and 2 if we also released the + * whole transaction. + * + * Requires j_list_lock + * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it + */ +static int __try_to_free_cp_buf(struct journal_head *jh) +{ + int ret = 0; + struct buffer_head *bh = jh2bh(jh); + + if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) { + JBUFFER_TRACE(jh, "remove from checkpoint list"); + ret = __journal_remove_checkpoint(jh) + 1; + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); + BUFFER_TRACE(bh, "release"); + __brelse(bh); + } else { + jbd_unlock_bh_state(bh); + } + return ret; +} + +/* + * __log_wait_for_space: wait until there is space in the journal. + * + * Called under j-state_lock *only*. It will be unlocked if we have to wait + * for a checkpoint to free up some space in the log. + */ +void __log_wait_for_space(journal_t *journal) +{ + int nblocks; + assert_spin_locked(&journal->j_state_lock); + + nblocks = jbd_space_needed(journal); + while (__log_space_left(journal) < nblocks) { + if (journal->j_flags & JFS_ABORT) + return; + spin_unlock(&journal->j_state_lock); + mutex_lock(&journal->j_checkpoint_mutex); + + /* + * Test again, another process may have checkpointed while we + * were waiting for the checkpoint lock + */ + spin_lock(&journal->j_state_lock); + nblocks = jbd_space_needed(journal); + if (__log_space_left(journal) < nblocks) { + spin_unlock(&journal->j_state_lock); + log_do_checkpoint(journal); + spin_lock(&journal->j_state_lock); + } + mutex_unlock(&journal->j_checkpoint_mutex); + } +} + +/* + * We were unable to perform jbd_trylock_bh_state() inside j_list_lock. + * The caller must restart a list walk. Wait for someone else to run + * jbd_unlock_bh_state(). + */ +static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh) + __releases(journal->j_list_lock) +{ + get_bh(bh); + spin_unlock(&journal->j_list_lock); + jbd_lock_bh_state(bh); + jbd_unlock_bh_state(bh); + put_bh(bh); +} + +/* + * Clean up transaction's list of buffers submitted for io. + * We wait for any pending IO to complete and remove any clean + * buffers. Note that we take the buffers in the opposite ordering + * from the one in which they were submitted for IO. + * + * Called with j_list_lock held. + */ +static void __wait_cp_io(journal_t *journal, transaction_t *transaction) +{ + struct journal_head *jh; + struct buffer_head *bh; + tid_t this_tid; + int released = 0; + + this_tid = transaction->t_tid; +restart: + /* Did somebody clean up the transaction in the meanwhile? */ + if (journal->j_checkpoint_transactions != transaction || + transaction->t_tid != this_tid) + return; + while (!released && transaction->t_checkpoint_io_list) { + jh = transaction->t_checkpoint_io_list; + bh = jh2bh(jh); + if (!jbd_trylock_bh_state(bh)) { + jbd_sync_bh(journal, bh); + spin_lock(&journal->j_list_lock); + goto restart; + } + if (buffer_locked(bh)) { + atomic_inc(&bh->b_count); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + wait_on_buffer(bh); + /* the journal_head may have gone by now */ + BUFFER_TRACE(bh, "brelse"); + __brelse(bh); + spin_lock(&journal->j_list_lock); + goto restart; + } + /* + * Now in whatever state the buffer currently is, we know that + * it has been written out and so we can drop it from the list + */ + released = __journal_remove_checkpoint(jh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); + __brelse(bh); + } +} + +#define NR_BATCH 64 + +static void +__flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) +{ + int i; + + ll_rw_block(SWRITE, *batch_count, bhs); + for (i = 0; i < *batch_count; i++) { + struct buffer_head *bh = bhs[i]; + clear_buffer_jwrite(bh); + BUFFER_TRACE(bh, "brelse"); + __brelse(bh); + } + *batch_count = 0; +} + +/* + * Try to flush one buffer from the checkpoint list to disk. + * + * Return 1 if something happened which requires us to abort the current + * scan of the checkpoint list. + * + * Called with j_list_lock held and drops it if 1 is returned + * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it + */ +static int __process_buffer(journal_t *journal, struct journal_head *jh, + struct buffer_head **bhs, int *batch_count) +{ + struct buffer_head *bh = jh2bh(jh); + int ret = 0; + + if (buffer_locked(bh)) { + atomic_inc(&bh->b_count); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + wait_on_buffer(bh); + /* the journal_head may have gone by now */ + BUFFER_TRACE(bh, "brelse"); + __brelse(bh); + ret = 1; + } else if (jh->b_transaction != NULL) { + transaction_t *t = jh->b_transaction; + tid_t tid = t->t_tid; + + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + log_start_commit(journal, tid); + log_wait_commit(journal, tid); + ret = 1; + } else if (!buffer_dirty(bh)) { + J_ASSERT_JH(jh, !buffer_jbddirty(bh)); + BUFFER_TRACE(bh, "remove from checkpoint"); + __journal_remove_checkpoint(jh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); + __brelse(bh); + ret = 1; + } else { + /* + * Important: we are about to write the buffer, and + * possibly block, while still holding the journal lock. + * We cannot afford to let the transaction logic start + * messing around with this buffer before we write it to + * disk, as that would break recoverability. + */ + BUFFER_TRACE(bh, "queue"); + get_bh(bh); + J_ASSERT_BH(bh, !buffer_jwrite(bh)); + set_buffer_jwrite(bh); + bhs[*batch_count] = bh; + __buffer_relink_io(jh); + jbd_unlock_bh_state(bh); + (*batch_count)++; + if (*batch_count == NR_BATCH) { + spin_unlock(&journal->j_list_lock); + __flush_batch(journal, bhs, batch_count); + ret = 1; + } + } + return ret; +} + +/* + * Perform an actual checkpoint. We take the first transaction on the + * list of transactions to be checkpointed and send all its buffers + * to disk. We submit larger chunks of data at once. + * + * The journal should be locked before calling this function. + */ +int log_do_checkpoint(journal_t *journal) +{ + transaction_t *transaction; + tid_t this_tid; + int result; + + jbd_debug(1, "Start checkpoint\n"); + + /* + * First thing: if there are any transactions in the log which + * don't need checkpointing, just eliminate them from the + * journal straight away. + */ + result = cleanup_journal_tail(journal); + jbd_debug(1, "cleanup_journal_tail returned %d\n", result); + if (result <= 0) + return result; + + /* + * OK, we need to start writing disk blocks. Take one transaction + * and write it. + */ + spin_lock(&journal->j_list_lock); + if (!journal->j_checkpoint_transactions) + goto out; + transaction = journal->j_checkpoint_transactions; + this_tid = transaction->t_tid; +restart: + /* + * If someone cleaned up this transaction while we slept, we're + * done (maybe it's a new transaction, but it fell at the same + * address). + */ + if (journal->j_checkpoint_transactions == transaction && + transaction->t_tid == this_tid) { + int batch_count = 0; + struct buffer_head *bhs[NR_BATCH]; + struct journal_head *jh; + int retry = 0; + + while (!retry && transaction->t_checkpoint_list) { + struct buffer_head *bh; + + jh = transaction->t_checkpoint_list; + bh = jh2bh(jh); + if (!jbd_trylock_bh_state(bh)) { + jbd_sync_bh(journal, bh); + retry = 1; + break; + } + retry = __process_buffer(journal, jh, bhs,&batch_count); + if (!retry && lock_need_resched(&journal->j_list_lock)){ + spin_unlock(&journal->j_list_lock); + retry = 1; + break; + } + } + + if (batch_count) { + if (!retry) { + spin_unlock(&journal->j_list_lock); + retry = 1; + } + __flush_batch(journal, bhs, &batch_count); + } + + if (retry) { + spin_lock(&journal->j_list_lock); + goto restart; + } + /* + * Now we have cleaned up the first transaction's checkpoint + * list. Let's clean up the second one + */ + __wait_cp_io(journal, transaction); + } +out: + spin_unlock(&journal->j_list_lock); + result = cleanup_journal_tail(journal); + if (result < 0) + return result; + return 0; +} + +/* + * Check the list of checkpoint transactions for the journal to see if + * we have already got rid of any since the last update of the log tail + * in the journal superblock. If so, we can instantly roll the + * superblock forward to remove those transactions from the log. + * + * Return <0 on error, 0 on success, 1 if there was nothing to clean up. + * + * Called with the journal lock held. + * + * This is the only part of the journaling code which really needs to be + * aware of transaction aborts. Checkpointing involves writing to the + * main filesystem area rather than to the journal, so it can proceed + * even in abort state, but we must not update the journal superblock if + * we have an abort error outstanding. + */ + +int cleanup_journal_tail(journal_t *journal) +{ + transaction_t * transaction; + tid_t first_tid; + unsigned long blocknr, freed; + + /* OK, work out the oldest transaction remaining in the log, and + * the log block it starts at. + * + * If the log is now empty, we need to work out which is the + * next transaction ID we will write, and where it will + * start. */ + + spin_lock(&journal->j_state_lock); + spin_lock(&journal->j_list_lock); + transaction = journal->j_checkpoint_transactions; + if (transaction) { + first_tid = transaction->t_tid; + blocknr = transaction->t_log_start; + } else if ((transaction = journal->j_committing_transaction) != NULL) { + first_tid = transaction->t_tid; + blocknr = transaction->t_log_start; + } else if ((transaction = journal->j_running_transaction) != NULL) { + first_tid = transaction->t_tid; + blocknr = journal->j_head; + } else { + first_tid = journal->j_transaction_sequence; + blocknr = journal->j_head; + } + spin_unlock(&journal->j_list_lock); + J_ASSERT(blocknr != 0); + + /* If the oldest pinned transaction is at the tail of the log + already then there's not much we can do right now. */ + if (journal->j_tail_sequence == first_tid) { + spin_unlock(&journal->j_state_lock); + return 1; + } + + /* OK, update the superblock to recover the freed space. + * Physical blocks come first: have we wrapped beyond the end of + * the log? */ + freed = blocknr - journal->j_tail; + if (blocknr < journal->j_tail) + freed = freed + journal->j_last - journal->j_first; + + jbd_debug(1, + "Cleaning journal tail from %d to %d (offset %lu), " + "freeing %lu\n", + journal->j_tail_sequence, first_tid, blocknr, freed); + + journal->j_free += freed; + journal->j_tail_sequence = first_tid; + journal->j_tail = blocknr; + spin_unlock(&journal->j_state_lock); + if (!(journal->j_flags & JFS_ABORT)) + journal_update_superblock(journal, 1); + return 0; +} + + +/* Checkpoint list management */ + +/* + * journal_clean_one_cp_list + * + * Find all the written-back checkpoint buffers in the given list and release them. + * + * Called with the journal locked. + * Called with j_list_lock held. + * Returns number of bufers reaped (for debug) + */ + +static int journal_clean_one_cp_list(struct journal_head *jh, int *released) +{ + struct journal_head *last_jh; + struct journal_head *next_jh = jh; + int ret, freed = 0; + + *released = 0; + if (!jh) + return 0; + + last_jh = jh->b_cpprev; + do { + jh = next_jh; + next_jh = jh->b_cpnext; + /* Use trylock because of the ranking */ + if (jbd_trylock_bh_state(jh2bh(jh))) { + ret = __try_to_free_cp_buf(jh); + if (ret) { + freed++; + if (ret == 2) { + *released = 1; + return freed; + } + } + } + /* + * This function only frees up some memory + * if possible so we dont have an obligation + * to finish processing. Bail out if preemption + * requested: + */ + if (need_resched()) + return freed; + } while (jh != last_jh); + + return freed; +} + +/* + * journal_clean_checkpoint_list + * + * Find all the written-back checkpoint buffers in the journal and release them. + * + * Called with the journal locked. + * Called with j_list_lock held. + * Returns number of buffers reaped (for debug) + */ + +int __journal_clean_checkpoint_list(journal_t *journal) +{ + transaction_t *transaction, *last_transaction, *next_transaction; + int ret = 0; + int released; + + transaction = journal->j_checkpoint_transactions; + if (!transaction) + goto out; + + last_transaction = transaction->t_cpprev; + next_transaction = transaction; + do { + transaction = next_transaction; + next_transaction = transaction->t_cpnext; + ret += journal_clean_one_cp_list(transaction-> + t_checkpoint_list, &released); + /* + * This function only frees up some memory if possible so we + * dont have an obligation to finish processing. Bail out if + * preemption requested: + */ + if (need_resched()) + goto out; + if (released) + continue; + /* + * It is essential that we are as careful as in the case of + * t_checkpoint_list with removing the buffer from the list as + * we can possibly see not yet submitted buffers on io_list + */ + ret += journal_clean_one_cp_list(transaction-> + t_checkpoint_io_list, &released); + if (need_resched()) + goto out; + } while (transaction != last_transaction); +out: + return ret; +} + +/* + * journal_remove_checkpoint: called after a buffer has been committed + * to disk (either by being write-back flushed to disk, or being + * committed to the log). + * + * We cannot safely clean a transaction out of the log until all of the + * buffer updates committed in that transaction have safely been stored + * elsewhere on disk. To achieve this, all of the buffers in a + * transaction need to be maintained on the transaction's checkpoint + * lists until they have been rewritten, at which point this function is + * called to remove the buffer from the existing transaction's + * checkpoint lists. + * + * The function returns 1 if it frees the transaction, 0 otherwise. + * + * This function is called with the journal locked. + * This function is called with j_list_lock held. + * This function is called with jbd_lock_bh_state(jh2bh(jh)) + */ + +int __journal_remove_checkpoint(struct journal_head *jh) +{ + transaction_t *transaction; + journal_t *journal; + int ret = 0; + + JBUFFER_TRACE(jh, "entry"); + + if ((transaction = jh->b_cp_transaction) == NULL) { + JBUFFER_TRACE(jh, "not on transaction"); + goto out; + } + journal = transaction->t_journal; + + __buffer_unlink(jh); + jh->b_cp_transaction = NULL; + + if (transaction->t_checkpoint_list != NULL || + transaction->t_checkpoint_io_list != NULL) + goto out; + JBUFFER_TRACE(jh, "transaction has no more buffers"); + + /* + * There is one special case to worry about: if we have just pulled the + * buffer off a committing transaction's forget list, then even if the + * checkpoint list is empty, the transaction obviously cannot be + * dropped! + * + * The locking here around j_committing_transaction is a bit sleazy. + * See the comment at the end of journal_commit_transaction(). + */ + if (transaction == journal->j_committing_transaction) { + JBUFFER_TRACE(jh, "belongs to committing transaction"); + goto out; + } + + /* OK, that was the last buffer for the transaction: we can now + safely remove this transaction from the log */ + + __journal_drop_transaction(journal, transaction); + + /* Just in case anybody was waiting for more transactions to be + checkpointed... */ + wake_up(&journal->j_wait_logspace); + ret = 1; +out: + JBUFFER_TRACE(jh, "exit"); + return ret; +} + +/* + * journal_insert_checkpoint: put a committed buffer onto a checkpoint + * list so that we know when it is safe to clean the transaction out of + * the log. + * + * Called with the journal locked. + * Called with j_list_lock held. + */ +void __journal_insert_checkpoint(struct journal_head *jh, + transaction_t *transaction) +{ + JBUFFER_TRACE(jh, "entry"); + J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh))); + J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); + + jh->b_cp_transaction = transaction; + + if (!transaction->t_checkpoint_list) { + jh->b_cpnext = jh->b_cpprev = jh; + } else { + jh->b_cpnext = transaction->t_checkpoint_list; + jh->b_cpprev = transaction->t_checkpoint_list->b_cpprev; + jh->b_cpprev->b_cpnext = jh; + jh->b_cpnext->b_cpprev = jh; + } + transaction->t_checkpoint_list = jh; +} + +/* + * We've finished with this transaction structure: adios... + * + * The transaction must have no links except for the checkpoint by this + * point. + * + * Called with the journal locked. + * Called with j_list_lock held. + */ + +void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) +{ + assert_spin_locked(&journal->j_list_lock); + if (transaction->t_cpnext) { + transaction->t_cpnext->t_cpprev = transaction->t_cpprev; + transaction->t_cpprev->t_cpnext = transaction->t_cpnext; + if (journal->j_checkpoint_transactions == transaction) + journal->j_checkpoint_transactions = + transaction->t_cpnext; + if (journal->j_checkpoint_transactions == transaction) + journal->j_checkpoint_transactions = NULL; + } + + J_ASSERT(transaction->t_state == T_FINISHED); + J_ASSERT(transaction->t_buffers == NULL); + J_ASSERT(transaction->t_sync_datalist == NULL); + J_ASSERT(transaction->t_forget == NULL); + J_ASSERT(transaction->t_iobuf_list == NULL); + J_ASSERT(transaction->t_shadow_list == NULL); + J_ASSERT(transaction->t_log_list == NULL); + J_ASSERT(transaction->t_checkpoint_list == NULL); + J_ASSERT(transaction->t_checkpoint_io_list == NULL); + J_ASSERT(transaction->t_updates == 0); + J_ASSERT(journal->j_committing_transaction != transaction); + J_ASSERT(journal->j_running_transaction != transaction); + + jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid); + kfree(transaction); +} diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c new file mode 100644 index 000000000000..10be51290a27 --- /dev/null +++ b/fs/jbd2/commit.c @@ -0,0 +1,911 @@ +/* + * linux/fs/jbd/commit.c + * + * Written by Stephen C. Tweedie , 1998 + * + * Copyright 1998 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Journal commit routines for the generic filesystem journaling code; + * part of the ext2fs journaling system. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Default IO end handler for temporary BJ_IO buffer_heads. + */ +static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) +{ + BUFFER_TRACE(bh, ""); + if (uptodate) + set_buffer_uptodate(bh); + else + clear_buffer_uptodate(bh); + unlock_buffer(bh); +} + +/* + * When an ext3-ordered file is truncated, it is possible that many pages are + * not sucessfully freed, because they are attached to a committing transaction. + * After the transaction commits, these pages are left on the LRU, with no + * ->mapping, and with attached buffers. These pages are trivially reclaimable + * by the VM, but their apparent absence upsets the VM accounting, and it makes + * the numbers in /proc/meminfo look odd. + * + * So here, we have a buffer which has just come off the forget list. Look to + * see if we can strip all buffers from the backing page. + * + * Called under lock_journal(), and possibly under journal_datalist_lock. The + * caller provided us with a ref against the buffer, and we drop that here. + */ +static void release_buffer_page(struct buffer_head *bh) +{ + struct page *page; + + if (buffer_dirty(bh)) + goto nope; + if (atomic_read(&bh->b_count) != 1) + goto nope; + page = bh->b_page; + if (!page) + goto nope; + if (page->mapping) + goto nope; + + /* OK, it's a truncated page */ + if (TestSetPageLocked(page)) + goto nope; + + page_cache_get(page); + __brelse(bh); + try_to_free_buffers(page); + unlock_page(page); + page_cache_release(page); + return; + +nope: + __brelse(bh); +} + +/* + * Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is + * held. For ranking reasons we must trylock. If we lose, schedule away and + * return 0. j_list_lock is dropped in this case. + */ +static int inverted_lock(journal_t *journal, struct buffer_head *bh) +{ + if (!jbd_trylock_bh_state(bh)) { + spin_unlock(&journal->j_list_lock); + schedule(); + return 0; + } + return 1; +} + +/* Done it all: now write the commit record. We should have + * cleaned up our previous buffers by now, so if we are in abort + * mode we can now just skip the rest of the journal write + * entirely. + * + * Returns 1 if the journal needs to be aborted or 0 on success + */ +static int journal_write_commit_record(journal_t *journal, + transaction_t *commit_transaction) +{ + struct journal_head *descriptor; + struct buffer_head *bh; + int i, ret; + int barrier_done = 0; + + if (is_journal_aborted(journal)) + return 0; + + descriptor = journal_get_descriptor_buffer(journal); + if (!descriptor) + return 1; + + bh = jh2bh(descriptor); + + /* AKPM: buglet - add `i' to tmp! */ + for (i = 0; i < bh->b_size; i += 512) { + journal_header_t *tmp = (journal_header_t*)bh->b_data; + tmp->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); + tmp->h_blocktype = cpu_to_be32(JFS_COMMIT_BLOCK); + tmp->h_sequence = cpu_to_be32(commit_transaction->t_tid); + } + + JBUFFER_TRACE(descriptor, "write commit block"); + set_buffer_dirty(bh); + if (journal->j_flags & JFS_BARRIER) { + set_buffer_ordered(bh); + barrier_done = 1; + } + ret = sync_dirty_buffer(bh); + /* is it possible for another commit to fail at roughly + * the same time as this one? If so, we don't want to + * trust the barrier flag in the super, but instead want + * to remember if we sent a barrier request + */ + if (ret == -EOPNOTSUPP && barrier_done) { + char b[BDEVNAME_SIZE]; + + printk(KERN_WARNING + "JBD: barrier-based sync failed on %s - " + "disabling barriers\n", + bdevname(journal->j_dev, b)); + spin_lock(&journal->j_state_lock); + journal->j_flags &= ~JFS_BARRIER; + spin_unlock(&journal->j_state_lock); + + /* And try again, without the barrier */ + clear_buffer_ordered(bh); + set_buffer_uptodate(bh); + set_buffer_dirty(bh); + ret = sync_dirty_buffer(bh); + } + put_bh(bh); /* One for getblk() */ + journal_put_journal_head(descriptor); + + return (ret == -EIO); +} + +static void journal_do_submit_data(struct buffer_head **wbuf, int bufs) +{ + int i; + + for (i = 0; i < bufs; i++) { + wbuf[i]->b_end_io = end_buffer_write_sync; + /* We use-up our safety reference in submit_bh() */ + submit_bh(WRITE, wbuf[i]); + } +} + +/* + * Submit all the data buffers to disk + */ +static void journal_submit_data_buffers(journal_t *journal, + transaction_t *commit_transaction) +{ + struct journal_head *jh; + struct buffer_head *bh; + int locked; + int bufs = 0; + struct buffer_head **wbuf = journal->j_wbuf; + + /* + * Whenever we unlock the journal and sleep, things can get added + * onto ->t_sync_datalist, so we have to keep looping back to + * write_out_data until we *know* that the list is empty. + * + * Cleanup any flushed data buffers from the data list. Even in + * abort mode, we want to flush this out as soon as possible. + */ +write_out_data: + cond_resched(); + spin_lock(&journal->j_list_lock); + + while (commit_transaction->t_sync_datalist) { + jh = commit_transaction->t_sync_datalist; + bh = jh2bh(jh); + locked = 0; + + /* Get reference just to make sure buffer does not disappear + * when we are forced to drop various locks */ + get_bh(bh); + /* If the buffer is dirty, we need to submit IO and hence + * we need the buffer lock. We try to lock the buffer without + * blocking. If we fail, we need to drop j_list_lock and do + * blocking lock_buffer(). + */ + if (buffer_dirty(bh)) { + if (test_set_buffer_locked(bh)) { + BUFFER_TRACE(bh, "needs blocking lock"); + spin_unlock(&journal->j_list_lock); + /* Write out all data to prevent deadlocks */ + journal_do_submit_data(wbuf, bufs); + bufs = 0; + lock_buffer(bh); + spin_lock(&journal->j_list_lock); + } + locked = 1; + } + /* We have to get bh_state lock. Again out of order, sigh. */ + if (!inverted_lock(journal, bh)) { + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); + } + /* Someone already cleaned up the buffer? */ + if (!buffer_jbd(bh) + || jh->b_transaction != commit_transaction + || jh->b_jlist != BJ_SyncData) { + jbd_unlock_bh_state(bh); + if (locked) + unlock_buffer(bh); + BUFFER_TRACE(bh, "already cleaned up"); + put_bh(bh); + continue; + } + if (locked && test_clear_buffer_dirty(bh)) { + BUFFER_TRACE(bh, "needs writeout, adding to array"); + wbuf[bufs++] = bh; + __journal_file_buffer(jh, commit_transaction, + BJ_Locked); + jbd_unlock_bh_state(bh); + if (bufs == journal->j_wbufsize) { + spin_unlock(&journal->j_list_lock); + journal_do_submit_data(wbuf, bufs); + bufs = 0; + goto write_out_data; + } + } + else { + BUFFER_TRACE(bh, "writeout complete: unfile"); + __journal_unfile_buffer(jh); + jbd_unlock_bh_state(bh); + if (locked) + unlock_buffer(bh); + journal_remove_journal_head(bh); + /* Once for our safety reference, once for + * journal_remove_journal_head() */ + put_bh(bh); + put_bh(bh); + } + + if (lock_need_resched(&journal->j_list_lock)) { + spin_unlock(&journal->j_list_lock); + goto write_out_data; + } + } + spin_unlock(&journal->j_list_lock); + journal_do_submit_data(wbuf, bufs); +} + +/* + * journal_commit_transaction + * + * The primary function for committing a transaction to the log. This + * function is called by the journal thread to begin a complete commit. + */ +void journal_commit_transaction(journal_t *journal) +{ + transaction_t *commit_transaction; + struct journal_head *jh, *new_jh, *descriptor; + struct buffer_head **wbuf = journal->j_wbuf; + int bufs; + int flags; + int err; + unsigned long blocknr; + char *tagp = NULL; + journal_header_t *header; + journal_block_tag_t *tag = NULL; + int space_left = 0; + int first_tag = 0; + int tag_flag; + int i; + + /* + * First job: lock down the current transaction and wait for + * all outstanding updates to complete. + */ + +#ifdef COMMIT_STATS + spin_lock(&journal->j_list_lock); + summarise_journal_usage(journal); + spin_unlock(&journal->j_list_lock); +#endif + + /* Do we need to erase the effects of a prior journal_flush? */ + if (journal->j_flags & JFS_FLUSHED) { + jbd_debug(3, "super block updated\n"); + journal_update_superblock(journal, 1); + } else { + jbd_debug(3, "superblock not updated\n"); + } + + J_ASSERT(journal->j_running_transaction != NULL); + J_ASSERT(journal->j_committing_transaction == NULL); + + commit_transaction = journal->j_running_transaction; + J_ASSERT(commit_transaction->t_state == T_RUNNING); + + jbd_debug(1, "JBD: starting commit of transaction %d\n", + commit_transaction->t_tid); + + spin_lock(&journal->j_state_lock); + commit_transaction->t_state = T_LOCKED; + + spin_lock(&commit_transaction->t_handle_lock); + while (commit_transaction->t_updates) { + DEFINE_WAIT(wait); + + prepare_to_wait(&journal->j_wait_updates, &wait, + TASK_UNINTERRUPTIBLE); + if (commit_transaction->t_updates) { + spin_unlock(&commit_transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); + schedule(); + spin_lock(&journal->j_state_lock); + spin_lock(&commit_transaction->t_handle_lock); + } + finish_wait(&journal->j_wait_updates, &wait); + } + spin_unlock(&commit_transaction->t_handle_lock); + + J_ASSERT (commit_transaction->t_outstanding_credits <= + journal->j_max_transaction_buffers); + + /* + * First thing we are allowed to do is to discard any remaining + * BJ_Reserved buffers. Note, it is _not_ permissible to assume + * that there are no such buffers: if a large filesystem + * operation like a truncate needs to split itself over multiple + * transactions, then it may try to do a journal_restart() while + * there are still BJ_Reserved buffers outstanding. These must + * be released cleanly from the current transaction. + * + * In this case, the filesystem must still reserve write access + * again before modifying the buffer in the new transaction, but + * we do not require it to remember exactly which old buffers it + * has reserved. This is consistent with the existing behaviour + * that multiple journal_get_write_access() calls to the same + * buffer are perfectly permissable. + */ + while (commit_transaction->t_reserved_list) { + jh = commit_transaction->t_reserved_list; + JBUFFER_TRACE(jh, "reserved, unused: refile"); + /* + * A journal_get_undo_access()+journal_release_buffer() may + * leave undo-committed data. + */ + if (jh->b_committed_data) { + struct buffer_head *bh = jh2bh(jh); + + jbd_lock_bh_state(bh); + jbd_slab_free(jh->b_committed_data, bh->b_size); + jh->b_committed_data = NULL; + jbd_unlock_bh_state(bh); + } + journal_refile_buffer(journal, jh); + } + + /* + * Now try to drop any written-back buffers from the journal's + * checkpoint lists. We do this *before* commit because it potentially + * frees some memory + */ + spin_lock(&journal->j_list_lock); + __journal_clean_checkpoint_list(journal); + spin_unlock(&journal->j_list_lock); + + jbd_debug (3, "JBD: commit phase 1\n"); + + /* + * Switch to a new revoke table. + */ + journal_switch_revoke_table(journal); + + commit_transaction->t_state = T_FLUSH; + journal->j_committing_transaction = commit_transaction; + journal->j_running_transaction = NULL; + commit_transaction->t_log_start = journal->j_head; + wake_up(&journal->j_wait_transaction_locked); + spin_unlock(&journal->j_state_lock); + + jbd_debug (3, "JBD: commit phase 2\n"); + + /* + * First, drop modified flag: all accesses to the buffers + * will be tracked for a new trasaction only -bzzz + */ + spin_lock(&journal->j_list_lock); + if (commit_transaction->t_buffers) { + new_jh = jh = commit_transaction->t_buffers->b_tnext; + do { + J_ASSERT_JH(new_jh, new_jh->b_modified == 1 || + new_jh->b_modified == 0); + new_jh->b_modified = 0; + new_jh = new_jh->b_tnext; + } while (new_jh != jh); + } + spin_unlock(&journal->j_list_lock); + + /* + * Now start flushing things to disk, in the order they appear + * on the transaction lists. Data blocks go first. + */ + err = 0; + journal_submit_data_buffers(journal, commit_transaction); + + /* + * Wait for all previously submitted IO to complete. + */ + spin_lock(&journal->j_list_lock); + while (commit_transaction->t_locked_list) { + struct buffer_head *bh; + + jh = commit_transaction->t_locked_list->b_tprev; + bh = jh2bh(jh); + get_bh(bh); + if (buffer_locked(bh)) { + spin_unlock(&journal->j_list_lock); + wait_on_buffer(bh); + if (unlikely(!buffer_uptodate(bh))) + err = -EIO; + spin_lock(&journal->j_list_lock); + } + if (!inverted_lock(journal, bh)) { + put_bh(bh); + spin_lock(&journal->j_list_lock); + continue; + } + if (buffer_jbd(bh) && jh->b_jlist == BJ_Locked) { + __journal_unfile_buffer(jh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); + put_bh(bh); + } else { + jbd_unlock_bh_state(bh); + } + put_bh(bh); + cond_resched_lock(&journal->j_list_lock); + } + 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"); + + /* + * If we found any dirty or locked buffers, then we should have + * looped back up to the write_out_data label. If there weren't + * any then journal_clean_data_list should have wiped the list + * clean by now, so check that it is in fact empty. + */ + J_ASSERT (commit_transaction->t_sync_datalist == NULL); + + jbd_debug (3, "JBD: commit phase 3\n"); + + /* + * Way to go: we have now written out all of the data for a + * transaction! Now comes the tricky part: we need to write out + * metadata. Loop over the transaction's entire buffer list: + */ + commit_transaction->t_state = T_COMMIT; + + descriptor = NULL; + bufs = 0; + while (commit_transaction->t_buffers) { + + /* Find the next buffer to be journaled... */ + + jh = commit_transaction->t_buffers; + + /* If we're in abort mode, we just un-journal the buffer and + release it for background writing. */ + + if (is_journal_aborted(journal)) { + JBUFFER_TRACE(jh, "journal is aborting: refile"); + journal_refile_buffer(journal, jh); + /* If that was the last one, we need to clean up + * any descriptor buffers which may have been + * already allocated, even if we are now + * aborting. */ + if (!commit_transaction->t_buffers) + goto start_journal_io; + continue; + } + + /* Make sure we have a descriptor block in which to + record the metadata buffer. */ + + if (!descriptor) { + struct buffer_head *bh; + + J_ASSERT (bufs == 0); + + jbd_debug(4, "JBD: get descriptor\n"); + + descriptor = journal_get_descriptor_buffer(journal); + if (!descriptor) { + __journal_abort_hard(journal); + continue; + } + + bh = jh2bh(descriptor); + jbd_debug(4, "JBD: got buffer %llu (%p)\n", + (unsigned long long)bh->b_blocknr, bh->b_data); + header = (journal_header_t *)&bh->b_data[0]; + header->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); + header->h_blocktype = cpu_to_be32(JFS_DESCRIPTOR_BLOCK); + header->h_sequence = cpu_to_be32(commit_transaction->t_tid); + + tagp = &bh->b_data[sizeof(journal_header_t)]; + space_left = bh->b_size - sizeof(journal_header_t); + first_tag = 1; + set_buffer_jwrite(bh); + set_buffer_dirty(bh); + wbuf[bufs++] = bh; + + /* Record it so that we can wait for IO + completion later */ + BUFFER_TRACE(bh, "ph3: file as descriptor"); + journal_file_buffer(descriptor, commit_transaction, + BJ_LogCtl); + } + + /* Where is the buffer to be written? */ + + err = journal_next_log_block(journal, &blocknr); + /* If the block mapping failed, just abandon the buffer + and repeat this loop: we'll fall into the + refile-on-abort condition above. */ + if (err) { + __journal_abort_hard(journal); + continue; + } + + /* + * start_this_handle() uses t_outstanding_credits to determine + * the free space in the log, but this counter is changed + * by journal_next_log_block() also. + */ + commit_transaction->t_outstanding_credits--; + + /* Bump b_count to prevent truncate from stumbling over + the shadowed buffer! @@@ This can go if we ever get + rid of the BJ_IO/BJ_Shadow pairing of buffers. */ + atomic_inc(&jh2bh(jh)->b_count); + + /* Make a temporary IO buffer with which to write it out + (this will requeue both the metadata buffer and the + temporary IO buffer). new_bh goes on BJ_IO*/ + + set_bit(BH_JWrite, &jh2bh(jh)->b_state); + /* + * akpm: journal_write_metadata_buffer() sets + * new_bh->b_transaction to commit_transaction. + * We need to clean this up before we release new_bh + * (which is of type BJ_IO) + */ + JBUFFER_TRACE(jh, "ph3: write metadata"); + flags = journal_write_metadata_buffer(commit_transaction, + jh, &new_jh, blocknr); + set_bit(BH_JWrite, &jh2bh(new_jh)->b_state); + wbuf[bufs++] = jh2bh(new_jh); + + /* Record the new block's tag in the current descriptor + buffer */ + + tag_flag = 0; + if (flags & 1) + tag_flag |= JFS_FLAG_ESCAPE; + if (!first_tag) + tag_flag |= JFS_FLAG_SAME_UUID; + + tag = (journal_block_tag_t *) tagp; + tag->t_blocknr = cpu_to_be32(jh2bh(jh)->b_blocknr); + tag->t_flags = cpu_to_be32(tag_flag); + tagp += sizeof(journal_block_tag_t); + space_left -= sizeof(journal_block_tag_t); + + if (first_tag) { + memcpy (tagp, journal->j_uuid, 16); + tagp += 16; + space_left -= 16; + first_tag = 0; + } + + /* If there's no more to do, or if the descriptor is full, + let the IO rip! */ + + if (bufs == journal->j_wbufsize || + commit_transaction->t_buffers == NULL || + space_left < sizeof(journal_block_tag_t) + 16) { + + jbd_debug(4, "JBD: Submit %d IOs\n", bufs); + + /* Write an end-of-descriptor marker before + submitting the IOs. "tag" still points to + the last tag we set up. */ + + tag->t_flags |= cpu_to_be32(JFS_FLAG_LAST_TAG); + +start_journal_io: + for (i = 0; i < bufs; i++) { + struct buffer_head *bh = wbuf[i]; + lock_buffer(bh); + clear_buffer_dirty(bh); + set_buffer_uptodate(bh); + bh->b_end_io = journal_end_buffer_io_sync; + submit_bh(WRITE, bh); + } + cond_resched(); + + /* Force a new descriptor to be generated next + time round the loop. */ + descriptor = NULL; + bufs = 0; + } + } + + /* Lo and behold: we have just managed to send a transaction to + the log. Before we can commit it, wait for the IO so far to + complete. Control buffers being written are on the + transaction's t_log_list queue, and metadata buffers are on + the t_iobuf_list queue. + + Wait for the buffers in reverse order. That way we are + less likely to be woken up until all IOs have completed, and + so we incur less scheduling load. + */ + + jbd_debug(3, "JBD: commit phase 4\n"); + + /* + * akpm: these are BJ_IO, and j_list_lock is not needed. + * See __journal_try_to_free_buffer. + */ +wait_for_iobuf: + while (commit_transaction->t_iobuf_list != NULL) { + struct buffer_head *bh; + + jh = commit_transaction->t_iobuf_list->b_tprev; + bh = jh2bh(jh); + if (buffer_locked(bh)) { + wait_on_buffer(bh); + goto wait_for_iobuf; + } + if (cond_resched()) + goto wait_for_iobuf; + + if (unlikely(!buffer_uptodate(bh))) + err = -EIO; + + clear_buffer_jwrite(bh); + + JBUFFER_TRACE(jh, "ph4: unfile after journal write"); + journal_unfile_buffer(journal, jh); + + /* + * ->t_iobuf_list should contain only dummy buffer_heads + * which were created by journal_write_metadata_buffer(). + */ + BUFFER_TRACE(bh, "dumping temporary bh"); + journal_put_journal_head(jh); + __brelse(bh); + J_ASSERT_BH(bh, atomic_read(&bh->b_count) == 0); + free_buffer_head(bh); + + /* We also have to unlock and free the corresponding + shadowed buffer */ + jh = commit_transaction->t_shadow_list->b_tprev; + bh = jh2bh(jh); + clear_bit(BH_JWrite, &bh->b_state); + J_ASSERT_BH(bh, buffer_jbddirty(bh)); + + /* The metadata is now released for reuse, but we need + to remember it against this transaction so that when + we finally commit, we can do any checkpointing + required. */ + JBUFFER_TRACE(jh, "file as BJ_Forget"); + journal_file_buffer(jh, commit_transaction, BJ_Forget); + /* Wake up any transactions which were waiting for this + IO to complete */ + wake_up_bit(&bh->b_state, BH_Unshadow); + JBUFFER_TRACE(jh, "brelse shadowed buffer"); + __brelse(bh); + } + + J_ASSERT (commit_transaction->t_shadow_list == NULL); + + jbd_debug(3, "JBD: commit phase 5\n"); + + /* Here we wait for the revoke record and descriptor record buffers */ + wait_for_ctlbuf: + while (commit_transaction->t_log_list != NULL) { + struct buffer_head *bh; + + jh = commit_transaction->t_log_list->b_tprev; + bh = jh2bh(jh); + if (buffer_locked(bh)) { + wait_on_buffer(bh); + goto wait_for_ctlbuf; + } + if (cond_resched()) + goto wait_for_ctlbuf; + + if (unlikely(!buffer_uptodate(bh))) + err = -EIO; + + BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile"); + clear_buffer_jwrite(bh); + journal_unfile_buffer(journal, jh); + journal_put_journal_head(jh); + __brelse(bh); /* One for getblk */ + /* AKPM: bforget here */ + } + + jbd_debug(3, "JBD: commit phase 6\n"); + + if (journal_write_commit_record(journal, commit_transaction)) + err = -EIO; + + if (err) + __journal_abort_hard(journal); + + /* End of a transaction! Finally, we can do checkpoint + processing: any buffers committed as a result of this + transaction can be removed from any checkpoint list it was on + before. */ + + jbd_debug(3, "JBD: commit phase 7\n"); + + J_ASSERT(commit_transaction->t_sync_datalist == NULL); + J_ASSERT(commit_transaction->t_buffers == NULL); + J_ASSERT(commit_transaction->t_checkpoint_list == NULL); + J_ASSERT(commit_transaction->t_iobuf_list == NULL); + J_ASSERT(commit_transaction->t_shadow_list == NULL); + J_ASSERT(commit_transaction->t_log_list == NULL); + +restart_loop: + /* + * As there are other places (journal_unmap_buffer()) adding buffers + * to this list we have to be careful and hold the j_list_lock. + */ + spin_lock(&journal->j_list_lock); + while (commit_transaction->t_forget) { + transaction_t *cp_transaction; + struct buffer_head *bh; + + jh = commit_transaction->t_forget; + spin_unlock(&journal->j_list_lock); + bh = jh2bh(jh); + jbd_lock_bh_state(bh); + J_ASSERT_JH(jh, jh->b_transaction == commit_transaction || + jh->b_transaction == journal->j_running_transaction); + + /* + * If there is undo-protected committed data against + * this buffer, then we can remove it now. If it is a + * buffer needing such protection, the old frozen_data + * field now points to a committed version of the + * buffer, so rotate that field to the new committed + * data. + * + * Otherwise, we can just throw away the frozen data now. + */ + if (jh->b_committed_data) { + jbd_slab_free(jh->b_committed_data, bh->b_size); + jh->b_committed_data = NULL; + if (jh->b_frozen_data) { + jh->b_committed_data = jh->b_frozen_data; + jh->b_frozen_data = NULL; + } + } else if (jh->b_frozen_data) { + jbd_slab_free(jh->b_frozen_data, bh->b_size); + jh->b_frozen_data = NULL; + } + + spin_lock(&journal->j_list_lock); + cp_transaction = jh->b_cp_transaction; + if (cp_transaction) { + JBUFFER_TRACE(jh, "remove from old cp transaction"); + __journal_remove_checkpoint(jh); + } + + /* Only re-checkpoint the buffer_head if it is marked + * dirty. If the buffer was added to the BJ_Forget list + * by journal_forget, it may no longer be dirty and + * there's no point in keeping a checkpoint record for + * it. */ + + /* A buffer which has been freed while still being + * journaled by a previous transaction may end up still + * being dirty here, but we want to avoid writing back + * that buffer in the future now that the last use has + * been committed. That's not only a performance gain, + * it also stops aliasing problems if the buffer is left + * behind for writeback and gets reallocated for another + * use in a different page. */ + if (buffer_freed(bh)) { + clear_buffer_freed(bh); + clear_buffer_jbddirty(bh); + } + + if (buffer_jbddirty(bh)) { + JBUFFER_TRACE(jh, "add to new checkpointing trans"); + __journal_insert_checkpoint(jh, commit_transaction); + JBUFFER_TRACE(jh, "refile for checkpoint writeback"); + __journal_refile_buffer(jh); + jbd_unlock_bh_state(bh); + } else { + J_ASSERT_BH(bh, !buffer_dirty(bh)); + /* The buffer on BJ_Forget list and not jbddirty means + * it has been freed by this transaction and hence it + * could not have been reallocated until this + * transaction has committed. *BUT* it could be + * reallocated once we have written all the data to + * disk and before we process the buffer on BJ_Forget + * list. */ + JBUFFER_TRACE(jh, "refile or unfile freed buffer"); + __journal_refile_buffer(jh); + if (!jh->b_transaction) { + jbd_unlock_bh_state(bh); + /* needs a brelse */ + journal_remove_journal_head(bh); + release_buffer_page(bh); + } else + jbd_unlock_bh_state(bh); + } + cond_resched_lock(&journal->j_list_lock); + } + spin_unlock(&journal->j_list_lock); + /* + * This is a bit sleazy. We borrow j_list_lock to protect + * journal->j_committing_transaction in __journal_remove_checkpoint. + * Really, __journal_remove_checkpoint should be using j_state_lock but + * it's a bit hassle to hold that across __journal_remove_checkpoint + */ + spin_lock(&journal->j_state_lock); + spin_lock(&journal->j_list_lock); + /* + * Now recheck if some buffers did not get attached to the transaction + * while the lock was dropped... + */ + if (commit_transaction->t_forget) { + spin_unlock(&journal->j_list_lock); + spin_unlock(&journal->j_state_lock); + goto restart_loop; + } + + /* Done with this transaction! */ + + jbd_debug(3, "JBD: commit phase 8\n"); + + J_ASSERT(commit_transaction->t_state == T_COMMIT); + + commit_transaction->t_state = T_FINISHED; + J_ASSERT(commit_transaction == journal->j_committing_transaction); + journal->j_commit_sequence = commit_transaction->t_tid; + journal->j_committing_transaction = NULL; + spin_unlock(&journal->j_state_lock); + + if (commit_transaction->t_checkpoint_list == NULL) { + __journal_drop_transaction(journal, commit_transaction); + } else { + if (journal->j_checkpoint_transactions == NULL) { + journal->j_checkpoint_transactions = commit_transaction; + commit_transaction->t_cpnext = commit_transaction; + commit_transaction->t_cpprev = commit_transaction; + } else { + commit_transaction->t_cpnext = + journal->j_checkpoint_transactions; + commit_transaction->t_cpprev = + commit_transaction->t_cpnext->t_cpprev; + commit_transaction->t_cpnext->t_cpprev = + commit_transaction; + commit_transaction->t_cpprev->t_cpnext = + commit_transaction; + } + } + spin_unlock(&journal->j_list_lock); + + jbd_debug(1, "JBD: commit %d complete, head %d\n", + journal->j_commit_sequence, journal->j_tail_sequence); + + wake_up(&journal->j_wait_done_commit); +} diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c new file mode 100644 index 000000000000..c518dd8fe60a --- /dev/null +++ b/fs/jbd2/journal.c @@ -0,0 +1,2072 @@ +/* + * linux/fs/jbd/journal.c + * + * Written by Stephen C. Tweedie , 1998 + * + * Copyright 1998 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Generic filesystem journal-writing code; part of the ext2fs + * journaling system. + * + * This file manages journals: areas of disk reserved for logging + * transactional updates. This includes the kernel journaling thread + * which is responsible for scheduling updates to the log. + * + * We do not actually manage the physical storage of the journal in this + * file: that is left to a per-journal policy function, which allows us + * to store the journal within a filesystem-specified area for ext2 + * journaling (ext2 can use a reserved inode for storing the log). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +EXPORT_SYMBOL(journal_start); +EXPORT_SYMBOL(journal_restart); +EXPORT_SYMBOL(journal_extend); +EXPORT_SYMBOL(journal_stop); +EXPORT_SYMBOL(journal_lock_updates); +EXPORT_SYMBOL(journal_unlock_updates); +EXPORT_SYMBOL(journal_get_write_access); +EXPORT_SYMBOL(journal_get_create_access); +EXPORT_SYMBOL(journal_get_undo_access); +EXPORT_SYMBOL(journal_dirty_data); +EXPORT_SYMBOL(journal_dirty_metadata); +EXPORT_SYMBOL(journal_release_buffer); +EXPORT_SYMBOL(journal_forget); +#if 0 +EXPORT_SYMBOL(journal_sync_buffer); +#endif +EXPORT_SYMBOL(journal_flush); +EXPORT_SYMBOL(journal_revoke); + +EXPORT_SYMBOL(journal_init_dev); +EXPORT_SYMBOL(journal_init_inode); +EXPORT_SYMBOL(journal_update_format); +EXPORT_SYMBOL(journal_check_used_features); +EXPORT_SYMBOL(journal_check_available_features); +EXPORT_SYMBOL(journal_set_features); +EXPORT_SYMBOL(journal_create); +EXPORT_SYMBOL(journal_load); +EXPORT_SYMBOL(journal_destroy); +EXPORT_SYMBOL(journal_update_superblock); +EXPORT_SYMBOL(journal_abort); +EXPORT_SYMBOL(journal_errno); +EXPORT_SYMBOL(journal_ack_err); +EXPORT_SYMBOL(journal_clear_err); +EXPORT_SYMBOL(log_wait_commit); +EXPORT_SYMBOL(journal_start_commit); +EXPORT_SYMBOL(journal_force_commit_nested); +EXPORT_SYMBOL(journal_wipe); +EXPORT_SYMBOL(journal_blocks_per_page); +EXPORT_SYMBOL(journal_invalidatepage); +EXPORT_SYMBOL(journal_try_to_free_buffers); +EXPORT_SYMBOL(journal_force_commit); + +static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); +static void __journal_abort_soft (journal_t *journal, int errno); +static int journal_create_jbd_slab(size_t slab_size); + +/* + * Helper function used to manage commit timeouts + */ + +static void commit_timeout(unsigned long __data) +{ + struct task_struct * p = (struct task_struct *) __data; + + wake_up_process(p); +} + +/* + * kjournald: The main thread function used to manage a logging device + * journal. + * + * This kernel thread is responsible for two things: + * + * 1) COMMIT: Every so often we need to commit the current state of the + * filesystem to disk. The journal thread is responsible for writing + * all of the metadata buffers to disk. + * + * 2) CHECKPOINT: We cannot reuse a used section of the log file until all + * of the data in that part of the log has been rewritten elsewhere on + * the disk. Flushing these old buffers to reclaim space in the log is + * known as checkpointing, and this thread is responsible for that job. + */ + +static int kjournald(void *arg) +{ + journal_t *journal = arg; + transaction_t *transaction; + + /* + * Set up an interval timer which can be used to trigger a commit wakeup + * after the commit interval expires + */ + setup_timer(&journal->j_commit_timer, commit_timeout, + (unsigned long)current); + + /* Record that the journal thread is running */ + journal->j_task = current; + wake_up(&journal->j_wait_done_commit); + + printk(KERN_INFO "kjournald starting. Commit interval %ld seconds\n", + journal->j_commit_interval / HZ); + + /* + * And now, wait forever for commit wakeup events. + */ + spin_lock(&journal->j_state_lock); + +loop: + if (journal->j_flags & JFS_UNMOUNT) + goto end_loop; + + jbd_debug(1, "commit_sequence=%d, commit_request=%d\n", + journal->j_commit_sequence, journal->j_commit_request); + + if (journal->j_commit_sequence != journal->j_commit_request) { + jbd_debug(1, "OK, requests differ\n"); + spin_unlock(&journal->j_state_lock); + del_timer_sync(&journal->j_commit_timer); + journal_commit_transaction(journal); + spin_lock(&journal->j_state_lock); + goto loop; + } + + wake_up(&journal->j_wait_done_commit); + if (freezing(current)) { + /* + * The simpler the better. Flushing journal isn't a + * good idea, because that depends on threads that may + * be already stopped. + */ + jbd_debug(1, "Now suspending kjournald\n"); + spin_unlock(&journal->j_state_lock); + refrigerator(); + spin_lock(&journal->j_state_lock); + } else { + /* + * We assume on resume that commits are already there, + * so we don't sleep + */ + DEFINE_WAIT(wait); + int should_sleep = 1; + + prepare_to_wait(&journal->j_wait_commit, &wait, + TASK_INTERRUPTIBLE); + if (journal->j_commit_sequence != journal->j_commit_request) + should_sleep = 0; + transaction = journal->j_running_transaction; + if (transaction && time_after_eq(jiffies, + transaction->t_expires)) + should_sleep = 0; + if (journal->j_flags & JFS_UNMOUNT) + should_sleep = 0; + if (should_sleep) { + spin_unlock(&journal->j_state_lock); + schedule(); + spin_lock(&journal->j_state_lock); + } + finish_wait(&journal->j_wait_commit, &wait); + } + + jbd_debug(1, "kjournald wakes\n"); + + /* + * Were we woken up by a commit wakeup event? + */ + transaction = journal->j_running_transaction; + if (transaction && time_after_eq(jiffies, transaction->t_expires)) { + journal->j_commit_request = transaction->t_tid; + jbd_debug(1, "woke because of timeout\n"); + } + goto loop; + +end_loop: + spin_unlock(&journal->j_state_lock); + del_timer_sync(&journal->j_commit_timer); + journal->j_task = NULL; + wake_up(&journal->j_wait_done_commit); + jbd_debug(1, "Journal thread exiting.\n"); + return 0; +} + +static void journal_start_thread(journal_t *journal) +{ + kthread_run(kjournald, journal, "kjournald"); + wait_event(journal->j_wait_done_commit, journal->j_task != 0); +} + +static void journal_kill_thread(journal_t *journal) +{ + spin_lock(&journal->j_state_lock); + journal->j_flags |= JFS_UNMOUNT; + + while (journal->j_task) { + wake_up(&journal->j_wait_commit); + spin_unlock(&journal->j_state_lock); + wait_event(journal->j_wait_done_commit, journal->j_task == 0); + spin_lock(&journal->j_state_lock); + } + spin_unlock(&journal->j_state_lock); +} + +/* + * journal_write_metadata_buffer: write a metadata buffer to the journal. + * + * Writes a metadata buffer to a given disk block. The actual IO is not + * performed but a new buffer_head is constructed which labels the data + * to be written with the correct destination disk block. + * + * Any magic-number escaping which needs to be done will cause a + * copy-out here. If the buffer happens to start with the + * JFS_MAGIC_NUMBER, then we can't write it to the log directly: the + * magic number is only written to the log for descripter blocks. In + * this case, we copy the data and replace the first word with 0, and we + * return a result code which indicates that this buffer needs to be + * marked as an escaped buffer in the corresponding log descriptor + * block. The missing word can then be restored when the block is read + * during recovery. + * + * If the source buffer has already been modified by a new transaction + * since we took the last commit snapshot, we use the frozen copy of + * that data for IO. If we end up using the existing buffer_head's data + * for the write, then we *have* to lock the buffer to prevent anyone + * else from using and possibly modifying it while the IO is in + * progress. + * + * The function returns a pointer to the buffer_heads to be used for IO. + * + * We assume that the journal has already been locked in this function. + * + * Return value: + * <0: Error + * >=0: Finished OK + * + * On success: + * Bit 0 set == escape performed on the data + * Bit 1 set == buffer copy-out performed (kfree the data after IO) + */ + +int journal_write_metadata_buffer(transaction_t *transaction, + struct journal_head *jh_in, + struct journal_head **jh_out, + unsigned long blocknr) +{ + int need_copy_out = 0; + int done_copy_out = 0; + int do_escape = 0; + char *mapped_data; + struct buffer_head *new_bh; + struct journal_head *new_jh; + struct page *new_page; + unsigned int new_offset; + struct buffer_head *bh_in = jh2bh(jh_in); + + /* + * The buffer really shouldn't be locked: only the current committing + * transaction is allowed to write it, so nobody else is allowed + * to do any IO. + * + * akpm: except if we're journalling data, and write() output is + * also part of a shared mapping, and another thread has + * decided to launch a writepage() against this buffer. + */ + J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in)); + + new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); + + /* + * If a new transaction has already done a buffer copy-out, then + * we use that version of the data for the commit. + */ + jbd_lock_bh_state(bh_in); +repeat: + if (jh_in->b_frozen_data) { + done_copy_out = 1; + new_page = virt_to_page(jh_in->b_frozen_data); + new_offset = offset_in_page(jh_in->b_frozen_data); + } else { + new_page = jh2bh(jh_in)->b_page; + new_offset = offset_in_page(jh2bh(jh_in)->b_data); + } + + mapped_data = kmap_atomic(new_page, KM_USER0); + /* + * Check for escaping + */ + if (*((__be32 *)(mapped_data + new_offset)) == + cpu_to_be32(JFS_MAGIC_NUMBER)) { + need_copy_out = 1; + do_escape = 1; + } + kunmap_atomic(mapped_data, KM_USER0); + + /* + * Do we need to do a data copy? + */ + if (need_copy_out && !done_copy_out) { + char *tmp; + + jbd_unlock_bh_state(bh_in); + tmp = jbd_slab_alloc(bh_in->b_size, GFP_NOFS); + jbd_lock_bh_state(bh_in); + if (jh_in->b_frozen_data) { + jbd_slab_free(tmp, bh_in->b_size); + goto repeat; + } + + jh_in->b_frozen_data = tmp; + mapped_data = kmap_atomic(new_page, KM_USER0); + memcpy(tmp, mapped_data + new_offset, jh2bh(jh_in)->b_size); + kunmap_atomic(mapped_data, KM_USER0); + + new_page = virt_to_page(tmp); + new_offset = offset_in_page(tmp); + done_copy_out = 1; + } + + /* + * Did we need to do an escaping? Now we've done all the + * copying, we can finally do so. + */ + if (do_escape) { + mapped_data = kmap_atomic(new_page, KM_USER0); + *((unsigned int *)(mapped_data + new_offset)) = 0; + kunmap_atomic(mapped_data, KM_USER0); + } + + /* keep subsequent assertions sane */ + new_bh->b_state = 0; + init_buffer(new_bh, NULL, NULL); + atomic_set(&new_bh->b_count, 1); + jbd_unlock_bh_state(bh_in); + + new_jh = journal_add_journal_head(new_bh); /* This sleeps */ + + set_bh_page(new_bh, new_page, new_offset); + new_jh->b_transaction = NULL; + new_bh->b_size = jh2bh(jh_in)->b_size; + new_bh->b_bdev = transaction->t_journal->j_dev; + new_bh->b_blocknr = blocknr; + set_buffer_mapped(new_bh); + set_buffer_dirty(new_bh); + + *jh_out = new_jh; + + /* + * The to-be-written buffer needs to get moved to the io queue, + * and the original buffer whose contents we are shadowing or + * copying is moved to the transaction's shadow queue. + */ + JBUFFER_TRACE(jh_in, "file as BJ_Shadow"); + journal_file_buffer(jh_in, transaction, BJ_Shadow); + JBUFFER_TRACE(new_jh, "file as BJ_IO"); + journal_file_buffer(new_jh, transaction, BJ_IO); + + return do_escape | (done_copy_out << 1); +} + +/* + * Allocation code for the journal file. Manage the space left in the + * journal, so that we can begin checkpointing when appropriate. + */ + +/* + * __log_space_left: Return the number of free blocks left in the journal. + * + * Called with the journal already locked. + * + * Called under j_state_lock + */ + +int __log_space_left(journal_t *journal) +{ + int left = journal->j_free; + + assert_spin_locked(&journal->j_state_lock); + + /* + * Be pessimistic here about the number of those free blocks which + * might be required for log descriptor control blocks. + */ + +#define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */ + + left -= MIN_LOG_RESERVED_BLOCKS; + + if (left <= 0) + return 0; + left -= (left >> 3); + return left; +} + +/* + * Called under j_state_lock. Returns true if a transaction was started. + */ +int __log_start_commit(journal_t *journal, tid_t target) +{ + /* + * Are we already doing a recent enough commit? + */ + if (!tid_geq(journal->j_commit_request, target)) { + /* + * We want a new commit: OK, mark the request and wakup the + * commit thread. We do _not_ do the commit ourselves. + */ + + journal->j_commit_request = target; + jbd_debug(1, "JBD: requesting commit %d/%d\n", + journal->j_commit_request, + journal->j_commit_sequence); + wake_up(&journal->j_wait_commit); + return 1; + } + return 0; +} + +int log_start_commit(journal_t *journal, tid_t tid) +{ + int ret; + + spin_lock(&journal->j_state_lock); + ret = __log_start_commit(journal, tid); + spin_unlock(&journal->j_state_lock); + return ret; +} + +/* + * Force and wait upon a commit if the calling process is not within + * transaction. This is used for forcing out undo-protected data which contains + * bitmaps, when the fs is running out of space. + * + * We can only force the running transaction if we don't have an active handle; + * otherwise, we will deadlock. + * + * Returns true if a transaction was started. + */ +int journal_force_commit_nested(journal_t *journal) +{ + transaction_t *transaction = NULL; + tid_t tid; + + spin_lock(&journal->j_state_lock); + if (journal->j_running_transaction && !current->journal_info) { + transaction = journal->j_running_transaction; + __log_start_commit(journal, transaction->t_tid); + } else if (journal->j_committing_transaction) + transaction = journal->j_committing_transaction; + + if (!transaction) { + spin_unlock(&journal->j_state_lock); + return 0; /* Nothing to retry */ + } + + tid = transaction->t_tid; + spin_unlock(&journal->j_state_lock); + log_wait_commit(journal, tid); + return 1; +} + +/* + * Start a commit of the current running transaction (if any). Returns true + * if a transaction was started, and fills its tid in at *ptid + */ +int journal_start_commit(journal_t *journal, tid_t *ptid) +{ + int ret = 0; + + spin_lock(&journal->j_state_lock); + if (journal->j_running_transaction) { + tid_t tid = journal->j_running_transaction->t_tid; + + ret = __log_start_commit(journal, tid); + if (ret && ptid) + *ptid = tid; + } else if (journal->j_committing_transaction && ptid) { + /* + * If ext3_write_super() recently started a commit, then we + * have to wait for completion of that transaction + */ + *ptid = journal->j_committing_transaction->t_tid; + ret = 1; + } + spin_unlock(&journal->j_state_lock); + return ret; +} + +/* + * Wait for a specified commit to complete. + * The caller may not hold the journal lock. + */ +int log_wait_commit(journal_t *journal, tid_t tid) +{ + int err = 0; + +#ifdef CONFIG_JBD_DEBUG + spin_lock(&journal->j_state_lock); + if (!tid_geq(journal->j_commit_request, tid)) { + printk(KERN_EMERG + "%s: error: j_commit_request=%d, tid=%d\n", + __FUNCTION__, journal->j_commit_request, tid); + } + spin_unlock(&journal->j_state_lock); +#endif + spin_lock(&journal->j_state_lock); + while (tid_gt(tid, journal->j_commit_sequence)) { + jbd_debug(1, "JBD: want %d, j_commit_sequence=%d\n", + tid, journal->j_commit_sequence); + wake_up(&journal->j_wait_commit); + spin_unlock(&journal->j_state_lock); + wait_event(journal->j_wait_done_commit, + !tid_gt(tid, journal->j_commit_sequence)); + spin_lock(&journal->j_state_lock); + } + spin_unlock(&journal->j_state_lock); + + if (unlikely(is_journal_aborted(journal))) { + printk(KERN_EMERG "journal commit I/O error\n"); + err = -EIO; + } + return err; +} + +/* + * Log buffer allocation routines: + */ + +int journal_next_log_block(journal_t *journal, unsigned long *retp) +{ + unsigned long blocknr; + + spin_lock(&journal->j_state_lock); + J_ASSERT(journal->j_free > 1); + + blocknr = journal->j_head; + journal->j_head++; + journal->j_free--; + if (journal->j_head == journal->j_last) + journal->j_head = journal->j_first; + spin_unlock(&journal->j_state_lock); + return journal_bmap(journal, blocknr, retp); +} + +/* + * Conversion of logical to physical block numbers for the journal + * + * On external journals the journal blocks are identity-mapped, so + * this is a no-op. If needed, we can use j_blk_offset - everything is + * ready. + */ +int journal_bmap(journal_t *journal, unsigned long blocknr, + unsigned long *retp) +{ + int err = 0; + unsigned long ret; + + if (journal->j_inode) { + ret = bmap(journal->j_inode, blocknr); + if (ret) + *retp = ret; + else { + char b[BDEVNAME_SIZE]; + + printk(KERN_ALERT "%s: journal block not found " + "at offset %lu on %s\n", + __FUNCTION__, + blocknr, + bdevname(journal->j_dev, b)); + err = -EIO; + __journal_abort_soft(journal, err); + } + } else { + *retp = blocknr; /* +journal->j_blk_offset */ + } + return err; +} + +/* + * We play buffer_head aliasing tricks to write data/metadata blocks to + * the journal without copying their contents, but for journal + * descriptor blocks we do need to generate bona fide buffers. + * + * After the caller of journal_get_descriptor_buffer() has finished modifying + * the buffer's contents they really should run flush_dcache_page(bh->b_page). + * But we don't bother doing that, so there will be coherency problems with + * mmaps of blockdevs which hold live JBD-controlled filesystems. + */ +struct journal_head *journal_get_descriptor_buffer(journal_t *journal) +{ + struct buffer_head *bh; + unsigned long blocknr; + int err; + + err = journal_next_log_block(journal, &blocknr); + + if (err) + return NULL; + + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); + lock_buffer(bh); + memset(bh->b_data, 0, journal->j_blocksize); + set_buffer_uptodate(bh); + unlock_buffer(bh); + BUFFER_TRACE(bh, "return this buffer"); + return journal_add_journal_head(bh); +} + +/* + * Management for journal control blocks: functions to create and + * destroy journal_t structures, and to initialise and read existing + * journal blocks from disk. */ + +/* First: create and setup a journal_t object in memory. We initialise + * very few fields yet: that has to wait until we have created the + * journal structures from from scratch, or loaded them from disk. */ + +static journal_t * journal_init_common (void) +{ + journal_t *journal; + int err; + + journal = jbd_kmalloc(sizeof(*journal), GFP_KERNEL); + if (!journal) + goto fail; + memset(journal, 0, sizeof(*journal)); + + init_waitqueue_head(&journal->j_wait_transaction_locked); + init_waitqueue_head(&journal->j_wait_logspace); + init_waitqueue_head(&journal->j_wait_done_commit); + init_waitqueue_head(&journal->j_wait_checkpoint); + init_waitqueue_head(&journal->j_wait_commit); + init_waitqueue_head(&journal->j_wait_updates); + mutex_init(&journal->j_barrier); + mutex_init(&journal->j_checkpoint_mutex); + spin_lock_init(&journal->j_revoke_lock); + spin_lock_init(&journal->j_list_lock); + spin_lock_init(&journal->j_state_lock); + + journal->j_commit_interval = (HZ * JBD_DEFAULT_MAX_COMMIT_AGE); + + /* The journal is marked for error until we succeed with recovery! */ + journal->j_flags = JFS_ABORT; + + /* Set up a default-sized revoke table for the new mount. */ + err = journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH); + if (err) { + kfree(journal); + goto fail; + } + return journal; +fail: + return NULL; +} + +/* journal_init_dev and journal_init_inode: + * + * Create a journal structure assigned some fixed set of disk blocks to + * the journal. We don't actually touch those disk blocks yet, but we + * need to set up all of the mapping information to tell the journaling + * system where the journal blocks are. + * + */ + +/** + * journal_t * journal_init_dev() - creates an initialises a journal structure + * @bdev: Block device on which to create the journal + * @fs_dev: Device which hold journalled filesystem for this journal. + * @start: Block nr Start of journal. + * @len: Length of the journal in blocks. + * @blocksize: blocksize of journalling device + * @returns: a newly created journal_t * + * + * journal_init_dev creates a journal which maps a fixed contiguous + * range of blocks on an arbitrary block device. + * + */ +journal_t * journal_init_dev(struct block_device *bdev, + struct block_device *fs_dev, + int start, int len, int blocksize) +{ + journal_t *journal = journal_init_common(); + struct buffer_head *bh; + int n; + + if (!journal) + return NULL; + + /* journal descriptor can store up to n blocks -bzzz */ + journal->j_blocksize = blocksize; + n = journal->j_blocksize / sizeof(journal_block_tag_t); + journal->j_wbufsize = n; + journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL); + if (!journal->j_wbuf) { + printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n", + __FUNCTION__); + kfree(journal); + journal = NULL; + } + journal->j_dev = bdev; + journal->j_fs_dev = fs_dev; + journal->j_blk_offset = start; + journal->j_maxlen = len; + + bh = __getblk(journal->j_dev, start, journal->j_blocksize); + J_ASSERT(bh != NULL); + journal->j_sb_buffer = bh; + journal->j_superblock = (journal_superblock_t *)bh->b_data; + + return journal; +} + +/** + * journal_t * journal_init_inode () - creates a journal which maps to a inode. + * @inode: An inode to create the journal in + * + * journal_init_inode creates a journal which maps an on-disk inode as + * the journal. The inode must exist already, must support bmap() and + * must have all data blocks preallocated. + */ +journal_t * journal_init_inode (struct inode *inode) +{ + struct buffer_head *bh; + journal_t *journal = journal_init_common(); + int err; + int n; + unsigned long blocknr; + + if (!journal) + return NULL; + + journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev; + journal->j_inode = inode; + jbd_debug(1, + "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n", + journal, inode->i_sb->s_id, inode->i_ino, + (long long) inode->i_size, + inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize); + + journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits; + journal->j_blocksize = inode->i_sb->s_blocksize; + + /* journal descriptor can store up to n blocks -bzzz */ + n = journal->j_blocksize / sizeof(journal_block_tag_t); + journal->j_wbufsize = n; + journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL); + if (!journal->j_wbuf) { + printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n", + __FUNCTION__); + kfree(journal); + return NULL; + } + + err = journal_bmap(journal, 0, &blocknr); + /* If that failed, give up */ + if (err) { + printk(KERN_ERR "%s: Cannnot locate journal superblock\n", + __FUNCTION__); + kfree(journal); + return NULL; + } + + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); + J_ASSERT(bh != NULL); + journal->j_sb_buffer = bh; + journal->j_superblock = (journal_superblock_t *)bh->b_data; + + return journal; +} + +/* + * If the journal init or create aborts, we need to mark the journal + * superblock as being NULL to prevent the journal destroy from writing + * back a bogus superblock. + */ +static void journal_fail_superblock (journal_t *journal) +{ + struct buffer_head *bh = journal->j_sb_buffer; + brelse(bh); + journal->j_sb_buffer = NULL; +} + +/* + * Given a journal_t structure, initialise the various fields for + * startup of a new journaling session. We use this both when creating + * a journal, and after recovering an old journal to reset it for + * subsequent use. + */ + +static int journal_reset(journal_t *journal) +{ + journal_superblock_t *sb = journal->j_superblock; + unsigned long first, last; + + first = be32_to_cpu(sb->s_first); + last = be32_to_cpu(sb->s_maxlen); + + journal->j_first = first; + journal->j_last = last; + + journal->j_head = first; + journal->j_tail = first; + journal->j_free = last - first; + + journal->j_tail_sequence = journal->j_transaction_sequence; + journal->j_commit_sequence = journal->j_transaction_sequence - 1; + journal->j_commit_request = journal->j_commit_sequence; + + journal->j_max_transaction_buffers = journal->j_maxlen / 4; + + /* Add the dynamic fields and write it to disk. */ + journal_update_superblock(journal, 1); + journal_start_thread(journal); + return 0; +} + +/** + * int journal_create() - Initialise the new journal file + * @journal: Journal to create. This structure must have been initialised + * + * Given a journal_t structure which tells us which disk blocks we can + * use, create a new journal superblock and initialise all of the + * journal fields from scratch. + **/ +int journal_create(journal_t *journal) +{ + unsigned long blocknr; + struct buffer_head *bh; + journal_superblock_t *sb; + int i, err; + + if (journal->j_maxlen < JFS_MIN_JOURNAL_BLOCKS) { + printk (KERN_ERR "Journal length (%d blocks) too short.\n", + journal->j_maxlen); + journal_fail_superblock(journal); + return -EINVAL; + } + + if (journal->j_inode == NULL) { + /* + * We don't know what block to start at! + */ + printk(KERN_EMERG + "%s: creation of journal on external device!\n", + __FUNCTION__); + BUG(); + } + + /* Zero out the entire journal on disk. We cannot afford to + have any blocks on disk beginning with JFS_MAGIC_NUMBER. */ + jbd_debug(1, "JBD: Zeroing out journal blocks...\n"); + for (i = 0; i < journal->j_maxlen; i++) { + err = journal_bmap(journal, i, &blocknr); + if (err) + return err; + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); + lock_buffer(bh); + memset (bh->b_data, 0, journal->j_blocksize); + BUFFER_TRACE(bh, "marking dirty"); + mark_buffer_dirty(bh); + BUFFER_TRACE(bh, "marking uptodate"); + set_buffer_uptodate(bh); + unlock_buffer(bh); + __brelse(bh); + } + + sync_blockdev(journal->j_dev); + jbd_debug(1, "JBD: journal cleared.\n"); + + /* OK, fill in the initial static fields in the new superblock */ + sb = journal->j_superblock; + + sb->s_header.h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); + sb->s_header.h_blocktype = cpu_to_be32(JFS_SUPERBLOCK_V2); + + sb->s_blocksize = cpu_to_be32(journal->j_blocksize); + sb->s_maxlen = cpu_to_be32(journal->j_maxlen); + sb->s_first = cpu_to_be32(1); + + journal->j_transaction_sequence = 1; + + journal->j_flags &= ~JFS_ABORT; + journal->j_format_version = 2; + + return journal_reset(journal); +} + +/** + * void journal_update_superblock() - Update journal sb on disk. + * @journal: The journal to update. + * @wait: Set to '0' if you don't want to wait for IO completion. + * + * Update a journal's dynamic superblock fields and write it to disk, + * optionally waiting for the IO to complete. + */ +void journal_update_superblock(journal_t *journal, int wait) +{ + journal_superblock_t *sb = journal->j_superblock; + struct buffer_head *bh = journal->j_sb_buffer; + + /* + * As a special case, if the on-disk copy is already marked as needing + * no recovery (s_start == 0) and there are no outstanding transactions + * in the filesystem, then we can safely defer the superblock update + * until the next commit by setting JFS_FLUSHED. This avoids + * attempting a write to a potential-readonly device. + */ + if (sb->s_start == 0 && journal->j_tail_sequence == + journal->j_transaction_sequence) { + jbd_debug(1,"JBD: Skipping superblock update on recovered sb " + "(start %ld, seq %d, errno %d)\n", + journal->j_tail, journal->j_tail_sequence, + journal->j_errno); + goto out; + } + + spin_lock(&journal->j_state_lock); + jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n", + journal->j_tail, journal->j_tail_sequence, journal->j_errno); + + sb->s_sequence = cpu_to_be32(journal->j_tail_sequence); + sb->s_start = cpu_to_be32(journal->j_tail); + sb->s_errno = cpu_to_be32(journal->j_errno); + spin_unlock(&journal->j_state_lock); + + BUFFER_TRACE(bh, "marking dirty"); + mark_buffer_dirty(bh); + if (wait) + sync_dirty_buffer(bh); + else + ll_rw_block(SWRITE, 1, &bh); + +out: + /* If we have just flushed the log (by marking s_start==0), then + * any future commit will have to be careful to update the + * superblock again to re-record the true start of the log. */ + + spin_lock(&journal->j_state_lock); + if (sb->s_start) + journal->j_flags &= ~JFS_FLUSHED; + else + journal->j_flags |= JFS_FLUSHED; + spin_unlock(&journal->j_state_lock); +} + +/* + * Read the superblock for a given journal, performing initial + * validation of the format. + */ + +static int journal_get_superblock(journal_t *journal) +{ + struct buffer_head *bh; + journal_superblock_t *sb; + int err = -EIO; + + bh = journal->j_sb_buffer; + + J_ASSERT(bh != NULL); + if (!buffer_uptodate(bh)) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { + printk (KERN_ERR + "JBD: IO error reading journal superblock\n"); + goto out; + } + } + + sb = journal->j_superblock; + + err = -EINVAL; + + if (sb->s_header.h_magic != cpu_to_be32(JFS_MAGIC_NUMBER) || + sb->s_blocksize != cpu_to_be32(journal->j_blocksize)) { + printk(KERN_WARNING "JBD: no valid journal superblock found\n"); + goto out; + } + + switch(be32_to_cpu(sb->s_header.h_blocktype)) { + case JFS_SUPERBLOCK_V1: + journal->j_format_version = 1; + break; + case JFS_SUPERBLOCK_V2: + journal->j_format_version = 2; + break; + default: + printk(KERN_WARNING "JBD: unrecognised superblock format ID\n"); + goto out; + } + + if (be32_to_cpu(sb->s_maxlen) < journal->j_maxlen) + journal->j_maxlen = be32_to_cpu(sb->s_maxlen); + else if (be32_to_cpu(sb->s_maxlen) > journal->j_maxlen) { + printk (KERN_WARNING "JBD: journal file too short\n"); + goto out; + } + + return 0; + +out: + journal_fail_superblock(journal); + return err; +} + +/* + * Load the on-disk journal superblock and read the key fields into the + * journal_t. + */ + +static int load_superblock(journal_t *journal) +{ + int err; + journal_superblock_t *sb; + + err = journal_get_superblock(journal); + if (err) + return err; + + sb = journal->j_superblock; + + journal->j_tail_sequence = be32_to_cpu(sb->s_sequence); + journal->j_tail = be32_to_cpu(sb->s_start); + journal->j_first = be32_to_cpu(sb->s_first); + journal->j_last = be32_to_cpu(sb->s_maxlen); + journal->j_errno = be32_to_cpu(sb->s_errno); + + return 0; +} + + +/** + * int journal_load() - Read journal from disk. + * @journal: Journal to act on. + * + * Given a journal_t structure which tells us which disk blocks contain + * a journal, read the journal from disk to initialise the in-memory + * structures. + */ +int journal_load(journal_t *journal) +{ + int err; + journal_superblock_t *sb; + + err = load_superblock(journal); + if (err) + return err; + + sb = journal->j_superblock; + /* If this is a V2 superblock, then we have to check the + * features flags on it. */ + + if (journal->j_format_version >= 2) { + if ((sb->s_feature_ro_compat & + ~cpu_to_be32(JFS_KNOWN_ROCOMPAT_FEATURES)) || + (sb->s_feature_incompat & + ~cpu_to_be32(JFS_KNOWN_INCOMPAT_FEATURES))) { + printk (KERN_WARNING + "JBD: Unrecognised features on journal\n"); + return -EINVAL; + } + } + + /* + * Create a slab for this blocksize + */ + err = journal_create_jbd_slab(be32_to_cpu(sb->s_blocksize)); + if (err) + return err; + + /* Let the recovery code check whether it needs to recover any + * data from the journal. */ + if (journal_recover(journal)) + goto recovery_error; + + /* OK, we've finished with the dynamic journal bits: + * reinitialise the dynamic contents of the superblock in memory + * and reset them on disk. */ + if (journal_reset(journal)) + goto recovery_error; + + journal->j_flags &= ~JFS_ABORT; + journal->j_flags |= JFS_LOADED; + return 0; + +recovery_error: + printk (KERN_WARNING "JBD: recovery failed\n"); + return -EIO; +} + +/** + * void journal_destroy() - Release a journal_t structure. + * @journal: Journal to act on. + * + * Release a journal_t structure once it is no longer in use by the + * journaled object. + */ +void journal_destroy(journal_t *journal) +{ + /* Wait for the commit thread to wake up and die. */ + journal_kill_thread(journal); + + /* Force a final log commit */ + if (journal->j_running_transaction) + journal_commit_transaction(journal); + + /* Force any old transactions to disk */ + + /* Totally anal locking here... */ + spin_lock(&journal->j_list_lock); + while (journal->j_checkpoint_transactions != NULL) { + spin_unlock(&journal->j_list_lock); + log_do_checkpoint(journal); + spin_lock(&journal->j_list_lock); + } + + J_ASSERT(journal->j_running_transaction == NULL); + J_ASSERT(journal->j_committing_transaction == NULL); + J_ASSERT(journal->j_checkpoint_transactions == NULL); + spin_unlock(&journal->j_list_lock); + + /* We can now mark the journal as empty. */ + journal->j_tail = 0; + journal->j_tail_sequence = ++journal->j_transaction_sequence; + if (journal->j_sb_buffer) { + journal_update_superblock(journal, 1); + brelse(journal->j_sb_buffer); + } + + if (journal->j_inode) + iput(journal->j_inode); + if (journal->j_revoke) + journal_destroy_revoke(journal); + kfree(journal->j_wbuf); + kfree(journal); +} + + +/** + *int journal_check_used_features () - Check if features specified are used. + * @journal: Journal to check. + * @compat: bitmask of compatible features + * @ro: bitmask of features that force read-only mount + * @incompat: bitmask of incompatible features + * + * Check whether the journal uses all of a given set of + * features. Return true (non-zero) if it does. + **/ + +int journal_check_used_features (journal_t *journal, unsigned long compat, + unsigned long ro, unsigned long incompat) +{ + journal_superblock_t *sb; + + if (!compat && !ro && !incompat) + return 1; + if (journal->j_format_version == 1) + return 0; + + sb = journal->j_superblock; + + if (((be32_to_cpu(sb->s_feature_compat) & compat) == compat) && + ((be32_to_cpu(sb->s_feature_ro_compat) & ro) == ro) && + ((be32_to_cpu(sb->s_feature_incompat) & incompat) == incompat)) + return 1; + + return 0; +} + +/** + * int journal_check_available_features() - Check feature set in journalling layer + * @journal: Journal to check. + * @compat: bitmask of compatible features + * @ro: bitmask of features that force read-only mount + * @incompat: bitmask of incompatible features + * + * Check whether the journaling code supports the use of + * all of a given set of features on this journal. Return true + * (non-zero) if it can. */ + +int journal_check_available_features (journal_t *journal, unsigned long compat, + unsigned long ro, unsigned long incompat) +{ + journal_superblock_t *sb; + + if (!compat && !ro && !incompat) + return 1; + + sb = journal->j_superblock; + + /* We can support any known requested features iff the + * superblock is in version 2. Otherwise we fail to support any + * extended sb features. */ + + if (journal->j_format_version != 2) + return 0; + + if ((compat & JFS_KNOWN_COMPAT_FEATURES) == compat && + (ro & JFS_KNOWN_ROCOMPAT_FEATURES) == ro && + (incompat & JFS_KNOWN_INCOMPAT_FEATURES) == incompat) + return 1; + + return 0; +} + +/** + * int journal_set_features () - Mark a given journal feature in the superblock + * @journal: Journal to act on. + * @compat: bitmask of compatible features + * @ro: bitmask of features that force read-only mount + * @incompat: bitmask of incompatible features + * + * Mark a given journal feature as present on the + * superblock. Returns true if the requested features could be set. + * + */ + +int journal_set_features (journal_t *journal, unsigned long compat, + unsigned long ro, unsigned long incompat) +{ + journal_superblock_t *sb; + + if (journal_check_used_features(journal, compat, ro, incompat)) + return 1; + + if (!journal_check_available_features(journal, compat, ro, incompat)) + return 0; + + jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n", + compat, ro, incompat); + + sb = journal->j_superblock; + + sb->s_feature_compat |= cpu_to_be32(compat); + sb->s_feature_ro_compat |= cpu_to_be32(ro); + sb->s_feature_incompat |= cpu_to_be32(incompat); + + return 1; +} + + +/** + * int journal_update_format () - Update on-disk journal structure. + * @journal: Journal to act on. + * + * Given an initialised but unloaded journal struct, poke about in the + * on-disk structure to update it to the most recent supported version. + */ +int journal_update_format (journal_t *journal) +{ + journal_superblock_t *sb; + int err; + + err = journal_get_superblock(journal); + if (err) + return err; + + sb = journal->j_superblock; + + switch (be32_to_cpu(sb->s_header.h_blocktype)) { + case JFS_SUPERBLOCK_V2: + return 0; + case JFS_SUPERBLOCK_V1: + return journal_convert_superblock_v1(journal, sb); + default: + break; + } + return -EINVAL; +} + +static int journal_convert_superblock_v1(journal_t *journal, + journal_superblock_t *sb) +{ + int offset, blocksize; + struct buffer_head *bh; + + printk(KERN_WARNING + "JBD: Converting superblock from version 1 to 2.\n"); + + /* Pre-initialise new fields to zero */ + offset = ((char *) &(sb->s_feature_compat)) - ((char *) sb); + blocksize = be32_to_cpu(sb->s_blocksize); + memset(&sb->s_feature_compat, 0, blocksize-offset); + + sb->s_nr_users = cpu_to_be32(1); + sb->s_header.h_blocktype = cpu_to_be32(JFS_SUPERBLOCK_V2); + journal->j_format_version = 2; + + bh = journal->j_sb_buffer; + BUFFER_TRACE(bh, "marking dirty"); + mark_buffer_dirty(bh); + sync_dirty_buffer(bh); + return 0; +} + + +/** + * int journal_flush () - Flush journal + * @journal: Journal to act on. + * + * Flush all data for a given journal to disk and empty the journal. + * Filesystems can use this when remounting readonly to ensure that + * recovery does not need to happen on remount. + */ + +int journal_flush(journal_t *journal) +{ + int err = 0; + transaction_t *transaction = NULL; + unsigned long old_tail; + + spin_lock(&journal->j_state_lock); + + /* Force everything buffered to the log... */ + if (journal->j_running_transaction) { + transaction = journal->j_running_transaction; + __log_start_commit(journal, transaction->t_tid); + } else if (journal->j_committing_transaction) + transaction = journal->j_committing_transaction; + + /* Wait for the log commit to complete... */ + if (transaction) { + tid_t tid = transaction->t_tid; + + spin_unlock(&journal->j_state_lock); + log_wait_commit(journal, tid); + } else { + spin_unlock(&journal->j_state_lock); + } + + /* ...and flush everything in the log out to disk. */ + spin_lock(&journal->j_list_lock); + while (!err && journal->j_checkpoint_transactions != NULL) { + spin_unlock(&journal->j_list_lock); + err = log_do_checkpoint(journal); + spin_lock(&journal->j_list_lock); + } + spin_unlock(&journal->j_list_lock); + cleanup_journal_tail(journal); + + /* Finally, mark the journal as really needing no recovery. + * This sets s_start==0 in the underlying superblock, which is + * the magic code for a fully-recovered superblock. Any future + * commits of data to the journal will restore the current + * s_start value. */ + spin_lock(&journal->j_state_lock); + old_tail = journal->j_tail; + journal->j_tail = 0; + spin_unlock(&journal->j_state_lock); + journal_update_superblock(journal, 1); + spin_lock(&journal->j_state_lock); + journal->j_tail = old_tail; + + J_ASSERT(!journal->j_running_transaction); + J_ASSERT(!journal->j_committing_transaction); + J_ASSERT(!journal->j_checkpoint_transactions); + J_ASSERT(journal->j_head == journal->j_tail); + J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence); + spin_unlock(&journal->j_state_lock); + return err; +} + +/** + * int journal_wipe() - Wipe journal contents + * @journal: Journal to act on. + * @write: flag (see below) + * + * Wipe out all of the contents of a journal, safely. This will produce + * a warning if the journal contains any valid recovery information. + * Must be called between journal_init_*() and journal_load(). + * + * If 'write' is non-zero, then we wipe out the journal on disk; otherwise + * we merely suppress recovery. + */ + +int journal_wipe(journal_t *journal, int write) +{ + journal_superblock_t *sb; + int err = 0; + + J_ASSERT (!(journal->j_flags & JFS_LOADED)); + + err = load_superblock(journal); + if (err) + return err; + + sb = journal->j_superblock; + + if (!journal->j_tail) + goto no_recovery; + + printk (KERN_WARNING "JBD: %s recovery information on journal\n", + write ? "Clearing" : "Ignoring"); + + err = journal_skip_recovery(journal); + if (write) + journal_update_superblock(journal, 1); + + no_recovery: + return err; +} + +/* + * journal_dev_name: format a character string to describe on what + * device this journal is present. + */ + +static const char *journal_dev_name(journal_t *journal, char *buffer) +{ + struct block_device *bdev; + + if (journal->j_inode) + bdev = journal->j_inode->i_sb->s_bdev; + else + bdev = journal->j_dev; + + return bdevname(bdev, buffer); +} + +/* + * Journal abort has very specific semantics, which we describe + * for journal abort. + * + * Two internal function, which provide abort to te jbd layer + * itself are here. + */ + +/* + * Quick version for internal journal use (doesn't lock the journal). + * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, + * and don't attempt to make any other journal updates. + */ +void __journal_abort_hard(journal_t *journal) +{ + transaction_t *transaction; + char b[BDEVNAME_SIZE]; + + if (journal->j_flags & JFS_ABORT) + return; + + printk(KERN_ERR "Aborting journal on device %s.\n", + journal_dev_name(journal, b)); + + spin_lock(&journal->j_state_lock); + journal->j_flags |= JFS_ABORT; + transaction = journal->j_running_transaction; + if (transaction) + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); +} + +/* Soft abort: record the abort error status in the journal superblock, + * but don't do any other IO. */ +static void __journal_abort_soft (journal_t *journal, int errno) +{ + if (journal->j_flags & JFS_ABORT) + return; + + if (!journal->j_errno) + journal->j_errno = errno; + + __journal_abort_hard(journal); + + if (errno) + journal_update_superblock(journal, 1); +} + +/** + * void journal_abort () - Shutdown the journal immediately. + * @journal: the journal to shutdown. + * @errno: an error number to record in the journal indicating + * the reason for the shutdown. + * + * Perform a complete, immediate shutdown of the ENTIRE + * journal (not of a single transaction). This operation cannot be + * undone without closing and reopening the journal. + * + * The journal_abort function is intended to support higher level error + * recovery mechanisms such as the ext2/ext3 remount-readonly error + * mode. + * + * Journal abort has very specific semantics. Any existing dirty, + * unjournaled buffers in the main filesystem will still be written to + * disk by bdflush, but the journaling mechanism will be suspended + * immediately and no further transaction commits will be honoured. + * + * Any dirty, journaled buffers will be written back to disk without + * hitting the journal. Atomicity cannot be guaranteed on an aborted + * filesystem, but we _do_ attempt to leave as much data as possible + * behind for fsck to use for cleanup. + * + * Any attempt to get a new transaction handle on a journal which is in + * ABORT state will just result in an -EROFS error return. A + * journal_stop on an existing handle will return -EIO if we have + * entered abort state during the update. + * + * Recursive transactions are not disturbed by journal abort until the + * final journal_stop, which will receive the -EIO error. + * + * Finally, the journal_abort call allows the caller to supply an errno + * which will be recorded (if possible) in the journal superblock. This + * allows a client to record failure conditions in the middle of a + * transaction without having to complete the transaction to record the + * failure to disk. ext3_error, for example, now uses this + * functionality. + * + * Errors which originate from within the journaling layer will NOT + * supply an errno; a null errno implies that absolutely no further + * writes are done to the journal (unless there are any already in + * progress). + * + */ + +void journal_abort(journal_t *journal, int errno) +{ + __journal_abort_soft(journal, errno); +} + +/** + * int journal_errno () - returns the journal's error state. + * @journal: journal to examine. + * + * This is the errno numbet set with journal_abort(), the last + * time the journal was mounted - if the journal was stopped + * without calling abort this will be 0. + * + * If the journal has been aborted on this mount time -EROFS will + * be returned. + */ +int journal_errno(journal_t *journal) +{ + int err; + + spin_lock(&journal->j_state_lock); + if (journal->j_flags & JFS_ABORT) + err = -EROFS; + else + err = journal->j_errno; + spin_unlock(&journal->j_state_lock); + return err; +} + +/** + * int journal_clear_err () - clears the journal's error state + * @journal: journal to act on. + * + * An error must be cleared or Acked to take a FS out of readonly + * mode. + */ +int journal_clear_err(journal_t *journal) +{ + int err = 0; + + spin_lock(&journal->j_state_lock); + if (journal->j_flags & JFS_ABORT) + err = -EROFS; + else + journal->j_errno = 0; + spin_unlock(&journal->j_state_lock); + return err; +} + +/** + * void journal_ack_err() - Ack journal err. + * @journal: journal to act on. + * + * An error must be cleared or Acked to take a FS out of readonly + * mode. + */ +void journal_ack_err(journal_t *journal) +{ + spin_lock(&journal->j_state_lock); + if (journal->j_errno) + journal->j_flags |= JFS_ACK_ERR; + spin_unlock(&journal->j_state_lock); +} + +int journal_blocks_per_page(struct inode *inode) +{ + return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); +} + +/* + * Simple support for retrying memory allocations. Introduced to help to + * debug different VM deadlock avoidance strategies. + */ +void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry) +{ + return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0)); +} + +/* + * jbd slab management: create 1k, 2k, 4k, 8k slabs as needed + * and allocate frozen and commit buffers from these slabs. + * + * Reason for doing this is to avoid, SLAB_DEBUG - since it could + * cause bh to cross page boundary. + */ + +#define JBD_MAX_SLABS 5 +#define JBD_SLAB_INDEX(size) (size >> 11) + +static kmem_cache_t *jbd_slab[JBD_MAX_SLABS]; +static const char *jbd_slab_names[JBD_MAX_SLABS] = { + "jbd_1k", "jbd_2k", "jbd_4k", NULL, "jbd_8k" +}; + +static void journal_destroy_jbd_slabs(void) +{ + int i; + + for (i = 0; i < JBD_MAX_SLABS; i++) { + if (jbd_slab[i]) + kmem_cache_destroy(jbd_slab[i]); + jbd_slab[i] = NULL; + } +} + +static int journal_create_jbd_slab(size_t slab_size) +{ + int i = JBD_SLAB_INDEX(slab_size); + + BUG_ON(i >= JBD_MAX_SLABS); + + /* + * Check if we already have a slab created for this size + */ + if (jbd_slab[i]) + return 0; + + /* + * Create a slab and force alignment to be same as slabsize - + * this will make sure that allocations won't cross the page + * boundary. + */ + jbd_slab[i] = kmem_cache_create(jbd_slab_names[i], + slab_size, slab_size, 0, NULL, NULL); + if (!jbd_slab[i]) { + printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n"); + return -ENOMEM; + } + return 0; +} + +void * jbd_slab_alloc(size_t size, gfp_t flags) +{ + int idx; + + idx = JBD_SLAB_INDEX(size); + BUG_ON(jbd_slab[idx] == NULL); + return kmem_cache_alloc(jbd_slab[idx], flags | __GFP_NOFAIL); +} + +void jbd_slab_free(void *ptr, size_t size) +{ + int idx; + + idx = JBD_SLAB_INDEX(size); + BUG_ON(jbd_slab[idx] == NULL); + kmem_cache_free(jbd_slab[idx], ptr); +} + +/* + * Journal_head storage management + */ +static kmem_cache_t *journal_head_cache; +#ifdef CONFIG_JBD_DEBUG +static atomic_t nr_journal_heads = ATOMIC_INIT(0); +#endif + +static int journal_init_journal_head_cache(void) +{ + int retval; + + J_ASSERT(journal_head_cache == 0); + journal_head_cache = kmem_cache_create("journal_head", + sizeof(struct journal_head), + 0, /* offset */ + 0, /* flags */ + NULL, /* ctor */ + NULL); /* dtor */ + retval = 0; + if (journal_head_cache == 0) { + retval = -ENOMEM; + printk(KERN_EMERG "JBD: no memory for journal_head cache\n"); + } + return retval; +} + +static void journal_destroy_journal_head_cache(void) +{ + J_ASSERT(journal_head_cache != NULL); + kmem_cache_destroy(journal_head_cache); + journal_head_cache = NULL; +} + +/* + * journal_head splicing and dicing + */ +static struct journal_head *journal_alloc_journal_head(void) +{ + struct journal_head *ret; + static unsigned long last_warning; + +#ifdef CONFIG_JBD_DEBUG + atomic_inc(&nr_journal_heads); +#endif + ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); + if (ret == 0) { + jbd_debug(1, "out of memory for journal_head\n"); + if (time_after(jiffies, last_warning + 5*HZ)) { + printk(KERN_NOTICE "ENOMEM in %s, retrying.\n", + __FUNCTION__); + last_warning = jiffies; + } + while (ret == 0) { + yield(); + ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); + } + } + return ret; +} + +static void journal_free_journal_head(struct journal_head *jh) +{ +#ifdef CONFIG_JBD_DEBUG + atomic_dec(&nr_journal_heads); + memset(jh, JBD_POISON_FREE, sizeof(*jh)); +#endif + kmem_cache_free(journal_head_cache, jh); +} + +/* + * A journal_head is attached to a buffer_head whenever JBD has an + * interest in the buffer. + * + * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit + * is set. This bit is tested in core kernel code where we need to take + * JBD-specific actions. Testing the zeroness of ->b_private is not reliable + * there. + * + * When a buffer has its BH_JBD bit set, its ->b_count is elevated by one. + * + * When a buffer has its BH_JBD bit set it is immune from being released by + * core kernel code, mainly via ->b_count. + * + * A journal_head may be detached from its buffer_head when the journal_head's + * b_transaction, b_cp_transaction and b_next_transaction pointers are NULL. + * Various places in JBD call journal_remove_journal_head() to indicate that the + * journal_head can be dropped if needed. + * + * Various places in the kernel want to attach a journal_head to a buffer_head + * _before_ attaching the journal_head to a transaction. To protect the + * journal_head in this situation, journal_add_journal_head elevates the + * journal_head's b_jcount refcount by one. The caller must call + * journal_put_journal_head() to undo this. + * + * So the typical usage would be: + * + * (Attach a journal_head if needed. Increments b_jcount) + * struct journal_head *jh = journal_add_journal_head(bh); + * ... + * jh->b_transaction = xxx; + * journal_put_journal_head(jh); + * + * Now, the journal_head's b_jcount is zero, but it is safe from being released + * because it has a non-zero b_transaction. + */ + +/* + * Give a buffer_head a journal_head. + * + * Doesn't need the journal lock. + * May sleep. + */ +struct journal_head *journal_add_journal_head(struct buffer_head *bh) +{ + struct journal_head *jh; + struct journal_head *new_jh = NULL; + +repeat: + if (!buffer_jbd(bh)) { + new_jh = journal_alloc_journal_head(); + memset(new_jh, 0, sizeof(*new_jh)); + } + + jbd_lock_bh_journal_head(bh); + if (buffer_jbd(bh)) { + jh = bh2jh(bh); + } else { + J_ASSERT_BH(bh, + (atomic_read(&bh->b_count) > 0) || + (bh->b_page && bh->b_page->mapping)); + + if (!new_jh) { + jbd_unlock_bh_journal_head(bh); + goto repeat; + } + + jh = new_jh; + new_jh = NULL; /* We consumed it */ + set_buffer_jbd(bh); + bh->b_private = jh; + jh->b_bh = bh; + get_bh(bh); + BUFFER_TRACE(bh, "added journal_head"); + } + jh->b_jcount++; + jbd_unlock_bh_journal_head(bh); + if (new_jh) + journal_free_journal_head(new_jh); + return bh->b_private; +} + +/* + * Grab a ref against this buffer_head's journal_head. If it ended up not + * having a journal_head, return NULL + */ +struct journal_head *journal_grab_journal_head(struct buffer_head *bh) +{ + struct journal_head *jh = NULL; + + jbd_lock_bh_journal_head(bh); + if (buffer_jbd(bh)) { + jh = bh2jh(bh); + jh->b_jcount++; + } + jbd_unlock_bh_journal_head(bh); + return jh; +} + +static void __journal_remove_journal_head(struct buffer_head *bh) +{ + struct journal_head *jh = bh2jh(bh); + + J_ASSERT_JH(jh, jh->b_jcount >= 0); + + get_bh(bh); + if (jh->b_jcount == 0) { + if (jh->b_transaction == NULL && + jh->b_next_transaction == NULL && + jh->b_cp_transaction == NULL) { + J_ASSERT_JH(jh, jh->b_jlist == BJ_None); + J_ASSERT_BH(bh, buffer_jbd(bh)); + J_ASSERT_BH(bh, jh2bh(jh) == bh); + BUFFER_TRACE(bh, "remove journal_head"); + if (jh->b_frozen_data) { + printk(KERN_WARNING "%s: freeing " + "b_frozen_data\n", + __FUNCTION__); + jbd_slab_free(jh->b_frozen_data, bh->b_size); + } + if (jh->b_committed_data) { + printk(KERN_WARNING "%s: freeing " + "b_committed_data\n", + __FUNCTION__); + jbd_slab_free(jh->b_committed_data, bh->b_size); + } + bh->b_private = NULL; + jh->b_bh = NULL; /* debug, really */ + clear_buffer_jbd(bh); + __brelse(bh); + journal_free_journal_head(jh); + } else { + BUFFER_TRACE(bh, "journal_head was locked"); + } + } +} + +/* + * journal_remove_journal_head(): if the buffer isn't attached to a transaction + * and has a zero b_jcount then remove and release its journal_head. If we did + * see that the buffer is not used by any transaction we also "logically" + * decrement ->b_count. + * + * We in fact take an additional increment on ->b_count as a convenience, + * because the caller usually wants to do additional things with the bh + * after calling here. + * The caller of journal_remove_journal_head() *must* run __brelse(bh) at some + * time. Once the caller has run __brelse(), the buffer is eligible for + * reaping by try_to_free_buffers(). + */ +void journal_remove_journal_head(struct buffer_head *bh) +{ + jbd_lock_bh_journal_head(bh); + __journal_remove_journal_head(bh); + jbd_unlock_bh_journal_head(bh); +} + +/* + * Drop a reference on the passed journal_head. If it fell to zero then try to + * release the journal_head from the buffer_head. + */ +void journal_put_journal_head(struct journal_head *jh) +{ + struct buffer_head *bh = jh2bh(jh); + + jbd_lock_bh_journal_head(bh); + J_ASSERT_JH(jh, jh->b_jcount > 0); + --jh->b_jcount; + if (!jh->b_jcount && !jh->b_transaction) { + __journal_remove_journal_head(bh); + __brelse(bh); + } + jbd_unlock_bh_journal_head(bh); +} + +/* + * /proc tunables + */ +#if defined(CONFIG_JBD_DEBUG) +int journal_enable_debug; +EXPORT_SYMBOL(journal_enable_debug); +#endif + +#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS) + +static struct proc_dir_entry *proc_jbd_debug; + +static int read_jbd_debug(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int ret; + + ret = sprintf(page + off, "%d\n", journal_enable_debug); + *eof = 1; + return ret; +} + +static int write_jbd_debug(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + char buf[32]; + + if (count > ARRAY_SIZE(buf) - 1) + count = ARRAY_SIZE(buf) - 1; + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + buf[ARRAY_SIZE(buf) - 1] = '\0'; + journal_enable_debug = simple_strtoul(buf, NULL, 10); + return count; +} + +#define JBD_PROC_NAME "sys/fs/jbd-debug" + +static void __init create_jbd_proc_entry(void) +{ + proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL); + if (proc_jbd_debug) { + /* Why is this so hard? */ + proc_jbd_debug->read_proc = read_jbd_debug; + proc_jbd_debug->write_proc = write_jbd_debug; + } +} + +static void __exit remove_jbd_proc_entry(void) +{ + if (proc_jbd_debug) + remove_proc_entry(JBD_PROC_NAME, NULL); +} + +#else + +#define create_jbd_proc_entry() do {} while (0) +#define remove_jbd_proc_entry() do {} while (0) + +#endif + +kmem_cache_t *jbd_handle_cache; + +static int __init journal_init_handle_cache(void) +{ + jbd_handle_cache = kmem_cache_create("journal_handle", + sizeof(handle_t), + 0, /* offset */ + 0, /* flags */ + NULL, /* ctor */ + NULL); /* dtor */ + if (jbd_handle_cache == NULL) { + printk(KERN_EMERG "JBD: failed to create handle cache\n"); + return -ENOMEM; + } + return 0; +} + +static void journal_destroy_handle_cache(void) +{ + if (jbd_handle_cache) + kmem_cache_destroy(jbd_handle_cache); +} + +/* + * Module startup and shutdown + */ + +static int __init journal_init_caches(void) +{ + int ret; + + ret = journal_init_revoke_caches(); + if (ret == 0) + ret = journal_init_journal_head_cache(); + if (ret == 0) + ret = journal_init_handle_cache(); + return ret; +} + +static void journal_destroy_caches(void) +{ + journal_destroy_revoke_caches(); + journal_destroy_journal_head_cache(); + journal_destroy_handle_cache(); + journal_destroy_jbd_slabs(); +} + +static int __init journal_init(void) +{ + int ret; + + BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024); + + ret = journal_init_caches(); + if (ret != 0) + journal_destroy_caches(); + create_jbd_proc_entry(); + return ret; +} + +static void __exit journal_exit(void) +{ +#ifdef CONFIG_JBD_DEBUG + int n = atomic_read(&nr_journal_heads); + if (n) + printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n); +#endif + remove_jbd_proc_entry(); + journal_destroy_caches(); +} + +MODULE_LICENSE("GPL"); +module_init(journal_init); +module_exit(journal_exit); + diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c new file mode 100644 index 000000000000..11563fe2a52b --- /dev/null +++ b/fs/jbd2/recovery.c @@ -0,0 +1,592 @@ +/* + * linux/fs/recovery.c + * + * Written by Stephen C. Tweedie , 1999 + * + * Copyright 1999-2000 Red Hat Software --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Journal recovery routines for the generic filesystem journaling code; + * part of the ext2fs journaling system. + */ + +#ifndef __KERNEL__ +#include "jfs_user.h" +#else +#include +#include +#include +#include +#include +#endif + +/* + * Maintain information about the progress of the recovery job, so that + * the different passes can carry information between them. + */ +struct recovery_info +{ + tid_t start_transaction; + tid_t end_transaction; + + int nr_replays; + int nr_revokes; + int nr_revoke_hits; +}; + +enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY}; +static int do_one_pass(journal_t *journal, + struct recovery_info *info, enum passtype pass); +static int scan_revoke_records(journal_t *, struct buffer_head *, + tid_t, struct recovery_info *); + +#ifdef __KERNEL__ + +/* Release readahead buffers after use */ +static void journal_brelse_array(struct buffer_head *b[], int n) +{ + while (--n >= 0) + brelse (b[n]); +} + + +/* + * When reading from the journal, we are going through the block device + * layer directly and so there is no readahead being done for us. We + * need to implement any readahead ourselves if we want it to happen at + * all. Recovery is basically one long sequential read, so make sure we + * do the IO in reasonably large chunks. + * + * This is not so critical that we need to be enormously clever about + * the readahead size, though. 128K is a purely arbitrary, good-enough + * fixed value. + */ + +#define MAXBUF 8 +static int do_readahead(journal_t *journal, unsigned int start) +{ + int err; + unsigned int max, nbufs, next; + unsigned long blocknr; + struct buffer_head *bh; + + struct buffer_head * bufs[MAXBUF]; + + /* Do up to 128K of readahead */ + max = start + (128 * 1024 / journal->j_blocksize); + if (max > journal->j_maxlen) + max = journal->j_maxlen; + + /* Do the readahead itself. We'll submit MAXBUF buffer_heads at + * a time to the block device IO layer. */ + + nbufs = 0; + + for (next = start; next < max; next++) { + err = journal_bmap(journal, next, &blocknr); + + if (err) { + printk (KERN_ERR "JBD: bad block at offset %u\n", + next); + goto failed; + } + + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); + if (!bh) { + err = -ENOMEM; + goto failed; + } + + if (!buffer_uptodate(bh) && !buffer_locked(bh)) { + bufs[nbufs++] = bh; + if (nbufs == MAXBUF) { + ll_rw_block(READ, nbufs, bufs); + journal_brelse_array(bufs, nbufs); + nbufs = 0; + } + } else + brelse(bh); + } + + if (nbufs) + ll_rw_block(READ, nbufs, bufs); + err = 0; + +failed: + if (nbufs) + journal_brelse_array(bufs, nbufs); + return err; +} + +#endif /* __KERNEL__ */ + + +/* + * Read a block from the journal + */ + +static int jread(struct buffer_head **bhp, journal_t *journal, + unsigned int offset) +{ + int err; + unsigned long blocknr; + struct buffer_head *bh; + + *bhp = NULL; + + if (offset >= journal->j_maxlen) { + printk(KERN_ERR "JBD: corrupted journal superblock\n"); + return -EIO; + } + + err = journal_bmap(journal, offset, &blocknr); + + if (err) { + printk (KERN_ERR "JBD: bad block at offset %u\n", + offset); + return err; + } + + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); + if (!bh) + return -ENOMEM; + + if (!buffer_uptodate(bh)) { + /* If this is a brand new buffer, start readahead. + Otherwise, we assume we are already reading it. */ + if (!buffer_req(bh)) + do_readahead(journal, offset); + wait_on_buffer(bh); + } + + if (!buffer_uptodate(bh)) { + printk (KERN_ERR "JBD: Failed to read block at offset %u\n", + offset); + brelse(bh); + return -EIO; + } + + *bhp = bh; + return 0; +} + + +/* + * Count the number of in-use tags in a journal descriptor block. + */ + +static int count_tags(struct buffer_head *bh, int size) +{ + char * tagp; + journal_block_tag_t * tag; + int nr = 0; + + tagp = &bh->b_data[sizeof(journal_header_t)]; + + while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) { + tag = (journal_block_tag_t *) tagp; + + nr++; + tagp += sizeof(journal_block_tag_t); + if (!(tag->t_flags & cpu_to_be32(JFS_FLAG_SAME_UUID))) + tagp += 16; + + if (tag->t_flags & cpu_to_be32(JFS_FLAG_LAST_TAG)) + break; + } + + return nr; +} + + +/* Make sure we wrap around the log correctly! */ +#define wrap(journal, var) \ +do { \ + if (var >= (journal)->j_last) \ + var -= ((journal)->j_last - (journal)->j_first); \ +} while (0) + +/** + * journal_recover - recovers a on-disk journal + * @journal: the journal to recover + * + * The primary function for recovering the log contents when mounting a + * journaled device. + * + * Recovery is done in three passes. In the first pass, we look for the + * end of the log. In the second, we assemble the list of revoke + * blocks. In the third and final pass, we replay any un-revoked blocks + * in the log. + */ +int journal_recover(journal_t *journal) +{ + int err; + journal_superblock_t * sb; + + struct recovery_info info; + + memset(&info, 0, sizeof(info)); + sb = journal->j_superblock; + + /* + * The journal superblock's s_start field (the current log head) + * is always zero if, and only if, the journal was cleanly + * unmounted. + */ + + if (!sb->s_start) { + jbd_debug(1, "No recovery required, last transaction %d\n", + be32_to_cpu(sb->s_sequence)); + journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1; + return 0; + } + + err = do_one_pass(journal, &info, PASS_SCAN); + if (!err) + err = do_one_pass(journal, &info, PASS_REVOKE); + if (!err) + err = do_one_pass(journal, &info, PASS_REPLAY); + + jbd_debug(0, "JBD: recovery, exit status %d, " + "recovered transactions %u to %u\n", + err, info.start_transaction, info.end_transaction); + jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n", + info.nr_replays, info.nr_revoke_hits, info.nr_revokes); + + /* Restart the log at the next transaction ID, thus invalidating + * any existing commit records in the log. */ + journal->j_transaction_sequence = ++info.end_transaction; + + journal_clear_revoke(journal); + sync_blockdev(journal->j_fs_dev); + return err; +} + +/** + * journal_skip_recovery - Start journal and wipe exiting records + * @journal: journal to startup + * + * Locate any valid recovery information from the journal and set up the + * journal structures in memory to ignore it (presumably because the + * caller has evidence that it is out of date). + * This function does'nt appear to be exorted.. + * + * We perform one pass over the journal to allow us to tell the user how + * much recovery information is being erased, and to let us initialise + * the journal transaction sequence numbers to the next unused ID. + */ +int journal_skip_recovery(journal_t *journal) +{ + int err; + journal_superblock_t * sb; + + struct recovery_info info; + + memset (&info, 0, sizeof(info)); + sb = journal->j_superblock; + + err = do_one_pass(journal, &info, PASS_SCAN); + + if (err) { + printk(KERN_ERR "JBD: error %d scanning journal\n", err); + ++journal->j_transaction_sequence; + } else { +#ifdef CONFIG_JBD_DEBUG + int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence); +#endif + jbd_debug(0, + "JBD: ignoring %d transaction%s from the journal.\n", + dropped, (dropped == 1) ? "" : "s"); + journal->j_transaction_sequence = ++info.end_transaction; + } + + journal->j_tail = 0; + return err; +} + +static int do_one_pass(journal_t *journal, + struct recovery_info *info, enum passtype pass) +{ + unsigned int first_commit_ID, next_commit_ID; + unsigned long next_log_block; + int err, success = 0; + journal_superblock_t * sb; + journal_header_t * tmp; + struct buffer_head * bh; + unsigned int sequence; + int blocktype; + + /* Precompute the maximum metadata descriptors in a descriptor block */ + int MAX_BLOCKS_PER_DESC; + MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t)) + / sizeof(journal_block_tag_t)); + + /* + * First thing is to establish what we expect to find in the log + * (in terms of transaction IDs), and where (in terms of log + * block offsets): query the superblock. + */ + + sb = journal->j_superblock; + next_commit_ID = be32_to_cpu(sb->s_sequence); + next_log_block = be32_to_cpu(sb->s_start); + + first_commit_ID = next_commit_ID; + if (pass == PASS_SCAN) + info->start_transaction = first_commit_ID; + + jbd_debug(1, "Starting recovery pass %d\n", pass); + + /* + * Now we walk through the log, transaction by transaction, + * making sure that each transaction has a commit block in the + * expected place. Each complete transaction gets replayed back + * into the main filesystem. + */ + + while (1) { + int flags; + char * tagp; + journal_block_tag_t * tag; + struct buffer_head * obh; + struct buffer_head * nbh; + + cond_resched(); /* We're under lock_kernel() */ + + /* If we already know where to stop the log traversal, + * check right now that we haven't gone past the end of + * the log. */ + + if (pass != PASS_SCAN) + if (tid_geq(next_commit_ID, info->end_transaction)) + break; + + jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n", + next_commit_ID, next_log_block, journal->j_last); + + /* Skip over each chunk of the transaction looking + * either the next descriptor block or the final commit + * record. */ + + jbd_debug(3, "JBD: checking block %ld\n", next_log_block); + err = jread(&bh, journal, next_log_block); + if (err) + goto failed; + + next_log_block++; + wrap(journal, next_log_block); + + /* What kind of buffer is it? + * + * If it is a descriptor block, check that it has the + * expected sequence number. Otherwise, we're all done + * here. */ + + tmp = (journal_header_t *)bh->b_data; + + if (tmp->h_magic != cpu_to_be32(JFS_MAGIC_NUMBER)) { + brelse(bh); + break; + } + + blocktype = be32_to_cpu(tmp->h_blocktype); + sequence = be32_to_cpu(tmp->h_sequence); + jbd_debug(3, "Found magic %d, sequence %d\n", + blocktype, sequence); + + if (sequence != next_commit_ID) { + brelse(bh); + break; + } + + /* OK, we have a valid descriptor block which matches + * all of the sequence number checks. What are we going + * to do with it? That depends on the pass... */ + + switch(blocktype) { + case JFS_DESCRIPTOR_BLOCK: + /* If it is a valid descriptor block, replay it + * in pass REPLAY; otherwise, just skip over the + * blocks it describes. */ + if (pass != PASS_REPLAY) { + next_log_block += + count_tags(bh, journal->j_blocksize); + wrap(journal, next_log_block); + brelse(bh); + continue; + } + + /* A descriptor block: we can now write all of + * the data blocks. Yay, useful work is finally + * getting done here! */ + + tagp = &bh->b_data[sizeof(journal_header_t)]; + while ((tagp - bh->b_data +sizeof(journal_block_tag_t)) + <= journal->j_blocksize) { + unsigned long io_block; + + tag = (journal_block_tag_t *) tagp; + flags = be32_to_cpu(tag->t_flags); + + io_block = next_log_block++; + wrap(journal, next_log_block); + err = jread(&obh, journal, io_block); + if (err) { + /* Recover what we can, but + * report failure at the end. */ + success = err; + printk (KERN_ERR + "JBD: IO error %d recovering " + "block %ld in log\n", + err, io_block); + } else { + unsigned long blocknr; + + J_ASSERT(obh != NULL); + blocknr = be32_to_cpu(tag->t_blocknr); + + /* If the block has been + * revoked, then we're all done + * here. */ + if (journal_test_revoke + (journal, blocknr, + next_commit_ID)) { + brelse(obh); + ++info->nr_revoke_hits; + goto skip_write; + } + + /* Find a buffer for the new + * data being restored */ + nbh = __getblk(journal->j_fs_dev, + blocknr, + journal->j_blocksize); + if (nbh == NULL) { + printk(KERN_ERR + "JBD: Out of memory " + "during recovery.\n"); + err = -ENOMEM; + brelse(bh); + brelse(obh); + goto failed; + } + + lock_buffer(nbh); + memcpy(nbh->b_data, obh->b_data, + journal->j_blocksize); + if (flags & JFS_FLAG_ESCAPE) { + *((__be32 *)bh->b_data) = + cpu_to_be32(JFS_MAGIC_NUMBER); + } + + BUFFER_TRACE(nbh, "marking dirty"); + set_buffer_uptodate(nbh); + mark_buffer_dirty(nbh); + BUFFER_TRACE(nbh, "marking uptodate"); + ++info->nr_replays; + /* ll_rw_block(WRITE, 1, &nbh); */ + unlock_buffer(nbh); + brelse(obh); + brelse(nbh); + } + + skip_write: + tagp += sizeof(journal_block_tag_t); + if (!(flags & JFS_FLAG_SAME_UUID)) + tagp += 16; + + if (flags & JFS_FLAG_LAST_TAG) + break; + } + + brelse(bh); + continue; + + case JFS_COMMIT_BLOCK: + /* Found an expected commit block: not much to + * do other than move on to the next sequence + * number. */ + brelse(bh); + next_commit_ID++; + continue; + + case JFS_REVOKE_BLOCK: + /* If we aren't in the REVOKE pass, then we can + * just skip over this block. */ + if (pass != PASS_REVOKE) { + brelse(bh); + continue; + } + + err = scan_revoke_records(journal, bh, + next_commit_ID, info); + brelse(bh); + if (err) + goto failed; + continue; + + default: + jbd_debug(3, "Unrecognised magic %d, end of scan.\n", + blocktype); + brelse(bh); + goto done; + } + } + + done: + /* + * We broke out of the log scan loop: either we came to the + * known end of the log or we found an unexpected block in the + * log. If the latter happened, then we know that the "current" + * transaction marks the end of the valid log. + */ + + if (pass == PASS_SCAN) + info->end_transaction = next_commit_ID; + else { + /* It's really bad news if different passes end up at + * different places (but possible due to IO errors). */ + if (info->end_transaction != next_commit_ID) { + printk (KERN_ERR "JBD: recovery pass %d ended at " + "transaction %u, expected %u\n", + pass, next_commit_ID, info->end_transaction); + if (!success) + success = -EIO; + } + } + + return success; + + failed: + return err; +} + + +/* Scan a revoke record, marking all blocks mentioned as revoked. */ + +static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, + tid_t sequence, struct recovery_info *info) +{ + journal_revoke_header_t *header; + int offset, max; + + header = (journal_revoke_header_t *) bh->b_data; + offset = sizeof(journal_revoke_header_t); + max = be32_to_cpu(header->r_count); + + while (offset < max) { + unsigned long blocknr; + int err; + + blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); + offset += 4; + err = journal_set_revoke(journal, blocknr, sequence); + if (err) + return err; + ++info->nr_revokes; + } + return 0; +} diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c new file mode 100644 index 000000000000..c532429d8d9b --- /dev/null +++ b/fs/jbd2/revoke.c @@ -0,0 +1,703 @@ +/* + * linux/fs/revoke.c + * + * Written by Stephen C. Tweedie , 2000 + * + * Copyright 2000 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Journal revoke routines for the generic filesystem journaling code; + * part of the ext2fs journaling system. + * + * Revoke is the mechanism used to prevent old log records for deleted + * metadata from being replayed on top of newer data using the same + * blocks. The revoke mechanism is used in two separate places: + * + * + Commit: during commit we write the entire list of the current + * transaction's revoked blocks to the journal + * + * + Recovery: during recovery we record the transaction ID of all + * revoked blocks. If there are multiple revoke records in the log + * for a single block, only the last one counts, and if there is a log + * entry for a block beyond the last revoke, then that log entry still + * gets replayed. + * + * We can get interactions between revokes and new log data within a + * single transaction: + * + * Block is revoked and then journaled: + * The desired end result is the journaling of the new block, so we + * cancel the revoke before the transaction commits. + * + * Block is journaled and then revoked: + * The revoke must take precedence over the write of the block, so we + * need either to cancel the journal entry or to write the revoke + * later in the log than the log block. In this case, we choose the + * latter: journaling a block cancels any revoke record for that block + * in the current transaction, so any revoke for that block in the + * transaction must have happened after the block was journaled and so + * the revoke must take precedence. + * + * Block is revoked and then written as data: + * The data write is allowed to succeed, but the revoke is _not_ + * cancelled. We still need to prevent old log records from + * overwriting the new data. We don't even need to clear the revoke + * bit here. + * + * Revoke information on buffers is a tri-state value: + * + * RevokeValid clear: no cached revoke status, need to look it up + * RevokeValid set, Revoked clear: + * buffer has not been revoked, and cancel_revoke + * need do nothing. + * RevokeValid set, Revoked set: + * buffer has been revoked. + */ + +#ifndef __KERNEL__ +#include "jfs_user.h" +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +static kmem_cache_t *revoke_record_cache; +static kmem_cache_t *revoke_table_cache; + +/* Each revoke record represents one single revoked block. During + journal replay, this involves recording the transaction ID of the + last transaction to revoke this block. */ + +struct jbd_revoke_record_s +{ + struct list_head hash; + tid_t sequence; /* Used for recovery only */ + unsigned long blocknr; +}; + + +/* The revoke table is just a simple hash table of revoke records. */ +struct jbd_revoke_table_s +{ + /* It is conceivable that we might want a larger hash table + * for recovery. Must be a power of two. */ + int hash_size; + int hash_shift; + struct list_head *hash_table; +}; + + +#ifdef __KERNEL__ +static void write_one_revoke_record(journal_t *, transaction_t *, + struct journal_head **, int *, + struct jbd_revoke_record_s *); +static void flush_descriptor(journal_t *, struct journal_head *, int); +#endif + +/* Utility functions to maintain the revoke table */ + +/* Borrowed from buffer.c: this is a tried and tested block hash function */ +static inline int hash(journal_t *journal, unsigned long block) +{ + struct jbd_revoke_table_s *table = journal->j_revoke; + int hash_shift = table->hash_shift; + + return ((block << (hash_shift - 6)) ^ + (block >> 13) ^ + (block << (hash_shift - 12))) & (table->hash_size - 1); +} + +static int insert_revoke_hash(journal_t *journal, unsigned long blocknr, + tid_t seq) +{ + struct list_head *hash_list; + struct jbd_revoke_record_s *record; + +repeat: + record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS); + if (!record) + goto oom; + + record->sequence = seq; + record->blocknr = blocknr; + hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; + spin_lock(&journal->j_revoke_lock); + list_add(&record->hash, hash_list); + spin_unlock(&journal->j_revoke_lock); + return 0; + +oom: + if (!journal_oom_retry) + return -ENOMEM; + jbd_debug(1, "ENOMEM in %s, retrying\n", __FUNCTION__); + yield(); + goto repeat; +} + +/* Find a revoke record in the journal's hash table. */ + +static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, + unsigned long blocknr) +{ + struct list_head *hash_list; + struct jbd_revoke_record_s *record; + + hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; + + spin_lock(&journal->j_revoke_lock); + record = (struct jbd_revoke_record_s *) hash_list->next; + while (&(record->hash) != hash_list) { + if (record->blocknr == blocknr) { + spin_unlock(&journal->j_revoke_lock); + return record; + } + record = (struct jbd_revoke_record_s *) record->hash.next; + } + spin_unlock(&journal->j_revoke_lock); + return NULL; +} + +int __init journal_init_revoke_caches(void) +{ + revoke_record_cache = kmem_cache_create("revoke_record", + sizeof(struct jbd_revoke_record_s), + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + if (revoke_record_cache == 0) + return -ENOMEM; + + revoke_table_cache = kmem_cache_create("revoke_table", + sizeof(struct jbd_revoke_table_s), + 0, 0, NULL, NULL); + if (revoke_table_cache == 0) { + kmem_cache_destroy(revoke_record_cache); + revoke_record_cache = NULL; + return -ENOMEM; + } + return 0; +} + +void journal_destroy_revoke_caches(void) +{ + kmem_cache_destroy(revoke_record_cache); + revoke_record_cache = NULL; + kmem_cache_destroy(revoke_table_cache); + revoke_table_cache = NULL; +} + +/* Initialise the revoke table for a given journal to a given size. */ + +int journal_init_revoke(journal_t *journal, int hash_size) +{ + int shift, tmp; + + J_ASSERT (journal->j_revoke_table[0] == NULL); + + shift = 0; + tmp = hash_size; + while((tmp >>= 1UL) != 0UL) + shift++; + + journal->j_revoke_table[0] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); + if (!journal->j_revoke_table[0]) + return -ENOMEM; + journal->j_revoke = journal->j_revoke_table[0]; + + /* Check that the hash_size is a power of two */ + J_ASSERT ((hash_size & (hash_size-1)) == 0); + + journal->j_revoke->hash_size = hash_size; + + journal->j_revoke->hash_shift = shift; + + journal->j_revoke->hash_table = + kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); + if (!journal->j_revoke->hash_table) { + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); + journal->j_revoke = NULL; + return -ENOMEM; + } + + for (tmp = 0; tmp < hash_size; tmp++) + INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); + + journal->j_revoke_table[1] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); + if (!journal->j_revoke_table[1]) { + kfree(journal->j_revoke_table[0]->hash_table); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); + return -ENOMEM; + } + + journal->j_revoke = journal->j_revoke_table[1]; + + /* Check that the hash_size is a power of two */ + J_ASSERT ((hash_size & (hash_size-1)) == 0); + + journal->j_revoke->hash_size = hash_size; + + journal->j_revoke->hash_shift = shift; + + journal->j_revoke->hash_table = + kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); + if (!journal->j_revoke->hash_table) { + kfree(journal->j_revoke_table[0]->hash_table); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[1]); + journal->j_revoke = NULL; + return -ENOMEM; + } + + for (tmp = 0; tmp < hash_size; tmp++) + INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); + + spin_lock_init(&journal->j_revoke_lock); + + return 0; +} + +/* Destoy a journal's revoke table. The table must already be empty! */ + +void journal_destroy_revoke(journal_t *journal) +{ + struct jbd_revoke_table_s *table; + struct list_head *hash_list; + int i; + + table = journal->j_revoke_table[0]; + if (!table) + return; + + for (i=0; ihash_size; i++) { + hash_list = &table->hash_table[i]; + J_ASSERT (list_empty(hash_list)); + } + + kfree(table->hash_table); + kmem_cache_free(revoke_table_cache, table); + journal->j_revoke = NULL; + + table = journal->j_revoke_table[1]; + if (!table) + return; + + for (i=0; ihash_size; i++) { + hash_list = &table->hash_table[i]; + J_ASSERT (list_empty(hash_list)); + } + + kfree(table->hash_table); + kmem_cache_free(revoke_table_cache, table); + journal->j_revoke = NULL; +} + + +#ifdef __KERNEL__ + +/* + * journal_revoke: revoke a given buffer_head from the journal. This + * prevents the block from being replayed during recovery if we take a + * crash after this current transaction commits. Any subsequent + * metadata writes of the buffer in this transaction cancel the + * revoke. + * + * Note that this call may block --- it is up to the caller to make + * sure that there are no further calls to journal_write_metadata + * before the revoke is complete. In ext3, this implies calling the + * revoke before clearing the block bitmap when we are deleting + * metadata. + * + * Revoke performs a journal_forget on any buffer_head passed in as a + * parameter, but does _not_ forget the buffer_head if the bh was only + * found implicitly. + * + * bh_in may not be a journalled buffer - it may have come off + * the hash tables without an attached journal_head. + * + * If bh_in is non-zero, journal_revoke() will decrement its b_count + * by one. + */ + +int journal_revoke(handle_t *handle, unsigned long blocknr, + struct buffer_head *bh_in) +{ + struct buffer_head *bh = NULL; + journal_t *journal; + struct block_device *bdev; + int err; + + might_sleep(); + if (bh_in) + BUFFER_TRACE(bh_in, "enter"); + + journal = handle->h_transaction->t_journal; + if (!journal_set_features(journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)){ + J_ASSERT (!"Cannot set revoke feature!"); + return -EINVAL; + } + + bdev = journal->j_fs_dev; + bh = bh_in; + + if (!bh) { + bh = __find_get_block(bdev, blocknr, journal->j_blocksize); + if (bh) + BUFFER_TRACE(bh, "found on hash"); + } +#ifdef JBD_EXPENSIVE_CHECKING + else { + struct buffer_head *bh2; + + /* If there is a different buffer_head lying around in + * memory anywhere... */ + bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize); + if (bh2) { + /* ... and it has RevokeValid status... */ + if (bh2 != bh && buffer_revokevalid(bh2)) + /* ...then it better be revoked too, + * since it's illegal to create a revoke + * record against a buffer_head which is + * not marked revoked --- that would + * risk missing a subsequent revoke + * cancel. */ + J_ASSERT_BH(bh2, buffer_revoked(bh2)); + put_bh(bh2); + } + } +#endif + + /* We really ought not ever to revoke twice in a row without + first having the revoke cancelled: it's illegal to free a + block twice without allocating it in between! */ + if (bh) { + if (!J_EXPECT_BH(bh, !buffer_revoked(bh), + "inconsistent data on disk")) { + if (!bh_in) + brelse(bh); + return -EIO; + } + set_buffer_revoked(bh); + set_buffer_revokevalid(bh); + if (bh_in) { + BUFFER_TRACE(bh_in, "call journal_forget"); + journal_forget(handle, bh_in); + } else { + BUFFER_TRACE(bh, "call brelse"); + __brelse(bh); + } + } + + jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in); + err = insert_revoke_hash(journal, blocknr, + handle->h_transaction->t_tid); + BUFFER_TRACE(bh_in, "exit"); + return err; +} + +/* + * Cancel an outstanding revoke. For use only internally by the + * journaling code (called from journal_get_write_access). + * + * We trust buffer_revoked() on the buffer if the buffer is already + * being journaled: if there is no revoke pending on the buffer, then we + * don't do anything here. + * + * This would break if it were possible for a buffer to be revoked and + * discarded, and then reallocated within the same transaction. In such + * a case we would have lost the revoked bit, but when we arrived here + * the second time we would still have a pending revoke to cancel. So, + * do not trust the Revoked bit on buffers unless RevokeValid is also + * set. + * + * The caller must have the journal locked. + */ +int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) +{ + struct jbd_revoke_record_s *record; + journal_t *journal = handle->h_transaction->t_journal; + int need_cancel; + int did_revoke = 0; /* akpm: debug */ + struct buffer_head *bh = jh2bh(jh); + + jbd_debug(4, "journal_head %p, cancelling revoke\n", jh); + + /* Is the existing Revoke bit valid? If so, we trust it, and + * only perform the full cancel if the revoke bit is set. If + * not, we can't trust the revoke bit, and we need to do the + * full search for a revoke record. */ + if (test_set_buffer_revokevalid(bh)) { + need_cancel = test_clear_buffer_revoked(bh); + } else { + need_cancel = 1; + clear_buffer_revoked(bh); + } + + if (need_cancel) { + record = find_revoke_record(journal, bh->b_blocknr); + if (record) { + jbd_debug(4, "cancelled existing revoke on " + "blocknr %llu\n", (unsigned long long)bh->b_blocknr); + spin_lock(&journal->j_revoke_lock); + list_del(&record->hash); + spin_unlock(&journal->j_revoke_lock); + kmem_cache_free(revoke_record_cache, record); + did_revoke = 1; + } + } + +#ifdef JBD_EXPENSIVE_CHECKING + /* There better not be one left behind by now! */ + record = find_revoke_record(journal, bh->b_blocknr); + J_ASSERT_JH(jh, record == NULL); +#endif + + /* Finally, have we just cleared revoke on an unhashed + * buffer_head? If so, we'd better make sure we clear the + * revoked status on any hashed alias too, otherwise the revoke + * state machine will get very upset later on. */ + if (need_cancel) { + struct buffer_head *bh2; + bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size); + if (bh2) { + if (bh2 != bh) + clear_buffer_revoked(bh2); + __brelse(bh2); + } + } + return did_revoke; +} + +/* journal_switch_revoke table select j_revoke for next transaction + * we do not want to suspend any processing until all revokes are + * written -bzzz + */ +void journal_switch_revoke_table(journal_t *journal) +{ + int i; + + if (journal->j_revoke == journal->j_revoke_table[0]) + journal->j_revoke = journal->j_revoke_table[1]; + else + journal->j_revoke = journal->j_revoke_table[0]; + + for (i = 0; i < journal->j_revoke->hash_size; i++) + INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]); +} + +/* + * Write revoke records to the journal for all entries in the current + * revoke hash, deleting the entries as we go. + * + * Called with the journal lock held. + */ + +void journal_write_revoke_records(journal_t *journal, + transaction_t *transaction) +{ + struct journal_head *descriptor; + struct jbd_revoke_record_s *record; + struct jbd_revoke_table_s *revoke; + struct list_head *hash_list; + int i, offset, count; + + descriptor = NULL; + offset = 0; + count = 0; + + /* select revoke table for committing transaction */ + revoke = journal->j_revoke == journal->j_revoke_table[0] ? + journal->j_revoke_table[1] : journal->j_revoke_table[0]; + + for (i = 0; i < revoke->hash_size; i++) { + hash_list = &revoke->hash_table[i]; + + while (!list_empty(hash_list)) { + record = (struct jbd_revoke_record_s *) + hash_list->next; + write_one_revoke_record(journal, transaction, + &descriptor, &offset, + record); + count++; + list_del(&record->hash); + kmem_cache_free(revoke_record_cache, record); + } + } + if (descriptor) + flush_descriptor(journal, descriptor, offset); + jbd_debug(1, "Wrote %d revoke records\n", count); +} + +/* + * Write out one revoke record. We need to create a new descriptor + * block if the old one is full or if we have not already created one. + */ + +static void write_one_revoke_record(journal_t *journal, + transaction_t *transaction, + struct journal_head **descriptorp, + int *offsetp, + struct jbd_revoke_record_s *record) +{ + struct journal_head *descriptor; + int offset; + journal_header_t *header; + + /* If we are already aborting, this all becomes a noop. We + still need to go round the loop in + journal_write_revoke_records in order to free all of the + revoke records: only the IO to the journal is omitted. */ + if (is_journal_aborted(journal)) + return; + + descriptor = *descriptorp; + offset = *offsetp; + + /* Make sure we have a descriptor with space left for the record */ + if (descriptor) { + if (offset == journal->j_blocksize) { + flush_descriptor(journal, descriptor, offset); + descriptor = NULL; + } + } + + if (!descriptor) { + descriptor = journal_get_descriptor_buffer(journal); + if (!descriptor) + return; + header = (journal_header_t *) &jh2bh(descriptor)->b_data[0]; + header->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); + header->h_blocktype = cpu_to_be32(JFS_REVOKE_BLOCK); + header->h_sequence = cpu_to_be32(transaction->t_tid); + + /* Record it so that we can wait for IO completion later */ + JBUFFER_TRACE(descriptor, "file as BJ_LogCtl"); + journal_file_buffer(descriptor, transaction, BJ_LogCtl); + + offset = sizeof(journal_revoke_header_t); + *descriptorp = descriptor; + } + + * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) = + cpu_to_be32(record->blocknr); + offset += 4; + *offsetp = offset; +} + +/* + * Flush a revoke descriptor out to the journal. If we are aborting, + * this is a noop; otherwise we are generating a buffer which needs to + * be waited for during commit, so it has to go onto the appropriate + * journal buffer list. + */ + +static void flush_descriptor(journal_t *journal, + struct journal_head *descriptor, + int offset) +{ + journal_revoke_header_t *header; + struct buffer_head *bh = jh2bh(descriptor); + + if (is_journal_aborted(journal)) { + put_bh(bh); + return; + } + + header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data; + header->r_count = cpu_to_be32(offset); + set_buffer_jwrite(bh); + BUFFER_TRACE(bh, "write"); + set_buffer_dirty(bh); + ll_rw_block(SWRITE, 1, &bh); +} +#endif + +/* + * Revoke support for recovery. + * + * Recovery needs to be able to: + * + * record all revoke records, including the tid of the latest instance + * of each revoke in the journal + * + * check whether a given block in a given transaction should be replayed + * (ie. has not been revoked by a revoke record in that or a subsequent + * transaction) + * + * empty the revoke table after recovery. + */ + +/* + * First, setting revoke records. We create a new revoke record for + * every block ever revoked in the log as we scan it for recovery, and + * we update the existing records if we find multiple revokes for a + * single block. + */ + +int journal_set_revoke(journal_t *journal, + unsigned long blocknr, + tid_t sequence) +{ + struct jbd_revoke_record_s *record; + + record = find_revoke_record(journal, blocknr); + if (record) { + /* If we have multiple occurrences, only record the + * latest sequence number in the hashed record */ + if (tid_gt(sequence, record->sequence)) + record->sequence = sequence; + return 0; + } + return insert_revoke_hash(journal, blocknr, sequence); +} + +/* + * Test revoke records. For a given block referenced in the log, has + * that block been revoked? A revoke record with a given transaction + * sequence number revokes all blocks in that transaction and earlier + * ones, but later transactions still need replayed. + */ + +int journal_test_revoke(journal_t *journal, + unsigned long blocknr, + tid_t sequence) +{ + struct jbd_revoke_record_s *record; + + record = find_revoke_record(journal, blocknr); + if (!record) + return 0; + if (tid_gt(sequence, record->sequence)) + return 0; + return 1; +} + +/* + * Finally, once recovery is over, we need to clear the revoke table so + * that it can be reused by the running filesystem. + */ + +void journal_clear_revoke(journal_t *journal) +{ + int i; + struct list_head *hash_list; + struct jbd_revoke_record_s *record; + struct jbd_revoke_table_s *revoke; + + revoke = journal->j_revoke; + + for (i = 0; i < revoke->hash_size; i++) { + hash_list = &revoke->hash_table[i]; + while (!list_empty(hash_list)) { + record = (struct jbd_revoke_record_s*) hash_list->next; + list_del(&record->hash); + kmem_cache_free(revoke_record_cache, record); + } + } +} diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c new file mode 100644 index 000000000000..e1b3c8af4d17 --- /dev/null +++ b/fs/jbd2/transaction.c @@ -0,0 +1,2080 @@ +/* + * linux/fs/transaction.c + * + * Written by Stephen C. Tweedie , 1998 + * + * Copyright 1998 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Generic filesystem transaction handling code; part of the ext2fs + * journaling system. + * + * This file manages transactions (compound commits managed by the + * journaling code) and handles (individual atomic operations by the + * filesystem). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * get_transaction: obtain a new transaction_t object. + * + * Simply allocate and initialise a new transaction. Create it in + * RUNNING state and add it to the current journal (which should not + * have an existing running transaction: we only make a new transaction + * once we have started to commit the old one). + * + * Preconditions: + * The journal MUST be locked. We don't perform atomic mallocs on the + * new transaction and we can't block without protecting against other + * processes trying to touch the journal while it is in transition. + * + * Called under j_state_lock + */ + +static transaction_t * +get_transaction(journal_t *journal, transaction_t *transaction) +{ + transaction->t_journal = journal; + transaction->t_state = T_RUNNING; + transaction->t_tid = journal->j_transaction_sequence++; + transaction->t_expires = jiffies + journal->j_commit_interval; + spin_lock_init(&transaction->t_handle_lock); + + /* Set up the commit timer for the new transaction. */ + journal->j_commit_timer.expires = transaction->t_expires; + add_timer(&journal->j_commit_timer); + + J_ASSERT(journal->j_running_transaction == NULL); + journal->j_running_transaction = transaction; + + return transaction; +} + +/* + * Handle management. + * + * A handle_t is an object which represents a single atomic update to a + * filesystem, and which tracks all of the modifications which form part + * of that one update. + */ + +/* + * start_this_handle: Given a handle, deal with any locking or stalling + * needed to make sure that there is enough journal space for the handle + * to begin. Attach the handle to a transaction and set up the + * transaction's buffer credits. + */ + +static int start_this_handle(journal_t *journal, handle_t *handle) +{ + transaction_t *transaction; + int needed; + int nblocks = handle->h_buffer_credits; + transaction_t *new_transaction = NULL; + int ret = 0; + + if (nblocks > journal->j_max_transaction_buffers) { + printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n", + current->comm, nblocks, + journal->j_max_transaction_buffers); + ret = -ENOSPC; + goto out; + } + +alloc_transaction: + if (!journal->j_running_transaction) { + new_transaction = jbd_kmalloc(sizeof(*new_transaction), + GFP_NOFS); + if (!new_transaction) { + ret = -ENOMEM; + goto out; + } + memset(new_transaction, 0, sizeof(*new_transaction)); + } + + jbd_debug(3, "New handle %p going live.\n", handle); + +repeat: + + /* + * We need to hold j_state_lock until t_updates has been incremented, + * for proper journal barrier handling + */ + spin_lock(&journal->j_state_lock); +repeat_locked: + if (is_journal_aborted(journal) || + (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) { + spin_unlock(&journal->j_state_lock); + ret = -EROFS; + goto out; + } + + /* Wait on the journal's transaction barrier if necessary */ + if (journal->j_barrier_count) { + spin_unlock(&journal->j_state_lock); + wait_event(journal->j_wait_transaction_locked, + journal->j_barrier_count == 0); + goto repeat; + } + + if (!journal->j_running_transaction) { + if (!new_transaction) { + spin_unlock(&journal->j_state_lock); + goto alloc_transaction; + } + get_transaction(journal, new_transaction); + new_transaction = NULL; + } + + transaction = journal->j_running_transaction; + + /* + * If the current transaction is locked down for commit, wait for the + * lock to be released. + */ + if (transaction->t_state == T_LOCKED) { + DEFINE_WAIT(wait); + + prepare_to_wait(&journal->j_wait_transaction_locked, + &wait, TASK_UNINTERRUPTIBLE); + spin_unlock(&journal->j_state_lock); + schedule(); + finish_wait(&journal->j_wait_transaction_locked, &wait); + goto repeat; + } + + /* + * If there is not enough space left in the log to write all potential + * buffers requested by this operation, we need to stall pending a log + * checkpoint to free some more log space. + */ + spin_lock(&transaction->t_handle_lock); + needed = transaction->t_outstanding_credits + nblocks; + + if (needed > journal->j_max_transaction_buffers) { + /* + * If the current transaction is already too large, then start + * to commit it: we can then go back and attach this handle to + * a new transaction. + */ + DEFINE_WAIT(wait); + + jbd_debug(2, "Handle %p starting new commit...\n", handle); + spin_unlock(&transaction->t_handle_lock); + prepare_to_wait(&journal->j_wait_transaction_locked, &wait, + TASK_UNINTERRUPTIBLE); + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); + schedule(); + finish_wait(&journal->j_wait_transaction_locked, &wait); + goto repeat; + } + + /* + * The commit code assumes that it can get enough log space + * without forcing a checkpoint. This is *critical* for + * correctness: a checkpoint of a buffer which is also + * associated with a committing transaction creates a deadlock, + * so commit simply cannot force through checkpoints. + * + * We must therefore ensure the necessary space in the journal + * *before* starting to dirty potentially checkpointed buffers + * in the new transaction. + * + * The worst part is, any transaction currently committing can + * reduce the free space arbitrarily. Be careful to account for + * those buffers when checkpointing. + */ + + /* + * @@@ AKPM: This seems rather over-defensive. We're giving commit + * a _lot_ of headroom: 1/4 of the journal plus the size of + * the committing transaction. Really, we only need to give it + * committing_transaction->t_outstanding_credits plus "enough" for + * the log control blocks. + * Also, this test is inconsitent with the matching one in + * journal_extend(). + */ + if (__log_space_left(journal) < jbd_space_needed(journal)) { + jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); + spin_unlock(&transaction->t_handle_lock); + __log_wait_for_space(journal); + goto repeat_locked; + } + + /* OK, account for the buffers that this operation expects to + * use and add the handle to the running transaction. */ + + handle->h_transaction = transaction; + transaction->t_outstanding_credits += nblocks; + transaction->t_updates++; + transaction->t_handle_count++; + jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", + handle, nblocks, transaction->t_outstanding_credits, + __log_space_left(journal)); + spin_unlock(&transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); +out: + if (unlikely(new_transaction)) /* It's usually NULL */ + kfree(new_transaction); + return ret; +} + +/* Allocate a new handle. This should probably be in a slab... */ +static handle_t *new_handle(int nblocks) +{ + handle_t *handle = jbd_alloc_handle(GFP_NOFS); + if (!handle) + return NULL; + memset(handle, 0, sizeof(*handle)); + handle->h_buffer_credits = nblocks; + handle->h_ref = 1; + + return handle; +} + +/** + * handle_t *journal_start() - Obtain a new handle. + * @journal: Journal to start transaction on. + * @nblocks: number of block buffer we might modify + * + * We make sure that the transaction can guarantee at least nblocks of + * modified buffers in the log. We block until the log can guarantee + * that much space. + * + * This function is visible to journal users (like ext3fs), so is not + * called with the journal already locked. + * + * Return a pointer to a newly allocated handle, or NULL on failure + */ +handle_t *journal_start(journal_t *journal, int nblocks) +{ + handle_t *handle = journal_current_handle(); + int err; + + if (!journal) + return ERR_PTR(-EROFS); + + if (handle) { + J_ASSERT(handle->h_transaction->t_journal == journal); + handle->h_ref++; + return handle; + } + + handle = new_handle(nblocks); + if (!handle) + return ERR_PTR(-ENOMEM); + + current->journal_info = handle; + + err = start_this_handle(journal, handle); + if (err < 0) { + jbd_free_handle(handle); + current->journal_info = NULL; + handle = ERR_PTR(err); + } + return handle; +} + +/** + * int journal_extend() - extend buffer credits. + * @handle: handle to 'extend' + * @nblocks: nr blocks to try to extend by. + * + * Some transactions, such as large extends and truncates, can be done + * atomically all at once or in several stages. The operation requests + * a credit for a number of buffer modications in advance, but can + * extend its credit if it needs more. + * + * journal_extend tries to give the running handle more buffer credits. + * It does not guarantee that allocation - this is a best-effort only. + * The calling process MUST be able to deal cleanly with a failure to + * extend here. + * + * Return 0 on success, non-zero on failure. + * + * return code < 0 implies an error + * return code > 0 implies normal transaction-full status. + */ +int journal_extend(handle_t *handle, int nblocks) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + int result; + int wanted; + + result = -EIO; + if (is_handle_aborted(handle)) + goto out; + + result = 1; + + spin_lock(&journal->j_state_lock); + + /* Don't extend a locked-down transaction! */ + if (handle->h_transaction->t_state != T_RUNNING) { + jbd_debug(3, "denied handle %p %d blocks: " + "transaction not running\n", handle, nblocks); + goto error_out; + } + + spin_lock(&transaction->t_handle_lock); + wanted = transaction->t_outstanding_credits + nblocks; + + if (wanted > journal->j_max_transaction_buffers) { + jbd_debug(3, "denied handle %p %d blocks: " + "transaction too large\n", handle, nblocks); + goto unlock; + } + + if (wanted > __log_space_left(journal)) { + jbd_debug(3, "denied handle %p %d blocks: " + "insufficient log space\n", handle, nblocks); + goto unlock; + } + + handle->h_buffer_credits += nblocks; + transaction->t_outstanding_credits += nblocks; + result = 0; + + jbd_debug(3, "extended handle %p by %d\n", handle, nblocks); +unlock: + spin_unlock(&transaction->t_handle_lock); +error_out: + spin_unlock(&journal->j_state_lock); +out: + return result; +} + + +/** + * int journal_restart() - restart a handle . + * @handle: handle to restart + * @nblocks: nr credits requested + * + * Restart a handle for a multi-transaction filesystem + * operation. + * + * If the journal_extend() call above fails to grant new buffer credits + * to a running handle, a call to journal_restart will commit the + * handle's transaction so far and reattach the handle to a new + * transaction capabable of guaranteeing the requested number of + * credits. + */ + +int journal_restart(handle_t *handle, int nblocks) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + int ret; + + /* If we've had an abort of any type, don't even think about + * actually doing the restart! */ + if (is_handle_aborted(handle)) + return 0; + + /* + * First unlink the handle from its current transaction, and start the + * commit on that. + */ + J_ASSERT(transaction->t_updates > 0); + J_ASSERT(journal_current_handle() == handle); + + spin_lock(&journal->j_state_lock); + spin_lock(&transaction->t_handle_lock); + transaction->t_outstanding_credits -= handle->h_buffer_credits; + transaction->t_updates--; + + if (!transaction->t_updates) + wake_up(&journal->j_wait_updates); + spin_unlock(&transaction->t_handle_lock); + + jbd_debug(2, "restarting handle %p\n", handle); + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); + + handle->h_buffer_credits = nblocks; + ret = start_this_handle(journal, handle); + return ret; +} + + +/** + * void journal_lock_updates () - establish a transaction barrier. + * @journal: Journal to establish a barrier on. + * + * This locks out any further updates from being started, and blocks + * until all existing updates have completed, returning only once the + * journal is in a quiescent state with no updates running. + * + * The journal lock should not be held on entry. + */ +void journal_lock_updates(journal_t *journal) +{ + DEFINE_WAIT(wait); + + spin_lock(&journal->j_state_lock); + ++journal->j_barrier_count; + + /* Wait until there are no running updates */ + while (1) { + transaction_t *transaction = journal->j_running_transaction; + + if (!transaction) + break; + + spin_lock(&transaction->t_handle_lock); + if (!transaction->t_updates) { + spin_unlock(&transaction->t_handle_lock); + break; + } + prepare_to_wait(&journal->j_wait_updates, &wait, + TASK_UNINTERRUPTIBLE); + spin_unlock(&transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); + schedule(); + finish_wait(&journal->j_wait_updates, &wait); + spin_lock(&journal->j_state_lock); + } + spin_unlock(&journal->j_state_lock); + + /* + * We have now established a barrier against other normal updates, but + * we also need to barrier against other journal_lock_updates() calls + * to make sure that we serialise special journal-locked operations + * too. + */ + mutex_lock(&journal->j_barrier); +} + +/** + * void journal_unlock_updates (journal_t* journal) - release barrier + * @journal: Journal to release the barrier on. + * + * Release a transaction barrier obtained with journal_lock_updates(). + * + * Should be called without the journal lock held. + */ +void journal_unlock_updates (journal_t *journal) +{ + J_ASSERT(journal->j_barrier_count != 0); + + mutex_unlock(&journal->j_barrier); + spin_lock(&journal->j_state_lock); + --journal->j_barrier_count; + spin_unlock(&journal->j_state_lock); + wake_up(&journal->j_wait_transaction_locked); +} + +/* + * Report any unexpected dirty buffers which turn up. Normally those + * indicate an error, but they can occur if the user is running (say) + * tune2fs to modify the live filesystem, so we need the option of + * continuing as gracefully as possible. # + * + * The caller should already hold the journal lock and + * j_list_lock spinlock: most callers will need those anyway + * in order to probe the buffer's journaling state safely. + */ +static void jbd_unexpected_dirty_buffer(struct journal_head *jh) +{ + int jlist; + + /* If this buffer is one which might reasonably be dirty + * --- ie. data, or not part of this journal --- then + * we're OK to leave it alone, but otherwise we need to + * move the dirty bit to the journal's own internal + * JBDDirty bit. */ + jlist = jh->b_jlist; + + if (jlist == BJ_Metadata || jlist == BJ_Reserved || + jlist == BJ_Shadow || jlist == BJ_Forget) { + struct buffer_head *bh = jh2bh(jh); + + if (test_clear_buffer_dirty(bh)) + set_buffer_jbddirty(bh); + } +} + +/* + * If the buffer is already part of the current transaction, then there + * is nothing we need to do. If it is already part of a prior + * transaction which we are still committing to disk, then we need to + * make sure that we do not overwrite the old copy: we do copy-out to + * preserve the copy going to disk. We also account the buffer against + * the handle's metadata buffer credits (unless the buffer is already + * part of the transaction, that is). + * + */ +static int +do_get_write_access(handle_t *handle, struct journal_head *jh, + int force_copy) +{ + struct buffer_head *bh; + transaction_t *transaction; + journal_t *journal; + int error; + char *frozen_buffer = NULL; + int need_copy = 0; + + if (is_handle_aborted(handle)) + return -EROFS; + + transaction = handle->h_transaction; + journal = transaction->t_journal; + + jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy); + + JBUFFER_TRACE(jh, "entry"); +repeat: + bh = jh2bh(jh); + + /* @@@ Need to check for errors here at some point. */ + + lock_buffer(bh); + jbd_lock_bh_state(bh); + + /* We now hold the buffer lock so it is safe to query the buffer + * state. Is the buffer dirty? + * + * If so, there are two possibilities. The buffer may be + * non-journaled, and undergoing a quite legitimate writeback. + * Otherwise, it is journaled, and we don't expect dirty buffers + * in that state (the buffers should be marked JBD_Dirty + * instead.) So either the IO is being done under our own + * control and this is a bug, or it's a third party IO such as + * dump(8) (which may leave the buffer scheduled for read --- + * ie. locked but not dirty) or tune2fs (which may actually have + * the buffer dirtied, ugh.) */ + + if (buffer_dirty(bh)) { + /* + * First question: is this buffer already part of the current + * transaction or the existing committing transaction? + */ + if (jh->b_transaction) { + J_ASSERT_JH(jh, + jh->b_transaction == transaction || + jh->b_transaction == + journal->j_committing_transaction); + if (jh->b_next_transaction) + J_ASSERT_JH(jh, jh->b_next_transaction == + transaction); + } + /* + * In any case we need to clean the dirty flag and we must + * do it under the buffer lock to be sure we don't race + * with running write-out. + */ + JBUFFER_TRACE(jh, "Unexpected dirty buffer"); + jbd_unexpected_dirty_buffer(jh); + } + + unlock_buffer(bh); + + error = -EROFS; + if (is_handle_aborted(handle)) { + jbd_unlock_bh_state(bh); + goto out; + } + error = 0; + + /* + * The buffer is already part of this transaction if b_transaction or + * b_next_transaction points to it + */ + if (jh->b_transaction == transaction || + jh->b_next_transaction == transaction) + goto done; + + /* + * If there is already a copy-out version of this buffer, then we don't + * need to make another one + */ + if (jh->b_frozen_data) { + JBUFFER_TRACE(jh, "has frozen data"); + J_ASSERT_JH(jh, jh->b_next_transaction == NULL); + jh->b_next_transaction = transaction; + goto done; + } + + /* Is there data here we need to preserve? */ + + if (jh->b_transaction && jh->b_transaction != transaction) { + JBUFFER_TRACE(jh, "owned by older transaction"); + J_ASSERT_JH(jh, jh->b_next_transaction == NULL); + J_ASSERT_JH(jh, jh->b_transaction == + journal->j_committing_transaction); + + /* There is one case we have to be very careful about. + * If the committing transaction is currently writing + * this buffer out to disk and has NOT made a copy-out, + * then we cannot modify the buffer contents at all + * right now. The essence of copy-out is that it is the + * extra copy, not the primary copy, which gets + * journaled. If the primary copy is already going to + * disk then we cannot do copy-out here. */ + + if (jh->b_jlist == BJ_Shadow) { + DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Unshadow); + wait_queue_head_t *wqh; + + wqh = bit_waitqueue(&bh->b_state, BH_Unshadow); + + JBUFFER_TRACE(jh, "on shadow: sleep"); + jbd_unlock_bh_state(bh); + /* commit wakes up all shadow buffers after IO */ + for ( ; ; ) { + prepare_to_wait(wqh, &wait.wait, + TASK_UNINTERRUPTIBLE); + if (jh->b_jlist != BJ_Shadow) + break; + schedule(); + } + finish_wait(wqh, &wait.wait); + goto repeat; + } + + /* Only do the copy if the currently-owning transaction + * still needs it. If it is on the Forget list, the + * committing transaction is past that stage. The + * buffer had better remain locked during the kmalloc, + * but that should be true --- we hold the journal lock + * still and the buffer is already on the BUF_JOURNAL + * list so won't be flushed. + * + * Subtle point, though: if this is a get_undo_access, + * then we will be relying on the frozen_data to contain + * the new value of the committed_data record after the + * transaction, so we HAVE to force the frozen_data copy + * in that case. */ + + if (jh->b_jlist != BJ_Forget || force_copy) { + JBUFFER_TRACE(jh, "generate frozen data"); + if (!frozen_buffer) { + JBUFFER_TRACE(jh, "allocate memory for buffer"); + jbd_unlock_bh_state(bh); + frozen_buffer = + jbd_slab_alloc(jh2bh(jh)->b_size, + GFP_NOFS); + if (!frozen_buffer) { + printk(KERN_EMERG + "%s: OOM for frozen_buffer\n", + __FUNCTION__); + JBUFFER_TRACE(jh, "oom!"); + error = -ENOMEM; + jbd_lock_bh_state(bh); + goto done; + } + goto repeat; + } + jh->b_frozen_data = frozen_buffer; + frozen_buffer = NULL; + need_copy = 1; + } + jh->b_next_transaction = transaction; + } + + + /* + * Finally, if the buffer is not journaled right now, we need to make + * sure it doesn't get written to disk before the caller actually + * commits the new data + */ + if (!jh->b_transaction) { + JBUFFER_TRACE(jh, "no transaction"); + J_ASSERT_JH(jh, !jh->b_next_transaction); + jh->b_transaction = transaction; + JBUFFER_TRACE(jh, "file as BJ_Reserved"); + spin_lock(&journal->j_list_lock); + __journal_file_buffer(jh, transaction, BJ_Reserved); + spin_unlock(&journal->j_list_lock); + } + +done: + if (need_copy) { + struct page *page; + int offset; + char *source; + + J_EXPECT_JH(jh, buffer_uptodate(jh2bh(jh)), + "Possible IO failure.\n"); + page = jh2bh(jh)->b_page; + offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK; + source = kmap_atomic(page, KM_USER0); + memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size); + kunmap_atomic(source, KM_USER0); + } + jbd_unlock_bh_state(bh); + + /* + * If we are about to journal a buffer, then any revoke pending on it is + * no longer valid + */ + journal_cancel_revoke(handle, jh); + +out: + if (unlikely(frozen_buffer)) /* It's usually NULL */ + jbd_slab_free(frozen_buffer, bh->b_size); + + JBUFFER_TRACE(jh, "exit"); + return error; +} + +/** + * int journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update. + * @handle: transaction to add buffer modifications to + * @bh: bh to be used for metadata writes + * @credits: variable that will receive credits for the buffer + * + * Returns an error code or 0 on success. + * + * In full data journalling mode the buffer may be of type BJ_AsyncData, + * because we're write()ing a buffer which is also part of a shared mapping. + */ + +int journal_get_write_access(handle_t *handle, struct buffer_head *bh) +{ + struct journal_head *jh = journal_add_journal_head(bh); + int rc; + + /* We do not want to get caught playing with fields which the + * log thread also manipulates. Make sure that the buffer + * completes any outstanding IO before proceeding. */ + rc = do_get_write_access(handle, jh, 0); + journal_put_journal_head(jh); + return rc; +} + + +/* + * When the user wants to journal a newly created buffer_head + * (ie. getblk() returned a new buffer and we are going to populate it + * manually rather than reading off disk), then we need to keep the + * buffer_head locked until it has been completely filled with new + * data. In this case, we should be able to make the assertion that + * the bh is not already part of an existing transaction. + * + * The buffer should already be locked by the caller by this point. + * There is no lock ranking violation: it was a newly created, + * unlocked buffer beforehand. */ + +/** + * int journal_get_create_access () - notify intent to use newly created bh + * @handle: transaction to new buffer to + * @bh: new buffer. + * + * Call this if you create a new bh. + */ +int journal_get_create_access(handle_t *handle, struct buffer_head *bh) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + struct journal_head *jh = journal_add_journal_head(bh); + int err; + + jbd_debug(5, "journal_head %p\n", jh); + err = -EROFS; + if (is_handle_aborted(handle)) + goto out; + err = 0; + + JBUFFER_TRACE(jh, "entry"); + /* + * The buffer may already belong to this transaction due to pre-zeroing + * in the filesystem's new_block code. It may also be on the previous, + * committing transaction's lists, but it HAS to be in Forget state in + * that case: the transaction must have deleted the buffer for it to be + * reused here. + */ + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); + J_ASSERT_JH(jh, (jh->b_transaction == transaction || + jh->b_transaction == NULL || + (jh->b_transaction == journal->j_committing_transaction && + jh->b_jlist == BJ_Forget))); + + J_ASSERT_JH(jh, jh->b_next_transaction == NULL); + J_ASSERT_JH(jh, buffer_locked(jh2bh(jh))); + + if (jh->b_transaction == NULL) { + jh->b_transaction = transaction; + JBUFFER_TRACE(jh, "file as BJ_Reserved"); + __journal_file_buffer(jh, transaction, BJ_Reserved); + } else if (jh->b_transaction == journal->j_committing_transaction) { + JBUFFER_TRACE(jh, "set next transaction"); + jh->b_next_transaction = transaction; + } + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + + /* + * akpm: I added this. ext3_alloc_branch can pick up new indirect + * blocks which contain freed but then revoked metadata. We need + * to cancel the revoke in case we end up freeing it yet again + * and the reallocating as data - this would cause a second revoke, + * which hits an assertion error. + */ + JBUFFER_TRACE(jh, "cancelling revoke"); + journal_cancel_revoke(handle, jh); + journal_put_journal_head(jh); +out: + return err; +} + +/** + * int journal_get_undo_access() - Notify intent to modify metadata with + * non-rewindable consequences + * @handle: transaction + * @bh: buffer to undo + * @credits: store the number of taken credits here (if not NULL) + * + * Sometimes there is a need to distinguish between metadata which has + * been committed to disk and that which has not. The ext3fs code uses + * this for freeing and allocating space, we have to make sure that we + * do not reuse freed space until the deallocation has been committed, + * since if we overwrote that space we would make the delete + * un-rewindable in case of a crash. + * + * To deal with that, journal_get_undo_access requests write access to a + * buffer for parts of non-rewindable operations such as delete + * operations on the bitmaps. The journaling code must keep a copy of + * the buffer's contents prior to the undo_access call until such time + * as we know that the buffer has definitely been committed to disk. + * + * We never need to know which transaction the committed data is part + * of, buffers touched here are guaranteed to be dirtied later and so + * will be committed to a new transaction in due course, at which point + * we can discard the old committed data pointer. + * + * Returns error number or 0 on success. + */ +int journal_get_undo_access(handle_t *handle, struct buffer_head *bh) +{ + int err; + struct journal_head *jh = journal_add_journal_head(bh); + char *committed_data = NULL; + + JBUFFER_TRACE(jh, "entry"); + + /* + * Do this first --- it can drop the journal lock, so we want to + * make sure that obtaining the committed_data is done + * atomically wrt. completion of any outstanding commits. + */ + err = do_get_write_access(handle, jh, 1); + if (err) + goto out; + +repeat: + if (!jh->b_committed_data) { + committed_data = jbd_slab_alloc(jh2bh(jh)->b_size, GFP_NOFS); + if (!committed_data) { + printk(KERN_EMERG "%s: No memory for committed data\n", + __FUNCTION__); + err = -ENOMEM; + goto out; + } + } + + jbd_lock_bh_state(bh); + if (!jh->b_committed_data) { + /* Copy out the current buffer contents into the + * preserved, committed copy. */ + JBUFFER_TRACE(jh, "generate b_committed data"); + if (!committed_data) { + jbd_unlock_bh_state(bh); + goto repeat; + } + + jh->b_committed_data = committed_data; + committed_data = NULL; + memcpy(jh->b_committed_data, bh->b_data, bh->b_size); + } + jbd_unlock_bh_state(bh); +out: + journal_put_journal_head(jh); + if (unlikely(committed_data)) + jbd_slab_free(committed_data, bh->b_size); + return err; +} + +/** + * int journal_dirty_data() - mark a buffer as containing dirty data which + * needs to be flushed before we can commit the + * current transaction. + * @handle: transaction + * @bh: bufferhead to mark + * + * The buffer is placed on the transaction's data list and is marked as + * belonging to the transaction. + * + * Returns error number or 0 on success. + * + * journal_dirty_data() can be called via page_launder->ext3_writepage + * by kswapd. + */ +int journal_dirty_data(handle_t *handle, struct buffer_head *bh) +{ + journal_t *journal = handle->h_transaction->t_journal; + int need_brelse = 0; + struct journal_head *jh; + + if (is_handle_aborted(handle)) + return 0; + + jh = journal_add_journal_head(bh); + JBUFFER_TRACE(jh, "entry"); + + /* + * The buffer could *already* be dirty. Writeout can start + * at any time. + */ + jbd_debug(4, "jh: %p, tid:%d\n", jh, handle->h_transaction->t_tid); + + /* + * What if the buffer is already part of a running transaction? + * + * There are two cases: + * 1) It is part of the current running transaction. Refile it, + * just in case we have allocated it as metadata, deallocated + * it, then reallocated it as data. + * 2) It is part of the previous, still-committing transaction. + * If all we want to do is to guarantee that the buffer will be + * written to disk before this new transaction commits, then + * being sure that the *previous* transaction has this same + * property is sufficient for us! Just leave it on its old + * transaction. + * + * In case (2), the buffer must not already exist as metadata + * --- that would violate write ordering (a transaction is free + * to write its data at any point, even before the previous + * committing transaction has committed). The caller must + * never, ever allow this to happen: there's nothing we can do + * about it in this layer. + */ + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); + if (jh->b_transaction) { + JBUFFER_TRACE(jh, "has transaction"); + if (jh->b_transaction != handle->h_transaction) { + JBUFFER_TRACE(jh, "belongs to older transaction"); + J_ASSERT_JH(jh, jh->b_transaction == + journal->j_committing_transaction); + + /* @@@ IS THIS TRUE ? */ + /* + * Not any more. Scenario: someone does a write() + * in data=journal mode. The buffer's transaction has + * moved into commit. Then someone does another + * write() to the file. We do the frozen data copyout + * and set b_next_transaction to point to j_running_t. + * And while we're in that state, someone does a + * writepage() in an attempt to pageout the same area + * of the file via a shared mapping. At present that + * calls journal_dirty_data(), and we get right here. + * It may be too late to journal the data. Simply + * falling through to the next test will suffice: the + * data will be dirty and wil be checkpointed. The + * ordering comments in the next comment block still + * apply. + */ + //J_ASSERT_JH(jh, jh->b_next_transaction == NULL); + + /* + * If we're journalling data, and this buffer was + * subject to a write(), it could be metadata, forget + * or shadow against the committing transaction. Now, + * someone has dirtied the same darn page via a mapping + * and it is being writepage()'d. + * We *could* just steal the page from commit, with some + * fancy locking there. Instead, we just skip it - + * don't tie the page's buffers to the new transaction + * at all. + * Implication: if we crash before the writepage() data + * is written into the filesystem, recovery will replay + * the write() data. + */ + if (jh->b_jlist != BJ_None && + jh->b_jlist != BJ_SyncData && + jh->b_jlist != BJ_Locked) { + JBUFFER_TRACE(jh, "Not stealing"); + goto no_journal; + } + + /* + * This buffer may be undergoing writeout in commit. We + * can't return from here and let the caller dirty it + * again because that can cause the write-out loop in + * commit to never terminate. + */ + if (buffer_dirty(bh)) { + get_bh(bh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + need_brelse = 1; + sync_dirty_buffer(bh); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); + /* The buffer may become locked again at any + time if it is redirtied */ + } + + /* journal_clean_data_list() may have got there first */ + if (jh->b_transaction != NULL) { + JBUFFER_TRACE(jh, "unfile from commit"); + __journal_temp_unlink_buffer(jh); + /* It still points to the committing + * transaction; move it to this one so + * that the refile assert checks are + * happy. */ + jh->b_transaction = handle->h_transaction; + } + /* The buffer will be refiled below */ + + } + /* + * Special case --- the buffer might actually have been + * allocated and then immediately deallocated in the previous, + * committing transaction, so might still be left on that + * transaction's metadata lists. + */ + if (jh->b_jlist != BJ_SyncData && jh->b_jlist != BJ_Locked) { + JBUFFER_TRACE(jh, "not on correct data list: unfile"); + J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow); + __journal_temp_unlink_buffer(jh); + jh->b_transaction = handle->h_transaction; + JBUFFER_TRACE(jh, "file as data"); + __journal_file_buffer(jh, handle->h_transaction, + BJ_SyncData); + } + } else { + JBUFFER_TRACE(jh, "not on a transaction"); + __journal_file_buffer(jh, handle->h_transaction, BJ_SyncData); + } +no_journal: + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + if (need_brelse) { + BUFFER_TRACE(bh, "brelse"); + __brelse(bh); + } + JBUFFER_TRACE(jh, "exit"); + journal_put_journal_head(jh); + return 0; +} + +/** + * int journal_dirty_metadata() - mark a buffer as containing dirty metadata + * @handle: transaction to add buffer to. + * @bh: buffer to mark + * + * mark dirty metadata which needs to be journaled as part of the current + * transaction. + * + * The buffer is placed on the transaction's metadata list and is marked + * as belonging to the transaction. + * + * Returns error number or 0 on success. + * + * Special care needs to be taken if the buffer already belongs to the + * current committing transaction (in which case we should have frozen + * data present for that commit). In that case, we don't relink the + * buffer: that only gets done when the old transaction finally + * completes its commit. + */ +int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + struct journal_head *jh = bh2jh(bh); + + jbd_debug(5, "journal_head %p\n", jh); + JBUFFER_TRACE(jh, "entry"); + if (is_handle_aborted(handle)) + goto out; + + jbd_lock_bh_state(bh); + + if (jh->b_modified == 0) { + /* + * This buffer's got modified and becoming part + * of the transaction. This needs to be done + * once a transaction -bzzz + */ + jh->b_modified = 1; + J_ASSERT_JH(jh, handle->h_buffer_credits > 0); + handle->h_buffer_credits--; + } + + /* + * fastpath, to avoid expensive locking. If this buffer is already + * on the running transaction's metadata list there is nothing to do. + * Nobody can take it off again because there is a handle open. + * I _think_ we're OK here with SMP barriers - a mistaken decision will + * result in this test being false, so we go in and take the locks. + */ + if (jh->b_transaction == transaction && jh->b_jlist == BJ_Metadata) { + JBUFFER_TRACE(jh, "fastpath"); + J_ASSERT_JH(jh, jh->b_transaction == + journal->j_running_transaction); + goto out_unlock_bh; + } + + set_buffer_jbddirty(bh); + + /* + * Metadata already on the current transaction list doesn't + * need to be filed. Metadata on another transaction's list must + * be committing, and will be refiled once the commit completes: + * leave it alone for now. + */ + if (jh->b_transaction != transaction) { + JBUFFER_TRACE(jh, "already on other transaction"); + J_ASSERT_JH(jh, jh->b_transaction == + journal->j_committing_transaction); + J_ASSERT_JH(jh, jh->b_next_transaction == transaction); + /* And this case is illegal: we can't reuse another + * transaction's data buffer, ever. */ + goto out_unlock_bh; + } + + /* That test should have eliminated the following case: */ + J_ASSERT_JH(jh, jh->b_frozen_data == 0); + + JBUFFER_TRACE(jh, "file as BJ_Metadata"); + spin_lock(&journal->j_list_lock); + __journal_file_buffer(jh, handle->h_transaction, BJ_Metadata); + spin_unlock(&journal->j_list_lock); +out_unlock_bh: + jbd_unlock_bh_state(bh); +out: + JBUFFER_TRACE(jh, "exit"); + return 0; +} + +/* + * journal_release_buffer: undo a get_write_access without any buffer + * updates, if the update decided in the end that it didn't need access. + * + */ +void +journal_release_buffer(handle_t *handle, struct buffer_head *bh) +{ + BUFFER_TRACE(bh, "entry"); +} + +/** + * void journal_forget() - bforget() for potentially-journaled buffers. + * @handle: transaction handle + * @bh: bh to 'forget' + * + * We can only do the bforget if there are no commits pending against the + * buffer. If the buffer is dirty in the current running transaction we + * can safely unlink it. + * + * bh may not be a journalled buffer at all - it may be a non-JBD + * buffer which came off the hashtable. Check for this. + * + * Decrements bh->b_count by one. + * + * Allow this call even if the handle has aborted --- it may be part of + * the caller's cleanup after an abort. + */ +int journal_forget (handle_t *handle, struct buffer_head *bh) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + struct journal_head *jh; + int drop_reserve = 0; + int err = 0; + + BUFFER_TRACE(bh, "entry"); + + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); + + if (!buffer_jbd(bh)) + goto not_jbd; + jh = bh2jh(bh); + + /* Critical error: attempting to delete a bitmap buffer, maybe? + * Don't do any jbd operations, and return an error. */ + if (!J_EXPECT_JH(jh, !jh->b_committed_data, + "inconsistent data on disk")) { + err = -EIO; + goto not_jbd; + } + + /* + * The buffer's going from the transaction, we must drop + * all references -bzzz + */ + jh->b_modified = 0; + + if (jh->b_transaction == handle->h_transaction) { + J_ASSERT_JH(jh, !jh->b_frozen_data); + + /* If we are forgetting a buffer which is already part + * of this transaction, then we can just drop it from + * the transaction immediately. */ + clear_buffer_dirty(bh); + clear_buffer_jbddirty(bh); + + JBUFFER_TRACE(jh, "belongs to current transaction: unfile"); + + drop_reserve = 1; + + /* + * We are no longer going to journal this buffer. + * However, the commit of this transaction is still + * important to the buffer: the delete that we are now + * processing might obsolete an old log entry, so by + * committing, we can satisfy the buffer's checkpoint. + * + * So, if we have a checkpoint on the buffer, we should + * now refile the buffer on our BJ_Forget list so that + * we know to remove the checkpoint after we commit. + */ + + if (jh->b_cp_transaction) { + __journal_temp_unlink_buffer(jh); + __journal_file_buffer(jh, transaction, BJ_Forget); + } else { + __journal_unfile_buffer(jh); + journal_remove_journal_head(bh); + __brelse(bh); + if (!buffer_jbd(bh)) { + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + __bforget(bh); + goto drop; + } + } + } else if (jh->b_transaction) { + J_ASSERT_JH(jh, (jh->b_transaction == + journal->j_committing_transaction)); + /* However, if the buffer is still owned by a prior + * (committing) transaction, we can't drop it yet... */ + JBUFFER_TRACE(jh, "belongs to older transaction"); + /* ... but we CAN drop it from the new transaction if we + * have also modified it since the original commit. */ + + if (jh->b_next_transaction) { + J_ASSERT(jh->b_next_transaction == transaction); + jh->b_next_transaction = NULL; + drop_reserve = 1; + } + } + +not_jbd: + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + __brelse(bh); +drop: + if (drop_reserve) { + /* no need to reserve log space for this block -bzzz */ + handle->h_buffer_credits++; + } + return err; +} + +/** + * int journal_stop() - complete a transaction + * @handle: tranaction to complete. + * + * All done for a particular handle. + * + * There is not much action needed here. We just return any remaining + * buffer credits to the transaction and remove the handle. The only + * complication is that we need to start a commit operation if the + * filesystem is marked for synchronous update. + * + * journal_stop itself will not usually return an error, but it may + * do so in unusual circumstances. In particular, expect it to + * return -EIO if a journal_abort has been executed since the + * transaction began. + */ +int journal_stop(handle_t *handle) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + int old_handle_count, err; + pid_t pid; + + J_ASSERT(transaction->t_updates > 0); + J_ASSERT(journal_current_handle() == handle); + + if (is_handle_aborted(handle)) + err = -EIO; + else + err = 0; + + if (--handle->h_ref > 0) { + jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, + handle->h_ref); + return err; + } + + jbd_debug(4, "Handle %p going down\n", handle); + + /* + * Implement synchronous transaction batching. If the handle + * was synchronous, don't force a commit immediately. Let's + * yield and let another thread piggyback onto this transaction. + * Keep doing that while new threads continue to arrive. + * It doesn't cost much - we're about to run a commit and sleep + * on IO anyway. Speeds up many-threaded, many-dir operations + * by 30x or more... + * + * But don't do this if this process was the most recent one to + * perform a synchronous write. We do this to detect the case where a + * single process is doing a stream of sync writes. No point in waiting + * for joiners in that case. + */ + pid = current->pid; + if (handle->h_sync && journal->j_last_sync_writer != pid) { + journal->j_last_sync_writer = pid; + do { + old_handle_count = transaction->t_handle_count; + schedule_timeout_uninterruptible(1); + } while (old_handle_count != transaction->t_handle_count); + } + + current->journal_info = NULL; + spin_lock(&journal->j_state_lock); + spin_lock(&transaction->t_handle_lock); + transaction->t_outstanding_credits -= handle->h_buffer_credits; + transaction->t_updates--; + if (!transaction->t_updates) { + wake_up(&journal->j_wait_updates); + if (journal->j_barrier_count) + wake_up(&journal->j_wait_transaction_locked); + } + + /* + * If the handle is marked SYNC, we need to set another commit + * going! We also want to force a commit if the current + * transaction is occupying too much of the log, or if the + * transaction is too old now. + */ + if (handle->h_sync || + transaction->t_outstanding_credits > + journal->j_max_transaction_buffers || + time_after_eq(jiffies, transaction->t_expires)) { + /* Do this even for aborted journals: an abort still + * completes the commit thread, it just doesn't write + * anything to disk. */ + tid_t tid = transaction->t_tid; + + spin_unlock(&transaction->t_handle_lock); + jbd_debug(2, "transaction too old, requesting commit for " + "handle %p\n", handle); + /* This is non-blocking */ + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); + + /* + * Special case: JFS_SYNC synchronous updates require us + * to wait for the commit to complete. + */ + if (handle->h_sync && !(current->flags & PF_MEMALLOC)) + err = log_wait_commit(journal, tid); + } else { + spin_unlock(&transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); + } + + jbd_free_handle(handle); + return err; +} + +/**int journal_force_commit() - force any uncommitted transactions + * @journal: journal to force + * + * For synchronous operations: force any uncommitted transactions + * to disk. May seem kludgy, but it reuses all the handle batching + * code in a very simple manner. + */ +int journal_force_commit(journal_t *journal) +{ + handle_t *handle; + int ret; + + handle = journal_start(journal, 1); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + } else { + handle->h_sync = 1; + ret = journal_stop(handle); + } + return ret; +} + +/* + * + * List management code snippets: various functions for manipulating the + * transaction buffer lists. + * + */ + +/* + * Append a buffer to a transaction list, given the transaction's list head + * pointer. + * + * j_list_lock is held. + * + * jbd_lock_bh_state(jh2bh(jh)) is held. + */ + +static inline void +__blist_add_buffer(struct journal_head **list, struct journal_head *jh) +{ + if (!*list) { + jh->b_tnext = jh->b_tprev = jh; + *list = jh; + } else { + /* Insert at the tail of the list to preserve order */ + struct journal_head *first = *list, *last = first->b_tprev; + jh->b_tprev = last; + jh->b_tnext = first; + last->b_tnext = first->b_tprev = jh; + } +} + +/* + * Remove a buffer from a transaction list, given the transaction's list + * head pointer. + * + * Called with j_list_lock held, and the journal may not be locked. + * + * jbd_lock_bh_state(jh2bh(jh)) is held. + */ + +static inline void +__blist_del_buffer(struct journal_head **list, struct journal_head *jh) +{ + if (*list == jh) { + *list = jh->b_tnext; + if (*list == jh) + *list = NULL; + } + jh->b_tprev->b_tnext = jh->b_tnext; + jh->b_tnext->b_tprev = jh->b_tprev; +} + +/* + * Remove a buffer from the appropriate transaction list. + * + * Note that this function can *change* the value of + * bh->b_transaction->t_sync_datalist, t_buffers, t_forget, + * t_iobuf_list, t_shadow_list, t_log_list or t_reserved_list. If the caller + * is holding onto a copy of one of thee pointers, it could go bad. + * Generally the caller needs to re-read the pointer from the transaction_t. + * + * Called under j_list_lock. The journal may not be locked. + */ +void __journal_temp_unlink_buffer(struct journal_head *jh) +{ + struct journal_head **list = NULL; + transaction_t *transaction; + struct buffer_head *bh = jh2bh(jh); + + J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); + transaction = jh->b_transaction; + if (transaction) + assert_spin_locked(&transaction->t_journal->j_list_lock); + + J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); + if (jh->b_jlist != BJ_None) + J_ASSERT_JH(jh, transaction != 0); + + switch (jh->b_jlist) { + case BJ_None: + return; + case BJ_SyncData: + list = &transaction->t_sync_datalist; + break; + case BJ_Metadata: + transaction->t_nr_buffers--; + J_ASSERT_JH(jh, transaction->t_nr_buffers >= 0); + list = &transaction->t_buffers; + break; + case BJ_Forget: + list = &transaction->t_forget; + break; + case BJ_IO: + list = &transaction->t_iobuf_list; + break; + case BJ_Shadow: + list = &transaction->t_shadow_list; + break; + case BJ_LogCtl: + list = &transaction->t_log_list; + break; + case BJ_Reserved: + list = &transaction->t_reserved_list; + break; + case BJ_Locked: + list = &transaction->t_locked_list; + break; + } + + __blist_del_buffer(list, jh); + jh->b_jlist = BJ_None; + if (test_clear_buffer_jbddirty(bh)) + mark_buffer_dirty(bh); /* Expose it to the VM */ +} + +void __journal_unfile_buffer(struct journal_head *jh) +{ + __journal_temp_unlink_buffer(jh); + jh->b_transaction = NULL; +} + +void journal_unfile_buffer(journal_t *journal, struct journal_head *jh) +{ + jbd_lock_bh_state(jh2bh(jh)); + spin_lock(&journal->j_list_lock); + __journal_unfile_buffer(jh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(jh2bh(jh)); +} + +/* + * Called from journal_try_to_free_buffers(). + * + * Called under jbd_lock_bh_state(bh) + */ +static void +__journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) +{ + struct journal_head *jh; + + jh = bh2jh(bh); + + if (buffer_locked(bh) || buffer_dirty(bh)) + goto out; + + if (jh->b_next_transaction != 0) + goto out; + + spin_lock(&journal->j_list_lock); + if (jh->b_transaction != 0 && jh->b_cp_transaction == 0) { + if (jh->b_jlist == BJ_SyncData || jh->b_jlist == BJ_Locked) { + /* A written-back ordered data buffer */ + JBUFFER_TRACE(jh, "release data"); + __journal_unfile_buffer(jh); + journal_remove_journal_head(bh); + __brelse(bh); + } + } else if (jh->b_cp_transaction != 0 && jh->b_transaction == 0) { + /* written-back checkpointed metadata buffer */ + if (jh->b_jlist == BJ_None) { + JBUFFER_TRACE(jh, "remove from checkpoint list"); + __journal_remove_checkpoint(jh); + journal_remove_journal_head(bh); + __brelse(bh); + } + } + spin_unlock(&journal->j_list_lock); +out: + return; +} + + +/** + * int journal_try_to_free_buffers() - try to free page buffers. + * @journal: journal for operation + * @page: to try and free + * @unused_gfp_mask: unused + * + * + * For all the buffers on this page, + * if they are fully written out ordered data, move them onto BUF_CLEAN + * so try_to_free_buffers() can reap them. + * + * This function returns non-zero if we wish try_to_free_buffers() + * to be called. We do this if the page is releasable by try_to_free_buffers(). + * We also do it if the page has locked or dirty buffers and the caller wants + * us to perform sync or async writeout. + * + * This complicates JBD locking somewhat. We aren't protected by the + * BKL here. We wish to remove the buffer from its committing or + * running transaction's ->t_datalist via __journal_unfile_buffer. + * + * This may *change* the value of transaction_t->t_datalist, so anyone + * who looks at t_datalist needs to lock against this function. + * + * Even worse, someone may be doing a journal_dirty_data on this + * buffer. So we need to lock against that. journal_dirty_data() + * will come out of the lock with the buffer dirty, which makes it + * ineligible for release here. + * + * Who else is affected by this? hmm... Really the only contender + * is do_get_write_access() - it could be looking at the buffer while + * journal_try_to_free_buffer() is changing its state. But that + * cannot happen because we never reallocate freed data as metadata + * while the data is part of a transaction. Yes? + */ +int journal_try_to_free_buffers(journal_t *journal, + struct page *page, gfp_t unused_gfp_mask) +{ + struct buffer_head *head; + struct buffer_head *bh; + int ret = 0; + + J_ASSERT(PageLocked(page)); + + head = page_buffers(page); + bh = head; + do { + struct journal_head *jh; + + /* + * We take our own ref against the journal_head here to avoid + * having to add tons of locking around each instance of + * journal_remove_journal_head() and journal_put_journal_head(). + */ + jh = journal_grab_journal_head(bh); + if (!jh) + continue; + + jbd_lock_bh_state(bh); + __journal_try_to_free_buffer(journal, bh); + journal_put_journal_head(jh); + jbd_unlock_bh_state(bh); + if (buffer_jbd(bh)) + goto busy; + } while ((bh = bh->b_this_page) != head); + ret = try_to_free_buffers(page); +busy: + return ret; +} + +/* + * This buffer is no longer needed. If it is on an older transaction's + * checkpoint list we need to record it on this transaction's forget list + * to pin this buffer (and hence its checkpointing transaction) down until + * this transaction commits. If the buffer isn't on a checkpoint list, we + * release it. + * Returns non-zero if JBD no longer has an interest in the buffer. + * + * Called under j_list_lock. + * + * Called under jbd_lock_bh_state(bh). + */ +static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) +{ + int may_free = 1; + struct buffer_head *bh = jh2bh(jh); + + __journal_unfile_buffer(jh); + + if (jh->b_cp_transaction) { + JBUFFER_TRACE(jh, "on running+cp transaction"); + __journal_file_buffer(jh, transaction, BJ_Forget); + clear_buffer_jbddirty(bh); + may_free = 0; + } else { + JBUFFER_TRACE(jh, "on running transaction"); + journal_remove_journal_head(bh); + __brelse(bh); + } + return may_free; +} + +/* + * journal_invalidatepage + * + * This code is tricky. It has a number of cases to deal with. + * + * There are two invariants which this code relies on: + * + * i_size must be updated on disk before we start calling invalidatepage on the + * data. + * + * This is done in ext3 by defining an ext3_setattr method which + * updates i_size before truncate gets going. By maintaining this + * invariant, we can be sure that it is safe to throw away any buffers + * attached to the current transaction: once the transaction commits, + * we know that the data will not be needed. + * + * Note however that we can *not* throw away data belonging to the + * previous, committing transaction! + * + * Any disk blocks which *are* part of the previous, committing + * transaction (and which therefore cannot be discarded immediately) are + * not going to be reused in the new running transaction + * + * The bitmap committed_data images guarantee this: any block which is + * allocated in one transaction and removed in the next will be marked + * as in-use in the committed_data bitmap, so cannot be reused until + * the next transaction to delete the block commits. This means that + * leaving committing buffers dirty is quite safe: the disk blocks + * cannot be reallocated to a different file and so buffer aliasing is + * not possible. + * + * + * The above applies mainly to ordered data mode. In writeback mode we + * don't make guarantees about the order in which data hits disk --- in + * particular we don't guarantee that new dirty data is flushed before + * transaction commit --- so it is always safe just to discard data + * immediately in that mode. --sct + */ + +/* + * The journal_unmap_buffer helper function returns zero if the buffer + * concerned remains pinned as an anonymous buffer belonging to an older + * transaction. + * + * We're outside-transaction here. Either or both of j_running_transaction + * and j_committing_transaction may be NULL. + */ +static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) +{ + transaction_t *transaction; + struct journal_head *jh; + int may_free = 1; + int ret; + + BUFFER_TRACE(bh, "entry"); + + /* + * It is safe to proceed here without the j_list_lock because the + * buffers cannot be stolen by try_to_free_buffers as long as we are + * holding the page lock. --sct + */ + + if (!buffer_jbd(bh)) + goto zap_buffer_unlocked; + + spin_lock(&journal->j_state_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); + + jh = journal_grab_journal_head(bh); + if (!jh) + goto zap_buffer_no_jh; + + transaction = jh->b_transaction; + if (transaction == NULL) { + /* First case: not on any transaction. If it + * has no checkpoint link, then we can zap it: + * it's a writeback-mode buffer so we don't care + * if it hits disk safely. */ + if (!jh->b_cp_transaction) { + JBUFFER_TRACE(jh, "not on any transaction: zap"); + goto zap_buffer; + } + + if (!buffer_dirty(bh)) { + /* bdflush has written it. We can drop it now */ + goto zap_buffer; + } + + /* OK, it must be in the journal but still not + * written fully to disk: it's metadata or + * journaled data... */ + + if (journal->j_running_transaction) { + /* ... and once the current transaction has + * committed, the buffer won't be needed any + * longer. */ + JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); + ret = __dispose_buffer(jh, + journal->j_running_transaction); + journal_put_journal_head(jh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); + return ret; + } else { + /* There is no currently-running transaction. So the + * orphan record which we wrote for this file must have + * passed into commit. We must attach this buffer to + * the committing transaction, if it exists. */ + if (journal->j_committing_transaction) { + JBUFFER_TRACE(jh, "give to committing trans"); + ret = __dispose_buffer(jh, + journal->j_committing_transaction); + journal_put_journal_head(jh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); + return ret; + } else { + /* The orphan record's transaction has + * committed. We can cleanse this buffer */ + clear_buffer_jbddirty(bh); + goto zap_buffer; + } + } + } else if (transaction == journal->j_committing_transaction) { + if (jh->b_jlist == BJ_Locked) { + /* + * The buffer is on the committing transaction's locked + * list. We have the buffer locked, so I/O has + * completed. So we can nail the buffer now. + */ + may_free = __dispose_buffer(jh, transaction); + goto zap_buffer; + } + /* + * If it is committing, we simply cannot touch it. We + * can remove it's next_transaction pointer from the + * running transaction if that is set, but nothing + * else. */ + JBUFFER_TRACE(jh, "on committing transaction"); + set_buffer_freed(bh); + if (jh->b_next_transaction) { + J_ASSERT(jh->b_next_transaction == + journal->j_running_transaction); + jh->b_next_transaction = NULL; + } + journal_put_journal_head(jh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); + return 0; + } else { + /* Good, the buffer belongs to the running transaction. + * We are writing our own transaction's data, not any + * previous one's, so it is safe to throw it away + * (remember that we expect the filesystem to have set + * i_size already for this truncate so recovery will not + * expose the disk blocks we are discarding here.) */ + J_ASSERT_JH(jh, transaction == journal->j_running_transaction); + may_free = __dispose_buffer(jh, transaction); + } + +zap_buffer: + journal_put_journal_head(jh); +zap_buffer_no_jh: + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); +zap_buffer_unlocked: + clear_buffer_dirty(bh); + J_ASSERT_BH(bh, !buffer_jbddirty(bh)); + clear_buffer_mapped(bh); + clear_buffer_req(bh); + clear_buffer_new(bh); + bh->b_bdev = NULL; + return may_free; +} + +/** + * void journal_invalidatepage() + * @journal: journal to use for flush... + * @page: page to flush + * @offset: length of page to invalidate. + * + * Reap page buffers containing data after offset in page. + * + */ +void journal_invalidatepage(journal_t *journal, + struct page *page, + unsigned long offset) +{ + struct buffer_head *head, *bh, *next; + unsigned int curr_off = 0; + int may_free = 1; + + if (!PageLocked(page)) + BUG(); + if (!page_has_buffers(page)) + return; + + /* We will potentially be playing with lists other than just the + * data lists (especially for journaled data mode), so be + * cautious in our locking. */ + + head = bh = page_buffers(page); + do { + unsigned int next_off = curr_off + bh->b_size; + next = bh->b_this_page; + + if (offset <= curr_off) { + /* This block is wholly outside the truncation point */ + lock_buffer(bh); + may_free &= journal_unmap_buffer(journal, bh); + unlock_buffer(bh); + } + curr_off = next_off; + bh = next; + + } while (bh != head); + + if (!offset) { + if (may_free && try_to_free_buffers(page)) + J_ASSERT(!page_has_buffers(page)); + } +} + +/* + * File a buffer on the given transaction list. + */ +void __journal_file_buffer(struct journal_head *jh, + transaction_t *transaction, int jlist) +{ + struct journal_head **list = NULL; + int was_dirty = 0; + struct buffer_head *bh = jh2bh(jh); + + J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); + assert_spin_locked(&transaction->t_journal->j_list_lock); + + J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); + J_ASSERT_JH(jh, jh->b_transaction == transaction || + jh->b_transaction == 0); + + if (jh->b_transaction && jh->b_jlist == jlist) + return; + + /* The following list of buffer states needs to be consistent + * with __jbd_unexpected_dirty_buffer()'s handling of dirty + * state. */ + + if (jlist == BJ_Metadata || jlist == BJ_Reserved || + jlist == BJ_Shadow || jlist == BJ_Forget) { + if (test_clear_buffer_dirty(bh) || + test_clear_buffer_jbddirty(bh)) + was_dirty = 1; + } + + if (jh->b_transaction) + __journal_temp_unlink_buffer(jh); + jh->b_transaction = transaction; + + switch (jlist) { + case BJ_None: + J_ASSERT_JH(jh, !jh->b_committed_data); + J_ASSERT_JH(jh, !jh->b_frozen_data); + return; + case BJ_SyncData: + list = &transaction->t_sync_datalist; + break; + case BJ_Metadata: + transaction->t_nr_buffers++; + list = &transaction->t_buffers; + break; + case BJ_Forget: + list = &transaction->t_forget; + break; + case BJ_IO: + list = &transaction->t_iobuf_list; + break; + case BJ_Shadow: + list = &transaction->t_shadow_list; + break; + case BJ_LogCtl: + list = &transaction->t_log_list; + break; + case BJ_Reserved: + list = &transaction->t_reserved_list; + break; + case BJ_Locked: + list = &transaction->t_locked_list; + break; + } + + __blist_add_buffer(list, jh); + jh->b_jlist = jlist; + + if (was_dirty) + set_buffer_jbddirty(bh); +} + +void journal_file_buffer(struct journal_head *jh, + transaction_t *transaction, int jlist) +{ + jbd_lock_bh_state(jh2bh(jh)); + spin_lock(&transaction->t_journal->j_list_lock); + __journal_file_buffer(jh, transaction, jlist); + spin_unlock(&transaction->t_journal->j_list_lock); + jbd_unlock_bh_state(jh2bh(jh)); +} + +/* + * Remove a buffer from its current buffer list in preparation for + * dropping it from its current transaction entirely. If the buffer has + * already started to be used by a subsequent transaction, refile the + * buffer on that transaction's metadata list. + * + * Called under journal->j_list_lock + * + * Called under jbd_lock_bh_state(jh2bh(jh)) + */ +void __journal_refile_buffer(struct journal_head *jh) +{ + int was_dirty; + struct buffer_head *bh = jh2bh(jh); + + J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); + if (jh->b_transaction) + assert_spin_locked(&jh->b_transaction->t_journal->j_list_lock); + + /* If the buffer is now unused, just drop it. */ + if (jh->b_next_transaction == NULL) { + __journal_unfile_buffer(jh); + return; + } + + /* + * It has been modified by a later transaction: add it to the new + * transaction's metadata list. + */ + + was_dirty = test_clear_buffer_jbddirty(bh); + __journal_temp_unlink_buffer(jh); + jh->b_transaction = jh->b_next_transaction; + jh->b_next_transaction = NULL; + __journal_file_buffer(jh, jh->b_transaction, + was_dirty ? BJ_Metadata : BJ_Reserved); + J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); + + if (was_dirty) + set_buffer_jbddirty(bh); +} + +/* + * For the unlocked version of this call, also make sure that any + * hanging journal_head is cleaned up if necessary. + * + * __journal_refile_buffer is usually called as part of a single locked + * operation on a buffer_head, in which the caller is probably going to + * be hooking the journal_head onto other lists. In that case it is up + * to the caller to remove the journal_head if necessary. For the + * unlocked journal_refile_buffer call, the caller isn't going to be + * doing anything else to the buffer so we need to do the cleanup + * ourselves to avoid a jh leak. + * + * *** The journal_head may be freed by this call! *** + */ +void journal_refile_buffer(journal_t *journal, struct journal_head *jh) +{ + struct buffer_head *bh = jh2bh(jh); + + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); + + __journal_refile_buffer(jh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); + + spin_unlock(&journal->j_list_lock); + __brelse(bh); +} diff --git a/include/linux/ext4_jbd2.h b/include/linux/ext4_jbd2.h new file mode 100644 index 000000000000..3dbf6c779037 --- /dev/null +++ b/include/linux/ext4_jbd2.h @@ -0,0 +1,268 @@ +/* + * linux/include/linux/ext4_jbd.h + * + * Written by Stephen C. Tweedie , 1999 + * + * Copyright 1998--1999 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Ext4-specific journaling extensions. + */ + +#ifndef _LINUX_EXT4_JBD_H +#define _LINUX_EXT4_JBD_H + +#include +#include +#include + +#define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal) + +/* Define the number of blocks we need to account to a transaction to + * modify one block of data. + * + * We may have to touch one inode, one bitmap buffer, up to three + * indirection blocks, the group and superblock summaries, and the data + * block to complete the transaction. */ + +#define EXT4_SINGLEDATA_TRANS_BLOCKS 8U + +/* Extended attribute operations touch at most two data buffers, + * two bitmap buffers, and two group summaries, in addition to the inode + * and the superblock, which are already accounted for. */ + +#define EXT4_XATTR_TRANS_BLOCKS 6U + +/* Define the minimum size for a transaction which modifies data. This + * needs to take into account the fact that we may end up modifying two + * quota files too (one for the group, one for the user quota). The + * superblock only gets updated once, of course, so don't bother + * counting that again for the quota updates. */ + +#define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS + \ + EXT4_XATTR_TRANS_BLOCKS - 2 + \ + 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) + +/* 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. */ + +#define EXT4_DELETE_TRANS_BLOCKS(sb) (2 * EXT4_DATA_TRANS_BLOCKS(sb) + 64) + +/* Define an arbitrary limit for the amount of data we will anticipate + * writing to any given transaction. For unbounded transactions such as + * write(2) and truncate(2) we can write more than this, but we always + * start off at the maximum transaction size and grow the transaction + * optimistically as we go. */ + +#define EXT4_MAX_TRANS_DATA 64U + +/* We break up a large truncate or write transaction once the handle's + * buffer credits gets this low, we need either to extend the + * transaction or to start a new one. Reserve enough space here for + * inode, bitmap, superblock, group and indirection updates for at least + * one block, plus two quota updates. Quota allocations are not + * needed. */ + +#define EXT4_RESERVE_TRANS_BLOCKS 12U + +#define EXT4_INDEX_EXTRA_TRANS_BLOCKS 8 + +#ifdef CONFIG_QUOTA +/* Amount of blocks needed for quota update - we know that the structure was + * allocated so we need to update only inode+data */ +#define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0) +/* Amount of blocks needed for quota insert/delete - we do some block writes + * but inode, sb and group updates are done only once */ +#define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ + (EXT4_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0) +#define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ + (EXT4_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0) +#else +#define EXT4_QUOTA_TRANS_BLOCKS(sb) 0 +#define EXT4_QUOTA_INIT_BLOCKS(sb) 0 +#define EXT4_QUOTA_DEL_BLOCKS(sb) 0 +#endif + +int +ext4_mark_iloc_dirty(handle_t *handle, + struct inode *inode, + struct ext4_iloc *iloc); + +/* + * On success, We end up with an outstanding reference count against + * iloc->bh. This _must_ be cleaned up later. + */ + +int ext4_reserve_inode_write(handle_t *handle, struct inode *inode, + struct ext4_iloc *iloc); + +int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode); + +/* + * Wrapper functions with which ext4 calls into JBD. The intent here is + * to allow these to be turned into appropriate stubs so ext4 can control + * ext2 filesystems, so ext2+ext4 systems only nee one fs. This work hasn't + * been done yet. + */ + +void ext4_journal_abort_handle(const char *caller, const char *err_fn, + struct buffer_head *bh, handle_t *handle, int err); + +static inline int +__ext4_journal_get_undo_access(const char *where, handle_t *handle, + struct buffer_head *bh) +{ + int err = journal_get_undo_access(handle, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext4_journal_get_write_access(const char *where, handle_t *handle, + struct buffer_head *bh) +{ + int err = journal_get_write_access(handle, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline void +ext4_journal_release_buffer(handle_t *handle, struct buffer_head *bh) +{ + journal_release_buffer(handle, bh); +} + +static inline int +__ext4_journal_forget(const char *where, handle_t *handle, struct buffer_head *bh) +{ + int err = journal_forget(handle, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext4_journal_revoke(const char *where, handle_t *handle, + unsigned long blocknr, struct buffer_head *bh) +{ + int err = journal_revoke(handle, blocknr, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext4_journal_get_create_access(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = journal_get_create_access(handle, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext4_journal_dirty_metadata(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = journal_dirty_metadata(handle, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + + +#define ext4_journal_get_undo_access(handle, bh) \ + __ext4_journal_get_undo_access(__FUNCTION__, (handle), (bh)) +#define ext4_journal_get_write_access(handle, bh) \ + __ext4_journal_get_write_access(__FUNCTION__, (handle), (bh)) +#define ext4_journal_revoke(handle, blocknr, bh) \ + __ext4_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh)) +#define ext4_journal_get_create_access(handle, bh) \ + __ext4_journal_get_create_access(__FUNCTION__, (handle), (bh)) +#define ext4_journal_dirty_metadata(handle, bh) \ + __ext4_journal_dirty_metadata(__FUNCTION__, (handle), (bh)) +#define ext4_journal_forget(handle, bh) \ + __ext4_journal_forget(__FUNCTION__, (handle), (bh)) + +int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh); + +handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); +int __ext4_journal_stop(const char *where, handle_t *handle); + +static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks) +{ + return ext4_journal_start_sb(inode->i_sb, nblocks); +} + +#define ext4_journal_stop(handle) \ + __ext4_journal_stop(__FUNCTION__, (handle)) + +static inline handle_t *ext4_journal_current_handle(void) +{ + return journal_current_handle(); +} + +static inline int ext4_journal_extend(handle_t *handle, int nblocks) +{ + return journal_extend(handle, nblocks); +} + +static inline int ext4_journal_restart(handle_t *handle, int nblocks) +{ + return journal_restart(handle, nblocks); +} + +static inline int ext4_journal_blocks_per_page(struct inode *inode) +{ + return journal_blocks_per_page(inode); +} + +static inline int ext4_journal_force_commit(journal_t *journal) +{ + return journal_force_commit(journal); +} + +/* super.c */ +int ext4_force_commit(struct super_block *sb); + +static inline int ext4_should_journal_data(struct inode *inode) +{ + if (!S_ISREG(inode->i_mode)) + return 1; + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) + return 1; + if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) + return 1; + return 0; +} + +static inline int ext4_should_order_data(struct inode *inode) +{ + if (!S_ISREG(inode->i_mode)) + return 0; + if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) + return 0; + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) + return 1; + return 0; +} + +static inline int ext4_should_writeback_data(struct inode *inode) +{ + if (!S_ISREG(inode->i_mode)) + return 0; + if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) + return 0; + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) + return 1; + return 0; +} + +#endif /* _LINUX_EXT4_JBD_H */ diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h new file mode 100644 index 000000000000..fe89444b1c6f --- /dev/null +++ b/include/linux/jbd2.h @@ -0,0 +1,1098 @@ +/* + * linux/include/linux/jbd.h + * + * Written by Stephen C. Tweedie + * + * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Definitions for transaction data structures for the buffer cache + * filesystem journaling support. + */ + +#ifndef _LINUX_JBD_H +#define _LINUX_JBD_H + +/* Allow this file to be included directly into e2fsprogs */ +#ifndef __KERNEL__ +#include "jfs_compat.h" +#define JFS_DEBUG +#define jfs_debug jbd_debug +#else + +#include +#include +#include +#include +#include +#include +#include + +#include +#endif + +#define journal_oom_retry 1 + +/* + * Define JBD_PARANIOD_IOFAIL to cause a kernel BUG() if ext3 finds + * certain classes of error which can occur due to failed IOs. Under + * normal use we want ext3 to continue after such errors, because + * hardware _can_ fail, but for debugging purposes when running tests on + * known-good hardware we may want to trap these errors. + */ +#undef JBD_PARANOID_IOFAIL + +/* + * The default maximum commit age, in seconds. + */ +#define JBD_DEFAULT_MAX_COMMIT_AGE 5 + +#ifdef CONFIG_JBD_DEBUG +/* + * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal + * consistency checks. By default we don't do this unless + * CONFIG_JBD_DEBUG is on. + */ +#define JBD_EXPENSIVE_CHECKING +extern int journal_enable_debug; + +#define jbd_debug(n, f, a...) \ + do { \ + if ((n) <= journal_enable_debug) { \ + printk (KERN_DEBUG "(%s, %d): %s: ", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (f, ## a); \ + } \ + } while (0) +#else +#define jbd_debug(f, a...) /**/ +#endif + +extern void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry); +extern void * jbd_slab_alloc(size_t size, gfp_t flags); +extern void jbd_slab_free(void *ptr, size_t size); + +#define jbd_kmalloc(size, flags) \ + __jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry) +#define jbd_rep_kmalloc(size, flags) \ + __jbd_kmalloc(__FUNCTION__, (size), (flags), 1) + +#define JFS_MIN_JOURNAL_BLOCKS 1024 + +#ifdef __KERNEL__ + +/** + * typedef handle_t - The handle_t type represents a single atomic update being performed by some process. + * + * All filesystem modifications made by the process go + * through this handle. Recursive operations (such as quota operations) + * are gathered into a single update. + * + * The buffer credits field is used to account for journaled buffers + * being modified by the running process. To ensure that there is + * enough log space for all outstanding operations, we need to limit the + * number of outstanding buffers possible at any time. When the + * operation completes, any buffer credits not used are credited back to + * the transaction, so that at all times we know how many buffers the + * outstanding updates on a transaction might possibly touch. + * + * This is an opaque datatype. + **/ +typedef struct handle_s handle_t; /* Atomic operation type */ + + +/** + * typedef journal_t - The journal_t maintains all of the journaling state information for a single filesystem. + * + * journal_t is linked to from the fs superblock structure. + * + * We use the journal_t to keep track of all outstanding transaction + * activity on the filesystem, and to manage the state of the log + * writing process. + * + * This is an opaque datatype. + **/ +typedef struct journal_s journal_t; /* Journal control structure */ +#endif + +/* + * Internal structures used by the logging mechanism: + */ + +#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ + +/* + * On-disk structures + */ + +/* + * Descriptor block types: + */ + +#define JFS_DESCRIPTOR_BLOCK 1 +#define JFS_COMMIT_BLOCK 2 +#define JFS_SUPERBLOCK_V1 3 +#define JFS_SUPERBLOCK_V2 4 +#define JFS_REVOKE_BLOCK 5 + +/* + * Standard header for all descriptor blocks: + */ +typedef struct journal_header_s +{ + __be32 h_magic; + __be32 h_blocktype; + __be32 h_sequence; +} journal_header_t; + + +/* + * The block tag: used to describe a single buffer in the journal + */ +typedef struct journal_block_tag_s +{ + __be32 t_blocknr; /* The on-disk block number */ + __be32 t_flags; /* See below */ +} journal_block_tag_t; + +/* + * The revoke descriptor: used on disk to describe a series of blocks to + * be revoked from the log + */ +typedef struct journal_revoke_header_s +{ + journal_header_t r_header; + __be32 r_count; /* Count of bytes used in the block */ +} journal_revoke_header_t; + + +/* Definitions for the journal tag flags word: */ +#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */ +#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */ +#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */ +#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ + + +/* + * The journal superblock. All fields are in big-endian byte order. + */ +typedef struct journal_superblock_s +{ +/* 0x0000 */ + journal_header_t s_header; + +/* 0x000C */ + /* Static information describing the journal */ + __be32 s_blocksize; /* journal device blocksize */ + __be32 s_maxlen; /* total blocks in journal file */ + __be32 s_first; /* first block of log information */ + +/* 0x0018 */ + /* Dynamic information describing the current state of the log */ + __be32 s_sequence; /* first commit ID expected in log */ + __be32 s_start; /* blocknr of start of log */ + +/* 0x0020 */ + /* Error value, as set by journal_abort(). */ + __be32 s_errno; + +/* 0x0024 */ + /* Remaining fields are only valid in a version-2 superblock */ + __be32 s_feature_compat; /* compatible feature set */ + __be32 s_feature_incompat; /* incompatible feature set */ + __be32 s_feature_ro_compat; /* readonly-compatible feature set */ +/* 0x0030 */ + __u8 s_uuid[16]; /* 128-bit uuid for journal */ + +/* 0x0040 */ + __be32 s_nr_users; /* Nr of filesystems sharing log */ + + __be32 s_dynsuper; /* Blocknr of dynamic superblock copy*/ + +/* 0x0048 */ + __be32 s_max_transaction; /* Limit of journal blocks per trans.*/ + __be32 s_max_trans_data; /* Limit of data blocks per trans. */ + +/* 0x0050 */ + __u32 s_padding[44]; + +/* 0x0100 */ + __u8 s_users[16*48]; /* ids of all fs'es sharing the log */ +/* 0x0400 */ +} journal_superblock_t; + +#define JFS_HAS_COMPAT_FEATURE(j,mask) \ + ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask)))) +#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \ + ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask)))) +#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \ + ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask)))) + +#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001 + +/* Features known to this kernel version: */ +#define JFS_KNOWN_COMPAT_FEATURES 0 +#define JFS_KNOWN_ROCOMPAT_FEATURES 0 +#define JFS_KNOWN_INCOMPAT_FEATURES JFS_FEATURE_INCOMPAT_REVOKE + +#ifdef __KERNEL__ + +#include +#include + +#define JBD_ASSERTIONS +#ifdef JBD_ASSERTIONS +#define J_ASSERT(assert) \ +do { \ + if (!(assert)) { \ + printk (KERN_EMERG \ + "Assertion failure in %s() at %s:%d: \"%s\"\n", \ + __FUNCTION__, __FILE__, __LINE__, # assert); \ + BUG(); \ + } \ +} while (0) + +#if defined(CONFIG_BUFFER_DEBUG) +void buffer_assertion_failure(struct buffer_head *bh); +#define J_ASSERT_BH(bh, expr) \ + do { \ + if (!(expr)) \ + buffer_assertion_failure(bh); \ + J_ASSERT(expr); \ + } while (0) +#define J_ASSERT_JH(jh, expr) J_ASSERT_BH(jh2bh(jh), expr) +#else +#define J_ASSERT_BH(bh, expr) J_ASSERT(expr) +#define J_ASSERT_JH(jh, expr) J_ASSERT(expr) +#endif + +#else +#define J_ASSERT(assert) do { } while (0) +#endif /* JBD_ASSERTIONS */ + +#if defined(JBD_PARANOID_IOFAIL) +#define J_EXPECT(expr, why...) J_ASSERT(expr) +#define J_EXPECT_BH(bh, expr, why...) J_ASSERT_BH(bh, expr) +#define J_EXPECT_JH(jh, expr, why...) J_ASSERT_JH(jh, expr) +#else +#define __journal_expect(expr, why...) \ + ({ \ + int val = (expr); \ + if (!val) { \ + printk(KERN_ERR \ + "EXT3-fs unexpected failure: %s;\n",# expr); \ + printk(KERN_ERR why "\n"); \ + } \ + val; \ + }) +#define J_EXPECT(expr, why...) __journal_expect(expr, ## why) +#define J_EXPECT_BH(bh, expr, why...) __journal_expect(expr, ## why) +#define J_EXPECT_JH(jh, expr, why...) __journal_expect(expr, ## why) +#endif + +enum jbd_state_bits { + BH_JBD /* Has an attached ext3 journal_head */ + = BH_PrivateStart, + BH_JWrite, /* Being written to log (@@@ DEBUGGING) */ + BH_Freed, /* Has been freed (truncated) */ + BH_Revoked, /* Has been revoked from the log */ + BH_RevokeValid, /* Revoked flag is valid */ + BH_JBDDirty, /* Is dirty but journaled */ + BH_State, /* Pins most journal_head state */ + BH_JournalHead, /* Pins bh->b_private and jh->b_bh */ + BH_Unshadow, /* Dummy bit, for BJ_Shadow wakeup filtering */ +}; + +BUFFER_FNS(JBD, jbd) +BUFFER_FNS(JWrite, jwrite) +BUFFER_FNS(JBDDirty, jbddirty) +TAS_BUFFER_FNS(JBDDirty, jbddirty) +BUFFER_FNS(Revoked, revoked) +TAS_BUFFER_FNS(Revoked, revoked) +BUFFER_FNS(RevokeValid, revokevalid) +TAS_BUFFER_FNS(RevokeValid, revokevalid) +BUFFER_FNS(Freed, freed) + +static inline struct buffer_head *jh2bh(struct journal_head *jh) +{ + return jh->b_bh; +} + +static inline struct journal_head *bh2jh(struct buffer_head *bh) +{ + return bh->b_private; +} + +static inline void jbd_lock_bh_state(struct buffer_head *bh) +{ + bit_spin_lock(BH_State, &bh->b_state); +} + +static inline int jbd_trylock_bh_state(struct buffer_head *bh) +{ + return bit_spin_trylock(BH_State, &bh->b_state); +} + +static inline int jbd_is_locked_bh_state(struct buffer_head *bh) +{ + return bit_spin_is_locked(BH_State, &bh->b_state); +} + +static inline void jbd_unlock_bh_state(struct buffer_head *bh) +{ + bit_spin_unlock(BH_State, &bh->b_state); +} + +static inline void jbd_lock_bh_journal_head(struct buffer_head *bh) +{ + bit_spin_lock(BH_JournalHead, &bh->b_state); +} + +static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh) +{ + bit_spin_unlock(BH_JournalHead, &bh->b_state); +} + +struct jbd_revoke_table_s; + +/** + * struct handle_s - The handle_s type is the concrete type associated with + * handle_t. + * @h_transaction: Which compound transaction is this update a part of? + * @h_buffer_credits: Number of remaining buffers we are allowed to dirty. + * @h_ref: Reference count on this handle + * @h_err: Field for caller's use to track errors through large fs operations + * @h_sync: flag for sync-on-close + * @h_jdata: flag to force data journaling + * @h_aborted: flag indicating fatal error on handle + **/ + +/* Docbook can't yet cope with the bit fields, but will leave the documentation + * in so it can be fixed later. + */ + +struct handle_s +{ + /* Which compound transaction is this update a part of? */ + transaction_t *h_transaction; + + /* Number of remaining buffers we are allowed to dirty: */ + int h_buffer_credits; + + /* Reference count on this handle */ + int h_ref; + + /* Field for caller's use to track errors through large fs */ + /* operations */ + int h_err; + + /* Flags [no locking] */ + unsigned int h_sync: 1; /* sync-on-close */ + unsigned int h_jdata: 1; /* force data journaling */ + unsigned int h_aborted: 1; /* fatal error on handle */ +}; + + +/* The transaction_t type is the guts of the journaling mechanism. It + * tracks a compound transaction through its various states: + * + * RUNNING: accepting new updates + * LOCKED: Updates still running but we don't accept new ones + * RUNDOWN: Updates are tidying up but have finished requesting + * new buffers to modify (state not used for now) + * FLUSH: All updates complete, but we are still writing to disk + * COMMIT: All data on disk, writing commit record + * FINISHED: We still have to keep the transaction for checkpointing. + * + * The transaction keeps track of all of the buffers modified by a + * running transaction, and all of the buffers committed but not yet + * flushed to home for finished transactions. + */ + +/* + * Lock ranking: + * + * j_list_lock + * ->jbd_lock_bh_journal_head() (This is "innermost") + * + * j_state_lock + * ->jbd_lock_bh_state() + * + * jbd_lock_bh_state() + * ->j_list_lock + * + * j_state_lock + * ->t_handle_lock + * + * j_state_lock + * ->j_list_lock (journal_unmap_buffer) + * + */ + +struct transaction_s +{ + /* Pointer to the journal for this transaction. [no locking] */ + journal_t *t_journal; + + /* Sequence number for this transaction [no locking] */ + tid_t t_tid; + + /* + * Transaction's current state + * [no locking - only kjournald alters this] + * FIXME: needs barriers + * KLUDGE: [use j_state_lock] + */ + enum { + T_RUNNING, + T_LOCKED, + T_RUNDOWN, + T_FLUSH, + T_COMMIT, + T_FINISHED + } t_state; + + /* + * Where in the log does this transaction's commit start? [no locking] + */ + unsigned long t_log_start; + + /* Number of buffers on the t_buffers list [j_list_lock] */ + int t_nr_buffers; + + /* + * Doubly-linked circular list of all buffers reserved but not yet + * modified by this transaction [j_list_lock] + */ + struct journal_head *t_reserved_list; + + /* + * Doubly-linked circular list of all buffers under writeout during + * commit [j_list_lock] + */ + struct journal_head *t_locked_list; + + /* + * Doubly-linked circular list of all metadata buffers owned by this + * transaction [j_list_lock] + */ + struct journal_head *t_buffers; + + /* + * Doubly-linked circular list of all data buffers still to be + * flushed before this transaction can be committed [j_list_lock] + */ + struct journal_head *t_sync_datalist; + + /* + * Doubly-linked circular list of all forget buffers (superseded + * buffers which we can un-checkpoint once this transaction commits) + * [j_list_lock] + */ + struct journal_head *t_forget; + + /* + * Doubly-linked circular list of all buffers still to be flushed before + * this transaction can be checkpointed. [j_list_lock] + */ + struct journal_head *t_checkpoint_list; + + /* + * Doubly-linked circular list of all buffers submitted for IO while + * checkpointing. [j_list_lock] + */ + struct journal_head *t_checkpoint_io_list; + + /* + * Doubly-linked circular list of temporary buffers currently undergoing + * IO in the log [j_list_lock] + */ + struct journal_head *t_iobuf_list; + + /* + * Doubly-linked circular list of metadata buffers being shadowed by log + * IO. The IO buffers on the iobuf list and the shadow buffers on this + * list match each other one for one at all times. [j_list_lock] + */ + struct journal_head *t_shadow_list; + + /* + * Doubly-linked circular list of control buffers being written to the + * log. [j_list_lock] + */ + struct journal_head *t_log_list; + + /* + * Protects info related to handles + */ + spinlock_t t_handle_lock; + + /* + * Number of outstanding updates running on this transaction + * [t_handle_lock] + */ + int t_updates; + + /* + * Number of buffers reserved for use by all handles in this transaction + * handle but not yet modified. [t_handle_lock] + */ + int t_outstanding_credits; + + /* + * Forward and backward links for the circular list of all transactions + * awaiting checkpoint. [j_list_lock] + */ + transaction_t *t_cpnext, *t_cpprev; + + /* + * When will the transaction expire (become due for commit), in jiffies? + * [no locking] + */ + unsigned long t_expires; + + /* + * How many handles used this transaction? [t_handle_lock] + */ + int t_handle_count; + +}; + +/** + * struct journal_s - The journal_s type is the concrete type associated with + * journal_t. + * @j_flags: General journaling state flags + * @j_errno: Is there an outstanding uncleared error on the journal (from a + * prior abort)? + * @j_sb_buffer: First part of superblock buffer + * @j_superblock: Second part of superblock buffer + * @j_format_version: Version of the superblock format + * @j_state_lock: Protect the various scalars in the journal + * @j_barrier_count: Number of processes waiting to create a barrier lock + * @j_barrier: The barrier lock itself + * @j_running_transaction: The current running transaction.. + * @j_committing_transaction: the transaction we are pushing to disk + * @j_checkpoint_transactions: a linked circular list of all transactions + * waiting for checkpointing + * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction + * to start committing, or for a barrier lock to be released + * @j_wait_logspace: Wait queue for waiting for checkpointing to complete + * @j_wait_done_commit: Wait queue for waiting for commit to complete + * @j_wait_checkpoint: Wait queue to trigger checkpointing + * @j_wait_commit: Wait queue to trigger commit + * @j_wait_updates: Wait queue to wait for updates to complete + * @j_checkpoint_mutex: Mutex for locking against concurrent checkpoints + * @j_head: Journal head - identifies the first unused block in the journal + * @j_tail: Journal tail - identifies the oldest still-used block in the + * journal. + * @j_free: Journal free - how many free blocks are there in the journal? + * @j_first: The block number of the first usable block + * @j_last: The block number one beyond the last usable block + * @j_dev: Device where we store the journal + * @j_blocksize: blocksize for the location where we store the journal. + * @j_blk_offset: starting block offset for into the device where we store the + * journal + * @j_fs_dev: Device which holds the client fs. For internal journal this will + * be equal to j_dev + * @j_maxlen: Total maximum capacity of the journal region on disk. + * @j_list_lock: Protects the buffer lists and internal buffer state. + * @j_inode: Optional inode where we store the journal. If present, all journal + * block numbers are mapped into this inode via bmap(). + * @j_tail_sequence: Sequence number of the oldest transaction in the log + * @j_transaction_sequence: Sequence number of the next transaction to grant + * @j_commit_sequence: Sequence number of the most recently committed + * transaction + * @j_commit_request: Sequence number of the most recent transaction wanting + * commit + * @j_uuid: Uuid of client object. + * @j_task: Pointer to the current commit thread for this journal + * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a + * single compound commit transaction + * @j_commit_interval: What is the maximum transaction lifetime before we begin + * a commit? + * @j_commit_timer: The timer used to wakeup the commit thread + * @j_revoke_lock: Protect the revoke table + * @j_revoke: The revoke table - maintains the list of revoked blocks in the + * current transaction. + * @j_revoke_table: alternate revoke tables for j_revoke + * @j_wbuf: array of buffer_heads for journal_commit_transaction + * @j_wbufsize: maximum number of buffer_heads allowed in j_wbuf, the + * number that will fit in j_blocksize + * @j_last_sync_writer: most recent pid which did a synchronous write + * @j_private: An opaque pointer to fs-private information. + */ + +struct journal_s +{ + /* General journaling state flags [j_state_lock] */ + unsigned long j_flags; + + /* + * Is there an outstanding uncleared error on the journal (from a prior + * abort)? [j_state_lock] + */ + int j_errno; + + /* The superblock buffer */ + struct buffer_head *j_sb_buffer; + journal_superblock_t *j_superblock; + + /* Version of the superblock format */ + int j_format_version; + + /* + * Protect the various scalars in the journal + */ + spinlock_t j_state_lock; + + /* + * Number of processes waiting to create a barrier lock [j_state_lock] + */ + int j_barrier_count; + + /* The barrier lock itself */ + struct mutex j_barrier; + + /* + * Transactions: The current running transaction... + * [j_state_lock] [caller holding open handle] + */ + transaction_t *j_running_transaction; + + /* + * the transaction we are pushing to disk + * [j_state_lock] [caller holding open handle] + */ + transaction_t *j_committing_transaction; + + /* + * ... and a linked circular list of all transactions waiting for + * checkpointing. [j_list_lock] + */ + transaction_t *j_checkpoint_transactions; + + /* + * Wait queue for waiting for a locked transaction to start committing, + * or for a barrier lock to be released + */ + wait_queue_head_t j_wait_transaction_locked; + + /* Wait queue for waiting for checkpointing to complete */ + wait_queue_head_t j_wait_logspace; + + /* Wait queue for waiting for commit to complete */ + wait_queue_head_t j_wait_done_commit; + + /* Wait queue to trigger checkpointing */ + wait_queue_head_t j_wait_checkpoint; + + /* Wait queue to trigger commit */ + wait_queue_head_t j_wait_commit; + + /* Wait queue to wait for updates to complete */ + wait_queue_head_t j_wait_updates; + + /* Semaphore for locking against concurrent checkpoints */ + struct mutex j_checkpoint_mutex; + + /* + * Journal head: identifies the first unused block in the journal. + * [j_state_lock] + */ + unsigned long j_head; + + /* + * Journal tail: identifies the oldest still-used block in the journal. + * [j_state_lock] + */ + unsigned long j_tail; + + /* + * Journal free: how many free blocks are there in the journal? + * [j_state_lock] + */ + unsigned long j_free; + + /* + * Journal start and end: the block numbers of the first usable block + * and one beyond the last usable block in the journal. [j_state_lock] + */ + unsigned long j_first; + unsigned long j_last; + + /* + * Device, blocksize and starting block offset for the location where we + * store the journal. + */ + struct block_device *j_dev; + int j_blocksize; + unsigned long j_blk_offset; + + /* + * Device which holds the client fs. For internal journal this will be + * equal to j_dev. + */ + struct block_device *j_fs_dev; + + /* Total maximum capacity of the journal region on disk. */ + unsigned int j_maxlen; + + /* + * Protects the buffer lists and internal buffer state. + */ + spinlock_t j_list_lock; + + /* Optional inode where we store the journal. If present, all */ + /* journal block numbers are mapped into this inode via */ + /* bmap(). */ + struct inode *j_inode; + + /* + * Sequence number of the oldest transaction in the log [j_state_lock] + */ + tid_t j_tail_sequence; + + /* + * Sequence number of the next transaction to grant [j_state_lock] + */ + tid_t j_transaction_sequence; + + /* + * Sequence number of the most recently committed transaction + * [j_state_lock]. + */ + tid_t j_commit_sequence; + + /* + * Sequence number of the most recent transaction wanting commit + * [j_state_lock] + */ + tid_t j_commit_request; + + /* + * Journal uuid: identifies the object (filesystem, LVM volume etc) + * backed by this journal. This will eventually be replaced by an array + * of uuids, allowing us to index multiple devices within a single + * journal and to perform atomic updates across them. + */ + __u8 j_uuid[16]; + + /* Pointer to the current commit thread for this journal */ + struct task_struct *j_task; + + /* + * Maximum number of metadata buffers to allow in a single compound + * commit transaction + */ + int j_max_transaction_buffers; + + /* + * What is the maximum transaction lifetime before we begin a commit? + */ + unsigned long j_commit_interval; + + /* The timer used to wakeup the commit thread: */ + struct timer_list j_commit_timer; + + /* + * The revoke table: maintains the list of revoked blocks in the + * current transaction. [j_revoke_lock] + */ + spinlock_t j_revoke_lock; + struct jbd_revoke_table_s *j_revoke; + struct jbd_revoke_table_s *j_revoke_table[2]; + + /* + * array of bhs for journal_commit_transaction + */ + struct buffer_head **j_wbuf; + int j_wbufsize; + + pid_t j_last_sync_writer; + + /* + * An opaque pointer to fs-private information. ext3 puts its + * superblock pointer here + */ + void *j_private; +}; + +/* + * Journal flag definitions + */ +#define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */ +#define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */ +#define JFS_ACK_ERR 0x004 /* The errno in the sb has been acked */ +#define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */ +#define JFS_LOADED 0x010 /* The journal superblock has been loaded */ +#define JFS_BARRIER 0x020 /* Use IDE barriers */ + +/* + * Function declarations for the journaling transaction and buffer + * management + */ + +/* Filing buffers */ +extern void __journal_temp_unlink_buffer(struct journal_head *jh); +extern void journal_unfile_buffer(journal_t *, struct journal_head *); +extern void __journal_unfile_buffer(struct journal_head *); +extern void __journal_refile_buffer(struct journal_head *); +extern void journal_refile_buffer(journal_t *, struct journal_head *); +extern void __journal_file_buffer(struct journal_head *, transaction_t *, int); +extern void __journal_free_buffer(struct journal_head *bh); +extern void journal_file_buffer(struct journal_head *, transaction_t *, int); +extern void __journal_clean_data_list(transaction_t *transaction); + +/* Log buffer allocation */ +extern struct journal_head * journal_get_descriptor_buffer(journal_t *); +int journal_next_log_block(journal_t *, unsigned long *); + +/* Commit management */ +extern void journal_commit_transaction(journal_t *); + +/* Checkpoint list management */ +int __journal_clean_checkpoint_list(journal_t *journal); +int __journal_remove_checkpoint(struct journal_head *); +void __journal_insert_checkpoint(struct journal_head *, transaction_t *); + +/* Buffer IO */ +extern int +journal_write_metadata_buffer(transaction_t *transaction, + struct journal_head *jh_in, + struct journal_head **jh_out, + unsigned long blocknr); + +/* Transaction locking */ +extern void __wait_on_journal (journal_t *); + +/* + * Journal locking. + * + * We need to lock the journal during transaction state changes so that nobody + * ever tries to take a handle on the running transaction while we are in the + * middle of moving it to the commit phase. j_state_lock does this. + * + * Note that the locking is completely interrupt unsafe. We never touch + * journal structures from interrupts. + */ + +static inline handle_t *journal_current_handle(void) +{ + return current->journal_info; +} + +/* The journaling code user interface: + * + * Create and destroy handles + * Register buffer modifications against the current transaction. + */ + +extern handle_t *journal_start(journal_t *, int nblocks); +extern int journal_restart (handle_t *, int nblocks); +extern int journal_extend (handle_t *, int nblocks); +extern int journal_get_write_access(handle_t *, struct buffer_head *); +extern int journal_get_create_access (handle_t *, struct buffer_head *); +extern int journal_get_undo_access(handle_t *, struct buffer_head *); +extern int journal_dirty_data (handle_t *, struct buffer_head *); +extern int journal_dirty_metadata (handle_t *, struct buffer_head *); +extern void journal_release_buffer (handle_t *, struct buffer_head *); +extern int journal_forget (handle_t *, struct buffer_head *); +extern void journal_sync_buffer (struct buffer_head *); +extern void journal_invalidatepage(journal_t *, + struct page *, unsigned long); +extern int journal_try_to_free_buffers(journal_t *, struct page *, gfp_t); +extern int journal_stop(handle_t *); +extern int journal_flush (journal_t *); +extern void journal_lock_updates (journal_t *); +extern void journal_unlock_updates (journal_t *); + +extern journal_t * journal_init_dev(struct block_device *bdev, + struct block_device *fs_dev, + int start, int len, int bsize); +extern journal_t * journal_init_inode (struct inode *); +extern int journal_update_format (journal_t *); +extern int journal_check_used_features + (journal_t *, unsigned long, unsigned long, unsigned long); +extern int journal_check_available_features + (journal_t *, unsigned long, unsigned long, unsigned long); +extern int journal_set_features + (journal_t *, unsigned long, unsigned long, unsigned long); +extern int journal_create (journal_t *); +extern int journal_load (journal_t *journal); +extern void journal_destroy (journal_t *); +extern int journal_recover (journal_t *journal); +extern int journal_wipe (journal_t *, int); +extern int journal_skip_recovery (journal_t *); +extern void journal_update_superblock (journal_t *, int); +extern void __journal_abort_hard (journal_t *); +extern void journal_abort (journal_t *, int); +extern int journal_errno (journal_t *); +extern void journal_ack_err (journal_t *); +extern int journal_clear_err (journal_t *); +extern int journal_bmap(journal_t *, unsigned long, unsigned long *); +extern int journal_force_commit(journal_t *); + +/* + * journal_head management + */ +struct journal_head *journal_add_journal_head(struct buffer_head *bh); +struct journal_head *journal_grab_journal_head(struct buffer_head *bh); +void journal_remove_journal_head(struct buffer_head *bh); +void journal_put_journal_head(struct journal_head *jh); + +/* + * handle management + */ +extern kmem_cache_t *jbd_handle_cache; + +static inline handle_t *jbd_alloc_handle(gfp_t gfp_flags) +{ + return kmem_cache_alloc(jbd_handle_cache, gfp_flags); +} + +static inline void jbd_free_handle(handle_t *handle) +{ + kmem_cache_free(jbd_handle_cache, handle); +} + +/* Primary revoke support */ +#define JOURNAL_REVOKE_DEFAULT_HASH 256 +extern int journal_init_revoke(journal_t *, int); +extern void journal_destroy_revoke_caches(void); +extern int journal_init_revoke_caches(void); + +extern void journal_destroy_revoke(journal_t *); +extern int journal_revoke (handle_t *, + unsigned long, struct buffer_head *); +extern int journal_cancel_revoke(handle_t *, struct journal_head *); +extern void journal_write_revoke_records(journal_t *, transaction_t *); + +/* Recovery revoke support */ +extern int journal_set_revoke(journal_t *, unsigned long, tid_t); +extern int journal_test_revoke(journal_t *, unsigned long, tid_t); +extern void journal_clear_revoke(journal_t *); +extern void journal_switch_revoke_table(journal_t *journal); + +/* + * The log thread user interface: + * + * Request space in the current transaction, and force transaction commit + * transitions on demand. + */ + +int __log_space_left(journal_t *); /* Called with journal locked */ +int log_start_commit(journal_t *journal, tid_t tid); +int __log_start_commit(journal_t *journal, tid_t tid); +int journal_start_commit(journal_t *journal, tid_t *tid); +int journal_force_commit_nested(journal_t *journal); +int log_wait_commit(journal_t *journal, tid_t tid); +int log_do_checkpoint(journal_t *journal); + +void __log_wait_for_space(journal_t *journal); +extern void __journal_drop_transaction(journal_t *, transaction_t *); +extern int cleanup_journal_tail(journal_t *); + +/* Debugging code only: */ + +#define jbd_ENOSYS() \ +do { \ + printk (KERN_ERR "JBD unimplemented function %s\n", __FUNCTION__); \ + current->state = TASK_UNINTERRUPTIBLE; \ + schedule(); \ +} while (1) + +/* + * is_journal_abort + * + * Simple test wrapper function to test the JFS_ABORT state flag. This + * bit, when set, indicates that we have had a fatal error somewhere, + * either inside the journaling layer or indicated to us by the client + * (eg. ext3), and that we and should not commit any further + * transactions. + */ + +static inline int is_journal_aborted(journal_t *journal) +{ + return journal->j_flags & JFS_ABORT; +} + +static inline int is_handle_aborted(handle_t *handle) +{ + if (handle->h_aborted) + return 1; + return is_journal_aborted(handle->h_transaction->t_journal); +} + +static inline void journal_abort_handle(handle_t *handle) +{ + handle->h_aborted = 1; +} + +#endif /* __KERNEL__ */ + +/* Comparison functions for transaction IDs: perform comparisons using + * modulo arithmetic so that they work over sequence number wraps. */ + +static inline int tid_gt(tid_t x, tid_t y) +{ + int difference = (x - y); + return (difference > 0); +} + +static inline int tid_geq(tid_t x, tid_t y) +{ + int difference = (x - y); + return (difference >= 0); +} + +extern int journal_blocks_per_page(struct inode *inode); + +/* + * Return the minimum number of blocks which must be free in the journal + * before a new transaction may be started. Must be called under j_state_lock. + */ +static inline int jbd_space_needed(journal_t *journal) +{ + int nblocks = journal->j_max_transaction_buffers; + if (journal->j_committing_transaction) + nblocks += journal->j_committing_transaction-> + t_outstanding_credits; + return nblocks; +} + +/* + * Definitions which augment the buffer_head layer + */ + +/* journaling buffer types */ +#define BJ_None 0 /* Not journaled */ +#define BJ_SyncData 1 /* Normal data: flush before commit */ +#define BJ_Metadata 2 /* Normal journaled metadata */ +#define BJ_Forget 3 /* Buffer superseded by this transaction */ +#define BJ_IO 4 /* Buffer is for temporary IO use */ +#define BJ_Shadow 5 /* Buffer contents being shadowed to the log */ +#define BJ_LogCtl 6 /* Buffer contains log descriptors */ +#define BJ_Reserved 7 /* Buffer is reserved for access by journal */ +#define BJ_Locked 8 /* Locked for I/O during commit */ +#define BJ_Types 9 + +extern int jbd_blocks_per_page(struct inode *inode); + +#ifdef __KERNEL__ + +#define buffer_trace_init(bh) do {} while (0) +#define print_buffer_fields(bh) do {} while (0) +#define print_buffer_trace(bh) do {} while (0) +#define BUFFER_TRACE(bh, info) do {} while (0) +#define BUFFER_TRACE2(bh, bh2, info) do {} while (0) +#define JBUFFER_TRACE(jh, info) do {} while (0) + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_JBD_H */ -- cgit v1.2.3 From f7f4bccb729844a0fa873e224e3a6f7eeed095bb Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:20:59 -0700 Subject: [PATCH] jbd2: rename jbd2 symbols to avoid duplication of jbd symbols Mingming Cao originally did this work, and Shaggy reproduced it using some scripts from her. Signed-off-by: Mingming Cao Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd2/Makefile | 4 +- fs/jbd2/checkpoint.c | 54 +++--- fs/jbd2/commit.c | 122 ++++++------- fs/jbd2/journal.c | 454 +++++++++++++++++++++++----------------------- fs/jbd2/recovery.c | 46 ++--- fs/jbd2/revoke.c | 146 +++++++-------- fs/jbd2/transaction.c | 244 ++++++++++++------------- include/linux/ext4_jbd2.h | 26 +-- include/linux/jbd2.h | 248 ++++++++++++------------- 9 files changed, 672 insertions(+), 672 deletions(-) (limited to 'include/linux') diff --git a/fs/jbd2/Makefile b/fs/jbd2/Makefile index 54aca4868a36..802a3413872a 100644 --- a/fs/jbd2/Makefile +++ b/fs/jbd2/Makefile @@ -2,6 +2,6 @@ # Makefile for the linux journaling routines. # -obj-$(CONFIG_JBD) += jbd.o +obj-$(CONFIG_JBD2) += jbd2.o -jbd-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o +jbd2-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 0208cc7ac5d0..68039fa9a566 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include @@ -95,9 +95,9 @@ static int __try_to_free_cp_buf(struct journal_head *jh) if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) { JBUFFER_TRACE(jh, "remove from checkpoint list"); - ret = __journal_remove_checkpoint(jh) + 1; + ret = __jbd2_journal_remove_checkpoint(jh) + 1; jbd_unlock_bh_state(bh); - journal_remove_journal_head(bh); + jbd2_journal_remove_journal_head(bh); BUFFER_TRACE(bh, "release"); __brelse(bh); } else { @@ -107,19 +107,19 @@ static int __try_to_free_cp_buf(struct journal_head *jh) } /* - * __log_wait_for_space: wait until there is space in the journal. + * __jbd2_log_wait_for_space: wait until there is space in the journal. * * Called under j-state_lock *only*. It will be unlocked if we have to wait * for a checkpoint to free up some space in the log. */ -void __log_wait_for_space(journal_t *journal) +void __jbd2_log_wait_for_space(journal_t *journal) { int nblocks; assert_spin_locked(&journal->j_state_lock); nblocks = jbd_space_needed(journal); - while (__log_space_left(journal) < nblocks) { - if (journal->j_flags & JFS_ABORT) + while (__jbd2_log_space_left(journal) < nblocks) { + if (journal->j_flags & JBD2_ABORT) return; spin_unlock(&journal->j_state_lock); mutex_lock(&journal->j_checkpoint_mutex); @@ -130,9 +130,9 @@ void __log_wait_for_space(journal_t *journal) */ spin_lock(&journal->j_state_lock); nblocks = jbd_space_needed(journal); - if (__log_space_left(journal) < nblocks) { + if (__jbd2_log_space_left(journal) < nblocks) { spin_unlock(&journal->j_state_lock); - log_do_checkpoint(journal); + jbd2_log_do_checkpoint(journal); spin_lock(&journal->j_state_lock); } mutex_unlock(&journal->j_checkpoint_mutex); @@ -198,9 +198,9 @@ restart: * Now in whatever state the buffer currently is, we know that * it has been written out and so we can drop it from the list */ - released = __journal_remove_checkpoint(jh); + released = __jbd2_journal_remove_checkpoint(jh); jbd_unlock_bh_state(bh); - journal_remove_journal_head(bh); + jbd2_journal_remove_journal_head(bh); __brelse(bh); } } @@ -252,16 +252,16 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh, spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); - log_start_commit(journal, tid); - log_wait_commit(journal, tid); + jbd2_log_start_commit(journal, tid); + jbd2_log_wait_commit(journal, tid); ret = 1; } else if (!buffer_dirty(bh)) { J_ASSERT_JH(jh, !buffer_jbddirty(bh)); BUFFER_TRACE(bh, "remove from checkpoint"); - __journal_remove_checkpoint(jh); + __jbd2_journal_remove_checkpoint(jh); spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); - journal_remove_journal_head(bh); + jbd2_journal_remove_journal_head(bh); __brelse(bh); ret = 1; } else { @@ -296,7 +296,7 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh, * * The journal should be locked before calling this function. */ -int log_do_checkpoint(journal_t *journal) +int jbd2_log_do_checkpoint(journal_t *journal) { transaction_t *transaction; tid_t this_tid; @@ -309,7 +309,7 @@ int log_do_checkpoint(journal_t *journal) * don't need checkpointing, just eliminate them from the * journal straight away. */ - result = cleanup_journal_tail(journal); + result = jbd2_cleanup_journal_tail(journal); jbd_debug(1, "cleanup_journal_tail returned %d\n", result); if (result <= 0) return result; @@ -374,7 +374,7 @@ restart: } out: spin_unlock(&journal->j_list_lock); - result = cleanup_journal_tail(journal); + result = jbd2_cleanup_journal_tail(journal); if (result < 0) return result; return 0; @@ -397,7 +397,7 @@ out: * we have an abort error outstanding. */ -int cleanup_journal_tail(journal_t *journal) +int jbd2_cleanup_journal_tail(journal_t *journal) { transaction_t * transaction; tid_t first_tid; @@ -452,8 +452,8 @@ int cleanup_journal_tail(journal_t *journal) journal->j_tail_sequence = first_tid; journal->j_tail = blocknr; spin_unlock(&journal->j_state_lock); - if (!(journal->j_flags & JFS_ABORT)) - journal_update_superblock(journal, 1); + if (!(journal->j_flags & JBD2_ABORT)) + jbd2_journal_update_superblock(journal, 1); return 0; } @@ -518,7 +518,7 @@ static int journal_clean_one_cp_list(struct journal_head *jh, int *released) * Returns number of buffers reaped (for debug) */ -int __journal_clean_checkpoint_list(journal_t *journal) +int __jbd2_journal_clean_checkpoint_list(journal_t *journal) { transaction_t *transaction, *last_transaction, *next_transaction; int ret = 0; @@ -578,7 +578,7 @@ out: * This function is called with jbd_lock_bh_state(jh2bh(jh)) */ -int __journal_remove_checkpoint(struct journal_head *jh) +int __jbd2_journal_remove_checkpoint(struct journal_head *jh) { transaction_t *transaction; journal_t *journal; @@ -607,7 +607,7 @@ int __journal_remove_checkpoint(struct journal_head *jh) * dropped! * * The locking here around j_committing_transaction is a bit sleazy. - * See the comment at the end of journal_commit_transaction(). + * See the comment at the end of jbd2_journal_commit_transaction(). */ if (transaction == journal->j_committing_transaction) { JBUFFER_TRACE(jh, "belongs to committing transaction"); @@ -617,7 +617,7 @@ int __journal_remove_checkpoint(struct journal_head *jh) /* OK, that was the last buffer for the transaction: we can now safely remove this transaction from the log */ - __journal_drop_transaction(journal, transaction); + __jbd2_journal_drop_transaction(journal, transaction); /* Just in case anybody was waiting for more transactions to be checkpointed... */ @@ -636,7 +636,7 @@ out: * Called with the journal locked. * Called with j_list_lock held. */ -void __journal_insert_checkpoint(struct journal_head *jh, +void __jbd2_journal_insert_checkpoint(struct journal_head *jh, transaction_t *transaction) { JBUFFER_TRACE(jh, "entry"); @@ -666,7 +666,7 @@ void __journal_insert_checkpoint(struct journal_head *jh, * Called with j_list_lock held. */ -void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) +void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transaction) { assert_spin_locked(&journal->j_list_lock); if (transaction->t_cpnext) { diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 10be51290a27..b1a4eafc1541 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -1,5 +1,5 @@ /* - * linux/fs/jbd/commit.c + * linux/fs/jbd2/commit.c * * Written by Stephen C. Tweedie , 1998 * @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -111,7 +111,7 @@ static int journal_write_commit_record(journal_t *journal, if (is_journal_aborted(journal)) return 0; - descriptor = journal_get_descriptor_buffer(journal); + descriptor = jbd2_journal_get_descriptor_buffer(journal); if (!descriptor) return 1; @@ -120,14 +120,14 @@ static int journal_write_commit_record(journal_t *journal, /* AKPM: buglet - add `i' to tmp! */ for (i = 0; i < bh->b_size; i += 512) { journal_header_t *tmp = (journal_header_t*)bh->b_data; - tmp->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); - tmp->h_blocktype = cpu_to_be32(JFS_COMMIT_BLOCK); + tmp->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER); + tmp->h_blocktype = cpu_to_be32(JBD2_COMMIT_BLOCK); tmp->h_sequence = cpu_to_be32(commit_transaction->t_tid); } JBUFFER_TRACE(descriptor, "write commit block"); set_buffer_dirty(bh); - if (journal->j_flags & JFS_BARRIER) { + if (journal->j_flags & JBD2_BARRIER) { set_buffer_ordered(bh); barrier_done = 1; } @@ -145,7 +145,7 @@ static int journal_write_commit_record(journal_t *journal, "disabling barriers\n", bdevname(journal->j_dev, b)); spin_lock(&journal->j_state_lock); - journal->j_flags &= ~JFS_BARRIER; + journal->j_flags &= ~JBD2_BARRIER; spin_unlock(&journal->j_state_lock); /* And try again, without the barrier */ @@ -155,7 +155,7 @@ static int journal_write_commit_record(journal_t *journal, ret = sync_dirty_buffer(bh); } put_bh(bh); /* One for getblk() */ - journal_put_journal_head(descriptor); + jbd2_journal_put_journal_head(descriptor); return (ret == -EIO); } @@ -239,7 +239,7 @@ write_out_data: if (locked && test_clear_buffer_dirty(bh)) { BUFFER_TRACE(bh, "needs writeout, adding to array"); wbuf[bufs++] = bh; - __journal_file_buffer(jh, commit_transaction, + __jbd2_journal_file_buffer(jh, commit_transaction, BJ_Locked); jbd_unlock_bh_state(bh); if (bufs == journal->j_wbufsize) { @@ -251,13 +251,13 @@ write_out_data: } else { BUFFER_TRACE(bh, "writeout complete: unfile"); - __journal_unfile_buffer(jh); + __jbd2_journal_unfile_buffer(jh); jbd_unlock_bh_state(bh); if (locked) unlock_buffer(bh); - journal_remove_journal_head(bh); + jbd2_journal_remove_journal_head(bh); /* Once for our safety reference, once for - * journal_remove_journal_head() */ + * jbd2_journal_remove_journal_head() */ put_bh(bh); put_bh(bh); } @@ -272,12 +272,12 @@ write_out_data: } /* - * journal_commit_transaction + * jbd2_journal_commit_transaction * * The primary function for committing a transaction to the log. This * function is called by the journal thread to begin a complete commit. */ -void journal_commit_transaction(journal_t *journal) +void jbd2_journal_commit_transaction(journal_t *journal) { transaction_t *commit_transaction; struct journal_head *jh, *new_jh, *descriptor; @@ -305,10 +305,10 @@ void journal_commit_transaction(journal_t *journal) spin_unlock(&journal->j_list_lock); #endif - /* Do we need to erase the effects of a prior journal_flush? */ - if (journal->j_flags & JFS_FLUSHED) { + /* Do we need to erase the effects of a prior jbd2_journal_flush? */ + if (journal->j_flags & JBD2_FLUSHED) { jbd_debug(3, "super block updated\n"); - journal_update_superblock(journal, 1); + jbd2_journal_update_superblock(journal, 1); } else { jbd_debug(3, "superblock not updated\n"); } @@ -350,7 +350,7 @@ void journal_commit_transaction(journal_t *journal) * BJ_Reserved buffers. Note, it is _not_ permissible to assume * that there are no such buffers: if a large filesystem * operation like a truncate needs to split itself over multiple - * transactions, then it may try to do a journal_restart() while + * transactions, then it may try to do a jbd2_journal_restart() while * there are still BJ_Reserved buffers outstanding. These must * be released cleanly from the current transaction. * @@ -358,25 +358,25 @@ void journal_commit_transaction(journal_t *journal) * again before modifying the buffer in the new transaction, but * we do not require it to remember exactly which old buffers it * has reserved. This is consistent with the existing behaviour - * that multiple journal_get_write_access() calls to the same + * that multiple jbd2_journal_get_write_access() calls to the same * buffer are perfectly permissable. */ while (commit_transaction->t_reserved_list) { jh = commit_transaction->t_reserved_list; JBUFFER_TRACE(jh, "reserved, unused: refile"); /* - * A journal_get_undo_access()+journal_release_buffer() may + * A jbd2_journal_get_undo_access()+jbd2_journal_release_buffer() may * leave undo-committed data. */ if (jh->b_committed_data) { struct buffer_head *bh = jh2bh(jh); jbd_lock_bh_state(bh); - jbd_slab_free(jh->b_committed_data, bh->b_size); + jbd2_slab_free(jh->b_committed_data, bh->b_size); jh->b_committed_data = NULL; jbd_unlock_bh_state(bh); } - journal_refile_buffer(journal, jh); + jbd2_journal_refile_buffer(journal, jh); } /* @@ -385,7 +385,7 @@ void journal_commit_transaction(journal_t *journal) * frees some memory */ spin_lock(&journal->j_list_lock); - __journal_clean_checkpoint_list(journal); + __jbd2_journal_clean_checkpoint_list(journal); spin_unlock(&journal->j_list_lock); jbd_debug (3, "JBD: commit phase 1\n"); @@ -393,7 +393,7 @@ void journal_commit_transaction(journal_t *journal) /* * Switch to a new revoke table. */ - journal_switch_revoke_table(journal); + jbd2_journal_switch_revoke_table(journal); commit_transaction->t_state = T_FLUSH; journal->j_committing_transaction = commit_transaction; @@ -450,9 +450,9 @@ void journal_commit_transaction(journal_t *journal) continue; } if (buffer_jbd(bh) && jh->b_jlist == BJ_Locked) { - __journal_unfile_buffer(jh); + __jbd2_journal_unfile_buffer(jh); jbd_unlock_bh_state(bh); - journal_remove_journal_head(bh); + jbd2_journal_remove_journal_head(bh); put_bh(bh); } else { jbd_unlock_bh_state(bh); @@ -463,9 +463,9 @@ void journal_commit_transaction(journal_t *journal) spin_unlock(&journal->j_list_lock); if (err) - __journal_abort_hard(journal); + __jbd2_journal_abort_hard(journal); - journal_write_revoke_records(journal, commit_transaction); + jbd2_journal_write_revoke_records(journal, commit_transaction); jbd_debug(3, "JBD: commit phase 2\n"); @@ -499,7 +499,7 @@ void journal_commit_transaction(journal_t *journal) if (is_journal_aborted(journal)) { JBUFFER_TRACE(jh, "journal is aborting: refile"); - journal_refile_buffer(journal, jh); + jbd2_journal_refile_buffer(journal, jh); /* If that was the last one, we need to clean up * any descriptor buffers which may have been * already allocated, even if we are now @@ -519,9 +519,9 @@ void journal_commit_transaction(journal_t *journal) jbd_debug(4, "JBD: get descriptor\n"); - descriptor = journal_get_descriptor_buffer(journal); + descriptor = jbd2_journal_get_descriptor_buffer(journal); if (!descriptor) { - __journal_abort_hard(journal); + __jbd2_journal_abort_hard(journal); continue; } @@ -529,8 +529,8 @@ void journal_commit_transaction(journal_t *journal) jbd_debug(4, "JBD: got buffer %llu (%p)\n", (unsigned long long)bh->b_blocknr, bh->b_data); header = (journal_header_t *)&bh->b_data[0]; - header->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); - header->h_blocktype = cpu_to_be32(JFS_DESCRIPTOR_BLOCK); + header->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER); + header->h_blocktype = cpu_to_be32(JBD2_DESCRIPTOR_BLOCK); header->h_sequence = cpu_to_be32(commit_transaction->t_tid); tagp = &bh->b_data[sizeof(journal_header_t)]; @@ -543,25 +543,25 @@ void journal_commit_transaction(journal_t *journal) /* Record it so that we can wait for IO completion later */ BUFFER_TRACE(bh, "ph3: file as descriptor"); - journal_file_buffer(descriptor, commit_transaction, + jbd2_journal_file_buffer(descriptor, commit_transaction, BJ_LogCtl); } /* Where is the buffer to be written? */ - err = journal_next_log_block(journal, &blocknr); + err = jbd2_journal_next_log_block(journal, &blocknr); /* If the block mapping failed, just abandon the buffer and repeat this loop: we'll fall into the refile-on-abort condition above. */ if (err) { - __journal_abort_hard(journal); + __jbd2_journal_abort_hard(journal); continue; } /* * start_this_handle() uses t_outstanding_credits to determine * the free space in the log, but this counter is changed - * by journal_next_log_block() also. + * by jbd2_journal_next_log_block() also. */ commit_transaction->t_outstanding_credits--; @@ -576,13 +576,13 @@ void journal_commit_transaction(journal_t *journal) set_bit(BH_JWrite, &jh2bh(jh)->b_state); /* - * akpm: journal_write_metadata_buffer() sets + * akpm: jbd2_journal_write_metadata_buffer() sets * new_bh->b_transaction to commit_transaction. * We need to clean this up before we release new_bh * (which is of type BJ_IO) */ JBUFFER_TRACE(jh, "ph3: write metadata"); - flags = journal_write_metadata_buffer(commit_transaction, + flags = jbd2_journal_write_metadata_buffer(commit_transaction, jh, &new_jh, blocknr); set_bit(BH_JWrite, &jh2bh(new_jh)->b_state); wbuf[bufs++] = jh2bh(new_jh); @@ -592,9 +592,9 @@ void journal_commit_transaction(journal_t *journal) tag_flag = 0; if (flags & 1) - tag_flag |= JFS_FLAG_ESCAPE; + tag_flag |= JBD2_FLAG_ESCAPE; if (!first_tag) - tag_flag |= JFS_FLAG_SAME_UUID; + tag_flag |= JBD2_FLAG_SAME_UUID; tag = (journal_block_tag_t *) tagp; tag->t_blocknr = cpu_to_be32(jh2bh(jh)->b_blocknr); @@ -622,7 +622,7 @@ void journal_commit_transaction(journal_t *journal) submitting the IOs. "tag" still points to the last tag we set up. */ - tag->t_flags |= cpu_to_be32(JFS_FLAG_LAST_TAG); + tag->t_flags |= cpu_to_be32(JBD2_FLAG_LAST_TAG); start_journal_io: for (i = 0; i < bufs; i++) { @@ -678,14 +678,14 @@ wait_for_iobuf: clear_buffer_jwrite(bh); JBUFFER_TRACE(jh, "ph4: unfile after journal write"); - journal_unfile_buffer(journal, jh); + jbd2_journal_unfile_buffer(journal, jh); /* * ->t_iobuf_list should contain only dummy buffer_heads - * which were created by journal_write_metadata_buffer(). + * which were created by jbd2_journal_write_metadata_buffer(). */ BUFFER_TRACE(bh, "dumping temporary bh"); - journal_put_journal_head(jh); + jbd2_journal_put_journal_head(jh); __brelse(bh); J_ASSERT_BH(bh, atomic_read(&bh->b_count) == 0); free_buffer_head(bh); @@ -702,7 +702,7 @@ wait_for_iobuf: we finally commit, we can do any checkpointing required. */ JBUFFER_TRACE(jh, "file as BJ_Forget"); - journal_file_buffer(jh, commit_transaction, BJ_Forget); + jbd2_journal_file_buffer(jh, commit_transaction, BJ_Forget); /* Wake up any transactions which were waiting for this IO to complete */ wake_up_bit(&bh->b_state, BH_Unshadow); @@ -733,8 +733,8 @@ wait_for_iobuf: BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile"); clear_buffer_jwrite(bh); - journal_unfile_buffer(journal, jh); - journal_put_journal_head(jh); + jbd2_journal_unfile_buffer(journal, jh); + jbd2_journal_put_journal_head(jh); __brelse(bh); /* One for getblk */ /* AKPM: bforget here */ } @@ -745,7 +745,7 @@ wait_for_iobuf: err = -EIO; if (err) - __journal_abort_hard(journal); + __jbd2_journal_abort_hard(journal); /* End of a transaction! Finally, we can do checkpoint processing: any buffers committed as a result of this @@ -789,14 +789,14 @@ restart_loop: * Otherwise, we can just throw away the frozen data now. */ if (jh->b_committed_data) { - jbd_slab_free(jh->b_committed_data, bh->b_size); + jbd2_slab_free(jh->b_committed_data, bh->b_size); jh->b_committed_data = NULL; if (jh->b_frozen_data) { jh->b_committed_data = jh->b_frozen_data; jh->b_frozen_data = NULL; } } else if (jh->b_frozen_data) { - jbd_slab_free(jh->b_frozen_data, bh->b_size); + jbd2_slab_free(jh->b_frozen_data, bh->b_size); jh->b_frozen_data = NULL; } @@ -804,12 +804,12 @@ restart_loop: cp_transaction = jh->b_cp_transaction; if (cp_transaction) { JBUFFER_TRACE(jh, "remove from old cp transaction"); - __journal_remove_checkpoint(jh); + __jbd2_journal_remove_checkpoint(jh); } /* Only re-checkpoint the buffer_head if it is marked * dirty. If the buffer was added to the BJ_Forget list - * by journal_forget, it may no longer be dirty and + * by jbd2_journal_forget, it may no longer be dirty and * there's no point in keeping a checkpoint record for * it. */ @@ -828,9 +828,9 @@ restart_loop: if (buffer_jbddirty(bh)) { JBUFFER_TRACE(jh, "add to new checkpointing trans"); - __journal_insert_checkpoint(jh, commit_transaction); + __jbd2_journal_insert_checkpoint(jh, commit_transaction); JBUFFER_TRACE(jh, "refile for checkpoint writeback"); - __journal_refile_buffer(jh); + __jbd2_journal_refile_buffer(jh); jbd_unlock_bh_state(bh); } else { J_ASSERT_BH(bh, !buffer_dirty(bh)); @@ -842,11 +842,11 @@ restart_loop: * disk and before we process the buffer on BJ_Forget * list. */ JBUFFER_TRACE(jh, "refile or unfile freed buffer"); - __journal_refile_buffer(jh); + __jbd2_journal_refile_buffer(jh); if (!jh->b_transaction) { jbd_unlock_bh_state(bh); /* needs a brelse */ - journal_remove_journal_head(bh); + jbd2_journal_remove_journal_head(bh); release_buffer_page(bh); } else jbd_unlock_bh_state(bh); @@ -856,9 +856,9 @@ restart_loop: spin_unlock(&journal->j_list_lock); /* * This is a bit sleazy. We borrow j_list_lock to protect - * journal->j_committing_transaction in __journal_remove_checkpoint. - * Really, __journal_remove_checkpoint should be using j_state_lock but - * it's a bit hassle to hold that across __journal_remove_checkpoint + * journal->j_committing_transaction in __jbd2_journal_remove_checkpoint. + * Really, __jbd2_journal_remove_checkpoint should be using j_state_lock but + * it's a bit hassle to hold that across __jbd2_journal_remove_checkpoint */ spin_lock(&journal->j_state_lock); spin_lock(&journal->j_list_lock); @@ -885,7 +885,7 @@ restart_loop: spin_unlock(&journal->j_state_lock); if (commit_transaction->t_checkpoint_list == NULL) { - __journal_drop_transaction(journal, commit_transaction); + __jbd2_journal_drop_transaction(journal, commit_transaction); } else { if (journal->j_checkpoint_transactions == NULL) { journal->j_checkpoint_transactions = commit_transaction; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index c518dd8fe60a..3fbbba20a516 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1,5 +1,5 @@ /* - * linux/fs/jbd/journal.c + * linux/fs/jbd2/journal.c * * Written by Stephen C. Tweedie , 1998 * @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -40,51 +40,51 @@ #include #include -EXPORT_SYMBOL(journal_start); -EXPORT_SYMBOL(journal_restart); -EXPORT_SYMBOL(journal_extend); -EXPORT_SYMBOL(journal_stop); -EXPORT_SYMBOL(journal_lock_updates); -EXPORT_SYMBOL(journal_unlock_updates); -EXPORT_SYMBOL(journal_get_write_access); -EXPORT_SYMBOL(journal_get_create_access); -EXPORT_SYMBOL(journal_get_undo_access); -EXPORT_SYMBOL(journal_dirty_data); -EXPORT_SYMBOL(journal_dirty_metadata); -EXPORT_SYMBOL(journal_release_buffer); -EXPORT_SYMBOL(journal_forget); +EXPORT_SYMBOL(jbd2_journal_start); +EXPORT_SYMBOL(jbd2_journal_restart); +EXPORT_SYMBOL(jbd2_journal_extend); +EXPORT_SYMBOL(jbd2_journal_stop); +EXPORT_SYMBOL(jbd2_journal_lock_updates); +EXPORT_SYMBOL(jbd2_journal_unlock_updates); +EXPORT_SYMBOL(jbd2_journal_get_write_access); +EXPORT_SYMBOL(jbd2_journal_get_create_access); +EXPORT_SYMBOL(jbd2_journal_get_undo_access); +EXPORT_SYMBOL(jbd2_journal_dirty_data); +EXPORT_SYMBOL(jbd2_journal_dirty_metadata); +EXPORT_SYMBOL(jbd2_journal_release_buffer); +EXPORT_SYMBOL(jbd2_journal_forget); #if 0 EXPORT_SYMBOL(journal_sync_buffer); #endif -EXPORT_SYMBOL(journal_flush); -EXPORT_SYMBOL(journal_revoke); - -EXPORT_SYMBOL(journal_init_dev); -EXPORT_SYMBOL(journal_init_inode); -EXPORT_SYMBOL(journal_update_format); -EXPORT_SYMBOL(journal_check_used_features); -EXPORT_SYMBOL(journal_check_available_features); -EXPORT_SYMBOL(journal_set_features); -EXPORT_SYMBOL(journal_create); -EXPORT_SYMBOL(journal_load); -EXPORT_SYMBOL(journal_destroy); -EXPORT_SYMBOL(journal_update_superblock); -EXPORT_SYMBOL(journal_abort); -EXPORT_SYMBOL(journal_errno); -EXPORT_SYMBOL(journal_ack_err); -EXPORT_SYMBOL(journal_clear_err); -EXPORT_SYMBOL(log_wait_commit); -EXPORT_SYMBOL(journal_start_commit); -EXPORT_SYMBOL(journal_force_commit_nested); -EXPORT_SYMBOL(journal_wipe); -EXPORT_SYMBOL(journal_blocks_per_page); -EXPORT_SYMBOL(journal_invalidatepage); -EXPORT_SYMBOL(journal_try_to_free_buffers); -EXPORT_SYMBOL(journal_force_commit); +EXPORT_SYMBOL(jbd2_journal_flush); +EXPORT_SYMBOL(jbd2_journal_revoke); + +EXPORT_SYMBOL(jbd2_journal_init_dev); +EXPORT_SYMBOL(jbd2_journal_init_inode); +EXPORT_SYMBOL(jbd2_journal_update_format); +EXPORT_SYMBOL(jbd2_journal_check_used_features); +EXPORT_SYMBOL(jbd2_journal_check_available_features); +EXPORT_SYMBOL(jbd2_journal_set_features); +EXPORT_SYMBOL(jbd2_journal_create); +EXPORT_SYMBOL(jbd2_journal_load); +EXPORT_SYMBOL(jbd2_journal_destroy); +EXPORT_SYMBOL(jbd2_journal_update_superblock); +EXPORT_SYMBOL(jbd2_journal_abort); +EXPORT_SYMBOL(jbd2_journal_errno); +EXPORT_SYMBOL(jbd2_journal_ack_err); +EXPORT_SYMBOL(jbd2_journal_clear_err); +EXPORT_SYMBOL(jbd2_log_wait_commit); +EXPORT_SYMBOL(jbd2_journal_start_commit); +EXPORT_SYMBOL(jbd2_journal_force_commit_nested); +EXPORT_SYMBOL(jbd2_journal_wipe); +EXPORT_SYMBOL(jbd2_journal_blocks_per_page); +EXPORT_SYMBOL(jbd2_journal_invalidatepage); +EXPORT_SYMBOL(jbd2_journal_try_to_free_buffers); +EXPORT_SYMBOL(jbd2_journal_force_commit); static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); static void __journal_abort_soft (journal_t *journal, int errno); -static int journal_create_jbd_slab(size_t slab_size); +static int jbd2_journal_create_jbd_slab(size_t slab_size); /* * Helper function used to manage commit timeouts @@ -98,7 +98,7 @@ static void commit_timeout(unsigned long __data) } /* - * kjournald: The main thread function used to manage a logging device + * kjournald2: The main thread function used to manage a logging device * journal. * * This kernel thread is responsible for two things: @@ -113,7 +113,7 @@ static void commit_timeout(unsigned long __data) * known as checkpointing, and this thread is responsible for that job. */ -static int kjournald(void *arg) +static int kjournald2(void *arg) { journal_t *journal = arg; transaction_t *transaction; @@ -129,7 +129,7 @@ static int kjournald(void *arg) journal->j_task = current; wake_up(&journal->j_wait_done_commit); - printk(KERN_INFO "kjournald starting. Commit interval %ld seconds\n", + printk(KERN_INFO "kjournald2 starting. Commit interval %ld seconds\n", journal->j_commit_interval / HZ); /* @@ -138,7 +138,7 @@ static int kjournald(void *arg) spin_lock(&journal->j_state_lock); loop: - if (journal->j_flags & JFS_UNMOUNT) + if (journal->j_flags & JBD2_UNMOUNT) goto end_loop; jbd_debug(1, "commit_sequence=%d, commit_request=%d\n", @@ -148,7 +148,7 @@ loop: jbd_debug(1, "OK, requests differ\n"); spin_unlock(&journal->j_state_lock); del_timer_sync(&journal->j_commit_timer); - journal_commit_transaction(journal); + jbd2_journal_commit_transaction(journal); spin_lock(&journal->j_state_lock); goto loop; } @@ -160,7 +160,7 @@ loop: * good idea, because that depends on threads that may * be already stopped. */ - jbd_debug(1, "Now suspending kjournald\n"); + jbd_debug(1, "Now suspending kjournald2\n"); spin_unlock(&journal->j_state_lock); refrigerator(); spin_lock(&journal->j_state_lock); @@ -180,7 +180,7 @@ loop: if (transaction && time_after_eq(jiffies, transaction->t_expires)) should_sleep = 0; - if (journal->j_flags & JFS_UNMOUNT) + if (journal->j_flags & JBD2_UNMOUNT) should_sleep = 0; if (should_sleep) { spin_unlock(&journal->j_state_lock); @@ -190,7 +190,7 @@ loop: finish_wait(&journal->j_wait_commit, &wait); } - jbd_debug(1, "kjournald wakes\n"); + jbd_debug(1, "kjournald2 wakes\n"); /* * Were we woken up by a commit wakeup event? @@ -211,16 +211,16 @@ end_loop: return 0; } -static void journal_start_thread(journal_t *journal) +static void jbd2_journal_start_thread(journal_t *journal) { - kthread_run(kjournald, journal, "kjournald"); + kthread_run(kjournald2, journal, "kjournald2"); wait_event(journal->j_wait_done_commit, journal->j_task != 0); } static void journal_kill_thread(journal_t *journal) { spin_lock(&journal->j_state_lock); - journal->j_flags |= JFS_UNMOUNT; + journal->j_flags |= JBD2_UNMOUNT; while (journal->j_task) { wake_up(&journal->j_wait_commit); @@ -232,7 +232,7 @@ static void journal_kill_thread(journal_t *journal) } /* - * journal_write_metadata_buffer: write a metadata buffer to the journal. + * jbd2_journal_write_metadata_buffer: write a metadata buffer to the journal. * * Writes a metadata buffer to a given disk block. The actual IO is not * performed but a new buffer_head is constructed which labels the data @@ -240,7 +240,7 @@ static void journal_kill_thread(journal_t *journal) * * Any magic-number escaping which needs to be done will cause a * copy-out here. If the buffer happens to start with the - * JFS_MAGIC_NUMBER, then we can't write it to the log directly: the + * JBD2_MAGIC_NUMBER, then we can't write it to the log directly: the * magic number is only written to the log for descripter blocks. In * this case, we copy the data and replace the first word with 0, and we * return a result code which indicates that this buffer needs to be @@ -268,7 +268,7 @@ static void journal_kill_thread(journal_t *journal) * Bit 1 set == buffer copy-out performed (kfree the data after IO) */ -int journal_write_metadata_buffer(transaction_t *transaction, +int jbd2_journal_write_metadata_buffer(transaction_t *transaction, struct journal_head *jh_in, struct journal_head **jh_out, unsigned long blocknr) @@ -316,7 +316,7 @@ repeat: * Check for escaping */ if (*((__be32 *)(mapped_data + new_offset)) == - cpu_to_be32(JFS_MAGIC_NUMBER)) { + cpu_to_be32(JBD2_MAGIC_NUMBER)) { need_copy_out = 1; do_escape = 1; } @@ -329,10 +329,10 @@ repeat: char *tmp; jbd_unlock_bh_state(bh_in); - tmp = jbd_slab_alloc(bh_in->b_size, GFP_NOFS); + tmp = jbd2_slab_alloc(bh_in->b_size, GFP_NOFS); jbd_lock_bh_state(bh_in); if (jh_in->b_frozen_data) { - jbd_slab_free(tmp, bh_in->b_size); + jbd2_slab_free(tmp, bh_in->b_size); goto repeat; } @@ -362,7 +362,7 @@ repeat: atomic_set(&new_bh->b_count, 1); jbd_unlock_bh_state(bh_in); - new_jh = journal_add_journal_head(new_bh); /* This sleeps */ + new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */ set_bh_page(new_bh, new_page, new_offset); new_jh->b_transaction = NULL; @@ -380,9 +380,9 @@ repeat: * copying is moved to the transaction's shadow queue. */ JBUFFER_TRACE(jh_in, "file as BJ_Shadow"); - journal_file_buffer(jh_in, transaction, BJ_Shadow); + jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow); JBUFFER_TRACE(new_jh, "file as BJ_IO"); - journal_file_buffer(new_jh, transaction, BJ_IO); + jbd2_journal_file_buffer(new_jh, transaction, BJ_IO); return do_escape | (done_copy_out << 1); } @@ -393,14 +393,14 @@ repeat: */ /* - * __log_space_left: Return the number of free blocks left in the journal. + * __jbd2_log_space_left: Return the number of free blocks left in the journal. * * Called with the journal already locked. * * Called under j_state_lock */ -int __log_space_left(journal_t *journal) +int __jbd2_log_space_left(journal_t *journal) { int left = journal->j_free; @@ -424,7 +424,7 @@ int __log_space_left(journal_t *journal) /* * Called under j_state_lock. Returns true if a transaction was started. */ -int __log_start_commit(journal_t *journal, tid_t target) +int __jbd2_log_start_commit(journal_t *journal, tid_t target) { /* * Are we already doing a recent enough commit? @@ -445,12 +445,12 @@ int __log_start_commit(journal_t *journal, tid_t target) return 0; } -int log_start_commit(journal_t *journal, tid_t tid) +int jbd2_log_start_commit(journal_t *journal, tid_t tid) { int ret; spin_lock(&journal->j_state_lock); - ret = __log_start_commit(journal, tid); + ret = __jbd2_log_start_commit(journal, tid); spin_unlock(&journal->j_state_lock); return ret; } @@ -465,7 +465,7 @@ int log_start_commit(journal_t *journal, tid_t tid) * * Returns true if a transaction was started. */ -int journal_force_commit_nested(journal_t *journal) +int jbd2_journal_force_commit_nested(journal_t *journal) { transaction_t *transaction = NULL; tid_t tid; @@ -473,7 +473,7 @@ int journal_force_commit_nested(journal_t *journal) spin_lock(&journal->j_state_lock); if (journal->j_running_transaction && !current->journal_info) { transaction = journal->j_running_transaction; - __log_start_commit(journal, transaction->t_tid); + __jbd2_log_start_commit(journal, transaction->t_tid); } else if (journal->j_committing_transaction) transaction = journal->j_committing_transaction; @@ -484,7 +484,7 @@ int journal_force_commit_nested(journal_t *journal) tid = transaction->t_tid; spin_unlock(&journal->j_state_lock); - log_wait_commit(journal, tid); + jbd2_log_wait_commit(journal, tid); return 1; } @@ -492,7 +492,7 @@ int journal_force_commit_nested(journal_t *journal) * Start a commit of the current running transaction (if any). Returns true * if a transaction was started, and fills its tid in at *ptid */ -int journal_start_commit(journal_t *journal, tid_t *ptid) +int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid) { int ret = 0; @@ -500,7 +500,7 @@ int journal_start_commit(journal_t *journal, tid_t *ptid) if (journal->j_running_transaction) { tid_t tid = journal->j_running_transaction->t_tid; - ret = __log_start_commit(journal, tid); + ret = __jbd2_log_start_commit(journal, tid); if (ret && ptid) *ptid = tid; } else if (journal->j_committing_transaction && ptid) { @@ -519,7 +519,7 @@ int journal_start_commit(journal_t *journal, tid_t *ptid) * Wait for a specified commit to complete. * The caller may not hold the journal lock. */ -int log_wait_commit(journal_t *journal, tid_t tid) +int jbd2_log_wait_commit(journal_t *journal, tid_t tid) { int err = 0; @@ -555,7 +555,7 @@ int log_wait_commit(journal_t *journal, tid_t tid) * Log buffer allocation routines: */ -int journal_next_log_block(journal_t *journal, unsigned long *retp) +int jbd2_journal_next_log_block(journal_t *journal, unsigned long *retp) { unsigned long blocknr; @@ -568,7 +568,7 @@ int journal_next_log_block(journal_t *journal, unsigned long *retp) if (journal->j_head == journal->j_last) journal->j_head = journal->j_first; spin_unlock(&journal->j_state_lock); - return journal_bmap(journal, blocknr, retp); + return jbd2_journal_bmap(journal, blocknr, retp); } /* @@ -578,7 +578,7 @@ int journal_next_log_block(journal_t *journal, unsigned long *retp) * this is a no-op. If needed, we can use j_blk_offset - everything is * ready. */ -int journal_bmap(journal_t *journal, unsigned long blocknr, +int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr, unsigned long *retp) { int err = 0; @@ -610,18 +610,18 @@ int journal_bmap(journal_t *journal, unsigned long blocknr, * the journal without copying their contents, but for journal * descriptor blocks we do need to generate bona fide buffers. * - * After the caller of journal_get_descriptor_buffer() has finished modifying + * After the caller of jbd2_journal_get_descriptor_buffer() has finished modifying * the buffer's contents they really should run flush_dcache_page(bh->b_page). * But we don't bother doing that, so there will be coherency problems with * mmaps of blockdevs which hold live JBD-controlled filesystems. */ -struct journal_head *journal_get_descriptor_buffer(journal_t *journal) +struct journal_head *jbd2_journal_get_descriptor_buffer(journal_t *journal) { struct buffer_head *bh; unsigned long blocknr; int err; - err = journal_next_log_block(journal, &blocknr); + err = jbd2_journal_next_log_block(journal, &blocknr); if (err) return NULL; @@ -632,7 +632,7 @@ struct journal_head *journal_get_descriptor_buffer(journal_t *journal) set_buffer_uptodate(bh); unlock_buffer(bh); BUFFER_TRACE(bh, "return this buffer"); - return journal_add_journal_head(bh); + return jbd2_journal_add_journal_head(bh); } /* @@ -669,10 +669,10 @@ static journal_t * journal_init_common (void) journal->j_commit_interval = (HZ * JBD_DEFAULT_MAX_COMMIT_AGE); /* The journal is marked for error until we succeed with recovery! */ - journal->j_flags = JFS_ABORT; + journal->j_flags = JBD2_ABORT; /* Set up a default-sized revoke table for the new mount. */ - err = journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH); + err = jbd2_journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH); if (err) { kfree(journal); goto fail; @@ -682,7 +682,7 @@ fail: return NULL; } -/* journal_init_dev and journal_init_inode: +/* jbd2_journal_init_dev and jbd2_journal_init_inode: * * Create a journal structure assigned some fixed set of disk blocks to * the journal. We don't actually touch those disk blocks yet, but we @@ -692,7 +692,7 @@ fail: */ /** - * journal_t * journal_init_dev() - creates an initialises a journal structure + * journal_t * jbd2_journal_init_dev() - creates an initialises a journal structure * @bdev: Block device on which to create the journal * @fs_dev: Device which hold journalled filesystem for this journal. * @start: Block nr Start of journal. @@ -700,11 +700,11 @@ fail: * @blocksize: blocksize of journalling device * @returns: a newly created journal_t * * - * journal_init_dev creates a journal which maps a fixed contiguous + * jbd2_journal_init_dev creates a journal which maps a fixed contiguous * range of blocks on an arbitrary block device. * */ -journal_t * journal_init_dev(struct block_device *bdev, +journal_t * jbd2_journal_init_dev(struct block_device *bdev, struct block_device *fs_dev, int start, int len, int blocksize) { @@ -740,14 +740,14 @@ journal_t * journal_init_dev(struct block_device *bdev, } /** - * journal_t * journal_init_inode () - creates a journal which maps to a inode. + * journal_t * jbd2_journal_init_inode () - creates a journal which maps to a inode. * @inode: An inode to create the journal in * - * journal_init_inode creates a journal which maps an on-disk inode as + * jbd2_journal_init_inode creates a journal which maps an on-disk inode as * the journal. The inode must exist already, must support bmap() and * must have all data blocks preallocated. */ -journal_t * journal_init_inode (struct inode *inode) +journal_t * jbd2_journal_init_inode (struct inode *inode) { struct buffer_head *bh; journal_t *journal = journal_init_common(); @@ -780,7 +780,7 @@ journal_t * journal_init_inode (struct inode *inode) return NULL; } - err = journal_bmap(journal, 0, &blocknr); + err = jbd2_journal_bmap(journal, 0, &blocknr); /* If that failed, give up */ if (err) { printk(KERN_ERR "%s: Cannnot locate journal superblock\n", @@ -838,27 +838,27 @@ static int journal_reset(journal_t *journal) journal->j_max_transaction_buffers = journal->j_maxlen / 4; /* Add the dynamic fields and write it to disk. */ - journal_update_superblock(journal, 1); - journal_start_thread(journal); + jbd2_journal_update_superblock(journal, 1); + jbd2_journal_start_thread(journal); return 0; } /** - * int journal_create() - Initialise the new journal file + * int jbd2_journal_create() - Initialise the new journal file * @journal: Journal to create. This structure must have been initialised * * Given a journal_t structure which tells us which disk blocks we can * use, create a new journal superblock and initialise all of the * journal fields from scratch. **/ -int journal_create(journal_t *journal) +int jbd2_journal_create(journal_t *journal) { unsigned long blocknr; struct buffer_head *bh; journal_superblock_t *sb; int i, err; - if (journal->j_maxlen < JFS_MIN_JOURNAL_BLOCKS) { + if (journal->j_maxlen < JBD2_MIN_JOURNAL_BLOCKS) { printk (KERN_ERR "Journal length (%d blocks) too short.\n", journal->j_maxlen); journal_fail_superblock(journal); @@ -876,10 +876,10 @@ int journal_create(journal_t *journal) } /* Zero out the entire journal on disk. We cannot afford to - have any blocks on disk beginning with JFS_MAGIC_NUMBER. */ + have any blocks on disk beginning with JBD2_MAGIC_NUMBER. */ jbd_debug(1, "JBD: Zeroing out journal blocks...\n"); for (i = 0; i < journal->j_maxlen; i++) { - err = journal_bmap(journal, i, &blocknr); + err = jbd2_journal_bmap(journal, i, &blocknr); if (err) return err; bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); @@ -899,8 +899,8 @@ int journal_create(journal_t *journal) /* OK, fill in the initial static fields in the new superblock */ sb = journal->j_superblock; - sb->s_header.h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); - sb->s_header.h_blocktype = cpu_to_be32(JFS_SUPERBLOCK_V2); + sb->s_header.h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER); + sb->s_header.h_blocktype = cpu_to_be32(JBD2_SUPERBLOCK_V2); sb->s_blocksize = cpu_to_be32(journal->j_blocksize); sb->s_maxlen = cpu_to_be32(journal->j_maxlen); @@ -908,21 +908,21 @@ int journal_create(journal_t *journal) journal->j_transaction_sequence = 1; - journal->j_flags &= ~JFS_ABORT; + journal->j_flags &= ~JBD2_ABORT; journal->j_format_version = 2; return journal_reset(journal); } /** - * void journal_update_superblock() - Update journal sb on disk. + * void jbd2_journal_update_superblock() - Update journal sb on disk. * @journal: The journal to update. * @wait: Set to '0' if you don't want to wait for IO completion. * * Update a journal's dynamic superblock fields and write it to disk, * optionally waiting for the IO to complete. */ -void journal_update_superblock(journal_t *journal, int wait) +void jbd2_journal_update_superblock(journal_t *journal, int wait) { journal_superblock_t *sb = journal->j_superblock; struct buffer_head *bh = journal->j_sb_buffer; @@ -931,7 +931,7 @@ void journal_update_superblock(journal_t *journal, int wait) * As a special case, if the on-disk copy is already marked as needing * no recovery (s_start == 0) and there are no outstanding transactions * in the filesystem, then we can safely defer the superblock update - * until the next commit by setting JFS_FLUSHED. This avoids + * until the next commit by setting JBD2_FLUSHED. This avoids * attempting a write to a potential-readonly device. */ if (sb->s_start == 0 && journal->j_tail_sequence == @@ -966,9 +966,9 @@ out: spin_lock(&journal->j_state_lock); if (sb->s_start) - journal->j_flags &= ~JFS_FLUSHED; + journal->j_flags &= ~JBD2_FLUSHED; else - journal->j_flags |= JFS_FLUSHED; + journal->j_flags |= JBD2_FLUSHED; spin_unlock(&journal->j_state_lock); } @@ -1000,17 +1000,17 @@ static int journal_get_superblock(journal_t *journal) err = -EINVAL; - if (sb->s_header.h_magic != cpu_to_be32(JFS_MAGIC_NUMBER) || + if (sb->s_header.h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER) || sb->s_blocksize != cpu_to_be32(journal->j_blocksize)) { printk(KERN_WARNING "JBD: no valid journal superblock found\n"); goto out; } switch(be32_to_cpu(sb->s_header.h_blocktype)) { - case JFS_SUPERBLOCK_V1: + case JBD2_SUPERBLOCK_V1: journal->j_format_version = 1; break; - case JFS_SUPERBLOCK_V2: + case JBD2_SUPERBLOCK_V2: journal->j_format_version = 2; break; default: @@ -1059,14 +1059,14 @@ static int load_superblock(journal_t *journal) /** - * int journal_load() - Read journal from disk. + * int jbd2_journal_load() - Read journal from disk. * @journal: Journal to act on. * * Given a journal_t structure which tells us which disk blocks contain * a journal, read the journal from disk to initialise the in-memory * structures. */ -int journal_load(journal_t *journal) +int jbd2_journal_load(journal_t *journal) { int err; journal_superblock_t *sb; @@ -1081,9 +1081,9 @@ int journal_load(journal_t *journal) if (journal->j_format_version >= 2) { if ((sb->s_feature_ro_compat & - ~cpu_to_be32(JFS_KNOWN_ROCOMPAT_FEATURES)) || + ~cpu_to_be32(JBD2_KNOWN_ROCOMPAT_FEATURES)) || (sb->s_feature_incompat & - ~cpu_to_be32(JFS_KNOWN_INCOMPAT_FEATURES))) { + ~cpu_to_be32(JBD2_KNOWN_INCOMPAT_FEATURES))) { printk (KERN_WARNING "JBD: Unrecognised features on journal\n"); return -EINVAL; @@ -1093,13 +1093,13 @@ int journal_load(journal_t *journal) /* * Create a slab for this blocksize */ - err = journal_create_jbd_slab(be32_to_cpu(sb->s_blocksize)); + err = jbd2_journal_create_jbd_slab(be32_to_cpu(sb->s_blocksize)); if (err) return err; /* Let the recovery code check whether it needs to recover any * data from the journal. */ - if (journal_recover(journal)) + if (jbd2_journal_recover(journal)) goto recovery_error; /* OK, we've finished with the dynamic journal bits: @@ -1108,8 +1108,8 @@ int journal_load(journal_t *journal) if (journal_reset(journal)) goto recovery_error; - journal->j_flags &= ~JFS_ABORT; - journal->j_flags |= JFS_LOADED; + journal->j_flags &= ~JBD2_ABORT; + journal->j_flags |= JBD2_LOADED; return 0; recovery_error: @@ -1118,20 +1118,20 @@ recovery_error: } /** - * void journal_destroy() - Release a journal_t structure. + * void jbd2_journal_destroy() - Release a journal_t structure. * @journal: Journal to act on. * * Release a journal_t structure once it is no longer in use by the * journaled object. */ -void journal_destroy(journal_t *journal) +void jbd2_journal_destroy(journal_t *journal) { /* Wait for the commit thread to wake up and die. */ journal_kill_thread(journal); /* Force a final log commit */ if (journal->j_running_transaction) - journal_commit_transaction(journal); + jbd2_journal_commit_transaction(journal); /* Force any old transactions to disk */ @@ -1139,7 +1139,7 @@ void journal_destroy(journal_t *journal) spin_lock(&journal->j_list_lock); while (journal->j_checkpoint_transactions != NULL) { spin_unlock(&journal->j_list_lock); - log_do_checkpoint(journal); + jbd2_log_do_checkpoint(journal); spin_lock(&journal->j_list_lock); } @@ -1152,21 +1152,21 @@ void journal_destroy(journal_t *journal) journal->j_tail = 0; journal->j_tail_sequence = ++journal->j_transaction_sequence; if (journal->j_sb_buffer) { - journal_update_superblock(journal, 1); + jbd2_journal_update_superblock(journal, 1); brelse(journal->j_sb_buffer); } if (journal->j_inode) iput(journal->j_inode); if (journal->j_revoke) - journal_destroy_revoke(journal); + jbd2_journal_destroy_revoke(journal); kfree(journal->j_wbuf); kfree(journal); } /** - *int journal_check_used_features () - Check if features specified are used. + *int jbd2_journal_check_used_features () - Check if features specified are used. * @journal: Journal to check. * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount @@ -1176,7 +1176,7 @@ void journal_destroy(journal_t *journal) * features. Return true (non-zero) if it does. **/ -int journal_check_used_features (journal_t *journal, unsigned long compat, +int jbd2_journal_check_used_features (journal_t *journal, unsigned long compat, unsigned long ro, unsigned long incompat) { journal_superblock_t *sb; @@ -1197,7 +1197,7 @@ int journal_check_used_features (journal_t *journal, unsigned long compat, } /** - * int journal_check_available_features() - Check feature set in journalling layer + * int jbd2_journal_check_available_features() - Check feature set in journalling layer * @journal: Journal to check. * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount @@ -1207,7 +1207,7 @@ int journal_check_used_features (journal_t *journal, unsigned long compat, * all of a given set of features on this journal. Return true * (non-zero) if it can. */ -int journal_check_available_features (journal_t *journal, unsigned long compat, +int jbd2_journal_check_available_features (journal_t *journal, unsigned long compat, unsigned long ro, unsigned long incompat) { journal_superblock_t *sb; @@ -1224,16 +1224,16 @@ int journal_check_available_features (journal_t *journal, unsigned long compat, if (journal->j_format_version != 2) return 0; - if ((compat & JFS_KNOWN_COMPAT_FEATURES) == compat && - (ro & JFS_KNOWN_ROCOMPAT_FEATURES) == ro && - (incompat & JFS_KNOWN_INCOMPAT_FEATURES) == incompat) + if ((compat & JBD2_KNOWN_COMPAT_FEATURES) == compat && + (ro & JBD2_KNOWN_ROCOMPAT_FEATURES) == ro && + (incompat & JBD2_KNOWN_INCOMPAT_FEATURES) == incompat) return 1; return 0; } /** - * int journal_set_features () - Mark a given journal feature in the superblock + * int jbd2_journal_set_features () - Mark a given journal feature in the superblock * @journal: Journal to act on. * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount @@ -1244,15 +1244,15 @@ int journal_check_available_features (journal_t *journal, unsigned long compat, * */ -int journal_set_features (journal_t *journal, unsigned long compat, +int jbd2_journal_set_features (journal_t *journal, unsigned long compat, unsigned long ro, unsigned long incompat) { journal_superblock_t *sb; - if (journal_check_used_features(journal, compat, ro, incompat)) + if (jbd2_journal_check_used_features(journal, compat, ro, incompat)) return 1; - if (!journal_check_available_features(journal, compat, ro, incompat)) + if (!jbd2_journal_check_available_features(journal, compat, ro, incompat)) return 0; jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n", @@ -1269,13 +1269,13 @@ int journal_set_features (journal_t *journal, unsigned long compat, /** - * int journal_update_format () - Update on-disk journal structure. + * int jbd2_journal_update_format () - Update on-disk journal structure. * @journal: Journal to act on. * * Given an initialised but unloaded journal struct, poke about in the * on-disk structure to update it to the most recent supported version. */ -int journal_update_format (journal_t *journal) +int jbd2_journal_update_format (journal_t *journal) { journal_superblock_t *sb; int err; @@ -1287,9 +1287,9 @@ int journal_update_format (journal_t *journal) sb = journal->j_superblock; switch (be32_to_cpu(sb->s_header.h_blocktype)) { - case JFS_SUPERBLOCK_V2: + case JBD2_SUPERBLOCK_V2: return 0; - case JFS_SUPERBLOCK_V1: + case JBD2_SUPERBLOCK_V1: return journal_convert_superblock_v1(journal, sb); default: break; @@ -1312,7 +1312,7 @@ static int journal_convert_superblock_v1(journal_t *journal, memset(&sb->s_feature_compat, 0, blocksize-offset); sb->s_nr_users = cpu_to_be32(1); - sb->s_header.h_blocktype = cpu_to_be32(JFS_SUPERBLOCK_V2); + sb->s_header.h_blocktype = cpu_to_be32(JBD2_SUPERBLOCK_V2); journal->j_format_version = 2; bh = journal->j_sb_buffer; @@ -1324,7 +1324,7 @@ static int journal_convert_superblock_v1(journal_t *journal, /** - * int journal_flush () - Flush journal + * int jbd2_journal_flush () - Flush journal * @journal: Journal to act on. * * Flush all data for a given journal to disk and empty the journal. @@ -1332,7 +1332,7 @@ static int journal_convert_superblock_v1(journal_t *journal, * recovery does not need to happen on remount. */ -int journal_flush(journal_t *journal) +int jbd2_journal_flush(journal_t *journal) { int err = 0; transaction_t *transaction = NULL; @@ -1343,7 +1343,7 @@ int journal_flush(journal_t *journal) /* Force everything buffered to the log... */ if (journal->j_running_transaction) { transaction = journal->j_running_transaction; - __log_start_commit(journal, transaction->t_tid); + __jbd2_log_start_commit(journal, transaction->t_tid); } else if (journal->j_committing_transaction) transaction = journal->j_committing_transaction; @@ -1352,7 +1352,7 @@ int journal_flush(journal_t *journal) tid_t tid = transaction->t_tid; spin_unlock(&journal->j_state_lock); - log_wait_commit(journal, tid); + jbd2_log_wait_commit(journal, tid); } else { spin_unlock(&journal->j_state_lock); } @@ -1361,11 +1361,11 @@ int journal_flush(journal_t *journal) spin_lock(&journal->j_list_lock); while (!err && journal->j_checkpoint_transactions != NULL) { spin_unlock(&journal->j_list_lock); - err = log_do_checkpoint(journal); + err = jbd2_log_do_checkpoint(journal); spin_lock(&journal->j_list_lock); } spin_unlock(&journal->j_list_lock); - cleanup_journal_tail(journal); + jbd2_cleanup_journal_tail(journal); /* Finally, mark the journal as really needing no recovery. * This sets s_start==0 in the underlying superblock, which is @@ -1376,7 +1376,7 @@ int journal_flush(journal_t *journal) old_tail = journal->j_tail; journal->j_tail = 0; spin_unlock(&journal->j_state_lock); - journal_update_superblock(journal, 1); + jbd2_journal_update_superblock(journal, 1); spin_lock(&journal->j_state_lock); journal->j_tail = old_tail; @@ -1390,24 +1390,24 @@ int journal_flush(journal_t *journal) } /** - * int journal_wipe() - Wipe journal contents + * int jbd2_journal_wipe() - Wipe journal contents * @journal: Journal to act on. * @write: flag (see below) * * Wipe out all of the contents of a journal, safely. This will produce * a warning if the journal contains any valid recovery information. - * Must be called between journal_init_*() and journal_load(). + * Must be called between journal_init_*() and jbd2_journal_load(). * * If 'write' is non-zero, then we wipe out the journal on disk; otherwise * we merely suppress recovery. */ -int journal_wipe(journal_t *journal, int write) +int jbd2_journal_wipe(journal_t *journal, int write) { journal_superblock_t *sb; int err = 0; - J_ASSERT (!(journal->j_flags & JFS_LOADED)); + J_ASSERT (!(journal->j_flags & JBD2_LOADED)); err = load_superblock(journal); if (err) @@ -1421,9 +1421,9 @@ int journal_wipe(journal_t *journal, int write) printk (KERN_WARNING "JBD: %s recovery information on journal\n", write ? "Clearing" : "Ignoring"); - err = journal_skip_recovery(journal); + err = jbd2_journal_skip_recovery(journal); if (write) - journal_update_superblock(journal, 1); + jbd2_journal_update_superblock(journal, 1); no_recovery: return err; @@ -1459,22 +1459,22 @@ static const char *journal_dev_name(journal_t *journal, char *buffer) * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, * and don't attempt to make any other journal updates. */ -void __journal_abort_hard(journal_t *journal) +void __jbd2_journal_abort_hard(journal_t *journal) { transaction_t *transaction; char b[BDEVNAME_SIZE]; - if (journal->j_flags & JFS_ABORT) + if (journal->j_flags & JBD2_ABORT) return; printk(KERN_ERR "Aborting journal on device %s.\n", journal_dev_name(journal, b)); spin_lock(&journal->j_state_lock); - journal->j_flags |= JFS_ABORT; + journal->j_flags |= JBD2_ABORT; transaction = journal->j_running_transaction; if (transaction) - __log_start_commit(journal, transaction->t_tid); + __jbd2_log_start_commit(journal, transaction->t_tid); spin_unlock(&journal->j_state_lock); } @@ -1482,20 +1482,20 @@ void __journal_abort_hard(journal_t *journal) * but don't do any other IO. */ static void __journal_abort_soft (journal_t *journal, int errno) { - if (journal->j_flags & JFS_ABORT) + if (journal->j_flags & JBD2_ABORT) return; if (!journal->j_errno) journal->j_errno = errno; - __journal_abort_hard(journal); + __jbd2_journal_abort_hard(journal); if (errno) - journal_update_superblock(journal, 1); + jbd2_journal_update_superblock(journal, 1); } /** - * void journal_abort () - Shutdown the journal immediately. + * void jbd2_journal_abort () - Shutdown the journal immediately. * @journal: the journal to shutdown. * @errno: an error number to record in the journal indicating * the reason for the shutdown. @@ -1504,7 +1504,7 @@ static void __journal_abort_soft (journal_t *journal, int errno) * journal (not of a single transaction). This operation cannot be * undone without closing and reopening the journal. * - * The journal_abort function is intended to support higher level error + * The jbd2_journal_abort function is intended to support higher level error * recovery mechanisms such as the ext2/ext3 remount-readonly error * mode. * @@ -1520,13 +1520,13 @@ static void __journal_abort_soft (journal_t *journal, int errno) * * Any attempt to get a new transaction handle on a journal which is in * ABORT state will just result in an -EROFS error return. A - * journal_stop on an existing handle will return -EIO if we have + * jbd2_journal_stop on an existing handle will return -EIO if we have * entered abort state during the update. * * Recursive transactions are not disturbed by journal abort until the - * final journal_stop, which will receive the -EIO error. + * final jbd2_journal_stop, which will receive the -EIO error. * - * Finally, the journal_abort call allows the caller to supply an errno + * Finally, the jbd2_journal_abort call allows the caller to supply an errno * which will be recorded (if possible) in the journal superblock. This * allows a client to record failure conditions in the middle of a * transaction without having to complete the transaction to record the @@ -1540,28 +1540,28 @@ static void __journal_abort_soft (journal_t *journal, int errno) * */ -void journal_abort(journal_t *journal, int errno) +void jbd2_journal_abort(journal_t *journal, int errno) { __journal_abort_soft(journal, errno); } /** - * int journal_errno () - returns the journal's error state. + * int jbd2_journal_errno () - returns the journal's error state. * @journal: journal to examine. * - * This is the errno numbet set with journal_abort(), the last + * This is the errno numbet set with jbd2_journal_abort(), the last * time the journal was mounted - if the journal was stopped * without calling abort this will be 0. * * If the journal has been aborted on this mount time -EROFS will * be returned. */ -int journal_errno(journal_t *journal) +int jbd2_journal_errno(journal_t *journal) { int err; spin_lock(&journal->j_state_lock); - if (journal->j_flags & JFS_ABORT) + if (journal->j_flags & JBD2_ABORT) err = -EROFS; else err = journal->j_errno; @@ -1570,18 +1570,18 @@ int journal_errno(journal_t *journal) } /** - * int journal_clear_err () - clears the journal's error state + * int jbd2_journal_clear_err () - clears the journal's error state * @journal: journal to act on. * * An error must be cleared or Acked to take a FS out of readonly * mode. */ -int journal_clear_err(journal_t *journal) +int jbd2_journal_clear_err(journal_t *journal) { int err = 0; spin_lock(&journal->j_state_lock); - if (journal->j_flags & JFS_ABORT) + if (journal->j_flags & JBD2_ABORT) err = -EROFS; else journal->j_errno = 0; @@ -1590,21 +1590,21 @@ int journal_clear_err(journal_t *journal) } /** - * void journal_ack_err() - Ack journal err. + * void jbd2_journal_ack_err() - Ack journal err. * @journal: journal to act on. * * An error must be cleared or Acked to take a FS out of readonly * mode. */ -void journal_ack_err(journal_t *journal) +void jbd2_journal_ack_err(journal_t *journal) { spin_lock(&journal->j_state_lock); if (journal->j_errno) - journal->j_flags |= JFS_ACK_ERR; + journal->j_flags |= JBD2_ACK_ERR; spin_unlock(&journal->j_state_lock); } -int journal_blocks_per_page(struct inode *inode) +int jbd2_journal_blocks_per_page(struct inode *inode) { return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); } @@ -1613,7 +1613,7 @@ int journal_blocks_per_page(struct inode *inode) * Simple support for retrying memory allocations. Introduced to help to * debug different VM deadlock avoidance strategies. */ -void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry) +void * __jbd2_kmalloc (const char *where, size_t size, gfp_t flags, int retry) { return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0)); } @@ -1634,7 +1634,7 @@ static const char *jbd_slab_names[JBD_MAX_SLABS] = { "jbd_1k", "jbd_2k", "jbd_4k", NULL, "jbd_8k" }; -static void journal_destroy_jbd_slabs(void) +static void jbd2_journal_destroy_jbd_slabs(void) { int i; @@ -1645,7 +1645,7 @@ static void journal_destroy_jbd_slabs(void) } } -static int journal_create_jbd_slab(size_t slab_size) +static int jbd2_journal_create_jbd_slab(size_t slab_size) { int i = JBD_SLAB_INDEX(slab_size); @@ -1671,7 +1671,7 @@ static int journal_create_jbd_slab(size_t slab_size) return 0; } -void * jbd_slab_alloc(size_t size, gfp_t flags) +void * jbd2_slab_alloc(size_t size, gfp_t flags) { int idx; @@ -1680,7 +1680,7 @@ void * jbd_slab_alloc(size_t size, gfp_t flags) return kmem_cache_alloc(jbd_slab[idx], flags | __GFP_NOFAIL); } -void jbd_slab_free(void *ptr, size_t size) +void jbd2_slab_free(void *ptr, size_t size) { int idx; @@ -1692,35 +1692,35 @@ void jbd_slab_free(void *ptr, size_t size) /* * Journal_head storage management */ -static kmem_cache_t *journal_head_cache; +static kmem_cache_t *jbd2_journal_head_cache; #ifdef CONFIG_JBD_DEBUG static atomic_t nr_journal_heads = ATOMIC_INIT(0); #endif -static int journal_init_journal_head_cache(void) +static int journal_init_jbd2_journal_head_cache(void) { int retval; - J_ASSERT(journal_head_cache == 0); - journal_head_cache = kmem_cache_create("journal_head", + J_ASSERT(jbd2_journal_head_cache == 0); + jbd2_journal_head_cache = kmem_cache_create("journal_head", sizeof(struct journal_head), 0, /* offset */ 0, /* flags */ NULL, /* ctor */ NULL); /* dtor */ retval = 0; - if (journal_head_cache == 0) { + if (jbd2_journal_head_cache == 0) { retval = -ENOMEM; printk(KERN_EMERG "JBD: no memory for journal_head cache\n"); } return retval; } -static void journal_destroy_journal_head_cache(void) +static void jbd2_journal_destroy_jbd2_journal_head_cache(void) { - J_ASSERT(journal_head_cache != NULL); - kmem_cache_destroy(journal_head_cache); - journal_head_cache = NULL; + J_ASSERT(jbd2_journal_head_cache != NULL); + kmem_cache_destroy(jbd2_journal_head_cache); + jbd2_journal_head_cache = NULL; } /* @@ -1734,7 +1734,7 @@ static struct journal_head *journal_alloc_journal_head(void) #ifdef CONFIG_JBD_DEBUG atomic_inc(&nr_journal_heads); #endif - ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); + ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS); if (ret == 0) { jbd_debug(1, "out of memory for journal_head\n"); if (time_after(jiffies, last_warning + 5*HZ)) { @@ -1744,7 +1744,7 @@ static struct journal_head *journal_alloc_journal_head(void) } while (ret == 0) { yield(); - ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); + ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS); } } return ret; @@ -1756,7 +1756,7 @@ static void journal_free_journal_head(struct journal_head *jh) atomic_dec(&nr_journal_heads); memset(jh, JBD_POISON_FREE, sizeof(*jh)); #endif - kmem_cache_free(journal_head_cache, jh); + kmem_cache_free(jbd2_journal_head_cache, jh); } /* @@ -1775,22 +1775,22 @@ static void journal_free_journal_head(struct journal_head *jh) * * A journal_head may be detached from its buffer_head when the journal_head's * b_transaction, b_cp_transaction and b_next_transaction pointers are NULL. - * Various places in JBD call journal_remove_journal_head() to indicate that the + * Various places in JBD call jbd2_journal_remove_journal_head() to indicate that the * journal_head can be dropped if needed. * * Various places in the kernel want to attach a journal_head to a buffer_head * _before_ attaching the journal_head to a transaction. To protect the - * journal_head in this situation, journal_add_journal_head elevates the + * journal_head in this situation, jbd2_journal_add_journal_head elevates the * journal_head's b_jcount refcount by one. The caller must call - * journal_put_journal_head() to undo this. + * jbd2_journal_put_journal_head() to undo this. * * So the typical usage would be: * * (Attach a journal_head if needed. Increments b_jcount) - * struct journal_head *jh = journal_add_journal_head(bh); + * struct journal_head *jh = jbd2_journal_add_journal_head(bh); * ... * jh->b_transaction = xxx; - * journal_put_journal_head(jh); + * jbd2_journal_put_journal_head(jh); * * Now, the journal_head's b_jcount is zero, but it is safe from being released * because it has a non-zero b_transaction. @@ -1802,7 +1802,7 @@ static void journal_free_journal_head(struct journal_head *jh) * Doesn't need the journal lock. * May sleep. */ -struct journal_head *journal_add_journal_head(struct buffer_head *bh) +struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh) { struct journal_head *jh; struct journal_head *new_jh = NULL; @@ -1845,7 +1845,7 @@ repeat: * Grab a ref against this buffer_head's journal_head. If it ended up not * having a journal_head, return NULL */ -struct journal_head *journal_grab_journal_head(struct buffer_head *bh) +struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh) { struct journal_head *jh = NULL; @@ -1877,13 +1877,13 @@ static void __journal_remove_journal_head(struct buffer_head *bh) printk(KERN_WARNING "%s: freeing " "b_frozen_data\n", __FUNCTION__); - jbd_slab_free(jh->b_frozen_data, bh->b_size); + jbd2_slab_free(jh->b_frozen_data, bh->b_size); } if (jh->b_committed_data) { printk(KERN_WARNING "%s: freeing " "b_committed_data\n", __FUNCTION__); - jbd_slab_free(jh->b_committed_data, bh->b_size); + jbd2_slab_free(jh->b_committed_data, bh->b_size); } bh->b_private = NULL; jh->b_bh = NULL; /* debug, really */ @@ -1897,7 +1897,7 @@ static void __journal_remove_journal_head(struct buffer_head *bh) } /* - * journal_remove_journal_head(): if the buffer isn't attached to a transaction + * jbd2_journal_remove_journal_head(): if the buffer isn't attached to a transaction * and has a zero b_jcount then remove and release its journal_head. If we did * see that the buffer is not used by any transaction we also "logically" * decrement ->b_count. @@ -1905,11 +1905,11 @@ static void __journal_remove_journal_head(struct buffer_head *bh) * We in fact take an additional increment on ->b_count as a convenience, * because the caller usually wants to do additional things with the bh * after calling here. - * The caller of journal_remove_journal_head() *must* run __brelse(bh) at some + * The caller of jbd2_journal_remove_journal_head() *must* run __brelse(bh) at some * time. Once the caller has run __brelse(), the buffer is eligible for * reaping by try_to_free_buffers(). */ -void journal_remove_journal_head(struct buffer_head *bh) +void jbd2_journal_remove_journal_head(struct buffer_head *bh) { jbd_lock_bh_journal_head(bh); __journal_remove_journal_head(bh); @@ -1920,7 +1920,7 @@ void journal_remove_journal_head(struct buffer_head *bh) * Drop a reference on the passed journal_head. If it fell to zero then try to * release the journal_head from the buffer_head. */ -void journal_put_journal_head(struct journal_head *jh) +void jbd2_journal_put_journal_head(struct journal_head *jh) { struct buffer_head *bh = jh2bh(jh); @@ -1938,8 +1938,8 @@ void journal_put_journal_head(struct journal_head *jh) * /proc tunables */ #if defined(CONFIG_JBD_DEBUG) -int journal_enable_debug; -EXPORT_SYMBOL(journal_enable_debug); +int jbd2_journal_enable_debug; +EXPORT_SYMBOL(jbd2_journal_enable_debug); #endif #if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS) @@ -1951,7 +1951,7 @@ static int read_jbd_debug(char *page, char **start, off_t off, { int ret; - ret = sprintf(page + off, "%d\n", journal_enable_debug); + ret = sprintf(page + off, "%d\n", jbd2_journal_enable_debug); *eof = 1; return ret; } @@ -1966,11 +1966,11 @@ static int write_jbd_debug(struct file *file, const char __user *buffer, if (copy_from_user(buf, buffer, count)) return -EFAULT; buf[ARRAY_SIZE(buf) - 1] = '\0'; - journal_enable_debug = simple_strtoul(buf, NULL, 10); + jbd2_journal_enable_debug = simple_strtoul(buf, NULL, 10); return count; } -#define JBD_PROC_NAME "sys/fs/jbd-debug" +#define JBD_PROC_NAME "sys/fs/jbd2-debug" static void __init create_jbd_proc_entry(void) { @@ -1982,7 +1982,7 @@ static void __init create_jbd_proc_entry(void) } } -static void __exit remove_jbd_proc_entry(void) +static void __exit jbd2_remove_jbd_proc_entry(void) { if (proc_jbd_debug) remove_proc_entry(JBD_PROC_NAME, NULL); @@ -1991,31 +1991,31 @@ static void __exit remove_jbd_proc_entry(void) #else #define create_jbd_proc_entry() do {} while (0) -#define remove_jbd_proc_entry() do {} while (0) +#define jbd2_remove_jbd_proc_entry() do {} while (0) #endif -kmem_cache_t *jbd_handle_cache; +kmem_cache_t *jbd2_handle_cache; static int __init journal_init_handle_cache(void) { - jbd_handle_cache = kmem_cache_create("journal_handle", + jbd2_handle_cache = kmem_cache_create("journal_handle", sizeof(handle_t), 0, /* offset */ 0, /* flags */ NULL, /* ctor */ NULL); /* dtor */ - if (jbd_handle_cache == NULL) { + if (jbd2_handle_cache == NULL) { printk(KERN_EMERG "JBD: failed to create handle cache\n"); return -ENOMEM; } return 0; } -static void journal_destroy_handle_cache(void) +static void jbd2_journal_destroy_handle_cache(void) { - if (jbd_handle_cache) - kmem_cache_destroy(jbd_handle_cache); + if (jbd2_handle_cache) + kmem_cache_destroy(jbd2_handle_cache); } /* @@ -2026,20 +2026,20 @@ static int __init journal_init_caches(void) { int ret; - ret = journal_init_revoke_caches(); + ret = jbd2_journal_init_revoke_caches(); if (ret == 0) - ret = journal_init_journal_head_cache(); + ret = journal_init_jbd2_journal_head_cache(); if (ret == 0) ret = journal_init_handle_cache(); return ret; } -static void journal_destroy_caches(void) +static void jbd2_journal_destroy_caches(void) { - journal_destroy_revoke_caches(); - journal_destroy_journal_head_cache(); - journal_destroy_handle_cache(); - journal_destroy_jbd_slabs(); + jbd2_journal_destroy_revoke_caches(); + jbd2_journal_destroy_jbd2_journal_head_cache(); + jbd2_journal_destroy_handle_cache(); + jbd2_journal_destroy_jbd_slabs(); } static int __init journal_init(void) @@ -2050,7 +2050,7 @@ static int __init journal_init(void) ret = journal_init_caches(); if (ret != 0) - journal_destroy_caches(); + jbd2_journal_destroy_caches(); create_jbd_proc_entry(); return ret; } @@ -2062,8 +2062,8 @@ static void __exit journal_exit(void) if (n) printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n); #endif - remove_jbd_proc_entry(); - journal_destroy_caches(); + jbd2_remove_jbd_proc_entry(); + jbd2_journal_destroy_caches(); } MODULE_LICENSE("GPL"); diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 11563fe2a52b..b2012d112432 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -18,7 +18,7 @@ #else #include #include -#include +#include #include #include #endif @@ -86,7 +86,7 @@ static int do_readahead(journal_t *journal, unsigned int start) nbufs = 0; for (next = start; next < max; next++) { - err = journal_bmap(journal, next, &blocknr); + err = jbd2_journal_bmap(journal, next, &blocknr); if (err) { printk (KERN_ERR "JBD: bad block at offset %u\n", @@ -142,7 +142,7 @@ static int jread(struct buffer_head **bhp, journal_t *journal, return -EIO; } - err = journal_bmap(journal, offset, &blocknr); + err = jbd2_journal_bmap(journal, offset, &blocknr); if (err) { printk (KERN_ERR "JBD: bad block at offset %u\n", @@ -191,10 +191,10 @@ static int count_tags(struct buffer_head *bh, int size) nr++; tagp += sizeof(journal_block_tag_t); - if (!(tag->t_flags & cpu_to_be32(JFS_FLAG_SAME_UUID))) + if (!(tag->t_flags & cpu_to_be32(JBD2_FLAG_SAME_UUID))) tagp += 16; - if (tag->t_flags & cpu_to_be32(JFS_FLAG_LAST_TAG)) + if (tag->t_flags & cpu_to_be32(JBD2_FLAG_LAST_TAG)) break; } @@ -210,7 +210,7 @@ do { \ } while (0) /** - * journal_recover - recovers a on-disk journal + * jbd2_journal_recover - recovers a on-disk journal * @journal: the journal to recover * * The primary function for recovering the log contents when mounting a @@ -221,7 +221,7 @@ do { \ * blocks. In the third and final pass, we replay any un-revoked blocks * in the log. */ -int journal_recover(journal_t *journal) +int jbd2_journal_recover(journal_t *journal) { int err; journal_superblock_t * sb; @@ -260,13 +260,13 @@ int journal_recover(journal_t *journal) * any existing commit records in the log. */ journal->j_transaction_sequence = ++info.end_transaction; - journal_clear_revoke(journal); + jbd2_journal_clear_revoke(journal); sync_blockdev(journal->j_fs_dev); return err; } /** - * journal_skip_recovery - Start journal and wipe exiting records + * jbd2_journal_skip_recovery - Start journal and wipe exiting records * @journal: journal to startup * * Locate any valid recovery information from the journal and set up the @@ -278,7 +278,7 @@ int journal_recover(journal_t *journal) * much recovery information is being erased, and to let us initialise * the journal transaction sequence numbers to the next unused ID. */ -int journal_skip_recovery(journal_t *journal) +int jbd2_journal_skip_recovery(journal_t *journal) { int err; journal_superblock_t * sb; @@ -387,7 +387,7 @@ static int do_one_pass(journal_t *journal, tmp = (journal_header_t *)bh->b_data; - if (tmp->h_magic != cpu_to_be32(JFS_MAGIC_NUMBER)) { + if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) { brelse(bh); break; } @@ -407,7 +407,7 @@ static int do_one_pass(journal_t *journal, * to do with it? That depends on the pass... */ switch(blocktype) { - case JFS_DESCRIPTOR_BLOCK: + case JBD2_DESCRIPTOR_BLOCK: /* If it is a valid descriptor block, replay it * in pass REPLAY; otherwise, just skip over the * blocks it describes. */ @@ -451,7 +451,7 @@ static int do_one_pass(journal_t *journal, /* If the block has been * revoked, then we're all done * here. */ - if (journal_test_revoke + if (jbd2_journal_test_revoke (journal, blocknr, next_commit_ID)) { brelse(obh); @@ -477,9 +477,9 @@ static int do_one_pass(journal_t *journal, lock_buffer(nbh); memcpy(nbh->b_data, obh->b_data, journal->j_blocksize); - if (flags & JFS_FLAG_ESCAPE) { + if (flags & JBD2_FLAG_ESCAPE) { *((__be32 *)bh->b_data) = - cpu_to_be32(JFS_MAGIC_NUMBER); + cpu_to_be32(JBD2_MAGIC_NUMBER); } BUFFER_TRACE(nbh, "marking dirty"); @@ -495,17 +495,17 @@ static int do_one_pass(journal_t *journal, skip_write: tagp += sizeof(journal_block_tag_t); - if (!(flags & JFS_FLAG_SAME_UUID)) + if (!(flags & JBD2_FLAG_SAME_UUID)) tagp += 16; - if (flags & JFS_FLAG_LAST_TAG) + if (flags & JBD2_FLAG_LAST_TAG) break; } brelse(bh); continue; - case JFS_COMMIT_BLOCK: + case JBD2_COMMIT_BLOCK: /* Found an expected commit block: not much to * do other than move on to the next sequence * number. */ @@ -513,7 +513,7 @@ static int do_one_pass(journal_t *journal, next_commit_ID++; continue; - case JFS_REVOKE_BLOCK: + case JBD2_REVOKE_BLOCK: /* If we aren't in the REVOKE pass, then we can * just skip over this block. */ if (pass != PASS_REVOKE) { @@ -570,11 +570,11 @@ static int do_one_pass(journal_t *journal, static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, tid_t sequence, struct recovery_info *info) { - journal_revoke_header_t *header; + jbd2_journal_revoke_header_t *header; int offset, max; - header = (journal_revoke_header_t *) bh->b_data; - offset = sizeof(journal_revoke_header_t); + header = (jbd2_journal_revoke_header_t *) bh->b_data; + offset = sizeof(jbd2_journal_revoke_header_t); max = be32_to_cpu(header->r_count); while (offset < max) { @@ -583,7 +583,7 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); offset += 4; - err = journal_set_revoke(journal, blocknr, sequence); + err = jbd2_journal_set_revoke(journal, blocknr, sequence); if (err) return err; ++info->nr_revokes; diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index c532429d8d9b..2fccddc7acad 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -62,7 +62,7 @@ #else #include #include -#include +#include #include #include #include @@ -70,14 +70,14 @@ #include #endif -static kmem_cache_t *revoke_record_cache; -static kmem_cache_t *revoke_table_cache; +static kmem_cache_t *jbd2_revoke_record_cache; +static kmem_cache_t *jbd2_revoke_table_cache; /* Each revoke record represents one single revoked block. During journal replay, this involves recording the transaction ID of the last transaction to revoke this block. */ -struct jbd_revoke_record_s +struct jbd2_revoke_record_s { struct list_head hash; tid_t sequence; /* Used for recovery only */ @@ -86,7 +86,7 @@ struct jbd_revoke_record_s /* The revoke table is just a simple hash table of revoke records. */ -struct jbd_revoke_table_s +struct jbd2_revoke_table_s { /* It is conceivable that we might want a larger hash table * for recovery. Must be a power of two. */ @@ -99,7 +99,7 @@ struct jbd_revoke_table_s #ifdef __KERNEL__ static void write_one_revoke_record(journal_t *, transaction_t *, struct journal_head **, int *, - struct jbd_revoke_record_s *); + struct jbd2_revoke_record_s *); static void flush_descriptor(journal_t *, struct journal_head *, int); #endif @@ -108,7 +108,7 @@ static void flush_descriptor(journal_t *, struct journal_head *, int); /* Borrowed from buffer.c: this is a tried and tested block hash function */ static inline int hash(journal_t *journal, unsigned long block) { - struct jbd_revoke_table_s *table = journal->j_revoke; + struct jbd2_revoke_table_s *table = journal->j_revoke; int hash_shift = table->hash_shift; return ((block << (hash_shift - 6)) ^ @@ -120,10 +120,10 @@ static int insert_revoke_hash(journal_t *journal, unsigned long blocknr, tid_t seq) { struct list_head *hash_list; - struct jbd_revoke_record_s *record; + struct jbd2_revoke_record_s *record; repeat: - record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS); + record = kmem_cache_alloc(jbd2_revoke_record_cache, GFP_NOFS); if (!record) goto oom; @@ -145,57 +145,57 @@ oom: /* Find a revoke record in the journal's hash table. */ -static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, +static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal, unsigned long blocknr) { struct list_head *hash_list; - struct jbd_revoke_record_s *record; + struct jbd2_revoke_record_s *record; hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; spin_lock(&journal->j_revoke_lock); - record = (struct jbd_revoke_record_s *) hash_list->next; + record = (struct jbd2_revoke_record_s *) hash_list->next; while (&(record->hash) != hash_list) { if (record->blocknr == blocknr) { spin_unlock(&journal->j_revoke_lock); return record; } - record = (struct jbd_revoke_record_s *) record->hash.next; + record = (struct jbd2_revoke_record_s *) record->hash.next; } spin_unlock(&journal->j_revoke_lock); return NULL; } -int __init journal_init_revoke_caches(void) +int __init jbd2_journal_init_revoke_caches(void) { - revoke_record_cache = kmem_cache_create("revoke_record", - sizeof(struct jbd_revoke_record_s), + jbd2_revoke_record_cache = kmem_cache_create("revoke_record", + sizeof(struct jbd2_revoke_record_s), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); - if (revoke_record_cache == 0) + if (jbd2_revoke_record_cache == 0) return -ENOMEM; - revoke_table_cache = kmem_cache_create("revoke_table", - sizeof(struct jbd_revoke_table_s), + jbd2_revoke_table_cache = kmem_cache_create("revoke_table", + sizeof(struct jbd2_revoke_table_s), 0, 0, NULL, NULL); - if (revoke_table_cache == 0) { - kmem_cache_destroy(revoke_record_cache); - revoke_record_cache = NULL; + if (jbd2_revoke_table_cache == 0) { + kmem_cache_destroy(jbd2_revoke_record_cache); + jbd2_revoke_record_cache = NULL; return -ENOMEM; } return 0; } -void journal_destroy_revoke_caches(void) +void jbd2_journal_destroy_revoke_caches(void) { - kmem_cache_destroy(revoke_record_cache); - revoke_record_cache = NULL; - kmem_cache_destroy(revoke_table_cache); - revoke_table_cache = NULL; + kmem_cache_destroy(jbd2_revoke_record_cache); + jbd2_revoke_record_cache = NULL; + kmem_cache_destroy(jbd2_revoke_table_cache); + jbd2_revoke_table_cache = NULL; } /* Initialise the revoke table for a given journal to a given size. */ -int journal_init_revoke(journal_t *journal, int hash_size) +int jbd2_journal_init_revoke(journal_t *journal, int hash_size) { int shift, tmp; @@ -206,7 +206,7 @@ int journal_init_revoke(journal_t *journal, int hash_size) while((tmp >>= 1UL) != 0UL) shift++; - journal->j_revoke_table[0] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); + journal->j_revoke_table[0] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL); if (!journal->j_revoke_table[0]) return -ENOMEM; journal->j_revoke = journal->j_revoke_table[0]; @@ -221,7 +221,7 @@ int journal_init_revoke(journal_t *journal, int hash_size) journal->j_revoke->hash_table = kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); if (!journal->j_revoke->hash_table) { - kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); + kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]); journal->j_revoke = NULL; return -ENOMEM; } @@ -229,10 +229,10 @@ int journal_init_revoke(journal_t *journal, int hash_size) for (tmp = 0; tmp < hash_size; tmp++) INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); - journal->j_revoke_table[1] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); + journal->j_revoke_table[1] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL); if (!journal->j_revoke_table[1]) { kfree(journal->j_revoke_table[0]->hash_table); - kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); + kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]); return -ENOMEM; } @@ -249,8 +249,8 @@ int journal_init_revoke(journal_t *journal, int hash_size) kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); if (!journal->j_revoke->hash_table) { kfree(journal->j_revoke_table[0]->hash_table); - kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); - kmem_cache_free(revoke_table_cache, journal->j_revoke_table[1]); + kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]); + kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[1]); journal->j_revoke = NULL; return -ENOMEM; } @@ -265,9 +265,9 @@ int journal_init_revoke(journal_t *journal, int hash_size) /* Destoy a journal's revoke table. The table must already be empty! */ -void journal_destroy_revoke(journal_t *journal) +void jbd2_journal_destroy_revoke(journal_t *journal) { - struct jbd_revoke_table_s *table; + struct jbd2_revoke_table_s *table; struct list_head *hash_list; int i; @@ -281,7 +281,7 @@ void journal_destroy_revoke(journal_t *journal) } kfree(table->hash_table); - kmem_cache_free(revoke_table_cache, table); + kmem_cache_free(jbd2_revoke_table_cache, table); journal->j_revoke = NULL; table = journal->j_revoke_table[1]; @@ -294,7 +294,7 @@ void journal_destroy_revoke(journal_t *journal) } kfree(table->hash_table); - kmem_cache_free(revoke_table_cache, table); + kmem_cache_free(jbd2_revoke_table_cache, table); journal->j_revoke = NULL; } @@ -302,7 +302,7 @@ void journal_destroy_revoke(journal_t *journal) #ifdef __KERNEL__ /* - * journal_revoke: revoke a given buffer_head from the journal. This + * jbd2_journal_revoke: revoke a given buffer_head from the journal. This * prevents the block from being replayed during recovery if we take a * crash after this current transaction commits. Any subsequent * metadata writes of the buffer in this transaction cancel the @@ -314,18 +314,18 @@ void journal_destroy_revoke(journal_t *journal) * revoke before clearing the block bitmap when we are deleting * metadata. * - * Revoke performs a journal_forget on any buffer_head passed in as a + * Revoke performs a jbd2_journal_forget on any buffer_head passed in as a * parameter, but does _not_ forget the buffer_head if the bh was only * found implicitly. * * bh_in may not be a journalled buffer - it may have come off * the hash tables without an attached journal_head. * - * If bh_in is non-zero, journal_revoke() will decrement its b_count + * If bh_in is non-zero, jbd2_journal_revoke() will decrement its b_count * by one. */ -int journal_revoke(handle_t *handle, unsigned long blocknr, +int jbd2_journal_revoke(handle_t *handle, unsigned long blocknr, struct buffer_head *bh_in) { struct buffer_head *bh = NULL; @@ -338,7 +338,7 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, BUFFER_TRACE(bh_in, "enter"); journal = handle->h_transaction->t_journal; - if (!journal_set_features(journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)){ + if (!jbd2_journal_set_features(journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)){ J_ASSERT (!"Cannot set revoke feature!"); return -EINVAL; } @@ -386,8 +386,8 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, set_buffer_revoked(bh); set_buffer_revokevalid(bh); if (bh_in) { - BUFFER_TRACE(bh_in, "call journal_forget"); - journal_forget(handle, bh_in); + BUFFER_TRACE(bh_in, "call jbd2_journal_forget"); + jbd2_journal_forget(handle, bh_in); } else { BUFFER_TRACE(bh, "call brelse"); __brelse(bh); @@ -403,7 +403,7 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, /* * Cancel an outstanding revoke. For use only internally by the - * journaling code (called from journal_get_write_access). + * journaling code (called from jbd2_journal_get_write_access). * * We trust buffer_revoked() on the buffer if the buffer is already * being journaled: if there is no revoke pending on the buffer, then we @@ -418,9 +418,9 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, * * The caller must have the journal locked. */ -int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) +int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh) { - struct jbd_revoke_record_s *record; + struct jbd2_revoke_record_s *record; journal_t *journal = handle->h_transaction->t_journal; int need_cancel; int did_revoke = 0; /* akpm: debug */ @@ -447,7 +447,7 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) spin_lock(&journal->j_revoke_lock); list_del(&record->hash); spin_unlock(&journal->j_revoke_lock); - kmem_cache_free(revoke_record_cache, record); + kmem_cache_free(jbd2_revoke_record_cache, record); did_revoke = 1; } } @@ -478,7 +478,7 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) * we do not want to suspend any processing until all revokes are * written -bzzz */ -void journal_switch_revoke_table(journal_t *journal) +void jbd2_journal_switch_revoke_table(journal_t *journal) { int i; @@ -498,12 +498,12 @@ void journal_switch_revoke_table(journal_t *journal) * Called with the journal lock held. */ -void journal_write_revoke_records(journal_t *journal, +void jbd2_journal_write_revoke_records(journal_t *journal, transaction_t *transaction) { struct journal_head *descriptor; - struct jbd_revoke_record_s *record; - struct jbd_revoke_table_s *revoke; + struct jbd2_revoke_record_s *record; + struct jbd2_revoke_table_s *revoke; struct list_head *hash_list; int i, offset, count; @@ -519,14 +519,14 @@ void journal_write_revoke_records(journal_t *journal, hash_list = &revoke->hash_table[i]; while (!list_empty(hash_list)) { - record = (struct jbd_revoke_record_s *) + record = (struct jbd2_revoke_record_s *) hash_list->next; write_one_revoke_record(journal, transaction, &descriptor, &offset, record); count++; list_del(&record->hash); - kmem_cache_free(revoke_record_cache, record); + kmem_cache_free(jbd2_revoke_record_cache, record); } } if (descriptor) @@ -543,7 +543,7 @@ static void write_one_revoke_record(journal_t *journal, transaction_t *transaction, struct journal_head **descriptorp, int *offsetp, - struct jbd_revoke_record_s *record) + struct jbd2_revoke_record_s *record) { struct journal_head *descriptor; int offset; @@ -551,7 +551,7 @@ static void write_one_revoke_record(journal_t *journal, /* If we are already aborting, this all becomes a noop. We still need to go round the loop in - journal_write_revoke_records in order to free all of the + jbd2_journal_write_revoke_records in order to free all of the revoke records: only the IO to the journal is omitted. */ if (is_journal_aborted(journal)) return; @@ -568,19 +568,19 @@ static void write_one_revoke_record(journal_t *journal, } if (!descriptor) { - descriptor = journal_get_descriptor_buffer(journal); + descriptor = jbd2_journal_get_descriptor_buffer(journal); if (!descriptor) return; header = (journal_header_t *) &jh2bh(descriptor)->b_data[0]; - header->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); - header->h_blocktype = cpu_to_be32(JFS_REVOKE_BLOCK); + header->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER); + header->h_blocktype = cpu_to_be32(JBD2_REVOKE_BLOCK); header->h_sequence = cpu_to_be32(transaction->t_tid); /* Record it so that we can wait for IO completion later */ JBUFFER_TRACE(descriptor, "file as BJ_LogCtl"); - journal_file_buffer(descriptor, transaction, BJ_LogCtl); + jbd2_journal_file_buffer(descriptor, transaction, BJ_LogCtl); - offset = sizeof(journal_revoke_header_t); + offset = sizeof(jbd2_journal_revoke_header_t); *descriptorp = descriptor; } @@ -601,7 +601,7 @@ static void flush_descriptor(journal_t *journal, struct journal_head *descriptor, int offset) { - journal_revoke_header_t *header; + jbd2_journal_revoke_header_t *header; struct buffer_head *bh = jh2bh(descriptor); if (is_journal_aborted(journal)) { @@ -609,7 +609,7 @@ static void flush_descriptor(journal_t *journal, return; } - header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data; + header = (jbd2_journal_revoke_header_t *) jh2bh(descriptor)->b_data; header->r_count = cpu_to_be32(offset); set_buffer_jwrite(bh); BUFFER_TRACE(bh, "write"); @@ -640,11 +640,11 @@ static void flush_descriptor(journal_t *journal, * single block. */ -int journal_set_revoke(journal_t *journal, +int jbd2_journal_set_revoke(journal_t *journal, unsigned long blocknr, tid_t sequence) { - struct jbd_revoke_record_s *record; + struct jbd2_revoke_record_s *record; record = find_revoke_record(journal, blocknr); if (record) { @@ -664,11 +664,11 @@ int journal_set_revoke(journal_t *journal, * ones, but later transactions still need replayed. */ -int journal_test_revoke(journal_t *journal, +int jbd2_journal_test_revoke(journal_t *journal, unsigned long blocknr, tid_t sequence) { - struct jbd_revoke_record_s *record; + struct jbd2_revoke_record_s *record; record = find_revoke_record(journal, blocknr); if (!record) @@ -683,21 +683,21 @@ int journal_test_revoke(journal_t *journal, * that it can be reused by the running filesystem. */ -void journal_clear_revoke(journal_t *journal) +void jbd2_journal_clear_revoke(journal_t *journal) { int i; struct list_head *hash_list; - struct jbd_revoke_record_s *record; - struct jbd_revoke_table_s *revoke; + struct jbd2_revoke_record_s *record; + struct jbd2_revoke_table_s *revoke; revoke = journal->j_revoke; for (i = 0; i < revoke->hash_size; i++) { hash_list = &revoke->hash_table[i]; while (!list_empty(hash_list)) { - record = (struct jbd_revoke_record_s*) hash_list->next; + record = (struct jbd2_revoke_record_s*) hash_list->next; list_del(&record->hash); - kmem_cache_free(revoke_record_cache, record); + kmem_cache_free(jbd2_revoke_record_cache, record); } } } diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index e1b3c8af4d17..149957bef907 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include @@ -28,7 +28,7 @@ #include /* - * get_transaction: obtain a new transaction_t object. + * jbd2_get_transaction: obtain a new transaction_t object. * * Simply allocate and initialise a new transaction. Create it in * RUNNING state and add it to the current journal (which should not @@ -44,7 +44,7 @@ */ static transaction_t * -get_transaction(journal_t *journal, transaction_t *transaction) +jbd2_get_transaction(journal_t *journal, transaction_t *transaction) { transaction->t_journal = journal; transaction->t_state = T_RUNNING; @@ -115,7 +115,7 @@ repeat: spin_lock(&journal->j_state_lock); repeat_locked: if (is_journal_aborted(journal) || - (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) { + (journal->j_errno != 0 && !(journal->j_flags & JBD2_ACK_ERR))) { spin_unlock(&journal->j_state_lock); ret = -EROFS; goto out; @@ -134,7 +134,7 @@ repeat_locked: spin_unlock(&journal->j_state_lock); goto alloc_transaction; } - get_transaction(journal, new_transaction); + jbd2_get_transaction(journal, new_transaction); new_transaction = NULL; } @@ -175,7 +175,7 @@ repeat_locked: spin_unlock(&transaction->t_handle_lock); prepare_to_wait(&journal->j_wait_transaction_locked, &wait, TASK_UNINTERRUPTIBLE); - __log_start_commit(journal, transaction->t_tid); + __jbd2_log_start_commit(journal, transaction->t_tid); spin_unlock(&journal->j_state_lock); schedule(); finish_wait(&journal->j_wait_transaction_locked, &wait); @@ -205,12 +205,12 @@ repeat_locked: * committing_transaction->t_outstanding_credits plus "enough" for * the log control blocks. * Also, this test is inconsitent with the matching one in - * journal_extend(). + * jbd2_journal_extend(). */ - if (__log_space_left(journal) < jbd_space_needed(journal)) { + if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) { jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); spin_unlock(&transaction->t_handle_lock); - __log_wait_for_space(journal); + __jbd2_log_wait_for_space(journal); goto repeat_locked; } @@ -223,7 +223,7 @@ repeat_locked: transaction->t_handle_count++; jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", handle, nblocks, transaction->t_outstanding_credits, - __log_space_left(journal)); + __jbd2_log_space_left(journal)); spin_unlock(&transaction->t_handle_lock); spin_unlock(&journal->j_state_lock); out: @@ -246,7 +246,7 @@ static handle_t *new_handle(int nblocks) } /** - * handle_t *journal_start() - Obtain a new handle. + * handle_t *jbd2_journal_start() - Obtain a new handle. * @journal: Journal to start transaction on. * @nblocks: number of block buffer we might modify * @@ -259,7 +259,7 @@ static handle_t *new_handle(int nblocks) * * Return a pointer to a newly allocated handle, or NULL on failure */ -handle_t *journal_start(journal_t *journal, int nblocks) +handle_t *jbd2_journal_start(journal_t *journal, int nblocks) { handle_t *handle = journal_current_handle(); int err; @@ -289,7 +289,7 @@ handle_t *journal_start(journal_t *journal, int nblocks) } /** - * int journal_extend() - extend buffer credits. + * int jbd2_journal_extend() - extend buffer credits. * @handle: handle to 'extend' * @nblocks: nr blocks to try to extend by. * @@ -298,7 +298,7 @@ handle_t *journal_start(journal_t *journal, int nblocks) * a credit for a number of buffer modications in advance, but can * extend its credit if it needs more. * - * journal_extend tries to give the running handle more buffer credits. + * jbd2_journal_extend tries to give the running handle more buffer credits. * It does not guarantee that allocation - this is a best-effort only. * The calling process MUST be able to deal cleanly with a failure to * extend here. @@ -308,7 +308,7 @@ handle_t *journal_start(journal_t *journal, int nblocks) * return code < 0 implies an error * return code > 0 implies normal transaction-full status. */ -int journal_extend(handle_t *handle, int nblocks) +int jbd2_journal_extend(handle_t *handle, int nblocks) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -339,7 +339,7 @@ int journal_extend(handle_t *handle, int nblocks) goto unlock; } - if (wanted > __log_space_left(journal)) { + if (wanted > __jbd2_log_space_left(journal)) { jbd_debug(3, "denied handle %p %d blocks: " "insufficient log space\n", handle, nblocks); goto unlock; @@ -360,21 +360,21 @@ out: /** - * int journal_restart() - restart a handle . + * int jbd2_journal_restart() - restart a handle . * @handle: handle to restart * @nblocks: nr credits requested * * Restart a handle for a multi-transaction filesystem * operation. * - * If the journal_extend() call above fails to grant new buffer credits - * to a running handle, a call to journal_restart will commit the + * If the jbd2_journal_extend() call above fails to grant new buffer credits + * to a running handle, a call to jbd2_journal_restart will commit the * handle's transaction so far and reattach the handle to a new * transaction capabable of guaranteeing the requested number of * credits. */ -int journal_restart(handle_t *handle, int nblocks) +int jbd2_journal_restart(handle_t *handle, int nblocks) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -402,7 +402,7 @@ int journal_restart(handle_t *handle, int nblocks) spin_unlock(&transaction->t_handle_lock); jbd_debug(2, "restarting handle %p\n", handle); - __log_start_commit(journal, transaction->t_tid); + __jbd2_log_start_commit(journal, transaction->t_tid); spin_unlock(&journal->j_state_lock); handle->h_buffer_credits = nblocks; @@ -412,7 +412,7 @@ int journal_restart(handle_t *handle, int nblocks) /** - * void journal_lock_updates () - establish a transaction barrier. + * void jbd2_journal_lock_updates () - establish a transaction barrier. * @journal: Journal to establish a barrier on. * * This locks out any further updates from being started, and blocks @@ -421,7 +421,7 @@ int journal_restart(handle_t *handle, int nblocks) * * The journal lock should not be held on entry. */ -void journal_lock_updates(journal_t *journal) +void jbd2_journal_lock_updates(journal_t *journal) { DEFINE_WAIT(wait); @@ -452,7 +452,7 @@ void journal_lock_updates(journal_t *journal) /* * We have now established a barrier against other normal updates, but - * we also need to barrier against other journal_lock_updates() calls + * we also need to barrier against other jbd2_journal_lock_updates() calls * to make sure that we serialise special journal-locked operations * too. */ @@ -460,14 +460,14 @@ void journal_lock_updates(journal_t *journal) } /** - * void journal_unlock_updates (journal_t* journal) - release barrier + * void jbd2_journal_unlock_updates (journal_t* journal) - release barrier * @journal: Journal to release the barrier on. * - * Release a transaction barrier obtained with journal_lock_updates(). + * Release a transaction barrier obtained with jbd2_journal_lock_updates(). * * Should be called without the journal lock held. */ -void journal_unlock_updates (journal_t *journal) +void jbd2_journal_unlock_updates (journal_t *journal) { J_ASSERT(journal->j_barrier_count != 0); @@ -667,7 +667,7 @@ repeat: JBUFFER_TRACE(jh, "allocate memory for buffer"); jbd_unlock_bh_state(bh); frozen_buffer = - jbd_slab_alloc(jh2bh(jh)->b_size, + jbd2_slab_alloc(jh2bh(jh)->b_size, GFP_NOFS); if (!frozen_buffer) { printk(KERN_EMERG @@ -699,7 +699,7 @@ repeat: jh->b_transaction = transaction; JBUFFER_TRACE(jh, "file as BJ_Reserved"); spin_lock(&journal->j_list_lock); - __journal_file_buffer(jh, transaction, BJ_Reserved); + __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); spin_unlock(&journal->j_list_lock); } @@ -723,18 +723,18 @@ done: * If we are about to journal a buffer, then any revoke pending on it is * no longer valid */ - journal_cancel_revoke(handle, jh); + jbd2_journal_cancel_revoke(handle, jh); out: if (unlikely(frozen_buffer)) /* It's usually NULL */ - jbd_slab_free(frozen_buffer, bh->b_size); + jbd2_slab_free(frozen_buffer, bh->b_size); JBUFFER_TRACE(jh, "exit"); return error; } /** - * int journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update. + * int jbd2_journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update. * @handle: transaction to add buffer modifications to * @bh: bh to be used for metadata writes * @credits: variable that will receive credits for the buffer @@ -745,16 +745,16 @@ out: * because we're write()ing a buffer which is also part of a shared mapping. */ -int journal_get_write_access(handle_t *handle, struct buffer_head *bh) +int jbd2_journal_get_write_access(handle_t *handle, struct buffer_head *bh) { - struct journal_head *jh = journal_add_journal_head(bh); + struct journal_head *jh = jbd2_journal_add_journal_head(bh); int rc; /* We do not want to get caught playing with fields which the * log thread also manipulates. Make sure that the buffer * completes any outstanding IO before proceeding. */ rc = do_get_write_access(handle, jh, 0); - journal_put_journal_head(jh); + jbd2_journal_put_journal_head(jh); return rc; } @@ -772,17 +772,17 @@ int journal_get_write_access(handle_t *handle, struct buffer_head *bh) * unlocked buffer beforehand. */ /** - * int journal_get_create_access () - notify intent to use newly created bh + * int jbd2_journal_get_create_access () - notify intent to use newly created bh * @handle: transaction to new buffer to * @bh: new buffer. * * Call this if you create a new bh. */ -int journal_get_create_access(handle_t *handle, struct buffer_head *bh) +int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; - struct journal_head *jh = journal_add_journal_head(bh); + struct journal_head *jh = jbd2_journal_add_journal_head(bh); int err; jbd_debug(5, "journal_head %p\n", jh); @@ -812,7 +812,7 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh) if (jh->b_transaction == NULL) { jh->b_transaction = transaction; JBUFFER_TRACE(jh, "file as BJ_Reserved"); - __journal_file_buffer(jh, transaction, BJ_Reserved); + __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); } else if (jh->b_transaction == journal->j_committing_transaction) { JBUFFER_TRACE(jh, "set next transaction"); jh->b_next_transaction = transaction; @@ -828,14 +828,14 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh) * which hits an assertion error. */ JBUFFER_TRACE(jh, "cancelling revoke"); - journal_cancel_revoke(handle, jh); - journal_put_journal_head(jh); + jbd2_journal_cancel_revoke(handle, jh); + jbd2_journal_put_journal_head(jh); out: return err; } /** - * int journal_get_undo_access() - Notify intent to modify metadata with + * int jbd2_journal_get_undo_access() - Notify intent to modify metadata with * non-rewindable consequences * @handle: transaction * @bh: buffer to undo @@ -848,7 +848,7 @@ out: * since if we overwrote that space we would make the delete * un-rewindable in case of a crash. * - * To deal with that, journal_get_undo_access requests write access to a + * To deal with that, jbd2_journal_get_undo_access requests write access to a * buffer for parts of non-rewindable operations such as delete * operations on the bitmaps. The journaling code must keep a copy of * the buffer's contents prior to the undo_access call until such time @@ -861,10 +861,10 @@ out: * * Returns error number or 0 on success. */ -int journal_get_undo_access(handle_t *handle, struct buffer_head *bh) +int jbd2_journal_get_undo_access(handle_t *handle, struct buffer_head *bh) { int err; - struct journal_head *jh = journal_add_journal_head(bh); + struct journal_head *jh = jbd2_journal_add_journal_head(bh); char *committed_data = NULL; JBUFFER_TRACE(jh, "entry"); @@ -880,7 +880,7 @@ int journal_get_undo_access(handle_t *handle, struct buffer_head *bh) repeat: if (!jh->b_committed_data) { - committed_data = jbd_slab_alloc(jh2bh(jh)->b_size, GFP_NOFS); + committed_data = jbd2_slab_alloc(jh2bh(jh)->b_size, GFP_NOFS); if (!committed_data) { printk(KERN_EMERG "%s: No memory for committed data\n", __FUNCTION__); @@ -905,14 +905,14 @@ repeat: } jbd_unlock_bh_state(bh); out: - journal_put_journal_head(jh); + jbd2_journal_put_journal_head(jh); if (unlikely(committed_data)) - jbd_slab_free(committed_data, bh->b_size); + jbd2_slab_free(committed_data, bh->b_size); return err; } /** - * int journal_dirty_data() - mark a buffer as containing dirty data which + * int jbd2_journal_dirty_data() - mark a buffer as containing dirty data which * needs to be flushed before we can commit the * current transaction. * @handle: transaction @@ -923,10 +923,10 @@ out: * * Returns error number or 0 on success. * - * journal_dirty_data() can be called via page_launder->ext3_writepage + * jbd2_journal_dirty_data() can be called via page_launder->ext3_writepage * by kswapd. */ -int journal_dirty_data(handle_t *handle, struct buffer_head *bh) +int jbd2_journal_dirty_data(handle_t *handle, struct buffer_head *bh) { journal_t *journal = handle->h_transaction->t_journal; int need_brelse = 0; @@ -935,7 +935,7 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh) if (is_handle_aborted(handle)) return 0; - jh = journal_add_journal_head(bh); + jh = jbd2_journal_add_journal_head(bh); JBUFFER_TRACE(jh, "entry"); /* @@ -984,7 +984,7 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh) * And while we're in that state, someone does a * writepage() in an attempt to pageout the same area * of the file via a shared mapping. At present that - * calls journal_dirty_data(), and we get right here. + * calls jbd2_journal_dirty_data(), and we get right here. * It may be too late to journal the data. Simply * falling through to the next test will suffice: the * data will be dirty and wil be checkpointed. The @@ -1035,7 +1035,7 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh) /* journal_clean_data_list() may have got there first */ if (jh->b_transaction != NULL) { JBUFFER_TRACE(jh, "unfile from commit"); - __journal_temp_unlink_buffer(jh); + __jbd2_journal_temp_unlink_buffer(jh); /* It still points to the committing * transaction; move it to this one so * that the refile assert checks are @@ -1054,15 +1054,15 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh) if (jh->b_jlist != BJ_SyncData && jh->b_jlist != BJ_Locked) { JBUFFER_TRACE(jh, "not on correct data list: unfile"); J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow); - __journal_temp_unlink_buffer(jh); + __jbd2_journal_temp_unlink_buffer(jh); jh->b_transaction = handle->h_transaction; JBUFFER_TRACE(jh, "file as data"); - __journal_file_buffer(jh, handle->h_transaction, + __jbd2_journal_file_buffer(jh, handle->h_transaction, BJ_SyncData); } } else { JBUFFER_TRACE(jh, "not on a transaction"); - __journal_file_buffer(jh, handle->h_transaction, BJ_SyncData); + __jbd2_journal_file_buffer(jh, handle->h_transaction, BJ_SyncData); } no_journal: spin_unlock(&journal->j_list_lock); @@ -1072,12 +1072,12 @@ no_journal: __brelse(bh); } JBUFFER_TRACE(jh, "exit"); - journal_put_journal_head(jh); + jbd2_journal_put_journal_head(jh); return 0; } /** - * int journal_dirty_metadata() - mark a buffer as containing dirty metadata + * int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata * @handle: transaction to add buffer to. * @bh: buffer to mark * @@ -1095,7 +1095,7 @@ no_journal: * buffer: that only gets done when the old transaction finally * completes its commit. */ -int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) +int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -1156,7 +1156,7 @@ int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) JBUFFER_TRACE(jh, "file as BJ_Metadata"); spin_lock(&journal->j_list_lock); - __journal_file_buffer(jh, handle->h_transaction, BJ_Metadata); + __jbd2_journal_file_buffer(jh, handle->h_transaction, BJ_Metadata); spin_unlock(&journal->j_list_lock); out_unlock_bh: jbd_unlock_bh_state(bh); @@ -1166,18 +1166,18 @@ out: } /* - * journal_release_buffer: undo a get_write_access without any buffer + * jbd2_journal_release_buffer: undo a get_write_access without any buffer * updates, if the update decided in the end that it didn't need access. * */ void -journal_release_buffer(handle_t *handle, struct buffer_head *bh) +jbd2_journal_release_buffer(handle_t *handle, struct buffer_head *bh) { BUFFER_TRACE(bh, "entry"); } /** - * void journal_forget() - bforget() for potentially-journaled buffers. + * void jbd2_journal_forget() - bforget() for potentially-journaled buffers. * @handle: transaction handle * @bh: bh to 'forget' * @@ -1193,7 +1193,7 @@ journal_release_buffer(handle_t *handle, struct buffer_head *bh) * Allow this call even if the handle has aborted --- it may be part of * the caller's cleanup after an abort. */ -int journal_forget (handle_t *handle, struct buffer_head *bh) +int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -1250,11 +1250,11 @@ int journal_forget (handle_t *handle, struct buffer_head *bh) */ if (jh->b_cp_transaction) { - __journal_temp_unlink_buffer(jh); - __journal_file_buffer(jh, transaction, BJ_Forget); + __jbd2_journal_temp_unlink_buffer(jh); + __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); } else { - __journal_unfile_buffer(jh); - journal_remove_journal_head(bh); + __jbd2_journal_unfile_buffer(jh); + jbd2_journal_remove_journal_head(bh); __brelse(bh); if (!buffer_jbd(bh)) { spin_unlock(&journal->j_list_lock); @@ -1292,7 +1292,7 @@ drop: } /** - * int journal_stop() - complete a transaction + * int jbd2_journal_stop() - complete a transaction * @handle: tranaction to complete. * * All done for a particular handle. @@ -1302,12 +1302,12 @@ drop: * complication is that we need to start a commit operation if the * filesystem is marked for synchronous update. * - * journal_stop itself will not usually return an error, but it may + * jbd2_journal_stop itself will not usually return an error, but it may * do so in unusual circumstances. In particular, expect it to - * return -EIO if a journal_abort has been executed since the + * return -EIO if a jbd2_journal_abort has been executed since the * transaction began. */ -int journal_stop(handle_t *handle) +int jbd2_journal_stop(handle_t *handle) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -1383,15 +1383,15 @@ int journal_stop(handle_t *handle) jbd_debug(2, "transaction too old, requesting commit for " "handle %p\n", handle); /* This is non-blocking */ - __log_start_commit(journal, transaction->t_tid); + __jbd2_log_start_commit(journal, transaction->t_tid); spin_unlock(&journal->j_state_lock); /* - * Special case: JFS_SYNC synchronous updates require us + * Special case: JBD2_SYNC synchronous updates require us * to wait for the commit to complete. */ if (handle->h_sync && !(current->flags & PF_MEMALLOC)) - err = log_wait_commit(journal, tid); + err = jbd2_log_wait_commit(journal, tid); } else { spin_unlock(&transaction->t_handle_lock); spin_unlock(&journal->j_state_lock); @@ -1401,24 +1401,24 @@ int journal_stop(handle_t *handle) return err; } -/**int journal_force_commit() - force any uncommitted transactions +/**int jbd2_journal_force_commit() - force any uncommitted transactions * @journal: journal to force * * For synchronous operations: force any uncommitted transactions * to disk. May seem kludgy, but it reuses all the handle batching * code in a very simple manner. */ -int journal_force_commit(journal_t *journal) +int jbd2_journal_force_commit(journal_t *journal) { handle_t *handle; int ret; - handle = journal_start(journal, 1); + handle = jbd2_journal_start(journal, 1); if (IS_ERR(handle)) { ret = PTR_ERR(handle); } else { handle->h_sync = 1; - ret = journal_stop(handle); + ret = jbd2_journal_stop(handle); } return ret; } @@ -1486,7 +1486,7 @@ __blist_del_buffer(struct journal_head **list, struct journal_head *jh) * * Called under j_list_lock. The journal may not be locked. */ -void __journal_temp_unlink_buffer(struct journal_head *jh) +void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh) { struct journal_head **list = NULL; transaction_t *transaction; @@ -1538,23 +1538,23 @@ void __journal_temp_unlink_buffer(struct journal_head *jh) mark_buffer_dirty(bh); /* Expose it to the VM */ } -void __journal_unfile_buffer(struct journal_head *jh) +void __jbd2_journal_unfile_buffer(struct journal_head *jh) { - __journal_temp_unlink_buffer(jh); + __jbd2_journal_temp_unlink_buffer(jh); jh->b_transaction = NULL; } -void journal_unfile_buffer(journal_t *journal, struct journal_head *jh) +void jbd2_journal_unfile_buffer(journal_t *journal, struct journal_head *jh) { jbd_lock_bh_state(jh2bh(jh)); spin_lock(&journal->j_list_lock); - __journal_unfile_buffer(jh); + __jbd2_journal_unfile_buffer(jh); spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(jh2bh(jh)); } /* - * Called from journal_try_to_free_buffers(). + * Called from jbd2_journal_try_to_free_buffers(). * * Called under jbd_lock_bh_state(bh) */ @@ -1576,16 +1576,16 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) if (jh->b_jlist == BJ_SyncData || jh->b_jlist == BJ_Locked) { /* A written-back ordered data buffer */ JBUFFER_TRACE(jh, "release data"); - __journal_unfile_buffer(jh); - journal_remove_journal_head(bh); + __jbd2_journal_unfile_buffer(jh); + jbd2_journal_remove_journal_head(bh); __brelse(bh); } } else if (jh->b_cp_transaction != 0 && jh->b_transaction == 0) { /* written-back checkpointed metadata buffer */ if (jh->b_jlist == BJ_None) { JBUFFER_TRACE(jh, "remove from checkpoint list"); - __journal_remove_checkpoint(jh); - journal_remove_journal_head(bh); + __jbd2_journal_remove_checkpoint(jh); + jbd2_journal_remove_journal_head(bh); __brelse(bh); } } @@ -1596,7 +1596,7 @@ out: /** - * int journal_try_to_free_buffers() - try to free page buffers. + * int jbd2_journal_try_to_free_buffers() - try to free page buffers. * @journal: journal for operation * @page: to try and free * @unused_gfp_mask: unused @@ -1613,13 +1613,13 @@ out: * * This complicates JBD locking somewhat. We aren't protected by the * BKL here. We wish to remove the buffer from its committing or - * running transaction's ->t_datalist via __journal_unfile_buffer. + * running transaction's ->t_datalist via __jbd2_journal_unfile_buffer. * * This may *change* the value of transaction_t->t_datalist, so anyone * who looks at t_datalist needs to lock against this function. * - * Even worse, someone may be doing a journal_dirty_data on this - * buffer. So we need to lock against that. journal_dirty_data() + * Even worse, someone may be doing a jbd2_journal_dirty_data on this + * buffer. So we need to lock against that. jbd2_journal_dirty_data() * will come out of the lock with the buffer dirty, which makes it * ineligible for release here. * @@ -1629,7 +1629,7 @@ out: * cannot happen because we never reallocate freed data as metadata * while the data is part of a transaction. Yes? */ -int journal_try_to_free_buffers(journal_t *journal, +int jbd2_journal_try_to_free_buffers(journal_t *journal, struct page *page, gfp_t unused_gfp_mask) { struct buffer_head *head; @@ -1646,15 +1646,15 @@ int journal_try_to_free_buffers(journal_t *journal, /* * We take our own ref against the journal_head here to avoid * having to add tons of locking around each instance of - * journal_remove_journal_head() and journal_put_journal_head(). + * jbd2_journal_remove_journal_head() and jbd2_journal_put_journal_head(). */ - jh = journal_grab_journal_head(bh); + jh = jbd2_journal_grab_journal_head(bh); if (!jh) continue; jbd_lock_bh_state(bh); __journal_try_to_free_buffer(journal, bh); - journal_put_journal_head(jh); + jbd2_journal_put_journal_head(jh); jbd_unlock_bh_state(bh); if (buffer_jbd(bh)) goto busy; @@ -1681,23 +1681,23 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) int may_free = 1; struct buffer_head *bh = jh2bh(jh); - __journal_unfile_buffer(jh); + __jbd2_journal_unfile_buffer(jh); if (jh->b_cp_transaction) { JBUFFER_TRACE(jh, "on running+cp transaction"); - __journal_file_buffer(jh, transaction, BJ_Forget); + __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); clear_buffer_jbddirty(bh); may_free = 0; } else { JBUFFER_TRACE(jh, "on running transaction"); - journal_remove_journal_head(bh); + jbd2_journal_remove_journal_head(bh); __brelse(bh); } return may_free; } /* - * journal_invalidatepage + * jbd2_journal_invalidatepage * * This code is tricky. It has a number of cases to deal with. * @@ -1765,7 +1765,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) jbd_lock_bh_state(bh); spin_lock(&journal->j_list_lock); - jh = journal_grab_journal_head(bh); + jh = jbd2_journal_grab_journal_head(bh); if (!jh) goto zap_buffer_no_jh; @@ -1796,7 +1796,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); ret = __dispose_buffer(jh, journal->j_running_transaction); - journal_put_journal_head(jh); + jbd2_journal_put_journal_head(jh); spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); spin_unlock(&journal->j_state_lock); @@ -1810,7 +1810,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) JBUFFER_TRACE(jh, "give to committing trans"); ret = __dispose_buffer(jh, journal->j_committing_transaction); - journal_put_journal_head(jh); + jbd2_journal_put_journal_head(jh); spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); spin_unlock(&journal->j_state_lock); @@ -1844,7 +1844,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) journal->j_running_transaction); jh->b_next_transaction = NULL; } - journal_put_journal_head(jh); + jbd2_journal_put_journal_head(jh); spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); spin_unlock(&journal->j_state_lock); @@ -1861,7 +1861,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) } zap_buffer: - journal_put_journal_head(jh); + jbd2_journal_put_journal_head(jh); zap_buffer_no_jh: spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); @@ -1877,7 +1877,7 @@ zap_buffer_unlocked: } /** - * void journal_invalidatepage() + * void jbd2_journal_invalidatepage() * @journal: journal to use for flush... * @page: page to flush * @offset: length of page to invalidate. @@ -1885,7 +1885,7 @@ zap_buffer_unlocked: * Reap page buffers containing data after offset in page. * */ -void journal_invalidatepage(journal_t *journal, +void jbd2_journal_invalidatepage(journal_t *journal, struct page *page, unsigned long offset) { @@ -1927,7 +1927,7 @@ void journal_invalidatepage(journal_t *journal, /* * File a buffer on the given transaction list. */ -void __journal_file_buffer(struct journal_head *jh, +void __jbd2_journal_file_buffer(struct journal_head *jh, transaction_t *transaction, int jlist) { struct journal_head **list = NULL; @@ -1956,7 +1956,7 @@ void __journal_file_buffer(struct journal_head *jh, } if (jh->b_transaction) - __journal_temp_unlink_buffer(jh); + __jbd2_journal_temp_unlink_buffer(jh); jh->b_transaction = transaction; switch (jlist) { @@ -1998,12 +1998,12 @@ void __journal_file_buffer(struct journal_head *jh, set_buffer_jbddirty(bh); } -void journal_file_buffer(struct journal_head *jh, +void jbd2_journal_file_buffer(struct journal_head *jh, transaction_t *transaction, int jlist) { jbd_lock_bh_state(jh2bh(jh)); spin_lock(&transaction->t_journal->j_list_lock); - __journal_file_buffer(jh, transaction, jlist); + __jbd2_journal_file_buffer(jh, transaction, jlist); spin_unlock(&transaction->t_journal->j_list_lock); jbd_unlock_bh_state(jh2bh(jh)); } @@ -2018,7 +2018,7 @@ void journal_file_buffer(struct journal_head *jh, * * Called under jbd_lock_bh_state(jh2bh(jh)) */ -void __journal_refile_buffer(struct journal_head *jh) +void __jbd2_journal_refile_buffer(struct journal_head *jh) { int was_dirty; struct buffer_head *bh = jh2bh(jh); @@ -2029,7 +2029,7 @@ void __journal_refile_buffer(struct journal_head *jh) /* If the buffer is now unused, just drop it. */ if (jh->b_next_transaction == NULL) { - __journal_unfile_buffer(jh); + __jbd2_journal_unfile_buffer(jh); return; } @@ -2039,10 +2039,10 @@ void __journal_refile_buffer(struct journal_head *jh) */ was_dirty = test_clear_buffer_jbddirty(bh); - __journal_temp_unlink_buffer(jh); + __jbd2_journal_temp_unlink_buffer(jh); jh->b_transaction = jh->b_next_transaction; jh->b_next_transaction = NULL; - __journal_file_buffer(jh, jh->b_transaction, + __jbd2_journal_file_buffer(jh, jh->b_transaction, was_dirty ? BJ_Metadata : BJ_Reserved); J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); @@ -2054,26 +2054,26 @@ void __journal_refile_buffer(struct journal_head *jh) * For the unlocked version of this call, also make sure that any * hanging journal_head is cleaned up if necessary. * - * __journal_refile_buffer is usually called as part of a single locked + * __jbd2_journal_refile_buffer is usually called as part of a single locked * operation on a buffer_head, in which the caller is probably going to * be hooking the journal_head onto other lists. In that case it is up * to the caller to remove the journal_head if necessary. For the - * unlocked journal_refile_buffer call, the caller isn't going to be + * unlocked jbd2_journal_refile_buffer call, the caller isn't going to be * doing anything else to the buffer so we need to do the cleanup * ourselves to avoid a jh leak. * * *** The journal_head may be freed by this call! *** */ -void journal_refile_buffer(journal_t *journal, struct journal_head *jh) +void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh) { struct buffer_head *bh = jh2bh(jh); jbd_lock_bh_state(bh); spin_lock(&journal->j_list_lock); - __journal_refile_buffer(jh); + __jbd2_journal_refile_buffer(jh); jbd_unlock_bh_state(bh); - journal_remove_journal_head(bh); + jbd2_journal_remove_journal_head(bh); spin_unlock(&journal->j_list_lock); __brelse(bh); diff --git a/include/linux/ext4_jbd2.h b/include/linux/ext4_jbd2.h index 3dbf6c779037..99d37557cbb4 100644 --- a/include/linux/ext4_jbd2.h +++ b/include/linux/ext4_jbd2.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/ext4_jbd.h + * linux/include/linux/ext4_jbd2.h * * Written by Stephen C. Tweedie , 1999 * @@ -16,7 +16,7 @@ #define _LINUX_EXT4_JBD_H #include -#include +#include #include #define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal) @@ -116,7 +116,7 @@ static inline int __ext4_journal_get_undo_access(const char *where, handle_t *handle, struct buffer_head *bh) { - int err = journal_get_undo_access(handle, bh); + int err = jbd2_journal_get_undo_access(handle, bh); if (err) ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; @@ -126,7 +126,7 @@ static inline int __ext4_journal_get_write_access(const char *where, handle_t *handle, struct buffer_head *bh) { - int err = journal_get_write_access(handle, bh); + int err = jbd2_journal_get_write_access(handle, bh); if (err) ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; @@ -135,13 +135,13 @@ __ext4_journal_get_write_access(const char *where, handle_t *handle, static inline void ext4_journal_release_buffer(handle_t *handle, struct buffer_head *bh) { - journal_release_buffer(handle, bh); + jbd2_journal_release_buffer(handle, bh); } static inline int __ext4_journal_forget(const char *where, handle_t *handle, struct buffer_head *bh) { - int err = journal_forget(handle, bh); + int err = jbd2_journal_forget(handle, bh); if (err) ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; @@ -151,7 +151,7 @@ static inline int __ext4_journal_revoke(const char *where, handle_t *handle, unsigned long blocknr, struct buffer_head *bh) { - int err = journal_revoke(handle, blocknr, bh); + int err = jbd2_journal_revoke(handle, blocknr, bh); if (err) ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; @@ -161,7 +161,7 @@ static inline int __ext4_journal_get_create_access(const char *where, handle_t *handle, struct buffer_head *bh) { - int err = journal_get_create_access(handle, bh); + int err = jbd2_journal_get_create_access(handle, bh); if (err) ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; @@ -171,7 +171,7 @@ static inline int __ext4_journal_dirty_metadata(const char *where, handle_t *handle, struct buffer_head *bh) { - int err = journal_dirty_metadata(handle, bh); + int err = jbd2_journal_dirty_metadata(handle, bh); if (err) ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; @@ -211,22 +211,22 @@ static inline handle_t *ext4_journal_current_handle(void) static inline int ext4_journal_extend(handle_t *handle, int nblocks) { - return journal_extend(handle, nblocks); + return jbd2_journal_extend(handle, nblocks); } static inline int ext4_journal_restart(handle_t *handle, int nblocks) { - return journal_restart(handle, nblocks); + return jbd2_journal_restart(handle, nblocks); } static inline int ext4_journal_blocks_per_page(struct inode *inode) { - return journal_blocks_per_page(inode); + return jbd2_journal_blocks_per_page(inode); } static inline int ext4_journal_force_commit(journal_t *journal) { - return journal_force_commit(journal); + return jbd2_journal_force_commit(journal); } /* super.c */ diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index fe89444b1c6f..3251f7abb57d 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/jbd.h + * linux/include/linux/jbd2.h * * Written by Stephen C. Tweedie * @@ -19,7 +19,7 @@ /* Allow this file to be included directly into e2fsprogs */ #ifndef __KERNEL__ #include "jfs_compat.h" -#define JFS_DEBUG +#define JBD2_DEBUG #define jfs_debug jbd_debug #else @@ -57,11 +57,11 @@ * CONFIG_JBD_DEBUG is on. */ #define JBD_EXPENSIVE_CHECKING -extern int journal_enable_debug; +extern int jbd2_journal_enable_debug; #define jbd_debug(n, f, a...) \ do { \ - if ((n) <= journal_enable_debug) { \ + if ((n) <= jbd2_journal_enable_debug) { \ printk (KERN_DEBUG "(%s, %d): %s: ", \ __FILE__, __LINE__, __FUNCTION__); \ printk (f, ## a); \ @@ -71,16 +71,16 @@ extern int journal_enable_debug; #define jbd_debug(f, a...) /**/ #endif -extern void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry); -extern void * jbd_slab_alloc(size_t size, gfp_t flags); -extern void jbd_slab_free(void *ptr, size_t size); +extern void * __jbd2_kmalloc (const char *where, size_t size, gfp_t flags, int retry); +extern void * jbd2_slab_alloc(size_t size, gfp_t flags); +extern void jbd2_slab_free(void *ptr, size_t size); #define jbd_kmalloc(size, flags) \ - __jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry) + __jbd2_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry) #define jbd_rep_kmalloc(size, flags) \ - __jbd_kmalloc(__FUNCTION__, (size), (flags), 1) + __jbd2_kmalloc(__FUNCTION__, (size), (flags), 1) -#define JFS_MIN_JOURNAL_BLOCKS 1024 +#define JBD2_MIN_JOURNAL_BLOCKS 1024 #ifdef __KERNEL__ @@ -122,7 +122,7 @@ typedef struct journal_s journal_t; /* Journal control structure */ * Internal structures used by the logging mechanism: */ -#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ +#define JBD2_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ /* * On-disk structures @@ -132,11 +132,11 @@ typedef struct journal_s journal_t; /* Journal control structure */ * Descriptor block types: */ -#define JFS_DESCRIPTOR_BLOCK 1 -#define JFS_COMMIT_BLOCK 2 -#define JFS_SUPERBLOCK_V1 3 -#define JFS_SUPERBLOCK_V2 4 -#define JFS_REVOKE_BLOCK 5 +#define JBD2_DESCRIPTOR_BLOCK 1 +#define JBD2_COMMIT_BLOCK 2 +#define JBD2_SUPERBLOCK_V1 3 +#define JBD2_SUPERBLOCK_V2 4 +#define JBD2_REVOKE_BLOCK 5 /* * Standard header for all descriptor blocks: @@ -162,18 +162,18 @@ typedef struct journal_block_tag_s * The revoke descriptor: used on disk to describe a series of blocks to * be revoked from the log */ -typedef struct journal_revoke_header_s +typedef struct jbd2_journal_revoke_header_s { journal_header_t r_header; __be32 r_count; /* Count of bytes used in the block */ -} journal_revoke_header_t; +} jbd2_journal_revoke_header_t; /* Definitions for the journal tag flags word: */ -#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */ -#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */ -#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */ -#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ +#define JBD2_FLAG_ESCAPE 1 /* on-disk block is escaped */ +#define JBD2_FLAG_SAME_UUID 2 /* block has same uuid as previous */ +#define JBD2_FLAG_DELETED 4 /* block deleted by this transaction */ +#define JBD2_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ /* @@ -196,7 +196,7 @@ typedef struct journal_superblock_s __be32 s_start; /* blocknr of start of log */ /* 0x0020 */ - /* Error value, as set by journal_abort(). */ + /* Error value, as set by jbd2_journal_abort(). */ __be32 s_errno; /* 0x0024 */ @@ -224,22 +224,22 @@ typedef struct journal_superblock_s /* 0x0400 */ } journal_superblock_t; -#define JFS_HAS_COMPAT_FEATURE(j,mask) \ +#define JBD2_HAS_COMPAT_FEATURE(j,mask) \ ((j)->j_format_version >= 2 && \ ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask)))) -#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \ +#define JBD2_HAS_RO_COMPAT_FEATURE(j,mask) \ ((j)->j_format_version >= 2 && \ ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask)))) -#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \ +#define JBD2_HAS_INCOMPAT_FEATURE(j,mask) \ ((j)->j_format_version >= 2 && \ ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask)))) -#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001 +#define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001 /* Features known to this kernel version: */ -#define JFS_KNOWN_COMPAT_FEATURES 0 -#define JFS_KNOWN_ROCOMPAT_FEATURES 0 -#define JFS_KNOWN_INCOMPAT_FEATURES JFS_FEATURE_INCOMPAT_REVOKE +#define JBD2_KNOWN_COMPAT_FEATURES 0 +#define JBD2_KNOWN_ROCOMPAT_FEATURES 0 +#define JBD2_KNOWN_INCOMPAT_FEATURES JBD2_FEATURE_INCOMPAT_REVOKE #ifdef __KERNEL__ @@ -359,7 +359,7 @@ static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh) bit_spin_unlock(BH_JournalHead, &bh->b_state); } -struct jbd_revoke_table_s; +struct jbd2_revoke_table_s; /** * struct handle_s - The handle_s type is the concrete type associated with @@ -445,7 +445,7 @@ struct transaction_s /* * Transaction's current state - * [no locking - only kjournald alters this] + * [no locking - only kjournald2 alters this] * FIXME: needs barriers * KLUDGE: [use j_state_lock] */ @@ -621,7 +621,7 @@ struct transaction_s * @j_revoke: The revoke table - maintains the list of revoked blocks in the * current transaction. * @j_revoke_table: alternate revoke tables for j_revoke - * @j_wbuf: array of buffer_heads for journal_commit_transaction + * @j_wbuf: array of buffer_heads for jbd2_journal_commit_transaction * @j_wbufsize: maximum number of buffer_heads allowed in j_wbuf, the * number that will fit in j_blocksize * @j_last_sync_writer: most recent pid which did a synchronous write @@ -805,11 +805,11 @@ struct journal_s * current transaction. [j_revoke_lock] */ spinlock_t j_revoke_lock; - struct jbd_revoke_table_s *j_revoke; - struct jbd_revoke_table_s *j_revoke_table[2]; + struct jbd2_revoke_table_s *j_revoke; + struct jbd2_revoke_table_s *j_revoke_table[2]; /* - * array of bhs for journal_commit_transaction + * array of bhs for jbd2_journal_commit_transaction */ struct buffer_head **j_wbuf; int j_wbufsize; @@ -826,12 +826,12 @@ struct journal_s /* * Journal flag definitions */ -#define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */ -#define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */ -#define JFS_ACK_ERR 0x004 /* The errno in the sb has been acked */ -#define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */ -#define JFS_LOADED 0x010 /* The journal superblock has been loaded */ -#define JFS_BARRIER 0x020 /* Use IDE barriers */ +#define JBD2_UNMOUNT 0x001 /* Journal thread is being destroyed */ +#define JBD2_ABORT 0x002 /* Journaling has been aborted for errors. */ +#define JBD2_ACK_ERR 0x004 /* The errno in the sb has been acked */ +#define JBD2_FLUSHED 0x008 /* The journal superblock has been flushed */ +#define JBD2_LOADED 0x010 /* The journal superblock has been loaded */ +#define JBD2_BARRIER 0x020 /* Use IDE barriers */ /* * Function declarations for the journaling transaction and buffer @@ -839,31 +839,31 @@ struct journal_s */ /* Filing buffers */ -extern void __journal_temp_unlink_buffer(struct journal_head *jh); -extern void journal_unfile_buffer(journal_t *, struct journal_head *); -extern void __journal_unfile_buffer(struct journal_head *); -extern void __journal_refile_buffer(struct journal_head *); -extern void journal_refile_buffer(journal_t *, struct journal_head *); -extern void __journal_file_buffer(struct journal_head *, transaction_t *, int); +extern void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh); +extern void jbd2_journal_unfile_buffer(journal_t *, struct journal_head *); +extern void __jbd2_journal_unfile_buffer(struct journal_head *); +extern void __jbd2_journal_refile_buffer(struct journal_head *); +extern void jbd2_journal_refile_buffer(journal_t *, struct journal_head *); +extern void __jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int); extern void __journal_free_buffer(struct journal_head *bh); -extern void journal_file_buffer(struct journal_head *, transaction_t *, int); +extern void jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int); extern void __journal_clean_data_list(transaction_t *transaction); /* Log buffer allocation */ -extern struct journal_head * journal_get_descriptor_buffer(journal_t *); -int journal_next_log_block(journal_t *, unsigned long *); +extern struct journal_head * jbd2_journal_get_descriptor_buffer(journal_t *); +int jbd2_journal_next_log_block(journal_t *, unsigned long *); /* Commit management */ -extern void journal_commit_transaction(journal_t *); +extern void jbd2_journal_commit_transaction(journal_t *); /* Checkpoint list management */ -int __journal_clean_checkpoint_list(journal_t *journal); -int __journal_remove_checkpoint(struct journal_head *); -void __journal_insert_checkpoint(struct journal_head *, transaction_t *); +int __jbd2_journal_clean_checkpoint_list(journal_t *journal); +int __jbd2_journal_remove_checkpoint(struct journal_head *); +void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *); /* Buffer IO */ extern int -journal_write_metadata_buffer(transaction_t *transaction, +jbd2_journal_write_metadata_buffer(transaction_t *transaction, struct journal_head *jh_in, struct journal_head **jh_out, unsigned long blocknr); @@ -893,91 +893,91 @@ static inline handle_t *journal_current_handle(void) * Register buffer modifications against the current transaction. */ -extern handle_t *journal_start(journal_t *, int nblocks); -extern int journal_restart (handle_t *, int nblocks); -extern int journal_extend (handle_t *, int nblocks); -extern int journal_get_write_access(handle_t *, struct buffer_head *); -extern int journal_get_create_access (handle_t *, struct buffer_head *); -extern int journal_get_undo_access(handle_t *, struct buffer_head *); -extern int journal_dirty_data (handle_t *, struct buffer_head *); -extern int journal_dirty_metadata (handle_t *, struct buffer_head *); -extern void journal_release_buffer (handle_t *, struct buffer_head *); -extern int journal_forget (handle_t *, struct buffer_head *); +extern handle_t *jbd2_journal_start(journal_t *, int nblocks); +extern int jbd2_journal_restart (handle_t *, int nblocks); +extern int jbd2_journal_extend (handle_t *, int nblocks); +extern int jbd2_journal_get_write_access(handle_t *, struct buffer_head *); +extern int jbd2_journal_get_create_access (handle_t *, struct buffer_head *); +extern int jbd2_journal_get_undo_access(handle_t *, struct buffer_head *); +extern int jbd2_journal_dirty_data (handle_t *, struct buffer_head *); +extern int jbd2_journal_dirty_metadata (handle_t *, struct buffer_head *); +extern void jbd2_journal_release_buffer (handle_t *, struct buffer_head *); +extern int jbd2_journal_forget (handle_t *, struct buffer_head *); extern void journal_sync_buffer (struct buffer_head *); -extern void journal_invalidatepage(journal_t *, +extern void jbd2_journal_invalidatepage(journal_t *, struct page *, unsigned long); -extern int journal_try_to_free_buffers(journal_t *, struct page *, gfp_t); -extern int journal_stop(handle_t *); -extern int journal_flush (journal_t *); -extern void journal_lock_updates (journal_t *); -extern void journal_unlock_updates (journal_t *); +extern int jbd2_journal_try_to_free_buffers(journal_t *, struct page *, gfp_t); +extern int jbd2_journal_stop(handle_t *); +extern int jbd2_journal_flush (journal_t *); +extern void jbd2_journal_lock_updates (journal_t *); +extern void jbd2_journal_unlock_updates (journal_t *); -extern journal_t * journal_init_dev(struct block_device *bdev, +extern journal_t * jbd2_journal_init_dev(struct block_device *bdev, struct block_device *fs_dev, int start, int len, int bsize); -extern journal_t * journal_init_inode (struct inode *); -extern int journal_update_format (journal_t *); -extern int journal_check_used_features +extern journal_t * jbd2_journal_init_inode (struct inode *); +extern int jbd2_journal_update_format (journal_t *); +extern int jbd2_journal_check_used_features (journal_t *, unsigned long, unsigned long, unsigned long); -extern int journal_check_available_features +extern int jbd2_journal_check_available_features (journal_t *, unsigned long, unsigned long, unsigned long); -extern int journal_set_features +extern int jbd2_journal_set_features (journal_t *, unsigned long, unsigned long, unsigned long); -extern int journal_create (journal_t *); -extern int journal_load (journal_t *journal); -extern void journal_destroy (journal_t *); -extern int journal_recover (journal_t *journal); -extern int journal_wipe (journal_t *, int); -extern int journal_skip_recovery (journal_t *); -extern void journal_update_superblock (journal_t *, int); -extern void __journal_abort_hard (journal_t *); -extern void journal_abort (journal_t *, int); -extern int journal_errno (journal_t *); -extern void journal_ack_err (journal_t *); -extern int journal_clear_err (journal_t *); -extern int journal_bmap(journal_t *, unsigned long, unsigned long *); -extern int journal_force_commit(journal_t *); +extern int jbd2_journal_create (journal_t *); +extern int jbd2_journal_load (journal_t *journal); +extern void jbd2_journal_destroy (journal_t *); +extern int jbd2_journal_recover (journal_t *journal); +extern int jbd2_journal_wipe (journal_t *, int); +extern int jbd2_journal_skip_recovery (journal_t *); +extern void jbd2_journal_update_superblock (journal_t *, int); +extern void __jbd2_journal_abort_hard (journal_t *); +extern void jbd2_journal_abort (journal_t *, int); +extern int jbd2_journal_errno (journal_t *); +extern void jbd2_journal_ack_err (journal_t *); +extern int jbd2_journal_clear_err (journal_t *); +extern int jbd2_journal_bmap(journal_t *, unsigned long, unsigned long *); +extern int jbd2_journal_force_commit(journal_t *); /* * journal_head management */ -struct journal_head *journal_add_journal_head(struct buffer_head *bh); -struct journal_head *journal_grab_journal_head(struct buffer_head *bh); -void journal_remove_journal_head(struct buffer_head *bh); -void journal_put_journal_head(struct journal_head *jh); +struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh); +struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh); +void jbd2_journal_remove_journal_head(struct buffer_head *bh); +void jbd2_journal_put_journal_head(struct journal_head *jh); /* * handle management */ -extern kmem_cache_t *jbd_handle_cache; +extern kmem_cache_t *jbd2_handle_cache; static inline handle_t *jbd_alloc_handle(gfp_t gfp_flags) { - return kmem_cache_alloc(jbd_handle_cache, gfp_flags); + return kmem_cache_alloc(jbd2_handle_cache, gfp_flags); } static inline void jbd_free_handle(handle_t *handle) { - kmem_cache_free(jbd_handle_cache, handle); + kmem_cache_free(jbd2_handle_cache, handle); } /* Primary revoke support */ #define JOURNAL_REVOKE_DEFAULT_HASH 256 -extern int journal_init_revoke(journal_t *, int); -extern void journal_destroy_revoke_caches(void); -extern int journal_init_revoke_caches(void); +extern int jbd2_journal_init_revoke(journal_t *, int); +extern void jbd2_journal_destroy_revoke_caches(void); +extern int jbd2_journal_init_revoke_caches(void); -extern void journal_destroy_revoke(journal_t *); -extern int journal_revoke (handle_t *, +extern void jbd2_journal_destroy_revoke(journal_t *); +extern int jbd2_journal_revoke (handle_t *, unsigned long, struct buffer_head *); -extern int journal_cancel_revoke(handle_t *, struct journal_head *); -extern void journal_write_revoke_records(journal_t *, transaction_t *); +extern int jbd2_journal_cancel_revoke(handle_t *, struct journal_head *); +extern void jbd2_journal_write_revoke_records(journal_t *, transaction_t *); /* Recovery revoke support */ -extern int journal_set_revoke(journal_t *, unsigned long, tid_t); -extern int journal_test_revoke(journal_t *, unsigned long, tid_t); -extern void journal_clear_revoke(journal_t *); -extern void journal_switch_revoke_table(journal_t *journal); +extern int jbd2_journal_set_revoke(journal_t *, unsigned long, tid_t); +extern int jbd2_journal_test_revoke(journal_t *, unsigned long, tid_t); +extern void jbd2_journal_clear_revoke(journal_t *); +extern void jbd2_journal_switch_revoke_table(journal_t *journal); /* * The log thread user interface: @@ -986,17 +986,17 @@ extern void journal_switch_revoke_table(journal_t *journal); * transitions on demand. */ -int __log_space_left(journal_t *); /* Called with journal locked */ -int log_start_commit(journal_t *journal, tid_t tid); -int __log_start_commit(journal_t *journal, tid_t tid); -int journal_start_commit(journal_t *journal, tid_t *tid); -int journal_force_commit_nested(journal_t *journal); -int log_wait_commit(journal_t *journal, tid_t tid); -int log_do_checkpoint(journal_t *journal); +int __jbd2_log_space_left(journal_t *); /* Called with journal locked */ +int jbd2_log_start_commit(journal_t *journal, tid_t tid); +int __jbd2_log_start_commit(journal_t *journal, tid_t tid); +int jbd2_journal_start_commit(journal_t *journal, tid_t *tid); +int jbd2_journal_force_commit_nested(journal_t *journal); +int jbd2_log_wait_commit(journal_t *journal, tid_t tid); +int jbd2_log_do_checkpoint(journal_t *journal); -void __log_wait_for_space(journal_t *journal); -extern void __journal_drop_transaction(journal_t *, transaction_t *); -extern int cleanup_journal_tail(journal_t *); +void __jbd2_log_wait_for_space(journal_t *journal); +extern void __jbd2_journal_drop_transaction(journal_t *, transaction_t *); +extern int jbd2_cleanup_journal_tail(journal_t *); /* Debugging code only: */ @@ -1010,7 +1010,7 @@ do { \ /* * is_journal_abort * - * Simple test wrapper function to test the JFS_ABORT state flag. This + * Simple test wrapper function to test the JBD2_ABORT state flag. This * bit, when set, indicates that we have had a fatal error somewhere, * either inside the journaling layer or indicated to us by the client * (eg. ext3), and that we and should not commit any further @@ -1019,7 +1019,7 @@ do { \ static inline int is_journal_aborted(journal_t *journal) { - return journal->j_flags & JFS_ABORT; + return journal->j_flags & JBD2_ABORT; } static inline int is_handle_aborted(handle_t *handle) @@ -1029,7 +1029,7 @@ static inline int is_handle_aborted(handle_t *handle) return is_journal_aborted(handle->h_transaction->t_journal); } -static inline void journal_abort_handle(handle_t *handle) +static inline void jbd2_journal_abort_handle(handle_t *handle) { handle->h_aborted = 1; } @@ -1051,7 +1051,7 @@ static inline int tid_geq(tid_t x, tid_t y) return (difference >= 0); } -extern int journal_blocks_per_page(struct inode *inode); +extern int jbd2_journal_blocks_per_page(struct inode *inode); /* * Return the minimum number of blocks which must be free in the journal -- cgit v1.2.3 From c3fcc8137ce4296ad6ab94f88bd60cbe03d21527 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 11 Oct 2006 01:21:02 -0700 Subject: [PATCH] jbd2: cleanup ext4_jbd.h To allow ext4 to build during the transition from jbd to jbd2, we have both ext4_jbd.h and ext4_jbd2.h in the tree. We no longer need the former. Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/ext4_jbd.h | 268 ----------------------------------------------- 1 file changed, 268 deletions(-) delete mode 100644 include/linux/ext4_jbd.h (limited to 'include/linux') diff --git a/include/linux/ext4_jbd.h b/include/linux/ext4_jbd.h deleted file mode 100644 index 3dbf6c779037..000000000000 --- a/include/linux/ext4_jbd.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * linux/include/linux/ext4_jbd.h - * - * Written by Stephen C. Tweedie , 1999 - * - * Copyright 1998--1999 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Ext4-specific journaling extensions. - */ - -#ifndef _LINUX_EXT4_JBD_H -#define _LINUX_EXT4_JBD_H - -#include -#include -#include - -#define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal) - -/* Define the number of blocks we need to account to a transaction to - * modify one block of data. - * - * We may have to touch one inode, one bitmap buffer, up to three - * indirection blocks, the group and superblock summaries, and the data - * block to complete the transaction. */ - -#define EXT4_SINGLEDATA_TRANS_BLOCKS 8U - -/* Extended attribute operations touch at most two data buffers, - * two bitmap buffers, and two group summaries, in addition to the inode - * and the superblock, which are already accounted for. */ - -#define EXT4_XATTR_TRANS_BLOCKS 6U - -/* Define the minimum size for a transaction which modifies data. This - * needs to take into account the fact that we may end up modifying two - * quota files too (one for the group, one for the user quota). The - * superblock only gets updated once, of course, so don't bother - * counting that again for the quota updates. */ - -#define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS + \ - EXT4_XATTR_TRANS_BLOCKS - 2 + \ - 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) - -/* 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. */ - -#define EXT4_DELETE_TRANS_BLOCKS(sb) (2 * EXT4_DATA_TRANS_BLOCKS(sb) + 64) - -/* Define an arbitrary limit for the amount of data we will anticipate - * writing to any given transaction. For unbounded transactions such as - * write(2) and truncate(2) we can write more than this, but we always - * start off at the maximum transaction size and grow the transaction - * optimistically as we go. */ - -#define EXT4_MAX_TRANS_DATA 64U - -/* We break up a large truncate or write transaction once the handle's - * buffer credits gets this low, we need either to extend the - * transaction or to start a new one. Reserve enough space here for - * inode, bitmap, superblock, group and indirection updates for at least - * one block, plus two quota updates. Quota allocations are not - * needed. */ - -#define EXT4_RESERVE_TRANS_BLOCKS 12U - -#define EXT4_INDEX_EXTRA_TRANS_BLOCKS 8 - -#ifdef CONFIG_QUOTA -/* Amount of blocks needed for quota update - we know that the structure was - * allocated so we need to update only inode+data */ -#define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0) -/* Amount of blocks needed for quota insert/delete - we do some block writes - * but inode, sb and group updates are done only once */ -#define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ - (EXT4_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0) -#define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ - (EXT4_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0) -#else -#define EXT4_QUOTA_TRANS_BLOCKS(sb) 0 -#define EXT4_QUOTA_INIT_BLOCKS(sb) 0 -#define EXT4_QUOTA_DEL_BLOCKS(sb) 0 -#endif - -int -ext4_mark_iloc_dirty(handle_t *handle, - struct inode *inode, - struct ext4_iloc *iloc); - -/* - * On success, We end up with an outstanding reference count against - * iloc->bh. This _must_ be cleaned up later. - */ - -int ext4_reserve_inode_write(handle_t *handle, struct inode *inode, - struct ext4_iloc *iloc); - -int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode); - -/* - * Wrapper functions with which ext4 calls into JBD. The intent here is - * to allow these to be turned into appropriate stubs so ext4 can control - * ext2 filesystems, so ext2+ext4 systems only nee one fs. This work hasn't - * been done yet. - */ - -void ext4_journal_abort_handle(const char *caller, const char *err_fn, - struct buffer_head *bh, handle_t *handle, int err); - -static inline int -__ext4_journal_get_undo_access(const char *where, handle_t *handle, - struct buffer_head *bh) -{ - int err = journal_get_undo_access(handle, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} - -static inline int -__ext4_journal_get_write_access(const char *where, handle_t *handle, - struct buffer_head *bh) -{ - int err = journal_get_write_access(handle, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} - -static inline void -ext4_journal_release_buffer(handle_t *handle, struct buffer_head *bh) -{ - journal_release_buffer(handle, bh); -} - -static inline int -__ext4_journal_forget(const char *where, handle_t *handle, struct buffer_head *bh) -{ - int err = journal_forget(handle, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} - -static inline int -__ext4_journal_revoke(const char *where, handle_t *handle, - unsigned long blocknr, struct buffer_head *bh) -{ - int err = journal_revoke(handle, blocknr, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} - -static inline int -__ext4_journal_get_create_access(const char *where, - handle_t *handle, struct buffer_head *bh) -{ - int err = journal_get_create_access(handle, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} - -static inline int -__ext4_journal_dirty_metadata(const char *where, - handle_t *handle, struct buffer_head *bh) -{ - int err = journal_dirty_metadata(handle, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} - - -#define ext4_journal_get_undo_access(handle, bh) \ - __ext4_journal_get_undo_access(__FUNCTION__, (handle), (bh)) -#define ext4_journal_get_write_access(handle, bh) \ - __ext4_journal_get_write_access(__FUNCTION__, (handle), (bh)) -#define ext4_journal_revoke(handle, blocknr, bh) \ - __ext4_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh)) -#define ext4_journal_get_create_access(handle, bh) \ - __ext4_journal_get_create_access(__FUNCTION__, (handle), (bh)) -#define ext4_journal_dirty_metadata(handle, bh) \ - __ext4_journal_dirty_metadata(__FUNCTION__, (handle), (bh)) -#define ext4_journal_forget(handle, bh) \ - __ext4_journal_forget(__FUNCTION__, (handle), (bh)) - -int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh); - -handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); -int __ext4_journal_stop(const char *where, handle_t *handle); - -static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks) -{ - return ext4_journal_start_sb(inode->i_sb, nblocks); -} - -#define ext4_journal_stop(handle) \ - __ext4_journal_stop(__FUNCTION__, (handle)) - -static inline handle_t *ext4_journal_current_handle(void) -{ - return journal_current_handle(); -} - -static inline int ext4_journal_extend(handle_t *handle, int nblocks) -{ - return journal_extend(handle, nblocks); -} - -static inline int ext4_journal_restart(handle_t *handle, int nblocks) -{ - return journal_restart(handle, nblocks); -} - -static inline int ext4_journal_blocks_per_page(struct inode *inode) -{ - return journal_blocks_per_page(inode); -} - -static inline int ext4_journal_force_commit(journal_t *journal) -{ - return journal_force_commit(journal); -} - -/* super.c */ -int ext4_force_commit(struct super_block *sb); - -static inline int ext4_should_journal_data(struct inode *inode) -{ - if (!S_ISREG(inode->i_mode)) - return 1; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) - return 1; - if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) - return 1; - return 0; -} - -static inline int ext4_should_order_data(struct inode *inode) -{ - if (!S_ISREG(inode->i_mode)) - return 0; - if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) - return 0; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) - return 1; - return 0; -} - -static inline int ext4_should_writeback_data(struct inode *inode) -{ - if (!S_ISREG(inode->i_mode)) - return 0; - if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) - return 0; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) - return 1; - return 0; -} - -#endif /* _LINUX_EXT4_JBD_H */ -- cgit v1.2.3 From a86c61812637c7dd0c57e29880cffd477b62f2e7 Mon Sep 17 00:00:00 2001 From: Alex Tomas Date: Wed, 11 Oct 2006 01:21:03 -0700 Subject: [PATCH] ext3: add extent map support On disk extents format: /* * this is extent on-disk structure * it's used at the bottom of the tree */ struct ext3_extent { __le32 ee_block; /* first logical block extent covers */ __le16 ee_len; /* number of blocks covered by extent */ __le16 ee_start_hi; /* high 16 bits of physical block */ __le32 ee_start; /* low 32 bigs of physical block */ }; Signed-off-by: Alex Tomas Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/Makefile | 2 +- fs/ext4/dir.c | 3 +- fs/ext4/extents.c | 2075 +++++++++++++++++++++++++++++++++++++++ fs/ext4/ialloc.c | 11 + fs/ext4/inode.c | 17 +- fs/ext4/ioctl.c | 1 - fs/ext4/super.c | 10 +- include/linux/ext4_fs.h | 33 +- include/linux/ext4_fs_extents.h | 196 ++++ include/linux/ext4_fs_i.h | 13 + include/linux/ext4_fs_sb.h | 10 + include/linux/ext4_jbd2.h | 15 +- 12 files changed, 2368 insertions(+), 18 deletions(-) create mode 100644 fs/ext4/extents.c create mode 100644 include/linux/ext4_fs_extents.h (limited to 'include/linux') diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 09c487893e4a..a6acb96ebeb9 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_EXT4DEV_FS) += ext4dev.o ext4dev-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o hash.o resize.o + ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o ext4dev-$(CONFIG_EXT4DEV_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o ext4dev-$(CONFIG_EXT4DEV_FS_POSIX_ACL) += acl.o diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 9833d5d00c46..18ac173af575 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -134,8 +134,7 @@ static int ext4_readdir(struct file * filp, struct buffer_head *bh = NULL; map_bh.b_state = 0; - err = ext4_get_blocks_handle(NULL, inode, blk, 1, - &map_bh, 0, 0); + err = ext4_get_blocks_wrap(NULL, inode, blk, 1, &map_bh, 0, 0); if (err > 0) { page_cache_readahead(sb->s_bdev->bd_inode->i_mapping, &filp->f_ra, diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c new file mode 100644 index 000000000000..f67b2ef6a71f --- /dev/null +++ b/fs/ext4/extents.c @@ -0,0 +1,2075 @@ +/* + * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com + * Written by Alex Tomas + * + * Architecture independence: + * Copyright (c) 2005, Bull S.A. + * Written by Pierre Peiffer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public Licens + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- + */ + +/* + * Extents support for EXT4 + * + * TODO: + * - ext4*_error() should be used in some situations + * - analyze all BUG()/BUG_ON(), use -EIO where appropriate + * - smart tree reduction + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static int ext4_ext_check_header(const char *function, struct inode *inode, + struct ext4_extent_header *eh) +{ + const char *error_msg = NULL; + + if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) { + error_msg = "invalid magic"; + goto corrupted; + } + if (unlikely(eh->eh_max == 0)) { + error_msg = "invalid eh_max"; + goto corrupted; + } + if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) { + error_msg = "invalid eh_entries"; + goto corrupted; + } + return 0; + +corrupted: + ext4_error(inode->i_sb, function, + "bad header in inode #%lu: %s - magic %x, " + "entries %u, max %u, depth %u", + inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic), + le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max), + le16_to_cpu(eh->eh_depth)); + + return -EIO; +} + +static handle_t *ext4_ext_journal_restart(handle_t *handle, int needed) +{ + int err; + + if (handle->h_buffer_credits > needed) + return handle; + if (!ext4_journal_extend(handle, needed)) + return handle; + err = ext4_journal_restart(handle, needed); + + return handle; +} + +/* + * could return: + * - EROFS + * - ENOMEM + */ +static int ext4_ext_get_access(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path) +{ + if (path->p_bh) { + /* path points to block */ + return ext4_journal_get_write_access(handle, path->p_bh); + } + /* path points to leaf/index in inode body */ + /* we use in-core data, no need to protect them */ + return 0; +} + +/* + * could return: + * - EROFS + * - ENOMEM + * - EIO + */ +static int ext4_ext_dirty(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path) +{ + int err; + if (path->p_bh) { + /* path points to block */ + err = ext4_journal_dirty_metadata(handle, path->p_bh); + } else { + /* path points to leaf/index in inode body */ + err = ext4_mark_inode_dirty(handle, inode); + } + return err; +} + +static int ext4_ext_find_goal(struct inode *inode, + struct ext4_ext_path *path, + unsigned long block) +{ + struct ext4_inode_info *ei = EXT4_I(inode); + unsigned long bg_start; + unsigned long colour; + int depth; + + if (path) { + struct ext4_extent *ex; + depth = path->p_depth; + + /* try to predict block placement */ + if ((ex = path[depth].p_ext)) + return le32_to_cpu(ex->ee_start) + + (block - le32_to_cpu(ex->ee_block)); + + /* it looks index is empty + * try to find starting from index itself */ + if (path[depth].p_bh) + return path[depth].p_bh->b_blocknr; + } + + /* OK. use inode's group */ + bg_start = (ei->i_block_group * EXT4_BLOCKS_PER_GROUP(inode->i_sb)) + + le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_first_data_block); + colour = (current->pid % 16) * + (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16); + return bg_start + colour + block; +} + +static int +ext4_ext_new_block(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path, + struct ext4_extent *ex, int *err) +{ + int goal, newblock; + + goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block)); + newblock = ext4_new_block(handle, inode, goal, err); + return newblock; +} + +static inline int ext4_ext_space_block(struct inode *inode) +{ + int size; + + size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) + / sizeof(struct ext4_extent); +#ifdef AGRESSIVE_TEST + if (size > 6) + size = 6; +#endif + return size; +} + +static inline int ext4_ext_space_block_idx(struct inode *inode) +{ + int size; + + size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) + / sizeof(struct ext4_extent_idx); +#ifdef AGRESSIVE_TEST + if (size > 5) + size = 5; +#endif + return size; +} + +static inline int ext4_ext_space_root(struct inode *inode) +{ + int size; + + size = sizeof(EXT4_I(inode)->i_data); + size -= sizeof(struct ext4_extent_header); + size /= sizeof(struct ext4_extent); +#ifdef AGRESSIVE_TEST + if (size > 3) + size = 3; +#endif + return size; +} + +static inline int ext4_ext_space_root_idx(struct inode *inode) +{ + int size; + + size = sizeof(EXT4_I(inode)->i_data); + size -= sizeof(struct ext4_extent_header); + size /= sizeof(struct ext4_extent_idx); +#ifdef AGRESSIVE_TEST + if (size > 4) + size = 4; +#endif + return size; +} + +#ifdef EXT_DEBUG +static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) +{ + int k, l = path->p_depth; + + ext_debug("path:"); + for (k = 0; k <= l; k++, path++) { + if (path->p_idx) { + ext_debug(" %d->%d", le32_to_cpu(path->p_idx->ei_block), + le32_to_cpu(path->p_idx->ei_leaf)); + } else if (path->p_ext) { + ext_debug(" %d:%d:%d", + le32_to_cpu(path->p_ext->ee_block), + le16_to_cpu(path->p_ext->ee_len), + le32_to_cpu(path->p_ext->ee_start)); + } else + ext_debug(" []"); + } + ext_debug("\n"); +} + +static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path) +{ + int depth = ext_depth(inode); + struct ext4_extent_header *eh; + struct ext4_extent *ex; + int i; + + if (!path) + return; + + eh = path[depth].p_hdr; + ex = EXT_FIRST_EXTENT(eh); + + for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) { + ext_debug("%d:%d:%d ", le32_to_cpu(ex->ee_block), + le16_to_cpu(ex->ee_len), + le32_to_cpu(ex->ee_start)); + } + ext_debug("\n"); +} +#else +#define ext4_ext_show_path(inode,path) +#define ext4_ext_show_leaf(inode,path) +#endif + +static void ext4_ext_drop_refs(struct ext4_ext_path *path) +{ + int depth = path->p_depth; + int i; + + for (i = 0; i <= depth; i++, path++) + if (path->p_bh) { + brelse(path->p_bh); + path->p_bh = NULL; + } +} + +/* + * binary search for closest index by given block + */ +static void +ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int block) +{ + struct ext4_extent_header *eh = path->p_hdr; + struct ext4_extent_idx *r, *l, *m; + + BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC); + BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max)); + BUG_ON(le16_to_cpu(eh->eh_entries) <= 0); + + ext_debug("binsearch for %d(idx): ", block); + + l = EXT_FIRST_INDEX(eh) + 1; + r = EXT_FIRST_INDEX(eh) + le16_to_cpu(eh->eh_entries) - 1; + while (l <= r) { + m = l + (r - l) / 2; + if (block < le32_to_cpu(m->ei_block)) + r = m - 1; + else + l = m + 1; + ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ei_block, + m, m->ei_block, r, r->ei_block); + } + + path->p_idx = l - 1; + ext_debug(" -> %d->%d ", le32_to_cpu(path->p_idx->ei_block), + le32_to_cpu(path->p_idx->ei_leaf)); + +#ifdef CHECK_BINSEARCH + { + struct ext4_extent_idx *chix, *ix; + int k; + + chix = ix = EXT_FIRST_INDEX(eh); + for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ix++) { + if (k != 0 && + le32_to_cpu(ix->ei_block) <= le32_to_cpu(ix[-1].ei_block)) { + printk("k=%d, ix=0x%p, first=0x%p\n", k, + ix, EXT_FIRST_INDEX(eh)); + printk("%u <= %u\n", + le32_to_cpu(ix->ei_block), + le32_to_cpu(ix[-1].ei_block)); + } + BUG_ON(k && le32_to_cpu(ix->ei_block) + <= le32_to_cpu(ix[-1].ei_block)); + if (block < le32_to_cpu(ix->ei_block)) + break; + chix = ix; + } + BUG_ON(chix != path->p_idx); + } +#endif + +} + +/* + * binary search for closest extent by given block + */ +static void +ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block) +{ + struct ext4_extent_header *eh = path->p_hdr; + struct ext4_extent *r, *l, *m; + + BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC); + BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max)); + + if (eh->eh_entries == 0) { + /* + * this leaf is empty yet: + * we get such a leaf in split/add case + */ + return; + } + + ext_debug("binsearch for %d: ", block); + + l = EXT_FIRST_EXTENT(eh) + 1; + r = EXT_FIRST_EXTENT(eh) + le16_to_cpu(eh->eh_entries) - 1; + + while (l <= r) { + m = l + (r - l) / 2; + if (block < le32_to_cpu(m->ee_block)) + r = m - 1; + else + l = m + 1; + ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ee_block, + m, m->ee_block, r, r->ee_block); + } + + path->p_ext = l - 1; + ext_debug(" -> %d:%d:%d ", + le32_to_cpu(path->p_ext->ee_block), + le32_to_cpu(path->p_ext->ee_start), + le16_to_cpu(path->p_ext->ee_len)); + +#ifdef CHECK_BINSEARCH + { + struct ext4_extent *chex, *ex; + int k; + + chex = ex = EXT_FIRST_EXTENT(eh); + for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ex++) { + BUG_ON(k && le32_to_cpu(ex->ee_block) + <= le32_to_cpu(ex[-1].ee_block)); + if (block < le32_to_cpu(ex->ee_block)) + break; + chex = ex; + } + BUG_ON(chex != path->p_ext); + } +#endif + +} + +int ext4_ext_tree_init(handle_t *handle, struct inode *inode) +{ + struct ext4_extent_header *eh; + + eh = ext_inode_hdr(inode); + eh->eh_depth = 0; + eh->eh_entries = 0; + eh->eh_magic = EXT4_EXT_MAGIC; + eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode)); + ext4_mark_inode_dirty(handle, inode); + ext4_ext_invalidate_cache(inode); + return 0; +} + +struct ext4_ext_path * +ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path) +{ + struct ext4_extent_header *eh; + struct buffer_head *bh; + short int depth, i, ppos = 0, alloc = 0; + + eh = ext_inode_hdr(inode); + BUG_ON(eh == NULL); + if (ext4_ext_check_header(__FUNCTION__, inode, eh)) + return ERR_PTR(-EIO); + + i = depth = ext_depth(inode); + + /* account possible depth increase */ + if (!path) { + path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 2), + GFP_NOFS); + if (!path) + return ERR_PTR(-ENOMEM); + alloc = 1; + } + memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1)); + path[0].p_hdr = eh; + + /* walk through the tree */ + while (i) { + ext_debug("depth %d: num %d, max %d\n", + ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); + ext4_ext_binsearch_idx(inode, path + ppos, block); + path[ppos].p_block = le32_to_cpu(path[ppos].p_idx->ei_leaf); + path[ppos].p_depth = i; + path[ppos].p_ext = NULL; + + bh = sb_bread(inode->i_sb, path[ppos].p_block); + if (!bh) + goto err; + + eh = ext_block_hdr(bh); + ppos++; + BUG_ON(ppos > depth); + path[ppos].p_bh = bh; + path[ppos].p_hdr = eh; + i--; + + if (ext4_ext_check_header(__FUNCTION__, inode, eh)) + goto err; + } + + path[ppos].p_depth = i; + path[ppos].p_hdr = eh; + path[ppos].p_ext = NULL; + path[ppos].p_idx = NULL; + + if (ext4_ext_check_header(__FUNCTION__, inode, eh)) + goto err; + + /* find extent */ + ext4_ext_binsearch(inode, path + ppos, block); + + ext4_ext_show_path(inode, path); + + return path; + +err: + ext4_ext_drop_refs(path); + if (alloc) + kfree(path); + return ERR_PTR(-EIO); +} + +/* + * insert new index [logical;ptr] into the block at cupr + * it check where to insert: before curp or after curp + */ +static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, + struct ext4_ext_path *curp, + int logical, int ptr) +{ + struct ext4_extent_idx *ix; + int len, err; + + if ((err = ext4_ext_get_access(handle, inode, curp))) + return err; + + BUG_ON(logical == le32_to_cpu(curp->p_idx->ei_block)); + len = EXT_MAX_INDEX(curp->p_hdr) - curp->p_idx; + if (logical > le32_to_cpu(curp->p_idx->ei_block)) { + /* insert after */ + if (curp->p_idx != EXT_LAST_INDEX(curp->p_hdr)) { + len = (len - 1) * sizeof(struct ext4_extent_idx); + len = len < 0 ? 0 : len; + ext_debug("insert new index %d after: %d. " + "move %d from 0x%p to 0x%p\n", + logical, ptr, len, + (curp->p_idx + 1), (curp->p_idx + 2)); + memmove(curp->p_idx + 2, curp->p_idx + 1, len); + } + ix = curp->p_idx + 1; + } else { + /* insert before */ + len = len * sizeof(struct ext4_extent_idx); + len = len < 0 ? 0 : len; + ext_debug("insert new index %d before: %d. " + "move %d from 0x%p to 0x%p\n", + logical, ptr, len, + curp->p_idx, (curp->p_idx + 1)); + memmove(curp->p_idx + 1, curp->p_idx, len); + ix = curp->p_idx; + } + + ix->ei_block = cpu_to_le32(logical); + ix->ei_leaf = cpu_to_le32(ptr); + curp->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(curp->p_hdr->eh_entries)+1); + + BUG_ON(le16_to_cpu(curp->p_hdr->eh_entries) + > le16_to_cpu(curp->p_hdr->eh_max)); + BUG_ON(ix > EXT_LAST_INDEX(curp->p_hdr)); + + err = ext4_ext_dirty(handle, inode, curp); + ext4_std_error(inode->i_sb, err); + + return err; +} + +/* + * routine inserts new subtree into the path, using free index entry + * at depth 'at: + * - allocates all needed blocks (new leaf and all intermediate index blocks) + * - makes decision where to split + * - moves remaining extens and index entries (right to the split point) + * into the newly allocated blocks + * - initialize subtree + */ +static int ext4_ext_split(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path, + struct ext4_extent *newext, int at) +{ + struct buffer_head *bh = NULL; + int depth = ext_depth(inode); + struct ext4_extent_header *neh; + struct ext4_extent_idx *fidx; + struct ext4_extent *ex; + int i = at, k, m, a; + unsigned long newblock, oldblock; + __le32 border; + int *ablocks = NULL; /* array of allocated blocks */ + int err = 0; + + /* make decision: where to split? */ + /* FIXME: now desicion is simplest: at current extent */ + + /* if current leaf will be splitted, then we should use + * border from split point */ + BUG_ON(path[depth].p_ext > EXT_MAX_EXTENT(path[depth].p_hdr)); + if (path[depth].p_ext != EXT_MAX_EXTENT(path[depth].p_hdr)) { + border = path[depth].p_ext[1].ee_block; + ext_debug("leaf will be splitted." + " next leaf starts at %d\n", + le32_to_cpu(border)); + } else { + border = newext->ee_block; + ext_debug("leaf will be added." + " next leaf starts at %d\n", + le32_to_cpu(border)); + } + + /* + * if error occurs, then we break processing + * and turn filesystem read-only. so, index won't + * be inserted and tree will be in consistent + * state. next mount will repair buffers too + */ + + /* + * get array to track all allocated blocks + * we need this to handle errors and free blocks + * upon them + */ + ablocks = kmalloc(sizeof(unsigned long) * depth, GFP_NOFS); + if (!ablocks) + return -ENOMEM; + memset(ablocks, 0, sizeof(unsigned long) * depth); + + /* allocate all needed blocks */ + ext_debug("allocate %d blocks for indexes/leaf\n", depth - at); + for (a = 0; a < depth - at; a++) { + newblock = ext4_ext_new_block(handle, inode, path, newext, &err); + if (newblock == 0) + goto cleanup; + ablocks[a] = newblock; + } + + /* initialize new leaf */ + newblock = ablocks[--a]; + BUG_ON(newblock == 0); + bh = sb_getblk(inode->i_sb, newblock); + if (!bh) { + err = -EIO; + goto cleanup; + } + lock_buffer(bh); + + if ((err = ext4_journal_get_create_access(handle, bh))) + goto cleanup; + + neh = ext_block_hdr(bh); + neh->eh_entries = 0; + neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode)); + neh->eh_magic = EXT4_EXT_MAGIC; + neh->eh_depth = 0; + ex = EXT_FIRST_EXTENT(neh); + + /* move remain of path[depth] to the new leaf */ + BUG_ON(path[depth].p_hdr->eh_entries != path[depth].p_hdr->eh_max); + /* start copy from next extent */ + /* TODO: we could do it by single memmove */ + m = 0; + path[depth].p_ext++; + while (path[depth].p_ext <= + EXT_MAX_EXTENT(path[depth].p_hdr)) { + ext_debug("move %d:%d:%d in new leaf %lu\n", + le32_to_cpu(path[depth].p_ext->ee_block), + le32_to_cpu(path[depth].p_ext->ee_start), + le16_to_cpu(path[depth].p_ext->ee_len), + newblock); + /*memmove(ex++, path[depth].p_ext++, + sizeof(struct ext4_extent)); + neh->eh_entries++;*/ + path[depth].p_ext++; + m++; + } + if (m) { + memmove(ex, path[depth].p_ext-m, sizeof(struct ext4_extent)*m); + neh->eh_entries = cpu_to_le16(le16_to_cpu(neh->eh_entries)+m); + } + + set_buffer_uptodate(bh); + unlock_buffer(bh); + + if ((err = ext4_journal_dirty_metadata(handle, bh))) + goto cleanup; + brelse(bh); + bh = NULL; + + /* correct old leaf */ + if (m) { + if ((err = ext4_ext_get_access(handle, inode, path + depth))) + goto cleanup; + path[depth].p_hdr->eh_entries = + cpu_to_le16(le16_to_cpu(path[depth].p_hdr->eh_entries)-m); + if ((err = ext4_ext_dirty(handle, inode, path + depth))) + goto cleanup; + + } + + /* create intermediate indexes */ + k = depth - at - 1; + BUG_ON(k < 0); + if (k) + ext_debug("create %d intermediate indices\n", k); + /* insert new index into current index block */ + /* current depth stored in i var */ + i = depth - 1; + while (k--) { + oldblock = newblock; + newblock = ablocks[--a]; + bh = sb_getblk(inode->i_sb, newblock); + if (!bh) { + err = -EIO; + goto cleanup; + } + lock_buffer(bh); + + if ((err = ext4_journal_get_create_access(handle, bh))) + goto cleanup; + + neh = ext_block_hdr(bh); + neh->eh_entries = cpu_to_le16(1); + neh->eh_magic = EXT4_EXT_MAGIC; + neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode)); + neh->eh_depth = cpu_to_le16(depth - i); + fidx = EXT_FIRST_INDEX(neh); + fidx->ei_block = border; + fidx->ei_leaf = cpu_to_le32(oldblock); + + ext_debug("int.index at %d (block %lu): %lu -> %lu\n", i, + newblock, (unsigned long) le32_to_cpu(border), + oldblock); + /* copy indexes */ + m = 0; + path[i].p_idx++; + + ext_debug("cur 0x%p, last 0x%p\n", path[i].p_idx, + EXT_MAX_INDEX(path[i].p_hdr)); + BUG_ON(EXT_MAX_INDEX(path[i].p_hdr) != + EXT_LAST_INDEX(path[i].p_hdr)); + while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) { + ext_debug("%d: move %d:%d in new index %lu\n", i, + le32_to_cpu(path[i].p_idx->ei_block), + le32_to_cpu(path[i].p_idx->ei_leaf), + newblock); + /*memmove(++fidx, path[i].p_idx++, + sizeof(struct ext4_extent_idx)); + neh->eh_entries++; + BUG_ON(neh->eh_entries > neh->eh_max);*/ + path[i].p_idx++; + m++; + } + if (m) { + memmove(++fidx, path[i].p_idx - m, + sizeof(struct ext4_extent_idx) * m); + neh->eh_entries = + cpu_to_le16(le16_to_cpu(neh->eh_entries) + m); + } + set_buffer_uptodate(bh); + unlock_buffer(bh); + + if ((err = ext4_journal_dirty_metadata(handle, bh))) + goto cleanup; + brelse(bh); + bh = NULL; + + /* correct old index */ + if (m) { + err = ext4_ext_get_access(handle, inode, path + i); + if (err) + goto cleanup; + path[i].p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path[i].p_hdr->eh_entries)-m); + err = ext4_ext_dirty(handle, inode, path + i); + if (err) + goto cleanup; + } + + i--; + } + + /* insert new index */ + if (err) + goto cleanup; + + err = ext4_ext_insert_index(handle, inode, path + at, + le32_to_cpu(border), newblock); + +cleanup: + if (bh) { + if (buffer_locked(bh)) + unlock_buffer(bh); + brelse(bh); + } + + if (err) { + /* free all allocated blocks in error case */ + for (i = 0; i < depth; i++) { + if (!ablocks[i]) + continue; + ext4_free_blocks(handle, inode, ablocks[i], 1); + } + } + kfree(ablocks); + + return err; +} + +/* + * routine implements tree growing procedure: + * - allocates new block + * - moves top-level data (index block or leaf) into the new block + * - initialize new top-level, creating index that points to the + * just created block + */ +static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path, + struct ext4_extent *newext) +{ + struct ext4_ext_path *curp = path; + struct ext4_extent_header *neh; + struct ext4_extent_idx *fidx; + struct buffer_head *bh; + unsigned long newblock; + int err = 0; + + newblock = ext4_ext_new_block(handle, inode, path, newext, &err); + if (newblock == 0) + return err; + + bh = sb_getblk(inode->i_sb, newblock); + if (!bh) { + err = -EIO; + ext4_std_error(inode->i_sb, err); + return err; + } + lock_buffer(bh); + + if ((err = ext4_journal_get_create_access(handle, bh))) { + unlock_buffer(bh); + goto out; + } + + /* move top-level index/leaf into new block */ + memmove(bh->b_data, curp->p_hdr, sizeof(EXT4_I(inode)->i_data)); + + /* set size of new block */ + neh = ext_block_hdr(bh); + /* old root could have indexes or leaves + * so calculate e_max right way */ + if (ext_depth(inode)) + neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode)); + else + neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode)); + neh->eh_magic = EXT4_EXT_MAGIC; + set_buffer_uptodate(bh); + unlock_buffer(bh); + + if ((err = ext4_journal_dirty_metadata(handle, bh))) + goto out; + + /* create index in new top-level index: num,max,pointer */ + if ((err = ext4_ext_get_access(handle, inode, curp))) + goto out; + + curp->p_hdr->eh_magic = EXT4_EXT_MAGIC; + curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode)); + curp->p_hdr->eh_entries = cpu_to_le16(1); + curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr); + /* FIXME: it works, but actually path[0] can be index */ + curp->p_idx->ei_block = EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block; + curp->p_idx->ei_leaf = cpu_to_le32(newblock); + + neh = ext_inode_hdr(inode); + fidx = EXT_FIRST_INDEX(neh); + ext_debug("new root: num %d(%d), lblock %d, ptr %d\n", + le16_to_cpu(neh->eh_entries), le16_to_cpu(neh->eh_max), + le32_to_cpu(fidx->ei_block), le32_to_cpu(fidx->ei_leaf)); + + neh->eh_depth = cpu_to_le16(path->p_depth + 1); + err = ext4_ext_dirty(handle, inode, curp); +out: + brelse(bh); + + return err; +} + +/* + * routine finds empty index and adds new leaf. if no free index found + * then it requests in-depth growing + */ +static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path, + struct ext4_extent *newext) +{ + struct ext4_ext_path *curp; + int depth, i, err = 0; + +repeat: + i = depth = ext_depth(inode); + + /* walk up to the tree and look for free index entry */ + curp = path + depth; + while (i > 0 && !EXT_HAS_FREE_INDEX(curp)) { + i--; + curp--; + } + + /* we use already allocated block for index block + * so, subsequent data blocks should be contigoues */ + if (EXT_HAS_FREE_INDEX(curp)) { + /* if we found index with free entry, then use that + * entry: create all needed subtree and add new leaf */ + err = ext4_ext_split(handle, inode, path, newext, i); + + /* refill path */ + ext4_ext_drop_refs(path); + path = ext4_ext_find_extent(inode, + le32_to_cpu(newext->ee_block), + path); + if (IS_ERR(path)) + err = PTR_ERR(path); + } else { + /* tree is full, time to grow in depth */ + err = ext4_ext_grow_indepth(handle, inode, path, newext); + if (err) + goto out; + + /* refill path */ + ext4_ext_drop_refs(path); + path = ext4_ext_find_extent(inode, + le32_to_cpu(newext->ee_block), + path); + if (IS_ERR(path)) { + err = PTR_ERR(path); + goto out; + } + + /* + * only first (depth 0 -> 1) produces free space + * in all other cases we have to split growed tree + */ + depth = ext_depth(inode); + if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) { + /* now we need split */ + goto repeat; + } + } + +out: + return err; +} + +/* + * returns allocated block in subsequent extent or EXT_MAX_BLOCK + * NOTE: it consider block number from index entry as + * allocated block. thus, index entries have to be consistent + * with leafs + */ +static unsigned long +ext4_ext_next_allocated_block(struct ext4_ext_path *path) +{ + int depth; + + BUG_ON(path == NULL); + depth = path->p_depth; + + if (depth == 0 && path->p_ext == NULL) + return EXT_MAX_BLOCK; + + while (depth >= 0) { + if (depth == path->p_depth) { + /* leaf */ + if (path[depth].p_ext != + EXT_LAST_EXTENT(path[depth].p_hdr)) + return le32_to_cpu(path[depth].p_ext[1].ee_block); + } else { + /* index */ + if (path[depth].p_idx != + EXT_LAST_INDEX(path[depth].p_hdr)) + return le32_to_cpu(path[depth].p_idx[1].ei_block); + } + depth--; + } + + return EXT_MAX_BLOCK; +} + +/* + * returns first allocated block from next leaf or EXT_MAX_BLOCK + */ +static unsigned ext4_ext_next_leaf_block(struct inode *inode, + struct ext4_ext_path *path) +{ + int depth; + + BUG_ON(path == NULL); + depth = path->p_depth; + + /* zero-tree has no leaf blocks at all */ + if (depth == 0) + return EXT_MAX_BLOCK; + + /* go to index block */ + depth--; + + while (depth >= 0) { + if (path[depth].p_idx != + EXT_LAST_INDEX(path[depth].p_hdr)) + return le32_to_cpu(path[depth].p_idx[1].ei_block); + depth--; + } + + return EXT_MAX_BLOCK; +} + +/* + * if leaf gets modified and modified extent is first in the leaf + * then we have to correct all indexes above + * TODO: do we need to correct tree in all cases? + */ +int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path) +{ + struct ext4_extent_header *eh; + int depth = ext_depth(inode); + struct ext4_extent *ex; + __le32 border; + int k, err = 0; + + eh = path[depth].p_hdr; + ex = path[depth].p_ext; + BUG_ON(ex == NULL); + BUG_ON(eh == NULL); + + if (depth == 0) { + /* there is no tree at all */ + return 0; + } + + if (ex != EXT_FIRST_EXTENT(eh)) { + /* we correct tree if first leaf got modified only */ + return 0; + } + + /* + * TODO: we need correction if border is smaller then current one + */ + k = depth - 1; + border = path[depth].p_ext->ee_block; + if ((err = ext4_ext_get_access(handle, inode, path + k))) + return err; + path[k].p_idx->ei_block = border; + if ((err = ext4_ext_dirty(handle, inode, path + k))) + return err; + + while (k--) { + /* change all left-side indexes */ + if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr)) + break; + if ((err = ext4_ext_get_access(handle, inode, path + k))) + break; + path[k].p_idx->ei_block = border; + if ((err = ext4_ext_dirty(handle, inode, path + k))) + break; + } + + return err; +} + +static int inline +ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, + struct ext4_extent *ex2) +{ + /* FIXME: 48bit support */ + if (le32_to_cpu(ex1->ee_block) + le16_to_cpu(ex1->ee_len) + != le32_to_cpu(ex2->ee_block)) + return 0; + +#ifdef AGRESSIVE_TEST + if (le16_to_cpu(ex1->ee_len) >= 4) + return 0; +#endif + + if (le32_to_cpu(ex1->ee_start) + le16_to_cpu(ex1->ee_len) + == le32_to_cpu(ex2->ee_start)) + return 1; + return 0; +} + +/* + * this routine tries to merge requsted extent into the existing + * extent or inserts requested extent as new one into the tree, + * creating new leaf in no-space case + */ +int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path, + struct ext4_extent *newext) +{ + struct ext4_extent_header * eh; + struct ext4_extent *ex, *fex; + struct ext4_extent *nearex; /* nearest extent */ + struct ext4_ext_path *npath = NULL; + int depth, len, err, next; + + BUG_ON(newext->ee_len == 0); + depth = ext_depth(inode); + ex = path[depth].p_ext; + BUG_ON(path[depth].p_hdr == NULL); + + /* try to insert block into found extent and return */ + if (ex && ext4_can_extents_be_merged(inode, ex, newext)) { + ext_debug("append %d block to %d:%d (from %d)\n", + le16_to_cpu(newext->ee_len), + le32_to_cpu(ex->ee_block), + le16_to_cpu(ex->ee_len), + le32_to_cpu(ex->ee_start)); + if ((err = ext4_ext_get_access(handle, inode, path + depth))) + return err; + ex->ee_len = cpu_to_le16(le16_to_cpu(ex->ee_len) + + le16_to_cpu(newext->ee_len)); + eh = path[depth].p_hdr; + nearex = ex; + goto merge; + } + +repeat: + depth = ext_depth(inode); + eh = path[depth].p_hdr; + if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) + goto has_space; + + /* probably next leaf has space for us? */ + fex = EXT_LAST_EXTENT(eh); + next = ext4_ext_next_leaf_block(inode, path); + if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block) + && next != EXT_MAX_BLOCK) { + ext_debug("next leaf block - %d\n", next); + BUG_ON(npath != NULL); + npath = ext4_ext_find_extent(inode, next, NULL); + if (IS_ERR(npath)) + return PTR_ERR(npath); + BUG_ON(npath->p_depth != path->p_depth); + eh = npath[depth].p_hdr; + if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) { + ext_debug("next leaf isnt full(%d)\n", + le16_to_cpu(eh->eh_entries)); + path = npath; + goto repeat; + } + ext_debug("next leaf has no free space(%d,%d)\n", + le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); + } + + /* + * there is no free space in found leaf + * we're gonna add new leaf in the tree + */ + err = ext4_ext_create_new_leaf(handle, inode, path, newext); + if (err) + goto cleanup; + depth = ext_depth(inode); + eh = path[depth].p_hdr; + +has_space: + nearex = path[depth].p_ext; + + if ((err = ext4_ext_get_access(handle, inode, path + depth))) + goto cleanup; + + if (!nearex) { + /* there is no extent in this leaf, create first one */ + ext_debug("first extent in the leaf: %d:%d:%d\n", + le32_to_cpu(newext->ee_block), + le32_to_cpu(newext->ee_start), + le16_to_cpu(newext->ee_len)); + path[depth].p_ext = EXT_FIRST_EXTENT(eh); + } else if (le32_to_cpu(newext->ee_block) + > le32_to_cpu(nearex->ee_block)) { +/* BUG_ON(newext->ee_block == nearex->ee_block); */ + if (nearex != EXT_LAST_EXTENT(eh)) { + len = EXT_MAX_EXTENT(eh) - nearex; + len = (len - 1) * sizeof(struct ext4_extent); + len = len < 0 ? 0 : len; + ext_debug("insert %d:%d:%d after: nearest 0x%p, " + "move %d from 0x%p to 0x%p\n", + le32_to_cpu(newext->ee_block), + le32_to_cpu(newext->ee_start), + le16_to_cpu(newext->ee_len), + nearex, len, nearex + 1, nearex + 2); + memmove(nearex + 2, nearex + 1, len); + } + path[depth].p_ext = nearex + 1; + } else { + BUG_ON(newext->ee_block == nearex->ee_block); + len = (EXT_MAX_EXTENT(eh) - nearex) * sizeof(struct ext4_extent); + len = len < 0 ? 0 : len; + ext_debug("insert %d:%d:%d before: nearest 0x%p, " + "move %d from 0x%p to 0x%p\n", + le32_to_cpu(newext->ee_block), + le32_to_cpu(newext->ee_start), + le16_to_cpu(newext->ee_len), + nearex, len, nearex + 1, nearex + 2); + memmove(nearex + 1, nearex, len); + path[depth].p_ext = nearex; + } + + eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)+1); + nearex = path[depth].p_ext; + nearex->ee_block = newext->ee_block; + nearex->ee_start = newext->ee_start; + nearex->ee_len = newext->ee_len; + /* FIXME: support for large fs */ + nearex->ee_start_hi = 0; + +merge: + /* try to merge extents to the right */ + while (nearex < EXT_LAST_EXTENT(eh)) { + if (!ext4_can_extents_be_merged(inode, nearex, nearex + 1)) + break; + /* merge with next extent! */ + nearex->ee_len = cpu_to_le16(le16_to_cpu(nearex->ee_len) + + le16_to_cpu(nearex[1].ee_len)); + if (nearex + 1 < EXT_LAST_EXTENT(eh)) { + len = (EXT_LAST_EXTENT(eh) - nearex - 1) + * sizeof(struct ext4_extent); + memmove(nearex + 1, nearex + 2, len); + } + eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1); + BUG_ON(eh->eh_entries == 0); + } + + /* try to merge extents to the left */ + + /* time to correct all indexes above */ + err = ext4_ext_correct_indexes(handle, inode, path); + if (err) + goto cleanup; + + err = ext4_ext_dirty(handle, inode, path + depth); + +cleanup: + if (npath) { + ext4_ext_drop_refs(npath); + kfree(npath); + } + ext4_ext_tree_changed(inode); + ext4_ext_invalidate_cache(inode); + return err; +} + +int ext4_ext_walk_space(struct inode *inode, unsigned long block, + unsigned long num, ext_prepare_callback func, + void *cbdata) +{ + struct ext4_ext_path *path = NULL; + struct ext4_ext_cache cbex; + struct ext4_extent *ex; + unsigned long next, start = 0, end = 0; + unsigned long last = block + num; + int depth, exists, err = 0; + + BUG_ON(func == NULL); + BUG_ON(inode == NULL); + + while (block < last && block != EXT_MAX_BLOCK) { + num = last - block; + /* find extent for this block */ + path = ext4_ext_find_extent(inode, block, path); + if (IS_ERR(path)) { + err = PTR_ERR(path); + path = NULL; + break; + } + + depth = ext_depth(inode); + BUG_ON(path[depth].p_hdr == NULL); + ex = path[depth].p_ext; + next = ext4_ext_next_allocated_block(path); + + exists = 0; + if (!ex) { + /* there is no extent yet, so try to allocate + * all requested space */ + start = block; + end = block + num; + } else if (le32_to_cpu(ex->ee_block) > block) { + /* need to allocate space before found extent */ + start = block; + end = le32_to_cpu(ex->ee_block); + if (block + num < end) + end = block + num; + } else if (block >= + le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len)) { + /* need to allocate space after found extent */ + start = block; + end = block + num; + if (end >= next) + end = next; + } else if (block >= le32_to_cpu(ex->ee_block)) { + /* + * some part of requested space is covered + * by found extent + */ + start = block; + end = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len); + if (block + num < end) + end = block + num; + exists = 1; + } else { + BUG(); + } + BUG_ON(end <= start); + + if (!exists) { + cbex.ec_block = start; + cbex.ec_len = end - start; + cbex.ec_start = 0; + cbex.ec_type = EXT4_EXT_CACHE_GAP; + } else { + cbex.ec_block = le32_to_cpu(ex->ee_block); + cbex.ec_len = le16_to_cpu(ex->ee_len); + cbex.ec_start = le32_to_cpu(ex->ee_start); + cbex.ec_type = EXT4_EXT_CACHE_EXTENT; + } + + BUG_ON(cbex.ec_len == 0); + err = func(inode, path, &cbex, cbdata); + ext4_ext_drop_refs(path); + + if (err < 0) + break; + if (err == EXT_REPEAT) + continue; + else if (err == EXT_BREAK) { + err = 0; + break; + } + + if (ext_depth(inode) != depth) { + /* depth was changed. we have to realloc path */ + kfree(path); + path = NULL; + } + + block = cbex.ec_block + cbex.ec_len; + } + + if (path) { + ext4_ext_drop_refs(path); + kfree(path); + } + + return err; +} + +static inline void +ext4_ext_put_in_cache(struct inode *inode, __u32 block, + __u32 len, __u32 start, int type) +{ + struct ext4_ext_cache *cex; + BUG_ON(len == 0); + cex = &EXT4_I(inode)->i_cached_extent; + cex->ec_type = type; + cex->ec_block = block; + cex->ec_len = len; + cex->ec_start = start; +} + +/* + * this routine calculate boundaries of the gap requested block fits into + * and cache this gap + */ +static inline void +ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path, + unsigned long block) +{ + int depth = ext_depth(inode); + unsigned long lblock, len; + struct ext4_extent *ex; + + ex = path[depth].p_ext; + if (ex == NULL) { + /* there is no extent yet, so gap is [0;-] */ + lblock = 0; + len = EXT_MAX_BLOCK; + ext_debug("cache gap(whole file):"); + } else if (block < le32_to_cpu(ex->ee_block)) { + lblock = block; + len = le32_to_cpu(ex->ee_block) - block; + ext_debug("cache gap(before): %lu [%lu:%lu]", + (unsigned long) block, + (unsigned long) le32_to_cpu(ex->ee_block), + (unsigned long) le16_to_cpu(ex->ee_len)); + } else if (block >= le32_to_cpu(ex->ee_block) + + le16_to_cpu(ex->ee_len)) { + lblock = le32_to_cpu(ex->ee_block) + + le16_to_cpu(ex->ee_len); + len = ext4_ext_next_allocated_block(path); + ext_debug("cache gap(after): [%lu:%lu] %lu", + (unsigned long) le32_to_cpu(ex->ee_block), + (unsigned long) le16_to_cpu(ex->ee_len), + (unsigned long) block); + BUG_ON(len == lblock); + len = len - lblock; + } else { + lblock = len = 0; + BUG(); + } + + ext_debug(" -> %lu:%lu\n", (unsigned long) lblock, len); + ext4_ext_put_in_cache(inode, lblock, len, 0, EXT4_EXT_CACHE_GAP); +} + +static inline int +ext4_ext_in_cache(struct inode *inode, unsigned long block, + struct ext4_extent *ex) +{ + struct ext4_ext_cache *cex; + + cex = &EXT4_I(inode)->i_cached_extent; + + /* has cache valid data? */ + if (cex->ec_type == EXT4_EXT_CACHE_NO) + return EXT4_EXT_CACHE_NO; + + BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP && + cex->ec_type != EXT4_EXT_CACHE_EXTENT); + if (block >= cex->ec_block && block < cex->ec_block + cex->ec_len) { + ex->ee_block = cpu_to_le32(cex->ec_block); + ex->ee_start = cpu_to_le32(cex->ec_start); + ex->ee_len = cpu_to_le16(cex->ec_len); + ext_debug("%lu cached by %lu:%lu:%lu\n", + (unsigned long) block, + (unsigned long) cex->ec_block, + (unsigned long) cex->ec_len, + (unsigned long) cex->ec_start); + return cex->ec_type; + } + + /* not in cache */ + return EXT4_EXT_CACHE_NO; +} + +/* + * routine removes index from the index block + * it's used in truncate case only. thus all requests are for + * last index in the block only + */ +int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path) +{ + struct buffer_head *bh; + int err; + unsigned long leaf; + + /* free index block */ + path--; + leaf = le32_to_cpu(path->p_idx->ei_leaf); + BUG_ON(path->p_hdr->eh_entries == 0); + if ((err = ext4_ext_get_access(handle, inode, path))) + return err; + path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1); + if ((err = ext4_ext_dirty(handle, inode, path))) + return err; + ext_debug("index is empty, remove it, free block %lu\n", leaf); + bh = sb_find_get_block(inode->i_sb, leaf); + ext4_forget(handle, 1, inode, bh, leaf); + ext4_free_blocks(handle, inode, leaf, 1); + return err; +} + +/* + * This routine returns max. credits extent tree can consume. + * It should be OK for low-performance paths like ->writepage() + * To allow many writing process to fit a single transaction, + * caller should calculate credits under truncate_mutex and + * pass actual path. + */ +int inline ext4_ext_calc_credits_for_insert(struct inode *inode, + struct ext4_ext_path *path) +{ + int depth, needed; + + if (path) { + /* probably there is space in leaf? */ + depth = ext_depth(inode); + if (le16_to_cpu(path[depth].p_hdr->eh_entries) + < le16_to_cpu(path[depth].p_hdr->eh_max)) + return 1; + } + + /* + * given 32bit logical block (4294967296 blocks), max. tree + * can be 4 levels in depth -- 4 * 340^4 == 53453440000. + * let's also add one more level for imbalance. + */ + depth = 5; + + /* allocation of new data block(s) */ + needed = 2; + + /* + * tree can be full, so it'd need to grow in depth: + * allocation + old root + new root + */ + needed += 2 + 1 + 1; + + /* + * Index split can happen, we'd need: + * allocate intermediate indexes (bitmap + group) + * + change two blocks at each level, but root (already included) + */ + needed = (depth * 2) + (depth * 2); + + /* any allocation modifies superblock */ + needed += 1; + + return needed; +} + +static int ext4_remove_blocks(handle_t *handle, struct inode *inode, + struct ext4_extent *ex, + unsigned long from, unsigned long to) +{ + struct buffer_head *bh; + int i; + +#ifdef EXTENTS_STATS + { + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + unsigned short ee_len = le16_to_cpu(ex->ee_len); + spin_lock(&sbi->s_ext_stats_lock); + sbi->s_ext_blocks += ee_len; + sbi->s_ext_extents++; + if (ee_len < sbi->s_ext_min) + sbi->s_ext_min = ee_len; + if (ee_len > sbi->s_ext_max) + sbi->s_ext_max = ee_len; + if (ext_depth(inode) > sbi->s_depth_max) + sbi->s_depth_max = ext_depth(inode); + spin_unlock(&sbi->s_ext_stats_lock); + } +#endif + if (from >= le32_to_cpu(ex->ee_block) + && to == le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) { + /* tail removal */ + unsigned long num, start; + num = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - from; + start = le32_to_cpu(ex->ee_start) + le16_to_cpu(ex->ee_len) - num; + ext_debug("free last %lu blocks starting %lu\n", num, start); + for (i = 0; i < num; i++) { + bh = sb_find_get_block(inode->i_sb, start + i); + ext4_forget(handle, 0, inode, bh, start + i); + } + ext4_free_blocks(handle, inode, start, num); + } else if (from == le32_to_cpu(ex->ee_block) + && to <= le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) { + printk("strange request: removal %lu-%lu from %u:%u\n", + from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len)); + } else { + printk("strange request: removal(2) %lu-%lu from %u:%u\n", + from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len)); + } + return 0; +} + +static int +ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, + struct ext4_ext_path *path, unsigned long start) +{ + int err = 0, correct_index = 0; + int depth = ext_depth(inode), credits; + struct ext4_extent_header *eh; + unsigned a, b, block, num; + unsigned long ex_ee_block; + unsigned short ex_ee_len; + struct ext4_extent *ex; + + ext_debug("truncate since %lu in leaf\n", start); + if (!path[depth].p_hdr) + path[depth].p_hdr = ext_block_hdr(path[depth].p_bh); + eh = path[depth].p_hdr; + BUG_ON(eh == NULL); + BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max)); + BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC); + + /* find where to start removing */ + ex = EXT_LAST_EXTENT(eh); + + ex_ee_block = le32_to_cpu(ex->ee_block); + ex_ee_len = le16_to_cpu(ex->ee_len); + + while (ex >= EXT_FIRST_EXTENT(eh) && + ex_ee_block + ex_ee_len > start) { + ext_debug("remove ext %lu:%u\n", ex_ee_block, ex_ee_len); + path[depth].p_ext = ex; + + a = ex_ee_block > start ? ex_ee_block : start; + b = ex_ee_block + ex_ee_len - 1 < EXT_MAX_BLOCK ? + ex_ee_block + ex_ee_len - 1 : EXT_MAX_BLOCK; + + ext_debug(" border %u:%u\n", a, b); + + if (a != ex_ee_block && b != ex_ee_block + ex_ee_len - 1) { + block = 0; + num = 0; + BUG(); + } else if (a != ex_ee_block) { + /* remove tail of the extent */ + block = ex_ee_block; + num = a - block; + } else if (b != ex_ee_block + ex_ee_len - 1) { + /* remove head of the extent */ + block = a; + num = b - a; + /* there is no "make a hole" API yet */ + BUG(); + } else { + /* remove whole extent: excellent! */ + block = ex_ee_block; + num = 0; + BUG_ON(a != ex_ee_block); + BUG_ON(b != ex_ee_block + ex_ee_len - 1); + } + + /* at present, extent can't cross block group */ + /* leaf + bitmap + group desc + sb + inode */ + credits = 5; + if (ex == EXT_FIRST_EXTENT(eh)) { + correct_index = 1; + credits += (ext_depth(inode)) + 1; + } +#ifdef CONFIG_QUOTA + credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); +#endif + + handle = ext4_ext_journal_restart(handle, credits); + if (IS_ERR(handle)) { + err = PTR_ERR(handle); + goto out; + } + + err = ext4_ext_get_access(handle, inode, path + depth); + if (err) + goto out; + + err = ext4_remove_blocks(handle, inode, ex, a, b); + if (err) + goto out; + + if (num == 0) { + /* this extent is removed entirely mark slot unused */ + ex->ee_start = 0; + eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1); + } + + ex->ee_block = cpu_to_le32(block); + ex->ee_len = cpu_to_le16(num); + + err = ext4_ext_dirty(handle, inode, path + depth); + if (err) + goto out; + + ext_debug("new extent: %u:%u:%u\n", block, num, + le32_to_cpu(ex->ee_start)); + ex--; + ex_ee_block = le32_to_cpu(ex->ee_block); + ex_ee_len = le16_to_cpu(ex->ee_len); + } + + if (correct_index && eh->eh_entries) + err = ext4_ext_correct_indexes(handle, inode, path); + + /* if this leaf is free, then we should + * remove it from index block above */ + if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL) + err = ext4_ext_rm_idx(handle, inode, path + depth); + +out: + return err; +} + +/* + * returns 1 if current index have to be freed (even partial) + */ +static int inline +ext4_ext_more_to_rm(struct ext4_ext_path *path) +{ + BUG_ON(path->p_idx == NULL); + + if (path->p_idx < EXT_FIRST_INDEX(path->p_hdr)) + return 0; + + /* + * if truncate on deeper level happened it it wasn't partial + * so we have to consider current index for truncation + */ + if (le16_to_cpu(path->p_hdr->eh_entries) == path->p_block) + return 0; + return 1; +} + +int ext4_ext_remove_space(struct inode *inode, unsigned long start) +{ + struct super_block *sb = inode->i_sb; + int depth = ext_depth(inode); + struct ext4_ext_path *path; + handle_t *handle; + int i = 0, err = 0; + + ext_debug("truncate since %lu\n", start); + + /* probably first extent we're gonna free will be last in block */ + handle = ext4_journal_start(inode, depth + 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + ext4_ext_invalidate_cache(inode); + + /* + * we start scanning from right side freeing all the blocks + * after i_size and walking into the deep + */ + path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL); + if (path == NULL) { + ext4_journal_stop(handle); + return -ENOMEM; + } + memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1)); + path[0].p_hdr = ext_inode_hdr(inode); + if (ext4_ext_check_header(__FUNCTION__, inode, path[0].p_hdr)) { + err = -EIO; + goto out; + } + path[0].p_depth = depth; + + while (i >= 0 && err == 0) { + if (i == depth) { + /* this is leaf block */ + err = ext4_ext_rm_leaf(handle, inode, path, start); + /* root level have p_bh == NULL, brelse() eats this */ + brelse(path[i].p_bh); + path[i].p_bh = NULL; + i--; + continue; + } + + /* this is index block */ + if (!path[i].p_hdr) { + ext_debug("initialize header\n"); + path[i].p_hdr = ext_block_hdr(path[i].p_bh); + if (ext4_ext_check_header(__FUNCTION__, inode, + path[i].p_hdr)) { + err = -EIO; + goto out; + } + } + + BUG_ON(le16_to_cpu(path[i].p_hdr->eh_entries) + > le16_to_cpu(path[i].p_hdr->eh_max)); + BUG_ON(path[i].p_hdr->eh_magic != EXT4_EXT_MAGIC); + + if (!path[i].p_idx) { + /* this level hasn't touched yet */ + path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr); + path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries)+1; + ext_debug("init index ptr: hdr 0x%p, num %d\n", + path[i].p_hdr, + le16_to_cpu(path[i].p_hdr->eh_entries)); + } else { + /* we've already was here, see at next index */ + path[i].p_idx--; + } + + ext_debug("level %d - index, first 0x%p, cur 0x%p\n", + i, EXT_FIRST_INDEX(path[i].p_hdr), + path[i].p_idx); + if (ext4_ext_more_to_rm(path + i)) { + /* go to the next level */ + ext_debug("move to level %d (block %d)\n", + i + 1, le32_to_cpu(path[i].p_idx->ei_leaf)); + memset(path + i + 1, 0, sizeof(*path)); + path[i+1].p_bh = + sb_bread(sb, le32_to_cpu(path[i].p_idx->ei_leaf)); + if (!path[i+1].p_bh) { + /* should we reset i_size? */ + err = -EIO; + break; + } + + /* put actual number of indexes to know is this + * number got changed at the next iteration */ + path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries); + i++; + } else { + /* we finish processing this index, go up */ + if (path[i].p_hdr->eh_entries == 0 && i > 0) { + /* index is empty, remove it + * handle must be already prepared by the + * truncatei_leaf() */ + err = ext4_ext_rm_idx(handle, inode, path + i); + } + /* root level have p_bh == NULL, brelse() eats this */ + brelse(path[i].p_bh); + path[i].p_bh = NULL; + i--; + ext_debug("return to level %d\n", i); + } + } + + /* TODO: flexible tree reduction should be here */ + if (path->p_hdr->eh_entries == 0) { + /* + * truncate to zero freed all the tree + * so, we need to correct eh_depth + */ + err = ext4_ext_get_access(handle, inode, path); + if (err == 0) { + ext_inode_hdr(inode)->eh_depth = 0; + ext_inode_hdr(inode)->eh_max = + cpu_to_le16(ext4_ext_space_root(inode)); + err = ext4_ext_dirty(handle, inode, path); + } + } +out: + ext4_ext_tree_changed(inode); + ext4_ext_drop_refs(path); + kfree(path); + ext4_journal_stop(handle); + + return err; +} + +/* + * called at mount time + */ +void ext4_ext_init(struct super_block *sb) +{ + /* + * possible initialization would be here + */ + + if (test_opt(sb, EXTENTS)) { + printk("EXT4-fs: file extents enabled"); +#ifdef AGRESSIVE_TEST + printk(", agressive tests"); +#endif +#ifdef CHECK_BINSEARCH + printk(", check binsearch"); +#endif +#ifdef EXTENTS_STATS + printk(", stats"); +#endif + printk("\n"); +#ifdef EXTENTS_STATS + spin_lock_init(&EXT4_SB(sb)->s_ext_stats_lock); + EXT4_SB(sb)->s_ext_min = 1 << 30; + EXT4_SB(sb)->s_ext_max = 0; +#endif + } +} + +/* + * called at umount time + */ +void ext4_ext_release(struct super_block *sb) +{ + if (!test_opt(sb, EXTENTS)) + return; + +#ifdef EXTENTS_STATS + if (EXT4_SB(sb)->s_ext_blocks && EXT4_SB(sb)->s_ext_extents) { + struct ext4_sb_info *sbi = EXT4_SB(sb); + printk(KERN_ERR "EXT4-fs: %lu blocks in %lu extents (%lu ave)\n", + sbi->s_ext_blocks, sbi->s_ext_extents, + sbi->s_ext_blocks / sbi->s_ext_extents); + printk(KERN_ERR "EXT4-fs: extents: %lu min, %lu max, max depth %lu\n", + sbi->s_ext_min, sbi->s_ext_max, sbi->s_depth_max); + } +#endif +} + +int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, sector_t iblock, + unsigned long max_blocks, struct buffer_head *bh_result, + int create, int extend_disksize) +{ + struct ext4_ext_path *path = NULL; + struct ext4_extent newex, *ex; + int goal, newblock, err = 0, depth; + unsigned long allocated = 0; + + __clear_bit(BH_New, &bh_result->b_state); + ext_debug("blocks %d/%lu requested for inode %u\n", (int) iblock, + max_blocks, (unsigned) inode->i_ino); + mutex_lock(&EXT4_I(inode)->truncate_mutex); + + /* check in cache */ + if ((goal = ext4_ext_in_cache(inode, iblock, &newex))) { + if (goal == EXT4_EXT_CACHE_GAP) { + if (!create) { + /* block isn't allocated yet and + * user don't want to allocate it */ + goto out2; + } + /* we should allocate requested block */ + } else if (goal == EXT4_EXT_CACHE_EXTENT) { + /* block is already allocated */ + newblock = iblock + - le32_to_cpu(newex.ee_block) + + le32_to_cpu(newex.ee_start); + /* number of remain blocks in the extent */ + allocated = le16_to_cpu(newex.ee_len) - + (iblock - le32_to_cpu(newex.ee_block)); + goto out; + } else { + BUG(); + } + } + + /* find extent for this block */ + path = ext4_ext_find_extent(inode, iblock, NULL); + if (IS_ERR(path)) { + err = PTR_ERR(path); + path = NULL; + goto out2; + } + + depth = ext_depth(inode); + + /* + * consistent leaf must not be empty + * this situations is possible, though, _during_ tree modification + * this is why assert can't be put in ext4_ext_find_extent() + */ + BUG_ON(path[depth].p_ext == NULL && depth != 0); + + if ((ex = path[depth].p_ext)) { + unsigned long ee_block = le32_to_cpu(ex->ee_block); + unsigned long ee_start = le32_to_cpu(ex->ee_start); + unsigned short ee_len = le16_to_cpu(ex->ee_len); + /* if found exent covers block, simple return it */ + if (iblock >= ee_block && iblock < ee_block + ee_len) { + newblock = iblock - ee_block + ee_start; + /* number of remain blocks in the extent */ + allocated = ee_len - (iblock - ee_block); + ext_debug("%d fit into %lu:%d -> %d\n", (int) iblock, + ee_block, ee_len, newblock); + ext4_ext_put_in_cache(inode, ee_block, ee_len, + ee_start, EXT4_EXT_CACHE_EXTENT); + goto out; + } + } + + /* + * requested block isn't allocated yet + * we couldn't try to create block if create flag is zero + */ + if (!create) { + /* put just found gap into cache to speedup subsequest reqs */ + ext4_ext_put_gap_in_cache(inode, path, iblock); + goto out2; + } + /* + * Okay, we need to do block allocation. Lazily initialize the block + * allocation info here if necessary + */ + if (S_ISREG(inode->i_mode) && (!EXT4_I(inode)->i_block_alloc_info)) + ext4_init_block_alloc_info(inode); + + /* allocate new block */ + goal = ext4_ext_find_goal(inode, path, iblock); + allocated = max_blocks; + newblock = ext4_new_blocks(handle, inode, goal, &allocated, &err); + if (!newblock) + goto out2; + ext_debug("allocate new block: goal %d, found %d/%lu\n", + goal, newblock, allocated); + + /* try to insert new extent into found leaf and return */ + newex.ee_block = cpu_to_le32(iblock); + newex.ee_start = cpu_to_le32(newblock); + newex.ee_len = cpu_to_le16(allocated); + err = ext4_ext_insert_extent(handle, inode, path, &newex); + if (err) + goto out2; + + if (extend_disksize && inode->i_size > EXT4_I(inode)->i_disksize) + EXT4_I(inode)->i_disksize = inode->i_size; + + /* previous routine could use block we allocated */ + newblock = le32_to_cpu(newex.ee_start); + __set_bit(BH_New, &bh_result->b_state); + + ext4_ext_put_in_cache(inode, iblock, allocated, newblock, + EXT4_EXT_CACHE_EXTENT); +out: + if (allocated > max_blocks) + allocated = max_blocks; + ext4_ext_show_leaf(inode, path); + __set_bit(BH_Mapped, &bh_result->b_state); + bh_result->b_bdev = inode->i_sb->s_bdev; + bh_result->b_blocknr = newblock; +out2: + if (path) { + ext4_ext_drop_refs(path); + kfree(path); + } + mutex_unlock(&EXT4_I(inode)->truncate_mutex); + + return err ? err : allocated; +} + +void ext4_ext_truncate(struct inode * inode, struct page *page) +{ + struct address_space *mapping = inode->i_mapping; + struct super_block *sb = inode->i_sb; + unsigned long last_block; + handle_t *handle; + int err = 0; + + /* + * probably first extent we're gonna free will be last in block + */ + err = ext4_writepage_trans_blocks(inode) + 3; + handle = ext4_journal_start(inode, err); + if (IS_ERR(handle)) { + if (page) { + clear_highpage(page); + flush_dcache_page(page); + unlock_page(page); + page_cache_release(page); + } + return; + } + + if (page) + ext4_block_truncate_page(handle, page, mapping, inode->i_size); + + mutex_lock(&EXT4_I(inode)->truncate_mutex); + ext4_ext_invalidate_cache(inode); + + /* + * TODO: optimization is possible here + * probably we need not scaning at all, + * because page truncation is enough + */ + if (ext4_orphan_add(handle, inode)) + goto out_stop; + + /* we have to know where to truncate from in crash case */ + EXT4_I(inode)->i_disksize = inode->i_size; + ext4_mark_inode_dirty(handle, inode); + + last_block = (inode->i_size + sb->s_blocksize - 1) + >> EXT4_BLOCK_SIZE_BITS(sb); + err = ext4_ext_remove_space(inode, last_block); + + /* In a multi-transaction truncate, we only make the final + * transaction synchronous */ + if (IS_SYNC(inode)) + handle->h_sync = 1; + +out_stop: + /* + * If this was a simple ftruncate(), and the file will remain alive + * then we need to clear up the orphan record which we created above. + * However, if this was a real unlink then we were called by + * ext4_delete_inode(), and we allow that function to clean up the + * orphan info for us. + */ + if (inode->i_nlink) + ext4_orphan_del(handle, inode); + + mutex_unlock(&EXT4_I(inode)->truncate_mutex); + ext4_journal_stop(handle); +} + +/* + * this routine calculate max number of blocks we could modify + * in order to allocate new block for an inode + */ +int ext4_ext_writepage_trans_blocks(struct inode *inode, int num) +{ + int needed; + + needed = ext4_ext_calc_credits_for_insert(inode, NULL); + + /* caller want to allocate num blocks, but note it includes sb */ + needed = needed * num - (num - 1); + +#ifdef CONFIG_QUOTA + needed += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); +#endif + + return needed; +} + +EXPORT_SYMBOL(ext4_mark_inode_dirty); +EXPORT_SYMBOL(ext4_ext_invalidate_cache); +EXPORT_SYMBOL(ext4_ext_insert_extent); +EXPORT_SYMBOL(ext4_ext_walk_space); +EXPORT_SYMBOL(ext4_ext_find_goal); +EXPORT_SYMBOL(ext4_ext_calc_credits_for_insert); + diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 34d39ae966f7..e17a6c918d72 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -615,6 +615,17 @@ got: ext4_std_error(sb, err); goto fail_free_drop; } + if (test_opt(sb, EXTENTS)) { + EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL; + ext4_ext_tree_init(handle, inode); + if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) { + err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); + if (err) goto fail; + EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS); + BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); + } + } ext4_debug("allocating inode %lu\n", inode->i_ino); goto really_out; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 0d96c7d3bb5b..2b81b1324a6f 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -40,8 +40,6 @@ #include "xattr.h" #include "acl.h" -static int ext4_writepage_trans_blocks(struct inode *inode); - /* * Test whether an inode is a fast symlink. */ @@ -804,6 +802,7 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, ext4_fsblk_t first_block = 0; + J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)); J_ASSERT(handle != NULL || create == 0); depth = ext4_block_to_path(inode,iblock,offsets,&blocks_to_boundary); @@ -984,7 +983,7 @@ static int ext4_get_block(struct inode *inode, sector_t iblock, get_block: if (ret == 0) { - ret = ext4_get_blocks_handle(handle, inode, iblock, + ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks, bh_result, create, 0); if (ret > 0) { bh_result->b_size = (ret << inode->i_blkbits); @@ -1008,7 +1007,7 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, dummy.b_state = 0; dummy.b_blocknr = -1000; buffer_trace_init(&dummy.b_history); - err = ext4_get_blocks_handle(handle, inode, block, 1, + err = ext4_get_blocks_wrap(handle, inode, block, 1, &dummy, create, 1); /* * ext4_get_blocks_handle() returns number of blocks @@ -1759,7 +1758,7 @@ void ext4_set_aops(struct inode *inode) * This required during truncate. We need to physically zero the tail end * of that block so it doesn't yield old data if the file is later grown. */ -static int ext4_block_truncate_page(handle_t *handle, struct page *page, +int ext4_block_truncate_page(handle_t *handle, struct page *page, struct address_space *mapping, loff_t from) { ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT; @@ -2263,6 +2262,9 @@ void ext4_truncate(struct inode *inode) return; } + if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) + return ext4_ext_truncate(inode, page); + handle = start_transaction(inode); if (IS_ERR(handle)) { if (page) { @@ -3003,12 +3005,15 @@ err_out: * block and work out the exact number of indirects which are touched. Pah. */ -static int ext4_writepage_trans_blocks(struct inode *inode) +int ext4_writepage_trans_blocks(struct inode *inode) { int bpp = ext4_journal_blocks_per_page(inode); int indirects = (EXT4_NDIR_BLOCKS % bpp) ? 5 : 3; int ret; + if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) + return ext4_ext_writepage_trans_blocks(inode, bpp); + if (ext4_should_journal_data(inode)) ret = 3 * (bpp + indirects) + 2; else diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index a63dce2117b8..22a737c306c7 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -248,7 +248,6 @@ flags_err: return err; } - default: return -ENOTTY; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index f131bb69b62e..69f875250500 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -390,6 +390,7 @@ static void ext4_put_super (struct super_block * sb) struct ext4_super_block *es = sbi->s_es; int i; + ext4_ext_release(sb); ext4_xattr_put_super(sb); jbd2_journal_destroy(sbi->s_journal); if (!(sb->s_flags & MS_RDONLY)) { @@ -454,6 +455,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) #endif ei->i_block_alloc_info = NULL; ei->vfs_inode.i_version = 1; + memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); return &ei->vfs_inode; } @@ -677,7 +679,7 @@ enum { Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota, - Opt_grpquota + Opt_grpquota, Opt_extents, }; static match_table_t tokens = { @@ -727,6 +729,7 @@ static match_table_t tokens = { {Opt_quota, "quota"}, {Opt_usrquota, "usrquota"}, {Opt_barrier, "barrier=%u"}, + {Opt_extents, "extents"}, {Opt_err, NULL}, {Opt_resize, "resize"}, }; @@ -1059,6 +1062,9 @@ clear_qf_name: case Opt_bh: clear_opt(sbi->s_mount_opt, NOBH); break; + case Opt_extents: + set_opt (sbi->s_mount_opt, EXTENTS); + break; default: printk (KERN_ERR "EXT4-fs: Unrecognized mount option \"%s\" " @@ -1787,6 +1793,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) test_opt(sb,DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered": "writeback"); + ext4_ext_init(sb); + lock_kernel(); return 0; diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index f582cd762caf..b61181aadcbb 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -178,8 +178,9 @@ struct ext4_group_desc #define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ #define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ +#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ -#define EXT4_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ +#define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */ #define EXT4_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ /* @@ -384,6 +385,7 @@ struct ext4_inode { #define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */ #define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */ #define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ +#define EXT4_MOUNT_EXTENTS 0x400000 /* Extents support */ /* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H @@ -582,11 +584,13 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) #define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ #define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ #define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ #define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR #define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ EXT4_FEATURE_INCOMPAT_RECOVER| \ - EXT4_FEATURE_INCOMPAT_META_BG) + EXT4_FEATURE_INCOMPAT_META_BG| \ + EXT4_FEATURE_INCOMPAT_EXTENTS) #define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ EXT4_FEATURE_RO_COMPAT_BTREE_DIR) @@ -825,6 +829,9 @@ extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *); extern void ext4_truncate (struct inode *); extern void ext4_set_inode_flags(struct inode *); extern void ext4_set_aops(struct inode *inode); +extern int ext4_writepage_trans_blocks(struct inode *); +extern int ext4_block_truncate_page(handle_t *handle, struct page *page, + struct address_space *mapping, loff_t from); /* ioctl.c */ extern int ext4_ioctl (struct inode *, struct file *, unsigned int, @@ -879,6 +886,28 @@ extern struct inode_operations ext4_special_inode_operations; extern struct inode_operations ext4_symlink_inode_operations; extern struct inode_operations ext4_fast_symlink_inode_operations; +/* extents.c */ +extern int ext4_ext_tree_init(handle_t *handle, struct inode *); +extern int ext4_ext_writepage_trans_blocks(struct inode *, int); +extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, + ext4_fsblk_t iblock, + unsigned long max_blocks, struct buffer_head *bh_result, + int create, int extend_disksize); +extern void ext4_ext_truncate(struct inode *, struct page *); +extern void ext4_ext_init(struct super_block *); +extern void ext4_ext_release(struct super_block *); +static inline int +ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block, + unsigned long max_blocks, struct buffer_head *bh, + int create, int extend_disksize) +{ + if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) + return ext4_ext_get_blocks(handle, inode, block, max_blocks, + bh, create, extend_disksize); + return ext4_get_blocks_handle(handle, inode, block, max_blocks, bh, + create, extend_disksize); +} + #endif /* __KERNEL__ */ diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h new file mode 100644 index 000000000000..8029879e29e2 --- /dev/null +++ b/include/linux/ext4_fs_extents.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com + * Written by Alex Tomas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public Licens + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- + */ + +#ifndef _LINUX_EXT4_EXTENTS +#define _LINUX_EXT4_EXTENTS + +#include + +/* + * with AGRESSIVE_TEST defined capacity of index/leaf blocks + * become very little, so index split, in-depth growing and + * other hard changes happens much more often + * this is for debug purposes only + */ +#define AGRESSIVE_TEST_ + +/* + * with EXTENTS_STATS defined number of blocks and extents + * are collected in truncate path. they'll be showed at + * umount time + */ +#define EXTENTS_STATS__ + +/* + * if CHECK_BINSEARCH defined, then results of binary search + * will be checked by linear search + */ +#define CHECK_BINSEARCH__ + +/* + * if EXT_DEBUG is defined you can use 'extdebug' mount option + * to get lots of info what's going on + */ +#define EXT_DEBUG__ +#ifdef EXT_DEBUG +#define ext_debug(a...) printk(a) +#else +#define ext_debug(a...) +#endif + +/* + * if EXT_STATS is defined then stats numbers are collected + * these number will be displayed at umount time + */ +#define EXT_STATS_ + + +/* + * ext4_inode has i_block array (60 bytes total) + * first 12 bytes store ext4_extent_header + * the remain stores array of ext4_extent + */ + +/* + * this is extent on-disk structure + * it's used at the bottom of the tree + */ +struct ext4_extent { + __le32 ee_block; /* first logical block extent covers */ + __le16 ee_len; /* number of blocks covered by extent */ + __le16 ee_start_hi; /* high 16 bits of physical block */ + __le32 ee_start; /* low 32 bigs of physical block */ +}; + +/* + * this is index on-disk structure + * it's used at all the levels, but the bottom + */ +struct ext4_extent_idx { + __le32 ei_block; /* index covers logical blocks from 'block' */ + __le32 ei_leaf; /* pointer to the physical block of the next * + * level. leaf or next index could bet here */ + __le16 ei_leaf_hi; /* high 16 bits of physical block */ + __u16 ei_unused; +}; + +/* + * each block (leaves and indexes), even inode-stored has header + */ +struct ext4_extent_header { + __le16 eh_magic; /* probably will support different formats */ + __le16 eh_entries; /* number of valid entries */ + __le16 eh_max; /* capacity of store in entries */ + __le16 eh_depth; /* has tree real underlaying blocks? */ + __le32 eh_generation; /* generation of the tree */ +}; + +#define EXT4_EXT_MAGIC cpu_to_le16(0xf30a) + +/* + * array of ext4_ext_path contains path to some extent + * creation/lookup routines use it for traversal/splitting/etc + * truncate uses it to simulate recursive walking + */ +struct ext4_ext_path { + __u32 p_block; + __u16 p_depth; + struct ext4_extent *p_ext; + struct ext4_extent_idx *p_idx; + struct ext4_extent_header *p_hdr; + struct buffer_head *p_bh; +}; + +/* + * structure for external API + */ + +#define EXT4_EXT_CACHE_NO 0 +#define EXT4_EXT_CACHE_GAP 1 +#define EXT4_EXT_CACHE_EXTENT 2 + +/* + * to be called by ext4_ext_walk_space() + * negative retcode - error + * positive retcode - signal for ext4_ext_walk_space(), see below + * callback must return valid extent (passed or newly created) + */ +typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *, + struct ext4_ext_cache *, + void *); + +#define EXT_CONTINUE 0 +#define EXT_BREAK 1 +#define EXT_REPEAT 2 + + +#define EXT_MAX_BLOCK 0xffffffff + + +#define EXT_FIRST_EXTENT(__hdr__) \ + ((struct ext4_extent *) (((char *) (__hdr__)) + \ + sizeof(struct ext4_extent_header))) +#define EXT_FIRST_INDEX(__hdr__) \ + ((struct ext4_extent_idx *) (((char *) (__hdr__)) + \ + sizeof(struct ext4_extent_header))) +#define EXT_HAS_FREE_INDEX(__path__) \ + (le16_to_cpu((__path__)->p_hdr->eh_entries) \ + < le16_to_cpu((__path__)->p_hdr->eh_max)) +#define EXT_LAST_EXTENT(__hdr__) \ + (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1) +#define EXT_LAST_INDEX(__hdr__) \ + (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1) +#define EXT_MAX_EXTENT(__hdr__) \ + (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1) +#define EXT_MAX_INDEX(__hdr__) \ + (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1) + +static inline struct ext4_extent_header *ext_inode_hdr(struct inode *inode) +{ + return (struct ext4_extent_header *) EXT4_I(inode)->i_data; +} + +static inline struct ext4_extent_header *ext_block_hdr(struct buffer_head *bh) +{ + return (struct ext4_extent_header *) bh->b_data; +} + +static inline unsigned short ext_depth(struct inode *inode) +{ + return le16_to_cpu(ext_inode_hdr(inode)->eh_depth); +} + +static inline void ext4_ext_tree_changed(struct inode *inode) +{ + EXT4_I(inode)->i_ext_generation++; +} + +static inline void +ext4_ext_invalidate_cache(struct inode *inode) +{ + EXT4_I(inode)->i_cached_extent.ec_type = EXT4_EXT_CACHE_NO; +} + +extern int ext4_extent_tree_init(handle_t *, struct inode *); +extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *); +extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *); +extern int ext4_ext_walk_space(struct inode *, unsigned long, unsigned long, ext_prepare_callback, void *); +extern struct ext4_ext_path * ext4_ext_find_extent(struct inode *, int, struct ext4_ext_path *); + +#endif /* _LINUX_EXT4_EXTENTS */ + diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h index 18a6ce98537f..40ce04a52b04 100644 --- a/include/linux/ext4_fs_i.h +++ b/include/linux/ext4_fs_i.h @@ -64,6 +64,16 @@ struct ext4_block_alloc_info { #define rsv_start rsv_window._rsv_start #define rsv_end rsv_window._rsv_end +/* + * storage for cached extent + */ +struct ext4_ext_cache { + __u32 ec_start; + __u32 ec_block; + __u32 ec_len; /* must be 32bit to return holes */ + __u32 ec_type; +}; + /* * third extended file system inode data in memory */ @@ -142,6 +152,9 @@ struct ext4_inode_info { */ struct mutex truncate_mutex; struct inode vfs_inode; + + unsigned long i_ext_generation; + struct ext4_ext_cache i_cached_extent; }; #endif /* _LINUX_EXT4_FS_I */ diff --git a/include/linux/ext4_fs_sb.h b/include/linux/ext4_fs_sb.h index ce4856d70100..ce7a844d6703 100644 --- a/include/linux/ext4_fs_sb.h +++ b/include/linux/ext4_fs_sb.h @@ -78,6 +78,16 @@ struct ext4_sb_info { char *s_qf_names[MAXQUOTAS]; /* Names of quota files with journalled quota */ int s_jquota_fmt; /* Format of quota to use */ #endif + +#ifdef EXTENTS_STATS + /* ext4 extents stats */ + unsigned long s_ext_min; + unsigned long s_ext_max; + unsigned long s_depth_max; + spinlock_t s_ext_stats_lock; + unsigned long s_ext_blocks; + unsigned long s_ext_extents; +#endif }; #endif /* _LINUX_EXT4_FS_SB */ diff --git a/include/linux/ext4_jbd2.h b/include/linux/ext4_jbd2.h index 99d37557cbb4..aa273f024ad0 100644 --- a/include/linux/ext4_jbd2.h +++ b/include/linux/ext4_jbd2.h @@ -26,9 +26,14 @@ * * We may have to touch one inode, one bitmap buffer, up to three * indirection blocks, the group and superblock summaries, and the data - * block to complete the transaction. */ + * block to complete the transaction. + * + * For extents-enabled fs we may have to allocate and modify upto + * 5 levels of tree + root which is stored in inode. */ -#define EXT4_SINGLEDATA_TRANS_BLOCKS 8U +#define EXT4_SINGLEDATA_TRANS_BLOCKS(sb) \ + (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS) \ + || test_opt(sb, EXTENTS) ? 27U : 8U) /* Extended attribute operations touch at most two data buffers, * two bitmap buffers, and two group summaries, in addition to the inode @@ -42,7 +47,7 @@ * superblock only gets updated once, of course, so don't bother * counting that again for the quota updates. */ -#define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS + \ +#define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS(sb) + \ EXT4_XATTR_TRANS_BLOCKS - 2 + \ 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) @@ -78,9 +83,9 @@ /* Amount of blocks needed for quota insert/delete - we do some block writes * but inode, sb and group updates are done only once */ #define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ - (EXT4_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0) + (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_INIT_REWRITE) : 0) #define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ - (EXT4_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0) + (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_DEL_REWRITE) : 0) #else #define EXT4_QUOTA_TRANS_BLOCKS(sb) 0 #define EXT4_QUOTA_INIT_BLOCKS(sb) 0 -- cgit v1.2.3 From 3a5b2ecdd1fa63a8f25bd769223bc1c2564ce45d Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:21:05 -0700 Subject: [PATCH] ext4: switch fsblk to sector_t Redefine ext3 in-kernel filesystem block type (ext3_fsblk_t) from unsigned long to sector_t, to allow kernel to handle >32 bit ext3 blocks. Signed-off-by: Mingming Cao Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/balloc.c | 23 +++++++++-------------- fs/ext4/ialloc.c | 11 +++++++---- fs/ext4/resize.c | 13 ++++++------- fs/ext4/super.c | 8 ++++---- include/linux/ext4_fs.h | 26 ++++++++++++++++++++++++++ include/linux/ext4_fs_i.h | 6 +++++- 6 files changed, 57 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index e9e98449137b..aa33ff271fa9 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -147,7 +147,7 @@ restart: rsv = list_entry(n, struct ext4_reserve_window_node, rsv_node); if (verbose) printk("reservation window 0x%p " - "start: %lu, end: %lu\n", + "start: "E3FSBLK", end: "E3FSBLK"\n", rsv, rsv->rsv_start, rsv->rsv_end); if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) { printk("Bad reservation %p (start >= end)\n", @@ -443,10 +443,7 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, do_more: overflow = 0; - block_group = (block - le32_to_cpu(es->s_first_data_block)) / - EXT4_BLOCKS_PER_GROUP(sb); - bit = (block - le32_to_cpu(es->s_first_data_block)) % - EXT4_BLOCKS_PER_GROUP(sb); + ext4_get_group_no_and_offset(sb, block, &block_group, &bit); /* * Check to see if we are freeing blocks across a group * boundary. @@ -1404,7 +1401,7 @@ ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, { struct buffer_head *bitmap_bh = NULL; struct buffer_head *gdp_bh; - int group_no; + unsigned long group_no; int goal_group; ext4_grpblk_t grp_target_blk; /* blockgroup relative goal block */ ext4_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/ @@ -1467,8 +1464,7 @@ ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, if (goal < le32_to_cpu(es->s_first_data_block) || goal >= le32_to_cpu(es->s_blocks_count)) goal = le32_to_cpu(es->s_first_data_block); - group_no = (goal - le32_to_cpu(es->s_first_data_block)) / - EXT4_BLOCKS_PER_GROUP(sb); + ext4_get_group_no_and_offset(sb, goal, &group_no, &grp_target_blk); goal_group = group_no; retry_alloc: gdp = ext4_get_group_desc(sb, group_no, &gdp_bh); @@ -1485,8 +1481,6 @@ retry_alloc: my_rsv = NULL; if (free_blocks > 0) { - grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) % - EXT4_BLOCKS_PER_GROUP(sb)); bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) goto io_error; @@ -1613,7 +1607,7 @@ allocated: if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) { ext4_error(sb, "ext4_new_block", "block("E3FSBLK") >= blocks count(%d) - " - "block_group = %d, es == %p ", ret_block, + "block_group = %lu, es == %p ", ret_block, le32_to_cpu(es->s_blocks_count), group_no, es); goto out; } @@ -1733,9 +1727,10 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb) static inline int block_in_use(ext4_fsblk_t block, struct super_block *sb, unsigned char *map) { - return ext4_test_bit ((block - - le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) % - EXT4_BLOCKS_PER_GROUP(sb), map); + ext4_grpblk_t offset; + + ext4_get_group_no_and_offset(sb, block, NULL, &offset); + return ext4_test_bit (offset, map); } static inline int test_root(int a, int b) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index e17a6c918d72..94e1bb4abe31 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -23,7 +23,7 @@ #include #include #include - +#include #include #include "xattr.h" @@ -274,7 +274,8 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); avefreei = freei / ngroups; freeb = percpu_counter_read_positive(&sbi->s_freeblocks_counter); - avefreeb = freeb / ngroups; + avefreeb = freeb; + sector_div(avefreeb, ngroups); ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); if ((parent == sb->s_root->d_inode) || @@ -303,13 +304,15 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) goto fallback; } - blocks_per_dir = (le32_to_cpu(es->s_blocks_count) - freeb) / ndirs; + blocks_per_dir = le32_to_cpu(es->s_blocks_count) - freeb; + sector_div(blocks_per_dir, ndirs); max_dirs = ndirs / ngroups + inodes_per_group / 16; min_inodes = avefreei - inodes_per_group / 4; min_blocks = avefreeb - EXT4_BLOCKS_PER_GROUP(sb) / 4; - max_debt = EXT4_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, (ext4_fsblk_t)BLOCK_COST); + max_debt = EXT4_BLOCKS_PER_GROUP(sb); + sector_div(max_debt, max(blocks_per_dir, (ext4_fsblk_t)BLOCK_COST)); if (max_debt * INODE_COST > inodes_per_group) max_debt = inodes_per_group / INODE_COST; if (max_debt > 255) diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 5b2828d21180..c60bfed5f5e7 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -36,7 +36,7 @@ static int verify_group_input(struct super_block *sb, le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; ext4_fsblk_t metaend = start + overhead; struct buffer_head *bh = NULL; - ext4_grpblk_t free_blocks_count; + ext4_grpblk_t free_blocks_count, offset; int err = -EINVAL; input->free_blocks_count = free_blocks_count = @@ -49,13 +49,13 @@ static int verify_group_input(struct super_block *sb, "no-super", input->group, input->blocks_count, free_blocks_count, input->reserved_blocks); + ext4_get_group_no_and_offset(sb, start, NULL, &offset); if (group != sbi->s_groups_count) ext4_warning(sb, __FUNCTION__, "Cannot add at group %u (only %lu groups)", input->group, sbi->s_groups_count); - else if ((start - le32_to_cpu(es->s_first_data_block)) % - EXT4_BLOCKS_PER_GROUP(sb)) - ext4_warning(sb, __FUNCTION__, "Last group not full"); + else if (offset != 0) + ext4_warning(sb, __FUNCTION__, "Last group not full"); else if (input->reserved_blocks > input->blocks_count / 5) ext4_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)", input->reserved_blocks); @@ -945,7 +945,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { printk(KERN_ERR "EXT4-fs: filesystem on %s:" - " too large to resize to %lu blocks safely\n", + " too large to resize to "E3FSBLK" blocks safely\n", sb->s_id, n_blocks_count); if (sizeof(sector_t) < 8) ext4_warning(sb, __FUNCTION__, @@ -960,8 +960,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, } /* Handle the remaining blocks in the last group only. */ - last = (o_blocks_count - le32_to_cpu(es->s_first_data_block)) % - EXT4_BLOCKS_PER_GROUP(sb); + ext4_get_group_no_and_offset(sb, o_blocks_count, NULL, &last); if (last == 0) { ext4_warning(sb, __FUNCTION__, diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 69f875250500..1d12e4f7d69f 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1433,8 +1433,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) * block sizes. We need to calculate the offset from buffer start. */ if (blocksize != EXT4_MIN_BLOCK_SIZE) { - logic_sb_block = (sb_block * EXT4_MIN_BLOCK_SIZE) / blocksize; - offset = (sb_block * EXT4_MIN_BLOCK_SIZE) % blocksize; + logic_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; + offset = sector_div(logic_sb_block, blocksize); } else { logic_sb_block = sb_block; } @@ -1539,8 +1539,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) brelse (bh); sb_set_blocksize(sb, blocksize); - logic_sb_block = (sb_block * EXT4_MIN_BLOCK_SIZE) / blocksize; - offset = (sb_block * EXT4_MIN_BLOCK_SIZE) % blocksize; + logic_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; + offset = sector_div(logic_sb_block, blocksize); bh = sb_bread(sb, logic_sb_block); if (!bh) { printk(KERN_ERR diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index b61181aadcbb..e952c6db9690 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -17,6 +17,7 @@ #define _LINUX_EXT4_FS_H #include +#include #include /* @@ -749,6 +750,27 @@ ext4_group_first_block_no(struct super_block *sb, unsigned long group_no) */ #define ERR_BAD_DX_DIR -75000 +/* + * This function calculate the block group number and offset, + * given a block number + */ + +static inline void ext4_get_group_no_and_offset(struct super_block * sb, + ext4_fsblk_t blocknr, unsigned long* blockgrpp, + ext4_grpblk_t *offsetp) +{ + struct ext4_super_block *es = EXT4_SB(sb)->s_es; + ext4_grpblk_t offset; + + blocknr = blocknr - le32_to_cpu(es->s_first_data_block); + offset = sector_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb)); + if (offsetp) + *offsetp = offset; + if (blockgrpp) + *blockgrpp = blocknr; + +} + /* * Function prototypes */ @@ -762,6 +784,10 @@ ext4_group_first_block_no(struct super_block *sb, unsigned long group_no) # define NORET_AND noreturn, /* balloc.c */ +extern unsigned int ext4_block_group(struct super_block *sb, + ext4_fsblk_t blocknr); +extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb, + ext4_fsblk_t blocknr); extern int ext4_bg_has_super(struct super_block *sb, int group); extern unsigned long ext4_bg_num_gdb(struct super_block *sb, int group); extern ext4_fsblk_t ext4_new_block (handle_t *handle, struct inode *inode, diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h index 40ce04a52b04..b2ccd9876bd1 100644 --- a/include/linux/ext4_fs_i.h +++ b/include/linux/ext4_fs_i.h @@ -25,9 +25,13 @@ typedef int ext4_grpblk_t; /* data type for filesystem-wide blocks number */ -typedef unsigned long ext4_fsblk_t; +typedef sector_t ext4_fsblk_t; +#if BITS_PER_LONG == 64 #define E3FSBLK "%lu" +#else +#define E3FSBLK "%llu" +#endif struct ext4_reserve_window { ext4_fsblk_t _rsv_start; /* First byte reserved */ -- cgit v1.2.3 From f65e6fba163dfd0f962efb7d8f5528b6872e2b15 Mon Sep 17 00:00:00 2001 From: Alex Tomas Date: Wed, 11 Oct 2006 01:21:05 -0700 Subject: [PATCH] ext4: 48bit physical block number support in extents Signed-off-by: Alex Tomas Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/extents.c | 187 ++++++++++++++++++++++++---------------- include/linux/ext4_fs_extents.h | 2 +- include/linux/ext4_fs_i.h | 8 +- 3 files changed, 116 insertions(+), 81 deletions(-) (limited to 'include/linux') diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index f67b2ef6a71f..4a13b56e1540 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -44,6 +44,44 @@ #include +/* this macro combines low and hi parts of phys. blocknr into ext4_fsblk_t */ +static inline ext4_fsblk_t ext_pblock(struct ext4_extent *ex) +{ + ext4_fsblk_t block; + + block = le32_to_cpu(ex->ee_start); + if (sizeof(ext4_fsblk_t) > 4) + block |= ((ext4_fsblk_t) le16_to_cpu(ex->ee_start_hi) << 31) << 1; + return block; +} + +/* this macro combines low and hi parts of phys. blocknr into ext4_fsblk_t */ +static inline ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix) +{ + ext4_fsblk_t block; + + block = le32_to_cpu(ix->ei_leaf); + if (sizeof(ext4_fsblk_t) > 4) + block |= ((ext4_fsblk_t) le16_to_cpu(ix->ei_leaf_hi) << 31) << 1; + return block; +} + +/* the routine stores large phys. blocknr into extent breaking it into parts */ +static inline void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb) +{ + ex->ee_start = cpu_to_le32((unsigned long) (pb & 0xffffffff)); + if (sizeof(ext4_fsblk_t) > 4) + ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff); +} + +/* the routine stores large phys. blocknr into index breaking it into parts */ +static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb) +{ + ix->ei_leaf = cpu_to_le32((unsigned long) (pb & 0xffffffff)); + if (sizeof(ext4_fsblk_t) > 4) + ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff); +} + static int ext4_ext_check_header(const char *function, struct inode *inode, struct ext4_extent_header *eh) { @@ -124,13 +162,13 @@ static int ext4_ext_dirty(handle_t *handle, struct inode *inode, return err; } -static int ext4_ext_find_goal(struct inode *inode, +static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode, struct ext4_ext_path *path, - unsigned long block) + ext4_fsblk_t block) { struct ext4_inode_info *ei = EXT4_I(inode); - unsigned long bg_start; - unsigned long colour; + ext4_fsblk_t bg_start; + ext4_grpblk_t colour; int depth; if (path) { @@ -139,8 +177,7 @@ static int ext4_ext_find_goal(struct inode *inode, /* try to predict block placement */ if ((ex = path[depth].p_ext)) - return le32_to_cpu(ex->ee_start) - + (block - le32_to_cpu(ex->ee_block)); + return ext_pblock(ex)+(block-le32_to_cpu(ex->ee_block)); /* it looks index is empty * try to find starting from index itself */ @@ -156,12 +193,12 @@ static int ext4_ext_find_goal(struct inode *inode, return bg_start + colour + block; } -static int +static ext4_fsblk_t ext4_ext_new_block(handle_t *handle, struct inode *inode, struct ext4_ext_path *path, struct ext4_extent *ex, int *err) { - int goal, newblock; + ext4_fsblk_t goal, newblock; goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block)); newblock = ext4_new_block(handle, inode, goal, err); @@ -230,13 +267,13 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) ext_debug("path:"); for (k = 0; k <= l; k++, path++) { if (path->p_idx) { - ext_debug(" %d->%d", le32_to_cpu(path->p_idx->ei_block), - le32_to_cpu(path->p_idx->ei_leaf)); + ext_debug(" %d->"E3FSBLK, le32_to_cpu(path->p_idx->ei_block), + idx_pblock(path->p_idx)); } else if (path->p_ext) { - ext_debug(" %d:%d:%d", + ext_debug(" %d:%d:"E3FSBLK" ", le32_to_cpu(path->p_ext->ee_block), le16_to_cpu(path->p_ext->ee_len), - le32_to_cpu(path->p_ext->ee_start)); + ext_pblock(path->p_ext)); } else ext_debug(" []"); } @@ -257,9 +294,8 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path) ex = EXT_FIRST_EXTENT(eh); for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) { - ext_debug("%d:%d:%d ", le32_to_cpu(ex->ee_block), - le16_to_cpu(ex->ee_len), - le32_to_cpu(ex->ee_start)); + ext_debug("%d:%d:"E3FSBLK" ", le32_to_cpu(ex->ee_block), + le16_to_cpu(ex->ee_len), ext_pblock(ex)); } ext_debug("\n"); } @@ -308,8 +344,8 @@ ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int bloc } path->p_idx = l - 1; - ext_debug(" -> %d->%d ", le32_to_cpu(path->p_idx->ei_block), - le32_to_cpu(path->p_idx->ei_leaf)); + ext_debug(" -> %d->%lld ", le32_to_cpu(path->p_idx->ei_block), + idx_block(path->p_idx)); #ifdef CHECK_BINSEARCH { @@ -374,10 +410,10 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block) } path->p_ext = l - 1; - ext_debug(" -> %d:%d:%d ", + ext_debug(" -> %d:"E3FSBLK":%d ", le32_to_cpu(path->p_ext->ee_block), - le32_to_cpu(path->p_ext->ee_start), - le16_to_cpu(path->p_ext->ee_len)); + ext_pblock(path->p_ext), + le16_to_cpu(path->p_ext->ee_len)); #ifdef CHECK_BINSEARCH { @@ -442,7 +478,7 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path) ext_debug("depth %d: num %d, max %d\n", ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); ext4_ext_binsearch_idx(inode, path + ppos, block); - path[ppos].p_block = le32_to_cpu(path[ppos].p_idx->ei_leaf); + path[ppos].p_block = idx_pblock(path[ppos].p_idx); path[ppos].p_depth = i; path[ppos].p_ext = NULL; @@ -489,7 +525,7 @@ err: */ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, struct ext4_ext_path *curp, - int logical, int ptr) + int logical, ext4_fsblk_t ptr) { struct ext4_extent_idx *ix; int len, err; @@ -524,7 +560,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, } ix->ei_block = cpu_to_le32(logical); - ix->ei_leaf = cpu_to_le32(ptr); + ext4_idx_store_pblock(ix, ptr); curp->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(curp->p_hdr->eh_entries)+1); BUG_ON(le16_to_cpu(curp->p_hdr->eh_entries) @@ -556,9 +592,9 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, struct ext4_extent_idx *fidx; struct ext4_extent *ex; int i = at, k, m, a; - unsigned long newblock, oldblock; + ext4_fsblk_t newblock, oldblock; __le32 border; - int *ablocks = NULL; /* array of allocated blocks */ + ext4_fsblk_t *ablocks = NULL; /* array of allocated blocks */ int err = 0; /* make decision: where to split? */ @@ -591,10 +627,10 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, * we need this to handle errors and free blocks * upon them */ - ablocks = kmalloc(sizeof(unsigned long) * depth, GFP_NOFS); + ablocks = kmalloc(sizeof(ext4_fsblk_t) * depth, GFP_NOFS); if (!ablocks) return -ENOMEM; - memset(ablocks, 0, sizeof(unsigned long) * depth); + memset(ablocks, 0, sizeof(ext4_fsblk_t) * depth); /* allocate all needed blocks */ ext_debug("allocate %d blocks for indexes/leaf\n", depth - at); @@ -633,9 +669,9 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, path[depth].p_ext++; while (path[depth].p_ext <= EXT_MAX_EXTENT(path[depth].p_hdr)) { - ext_debug("move %d:%d:%d in new leaf %lu\n", + ext_debug("move %d:"E3FSBLK":%d in new leaf "E3FSBLK"\n", le32_to_cpu(path[depth].p_ext->ee_block), - le32_to_cpu(path[depth].p_ext->ee_start), + ext_pblock(path[depth].p_ext), le16_to_cpu(path[depth].p_ext->ee_len), newblock); /*memmove(ex++, path[depth].p_ext++, @@ -679,7 +715,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, while (k--) { oldblock = newblock; newblock = ablocks[--a]; - bh = sb_getblk(inode->i_sb, newblock); + bh = sb_getblk(inode->i_sb, (ext4_fsblk_t)newblock); if (!bh) { err = -EIO; goto cleanup; @@ -696,9 +732,9 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, neh->eh_depth = cpu_to_le16(depth - i); fidx = EXT_FIRST_INDEX(neh); fidx->ei_block = border; - fidx->ei_leaf = cpu_to_le32(oldblock); + ext4_idx_store_pblock(fidx, oldblock); - ext_debug("int.index at %d (block %lu): %lu -> %lu\n", i, + ext_debug("int.index at %d (block "E3FSBLK"): %lu -> "E3FSBLK"\n", i, newblock, (unsigned long) le32_to_cpu(border), oldblock); /* copy indexes */ @@ -710,9 +746,9 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, BUG_ON(EXT_MAX_INDEX(path[i].p_hdr) != EXT_LAST_INDEX(path[i].p_hdr)); while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) { - ext_debug("%d: move %d:%d in new index %lu\n", i, + ext_debug("%d: move %d:%d in new index "E3FSBLK"\n", i, le32_to_cpu(path[i].p_idx->ei_block), - le32_to_cpu(path[i].p_idx->ei_leaf), + idx_pblock(path[i].p_idx), newblock); /*memmove(++fidx, path[i].p_idx++, sizeof(struct ext4_extent_idx)); @@ -791,7 +827,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, struct ext4_extent_header *neh; struct ext4_extent_idx *fidx; struct buffer_head *bh; - unsigned long newblock; + ext4_fsblk_t newblock; int err = 0; newblock = ext4_ext_new_block(handle, inode, path, newext, &err); @@ -839,13 +875,13 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr); /* FIXME: it works, but actually path[0] can be index */ curp->p_idx->ei_block = EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block; - curp->p_idx->ei_leaf = cpu_to_le32(newblock); + ext4_idx_store_pblock(curp->p_idx, newblock); neh = ext_inode_hdr(inode); fidx = EXT_FIRST_INDEX(neh); - ext_debug("new root: num %d(%d), lblock %d, ptr %d\n", + ext_debug("new root: num %d(%d), lblock %d, ptr "E3FSBLK"\n", le16_to_cpu(neh->eh_entries), le16_to_cpu(neh->eh_max), - le32_to_cpu(fidx->ei_block), le32_to_cpu(fidx->ei_leaf)); + le32_to_cpu(fidx->ei_block), idx_pblock(fidx)); neh->eh_depth = cpu_to_le16(path->p_depth + 1); err = ext4_ext_dirty(handle, inode, curp); @@ -1042,7 +1078,6 @@ static int inline ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, struct ext4_extent *ex2) { - /* FIXME: 48bit support */ if (le32_to_cpu(ex1->ee_block) + le16_to_cpu(ex1->ee_len) != le32_to_cpu(ex2->ee_block)) return 0; @@ -1052,8 +1087,7 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, return 0; #endif - if (le32_to_cpu(ex1->ee_start) + le16_to_cpu(ex1->ee_len) - == le32_to_cpu(ex2->ee_start)) + if (ext_pblock(ex1) + le16_to_cpu(ex1->ee_len) == ext_pblock(ex2)) return 1; return 0; } @@ -1080,11 +1114,10 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, /* try to insert block into found extent and return */ if (ex && ext4_can_extents_be_merged(inode, ex, newext)) { - ext_debug("append %d block to %d:%d (from %d)\n", + ext_debug("append %d block to %d:%d (from "E3FSBLK")\n", le16_to_cpu(newext->ee_len), le32_to_cpu(ex->ee_block), - le16_to_cpu(ex->ee_len), - le32_to_cpu(ex->ee_start)); + le16_to_cpu(ex->ee_len), ext_pblock(ex)); if ((err = ext4_ext_get_access(handle, inode, path + depth))) return err; ex->ee_len = cpu_to_le16(le16_to_cpu(ex->ee_len) @@ -1140,9 +1173,9 @@ has_space: if (!nearex) { /* there is no extent in this leaf, create first one */ - ext_debug("first extent in the leaf: %d:%d:%d\n", + ext_debug("first extent in the leaf: %d:"E3FSBLK":%d\n", le32_to_cpu(newext->ee_block), - le32_to_cpu(newext->ee_start), + ext_pblock(newext), le16_to_cpu(newext->ee_len)); path[depth].p_ext = EXT_FIRST_EXTENT(eh); } else if (le32_to_cpu(newext->ee_block) @@ -1152,10 +1185,10 @@ has_space: len = EXT_MAX_EXTENT(eh) - nearex; len = (len - 1) * sizeof(struct ext4_extent); len = len < 0 ? 0 : len; - ext_debug("insert %d:%d:%d after: nearest 0x%p, " + ext_debug("insert %d:"E3FSBLK":%d after: nearest 0x%p, " "move %d from 0x%p to 0x%p\n", le32_to_cpu(newext->ee_block), - le32_to_cpu(newext->ee_start), + ext_pblock(newext), le16_to_cpu(newext->ee_len), nearex, len, nearex + 1, nearex + 2); memmove(nearex + 2, nearex + 1, len); @@ -1165,10 +1198,10 @@ has_space: BUG_ON(newext->ee_block == nearex->ee_block); len = (EXT_MAX_EXTENT(eh) - nearex) * sizeof(struct ext4_extent); len = len < 0 ? 0 : len; - ext_debug("insert %d:%d:%d before: nearest 0x%p, " + ext_debug("insert %d:"E3FSBLK":%d before: nearest 0x%p, " "move %d from 0x%p to 0x%p\n", le32_to_cpu(newext->ee_block), - le32_to_cpu(newext->ee_start), + ext_pblock(newext), le16_to_cpu(newext->ee_len), nearex, len, nearex + 1, nearex + 2); memmove(nearex + 1, nearex, len); @@ -1179,9 +1212,8 @@ has_space: nearex = path[depth].p_ext; nearex->ee_block = newext->ee_block; nearex->ee_start = newext->ee_start; + nearex->ee_start_hi = newext->ee_start_hi; nearex->ee_len = newext->ee_len; - /* FIXME: support for large fs */ - nearex->ee_start_hi = 0; merge: /* try to merge extents to the right */ @@ -1290,7 +1322,7 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block, } else { cbex.ec_block = le32_to_cpu(ex->ee_block); cbex.ec_len = le16_to_cpu(ex->ee_len); - cbex.ec_start = le32_to_cpu(ex->ee_start); + cbex.ec_start = ext_pblock(ex); cbex.ec_type = EXT4_EXT_CACHE_EXTENT; } @@ -1398,13 +1430,13 @@ ext4_ext_in_cache(struct inode *inode, unsigned long block, cex->ec_type != EXT4_EXT_CACHE_EXTENT); if (block >= cex->ec_block && block < cex->ec_block + cex->ec_len) { ex->ee_block = cpu_to_le32(cex->ec_block); - ex->ee_start = cpu_to_le32(cex->ec_start); + ext4_ext_store_pblock(ex, cex->ec_start); ex->ee_len = cpu_to_le16(cex->ec_len); - ext_debug("%lu cached by %lu:%lu:%lu\n", + ext_debug("%lu cached by %lu:%lu:"E3FSBLK"\n", (unsigned long) block, (unsigned long) cex->ec_block, (unsigned long) cex->ec_len, - (unsigned long) cex->ec_start); + cex->ec_start); return cex->ec_type; } @@ -1422,18 +1454,18 @@ int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, { struct buffer_head *bh; int err; - unsigned long leaf; + ext4_fsblk_t leaf; /* free index block */ path--; - leaf = le32_to_cpu(path->p_idx->ei_leaf); + leaf = idx_pblock(path->p_idx); BUG_ON(path->p_hdr->eh_entries == 0); if ((err = ext4_ext_get_access(handle, inode, path))) return err; path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1); if ((err = ext4_ext_dirty(handle, inode, path))) return err; - ext_debug("index is empty, remove it, free block %lu\n", leaf); + ext_debug("index is empty, remove it, free block "E3FSBLK"\n", leaf); bh = sb_find_get_block(inode->i_sb, leaf); ext4_forget(handle, 1, inode, bh, leaf); ext4_free_blocks(handle, inode, leaf, 1); @@ -1515,10 +1547,11 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode, if (from >= le32_to_cpu(ex->ee_block) && to == le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) { /* tail removal */ - unsigned long num, start; + unsigned long num; + ext4_fsblk_t start; num = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - from; - start = le32_to_cpu(ex->ee_start) + le16_to_cpu(ex->ee_len) - num; - ext_debug("free last %lu blocks starting %lu\n", num, start); + start = ext_pblock(ex) + le16_to_cpu(ex->ee_len) - num; + ext_debug("free last %lu blocks starting "E3FSBLK"\n", num, start); for (i = 0; i < num; i++) { bh = sb_find_get_block(inode->i_sb, start + i); ext4_forget(handle, 0, inode, bh, start + i); @@ -1621,7 +1654,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, if (num == 0) { /* this extent is removed entirely mark slot unused */ - ex->ee_start = 0; + ext4_ext_store_pblock(ex, 0); eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1); } @@ -1632,8 +1665,8 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, if (err) goto out; - ext_debug("new extent: %u:%u:%u\n", block, num, - le32_to_cpu(ex->ee_start)); + ext_debug("new extent: %u:%u:"E3FSBLK"\n", block, num, + ext_pblock(ex)); ex--; ex_ee_block = le32_to_cpu(ex->ee_block); ex_ee_len = le16_to_cpu(ex->ee_len); @@ -1748,11 +1781,11 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start) path[i].p_idx); if (ext4_ext_more_to_rm(path + i)) { /* go to the next level */ - ext_debug("move to level %d (block %d)\n", - i + 1, le32_to_cpu(path[i].p_idx->ei_leaf)); + ext_debug("move to level %d (block "E3FSBLK")\n", + i + 1, idx_pblock(path[i].p_idx)); memset(path + i + 1, 0, sizeof(*path)); path[i+1].p_bh = - sb_bread(sb, le32_to_cpu(path[i].p_idx->ei_leaf)); + sb_bread(sb, idx_pblock(path[i].p_idx)); if (!path[i+1].p_bh) { /* should we reset i_size? */ err = -EIO; @@ -1851,13 +1884,15 @@ void ext4_ext_release(struct super_block *sb) #endif } -int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, sector_t iblock, +int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, + ext4_fsblk_t iblock, unsigned long max_blocks, struct buffer_head *bh_result, int create, int extend_disksize) { struct ext4_ext_path *path = NULL; struct ext4_extent newex, *ex; - int goal, newblock, err = 0, depth; + ext4_fsblk_t goal, newblock; + int err = 0, depth; unsigned long allocated = 0; __clear_bit(BH_New, &bh_result->b_state); @@ -1878,7 +1913,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, sector_t iblock, /* block is already allocated */ newblock = iblock - le32_to_cpu(newex.ee_block) - + le32_to_cpu(newex.ee_start); + + ext_pblock(&newex); /* number of remain blocks in the extent */ allocated = le16_to_cpu(newex.ee_len) - (iblock - le32_to_cpu(newex.ee_block)); @@ -1907,14 +1942,14 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, sector_t iblock, if ((ex = path[depth].p_ext)) { unsigned long ee_block = le32_to_cpu(ex->ee_block); - unsigned long ee_start = le32_to_cpu(ex->ee_start); + ext4_fsblk_t ee_start = ext_pblock(ex); unsigned short ee_len = le16_to_cpu(ex->ee_len); /* if found exent covers block, simple return it */ if (iblock >= ee_block && iblock < ee_block + ee_len) { newblock = iblock - ee_block + ee_start; /* number of remain blocks in the extent */ allocated = ee_len - (iblock - ee_block); - ext_debug("%d fit into %lu:%d -> %d\n", (int) iblock, + ext_debug("%d fit into %lu:%d -> "E3FSBLK"\n", (int) iblock, ee_block, ee_len, newblock); ext4_ext_put_in_cache(inode, ee_block, ee_len, ee_start, EXT4_EXT_CACHE_EXTENT); @@ -1944,12 +1979,12 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, sector_t iblock, newblock = ext4_new_blocks(handle, inode, goal, &allocated, &err); if (!newblock) goto out2; - ext_debug("allocate new block: goal %d, found %d/%lu\n", + ext_debug("allocate new block: goal "E3FSBLK", found "E3FSBLK"/%lu\n", goal, newblock, allocated); /* try to insert new extent into found leaf and return */ newex.ee_block = cpu_to_le32(iblock); - newex.ee_start = cpu_to_le32(newblock); + ext4_ext_store_pblock(&newex, newblock); newex.ee_len = cpu_to_le16(allocated); err = ext4_ext_insert_extent(handle, inode, path, &newex); if (err) @@ -1959,7 +1994,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, sector_t iblock, EXT4_I(inode)->i_disksize = inode->i_size; /* previous routine could use block we allocated */ - newblock = le32_to_cpu(newex.ee_start); + newblock = ext_pblock(&newex); __set_bit(BH_New, &bh_result->b_state); ext4_ext_put_in_cache(inode, iblock, allocated, newblock, diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h index 8029879e29e2..facc76684d4f 100644 --- a/include/linux/ext4_fs_extents.h +++ b/include/linux/ext4_fs_extents.h @@ -108,7 +108,7 @@ struct ext4_extent_header { * truncate uses it to simulate recursive walking */ struct ext4_ext_path { - __u32 p_block; + ext4_fsblk_t p_block; __u16 p_depth; struct ext4_extent *p_ext; struct ext4_extent_idx *p_idx; diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h index b2ccd9876bd1..2bed0effdcae 100644 --- a/include/linux/ext4_fs_i.h +++ b/include/linux/ext4_fs_i.h @@ -72,10 +72,10 @@ struct ext4_block_alloc_info { * storage for cached extent */ struct ext4_ext_cache { - __u32 ec_start; - __u32 ec_block; - __u32 ec_len; /* must be 32bit to return holes */ - __u32 ec_type; + ext4_fsblk_t ec_start; + __u32 ec_block; + __u32 ec_len; /* must be 32bit to return holes */ + __u32 ec_type; }; /* -- cgit v1.2.3 From 471d4011a9862efff02094388b8fe8cd67683c38 Mon Sep 17 00:00:00 2001 From: Suparna Bhattacharya Date: Wed, 11 Oct 2006 01:21:06 -0700 Subject: [PATCH] ext4: uninitialised extent handling Make it possible to add file preallocation support in future as an RO_COMPAT feature by recognizing uninitialized extents as holes and limiting extent length to keep the top bit of ee_len free for marking uninitialized extents. Signed-off-by: Suparna Bhattacharya Signed-off-by: Mingming Cao Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/extents.c | 16 ++++++++++++++++ include/linux/ext4_fs_extents.h | 2 ++ 2 files changed, 18 insertions(+) (limited to 'include/linux') diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 4a13b56e1540..32526061a17d 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -1082,6 +1082,13 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, != le32_to_cpu(ex2->ee_block)) return 0; + /* + * To allow future support for preallocated extents to be added + * as an RO_COMPAT feature, refuse to merge to extents if + * can result in the top bit of ee_len being set + */ + if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN) + return 0; #ifdef AGRESSIVE_TEST if (le16_to_cpu(ex1->ee_len) >= 4) return 0; @@ -1944,6 +1951,15 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, unsigned long ee_block = le32_to_cpu(ex->ee_block); ext4_fsblk_t ee_start = ext_pblock(ex); unsigned short ee_len = le16_to_cpu(ex->ee_len); + + /* + * Allow future support for preallocated extents to be added + * as an RO_COMPAT feature: + * Uninitialized extents are treated as holes, except that + * we avoid (fail) allocating new blocks during a write. + */ + if (ee_len > EXT_MAX_LEN) + goto out2; /* if found exent covers block, simple return it */ if (iblock >= ee_block && iblock < ee_block + ee_len) { newblock = iblock - ee_block + ee_start; diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h index facc76684d4f..0eba0acf6ba6 100644 --- a/include/linux/ext4_fs_extents.h +++ b/include/linux/ext4_fs_extents.h @@ -141,6 +141,8 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *, #define EXT_MAX_BLOCK 0xffffffff +#define EXT_MAX_LEN ((1UL << 15) - 1) + #define EXT_FIRST_EXTENT(__hdr__) \ ((struct ext4_extent *) (((char *) (__hdr__)) + \ -- cgit v1.2.3 From d0d856e8bd6e697cb44b2b4dd038f3bec576a70e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Oct 2006 01:21:07 -0700 Subject: [PATCH] ext4: clean up comments in ext4-extents patch Signed-off-by: Randy Dunlap Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/extents.c | 226 +++++++++++++++++++++++----------------- include/linux/ext4_fs_extents.h | 54 +++++----- include/linux/ext4_jbd2.h | 4 +- 3 files changed, 157 insertions(+), 127 deletions(-) (limited to 'include/linux') diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 32526061a17d..e06e937a52b8 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -44,7 +44,10 @@ #include -/* this macro combines low and hi parts of phys. blocknr into ext4_fsblk_t */ +/* + * ext_pblock: + * combine low and high parts of physical block number into ext4_fsblk_t + */ static inline ext4_fsblk_t ext_pblock(struct ext4_extent *ex) { ext4_fsblk_t block; @@ -55,7 +58,10 @@ static inline ext4_fsblk_t ext_pblock(struct ext4_extent *ex) return block; } -/* this macro combines low and hi parts of phys. blocknr into ext4_fsblk_t */ +/* + * idx_pblock: + * combine low and high parts of a leaf physical block number into ext4_fsblk_t + */ static inline ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix) { ext4_fsblk_t block; @@ -66,7 +72,11 @@ static inline ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix) return block; } -/* the routine stores large phys. blocknr into extent breaking it into parts */ +/* + * ext4_ext_store_pblock: + * stores a large physical block number into an extent struct, + * breaking it into parts + */ static inline void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb) { ex->ee_start = cpu_to_le32((unsigned long) (pb & 0xffffffff)); @@ -74,7 +84,11 @@ static inline void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff); } -/* the routine stores large phys. blocknr into index breaking it into parts */ +/* + * ext4_idx_store_pblock: + * stores a large physical block number into an index struct, + * breaking it into parts + */ static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb) { ix->ei_leaf = cpu_to_le32((unsigned long) (pb & 0xffffffff)); @@ -179,8 +193,8 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode, if ((ex = path[depth].p_ext)) return ext_pblock(ex)+(block-le32_to_cpu(ex->ee_block)); - /* it looks index is empty - * try to find starting from index itself */ + /* it looks like index is empty; + * try to find starting block from index itself */ if (path[depth].p_bh) return path[depth].p_bh->b_blocknr; } @@ -317,7 +331,8 @@ static void ext4_ext_drop_refs(struct ext4_ext_path *path) } /* - * binary search for closest index by given block + * ext4_ext_binsearch_idx: + * binary search for the closest index of the given block */ static void ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int block) @@ -375,7 +390,8 @@ ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int bloc } /* - * binary search for closest extent by given block + * ext4_ext_binsearch: + * binary search for closest extent of the given block */ static void ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block) @@ -388,8 +404,8 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block) if (eh->eh_entries == 0) { /* - * this leaf is empty yet: - * we get such a leaf in split/add case + * this leaf is empty: + * we get such a leaf in split/add case */ return; } @@ -520,8 +536,9 @@ err: } /* - * insert new index [logical;ptr] into the block at cupr - * it check where to insert: before curp or after curp + * ext4_ext_insert_index: + * insert new index [@logical;@ptr] into the block at @curp; + * check where to insert: before @curp or after @curp */ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, struct ext4_ext_path *curp, @@ -574,13 +591,14 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, } /* - * routine inserts new subtree into the path, using free index entry - * at depth 'at: - * - allocates all needed blocks (new leaf and all intermediate index blocks) - * - makes decision where to split - * - moves remaining extens and index entries (right to the split point) - * into the newly allocated blocks - * - initialize subtree + * ext4_ext_split: + * inserts new subtree into the path, using free index entry + * at depth @at: + * - allocates all needed blocks (new leaf and all intermediate index blocks) + * - makes decision where to split + * - moves remaining extents and index entries (right to the split point) + * into the newly allocated blocks + * - initializes subtree */ static int ext4_ext_split(handle_t *handle, struct inode *inode, struct ext4_ext_path *path, @@ -598,14 +616,14 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, int err = 0; /* make decision: where to split? */ - /* FIXME: now desicion is simplest: at current extent */ + /* FIXME: now decision is simplest: at current extent */ - /* if current leaf will be splitted, then we should use + /* if current leaf will be split, then we should use * border from split point */ BUG_ON(path[depth].p_ext > EXT_MAX_EXTENT(path[depth].p_hdr)); if (path[depth].p_ext != EXT_MAX_EXTENT(path[depth].p_hdr)) { border = path[depth].p_ext[1].ee_block; - ext_debug("leaf will be splitted." + ext_debug("leaf will be split." " next leaf starts at %d\n", le32_to_cpu(border)); } else { @@ -616,16 +634,16 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, } /* - * if error occurs, then we break processing - * and turn filesystem read-only. so, index won't + * If error occurs, then we break processing + * and mark filesystem read-only. index won't * be inserted and tree will be in consistent - * state. next mount will repair buffers too + * state. Next mount will repair buffers too. */ /* - * get array to track all allocated blocks - * we need this to handle errors and free blocks - * upon them + * Get array to track all allocated blocks. + * We need this to handle errors and free blocks + * upon them. */ ablocks = kmalloc(sizeof(ext4_fsblk_t) * depth, GFP_NOFS); if (!ablocks) @@ -661,7 +679,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, neh->eh_depth = 0; ex = EXT_FIRST_EXTENT(neh); - /* move remain of path[depth] to the new leaf */ + /* move remainder of path[depth] to the new leaf */ BUG_ON(path[depth].p_hdr->eh_entries != path[depth].p_hdr->eh_max); /* start copy from next extent */ /* TODO: we could do it by single memmove */ @@ -813,11 +831,12 @@ cleanup: } /* - * routine implements tree growing procedure: - * - allocates new block - * - moves top-level data (index block or leaf) into the new block - * - initialize new top-level, creating index that points to the - * just created block + * ext4_ext_grow_indepth: + * implements tree growing procedure: + * - allocates new block + * - moves top-level data (index block or leaf) into the new block + * - initializes new top-level, creating index that points to the + * just created block */ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, struct ext4_ext_path *path, @@ -892,8 +911,9 @@ out: } /* - * routine finds empty index and adds new leaf. if no free index found - * then it requests in-depth growing + * ext4_ext_create_new_leaf: + * finds empty index and adds new leaf. + * if no free index is found, then it requests in-depth growing. */ static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode, struct ext4_ext_path *path, @@ -912,8 +932,8 @@ repeat: curp--; } - /* we use already allocated block for index block - * so, subsequent data blocks should be contigoues */ + /* we use already allocated block for index block, + * so subsequent data blocks should be contiguous */ if (EXT_HAS_FREE_INDEX(curp)) { /* if we found index with free entry, then use that * entry: create all needed subtree and add new leaf */ @@ -943,12 +963,12 @@ repeat: } /* - * only first (depth 0 -> 1) produces free space - * in all other cases we have to split growed tree + * only first (depth 0 -> 1) produces free space; + * in all other cases we have to split the grown tree */ depth = ext_depth(inode); if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) { - /* now we need split */ + /* now we need to split */ goto repeat; } } @@ -958,10 +978,11 @@ out: } /* - * returns allocated block in subsequent extent or EXT_MAX_BLOCK - * NOTE: it consider block number from index entry as - * allocated block. thus, index entries have to be consistent - * with leafs + * ext4_ext_next_allocated_block: + * returns allocated block in subsequent extent or EXT_MAX_BLOCK. + * NOTE: it considers block number from index entry as + * allocated block. Thus, index entries have to be consistent + * with leaves. */ static unsigned long ext4_ext_next_allocated_block(struct ext4_ext_path *path) @@ -993,6 +1014,7 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path) } /* + * ext4_ext_next_leaf_block: * returns first allocated block from next leaf or EXT_MAX_BLOCK */ static unsigned ext4_ext_next_leaf_block(struct inode *inode, @@ -1021,8 +1043,9 @@ static unsigned ext4_ext_next_leaf_block(struct inode *inode, } /* - * if leaf gets modified and modified extent is first in the leaf - * then we have to correct all indexes above + * ext4_ext_correct_indexes: + * if leaf gets modified and modified extent is first in the leaf, + * then we have to correct all indexes above. * TODO: do we need to correct tree in all cases? */ int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode, @@ -1050,7 +1073,7 @@ int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode, } /* - * TODO: we need correction if border is smaller then current one + * TODO: we need correction if border is smaller than current one */ k = depth - 1; border = path[depth].p_ext->ee_block; @@ -1085,7 +1108,7 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, /* * To allow future support for preallocated extents to be added * as an RO_COMPAT feature, refuse to merge to extents if - * can result in the top bit of ee_len being set + * this can result in the top bit of ee_len being set. */ if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN) return 0; @@ -1100,9 +1123,10 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, } /* - * this routine tries to merge requsted extent into the existing - * extent or inserts requested extent as new one into the tree, - * creating new leaf in no-space case + * ext4_ext_insert_extent: + * tries to merge requsted extent into the existing extent or + * inserts requested extent as new one into the tree, + * creating new leaf in the no-space case. */ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, struct ext4_ext_path *path, @@ -1163,8 +1187,8 @@ repeat: } /* - * there is no free space in found leaf - * we're gonna add new leaf in the tree + * There is no free space in the found leaf. + * We're gonna add a new leaf in the tree. */ err = ext4_ext_create_new_leaf(handle, inode, path, newext); if (err) @@ -1377,7 +1401,8 @@ ext4_ext_put_in_cache(struct inode *inode, __u32 block, } /* - * this routine calculate boundaries of the gap requested block fits into + * ext4_ext_put_gap_in_cache: + * calculate boundaries of the gap that the requested block fits into * and cache this gap */ static inline void @@ -1452,9 +1477,10 @@ ext4_ext_in_cache(struct inode *inode, unsigned long block, } /* - * routine removes index from the index block - * it's used in truncate case only. thus all requests are for - * last index in the block only + * ext4_ext_rm_idx: + * removes index from the index block. + * It's used in truncate case only, thus all requests are for + * last index in the block only. */ int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, struct ext4_ext_path *path) @@ -1480,11 +1506,12 @@ int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, } /* - * This routine returns max. credits extent tree can consume. + * ext4_ext_calc_credits_for_insert: + * This routine returns max. credits that the extent tree can consume. * It should be OK for low-performance paths like ->writepage() - * To allow many writing process to fit a single transaction, - * caller should calculate credits under truncate_mutex and - * pass actual path. + * To allow many writing processes to fit into a single transaction, + * the caller should calculate credits under truncate_mutex and + * pass the actual path. */ int inline ext4_ext_calc_credits_for_insert(struct inode *inode, struct ext4_ext_path *path) @@ -1500,9 +1527,9 @@ int inline ext4_ext_calc_credits_for_insert(struct inode *inode, } /* - * given 32bit logical block (4294967296 blocks), max. tree + * given 32-bit logical block (4294967296 blocks), max. tree * can be 4 levels in depth -- 4 * 340^4 == 53453440000. - * let's also add one more level for imbalance. + * Let's also add one more level for imbalance. */ depth = 5; @@ -1510,13 +1537,13 @@ int inline ext4_ext_calc_credits_for_insert(struct inode *inode, needed = 2; /* - * tree can be full, so it'd need to grow in depth: + * tree can be full, so it would need to grow in depth: * allocation + old root + new root */ needed += 2 + 1 + 1; /* - * Index split can happen, we'd need: + * Index split can happen, we would need: * allocate intermediate indexes (bitmap + group) * + change two blocks at each level, but root (already included) */ @@ -1634,7 +1661,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, BUG_ON(b != ex_ee_block + ex_ee_len - 1); } - /* at present, extent can't cross block group */ + /* at present, extent can't cross block group: */ /* leaf + bitmap + group desc + sb + inode */ credits = 5; if (ex == EXT_FIRST_EXTENT(eh)) { @@ -1660,7 +1687,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, goto out; if (num == 0) { - /* this extent is removed entirely mark slot unused */ + /* this extent is removed; mark slot entirely unused */ ext4_ext_store_pblock(ex, 0); eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1); } @@ -1692,7 +1719,8 @@ out: } /* - * returns 1 if current index have to be freed (even partial) + * ext4_ext_more_to_rm: + * returns 1 if current index has to be freed (even partial) */ static int inline ext4_ext_more_to_rm(struct ext4_ext_path *path) @@ -1703,7 +1731,7 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path) return 0; /* - * if truncate on deeper level happened it it wasn't partial + * if truncate on deeper level happened, it wasn't partial, * so we have to consider current index for truncation */ if (le16_to_cpu(path->p_hdr->eh_entries) == path->p_block) @@ -1729,8 +1757,8 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start) ext4_ext_invalidate_cache(inode); /* - * we start scanning from right side freeing all the blocks - * after i_size and walking into the deep + * We start scanning from right side, freeing all the blocks + * after i_size and walking into the tree depth-wise. */ path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL); if (path == NULL) { @@ -1749,7 +1777,7 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start) if (i == depth) { /* this is leaf block */ err = ext4_ext_rm_leaf(handle, inode, path, start); - /* root level have p_bh == NULL, brelse() eats this */ + /* root level has p_bh == NULL, brelse() eats this */ brelse(path[i].p_bh); path[i].p_bh = NULL; i--; @@ -1772,14 +1800,14 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start) BUG_ON(path[i].p_hdr->eh_magic != EXT4_EXT_MAGIC); if (!path[i].p_idx) { - /* this level hasn't touched yet */ + /* this level hasn't been touched yet */ path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr); path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries)+1; ext_debug("init index ptr: hdr 0x%p, num %d\n", path[i].p_hdr, le16_to_cpu(path[i].p_hdr->eh_entries)); } else { - /* we've already was here, see at next index */ + /* we were already here, see at next index */ path[i].p_idx--; } @@ -1799,19 +1827,19 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start) break; } - /* put actual number of indexes to know is this - * number got changed at the next iteration */ + /* save actual number of indexes since this + * number is changed at the next iteration */ path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries); i++; } else { - /* we finish processing this index, go up */ + /* we finished processing this index, go up */ if (path[i].p_hdr->eh_entries == 0 && i > 0) { - /* index is empty, remove it + /* index is empty, remove it; * handle must be already prepared by the * truncatei_leaf() */ err = ext4_ext_rm_idx(handle, inode, path + i); } - /* root level have p_bh == NULL, brelse() eats this */ + /* root level has p_bh == NULL, brelse() eats this */ brelse(path[i].p_bh); path[i].p_bh = NULL; i--; @@ -1822,8 +1850,8 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start) /* TODO: flexible tree reduction should be here */ if (path->p_hdr->eh_entries == 0) { /* - * truncate to zero freed all the tree - * so, we need to correct eh_depth + * truncate to zero freed all the tree, + * so we need to correct eh_depth */ err = ext4_ext_get_access(handle, inode, path); if (err == 0) { @@ -1912,7 +1940,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, if (goal == EXT4_EXT_CACHE_GAP) { if (!create) { /* block isn't allocated yet and - * user don't want to allocate it */ + * user doesn't want to allocate it */ goto out2; } /* we should allocate requested block */ @@ -1921,7 +1949,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, newblock = iblock - le32_to_cpu(newex.ee_block) + ext_pblock(&newex); - /* number of remain blocks in the extent */ + /* number of remaining blocks in the extent */ allocated = le16_to_cpu(newex.ee_len) - (iblock - le32_to_cpu(newex.ee_block)); goto out; @@ -1941,8 +1969,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, depth = ext_depth(inode); /* - * consistent leaf must not be empty - * this situations is possible, though, _during_ tree modification + * consistent leaf must not be empty; + * this situation is possible, though, _during_ tree modification; * this is why assert can't be put in ext4_ext_find_extent() */ BUG_ON(path[depth].p_ext == NULL && depth != 0); @@ -1960,10 +1988,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, */ if (ee_len > EXT_MAX_LEN) goto out2; - /* if found exent covers block, simple return it */ + /* if found extent covers block, simply return it */ if (iblock >= ee_block && iblock < ee_block + ee_len) { newblock = iblock - ee_block + ee_start; - /* number of remain blocks in the extent */ + /* number of remaining blocks in the extent */ allocated = ee_len - (iblock - ee_block); ext_debug("%d fit into %lu:%d -> "E3FSBLK"\n", (int) iblock, ee_block, ee_len, newblock); @@ -1974,17 +2002,18 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, } /* - * requested block isn't allocated yet + * requested block isn't allocated yet; * we couldn't try to create block if create flag is zero */ if (!create) { - /* put just found gap into cache to speedup subsequest reqs */ + /* put just found gap into cache to speed up + * subsequent requests */ ext4_ext_put_gap_in_cache(inode, path, iblock); goto out2; } /* * Okay, we need to do block allocation. Lazily initialize the block - * allocation info here if necessary + * allocation info here if necessary. */ if (S_ISREG(inode->i_mode) && (!EXT4_I(inode)->i_block_alloc_info)) ext4_init_block_alloc_info(inode); @@ -2062,9 +2091,9 @@ void ext4_ext_truncate(struct inode * inode, struct page *page) ext4_ext_invalidate_cache(inode); /* - * TODO: optimization is possible here - * probably we need not scaning at all, - * because page truncation is enough + * TODO: optimization is possible here. + * Probably we need not scan at all, + * because page truncation is enough. */ if (ext4_orphan_add(handle, inode)) goto out_stop; @@ -2078,13 +2107,13 @@ void ext4_ext_truncate(struct inode * inode, struct page *page) err = ext4_ext_remove_space(inode, last_block); /* In a multi-transaction truncate, we only make the final - * transaction synchronous */ + * transaction synchronous. */ if (IS_SYNC(inode)) handle->h_sync = 1; out_stop: /* - * If this was a simple ftruncate(), and the file will remain alive + * If this was a simple ftruncate() and the file will remain alive, * then we need to clear up the orphan record which we created above. * However, if this was a real unlink then we were called by * ext4_delete_inode(), and we allow that function to clean up the @@ -2098,7 +2127,8 @@ out_stop: } /* - * this routine calculate max number of blocks we could modify + * ext4_ext_writepage_trans_blocks: + * calculate max number of blocks we could modify * in order to allocate new block for an inode */ int ext4_ext_writepage_trans_blocks(struct inode *inode, int num) @@ -2107,7 +2137,7 @@ int ext4_ext_writepage_trans_blocks(struct inode *inode, int num) needed = ext4_ext_calc_credits_for_insert(inode, NULL); - /* caller want to allocate num blocks, but note it includes sb */ + /* caller wants to allocate num blocks, but note it includes sb */ needed = needed * num - (num - 1); #ifdef CONFIG_QUOTA diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h index 0eba0acf6ba6..a41cc24568ca 100644 --- a/include/linux/ext4_fs_extents.h +++ b/include/linux/ext4_fs_extents.h @@ -22,29 +22,29 @@ #include /* - * with AGRESSIVE_TEST defined capacity of index/leaf blocks - * become very little, so index split, in-depth growing and - * other hard changes happens much more often - * this is for debug purposes only + * With AGRESSIVE_TEST defined, the capacity of index/leaf blocks + * becomes very small, so index split, in-depth growing and + * other hard changes happen much more often. + * This is for debug purposes only. */ #define AGRESSIVE_TEST_ /* - * with EXTENTS_STATS defined number of blocks and extents - * are collected in truncate path. they'll be showed at - * umount time + * With EXTENTS_STATS defined, the number of blocks and extents + * are collected in the truncate path. They'll be shown at + * umount time. */ #define EXTENTS_STATS__ /* - * if CHECK_BINSEARCH defined, then results of binary search - * will be checked by linear search + * If CHECK_BINSEARCH is defined, then the results of the binary search + * will also be checked by linear search. */ #define CHECK_BINSEARCH__ /* - * if EXT_DEBUG is defined you can use 'extdebug' mount option - * to get lots of info what's going on + * If EXT_DEBUG is defined you can use the 'extdebug' mount option + * to get lots of info about what's going on. */ #define EXT_DEBUG__ #ifdef EXT_DEBUG @@ -54,58 +54,58 @@ #endif /* - * if EXT_STATS is defined then stats numbers are collected - * these number will be displayed at umount time + * If EXT_STATS is defined then stats numbers are collected. + * These number will be displayed at umount time. */ #define EXT_STATS_ /* - * ext4_inode has i_block array (60 bytes total) - * first 12 bytes store ext4_extent_header - * the remain stores array of ext4_extent + * ext4_inode has i_block array (60 bytes total). + * The first 12 bytes store ext4_extent_header; + * the remainder stores an array of ext4_extent. */ /* - * this is extent on-disk structure - * it's used at the bottom of the tree + * This is the extent on-disk structure. + * It's used at the bottom of the tree. */ struct ext4_extent { __le32 ee_block; /* first logical block extent covers */ __le16 ee_len; /* number of blocks covered by extent */ __le16 ee_start_hi; /* high 16 bits of physical block */ - __le32 ee_start; /* low 32 bigs of physical block */ + __le32 ee_start; /* low 32 bits of physical block */ }; /* - * this is index on-disk structure - * it's used at all the levels, but the bottom + * This is index on-disk structure. + * It's used at all the levels except the bottom. */ struct ext4_extent_idx { __le32 ei_block; /* index covers logical blocks from 'block' */ __le32 ei_leaf; /* pointer to the physical block of the next * - * level. leaf or next index could bet here */ + * level. leaf or next index could be there */ __le16 ei_leaf_hi; /* high 16 bits of physical block */ __u16 ei_unused; }; /* - * each block (leaves and indexes), even inode-stored has header + * Each block (leaves and indexes), even inode-stored has header. */ struct ext4_extent_header { __le16 eh_magic; /* probably will support different formats */ __le16 eh_entries; /* number of valid entries */ __le16 eh_max; /* capacity of store in entries */ - __le16 eh_depth; /* has tree real underlaying blocks? */ + __le16 eh_depth; /* has tree real underlying blocks? */ __le32 eh_generation; /* generation of the tree */ }; #define EXT4_EXT_MAGIC cpu_to_le16(0xf30a) /* - * array of ext4_ext_path contains path to some extent - * creation/lookup routines use it for traversal/splitting/etc - * truncate uses it to simulate recursive walking + * Array of ext4_ext_path contains path to some extent. + * Creation/lookup routines use it for traversal/splitting/etc. + * Truncate uses it to simulate recursive walking. */ struct ext4_ext_path { ext4_fsblk_t p_block; diff --git a/include/linux/ext4_jbd2.h b/include/linux/ext4_jbd2.h index aa273f024ad0..f69af60d7692 100644 --- a/include/linux/ext4_jbd2.h +++ b/include/linux/ext4_jbd2.h @@ -28,8 +28,8 @@ * indirection blocks, the group and superblock summaries, and the data * block to complete the transaction. * - * For extents-enabled fs we may have to allocate and modify upto - * 5 levels of tree + root which is stored in inode. */ + * For extents-enabled fs we may have to allocate and modify up to + * 5 levels of tree + root which are stored in the inode. */ #define EXT4_SINGLEDATA_TRANS_BLOCKS(sb) \ (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS) \ -- cgit v1.2.3 From b517bea1c74e4773482b3f41b3f493522a8c8e30 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 11 Oct 2006 01:21:08 -0700 Subject: [PATCH] 64-bit jbd2 core Here is the patch to JBD to handle 64 bit block numbers, originally from Zach Brown. This patch is useful only after adding support for 64-bit block numbers in the filesystem. Signed-off-by: Badari Pulavarty Signed-off-by: Zach Brown Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd2/commit.c | 17 +++++++++++++---- fs/jbd2/journal.c | 11 +++++++++++ fs/jbd2/recovery.c | 43 ++++++++++++++++++++++++++++++------------- fs/jbd2/revoke.c | 14 +++++++++++--- include/linux/jbd2.h | 14 ++++++++++++-- 5 files changed, 77 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index b1a4eafc1541..44d68a113c73 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -271,6 +271,14 @@ write_out_data: journal_do_submit_data(wbuf, bufs); } +static inline void write_tag_block(int tag_bytes, journal_block_tag_t *tag, + sector_t block) +{ + tag->t_blocknr = cpu_to_be32(block & (u32)~0); + if (tag_bytes > JBD_TAG_SIZE32) + tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); +} + /* * jbd2_journal_commit_transaction * @@ -293,6 +301,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) int first_tag = 0; int tag_flag; int i; + int tag_bytes = journal_tag_bytes(journal); /* * First job: lock down the current transaction and wait for @@ -597,10 +606,10 @@ void jbd2_journal_commit_transaction(journal_t *journal) tag_flag |= JBD2_FLAG_SAME_UUID; tag = (journal_block_tag_t *) tagp; - tag->t_blocknr = cpu_to_be32(jh2bh(jh)->b_blocknr); + write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr); tag->t_flags = cpu_to_be32(tag_flag); - tagp += sizeof(journal_block_tag_t); - space_left -= sizeof(journal_block_tag_t); + tagp += tag_bytes; + space_left -= tag_bytes; if (first_tag) { memcpy (tagp, journal->j_uuid, 16); @@ -614,7 +623,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) if (bufs == journal->j_wbufsize || commit_transaction->t_buffers == NULL || - space_left < sizeof(journal_block_tag_t) + 16) { + space_left < tag_bytes + 16) { jbd_debug(4, "JBD: Submit %d IOs\n", bufs); diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 8d0f71e562fe..926ebcbf8a7a 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1609,6 +1609,17 @@ int jbd2_journal_blocks_per_page(struct inode *inode) return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); } +/* + * helper functions to deal with 32 or 64bit block numbers. + */ +size_t journal_tag_bytes(journal_t *journal) +{ + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) + return JBD_TAG_SIZE64; + else + return JBD_TAG_SIZE32; +} + /* * Simple support for retrying memory allocations. Introduced to help to * debug different VM deadlock avoidance strategies. diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index b2012d112432..2486843adda0 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -178,19 +178,20 @@ static int jread(struct buffer_head **bhp, journal_t *journal, * Count the number of in-use tags in a journal descriptor block. */ -static int count_tags(struct buffer_head *bh, int size) +static int count_tags(journal_t *journal, struct buffer_head *bh) { char * tagp; journal_block_tag_t * tag; - int nr = 0; + int nr = 0, size = journal->j_blocksize; + int tag_bytes = journal_tag_bytes(journal); tagp = &bh->b_data[sizeof(journal_header_t)]; - while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) { + while ((tagp - bh->b_data + tag_bytes) <= size) { tag = (journal_block_tag_t *) tagp; nr++; - tagp += sizeof(journal_block_tag_t); + tagp += tag_bytes; if (!(tag->t_flags & cpu_to_be32(JBD2_FLAG_SAME_UUID))) tagp += 16; @@ -307,6 +308,14 @@ int jbd2_journal_skip_recovery(journal_t *journal) return err; } +static inline sector_t read_tag_block(int tag_bytes, journal_block_tag_t *tag) +{ + sector_t block = be32_to_cpu(tag->t_blocknr); + if (tag_bytes > JBD_TAG_SIZE32) + block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32; + return block; +} + static int do_one_pass(journal_t *journal, struct recovery_info *info, enum passtype pass) { @@ -318,11 +327,12 @@ static int do_one_pass(journal_t *journal, struct buffer_head * bh; unsigned int sequence; int blocktype; + int tag_bytes = journal_tag_bytes(journal); /* Precompute the maximum metadata descriptors in a descriptor block */ int MAX_BLOCKS_PER_DESC; MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t)) - / sizeof(journal_block_tag_t)); + / tag_bytes); /* * First thing is to establish what we expect to find in the log @@ -412,8 +422,7 @@ static int do_one_pass(journal_t *journal, * in pass REPLAY; otherwise, just skip over the * blocks it describes. */ if (pass != PASS_REPLAY) { - next_log_block += - count_tags(bh, journal->j_blocksize); + next_log_block += count_tags(journal, bh); wrap(journal, next_log_block); brelse(bh); continue; @@ -424,7 +433,7 @@ static int do_one_pass(journal_t *journal, * getting done here! */ tagp = &bh->b_data[sizeof(journal_header_t)]; - while ((tagp - bh->b_data +sizeof(journal_block_tag_t)) + while ((tagp - bh->b_data + tag_bytes) <= journal->j_blocksize) { unsigned long io_block; @@ -446,7 +455,8 @@ static int do_one_pass(journal_t *journal, unsigned long blocknr; J_ASSERT(obh != NULL); - blocknr = be32_to_cpu(tag->t_blocknr); + blocknr = read_tag_block(tag_bytes, + tag); /* If the block has been * revoked, then we're all done @@ -494,7 +504,7 @@ static int do_one_pass(journal_t *journal, } skip_write: - tagp += sizeof(journal_block_tag_t); + tagp += tag_bytes; if (!(flags & JBD2_FLAG_SAME_UUID)) tagp += 16; @@ -572,17 +582,24 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, { jbd2_journal_revoke_header_t *header; int offset, max; + int record_len = 4; header = (jbd2_journal_revoke_header_t *) bh->b_data; offset = sizeof(jbd2_journal_revoke_header_t); max = be32_to_cpu(header->r_count); - while (offset < max) { + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) + record_len = 8; + + while (offset + record_len <= max) { unsigned long blocknr; int err; - blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); - offset += 4; + if (record_len == 4) + blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); + else + blocknr = be64_to_cpu(* ((__be64 *) (bh->b_data+offset))); + offset += record_len; err = jbd2_journal_set_revoke(journal, blocknr, sequence); if (err) return err; diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 5820a0c5ad26..8aac875bd301 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -584,9 +584,17 @@ static void write_one_revoke_record(journal_t *journal, *descriptorp = descriptor; } - * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) = - cpu_to_be32(record->blocknr); - offset += 4; + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) { + * ((__be64 *)(&jh2bh(descriptor)->b_data[offset])) = + cpu_to_be64(record->blocknr); + offset += 8; + + } else { + * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) = + cpu_to_be32(record->blocknr); + offset += 4; + } + *offsetp = offset; } diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 3251f7abb57d..5e5aa64f1261 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -150,14 +150,21 @@ typedef struct journal_header_s /* - * The block tag: used to describe a single buffer in the journal + * The block tag: used to describe a single buffer in the journal. + * t_blocknr_high is only used if INCOMPAT_64BIT is set, so this + * raw struct shouldn't be used for pointer math or sizeof() - use + * journal_tag_bytes(journal) instead to compute this. */ typedef struct journal_block_tag_s { __be32 t_blocknr; /* The on-disk block number */ __be32 t_flags; /* See below */ + __be32 t_blocknr_high; /* most-significant high 32bits. */ } journal_block_tag_t; +#define JBD_TAG_SIZE32 (offsetof(journal_block_tag_t, t_blocknr_high)) +#define JBD_TAG_SIZE64 (sizeof(journal_block_tag_t)) + /* * The revoke descriptor: used on disk to describe a series of blocks to * be revoked from the log @@ -235,11 +242,13 @@ typedef struct journal_superblock_s ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask)))) #define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001 +#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002 /* Features known to this kernel version: */ #define JBD2_KNOWN_COMPAT_FEATURES 0 #define JBD2_KNOWN_ROCOMPAT_FEATURES 0 -#define JBD2_KNOWN_INCOMPAT_FEATURES JBD2_FEATURE_INCOMPAT_REVOKE +#define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE | \ + JBD2_FEATURE_INCOMPAT_64BIT) #ifdef __KERNEL__ @@ -1052,6 +1061,7 @@ static inline int tid_geq(tid_t x, tid_t y) } extern int jbd2_journal_blocks_per_page(struct inode *inode); +extern size_t journal_tag_bytes(journal_t *journal); /* * Return the minimum number of blocks which must be free in the journal -- cgit v1.2.3 From 299717696d48531d70aeb4614c3939e4a28456c1 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:21:09 -0700 Subject: [PATCH] jbd2: sector_t conversion JBD layer in-kernel block varibles type fixes to support >32 bit block number and convert to sector_t type. Signed-off-by: Mingming Cao Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd2/commit.c | 2 +- fs/jbd2/journal.c | 18 +++++++++--------- fs/jbd2/recovery.c | 8 ++++---- fs/jbd2/revoke.c | 23 ++++++++++++----------- include/linux/ext4_jbd2.h | 2 +- include/linux/jbd2.h | 17 ++++++++--------- 6 files changed, 35 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 44d68a113c73..1a9ce8885220 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -293,7 +293,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) int bufs; int flags; int err; - unsigned long blocknr; + sector_t blocknr; char *tagp = NULL; journal_header_t *header; journal_block_tag_t *tag = NULL; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 926ebcbf8a7a..259e8365ea15 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -271,7 +271,7 @@ static void journal_kill_thread(journal_t *journal) int jbd2_journal_write_metadata_buffer(transaction_t *transaction, struct journal_head *jh_in, struct journal_head **jh_out, - unsigned long blocknr) + sector_t blocknr) { int need_copy_out = 0; int done_copy_out = 0; @@ -555,7 +555,7 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid) * Log buffer allocation routines: */ -int jbd2_journal_next_log_block(journal_t *journal, unsigned long *retp) +int jbd2_journal_next_log_block(journal_t *journal, sector_t *retp) { unsigned long blocknr; @@ -579,10 +579,10 @@ int jbd2_journal_next_log_block(journal_t *journal, unsigned long *retp) * ready. */ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr, - unsigned long *retp) + sector_t *retp) { int err = 0; - unsigned long ret; + sector_t ret; if (journal->j_inode) { ret = bmap(journal->j_inode, blocknr); @@ -618,7 +618,7 @@ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr, struct journal_head *jbd2_journal_get_descriptor_buffer(journal_t *journal) { struct buffer_head *bh; - unsigned long blocknr; + sector_t blocknr; int err; err = jbd2_journal_next_log_block(journal, &blocknr); @@ -706,7 +706,7 @@ fail: */ journal_t * jbd2_journal_init_dev(struct block_device *bdev, struct block_device *fs_dev, - int start, int len, int blocksize) + sector_t start, int len, int blocksize) { journal_t *journal = journal_init_common(); struct buffer_head *bh; @@ -753,7 +753,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode) journal_t *journal = journal_init_common(); int err; int n; - unsigned long blocknr; + sector_t blocknr; if (!journal) return NULL; @@ -819,7 +819,7 @@ static void journal_fail_superblock (journal_t *journal) static int journal_reset(journal_t *journal) { journal_superblock_t *sb = journal->j_superblock; - unsigned long first, last; + sector_t first, last; first = be32_to_cpu(sb->s_first); last = be32_to_cpu(sb->s_maxlen); @@ -853,7 +853,7 @@ static int journal_reset(journal_t *journal) **/ int jbd2_journal_create(journal_t *journal) { - unsigned long blocknr; + sector_t blocknr; struct buffer_head *bh; journal_superblock_t *sb; int i, err; diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 2486843adda0..52054a83e717 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -70,7 +70,7 @@ static int do_readahead(journal_t *journal, unsigned int start) { int err; unsigned int max, nbufs, next; - unsigned long blocknr; + sector_t blocknr; struct buffer_head *bh; struct buffer_head * bufs[MAXBUF]; @@ -132,7 +132,7 @@ static int jread(struct buffer_head **bhp, journal_t *journal, unsigned int offset) { int err; - unsigned long blocknr; + sector_t blocknr; struct buffer_head *bh; *bhp = NULL; @@ -452,7 +452,7 @@ static int do_one_pass(journal_t *journal, "block %ld in log\n", err, io_block); } else { - unsigned long blocknr; + sector_t blocknr; J_ASSERT(obh != NULL); blocknr = read_tag_block(tag_bytes, @@ -592,7 +592,7 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, record_len = 8; while (offset + record_len <= max) { - unsigned long blocknr; + sector_t blocknr; int err; if (record_len == 4) diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 8aac875bd301..3310a1d7ace9 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -81,7 +81,7 @@ struct jbd2_revoke_record_s { struct list_head hash; tid_t sequence; /* Used for recovery only */ - unsigned long blocknr; + sector_t blocknr; }; @@ -106,17 +106,18 @@ static void flush_descriptor(journal_t *, struct journal_head *, int); /* Utility functions to maintain the revoke table */ /* Borrowed from buffer.c: this is a tried and tested block hash function */ -static inline int hash(journal_t *journal, unsigned long block) +static inline int hash(journal_t *journal, sector_t block) { struct jbd2_revoke_table_s *table = journal->j_revoke; int hash_shift = table->hash_shift; + int hash = (int)block ^ (int)((block >> 31) >> 1); - return ((block << (hash_shift - 6)) ^ - (block >> 13) ^ - (block << (hash_shift - 12))) & (table->hash_size - 1); + return ((hash << (hash_shift - 6)) ^ + (hash >> 13) ^ + (hash << (hash_shift - 12))) & (table->hash_size - 1); } -static int insert_revoke_hash(journal_t *journal, unsigned long blocknr, +static int insert_revoke_hash(journal_t *journal, sector_t blocknr, tid_t seq) { struct list_head *hash_list; @@ -146,7 +147,7 @@ oom: /* Find a revoke record in the journal's hash table. */ static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal, - unsigned long blocknr) + sector_t blocknr) { struct list_head *hash_list; struct jbd2_revoke_record_s *record; @@ -325,7 +326,7 @@ void jbd2_journal_destroy_revoke(journal_t *journal) * by one. */ -int jbd2_journal_revoke(handle_t *handle, unsigned long blocknr, +int jbd2_journal_revoke(handle_t *handle, sector_t blocknr, struct buffer_head *bh_in) { struct buffer_head *bh = NULL; @@ -394,7 +395,7 @@ int jbd2_journal_revoke(handle_t *handle, unsigned long blocknr, } } - jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in); + jbd_debug(2, "insert revoke for block %llu, bh_in=%p\n",blocknr, bh_in); err = insert_revoke_hash(journal, blocknr, handle->h_transaction->t_tid); BUFFER_TRACE(bh_in, "exit"); @@ -649,7 +650,7 @@ static void flush_descriptor(journal_t *journal, */ int jbd2_journal_set_revoke(journal_t *journal, - unsigned long blocknr, + sector_t blocknr, tid_t sequence) { struct jbd2_revoke_record_s *record; @@ -673,7 +674,7 @@ int jbd2_journal_set_revoke(journal_t *journal, */ int jbd2_journal_test_revoke(journal_t *journal, - unsigned long blocknr, + sector_t blocknr, tid_t sequence) { struct jbd2_revoke_record_s *record; diff --git a/include/linux/ext4_jbd2.h b/include/linux/ext4_jbd2.h index f69af60d7692..72dd631912e4 100644 --- a/include/linux/ext4_jbd2.h +++ b/include/linux/ext4_jbd2.h @@ -154,7 +154,7 @@ __ext4_journal_forget(const char *where, handle_t *handle, struct buffer_head *b static inline int __ext4_journal_revoke(const char *where, handle_t *handle, - unsigned long blocknr, struct buffer_head *bh) + ext4_fsblk_t blocknr, struct buffer_head *bh) { int err = jbd2_journal_revoke(handle, blocknr, bh); if (err) diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 5e5aa64f1261..3c939c844a7d 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -741,7 +741,7 @@ struct journal_s */ struct block_device *j_dev; int j_blocksize; - unsigned long j_blk_offset; + sector_t j_blk_offset; /* * Device which holds the client fs. For internal journal this will be @@ -860,7 +860,7 @@ extern void __journal_clean_data_list(transaction_t *transaction); /* Log buffer allocation */ extern struct journal_head * jbd2_journal_get_descriptor_buffer(journal_t *); -int jbd2_journal_next_log_block(journal_t *, unsigned long *); +int jbd2_journal_next_log_block(journal_t *, sector_t *); /* Commit management */ extern void jbd2_journal_commit_transaction(journal_t *); @@ -875,7 +875,7 @@ extern int jbd2_journal_write_metadata_buffer(transaction_t *transaction, struct journal_head *jh_in, struct journal_head **jh_out, - unsigned long blocknr); + sector_t blocknr); /* Transaction locking */ extern void __wait_on_journal (journal_t *); @@ -923,7 +923,7 @@ extern void jbd2_journal_unlock_updates (journal_t *); extern journal_t * jbd2_journal_init_dev(struct block_device *bdev, struct block_device *fs_dev, - int start, int len, int bsize); + sector_t start, int len, int bsize); extern journal_t * jbd2_journal_init_inode (struct inode *); extern int jbd2_journal_update_format (journal_t *); extern int jbd2_journal_check_used_features @@ -944,7 +944,7 @@ extern void jbd2_journal_abort (journal_t *, int); extern int jbd2_journal_errno (journal_t *); extern void jbd2_journal_ack_err (journal_t *); extern int jbd2_journal_clear_err (journal_t *); -extern int jbd2_journal_bmap(journal_t *, unsigned long, unsigned long *); +extern int jbd2_journal_bmap(journal_t *, unsigned long, sector_t *); extern int jbd2_journal_force_commit(journal_t *); /* @@ -977,14 +977,13 @@ extern void jbd2_journal_destroy_revoke_caches(void); extern int jbd2_journal_init_revoke_caches(void); extern void jbd2_journal_destroy_revoke(journal_t *); -extern int jbd2_journal_revoke (handle_t *, - unsigned long, struct buffer_head *); +extern int jbd2_journal_revoke (handle_t *, sector_t, struct buffer_head *); extern int jbd2_journal_cancel_revoke(handle_t *, struct journal_head *); extern void jbd2_journal_write_revoke_records(journal_t *, transaction_t *); /* Recovery revoke support */ -extern int jbd2_journal_set_revoke(journal_t *, unsigned long, tid_t); -extern int jbd2_journal_test_revoke(journal_t *, unsigned long, tid_t); +extern int jbd2_journal_set_revoke(journal_t *, sector_t, tid_t); +extern int jbd2_journal_test_revoke(journal_t *, sector_t, tid_t); extern void jbd2_journal_clear_revoke(journal_t *); extern void jbd2_journal_switch_revoke_table(journal_t *journal); -- cgit v1.2.3 From a1ddeb7eaecea6a924e3a79aa386797020cb436f Mon Sep 17 00:00:00 2001 From: Badari Pulavarty Date: Wed, 11 Oct 2006 01:21:09 -0700 Subject: [PATCH] ext4: 48bit i_file_acl As we are planning to support 48-bit block numbers for ext4, we need to support 48-bit block numbers for extended attributes. In the short term, we can do this by reuse (on-disk) 16-bit padding (linux2.i_pad1 currently used only by "hurd") as high order bits for xattr. This patch basically does that. Signed-off-by: Badari Pulavarty Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/inode.c | 10 ++++++++++ include/linux/ext4_fs.h | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2b81b1324a6f..9db8cff3baa4 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2643,6 +2643,11 @@ void ext4_read_inode(struct inode * inode) ei->i_frag_size = raw_inode->i_fsize; #endif ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl); + if ((sizeof(sector_t) > 4) && + (EXT4_SB(inode->i_sb)->s_es->s_creator_os != + cpu_to_le32(EXT4_OS_HURD))) + ei->i_file_acl |= + ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32; if (!S_ISREG(inode->i_mode)) { ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); } else { @@ -2776,6 +2781,11 @@ static int ext4_do_update_inode(handle_t *handle, raw_inode->i_frag = ei->i_frag_no; raw_inode->i_fsize = ei->i_frag_size; #endif + if ((sizeof(sector_t) > 4) && + (EXT4_SB(inode->i_sb)->s_es->s_creator_os != + cpu_to_le32(EXT4_OS_HURD))) + raw_inode->i_file_acl_high = + cpu_to_le16(ei->i_file_acl >> 32); raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl); if (!S_ISREG(inode->i_mode)) { raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl); diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index e952c6db9690..63ed89f5b27b 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -298,7 +298,7 @@ struct ext4_inode { struct { __u8 l_i_frag; /* Fragment number */ __u8 l_i_fsize; /* Fragment size */ - __u16 i_pad1; + __le16 l_i_file_acl_high; __le16 l_i_uid_high; /* these 2 fields */ __le16 l_i_gid_high; /* were reserved2[0] */ __u32 l_i_reserved2; @@ -314,7 +314,7 @@ struct ext4_inode { struct { __u8 m_i_frag; /* Fragment number */ __u8 m_i_fsize; /* Fragment size */ - __u16 m_pad1; + __le16 m_i_file_acl_high; __u32 m_i_reserved2[2]; } masix2; } osd2; /* OS dependent 2 */ @@ -328,6 +328,7 @@ struct ext4_inode { #define i_reserved1 osd1.linux1.l_i_reserved1 #define i_frag osd2.linux2.l_i_frag #define i_fsize osd2.linux2.l_i_fsize +#define i_file_acl_high osd2.linux2.l_i_file_acl_high #define i_uid_low i_uid #define i_gid_low i_gid #define i_uid_high osd2.linux2.l_i_uid_high @@ -348,6 +349,7 @@ struct ext4_inode { #define i_reserved1 osd1.masix1.m_i_reserved1 #define i_frag osd2.masix2.m_i_frag #define i_fsize osd2.masix2.m_i_fsize +#define i_file_acl_high osd2.masix2.m_i_file_acl_high #define i_reserved2 osd2.masix2.m_i_reserved2 #endif /* defined(__KERNEL__) || defined(__linux__) */ -- cgit v1.2.3 From bd81d8eec043094d3ff729a8ff6d5b3a06d3c4b1 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 11 Oct 2006 01:21:10 -0700 Subject: [PATCH] ext4: 64bit metadata In-kernel super block changes to support >32 bit free blocks numbers. Signed-off-by: Laurent Vivier Signed-off-by: Dave Kleikamp Signed-off-by: Alexandre Ratchov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/balloc.c | 50 +++++++++++++------------- fs/ext4/ialloc.c | 8 ++--- fs/ext4/inode.c | 6 ++-- fs/ext4/resize.c | 52 ++++++++++++++------------- fs/ext4/super.c | 96 ++++++++++++++++++++++++++++++++++--------------- include/linux/ext4_fs.h | 86 +++++++++++++++++++++++++++++++++++++------- 6 files changed, 201 insertions(+), 97 deletions(-) (limited to 'include/linux') diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index aa33ff271fa9..6887151ccc47 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -99,12 +99,13 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) desc = ext4_get_group_desc (sb, block_group, NULL); if (!desc) goto error_out; - bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); + bh = sb_bread(sb, ext4_block_bitmap(desc)); if (!bh) ext4_error (sb, "read_block_bitmap", "Cannot read block bitmap - " - "block_group = %d, block_bitmap = %u", - block_group, le32_to_cpu(desc->bg_block_bitmap)); + "block_group = %d, block_bitmap = "E3FSBLK, + block_group, + ext4_block_bitmap(desc)); error_out: return bh; } @@ -432,14 +433,14 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, es = sbi->s_es; if (block < le32_to_cpu(es->s_first_data_block) || block + count < block || - block + count > le32_to_cpu(es->s_blocks_count)) { + block + count > ext4_blocks_count(es)) { ext4_error (sb, "ext4_free_blocks", "Freeing blocks not in datazone - " "block = "E3FSBLK", count = %lu", block, count); goto error_return; } - ext4_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1); + ext4_debug ("freeing block(s) %llu-%llu\n", block, block + count - 1); do_more: overflow = 0; @@ -460,12 +461,11 @@ do_more: if (!desc) goto error_return; - if (in_range (le32_to_cpu(desc->bg_block_bitmap), block, count) || - in_range (le32_to_cpu(desc->bg_inode_bitmap), block, count) || - in_range (block, le32_to_cpu(desc->bg_inode_table), - sbi->s_itb_per_group) || - in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table), - sbi->s_itb_per_group)) + if (in_range(ext4_block_bitmap(desc), block, count) || + in_range(ext4_inode_bitmap(desc), block, count) || + in_range(block, ext4_inode_table(desc), sbi->s_itb_per_group) || + in_range(block + count - 1, ext4_inode_table(desc), + sbi->s_itb_per_group)) ext4_error (sb, "ext4_free_blocks", "Freeing blocks in system zones - " "Block = "E3FSBLK", count = %lu", @@ -552,8 +552,8 @@ do_more: bit + i, bitmap_bh->b_data)) { jbd_unlock_bh_state(bitmap_bh); ext4_error(sb, __FUNCTION__, - "bit already cleared for block "E3FSBLK, - block + i); + "bit already cleared for block "E3FSBLK, + (ext4_fsblk_t)(block + i)); jbd_lock_bh_state(bitmap_bh); BUFFER_TRACE(bitmap_bh, "bit already cleared"); } else { @@ -1351,7 +1351,7 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi) ext4_fsblk_t free_blocks, root_blocks; free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); - root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); + root_blocks = ext4_r_blocks_count(sbi->s_es); if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && sbi->s_resuid != current->fsuid && (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { @@ -1462,7 +1462,7 @@ ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, * First, test whether the goal block is free. */ if (goal < le32_to_cpu(es->s_first_data_block) || - goal >= le32_to_cpu(es->s_blocks_count)) + goal >= ext4_blocks_count(es)) goal = le32_to_cpu(es->s_first_data_block); ext4_get_group_no_and_offset(sb, goal, &group_no, &grp_target_blk); goal_group = group_no; @@ -1561,12 +1561,12 @@ allocated: ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no); - if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) || - in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) || - in_range(ret_block, le32_to_cpu(gdp->bg_inode_table), - EXT4_SB(sb)->s_itb_per_group) || - in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table), - EXT4_SB(sb)->s_itb_per_group)) + if (in_range(ext4_block_bitmap(gdp), ret_block, num) || + in_range(ext4_block_bitmap(gdp), ret_block, num) || + in_range(ret_block, ext4_inode_table(gdp), + EXT4_SB(sb)->s_itb_per_group) || + in_range(ret_block + num - 1, ext4_inode_table(gdp), + EXT4_SB(sb)->s_itb_per_group)) ext4_error(sb, "ext4_new_block", "Allocating block in system zone - " "blocks from "E3FSBLK", length %lu", @@ -1604,11 +1604,11 @@ allocated: jbd_unlock_bh_state(bitmap_bh); #endif - if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) { + if (ret_block + num - 1 >= ext4_blocks_count(es)) { ext4_error(sb, "ext4_new_block", - "block("E3FSBLK") >= blocks count(%d) - " + "block("E3FSBLK") >= blocks count("E3FSBLK") - " "block_group = %lu, es == %p ", ret_block, - le32_to_cpu(es->s_blocks_count), group_no, es); + ext4_blocks_count(es), group_no, es); goto out; } @@ -1707,7 +1707,7 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb) brelse(bitmap_bh); printk("ext4_count_free_blocks: stored = "E3FSBLK ", computed = "E3FSBLK", "E3FSBLK"\n", - le32_to_cpu(es->s_free_blocks_count), + EXT4_FREE_BLOCKS_COUNT(es), desc_count, bitmap_count); return bitmap_count; #else diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 94e1bb4abe31..959b7fa8f5db 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -60,12 +60,12 @@ read_inode_bitmap(struct super_block * sb, unsigned long block_group) if (!desc) goto error_out; - bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap)); + bh = sb_bread(sb, ext4_inode_bitmap(desc)); if (!bh) ext4_error(sb, "read_inode_bitmap", "Cannot read inode bitmap - " - "block_group = %lu, inode_bitmap = %u", - block_group, le32_to_cpu(desc->bg_inode_bitmap)); + "block_group = %lu, inode_bitmap = %llu", + block_group, ext4_inode_bitmap(desc)); error_out: return bh; } @@ -304,7 +304,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) goto fallback; } - blocks_per_dir = le32_to_cpu(es->s_blocks_count) - freeb; + blocks_per_dir = ext4_blocks_count(es) - freeb; sector_div(blocks_per_dir, ndirs); max_dirs = ndirs / ngroups + inodes_per_group / 16; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 9db8cff3baa4..effc38afebe3 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2438,8 +2438,8 @@ static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb, */ offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) * EXT4_INODE_SIZE(sb); - block = le32_to_cpu(gdp[desc].bg_inode_table) + - (offset >> EXT4_BLOCK_SIZE_BITS(sb)); + block = ext4_inode_table(gdp + desc) + + (offset >> EXT4_BLOCK_SIZE_BITS(sb)); iloc->block_group = block_group; iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1); @@ -2506,7 +2506,7 @@ static int __ext4_get_inode_loc(struct inode *inode, goto make_io; bitmap_bh = sb_getblk(inode->i_sb, - le32_to_cpu(desc->bg_inode_bitmap)); + ext4_inode_bitmap(desc)); if (!bitmap_bh) goto make_io; diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index c60bfed5f5e7..3dbf91b82202 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -27,7 +27,7 @@ static int verify_group_input(struct super_block *sb, { struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; - ext4_fsblk_t start = le32_to_cpu(es->s_blocks_count); + ext4_fsblk_t start = ext4_blocks_count(es); ext4_fsblk_t end = start + input->blocks_count; unsigned group = input->group; ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; @@ -68,43 +68,43 @@ static int verify_group_input(struct super_block *sb, end - 1); else if (outside(input->block_bitmap, start, end)) ext4_warning(sb, __FUNCTION__, - "Block bitmap not in group (block %u)", + "Block bitmap not in group (block %llu)", input->block_bitmap); else if (outside(input->inode_bitmap, start, end)) ext4_warning(sb, __FUNCTION__, - "Inode bitmap not in group (block %u)", + "Inode bitmap not in group (block %llu)", input->inode_bitmap); else if (outside(input->inode_table, start, end) || outside(itend - 1, start, end)) ext4_warning(sb, __FUNCTION__, - "Inode table not in group (blocks %u-"E3FSBLK")", + "Inode table not in group (blocks %llu-%llu)", input->inode_table, itend - 1); else if (input->inode_bitmap == input->block_bitmap) ext4_warning(sb, __FUNCTION__, - "Block bitmap same as inode bitmap (%u)", + "Block bitmap same as inode bitmap (%llu)", input->block_bitmap); else if (inside(input->block_bitmap, input->inode_table, itend)) ext4_warning(sb, __FUNCTION__, - "Block bitmap (%u) in inode table (%u-"E3FSBLK")", + "Block bitmap (%llu) in inode table (%llu-%llu)", input->block_bitmap, input->inode_table, itend-1); else if (inside(input->inode_bitmap, input->inode_table, itend)) ext4_warning(sb, __FUNCTION__, - "Inode bitmap (%u) in inode table (%u-"E3FSBLK")", + "Inode bitmap (%llu) in inode table (%llu-%llu)", input->inode_bitmap, input->inode_table, itend-1); else if (inside(input->block_bitmap, start, metaend)) ext4_warning(sb, __FUNCTION__, - "Block bitmap (%u) in GDT table" + "Block bitmap (%llu) in GDT table" " ("E3FSBLK"-"E3FSBLK")", input->block_bitmap, start, metaend - 1); else if (inside(input->inode_bitmap, start, metaend)) ext4_warning(sb, __FUNCTION__, - "Inode bitmap (%u) in GDT table" + "Inode bitmap (%llu) in GDT table" " ("E3FSBLK"-"E3FSBLK")", input->inode_bitmap, start, metaend - 1); else if (inside(input->inode_table, start, metaend) || inside(itend - 1, start, metaend)) ext4_warning(sb, __FUNCTION__, - "Inode table (%u-"E3FSBLK") overlaps" + "Inode table ("E3FSBLK"-"E3FSBLK") overlaps" "GDT table ("E3FSBLK"-"E3FSBLK")", input->inode_table, itend - 1, start, metaend - 1); else @@ -286,6 +286,7 @@ exit_journal: return err; } + /* * Iterate through the groups which hold BACKUP superblock/GDT copies in an * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before @@ -340,12 +341,15 @@ static int verify_reserved_gdb(struct super_block *sb, int gdbackups = 0; while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) { - if (le32_to_cpu(*p++) != grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){ + if (le32_to_cpu(*p++) != + grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){ ext4_warning(sb, __FUNCTION__, "reserved GDT "E3FSBLK " missing grp %d ("E3FSBLK")", blk, grp, - grp * EXT4_BLOCKS_PER_GROUP(sb) + blk); + grp * + (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) + + blk); return -EINVAL; } if (++gdbackups > EXT4_ADDR_PER_BLOCK(sb)) @@ -731,8 +735,8 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) return -EPERM; } - if (le32_to_cpu(es->s_blocks_count) + input->blocks_count < - le32_to_cpu(es->s_blocks_count)) { + if (ext4_blocks_count(es) + input->blocks_count < + ext4_blocks_count(es)) { ext4_warning(sb, __FUNCTION__, "blocks_count overflow\n"); return -EINVAL; } @@ -830,9 +834,9 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) /* Update group descriptor block for new group */ gdp = (struct ext4_group_desc *)primary->b_data + gdb_off; - gdp->bg_block_bitmap = cpu_to_le32(input->block_bitmap); - gdp->bg_inode_bitmap = cpu_to_le32(input->inode_bitmap); - gdp->bg_inode_table = cpu_to_le32(input->inode_table); + ext4_block_bitmap_set(gdp, input->block_bitmap); /* LV FIXME */ + ext4_inode_bitmap_set(gdp, input->inode_bitmap); /* LV FIXME */ + ext4_inode_table_set(gdp, input->inode_table); /* LV FIXME */ gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb)); @@ -846,7 +850,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) * blocks/inodes before the group is live won't actually let us * allocate the new space yet. */ - es->s_blocks_count = cpu_to_le32(le32_to_cpu(es->s_blocks_count) + + ext4_blocks_count_set(es, ext4_blocks_count(es) + input->blocks_count); es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) + EXT4_INODES_PER_GROUP(sb)); @@ -882,7 +886,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) /* Update the reserved block counts only once the new group is * active. */ - es->s_r_blocks_count = cpu_to_le32(le32_to_cpu(es->s_r_blocks_count) + + ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) + input->reserved_blocks); /* Update the free space counts */ @@ -933,7 +937,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, /* We don't need to worry about locking wrt other resizers just * yet: we're going to revalidate es->s_blocks_count after * taking lock_super() below. */ - o_blocks_count = le32_to_cpu(es->s_blocks_count); + o_blocks_count = ext4_blocks_count(es); o_groups_count = EXT4_SB(sb)->s_groups_count; if (test_opt(sb, DEBUG)) @@ -1004,7 +1008,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, } lock_super(sb); - if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) { + if (o_blocks_count != ext4_blocks_count(es)) { ext4_warning(sb, __FUNCTION__, "multiple resizers run on filesystem!"); unlock_super(sb); @@ -1020,7 +1024,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, ext4_journal_stop(handle); goto exit_put; } - es->s_blocks_count = cpu_to_le32(o_blocks_count + add); + ext4_blocks_count_set(es, o_blocks_count + add); ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); sb->s_dirt = 1; unlock_super(sb); @@ -1032,8 +1036,8 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, if ((err = ext4_journal_stop(handle))) goto exit_put; if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT4-fs: extended group to %u blocks\n", - le32_to_cpu(es->s_blocks_count)); + printk(KERN_DEBUG "EXT4-fs: extended group to %llu blocks\n", + ext4_blocks_count(es)); update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, (char *)es, sizeof(struct ext4_super_block)); exit_put: diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 1d12e4f7d69f..b91dffd7a031 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -62,6 +62,43 @@ static void ext4_unlockfs(struct super_block *sb); static void ext4_write_super (struct super_block * sb); static void ext4_write_super_lockfs(struct super_block *sb); + +ext4_fsblk_t ext4_block_bitmap(struct ext4_group_desc *bg) +{ + return le32_to_cpu(bg->bg_block_bitmap) | + ((ext4_fsblk_t)le16_to_cpu(bg->bg_block_bitmap_hi) << 32); +} + +ext4_fsblk_t ext4_inode_bitmap(struct ext4_group_desc *bg) +{ + return le32_to_cpu(bg->bg_inode_bitmap) | + ((ext4_fsblk_t)le16_to_cpu(bg->bg_inode_bitmap_hi) << 32); +} + +ext4_fsblk_t ext4_inode_table(struct ext4_group_desc *bg) +{ + return le32_to_cpu(bg->bg_inode_table) | + ((ext4_fsblk_t)le16_to_cpu(bg->bg_inode_table_hi) << 32); +} + +void ext4_block_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk) +{ + bg->bg_block_bitmap = cpu_to_le32((u32)blk); + bg->bg_block_bitmap_hi = cpu_to_le16(blk >> 32); +} + +void ext4_inode_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk) +{ + bg->bg_inode_bitmap = cpu_to_le32((u32)blk); + bg->bg_inode_bitmap_hi = cpu_to_le16(blk >> 32); +} + +void ext4_inode_table_set(struct ext4_group_desc *bg, ext4_fsblk_t blk) +{ + bg->bg_inode_table = cpu_to_le32((u32)blk); + bg->bg_inode_table_hi = cpu_to_le16(blk >> 32); +} + /* * Wrappers for jbd2_journal_start/end. * @@ -1182,6 +1219,9 @@ static int ext4_check_descriptors (struct super_block * sb) struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); ext4_fsblk_t last_block; + ext4_fsblk_t block_bitmap; + ext4_fsblk_t inode_bitmap; + ext4_fsblk_t inode_table; struct ext4_group_desc * gdp = NULL; int desc_block = 0; int i; @@ -1191,7 +1231,7 @@ static int ext4_check_descriptors (struct super_block * sb) for (i = 0; i < sbi->s_groups_count; i++) { if (i == sbi->s_groups_count - 1) - last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; + last_block = ext4_blocks_count(sbi->s_es) - 1; else last_block = first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1); @@ -1199,42 +1239,39 @@ static int ext4_check_descriptors (struct super_block * sb) if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0) gdp = (struct ext4_group_desc *) sbi->s_group_desc[desc_block++]->b_data; - if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || - le32_to_cpu(gdp->bg_block_bitmap) > last_block) + block_bitmap = ext4_block_bitmap(gdp); + if (block_bitmap < first_block || block_bitmap > last_block) { ext4_error (sb, "ext4_check_descriptors", "Block bitmap for group %d" - " not in group (block %lu)!", - i, (unsigned long) - le32_to_cpu(gdp->bg_block_bitmap)); + " not in group (block "E3FSBLK")!", + i, block_bitmap); return 0; } - if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || - le32_to_cpu(gdp->bg_inode_bitmap) > last_block) + inode_bitmap = ext4_inode_bitmap(gdp); + if (inode_bitmap < first_block || inode_bitmap > last_block) { ext4_error (sb, "ext4_check_descriptors", "Inode bitmap for group %d" - " not in group (block %lu)!", - i, (unsigned long) - le32_to_cpu(gdp->bg_inode_bitmap)); + " not in group (block "E3FSBLK")!", + i, inode_bitmap); return 0; } - if (le32_to_cpu(gdp->bg_inode_table) < first_block || - le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group > - last_block) + inode_table = ext4_inode_table(gdp); + if (inode_table < first_block || + inode_table + sbi->s_itb_per_group > last_block) { ext4_error (sb, "ext4_check_descriptors", "Inode table for group %d" - " not in group (block %lu)!", - i, (unsigned long) - le32_to_cpu(gdp->bg_inode_table)); + " not in group (block "E3FSBLK")!", + i, inode_table); return 0; } first_block += EXT4_BLOCKS_PER_GROUP(sb); gdp++; } - sbi->s_es->s_free_blocks_count=cpu_to_le32(ext4_count_free_blocks(sb)); + ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb)); sbi->s_es->s_free_inodes_count=cpu_to_le32(ext4_count_free_inodes(sb)); return 1; } @@ -1411,6 +1448,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) int i; int needs_recovery; __le32 features; + __u64 blocks_count; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) @@ -1620,7 +1658,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) goto failed_mount; } - if (le32_to_cpu(es->s_blocks_count) > + if (ext4_blocks_count(es) > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { printk(KERN_ERR "EXT4-fs: filesystem on %s:" " too large to mount safely\n", sb->s_id); @@ -1632,9 +1670,11 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) if (EXT4_BLOCKS_PER_GROUP(sb) == 0) goto cantfind_ext4; - sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - - le32_to_cpu(es->s_first_data_block) - 1) - / EXT4_BLOCKS_PER_GROUP(sb)) + 1; + blocks_count = (ext4_blocks_count(es) - + le32_to_cpu(es->s_first_data_block) + + EXT4_BLOCKS_PER_GROUP(sb) - 1); + do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb)); + sbi->s_groups_count = blocks_count; db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / EXT4_DESC_PER_BLOCK(sb); sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), @@ -1949,7 +1989,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, goto out_bdev; } - len = le32_to_cpu(es->s_blocks_count); + len = ext4_blocks_count(es); start = sb_block + 1; brelse(bh); /* we're done with the superblock */ @@ -2119,7 +2159,7 @@ static void ext4_commit_super (struct super_block * sb, if (!sbh) return; es->s_wtime = cpu_to_le32(get_seconds()); - es->s_free_blocks_count = cpu_to_le32(ext4_count_free_blocks(sb)); + ext4_free_blocks_count_set(es, ext4_count_free_blocks(sb)); es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb)); BUFFER_TRACE(sbh, "marking dirty"); mark_buffer_dirty(sbh); @@ -2312,7 +2352,7 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data) ext4_init_journal_params(sb, sbi->s_journal); if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || - n_blocks_count > le32_to_cpu(es->s_blocks_count)) { + n_blocks_count > ext4_blocks_count(es)) { if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) { err = -EROFS; goto restore_opts; @@ -2431,10 +2471,10 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf) buf->f_type = EXT4_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; - buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead; + buf->f_blocks = ext4_blocks_count(es) - overhead; buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); - buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count); - if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count)) + buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); + if (buf->f_bfree < ext4_r_blocks_count(es)) buf->f_bavail = 0; buf->f_files = le32_to_cpu(es->s_inodes_count); buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index 63ed89f5b27b..8e5009ee4ad8 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -128,10 +128,17 @@ struct ext4_group_desc __le16 bg_free_blocks_count; /* Free blocks count */ __le16 bg_free_inodes_count; /* Free inodes count */ __le16 bg_used_dirs_count; /* Directories count */ - __u16 bg_pad; - __le32 bg_reserved[3]; + __u16 bg_flags; + __le16 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ + __le16 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ + __le16 bg_inode_table_hi; /* Inodes table block MSB */ + __u16 bg_reserved[3]; }; +#ifdef __KERNEL__ +#include +#include +#endif /* * Macro-instructions used to manage group descriptors */ @@ -194,9 +201,9 @@ struct ext4_group_desc /* Used to pass group descriptor data when online resize is done */ struct ext4_new_group_input { __u32 group; /* Group number for this data */ - __u32 block_bitmap; /* Absolute block number of block bitmap */ - __u32 inode_bitmap; /* Absolute block number of inode bitmap */ - __u32 inode_table; /* Absolute block number of inode table start */ + __u64 block_bitmap; /* Absolute block number of block bitmap */ + __u64 inode_bitmap; /* Absolute block number of inode bitmap */ + __u64 inode_table; /* Absolute block number of inode table start */ __u32 blocks_count; /* Total number of blocks in this group */ __u16 reserved_blocks; /* Number of reserved blocks in this group */ __u16 unused; @@ -205,9 +212,9 @@ struct ext4_new_group_input { /* The struct ext4_new_group_input in kernel space, with free_blocks_count */ struct ext4_new_group_data { __u32 group; - __u32 block_bitmap; - __u32 inode_bitmap; - __u32 inode_table; + __u64 block_bitmap; + __u64 inode_bitmap; + __u64 inode_table; __u32 blocks_count; __u16 reserved_blocks; __u16 unused; @@ -494,14 +501,18 @@ struct ext4_super_block { __u8 s_def_hash_version; /* Default hash version to use */ __u8 s_reserved_char_pad; __u16 s_reserved_word_pad; - __le32 s_default_mount_opts; +/*100*/ __le32 s_default_mount_opts; __le32 s_first_meta_bg; /* First metablock block group */ - __u32 s_reserved[190]; /* Padding to the end of the block */ + __le32 s_mkfs_time; /* When the filesystem was created */ + __le32 s_jnl_blocks[17]; /* Backup of the journal inode */ + /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */ +/*150*/ __le32 s_blocks_count_hi; /* Blocks count */ + __le32 s_r_blocks_count_hi; /* Reserved blocks count */ + __le32 s_free_blocks_count_hi; /* Free blocks count */ + __u32 s_reserved[169]; /* Padding to the end of the block */ }; #ifdef __KERNEL__ -#include -#include static inline struct ext4_sb_info * EXT4_SB(struct super_block *sb) { return sb->s_fs_info; @@ -588,12 +599,14 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) #define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ #define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 #define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR #define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ EXT4_FEATURE_INCOMPAT_RECOVER| \ EXT4_FEATURE_INCOMPAT_META_BG| \ - EXT4_FEATURE_INCOMPAT_EXTENTS) + EXT4_FEATURE_INCOMPAT_EXTENTS| \ + EXT4_FEATURE_INCOMPAT_64BIT) #define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ EXT4_FEATURE_RO_COMPAT_BTREE_DIR) @@ -888,6 +901,53 @@ extern void ext4_abort (struct super_block *, const char *, const char *, ...) extern void ext4_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); extern void ext4_update_dynamic_rev (struct super_block *sb); +extern ext4_fsblk_t ext4_block_bitmap(struct ext4_group_desc *bg); +extern ext4_fsblk_t ext4_inode_bitmap(struct ext4_group_desc *bg); +extern ext4_fsblk_t ext4_inode_table(struct ext4_group_desc *bg); +extern void ext4_block_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk); +extern void ext4_inode_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk); +extern void ext4_inode_table_set(struct ext4_group_desc *bg, ext4_fsblk_t blk); + +static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) +{ + return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) | + le32_to_cpu(es->s_blocks_count); +} + +static inline ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es) +{ + return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) | + le32_to_cpu(es->s_r_blocks_count); +} + +static inline ext4_fsblk_t ext4_free_blocks_count(struct ext4_super_block *es) +{ + return ((ext4_fsblk_t)le32_to_cpu(es->s_free_blocks_count_hi) << 32) | + le32_to_cpu(es->s_free_blocks_count); +} + +static inline void ext4_blocks_count_set(struct ext4_super_block *es, + ext4_fsblk_t blk) +{ + es->s_blocks_count = cpu_to_le32((u32)blk); + es->s_blocks_count_hi = cpu_to_le32(blk >> 32); +} + +static inline void ext4_free_blocks_count_set(struct ext4_super_block *es, + ext4_fsblk_t blk) +{ + es->s_free_blocks_count = cpu_to_le32((u32)blk); + es->s_free_blocks_count_hi = cpu_to_le32(blk >> 32); +} + +static inline void ext4_r_blocks_count_set(struct ext4_super_block *es, + ext4_fsblk_t blk) +{ + es->s_r_blocks_count = cpu_to_le32((u32)blk); + es->s_r_blocks_count_hi = cpu_to_le32(blk >> 32); +} + + #define ext4_std_error(sb, errno) \ do { \ -- cgit v1.2.3 From 2ae0210760aed9d626eaede5b63db95e198f7c8e Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:21:11 -0700 Subject: [PATCH] ext4: blk_type from sector_t to unsigned long long Change ext4 in-kernel block type (ext4_fsblk_t) from sector_t to unsigned long long. Remove ext4 block type string micro E3FSBLK, replaced with "%llu" [akpm@osdl.org: build fix] Signed-off-by: Mingming Cao Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/balloc.c | 18 +++++++++--------- fs/ext4/extents.c | 38 +++++++++++++++++++------------------- fs/ext4/inode.c | 6 +++--- fs/ext4/resize.c | 28 ++++++++++++++-------------- fs/ext4/super.c | 6 +++--- fs/ext4/xattr.c | 12 ++++++------ include/linux/ext4_fs_i.h | 8 +------- 7 files changed, 55 insertions(+), 61 deletions(-) (limited to 'include/linux') diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 6887151ccc47..df77ea891f29 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -103,7 +103,7 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) if (!bh) ext4_error (sb, "read_block_bitmap", "Cannot read block bitmap - " - "block_group = %d, block_bitmap = "E3FSBLK, + "block_group = %d, block_bitmap = %llu", block_group, ext4_block_bitmap(desc)); error_out: @@ -148,7 +148,7 @@ restart: rsv = list_entry(n, struct ext4_reserve_window_node, rsv_node); if (verbose) printk("reservation window 0x%p " - "start: "E3FSBLK", end: "E3FSBLK"\n", + "start: %llu, end: %llu\n", rsv, rsv->rsv_start, rsv->rsv_end); if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) { printk("Bad reservation %p (start >= end)\n", @@ -436,7 +436,7 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, block + count > ext4_blocks_count(es)) { ext4_error (sb, "ext4_free_blocks", "Freeing blocks not in datazone - " - "block = "E3FSBLK", count = %lu", block, count); + "block = %llu, count = %lu", block, count); goto error_return; } @@ -468,7 +468,7 @@ do_more: sbi->s_itb_per_group)) ext4_error (sb, "ext4_free_blocks", "Freeing blocks in system zones - " - "Block = "E3FSBLK", count = %lu", + "Block = %llu, count = %lu", block, count); /* @@ -552,7 +552,7 @@ do_more: bit + i, bitmap_bh->b_data)) { jbd_unlock_bh_state(bitmap_bh); ext4_error(sb, __FUNCTION__, - "bit already cleared for block "E3FSBLK, + "bit already cleared for block %llu", (ext4_fsblk_t)(block + i)); jbd_lock_bh_state(bitmap_bh); BUFFER_TRACE(bitmap_bh, "bit already cleared"); @@ -1569,7 +1569,7 @@ allocated: EXT4_SB(sb)->s_itb_per_group)) ext4_error(sb, "ext4_new_block", "Allocating block in system zone - " - "blocks from "E3FSBLK", length %lu", + "blocks from %llu, length %lu", ret_block, num); performed_allocation = 1; @@ -1606,7 +1606,7 @@ allocated: if (ret_block + num - 1 >= ext4_blocks_count(es)) { ext4_error(sb, "ext4_new_block", - "block("E3FSBLK") >= blocks count("E3FSBLK") - " + "block(%llu) >= blocks count(%llu) - " "block_group = %lu, es == %p ", ret_block, ext4_blocks_count(es), group_no, es); goto out; @@ -1705,8 +1705,8 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb) bitmap_count += x; } brelse(bitmap_bh); - printk("ext4_count_free_blocks: stored = "E3FSBLK - ", computed = "E3FSBLK", "E3FSBLK"\n", + printk("ext4_count_free_blocks: stored = %llu" + ", computed = %llu, %llu\n", EXT4_FREE_BLOCKS_COUNT(es), desc_count, bitmap_count); return bitmap_count; diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e06e937a52b8..f72b7567bfa2 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -281,10 +281,10 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) ext_debug("path:"); for (k = 0; k <= l; k++, path++) { if (path->p_idx) { - ext_debug(" %d->"E3FSBLK, le32_to_cpu(path->p_idx->ei_block), + ext_debug(" %d->%llu", le32_to_cpu(path->p_idx->ei_block), idx_pblock(path->p_idx)); } else if (path->p_ext) { - ext_debug(" %d:%d:"E3FSBLK" ", + ext_debug(" %d:%d:%llu ", le32_to_cpu(path->p_ext->ee_block), le16_to_cpu(path->p_ext->ee_len), ext_pblock(path->p_ext)); @@ -308,7 +308,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path) ex = EXT_FIRST_EXTENT(eh); for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) { - ext_debug("%d:%d:"E3FSBLK" ", le32_to_cpu(ex->ee_block), + ext_debug("%d:%d:%llu ", le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len), ext_pblock(ex)); } ext_debug("\n"); @@ -426,7 +426,7 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block) } path->p_ext = l - 1; - ext_debug(" -> %d:"E3FSBLK":%d ", + ext_debug(" -> %d:%llu:%d ", le32_to_cpu(path->p_ext->ee_block), ext_pblock(path->p_ext), le16_to_cpu(path->p_ext->ee_len)); @@ -687,7 +687,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, path[depth].p_ext++; while (path[depth].p_ext <= EXT_MAX_EXTENT(path[depth].p_hdr)) { - ext_debug("move %d:"E3FSBLK":%d in new leaf "E3FSBLK"\n", + ext_debug("move %d:%llu:%d in new leaf %llu\n", le32_to_cpu(path[depth].p_ext->ee_block), ext_pblock(path[depth].p_ext), le16_to_cpu(path[depth].p_ext->ee_len), @@ -752,7 +752,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, fidx->ei_block = border; ext4_idx_store_pblock(fidx, oldblock); - ext_debug("int.index at %d (block "E3FSBLK"): %lu -> "E3FSBLK"\n", i, + ext_debug("int.index at %d (block %llu): %lu -> %llu\n", i, newblock, (unsigned long) le32_to_cpu(border), oldblock); /* copy indexes */ @@ -764,7 +764,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, BUG_ON(EXT_MAX_INDEX(path[i].p_hdr) != EXT_LAST_INDEX(path[i].p_hdr)); while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) { - ext_debug("%d: move %d:%d in new index "E3FSBLK"\n", i, + ext_debug("%d: move %d:%d in new index %llu\n", i, le32_to_cpu(path[i].p_idx->ei_block), idx_pblock(path[i].p_idx), newblock); @@ -898,7 +898,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, neh = ext_inode_hdr(inode); fidx = EXT_FIRST_INDEX(neh); - ext_debug("new root: num %d(%d), lblock %d, ptr "E3FSBLK"\n", + ext_debug("new root: num %d(%d), lblock %d, ptr %llu\n", le16_to_cpu(neh->eh_entries), le16_to_cpu(neh->eh_max), le32_to_cpu(fidx->ei_block), idx_pblock(fidx)); @@ -1145,7 +1145,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, /* try to insert block into found extent and return */ if (ex && ext4_can_extents_be_merged(inode, ex, newext)) { - ext_debug("append %d block to %d:%d (from "E3FSBLK")\n", + ext_debug("append %d block to %d:%d (from %llu)\n", le16_to_cpu(newext->ee_len), le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len), ext_pblock(ex)); @@ -1204,7 +1204,7 @@ has_space: if (!nearex) { /* there is no extent in this leaf, create first one */ - ext_debug("first extent in the leaf: %d:"E3FSBLK":%d\n", + ext_debug("first extent in the leaf: %d:%llu:%d\n", le32_to_cpu(newext->ee_block), ext_pblock(newext), le16_to_cpu(newext->ee_len)); @@ -1216,7 +1216,7 @@ has_space: len = EXT_MAX_EXTENT(eh) - nearex; len = (len - 1) * sizeof(struct ext4_extent); len = len < 0 ? 0 : len; - ext_debug("insert %d:"E3FSBLK":%d after: nearest 0x%p, " + ext_debug("insert %d:%llu:%d after: nearest 0x%p, " "move %d from 0x%p to 0x%p\n", le32_to_cpu(newext->ee_block), ext_pblock(newext), @@ -1229,7 +1229,7 @@ has_space: BUG_ON(newext->ee_block == nearex->ee_block); len = (EXT_MAX_EXTENT(eh) - nearex) * sizeof(struct ext4_extent); len = len < 0 ? 0 : len; - ext_debug("insert %d:"E3FSBLK":%d before: nearest 0x%p, " + ext_debug("insert %d:%llu:%d before: nearest 0x%p, " "move %d from 0x%p to 0x%p\n", le32_to_cpu(newext->ee_block), ext_pblock(newext), @@ -1464,7 +1464,7 @@ ext4_ext_in_cache(struct inode *inode, unsigned long block, ex->ee_block = cpu_to_le32(cex->ec_block); ext4_ext_store_pblock(ex, cex->ec_start); ex->ee_len = cpu_to_le16(cex->ec_len); - ext_debug("%lu cached by %lu:%lu:"E3FSBLK"\n", + ext_debug("%lu cached by %lu:%lu:%llu\n", (unsigned long) block, (unsigned long) cex->ec_block, (unsigned long) cex->ec_len, @@ -1498,7 +1498,7 @@ int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1); if ((err = ext4_ext_dirty(handle, inode, path))) return err; - ext_debug("index is empty, remove it, free block "E3FSBLK"\n", leaf); + ext_debug("index is empty, remove it, free block %llu\n", leaf); bh = sb_find_get_block(inode->i_sb, leaf); ext4_forget(handle, 1, inode, bh, leaf); ext4_free_blocks(handle, inode, leaf, 1); @@ -1585,7 +1585,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode, ext4_fsblk_t start; num = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - from; start = ext_pblock(ex) + le16_to_cpu(ex->ee_len) - num; - ext_debug("free last %lu blocks starting "E3FSBLK"\n", num, start); + ext_debug("free last %lu blocks starting %llu\n", num, start); for (i = 0; i < num; i++) { bh = sb_find_get_block(inode->i_sb, start + i); ext4_forget(handle, 0, inode, bh, start + i); @@ -1699,7 +1699,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, if (err) goto out; - ext_debug("new extent: %u:%u:"E3FSBLK"\n", block, num, + ext_debug("new extent: %u:%u:%llu\n", block, num, ext_pblock(ex)); ex--; ex_ee_block = le32_to_cpu(ex->ee_block); @@ -1816,7 +1816,7 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start) path[i].p_idx); if (ext4_ext_more_to_rm(path + i)) { /* go to the next level */ - ext_debug("move to level %d (block "E3FSBLK")\n", + ext_debug("move to level %d (block %llu)\n", i + 1, idx_pblock(path[i].p_idx)); memset(path + i + 1, 0, sizeof(*path)); path[i+1].p_bh = @@ -1993,7 +1993,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, newblock = iblock - ee_block + ee_start; /* number of remaining blocks in the extent */ allocated = ee_len - (iblock - ee_block); - ext_debug("%d fit into %lu:%d -> "E3FSBLK"\n", (int) iblock, + ext_debug("%d fit into %lu:%d -> %llu\n", (int) iblock, ee_block, ee_len, newblock); ext4_ext_put_in_cache(inode, ee_block, ee_len, ee_start, EXT4_EXT_CACHE_EXTENT); @@ -2024,7 +2024,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, newblock = ext4_new_blocks(handle, inode, goal, &allocated, &err); if (!newblock) goto out2; - ext_debug("allocate new block: goal "E3FSBLK", found "E3FSBLK"/%lu\n", + ext_debug("allocate new block: goal %llu, found %llu/%lu\n", goal, newblock, allocated); /* try to insert new extent into found leaf and return */ diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index effc38afebe3..99b82b52b5f0 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2115,7 +2115,7 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, */ if (!bh) { ext4_error(inode->i_sb, "ext4_free_branches", - "Read failure, inode=%lu, block="E3FSBLK, + "Read failure, inode=%lu, block=%llu", inode->i_ino, nr); continue; } @@ -2466,7 +2466,7 @@ static int __ext4_get_inode_loc(struct inode *inode, if (!bh) { ext4_error (inode->i_sb, "ext4_get_inode_loc", "unable to read inode block - " - "inode=%lu, block="E3FSBLK, + "inode=%lu, block=%llu", inode->i_ino, block); return -EIO; } @@ -2548,7 +2548,7 @@ make_io: if (!buffer_uptodate(bh)) { ext4_error(inode->i_sb, "ext4_get_inode_loc", "unable to read inode block - " - "inode=%lu, block="E3FSBLK, + "inode=%lu, block=%llu", inode->i_ino, block); brelse(bh); return -EIO; diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 3dbf91b82202..3e960677c2f2 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -64,7 +64,7 @@ static int verify_group_input(struct super_block *sb, input->blocks_count); else if (!(bh = sb_bread(sb, end - 1))) ext4_warning(sb, __FUNCTION__, - "Cannot read last block ("E3FSBLK")", + "Cannot read last block (%llu)", end - 1); else if (outside(input->block_bitmap, start, end)) ext4_warning(sb, __FUNCTION__, @@ -94,18 +94,18 @@ static int verify_group_input(struct super_block *sb, else if (inside(input->block_bitmap, start, metaend)) ext4_warning(sb, __FUNCTION__, "Block bitmap (%llu) in GDT table" - " ("E3FSBLK"-"E3FSBLK")", + " (%llu-%llu)", input->block_bitmap, start, metaend - 1); else if (inside(input->inode_bitmap, start, metaend)) ext4_warning(sb, __FUNCTION__, "Inode bitmap (%llu) in GDT table" - " ("E3FSBLK"-"E3FSBLK")", + " (%llu-%llu)", input->inode_bitmap, start, metaend - 1); else if (inside(input->inode_table, start, metaend) || inside(itend - 1, start, metaend)) ext4_warning(sb, __FUNCTION__, - "Inode table ("E3FSBLK"-"E3FSBLK") overlaps" - "GDT table ("E3FSBLK"-"E3FSBLK")", + "Inode table (%llu-%llu) overlaps" + "GDT table (%llu-%llu)", input->inode_table, itend - 1, start, metaend - 1); else err = 0; @@ -344,8 +344,8 @@ static int verify_reserved_gdb(struct super_block *sb, if (le32_to_cpu(*p++) != grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){ ext4_warning(sb, __FUNCTION__, - "reserved GDT "E3FSBLK - " missing grp %d ("E3FSBLK")", + "reserved GDT %llu" + " missing grp %d (%llu)", blk, grp, grp * (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) + @@ -424,7 +424,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, data = (__le32 *)dind->b_data; if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) { ext4_warning(sb, __FUNCTION__, - "new group %u GDT block "E3FSBLK" not reserved", + "new group %u GDT block %llu not reserved", input->group, gdblock); err = -EINVAL; goto exit_dind; @@ -547,7 +547,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, for (res = 0; res < reserved_gdb; res++, blk++) { if (le32_to_cpu(*data) != blk) { ext4_warning(sb, __FUNCTION__, - "reserved block "E3FSBLK + "reserved block %llu" " not at offset %ld", blk, (long)(data - (__le32 *)dind->b_data)); @@ -941,7 +941,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, o_groups_count = EXT4_SB(sb)->s_groups_count; if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT4-fs: extending last group from "E3FSBLK" uto "E3FSBLK" blocks\n", + printk(KERN_DEBUG "EXT4-fs: extending last group from %llu uto %llu blocks\n", o_blocks_count, n_blocks_count); if (n_blocks_count == 0 || n_blocks_count == o_blocks_count) @@ -949,7 +949,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { printk(KERN_ERR "EXT4-fs: filesystem on %s:" - " too large to resize to "E3FSBLK" blocks safely\n", + " too large to resize to %llu blocks safely\n", sb->s_id, n_blocks_count); if (sizeof(sector_t) < 8) ext4_warning(sb, __FUNCTION__, @@ -984,7 +984,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, if (o_blocks_count + add < n_blocks_count) ext4_warning(sb, __FUNCTION__, - "will only finish group ("E3FSBLK + "will only finish group (%llu" " blocks, %u new)", o_blocks_count + add, add); @@ -1028,10 +1028,10 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); sb->s_dirt = 1; unlock_super(sb); - ext4_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count, + ext4_debug("freeing blocks %lu through %llu\n", o_blocks_count, o_blocks_count + add); ext4_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks); - ext4_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n", o_blocks_count, + ext4_debug("freed blocks %llu through %llu\n", o_blocks_count, o_blocks_count + add); if ((err = ext4_journal_stop(handle))) goto exit_put; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b91dffd7a031..d844175e60e8 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1244,7 +1244,7 @@ static int ext4_check_descriptors (struct super_block * sb) { ext4_error (sb, "ext4_check_descriptors", "Block bitmap for group %d" - " not in group (block "E3FSBLK")!", + " not in group (block %llu)!", i, block_bitmap); return 0; } @@ -1253,7 +1253,7 @@ static int ext4_check_descriptors (struct super_block * sb) { ext4_error (sb, "ext4_check_descriptors", "Inode bitmap for group %d" - " not in group (block "E3FSBLK")!", + " not in group (block %llu)!", i, inode_bitmap); return 0; } @@ -1263,7 +1263,7 @@ static int ext4_check_descriptors (struct super_block * sb) { ext4_error (sb, "ext4_check_descriptors", "Inode table for group %d" - " not in group (block "E3FSBLK")!", + " not in group (block %llu)!", i, inode_table); return 0; } diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 90f7d5c0bae4..63233cd946a7 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -233,7 +233,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); if (ext4_xattr_check_block(bh)) { bad_block: ext4_error(inode->i_sb, __FUNCTION__, - "inode %lu: bad block "E3FSBLK, inode->i_ino, + "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); error = -EIO; goto cleanup; @@ -375,7 +375,7 @@ ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size) atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); if (ext4_xattr_check_block(bh)) { ext4_error(inode->i_sb, __FUNCTION__, - "inode %lu: bad block "E3FSBLK, inode->i_ino, + "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); error = -EIO; goto cleanup; @@ -647,7 +647,7 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i, le32_to_cpu(BHDR(bs->bh)->h_refcount)); if (ext4_xattr_check_block(bs->bh)) { ext4_error(sb, __FUNCTION__, - "inode %lu: bad block "E3FSBLK, inode->i_ino, + "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); error = -EIO; goto cleanup; @@ -848,7 +848,7 @@ cleanup_dquot: bad_block: ext4_error(inode->i_sb, __FUNCTION__, - "inode %lu: bad block "E3FSBLK, inode->i_ino, + "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); goto cleanup; @@ -1077,14 +1077,14 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode) bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); if (!bh) { ext4_error(inode->i_sb, __FUNCTION__, - "inode %lu: block "E3FSBLK" read error", inode->i_ino, + "inode %lu: block %llu read error", inode->i_ino, EXT4_I(inode)->i_file_acl); goto cleanup; } if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || BHDR(bh)->h_blocks != cpu_to_le32(1)) { ext4_error(inode->i_sb, __FUNCTION__, - "inode %lu: bad block "E3FSBLK, inode->i_ino, + "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); goto cleanup; } diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h index 2bed0effdcae..bb42379cb7fd 100644 --- a/include/linux/ext4_fs_i.h +++ b/include/linux/ext4_fs_i.h @@ -25,13 +25,7 @@ typedef int ext4_grpblk_t; /* data type for filesystem-wide blocks number */ -typedef sector_t ext4_fsblk_t; - -#if BITS_PER_LONG == 64 -#define E3FSBLK "%lu" -#else -#define E3FSBLK "%llu" -#endif +typedef unsigned long long ext4_fsblk_t; struct ext4_reserve_window { ext4_fsblk_t _rsv_start; /* First byte reserved */ -- cgit v1.2.3 From 18eba7aae080d4a5c0d850ea810e83d11f0a8d77 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 11 Oct 2006 01:21:13 -0700 Subject: [PATCH] jbd2: switch blks_type from sector_t to ull Similar to ext4, change blocks in JBD2 from sector_t to unsigned long long. Signed-off-by: Mingming Cao Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd2/commit.c | 4 ++-- fs/jbd2/journal.c | 18 +++++++++--------- fs/jbd2/recovery.c | 12 ++++++------ fs/jbd2/revoke.c | 14 +++++++------- include/linux/jbd2.h | 16 ++++++++-------- 5 files changed, 32 insertions(+), 32 deletions(-) (limited to 'include/linux') diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 1a9ce8885220..70b2ae1ef281 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -272,7 +272,7 @@ write_out_data: } static inline void write_tag_block(int tag_bytes, journal_block_tag_t *tag, - sector_t block) + unsigned long long block) { tag->t_blocknr = cpu_to_be32(block & (u32)~0); if (tag_bytes > JBD_TAG_SIZE32) @@ -293,7 +293,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) int bufs; int flags; int err; - sector_t blocknr; + unsigned long long blocknr; char *tagp = NULL; journal_header_t *header; journal_block_tag_t *tag = NULL; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 259e8365ea15..10db92ced014 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -271,7 +271,7 @@ static void journal_kill_thread(journal_t *journal) int jbd2_journal_write_metadata_buffer(transaction_t *transaction, struct journal_head *jh_in, struct journal_head **jh_out, - sector_t blocknr) + unsigned long long blocknr) { int need_copy_out = 0; int done_copy_out = 0; @@ -555,7 +555,7 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid) * Log buffer allocation routines: */ -int jbd2_journal_next_log_block(journal_t *journal, sector_t *retp) +int jbd2_journal_next_log_block(journal_t *journal, unsigned long long *retp) { unsigned long blocknr; @@ -579,10 +579,10 @@ int jbd2_journal_next_log_block(journal_t *journal, sector_t *retp) * ready. */ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr, - sector_t *retp) + unsigned long long *retp) { int err = 0; - sector_t ret; + unsigned long long ret; if (journal->j_inode) { ret = bmap(journal->j_inode, blocknr); @@ -618,7 +618,7 @@ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr, struct journal_head *jbd2_journal_get_descriptor_buffer(journal_t *journal) { struct buffer_head *bh; - sector_t blocknr; + unsigned long long blocknr; int err; err = jbd2_journal_next_log_block(journal, &blocknr); @@ -706,7 +706,7 @@ fail: */ journal_t * jbd2_journal_init_dev(struct block_device *bdev, struct block_device *fs_dev, - sector_t start, int len, int blocksize) + unsigned long long start, int len, int blocksize) { journal_t *journal = journal_init_common(); struct buffer_head *bh; @@ -753,7 +753,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode) journal_t *journal = journal_init_common(); int err; int n; - sector_t blocknr; + unsigned long long blocknr; if (!journal) return NULL; @@ -819,7 +819,7 @@ static void journal_fail_superblock (journal_t *journal) static int journal_reset(journal_t *journal) { journal_superblock_t *sb = journal->j_superblock; - sector_t first, last; + unsigned long long first, last; first = be32_to_cpu(sb->s_first); last = be32_to_cpu(sb->s_maxlen); @@ -853,7 +853,7 @@ static int journal_reset(journal_t *journal) **/ int jbd2_journal_create(journal_t *journal) { - sector_t blocknr; + unsigned long long blocknr; struct buffer_head *bh; journal_superblock_t *sb; int i, err; diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 52054a83e717..9f10acafaf70 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -70,7 +70,7 @@ static int do_readahead(journal_t *journal, unsigned int start) { int err; unsigned int max, nbufs, next; - sector_t blocknr; + unsigned long long blocknr; struct buffer_head *bh; struct buffer_head * bufs[MAXBUF]; @@ -132,7 +132,7 @@ static int jread(struct buffer_head **bhp, journal_t *journal, unsigned int offset) { int err; - sector_t blocknr; + unsigned long long blocknr; struct buffer_head *bh; *bhp = NULL; @@ -308,9 +308,9 @@ int jbd2_journal_skip_recovery(journal_t *journal) return err; } -static inline sector_t read_tag_block(int tag_bytes, journal_block_tag_t *tag) +static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag) { - sector_t block = be32_to_cpu(tag->t_blocknr); + unsigned long long block = be32_to_cpu(tag->t_blocknr); if (tag_bytes > JBD_TAG_SIZE32) block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32; return block; @@ -452,7 +452,7 @@ static int do_one_pass(journal_t *journal, "block %ld in log\n", err, io_block); } else { - sector_t blocknr; + unsigned long long blocknr; J_ASSERT(obh != NULL); blocknr = read_tag_block(tag_bytes, @@ -592,7 +592,7 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, record_len = 8; while (offset + record_len <= max) { - sector_t blocknr; + unsigned long long blocknr; int err; if (record_len == 4) diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 3310a1d7ace9..380d19917f37 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -81,7 +81,7 @@ struct jbd2_revoke_record_s { struct list_head hash; tid_t sequence; /* Used for recovery only */ - sector_t blocknr; + unsigned long long blocknr; }; @@ -106,7 +106,7 @@ static void flush_descriptor(journal_t *, struct journal_head *, int); /* Utility functions to maintain the revoke table */ /* Borrowed from buffer.c: this is a tried and tested block hash function */ -static inline int hash(journal_t *journal, sector_t block) +static inline int hash(journal_t *journal, unsigned long long block) { struct jbd2_revoke_table_s *table = journal->j_revoke; int hash_shift = table->hash_shift; @@ -117,7 +117,7 @@ static inline int hash(journal_t *journal, sector_t block) (hash << (hash_shift - 12))) & (table->hash_size - 1); } -static int insert_revoke_hash(journal_t *journal, sector_t blocknr, +static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr, tid_t seq) { struct list_head *hash_list; @@ -147,7 +147,7 @@ oom: /* Find a revoke record in the journal's hash table. */ static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal, - sector_t blocknr) + unsigned long long blocknr) { struct list_head *hash_list; struct jbd2_revoke_record_s *record; @@ -326,7 +326,7 @@ void jbd2_journal_destroy_revoke(journal_t *journal) * by one. */ -int jbd2_journal_revoke(handle_t *handle, sector_t blocknr, +int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr, struct buffer_head *bh_in) { struct buffer_head *bh = NULL; @@ -650,7 +650,7 @@ static void flush_descriptor(journal_t *journal, */ int jbd2_journal_set_revoke(journal_t *journal, - sector_t blocknr, + unsigned long long blocknr, tid_t sequence) { struct jbd2_revoke_record_s *record; @@ -674,7 +674,7 @@ int jbd2_journal_set_revoke(journal_t *journal, */ int jbd2_journal_test_revoke(journal_t *journal, - sector_t blocknr, + unsigned long long blocknr, tid_t sequence) { struct jbd2_revoke_record_s *record; diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 3c939c844a7d..ddb128795781 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -741,7 +741,7 @@ struct journal_s */ struct block_device *j_dev; int j_blocksize; - sector_t j_blk_offset; + unsigned long long j_blk_offset; /* * Device which holds the client fs. For internal journal this will be @@ -860,7 +860,7 @@ extern void __journal_clean_data_list(transaction_t *transaction); /* Log buffer allocation */ extern struct journal_head * jbd2_journal_get_descriptor_buffer(journal_t *); -int jbd2_journal_next_log_block(journal_t *, sector_t *); +int jbd2_journal_next_log_block(journal_t *, unsigned long long *); /* Commit management */ extern void jbd2_journal_commit_transaction(journal_t *); @@ -875,7 +875,7 @@ extern int jbd2_journal_write_metadata_buffer(transaction_t *transaction, struct journal_head *jh_in, struct journal_head **jh_out, - sector_t blocknr); + unsigned long long blocknr); /* Transaction locking */ extern void __wait_on_journal (journal_t *); @@ -923,7 +923,7 @@ extern void jbd2_journal_unlock_updates (journal_t *); extern journal_t * jbd2_journal_init_dev(struct block_device *bdev, struct block_device *fs_dev, - sector_t start, int len, int bsize); + unsigned long long start, int len, int bsize); extern journal_t * jbd2_journal_init_inode (struct inode *); extern int jbd2_journal_update_format (journal_t *); extern int jbd2_journal_check_used_features @@ -944,7 +944,7 @@ extern void jbd2_journal_abort (journal_t *, int); extern int jbd2_journal_errno (journal_t *); extern void jbd2_journal_ack_err (journal_t *); extern int jbd2_journal_clear_err (journal_t *); -extern int jbd2_journal_bmap(journal_t *, unsigned long, sector_t *); +extern int jbd2_journal_bmap(journal_t *, unsigned long, unsigned long long *); extern int jbd2_journal_force_commit(journal_t *); /* @@ -977,13 +977,13 @@ extern void jbd2_journal_destroy_revoke_caches(void); extern int jbd2_journal_init_revoke_caches(void); extern void jbd2_journal_destroy_revoke(journal_t *); -extern int jbd2_journal_revoke (handle_t *, sector_t, struct buffer_head *); +extern int jbd2_journal_revoke (handle_t *, unsigned long long, struct buffer_head *); extern int jbd2_journal_cancel_revoke(handle_t *, struct journal_head *); extern void jbd2_journal_write_revoke_records(journal_t *, transaction_t *); /* Recovery revoke support */ -extern int jbd2_journal_set_revoke(journal_t *, sector_t, tid_t); -extern int jbd2_journal_test_revoke(journal_t *, sector_t, tid_t); +extern int jbd2_journal_set_revoke(journal_t *, unsigned long long, tid_t); +extern int jbd2_journal_test_revoke(journal_t *, unsigned long long, tid_t); extern void jbd2_journal_clear_revoke(journal_t *); extern void jbd2_journal_switch_revoke_table(journal_t *journal); -- cgit v1.2.3 From 0d1ee42f27d30eed1659f3e85bcbbc7b3711f61f Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Wed, 11 Oct 2006 01:21:14 -0700 Subject: [PATCH] ext4: allow larger descriptor size make block group descriptor larger. Signed-off-by: Alexandre Ratchov Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/balloc.c | 6 ++++-- fs/ext4/inode.c | 8 +++++--- fs/ext4/super.c | 18 +++++++++++++++--- include/linux/ext4_fs.h | 9 ++++++--- include/linux/ext4_fs_sb.h | 1 + 5 files changed, 31 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index df77ea891f29..3dacb124b8c8 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -74,10 +74,12 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, return NULL; } - desc = (struct ext4_group_desc *) sbi->s_group_desc[group_desc]->b_data; + desc = (struct ext4_group_desc *)( + (__u8 *)sbi->s_group_desc[group_desc]->b_data + + offset * EXT4_DESC_SIZE(sb)); if (bh) *bh = sbi->s_group_desc[group_desc]; - return desc + offset; + return desc; } /** diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c05dc57148bb..d03e7d85a638 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2432,14 +2432,16 @@ static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb, return 0; } - gdp = (struct ext4_group_desc *)bh->b_data; + gdp = (struct ext4_group_desc *)((__u8 *)bh->b_data + + desc * EXT4_DESC_SIZE(sb)); /* * Figure out the offset within the block group inode table */ offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) * EXT4_INODE_SIZE(sb); - block = ext4_inode_table(gdp + desc) + - (offset >> EXT4_BLOCK_SIZE_BITS(sb)); + block = ext4_inode_table(gdp) + (offset >> EXT4_BLOCK_SIZE_BITS(sb)); + + iloc->block_group = block_group; iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index d844175e60e8..bc8848bff2f1 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1268,7 +1268,8 @@ static int ext4_check_descriptors (struct super_block * sb) return 0; } first_block += EXT4_BLOCKS_PER_GROUP(sb); - gdp++; + gdp = (struct ext4_group_desc *) + ((__u8 *)gdp + EXT4_DESC_SIZE(sb)); } ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb)); @@ -1619,7 +1620,18 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) sbi->s_frag_size, blocksize); goto failed_mount; } - sbi->s_frags_per_block = 1; + sbi->s_desc_size = le16_to_cpu(es->s_desc_size); + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) { + if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE || + sbi->s_desc_size > EXT4_MAX_DESC_SIZE || + sbi->s_desc_size & (sbi->s_desc_size - 1)) { + printk(KERN_ERR + "EXT4-fs: unsupported descriptor size %ld\n", + sbi->s_desc_size); + goto failed_mount; + } + } else + sbi->s_desc_size = EXT4_MIN_DESC_SIZE; sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); @@ -1630,7 +1642,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) goto cantfind_ext4; sbi->s_itb_per_group = sbi->s_inodes_per_group / sbi->s_inodes_per_block; - sbi->s_desc_per_block = blocksize / sizeof(struct ext4_group_desc); + sbi->s_desc_per_block = blocksize / EXT4_DESC_SIZE(sb); sbi->s_sbh = bh; sbi->s_mount_state = le16_to_cpu(es->s_state); sbi->s_addr_per_block_bits = log2(EXT4_ADDR_PER_BLOCK(sb)); diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index 8e5009ee4ad8..a3df2afc004b 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -142,6 +142,9 @@ struct ext4_group_desc /* * Macro-instructions used to manage group descriptors */ +#define EXT4_MIN_DESC_SIZE 32 +#define EXT4_MAX_DESC_SIZE EXT4_MIN_BLOCK_SIZE +#define EXT4_DESC_SIZE(s) (EXT4_SB(s)->s_desc_size) #ifdef __KERNEL__ # define EXT4_BLOCKS_PER_GROUP(s) (EXT4_SB(s)->s_blocks_per_group) # define EXT4_DESC_PER_BLOCK(s) (EXT4_SB(s)->s_desc_per_block) @@ -149,7 +152,7 @@ struct ext4_group_desc # define EXT4_DESC_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_desc_per_block_bits) #else # define EXT4_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) -# define EXT4_DESC_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof (struct ext4_group_desc)) +# define EXT4_DESC_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_DESC_SIZE(s)) # define EXT4_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) #endif @@ -474,7 +477,7 @@ struct ext4_super_block { * things it doesn't understand... */ __le32 s_first_ino; /* First non-reserved inode */ - __le16 s_inode_size; /* size of inode structure */ + __le16 s_inode_size; /* size of inode structure */ __le16 s_block_group_nr; /* block group # of this superblock */ __le32 s_feature_compat; /* compatible feature set */ /*60*/ __le32 s_feature_incompat; /* incompatible feature set */ @@ -500,7 +503,7 @@ struct ext4_super_block { __le32 s_hash_seed[4]; /* HTREE hash seed */ __u8 s_def_hash_version; /* Default hash version to use */ __u8 s_reserved_char_pad; - __u16 s_reserved_word_pad; + __le16 s_desc_size; /* size of group descriptor */ /*100*/ __le32 s_default_mount_opts; __le32 s_first_meta_bg; /* First metablock block group */ __le32 s_mkfs_time; /* When the filesystem was created */ diff --git a/include/linux/ext4_fs_sb.h b/include/linux/ext4_fs_sb.h index ce7a844d6703..691a713139ce 100644 --- a/include/linux/ext4_fs_sb.h +++ b/include/linux/ext4_fs_sb.h @@ -29,6 +29,7 @@ */ struct ext4_sb_info { unsigned long s_frag_size; /* Size of a fragment in bytes */ + unsigned long s_desc_size; /* Size of a group descriptor in bytes */ unsigned long s_frags_per_block;/* Number of fragments per block */ unsigned long s_inodes_per_block;/* Number of inodes per block */ unsigned long s_frags_per_group;/* Number of fragments in a group */ -- cgit v1.2.3 From 8fadc14323684c547f74cf2f4d13517c6c264731 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Wed, 11 Oct 2006 01:21:15 -0700 Subject: [PATCH] ext4: move block number hi bits move '_hi' bits of block numbers in the larger part of the block group descriptor structure Signed-off-by: Alexandre Ratchov Signed-off-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/balloc.c | 20 ++++++++++---------- fs/ext4/ialloc.c | 4 ++-- fs/ext4/inode.c | 7 +++---- fs/ext4/resize.c | 6 +++--- fs/ext4/super.c | 46 +++++++++++++++++++++++++++++----------------- include/linux/ext4_fs.h | 27 +++++++++++++++++---------- 6 files changed, 64 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 3dacb124b8c8..3e85886a6382 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -101,13 +101,13 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) desc = ext4_get_group_desc (sb, block_group, NULL); if (!desc) goto error_out; - bh = sb_bread(sb, ext4_block_bitmap(desc)); + bh = sb_bread(sb, ext4_block_bitmap(sb, desc)); if (!bh) ext4_error (sb, "read_block_bitmap", "Cannot read block bitmap - " "block_group = %d, block_bitmap = %llu", block_group, - ext4_block_bitmap(desc)); + ext4_block_bitmap(sb, desc)); error_out: return bh; } @@ -463,10 +463,10 @@ do_more: if (!desc) goto error_return; - if (in_range(ext4_block_bitmap(desc), block, count) || - in_range(ext4_inode_bitmap(desc), block, count) || - in_range(block, ext4_inode_table(desc), sbi->s_itb_per_group) || - in_range(block + count - 1, ext4_inode_table(desc), + if (in_range(ext4_block_bitmap(sb, desc), block, count) || + in_range(ext4_inode_bitmap(sb, desc), block, count) || + in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) || + in_range(block + count - 1, ext4_inode_table(sb, desc), sbi->s_itb_per_group)) ext4_error (sb, "ext4_free_blocks", "Freeing blocks in system zones - " @@ -1563,11 +1563,11 @@ allocated: ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no); - if (in_range(ext4_block_bitmap(gdp), ret_block, num) || - in_range(ext4_block_bitmap(gdp), ret_block, num) || - in_range(ret_block, ext4_inode_table(gdp), + if (in_range(ext4_block_bitmap(sb, gdp), ret_block, num) || + in_range(ext4_block_bitmap(sb, gdp), ret_block, num) || + in_range(ret_block, ext4_inode_table(sb, gdp), EXT4_SB(sb)->s_itb_per_group) || - in_range(ret_block + num - 1, ext4_inode_table(gdp), + in_range(ret_block + num - 1, ext4_inode_table(sb, gdp), EXT4_SB(sb)->s_itb_per_group)) ext4_error(sb, "ext4_new_block", "Allocating block in system zone - " diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 959b7fa8f5db..75608e1e5555 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -60,12 +60,12 @@ read_inode_bitmap(struct super_block * sb, unsigned long block_group) if (!desc) goto error_out; - bh = sb_bread(sb, ext4_inode_bitmap(desc)); + bh = sb_bread(sb, ext4_inode_bitmap(sb, desc)); if (!bh) ext4_error(sb, "read_inode_bitmap", "Cannot read inode bitmap - " "block_group = %lu, inode_bitmap = %llu", - block_group, ext4_inode_bitmap(desc)); + block_group, ext4_inode_bitmap(sb, desc)); error_out: return bh; } diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index d03e7d85a638..0a60ec5a16db 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2439,9 +2439,8 @@ static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb, */ offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) * EXT4_INODE_SIZE(sb); - block = ext4_inode_table(gdp) + (offset >> EXT4_BLOCK_SIZE_BITS(sb)); - - + block = ext4_inode_table(sb, gdp) + + (offset >> EXT4_BLOCK_SIZE_BITS(sb)); iloc->block_group = block_group; iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1); @@ -2508,7 +2507,7 @@ static int __ext4_get_inode_loc(struct inode *inode, goto make_io; bitmap_bh = sb_getblk(inode->i_sb, - ext4_inode_bitmap(desc)); + ext4_inode_bitmap(inode->i_sb, desc)); if (!bitmap_bh) goto make_io; diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 3e960677c2f2..1e9578052cd3 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -834,9 +834,9 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) /* Update group descriptor block for new group */ gdp = (struct ext4_group_desc *)primary->b_data + gdb_off; - ext4_block_bitmap_set(gdp, input->block_bitmap); /* LV FIXME */ - ext4_inode_bitmap_set(gdp, input->inode_bitmap); /* LV FIXME */ - ext4_inode_table_set(gdp, input->inode_table); /* LV FIXME */ + ext4_block_bitmap_set(sb, gdp, input->block_bitmap); /* LV FIXME */ + ext4_inode_bitmap_set(sb, gdp, input->inode_bitmap); /* LV FIXME */ + ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */ gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb)); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index bc8848bff2f1..811011fc5c94 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -63,40 +63,52 @@ static void ext4_write_super (struct super_block * sb); static void ext4_write_super_lockfs(struct super_block *sb); -ext4_fsblk_t ext4_block_bitmap(struct ext4_group_desc *bg) +ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, + struct ext4_group_desc *bg) { return le32_to_cpu(bg->bg_block_bitmap) | - ((ext4_fsblk_t)le16_to_cpu(bg->bg_block_bitmap_hi) << 32); + (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? + (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0); } -ext4_fsblk_t ext4_inode_bitmap(struct ext4_group_desc *bg) +ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb, + struct ext4_group_desc *bg) { return le32_to_cpu(bg->bg_inode_bitmap) | - ((ext4_fsblk_t)le16_to_cpu(bg->bg_inode_bitmap_hi) << 32); + (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? + (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0); } -ext4_fsblk_t ext4_inode_table(struct ext4_group_desc *bg) +ext4_fsblk_t ext4_inode_table(struct super_block *sb, + struct ext4_group_desc *bg) { return le32_to_cpu(bg->bg_inode_table) | - ((ext4_fsblk_t)le16_to_cpu(bg->bg_inode_table_hi) << 32); + (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? + (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0); } -void ext4_block_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk) +void ext4_block_bitmap_set(struct super_block *sb, + struct ext4_group_desc *bg, ext4_fsblk_t blk) { bg->bg_block_bitmap = cpu_to_le32((u32)blk); - bg->bg_block_bitmap_hi = cpu_to_le16(blk >> 32); + if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) + bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32); } -void ext4_inode_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk) +void ext4_inode_bitmap_set(struct super_block *sb, + struct ext4_group_desc *bg, ext4_fsblk_t blk) { bg->bg_inode_bitmap = cpu_to_le32((u32)blk); - bg->bg_inode_bitmap_hi = cpu_to_le16(blk >> 32); + if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) + bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32); } -void ext4_inode_table_set(struct ext4_group_desc *bg, ext4_fsblk_t blk) +void ext4_inode_table_set(struct super_block *sb, + struct ext4_group_desc *bg, ext4_fsblk_t blk) { bg->bg_inode_table = cpu_to_le32((u32)blk); - bg->bg_inode_table_hi = cpu_to_le16(blk >> 32); + if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) + bg->bg_inode_table_hi = cpu_to_le32(blk >> 32); } /* @@ -1239,7 +1251,7 @@ static int ext4_check_descriptors (struct super_block * sb) if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0) gdp = (struct ext4_group_desc *) sbi->s_group_desc[desc_block++]->b_data; - block_bitmap = ext4_block_bitmap(gdp); + block_bitmap = ext4_block_bitmap(sb, gdp); if (block_bitmap < first_block || block_bitmap > last_block) { ext4_error (sb, "ext4_check_descriptors", @@ -1248,7 +1260,7 @@ static int ext4_check_descriptors (struct super_block * sb) i, block_bitmap); return 0; } - inode_bitmap = ext4_inode_bitmap(gdp); + inode_bitmap = ext4_inode_bitmap(sb, gdp); if (inode_bitmap < first_block || inode_bitmap > last_block) { ext4_error (sb, "ext4_check_descriptors", @@ -1257,7 +1269,7 @@ static int ext4_check_descriptors (struct super_block * sb) i, inode_bitmap); return 0; } - inode_table = ext4_inode_table(gdp); + inode_table = ext4_inode_table(sb, gdp); if (inode_table < first_block || inode_table + sbi->s_itb_per_group > last_block) { @@ -1622,11 +1634,11 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) } sbi->s_desc_size = le16_to_cpu(es->s_desc_size); if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) { - if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE || + if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT || sbi->s_desc_size > EXT4_MAX_DESC_SIZE || sbi->s_desc_size & (sbi->s_desc_size - 1)) { printk(KERN_ERR - "EXT4-fs: unsupported descriptor size %ld\n", + "EXT4-fs: unsupported descriptor size %lu\n", sbi->s_desc_size); goto failed_mount; } diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index a3df2afc004b..296609b9242d 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -129,10 +129,10 @@ struct ext4_group_desc __le16 bg_free_inodes_count; /* Free inodes count */ __le16 bg_used_dirs_count; /* Directories count */ __u16 bg_flags; - __le16 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ - __le16 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ - __le16 bg_inode_table_hi; /* Inodes table block MSB */ - __u16 bg_reserved[3]; + __u32 bg_reserved[3]; + __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ + __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ + __le32 bg_inode_table_hi; /* Inodes table block MSB */ }; #ifdef __KERNEL__ @@ -143,6 +143,7 @@ struct ext4_group_desc * Macro-instructions used to manage group descriptors */ #define EXT4_MIN_DESC_SIZE 32 +#define EXT4_MIN_DESC_SIZE_64BIT 64 #define EXT4_MAX_DESC_SIZE EXT4_MIN_BLOCK_SIZE #define EXT4_DESC_SIZE(s) (EXT4_SB(s)->s_desc_size) #ifdef __KERNEL__ @@ -904,12 +905,18 @@ extern void ext4_abort (struct super_block *, const char *, const char *, ...) extern void ext4_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); extern void ext4_update_dynamic_rev (struct super_block *sb); -extern ext4_fsblk_t ext4_block_bitmap(struct ext4_group_desc *bg); -extern ext4_fsblk_t ext4_inode_bitmap(struct ext4_group_desc *bg); -extern ext4_fsblk_t ext4_inode_table(struct ext4_group_desc *bg); -extern void ext4_block_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk); -extern void ext4_inode_bitmap_set(struct ext4_group_desc *bg, ext4_fsblk_t blk); -extern void ext4_inode_table_set(struct ext4_group_desc *bg, ext4_fsblk_t blk); +extern ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, + struct ext4_group_desc *bg); +extern ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb, + struct ext4_group_desc *bg); +extern ext4_fsblk_t ext4_inode_table(struct super_block *sb, + struct ext4_group_desc *bg); +extern void ext4_block_bitmap_set(struct super_block *sb, + struct ext4_group_desc *bg, ext4_fsblk_t blk); +extern void ext4_inode_bitmap_set(struct super_block *sb, + struct ext4_group_desc *bg, ext4_fsblk_t blk); +extern void ext4_inode_table_set(struct super_block *sb, + struct ext4_group_desc *bg, ext4_fsblk_t blk); static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) { -- cgit v1.2.3 From 72b64b594081ef0a0717f6aad77e891c72ed4afa Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 01:21:18 -0700 Subject: [PATCH] ext4 uninline ext4_get_group_no_and_offset() Way too big to inline. Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/balloc.c | 18 ++++++++++++++++++ include/linux/ext4_fs.h | 22 ++-------------------- 2 files changed, 20 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 3e85886a6382..402475a6f3df 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -24,6 +24,24 @@ * balloc.c contains the blocks allocation and deallocation routines */ +/* + * Calculate the block group number and offset, given a block number + */ +void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, + unsigned long *blockgrpp, ext4_grpblk_t *offsetp) +{ + struct ext4_super_block *es = EXT4_SB(sb)->s_es; + ext4_grpblk_t offset; + + blocknr = blocknr - le32_to_cpu(es->s_first_data_block); + offset = sector_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb)); + if (offsetp) + *offsetp = offset; + if (blockgrpp) + *blockgrpp = blocknr; + +} + /* * The free blocks are managed by bitmaps. A file system contains several * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index 296609b9242d..498503ee613d 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -769,26 +769,8 @@ ext4_group_first_block_no(struct super_block *sb, unsigned long group_no) */ #define ERR_BAD_DX_DIR -75000 -/* - * This function calculate the block group number and offset, - * given a block number - */ - -static inline void ext4_get_group_no_and_offset(struct super_block * sb, - ext4_fsblk_t blocknr, unsigned long* blockgrpp, - ext4_grpblk_t *offsetp) -{ - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - ext4_grpblk_t offset; - - blocknr = blocknr - le32_to_cpu(es->s_first_data_block); - offset = sector_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb)); - if (offsetp) - *offsetp = offset; - if (blockgrpp) - *blockgrpp = blocknr; - -} +void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, + unsigned long *blockgrpp, ext4_grpblk_t *offsetp); /* * Function prototypes -- cgit v1.2.3 From 9858db504caedb2424b9a32744c23f9a81ec1731 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 11 Oct 2006 01:21:30 -0700 Subject: [PATCH] mm: locks_freed fix Move the lock debug checks below the page reserved checks. Also, having debug_check_no_locks_freed in kernel_map_pages is wrong. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 7 +------ mm/page_alloc.c | 8 ++++---- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index 26146623be2f..5a6068ff5556 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1103,12 +1103,7 @@ static inline void vm_stat_account(struct mm_struct *mm, #ifndef CONFIG_DEBUG_PAGEALLOC static inline void -kernel_map_pages(struct page *page, int numpages, int enable) -{ - if (!PageHighMem(page) && !enable) - debug_check_no_locks_freed(page_address(page), - numpages * PAGE_SIZE); -} +kernel_map_pages(struct page *page, int numpages, int enable) {} #endif extern struct vm_area_struct *get_gate_vma(struct task_struct *tsk); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c5caac2c3c5a..40db96a655d0 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -495,15 +495,13 @@ static void __free_pages_ok(struct page *page, unsigned int order) int i; int reserved = 0; - if (!PageHighMem(page)) - debug_check_no_locks_freed(page_address(page), - PAGE_SIZE< Date: Wed, 11 Oct 2006 01:21:44 -0700 Subject: [PATCH] epoll_pwait() Implement the epoll_pwait system call, that extend the event wait mechanism with the same logic ppoll and pselect do. The definition of epoll_pwait is: int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask, size_t sigsetsize); The difference between the vanilla epoll_wait and epoll_pwait is that the latter allows the caller to specify a signal mask to be set while waiting for events. Hence epoll_pwait will wait until either one monitored event, or an unmasked signal happen. If sigmask is NULL, the epoll_pwait system call will act exactly like epoll_wait. For the POSIX definition of pselect, information is available here: http://www.opengroup.org/onlinepubs/009695399/functions/select.html Signed-off-by: Davide Libenzi Cc: David Woodhouse Cc: Andi Kleen Cc: Michael Kerrisk Cc: Ulrich Drepper Cc: Roland McGrath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/syscall_table.S | 1 + fs/eventpoll.c | 56 +++++++++++++++++++++++++++++++++++++--- include/asm-i386/unistd.h | 3 ++- include/linux/syscalls.h | 4 +++ 4 files changed, 60 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index 7e639f78b0b9..2697e9210e92 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S @@ -318,3 +318,4 @@ ENTRY(sys_call_table) .long sys_vmsplice .long sys_move_pages .long sys_getcpu + .long sys_epoll_pwait diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 557d5b614fae..ae228ec54e94 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -105,6 +105,8 @@ /* Maximum msec timeout value storeable in a long int */ #define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ) +#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) + struct epoll_filefd { struct file *file; @@ -497,7 +499,7 @@ void eventpoll_release_file(struct file *file) */ asmlinkage long sys_epoll_create(int size) { - int error, fd; + int error, fd = -1; struct eventpoll *ep; struct inode *inode; struct file *file; @@ -640,7 +642,6 @@ eexit_1: return error; } -#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) /* * Implement the event wait interface for the eventpoll file. It is the kernel @@ -657,7 +658,7 @@ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, current, epfd, events, maxevents, timeout)); /* The maximum number of event must be greater than zero */ - if (maxevents <= 0 || maxevents > MAX_EVENTS) + if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) return -EINVAL; /* Verify that the area passed by the user is writeable */ @@ -699,6 +700,55 @@ eexit_1: } +#ifdef TIF_RESTORE_SIGMASK + +/* + * Implement the event wait interface for the eventpoll file. It is the kernel + * part of the user space epoll_pwait(2). + */ +asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events, + int maxevents, int timeout, const sigset_t __user *sigmask, + size_t sigsetsize) +{ + int error; + sigset_t ksigmask, sigsaved; + + /* + * If the caller wants a certain signal mask to be set during the wait, + * we apply it here. + */ + if (sigmask) { + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) + return -EFAULT; + sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); + sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); + } + + error = sys_epoll_wait(epfd, events, maxevents, timeout); + + /* + * If we changed the signal mask, we need to restore the original one. + * In case we've got a signal while waiting, we do not restore the + * signal mask yet, and we allow do_signal() to deliver the signal on + * the way back to userspace, before the signal mask is restored. + */ + if (sigmask) { + if (error == -EINTR) { + memcpy(¤t->saved_sigmask, &sigsaved, + sizeof(sigsaved)); + set_thread_flag(TIF_RESTORE_SIGMASK); + } else + sigprocmask(SIG_SETMASK, &sigsaved, NULL); + } + + return error; +} + +#endif /* #ifdef TIF_RESTORE_SIGMASK */ + + /* * Creates the file descriptor to be used by the epoll interface. */ diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 3ca7ab963d7d..beeeaf6b054a 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -324,10 +324,11 @@ #define __NR_vmsplice 316 #define __NR_move_pages 317 #define __NR_getcpu 318 +#define __NR_epoll_pwait 319 #ifdef __KERNEL__ -#define NR_syscalls 319 +#define NR_syscalls 320 #include /* diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index b0ace3fd7eb9..1912c6cbef55 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -431,6 +431,10 @@ asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event); asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, int maxevents, int timeout); +asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events, + int maxevents, int timeout, + const sigset_t __user *sigmask, + size_t sigsetsize); asmlinkage long sys_gethostname(char __user *name, int len); asmlinkage long sys_sethostname(char __user *name, int len); asmlinkage long sys_setdomainname(char __user *name, int len); -- cgit v1.2.3 From e0ab2928cc2202f13f0574d4c6f567f166d307eb Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Wed, 11 Oct 2006 01:21:45 -0700 Subject: [PATCH] Add carta_random32() library routine This is a follow-up patch based on the review for perfmon2. This patch adds the carta_random32() library routine + carta_random32.h header file. This is fast, simple, and efficient pseudo number generator algorithm. We use it in perfmon2 to randomize the sampling periods. In this context, we do not need any fancy randomizer. Signed-off-by: stephane eranian Cc: David Mosberger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/carta_random32.h | 29 +++++++++++++++++++++++++++++ lib/Makefile | 2 +- lib/carta_random32.c | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 include/linux/carta_random32.h create mode 100644 lib/carta_random32.c (limited to 'include/linux') diff --git a/include/linux/carta_random32.h b/include/linux/carta_random32.h new file mode 100644 index 000000000000..f6f3bd9f20b5 --- /dev/null +++ b/include/linux/carta_random32.h @@ -0,0 +1,29 @@ +/* + * Fast, simple, yet decent quality random number generator based on + * a paper by David G. Carta ("Two Fast Implementations of the + * `Minimal Standard' Random Number Generator," Communications of the + * ACM, January, 1990). + * + * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P. + * Contributed by Stephane Eranian + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +#ifndef _LINUX_CARTA_RANDOM32_H_ +#define _LINUX_CARTA_RANDOM32_H_ + +u64 carta_random32(u64 seed); + +#endif /* _LINUX_CARTA_RANDOM32_H_ */ diff --git a/lib/Makefile b/lib/Makefile index 8e6662bb9c37..59070dbfbeb4 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,7 +5,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \ - sha1.o irq_regs.o + sha1.o irq_regs.o carta_random32.o lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o diff --git a/lib/carta_random32.c b/lib/carta_random32.c new file mode 100644 index 000000000000..ca82df70eee4 --- /dev/null +++ b/lib/carta_random32.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P. + * Contributed by David Mosberger-Tang + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +#include +#include + +/* + * Fast, simple, yet decent quality random number generator based on + * a paper by David G. Carta ("Two Fast Implementations of the + * `Minimal Standard' Random Number Generator," Communications of the + * ACM, January, 1990). + */ +u64 carta_random32 (u64 seed) +{ +# define A 16807 +# define M ((u32) 1 << 31) + u64 s, prod = A * seed, p, q; + + p = (prod >> 31) & (M - 1); + q = (prod >> 0) & (M - 1); + s = p + q; + if (s >= M) + s -= M - 1; + return s; +} +EXPORT_SYMBOL_GPL(carta_random32); -- cgit v1.2.3 From fa3ba2e81ea23416272a22009bba95954c81969c Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Wed, 11 Oct 2006 01:21:48 -0700 Subject: [PATCH] fix Module taint flags listing in Oops/panic Module taint flags listing in Oops/panic has a couple of issues: * taint_flags() doesn't null-terminate the buffer after printing the flags * per-module taints are only set if the kernel is not already tainted (with that particular flag) => only the first offending module gets its taint info correctly updated Some additional changes: * 'license_gplok' is no longer needed - equivalent to !(taints & TAINT_PROPRIETARY_MODULE) - so we can drop it from struct module * exporting module taint info via /proc/module: pwc 88576 0 - Live 0xf8c32000 evilmod 6784 1 pwc, Live 0xf8bbf000 (PF) Signed-off-by: Florin Malita Cc: "Randy.Dunlap" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/module.h | 3 -- kernel/module.c | 94 ++++++++++++++++++++++++++------------------------ 2 files changed, 49 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/include/linux/module.h b/include/linux/module.h index 4b2d8091a410..d1d00ce8f4ed 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -317,9 +317,6 @@ struct module /* Am I unsafe to unload? */ int unsafe; - /* Am I GPL-compatible */ - int license_gplok; - unsigned int taints; /* same bits as kernel:tainted */ #ifdef CONFIG_MODULE_UNLOAD diff --git a/kernel/module.c b/kernel/module.c index 7f60e782de1e..67009bd56c52 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -87,6 +87,12 @@ static inline int strong_try_module_get(struct module *mod) return try_module_get(mod); } +static inline void add_taint_module(struct module *mod, unsigned flag) +{ + add_taint(flag); + mod->taints |= flag; +} + /* A thread that wants to hold a reference to a module only while it * is running can call ths to safely exit. * nfsd and lockd use this. @@ -847,12 +853,10 @@ static int check_version(Elf_Shdr *sechdrs, return 0; } /* Not in module's version table. OK, but that taints the kernel. */ - if (!(tainted & TAINT_FORCED_MODULE)) { + if (!(tainted & TAINT_FORCED_MODULE)) printk("%s: no version for \"%s\" found: kernel tainted.\n", mod->name, symname); - add_taint(TAINT_FORCED_MODULE); - mod->taints |= TAINT_FORCED_MODULE; - } + add_taint_module(mod, TAINT_FORCED_MODULE); return 1; } @@ -910,7 +914,8 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, unsigned long ret; const unsigned long *crc; - ret = __find_symbol(name, &owner, &crc, mod->license_gplok); + ret = __find_symbol(name, &owner, &crc, + !(mod->taints & TAINT_PROPRIETARY_MODULE)); if (ret) { /* use_module can fail due to OOM, or module unloading */ if (!check_version(sechdrs, versindex, name, mod, crc) || @@ -1335,12 +1340,11 @@ static void set_license(struct module *mod, const char *license) if (!license) license = "unspecified"; - mod->license_gplok = license_is_gpl_compatible(license); - if (!mod->license_gplok && !(tainted & TAINT_PROPRIETARY_MODULE)) { - printk(KERN_WARNING "%s: module license '%s' taints kernel.\n", - mod->name, license); - add_taint(TAINT_PROPRIETARY_MODULE); - mod->taints |= TAINT_PROPRIETARY_MODULE; + if (!license_is_gpl_compatible(license)) { + if (!(tainted & TAINT_PROPRIETARY_MODULE)) + printk(KERN_WARNING "%s: module license '%s' taints" + "kernel.\n", mod->name, license); + add_taint_module(mod, TAINT_PROPRIETARY_MODULE); } } @@ -1619,8 +1623,7 @@ static struct module *load_module(void __user *umod, modmagic = get_modinfo(sechdrs, infoindex, "vermagic"); /* This is allowed: modprobe --force will invalidate it. */ if (!modmagic) { - add_taint(TAINT_FORCED_MODULE); - mod->taints |= TAINT_FORCED_MODULE; + add_taint_module(mod, TAINT_FORCED_MODULE); printk(KERN_WARNING "%s: no version magic, tainting kernel.\n", mod->name); } else if (!same_magic(modmagic, vermagic)) { @@ -1714,14 +1717,10 @@ static struct module *load_module(void __user *umod, /* Set up license info based on the info section */ set_license(mod, get_modinfo(sechdrs, infoindex, "license")); - if (strcmp(mod->name, "ndiswrapper") == 0) { - add_taint(TAINT_PROPRIETARY_MODULE); - mod->taints |= TAINT_PROPRIETARY_MODULE; - } - if (strcmp(mod->name, "driverloader") == 0) { - add_taint(TAINT_PROPRIETARY_MODULE); - mod->taints |= TAINT_PROPRIETARY_MODULE; - } + if (strcmp(mod->name, "ndiswrapper") == 0) + add_taint_module(mod, TAINT_PROPRIETARY_MODULE); + if (strcmp(mod->name, "driverloader") == 0) + add_taint_module(mod, TAINT_PROPRIETARY_MODULE); /* Set up MODINFO_ATTR fields */ setup_modinfo(mod, sechdrs, infoindex); @@ -1766,8 +1765,7 @@ static struct module *load_module(void __user *umod, (mod->num_unused_gpl_syms && !unusedgplcrcindex)) { printk(KERN_WARNING "%s: No versions for exported symbols." " Tainting kernel.\n", mod->name); - add_taint(TAINT_FORCED_MODULE); - mod->taints |= TAINT_FORCED_MODULE; + add_taint_module(mod, TAINT_FORCED_MODULE); } #endif @@ -2132,9 +2130,33 @@ static void m_stop(struct seq_file *m, void *p) mutex_unlock(&module_mutex); } +static char *taint_flags(unsigned int taints, char *buf) +{ + int bx = 0; + + if (taints) { + buf[bx++] = '('; + if (taints & TAINT_PROPRIETARY_MODULE) + buf[bx++] = 'P'; + if (taints & TAINT_FORCED_MODULE) + buf[bx++] = 'F'; + /* + * TAINT_FORCED_RMMOD: could be added. + * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't + * apply to modules. + */ + buf[bx++] = ')'; + } + buf[bx] = '\0'; + + return buf; +} + static int m_show(struct seq_file *m, void *p) { struct module *mod = list_entry(p, struct module, list); + char buf[8]; + seq_printf(m, "%s %lu", mod->name, mod->init_size + mod->core_size); print_unload_info(m, mod); @@ -2147,6 +2169,10 @@ static int m_show(struct seq_file *m, void *p) /* Used by oprofile and other similar tools. */ seq_printf(m, " 0x%p", mod->module_core); + /* Taints info */ + if (mod->taints) + seq_printf(m, " %s", taint_flags(mod->taints, buf)); + seq_printf(m, "\n"); return 0; } @@ -2235,28 +2261,6 @@ struct module *module_text_address(unsigned long addr) return mod; } -static char *taint_flags(unsigned int taints, char *buf) -{ - *buf = '\0'; - if (taints) { - int bx; - - buf[0] = '('; - bx = 1; - if (taints & TAINT_PROPRIETARY_MODULE) - buf[bx++] = 'P'; - if (taints & TAINT_FORCED_MODULE) - buf[bx++] = 'F'; - /* - * TAINT_FORCED_RMMOD: could be added. - * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't - * apply to modules. - */ - buf[bx] = ')'; - } - return buf; -} - /* Don't grab lock, we're oopsing. */ void print_modules(void) { -- cgit v1.2.3 From 39484e53bb00f55b6303a908070db133608ef2a5 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 11 Oct 2006 01:21:54 -0700 Subject: [PATCH] 32-bit compatibility HDIO IOCTLs A couple of HDIO IOCTLs are not yet handled and a few others are marked as using a pointer rather than an unsigned long. The formers include: HDIO_GET_WCACHE, HDIO_GET_ACOUSTIC, HDIO_GET_ADDRESS and HDIO_GET_BUSSTATE. The latters are: HDIO_SET_MULTCOUNT, HDIO_SET_UNMASKINTR, HDIO_SET_KEEPSETTINGS, HDIO_SET_32BIT, HDIO_SET_NOWERR, HDIO_SET_DMA, HDIO_SET_PIO_MODE and HDIO_SET_NICE. Additionally 0x330 used to be HDIO_GETGEO_BIG and may be issued by 32-bit `hdparm' run on a 64-bit kernel making Linux complain loudly. This is a fix for these issues. Signed-off-by: Maciej W. Rozycki Cc: Alan Cox Acked-by: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/compat_ioctl.c | 10 +++++++--- include/linux/compat_ioctl.h | 24 +++++++++++++++--------- 2 files changed, 22 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 27ca1aa30562..a91f2628c981 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -2438,13 +2438,17 @@ HANDLE_IOCTL(0x1260, broken_blkgetsize) HANDLE_IOCTL(BLKFRAGET, w_long) HANDLE_IOCTL(BLKSECTGET, w_long) HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans) HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans) HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans) HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans) HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_WCACHE, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_ACOUSTIC, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_ADDRESS, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_BUSSTATE, hdio_ioctl_trans) HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans) HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans) HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans) diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index 4e1663d7691e..cfdb4f6a89d4 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -61,17 +61,23 @@ COMPATIBLE_IOCTL(FIGETBSZ) * Some need translations, these do not. */ COMPATIBLE_IOCTL(HDIO_GET_IDENTITY) -COMPATIBLE_IOCTL(HDIO_SET_DMA) -COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR) -COMPATIBLE_IOCTL(HDIO_SET_NOWERR) -COMPATIBLE_IOCTL(HDIO_SET_32BIT) -COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT) -COMPATIBLE_IOCTL(HDIO_DRIVE_CMD) COMPATIBLE_IOCTL(HDIO_DRIVE_TASK) -COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE) -COMPATIBLE_IOCTL(HDIO_SET_NICE) -COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS) +COMPATIBLE_IOCTL(HDIO_DRIVE_CMD) +ULONG_IOCTL(HDIO_SET_MULTCOUNT) +ULONG_IOCTL(HDIO_SET_UNMASKINTR) +ULONG_IOCTL(HDIO_SET_KEEPSETTINGS) +ULONG_IOCTL(HDIO_SET_32BIT) +ULONG_IOCTL(HDIO_SET_NOWERR) +ULONG_IOCTL(HDIO_SET_DMA) +ULONG_IOCTL(HDIO_SET_PIO_MODE) +ULONG_IOCTL(HDIO_SET_NICE) +ULONG_IOCTL(HDIO_SET_WCACHE) +ULONG_IOCTL(HDIO_SET_ACOUSTIC) +ULONG_IOCTL(HDIO_SET_BUSSTATE) +ULONG_IOCTL(HDIO_SET_ADDRESS) COMPATIBLE_IOCTL(HDIO_SCAN_HWIF) +/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */ +COMPATIBLE_IOCTL(0x330) /* 0x02 -- Floppy ioctls */ COMPATIBLE_IOCTL(FDMSGON) COMPATIBLE_IOCTL(FDMSGOFF) -- cgit v1.2.3 From 01a3ee2b203e511e20f98b85a9172fd32c53e87c Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Wed, 11 Oct 2006 01:21:55 -0700 Subject: [PATCH] bitmap: parse input from kernel and user buffers lib/bitmap.c:bitmap_parse() is a library function that received as input a user buffer. This seemed to have originated from the way the write_proc function of the /proc filesystem operates. This has been reworked to not use kmalloc and eliminates a lot of get_user() overhead by performing one access_ok before using __get_user(). We need to test if we are in kernel or user space (is_user) and access the buffer differently. We cannot use __get_user() to access kernel addresses in all cases, for example in architectures with separate address space for kernel and user. This function will be useful for other uses as well; for example, taking input for /sysfs instead of /proc, so it was changed to accept kernel buffers. We have this use for the Linux UWB project, as part as the upcoming bandwidth allocator code. Only a few routines used this function and they were changed too. Signed-off-by: Reinette Chatre Signed-off-by: Inaky Perez-Gonzalez Cc: Paul Jackson Cc: Joe Korty Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/bitmap.h | 13 ++++++++++-- include/linux/cpumask.h | 14 ++++++------- include/linux/nodemask.h | 14 ++++++------- kernel/irq/proc.c | 2 +- kernel/profile.c | 2 +- lib/bitmap.c | 54 ++++++++++++++++++++++++++++++++++++++---------- 6 files changed, 70 insertions(+), 29 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index dcc5de7cc487..64b4641904fe 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -46,7 +46,8 @@ * bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src) * bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit) * bitmap_scnprintf(buf, len, src, nbits) Print bitmap src to buf - * bitmap_parse(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf + * bitmap_parse(buf, buflen, dst, nbits) Parse bitmap dst from kernel buf + * bitmap_parse_user(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf * bitmap_scnlistprintf(buf, len, src, nbits) Print bitmap src as list to buf * bitmap_parselist(buf, dst, nbits) Parse bitmap dst from list * bitmap_find_free_region(bitmap, bits, order) Find and allocate bit region @@ -106,7 +107,9 @@ extern int __bitmap_weight(const unsigned long *bitmap, int bits); extern int bitmap_scnprintf(char *buf, unsigned int len, const unsigned long *src, int nbits); -extern int bitmap_parse(const char __user *ubuf, unsigned int ulen, +extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user, + unsigned long *dst, int nbits); +extern int bitmap_parse_user(const char __user *ubuf, unsigned int ulen, unsigned long *dst, int nbits); extern int bitmap_scnlistprintf(char *buf, unsigned int len, const unsigned long *src, int nbits); @@ -270,6 +273,12 @@ static inline void bitmap_shift_left(unsigned long *dst, __bitmap_shift_left(dst, src, n, nbits); } +static inline int bitmap_parse(const char *buf, unsigned int buflen, + unsigned long *maskp, int nmaskbits) +{ + return __bitmap_parse(buf, buflen, 0, maskp, nmaskbits); +} + #endif /* __ASSEMBLY__ */ #endif /* __LINUX_BITMAP_H */ diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index b268a3c0c376..d0e8c8b0e34d 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -8,8 +8,8 @@ * See detailed comments in the file linux/bitmap.h describing the * data type on which these cpumasks are based. * - * For details of cpumask_scnprintf() and cpumask_parse(), - * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c. + * For details of cpumask_scnprintf() and cpumask_parse_user(), + * see bitmap_scnprintf() and bitmap_parse_user() in lib/bitmap.c. * For details of cpulist_scnprintf() and cpulist_parse(), see * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c. * For details of cpu_remap(), see bitmap_bitremap in lib/bitmap.c @@ -49,7 +49,7 @@ * unsigned long *cpus_addr(mask) Array of unsigned long's in mask * * int cpumask_scnprintf(buf, len, mask) Format cpumask for printing - * int cpumask_parse(ubuf, ulen, mask) Parse ascii string as cpumask + * int cpumask_parse_user(ubuf, ulen, mask) Parse ascii string as cpumask * int cpulist_scnprintf(buf, len, mask) Format cpumask as list for printing * int cpulist_parse(buf, map) Parse ascii string as cpulist * int cpu_remap(oldbit, old, new) newbit = map(old, new)(oldbit) @@ -273,12 +273,12 @@ static inline int __cpumask_scnprintf(char *buf, int len, return bitmap_scnprintf(buf, len, srcp->bits, nbits); } -#define cpumask_parse(ubuf, ulen, dst) \ - __cpumask_parse((ubuf), (ulen), &(dst), NR_CPUS) -static inline int __cpumask_parse(const char __user *buf, int len, +#define cpumask_parse_user(ubuf, ulen, dst) \ + __cpumask_parse_user((ubuf), (ulen), &(dst), NR_CPUS) +static inline int __cpumask_parse_user(const char __user *buf, int len, cpumask_t *dstp, int nbits) { - return bitmap_parse(buf, len, dstp->bits, nbits); + return bitmap_parse_user(buf, len, dstp->bits, nbits); } #define cpulist_scnprintf(buf, len, src) \ diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 5dce5c21822c..b1063e9cdb1b 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -8,8 +8,8 @@ * See detailed comments in the file linux/bitmap.h describing the * data type on which these nodemasks are based. * - * For details of nodemask_scnprintf() and nodemask_parse(), - * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c. + * For details of nodemask_scnprintf() and nodemask_parse_user(), + * see bitmap_scnprintf() and bitmap_parse_user() in lib/bitmap.c. * For details of nodelist_scnprintf() and nodelist_parse(), see * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c. * For details of node_remap(), see bitmap_bitremap in lib/bitmap.c. @@ -51,7 +51,7 @@ * unsigned long *nodes_addr(mask) Array of unsigned long's in mask * * int nodemask_scnprintf(buf, len, mask) Format nodemask for printing - * int nodemask_parse(ubuf, ulen, mask) Parse ascii string as nodemask + * int nodemask_parse_user(ubuf, ulen, mask) Parse ascii string as nodemask * int nodelist_scnprintf(buf, len, mask) Format nodemask as list for printing * int nodelist_parse(buf, map) Parse ascii string as nodelist * int node_remap(oldbit, old, new) newbit = map(old, new)(oldbit) @@ -288,12 +288,12 @@ static inline int __nodemask_scnprintf(char *buf, int len, return bitmap_scnprintf(buf, len, srcp->bits, nbits); } -#define nodemask_parse(ubuf, ulen, dst) \ - __nodemask_parse((ubuf), (ulen), &(dst), MAX_NUMNODES) -static inline int __nodemask_parse(const char __user *buf, int len, +#define nodemask_parse_user(ubuf, ulen, dst) \ + __nodemask_parse_user((ubuf), (ulen), &(dst), MAX_NUMNODES) +static inline int __nodemask_parse_user(const char __user *buf, int len, nodemask_t *dstp, int nbits) { - return bitmap_parse(buf, len, dstp->bits, nbits); + return bitmap_parse_user(buf, len, dstp->bits, nbits); } #define nodelist_scnprintf(buf, len, src) \ diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 607c7809ad01..9a352667007c 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -57,7 +57,7 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer, if (!irq_desc[irq].chip->set_affinity || no_irq_affinity) return -EIO; - err = cpumask_parse(buffer, count, new_value); + err = cpumask_parse_user(buffer, count, new_value); if (err) return err; diff --git a/kernel/profile.c b/kernel/profile.c index 857300a2afec..f940b462eec9 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -399,7 +399,7 @@ static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffe unsigned long full_count = count, err; cpumask_t new_value; - err = cpumask_parse(buffer, count, new_value); + err = cpumask_parse_user(buffer, count, new_value); if (err) return err; diff --git a/lib/bitmap.c b/lib/bitmap.c index d71e38c54ea5..037fa9aa2ed7 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -316,10 +316,11 @@ int bitmap_scnprintf(char *buf, unsigned int buflen, EXPORT_SYMBOL(bitmap_scnprintf); /** - * bitmap_parse - convert an ASCII hex string into a bitmap. - * @ubuf: pointer to buffer in user space containing string. - * @ubuflen: buffer size in bytes. If string is smaller than this + * __bitmap_parse - convert an ASCII hex string into a bitmap. + * @buf: pointer to buffer containing string. + * @buflen: buffer size in bytes. If string is smaller than this * then it must be terminated with a \0. + * @is_user: location of buffer, 0 indicates kernel space * @maskp: pointer to bitmap array that will contain result. * @nmaskbits: size of bitmap, in bits. * @@ -330,11 +331,13 @@ EXPORT_SYMBOL(bitmap_scnprintf); * characters and for grouping errors such as "1,,5", ",44", "," and "". * Leading and trailing whitespace accepted, but not embedded whitespace. */ -int bitmap_parse(const char __user *ubuf, unsigned int ubuflen, - unsigned long *maskp, int nmaskbits) +int __bitmap_parse(const char *buf, unsigned int buflen, + int is_user, unsigned long *maskp, + int nmaskbits) { int c, old_c, totaldigits, ndigits, nchunks, nbits; u32 chunk; + const char __user *ubuf = buf; bitmap_zero(maskp, nmaskbits); @@ -343,11 +346,15 @@ int bitmap_parse(const char __user *ubuf, unsigned int ubuflen, chunk = ndigits = 0; /* Get the next chunk of the bitmap */ - while (ubuflen) { + while (buflen) { old_c = c; - if (get_user(c, ubuf++)) - return -EFAULT; - ubuflen--; + if (is_user) { + if (__get_user(c, ubuf++)) + return -EFAULT; + } + else + c = *buf++; + buflen--; if (isspace(c)) continue; @@ -388,11 +395,36 @@ int bitmap_parse(const char __user *ubuf, unsigned int ubuflen, nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ; if (nbits > nmaskbits) return -EOVERFLOW; - } while (ubuflen && c == ','); + } while (buflen && c == ','); return 0; } -EXPORT_SYMBOL(bitmap_parse); +EXPORT_SYMBOL(__bitmap_parse); + +/** + * bitmap_parse_user() + * + * @ubuf: pointer to user buffer containing string. + * @ulen: buffer size in bytes. If string is smaller than this + * then it must be terminated with a \0. + * @maskp: pointer to bitmap array that will contain result. + * @nmaskbits: size of bitmap, in bits. + * + * Wrapper for __bitmap_parse(), providing it with user buffer. + * + * We cannot have this as an inline function in bitmap.h because it needs + * linux/uaccess.h to get the access_ok() declaration and this causes + * cyclic dependencies. + */ +int bitmap_parse_user(const char __user *ubuf, + unsigned int ulen, unsigned long *maskp, + int nmaskbits) +{ + if (!access_ok(VERIFY_READ, ubuf, ulen)) + return -EFAULT; + return __bitmap_parse((const char *)ubuf, ulen, 1, maskp, nmaskbits); +} +EXPORT_SYMBOL(bitmap_parse_user); /* * bscnl_emit(buf, buflen, rbot, rtop, bp) -- cgit v1.2.3 From e50190a8341485b413f599033cb74649f849d939 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 11 Oct 2006 01:22:02 -0700 Subject: [PATCH] Consolidate check_signature There's nothing arch-specific about check_signature(), so move it to . Use a cross between the Alpha and i386 implementations as the generic one. Signed-off-by: Matthew Wilcox Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-alpha/io.h | 13 ------------- include/asm-arm/io.h | 17 ----------------- include/asm-frv/io.h | 21 --------------------- include/asm-i386/io.h | 27 --------------------------- include/asm-m32r/io.h | 32 -------------------------------- include/asm-mips/io.h | 26 -------------------------- include/asm-powerpc/io.h | 26 -------------------------- include/asm-ppc/io.h | 16 ---------------- include/asm-sh/io.h | 16 ---------------- include/asm-sh64/io.h | 16 ---------------- include/asm-sparc64/io.h | 15 --------------- include/asm-x86_64/io.h | 27 --------------------------- include/linux/io.h | 27 +++++++++++++++++++++++++++ 13 files changed, 27 insertions(+), 252 deletions(-) (limited to 'include/linux') diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h index f5ae98c25d1f..5d15af24573b 100644 --- a/include/asm-alpha/io.h +++ b/include/asm-alpha/io.h @@ -533,19 +533,6 @@ extern void outsl (unsigned long port, const void *src, unsigned long count); #define eth_io_copy_and_sum(skb,src,len,unused) \ memcpy_fromio((skb)->data,src,len) -static inline int -check_signature(const volatile void __iomem *io_addr, - const unsigned char *signature, int length) -{ - do { - if (readb(io_addr) != *signature) - return 0; - io_addr++; - signature++; - } while (--length); - return 1; -} - /* * The Alpha Jensen hardware for some rather strange reason puts * the RTC clock at 0x170 instead of 0x70. Probably due to some diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h index 34aaaac4f617..ae999fd5dc67 100644 --- a/include/asm-arm/io.h +++ b/include/asm-arm/io.h @@ -193,23 +193,6 @@ extern void _memset_io(volatile void __iomem *, int, size_t); #define eth_io_copy_and_sum(s,c,l,b) \ eth_copy_and_sum((s),__mem_pci(c),(l),(b)) -static inline int -check_signature(void __iomem *io_addr, const unsigned char *signature, - int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: - return retval; -} - #elif !defined(readb) #define readb(c) (__readwrite_bug("readb"),0) diff --git a/include/asm-frv/io.h b/include/asm-frv/io.h index 7765f5528894..20e44fe00abf 100644 --- a/include/asm-frv/io.h +++ b/include/asm-frv/io.h @@ -385,27 +385,6 @@ static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p) */ #define xlate_dev_kmem_ptr(p) p -/* - * Check BIOS signature - */ -static inline int check_signature(volatile void __iomem *io_addr, - const unsigned char *signature, int length) -{ - int retval = 0; - - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - - retval = 1; -out: - return retval; -} - #endif /* __KERNEL__ */ #endif /* _ASM_IO_H */ diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h index b3724fe93ff1..68df0dc3ab8f 100644 --- a/include/asm-i386/io.h +++ b/include/asm-i386/io.h @@ -224,33 +224,6 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int #define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void __force *)(b),(c),(d)) -/** - * check_signature - find BIOS signatures - * @io_addr: mmio address to check - * @signature: signature block - * @length: length of signature - * - * Perform a signature comparison with the mmio address io_addr. This - * address should have been obtained by ioremap. - * Returns 1 on a match. - */ - -static inline int check_signature(volatile void __iomem * io_addr, - const unsigned char *signature, int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: - return retval; -} - /* * Cache management * diff --git a/include/asm-m32r/io.h b/include/asm-m32r/io.h index 70ad1c949c2b..d06933bd6318 100644 --- a/include/asm-m32r/io.h +++ b/include/asm-m32r/io.h @@ -166,38 +166,6 @@ static inline void _writel(unsigned long l, unsigned long addr) #define flush_write_buffers() do { } while (0) /* M32R_FIXME */ -/** - * check_signature - find BIOS signatures - * @io_addr: mmio address to check - * @signature: signature block - * @length: length of signature - * - * Perform a signature comparison with the ISA mmio address io_addr. - * Returns 1 on a match. - * - * This function is deprecated. New drivers should use ioremap and - * check_signature. - */ - -static inline int check_signature(void __iomem *io_addr, - const unsigned char *signature, int length) -{ - int retval = 0; -#if 0 -printk("check_signature\n"); - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: -#endif - return retval; -} - static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count) { diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h index df624e1ee6e2..c2d124badbe5 100644 --- a/include/asm-mips/io.h +++ b/include/asm-mips/io.h @@ -561,32 +561,6 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *); */ #define eth_io_copy_and_sum(skb,src,len,unused) memcpy_fromio((skb)->data,(src),(len)) -/* - * check_signature - find BIOS signatures - * @io_addr: mmio address to check - * @signature: signature block - * @length: length of signature - * - * Perform a signature comparison with the mmio address io_addr. This - * address should have been obtained by ioremap. - * Returns 1 on a match. - */ -static inline int check_signature(char __iomem *io_addr, - const unsigned char *signature, int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: - return retval; -} - /* * The caches on some architectures aren't dma-coherent and have need to * handle this in software. There are three types of operations that diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h index cbbd8c648df1..3baff8b0fd5a 100644 --- a/include/asm-powerpc/io.h +++ b/include/asm-powerpc/io.h @@ -404,32 +404,6 @@ static inline void __out_be64(volatile unsigned long __iomem *addr, unsigned lon #include -/** - * check_signature - find BIOS signatures - * @io_addr: mmio address to check - * @signature: signature block - * @length: length of signature - * - * Perform a signature comparison with the mmio address io_addr. This - * address should have been obtained by ioremap. - * Returns 1 on a match. - */ -static inline int check_signature(const volatile void __iomem * io_addr, - const unsigned char *signature, int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: - return retval; -} - /* Nothing to do */ #define dma_cache_inv(_start,_size) do { } while (0) diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index 3d9a9e6f3321..a4c411b753ef 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -439,22 +439,6 @@ extern inline void * phys_to_virt(unsigned long address) #define iobarrier_r() eieio() #define iobarrier_w() eieio() -static inline int check_signature(volatile void __iomem * io_addr, - const unsigned char *signature, int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: - return retval; -} - /* * Here comes the ppc implementation of the IOMAP * interfaces. diff --git a/include/asm-sh/io.h b/include/asm-sh/io.h index ed12d38e8c00..a0e55b09e4fd 100644 --- a/include/asm-sh/io.h +++ b/include/asm-sh/io.h @@ -304,22 +304,6 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) #define iounmap(addr) \ __iounmap((addr)) -static inline int check_signature(char __iomem *io_addr, - const unsigned char *signature, int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: - return retval; -} - /* * The caches on some architectures aren't dma-coherent and have need to * handle this in software. There are three types of operations that diff --git a/include/asm-sh64/io.h b/include/asm-sh64/io.h index 252fedbb6621..14d8e7b4bf4b 100644 --- a/include/asm-sh64/io.h +++ b/include/asm-sh64/io.h @@ -178,22 +178,6 @@ extern void iounmap(void *addr); unsigned long onchip_remap(unsigned long addr, unsigned long size, const char* name); extern void onchip_unmap(unsigned long vaddr); -static __inline__ int check_signature(volatile void __iomem *io_addr, - const unsigned char *signature, int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: - return retval; -} - /* * The caches on some architectures aren't dma-coherent and have need to * handle this in software. There are three types of operations that diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h index 0056770e83ad..30b912d8e8bc 100644 --- a/include/asm-sparc64/io.h +++ b/include/asm-sparc64/io.h @@ -440,21 +440,6 @@ _memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n) #define memcpy_toio(d,s,sz) _memcpy_toio(d,s,sz) -static inline int check_signature(void __iomem *io_addr, - const unsigned char *signature, - int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature++) - goto out; - io_addr++; - } while (--length); - retval = 1; -out: - return retval; -} - #define mmiowb() #ifdef __KERNEL__ diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h index 70e91fe76344..6ee9fadaaacb 100644 --- a/include/asm-x86_64/io.h +++ b/include/asm-x86_64/io.h @@ -254,33 +254,6 @@ void memset_io(volatile void __iomem *a, int b, size_t c); #define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d)) -/** - * check_signature - find BIOS signatures - * @io_addr: mmio address to check - * @signature: signature block - * @length: length of signature - * - * Perform a signature comparison with the mmio address io_addr. This - * address should have been obtained by ioremap. - * Returns 1 on a match. - */ - -static inline int check_signature(void __iomem *io_addr, - const unsigned char *signature, int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: - return retval; -} - /* Nothing to do */ #define dma_cache_inv(_start,_size) do { } while (0) diff --git a/include/linux/io.h b/include/linux/io.h index 2ad96c3f0e4e..81877ea39309 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -28,4 +28,31 @@ void __iowrite64_copy(void __iomem *to, const void *from, size_t count); int ioremap_page_range(unsigned long addr, unsigned long end, unsigned long phys_addr, pgprot_t prot); +/** + * check_signature - find BIOS signatures + * @io_addr: mmio address to check + * @signature: signature block + * @length: length of signature + * + * Perform a signature comparison with the mmio address io_addr. This + * address should have been obtained by ioremap. + * Returns 1 on a match. + */ + +static inline int check_signature(const volatile void __iomem *io_addr, + const unsigned char *signature, int length) +{ + int retval = 0; + do { + if (readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } while (length); + retval = 1; +out: + return retval; +} + #endif /* _LINUX_IO_H */ -- cgit v1.2.3 From c751c1dbb1289d220a8a175ba0df47706ce95a7e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 11 Oct 2006 01:22:11 -0700 Subject: [PATCH] include linux/types.h in linux/nbd.h The nbd header uses __be32 and such types but doesn't actually include the header that defines these things (linux/types.h); so let's include it. Signed-off-by: Mike Frysinger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/nbd.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/nbd.h b/include/linux/nbd.h index e712e7d47cc2..d6b6dc09ad97 100644 --- a/include/linux/nbd.h +++ b/include/linux/nbd.h @@ -15,6 +15,8 @@ #ifndef LINUX_NBD_H #define LINUX_NBD_H +#include + #define NBD_SET_SOCK _IO( 0xab, 0 ) #define NBD_SET_BLKSIZE _IO( 0xab, 1 ) #define NBD_SET_SIZE _IO( 0xab, 2 ) -- cgit v1.2.3 From c636ebdb186bf37f98d3839f69293597723edb36 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 11 Oct 2006 01:22:19 -0700 Subject: [PATCH] VFS: Destroy the dentries contributed by a superblock on unmounting The attached patch destroys all the dentries attached to a superblock in one go by: (1) Destroying the tree rooted at s_root. (2) Destroying every entry in the anon list, one at a time. (3) Each entry in the anon list has its subtree consumed from the leaves inwards. This reduces the amount of work generic_shutdown_super() does, and avoids iterating through the dentry_unused list. Note that locking is almost entirely absent in the shrink_dcache_for_umount*() functions added by this patch. This is because: (1) at the point the filesystem calls generic_shutdown_super(), it is not permitted to further touch the superblock's set of dentries, and nor may it remove aliases from inodes; (2) the dcache memory shrinker now skips dentries that are being unmounted; and (3) the superblock no longer has any external references through which the VFS can reach it. Given these points, the only locking we need to do is when we remove dentries from the unused list and the name hashes, which we do a directory's worth at a time. We also don't need to guard against reference counts going to zero unexpectedly and removing bits of the tree we're working on as nothing else can call dput(). A cut down version of dentry_iput() has been folded into shrink_dcache_for_umount_subtree() function. Apart from not needing to unlock things, it also doesn't need to check for inotify watches. In this version of the patch, the complaint about a dentry still being in use has been expanded from a single BUG_ON() and now gives much more information. Signed-off-by: David Howells Acked-by: NeilBrown Acked-by: Ian Kent Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dcache.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/super.c | 12 ++--- include/linux/dcache.h | 1 + 3 files changed, 137 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/dcache.c b/fs/dcache.c index 2355bddad8de..2bac4ba1d1d3 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -548,6 +548,136 @@ repeat: spin_unlock(&dcache_lock); } +/* + * destroy a single subtree of dentries for unmount + * - see the comments on shrink_dcache_for_umount() for a description of the + * locking + */ +static void shrink_dcache_for_umount_subtree(struct dentry *dentry) +{ + struct dentry *parent; + + BUG_ON(!IS_ROOT(dentry)); + + /* detach this root from the system */ + spin_lock(&dcache_lock); + if (!list_empty(&dentry->d_lru)) { + dentry_stat.nr_unused--; + list_del_init(&dentry->d_lru); + } + __d_drop(dentry); + spin_unlock(&dcache_lock); + + for (;;) { + /* descend to the first leaf in the current subtree */ + while (!list_empty(&dentry->d_subdirs)) { + struct dentry *loop; + + /* this is a branch with children - detach all of them + * from the system in one go */ + spin_lock(&dcache_lock); + list_for_each_entry(loop, &dentry->d_subdirs, + d_u.d_child) { + if (!list_empty(&loop->d_lru)) { + dentry_stat.nr_unused--; + list_del_init(&loop->d_lru); + } + + __d_drop(loop); + cond_resched_lock(&dcache_lock); + } + spin_unlock(&dcache_lock); + + /* move to the first child */ + dentry = list_entry(dentry->d_subdirs.next, + struct dentry, d_u.d_child); + } + + /* consume the dentries from this leaf up through its parents + * until we find one with children or run out altogether */ + do { + struct inode *inode; + + if (atomic_read(&dentry->d_count) != 0) { + printk(KERN_ERR + "BUG: Dentry %p{i=%lx,n=%s}" + " still in use (%d)" + " [unmount of %s %s]\n", + dentry, + dentry->d_inode ? + dentry->d_inode->i_ino : 0UL, + dentry->d_name.name, + atomic_read(&dentry->d_count), + dentry->d_sb->s_type->name, + dentry->d_sb->s_id); + BUG(); + } + + parent = dentry->d_parent; + if (parent == dentry) + parent = NULL; + else + atomic_dec(&parent->d_count); + + list_del(&dentry->d_u.d_child); + dentry_stat.nr_dentry--; /* For d_free, below */ + + inode = dentry->d_inode; + if (inode) { + dentry->d_inode = NULL; + list_del_init(&dentry->d_alias); + if (dentry->d_op && dentry->d_op->d_iput) + dentry->d_op->d_iput(dentry, inode); + else + iput(inode); + } + + d_free(dentry); + + /* finished when we fall off the top of the tree, + * otherwise we ascend to the parent and move to the + * next sibling if there is one */ + if (!parent) + return; + + dentry = parent; + + } while (list_empty(&dentry->d_subdirs)); + + dentry = list_entry(dentry->d_subdirs.next, + struct dentry, d_u.d_child); + } +} + +/* + * destroy the dentries attached to a superblock on unmounting + * - we don't need to use dentry->d_lock, and only need dcache_lock when + * removing the dentry from the system lists and hashes because: + * - the superblock is detached from all mountings and open files, so the + * dentry trees will not be rearranged by the VFS + * - s_umount is write-locked, so the memory pressure shrinker will ignore + * any dentries belonging to this superblock that it comes across + * - the filesystem itself is no longer permitted to rearrange the dentries + * in this superblock + */ +void shrink_dcache_for_umount(struct super_block *sb) +{ + struct dentry *dentry; + + if (down_read_trylock(&sb->s_umount)) + BUG(); + + dentry = sb->s_root; + sb->s_root = NULL; + atomic_dec(&dentry->d_count); + shrink_dcache_for_umount_subtree(dentry); + + while (!hlist_empty(&sb->s_anon)) { + dentry = hlist_entry(sb->s_anon.first, struct dentry, d_hash); + shrink_dcache_for_umount_subtree(dentry); + } +} + /* * Search for at least 1 mount point in the dentry's subdirs. * We descend to the next level whenever the d_subdirs diff --git a/fs/super.c b/fs/super.c index aec99ddbe53f..47e554c12e76 100644 --- a/fs/super.c +++ b/fs/super.c @@ -260,17 +260,17 @@ int fsync_super(struct super_block *sb) * that need destruction out of superblock, call generic_shutdown_super() * and release aforementioned objects. Note: dentries and inodes _are_ * taken care of and do not need specific handling. + * + * Upon calling this function, the filesystem may no longer alter or + * rearrange the set of dentries belonging to this super_block, nor may it + * change the attachments of dentries to inodes. */ void generic_shutdown_super(struct super_block *sb) { - struct dentry *root = sb->s_root; struct super_operations *sop = sb->s_op; - if (root) { - sb->s_root = NULL; - shrink_dcache_parent(root); - shrink_dcache_sb(sb); - dput(root); + if (sb->s_root) { + shrink_dcache_for_umount(sb); fsync_super(sb); lock_super(sb); sb->s_flags &= ~MS_ACTIVE; diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 44605be59409..63f64a9a5bf7 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -230,6 +230,7 @@ extern struct dentry * d_alloc_anon(struct inode *); extern struct dentry * d_splice_alias(struct inode *, struct dentry *); extern void shrink_dcache_sb(struct super_block *); extern void shrink_dcache_parent(struct dentry *); +extern void shrink_dcache_for_umount(struct super_block *); extern int d_invalidate(struct dentry *); /* only used at mount-time */ -- cgit v1.2.3 From 07646e217f473a3e6213f8228336a9046833d6aa Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 23:45:23 -0400 Subject: Lockdep: fix compile error in drivers/input/serio/serio.c lockdep_set_subclass() was missing in !LOCKDEP case Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- include/linux/lockdep.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 14fec2a23b2e..819f08f1310d 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -268,6 +268,8 @@ static inline int lockdep_internal(void) do { (void)(key); } while (0) #define lockdep_set_class_and_subclass(lock, key, sub) \ do { (void)(key); } while (0) +#define lockdep_set_subclass(lock, sub) do { } while (0) + # define INIT_LOCKDEP # define lockdep_reset() do { debug_locks = 1; } while (0) # define lockdep_free_key_range(start, size) do { } while (0) -- cgit v1.2.3 From 5b368e61c2bcb2666bb66e2acf1d6d85ba6f474d Mon Sep 17 00:00:00 2001 From: Venkat Yekkirala Date: Thu, 5 Oct 2006 15:42:18 -0500 Subject: IPsec: correct semantics for SELinux policy matching Currently when an IPSec policy rule doesn't specify a security context, it is assumed to be "unlabeled" by SELinux, and so the IPSec policy rule fails to match to a flow that it would otherwise match to, unless one has explicitly added an SELinux policy rule allowing the flow to "polmatch" to the "unlabeled" IPSec policy rules. In the absence of such an explicitly added SELinux policy rule, the IPSec policy rule fails to match and so the packet(s) flow in clear text without the otherwise applicable xfrm(s) applied. The above SELinux behavior violates the SELinux security notion of "deny by default" which should actually translate to "encrypt by default" in the above case. This was first reported by Evgeniy Polyakov and the way James Morris was seeing the problem was when connecting via IPsec to a confined service on an SELinux box (vsftpd), which did not have the appropriate SELinux policy permissions to send packets via IPsec. With this patch applied, SELinux "polmatching" of flows Vs. IPSec policy rules will only come into play when there's a explicit context specified for the IPSec policy rule (which also means there's corresponding SELinux policy allowing appropriate domains/flows to polmatch to this context). Secondly, when a security module is loaded (in this case, SELinux), the security_xfrm_policy_lookup() hook can return errors other than access denied, such as -EINVAL. We were not handling that correctly, and in fact inverting the return logic and propagating a false "ok" back up to xfrm_lookup(), which then allowed packets to pass as if they were not associated with an xfrm policy. The solution for this is to first ensure that errno values are correctly propagated all the way back up through the various call chains from security_xfrm_policy_lookup(), and handled correctly. Then, flow_cache_lookup() is modified, so that if the policy resolver fails (typically a permission denied via the security module), the flow cache entry is killed rather than having a null policy assigned (which indicates that the packet can pass freely). This also forces any future lookups for the same flow to consult the security module (e.g. SELinux) for current security policy (rather than, say, caching the error on the flow cache entry). This patch: Fix the selinux side of things. This makes sure SELinux polmatching of flow contexts to IPSec policy rules comes into play only when an explicit context is associated with the IPSec policy rule. Also, this no longer defaults the context of a socket policy to the context of the socket since the "no explicit context" case is now handled properly. Signed-off-by: Venkat Yekkirala Signed-off-by: James Morris --- include/linux/security.h | 24 +++++++------------ include/net/xfrm.h | 3 ++- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/xfrm6_policy.c | 2 +- net/key/af_key.c | 5 ---- net/xfrm/xfrm_policy.c | 7 +++--- net/xfrm/xfrm_user.c | 9 ------- security/dummy.c | 3 ++- security/selinux/include/xfrm.h | 3 ++- security/selinux/xfrm.c | 53 +++++++++++++++++++++++++++++++---------- 10 files changed, 62 insertions(+), 49 deletions(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index 9b5fea81f55e..b200b9856f32 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -882,7 +882,8 @@ struct request_sock; * Check permission when a flow selects a xfrm_policy for processing * XFRMs on a packet. The hook is called when selecting either a * per-socket policy or a generic xfrm policy. - * Return 0 if permission is granted. + * Return 0 if permission is granted, -ESRCH otherwise, or -errno + * on other errors. * @xfrm_state_pol_flow_match: * @x contains the state to match. * @xp contains the policy to check for a match. @@ -891,6 +892,7 @@ struct request_sock; * @xfrm_flow_state_match: * @fl contains the flow key to match. * @xfrm points to the xfrm_state to match. + * @xp points to the xfrm_policy to match. * Return 1 if there is a match. * @xfrm_decode_session: * @skb points to skb to decode. @@ -1388,7 +1390,8 @@ struct security_operations { int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir); int (*xfrm_state_pol_flow_match)(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); - int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm); + int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm, + struct xfrm_policy *xp); int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall); #endif /* CONFIG_SECURITY_NETWORK_XFRM */ @@ -3120,11 +3123,6 @@ static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm return security_ops->xfrm_policy_alloc_security(xp, sec_ctx, NULL); } -static inline int security_xfrm_sock_policy_alloc(struct xfrm_policy *xp, struct sock *sk) -{ - return security_ops->xfrm_policy_alloc_security(xp, NULL, sk); -} - static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) { return security_ops->xfrm_policy_clone_security(old, new); @@ -3175,9 +3173,10 @@ static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, return security_ops->xfrm_state_pol_flow_match(x, xp, fl); } -static inline int security_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) +static inline int security_xfrm_flow_state_match(struct flowi *fl, + struct xfrm_state *xfrm, struct xfrm_policy *xp) { - return security_ops->xfrm_flow_state_match(fl, xfrm); + return security_ops->xfrm_flow_state_match(fl, xfrm, xp); } static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) @@ -3197,11 +3196,6 @@ static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm return 0; } -static inline int security_xfrm_sock_policy_alloc(struct xfrm_policy *xp, struct sock *sk) -{ - return 0; -} - static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) { return 0; @@ -3249,7 +3243,7 @@ static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, } static inline int security_xfrm_flow_state_match(struct flowi *fl, - struct xfrm_state *xfrm) + struct xfrm_state *xfrm, struct xfrm_policy *xp) { return 1; } diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 1e2a4ddec96e..737fdb2ee8a4 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -995,7 +995,8 @@ struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, int create, unsigned short family); extern void xfrm_policy_flush(u8 type); extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); -extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family, int strict); +extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst, + struct flowi *fl, int family, int strict); extern void xfrm_init_pmtu(struct dst_entry *dst); extern wait_queue_head_t km_waitq; diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 7a7a00147e55..1bed0cdf53e3 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -52,7 +52,7 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) xdst->u.rt.fl.fl4_dst == fl->fl4_dst && xdst->u.rt.fl.fl4_src == fl->fl4_src && xdst->u.rt.fl.fl4_tos == fl->fl4_tos && - xfrm_bundle_ok(xdst, fl, AF_INET, 0)) { + xfrm_bundle_ok(policy, xdst, fl, AF_INET, 0)) { dst_clone(dst); break; } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 6a252e2134d1..73cee2ec07e8 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -73,7 +73,7 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) xdst->u.rt6.rt6i_src.plen); if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && - xfrm_bundle_ok(xdst, fl, AF_INET6, + xfrm_bundle_ok(policy, xdst, fl, AF_INET6, (xdst->u.rt6.rt6i_dst.plen != 128 || xdst->u.rt6.rt6i_src.plen != 128))) { dst_clone(dst); diff --git a/net/key/af_key.c b/net/key/af_key.c index ff98e70b0931..20ff7cca1d07 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2928,11 +2928,6 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, if (*dir) goto out; } - else { - *dir = security_xfrm_sock_policy_alloc(xp, sk); - if (*dir) - goto out; - } *dir = pol->sadb_x_policy_dir-1; return xp; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index fffdd34f3baf..695761ff1321 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1744,7 +1744,7 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) static int stale_bundle(struct dst_entry *dst) { - return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0); + return !xfrm_bundle_ok(NULL, (struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0); } void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) @@ -1866,7 +1866,8 @@ EXPORT_SYMBOL(xfrm_init_pmtu); * still valid. */ -int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int strict) +int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, + struct flowi *fl, int family, int strict) { struct dst_entry *dst = &first->u.dst; struct xfrm_dst *last; @@ -1883,7 +1884,7 @@ int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int str if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) return 0; - if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm)) + if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm, pol)) return 0; if (dst->xfrm->km.state != XFRM_STATE_VALID) return 0; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index d54b3a70d5df..2b2e59d8ffbc 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1992,15 +1992,6 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, xp->type = XFRM_POLICY_TYPE_MAIN; copy_templates(xp, ut, nr); - if (!xp->security) { - int err = security_xfrm_sock_policy_alloc(xp, sk); - if (err) { - kfree(xp); - *dir = err; - return NULL; - } - } - *dir = p->dir; return xp; diff --git a/security/dummy.c b/security/dummy.c index aeee70565509..43874c1e6e23 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -881,7 +881,8 @@ static int dummy_xfrm_state_pol_flow_match(struct xfrm_state *x, return 1; } -static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) +static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, + struct xfrm_policy *xp) { return 1; } diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 81eb59890162..526b28019aca 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -19,7 +19,8 @@ int selinux_xfrm_state_delete(struct xfrm_state *x); int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); -int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm); +int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, + struct xfrm_policy *xp); /* diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 3e742b850af6..675b995a67c3 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -77,8 +77,8 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x) */ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) { - int rc = 0; - u32 sel_sid = SECINITSID_UNLABELED; + int rc; + u32 sel_sid; struct xfrm_sec_ctx *ctx; /* Context sid is either set to label or ANY_ASSOC */ @@ -88,11 +88,21 @@ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) sel_sid = ctx->ctx_sid; } + else + /* + * All flows should be treated as polmatch'ing an + * otherwise applicable "non-labeled" policy. This + * would prevent inadvertent "leaks". + */ + return 0; rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL); + if (rc == -EACCES) + rc = -ESRCH; + return rc; } @@ -108,15 +118,20 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * u32 pol_sid; int err; - if (x->security) - state_sid = x->security->ctx_sid; - else - state_sid = SECINITSID_UNLABELED; - - if (xp->security) + if (xp->security) { + if (!x->security) + /* unlabeled SA and labeled policy can't match */ + return 0; + else + state_sid = x->security->ctx_sid; pol_sid = xp->security->ctx_sid; - else - pol_sid = SECINITSID_UNLABELED; + } else + if (x->security) + /* unlabeled policy and labeled SA can't match */ + return 0; + else + /* unlabeled policy and unlabeled SA match all flows */ + return 1; err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, @@ -125,7 +140,11 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * if (err) return 0; - return selinux_xfrm_flow_state_match(fl, x); + err = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, + ASSOCIATION__SENDTO, + NULL)? 0:1; + + return err; } /* @@ -133,12 +152,22 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * * can use a given security association. */ -int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) +int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, + struct xfrm_policy *xp) { int rc = 0; u32 sel_sid = SECINITSID_UNLABELED; struct xfrm_sec_ctx *ctx; + if (!xp->security) + if (!xfrm->security) + return 1; + else + return 0; + else + if (!xfrm->security) + return 0; + /* Context sid is either set to label or ANY_ASSOC */ if ((ctx = xfrm->security)) { if (!selinux_authorizable_ctx(ctx)) -- cgit v1.2.3 From 2b1191af683d16a899c2b81b87b605841ceffdec Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 9 Oct 2006 13:04:35 +0200 Subject: [PATCH] elevator: elevator_type member not used elevator_type field in elevator_type structure is useless: it isn't used anywhere in kernel sources. Signed-off-by: Vasily Tarasov Signed-off-by: Jens Axboe --- include/linux/elevator.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/elevator.h b/include/linux/elevator.h index b3370ef5164d..2fa9f1144228 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -70,7 +70,6 @@ struct elevator_type { struct list_head list; struct elevator_ops ops; - struct elevator_type *elevator_type; struct elv_fs_entry *elevator_attrs; char elevator_name[ELV_NAME_MAX]; struct module *elevator_owner; -- cgit v1.2.3 From cea2885a2e989d1dc19af1fc991717b33b7d1456 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 12 Oct 2006 15:08:45 +0200 Subject: [PATCH] ide-cd: fix breakage with internally queued commands We still need to maintain a private PC style command, since it isn't completely unified with REQ_TYPE_BLOCK_PC yet. Signed-off-by: Jens Axboe --- drivers/ide/ide-cd.c | 5 +++-- include/linux/blkdev.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 69bbb6206a00..e7513e55ace8 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -597,7 +597,7 @@ static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq) struct cdrom_info *cd = drive->driver_data; ide_init_drive_cmd(rq); - rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->cmd_type = REQ_TYPE_ATA_PC; rq->rq_disk = cd->disk; } @@ -2023,7 +2023,8 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block) } info->last_block = block; return action; - } else if (rq->cmd_type == REQ_TYPE_SENSE) { + } else if (rq->cmd_type == REQ_TYPE_SENSE || + rq->cmd_type == REQ_TYPE_ATA_PC) { return cdrom_do_packet_command(drive); } else if (blk_pc_request(rq)) { return cdrom_do_block_pc(drive, rq); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 26f7856ff812..d370d2cfe138 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -157,6 +157,7 @@ enum rq_cmd_type_bits { REQ_TYPE_ATA_CMD, REQ_TYPE_ATA_TASK, REQ_TYPE_ATA_TASKFILE, + REQ_TYPE_ATA_PC, }; /* -- cgit v1.2.3 From 5011915cbb139a331c083e65a61c82e9174f9813 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 Oct 2006 05:12:42 -0300 Subject: V4L/DVB (4746): HM12 is YUV 4:2:0, not YUV 4:1:1 Fix comment in videodev2.h Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index c5fdf6259548..df5c4654360d 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -243,7 +243,7 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */ #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ -#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:1:1 16x16 macroblocks */ +#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:2:0 16x16 macroblocks */ /* see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */ -- cgit v1.2.3 From d7a76e4cb3b4469b1eccb6204c053e3ebcd4c196 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 5 Sep 2006 12:12:24 -0400 Subject: ACPI: consolidate functions in acpi ec driver Unify the following functions: acpi_ec_poll_read() acpi_ec_poll_write() acpi_ec_poll_query() acpi_ec_intr_read() acpi_ec_intr_write() acpi_ec_intr_query() into: acpi_ec_poll_transaction() acpi_ec_intr_transaction() These new functions take as arguments an ACPI EC command, a few bytes to write to the EC data register and a buffer for a few bytes to read from the EC data register. The old _read(), _write(), _query() are just special cases of these functions. Then unified the code in acpi_ec_poll_transaction() and acpi_ec_intr_transaction() a little more. Both functions are now just wrappers around the new acpi_ec_transaction_unlocked() function. The latter contains the EC access logic, the two original function now just do their special way of locking and call the the new function for the actual work. This saves a lot of very similar code. The primary reason for doing this, however, is that my driver for MSI 270 laptops needs to issue some non-standard EC commands in a safe way. Due to this I added a new exported function similar to ec_write()/ec_write() which is called ec_transaction() and is essentially just a wrapper around acpi_ec_{poll,intr}_transaction(). Signed-off-by: Lennart Poettering Acked-by: Luming Yu Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/ec.c | 325 +++++++++++++++------------------------------------ include/linux/acpi.h | 3 + 2 files changed, 98 insertions(+), 230 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e5d796362854..a0dcbad97c45 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -122,12 +122,12 @@ union acpi_ec { static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event); static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event); -static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data); -static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data); -static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data); -static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data); -static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data); -static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data); +static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len); +static int acpi_ec_intr_transaction(union acpi_ec *ec, u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len); static void acpi_ec_gpe_poll_query(void *ec_cxt); static void acpi_ec_gpe_intr_query(void *ec_cxt); static u32 acpi_ec_gpe_poll_handler(void *data); @@ -302,110 +302,95 @@ end: } #endif /* ACPI_FUTURE_USAGE */ -static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data) +static int acpi_ec_transaction(union acpi_ec *ec, u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { if (acpi_ec_poll_mode) - return acpi_ec_poll_read(ec, address, data); + return acpi_ec_poll_transaction(ec, command, wdata, wdata_len, rdata, rdata_len); else - return acpi_ec_intr_read(ec, address, data); + return acpi_ec_intr_transaction(ec, command, wdata, wdata_len, rdata, rdata_len); +} +static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data) +{ + int result; + u8 d; + result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ, &address, 1, &d, 1); + *data = d; + return result; } static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data) { - if (acpi_ec_poll_mode) - return acpi_ec_poll_write(ec, address, data); - else - return acpi_ec_intr_write(ec, address, data); + u8 wdata[2] = { address, data }; + return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, wdata, 2, NULL, 0); } -static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data) + +static int acpi_ec_transaction_unlocked(union acpi_ec *ec, u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { - acpi_status status = AE_OK; - int result = 0; - u32 glk = 0; + int result; + acpi_hw_low_level_write(8, command, &ec->common.command_addr); - if (!ec || !data) - return -EINVAL; + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + if (result) + return result; - *data = 0; + for (; wdata_len > 0; wdata_len --) { - if (ec->common.global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - return -ENODEV; - } + acpi_hw_low_level_write(8, *(wdata++), &ec->common.data_addr); - if (down_interruptible(&ec->poll.sem)) { - result = -ERESTARTSYS; - goto end_nosem; - } - - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, - &ec->common.command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) - goto end; + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + if (result) + return result; + } - acpi_hw_low_level_write(8, address, &ec->common.data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (result) - goto end; - acpi_hw_low_level_read(8, data, &ec->common.data_addr); + for (; rdata_len > 0; rdata_len --) { + u32 d; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", - *data, address)); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (result) + return result; - end: - up(&ec->poll.sem); -end_nosem: - if (ec->common.global_lock) - acpi_release_global_lock(glk); + acpi_hw_low_level_read(8, &d, &ec->common.data_addr); + *(rdata++) = (u8) d; + } - return result; + return 0; } -static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data) +static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { - int result = 0; acpi_status status = AE_OK; + int result; u32 glk = 0; - - if (!ec) + if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) return -EINVAL; + if (rdata) + memset(rdata, 0, rdata_len); + if (ec->common.global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) return -ENODEV; - } + } if (down_interruptible(&ec->poll.sem)) { result = -ERESTARTSYS; goto end_nosem; } - - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, - &ec->common.command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) - goto end; - acpi_hw_low_level_write(8, address, &ec->common.data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) - goto end; - - acpi_hw_low_level_write(8, data, &ec->common.data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) - goto end; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", - data, address)); - - end: + result = acpi_ec_transaction_unlocked(ec, command, + wdata, wdata_len, + rdata, rdata_len); up(&ec->poll.sem); + end_nosem: if (ec->common.global_lock) acpi_release_global_lock(glk); @@ -413,16 +398,18 @@ end_nosem: return result; } -static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data) +static int acpi_ec_intr_transaction(union acpi_ec *ec, u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { - int status = 0; + int status; u32 glk; - - if (!ec || !data) + if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) return -EINVAL; - *data = 0; + if (rdata) + memset(rdata, 0, rdata_len); if (ec->common.global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); @@ -438,72 +425,12 @@ static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data) printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); goto end; } - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, - &ec->common.command_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (status) { - printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); - } - - acpi_hw_low_level_write(8, address, &ec->common.data_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (status) { - printk(KERN_DEBUG PREFIX "read EC, OB not full\n"); - goto end; - } - acpi_hw_low_level_read(8, data, &ec->common.data_addr); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", - *data, address)); - - end: - up(&ec->intr.sem); - - if (ec->common.global_lock) - acpi_release_global_lock(glk); - - return status; -} - -static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data) -{ - int status = 0; - u32 glk; - - - if (!ec) - return -EINVAL; - - if (ec->common.global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - return -ENODEV; - } - - WARN_ON(in_interrupt()); - down(&ec->intr.sem); - - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (status) { - printk(KERN_DEBUG PREFIX "write EC, IB not empty\n"); - } - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, - &ec->common.command_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (status) { - printk(KERN_DEBUG PREFIX "write EC, IB not empty\n"); - } - - acpi_hw_low_level_write(8, address, &ec->common.data_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (status) { - printk(KERN_DEBUG PREFIX "write EC, IB not empty\n"); - } - acpi_hw_low_level_write(8, data, &ec->common.data_addr); - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", - data, address)); + status = acpi_ec_transaction_unlocked(ec, command, + wdata, wdata_len, + rdata, rdata_len); +end: up(&ec->intr.sem); if (ec->common.global_lock) @@ -554,106 +481,44 @@ int ec_write(u8 addr, u8 val) EXPORT_SYMBOL(ec_write); -static int acpi_ec_query(union acpi_ec *ec, u32 * data) -{ - if (acpi_ec_poll_mode) - return acpi_ec_poll_query(ec, data); - else - return acpi_ec_intr_query(ec, data); -} -static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data) +extern int ec_transaction(u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len) { - int result = 0; - acpi_status status = AE_OK; - u32 glk = 0; - - - if (!ec || !data) - return -EINVAL; - - *data = 0; - - if (ec->common.global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - return -ENODEV; - } - - /* - * Query the EC to find out which _Qxx method we need to evaluate. - * Note that successful completion of the query causes the ACPI_EC_SCI - * bit to be cleared (and thus clearing the interrupt source). - */ - if (down_interruptible(&ec->poll.sem)) { - result = -ERESTARTSYS; - goto end_nosem; - } - - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, - &ec->common.command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (result) - goto end; + union acpi_ec *ec; - acpi_hw_low_level_read(8, data, &ec->common.data_addr); - if (!*data) - result = -ENODATA; + if (!first_ec) + return -ENODEV; - end: - up(&ec->poll.sem); -end_nosem: - if (ec->common.global_lock) - acpi_release_global_lock(glk); + ec = acpi_driver_data(first_ec); - return result; + return acpi_ec_transaction(ec, command, wdata, wdata_len, rdata, rdata_len); } -static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data) -{ - int status = 0; - u32 glk; +EXPORT_SYMBOL(ec_transaction); - if (!ec || !data) - return -EINVAL; - *data = 0; +static int acpi_ec_query(union acpi_ec *ec, u32 * data) { + int result; + u8 d; - if (ec->common.global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - return -ENODEV; - } + if (!ec || !data) + return -EINVAL; - down(&ec->intr.sem); + /* + * Query the EC to find out which _Qxx method we need to evaluate. + * Note that successful completion of the query causes the ACPI_EC_SCI + * bit to be cleared (and thus clearing the interrupt source). + */ - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (status) { - printk(KERN_DEBUG PREFIX "query EC, IB not empty\n"); - goto end; - } - /* - * Query the EC to find out which _Qxx method we need to evaluate. - * Note that successful completion of the query causes the ACPI_EC_SCI - * bit to be cleared (and thus clearing the interrupt source). - */ - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, - &ec->common.command_addr); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (status) { - printk(KERN_DEBUG PREFIX "query EC, OB not full\n"); - goto end; - } - - acpi_hw_low_level_read(8, data, &ec->common.data_addr); - if (!*data) - status = -ENODATA; + result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1); + if (result) + return result; - end: - up(&ec->intr.sem); + if (!d) + return -ENODATA; - if (ec->common.global_lock) - acpi_release_global_lock(glk); - - return status; + *data = d; + return 0; } /* -------------------------------------------------------------------------- diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 88b5dfd8ee12..2b0c955590fe 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -494,6 +494,9 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver); extern int ec_read(u8 addr, u8 *val); extern int ec_write(u8 addr, u8 val); +extern int ec_transaction(u8 command, + const u8 *wdata, unsigned wdata_len, + u8 *rdata, unsigned rdata_len); #endif /*CONFIG_ACPI_EC*/ -- cgit v1.2.3 From aaa248f6c9c81b2683db7dbb0689cd5ed1c86d88 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 00:09:42 -0700 Subject: [PATCH] rename net_random to random32 Make net_random() more widely available by calling it random32 akpm: hopefully this will permit the removal of carta_random32. That needs confirmation from Stephane - this code looks somewhat more computationally expensive, and has a different (ie: callee-stateful) interface. [akpm@osdl.org: lots of build fixes, cleanups] Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Cc: Stephane Eranian Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/net.h | 7 +-- include/linux/random.h | 3 ++ lib/Makefile | 2 +- lib/random32.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++ net/core/dev.c | 2 - net/core/utils.c | 116 ---------------------------------------- 6 files changed, 150 insertions(+), 122 deletions(-) create mode 100644 lib/random32.c (limited to 'include/linux') diff --git a/include/linux/net.h b/include/linux/net.h index c257f716e00f..15c733b816f0 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -19,6 +19,7 @@ #define _LINUX_NET_H #include +#include #include struct poll_table_struct; @@ -193,9 +194,9 @@ extern int sock_map_fd(struct socket *sock); extern struct socket *sockfd_lookup(int fd, int *err); #define sockfd_put(sock) fput(sock->file) extern int net_ratelimit(void); -extern unsigned long net_random(void); -extern void net_srandom(unsigned long); -extern void net_random_init(void); + +#define net_random() random32() +#define net_srandom(seed) srandom32(seed) extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t len); diff --git a/include/linux/random.h b/include/linux/random.h index 5d6456bcdeba..0248b30e306d 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -69,6 +69,9 @@ extern struct file_operations random_fops, urandom_fops; unsigned int get_random_int(void); unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len); +u32 random32(void); +void srandom32(u32 seed); + #endif /* __KERNEL___ */ #endif /* _LINUX_RANDOM_H */ diff --git a/lib/Makefile b/lib/Makefile index 59070dbfbeb4..4b8052f6a7b0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -12,7 +12,7 @@ lib-$(CONFIG_SMP) += cpumask.o lib-y += kobject.o kref.o kobject_uevent.o klist.o -obj-y += sort.o parser.o halfmd4.o iomap_copy.o debug_locks.o +obj-y += sort.o parser.o halfmd4.o iomap_copy.o debug_locks.o random32.o ifeq ($(CONFIG_DEBUG_KOBJECT),y) CFLAGS_kobject.o += -DDEBUG diff --git a/lib/random32.c b/lib/random32.c new file mode 100644 index 000000000000..4a15ce51cea7 --- /dev/null +++ b/lib/random32.c @@ -0,0 +1,142 @@ +/* + This is a maximally equidistributed combined Tausworthe generator + based on code from GNU Scientific Library 1.5 (30 Jun 2004) + + x_n = (s1_n ^ s2_n ^ s3_n) + + s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) + s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25)) + s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11)) + + The period of this generator is about 2^88. + + From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe + Generators", Mathematics of Computation, 65, 213 (1996), 203--213. + + This is available on the net from L'Ecuyer's home page, + + http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps + ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps + + There is an erratum in the paper "Tables of Maximally + Equidistributed Combined LFSR Generators", Mathematics of + Computation, 68, 225 (1999), 261--269: + http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps + + ... the k_j most significant bits of z_j must be non- + zero, for each j. (Note: this restriction also applies to the + computer code given in [4], but was mistakenly not mentioned in + that paper.) + + This affects the seeding procedure by imposing the requirement + s1 > 1, s2 > 7, s3 > 15. + +*/ + +#include +#include +#include +#include + +struct rnd_state { + u32 s1, s2, s3; +}; + +static DEFINE_PER_CPU(struct rnd_state, net_rand_state); + +static u32 __random32(struct rnd_state *state) +{ +#define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) + + state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); + state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); + state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); + + return (state->s1 ^ state->s2 ^ state->s3); +} + +static void __set_random32(struct rnd_state *state, unsigned long s) +{ + if (s == 0) + s = 1; /* default seed is 1 */ + +#define LCG(n) (69069 * n) + state->s1 = LCG(s); + state->s2 = LCG(state->s1); + state->s3 = LCG(state->s2); + + /* "warm it up" */ + __random32(state); + __random32(state); + __random32(state); + __random32(state); + __random32(state); + __random32(state); +} + +/** + * random32 - pseudo random number generator + * + * A 32 bit pseudo-random number is generated using a fast + * algorithm suitable for simulation. This algorithm is NOT + * considered safe for cryptographic use. + */ +u32 random32(void) +{ + unsigned long r; + struct rnd_state *state = &get_cpu_var(net_rand_state); + r = __random32(state); + put_cpu_var(state); + return r; +} +EXPORT_SYMBOL(random32); + +/** + * srandom32 - add entropy to pseudo random number generator + * @seed: seed value + * + * Add some additional seeding to the random32() pool. + * Note: this pool is per cpu so it only affects current CPU. + */ +void srandom32(u32 entropy) +{ + struct rnd_state *state = &get_cpu_var(net_rand_state); + __set_random32(state, state->s1 ^ entropy); + put_cpu_var(state); +} +EXPORT_SYMBOL(srandom32); + +/* + * Generate some initially weak seeding values to allow + * to start the random32() engine. + */ +static int __init random32_init(void) +{ + int i; + + for_each_possible_cpu(i) { + struct rnd_state *state = &per_cpu(net_rand_state,i); + __set_random32(state, i + jiffies); + } + return 0; +} +core_initcall(random32_init); + +/* + * Generate better values after random number generator + * is fully initalized. + */ +static int __init random32_reseed(void) +{ + int i; + unsigned long seed; + + for_each_possible_cpu(i) { + struct rnd_state *state = &per_cpu(net_rand_state,i); + + get_random_bytes(&seed, sizeof(seed)); + __set_random32(state, seed); + } + return 0; +} +late_initcall(random32_reseed); diff --git a/net/core/dev.c b/net/core/dev.c index 4d891beab138..81c426adcd1e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3502,8 +3502,6 @@ static int __init net_dev_init(void) BUG_ON(!dev_boot_phase); - net_random_init(); - if (dev_proc_init()) goto out; diff --git a/net/core/utils.c b/net/core/utils.c index 94c5d761c830..d93fe64f6693 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -30,119 +30,6 @@ #include #include -/* - This is a maximally equidistributed combined Tausworthe generator - based on code from GNU Scientific Library 1.5 (30 Jun 2004) - - x_n = (s1_n ^ s2_n ^ s3_n) - - s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) - s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25)) - s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11)) - - The period of this generator is about 2^88. - - From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe - Generators", Mathematics of Computation, 65, 213 (1996), 203--213. - - This is available on the net from L'Ecuyer's home page, - - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps - ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps - - There is an erratum in the paper "Tables of Maximally - Equidistributed Combined LFSR Generators", Mathematics of - Computation, 68, 225 (1999), 261--269: - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps - - ... the k_j most significant bits of z_j must be non- - zero, for each j. (Note: this restriction also applies to the - computer code given in [4], but was mistakenly not mentioned in - that paper.) - - This affects the seeding procedure by imposing the requirement - s1 > 1, s2 > 7, s3 > 15. - -*/ -struct nrnd_state { - u32 s1, s2, s3; -}; - -static DEFINE_PER_CPU(struct nrnd_state, net_rand_state); - -static u32 __net_random(struct nrnd_state *state) -{ -#define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) - - state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); - state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); - state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); - - return (state->s1 ^ state->s2 ^ state->s3); -} - -static void __net_srandom(struct nrnd_state *state, unsigned long s) -{ - if (s == 0) - s = 1; /* default seed is 1 */ - -#define LCG(n) (69069 * n) - state->s1 = LCG(s); - state->s2 = LCG(state->s1); - state->s3 = LCG(state->s2); - - /* "warm it up" */ - __net_random(state); - __net_random(state); - __net_random(state); - __net_random(state); - __net_random(state); - __net_random(state); -} - - -unsigned long net_random(void) -{ - unsigned long r; - struct nrnd_state *state = &get_cpu_var(net_rand_state); - r = __net_random(state); - put_cpu_var(state); - return r; -} - - -void net_srandom(unsigned long entropy) -{ - struct nrnd_state *state = &get_cpu_var(net_rand_state); - __net_srandom(state, state->s1^entropy); - put_cpu_var(state); -} - -void __init net_random_init(void) -{ - int i; - - for_each_possible_cpu(i) { - struct nrnd_state *state = &per_cpu(net_rand_state,i); - __net_srandom(state, i+jiffies); - } -} - -static int net_random_reseed(void) -{ - int i; - unsigned long seed; - - for_each_possible_cpu(i) { - struct nrnd_state *state = &per_cpu(net_rand_state,i); - - get_random_bytes(&seed, sizeof(seed)); - __net_srandom(state, seed); - } - return 0; -} -late_initcall(net_random_reseed); - int net_msg_cost = 5*HZ; int net_msg_burst = 10; @@ -153,10 +40,7 @@ int net_ratelimit(void) { return __printk_ratelimit(net_msg_cost, net_msg_burst); } - -EXPORT_SYMBOL(net_random); EXPORT_SYMBOL(net_ratelimit); -EXPORT_SYMBOL(net_srandom); /* * Convert an ASCII string to binary IP. -- cgit v1.2.3 From a460e745e8f9c75a0525ff94154a0629f9d3e05d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 17 Oct 2006 00:10:03 -0700 Subject: [PATCH] genirq: clean up irq-flow-type naming Introduce desc->name and eliminate the handle_irq_name() hack. Add set_irq_chip_and_handler_name() to set the flow type and name at once. Signed-off-by: Ingo Molnar Acked-by: Thomas Gleixner Cc: "Eric W. Biederman" Cc: Matthew Wilcox Cc: Kyle McMartin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/i8259.c | 7 ++++--- arch/i386/kernel/io_apic.c | 17 ++++++++++------- arch/i386/kernel/irq.c | 2 +- arch/x86_64/kernel/i8259.c | 7 ++++--- arch/x86_64/kernel/io_apic.c | 15 ++++++++------- arch/x86_64/kernel/irq.c | 2 +- include/linux/irq.h | 22 ++++++++++------------ kernel/irq/chip.c | 33 +++++++++------------------------ 8 files changed, 47 insertions(+), 58 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index d53eafb6daa7..62996cd17084 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -113,7 +113,8 @@ void make_8259A_irq(unsigned int irq) { disable_irq_nosync(irq); io_apic_irqs &= ~(1<name); - seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); + seq_printf(p, "-%-8s", irq_desc[i].name); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 0612a33bb896..c4ef801b765b 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -178,7 +178,8 @@ void make_8259A_irq(unsigned int irq) { disable_irq_nosync(irq); io_apic_irqs &= ~(1<name); - seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); + seq_printf(p, "-%-8s", irq_desc[i].name); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) diff --git a/include/linux/irq.h b/include/linux/irq.h index c64f3cc7e870..775f5a7da493 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -141,6 +141,7 @@ struct irq_chip { * @pending_mask: pending rebalanced interrupts * @dir: /proc/irq/ procfs entry * @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP + * @name: flow handler name for /proc/interrupts output * * Pad this out to 32 bytes for cache and indexing reasons. */ @@ -165,8 +166,9 @@ struct irq_desc { cpumask_t pending_mask; #endif #ifdef CONFIG_PROC_FS - struct proc_dir_entry *dir; + struct proc_dir_entry *dir; #endif + const char *name; } ____cacheline_aligned; extern struct irq_desc irq_desc[NR_IRQS]; @@ -271,12 +273,6 @@ extern void fastcall handle_simple_irq(unsigned int irq, struct irq_desc *desc); extern void fastcall handle_percpu_irq(unsigned int irq, struct irq_desc *desc); extern void fastcall handle_bad_irq(unsigned int irq, struct irq_desc *desc); -/* - * Get a descriptive string for the highlevel handler, for - * /proc/interrupts output: - */ -extern const char *handle_irq_name(irq_flow_handler_t handle); - /* * Monolithic do_IRQ implementation. * (is an explicit fastcall, because i386 4KSTACKS calls it from assembly) @@ -326,10 +322,12 @@ extern struct irq_chip no_irq_chip; extern struct irq_chip dummy_irq_chip; extern void -set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, - irq_flow_handler_t handle); +set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, + irq_flow_handler_t handle, const char *name); + extern void -__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained); +__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, + const char *name); /* * Set a highlevel flow handler for a given IRQ: @@ -337,7 +335,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained); static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handle) { - __set_irq_handler(irq, handle, 0); + __set_irq_handler(irq, handle, 0, NULL); } /* @@ -349,7 +347,7 @@ static inline void set_irq_chained_handler(unsigned int irq, irq_flow_handler_t handle) { - __set_irq_handler(irq, handle, 1); + __set_irq_handler(irq, handle, 1, NULL); } /* Handle dynamic irq creation and destruction */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 11c99697acfe..2d0dc3efe813 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -499,7 +499,8 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc) #endif /* CONFIG_SMP */ void -__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained) +__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, + const char *name) { struct irq_desc *desc; unsigned long flags; @@ -540,6 +541,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained) desc->depth = 1; } desc->handle_irq = handle; + desc->name = name; if (handle != handle_bad_irq && is_chained) { desc->status &= ~IRQ_DISABLED; @@ -555,30 +557,13 @@ set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, irq_flow_handler_t handle) { set_irq_chip(irq, chip); - __set_irq_handler(irq, handle, 0); + __set_irq_handler(irq, handle, 0, NULL); } -/* - * Get a descriptive string for the highlevel handler, for - * /proc/interrupts output: - */ -const char * -handle_irq_name(irq_flow_handler_t handle) +void +set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, + irq_flow_handler_t handle, const char *name) { - if (handle == handle_level_irq) - return "level "; - if (handle == handle_fasteoi_irq) - return "fasteoi"; - if (handle == handle_edge_irq) - return "edge "; - if (handle == handle_simple_irq) - return "simple "; -#ifdef CONFIG_SMP - if (handle == handle_percpu_irq) - return "percpu "; -#endif - if (handle == handle_bad_irq) - return "bad "; - - return NULL; + set_irq_chip(irq, chip); + __set_irq_handler(irq, handle, 0, name); } -- cgit v1.2.3 From 7762f5a0b709b415fda132258ad37b9f2a1db994 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 17 Oct 2006 00:10:07 -0700 Subject: [PATCH] document i_size_write locking rules Unless someone reads the documentation for write_seqcount_{begin,end} it is not obvious, that i_size_write() needs locking. Especially, that lack of such locking can result in a system hang. Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 34406ed467c3..661c7c572149 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -656,7 +656,11 @@ static inline loff_t i_size_read(struct inode *inode) #endif } - +/* + * NOTE: unlike i_size_read(), i_size_write() does need locking around it + * (normally i_mutex), otherwise on 32bit/SMP an update of i_size_seqcount + * can be lost, resulting in subsequent i_size_read() calls spinning forever. + */ static inline void i_size_write(struct inode *inode, loff_t i_size) { #if BITS_PER_LONG==32 && defined(CONFIG_SMP) -- cgit v1.2.3 From d343fce148a4eee24a907a05c4101d3268045aae Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 17 Oct 2006 00:10:18 -0700 Subject: [PATCH] knfsd: Allow lockd to drop replies as appropriate It is possible for the ->fopen callback from lockd into nfsd to find that an answer cannot be given straight away (an upcall is needed) and so the request has to be 'dropped', to be retried later. That error status is not currently propagated back. So: Change nlm_fopen to return nlm error codes (rather than a private protocol) and define a new nlm_drop_reply code. Cause nlm_drop_reply to cause the rpc request to get rpc_drop_reply when this error comes back. Cause svc_process to drop a request which returns a status of rpc_drop_reply. [akpm@osdl.org: fix warning storm] Cc: Marc Eshel Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svc4proc.c | 12 ++++++------ fs/lockd/svcproc.c | 16 +++++++++------- fs/lockd/svcsubs.c | 6 ------ fs/nfsd/lockd.c | 14 ++++++++------ include/linux/lockd/bind.h | 5 +++++ include/linux/lockd/xdr.h | 4 ++++ include/linux/sunrpc/msg_prot.h | 4 +++- include/linux/sunrpc/xdr.h | 1 + net/sunrpc/svc.c | 5 +++++ 9 files changed, 41 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index fa370f6eb07b..399ad11b97be 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -96,7 +96,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now check for conflicting locks */ resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock); @@ -126,7 +126,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; #if 0 /* If supplied state doesn't match current state, we assume it's @@ -169,7 +169,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Try to cancel request. */ resp->status = nlmsvc_cancel_blocked(file, &argp->lock); @@ -202,7 +202,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to remove the lock */ resp->status = nlmsvc_unlock(file, &argp->lock); @@ -339,7 +339,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to create the share */ resp->status = nlmsvc_share_file(host, file, argp); @@ -372,7 +372,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to lock the file */ resp->status = nlmsvc_unshare_file(host, file, argp); diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 75b2c81bcb93..6a931f4ab75c 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -59,7 +59,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_host *host = NULL; struct nlm_file *file = NULL; struct nlm_lock *lock = &argp->lock; - u32 error; + u32 error = 0; /* nfsd callbacks must have been installed for this procedure */ if (!nlmsvc_ops) @@ -88,6 +88,8 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, no_locks: if (host) nlm_release_host(host); + if (error) + return error; return nlm_lck_denied_nolocks; } @@ -122,7 +124,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now check for conflicting locks */ resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock)); @@ -153,7 +155,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; #if 0 /* If supplied state doesn't match current state, we assume it's @@ -196,7 +198,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Try to cancel request. */ resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock)); @@ -229,7 +231,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to remove the lock */ resp->status = cast_status(nlmsvc_unlock(file, &argp->lock)); @@ -368,7 +370,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to create the share */ resp->status = cast_status(nlmsvc_share_file(host, file, argp)); @@ -401,7 +403,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to unshare the file */ resp->status = cast_status(nlmsvc_unshare_file(host, file, argp)); diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index c5f9113cdc70..7dac96e6c82c 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -135,12 +135,6 @@ out_unlock: out_free: kfree(file); -#ifdef CONFIG_LOCKD_V4 - if (nfserr == 1) - nfserr = nlm4_stale_fh; - else -#endif - nfserr = nlm_lck_denied; goto out_unlock; } diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 7b889ff15ae6..9b9e7e127c03 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -39,18 +39,20 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) fh_put(&fh); rqstp->rq_client = NULL; exp_readunlock(); - /* nlm and nfsd don't share error codes. - * we invent: 0 = no error - * 1 = stale file handle - * 2 = other error + /* We return nlm error codes as nlm doesn't know + * about nfsd, but nfsd does know about nlm.. */ switch (nfserr) { case nfs_ok: return 0; + case nfserr_dropit: + return nlm_drop_reply; +#ifdef CONFIG_LOCKD_V4 case nfserr_stale: - return 1; + return nlm4_stale_fh; +#endif default: - return 2; + return nlm_lck_denied; } } diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index 81e3a185f951..aa50d89eacd7 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h @@ -10,6 +10,11 @@ #define LINUX_LOCKD_BIND_H #include +/* need xdr-encoded error codes too, so... */ +#include +#ifdef CONFIG_LOCKD_V4 +#include +#endif /* Dummy declarations */ struct svc_rqst; diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h index bb0a0f1caa91..66fdae3b490c 100644 --- a/include/linux/lockd/xdr.h +++ b/include/linux/lockd/xdr.h @@ -13,6 +13,8 @@ #include #include +struct svc_rqst; + #define NLM_MAXCOOKIELEN 32 #define NLM_MAXSTRLEN 1024 @@ -22,6 +24,8 @@ #define nlm_lck_blocked __constant_htonl(NLM_LCK_BLOCKED) #define nlm_lck_denied_grace_period __constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD) +#define nlm_drop_reply __constant_htonl(30000) + /* Lock info passed via NLM */ struct nlm_lock { char * caller; diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h index 1e65f2dd80e5..606cb2165232 100644 --- a/include/linux/sunrpc/msg_prot.h +++ b/include/linux/sunrpc/msg_prot.h @@ -56,7 +56,9 @@ enum rpc_accept_stat { RPC_PROG_MISMATCH = 2, RPC_PROC_UNAVAIL = 3, RPC_GARBAGE_ARGS = 4, - RPC_SYSTEM_ERR = 5 + RPC_SYSTEM_ERR = 5, + /* internal use only */ + RPC_DROP_REPLY = 60000, }; enum rpc_reject_stat { diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 953723b09bc6..ac69e5511606 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -74,6 +74,7 @@ struct xdr_buf { #define rpc_proc_unavail __constant_htonl(RPC_PROC_UNAVAIL) #define rpc_garbage_args __constant_htonl(RPC_GARBAGE_ARGS) #define rpc_system_err __constant_htonl(RPC_SYSTEM_ERR) +#define rpc_drop_reply __constant_htonl(RPC_DROP_REPLY) #define rpc_auth_ok __constant_htonl(RPC_AUTH_OK) #define rpc_autherr_badcred __constant_htonl(RPC_AUTH_BADCRED) diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 2807fa0eab40..eb44ec929ca1 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -828,6 +828,11 @@ svc_process(struct svc_rqst *rqstp) *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); /* Encode reply */ + if (*statp == rpc_drop_reply) { + if (procp->pc_release) + procp->pc_release(rqstp, NULL, rqstp->rq_resp); + goto dropit; + } if (*statp == rpc_success && (xdr = procp->pc_encode) && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { dprintk("svc: failed to encode reply\n"); -- cgit v1.2.3 From 58ff407bee5a55f9c1188a3f9d70ffc79485183c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 17 Oct 2006 00:10:19 -0700 Subject: [PATCH] Fix IO error reporting on fsync() When IO error happens on metadata buffer, buffer is freed from memory and later fsync() is called, filesystems like ext2 fail to report EIO. We solve the problem by introducing a pointer to associated address space into the buffer_head. When a buffer is removed from a list of metadata buffers associated with an address space, IO error is transferred from the buffer to the address space, so that fsync can later report it. Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/buffer.c | 11 +++++++++-- include/linux/buffer_head.h | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/buffer.c b/fs/buffer.c index f65ef8821c73..35527dca1dbc 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -452,6 +452,7 @@ static void end_buffer_async_write(struct buffer_head *bh, int uptodate) bdevname(bh->b_bdev, b)); } set_bit(AS_EIO, &page->mapping->flags); + set_buffer_write_io_error(bh); clear_buffer_uptodate(bh); SetPageError(page); } @@ -571,6 +572,10 @@ EXPORT_SYMBOL(mark_buffer_async_write); static inline void __remove_assoc_queue(struct buffer_head *bh) { list_del_init(&bh->b_assoc_buffers); + WARN_ON(!bh->b_assoc_map); + if (buffer_write_io_error(bh)) + set_bit(AS_EIO, &bh->b_assoc_map->flags); + bh->b_assoc_map = NULL; } int inode_has_buffers(struct inode *inode) @@ -669,6 +674,7 @@ void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode) spin_lock(&buffer_mapping->private_lock); list_move_tail(&bh->b_assoc_buffers, &mapping->private_list); + bh->b_assoc_map = mapping; spin_unlock(&buffer_mapping->private_lock); } } @@ -765,7 +771,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list) spin_lock(lock); while (!list_empty(list)) { bh = BH_ENTRY(list->next); - list_del_init(&bh->b_assoc_buffers); + __remove_assoc_queue(bh); if (buffer_dirty(bh) || buffer_locked(bh)) { list_add(&bh->b_assoc_buffers, &tmp); if (buffer_dirty(bh)) { @@ -786,7 +792,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list) while (!list_empty(&tmp)) { bh = BH_ENTRY(tmp.prev); - __remove_assoc_queue(bh); + list_del_init(&bh->b_assoc_buffers); get_bh(bh); spin_unlock(lock); wait_on_buffer(bh); @@ -1167,6 +1173,7 @@ void __bforget(struct buffer_head *bh) spin_lock(&buffer_mapping->private_lock); list_del_init(&bh->b_assoc_buffers); + bh->b_assoc_map = NULL; spin_unlock(&buffer_mapping->private_lock); } __brelse(bh); diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 131ffd37e716..5d9fb0e94156 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -69,6 +69,8 @@ struct buffer_head { bh_end_io_t *b_end_io; /* I/O completion */ void *b_private; /* reserved for b_end_io */ struct list_head b_assoc_buffers; /* associated with another mapping */ + struct address_space *b_assoc_map; /* mapping this buffer is + associated with */ atomic_t b_count; /* users using this buffer_head */ }; -- cgit v1.2.3 From 74d919465a93b6c2b928b29a8ed3e5e41adbfa93 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:55:54 -0400 Subject: [pci_ids] Add Quicknet XJ vendor/device ID's. Signed-off-by: Ben Collins --- include/linux/pci_ids.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f069df245469..f3a168f3c9df 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2351,3 +2351,5 @@ #define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897 #define PCI_DEVICE_ID_RME_DIGI32_8 0x9898 +#define PCI_VENDOR_ID_QUICKNET 0x15E2 +#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500 -- cgit v1.2.3 From 29f3eb64634cf96903a3cdb56b1f9a80bebad17d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 16 Oct 2006 16:20:21 -0700 Subject: pci: Additional search functions In order to finish converting to pci_get_* interfaces we need to add a couple of bits of missing functionaility pci_get_bus_and_slot() provides the equivalent to pci_find_slot() (pci_get_slot is already taken as a name for something similar but not the same) pci_get_device_reverse() is the equivalent of pci_find_device_reverse but refcounting Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/search.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++-- include/linux/pci.h | 3 ++- 2 files changed, 72 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/search.c b/drivers/pci/search.c index d529462d1b53..2f13eba5d5ae 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -139,6 +139,31 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) return dev; } +/** + * pci_get_bus_and_slot - locate PCI device from a given PCI slot + * @bus: number of PCI bus on which desired PCI device resides + * @devfn: encodes number of PCI slot in which the desired PCI + * device resides and the logical device number within that slot + * in case of multi-function devices. + * + * Given a PCI bus and slot/function number, the desired PCI device + * is located in system global list of PCI devices. If the device + * is found, a pointer to its data structure is returned. If no + * device is found, %NULL is returned. The returned device has its + * reference count bumped by one. + */ + +struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn) +{ + struct pci_dev *dev = NULL; + + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + if (dev->bus->number == bus && dev->devfn == devfn) + return dev; + } + return NULL; +} + /** * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids @@ -274,6 +299,45 @@ pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from) return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); } +/** + * pci_get_device_reverse - begin or continue searching for a PCI device by vendor/device id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices in the reverse order of + * pci_get_device. + * If a PCI device is found with a matching @vendor and @device, the reference + * count to the device is incremented and a pointer to its device structure + * is returned Otherwise, %NULL is returned. A new search is initiated by + * passing %NULL as the @from argument. Otherwise if @from is not %NULL, + * searches continue from next device on the global list. The reference + * count for @from is always decremented if it is not %NULL. + */ +struct pci_dev * +pci_get_device_reverse(unsigned int vendor, unsigned int device, struct pci_dev *from) +{ + struct list_head *n; + struct pci_dev *dev; + + WARN_ON(in_interrupt()); + down_read(&pci_bus_sem); + n = from ? from->global_list.prev : pci_devices.prev; + + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); + if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && + (device == PCI_ANY_ID || dev->device == device)) + goto exit; + n = n->prev; + } + dev = NULL; +exit: + dev = pci_dev_get(dev); + up_read(&pci_bus_sem); + pci_dev_put(from); + return dev; +} /** * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id @@ -382,12 +446,16 @@ exit: } EXPORT_SYMBOL(pci_dev_present); -EXPORT_SYMBOL(pci_find_bus); -EXPORT_SYMBOL(pci_find_next_bus); EXPORT_SYMBOL(pci_find_device); EXPORT_SYMBOL(pci_find_device_reverse); EXPORT_SYMBOL(pci_find_slot); +/* For boot time work */ +EXPORT_SYMBOL(pci_find_bus); +EXPORT_SYMBOL(pci_find_next_bus); +/* For everyone */ EXPORT_SYMBOL(pci_get_device); +EXPORT_SYMBOL(pci_get_device_reverse); EXPORT_SYMBOL(pci_get_subsys); EXPORT_SYMBOL(pci_get_slot); +EXPORT_SYMBOL(pci_get_bus_and_slot); EXPORT_SYMBOL(pci_get_class); diff --git a/include/linux/pci.h b/include/linux/pci.h index 5c604f5fad67..09bf88fc80c5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -452,13 +452,14 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); int pci_find_ext_capability (struct pci_dev *dev, int cap); -struct pci_bus * pci_find_next_bus(const struct pci_bus *from); +struct pci_bus *pci_find_next_bus(const struct pci_bus *from); struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from); struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from); struct pci_dev *pci_get_slot (struct pci_bus *bus, unsigned int devfn); +struct pci_dev *pci_get_bus_and_slot (unsigned int bus, unsigned int devfn); struct pci_dev *pci_get_class (unsigned int class, struct pci_dev *from); int pci_dev_present(const struct pci_device_id *ids); -- cgit v1.2.3 From 6b4b78fed47e7380dfe9280b154e8b9bfcd4c86c Mon Sep 17 00:00:00 2001 From: Matt Domsch Date: Fri, 29 Sep 2006 15:23:23 -0500 Subject: PCI: optionally sort device lists breadth-first Problem: New Dell PowerEdge servers have 2 embedded ethernet ports, which are labeled NIC1 and NIC2 on the chassis, in the BIOS setup screens, and in the printed documentation. Assuming no other add-in ethernet ports in the system, Linux 2.4 kernels name these eth0 and eth1 respectively. Many people have come to expect this naming. Linux 2.6 kernels name these eth1 and eth0 respectively (backwards from expectations). I also have reports that various Sun and HP servers have similar behavior. Root cause: Linux 2.4 kernels walk the pci_devices list, which happens to be sorted in breadth-first order (or pcbios_find_device order on i386, which most often is breadth-first also). 2.6 kernels have both the pci_devices list and the pci_bus_type.klist_devices list, the latter is what is walked at driver load time to match the pci_id tables; this klist happens to be in depth-first order. On systems where, for physical routing reasons, NIC1 appears on a lower bus number than NIC2, but NIC2's bridge is discovered first in the depth-first ordering, NIC2 will be discovered before NIC1. If the list were sorted breadth-first, NIC1 would be discovered before NIC2. A PowerEdge 1955 system has the following topology which easily exhibits the difference between depth-first and breadth-first device lists. -[0000:00]-+-00.0 Intel Corporation 5000P Chipset Memory Controller Hub +-02.0-[0000:03-08]--+-00.0-[0000:04-07]--+-00.0-[0000:05-06]----00.0-[0000:06]----00.0 Broadcom Corporation NetXtreme II BCM5708S Gigabit Ethernet (labeled NIC2, 2.4 kernel name eth1, 2.6 kernel name eth0) +-1c.0-[0000:01-02]----00.0-[0000:02]----00.0 Broadcom Corporation NetXtreme II BCM5708S Gigabit Ethernet (labeled NIC1, 2.4 kernel name eth0, 2.6 kernel name eth1) Other factors, such as device driver load order and the presence of PCI slots at various points in the bus hierarchy further complicate this problem; I'm not trying to solve those here, just restore the device order, and thus basic behavior, that 2.4 kernels had. Solution: The solution can come in multiple steps. Suggested fix #1: kernel Patch below optionally sorts the two device lists into breadth-first ordering to maintain compatibility with 2.4 kernels. It adds two new command line options: pci=bfsort pci=nobfsort to force the sort order, or not, as you wish. It also adds DMI checks for the specific Dell systems which exhibit "backwards" ordering, to make them "right". Suggested fix #2: udev rules from userland Many people also have the expectation that embedded NICs are always discovered before add-in NICs (which this patch does not try to do). Using the PCI IRQ Routing Table provided by system BIOS, it's easy to determine which PCI devices are embedded, or if add-in, which PCI slot they're in. I'm working on a tool that would allow udev to name ethernet devices in ascending embedded, slot 1 .. slot N order, subsort by PCI bus/dev/fn breadth-first. It'll be possible to use it independent of udev as well for those distributions that don't use udev in their installers. Suggested fix #3: system board routing rules One can constrain the system board layout to put NIC1 ahead of NIC2 regardless of breadth-first or depth-first discovery order. This adds a significant level of complexity to board routing, and may not be possible in all instances (witness the above systems from several major manufacturers). I don't want to encourage this particular train of thought too far, at the expense of not doing #1 or #2 above. Feedback appreciated. Patch tested on a Dell PowerEdge 1955 blade with 2.6.18. You'll also note I took some liberty and temporarily break the klist abstraction to simplify and speed up the sort algorithm. I think that's both safe and appropriate in this instance. Signed-off-by: Matt Domsch Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 5 ++ arch/i386/pci/common.c | 59 +++++++++++++++++++++++- arch/i386/pci/pci.h | 7 +++ drivers/pci/probe.c | 92 +++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + 5 files changed, 162 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ff571f9298e0..dd00fd556a60 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1231,6 +1231,11 @@ and is between 256 and 4096 characters. It is defined in the file machine check when some devices' config space is read. But various workarounds are disabled and some IOMMU drivers will not work. + bfsort Sort PCI devices into breadth-first order. + This sorting is done to get a device + order compatible with older (<= 2.4) kernels. + nobfsort Don't sort PCI devices into breadth-first order. + pcmv= [HW,PCMCIA] BadgePAD 4 pd. [PARIDE] diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index 68bce194e688..6d5ace845e44 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -20,6 +20,7 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | PCI_PROBE_MMCONF; +int pci_bf_sort; int pci_routeirq; int pcibios_last_bus = -1; unsigned long pirq_table_addr; @@ -117,6 +118,20 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b) pci_read_bridge_bases(b); } +/* + * Only use DMI information to set this if nothing was passed + * on the kernel command line (which was parsed earlier). + */ + +static int __devinit set_bf_sort(struct dmi_system_id *d) +{ + if (pci_bf_sort == pci_bf_sort_default) { + pci_bf_sort = pci_dmi_bf; + printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident); + } + return 0; +} + /* * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) */ @@ -130,11 +145,11 @@ static int __devinit assign_all_busses(struct dmi_system_id *d) } #endif +static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { +#ifdef __i386__ /* * Laptops which need pci=assign-busses to see Cardbus cards */ -static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { -#ifdef __i386__ { .callback = assign_all_busses, .ident = "Samsung X20 Laptop", @@ -144,6 +159,38 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { }, }, #endif /* __i386__ */ + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 1950", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"), + }, + }, + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 1955", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"), + }, + }, + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 2900", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"), + }, + }, + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 2950", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"), + }, + }, {} }; @@ -189,6 +236,8 @@ static int __init pcibios_init(void) pcibios_resource_survey(); + if (pci_bf_sort >= pci_force_bf) + pci_sort_breadthfirst(); #ifdef CONFIG_PCI_BIOS if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) pcibios_sort(); @@ -203,6 +252,12 @@ char * __devinit pcibios_setup(char *str) if (!strcmp(str, "off")) { pci_probe = 0; return NULL; + } else if (!strcmp(str, "bfsort")) { + pci_bf_sort = pci_force_bf; + return NULL; + } else if (!strcmp(str, "nobfsort")) { + pci_bf_sort = pci_force_nobf; + return NULL; } #ifdef CONFIG_PCI_BIOS else if (!strcmp(str, "bios")) { diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index 1814f74569c6..ad065cebd7b9 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h @@ -30,6 +30,13 @@ extern unsigned int pci_probe; extern unsigned long pirq_table_addr; +enum pci_bf_sort_state { + pci_bf_sort_default, + pci_force_nobf, + pci_force_bf, + pci_dmi_bf, +}; + /* pci-i386.c */ extern unsigned int pcibios_max_latency; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a3b0a5eb5054..e159d6604494 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1067,3 +1067,95 @@ EXPORT_SYMBOL(pci_scan_bridge); EXPORT_SYMBOL(pci_scan_single_device); EXPORT_SYMBOL_GPL(pci_scan_child_bus); #endif + +static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b) +{ + if (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1; + else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return 1; + + if (a->bus->number < b->bus->number) return -1; + else if (a->bus->number > b->bus->number) return 1; + + if (a->devfn < b->devfn) return -1; + else if (a->devfn > b->devfn) return 1; + + return 0; +} + +/* + * Yes, this forcably breaks the klist abstraction temporarily. It + * just wants to sort the klist, not change reference counts and + * take/drop locks rapidly in the process. It does all this while + * holding the lock for the list, so objects can't otherwise be + * added/removed while we're swizzling. + */ +static void __init pci_insertion_sort_klist(struct pci_dev *a, struct list_head *list) +{ + struct list_head *pos; + struct klist_node *n; + struct device *dev; + struct pci_dev *b; + + list_for_each(pos, list) { + n = container_of(pos, struct klist_node, n_node); + dev = container_of(n, struct device, knode_bus); + b = to_pci_dev(dev); + if (pci_sort_bf_cmp(a, b) <= 0) { + list_move_tail(&a->dev.knode_bus.n_node, &b->dev.knode_bus.n_node); + return; + } + } + list_move_tail(&a->dev.knode_bus.n_node, list); +} + +static void __init pci_sort_breadthfirst_klist(void) +{ + LIST_HEAD(sorted_devices); + struct list_head *pos, *tmp; + struct klist_node *n; + struct device *dev; + struct pci_dev *pdev; + + spin_lock(&pci_bus_type.klist_devices.k_lock); + list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) { + n = container_of(pos, struct klist_node, n_node); + dev = container_of(n, struct device, knode_bus); + pdev = to_pci_dev(dev); + pci_insertion_sort_klist(pdev, &sorted_devices); + } + list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list); + spin_unlock(&pci_bus_type.klist_devices.k_lock); +} + +static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list) +{ + struct pci_dev *b; + + list_for_each_entry(b, list, global_list) { + if (pci_sort_bf_cmp(a, b) <= 0) { + list_move_tail(&a->global_list, &b->global_list); + return; + } + } + list_move_tail(&a->global_list, list); +} + +static void __init pci_sort_breadthfirst_devices(void) +{ + LIST_HEAD(sorted_devices); + struct pci_dev *dev, *tmp; + + down_write(&pci_bus_sem); + list_for_each_entry_safe(dev, tmp, &pci_devices, global_list) { + pci_insertion_sort_devices(dev, &sorted_devices); + } + list_splice(&sorted_devices, &pci_devices); + up_write(&pci_bus_sem); +} + +void __init pci_sort_breadthfirst(void) +{ + pci_sort_breadthfirst_devices(); + pci_sort_breadthfirst_klist(); +} + diff --git a/include/linux/pci.h b/include/linux/pci.h index 09bf88fc80c5..4689e2a699c0 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -443,6 +443,7 @@ extern void pci_remove_bus(struct pci_bus *b); extern void pci_remove_bus_device(struct pci_dev *dev); extern void pci_stop_bus_device(struct pci_dev *dev); void pci_setup_cardbus(struct pci_bus *bus); +extern void pci_sort_breadthfirst(void); /* Generic PCI functions exported to card drivers */ -- cgit v1.2.3 From 7a54f25cef6c763f16c9fd49ae382de162147873 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 13 Oct 2006 20:05:19 -0700 Subject: PCI Hotplug: move pci_hotplug.h to include/linux/ This makes it possible to build pci hotplug drivers outside of the main kernel tree, and Sam keeps telling me to move local header files to their proper places... Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpi_pcihp.c | 2 +- drivers/pci/hotplug/acpiphp.h | 2 +- drivers/pci/hotplug/acpiphp_core.c | 2 +- drivers/pci/hotplug/acpiphp_glue.c | 2 +- drivers/pci/hotplug/acpiphp_ibm.c | 1 - drivers/pci/hotplug/cpci_hotplug_core.c | 2 +- drivers/pci/hotplug/cpci_hotplug_pci.c | 2 +- drivers/pci/hotplug/cpqphp.h | 1 - drivers/pci/hotplug/cpqphp_core.c | 1 + drivers/pci/hotplug/cpqphp_ctrl.c | 1 + drivers/pci/hotplug/cpqphp_nvram.c | 1 + drivers/pci/hotplug/cpqphp_pci.c | 1 + drivers/pci/hotplug/cpqphp_sysfs.c | 1 + drivers/pci/hotplug/fakephp.c | 2 +- drivers/pci/hotplug/ibmphp.h | 2 +- drivers/pci/hotplug/pci_hotplug.h | 236 -------------------------------- drivers/pci/hotplug/pci_hotplug_core.c | 7 +- drivers/pci/hotplug/pciehp.h | 2 +- drivers/pci/hotplug/pcihp_skeleton.c | 2 +- drivers/pci/hotplug/rpadlpar_sysfs.c | 2 +- drivers/pci/hotplug/rpaphp_core.c | 2 +- drivers/pci/hotplug/sgi_hotplug.c | 2 +- drivers/pci/hotplug/shpchp.h | 3 +- include/linux/pci_hotplug.h | 236 ++++++++++++++++++++++++++++++++ 24 files changed, 258 insertions(+), 257 deletions(-) delete mode 100644 drivers/pci/hotplug/pci_hotplug.h create mode 100644 include/linux/pci_hotplug.h (limited to 'include/linux') diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 51cb9f817c22..270a33cc08f6 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -29,10 +29,10 @@ #include #include #include +#include #include #include #include -#include "pci_hotplug.h" #define MY_NAME "acpi_pcihp" diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 7fff07e877c7..59c5b242d86d 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -38,7 +38,7 @@ #include #include /* for KOBJ_NAME_LEN */ #include -#include "pci_hotplug.h" +#include #define dbg(format, arg...) \ do { \ diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index e2fef60c2d06..c57d9d5ce84e 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -37,10 +37,10 @@ #include #include +#include #include #include #include -#include "pci_hotplug.h" #include "acpiphp.h" #define MY_NAME "acpiphp" diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 83e8e4412de5..c44311ac2fd3 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -45,11 +45,11 @@ #include #include +#include #include #include #include "../pci.h" -#include "pci_hotplug.h" #include "acpiphp.h" static LIST_HEAD(bridge_list); diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index d0a07d9ab30c..bd40aee10e16 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -35,7 +35,6 @@ #include #include "acpiphp.h" -#include "pci_hotplug.h" #define DRIVER_VERSION "1.0.1" #define DRIVER_AUTHOR "Irene Zubarev , Vernon Mauery " diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index d06ab4045134..684551559d44 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -29,12 +29,12 @@ #include #include #include +#include #include #include #include #include #include -#include "pci_hotplug.h" #include "cpci_hotplug.h" #define DRIVER_AUTHOR "Scott Murray " diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 4afcaffd031c..7b1beaad2752 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -26,9 +26,9 @@ #include #include #include +#include #include #include "../pci.h" -#include "pci_hotplug.h" #include "cpci_hotplug.h" #define MY_NAME "cpci_hotplug" diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index ea040c32f47d..298ad7f3f4f4 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -28,7 +28,6 @@ #ifndef _CPQPHP_H #define _CPQPHP_H -#include "pci_hotplug.h" #include #include /* for read? and write? functions */ #include /* for delays */ diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 1fc259913b68..5617cfdadc5c 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 3ec2ad7db49a..79ff6b4de3a6 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "cpqphp.h" static u32 configure_new_device(struct controller* ctrl, struct pci_func *func, diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index cf0878917537..298a6cfd8406 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include "cpqphp.h" diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 0d9688952f4a..fc7c74d72595 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "../pci.h" #include "cpqphp.h" #include "cpqphp_nvram.h" diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 5bab666cd67e..634f74d919d3 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "cpqphp.h" diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index aaeb1129132e..e27907c91d92 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -35,10 +35,10 @@ #include #include #include +#include #include #include #include -#include "pci_hotplug.h" #include "../pci.h" #if !defined(MODULE) diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index dba6d8ca9bda..612d96301509 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -30,7 +30,7 @@ * */ -#include "pci_hotplug.h" +#include extern int ibmphp_debug; diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h deleted file mode 100644 index a675a05c4091..000000000000 --- a/drivers/pci/hotplug/pci_hotplug.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * PCI HotPlug Core Functions - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ -#ifndef _PCI_HOTPLUG_H -#define _PCI_HOTPLUG_H - - -/* These values come from the PCI Hotplug Spec */ -enum pci_bus_speed { - PCI_SPEED_33MHz = 0x00, - PCI_SPEED_66MHz = 0x01, - PCI_SPEED_66MHz_PCIX = 0x02, - PCI_SPEED_100MHz_PCIX = 0x03, - PCI_SPEED_133MHz_PCIX = 0x04, - PCI_SPEED_66MHz_PCIX_ECC = 0x05, - PCI_SPEED_100MHz_PCIX_ECC = 0x06, - PCI_SPEED_133MHz_PCIX_ECC = 0x07, - PCI_SPEED_66MHz_PCIX_266 = 0x09, - PCI_SPEED_100MHz_PCIX_266 = 0x0a, - PCI_SPEED_133MHz_PCIX_266 = 0x0b, - PCI_SPEED_66MHz_PCIX_533 = 0x11, - PCI_SPEED_100MHz_PCIX_533 = 0x12, - PCI_SPEED_133MHz_PCIX_533 = 0x13, - PCI_SPEED_UNKNOWN = 0xff, -}; - -/* These values come from the PCI Express Spec */ -enum pcie_link_width { - PCIE_LNK_WIDTH_RESRV = 0x00, - PCIE_LNK_X1 = 0x01, - PCIE_LNK_X2 = 0x02, - PCIE_LNK_X4 = 0x04, - PCIE_LNK_X8 = 0x08, - PCIE_LNK_X12 = 0x0C, - PCIE_LNK_X16 = 0x10, - PCIE_LNK_X32 = 0x20, - PCIE_LNK_WIDTH_UNKNOWN = 0xFF, -}; - -enum pcie_link_speed { - PCIE_2PT5GB = 0x14, - PCIE_LNK_SPEED_UNKNOWN = 0xFF, -}; - -struct hotplug_slot; -struct hotplug_slot_attribute { - struct attribute attr; - ssize_t (*show)(struct hotplug_slot *, char *); - ssize_t (*store)(struct hotplug_slot *, const char *, size_t); -}; -#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr); - -/** - * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use - * @owner: The module owner of this structure - * @enable_slot: Called when the user wants to enable a specific pci slot - * @disable_slot: Called when the user wants to disable a specific pci slot - * @set_attention_status: Called to set the specific slot's attention LED to - * the specified value - * @hardware_test: Called to run a specified hardware test on the specified - * slot. - * @get_power_status: Called to get the current power status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_attention_status: Called to get the current attention status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_latch_status: Called to get the current latch status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_adapter_status: Called to get see if an adapter is present in the slot or not. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_address: Called to get pci address of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_max_bus_speed: Called to get the max bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_cur_bus_speed: Called to get the current bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * - * The table of function pointers that is passed to the hotplug pci core by a - * hotplug pci driver. These functions are called by the hotplug pci core when - * the user wants to do something to a specific slot (query it for information, - * set an LED, enable / disable power, etc.) - */ -struct hotplug_slot_ops { - struct module *owner; - int (*enable_slot) (struct hotplug_slot *slot); - int (*disable_slot) (struct hotplug_slot *slot); - int (*set_attention_status) (struct hotplug_slot *slot, u8 value); - int (*hardware_test) (struct hotplug_slot *slot, u32 value); - int (*get_power_status) (struct hotplug_slot *slot, u8 *value); - int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); - int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); - int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); - int (*get_address) (struct hotplug_slot *slot, u32 *value); - int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); - int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); -}; - -/** - * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot - * @power: if power is enabled or not (1/0) - * @attention_status: if the attention light is enabled or not (1/0) - * @latch_status: if the latch (if any) is open or closed (1/0) - * @adapter_present: if there is a pci board present in the slot or not (1/0) - * @address: (domain << 16 | bus << 8 | dev) - * - * Used to notify the hotplug pci core of the status of a specific slot. - */ -struct hotplug_slot_info { - u8 power_status; - u8 attention_status; - u8 latch_status; - u8 adapter_status; - u32 address; - enum pci_bus_speed max_bus_speed; - enum pci_bus_speed cur_bus_speed; -}; - -/** - * struct hotplug_slot - used to register a physical slot with the hotplug pci core - * @name: the name of the slot being registered. This string must - * be unique amoung slots registered on this system. - * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot - * @info: pointer to the &struct hotplug_slot_info for the initial values for - * this slot. - * @release: called during pci_hp_deregister to free memory allocated in a - * hotplug_slot structure. - * @private: used by the hotplug pci controller driver to store whatever it - * needs. - */ -struct hotplug_slot { - char *name; - struct hotplug_slot_ops *ops; - struct hotplug_slot_info *info; - void (*release) (struct hotplug_slot *slot); - void *private; - - /* Variables below this are for use only by the hotplug pci core. */ - struct list_head slot_list; - struct kobject kobj; -}; -#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) - -extern int pci_hp_register (struct hotplug_slot *slot); -extern int pci_hp_deregister (struct hotplug_slot *slot); -extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, - struct hotplug_slot_info *info); -extern struct subsystem pci_hotplug_slots_subsys; - -/* PCI Setting Record (Type 0) */ -struct hpp_type0 { - u32 revision; - u8 cache_line_size; - u8 latency_timer; - u8 enable_serr; - u8 enable_perr; -}; - -/* PCI-X Setting Record (Type 1) */ -struct hpp_type1 { - u32 revision; - u8 max_mem_read; - u8 avg_max_split; - u16 tot_max_split; -}; - -/* PCI Express Setting Record (Type 2) */ -struct hpp_type2 { - u32 revision; - u32 unc_err_mask_and; - u32 unc_err_mask_or; - u32 unc_err_sever_and; - u32 unc_err_sever_or; - u32 cor_err_mask_and; - u32 cor_err_mask_or; - u32 adv_err_cap_and; - u32 adv_err_cap_or; - u16 pci_exp_devctl_and; - u16 pci_exp_devctl_or; - u16 pci_exp_lnkctl_and; - u16 pci_exp_lnkctl_or; - u32 sec_unc_err_sever_and; - u32 sec_unc_err_sever_or; - u32 sec_unc_err_mask_and; - u32 sec_unc_err_mask_or; -}; - -struct hotplug_params { - struct hpp_type0 *t0; /* Type0: NULL if not available */ - struct hpp_type1 *t1; /* Type1: NULL if not available */ - struct hpp_type2 *t2; /* Type2: NULL if not available */ - struct hpp_type0 type0_data; - struct hpp_type1 type1_data; - struct hpp_type2 type2_data; -}; - -#ifdef CONFIG_ACPI -#include -#include -#include -extern acpi_status acpi_run_oshp(acpi_handle handle); -extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, - struct hotplug_params *hpp); -int acpi_root_bridge(acpi_handle handle); -#endif -#endif - diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index fa666d0cc489..f5d632e72323 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -37,11 +39,8 @@ #include #include #include +#include #include -#include -#include -#include "pci_hotplug.h" - #define MY_NAME "pci_hotplug" diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 30f021c55fe5..4fb12fcda563 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -31,11 +31,11 @@ #include #include +#include #include #include /* signal_pending() */ #include #include -#include "pci_hotplug.h" #define MY_NAME "pciehp" diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index 2b9e10e38613..50bcd3fe61da 100644 --- a/drivers/pci/hotplug/pcihp_skeleton.c +++ b/drivers/pci/hotplug/pcihp_skeleton.c @@ -33,8 +33,8 @@ #include #include #include +#include #include -#include "pci_hotplug.h" #define SLOT_NAME_SIZE 10 struct slot { diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index db69be85b458..6c5be3ff578c 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -14,7 +14,7 @@ */ #include #include -#include "pci_hotplug.h" +#include #include "rpadlpar.h" #define DLPAR_KOBJ_NAME "control" diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 7288a3eccfb3..141486df235b 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,6 @@ #include "../pci.h" /* for pci_add_new_bus */ /* and pci_do_scan_bus */ #include "rpaphp.h" -#include "pci_hotplug.h" int debug; static struct semaphore rpaphp_sem; diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index f31d83c2c633..b62ad31a9739 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,6 @@ #include #include "../pci.h" -#include "pci_hotplug.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 7e7d490622e1..ea2087c34149 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -31,12 +31,11 @@ #include #include +#include #include #include /* signal_pending(), struct timer_list */ #include -#include "pci_hotplug.h" - #if !defined(MODULE) #define MY_NAME "shpchp" #else diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h new file mode 100644 index 000000000000..a675a05c4091 --- /dev/null +++ b/include/linux/pci_hotplug.h @@ -0,0 +1,236 @@ +/* + * PCI HotPlug Core Functions + * + * Copyright (C) 1995,2001 Compaq Computer Corporation + * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ +#ifndef _PCI_HOTPLUG_H +#define _PCI_HOTPLUG_H + + +/* These values come from the PCI Hotplug Spec */ +enum pci_bus_speed { + PCI_SPEED_33MHz = 0x00, + PCI_SPEED_66MHz = 0x01, + PCI_SPEED_66MHz_PCIX = 0x02, + PCI_SPEED_100MHz_PCIX = 0x03, + PCI_SPEED_133MHz_PCIX = 0x04, + PCI_SPEED_66MHz_PCIX_ECC = 0x05, + PCI_SPEED_100MHz_PCIX_ECC = 0x06, + PCI_SPEED_133MHz_PCIX_ECC = 0x07, + PCI_SPEED_66MHz_PCIX_266 = 0x09, + PCI_SPEED_100MHz_PCIX_266 = 0x0a, + PCI_SPEED_133MHz_PCIX_266 = 0x0b, + PCI_SPEED_66MHz_PCIX_533 = 0x11, + PCI_SPEED_100MHz_PCIX_533 = 0x12, + PCI_SPEED_133MHz_PCIX_533 = 0x13, + PCI_SPEED_UNKNOWN = 0xff, +}; + +/* These values come from the PCI Express Spec */ +enum pcie_link_width { + PCIE_LNK_WIDTH_RESRV = 0x00, + PCIE_LNK_X1 = 0x01, + PCIE_LNK_X2 = 0x02, + PCIE_LNK_X4 = 0x04, + PCIE_LNK_X8 = 0x08, + PCIE_LNK_X12 = 0x0C, + PCIE_LNK_X16 = 0x10, + PCIE_LNK_X32 = 0x20, + PCIE_LNK_WIDTH_UNKNOWN = 0xFF, +}; + +enum pcie_link_speed { + PCIE_2PT5GB = 0x14, + PCIE_LNK_SPEED_UNKNOWN = 0xFF, +}; + +struct hotplug_slot; +struct hotplug_slot_attribute { + struct attribute attr; + ssize_t (*show)(struct hotplug_slot *, char *); + ssize_t (*store)(struct hotplug_slot *, const char *, size_t); +}; +#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr); + +/** + * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use + * @owner: The module owner of this structure + * @enable_slot: Called when the user wants to enable a specific pci slot + * @disable_slot: Called when the user wants to disable a specific pci slot + * @set_attention_status: Called to set the specific slot's attention LED to + * the specified value + * @hardware_test: Called to run a specified hardware test on the specified + * slot. + * @get_power_status: Called to get the current power status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_attention_status: Called to get the current attention status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_latch_status: Called to get the current latch status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_adapter_status: Called to get see if an adapter is present in the slot or not. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_address: Called to get pci address of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_max_bus_speed: Called to get the max bus speed for a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_cur_bus_speed: Called to get the current bus speed for a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * + * The table of function pointers that is passed to the hotplug pci core by a + * hotplug pci driver. These functions are called by the hotplug pci core when + * the user wants to do something to a specific slot (query it for information, + * set an LED, enable / disable power, etc.) + */ +struct hotplug_slot_ops { + struct module *owner; + int (*enable_slot) (struct hotplug_slot *slot); + int (*disable_slot) (struct hotplug_slot *slot); + int (*set_attention_status) (struct hotplug_slot *slot, u8 value); + int (*hardware_test) (struct hotplug_slot *slot, u32 value); + int (*get_power_status) (struct hotplug_slot *slot, u8 *value); + int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); + int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); + int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); + int (*get_address) (struct hotplug_slot *slot, u32 *value); + int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); + int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); +}; + +/** + * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot + * @power: if power is enabled or not (1/0) + * @attention_status: if the attention light is enabled or not (1/0) + * @latch_status: if the latch (if any) is open or closed (1/0) + * @adapter_present: if there is a pci board present in the slot or not (1/0) + * @address: (domain << 16 | bus << 8 | dev) + * + * Used to notify the hotplug pci core of the status of a specific slot. + */ +struct hotplug_slot_info { + u8 power_status; + u8 attention_status; + u8 latch_status; + u8 adapter_status; + u32 address; + enum pci_bus_speed max_bus_speed; + enum pci_bus_speed cur_bus_speed; +}; + +/** + * struct hotplug_slot - used to register a physical slot with the hotplug pci core + * @name: the name of the slot being registered. This string must + * be unique amoung slots registered on this system. + * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot + * @info: pointer to the &struct hotplug_slot_info for the initial values for + * this slot. + * @release: called during pci_hp_deregister to free memory allocated in a + * hotplug_slot structure. + * @private: used by the hotplug pci controller driver to store whatever it + * needs. + */ +struct hotplug_slot { + char *name; + struct hotplug_slot_ops *ops; + struct hotplug_slot_info *info; + void (*release) (struct hotplug_slot *slot); + void *private; + + /* Variables below this are for use only by the hotplug pci core. */ + struct list_head slot_list; + struct kobject kobj; +}; +#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) + +extern int pci_hp_register (struct hotplug_slot *slot); +extern int pci_hp_deregister (struct hotplug_slot *slot); +extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, + struct hotplug_slot_info *info); +extern struct subsystem pci_hotplug_slots_subsys; + +/* PCI Setting Record (Type 0) */ +struct hpp_type0 { + u32 revision; + u8 cache_line_size; + u8 latency_timer; + u8 enable_serr; + u8 enable_perr; +}; + +/* PCI-X Setting Record (Type 1) */ +struct hpp_type1 { + u32 revision; + u8 max_mem_read; + u8 avg_max_split; + u16 tot_max_split; +}; + +/* PCI Express Setting Record (Type 2) */ +struct hpp_type2 { + u32 revision; + u32 unc_err_mask_and; + u32 unc_err_mask_or; + u32 unc_err_sever_and; + u32 unc_err_sever_or; + u32 cor_err_mask_and; + u32 cor_err_mask_or; + u32 adv_err_cap_and; + u32 adv_err_cap_or; + u16 pci_exp_devctl_and; + u16 pci_exp_devctl_or; + u16 pci_exp_lnkctl_and; + u16 pci_exp_lnkctl_or; + u32 sec_unc_err_sever_and; + u32 sec_unc_err_sever_or; + u32 sec_unc_err_mask_and; + u32 sec_unc_err_mask_or; +}; + +struct hotplug_params { + struct hpp_type0 *t0; /* Type0: NULL if not available */ + struct hpp_type1 *t1; /* Type1: NULL if not available */ + struct hpp_type2 *t2; /* Type2: NULL if not available */ + struct hpp_type0 type0_data; + struct hpp_type1 type1_data; + struct hpp_type2 type2_data; +}; + +#ifdef CONFIG_ACPI +#include +#include +#include +extern acpi_status acpi_run_oshp(acpi_handle handle); +extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, + struct hotplug_params *hpp); +int acpi_root_bridge(acpi_handle handle); +#endif +#endif + -- cgit v1.2.3 From eb409460b1abec0e2a1f9c9d07019f4157a6d6bc Mon Sep 17 00:00:00 2001 From: Lijun Chen Date: Mon, 16 Oct 2006 21:59:42 -0700 Subject: [TIPC]: Added subscription cancellation capability This patch allows a TIPC application to cancel an existing topology service subscription by re-requesting the subscription with the TIPC_SUB_CANCEL filter bit set. (All other bits of the cancel request must match the original subscription request.) Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- include/linux/tipc.h | 1 + net/tipc/subscr.c | 99 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 85 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tipc.h b/include/linux/tipc.h index 243a15f54002..bea469455a0c 100644 --- a/include/linux/tipc.h +++ b/include/linux/tipc.h @@ -129,6 +129,7 @@ static inline unsigned int tipc_node(__u32 addr) #define TIPC_SUB_PORTS 0x01 /* filter for port availability */ #define TIPC_SUB_SERVICE 0x02 /* filter for service availability */ +#define TIPC_SUB_CANCEL 0x04 /* cancel a subscription */ #if 0 /* The following filter options are not currently implemented */ #define TIPC_SUB_NO_BIND_EVTS 0x04 /* filter out "publish" events */ diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index c51600ba5f4a..7a918f12a5df 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -155,7 +155,7 @@ void tipc_subscr_report_overlap(struct subscription *sub, sub->seq.upper, found_lower, found_upper); if (!tipc_subscr_overlap(sub, found_lower, found_upper)) return; - if (!must && (sub->filter != TIPC_SUB_PORTS)) + if (!must && !(sub->filter & TIPC_SUB_PORTS)) return; subscr_send_event(sub, found_lower, found_upper, event, port_ref, node); } @@ -176,6 +176,13 @@ static void subscr_timeout(struct subscription *sub) if (subscriber == NULL) return; + /* Validate timeout (in case subscription is being cancelled) */ + + if (sub->timeout == TIPC_WAIT_FOREVER) { + tipc_ref_unlock(subscriber_ref); + return; + } + /* Unlink subscription from name table */ tipc_nametbl_unsubscribe(sub); @@ -198,6 +205,20 @@ static void subscr_timeout(struct subscription *sub) atomic_dec(&topsrv.subscription_count); } +/** + * subscr_del - delete a subscription within a subscription list + * + * Called with subscriber locked. + */ + +static void subscr_del(struct subscription *sub) +{ + tipc_nametbl_unsubscribe(sub); + list_del(&sub->subscription_list); + kfree(sub); + atomic_dec(&topsrv.subscription_count); +} + /** * subscr_terminate - terminate communication with a subscriber * @@ -227,12 +248,9 @@ static void subscr_terminate(struct subscriber *subscriber) k_cancel_timer(&sub->timer); k_term_timer(&sub->timer); } - tipc_nametbl_unsubscribe(sub); - list_del(&sub->subscription_list); - dbg("Term: Removed sub %u,%u,%u from subscriber %x list\n", + dbg("Term: Removing sub %u,%u,%u from subscriber %x list\n", sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber); - kfree(sub); - atomic_dec(&topsrv.subscription_count); + subscr_del(sub); } /* Sever connection to subscriber */ @@ -252,6 +270,49 @@ static void subscr_terminate(struct subscriber *subscriber) kfree(subscriber); } +/** + * subscr_cancel - handle subscription cancellation request + * + * Called with subscriber locked. Routine must temporarily release this lock + * to enable the subscription timeout routine to finish without deadlocking; + * the lock is then reclaimed to allow caller to release it upon return. + * + * Note that fields of 's' use subscriber's endianness! + */ + +static void subscr_cancel(struct tipc_subscr *s, + struct subscriber *subscriber) +{ + struct subscription *sub; + struct subscription *sub_temp; + int found = 0; + + /* Find first matching subscription, exit if not found */ + + list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list, + subscription_list) { + if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) { + found = 1; + break; + } + } + if (!found) + return; + + /* Cancel subscription timer (if used), then delete subscription */ + + if (sub->timeout != TIPC_WAIT_FOREVER) { + sub->timeout = TIPC_WAIT_FOREVER; + spin_unlock_bh(subscriber->lock); + k_cancel_timer(&sub->timer); + k_term_timer(&sub->timer); + spin_lock_bh(subscriber->lock); + } + dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n", + sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber); + subscr_del(sub); +} + /** * subscr_subscribe - create subscription for subscriber * @@ -263,6 +324,21 @@ static void subscr_subscribe(struct tipc_subscr *s, { struct subscription *sub; + /* Determine/update subscriber's endianness */ + + if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE)) + subscriber->swap = 0; + else + subscriber->swap = 1; + + /* Detect & process a subscription cancellation request */ + + if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) { + s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap); + subscr_cancel(s, subscriber); + return; + } + /* Refuse subscription if global limit exceeded */ if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) { @@ -281,13 +357,6 @@ static void subscr_subscribe(struct tipc_subscr *s, return; } - /* Determine/update subscriber's endianness */ - - if ((s->filter == TIPC_SUB_PORTS) || (s->filter == TIPC_SUB_SERVICE)) - subscriber->swap = 0; - else - subscriber->swap = 1; - /* Initialize subscription object */ memset(sub, 0, sizeof(*sub)); @@ -296,8 +365,8 @@ static void subscr_subscribe(struct tipc_subscr *s, sub->seq.upper = htohl(s->seq.upper, subscriber->swap); sub->timeout = htohl(s->timeout, subscriber->swap); sub->filter = htohl(s->filter, subscriber->swap); - if ((((sub->filter != TIPC_SUB_PORTS) - && (sub->filter != TIPC_SUB_SERVICE))) + if ((!(sub->filter & TIPC_SUB_PORTS) + == !(sub->filter & TIPC_SUB_SERVICE)) || (sub->seq.lower > sub->seq.upper)) { warn("Subscription rejected, illegal request\n"); kfree(sub); -- cgit v1.2.3 From ae8064ac32d07f609114d73928cdef803be87134 Mon Sep 17 00:00:00 2001 From: John Heffner Date: Wed, 18 Oct 2006 20:36:48 -0700 Subject: [TCP]: Bound TSO defer time This patch limits the amount of time you will defer sending a TSO segment to less than two clock ticks, or the time between two acks, whichever is longer. On slow links, deferring causes significant bursts. See attached plots, which show RTT through a 1 Mbps link with a 100 ms RTT and ~100 ms queue for (a) non-TSO, (b) currnet TSO, and (c) patched TSO. This burstiness causes significant jitter, tends to overflow queues early (bad for short queues), and makes delay-based congestion control more difficult. Deferring by a couple clock ticks I believe will have a relatively small impact on performance. Signed-off-by: John Heffner Signed-off-by: David S. Miller --- include/linux/tcp.h | 2 ++ net/ipv4/tcp_output.c | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 0e058a2d1c6d..2d36f6db3706 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -342,6 +342,8 @@ struct tcp_sock { unsigned long last_synq_overflow; + __u32 tso_deferred; + /* Receiver side RTT estimation */ struct { __u32 rtt; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f22536e32cb1..ca406157724c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1096,10 +1096,14 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_ u32 send_win, cong_win, limit, in_flight; if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) - return 0; + goto send_now; if (icsk->icsk_ca_state != TCP_CA_Open) - return 0; + goto send_now; + + /* Defer for less than two clock ticks. */ + if (!tp->tso_deferred && ((jiffies<<1)>>1) - (tp->tso_deferred>>1) > 1) + goto send_now; in_flight = tcp_packets_in_flight(tp); @@ -1115,7 +1119,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_ /* If a full-sized TSO skb can be sent, do it. */ if (limit >= 65536) - return 0; + goto send_now; if (sysctl_tcp_tso_win_divisor) { u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache); @@ -1125,7 +1129,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_ */ chunk /= sysctl_tcp_tso_win_divisor; if (limit >= chunk) - return 0; + goto send_now; } else { /* Different approach, try not to defer past a single * ACK. Receiver should ACK every other full sized @@ -1133,11 +1137,17 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_ * then send now. */ if (limit > tcp_max_burst(tp) * tp->mss_cache) - return 0; + goto send_now; } /* Ok, it looks like it is advisable to defer. */ + tp->tso_deferred = 1 | (jiffies<<1); + return 1; + +send_now: + tp->tso_deferred = 0; + return 0; } /* Create a new MTU probe if we are ready. -- cgit v1.2.3 From 62752ee198dca9209b7dee504763e51b11e9e0ca Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Tue, 17 Oct 2006 10:31:38 +0200 Subject: [PATCH] Take i_mutex in splice_from_pipe() The splice_actor may be calling ->prepare_write() and ->commit_write(). We want i_mutex on the inode being written to before calling those so that we don't race i_size changes. The double locking behavior is done elsewhere in splice.c, and if we eventually want _nolock variants of generic_file_splice_write(), fs modules might have to replicate the nasty locking code. We introduce inode_double_lock() and inode_double_unlock() to consolidate the locking rules into one set of functions. Signed-off-by: Mark Fasheh Signed-off-by: Jens Axboe --- fs/inode.c | 36 ++++++++++++++++++++++++++++++++++++ fs/splice.c | 24 +++++++++++------------- include/linux/fs.h | 3 +++ 3 files changed, 50 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/fs/inode.c b/fs/inode.c index d9a21d122926..26cdb115ce67 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1306,6 +1306,42 @@ void wake_up_inode(struct inode *inode) wake_up_bit(&inode->i_state, __I_LOCK); } +/* + * We rarely want to lock two inodes that do not have a parent/child + * relationship (such as directory, child inode) simultaneously. The + * vast majority of file systems should be able to get along fine + * without this. Do not use these functions except as a last resort. + */ +void inode_double_lock(struct inode *inode1, struct inode *inode2) +{ + if (inode1 == NULL || inode2 == NULL || inode1 == inode2) { + if (inode1) + mutex_lock(&inode1->i_mutex); + else if (inode2) + mutex_lock(&inode2->i_mutex); + return; + } + + if (inode1 < inode2) { + mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD); + } else { + mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD); + } +} +EXPORT_SYMBOL(inode_double_lock); + +void inode_double_unlock(struct inode *inode1, struct inode *inode2) +{ + if (inode1) + mutex_unlock(&inode1->i_mutex); + + if (inode2 && inode2 != inode1) + mutex_unlock(&inode2->i_mutex); +} +EXPORT_SYMBOL(inode_double_unlock); + static __initdata unsigned long ihash_entries; static int __init set_ihash_entries(char *str) { diff --git a/fs/splice.c b/fs/splice.c index a567010b62ac..c1072b6940c3 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -713,6 +713,7 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, { int ret, do_wakeup, err; struct splice_desc sd; + struct inode *inode = out->f_mapping->host; ret = 0; do_wakeup = 0; @@ -722,8 +723,13 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, sd.file = out; sd.pos = *ppos; - if (pipe->inode) - mutex_lock(&pipe->inode->i_mutex); + /* + * The actor worker might be calling ->prepare_write and + * ->commit_write. Most of the time, these expect i_mutex to + * be held. Since this may result in an ABBA deadlock with + * pipe->inode, we have to order lock acquiry here. + */ + inode_double_lock(inode, pipe->inode); for (;;) { if (pipe->nrbufs) { @@ -797,8 +803,7 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, pipe_wait(pipe); } - if (pipe->inode) - mutex_unlock(&pipe->inode->i_mutex); + inode_double_unlock(inode, pipe->inode); if (do_wakeup) { smp_mb(); @@ -1400,13 +1405,7 @@ static int link_pipe(struct pipe_inode_info *ipipe, * grabbing by inode address. Otherwise two different processes * could deadlock (one doing tee from A -> B, the other from B -> A). */ - if (ipipe->inode < opipe->inode) { - mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_PARENT); - mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_CHILD); - } else { - mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_PARENT); - mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_CHILD); - } + inode_double_lock(ipipe->inode, opipe->inode); do { if (!opipe->readers) { @@ -1450,8 +1449,7 @@ static int link_pipe(struct pipe_inode_info *ipipe, i++; } while (len); - mutex_unlock(&ipipe->inode->i_mutex); - mutex_unlock(&opipe->inode->i_mutex); + inode_double_unlock(ipipe->inode, opipe->inode); /* * If we put data in the output pipe, wakeup any potential readers. diff --git a/include/linux/fs.h b/include/linux/fs.h index 661c7c572149..853a02f23936 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -623,6 +623,9 @@ enum inode_i_mutex_lock_class I_MUTEX_QUOTA }; +extern void inode_double_lock(struct inode *inode1, struct inode *inode2); +extern void inode_double_unlock(struct inode *inode1, struct inode *inode2); + /* * NOTE: in a 32bit arch with a preemptable kernel and * an UP compile the i_size_read/write must be atomic -- cgit v1.2.3 From 6da61809822c22634a3de2dcb3c60283b836a88a Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Tue, 17 Oct 2006 18:43:07 +0200 Subject: [PATCH] Introduce generic_file_splice_write_nolock() This allows file systems to manage their own i_mutex locking while still re-using the generic_file_splice_write() logic. OCFS2 in particular wants this so that it can order cluster locks within i_mutex. Signed-off-by: Mark Fasheh Signed-off-by: Jens Axboe --- fs/splice.c | 80 ++++++++++++++++++++++++++++++++++++++++++++---------- include/linux/fs.h | 2 ++ 2 files changed, 68 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/fs/splice.c b/fs/splice.c index c1072b6940c3..68e20e65c6e1 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -707,13 +707,12 @@ out_ret: * key here is the 'actor' worker passed in that actually moves the data * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. */ -ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags, - splice_actor *actor) +static ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, + struct file *out, loff_t *ppos, size_t len, + unsigned int flags, splice_actor *actor) { int ret, do_wakeup, err; struct splice_desc sd; - struct inode *inode = out->f_mapping->host; ret = 0; do_wakeup = 0; @@ -723,14 +722,6 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, sd.file = out; sd.pos = *ppos; - /* - * The actor worker might be calling ->prepare_write and - * ->commit_write. Most of the time, these expect i_mutex to - * be held. Since this may result in an ABBA deadlock with - * pipe->inode, we have to order lock acquiry here. - */ - inode_double_lock(inode, pipe->inode); - for (;;) { if (pipe->nrbufs) { struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; @@ -803,8 +794,6 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, pipe_wait(pipe); } - inode_double_unlock(inode, pipe->inode); - if (do_wakeup) { smp_mb(); if (waitqueue_active(&pipe->wait)) @@ -815,6 +804,69 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, return ret; } +ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags, + splice_actor *actor) +{ + ssize_t ret; + struct inode *inode = out->f_mapping->host; + + /* + * The actor worker might be calling ->prepare_write and + * ->commit_write. Most of the time, these expect i_mutex to + * be held. Since this may result in an ABBA deadlock with + * pipe->inode, we have to order lock acquiry here. + */ + inode_double_lock(inode, pipe->inode); + ret = __splice_from_pipe(pipe, out, ppos, len, flags, actor); + inode_double_unlock(inode, pipe->inode); + + return ret; +} + +/** + * generic_file_splice_write_nolock - generic_file_splice_write without mutexes + * @pipe: pipe info + * @out: file to write to + * @len: number of bytes to splice + * @flags: splice modifier flags + * + * Will either move or copy pages (determined by @flags options) from + * the given pipe inode to the given file. The caller is responsible + * for acquiring i_mutex on both inodes. + * + */ +ssize_t +generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +{ + struct address_space *mapping = out->f_mapping; + struct inode *inode = mapping->host; + ssize_t ret; + int err; + + ret = __splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); + if (ret > 0) { + *ppos += ret; + + /* + * If file or inode is SYNC and we actually wrote some data, + * sync it. + */ + if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) { + err = generic_osync_inode(inode, mapping, + OSYNC_METADATA|OSYNC_DATA); + + if (err) + ret = err; + } + } + + return ret; +} + +EXPORT_SYMBOL(generic_file_splice_write_nolock); + /** * generic_file_splice_write - splice data from a pipe to a file * @pipe: pipe info diff --git a/include/linux/fs.h b/include/linux/fs.h index 853a02f23936..d695ba2346a3 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1758,6 +1758,8 @@ extern ssize_t generic_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); extern ssize_t generic_file_splice_write(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); +extern ssize_t generic_file_splice_write_nolock(struct pipe_inode_info *, + struct file *, loff_t *, size_t, unsigned int); extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, loff_t *, size_t len, unsigned int flags); extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, -- cgit v1.2.3 From 01de85e057328ecbef36e108673b1e81059d54c1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 17 Oct 2006 19:50:36 +0200 Subject: [PATCH] Add lockless helpers for remove_suid() Right now users have to grab i_mutex before calling remove_suid(), in the unlikely event that a call to ->setattr() may be needed. Split up the function in two parts: - One to check if we need to remove suid - One to actually remove it The first we can call lockless. Signed-off-by: Jens Axboe --- include/linux/fs.h | 2 ++ mm/filemap.c | 30 ++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index d695ba2346a3..2fe6e3f900ba 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1712,6 +1712,8 @@ extern void __iget(struct inode * inode); extern void clear_inode(struct inode *); extern void destroy_inode(struct inode *); extern struct inode *new_inode(struct super_block *); +extern int __remove_suid(struct dentry *, int); +extern int should_remove_suid(struct dentry *); extern int remove_suid(struct dentry *); extern void remove_dquot_ref(struct super_block *, int, struct list_head *); diff --git a/mm/filemap.c b/mm/filemap.c index 3464b681f844..7c7addb9333c 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1884,11 +1884,10 @@ repeat: * if suid or (sgid and xgrp) * remove privs */ -int remove_suid(struct dentry *dentry) +int should_remove_suid(struct dentry *dentry) { mode_t mode = dentry->d_inode->i_mode; int kill = 0; - int result = 0; /* suid always must be killed */ if (unlikely(mode & S_ISUID)) @@ -1901,13 +1900,28 @@ int remove_suid(struct dentry *dentry) if (unlikely((mode & S_ISGID) && (mode & S_IXGRP))) kill |= ATTR_KILL_SGID; - if (unlikely(kill && !capable(CAP_FSETID))) { - struct iattr newattrs; + if (unlikely(kill && !capable(CAP_FSETID))) + return kill; - newattrs.ia_valid = ATTR_FORCE | kill; - result = notify_change(dentry, &newattrs); - } - return result; + return 0; +} + +int __remove_suid(struct dentry *dentry, int kill) +{ + struct iattr newattrs; + + newattrs.ia_valid = ATTR_FORCE | kill; + return notify_change(dentry, &newattrs); +} + +int remove_suid(struct dentry *dentry) +{ + int kill = should_remove_suid(dentry); + + if (unlikely(kill)) + return __remove_suid(dentry, kill); + + return 0; } EXPORT_SYMBOL(remove_suid); -- cgit v1.2.3 From 79e2de4bc53d7ca2a8eedee49e4a92479b4b530e Mon Sep 17 00:00:00 2001 From: Thomas Maier Date: Thu, 19 Oct 2006 23:28:15 -0700 Subject: [PATCH] export clear_queue_congested and set_queue_congested Export the clear_queue_congested() and set_queue_congested() functions located in ll_rw_blk.c The functions are renamed to blk_clear_queue_congested() and blk_set_queue_congested(). (needed in the pktcdvd driver's bio write congestion control) Signed-off-by: Thomas Maier Cc: Peter Osterlund Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- block/ll_rw_blk.c | 20 ++++++++++---------- include/linux/blkdev.h | 2 ++ 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index c847e17e5caa..132a858ce2c5 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -117,7 +117,7 @@ static void blk_queue_congestion_threshold(struct request_queue *q) * congested queues, and wake up anyone who was waiting for requests to be * put back. */ -static void clear_queue_congested(request_queue_t *q, int rw) +void blk_clear_queue_congested(request_queue_t *q, int rw) { enum bdi_state bit; wait_queue_head_t *wqh = &congestion_wqh[rw]; @@ -128,18 +128,20 @@ static void clear_queue_congested(request_queue_t *q, int rw) if (waitqueue_active(wqh)) wake_up(wqh); } +EXPORT_SYMBOL(blk_clear_queue_congested); /* * A queue has just entered congestion. Flag that in the queue's VM-visible * state flags and increment the global gounter of congested queues. */ -static void set_queue_congested(request_queue_t *q, int rw) +void blk_set_queue_congested(request_queue_t *q, int rw) { enum bdi_state bit; bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; set_bit(bit, &q->backing_dev_info.state); } +EXPORT_SYMBOL(blk_set_queue_congested); /** * blk_get_backing_dev_info - get the address of a queue's backing_dev_info @@ -159,7 +161,6 @@ struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev) ret = &q->backing_dev_info; return ret; } - EXPORT_SYMBOL(blk_get_backing_dev_info); void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data) @@ -167,7 +168,6 @@ void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data) q->activity_fn = fn; q->activity_data = data; } - EXPORT_SYMBOL(blk_queue_activity_fn); /** @@ -2067,7 +2067,7 @@ 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); + blk_clear_queue_congested(q, rw); if (rl->count[rw] + 1 <= q->nr_requests) { if (waitqueue_active(&rl->wait[rw])) @@ -2137,7 +2137,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, } } } - set_queue_congested(q, rw); + blk_set_queue_congested(q, rw); } /* @@ -3765,14 +3765,14 @@ queue_requests_store(struct request_queue *q, const char *page, size_t count) blk_queue_congestion_threshold(q); if (rl->count[READ] >= queue_congestion_on_threshold(q)) - set_queue_congested(q, READ); + blk_set_queue_congested(q, READ); else if (rl->count[READ] < queue_congestion_off_threshold(q)) - clear_queue_congested(q, READ); + blk_clear_queue_congested(q, READ); if (rl->count[WRITE] >= queue_congestion_on_threshold(q)) - set_queue_congested(q, WRITE); + blk_set_queue_congested(q, WRITE); else if (rl->count[WRITE] < queue_congestion_off_threshold(q)) - clear_queue_congested(q, WRITE); + blk_clear_queue_congested(q, WRITE); if (rl->count[READ] >= q->nr_requests) { blk_set_queue_full(q, READ); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index d370d2cfe138..9575e3a5ff2a 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -651,6 +651,8 @@ extern void blk_recount_segments(request_queue_t *, struct bio *); extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *); extern int sg_scsi_ioctl(struct file *, struct request_queue *, struct gendisk *, struct scsi_ioctl_command __user *); +extern void blk_clear_queue_congested(request_queue_t *q, int rw); +extern void blk_set_queue_congested(request_queue_t *q, int rw); extern void blk_start_queue(request_queue_t *q); extern void blk_stop_queue(request_queue_t *q); extern void blk_sync_queue(struct request_queue *q); -- cgit v1.2.3 From 3fcfab16c5b86eaa3db3a9a31adba550c5b67141 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 19 Oct 2006 23:28:16 -0700 Subject: [PATCH] separate bdi congestion functions from queue congestion functions Separate out the concept of "queue congestion" from "backing-dev congestion". Congestion is a backing-dev concept, not a queue concept. The blk_* congestion functions are retained, as wrappers around the core backing-dev congestion functions. This proper layering is needed so that NFS can cleanly use the congestion functions, and so that CONFIG_BLOCK=n actually links. Cc: "Thomas Maier" Cc: "Jens Axboe" Cc: Trond Myklebust Cc: David Howells Cc: Peter Osterlund Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/lib/usercopy.c | 3 +- block/ll_rw_blk.c | 71 --------------------------------------------- drivers/md/dm-crypt.c | 3 +- fs/fat/file.c | 3 +- fs/nfs/write.c | 4 ++- fs/reiserfs/journal.c | 3 +- fs/xfs/linux-2.6/kmem.c | 5 ++-- fs/xfs/linux-2.6/xfs_buf.c | 3 +- include/linux/backing-dev.h | 7 +++++ include/linux/blkdev.h | 24 ++++++++++++--- include/linux/writeback.h | 1 - mm/Makefile | 3 +- mm/backing-dev.c | 69 +++++++++++++++++++++++++++++++++++++++++++ mm/page-writeback.c | 17 +++-------- mm/page_alloc.c | 5 ++-- mm/shmem.c | 3 +- mm/vmscan.c | 6 ++-- 17 files changed, 126 insertions(+), 104 deletions(-) create mode 100644 mm/backing-dev.c (limited to 'include/linux') diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index 258df6b4d7d7..d22cfc9d656c 100644 --- a/arch/i386/lib/usercopy.c +++ b/arch/i386/lib/usercopy.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -741,7 +742,7 @@ survive: if (retval == -ENOMEM && is_init(current)) { up_read(¤t->mm->mmap_sem); - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); goto survive; } diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 132a858ce2c5..136066583c68 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -56,11 +56,6 @@ static kmem_cache_t *requestq_cachep; */ static kmem_cache_t *iocontext_cachep; -static wait_queue_head_t congestion_wqh[2] = { - __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]), - __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1]) - }; - /* * Controlling structure to kblockd */ @@ -112,37 +107,6 @@ static void blk_queue_congestion_threshold(struct request_queue *q) q->nr_congestion_off = nr; } -/* - * A queue has just exitted congestion. Note this in the global counter of - * congested queues, and wake up anyone who was waiting for requests to be - * put back. - */ -void blk_clear_queue_congested(request_queue_t *q, int rw) -{ - enum bdi_state bit; - wait_queue_head_t *wqh = &congestion_wqh[rw]; - - bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; - clear_bit(bit, &q->backing_dev_info.state); - smp_mb__after_clear_bit(); - if (waitqueue_active(wqh)) - wake_up(wqh); -} -EXPORT_SYMBOL(blk_clear_queue_congested); - -/* - * A queue has just entered congestion. Flag that in the queue's VM-visible - * state flags and increment the global gounter of congested queues. - */ -void blk_set_queue_congested(request_queue_t *q, int rw) -{ - enum bdi_state bit; - - bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; - set_bit(bit, &q->backing_dev_info.state); -} -EXPORT_SYMBOL(blk_set_queue_congested); - /** * blk_get_backing_dev_info - get the address of a queue's backing_dev_info * @bdev: device @@ -2755,41 +2719,6 @@ void blk_end_sync_rq(struct request *rq, int error) } EXPORT_SYMBOL(blk_end_sync_rq); -/** - * blk_congestion_wait - wait for a queue to become uncongested - * @rw: READ or WRITE - * @timeout: timeout in jiffies - * - * Waits for up to @timeout jiffies for a queue (any queue) to exit congestion. - * If no queues are congested then just wait for the next request to be - * returned. - */ -long blk_congestion_wait(int rw, long timeout) -{ - long ret; - DEFINE_WAIT(wait); - wait_queue_head_t *wqh = &congestion_wqh[rw]; - - prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); - ret = io_schedule_timeout(timeout); - finish_wait(wqh, &wait); - return ret; -} - -EXPORT_SYMBOL(blk_congestion_wait); - -/** - * blk_congestion_end - wake up sleepers on a congestion queue - * @rw: READ or WRITE - */ -void blk_congestion_end(int rw) -{ - wait_queue_head_t *wqh = &congestion_wqh[rw]; - - if (waitqueue_active(wqh)) - wake_up(wqh); -} - /* * Has to be called with the request spinlock acquired */ diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 655d816760e5..a625576fdeeb 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -602,7 +603,7 @@ static void process_write(struct crypt_io *io) /* out of memory -> run queues */ if (remaining) - blk_congestion_wait(bio_data_dir(clone), HZ/100); + congestion_wait(bio_data_dir(clone), HZ/100); } } diff --git a/fs/fat/file.c b/fs/fat/file.c index f4b8f8b3fbdd..8337451e7897 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -13,6 +13,7 @@ #include #include #include +#include #include int fat_generic_ioctl(struct inode *inode, struct file *filp, @@ -118,7 +119,7 @@ static int fat_file_release(struct inode *inode, struct file *filp) if ((filp->f_mode & FMODE_WRITE) && MSDOS_SB(inode->i_sb)->options.flush) { fat_flush_inodes(inode->i_sb, inode, NULL); - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); } return 0; } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index f6675d2c386c..ca92ac36fe9d 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -57,6 +57,8 @@ #include #include #include +#include + #include #include @@ -395,7 +397,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) out: clear_bit(BDI_write_congested, &bdi->state); wake_up_all(&nfs_write_congestion); - writeback_congestion_end(); + congestion_end(WRITE); return err; } diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index ad8cbc49883a..85ce23268302 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -53,6 +53,7 @@ #include #include #include +#include /* gets a struct reiserfs_journal_list * from a list head */ #define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \ @@ -970,7 +971,7 @@ int reiserfs_async_progress_wait(struct super_block *s) DEFINE_WAIT(wait); struct reiserfs_journal *j = SB_JOURNAL(s); if (atomic_read(&j->j_async_throttle)) - blk_congestion_wait(WRITE, HZ / 10); + congestion_wait(WRITE, HZ / 10); return 0; } diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c index d59737589815..004baf600611 100644 --- a/fs/xfs/linux-2.6/kmem.c +++ b/fs/xfs/linux-2.6/kmem.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "time.h" #include "kmem.h" @@ -53,7 +54,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags) printk(KERN_ERR "XFS: possible memory allocation " "deadlock in %s (mode:0x%x)\n", __FUNCTION__, lflags); - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); } while (1); } @@ -131,7 +132,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags) printk(KERN_ERR "XFS: possible memory allocation " "deadlock in %s (mode:0x%x)\n", __FUNCTION__, lflags); - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); } while (1); } diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 9bbadafdcb00..db5f5a3608ca 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "xfs_linux.h" STATIC kmem_zone_t *xfs_buf_zone; @@ -395,7 +396,7 @@ _xfs_buf_lookup_pages( XFS_STATS_INC(xb_page_retries); xfsbufd_wakeup(0, gfp_mask); - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); goto retry; } diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index f7a1390d67f5..7011d6255593 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -10,6 +10,8 @@ #include +struct page; + /* * Bits in backing_dev_info.state */ @@ -88,6 +90,11 @@ static inline int bdi_rw_congested(struct backing_dev_info *bdi) (1 << BDI_write_congested)); } +void clear_bdi_congested(struct backing_dev_info *bdi, int rw); +void set_bdi_congested(struct backing_dev_info *bdi, int rw); +long congestion_wait(int rw, long timeout); +void congestion_end(int rw); + #define bdi_cap_writeback_dirty(bdi) \ (!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK)) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 9575e3a5ff2a..7bfcde2d5578 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -651,8 +651,26 @@ extern void blk_recount_segments(request_queue_t *, struct bio *); extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *); extern int sg_scsi_ioctl(struct file *, struct request_queue *, struct gendisk *, struct scsi_ioctl_command __user *); -extern void blk_clear_queue_congested(request_queue_t *q, int rw); -extern void blk_set_queue_congested(request_queue_t *q, int rw); + +/* + * A queue has just exitted congestion. Note this in the global counter of + * congested queues, and wake up anyone who was waiting for requests to be + * put back. + */ +static inline void blk_clear_queue_congested(request_queue_t *q, int rw) +{ + clear_bdi_congested(&q->backing_dev_info, rw); +} + +/* + * A queue has just entered congestion. Flag that in the queue's VM-visible + * state flags and increment the global gounter of congested queues. + */ +static inline void blk_set_queue_congested(request_queue_t *q, int rw) +{ + set_bdi_congested(&q->backing_dev_info, rw); +} + extern void blk_start_queue(request_queue_t *q); extern void blk_stop_queue(request_queue_t *q); extern void blk_sync_queue(struct request_queue *q); @@ -767,10 +785,8 @@ extern int blk_queue_init_tags(request_queue_t *, int, struct blk_queue_tag *); extern void blk_queue_free_tags(request_queue_t *); extern int blk_queue_resize_tags(request_queue_t *, int); extern void blk_queue_invalidate_tags(request_queue_t *); -extern long blk_congestion_wait(int rw, long timeout); extern struct blk_queue_tag *blk_init_tags(int); extern void blk_free_tags(struct blk_queue_tag *); -extern void blk_congestion_end(int rw); static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, int tag) diff --git a/include/linux/writeback.h b/include/linux/writeback.h index a341c8032866..fc35e6bdfb93 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -85,7 +85,6 @@ int wakeup_pdflush(long nr_pages); void laptop_io_completion(void); void laptop_sync_completion(void); void throttle_vm_writeout(void); -void writeback_congestion_end(void); /* These are exported to sysctl. */ extern int dirty_background_ratio; diff --git a/mm/Makefile b/mm/Makefile index 12b3a4eee88d..f3c077eb0b8e 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -10,7 +10,8 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ page_alloc.o page-writeback.o pdflush.o \ readahead.o swap.o truncate.o vmscan.o \ - prio_tree.o util.o mmzone.o vmstat.o $(mmu-y) + prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \ + $(mmu-y) ifeq ($(CONFIG_MMU)$(CONFIG_BLOCK),yy) obj-y += bounce.o diff --git a/mm/backing-dev.c b/mm/backing-dev.c new file mode 100644 index 000000000000..f50a2811f9dc --- /dev/null +++ b/mm/backing-dev.c @@ -0,0 +1,69 @@ + +#include +#include +#include +#include +#include + +static wait_queue_head_t congestion_wqh[2] = { + __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]), + __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1]) + }; + + +void clear_bdi_congested(struct backing_dev_info *bdi, int rw) +{ + enum bdi_state bit; + wait_queue_head_t *wqh = &congestion_wqh[rw]; + + bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; + clear_bit(bit, &bdi->state); + smp_mb__after_clear_bit(); + if (waitqueue_active(wqh)) + wake_up(wqh); +} +EXPORT_SYMBOL(clear_bdi_congested); + +void set_bdi_congested(struct backing_dev_info *bdi, int rw) +{ + enum bdi_state bit; + + bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; + set_bit(bit, &bdi->state); +} +EXPORT_SYMBOL(set_bdi_congested); + +/** + * congestion_wait - wait for a backing_dev to become uncongested + * @rw: READ or WRITE + * @timeout: timeout in jiffies + * + * Waits for up to @timeout jiffies for a backing_dev (any backing_dev) to exit + * write congestion. If no backing_devs are congested then just wait for the + * next write to be completed. + */ +long congestion_wait(int rw, long timeout) +{ + long ret; + DEFINE_WAIT(wait); + wait_queue_head_t *wqh = &congestion_wqh[rw]; + + prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); + ret = io_schedule_timeout(timeout); + finish_wait(wqh, &wait); + return ret; +} +EXPORT_SYMBOL(congestion_wait); + +/** + * congestion_end - wake up sleepers on a congested backing_dev_info + * @rw: READ or WRITE + */ +void congestion_end(int rw) +{ + wait_queue_head_t *wqh = &congestion_wqh[rw]; + + if (waitqueue_active(wqh)) + wake_up(wqh); +} +EXPORT_SYMBOL(congestion_end); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index a0f339057449..8d9b19f239c3 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -222,7 +222,7 @@ static void balance_dirty_pages(struct address_space *mapping) if (pages_written >= write_chunk) break; /* We've done our duty */ } - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); } if (nr_reclaimable + global_page_state(NR_WRITEBACK) @@ -314,7 +314,7 @@ void throttle_vm_writeout(void) if (global_page_state(NR_UNSTABLE_NFS) + global_page_state(NR_WRITEBACK) <= dirty_thresh) break; - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); } } @@ -351,7 +351,7 @@ static void background_writeout(unsigned long _min_pages) min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) { /* Wrote less than expected */ - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); if (!wbc.encountered_congestion) break; } @@ -422,7 +422,7 @@ static void wb_kupdate(unsigned long arg) writeback_inodes(&wbc); if (wbc.nr_to_write > 0) { if (wbc.encountered_congestion) - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); else break; /* All the old data is written */ } @@ -955,15 +955,6 @@ int test_set_page_writeback(struct page *page) } EXPORT_SYMBOL(test_set_page_writeback); -/* - * Wakes up tasks that are being throttled due to writeback congestion - */ -void writeback_congestion_end(void) -{ - blk_congestion_end(WRITE); -} -EXPORT_SYMBOL(writeback_congestion_end); - /* * Return true if any of the pages in the mapping are marged with the * passed tag. diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 40db96a655d0..afee38f04d84 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -1050,7 +1051,7 @@ nofail_alloc: if (page) goto got_pg; if (gfp_mask & __GFP_NOFAIL) { - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); goto nofail_alloc; } } @@ -1113,7 +1114,7 @@ rebalance: do_retry = 1; } if (do_retry) { - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); goto rebalance; } diff --git a/mm/shmem.c b/mm/shmem.c index b378f66cf2f9..4959535fc14c 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -1131,7 +1132,7 @@ repeat: page_cache_release(swappage); if (error == -ENOMEM) { /* let kswapd refresh zone for GFP_ATOMICs */ - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); } goto repeat; } diff --git a/mm/vmscan.c b/mm/vmscan.c index af73c14f9d88..f05527bf792b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1059,7 +1059,7 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask) /* Take a nap, wait for some writeback to complete */ if (sc.nr_scanned && priority < DEF_PRIORITY - 2) - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); } /* top priority shrink_caches still had more to do? don't OOM, then */ if (!sc.all_unreclaimable) @@ -1214,7 +1214,7 @@ scan: * another pass across the zones. */ if (total_scanned && priority < DEF_PRIORITY - 2) - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); /* * We do this so kswapd doesn't build up large priorities for @@ -1458,7 +1458,7 @@ unsigned long shrink_all_memory(unsigned long nr_pages) goto out; if (sc.nr_scanned && prio < DEF_PRIORITY - 2) - blk_congestion_wait(WRITE, HZ / 10); + congestion_wait(WRITE, HZ / 10); } lru_pages = 0; -- cgit v1.2.3 From 34e856e6a522a8fc0feba7497f5b05aeaa13d473 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 19 Oct 2006 23:28:17 -0700 Subject: [PATCH] Make userspace proof contains the constants for personality(2) but also some defintions that are useless or even harmful in userspace such as the personality() macro. Signed-off-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/personality.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/linux') diff --git a/include/linux/personality.h b/include/linux/personality.h index 80d780e5a8f5..bf4cf2080e5c 100644 --- a/include/linux/personality.h +++ b/include/linux/personality.h @@ -1,6 +1,8 @@ #ifndef _LINUX_PERSONALITY_H #define _LINUX_PERSONALITY_H +#ifdef __KERNEL__ + /* * Handling of different ABIs (personalities). */ @@ -12,6 +14,8 @@ extern int register_exec_domain(struct exec_domain *); extern int unregister_exec_domain(struct exec_domain *); extern int __set_personality(unsigned long); +#endif /* __KERNEL__ */ + /* * Flags for bug emulation. * @@ -71,6 +75,7 @@ enum { PER_MASK = 0x00ff, }; +#ifdef __KERNEL__ /* * Description of an execution domain. @@ -111,4 +116,6 @@ struct exec_domain { #define set_personality(pers) \ ((current->personality == pers) ? 0 : __set_personality(pers)) +#endif /* __KERNEL__ */ + #endif /* _LINUX_PERSONALITY_H */ -- cgit v1.2.3 From 145fc655a1ceabda76cf2ad74f7cf96863c65b65 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 19 Oct 2006 23:28:28 -0700 Subject: [PATCH] genirq: clean up irq-flow-type naming, fix Re-add the set_irq_chip_and_handler() prototype, it's still widely used. Signed-off-by: Ingo Molnar Cc: Olaf Hering Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irq.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 775f5a7da493..52fc4052a0ae 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -321,6 +321,9 @@ extern int can_request_irq(unsigned int irq, unsigned long irqflags); extern struct irq_chip no_irq_chip; extern struct irq_chip dummy_irq_chip; +extern void +set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, + irq_flow_handler_t handle); extern void set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, irq_flow_handler_t handle, const char *name); -- cgit v1.2.3 From 8ac773b4f73afa6fd66695131103944b975d5d5c Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 19 Oct 2006 23:28:32 -0700 Subject: [PATCH] OOM killer meets userspace headers Despite mm.h is not being exported header, it does contain one thing which is part of userspace ABI -- value disabling OOM killer for given process. So, a) create and export include/linux/oom.h b) move OOM_DISABLE define there. c) turn bounding values of /proc/$PID/oom_adj into defines and export them too. Note: mass __KERNEL__ removal will be done later. Signed-off-by: Alexey Dobriyan Cc: Nick Piggin Cc: David Woodhouse Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 4 +++- include/linux/Kbuild | 1 + include/linux/mm.h | 3 --- include/linux/oom.h | 10 ++++++++++ mm/oom_kill.c | 1 + 5 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 include/linux/oom.h (limited to 'include/linux') diff --git a/fs/proc/base.c b/fs/proc/base.c index 26a8f8416b79..8df27401d292 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -72,6 +72,7 @@ #include #include #include +#include #include "internal.h" /* NOTE: @@ -689,7 +690,8 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, if (copy_from_user(buffer, buf, count)) return -EFAULT; oom_adjust = simple_strtol(buffer, &end, 0); - if ((oom_adjust < -16 || oom_adjust > 15) && oom_adjust != OOM_DISABLE) + if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) && + oom_adjust != OOM_DISABLE) return -EINVAL; if (*end == '\n') end++; diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 5114ff18101d..a1155a2beb32 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -120,6 +120,7 @@ header-y += netrom.h header-y += nfs2.h header-y += nfs4_mount.h header-y += nfs_mount.h +header-y += oom.h header-y += param.h header-y += pci_ids.h header-y += pci_regs.h diff --git a/include/linux/mm.h b/include/linux/mm.h index 5a6068ff5556..d538de901965 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1115,9 +1115,6 @@ int in_gate_area_no_task(unsigned long addr); #define in_gate_area(task, addr) ({(void)task; in_gate_area_no_task(addr);}) #endif /* __HAVE_ARCH_GATE_AREA */ -/* /proc//oom_adj set to -17 protects from the oom-killer */ -#define OOM_DISABLE -17 - int drop_caches_sysctl_handler(struct ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask, diff --git a/include/linux/oom.h b/include/linux/oom.h new file mode 100644 index 000000000000..ad76463629a0 --- /dev/null +++ b/include/linux/oom.h @@ -0,0 +1,10 @@ +#ifndef __INCLUDE_LINUX_OOM_H +#define __INCLUDE_LINUX_OOM_H + +/* /proc//oom_adj set to -17 protects from the oom-killer */ +#define OOM_DISABLE (-17) +/* inclusive */ +#define OOM_ADJUST_MIN (-16) +#define OOM_ADJUST_MAX 15 + +#endif diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 20f41b082e16..2e3ce3a928b9 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -15,6 +15,7 @@ * kernel subsystems and hints as to where to find out what things do. */ +#include #include #include #include -- cgit v1.2.3 From cd9ae2b6a75bb1fa0d370929c2d7a7da1ed719d9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 19 Oct 2006 23:28:40 -0700 Subject: [PATCH] NFS: Deal with failure of invalidate_inode_pages2() If invalidate_inode_pages2() fails, then it should in principle just be because the current process was signalled. In that case, we just want to ensure that the inode's page cache remains marked as invalid. Also add a helper to allow the O_DIRECT code to simply mark the page cache as invalid once it is finished writing, instead of calling invalidate_inode_pages2() itself. Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/dir.c | 6 ++++-- fs/nfs/direct.c | 13 ++----------- fs/nfs/inode.c | 28 +++++++++++++++++++++++----- include/linux/nfs_fs.h | 1 + 4 files changed, 30 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 481f8892a919..58d44057813e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -203,8 +203,10 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) * Note: assumes we have exclusive access to this mapping either * through inode->i_mutex or some other mechanism. */ - if (page->index == 0) - invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1); + if (page->index == 0 && invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1) < 0) { + /* Should never happen */ + nfs_zap_mapping(inode, inode->i_mapping); + } unlock_page(page); return 0; error: diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 1e873fcab947..bdfabf854a51 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -497,6 +497,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode if (dreq->commit_data != NULL) nfs_commit_free(dreq->commit_data); nfs_direct_free_writedata(dreq); + nfs_zap_mapping(inode, inode->i_mapping); nfs_direct_complete(dreq); } } @@ -517,6 +518,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode { nfs_end_data_update(inode); nfs_direct_free_writedata(dreq); + nfs_zap_mapping(inode, inode->i_mapping); nfs_direct_complete(dreq); } #endif @@ -830,17 +832,6 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos); - /* - * XXX: nfs_end_data_update() already ensures this file's - * cached data is subsequently invalidated. Do we really - * need to call invalidate_inode_pages2() again here? - * - * For aio writes, this invalidation will almost certainly - * occur before the writes complete. Kind of racey. - */ - if (mapping->nrpages) - invalidate_inode_pages2(mapping); - if (retval > 0) iocb->ki_pos = pos + retval; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bc9376ca86cd..9979ad1cf8eb 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -131,6 +131,15 @@ void nfs_zap_caches(struct inode *inode) spin_unlock(&inode->i_lock); } +void nfs_zap_mapping(struct inode *inode, struct address_space *mapping) +{ + if (mapping->nrpages != 0) { + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; + spin_unlock(&inode->i_lock); + } +} + static void nfs_zap_acl_cache(struct inode *inode) { void (*clear_acl_cache)(struct inode *); @@ -671,13 +680,20 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode)) ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); + if (ret < 0) + goto out; if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { - nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); - if (S_ISREG(inode->i_mode)) - nfs_sync_mapping(mapping); - invalidate_inode_pages2(mapping); - + if (mapping->nrpages != 0) { + if (S_ISREG(inode->i_mode)) { + ret = nfs_sync_mapping(mapping); + if (ret < 0) + goto out; + } + ret = invalidate_inode_pages2(mapping); + if (ret < 0) + goto out; + } spin_lock(&inode->i_lock); nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; if (S_ISDIR(inode->i_mode)) { @@ -687,10 +703,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) } spin_unlock(&inode->i_lock); + nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); } +out: return ret; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 76ff54846ada..6b2de1be5815 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -290,6 +290,7 @@ static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long * linux/fs/nfs/inode.c */ extern int nfs_sync_mapping(struct address_space *mapping); +extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping); extern void nfs_zap_caches(struct inode *); extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *); -- cgit v1.2.3 From 7111c66e4e70588c9602035a4996c9cdc2087d2d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:45 -0700 Subject: [PATCH] fix svc_procfunc declaration svc_procfunc instances return __be32, not int Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svc4proc.c | 40 ++++++++++++++++++++-------------------- fs/lockd/svcproc.c | 40 ++++++++++++++++++++-------------------- fs/nfs/callback_xdr.c | 4 ++-- fs/nfsd/nfs2acl.c | 10 +++++----- fs/nfsd/nfs3acl.c | 6 +++--- fs/nfsd/nfs3proc.c | 44 ++++++++++++++++++++++---------------------- fs/nfsd/nfs4proc.c | 4 ++-- fs/nfsd/nfsproc.c | 32 ++++++++++++++++---------------- include/linux/sunrpc/svc.h | 2 +- 9 files changed, 91 insertions(+), 91 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 399ad11b97be..4e719860b4bf 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -68,7 +68,7 @@ no_locks: /* * NULL: Test for presence of service */ -static int +static __be32 nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { dprintk("lockd: NULL called\n"); @@ -78,7 +78,7 @@ nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * TEST: Check for conflicting lock */ -static int +static __be32 nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -107,7 +107,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, return rpc_success; } -static int +static __be32 nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -150,7 +150,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, return rpc_success; } -static int +static __be32 nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -183,7 +183,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, /* * UNLOCK: release a lock */ -static int +static __be32 nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -217,7 +217,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, * GRANTED: A server calls us to tell that a process' lock request * was granted */ -static int +static __be32 nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -253,12 +253,12 @@ static const struct rpc_call_ops nlm4svc_callback_ops = { * because we send the callback before the reply proper. I hope this * doesn't break any clients. */ -static int nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp, - int (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *)) +static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp, + __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *)) { struct nlm_host *host; struct nlm_rqst *call; - int stat; + __be32 stat; host = nlmsvc_lookup_host(rqstp, argp->lock.caller, @@ -282,35 +282,35 @@ static int nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *a return rpc_success; } -static int nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: TEST_MSG called\n"); return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, argp, nlm4svc_proc_test); } -static int nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: LOCK_MSG called\n"); return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlm4svc_proc_lock); } -static int nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: CANCEL_MSG called\n"); return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlm4svc_proc_cancel); } -static int nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: UNLOCK_MSG called\n"); return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlm4svc_proc_unlock); } -static int nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: GRANTED_MSG called\n"); @@ -320,7 +320,7 @@ static int nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *arg /* * SHARE: create a DOS share or alter existing share. */ -static int +static __be32 nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -353,7 +353,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, /* * UNSHARE: Release a DOS share. */ -static int +static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -386,7 +386,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, /* * NM_LOCK: Create an unmonitored lock */ -static int +static __be32 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -399,7 +399,7 @@ nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp, /* * FREE_ALL: Release all locks and shares held by client */ -static int +static __be32 nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { @@ -417,7 +417,7 @@ nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, /* * SM_NOTIFY: private callback from statd (not part of official NLM proto) */ -static int +static __be32 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, void *resp) { @@ -446,7 +446,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, /* * client sent a GRANTED_RES, let's remove the associated block */ -static int +static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, void *resp) { diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 6a931f4ab75c..db8d85c32d29 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -96,7 +96,7 @@ no_locks: /* * NULL: Test for presence of service */ -static int +static __be32 nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { dprintk("lockd: NULL called\n"); @@ -106,7 +106,7 @@ nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * TEST: Check for conflicting lock */ -static int +static __be32 nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -136,7 +136,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, return rpc_success; } -static int +static __be32 nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -179,7 +179,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, return rpc_success; } -static int +static __be32 nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -212,7 +212,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, /* * UNLOCK: release a lock */ -static int +static __be32 nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -246,7 +246,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, * GRANTED: A server calls us to tell that a process' lock request * was granted */ -static int +static __be32 nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -282,12 +282,12 @@ static const struct rpc_call_ops nlmsvc_callback_ops = { * because we send the callback before the reply proper. I hope this * doesn't break any clients. */ -static int nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp, - int (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *)) +static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp, + __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *)) { struct nlm_host *host; struct nlm_rqst *call; - int stat; + __be32 stat; host = nlmsvc_lookup_host(rqstp, argp->lock.caller, @@ -311,28 +311,28 @@ static int nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *ar return rpc_success; } -static int nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: TEST_MSG called\n"); return nlmsvc_callback(rqstp, NLMPROC_TEST_RES, argp, nlmsvc_proc_test); } -static int nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: LOCK_MSG called\n"); return nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlmsvc_proc_lock); } -static int nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: CANCEL_MSG called\n"); return nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlmsvc_proc_cancel); } -static int +static __be32 nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { @@ -340,7 +340,7 @@ nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, return nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlmsvc_proc_unlock); } -static int +static __be32 nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { @@ -351,7 +351,7 @@ nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, /* * SHARE: create a DOS share or alter existing share. */ -static int +static __be32 nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -384,7 +384,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, /* * UNSHARE: Release a DOS share. */ -static int +static __be32 nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -417,7 +417,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, /* * NM_LOCK: Create an unmonitored lock */ -static int +static __be32 nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -430,7 +430,7 @@ nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp, /* * FREE_ALL: Release all locks and shares held by client */ -static int +static __be32 nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { @@ -448,7 +448,7 @@ nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, /* * SM_NOTIFY: private callback from statd (not part of official NLM proto) */ -static int +static __be32 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, void *resp) { @@ -477,7 +477,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, /* * client sent a GRANTED_RES, let's remove the associated block */ -static int +static __be32 nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, void *resp) { diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 29f932192054..5998d0c71757 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -36,7 +36,7 @@ struct callback_op { static struct callback_op callback_ops[]; -static int nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp) +static __be32 nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp) { return htonl(NFS4_OK); } @@ -399,7 +399,7 @@ static unsigned process_op(struct svc_rqst *rqstp, /* * Decode, process and encode a COMPOUND */ -static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp) +static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp) { struct cb_compound_hdr_arg hdr_arg; struct cb_compound_hdr_res hdr_res; diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 9187755661df..8d48616882c1 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -21,7 +21,7 @@ /* * NULL call. */ -static int +static __be32 nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { return nfs_ok; @@ -30,7 +30,7 @@ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * Get the Access and/or Default ACL of a file. */ -static int nfsacld_proc_getacl(struct svc_rqst * rqstp, +static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) { svc_fh *fh; @@ -97,7 +97,7 @@ fail: /* * Set the Access and/or Default ACL of a file. */ -static int nfsacld_proc_setacl(struct svc_rqst * rqstp, +static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_setaclargs *argp, struct nfsd_attrstat *resp) { @@ -128,7 +128,7 @@ static int nfsacld_proc_setacl(struct svc_rqst * rqstp, /* * Check file attributes */ -static int nfsacld_proc_getattr(struct svc_rqst * rqstp, +static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) { dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); @@ -140,7 +140,7 @@ static int nfsacld_proc_getattr(struct svc_rqst * rqstp, /* * Check file access */ -static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, +static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, struct nfsd3_accessres *resp) { int nfserr; diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index d4bdc00c1169..ed6e2c27b5e8 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -19,7 +19,7 @@ /* * NULL call. */ -static int +static __be32 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { return nfs_ok; @@ -28,7 +28,7 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * Get the Access and/or Default ACL of a file. */ -static int nfsd3_proc_getacl(struct svc_rqst * rqstp, +static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) { svc_fh *fh; @@ -93,7 +93,7 @@ fail: /* * Set the Access and/or Default ACL of a file. */ -static int nfsd3_proc_setacl(struct svc_rqst * rqstp, +static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_setaclargs *argp, struct nfsd3_attrstat *resp) { diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index a5ebc7dbb384..a12663fdfe16 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -43,7 +43,7 @@ static int nfs3_ftypes[] = { /* * NULL call. */ -static int +static __be32 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { return nfs_ok; @@ -52,7 +52,7 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * Get a file's attributes */ -static int +static __be32 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, struct nfsd3_attrstat *resp) { @@ -76,7 +76,7 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, /* * Set a file's attributes */ -static int +static __be32 nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, struct nfsd3_attrstat *resp) { @@ -94,7 +94,7 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, /* * Look up a path name component */ -static int +static __be32 nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, struct nfsd3_diropres *resp) { @@ -118,7 +118,7 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, /* * Check file access */ -static int +static __be32 nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, struct nfsd3_accessres *resp) { @@ -137,7 +137,7 @@ nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, /* * Read a symlink. */ -static int +static __be32 nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp, struct nfsd3_readlinkres *resp) { @@ -155,7 +155,7 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp, /* * Read a portion of a file. */ -static int +static __be32 nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, struct nfsd3_readres *resp) { @@ -195,7 +195,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, /* * Write data to a file */ -static int +static __be32 nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, struct nfsd3_writeres *resp) { @@ -223,7 +223,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, * At least in theory; we'll see how it fares in practice when the * first reports about SunOS compatibility problems start to pour in... */ -static int +static __be32 nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, struct nfsd3_diropres *resp) { @@ -265,7 +265,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, /* * Make directory. This operation is not idempotent. */ -static int +static __be32 nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, struct nfsd3_diropres *resp) { @@ -285,7 +285,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, RETURN_STATUS(nfserr); } -static int +static __be32 nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, struct nfsd3_diropres *resp) { @@ -307,7 +307,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, /* * Make socket/fifo/device. */ -static int +static __be32 nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, struct nfsd3_diropres *resp) { @@ -343,7 +343,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, /* * Remove file/fifo/socket etc. */ -static int +static __be32 nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, struct nfsd3_attrstat *resp) { @@ -363,7 +363,7 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, /* * Remove a directory */ -static int +static __be32 nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, struct nfsd3_attrstat *resp) { @@ -379,7 +379,7 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, RETURN_STATUS(nfserr); } -static int +static __be32 nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp, struct nfsd3_renameres *resp) { @@ -401,7 +401,7 @@ nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp, RETURN_STATUS(nfserr); } -static int +static __be32 nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp, struct nfsd3_linkres *resp) { @@ -424,7 +424,7 @@ nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp, /* * Read a portion of a directory. */ -static int +static __be32 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, struct nfsd3_readdirres *resp) { @@ -459,7 +459,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, * Read a portion of a directory, including file handles and attrs. * For now, we choose to ignore the dircount parameter. */ -static int +static __be32 nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, struct nfsd3_readdirres *resp) { @@ -517,7 +517,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, /* * Get file system stats */ -static int +static __be32 nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd3_fsstatres *resp) { @@ -534,7 +534,7 @@ nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, /* * Get file system info */ -static int +static __be32 nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd3_fsinfores *resp) { @@ -576,7 +576,7 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, /* * Get pathconf info for the specified file */ -static int +static __be32 nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd3_pathconfres *resp) { @@ -619,7 +619,7 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, /* * Commit a file (range) to stable storage. */ -static int +static __be32 nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, struct nfsd3_commitres *resp) { diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index d1fac6872c44..795ad6c5cb2c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -715,7 +715,7 @@ out_kfree: /* * NULL call. */ -static int +static __be32 nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { return nfs_ok; @@ -731,7 +731,7 @@ static inline void nfsd4_increment_op_stats(u32 opnum) /* * COMPOUND call. */ -static int +static __be32 nfsd4_proc_compound(struct svc_rqst *rqstp, struct nfsd4_compoundargs *args, struct nfsd4_compoundres *resp) diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 9ee1dab5d44a..09030afd7249 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -30,7 +30,7 @@ typedef struct svc_buf svc_buf; #define NFSDDBG_FACILITY NFSDDBG_PROC -static int +static __be32 nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { return nfs_ok; @@ -56,7 +56,7 @@ nfsd_return_dirop(int err, struct nfsd_diropres *resp) * Get a file's attributes * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) { @@ -72,7 +72,7 @@ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, * Set a file's attributes * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, struct nfsd_attrstat *resp) { @@ -92,7 +92,7 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, * doesn't exist yet. * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, struct nfsd_diropres *resp) { @@ -112,7 +112,7 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, /* * Read a symlink. */ -static int +static __be32 nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp, struct nfsd_readlinkres *resp) { @@ -132,7 +132,7 @@ nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp, * Read a portion of a file. * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, struct nfsd_readres *resp) { @@ -172,7 +172,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, * Write data to a file * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp, struct nfsd_attrstat *resp) { @@ -197,7 +197,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp, * and the actual create() call in compliance with VFS protocols. * N.B. After this call _both_ argp->fh and resp->fh need an fh_put */ -static int +static __be32 nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, struct nfsd_diropres *resp) { @@ -348,7 +348,7 @@ done: return nfsd_return_dirop(nfserr, resp); } -static int +static __be32 nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, void *resp) { @@ -363,7 +363,7 @@ nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, return nfserr; } -static int +static __be32 nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp, void *resp) { @@ -381,7 +381,7 @@ nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp, return nfserr; } -static int +static __be32 nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp, void *resp) { @@ -401,7 +401,7 @@ nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp, return nfserr; } -static int +static __be32 nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp, void *resp) { @@ -430,7 +430,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp, * Make directory. This operation is not idempotent. * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp, struct nfsd_diropres *resp) { @@ -454,7 +454,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp, /* * Remove a directory */ -static int +static __be32 nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, void *resp) { @@ -470,7 +470,7 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, /* * Read a portion of a directory. */ -static int +static __be32 nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, struct nfsd_readdirres *resp) { @@ -509,7 +509,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, /* * Get file system info */ -static int +static __be32 nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd_statfsres *resp) { diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 9c9a8ad92477..965d6c20086e 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -335,7 +335,7 @@ struct svc_version { /* * RPC procedure info */ -typedef int (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp); +typedef __be32 (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp); struct svc_procedure { svc_procfunc pc_func; /* process the request */ kxdrproc_t pc_decode; /* XDR decode args */ -- cgit v1.2.3 From 52921e02a4f4163a7b1f4b5dde71e1debc71de4a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:46 -0700 Subject: [PATCH] lockd endianness annotations Signed-off-by: Alexey Dobriyan Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntlock.c | 4 +-- fs/lockd/mon.c | 12 +++---- fs/lockd/svc4proc.c | 4 +-- fs/lockd/svclock.c | 10 +++--- fs/lockd/svcproc.c | 8 ++--- fs/lockd/svcshare.c | 4 +-- fs/lockd/svcsubs.c | 4 +-- fs/lockd/xdr.c | 76 +++++++++++++++++++++--------------------- fs/lockd/xdr4.c | 80 ++++++++++++++++++++++----------------------- include/linux/lockd/lockd.h | 12 +++---- include/linux/lockd/share.h | 4 +-- include/linux/lockd/xdr.h | 26 +++++++-------- include/linux/lockd/xdr4.h | 26 +++++++-------- 13 files changed, 135 insertions(+), 135 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index e8c7765419e8..b85a0ad2cfb6 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -100,12 +100,12 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout) /* * The server lockd has called us back to tell us the lock was granted */ -u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock) +__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock) { const struct file_lock *fl = &lock->fl; const struct nfs_fh *fh = &lock->fh; struct nlm_wait *block; - u32 res = nlm_lck_denied; + __be32 res = nlm_lck_denied; /* * Look up blocked request based on arguments. diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index e0179f8c327f..eb243edf8932 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -148,8 +148,8 @@ nsm_create(void) * XDR functions for NSM. */ -static u32 * -xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) +static __be32 * +xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) { char buffer[20], *name; @@ -176,7 +176,7 @@ xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) } static int -xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) +xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) { p = xdr_encode_common(rqstp, p, argp); if (IS_ERR(p)) @@ -192,7 +192,7 @@ xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) } static int -xdr_encode_unmon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) +xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) { p = xdr_encode_common(rqstp, p, argp); if (IS_ERR(p)) @@ -202,7 +202,7 @@ xdr_encode_unmon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) } static int -xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp) +xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) { resp->status = ntohl(*p++); resp->state = ntohl(*p++); @@ -212,7 +212,7 @@ xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp) } static int -xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp) +xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) { resp->state = ntohl(*p++); return 0; diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 4e719860b4bf..0ce5c81ff507 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -24,14 +24,14 @@ /* * Obtain client and file from arguments */ -static u32 +static __be32 nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_host **hostp, struct nlm_file **filp) { struct nlm_host *host = NULL; struct nlm_file *file = NULL; struct nlm_lock *lock = &argp->lock; - u32 error = 0; + __be32 error = 0; /* nfsd callbacks must have been installed for this procedure */ if (!nlmsvc_ops) diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 814c6064c9e0..7e219b938552 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -334,13 +334,13 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call) * Attempt to establish a lock, and if it can't be granted, block it * if required. */ -u32 +__be32 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_lock *lock, int wait, struct nlm_cookie *cookie) { struct nlm_block *block, *newblock = NULL; int error; - u32 ret; + __be32 ret; dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", file->f_file->f_dentry->d_inode->i_sb->s_id, @@ -415,7 +415,7 @@ out: /* * Test for presence of a conflicting lock. */ -u32 +__be32 nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, struct nlm_lock *conflock) { @@ -448,7 +448,7 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, * afterwards. In this case the block will still be there, and hence * must be removed. */ -u32 +__be32 nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) { int error; @@ -476,7 +476,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) * be in progress. * The calling procedure must check whether the file can be closed. */ -u32 +__be32 nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) { struct nlm_block *block; diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index db8d85c32d29..32e99a6e8dca 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -22,8 +22,8 @@ #define NLMDBG_FACILITY NLMDBG_CLIENT #ifdef CONFIG_LOCKD_V4 -static u32 -cast_to_nlm(u32 status, u32 vers) +static __be32 +cast_to_nlm(__be32 status, u32 vers) { /* Note: status is assumed to be in network byte order !!! */ if (vers != 4){ @@ -52,14 +52,14 @@ cast_to_nlm(u32 status, u32 vers) /* * Obtain client and file from arguments */ -static u32 +static __be32 nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_host **hostp, struct nlm_file **filp) { struct nlm_host *host = NULL; struct nlm_file *file = NULL; struct nlm_lock *lock = &argp->lock; - u32 error = 0; + __be32 error = 0; /* nfsd callbacks must have been installed for this procedure */ if (!nlmsvc_ops) diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c index b9926ce8782e..6220dc2a3f2c 100644 --- a/fs/lockd/svcshare.c +++ b/fs/lockd/svcshare.c @@ -23,7 +23,7 @@ nlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh) && !memcmp(share->s_owner.data, oh->data, oh->len); } -u32 +__be32 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, struct nlm_args *argp) { @@ -64,7 +64,7 @@ update: /* * Delete a share. */ -u32 +__be32 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, struct nlm_args *argp) { diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 7dac96e6c82c..e83024e16042 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -78,14 +78,14 @@ static inline unsigned int file_hash(struct nfs_fh *f) * This is not quite right, but for now, we assume the client performs * the proper R/W checking. */ -u32 +__be32 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, struct nfs_fh *f) { struct hlist_node *pos; struct nlm_file *file; unsigned int hash; - u32 nfserr; + __be32 nfserr; nlm_debug_print_fh("nlm_file_lookup", f); diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 61c46facf257..b7c949256e5a 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -43,7 +43,7 @@ loff_t_to_s32(loff_t offset) /* * XDR functions for basic NLM types */ -static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c) +static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c) { unsigned int len; @@ -69,8 +69,8 @@ static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c) return p; } -static inline u32 * -nlm_encode_cookie(u32 *p, struct nlm_cookie *c) +static inline __be32 * +nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) { *p++ = htonl(c->len); memcpy(p, c->data, c->len); @@ -78,8 +78,8 @@ nlm_encode_cookie(u32 *p, struct nlm_cookie *c) return p; } -static u32 * -nlm_decode_fh(u32 *p, struct nfs_fh *f) +static __be32 * +nlm_decode_fh(__be32 *p, struct nfs_fh *f) { unsigned int len; @@ -95,8 +95,8 @@ nlm_decode_fh(u32 *p, struct nfs_fh *f) return p + XDR_QUADLEN(NFS2_FHSIZE); } -static inline u32 * -nlm_encode_fh(u32 *p, struct nfs_fh *f) +static inline __be32 * +nlm_encode_fh(__be32 *p, struct nfs_fh *f) { *p++ = htonl(NFS2_FHSIZE); memcpy(p, f->data, NFS2_FHSIZE); @@ -106,20 +106,20 @@ nlm_encode_fh(u32 *p, struct nfs_fh *f) /* * Encode and decode owner handle */ -static inline u32 * -nlm_decode_oh(u32 *p, struct xdr_netobj *oh) +static inline __be32 * +nlm_decode_oh(__be32 *p, struct xdr_netobj *oh) { return xdr_decode_netobj(p, oh); } -static inline u32 * -nlm_encode_oh(u32 *p, struct xdr_netobj *oh) +static inline __be32 * +nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) { return xdr_encode_netobj(p, oh); } -static u32 * -nlm_decode_lock(u32 *p, struct nlm_lock *lock) +static __be32 * +nlm_decode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; s32 start, len, end; @@ -153,8 +153,8 @@ nlm_decode_lock(u32 *p, struct nlm_lock *lock) /* * Encode a lock as part of an NLM call */ -static u32 * -nlm_encode_lock(u32 *p, struct nlm_lock *lock) +static __be32 * +nlm_encode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; __s32 start, len; @@ -184,8 +184,8 @@ nlm_encode_lock(u32 *p, struct nlm_lock *lock) /* * Encode result of a TEST/TEST_MSG call */ -static u32 * -nlm_encode_testres(u32 *p, struct nlm_res *resp) +static __be32 * +nlm_encode_testres(__be32 *p, struct nlm_res *resp) { s32 start, len; @@ -221,7 +221,7 @@ nlm_encode_testres(u32 *p, struct nlm_res *resp) * First, the server side XDR functions */ int -nlmsvc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -238,7 +238,7 @@ nlmsvc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlmsvc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_encode_testres(p, resp))) return 0; @@ -246,7 +246,7 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlmsvc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -266,7 +266,7 @@ nlmsvc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlmsvc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -282,7 +282,7 @@ nlmsvc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { if (!(p = nlm_decode_cookie(p, &argp->cookie)) || !(p = nlm_decode_lock(p, &argp->lock))) @@ -292,7 +292,7 @@ nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -313,7 +313,7 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_encode_cookie(p, &resp->cookie))) return 0; @@ -323,7 +323,7 @@ nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_encode_cookie(p, &resp->cookie))) return 0; @@ -332,7 +332,7 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlmsvc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp) +nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -344,7 +344,7 @@ nlmsvc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp) } int -nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) +nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp) { if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) return 0; @@ -357,7 +357,7 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) } int -nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_decode_cookie(p, &resp->cookie))) return 0; @@ -366,13 +366,13 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlmsvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_argsize_check(rqstp, p); } int -nlmsvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } @@ -389,7 +389,7 @@ nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr) #endif static int -nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -403,7 +403,7 @@ nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_decode_cookie(p, &resp->cookie))) return -EIO; @@ -438,7 +438,7 @@ nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) static int -nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -455,7 +455,7 @@ nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -470,7 +470,7 @@ nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -483,7 +483,7 @@ nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_encode_cookie(p, &resp->cookie))) return -EIO; @@ -493,7 +493,7 @@ nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) } static int -nlmclt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_encode_testres(p, resp))) return -EIO; @@ -502,7 +502,7 @@ nlmclt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) } static int -nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_decode_cookie(p, &resp->cookie))) return -EIO; diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 36eb175ec335..f4c0b2b9f75a 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -44,8 +44,8 @@ loff_t_to_s64(loff_t offset) /* * XDR functions for basic NLM types */ -static u32 * -nlm4_decode_cookie(u32 *p, struct nlm_cookie *c) +static __be32 * +nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c) { unsigned int len; @@ -71,8 +71,8 @@ nlm4_decode_cookie(u32 *p, struct nlm_cookie *c) return p; } -static u32 * -nlm4_encode_cookie(u32 *p, struct nlm_cookie *c) +static __be32 * +nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) { *p++ = htonl(c->len); memcpy(p, c->data, c->len); @@ -80,8 +80,8 @@ nlm4_encode_cookie(u32 *p, struct nlm_cookie *c) return p; } -static u32 * -nlm4_decode_fh(u32 *p, struct nfs_fh *f) +static __be32 * +nlm4_decode_fh(__be32 *p, struct nfs_fh *f) { memset(f->data, 0, sizeof(f->data)); f->size = ntohl(*p++); @@ -95,8 +95,8 @@ nlm4_decode_fh(u32 *p, struct nfs_fh *f) return p + XDR_QUADLEN(f->size); } -static u32 * -nlm4_encode_fh(u32 *p, struct nfs_fh *f) +static __be32 * +nlm4_encode_fh(__be32 *p, struct nfs_fh *f) { *p++ = htonl(f->size); if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */ @@ -107,20 +107,20 @@ nlm4_encode_fh(u32 *p, struct nfs_fh *f) /* * Encode and decode owner handle */ -static u32 * -nlm4_decode_oh(u32 *p, struct xdr_netobj *oh) +static __be32 * +nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) { return xdr_decode_netobj(p, oh); } -static u32 * -nlm4_encode_oh(u32 *p, struct xdr_netobj *oh) +static __be32 * +nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh) { return xdr_encode_netobj(p, oh); } -static u32 * -nlm4_decode_lock(u32 *p, struct nlm_lock *lock) +static __be32 * +nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; __s64 len, start, end; @@ -153,8 +153,8 @@ nlm4_decode_lock(u32 *p, struct nlm_lock *lock) /* * Encode a lock as part of an NLM call */ -static u32 * -nlm4_encode_lock(u32 *p, struct nlm_lock *lock) +static __be32 * +nlm4_encode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; __s64 start, len; @@ -185,8 +185,8 @@ nlm4_encode_lock(u32 *p, struct nlm_lock *lock) /* * Encode result of a TEST/TEST_MSG call */ -static u32 * -nlm4_encode_testres(u32 *p, struct nlm_res *resp) +static __be32 * +nlm4_encode_testres(__be32 *p, struct nlm_res *resp) { s64 start, len; @@ -227,7 +227,7 @@ nlm4_encode_testres(u32 *p, struct nlm_res *resp) * First, the server side XDR functions */ int -nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -244,7 +244,7 @@ nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_encode_testres(p, resp))) return 0; @@ -252,7 +252,7 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -272,7 +272,7 @@ nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -288,7 +288,7 @@ nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { if (!(p = nlm4_decode_cookie(p, &argp->cookie)) || !(p = nlm4_decode_lock(p, &argp->lock))) @@ -298,7 +298,7 @@ nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -319,7 +319,7 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_encode_cookie(p, &resp->cookie))) return 0; @@ -329,7 +329,7 @@ nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_encode_cookie(p, &resp->cookie))) return 0; @@ -338,7 +338,7 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp) +nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -350,7 +350,7 @@ nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp) } int -nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) +nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp) { if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) return 0; @@ -363,7 +363,7 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) } int -nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_decode_cookie(p, &resp->cookie))) return 0; @@ -372,13 +372,13 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_argsize_check(rqstp, p); } int -nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } @@ -388,14 +388,14 @@ nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) */ #ifdef NLMCLNT_SUPPORT_SHARES static int -nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr) +nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr) { return 0; } #endif static int -nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -409,7 +409,7 @@ nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_decode_cookie(p, &resp->cookie))) return -EIO; @@ -444,7 +444,7 @@ nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) static int -nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -461,7 +461,7 @@ nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -476,7 +476,7 @@ nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -489,7 +489,7 @@ nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlm4clt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_encode_cookie(p, &resp->cookie))) return -EIO; @@ -499,7 +499,7 @@ nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) } static int -nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlm4clt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_encode_testres(p, resp))) return -EIO; @@ -508,7 +508,7 @@ nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) } static int -nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_decode_cookie(p, &resp->cookie))) return -EIO; diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 2909619c0295..862d9730a60d 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -154,7 +154,7 @@ int nlm_async_reply(struct nlm_rqst *, u32, const struct rpc_call_ops *); struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl); void nlmclnt_finish_block(struct nlm_wait *block); int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout); -u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *); +__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *); void nlmclnt_recovery(struct nlm_host *); int nlmclnt_reclaim(struct nlm_host *, struct file_lock *); void nlmclnt_next_cookie(struct nlm_cookie *); @@ -184,12 +184,12 @@ typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref) /* * Server-side lock handling */ -u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, +__be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, struct nlm_lock *, int, struct nlm_cookie *); -u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *); -u32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *, +__be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *); +__be32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *, struct nlm_lock *); -u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); +__be32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); unsigned long nlmsvc_retry_blocked(void); void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, nlm_host_match_fn_t match); @@ -198,7 +198,7 @@ void nlmsvc_grant_reply(struct nlm_cookie *, u32); /* * File handling for the server personality */ -u32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, +__be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, struct nfs_fh *); void nlm_release_file(struct nlm_file *); void nlmsvc_mark_resources(void); diff --git a/include/linux/lockd/share.h b/include/linux/lockd/share.h index cd7816e74c05..630c5bf69b07 100644 --- a/include/linux/lockd/share.h +++ b/include/linux/lockd/share.h @@ -21,9 +21,9 @@ struct nlm_share { u32 s_mode; /* deny mode */ }; -u32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *, +__be32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *, struct nlm_args *); -u32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *, +__be32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *, struct nlm_args *); void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, nlm_host_match_fn_t); diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h index 66fdae3b490c..29e7d9fc9dad 100644 --- a/include/linux/lockd/xdr.h +++ b/include/linux/lockd/xdr.h @@ -90,19 +90,19 @@ struct nlm_reboot { */ #define NLMSVC_XDRSIZE sizeof(struct nlm_args) -int nlmsvc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *); -int nlmsvc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *); -int nlmsvc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *); -int nlmsvc_encode_void(struct svc_rqst *, u32 *, void *); -int nlmsvc_decode_void(struct svc_rqst *, u32 *, void *); -int nlmsvc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *); -int nlmsvc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *); +int nlmsvc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlmsvc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlmsvc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlmsvc_encode_void(struct svc_rqst *, __be32 *, void *); +int nlmsvc_decode_void(struct svc_rqst *, __be32 *, void *); +int nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlmsvc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *); /* int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h index 3cc1ae25009b..dd12b4c9e613 100644 --- a/include/linux/lockd/xdr4.h +++ b/include/linux/lockd/xdr4.h @@ -23,19 +23,19 @@ -int nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *); -int nlm4svc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *); -int nlm4svc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *); -int nlm4svc_encode_void(struct svc_rqst *, u32 *, void *); -int nlm4svc_decode_void(struct svc_rqst *, u32 *, void *); -int nlm4svc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *); -int nlm4svc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *); +int nlm4svc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlm4svc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlm4svc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlm4svc_encode_void(struct svc_rqst *, __be32 *, void *); +int nlm4svc_decode_void(struct svc_rqst *, __be32 *, void *); +int nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlm4svc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *); /* int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); -- cgit v1.2.3 From 0dbb4c6799cf8fa8c5ba1926153a30960117477d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:49 -0700 Subject: [PATCH] xdr annotations: NFS readdir entries on-the-wire data is big-endian [in large part pulled from Alexey's patch] Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/dir.c | 6 +++--- fs/nfs/internal.h | 6 +++--- fs/nfs/nfs2xdr.c | 4 ++-- fs/nfs/nfs3xdr.c | 4 ++-- fs/nfs/nfs4_fs.h | 2 +- fs/nfs/nfs4proc.c | 4 ++-- fs/nfs/nfs4xdr.c | 2 +- include/linux/nfs_xdr.h | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c86a1ead4772..4133ef5264e5 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -142,12 +142,12 @@ nfs_opendir(struct inode *inode, struct file *filp) return res; } -typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int); +typedef __be32 * (*decode_dirent_t)(__be32 *, struct nfs_entry *, int); typedef struct { struct file *file; struct page *page; unsigned long page_index; - u32 *ptr; + __be32 *ptr; u64 *dir_cookie; loff_t current_index; struct nfs_entry *entry; @@ -220,7 +220,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) static inline int dir_decode(nfs_readdir_descriptor_t *desc) { - u32 *p = desc->ptr; + __be32 *p = desc->ptr; p = desc->decode(p, desc->entry, desc->plus); if (IS_ERR(p)) return PTR_ERR(p); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index bea0b016bd70..d205466233f6 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -93,15 +93,15 @@ extern void nfs_destroy_directcache(void); /* nfs2xdr.c */ extern int nfs_stat_to_errno(int); extern struct rpc_procinfo nfs_procedures[]; -extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); +extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int); /* nfs3xdr.c */ extern struct rpc_procinfo nfs3_procedures[]; -extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); +extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); /* nfs4xdr.c */ #ifdef CONFIG_NFS_V4 -extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); +extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); #endif /* nfs4proc.c */ diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 1d801e30c40e..3be4e72a0227 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -468,8 +468,8 @@ err_unmap: goto out; } -u32 * -nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) +__be32 * +nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) { if (!*p++) { if (!*p) diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index b4e740e4494a..0ace092d126f 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -583,8 +583,8 @@ err_unmap: goto out; } -u32 * -nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) +__be32 * +nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) { struct nfs_entry old = *entry; diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 61095fe4b5ca..6f346677332d 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -212,7 +212,7 @@ extern void nfs_free_seqid(struct nfs_seqid *seqid); extern const nfs4_stateid zero_stateid; /* nfs4xdr.c */ -extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus); +extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; struct nfs4_mount_data; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7421bcb3b728..8d09b47c91b9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -141,7 +141,7 @@ const u32 nfs4_fs_locations_bitmap[2] = { static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, struct nfs4_readdir_arg *readdir) { - u32 *start, *p; + __be32 *start, *p; BUG_ON(readdir->count < 80); if (cookie > 2) { @@ -162,7 +162,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, * when talking to the server, we always send cookie 0 * instead of 1 or 2. */ - start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0); + start = p = kmap_atomic(*readdir->pages, KM_USER0); if (cookie == 0) { *p++ = xdr_one; /* next */ diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e284123b9774..0cf3fa312a33 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4421,7 +4421,7 @@ out: return status; } -uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) +__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) { uint32_t bitmap[2] = {0}; uint32_t len; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index dc5397d9d23c..ac8058bc8f94 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -811,7 +811,7 @@ struct nfs_rpc_ops { int (*pathconf) (struct nfs_server *, struct nfs_fh *, struct nfs_pathconf *); int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); - u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus); + __be32 *(*decode_dirent)(__be32 *, struct nfs_entry *, int plus); void (*read_setup) (struct nfs_read_data *); int (*read_done) (struct rpc_task *, struct nfs_read_data *); void (*write_setup) (struct nfs_write_data *, int how); -- cgit v1.2.3 From bc4785cd475a11ba125df7af674e16c6ea1cfc30 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:51 -0700 Subject: [PATCH] nfs: verifier is network-endian Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/nfs3proc.c | 2 +- fs/nfs/nfs4proc.c | 6 +++--- include/linux/nfs_fs.h | 2 +- include/linux/nfs_xdr.h | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 3b234d4601e7..e5f128ffc32d 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -668,7 +668,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, { struct inode *dir = dentry->d_inode; struct nfs_fattr dir_attr; - u32 *verf = NFS_COOKIEVERF(dir); + __be32 *verf = NFS_COOKIEVERF(dir); struct nfs3_readdirargs arg = { .fh = NFS_FH(dir), .cookie = cookie, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8d09b47c91b9..8118036cc449 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -138,7 +138,7 @@ const u32 nfs4_fs_locations_bitmap[2] = { | FATTR4_WORD1_MOUNTED_ON_FILEID }; -static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, +static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry, struct nfs4_readdir_arg *readdir) { __be32 *start, *p; @@ -2915,11 +2915,11 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po .rpc_resp = clp, .rpc_cred = cred, }; - u32 *p; + __be32 *p; int loop = 0; int status; - p = (u32*)sc_verifier.data; + p = (__be32*)sc_verifier.data; *p++ = htonl((u32)clp->cl_boot_time.tv_sec); *p = htonl((u32)clp->cl_boot_time.tv_nsec); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 6b2de1be5815..45228c1a1195 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -157,7 +157,7 @@ struct nfs_inode { * This is the cookie verifier used for NFSv3 readdir * operations */ - __u32 cookieverf[2]; + __be32 cookieverf[2]; /* * This is the list of dirty unwritten pages. diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index ac8058bc8f94..768c1ad5ff6f 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -266,7 +266,7 @@ struct nfs_writeargs { struct nfs_writeverf { enum nfs3_stable_how committed; - __u32 verifier[2]; + __be32 verifier[2]; }; struct nfs_writeres { @@ -420,7 +420,7 @@ struct nfs3_createargs { unsigned int len; struct iattr * sattr; enum nfs3_createmode createmode; - __u32 verifier[2]; + __be32 verifier[2]; }; struct nfs3_mkdirargs { @@ -467,7 +467,7 @@ struct nfs3_linkargs { struct nfs3_readdirargs { struct nfs_fh * fh; __u64 cookie; - __u32 verf[2]; + __be32 verf[2]; int plus; unsigned int count; struct page ** pages; @@ -503,7 +503,7 @@ struct nfs3_linkres { struct nfs3_readdirres { struct nfs_fattr * dir_attr; - __u32 * verf; + __be32 * verf; int plus; }; -- cgit v1.2.3 From 63f103111fdfc3cba00e4c94921d32362f375d93 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:54 -0700 Subject: [PATCH] nfsd: nfserrno() endianness annotations Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsproc.c | 7 +++---- include/linux/nfsd/export.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 09030afd7249..03ab6822291f 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -579,11 +579,11 @@ struct svc_version nfsd_version2 = { /* * Map errnos to NFS errnos. */ -int +__be32 nfserrno (int errno) { static struct { - int nfserr; + __be32 nfserr; int syserr; } nfs_errtbl[] = { { nfs_ok, 0 }, @@ -615,11 +615,10 @@ nfserrno (int errno) { nfserr_badname, -ESRCH }, { nfserr_io, -ETXTBSY }, { nfserr_notsupp, -EOPNOTSUPP }, - { -1, -EIO } }; int i; - for (i = 0; nfs_errtbl[i].nfserr != -1; i++) { + for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) { if (nfs_errtbl[i].syserr == errno) return nfs_errtbl[i].nfserr; } diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 6e78ea969f49..27666f5b8b53 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -118,7 +118,7 @@ struct svc_export * exp_parent(struct auth_domain *clp, int exp_rootfh(struct auth_domain *, char *path, struct knfsd_fh *, int maxsize); int exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq); -int nfserrno(int errno); +__be32 nfserrno(int errno); extern struct cache_detail svc_export_cache; -- cgit v1.2.3 From 83b11340d683a67a77e35a5ffb5ad4afbf0be4e5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:55 -0700 Subject: [PATCH] nfsfh simple endianness annotations Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsfh.c | 10 +++++----- include/linux/nfsd/nfsfh.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 501d83884530..727ab3bd450d 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -76,7 +76,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) * comment in the NFSv3 spec says this is incorrect (implementation notes for * the write call). */ -static inline int +static inline __be32 nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type) { /* Type can be negative when creating hardlinks - not to a dir */ @@ -110,13 +110,13 @@ nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type) * This is only called at the start of an nfsproc call, so fhp points to * a svc_fh which is all 0 except for the over-the-wire file handle. */ -u32 +__be32 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) { struct knfsd_fh *fh = &fhp->fh_handle; struct svc_export *exp = NULL; struct dentry *dentry; - u32 error = 0; + __be32 error = 0; dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); @@ -315,7 +315,7 @@ static inline void _fh_update_old(struct dentry *dentry, fh->ofh_dirino = 0; } -int +__be32 fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh) { /* ref_fh is a reference file handle. @@ -451,7 +451,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st * Update file handle information after changing a dentry. * This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create */ -int +__be32 fh_update(struct svc_fh *fhp) { struct dentry *dentry; diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index 069257ea99a0..749bad1ca16f 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -209,9 +209,9 @@ extern char * SVCFH_fmt(struct svc_fh *fhp); /* * Function prototypes */ -u32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int); -int fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *); -int fh_update(struct svc_fh *); +__be32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int); +__be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *); +__be32 fh_update(struct svc_fh *); void fh_put(struct svc_fh *); static __inline__ struct svc_fh * -- cgit v1.2.3 From 131a21c2177c267ab259fcd06947c6f593a7de8e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:56 -0700 Subject: [PATCH] xdr annotations: NFSv2 server Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs2acl.c | 18 ++++++------ fs/nfsd/nfsxdr.c | 72 +++++++++++++++++++++++------------------------ include/linux/nfsd/nfsd.h | 2 +- include/linux/nfsd/xdr.h | 50 ++++++++++++++++---------------- 4 files changed, 71 insertions(+), 71 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 8d48616882c1..fd5397d8c62a 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -158,7 +158,7 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessarg /* * XDR decode functions */ -static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclargs *argp) { if (!(p = nfs2svc_decode_fh(p, &argp->fh))) @@ -169,7 +169,7 @@ static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, } -static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_setaclargs *argp) { struct kvec *head = rqstp->rq_arg.head; @@ -194,7 +194,7 @@ static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, return (n > 0); } -static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *argp) { if (!(p = nfs2svc_decode_fh(p, &argp->fh))) @@ -202,7 +202,7 @@ static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p, return xdr_argsize_check(rqstp, p); } -static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_accessargs *argp) { if (!(p = nfs2svc_decode_fh(p, &argp->fh))) @@ -217,7 +217,7 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, */ /* GETACL */ -static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclres *resp) { struct dentry *dentry = resp->fh.fh_dentry; @@ -259,7 +259,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, return 1; } -static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_attrstat *resp) { p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); @@ -267,7 +267,7 @@ static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p, } /* ACCESS */ -static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_accessres *resp) { p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); @@ -278,7 +278,7 @@ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p, /* * XDR release functions */ -static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclres *resp) { fh_put(&resp->fh); @@ -287,7 +287,7 @@ static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p, return 1; } -static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *resp) { fh_put(&resp->fh); diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 1135c0d14557..56ebb1443e0e 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -37,8 +37,8 @@ static u32 nfs_ftypes[] = { /* * XDR functions for basic NFS types */ -static u32 * -decode_fh(u32 *p, struct svc_fh *fhp) +static __be32 * +decode_fh(__be32 *p, struct svc_fh *fhp) { fh_init(fhp, NFS_FHSIZE); memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE); @@ -50,13 +50,13 @@ decode_fh(u32 *p, struct svc_fh *fhp) } /* Helper function for NFSv2 ACL code */ -u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp) +__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp) { return decode_fh(p, fhp); } -static inline u32 * -encode_fh(u32 *p, struct svc_fh *fhp) +static inline __be32 * +encode_fh(__be32 *p, struct svc_fh *fhp) { memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE); return p + (NFS_FHSIZE>> 2); @@ -66,8 +66,8 @@ encode_fh(u32 *p, struct svc_fh *fhp) * Decode a file name and make sure that the path contains * no slashes or null bytes. */ -static inline u32 * -decode_filename(u32 *p, char **namp, int *lenp) +static inline __be32 * +decode_filename(__be32 *p, char **namp, int *lenp) { char *name; int i; @@ -82,8 +82,8 @@ decode_filename(u32 *p, char **namp, int *lenp) return p; } -static inline u32 * -decode_pathname(u32 *p, char **namp, int *lenp) +static inline __be32 * +decode_pathname(__be32 *p, char **namp, int *lenp) { char *name; int i; @@ -98,8 +98,8 @@ decode_pathname(u32 *p, char **namp, int *lenp) return p; } -static inline u32 * -decode_sattr(u32 *p, struct iattr *iap) +static inline __be32 * +decode_sattr(__be32 *p, struct iattr *iap) { u32 tmp, tmp1; @@ -151,8 +151,8 @@ decode_sattr(u32 *p, struct iattr *iap) return p; } -static u32 * -encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp, +static __be32 * +encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat) { struct dentry *dentry = fhp->fh_dentry; @@ -195,7 +195,7 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp, } /* Helper function for NFSv2 ACL code */ -u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct kstat stat; vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, &stat); @@ -206,13 +206,13 @@ u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) * XDR decode functions */ int -nfssvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_argsize_check(rqstp, p); } int -nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args) +nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args) { if (!(p = decode_fh(p, &args->fh))) return 0; @@ -220,7 +220,7 @@ nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args) } int -nfssvc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_sattrargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -231,7 +231,7 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_diropargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_diropargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -242,7 +242,7 @@ nfssvc_decode_diropargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readargs *args) { unsigned int len; @@ -273,7 +273,7 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_writeargs *args) { unsigned int len; @@ -303,7 +303,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_createargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_createargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -315,7 +315,7 @@ nfssvc_decode_createargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_renameargs *args) { if (!(p = decode_fh(p, &args->ffh)) @@ -328,7 +328,7 @@ nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinkargs *args) +nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkargs *args) { if (!(p = decode_fh(p, &args->fh))) return 0; @@ -338,7 +338,7 @@ nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinka } int -nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_linkargs *args) { if (!(p = decode_fh(p, &args->ffh)) @@ -350,7 +350,7 @@ nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_symlinkargs *args) { if (!(p = decode_fh(p, &args->ffh)) @@ -363,7 +363,7 @@ nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readdirargs *args) { if (!(p = decode_fh(p, &args->fh))) @@ -382,13 +382,13 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, * XDR encode functions */ int -nfssvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } int -nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p, struct nfsd_attrstat *resp) { p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); @@ -396,7 +396,7 @@ nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_diropres *resp) { p = encode_fh(p, &resp->fh); @@ -405,7 +405,7 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkres *resp) { *p++ = htonl(resp->len); @@ -421,7 +421,7 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readres *resp) { p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); @@ -440,7 +440,7 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readdirres *resp) { xdr_ressize_check(rqstp, p); @@ -453,7 +453,7 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_statfsres *resp) { struct kstatfs *stat = &resp->stats; @@ -471,7 +471,7 @@ nfssvc_encode_entry(struct readdir_cd *ccd, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common); - u32 *p = cd->buffer; + __be32 *p = cd->buffer; int buflen, slen; /* @@ -497,7 +497,7 @@ nfssvc_encode_entry(struct readdir_cd *ccd, const char *name, *p++ = htonl((u32) ino); /* file id */ p = xdr_encode_array(p, name, namlen);/* name length & name */ cd->offset = p; /* remember pointer */ - *p++ = ~(u32) 0; /* offset of next entry */ + *p++ = htonl(~0U); /* offset of next entry */ cd->buflen = buflen; cd->buffer = p; @@ -509,7 +509,7 @@ nfssvc_encode_entry(struct readdir_cd *ccd, const char *name, * XDR release functions */ int -nfssvc_release_fhandle(struct svc_rqst *rqstp, u32 *p, +nfssvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *resp) { fh_put(&resp->fh); diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index d0d4aae7085f..2f75160a5824 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -50,7 +50,7 @@ * Callback function for readdir */ struct readdir_cd { - int err; /* 0, nfserr, or nfserr_eof */ + __be32 err; /* 0, nfserr, or nfserr_eof */ }; typedef int (*encode_dent_fn)(struct readdir_cd *, const char *, int, loff_t, ino_t, unsigned int); diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h index 0e53de87d886..877192d3ae79 100644 --- a/include/linux/nfsd/xdr.h +++ b/include/linux/nfsd/xdr.h @@ -81,7 +81,7 @@ struct nfsd_readdirargs { struct svc_fh fh; __u32 cookie; __u32 count; - u32 * buffer; + __be32 * buffer; }; struct nfsd_attrstat { @@ -108,9 +108,9 @@ struct nfsd_readdirres { int count; struct readdir_cd common; - u32 * buffer; + __be32 * buffer; int buflen; - u32 * offset; + __be32 * offset; }; struct nfsd_statfsres { @@ -135,43 +135,43 @@ union nfsd_xdrstore { #define NFS2_SVC_XDRSIZE sizeof(union nfsd_xdrstore) -int nfssvc_decode_void(struct svc_rqst *, u32 *, void *); -int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); -int nfssvc_decode_sattrargs(struct svc_rqst *, u32 *, +int nfssvc_decode_void(struct svc_rqst *, __be32 *, void *); +int nfssvc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *); +int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *, struct nfsd_sattrargs *); -int nfssvc_decode_diropargs(struct svc_rqst *, u32 *, +int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *, struct nfsd_diropargs *); -int nfssvc_decode_readargs(struct svc_rqst *, u32 *, +int nfssvc_decode_readargs(struct svc_rqst *, __be32 *, struct nfsd_readargs *); -int nfssvc_decode_writeargs(struct svc_rqst *, u32 *, +int nfssvc_decode_writeargs(struct svc_rqst *, __be32 *, struct nfsd_writeargs *); -int nfssvc_decode_createargs(struct svc_rqst *, u32 *, +int nfssvc_decode_createargs(struct svc_rqst *, __be32 *, struct nfsd_createargs *); -int nfssvc_decode_renameargs(struct svc_rqst *, u32 *, +int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *, struct nfsd_renameargs *); -int nfssvc_decode_readlinkargs(struct svc_rqst *, u32 *, +int nfssvc_decode_readlinkargs(struct svc_rqst *, __be32 *, struct nfsd_readlinkargs *); -int nfssvc_decode_linkargs(struct svc_rqst *, u32 *, +int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *, struct nfsd_linkargs *); -int nfssvc_decode_symlinkargs(struct svc_rqst *, u32 *, +int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *, struct nfsd_symlinkargs *); -int nfssvc_decode_readdirargs(struct svc_rqst *, u32 *, +int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *, struct nfsd_readdirargs *); -int nfssvc_encode_void(struct svc_rqst *, u32 *, void *); -int nfssvc_encode_attrstat(struct svc_rqst *, u32 *, struct nfsd_attrstat *); -int nfssvc_encode_diropres(struct svc_rqst *, u32 *, struct nfsd_diropres *); -int nfssvc_encode_readlinkres(struct svc_rqst *, u32 *, struct nfsd_readlinkres *); -int nfssvc_encode_readres(struct svc_rqst *, u32 *, struct nfsd_readres *); -int nfssvc_encode_statfsres(struct svc_rqst *, u32 *, struct nfsd_statfsres *); -int nfssvc_encode_readdirres(struct svc_rqst *, u32 *, struct nfsd_readdirres *); +int nfssvc_encode_void(struct svc_rqst *, __be32 *, void *); +int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *, struct nfsd_attrstat *); +int nfssvc_encode_diropres(struct svc_rqst *, __be32 *, struct nfsd_diropres *); +int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *, struct nfsd_readlinkres *); +int nfssvc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd_readres *); +int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *, struct nfsd_statfsres *); +int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *, struct nfsd_readdirres *); int nfssvc_encode_entry(struct readdir_cd *, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int); -int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); +int nfssvc_release_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *); /* Helper functions for NFSv2 ACL code */ -u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp); -u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp); +__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp); +__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp); #endif /* LINUX_NFSD_H */ -- cgit v1.2.3 From 91f07168cef8e99dd16f608fbc703e7a5af0237f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:57 -0700 Subject: [PATCH] xdr annotations: NFSv3 server Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs3acl.c | 10 ++-- fs/nfsd/nfs3xdr.c | 126 +++++++++++++++++++++++----------------------- include/linux/nfsd/xdr3.h | 114 ++++++++++++++++++++--------------------- 3 files changed, 125 insertions(+), 125 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index ed6e2c27b5e8..78b2c83d00c5 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -122,7 +122,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, /* * XDR decode functions */ -static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, +static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclargs *args) { if (!(p = nfs3svc_decode_fh(p, &args->fh))) @@ -133,7 +133,7 @@ static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, } -static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, +static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_setaclargs *args) { struct kvec *head = rqstp->rq_arg.head; @@ -163,7 +163,7 @@ static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, */ /* GETACL */ -static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, +static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclres *resp) { struct dentry *dentry = resp->fh.fh_dentry; @@ -208,7 +208,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, } /* SETACL */ -static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p, +static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); @@ -219,7 +219,7 @@ static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p, /* * XDR release functions */ -static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p, +static int nfs3svc_release_getacl(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclres *resp) { fh_put(&resp->fh); diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 247d518248bf..b4baca3053c3 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -42,23 +42,23 @@ static u32 nfs3_ftypes[] = { /* * XDR functions for basic NFS types */ -static inline u32 * -encode_time3(u32 *p, struct timespec *time) +static inline __be32 * +encode_time3(__be32 *p, struct timespec *time) { *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec); return p; } -static inline u32 * -decode_time3(u32 *p, struct timespec *time) +static inline __be32 * +decode_time3(__be32 *p, struct timespec *time) { time->tv_sec = ntohl(*p++); time->tv_nsec = ntohl(*p++); return p; } -static inline u32 * -decode_fh(u32 *p, struct svc_fh *fhp) +static inline __be32 * +decode_fh(__be32 *p, struct svc_fh *fhp) { unsigned int size; fh_init(fhp, NFS3_FHSIZE); @@ -72,13 +72,13 @@ decode_fh(u32 *p, struct svc_fh *fhp) } /* Helper function for NFSv3 ACL code */ -u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp) +__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp) { return decode_fh(p, fhp); } -static inline u32 * -encode_fh(u32 *p, struct svc_fh *fhp) +static inline __be32 * +encode_fh(__be32 *p, struct svc_fh *fhp) { unsigned int size = fhp->fh_handle.fh_size; *p++ = htonl(size); @@ -91,8 +91,8 @@ encode_fh(u32 *p, struct svc_fh *fhp) * Decode a file name and make sure that the path contains * no slashes or null bytes. */ -static inline u32 * -decode_filename(u32 *p, char **namp, int *lenp) +static inline __be32 * +decode_filename(__be32 *p, char **namp, int *lenp) { char *name; int i; @@ -107,8 +107,8 @@ decode_filename(u32 *p, char **namp, int *lenp) return p; } -static inline u32 * -decode_sattr3(u32 *p, struct iattr *iap) +static inline __be32 * +decode_sattr3(__be32 *p, struct iattr *iap) { u32 tmp; @@ -153,8 +153,8 @@ decode_sattr3(u32 *p, struct iattr *iap) return p; } -static inline u32 * -encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp, +static inline __be32 * +encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat) { struct dentry *dentry = fhp->fh_dentry; @@ -186,8 +186,8 @@ encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp, return p; } -static inline u32 * -encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +static inline __be32 * +encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct inode *inode = fhp->fh_dentry->d_inode; @@ -224,8 +224,8 @@ encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) * The inode may be NULL if the call failed because of a stale file * handle. In this case, no attributes are returned. */ -static u32 * -encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +static __be32 * +encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct dentry *dentry = fhp->fh_dentry; if (dentry && dentry->d_inode != NULL) { @@ -243,8 +243,8 @@ encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) } /* Helper for NFSv3 ACLs */ -u32 * -nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +__be32 * +nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { return encode_post_op_attr(rqstp, p, fhp); } @@ -252,8 +252,8 @@ nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) /* * Enocde weak cache consistency data */ -static u32 * -encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +static __be32 * +encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct dentry *dentry = fhp->fh_dentry; @@ -278,7 +278,7 @@ encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) * XDR decode functions */ int -nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args) +nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args) { if (!(p = decode_fh(p, &args->fh))) return 0; @@ -286,7 +286,7 @@ nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args } int -nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_sattrargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -303,7 +303,7 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_diropargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -314,7 +314,7 @@ nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_accessargs *args) { if (!(p = decode_fh(p, &args->fh))) @@ -325,7 +325,7 @@ nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readargs *args) { unsigned int len; @@ -355,7 +355,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_writeargs *args) { unsigned int len, v, hdr; @@ -393,7 +393,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_createargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -417,7 +417,7 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p, return xdr_argsize_check(rqstp, p); } int -nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_createargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -429,7 +429,7 @@ nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_symlinkargs *args) { unsigned int len; @@ -481,7 +481,7 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_mknodargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -505,7 +505,7 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_renameargs *args) { if (!(p = decode_fh(p, &args->ffh)) @@ -518,7 +518,7 @@ nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readlinkargs *args) { if (!(p = decode_fh(p, &args->fh))) @@ -530,7 +530,7 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_linkargs *args) { if (!(p = decode_fh(p, &args->ffh)) @@ -542,7 +542,7 @@ nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readdirargs *args) { if (!(p = decode_fh(p, &args->fh))) @@ -562,7 +562,7 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readdirargs *args) { int len, pn; @@ -590,7 +590,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_commitargs *args) { if (!(p = decode_fh(p, &args->fh))) @@ -609,14 +609,14 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p, * will work properly. */ int -nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy) +nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } /* GETATTR */ int -nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { if (resp->status == 0) @@ -626,7 +626,7 @@ nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p, /* SETATTR, REMOVE, RMDIR */ int -nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { p = encode_wcc_data(rqstp, p, &resp->fh); @@ -635,7 +635,7 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p, /* LOOKUP */ int -nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_diropres *resp) { if (resp->status == 0) { @@ -648,7 +648,7 @@ nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p, /* ACCESS */ int -nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_accessres *resp) { p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -659,7 +659,7 @@ nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p, /* READLINK */ int -nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readlinkres *resp) { p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -680,7 +680,7 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, /* READ */ int -nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readres *resp) { p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -704,7 +704,7 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p, /* WRITE */ int -nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_writeres *resp) { p = encode_wcc_data(rqstp, p, &resp->fh); @@ -719,7 +719,7 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p, /* CREATE, MKDIR, SYMLINK, MKNOD */ int -nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_diropres *resp) { if (resp->status == 0) { @@ -733,7 +733,7 @@ nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p, /* RENAME */ int -nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_renameres *resp) { p = encode_wcc_data(rqstp, p, &resp->ffh); @@ -743,7 +743,7 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p, /* LINK */ int -nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_linkres *resp) { p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -753,7 +753,7 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p, /* READDIR */ int -nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readdirres *resp) { p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -776,8 +776,8 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, return xdr_ressize_check(rqstp, p); } -static inline u32 * -encode_entry_baggage(struct nfsd3_readdirres *cd, u32 *p, const char *name, +static inline __be32 * +encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, ino_t ino) { *p++ = xdr_one; /* mark entry present */ @@ -790,8 +790,8 @@ encode_entry_baggage(struct nfsd3_readdirres *cd, u32 *p, const char *name, return p; } -static inline u32 * -encode_entryplus_baggage(struct nfsd3_readdirres *cd, u32 *p, +static inline __be32 * +encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, struct svc_fh *fhp) { p = encode_post_op_attr(cd->rqstp, p, fhp); @@ -853,7 +853,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, { struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres, common); - u32 *p = cd->buffer; + __be32 *p = cd->buffer; caddr_t curr_page_addr = NULL; int pn; /* current page number */ int slen; /* string (name) length */ @@ -919,7 +919,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, } else if (cd->rqstp->rq_respages[pn+1] != NULL) { /* temporarily encode entry into next page, then move back to * current and next page in rq_respages[] */ - u32 *p1, *tmp; + __be32 *p1, *tmp; int len1, len2; /* grab next page for temporary storage of entry */ @@ -1009,7 +1009,7 @@ nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name, /* FSSTAT */ int -nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_fsstatres *resp) { struct kstatfs *s = &resp->stats; @@ -1031,7 +1031,7 @@ nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p, /* FSINFO */ int -nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_fsinfores *resp) { *p++ = xdr_zero; /* no post_op_attr */ @@ -1055,7 +1055,7 @@ nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p, /* PATHCONF */ int -nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_pathconfres *resp) { *p++ = xdr_zero; /* no post_op_attr */ @@ -1074,7 +1074,7 @@ nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p, /* COMMIT */ int -nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_commitres *resp) { p = encode_wcc_data(rqstp, p, &resp->fh); @@ -1090,7 +1090,7 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p, * XDR release functions */ int -nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p, +nfs3svc_release_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { fh_put(&resp->fh); @@ -1098,7 +1098,7 @@ nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p, +nfs3svc_release_fhandle2(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_fhandle_pair *resp) { fh_put(&resp->fh1); diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h index 474d882dc2f3..79963867b0d7 100644 --- a/include/linux/nfsd/xdr3.h +++ b/include/linux/nfsd/xdr3.h @@ -51,7 +51,7 @@ struct nfsd3_createargs { int len; int createmode; struct iattr attrs; - __u32 * verf; + __be32 * verf; }; struct nfsd3_mknodargs { @@ -98,8 +98,8 @@ struct nfsd3_readdirargs { __u64 cookie; __u32 dircount; __u32 count; - __u32 * verf; - u32 * buffer; + __be32 * verf; + __be32 * buffer; }; struct nfsd3_commitargs { @@ -122,79 +122,79 @@ struct nfsd3_setaclargs { }; struct nfsd3_attrstat { - __u32 status; + __be32 status; struct svc_fh fh; struct kstat stat; }; /* LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD */ struct nfsd3_diropres { - __u32 status; + __be32 status; struct svc_fh dirfh; struct svc_fh fh; }; struct nfsd3_accessres { - __u32 status; + __be32 status; struct svc_fh fh; __u32 access; }; struct nfsd3_readlinkres { - __u32 status; + __be32 status; struct svc_fh fh; __u32 len; }; struct nfsd3_readres { - __u32 status; + __be32 status; struct svc_fh fh; unsigned long count; int eof; }; struct nfsd3_writeres { - __u32 status; + __be32 status; struct svc_fh fh; unsigned long count; int committed; }; struct nfsd3_renameres { - __u32 status; + __be32 status; struct svc_fh ffh; struct svc_fh tfh; }; struct nfsd3_linkres { - __u32 status; + __be32 status; struct svc_fh tfh; struct svc_fh fh; }; struct nfsd3_readdirres { - __u32 status; + __be32 status; struct svc_fh fh; int count; - __u32 verf[2]; + __be32 verf[2]; struct readdir_cd common; - u32 * buffer; + __be32 * buffer; int buflen; - u32 * offset; - u32 * offset1; + __be32 * offset; + __be32 * offset1; struct svc_rqst * rqstp; }; struct nfsd3_fsstatres { - __u32 status; + __be32 status; struct kstatfs stats; __u32 invarsec; }; struct nfsd3_fsinfores { - __u32 status; + __be32 status; __u32 f_rtmax; __u32 f_rtpref; __u32 f_rtmult; @@ -207,7 +207,7 @@ struct nfsd3_fsinfores { }; struct nfsd3_pathconfres { - __u32 status; + __be32 status; __u32 p_link_max; __u32 p_name_max; __u32 p_no_trunc; @@ -217,12 +217,12 @@ struct nfsd3_pathconfres { }; struct nfsd3_commitres { - __u32 status; + __be32 status; struct svc_fh fh; }; struct nfsd3_getaclres { - __u32 status; + __be32 status; struct svc_fh fh; int mask; struct posix_acl *acl_access; @@ -266,70 +266,70 @@ union nfsd3_xdrstore { #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) -int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); -int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *); +int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *, struct nfsd3_sattrargs *); -int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *, struct nfsd3_diropargs *); -int nfs3svc_decode_accessargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_accessargs(struct svc_rqst *, __be32 *, struct nfsd3_accessargs *); -int nfs3svc_decode_readargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_readargs(struct svc_rqst *, __be32 *, struct nfsd3_readargs *); -int nfs3svc_decode_writeargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_writeargs(struct svc_rqst *, __be32 *, struct nfsd3_writeargs *); -int nfs3svc_decode_createargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_createargs(struct svc_rqst *, __be32 *, struct nfsd3_createargs *); -int nfs3svc_decode_mkdirargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_mkdirargs(struct svc_rqst *, __be32 *, struct nfsd3_createargs *); -int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_mknodargs(struct svc_rqst *, __be32 *, struct nfsd3_mknodargs *); -int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_renameargs(struct svc_rqst *, __be32 *, struct nfsd3_renameargs *); -int nfs3svc_decode_readlinkargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_readlinkargs(struct svc_rqst *, __be32 *, struct nfsd3_readlinkargs *); -int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_linkargs(struct svc_rqst *, __be32 *, struct nfsd3_linkargs *); -int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *, struct nfsd3_symlinkargs *); -int nfs3svc_decode_readdirargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *, struct nfsd3_readdirargs *); -int nfs3svc_decode_readdirplusargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *, struct nfsd3_readdirargs *); -int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *, struct nfsd3_commitargs *); -int nfs3svc_encode_voidres(struct svc_rqst *, u32 *, void *); -int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *, +int nfs3svc_encode_voidres(struct svc_rqst *, __be32 *, void *); +int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *, struct nfsd3_attrstat *); -int nfs3svc_encode_wccstat(struct svc_rqst *, u32 *, +int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *, struct nfsd3_attrstat *); -int nfs3svc_encode_diropres(struct svc_rqst *, u32 *, +int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *, struct nfsd3_diropres *); -int nfs3svc_encode_accessres(struct svc_rqst *, u32 *, +int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *, struct nfsd3_accessres *); -int nfs3svc_encode_readlinkres(struct svc_rqst *, u32 *, +int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *, struct nfsd3_readlinkres *); -int nfs3svc_encode_readres(struct svc_rqst *, u32 *, struct nfsd3_readres *); -int nfs3svc_encode_writeres(struct svc_rqst *, u32 *, struct nfsd3_writeres *); -int nfs3svc_encode_createres(struct svc_rqst *, u32 *, +int nfs3svc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd3_readres *); +int nfs3svc_encode_writeres(struct svc_rqst *, __be32 *, struct nfsd3_writeres *); +int nfs3svc_encode_createres(struct svc_rqst *, __be32 *, struct nfsd3_diropres *); -int nfs3svc_encode_renameres(struct svc_rqst *, u32 *, +int nfs3svc_encode_renameres(struct svc_rqst *, __be32 *, struct nfsd3_renameres *); -int nfs3svc_encode_linkres(struct svc_rqst *, u32 *, +int nfs3svc_encode_linkres(struct svc_rqst *, __be32 *, struct nfsd3_linkres *); -int nfs3svc_encode_readdirres(struct svc_rqst *, u32 *, +int nfs3svc_encode_readdirres(struct svc_rqst *, __be32 *, struct nfsd3_readdirres *); -int nfs3svc_encode_fsstatres(struct svc_rqst *, u32 *, +int nfs3svc_encode_fsstatres(struct svc_rqst *, __be32 *, struct nfsd3_fsstatres *); -int nfs3svc_encode_fsinfores(struct svc_rqst *, u32 *, +int nfs3svc_encode_fsinfores(struct svc_rqst *, __be32 *, struct nfsd3_fsinfores *); -int nfs3svc_encode_pathconfres(struct svc_rqst *, u32 *, +int nfs3svc_encode_pathconfres(struct svc_rqst *, __be32 *, struct nfsd3_pathconfres *); -int nfs3svc_encode_commitres(struct svc_rqst *, u32 *, +int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *, struct nfsd3_commitres *); -int nfs3svc_release_fhandle(struct svc_rqst *, u32 *, +int nfs3svc_release_fhandle(struct svc_rqst *, __be32 *, struct nfsd3_attrstat *); -int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *, +int nfs3svc_release_fhandle2(struct svc_rqst *, __be32 *, struct nfsd3_fhandle_pair *); int nfs3svc_encode_entry(struct readdir_cd *, const char *name, int namlen, loff_t offset, ino_t ino, @@ -338,9 +338,9 @@ int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int); /* Helper functions for NFSv3 ACL code */ -u32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, +__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp); -u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp); +__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp); #endif /* _LINUX_NFSD_XDR3_H */ -- cgit v1.2.3 From 2ebbc012a9433a252be7ab4ce54e94bf7b21e506 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:58 -0700 Subject: [PATCH] xdr annotations: NFSv4 server Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfs4xdr.c | 66 +++++++++++++++++++++++------------------------ include/linux/nfsd/xdr4.h | 24 ++++++++--------- 3 files changed, 46 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 795ad6c5cb2c..ca6414248527 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -664,7 +664,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ static int nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify) { - u32 *buf, *p; + __be32 *buf, *p; int count; int status; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 77be0c4785e6..3419d99aeb1a 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -94,7 +94,7 @@ check_filename(char *str, int len, int err) * consistent with the style used in NFSv2/v3... */ #define DECODE_HEAD \ - u32 *p; \ + __be32 *p; \ int status #define DECODE_TAIL \ status = 0; \ @@ -144,13 +144,13 @@ xdr_error: \ } \ } while (0) -static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) +static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) { /* We want more bytes than seem to be available. * Maybe we need a new page, maybe we have just run out */ int avail = (char*)argp->end - (char*)argp->p; - u32 *p; + __be32 *p; if (avail + argp->pagelen < nbytes) return NULL; if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */ @@ -197,7 +197,7 @@ defer_free(struct nfsd4_compoundargs *argp, return 0; } -static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes) +static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) { void *new = NULL; if (p == argp->tmp) { @@ -951,8 +951,8 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) argp->pagelen -= len; } } - argp->end = (u32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len); - argp->p = (u32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2)); + argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len); + argp->p = (__be32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2)); argp->rqstp->rq_vec[v].iov_len = len; write->wr_vlen = v+1; @@ -1179,7 +1179,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define ENCODE_HEAD u32 *p +#define ENCODE_HEAD __be32 *p #define WRITE32(n) *p++ = htonl(n) #define WRITE64(n) do { \ @@ -1209,8 +1209,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) * Header routine to setup seqid operation replay cache */ #define ENCODE_SEQID_OP_HEAD \ - u32 *p; \ - u32 *save; \ + __be32 *p; \ + __be32 *save; \ \ save = resp->p; @@ -1235,10 +1235,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) * seperated @sep. */ static int nfsd4_encode_components(char sep, char *components, - u32 **pp, int *buflen) + __be32 **pp, int *buflen) { - u32 *p = *pp; - u32 *countp = p; + __be32 *p = *pp; + __be32 *countp = p; int strlen, count=0; char *str, *end; @@ -1272,10 +1272,10 @@ static int nfsd4_encode_components(char sep, char *components, * encode a location element of a fs_locations structure */ static int nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, - u32 **pp, int *buflen) + __be32 **pp, int *buflen) { int status; - u32 *p = *pp; + __be32 *p = *pp; status = nfsd4_encode_components(':', location->hosts, &p, buflen); if (status) @@ -1320,11 +1320,11 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, u32 *sta */ static int nfsd4_encode_fs_locations(struct svc_rqst *rqstp, struct svc_export *exp, - u32 **pp, int *buflen) + __be32 **pp, int *buflen) { u32 status; int i; - u32 *p = *pp; + __be32 *p = *pp; struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; char *root = nfsd4_path(rqstp, exp, &status); @@ -1355,7 +1355,7 @@ static u32 nfs4_ftypes[16] = { static int nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, - u32 **p, int *buflen) + __be32 **p, int *buflen) { int status; @@ -1376,20 +1376,20 @@ nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, } static inline int -nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen) +nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen) { return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen); } static inline int -nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, u32 **p, int *buflen) +nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen) { return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen); } static inline int nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, - u32 **p, int *buflen) + __be32 **p, int *buflen) { return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen); } @@ -1423,7 +1423,7 @@ static int fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) */ int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, - struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval, + struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, struct svc_rqst *rqstp) { u32 bmval0 = bmval[0]; @@ -1432,11 +1432,11 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, struct svc_fh tempfh; struct kstatfs statfs; int buflen = *countp << 2; - u32 *attrlenp; + __be32 *attrlenp; u32 dummy; u64 dummy64; u32 rdattr_err = 0; - u32 *p = buffer; + __be32 *p = buffer; int status; int aclsupport = 0; struct nfs4_acl *acl = NULL; @@ -1831,7 +1831,7 @@ out_serverfault: static int nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, - const char *name, int namlen, u32 *p, int *buflen) + const char *name, int namlen, __be32 *p, int *buflen) { struct svc_export *exp = cd->rd_fhp->fh_export; struct dentry *dentry; @@ -1864,10 +1864,10 @@ out_put: return nfserr; } -static u32 * -nfsd4_encode_rdattr_error(u32 *p, int buflen, int nfserr) +static __be32 * +nfsd4_encode_rdattr_error(__be32 *p, int buflen, int nfserr) { - u32 *attrlenp; + __be32 *attrlenp; if (buflen < 6) return NULL; @@ -1887,7 +1887,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, { struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); int buflen; - u32 *p = cd->buffer; + __be32 *p = cd->buffer; int nfserr = nfserr_toosmall; /* In nfsv4, "." and ".." never make it onto the wire.. */ @@ -2321,7 +2321,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re { int maxcount; loff_t offset; - u32 *page, *savep, *tailbase; + __be32 *page, *savep, *tailbase; ENCODE_HEAD; if (nfserr) @@ -2479,7 +2479,7 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_writ void nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) { - u32 *statp; + __be32 *statp; ENCODE_HEAD; RESERVE_SPACE(8); @@ -2617,7 +2617,7 @@ nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) */ int -nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy) +nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } @@ -2639,7 +2639,7 @@ void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args) } int -nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args) +nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) { int status; @@ -2660,7 +2660,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoun } int -nfs4svc_encode_compoundres(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundres *resp) +nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp) { /* * All that remains is to write the tag and operation count... diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index 66e642762a07..003193fe6fc6 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -258,9 +258,9 @@ struct nfsd4_readdir { struct svc_fh * rd_fhp; /* response */ struct readdir_cd common; - u32 * buffer; + __be32 * buffer; int buflen; - u32 * offset; + __be32 * offset; }; struct nfsd4_release_lockowner { @@ -371,12 +371,12 @@ struct nfsd4_op { struct nfsd4_compoundargs { /* scratch variables for XDR decode */ - u32 * p; - u32 * end; + __be32 * p; + __be32 * end; struct page ** pagelist; int pagelen; - u32 tmp[8]; - u32 * tmpp; + __be32 tmp[8]; + __be32 * tmpp; struct tmpbuf { struct tmpbuf *next; void (*release)(const void *); @@ -395,15 +395,15 @@ struct nfsd4_compoundargs { struct nfsd4_compoundres { /* scratch variables for XDR encode */ - u32 * p; - u32 * end; + __be32 * p; + __be32 * end; struct xdr_buf * xbuf; struct svc_rqst * rqstp; u32 taglen; char * tag; u32 opcnt; - u32 * tagp; /* where to encode tag and opcount */ + __be32 * tagp; /* where to encode tag and opcount */ }; #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) @@ -419,10 +419,10 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec; } -int nfs4svc_encode_voidres(struct svc_rqst *, u32 *, void *); -int nfs4svc_decode_compoundargs(struct svc_rqst *, u32 *, +int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); +int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *, struct nfsd4_compoundargs *); -int nfs4svc_encode_compoundres(struct svc_rqst *, u32 *, +int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, struct nfsd4_compoundres *); void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); -- cgit v1.2.3 From 6264d69d7df654ca64f625e9409189a0e50734e9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:58 -0700 Subject: [PATCH] nfsd: vfs.c endianness annotations don't use the same variable to store NFS and host error values Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/vfs.c | 299 ++++++++++++++++++++++++---------------------- include/linux/nfsd/nfsd.h | 38 +++--- 2 files changed, 176 insertions(+), 161 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 1141bd29e4e3..f21e917bb8ed 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -110,7 +110,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, struct dentry *dentry = *dpp; struct vfsmount *mnt = mntget(exp->ex_mnt); struct dentry *mounts = dget(dentry); - int err = nfs_ok; + int err = 0; while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); @@ -148,14 +148,15 @@ out: * clients and is explicitly disallowed for NFSv3 * NeilBrown */ -int +__be32 nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, int len, struct svc_fh *resfh) { struct svc_export *exp; struct dentry *dparent; struct dentry *dentry; - int err; + __be32 err; + int host_err; dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); @@ -193,7 +194,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, exp2 = exp_parent(exp->ex_client, mnt, dentry, &rqstp->rq_chandle); if (IS_ERR(exp2)) { - err = PTR_ERR(exp2); + host_err = PTR_ERR(exp2); dput(dentry); mntput(mnt); goto out_nfserr; @@ -210,14 +211,14 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, } else { fh_lock(fhp); dentry = lookup_one_len(name, dparent, len); - err = PTR_ERR(dentry); + host_err = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_nfserr; /* * check if we have crossed a mount point ... */ if (d_mountpoint(dentry)) { - if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { + if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { dput(dentry); goto out_nfserr; } @@ -236,7 +237,7 @@ out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } @@ -244,7 +245,7 @@ out_nfserr: * Set various file attributes. * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, int check_guard, time_t guardtime) { @@ -253,7 +254,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, int accmode = MAY_SATTR; int ftype = 0; int imode; - int err; + __be32 err; + int host_err; int size_change = 0; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) @@ -319,19 +321,19 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, * If we are changing the size of the file, then * we need to break all leases. */ - err = break_lease(inode, FMODE_WRITE | O_NONBLOCK); - if (err == -EWOULDBLOCK) - err = -ETIMEDOUT; - if (err) /* ENOMEM or EWOULDBLOCK */ + host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK); + if (host_err == -EWOULDBLOCK) + host_err = -ETIMEDOUT; + if (host_err) /* ENOMEM or EWOULDBLOCK */ goto out_nfserr; - err = get_write_access(inode); - if (err) + host_err = get_write_access(inode); + if (host_err) goto out_nfserr; size_change = 1; - err = locks_verify_truncate(inode, NULL, iap->ia_size); - if (err) { + host_err = locks_verify_truncate(inode, NULL, iap->ia_size); + if (host_err) { put_write_access(inode); goto out_nfserr; } @@ -357,8 +359,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, err = nfserr_notsync; if (!check_guard || guardtime == inode->i_ctime.tv_sec) { fh_lock(fhp); - err = notify_change(dentry, iap); - err = nfserrno(err); + host_err = notify_change(dentry, iap); + err = nfserrno(host_err); fh_unlock(fhp); } if (size_change) @@ -370,7 +372,7 @@ out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } @@ -420,11 +422,12 @@ out: return error; } -int +__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_acl *acl) { - int error; + __be32 error; + int host_error; struct dentry *dentry; struct inode *inode; struct posix_acl *pacl = NULL, *dpacl = NULL; @@ -440,20 +443,20 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, if (S_ISDIR(inode->i_mode)) flags = NFS4_ACL_DIR; - error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); - if (error == -EINVAL) { + host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); + if (host_error == -EINVAL) { error = nfserr_attrnotsupp; goto out; - } else if (error < 0) + } else if (host_error < 0) goto out_nfserr; - error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); - if (error < 0) + host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); + if (host_error < 0) goto out_nfserr; if (S_ISDIR(inode->i_mode)) { - error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); - if (error < 0) + host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); + if (host_error < 0) goto out_nfserr; } @@ -464,7 +467,7 @@ out: posix_acl_release(dpacl); return (error); out_nfserr: - error = nfserrno(error); + error = nfserrno(host_error); goto out; } @@ -571,14 +574,14 @@ static struct accessmap nfs3_anyaccess[] = { { 0, 0 } }; -int +__be32 nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported) { struct accessmap *map; struct svc_export *export; struct dentry *dentry; u32 query, result = 0, sresult = 0; - unsigned int error; + __be32 error; error = fh_verify(rqstp, fhp, 0, MAY_NOP); if (error) @@ -598,7 +601,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor query = *access; for (; map->access; map++) { if (map->access & query) { - unsigned int err2; + __be32 err2; sresult |= map->access; @@ -637,13 +640,15 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor * The access argument indicates the type of open (read/write/lock) * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access, struct file **filp) { struct dentry *dentry; struct inode *inode; - int flags = O_RDONLY|O_LARGEFILE, err; + int flags = O_RDONLY|O_LARGEFILE; + __be32 err; + int host_err; /* * If we get here, then the client has already done an "open", @@ -673,10 +678,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, * Check to see if there are any leases on this file. * This may block while leases are broken. */ - err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0)); - if (err == -EWOULDBLOCK) - err = -ETIMEDOUT; - if (err) /* NOMEM or WOULDBLOCK */ + host_err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0)); + if (host_err == -EWOULDBLOCK) + host_err = -ETIMEDOUT; + if (host_err) /* NOMEM or WOULDBLOCK */ goto out_nfserr; if (access & MAY_WRITE) { @@ -689,10 +694,9 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, } *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags); if (IS_ERR(*filp)) - err = PTR_ERR(*filp); + host_err = PTR_ERR(*filp); out_nfserr: - if (err) - err = nfserrno(err); + err = nfserrno(host_err); out: return err; } @@ -830,14 +834,15 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset return size; } -static int +static __be32 nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long *count) { struct inode *inode; struct raparms *ra; mm_segment_t oldfs; - int err; + __be32 err; + int host_err; err = nfserr_perm; inode = file->f_dentry->d_inode; @@ -855,12 +860,12 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (file->f_op->sendfile && rqstp->rq_sendfile_ok) { rqstp->rq_resused = 1; - err = file->f_op->sendfile(file, &offset, *count, + host_err = file->f_op->sendfile(file, &offset, *count, nfsd_read_actor, rqstp); } else { oldfs = get_fs(); set_fs(KERNEL_DS); - err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset); + host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset); set_fs(oldfs); } @@ -874,13 +879,13 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, spin_unlock(&rab->pb_lock); } - if (err >= 0) { - nfsdstats.io_read += err; - *count = err; + if (host_err >= 0) { + nfsdstats.io_read += host_err; + *count = host_err; err = 0; fsnotify_access(file->f_dentry); } else - err = nfserrno(err); + err = nfserrno(host_err); out: return err; } @@ -895,7 +900,7 @@ static void kill_suid(struct dentry *dentry) mutex_unlock(&dentry->d_inode->i_mutex); } -static int +static __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, int *stablep) @@ -904,7 +909,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, struct dentry *dentry; struct inode *inode; mm_segment_t oldfs; - int err = 0; + __be32 err = 0; + int host_err; int stable = *stablep; #ifdef MSNFS @@ -940,18 +946,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, /* Write the data. */ oldfs = get_fs(); set_fs(KERNEL_DS); - err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); + host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); set_fs(oldfs); - if (err >= 0) { + if (host_err >= 0) { nfsdstats.io_write += cnt; fsnotify_modify(file->f_dentry); } /* clear setuid/setgid flag after write */ - if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) + if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) kill_suid(dentry); - if (err >= 0 && stable) { + if (host_err >= 0 && stable) { static ino_t last_ino; static dev_t last_dev; @@ -977,7 +983,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (inode->i_state & I_DIRTY) { dprintk("nfsd: write sync %d\n", current->pid); - err=nfsd_sync(file); + host_err=nfsd_sync(file); } #if 0 wake_up(&inode->i_wait); @@ -987,11 +993,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, last_dev = inode->i_sb->s_dev; } - dprintk("nfsd: write complete err=%d\n", err); - if (err >= 0) + dprintk("nfsd: write complete host_err=%d\n", host_err); + if (host_err >= 0) err = 0; else - err = nfserrno(err); + err = nfserrno(host_err); out: return err; } @@ -1001,12 +1007,12 @@ out: * on entry. On return, *count contains the number of bytes actually read. * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long *count) { - int err; + __be32 err; if (file) { err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, @@ -1030,12 +1036,12 @@ out: * The stable flag requests synchronous writes. * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, int *stablep) { - int err = 0; + __be32 err = 0; if (file) { err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, @@ -1067,12 +1073,12 @@ out: * Unfortunately we cannot lock the file to make sure we return full WCC * data to the client, as locking happens lower down in the filesystem. */ -int +__be32 nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, unsigned long count) { struct file *file; - int err; + __be32 err; if ((u64)count > ~(u64)offset) return nfserr_inval; @@ -1100,14 +1106,15 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, * * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp */ -int +__be32 nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, struct iattr *iap, int type, dev_t rdev, struct svc_fh *resfhp) { struct dentry *dentry, *dchild = NULL; struct inode *dirp; - int err; + __be32 err; + int host_err; err = nfserr_perm; if (!flen) @@ -1134,7 +1141,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ fh_lock_nested(fhp, I_MUTEX_PARENT); dchild = lookup_one_len(fname, dentry, flen); - err = PTR_ERR(dchild); + host_err = PTR_ERR(dchild); if (IS_ERR(dchild)) goto out_nfserr; err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); @@ -1173,22 +1180,22 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_perm; switch (type) { case S_IFREG: - err = vfs_create(dirp, dchild, iap->ia_mode, NULL); + host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); break; case S_IFDIR: - err = vfs_mkdir(dirp, dchild, iap->ia_mode); + host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); break; case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); + host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); break; default: printk("nfsd: bad file type %o in nfsd_create\n", type); - err = -EINVAL; + host_err = -EINVAL; } - if (err < 0) + if (host_err < 0) goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) { @@ -1203,7 +1210,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, * directories via NFS. */ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) { - int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); + __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); if (err2) err = err2; } @@ -1218,7 +1225,7 @@ out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } @@ -1226,7 +1233,7 @@ out_nfserr: /* * NFSv3 version of nfsd_create */ -int +__be32 nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, struct iattr *iap, struct svc_fh *resfhp, int createmode, u32 *verifier, @@ -1234,7 +1241,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, { struct dentry *dentry, *dchild = NULL; struct inode *dirp; - int err; + __be32 err; + int host_err; __u32 v_mtime=0, v_atime=0; int v_mode=0; @@ -1264,7 +1272,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, * Compose the response file handle. */ dchild = lookup_one_len(fname, dentry, flen); - err = PTR_ERR(dchild); + host_err = PTR_ERR(dchild); if (IS_ERR(dchild)) goto out_nfserr; @@ -1320,8 +1328,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; } - err = vfs_create(dirp, dchild, iap->ia_mode, NULL); - if (err < 0) + host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); + if (host_err < 0) goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) { @@ -1350,7 +1358,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, */ set_attr: if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) { - int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); + __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); if (err2) err = err2; } @@ -1368,7 +1376,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } #endif /* CONFIG_NFSD_V3 */ @@ -1378,13 +1386,14 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, * fits into the buffer. On return, it contains the true length. * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) { struct dentry *dentry; struct inode *inode; mm_segment_t oldfs; - int err; + __be32 err; + int host_err; err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP); if (err) @@ -1403,18 +1412,18 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) */ oldfs = get_fs(); set_fs(KERNEL_DS); - err = inode->i_op->readlink(dentry, buf, *lenp); + host_err = inode->i_op->readlink(dentry, buf, *lenp); set_fs(oldfs); - if (err < 0) + if (host_err < 0) goto out_nfserr; - *lenp = err; + *lenp = host_err; err = 0; out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } @@ -1422,7 +1431,7 @@ out_nfserr: * Create a symlink and look up its inode * N.B. After this call _both_ fhp and resfhp need an fh_put */ -int +__be32 nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, char *path, int plen, @@ -1430,7 +1439,8 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) { struct dentry *dentry, *dnew; - int err, cerr; + __be32 err, cerr; + int host_err; umode_t mode; err = nfserr_noent; @@ -1446,7 +1456,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, fh_lock(fhp); dentry = fhp->fh_dentry; dnew = lookup_one_len(fname, dentry, flen); - err = PTR_ERR(dnew); + host_err = PTR_ERR(dnew); if (IS_ERR(dnew)) goto out_nfserr; @@ -1458,21 +1468,21 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, if (unlikely(path[plen] != 0)) { char *path_alloced = kmalloc(plen+1, GFP_KERNEL); if (path_alloced == NULL) - err = -ENOMEM; + host_err = -ENOMEM; else { strncpy(path_alloced, path, plen); path_alloced[plen] = 0; - err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode); + host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode); kfree(path_alloced); } } else - err = vfs_symlink(dentry->d_inode, dnew, path, mode); + host_err = vfs_symlink(dentry->d_inode, dnew, path, mode); - if (!err) + if (!host_err) { if (EX_ISSYNC(fhp->fh_export)) - err = nfsd_sync_dir(dentry); - if (err) - err = nfserrno(err); + host_err = nfsd_sync_dir(dentry); + } + err = nfserrno(host_err); fh_unlock(fhp); cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); @@ -1482,7 +1492,7 @@ out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } @@ -1490,13 +1500,14 @@ out_nfserr: * Create a hardlink * N.B. After this call _both_ ffhp and tfhp need an fh_put */ -int +__be32 nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *name, int len, struct svc_fh *tfhp) { struct dentry *ddir, *dnew, *dold; struct inode *dirp, *dest; - int err; + __be32 err; + int host_err; err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE); if (err) @@ -1517,24 +1528,25 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, dirp = ddir->d_inode; dnew = lookup_one_len(name, ddir, len); - err = PTR_ERR(dnew); + host_err = PTR_ERR(dnew); if (IS_ERR(dnew)) goto out_nfserr; dold = tfhp->fh_dentry; dest = dold->d_inode; - err = vfs_link(dold, dirp, dnew); - if (!err) { + host_err = vfs_link(dold, dirp, dnew); + if (!host_err) { if (EX_ISSYNC(ffhp->fh_export)) { err = nfserrno(nfsd_sync_dir(ddir)); write_inode_now(dest, 1); } + err = 0; } else { - if (err == -EXDEV && rqstp->rq_vers == 2) + if (host_err == -EXDEV && rqstp->rq_vers == 2) err = nfserr_acces; else - err = nfserrno(err); + err = nfserrno(host_err); } dput(dnew); @@ -1544,7 +1556,7 @@ out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out_unlock; } @@ -1552,13 +1564,14 @@ out_nfserr: * Rename a file * N.B. After this call _both_ ffhp and tfhp need an fh_put */ -int +__be32 nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, struct svc_fh *tfhp, char *tname, int tlen) { struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap; struct inode *fdir, *tdir; - int err; + __be32 err; + int host_err; err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE); if (err) @@ -1589,22 +1602,22 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, fill_pre_wcc(tfhp); odentry = lookup_one_len(fname, fdentry, flen); - err = PTR_ERR(odentry); + host_err = PTR_ERR(odentry); if (IS_ERR(odentry)) goto out_nfserr; - err = -ENOENT; + host_err = -ENOENT; if (!odentry->d_inode) goto out_dput_old; - err = -EINVAL; + host_err = -EINVAL; if (odentry == trap) goto out_dput_old; ndentry = lookup_one_len(tname, tdentry, tlen); - err = PTR_ERR(ndentry); + host_err = PTR_ERR(ndentry); if (IS_ERR(ndentry)) goto out_dput_old; - err = -ENOTEMPTY; + host_err = -ENOTEMPTY; if (ndentry == trap) goto out_dput_new; @@ -1612,14 +1625,14 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && ((atomic_read(&odentry->d_count) > 1) || (atomic_read(&ndentry->d_count) > 1))) { - err = -EPERM; + host_err = -EPERM; } else #endif - err = vfs_rename(fdir, odentry, tdir, ndentry); - if (!err && EX_ISSYNC(tfhp->fh_export)) { - err = nfsd_sync_dir(tdentry); - if (!err) - err = nfsd_sync_dir(fdentry); + host_err = vfs_rename(fdir, odentry, tdir, ndentry); + if (!host_err && EX_ISSYNC(tfhp->fh_export)) { + host_err = nfsd_sync_dir(tdentry); + if (!host_err) + host_err = nfsd_sync_dir(fdentry); } out_dput_new: @@ -1627,8 +1640,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, out_dput_old: dput(odentry); out_nfserr: - if (err) - err = nfserrno(err); + err = nfserrno(host_err); /* we cannot reply on fh_unlock on the two filehandles, * as that would do the wrong thing if the two directories @@ -1647,13 +1659,14 @@ out: * Unlink a file or directory * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, char *fname, int flen) { struct dentry *dentry, *rdentry; struct inode *dirp; - int err; + __be32 err; + int host_err; err = nfserr_acces; if (!flen || isdotent(fname, flen)) @@ -1667,7 +1680,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, dirp = dentry->d_inode; rdentry = lookup_one_len(fname, dentry, flen); - err = PTR_ERR(rdentry); + host_err = PTR_ERR(rdentry); if (IS_ERR(rdentry)) goto out_nfserr; @@ -1684,22 +1697,23 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, #ifdef MSNFS if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && (atomic_read(&rdentry->d_count) > 1)) { - err = -EPERM; + host_err = -EPERM; } else #endif - err = vfs_unlink(dirp, rdentry); + host_err = vfs_unlink(dirp, rdentry); } else { /* It's RMDIR */ - err = vfs_rmdir(dirp, rdentry); + host_err = vfs_rmdir(dirp, rdentry); } dput(rdentry); - if (err == 0 && - EX_ISSYNC(fhp->fh_export)) - err = nfsd_sync_dir(dentry); + if (host_err) + goto out_nfserr; + if (EX_ISSYNC(fhp->fh_export)) + host_err = nfsd_sync_dir(dentry); out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); out: return err; } @@ -1708,11 +1722,12 @@ out: * Read entries from a directory. * The NFSv3/4 verifier we ignore for now. */ -int +__be32 nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, struct readdir_cd *cdp, encode_dent_fn func) { - int err; + __be32 err; + int host_err; struct file *file; loff_t offset = *offsetp; @@ -1734,10 +1749,10 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, do { cdp->err = nfserr_eof; /* will be cleared on successful read */ - err = vfs_readdir(file, (filldir_t) func, cdp); - } while (err >=0 && cdp->err == nfs_ok); - if (err) - err = nfserrno(err); + host_err = vfs_readdir(file, (filldir_t) func, cdp); + } while (host_err >=0 && cdp->err == nfs_ok); + if (host_err) + err = nfserrno(host_err); else err = cdp->err; *offsetp = vfs_llseek(file, 0, 1); @@ -1754,10 +1769,10 @@ out: * Get file system stats * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) { - int err = fh_verify(rqstp, fhp, 0, MAY_NOP); + __be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP); if (!err && vfs_statfs(fhp->fh_dentry,stat)) err = nfserr_io; return err; @@ -1766,7 +1781,7 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) /* * Check for a user's access permissions to this inode. */ -int +__be32 nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) { struct inode *inode = dentry->d_inode; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 2f75160a5824..19a3c83d496e 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -72,57 +72,57 @@ int nfsd_racache_init(int); void nfsd_racache_shutdown(void); int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, struct svc_export **expp); -int nfsd_lookup(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *, const char *, int, struct svc_fh *); -int nfsd_setattr(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *, struct iattr *, int, time_t); #ifdef CONFIG_NFSD_V4 -int nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, +__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, struct nfs4_acl *); int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); #endif /* CONFIG_NFSD_V4 */ -int nfsd_create(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, int type, dev_t rdev, struct svc_fh *res); #ifdef CONFIG_NFSD_V3 -int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); -int nfsd_create_v3(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); +__be32 nfsd_create_v3(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, struct svc_fh *res, int createmode, u32 *verifier, int *truncp); -int nfsd_commit(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, loff_t, unsigned long); #endif /* CONFIG_NFSD_V3 */ -int nfsd_open(struct svc_rqst *, struct svc_fh *, int, +__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int, int, struct file **); void nfsd_close(struct file *); -int nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *, +__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *, loff_t, struct kvec *, int, unsigned long *); -int nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *, +__be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *, loff_t, struct kvec *,int, unsigned long, int *); -int nfsd_readlink(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *, char *, int *); -int nfsd_symlink(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *, char *name, int len, char *path, int plen, struct svc_fh *res, struct iattr *); -int nfsd_link(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_link(struct svc_rqst *, struct svc_fh *, char *, int, struct svc_fh *); -int nfsd_rename(struct svc_rqst *, +__be32 nfsd_rename(struct svc_rqst *, struct svc_fh *, char *, int, struct svc_fh *, char *, int); -int nfsd_remove(struct svc_rqst *, +__be32 nfsd_remove(struct svc_rqst *, struct svc_fh *, char *, int); -int nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, +__be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, char *name, int len); int nfsd_truncate(struct svc_rqst *, struct svc_fh *, unsigned long size); -int nfsd_readdir(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, loff_t *, struct readdir_cd *, encode_dent_fn); -int nfsd_statfs(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, struct kstatfs *); int nfsd_notify_change(struct inode *, struct iattr *); -int nfsd_permission(struct svc_export *, struct dentry *, int); +__be32 nfsd_permission(struct svc_export *, struct dentry *, int); int nfsd_sync_dir(struct dentry *dp); #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) -- cgit v1.2.3 From b37ad28bcaa7c486a4ff0fb6c3bdaaacd67b86ce Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:59 -0700 Subject: [PATCH] nfsd: nfs4 code returns error values in net-endian Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4proc.c | 82 ++++++++++++------------- fs/nfsd/nfs4recover.c | 14 ++--- fs/nfsd/nfs4state.c | 96 ++++++++++++++--------------- fs/nfsd/nfs4xdr.c | 150 ++++++++++++++++++++++----------------------- include/linux/nfsd/state.h | 10 +-- include/linux/nfsd/xdr4.h | 30 ++++----- 6 files changed, 191 insertions(+), 191 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index ca6414248527..63823945f972 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -67,10 +67,10 @@ fh_dup2(struct svc_fh *dst, struct svc_fh *src) *dst = *src; } -static int +static __be32 do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode) { - int status; + __be32 status; if (open->op_truncate && !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) @@ -88,11 +88,11 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs return status; } -static int +static __be32 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) { struct svc_fh resfh; - int status; + __be32 status; fh_init(&resfh, NFS4_FHSIZE); open->op_truncate = 0; @@ -131,10 +131,10 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o return status; } -static int +static __be32 do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) { - int status; + __be32 status; /* Only reclaims from previously confirmed clients are valid */ if ((status = nfs4_check_open_reclaim(&open->op_clientid))) @@ -161,10 +161,10 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ } -static inline int +static inline __be32 nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner) { - int status; + __be32 status; dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", (int)open->op_fname.len, open->op_fname.data, open->op_stateowner); @@ -261,7 +261,7 @@ out: /* * filehandle-manipulating ops. */ -static inline int +static inline __be32 nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh) { if (!current_fh->fh_dentry) @@ -271,7 +271,7 @@ nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh) return nfs_ok; } -static inline int +static inline __be32 nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh) { fh_put(current_fh); @@ -280,10 +280,10 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putf return fh_verify(rqstp, current_fh, 0, MAY_NOP); } -static inline int +static inline __be32 nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh) { - int status; + __be32 status; fh_put(current_fh); status = exp_pseudoroot(rqstp->rq_client, current_fh, @@ -291,7 +291,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh) return status; } -static inline int +static inline __be32 nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh) { if (!save_fh->fh_dentry) @@ -301,7 +301,7 @@ nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh) return nfs_ok; } -static inline int +static inline __be32 nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh) { if (!current_fh->fh_dentry) @@ -314,7 +314,7 @@ nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh) /* * misc nfsv4 ops */ -static inline int +static inline __be32 nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access) { if (access->ac_req_access & ~NFS3_ACCESS_FULL) @@ -324,10 +324,10 @@ nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_acc return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported); } -static inline int +static inline __be32 nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit) { - int status; + __be32 status; u32 *p = (u32 *)commit->co_verf.data; *p++ = nfssvc_boot.tv_sec; @@ -339,11 +339,11 @@ nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_com return status; } -static int +static __be32 nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create) { struct svc_fh resfh; - int status; + __be32 status; dev_t rdev; fh_init(&resfh, NFS4_FHSIZE); @@ -423,10 +423,10 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre return status; } -static inline int +static inline __be32 nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr) { - int status; + __be32 status; status = fh_verify(rqstp, current_fh, 0, MAY_NOP); if (status) @@ -442,11 +442,11 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ge return nfs_ok; } -static inline int +static inline __be32 nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct svc_fh *save_fh, struct nfsd4_link *link) { - int status = nfserr_nofilehandle; + __be32 status = nfserr_nofilehandle; if (!save_fh->fh_dentry) return status; @@ -456,11 +456,11 @@ nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh, return status; } -static int +static __be32 nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) { struct svc_fh tmp_fh; - int ret; + __be32 ret; fh_init(&tmp_fh, NFS4_FHSIZE); if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, @@ -474,16 +474,16 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh); } -static inline int +static inline __be32 nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup) { return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh); } -static inline int +static inline __be32 nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) { - int status; + __be32 status; /* no need to check permission - this will be done in nfsd_read() */ @@ -508,7 +508,7 @@ out: return status; } -static inline int +static inline __be32 nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir) { u64 cookie = readdir->rd_cookie; @@ -531,7 +531,7 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_re return nfs_ok; } -static inline int +static inline __be32 nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readlink *readlink) { readlink->rl_rqstp = rqstp; @@ -539,10 +539,10 @@ nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_r return nfs_ok; } -static inline int +static inline __be32 nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_remove *remove) { - int status; + __be32 status; if (nfs4_in_grace()) return nfserr_grace; @@ -556,11 +556,11 @@ nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_rem return status; } -static inline int +static inline __be32 nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct svc_fh *save_fh, struct nfsd4_rename *rename) { - int status = nfserr_nofilehandle; + __be32 status = nfserr_nofilehandle; if (!save_fh->fh_dentry) return status; @@ -589,10 +589,10 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, return status; } -static inline int +static inline __be32 nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr) { - int status = nfs_ok; + __be32 status = nfs_ok; if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { nfs4_lock_state(); @@ -614,13 +614,13 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se return status; } -static inline int +static inline __be32 nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write) { stateid_t *stateid = &write->wr_stateid; struct file *filp = NULL; u32 *p; - int status = nfs_ok; + __be32 status = nfs_ok; /* no need to check permission - this will be done in nfsd_write() */ @@ -661,12 +661,12 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ * attributes matched. VERIFY is implemented by mapping NFSERR_SAME * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. */ -static int +static __be32 nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify) { __be32 *buf, *p; int count; - int status; + __be32 status; status = fh_verify(rqstp, current_fh, 0, MAY_NOP); if (status) @@ -741,7 +741,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, struct svc_fh *save_fh = NULL; struct nfs4_stateowner *replay_owner = NULL; int slack_space; /* in words, not bytes! */ - int status; + __be32 status; status = nfserr_resource; current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL); diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 1cbd2e4ee122..e9d07704680e 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -83,13 +83,13 @@ md5_to_hex(char *out, char *md5) *out = '\0'; } -int +__be32 nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) { struct xdr_netobj cksum; struct hash_desc desc; struct scatterlist sg[1]; - int status = nfserr_resource; + __be32 status = nfserr_resource; dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", clname->len, clname->data); @@ -193,7 +193,7 @@ nfsd4_build_dentrylist(void *arg, const char *name, int namlen, struct dentry_list *child; if (name && isdotent(name, namlen)) - return nfs_ok; + return 0; dentry = lookup_one_len(name, parent, namlen); if (IS_ERR(dentry)) return PTR_ERR(dentry); @@ -333,14 +333,14 @@ purge_old(struct dentry *parent, struct dentry *child) int status; if (nfs4_has_reclaimed_state(child->d_name.name)) - return nfs_ok; + return 0; status = nfsd4_clear_clid_dir(parent, child); if (status) printk("failed to remove client recovery directory %s\n", child->d_name.name); /* Keep trying, success or failure: */ - return nfs_ok; + return 0; } void @@ -365,10 +365,10 @@ load_recdir(struct dentry *parent, struct dentry *child) printk("nfsd4: illegal name %s in recovery directory\n", child->d_name.name); /* Keep trying; maybe the others are OK: */ - return nfs_ok; + return 0; } nfs4_client_to_reclaim(child->d_name.name); - return nfs_ok; + return 0; } int diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ebcf226a9e4a..e5ca6d7028df 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -710,7 +710,7 @@ out_err: * as described above. * */ -int +__be32 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) { u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; @@ -721,7 +721,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) nfs4_verifier clverifier = setclid->se_verf; unsigned int strhashval; struct nfs4_client *conf, *unconf, *new; - int status; + __be32 status; char dname[HEXDIR_LEN]; if (!check_name(clname)) @@ -875,14 +875,14 @@ out: * * NOTE: callback information will be processed here in a future patch */ -int +__be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm) { u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; struct nfs4_client *conf, *unconf; nfs4_verifier confirm = setclientid_confirm->sc_confirm; clientid_t * clid = &setclientid_confirm->sc_clientid; - int status; + __be32 status; if (STALE_CLIENTID(clid)) return nfserr_stale_clientid; @@ -1280,13 +1280,13 @@ test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { * Called to check deny when READ with all zero stateid or * WRITE with all zero or all one stateid */ -static int +static __be32 nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) { struct inode *ino = current_fh->fh_dentry->d_inode; struct nfs4_file *fp; struct nfs4_stateid *stp; - int ret; + __be32 ret; dprintk("NFSD: nfs4_share_conflict\n"); @@ -1444,7 +1444,7 @@ static struct lock_manager_operations nfsd_lease_mng_ops = { }; -int +__be32 nfsd4_process_open1(struct nfsd4_open *open) { clientid_t *clientid = &open->op_clientid; @@ -1501,7 +1501,7 @@ renew: return nfs_ok; } -static inline int +static inline __be32 nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) { if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) @@ -1522,12 +1522,12 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid) return NULL; } -static int +static __be32 nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_delegation **dp) { int flags; - int status = nfserr_bad_stateid; + __be32 status = nfserr_bad_stateid; *dp = find_delegation_file(fp, &open->op_delegate_stateid); if (*dp == NULL) @@ -1546,11 +1546,11 @@ out: return nfs_ok; } -static int +static __be32 nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp) { struct nfs4_stateid *local; - int status = nfserr_share_denied; + __be32 status = nfserr_share_denied; struct nfs4_stateowner *sop = open->op_stateowner; list_for_each_entry(local, &fp->fi_stateids, st_perfile) { @@ -1575,7 +1575,7 @@ nfs4_alloc_stateid(void) return kmem_cache_alloc(stateid_slab, GFP_KERNEL); } -static int +static __be32 nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, struct nfs4_delegation *dp, struct svc_fh *cur_fh, int flags) @@ -1590,7 +1590,7 @@ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, get_file(dp->dl_vfs_file); stp->st_vfs_file = dp->dl_vfs_file; } else { - int status; + __be32 status; status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, &stp->st_vfs_file); if (status) { @@ -1604,7 +1604,7 @@ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, return 0; } -static inline int +static inline __be32 nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, struct nfsd4_open *open) { @@ -1619,22 +1619,22 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); } -static int +static __be32 nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) { struct file *filp = stp->st_vfs_file; struct inode *inode = filp->f_dentry->d_inode; unsigned int share_access, new_writer; - int status; + __be32 status; set_access(&share_access, stp->st_access_bmap); new_writer = (~share_access) & open->op_share_access & NFS4_SHARE_ACCESS_WRITE; if (new_writer) { - status = get_write_access(inode); - if (status) - return nfserrno(status); + int err = get_write_access(inode); + if (err) + return nfserrno(err); } status = nfsd4_truncate(rqstp, cur_fh, open); if (status) { @@ -1738,14 +1738,14 @@ out: /* * called with nfs4_lock_state() held. */ -int +__be32 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) { struct nfs4_file *fp = NULL; struct inode *ino = current_fh->fh_dentry->d_inode; struct nfs4_stateid *stp = NULL; struct nfs4_delegation *dp = NULL; - int status; + __be32 status; status = nfserr_inval; if (!access_valid(open->op_share_access) @@ -1833,11 +1833,11 @@ static struct work_struct laundromat_work; static void laundromat_main(void *); static DECLARE_WORK(laundromat_work, laundromat_main, NULL); -int +__be32 nfsd4_renew(clientid_t *clid) { struct nfs4_client *clp; - int status; + __be32 status; nfs4_lock_state(); dprintk("process_renew(%08x/%08x): starting\n", @@ -1996,9 +1996,9 @@ access_permit_write(unsigned long access_bmap) } static -int nfs4_check_openmode(struct nfs4_stateid *stp, int flags) +__be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags) { - int status = nfserr_openmode; + __be32 status = nfserr_openmode; if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) goto out; @@ -2009,7 +2009,7 @@ out: return status; } -static inline int +static inline __be32 check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) { /* Trying to call delegreturn with a special stateid? Yuch: */ @@ -2043,14 +2043,14 @@ io_during_grace_disallowed(struct inode *inode, int flags) /* * Checks for stateid operations */ -int +__be32 nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filpp) { struct nfs4_stateid *stp = NULL; struct nfs4_delegation *dp = NULL; stateid_t *stidp; struct inode *ino = current_fh->fh_dentry->d_inode; - int status; + __be32 status; dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n", stateid->si_boot, stateid->si_stateownerid, @@ -2125,7 +2125,7 @@ setlkflg (int type) /* * Checks for sequence id mutating operations. */ -static int +static __be32 nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock) { struct nfs4_stateid *stp; @@ -2169,7 +2169,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei clientid_t *lockclid = &lock->v.new.clientid; struct nfs4_client *clp = sop->so_client; int lkflg = 0; - int status; + __be32 status; lkflg = setlkflg(lock->lk_type); @@ -2241,10 +2241,10 @@ check_replay: return nfserr_bad_seqid; } -int +__be32 nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner) { - int status; + __be32 status; struct nfs4_stateowner *sop; struct nfs4_stateid *stp; @@ -2310,10 +2310,10 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) } } -int +__be32 nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner) { - int status; + __be32 status; struct nfs4_stateid *stp; unsigned int share_access; @@ -2365,10 +2365,10 @@ out: /* * nfs4_unlock_state() called after encode */ -int +__be32 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner) { - int status; + __be32 status; struct nfs4_stateid *stp; dprintk("NFSD: nfsd4_close on file %.*s\n", @@ -2404,10 +2404,10 @@ out: return status; } -int +__be32 nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr) { - int status; + __be32 status; if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) goto out; @@ -2635,7 +2635,7 @@ check_lock_length(u64 offset, u64 length) /* * LOCK operation */ -int +__be32 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner) { struct nfs4_stateowner *open_sop = NULL; @@ -2644,7 +2644,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock struct file *filp; struct file_lock file_lock; struct file_lock conflock; - int status = 0; + __be32 status = 0; unsigned int strhashval; dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", @@ -2793,14 +2793,14 @@ out: /* * LOCKT operation */ -int +__be32 nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt) { struct inode *inode; struct file file; struct file_lock file_lock; struct file_lock conflock; - int status; + __be32 status; if (nfs4_in_grace()) return nfserr_grace; @@ -2873,13 +2873,13 @@ out: return status; } -int +__be32 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner) { struct nfs4_stateid *stp; struct file *filp = NULL; struct file_lock file_lock; - int status; + __be32 status; dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", (long long) locku->lu_offset, @@ -2965,7 +2965,7 @@ out: return status; } -int +__be32 nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) { clientid_t *clid = &rlockowner->rl_clientid; @@ -2974,7 +2974,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner * struct xdr_netobj *owner = &rlockowner->rl_owner; struct list_head matches; int i; - int status; + __be32 status; dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", clid->cl_boot, clid->cl_id); @@ -3111,7 +3111,7 @@ nfs4_find_reclaim_client(clientid_t *clid) /* * Called from OPEN. Look for clientid in reclaim list. */ -int +__be32 nfs4_check_open_reclaim(clientid_t *clid) { return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 3419d99aeb1a..d7b630f1a9ae 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -68,8 +68,8 @@ #define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL #define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL -static int -check_filename(char *str, int len, int err) +static __be32 +check_filename(char *str, int len, __be32 err) { int i; @@ -95,7 +95,7 @@ check_filename(char *str, int len, int err) */ #define DECODE_HEAD \ __be32 *p; \ - int status + __be32 status #define DECODE_TAIL \ status = 0; \ out: \ @@ -217,7 +217,7 @@ static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) } -static int +static __be32 nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) { u32 bmlen; @@ -240,7 +240,7 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr, struct nfs4_acl **acl) { @@ -418,7 +418,7 @@ out_nfserr: goto out; } -static int +static __be32 nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access) { DECODE_HEAD; @@ -429,7 +429,7 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access DECODE_TAIL; } -static int +static __be32 nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) { DECODE_HEAD; @@ -444,7 +444,7 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) } -static int +static __be32 nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit) { DECODE_HEAD; @@ -456,7 +456,7 @@ nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit DECODE_TAIL; } -static int +static __be32 nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create) { DECODE_HEAD; @@ -496,7 +496,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create DECODE_TAIL; } -static inline int +static inline __be32 nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr) { DECODE_HEAD; @@ -508,13 +508,13 @@ nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegretu DECODE_TAIL; } -static inline int +static inline __be32 nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) { return nfsd4_decode_bitmap(argp, getattr->ga_bmval); } -static int +static __be32 nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) { DECODE_HEAD; @@ -529,7 +529,7 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) { DECODE_HEAD; @@ -568,7 +568,7 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) { DECODE_HEAD; @@ -587,7 +587,7 @@ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) { DECODE_HEAD; @@ -606,7 +606,7 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) { DECODE_HEAD; @@ -621,7 +621,7 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup DECODE_TAIL; } -static int +static __be32 nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) { DECODE_HEAD; @@ -699,7 +699,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) { DECODE_HEAD; @@ -713,7 +713,7 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con DECODE_TAIL; } -static int +static __be32 nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down) { DECODE_HEAD; @@ -729,7 +729,7 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d DECODE_TAIL; } -static int +static __be32 nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) { DECODE_HEAD; @@ -744,7 +744,7 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) { DECODE_HEAD; @@ -758,7 +758,7 @@ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir) { DECODE_HEAD; @@ -774,7 +774,7 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read DECODE_TAIL; } -static int +static __be32 nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove) { DECODE_HEAD; @@ -789,7 +789,7 @@ nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove DECODE_TAIL; } -static int +static __be32 nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename) { DECODE_HEAD; @@ -809,7 +809,7 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename DECODE_TAIL; } -static int +static __be32 nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) { DECODE_HEAD; @@ -820,7 +820,7 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) { DECODE_HEAD; @@ -834,7 +834,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta DECODE_TAIL; } -static int +static __be32 nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid) { DECODE_HEAD; @@ -859,7 +859,7 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient DECODE_TAIL; } -static int +static __be32 nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c) { DECODE_HEAD; @@ -872,7 +872,7 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s } /* Also used for NVERIFY */ -static int +static __be32 nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) { #if 0 @@ -908,7 +908,7 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify DECODE_TAIL; } -static int +static __be32 nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) { int avail; @@ -959,7 +959,7 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner) { DECODE_HEAD; @@ -973,7 +973,7 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel DECODE_TAIL; } -static int +static __be32 nfsd4_decode_compound(struct nfsd4_compoundargs *argp) { DECODE_HEAD; @@ -1234,7 +1234,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) /* Encode as an array of strings the string given with components * seperated @sep. */ -static int nfsd4_encode_components(char sep, char *components, +static __be32 nfsd4_encode_components(char sep, char *components, __be32 **pp, int *buflen) { __be32 *p = *pp; @@ -1271,10 +1271,10 @@ static int nfsd4_encode_components(char sep, char *components, /* * encode a location element of a fs_locations structure */ -static int nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, +static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, __be32 **pp, int *buflen) { - int status; + __be32 status; __be32 *p = *pp; status = nfsd4_encode_components(':', location->hosts, &p, buflen); @@ -1292,7 +1292,7 @@ static int nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, * Returned string is safe to use as long as the caller holds a reference * to @exp. */ -static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, u32 *stat) +static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) { struct svc_fh tmp_fh; char *path, *rootpath; @@ -1318,11 +1318,11 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, u32 *sta /* * encode a fs_locations structure */ -static int nfsd4_encode_fs_locations(struct svc_rqst *rqstp, +static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp, struct svc_export *exp, __be32 **pp, int *buflen) { - u32 status; + __be32 status; int i; __be32 *p = *pp; struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; @@ -1353,7 +1353,7 @@ static u32 nfs4_ftypes[16] = { NF4SOCK, NF4BAD, NF4LNK, NF4BAD, }; -static int +static __be32 nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, __be32 **p, int *buflen) { @@ -1375,19 +1375,19 @@ nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, return 0; } -static inline int +static inline __be32 nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen) { return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen); } -static inline int +static inline __be32 nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen) { return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen); } -static inline int +static inline __be32 nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, __be32 **p, int *buflen) { @@ -1398,7 +1398,7 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, FATTR4_WORD0_RDATTR_ERROR) #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID -static int fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) +static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) { /* As per referral draft: */ if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS || @@ -1421,7 +1421,7 @@ static int fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) * @countp is the buffer size in _words_; upon successful return this becomes * replaced with the number of words written. */ -int +__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, struct svc_rqst *rqstp) @@ -1437,7 +1437,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, u64 dummy64; u32 rdattr_err = 0; __be32 *p = buffer; - int status; + __be32 status; int aclsupport = 0; struct nfs4_acl *acl = NULL; @@ -1829,13 +1829,13 @@ out_serverfault: goto out; } -static int +static __be32 nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, const char *name, int namlen, __be32 *p, int *buflen) { struct svc_export *exp = cd->rd_fhp->fh_export; struct dentry *dentry; - int nfserr; + __be32 nfserr; dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); if (IS_ERR(dentry)) @@ -1865,7 +1865,7 @@ out_put: } static __be32 * -nfsd4_encode_rdattr_error(__be32 *p, int buflen, int nfserr) +nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr) { __be32 *attrlenp; @@ -1888,7 +1888,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); int buflen; __be32 *p = cd->buffer; - int nfserr = nfserr_toosmall; + __be32 nfserr = nfserr_toosmall; /* In nfsv4, "." and ".." never make it onto the wire.. */ if (name && isdotent(name, namlen)) { @@ -1944,7 +1944,7 @@ fail: } static void -nfsd4_encode_access(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_access *access) +nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) { ENCODE_HEAD; @@ -1957,7 +1957,7 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_acc } static void -nfsd4_encode_close(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_close *close) +nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) { ENCODE_SEQID_OP_HEAD; @@ -1972,7 +1972,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_clos static void -nfsd4_encode_commit(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_commit *commit) +nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) { ENCODE_HEAD; @@ -1984,7 +1984,7 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_com } static void -nfsd4_encode_create(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_create *create) +nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) { ENCODE_HEAD; @@ -1998,8 +1998,8 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_cre } } -static int -nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_getattr *getattr) +static __be32 +nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr) { struct svc_fh *fhp = getattr->ga_fhp; int buflen; @@ -2017,7 +2017,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_ge } static void -nfsd4_encode_getfh(struct nfsd4_compoundres *resp, int nfserr, struct svc_fh *fhp) +nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh *fhp) { unsigned int len; ENCODE_HEAD; @@ -2057,7 +2057,7 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie } static void -nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock) +nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) { ENCODE_SEQID_OP_HEAD; @@ -2073,14 +2073,14 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock } static void -nfsd4_encode_lockt(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lockt *lockt) +nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) { if (nfserr == nfserr_denied) nfsd4_encode_lock_denied(resp, &lockt->lt_denied); } static void -nfsd4_encode_locku(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_locku *locku) +nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) { ENCODE_SEQID_OP_HEAD; @@ -2096,7 +2096,7 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock static void -nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link *link) +nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) { ENCODE_HEAD; @@ -2109,7 +2109,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link static void -nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open *open) +nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) { ENCODE_SEQID_OP_HEAD; @@ -2174,7 +2174,7 @@ out: } static void -nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_confirm *oc) +nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) { ENCODE_SEQID_OP_HEAD; @@ -2189,7 +2189,7 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, int nfserr, struct nfs } static void -nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_downgrade *od) +nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) { ENCODE_SEQID_OP_HEAD; @@ -2203,8 +2203,8 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct n ENCODE_SEQID_OP_TAIL(od->od_stateowner); } -static int -nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, +static __be32 +nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_read *read) { u32 eof; @@ -2268,8 +2268,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, return 0; } -static int -nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readlink *readlink) +static __be32 +nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink) { int maxcount; char *page; @@ -2316,8 +2316,8 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r return 0; } -static int -nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readdir *readdir) +static __be32 +nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir) { int maxcount; loff_t offset; @@ -2396,7 +2396,7 @@ err_no_verf: } static void -nfsd4_encode_remove(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_remove *remove) +nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) { ENCODE_HEAD; @@ -2408,7 +2408,7 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_rem } static void -nfsd4_encode_rename(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_rename *rename) +nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) { ENCODE_HEAD; @@ -2425,7 +2425,7 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_ren * regardless of the error status. */ static void -nfsd4_encode_setattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setattr *setattr) +nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) { ENCODE_HEAD; @@ -2444,7 +2444,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_se } static void -nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setclientid *scd) +nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) { ENCODE_HEAD; @@ -2463,7 +2463,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd } static void -nfsd4_encode_write(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_write *write) +nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) { ENCODE_HEAD; @@ -2641,7 +2641,7 @@ void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args) int nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) { - int status; + __be32 status; args->p = p; args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 8bf23cf8b603..a597e2e72469 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -164,7 +164,7 @@ update_stateid(stateid_t *stateid) * is cached. */ struct nfs4_replay { - u32 rp_status; + __be32 rp_status; unsigned int rp_buflen; char *rp_buf; unsigned intrp_allocated; @@ -273,19 +273,19 @@ struct nfs4_stateid { ((err) != nfserr_stale_stateid) && \ ((err) != nfserr_bad_stateid)) -extern int nfsd4_renew(clientid_t *clid); -extern int nfs4_preprocess_stateid_op(struct svc_fh *current_fh, +extern __be32 nfsd4_renew(clientid_t *clid); +extern __be32 nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filp); extern void nfs4_lock_state(void); extern void nfs4_unlock_state(void); extern int nfs4_in_grace(void); -extern int nfs4_check_open_reclaim(clientid_t *clid); +extern __be32 nfs4_check_open_reclaim(clientid_t *clid); extern void put_nfs4_client(struct nfs4_client *clp); extern void nfs4_free_stateowner(struct kref *kref); extern void nfsd4_probe_callback(struct nfs4_client *clp); extern void nfsd4_cb_recall(struct nfs4_delegation *dp); extern void nfs4_put_delegation(struct nfs4_delegation *dp); -extern int nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); +extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); extern void nfsd4_init_recdir(char *recdir_name); extern int nfsd4_recdir_load(void); extern void nfsd4_shutdown_recdir(void); diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index 003193fe6fc6..45ca01b5f844 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -334,7 +334,7 @@ struct nfsd4_write { struct nfsd4_op { int opnum; - int status; + __be32 status; union { struct nfsd4_access access; struct nfsd4_close close; @@ -426,38 +426,38 @@ int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, struct nfsd4_compoundres *); void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); -int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, - struct dentry *dentry, u32 *buffer, int *countp, +__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, + struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, struct svc_rqst *); -extern int nfsd4_setclientid(struct svc_rqst *rqstp, +extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid); -extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp, +extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm); -extern int nfsd4_process_open1(struct nfsd4_open *open); -extern int nfsd4_process_open2(struct svc_rqst *rqstp, +extern __be32 nfsd4_process_open1(struct nfsd4_open *open); +extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open); -extern int nfsd4_open_confirm(struct svc_rqst *rqstp, +extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **); -extern int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, +extern __be32 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner); -extern int nfsd4_open_downgrade(struct svc_rqst *rqstp, +extern __be32 nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner); -extern int nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, +extern __be32 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner); -extern int nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, +extern __be32 nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt); -extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, +extern __be32 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner); -extern int +extern __be32 nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner); extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *); -extern int nfsd4_delegreturn(struct svc_rqst *rqstp, +extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr); #endif -- cgit v1.2.3 From c7afef1f963bec198b186cc34b9e8c9b9ce2e266 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:29:02 -0700 Subject: [PATCH] nfsd: misc endianness annotations Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/export.c | 4 ++-- fs/nfsd/lockd.c | 2 +- fs/nfsd/nfs4callback.c | 2 +- fs/nfsd/nfs4state.c | 4 ++-- fs/nfsd/nfscache.c | 8 ++++---- fs/nfsd/nfssvc.c | 2 +- include/linux/nfsd/cache.h | 6 +++--- include/linux/nfsd/export.h | 2 +- include/linux/nfsd/nfsd.h | 2 +- include/linux/nfsd/nfsfh.h | 2 +- include/linux/nfsd/state.h | 2 +- 11 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index e13fa23bd108..f37df46d2eaa 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1148,12 +1148,12 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, * for a given NFSv4 client. The root is defined to be the * export point with fsid==0 */ -int +__be32 exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, struct cache_req *creq) { struct svc_export *exp; - int rv; + __be32 rv; u32 fsidv[2]; mk_fsid_v1(fsidv, 0); diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 9b9e7e127c03..11fdaf7721b4 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -25,7 +25,7 @@ static u32 nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) { - u32 nfserr; + __be32 nfserr; struct svc_fh fh; /* must initialize before using! but maxsize doesn't matter */ diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 8497ed4862b2..f57655a7a2b6 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -461,7 +461,7 @@ nfs4_cb_null(struct rpc_task *task, void *dummy) { struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; struct nfs4_callback *cb = &clp->cl_callback; - u32 addr = htonl(cb->cb_addr); + __be32 addr = htonl(cb->cb_addr); dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ae1d47715b90..2e468c9e64d9 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -713,7 +713,7 @@ out_err: __be32 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) { - u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; + __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; struct xdr_netobj clname = { .len = setclid->se_namelen, .data = setclid->se_name, @@ -878,7 +878,7 @@ out: __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm) { - u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; + __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; struct nfs4_client *conf, *unconf; nfs4_verifier confirm = setclientid_confirm->sc_confirm; clientid_t * clid = &setclientid_confirm->sc_clientid; diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index fdf7cf3dfadc..6100bbe27432 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -29,7 +29,7 @@ */ #define CACHESIZE 1024 #define HASHSIZE 64 -#define REQHASH(xid) ((((xid) >> 24) ^ (xid)) & (HASHSIZE-1)) +#define REQHASH(xid) (((((__force __u32)xid) >> 24) ^ ((__force __u32)xid)) & (HASHSIZE-1)) static struct hlist_head * hash_list; static struct list_head lru_head; @@ -127,8 +127,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) struct hlist_node *hn; struct hlist_head *rh; struct svc_cacherep *rp; - u32 xid = rqstp->rq_xid, - proto = rqstp->rq_prot, + __be32 xid = rqstp->rq_xid; + u32 proto = rqstp->rq_prot, vers = rqstp->rq_vers, proc = rqstp->rq_proc; unsigned long age; @@ -258,7 +258,7 @@ found_entry: * In this case, nfsd_cache_update is called with statp == NULL. */ void -nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, u32 *statp) +nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) { struct svc_cacherep *rp; struct kvec *resv = &rqstp->rq_res.head[0], *cachv; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 8067118b1c0c..0aaccb03bf76 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -491,7 +491,7 @@ out: } int -nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) +nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) { struct svc_procedure *proc; kxdrproc_t xdr; diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h index c3a3557c2a5b..007480cd6a60 100644 --- a/include/linux/nfsd/cache.h +++ b/include/linux/nfsd/cache.h @@ -26,14 +26,14 @@ struct svc_cacherep { c_type, /* status, buffer */ c_secure : 1; /* req came from port < 1024 */ struct sockaddr_in c_addr; - u32 c_xid; + __be32 c_xid; u32 c_prot; u32 c_proc; u32 c_vers; unsigned long c_timestamp; union { struct kvec u_vec; - u32 u_status; + __be32 u_status; } c_u; }; @@ -75,7 +75,7 @@ enum { void nfsd_cache_init(void); void nfsd_cache_shutdown(void); int nfsd_cache_lookup(struct svc_rqst *, int); -void nfsd_cache_update(struct svc_rqst *, int, u32 *); +void nfsd_cache_update(struct svc_rqst *, int, __be32 *); #endif /* __KERNEL__ */ #endif /* NFSCACHE_H */ diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 27666f5b8b53..045e38cdbe64 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -117,7 +117,7 @@ struct svc_export * exp_parent(struct auth_domain *clp, struct cache_req *reqp); int exp_rootfh(struct auth_domain *, char *path, struct knfsd_fh *, int maxsize); -int exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq); +__be32 exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq); __be32 nfserrno(int errno); extern struct cache_detail svc_export_cache; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 19a3c83d496e..68d29b66c6e2 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -64,7 +64,7 @@ extern struct svc_serv *nfsd_serv; * Function prototypes. */ int nfsd_svc(unsigned short port, int nrservs); -int nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp); +int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); /* nfsd/vfs.c */ int fh_lock_parent(struct svc_fh *, struct dentry *); diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index 749bad1ca16f..f3b51d62ec7d 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -157,7 +157,7 @@ typedef struct svc_fh { __u64 fh_post_size; /* i_size */ unsigned long fh_post_blocks; /* i_blocks */ unsigned long fh_post_blksize;/* i_blksize */ - __u32 fh_post_rdev[2];/* i_rdev */ + __be32 fh_post_rdev[2];/* i_rdev */ struct timespec fh_post_atime; /* i_atime */ struct timespec fh_post_mtime; /* i_mtime */ struct timespec fh_post_ctime; /* i_ctime */ diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index a597e2e72469..c3673f487e84 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -125,7 +125,7 @@ struct nfs4_client { char cl_recdir[HEXDIR_LEN]; /* recovery dir */ nfs4_verifier cl_verifier; /* generated by client */ time_t cl_time; /* time of last lease renewal */ - u32 cl_addr; /* client ipaddress */ + __be32 cl_addr; /* client ipaddress */ struct svc_cred cl_cred; /* setclientid principal */ clientid_t cl_clientid; /* generated by server */ nfs4_verifier cl_confirm; /* generated by server */ -- cgit v1.2.3 From a90b061c0bf712961cea40d9c916b300073d12e5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:29:03 -0700 Subject: [PATCH] nfsd: nfs_replay_me We are using NFS_REPLAY_ME as a special error value that is never leaked to clients. That works fine; the only problem is mixing host- and network- endian values in the same objects. Network-endian equivalent would work just as fine; switch to it. Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4proc.c | 6 +++--- fs/nfsd/nfs4state.c | 4 ++-- include/linux/nfsd/nfsd.h | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 63823945f972..0a7bbdc4a10a 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -177,7 +177,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open /* check seqid for replay. set nfs4_owner */ status = nfsd4_process_open1(open); - if (status == NFSERR_REPLAY_ME) { + if (status == nfserr_replay_me) { struct nfs4_replay *rp = &open->op_stateowner->so_replay; fh_put(current_fh); current_fh->fh_handle.fh_size = rp->rp_openfh_len; @@ -188,7 +188,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open dprintk("nfsd4_open: replay failed" " restoring previous filehandle\n"); else - status = NFSERR_REPLAY_ME; + status = nfserr_replay_me; } if (status) goto out; @@ -937,7 +937,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, } encode_op: - if (op->status == NFSERR_REPLAY_ME) { + if (op->status == nfserr_replay_me) { op->replay = &replay_owner->so_replay; nfsd4_encode_replay(resp, op); status = op->status = op->replay->rp_status; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2e468c9e64d9..293b6495829f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1477,7 +1477,7 @@ nfsd4_process_open1(struct nfsd4_open *open) } if (open->op_seqid == sop->so_seqid - 1) { if (sop->so_replay.rp_buflen) - return NFSERR_REPLAY_ME; + return nfserr_replay_me; /* The original OPEN failed so spectacularly * that we don't even have replay data saved! * Therefore, we have no choice but to continue @@ -2233,7 +2233,7 @@ check_replay: if (seqid == sop->so_seqid - 1) { dprintk("NFSD: preprocess_seqid_op: retransmission?\n"); /* indicate replay to calling function */ - return NFSERR_REPLAY_ME; + return nfserr_replay_me; } printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n", sop->so_seqid, seqid); diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 68d29b66c6e2..eb231143d579 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -238,6 +238,7 @@ void nfsd_lockd_shutdown(void); #define nfserr_badname __constant_htonl(NFSERR_BADNAME) #define nfserr_cb_path_down __constant_htonl(NFSERR_CB_PATH_DOWN) #define nfserr_locked __constant_htonl(NFSERR_LOCKED) +#define nfserr_replay_me __constant_htonl(NFSERR_REPLAY_ME) /* error codes for internal use */ /* if a request fails due to kmalloc failure, it gets dropped. -- cgit v1.2.3 From 690a973f48b6ba2954465992c08e65059c8374fe Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Sat, 21 Oct 2006 18:37:01 +0200 Subject: [PATCH] x86-64: Speed up dwarf2 unwinder This changes the dwarf2 unwinder to do a binary search for CIEs instead of a linear work. The linker is unfortunately not able to build a proper lookup table at link time, instead it creates one at runtime as soon as the bootmem allocator is usable (so you'll continue using the linear lookup for the first [hopefully] few calls). The code should be ready to utilize a build-time created table once a fixed linker becomes available. Signed-off-by: Jan Beulich Signed-off-by: Andi Kleen --- Makefile | 1 + include/asm-generic/vmlinux.lds.h | 16 ++ include/linux/unwind.h | 2 + init/main.c | 1 + kernel/unwind.c | 318 +++++++++++++++++++++++++++++++++----- 5 files changed, 299 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/Makefile b/Makefile index 62a1343cf327..389ff0cca9a7 100644 --- a/Makefile +++ b/Makefile @@ -499,6 +499,7 @@ endif ifdef CONFIG_UNWIND_INFO CFLAGS += -fasynchronous-unwind-tables +LDFLAGS_vmlinux += --eh-frame-hdr endif ifdef CONFIG_DEBUG_INFO diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 69240b52f8e1..9d0d11c180d9 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -125,6 +125,10 @@ *(__param) \ VMLINUX_SYMBOL(__stop___param) = .; \ } \ + \ + /* Unwind data binary search table */ \ + EH_FRAME_HDR \ + \ __end_rodata = .; \ . = ALIGN(4096); @@ -157,6 +161,18 @@ *(.kprobes.text) \ VMLINUX_SYMBOL(__kprobes_text_end) = .; +#ifdef CONFIG_STACK_UNWIND + /* Unwind data binary search table */ +#define EH_FRAME_HDR \ + .eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_unwind_hdr) = .; \ + *(.eh_frame_hdr) \ + VMLINUX_SYMBOL(__end_unwind_hdr) = .; \ + } +#else +#define EH_FRAME_HDR +#endif + /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ diff --git a/include/linux/unwind.h b/include/linux/unwind.h index 73e1751d03dd..749928c161fb 100644 --- a/include/linux/unwind.h +++ b/include/linux/unwind.h @@ -26,6 +26,7 @@ struct module; * Initialize unwind support. */ extern void unwind_init(void); +extern void unwind_setup(void); #ifdef CONFIG_MODULES @@ -73,6 +74,7 @@ extern int unwind_to_user(struct unwind_frame_info *); struct unwind_frame_info {}; static inline void unwind_init(void) {} +static inline void unwind_setup(void) {} #ifdef CONFIG_MODULES diff --git a/init/main.c b/init/main.c index ee123243fb53..36f608a7cfba 100644 --- a/init/main.c +++ b/init/main.c @@ -503,6 +503,7 @@ asmlinkage void __init start_kernel(void) printk(KERN_NOTICE); printk(linux_banner); setup_arch(&command_line); + unwind_setup(); setup_per_cpu_areas(); smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */ diff --git a/kernel/unwind.c b/kernel/unwind.c index 2e2368607aab..f7e50d16dbf6 100644 --- a/kernel/unwind.c +++ b/kernel/unwind.c @@ -11,13 +11,15 @@ #include #include -#include +#include +#include #include #include #include #include extern char __start_unwind[], __end_unwind[]; +extern const u8 __start_unwind_hdr[], __end_unwind_hdr[]; #define MAX_STACK_DEPTH 8 @@ -100,6 +102,8 @@ static struct unwind_table { } core, init; const void *address; unsigned long size; + const unsigned char *header; + unsigned long hdrsz; struct unwind_table *link; const char *name; } root_table; @@ -145,6 +149,10 @@ static struct unwind_table *find_table(unsigned long pc) return table; } +static unsigned long read_pointer(const u8 **pLoc, + const void *end, + signed ptrType); + static void init_unwind_table(struct unwind_table *table, const char *name, const void *core_start, @@ -152,14 +160,30 @@ static void init_unwind_table(struct unwind_table *table, const void *init_start, unsigned long init_size, const void *table_start, - unsigned long table_size) + unsigned long table_size, + const u8 *header_start, + unsigned long header_size) { + const u8 *ptr = header_start + 4; + const u8 *end = header_start + header_size; + table->core.pc = (unsigned long)core_start; table->core.range = core_size; table->init.pc = (unsigned long)init_start; table->init.range = init_size; table->address = table_start; table->size = table_size; + /* See if the linker provided table looks valid. */ + if (header_size <= 4 + || header_start[0] != 1 + || (void *)read_pointer(&ptr, end, header_start[1]) != table_start + || header_start[2] == DW_EH_PE_omit + || read_pointer(&ptr, end, header_start[2]) <= 0 + || header_start[3] == DW_EH_PE_omit) + header_start = NULL; + table->hdrsz = header_size; + smp_wmb(); + table->header = header_start; table->link = NULL; table->name = name; } @@ -169,7 +193,143 @@ void __init unwind_init(void) init_unwind_table(&root_table, "kernel", _text, _end - _text, NULL, 0, - __start_unwind, __end_unwind - __start_unwind); + __start_unwind, __end_unwind - __start_unwind, + __start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr); +} + +static const u32 bad_cie, not_fde; +static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *); +static signed fde_pointer_type(const u32 *cie); + +struct eh_frame_hdr_table_entry { + unsigned long start, fde; +}; + +static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2) +{ + const struct eh_frame_hdr_table_entry *e1 = p1; + const struct eh_frame_hdr_table_entry *e2 = p2; + + return (e1->start > e2->start) - (e1->start < e2->start); +} + +static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size) +{ + struct eh_frame_hdr_table_entry *e1 = p1; + struct eh_frame_hdr_table_entry *e2 = p2; + unsigned long v; + + v = e1->start; + e1->start = e2->start; + e2->start = v; + v = e1->fde; + e1->fde = e2->fde; + e2->fde = v; +} + +static void __init setup_unwind_table(struct unwind_table *table, + void *(*alloc)(unsigned long)) +{ + const u8 *ptr; + unsigned long tableSize = table->size, hdrSize; + unsigned n; + const u32 *fde; + struct { + u8 version; + u8 eh_frame_ptr_enc; + u8 fde_count_enc; + u8 table_enc; + unsigned long eh_frame_ptr; + unsigned int fde_count; + struct eh_frame_hdr_table_entry table[]; + } __attribute__((__packed__)) *header; + + if (table->header) + return; + + if (table->hdrsz) + printk(KERN_WARNING ".eh_frame_hdr for '%s' present but unusable\n", + table->name); + + if (tableSize & (sizeof(*fde) - 1)) + return; + + for (fde = table->address, n = 0; + tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde; + tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { + const u32 *cie = cie_for_fde(fde, table); + signed ptrType; + + if (cie == ¬_fde) + continue; + if (cie == NULL + || cie == &bad_cie + || (ptrType = fde_pointer_type(cie)) < 0) + return; + ptr = (const u8 *)(fde + 2); + if (!read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + ptrType)) + return; + ++n; + } + + if (tableSize || !n) + return; + + hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) + + 2 * n * sizeof(unsigned long); + header = alloc(hdrSize); + if (!header) + return; + header->version = 1; + header->eh_frame_ptr_enc = DW_EH_PE_abs|DW_EH_PE_native; + header->fde_count_enc = DW_EH_PE_abs|DW_EH_PE_data4; + header->table_enc = DW_EH_PE_abs|DW_EH_PE_native; + put_unaligned((unsigned long)table->address, &header->eh_frame_ptr); + BUILD_BUG_ON(offsetof(typeof(*header), fde_count) + % __alignof(typeof(header->fde_count))); + header->fde_count = n; + + BUILD_BUG_ON(offsetof(typeof(*header), table) + % __alignof(typeof(*header->table))); + for (fde = table->address, tableSize = table->size, n = 0; + tableSize; + tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { + const u32 *cie = fde + 1 - fde[1] / sizeof(*fde); + + if (!fde[1]) + continue; /* this is a CIE */ + ptr = (const u8 *)(fde + 2); + header->table[n].start = read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + fde_pointer_type(cie)); + header->table[n].fde = (unsigned long)fde; + ++n; + } + WARN_ON(n != header->fde_count); + + sort(header->table, + n, + sizeof(*header->table), + cmp_eh_frame_hdr_table_entries, + swap_eh_frame_hdr_table_entries); + + table->hdrsz = hdrSize; + smp_wmb(); + table->header = (const void *)header; +} + +static void *__init balloc(unsigned long sz) +{ + return __alloc_bootmem_nopanic(sz, + sizeof(unsigned int), + __pa(MAX_DMA_ADDRESS)); +} + +void __init unwind_setup(void) +{ + setup_unwind_table(&root_table, balloc); } #ifdef CONFIG_MODULES @@ -193,7 +353,8 @@ void *unwind_add_table(struct module *module, init_unwind_table(table, module->name, module->module_core, module->core_size, module->module_init, module->init_size, - table_start, table_size); + table_start, table_size, + NULL, 0); if (last_table) last_table->link = table; @@ -303,6 +464,26 @@ static sleb128_t get_sleb128(const u8 **pcur, const u8 *end) return value; } +static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table) +{ + const u32 *cie; + + if (!*fde || (*fde & (sizeof(*fde) - 1))) + return &bad_cie; + if (!fde[1]) + return ¬_fde; /* this is a CIE */ + if ((fde[1] & (sizeof(*fde) - 1)) + || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address) + return NULL; /* this is not a valid FDE */ + cie = fde + 1 - fde[1] / sizeof(*fde); + if (*cie <= sizeof(*cie) + 4 + || *cie >= fde[1] - sizeof(*fde) + || (*cie & (sizeof(*cie) - 1)) + || cie[1]) + return NULL; /* this is not a (valid) CIE */ + return cie; +} + static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrType) @@ -610,49 +791,108 @@ int unwind(struct unwind_frame_info *frame) unsigned i; signed ptrType = -1; uleb128_t retAddrReg = 0; - struct unwind_table *table; + const struct unwind_table *table; struct unwind_state state; if (UNW_PC(frame) == 0) return -EINVAL; if ((table = find_table(pc)) != NULL && !(table->size & (sizeof(*fde) - 1))) { - unsigned long tableSize = table->size; - - for (fde = table->address; - tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde; - tableSize -= sizeof(*fde) + *fde, - fde += 1 + *fde / sizeof(*fde)) { - if (!*fde || (*fde & (sizeof(*fde) - 1))) - break; - if (!fde[1]) - continue; /* this is a CIE */ - if ((fde[1] & (sizeof(*fde) - 1)) - || fde[1] > (unsigned long)(fde + 1) - - (unsigned long)table->address) - continue; /* this is not a valid FDE */ - cie = fde + 1 - fde[1] / sizeof(*fde); - if (*cie <= sizeof(*cie) + 4 - || *cie >= fde[1] - sizeof(*fde) - || (*cie & (sizeof(*cie) - 1)) - || cie[1] - || (ptrType = fde_pointer_type(cie)) < 0) { - cie = NULL; /* this is not a (valid) CIE */ - continue; + const u8 *hdr = table->header; + unsigned long tableSize; + + smp_rmb(); + if (hdr && hdr[0] == 1) { + switch(hdr[3] & DW_EH_PE_FORM) { + case DW_EH_PE_native: tableSize = sizeof(unsigned long); break; + case DW_EH_PE_data2: tableSize = 2; break; + case DW_EH_PE_data4: tableSize = 4; break; + case DW_EH_PE_data8: tableSize = 8; break; + default: tableSize = 0; break; + } + ptr = hdr + 4; + end = hdr + table->hdrsz; + if (tableSize + && read_pointer(&ptr, end, hdr[1]) + == (unsigned long)table->address + && (i = read_pointer(&ptr, end, hdr[2])) > 0 + && i == (end - ptr) / (2 * tableSize) + && !((end - ptr) % (2 * tableSize))) { + do { + const u8 *cur = ptr + (i / 2) * (2 * tableSize); + + startLoc = read_pointer(&cur, + cur + tableSize, + hdr[3]); + if (pc < startLoc) + i /= 2; + else { + ptr = cur - tableSize; + i = (i + 1) / 2; + } + } while (startLoc && i > 1); + if (i == 1 + && (startLoc = read_pointer(&ptr, + ptr + tableSize, + hdr[3])) != 0 + && pc >= startLoc) + fde = (void *)read_pointer(&ptr, + ptr + tableSize, + hdr[3]); } + } + + if (fde != NULL) { + cie = cie_for_fde(fde, table); ptr = (const u8 *)(fde + 2); - startLoc = read_pointer(&ptr, - (const u8 *)(fde + 1) + *fde, - ptrType); - endLoc = startLoc - + read_pointer(&ptr, - (const u8 *)(fde + 1) + *fde, - ptrType & DW_EH_PE_indirect - ? ptrType - : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed)); - if (pc >= startLoc && pc < endLoc) - break; - cie = NULL; + if(cie != NULL + && cie != &bad_cie + && cie != ¬_fde + && (ptrType = fde_pointer_type(cie)) >= 0 + && read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + ptrType) == startLoc) { + if (!(ptrType & DW_EH_PE_indirect)) + ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed; + endLoc = startLoc + + read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + ptrType); + if(pc >= endLoc) + fde = NULL; + } else + fde = NULL; + } + if (fde == NULL) { + for (fde = table->address, tableSize = table->size; + cie = NULL, tableSize > sizeof(*fde) + && tableSize - sizeof(*fde) >= *fde; + tableSize -= sizeof(*fde) + *fde, + fde += 1 + *fde / sizeof(*fde)) { + cie = cie_for_fde(fde, table); + if (cie == &bad_cie) { + cie = NULL; + break; + } + if (cie == NULL + || cie == ¬_fde + || (ptrType = fde_pointer_type(cie)) < 0) + continue; + ptr = (const u8 *)(fde + 2); + startLoc = read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + ptrType); + if (!startLoc) + continue; + if (!(ptrType & DW_EH_PE_indirect)) + ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed; + endLoc = startLoc + + read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + ptrType); + if (pc >= startLoc && pc < endLoc) + break; + } } } if (cie != NULL) { -- cgit v1.2.3 From a1bae67243512ca30ceda48e3e24e25b543f8ab7 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 21 Oct 2006 18:37:02 +0200 Subject: [PATCH] i386: Disable nmi watchdog on all ThinkPads Even newer Thinkpads have bugs in SMM code that causes hangs with NMI watchdog. Signed-off-by: Andi Kleen --- arch/i386/kernel/nmi.c | 10 +++++----- drivers/firmware/dmi_scan.c | 20 ++++++++++++++++++++ include/linux/dmi.h | 2 ++ 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 3e8e3adb0489..eaafe233a5da 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -219,11 +219,11 @@ static int __init check_nmi_watchdog(void) int cpu; /* Enable NMI watchdog for newer systems. - Actually it should be safe for most systems before 2004 too except - for some IBM systems that corrupt registers when NMI happens - during SMM. Unfortunately we don't have more exact information - on these and use this coarse check. */ - if (nmi_watchdog == NMI_DEFAULT && dmi_get_year(DMI_BIOS_DATE) >= 2004) + Probably safe on most older systems too, but let's be careful. + IBM ThinkPads use INT10 inside SMM and that allows early NMI inside SMM + which hangs the system. Disable watchdog for all thinkpads */ + if (nmi_watchdog == NMI_DEFAULT && dmi_get_year(DMI_BIOS_DATE) >= 2004 && + !dmi_name_in_vendors("ThinkPad")) nmi_watchdog = NMI_LOCAL_APIC; if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DEFAULT)) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index b8b596d5778d..37deee6c0c1c 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -326,6 +326,26 @@ char *dmi_get_system_info(int field) } EXPORT_SYMBOL(dmi_get_system_info); + +/** + * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. + * @str: Case sensitive Name + */ +int dmi_name_in_vendors(char *str) +{ + static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR, + DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE }; + int i; + for (i = 0; fields[i] != DMI_NONE; i++) { + int f = fields[i]; + if (dmi_ident[f] && strstr(dmi_ident[f], str)) + return 1; + } + return 0; +} +EXPORT_SYMBOL(dmi_name_in_vendors); + /** * dmi_find_device - find onboard device by type/name * @type: device type or %DMI_DEV_TYPE_ANY to match all device types diff --git a/include/linux/dmi.h b/include/linux/dmi.h index 38dc403be70b..904bf3d2d90b 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -69,6 +69,7 @@ extern struct dmi_device * dmi_find_device(int type, const char *name, struct dmi_device *from); extern void dmi_scan_machine(void); extern int dmi_get_year(int field); +extern int dmi_name_in_vendors(char *str); #else @@ -77,6 +78,7 @@ static inline char * dmi_get_system_info(int field) { return NULL; } static inline struct dmi_device * dmi_find_device(int type, const char *name, struct dmi_device *from) { return NULL; } static inline int dmi_get_year(int year) { return 0; } +static inline int dmi_name_in_vendors(char *s) { return 0; } #endif -- cgit v1.2.3 From 3343571d9f88a0de542d33aea9ab881f00ff866d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 19 Oct 2006 14:44:53 +0900 Subject: [PATCH] libata: typo fix Typo fix in commment. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- include/linux/libata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index d0a7ad5ed518..b03d5a340dc8 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -143,7 +143,7 @@ enum { ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */ - ATA_DFLAG_NCQ_OFF = (1 << 9), /* devied limited to non-NCQ mode */ + ATA_DFLAG_NCQ_OFF = (1 << 9), /* device limited to non-NCQ mode */ ATA_DFLAG_SUSPENDED = (1 << 10), /* device suspended */ ATA_DFLAG_INIT_MASK = (1 << 16) - 1, -- cgit v1.2.3 From da3ed32fe568148ede256975d40825ffcdac767b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 21 Oct 2006 10:24:08 -0700 Subject: [PATCH] md: add another COMPAT_IOCTL for md .. so that you can use bitmaps with 32bit userspace on a 64 bit kernel. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/compat_ioctl.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index cfdb4f6a89d4..c26c3adcfacf 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -131,6 +131,7 @@ COMPATIBLE_IOCTL(RUN_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY_RO) COMPATIBLE_IOCTL(RESTART_ARRAY_RW) +COMPATIBLE_IOCTL(GET_BITMAP_FILE) ULONG_IOCTL(SET_BITMAP_FILE) /* DM */ COMPATIBLE_IOCTL(DM_VERSION_32) -- cgit v1.2.3 From 1c05b4bc22cd640d3a534bd2851a8413d5df3709 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 21 Oct 2006 10:24:08 -0700 Subject: [PATCH] md: endian annotation for v1 superblock access Includes a couple of bugfixes found by sparse. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/md.c | 13 ++++++----- include/linux/raid/md_p.h | 56 +++++++++++++++++++++++------------------------ 2 files changed, 35 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index f7f19088f3be..7daa7b1e145f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -974,12 +974,13 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) * version 1 superblock */ -static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) +static __le32 calc_sb_1_csum(struct mdp_superblock_1 * sb) { - unsigned int disk_csum, csum; + __le32 disk_csum; + u32 csum; unsigned long long newcsum; int size = 256 + le32_to_cpu(sb->max_dev)*2; - unsigned int *isuper = (unsigned int*)sb; + __le32 *isuper = (__le32*)sb; int i; disk_csum = sb->sb_csum; @@ -989,7 +990,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) newcsum += le32_to_cpu(*isuper++); if (size == 2) - newcsum += le16_to_cpu(*(unsigned short*) isuper); + newcsum += le16_to_cpu(*(__le16*) isuper); csum = (newcsum & 0xffffffff) + (newcsum >> 32); sb->sb_csum = disk_csum; @@ -1106,7 +1107,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) if (le32_to_cpu(sb->chunksize)) rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1); - if (le32_to_cpu(sb->size) > rdev->size*2) + if (le64_to_cpu(sb->size) > rdev->size*2) return -EINVAL; return ret; } @@ -1228,7 +1229,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) else sb->resync_offset = cpu_to_le64(0); - sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors); + sb->cnt_corrected_read = cpu_to_le32(atomic_read(&rdev->corrected_errors)); sb->raid_disks = cpu_to_le32(mddev->raid_disks); sb->size = cpu_to_le64(mddev->size<<1); diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h index b6ebc69bae54..3f2cd98c508b 100644 --- a/include/linux/raid/md_p.h +++ b/include/linux/raid/md_p.h @@ -206,52 +206,52 @@ static inline __u64 md_event(mdp_super_t *sb) { */ struct mdp_superblock_1 { /* constant array information - 128 bytes */ - __u32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ - __u32 major_version; /* 1 */ - __u32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */ - __u32 pad0; /* always set to 0 when writing */ + __le32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ + __le32 major_version; /* 1 */ + __le32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */ + __le32 pad0; /* always set to 0 when writing */ __u8 set_uuid[16]; /* user-space generated. */ char set_name[32]; /* set and interpreted by user-space */ - __u64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ - __u32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ - __u32 layout; /* only for raid5 and raid10 currently */ - __u64 size; /* used size of component devices, in 512byte sectors */ + __le64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ + __le32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ + __le32 layout; /* only for raid5 and raid10 currently */ + __le64 size; /* used size of component devices, in 512byte sectors */ - __u32 chunksize; /* in 512byte sectors */ - __u32 raid_disks; - __u32 bitmap_offset; /* sectors after start of superblock that bitmap starts + __le32 chunksize; /* in 512byte sectors */ + __le32 raid_disks; + __le32 bitmap_offset; /* sectors after start of superblock that bitmap starts * NOTE: signed, so bitmap can be before superblock * only meaningful of feature_map[0] is set. */ /* These are only valid with feature bit '4' */ - __u32 new_level; /* new level we are reshaping to */ - __u64 reshape_position; /* next address in array-space for reshape */ - __u32 delta_disks; /* change in number of raid_disks */ - __u32 new_layout; /* new layout */ - __u32 new_chunk; /* new chunk size (bytes) */ + __le32 new_level; /* new level we are reshaping to */ + __le64 reshape_position; /* next address in array-space for reshape */ + __le32 delta_disks; /* change in number of raid_disks */ + __le32 new_layout; /* new layout */ + __le32 new_chunk; /* new chunk size (bytes) */ __u8 pad1[128-124]; /* set to 0 when written */ /* constant this-device information - 64 bytes */ - __u64 data_offset; /* sector start of data, often 0 */ - __u64 data_size; /* sectors in this device that can be used for data */ - __u64 super_offset; /* sector start of this superblock */ - __u64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ - __u32 dev_number; /* permanent identifier of this device - not role in raid */ - __u32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */ + __le64 data_offset; /* sector start of data, often 0 */ + __le64 data_size; /* sectors in this device that can be used for data */ + __le64 super_offset; /* sector start of this superblock */ + __le64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ + __le32 dev_number; /* permanent identifier of this device - not role in raid */ + __le32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */ __u8 device_uuid[16]; /* user-space setable, ignored by kernel */ __u8 devflags; /* per-device flags. Only one defined...*/ #define WriteMostly1 1 /* mask for writemostly flag in above */ __u8 pad2[64-57]; /* set to 0 when writing */ /* array state information - 64 bytes */ - __u64 utime; /* 40 bits second, 24 btes microseconds */ - __u64 events; /* incremented when superblock updated */ - __u64 resync_offset; /* data before this offset (from data_offset) known to be in sync */ - __u32 sb_csum; /* checksum upto devs[max_dev] */ - __u32 max_dev; /* size of devs[] array to consider */ + __le64 utime; /* 40 bits second, 24 btes microseconds */ + __le64 events; /* incremented when superblock updated */ + __le64 resync_offset; /* data before this offset (from data_offset) known to be in sync */ + __le32 sb_csum; /* checksum upto devs[max_dev] */ + __le32 max_dev; /* size of devs[] array to consider */ __u8 pad3[64-32]; /* set to 0 when writing */ /* device state information. Indexed by dev_number. @@ -260,7 +260,7 @@ struct mdp_superblock_1 { * into the 'roles' value. If a device is spare or faulty, then it doesn't * have a meaningful role. */ - __u16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ + __le16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ }; /* feature_map bits */ -- cgit v1.2.3 From 4f2e639af4bd5e152fc79256e333643d3dd6c10f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 21 Oct 2006 10:24:09 -0700 Subject: [PATCH] md: endian annotations for the bitmap superblock And a couple of bug fixes found by sparse. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/bitmap.c | 10 +++++----- include/linux/raid/bitmap.h | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index d47d38ac71b1..d6f614738bbd 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -536,7 +536,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) printk(KERN_INFO "%s: bitmap file is out of date (%llu < %llu) " "-- forcing full recovery\n", bmname(bitmap), events, (unsigned long long) bitmap->mddev->events); - sb->state |= BITMAP_STALE; + sb->state |= cpu_to_le32(BITMAP_STALE); } success: /* assign fields using values from superblock */ @@ -544,11 +544,11 @@ success: bitmap->daemon_sleep = daemon_sleep; bitmap->daemon_lastrun = jiffies; bitmap->max_write_behind = write_behind; - bitmap->flags |= sb->state; + bitmap->flags |= le32_to_cpu(sb->state); if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN) bitmap->flags |= BITMAP_HOSTENDIAN; bitmap->events_cleared = le64_to_cpu(sb->events_cleared); - if (sb->state & BITMAP_STALE) + if (sb->state & cpu_to_le32(BITMAP_STALE)) bitmap->events_cleared = bitmap->mddev->events; err = 0; out: @@ -578,9 +578,9 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, spin_unlock_irqrestore(&bitmap->lock, flags); sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); switch (op) { - case MASK_SET: sb->state |= bits; + case MASK_SET: sb->state |= cpu_to_le32(bits); break; - case MASK_UNSET: sb->state &= ~bits; + case MASK_UNSET: sb->state &= cpu_to_le32(~bits); break; default: BUG(); } diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h index 84d887751855..ebd42a3710b4 100644 --- a/include/linux/raid/bitmap.h +++ b/include/linux/raid/bitmap.h @@ -146,16 +146,16 @@ enum bitmap_state { /* the superblock at the front of the bitmap file -- little endian */ typedef struct bitmap_super_s { - __u32 magic; /* 0 BITMAP_MAGIC */ - __u32 version; /* 4 the bitmap major for now, could change... */ - __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */ - __u64 events; /* 24 event counter for the bitmap (1)*/ - __u64 events_cleared;/*32 event counter when last bit cleared (2) */ - __u64 sync_size; /* 40 the size of the md device's sync range(3) */ - __u32 state; /* 48 bitmap state information */ - __u32 chunksize; /* 52 the bitmap chunk size in bytes */ - __u32 daemon_sleep; /* 56 seconds between disk flushes */ - __u32 write_behind; /* 60 number of outstanding write-behind writes */ + __le32 magic; /* 0 BITMAP_MAGIC */ + __le32 version; /* 4 the bitmap major for now, could change... */ + __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */ + __le64 events; /* 24 event counter for the bitmap (1)*/ + __le64 events_cleared;/*32 event counter when last bit cleared (2) */ + __le64 sync_size; /* 40 the size of the md device's sync range(3) */ + __le32 state; /* 48 bitmap state information */ + __le32 chunksize; /* 52 the bitmap chunk size in bytes */ + __le32 daemon_sleep; /* 56 seconds between disk flushes */ + __le32 write_behind; /* 60 number of outstanding write-behind writes */ __u8 pad[256 - 64]; /* set to zero */ } bitmap_super_t; -- cgit v1.2.3 From d42552c3ace1fa1f16ae02ce642f4c733cec40ca Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 21 Oct 2006 10:24:12 -0700 Subject: [PATCH] pci: declare pci_get_device_reverse() We seem to have lost the declaration of pci_get_device_reverse(), if we ever had one. Add a CONFIG_PCI=0 stub too. Acked-by: Alan Cox Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pci.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index 4689e2a699c0..09be0f81b27b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -455,7 +455,11 @@ int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); int pci_find_ext_capability (struct pci_dev *dev, int cap); struct pci_bus *pci_find_next_bus(const struct pci_bus *from); -struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from); +struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, + struct pci_dev *from); +struct pci_dev *pci_get_device_reverse(unsigned int vendor, unsigned int device, + struct pci_dev *from); + struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from); @@ -660,7 +664,12 @@ static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) { return NULL; } -static inline struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from) +static inline struct pci_dev *pci_get_device(unsigned int vendor, + unsigned int device, struct pci_dev *from) +{ return NULL; } + +static inline struct pci_dev *pci_get_device_reverse(unsigned int vendor, + unsigned int device, struct pci_dev *from) { return NULL; } static inline struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, -- cgit v1.2.3 From 7516795739bd53175629b90fab0ad488d7a6a9f7 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Sat, 21 Oct 2006 10:24:14 -0700 Subject: [PATCH] Reintroduce NODES_SPAN_OTHER_NODES for powerpc Reintroduce NODES_SPAN_OTHER_NODES for powerpc Revert "[PATCH] Remove SPAN_OTHER_NODES config definition" This reverts commit f62859bb6871c5e4a8e591c60befc8caaf54db8c. Revert "[PATCH] mm: remove arch independent NODES_SPAN_OTHER_NODES" This reverts commit a94b3ab7eab4edcc9b2cb474b188f774c331adf7. Also update the comments to indicate that this is still required and where its used. Signed-off-by: Andy Whitcroft Cc: Paul Mackerras Cc: Mike Kravetz Cc: Benjamin Herrenschmidt Acked-by: Mel Gorman Acked-by: Will Schmidt Cc: Christoph Lameter Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/Kconfig | 9 +++++++++ arch/powerpc/configs/pseries_defconfig | 1 + include/linux/mmzone.h | 6 ++++++ mm/page_alloc.c | 2 ++ 4 files changed, 18 insertions(+) (limited to 'include/linux') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 8b6910465578..2bd9b7fb0f6c 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -751,6 +751,15 @@ config ARCH_MEMORY_PROBE def_bool y depends on MEMORY_HOTPLUG +# Some NUMA nodes have memory ranges that span +# other nodes. Even though a pfn is valid and +# between a node's start and end pfns, it may not +# reside on that node. See memmap_init_zone() +# for details. +config NODES_SPAN_OTHER_NODES + def_bool y + depends on NEED_MULTIPLE_NODES + config PPC_64K_PAGES bool "64k page size" depends on PPC64 diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 9828663652e9..d2833c1a1f3d 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -184,6 +184,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_MIGRATION=y CONFIG_RESOURCES_64BIT=y CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y +CONFIG_NODES_SPAN_OTHER_NODES=y # CONFIG_PPC_64K_PAGES is not set CONFIG_SCHED_SMT=y CONFIG_PROC_DEVICETREE=y diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 59855b8718a0..ed0762b283a9 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -674,6 +674,12 @@ void sparse_init(void); #define sparse_index_init(_sec, _nid) do {} while (0) #endif /* CONFIG_SPARSEMEM */ +#ifdef CONFIG_NODES_SPAN_OTHER_NODES +#define early_pfn_in_nid(pfn, nid) (early_pfn_to_nid(pfn) == (nid)) +#else +#define early_pfn_in_nid(pfn, nid) (1) +#endif + #ifndef early_pfn_valid #define early_pfn_valid(pfn) (1) #endif diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ebd425c2e2a7..f5fc45472d5c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1689,6 +1689,8 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, for (pfn = start_pfn; pfn < end_pfn; pfn++) { if (!early_pfn_valid(pfn)) continue; + if (!early_pfn_in_nid(pfn, nid)) + continue; page = pfn_to_page(pfn); set_page_links(page, zone, nid, pfn); init_page_count(page); -- cgit v1.2.3 From faf6bbcf94caee10ba34adb86db4ecca96bfd3bf Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sat, 21 Oct 2006 10:24:17 -0700 Subject: [PATCH] cpuset: mempolicy migration typo fix Mistyped an ifdef CONFIG_CPUSETS - fixed. I doubt that anyone ever noticed. The impact of this typo was that if someone: 1) was using MPOL_BIND to force off node allocations 2) while using cpusets to constrain memory placement 3) when that cpuset was migrating that jobs memory 4) while the tasks in that job were actively forking then there was a rare chance that future allocations using that MPOL_BIND policy would be node local, not off node. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mempolicy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 09f0f575ddff..daabb3aa1ec6 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -150,7 +150,7 @@ extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new); extern void mpol_fix_fork_child_flag(struct task_struct *p); #define set_cpuset_being_rebound(x) (cpuset_being_rebound = (x)) -#ifdef CONFIG_CPUSET +#ifdef CONFIG_CPUSETS #define current_cpuset_is_being_rebound() \ (cpuset_being_rebound == current->cpuset) #else -- cgit v1.2.3 From 04fed361dadb7921507a470947ac23d2f26352cf Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 22 Oct 2006 15:57:18 +0100 Subject: [PATCH] Remove __must_check for device_for_each_child() Eliminate more __must_check madness. The return code from device_for_each_child() depends on the values which the helper function returns. If the helper function always returns zero, it's utterly pointless to check the return code from device_for_each_child(). The only code which knows if the return value should be checked is the caller itself, so forcing the return code to always be checked is silly. Hence, remove the __must_check annotation. Signed-off-by: Russell King Signed-off-by: Linus Torvalds --- include/linux/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/device.h b/include/linux/device.h index 662e6a10144e..9d4f6a963936 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -393,7 +393,7 @@ extern void device_unregister(struct device * dev); extern void device_initialize(struct device * dev); extern int __must_check device_add(struct device * dev); extern void device_del(struct device * dev); -extern int __must_check device_for_each_child(struct device *, void *, +extern int device_for_each_child(struct device *, void *, int (*fn)(struct device *, void *)); extern int device_rename(struct device *dev, char *new_name); -- cgit v1.2.3 From 0344c6c5387ba335bba5a66fd44714b94c98573f Mon Sep 17 00:00:00 2001 From: Christian Krafft Date: Tue, 24 Oct 2006 18:31:24 +0200 Subject: [POWERPC] sysfs: add support for adding/removing spu sysfs attributes This patch adds two functions to create and remove sysfs attributes and attribute_group to all cpus. That allows to register sysfs attributes in a subdirectory like: /sys/devices/system/cpu/cpuX/group_name/what_ever This will be used by cbe_thermal to group all attributes dealing with thermal support in one directory. Signed-of-by: Christian Krafft Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/sysfs.c | 66 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/cpu.h | 8 ++++++ 2 files changed, 74 insertions(+) (limited to 'include/linux') diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index d45a168bdaca..cda21a27490a 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -299,6 +299,72 @@ static struct notifier_block __cpuinitdata sysfs_cpu_nb = { .notifier_call = sysfs_cpu_notify, }; +static DEFINE_MUTEX(cpu_mutex); + +int cpu_add_sysdev_attr(struct sysdev_attribute *attr) +{ + int cpu; + + mutex_lock(&cpu_mutex); + + for_each_possible_cpu(cpu) { + sysdev_create_file(get_cpu_sysdev(cpu), attr); + } + + mutex_unlock(&cpu_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr); + +int cpu_add_sysdev_attr_group(struct attribute_group *attrs) +{ + int cpu; + struct sys_device *sysdev; + + mutex_lock(&cpu_mutex); + + for_each_possible_cpu(cpu) { + sysdev = get_cpu_sysdev(cpu); + sysfs_create_group(&sysdev->kobj, attrs); + } + + mutex_unlock(&cpu_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr_group); + + +void cpu_remove_sysdev_attr(struct sysdev_attribute *attr) +{ + int cpu; + + mutex_lock(&cpu_mutex); + + for_each_possible_cpu(cpu) { + sysdev_remove_file(get_cpu_sysdev(cpu), attr); + } + + mutex_unlock(&cpu_mutex); +} +EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr); + +void cpu_remove_sysdev_attr_group(struct attribute_group *attrs) +{ + int cpu; + struct sys_device *sysdev; + + mutex_lock(&cpu_mutex); + + for_each_possible_cpu(cpu) { + sysdev = get_cpu_sysdev(cpu); + sysfs_remove_group(&sysdev->kobj, attrs); + } + + mutex_unlock(&cpu_mutex); +} +EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr_group); + + /* NUMA stuff */ #ifdef CONFIG_NUMA diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 3fef7d67aedc..f02d71bf6894 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -33,6 +33,14 @@ struct cpu { extern int register_cpu(struct cpu *cpu, int num); extern struct sys_device *get_cpu_sysdev(unsigned cpu); + +extern int cpu_add_sysdev_attr(struct sysdev_attribute *attr); +extern void cpu_remove_sysdev_attr(struct sysdev_attribute *attr); + +extern int cpu_add_sysdev_attr_group(struct attribute_group *attrs); +extern void cpu_remove_sysdev_attr_group(struct attribute_group *attrs); + + #ifdef CONFIG_HOTPLUG_CPU extern void unregister_cpu(struct cpu *cpu); #endif -- cgit v1.2.3 From 735a7ffb739b6efeaeb1e720306ba308eaaeb20e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 27 Oct 2006 11:42:37 -0700 Subject: [PATCH] drivers: wait for threaded probes between initcall levels The multithreaded-probing code has a problem: after one initcall level (eg, core_initcall) has been processed, we will then start processing the next level (postcore_initcall) while the kernel threads which are handling core_initcall are still executing. This breaks the guarantees which the layered initcalls previously gave us. IOW, we want to be multithreaded _within_ an initcall level, but not between different levels. Fix that up by causing the probing code to wait for all outstanding probes at one level to complete before we start processing the next level. Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/dd.c | 30 ++++++++++++++++++++++++++++++ include/asm-generic/vmlinux.lds.h | 9 ++++++++- include/linux/init.h | 28 +++++++++++++++++++--------- 3 files changed, 57 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index db01b95a47a5..c5d6bb4290ad 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "base.h" #include "power/power.h" @@ -70,6 +71,8 @@ struct stupid_thread_structure { }; static atomic_t probe_count = ATOMIC_INIT(0); +static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); + static int really_probe(void *void_data) { struct stupid_thread_structure *data = void_data; @@ -121,6 +124,7 @@ probe_failed: done: kfree(data); atomic_dec(&probe_count); + wake_up(&probe_waitqueue); return ret; } @@ -337,6 +341,32 @@ void driver_detach(struct device_driver * drv) } } +#ifdef CONFIG_PCI_MULTITHREAD_PROBE +static int __init wait_for_probes(void) +{ + DEFINE_WAIT(wait); + + printk(KERN_INFO "%s: waiting for %d threads\n", __FUNCTION__, + atomic_read(&probe_count)); + if (!atomic_read(&probe_count)) + return 0; + while (atomic_read(&probe_count)) { + prepare_to_wait(&probe_waitqueue, &wait, TASK_UNINTERRUPTIBLE); + if (atomic_read(&probe_count)) + schedule(); + } + finish_wait(&probe_waitqueue, &wait); + return 0; +} + +core_initcall_sync(wait_for_probes); +postcore_initcall_sync(wait_for_probes); +arch_initcall_sync(wait_for_probes); +subsys_initcall_sync(wait_for_probes); +fs_initcall_sync(wait_for_probes); +device_initcall_sync(wait_for_probes); +late_initcall_sync(wait_for_probes); +#endif EXPORT_SYMBOL_GPL(device_bind_driver); EXPORT_SYMBOL_GPL(device_release_driver); diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index e3e83bcaf710..9d873163a7ab 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -216,10 +216,17 @@ #define INITCALLS \ *(.initcall1.init) \ + *(.initcall1s.init) \ *(.initcall2.init) \ + *(.initcall2s.init) \ *(.initcall3.init) \ + *(.initcall3s.init) \ *(.initcall4.init) \ + *(.initcall4s.init) \ *(.initcall5.init) \ + *(.initcall5s.init) \ *(.initcall6.init) \ - *(.initcall7.init) + *(.initcall6s.init) \ + *(.initcall7.init) \ + *(.initcall7s.init) diff --git a/include/linux/init.h b/include/linux/init.h index e92b1455d7af..ff40ea118e3a 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -84,19 +84,29 @@ extern void setup_arch(char **); * by link order. * For backwards compatibility, initcall() puts the call in * the device init subsection. + * + * The `id' arg to __define_initcall() is needed so that multiple initcalls + * can point at the same handler without causing duplicate-symbol build errors. */ -#define __define_initcall(level,fn) \ - static initcall_t __initcall_##fn __attribute_used__ \ +#define __define_initcall(level,fn,id) \ + static initcall_t __initcall_##fn##id __attribute_used__ \ __attribute__((__section__(".initcall" level ".init"))) = fn -#define core_initcall(fn) __define_initcall("1",fn) -#define postcore_initcall(fn) __define_initcall("2",fn) -#define arch_initcall(fn) __define_initcall("3",fn) -#define subsys_initcall(fn) __define_initcall("4",fn) -#define fs_initcall(fn) __define_initcall("5",fn) -#define device_initcall(fn) __define_initcall("6",fn) -#define late_initcall(fn) __define_initcall("7",fn) +#define core_initcall(fn) __define_initcall("1",fn,1) +#define core_initcall_sync(fn) __define_initcall("1s",fn,1s) +#define postcore_initcall(fn) __define_initcall("2",fn,2) +#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s) +#define arch_initcall(fn) __define_initcall("3",fn,3) +#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s) +#define subsys_initcall(fn) __define_initcall("4",fn,4) +#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s) +#define fs_initcall(fn) __define_initcall("5",fn,5) +#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s) +#define device_initcall(fn) __define_initcall("6",fn,6) +#define device_initcall_sync(fn) __define_initcall("6s",fn,6s) +#define late_initcall(fn) __define_initcall("7",fn,7) +#define late_initcall_sync(fn) __define_initcall("7s",fn,7s) #define __initcall(fn) device_initcall(fn) -- cgit v1.2.3 From 2ae88149a27cadf2840e0ab8155bef13be285c03 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sat, 28 Oct 2006 10:38:23 -0700 Subject: [PATCH] mm: clean up pagecache allocation - Consolidate page_cache_alloc - Fix splice: only the pagecache pages and filesystem data need to use mapping_gfp_mask. - Fix grab_cache_page_nowait: same as splice, also honour NUMA placement. Signed-off-by: Nick Piggin Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/splice.c | 9 ++++----- include/linux/pagemap.h | 14 +++++++++----- mm/filemap.c | 24 ++++++------------------ 3 files changed, 19 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/fs/splice.c b/fs/splice.c index 49fb9f129938..8d705954d294 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -74,7 +74,7 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe, wait_on_page_writeback(page); if (PagePrivate(page)) - try_to_release_page(page, mapping_gfp_mask(mapping)); + try_to_release_page(page, GFP_KERNEL); /* * If we succeeded in removing the mapping, set LRU flag @@ -333,7 +333,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, break; error = add_to_page_cache_lru(page, mapping, index, - mapping_gfp_mask(mapping)); + GFP_KERNEL); if (unlikely(error)) { page_cache_release(page); if (error == -EEXIST) @@ -557,7 +557,6 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, { struct file *file = sd->file; struct address_space *mapping = file->f_mapping; - gfp_t gfp_mask = mapping_gfp_mask(mapping); unsigned int offset, this_len; struct page *page; pgoff_t index; @@ -591,7 +590,7 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, goto find_page; page = buf->page; - if (add_to_page_cache(page, mapping, index, gfp_mask)) { + if (add_to_page_cache(page, mapping, index, GFP_KERNEL)) { unlock_page(page); goto find_page; } @@ -613,7 +612,7 @@ find_page: * This will also lock the page */ ret = add_to_page_cache_lru(page, mapping, index, - gfp_mask); + GFP_KERNEL); if (unlikely(ret)) goto out; } diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 64f950925151..c3e255bf8594 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -52,19 +52,23 @@ static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask) void release_pages(struct page **pages, int nr, int cold); #ifdef CONFIG_NUMA -extern struct page *page_cache_alloc(struct address_space *x); -extern struct page *page_cache_alloc_cold(struct address_space *x); +extern struct page *__page_cache_alloc(gfp_t gfp); #else +static inline struct page *__page_cache_alloc(gfp_t gfp) +{ + return alloc_pages(gfp, 0); +} +#endif + static inline struct page *page_cache_alloc(struct address_space *x) { - return alloc_pages(mapping_gfp_mask(x), 0); + return __page_cache_alloc(mapping_gfp_mask(x)); } static inline struct page *page_cache_alloc_cold(struct address_space *x) { - return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0); + return __page_cache_alloc(mapping_gfp_mask(x)|__GFP_COLD); } -#endif typedef int filler_t(void *, struct page *); diff --git a/mm/filemap.c b/mm/filemap.c index cb26e33fd0ff..7b84dc814347 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -467,25 +467,15 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping, } #ifdef CONFIG_NUMA -struct page *page_cache_alloc(struct address_space *x) +struct page *__page_cache_alloc(gfp_t gfp) { if (cpuset_do_page_mem_spread()) { int n = cpuset_mem_spread_node(); - return alloc_pages_node(n, mapping_gfp_mask(x), 0); + return alloc_pages_node(n, gfp, 0); } - return alloc_pages(mapping_gfp_mask(x), 0); + return alloc_pages(gfp, 0); } -EXPORT_SYMBOL(page_cache_alloc); - -struct page *page_cache_alloc_cold(struct address_space *x) -{ - if (cpuset_do_page_mem_spread()) { - int n = cpuset_mem_spread_node(); - return alloc_pages_node(n, mapping_gfp_mask(x)|__GFP_COLD, 0); - } - return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0); -} -EXPORT_SYMBOL(page_cache_alloc_cold); +EXPORT_SYMBOL(__page_cache_alloc); #endif static int __sleep_on_page_lock(void *word) @@ -826,7 +816,6 @@ struct page * grab_cache_page_nowait(struct address_space *mapping, unsigned long index) { struct page *page = find_get_page(mapping, index); - gfp_t gfp_mask; if (page) { if (!TestSetPageLocked(page)) @@ -834,9 +823,8 @@ grab_cache_page_nowait(struct address_space *mapping, unsigned long index) page_cache_release(page); return NULL; } - gfp_mask = mapping_gfp_mask(mapping) & ~__GFP_FS; - page = alloc_pages(gfp_mask, 0); - if (page && add_to_page_cache_lru(page, mapping, index, gfp_mask)) { + page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~__GFP_FS); + if (page && add_to_page_cache_lru(page, mapping, index, GFP_KERNEL)) { page_cache_release(page); page = NULL; } -- cgit v1.2.3 From 3bb1a852ab6c9cdf211a2f4a2f502340c8c38eca Mon Sep 17 00:00:00 2001 From: Martin Bligh Date: Sat, 28 Oct 2006 10:38:24 -0700 Subject: [PATCH] vmscan: Fix temp_priority race The temp_priority field in zone is racy, as we can walk through a reclaim path, and just before we copy it into prev_priority, it can be overwritten (say with DEF_PRIORITY) by another reclaimer. The same bug is contained in both try_to_free_pages and balance_pgdat, but it is fixed slightly differently. In balance_pgdat, we keep a separate priority record per zone in a local array. In try_to_free_pages there is no need to do this, as the priority level is the same for all zones that we reclaim from. Impact of this bug is that temp_priority is copied into prev_priority, and setting this artificially high causes reclaimers to set distress artificially low. They then fail to reclaim mapped pages, when they are, in fact, under severe memory pressure (their priority may be as low as 0). This causes the OOM killer to fire incorrectly. From: Andrew Morton __zone_reclaim() isn't modifying zone->prev_priority. But zone->prev_priority is used in the decision whether or not to bring mapped pages onto the inactive list. Hence there's a risk here that __zone_reclaim() will fail because zone->prev_priority ir large (ie: low urgency) and lots of mapped pages end up stuck on the active list. Fix that up by decreasing (ie making more urgent) zone->prev_priority as __zone_reclaim() scans the zone's pages. This bug perhaps explains why ZONE_RECLAIM_PRIORITY was created. It should be possible to remove that now, and to just start out at DEF_PRIORITY? Cc: Nick Piggin Cc: Christoph Lameter Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 6 +----- mm/page_alloc.c | 2 +- mm/vmscan.c | 55 +++++++++++++++++++++++++++++++++++++------------- mm/vmstat.c | 2 -- 4 files changed, 43 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index ed0762b283a9..e06683e2bea3 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -218,13 +218,9 @@ struct zone { * under - it drives the swappiness decision: whether to unmap mapped * pages. * - * temp_priority is used to remember the scanning priority at which - * this zone was successfully refilled to free_pages == pages_high. - * - * Access to both these fields is quite racy even on uniprocessor. But + * Access to both this field is quite racy even on uniprocessor. But * it is expected to average out OK. */ - int temp_priority; int prev_priority; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f5fc45472d5c..ecf853b5e30e 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2407,7 +2407,7 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat, zone->zone_pgdat = pgdat; zone->free_pages = 0; - zone->temp_priority = zone->prev_priority = DEF_PRIORITY; + zone->prev_priority = DEF_PRIORITY; zone_pcp_init(zone); INIT_LIST_HEAD(&zone->active_list); diff --git a/mm/vmscan.c b/mm/vmscan.c index f05527bf792b..b32560ead5c0 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -723,6 +723,20 @@ done: return nr_reclaimed; } +/* + * We are about to scan this zone at a certain priority level. If that priority + * level is smaller (ie: more urgent) than the previous priority, then note + * that priority level within the zone. This is done so that when the next + * process comes in to scan this zone, it will immediately start out at this + * priority level rather than having to build up its own scanning priority. + * Here, this priority affects only the reclaim-mapped threshold. + */ +static inline void note_zone_scanning_priority(struct zone *zone, int priority) +{ + if (priority < zone->prev_priority) + zone->prev_priority = priority; +} + static inline int zone_is_near_oom(struct zone *zone) { return zone->pages_scanned >= (zone->nr_active + zone->nr_inactive)*3; @@ -972,9 +986,7 @@ static unsigned long shrink_zones(int priority, struct zone **zones, if (!cpuset_zone_allowed(zone, __GFP_HARDWALL)) continue; - zone->temp_priority = priority; - if (zone->prev_priority > priority) - zone->prev_priority = priority; + note_zone_scanning_priority(zone, priority); if (zone->all_unreclaimable && priority != DEF_PRIORITY) continue; /* Let kswapd poll it */ @@ -1024,7 +1036,6 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask) if (!cpuset_zone_allowed(zone, __GFP_HARDWALL)) continue; - zone->temp_priority = DEF_PRIORITY; lru_pages += zone->nr_active + zone->nr_inactive; } @@ -1065,13 +1076,22 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask) if (!sc.all_unreclaimable) ret = 1; out: + /* + * Now that we've scanned all the zones at this priority level, note + * that level within the zone so that the next thread which performs + * scanning of this zone will immediately start out at this priority + * level. This affects only the decision whether or not to bring + * mapped pages onto the inactive list. + */ + if (priority < 0) + priority = 0; for (i = 0; zones[i] != 0; i++) { struct zone *zone = zones[i]; if (!cpuset_zone_allowed(zone, __GFP_HARDWALL)) continue; - zone->prev_priority = zone->temp_priority; + zone->prev_priority = priority; } return ret; } @@ -1111,6 +1131,11 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order) .swap_cluster_max = SWAP_CLUSTER_MAX, .swappiness = vm_swappiness, }; + /* + * temp_priority is used to remember the scanning priority at which + * this zone was successfully refilled to free_pages == pages_high. + */ + int temp_priority[MAX_NR_ZONES]; loop_again: total_scanned = 0; @@ -1118,11 +1143,8 @@ loop_again: sc.may_writepage = !laptop_mode; count_vm_event(PAGEOUTRUN); - for (i = 0; i < pgdat->nr_zones; i++) { - struct zone *zone = pgdat->node_zones + i; - - zone->temp_priority = DEF_PRIORITY; - } + for (i = 0; i < pgdat->nr_zones; i++) + temp_priority[i] = DEF_PRIORITY; for (priority = DEF_PRIORITY; priority >= 0; priority--) { int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */ @@ -1183,10 +1205,9 @@ scan: if (!zone_watermark_ok(zone, order, zone->pages_high, end_zone, 0)) all_zones_ok = 0; - zone->temp_priority = priority; - if (zone->prev_priority > priority) - zone->prev_priority = priority; + temp_priority[i] = priority; sc.nr_scanned = 0; + note_zone_scanning_priority(zone, priority); nr_reclaimed += shrink_zone(priority, zone, &sc); reclaim_state->reclaimed_slab = 0; nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL, @@ -1226,10 +1247,15 @@ scan: break; } out: + /* + * Note within each zone the priority level at which this zone was + * brought into a happy state. So that the next thread which scans this + * zone will start out at that priority level. + */ for (i = 0; i < pgdat->nr_zones; i++) { struct zone *zone = pgdat->node_zones + i; - zone->prev_priority = zone->temp_priority; + zone->prev_priority = temp_priority[i]; } if (!all_zones_ok) { cond_resched(); @@ -1614,6 +1640,7 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) */ priority = ZONE_RECLAIM_PRIORITY; do { + note_zone_scanning_priority(zone, priority); nr_reclaimed += shrink_zone(priority, zone, &sc); priority--; } while (priority >= 0 && nr_reclaimed < nr_pages); diff --git a/mm/vmstat.c b/mm/vmstat.c index 45b124e012f5..8614e8f6743b 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -587,11 +587,9 @@ static int zoneinfo_show(struct seq_file *m, void *arg) seq_printf(m, "\n all_unreclaimable: %u" "\n prev_priority: %i" - "\n temp_priority: %i" "\n start_pfn: %lu", zone->all_unreclaimable, zone->prev_priority, - zone->temp_priority, zone->zone_start_pfn); spin_unlock_irqrestore(&zone->lock, flags); seq_putc(m, '\n'); -- cgit v1.2.3 From 52fd24ca1db3a741f144bbc229beefe044202cac Mon Sep 17 00:00:00 2001 From: Giridhar Pemmasani Date: Sat, 28 Oct 2006 10:38:34 -0700 Subject: [PATCH] __vmalloc with GFP_ATOMIC causes 'sleeping from invalid context' If __vmalloc is called to allocate memory with GFP_ATOMIC in atomic context, the chain of calls results in __get_vm_area_node allocating memory for vm_struct with GFP_KERNEL, causing the 'sleeping from invalid context' warning. This patch fixes it by passing the gfp flags along so __get_vm_area_node allocates memory for vm_struct with the same flags. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmalloc.h | 3 ++- mm/vmalloc.c | 18 +++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index ce5f1482e6be..dc9a29d84abc 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -60,7 +60,8 @@ extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags); extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, unsigned long start, unsigned long end); extern struct vm_struct *get_vm_area_node(unsigned long size, - unsigned long flags, int node); + unsigned long flags, int node, + gfp_t gfp_mask); extern struct vm_struct *remove_vm_area(void *addr); extern int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 1133dd3aafcf..6d381df7c9b3 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -160,13 +160,15 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages) return err; } -struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, - unsigned long start, unsigned long end, int node) +static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, + unsigned long start, unsigned long end, + int node, gfp_t gfp_mask) { struct vm_struct **p, *tmp, *area; unsigned long align = 1; unsigned long addr; + BUG_ON(in_interrupt()); if (flags & VM_IOREMAP) { int bit = fls(size); @@ -180,7 +182,7 @@ struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, addr = ALIGN(start, align); size = PAGE_ALIGN(size); - area = kmalloc_node(sizeof(*area), GFP_KERNEL, node); + area = kmalloc_node(sizeof(*area), gfp_mask, node); if (unlikely(!area)) return NULL; @@ -236,7 +238,7 @@ out: struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, unsigned long start, unsigned long end) { - return __get_vm_area_node(size, flags, start, end, -1); + return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL); } /** @@ -253,9 +255,11 @@ struct vm_struct *get_vm_area(unsigned long size, unsigned long flags) return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END); } -struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int node) +struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, + int node, gfp_t gfp_mask) { - return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node); + return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node, + gfp_mask); } /* Caller must hold vmlist_lock */ @@ -487,7 +491,7 @@ static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot, if (!size || (size >> PAGE_SHIFT) > num_physpages) return NULL; - area = get_vm_area_node(size, VM_ALLOC, node); + area = get_vm_area_node(size, VM_ALLOC, node, gfp_mask); if (!area) return NULL; -- cgit v1.2.3 From 5fa3839a64203b2ab727dcb37da9b2d7079fca28 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Sat, 28 Oct 2006 10:38:46 -0700 Subject: [PATCH] Constify compat_get_bitmap argument This means we can call it when the bitmap we want to fetch is declared const. Signed-off-by: Stephen Rothwell Cc: Christoph Lameter Cc: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/compat.h | 2 +- kernel/compat.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/compat.h b/include/linux/compat.h index f4ebf96f5308..f1553196826f 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -196,7 +196,7 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, #define BITS_TO_COMPAT_LONGS(bits) \ (((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG) -long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask, +long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, unsigned long bitmap_size); long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, unsigned long bitmap_size); diff --git a/kernel/compat.c b/kernel/compat.c index 75573e5d27b0..d4898aad6cfa 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -678,7 +678,7 @@ int get_compat_sigevent(struct sigevent *event, ? -EFAULT : 0; } -long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask, +long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, unsigned long bitmap_size) { int i, j; -- cgit v1.2.3 From 093a8e8aecd77b2799934996a55a6838e1e2b8f3 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 28 Oct 2006 10:38:51 -0700 Subject: [PATCH] taskstats_tgid_free: fix usage taskstats_tgid_free() is called on copy_process's error path. This is wrong. IF (clone_flags & CLONE_THREAD) We should not clear ->signal->taskstats, current uses it, it probably has a valid accumulated info. ELSE taskstats_tgid_init() set ->signal->taskstats = NULL, there is nothing to free. Move the callsite to __exit_signal(). We don't need any locking, entire thread group is exiting, nobody should have a reference to soon to be released ->signal. Signed-off-by: Oleg Nesterov Cc: Shailabh Nagar Cc: Balbir Singh Cc: Jay Lan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/taskstats_kern.h | 13 ++----------- kernel/exit.c | 1 + kernel/fork.c | 1 - 3 files changed, 3 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h index 16894b7edcc8..a437ca0d226b 100644 --- a/include/linux/taskstats_kern.h +++ b/include/linux/taskstats_kern.h @@ -49,17 +49,8 @@ static inline void taskstats_tgid_alloc(struct signal_struct *sig) static inline void taskstats_tgid_free(struct signal_struct *sig) { - struct taskstats *stats = NULL; - unsigned long flags; - - spin_lock_irqsave(&sig->stats_lock, flags); - if (sig->stats) { - stats = sig->stats; - sig->stats = NULL; - } - spin_unlock_irqrestore(&sig->stats_lock, flags); - if (stats) - kmem_cache_free(taskstats_cache, stats); + if (sig->stats) + kmem_cache_free(taskstats_cache, sig->stats); } extern void taskstats_exit_alloc(struct taskstats **, unsigned int *); diff --git a/kernel/exit.c b/kernel/exit.c index f250a5e3e281..06de6c4e8ca3 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -128,6 +128,7 @@ static void __exit_signal(struct task_struct *tsk) flush_sigqueue(&tsk->pending); if (sig) { flush_sigqueue(&sig->shared_pending); + taskstats_tgid_free(sig); __cleanup_signal(sig); } } diff --git a/kernel/fork.c b/kernel/fork.c index 29ebb30850ed..213326609bac 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -897,7 +897,6 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts void __cleanup_signal(struct signal_struct *sig) { exit_thread_group_keys(sig); - taskstats_tgid_free(sig); kmem_cache_free(signal_cachep, sig); } -- cgit v1.2.3 From 17b02695b254aa2ef0e53df9c8e6548f86e66a9d Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 28 Oct 2006 10:38:52 -0700 Subject: [PATCH] taskstats_tgid_alloc: optimization Every subthread (except first) does unneeded kmem_cache_alloc/kmem_cache_free. Signed-off-by: Oleg Nesterov Cc: Shailabh Nagar Cc: Balbir Singh Cc: Jay Lan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/taskstats_kern.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h index a437ca0d226b..664224008fb2 100644 --- a/include/linux/taskstats_kern.h +++ b/include/linux/taskstats_kern.h @@ -32,6 +32,9 @@ static inline void taskstats_tgid_alloc(struct signal_struct *sig) struct taskstats *stats; unsigned long flags; + if (sig->stats != NULL) + return; + stats = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL); if (!stats) return; -- cgit v1.2.3 From b8534d7bd89df0cd41cd47bcd6733a05ea9a691a Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 28 Oct 2006 10:38:53 -0700 Subject: [PATCH] taskstats: kill ->taskstats_lock in favor of ->siglock signal_struct is (mostly) protected by ->sighand->siglock, I think we don't need ->taskstats_lock to protect ->stats. This also allows us to simplify the locking in fill_tgid(). Signed-off-by: Oleg Nesterov Cc: Shailabh Nagar Cc: Balbir Singh Cc: Jay Lan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 - include/linux/taskstats_kern.h | 15 ++++++--------- kernel/fork.c | 2 +- kernel/taskstats.c | 16 ++++++---------- 4 files changed, 13 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 6735c1cf334c..eafe4a7b8237 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -466,7 +466,6 @@ struct signal_struct { struct pacct_struct pacct; /* per-process accounting information */ #endif #ifdef CONFIG_TASKSTATS - spinlock_t stats_lock; struct taskstats *stats; #endif }; diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h index 664224008fb2..6562a2050a25 100644 --- a/include/linux/taskstats_kern.h +++ b/include/linux/taskstats_kern.h @@ -23,28 +23,26 @@ static inline void taskstats_exit_free(struct taskstats *tidstats) static inline void taskstats_tgid_init(struct signal_struct *sig) { - spin_lock_init(&sig->stats_lock); sig->stats = NULL; } -static inline void taskstats_tgid_alloc(struct signal_struct *sig) +static inline void taskstats_tgid_alloc(struct task_struct *tsk) { + struct signal_struct *sig = tsk->signal; struct taskstats *stats; - unsigned long flags; if (sig->stats != NULL) return; + /* No problem if kmem_cache_zalloc() fails */ stats = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL); - if (!stats) - return; - spin_lock_irqsave(&sig->stats_lock, flags); + spin_lock_irq(&tsk->sighand->siglock); if (!sig->stats) { sig->stats = stats; stats = NULL; } - spin_unlock_irqrestore(&sig->stats_lock, flags); + spin_unlock_irq(&tsk->sighand->siglock); if (stats) kmem_cache_free(taskstats_cache, stats); @@ -59,7 +57,6 @@ static inline void taskstats_tgid_free(struct signal_struct *sig) extern void taskstats_exit_alloc(struct taskstats **, unsigned int *); extern void taskstats_exit_send(struct task_struct *, struct taskstats *, int, unsigned int); extern void taskstats_init_early(void); -extern void taskstats_tgid_alloc(struct signal_struct *); #else static inline void taskstats_exit_alloc(struct taskstats **ptidstats, unsigned int *mycpu) {} @@ -71,7 +68,7 @@ static inline void taskstats_exit_send(struct task_struct *tsk, {} static inline void taskstats_tgid_init(struct signal_struct *sig) {} -static inline void taskstats_tgid_alloc(struct signal_struct *sig) +static inline void taskstats_tgid_alloc(struct task_struct *tsk) {} static inline void taskstats_tgid_free(struct signal_struct *sig) {} diff --git a/kernel/fork.c b/kernel/fork.c index 213326609bac..3da978eec791 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -830,7 +830,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts if (clone_flags & CLONE_THREAD) { atomic_inc(¤t->signal->count); atomic_inc(¤t->signal->live); - taskstats_tgid_alloc(current->signal); + taskstats_tgid_alloc(current); return 0; } sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL); diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 9aeee511a463..b2efda94615a 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -241,11 +241,11 @@ static int fill_tgid(pid_t tgid, struct task_struct *tgidtsk, tsk = first; read_lock(&tasklist_lock); /* Start with stats from dead tasks */ - if (first->signal) { - spin_lock_irqsave(&first->signal->stats_lock, flags); + if (first->sighand) { + spin_lock_irqsave(&first->sighand->siglock, flags); if (first->signal->stats) memcpy(stats, first->signal->stats, sizeof(*stats)); - spin_unlock_irqrestore(&first->signal->stats_lock, flags); + spin_unlock_irqrestore(&first->sighand->siglock, flags); } do { @@ -276,7 +276,7 @@ static void fill_tgid_exit(struct task_struct *tsk) { unsigned long flags; - spin_lock_irqsave(&tsk->signal->stats_lock, flags); + spin_lock_irqsave(&tsk->sighand->siglock, flags); if (!tsk->signal->stats) goto ret; @@ -288,7 +288,7 @@ static void fill_tgid_exit(struct task_struct *tsk) */ delayacct_add_tsk(tsk->signal->stats, tsk); ret: - spin_unlock_irqrestore(&tsk->signal->stats_lock, flags); + spin_unlock_irqrestore(&tsk->sighand->siglock, flags); return; } @@ -464,15 +464,10 @@ void taskstats_exit_send(struct task_struct *tsk, struct taskstats *tidstats, size_t size; int is_thread_group; struct nlattr *na; - unsigned long flags; if (!family_registered || !tidstats) return; - spin_lock_irqsave(&tsk->signal->stats_lock, flags); - is_thread_group = tsk->signal->stats ? 1 : 0; - spin_unlock_irqrestore(&tsk->signal->stats_lock, flags); - rc = 0; /* * Size includes space for nested attributes @@ -480,6 +475,7 @@ void taskstats_exit_send(struct task_struct *tsk, struct taskstats *tidstats, size = nla_total_size(sizeof(u32)) + nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); + is_thread_group = (tsk->signal->stats != NULL); if (is_thread_group) size = 2 * size; /* PID + STATS + TGID + STATS */ -- cgit v1.2.3 From 7259f0d05d595b73ef312a082e628627c6414969 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 29 Oct 2006 22:46:36 -0800 Subject: [PATCH] lockdep: annotate DECLARE_WAIT_QUEUE_HEAD kernel: INFO: trying to register non-static key. kernel: the code is fine but needs lockdep annotation. kernel: turning off the locking correctness validator. kernel: [] show_trace_log_lvl+0x58/0x16a kernel: [] show_trace+0xd/0x10 kernel: [] dump_stack+0x19/0x1b kernel: [] __lock_acquire+0xf0/0x90d kernel: [] lock_acquire+0x4b/0x6b kernel: [] _spin_lock_irqsave+0x22/0x32 kernel: [] prepare_to_wait+0x17/0x4b kernel: [] lpfc_do_work+0xdd/0xcc2 [lpfc] kernel: [] kthread+0xc3/0xf2 kernel: [] kernel_thread_helper+0x5/0xb Another case of non-static lockdep keys; duplicate the paradigm set by DECLARE_COMPLETION_ONSTACK and introduce DECLARE_WAIT_QUEUE_HEAD_ONSTACK. Signed-off-by: Peter Zijlstra Cc: Greg KH Cc: Markus Lidel Acked-by: Ingo Molnar Cc: Arjan van de Ven Cc: James Bottomley Cc: Marcel Holtmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/bluetooth/bluecard_cs.c | 2 +- drivers/message/i2o/exec-osm.c | 2 +- drivers/scsi/dpt/dpti_i2o.h | 2 +- drivers/scsi/imm.c | 2 +- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 4 ++-- drivers/scsi/ppa.c | 2 +- drivers/usb/net/usbnet.c | 2 +- include/linux/wait.h | 9 +++++++++ 9 files changed, 18 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 845b8680032a..cbc07250b898 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -282,7 +282,7 @@ static void bluecard_write_wakeup(bluecard_info_t *info) clear_bit(ready_bit, &(info->tx_state)); if (bt_cb(skb)->pkt_type & 0x80) { - DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); DEFINE_WAIT(wait); unsigned char baud_reg; diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index 01a5a702b037..a2350640384b 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -124,7 +124,7 @@ static void i2o_exec_wait_free(struct i2o_exec_wait *wait) int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg, unsigned long timeout, struct i2o_dma *dma) { - DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); struct i2o_exec_wait *wait; static u32 tcntxt = 0x80000000; unsigned long flags; diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h index b3fa7ed71faf..5a49216fe4cf 100644 --- a/drivers/scsi/dpt/dpti_i2o.h +++ b/drivers/scsi/dpt/dpti_i2o.h @@ -49,7 +49,7 @@ #include typedef wait_queue_head_t adpt_wait_queue_head_t; -#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD(wait) +#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait) typedef wait_queue_t adpt_wait_queue_t; /* diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 2d95ac9c32c1..e31f6122106f 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -1153,7 +1153,7 @@ static int __imm_attach(struct parport *pb) { struct Scsi_Host *host; imm_struct *dev; - DECLARE_WAIT_QUEUE_HEAD(waiting); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); DEFINE_WAIT(wait); int ports; int modes, ppb; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index d586c3d3b0d0..19c79a0549a7 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -305,7 +305,7 @@ lpfc_do_work(void *p) { struct lpfc_hba *phba = p; int rc; - DECLARE_WAIT_QUEUE_HEAD(work_waitq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(work_waitq); set_user_nice(current, -20); phba->work_wait = &work_waitq; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 24a1779b9af4..582f5ea4e84e 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2983,7 +2983,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, struct lpfc_iocbq * prspiocbq, uint32_t timeout) { - DECLARE_WAIT_QUEUE_HEAD(done_q); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); long timeleft, timeout_req = 0; int retval = IOCB_SUCCESS; uint32_t creg_val; @@ -3061,7 +3061,7 @@ int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, uint32_t timeout) { - DECLARE_WAIT_QUEUE_HEAD(done_q); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); DECLARE_WAITQUEUE(wq_entry, current); uint32_t timeleft = 0; int retval; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index b0eba39f208a..89a2a9f11e41 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -1012,7 +1012,7 @@ static LIST_HEAD(ppa_hosts); static int __ppa_attach(struct parport *pb) { struct Scsi_Host *host; - DECLARE_WAIT_QUEUE_HEAD(waiting); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); DEFINE_WAIT(wait); ppa_struct *dev; int ports; diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index cf3d20eb781c..40873635d80e 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -554,7 +554,7 @@ static int usbnet_stop (struct net_device *net) { struct usbnet *dev = netdev_priv(net); int temp; - DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); DECLARE_WAITQUEUE (wait, current); netif_stop_queue (net); diff --git a/include/linux/wait.h b/include/linux/wait.h index b3b9048421d8..e820d00e1383 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -79,6 +79,15 @@ struct task_struct; extern void init_waitqueue_head(wait_queue_head_t *q); +#ifdef CONFIG_LOCKDEP +# define __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) \ + ({ init_waitqueue_head(&name); name; }) +# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) \ + wait_queue_head_t name = __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) +#else +# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) DECLARE_WAIT_QUEUE_HEAD(name) +#endif + static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p) { q->flags = 0; -- cgit v1.2.3 From 351edd240d0ba8620789ca9e24f5a38b62157f23 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 29 Oct 2006 22:46:40 -0800 Subject: [PATCH] MTD: fix last kernel-doc warning Fix the last current kernel-doc warning: Warning(/var/linsrc/linux-2619-rc3g5//include/linux/mtd/nand.h:416): No description found for parameter 'write_page' Signed-off-by: Randy Dunlap Cc: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mtd/nand.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 70420bbae82b..8b3ef4187219 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -355,7 +355,7 @@ struct nand_buffers { * @priv: [OPTIONAL] pointer to private chip date * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks * (determine if errors are correctable) - * @write_page [REPLACEABLE] High-level page write function + * @write_page: [REPLACEABLE] High-level page write function */ struct nand_chip { -- cgit v1.2.3 From 6e42acc4115bc376b8523acbcba2b2b7cc27d016 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 27 Oct 2006 19:08:42 -0700 Subject: [PATCH] libata: unexport ata_dev_revalidate() ata_dev_revalidate() isn't used outside of libata core. Unexport it. Signed-off-by: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 - drivers/ata/libata.h | 1 + include/linux/libata.h | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 83728a9457ad..a8fd0c3e59b3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6122,7 +6122,6 @@ EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); -EXPORT_SYMBOL_GPL(ata_dev_revalidate); EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_pair); EXPORT_SYMBOL_GPL(ata_port_disable); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a5ecb71390a9..0ed263be652a 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -53,6 +53,7 @@ extern unsigned ata_exec_internal(struct ata_device *dev, extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, int post_reset, u16 *id); +extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); extern int ata_dev_configure(struct ata_device *dev, int print_info); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); diff --git a/include/linux/libata.h b/include/linux/libata.h index b03d5a340dc8..abd2debebca2 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -702,7 +702,6 @@ extern int ata_std_prereset(struct ata_port *ap); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); -extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); extern void ata_port_disable(struct ata_port *); extern void ata_std_ports(struct ata_ioports *ioaddr); #ifdef CONFIG_PCI -- cgit v1.2.3 From 4fa2eeeac5e13a8579ee45bc172eed690d28fbb7 Mon Sep 17 00:00:00 2001 From: Peer Chen Date: Thu, 2 Nov 2006 18:55:48 -0500 Subject: pci_ids.h: Add NVIDIA PCI ID Signed-off-by: Jeff Garzik --- include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f3a168f3c9df..fa4e1d799782 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1213,6 +1213,7 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451 #define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452 #define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560 #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_TT128 0x9128 -- cgit v1.2.3 From 86f4f0f9ba6e35fbbc409dfc3d8615c1a9822482 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Thu, 2 Nov 2006 22:07:05 -0800 Subject: [PATCH] fix UFS superblock alignment issues ufs2 fails to mount on x86_64, claiming bad magic. This is because ufs_super_block_third's fs_un1 member is padded out by 4 bytes for 8-byte alignment, pushing down the rest of the struct. Forcing this to be packed solves it. I took a quick look over other on-disk structures and didn't immediately find other problems. I was able to mount & ls a populated ufs2 filesystem w/ this change. Signed-off-by: Eric Sandeen Cc: Evgeniy Dushistov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/ufs_fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h index 61eef508b041..28967eda9d7b 100644 --- a/include/linux/ufs_fs.h +++ b/include/linux/ufs_fs.h @@ -908,7 +908,7 @@ struct ufs_super_block_third { __fs64 fs_csaddr; /* blk addr of cyl grp summary area */ __fs64 fs_pendingblocks;/* blocks in process of being freed */ __fs32 fs_pendinginodes;/*inodes in process of being freed */ - } fs_u2; + } __attribute__ ((packed)) fs_u2; } fs_un1; union { struct { -- cgit v1.2.3 From f46c483357c2d87606bbefb511321e3efd4baae0 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 2 Nov 2006 22:07:16 -0800 Subject: [PATCH] Add printk_timed_ratelimit() printk_ratelimit() has global state which makes it not useful for callers which wish to perform ratelimiting at a particular frequency. Add a printk_timed_ratelimit() which utilises caller-provided state storage to permit more flexibility. This function can in fact be used for things other than printk ratelimiting and is perhaps poorly named. Cc: Ulrich Drepper Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 2 ++ kernel/printk.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 80f39cab470a..24b611147adb 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -171,6 +171,8 @@ __attribute_const__ roundup_pow_of_two(unsigned long x) extern int printk_ratelimit(void); extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst); +extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, + unsigned int interval_msec); static inline void console_silent(void) { diff --git a/kernel/printk.c b/kernel/printk.c index f7d427ef5038..66426552fbfe 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -1101,3 +1102,23 @@ int printk_ratelimit(void) printk_ratelimit_burst); } EXPORT_SYMBOL(printk_ratelimit); + +/** + * printk_timed_ratelimit - caller-controlled printk ratelimiting + * @caller_jiffies: pointer to caller's state + * @interval_msecs: minimum interval between prints + * + * printk_timed_ratelimit() returns true if more than @interval_msecs + * milliseconds have elapsed since the last time printk_timed_ratelimit() + * returned true. + */ +bool printk_timed_ratelimit(unsigned long *caller_jiffies, + unsigned int interval_msecs) +{ + if (*caller_jiffies == 0 || time_after(jiffies, *caller_jiffies)) { + *caller_jiffies = jiffies + msecs_to_jiffies(interval_msecs); + return true; + } + return false; +} +EXPORT_SYMBOL(printk_timed_ratelimit); -- cgit v1.2.3 From b918f6e62cd46774f9fc0a3fbba6bd10ad85ee14 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 2 Nov 2006 22:07:19 -0800 Subject: [PATCH] swsusp: debugging Add a swsusp debugging mode. This does everything that's needed for a suspend except for actually suspending. So we can look in the log messages and work out a) what code is being slow and b) which drivers are misbehaving. (1) # echo testproc > /sys/power/disk # echo disk > /sys/power/state This should turn off the non-boot CPU, freeze all processes, wait for 5 seconds and then thaw the processes and the CPU. (2) # echo test > /sys/power/disk # echo disk > /sys/power/state This should turn off the non-boot CPU, freeze all processes, shrink memory, suspend all devices, wait for 5 seconds, resume the devices etc. Cc: Pavel Machek Cc: Stefan Seyfried Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/testing/sysfs-power | 17 +++++++++++++++- Documentation/power/interface.txt | 13 ++++++++++++ include/linux/pm.h | 4 +++- kernel/power/disk.c | 37 ++++++++++++++++++++++++++--------- 4 files changed, 60 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index d882f8093871..dcff4d0623ad 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -21,7 +21,7 @@ Description: these states. What: /sys/power/disk -Date: August 2006 +Date: September 2006 Contact: Rafael J. Wysocki Description: The /sys/power/disk file controls the operating mode of the @@ -39,6 +39,19 @@ Description: 'reboot' - the memory image will be saved by the kernel and the system will be rebooted. + Additionally, /sys/power/disk can be used to turn on one of the + two testing modes of the suspend-to-disk mechanism: 'testproc' + or 'test'. If the suspend-to-disk mechanism is in the + 'testproc' mode, writing 'disk' to /sys/power/state will cause + the kernel to disable nonboot CPUs and freeze tasks, wait for 5 + seconds, unfreeze tasks and enable nonboot CPUs. If it is in + the 'test' mode, writing 'disk' to /sys/power/state will cause + the kernel to disable nonboot CPUs and freeze tasks, shrink + memory, suspend devices, wait for 5 seconds, resume devices, + unfreeze tasks and enable nonboot CPUs. Then, we are able to + look in the log messages and work out, for example, which code + is being slow and which device drivers are misbehaving. + The suspend-to-disk method may be chosen by writing to this file one of the accepted strings: @@ -46,6 +59,8 @@ Description: 'platform' 'shutdown' 'reboot' + 'testproc' + 'test' It will only change to 'firmware' or 'platform' if the system supports that. diff --git a/Documentation/power/interface.txt b/Documentation/power/interface.txt index a66bec222b16..74311d7e0f3c 100644 --- a/Documentation/power/interface.txt +++ b/Documentation/power/interface.txt @@ -30,6 +30,17 @@ testing). The system will support either 'firmware' or 'platform', and that is known a priori. But, the user may choose 'shutdown' or 'reboot' as alternatives. +Additionally, /sys/power/disk can be used to turn on one of the two testing +modes of the suspend-to-disk mechanism: 'testproc' or 'test'. If the +suspend-to-disk mechanism is in the 'testproc' mode, writing 'disk' to +/sys/power/state will cause the kernel to disable nonboot CPUs and freeze +tasks, wait for 5 seconds, unfreeze tasks and enable nonboot CPUs. If it is +in the 'test' mode, writing 'disk' to /sys/power/state will cause the kernel +to disable nonboot CPUs and freeze tasks, shrink memory, suspend devices, wait +for 5 seconds, resume devices, unfreeze tasks and enable nonboot CPUs. Then, +we are able to look in the log messages and work out, for example, which code +is being slow and which device drivers are misbehaving. + Reading from this file will display what the mode is currently set to. Writing to this file will accept one of @@ -37,6 +48,8 @@ to. Writing to this file will accept one of 'platform' 'shutdown' 'reboot' + 'testproc' + 'test' It will only change to 'firmware' or 'platform' if the system supports it. diff --git a/include/linux/pm.h b/include/linux/pm.h index 6b27e07aef19..070394e846d0 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -116,7 +116,9 @@ typedef int __bitwise suspend_disk_method_t; #define PM_DISK_PLATFORM ((__force suspend_disk_method_t) 2) #define PM_DISK_SHUTDOWN ((__force suspend_disk_method_t) 3) #define PM_DISK_REBOOT ((__force suspend_disk_method_t) 4) -#define PM_DISK_MAX ((__force suspend_disk_method_t) 5) +#define PM_DISK_TEST ((__force suspend_disk_method_t) 5) +#define PM_DISK_TESTPROC ((__force suspend_disk_method_t) 6) +#define PM_DISK_MAX ((__force suspend_disk_method_t) 7) struct pm_ops { suspend_disk_method_t pm_disk_mode; diff --git a/kernel/power/disk.c b/kernel/power/disk.c index d3a158a60312..b1fb7866b0b3 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -71,7 +71,7 @@ static inline void platform_finish(void) static int prepare_processes(void) { - int error; + int error = 0; pm_prepare_console(); @@ -84,6 +84,12 @@ static int prepare_processes(void) goto thaw; } + if (pm_disk_mode == PM_DISK_TESTPROC) { + printk("swsusp debug: Waiting for 5 seconds.\n"); + mdelay(5000); + goto thaw; + } + /* Free memory before shutting down devices. */ if (!(error = swsusp_shrink_memory())) return 0; @@ -120,13 +126,21 @@ int pm_suspend_disk(void) if (error) return error; + if (pm_disk_mode == PM_DISK_TESTPROC) + goto Thaw; + suspend_console(); error = device_suspend(PMSG_FREEZE); if (error) { resume_console(); printk("Some devices failed to suspend\n"); - unprepare_processes(); - return error; + goto Thaw; + } + + if (pm_disk_mode == PM_DISK_TEST) { + printk("swsusp debug: Waiting for 5 seconds.\n"); + mdelay(5000); + goto Done; } pr_debug("PM: snapshotting memory.\n"); @@ -143,16 +157,17 @@ int pm_suspend_disk(void) power_down(pm_disk_mode); else { swsusp_free(); - unprepare_processes(); - return error; + goto Thaw; } - } else + } else { pr_debug("PM: Image restored successfully.\n"); + } swsusp_free(); Done: device_resume(); resume_console(); + Thaw: unprepare_processes(); return error; } @@ -249,6 +264,8 @@ static const char * const pm_disk_modes[] = { [PM_DISK_PLATFORM] = "platform", [PM_DISK_SHUTDOWN] = "shutdown", [PM_DISK_REBOOT] = "reboot", + [PM_DISK_TEST] = "test", + [PM_DISK_TESTPROC] = "testproc", }; /** @@ -303,17 +320,19 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n) } } if (mode) { - if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT) + if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT || + mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) { pm_disk_mode = mode; - else { + } else { if (pm_ops && pm_ops->enter && (mode == pm_ops->pm_disk_mode)) pm_disk_mode = mode; else error = -EINVAL; } - } else + } else { error = -EINVAL; + } pr_debug("PM: suspend-to-disk mode set to '%s'\n", pm_disk_modes[mode]); -- cgit v1.2.3 From 3fd593979802f81ff6452596ac61e3840f917589 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 2 Nov 2006 22:07:24 -0800 Subject: [PATCH] Create compat_sys_migrate_pages This is needed on bigendian 64bit architectures. Signed-off-by: Stephen Rothwell Acked-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/compat.h | 4 ++++ kernel/compat.c | 33 +++++++++++++++++++++++++++++++++ kernel/sys_ni.c | 1 + 3 files changed, 38 insertions(+) (limited to 'include/linux') diff --git a/include/linux/compat.h b/include/linux/compat.h index f1553196826f..80b17f440ec1 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -230,5 +230,9 @@ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); extern int compat_printk(const char *fmt, ...); extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); +asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, + compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, + const compat_ulong_t __user *new_nodes); + #endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */ diff --git a/kernel/compat.c b/kernel/compat.c index d4898aad6cfa..6952dd057300 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -982,4 +982,37 @@ asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages, } return sys_move_pages(pid, nr_pages, pages, nodes, status, flags); } + +asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, + compat_ulong_t maxnode, + const compat_ulong_t __user *old_nodes, + const compat_ulong_t __user *new_nodes) +{ + unsigned long __user *old = NULL; + unsigned long __user *new = NULL; + nodemask_t tmp_mask; + unsigned long nr_bits; + unsigned long size; + + nr_bits = min_t(unsigned long, maxnode - 1, MAX_NUMNODES); + size = ALIGN(nr_bits, BITS_PER_LONG) / 8; + if (old_nodes) { + if (compat_get_bitmap(nodes_addr(tmp_mask), old_nodes, nr_bits)) + return -EFAULT; + old = compat_alloc_user_space(new_nodes ? size * 2 : size); + if (new_nodes) + new = old + size / sizeof(unsigned long); + if (copy_to_user(old, nodes_addr(tmp_mask), size)) + return -EFAULT; + } + if (new_nodes) { + if (compat_get_bitmap(nodes_addr(tmp_mask), new_nodes, nr_bits)) + return -EFAULT; + if (new == NULL) + new = compat_alloc_user_space(size); + if (copy_to_user(new, nodes_addr(tmp_mask), size)) + return -EFAULT; + } + return sys_migrate_pages(pid, nr_bits + 1, old, new); +} #endif diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 0e53314b14de..d7306d0f3dfc 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -135,6 +135,7 @@ cond_syscall(sys_madvise); cond_syscall(sys_mremap); cond_syscall(sys_remap_file_pages); cond_syscall(compat_sys_move_pages); +cond_syscall(compat_sys_migrate_pages); /* block-layer dependent */ cond_syscall(sys_bdflush); -- cgit v1.2.3 From 4833ed094097323f5f219820f6ebdc8dd66f501f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 3 Nov 2006 00:27:06 -0800 Subject: [IPX]: Trivial parts of endianness annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/ipx.h | 14 +++++++------- include/net/ipx.h | 22 +++++++++++----------- net/ipx/af_ipx.c | 54 ++++++++++++++++++++++++++--------------------------- net/ipx/ipx_proc.c | 12 ++++++------ net/ipx/ipx_route.c | 10 +++++----- 5 files changed, 56 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ipx.h b/include/linux/ipx.h index 4f29c60964c4..eb19b4ea84f4 100644 --- a/include/linux/ipx.h +++ b/include/linux/ipx.h @@ -7,8 +7,8 @@ struct sockaddr_ipx { sa_family_t sipx_family; - __u16 sipx_port; - __u32 sipx_network; + __be16 sipx_port; + __be32 sipx_network; unsigned char sipx_node[IPX_NODE_LEN]; __u8 sipx_type; unsigned char sipx_zero; /* 16 byte fill */ @@ -23,13 +23,13 @@ struct sockaddr_ipx { #define IPX_CRTITF 1 struct ipx_route_definition { - __u32 ipx_network; - __u32 ipx_router_network; + __be32 ipx_network; + __be32 ipx_router_network; unsigned char ipx_router_node[IPX_NODE_LEN]; }; struct ipx_interface_definition { - __u32 ipx_network; + __be32 ipx_network; unsigned char ipx_device[16]; unsigned char ipx_dlink_type; #define IPX_FRAME_NONE 0 @@ -55,8 +55,8 @@ struct ipx_config_data { */ struct ipx_route_def { - __u32 ipx_network; - __u32 ipx_router_network; + __be32 ipx_network; + __be32 ipx_router_network; #define IPX_ROUTE_NO_ROUTER 0 unsigned char ipx_router_node[IPX_NODE_LEN]; unsigned char ipx_device[16]; diff --git a/include/net/ipx.h b/include/net/ipx.h index 5c0cf33826c5..4a423d2695ba 100644 --- a/include/net/ipx.h +++ b/include/net/ipx.h @@ -15,9 +15,9 @@ #include struct ipx_address { - __u32 net; + __be32 net; __u8 node[IPX_NODE_LEN]; - __u16 sock; + __be16 sock; }; #define ipx_broadcast_node "\377\377\377\377\377\377" @@ -28,7 +28,7 @@ struct ipx_address { struct ipxhdr { __u16 ipx_checksum __attribute__ ((packed)); #define IPX_NO_CHECKSUM 0xFFFF - __u16 ipx_pktsize __attribute__ ((packed)); + __be16 ipx_pktsize __attribute__ ((packed)); __u8 ipx_tctrl; __u8 ipx_type; #define IPX_TYPE_UNKNOWN 0x00 @@ -48,14 +48,14 @@ static __inline__ struct ipxhdr *ipx_hdr(struct sk_buff *skb) struct ipx_interface { /* IPX address */ - __u32 if_netnum; + __be32 if_netnum; unsigned char if_node[IPX_NODE_LEN]; atomic_t refcnt; /* physical device info */ struct net_device *if_dev; struct datalink_proto *if_dlink; - unsigned short if_dlink_type; + __be16 if_dlink_type; /* socket support */ unsigned short if_sknum; @@ -71,7 +71,7 @@ struct ipx_interface { }; struct ipx_route { - __u32 ir_net; + __be32 ir_net; struct ipx_interface *ir_intrfc; unsigned char ir_routed; unsigned char ir_router_node[IPX_NODE_LEN]; @@ -82,10 +82,10 @@ struct ipx_route { #ifdef __KERNEL__ struct ipx_cb { u8 ipx_tctrl; - u32 ipx_dest_net; - u32 ipx_source_net; + __be32 ipx_dest_net; + __be32 ipx_source_net; struct { - u32 netnum; + __be32 netnum; int index; } last_hop; }; @@ -97,7 +97,7 @@ struct ipx_sock { struct sock sk; struct ipx_address dest_addr; struct ipx_interface *intrfc; - unsigned short port; + __be16 port; #ifdef CONFIG_IPX_INTERN unsigned char node[IPX_NODE_LEN]; #endif @@ -132,7 +132,7 @@ extern struct ipx_interface *ipx_primary_net; extern int ipx_proc_init(void); extern void ipx_proc_exit(void); -extern const char *ipx_frame_name(unsigned short); +extern const char *ipx_frame_name(__be16); extern const char *ipx_device_name(struct ipx_interface *intrfc); static __inline__ void ipxitf_hold(struct ipx_interface *intrfc) diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index bef3f61569f7..c272a38af325 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -83,13 +83,13 @@ DEFINE_SPINLOCK(ipx_interfaces_lock); struct ipx_interface *ipx_primary_net; struct ipx_interface *ipx_internal_net; -extern int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc, +extern int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc, unsigned char *node); extern void ipxrtr_del_routes(struct ipx_interface *intrfc); extern int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx, struct iovec *iov, int len, int noblock); extern int ipxrtr_route_skb(struct sk_buff *skb); -extern struct ipx_route *ipxrtr_lookup(__u32 net); +extern struct ipx_route *ipxrtr_lookup(__be32 net); extern int ipxrtr_ioctl(unsigned int cmd, void __user *arg); #undef IPX_REFCNT_DEBUG @@ -177,7 +177,7 @@ static void ipxitf_clear_primary_net(void) } static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev, - unsigned short datalink) + __be16 datalink) { struct ipx_interface *i; @@ -190,7 +190,7 @@ out: } static struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev, - unsigned short datalink) + __be16 datalink) { struct ipx_interface *i; @@ -202,7 +202,7 @@ static struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev, return i; } -struct ipx_interface *ipxitf_find_using_net(__u32 net) +struct ipx_interface *ipxitf_find_using_net(__be32 net) { struct ipx_interface *i; @@ -237,7 +237,7 @@ static void ipxitf_insert_socket(struct ipx_interface *intrfc, struct sock *sk) /* caller must hold intrfc->if_sklist_lock */ static struct sock *__ipxitf_find_socket(struct ipx_interface *intrfc, - unsigned short port) + __be16 port) { struct sock *s; struct hlist_node *node; @@ -252,7 +252,7 @@ found: /* caller must hold a reference to intrfc */ static struct sock *ipxitf_find_socket(struct ipx_interface *intrfc, - unsigned short port) + __be16 port) { struct sock *s; @@ -268,7 +268,7 @@ static struct sock *ipxitf_find_socket(struct ipx_interface *intrfc, #ifdef CONFIG_IPX_INTERN static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc, unsigned char *ipx_node, - unsigned short port) + __be16 port) { struct sock *s; struct hlist_node *node; @@ -600,10 +600,10 @@ int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, char *node) /* see if we need to include the netnum in the route list */ if (IPX_SKB_CB(skb)->last_hop.index >= 0) { - u32 *last_hop = (u32 *)(((u8 *) skb->data) + + __be32 *last_hop = (__be32 *)(((u8 *) skb->data) + sizeof(struct ipxhdr) + IPX_SKB_CB(skb)->last_hop.index * - sizeof(u32)); + sizeof(__be32)); *last_hop = IPX_SKB_CB(skb)->last_hop.netnum; IPX_SKB_CB(skb)->last_hop.index = -1; } @@ -772,7 +772,7 @@ static void ipxitf_discover_netnum(struct ipx_interface *intrfc, } else { printk(KERN_WARNING "IPX: Network number collision " "%lx\n %s %s and %s %s\n", - (unsigned long) htonl(cb->ipx_source_net), + (unsigned long) ntohl(cb->ipx_source_net), ipx_device_name(i), ipx_frame_name(i->if_dlink_type), ipx_device_name(intrfc), @@ -812,7 +812,7 @@ static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb) int i, rc = -EINVAL; struct ipx_interface *ifcs; char *c; - u32 *l; + __be32 *l; /* Illegal packet - too many hops or too short */ /* We decide to throw it away: no broadcasting, no local processing. @@ -833,7 +833,7 @@ static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb) goto out; c = ((u8 *) ipx) + sizeof(struct ipxhdr); - l = (u32 *) c; + l = (__be32 *) c; /* Don't broadcast packet if already seen this net */ for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++) @@ -855,7 +855,7 @@ static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb) /* That aren't in the list */ if (ifcs == intrfc) continue; - l = (__u32 *) c; + l = (__be32 *) c; /* don't consider the last entry in the packet list, * it is our netnum, and it is not there yet */ for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++) @@ -885,8 +885,8 @@ static void ipxitf_insert(struct ipx_interface *intrfc) ipx_primary_net = intrfc; } -static struct ipx_interface *ipxitf_alloc(struct net_device *dev, __u32 netnum, - unsigned short dlink_type, +static struct ipx_interface *ipxitf_alloc(struct net_device *dev, __be32 netnum, + __be16 dlink_type, struct datalink_proto *dlink, unsigned char internal, int ipx_offset) @@ -960,7 +960,7 @@ static __be16 ipx_map_frame_type(unsigned char type) static int ipxitf_create(struct ipx_interface_definition *idef) { struct net_device *dev; - unsigned short dlink_type = 0; + __be16 dlink_type = 0; struct datalink_proto *datalink = NULL; struct ipx_interface *intrfc; int rc; @@ -1073,7 +1073,7 @@ out: static int ipxitf_delete(struct ipx_interface_definition *idef) { struct net_device *dev = NULL; - unsigned short dlink_type = 0; + __be16 dlink_type = 0; struct ipx_interface *intrfc; int rc = 0; @@ -1110,7 +1110,7 @@ out: } static struct ipx_interface *ipxitf_auto_create(struct net_device *dev, - unsigned short dlink_type) + __be16 dlink_type) { struct ipx_interface *intrfc = NULL; struct datalink_proto *datalink; @@ -1122,7 +1122,7 @@ static struct ipx_interface *ipxitf_auto_create(struct net_device *dev, if (dev->addr_len > IPX_NODE_LEN) goto out; - switch (htons(dlink_type)) { + switch (ntohs(dlink_type)) { case ETH_P_IPX: datalink = pEII_datalink; break; case ETH_P_802_2: datalink = p8022_datalink; break; case ETH_P_SNAP: datalink = pSNAP_datalink; break; @@ -1266,7 +1266,7 @@ __u16 ipx_cksum(struct ipxhdr *packet, int length) return ~sum; } -const char *ipx_frame_name(unsigned short frame) +const char *ipx_frame_name(__be16 frame) { char* rc = "None"; @@ -1401,7 +1401,7 @@ out: /* caller must hold a reference to intrfc */ -static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc) +static __be16 ipx_first_free_socketnum(struct ipx_interface *intrfc) { unsigned short socketNum = intrfc->if_sknum; @@ -1410,7 +1410,7 @@ static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc) if (socketNum < IPX_MIN_EPHEMERAL_SOCKET) socketNum = IPX_MIN_EPHEMERAL_SOCKET; - while (__ipxitf_find_socket(intrfc, ntohs(socketNum))) + while (__ipxitf_find_socket(intrfc, htons(socketNum))) if (socketNum > IPX_MAX_EPHEMERAL_SOCKET) socketNum = IPX_MIN_EPHEMERAL_SOCKET; else @@ -1419,7 +1419,7 @@ static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc) spin_unlock_bh(&intrfc->if_sklist_lock); intrfc->if_sknum = socketNum; - return ntohs(socketNum); + return htons(socketNum); } static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) @@ -1473,7 +1473,7 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ipxs->port)) { SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n", - ntohs((int)addr->sipx_port)); + ntohs(addr->sipx_port)); goto out_put; } } else { @@ -1488,7 +1488,7 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (ipxitf_find_socket(intrfc, addr->sipx_port)) { SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n", - ntohs((int)addr->sipx_port)); + ntohs(addr->sipx_port)); goto out_put; } } @@ -1665,7 +1665,7 @@ static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty intrfc = ipxitf_find_using_phys(dev, pt->type); if (!intrfc) { if (ipxcfg_auto_create_interfaces && - ntohl(IPX_SKB_CB(skb)->ipx_dest_net)) { + IPX_SKB_CB(skb)->ipx_dest_net) { intrfc = ipxitf_auto_create(dev, pt->type); if (intrfc) ipxitf_hold(intrfc); diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c index 4c0c71206e54..b7463dfca63e 100644 --- a/net/ipx/ipx_proc.c +++ b/net/ipx/ipx_proc.c @@ -260,22 +260,22 @@ static int ipx_seq_socket_show(struct seq_file *seq, void *v) ipxs = ipx_sk(s); #ifdef CONFIG_IPX_INTERN seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", - (unsigned long)htonl(ipxs->intrfc->if_netnum), + (unsigned long)ntohl(ipxs->intrfc->if_netnum), ipxs->node[0], ipxs->node[1], ipxs->node[2], ipxs->node[3], - ipxs->node[4], ipxs->node[5], htons(ipxs->port)); + ipxs->node[4], ipxs->node[5], ntohs(ipxs->port)); #else - seq_printf(seq, "%08lX:%04X ", (unsigned long) htonl(ipxs->intrfc->if_netnum), - htons(ipxs->port)); + seq_printf(seq, "%08lX:%04X ", (unsigned long) ntohl(ipxs->intrfc->if_netnum), + ntohs(ipxs->port)); #endif /* CONFIG_IPX_INTERN */ if (s->sk_state != TCP_ESTABLISHED) seq_printf(seq, "%-28s", "Not_Connected"); else { seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", - (unsigned long)htonl(ipxs->dest_addr.net), + (unsigned long)ntohl(ipxs->dest_addr.net), ipxs->dest_addr.node[0], ipxs->dest_addr.node[1], ipxs->dest_addr.node[2], ipxs->dest_addr.node[3], ipxs->dest_addr.node[4], ipxs->dest_addr.node[5], - htons(ipxs->dest_addr.sock)); + ntohs(ipxs->dest_addr.sock)); } seq_printf(seq, "%08X %08X %02X %03d\n", diff --git a/net/ipx/ipx_route.c b/net/ipx/ipx_route.c index a30dbb1e08fb..8bfaefaf8841 100644 --- a/net/ipx/ipx_route.c +++ b/net/ipx/ipx_route.c @@ -20,16 +20,16 @@ DEFINE_RWLOCK(ipx_routes_lock); extern struct ipx_interface *ipx_internal_net; extern __u16 ipx_cksum(struct ipxhdr *packet, int length); -extern struct ipx_interface *ipxitf_find_using_net(__u32 net); +extern struct ipx_interface *ipxitf_find_using_net(__be32 net); extern int ipxitf_demux_socket(struct ipx_interface *intrfc, struct sk_buff *skb, int copy); extern int ipxitf_demux_socket(struct ipx_interface *intrfc, struct sk_buff *skb, int copy); extern int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, char *node); -extern struct ipx_interface *ipxitf_find_using_net(__u32 net); +extern struct ipx_interface *ipxitf_find_using_net(__be32 net); -struct ipx_route *ipxrtr_lookup(__u32 net) +struct ipx_route *ipxrtr_lookup(__be32 net) { struct ipx_route *r; @@ -48,7 +48,7 @@ unlock: /* * Caller must hold a reference to intrfc */ -int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc, +int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc, unsigned char *node) { struct ipx_route *rt; @@ -118,7 +118,7 @@ out: return rc; } -static int ipxrtr_delete(__u32 net) +static int ipxrtr_delete(__be32 net) { struct ipx_route *r, *tmp; int rc; -- cgit v1.2.3 From d99f160ac53e51090f015a8f0617cea25f81a191 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 5 Nov 2006 23:52:12 -0800 Subject: [PATCH] sysctl: allow a zero ctl_name in the middle of a sysctl table Since it is becoming clear that there are just enough users of the binary sysctl interface that completely removing the binary interface from the kernel will not be an option for foreseeable future, we need to find a way to address the sysctl maintenance issues. The basic problem is that sysctl requires one central authority to allocate sysctl numbers, or else conflicts and ABI breakage occur. The proc interface to sysctl does not have that problem, as names are not densely allocated. By not terminating a sysctl table until I have neither a ctl_name nor a procname, it becomes simple to add sysctl entries that don't show up in the binary sysctl interface. Which allows people to avoid allocating a binary sysctl value when not needed. I have audited the kernel code and in my reading I have not found a single sysctl table that wasn't terminated by a completely zero filled entry. So this change in behavior should not affect anything. I think this mechanism eases the pain enough that combined with a little disciple we can solve the reoccurring sysctl ABI breakage. Signed-off-by: Eric W. Biederman Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sysctl.h | 9 ++++++--- kernel/sysctl.c | 8 +++++--- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 1b24bd45e080..c184732a70fc 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -961,8 +961,8 @@ extern ctl_handler sysctl_ms_jiffies; /* * Register a set of sysctl names by calling register_sysctl_table * with an initialised array of ctl_table's. An entry with zero - * ctl_name terminates the table. table->de will be set up by the - * registration and need not be initialised in advance. + * ctl_name and NULL procname terminates the table. table->de will be + * set up by the registration and need not be initialised in advance. * * sysctl names can be mirrored automatically under /proc/sys. The * procname supplied controls /proc naming. @@ -973,7 +973,10 @@ extern ctl_handler sysctl_ms_jiffies; * Leaf nodes in the sysctl tree will be represented by a single file * under /proc; non-leaf nodes will be represented by directories. A * null procname disables /proc mirroring at this node. - * + * + * sysctl entries with a zero ctl_name will not be available through + * the binary sysctl interface. + * * sysctl(2) can automatically manage read and write requests through * the sysctl table. The data and maxlen fields of the ctl_table * struct enable minimal validation of the values being written to be diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 0c8e805bbd6f..09e569f4792b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1315,7 +1315,9 @@ repeat: return -ENOTDIR; if (get_user(n, name)) return -EFAULT; - for ( ; table->ctl_name; table++) { + for ( ; table->ctl_name || table->procname; table++) { + if (!table->ctl_name) + continue; if (n == table->ctl_name || table->ctl_name == CTL_ANY) { int error; if (table->child) { @@ -1532,7 +1534,7 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, int len; mode_t mode; - for (; table->ctl_name; table++) { + for (; table->ctl_name || table->procname; table++) { /* Can't do anything without a proc name. */ if (!table->procname) continue; @@ -1579,7 +1581,7 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) { struct proc_dir_entry *de; - for (; table->ctl_name; table++) { + for (; table->ctl_name || table->procname; table++) { if (!(de = table->de)) continue; if (de->mode & S_IFDIR) { -- cgit v1.2.3 From 7cc13edc139108bb527b692f0548dce6bc648572 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 5 Nov 2006 23:52:13 -0800 Subject: [PATCH] sysctl: implement CTL_UNNUMBERED This patch takes the CTL_UNNUMBERD concept from NFS and makes it available to all new sysctl users. At the same time the sysctl binary interface maintenance documentation is updated to mention and to describe what is needed to successfully maintain the sysctl binary interface. Signed-off-by: Eric W. Biederman Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svc.c | 3 --- fs/nfs/sysctl.c | 5 ----- include/linux/sysctl.h | 14 +++++++++++--- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 634139232aaf..8ca18085e68d 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -353,9 +353,6 @@ EXPORT_SYMBOL(lockd_down); * Sysctl parameters (same as module parameters, different interface). */ -/* Something that isn't CTL_ANY, CTL_NONE or a value that may clash. */ -#define CTL_UNNUMBERED -2 - static ctl_table nlm_sysctls[] = { { .ctl_name = CTL_UNNUMBERED, diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index 2fe3403c2409..3ea50ac64820 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c @@ -18,11 +18,6 @@ static const int nfs_set_port_min = 0; static const int nfs_set_port_max = 65535; static struct ctl_table_header *nfs_callback_sysctl_table; -/* - * Something that isn't CTL_ANY, CTL_NONE or a value that may clash. - * Use the same values as fs/lockd/svc.c - */ -#define CTL_UNNUMBERED -2 static ctl_table nfs_cb_sysctls[] = { #ifdef CONFIG_NFS_V4 diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index c184732a70fc..d98562f1df76 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -6,10 +6,17 @@ **************************************************************** **************************************************************** ** + ** WARNING: ** The values in this file are exported to user space via - ** the sysctl() binary interface. However this interface - ** is unstable and deprecated and will be removed in the future. - ** For a stable interface use /proc/sys. + ** the sysctl() binary interface. Do *NOT* change the + ** numbering of any existing values here, and do not change + ** any numbers within any one set of values. If you have to + ** have to redefine an existing interface, use a new number for it. + ** The kernel will then return -ENOTDIR to any application using + ** the old binary interface. + ** + ** For new interfaces unless you really need a binary number + ** please use CTL_UNNUMBERED. ** **************************************************************** **************************************************************** @@ -48,6 +55,7 @@ struct __sysctl_args { #ifdef __KERNEL__ #define CTL_ANY -1 /* Matches any name */ #define CTL_NONE 0 +#define CTL_UNNUMBERED CTL_NONE /* sysctl without a binary number */ #endif enum -- cgit v1.2.3 From 81ac95c5569d7a60ab5db6c1ccec56c12b3ebcb5 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 8 Nov 2006 17:44:40 -0800 Subject: [PATCH] nfsd4: fix open-create permissions In the case where an open creates the file, we shouldn't be rechecking permissions to open the file; the open succeeds regardless of what the new file's mode bits say. This patch fixes the problem, but only by introducing yet another parameter to nfsd_create_v3. This is ugly. This will be fixed by later patches. Signed-off-by: J. Bruce Fields Acked-by: Neil Brown Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs3proc.c | 2 +- fs/nfsd/nfs4proc.c | 6 ++++-- fs/nfsd/vfs.c | 4 +++- include/linux/nfsd/nfsd.h | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 64db601c2bd2..7f5bad0393b1 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -258,7 +258,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, /* Now create the file and set attributes */ nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len, attr, newfhp, - argp->createmode, argp->verf, NULL); + argp->createmode, argp->verf, NULL, NULL); RETURN_STATUS(nfserr); } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 4a73f5b2546f..50bc94243ca1 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -93,6 +93,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o { struct svc_fh resfh; __be32 status; + int created = 0; fh_init(&resfh, NFS4_FHSIZE); open->op_truncate = 0; @@ -105,7 +106,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &open->op_iattr, &resfh, open->op_createmode, - (u32 *)open->op_verf.data, &open->op_truncate); + (u32 *)open->op_verf.data, &open->op_truncate, &created); } else { status = nfsd_lookup(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &resfh); @@ -122,7 +123,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o memcpy(open->op_stateowner->so_replay.rp_openfh, &resfh.fh_handle.fh_base, resfh.fh_handle.fh_size); - status = do_open_permission(rqstp, current_fh, open, MAY_NOP); + if (!created) + status = do_open_permission(rqstp, current_fh, open, MAY_NOP); out: fh_put(&resfh); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index f21e917bb8ed..1a7ad8c983d1 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1237,7 +1237,7 @@ __be32 nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, struct iattr *iap, struct svc_fh *resfhp, int createmode, u32 *verifier, - int *truncp) + int *truncp, int *created) { struct dentry *dentry, *dchild = NULL; struct inode *dirp; @@ -1331,6 +1331,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); if (host_err < 0) goto out_nfserr; + if (created) + *created = 1; if (EX_ISSYNC(fhp->fh_export)) { err = nfserrno(nfsd_sync_dir(dentry)); diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index eb231143d579..edb54c3171b3 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -89,7 +89,7 @@ __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); __be32 nfsd_create_v3(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, struct svc_fh *res, int createmode, - u32 *verifier, int *truncp); + u32 *verifier, int *truncp, int *created); __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, loff_t, unsigned long); #endif /* CONFIG_NFSD_V3 */ -- cgit v1.2.3 From 46d52b09fa6a2d1e313cb75ca352d6f466e67bd1 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Wed, 8 Nov 2006 17:44:55 -0800 Subject: [PATCH] IPMI: retry messages on certain error returns Some more errors from the IPMI send message command are retryable, but are not being retried by the IPMI code. Make sure they get retried. Signed-off-by: Corey Minyard Cc: Frederic Lelievre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_msghandler.c | 4 +++- include/linux/ipmi_msgdefs.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index e55a0d276729..0b07ca1b71fa 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3242,7 +3242,9 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, report the error immediately. */ if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) - && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)) + && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) + && (msg->rsp[2] != IPMI_BUS_ERR) + && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) { int chan = msg->rsp[3] & 0xf; diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h index 22f5e2afda4f..4d04d8b58a0a 100644 --- a/include/linux/ipmi_msgdefs.h +++ b/include/linux/ipmi_msgdefs.h @@ -75,6 +75,8 @@ #define IPMI_INVALID_COMMAND_ERR 0xc1 #define IPMI_ERR_MSG_TRUNCATED 0xc6 #define IPMI_LOST_ARBITRATION_ERR 0x81 +#define IPMI_BUS_ERR 0x82 +#define IPMI_NAK_ON_WRITE_ERR 0x83 #define IPMI_ERR_UNSPECIFIED 0xff #define IPMI_CHANNEL_PROTOCOL_IPMB 1 -- cgit v1.2.3 From ec68307cc5a8dc499e48693843bb42f6b6028458 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 8 Nov 2006 17:44:57 -0800 Subject: [PATCH] htirq: refactor so we only have one function that writes to the chip This refactoring actually optimizes the code a little by caching the value that we think the device is programmed with instead of reading it back from the hardware. Which simplifies the code a little and should speed things up a bit. This patch introduces the concept of a ht_irq_msg and modifies the architecture read/write routines to update this code. There is a minor consistency fix here as well as x86_64 forgot to initialize the htirq as masked. Signed-off-by: Eric W. Biederman Cc: Andi Kleen Acked-by: Bryan O'Sullivan Cc: Cc: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/io_apic.c | 26 ++++++++-------- arch/x86_64/kernel/io_apic.c | 31 +++++++++---------- drivers/pci/htirq.c | 72 +++++++++++++++----------------------------- include/linux/htirq.h | 11 ++++--- 4 files changed, 58 insertions(+), 82 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 507983c513c3..ad84bc2802a6 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -2624,18 +2624,16 @@ void arch_teardown_msi_irq(unsigned int irq) static void target_ht_irq(unsigned int irq, unsigned int dest) { - u32 low, high; - low = read_ht_irq_low(irq); - high = read_ht_irq_high(irq); + struct ht_irq_msg msg; + fetch_ht_irq_msg(irq, &msg); - low &= ~(HT_IRQ_LOW_DEST_ID_MASK); - high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); + msg.address_lo &= ~(HT_IRQ_LOW_DEST_ID_MASK); + msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK); - low |= HT_IRQ_LOW_DEST_ID(dest); - high |= HT_IRQ_HIGH_DEST_ID(dest); + msg.address_lo |= HT_IRQ_LOW_DEST_ID(dest); + msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest); - write_ht_irq_low(irq, low); - write_ht_irq_high(irq, high); + write_ht_irq_msg(irq, &msg); } static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) @@ -2673,7 +2671,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) vector = assign_irq_vector(irq); if (vector >= 0) { - u32 low, high; + struct ht_irq_msg msg; unsigned dest; cpumask_t tmp; @@ -2681,9 +2679,10 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) cpu_set(vector >> 8, tmp); dest = cpu_mask_to_apicid(tmp); - high = HT_IRQ_HIGH_DEST_ID(dest); + msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); - low = HT_IRQ_LOW_BASE | + msg.address_lo = + HT_IRQ_LOW_BASE | HT_IRQ_LOW_DEST_ID(dest) | HT_IRQ_LOW_VECTOR(vector) | ((INT_DEST_MODE == 0) ? @@ -2695,8 +2694,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) HT_IRQ_LOW_MT_ARBITRATED) | HT_IRQ_LOW_IRQ_MASKED; - write_ht_irq_low(irq, low); - write_ht_irq_high(irq, high); + write_ht_irq_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &ht_irq_chip, handle_edge_irq, "edge"); diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 3b8f9c68ad3c..41bfc49301ad 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1955,18 +1955,16 @@ void arch_teardown_msi_irq(unsigned int irq) static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) { - u32 low, high; - low = read_ht_irq_low(irq); - high = read_ht_irq_high(irq); + struct ht_irq_msg msg; + fetch_ht_irq_msg(irq, &msg); - low &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK); - high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); + msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK); + msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK); - low |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest); - high |= HT_IRQ_HIGH_DEST_ID(dest); + msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest); + msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest); - write_ht_irq_low(irq, low); - write_ht_irq_high(irq, high); + write_ht_irq_msg(irq, &msg); } static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) @@ -1987,7 +1985,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) dest = cpu_mask_to_apicid(tmp); - target_ht_irq(irq, dest, vector & 0xff); + target_ht_irq(irq, dest, vector); set_native_irq_info(irq, mask); } #endif @@ -2010,14 +2008,15 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) vector = assign_irq_vector(irq, TARGET_CPUS, &tmp); if (vector >= 0) { - u32 low, high; + struct ht_irq_msg msg; unsigned dest; dest = cpu_mask_to_apicid(tmp); - high = HT_IRQ_HIGH_DEST_ID(dest); + msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); - low = HT_IRQ_LOW_BASE | + msg.address_lo = + HT_IRQ_LOW_BASE | HT_IRQ_LOW_DEST_ID(dest) | HT_IRQ_LOW_VECTOR(vector) | ((INT_DEST_MODE == 0) ? @@ -2026,10 +2025,10 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) HT_IRQ_LOW_RQEOI_EDGE | ((INT_DELIVERY_MODE != dest_LowestPrio) ? HT_IRQ_LOW_MT_FIXED : - HT_IRQ_LOW_MT_ARBITRATED); + HT_IRQ_LOW_MT_ARBITRATED) | + HT_IRQ_LOW_IRQ_MASKED; - write_ht_irq_low(irq, low); - write_ht_irq_high(irq, high); + write_ht_irq_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &ht_irq_chip, handle_edge_irq, "edge"); diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 0e27f2404a83..e346fe31f97a 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -27,82 +27,55 @@ struct ht_irq_cfg { struct pci_dev *dev; unsigned pos; unsigned idx; + struct ht_irq_msg msg; }; -void write_ht_irq_low(unsigned int irq, u32 data) -{ - struct ht_irq_cfg *cfg = get_irq_data(irq); - unsigned long flags; - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); -} - -void write_ht_irq_high(unsigned int irq, u32 data) -{ - struct ht_irq_cfg *cfg = get_irq_data(irq); - unsigned long flags; - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); -} -u32 read_ht_irq_low(unsigned int irq) +void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) { struct ht_irq_cfg *cfg = get_irq_data(irq); unsigned long flags; - u32 data; spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); + if (cfg->msg.address_lo != msg->address_lo) { + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); + pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_lo); + } + if (cfg->msg.address_hi != msg->address_hi) { + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); + pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_hi); + } spin_unlock_irqrestore(&ht_irq_lock, flags); - return data; + cfg->msg = *msg; } -u32 read_ht_irq_high(unsigned int irq) +void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) { struct ht_irq_cfg *cfg = get_irq_data(irq); - unsigned long flags; - u32 data; - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); - spin_unlock_irqrestore(&ht_irq_lock, flags); - return data; + *msg = cfg->msg; } void mask_ht_irq(unsigned int irq) { struct ht_irq_cfg *cfg; - unsigned long flags; - u32 data; + struct ht_irq_msg msg; cfg = get_irq_data(irq); - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); - data |= 1; - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); + msg = cfg->msg; + msg.address_lo |= 1; + write_ht_irq_msg(irq, &msg); } void unmask_ht_irq(unsigned int irq) { struct ht_irq_cfg *cfg; - unsigned long flags; - u32 data; + struct ht_irq_msg msg; cfg = get_irq_data(irq); - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); - data &= ~1; - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); + msg = cfg->msg; + msg.address_lo &= ~1; + write_ht_irq_msg(irq, &msg); } /** @@ -152,6 +125,9 @@ int ht_create_irq(struct pci_dev *dev, int idx) cfg->dev = dev; cfg->pos = pos; cfg->idx = 0x10 + (idx * 2); + /* Initialize msg to a value that will never match the first write. */ + cfg->msg.address_lo = 0xffffffff; + cfg->msg.address_hi = 0xffffffff; irq = create_irq(); if (irq < 0) { diff --git a/include/linux/htirq.h b/include/linux/htirq.h index 1f15ce279a23..108f0d91e11e 100644 --- a/include/linux/htirq.h +++ b/include/linux/htirq.h @@ -1,11 +1,14 @@ #ifndef LINUX_HTIRQ_H #define LINUX_HTIRQ_H +struct ht_irq_msg { + u32 address_lo; /* low 32 bits of the ht irq message */ + u32 address_hi; /* high 32 bits of the it irq message */ +}; + /* Helper functions.. */ -void write_ht_irq_low(unsigned int irq, u32 data); -void write_ht_irq_high(unsigned int irq, u32 data); -u32 read_ht_irq_low(unsigned int irq); -u32 read_ht_irq_high(unsigned int irq); +void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg); +void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg); void mask_ht_irq(unsigned int irq); void unmask_ht_irq(unsigned int irq); -- cgit v1.2.3 From 43539c38cd8edb915d1f0e1f55dcb70638b4cc8e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 8 Nov 2006 17:44:57 -0800 Subject: [PATCH] htirq: allow buggy drivers of buggy hardware to write the registers This patch adds a variant of ht_create_irq __ht_create_irq that takes an aditional parameter update that is a function that is called whenever we want to write to a drivers htirq configuration registers. This is needed to support the ipath_iba6110 because it's registers in the proper location are not actually conected to the hardware that controlls interrupt delivery. [bos@serpentine.com: fixes] Signed-off-by: Eric W. Biederman Cc: Andi Kleen Cc: Cc: Roland Dreier Signed-off-by: Bryan O'Sullivan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/htirq.c | 29 ++++++++++++++++++++++++----- include/linux/htirq.h | 5 +++++ 2 files changed, 29 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index e346fe31f97a..0a8d1cce9fa0 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -25,6 +25,8 @@ static DEFINE_SPINLOCK(ht_irq_lock); struct ht_irq_cfg { struct pci_dev *dev; + /* Update callback used to cope with buggy hardware */ + ht_irq_update_t *update; unsigned pos; unsigned idx; struct ht_irq_msg msg; @@ -44,6 +46,8 @@ void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_hi); } + if (cfg->update) + cfg->update(cfg->dev, irq, msg); spin_unlock_irqrestore(&ht_irq_lock, flags); cfg->msg = *msg; } @@ -79,16 +83,14 @@ void unmask_ht_irq(unsigned int irq) } /** - * ht_create_irq - create an irq and attach it to a device. + * __ht_create_irq - create an irq and attach it to a device. * @dev: The hypertransport device to find the irq capability on. * @idx: Which of the possible irqs to attach to. - * - * ht_create_irq is needs to be called for all hypertransport devices - * that generate irqs. + * @update: Function to be called when changing the htirq message * * The irq number of the new irq or a negative error value is returned. */ -int ht_create_irq(struct pci_dev *dev, int idx) +int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) { struct ht_irq_cfg *cfg; unsigned long flags; @@ -123,6 +125,7 @@ int ht_create_irq(struct pci_dev *dev, int idx) return -ENOMEM; cfg->dev = dev; + cfg->update = update; cfg->pos = pos; cfg->idx = 0x10 + (idx * 2); /* Initialize msg to a value that will never match the first write. */ @@ -144,6 +147,21 @@ int ht_create_irq(struct pci_dev *dev, int idx) return irq; } +/** + * ht_create_irq - create an irq and attach it to a device. + * @dev: The hypertransport device to find the irq capability on. + * @idx: Which of the possible irqs to attach to. + * + * ht_create_irq needs to be called for all hypertransport devices + * that generate irqs. + * + * The irq number of the new irq or a negative error value is returned. + */ +int ht_create_irq(struct pci_dev *dev, int idx) +{ + return __ht_create_irq(dev, idx, NULL); +} + /** * ht_destroy_irq - destroy an irq created with ht_create_irq * @@ -162,5 +180,6 @@ void ht_destroy_irq(unsigned int irq) kfree(cfg); } +EXPORT_SYMBOL(__ht_create_irq); EXPORT_SYMBOL(ht_create_irq); EXPORT_SYMBOL(ht_destroy_irq); diff --git a/include/linux/htirq.h b/include/linux/htirq.h index 108f0d91e11e..c96ea46737d0 100644 --- a/include/linux/htirq.h +++ b/include/linux/htirq.h @@ -15,4 +15,9 @@ void unmask_ht_irq(unsigned int irq); /* The arch hook for getting things started */ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev); +/* For drivers of buggy hardware */ +typedef void (ht_irq_update_t)(struct pci_dev *dev, int irq, + struct ht_irq_msg *msg); +int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update); + #endif /* LINUX_HTIRQ_H */ -- cgit v1.2.3 From a9b14973a8c42b2aecc968851372203c6567e196 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Thu, 19 Oct 2006 19:52:26 -0500 Subject: [PATCH] Slight refactor of interrupt mapping for FSL parts * Cleaned up interrupt mapping a little by adding a helper function which parses the irq out of the device-tree, and puts it into a resource. * Changed the arch/ppc platform files to specify PHY_POLL, instead of -1 * Changed the fixed phy to use PHY_IGNORE_INTERRUPT * Added ethtool.h and mii.h to phy.h includes Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/fsl_soc.c | 28 +++++++++++----------------- arch/ppc/platforms/83xx/mpc834x_sys.c | 4 ++-- arch/ppc/platforms/85xx/mpc8540_ads.c | 4 ++-- arch/ppc/platforms/85xx/mpc8560_ads.c | 4 ++-- arch/ppc/platforms/85xx/mpc85xx_cds_common.c | 6 +++--- arch/ppc/platforms/85xx/sbc8560.c | 2 +- arch/ppc/platforms/85xx/stx_gp3.c | 2 +- arch/ppc/platforms/85xx/tqm85xx.c | 4 ++-- arch/ppc/platforms/mpc8272ads_setup.c | 6 +++--- arch/ppc/platforms/mpc866ads_setup.c | 4 ++-- drivers/net/phy/fixed.c | 2 +- include/asm-powerpc/prom.h | 7 +++++++ include/linux/phy.h | 3 +++ 13 files changed, 40 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index dbe92ae20333..ad31e56e892b 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -146,7 +147,7 @@ static int __init gfar_mdio_of_init(void) } for (k = 0; k < 32; k++) - mdio_data.irq[k] = -1; + mdio_data.irq[k] = PHY_POLL; while ((child = of_get_next_child(np, child)) != NULL) { int irq = irq_of_parse_and_map(child, 0); @@ -177,6 +178,7 @@ static const char *gfar_tx_intr = "tx"; static const char *gfar_rx_intr = "rx"; static const char *gfar_err_intr = "error"; + static int __init gfar_of_init(void) { struct device_node *np; @@ -204,8 +206,7 @@ static int __init gfar_of_init(void) if (ret) goto err; - r[1].start = r[1].end = irq_of_parse_and_map(np, 0); - r[1].flags = IORESOURCE_IRQ; + of_irq_to_resource(np, 0, &r[1]); model = get_property(np, "model", NULL); @@ -214,12 +215,10 @@ static int __init gfar_of_init(void) r[1].name = gfar_tx_intr; r[2].name = gfar_rx_intr; - r[2].start = r[2].end = irq_of_parse_and_map(np, 1); - r[2].flags = IORESOURCE_IRQ; + of_irq_to_resource(np, 1, &r[2]); r[3].name = gfar_err_intr; - r[3].start = r[3].end = irq_of_parse_and_map(np, 2); - r[3].flags = IORESOURCE_IRQ; + of_irq_to_resource(np, 2, &r[3]); n_res += 2; } @@ -323,8 +322,7 @@ static int __init fsl_i2c_of_init(void) if (ret) goto err; - r[1].start = r[1].end = irq_of_parse_and_map(np, 0); - r[1].flags = IORESOURCE_IRQ; + of_irq_to_resource(np, 0, &r[1]); i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2); if (IS_ERR(i2c_dev)) { @@ -459,8 +457,7 @@ static int __init fsl_usb_of_init(void) if (ret) goto err; - r[1].start = r[1].end = irq_of_parse_and_map(np, 0); - r[1].flags = IORESOURCE_IRQ; + of_irq_to_resource(np, 0, &r[1]); usb_dev_mph = platform_device_register_simple("fsl-ehci", i, r, 2); @@ -507,8 +504,7 @@ static int __init fsl_usb_of_init(void) if (ret) goto unreg_mph; - r[1].start = r[1].end = irq_of_parse_and_map(np, 0); - r[1].flags = IORESOURCE_IRQ; + of_irq_to_resource(np, 0, &r[1]); usb_dev_dr = platform_device_register_simple("fsl-ehci", i, r, 2); @@ -591,8 +587,7 @@ static int __init fs_enet_of_init(void) r[2].name = fcc_regs_c; fs_enet_data.fcc_regs_c = r[2].start; - r[3].start = r[3].end = irq_of_parse_and_map(np, 0); - r[3].flags = IORESOURCE_IRQ; + of_irq_to_resource(np, 0, &r[3]); fs_enet_dev = platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4); @@ -754,8 +749,7 @@ static int __init cpm_uart_of_init(void) goto err; r[1].name = scc_pram; - r[2].start = r[2].end = irq_of_parse_and_map(np, 0); - r[2].flags = IORESOURCE_IRQ; + of_irq_to_resource(np, 0, &r[2]); cpm_uart_dev = platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3); diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c index 3397f0de1592..b84f8df325c4 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.c +++ b/arch/ppc/platforms/83xx/mpc834x_sys.c @@ -121,8 +121,8 @@ mpc834x_sys_setup_arch(void) mdata->irq[0] = MPC83xx_IRQ_EXT1; mdata->irq[1] = MPC83xx_IRQ_EXT2; - mdata->irq[2] = -1; - mdata->irq[31] = -1; + mdata->irq[2] = PHY_POLL; + mdata->irq[31] = PHY_POLL; /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1); diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c index 4f839da6782f..00a3ba57063f 100644 --- a/arch/ppc/platforms/85xx/mpc8540_ads.c +++ b/arch/ppc/platforms/85xx/mpc8540_ads.c @@ -92,9 +92,9 @@ mpc8540ads_setup_arch(void) mdata->irq[0] = MPC85xx_IRQ_EXT5; mdata->irq[1] = MPC85xx_IRQ_EXT5; - mdata->irq[2] = -1; + mdata->irq[2] = PHY_POLL; mdata->irq[3] = MPC85xx_IRQ_EXT5; - mdata->irq[31] = -1; + mdata->irq[31] = PHY_POLL; /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c index 14ecec7bbed7..3a060468dd95 100644 --- a/arch/ppc/platforms/85xx/mpc8560_ads.c +++ b/arch/ppc/platforms/85xx/mpc8560_ads.c @@ -156,9 +156,9 @@ mpc8560ads_setup_arch(void) mdata->irq[0] = MPC85xx_IRQ_EXT5; mdata->irq[1] = MPC85xx_IRQ_EXT5; - mdata->irq[2] = -1; + mdata->irq[2] = PHY_POLL; mdata->irq[3] = MPC85xx_IRQ_EXT5; - mdata->irq[31] = -1; + mdata->irq[31] = PHY_POLL; /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 5ce0f69c1db6..2d59eb776c95 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -451,9 +451,9 @@ mpc85xx_cds_setup_arch(void) mdata->irq[0] = MPC85xx_IRQ_EXT5; mdata->irq[1] = MPC85xx_IRQ_EXT5; - mdata->irq[2] = -1; - mdata->irq[3] = -1; - mdata->irq[31] = -1; + mdata->irq[2] = PHY_POLL; + mdata->irq[3] = PHY_POLL; + mdata->irq[31] = PHY_POLL; /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c index 764d580ff535..1d10ab98f66d 100644 --- a/arch/ppc/platforms/85xx/sbc8560.c +++ b/arch/ppc/platforms/85xx/sbc8560.c @@ -129,7 +129,7 @@ sbc8560_setup_arch(void) mdata->irq[25] = MPC85xx_IRQ_EXT6; mdata->irq[26] = MPC85xx_IRQ_EXT7; - mdata->irq[31] = -1; + mdata->irq[31] = PHY_POLL; /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c index 4bb18ab27672..b1f5b737c70d 100644 --- a/arch/ppc/platforms/85xx/stx_gp3.c +++ b/arch/ppc/platforms/85xx/stx_gp3.c @@ -123,7 +123,7 @@ gp3_setup_arch(void) mdata->irq[2] = MPC85xx_IRQ_EXT5; mdata->irq[4] = MPC85xx_IRQ_EXT5; - mdata->irq[31] = -1; + mdata->irq[31] = PHY_POLL; /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c index dd45f2e18449..4ee2bd156dc5 100644 --- a/arch/ppc/platforms/85xx/tqm85xx.c +++ b/arch/ppc/platforms/85xx/tqm85xx.c @@ -137,9 +137,9 @@ tqm85xx_setup_arch(void) mdata->irq[0] = MPC85xx_IRQ_EXT8; mdata->irq[1] = MPC85xx_IRQ_EXT8; - mdata->irq[2] = -1; + mdata->irq[2] = PHY_POLL; mdata->irq[3] = MPC85xx_IRQ_EXT8; - mdata->irq[31] = -1; + mdata->irq[31] = PHY_POLL; /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c index 1f9ea36837b1..0bc06768cf24 100644 --- a/arch/ppc/platforms/mpc8272ads_setup.c +++ b/arch/ppc/platforms/mpc8272ads_setup.c @@ -266,10 +266,10 @@ static void __init mpc8272ads_fixup_mdio_pdata(struct platform_device *pdev, int idx) { m82xx_mii_bb_pdata.irq[0] = PHY_INTERRUPT; - m82xx_mii_bb_pdata.irq[1] = -1; - m82xx_mii_bb_pdata.irq[2] = -1; + m82xx_mii_bb_pdata.irq[1] = PHY_POLL; + m82xx_mii_bb_pdata.irq[2] = PHY_POLL; m82xx_mii_bb_pdata.irq[3] = PHY_INTERRUPT; - m82xx_mii_bb_pdata.irq[31] = -1; + m82xx_mii_bb_pdata.irq[31] = PHY_POLL; m82xx_mii_bb_pdata.mdio_dat.offset = diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c index e95d2c111747..8a0c07eb4449 100644 --- a/arch/ppc/platforms/mpc866ads_setup.c +++ b/arch/ppc/platforms/mpc866ads_setup.c @@ -361,7 +361,7 @@ int __init mpc866ads_init(void) fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1; /* No PHY interrupt line here */ - fmpi->irq[0xf] = -1; + fmpi->irq[0xf] = PHY_POLL; /* Since either of the uarts could be used as console, they need to ready */ #ifdef CONFIG_SERIAL_CPM_SMC1 @@ -380,7 +380,7 @@ int __init mpc866ads_init(void) fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1; /* No PHY interrupt line here */ - fmpi->irq[0xf] = -1; + fmpi->irq[0xf] = PHY_POLL; return 0; } diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index f14e99276dba..096d4a100bf2 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -254,7 +254,7 @@ static int fixed_mdio_register_device(int number, int speed, int duplex) goto device_create_fail; } - phydev->irq = -1; + phydev->irq = PHY_IGNORE_INTERRUPT; phydev->dev.bus = &mdio_bus_type; if(number) diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 524629769336..39f04ef96f38 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -17,6 +17,7 @@ */ #include #include +#include #include /* Definitions used by the flattened device tree */ @@ -331,6 +332,12 @@ extern int of_irq_map_one(struct device_node *device, int index, struct pci_dev; extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); +static inline void of_irq_to_resource(struct device_node *dev, int index, struct resource *r) +{ + r->start = r->end = irq_of_parse_and_map(dev, index); + r->flags = IORESOURCE_IRQ; +} + #endif /* __KERNEL__ */ #endif /* _POWERPC_PROM_H */ diff --git a/include/linux/phy.h b/include/linux/phy.h index 9447a57ee8a9..892d6abe57e5 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -20,6 +20,9 @@ #include #include +#include +#include +#include #define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ SUPPORTED_10baseT_Full | \ -- cgit v1.2.3 From 2b4ac44e7c7e16cf9411b81693ff3e604f332bf1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 10 Nov 2006 12:27:48 -0800 Subject: [PATCH] vmalloc: optimization, cleanup, bugfixes - reorder 'struct vm_struct' to speedup lookups on CPUS with small cache lines. The fields 'next,addr,size' should be now in the same cache line, to speedup lookups. - One minor cleanup in __get_vm_area_node() - Bugfixes in vmalloc_user() and vmalloc_32_user() NULL returns from __vmalloc() and __find_vm_area() were not tested. [akpm@osdl.org: remove redundant BUG_ONs] Signed-off-by: Eric Dumazet Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmalloc.h | 3 ++- mm/vmalloc.c | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index dc9a29d84abc..924e502905d4 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -23,13 +23,14 @@ struct vm_area_struct; #endif struct vm_struct { + /* keep next,addr,size together to speedup lookups */ + struct vm_struct *next; void *addr; unsigned long size; unsigned long flags; struct page **pages; unsigned int nr_pages; unsigned long phys_addr; - struct vm_struct *next; }; /* diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 46606c133e82..7dc6aa745166 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -186,10 +186,8 @@ static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long fl if (unlikely(!area)) return NULL; - if (unlikely(!size)) { - kfree (area); + if (unlikely(!size)) return NULL; - } /* * We always allocate a guard page. @@ -532,11 +530,12 @@ void *vmalloc_user(unsigned long size) void *ret; ret = __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); - write_lock(&vmlist_lock); - area = __find_vm_area(ret); - area->flags |= VM_USERMAP; - write_unlock(&vmlist_lock); - + if (ret) { + write_lock(&vmlist_lock); + area = __find_vm_area(ret); + area->flags |= VM_USERMAP; + write_unlock(&vmlist_lock); + } return ret; } EXPORT_SYMBOL(vmalloc_user); @@ -605,11 +604,12 @@ void *vmalloc_32_user(unsigned long size) void *ret; ret = __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); - write_lock(&vmlist_lock); - area = __find_vm_area(ret); - area->flags |= VM_USERMAP; - write_unlock(&vmlist_lock); - + if (ret) { + write_lock(&vmlist_lock); + area = __find_vm_area(ret); + area->flags |= VM_USERMAP; + write_unlock(&vmlist_lock); + } return ret; } EXPORT_SYMBOL(vmalloc_32_user); -- cgit v1.2.3 From d8b295f29091310d746509bb6d5828aaf4907a18 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 10 Nov 2006 12:27:53 -0800 Subject: [PATCH] Fix missing parens in set_personality() If you call set_personality() with an expression such as: set_personality(foo ? PERS_FOO1 : PERS_FOO2); then this evaluates to: ((current->personality == foo ? PERS_FOO1 : PERS_FOO2) ? ... which is obviously not the intended result. Add the missing parents to ensure this gets evaluated as expected: ((current->personality == (foo ? PERS_FOO1 : PERS_FOO2)) ? ... Signed-off-by: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/personality.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/personality.h b/include/linux/personality.h index bf4cf2080e5c..012cd558189b 100644 --- a/include/linux/personality.h +++ b/include/linux/personality.h @@ -114,7 +114,7 @@ struct exec_domain { * Change personality of the currently running process. */ #define set_personality(pers) \ - ((current->personality == pers) ? 0 : __set_personality(pers)) + ((current->personality == (pers)) ? 0 : __set_personality(pers)) #endif /* __KERNEL__ */ -- cgit v1.2.3 From 68589bc353037f233fe510ad9ff432338c95db66 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 14 Nov 2006 02:03:32 -0800 Subject: [PATCH] hugetlb: prepare_hugepage_range check offset too (David:) If hugetlbfs_file_mmap() returns a failure to do_mmap_pgoff() - for example, because the given file offset is not hugepage aligned - then do_mmap_pgoff will go to the unmap_and_free_vma backout path. But at this stage the vma hasn't been marked as hugepage, and the backout path will call unmap_region() on it. That will eventually call down to the non-hugepage version of unmap_page_range(). On ppc64, at least, that will cause serious problems if there are any existing hugepage pagetable entries in the vicinity - for example if there are any other hugepage mappings under the same PUD. unmap_page_range() will trigger a bad_pud() on the hugepage pud entries. I suspect this will also cause bad problems on ia64, though I don't have a machine to test it on. (Hugh:) prepare_hugepage_range() should check file offset alignment when it checks virtual address and length, to stop MAP_FIXED with a bad huge offset from unmapping before it fails further down. PowerPC should apply the same prepare_hugepage_range alignment checks as ia64 and all the others do. Then none of the alignment checks in hugetlbfs_file_mmap are required (nor is the check for too small a mapping); but even so, move up setting of VM_HUGETLB and add a comment to warn of what David Gibson discovered - if hugetlbfs_file_mmap fails before setting it, do_mmap_pgoff's unmap_region when unwinding from error will go the non-huge way, which may cause bad behaviour on architectures (powerpc and ia64) which segregate their huge mappings into a separate region of the address space. Signed-off-by: Hugh Dickins Cc: "Luck, Tony" Cc: "David S. Miller" Acked-by: Adam Litke Acked-by: David Gibson Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ia64/mm/hugetlbpage.c | 4 +++- arch/powerpc/mm/hugetlbpage.c | 8 ++++++-- fs/hugetlbfs/inode.c | 21 ++++++++------------- include/linux/hugetlb.h | 10 +++++++--- mm/mmap.c | 2 +- 5 files changed, 25 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index eee5c1cfbe32..f3a9585e98a8 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c @@ -70,8 +70,10 @@ huge_pte_offset (struct mm_struct *mm, unsigned long addr) * Don't actually need to do any preparation, but need to make sure * the address is in the right region. */ -int prepare_hugepage_range(unsigned long addr, unsigned long len) +int prepare_hugepage_range(unsigned long addr, unsigned long len, pgoff_t pgoff) { + if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT)) + return -EINVAL; if (len & ~HPAGE_MASK) return -EINVAL; if (addr & ~HPAGE_MASK) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index fd68b74c07c3..506d89768d45 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -491,11 +491,15 @@ static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas) return 0; } -int prepare_hugepage_range(unsigned long addr, unsigned long len) +int prepare_hugepage_range(unsigned long addr, unsigned long len, pgoff_t pgoff) { int err = 0; - if ( (addr+len) < addr ) + if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT)) + return -EINVAL; + if (len & ~HPAGE_MASK) + return -EINVAL; + if (addr & ~HPAGE_MASK) return -EINVAL; if (addr < 0x100000000UL) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 0bea6a619e10..7f4756963d05 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -62,24 +62,19 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) loff_t len, vma_len; int ret; - if (vma->vm_pgoff & (HPAGE_SIZE / PAGE_SIZE - 1)) - return -EINVAL; - - if (vma->vm_start & ~HPAGE_MASK) - return -EINVAL; - - if (vma->vm_end & ~HPAGE_MASK) - return -EINVAL; - - if (vma->vm_end - vma->vm_start < HPAGE_SIZE) - return -EINVAL; + /* + * vma alignment has already been checked by prepare_hugepage_range. + * If you add any error returns here, do so after setting VM_HUGETLB, + * so is_vm_hugetlb_page tests below unmap_region go the right way + * when do_mmap_pgoff unwinds (may be important on powerpc and ia64). + */ + vma->vm_flags |= VM_HUGETLB | VM_RESERVED; + vma->vm_ops = &hugetlb_vm_ops; vma_len = (loff_t)(vma->vm_end - vma->vm_start); mutex_lock(&inode->i_mutex); file_accessed(file); - vma->vm_flags |= VM_HUGETLB | VM_RESERVED; - vma->vm_ops = &hugetlb_vm_ops; ret = -ENOMEM; len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 5081d27bfa27..ace64e57e17f 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -60,8 +60,11 @@ void hugetlb_free_pgd_range(struct mmu_gather **tlb, unsigned long addr, * If the arch doesn't supply something else, assume that hugepage * size aligned regions are ok without further preparation. */ -static inline int prepare_hugepage_range(unsigned long addr, unsigned long len) +static inline int prepare_hugepage_range(unsigned long addr, unsigned long len, + pgoff_t pgoff) { + if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT)) + return -EINVAL; if (len & ~HPAGE_MASK) return -EINVAL; if (addr & ~HPAGE_MASK) @@ -69,7 +72,8 @@ static inline int prepare_hugepage_range(unsigned long addr, unsigned long len) return 0; } #else -int prepare_hugepage_range(unsigned long addr, unsigned long len); +int prepare_hugepage_range(unsigned long addr, unsigned long len, + pgoff_t pgoff); #endif #ifndef ARCH_HAS_SETCLEAR_HUGE_PTE @@ -107,7 +111,7 @@ static inline unsigned long hugetlb_total_pages(void) #define hugetlb_report_meminfo(buf) 0 #define hugetlb_report_node_meminfo(n, buf) 0 #define follow_huge_pmd(mm, addr, pmd, write) NULL -#define prepare_hugepage_range(addr, len) (-EINVAL) +#define prepare_hugepage_range(addr,len,pgoff) (-EINVAL) #define pmd_huge(x) 0 #define is_hugepage_only_range(mm, addr, len) 0 #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; }) diff --git a/mm/mmap.c b/mm/mmap.c index 497e502dfd6b..bdace87d7c01 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1379,7 +1379,7 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, * Check if the given range is hugepage aligned, and * can be made suitable for hugepages. */ - ret = prepare_hugepage_range(addr, len); + ret = prepare_hugepage_range(addr, len, pgoff); } else { /* * Ensure that a normal request is not falling in a -- cgit v1.2.3 From b96e7ecbd052a0916b6078e7600604d7e276a336 Mon Sep 17 00:00:00 2001 From: Yasuyuki Kozakai Date: Tue, 14 Nov 2006 19:48:48 -0800 Subject: [NETFILTER]: ip6_tables: fixed conflicted optname for getsockopt 66 and 67 for getsockopt on IPv6 socket is doubly used for IPv6 Advanced API and ip6tables. This moves numbers for ip6tables to 68 and 69. This also kills XT_SO_* because {ip,ip6,arp}_tables doesn't have so much common numbers now. The old userland tools keep to behave as ever, because old kernel always calls functions of IPv6 Advanced API for their numbers. Signed-off-by: Yasuyuki Kozakai Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/in6.h | 12 +++++++++++- include/linux/netfilter/x_tables.h | 16 ---------------- include/linux/netfilter_arp/arp_tables.h | 25 +++++++++++++------------ include/linux/netfilter_ipv4/ip_tables.h | 27 +++++++++++++++------------ include/linux/netfilter_ipv6/ip6_tables.h | 27 +++++++++++++++------------ 5 files changed, 54 insertions(+), 53 deletions(-) (limited to 'include/linux') diff --git a/include/linux/in6.h b/include/linux/in6.h index 9be6a4756f0b..f28621f638e0 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -225,7 +225,7 @@ struct in6_flowlabel_req #endif /* - * Netfilter + * Netfilter (1) * * Following socket options are used in ip6_tables; * see include/linux/netfilter_ipv6/ip6_tables.h. @@ -240,4 +240,14 @@ struct in6_flowlabel_req #define IPV6_RECVTCLASS 66 #define IPV6_TCLASS 67 +/* + * Netfilter (2) + * + * Following socket options are used in ip6_tables; + * see include/linux/netfilter_ipv6/ip6_tables.h. + * + * IP6T_SO_GET_REVISION_MATCH 68 + * IP6T_SO_GET_REVISION_TARGET 69 + */ + #endif diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 04319a76103a..022edfa97ed9 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -96,22 +96,6 @@ struct _xt_align /* Error verdict. */ #define XT_ERROR_TARGET "ERROR" -/* - * New IP firewall options for [gs]etsockopt at the RAW IP level. - * Unlike BSD Linux inherits IP options so you don't have to use a raw - * socket for this. Instead we check rights in the calls. */ -#define XT_BASE_CTL 64 /* base for firewall socket options */ - -#define XT_SO_SET_REPLACE (XT_BASE_CTL) -#define XT_SO_SET_ADD_COUNTERS (XT_BASE_CTL + 1) -#define XT_SO_SET_MAX XT_SO_SET_ADD_COUNTERS - -#define XT_SO_GET_INFO (XT_BASE_CTL) -#define XT_SO_GET_ENTRIES (XT_BASE_CTL + 1) -#define XT_SO_GET_REVISION_MATCH (XT_BASE_CTL + 2) -#define XT_SO_GET_REVISION_TARGET (XT_BASE_CTL + 3) -#define XT_SO_GET_MAX XT_SO_GET_REVISION_TARGET - #define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0) #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0) diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 44e39b61d9e7..0be235418a2f 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -112,19 +112,20 @@ struct arpt_entry * New IP firewall options for [gs]etsockopt at the RAW IP level. * Unlike BSD Linux inherits IP options so you don't have to use a raw * socket for this. Instead we check rights in the calls. + * + * ATTENTION: check linux/in.h before adding new number here. */ -#define ARPT_CTL_OFFSET 32 -#define ARPT_BASE_CTL (XT_BASE_CTL+ARPT_CTL_OFFSET) - -#define ARPT_SO_SET_REPLACE (XT_SO_SET_REPLACE+ARPT_CTL_OFFSET) -#define ARPT_SO_SET_ADD_COUNTERS (XT_SO_SET_ADD_COUNTERS+ARPT_CTL_OFFSET) -#define ARPT_SO_SET_MAX (XT_SO_SET_MAX+ARPT_CTL_OFFSET) - -#define ARPT_SO_GET_INFO (XT_SO_GET_INFO+ARPT_CTL_OFFSET) -#define ARPT_SO_GET_ENTRIES (XT_SO_GET_ENTRIES+ARPT_CTL_OFFSET) -/* #define ARPT_SO_GET_REVISION_MATCH XT_SO_GET_REVISION_MATCH */ -#define ARPT_SO_GET_REVISION_TARGET (XT_SO_GET_REVISION_TARGET+ARPT_CTL_OFFSET) -#define ARPT_SO_GET_MAX (XT_SO_GET_REVISION_TARGET+ARPT_CTL_OFFSET) +#define ARPT_BASE_CTL 96 + +#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL) +#define ARPT_SO_SET_ADD_COUNTERS (ARPT_BASE_CTL + 1) +#define ARPT_SO_SET_MAX ARPT_SO_SET_ADD_COUNTERS + +#define ARPT_SO_GET_INFO (ARPT_BASE_CTL) +#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1) +/* #define ARPT_SO_GET_REVISION_MATCH (APRT_BASE_CTL + 2) */ +#define ARPT_SO_GET_REVISION_TARGET (ARPT_BASE_CTL + 3) +#define ARPT_SO_GET_MAX (ARPT_SO_GET_REVISION_TARGET) /* CONTINUE verdict for targets */ #define ARPT_CONTINUE XT_CONTINUE diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index a536bbdef145..4f06dad0bde9 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -101,18 +101,21 @@ struct ipt_entry /* * New IP firewall options for [gs]etsockopt at the RAW IP level. * Unlike BSD Linux inherits IP options so you don't have to use a raw - * socket for this. Instead we check rights in the calls. */ -#define IPT_BASE_CTL XT_BASE_CTL - -#define IPT_SO_SET_REPLACE XT_SO_SET_REPLACE -#define IPT_SO_SET_ADD_COUNTERS XT_SO_SET_ADD_COUNTERS -#define IPT_SO_SET_MAX XT_SO_SET_MAX - -#define IPT_SO_GET_INFO XT_SO_GET_INFO -#define IPT_SO_GET_ENTRIES XT_SO_GET_ENTRIES -#define IPT_SO_GET_REVISION_MATCH XT_SO_GET_REVISION_MATCH -#define IPT_SO_GET_REVISION_TARGET XT_SO_GET_REVISION_TARGET -#define IPT_SO_GET_MAX XT_SO_GET_REVISION_TARGET + * socket for this. Instead we check rights in the calls. + * + * ATTENTION: check linux/in.h before adding new number here. + */ +#define IPT_BASE_CTL 64 + +#define IPT_SO_SET_REPLACE (IPT_BASE_CTL) +#define IPT_SO_SET_ADD_COUNTERS (IPT_BASE_CTL + 1) +#define IPT_SO_SET_MAX IPT_SO_SET_ADD_COUNTERS + +#define IPT_SO_GET_INFO (IPT_BASE_CTL) +#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1) +#define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2) +#define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3) +#define IPT_SO_GET_MAX IPT_SO_GET_REVISION_TARGET #define IPT_CONTINUE XT_CONTINUE #define IPT_RETURN XT_RETURN diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index d7a8e9c0dad0..4aed340401db 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -107,18 +107,21 @@ struct ip6t_entry /* * New IP firewall options for [gs]etsockopt at the RAW IP level. * Unlike BSD Linux inherits IP options so you don't have to use - * a raw socket for this. Instead we check rights in the calls. */ -#define IP6T_BASE_CTL XT_BASE_CTL - -#define IP6T_SO_SET_REPLACE XT_SO_SET_REPLACE -#define IP6T_SO_SET_ADD_COUNTERS XT_SO_SET_ADD_COUNTERS -#define IP6T_SO_SET_MAX XT_SO_SET_MAX - -#define IP6T_SO_GET_INFO XT_SO_GET_INFO -#define IP6T_SO_GET_ENTRIES XT_SO_GET_ENTRIES -#define IP6T_SO_GET_REVISION_MATCH XT_SO_GET_REVISION_MATCH -#define IP6T_SO_GET_REVISION_TARGET XT_SO_GET_REVISION_TARGET -#define IP6T_SO_GET_MAX XT_SO_GET_REVISION_TARGET + * a raw socket for this. Instead we check rights in the calls. + * + * ATTENTION: check linux/in6.h before adding new number here. + */ +#define IP6T_BASE_CTL 64 + +#define IP6T_SO_SET_REPLACE (IP6T_BASE_CTL) +#define IP6T_SO_SET_ADD_COUNTERS (IP6T_BASE_CTL + 1) +#define IP6T_SO_SET_MAX IP6T_SO_SET_ADD_COUNTERS + +#define IP6T_SO_GET_INFO (IP6T_BASE_CTL) +#define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1) +#define IP6T_SO_GET_REVISION_MATCH (IP6T_BASE_CTL + 4) +#define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 5) +#define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET /* CONTINUE verdict for targets */ #define IP6T_CONTINUE XT_CONTINUE -- cgit v1.2.3 From c7835a77c86422d276b0d1a4c70924d933014c13 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 15 Nov 2006 21:14:42 -0800 Subject: [TG3]: Disable TSO on 5906 if CLKREQ is enabled. Due to hardware errata, TSO must be disabled if the PCI Express clock request is enabled on 5906. The chip may hang when transmitting TSO frames if CLKREQ is enabled. Update version to 3.69. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 20 ++++++++++++++++---- include/linux/pci_regs.h | 1 + 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6e86866bd3fa..1dbdd6bb587b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.68" -#define DRV_MODULE_RELDATE "November 02, 2006" +#define DRV_MODULE_VERSION "3.69" +#define DRV_MODULE_RELDATE "November 15, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -10366,7 +10366,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) u32 pci_state_reg, grc_misc_cfg; u32 val; u16 pci_cmd; - int err; + int err, pcie_cap; /* Force memory write invalidate off. If we leave it on, * then on 5700_BX chips we have to enable a workaround. @@ -10541,8 +10541,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; - if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0) + pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); + if (pcie_cap != 0) { tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + u16 lnkctl; + + pci_read_config_word(tp->pdev, + pcie_cap + PCI_EXP_LNKCTL, + &lnkctl); + if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) + tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; + } + } /* If we have an AMD 762 or VIA K8T800 chipset, write * reordering to the mailbox registers done by the host @@ -11809,6 +11820,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A0 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) { tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; } else { diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index c312a12ad2d6..c321316f1bc7 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -371,6 +371,7 @@ #define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ #define PCI_EXP_LNKCAP 12 /* Link Capabilities */ #define PCI_EXP_LNKCTL 16 /* Link Control */ +#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ #define PCI_EXP_LNKSTA 18 /* Link Status */ #define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ #define PCI_EXP_SLTCTL 24 /* Slot Control */ -- cgit v1.2.3 From da63fc7ce63b43426dc3c69c05e28de2872c159a Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Thu, 16 Nov 2006 01:19:28 -0800 Subject: [PATCH] fat: add fat_getattr() This adds fat_getattr() for setting stat->blksize. (FAT uses the size of cluster for proper I/O) Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/file.c | 10 ++++++++++ fs/msdos/namei.c | 1 + fs/vfat/namei.c | 1 + include/linux/msdos_fs.h | 2 ++ 4 files changed, 14 insertions(+) (limited to 'include/linux') diff --git a/fs/fat/file.c b/fs/fat/file.c index 8337451e7897..0aa813d944a6 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -303,7 +303,17 @@ void fat_truncate(struct inode *inode) fat_flush_inodes(inode->i_sb, inode, NULL); } +int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + generic_fillattr(inode, stat); + stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size; + return 0; +} +EXPORT_SYMBOL_GPL(fat_getattr); + struct inode_operations fat_file_inode_operations = { .truncate = fat_truncate, .setattr = fat_notify_change, + .getattr = fat_getattr, }; diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index b0f01b3b0536..452461955cbd 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -654,6 +654,7 @@ static struct inode_operations msdos_dir_inode_operations = { .rmdir = msdos_rmdir, .rename = msdos_rename, .setattr = fat_notify_change, + .getattr = fat_getattr, }; static int msdos_fill_super(struct super_block *sb, void *data, int silent) diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index edb711ff7b05..0afd745a37cd 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -1004,6 +1004,7 @@ static struct inode_operations vfat_dir_inode_operations = { .rmdir = vfat_rmdir, .rename = vfat_rename, .setattr = fat_notify_change, + .getattr = fat_getattr, }; static int vfat_fill_super(struct super_block *sb, void *data, int silent) diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index ce6c85815cbd..24a9ef1506b6 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -402,6 +402,8 @@ extern const struct file_operations fat_file_operations; extern struct inode_operations fat_file_inode_operations; extern int fat_notify_change(struct dentry * dentry, struct iattr * attr); extern void fat_truncate(struct inode *inode); +extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat); /* fat/inode.c */ extern void fat_attach(struct inode *inode, loff_t i_pos); -- cgit v1.2.3 From 9d92fe17b652f5496c97bc83fdfe925f3182f602 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 17 Nov 2006 01:07:39 -0500 Subject: Input: serio - remove serio_unregister_port_delayed() Now that i8042 reserves IRQs early there are no more users of this function and it should be removed. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 18 ------------------ include/linux/serio.h | 5 ----- 2 files changed, 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 3cb99d454ecd..cd55ddb7df4f 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -44,7 +44,6 @@ EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_child_port); -EXPORT_SYMBOL(__serio_unregister_port_delayed); EXPORT_SYMBOL(__serio_register_driver); EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); @@ -64,7 +63,6 @@ static struct bus_type serio_bus; static void serio_add_driver(struct serio_driver *drv); static void serio_add_port(struct serio *serio); -static void serio_destroy_port(struct serio *serio); static void serio_reconnect_port(struct serio *serio); static void serio_disconnect_port(struct serio *serio); @@ -173,7 +171,6 @@ enum serio_event_type { SERIO_RESCAN, SERIO_RECONNECT, SERIO_REGISTER_PORT, - SERIO_UNREGISTER_PORT, SERIO_REGISTER_DRIVER, }; @@ -307,11 +304,6 @@ static void serio_handle_event(void) serio_add_port(event->object); break; - case SERIO_UNREGISTER_PORT: - serio_disconnect_port(event->object); - serio_destroy_port(event->object); - break; - case SERIO_RECONNECT: serio_reconnect_port(event->object); break; @@ -716,16 +708,6 @@ void serio_unregister_child_port(struct serio *serio) mutex_unlock(&serio_mutex); } -/* - * Submits register request to kseriod for subsequent execution. - * Can be used when it is not obvious whether the serio_mutex is - * taken or not and when delayed execution is feasible. - */ -void __serio_unregister_port_delayed(struct serio *serio, struct module *owner) -{ - serio_queue_event(serio, owner, SERIO_UNREGISTER_PORT); -} - /* * Serio driver operations diff --git a/include/linux/serio.h b/include/linux/serio.h index b99c5ca9708d..8f52228390ab 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -85,11 +85,6 @@ static inline void serio_register_port(struct serio *serio) void serio_unregister_port(struct serio *serio); void serio_unregister_child_port(struct serio *serio); -void __serio_unregister_port_delayed(struct serio *serio, struct module *owner); -static inline void serio_unregister_port_delayed(struct serio *serio) -{ - __serio_unregister_port_delayed(serio, THIS_MODULE); -} void __serio_register_driver(struct serio_driver *drv, struct module *owner); static inline void serio_register_driver(struct serio_driver *drv) -- cgit v1.2.3 From 610a5b742e9df4e59047f22d13d8bd83cafce388 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Fri, 17 Nov 2006 11:51:41 +1100 Subject: [CRYPTO] api: Remove one too many semicolon This patch has removed one too many semicolon in crypto.h. Signed-off-by: Yoichi Yuasa Signed-off-by: Herbert Xu --- include/linux/crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 8f2ffa4caabf..6485e9716b36 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -245,7 +245,7 @@ int crypto_alg_available(const char *name, u32 flags) __deprecated_for_modules; int crypto_has_alg(const char *name, u32 type, u32 mask); #else -static int crypto_alg_available(const char *name, u32 flags); +static int crypto_alg_available(const char *name, u32 flags) __deprecated_for_modules; static inline int crypto_alg_available(const char *name, u32 flags) { -- cgit v1.2.3 From b3438f8266cb1f5010085ac47d7ad6a36a212164 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 20 Nov 2006 11:47:18 -0800 Subject: Add "pure_initcall" for static variable initialization This is a quick hack to overcome the fact that SRCU currently does not allow static initializers, and we need to sometimes initialize those things before any other initializers (even "core" ones) can do so. Currently we don't allow this at all for modules, and the only user that needs is right now is cpufreq. As reported by Thomas Gleixner: "Commit b4dfdbb3c707474a2254c5b4d7e62be31a4b7da9 ("[PATCH] cpufreq: make the transition_notifier chain use SRCU breaks cpu frequency notification users, which register the callback > on core_init level." Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Arjan van de Ven Cc: Andrew Morton , Signed-off-by: Linus Torvalds --- drivers/cpufreq/cpufreq.c | 2 +- include/asm-generic/vmlinux.lds.h | 2 ++ include/linux/init.h | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 86e69b7f9122..dd0c2623e27b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -59,7 +59,7 @@ static int __init init_cpufreq_transition_notifier_list(void) srcu_init_notifier_head(&cpufreq_transition_notifier_list); return 0; } -core_initcall(init_cpufreq_transition_notifier_list); +pure_initcall(init_cpufreq_transition_notifier_list); static LIST_HEAD(cpufreq_governor_list); static DEFINE_MUTEX (cpufreq_governor_mutex); diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 9d873163a7ab..e60d6f21fa62 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -215,6 +215,8 @@ .notes : { *(.note.*) } :note #define INITCALLS \ + *(.initcall0.init) \ + *(.initcall0s.init) \ *(.initcall1.init) \ *(.initcall1s.init) \ *(.initcall2.init) \ diff --git a/include/linux/init.h b/include/linux/init.h index ff40ea118e3a..5eb5d24b7680 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -93,6 +93,14 @@ extern void setup_arch(char **); static initcall_t __initcall_##fn##id __attribute_used__ \ __attribute__((__section__(".initcall" level ".init"))) = fn +/* + * A "pure" initcall has no dependencies on anything else, and purely + * initializes variables that couldn't be statically initialized. + * + * This only exists for built-in code, not for modules. + */ +#define pure_initcall(fn) __define_initcall("0",fn,1) + #define core_initcall(fn) __define_initcall("1",fn,1) #define core_initcall_sync(fn) __define_initcall("1s",fn,1s) #define postcore_initcall(fn) __define_initcall("2",fn,2) -- cgit v1.2.3 From fb47ddb2db9c18664bd7b06c201a2398885b64fc Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Sun, 19 Nov 2006 10:38:39 -0800 Subject: [IGMP]: Fix IGMPV3_EXP() normalization bit shift value. The IGMPV3_EXP() macro doesn't correctly shift the normalization bit, so time-out values are longer than they should be. Thanks to Dirk Ooms for finding the problem in IGMPv3 - MLDv2 had a similar problem that was already fixed a year ago. :-( Signed-off-by: David L Stevens Signed-off-by: David S. Miller --- include/linux/igmp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 03f43e2893a4..21dd56905271 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -191,7 +191,7 @@ struct ip_mc_list #define IGMPV3_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value)) #define IGMPV3_EXP(thresh, nbmant, nbexp, value) \ ((value) < (thresh) ? (value) : \ - ((IGMPV3_MASK(value, nbmant) | (1<<(nbmant+nbexp))) << \ + ((IGMPV3_MASK(value, nbmant) | (1<<(nbmant))) << \ (IGMPV3_MASK((value) >> (nbmant), nbexp) + (nbexp)))) #define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value) -- cgit v1.2.3 From 52bad64d95bd89e08c49ec5a071fa6dcbe5a1a9c Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 22 Nov 2006 14:54:01 +0000 Subject: WorkStruct: Separate delayable and non-delayable events. Separate delayable work items from non-delayable work items be splitting them into a separate structure (delayed_work), which incorporates a work_struct and the timer_list removed from work_struct. The work_struct struct is huge, and this limits it's usefulness. On a 64-bit architecture it's nearly 100 bytes in size. This reduces that by half for the non-delayable type of event. Signed-Off-By: David Howells --- arch/x86_64/kernel/mce.c | 2 +- drivers/ata/libata-core.c | 11 +++----- drivers/ata/libata-eh.c | 2 +- drivers/char/random.c | 2 +- drivers/char/tty_io.c | 2 +- fs/aio.c | 4 +-- fs/nfs/client.c | 2 +- fs/nfs/namespace.c | 3 ++- include/linux/aio.h | 2 +- include/linux/kbd_kern.h | 2 +- include/linux/libata.h | 4 +-- include/linux/nfs_fs_sb.h | 2 +- include/linux/sunrpc/rpc_pipe_fs.h | 2 +- include/linux/sunrpc/xprt.h | 2 +- include/linux/tty.h | 2 +- include/linux/workqueue.h | 44 +++++++++++++++++++++++--------- kernel/workqueue.c | 51 +++++++++++++++++++++----------------- mm/slab.c | 8 +++--- net/core/link_watch.c | 9 +++---- net/sunrpc/cache.c | 4 +-- net/sunrpc/rpc_pipe.c | 3 ++- net/sunrpc/xprtsock.c | 6 ++--- 22 files changed, 96 insertions(+), 73 deletions(-) (limited to 'include/linux') diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index bbea88801d88..5306f2630905 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -307,7 +307,7 @@ void mce_log_therm_throt_event(unsigned int cpu, __u64 status) static int check_interval = 5 * 60; /* 5 minutes */ static void mcheck_timer(void *data); -static DECLARE_WORK(mcheck_work, mcheck_timer, NULL); +static DECLARE_DELAYED_WORK(mcheck_work, mcheck_timer, NULL); static void mcheck_check_cpu(void *info) { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 915a55a6cc14..0bb4b4dced76 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -937,12 +937,9 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK) return; - PREPARE_WORK(&ap->port_task, fn, data); + PREPARE_DELAYED_WORK(&ap->port_task, fn, data); - if (!delay) - rc = queue_work(ata_wq, &ap->port_task); - else - rc = queue_delayed_work(ata_wq, &ap->port_task, delay); + rc = queue_delayed_work(ata_wq, &ap->port_task, delay); /* rc == 0 means that another user is using port task */ WARN_ON(rc == 0); @@ -5320,8 +5317,8 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host, ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN; #endif - INIT_WORK(&ap->port_task, NULL, NULL); - INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap); + INIT_DELAYED_WORK(&ap->port_task, NULL, NULL); + INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap); INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap); INIT_LIST_HEAD(&ap->eh_done_q); init_waitqueue_head(&ap->eh_wait_q); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 02b2b2787d9b..9f6b7cc74fd9 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -332,7 +332,7 @@ void ata_scsi_error(struct Scsi_Host *host) if (ap->pflags & ATA_PFLAG_LOADING) ap->pflags &= ~ATA_PFLAG_LOADING; else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) - queue_work(ata_aux_wq, &ap->hotplug_task); + queue_delayed_work(ata_aux_wq, &ap->hotplug_task, 0); if (ap->pflags & ATA_PFLAG_RECOVERED) ata_port_printk(ap, KERN_INFO, "EH complete\n"); diff --git a/drivers/char/random.c b/drivers/char/random.c index eb6b13f4211a..f2ab61f3e8ae 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1424,7 +1424,7 @@ static unsigned int ip_cnt; static void rekey_seq_generator(void *private_); -static DECLARE_WORK(rekey_work, rekey_seq_generator, NULL); +static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator, NULL); /* * Lock avoidance: diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e90ea39c7c4b..7297acfe520c 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -3580,7 +3580,7 @@ static void initialize_tty_struct(struct tty_struct *tty) tty->overrun_time = jiffies; tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); - INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); + INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc, tty); init_MUTEX(&tty->buf.pty_sem); mutex_init(&tty->termios_mutex); init_waitqueue_head(&tty->write_wait); diff --git a/fs/aio.c b/fs/aio.c index 94766599db00..11a1a7100ad6 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -227,7 +227,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) INIT_LIST_HEAD(&ctx->active_reqs); INIT_LIST_HEAD(&ctx->run_list); - INIT_WORK(&ctx->wq, aio_kick_handler, ctx); + INIT_DELAYED_WORK(&ctx->wq, aio_kick_handler, ctx); if (aio_setup_ring(ctx) < 0) goto out_freectx; @@ -876,7 +876,7 @@ static void aio_kick_handler(void *data) * we're in a worker thread already, don't use queue_delayed_work, */ if (requeue) - queue_work(aio_wq, &ctx->wq); + queue_delayed_work(aio_wq, &ctx->wq, 0); } diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 5fea638743e4..6f0487d6f44a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -143,7 +143,7 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, INIT_LIST_HEAD(&clp->cl_state_owners); INIT_LIST_HEAD(&clp->cl_unused); spin_lock_init(&clp->cl_lock); - INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); + INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state, clp); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); clp->cl_boot_time = CURRENT_TIME; clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index ec1114b33d89..5ed798bc1cf7 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -21,7 +21,8 @@ static void nfs_expire_automounts(void *list); LIST_HEAD(nfs_automount_list); -static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list); +static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts, + &nfs_automount_list); int nfs_mountpoint_expiry_timeout = 500 * HZ; static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, diff --git a/include/linux/aio.h b/include/linux/aio.h index 0d71c0041f13..9e350fd44d77 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -194,7 +194,7 @@ struct kioctx { struct aio_ring_info ring_info; - struct work_struct wq; + struct delayed_work wq; }; /* prototypes */ diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index efe0ee4cc80b..06c58c423fe1 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -158,7 +158,7 @@ static inline void con_schedule_flip(struct tty_struct *t) if (t->buf.tail != NULL) t->buf.tail->commit = t->buf.tail->used; spin_unlock_irqrestore(&t->buf.lock, flags); - schedule_work(&t->buf.work); + schedule_delayed_work(&t->buf.work, 0); } #endif diff --git a/include/linux/libata.h b/include/linux/libata.h index abd2debebca2..5f04006e8dd2 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -568,8 +568,8 @@ struct ata_port { struct ata_host *host; struct device *dev; - struct work_struct port_task; - struct work_struct hotplug_task; + struct delayed_work port_task; + struct delayed_work hotplug_task; struct work_struct scsi_rescan_task; unsigned int hsm_task_state; diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 7ccfc7ef0a83..95796e6924f1 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -51,7 +51,7 @@ struct nfs_client { unsigned long cl_lease_time; unsigned long cl_last_renewal; - struct work_struct cl_renewd; + struct delayed_work cl_renewd; struct rpc_wait_queue cl_rpcwaitq; diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index a2eb9b4a9de3..4a68125b6de6 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -30,7 +30,7 @@ struct rpc_inode { #define RPC_PIPE_WAIT_FOR_OPEN 1 int flags; struct rpc_pipe_ops *ops; - struct work_struct queue_timeout; + struct delayed_work queue_timeout; }; static inline struct rpc_inode * diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 60394fbc4c70..3e04c1512fc4 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -177,7 +177,7 @@ struct rpc_xprt { unsigned long connect_timeout, bind_timeout, reestablish_timeout; - struct work_struct connect_worker; + struct delayed_work connect_worker; unsigned short port; /* diff --git a/include/linux/tty.h b/include/linux/tty.h index 44091c0db0b4..c1f716446161 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -53,7 +53,7 @@ struct tty_buffer { }; struct tty_bufhead { - struct work_struct work; + struct delayed_work work; struct semaphore pty_sem; spinlock_t lock; struct tty_buffer *head; /* Queue head */ diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 9bca3539a1e5..9faaccae570e 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -17,6 +17,10 @@ struct work_struct { void (*func)(void *); void *data; void *wq_data; +}; + +struct delayed_work { + struct work_struct work; struct timer_list timer; }; @@ -28,32 +32,48 @@ struct execute_work { .entry = { &(n).entry, &(n).entry }, \ .func = (f), \ .data = (d), \ + } + +#define __DELAYED_WORK_INITIALIZER(n, f, d) { \ + .work = __WORK_INITIALIZER((n).work, (f), (d)), \ .timer = TIMER_INITIALIZER(NULL, 0, 0), \ } #define DECLARE_WORK(n, f, d) \ struct work_struct n = __WORK_INITIALIZER(n, f, d) +#define DECLARE_DELAYED_WORK(n, f, d) \ + struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, d) + /* - * initialize a work-struct's func and data pointers: + * initialize a work item's function and data pointers */ #define PREPARE_WORK(_work, _func, _data) \ do { \ - (_work)->func = _func; \ - (_work)->data = _data; \ + (_work)->func = (_func); \ + (_work)->data = (_data); \ } while (0) +#define PREPARE_DELAYED_WORK(_work, _func, _data) \ + PREPARE_WORK(&(_work)->work, (_func), (_data)) + /* - * initialize all of a work-struct: + * initialize all of a work item in one go */ #define INIT_WORK(_work, _func, _data) \ do { \ INIT_LIST_HEAD(&(_work)->entry); \ (_work)->pending = 0; \ PREPARE_WORK((_work), (_func), (_data)); \ + } while (0) + +#define INIT_DELAYED_WORK(_work, _func, _data) \ + do { \ + INIT_WORK(&(_work)->work, (_func), (_data)); \ init_timer(&(_work)->timer); \ } while (0) + extern struct workqueue_struct *__create_workqueue(const char *name, int singlethread); #define create_workqueue(name) __create_workqueue((name), 0) @@ -62,24 +82,24 @@ extern struct workqueue_struct *__create_workqueue(const char *name, extern void destroy_workqueue(struct workqueue_struct *wq); extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work)); -extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay)); +extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay)); extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, - struct work_struct *work, unsigned long delay); + struct delayed_work *work, unsigned long delay); extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq)); extern int FASTCALL(schedule_work(struct work_struct *work)); -extern int FASTCALL(schedule_delayed_work(struct work_struct *work, unsigned long delay)); +extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay)); -extern int schedule_delayed_work_on(int cpu, struct work_struct *work, unsigned long delay); +extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay); extern int schedule_on_each_cpu(void (*func)(void *info), void *info); extern void flush_scheduled_work(void); extern int current_is_keventd(void); extern int keventd_up(void); extern void init_workqueues(void); -void cancel_rearming_delayed_work(struct work_struct *work); +void cancel_rearming_delayed_work(struct delayed_work *work); void cancel_rearming_delayed_workqueue(struct workqueue_struct *, - struct work_struct *); + struct delayed_work *); int execute_in_process_context(void (*fn)(void *), void *, struct execute_work *); @@ -88,13 +108,13 @@ int execute_in_process_context(void (*fn)(void *), void *, * function may still be running on return from cancel_delayed_work(). Run * flush_scheduled_work() to wait on it. */ -static inline int cancel_delayed_work(struct work_struct *work) +static inline int cancel_delayed_work(struct delayed_work *work) { int ret; ret = del_timer_sync(&work->timer); if (ret) - clear_bit(0, &work->pending); + clear_bit(0, &work->work.pending); return ret; } diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 17c2f03d2c27..44fc54b7decf 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -122,29 +122,33 @@ EXPORT_SYMBOL_GPL(queue_work); static void delayed_work_timer_fn(unsigned long __data) { - struct work_struct *work = (struct work_struct *)__data; - struct workqueue_struct *wq = work->wq_data; + struct delayed_work *dwork = (struct delayed_work *)__data; + struct workqueue_struct *wq = dwork->work.wq_data; int cpu = smp_processor_id(); if (unlikely(is_single_threaded(wq))) cpu = singlethread_cpu; - __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); + __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), &dwork->work); } /** * queue_delayed_work - queue work on a workqueue after delay * @wq: workqueue to use - * @work: work to queue + * @work: delayable work to queue * @delay: number of jiffies to wait before queueing * * Returns 0 if @work was already on a queue, non-zero otherwise. */ int fastcall queue_delayed_work(struct workqueue_struct *wq, - struct work_struct *work, unsigned long delay) + struct delayed_work *dwork, unsigned long delay) { int ret = 0; - struct timer_list *timer = &work->timer; + struct timer_list *timer = &dwork->timer; + struct work_struct *work = &dwork->work; + + if (delay == 0) + return queue_work(wq, work); if (!test_and_set_bit(0, &work->pending)) { BUG_ON(timer_pending(timer)); @@ -153,7 +157,7 @@ int fastcall queue_delayed_work(struct workqueue_struct *wq, /* This stores wq for the moment, for the timer_fn */ work->wq_data = wq; timer->expires = jiffies + delay; - timer->data = (unsigned long)work; + timer->data = (unsigned long)dwork; timer->function = delayed_work_timer_fn; add_timer(timer); ret = 1; @@ -172,10 +176,11 @@ EXPORT_SYMBOL_GPL(queue_delayed_work); * Returns 0 if @work was already on a queue, non-zero otherwise. */ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, - struct work_struct *work, unsigned long delay) + struct delayed_work *dwork, unsigned long delay) { int ret = 0; - struct timer_list *timer = &work->timer; + struct timer_list *timer = &dwork->timer; + struct work_struct *work = &dwork->work; if (!test_and_set_bit(0, &work->pending)) { BUG_ON(timer_pending(timer)); @@ -184,7 +189,7 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, /* This stores wq for the moment, for the timer_fn */ work->wq_data = wq; timer->expires = jiffies + delay; - timer->data = (unsigned long)work; + timer->data = (unsigned long)dwork; timer->function = delayed_work_timer_fn; add_timer_on(timer, cpu); ret = 1; @@ -468,31 +473,31 @@ EXPORT_SYMBOL(schedule_work); /** * schedule_delayed_work - put work task in global workqueue after delay - * @work: job to be done - * @delay: number of jiffies to wait + * @dwork: job to be done + * @delay: number of jiffies to wait or 0 for immediate execution * * After waiting for a given time this puts a job in the kernel-global * workqueue. */ -int fastcall schedule_delayed_work(struct work_struct *work, unsigned long delay) +int fastcall schedule_delayed_work(struct delayed_work *dwork, unsigned long delay) { - return queue_delayed_work(keventd_wq, work, delay); + return queue_delayed_work(keventd_wq, dwork, delay); } EXPORT_SYMBOL(schedule_delayed_work); /** * schedule_delayed_work_on - queue work in global workqueue on CPU after delay * @cpu: cpu to use - * @work: job to be done + * @dwork: job to be done * @delay: number of jiffies to wait * * After waiting for a given time this puts a job in the kernel-global * workqueue on the specified CPU. */ int schedule_delayed_work_on(int cpu, - struct work_struct *work, unsigned long delay) + struct delayed_work *dwork, unsigned long delay) { - return queue_delayed_work_on(cpu, keventd_wq, work, delay); + return queue_delayed_work_on(cpu, keventd_wq, dwork, delay); } EXPORT_SYMBOL(schedule_delayed_work_on); @@ -539,12 +544,12 @@ EXPORT_SYMBOL(flush_scheduled_work); * cancel_rearming_delayed_workqueue - reliably kill off a delayed * work whose handler rearms the delayed work. * @wq: the controlling workqueue structure - * @work: the delayed work struct + * @dwork: the delayed work struct */ void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq, - struct work_struct *work) + struct delayed_work *dwork) { - while (!cancel_delayed_work(work)) + while (!cancel_delayed_work(dwork)) flush_workqueue(wq); } EXPORT_SYMBOL(cancel_rearming_delayed_workqueue); @@ -552,11 +557,11 @@ EXPORT_SYMBOL(cancel_rearming_delayed_workqueue); /** * cancel_rearming_delayed_work - reliably kill off a delayed keventd * work whose handler rearms the delayed work. - * @work: the delayed work struct + * @dwork: the delayed work struct */ -void cancel_rearming_delayed_work(struct work_struct *work) +void cancel_rearming_delayed_work(struct delayed_work *dwork) { - cancel_rearming_delayed_workqueue(keventd_wq, work); + cancel_rearming_delayed_workqueue(keventd_wq, dwork); } EXPORT_SYMBOL(cancel_rearming_delayed_work); diff --git a/mm/slab.c b/mm/slab.c index 3c4a7e34eddc..a65bc5e992c3 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -753,7 +753,7 @@ int slab_is_available(void) return g_cpucache_up == FULL; } -static DEFINE_PER_CPU(struct work_struct, reap_work); +static DEFINE_PER_CPU(struct delayed_work, reap_work); static inline struct array_cache *cpu_cache_get(struct kmem_cache *cachep) { @@ -916,16 +916,16 @@ static void next_reap_node(void) */ static void __devinit start_cpu_timer(int cpu) { - struct work_struct *reap_work = &per_cpu(reap_work, cpu); + struct delayed_work *reap_work = &per_cpu(reap_work, cpu); /* * When this gets called from do_initcalls via cpucache_init(), * init_workqueues() has already run, so keventd will be setup * at that time. */ - if (keventd_up() && reap_work->func == NULL) { + if (keventd_up() && reap_work->work.func == NULL) { init_reap_node(cpu); - INIT_WORK(reap_work, cache_reap, NULL); + INIT_DELAYED_WORK(reap_work, cache_reap, NULL); schedule_delayed_work_on(cpu, reap_work, HZ + 3 * cpu); } } diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 4b36114744c5..f2ed09e25dfd 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -35,7 +35,7 @@ static unsigned long linkwatch_flags; static unsigned long linkwatch_nextevent; static void linkwatch_event(void *dummy); -static DECLARE_WORK(linkwatch_work, linkwatch_event, NULL); +static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event, NULL); static LIST_HEAD(lweventlist); static DEFINE_SPINLOCK(lweventlist_lock); @@ -171,10 +171,9 @@ void linkwatch_fire_event(struct net_device *dev) unsigned long delay = linkwatch_nextevent - jiffies; /* If we wrap around we'll delay it by at most HZ. */ - if (!delay || delay > HZ) - schedule_work(&linkwatch_work); - else - schedule_delayed_work(&linkwatch_work, delay); + if (delay > HZ) + delay = 0; + schedule_delayed_work(&linkwatch_work, delay); } } } diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 00cb388ece03..d5725cb1491e 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -285,7 +285,7 @@ static struct file_operations content_file_operations; static struct file_operations cache_flush_operations; static void do_cache_clean(void *data); -static DECLARE_WORK(cache_cleaner, do_cache_clean, NULL); +static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean, NULL); void cache_register(struct cache_detail *cd) { @@ -337,7 +337,7 @@ void cache_register(struct cache_detail *cd) spin_unlock(&cache_list_lock); /* start the cleaning process */ - schedule_work(&cache_cleaner); + schedule_delayed_work(&cache_cleaner, 0); } int cache_unregister(struct cache_detail *cd) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 9a0b41a97f90..97be3f7fed44 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -837,7 +837,8 @@ init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) INIT_LIST_HEAD(&rpci->pipe); rpci->pipelen = 0; init_waitqueue_head(&rpci->waitq); - INIT_WORK(&rpci->queue_timeout, rpc_timeout_upcall_queue, rpci); + INIT_DELAYED_WORK(&rpci->queue_timeout, + rpc_timeout_upcall_queue, rpci); rpci->ops = NULL; } } diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 757fc91ef25d..3c7532cd009e 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1262,7 +1262,7 @@ static void xs_connect(struct rpc_task *task) xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO; } else { dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); - schedule_work(&xprt->connect_worker); + schedule_delayed_work(&xprt->connect_worker, 0); /* flush_scheduled_work can sleep... */ if (!RPC_IS_ASYNC(task)) @@ -1375,7 +1375,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); - INIT_WORK(&xprt->connect_worker, xs_udp_connect_worker, xprt); + INIT_DELAYED_WORK(&xprt->connect_worker, xs_udp_connect_worker, xprt); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_UDP_CONN_TO; xprt->reestablish_timeout = XS_UDP_REEST_TO; @@ -1420,7 +1420,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; - INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); + INIT_DELAYED_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_TCP_CONN_TO; xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; -- cgit v1.2.3 From 6bb49e5965c1fc399b4d3cd2b5cf2da535b330c0 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 22 Nov 2006 14:54:45 +0000 Subject: WorkStruct: Typedef the work function prototype Define a type for the work function prototype. It's not only kept in the work_struct struct, it's also passed as an argument to several functions. This makes it easier to change it. Signed-Off-By: David Howells --- drivers/block/floppy.c | 4 ++-- include/linux/workqueue.h | 9 +++++---- kernel/workqueue.c | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 9e6d3a87cbe3..5a14fac13b12 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -996,7 +996,7 @@ static DECLARE_WORK(floppy_work, NULL, NULL); static void schedule_bh(void (*handler) (void)) { - PREPARE_WORK(&floppy_work, (void (*)(void *))handler, NULL); + PREPARE_WORK(&floppy_work, (work_func_t)handler, NULL); schedule_work(&floppy_work); } @@ -1008,7 +1008,7 @@ static void cancel_activity(void) spin_lock_irqsave(&floppy_lock, flags); do_floppy = NULL; - PREPARE_WORK(&floppy_work, (void *)empty, NULL); + PREPARE_WORK(&floppy_work, (work_func_t)empty, NULL); del_timer(&fd_timer); spin_unlock_irqrestore(&floppy_lock, flags); } diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 9faaccae570e..cef40b22ff9a 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -11,10 +11,12 @@ struct workqueue_struct; +typedef void (*work_func_t)(void *data); + struct work_struct { unsigned long pending; struct list_head entry; - void (*func)(void *); + work_func_t func; void *data; void *wq_data; }; @@ -91,7 +93,7 @@ extern int FASTCALL(schedule_work(struct work_struct *work)); extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay)); extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay); -extern int schedule_on_each_cpu(void (*func)(void *info), void *info); +extern int schedule_on_each_cpu(work_func_t func, void *info); extern void flush_scheduled_work(void); extern int current_is_keventd(void); extern int keventd_up(void); @@ -100,8 +102,7 @@ extern void init_workqueues(void); void cancel_rearming_delayed_work(struct delayed_work *work); void cancel_rearming_delayed_workqueue(struct workqueue_struct *, struct delayed_work *); -int execute_in_process_context(void (*fn)(void *), void *, - struct execute_work *); +int execute_in_process_context(work_func_t fn, void *, struct execute_work *); /* * Kill off a pending schedule_delayed_work(). Note that the work callback diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 44fc54b7decf..1e9d61ecf762 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -217,7 +217,7 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq) while (!list_empty(&cwq->worklist)) { struct work_struct *work = list_entry(cwq->worklist.next, struct work_struct, entry); - void (*f) (void *) = work->func; + work_func_t f = work->func; void *data = work->data; list_del_init(cwq->worklist.next); @@ -513,7 +513,7 @@ EXPORT_SYMBOL(schedule_delayed_work_on); * * schedule_on_each_cpu() is very slow. */ -int schedule_on_each_cpu(void (*func)(void *info), void *info) +int schedule_on_each_cpu(work_func_t func, void *info) { int cpu; struct work_struct *works; @@ -578,7 +578,7 @@ EXPORT_SYMBOL(cancel_rearming_delayed_work); * Returns: 0 - function was executed * 1 - function was scheduled for execution */ -int execute_in_process_context(void (*fn)(void *data), void *data, +int execute_in_process_context(work_func_t fn, void *data, struct execute_work *ew) { if (!in_interrupt()) { -- cgit v1.2.3 From 365970a1ea76d81cb1ad2f652acb605f06dae256 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 22 Nov 2006 14:54:49 +0000 Subject: WorkStruct: Merge the pending bit into the wq_data pointer Reclaim a word from the size of the work_struct by folding the pending bit and the wq_data pointer together. This shouldn't cause misalignment problems as all pointers should be at least 4-byte aligned. Signed-Off-By: David Howells --- drivers/block/floppy.c | 4 ++-- include/linux/workqueue.h | 27 +++++++++++++++++++++++---- kernel/workqueue.c | 41 ++++++++++++++++++++++++++++++++--------- 3 files changed, 57 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 5a14fac13b12..aa1eb4466f9d 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -1868,7 +1868,7 @@ static void show_floppy(void) printk("fdc_busy=%lu\n", fdc_busy); if (do_floppy) printk("do_floppy=%p\n", do_floppy); - if (floppy_work.pending) + if (work_pending(&floppy_work)) printk("floppy_work.func=%p\n", floppy_work.func); if (timer_pending(&fd_timer)) printk("fd_timer.function=%p\n", fd_timer.function); @@ -4498,7 +4498,7 @@ static void floppy_release_irq_and_dma(void) printk("floppy timer still active:%s\n", timeout_message); if (timer_pending(&fd_timer)) printk("auxiliary floppy timer still active\n"); - if (floppy_work.pending) + if (work_pending(&floppy_work)) printk("work still pending\n"); #endif old_fdc = fdc; diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index cef40b22ff9a..ecc017d24cf3 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -14,11 +14,15 @@ struct workqueue_struct; typedef void (*work_func_t)(void *data); struct work_struct { - unsigned long pending; + /* the first word is the work queue pointer and the pending flag + * rolled into one */ + unsigned long management; +#define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ +#define WORK_STRUCT_FLAG_MASK (3UL) +#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK) struct list_head entry; work_func_t func; void *data; - void *wq_data; }; struct delayed_work { @@ -65,7 +69,7 @@ struct execute_work { #define INIT_WORK(_work, _func, _data) \ do { \ INIT_LIST_HEAD(&(_work)->entry); \ - (_work)->pending = 0; \ + (_work)->management = 0; \ PREPARE_WORK((_work), (_func), (_data)); \ } while (0) @@ -75,6 +79,21 @@ struct execute_work { init_timer(&(_work)->timer); \ } while (0) +/** + * work_pending - Find out whether a work item is currently pending + * @work: The work item in question + */ +#define work_pending(work) \ + test_bit(WORK_STRUCT_PENDING, &(work)->management) + +/** + * delayed_work_pending - Find out whether a delayable work item is currently + * pending + * @work: The work item in question + */ +#define delayed_work_pending(work) \ + test_bit(WORK_STRUCT_PENDING, &(work)->work.management) + extern struct workqueue_struct *__create_workqueue(const char *name, int singlethread); @@ -115,7 +134,7 @@ static inline int cancel_delayed_work(struct delayed_work *work) ret = del_timer_sync(&work->timer); if (ret) - clear_bit(0, &work->work.pending); + clear_bit(WORK_STRUCT_PENDING, &work->work.management); return ret; } diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 1e9d61ecf762..967479756511 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -80,6 +80,29 @@ static inline int is_single_threaded(struct workqueue_struct *wq) return list_empty(&wq->list); } +static inline void set_wq_data(struct work_struct *work, void *wq) +{ + unsigned long new, old, res; + + /* assume the pending flag is already set and that the task has already + * been queued on this workqueue */ + new = (unsigned long) wq | (1UL << WORK_STRUCT_PENDING); + res = work->management; + if (res != new) { + do { + old = res; + new = (unsigned long) wq; + new |= (old & WORK_STRUCT_FLAG_MASK); + res = cmpxchg(&work->management, old, new); + } while (res != old); + } +} + +static inline void *get_wq_data(struct work_struct *work) +{ + return (void *) (work->management & WORK_STRUCT_WQ_DATA_MASK); +} + /* Preempt must be disabled. */ static void __queue_work(struct cpu_workqueue_struct *cwq, struct work_struct *work) @@ -87,7 +110,7 @@ static void __queue_work(struct cpu_workqueue_struct *cwq, unsigned long flags; spin_lock_irqsave(&cwq->lock, flags); - work->wq_data = cwq; + set_wq_data(work, cwq); list_add_tail(&work->entry, &cwq->worklist); cwq->insert_sequence++; wake_up(&cwq->more_work); @@ -108,7 +131,7 @@ int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work) { int ret = 0, cpu = get_cpu(); - if (!test_and_set_bit(0, &work->pending)) { + if (!test_and_set_bit(WORK_STRUCT_PENDING, &work->management)) { if (unlikely(is_single_threaded(wq))) cpu = singlethread_cpu; BUG_ON(!list_empty(&work->entry)); @@ -123,7 +146,7 @@ EXPORT_SYMBOL_GPL(queue_work); static void delayed_work_timer_fn(unsigned long __data) { struct delayed_work *dwork = (struct delayed_work *)__data; - struct workqueue_struct *wq = dwork->work.wq_data; + struct workqueue_struct *wq = get_wq_data(&dwork->work); int cpu = smp_processor_id(); if (unlikely(is_single_threaded(wq))) @@ -150,12 +173,12 @@ int fastcall queue_delayed_work(struct workqueue_struct *wq, if (delay == 0) return queue_work(wq, work); - if (!test_and_set_bit(0, &work->pending)) { + if (!test_and_set_bit(WORK_STRUCT_PENDING, &work->management)) { BUG_ON(timer_pending(timer)); BUG_ON(!list_empty(&work->entry)); /* This stores wq for the moment, for the timer_fn */ - work->wq_data = wq; + set_wq_data(work, wq); timer->expires = jiffies + delay; timer->data = (unsigned long)dwork; timer->function = delayed_work_timer_fn; @@ -182,12 +205,12 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, struct timer_list *timer = &dwork->timer; struct work_struct *work = &dwork->work; - if (!test_and_set_bit(0, &work->pending)) { + if (!test_and_set_bit(WORK_STRUCT_PENDING, &work->management)) { BUG_ON(timer_pending(timer)); BUG_ON(!list_empty(&work->entry)); /* This stores wq for the moment, for the timer_fn */ - work->wq_data = wq; + set_wq_data(work, wq); timer->expires = jiffies + delay; timer->data = (unsigned long)dwork; timer->function = delayed_work_timer_fn; @@ -223,8 +246,8 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq) list_del_init(cwq->worklist.next); spin_unlock_irqrestore(&cwq->lock, flags); - BUG_ON(work->wq_data != cwq); - clear_bit(0, &work->pending); + BUG_ON(get_wq_data(work) != cwq); + clear_bit(WORK_STRUCT_PENDING, &work->management); f(data); spin_lock_irqsave(&cwq->lock, flags); -- cgit v1.2.3 From 65f27f38446e1976cc98fd3004b110fedcddd189 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 22 Nov 2006 14:55:48 +0000 Subject: WorkStruct: Pass the work_struct pointer instead of context data Pass the work_struct pointer to the work function rather than context data. The work function can use container_of() to work out the data. For the cases where the container of the work_struct may go away the moment the pending bit is cleared, it is made possible to defer the release of the structure by deferring the clearing of the pending bit. To make this work, an extra flag is introduced into the management side of the work_struct. This governs auto-release of the structure upon execution. Ordinarily, the work queue executor would release the work_struct for further scheduling or deallocation by clearing the pending bit prior to jumping to the work function. This means that, unless the driver makes some guarantee itself that the work_struct won't go away, the work function may not access anything else in the work_struct or its container lest they be deallocated.. This is a problem if the auxiliary data is taken away (as done by the last patch). However, if the pending bit is *not* cleared before jumping to the work function, then the work function *may* access the work_struct and its container with no problems. But then the work function must itself release the work_struct by calling work_release(). In most cases, automatic release is fine, so this is the default. Special initiators exist for the non-auto-release case (ending in _NAR). Signed-Off-By: David Howells --- arch/x86_64/kernel/mce.c | 6 +-- arch/x86_64/kernel/smpboot.c | 12 +++-- arch/x86_64/kernel/time.c | 4 +- block/as-iosched.c | 7 +-- block/cfq-iosched.c | 8 +-- block/ll_rw_blk.c | 8 +-- crypto/cryptomgr.c | 7 +-- drivers/acpi/osl.c | 25 +++------- drivers/ata/libata-core.c | 20 ++++---- drivers/ata/libata-scsi.c | 14 +++--- drivers/ata/libata.h | 4 +- drivers/block/floppy.c | 6 +-- drivers/char/random.c | 6 +-- drivers/char/sysrq.c | 4 +- drivers/char/tty_io.c | 31 ++++++------ drivers/char/vt.c | 6 +-- drivers/cpufreq/cpufreq.c | 10 ++-- drivers/input/keyboard/atkbd.c | 6 +-- drivers/input/serio/libps2.c | 6 +-- drivers/net/e1000/e1000_main.c | 10 ++-- drivers/pci/pcie/aer/aerdrv.c | 2 +- drivers/pci/pcie/aer/aerdrv.h | 2 +- drivers/pci/pcie/aer/aerdrv_core.c | 8 +-- drivers/scsi/scsi_scan.c | 7 +-- drivers/scsi/scsi_sysfs.c | 10 ++-- fs/aio.c | 14 +++--- fs/bio.c | 6 +-- fs/file.c | 6 ++- fs/nfs/client.c | 2 +- fs/nfs/namespace.c | 9 ++-- fs/nfs/nfs4_fs.h | 2 +- fs/nfs/nfs4renewd.c | 5 +- include/linux/libata.h | 3 +- include/linux/workqueue.h | 99 +++++++++++++++++++++++++++++--------- include/net/inet_timewait_sock.h | 2 +- ipc/util.c | 7 ++- kernel/kmod.c | 16 +++--- kernel/kthread.c | 13 +++-- kernel/power/poweroff.c | 4 +- kernel/sys.c | 4 +- kernel/workqueue.c | 19 +++----- mm/slab.c | 6 +-- net/core/link_watch.c | 6 +-- net/ipv4/inet_timewait_sock.c | 5 +- net/ipv4/tcp_minisocks.c | 3 +- net/sunrpc/cache.c | 6 +-- net/sunrpc/rpc_pipe.c | 7 +-- net/sunrpc/sched.c | 8 +-- net/sunrpc/xprt.c | 7 +-- net/sunrpc/xprtsock.c | 18 ++++--- security/keys/key.c | 6 +-- 51 files changed, 293 insertions(+), 219 deletions(-) (limited to 'include/linux') diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 5306f2630905..c7587fc39015 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -306,8 +306,8 @@ void mce_log_therm_throt_event(unsigned int cpu, __u64 status) */ static int check_interval = 5 * 60; /* 5 minutes */ -static void mcheck_timer(void *data); -static DECLARE_DELAYED_WORK(mcheck_work, mcheck_timer, NULL); +static void mcheck_timer(struct work_struct *work); +static DECLARE_DELAYED_WORK(mcheck_work, mcheck_timer); static void mcheck_check_cpu(void *info) { @@ -315,7 +315,7 @@ static void mcheck_check_cpu(void *info) do_machine_check(NULL, 0); } -static void mcheck_timer(void *data) +static void mcheck_timer(struct work_struct *work) { on_each_cpu(mcheck_check_cpu, NULL, 1, 1); schedule_delayed_work(&mcheck_work, check_interval * HZ); diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 62c2e747af58..9800147c4c68 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -753,14 +753,16 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta } struct create_idle { + struct work_struct work; struct task_struct *idle; struct completion done; int cpu; }; -void do_fork_idle(void *_c_idle) +void do_fork_idle(struct work_struct *work) { - struct create_idle *c_idle = _c_idle; + struct create_idle *c_idle = + container_of(work, struct create_idle, work); c_idle->idle = fork_idle(c_idle->cpu); complete(&c_idle->done); @@ -775,10 +777,10 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid) int timeout; unsigned long start_rip; struct create_idle c_idle = { + .work = __WORK_INITIALIZER(c_idle.work, do_fork_idle), .cpu = cpu, .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done), }; - DECLARE_WORK(work, do_fork_idle, &c_idle); /* allocate memory for gdts of secondary cpus. Hotplug is considered */ if (!cpu_gdt_descr[cpu].address && @@ -825,9 +827,9 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid) * thread. */ if (!keventd_up() || current_is_keventd()) - work.func(work.data); + c_idle.work.func(&c_idle.work); else { - schedule_work(&work); + schedule_work(&c_idle.work); wait_for_completion(&c_idle.done); } diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index e3ef544d2cfb..9f05bc9b2dad 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -563,7 +563,7 @@ static unsigned int cpufreq_delayed_issched = 0; static unsigned int cpufreq_init = 0; static struct work_struct cpufreq_delayed_get_work; -static void handle_cpufreq_delayed_get(void *v) +static void handle_cpufreq_delayed_get(struct work_struct *v) { unsigned int cpu; for_each_online_cpu(cpu) { @@ -639,7 +639,7 @@ static struct notifier_block time_cpufreq_notifier_block = { static int __init cpufreq_tsc(void) { - INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL); + INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get); if (!cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER)) cpufreq_init = 1; diff --git a/block/as-iosched.c b/block/as-iosched.c index 50b95e4c1425..f371c9359999 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -1274,9 +1274,10 @@ static void as_merged_requests(request_queue_t *q, struct request *req, * * FIXME! dispatch queue is not a queue at all! */ -static void as_work_handler(void *data) +static void as_work_handler(struct work_struct *work) { - struct request_queue *q = data; + struct as_data *ad = container_of(work, struct as_data, antic_work); + struct request_queue *q = ad->q; unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); @@ -1332,7 +1333,7 @@ static void *as_init_queue(request_queue_t *q, elevator_t *e) ad->antic_timer.function = as_antic_timeout; ad->antic_timer.data = (unsigned long)q; init_timer(&ad->antic_timer); - INIT_WORK(&ad->antic_work, as_work_handler, q); + INIT_WORK(&ad->antic_work, as_work_handler); INIT_LIST_HEAD(&ad->fifo_list[REQ_SYNC]); INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]); diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 1d9c3c70a9a0..6cec3a1dccb8 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1841,9 +1841,11 @@ queue_fail: return 1; } -static void cfq_kick_queue(void *data) +static void cfq_kick_queue(struct work_struct *work) { - request_queue_t *q = data; + struct cfq_data *cfqd = + container_of(work, struct cfq_data, unplug_work); + request_queue_t *q = cfqd->queue; unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); @@ -1987,7 +1989,7 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e) cfqd->idle_class_timer.function = cfq_idle_class_timer; cfqd->idle_class_timer.data = (unsigned long) cfqd; - INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q); + INIT_WORK(&cfqd->unplug_work, cfq_kick_queue); cfqd->cfq_quantum = cfq_quantum; cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0]; diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 9eaee6640535..eb4cf6df7374 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -34,7 +34,7 @@ */ #include -static void blk_unplug_work(void *data); +static void blk_unplug_work(struct work_struct *work); static void blk_unplug_timeout(unsigned long data); static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io); static void init_request_from_bio(struct request *req, struct bio *bio); @@ -227,7 +227,7 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) if (q->unplug_delay == 0) q->unplug_delay = 1; - INIT_WORK(&q->unplug_work, blk_unplug_work, q); + INIT_WORK(&q->unplug_work, blk_unplug_work); q->unplug_timer.function = blk_unplug_timeout; q->unplug_timer.data = (unsigned long)q; @@ -1631,9 +1631,9 @@ static void blk_backing_dev_unplug(struct backing_dev_info *bdi, } } -static void blk_unplug_work(void *data) +static void blk_unplug_work(struct work_struct *work) { - request_queue_t *q = data; + request_queue_t *q = container_of(work, request_queue_t, unplug_work); blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL, q->rq.count[READ] + q->rq.count[WRITE]); diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c index 9b5b15601068..2ebffb84f1d9 100644 --- a/crypto/cryptomgr.c +++ b/crypto/cryptomgr.c @@ -40,9 +40,10 @@ struct cryptomgr_param { char template[CRYPTO_MAX_ALG_NAME]; }; -static void cryptomgr_probe(void *data) +static void cryptomgr_probe(struct work_struct *work) { - struct cryptomgr_param *param = data; + struct cryptomgr_param *param = + container_of(work, struct cryptomgr_param, work); struct crypto_template *tmpl; struct crypto_instance *inst; int err; @@ -112,7 +113,7 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) param->larval.type = larval->alg.cra_flags; param->larval.mask = larval->mask; - INIT_WORK(¶m->work, cryptomgr_probe, param); + INIT_WORK(¶m->work, cryptomgr_probe); schedule_work(¶m->work); return NOTIFY_STOP; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 068fe4f100b0..02b30ae6a68e 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -50,6 +50,7 @@ ACPI_MODULE_NAME("osl") struct acpi_os_dpc { acpi_osd_exec_callback function; void *context; + struct work_struct work; }; #ifdef CONFIG_ACPI_CUSTOM_DSDT @@ -564,12 +565,9 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */ acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number); } -static void acpi_os_execute_deferred(void *context) +static void acpi_os_execute_deferred(struct work_struct *work) { - struct acpi_os_dpc *dpc = NULL; - - - dpc = (struct acpi_os_dpc *)context; + struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); if (!dpc) { printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); return; @@ -602,7 +600,6 @@ acpi_status acpi_os_execute(acpi_execute_type type, { acpi_status status = AE_OK; struct acpi_os_dpc *dpc; - struct work_struct *task; ACPI_FUNCTION_TRACE("os_queue_for_execution"); @@ -615,28 +612,22 @@ acpi_status acpi_os_execute(acpi_execute_type type, /* * Allocate/initialize DPC structure. Note that this memory will be - * freed by the callee. The kernel handles the tq_struct list in a + * freed by the callee. The kernel handles the work_struct list in a * way that allows us to also free its memory inside the callee. * Because we may want to schedule several tasks with different * parameters we can't use the approach some kernel code uses of - * having a static tq_struct. - * We can save time and code by allocating the DPC and tq_structs - * from the same memory. + * having a static work_struct. */ - dpc = - kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct), - GFP_ATOMIC); + dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); if (!dpc) return_ACPI_STATUS(AE_NO_MEMORY); dpc->function = function; dpc->context = context; - task = (void *)(dpc + 1); - INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc); - - if (!queue_work(kacpid_wq, task)) { + INIT_WORK(&dpc->work, acpi_os_execute_deferred); + if (!queue_work(kacpid_wq, &dpc->work)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Call to queue_work() failed.\n")); kfree(dpc); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 0bb4b4dced76..b5f2da6ac80e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -914,7 +914,7 @@ static unsigned int ata_id_xfermask(const u16 *id) * ata_port_queue_task - Queue port_task * @ap: The ata_port to queue port_task for * @fn: workqueue function to be scheduled - * @data: data value to pass to workqueue function + * @data: data for @fn to use * @delay: delay time for workqueue function * * Schedule @fn(@data) for execution after @delay jiffies using @@ -929,7 +929,7 @@ static unsigned int ata_id_xfermask(const u16 *id) * LOCKING: * Inherited from caller. */ -void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, +void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data, unsigned long delay) { int rc; @@ -937,7 +937,8 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK) return; - PREPARE_DELAYED_WORK(&ap->port_task, fn, data); + PREPARE_DELAYED_WORK(&ap->port_task, fn); + ap->port_task_data = data; rc = queue_delayed_work(ata_wq, &ap->port_task, delay); @@ -4292,10 +4293,11 @@ fsm_start: return poll_next; } -static void ata_pio_task(void *_data) +static void ata_pio_task(struct work_struct *work) { - struct ata_queued_cmd *qc = _data; - struct ata_port *ap = qc->ap; + struct ata_port *ap = + container_of(work, struct ata_port, port_task.work); + struct ata_queued_cmd *qc = ap->port_task_data; u8 status; int poll_next; @@ -5317,9 +5319,9 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host, ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN; #endif - INIT_DELAYED_WORK(&ap->port_task, NULL, NULL); - INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap); - INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap); + INIT_DELAYED_WORK(&ap->port_task, NULL); + INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug); + INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); INIT_LIST_HEAD(&ap->eh_done_q); init_waitqueue_head(&ap->eh_wait_q); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 5c1fc467fc7f..c872b324dbd3 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3079,7 +3079,7 @@ static void ata_scsi_remove_dev(struct ata_device *dev) /** * ata_scsi_hotplug - SCSI part of hotplug - * @data: Pointer to ATA port to perform SCSI hotplug on + * @work: Pointer to ATA port to perform SCSI hotplug on * * Perform SCSI part of hotplug. It's executed from a separate * workqueue after EH completes. This is necessary because SCSI @@ -3089,9 +3089,10 @@ static void ata_scsi_remove_dev(struct ata_device *dev) * LOCKING: * Kernel thread context (may sleep). */ -void ata_scsi_hotplug(void *data) +void ata_scsi_hotplug(struct work_struct *work) { - struct ata_port *ap = data; + struct ata_port *ap = + container_of(work, struct ata_port, hotplug_task.work); int i; if (ap->pflags & ATA_PFLAG_UNLOADING) { @@ -3190,7 +3191,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, /** * ata_scsi_dev_rescan - initiate scsi_rescan_device() - * @data: Pointer to ATA port to perform scsi_rescan_device() + * @work: Pointer to ATA port to perform scsi_rescan_device() * * After ATA pass thru (SAT) commands are executed successfully, * libata need to propagate the changes to SCSI layer. This @@ -3200,9 +3201,10 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, * LOCKING: * Kernel thread context (may sleep). */ -void ata_scsi_dev_rescan(void *data) +void ata_scsi_dev_rescan(struct work_struct *work) { - struct ata_port *ap = data; + struct ata_port *ap = + container_of(work, struct ata_port, scsi_rescan_task); struct ata_device *dev; unsigned int i; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0ed263be652a..7e0f3aff873d 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -81,7 +81,7 @@ extern struct scsi_transport_template ata_scsi_transport_template; extern void ata_scsi_scan_host(struct ata_port *ap); extern int ata_scsi_offline_dev(struct ata_device *dev); -extern void ata_scsi_hotplug(void *data); +extern void ata_scsi_hotplug(struct work_struct *work); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); @@ -111,7 +111,7 @@ extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); -extern void ata_scsi_dev_rescan(void *data); +extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); /* libata-eh.c */ diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index aa1eb4466f9d..3f1b38276e96 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -992,11 +992,11 @@ static void empty(void) { } -static DECLARE_WORK(floppy_work, NULL, NULL); +static DECLARE_WORK(floppy_work, NULL); static void schedule_bh(void (*handler) (void)) { - PREPARE_WORK(&floppy_work, (work_func_t)handler, NULL); + PREPARE_WORK(&floppy_work, (work_func_t)handler); schedule_work(&floppy_work); } @@ -1008,7 +1008,7 @@ static void cancel_activity(void) spin_lock_irqsave(&floppy_lock, flags); do_floppy = NULL; - PREPARE_WORK(&floppy_work, (work_func_t)empty, NULL); + PREPARE_WORK(&floppy_work, (work_func_t)empty); del_timer(&fd_timer); spin_unlock_irqrestore(&floppy_lock, flags); } diff --git a/drivers/char/random.c b/drivers/char/random.c index f2ab61f3e8ae..fa764688cad1 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1422,9 +1422,9 @@ static struct keydata { static unsigned int ip_cnt; -static void rekey_seq_generator(void *private_); +static void rekey_seq_generator(struct work_struct *work); -static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator, NULL); +static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator); /* * Lock avoidance: @@ -1438,7 +1438,7 @@ static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator, NULL); * happen, and even if that happens only a not perfectly compliant * ISN is generated, nothing fatal. */ -static void rekey_seq_generator(void *private_) +static void rekey_seq_generator(struct work_struct *work) { struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)]; diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 5f49280779fb..c64f5bcff947 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -219,13 +219,13 @@ static struct sysrq_key_op sysrq_term_op = { .enable_mask = SYSRQ_ENABLE_SIGNAL, }; -static void moom_callback(void *ignored) +static void moom_callback(struct work_struct *ignored) { out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], GFP_KERNEL, 0); } -static DECLARE_WORK(moom_work, moom_callback, NULL); +static DECLARE_WORK(moom_work, moom_callback); static void sysrq_handle_moom(int key, struct tty_struct *tty) { diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 7297acfe520c..83e9e7d9b58c 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1254,7 +1254,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); /** * do_tty_hangup - actual handler for hangup events - * @data: tty device + * @work: tty device * * This can be called by the "eventd" kernel thread. That is process * synchronous but doesn't hold any locks, so we need to make sure we @@ -1274,9 +1274,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); * tasklist_lock to walk task list for hangup event * */ -static void do_tty_hangup(void *data) +static void do_tty_hangup(struct work_struct *work) { - struct tty_struct *tty = (struct tty_struct *) data; + struct tty_struct *tty = + container_of(work, struct tty_struct, hangup_work); struct file * cons_filp = NULL; struct file *filp, *f = NULL; struct task_struct *p; @@ -1433,7 +1434,7 @@ void tty_vhangup(struct tty_struct * tty) printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); #endif - do_tty_hangup((void *) tty); + do_tty_hangup(&tty->hangup_work); } EXPORT_SYMBOL(tty_vhangup); @@ -3304,12 +3305,13 @@ int tty_ioctl(struct inode * inode, struct file * file, * Nasty bug: do_SAK is being called in interrupt context. This can * deadlock. We punt it up to process context. AKPM - 16Mar2001 */ -static void __do_SAK(void *arg) +static void __do_SAK(struct work_struct *work) { + struct tty_struct *tty = + container_of(work, struct tty_struct, SAK_work); #ifdef TTY_SOFT_SAK tty_hangup(tty); #else - struct tty_struct *tty = arg; struct task_struct *g, *p; int session; int i; @@ -3388,7 +3390,7 @@ void do_SAK(struct tty_struct *tty) { if (!tty) return; - PREPARE_WORK(&tty->SAK_work, __do_SAK, tty); + PREPARE_WORK(&tty->SAK_work, __do_SAK); schedule_work(&tty->SAK_work); } @@ -3396,7 +3398,7 @@ EXPORT_SYMBOL(do_SAK); /** * flush_to_ldisc - * @private_: tty structure passed from work queue. + * @work: tty structure passed from work queue. * * This routine is called out of the software interrupt to flush data * from the buffer chain to the line discipline. @@ -3406,9 +3408,10 @@ EXPORT_SYMBOL(do_SAK); * receive_buf method is single threaded for each tty instance. */ -static void flush_to_ldisc(void *private_) +static void flush_to_ldisc(struct work_struct *work) { - struct tty_struct *tty = (struct tty_struct *) private_; + struct tty_struct *tty = + container_of(work, struct tty_struct, buf.work.work); unsigned long flags; struct tty_ldisc *disc; struct tty_buffer *tbuf, *head; @@ -3553,7 +3556,7 @@ void tty_flip_buffer_push(struct tty_struct *tty) spin_unlock_irqrestore(&tty->buf.lock, flags); if (tty->low_latency) - flush_to_ldisc((void *) tty); + flush_to_ldisc(&tty->buf.work.work); else schedule_delayed_work(&tty->buf.work, 1); } @@ -3580,17 +3583,17 @@ static void initialize_tty_struct(struct tty_struct *tty) tty->overrun_time = jiffies; tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); - INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc, tty); + INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); init_MUTEX(&tty->buf.pty_sem); mutex_init(&tty->termios_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); - INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); + INIT_WORK(&tty->hangup_work, do_tty_hangup); mutex_init(&tty->atomic_read_lock); mutex_init(&tty->atomic_write_lock); spin_lock_init(&tty->read_lock); INIT_LIST_HEAD(&tty->tty_files); - INIT_WORK(&tty->SAK_work, NULL, NULL); + INIT_WORK(&tty->SAK_work, NULL); } /* diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 8e4413f6fbaf..8ee04adc37f0 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -155,7 +155,7 @@ static void con_flush_chars(struct tty_struct *tty); static void set_vesa_blanking(char __user *p); static void set_cursor(struct vc_data *vc); static void hide_cursor(struct vc_data *vc); -static void console_callback(void *ignored); +static void console_callback(struct work_struct *ignored); static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); @@ -174,7 +174,7 @@ static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ static int blankinterval = 10*60*HZ; static int vesa_off_interval; -static DECLARE_WORK(console_work, console_callback, NULL); +static DECLARE_WORK(console_work, console_callback); /* * fg_console is the current virtual console, @@ -2154,7 +2154,7 @@ out: * with other console code and prevention of re-entrancy is * ensured with console_sem. */ -static void console_callback(void *ignored) +static void console_callback(struct work_struct *ignored) { acquire_console_sem(); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index dd0c2623e27b..7a7c6e6dfe4f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -42,7 +42,7 @@ static DEFINE_SPINLOCK(cpufreq_driver_lock); /* internal prototypes */ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); -static void handle_update(void *data); +static void handle_update(struct work_struct *work); /** * Two notifier lists: the "policy" list is involved in the @@ -665,7 +665,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) mutex_init(&policy->lock); mutex_lock(&policy->lock); init_completion(&policy->kobj_unregister); - INIT_WORK(&policy->update, handle_update, (void *)(long)cpu); + INIT_WORK(&policy->update, handle_update); /* call driver. From then on the cpufreq must be able * to accept all calls to ->verify and ->setpolicy for this CPU @@ -895,9 +895,11 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) } -static void handle_update(void *data) +static void handle_update(struct work_struct *work) { - unsigned int cpu = (unsigned int)(long)data; + struct cpufreq_policy *policy = + container_of(work, struct cpufreq_policy, update); + unsigned int cpu = policy->cpu; dprintk("handle_update for cpu %u called\n", cpu); cpufreq_update_policy(cpu); } diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index cbb93669d1ce..8451b29a3db5 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -567,9 +567,9 @@ static int atkbd_set_leds(struct atkbd *atkbd) * interrupt context. */ -static void atkbd_event_work(void *data) +static void atkbd_event_work(struct work_struct *work) { - struct atkbd *atkbd = data; + struct atkbd *atkbd = container_of(work, struct atkbd, event_work); mutex_lock(&atkbd->event_mutex); @@ -943,7 +943,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd->dev = dev; ps2_init(&atkbd->ps2dev, serio); - INIT_WORK(&atkbd->event_work, atkbd_event_work, atkbd); + INIT_WORK(&atkbd->event_work, atkbd_event_work); mutex_init(&atkbd->event_mutex); switch (serio->id.type) { diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index e5b1b60757bb..b3e84d3bb7f7 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -251,9 +251,9 @@ EXPORT_SYMBOL(ps2_command); * ps2_schedule_command(), to a PS/2 device (keyboard, mouse, etc.) */ -static void ps2_execute_scheduled_command(void *data) +static void ps2_execute_scheduled_command(struct work_struct *work) { - struct ps2work *ps2work = data; + struct ps2work *ps2work = container_of(work, struct ps2work, work); ps2_command(ps2work->ps2dev, ps2work->param, ps2work->command); kfree(ps2work); @@ -278,7 +278,7 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman ps2work->ps2dev = ps2dev; ps2work->command = command; memcpy(ps2work->param, param, send); - INIT_WORK(&ps2work->work, ps2_execute_scheduled_command, ps2work); + INIT_WORK(&ps2work->work, ps2_execute_scheduled_command); if (!schedule_work(&ps2work->work)) { kfree(ps2work); diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 726ec5e88ab2..03294400bc90 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -183,7 +183,7 @@ void e1000_set_ethtool_ops(struct net_device *netdev); static void e1000_enter_82542_rst(struct e1000_adapter *adapter); static void e1000_leave_82542_rst(struct e1000_adapter *adapter); static void e1000_tx_timeout(struct net_device *dev); -static void e1000_reset_task(struct net_device *dev); +static void e1000_reset_task(struct work_struct *work); static void e1000_smartspeed(struct e1000_adapter *adapter); static int e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb); @@ -908,8 +908,7 @@ e1000_probe(struct pci_dev *pdev, adapter->phy_info_timer.function = &e1000_update_phy_info; adapter->phy_info_timer.data = (unsigned long) adapter; - INIT_WORK(&adapter->reset_task, - (void (*)(void *))e1000_reset_task, netdev); + INIT_WORK(&adapter->reset_task, e1000_reset_task); e1000_check_options(adapter); @@ -3154,9 +3153,10 @@ e1000_tx_timeout(struct net_device *netdev) } static void -e1000_reset_task(struct net_device *netdev) +e1000_reset_task(struct work_struct *work) { - struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_adapter *adapter = + container_of(work, struct e1000_adapter, reset_task); e1000_reinit_locked(adapter); } diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 04c43ef529ac..55866b6b26fa 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -160,7 +160,7 @@ static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev) rpc->e_lock = SPIN_LOCK_UNLOCKED; rpc->rpd = dev; - INIT_WORK(&rpc->dpc_handler, aer_isr, (void *)dev); + INIT_WORK(&rpc->dpc_handler, aer_isr); rpc->prod_idx = rpc->cons_idx = 0; mutex_init(&rpc->rpc_mutex); init_waitqueue_head(&rpc->wait_release); diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index daf0cad88fc8..3c0a58f64dd8 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -118,7 +118,7 @@ extern struct bus_type pcie_port_bus_type; extern void aer_enable_rootport(struct aer_rpc *rpc); extern void aer_delete_rootport(struct aer_rpc *rpc); extern int aer_init(struct pcie_device *dev); -extern void aer_isr(void *context); +extern void aer_isr(struct work_struct *work); extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); extern int aer_osc_setup(struct pci_dev *dev); diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 1c7e660d6535..08e13033ced8 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -690,14 +690,14 @@ static void aer_isr_one_error(struct pcie_device *p_device, /** * aer_isr - consume errors detected by root port - * @context: pointer to a private data of pcie device + * @work: definition of this work item * * Invoked, as DPC, when root port records new detected error **/ -void aer_isr(void *context) +void aer_isr(struct work_struct *work) { - struct pcie_device *p_device = (struct pcie_device *) context; - struct aer_rpc *rpc = get_service_data(p_device); + struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler); + struct pcie_device *p_device = rpc->rpd; struct aer_err_source *e_src; mutex_lock(&rpc->rpc_mutex); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 94a274645f6f..d3c5e964c964 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -362,9 +362,10 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, goto retry; } -static void scsi_target_reap_usercontext(void *data) +static void scsi_target_reap_usercontext(struct work_struct *work) { - struct scsi_target *starget = data; + struct scsi_target *starget = + container_of(work, struct scsi_target, ew.work); struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); unsigned long flags; @@ -400,7 +401,7 @@ void scsi_target_reap(struct scsi_target *starget) starget->state = STARGET_DEL; spin_unlock_irqrestore(shost->host_lock, flags); execute_in_process_context(scsi_target_reap_usercontext, - starget, &starget->ew); + &starget->ew); return; } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index e1a91665d1c2..259c90cfa367 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -218,16 +218,16 @@ static void scsi_device_cls_release(struct class_device *class_dev) put_device(&sdev->sdev_gendev); } -static void scsi_device_dev_release_usercontext(void *data) +static void scsi_device_dev_release_usercontext(struct work_struct *work) { - struct device *dev = data; struct scsi_device *sdev; struct device *parent; struct scsi_target *starget; unsigned long flags; - parent = dev->parent; - sdev = to_scsi_device(dev); + sdev = container_of(work, struct scsi_device, ew.work); + + parent = sdev->sdev_gendev.parent; starget = to_scsi_target(parent); spin_lock_irqsave(sdev->host->host_lock, flags); @@ -258,7 +258,7 @@ static void scsi_device_dev_release_usercontext(void *data) static void scsi_device_dev_release(struct device *dev) { struct scsi_device *sdp = to_scsi_device(dev); - execute_in_process_context(scsi_device_dev_release_usercontext, dev, + execute_in_process_context(scsi_device_dev_release_usercontext, &sdp->ew); } diff --git a/fs/aio.c b/fs/aio.c index 11a1a7100ad6..ca1c5180a17f 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -53,13 +53,13 @@ static kmem_cache_t *kioctx_cachep; static struct workqueue_struct *aio_wq; /* Used for rare fput completion. */ -static void aio_fput_routine(void *); -static DECLARE_WORK(fput_work, aio_fput_routine, NULL); +static void aio_fput_routine(struct work_struct *); +static DECLARE_WORK(fput_work, aio_fput_routine); static DEFINE_SPINLOCK(fput_lock); static LIST_HEAD(fput_head); -static void aio_kick_handler(void *); +static void aio_kick_handler(struct work_struct *); static void aio_queue_work(struct kioctx *); /* aio_setup @@ -227,7 +227,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) INIT_LIST_HEAD(&ctx->active_reqs); INIT_LIST_HEAD(&ctx->run_list); - INIT_DELAYED_WORK(&ctx->wq, aio_kick_handler, ctx); + INIT_DELAYED_WORK(&ctx->wq, aio_kick_handler); if (aio_setup_ring(ctx) < 0) goto out_freectx; @@ -470,7 +470,7 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) wake_up(&ctx->wait); } -static void aio_fput_routine(void *data) +static void aio_fput_routine(struct work_struct *data) { spin_lock_irq(&fput_lock); while (likely(!list_empty(&fput_head))) { @@ -859,9 +859,9 @@ static inline void aio_run_all_iocbs(struct kioctx *ctx) * space. * Run on aiod's context. */ -static void aio_kick_handler(void *data) +static void aio_kick_handler(struct work_struct *work) { - struct kioctx *ctx = data; + struct kioctx *ctx = container_of(work, struct kioctx, wq.work); mm_segment_t oldfs = get_fs(); int requeue; diff --git a/fs/bio.c b/fs/bio.c index f95c8749499f..c6c07ca5b5a9 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -955,16 +955,16 @@ static void bio_release_pages(struct bio *bio) * run one bio_put() against the BIO. */ -static void bio_dirty_fn(void *data); +static void bio_dirty_fn(struct work_struct *work); -static DECLARE_WORK(bio_dirty_work, bio_dirty_fn, NULL); +static DECLARE_WORK(bio_dirty_work, bio_dirty_fn); static DEFINE_SPINLOCK(bio_dirty_lock); static struct bio *bio_dirty_list; /* * This runs in process context */ -static void bio_dirty_fn(void *data) +static void bio_dirty_fn(struct work_struct *work) { unsigned long flags; struct bio *bio; diff --git a/fs/file.c b/fs/file.c index 8e81775c5dc8..3787e82f54c1 100644 --- a/fs/file.c +++ b/fs/file.c @@ -91,8 +91,10 @@ out: spin_unlock(&fddef->lock); } -static void free_fdtable_work(struct fdtable_defer *f) +static void free_fdtable_work(struct work_struct *work) { + struct fdtable_defer *f = + container_of(work, struct fdtable_defer, wq); struct fdtable *fdt; spin_lock_bh(&f->lock); @@ -351,7 +353,7 @@ static void __devinit fdtable_defer_list_init(int cpu) { struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu); spin_lock_init(&fddef->lock); - INIT_WORK(&fddef->wq, (void (*)(void *))free_fdtable_work, fddef); + INIT_WORK(&fddef->wq, free_fdtable_work); init_timer(&fddef->timer); fddef->timer.data = (unsigned long)fddef; fddef->timer.function = fdtable_timer; diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 6f0487d6f44a..23ab145daa2d 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -143,7 +143,7 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, INIT_LIST_HEAD(&clp->cl_state_owners); INIT_LIST_HEAD(&clp->cl_unused); spin_lock_init(&clp->cl_lock); - INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state, clp); + INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); clp->cl_boot_time = CURRENT_TIME; clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 5ed798bc1cf7..371b804e7cc8 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -18,11 +18,10 @@ #define NFSDBG_FACILITY NFSDBG_VFS -static void nfs_expire_automounts(void *list); +static void nfs_expire_automounts(struct work_struct *work); LIST_HEAD(nfs_automount_list); -static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts, - &nfs_automount_list); +static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); int nfs_mountpoint_expiry_timeout = 500 * HZ; static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, @@ -165,9 +164,9 @@ struct inode_operations nfs_referral_inode_operations = { .follow_link = nfs_follow_mountpoint, }; -static void nfs_expire_automounts(void *data) +static void nfs_expire_automounts(struct work_struct *work) { - struct list_head *list = (struct list_head *)data; + struct list_head *list = &nfs_automount_list; mark_mounts_for_expiry(list); if (!list_empty(list)) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 6f346677332d..c26cd978c7cc 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -185,7 +185,7 @@ extern const u32 nfs4_fs_locations_bitmap[2]; extern void nfs4_schedule_state_renewal(struct nfs_client *); extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); extern void nfs4_kill_renewd(struct nfs_client *); -extern void nfs4_renew_state(void *); +extern void nfs4_renew_state(struct work_struct *); /* nfs4state.c */ struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp); diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 7b6df1852e75..823298561c0a 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c @@ -59,9 +59,10 @@ #define NFSDBG_FACILITY NFSDBG_PROC void -nfs4_renew_state(void *data) +nfs4_renew_state(struct work_struct *work) { - struct nfs_client *clp = (struct nfs_client *)data; + struct nfs_client *clp = + container_of(work, struct nfs_client, cl_renewd.work); struct rpc_cred *cred; long lease, timeout; unsigned long last, now; diff --git a/include/linux/libata.h b/include/linux/libata.h index 5f04006e8dd2..b3f32eadbef5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -568,6 +568,7 @@ struct ata_port { struct ata_host *host; struct device *dev; + void *port_task_data; struct delayed_work port_task; struct delayed_work hotplug_task; struct work_struct scsi_rescan_task; @@ -747,7 +748,7 @@ extern int ata_ratelimit(void); extern unsigned int ata_busy_sleep(struct ata_port *ap, unsigned long timeout_pat, unsigned long timeout); -extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), +extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data, unsigned long delay); extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, unsigned long interval_msec, diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index ecc017d24cf3..4a3ea83c6d16 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -11,18 +11,19 @@ struct workqueue_struct; -typedef void (*work_func_t)(void *data); +struct work_struct; +typedef void (*work_func_t)(struct work_struct *work); struct work_struct { - /* the first word is the work queue pointer and the pending flag - * rolled into one */ + /* the first word is the work queue pointer and the flags rolled into + * one */ unsigned long management; #define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ +#define WORK_STRUCT_NOAUTOREL 1 /* F if work item automatically released on exec */ #define WORK_STRUCT_FLAG_MASK (3UL) #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK) struct list_head entry; work_func_t func; - void *data; }; struct delayed_work { @@ -34,48 +35,77 @@ struct execute_work { struct work_struct work; }; -#define __WORK_INITIALIZER(n, f, d) { \ +#define __WORK_INITIALIZER(n, f) { \ + .management = 0, \ .entry = { &(n).entry, &(n).entry }, \ .func = (f), \ - .data = (d), \ } -#define __DELAYED_WORK_INITIALIZER(n, f, d) { \ - .work = __WORK_INITIALIZER((n).work, (f), (d)), \ +#define __WORK_INITIALIZER_NAR(n, f) { \ + .management = (1 << WORK_STRUCT_NOAUTOREL), \ + .entry = { &(n).entry, &(n).entry }, \ + .func = (f), \ + } + +#define __DELAYED_WORK_INITIALIZER(n, f) { \ + .work = __WORK_INITIALIZER((n).work, (f)), \ + .timer = TIMER_INITIALIZER(NULL, 0, 0), \ + } + +#define __DELAYED_WORK_INITIALIZER_NAR(n, f) { \ + .work = __WORK_INITIALIZER_NAR((n).work, (f)), \ .timer = TIMER_INITIALIZER(NULL, 0, 0), \ } -#define DECLARE_WORK(n, f, d) \ - struct work_struct n = __WORK_INITIALIZER(n, f, d) +#define DECLARE_WORK(n, f) \ + struct work_struct n = __WORK_INITIALIZER(n, f) + +#define DECLARE_WORK_NAR(n, f) \ + struct work_struct n = __WORK_INITIALIZER_NAR(n, f) -#define DECLARE_DELAYED_WORK(n, f, d) \ - struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, d) +#define DECLARE_DELAYED_WORK(n, f) \ + struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f) + +#define DECLARE_DELAYED_WORK_NAR(n, f) \ + struct dwork_struct n = __DELAYED_WORK_INITIALIZER_NAR(n, f) /* - * initialize a work item's function and data pointers + * initialize a work item's function pointer */ -#define PREPARE_WORK(_work, _func, _data) \ +#define PREPARE_WORK(_work, _func) \ do { \ (_work)->func = (_func); \ - (_work)->data = (_data); \ } while (0) -#define PREPARE_DELAYED_WORK(_work, _func, _data) \ - PREPARE_WORK(&(_work)->work, (_func), (_data)) +#define PREPARE_DELAYED_WORK(_work, _func) \ + PREPARE_WORK(&(_work)->work, (_func)) /* * initialize all of a work item in one go */ -#define INIT_WORK(_work, _func, _data) \ +#define INIT_WORK(_work, _func) \ do { \ - INIT_LIST_HEAD(&(_work)->entry); \ (_work)->management = 0; \ - PREPARE_WORK((_work), (_func), (_data)); \ + INIT_LIST_HEAD(&(_work)->entry); \ + PREPARE_WORK((_work), (_func)); \ + } while (0) + +#define INIT_WORK_NAR(_work, _func) \ + do { \ + (_work)->management = (1 << WORK_STRUCT_NOAUTOREL); \ + INIT_LIST_HEAD(&(_work)->entry); \ + PREPARE_WORK((_work), (_func)); \ + } while (0) + +#define INIT_DELAYED_WORK(_work, _func) \ + do { \ + INIT_WORK(&(_work)->work, (_func)); \ + init_timer(&(_work)->timer); \ } while (0) -#define INIT_DELAYED_WORK(_work, _func, _data) \ +#define INIT_DELAYED_WORK_NAR(_work, _func) \ do { \ - INIT_WORK(&(_work)->work, (_func), (_data)); \ + INIT_WORK_NAR(&(_work)->work, (_func)); \ init_timer(&(_work)->timer); \ } while (0) @@ -94,6 +124,27 @@ struct execute_work { #define delayed_work_pending(work) \ test_bit(WORK_STRUCT_PENDING, &(work)->work.management) +/** + * work_release - Release a work item under execution + * @work: The work item to release + * + * This is used to release a work item that has been initialised with automatic + * release mode disabled (WORK_STRUCT_NOAUTOREL is set). This gives the work + * function the opportunity to grab auxiliary data from the container of the + * work_struct before clearing the pending bit as the work_struct may be + * subject to deallocation the moment the pending bit is cleared. + * + * In such a case, this should be called in the work function after it has + * fetched any data it may require from the containter of the work_struct. + * After this function has been called, the work_struct may be scheduled for + * further execution or it may be deallocated unless other precautions are + * taken. + * + * This should also be used to release a delayed work item. + */ +#define work_release(work) \ + clear_bit(WORK_STRUCT_PENDING, &(work)->management) + extern struct workqueue_struct *__create_workqueue(const char *name, int singlethread); @@ -112,7 +163,7 @@ extern int FASTCALL(schedule_work(struct work_struct *work)); extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay)); extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay); -extern int schedule_on_each_cpu(work_func_t func, void *info); +extern int schedule_on_each_cpu(work_func_t func); extern void flush_scheduled_work(void); extern int current_is_keventd(void); extern int keventd_up(void); @@ -121,7 +172,7 @@ extern void init_workqueues(void); void cancel_rearming_delayed_work(struct delayed_work *work); void cancel_rearming_delayed_workqueue(struct workqueue_struct *, struct delayed_work *); -int execute_in_process_context(work_func_t fn, void *, struct execute_work *); +int execute_in_process_context(work_func_t fn, struct execute_work *); /* * Kill off a pending schedule_delayed_work(). Note that the work callback diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 5f48748fe017..f7be1ac73601 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -84,7 +84,7 @@ struct inet_timewait_death_row { }; extern void inet_twdr_hangman(unsigned long data); -extern void inet_twdr_twkill_work(void *data); +extern void inet_twdr_twkill_work(struct work_struct *work); extern void inet_twdr_twcal_tick(unsigned long data); #if (BITS_PER_LONG == 64) diff --git a/ipc/util.c b/ipc/util.c index cd8bb14a431f..a9b7a227b8d4 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -514,6 +514,11 @@ void ipc_rcu_getref(void *ptr) container_of(ptr, struct ipc_rcu_hdr, data)->refcount++; } +static void ipc_do_vfree(struct work_struct *work) +{ + vfree(container_of(work, struct ipc_rcu_sched, work)); +} + /** * ipc_schedule_free - free ipc + rcu space * @head: RCU callback structure for queued work @@ -528,7 +533,7 @@ static void ipc_schedule_free(struct rcu_head *head) struct ipc_rcu_sched *sched = container_of(&(grace->data[0]), struct ipc_rcu_sched, data[0]); - INIT_WORK(&sched->work, vfree, sched); + INIT_WORK(&sched->work, ipc_do_vfree); schedule_work(&sched->work); } diff --git a/kernel/kmod.c b/kernel/kmod.c index bb4e29d924e4..7dc7a9dad6ac 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -114,6 +114,7 @@ EXPORT_SYMBOL(request_module); #endif /* CONFIG_KMOD */ struct subprocess_info { + struct work_struct work; struct completion *complete; char *path; char **argv; @@ -221,9 +222,10 @@ static int wait_for_helper(void *data) } /* This is run by khelper thread */ -static void __call_usermodehelper(void *data) +static void __call_usermodehelper(struct work_struct *work) { - struct subprocess_info *sub_info = data; + struct subprocess_info *sub_info = + container_of(work, struct subprocess_info, work); pid_t pid; int wait = sub_info->wait; @@ -264,6 +266,8 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp, { DECLARE_COMPLETION_ONSTACK(done); struct subprocess_info sub_info = { + .work = __WORK_INITIALIZER(sub_info.work, + __call_usermodehelper), .complete = &done, .path = path, .argv = argv, @@ -272,7 +276,6 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp, .wait = wait, .retval = 0, }; - DECLARE_WORK(work, __call_usermodehelper, &sub_info); if (!khelper_wq) return -EBUSY; @@ -280,7 +283,7 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp, if (path[0] == '\0') return 0; - queue_work(khelper_wq, &work); + queue_work(khelper_wq, &sub_info.work); wait_for_completion(&done); return sub_info.retval; } @@ -291,6 +294,8 @@ int call_usermodehelper_pipe(char *path, char **argv, char **envp, { DECLARE_COMPLETION(done); struct subprocess_info sub_info = { + .work = __WORK_INITIALIZER(sub_info.work, + __call_usermodehelper), .complete = &done, .path = path, .argv = argv, @@ -298,7 +303,6 @@ int call_usermodehelper_pipe(char *path, char **argv, char **envp, .retval = 0, }; struct file *f; - DECLARE_WORK(work, __call_usermodehelper, &sub_info); if (!khelper_wq) return -EBUSY; @@ -318,7 +322,7 @@ int call_usermodehelper_pipe(char *path, char **argv, char **envp, } sub_info.stdin = f; - queue_work(khelper_wq, &work); + queue_work(khelper_wq, &sub_info.work); wait_for_completion(&done); return sub_info.retval; } diff --git a/kernel/kthread.c b/kernel/kthread.c index 4f9c60ef95e8..1db8c72d0d38 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -31,6 +31,8 @@ struct kthread_create_info /* Result passed back to kthread_create() from keventd. */ struct task_struct *result; struct completion done; + + struct work_struct work; }; struct kthread_stop_info @@ -111,9 +113,10 @@ static int kthread(void *_create) } /* We are keventd: create a thread. */ -static void keventd_create_kthread(void *_create) +static void keventd_create_kthread(struct work_struct *work) { - struct kthread_create_info *create = _create; + struct kthread_create_info *create = + container_of(work, struct kthread_create_info, work); int pid; /* We want our own signal handler (we take no signals by default). */ @@ -154,20 +157,20 @@ struct task_struct *kthread_create(int (*threadfn)(void *data), ...) { struct kthread_create_info create; - DECLARE_WORK(work, keventd_create_kthread, &create); create.threadfn = threadfn; create.data = data; init_completion(&create.started); init_completion(&create.done); + INIT_WORK(&create.work, keventd_create_kthread); /* * The workqueue needs to start up first: */ if (!helper_wq) - work.func(work.data); + create.work.func(&create.work); else { - queue_work(helper_wq, &work); + queue_work(helper_wq, &create.work); wait_for_completion(&create.done); } if (!IS_ERR(create.result)) { diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c index f1f900ac3164..678ec736076b 100644 --- a/kernel/power/poweroff.c +++ b/kernel/power/poweroff.c @@ -16,12 +16,12 @@ * callback we use. */ -static void do_poweroff(void *dummy) +static void do_poweroff(struct work_struct *dummy) { kernel_power_off(); } -static DECLARE_WORK(poweroff_work, do_poweroff, NULL); +static DECLARE_WORK(poweroff_work, do_poweroff); static void handle_poweroff(int key, struct tty_struct *tty) { diff --git a/kernel/sys.c b/kernel/sys.c index 98489d82801b..c87b461de38d 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -880,7 +880,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user return 0; } -static void deferred_cad(void *dummy) +static void deferred_cad(struct work_struct *dummy) { kernel_restart(NULL); } @@ -892,7 +892,7 @@ static void deferred_cad(void *dummy) */ void ctrl_alt_del(void) { - static DECLARE_WORK(cad_work, deferred_cad, NULL); + static DECLARE_WORK(cad_work, deferred_cad); if (C_A_D) schedule_work(&cad_work); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 967479756511..8d1e7cb8a51a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -241,14 +241,14 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq) struct work_struct *work = list_entry(cwq->worklist.next, struct work_struct, entry); work_func_t f = work->func; - void *data = work->data; list_del_init(cwq->worklist.next); spin_unlock_irqrestore(&cwq->lock, flags); BUG_ON(get_wq_data(work) != cwq); - clear_bit(WORK_STRUCT_PENDING, &work->management); - f(data); + if (!test_bit(WORK_STRUCT_NOAUTOREL, &work->management)) + work_release(work); + f(work); spin_lock_irqsave(&cwq->lock, flags); cwq->remove_sequence++; @@ -527,7 +527,6 @@ EXPORT_SYMBOL(schedule_delayed_work_on); /** * schedule_on_each_cpu - call a function on each online CPU from keventd * @func: the function to call - * @info: a pointer to pass to func() * * Returns zero on success. * Returns -ve errno on failure. @@ -536,7 +535,7 @@ EXPORT_SYMBOL(schedule_delayed_work_on); * * schedule_on_each_cpu() is very slow. */ -int schedule_on_each_cpu(work_func_t func, void *info) +int schedule_on_each_cpu(work_func_t func) { int cpu; struct work_struct *works; @@ -547,7 +546,7 @@ int schedule_on_each_cpu(work_func_t func, void *info) mutex_lock(&workqueue_mutex); for_each_online_cpu(cpu) { - INIT_WORK(per_cpu_ptr(works, cpu), func, info); + INIT_WORK(per_cpu_ptr(works, cpu), func); __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), per_cpu_ptr(works, cpu)); } @@ -591,7 +590,6 @@ EXPORT_SYMBOL(cancel_rearming_delayed_work); /** * execute_in_process_context - reliably execute the routine with user context * @fn: the function to execute - * @data: data to pass to the function * @ew: guaranteed storage for the execute work structure (must * be available when the work executes) * @@ -601,15 +599,14 @@ EXPORT_SYMBOL(cancel_rearming_delayed_work); * Returns: 0 - function was executed * 1 - function was scheduled for execution */ -int execute_in_process_context(work_func_t fn, void *data, - struct execute_work *ew) +int execute_in_process_context(work_func_t fn, struct execute_work *ew) { if (!in_interrupt()) { - fn(data); + fn(&ew->work); return 0; } - INIT_WORK(&ew->work, fn, data); + INIT_WORK(&ew->work, fn); schedule_work(&ew->work); return 1; diff --git a/mm/slab.c b/mm/slab.c index a65bc5e992c3..5de81473df34 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -313,7 +313,7 @@ static int drain_freelist(struct kmem_cache *cache, static void free_block(struct kmem_cache *cachep, void **objpp, int len, int node); static int enable_cpucache(struct kmem_cache *cachep); -static void cache_reap(void *unused); +static void cache_reap(struct work_struct *unused); /* * This function must be completely optimized away if a constant is passed to @@ -925,7 +925,7 @@ static void __devinit start_cpu_timer(int cpu) */ if (keventd_up() && reap_work->work.func == NULL) { init_reap_node(cpu); - INIT_DELAYED_WORK(reap_work, cache_reap, NULL); + INIT_DELAYED_WORK(reap_work, cache_reap); schedule_delayed_work_on(cpu, reap_work, HZ + 3 * cpu); } } @@ -3815,7 +3815,7 @@ void drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3, * If we cannot acquire the cache chain mutex then just give up - we'll try * again on the next iteration. */ -static void cache_reap(void *unused) +static void cache_reap(struct work_struct *unused) { struct kmem_cache *searchp; struct kmem_list3 *l3; diff --git a/net/core/link_watch.c b/net/core/link_watch.c index f2ed09e25dfd..549a2ce951b0 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -34,8 +34,8 @@ enum lw_bits { static unsigned long linkwatch_flags; static unsigned long linkwatch_nextevent; -static void linkwatch_event(void *dummy); -static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event, NULL); +static void linkwatch_event(struct work_struct *dummy); +static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); static LIST_HEAD(lweventlist); static DEFINE_SPINLOCK(lweventlist_lock); @@ -127,7 +127,7 @@ void linkwatch_run_queue(void) } -static void linkwatch_event(void *dummy) +static void linkwatch_event(struct work_struct *dummy) { /* Limit the number of linkwatch events to one * per second so that a runaway driver does not diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index cdd805344c61..8c74f9168b7d 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -197,9 +197,10 @@ EXPORT_SYMBOL_GPL(inet_twdr_hangman); extern void twkill_slots_invalid(void); -void inet_twdr_twkill_work(void *data) +void inet_twdr_twkill_work(struct work_struct *work) { - struct inet_timewait_death_row *twdr = data; + struct inet_timewait_death_row *twdr = + container_of(work, struct inet_timewait_death_row, twkill_work); int i; if ((INET_TWDR_TWKILL_SLOTS - 1) > (sizeof(twdr->thread_slots) * 8)) diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 0163d9826907..af7b2c986b1f 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -45,8 +45,7 @@ struct inet_timewait_death_row tcp_death_row = { .tw_timer = TIMER_INITIALIZER(inet_twdr_hangman, 0, (unsigned long)&tcp_death_row), .twkill_work = __WORK_INITIALIZER(tcp_death_row.twkill_work, - inet_twdr_twkill_work, - &tcp_death_row), + inet_twdr_twkill_work), /* Short-time timewait calendar */ .twcal_hand = -1, diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index d5725cb1491e..d96fd466a9a4 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -284,8 +284,8 @@ static struct file_operations cache_file_operations; static struct file_operations content_file_operations; static struct file_operations cache_flush_operations; -static void do_cache_clean(void *data); -static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean, NULL); +static void do_cache_clean(struct work_struct *work); +static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean); void cache_register(struct cache_detail *cd) { @@ -461,7 +461,7 @@ static int cache_clean(void) /* * We want to regularly clean the cache, so we need to schedule some work ... */ -static void do_cache_clean(void *data) +static void do_cache_clean(struct work_struct *work) { int delay = 5; if (cache_clean() == -1) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 97be3f7fed44..49dba5febbbd 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -54,10 +54,11 @@ static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, } static void -rpc_timeout_upcall_queue(void *data) +rpc_timeout_upcall_queue(struct work_struct *work) { LIST_HEAD(free_list); - struct rpc_inode *rpci = (struct rpc_inode *)data; + struct rpc_inode *rpci = + container_of(work, struct rpc_inode, queue_timeout.work); struct inode *inode = &rpci->vfs_inode; void (*destroy_msg)(struct rpc_pipe_msg *); @@ -838,7 +839,7 @@ init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) rpci->pipelen = 0; init_waitqueue_head(&rpci->waitq); INIT_DELAYED_WORK(&rpci->queue_timeout, - rpc_timeout_upcall_queue, rpci); + rpc_timeout_upcall_queue); rpci->ops = NULL; } } diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index a1ab4eed41f4..eff44bcdc95a 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -41,7 +41,7 @@ static mempool_t *rpc_buffer_mempool __read_mostly; static void __rpc_default_timer(struct rpc_task *task); static void rpciod_killall(void); -static void rpc_async_schedule(void *); +static void rpc_async_schedule(struct work_struct *); /* * RPC tasks sit here while waiting for conditions to improve. @@ -305,7 +305,7 @@ static void rpc_make_runnable(struct rpc_task *task) if (RPC_IS_ASYNC(task)) { int status; - INIT_WORK(&task->u.tk_work, rpc_async_schedule, (void *)task); + INIT_WORK(&task->u.tk_work, rpc_async_schedule); status = queue_work(task->tk_workqueue, &task->u.tk_work); if (status < 0) { printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); @@ -695,9 +695,9 @@ rpc_execute(struct rpc_task *task) return __rpc_execute(task); } -static void rpc_async_schedule(void *arg) +static void rpc_async_schedule(struct work_struct *work) { - __rpc_execute((struct rpc_task *)arg); + __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); } /** diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 80857470dc11..4f9a5d9791fb 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -479,9 +479,10 @@ int xprt_adjust_timeout(struct rpc_rqst *req) return status; } -static void xprt_autoclose(void *args) +static void xprt_autoclose(struct work_struct *work) { - struct rpc_xprt *xprt = (struct rpc_xprt *)args; + struct rpc_xprt *xprt = + container_of(work, struct rpc_xprt, task_cleanup); xprt_disconnect(xprt); xprt->ops->close(xprt); @@ -932,7 +933,7 @@ struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t si INIT_LIST_HEAD(&xprt->free); INIT_LIST_HEAD(&xprt->recv); - INIT_WORK(&xprt->task_cleanup, xprt_autoclose, xprt); + INIT_WORK(&xprt->task_cleanup, xprt_autoclose); init_timer(&xprt->timer); xprt->timer.function = xprt_init_autodisconnect; xprt->timer.data = (unsigned long) xprt; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 3c7532cd009e..cfe3c15be948 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1060,13 +1060,14 @@ static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) /** * xs_udp_connect_worker - set up a UDP socket - * @args: RPC transport to connect + * @work: RPC transport to connect * * Invoked by a work queue tasklet. */ -static void xs_udp_connect_worker(void *args) +static void xs_udp_connect_worker(struct work_struct *work) { - struct rpc_xprt *xprt = (struct rpc_xprt *) args; + struct rpc_xprt *xprt = + container_of(work, struct rpc_xprt, connect_worker.work); struct socket *sock = xprt->sock; int err, status = -EIO; @@ -1144,13 +1145,14 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) /** * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint - * @args: RPC transport to connect + * @work: RPC transport to connect * * Invoked by a work queue tasklet. */ -static void xs_tcp_connect_worker(void *args) +static void xs_tcp_connect_worker(struct work_struct *work) { - struct rpc_xprt *xprt = (struct rpc_xprt *)args; + struct rpc_xprt *xprt = + container_of(work, struct rpc_xprt, connect_worker.work); struct socket *sock = xprt->sock; int err, status = -EIO; @@ -1375,7 +1377,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); - INIT_DELAYED_WORK(&xprt->connect_worker, xs_udp_connect_worker, xprt); + INIT_DELAYED_WORK(&xprt->connect_worker, xs_udp_connect_worker); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_UDP_CONN_TO; xprt->reestablish_timeout = XS_UDP_REEST_TO; @@ -1420,7 +1422,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; - INIT_DELAYED_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); + INIT_DELAYED_WORK(&xprt->connect_worker, xs_tcp_connect_worker); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_TCP_CONN_TO; xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; diff --git a/security/keys/key.c b/security/keys/key.c index 80de8c3e9cc3..70eacbe5abde 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -30,8 +30,8 @@ DEFINE_SPINLOCK(key_user_lock); static LIST_HEAD(key_types_list); static DECLARE_RWSEM(key_types_sem); -static void key_cleanup(void *data); -static DECLARE_WORK(key_cleanup_task, key_cleanup, NULL); +static void key_cleanup(struct work_struct *work); +static DECLARE_WORK(key_cleanup_task, key_cleanup); /* we serialise key instantiation and link */ DECLARE_RWSEM(key_construction_sem); @@ -552,7 +552,7 @@ EXPORT_SYMBOL(key_negate_and_link); * do cleaning up in process context so that we don't have to disable * interrupts all over the place */ -static void key_cleanup(void *data) +static void key_cleanup(struct work_struct *work) { struct rb_node *_n; struct key *key; -- cgit v1.2.3 From c4028958b6ecad064b1a6303a6a5906d4fe48d73 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 22 Nov 2006 14:57:56 +0000 Subject: WorkStruct: make allyesconfig Fix up for make allyesconfig. Signed-Off-By: David Howells --- arch/i386/kernel/cpu/mcheck/non-fatal.c | 6 +- arch/i386/kernel/smpboot.c | 11 +- arch/i386/kernel/tsc.c | 4 +- arch/powerpc/platforms/pseries/eeh_event.c | 6 +- drivers/atm/idt77252.c | 9 +- drivers/block/aoe/aoe.h | 2 +- drivers/block/aoe/aoecmd.c | 4 +- drivers/block/aoe/aoedev.c | 2 +- drivers/block/paride/pd.c | 8 +- drivers/block/paride/pseudo.h | 10 +- drivers/block/sx8.c | 7 +- drivers/block/ub.c | 8 +- drivers/bluetooth/bcm203x.c | 7 +- drivers/char/cyclades.c | 9 +- drivers/char/drm/via_dmablit.c | 6 +- drivers/char/epca.c | 8 +- drivers/char/esp.c | 14 +- drivers/char/genrtc.c | 4 +- drivers/char/hvsi.c | 16 +- drivers/char/ip2/i2lib.c | 12 +- drivers/char/ip2/ip2main.c | 23 +-- drivers/char/isicom.c | 12 +- drivers/char/moxa.c | 8 +- drivers/char/mxser.c | 9 +- drivers/char/pcmcia/synclink_cs.c | 8 +- drivers/char/sonypi.c | 4 +- drivers/char/specialix.c | 14 +- drivers/char/synclink.c | 9 +- drivers/char/synclink_gt.c | 10 +- drivers/char/synclinkmp.c | 8 +- drivers/char/tpm/tpm.c | 6 +- drivers/connector/cn_queue.c | 8 +- drivers/connector/connector.c | 31 ++-- drivers/cpufreq/cpufreq_conservative.c | 7 +- drivers/cpufreq/cpufreq_ondemand.c | 28 +-- drivers/i2c/chips/ds1374.c | 12 +- drivers/ieee1394/hosts.c | 9 +- drivers/ieee1394/hosts.h | 2 +- drivers/ieee1394/sbp2.c | 28 +-- drivers/ieee1394/sbp2.h | 2 +- drivers/infiniband/core/addr.c | 6 +- drivers/infiniband/core/cache.c | 7 +- drivers/infiniband/core/cm.c | 19 +- drivers/infiniband/core/cma.c | 10 +- drivers/infiniband/core/iwcm.c | 7 +- drivers/infiniband/core/mad.c | 25 +-- drivers/infiniband/core/mad_priv.h | 2 +- drivers/infiniband/core/mad_rmpp.c | 18 +- drivers/infiniband/core/sa_query.c | 10 +- drivers/infiniband/core/uverbs_mem.c | 7 +- drivers/infiniband/hw/ipath/ipath_user_pages.c | 7 +- drivers/infiniband/hw/mthca/mthca_catas.c | 4 +- drivers/infiniband/ulp/ipoib/ipoib.h | 16 +- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 25 +-- drivers/infiniband/ulp/ipoib/ipoib_main.c | 10 +- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 22 ++- drivers/infiniband/ulp/iser/iser_verbs.c | 10 +- drivers/infiniband/ulp/srp/ib_srp.c | 7 +- drivers/input/keyboard/lkkbd.c | 6 +- drivers/input/keyboard/sunkbd.c | 6 +- drivers/input/mouse/psmouse-base.c | 7 +- drivers/isdn/act2000/capi.c | 4 +- drivers/isdn/act2000/capi.h | 2 +- drivers/isdn/act2000/module.c | 18 +- drivers/isdn/capi/kcapi.c | 14 +- drivers/isdn/hisax/amd7930_fn.c | 7 +- drivers/isdn/hisax/config.c | 9 +- drivers/isdn/hisax/hfc4s8s_l1.c | 5 +- drivers/isdn/hisax/hfc_2bds0.c | 9 +- drivers/isdn/hisax/hfc_pci.c | 6 +- drivers/isdn/hisax/hfc_sx.c | 6 +- drivers/isdn/hisax/icc.c | 6 +- drivers/isdn/hisax/isac.c | 6 +- drivers/isdn/hisax/isar.c | 6 +- drivers/isdn/hisax/isdnl1.c | 6 +- drivers/isdn/hisax/w6692.c | 6 +- drivers/isdn/i4l/isdn_net.c | 6 +- drivers/isdn/pcbit/drv.c | 4 +- drivers/isdn/pcbit/layer2.c | 6 +- drivers/isdn/pcbit/pcbit.h | 2 + drivers/macintosh/smu.c | 4 +- drivers/md/dm-crypt.c | 8 +- drivers/md/dm-mpath.c | 18 +- drivers/md/dm-raid1.c | 4 +- drivers/md/dm-snap.c | 9 +- drivers/md/kcopyd.c | 4 +- drivers/media/dvb/b2c2/flexcop-pci.c | 9 +- drivers/media/dvb/cinergyT2/cinergyT2.c | 18 +- drivers/media/dvb/dvb-core/dvb_net.c | 19 +- drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 7 +- drivers/media/dvb/dvb-usb/dvb-usb.h | 2 +- drivers/media/video/cpia_pp.c | 20 ++- drivers/media/video/cx88/cx88-input.c | 6 +- drivers/media/video/ir-kbd-i2c.c | 6 +- drivers/media/video/pvrusb2/pvrusb2-context.c | 13 +- drivers/media/video/saa6588.c | 6 +- drivers/media/video/saa7134/saa7134-empress.c | 9 +- drivers/message/fusion/mptfc.c | 14 +- drivers/message/fusion/mptlan.c | 29 +-- drivers/message/fusion/mptsas.c | 25 +-- drivers/message/fusion/mptspi.c | 14 +- drivers/message/i2o/driver.c | 2 +- drivers/message/i2o/exec-osm.c | 13 +- drivers/message/i2o/i2o_block.c | 15 +- drivers/message/i2o/i2o_block.h | 2 +- drivers/misc/tifm_7xx1.c | 18 +- drivers/mmc/mmc.c | 14 +- drivers/mmc/mmc.h | 2 +- drivers/mmc/mmc_sysfs.c | 10 +- drivers/mmc/tifm_sd.c | 28 +-- drivers/net/8139too.c | 26 +-- drivers/net/bnx2.c | 6 +- drivers/net/cassini.c | 6 +- drivers/net/chelsio/common.h | 2 +- drivers/net/chelsio/cxgb2.c | 16 +- drivers/net/e100.c | 8 +- drivers/net/ehea/ehea_main.c | 9 +- drivers/net/hamradio/baycom_epp.c | 14 +- drivers/net/irda/mcs7780.c | 6 +- drivers/net/irda/sir-dev.h | 2 +- drivers/net/irda/sir_dev.c | 8 +- drivers/net/iseries_veth.c | 12 +- drivers/net/ixgb/ixgb_main.c | 10 +- drivers/net/myri10ge/myri10ge.c | 7 +- drivers/net/ns83820.c | 10 +- drivers/net/pcmcia/xirc2ps_cs.c | 12 +- drivers/net/phy/phy.c | 9 +- drivers/net/plip.c | 38 ++-- drivers/net/qla3xxx.c | 20 ++- drivers/net/qla3xxx.h | 4 +- drivers/net/r8169.c | 23 ++- drivers/net/s2io.c | 16 +- drivers/net/s2io.h | 2 +- drivers/net/sis190.c | 13 +- drivers/net/skge.c | 15 +- drivers/net/skge.h | 2 +- drivers/net/spider_net.c | 9 +- drivers/net/sungem.c | 6 +- drivers/net/tg3.c | 6 +- drivers/net/tlan.c | 23 ++- drivers/net/tlan.h | 1 + drivers/net/tulip/21142.c | 7 +- drivers/net/tulip/timer.c | 7 +- drivers/net/tulip/tulip.h | 7 +- drivers/net/tulip/tulip_core.c | 3 +- drivers/net/wan/pc300_tty.c | 23 +-- drivers/net/wireless/bcm43xx/bcm43xx.h | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 20 ++- drivers/net/wireless/hostap/hostap.h | 2 +- drivers/net/wireless/hostap/hostap_ap.c | 19 +- drivers/net/wireless/hostap/hostap_hw.c | 21 +-- drivers/net/wireless/hostap/hostap_info.c | 6 +- drivers/net/wireless/hostap/hostap_main.c | 8 +- drivers/net/wireless/ipw2100.c | 47 ++--- drivers/net/wireless/ipw2100.h | 10 +- drivers/net/wireless/ipw2200.c | 227 +++++++++++++----------- drivers/net/wireless/ipw2200.h | 16 +- drivers/net/wireless/orinoco.c | 28 +-- drivers/net/wireless/prism54/isl_ioctl.c | 8 +- drivers/net/wireless/prism54/isl_ioctl.h | 4 +- drivers/net/wireless/prism54/islpci_dev.c | 5 +- drivers/net/wireless/prism54/islpci_eth.c | 4 +- drivers/net/wireless/prism54/islpci_eth.h | 2 +- drivers/net/wireless/prism54/islpci_mgt.c | 2 +- drivers/net/wireless/zd1211rw/zd_mac.c | 7 +- drivers/net/wireless/zd1211rw/zd_mac.h | 2 +- drivers/oprofile/cpu_buffer.c | 9 +- drivers/oprofile/cpu_buffer.h | 2 +- drivers/pci/hotplug/shpchp.h | 4 +- drivers/pci/hotplug/shpchp_core.c | 2 +- drivers/pci/hotplug/shpchp_ctrl.c | 19 +- drivers/pcmcia/ds.c | 7 +- drivers/rtc/rtc-dev.c | 7 +- drivers/scsi/NCR5380.c | 11 +- drivers/scsi/NCR5380.h | 4 +- drivers/scsi/aha152x.c | 4 +- drivers/scsi/imm.c | 12 +- drivers/scsi/ipr.c | 9 +- drivers/scsi/libiscsi.c | 7 +- drivers/scsi/libsas/sas_discover.c | 22 ++- drivers/scsi/libsas/sas_event.c | 14 +- drivers/scsi/libsas/sas_init.c | 6 +- drivers/scsi/libsas/sas_internal.h | 12 +- drivers/scsi/libsas/sas_phy.c | 45 +++-- drivers/scsi/libsas/sas_port.c | 30 ++-- drivers/scsi/ppa.c | 12 +- drivers/scsi/qla4xxx/ql4_os.c | 7 +- drivers/scsi/scsi_transport_fc.c | 60 ++++--- drivers/scsi/scsi_transport_iscsi.c | 8 +- drivers/scsi/scsi_transport_spi.c | 7 +- drivers/spi/spi_bitbang.c | 7 +- drivers/usb/atm/cxacru.c | 12 +- drivers/usb/atm/speedtch.c | 15 +- drivers/usb/atm/ueagle-atm.c | 6 +- drivers/usb/class/cdc-acm.c | 6 +- drivers/usb/core/hub.c | 18 +- drivers/usb/core/hub.h | 2 +- drivers/usb/core/message.c | 7 +- drivers/usb/core/usb.c | 9 +- drivers/usb/gadget/ether.c | 6 +- drivers/usb/host/u132-hcd.c | 62 +++---- drivers/usb/input/hid-core.c | 7 +- drivers/usb/misc/ftdi-elan.c | 86 +++------ drivers/usb/misc/phidgetkit.c | 21 ++- drivers/usb/misc/phidgetmotorcontrol.c | 11 +- drivers/usb/net/kaweth.c | 9 +- drivers/usb/net/pegasus.c | 6 +- drivers/usb/net/pegasus.h | 2 +- drivers/usb/net/usbnet.c | 7 +- drivers/usb/serial/aircable.c | 13 +- drivers/usb/serial/digi_acceleport.c | 14 +- drivers/usb/serial/ftdi_sio.c | 19 +- drivers/usb/serial/keyspan_pda.c | 22 ++- drivers/usb/serial/usb-serial.c | 7 +- drivers/usb/serial/whiteheat.c | 15 +- drivers/video/console/fbcon.c | 6 +- fs/9p/mux.c | 16 +- fs/gfs2/glock.c | 8 +- fs/ncpfs/inode.c | 8 +- fs/ncpfs/sock.c | 20 ++- fs/nfsd/nfs4state.c | 7 +- fs/ocfs2/alloc.c | 9 +- fs/ocfs2/cluster/heartbeat.c | 10 +- fs/ocfs2/cluster/quorum.c | 4 +- fs/ocfs2/cluster/tcp.c | 78 ++++---- fs/ocfs2/cluster/tcp_internal.h | 8 +- fs/ocfs2/dlm/dlmcommon.h | 2 +- fs/ocfs2/dlm/dlmdomain.c | 2 +- fs/ocfs2/dlm/dlmrecovery.c | 5 +- fs/ocfs2/dlm/userdlm.c | 10 +- fs/ocfs2/journal.c | 7 +- fs/ocfs2/journal.h | 2 +- fs/ocfs2/ocfs2.h | 2 +- fs/ocfs2/super.c | 2 +- fs/reiserfs/journal.c | 12 +- fs/xfs/linux-2.6/xfs_aops.c | 21 ++- fs/xfs/linux-2.6/xfs_buf.c | 9 +- include/linux/connector.h | 4 +- include/linux/i2o.h | 2 +- include/linux/mmc/host.h | 2 +- include/linux/ncp_fs_sb.h | 8 +- include/linux/reiserfs_fs_sb.h | 3 +- include/linux/relay.h | 2 +- include/linux/usb.h | 2 +- include/net/ieee80211softmac.h | 4 +- include/net/sctp/structs.h | 2 +- include/scsi/libsas.h | 23 ++- include/scsi/scsi_transport_fc.h | 4 +- include/scsi/scsi_transport_iscsi.h | 2 +- include/sound/ac97_codec.h | 2 +- include/sound/ak4114.h | 2 +- kernel/relay.c | 10 +- mm/swap.c | 4 +- net/atm/lec.c | 9 +- net/atm/lec.h | 2 +- net/bluetooth/hci_sysfs.c | 12 +- net/bridge/br_if.c | 10 +- net/bridge/br_private.h | 2 +- net/core/netpoll.c | 4 +- net/dccp/minisocks.c | 3 +- net/ieee80211/softmac/ieee80211softmac_assoc.c | 18 +- net/ieee80211/softmac/ieee80211softmac_auth.c | 23 +-- net/ieee80211/softmac/ieee80211softmac_event.c | 12 +- net/ieee80211/softmac/ieee80211softmac_module.c | 4 +- net/ieee80211/softmac/ieee80211softmac_priv.h | 13 +- net/ieee80211/softmac/ieee80211softmac_scan.c | 13 +- net/ieee80211/softmac/ieee80211softmac_wx.c | 6 +- net/ipv4/ipvs/ip_vs_ctl.c | 6 +- net/irda/ircomm/ircomm_tty.c | 11 +- net/sctp/associola.c | 11 +- net/sctp/endpointola.c | 10 +- net/sctp/inqueue.c | 9 +- net/xfrm/xfrm_policy.c | 8 +- net/xfrm/xfrm_state.c | 8 +- sound/aoa/aoa-gpio.h | 2 +- sound/aoa/core/snd-aoa-gpio-feature.c | 16 +- sound/aoa/core/snd-aoa-gpio-pmf.c | 16 +- sound/i2c/other/ak4114.c | 8 +- sound/pci/ac97/ac97_codec.c | 7 +- sound/pci/hda/hda_codec.c | 10 +- sound/pci/hda/hda_local.h | 1 + sound/ppc/tumbler.c | 8 +- 282 files changed, 1771 insertions(+), 1450 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/cpu/mcheck/non-fatal.c b/arch/i386/kernel/cpu/mcheck/non-fatal.c index 1f9153ae5b03..6b5d3518a1c0 100644 --- a/arch/i386/kernel/cpu/mcheck/non-fatal.c +++ b/arch/i386/kernel/cpu/mcheck/non-fatal.c @@ -51,10 +51,10 @@ static void mce_checkregs (void *info) } } -static void mce_work_fn(void *data); -static DECLARE_WORK(mce_work, mce_work_fn, NULL); +static void mce_work_fn(struct work_struct *work); +static DECLARE_DELAYED_WORK(mce_work, mce_work_fn); -static void mce_work_fn(void *data) +static void mce_work_fn(struct work_struct *work) { on_each_cpu(mce_checkregs, NULL, 1, 1); schedule_delayed_work(&mce_work, MCE_RATE); diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 4bb8b77cd65b..02a9b66b6ac3 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -1049,13 +1049,15 @@ void cpu_exit_clear(void) struct warm_boot_cpu_info { struct completion *complete; + struct work_struct task; int apicid; int cpu; }; -static void __cpuinit do_warm_boot_cpu(void *p) +static void __cpuinit do_warm_boot_cpu(struct work_struct *work) { - struct warm_boot_cpu_info *info = p; + struct warm_boot_cpu_info *info = + container_of(work, struct warm_boot_cpu_info, task); do_boot_cpu(info->apicid, info->cpu); complete(info->complete); } @@ -1064,7 +1066,6 @@ static int __cpuinit __smp_prepare_cpu(int cpu) { DECLARE_COMPLETION_ONSTACK(done); struct warm_boot_cpu_info info; - struct work_struct task; int apicid, ret; struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); @@ -1089,7 +1090,7 @@ static int __cpuinit __smp_prepare_cpu(int cpu) info.complete = &done; info.apicid = apicid; info.cpu = cpu; - INIT_WORK(&task, do_warm_boot_cpu, &info); + INIT_WORK(&info.task, do_warm_boot_cpu); tsc_sync_disabled = 1; @@ -1097,7 +1098,7 @@ static int __cpuinit __smp_prepare_cpu(int cpu) clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, KERNEL_PGD_PTRS); flush_tlb_all(); - schedule_work(&task); + schedule_work(&info.task); wait_for_completion(&done); tsc_sync_disabled = 0; diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c index fbc95828cd74..9810c8c90750 100644 --- a/arch/i386/kernel/tsc.c +++ b/arch/i386/kernel/tsc.c @@ -217,7 +217,7 @@ static unsigned int cpufreq_delayed_issched = 0; static unsigned int cpufreq_init = 0; static struct work_struct cpufreq_delayed_get_work; -static void handle_cpufreq_delayed_get(void *v) +static void handle_cpufreq_delayed_get(struct work_struct *work) { unsigned int cpu; @@ -306,7 +306,7 @@ static int __init cpufreq_tsc(void) { int ret; - INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL); + INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get); ret = cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); if (!ret) diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index 137077451316..49037edf7d39 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -37,8 +37,8 @@ /* EEH event workqueue setup. */ static DEFINE_SPINLOCK(eeh_eventlist_lock); LIST_HEAD(eeh_eventlist); -static void eeh_thread_launcher(void *); -DECLARE_WORK(eeh_event_wq, eeh_thread_launcher, NULL); +static void eeh_thread_launcher(struct work_struct *); +DECLARE_WORK(eeh_event_wq, eeh_thread_launcher); /* Serialize reset sequences for a given pci device */ DEFINE_MUTEX(eeh_event_mutex); @@ -103,7 +103,7 @@ static int eeh_event_handler(void * dummy) * eeh_thread_launcher * @dummy - unused */ -static void eeh_thread_launcher(void *dummy) +static void eeh_thread_launcher(struct work_struct *dummy) { if (kernel_thread(eeh_event_handler, NULL, CLONE_KERNEL) < 0) printk(KERN_ERR "Failed to start EEH daemon\n"); diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 87b17c33b3f9..f40786121948 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -135,7 +135,7 @@ static int idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags); static int idt77252_proc_read(struct atm_dev *dev, loff_t * pos, char *page); -static void idt77252_softint(void *dev_id); +static void idt77252_softint(struct work_struct *work); static struct atmdev_ops idt77252_ops = @@ -2866,9 +2866,10 @@ out: } static void -idt77252_softint(void *dev_id) +idt77252_softint(struct work_struct *work) { - struct idt77252_dev *card = dev_id; + struct idt77252_dev *card = + container_of(work, struct idt77252_dev, tqueue); u32 stat; int done; @@ -3697,7 +3698,7 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id) card->pcidev = pcidev; sprintf(card->name, "idt77252-%d", card->index); - INIT_WORK(&card->tqueue, idt77252_softint, (void *)card); + INIT_WORK(&card->tqueue, idt77252_softint); membase = pci_resource_start(pcidev, 1); srambase = pci_resource_start(pcidev, 2); diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 6d111228cfac..2308e83e5f33 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -159,7 +159,7 @@ void aoecmd_work(struct aoedev *d); void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor); void aoecmd_ata_rsp(struct sk_buff *); void aoecmd_cfg_rsp(struct sk_buff *); -void aoecmd_sleepwork(void *vp); +void aoecmd_sleepwork(struct work_struct *); struct sk_buff *new_skb(ulong); int aoedev_init(void); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 8a13b1af8bab..97f7f535f412 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -408,9 +408,9 @@ rexmit_timer(ulong vp) /* this function performs work that has been deferred until sleeping is OK */ void -aoecmd_sleepwork(void *vp) +aoecmd_sleepwork(struct work_struct *work) { - struct aoedev *d = (struct aoedev *) vp; + struct aoedev *d = container_of(work, struct aoedev, work); if (d->flags & DEVFL_GDALLOC) aoeblk_gdalloc(d); diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index 6125921bbec4..05a97197c918 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -88,7 +88,7 @@ aoedev_newdev(ulong nframes) kfree(d); return NULL; } - INIT_WORK(&d->work, aoecmd_sleepwork, d); + INIT_WORK(&d->work, aoecmd_sleepwork); spin_lock_init(&d->lock); init_timer(&d->timer); d->timer.data = (ulong) d; diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 40a11e567970..9d9bff23f426 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -352,19 +352,19 @@ static enum action (*phase)(void); static void run_fsm(void); -static void ps_tq_int( void *data); +static void ps_tq_int(struct work_struct *work); -static DECLARE_WORK(fsm_tq, ps_tq_int, NULL); +static DECLARE_DELAYED_WORK(fsm_tq, ps_tq_int); static void schedule_fsm(void) { if (!nice) - schedule_work(&fsm_tq); + schedule_delayed_work(&fsm_tq, 0); else schedule_delayed_work(&fsm_tq, nice-1); } -static void ps_tq_int(void *data) +static void ps_tq_int(struct work_struct *work) { run_fsm(); } diff --git a/drivers/block/paride/pseudo.h b/drivers/block/paride/pseudo.h index 932342d7a8eb..bc3703294143 100644 --- a/drivers/block/paride/pseudo.h +++ b/drivers/block/paride/pseudo.h @@ -35,7 +35,7 @@ #include #include -static void ps_tq_int( void *data); +static void ps_tq_int(struct work_struct *work); static void (* ps_continuation)(void); static int (* ps_ready)(void); @@ -45,7 +45,7 @@ static int ps_nice = 0; static DEFINE_SPINLOCK(ps_spinlock __attribute__((unused))); -static DECLARE_WORK(ps_tq, ps_tq_int, NULL); +static DECLARE_DELAYED_WORK(ps_tq, ps_tq_int); static void ps_set_intr(void (*continuation)(void), int (*ready)(void), @@ -63,14 +63,14 @@ static void ps_set_intr(void (*continuation)(void), if (!ps_tq_active) { ps_tq_active = 1; if (!ps_nice) - schedule_work(&ps_tq); + schedule_delayed_work(&ps_tq, 0); else schedule_delayed_work(&ps_tq, ps_nice-1); } spin_unlock_irqrestore(&ps_spinlock,flags); } -static void ps_tq_int(void *data) +static void ps_tq_int(struct work_struct *work) { void (*con)(void); unsigned long flags; @@ -92,7 +92,7 @@ static void ps_tq_int(void *data) } ps_tq_active = 1; if (!ps_nice) - schedule_work(&ps_tq); + schedule_delayed_work(&ps_tq, 0); else schedule_delayed_work(&ps_tq, ps_nice-1); spin_unlock_irqrestore(&ps_spinlock,flags); diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 47d6975268ff..54509eb3391b 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1244,9 +1244,10 @@ out: return IRQ_RETVAL(handled); } -static void carm_fsm_task (void *_data) +static void carm_fsm_task (struct work_struct *work) { - struct carm_host *host = _data; + struct carm_host *host = + container_of(work, struct carm_host, fsm_task); unsigned long flags; unsigned int state; int rc, i, next_dev; @@ -1619,7 +1620,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) host->pdev = pdev; host->flags = pci_dac ? FL_DAC : 0; spin_lock_init(&host->lock); - INIT_WORK(&host->fsm_task, carm_fsm_task, host); + INIT_WORK(&host->fsm_task, carm_fsm_task); init_completion(&host->probe_comp); for (i = 0; i < ARRAY_SIZE(host->req); i++) diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 0d5c73f07265..2098eff91e14 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -376,7 +376,7 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int stalled_pipe); static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd); static void ub_reset_enter(struct ub_dev *sc, int try); -static void ub_reset_task(void *arg); +static void ub_reset_task(struct work_struct *work); static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun); static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, struct ub_capacity *ret); @@ -1558,9 +1558,9 @@ static void ub_reset_enter(struct ub_dev *sc, int try) schedule_work(&sc->reset_work); } -static void ub_reset_task(void *arg) +static void ub_reset_task(struct work_struct *work) { - struct ub_dev *sc = arg; + struct ub_dev *sc = container_of(work, struct ub_dev, reset_work); unsigned long flags; struct list_head *p; struct ub_lun *lun; @@ -2179,7 +2179,7 @@ static int ub_probe(struct usb_interface *intf, usb_init_urb(&sc->work_urb); tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc); atomic_set(&sc->poison, 0); - INIT_WORK(&sc->reset_work, ub_reset_task, sc); + INIT_WORK(&sc->reset_work, ub_reset_task); init_waitqueue_head(&sc->reset_wait); init_timer(&sc->work_timer); diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 516751754aa9..9256985cbe36 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -157,9 +157,10 @@ static void bcm203x_complete(struct urb *urb) } } -static void bcm203x_work(void *user_data) +static void bcm203x_work(struct work_struct *work) { - struct bcm203x_data *data = user_data; + struct bcm203x_data *data = + container_of(work, struct bcm203x_data, work); if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) BT_ERR("Can't submit URB"); @@ -246,7 +247,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id release_firmware(firmware); - INIT_WORK(&data->work, bcm203x_work, (void *) data); + INIT_WORK(&data->work, bcm203x_work); usb_set_intfdata(intf, data); diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index e608dadece2f..acb2de5e3a98 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -926,9 +926,10 @@ cy_sched_event(struct cyclades_port *info, int event) * had to poll every port to see if that port needed servicing. */ static void -do_softint(void *private_) +do_softint(struct work_struct *work) { - struct cyclades_port *info = (struct cyclades_port *) private_; + struct cyclades_port *info = + container_of(work, struct cyclades_port, tqueue); struct tty_struct *tty; tty = info->tty; @@ -5328,7 +5329,7 @@ cy_init(void) info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue, do_softint); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->shutdown_wait); @@ -5403,7 +5404,7 @@ cy_init(void) info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue, do_softint); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->shutdown_wait); diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index 60c1695db300..806f9ce5f47b 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c @@ -500,9 +500,9 @@ via_dmablit_timer(unsigned long data) static void -via_dmablit_workqueue(void *data) +via_dmablit_workqueue(struct work_struct *work) { - drm_via_blitq_t *blitq = (drm_via_blitq_t *) data; + drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq); drm_device_t *dev = blitq->dev; unsigned long irqsave; drm_via_sg_info_t *cur_sg; @@ -571,7 +571,7 @@ via_init_dmablit(drm_device_t *dev) DRM_INIT_WAITQUEUE(blitq->blit_queue + j); } DRM_INIT_WAITQUEUE(&blitq->busy_queue); - INIT_WORK(&blitq->wq, via_dmablit_workqueue, blitq); + INIT_WORK(&blitq->wq, via_dmablit_workqueue); init_timer(&blitq->poll_timer); blitq->poll_timer.function = &via_dmablit_timer; blitq->poll_timer.data = (unsigned long) blitq; diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 706733c0b36a..7c71eb779802 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -200,7 +200,7 @@ static int pc_ioctl(struct tty_struct *, struct file *, static int info_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); static void pc_set_termios(struct tty_struct *, struct termios *); -static void do_softint(void *); +static void do_softint(struct work_struct *work); static void pc_stop(struct tty_struct *); static void pc_start(struct tty_struct *); static void pc_throttle(struct tty_struct * tty); @@ -1505,7 +1505,7 @@ static void post_fep_init(unsigned int crd) ch->brdchan = bc; ch->mailbox = gd; - INIT_WORK(&ch->tqueue, do_softint, ch); + INIT_WORK(&ch->tqueue, do_softint); ch->board = &boards[crd]; spin_lock_irqsave(&epca_lock, flags); @@ -2566,9 +2566,9 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) /* --------------------- Begin do_softint ----------------------- */ -static void do_softint(void *private_) +static void do_softint(struct work_struct *work) { /* Begin do_softint */ - struct channel *ch = (struct channel *) private_; + struct channel *ch = container_of(work, struct channel, tqueue); /* Called in response to a modem change event */ if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */ struct tty_struct *tty = ch->tty; diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 15a4ea896328..93b551962513 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -723,9 +723,10 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) * ------------------------------------------------------------------- */ -static void do_softint(void *private_) +static void do_softint(struct work_struct *work) { - struct esp_struct *info = (struct esp_struct *) private_; + struct esp_struct *info = + container_of(work, struct esp_struct, tqueue); struct tty_struct *tty; tty = info->tty; @@ -746,9 +747,10 @@ static void do_softint(void *private_) * do_serial_hangup() -> tty->hangup() -> esp_hangup() * */ -static void do_serial_hangup(void *private_) +static void do_serial_hangup(struct work_struct *work) { - struct esp_struct *info = (struct esp_struct *) private_; + struct esp_struct *info = + container_of(work, struct esp_struct, tqueue_hangup); struct tty_struct *tty; tty = info->tty; @@ -2501,8 +2503,8 @@ static int __init espserial_init(void) info->magic = ESP_MAGIC; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; - INIT_WORK(&info->tqueue, do_softint, info); - INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); + INIT_WORK(&info->tqueue, do_softint); + INIT_WORK(&info->tqueue_hangup, do_serial_hangup); info->config.rx_timeout = rx_timeout; info->config.flow_on = flow_on; info->config.flow_off = flow_off; diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index 817dc409ac20..23b25ada65ea 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -102,7 +102,7 @@ static void gen_rtc_interrupt(unsigned long arg); * Routine to poll RTC seconds field for change as often as possible, * after first RTC_UIE use timer to reduce polling */ -static void genrtc_troutine(void *data) +static void genrtc_troutine(struct work_struct *work) { unsigned int tmp = get_rtc_ss(); @@ -255,7 +255,7 @@ static inline int gen_set_rtc_irq_bit(unsigned char bit) irq_active = 1; stop_rtc_timers = 0; lostint = 0; - INIT_WORK(&genrtc_task, genrtc_troutine, NULL); + INIT_WORK(&genrtc_task, genrtc_troutine); oldsecs = get_rtc_ss(); init_timer(&timer_task); diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 2cf63e7305a3..82a41d5b4ed0 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -69,7 +69,7 @@ #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) struct hvsi_struct { - struct work_struct writer; + struct delayed_work writer; struct work_struct handshaker; wait_queue_head_t emptyq; /* woken when outbuf is emptied */ wait_queue_head_t stateq; /* woken when HVSI state changes */ @@ -744,9 +744,10 @@ static int hvsi_handshake(struct hvsi_struct *hp) return 0; } -static void hvsi_handshaker(void *arg) +static void hvsi_handshaker(struct work_struct *work) { - struct hvsi_struct *hp = (struct hvsi_struct *)arg; + struct hvsi_struct *hp = + container_of(work, struct hvsi_struct, handshaker); if (hvsi_handshake(hp) >= 0) return; @@ -951,9 +952,10 @@ static void hvsi_push(struct hvsi_struct *hp) } /* hvsi_write_worker will keep rescheduling itself until outbuf is empty */ -static void hvsi_write_worker(void *arg) +static void hvsi_write_worker(struct work_struct *work) { - struct hvsi_struct *hp = (struct hvsi_struct *)arg; + struct hvsi_struct *hp = + container_of(work, struct hvsi_struct, writer.work); unsigned long flags; #ifdef DEBUG static long start_j = 0; @@ -1287,8 +1289,8 @@ static int __init hvsi_console_init(void) } hp = &hvsi_ports[hvsi_count]; - INIT_WORK(&hp->writer, hvsi_write_worker, hp); - INIT_WORK(&hp->handshaker, hvsi_handshaker, hp); + INIT_DELAYED_WORK(&hp->writer, hvsi_write_worker); + INIT_WORK(&hp->handshaker, hvsi_handshaker); init_waitqueue_head(&hp->emptyq); init_waitqueue_head(&hp->stateq); spin_lock_init(&hp->lock); diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 54d93f0345e8..c213fdbdb2b0 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -84,8 +84,8 @@ static void iiSendPendingMail(i2eBordStrPtr); static void serviceOutgoingFifo(i2eBordStrPtr); // Functions defined in ip2.c as part of interrupt handling -static void do_input(void *); -static void do_status(void *); +static void do_input(struct work_struct *); +static void do_status(struct work_struct *); //*************** //* Debug Data * @@ -331,8 +331,8 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh) pCh->ClosingWaitTime = 30*HZ; // Initialize task queue objects - INIT_WORK(&pCh->tqueue_input, do_input, pCh); - INIT_WORK(&pCh->tqueue_status, do_status, pCh); + INIT_WORK(&pCh->tqueue_input, do_input); + INIT_WORK(&pCh->tqueue_status, do_status); #ifdef IP2DEBUG_TRACE pCh->trace = ip2trace; @@ -1573,7 +1573,7 @@ i2StripFifo(i2eBordStrPtr pB) #ifdef USE_IQ schedule_work(&pCh->tqueue_input); #else - do_input(pCh); + do_input(&pCh->tqueue_input); #endif // Note we do not need to maintain any flow-control credits at this @@ -1810,7 +1810,7 @@ i2StripFifo(i2eBordStrPtr pB) #ifdef USE_IQ schedule_work(&pCh->tqueue_status); #else - do_status(pCh); + do_status(&pCh->tqueue_status); #endif } } diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index a3f32d46d2f8..cda2459c1d60 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -189,12 +189,12 @@ static int ip2_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static void set_irq(int, int); -static void ip2_interrupt_bh(i2eBordStrPtr pB); +static void ip2_interrupt_bh(struct work_struct *work); static irqreturn_t ip2_interrupt(int irq, void *dev_id); static void ip2_poll(unsigned long arg); static inline void service_all_boards(void); -static void do_input(void *p); -static void do_status(void *p); +static void do_input(struct work_struct *); +static void do_status(struct work_struct *); static void ip2_wait_until_sent(PTTY,int); @@ -918,7 +918,7 @@ ip2_init_board( int boardnum ) pCh++; } ex_exit: - INIT_WORK(&pB->tqueue_interrupt, (void(*)(void*)) ip2_interrupt_bh, pB); + INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh); return; err_release_region: @@ -1125,8 +1125,8 @@ service_all_boards(void) /******************************************************************************/ -/* Function: ip2_interrupt_bh(pB) */ -/* Parameters: pB - pointer to the board structure */ +/* Function: ip2_interrupt_bh(work) */ +/* Parameters: work - pointer to the board structure */ /* Returns: Nothing */ /* */ /* Description: */ @@ -1135,8 +1135,9 @@ service_all_boards(void) /* */ /******************************************************************************/ static void -ip2_interrupt_bh(i2eBordStrPtr pB) +ip2_interrupt_bh(struct work_struct *work) { + i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt); // pB better well be set or we have a problem! We can only get // here from the IMMEDIATE queue. Here, we process the boards. // Checking pB doesn't cost much and it saves us from the sanity checkers. @@ -1245,9 +1246,9 @@ ip2_poll(unsigned long arg) ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); } -static void do_input(void *p) +static void do_input(struct work_struct *work) { - i2ChanStrPtr pCh = p; + i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input); unsigned long flags; ip2trace(CHANN, ITRC_INPUT, 21, 0 ); @@ -1279,9 +1280,9 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) } } -static void do_status(void *p) +static void do_status(struct work_struct *work) { - i2ChanStrPtr pCh = p; + i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status); int status; status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) ); diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 58c955e390b3..1637c1d9a4ba 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -530,9 +530,9 @@ sched_again: /* Interrupt handlers */ -static void isicom_bottomhalf(void *data) +static void isicom_bottomhalf(struct work_struct *work) { - struct isi_port *port = (struct isi_port *) data; + struct isi_port *port = container_of(work, struct isi_port, bh_tqueue); struct tty_struct *tty = port->tty; if (!tty) @@ -1474,9 +1474,9 @@ static void isicom_start(struct tty_struct *tty) } /* hangup et all */ -static void do_isicom_hangup(void *data) +static void do_isicom_hangup(struct work_struct *work) { - struct isi_port *port = data; + struct isi_port *port = container_of(work, struct isi_port, hangup_tq); struct tty_struct *tty; tty = port->tty; @@ -1966,8 +1966,8 @@ static int __devinit isicom_setup(void) port->channel = channel; port->close_delay = 50 * HZ/100; port->closing_wait = 3000 * HZ/100; - INIT_WORK(&port->hangup_tq, do_isicom_hangup, port); - INIT_WORK(&port->bh_tqueue, isicom_bottomhalf, port); + INIT_WORK(&port->hangup_tq, do_isicom_hangup); + INIT_WORK(&port->bh_tqueue, isicom_bottomhalf); port->status = 0; init_waitqueue_head(&port->open_wait); init_waitqueue_head(&port->close_wait); diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 96cb1f07332b..2d025a9fd14d 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -222,7 +222,7 @@ static struct semaphore moxaBuffSem; /* * static functions: */ -static void do_moxa_softint(void *); +static void do_moxa_softint(struct work_struct *); static int moxa_open(struct tty_struct *, struct file *); static void moxa_close(struct tty_struct *, struct file *); static int moxa_write(struct tty_struct *, const unsigned char *, int); @@ -363,7 +363,7 @@ static int __init moxa_init(void) for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) { ch->type = PORT_16550A; ch->port = i; - INIT_WORK(&ch->tqueue, do_moxa_softint, ch); + INIT_WORK(&ch->tqueue, do_moxa_softint); ch->tty = NULL; ch->close_delay = 5 * HZ / 10; ch->closing_wait = 30 * HZ; @@ -509,9 +509,9 @@ static void __exit moxa_exit(void) module_init(moxa_init); module_exit(moxa_exit); -static void do_moxa_softint(void *private_) +static void do_moxa_softint(struct work_struct *work) { - struct moxa_str *ch = (struct moxa_str *) private_; + struct moxa_str *ch = container_of(work, struct moxa_str, tqueue); struct tty_struct *tty; if (ch && (tty = ch->tty)) { diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 048d91142c17..5ed2486b7581 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -389,7 +389,7 @@ static int mxser_init(void); /* static void mxser_poll(unsigned long); */ static int mxser_get_ISA_conf(int, struct mxser_hwconf *); static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *); -static void mxser_do_softint(void *); +static void mxser_do_softint(struct work_struct *); static int mxser_open(struct tty_struct *, struct file *); static void mxser_close(struct tty_struct *, struct file *); static int mxser_write(struct tty_struct *, const unsigned char *, int); @@ -590,7 +590,7 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf) info->custom_divisor = hwconf->baud_base[i] * 16; info->close_delay = 5 * HZ / 10; info->closing_wait = 30 * HZ; - INIT_WORK(&info->tqueue, mxser_do_softint, info); + INIT_WORK(&info->tqueue, mxser_do_softint); info->normal_termios = mxvar_sdriver->init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); @@ -917,9 +917,10 @@ static int mxser_init(void) return 0; } -static void mxser_do_softint(void *private_) +static void mxser_do_softint(struct work_struct *work) { - struct mxser_struct *info = private_; + struct mxser_struct *info = + container_of(work, struct mxser_struct, tqueue); struct tty_struct *tty; tty = info->tty; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 1a0bc30b79d1..e4d950072b5a 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -421,7 +421,7 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id); /* * Bottom half interrupt handlers */ -static void bh_handler(void* Context); +static void bh_handler(struct work_struct *work); static void bh_transmit(MGSLPC_INFO *info); static void bh_status(MGSLPC_INFO *info); @@ -547,7 +547,7 @@ static int mgslpc_probe(struct pcmcia_device *link) memset(info, 0, sizeof(MGSLPC_INFO)); info->magic = MGSLPC_MAGIC; - INIT_WORK(&info->task, bh_handler, info); + INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; @@ -842,9 +842,9 @@ static int bh_action(MGSLPC_INFO *info) return rc; } -static void bh_handler(void* Context) +static void bh_handler(struct work_struct *work) { - MGSLPC_INFO *info = (MGSLPC_INFO*)Context; + MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task); int action; if (!info) diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index c084149153de..fc87070f1866 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -765,7 +765,7 @@ static void sonypi_setbluetoothpower(u8 state) sonypi_device.bluetooth_power = state; } -static void input_keyrelease(void *data) +static void input_keyrelease(struct work_struct *work) { struct sonypi_keypress kp; @@ -1412,7 +1412,7 @@ static int __devinit sonypi_probe(struct platform_device *dev) goto err_inpdev_unregister; } - INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL); + INIT_WORK(&sonypi_device.input_work, input_keyrelease); } sonypi_enable(0); diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 7e1bd9562c2a..99137ab66b62 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -2261,9 +2261,10 @@ static void sx_start(struct tty_struct * tty) * do_sx_hangup() -> tty->hangup() -> sx_hangup() * */ -static void do_sx_hangup(void *private_) +static void do_sx_hangup(struct work_struct *work) { - struct specialix_port *port = (struct specialix_port *) private_; + struct specialix_port *port = + container_of(work, struct specialix_port, tqueue_hangup); struct tty_struct *tty; func_enter(); @@ -2336,9 +2337,10 @@ static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios } -static void do_softint(void *private_) +static void do_softint(struct work_struct *work) { - struct specialix_port *port = (struct specialix_port *) private_; + struct specialix_port *port = + container_of(work, struct specialix_port, tqueue); struct tty_struct *tty; func_enter(); @@ -2411,8 +2413,8 @@ static int sx_init_drivers(void) memset(sx_port, 0, sizeof(sx_port)); for (i = 0; i < SX_NPORT * SX_NBOARD; i++) { sx_port[i].magic = SPECIALIX_MAGIC; - INIT_WORK(&sx_port[i].tqueue, do_softint, &sx_port[i]); - INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup, &sx_port[i]); + INIT_WORK(&sx_port[i].tqueue, do_softint); + INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup); sx_port[i].close_delay = 50 * HZ/100; sx_port[i].closing_wait = 3000 * HZ/100; init_waitqueue_head(&sx_port[i].open_wait); diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 06784adcc35c..147c30da81ea 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -802,7 +802,7 @@ static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, u /* * Bottom half interrupt handlers */ -static void mgsl_bh_handler(void* Context); +static void mgsl_bh_handler(struct work_struct *work); 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); @@ -1071,9 +1071,10 @@ static int mgsl_bh_action(struct mgsl_struct *info) /* * Perform bottom half processing of work items queued by ISR. */ -static void mgsl_bh_handler(void* Context) +static void mgsl_bh_handler(struct work_struct *work) { - struct mgsl_struct *info = (struct mgsl_struct*)Context; + struct mgsl_struct *info = + container_of(work, struct mgsl_struct, task); int action; if (!info) @@ -4337,7 +4338,7 @@ static struct mgsl_struct* mgsl_allocate_device(void) } else { memset(info, 0, sizeof(struct mgsl_struct)); info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, mgsl_bh_handler, info); + INIT_WORK(&info->task, mgsl_bh_handler); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index d4334c79f8d4..07f34d43dc7f 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -485,7 +485,7 @@ static void enable_loopback(struct slgt_info *info); static void set_rate(struct slgt_info *info, u32 data_rate); static int bh_action(struct slgt_info *info); -static void bh_handler(void* context); +static void bh_handler(struct work_struct *work); static void bh_transmit(struct slgt_info *info); static void isr_serial(struct slgt_info *info); static void isr_rdma(struct slgt_info *info); @@ -1878,9 +1878,9 @@ static int bh_action(struct slgt_info *info) /* * perform bottom half processing */ -static void bh_handler(void* context) +static void bh_handler(struct work_struct *work) { - struct slgt_info *info = context; + struct slgt_info *info = container_of(work, struct slgt_info, task); int action; if (!info) @@ -3326,7 +3326,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev } else { memset(info, 0, sizeof(struct slgt_info)); info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, bh_handler, info); + INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->raw_rx_size = DMABUFSIZE; info->close_delay = 5*HZ/10; @@ -4799,6 +4799,6 @@ static void rx_timeout(unsigned long context) spin_lock_irqsave(&info->lock, flags); info->pending_bh |= BH_RECEIVE; spin_unlock_irqrestore(&info->lock, flags); - bh_handler(info); + bh_handler(&info->task); } diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 3e932b681371..13a57245cf2e 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -602,7 +602,7 @@ static void enable_loopback(SLMP_INFO *info, int enable); static void set_rate(SLMP_INFO *info, u32 data_rate); static int bh_action(SLMP_INFO *info); -static void bh_handler(void* Context); +static void bh_handler(struct work_struct *work); static void bh_receive(SLMP_INFO *info); static void bh_transmit(SLMP_INFO *info); static void bh_status(SLMP_INFO *info); @@ -2063,9 +2063,9 @@ int bh_action(SLMP_INFO *info) /* Perform bottom half processing of work items queued by ISR. */ -void bh_handler(void* Context) +void bh_handler(struct work_struct *work) { - SLMP_INFO *info = (SLMP_INFO*)Context; + SLMP_INFO *info = container_of(work, SLMP_INFO, task); int action; if (!info) @@ -3805,7 +3805,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) } else { memset(info, 0, sizeof(SLMP_INFO)); info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, bh_handler, info); + INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 6ad2d3bb945c..36f91a655275 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -325,9 +325,9 @@ static void user_reader_timeout(unsigned long ptr) schedule_work(&chip->work); } -static void timeout_work(void *ptr) +static void timeout_work(struct work_struct *work) { - struct tpm_chip *chip = ptr; + struct tpm_chip *chip = container_of(work, struct tpm_chip, work); down(&chip->buffer_mutex); atomic_set(&chip->data_pending, 0); @@ -1105,7 +1105,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend init_MUTEX(&chip->tpm_mutex); INIT_LIST_HEAD(&chip->list); - INIT_WORK(&chip->work, timeout_work, chip); + INIT_WORK(&chip->work, timeout_work); init_timer(&chip->user_read_timer); chip->user_read_timer.function = user_reader_timeout; diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index 05f8ce2cfb4a..b418b16e910e 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -31,9 +31,11 @@ #include #include -void cn_queue_wrapper(void *data) +void cn_queue_wrapper(struct work_struct *work) { - struct cn_callback_data *d = data; + struct cn_callback_entry *cbq = + container_of(work, struct cn_callback_entry, work.work); + struct cn_callback_data *d = &cbq->data; d->callback(d->callback_priv); @@ -57,7 +59,7 @@ static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struc memcpy(&cbq->id.id, id, sizeof(struct cb_id)); cbq->data.callback = callback; - INIT_WORK(&cbq->work, &cn_queue_wrapper, &cbq->data); + INIT_DELAYED_WORK(&cbq->work, &cn_queue_wrapper); return cbq; } diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index b49bacfd8de8..5e7cd45d10ee 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -135,40 +135,39 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v spin_lock_bh(&dev->cbdev->queue_lock); list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) { if (cn_cb_equal(&__cbq->id.id, &msg->id)) { - if (likely(!test_bit(0, &__cbq->work.pending) && + if (likely(!test_bit(WORK_STRUCT_PENDING, + &__cbq->work.work.management) && __cbq->data.ddata == NULL)) { __cbq->data.callback_priv = msg; __cbq->data.ddata = data; __cbq->data.destruct_data = destruct_data; - if (queue_work(dev->cbdev->cn_queue, - &__cbq->work)) + if (queue_delayed_work( + dev->cbdev->cn_queue, + &__cbq->work, 0)) err = 0; } else { - struct work_struct *w; struct cn_callback_data *d; - w = kzalloc(sizeof(*w) + sizeof(*d), GFP_ATOMIC); - if (w) { - d = (struct cn_callback_data *)(w+1); - + __cbq = kzalloc(sizeof(*__cbq), GFP_ATOMIC); + if (__cbq) { + d = &__cbq->data; d->callback_priv = msg; d->callback = __cbq->data.callback; d->ddata = data; d->destruct_data = destruct_data; - d->free = w; + d->free = __cbq; - INIT_LIST_HEAD(&w->entry); - w->pending = 0; - w->func = &cn_queue_wrapper; - w->data = d; - init_timer(&w->timer); + INIT_DELAYED_WORK(&__cbq->work, + &cn_queue_wrapper); - if (queue_work(dev->cbdev->cn_queue, w)) + if (queue_delayed_work( + dev->cbdev->cn_queue, + &__cbq->work, 0)) err = 0; else { - kfree(w); + kfree(__cbq); err = -EINVAL; } } else diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index c4c578defabf..5ef5ede5b884 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -59,7 +59,7 @@ static unsigned int def_sampling_rate; #define MAX_SAMPLING_DOWN_FACTOR (10) #define TRANSITION_LATENCY_LIMIT (10 * 1000) -static void do_dbs_timer(void *data); +static void do_dbs_timer(struct work_struct *work); struct cpu_dbs_info_s { struct cpufreq_policy *cur_policy; @@ -82,7 +82,7 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */ * is recursive for the same process. -Venki */ static DEFINE_MUTEX (dbs_mutex); -static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); +static DECLARE_DELAYED_WORK(dbs_work, do_dbs_timer); struct dbs_tuners { unsigned int sampling_rate; @@ -420,7 +420,7 @@ static void dbs_check_cpu(int cpu) } } -static void do_dbs_timer(void *data) +static void do_dbs_timer(struct work_struct *work) { int i; lock_cpu_hotplug(); @@ -435,7 +435,6 @@ static void do_dbs_timer(void *data) static inline void dbs_timer_init(void) { - INIT_WORK(&dbs_work, do_dbs_timer, NULL); schedule_delayed_work(&dbs_work, usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); return; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index bf8aa45d4f01..e1cc5113c2ae 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -47,13 +47,17 @@ static unsigned int def_sampling_rate; #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define TRANSITION_LATENCY_LIMIT (10 * 1000) -static void do_dbs_timer(void *data); +static void do_dbs_timer(struct work_struct *work); + +/* Sampling types */ +enum dbs_sample {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; struct cpu_dbs_info_s { cputime64_t prev_cpu_idle; cputime64_t prev_cpu_wall; struct cpufreq_policy *cur_policy; - struct work_struct work; + struct delayed_work work; + enum dbs_sample sample_type; unsigned int enable; struct cpufreq_frequency_table *freq_table; unsigned int freq_lo; @@ -407,30 +411,31 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) } } -/* Sampling types */ -enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; - -static void do_dbs_timer(void *data) +static void do_dbs_timer(struct work_struct *work) { unsigned int cpu = smp_processor_id(); struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); + enum dbs_sample sample_type = dbs_info->sample_type; /* We want all CPUs to do sampling nearly on same jiffy */ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + /* Permit rescheduling of this work item */ + work_release(work); + delay -= jiffies % delay; if (!dbs_info->enable) return; /* Common NORMAL_SAMPLE setup */ - INIT_WORK(&dbs_info->work, do_dbs_timer, (void *)DBS_NORMAL_SAMPLE); + dbs_info->sample_type = DBS_NORMAL_SAMPLE; if (!dbs_tuners_ins.powersave_bias || - (unsigned long) data == DBS_NORMAL_SAMPLE) { + sample_type == DBS_NORMAL_SAMPLE) { lock_cpu_hotplug(); dbs_check_cpu(dbs_info); unlock_cpu_hotplug(); if (dbs_info->freq_lo) { /* Setup timer for SUB_SAMPLE */ - INIT_WORK(&dbs_info->work, do_dbs_timer, - (void *)DBS_SUB_SAMPLE); + dbs_info->sample_type = DBS_SUB_SAMPLE; delay = dbs_info->freq_hi_jiffies; } } else { @@ -449,7 +454,8 @@ static inline void dbs_timer_init(unsigned int cpu) delay -= jiffies % delay; ondemand_powersave_bias_init(); - INIT_WORK(&dbs_info->work, do_dbs_timer, NULL); + INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer); + dbs_info->sample_type = DBS_NORMAL_SAMPLE; queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); } diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index 4630f1969a09..15edf40828b4 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -140,12 +140,14 @@ ulong ds1374_get_rtc_time(void) return t1; } -static void ds1374_set_work(void *arg) +static ulong new_time; + +static void ds1374_set_work(struct work_struct *work) { ulong t1, t2; int limit = 10; /* arbitrary retry limit */ - t1 = *(ulong *) arg; + t1 = new_time; mutex_lock(&ds1374_mutex); @@ -167,11 +169,9 @@ static void ds1374_set_work(void *arg) "can't confirm time set from rtc chip\n"); } -static ulong new_time; - static struct workqueue_struct *ds1374_workqueue; -static DECLARE_WORK(ds1374_work, ds1374_set_work, &new_time); +static DECLARE_WORK(ds1374_work, ds1374_set_work); int ds1374_set_rtc_time(ulong nowtime) { @@ -180,7 +180,7 @@ int ds1374_set_rtc_time(ulong nowtime) if (in_interrupt()) queue_work(ds1374_workqueue, &ds1374_work); else - ds1374_set_work(&new_time); + ds1374_set_work(NULL); return 0; } diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c index d90a3a1898c0..8f4378a1631c 100644 --- a/drivers/ieee1394/hosts.c +++ b/drivers/ieee1394/hosts.c @@ -31,9 +31,10 @@ #include "config_roms.h" -static void delayed_reset_bus(void * __reset_info) +static void delayed_reset_bus(struct work_struct *work) { - struct hpsb_host *host = (struct hpsb_host*)__reset_info; + struct hpsb_host *host = + container_of(work, struct hpsb_host, delayed_reset.work); int generation = host->csr.generation + 1; /* The generation field rolls over to 2 rather than 0 per IEEE @@ -145,7 +146,7 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra, atomic_set(&h->generation, 0); - INIT_WORK(&h->delayed_reset, delayed_reset_bus, h); + INIT_DELAYED_WORK(&h->delayed_reset, delayed_reset_bus); init_timer(&h->timeout); h->timeout.data = (unsigned long) h; @@ -234,7 +235,7 @@ int hpsb_update_config_rom_image(struct hpsb_host *host) * Config ROM in the near future. */ reset_delay = HZ; - PREPARE_WORK(&host->delayed_reset, delayed_reset_bus, host); + PREPARE_DELAYED_WORK(&host->delayed_reset, delayed_reset_bus); schedule_delayed_work(&host->delayed_reset, reset_delay); return 0; diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h index bc6dbfadb891..d553e38c9543 100644 --- a/drivers/ieee1394/hosts.h +++ b/drivers/ieee1394/hosts.h @@ -62,7 +62,7 @@ struct hpsb_host { struct class_device class_dev; int update_config_rom; - struct work_struct delayed_reset; + struct delayed_work delayed_reset; unsigned int config_roms; struct list_head addr_space; diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 6986ac188281..cd156d4e779e 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -493,20 +493,25 @@ static void sbp2util_notify_fetch_agent(struct scsi_id_instance_data *scsi_id, scsi_unblock_requests(scsi_id->scsi_host); } -static void sbp2util_write_orb_pointer(void *p) +static void sbp2util_write_orb_pointer(struct work_struct *work) { + struct scsi_id_instance_data *scsi_id = + container_of(work, struct scsi_id_instance_data, + protocol_work.work); quadlet_t data[2]; - data[0] = ORB_SET_NODE_ID( - ((struct scsi_id_instance_data *)p)->hi->host->node_id); - data[1] = ((struct scsi_id_instance_data *)p)->last_orb_dma; + data[0] = ORB_SET_NODE_ID(scsi_id->hi->host->node_id); + data[1] = scsi_id->last_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); - sbp2util_notify_fetch_agent(p, SBP2_ORB_POINTER_OFFSET, data, 8); + sbp2util_notify_fetch_agent(scsi_id, SBP2_ORB_POINTER_OFFSET, data, 8); } -static void sbp2util_write_doorbell(void *p) +static void sbp2util_write_doorbell(struct work_struct *work) { - sbp2util_notify_fetch_agent(p, SBP2_DOORBELL_OFFSET, NULL, 4); + struct scsi_id_instance_data *scsi_id = + container_of(work, struct scsi_id_instance_data, + protocol_work.work); + sbp2util_notify_fetch_agent(scsi_id, SBP2_DOORBELL_OFFSET, NULL, 4); } /* @@ -843,7 +848,7 @@ static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud INIT_LIST_HEAD(&scsi_id->scsi_list); spin_lock_init(&scsi_id->sbp2_command_orb_lock); atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING); - INIT_WORK(&scsi_id->protocol_work, NULL, NULL); + INIT_DELAYED_WORK(&scsi_id->protocol_work, NULL); ud->device.driver_data = scsi_id; @@ -2047,11 +2052,10 @@ static void sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id, * We do not accept new commands until the job is over. */ scsi_block_requests(scsi_id->scsi_host); - PREPARE_WORK(&scsi_id->protocol_work, + PREPARE_DELAYED_WORK(&scsi_id->protocol_work, last_orb ? sbp2util_write_doorbell: - sbp2util_write_orb_pointer, - scsi_id); - schedule_work(&scsi_id->protocol_work); + sbp2util_write_orb_pointer); + schedule_delayed_work(&scsi_id->protocol_work, 0); } } diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h index abbe48e646c3..1b16d6b9cf11 100644 --- a/drivers/ieee1394/sbp2.h +++ b/drivers/ieee1394/sbp2.h @@ -348,7 +348,7 @@ struct scsi_id_instance_data { unsigned workarounds; atomic_t state; - struct work_struct protocol_work; + struct delayed_work protocol_work; }; /* For use in scsi_id_instance_data.state */ diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index e11187ecc931..84b2f5cb3722 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -55,11 +55,11 @@ struct addr_req { int status; }; -static void process_req(void *data); +static void process_req(struct work_struct *work); static DEFINE_MUTEX(lock); static LIST_HEAD(req_list); -static DECLARE_WORK(work, process_req, NULL); +static DECLARE_DELAYED_WORK(work, process_req); static struct workqueue_struct *addr_wq; void rdma_addr_register_client(struct rdma_addr_client *client) @@ -215,7 +215,7 @@ out: return ret; } -static void process_req(void *data) +static void process_req(struct work_struct *work) { struct addr_req *req, *temp_req; struct sockaddr_in *src_in, *dst_in; diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 20e9f64e67a6..98272fbbfb31 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -285,9 +285,10 @@ err: kfree(tprops); } -static void ib_cache_task(void *work_ptr) +static void ib_cache_task(struct work_struct *_work) { - struct ib_update_work *work = work_ptr; + struct ib_update_work *work = + container_of(_work, struct ib_update_work, work); ib_cache_update(work->device, work->port_num); kfree(work); @@ -306,7 +307,7 @@ static void ib_cache_event(struct ib_event_handler *handler, event->event == IB_EVENT_CLIENT_REREGISTER) { work = kmalloc(sizeof *work, GFP_ATOMIC); if (work) { - INIT_WORK(&work->work, ib_cache_task, work); + INIT_WORK(&work->work, ib_cache_task); work->device = event->device; work->port_num = event->element.port_num; schedule_work(&work->work); diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 25b1018a476c..e1990f531d0a 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -101,7 +101,7 @@ struct cm_av { }; struct cm_work { - struct work_struct work; + struct delayed_work work; struct list_head list; struct cm_port *port; struct ib_mad_recv_wc *mad_recv_wc; /* Received MADs */ @@ -161,7 +161,7 @@ struct cm_id_private { atomic_t work_count; }; -static void cm_work_handler(void *data); +static void cm_work_handler(struct work_struct *work); static inline void cm_deref_id(struct cm_id_private *cm_id_priv) { @@ -669,8 +669,7 @@ static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id) return ERR_PTR(-ENOMEM); timewait_info->work.local_id = local_id; - INIT_WORK(&timewait_info->work.work, cm_work_handler, - &timewait_info->work); + INIT_DELAYED_WORK(&timewait_info->work.work, cm_work_handler); timewait_info->work.cm_event.event = IB_CM_TIMEWAIT_EXIT; return timewait_info; } @@ -2987,9 +2986,9 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent, } } -static void cm_work_handler(void *data) +static void cm_work_handler(struct work_struct *_work) { - struct cm_work *work = data; + struct cm_work *work = container_of(_work, struct cm_work, work.work); int ret; switch (work->cm_event.event) { @@ -3079,12 +3078,12 @@ int ib_cm_establish(struct ib_cm_id *cm_id) * we need to find the cm_id once we're in the context of the * worker thread, rather than holding a reference on it. */ - INIT_WORK(&work->work, cm_work_handler, work); + INIT_DELAYED_WORK(&work->work, cm_work_handler); work->local_id = cm_id->local_id; work->remote_id = cm_id->remote_id; work->mad_recv_wc = NULL; work->cm_event.event = IB_CM_USER_ESTABLISHED; - queue_work(cm.wq, &work->work); + queue_delayed_work(cm.wq, &work->work, 0); out: return ret; } @@ -3146,11 +3145,11 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, return; } - INIT_WORK(&work->work, cm_work_handler, work); + INIT_DELAYED_WORK(&work->work, cm_work_handler); work->cm_event.event = event; work->mad_recv_wc = mad_recv_wc; work->port = (struct cm_port *)mad_agent->context; - queue_work(cm.wq, &work->work); + queue_delayed_work(cm.wq, &work->work, 0); } static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv, diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 845090b0859c..189f73f3f721 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1341,9 +1341,9 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, return (id_priv->query_id < 0) ? id_priv->query_id : 0; } -static void cma_work_handler(void *data) +static void cma_work_handler(struct work_struct *_work) { - struct cma_work *work = data; + struct cma_work *work = container_of(_work, struct cma_work, work); struct rdma_id_private *id_priv = work->id; int destroy = 0; @@ -1374,7 +1374,7 @@ static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) return -ENOMEM; work->id = id_priv; - INIT_WORK(&work->work, cma_work_handler, work); + INIT_WORK(&work->work, cma_work_handler); work->old_state = CMA_ROUTE_QUERY; work->new_state = CMA_ROUTE_RESOLVED; work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; @@ -1431,7 +1431,7 @@ static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) return -ENOMEM; work->id = id_priv; - INIT_WORK(&work->work, cma_work_handler, work); + INIT_WORK(&work->work, cma_work_handler); work->old_state = CMA_ROUTE_QUERY; work->new_state = CMA_ROUTE_RESOLVED; work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; @@ -1585,7 +1585,7 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv) } work->id = id_priv; - INIT_WORK(&work->work, cma_work_handler, work); + INIT_WORK(&work->work, cma_work_handler); work->old_state = CMA_ADDR_QUERY; work->new_state = CMA_ADDR_RESOLVED; work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index c3fb304a4e86..9bfa785252dc 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -828,9 +828,10 @@ static int process_event(struct iwcm_id_private *cm_id_priv, * thread asleep on the destroy_comp list vs. an object destroyed * here synchronously when the last reference is removed. */ -static void cm_work_handler(void *arg) +static void cm_work_handler(struct work_struct *_work) { - struct iwcm_work *work = arg, lwork; + struct iwcm_work lwork, *work = + container_of(_work, struct iwcm_work, work); struct iwcm_id_private *cm_id_priv = work->cm_id; unsigned long flags; int empty; @@ -899,7 +900,7 @@ static int cm_event_handler(struct iw_cm_id *cm_id, goto out; } - INIT_WORK(&work->work, cm_work_handler, work); + INIT_WORK(&work->work, cm_work_handler); work->cm_id = cm_id_priv; work->event = *iw_event; diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index a72bcea46ff6..5a54ac35e961 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -65,8 +65,8 @@ static struct ib_mad_agent_private *find_mad_agent( static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info, struct ib_mad_private *mad); static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv); -static void timeout_sends(void *data); -static void local_completions(void *data); +static void timeout_sends(struct work_struct *work); +static void local_completions(struct work_struct *work); static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req, struct ib_mad_agent_private *agent_priv, u8 mgmt_class); @@ -356,10 +356,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, INIT_LIST_HEAD(&mad_agent_priv->wait_list); INIT_LIST_HEAD(&mad_agent_priv->done_list); INIT_LIST_HEAD(&mad_agent_priv->rmpp_list); - INIT_WORK(&mad_agent_priv->timed_work, timeout_sends, mad_agent_priv); + INIT_DELAYED_WORK(&mad_agent_priv->timed_work, timeout_sends); INIT_LIST_HEAD(&mad_agent_priv->local_list); - INIT_WORK(&mad_agent_priv->local_work, local_completions, - mad_agent_priv); + INIT_WORK(&mad_agent_priv->local_work, local_completions); atomic_set(&mad_agent_priv->refcount, 1); init_completion(&mad_agent_priv->comp); @@ -2198,12 +2197,12 @@ static void mad_error_handler(struct ib_mad_port_private *port_priv, /* * IB MAD completion callback */ -static void ib_mad_completion_handler(void *data) +static void ib_mad_completion_handler(struct work_struct *work) { struct ib_mad_port_private *port_priv; struct ib_wc wc; - port_priv = (struct ib_mad_port_private *)data; + port_priv = container_of(work, struct ib_mad_port_private, work); ib_req_notify_cq(port_priv->cq, IB_CQ_NEXT_COMP); while (ib_poll_cq(port_priv->cq, 1, &wc) == 1) { @@ -2324,7 +2323,7 @@ void ib_cancel_mad(struct ib_mad_agent *mad_agent, } EXPORT_SYMBOL(ib_cancel_mad); -static void local_completions(void *data) +static void local_completions(struct work_struct *work) { struct ib_mad_agent_private *mad_agent_priv; struct ib_mad_local_private *local; @@ -2334,7 +2333,8 @@ static void local_completions(void *data) struct ib_wc wc; struct ib_mad_send_wc mad_send_wc; - mad_agent_priv = (struct ib_mad_agent_private *)data; + mad_agent_priv = + container_of(work, struct ib_mad_agent_private, local_work); spin_lock_irqsave(&mad_agent_priv->lock, flags); while (!list_empty(&mad_agent_priv->local_list)) { @@ -2434,14 +2434,15 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr) return ret; } -static void timeout_sends(void *data) +static void timeout_sends(struct work_struct *work) { struct ib_mad_agent_private *mad_agent_priv; struct ib_mad_send_wr_private *mad_send_wr; struct ib_mad_send_wc mad_send_wc; unsigned long flags, delay; - mad_agent_priv = (struct ib_mad_agent_private *)data; + mad_agent_priv = container_of(work, struct ib_mad_agent_private, + timed_work.work); mad_send_wc.vendor_err = 0; spin_lock_irqsave(&mad_agent_priv->lock, flags); @@ -2799,7 +2800,7 @@ static int ib_mad_port_open(struct ib_device *device, ret = -ENOMEM; goto error8; } - INIT_WORK(&port_priv->work, ib_mad_completion_handler, port_priv); + INIT_WORK(&port_priv->work, ib_mad_completion_handler); spin_lock_irqsave(&ib_mad_port_list_lock, flags); list_add_tail(&port_priv->port_list, &ib_mad_port_list); diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index d06b59083f6e..d5548e73e068 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -102,7 +102,7 @@ struct ib_mad_agent_private { struct list_head send_list; struct list_head wait_list; struct list_head done_list; - struct work_struct timed_work; + struct delayed_work timed_work; unsigned long timeout; struct list_head local_list; struct work_struct local_work; diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index 1ef79d015a1e..3663fd7022be 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -45,8 +45,8 @@ enum rmpp_state { struct mad_rmpp_recv { struct ib_mad_agent_private *agent; struct list_head list; - struct work_struct timeout_work; - struct work_struct cleanup_work; + struct delayed_work timeout_work; + struct delayed_work cleanup_work; struct completion comp; enum rmpp_state state; spinlock_t lock; @@ -233,9 +233,10 @@ static void nack_recv(struct ib_mad_agent_private *agent, } } -static void recv_timeout_handler(void *data) +static void recv_timeout_handler(struct work_struct *work) { - struct mad_rmpp_recv *rmpp_recv = data; + struct mad_rmpp_recv *rmpp_recv = + container_of(work, struct mad_rmpp_recv, timeout_work.work); struct ib_mad_recv_wc *rmpp_wc; unsigned long flags; @@ -254,9 +255,10 @@ static void recv_timeout_handler(void *data) ib_free_recv_mad(rmpp_wc); } -static void recv_cleanup_handler(void *data) +static void recv_cleanup_handler(struct work_struct *work) { - struct mad_rmpp_recv *rmpp_recv = data; + struct mad_rmpp_recv *rmpp_recv = + container_of(work, struct mad_rmpp_recv, cleanup_work.work); unsigned long flags; spin_lock_irqsave(&rmpp_recv->agent->lock, flags); @@ -285,8 +287,8 @@ create_rmpp_recv(struct ib_mad_agent_private *agent, rmpp_recv->agent = agent; init_completion(&rmpp_recv->comp); - INIT_WORK(&rmpp_recv->timeout_work, recv_timeout_handler, rmpp_recv); - INIT_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler, rmpp_recv); + INIT_DELAYED_WORK(&rmpp_recv->timeout_work, recv_timeout_handler); + INIT_DELAYED_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler); spin_lock_init(&rmpp_recv->lock); rmpp_recv->state = RMPP_STATE_ACTIVE; atomic_set(&rmpp_recv->refcount, 1); diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 1706d3c7e95e..e45afba75341 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -360,9 +360,10 @@ static void free_sm_ah(struct kref *kref) kfree(sm_ah); } -static void update_sm_ah(void *port_ptr) +static void update_sm_ah(struct work_struct *work) { - struct ib_sa_port *port = port_ptr; + struct ib_sa_port *port = + container_of(work, struct ib_sa_port, update_task); struct ib_sa_sm_ah *new_ah, *old_ah; struct ib_port_attr port_attr; struct ib_ah_attr ah_attr; @@ -992,8 +993,7 @@ static void ib_sa_add_one(struct ib_device *device) if (IS_ERR(sa_dev->port[i].agent)) goto err; - INIT_WORK(&sa_dev->port[i].update_task, - update_sm_ah, &sa_dev->port[i]); + INIT_WORK(&sa_dev->port[i].update_task, update_sm_ah); } ib_set_client_data(device, &sa_client, sa_dev); @@ -1010,7 +1010,7 @@ static void ib_sa_add_one(struct ib_device *device) goto err; for (i = 0; i <= e - s; ++i) - update_sm_ah(&sa_dev->port[i]); + update_sm_ah(&sa_dev->port[i].update_task); return; diff --git a/drivers/infiniband/core/uverbs_mem.c b/drivers/infiniband/core/uverbs_mem.c index efe147dbeb42..db12cc0841df 100644 --- a/drivers/infiniband/core/uverbs_mem.c +++ b/drivers/infiniband/core/uverbs_mem.c @@ -179,9 +179,10 @@ void ib_umem_release(struct ib_device *dev, struct ib_umem *umem) up_write(¤t->mm->mmap_sem); } -static void ib_umem_account(void *work_ptr) +static void ib_umem_account(struct work_struct *_work) { - struct ib_umem_account_work *work = work_ptr; + struct ib_umem_account_work *work = + container_of(_work, struct ib_umem_account_work, work); down_write(&work->mm->mmap_sem); work->mm->locked_vm -= work->diff; @@ -216,7 +217,7 @@ void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem) return; } - INIT_WORK(&work->work, ib_umem_account, work); + INIT_WORK(&work->work, ib_umem_account); work->mm = mm; work->diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT; diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c index 413754b1d8a2..8536aeb96af8 100644 --- a/drivers/infiniband/hw/ipath/ipath_user_pages.c +++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c @@ -214,9 +214,10 @@ struct ipath_user_pages_work { unsigned long num_pages; }; -static void user_pages_account(void *ptr) +static void user_pages_account(struct work_struct *_work) { - struct ipath_user_pages_work *work = ptr; + struct ipath_user_pages_work *work = + container_of(_work, struct ipath_user_pages_work, work); down_write(&work->mm->mmap_sem); work->mm->locked_vm -= work->num_pages; @@ -242,7 +243,7 @@ void ipath_release_user_pages_on_close(struct page **p, size_t num_pages) goto bail; - INIT_WORK(&work->work, user_pages_account, work); + INIT_WORK(&work->work, user_pages_account); work->mm = mm; work->num_pages = num_pages; diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index cd044ea2dfa4..e948158a28d9 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c @@ -57,7 +57,7 @@ static int catas_reset_disable; module_param_named(catas_reset_disable, catas_reset_disable, int, 0644); MODULE_PARM_DESC(catas_reset_disable, "disable reset on catastrophic event if nonzero"); -static void catas_reset(void *work_ptr) +static void catas_reset(struct work_struct *work) { struct mthca_dev *dev, *tmpdev; LIST_HEAD(tlist); @@ -203,7 +203,7 @@ void mthca_stop_catas_poll(struct mthca_dev *dev) int __init mthca_catas_init(void) { - INIT_WORK(&catas_work, catas_reset, NULL); + INIT_WORK(&catas_work, catas_reset); catas_wq = create_singlethread_workqueue("mthca_catas"); if (!catas_wq) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 0b8a79d53a00..3b2ee0eba05e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -136,11 +136,11 @@ struct ipoib_dev_priv { struct list_head multicast_list; struct rb_root multicast_tree; - struct work_struct pkey_task; - struct work_struct mcast_task; + struct delayed_work pkey_task; + struct delayed_work mcast_task; struct work_struct flush_task; struct work_struct restart_task; - struct work_struct ah_reap_task; + struct delayed_work ah_reap_task; struct ib_device *ca; u8 port; @@ -254,13 +254,13 @@ int ipoib_add_pkey_attr(struct net_device *dev); void ipoib_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_ah *address, u32 qpn); -void ipoib_reap_ah(void *dev_ptr); +void ipoib_reap_ah(struct work_struct *work); void ipoib_flush_paths(struct net_device *dev); struct ipoib_dev_priv *ipoib_intf_alloc(const char *format); int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port); -void ipoib_ib_dev_flush(void *dev); +void ipoib_ib_dev_flush(struct work_struct *work); void ipoib_ib_dev_cleanup(struct net_device *dev); int ipoib_ib_dev_open(struct net_device *dev); @@ -271,10 +271,10 @@ int ipoib_ib_dev_stop(struct net_device *dev); int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port); void ipoib_dev_cleanup(struct net_device *dev); -void ipoib_mcast_join_task(void *dev_ptr); +void ipoib_mcast_join_task(struct work_struct *work); void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb); -void ipoib_mcast_restart_task(void *dev_ptr); +void ipoib_mcast_restart_task(struct work_struct *work); int ipoib_mcast_start_thread(struct net_device *dev); int ipoib_mcast_stop_thread(struct net_device *dev, int flush); @@ -312,7 +312,7 @@ void ipoib_event(struct ib_event_handler *handler, int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey); int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey); -void ipoib_pkey_poll(void *dev); +void ipoib_pkey_poll(struct work_struct *work); int ipoib_pkey_dev_delay_open(struct net_device *dev); #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 8bf5e9ec7c95..f10fba5d3265 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -400,10 +400,11 @@ static void __ipoib_reap_ah(struct net_device *dev) spin_unlock_irq(&priv->tx_lock); } -void ipoib_reap_ah(void *dev_ptr) +void ipoib_reap_ah(struct work_struct *work) { - struct net_device *dev = dev_ptr; - struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, ah_reap_task.work); + struct net_device *dev = priv->dev; __ipoib_reap_ah(dev); @@ -613,10 +614,11 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port) return 0; } -void ipoib_ib_dev_flush(void *_dev) +void ipoib_ib_dev_flush(struct work_struct *work) { - struct net_device *dev = (struct net_device *)_dev; - struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv; + struct ipoib_dev_priv *cpriv, *priv = + container_of(work, struct ipoib_dev_priv, flush_task); + struct net_device *dev = priv->dev; if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags) ) { ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n"); @@ -638,14 +640,14 @@ void ipoib_ib_dev_flush(void *_dev) */ if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { ipoib_ib_dev_up(dev); - ipoib_mcast_restart_task(dev); + ipoib_mcast_restart_task(&priv->restart_task); } mutex_lock(&priv->vlan_mutex); /* Flush any child interfaces too */ list_for_each_entry(cpriv, &priv->child_intfs, list) - ipoib_ib_dev_flush(cpriv->dev); + ipoib_ib_dev_flush(&cpriv->flush_task); mutex_unlock(&priv->vlan_mutex); } @@ -672,10 +674,11 @@ void ipoib_ib_dev_cleanup(struct net_device *dev) * change async notification is available. */ -void ipoib_pkey_poll(void *dev_ptr) +void ipoib_pkey_poll(struct work_struct *work) { - struct net_device *dev = dev_ptr; - struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, pkey_task.work); + struct net_device *dev = priv->dev; ipoib_pkey_dev_check_presence(dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 85522daeb946..71114a8c12b9 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -933,11 +933,11 @@ static void ipoib_setup(struct net_device *dev) INIT_LIST_HEAD(&priv->dead_ahs); INIT_LIST_HEAD(&priv->multicast_list); - INIT_WORK(&priv->pkey_task, ipoib_pkey_poll, priv->dev); - INIT_WORK(&priv->mcast_task, ipoib_mcast_join_task, priv->dev); - INIT_WORK(&priv->flush_task, ipoib_ib_dev_flush, priv->dev); - INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task, priv->dev); - INIT_WORK(&priv->ah_reap_task, ipoib_reap_ah, priv->dev); + INIT_DELAYED_WORK(&priv->pkey_task, ipoib_pkey_poll); + INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); + INIT_WORK(&priv->flush_task, ipoib_ib_dev_flush); + INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); + INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah); } struct ipoib_dev_priv *ipoib_intf_alloc(const char *name) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 3faa1820f0e9..f0a4fac1a215 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -399,7 +399,8 @@ static void ipoib_mcast_join_complete(int status, mcast->backoff = 1; mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) - queue_work(ipoib_workqueue, &priv->mcast_task); + queue_delayed_work(ipoib_workqueue, + &priv->mcast_task, 0); mutex_unlock(&mcast_mutex); complete(&mcast->done); return; @@ -435,7 +436,8 @@ static void ipoib_mcast_join_complete(int status, if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) { if (status == -ETIMEDOUT) - queue_work(ipoib_workqueue, &priv->mcast_task); + queue_delayed_work(ipoib_workqueue, &priv->mcast_task, + 0); else queue_delayed_work(ipoib_workqueue, &priv->mcast_task, mcast->backoff * HZ); @@ -517,10 +519,11 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, mcast->query_id = ret; } -void ipoib_mcast_join_task(void *dev_ptr) +void ipoib_mcast_join_task(struct work_struct *work) { - struct net_device *dev = dev_ptr; - struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, mcast_task.work); + struct net_device *dev = priv->dev; if (!test_bit(IPOIB_MCAST_RUN, &priv->flags)) return; @@ -610,7 +613,7 @@ int ipoib_mcast_start_thread(struct net_device *dev) mutex_lock(&mcast_mutex); if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags)) - queue_work(ipoib_workqueue, &priv->mcast_task); + queue_delayed_work(ipoib_workqueue, &priv->mcast_task, 0); mutex_unlock(&mcast_mutex); spin_lock_irq(&priv->lock); @@ -818,10 +821,11 @@ void ipoib_mcast_dev_flush(struct net_device *dev) } } -void ipoib_mcast_restart_task(void *dev_ptr) +void ipoib_mcast_restart_task(struct work_struct *work) { - struct net_device *dev = dev_ptr; - struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, restart_task); + struct net_device *dev = priv->dev; struct dev_mc_list *mclist; struct ipoib_mcast *mcast, *tmcast; LIST_HEAD(remove_list); diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 18a000034996..693b77002897 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -48,7 +48,7 @@ static void iser_cq_tasklet_fn(unsigned long data); static void iser_cq_callback(struct ib_cq *cq, void *cq_context); -static void iser_comp_error_worker(void *data); +static void iser_comp_error_worker(struct work_struct *work); static void iser_cq_event_callback(struct ib_event *cause, void *context) { @@ -480,8 +480,7 @@ int iser_conn_init(struct iser_conn **ibconn) init_waitqueue_head(&ib_conn->wait); atomic_set(&ib_conn->post_recv_buf_count, 0); atomic_set(&ib_conn->post_send_buf_count, 0); - INIT_WORK(&ib_conn->comperror_work, iser_comp_error_worker, - ib_conn); + INIT_WORK(&ib_conn->comperror_work, iser_comp_error_worker); INIT_LIST_HEAD(&ib_conn->conn_list); spin_lock_init(&ib_conn->lock); @@ -754,9 +753,10 @@ int iser_post_send(struct iser_desc *tx_desc) return ret_val; } -static void iser_comp_error_worker(void *data) +static void iser_comp_error_worker(struct work_struct *work) { - struct iser_conn *ib_conn = data; + struct iser_conn *ib_conn = + container_of(work, struct iser_conn, comperror_work); /* getting here when the state is UP means that the conn is being * * terminated asynchronously from the iSCSI layer's perspective. */ diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 4b09147f438f..214f66195af2 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -390,9 +390,10 @@ static void srp_disconnect_target(struct srp_target_port *target) wait_for_completion(&target->done); } -static void srp_remove_work(void *target_ptr) +static void srp_remove_work(struct work_struct *work) { - struct srp_target_port *target = target_ptr; + struct srp_target_port *target = + container_of(work, struct srp_target_port, work); spin_lock_irq(target->scsi_host->host_lock); if (target->state != SRP_TARGET_DEAD) { @@ -575,7 +576,7 @@ err: spin_lock_irq(target->scsi_host->host_lock); if (target->state == SRP_TARGET_CONNECTING) { target->state = SRP_TARGET_DEAD; - INIT_WORK(&target->work, srp_remove_work, target); + INIT_WORK(&target->work, srp_remove_work); schedule_work(&target->work); } spin_unlock_irq(target->scsi_host->host_lock); diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 979b93e33da7..b7f049b45b6b 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -572,9 +572,9 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, * were in. */ static void -lkkbd_reinit (void *data) +lkkbd_reinit (struct work_struct *work) { - struct lkkbd *lk = data; + struct lkkbd *lk = container_of(work, struct lkkbd, tq); int division; unsigned char leds_on = 0; unsigned char leds_off = 0; @@ -651,7 +651,7 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) lk->serio = serio; lk->dev = input_dev; - INIT_WORK (&lk->tq, lkkbd_reinit, lk); + INIT_WORK (&lk->tq, lkkbd_reinit); lk->bell_volume = bell_volume; lk->keyclick_volume = keyclick_volume; lk->ctrlclick_volume = ctrlclick_volume; diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index cac4781103c3..6cd887c5eb0a 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -208,9 +208,9 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) * were in. */ -static void sunkbd_reinit(void *data) +static void sunkbd_reinit(struct work_struct *work) { - struct sunkbd *sunkbd = data; + struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); @@ -248,7 +248,7 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) sunkbd->serio = serio; sunkbd->dev = input_dev; init_waitqueue_head(&sunkbd->wait); - INIT_WORK(&sunkbd->tq, sunkbd_reinit, sunkbd); + INIT_WORK(&sunkbd->tq, sunkbd_reinit); snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys); serio_set_drvdata(serio, sunkbd); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 6f9b2c7cc9c2..52bb2226ce2f 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -888,9 +888,10 @@ static int psmouse_poll(struct psmouse *psmouse) * psmouse_resync() attempts to re-validate current protocol. */ -static void psmouse_resync(void *p) +static void psmouse_resync(struct work_struct *work) { - struct psmouse *psmouse = p, *parent = NULL; + struct psmouse *parent = NULL, *psmouse = + container_of(work, struct psmouse, resync_work); struct serio *serio = psmouse->ps2dev.serio; psmouse_ret_t rc = PSMOUSE_GOOD_DATA; int failed = 0, enabled = 0; @@ -1121,7 +1122,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) goto out; ps2_init(&psmouse->ps2dev, serio); - INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse); + INIT_WORK(&psmouse->resync_work, psmouse_resync); psmouse->dev = input_dev; snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys); diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c index 6ae6eb322111..946c38cf6f8a 100644 --- a/drivers/isdn/act2000/capi.c +++ b/drivers/isdn/act2000/capi.c @@ -627,8 +627,10 @@ handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) { } void -actcapi_dispatch(act2000_card *card) +actcapi_dispatch(struct work_struct *work) { + struct act2000_card *card = + container_of(work, struct act2000_card, rcv_tq); struct sk_buff *skb; actcapi_msg *msg; __u16 ccmd; diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h index 49f453c53c64..e55f6a931f66 100644 --- a/drivers/isdn/act2000/capi.h +++ b/drivers/isdn/act2000/capi.h @@ -356,7 +356,7 @@ extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int extern void actcapi_select_b2_protocol_req(act2000_card *, act2000_chan *); extern void actcapi_disconnect_b3_req(act2000_card *, act2000_chan *); extern void actcapi_connect_resp(act2000_card *, act2000_chan *, __u8); -extern void actcapi_dispatch(act2000_card *); +extern void actcapi_dispatch(struct work_struct *); #ifdef DEBUG_MSG extern void actcapi_debug_msg(struct sk_buff *skb, int); #else diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c index d89dcde4eade..90593e2ef872 100644 --- a/drivers/isdn/act2000/module.c +++ b/drivers/isdn/act2000/module.c @@ -192,8 +192,11 @@ act2000_set_msn(act2000_card *card, char *eazmsn) } static void -act2000_transmit(struct act2000_card *card) +act2000_transmit(struct work_struct *work) { + struct act2000_card *card = + container_of(work, struct act2000_card, snd_tq); + switch (card->bus) { case ACT2000_BUS_ISA: act2000_isa_send(card); @@ -207,8 +210,11 @@ act2000_transmit(struct act2000_card *card) } static void -act2000_receive(struct act2000_card *card) +act2000_receive(struct work_struct *work) { + struct act2000_card *card = + container_of(work, struct act2000_card, poll_tq); + switch (card->bus) { case ACT2000_BUS_ISA: act2000_isa_receive(card); @@ -227,7 +233,7 @@ act2000_poll(unsigned long data) act2000_card * card = (act2000_card *)data; unsigned long flags; - act2000_receive(card); + act2000_receive(&card->poll_tq); spin_lock_irqsave(&card->lock, flags); mod_timer(&card->ptimer, jiffies+3); spin_unlock_irqrestore(&card->lock, flags); @@ -578,9 +584,9 @@ act2000_alloccard(int bus, int port, int irq, char *id) skb_queue_head_init(&card->sndq); skb_queue_head_init(&card->rcvq); skb_queue_head_init(&card->ackq); - INIT_WORK(&card->snd_tq, (void *) (void *) act2000_transmit, card); - INIT_WORK(&card->rcv_tq, (void *) (void *) actcapi_dispatch, card); - INIT_WORK(&card->poll_tq, (void *) (void *) act2000_receive, card); + INIT_WORK(&card->snd_tq, act2000_transmit); + INIT_WORK(&card->rcv_tq, actcapi_dispatch); + INIT_WORK(&card->poll_tq, act2000_receive); init_timer(&card->ptimer); card->interface.owner = THIS_MODULE; card->interface.channels = ACT2000_BCH; diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 8c4fcb9027b3..783a25526315 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -208,9 +208,10 @@ static void notify_down(u32 contr) } } -static void notify_handler(void *data) +static void notify_handler(struct work_struct *work) { - struct capi_notifier *np = data; + struct capi_notifier *np = + container_of(work, struct capi_notifier, work); switch (np->cmd) { case KCI_CONTRUP: @@ -235,7 +236,7 @@ static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci) if (!np) return -ENOMEM; - INIT_WORK(&np->work, notify_handler, np); + INIT_WORK(&np->work, notify_handler); np->cmd = cmd; np->controller = controller; np->applid = applid; @@ -248,10 +249,11 @@ static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci) /* -------- Receiver ------------------------------------------ */ -static void recv_handler(void *_ap) +static void recv_handler(struct work_struct *work) { struct sk_buff *skb; - struct capi20_appl *ap = (struct capi20_appl *) _ap; + struct capi20_appl *ap = + container_of(work, struct capi20_appl, recv_work); if ((!ap) || (ap->release_in_progress)) return; @@ -527,7 +529,7 @@ u16 capi20_register(struct capi20_appl *ap) ap->callback = NULL; init_MUTEX(&ap->recv_sem); skb_queue_head_init(&ap->recv_queue); - INIT_WORK(&ap->recv_work, recv_handler, (void *)ap); + INIT_WORK(&ap->recv_work, recv_handler); ap->release_in_progress = 0; write_unlock_irqrestore(&application_lock, flags); diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index bec59010bc66..3b19caeba258 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -232,9 +232,10 @@ Amd7930_new_ph(struct IsdnCardState *cs) static void -Amd7930_bh(struct IsdnCardState *cs) +Amd7930_bh(struct work_struct *work) { - + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; if (!cs) @@ -789,7 +790,7 @@ Amd7930_init(struct IsdnCardState *cs) void __devinit setup_Amd7930(struct IsdnCardState *cs) { - INIT_WORK(&cs->tqueue, (void *)(void *) Amd7930_bh, cs); + INIT_WORK(&cs->tqueue, Amd7930_bh); cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 785b08554fca..cede72cdbb31 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1137,7 +1137,6 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow cs->tx_skb = NULL; cs->tx_cnt = 0; cs->event = 0; - cs->tqueue.data = cs; skb_queue_head_init(&cs->rq); skb_queue_head_init(&cs->sq); @@ -1554,7 +1553,7 @@ static void hisax_b_l2l1(struct PStack *st, int pr, void *arg); static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg); static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs); static void hisax_bc_close(struct BCState *bcs); -static void hisax_bh(struct IsdnCardState *cs); +static void hisax_bh(struct work_struct *work); static void EChannel_proc_rcv(struct hisax_d_if *d_if); int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[], @@ -1586,7 +1585,7 @@ int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[], hisax_d_if->cs = cs; cs->hw.hisax_d_if = hisax_d_if; cs->cardmsg = hisax_cardmsg; - INIT_WORK(&cs->tqueue, (void *)(void *)hisax_bh, cs); + INIT_WORK(&cs->tqueue, hisax_bh); cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1; for (i = 0; i < 2; i++) { cs->bcs[i].BC_SetStack = hisax_bc_setstack; @@ -1618,8 +1617,10 @@ static void hisax_sched_event(struct IsdnCardState *cs, int event) schedule_work(&cs->tqueue); } -static void hisax_bh(struct IsdnCardState *cs) +static void hisax_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); struct PStack *st; int pr; diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index d852c9d998b2..de9b1a4d6bac 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -1083,8 +1083,9 @@ tx_b_frame(struct hfc4s8s_btype *bch) /* bottom half handler for interrupt */ /*************************************/ static void -hfc4s8s_bh(hfc4s8s_hw * hw) +hfc4s8s_bh(struct work_struct *work) { + hfc4s8s_hw *hw = container_of(work, hfc4s8s_hw, tqueue); u_char b; struct hfc4s8s_l1 *l1p; volatile u_char *fifo_stat; @@ -1550,7 +1551,7 @@ setup_instance(hfc4s8s_hw * hw) goto out; } - INIT_WORK(&hw->tqueue, (void *) (void *) hfc4s8s_bh, hw); + INIT_WORK(&hw->tqueue, hfc4s8s_bh); if (request_irq (hw->irq, hfc4s8s_interrupt, IRQF_SHARED, hw->card_name, hw)) { diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index 6360e8214720..8d9864453a23 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -549,10 +549,11 @@ setstack_2b(struct PStack *st, struct BCState *bcs) } static void -hfcd_bh(struct IsdnCardState *cs) +hfcd_bh(struct work_struct *work) { - if (!cs) - return; + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); + if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { switch (cs->dc.hfcd.ph_state) { case (0): @@ -1072,5 +1073,5 @@ set_cs_func(struct IsdnCardState *cs) cs->dbusytimer.function = (void *) hfc_dbusy_timer; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); - INIT_WORK(&cs->tqueue, (void *)(void *) hfcd_bh, cs); + INIT_WORK(&cs->tqueue, hfcd_bh); } diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 93f60b563515..5db0a85b827f 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1506,8 +1506,10 @@ setstack_2b(struct PStack *st, struct BCState *bcs) /* handle L1 state changes */ /***************************/ static void -hfcpci_bh(struct IsdnCardState *cs) +hfcpci_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); u_long flags; // struct PStack *stptr; @@ -1722,7 +1724,7 @@ setup_hfcpci(struct IsdnCard *card) Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); /* At this point the needed PCI config is done */ /* fifos are still not enabled */ - INIT_WORK(&cs->tqueue, (void *)(void *) hfcpci_bh, cs); + INIT_WORK(&cs->tqueue, hfcpci_bh); cs->setstack_d = setstack_hfcpci; cs->BC_Send_Data = &hfcpci_send_data; cs->readisac = NULL; diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index 954d1536db1f..4fd09d21a27f 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -1251,8 +1251,10 @@ setstack_2b(struct PStack *st, struct BCState *bcs) /* handle L1 state changes */ /***************************/ static void -hfcsx_bh(struct IsdnCardState *cs) +hfcsx_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); u_long flags; if (!cs) @@ -1499,7 +1501,7 @@ setup_hfcsx(struct IsdnCard *card) cs->dbusytimer.function = (void *) hfcsx_dbusy_timer; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); - INIT_WORK(&cs->tqueue, (void *)(void *) hfcsx_bh, cs); + INIT_WORK(&cs->tqueue, hfcsx_bh); cs->readisac = NULL; cs->writeisac = NULL; cs->readisacfifo = NULL; diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index da706925d54d..682cac32f259 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -77,8 +77,10 @@ icc_new_ph(struct IsdnCardState *cs) } static void -icc_bh(struct IsdnCardState *cs) +icc_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; if (!cs) @@ -674,7 +676,7 @@ clear_pending_icc_ints(struct IsdnCardState *cs) void __devinit setup_icc(struct IsdnCardState *cs) { - INIT_WORK(&cs->tqueue, (void *)(void *) icc_bh, cs); + INIT_WORK(&cs->tqueue, icc_bh); cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 282f349408bc..4e9f23803dae 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -81,8 +81,10 @@ isac_new_ph(struct IsdnCardState *cs) } static void -isac_bh(struct IsdnCardState *cs) +isac_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; if (!cs) @@ -674,7 +676,7 @@ clear_pending_isac_ints(struct IsdnCardState *cs) void __devinit setup_isac(struct IsdnCardState *cs) { - INIT_WORK(&cs->tqueue, (void *)(void *) isac_bh, cs); + INIT_WORK(&cs->tqueue, isac_bh); cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 674af673ff96..6f1a6583b17d 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -437,8 +437,10 @@ extern void BChannel_bh(struct BCState *); #define B_LL_OK 10 static void -isar_bh(struct BCState *bcs) +isar_bh(struct work_struct *work) { + struct BCState *bcs = container_of(work, struct BCState, tqueue); + BChannel_bh(bcs); if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event)) ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR); @@ -1580,7 +1582,7 @@ isar_setup(struct IsdnCardState *cs) cs->bcs[i].mode = 0; cs->bcs[i].hw.isar.dpath = i + 1; modeisar(&cs->bcs[i], 0, 0); - INIT_WORK(&cs->bcs[i].tqueue, (void *)(void *) isar_bh, &cs->bcs[i]); + INIT_WORK(&cs->bcs[i].tqueue, isar_bh); } } diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index bab356886483..a14204ec88ee 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -315,8 +315,10 @@ BChannel_proc_ack(struct BCState *bcs) } void -BChannel_bh(struct BCState *bcs) +BChannel_bh(struct work_struct *work) { + struct BCState *bcs = container_of(work, struct BCState, tqueue); + if (!bcs) return; if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event)) @@ -362,7 +364,7 @@ init_bcstate(struct IsdnCardState *cs, int bc) bcs->cs = cs; bcs->channel = bc; - INIT_WORK(&bcs->tqueue, (void *)(void *) BChannel_bh, bcs); + INIT_WORK(&bcs->tqueue, BChannel_bh); spin_lock_init(&bcs->aclock); bcs->BC_SetStack = NULL; bcs->BC_Close = NULL; diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 1655341797a9..3aeceaf9769e 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -101,8 +101,10 @@ W6692_new_ph(struct IsdnCardState *cs) } static void -W6692_bh(struct IsdnCardState *cs) +W6692_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; if (!cs) @@ -1070,7 +1072,7 @@ setup_w6692(struct IsdnCard *card) id_list[cs->subtyp].card_name, cs->irq, cs->hw.w6692.iobase); - INIT_WORK(&cs->tqueue, (void *)(void *) W6692_bh, cs); + INIT_WORK(&cs->tqueue, W6692_bh); cs->readW6692 = &ReadW6692; cs->writeW6692 = &WriteW6692; cs->readisacfifo = &ReadISACfifo; diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 1f8d6ae66b41..2e4daebfb7e0 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -984,9 +984,9 @@ void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb) /* * called from tq_immediate */ -static void isdn_net_softint(void *private) +static void isdn_net_softint(struct work_struct *work) { - isdn_net_local *lp = private; + isdn_net_local *lp = container_of(work, isdn_net_local, tqueue); struct sk_buff *skb; spin_lock_bh(&lp->xmit_lock); @@ -2596,7 +2596,7 @@ isdn_net_new(char *name, struct net_device *master) netdev->local->netdev = netdev; netdev->local->next = netdev->local; - INIT_WORK(&netdev->local->tqueue, (void *)(void *) isdn_net_softint, netdev->local); + INIT_WORK(&netdev->local->tqueue, isdn_net_softint); spin_lock_init(&netdev->local->xmit_lock); netdev->local->isdn_device = -1; diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 6ead5e1508b7..1966f3410a13 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -68,8 +68,6 @@ static void pcbit_set_msn(struct pcbit_dev *dev, char *list); static int pcbit_check_msn(struct pcbit_dev *dev, char *msn); -extern void pcbit_deliver(void * data); - int pcbit_init_dev(int board, int mem_base, int irq) { struct pcbit_dev *dev; @@ -129,7 +127,7 @@ int pcbit_init_dev(int board, int mem_base, int irq) memset(dev->b2, 0, sizeof(struct pcbit_chan)); dev->b2->id = 1; - INIT_WORK(&dev->qdelivery, pcbit_deliver, dev); + INIT_WORK(&dev->qdelivery, pcbit_deliver); /* * interrupts diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index 937fd2120381..0c9f6df873fc 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -67,7 +67,6 @@ extern void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg, * Prototypes */ -void pcbit_deliver(void *data); static void pcbit_transmit(struct pcbit_dev *dev); static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack); @@ -299,11 +298,12 @@ pcbit_transmit(struct pcbit_dev *dev) */ void -pcbit_deliver(void *data) +pcbit_deliver(struct work_struct *work) { struct frame_buf *frame; unsigned long flags, msg; - struct pcbit_dev *dev = (struct pcbit_dev *) data; + struct pcbit_dev *dev = + container_of(work, struct pcbit_dev, qdelivery); spin_lock_irqsave(&dev->lock, flags); diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h index 388bacefd23a..19c18e88ff16 100644 --- a/drivers/isdn/pcbit/pcbit.h +++ b/drivers/isdn/pcbit/pcbit.h @@ -166,4 +166,6 @@ struct pcbit_ioctl { #define L2_RUNNING 5 #define L2_ERROR 6 +extern void pcbit_deliver(struct work_struct *work); + #endif diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index ade25b3fbb35..4871158aca3e 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -600,7 +600,7 @@ core_initcall(smu_late_init); * sysfs visibility */ -static void smu_expose_childs(void *unused) +static void smu_expose_childs(struct work_struct *unused) { struct device_node *np; @@ -610,7 +610,7 @@ static void smu_expose_childs(void *unused) &smu->of_dev->dev); } -static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs, NULL); +static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs); static int smu_platform_probe(struct of_device* dev, const struct of_device_id *match) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 08a40f4e4f60..ed2d4ef27fd8 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -458,11 +458,11 @@ static void dec_pending(struct crypt_io *io, int error) * interrupt context. */ static struct workqueue_struct *_kcryptd_workqueue; -static void kcryptd_do_work(void *data); +static void kcryptd_do_work(struct work_struct *work); static void kcryptd_queue_io(struct crypt_io *io) { - INIT_WORK(&io->work, kcryptd_do_work, io); + INIT_WORK(&io->work, kcryptd_do_work); queue_work(_kcryptd_workqueue, &io->work); } @@ -618,9 +618,9 @@ static void process_read_endio(struct crypt_io *io) dec_pending(io, crypt_convert(cc, &ctx)); } -static void kcryptd_do_work(void *data) +static void kcryptd_do_work(struct work_struct *work) { - struct crypt_io *io = data; + struct crypt_io *io = container_of(work, struct crypt_io, work); if (io->post_process) process_read_endio(io); diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index d754e0bc6e90..e77ee6fd1044 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -104,8 +104,8 @@ typedef int (*action_fn) (struct pgpath *pgpath); static kmem_cache_t *_mpio_cache; struct workqueue_struct *kmultipathd; -static void process_queued_ios(void *data); -static void trigger_event(void *data); +static void process_queued_ios(struct work_struct *work); +static void trigger_event(struct work_struct *work); /*----------------------------------------------- @@ -173,8 +173,8 @@ static struct multipath *alloc_multipath(struct dm_target *ti) INIT_LIST_HEAD(&m->priority_groups); spin_lock_init(&m->lock); m->queue_io = 1; - INIT_WORK(&m->process_queued_ios, process_queued_ios, m); - INIT_WORK(&m->trigger_event, trigger_event, m); + INIT_WORK(&m->process_queued_ios, process_queued_ios); + INIT_WORK(&m->trigger_event, trigger_event); m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache); if (!m->mpio_pool) { kfree(m); @@ -379,9 +379,10 @@ static void dispatch_queued_ios(struct multipath *m) } } -static void process_queued_ios(void *data) +static void process_queued_ios(struct work_struct *work) { - struct multipath *m = (struct multipath *) data; + struct multipath *m = + container_of(work, struct multipath, process_queued_ios); struct hw_handler *hwh = &m->hw_handler; struct pgpath *pgpath = NULL; unsigned init_required = 0, must_queue = 1; @@ -421,9 +422,10 @@ out: * An event is triggered whenever a path is taken out of use. * Includes path failure and PG bypass. */ -static void trigger_event(void *data) +static void trigger_event(struct work_struct *work) { - struct multipath *m = (struct multipath *) data; + struct multipath *m = + container_of(work, struct multipath, trigger_event); dm_table_event(m->ti->table); } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 48a653b3f518..fc8cbb168e3e 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -883,7 +883,7 @@ static void do_mirror(struct mirror_set *ms) do_writes(ms, &writes); } -static void do_work(void *ignored) +static void do_work(struct work_struct *ignored) { struct mirror_set *ms; @@ -1269,7 +1269,7 @@ static int __init dm_mirror_init(void) dm_dirty_log_exit(); return r; } - INIT_WORK(&_kmirrord_work, do_work, NULL); + INIT_WORK(&_kmirrord_work, do_work); r = dm_register_target(&mirror_target); if (r < 0) { diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 5281e0094072..91c7aa1fed0e 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -40,7 +40,7 @@ #define SNAPSHOT_PAGES 256 struct workqueue_struct *ksnapd; -static void flush_queued_bios(void *data); +static void flush_queued_bios(struct work_struct *work); struct pending_exception { struct exception e; @@ -528,7 +528,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) } bio_list_init(&s->queued_bios); - INIT_WORK(&s->queued_bios_work, flush_queued_bios, s); + INIT_WORK(&s->queued_bios_work, flush_queued_bios); /* Add snapshot to the list of snapshots for this origin */ /* Exceptions aren't triggered till snapshot_resume() is called */ @@ -603,9 +603,10 @@ static void flush_bios(struct bio *bio) } } -static void flush_queued_bios(void *data) +static void flush_queued_bios(struct work_struct *work) { - struct dm_snapshot *s = (struct dm_snapshot *) data; + struct dm_snapshot *s = + container_of(work, struct dm_snapshot, queued_bios_work); struct bio *queued_bios; unsigned long flags; diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c index f1db6eff4857..b3c01496c737 100644 --- a/drivers/md/kcopyd.c +++ b/drivers/md/kcopyd.c @@ -417,7 +417,7 @@ static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *)) /* * kcopyd does this every time it's woken up. */ -static void do_work(void *ignored) +static void do_work(struct work_struct *ignored) { /* * The order that these are called is *very* important. @@ -628,7 +628,7 @@ static int kcopyd_init(void) } kcopyd_clients++; - INIT_WORK(&_kcopyd_work, do_work, NULL); + INIT_WORK(&_kcopyd_work, do_work); mutex_unlock(&kcopyd_init_lock); return 0; } diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 06893243f3d4..6e166801505d 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -63,7 +63,7 @@ struct flexcop_pci { unsigned long last_irq; - struct work_struct irq_check_work; + struct delayed_work irq_check_work; struct flexcop_device *fc_dev; }; @@ -97,9 +97,10 @@ static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_regi return 0; } -static void flexcop_pci_irq_check_work(void *data) +static void flexcop_pci_irq_check_work(struct work_struct *work) { - struct flexcop_pci *fc_pci = data; + struct flexcop_pci *fc_pci = + container_of(work, struct flexcop_pci, irq_check_work.work); struct flexcop_device *fc = fc_pci->fc_dev; flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); @@ -371,7 +372,7 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) goto err_fc_exit; - INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci); + INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work); return ret; diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index ff7d4f56ced3..dd0bcbe140bd 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -127,7 +127,7 @@ struct cinergyt2 { struct dvbt_set_parameters_msg param; struct dvbt_get_status_msg status; - struct work_struct query_work; + struct delayed_work query_work; wait_queue_head_t poll_wq; int pending_fe_events; @@ -141,7 +141,7 @@ struct cinergyt2 { #ifdef ENABLE_RC struct input_dev *rc_input_dev; char phys[64]; - struct work_struct rc_query_work; + struct delayed_work rc_query_work; int rc_input_event; u32 rc_last_code; unsigned long last_event_jiffies; @@ -724,9 +724,10 @@ static struct dvb_device cinergyt2_fe_template = { #ifdef ENABLE_RC -static void cinergyt2_query_rc (void *data) +static void cinergyt2_query_rc (struct work_struct *work) { - struct cinergyt2 *cinergyt2 = data; + struct cinergyt2 *cinergyt2 = + container_of(work, struct cinergyt2, rc_query_work.work); char buf[1] = { CINERGYT2_EP1_GET_RC_EVENTS }; struct cinergyt2_rc_event rc_events[12]; int n, len, i; @@ -807,7 +808,7 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys)); cinergyt2->rc_input_event = KEY_MAX; cinergyt2->rc_last_code = ~0; - INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); + INIT_DELAYED_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc); input_dev->name = DRIVER_NAME " remote control"; input_dev->phys = cinergyt2->phys; @@ -848,9 +849,10 @@ static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { } #endif /* ENABLE_RC */ -static void cinergyt2_query (void *data) +static void cinergyt2_query (struct work_struct *work) { - struct cinergyt2 *cinergyt2 = (struct cinergyt2 *) data; + struct cinergyt2 *cinergyt2 = + container_of(work, struct cinergyt2, query_work.work); char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS }; struct dvbt_get_status_msg *s = &cinergyt2->status; uint8_t lock_bits; @@ -894,7 +896,7 @@ static int cinergyt2_probe (struct usb_interface *intf, mutex_init(&cinergyt2->sem); init_waitqueue_head (&cinergyt2->poll_wq); - INIT_WORK(&cinergyt2->query_work, cinergyt2_query, cinergyt2); + INIT_DELAYED_WORK(&cinergyt2->query_work, cinergyt2_query); cinergyt2->udev = interface_to_usbdev(intf); cinergyt2->param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 8859ab74f0fe..ebf4dc5190f6 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -127,6 +127,7 @@ struct dvb_net_priv { int in_use; struct net_device_stats stats; u16 pid; + struct net_device *net; struct dvb_net *host; struct dmx_demux *demux; struct dmx_section_feed *secfeed; @@ -1123,10 +1124,11 @@ static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) } -static void wq_set_multicast_list (void *data) +static void wq_set_multicast_list (struct work_struct *work) { - struct net_device *dev = data; - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = + container_of(work, struct dvb_net_priv, set_multicast_list_wq); + struct net_device *dev = priv->net; dvb_net_feed_stop(dev); priv->rx_mode = RX_MODE_UNI; @@ -1167,9 +1169,11 @@ static void dvb_net_set_multicast_list (struct net_device *dev) } -static void wq_restart_net_feed (void *data) +static void wq_restart_net_feed (struct work_struct *work) { - struct net_device *dev = data; + struct dvb_net_priv *priv = + container_of(work, struct dvb_net_priv, restart_net_feed_wq); + struct net_device *dev = priv->net; if (netif_running(dev)) { dvb_net_feed_stop(dev); @@ -1276,6 +1280,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) dvbnet->device[if_num] = net; priv = net->priv; + priv->net = net; priv->demux = dvbnet->demux; priv->pid = pid; priv->rx_mode = RX_MODE_UNI; @@ -1284,8 +1289,8 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) priv->feedtype = feedtype; reset_ule(priv); - INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net); - INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net); + INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list); + INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed); mutex_init(&priv->mutex); net->base_addr = pid; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index 0a3a0b6c2350..794e4471561c 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -13,9 +13,10 @@ * * TODO: Fix the repeat rate of the input device. */ -static void dvb_usb_read_remote_control(void *data) +static void dvb_usb_read_remote_control(struct work_struct *work) { - struct dvb_usb_device *d = data; + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, rc_query_work.work); u32 event; int state; @@ -128,7 +129,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) input_register_device(d->rc_input_dev); - INIT_WORK(&d->rc_query_work, dvb_usb_read_remote_control, d); + INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); info("schedule remote query interval to %d msecs.", d->props.rc_interval); schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval)); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 376c45a8e779..0d721731a524 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -369,7 +369,7 @@ struct dvb_usb_device { /* remote control */ struct input_dev *rc_input_dev; char rc_phys[64]; - struct work_struct rc_query_work; + struct delayed_work rc_query_work; u32 last_event; int last_state; diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c index 41f4b8d17559..b12cec94f4cc 100644 --- a/drivers/media/video/cpia_pp.c +++ b/drivers/media/video/cpia_pp.c @@ -82,6 +82,8 @@ struct pp_cam_entry { struct pardevice *pdev; struct parport *port; struct work_struct cb_task; + void (*cb_func)(void *cbdata); + void *cb_data; int open_count; wait_queue_head_t wq_stream; /* image state flags */ @@ -130,6 +132,20 @@ static void cpia_parport_disable_irq( struct parport *port ) { #define PARPORT_CHUNK_SIZE PAGE_SIZE +static void cpia_pp_run_callback(struct work_struct *work) +{ + void (*cb_func)(void *cbdata); + void *cb_data; + struct pp_cam_entry *cam; + + cam = container_of(work, struct pp_cam_entry, cb_task); + cb_func = cam->cb_func; + cb_data = cam->cb_data; + work_release(work); + + cb_func(cb_data); +} + /**************************************************************************** * * CPiA-specific low-level parport functions for nibble uploads @@ -664,7 +680,9 @@ static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), vo int retval = 0; if(cam->port->irq != PARPORT_IRQ_NONE) { - INIT_WORK(&cam->cb_task, cb, cbdata); + cam->cb_func = cb; + cam->cb_data = cbdata; + INIT_WORK_NAR(&cam->cb_task, cpia_pp_run_callback); } else { retval = -1; } diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 57e1c024a547..e60a0a52e4b2 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -145,9 +145,9 @@ static void ir_timer(unsigned long data) schedule_work(&ir->work); } -static void cx88_ir_work(void *data) +static void cx88_ir_work(struct work_struct *work) { - struct cx88_IR *ir = data; + struct cx88_IR *ir = container_of(work, struct cx88_IR, work); unsigned long timeout; cx88_ir_handle_key(ir); @@ -308,7 +308,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) core->ir = ir; if (ir->polling) { - INIT_WORK(&ir->work, cx88_ir_work, ir); + INIT_WORK(&ir->work, cx88_ir_work); init_timer(&ir->timer); ir->timer.function = ir_timer; ir->timer.data = (unsigned long)ir; diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 1457b1602221..ab87e7bfe84f 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -268,9 +268,9 @@ static void ir_timer(unsigned long data) schedule_work(&ir->work); } -static void ir_work(void *data) +static void ir_work(struct work_struct *work) { - struct IR_i2c *ir = data; + struct IR_i2c *ir = container_of(work, struct IR_i2c, work); ir_key_poll(ir); mod_timer(&ir->timer, jiffies+HZ/10); } @@ -400,7 +400,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir->input->name,ir->input->phys,adap->name); /* start polling via eventd */ - INIT_WORK(&ir->work, ir_work, ir); + INIT_WORK(&ir->work, ir_work); init_timer(&ir->timer); ir->timer.function = ir_timer; ir->timer.data = (unsigned long)ir; diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index f129f316d20e..cf129746205d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -45,16 +45,21 @@ static void pvr2_context_trigger_poll(struct pvr2_context *mp) } -static void pvr2_context_poll(struct pvr2_context *mp) +static void pvr2_context_poll(struct work_struct *work) { + struct pvr2_context *mp = + container_of(work, struct pvr2_context, workpoll); pvr2_context_enter(mp); do { pvr2_hdw_poll(mp->hdw); } while (0); pvr2_context_exit(mp); } -static void pvr2_context_setup(struct pvr2_context *mp) +static void pvr2_context_setup(struct work_struct *work) { + struct pvr2_context *mp = + container_of(work, struct pvr2_context, workinit); + pvr2_context_enter(mp); do { if (!pvr2_hdw_dev_ok(mp->hdw)) break; pvr2_hdw_setup(mp->hdw); @@ -92,8 +97,8 @@ struct pvr2_context *pvr2_context_create( } mp->workqueue = create_singlethread_workqueue("pvrusb2"); - INIT_WORK(&mp->workinit,(void (*)(void*))pvr2_context_setup,mp); - INIT_WORK(&mp->workpoll,(void (*)(void*))pvr2_context_poll,mp); + INIT_WORK(&mp->workinit, pvr2_context_setup); + INIT_WORK(&mp->workpoll, pvr2_context_poll); queue_work(mp->workqueue,&mp->workinit); done: return mp; diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index a81285ca7d5b..8ba05c214ca7 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c @@ -322,9 +322,9 @@ static void saa6588_timer(unsigned long data) schedule_work(&s->work); } -static void saa6588_work(void *data) +static void saa6588_work(struct work_struct *work) { - struct saa6588 *s = (struct saa6588 *)data; + struct saa6588 *s = container_of(work, struct saa6588, work); saa6588_i2c_poll(s); mod_timer(&s->timer, jiffies + msecs_to_jiffies(20)); @@ -417,7 +417,7 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind) saa6588_configure(s); /* start polling via eventd */ - INIT_WORK(&s->work, saa6588_work, s); + INIT_WORK(&s->work, saa6588_work); init_timer(&s->timer); s->timer.function = saa6588_timer; s->timer.data = (unsigned long)s; diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 65d044086ce9..daaae870a2c4 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -343,9 +343,10 @@ static struct video_device saa7134_empress_template = .minor = -1, }; -static void empress_signal_update(void* data) +static void empress_signal_update(struct work_struct *work) { - struct saa7134_dev* dev = (struct saa7134_dev*) data; + struct saa7134_dev* dev = + container_of(work, struct saa7134_dev, empress_workqueue); if (dev->nosignal) { dprintk("no video signal\n"); @@ -378,7 +379,7 @@ static int empress_init(struct saa7134_dev *dev) "%s empress (%s)", dev->name, saa7134_boards[dev->board].name); - INIT_WORK(&dev->empress_workqueue, empress_signal_update, (void*) dev); + INIT_WORK(&dev->empress_workqueue, empress_signal_update); err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, empress_nr[dev->nr]); @@ -399,7 +400,7 @@ static int empress_init(struct saa7134_dev *dev) sizeof(struct saa7134_buf), dev); - empress_signal_update(dev); + empress_signal_update(&dev->empress_workqueue); return 0; } diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 1dd491773150..ef2b55e19910 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -1018,9 +1018,10 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum) } static void -mptfc_setup_reset(void *arg) +mptfc_setup_reset(struct work_struct *work) { - MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fc_setup_reset_work); u64 pn; struct mptfc_rport_info *ri; @@ -1043,9 +1044,10 @@ mptfc_setup_reset(void *arg) } static void -mptfc_rescan_devices(void *arg) +mptfc_rescan_devices(struct work_struct *work) { - MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fc_rescan_work); int ii; u64 pn; struct mptfc_rport_info *ri; @@ -1154,8 +1156,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) } spin_lock_init(&ioc->fc_rescan_work_lock); - INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc); - INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset, (void *)ioc); + INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices); + INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset); spin_lock_irqsave(&ioc->FreeQlock, flags); diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 314c3a27585d..b7c4407c5e3f 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -111,7 +111,8 @@ struct mpt_lan_priv { u32 total_received; struct net_device_stats stats; /* Per device statistics */ - struct work_struct post_buckets_task; + struct delayed_work post_buckets_task; + struct net_device *dev; unsigned long post_buckets_active; }; @@ -132,7 +133,7 @@ static int lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, static int mpt_lan_open(struct net_device *dev); static int mpt_lan_reset(struct net_device *dev); static int mpt_lan_close(struct net_device *dev); -static void mpt_lan_post_receive_buckets(void *dev_id); +static void mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv); static void mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority); static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg); @@ -345,7 +346,7 @@ mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i; spin_unlock_irqrestore(&priv->rxfidx_lock, flags); } else { - mpt_lan_post_receive_buckets(dev); + mpt_lan_post_receive_buckets(priv); netif_wake_queue(dev); } @@ -441,7 +442,7 @@ mpt_lan_open(struct net_device *dev) dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n")); - mpt_lan_post_receive_buckets(dev); + mpt_lan_post_receive_buckets(priv); printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n", IOC_AND_NETDEV_NAMES_s_s(dev)); @@ -854,7 +855,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority) if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { if (priority) { - schedule_work(&priv->post_buckets_task); + schedule_delayed_work(&priv->post_buckets_task, 0); } else { schedule_delayed_work(&priv->post_buckets_task, 1); dioprintk((KERN_INFO MYNAM ": post_buckets queued on " @@ -1188,10 +1189,9 @@ mpt_lan_receive_post_reply(struct net_device *dev, /* Simple SGE's only at the moment */ static void -mpt_lan_post_receive_buckets(void *dev_id) +mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) { - struct net_device *dev = dev_id; - struct mpt_lan_priv *priv = dev->priv; + struct net_device *dev = priv->dev; MPT_ADAPTER *mpt_dev = priv->mpt_dev; MPT_FRAME_HDR *mf; LANReceivePostRequest_t *pRecvReq; @@ -1335,6 +1335,13 @@ out: clear_bit(0, &priv->post_buckets_active); } +static void +mpt_lan_post_receive_buckets_work(struct work_struct *work) +{ + mpt_lan_post_receive_buckets(container_of(work, struct mpt_lan_priv, + post_buckets_task.work)); +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static struct net_device * mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) @@ -1350,11 +1357,13 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) priv = netdev_priv(dev); + priv->dev = dev; priv->mpt_dev = mpt_dev; priv->pnum = pnum; - memset(&priv->post_buckets_task, 0, sizeof(struct work_struct)); - INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev); + memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task)); + INIT_DELAYED_WORK(&priv->post_buckets_task, + mpt_lan_post_receive_buckets_work); priv->post_buckets_active = 0; dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n", diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index b752a479f6db..4f0c530e47b0 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -2006,9 +2006,10 @@ __mptsas_discovery_work(MPT_ADAPTER *ioc) *(Mutex LOCKED) */ static void -mptsas_discovery_work(void * arg) +mptsas_discovery_work(struct work_struct *work) { - struct mptsas_discovery_event *ev = arg; + struct mptsas_discovery_event *ev = + container_of(work, struct mptsas_discovery_event, work); MPT_ADAPTER *ioc = ev->ioc; mutex_lock(&ioc->sas_discovery_mutex); @@ -2068,9 +2069,9 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) * Work queue thread to clear the persitency table */ static void -mptsas_persist_clear_table(void * arg) +mptsas_persist_clear_table(struct work_struct *work) { - MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; + MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task); mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); } @@ -2093,9 +2094,10 @@ mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) * Work queue thread to handle SAS hotplug events */ static void -mptsas_hotplug_work(void *arg) +mptsas_hotplug_work(struct work_struct *work) { - struct mptsas_hotplug_event *ev = arg; + struct mptsas_hotplug_event *ev = + container_of(work, struct mptsas_hotplug_event, work); MPT_ADAPTER *ioc = ev->ioc; struct mptsas_phyinfo *phy_info; struct sas_rphy *rphy; @@ -2341,7 +2343,7 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc, break; } - INIT_WORK(&ev->work, mptsas_hotplug_work, ev); + INIT_WORK(&ev->work, mptsas_hotplug_work); ev->ioc = ioc; ev->handle = le16_to_cpu(sas_event_data->DevHandle); ev->parent_handle = @@ -2366,7 +2368,7 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc, * Persistent table is full. */ INIT_WORK(&ioc->sas_persist_task, - mptsas_persist_clear_table, (void *)ioc); + mptsas_persist_clear_table); schedule_work(&ioc->sas_persist_task); break; case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: @@ -2395,7 +2397,7 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc, return; } - INIT_WORK(&ev->work, mptsas_hotplug_work, ev); + INIT_WORK(&ev->work, mptsas_hotplug_work); ev->ioc = ioc; ev->id = raid_event_data->VolumeID; ev->event_type = MPTSAS_IGNORE_EVENT; @@ -2474,7 +2476,7 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc, ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) return; - INIT_WORK(&ev->work, mptsas_discovery_work, ev); + INIT_WORK(&ev->work, mptsas_discovery_work); ev->ioc = ioc; schedule_work(&ev->work); }; @@ -2511,8 +2513,7 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) break; case MPI_EVENT_PERSISTENT_TABLE_FULL: INIT_WORK(&ioc->sas_persist_task, - mptsas_persist_clear_table, - (void *)ioc); + mptsas_persist_clear_table); schedule_work(&ioc->sas_persist_task); break; case MPI_EVENT_SAS_DISCOVERY: diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index e4cc3dd5fc9f..f422c0d0621c 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -646,9 +646,10 @@ struct work_queue_wrapper { int disk; }; -static void mpt_work_wrapper(void *data) +static void mpt_work_wrapper(struct work_struct *work) { - struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct work_queue_wrapper *wqw = + container_of(work, struct work_queue_wrapper, work); struct _MPT_SCSI_HOST *hd = wqw->hd; struct Scsi_Host *shost = hd->ioc->sh; struct scsi_device *sdev; @@ -695,7 +696,7 @@ static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk) disk); return; } - INIT_WORK(&wqw->work, mpt_work_wrapper, wqw); + INIT_WORK(&wqw->work, mpt_work_wrapper); wqw->hd = hd; wqw->disk = disk; @@ -784,9 +785,10 @@ MODULE_DEVICE_TABLE(pci, mptspi_pci_table); * renegotiate for a given target */ static void -mptspi_dv_renegotiate_work(void *data) +mptspi_dv_renegotiate_work(struct work_struct *work) { - struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct work_queue_wrapper *wqw = + container_of(work, struct work_queue_wrapper, work); struct _MPT_SCSI_HOST *hd = wqw->hd; struct scsi_device *sdev; @@ -804,7 +806,7 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd) if (!wqw) return; - INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work, wqw); + INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work); wqw->hd = hd; schedule_work(&wqw->work); diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c index 64130227574f..7fc7399bd2ec 100644 --- a/drivers/message/i2o/driver.c +++ b/drivers/message/i2o/driver.c @@ -232,7 +232,7 @@ int i2o_driver_dispatch(struct i2o_controller *c, u32 m) break; } - INIT_WORK(&evt->work, (void (*)(void *))drv->event, evt); + INIT_WORK(&evt->work, drv->event); queue_work(drv->event_queue, &evt->work); return 1; } diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index a2350640384b..9e529d8dd5cb 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -371,8 +371,10 @@ static int i2o_exec_remove(struct device *dev) * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY * again, otherwise send LCT NOTIFY to get informed on next LCT change. */ -static void i2o_exec_lct_modified(struct i2o_exec_lct_notify_work *work) +static void i2o_exec_lct_modified(struct work_struct *_work) { + struct i2o_exec_lct_notify_work *work = + container_of(_work, struct i2o_exec_lct_notify_work, work); u32 change_ind = 0; struct i2o_controller *c = work->c; @@ -439,8 +441,7 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m, work->c = c; - INIT_WORK(&work->work, (void (*)(void *))i2o_exec_lct_modified, - work); + INIT_WORK(&work->work, i2o_exec_lct_modified); queue_work(i2o_exec_driver.event_queue, &work->work); return 1; } @@ -460,13 +461,15 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m, /** * i2o_exec_event - Event handling function - * @evt: Event which occurs + * @work: Work item in occurring event * * Handles events send by the Executive device. At the moment does not do * anything useful. */ -static void i2o_exec_event(struct i2o_event *evt) +static void i2o_exec_event(struct work_struct *work) { + struct i2o_event *evt = container_of(work, struct i2o_event, work); + if (likely(evt->i2o_dev)) osm_debug("Event received from device: %d\n", evt->i2o_dev->lct_data.tid); diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index eaba81bf2eca..70ae00253321 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -419,16 +419,18 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req) /** * i2o_block_delayed_request_fn - delayed request queue function - * delayed_request: the delayed request with the queue to start + * @work: the delayed request with the queue to start * * If the request queue is stopped for a disk, and there is no open * request, a new event is created, which calls this function to start * the queue after I2O_BLOCK_REQUEST_TIME. Otherwise the queue will never * be started again. */ -static void i2o_block_delayed_request_fn(void *delayed_request) +static void i2o_block_delayed_request_fn(struct work_struct *work) { - struct i2o_block_delayed_request *dreq = delayed_request; + struct i2o_block_delayed_request *dreq = + container_of(work, struct i2o_block_delayed_request, + work.work); struct request_queue *q = dreq->queue; unsigned long flags; @@ -538,8 +540,9 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m, return 1; }; -static void i2o_block_event(struct i2o_event *evt) +static void i2o_block_event(struct work_struct *work) { + struct i2o_event *evt = container_of(work, struct i2o_event, work); osm_debug("event received\n"); kfree(evt); }; @@ -938,8 +941,8 @@ static void i2o_block_request_fn(struct request_queue *q) continue; dreq->queue = q; - INIT_WORK(&dreq->work, i2o_block_delayed_request_fn, - dreq); + INIT_DELAYED_WORK(&dreq->work, + i2o_block_delayed_request_fn); if (!queue_delayed_work(i2o_block_driver.event_queue, &dreq->work, diff --git a/drivers/message/i2o/i2o_block.h b/drivers/message/i2o/i2o_block.h index 4fdaa5bda412..d9fdc95b440d 100644 --- a/drivers/message/i2o/i2o_block.h +++ b/drivers/message/i2o/i2o_block.h @@ -96,7 +96,7 @@ struct i2o_block_request { /* I2O Block device delayed request */ struct i2o_block_delayed_request { - struct work_struct work; + struct delayed_work work; struct request_queue *queue; }; diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 1ba8754e9383..2ab7add78f94 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -33,9 +33,10 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) spin_unlock_irqrestore(&fm->lock, flags); } -static void tifm_7xx1_remove_media(void *adapter) +static void tifm_7xx1_remove_media(struct work_struct *work) { - struct tifm_adapter *fm = adapter; + struct tifm_adapter *fm = + container_of(work, struct tifm_adapter, media_remover); unsigned long flags; int cnt; struct tifm_dev *sock; @@ -169,9 +170,10 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) return base_addr + ((sock_num + 1) << 10); } -static void tifm_7xx1_insert_media(void *adapter) +static void tifm_7xx1_insert_media(struct work_struct *work) { - struct tifm_adapter *fm = adapter; + struct tifm_adapter *fm = + container_of(work, struct tifm_adapter, media_inserter); unsigned long flags; tifm_media_id media_id; char *card_name = "xx"; @@ -261,7 +263,7 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) spin_unlock_irqrestore(&fm->lock, flags); flush_workqueue(fm->wq); - tifm_7xx1_remove_media(fm); + tifm_7xx1_remove_media(&fm->media_remover); pci_set_power_state(dev, PCI_D3hot); pci_disable_device(dev); @@ -328,8 +330,8 @@ static int tifm_7xx1_probe(struct pci_dev *dev, if (!fm->sockets) goto err_out_free; - INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media, fm); - INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media, fm); + INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media); + INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media); fm->eject = tifm_7xx1_eject; pci_set_drvdata(dev, fm); @@ -384,7 +386,7 @@ static void tifm_7xx1_remove(struct pci_dev *dev) flush_workqueue(fm->wq); - tifm_7xx1_remove_media(fm); + tifm_7xx1_remove_media(&fm->media_remover); writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); free_irq(dev->irq, fm); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 766bc54406e5..21fd39e4a20f 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1165,18 +1165,16 @@ static void mmc_setup(struct mmc_host *host) */ void mmc_detect_change(struct mmc_host *host, unsigned long delay) { - if (delay) - mmc_schedule_delayed_work(&host->detect, delay); - else - mmc_schedule_work(&host->detect); + mmc_schedule_delayed_work(&host->detect, delay); } EXPORT_SYMBOL(mmc_detect_change); -static void mmc_rescan(void *data) +static void mmc_rescan(struct work_struct *work) { - struct mmc_host *host = data; + struct mmc_host *host = + container_of(work, struct mmc_host, detect.work); struct list_head *l, *n; unsigned char power_mode; @@ -1259,7 +1257,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_LIST_HEAD(&host->cards); - INIT_WORK(&host->detect, mmc_rescan, host); + INIT_DELAYED_WORK(&host->detect, mmc_rescan); /* * By default, hosts do not support SGIO or large requests. @@ -1357,7 +1355,7 @@ EXPORT_SYMBOL(mmc_suspend_host); */ int mmc_resume_host(struct mmc_host *host) { - mmc_rescan(host); + mmc_rescan(&host->detect.work); return 0; } diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h index cd5e0ab3d84b..149affe0b686 100644 --- a/drivers/mmc/mmc.h +++ b/drivers/mmc/mmc.h @@ -20,6 +20,6 @@ void mmc_remove_host_sysfs(struct mmc_host *host); void mmc_free_host_sysfs(struct mmc_host *host); int mmc_schedule_work(struct work_struct *work); -int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay); +int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay); void mmc_flush_scheduled_work(void); #endif diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index 10cc9734eaa0..fd9a5fc6db7b 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -320,18 +320,10 @@ void mmc_free_host_sysfs(struct mmc_host *host) static struct workqueue_struct *workqueue; -/* - * Internal function. Schedule work in the MMC work queue. - */ -int mmc_schedule_work(struct work_struct *work) -{ - return queue_work(workqueue, work); -} - /* * Internal function. Schedule delayed work in the MMC work queue. */ -int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay) +int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay) { return queue_delayed_work(workqueue, work, delay); } diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index 0fdc55b08a6d..e846499a004c 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -99,7 +99,7 @@ struct tifm_sd { struct mmc_request *req; struct work_struct cmd_handler; - struct work_struct abort_handler; + struct delayed_work abort_handler; wait_queue_head_t can_eject; size_t written_blocks; @@ -496,9 +496,9 @@ err_out: mmc_request_done(mmc, mrq); } -static void tifm_sd_end_cmd(void *data) +static void tifm_sd_end_cmd(struct work_struct *work) { - struct tifm_sd *host = data; + struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); struct tifm_dev *sock = host->dev; struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_request *mrq; @@ -608,9 +608,9 @@ err_out: mmc_request_done(mmc, mrq); } -static void tifm_sd_end_cmd_nodma(void *data) +static void tifm_sd_end_cmd_nodma(struct work_struct *work) { - struct tifm_sd *host = (struct tifm_sd*)data; + struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); struct tifm_dev *sock = host->dev; struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_request *mrq; @@ -661,11 +661,14 @@ static void tifm_sd_end_cmd_nodma(void *data) mmc_request_done(mmc, mrq); } -static void tifm_sd_abort(void *data) +static void tifm_sd_abort(struct work_struct *work) { + struct tifm_sd *host = + container_of(work, struct tifm_sd, abort_handler.work); + printk(KERN_ERR DRIVER_NAME ": card failed to respond for a long period of time"); - tifm_eject(((struct tifm_sd*)data)->dev); + tifm_eject(host->dev); } static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -762,9 +765,9 @@ static struct mmc_host_ops tifm_sd_ops = { .get_ro = tifm_sd_ro }; -static void tifm_sd_register_host(void *data) +static void tifm_sd_register_host(struct work_struct *work) { - struct tifm_sd *host = (struct tifm_sd*)data; + struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); struct tifm_dev *sock = host->dev; struct mmc_host *mmc = tifm_get_drvdata(sock); unsigned long flags; @@ -772,8 +775,7 @@ static void tifm_sd_register_host(void *data) spin_lock_irqsave(&sock->lock, flags); host->flags |= HOST_REG; PREPARE_WORK(&host->cmd_handler, - no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd, - data); + no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd); spin_unlock_irqrestore(&sock->lock, flags); dev_dbg(&sock->dev, "adding host\n"); mmc_add_host(mmc); @@ -799,8 +801,8 @@ static int tifm_sd_probe(struct tifm_dev *sock) host->dev = sock; host->clk_div = 61; init_waitqueue_head(&host->can_eject); - INIT_WORK(&host->cmd_handler, tifm_sd_register_host, host); - INIT_WORK(&host->abort_handler, tifm_sd_abort, host); + INIT_WORK(&host->cmd_handler, tifm_sd_register_host); + INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort); tifm_set_drvdata(sock, mmc); sock->signal_irq = tifm_sd_signal_irq; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index d02ed51abfcc..931028f672de 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -594,7 +594,7 @@ struct rtl8139_private { u32 rx_config; struct rtl_extra_stats xstats; - struct work_struct thread; + struct delayed_work thread; struct mii_if_info mii; unsigned int regs_len; @@ -636,8 +636,8 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); static void rtl8139_set_rx_mode (struct net_device *dev); static void __set_rx_mode (struct net_device *dev); static void rtl8139_hw_start (struct net_device *dev); -static void rtl8139_thread (void *_data); -static void rtl8139_tx_timeout_task(void *_data); +static void rtl8139_thread (struct work_struct *work); +static void rtl8139_tx_timeout_task(struct work_struct *work); static const struct ethtool_ops rtl8139_ethtool_ops; /* write MMIO register, with flush */ @@ -1010,7 +1010,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1)); spin_lock_init (&tp->lock); spin_lock_init (&tp->rx_lock); - INIT_WORK(&tp->thread, rtl8139_thread, dev); + INIT_DELAYED_WORK(&tp->thread, rtl8139_thread); tp->mii.dev = dev; tp->mii.mdio_read = mdio_read; tp->mii.mdio_write = mdio_write; @@ -1596,15 +1596,16 @@ static inline void rtl8139_thread_iter (struct net_device *dev, RTL_R8 (Config1)); } -static void rtl8139_thread (void *_data) +static void rtl8139_thread (struct work_struct *work) { - struct net_device *dev = _data; - struct rtl8139_private *tp = netdev_priv(dev); + struct rtl8139_private *tp = + container_of(work, struct rtl8139_private, thread.work); + struct net_device *dev = tp->mii.dev; unsigned long thr_delay = next_tick; if (tp->watchdog_fired) { tp->watchdog_fired = 0; - rtl8139_tx_timeout_task(_data); + rtl8139_tx_timeout_task(work); } else if (rtnl_trylock()) { rtl8139_thread_iter (dev, tp, tp->mmio_addr); rtnl_unlock (); @@ -1646,10 +1647,11 @@ static inline void rtl8139_tx_clear (struct rtl8139_private *tp) /* XXX account for unsent Tx packets in tp->stats.tx_dropped */ } -static void rtl8139_tx_timeout_task (void *_data) +static void rtl8139_tx_timeout_task (struct work_struct *work) { - struct net_device *dev = _data; - struct rtl8139_private *tp = netdev_priv(dev); + struct rtl8139_private *tp = + container_of(work, struct rtl8139_private, thread.work); + struct net_device *dev = tp->mii.dev; void __iomem *ioaddr = tp->mmio_addr; int i; u8 tmp8; @@ -1695,7 +1697,7 @@ static void rtl8139_tx_timeout (struct net_device *dev) struct rtl8139_private *tp = netdev_priv(dev); if (!tp->have_thread) { - INIT_WORK(&tp->thread, rtl8139_tx_timeout_task, dev); + INIT_DELAYED_WORK(&tp->thread, rtl8139_tx_timeout_task); schedule_delayed_work(&tp->thread, next_tick); } else tp->watchdog_fired = 1; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 01b76d3aa42f..b12cc4596b8d 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -4339,9 +4339,9 @@ bnx2_open(struct net_device *dev) } static void -bnx2_reset_task(void *data) +bnx2_reset_task(struct work_struct *work) { - struct bnx2 *bp = data; + struct bnx2 *bp = container_of(work, struct bnx2, reset_task); if (!netif_running(bp->dev)) return; @@ -5630,7 +5630,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->pdev = pdev; spin_lock_init(&bp->phy_lock); - INIT_WORK(&bp->reset_task, bnx2_reset_task, bp); + INIT_WORK(&bp->reset_task, bnx2_reset_task); dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0); mem_len = MB_GET_CID_ADDR(17); diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 521c5b71023c..fe08f3845491 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4066,9 +4066,9 @@ static int cas_alloc_rxds(struct cas *cp) return 0; } -static void cas_reset_task(void *data) +static void cas_reset_task(struct work_struct *work) { - struct cas *cp = (struct cas *) data; + struct cas *cp = container_of(work, struct cas, reset_task); #if 0 int pending = atomic_read(&cp->reset_task_pending); #else @@ -5006,7 +5006,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, atomic_set(&cp->reset_task_pending_spare, 0); atomic_set(&cp->reset_task_pending_mtu, 0); #endif - INIT_WORK(&cp->reset_task, cas_reset_task, cp); + INIT_WORK(&cp->reset_task, cas_reset_task); /* Default link parameters */ if (link_mode >= 0 && link_mode <= 6) diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 5d9dd14427c5..8b1bedbce0d5 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -209,7 +209,7 @@ struct adapter { struct peespi *espi; struct port_info port[MAX_NPORTS]; - struct work_struct stats_update_task; + struct delayed_work stats_update_task; struct timer_list stats_update_timer; struct semaphore mib_mutex; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index ad7ff9641a7e..f607cc6a276b 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -927,10 +927,11 @@ static void t1_netpoll(struct net_device *dev) * Periodic accumulation of MAC statistics. This is used only if the MAC * does not have any other way to prevent stats counter overflow. */ -static void mac_stats_task(void *data) +static void mac_stats_task(struct work_struct *work) { int i; - struct adapter *adapter = data; + struct adapter *adapter = + container_of(work, struct adapter, stats_update_task.work); for_each_port(adapter, i) { struct port_info *p = &adapter->port[i]; @@ -951,9 +952,10 @@ static void mac_stats_task(void *data) /* * Processes elmer0 external interrupts in process context. */ -static void ext_intr_task(void *data) +static void ext_intr_task(struct work_struct *work) { - struct adapter *adapter = data; + struct adapter *adapter = + container_of(work, struct adapter, ext_intr_handler_task); elmer0_ext_intr_handler(adapter); @@ -1087,9 +1089,9 @@ static int __devinit init_one(struct pci_dev *pdev, spin_lock_init(&adapter->async_lock); INIT_WORK(&adapter->ext_intr_handler_task, - ext_intr_task, adapter); - INIT_WORK(&adapter->stats_update_task, mac_stats_task, - adapter); + ext_intr_task); + INIT_DELAYED_WORK(&adapter->stats_update_task, + mac_stats_task); #ifdef work_struct init_timer(&adapter->stats_update_timer); adapter->stats_update_timer.function = mac_stats_timer; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 19ab3441269c..e7737d02bb05 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2102,9 +2102,10 @@ static void e100_tx_timeout(struct net_device *netdev) schedule_work(&nic->tx_timeout_task); } -static void e100_tx_timeout_task(struct net_device *netdev) +static void e100_tx_timeout_task(struct work_struct *work) { - struct nic *nic = netdev_priv(netdev); + struct nic *nic = container_of(work, struct nic, tx_timeout_task); + struct net_device *netdev = nic->netdev; DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", readb(&nic->csr->scb.status)); @@ -2637,8 +2638,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, nic->blink_timer.function = e100_blink_led; nic->blink_timer.data = (unsigned long)nic; - INIT_WORK(&nic->tx_timeout_task, - (void (*)(void *))e100_tx_timeout_task, netdev); + INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task); if((err = e100_alloc(nic))) { DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n"); diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 6ad696101418..83fa32f72398 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2224,11 +2224,12 @@ static int ehea_stop(struct net_device *dev) return ret; } -static void ehea_reset_port(void *data) +static void ehea_reset_port(struct work_struct *work) { int ret; - struct net_device *dev = data; - struct ehea_port *port = netdev_priv(dev); + struct ehea_port *port = + container_of(work, struct ehea_port, reset_task); + struct net_device *dev = port->netdev; port->resets++; down(&port->port_lock); @@ -2379,7 +2380,7 @@ static int ehea_setup_single_port(struct ehea_port *port, dev->tx_timeout = &ehea_tx_watchdog; dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT; - INIT_WORK(&port->reset_task, ehea_reset_port, dev); + INIT_WORK(&port->reset_task, ehea_reset_port); ehea_set_ethtool_ops(dev); diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 1ed9cccd3c11..3c33d6f6a6a6 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -168,8 +168,9 @@ struct baycom_state { int magic; struct pardevice *pdev; + struct net_device *dev; unsigned int work_running; - struct work_struct run_work; + struct delayed_work run_work; unsigned int modem; unsigned int bitrate; unsigned char stat; @@ -659,16 +660,18 @@ static int receive(struct net_device *dev, int cnt) #define GETTICK(x) #endif /* __i386__ */ -static void epp_bh(struct net_device *dev) +static void epp_bh(struct work_struct *work) { + struct net_device *dev; struct baycom_state *bc; struct parport *pp; unsigned char stat; unsigned char tmp[2]; unsigned int time1 = 0, time2 = 0, time3 = 0; int cnt, cnt2; - - bc = netdev_priv(dev); + + bc = container_of(work, struct baycom_state, run_work.work); + dev = bc->dev; if (!bc->work_running) return; baycom_int_freq(bc); @@ -889,7 +892,7 @@ static int epp_open(struct net_device *dev) return -EBUSY; } dev->irq = /*pp->irq*/ 0; - INIT_WORK(&bc->run_work, (void *)(void *)epp_bh, dev); + INIT_DELAYED_WORK(&bc->run_work, epp_bh); bc->work_running = 1; bc->modem = EPP_CONVENTIONAL; if (eppconfig(bc)) @@ -1213,6 +1216,7 @@ static void __init baycom_epp_dev_setup(struct net_device *dev) /* * initialize part of the baycom_state struct */ + bc->dev = dev; bc->magic = BAYCOM_MAGIC; bc->cfg.fclk = 19666600; bc->cfg.bps = 9600; diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index b32c52ed19d7..f0c61f3b2a82 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -560,9 +560,9 @@ static inline int mcs_find_endpoints(struct mcs_cb *mcs, return ret; } -static void mcs_speed_work(void *arg) +static void mcs_speed_work(struct work_struct *work) { - struct mcs_cb *mcs = arg; + struct mcs_cb *mcs = container_of(work, struct mcs_cb, work); struct net_device *netdev = mcs->netdev; mcs_speed_change(mcs); @@ -927,7 +927,7 @@ static int mcs_probe(struct usb_interface *intf, irda_qos_bits_to_value(&mcs->qos); /* Speed change work initialisation*/ - INIT_WORK(&mcs->work, mcs_speed_work, mcs); + INIT_WORK(&mcs->work, mcs_speed_work); /* Override the network functions we need to use */ ndev->hard_start_xmit = mcs_hard_xmit; diff --git a/drivers/net/irda/sir-dev.h b/drivers/net/irda/sir-dev.h index 9fa294a546d6..2a57bc67ce35 100644 --- a/drivers/net/irda/sir-dev.h +++ b/drivers/net/irda/sir-dev.h @@ -22,7 +22,7 @@ struct sir_fsm { struct semaphore sem; - struct work_struct work; + struct delayed_work work; unsigned state, substate; int param; int result; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 3b5854d10c17..17b0c3ab6201 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -100,9 +100,9 @@ static int sirdev_tx_complete_fsm(struct sir_dev *dev) * Both must be unlocked/restarted on completion - but only on final exit. */ -static void sirdev_config_fsm(void *data) +static void sirdev_config_fsm(struct work_struct *work) { - struct sir_dev *dev = data; + struct sir_dev *dev = container_of(work, struct sir_dev, fsm.work.work); struct sir_fsm *fsm = &dev->fsm; int next_state; int ret = -1; @@ -309,8 +309,8 @@ int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned par fsm->param = param; fsm->result = 0; - INIT_WORK(&fsm->work, sirdev_config_fsm, dev); - queue_work(irda_sir_wq, &fsm->work); + INIT_DELAYED_WORK(&fsm->work, sirdev_config_fsm); + queue_delayed_work(irda_sir_wq, &fsm->work, 0); return 0; } diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 2284e2ce1692..d6f4f185bf37 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -166,7 +166,7 @@ struct veth_msg { struct veth_lpar_connection { HvLpIndex remote_lp; - struct work_struct statemachine_wq; + struct delayed_work statemachine_wq; struct veth_msg *msgs; int num_events; struct veth_cap_data local_caps; @@ -456,7 +456,7 @@ static struct kobj_type veth_port_ktype = { static inline void veth_kick_statemachine(struct veth_lpar_connection *cnx) { - schedule_work(&cnx->statemachine_wq); + schedule_delayed_work(&cnx->statemachine_wq, 0); } static void veth_take_cap(struct veth_lpar_connection *cnx, @@ -638,9 +638,11 @@ static int veth_process_caps(struct veth_lpar_connection *cnx) } /* FIXME: The gotos here are a bit dubious */ -static void veth_statemachine(void *p) +static void veth_statemachine(struct work_struct *work) { - struct veth_lpar_connection *cnx = (struct veth_lpar_connection *)p; + struct veth_lpar_connection *cnx = + container_of(work, struct veth_lpar_connection, + statemachine_wq.work); int rlp = cnx->remote_lp; int rc; @@ -827,7 +829,7 @@ static int veth_init_connection(u8 rlp) cnx->remote_lp = rlp; spin_lock_init(&cnx->lock); - INIT_WORK(&cnx->statemachine_wq, veth_statemachine, cnx); + INIT_DELAYED_WORK(&cnx->statemachine_wq, veth_statemachine); init_timer(&cnx->ack_timer); cnx->ack_timer.function = veth_timed_ack; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index e09f575a3a38..d1ebb91ed278 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -106,7 +106,7 @@ static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter); static void ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter); void ixgb_set_ethtool_ops(struct net_device *netdev); static void ixgb_tx_timeout(struct net_device *dev); -static void ixgb_tx_timeout_task(struct net_device *dev); +static void ixgb_tx_timeout_task(struct work_struct *work); static void ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); static void ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); @@ -489,8 +489,7 @@ ixgb_probe(struct pci_dev *pdev, adapter->watchdog_timer.function = &ixgb_watchdog; adapter->watchdog_timer.data = (unsigned long)adapter; - INIT_WORK(&adapter->tx_timeout_task, - (void (*)(void *))ixgb_tx_timeout_task, netdev); + INIT_WORK(&adapter->tx_timeout_task, ixgb_tx_timeout_task); strcpy(netdev->name, "eth%d"); if((err = register_netdev(netdev))) @@ -1493,9 +1492,10 @@ ixgb_tx_timeout(struct net_device *netdev) } static void -ixgb_tx_timeout_task(struct net_device *netdev) +ixgb_tx_timeout_task(struct work_struct *work) { - struct ixgb_adapter *adapter = netdev_priv(netdev); + struct ixgb_adapter *adapter = + container_of(work, struct ixgb_adapter, tx_timeout_task); adapter->tx_timeout_count++; ixgb_down(adapter, TRUE); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 806081b59733..98703e086ee7 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2615,9 +2615,10 @@ static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp) * This watchdog is used to check whether the board has suffered * from a parity error and needs to be recovered. */ -static void myri10ge_watchdog(void *arg) +static void myri10ge_watchdog(struct work_struct *work) { - struct myri10ge_priv *mgp = arg; + struct myri10ge_priv *mgp = + container_of(work, struct myri10ge_priv, watchdog_work); u32 reboot; int status; u16 cmd, vendor; @@ -2887,7 +2888,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) (unsigned long)mgp); SET_ETHTOOL_OPS(netdev, &myri10ge_ethtool_ops); - INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog, mgp); + INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog); status = register_netdev(netdev); if (status != 0) { dev_err(&pdev->dev, "register_netdev failed: %d\n", status); diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index b0127c71a5b6..312e0e331712 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -427,6 +427,7 @@ struct ns83820 { u8 __iomem *base; struct pci_dev *pci_dev; + struct net_device *ndev; #ifdef NS83820_VLAN_ACCEL_SUPPORT struct vlan_group *vlgrp; @@ -631,10 +632,10 @@ static void fastcall rx_refill_atomic(struct net_device *ndev) } /* REFILL */ -static inline void queue_refill(void *_dev) +static inline void queue_refill(struct work_struct *work) { - struct net_device *ndev = _dev; - struct ns83820 *dev = PRIV(ndev); + struct ns83820 *dev = container_of(work, struct ns83820, tq_refill); + struct net_device *ndev = dev->ndev; rx_refill(ndev, GFP_KERNEL); if (dev->rx_info.up) @@ -1841,6 +1842,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ndev = alloc_etherdev(sizeof(struct ns83820)); dev = PRIV(ndev); + dev->ndev = ndev; err = -ENOMEM; if (!dev) goto out; @@ -1853,7 +1855,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pci_dev->dev); - INIT_WORK(&dev->tq_refill, queue_refill, ndev); + INIT_WORK(&dev->tq_refill, queue_refill); tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)ndev); err = pci_enable_device(pci_dev); diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index f3914f58d67f..5de8850f2323 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -332,6 +332,7 @@ static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id); */ typedef struct local_info_t { + struct net_device *dev; struct pcmcia_device *p_dev; dev_node_t node; struct net_device_stats stats; @@ -353,7 +354,7 @@ typedef struct local_info_t { */ static int do_start_xmit(struct sk_buff *skb, struct net_device *dev); static void do_tx_timeout(struct net_device *dev); -static void xirc2ps_tx_timeout_task(void *data); +static void xirc2ps_tx_timeout_task(struct work_struct *work); static struct net_device_stats *do_get_stats(struct net_device *dev); static void set_addresses(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -567,6 +568,7 @@ xirc2ps_probe(struct pcmcia_device *link) if (!dev) return -ENOMEM; local = netdev_priv(dev); + local->dev = dev; local->p_dev = link; link->priv = dev; @@ -591,7 +593,7 @@ xirc2ps_probe(struct pcmcia_device *link) #ifdef HAVE_TX_TIMEOUT dev->tx_timeout = do_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task, dev); + INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task); #endif return xirc2ps_config(link); @@ -1344,9 +1346,11 @@ xirc2ps_interrupt(int irq, void *dev_id) /*====================================================================*/ static void -xirc2ps_tx_timeout_task(void *data) +xirc2ps_tx_timeout_task(struct work_struct *work) { - struct net_device *dev = data; + local_info_t *local = + container_of(work, local_info_t, tx_timeout_task); + struct net_device *dev = local->dev; /* reset the card */ do_reset(dev,1); dev->trans_start = jiffies; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 3af9fcf76c81..a443976d5dcf 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -394,7 +394,7 @@ out_unlock: EXPORT_SYMBOL(phy_start_aneg); -static void phy_change(void *data); +static void phy_change(struct work_struct *work); static void phy_timer(unsigned long data); /* phy_start_machine: @@ -549,7 +549,7 @@ int phy_start_interrupts(struct phy_device *phydev) { int err = 0; - INIT_WORK(&phydev->phy_queue, phy_change, phydev); + INIT_WORK(&phydev->phy_queue, phy_change); if (request_irq(phydev->irq, phy_interrupt, IRQF_SHARED, @@ -585,10 +585,11 @@ EXPORT_SYMBOL(phy_stop_interrupts); /* Scheduled by the phy_interrupt/timer to handle PHY changes */ -static void phy_change(void *data) +static void phy_change(struct work_struct *work) { int err; - struct phy_device *phydev = data; + struct phy_device *phydev = + container_of(work, struct phy_device, phy_queue); err = phy_disable_interrupts(phydev); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 71afb274498f..6bb085f54437 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -138,9 +138,9 @@ static const unsigned int net_debug = NET_DEBUG; #define PLIP_NIBBLE_WAIT 3000 /* Bottom halves */ -static void plip_kick_bh(struct net_device *dev); -static void plip_bh(struct net_device *dev); -static void plip_timer_bh(struct net_device *dev); +static void plip_kick_bh(struct work_struct *work); +static void plip_bh(struct work_struct *work); +static void plip_timer_bh(struct work_struct *work); /* Interrupt handler */ static void plip_interrupt(int irq, void *dev_id); @@ -207,9 +207,10 @@ struct plip_local { struct net_local { struct net_device_stats enet_stats; + struct net_device *dev; struct work_struct immediate; - struct work_struct deferred; - struct work_struct timer; + struct delayed_work deferred; + struct delayed_work timer; struct plip_local snd_data; struct plip_local rcv_data; struct pardevice *pardev; @@ -306,11 +307,11 @@ plip_init_netdev(struct net_device *dev) nl->nibble = PLIP_NIBBLE_WAIT; /* Initialize task queue structures */ - INIT_WORK(&nl->immediate, (void (*)(void *))plip_bh, dev); - INIT_WORK(&nl->deferred, (void (*)(void *))plip_kick_bh, dev); + INIT_WORK(&nl->immediate, plip_bh); + INIT_DELAYED_WORK(&nl->deferred, plip_kick_bh); if (dev->irq == -1) - INIT_WORK(&nl->timer, (void (*)(void *))plip_timer_bh, dev); + INIT_DELAYED_WORK(&nl->timer, plip_timer_bh); spin_lock_init(&nl->lock); } @@ -319,9 +320,10 @@ plip_init_netdev(struct net_device *dev) This routine is kicked by do_timer(). Request `plip_bh' to be invoked. */ static void -plip_kick_bh(struct net_device *dev) +plip_kick_bh(struct work_struct *work) { - struct net_local *nl = netdev_priv(dev); + struct net_local *nl = + container_of(work, struct net_local, deferred.work); if (nl->is_deferred) schedule_work(&nl->immediate); @@ -362,9 +364,9 @@ static const plip_func connection_state_table[] = /* Bottom half handler of PLIP. */ static void -plip_bh(struct net_device *dev) +plip_bh(struct work_struct *work) { - struct net_local *nl = netdev_priv(dev); + struct net_local *nl = container_of(work, struct net_local, immediate); struct plip_local *snd = &nl->snd_data; struct plip_local *rcv = &nl->rcv_data; plip_func f; @@ -372,20 +374,21 @@ plip_bh(struct net_device *dev) nl->is_deferred = 0; f = connection_state_table[nl->connection]; - if ((r = (*f)(dev, nl, snd, rcv)) != OK - && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) { + if ((r = (*f)(nl->dev, nl, snd, rcv)) != OK + && (r = plip_bh_timeout_error(nl->dev, nl, snd, rcv, r)) != OK) { nl->is_deferred = 1; schedule_delayed_work(&nl->deferred, 1); } } static void -plip_timer_bh(struct net_device *dev) +plip_timer_bh(struct work_struct *work) { - struct net_local *nl = netdev_priv(dev); + struct net_local *nl = + container_of(work, struct net_local, timer.work); if (!(atomic_read (&nl->kill_timer))) { - plip_interrupt (-1, dev); + plip_interrupt (-1, nl->dev); schedule_delayed_work(&nl->timer, 1); } @@ -1284,6 +1287,7 @@ static void plip_attach (struct parport *port) } nl = netdev_priv(dev); + nl->dev = dev; nl->pardev = parport_register_device(port, name, plip_preempt, plip_wakeup, plip_interrupt, 0, dev); diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index ec640f6229ae..d79d141a601d 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2008,7 +2008,7 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) "%s: Another function issued a reset to the " "chip. ISR value = %x.\n", ndev->name, value); } - queue_work(qdev->workqueue, &qdev->reset_work); + queue_delayed_work(qdev->workqueue, &qdev->reset_work, 0); spin_unlock(&qdev->adapter_lock); } else if (value & ISP_IMR_DISABLE_CMPL_INT) { ql_disable_interrupts(qdev); @@ -3182,11 +3182,13 @@ static void ql3xxx_tx_timeout(struct net_device *ndev) /* * Wake up the worker to process this event. */ - queue_work(qdev->workqueue, &qdev->tx_timeout_work); + queue_delayed_work(qdev->workqueue, &qdev->tx_timeout_work, 0); } -static void ql_reset_work(struct ql3_adapter *qdev) +static void ql_reset_work(struct work_struct *work) { + struct ql3_adapter *qdev = + container_of(work, struct ql3_adapter, reset_work.work); struct net_device *ndev = qdev->ndev; u32 value; struct ql_tx_buf_cb *tx_cb; @@ -3278,9 +3280,12 @@ static void ql_reset_work(struct ql3_adapter *qdev) } } -static void ql_tx_timeout_work(struct ql3_adapter *qdev) +static void ql_tx_timeout_work(struct work_struct *work) { - ql_cycle_adapter(qdev,QL_DO_RESET); + struct ql3_adapter *qdev = + container_of(work, struct ql3_adapter, tx_timeout_work.work); + + ql_cycle_adapter(qdev, QL_DO_RESET); } static void ql_get_board_info(struct ql3_adapter *qdev) @@ -3459,9 +3464,8 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, netif_stop_queue(ndev); qdev->workqueue = create_singlethread_workqueue(ndev->name); - INIT_WORK(&qdev->reset_work, (void (*)(void *))ql_reset_work, qdev); - INIT_WORK(&qdev->tx_timeout_work, - (void (*)(void *))ql_tx_timeout_work, qdev); + INIT_DELAYED_WORK(&qdev->reset_work, ql_reset_work); + INIT_DELAYED_WORK(&qdev->tx_timeout_work, ql_tx_timeout_work); init_timer(&qdev->adapter_timer); qdev->adapter_timer.function = ql3xxx_timer; diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h index 65da2c0bfda6..ea94de7fd071 100644 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -1186,8 +1186,8 @@ struct ql3_adapter { u32 numPorts; struct net_device_stats stats; struct workqueue_struct *workqueue; - struct work_struct reset_work; - struct work_struct tx_timeout_work; + struct delayed_work reset_work; + struct delayed_work tx_timeout_work; u32 max_frame_size; }; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 27f90b2139c0..1f9663a70823 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -424,6 +424,7 @@ struct ring_info { struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; /* Index of PCI device */ + struct net_device *dev; struct net_device_stats stats; /* statistics of net device */ spinlock_t lock; /* spin lock flag */ u32 msg_enable; @@ -455,7 +456,7 @@ struct rtl8169_private { void (*phy_reset_enable)(void __iomem *); unsigned int (*phy_reset_pending)(void __iomem *); unsigned int (*link_ok)(void __iomem *); - struct work_struct task; + struct delayed_work task; unsigned wol_enabled : 1; }; @@ -1492,6 +1493,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); + tp->dev = dev; tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); /* enable device (incl. PCI PM wakeup and hotplug setup) */ @@ -1764,7 +1766,7 @@ static int rtl8169_open(struct net_device *dev) if (retval < 0) goto err_free_rx; - INIT_WORK(&tp->task, NULL, dev); + INIT_DELAYED_WORK(&tp->task, NULL); rtl8169_hw_start(dev); @@ -2087,11 +2089,11 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp) tp->cur_tx = tp->dirty_tx = 0; } -static void rtl8169_schedule_work(struct net_device *dev, void (*task)(void *)) +static void rtl8169_schedule_work(struct net_device *dev, work_func_t task) { struct rtl8169_private *tp = netdev_priv(dev); - PREPARE_WORK(&tp->task, task, dev); + PREPARE_DELAYED_WORK(&tp->task, task); schedule_delayed_work(&tp->task, 4); } @@ -2110,9 +2112,11 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev) netif_poll_enable(dev); } -static void rtl8169_reinit_task(void *_data) +static void rtl8169_reinit_task(struct work_struct *work) { - struct net_device *dev = _data; + struct rtl8169_private *tp = + container_of(work, struct rtl8169_private, task.work); + struct net_device *dev = tp->dev; int ret; if (netif_running(dev)) { @@ -2135,10 +2139,11 @@ static void rtl8169_reinit_task(void *_data) } } -static void rtl8169_reset_task(void *_data) +static void rtl8169_reset_task(struct work_struct *work) { - struct net_device *dev = _data; - struct rtl8169_private *tp = netdev_priv(dev); + struct rtl8169_private *tp = + container_of(work, struct rtl8169_private, task.work); + struct net_device *dev = tp->dev; if (!netif_running(dev)) return; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 33569ec9dbfc..250cdbeefdfd 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5872,9 +5872,9 @@ static void s2io_tasklet(unsigned long dev_addr) * Description: Sets the link status for the adapter */ -static void s2io_set_link(unsigned long data) +static void s2io_set_link(struct work_struct *work) { - nic_t *nic = (nic_t *) data; + nic_t *nic = container_of(work, nic_t, set_link_task); struct net_device *dev = nic->dev; XENA_dev_config_t __iomem *bar0 = nic->bar0; register u64 val64; @@ -6379,10 +6379,10 @@ static int s2io_card_up(nic_t * sp) * spin lock. */ -static void s2io_restart_nic(unsigned long data) +static void s2io_restart_nic(struct work_struct *work) { - struct net_device *dev = (struct net_device *) data; - nic_t *sp = dev->priv; + nic_t *sp = container_of(work, nic_t, rst_timer_task); + struct net_device *dev = sp->dev; s2io_card_down(sp); if (s2io_card_up(sp)) { @@ -6992,10 +6992,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->tx_timeout = &s2io_tx_watchdog; dev->watchdog_timeo = WATCH_DOG_TIMEOUT; - INIT_WORK(&sp->rst_timer_task, - (void (*)(void *)) s2io_restart_nic, dev); - INIT_WORK(&sp->set_link_task, - (void (*)(void *)) s2io_set_link, sp); + INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); + INIT_WORK(&sp->set_link_task, s2io_set_link); pci_save_state(sp->pdev); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 12b719f4d00f..3b0bafd273c8 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -1000,7 +1000,7 @@ s2io_msix_fifo_handle(int irq, void *dev_id); static irqreturn_t s2io_isr(int irq, void *dev_id); static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); static const struct ethtool_ops netdev_ethtool_ops; -static void s2io_set_link(unsigned long data); +static void s2io_set_link(struct work_struct *work); static int s2io_set_swapper(nic_t * sp); static void s2io_card_down(nic_t *nic); static int s2io_card_up(nic_t *nic); diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index aaba458584fb..b70ed79d4121 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -280,6 +280,7 @@ enum sis190_feature { struct sis190_private { void __iomem *mmio_addr; struct pci_dev *pci_dev; + struct net_device *dev; struct net_device_stats stats; spinlock_t lock; u32 rx_buf_sz; @@ -897,10 +898,11 @@ static void sis190_hw_start(struct net_device *dev) netif_start_queue(dev); } -static void sis190_phy_task(void * data) +static void sis190_phy_task(struct work_struct *work) { - struct net_device *dev = data; - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = + container_of(work, struct sis190_private, phy_task); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->mmio_addr; int phy_id = tp->mii_if.phy_id; u16 val; @@ -1047,7 +1049,7 @@ static int sis190_open(struct net_device *dev) if (rc < 0) goto err_free_rx_1; - INIT_WORK(&tp->phy_task, sis190_phy_task, dev); + INIT_WORK(&tp->phy_task, sis190_phy_task); sis190_request_timer(dev); @@ -1436,6 +1438,7 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev) SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); + tp->dev = dev; tp->msg_enable = netif_msg_init(debug.msg_enable, SIS190_MSG_DEFAULT); rc = pci_enable_device(pdev); @@ -1798,7 +1801,7 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, sis190_init_rxfilter(dev); - INIT_WORK(&tp->phy_task, sis190_phy_task, dev); + INIT_WORK(&tp->phy_task, sis190_phy_task); dev->open = sis190_open; dev->stop = sis190_close; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index b2949035f66a..3b67614372a7 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -1327,10 +1327,11 @@ static void xm_check_link(struct net_device *dev) * Since internal PHY is wired to a level triggered pin, can't * get an interrupt when carrier is detected. */ -static void xm_link_timer(void *arg) +static void xm_link_timer(struct work_struct *work) { - struct net_device *dev = arg; - struct skge_port *skge = netdev_priv(arg); + struct skge_port *skge = + container_of(work, struct skge_port, link_thread.work); + struct net_device *dev = skge->netdev; struct skge_hw *hw = skge->hw; int port = skge->port; @@ -3072,9 +3073,9 @@ static void skge_error_irq(struct skge_hw *hw) * because accessing phy registers requires spin wait which might * cause excess interrupt latency. */ -static void skge_extirq(void *arg) +static void skge_extirq(struct work_struct *work) { - struct skge_hw *hw = arg; + struct skge_hw *hw = container_of(work, struct skge_hw, phy_work); int port; mutex_lock(&hw->phy_mutex); @@ -3456,7 +3457,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, skge->port = port; /* Only used for Genesis XMAC */ - INIT_WORK(&skge->link_thread, xm_link_timer, dev); + INIT_DELAYED_WORK(&skge->link_thread, xm_link_timer); if (hw->chip_id != CHIP_ID_GENESIS) { dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; @@ -3543,7 +3544,7 @@ static int __devinit skge_probe(struct pci_dev *pdev, hw->pdev = pdev; mutex_init(&hw->phy_mutex); - INIT_WORK(&hw->phy_work, skge_extirq, hw); + INIT_WORK(&hw->phy_work, skge_extirq); spin_lock_init(&hw->hw_lock); hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 537c0aaa1db8..23e5275d920c 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2456,7 +2456,7 @@ struct skge_port { struct net_device_stats net_stats; - struct work_struct link_thread; + struct delayed_work link_thread; enum pause_control flow_control; enum pause_status flow_status; u8 rx_csum; diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 418138dd6c68..f88fcac0e46a 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1945,10 +1945,11 @@ spider_net_stop(struct net_device *netdev) * called as task when tx hangs, resets interface (if interface is up) */ static void -spider_net_tx_timeout_task(void *data) +spider_net_tx_timeout_task(struct work_struct *work) { - struct net_device *netdev = data; - struct spider_net_card *card = netdev_priv(netdev); + struct spider_net_card *card = + container_of(work, struct spider_net_card, tx_timeout_task); + struct net_device *netdev = card->netdev; if (!(netdev->flags & IFF_UP)) goto out; @@ -2122,7 +2123,7 @@ spider_net_alloc_card(void) card = netdev_priv(netdev); card->netdev = netdev; card->msg_enable = SPIDER_NET_DEFAULT_MSG; - INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task, netdev); + INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task); init_waitqueue_head(&card->waitq); atomic_set(&card->tx_timeout_task_counter, 0); diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 253e96e7ad20..004d651681ad 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2281,9 +2281,9 @@ static void gem_do_stop(struct net_device *dev, int wol) } } -static void gem_reset_task(void *data) +static void gem_reset_task(struct work_struct *work) { - struct gem *gp = (struct gem *) data; + struct gem *gp = container_of(work, struct gem, reset_task); mutex_lock(&gp->pm_mutex); @@ -3043,7 +3043,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gp->link_timer.function = gem_link_timer; gp->link_timer.data = (unsigned long) gp; - INIT_WORK(&gp->reset_task, gem_reset_task, gp); + INIT_WORK(&gp->reset_task, gem_reset_task); gp->lstate = link_down; gp->timer_ticks = 0; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c20bb998e0e5..d9123c9adc1e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3654,9 +3654,9 @@ static void tg3_poll_controller(struct net_device *dev) } #endif -static void tg3_reset_task(void *_data) +static void tg3_reset_task(struct work_struct *work) { - struct tg3 *tp = _data; + struct tg3 *tp = container_of(work, struct tg3, reset_task); unsigned int restart_timer; tg3_full_lock(tp, 0); @@ -11734,7 +11734,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, #endif spin_lock_init(&tp->lock); spin_lock_init(&tp->indirect_lock); - INIT_WORK(&tp->reset_task, tg3_reset_task, tp); + INIT_WORK(&tp->reset_task, tg3_reset_task); tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len); if (tp->regs == 0UL) { diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index e14f5a00f65a..f85f00251123 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -296,6 +296,7 @@ static void TLan_SetMulticastList( struct net_device *); static int TLan_ioctl( struct net_device *dev, struct ifreq *rq, int cmd); static int TLan_probe1( struct pci_dev *pdev, long ioaddr, int irq, int rev, const struct pci_device_id *ent); static void TLan_tx_timeout( struct net_device *dev); +static void TLan_tx_timeout_work(struct work_struct *work); static int tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent); static u32 TLan_HandleInvalid( struct net_device *, u16 ); @@ -562,6 +563,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, priv = netdev_priv(dev); priv->pciDev = pdev; + priv->dev = dev; /* Is this a PCI device? */ if (pdev) { @@ -634,7 +636,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, /* This will be used when we get an adapter error from * within our irq handler */ - INIT_WORK(&priv->tlan_tqueue, (void *)(void*)TLan_tx_timeout, dev); + INIT_WORK(&priv->tlan_tqueue, TLan_tx_timeout_work); spin_lock_init(&priv->lock); @@ -1040,6 +1042,25 @@ static void TLan_tx_timeout(struct net_device *dev) } + /*************************************************************** + * TLan_tx_timeout_work + * + * Returns: nothing + * + * Params: + * work work item of device which timed out + * + **************************************************************/ + +static void TLan_tx_timeout_work(struct work_struct *work) +{ + TLanPrivateInfo *priv = + container_of(work, TLanPrivateInfo, tlan_tqueue); + + TLan_tx_timeout(priv->dev); +} + + /*************************************************************** * TLan_StartTx diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index a44e2f2ef62a..41ce0b665937 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -170,6 +170,7 @@ typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE]; typedef struct tlan_private_tag { struct net_device *nextDevice; struct pci_dev *pciDev; + struct net_device *dev; void *dmaStorage; dma_addr_t dmaStorageDMA; unsigned int dmaSize; diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c index fa3a2bb105ad..942b839ccc5b 100644 --- a/drivers/net/tulip/21142.c +++ b/drivers/net/tulip/21142.c @@ -26,10 +26,11 @@ static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; /* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list of available transceivers. */ -void t21142_media_task(void *data) +void t21142_media_task(struct work_struct *work) { - struct net_device *dev = data; - struct tulip_private *tp = netdev_priv(dev); + struct tulip_private *tp = + container_of(work, struct tulip_private, media_work); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->base_addr; int csr12 = ioread32(ioaddr + CSR12); int next_tick = 60*HZ; diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c index 066e5d6bcbd8..df326fe1cc8f 100644 --- a/drivers/net/tulip/timer.c +++ b/drivers/net/tulip/timer.c @@ -18,10 +18,11 @@ #include "tulip.h" -void tulip_media_task(void *data) +void tulip_media_task(struct work_struct *work) { - struct net_device *dev = data; - struct tulip_private *tp = netdev_priv(dev); + struct tulip_private *tp = + container_of(work, struct tulip_private, media_work); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->base_addr; u32 csr12 = ioread32(ioaddr + CSR12); int next_tick = 2*HZ; diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index ad107f45c7b1..25f25da76917 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -44,7 +44,7 @@ struct tulip_chip_table { int valid_intrs; /* CSR7 interrupt enable settings */ int flags; void (*media_timer) (unsigned long); - void (*media_task) (void *); + work_func_t media_task; }; @@ -392,6 +392,7 @@ struct tulip_private { int csr12_shadow; int pad0; /* Used for 8-byte alignment */ struct work_struct media_work; + struct net_device *dev; }; @@ -406,7 +407,7 @@ struct eeprom_fixup { /* 21142.c */ extern u16 t21142_csr14[]; -void t21142_media_task(void *data); +void t21142_media_task(struct work_struct *work); void t21142_start_nway(struct net_device *dev); void t21142_lnk_change(struct net_device *dev, int csr5); @@ -444,7 +445,7 @@ void pnic_lnk_change(struct net_device *dev, int csr5); void pnic_timer(unsigned long data); /* timer.c */ -void tulip_media_task(void *data); +void tulip_media_task(struct work_struct *work); void mxic_timer(unsigned long data); void comet_timer(unsigned long data); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 0aee618f883c..5a35354aa523 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1367,6 +1367,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, * it is zeroed and aligned in alloc_etherdev */ tp = netdev_priv(dev); + tp->dev = dev; tp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct tulip_rx_desc) * RX_RING_SIZE + @@ -1389,7 +1390,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, tp->timer.data = (unsigned long)dev; tp->timer.function = tulip_tbl[tp->chip_id].media_timer; - INIT_WORK(&tp->media_work, tulip_tbl[tp->chip_id].media_task, dev); + INIT_WORK(&tp->media_work, tulip_tbl[tp->chip_id].media_task); dev->base_addr = (unsigned long)ioaddr; diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index 931cbdf6d791..b2a23aed4428 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -125,8 +125,8 @@ static int cpc_tty_write_room(struct tty_struct *tty); static int cpc_tty_chars_in_buffer(struct tty_struct *tty); static void cpc_tty_flush_buffer(struct tty_struct *tty); static void cpc_tty_hangup(struct tty_struct *tty); -static void cpc_tty_rx_work(void *data); -static void cpc_tty_tx_work(void *data); +static void cpc_tty_rx_work(struct work_struct *work); +static void cpc_tty_tx_work(struct work_struct *work); static int cpc_tty_send_to_card(pc300dev_t *dev,void *buf, int len); static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx); static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char); @@ -261,8 +261,8 @@ void cpc_tty_init(pc300dev_t *pc300dev) cpc_tty->tty_minor = port + CPC_TTY_MINOR_START; cpc_tty->pc300dev = pc300dev; - INIT_WORK(&cpc_tty->tty_tx_work, cpc_tty_tx_work, (void *)cpc_tty); - INIT_WORK(&cpc_tty->tty_rx_work, cpc_tty_rx_work, (void *)port); + INIT_WORK(&cpc_tty->tty_tx_work, cpc_tty_tx_work); + INIT_WORK(&cpc_tty->tty_rx_work, cpc_tty_rx_work); cpc_tty->buf_rx.first = cpc_tty->buf_rx.last = NULL; @@ -659,21 +659,23 @@ static void cpc_tty_hangup(struct tty_struct *tty) * o call the line disc. read * o free memory */ -static void cpc_tty_rx_work(void * data) +static void cpc_tty_rx_work(struct work_struct *work) { + st_cpc_tty_area *cpc_tty; unsigned long port; int i, j; - st_cpc_tty_area *cpc_tty; volatile st_cpc_rx_buf *buf; char flags=0,flg_rx=1; struct tty_ldisc *ld; if (cpc_tty_cnt == 0) return; - for (i=0; (i < 4) && flg_rx ; i++) { flg_rx = 0; - port = (unsigned long)data; + + cpc_tty = container_of(work, st_cpc_tty_area, tty_rx_work); + port = cpc_tty - cpc_tty_area; + for (j=0; j < CPC_TTY_NPORTS; j++) { cpc_tty = &cpc_tty_area[port]; @@ -882,9 +884,10 @@ void cpc_tty_receive(pc300dev_t *pc300dev) * o if need call line discipline wakeup * o call wake_up_interruptible */ -static void cpc_tty_tx_work(void *data) +static void cpc_tty_tx_work(struct work_struct *work) { - st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *) data; + st_cpc_tty_area *cpc_tty = + container_of(work, st_cpc_tty_area, tty_tx_work); struct tty_struct *tty; CPC_TTY_DBG("%s: cpc_tty_tx_work init\n",cpc_tty->name); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index d6a8bf09878e..fbc0c087f53c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -787,7 +787,7 @@ struct bcm43xx_private { struct tasklet_struct isr_tasklet; /* Periodic tasks */ - struct work_struct periodic_work; + struct delayed_work periodic_work; unsigned int periodic_state; struct work_struct restart_work; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index a1b783813d8e..728a9b789fdf 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3177,9 +3177,10 @@ static int estimate_periodic_work_badness(unsigned int state) return badness; } -static void bcm43xx_periodic_work_handler(void *d) +static void bcm43xx_periodic_work_handler(struct work_struct *work) { - struct bcm43xx_private *bcm = d; + struct bcm43xx_private *bcm = + container_of(work, struct bcm43xx_private, periodic_work.work); struct net_device *net_dev = bcm->net_dev; unsigned long flags; u32 savedirqs = 0; @@ -3242,11 +3243,11 @@ void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) { - struct work_struct *work = &(bcm->periodic_work); + struct delayed_work *work = &bcm->periodic_work; assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); - INIT_WORK(work, bcm43xx_periodic_work_handler, bcm); - schedule_work(work); + INIT_DELAYED_WORK(work, bcm43xx_periodic_work_handler); + schedule_delayed_work(work, 0); } static void bcm43xx_security_init(struct bcm43xx_private *bcm) @@ -3598,7 +3599,7 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) bcm43xx_periodic_tasks_setup(bcm); /*FIXME: This should be handled by softmac instead. */ - schedule_work(&bcm->softmac->associnfo.work); + schedule_delayed_work(&bcm->softmac->associnfo.work, 0); out: mutex_unlock(&(bcm)->mutex); @@ -4149,9 +4150,10 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) /* Hard-reset the chip. Do not call this directly. * Use bcm43xx_controller_restart() */ -static void bcm43xx_chip_reset(void *_bcm) +static void bcm43xx_chip_reset(struct work_struct *work) { - struct bcm43xx_private *bcm = _bcm; + struct bcm43xx_private *bcm = + container_of(work, struct bcm43xx_private, restart_work); struct bcm43xx_phyinfo *phy; int err = -ENODEV; @@ -4178,7 +4180,7 @@ void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) return; printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); - INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); + INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset); schedule_work(&bcm->restart_work); } diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index e663518bd570..e89c890d16fd 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -35,7 +35,7 @@ int hostap_80211_get_hdrlen(u16 fc); struct net_device_stats *hostap_get_stats(struct net_device *dev); void hostap_setup_dev(struct net_device *dev, local_info_t *local, int main_dev); -void hostap_set_multicast_list_queue(void *data); +void hostap_set_multicast_list_queue(struct work_struct *work); int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked); void hostap_cleanup(local_info_t *local); diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index ba13125024cb..08bc57a4b895 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -49,10 +49,10 @@ MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs " static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta); static void hostap_event_expired_sta(struct net_device *dev, struct sta_info *sta); -static void handle_add_proc_queue(void *data); +static void handle_add_proc_queue(struct work_struct *work); #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -static void handle_wds_oper_queue(void *data); +static void handle_wds_oper_queue(struct work_struct *work); static void prism2_send_mgmt(struct net_device *dev, u16 type_subtype, char *body, int body_len, u8 *addr, u16 tx_cb_idx); @@ -807,7 +807,7 @@ void hostap_init_data(local_info_t *local) INIT_LIST_HEAD(&ap->sta_list); /* Initialize task queue structure for AP management */ - INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap); + INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue); ap->tx_callback_idx = hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); @@ -815,7 +815,7 @@ void hostap_init_data(local_info_t *local) printk(KERN_WARNING "%s: failed to register TX callback for " "AP\n", local->dev->name); #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue, local); + INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue); ap->tx_callback_auth = hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); @@ -1062,9 +1062,10 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, } -static void handle_add_proc_queue(void *data) +static void handle_add_proc_queue(struct work_struct *work) { - struct ap_data *ap = (struct ap_data *) data; + struct ap_data *ap = container_of(work, struct ap_data, + add_sta_proc_queue); struct sta_info *sta; char name[20]; struct add_sta_proc_data *entry, *prev; @@ -1952,9 +1953,11 @@ static void handle_pspoll(local_info_t *local, #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -static void handle_wds_oper_queue(void *data) +static void handle_wds_oper_queue(struct work_struct *work) { - local_info_t *local = data; + struct ap_data *ap = container_of(work, struct ap_data, + wds_oper_queue); + local_info_t *local = ap->local; struct wds_oper_data *entry, *prev; spin_lock_bh(&local->lock); diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index ed00ebb6e7f4..c19e68636a1c 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -1645,9 +1645,9 @@ static void prism2_schedule_reset(local_info_t *local) /* Called only as scheduled task after noticing card timeout in interrupt * context */ -static void handle_reset_queue(void *data) +static void handle_reset_queue(struct work_struct *work) { - local_info_t *local = (local_info_t *) data; + local_info_t *local = container_of(work, local_info_t, reset_queue); printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); prism2_hw_reset(local->dev); @@ -2896,9 +2896,10 @@ static void hostap_passive_scan(unsigned long data) /* Called only as a scheduled task when communications quality values should * be updated. */ -static void handle_comms_qual_update(void *data) +static void handle_comms_qual_update(struct work_struct *work) { - local_info_t *local = data; + local_info_t *local = + container_of(work, local_info_t, comms_qual_update); prism2_update_comms_qual(local->dev); } @@ -3050,9 +3051,9 @@ static int prism2_set_tim(struct net_device *dev, int aid, int set) } -static void handle_set_tim_queue(void *data) +static void handle_set_tim_queue(struct work_struct *work) { - local_info_t *local = (local_info_t *) data; + local_info_t *local = container_of(work, local_info_t, set_tim_queue); struct set_tim_data *entry; u16 val; @@ -3209,15 +3210,15 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, local->scan_channel_mask = 0xffff; /* Initialize task queue structures */ - INIT_WORK(&local->reset_queue, handle_reset_queue, local); + INIT_WORK(&local->reset_queue, handle_reset_queue); INIT_WORK(&local->set_multicast_list_queue, - hostap_set_multicast_list_queue, local->dev); + hostap_set_multicast_list_queue); - INIT_WORK(&local->set_tim_queue, handle_set_tim_queue, local); + INIT_WORK(&local->set_tim_queue, handle_set_tim_queue); INIT_LIST_HEAD(&local->set_tim_list); spin_lock_init(&local->set_tim_lock); - INIT_WORK(&local->comms_qual_update, handle_comms_qual_update, local); + INIT_WORK(&local->comms_qual_update, handle_comms_qual_update); /* Initialize tasklets for handling hardware IRQ related operations * outside hw IRQ handler */ diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 50f72d831cf4..5fd2b1ad7f5e 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -474,9 +474,9 @@ static void handle_info_queue_scanresults(local_info_t *local) /* Called only as scheduled task after receiving info frames (used to avoid * pending too much time in HW IRQ handler). */ -static void handle_info_queue(void *data) +static void handle_info_queue(struct work_struct *work) { - local_info_t *local = (local_info_t *) data; + local_info_t *local = container_of(work, local_info_t, info_queue); if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info)) @@ -493,7 +493,7 @@ void hostap_info_init(local_info_t *local) { skb_queue_head_init(&local->info_list); #ifndef PRISM2_NO_STATION_MODES - INIT_WORK(&local->info_queue, handle_info_queue, local); + INIT_WORK(&local->info_queue, handle_info_queue); #endif /* PRISM2_NO_STATION_MODES */ } diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 53374fcba77e..0796be9d9e77 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -767,14 +767,14 @@ static int prism2_set_mac_address(struct net_device *dev, void *p) /* TODO: to be further implemented as soon as Prism2 fully supports * GroupAddresses and correct documentation is available */ -void hostap_set_multicast_list_queue(void *data) +void hostap_set_multicast_list_queue(struct work_struct *work) { - struct net_device *dev = (struct net_device *) data; + local_info_t *local = + container_of(work, local_info_t, set_multicast_list_queue); + struct net_device *dev = local->dev; struct hostap_interface *iface; - local_info_t *local; iface = netdev_priv(dev); - local = iface->local; if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, local->is_promisc)) { printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 4e4eaa2a99ca..0f554373a60d 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -316,7 +316,7 @@ static void ipw2100_release_firmware(struct ipw2100_priv *priv, struct ipw2100_fw *fw); static int ipw2100_ucode_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw); -static void ipw2100_wx_event_work(struct ipw2100_priv *priv); +static void ipw2100_wx_event_work(struct work_struct *work); static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev); static struct iw_handler_def ipw2100_wx_handler_def; @@ -679,7 +679,8 @@ static void schedule_reset(struct ipw2100_priv *priv) queue_delayed_work(priv->workqueue, &priv->reset_work, priv->reset_backoff * HZ); else - queue_work(priv->workqueue, &priv->reset_work); + queue_delayed_work(priv->workqueue, &priv->reset_work, + 0); if (priv->reset_backoff < MAX_RESET_BACKOFF) priv->reset_backoff++; @@ -1873,8 +1874,10 @@ static void ipw2100_down(struct ipw2100_priv *priv) netif_stop_queue(priv->net_dev); } -static void ipw2100_reset_adapter(struct ipw2100_priv *priv) +static void ipw2100_reset_adapter(struct work_struct *work) { + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, reset_work.work); unsigned long flags; union iwreq_data wrqu = { .ap_addr = { @@ -2071,9 +2074,9 @@ static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) return; if (priv->status & STATUS_SECURITY_UPDATED) - queue_work(priv->workqueue, &priv->security_work); + queue_delayed_work(priv->workqueue, &priv->security_work, 0); - queue_work(priv->workqueue, &priv->wx_event_work); + queue_delayed_work(priv->workqueue, &priv->wx_event_work, 0); } static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status) @@ -5524,8 +5527,11 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) return err; } -static void ipw2100_security_work(struct ipw2100_priv *priv) +static void ipw2100_security_work(struct work_struct *work) { + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, security_work.work); + /* If we happen to have reconnected before we get a chance to * process this, then update the security settings--which causes * a disassociation to occur */ @@ -5748,7 +5754,7 @@ static int ipw2100_set_address(struct net_device *dev, void *p) priv->reset_backoff = 0; mutex_unlock(&priv->action_mutex); - ipw2100_reset_adapter(priv); + ipw2100_reset_adapter(&priv->reset_work.work); return 0; done: @@ -5923,9 +5929,10 @@ static const struct ethtool_ops ipw2100_ethtool_ops = { .get_drvinfo = ipw_ethtool_get_drvinfo, }; -static void ipw2100_hang_check(void *adapter) +static void ipw2100_hang_check(struct work_struct *work) { - struct ipw2100_priv *priv = adapter; + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, hang_check.work); unsigned long flags; u32 rtc = 0xa5a5a5a5; u32 len = sizeof(rtc); @@ -5965,9 +5972,10 @@ static void ipw2100_hang_check(void *adapter) spin_unlock_irqrestore(&priv->low_lock, flags); } -static void ipw2100_rf_kill(void *adapter) +static void ipw2100_rf_kill(struct work_struct *work) { - struct ipw2100_priv *priv = adapter; + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, rf_kill.work); unsigned long flags; spin_lock_irqsave(&priv->low_lock, flags); @@ -6117,14 +6125,11 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, priv->workqueue = create_workqueue(DRV_NAME); - INIT_WORK(&priv->reset_work, - (void (*)(void *))ipw2100_reset_adapter, priv); - INIT_WORK(&priv->security_work, - (void (*)(void *))ipw2100_security_work, priv); - INIT_WORK(&priv->wx_event_work, - (void (*)(void *))ipw2100_wx_event_work, priv); - INIT_WORK(&priv->hang_check, ipw2100_hang_check, priv); - INIT_WORK(&priv->rf_kill, ipw2100_rf_kill, priv); + INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter); + INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work); + INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work); + INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check); + INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill); tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) ipw2100_irq_tasklet, (unsigned long)priv); @@ -8290,8 +8295,10 @@ static struct iw_handler_def ipw2100_wx_handler_def = { .get_wireless_stats = ipw2100_wx_wireless_stats, }; -static void ipw2100_wx_event_work(struct ipw2100_priv *priv) +static void ipw2100_wx_event_work(struct work_struct *work) { + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, wx_event_work.work); union iwreq_data wrqu; int len = ETH_ALEN; diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 55b7227198df..de7d384d38af 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -583,11 +583,11 @@ struct ipw2100_priv { struct tasklet_struct irq_tasklet; struct workqueue_struct *workqueue; - struct work_struct reset_work; - struct work_struct security_work; - struct work_struct wx_event_work; - struct work_struct hang_check; - struct work_struct rf_kill; + struct delayed_work reset_work; + struct delayed_work security_work; + struct delayed_work wx_event_work; + struct delayed_work hang_check; + struct delayed_work rf_kill; u32 interrupts; int tx_interrupts; diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 1f742814a01c..587a0918fa52 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -187,9 +187,9 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *); static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *); static void ipw_rx_queue_replenish(void *); static int ipw_up(struct ipw_priv *); -static void ipw_bg_up(void *); +static void ipw_bg_up(struct work_struct *work); static void ipw_down(struct ipw_priv *); -static void ipw_bg_down(void *); +static void ipw_bg_down(struct work_struct *work); static int ipw_config(struct ipw_priv *); static int init_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *prates); @@ -862,11 +862,12 @@ static void ipw_led_link_on(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_led_link_on(void *data) +static void ipw_bg_led_link_on(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_link_on.work); mutex_lock(&priv->mutex); - ipw_led_link_on(data); + ipw_led_link_on(priv); mutex_unlock(&priv->mutex); } @@ -906,11 +907,12 @@ static void ipw_led_link_off(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_led_link_off(void *data) +static void ipw_bg_led_link_off(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_link_off.work); mutex_lock(&priv->mutex); - ipw_led_link_off(data); + ipw_led_link_off(priv); mutex_unlock(&priv->mutex); } @@ -985,11 +987,12 @@ static void ipw_led_activity_off(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_led_activity_off(void *data) +static void ipw_bg_led_activity_off(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_act_off.work); mutex_lock(&priv->mutex); - ipw_led_activity_off(data); + ipw_led_activity_off(priv); mutex_unlock(&priv->mutex); } @@ -2228,11 +2231,12 @@ static void ipw_adapter_restart(void *adapter) } } -static void ipw_bg_adapter_restart(void *data) +static void ipw_bg_adapter_restart(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, adapter_restart); mutex_lock(&priv->mutex); - ipw_adapter_restart(data); + ipw_adapter_restart(priv); mutex_unlock(&priv->mutex); } @@ -2249,11 +2253,12 @@ static void ipw_scan_check(void *data) } } -static void ipw_bg_scan_check(void *data) +static void ipw_bg_scan_check(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, scan_check.work); mutex_lock(&priv->mutex); - ipw_scan_check(data); + ipw_scan_check(priv); mutex_unlock(&priv->mutex); } @@ -3831,17 +3836,19 @@ static int ipw_disassociate(void *data) return 1; } -static void ipw_bg_disassociate(void *data) +static void ipw_bg_disassociate(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, disassociate); mutex_lock(&priv->mutex); - ipw_disassociate(data); + ipw_disassociate(priv); mutex_unlock(&priv->mutex); } -static void ipw_system_config(void *data) +static void ipw_system_config(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, system_config); #ifdef CONFIG_IPW2200_PROMISCUOUS if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) { @@ -4208,11 +4215,12 @@ static void ipw_gather_stats(struct ipw_priv *priv) IPW_STATS_INTERVAL); } -static void ipw_bg_gather_stats(void *data) +static void ipw_bg_gather_stats(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, gather_stats.work); mutex_lock(&priv->mutex); - ipw_gather_stats(data); + ipw_gather_stats(priv); mutex_unlock(&priv->mutex); } @@ -4268,8 +4276,8 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, if (!(priv->status & STATUS_ROAMING)) { priv->status |= STATUS_ROAMING; if (!(priv->status & STATUS_SCANNING)) - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); } return; } @@ -4607,8 +4615,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { priv->status |= STATUS_SCAN_FORCED; - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); break; } priv->status &= ~STATUS_SCAN_FORCED; @@ -4631,8 +4639,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, /* Don't schedule if we aborted the scan */ priv->status &= ~STATUS_ROAMING; } else if (priv->status & STATUS_SCAN_PENDING) - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); else if (priv->config & CFG_BACKGROUND_SCAN && priv->status & STATUS_ASSOCIATED) queue_delayed_work(priv->workqueue, @@ -5055,11 +5063,12 @@ static void ipw_rx_queue_replenish(void *data) ipw_rx_queue_restock(priv); } -static void ipw_bg_rx_queue_replenish(void *data) +static void ipw_bg_rx_queue_replenish(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, rx_replenish); mutex_lock(&priv->mutex); - ipw_rx_queue_replenish(data); + ipw_rx_queue_replenish(priv); mutex_unlock(&priv->mutex); } @@ -5489,9 +5498,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, return 1; } -static void ipw_merge_adhoc_network(void *data) +static void ipw_merge_adhoc_network(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, merge_networks); struct ieee80211_network *network = NULL; struct ipw_network_match match = { .network = priv->assoc_network @@ -5948,11 +5958,12 @@ static void ipw_adhoc_check(void *data) priv->assoc_request.beacon_interval); } -static void ipw_bg_adhoc_check(void *data) +static void ipw_bg_adhoc_check(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, adhoc_check.work); mutex_lock(&priv->mutex); - ipw_adhoc_check(data); + ipw_adhoc_check(priv); mutex_unlock(&priv->mutex); } @@ -6299,19 +6310,26 @@ done: return err; } -static int ipw_request_passive_scan(struct ipw_priv *priv) { - return ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE); +static void ipw_request_passive_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_passive_scan); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE); } -static int ipw_request_scan(struct ipw_priv *priv) { - return ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE); +static void ipw_request_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_scan.work); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE); } -static void ipw_bg_abort_scan(void *data) +static void ipw_bg_abort_scan(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, abort_scan); mutex_lock(&priv->mutex); - ipw_abort_scan(data); + ipw_abort_scan(priv); mutex_unlock(&priv->mutex); } @@ -7084,9 +7102,10 @@ static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, /* * background support to run QoS activate functionality */ -static void ipw_bg_qos_activate(void *data) +static void ipw_bg_qos_activate(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, qos_activate); if (priv == NULL) return; @@ -7394,11 +7413,12 @@ static void ipw_roam(void *data) priv->status &= ~STATUS_ROAMING; } -static void ipw_bg_roam(void *data) +static void ipw_bg_roam(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, roam); mutex_lock(&priv->mutex); - ipw_roam(data); + ipw_roam(priv); mutex_unlock(&priv->mutex); } @@ -7479,8 +7499,8 @@ static int ipw_associate(void *data) &priv->request_scan, SCAN_INTERVAL); else - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); } return 0; @@ -7491,11 +7511,12 @@ static int ipw_associate(void *data) return 1; } -static void ipw_bg_associate(void *data) +static void ipw_bg_associate(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, associate); mutex_lock(&priv->mutex); - ipw_associate(data); + ipw_associate(priv); mutex_unlock(&priv->mutex); } @@ -9410,7 +9431,7 @@ static int ipw_wx_set_scan(struct net_device *dev, IPW_DEBUG_WX("Start scan\n"); - queue_work(priv->workqueue, &priv->request_scan); + queue_delayed_work(priv->workqueue, &priv->request_scan, 0); return 0; } @@ -10547,11 +10568,12 @@ static void ipw_rf_kill(void *adapter) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_rf_kill(void *data) +static void ipw_bg_rf_kill(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, rf_kill.work); mutex_lock(&priv->mutex); - ipw_rf_kill(data); + ipw_rf_kill(priv); mutex_unlock(&priv->mutex); } @@ -10582,11 +10604,12 @@ static void ipw_link_up(struct ipw_priv *priv) queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); } -static void ipw_bg_link_up(void *data) +static void ipw_bg_link_up(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, link_up); mutex_lock(&priv->mutex); - ipw_link_up(data); + ipw_link_up(priv); mutex_unlock(&priv->mutex); } @@ -10606,15 +10629,16 @@ static void ipw_link_down(struct ipw_priv *priv) if (!(priv->status & STATUS_EXIT_PENDING)) { /* Queue up another scan... */ - queue_work(priv->workqueue, &priv->request_scan); + queue_delayed_work(priv->workqueue, &priv->request_scan, 0); } } -static void ipw_bg_link_down(void *data) +static void ipw_bg_link_down(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, link_down); mutex_lock(&priv->mutex); - ipw_link_down(data); + ipw_link_down(priv); mutex_unlock(&priv->mutex); } @@ -10626,38 +10650,30 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) init_waitqueue_head(&priv->wait_command_queue); init_waitqueue_head(&priv->wait_state); - INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv); - INIT_WORK(&priv->associate, ipw_bg_associate, priv); - INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv); - INIT_WORK(&priv->system_config, ipw_system_config, priv); - INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv); - INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv); - INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv); - INIT_WORK(&priv->up, (void (*)(void *))ipw_bg_up, priv); - INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv); - INIT_WORK(&priv->request_scan, - (void (*)(void *))ipw_request_scan, priv); - INIT_WORK(&priv->request_passive_scan, - (void (*)(void *))ipw_request_passive_scan, priv); - INIT_WORK(&priv->gather_stats, - (void (*)(void *))ipw_bg_gather_stats, priv); - INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv); - INIT_WORK(&priv->roam, ipw_bg_roam, priv); - INIT_WORK(&priv->scan_check, ipw_bg_scan_check, priv); - INIT_WORK(&priv->link_up, (void (*)(void *))ipw_bg_link_up, priv); - INIT_WORK(&priv->link_down, (void (*)(void *))ipw_bg_link_down, priv); - INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_bg_led_link_on, - priv); - INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_bg_led_link_off, - priv); - INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_bg_led_activity_off, - priv); - INIT_WORK(&priv->merge_networks, - (void (*)(void *))ipw_merge_adhoc_network, priv); + INIT_DELAYED_WORK(&priv->adhoc_check, ipw_bg_adhoc_check); + INIT_WORK(&priv->associate, ipw_bg_associate); + INIT_WORK(&priv->disassociate, ipw_bg_disassociate); + INIT_WORK(&priv->system_config, ipw_system_config); + INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish); + INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart); + INIT_DELAYED_WORK(&priv->rf_kill, ipw_bg_rf_kill); + INIT_WORK(&priv->up, ipw_bg_up); + INIT_WORK(&priv->down, ipw_bg_down); + INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan); + INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan); + INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats); + INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan); + INIT_WORK(&priv->roam, ipw_bg_roam); + INIT_DELAYED_WORK(&priv->scan_check, ipw_bg_scan_check); + INIT_WORK(&priv->link_up, ipw_bg_link_up); + INIT_WORK(&priv->link_down, ipw_bg_link_down); + INIT_DELAYED_WORK(&priv->led_link_on, ipw_bg_led_link_on); + INIT_DELAYED_WORK(&priv->led_link_off, ipw_bg_led_link_off); + INIT_DELAYED_WORK(&priv->led_act_off, ipw_bg_led_activity_off); + INIT_WORK(&priv->merge_networks, ipw_merge_adhoc_network); #ifdef CONFIG_IPW2200_QOS - INIT_WORK(&priv->qos_activate, (void (*)(void *))ipw_bg_qos_activate, - priv); + INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate); #endif /* CONFIG_IPW2200_QOS */ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) @@ -11190,7 +11206,8 @@ static int ipw_up(struct ipw_priv *priv) /* If configure to try and auto-associate, kick * off a scan. */ - queue_work(priv->workqueue, &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); return 0; } @@ -11211,11 +11228,12 @@ static int ipw_up(struct ipw_priv *priv) return -EIO; } -static void ipw_bg_up(void *data) +static void ipw_bg_up(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, up); mutex_lock(&priv->mutex); - ipw_up(data); + ipw_up(priv); mutex_unlock(&priv->mutex); } @@ -11282,11 +11300,12 @@ static void ipw_down(struct ipw_priv *priv) ipw_led_radio_off(priv); } -static void ipw_bg_down(void *data) +static void ipw_bg_down(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, down); mutex_lock(&priv->mutex); - ipw_down(data); + ipw_down(priv); mutex_unlock(&priv->mutex); } diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index dad5eedefbf1..626a240a87d8 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1290,21 +1290,21 @@ struct ipw_priv { struct workqueue_struct *workqueue; - struct work_struct adhoc_check; + struct delayed_work adhoc_check; struct work_struct associate; struct work_struct disassociate; struct work_struct system_config; struct work_struct rx_replenish; - struct work_struct request_scan; + struct delayed_work request_scan; struct work_struct request_passive_scan; struct work_struct adapter_restart; - struct work_struct rf_kill; + struct delayed_work rf_kill; struct work_struct up; struct work_struct down; - struct work_struct gather_stats; + struct delayed_work gather_stats; struct work_struct abort_scan; struct work_struct roam; - struct work_struct scan_check; + struct delayed_work scan_check; struct work_struct link_up; struct work_struct link_down; @@ -1319,9 +1319,9 @@ struct ipw_priv { u32 led_ofdm_on; u32 led_ofdm_off; - struct work_struct led_link_on; - struct work_struct led_link_off; - struct work_struct led_act_off; + struct delayed_work led_link_on; + struct delayed_work led_link_off; + struct delayed_work led_act_off; struct work_struct merge_networks; struct ipw_cmd_log *cmdlog; diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 336cabac13b3..936c888e03e1 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -980,9 +980,11 @@ static void print_linkstatus(struct net_device *dev, u16 status) } /* Search scan results for requested BSSID, join it if found */ -static void orinoco_join_ap(struct net_device *dev) +static void orinoco_join_ap(struct work_struct *work) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = + container_of(work, struct orinoco_private, join_work); + struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; int err; unsigned long flags; @@ -1055,9 +1057,11 @@ static void orinoco_join_ap(struct net_device *dev) } /* Send new BSSID to userspace */ -static void orinoco_send_wevents(struct net_device *dev) +static void orinoco_send_wevents(struct work_struct *work) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = + container_of(work, struct orinoco_private, wevent_work); + struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; union iwreq_data wrqu; int err; @@ -1864,9 +1868,11 @@ __orinoco_set_multicast_list(struct net_device *dev) /* This must be called from user context, without locks held - use * schedule_work() */ -static void orinoco_reset(struct net_device *dev) +static void orinoco_reset(struct work_struct *work) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = + container_of(work, struct orinoco_private, reset_work); + struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; int err; unsigned long flags; @@ -2434,9 +2440,9 @@ struct net_device *alloc_orinocodev(int sizeof_card, priv->hw_unavailable = 1; /* orinoco_init() must clear this * before anything else touches the * hardware */ - INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); - INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev); - INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev); + INIT_WORK(&priv->reset_work, orinoco_reset); + INIT_WORK(&priv->join_work, orinoco_join_ap); + INIT_WORK(&priv->wevent_work, orinoco_send_wevents); netif_carrier_off(dev); priv->last_linkstatus = 0xffff; @@ -3608,7 +3614,7 @@ static int orinoco_ioctl_reset(struct net_device *dev, printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); /* Firmware reset */ - orinoco_reset(dev); + orinoco_reset(&priv->reset_work); } else { printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); @@ -4154,7 +4160,7 @@ static int orinoco_ioctl_commit(struct net_device *dev, return 0; if (priv->broken_disableport) { - orinoco_reset(dev); + orinoco_reset(&priv->reset_work); return 0; } diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 286325ca3293..e7700b4257eb 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -158,8 +158,9 @@ prism54_mib_init(islpci_private *priv) * schedule_work(), thus we can as well use sleeping semaphore * locking */ void -prism54_update_stats(islpci_private *priv) +prism54_update_stats(struct work_struct *work) { + islpci_private *priv = container_of(work, islpci_private, stats_work); char *data; int j; struct obj_bss bss, *bss2; @@ -2494,9 +2495,10 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, * interrupt context, no locks held. */ void -prism54_process_trap(void *data) +prism54_process_trap(struct work_struct *work) { - struct islpci_mgmtframe *frame = data; + struct islpci_mgmtframe *frame = + container_of(work, struct islpci_mgmtframe, ws); struct net_device *ndev = frame->ndev; enum oid_num_t n = mgt_oidtonum(frame->header->oid); diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h index 65f33acd0a42..0802fa64996f 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.h +++ b/drivers/net/wireless/prism54/isl_ioctl.h @@ -32,12 +32,12 @@ void prism54_mib_init(islpci_private *); struct iw_statistics *prism54_get_wireless_stats(struct net_device *); -void prism54_update_stats(islpci_private *); +void prism54_update_stats(struct work_struct *); void prism54_acl_init(struct islpci_acl *); void prism54_acl_clean(struct islpci_acl *); -void prism54_process_trap(void *); +void prism54_process_trap(struct work_struct *); void prism54_wpa_bss_ie_init(islpci_private *priv); void prism54_wpa_bss_ie_clean(islpci_private *priv); diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index ec1c00f19eb3..e35fcb2543c4 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -861,11 +861,10 @@ islpci_setup(struct pci_dev *pdev) priv->state_off = 1; /* initialize workqueue's */ - INIT_WORK(&priv->stats_work, - (void (*)(void *)) prism54_update_stats, priv); + INIT_WORK(&priv->stats_work, prism54_update_stats); priv->stats_timestamp = 0; - INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake, priv); + INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake); priv->reset_task_pending = 0; /* allocate various memory areas */ diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index a8261d8454dd..103a37877733 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -482,9 +482,9 @@ islpci_eth_receive(islpci_private *priv) } void -islpci_do_reset_and_wake(void *data) +islpci_do_reset_and_wake(struct work_struct *work) { - islpci_private *priv = (islpci_private *) data; + islpci_private *priv = container_of(work, islpci_private, reset_task); islpci_reset(priv, 1); netif_wake_queue(priv->ndev); priv->reset_task_pending = 0; diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h index bc9d7a60b8d6..99d37eda9f01 100644 --- a/drivers/net/wireless/prism54/islpci_eth.h +++ b/drivers/net/wireless/prism54/islpci_eth.h @@ -68,6 +68,6 @@ void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); int islpci_eth_transmit(struct sk_buff *, struct net_device *); int islpci_eth_receive(islpci_private *); void islpci_eth_tx_timeout(struct net_device *); -void islpci_do_reset_and_wake(void *data); +void islpci_do_reset_and_wake(struct work_struct *); #endif /* _ISL_GEN_H */ diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c index 2e061a80b294..656ec9fa7128 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.c +++ b/drivers/net/wireless/prism54/islpci_mgt.c @@ -387,7 +387,7 @@ islpci_mgt_receive(struct net_device *ndev) /* Create work to handle trap out of interrupt * context. */ - INIT_WORK(&frame->ws, prism54_process_trap, frame); + INIT_WORK(&frame->ws, prism54_process_trap); schedule_work(&frame->ws); } else { diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index a7d29bddb298..5e4f4b707375 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -1090,9 +1090,10 @@ void zd_dump_rx_status(const struct rx_status *status) #define LINK_LED_WORK_DELAY HZ -static void link_led_handler(void *p) +static void link_led_handler(struct work_struct *work) { - struct zd_mac *mac = p; + struct zd_mac *mac = + container_of(work, struct zd_mac, housekeeping.link_led_work.work); struct zd_chip *chip = &mac->chip; struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev); int is_associated; @@ -1113,7 +1114,7 @@ static void link_led_handler(void *p) static void housekeeping_init(struct zd_mac *mac) { - INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac); + INIT_DELAYED_WORK(&mac->housekeeping.link_led_work, link_led_handler); } static void housekeeping_enable(struct zd_mac *mac) diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index b8ea3de7924a..7957cac3de25 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -121,7 +121,7 @@ enum mac_flags { }; struct housekeeping { - struct work_struct link_led_work; + struct delayed_work link_led_work; }; #define ZD_MAC_STATS_BUFFER_SIZE 16 diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index fc4bc9b94c74..a83c3db7d18f 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -29,7 +29,7 @@ struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned; -static void wq_sync_buffer(void *); +static void wq_sync_buffer(struct work_struct *work); #define DEFAULT_TIMER_EXPIRE (HZ / 10) static int work_enabled; @@ -65,7 +65,7 @@ int alloc_cpu_buffers(void) b->sample_received = 0; b->sample_lost_overflow = 0; b->cpu = i; - INIT_WORK(&b->work, wq_sync_buffer, b); + INIT_DELAYED_WORK(&b->work, wq_sync_buffer); } return 0; @@ -282,9 +282,10 @@ void oprofile_add_trace(unsigned long pc) * By using schedule_delayed_work_on and then schedule_delayed_work * we guarantee this will stay on the correct cpu */ -static void wq_sync_buffer(void * data) +static void wq_sync_buffer(struct work_struct *work) { - struct oprofile_cpu_buffer * b = data; + struct oprofile_cpu_buffer * b = + container_of(work, struct oprofile_cpu_buffer, work.work); if (b->cpu != smp_processor_id()) { printk("WQ on CPU%d, prefer CPU%d\n", smp_processor_id(), b->cpu); diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 09abb80e0570..49900d9e3235 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -43,7 +43,7 @@ struct oprofile_cpu_buffer { unsigned long sample_lost_overflow; unsigned long backtrace_aborted; int cpu; - struct work_struct work; + struct delayed_work work; } ____cacheline_aligned; extern struct oprofile_cpu_buffer cpu_buffer[]; diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index ea2087c34149..50757695844f 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -70,7 +70,7 @@ struct slot { struct hotplug_slot *hotplug_slot; struct list_head slot_list; char name[SLOT_NAME_SIZE]; - struct work_struct work; /* work for button event */ + struct delayed_work work; /* work for button event */ struct mutex lock; }; @@ -187,7 +187,7 @@ extern int shpchp_configure_device(struct slot *p_slot); extern int shpchp_unconfigure_device(struct slot *p_slot); extern void shpchp_remove_ctrl_files(struct controller *ctrl); extern void cleanup_slots(struct controller *ctrl); -extern void queue_pushbutton_work(void *data); +extern void queue_pushbutton_work(struct work_struct *work); #ifdef CONFIG_ACPI diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 235c18a22393..4eac85b3d90e 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -159,7 +159,7 @@ static int init_slots(struct controller *ctrl) goto error_info; slot->number = sun; - INIT_WORK(&slot->work, queue_pushbutton_work, slot); + INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work); /* register this slot with the hotplug pci core */ hotplug_slot->private = slot; diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index c39901dbff20..158ac7836096 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -36,7 +36,7 @@ #include "../pci.h" #include "shpchp.h" -static void interrupt_event_handler(void *data); +static void interrupt_event_handler(struct work_struct *work); static int shpchp_enable_slot(struct slot *p_slot); static int shpchp_disable_slot(struct slot *p_slot); @@ -50,7 +50,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) info->event_type = event_type; info->p_slot = p_slot; - INIT_WORK(&info->work, interrupt_event_handler, info); + INIT_WORK(&info->work, interrupt_event_handler); schedule_work(&info->work); @@ -408,9 +408,10 @@ struct pushbutton_work_info { * Handles all pending events and exits. * */ -static void shpchp_pushbutton_thread(void *data) +static void shpchp_pushbutton_thread(struct work_struct *work) { - struct pushbutton_work_info *info = data; + struct pushbutton_work_info *info = + container_of(work, struct pushbutton_work_info, work); struct slot *p_slot = info->p_slot; mutex_lock(&p_slot->lock); @@ -436,9 +437,9 @@ static void shpchp_pushbutton_thread(void *data) kfree(info); } -void queue_pushbutton_work(void *data) +void queue_pushbutton_work(struct work_struct *work) { - struct slot *p_slot = data; + struct slot *p_slot = container_of(work, struct slot, work.work); struct pushbutton_work_info *info; info = kmalloc(sizeof(*info), GFP_KERNEL); @@ -447,7 +448,7 @@ void queue_pushbutton_work(void *data) return; } info->p_slot = p_slot; - INIT_WORK(&info->work, shpchp_pushbutton_thread, info); + INIT_WORK(&info->work, shpchp_pushbutton_thread); mutex_lock(&p_slot->lock); switch (p_slot->state) { @@ -541,9 +542,9 @@ static void handle_button_press_event(struct slot *p_slot) } } -static void interrupt_event_handler(void *data) +static void interrupt_event_handler(struct work_struct *work) { - struct event_info *info = data; + struct event_info *info = container_of(work, struct event_info, work); struct slot *p_slot = info->p_slot; mutex_lock(&p_slot->lock); diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index a20d84d707d9..e469a46a388b 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -698,9 +698,10 @@ static int pcmcia_card_add(struct pcmcia_socket *s) } -static void pcmcia_delayed_add_pseudo_device(void *data) +static void pcmcia_delayed_add_pseudo_device(struct work_struct *work) { - struct pcmcia_socket *s = data; + struct pcmcia_socket *s = + container_of(work, struct pcmcia_socket, device_add); pcmcia_device_add(s, 0); s->pcmcia_state.device_add_pending = 0; } @@ -1246,7 +1247,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, init_waitqueue_head(&socket->queue); #endif INIT_LIST_HEAD(&socket->devices_list); - INIT_WORK(&socket->device_add, pcmcia_delayed_add_pseudo_device, socket); + INIT_WORK(&socket->device_add, pcmcia_delayed_add_pseudo_device); memset(&socket->pcmcia_state, 0, sizeof(u8)); socket->device_count = 0; diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 583789c66cdb..dcf5f86461f7 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -53,9 +53,10 @@ static int rtc_dev_open(struct inode *inode, struct file *file) * Routine to poll RTC seconds field for change as often as possible, * after first RTC_UIE use timer to reduce polling */ -static void rtc_uie_task(void *data) +static void rtc_uie_task(struct work_struct *work) { - struct rtc_device *rtc = data; + struct rtc_device *rtc = + container_of(work, struct rtc_device, uie_task); struct rtc_time tm; int num = 0; int err; @@ -398,7 +399,7 @@ static int rtc_dev_add_device(struct class_device *class_dev, spin_lock_init(&rtc->irq_lock); init_waitqueue_head(&rtc->irq_queue); #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL - INIT_WORK(&rtc->uie_task, rtc_uie_task, rtc); + INIT_WORK(&rtc->uie_task, rtc_uie_task); setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); #endif diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index a6aa91072880..bb3cb3360541 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -849,7 +849,7 @@ static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags) hostdata->issue_queue = NULL; hostdata->disconnected_queue = NULL; - INIT_WORK(&hostdata->coroutine, NCR5380_main, hostdata); + INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main); #ifdef NCR5380_STATS for (i = 0; i < 8; ++i) { @@ -1016,7 +1016,7 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) /* Run the coroutine if it isn't already running. */ /* Kick off command processing */ - schedule_work(&hostdata->coroutine); + schedule_delayed_work(&hostdata->coroutine, 0); return 0; } @@ -1033,9 +1033,10 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) * host lock and called routines may take the isa dma lock. */ -static void NCR5380_main(void *p) +static void NCR5380_main(struct work_struct *work) { - struct NCR5380_hostdata *hostdata = p; + struct NCR5380_hostdata *hostdata = + container_of(work, struct NCR5380_hostdata, coroutine.work); struct Scsi_Host *instance = hostdata->host; Scsi_Cmnd *tmp, *prev; int done; @@ -1221,7 +1222,7 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id) } /* if BASR_IRQ */ spin_unlock_irqrestore(instance->host_lock, flags); if(!done) - schedule_work(&hostdata->coroutine); + schedule_delayed_work(&hostdata->coroutine, 0); } while (!done); return IRQ_HANDLED; } diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 1bc73de496b0..713a108c02ef 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -271,7 +271,7 @@ struct NCR5380_hostdata { unsigned long time_expires; /* in jiffies, set prior to sleeping */ int select_time; /* timer in select for target response */ volatile Scsi_Cmnd *selecting; - struct work_struct coroutine; /* our co-routine */ + struct delayed_work coroutine; /* our co-routine */ #ifdef NCR5380_STATS unsigned timebase; /* Base for time calcs */ long time_read[8]; /* time to do reads */ @@ -298,7 +298,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance); #ifndef DONT_USE_INTR static irqreturn_t NCR5380_intr(int irq, void *dev_id); #endif -static void NCR5380_main(void *ptr); +static void NCR5380_main(struct work_struct *work); static void NCR5380_print_options(struct Scsi_Host *instance); #ifdef NDEBUG static void NCR5380_print_phase(struct Scsi_Host *instance); diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 306f46b85a55..0cec742d12e9 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -1443,7 +1443,7 @@ static struct work_struct aha152x_tq; * Run service completions on the card with interrupts enabled. * */ -static void run(void) +static void run(struct work_struct *work) { struct aha152x_hostdata *hd; @@ -1499,7 +1499,7 @@ static irqreturn_t intr(int irqno, void *dev_id) HOSTDATA(shpnt)->service=1; /* Poke the BH handler */ - INIT_WORK(&aha152x_tq, (void *) run, NULL); + INIT_WORK(&aha152x_tq, run); schedule_work(&aha152x_tq); } DO_UNLOCK(flags); diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index e31f6122106f..0464c182c577 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -36,7 +36,7 @@ typedef struct { int base_hi; /* Hi Base address for ECP-ISA chipset */ int mode; /* Transfer mode */ struct scsi_cmnd *cur_cmd; /* Current queued command */ - struct work_struct imm_tq; /* Polling interrupt stuff */ + struct delayed_work imm_tq; /* Polling interrupt stuff */ unsigned long jstart; /* Jiffies at start */ unsigned failed:1; /* Failure flag */ unsigned dp:1; /* Data phase present */ @@ -733,9 +733,9 @@ static int imm_completion(struct scsi_cmnd *cmd) * the scheduler's task queue to generate a stream of call-backs and * complete the request when the drive is ready. */ -static void imm_interrupt(void *data) +static void imm_interrupt(struct work_struct *work) { - imm_struct *dev = (imm_struct *) data; + imm_struct *dev = container_of(work, imm_struct, imm_tq.work); struct scsi_cmnd *cmd = dev->cur_cmd; struct Scsi_Host *host = cmd->device->host; unsigned long flags; @@ -745,7 +745,6 @@ static void imm_interrupt(void *data) return; } if (imm_engine(dev, cmd)) { - INIT_WORK(&dev->imm_tq, imm_interrupt, (void *) dev); schedule_delayed_work(&dev->imm_tq, 1); return; } @@ -953,8 +952,7 @@ static int imm_queuecommand(struct scsi_cmnd *cmd, cmd->result = DID_ERROR << 16; /* default return code */ cmd->SCp.phase = 0; /* bus free */ - INIT_WORK(&dev->imm_tq, imm_interrupt, dev); - schedule_work(&dev->imm_tq); + schedule_delayed_work(&dev->imm_tq, 0); imm_pb_claim(dev); @@ -1225,7 +1223,7 @@ static int __imm_attach(struct parport *pb) else ports = 8; - INIT_WORK(&dev->imm_tq, imm_interrupt, dev); + INIT_DELAYED_WORK(&dev->imm_tq, imm_interrupt); err = -ENOMEM; host = scsi_host_alloc(&imm_template, sizeof(imm_struct *)); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 2dde821025f3..d51c3e764bb0 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -2093,7 +2093,7 @@ static void ipr_release_dump(struct kref *kref) /** * ipr_worker_thread - Worker thread - * @data: ioa config struct + * @work: ioa config struct * * Called at task level from a work thread. This function takes care * of adding and removing device from the mid-layer as configuration @@ -2102,13 +2102,14 @@ static void ipr_release_dump(struct kref *kref) * Return value: * nothing **/ -static void ipr_worker_thread(void *data) +static void ipr_worker_thread(struct work_struct *work) { unsigned long lock_flags; struct ipr_resource_entry *res; struct scsi_device *sdev; struct ipr_dump *dump; - struct ipr_ioa_cfg *ioa_cfg = data; + struct ipr_ioa_cfg *ioa_cfg = + container_of(work, struct ipr_ioa_cfg, work_q); u8 bus, target, lun; int did_work; @@ -6926,7 +6927,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q); INIT_LIST_HEAD(&ioa_cfg->free_res_q); INIT_LIST_HEAD(&ioa_cfg->used_res_q); - INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread, ioa_cfg); + INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); init_waitqueue_head(&ioa_cfg->reset_wait_q); ioa_cfg->sdt_state = INACTIVE; if (ipr_enable_cache) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 5d8862189485..e11b23c641e2 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -719,9 +719,10 @@ again: return rc; } -static void iscsi_xmitworker(void *data) +static void iscsi_xmitworker(struct work_struct *work) { - struct iscsi_conn *conn = data; + struct iscsi_conn *conn = + container_of(work, struct iscsi_conn, xmitwork); int rc; /* * serialize Xmit worker on a per-connection basis. @@ -1512,7 +1513,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) if (conn->mgmtqueue == ERR_PTR(-ENOMEM)) goto mgmtqueue_alloc_fail; - INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn); + INIT_WORK(&conn->xmitwork, iscsi_xmitworker); /* allocate login_mtask used for the login/text sequences */ spin_lock_bh(&session->lock); diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index d977bd492d8d..fb7df7b75811 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -647,10 +647,12 @@ void sas_unregister_domain_devices(struct asd_sas_port *port) * Discover process only interrogates devices in order to discover the * domain. */ -static void sas_discover_domain(void *data) +static void sas_discover_domain(struct work_struct *work) { int error = 0; - struct asd_sas_port *port = data; + struct sas_discovery_event *ev = + container_of(work, struct sas_discovery_event, work); + struct asd_sas_port *port = ev->port; sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock, &port->disc.pending); @@ -692,10 +694,12 @@ static void sas_discover_domain(void *data) current->pid, error); } -static void sas_revalidate_domain(void *data) +static void sas_revalidate_domain(struct work_struct *work) { int res = 0; - struct asd_sas_port *port = data; + struct sas_discovery_event *ev = + container_of(work, struct sas_discovery_event, work); + struct asd_sas_port *port = ev->port; sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock, &port->disc.pending); @@ -722,7 +726,7 @@ int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) BUG_ON(ev >= DISC_NUM_EVENTS); sas_queue_event(ev, &disc->disc_event_lock, &disc->pending, - &disc->disc_work[ev], port->ha->core.shost); + &disc->disc_work[ev].work, port->ha->core.shost); return 0; } @@ -737,13 +741,15 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port) { int i; - static void (*sas_event_fns[DISC_NUM_EVENTS])(void *) = { + static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, }; spin_lock_init(&disc->disc_event_lock); disc->pending = 0; - for (i = 0; i < DISC_NUM_EVENTS; i++) - INIT_WORK(&disc->disc_work[i], sas_event_fns[i], port); + for (i = 0; i < DISC_NUM_EVENTS; i++) { + INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]); + disc->disc_work[i].port = port; + } } diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index 19110ed1c89c..d83392ee6823 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -31,7 +31,7 @@ static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event) BUG_ON(event >= HA_NUM_EVENTS); sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending, - &sas_ha->ha_events[event], sas_ha->core.shost); + &sas_ha->ha_events[event].work, sas_ha->core.shost); } static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) @@ -41,7 +41,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) BUG_ON(event >= PORT_NUM_EVENTS); sas_queue_event(event, &ha->event_lock, &phy->port_events_pending, - &phy->port_events[event], ha->core.shost); + &phy->port_events[event].work, ha->core.shost); } static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) @@ -51,12 +51,12 @@ static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) BUG_ON(event >= PHY_NUM_EVENTS); sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending, - &phy->phy_events[event], ha->core.shost); + &phy->phy_events[event].work, ha->core.shost); } int sas_init_events(struct sas_ha_struct *sas_ha) { - static void (*sas_ha_event_fns[HA_NUM_EVENTS])(void *) = { + static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = { [HAE_RESET] = sas_hae_reset, }; @@ -64,8 +64,10 @@ int sas_init_events(struct sas_ha_struct *sas_ha) spin_lock_init(&sas_ha->event_lock); - for (i = 0; i < HA_NUM_EVENTS; i++) - INIT_WORK(&sas_ha->ha_events[i], sas_ha_event_fns[i], sas_ha); + for (i = 0; i < HA_NUM_EVENTS; i++) { + INIT_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]); + sas_ha->ha_events[i].ha = sas_ha; + } sas_ha->notify_ha_event = notify_ha_event; sas_ha->notify_port_event = notify_port_event; diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index c836a237fb79..7b4e9169f44d 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -65,9 +65,11 @@ void sas_hash_addr(u8 *hashed, const u8 *sas_addr) /* ---------- HA events ---------- */ -void sas_hae_reset(void *data) +void sas_hae_reset(struct work_struct *work) { - struct sas_ha_struct *ha = data; + struct sas_ha_event *ev = + container_of(work, struct sas_ha_event, work); + struct sas_ha_struct *ha = ev->ha; sas_begin_event(HAE_RESET, &ha->event_lock, &ha->pending); diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index bffcee474921..137d7e496b6d 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -60,11 +60,11 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha); void sas_deform_port(struct asd_sas_phy *phy); -void sas_porte_bytes_dmaed(void *); -void sas_porte_broadcast_rcvd(void *); -void sas_porte_link_reset_err(void *); -void sas_porte_timer_event(void *); -void sas_porte_hard_reset(void *); +void sas_porte_bytes_dmaed(struct work_struct *work); +void sas_porte_broadcast_rcvd(struct work_struct *work); +void sas_porte_link_reset_err(struct work_struct *work); +void sas_porte_timer_event(struct work_struct *work); +void sas_porte_hard_reset(struct work_struct *work); int sas_notify_lldd_dev_found(struct domain_device *); void sas_notify_lldd_dev_gone(struct domain_device *); @@ -75,7 +75,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy); struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); -void sas_hae_reset(void *); +void sas_hae_reset(struct work_struct *work); static inline void sas_queue_event(int event, spinlock_t *lock, unsigned long *pending, diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c index 9340cdbae4a3..b459c4b635b1 100644 --- a/drivers/scsi/libsas/sas_phy.c +++ b/drivers/scsi/libsas/sas_phy.c @@ -30,9 +30,11 @@ /* ---------- Phy events ---------- */ -static void sas_phye_loss_of_signal(void *data) +static void sas_phye_loss_of_signal(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock, &phy->phy_events_pending); @@ -40,18 +42,22 @@ static void sas_phye_loss_of_signal(void *data) sas_deform_port(phy); } -static void sas_phye_oob_done(void *data) +static void sas_phye_oob_done(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock, &phy->phy_events_pending); phy->error = 0; } -static void sas_phye_oob_error(void *data) +static void sas_phye_oob_error(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; struct sas_ha_struct *sas_ha = phy->ha; struct asd_sas_port *port = phy->port; struct sas_internal *i = @@ -80,9 +86,11 @@ static void sas_phye_oob_error(void *data) } } -static void sas_phye_spinup_hold(void *data) +static void sas_phye_spinup_hold(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; struct sas_ha_struct *sas_ha = phy->ha; struct sas_internal *i = to_sas_internal(sas_ha->core.shost->transportt); @@ -100,14 +108,14 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) { int i; - static void (*sas_phy_event_fns[PHY_NUM_EVENTS])(void *) = { + static const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = { [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal, [PHYE_OOB_DONE] = sas_phye_oob_done, [PHYE_OOB_ERROR] = sas_phye_oob_error, [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold, }; - static void (*sas_port_event_fns[PORT_NUM_EVENTS])(void *) = { + static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = { [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed, [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd, [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err, @@ -122,13 +130,18 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) phy->error = 0; INIT_LIST_HEAD(&phy->port_phy_el); - for (k = 0; k < PORT_NUM_EVENTS; k++) - INIT_WORK(&phy->port_events[k], sas_port_event_fns[k], - phy); + for (k = 0; k < PORT_NUM_EVENTS; k++) { + INIT_WORK(&phy->port_events[k].work, + sas_port_event_fns[k]); + phy->port_events[k].phy = phy; + } + + for (k = 0; k < PHY_NUM_EVENTS; k++) { + INIT_WORK(&phy->phy_events[k].work, + sas_phy_event_fns[k]); + phy->phy_events[k].phy = phy; + } - for (k = 0; k < PHY_NUM_EVENTS; k++) - INIT_WORK(&phy->phy_events[k], sas_phy_event_fns[k], - phy); phy->port = NULL; phy->ha = sas_ha; spin_lock_init(&phy->frame_rcvd_lock); diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 253cdcf306a2..971c37ceecb4 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -181,9 +181,11 @@ void sas_deform_port(struct asd_sas_phy *phy) /* ---------- SAS port events ---------- */ -void sas_porte_bytes_dmaed(void *data) +void sas_porte_bytes_dmaed(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock, &phy->port_events_pending); @@ -191,11 +193,13 @@ void sas_porte_bytes_dmaed(void *data) sas_form_port(phy); } -void sas_porte_broadcast_rcvd(void *data) +void sas_porte_broadcast_rcvd(struct work_struct *work) { + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; unsigned long flags; u32 prim; - struct asd_sas_phy *phy = data; sas_begin_event(PORTE_BROADCAST_RCVD, &phy->ha->event_lock, &phy->port_events_pending); @@ -208,9 +212,11 @@ void sas_porte_broadcast_rcvd(void *data) sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN); } -void sas_porte_link_reset_err(void *data) +void sas_porte_link_reset_err(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock, &phy->port_events_pending); @@ -218,9 +224,11 @@ void sas_porte_link_reset_err(void *data) sas_deform_port(phy); } -void sas_porte_timer_event(void *data) +void sas_porte_timer_event(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock, &phy->port_events_pending); @@ -228,9 +236,11 @@ void sas_porte_timer_event(void *data) sas_deform_port(phy); } -void sas_porte_hard_reset(void *data) +void sas_porte_hard_reset(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock, &phy->port_events_pending); diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 89a2a9f11e41..584ba4d6e038 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -31,7 +31,7 @@ typedef struct { int base; /* Actual port address */ int mode; /* Transfer mode */ struct scsi_cmnd *cur_cmd; /* Current queued command */ - struct work_struct ppa_tq; /* Polling interrupt stuff */ + struct delayed_work ppa_tq; /* Polling interrupt stuff */ unsigned long jstart; /* Jiffies at start */ unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */ unsigned int failed:1; /* Failure flag */ @@ -627,9 +627,9 @@ static int ppa_completion(struct scsi_cmnd *cmd) * the scheduler's task queue to generate a stream of call-backs and * complete the request when the drive is ready. */ -static void ppa_interrupt(void *data) +static void ppa_interrupt(struct work_struct *work) { - ppa_struct *dev = (ppa_struct *) data; + ppa_struct *dev = container_of(work, ppa_struct, ppa_tq.work); struct scsi_cmnd *cmd = dev->cur_cmd; if (!cmd) { @@ -637,7 +637,6 @@ static void ppa_interrupt(void *data) return; } if (ppa_engine(dev, cmd)) { - dev->ppa_tq.data = (void *) dev; schedule_delayed_work(&dev->ppa_tq, 1); return; } @@ -822,8 +821,7 @@ static int ppa_queuecommand(struct scsi_cmnd *cmd, cmd->result = DID_ERROR << 16; /* default return code */ cmd->SCp.phase = 0; /* bus free */ - dev->ppa_tq.data = dev; - schedule_work(&dev->ppa_tq); + schedule_delayed_work(&dev->ppa_tq, 0); ppa_pb_claim(dev); @@ -1086,7 +1084,7 @@ static int __ppa_attach(struct parport *pb) else ports = 8; - INIT_WORK(&dev->ppa_tq, ppa_interrupt, dev); + INIT_DELAYED_WORK(&dev->ppa_tq, ppa_interrupt); err = -ENOMEM; host = scsi_host_alloc(&ppa_template, sizeof(ppa_struct *)); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 5b8db6109536..bbbc9d039baa 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1011,9 +1011,10 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, * the mid-level tries to sleep when it reaches the driver threshold * "host->can_queue". This can cause a panic if we were in our interrupt code. **/ -static void qla4xxx_do_dpc(void *data) +static void qla4xxx_do_dpc(struct work_struct *work) { - struct scsi_qla_host *ha = (struct scsi_qla_host *) data; + struct scsi_qla_host *ha = + container_of(work, struct scsi_qla_host, dpc_work); struct ddb_entry *ddb_entry, *dtemp; DEBUG2(printk("scsi%ld: %s: DPC handler waking up.\n", @@ -1315,7 +1316,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ret = -ENODEV; goto probe_failed; } - INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc, ha); + INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); ret = request_irq(pdev->irq, qla4xxx_intr_handler, SA_INTERRUPT|SA_SHIRQ, "qla4xxx", ha); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 38c215a78f69..3571ce8934e7 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -241,9 +241,9 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) #define FC_MGMTSRVR_PORTID 0x00000a -static void fc_timeout_deleted_rport(void *data); -static void fc_timeout_fail_rport_io(void *data); -static void fc_scsi_scan_rport(void *data); +static void fc_timeout_deleted_rport(struct work_struct *work); +static void fc_timeout_fail_rport_io(struct work_struct *work); +static void fc_scsi_scan_rport(struct work_struct *work); /* * Attribute counts pre object type... @@ -1613,7 +1613,7 @@ fc_flush_work(struct Scsi_Host *shost) * 1 on success / 0 already queued / < 0 for error **/ static int -fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work, +fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work, unsigned long delay) { if (unlikely(!fc_host_devloss_work_q(shost))) { @@ -1625,9 +1625,6 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work, return -EINVAL; } - if (delay == 0) - return queue_work(fc_host_devloss_work_q(shost), work); - return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay); } @@ -1712,12 +1709,13 @@ EXPORT_SYMBOL(fc_remove_host); * fc_starget_delete - called to delete the scsi decendents of an rport * (target and all sdevs) * - * @data: remote port to be operated on. + * @work: remote port to be operated on. **/ static void -fc_starget_delete(void *data) +fc_starget_delete(struct work_struct *work) { - struct fc_rport *rport = (struct fc_rport *)data; + struct fc_rport *rport = + container_of(work, struct fc_rport, stgt_delete_work); struct Scsi_Host *shost = rport_to_shost(rport); unsigned long flags; struct fc_internal *i = to_fc_internal(shost->transportt); @@ -1751,12 +1749,13 @@ fc_starget_delete(void *data) /** * fc_rport_final_delete - finish rport termination and delete it. * - * @data: remote port to be deleted. + * @work: remote port to be deleted. **/ static void -fc_rport_final_delete(void *data) +fc_rport_final_delete(struct work_struct *work) { - struct fc_rport *rport = (struct fc_rport *)data; + struct fc_rport *rport = + container_of(work, struct fc_rport, rport_delete_work); struct device *dev = &rport->dev; struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); @@ -1770,7 +1769,7 @@ fc_rport_final_delete(void *data) /* Delete SCSI target and sdevs */ if (rport->scsi_target_id != -1) - fc_starget_delete(data); + fc_starget_delete(&rport->stgt_delete_work); else if (i->f->dev_loss_tmo_callbk) i->f->dev_loss_tmo_callbk(rport); else if (i->f->terminate_rport_io) @@ -1829,11 +1828,11 @@ fc_rport_create(struct Scsi_Host *shost, int channel, rport->channel = channel; rport->fast_io_fail_tmo = -1; - INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport); - INIT_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io, rport); - INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); - INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport); - INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport); + INIT_DELAYED_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport); + INIT_DELAYED_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io); + INIT_WORK(&rport->scan_work, fc_scsi_scan_rport); + INIT_WORK(&rport->stgt_delete_work, fc_starget_delete); + INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete); spin_lock_irqsave(shost->host_lock, flags); @@ -1963,7 +1962,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, } if (match) { - struct work_struct *work = + struct delayed_work *work = &rport->dev_loss_work; memcpy(&rport->node_name, &ids->node_name, @@ -2267,12 +2266,13 @@ EXPORT_SYMBOL(fc_remote_port_rolechg); * was a SCSI target (thus was blocked), and failed * to return in the alloted time. * - * @data: rport target that failed to reappear in the alloted time. + * @work: rport target that failed to reappear in the alloted time. **/ static void -fc_timeout_deleted_rport(void *data) +fc_timeout_deleted_rport(struct work_struct *work) { - struct fc_rport *rport = (struct fc_rport *)data; + struct fc_rport *rport = + container_of(work, struct fc_rport, dev_loss_work.work); struct Scsi_Host *shost = rport_to_shost(rport); struct fc_host_attrs *fc_host = shost_to_fc_host(shost); unsigned long flags; @@ -2366,15 +2366,16 @@ fc_timeout_deleted_rport(void *data) * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a * disconnected SCSI target. * - * @data: rport to terminate io on. + * @work: rport to terminate io on. * * Notes: Only requests the failure of the io, not that all are flushed * prior to returning. **/ static void -fc_timeout_fail_rport_io(void *data) +fc_timeout_fail_rport_io(struct work_struct *work) { - struct fc_rport *rport = (struct fc_rport *)data; + struct fc_rport *rport = + container_of(work, struct fc_rport, fail_io_work.work); struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); @@ -2387,12 +2388,13 @@ fc_timeout_fail_rport_io(void *data) /** * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. * - * @data: remote port to be scanned. + * @work: remote port to be scanned. **/ static void -fc_scsi_scan_rport(void *data) +fc_scsi_scan_rport(struct work_struct *work) { - struct fc_rport *rport = (struct fc_rport *)data; + struct fc_rport *rport = + container_of(work, struct fc_rport, scan_work); struct Scsi_Host *shost = rport_to_shost(rport); unsigned long flags; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 9b25124a989e..9c22f1342715 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -234,9 +234,11 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, return 0; } -static void session_recovery_timedout(void *data) +static void session_recovery_timedout(struct work_struct *work) { - struct iscsi_cls_session *session = data; + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, + recovery_work.work); dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " "out after %d secs\n", session->recovery_tmo); @@ -276,7 +278,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, session->transport = transport; session->recovery_tmo = 120; - INIT_WORK(&session->recovery_work, session_recovery_timedout, session); + INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 9f070f0d0f2b..3fded4831460 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -964,9 +964,10 @@ struct work_queue_wrapper { }; static void -spi_dv_device_work_wrapper(void *data) +spi_dv_device_work_wrapper(struct work_struct *work) { - struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct work_queue_wrapper *wqw = + container_of(work, struct work_queue_wrapper, work); struct scsi_device *sdev = wqw->sdev; kfree(wqw); @@ -1006,7 +1007,7 @@ spi_schedule_dv_device(struct scsi_device *sdev) return; } - INIT_WORK(&wqw->work, spi_dv_device_work_wrapper, wqw); + INIT_WORK(&wqw->work, spi_dv_device_work_wrapper); wqw->sdev = sdev; schedule_work(&wqw->work); diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index a23862ef72b2..08c1c57c6128 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -265,9 +265,10 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) * Drivers can provide word-at-a-time i/o primitives, or provide * transfer-at-a-time ones to leverage dma or fifo hardware. */ -static void bitbang_work(void *_bitbang) +static void bitbang_work(struct work_struct *work) { - struct spi_bitbang *bitbang = _bitbang; + struct spi_bitbang *bitbang = + container_of(work, struct spi_bitbang, work); unsigned long flags; spin_lock_irqsave(&bitbang->lock, flags); @@ -456,7 +457,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) if (!bitbang->master || !bitbang->chipselect) return -EINVAL; - INIT_WORK(&bitbang->work, bitbang_work, bitbang); + INIT_WORK(&bitbang->work, bitbang_work); spin_lock_init(&bitbang->lock); INIT_LIST_HEAD(&bitbang->queue); diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index e6565633ba0f..3dfa3e40e148 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -158,7 +158,7 @@ struct cxacru_data { const struct cxacru_modem_type *modem_type; int line_status; - struct work_struct poll_work; + struct delayed_work poll_work; /* contol handles */ struct mutex cm_serialize; @@ -347,7 +347,7 @@ static int cxacru_card_status(struct cxacru_data *instance) return 0; } -static void cxacru_poll_status(struct cxacru_data *instance); +static void cxacru_poll_status(struct work_struct *work); static int cxacru_atm_start(struct usbatm_data *usbatm_instance, struct atm_dev *atm_dev) @@ -376,12 +376,14 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, } /* Start status polling */ - cxacru_poll_status(instance); + cxacru_poll_status(&instance->poll_work.work); return 0; } -static void cxacru_poll_status(struct cxacru_data *instance) +static void cxacru_poll_status(struct work_struct *work) { + struct cxacru_data *instance = + container_of(work, struct cxacru_data, poll_work.work); u32 buf[CXINF_MAX] = {}; struct usbatm_data *usbatm = instance->usbatm; struct atm_dev *atm_dev = usbatm->atm_dev; @@ -720,7 +722,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, mutex_init(&instance->cm_serialize); - INIT_WORK(&instance->poll_work, (void *)cxacru_poll_status, instance); + INIT_DELAYED_WORK(&instance->poll_work, cxacru_poll_status); usbatm_instance->driver_data = instance; diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index c870c804470f..7ed34bb1c50f 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -142,7 +142,7 @@ struct speedtch_instance_data { struct speedtch_params params; /* set in probe, constant afterwards */ - struct work_struct status_checker; + struct delayed_work status_checker; unsigned char last_status; @@ -498,8 +498,11 @@ static int speedtch_start_synchro(struct speedtch_instance_data *instance) return ret; } -static void speedtch_check_status(struct speedtch_instance_data *instance) +static void speedtch_check_status(struct work_struct *work) { + struct speedtch_instance_data *instance = + container_of(work, struct speedtch_instance_data, + status_checker.work); struct usbatm_data *usbatm = instance->usbatm; struct atm_dev *atm_dev = usbatm->atm_dev; unsigned char *buf = instance->scratch_buffer; @@ -576,7 +579,7 @@ static void speedtch_status_poll(unsigned long data) { struct speedtch_instance_data *instance = (void *)data; - schedule_work(&instance->status_checker); + schedule_delayed_work(&instance->status_checker, 0); /* The following check is racy, but the race is harmless */ if (instance->poll_delay < MAX_POLL_DELAY) @@ -596,7 +599,7 @@ static void speedtch_resubmit_int(unsigned long data) if (int_urb) { ret = usb_submit_urb(int_urb, GFP_ATOMIC); if (!ret) - schedule_work(&instance->status_checker); + schedule_delayed_work(&instance->status_checker, 0); else { atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY)); @@ -640,7 +643,7 @@ static void speedtch_handle_int(struct urb *int_urb) if ((int_urb = instance->int_urb)) { ret = usb_submit_urb(int_urb, GFP_ATOMIC); - schedule_work(&instance->status_checker); + schedule_delayed_work(&instance->status_checker, 0); if (ret < 0) { atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); goto fail; @@ -855,7 +858,7 @@ static int speedtch_bind(struct usbatm_data *usbatm, usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); - INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance); + INIT_DELAYED_WORK(&instance->status_checker, speedtch_check_status); instance->status_checker.timer.function = speedtch_status_poll; instance->status_checker.timer.data = (unsigned long)instance; diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index f6b9f7e1f716..e39bb09f5af9 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -658,9 +658,9 @@ static int request_dsp(struct uea_softc *sc) /* * The uea_load_page() function must be called within a process context */ -static void uea_load_page(void *xsc) +static void uea_load_page(struct work_struct *work) { - struct uea_softc *sc = xsc; + struct uea_softc *sc = container_of(work, struct uea_softc, task); u16 pageno = sc->pageno; u16 ovl = sc->ovl; struct block_info bi; @@ -1352,7 +1352,7 @@ static int uea_boot(struct uea_softc *sc) uea_enters(INS_TO_USBDEV(sc)); - INIT_WORK(&sc->task, uea_load_page, sc); + INIT_WORK(&sc->task, uea_load_page); init_waitqueue_head(&sc->sync_q); init_waitqueue_head(&sc->cmv_ack_wait); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 9a9012fd284b..6408e10fdbf8 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -421,9 +421,9 @@ static void acm_write_bulk(struct urb *urb) schedule_work(&acm->work); } -static void acm_softint(void *private) +static void acm_softint(struct work_struct *work) { - struct acm *acm = private; + struct acm *acm = container_of(work, struct acm, work); dbg("Entering acm_softint."); if (!ACM_READY(acm)) @@ -927,7 +927,7 @@ skip_normal_probe: acm->rx_buflimit = num_rx_buf; acm->urb_task.func = acm_rx_tasklet; acm->urb_task.data = (unsigned long) acm; - INIT_WORK(&acm->work, acm_softint, acm); + INIT_WORK(&acm->work, acm_softint); spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ba165aff9ea4..ad0ffbe8f7d7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -167,9 +167,10 @@ static void set_port_led( #define LED_CYCLE_PERIOD ((2*HZ)/3) -static void led_work (void *__hub) +static void led_work (struct work_struct *work) { - struct usb_hub *hub = __hub; + struct usb_hub *hub = + container_of(work, struct usb_hub, leds.work); struct usb_device *hdev = hub->hdev; unsigned i; unsigned changed = 0; @@ -351,9 +352,10 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) * talking to TTs must queue control transfers (not just bulk and iso), so * both can talk to the same hub concurrently. */ -static void hub_tt_kevent (void *arg) +static void hub_tt_kevent (struct work_struct *work) { - struct usb_hub *hub = arg; + struct usb_hub *hub = + container_of(work, struct usb_hub, tt.kevent); unsigned long flags; spin_lock_irqsave (&hub->tt.lock, flags); @@ -641,7 +643,7 @@ static int hub_configure(struct usb_hub *hub, spin_lock_init (&hub->tt.lock); INIT_LIST_HEAD (&hub->tt.clear_list); - INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub); + INIT_WORK (&hub->tt.kevent, hub_tt_kevent); switch (hdev->descriptor.bDeviceProtocol) { case 0: break; @@ -880,7 +882,7 @@ descriptor_error: INIT_LIST_HEAD(&hub->event_list); hub->intfdev = &intf->dev; hub->hdev = hdev; - INIT_WORK(&hub->leds, led_work, hub); + INIT_DELAYED_WORK(&hub->leds, led_work); usb_set_intfdata (intf, hub); @@ -2281,7 +2283,7 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) /* hub LEDs are probably harder to miss than syslog */ if (hub->has_indicators) { hub->indicator[port1-1] = INDICATOR_GREEN_BLINK; - schedule_work (&hub->leds); + schedule_delayed_work (&hub->leds, 0); } } kfree(qual); @@ -2455,7 +2457,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (hub->has_indicators) { hub->indicator[port1-1] = INDICATOR_AMBER_BLINK; - schedule_work (&hub->leds); + schedule_delayed_work (&hub->leds, 0); } status = -ENOTCONN; /* Don't retry */ goto loop_disable; diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 0f8e82a4d480..035d3ef35888 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -230,7 +230,7 @@ struct usb_hub { unsigned has_indicators:1; enum hub_led_mode indicator[USB_MAXCHILDREN]; - struct work_struct leds; + struct delayed_work leds; }; #endif /* __LINUX_HUB_H */ diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 7729c0744886..89572bc021b1 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1501,9 +1501,10 @@ struct set_config_request { }; /* Worker routine for usb_driver_set_configuration() */ -static void driver_set_config_work(void *_req) +static void driver_set_config_work(struct work_struct *work) { - struct set_config_request *req = _req; + struct set_config_request *req = + container_of(work, struct set_config_request, work); usb_lock_device(req->udev); usb_set_configuration(req->udev, req->config); @@ -1541,7 +1542,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config) return -ENOMEM; req->udev = udev; req->config = config; - INIT_WORK(&req->work, driver_set_config_work, req); + INIT_WORK(&req->work, driver_set_config_work); usb_get_dev(udev); if (!schedule_work(&req->work)) { diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 467cb02832f3..ab2f68fc7d2d 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -210,9 +210,10 @@ static void ksuspend_usb_cleanup(void) #ifdef CONFIG_USB_SUSPEND /* usb_autosuspend_work - callback routine to autosuspend a USB device */ -static void usb_autosuspend_work(void *_udev) +static void usb_autosuspend_work(struct work_struct *work) { - struct usb_device *udev = _udev; + struct usb_device *udev = + container_of(work, struct usb_device, autosuspend.work); usb_pm_lock(udev); udev->auto_pm = 1; @@ -222,7 +223,7 @@ static void usb_autosuspend_work(void *_udev) #else -static void usb_autosuspend_work(void *_udev) +static void usb_autosuspend_work(struct work_struct *work) {} #endif @@ -304,7 +305,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) #ifdef CONFIG_PM mutex_init(&dev->pm_mutex); - INIT_WORK(&dev->autosuspend, usb_autosuspend_work, dev); + INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); #endif return dev; } diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 1c17d26d03b8..107119c54301 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1833,9 +1833,9 @@ static void rx_fill (struct eth_dev *dev, gfp_t gfp_flags) spin_unlock_irqrestore(&dev->req_lock, flags); } -static void eth_work (void *_dev) +static void eth_work (struct work_struct *work) { - struct eth_dev *dev = _dev; + struct eth_dev *dev = container_of(work, struct eth_dev, work); if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) { if (netif_running (dev->net)) @@ -2398,7 +2398,7 @@ autoconf_fail: dev = netdev_priv(net); spin_lock_init (&dev->lock); spin_lock_init (&dev->req_lock); - INIT_WORK (&dev->work, eth_work, dev); + INIT_WORK (&dev->work, eth_work); INIT_LIST_HEAD (&dev->tx_reqs); INIT_LIST_HEAD (&dev->rx_reqs); diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 32c635ecbf31..4f95a249c913 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -163,7 +163,7 @@ struct u132_endp { u16 queue_next; struct urb *urb_list[ENDP_QUEUE_SIZE]; struct list_head urb_more; - struct work_struct scheduler; + struct delayed_work scheduler; }; struct u132_ring { unsigned in_use:1; @@ -171,7 +171,7 @@ struct u132_ring { u8 number; struct u132 *u132; struct u132_endp *curr_endp; - struct work_struct scheduler; + struct delayed_work scheduler; }; #define OHCI_QUIRK_AMD756 0x01 #define OHCI_QUIRK_SUPERIO 0x02 @@ -198,7 +198,7 @@ struct u132 { u32 hc_roothub_portstatus[MAX_ROOT_PORTS]; int flags; unsigned long next_statechange; - struct work_struct monitor; + struct delayed_work monitor; int num_endpoints; struct u132_addr addr[MAX_U132_ADDRS]; struct u132_udev udev[MAX_U132_UDEVS]; @@ -314,7 +314,7 @@ static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, if (delta > 0) { if (queue_delayed_work(workqueue, &ring->scheduler, delta)) return; - } else if (queue_work(workqueue, &ring->scheduler)) + } else if (queue_delayed_work(workqueue, &ring->scheduler, 0)) return; kref_put(&u132->kref, u132_hcd_delete); return; @@ -393,12 +393,8 @@ static inline void u132_endp_init_kref(struct u132 *u132, static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(workqueue, &endp->scheduler, delta)) - kref_get(&endp->kref); - } else if (queue_work(workqueue, &endp->scheduler)) - kref_get(&endp->kref); - return; + if (queue_delayed_work(workqueue, &endp->scheduler, delta)) + kref_get(&endp->kref); } static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp) @@ -414,24 +410,14 @@ static inline void u132_monitor_put_kref(struct u132 *u132) static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(workqueue, &u132->monitor, delta)) { - kref_get(&u132->kref); - } - } else if (queue_work(workqueue, &u132->monitor)) - kref_get(&u132->kref); - return; + if (queue_delayed_work(workqueue, &u132->monitor, delta)) + kref_get(&u132->kref); } static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(workqueue, &u132->monitor, delta)) - return; - } else if (queue_work(workqueue, &u132->monitor)) - return; - kref_put(&u132->kref, u132_hcd_delete); - return; + if (!queue_delayed_work(workqueue, &u132->monitor, delta)) + kref_put(&u132->kref, u132_hcd_delete); } static void u132_monitor_cancel_work(struct u132 *u132) @@ -493,9 +479,9 @@ static int read_roothub_info(struct u132 *u132) return 0; } -static void u132_hcd_monitor_work(void *data) +static void u132_hcd_monitor_work(struct work_struct *work) { - struct u132 *u132 = data; + struct u132 *u132 = container_of(work, struct u132, monitor.work); if (u132->going > 1) { dev_err(&u132->platform_dev->dev, "device has been removed %d\n" , u132->going); @@ -1319,15 +1305,14 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, } } -static void u132_hcd_ring_work_scheduler(void *data); -static void u132_hcd_endp_work_scheduler(void *data); /* * this work function is only executed from the work queue * */ -static void u132_hcd_ring_work_scheduler(void *data) +static void u132_hcd_ring_work_scheduler(struct work_struct *work) { - struct u132_ring *ring = data; + struct u132_ring *ring = + container_of(work, struct u132_ring, scheduler.work); struct u132 *u132 = ring->u132; down(&u132->scheduler_lock); if (ring->in_use) { @@ -1386,10 +1371,11 @@ static void u132_hcd_ring_work_scheduler(void *data) } } -static void u132_hcd_endp_work_scheduler(void *data) +static void u132_hcd_endp_work_scheduler(struct work_struct *work) { struct u132_ring *ring; - struct u132_endp *endp = data; + struct u132_endp *endp = + container_of(work, struct u132_endp, scheduler.work); struct u132 *u132 = endp->u132; down(&u132->scheduler_lock); ring = endp->ring; @@ -1947,7 +1933,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132, if (!endp) { return -ENOMEM; } - INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; @@ -2036,7 +2022,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, if (!endp) { return -ENOMEM; } - INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); endp->dequeueing = 0; @@ -2121,7 +2107,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132, if (!endp) { return -ENOMEM; } - INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; @@ -3100,10 +3086,10 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) ring->number = rings + 1; ring->length = 0; ring->curr_endp = NULL; - INIT_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler, - (void *)ring); + INIT_DELAYED_WORK(&ring->scheduler, + u132_hcd_ring_work_scheduler); } down(&u132->sw_lock); - INIT_WORK(&u132->monitor, u132_hcd_monitor_work, (void *)u132); + INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); while (ports-- > 0) { struct u132_port *port = &u132->port[ports]; port->u132 = u132; diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 6d08a3bcc952..ebc9e823a46e 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -969,9 +969,10 @@ static void hid_retry_timeout(unsigned long _hid) } /* Workqueue routine to reset the device */ -static void hid_reset(void *_hid) +static void hid_reset(struct work_struct *work) { - struct hid_device *hid = (struct hid_device *) _hid; + struct hid_device *hid = + container_of(work, struct hid_device, reset_work); int rc_lock, rc; dev_dbg(&hid->intf->dev, "resetting device\n"); @@ -2015,7 +2016,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) init_waitqueue_head(&hid->wait); - INIT_WORK(&hid->reset_work, hid_reset, hid); + INIT_WORK(&hid->reset_work, hid_reset); setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid); spin_lock_init(&hid->inlock); diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 9b591b8b9369..e4e2cf2ba915 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -156,9 +156,9 @@ struct usb_ftdi { struct usb_device *udev; struct usb_interface *interface; struct usb_class_driver *class; - struct work_struct status_work; - struct work_struct command_work; - struct work_struct respond_work; + struct delayed_work status_work; + struct delayed_work command_work; + struct delayed_work respond_work; struct u132_platform_data platform_data; struct resource resources[0]; struct platform_device platform_dev; @@ -210,23 +210,14 @@ static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) - return; - } else if (queue_work(status_queue, &ftdi->status_work)) - return; - kref_put(&ftdi->kref, ftdi_elan_delete); - return; + if (!queue_delayed_work(status_queue, &ftdi->status_work, delta)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) - kref_get(&ftdi->kref); - } else if (queue_work(status_queue, &ftdi->status_work)) - kref_get(&ftdi->kref); - return; + if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) + kref_get(&ftdi->kref); } static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) @@ -237,25 +228,14 @@ static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(command_queue, &ftdi->command_work, - delta)) - return; - } else if (queue_work(command_queue, &ftdi->command_work)) - return; - kref_put(&ftdi->kref, ftdi_elan_delete); - return; + if (!queue_delayed_work(command_queue, &ftdi->command_work, delta)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(command_queue, &ftdi->command_work, - delta)) - kref_get(&ftdi->kref); - } else if (queue_work(command_queue, &ftdi->command_work)) - kref_get(&ftdi->kref); - return; + if (queue_delayed_work(command_queue, &ftdi->command_work, delta)) + kref_get(&ftdi->kref); } static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) @@ -267,25 +247,14 @@ static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(respond_queue, &ftdi->respond_work, - delta)) - return; - } else if (queue_work(respond_queue, &ftdi->respond_work)) - return; - kref_put(&ftdi->kref, ftdi_elan_delete); - return; + if (!queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(respond_queue, &ftdi->respond_work, - delta)) - kref_get(&ftdi->kref); - } else if (queue_work(respond_queue, &ftdi->respond_work)) - kref_get(&ftdi->kref); - return; + if (queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) + kref_get(&ftdi->kref); } static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) @@ -475,9 +444,11 @@ static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) return; } -static void ftdi_elan_command_work(void *data) +static void ftdi_elan_command_work(struct work_struct *work) { - struct usb_ftdi *ftdi = data; + struct usb_ftdi *ftdi = + container_of(work, struct usb_ftdi, command_work.work); + if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); return; @@ -500,9 +471,10 @@ static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) return; } -static void ftdi_elan_respond_work(void *data) +static void ftdi_elan_respond_work(struct work_struct *work) { - struct usb_ftdi *ftdi = data; + struct usb_ftdi *ftdi = + container_of(work, struct usb_ftdi, respond_work.work); if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); return; @@ -534,9 +506,10 @@ static void ftdi_elan_respond_work(void *data) * after the FTDI has been synchronized * */ -static void ftdi_elan_status_work(void *data) +static void ftdi_elan_status_work(struct work_struct *work) { - struct usb_ftdi *ftdi = data; + struct usb_ftdi *ftdi = + container_of(work, struct usb_ftdi, status_work.work); int work_delay_in_msec = 0; if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); @@ -2691,12 +2664,9 @@ static int ftdi_elan_probe(struct usb_interface *interface, ftdi->class = NULL; dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a" "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber); - INIT_WORK(&ftdi->status_work, ftdi_elan_status_work, - (void *)ftdi); - INIT_WORK(&ftdi->command_work, ftdi_elan_command_work, - (void *)ftdi); - INIT_WORK(&ftdi->respond_work, ftdi_elan_respond_work, - (void *)ftdi); + INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); + INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); + INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); return 0; } else { diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index abb4dcd811ac..33e716c6a79b 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -81,8 +81,8 @@ struct interfacekit { unsigned char *data; dma_addr_t data_dma; - struct work_struct do_notify; - struct work_struct do_resubmit; + struct delayed_work do_notify; + struct delayed_work do_resubmit; unsigned long input_events; unsigned long sensor_events; }; @@ -374,7 +374,7 @@ static void interfacekit_irq(struct urb *urb) } if (kit->input_events || kit->sensor_events) - schedule_work(&kit->do_notify); + schedule_delayed_work(&kit->do_notify, 0); resubmit: status = usb_submit_urb(urb, SLAB_ATOMIC); @@ -384,9 +384,10 @@ resubmit: kit->udev->devpath, status); } -static void do_notify(void *data) +static void do_notify(struct work_struct *work) { - struct interfacekit *kit = data; + struct interfacekit *kit = + container_of(work, struct interfacekit, do_notify.work); int i; char sysfs_file[8]; @@ -405,9 +406,11 @@ static void do_notify(void *data) } } -static void do_resubmit(void *data) +static void do_resubmit(struct work_struct *work) { - set_outputs(data); + struct interfacekit *kit = + container_of(work, struct interfacekit, do_resubmit.work); + set_outputs(kit); } #define show_set_output(value) \ @@ -575,8 +578,8 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic kit->udev = usb_get_dev(dev); kit->intf = intf; - INIT_WORK(&kit->do_notify, do_notify, kit); - INIT_WORK(&kit->do_resubmit, do_resubmit, kit); + INIT_DELAYED_WORK(&kit->do_notify, do_notify); + INIT_DELAYED_WORK(&kit->do_resubmit, do_resubmit); usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data, maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp, interfacekit_irq, kit, endpoint->bInterval); diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c index 5c780cab92e0..0385ffcc7419 100644 --- a/drivers/usb/misc/phidgetmotorcontrol.c +++ b/drivers/usb/misc/phidgetmotorcontrol.c @@ -41,7 +41,7 @@ struct motorcontrol { unsigned char *data; dma_addr_t data_dma; - struct work_struct do_notify; + struct delayed_work do_notify; unsigned long input_events; unsigned long speed_events; unsigned long exceed_events; @@ -148,7 +148,7 @@ static void motorcontrol_irq(struct urb *urb) set_bit(1, &mc->exceed_events); if (mc->input_events || mc->exceed_events || mc->speed_events) - schedule_work(&mc->do_notify); + schedule_delayed_work(&mc->do_notify, 0); resubmit: status = usb_submit_urb(urb, SLAB_ATOMIC); @@ -159,9 +159,10 @@ resubmit: mc->udev->devpath, status); } -static void do_notify(void *data) +static void do_notify(struct work_struct *work) { - struct motorcontrol *mc = data; + struct motorcontrol *mc = + container_of(work, struct motorcontrol, do_notify.work); int i; char sysfs_file[8]; @@ -348,7 +349,7 @@ static int motorcontrol_probe(struct usb_interface *intf, const struct usb_devic mc->udev = usb_get_dev(dev); mc->intf = intf; mc->acceleration[0] = mc->acceleration[1] = 10; - INIT_WORK(&mc->do_notify, do_notify, mc); + INIT_DELAYED_WORK(&mc->do_notify, do_notify); usb_fill_int_urb(mc->irq, mc->udev, pipe, mc->data, maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp, motorcontrol_irq, mc, endpoint->bInterval); diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 7c906a43e497..fa78326d0bf0 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -222,7 +222,7 @@ struct kaweth_device int suspend_lowmem_ctrl; int linkstate; int opened; - struct work_struct lowmem_work; + struct delayed_work lowmem_work; struct usb_device *dev; struct net_device *net; @@ -530,9 +530,10 @@ resubmit: kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC); } -static void kaweth_resubmit_tl(void *d) +static void kaweth_resubmit_tl(struct work_struct *work) { - struct kaweth_device *kaweth = (struct kaweth_device *)d; + struct kaweth_device *kaweth = + container_of(work, struct kaweth_device, lowmem_work.work); if (IS_BLOCKED(kaweth->status)) return; @@ -1126,7 +1127,7 @@ err_fw: /* kaweth is zeroed as part of alloc_netdev */ - INIT_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl, (void *)kaweth); + INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); SET_MODULE_OWNER(netdev); diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 33abbd2176b6..78cf6f091285 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -1280,9 +1280,9 @@ static inline void setup_pegasus_II(pegasus_t * pegasus) static struct workqueue_struct *pegasus_workqueue = NULL; #define CARRIER_CHECK_DELAY (2 * HZ) -static void check_carrier(void *data) +static void check_carrier(struct work_struct *work) { - pegasus_t *pegasus = data; + pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work); set_carrier(pegasus->net); if (!(pegasus->flags & PEGASUS_UNPLUG)) { queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, @@ -1318,7 +1318,7 @@ static int pegasus_probe(struct usb_interface *intf, tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus); - INIT_WORK(&pegasus->carrier_check, check_carrier, pegasus); + INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier); pegasus->intf = intf; pegasus->usb = dev; diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index 006438069b66..98f6898cae1f 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -95,7 +95,7 @@ typedef struct pegasus { int dev_index; int intr_interval; struct tasklet_struct rx_tl; - struct work_struct carrier_check; + struct delayed_work carrier_check; struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb; struct sk_buff *rx_pool[RX_SKBS]; struct sk_buff *rx_skb; diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 760b5327b81b..79b5474fe234 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -782,9 +782,10 @@ static struct ethtool_ops usbnet_ethtool_ops = { * especially now that control transfers can be queued. */ static void -kevent (void *data) +kevent (struct work_struct *work) { - struct usbnet *dev = data; + struct usbnet *dev = + container_of(work, struct usbnet, kevent); int status; /* usb_clear_halt() needs a thread context */ @@ -1146,7 +1147,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) skb_queue_head_init (&dev->done); dev->bh.func = usbnet_bh; dev->bh.data = (unsigned long) dev; - INIT_WORK (&dev->kevent, kevent, dev); + INIT_WORK (&dev->kevent, kevent); dev->delay.function = usbnet_bh; dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 812275509137..2a4ac9bd6a3a 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -92,6 +92,7 @@ struct aircable_private { struct circ_buf *rx_buf; /* read buffer */ int rx_flags; /* for throttilng */ struct work_struct rx_work; /* work cue for the receiving line */ + struct usb_serial_port *port; /* USB port with which associated */ }; /* Private methods */ @@ -251,10 +252,11 @@ static void aircable_send(struct usb_serial_port *port) schedule_work(&port->work); } -static void aircable_read(void *params) +static void aircable_read(struct work_struct *work) { - struct usb_serial_port *port = params; - struct aircable_private *priv = usb_get_serial_port_data(port); + struct aircable_private *priv = + container_of(work, struct aircable_private, rx_work); + struct usb_serial_port *port = priv->port; struct tty_struct *tty; unsigned char *data; int count; @@ -348,7 +350,8 @@ static int aircable_attach (struct usb_serial *serial) } priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - INIT_WORK(&priv->rx_work, aircable_read, port); + priv->port = port; + INIT_WORK(&priv->rx_work, aircable_read); usb_set_serial_port_data(serial->port[0], priv); @@ -515,7 +518,7 @@ static void aircable_read_bulk_callback(struct urb *urb) package_length - shift); } } - aircable_read(port); + aircable_read(&priv->rx_work); } /* Schedule the next read _if_ we are still open */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index bdb58100fc1d..fd159b040bfb 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -430,13 +430,14 @@ struct digi_port { int dp_in_close; /* close in progress */ wait_queue_head_t dp_close_wait; /* wait queue for close */ struct work_struct dp_wakeup_work; + struct usb_serial_port *dp_port; }; /* Local Function Declarations */ static void digi_wakeup_write( struct usb_serial_port *port ); -static void digi_wakeup_write_lock(void *); +static void digi_wakeup_write_lock(struct work_struct *work); static int digi_write_oob_command( struct usb_serial_port *port, unsigned char *buf, int count, int interruptible ); static int digi_write_inb_command( struct usb_serial_port *port, @@ -598,11 +599,12 @@ static inline long cond_wait_interruptible_timeout_irqrestore( * on writes. */ -static void digi_wakeup_write_lock(void *arg) +static void digi_wakeup_write_lock(struct work_struct *work) { - struct usb_serial_port *port = arg; + struct digi_port *priv = + container_of(work, struct digi_port, dp_wakeup_work); + struct usb_serial_port *port = priv->dp_port; unsigned long flags; - struct digi_port *priv = usb_get_serial_port_data(port); spin_lock_irqsave( &priv->dp_port_lock, flags ); @@ -1702,8 +1704,8 @@ dbg( "digi_startup: TOP" ); init_waitqueue_head( &priv->dp_flush_wait ); priv->dp_in_close = 0; init_waitqueue_head( &priv->dp_close_wait ); - INIT_WORK(&priv->dp_wakeup_work, - digi_wakeup_write_lock, serial->port[i]); + INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); + priv->dp_port = serial->port[i]; /* initialize write wait queue for this port */ init_waitqueue_head( &serial->port[i]->write_wait ); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c186b4e73c72..88ed5c1d236c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -559,7 +559,8 @@ struct ftdi_private { char prev_status, diff_status; /* Used for TIOCMIWAIT */ __u8 rx_flags; /* receive state flags (throttling) */ spinlock_t rx_lock; /* spinlock for receive state */ - struct work_struct rx_work; + struct delayed_work rx_work; + struct usb_serial_port *port; int rx_processed; unsigned long rx_bytes; @@ -593,7 +594,7 @@ static int ftdi_write_room (struct usb_serial_port *port); static int ftdi_chars_in_buffer (struct usb_serial_port *port); static void ftdi_write_bulk_callback (struct urb *urb); static void ftdi_read_bulk_callback (struct urb *urb); -static void ftdi_process_read (void *param); +static void ftdi_process_read (struct work_struct *work); static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old); static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file); static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear); @@ -1201,7 +1202,8 @@ static int ftdi_sio_attach (struct usb_serial *serial) port->read_urb->transfer_buffer_length = BUFSZ; } - INIT_WORK(&priv->rx_work, ftdi_process_read, port); + INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read); + priv->port = port; /* Free port's existing write urb and transfer buffer. */ if (port->write_urb) { @@ -1641,17 +1643,18 @@ static void ftdi_read_bulk_callback (struct urb *urb) priv->rx_bytes += countread; spin_unlock_irqrestore(&priv->rx_lock, flags); - ftdi_process_read(port); + ftdi_process_read(&priv->rx_work.work); } /* ftdi_read_bulk_callback */ -static void ftdi_process_read (void *param) +static void ftdi_process_read (struct work_struct *work) { /* ftdi_process_read */ - struct usb_serial_port *port = (struct usb_serial_port*)param; + struct ftdi_private *priv = + container_of(work, struct ftdi_private, rx_work.work); + struct usb_serial_port *port = priv->port; struct urb *urb; struct tty_struct *tty; - struct ftdi_private *priv; char error_flag; unsigned char *data; @@ -2180,7 +2183,7 @@ static void ftdi_unthrottle (struct usb_serial_port *port) spin_unlock_irqrestore(&priv->rx_lock, flags); if (actually_throttled) - schedule_work(&priv->rx_work); + schedule_delayed_work(&priv->rx_work, 0); } static int __init ftdi_init (void) diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 909005107ea2..e09a0bfe6231 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -120,6 +120,8 @@ struct keyspan_pda_private { int tx_throttled; struct work_struct wakeup_work; struct work_struct unthrottle_work; + struct usb_serial *serial; + struct usb_serial_port *port; }; @@ -175,9 +177,11 @@ static struct usb_device_id id_table_fake_xircom [] = { }; #endif -static void keyspan_pda_wakeup_write( struct usb_serial_port *port ) +static void keyspan_pda_wakeup_write(struct work_struct *work) { - + struct keyspan_pda_private *priv = + container_of(work, struct keyspan_pda_private, wakeup_work); + struct usb_serial_port *port = priv->port; struct tty_struct *tty = port->tty; /* wake up port processes */ @@ -187,8 +191,11 @@ static void keyspan_pda_wakeup_write( struct usb_serial_port *port ) tty_wakeup(tty); } -static void keyspan_pda_request_unthrottle( struct usb_serial *serial ) +static void keyspan_pda_request_unthrottle(struct work_struct *work) { + struct keyspan_pda_private *priv = + container_of(work, struct keyspan_pda_private, unthrottle_work); + struct usb_serial *serial = priv->serial; int result; dbg(" request_unthrottle"); @@ -765,11 +772,10 @@ static int keyspan_pda_startup (struct usb_serial *serial) return (1); /* error */ usb_set_serial_port_data(serial->port[0], priv); init_waitqueue_head(&serial->port[0]->write_wait); - INIT_WORK(&priv->wakeup_work, (void *)keyspan_pda_wakeup_write, - (void *)(serial->port[0])); - INIT_WORK(&priv->unthrottle_work, - (void *)keyspan_pda_request_unthrottle, - (void *)(serial)); + INIT_WORK(&priv->wakeup_work, keyspan_pda_wakeup_write); + INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle); + priv->serial = serial; + priv->port = serial->port[0]; return (0); } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 8006e51c34bb..2cfba8488a93 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -533,9 +533,10 @@ void usb_serial_port_softint(struct usb_serial_port *port) schedule_work(&port->work); } -static void usb_serial_port_work(void *private) +static void usb_serial_port_work(struct work_struct *work) { - struct usb_serial_port *port = private; + struct usb_serial_port *port = + container_of(work, struct usb_serial_port, work); struct tty_struct *tty; dbg("%s - port %d", __FUNCTION__, port->number); @@ -799,7 +800,7 @@ int usb_serial_probe(struct usb_interface *interface, port->serial = serial; spin_lock_init(&port->lock); mutex_init(&port->mutex); - INIT_WORK(&port->work, usb_serial_port_work, port); + INIT_WORK(&port->work, usb_serial_port_work); serial->port[i] = port; } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 4d1cd7aeccd3..154c7d290597 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -227,6 +227,7 @@ struct whiteheat_private { struct list_head rx_urbs_submitted; struct list_head rx_urb_q; struct work_struct rx_work; + struct usb_serial_port *port; struct list_head tx_urbs_free; struct list_head tx_urbs_submitted; }; @@ -241,7 +242,7 @@ static void command_port_read_callback(struct urb *urb); static int start_port_read(struct usb_serial_port *port); static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, struct list_head *head); static struct list_head *list_first(struct list_head *head); -static void rx_data_softint(void *private); +static void rx_data_softint(struct work_struct *work); static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize); static int firm_open(struct usb_serial_port *port); @@ -424,7 +425,8 @@ static int whiteheat_attach (struct usb_serial *serial) spin_lock_init(&info->lock); info->flags = 0; info->mcr = 0; - INIT_WORK(&info->rx_work, rx_data_softint, port); + INIT_WORK(&info->rx_work, rx_data_softint); + info->port = port; INIT_LIST_HEAD(&info->rx_urbs_free); INIT_LIST_HEAD(&info->rx_urbs_submitted); @@ -949,7 +951,7 @@ static void whiteheat_unthrottle (struct usb_serial_port *port) spin_unlock_irqrestore(&info->lock, flags); if (actually_throttled) - rx_data_softint(port); + rx_data_softint(&info->rx_work); return; } @@ -1400,10 +1402,11 @@ static struct list_head *list_first(struct list_head *head) } -static void rx_data_softint(void *private) +static void rx_data_softint(struct work_struct *work) { - struct usb_serial_port *port = (struct usb_serial_port *)private; - struct whiteheat_private *info = usb_get_serial_port_data(port); + struct whiteheat_private *info = + container_of(work, struct whiteheat_private, rx_work); + struct usb_serial_port *port = info->port; struct tty_struct *tty = port->tty; struct whiteheat_urb_wrap *wrap; struct urb *urb; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 302174b8e477..31f476a64790 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -383,9 +383,9 @@ static void fbcon_update_softback(struct vc_data *vc) softback_top = 0; } -static void fb_flashcursor(void *private) +static void fb_flashcursor(struct work_struct *work) { - struct fb_info *info = private; + struct fb_info *info = container_of(work, struct fb_info, queue); struct fbcon_ops *ops = info->fbcon_par; struct display *p; struct vc_data *vc = NULL; @@ -442,7 +442,7 @@ static void fbcon_add_cursor_timer(struct fb_info *info) if ((!info->queue.func || info->queue.func == fb_flashcursor) && !(ops->flags & FBCON_FLAGS_CURSOR_TIMER)) { if (!info->queue.func) - INIT_WORK(&info->queue, fb_flashcursor, info); + INIT_WORK(&info->queue, fb_flashcursor); init_timer(&ops->cursor_timer); ops->cursor_timer.function = cursor_timer_handler; diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 90a79c784549..944273c3dbff 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -110,8 +110,8 @@ struct v9fs_mux_rpc { }; static int v9fs_poll_proc(void *); -static void v9fs_read_work(void *); -static void v9fs_write_work(void *); +static void v9fs_read_work(struct work_struct *work); +static void v9fs_write_work(struct work_struct *work); static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, poll_table * p); static u16 v9fs_mux_get_tag(struct v9fs_mux_data *); @@ -297,8 +297,8 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, m->rbuf = NULL; m->wpos = m->wsize = 0; m->wbuf = NULL; - INIT_WORK(&m->rq, v9fs_read_work, m); - INIT_WORK(&m->wq, v9fs_write_work, m); + INIT_WORK(&m->rq, v9fs_read_work); + INIT_WORK(&m->wq, v9fs_write_work); m->wsched = 0; memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); m->poll_task = NULL; @@ -458,13 +458,13 @@ static int v9fs_poll_proc(void *a) /** * v9fs_write_work - called when a transport can send some data */ -static void v9fs_write_work(void *a) +static void v9fs_write_work(struct work_struct *work) { int n, err; struct v9fs_mux_data *m; struct v9fs_req *req; - m = a; + m = container_of(work, struct v9fs_mux_data, wq); if (m->err < 0) { clear_bit(Wworksched, &m->wsched); @@ -564,7 +564,7 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) /** * v9fs_read_work - called when there is some data to be read from a transport */ -static void v9fs_read_work(void *a) +static void v9fs_read_work(struct work_struct *work) { int n, err; struct v9fs_mux_data *m; @@ -572,7 +572,7 @@ static void v9fs_read_work(void *a) struct v9fs_fcall *rcall; char *rbuf; - m = a; + m = container_of(work, struct v9fs_mux_data, rq); if (m->err < 0) return; diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 78fe0fae23ff..55f5333dae99 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -35,7 +35,7 @@ struct greedy { struct gfs2_holder gr_gh; - struct work_struct gr_work; + struct delayed_work gr_work; }; struct gfs2_gl_hash_bucket { @@ -1368,9 +1368,9 @@ static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, glops->go_xmote_th(gl, state, flags); } -static void greedy_work(void *data) +static void greedy_work(struct work_struct *work) { - struct greedy *gr = data; + struct greedy *gr = container_of(work, struct greedy, gr_work.work); struct gfs2_holder *gh = &gr->gr_gh; struct gfs2_glock *gl = gh->gh_gl; const struct gfs2_glock_operations *glops = gl->gl_ops; @@ -1422,7 +1422,7 @@ int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time) gfs2_holder_init(gl, 0, 0, gh); set_bit(HIF_GREEDY, &gh->gh_iflags); - INIT_WORK(&gr->gr_work, greedy_work, gr); + INIT_DELAYED_WORK(&gr->gr_work, greedy_work); set_bit(GLF_SKIP_WAITERS2, &gl->gl_flags); schedule_delayed_work(&gr->gr_work, time); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 42e3bef270c9..72dad552aa00 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -577,12 +577,12 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) server->rcv.ptr = (unsigned char*)&server->rcv.buf; server->rcv.len = 10; server->rcv.state = 0; - INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc, server); - INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc, server); + INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc); + INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc); sock->sk->sk_write_space = ncp_tcp_write_space; } else { - INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc, server); - INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc, server); + INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc); + INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc); server->timeout_tm.data = (unsigned long)server; server->timeout_tm.function = ncpdgram_timeout_call; } diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c index 11c2b252ebed..e496d8b65e92 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -350,9 +350,10 @@ static void info_server(struct ncp_server *server, unsigned int id, const void * } } -void ncpdgram_rcv_proc(void *s) +void ncpdgram_rcv_proc(struct work_struct *work) { - struct ncp_server *server = s; + struct ncp_server *server = + container_of(work, struct ncp_server, rcv.tq); struct socket* sock; sock = server->ncp_sock; @@ -468,9 +469,10 @@ static void __ncpdgram_timeout_proc(struct ncp_server *server) } } -void ncpdgram_timeout_proc(void *s) +void ncpdgram_timeout_proc(struct work_struct *work) { - struct ncp_server *server = s; + struct ncp_server *server = + container_of(work, struct ncp_server, timeout_tq); mutex_lock(&server->rcv.creq_mutex); __ncpdgram_timeout_proc(server); mutex_unlock(&server->rcv.creq_mutex); @@ -652,18 +654,20 @@ skipdata:; } } -void ncp_tcp_rcv_proc(void *s) +void ncp_tcp_rcv_proc(struct work_struct *work) { - struct ncp_server *server = s; + struct ncp_server *server = + container_of(work, struct ncp_server, rcv.tq); mutex_lock(&server->rcv.creq_mutex); __ncptcp_rcv_proc(server); mutex_unlock(&server->rcv.creq_mutex); } -void ncp_tcp_tx_proc(void *s) +void ncp_tcp_tx_proc(struct work_struct *work) { - struct ncp_server *server = s; + struct ncp_server *server = + container_of(work, struct ncp_server, tx.tq); mutex_lock(&server->rcv.creq_mutex); __ncptcp_try_send(server); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 293b6495829f..e431e93ab503 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1829,9 +1829,8 @@ out: } static struct workqueue_struct *laundry_wq; -static struct work_struct laundromat_work; -static void laundromat_main(void *); -static DECLARE_WORK(laundromat_work, laundromat_main, NULL); +static void laundromat_main(struct work_struct *); +static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); __be32 nfsd4_renew(clientid_t *clid) @@ -1940,7 +1939,7 @@ nfs4_laundromat(void) } void -laundromat_main(void *not_used) +laundromat_main(struct work_struct *not_used) { time_t t; diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index f43bc5f18a35..0b2ad163005e 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -1205,10 +1205,12 @@ int ocfs2_flush_truncate_log(struct ocfs2_super *osb) return status; } -static void ocfs2_truncate_log_worker(void *data) +static void ocfs2_truncate_log_worker(struct work_struct *work) { int status; - struct ocfs2_super *osb = data; + struct ocfs2_super *osb = + container_of(work, struct ocfs2_super, + osb_truncate_log_wq.work); mlog_entry_void(); @@ -1441,7 +1443,8 @@ int ocfs2_truncate_log_init(struct ocfs2_super *osb) /* ocfs2_truncate_log_shutdown keys on the existence of * osb->osb_tl_inode so we don't set any of the osb variables * until we're sure all is well. */ - INIT_WORK(&osb->osb_truncate_log_wq, ocfs2_truncate_log_worker, osb); + INIT_DELAYED_WORK(&osb->osb_truncate_log_wq, + ocfs2_truncate_log_worker); osb->osb_tl_bh = tl_bh; osb->osb_tl_inode = tl_inode; diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 305cba3681fe..4cd9a9580456 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -141,7 +141,7 @@ struct o2hb_region { * recognizes a node going up and down in one iteration */ u64 hr_generation; - struct work_struct hr_write_timeout_work; + struct delayed_work hr_write_timeout_work; unsigned long hr_last_timeout_start; /* Used during o2hb_check_slot to hold a copy of the block @@ -156,9 +156,11 @@ struct o2hb_bio_wait_ctxt { int wc_error; }; -static void o2hb_write_timeout(void *arg) +static void o2hb_write_timeout(struct work_struct *work) { - struct o2hb_region *reg = arg; + struct o2hb_region *reg = + container_of(work, struct o2hb_region, + hr_write_timeout_work.work); mlog(ML_ERROR, "Heartbeat write timeout to device %s after %u " "milliseconds\n", reg->hr_dev_name, @@ -1404,7 +1406,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, goto out; } - INIT_WORK(®->hr_write_timeout_work, o2hb_write_timeout, reg); + INIT_DELAYED_WORK(®->hr_write_timeout_work, o2hb_write_timeout); /* * A node is considered live after it has beat LIVE_THRESHOLD diff --git a/fs/ocfs2/cluster/quorum.c b/fs/ocfs2/cluster/quorum.c index 7bba98fbfc15..4705d659fe57 100644 --- a/fs/ocfs2/cluster/quorum.c +++ b/fs/ocfs2/cluster/quorum.c @@ -88,7 +88,7 @@ void o2quo_disk_timeout(void) o2quo_fence_self(); } -static void o2quo_make_decision(void *arg) +static void o2quo_make_decision(struct work_struct *work) { int quorum; int lowest_hb, lowest_reachable = 0, fence = 0; @@ -306,7 +306,7 @@ void o2quo_init(void) struct o2quo_state *qs = &o2quo_state; spin_lock_init(&qs->qs_lock); - INIT_WORK(&qs->qs_work, o2quo_make_decision, NULL); + INIT_WORK(&qs->qs_work, o2quo_make_decision); } void o2quo_exit(void) diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index b650efa8c8be..9b3209dc0b16 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -140,11 +140,11 @@ static int o2net_sys_err_translations[O2NET_ERR_MAX] = [O2NET_ERR_DIED] = -EHOSTDOWN,}; /* can't quite avoid *all* internal declarations :/ */ -static void o2net_sc_connect_completed(void *arg); -static void o2net_rx_until_empty(void *arg); -static void o2net_shutdown_sc(void *arg); +static void o2net_sc_connect_completed(struct work_struct *work); +static void o2net_rx_until_empty(struct work_struct *work); +static void o2net_shutdown_sc(struct work_struct *work); static void o2net_listen_data_ready(struct sock *sk, int bytes); -static void o2net_sc_send_keep_req(void *arg); +static void o2net_sc_send_keep_req(struct work_struct *work); static void o2net_idle_timer(unsigned long data); static void o2net_sc_postpone_idle(struct o2net_sock_container *sc); @@ -308,10 +308,10 @@ static struct o2net_sock_container *sc_alloc(struct o2nm_node *node) o2nm_node_get(node); sc->sc_node = node; - INIT_WORK(&sc->sc_connect_work, o2net_sc_connect_completed, sc); - INIT_WORK(&sc->sc_rx_work, o2net_rx_until_empty, sc); - INIT_WORK(&sc->sc_shutdown_work, o2net_shutdown_sc, sc); - INIT_WORK(&sc->sc_keepalive_work, o2net_sc_send_keep_req, sc); + INIT_WORK(&sc->sc_connect_work, o2net_sc_connect_completed); + INIT_WORK(&sc->sc_rx_work, o2net_rx_until_empty); + INIT_WORK(&sc->sc_shutdown_work, o2net_shutdown_sc); + INIT_DELAYED_WORK(&sc->sc_keepalive_work, o2net_sc_send_keep_req); init_timer(&sc->sc_idle_timeout); sc->sc_idle_timeout.function = o2net_idle_timer; @@ -342,7 +342,7 @@ static void o2net_sc_queue_work(struct o2net_sock_container *sc, sc_put(sc); } static void o2net_sc_queue_delayed_work(struct o2net_sock_container *sc, - struct work_struct *work, + struct delayed_work *work, int delay) { sc_get(sc); @@ -350,7 +350,7 @@ static void o2net_sc_queue_delayed_work(struct o2net_sock_container *sc, sc_put(sc); } static void o2net_sc_cancel_delayed_work(struct o2net_sock_container *sc, - struct work_struct *work) + struct delayed_work *work) { if (cancel_delayed_work(work)) sc_put(sc); @@ -564,9 +564,11 @@ static void o2net_ensure_shutdown(struct o2net_node *nn, * ourselves as state_change couldn't get the nn_lock and call set_nn_state * itself. */ -static void o2net_shutdown_sc(void *arg) +static void o2net_shutdown_sc(struct work_struct *work) { - struct o2net_sock_container *sc = arg; + struct o2net_sock_container *sc = + container_of(work, struct o2net_sock_container, + sc_shutdown_work); struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); sclog(sc, "shutting down\n"); @@ -1201,9 +1203,10 @@ out: /* this work func is triggerd by data ready. it reads until it can read no * more. it interprets 0, eof, as fatal. if data_ready hits while we're doing * our work the work struct will be marked and we'll be called again. */ -static void o2net_rx_until_empty(void *arg) +static void o2net_rx_until_empty(struct work_struct *work) { - struct o2net_sock_container *sc = arg; + struct o2net_sock_container *sc = + container_of(work, struct o2net_sock_container, sc_rx_work); int ret; do { @@ -1249,9 +1252,11 @@ static int o2net_set_nodelay(struct socket *sock) /* called when a connect completes and after a sock is accepted. the * rx path will see the response and mark the sc valid */ -static void o2net_sc_connect_completed(void *arg) +static void o2net_sc_connect_completed(struct work_struct *work) { - struct o2net_sock_container *sc = arg; + struct o2net_sock_container *sc = + container_of(work, struct o2net_sock_container, + sc_connect_work); mlog(ML_MSG, "sc sending handshake with ver %llu id %llx\n", (unsigned long long)O2NET_PROTOCOL_VERSION, @@ -1262,9 +1267,11 @@ static void o2net_sc_connect_completed(void *arg) } /* this is called as a work_struct func. */ -static void o2net_sc_send_keep_req(void *arg) +static void o2net_sc_send_keep_req(struct work_struct *work) { - struct o2net_sock_container *sc = arg; + struct o2net_sock_container *sc = + container_of(work, struct o2net_sock_container, + sc_keepalive_work.work); o2net_sendpage(sc, o2net_keep_req, sizeof(*o2net_keep_req)); sc_put(sc); @@ -1314,14 +1321,15 @@ static void o2net_sc_postpone_idle(struct o2net_sock_container *sc) * having a connect attempt fail, etc. This centralizes the logic which decides * if a connect attempt should be made or if we should give up and all future * transmit attempts should fail */ -static void o2net_start_connect(void *arg) +static void o2net_start_connect(struct work_struct *work) { - struct o2net_node *nn = arg; + struct o2net_node *nn = + container_of(work, struct o2net_node, nn_connect_work.work); struct o2net_sock_container *sc = NULL; struct o2nm_node *node = NULL, *mynode = NULL; struct socket *sock = NULL; struct sockaddr_in myaddr = {0, }, remoteaddr = {0, }; - int ret = 0; + int ret = 0, stop; /* if we're greater we initiate tx, otherwise we accept */ if (o2nm_this_node() <= o2net_num_from_nn(nn)) @@ -1342,10 +1350,9 @@ static void o2net_start_connect(void *arg) spin_lock(&nn->nn_lock); /* see if we already have one pending or have given up */ - if (nn->nn_sc || nn->nn_persistent_error) - arg = NULL; + stop = (nn->nn_sc || nn->nn_persistent_error); spin_unlock(&nn->nn_lock); - if (arg == NULL) /* *shrug*, needed some indicator */ + if (stop) goto out; nn->nn_last_connect_attempt = jiffies; @@ -1421,9 +1428,10 @@ out: return; } -static void o2net_connect_expired(void *arg) +static void o2net_connect_expired(struct work_struct *work) { - struct o2net_node *nn = arg; + struct o2net_node *nn = + container_of(work, struct o2net_node, nn_connect_expired.work); spin_lock(&nn->nn_lock); if (!nn->nn_sc_valid) { @@ -1436,9 +1444,10 @@ static void o2net_connect_expired(void *arg) spin_unlock(&nn->nn_lock); } -static void o2net_still_up(void *arg) +static void o2net_still_up(struct work_struct *work) { - struct o2net_node *nn = arg; + struct o2net_node *nn = + container_of(work, struct o2net_node, nn_still_up.work); o2quo_hb_still_up(o2net_num_from_nn(nn)); } @@ -1644,9 +1653,9 @@ out: return ret; } -static void o2net_accept_many(void *arg) +static void o2net_accept_many(struct work_struct *work) { - struct socket *sock = arg; + struct socket *sock = o2net_listen_sock; while (o2net_accept_one(sock) == 0) cond_resched(); } @@ -1700,7 +1709,7 @@ static int o2net_open_listening_sock(__be16 port) write_unlock_bh(&sock->sk->sk_callback_lock); o2net_listen_sock = sock; - INIT_WORK(&o2net_listen_work, o2net_accept_many, sock); + INIT_WORK(&o2net_listen_work, o2net_accept_many); sock->sk->sk_reuse = 1; ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin)); @@ -1819,9 +1828,10 @@ int o2net_init(void) struct o2net_node *nn = o2net_nn_from_num(i); spin_lock_init(&nn->nn_lock); - INIT_WORK(&nn->nn_connect_work, o2net_start_connect, nn); - INIT_WORK(&nn->nn_connect_expired, o2net_connect_expired, nn); - INIT_WORK(&nn->nn_still_up, o2net_still_up, nn); + INIT_DELAYED_WORK(&nn->nn_connect_work, o2net_start_connect); + INIT_DELAYED_WORK(&nn->nn_connect_expired, + o2net_connect_expired); + INIT_DELAYED_WORK(&nn->nn_still_up, o2net_still_up); /* until we see hb from a node we'll return einval */ nn->nn_persistent_error = -ENOTCONN; init_waitqueue_head(&nn->nn_sc_wq); diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h index 4b46aac7d243..daebbd3a2c8c 100644 --- a/fs/ocfs2/cluster/tcp_internal.h +++ b/fs/ocfs2/cluster/tcp_internal.h @@ -86,18 +86,18 @@ struct o2net_node { * connect attempt fails and so can be self-arming. shutdown is * careful to first mark the nn such that no connects will be attempted * before canceling delayed connect work and flushing the queue. */ - struct work_struct nn_connect_work; + struct delayed_work nn_connect_work; unsigned long nn_last_connect_attempt; /* this is queued as nodes come up and is canceled when a connection is * established. this expiring gives up on the node and errors out * transmits */ - struct work_struct nn_connect_expired; + struct delayed_work nn_connect_expired; /* after we give up on a socket we wait a while before deciding * that it is still heartbeating and that we should do some * quorum work */ - struct work_struct nn_still_up; + struct delayed_work nn_still_up; }; struct o2net_sock_container { @@ -129,7 +129,7 @@ struct o2net_sock_container { struct work_struct sc_shutdown_work; struct timer_list sc_idle_timeout; - struct work_struct sc_keepalive_work; + struct delayed_work sc_keepalive_work; unsigned sc_handshake_ok:1; diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h index fa968180b072..6b6ff76538c5 100644 --- a/fs/ocfs2/dlm/dlmcommon.h +++ b/fs/ocfs2/dlm/dlmcommon.h @@ -153,7 +153,7 @@ static inline struct hlist_head *dlm_lockres_hash(struct dlm_ctxt *dlm, unsigned * called functions that cannot be directly called from the * net message handlers for some reason, usually because * they need to send net messages of their own. */ -void dlm_dispatch_work(void *data); +void dlm_dispatch_work(struct work_struct *work); struct dlm_lock_resource; struct dlm_work_item; diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 8d1065f8b3bd..637646e6922e 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -1296,7 +1296,7 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain, spin_lock_init(&dlm->work_lock); INIT_LIST_HEAD(&dlm->work_list); - INIT_WORK(&dlm->dispatched_work, dlm_dispatch_work, dlm); + INIT_WORK(&dlm->dispatched_work, dlm_dispatch_work); kref_init(&dlm->dlm_refs); dlm->dlm_state = DLM_CTXT_NEW; diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 9d950d7cea38..fb3e2b0817f1 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -153,9 +153,10 @@ static inline void dlm_reset_recovery(struct dlm_ctxt *dlm) } /* Worker function used during recovery. */ -void dlm_dispatch_work(void *data) +void dlm_dispatch_work(struct work_struct *work) { - struct dlm_ctxt *dlm = (struct dlm_ctxt *)data; + struct dlm_ctxt *dlm = + container_of(work, struct dlm_ctxt, dispatched_work); LIST_HEAD(tmp_list); struct list_head *iter, *iter2; struct dlm_work_item *item; diff --git a/fs/ocfs2/dlm/userdlm.c b/fs/ocfs2/dlm/userdlm.c index eead48bbfac6..7d2f578b267d 100644 --- a/fs/ocfs2/dlm/userdlm.c +++ b/fs/ocfs2/dlm/userdlm.c @@ -171,15 +171,14 @@ static inline void user_dlm_grab_inode_ref(struct user_lock_res *lockres) BUG(); } -static void user_dlm_unblock_lock(void *opaque); +static void user_dlm_unblock_lock(struct work_struct *work); static void __user_dlm_queue_lockres(struct user_lock_res *lockres) { if (!(lockres->l_flags & USER_LOCK_QUEUED)) { user_dlm_grab_inode_ref(lockres); - INIT_WORK(&lockres->l_work, user_dlm_unblock_lock, - lockres); + INIT_WORK(&lockres->l_work, user_dlm_unblock_lock); queue_work(user_dlm_worker, &lockres->l_work); lockres->l_flags |= USER_LOCK_QUEUED; @@ -279,10 +278,11 @@ static inline void user_dlm_drop_inode_ref(struct user_lock_res *lockres) iput(inode); } -static void user_dlm_unblock_lock(void *opaque) +static void user_dlm_unblock_lock(struct work_struct *work) { int new_level, status; - struct user_lock_res *lockres = (struct user_lock_res *) opaque; + struct user_lock_res *lockres = + container_of(work, struct user_lock_res, l_work); struct dlm_ctxt *dlm = dlm_ctxt_from_user_lockres(lockres); mlog(0, "processing lockres %.*s\n", lockres->l_namelen, diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index fd9734def551..d95ee2720e6e 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -911,11 +911,12 @@ struct ocfs2_la_recovery_item { * NOTE: This function can and will sleep on recovery of other nodes * during cluster locking, just like any other ocfs2 process. */ -void ocfs2_complete_recovery(void *data) +void ocfs2_complete_recovery(struct work_struct *work) { int ret; - struct ocfs2_super *osb = data; - struct ocfs2_journal *journal = osb->journal; + struct ocfs2_journal *journal = + container_of(work, struct ocfs2_journal, j_recovery_work); + struct ocfs2_super *osb = journal->j_osb; struct ocfs2_dinode *la_dinode, *tl_dinode; struct ocfs2_la_recovery_item *item; struct list_head *p, *n; diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index 2f3a6acdac45..5be161a4ad9f 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -172,7 +172,7 @@ static inline void ocfs2_handle_set_sync(struct ocfs2_journal_handle *handle, in } /* Exported only for the journal struct init code in super.c. Do not call. */ -void ocfs2_complete_recovery(void *data); +void ocfs2_complete_recovery(struct work_struct *work); /* * Journal Control: diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 0462a7f4e21b..9b1bad1d48ec 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -283,7 +283,7 @@ struct ocfs2_super /* Truncate log info */ struct inode *osb_tl_inode; struct buffer_head *osb_tl_bh; - struct work_struct osb_truncate_log_wq; + struct delayed_work osb_truncate_log_wq; struct ocfs2_node_map osb_recovering_orphan_dirs; unsigned int *osb_orphan_wipes; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 76b46ebbb10c..9a8089030f55 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1365,7 +1365,7 @@ static int ocfs2_initialize_super(struct super_block *sb, spin_lock_init(&journal->j_lock); journal->j_trans_id = (unsigned long) 1; INIT_LIST_HEAD(&journal->j_la_cleanups); - INIT_WORK(&journal->j_recovery_work, ocfs2_complete_recovery, osb); + INIT_WORK(&journal->j_recovery_work, ocfs2_complete_recovery); journal->j_state = OCFS2_JOURNAL_FREE; /* get some pseudo constants for clustersize bits */ diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 85ce23268302..cd1bb75ceb24 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -104,7 +104,7 @@ static int release_journal_dev(struct super_block *super, struct reiserfs_journal *journal); static int dirty_one_transaction(struct super_block *s, struct reiserfs_journal_list *jl); -static void flush_async_commits(void *p); +static void flush_async_commits(struct work_struct *work); static void queue_log_writer(struct super_block *s); /* values for join in do_journal_begin_r */ @@ -2836,7 +2836,8 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, if (reiserfs_mounted_fs_count <= 1) commit_wq = create_workqueue("reiserfs"); - INIT_WORK(&journal->j_work, flush_async_commits, p_s_sb); + INIT_DELAYED_WORK(&journal->j_work, flush_async_commits); + journal->j_work_sb = p_s_sb; return 0; free_and_return: free_journal_ram(p_s_sb); @@ -3447,10 +3448,11 @@ int journal_end_sync(struct reiserfs_transaction_handle *th, /* ** writeback the pending async commits to disk */ -static void flush_async_commits(void *p) +static void flush_async_commits(struct work_struct *work) { - struct super_block *p_s_sb = p; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = + container_of(work, struct reiserfs_journal, j_work.work); + struct super_block *p_s_sb = journal->j_work_sb; struct reiserfs_journal_list *jl; struct list_head *entry; diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 09360cf1e1f2..8e6b56fc1cad 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -149,9 +149,10 @@ xfs_destroy_ioend( */ STATIC void xfs_end_bio_delalloc( - void *data) + struct work_struct *work) { - xfs_ioend_t *ioend = data; + xfs_ioend_t *ioend = + container_of(work, xfs_ioend_t, io_work); xfs_destroy_ioend(ioend); } @@ -161,9 +162,10 @@ xfs_end_bio_delalloc( */ STATIC void xfs_end_bio_written( - void *data) + struct work_struct *work) { - xfs_ioend_t *ioend = data; + xfs_ioend_t *ioend = + container_of(work, xfs_ioend_t, io_work); xfs_destroy_ioend(ioend); } @@ -176,9 +178,10 @@ xfs_end_bio_written( */ STATIC void xfs_end_bio_unwritten( - void *data) + struct work_struct *work) { - xfs_ioend_t *ioend = data; + xfs_ioend_t *ioend = + container_of(work, xfs_ioend_t, io_work); bhv_vnode_t *vp = ioend->io_vnode; xfs_off_t offset = ioend->io_offset; size_t size = ioend->io_size; @@ -220,11 +223,11 @@ xfs_alloc_ioend( ioend->io_size = 0; if (type == IOMAP_UNWRITTEN) - INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten, ioend); + INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten); else if (type == IOMAP_DELAY) - INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc, ioend); + INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc); else - INIT_WORK(&ioend->io_work, xfs_end_bio_written, ioend); + INIT_WORK(&ioend->io_work, xfs_end_bio_written); return ioend; } diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index d3382843698e..eef4a0ba11e9 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -994,9 +994,10 @@ xfs_buf_wait_unpin( STATIC void xfs_buf_iodone_work( - void *v) + struct work_struct *work) { - xfs_buf_t *bp = (xfs_buf_t *)v; + xfs_buf_t *bp = + container_of(work, xfs_buf_t, b_iodone_work); if (bp->b_iodone) (*(bp->b_iodone))(bp); @@ -1017,10 +1018,10 @@ xfs_buf_ioend( if ((bp->b_iodone) || (bp->b_flags & XBF_ASYNC)) { if (schedule) { - INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work, bp); + INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work); queue_work(xfslogd_workqueue, &bp->b_iodone_work); } else { - xfs_buf_iodone_work(bp); + xfs_buf_iodone_work(&bp->b_iodone_work); } } else { up(&bp->b_iodonesema); diff --git a/include/linux/connector.h b/include/linux/connector.h index 4c02119c6ab9..3ea1cd58de97 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h @@ -133,7 +133,7 @@ struct cn_callback_data { struct cn_callback_entry { struct list_head callback_entry; struct cn_callback *cb; - struct work_struct work; + struct delayed_work work; struct cn_queue_dev *pdev; struct cn_callback_id id; @@ -170,7 +170,7 @@ void cn_queue_free_dev(struct cn_queue_dev *dev); int cn_cb_equal(struct cb_id *, struct cb_id *); -void cn_queue_wrapper(void *data); +void cn_queue_wrapper(struct work_struct *work); extern int cn_already_initialized; diff --git a/include/linux/i2o.h b/include/linux/i2o.h index c115e9e840b4..1fb02e17f6f6 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -461,7 +461,7 @@ struct i2o_driver { int (*reply) (struct i2o_controller *, u32, struct i2o_message *); /* Event handler */ - void (*event) (struct i2o_event *); + work_func_t event; struct workqueue_struct *event_queue; /* Event queue */ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 587264a58d56..8b08ef3820f2 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -110,7 +110,7 @@ struct mmc_host { struct mmc_card *card_busy; /* the MMC card claiming host */ struct mmc_card *card_selected; /* the selected MMC card */ - struct work_struct detect; + struct delayed_work detect; unsigned long private[0] ____cacheline_aligned; }; diff --git a/include/linux/ncp_fs_sb.h b/include/linux/ncp_fs_sb.h index b089d9506283..a503052138bd 100644 --- a/include/linux/ncp_fs_sb.h +++ b/include/linux/ncp_fs_sb.h @@ -127,10 +127,10 @@ struct ncp_server { } unexpected_packet; }; -extern void ncp_tcp_rcv_proc(void *server); -extern void ncp_tcp_tx_proc(void *server); -extern void ncpdgram_rcv_proc(void *server); -extern void ncpdgram_timeout_proc(void *server); +extern void ncp_tcp_rcv_proc(struct work_struct *work); +extern void ncp_tcp_tx_proc(struct work_struct *work); +extern void ncpdgram_rcv_proc(struct work_struct *work); +extern void ncpdgram_timeout_proc(struct work_struct *work); extern void ncpdgram_timeout_call(unsigned long server); extern void ncp_tcp_data_ready(struct sock* sk, int len); extern void ncp_tcp_write_space(struct sock* sk); diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h index 73e0becec086..6610103f23e1 100644 --- a/include/linux/reiserfs_fs_sb.h +++ b/include/linux/reiserfs_fs_sb.h @@ -249,7 +249,8 @@ struct reiserfs_journal { int j_errno; /* when flushing ordered buffers, throttle new ordered writers */ - struct work_struct j_work; + struct delayed_work j_work; + struct super_block *j_work_sb; atomic_t j_async_throttle; }; diff --git a/include/linux/relay.h b/include/linux/relay.h index 24accb483849..0e3d91b76996 100644 --- a/include/linux/relay.h +++ b/include/linux/relay.h @@ -38,7 +38,7 @@ struct rchan_buf size_t subbufs_consumed; /* count of sub-buffers consumed */ struct rchan *chan; /* associated channel */ wait_queue_head_t read_wait; /* reader wait queue */ - struct work_struct wake_readers; /* reader wake-up work struct */ + struct delayed_work wake_readers; /* reader wake-up work struct */ struct dentry *dentry; /* channel file dentry */ struct kref kref; /* channel buffer refcount */ struct page **page_array; /* array of current buffer pages */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 5482bfb3303d..06ce7a626040 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -382,7 +382,7 @@ struct usb_device { int pm_usage_cnt; /* usage counter for autosuspend */ #ifdef CONFIG_PM - struct work_struct autosuspend; /* for delayed autosuspends */ + struct delayed_work autosuspend; /* for delayed autosuspends */ struct mutex pm_mutex; /* protects PM operations */ unsigned auto_pm:1; /* autosuspend/resume in progress */ diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h index 617b672b1132..89119277553d 100644 --- a/include/net/ieee80211softmac.h +++ b/include/net/ieee80211softmac.h @@ -108,8 +108,8 @@ struct ieee80211softmac_assoc_info { /* Scan retries remaining */ int scan_retry; - struct work_struct work; - struct work_struct timeout; + struct delayed_work work; + struct delayed_work timeout; }; struct ieee80211softmac_bss_info { diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index c6d93bb0dcd2..60b684470db8 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1030,7 +1030,7 @@ void sctp_inq_init(struct sctp_inq *); void sctp_inq_free(struct sctp_inq *); void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); -void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *); +void sctp_inq_set_th_handler(struct sctp_inq *, work_func_t); /* This is the structure we use to hold outbound chunks. You push * chunks in and they automatically pop out the other end as bundled diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 9582e8401669..9ccc0365aa89 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -200,9 +200,14 @@ struct domain_device { void *lldd_dev; }; +struct sas_discovery_event { + struct work_struct work; + struct asd_sas_port *port; +}; + struct sas_discovery { spinlock_t disc_event_lock; - struct work_struct disc_work[DISC_NUM_EVENTS]; + struct sas_discovery_event disc_work[DISC_NUM_EVENTS]; unsigned long pending; u8 fanout_sas_addr[8]; u8 eeds_a[8]; @@ -248,14 +253,19 @@ struct asd_sas_port { void *lldd_port; /* not touched by the sas class code */ }; +struct asd_sas_event { + struct work_struct work; + struct asd_sas_phy *phy; +}; + /* The phy pretty much is controlled by the LLDD. * The class only reads those fields. */ struct asd_sas_phy { /* private: */ /* protected by ha->event_lock */ - struct work_struct port_events[PORT_NUM_EVENTS]; - struct work_struct phy_events[PHY_NUM_EVENTS]; + struct asd_sas_event port_events[PORT_NUM_EVENTS]; + struct asd_sas_event phy_events[PHY_NUM_EVENTS]; unsigned long port_events_pending; unsigned long phy_events_pending; @@ -307,10 +317,15 @@ struct scsi_core { int queue_thread_kill; }; +struct sas_ha_event { + struct work_struct work; + struct sas_ha_struct *ha; +}; + struct sas_ha_struct { /* private: */ spinlock_t event_lock; - struct work_struct ha_events[HA_NUM_EVENTS]; + struct sas_ha_event ha_events[HA_NUM_EVENTS]; unsigned long pending; struct scsi_core core; diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index fd352323378b..798f7c7ee426 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -206,9 +206,9 @@ struct fc_rport { /* aka fc_starget_attrs */ u8 flags; struct list_head peers; struct device dev; - struct work_struct dev_loss_work; + struct delayed_work dev_loss_work; struct work_struct scan_work; - struct work_struct fail_io_work; + struct delayed_work fail_io_work; struct work_struct stgt_delete_work; struct work_struct rport_delete_work; } __attribute__((aligned(sizeof(unsigned long)))); diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 4b95c89c95c9..d5c218ddc527 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -176,7 +176,7 @@ struct iscsi_cls_session { /* recovery fields */ int recovery_tmo; - struct work_struct recovery_work; + struct delayed_work recovery_work; int target_id; diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 4c43521cc493..33720397a904 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -511,7 +511,7 @@ struct snd_ac97 { #ifdef CONFIG_SND_AC97_POWER_SAVE unsigned int power_up; /* power states */ struct workqueue_struct *power_workq; - struct work_struct power_work; + struct delayed_work power_work; #endif struct device dev; }; diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h index 11702aa0bea9..2ee061625fd0 100644 --- a/include/sound/ak4114.h +++ b/include/sound/ak4114.h @@ -182,7 +182,7 @@ struct ak4114 { unsigned char rcs0; unsigned char rcs1; struct workqueue_struct *workqueue; - struct work_struct work; + struct delayed_work work; void *change_callback_private; void (*change_callback)(struct ak4114 *ak4114, unsigned char c0, unsigned char c1); }; diff --git a/kernel/relay.c b/kernel/relay.c index f04bbdb56ac2..2b92e8ece85b 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -308,9 +308,10 @@ static struct rchan_callbacks default_channel_callbacks = { * reason waking is deferred is that calling directly from write * causes problems if you're writing from say the scheduler. */ -static void wakeup_readers(void *private) +static void wakeup_readers(struct work_struct *work) { - struct rchan_buf *buf = private; + struct rchan_buf *buf = + container_of(work, struct rchan_buf, wake_readers.work); wake_up_interruptible(&buf->read_wait); } @@ -328,7 +329,7 @@ static inline void __relay_reset(struct rchan_buf *buf, unsigned int init) if (init) { init_waitqueue_head(&buf->read_wait); kref_init(&buf->kref); - INIT_WORK(&buf->wake_readers, NULL, NULL); + INIT_DELAYED_WORK(&buf->wake_readers, NULL); } else { cancel_delayed_work(&buf->wake_readers); flush_scheduled_work(); @@ -549,7 +550,8 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length) buf->padding[old_subbuf]; smp_mb(); if (waitqueue_active(&buf->read_wait)) { - PREPARE_WORK(&buf->wake_readers, wakeup_readers, buf); + PREPARE_DELAYED_WORK(&buf->wake_readers, + wakeup_readers); schedule_delayed_work(&buf->wake_readers, 1); } } diff --git a/mm/swap.c b/mm/swap.c index 2e0e871f542f..d9a3770d8f3c 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -216,7 +216,7 @@ void lru_add_drain(void) } #ifdef CONFIG_NUMA -static void lru_add_drain_per_cpu(void *dummy) +static void lru_add_drain_per_cpu(struct work_struct *dummy) { lru_add_drain(); } @@ -226,7 +226,7 @@ static void lru_add_drain_per_cpu(void *dummy) */ int lru_add_drain_all(void) { - return schedule_on_each_cpu(lru_add_drain_per_cpu, NULL); + return schedule_on_each_cpu(lru_add_drain_per_cpu); } #else diff --git a/net/atm/lec.c b/net/atm/lec.c index 66c57c1091a8..e801fff69dc0 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -1458,7 +1458,7 @@ static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr, #define LEC_ARP_REFRESH_INTERVAL (3*HZ) -static void lec_arp_check_expire(void *data); +static void lec_arp_check_expire(struct work_struct *work); static void lec_arp_expire_arp(unsigned long data); /* @@ -1481,7 +1481,7 @@ static void lec_arp_init(struct lec_priv *priv) INIT_HLIST_HEAD(&priv->lec_no_forward); INIT_HLIST_HEAD(&priv->mcast_fwds); spin_lock_init(&priv->lec_arp_lock); - INIT_WORK(&priv->lec_arp_work, lec_arp_check_expire, priv); + INIT_DELAYED_WORK(&priv->lec_arp_work, lec_arp_check_expire); schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL); } @@ -1879,10 +1879,11 @@ static void lec_arp_expire_vcc(unsigned long data) * to ESI_FORWARD_DIRECT. This causes the flush period to end * regardless of the progress of the flush protocol. */ -static void lec_arp_check_expire(void *data) +static void lec_arp_check_expire(struct work_struct *work) { unsigned long flags; - struct lec_priv *priv = data; + struct lec_priv *priv = + container_of(work, struct lec_priv, lec_arp_work.work); struct hlist_node *node, *next; struct lec_arp_table *entry; unsigned long now; diff --git a/net/atm/lec.h b/net/atm/lec.h index 877f50939696..984e8e6e083a 100644 --- a/net/atm/lec.h +++ b/net/atm/lec.h @@ -92,7 +92,7 @@ struct lec_priv { spinlock_t lec_arp_lock; struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ struct atm_vcc *lecd; - struct work_struct lec_arp_work; /* C10 */ + struct delayed_work lec_arp_work; /* C10 */ unsigned int maximum_unknown_frame_count; /* * Within the period of time defined by this variable, the client will send diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 3eeeb7a86e75..d4c935692ccf 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -237,9 +237,9 @@ static void bt_release(struct device *dev) kfree(data); } -static void add_conn(void *data) +static void add_conn(struct work_struct *work) { - struct hci_conn *conn = data; + struct hci_conn *conn = container_of(work, struct hci_conn, work); int i; if (device_register(&conn->dev) < 0) { @@ -272,14 +272,14 @@ void hci_conn_add_sysfs(struct hci_conn *conn) dev_set_drvdata(&conn->dev, conn); - INIT_WORK(&conn->work, add_conn, (void *) conn); + INIT_WORK(&conn->work, add_conn); schedule_work(&conn->work); } -static void del_conn(void *data) +static void del_conn(struct work_struct *work) { - struct hci_conn *conn = data; + struct hci_conn *conn = container_of(work, struct hci_conn, work); device_del(&conn->dev); } @@ -287,7 +287,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn) { BT_DBG("conn %p", conn); - INIT_WORK(&conn->work, del_conn, (void *) conn); + INIT_WORK(&conn->work, del_conn); schedule_work(&conn->work); } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f753c40c11d2..55bb2634c088 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -77,12 +77,16 @@ static int port_cost(struct net_device *dev) * Called from work queue to allow for calling functions that * might sleep (such as speed check), and to debounce. */ -static void port_carrier_check(void *arg) +static void port_carrier_check(struct work_struct *work) { - struct net_device *dev = arg; struct net_bridge_port *p; + struct net_device *dev; struct net_bridge *br; + dev = container_of(work, struct net_bridge_port, + carrier_check.work)->dev; + work_release(work); + rtnl_lock(); p = dev->br_port; if (!p) @@ -276,7 +280,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, p->port_no = index; br_init_port(p); p->state = BR_STATE_DISABLED; - INIT_WORK(&p->carrier_check, port_carrier_check, dev); + INIT_DELAYED_WORK_NAR(&p->carrier_check, port_carrier_check); br_stp_port_timer_init(p); kobject_init(&p->kobj); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 74258d86f256..3a534e94c7f3 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -82,7 +82,7 @@ struct net_bridge_port struct timer_list hold_timer; struct timer_list message_age_timer; struct kobject kobj; - struct work_struct carrier_check; + struct delayed_work carrier_check; struct rcu_head rcu; }; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 6589adb14cbf..63f24c914ddb 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -56,7 +56,7 @@ static atomic_t trapped; static void zap_completion_queue(void); static void arp_reply(struct sk_buff *skb); -static void queue_process(void *p) +static void queue_process(struct work_struct *work) { unsigned long flags; struct sk_buff *skb; @@ -77,7 +77,7 @@ static void queue_process(void *p) } } -static DECLARE_WORK(send_queue, queue_process, NULL); +static DECLARE_WORK(send_queue, queue_process); void netpoll_queue(struct sk_buff *skb) { diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 9045438d6b36..36db5be2a9e9 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -31,8 +31,7 @@ struct inet_timewait_death_row dccp_death_row = { .tw_timer = TIMER_INITIALIZER(inet_twdr_hangman, 0, (unsigned long)&dccp_death_row), .twkill_work = __WORK_INITIALIZER(dccp_death_row.twkill_work, - inet_twdr_twkill_work, - &dccp_death_row), + inet_twdr_twkill_work), /* Short-time timewait calendar */ .twcal_hand = -1, diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index cf51c87a971d..08386c102954 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -58,9 +58,11 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft } void -ieee80211softmac_assoc_timeout(void *d) +ieee80211softmac_assoc_timeout(struct work_struct *work) { - struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d; + struct ieee80211softmac_device *mac = + container_of(work, struct ieee80211softmac_device, + associnfo.timeout.work); struct ieee80211softmac_network *n; mutex_lock(&mac->associnfo.mutex); @@ -186,9 +188,11 @@ ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void /* This function is called to handle userspace requests (asynchronously) */ void -ieee80211softmac_assoc_work(void *d) +ieee80211softmac_assoc_work(struct work_struct *work) { - struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d; + struct ieee80211softmac_device *mac = + container_of(work, struct ieee80211softmac_device, + associnfo.work.work); struct ieee80211softmac_network *found = NULL; struct ieee80211_network *net = NULL, *best = NULL; int bssvalid; @@ -412,7 +416,7 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev, network->authenticated = 0; /* we don't want to do this more than once ... */ network->auth_desynced_once = 1; - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); break; } default: @@ -446,7 +450,7 @@ ieee80211softmac_handle_disassoc(struct net_device * dev, ieee80211softmac_disassoc(mac); /* try to reassociate */ - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); return 0; } @@ -466,7 +470,7 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev, dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); return 0; } - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index 4cef39e171d0..2ae1833b657a 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c @@ -26,7 +26,7 @@ #include "ieee80211softmac_priv.h" -static void ieee80211softmac_auth_queue(void *data); +static void ieee80211softmac_auth_queue(struct work_struct *work); /* Queues an auth request to the desired AP */ int @@ -54,14 +54,14 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, auth->mac = mac; auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT; auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST; - INIT_WORK(&auth->work, &ieee80211softmac_auth_queue, (void *)auth); + INIT_DELAYED_WORK(&auth->work, ieee80211softmac_auth_queue); /* Lock (for list) */ spin_lock_irqsave(&mac->lock, flags); /* add to list */ list_add_tail(&auth->list, &mac->auth_queue); - schedule_work(&auth->work); + schedule_delayed_work(&auth->work, 0); spin_unlock_irqrestore(&mac->lock, flags); return 0; @@ -70,14 +70,15 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, /* Sends an auth request to the desired AP and handles timeouts */ static void -ieee80211softmac_auth_queue(void *data) +ieee80211softmac_auth_queue(struct work_struct *work) { struct ieee80211softmac_device *mac; struct ieee80211softmac_auth_queue_item *auth; struct ieee80211softmac_network *net; unsigned long flags; - auth = (struct ieee80211softmac_auth_queue_item *)data; + auth = container_of(work, struct ieee80211softmac_auth_queue_item, + work.work); net = auth->net; mac = auth->mac; @@ -118,9 +119,11 @@ ieee80211softmac_auth_queue(void *data) /* Sends a response to an auth challenge (for shared key auth). */ static void -ieee80211softmac_auth_challenge_response(void *_aq) +ieee80211softmac_auth_challenge_response(struct work_struct *work) { - struct ieee80211softmac_auth_queue_item *aq = _aq; + struct ieee80211softmac_auth_queue_item *aq = + container_of(work, struct ieee80211softmac_auth_queue_item, + work.work); /* Send our response */ ieee80211softmac_send_mgt_frame(aq->mac, aq->net, IEEE80211_STYPE_AUTH, aq->state); @@ -228,8 +231,8 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) * we have obviously already sent the initial auth * request. */ cancel_delayed_work(&aq->work); - INIT_WORK(&aq->work, &ieee80211softmac_auth_challenge_response, (void *)aq); - schedule_work(&aq->work); + INIT_DELAYED_WORK(&aq->work, &ieee80211softmac_auth_challenge_response); + schedule_delayed_work(&aq->work, 0); spin_unlock_irqrestore(&mac->lock, flags); return 0; case IEEE80211SOFTMAC_AUTH_SHARED_PASS: @@ -392,6 +395,6 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de ieee80211softmac_deauth_from_net(mac, net); /* let's try to re-associate */ - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c index f34fa2ef666b..b9015656cfb3 100644 --- a/net/ieee80211/softmac/ieee80211softmac_event.c +++ b/net/ieee80211/softmac/ieee80211softmac_event.c @@ -73,10 +73,12 @@ static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = { static void -ieee80211softmac_notify_callback(void *d) +ieee80211softmac_notify_callback(struct work_struct *work) { - struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d; - kfree(d); + struct ieee80211softmac_event *pevent = + container_of(work, struct ieee80211softmac_event, work.work); + struct ieee80211softmac_event event = *pevent; + kfree(pevent); event.fun(event.mac->dev, event.event_type, event.context); } @@ -99,7 +101,7 @@ ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac, return -ENOMEM; eventptr->event_type = event; - INIT_WORK(&eventptr->work, ieee80211softmac_notify_callback, eventptr); + INIT_DELAYED_WORK(&eventptr->work, ieee80211softmac_notify_callback); eventptr->fun = fun; eventptr->context = context; eventptr->mac = mac; @@ -170,7 +172,7 @@ ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int eve /* User may have subscribed to ANY event, so * we tell them which event triggered it. */ eventptr->event_type = event; - schedule_work(&eventptr->work); + schedule_delayed_work(&eventptr->work, 0); } } } diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c index 33aff4f4a471..256207b71dc9 100644 --- a/net/ieee80211/softmac/ieee80211softmac_module.c +++ b/net/ieee80211/softmac/ieee80211softmac_module.c @@ -58,8 +58,8 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv) INIT_LIST_HEAD(&softmac->events); mutex_init(&softmac->associnfo.mutex); - INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac); - INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac); + INIT_DELAYED_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work); + INIT_DELAYED_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout); softmac->start_scan = ieee80211softmac_start_scan_implementation; softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation; softmac->stop_scan = ieee80211softmac_stop_scan_implementation; diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h index 0642e090b8a7..c0dbe070e548 100644 --- a/net/ieee80211/softmac/ieee80211softmac_priv.h +++ b/net/ieee80211/softmac/ieee80211softmac_priv.h @@ -78,7 +78,7 @@ /* private definitions and prototypes */ /*** prototypes from _scan.c */ -void ieee80211softmac_scan(void *sm); +void ieee80211softmac_scan(struct work_struct *work); /* for internal use if scanning is needed */ int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac); void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac); @@ -149,7 +149,7 @@ int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *au int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth); /*** prototypes from _assoc.c */ -void ieee80211softmac_assoc_work(void *d); +void ieee80211softmac_assoc_work(struct work_struct *work); int ieee80211softmac_handle_assoc_response(struct net_device * dev, struct ieee80211_assoc_response * resp, struct ieee80211_network * network); @@ -157,7 +157,7 @@ int ieee80211softmac_handle_disassoc(struct net_device * dev, struct ieee80211_disassoc * disassoc); int ieee80211softmac_handle_reassoc_req(struct net_device * dev, struct ieee80211_reassoc_request * reassoc); -void ieee80211softmac_assoc_timeout(void *d); +void ieee80211softmac_assoc_timeout(struct work_struct *work); void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason); void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac); @@ -207,7 +207,7 @@ struct ieee80211softmac_auth_queue_item { struct ieee80211softmac_device *mac; /* SoftMAC device */ u8 retry; /* Retry limit */ u8 state; /* Auth State */ - struct work_struct work; /* Work queue */ + struct delayed_work work; /* Work queue */ }; /* scanning information */ @@ -219,7 +219,8 @@ struct ieee80211softmac_scaninfo { stop:1; u8 skip_flags; struct completion finished; - struct work_struct softmac_scan; + struct delayed_work softmac_scan; + struct ieee80211softmac_device *mac; }; /* private event struct */ @@ -227,7 +228,7 @@ struct ieee80211softmac_event { struct list_head list; int event_type; void *event_context; - struct work_struct work; + struct delayed_work work; notify_function_ptr fun; void *context; struct ieee80211softmac_device *mac; diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c index d31cf77498c4..a8326076581a 100644 --- a/net/ieee80211/softmac/ieee80211softmac_scan.c +++ b/net/ieee80211/softmac/ieee80211softmac_scan.c @@ -91,12 +91,14 @@ ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm) /* internal scanning implementation follows */ -void ieee80211softmac_scan(void *d) +void ieee80211softmac_scan(struct work_struct *work) { int invalid_channel; u8 current_channel_idx; - struct ieee80211softmac_device *sm = (struct ieee80211softmac_device *)d; - struct ieee80211softmac_scaninfo *si = sm->scaninfo; + struct ieee80211softmac_scaninfo *si = + container_of(work, struct ieee80211softmac_scaninfo, + softmac_scan.work); + struct ieee80211softmac_device *sm = si->mac; unsigned long flags; while (!(si->stop) && (si->current_channel_idx < si->number_channels)) { @@ -146,7 +148,8 @@ static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee802 struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC); if (unlikely(!info)) return NULL; - INIT_WORK(&info->softmac_scan, ieee80211softmac_scan, mac); + INIT_DELAYED_WORK(&info->softmac_scan, ieee80211softmac_scan); + info->mac = mac; init_completion(&info->finished); return info; } @@ -189,7 +192,7 @@ int ieee80211softmac_start_scan_implementation(struct net_device *dev) sm->scaninfo->started = 1; sm->scaninfo->stop = 0; INIT_COMPLETION(sm->scaninfo->finished); - schedule_work(&sm->scaninfo->softmac_scan); + schedule_delayed_work(&sm->scaninfo->softmac_scan, 0); spin_unlock_irqrestore(&sm->lock, flags); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c index 23068a830f7d..2ffaebd21c53 100644 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c @@ -122,7 +122,7 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev, sm->associnfo.associating = 1; /* queue lower level code to do work (if necessary) */ - schedule_work(&sm->associnfo.work); + schedule_delayed_work(&sm->associnfo.work, 0); out: mutex_unlock(&sm->associnfo.mutex); @@ -356,7 +356,7 @@ ieee80211softmac_wx_set_wap(struct net_device *net_dev, /* force reassociation */ mac->associnfo.bssvalid = 0; if (mac->associnfo.associated) - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); } else if (is_zero_ether_addr(data->ap_addr.sa_data)) { /* the bssid we have is no longer fixed */ mac->associnfo.bssfixed = 0; @@ -373,7 +373,7 @@ ieee80211softmac_wx_set_wap(struct net_device *net_dev, /* tell the other code that this bssid should be used no matter what */ mac->associnfo.bssfixed = 1; /* queue associate if new bssid or (old one again and not associated) */ - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); } out: diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index f261616e4602..9b933381ebbe 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c @@ -221,10 +221,10 @@ static void update_defense_level(void) * Timer for checking the defense */ #define DEFENSE_TIMER_PERIOD 1*HZ -static void defense_work_handler(void *data); -static DECLARE_WORK(defense_work, defense_work_handler, NULL); +static void defense_work_handler(struct work_struct *work); +static DECLARE_DELAYED_WORK(defense_work, defense_work_handler); -static void defense_work_handler(void *data) +static void defense_work_handler(struct work_struct *work) { update_defense_level(); if (atomic_read(&ip_vs_dropentry)) diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index d50a02030ad7..262bda808d96 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -61,7 +61,7 @@ static void ircomm_tty_flush_buffer(struct tty_struct *tty); static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch); static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout); static void ircomm_tty_hangup(struct tty_struct *tty); -static void ircomm_tty_do_softint(void *private_); +static void ircomm_tty_do_softint(struct work_struct *work); static void ircomm_tty_shutdown(struct ircomm_tty_cb *self); static void ircomm_tty_stop(struct tty_struct *tty); @@ -389,7 +389,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) self->flow = FLOW_STOP; self->line = line; - INIT_WORK(&self->tqueue, ircomm_tty_do_softint, self); + INIT_WORK(&self->tqueue, ircomm_tty_do_softint); self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED; self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED; self->close_delay = 5*HZ/10; @@ -594,15 +594,16 @@ static void ircomm_tty_flush_buffer(struct tty_struct *tty) } /* - * Function ircomm_tty_do_softint (private_) + * Function ircomm_tty_do_softint (work) * * We use this routine to give the write wakeup to the user at at a * safe time (as fast as possible after write have completed). This * can be compared to the Tx interrupt. */ -static void ircomm_tty_do_softint(void *private_) +static void ircomm_tty_do_softint(struct work_struct *work) { - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) private_; + struct ircomm_tty_cb *self = + container_of(work, struct ircomm_tty_cb, tqueue); struct tty_struct *tty; unsigned long flags; struct sk_buff *skb, *ctrl_skb; diff --git a/net/sctp/associola.c b/net/sctp/associola.c index ed0445fe85e7..88124696ba60 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -61,7 +61,7 @@ #include /* Forward declarations for internal functions. */ -static void sctp_assoc_bh_rcv(struct sctp_association *asoc); +static void sctp_assoc_bh_rcv(struct work_struct *work); /* 1st Level Abstractions. */ @@ -269,9 +269,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a /* Create an input queue. */ sctp_inq_init(&asoc->base.inqueue); - sctp_inq_set_th_handler(&asoc->base.inqueue, - (void (*)(void *))sctp_assoc_bh_rcv, - asoc); + sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_assoc_bh_rcv); /* Create an output queue. */ sctp_outq_init(asoc, &asoc->outqueue); @@ -944,8 +942,11 @@ out: } /* Do delayed input processing. This is scheduled by sctp_rcv(). */ -static void sctp_assoc_bh_rcv(struct sctp_association *asoc) +static void sctp_assoc_bh_rcv(struct work_struct *work) { + struct sctp_association *asoc = + container_of(work, struct sctp_association, + base.inqueue.immediate); struct sctp_endpoint *ep; struct sctp_chunk *chunk; struct sock *sk; diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 9b6b394b66f6..a2b553721514 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -61,7 +61,7 @@ #include /* Forward declarations for internal helpers. */ -static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep); +static void sctp_endpoint_bh_rcv(struct work_struct *work); /* * Initialize the base fields of the endpoint structure. @@ -85,8 +85,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, sctp_inq_init(&ep->base.inqueue); /* Set its top-half handler */ - sctp_inq_set_th_handler(&ep->base.inqueue, - (void (*)(void *))sctp_endpoint_bh_rcv, ep); + sctp_inq_set_th_handler(&ep->base.inqueue, sctp_endpoint_bh_rcv); /* Initialize the bind addr area */ sctp_bind_addr_init(&ep->base.bind_addr, 0); @@ -311,8 +310,11 @@ int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep, /* Do delayed input processing. This is scheduled by sctp_rcv(). * This may be called on BH or task time. */ -static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep) +static void sctp_endpoint_bh_rcv(struct work_struct *work) { + struct sctp_endpoint *ep = + container_of(work, struct sctp_endpoint, + base.inqueue.immediate); struct sctp_association *asoc; struct sock *sk; struct sctp_transport *transport; diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index cf6deed7e849..71b07466e880 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -54,7 +54,7 @@ void sctp_inq_init(struct sctp_inq *queue) queue->in_progress = NULL; /* Create a task for delivering data. */ - INIT_WORK(&queue->immediate, NULL, NULL); + INIT_WORK(&queue->immediate, NULL); queue->malloced = 0; } @@ -97,7 +97,7 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk) * on the BH related data structures. */ list_add_tail(&chunk->list, &q->in_chunk_list); - q->immediate.func(q->immediate.data); + q->immediate.func(&q->immediate); } /* Extract a chunk from an SCTP inqueue. @@ -205,9 +205,8 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) * The intent is that this routine will pull stuff out of the * inqueue and process it. */ -void sctp_inq_set_th_handler(struct sctp_inq *q, - void (*callback)(void *), void *arg) +void sctp_inq_set_th_handler(struct sctp_inq *q, work_func_t callback) { - INIT_WORK(&q->immediate, callback, arg); + INIT_WORK(&q->immediate, callback); } diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 7736b23c3f03..ba924d40df7d 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -358,7 +358,7 @@ static void xfrm_policy_gc_kill(struct xfrm_policy *policy) xfrm_pol_put(policy); } -static void xfrm_policy_gc_task(void *data) +static void xfrm_policy_gc_task(struct work_struct *work) { struct xfrm_policy *policy; struct hlist_node *entry, *tmp; @@ -546,7 +546,7 @@ static inline int xfrm_byidx_should_resize(int total) static DEFINE_MUTEX(hash_resize_mutex); -static void xfrm_hash_resize(void *__unused) +static void xfrm_hash_resize(struct work_struct *__unused) { int dir, total; @@ -563,7 +563,7 @@ static void xfrm_hash_resize(void *__unused) mutex_unlock(&hash_resize_mutex); } -static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL); +static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize); /* Generate new index... KAME seems to generate them ordered by cost * of an absolute inpredictability of ordering of rules. This will not pass. */ @@ -2080,7 +2080,7 @@ static void __init xfrm_policy_init(void) panic("XFRM: failed to allocate bydst hash\n"); } - INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL); + INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); register_netdevice_notifier(&xfrm_dev_notifier); } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 899de9ed22a6..40c527179843 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -115,7 +115,7 @@ static unsigned long xfrm_hash_new_size(void) static DEFINE_MUTEX(hash_resize_mutex); -static void xfrm_hash_resize(void *__unused) +static void xfrm_hash_resize(struct work_struct *__unused) { struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; unsigned long nsize, osize; @@ -168,7 +168,7 @@ out_unlock: mutex_unlock(&hash_resize_mutex); } -static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL); +static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize); DECLARE_WAIT_QUEUE_HEAD(km_waitq); EXPORT_SYMBOL(km_waitq); @@ -207,7 +207,7 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) kfree(x); } -static void xfrm_state_gc_task(void *data) +static void xfrm_state_gc_task(struct work_struct *data) { struct xfrm_state *x; struct hlist_node *entry, *tmp; @@ -1568,6 +1568,6 @@ void __init xfrm_state_init(void) panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); - INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL); + INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task); } diff --git a/sound/aoa/aoa-gpio.h b/sound/aoa/aoa-gpio.h index 3a61f3115573..ee64f5de8966 100644 --- a/sound/aoa/aoa-gpio.h +++ b/sound/aoa/aoa-gpio.h @@ -59,10 +59,10 @@ struct gpio_methods { }; struct gpio_notification { + struct delayed_work work; notify_func_t notify; void *data; void *gpio_private; - struct work_struct work; struct mutex mutex; }; diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c index 40eb47eccf9a..2b03bc798bcb 100644 --- a/sound/aoa/core/snd-aoa-gpio-feature.c +++ b/sound/aoa/core/snd-aoa-gpio-feature.c @@ -195,9 +195,10 @@ static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt) ftr_gpio_set_lineout(rt, (s>>2)&1); } -static void ftr_handle_notify(void *data) +static void ftr_handle_notify(struct work_struct *work) { - struct gpio_notification *notif = data; + struct gpio_notification *notif = + container_of(work, struct gpio_notification, work.work); mutex_lock(¬if->mutex); if (notif->notify) @@ -253,12 +254,9 @@ static void ftr_gpio_init(struct gpio_runtime *rt) ftr_gpio_all_amps_off(rt); rt->implementation_private = 0; - INIT_WORK(&rt->headphone_notify.work, ftr_handle_notify, - &rt->headphone_notify); - INIT_WORK(&rt->line_in_notify.work, ftr_handle_notify, - &rt->line_in_notify); - INIT_WORK(&rt->line_out_notify.work, ftr_handle_notify, - &rt->line_out_notify); + INIT_DELAYED_WORK(&rt->headphone_notify.work, ftr_handle_notify); + INIT_DELAYED_WORK(&rt->line_in_notify.work, ftr_handle_notify); + INIT_DELAYED_WORK(&rt->line_out_notify.work, ftr_handle_notify); mutex_init(&rt->headphone_notify.mutex); mutex_init(&rt->line_in_notify.mutex); mutex_init(&rt->line_out_notify.mutex); @@ -287,7 +285,7 @@ static irqreturn_t ftr_handle_notify_irq(int xx, void *data) { struct gpio_notification *notif = data; - schedule_work(¬if->work); + schedule_delayed_work(¬if->work, 0); return IRQ_HANDLED; } diff --git a/sound/aoa/core/snd-aoa-gpio-pmf.c b/sound/aoa/core/snd-aoa-gpio-pmf.c index 2836c3218391..5ca2220eac7d 100644 --- a/sound/aoa/core/snd-aoa-gpio-pmf.c +++ b/sound/aoa/core/snd-aoa-gpio-pmf.c @@ -69,9 +69,10 @@ static void pmf_gpio_all_amps_restore(struct gpio_runtime *rt) pmf_gpio_set_lineout(rt, (s>>2)&1); } -static void pmf_handle_notify(void *data) +static void pmf_handle_notify(struct work_struct *work) { - struct gpio_notification *notif = data; + struct gpio_notification *notif = + container_of(work, struct gpio_notification, work.work); mutex_lock(¬if->mutex); if (notif->notify) @@ -83,12 +84,9 @@ static void pmf_gpio_init(struct gpio_runtime *rt) { pmf_gpio_all_amps_off(rt); rt->implementation_private = 0; - INIT_WORK(&rt->headphone_notify.work, pmf_handle_notify, - &rt->headphone_notify); - INIT_WORK(&rt->line_in_notify.work, pmf_handle_notify, - &rt->line_in_notify); - INIT_WORK(&rt->line_out_notify.work, pmf_handle_notify, - &rt->line_out_notify); + INIT_DELAYED_WORK(&rt->headphone_notify.work, pmf_handle_notify); + INIT_DELAYED_WORK(&rt->line_in_notify.work, pmf_handle_notify); + INIT_DELAYED_WORK(&rt->line_out_notify.work, pmf_handle_notify); mutex_init(&rt->headphone_notify.mutex); mutex_init(&rt->line_in_notify.mutex); mutex_init(&rt->line_out_notify.mutex); @@ -129,7 +127,7 @@ static void pmf_handle_notify_irq(void *data) { struct gpio_notification *notif = data; - schedule_work(¬if->work); + schedule_delayed_work(¬if->work, 0); } static int pmf_set_notify(struct gpio_runtime *rt, diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 12ffffc9e814..d2f2c5078e65 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -35,7 +35,7 @@ MODULE_LICENSE("GPL"); #define AK4114_ADDR 0x00 /* fixed address */ -static void ak4114_stats(void *); +static void ak4114_stats(struct work_struct *work); static void reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char val) { @@ -158,7 +158,7 @@ void snd_ak4114_reinit(struct ak4114 *chip) reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN); /* bring up statistics / event queing */ chip->init = 0; - INIT_WORK(&chip->work, ak4114_stats, chip); + INIT_DELAYED_WORK(&chip->work, ak4114_stats); queue_delayed_work(chip->workqueue, &chip->work, HZ / 10); } @@ -561,9 +561,9 @@ int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags) return res; } -static void ak4114_stats(void *data) +static void ak4114_stats(struct work_struct *work) { - struct ak4114 *chip = (struct ak4114 *)data; + struct ak4114 *chip = container_of(work, struct ak4114, work.work); if (chip->init) return; diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 6577b2325357..7abcb10b2754 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1927,9 +1927,10 @@ static int snd_ac97_dev_disconnect(struct snd_device *device) static struct snd_ac97_build_ops null_build_ops; #ifdef CONFIG_SND_AC97_POWER_SAVE -static void do_update_power(void *data) +static void do_update_power(struct work_struct *work) { - update_power_regs(data); + update_power_regs( + container_of(work, struct snd_ac97, power_work.work)); } #endif @@ -1989,7 +1990,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, mutex_init(&ac97->page_mutex); #ifdef CONFIG_SND_AC97_POWER_SAVE ac97->power_workq = create_workqueue("ac97"); - INIT_WORK(&ac97->power_work, do_update_power, ac97); + INIT_DELAYED_WORK(&ac97->power_work, do_update_power); #endif #ifdef CONFIG_PCI diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9c3d7ac08068..71482c15a852 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -272,10 +272,11 @@ EXPORT_SYMBOL(snd_hda_queue_unsol_event); /* * process queueud unsolicited events */ -static void process_unsol_events(void *data) +static void process_unsol_events(struct work_struct *work) { - struct hda_bus *bus = data; - struct hda_bus_unsolicited *unsol = bus->unsol; + struct hda_bus_unsolicited *unsol = + container_of(work, struct hda_bus_unsolicited, work); + struct hda_bus *bus = unsol->bus; struct hda_codec *codec; unsigned int rp, caddr, res; @@ -314,7 +315,8 @@ static int init_unsol_queue(struct hda_bus *bus) kfree(unsol); return -ENOMEM; } - INIT_WORK(&unsol->work, process_unsol_events, bus); + INIT_WORK(&unsol->work, process_unsol_events); + unsol->bus = bus; bus->unsol = unsol; return 0; } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index f9416c36396e..9ca1baf860bd 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -206,6 +206,7 @@ struct hda_bus_unsolicited { /* workqueue */ struct workqueue_struct *workq; struct work_struct work; + struct hda_bus *bus; }; /* diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 2fbe1d183fce..8f074c7936e6 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -942,10 +942,11 @@ static void check_mute(struct snd_pmac *chip, struct pmac_gpio *gp, int val, int } static struct work_struct device_change; +static struct snd_pmac *device_change_chip; -static void device_change_handler(void *self) +static void device_change_handler(struct work_struct *work) { - struct snd_pmac *chip = self; + struct snd_pmac *chip = device_change_chip; struct pmac_tumbler *mix; int headphone, lineout; @@ -1417,7 +1418,8 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip) chip->resume = tumbler_resume; #endif - INIT_WORK(&device_change, device_change_handler, (void *)chip); + INIT_WORK(&device_change, device_change_handler); + device_change_chip = chip; #ifdef PMAC_SUPPORT_AUTOMUTE if ((mix->headphone_irq >=0 || mix->lineout_irq >= 0) -- cgit v1.2.3 From ed7b1f6d6ea1054ea4fe293a7fd8015fc3803d93 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Nov 2006 23:34:49 -0500 Subject: Input: serio - make serio_register_driver() return errors Perform actual driver registration right in serio_register_driver() instead of offloading it to kseriod and return proper error code to callers if driver registration fails. Note that driver <-> port matching is still done by kseriod to speed up boot process since probing for PS/2 mice and keyboards is pretty slow. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 107 ++++++++++++++++++++++++++++++-------------- include/linux/serio.h | 7 +-- 2 files changed, 75 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index cd55ddb7df4f..8c717042f611 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -44,7 +44,7 @@ EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_child_port); -EXPORT_SYMBOL(__serio_register_driver); +EXPORT_SYMBOL(serio_register_driver); EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_close); @@ -61,10 +61,10 @@ static LIST_HEAD(serio_list); static struct bus_type serio_bus; -static void serio_add_driver(struct serio_driver *drv); static void serio_add_port(struct serio *serio); static void serio_reconnect_port(struct serio *serio); static void serio_disconnect_port(struct serio *serio); +static void serio_attach_driver(struct serio_driver *drv); static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) { @@ -168,10 +168,10 @@ static void serio_find_driver(struct serio *serio) */ enum serio_event_type { - SERIO_RESCAN, - SERIO_RECONNECT, + SERIO_RESCAN_PORT, + SERIO_RECONNECT_PORT, SERIO_REGISTER_PORT, - SERIO_REGISTER_DRIVER, + SERIO_ATTACH_DRIVER, }; struct serio_event { @@ -186,11 +186,12 @@ static LIST_HEAD(serio_event_list); static DECLARE_WAIT_QUEUE_HEAD(serio_wait); static struct task_struct *serio_task; -static void serio_queue_event(void *object, struct module *owner, - enum serio_event_type event_type) +static int serio_queue_event(void *object, struct module *owner, + enum serio_event_type event_type) { unsigned long flags; struct serio_event *event; + int retval = 0; spin_lock_irqsave(&serio_event_lock, flags); @@ -209,24 +210,34 @@ static void serio_queue_event(void *object, struct module *owner, } } - if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { - if (!try_module_get(owner)) { - printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type); - kfree(event); - goto out; - } - - event->type = event_type; - event->object = object; - event->owner = owner; + event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC); + if (!event) { + printk(KERN_ERR + "serio: Not enough memory to queue event %d\n", + event_type); + retval = -ENOMEM; + goto out; + } - list_add_tail(&event->node, &serio_event_list); - wake_up(&serio_wait); - } else { - printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type); + if (!try_module_get(owner)) { + printk(KERN_WARNING + "serio: Can't get module reference, dropping event %d\n", + event_type); + kfree(event); + retval = -EINVAL; + goto out; } + + event->type = event_type; + event->object = object; + event->owner = owner; + + list_add_tail(&event->node, &serio_event_list); + wake_up(&serio_wait); + out: spin_unlock_irqrestore(&serio_event_lock, flags); + return retval; } static void serio_free_event(struct serio_event *event) @@ -304,17 +315,17 @@ static void serio_handle_event(void) serio_add_port(event->object); break; - case SERIO_RECONNECT: + case SERIO_RECONNECT_PORT: serio_reconnect_port(event->object); break; - case SERIO_RESCAN: + case SERIO_RESCAN_PORT: serio_disconnect_port(event->object); serio_find_driver(event->object); break; - case SERIO_REGISTER_DRIVER: - serio_add_driver(event->object); + case SERIO_ATTACH_DRIVER: + serio_attach_driver(event->object); break; default: @@ -666,12 +677,12 @@ static void serio_disconnect_port(struct serio *serio) void serio_rescan(struct serio *serio) { - serio_queue_event(serio, NULL, SERIO_RESCAN); + serio_queue_event(serio, NULL, SERIO_RESCAN_PORT); } void serio_reconnect(struct serio *serio) { - serio_queue_event(serio, NULL, SERIO_RECONNECT); + serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); } /* @@ -766,22 +777,52 @@ static int serio_driver_remove(struct device *dev) return 0; } -static void serio_add_driver(struct serio_driver *drv) +static void serio_attach_driver(struct serio_driver *drv) { int error; - error = driver_register(&drv->driver); + error = driver_attach(&drv->driver); if (error) - printk(KERN_ERR - "serio: driver_register() failed for %s, error: %d\n", + printk(KERN_WARNING + "serio: driver_attach() failed for %s with error %d\n", drv->driver.name, error); } -void __serio_register_driver(struct serio_driver *drv, struct module *owner) +int serio_register_driver(struct serio_driver *drv) { + int manual_bind = drv->manual_bind; + int error; + drv->driver.bus = &serio_bus; - serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER); + /* + * Temporarily disable automatic binding because probing + * takes long time and we are better off doing it in kseriod + */ + drv->manual_bind = 1; + + error = driver_register(&drv->driver); + if (error) { + printk(KERN_ERR + "serio: driver_register() failed for %s, error: %d\n", + drv->driver.name, error); + return error; + } + + /* + * Restore original bind mode and let kseriod bind the + * driver to free ports + */ + if (!manual_bind) { + drv->manual_bind = 0; + error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER); + if (error) { + driver_unregister(&drv->driver); + return error; + } + } + + return 0; } void serio_unregister_driver(struct serio_driver *drv) diff --git a/include/linux/serio.h b/include/linux/serio.h index 8f52228390ab..0f478a8791a2 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -86,12 +86,7 @@ static inline void serio_register_port(struct serio *serio) void serio_unregister_port(struct serio *serio); void serio_unregister_child_port(struct serio *serio); -void __serio_register_driver(struct serio_driver *drv, struct module *owner); -static inline void serio_register_driver(struct serio_driver *drv) -{ - __serio_register_driver(drv, THIS_MODULE); -} - +int serio_register_driver(struct serio_driver *drv); void serio_unregister_driver(struct serio_driver *drv); static inline int serio_write(struct serio *serio, unsigned char data) -- cgit v1.2.3 From e4477d2d1bc3e6c76e83926f7fa8c8f94ba42615 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 24 Nov 2006 00:43:09 -0500 Subject: Input: add to kernel-api docbook Add input subsystem to kernel-api docbook. Enhance some function and parameter comments. Signed-off-by: Randy Dunlap Signed-off-by: Dmitry Torokhov --- Documentation/DocBook/kernel-api.tmpl | 8 ++++++++ drivers/input/ff-core.c | 4 ++-- drivers/input/ff-memless.c | 2 +- include/linux/input.h | 18 +++++++++--------- 4 files changed, 20 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index a166675c4303..a1af278f9901 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -533,4 +533,12 @@ X!Idrivers/video/console/fonts.c --> + + + Input Subsystem +!Iinclude/linux/input.h +!Edrivers/input/input.c +!Edrivers/input/ff-core.c +!Edrivers/input/ff-memless.c + diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 35656cadc914..783b3412cead 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -203,7 +203,7 @@ static int erase_effect(struct input_dev *dev, int effect_id, } /** - * input_ff_erase - erase an effect from device + * input_ff_erase - erase a force-feedback effect from device * @dev: input device to erase effect from * @effect_id: id of the ffect to be erased * @file: purported owner of the request @@ -347,7 +347,7 @@ EXPORT_SYMBOL_GPL(input_ff_create); /** * input_ff_free() - frees force feedback portion of input device - * @dev: input device supporintg force feedback + * @dev: input device supporting force feedback * * This function is only needed in error path as input core will * automatically free force feedback structures when device is diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index cd8b7297e6df..eba18b6ac5e4 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -460,7 +460,7 @@ static void ml_ff_destroy(struct ff_device *ff) } /** - * input_ff_create_memless() - create memoryless FF device + * input_ff_create_memless() - create memoryless force-feedback device * @dev: input device supporting force-feedback * @data: driver-specific data to be passed into @play_effect * @play_effect: driver-specific method for playing FF effect diff --git a/include/linux/input.h b/include/linux/input.h index c38507ba38b5..4e61158b06a0 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -663,7 +663,7 @@ struct input_absinfo { #define BUS_GSC 0x1A /* - * Values describing the status of an effect + * Values describing the status of a force-feedback effect */ #define FF_STATUS_STOPPED 0x00 #define FF_STATUS_PLAYING 0x01 @@ -680,7 +680,7 @@ struct input_absinfo { */ /** - * struct ff_replay - defines scheduling of the effect + * struct ff_replay - defines scheduling of the force-feedback effect * @length: duration of the effect * @delay: delay before effect should start playing */ @@ -690,7 +690,7 @@ struct ff_replay { }; /** - * struct ff_trigger - defines what triggers the effect + * struct ff_trigger - defines what triggers the force-feedback effect * @button: number of the button triggering the effect * @interval: controls how soon the effect can be re-triggered */ @@ -700,7 +700,7 @@ struct ff_trigger { }; /** - * struct ff_envelope - generic effect envelope + * struct ff_envelope - generic force-feedback effect envelope * @attack_length: duration of the attack (ms) * @attack_level: level at the beginning of the attack * @fade_length: duration of fade (ms) @@ -719,7 +719,7 @@ struct ff_envelope { }; /** - * struct ff_constant_effect - defines parameters of a constant effect + * struct ff_constant_effect - defines parameters of a constant force-feedback effect * @level: strength of the effect; may be negative * @envelope: envelope data */ @@ -729,7 +729,7 @@ struct ff_constant_effect { }; /** - * struct ff_ramp_effect - defines parameters of a ramp effect + * struct ff_ramp_effect - defines parameters of a ramp force-feedback effect * @start_level: beginning strength of the effect; may be negative * @end_level: final strength of the effect; may be negative * @envelope: envelope data @@ -741,7 +741,7 @@ struct ff_ramp_effect { }; /** - * struct ff_condition_effect - defines a spring or friction effect + * struct ff_condition_effect - defines a spring or friction force-feedback effect * @right_saturation: maximum level when joystick moved all way to the right * @left_saturation: same for the left side * @right_coeff: controls how fast the force grows when the joystick moves @@ -762,7 +762,7 @@ struct ff_condition_effect { }; /** - * struct ff_periodic_effect - defines parameters of a periodic effect + * struct ff_periodic_effect - defines parameters of a periodic force-feedback effect * @waveform: kind of the effect (wave) * @period: period of the wave (ms) * @magnitude: peak value @@ -793,7 +793,7 @@ struct ff_periodic_effect { }; /** - * struct ff_rumble_effect - defines parameters of a periodic effect + * struct ff_rumble_effect - defines parameters of a periodic force-feedback effect * @strong_magnitude: magnitude of the heavy motor * @weak_magnitude: magnitude of the light one * -- cgit v1.2.3 From 701e054e0c2db82359f0454c7ed4fd24346d52eb Mon Sep 17 00:00:00 2001 From: Vasily Tarasov Date: Sat, 25 Nov 2006 11:09:22 -0800 Subject: [PATCH] mounstats NULL pointer dereference OpenVZ developers team has encountered the following problem in 2.6.19-rc6 kernel. After some seconds of running script while [[ 1 ]] do find /proc -name mountstats | xargs cat done this Oops appears: BUG: unable to handle kernel NULL pointer dereference at virtual address 00000010 printing eip: c01a6b70 *pde = 00000000 Oops: 0000 [#1] SMP Modules linked in: xt_length ipt_ttl xt_tcpmss ipt_TCPMSS iptable_mangle iptable_filter xt_multiport xt_limit ipt_tos ipt_REJECT ip_tables x_tables parport_pc lp parport sunrpc af_packet thermal processor fan button battery asus_acpi ac ohci_hcd ehci_hcd usbcore i2c_nforce2 i2c_core tg3 floppy pata_amd ide_cd cdrom sata_nv libata CPU: 1 EIP: 0060:[] Not tainted VLI EFLAGS: 00010246 (2.6.19-rc6 #2) EIP is at mountstats_open+0x70/0xf0 eax: 00000000 ebx: e6247030 ecx: e62470f8 edx: 00000000 esi: 00000000 edi: c01a6b00 ebp: c33b83c0 esp: f4105eb4 ds: 007b es: 007b ss: 0068 Process cat (pid: 6044, ti=f4105000 task=f4104a70 task.ti=f4105000) Stack: c33b83c0 c04ee940 f46a4a80 c33b83c0 e4df31b4 c01a6b00 f4105000 c0169231 e4df31b4 c33b83c0 c33b83c0 f4105f20 00000003 f4105000 c0169445 f2503cf0 f7f8c4c0 00008000 c33b83c0 00000000 00008000 c0169350 f4105f20 00008000 Call Trace: [] mountstats_open+0x0/0xf0 [] __dentry_open+0x181/0x250 [] nameidata_to_filp+0x35/0x50 [] do_filp_open+0x50/0x60 [] seq_read+0xc6/0x300 [] get_unused_fd+0x31/0xc0 [] do_sys_open+0x63/0x110 [] sys_open+0x27/0x30 [] sysenter_past_esp+0x56/0x79 ======================= Code: 45 74 8b 54 24 20 89 44 24 08 8b 42 f0 31 d2 e8 47 cb f8 ff 85 c0 89 c3 74 51 8d 80 a0 04 00 00 e8 46 06 2c 00 8b 83 48 04 00 00 <8b> 78 10 85 ff 74 03 f0 ff 07 b0 01 86 83 a0 04 00 00 f0 ff 4b EIP: [] mountstats_open+0x70/0xf0 SS:ESP 0068:f4105eb4 The problem is that task->nsproxy can be equal NULL for some time during task exit. This patch fixes the BUG. Signed-off-by: Vasily Tarasov Cc: Herbert Poetzl Cc: "Serge E. Hallyn" Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 3 ++- include/linux/nsproxy.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/base.c b/fs/proc/base.c index 8df27401d292..795319c54f72 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -442,7 +442,8 @@ static int mountstats_open(struct inode *inode, struct file *file) if (task) { task_lock(task); - namespace = task->nsproxy->namespace; + if (task->nsproxy) + namespace = task->nsproxy->namespace; if (namespace) get_namespace(namespace); task_unlock(task); diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index f6baecdeecd6..971d1c6dfc4b 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h @@ -45,8 +45,10 @@ static inline void exit_task_namespaces(struct task_struct *p) { struct nsproxy *ns = p->nsproxy; if (ns) { - put_nsproxy(ns); + task_lock(p); p->nsproxy = NULL; + task_unlock(p); + put_nsproxy(ns); } } #endif -- cgit v1.2.3 From ee3ce191e8eaa4cc15c51a28b34143b36404c4f5 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 25 Nov 2006 11:09:36 -0800 Subject: [PATCH] Enforce "unsigned long flags;" when spinlocking Make it break or warn if you pass to spin_lock_irqsave() and friends something different from "unsigned long flags;". Suprisingly large amount of these was caught by recent commit c53421b18f205c5f97c604ae55c6a921f034b0f6 and others. Idea is largely from FRV typechecking. Suggestions from Andrew Morton. All stupid typos in first version fixed. Passes allmodconfig on i386, x86_64, alpha, arm as well as my usual config. Note #1: checking with sparse is still needed, because a driver can save and pass around flags or something. So far patch is very intrusive. Note #2: techically, we should break only if sizeof(flags) < sizeof(unsigned long), however, the more pain for getting suspicious code into kernel, the better. Signed-off-by: Alexey Dobriyan Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irqflags.h | 37 ++++++++++++++++++++++++++++----- include/linux/spinlock.h | 53 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 76 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h index 412e025bc5c7..4fe740bf4eae 100644 --- a/include/linux/irqflags.h +++ b/include/linux/irqflags.h @@ -11,6 +11,12 @@ #ifndef _LINUX_TRACE_IRQFLAGS_H #define _LINUX_TRACE_IRQFLAGS_H +#define BUILD_CHECK_IRQ_FLAGS(flags) \ + do { \ + BUILD_BUG_ON(sizeof(flags) != sizeof(unsigned long)); \ + typecheck(unsigned long, flags); \ + } while (0) + #ifdef CONFIG_TRACE_IRQFLAGS extern void trace_hardirqs_on(void); extern void trace_hardirqs_off(void); @@ -50,10 +56,15 @@ #define local_irq_disable() \ do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0) #define local_irq_save(flags) \ - do { raw_local_irq_save(flags); trace_hardirqs_off(); } while (0) + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + raw_local_irq_save(flags); \ + trace_hardirqs_off(); \ + } while (0) #define local_irq_restore(flags) \ do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ if (raw_irqs_disabled_flags(flags)) { \ raw_local_irq_restore(flags); \ trace_hardirqs_off(); \ @@ -69,8 +80,16 @@ */ # define raw_local_irq_disable() local_irq_disable() # define raw_local_irq_enable() local_irq_enable() -# define raw_local_irq_save(flags) local_irq_save(flags) -# define raw_local_irq_restore(flags) local_irq_restore(flags) +# define raw_local_irq_save(flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + local_irq_save(flags); \ + } while (0) +# define raw_local_irq_restore(flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + local_irq_restore(flags); \ + } while (0) #endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */ #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT @@ -80,7 +99,11 @@ raw_safe_halt(); \ } while (0) -#define local_save_flags(flags) raw_local_save_flags(flags) +#define local_save_flags(flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + raw_local_save_flags(flags); \ + } while (0) #define irqs_disabled() \ ({ \ @@ -90,7 +113,11 @@ raw_irqs_disabled_flags(flags); \ }) -#define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags) +#define irqs_disabled_flags(flags) \ +({ \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + raw_irqs_disabled_flags(flags); \ +}) #endif /* CONFIG_X86 */ #endif diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index b800d2d68b32..54ad37089c49 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -183,13 +184,37 @@ do { \ #define read_lock(lock) _read_lock(lock) #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) -#define spin_lock_irqsave(lock, flags) flags = _spin_lock_irqsave(lock) -#define read_lock_irqsave(lock, flags) flags = _read_lock_irqsave(lock) -#define write_lock_irqsave(lock, flags) flags = _write_lock_irqsave(lock) +#define spin_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + flags = _spin_lock_irqsave(lock); \ + } while (0) +#define read_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + flags = _read_lock_irqsave(lock); \ + } while (0) +#define write_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + flags = _write_lock_irqsave(lock); \ + } while (0) #else -#define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags) -#define read_lock_irqsave(lock, flags) _read_lock_irqsave(lock, flags) -#define write_lock_irqsave(lock, flags) _write_lock_irqsave(lock, flags) +#define spin_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _spin_lock_irqsave(lock, flags); \ + } while (0) +#define read_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _read_lock_irqsave(lock, flags); \ + } while (0) +#define write_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _write_lock_irqsave(lock, flags); \ + } while (0) #endif #define spin_lock_irq(lock) _spin_lock_irq(lock) @@ -225,15 +250,24 @@ do { \ #endif #define spin_unlock_irqrestore(lock, flags) \ - _spin_unlock_irqrestore(lock, flags) + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _spin_unlock_irqrestore(lock, flags); \ + } while (0) #define spin_unlock_bh(lock) _spin_unlock_bh(lock) #define read_unlock_irqrestore(lock, flags) \ - _read_unlock_irqrestore(lock, flags) + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _read_unlock_irqrestore(lock, flags); \ + } while (0) #define read_unlock_bh(lock) _read_unlock_bh(lock) #define write_unlock_irqrestore(lock, flags) \ - _write_unlock_irqrestore(lock, flags) + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _write_unlock_irqrestore(lock, flags); \ + } while (0) #define write_unlock_bh(lock) _write_unlock_bh(lock) #define spin_trylock_bh(lock) __cond_lock(lock, _spin_trylock_bh(lock)) @@ -247,6 +281,7 @@ do { \ #define spin_trylock_irqsave(lock, flags) \ ({ \ + BUILD_CHECK_IRQ_FLAGS(flags); \ local_irq_save(flags); \ spin_trylock(lock) ? \ 1 : ({ local_irq_restore(flags); 0; }); \ -- cgit v1.2.3 From cfd3ef2346f924d6c0e82236c20fdb3a8840136a Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sat, 25 Nov 2006 11:09:37 -0800 Subject: [PATCH] lockdep: spin_lock_irqsave_nested() Introduce spin_lock_irqsave_nested(); implementation from: http://lkml.org/lkml/2006/6/1/122 Patch from: http://lkml.org/lkml/2006/9/13/258 [akpm@osdl.org: two compile fixes] Signed-off-by: Arjan van de Ven Signed-off-by: Jiri Kosina Signed-off-by: Peter Zijlstra Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/spinlock.h | 18 ++++++++++++++++++ include/linux/spinlock_api_smp.h | 2 ++ kernel/spinlock.c | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+) (limited to 'include/linux') diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 54ad37089c49..57f670d78f7c 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -199,6 +199,21 @@ do { \ BUILD_CHECK_IRQ_FLAGS(flags); \ flags = _write_lock_irqsave(lock); \ } while (0) + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +#define spin_lock_irqsave_nested(lock, flags, subclass) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + flags = _spin_lock_irqsave_nested(lock, subclass); \ + } while (0) +#else +#define spin_lock_irqsave_nested(lock, flags, subclass) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + flags = _spin_lock_irqsave(lock); \ + } while (0) +#endif + #else #define spin_lock_irqsave(lock, flags) \ do { \ @@ -215,6 +230,9 @@ do { \ BUILD_CHECK_IRQ_FLAGS(flags); \ _write_lock_irqsave(lock, flags); \ } while (0) +#define spin_lock_irqsave_nested(lock, flags, subclass) \ + spin_lock_irqsave(lock, flags) + #endif #define spin_lock_irq(lock) _spin_lock_irq(lock) diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h index 8828b8155e9c..8a2307ce7296 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -32,6 +32,8 @@ void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(lock); void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(lock); unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) __acquires(lock); +unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) + __acquires(lock); unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) __acquires(lock); unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) diff --git a/kernel/spinlock.c b/kernel/spinlock.c index 476c3741511b..2c6c2bf85514 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -293,6 +293,27 @@ void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass) } EXPORT_SYMBOL(_spin_lock_nested); +unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) +{ + unsigned long flags; + + local_irq_save(flags); + preempt_disable(); + spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); + /* + * On lockdep we dont want the hand-coded irq-enable of + * _raw_spin_lock_flags() code, because lockdep assumes + * that interrupts are not re-enabled during lock-acquire: + */ +#ifdef CONFIG_PROVE_SPIN_LOCKING + _raw_spin_lock(lock); +#else + _raw_spin_lock_flags(lock, &flags); +#endif + return flags; +} + +EXPORT_SYMBOL(_spin_lock_irqsave_nested); #endif -- cgit v1.2.3 From b8e6ec865fd1d8838b6ce9516977b65e9f08f876 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 26 Nov 2006 16:27:17 -0800 Subject: Revert "[PATCH] Enforce "unsigned long flags;" when spinlocking" This reverts commit ee3ce191e8eaa4cc15c51a28b34143b36404c4f5, since it broke on at least ARM, MIPS and PA-RISC due to complicated header file dependencies. Conflicts in include/linux/spinlock.h (due to the "nested" variety fixes) fixed up by hand. Cc: Alexey Dobriyan Cc: Ralf Baechle Cc: Kyle McMartin Cc: Russell King Signed-off-by: Linus Torvalds --- include/linux/irqflags.h | 37 ++++---------------------- include/linux/spinlock.h | 69 +++++++++++------------------------------------- 2 files changed, 20 insertions(+), 86 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h index 4fe740bf4eae..412e025bc5c7 100644 --- a/include/linux/irqflags.h +++ b/include/linux/irqflags.h @@ -11,12 +11,6 @@ #ifndef _LINUX_TRACE_IRQFLAGS_H #define _LINUX_TRACE_IRQFLAGS_H -#define BUILD_CHECK_IRQ_FLAGS(flags) \ - do { \ - BUILD_BUG_ON(sizeof(flags) != sizeof(unsigned long)); \ - typecheck(unsigned long, flags); \ - } while (0) - #ifdef CONFIG_TRACE_IRQFLAGS extern void trace_hardirqs_on(void); extern void trace_hardirqs_off(void); @@ -56,15 +50,10 @@ #define local_irq_disable() \ do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0) #define local_irq_save(flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - raw_local_irq_save(flags); \ - trace_hardirqs_off(); \ - } while (0) + do { raw_local_irq_save(flags); trace_hardirqs_off(); } while (0) #define local_irq_restore(flags) \ do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ if (raw_irqs_disabled_flags(flags)) { \ raw_local_irq_restore(flags); \ trace_hardirqs_off(); \ @@ -80,16 +69,8 @@ */ # define raw_local_irq_disable() local_irq_disable() # define raw_local_irq_enable() local_irq_enable() -# define raw_local_irq_save(flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - local_irq_save(flags); \ - } while (0) -# define raw_local_irq_restore(flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - local_irq_restore(flags); \ - } while (0) +# define raw_local_irq_save(flags) local_irq_save(flags) +# define raw_local_irq_restore(flags) local_irq_restore(flags) #endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */ #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT @@ -99,11 +80,7 @@ raw_safe_halt(); \ } while (0) -#define local_save_flags(flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - raw_local_save_flags(flags); \ - } while (0) +#define local_save_flags(flags) raw_local_save_flags(flags) #define irqs_disabled() \ ({ \ @@ -113,11 +90,7 @@ raw_irqs_disabled_flags(flags); \ }) -#define irqs_disabled_flags(flags) \ -({ \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - raw_irqs_disabled_flags(flags); \ -}) +#define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags) #endif /* CONFIG_X86 */ #endif diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 57f670d78f7c..8451052ca66f 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -52,7 +52,6 @@ #include #include #include -#include #include @@ -184,52 +183,24 @@ do { \ #define read_lock(lock) _read_lock(lock) #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) -#define spin_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - flags = _spin_lock_irqsave(lock); \ - } while (0) -#define read_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - flags = _read_lock_irqsave(lock); \ - } while (0) -#define write_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - flags = _write_lock_irqsave(lock); \ - } while (0) + +#define spin_lock_irqsave(lock, flags) flags = _spin_lock_irqsave(lock) +#define read_lock_irqsave(lock, flags) flags = _read_lock_irqsave(lock) +#define write_lock_irqsave(lock, flags) flags = _write_lock_irqsave(lock) #ifdef CONFIG_DEBUG_LOCK_ALLOC -#define spin_lock_irqsave_nested(lock, flags, subclass) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - flags = _spin_lock_irqsave_nested(lock, subclass); \ - } while (0) +#define spin_lock_irqsave_nested(lock, flags, subclass) \ + flags = _spin_lock_irqsave_nested(lock, subclass) #else -#define spin_lock_irqsave_nested(lock, flags, subclass) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - flags = _spin_lock_irqsave(lock); \ - } while (0) +#define spin_lock_irqsave_nested(lock, flags, subclass) \ + flags = _spin_lock_irqsave(lock) #endif #else -#define spin_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _spin_lock_irqsave(lock, flags); \ - } while (0) -#define read_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _read_lock_irqsave(lock, flags); \ - } while (0) -#define write_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _write_lock_irqsave(lock, flags); \ - } while (0) + +#define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags) +#define read_lock_irqsave(lock, flags) _read_lock_irqsave(lock, flags) +#define write_lock_irqsave(lock, flags) _write_lock_irqsave(lock, flags) #define spin_lock_irqsave_nested(lock, flags, subclass) \ spin_lock_irqsave(lock, flags) @@ -268,24 +239,15 @@ do { \ #endif #define spin_unlock_irqrestore(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _spin_unlock_irqrestore(lock, flags); \ - } while (0) + _spin_unlock_irqrestore(lock, flags) #define spin_unlock_bh(lock) _spin_unlock_bh(lock) #define read_unlock_irqrestore(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _read_unlock_irqrestore(lock, flags); \ - } while (0) + _read_unlock_irqrestore(lock, flags) #define read_unlock_bh(lock) _read_unlock_bh(lock) #define write_unlock_irqrestore(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _write_unlock_irqrestore(lock, flags); \ - } while (0) + _write_unlock_irqrestore(lock, flags) #define write_unlock_bh(lock) _write_unlock_bh(lock) #define spin_trylock_bh(lock) __cond_lock(lock, _spin_trylock_bh(lock)) @@ -299,7 +261,6 @@ do { \ #define spin_trylock_irqsave(lock, flags) \ ({ \ - BUILD_CHECK_IRQ_FLAGS(flags); \ local_irq_save(flags); \ spin_trylock(lock) ? \ 1 : ({ local_irq_restore(flags); 0; }); \ -- cgit v1.2.3 From 2ea5814472c3c910aed5c5b60f1f3b1000e353f1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 26 Nov 2006 19:05:22 -0800 Subject: Fix 'ALIGN()' macro, take 2 You wouldn't think that doing an ALIGN() macro that aligns something up to a power-of-two boundary would be likely to have bugs, would you? But hey, in the wonderful world of mixing integer types, you have to be careful. This just makes sure that the alignment is interpreted in the same type as the thing to be aligned. Thanks to Roland Dreier, who noticed that the amso1100 driver got broken by the previous fix (that just extended the mask to "unsigned long", but was still broken in "unsigned long long" - it just happened to be the same on 64-bit architectures). See commit 4c8bd7eeee4c8f157fb61fb64b57500990b42e0e for the history of bugs here... Acked-by: Roland Dreier Cc: Andrew Morton Cc: David Miller Cc: Al Viro Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 24b611147adb..b9b5e4ba166a 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -30,8 +30,10 @@ extern const char linux_banner[]; #define STACK_MAGIC 0xdeadbeef +#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) +#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL)) #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) -- cgit v1.2.3 From e81c73596704793e73e6dbb478f41686f15a4b34 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 28 Nov 2006 20:53:39 -0800 Subject: [NET]: Fix MAX_HEADER setting. MAX_HEADER is either set to LL_MAX_HEADER or LL_MAX_HEADER + 48, and this is controlled by a set of CONFIG_* ifdef tests. It is trying to use LL_MAX_HEADER + 48 when any of the tunnels are enabled which set hard_header_len like this: dev->hard_header_len = LL_MAX_HEADER + sizeof(struct xxx); The correct set of tunnel drivers which do this are: ipip ip_gre ip6_tunnel sit so make the ifdef test match. Noticed by Patrick McHardy and with help from Herbert Xu. Signed-off-by: David S. Miller --- include/linux/netdevice.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9264139bd8df..83b8c4f1d69d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -93,8 +93,10 @@ struct netpoll_info; #endif #endif -#if !defined(CONFIG_NET_IPIP) && \ - !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) +#if !defined(CONFIG_NET_IPIP) && !defined(CONFIG_NET_IPIP_MODULE) && \ + !defined(CONFIG_NET_IPGRE) && !defined(CONFIG_NET_IPGRE_MODULE) && \ + !defined(CONFIG_IPV6_SIT) && !defined(CONFIG_IPV6_SIT_MODULE) && \ + !defined(CONFIG_IPV6_TUNNEL) && !defined(CONFIG_IPV6_TUNNEL_MODULE) #define MAX_HEADER LL_MAX_HEADER #else #define MAX_HEADER (LL_MAX_HEADER + 48) -- cgit v1.2.3 From 583bb86fbb9e85287f020fe4eb5352a0ec3c66a3 Mon Sep 17 00:00:00 2001 From: Nicolas Schichan Date: Wed, 18 Oct 2006 15:14:55 +0200 Subject: [MIPS] Add support for kexec A tiny userland application loading the kernel and invoking kexec_load for mips is available here: http://chac.le-poulpe.net/~nico/kexec/kexec-2006-10-18.tar.gz Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 17 ++++++++ arch/mips/kernel/Makefile | 2 + arch/mips/kernel/machine_kexec.c | 85 ++++++++++++++++++++++++++++++++++++++ arch/mips/kernel/relocate_kernel.S | 80 +++++++++++++++++++++++++++++++++++ arch/mips/kernel/scall32-o32.S | 2 +- arch/mips/kernel/scall64-64.S | 2 +- arch/mips/kernel/scall64-n32.S | 2 +- arch/mips/kernel/scall64-o32.S | 2 +- include/asm-mips/kexec.h | 32 ++++++++++++++ include/linux/kexec.h | 2 + 10 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 arch/mips/kernel/machine_kexec.c create mode 100644 arch/mips/kernel/relocate_kernel.S create mode 100644 include/asm-mips/kexec.h (limited to 'include/linux') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 1443024b1c7c..c0da0ffe8d57 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -766,6 +766,23 @@ config TOSHIBA_RBTX4938 endchoice +config KEXEC + bool "Kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + source "arch/mips/ddb5xxx/Kconfig" source "arch/mips/gt64120/ev64120/Kconfig" source "arch/mips/jazz/Kconfig" diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 6bfbbed0897e..f35b739d0a12 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -67,6 +67,8 @@ obj-$(CONFIG_64BIT) += cpu-bugs64.o obj-$(CONFIG_I8253) += i8253.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o + CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c new file mode 100644 index 000000000000..e0ad754c7edd --- /dev/null +++ b/arch/mips/kernel/machine_kexec.c @@ -0,0 +1,85 @@ +/* + * machine_kexec.c for kexec + * Created by on Thu Oct 12 15:15:06 2006 + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include + +#include +#include + +const extern unsigned char relocate_new_kernel[]; +const extern unsigned int relocate_new_kernel_size; + +extern unsigned long kexec_start_address; +extern unsigned long kexec_indirection_page; + +int +machine_kexec_prepare(struct kimage *kimage) +{ + return 0; +} + +void +machine_kexec_cleanup(struct kimage *kimage) +{ +} + +void +machine_shutdown(void) +{ +} + +void +machine_crash_shutdown(struct pt_regs *regs) +{ +} + +void +machine_kexec(struct kimage *image) +{ + unsigned long reboot_code_buffer; + unsigned long entry; + unsigned long *ptr; + + reboot_code_buffer = + (unsigned long)page_address(image->control_code_page); + + kexec_start_address = image->start; + kexec_indirection_page = phys_to_virt(image->head & PAGE_MASK); + + memcpy((void*)reboot_code_buffer, relocate_new_kernel, + relocate_new_kernel_size); + + /* + * The generic kexec code builds a page list with physical + * addresses. they are directly accessible through KSEG0 (or + * CKSEG0 or XPHYS if on 64bit system), hence the + * pys_to_virt() call. + */ + for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE); + ptr = (entry & IND_INDIRECTION) ? + phys_to_virt(entry & PAGE_MASK) : ptr + 1) { + if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION || + *ptr & IND_DESTINATION) + *ptr = phys_to_virt(*ptr); + } + + /* + * we do not want to be bothered. + */ + local_irq_disable(); + + flush_icache_range(reboot_code_buffer, + reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); + + printk("Will call new kernel at %08x\n", image->start); + printk("Bye ...\n"); + flush_cache_all(); + ((void (*)(void))reboot_code_buffer)(); +} diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S new file mode 100644 index 000000000000..a3f0d00c1334 --- /dev/null +++ b/arch/mips/kernel/relocate_kernel.S @@ -0,0 +1,80 @@ +/* + * relocate_kernel.S for kexec + * Created by on Thu Oct 12 17:49:57 2006 + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + + .globl relocate_new_kernel +relocate_new_kernel: + + PTR_L s0, kexec_indirection_page + PTR_L s1, kexec_start_address + +process_entry: + PTR_L s2, (s0) + PTR_ADD s0, s0, SZREG + + /* destination page */ + and s3, s2, 0x1 + beq s3, zero, 1f + and s4, s2, ~0x1 /* store destination addr in s4 */ + move a0, s4 + b process_entry + +1: + /* indirection page, update s0 */ + and s3, s2, 0x2 + beq s3, zero, 1f + and s0, s2, ~0x2 + b process_entry + +1: + /* done page */ + and s3, s2, 0x4 + beq s3, zero, 1f + b done +1: + /* source page */ + and s3, s2, 0x8 + beq s3, zero, process_entry + and s2, s2, ~0x8 + li s6, (1 << PAGE_SHIFT) / SZREG + +copy_word: + /* copy page word by word */ + REG_L s5, (s2) + REG_S s5, (s4) + INT_ADD s4, s4, SZREG + INT_ADD s2, s2, SZREG + INT_SUB s6, s6, 1 + beq s6, zero, process_entry + b copy_word + b process_entry + +done: + /* jump to kexec_start_address */ + j s1 + + .globl kexec_start_address +kexec_start_address: + .long 0x0 + + .globl kexec_indirection_page +kexec_indirection_page: + .long 0x0 + +relocate_new_kernel_end: + + .globl relocate_new_kernel_size +relocate_new_kernel_size: + .long relocate_new_kernel_end - relocate_new_kernel diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index a95f37de080e..7c0b3936ba44 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -653,7 +653,7 @@ einval: li v0, -EINVAL sys sys_move_pages 6 sys sys_set_robust_list 2 sys sys_get_robust_list 3 /* 4310 */ - sys sys_ni_syscall 0 + sys sys_kexec_load 4 sys sys_getcpu 3 sys sys_epoll_pwait 6 .endm diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 8fb0f60f657b..e569b846e9a3 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -468,6 +468,6 @@ sys_call_table: PTR sys_move_pages PTR sys_set_robust_list PTR sys_get_robust_list - PTR sys_ni_syscall /* 5270 */ + PTR sys_kexec_load /* 5270 */ PTR sys_getcpu PTR sys_epoll_pwait diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 0da5ca2040ff..5b18f265d75b 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -394,6 +394,6 @@ EXPORT(sysn32_call_table) PTR sys_move_pages PTR compat_sys_set_robust_list PTR compat_sys_get_robust_list - PTR sys_ni_syscall + PTR compat_sys_kexec_load PTR sys_getcpu PTR sys_epoll_pwait diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index b9d00cae8b5f..e91379c1be1d 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -516,7 +516,7 @@ sys_call_table: PTR compat_sys_move_pages PTR compat_sys_set_robust_list PTR compat_sys_get_robust_list /* 4310 */ - PTR sys_ni_syscall + PTR compat_sys_kexec_load PTR sys_getcpu PTR sys_epoll_pwait .size sys_call_table,.-sys_call_table diff --git a/include/asm-mips/kexec.h b/include/asm-mips/kexec.h new file mode 100644 index 000000000000..b25267ebcb09 --- /dev/null +++ b/include/asm-mips/kexec.h @@ -0,0 +1,32 @@ +/* + * kexec.h for kexec + * Created by on Thu Oct 12 14:59:34 2006 + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#ifndef _MIPS_KEXEC +# define _MIPS_KEXEC + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (0x20000000) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (0x20000000) + /* Maximum address we can use for the control code buffer */ +#define KEXEC_CONTROL_MEMORY_LIMIT (0x20000000) + +#define KEXEC_CONTROL_CODE_SIZE 4096 + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_MIPS + +#define MAX_NOTE_BYTES 1024 + +static inline void crash_setup_regs(struct pt_regs *newregs, + struct pt_regs *oldregs) +{ + /* Dummy implementation for now */ +} + +#endif /* !_MIPS_KEXEC */ diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 6427949ddf99..a4ede62b339d 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -122,6 +122,8 @@ extern struct kimage *kexec_crash_image; #define KEXEC_ARCH_IA_64 (50 << 16) #define KEXEC_ARCH_S390 (22 << 16) #define KEXEC_ARCH_SH (42 << 16) +#define KEXEC_ARCH_MIPS_LE (10 << 16) +#define KEXEC_ARCH_MIPS ( 8 << 16) #define KEXEC_FLAGS (KEXEC_ON_CRASH) /* List of defined/legal kexec flags */ -- cgit v1.2.3 From 139a7bdc2b9391a4d0362190d9e5625dcf580105 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 30 Nov 2006 04:40:22 +0100 Subject: mqueue.h: don't include linux/types.h This #include is not required. Signed-off-by: Alexey Dobriyan Signed-off-by: Adrian Bunk --- include/linux/mqueue.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mqueue.h b/include/linux/mqueue.h index 8db9d75541a6..8b5a79615fbf 100644 --- a/include/linux/mqueue.h +++ b/include/linux/mqueue.h @@ -18,8 +18,6 @@ #ifndef _LINUX_MQUEUE_H #define _LINUX_MQUEUE_H -#include - #define MQ_PRIO_MAX 32768 /* per-uid limit of kernel memory used by mqueue, in bytes */ #define MQ_BYTES_MAX 819200 -- cgit v1.2.3 From e20ec9911bfef897459b9f8aeaf6eadb0920299a Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Thu, 30 Nov 2006 04:46:13 +0100 Subject: fix spelling error in include/linux/kernel.h Signed-off-by: Adrian Bunk --- include/linux/kernel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index b9b5e4ba166a..6738283ac385 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -65,7 +65,7 @@ struct user; * context (spinlock, irq-handler, ...). * * This is a useful debugging help to be able to catch problems early and not - * be biten later when the calling function happens to sleep when it is not + * be bitten later when the calling function happens to sleep when it is not * supposed to. */ #ifdef CONFIG_PREEMPT_VOLUNTARY -- cgit v1.2.3 From 98c4f0c336afe4318c12397bc74910d86ee036a2 Mon Sep 17 00:00:00 2001 From: Chase Venters Date: Thu, 30 Nov 2006 04:53:49 +0100 Subject: Fix jiffies.h comment jiffies.h includes a comment informing that jiffies_64 must be read with the assistance of the xtime_lock seqlock. The comment text, however, calls jiffies_64 "not volatile", which should probably read "not atomic". Signed-off-by: Chase Venters Signed-off-by: Adrian Bunk --- include/linux/jiffies.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index c8d5f207c3d4..0ec6e28bccd2 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -74,7 +74,7 @@ #define __jiffy_data __attribute__((section(".data"))) /* - * The 64-bit value is not volatile - you MUST NOT read it + * The 64-bit value is not atomic - you MUST NOT read it * without sampling the sequence number in xtime_lock. * get_jiffies_64() will do this for you as appropriate. */ -- cgit v1.2.3 From 0779bf2d2ecc4d9b1e9437ae659f50e6776a7666 Mon Sep 17 00:00:00 2001 From: Matt LaPlante Date: Thu, 30 Nov 2006 05:24:39 +0100 Subject: Fix misc .c/.h comment typos Fix various .c/.h typos in comments (no code changes). Signed-off-by: Matt LaPlante Signed-off-by: Adrian Bunk --- arch/cris/arch-v10/drivers/eeprom.c | 6 +++--- arch/cris/arch-v10/drivers/i2c.c | 2 +- arch/cris/arch-v10/kernel/kgdb.c | 2 +- arch/ia64/hp/common/sba_iommu.c | 8 ++++---- arch/sh64/lib/dbg.c | 2 +- drivers/atm/iphase.c | 2 +- drivers/char/rio/riocmd.c | 2 +- drivers/char/rio/rioinit.c | 2 +- drivers/char/rio/rioparam.c | 6 +++--- drivers/ide/ide-floppy.c | 2 +- drivers/isdn/hardware/eicon/os_4bri.c | 2 +- drivers/isdn/hisax/hfc4s8s_l1.h | 2 +- drivers/media/dvb/ttpci/budget-patch.c | 8 ++++---- drivers/net/e100.c | 2 +- drivers/net/e1000/e1000_hw.c | 2 +- drivers/net/sk98lin/h/skdrv2nd.h | 2 +- drivers/net/sk98lin/skdim.c | 4 ++-- drivers/net/wireless/ipw2200.c | 4 ++-- drivers/parisc/ccio-dma.c | 2 +- drivers/parisc/iosapic.c | 6 +++--- drivers/pci/hotplug/ibmphp_hpc.c | 2 +- drivers/s390/net/claw.h | 2 +- drivers/scsi/aic94xx/aic94xx_reg_def.h | 2 +- drivers/scsi/aic94xx/aic94xx_sds.c | 4 ++-- drivers/scsi/ncr53c8xx.c | 14 +++++++------- drivers/scsi/ncr53c8xx.h | 6 +++--- drivers/usb/host/u132-hcd.c | 6 +++--- drivers/usb/misc/usb_u132.h | 2 +- drivers/usb/serial/digi_acceleport.c | 2 +- fs/reiserfs/journal.c | 6 +++--- include/asm-m68knommu/mcfmbus.h | 2 +- include/asm-parisc/dma.h | 6 +++--- include/asm-parisc/pci.h | 2 +- include/asm-parisc/ropes.h | 2 +- include/linux/ixjuser.h | 2 +- include/linux/reiserfs_fs_sb.h | 2 +- net/wanrouter/af_wanpipe.c | 4 ++-- net/wanrouter/wanmain.c | 2 +- sound/oss/cs46xx.c | 6 +++--- 39 files changed, 71 insertions(+), 71 deletions(-) (limited to 'include/linux') diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c index 6e1f191a71e3..284ebfda03f0 100644 --- a/arch/cris/arch-v10/drivers/eeprom.c +++ b/arch/cris/arch-v10/drivers/eeprom.c @@ -1,7 +1,7 @@ /*!***************************************************************************** *! -*! Implements an interface for i2c compatible eeproms to run under linux. -*! Supports 2k, 8k(?) and 16k. Uses adaptive timing adjustents by +*! Implements an interface for i2c compatible eeproms to run under Linux. +*! Supports 2k, 8k(?) and 16k. Uses adaptive timing adjustments by *! Johan.Adolfsson@axis.com *! *! Probing results: @@ -51,7 +51,7 @@ *! Revision 1.8 2001/06/15 13:24:29 jonashg *! * Added verification of pointers from userspace in read and write. *! * Made busy counter volatile. -*! * Added define for inital write delay. +*! * Added define for initial write delay. *! * Removed warnings by using loff_t instead of unsigned long. *! *! Revision 1.7 2001/06/14 15:26:54 jonashg diff --git a/arch/cris/arch-v10/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c index 6114596c3b33..092c724a645f 100644 --- a/arch/cris/arch-v10/drivers/i2c.c +++ b/arch/cris/arch-v10/drivers/i2c.c @@ -47,7 +47,7 @@ *! Update Port B register and shadow even when running with hardware support *! to avoid glitches when reading bits *! Never set direction to out in i2c_inbyte -*! Removed incorrect clock togling at end of i2c_inbyte +*! Removed incorrect clock toggling at end of i2c_inbyte *! *! Revision 1.8 2002/08/13 06:31:53 starvik *! Made SDA and SCL line configurable diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c index 34528da98817..07628a13c6c4 100644 --- a/arch/cris/arch-v10/kernel/kgdb.c +++ b/arch/cris/arch-v10/kernel/kgdb.c @@ -33,7 +33,7 @@ *! *! Revision 1.2 2002/11/19 14:35:24 starvik *! Changes from linux 2.4 -*! Changed struct initializer syntax to the currently prefered notation +*! Changed struct initializer syntax to the currently preferred notation *! *! Revision 1.1 2001/12/17 13:59:27 bjornw *! Initial revision diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index db8e1fcfa047..14691cda05c3 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -75,7 +75,7 @@ ** If a device prefetches beyond the end of a valid pdir entry, it will cause ** a hard failure, ie. MCA. Version 3.0 and later of the zx1 LBA should ** disconnect on 4k boundaries and prevent such issues. If the device is -** particularly agressive, this option will keep the entire pdir valid such +** particularly aggressive, this option will keep the entire pdir valid such ** that prefetching will hit a valid address. This could severely impact ** error containment, and is therefore off by default. The page that is ** used for spill-over is poisoned, so that should help debugging somewhat. @@ -258,10 +258,10 @@ static u64 prefetch_spill_page; /* ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up -** (or rather not merge) DMA's into managable chunks. +** (or rather not merge) DMAs into manageable chunks. ** On parisc, this is more of the software/tuning constraint -** rather than the HW. I/O MMU allocation alogorithms can be -** faster with smaller size is (to some degree). +** rather than the HW. I/O MMU allocation algorithms can be +** faster with smaller sizes (to some degree). */ #define DMA_CHUNK_SIZE (BITS_PER_LONG*iovp_size) diff --git a/arch/sh64/lib/dbg.c b/arch/sh64/lib/dbg.c index 1326f45f31eb..4310fc87444e 100644 --- a/arch/sh64/lib/dbg.c +++ b/arch/sh64/lib/dbg.c @@ -383,7 +383,7 @@ void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs) /* ======================================================================= */ /* -** Depending on scan the MMU, Data or Instrction side +** Depending on scan the MMU, Data or Instruction side ** looking for a valid mapping matching Eaddr & asid. ** Return -1 if not found or the TLB id entry otherwise. ** Note: it works only for 4k pages! diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 9ed1c60048f0..bb7ef570514c 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -305,7 +305,7 @@ static void clear_lockup (struct atm_vcc *vcc, IADEV *dev) { ** | R | NZ | 5-bit exponent | 9-bit mantissa | ** +----+----+------------------+-------------------------------+ ** -** R = reserverd (written as 0) +** R = reserved (written as 0) ** NZ = 0 if 0 cells/sec; 1 otherwise ** ** if NZ = 1, rate = 1.mmmmmmmmm x 2^(eeeee) cells/sec diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 4df6ab2206a1..167ebc84e8d7 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c @@ -922,7 +922,7 @@ int RIOUnUse(unsigned long iPortP, struct CmdBlk *CmdBlkP) ** ** Packet is an actual packet structure to be filled in with the packet ** information associated with the command. You need to fill in everything, -** as the command processore doesn't process the command packet in any way. +** as the command processor doesn't process the command packet in any way. ** ** The PreFuncP is called before the packet is enqueued on the host rup. ** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c index 99f3df02b61c..0794844369d6 100644 --- a/drivers/char/rio/rioinit.c +++ b/drivers/char/rio/rioinit.c @@ -222,7 +222,7 @@ int RIOBoardTest(unsigned long paddr, void __iomem *caddr, unsigned char type, i ** which value will be written into memory. ** Call with op set to zero means that the RAM will not be read and checked ** before it is written. -** Call with op not zero, and the RAM will be read and compated with val[op-1] +** Call with op not zero and the RAM will be read and compared with val[op-1] ** to check that the data from the previous phase was retained. */ diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c index 1066d9760704..bb498d24adcc 100644 --- a/drivers/char/rio/rioparam.c +++ b/drivers/char/rio/rioparam.c @@ -87,8 +87,8 @@ static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3"; ** command bit set onto the port. The command bit is in the len field, ** and gets ORed in with the actual byte count. ** -** When you send a packet with the command bit set, then the first -** data byte ( data[0] ) is interpretted as the command to execute. +** When you send a packet with the command bit set the first +** data byte (data[0]) is interpreted as the command to execute. ** It also governs what data structure overlay should accompany the packet. ** Commands are defined in cirrus/cirrus.h ** @@ -103,7 +103,7 @@ static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3"; ** ** Most commands do not use the remaining bytes in the data array. The ** exceptions are OPEN MOPEN and CONFIG. (NB. As with the SI CONFIG and -** OPEN are currently analagous). With these three commands the following +** OPEN are currently analogous). With these three commands the following ** 11 data bytes are all used to pass config information such as baud rate etc. ** The fields are also defined in cirrus.h. Some contain straightforward ** information such as the transmit XON character. Two contain the transmit and diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 8ccee9c769f8..e3a267622bb6 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -1635,7 +1635,7 @@ static int idefloppy_begin_format(ide_drive_t *drive, int __user *arg) /* ** Get ATAPI_FORMAT_UNIT progress indication. ** -** Userland gives a pointer to an int. The int is set to a progresss +** Userland gives a pointer to an int. The int is set to a progress ** indicator 0-65536, with 65536=100%. ** ** If the drive does not support format progress indication, we just check diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c index 11e6f937c1e4..7b4ec3f60dbf 100644 --- a/drivers/isdn/hardware/eicon/os_4bri.c +++ b/drivers/isdn/hardware/eicon/os_4bri.c @@ -464,7 +464,7 @@ int diva_4bri_init_card(diva_os_xdi_adapter_t * a) /* ** Cleanup function will be called for master adapter only -** this is garanteed by design: cleanup callback is set +** this is guaranteed by design: cleanup callback is set ** by master adapter only */ static int diva_4bri_cleanup_adapter(diva_os_xdi_adapter_t * a) diff --git a/drivers/isdn/hisax/hfc4s8s_l1.h b/drivers/isdn/hisax/hfc4s8s_l1.h index e8f9c077fa85..9d5d2a56b4e9 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.h +++ b/drivers/isdn/hisax/hfc4s8s_l1.h @@ -16,7 +16,7 @@ /* * include Genero generated HFC-4S/8S header file hfc48scu.h -* for comlete register description. This will define _HFC48SCU_H_ +* for complete register description. This will define _HFC48SCU_H_ * to prevent redefinitions */ diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index fc1267b8c892..9a155396d6ac 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -500,14 +500,14 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte /* New design (By Emard) ** this rps1 code will copy internal HS event to GPIO3 pin. -** GPIO3 is in budget-patch hardware connectd to port B VSYNC +** GPIO3 is in budget-patch hardware connected to port B VSYNC ** HS is an internal event of 7146, accessible with RPS ** and temporarily raised high every n lines ** (n in defined in the RPS_THRESH1 counter threshold) ** I think HS is raised high on the beginning of the n-th line ** and remains high until this n-th line that triggered -** it is completely received. When the receiption of n-th line +** it is completely received. When the reception of n-th line ** ends, HS is lowered. ** To transmit data over DMA, 7146 needs changing state at @@ -541,7 +541,7 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte ** hardware debug note: a working budget card (including budget patch) ** with vpeirq() interrupt setup in mode "0x90" (every 64K) will ** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes -** and that means 3*25=75 Hz of interrupt freqency, as seen by +** and that means 3*25=75 Hz of interrupt frequency, as seen by ** watch cat /proc/interrupts ** ** If this frequency is 3x lower (and data received in the DMA @@ -550,7 +550,7 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte ** this means VSYNC line is not connected in the hardware. ** (check soldering pcb and pins) ** The same behaviour of missing VSYNC can be duplicated on budget -** cards, by seting DD1_INIT trigger mode 7 in 3rd nibble. +** cards, by setting DD1_INIT trigger mode 7 in 3rd nibble. */ // Setup RPS1 "program" (p35) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 19ab3441269c..3a8df479cbda 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1215,7 +1215,7 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb * the literal in the instruction before the code is loaded, the * driver can change the algorithm. * -* INTDELAY - This loads the dead-man timer with its inital value. +* INTDELAY - This loads the dead-man timer with its initial value. * When this timer expires the interrupt is asserted, and the * timer is reset each time a new packet is received. (see * BUNDLEMAX below to set the limit on number of chained packets) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 65077f39da69..796c4f7d4260 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -3868,7 +3868,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) * * hw - Struct containing variables accessed by shared code * -* Sets bit 15 of the MII Control regiser +* Sets bit 15 of the MII Control register ******************************************************************************/ int32_t e1000_phy_reset(struct e1000_hw *hw) diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h index 778d9e618ebd..3fa67171e832 100644 --- a/drivers/net/sk98lin/h/skdrv2nd.h +++ b/drivers/net/sk98lin/h/skdrv2nd.h @@ -160,7 +160,7 @@ struct s_IOCTL { /* ** Interim definition of SK_DRV_TIMER placed in this file until -** common modules have boon finallized +** common modules have been finalized */ #define SK_DRV_TIMER 11 #define SK_DRV_MODERATION_TIMER 1 diff --git a/drivers/net/sk98lin/skdim.c b/drivers/net/sk98lin/skdim.c index 07c1b4c8699d..37ce03fb8de3 100644 --- a/drivers/net/sk98lin/skdim.c +++ b/drivers/net/sk98lin/skdim.c @@ -252,7 +252,7 @@ SkDimEnableModerationIfNeeded(SK_AC *pAC) { /******************************************************************************* ** Function : SkDimDisplayModerationSettings -** Description : Displays the current settings regaring interrupt moderation +** Description : Displays the current settings regarding interrupt moderation ** Programmer : Ralph Roesler ** Last Modified: 22-mar-03 ** Returns : void (!) @@ -510,7 +510,7 @@ EnableIntMod(SK_AC *pAC) { /******************************************************************************* ** Function : DisableIntMod() -** Description : Disbles the interrupt moderation independent of what inter- +** Description : Disables the interrupt moderation independent of what inter- ** rupts are running or not ** Programmer : Ralph Roesler ** Last Modified: 23-mar-03 diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 1f742814a01c..72120d5c2f7b 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -6920,8 +6920,8 @@ static int ipw_qos_association(struct ipw_priv *priv, } /* -* handling the beaconing responces. if we get different QoS setting -* of the network from the the associated setting adjust the QoS +* handling the beaconing responses. if we get different QoS setting +* off the network from the associated setting, adjust the QoS * setting */ static int ipw_qos_association_resp(struct ipw_priv *priv, diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 68cb3a080050..fe3f5f5365c5 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -486,7 +486,7 @@ typedef unsigned long space_t; ** This bit tells U2 to do R/M/W for partial cachelines. "Streaming" ** data can avoid this if the mapping covers full cache lines. ** o STOP_MOST is needed for atomicity across cachelines. -** Apperently only "some EISA devices" need this. +** Apparently only "some EISA devices" need this. ** Using CONFIG_ISA is hack. Only the IOA with EISA under it needs ** to use this hint iff the EISA devices needs this feature. ** According to the U2 ERS, STOP_MOST enabled pages hurt performance. diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index c2949b4367e5..12bab64a62a1 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -50,12 +50,12 @@ ** ** PA Firmware ** ----------- -** PA-RISC platforms have two fundementally different types of firmware. +** PA-RISC platforms have two fundamentally different types of firmware. ** For PCI devices, "Legacy" PDC initializes the "INTERRUPT_LINE" register ** and BARs similar to a traditional PC BIOS. ** The newer "PAT" firmware supports PDC calls which return tables. -** PAT firmware only initializes PCI Console and Boot interface. -** With these tables, the OS can progam all other PCI devices. +** PAT firmware only initializes the PCI Console and Boot interface. +** With these tables, the OS can program all other PCI devices. ** ** One such PAT PDC call returns the "Interrupt Routing Table" (IRT). ** The IRT maps each PCI slot's INTA-D "output" line to an I/O SAPIC diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index c3ac98a0a6a6..f55ac3885cb3 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -531,7 +531,7 @@ static u8 hpc_readcmdtoindex (u8 cmd, u8 index) * * Action: issue a READ command to HPC * -* Input: pslot - can not be NULL for READ_ALLSTAT +* Input: pslot - cannot be NULL for READ_ALLSTAT * pstatus - can be NULL for READ_ALLSTAT * * Return 0 or error codes diff --git a/drivers/s390/net/claw.h b/drivers/s390/net/claw.h index 969be465309c..1ee9a6f06541 100644 --- a/drivers/s390/net/claw.h +++ b/drivers/s390/net/claw.h @@ -29,7 +29,7 @@ #define CLAW_COMPLETE 0xff /* flag to indicate i/o completed */ /*-----------------------------------------------------* -* CLAW control comand code * +* CLAW control command code * *------------------------------------------------------*/ #define SYSTEM_VALIDATE_REQUEST 0x01 /* System Validate request */ diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h index b79f45f3ad47..a11f4e6d8bd9 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg_def.h +++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h @@ -2000,7 +2000,7 @@ * The host accesses this scratch in a different manner from the * central sequencer. The sequencer has to use CSEQ registers CSCRPAGE * and CMnSCRPAGE to access the scratch memory. A flat mapping of the - * scratch memory is avaliable for software convenience and to prevent + * scratch memory is available for software convenience and to prevent * corruption while the sequencer is running. This memory is mapped * onto addresses 800h - BFFh, total of 400h bytes. * diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index de7c04d4254d..e5a0ec37e954 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c @@ -64,7 +64,7 @@ struct asd_ocm_dir { #define OCM_INIT_DIR_ENTRIES 5 /*************************************************************************** -* OCM dircetory default +* OCM directory default ***************************************************************************/ static struct asd_ocm_dir OCMDirInit = { @@ -73,7 +73,7 @@ static struct asd_ocm_dir OCMDirInit = }; /*************************************************************************** -* OCM dircetory Entries default +* OCM directory Entries default ***************************************************************************/ static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] = { diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 6cc2bc2f62be..adb8eb4f5fd1 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -185,7 +185,7 @@ static inline struct list_head *ncr_list_pop(struct list_head *head) ** power of 2 cache line size. ** Enhanced in linux-2.3.44 to provide a memory pool ** per pcidev to support dynamic dma mapping. (I would -** have preferred a real bus astraction, btw). +** have preferred a real bus abstraction, btw). ** **========================================================== */ @@ -1438,7 +1438,7 @@ struct head { ** The first four bytes (scr_st[4]) are used inside the script by ** "COPY" commands. ** Because source and destination must have the same alignment -** in a DWORD, the fields HAVE to be at the choosen offsets. +** in a DWORD, the fields HAVE to be at the chosen offsets. ** xerr_st 0 (0x34) scratcha ** sync_st 1 (0x05) sxfer ** wide_st 3 (0x03) scntl3 @@ -1498,7 +1498,7 @@ struct head { ** the DSA (data structure address) register points ** to this substructure of the ccb. ** This substructure contains the header with -** the script-processor-changable data and +** the script-processor-changeable data and ** data blocks for the indirect move commands. ** **---------------------------------------------------------- @@ -5107,7 +5107,7 @@ void ncr_complete (struct ncb *np, struct ccb *cp) /* ** This CCB has been skipped by the NCR. -** Queue it in the correponding unit queue. +** Queue it in the corresponding unit queue. */ static void ncr_ccb_skipped(struct ncb *np, struct ccb *cp) { @@ -5896,8 +5896,8 @@ static void ncr_log_hard_error(struct ncb *np, u16 sist, u_char dstat) ** ** In normal cases, interrupt conditions occur one at a ** time. The ncr is able to stack in some extra registers -** other interrupts that will occurs after the first one. -** But severall interrupts may occur at the same time. +** other interrupts that will occur after the first one. +** But, several interrupts may occur at the same time. ** ** We probably should only try to deal with the normal ** case, but it seems that multiple interrupts occur in @@ -6796,7 +6796,7 @@ void ncr_int_sir (struct ncb *np) ** The host status field is set to HS_NEGOTIATE to mark this ** situation. ** -** If the target doesn't answer this message immidiately +** If the target doesn't answer this message immediately ** (as required by the standard), the SIR_NEGO_FAIL interrupt ** will be raised eventually. ** The handler removes the HS_NEGOTIATE status, and sets the diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h index cb8b7701431e..b39357d9af8d 100644 --- a/drivers/scsi/ncr53c8xx.h +++ b/drivers/scsi/ncr53c8xx.h @@ -218,7 +218,7 @@ ** Same as option 1, but also deal with ** misconfigured interrupts. ** -** - Edge triggerred instead of level sensitive. +** - Edge triggered instead of level sensitive. ** - No interrupt line connected. ** - IRQ number misconfigured. ** @@ -549,7 +549,7 @@ struct ncr_driver_setup { /* ** Initial setup. -** Can be overriden at startup by a command line. +** Can be overridden at startup by a command line. */ #define SCSI_NCR_DRIVER_SETUP \ { \ @@ -1093,7 +1093,7 @@ struct scr_tblsel { **----------------------------------------------------------- ** On 810A, 860, 825A, 875, 895 and 896 chips the content ** of SFBR register can be used as data (SCR_SFBR_DATA). -** The 896 has additionnal IO registers starting at +** The 896 has additional IO registers starting at ** offset 0x80. Bit 7 of register offset is stored in ** bit 7 of the SCRIPTS instruction first DWORD. **----------------------------------------------------------- diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 32c635ecbf31..a00d1595656c 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -211,7 +211,7 @@ int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, u8 addressofs, int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, u8 addressofs, u8 width, u32 data); /* -* these can not be inlines because we need the structure offset!! +* these cannot be inlines because we need the structure offset!! * Does anyone have a better way????? */ #define u132_read_pcimem(u132, member, data) \ @@ -3045,7 +3045,7 @@ static struct hc_driver u132_hc_driver = { * This function may be called by the USB core whilst the "usb_all_devices_rwsem" * is held for writing, thus this module must not call usb_remove_hcd() * synchronously - but instead should immediately stop activity to the -* device and ansynchronously call usb_remove_hcd() +* device and asynchronously call usb_remove_hcd() */ static int __devexit u132_remove(struct platform_device *pdev) { @@ -3241,7 +3241,7 @@ static int u132_resume(struct platform_device *pdev) #define u132_resume NULL #endif /* -* this driver is loaded explicitely by ftdi_u132 +* this driver is loaded explicitly by ftdi_u132 * * the platform_driver struct is static because it is per type of module */ diff --git a/drivers/usb/misc/usb_u132.h b/drivers/usb/misc/usb_u132.h index 551ba8906d62..5b5a3e621daa 100644 --- a/drivers/usb/misc/usb_u132.h +++ b/drivers/usb/misc/usb_u132.h @@ -52,7 +52,7 @@ * the kernel to load the "u132-hcd" module. * * The "ftdi-u132" module provides the interface to the inserted -* PC card and the "u132-hcd" module uses the API to send and recieve +* PC card and the "u132-hcd" module uses the API to send and receive * data. The API features call-backs, so that part of the "u132-hcd" * module code will run in the context of one of the kernel threads * of the "ftdi-u132" module. diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index bdb58100fc1d..5e3ac281a2f8 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -157,7 +157,7 @@ * to TASK_RUNNING will be lost and write_chan's subsequent call to * schedule() will never return (unless it catches a signal). * This race condition occurs because write_bulk_callback() (and thus -* the wakeup) are called asynchonously from an interrupt, rather than +* the wakeup) are called asynchronously from an interrupt, rather than * from the scheduler. We can avoid the race by calling the wakeup * from the scheduler queue and that's our fix: Now, at the end of * write_bulk_callback() we queue up a wakeup call on the scheduler diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 85ce23268302..ac93174c9639 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -1464,7 +1464,7 @@ static int flush_journal_list(struct super_block *s, } /* if someone has this block in a newer transaction, just make - ** sure they are commited, and don't try writing it to disk + ** sure they are committed, and don't try writing it to disk */ if (pjl) { if (atomic_read(&pjl->j_commit_left)) @@ -3384,7 +3384,7 @@ static int remove_from_transaction(struct super_block *p_s_sb, /* ** for any cnode in a journal list, it can only be dirtied of all the -** transactions that include it are commited to disk. +** transactions that include it are committed to disk. ** this checks through each transaction, and returns 1 if you are allowed to dirty, ** and 0 if you aren't ** @@ -3426,7 +3426,7 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) } /* syncs the commit blocks, but does not force the real buffers to disk -** will wait until the current transaction is done/commited before returning +** will wait until the current transaction is done/committed before returning */ int journal_end_sync(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) diff --git a/include/asm-m68knommu/mcfmbus.h b/include/asm-m68knommu/mcfmbus.h index 13df9d41bd1a..319899c47a2c 100644 --- a/include/asm-m68knommu/mcfmbus.h +++ b/include/asm-m68knommu/mcfmbus.h @@ -37,7 +37,7 @@ #define MCFMBUS_MFDR_MBC(a) ((a)&0x3F) /*M-Bus Clock*/ /* -* Define bit flags in Controll Register +* Define bit flags in Control Register */ #define MCFMBUS_MBCR_MEN (0x80) /* M-Bus Enable */ diff --git a/include/asm-parisc/dma.h b/include/asm-parisc/dma.h index da2cf373e31c..31ad0f05af3d 100644 --- a/include/asm-parisc/dma.h +++ b/include/asm-parisc/dma.h @@ -17,10 +17,10 @@ /* ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up -** (or rather not merge) DMA's into managable chunks. +** (or rather not merge) DMAs into manageable chunks. ** On parisc, this is more of the software/tuning constraint -** rather than the HW. I/O MMU allocation alogorithms can be -** faster with smaller size is (to some degree). +** rather than the HW. I/O MMU allocation algorithms can be +** faster with smaller sizes (to some degree). */ #define DMA_CHUNK_SIZE (BITS_PER_LONG*PAGE_SIZE) diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h index 7b8ad118d2fe..7b3be9ac0dda 100644 --- a/include/asm-parisc/pci.h +++ b/include/asm-parisc/pci.h @@ -149,7 +149,7 @@ extern int parisc_bus_is_phys; /* in arch/parisc/kernel/setup.c */ /* ** Most PCI devices (eg Tulip, NCR720) also export the same registers ** to both MMIO and I/O port space. Due to poor performance of I/O Port -** access under HP PCI bus adapters, strongly reccomend use of MMIO +** access under HP PCI bus adapters, strongly recommend the use of MMIO ** address space. ** ** While I'm at it more PA programming notes: diff --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h index 5542dd00472b..007a880615eb 100644 --- a/include/asm-parisc/ropes.h +++ b/include/asm-parisc/ropes.h @@ -14,7 +14,7 @@ #endif /* -** The number of pdir entries to "free" before issueing +** The number of pdir entries to "free" before issuing ** a read to PCOM register to flush out PCOM writes. ** Interacts with allocation granularity (ie 4 or 8 entries ** allocated and free'd/purged at a time might make this diff --git a/include/linux/ixjuser.h b/include/linux/ixjuser.h index fd1756d3a47e..88b45895746d 100644 --- a/include/linux/ixjuser.h +++ b/include/linux/ixjuser.h @@ -315,7 +315,7 @@ typedef struct { * structures. If the freq0 variable is non-zero, the tone table contents * for the tone_index are updated to the frequencies and gains defined. It * should be noted that DTMF tones cannot be reassigned, so if DTMF tone -* table indexs are used in a cadence the frequency and gain variables will +* table indexes are used in a cadence the frequency and gain variables will * be ignored. * * If the array elements contain frequency parameters the driver will diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h index 73e0becec086..62a7169aed8b 100644 --- a/include/linux/reiserfs_fs_sb.h +++ b/include/linux/reiserfs_fs_sb.h @@ -429,7 +429,7 @@ enum reiserfs_mount_options { /* -o hash={tea, rupasov, r5, detect} is meant for properly mounting ** reiserfs disks from 3.5.19 or earlier. 99% of the time, this option ** is not required. If the normal autodection code can't determine which -** hash to use (because both hases had the same value for a file) +** hash to use (because both hashes had the same value for a file) ** use this option to force a specific hash. It won't allow you to override ** the existing hash on the FS, so if you have a tea hash disk, and mount ** with -o hash=rupasov, the mount will fail. diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c index 6f39faa15832..c2059733e15a 100644 --- a/net/wanrouter/af_wanpipe.c +++ b/net/wanrouter/af_wanpipe.c @@ -13,7 +13,7 @@ * Due Credit: * Wanpipe socket layer is based on Packet and * the X25 socket layers. The above sockets were -* used for the specific use of Sangoma Technoloiges +* used for the specific use of Sangoma Technologies * API programs. * Packet socket Authors: Ross Biro, Fred N. van Kempen and * Alan Cox. @@ -23,7 +23,7 @@ * Apr 25, 2000 Nenad Corbic o Added the ability to send zero length packets. * Mar 13, 2000 Nenad Corbic o Added a tx buffer check via ioctl call. * Mar 06, 2000 Nenad Corbic o Fixed the corrupt sock lcn problem. -* Server and client applicaton can run +* Server and client application can run * simultaneously without conflicts. * Feb 29, 2000 Nenad Corbic o Added support for PVC protocols, such as * CHDLC, Frame Relay and HDLC API. diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 9479659277ae..316211d9f17d 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -3,7 +3,7 @@ * * This module is completely hardware-independent and provides * the following common services for the WAN Link Drivers: -* o WAN device managenment (registering, unregistering) +* o WAN device management (registering, unregistering) * o Network interface management * o Physical connection management (dial-up, incoming calls) * o Logical connection management (switched virtual circuits) diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c index 6e3c41f530e6..b1c5d8286e40 100644 --- a/sound/oss/cs46xx.c +++ b/sound/oss/cs46xx.c @@ -779,7 +779,7 @@ static unsigned int cs_set_adc_rate(struct cs_state *state, unsigned int rate) rate = 48000 / 9; /* - * We can not capture at at rate greater than the Input Rate (48000). + * We cannot capture at at rate greater than the Input Rate (48000). * Return an error if an attempt is made to stray outside that limit. */ if (rate > 48000) @@ -4754,8 +4754,8 @@ static int cs_hardware_init(struct cs_card *card) mdelay(5 * cs_laptop_wait); /* Shouldnt be needed ?? */ /* -* If we are resuming under 2.2.x then we can not schedule a timeout. -* so, just spin the CPU. +* If we are resuming under 2.2.x then we cannot schedule a timeout, +* so just spin the CPU. */ if (card->pm.flags & CS46XX_PM_IDLE) { /* -- cgit v1.2.3 From 03a67a46af8647b2c7825107045ecae641e103d3 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 30 Nov 2006 05:32:19 +0100 Subject: Fix typos in doc and comments Changes persistant -> persistent. www.dictionary.com does not know persistant (with an A), but should it be one of those things you can spell in more than one correct way, let me know. Signed-off-by: Jan Engelhardt Signed-off-by: Adrian Bunk --- Documentation/Changes | 2 +- Documentation/power/states.txt | 2 +- arch/um/drivers/chan_user.c | 2 +- drivers/message/fusion/mptbase.c | 2 +- drivers/mtd/maps/cfi_flagadm.c | 2 +- drivers/pci/Kconfig | 2 +- fs/Kconfig | 2 +- fs/jfs/jfs_filsys.h | 2 +- include/linux/textsearch.h | 4 ++-- lib/textsearch.c | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/Documentation/Changes b/Documentation/Changes index abee7f58c1ed..73a8617f1861 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -201,7 +201,7 @@ udev ---- udev is a userspace application for populating /dev dynamically with only entries for devices actually present. udev replaces the basic -functionality of devfs, while allowing persistant device naming for +functionality of devfs, while allowing persistent device naming for devices. FUSE diff --git a/Documentation/power/states.txt b/Documentation/power/states.txt index 3e5e5d3ff419..0931a330d362 100644 --- a/Documentation/power/states.txt +++ b/Documentation/power/states.txt @@ -62,7 +62,7 @@ setup via another operating system for it to use. Despite the inconvenience, this method requires minimal work by the kernel, since the firmware will also handle restoring memory contents on resume. -If the kernel is responsible for persistantly saving state, a mechanism +If the kernel is responsible for persistently saving state, a mechanism called 'swsusp' (Swap Suspend) is used to write memory contents to free swap space. swsusp has some restrictive requirements, but should work in most cases. Some, albeit outdated, documentation can be found diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 2f880cb167a5..0cad3546cb89 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -120,7 +120,7 @@ static int winch_thread(void *arg) /* These are synchronization calls between various UML threads on the * host - since they are not different kernel threads, we cannot use * kernel semaphores. We don't use SysV semaphores because they are - * persistant. */ + * persistent. */ count = os_read_file(pipe_fd, &c, sizeof(c)); if(count != sizeof(c)) printk("winch_thread : failed to read synchronization byte, " diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index e5c72719debc..051b7c5b8f03 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -6185,7 +6185,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) "Abort", /* 12h */ "IO Not Yet Executed", /* 13h */ "IO Executed", /* 14h */ - "Persistant Reservation Out Not Affiliation Owner", /* 15h */ + "Persistent Reservation Out Not Affiliation Owner", /* 15h */ "Open Transmit DMA Abort", /* 16h */ "IO Device Missing Delay Retry", /* 17h */ NULL, /* 18h */ diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index 92b5d883d7b0..65e5ee552010 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -80,7 +80,7 @@ struct mtd_partition flagadm_parts[] = { .size = FLASH_PARTITION2_SIZE }, { - .name = "Persistant storage", + .name = "Persistent storage", .offset = FLASH_PARTITION3_ADDR, .size = FLASH_PARTITION3_SIZE } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index d0ba112355cc..3cfb0a3575e6 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -34,7 +34,7 @@ config PCI_MULTITHREAD_PROBE It is very unwise to use this option if you are not using a boot process that can handle devices being created in any - order. A program that can create persistant block and network + order. A program that can create persistent block and network device names (like udev) is a good idea if you wish to use this option. diff --git a/fs/Kconfig b/fs/Kconfig index 8bec76bbc0c3..b3b5aa0edff9 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -972,7 +972,7 @@ config SYSFS Some system agents rely on the information in sysfs to operate. /sbin/hotplug uses device and object attributes in sysfs to assist in - delegating policy decisions, like persistantly naming devices. + delegating policy decisions, like persistently naming devices. sysfs is currently used by the block subsystem to mount the root partition. If sysfs is disabled you must specify the boot device on diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h index 9901928668cf..eb550b339bb8 100644 --- a/fs/jfs/jfs_filsys.h +++ b/fs/jfs/jfs_filsys.h @@ -81,7 +81,7 @@ #define JFS_SWAP_BYTES 0x00100000 /* running on big endian computer */ /* Directory index */ -#define JFS_DIR_INDEX 0x00200000 /* Persistant index for */ +#define JFS_DIR_INDEX 0x00200000 /* Persistent index for */ /* directory entries */ diff --git a/include/linux/textsearch.h b/include/linux/textsearch.h index 7dac8f04d28e..004808a6df1d 100644 --- a/include/linux/textsearch.h +++ b/include/linux/textsearch.h @@ -20,7 +20,7 @@ struct ts_config; /** * struct ts_state - search state * @offset: offset for next match - * @cb: control buffer, for persistant variables of get_next_block() + * @cb: control buffer, for persistent variables of get_next_block() */ struct ts_state { @@ -71,7 +71,7 @@ struct ts_config * Called repeatedly until 0 is returned. Must assign the * head of the next block of data to &*dst and return the length * of the block or 0 if at the end. consumed == 0 indicates - * a new search. May store/read persistant values in state->cb. + * a new search. May store/read persistent values in state->cb. */ unsigned int (*get_next_block)(unsigned int consumed, const u8 **dst, diff --git a/lib/textsearch.c b/lib/textsearch.c index 2cb4a437942e..98bcadc01185 100644 --- a/lib/textsearch.c +++ b/lib/textsearch.c @@ -40,7 +40,7 @@ * configuration according to the specified parameters. * (3) User starts the search(es) by calling _find() or _next() to * fetch subsequent occurrences. A state variable is provided - * to the algorihtm to store persistant variables. + * to the algorihtm to store persistent variables. * (4) Core eventually resets the search offset and forwards the find() * request to the algorithm. * (5) Algorithm calls get_next_block() provided by the user continously -- cgit v1.2.3 From beea494d5e09f9e2172894ec84324b94244826a9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 7 Nov 2006 21:03:20 +0000 Subject: [ARM] Remove EEPROM slave emulation from i2c-pxa driver. The i2c-pxa driver should not contain EEPROM slave-mode emulation; this is something the platform should provide where required. Remove it. Signed-off-by: Russell King --- drivers/i2c/busses/i2c-pxa.c | 131 +------------------------------------------ include/linux/i2c-pxa.h | 31 ---------- 2 files changed, 1 insertion(+), 161 deletions(-) (limited to 'include/linux') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index c95a6c154165..c3b1567c852a 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -357,133 +357,6 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c) #ifdef CONFIG_I2C_PXA_SLAVE -/* - * I2C EEPROM emulation. - */ -static struct i2c_eeprom_emu eeprom = { - .size = I2C_EEPROM_EMU_SIZE, - .watch = LIST_HEAD_INIT(eeprom.watch), -}; - -struct i2c_eeprom_emu *i2c_pxa_get_eeprom(void) -{ - return &eeprom; -} - -int i2c_eeprom_emu_addwatcher(struct i2c_eeprom_emu *emu, void *data, - unsigned int addr, unsigned int size, - struct i2c_eeprom_emu_watcher *watcher) -{ - struct i2c_eeprom_emu_watch *watch; - unsigned long flags; - - if (addr + size > emu->size) - return -EINVAL; - - watch = kmalloc(sizeof(struct i2c_eeprom_emu_watch), GFP_KERNEL); - if (watch) { - watch->start = addr; - watch->end = addr + size - 1; - watch->ops = watcher; - watch->data = data; - - local_irq_save(flags); - list_add(&watch->node, &emu->watch); - local_irq_restore(flags); - } - - return watch ? 0 : -ENOMEM; -} - -void i2c_eeprom_emu_delwatcher(struct i2c_eeprom_emu *emu, void *data, - struct i2c_eeprom_emu_watcher *watcher) -{ - struct i2c_eeprom_emu_watch *watch, *n; - unsigned long flags; - - list_for_each_entry_safe(watch, n, &emu->watch, node) { - if (watch->ops == watcher && watch->data == data) { - local_irq_save(flags); - list_del(&watch->node); - local_irq_restore(flags); - kfree(watch); - } - } -} - -static void i2c_eeprom_emu_event(void *ptr, i2c_slave_event_t event) -{ - struct i2c_eeprom_emu *emu = ptr; - - eedbg(3, "i2c_eeprom_emu_event: %d\n", event); - - switch (event) { - case I2C_SLAVE_EVENT_START_WRITE: - emu->seen_start = 1; - eedbg(2, "i2c_eeprom: write initiated\n"); - break; - - case I2C_SLAVE_EVENT_START_READ: - emu->seen_start = 0; - eedbg(2, "i2c_eeprom: read initiated\n"); - break; - - case I2C_SLAVE_EVENT_STOP: - emu->seen_start = 0; - eedbg(2, "i2c_eeprom: received stop\n"); - break; - - default: - eedbg(0, "i2c_eeprom: unhandled event\n"); - break; - } -} - -static int i2c_eeprom_emu_read(void *ptr) -{ - struct i2c_eeprom_emu *emu = ptr; - int ret; - - ret = emu->bytes[emu->ptr]; - emu->ptr = (emu->ptr + 1) % emu->size; - - return ret; -} - -static void i2c_eeprom_emu_write(void *ptr, unsigned int val) -{ - struct i2c_eeprom_emu *emu = ptr; - struct i2c_eeprom_emu_watch *watch; - - if (emu->seen_start != 0) { - eedbg(2, "i2c_eeprom_emu_write: setting ptr %02x\n", val); - emu->ptr = val; - emu->seen_start = 0; - return; - } - - emu->bytes[emu->ptr] = val; - - eedbg(1, "i2c_eeprom_emu_write: ptr=0x%02x, val=0x%02x\n", - emu->ptr, val); - - list_for_each_entry(watch, &emu->watch, node) { - if (!watch->ops || !watch->ops->write) - continue; - if (watch->start <= emu->ptr && watch->end >= emu->ptr) - watch->ops->write(watch->data, emu->ptr, val); - } - - emu->ptr = (emu->ptr + 1) % emu->size; -} - -struct i2c_slave_client eeprom_client = { - .data = &eeprom, - .event = i2c_eeprom_emu_event, - .read = i2c_eeprom_emu_read, - .write = i2c_eeprom_emu_write -}; - /* * PXA I2C Slave mode */ @@ -963,11 +836,9 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->slave_addr = I2C_PXA_SLAVE_ADDR; #ifdef CONFIG_I2C_PXA_SLAVE - i2c->slave = &eeprom_client; if (plat) { i2c->slave_addr = plat->slave_addr; - if (plat->slave) - i2c->slave = plat->slave; + i2c->slave = plat->slave; } #endif diff --git a/include/linux/i2c-pxa.h b/include/linux/i2c-pxa.h index 5f3eaf802223..41dcdfe7f625 100644 --- a/include/linux/i2c-pxa.h +++ b/include/linux/i2c-pxa.h @@ -1,29 +1,6 @@ #ifndef _LINUX_I2C_ALGO_PXA_H #define _LINUX_I2C_ALGO_PXA_H -struct i2c_eeprom_emu_watcher { - void (*write)(void *, unsigned int addr, unsigned char newval); -}; - -struct i2c_eeprom_emu_watch { - struct list_head node; - unsigned int start; - unsigned int end; - struct i2c_eeprom_emu_watcher *ops; - void *data; -}; - -#define I2C_EEPROM_EMU_SIZE (256) - -struct i2c_eeprom_emu { - unsigned int size; - unsigned int ptr; - unsigned int seen_start; - struct list_head watch; - - unsigned char bytes[I2C_EEPROM_EMU_SIZE]; -}; - typedef enum i2c_slave_event_e { I2C_SLAVE_EVENT_START_READ, I2C_SLAVE_EVENT_START_WRITE, @@ -37,12 +14,4 @@ struct i2c_slave_client { void (*write)(void *ptr, unsigned int val); }; -extern int i2c_eeprom_emu_addwatcher(struct i2c_eeprom_emu *, void *data, - unsigned int addr, unsigned int size, - struct i2c_eeprom_emu_watcher *); - -extern void i2c_eeprom_emu_delwatcher(struct i2c_eeprom_emu *, void *data, struct i2c_eeprom_emu_watcher *watcher); - -extern struct i2c_eeprom_emu *i2c_pxa_get_eeprom(void); - #endif /* _LINUX_I2C_ALGO_PXA_H */ -- cgit v1.2.3 From 3ca68df6ee61e1a2034f3307b9edb9b3d87e5ca1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 20:11:25 -0400 Subject: [GFS2] split gfs2_dinode into on-disk and host variants The latter is used as part of gfs2-private part of struct inode. It actually stores a lot of fields differently; for now the declaration is just cloned, inode field is swtiched and changes propagated. Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 4 ++-- fs/gfs2/ondisk.c | 6 +++--- include/linux/gfs2_ondisk.h | 48 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 50 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index d470e5286ecd..191a3df93d67 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -48,7 +48,7 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) { struct inode *inode = &ip->i_inode; - struct gfs2_dinode *di = &ip->i_di; + struct gfs2_dinode_host *di = &ip->i_di; inode->i_ino = ip->i_num.no_addr; @@ -98,7 +98,7 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) void gfs2_inode_attr_out(struct gfs2_inode *ip) { struct inode *inode = &ip->i_inode; - struct gfs2_dinode *di = &ip->i_di; + struct gfs2_dinode_host *di = &ip->i_di; gfs2_assert_withdraw(GFS2_SB(inode), (di->di_mode & S_IFMT) == (inode->i_mode & S_IFMT)); di->di_mode = inode->i_mode; diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 1025960b0e6e..52cb9a2dc058 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -153,7 +153,7 @@ void gfs2_quota_in(struct gfs2_quota *qu, const void *buf) qu->qu_value = be64_to_cpu(str->qu_value); } -void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf) +void gfs2_dinode_in(struct gfs2_dinode_host *di, const void *buf) { const struct gfs2_dinode *str = buf; @@ -187,7 +187,7 @@ void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf) } -void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf) +void gfs2_dinode_out(const struct gfs2_dinode_host *di, void *buf) { struct gfs2_dinode *str = buf; @@ -221,7 +221,7 @@ void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf) } -void gfs2_dinode_print(const struct gfs2_dinode *di) +void gfs2_dinode_print(const struct gfs2_dinode_host *di) { gfs2_meta_header_print(&di->di_header); gfs2_inum_print(&di->di_num); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index a7ae7c177cac..f334b4bd2915 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -270,6 +270,48 @@ struct gfs2_dinode { __u8 di_reserved[56]; }; +struct gfs2_dinode_host { + struct gfs2_meta_header di_header; + + struct gfs2_inum di_num; + + __be32 di_mode; /* mode of file */ + __be32 di_uid; /* owner's user id */ + __be32 di_gid; /* owner's group id */ + __be32 di_nlink; /* number of links to this file */ + __be64 di_size; /* number of bytes in file */ + __be64 di_blocks; /* number of blocks in file */ + __be64 di_atime; /* time last accessed */ + __be64 di_mtime; /* time last modified */ + __be64 di_ctime; /* time last changed */ + __be32 di_major; /* device major number */ + __be32 di_minor; /* device minor number */ + + /* This section varies from gfs1. Padding added to align with + * remainder of dinode + */ + __be64 di_goal_meta; /* rgrp to alloc from next */ + __be64 di_goal_data; /* data block goal */ + __be64 di_generation; /* generation number for NFS */ + + __be32 di_flags; /* GFS2_DIF_... */ + __be32 di_payload_format; /* GFS2_FORMAT_... */ + __u16 __pad1; /* Was ditype in gfs1 */ + __be16 di_height; /* height of metadata */ + __u32 __pad2; /* Unused incarnation number from gfs1 */ + + /* These only apply to directories */ + __u16 __pad3; /* Padding */ + __be16 di_depth; /* Number of bits in the table */ + __be32 di_entries; /* The number of entries in the directory */ + + struct gfs2_inum __pad4; /* Unused even in current gfs1 */ + + __be64 di_eattr; /* extended attribute block number */ + + __u8 di_reserved[56]; +}; + /* * directory structure - many of these per directory file */ @@ -422,8 +464,8 @@ extern void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf); extern void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf); extern void gfs2_quota_in(struct gfs2_quota *qu, const void *buf); extern void gfs2_quota_out(const struct gfs2_quota *qu, void *buf); -extern void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf); -extern void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf); +extern void gfs2_dinode_in(struct gfs2_dinode_host *di, const void *buf); +extern void gfs2_dinode_out(const struct gfs2_dinode_host *di, void *buf); extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf); extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf); extern void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf); @@ -436,7 +478,7 @@ extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf); /* Printing functions */ extern void gfs2_rindex_print(const struct gfs2_rindex *ri); -extern void gfs2_dinode_print(const struct gfs2_dinode *di); +extern void gfs2_dinode_print(const struct gfs2_dinode_host *di); #endif /* __KERNEL__ */ -- cgit v1.2.3 From 5c6edb576f3800723bb65dbfaff82517089e32d0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 20:33:01 -0400 Subject: [GFS2] gfs2_dinode_host fields are host-endian Annotated scalar fields, dropped unused ones. Note that it's not at all obvious that we want to convert all of them to host-endian... Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 2 +- include/linux/gfs2_ondisk.h | 47 +++++++++++++++++++-------------------------- 2 files changed, 21 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 118dc693d111..1c876e0fb44a 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -229,7 +229,7 @@ struct gfs2_inode { unsigned long i_flags; /* GIF_... */ u64 i_vn; - struct gfs2_dinode i_di; /* To be replaced by ref to block */ + struct gfs2_dinode_host i_di; /* To be replaced by ref to block */ struct gfs2_glock *i_gl; /* Move into i_gh? */ struct gfs2_holder i_iopen_gh; diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index f334b4bd2915..0e67a89a9699 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -275,41 +275,34 @@ struct gfs2_dinode_host { struct gfs2_inum di_num; - __be32 di_mode; /* mode of file */ - __be32 di_uid; /* owner's user id */ - __be32 di_gid; /* owner's group id */ - __be32 di_nlink; /* number of links to this file */ - __be64 di_size; /* number of bytes in file */ - __be64 di_blocks; /* number of blocks in file */ - __be64 di_atime; /* time last accessed */ - __be64 di_mtime; /* time last modified */ - __be64 di_ctime; /* time last changed */ - __be32 di_major; /* device major number */ - __be32 di_minor; /* device minor number */ + __u32 di_mode; /* mode of file */ + __u32 di_uid; /* owner's user id */ + __u32 di_gid; /* owner's group id */ + __u32 di_nlink; /* number of links to this file */ + __u64 di_size; /* number of bytes in file */ + __u64 di_blocks; /* number of blocks in file */ + __u64 di_atime; /* time last accessed */ + __u64 di_mtime; /* time last modified */ + __u64 di_ctime; /* time last changed */ + __u32 di_major; /* device major number */ + __u32 di_minor; /* device minor number */ /* This section varies from gfs1. Padding added to align with * remainder of dinode */ - __be64 di_goal_meta; /* rgrp to alloc from next */ - __be64 di_goal_data; /* data block goal */ - __be64 di_generation; /* generation number for NFS */ + __u64 di_goal_meta; /* rgrp to alloc from next */ + __u64 di_goal_data; /* data block goal */ + __u64 di_generation; /* generation number for NFS */ - __be32 di_flags; /* GFS2_DIF_... */ - __be32 di_payload_format; /* GFS2_FORMAT_... */ - __u16 __pad1; /* Was ditype in gfs1 */ - __be16 di_height; /* height of metadata */ - __u32 __pad2; /* Unused incarnation number from gfs1 */ + __u32 di_flags; /* GFS2_DIF_... */ + __u32 di_payload_format; /* GFS2_FORMAT_... */ + __u16 di_height; /* height of metadata */ /* These only apply to directories */ - __u16 __pad3; /* Padding */ - __be16 di_depth; /* Number of bits in the table */ - __be32 di_entries; /* The number of entries in the directory */ - - struct gfs2_inum __pad4; /* Unused even in current gfs1 */ + __u16 di_depth; /* Number of bits in the table */ + __u32 di_entries; /* The number of entries in the directory */ - __be64 di_eattr; /* extended attribute block number */ - - __u8 di_reserved[56]; + __u64 di_eattr; /* extended attribute block number */ }; /* -- cgit v1.2.3 From f50dfaf78c01df3cc2d8819f07d6661915567bae Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 20:45:02 -0400 Subject: [GFS2] split gfs2_sb Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 2 +- fs/gfs2/ondisk.c | 2 +- fs/gfs2/super.c | 2 +- fs/gfs2/super.h | 2 +- include/linux/gfs2_ondisk.h | 22 +++++++++++++++++++++- 5 files changed, 25 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 1c876e0fb44a..bd596ba74e56 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -450,7 +450,7 @@ struct gfs2_sbd { struct super_block *sd_vfs_meta; struct kobject sd_kobj; unsigned long sd_flags; /* SDF_... */ - struct gfs2_sb sd_sb; + struct gfs2_sb_host sd_sb; /* Constants computed on mount */ diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 52cb9a2dc058..5b32f1a35794 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -79,7 +79,7 @@ static void gfs2_meta_header_print(const struct gfs2_meta_header *mh) pv(mh, mh_format, "%u"); } -void gfs2_sb_in(struct gfs2_sb *sb, const void *buf) +void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf) { const struct gfs2_sb *str = buf; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 6a78b1b32e25..52aa3221fc99 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -97,7 +97,7 @@ void gfs2_tune_init(struct gfs2_tune *gt) * changed. */ -int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent) +int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent) { unsigned int x; diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 5bb443ae0f59..ac95064c1e5a 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -14,7 +14,7 @@ void gfs2_tune_init(struct gfs2_tune *gt); -int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent); +int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent); int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent); struct page *gfs2_read_super(struct super_block *sb, sector_t sector); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 0e67a89a9699..b7bdfef82e4e 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -128,6 +128,26 @@ struct gfs2_sb { /* In gfs1, quota and license dinodes followed */ }; +struct gfs2_sb_host { + struct gfs2_meta_header sb_header; + + __be32 sb_fs_format; + __be32 sb_multihost_format; + __u32 __pad0; /* Was superblock flags in gfs1 */ + + __be32 sb_bsize; + __be32 sb_bsize_shift; + __u32 __pad1; /* Was journal segment size in gfs1 */ + + struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ + struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */ + struct gfs2_inum sb_root_dir; + + char sb_lockproto[GFS2_LOCKNAME_LEN]; + char sb_locktable[GFS2_LOCKNAME_LEN]; + /* In gfs1, quota and license dinodes followed */ +}; + /* * resource index structure */ @@ -450,7 +470,7 @@ struct gfs2_quota_change { extern void gfs2_inum_in(struct gfs2_inum *no, const void *buf); extern void gfs2_inum_out(const struct gfs2_inum *no, void *buf); -extern void gfs2_sb_in(struct gfs2_sb *sb, const void *buf); +extern void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf); extern void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf); extern void gfs2_rindex_out(const struct gfs2_rindex *ri, void *buf); extern void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf); -- cgit v1.2.3 From bc558c87bb7e50c4f728d32684a9f4f4c73ebde3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 21:02:41 -0400 Subject: [GFS2] fields of gfs2_sb_host are host-endian ... and several could be killed, but that's another story. Annotate scalar ones, kill completely unused. Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- include/linux/gfs2_ondisk.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index b7bdfef82e4e..a5d36cdc46e9 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -131,16 +131,13 @@ struct gfs2_sb { struct gfs2_sb_host { struct gfs2_meta_header sb_header; - __be32 sb_fs_format; - __be32 sb_multihost_format; - __u32 __pad0; /* Was superblock flags in gfs1 */ + __u32 sb_fs_format; + __u32 sb_multihost_format; - __be32 sb_bsize; - __be32 sb_bsize_shift; - __u32 __pad1; /* Was journal segment size in gfs1 */ + __u32 sb_bsize; + __u32 sb_bsize_shift; struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ - struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */ struct gfs2_inum sb_root_dir; char sb_lockproto[GFS2_LOCKNAME_LEN]; -- cgit v1.2.3 From 68826664d12827d7a732192e2f00ba46fb899414 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 21:07:22 -0400 Subject: [GFS2] split and annotate gfs2_rgrp Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 2 +- fs/gfs2/ondisk.c | 4 ++-- include/linux/gfs2_ondisk.h | 13 +++++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index bd596ba74e56..8ca7a7f35062 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -68,7 +68,7 @@ struct gfs2_rgrpd { struct list_head rd_recent; /* Recently used rgrps */ struct gfs2_glock *rd_gl; /* Glock for this rgrp */ struct gfs2_rindex rd_ri; - struct gfs2_rgrp rd_rg; + struct gfs2_rgrp_host rd_rg; u64 rd_rg_vn; struct gfs2_bitmap *rd_bits; unsigned int rd_bh_count; diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 5b32f1a35794..3b156a15cd8d 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -120,7 +120,7 @@ void gfs2_rindex_print(const struct gfs2_rindex *ri) pv(ri, ri_bitbytes, "%u"); } -void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf) +void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf) { const struct gfs2_rgrp *str = buf; @@ -131,7 +131,7 @@ void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf) rg->rg_igeneration = be64_to_cpu(str->rg_igeneration); } -void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf) +void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf) { struct gfs2_rgrp *str = buf; diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index a5d36cdc46e9..e4ca6e4176bb 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -193,6 +193,15 @@ struct gfs2_rgrp { __u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */ }; +struct gfs2_rgrp_host { + struct gfs2_meta_header rg_header; + + __u32 rg_flags; + __u32 rg_free; + __u32 rg_dinodes; + __u64 rg_igeneration; +}; + /* * quota structure */ @@ -470,8 +479,8 @@ extern void gfs2_inum_out(const struct gfs2_inum *no, void *buf); extern void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf); extern void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf); extern void gfs2_rindex_out(const struct gfs2_rindex *ri, void *buf); -extern void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf); -extern void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf); +extern void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf); +extern void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf); extern void gfs2_quota_in(struct gfs2_quota *qu, const void *buf); extern void gfs2_quota_out(const struct gfs2_quota *qu, void *buf); extern void gfs2_dinode_in(struct gfs2_dinode_host *di, const void *buf); -- cgit v1.2.3 From e697264709c86040271cdd7abee781d7adbb7f91 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 21:29:46 -0400 Subject: [GFS2] split and annotate gfs2_inum_range Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 4 ++-- fs/gfs2/ondisk.c | 4 ++-- include/linux/gfs2_ondisk.h | 9 +++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 191a3df93d67..7eb6b440da6d 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -436,7 +436,7 @@ static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino) { struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode); struct buffer_head *bh; - struct gfs2_inum_range ir; + struct gfs2_inum_range_host ir; int error; error = gfs2_trans_begin(sdp, RES_DINODE, 0); @@ -479,7 +479,7 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, u64 *formal_ino) struct gfs2_inode *m_ip = GFS2_I(sdp->sd_inum_inode); struct gfs2_holder gh; struct buffer_head *bh; - struct gfs2_inum_range ir; + struct gfs2_inum_range_host ir; int error; error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 3b156a15cd8d..64f5f0c604aa 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -263,7 +263,7 @@ void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf) lh->lh_hash = be32_to_cpu(str->lh_hash); } -void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf) +void gfs2_inum_range_in(struct gfs2_inum_range_host *ir, const void *buf) { const struct gfs2_inum_range *str = buf; @@ -271,7 +271,7 @@ void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf) ir->ir_length = be64_to_cpu(str->ir_length); } -void gfs2_inum_range_out(const struct gfs2_inum_range *ir, void *buf) +void gfs2_inum_range_out(const struct gfs2_inum_range_host *ir, void *buf) { struct gfs2_inum_range *str = buf; diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index e4ca6e4176bb..c035587d066e 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -445,6 +445,11 @@ struct gfs2_inum_range { __be64 ir_length; }; +struct gfs2_inum_range_host { + __u64 ir_start; + __u64 ir_length; +}; + /* * Statfs change * Describes an change to the pool of free and allocated @@ -488,8 +493,8 @@ extern void gfs2_dinode_out(const struct gfs2_dinode_host *di, void *buf); extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf); extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf); extern void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf); -extern void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf); -extern void gfs2_inum_range_out(const struct gfs2_inum_range *ir, void *buf); +extern void gfs2_inum_range_in(struct gfs2_inum_range_host *ir, const void *buf); +extern void gfs2_inum_range_out(const struct gfs2_inum_range_host *ir, void *buf); extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf); extern void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf); extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf); -- cgit v1.2.3 From 551676226163379c217e8ec54bd287eab9b8521e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 21:47:13 -0400 Subject: [GFS2] split and annotate gfs2_log_head Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/glops.c | 2 +- fs/gfs2/incore.h | 2 +- fs/gfs2/lops.c | 4 ++-- fs/gfs2/lops.h | 2 +- fs/gfs2/ondisk.c | 2 +- fs/gfs2/recovery.c | 22 +++++++++++----------- fs/gfs2/recovery.h | 2 +- fs/gfs2/super.c | 4 ++-- include/linux/gfs2_ondisk.h | 12 +++++++++++- 9 files changed, 31 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 41a6b6818a50..5406b193227c 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -491,7 +491,7 @@ static void trans_go_xmote_bh(struct gfs2_glock *gl) struct gfs2_sbd *sdp = gl->gl_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode); struct gfs2_glock *j_gl = ip->i_gl; - struct gfs2_log_header head; + struct gfs2_log_header_host head; int error; if (gl->gl_state != LM_ST_UNLOCKED && diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 8ca7a7f35062..e69f3394a2ce 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -41,7 +41,7 @@ struct gfs2_log_operations { void (*lo_before_commit) (struct gfs2_sbd *sdp); void (*lo_after_commit) (struct gfs2_sbd *sdp, struct gfs2_ail *ai); void (*lo_before_scan) (struct gfs2_jdesc *jd, - struct gfs2_log_header *head, int pass); + struct gfs2_log_header_host *head, int pass); int (*lo_scan_elements) (struct gfs2_jdesc *jd, unsigned int start, struct gfs2_log_descriptor *ld, __be64 *ptr, int pass); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index ab6d1115f95d..8a654cd253dd 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -182,7 +182,7 @@ static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) } static void buf_lo_before_scan(struct gfs2_jdesc *jd, - struct gfs2_log_header *head, int pass) + struct gfs2_log_header_host *head, int pass) { struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); @@ -328,7 +328,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) } static void revoke_lo_before_scan(struct gfs2_jdesc *jd, - struct gfs2_log_header *head, int pass) + struct gfs2_log_header_host *head, int pass) { struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h index 5839c05ae6be..965bc65c7c64 100644 --- a/fs/gfs2/lops.h +++ b/fs/gfs2/lops.h @@ -60,7 +60,7 @@ static inline void lops_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) } static inline void lops_before_scan(struct gfs2_jdesc *jd, - struct gfs2_log_header *head, + struct gfs2_log_header_host *head, unsigned int pass) { int x; diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 64f5f0c604aa..84b1ebc7569e 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -251,7 +251,7 @@ void gfs2_dinode_print(const struct gfs2_dinode_host *di) printk(KERN_INFO " di_eattr = %llu\n", (unsigned long long)di->di_eattr); } -void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf) +void gfs2_log_header_in(struct gfs2_log_header_host *lh, const void *buf) { const struct gfs2_log_header *str = buf; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 62cd223819b7..447816241626 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -132,10 +132,10 @@ void gfs2_revoke_clean(struct gfs2_sbd *sdp) */ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, - struct gfs2_log_header *head) + struct gfs2_log_header_host *head) { struct buffer_head *bh; - struct gfs2_log_header lh; + struct gfs2_log_header_host lh; u32 hash; int error; @@ -143,7 +143,7 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, if (error) return error; - memcpy(&lh, bh->b_data, sizeof(struct gfs2_log_header)); + memcpy(&lh, bh->b_data, sizeof(struct gfs2_log_header)); /* XXX */ lh.lh_hash = 0; hash = gfs2_disk_hash((char *)&lh, sizeof(struct gfs2_log_header)); gfs2_log_header_in(&lh, bh->b_data); @@ -174,7 +174,7 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, */ static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk, - struct gfs2_log_header *head) + struct gfs2_log_header_host *head) { unsigned int orig_blk = *blk; int error; @@ -205,10 +205,10 @@ static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk, * Returns: errno */ -static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head) +static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) { unsigned int blk = head->lh_blkno; - struct gfs2_log_header lh; + struct gfs2_log_header_host lh; int error; for (;;) { @@ -245,9 +245,9 @@ static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head) * Returns: errno */ -int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header *head) +int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) { - struct gfs2_log_header lh_1, lh_m; + struct gfs2_log_header_host lh_1, lh_m; u32 blk_1, blk_2, blk_m; int error; @@ -320,7 +320,7 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, length = be32_to_cpu(ld->ld_length); if (be32_to_cpu(ld->ld_header.mh_type) == GFS2_METATYPE_LH) { - struct gfs2_log_header lh; + struct gfs2_log_header_host lh; error = get_log_header(jd, start, &lh); if (!error) { gfs2_replay_incr_blk(sdp, &start); @@ -363,7 +363,7 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, * Returns: errno */ -static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) +static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) { struct gfs2_inode *ip = GFS2_I(jd->jd_inode); struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); @@ -425,7 +425,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) { struct gfs2_inode *ip = GFS2_I(jd->jd_inode); struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); - struct gfs2_log_header head; + struct gfs2_log_header_host head; struct gfs2_holder j_gh, ji_gh, t_gh; unsigned long t; int ro = 0; diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index 961feedf4d8b..f7235e61c723 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h @@ -26,7 +26,7 @@ int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where); void gfs2_revoke_clean(struct gfs2_sbd *sdp); int gfs2_find_jhead(struct gfs2_jdesc *jd, - struct gfs2_log_header *head); + struct gfs2_log_header_host *head); int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd); void gfs2_check_journals(struct gfs2_sbd *sdp); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 52aa3221fc99..0faf563c83a9 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -508,7 +508,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode); struct gfs2_glock *j_gl = ip->i_gl; struct gfs2_holder t_gh; - struct gfs2_log_header head; + struct gfs2_log_header_host head; int error; error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, @@ -873,7 +873,7 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd; struct lfcc *lfcc; LIST_HEAD(list); - struct gfs2_log_header lh; + struct gfs2_log_header_host lh; int error; error = gfs2_jindex_hold(sdp, &ji_gh); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index c035587d066e..fb69a64c70cd 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -405,6 +405,16 @@ struct gfs2_log_header { __be32 lh_hash; }; +struct gfs2_log_header_host { + struct gfs2_meta_header lh_header; + + __u64 lh_sequence; /* Sequence number of this transaction */ + __u32 lh_flags; /* GFS2_LOG_HEAD_... */ + __u32 lh_tail; /* Block number of log tail */ + __u32 lh_blkno; + __u32 lh_hash; +}; + /* * Log type descriptor */ @@ -492,7 +502,7 @@ extern void gfs2_dinode_in(struct gfs2_dinode_host *di, const void *buf); extern void gfs2_dinode_out(const struct gfs2_dinode_host *di, void *buf); extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf); extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf); -extern void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf); +extern void gfs2_log_header_in(struct gfs2_log_header_host *lh, const void *buf); extern void gfs2_inum_range_in(struct gfs2_inum_range_host *ir, const void *buf); extern void gfs2_inum_range_out(const struct gfs2_inum_range_host *ir, void *buf); extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf); -- cgit v1.2.3 From e928a76f959e89884f6186bb6f846c533847d5df Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 21:57:23 -0400 Subject: [GFS2] split and annotate gfs2_meta_header Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/ondisk.c | 6 +++--- include/linux/gfs2_ondisk.h | 14 ++++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 84b1ebc7569e..b5aa7ab97f28 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -54,7 +54,7 @@ static void gfs2_inum_print(const struct gfs2_inum *no) printk(KERN_INFO " no_addr = %llu\n", (unsigned long long)no->no_addr); } -static void gfs2_meta_header_in(struct gfs2_meta_header *mh, const void *buf) +static void gfs2_meta_header_in(struct gfs2_meta_header_host *mh, const void *buf) { const struct gfs2_meta_header *str = buf; @@ -63,7 +63,7 @@ static void gfs2_meta_header_in(struct gfs2_meta_header *mh, const void *buf) mh->mh_format = be32_to_cpu(str->mh_format); } -static void gfs2_meta_header_out(const struct gfs2_meta_header *mh, void *buf) +static void gfs2_meta_header_out(const struct gfs2_meta_header_host *mh, void *buf) { struct gfs2_meta_header *str = buf; @@ -72,7 +72,7 @@ static void gfs2_meta_header_out(const struct gfs2_meta_header *mh, void *buf) str->mh_format = cpu_to_be32(mh->mh_format); } -static void gfs2_meta_header_print(const struct gfs2_meta_header *mh) +static void gfs2_meta_header_print(const struct gfs2_meta_header_host *mh) { pv(mh, mh_magic, "0x%.8X"); pv(mh, mh_type, "%u"); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index fb69a64c70cd..76eb9e1bb773 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -89,6 +89,12 @@ struct gfs2_meta_header { __be32 __pad1; /* Was incarnation number in gfs1 */ }; +struct gfs2_meta_header_host { + __u32 mh_magic; + __u32 mh_type; + __u32 mh_format; +}; + /* * super-block structure * @@ -129,7 +135,7 @@ struct gfs2_sb { }; struct gfs2_sb_host { - struct gfs2_meta_header sb_header; + struct gfs2_meta_header_host sb_header; __u32 sb_fs_format; __u32 sb_multihost_format; @@ -194,7 +200,7 @@ struct gfs2_rgrp { }; struct gfs2_rgrp_host { - struct gfs2_meta_header rg_header; + struct gfs2_meta_header_host rg_header; __u32 rg_flags; __u32 rg_free; @@ -297,7 +303,7 @@ struct gfs2_dinode { }; struct gfs2_dinode_host { - struct gfs2_meta_header di_header; + struct gfs2_meta_header_host di_header; struct gfs2_inum di_num; @@ -406,7 +412,7 @@ struct gfs2_log_header { }; struct gfs2_log_header_host { - struct gfs2_meta_header lh_header; + struct gfs2_meta_header_host lh_header; __u64 lh_sequence; /* Sequence number of this transaction */ __u32 lh_flags; /* GFS2_LOG_HEAD_... */ -- cgit v1.2.3 From 1e81c4c3e0f55c95b6278a827262b80debd0dc7e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 22:51:24 -0400 Subject: [GFS2] split and annotate gfs_rindex Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 2 +- fs/gfs2/ondisk.c | 4 ++-- fs/gfs2/rgrp.c | 2 +- include/linux/gfs2_ondisk.h | 14 +++++++++++--- 4 files changed, 15 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index e69f3394a2ce..e4afc2c4d609 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -67,7 +67,7 @@ struct gfs2_rgrpd { struct list_head rd_list_mru; struct list_head rd_recent; /* Recently used rgrps */ struct gfs2_glock *rd_gl; /* Glock for this rgrp */ - struct gfs2_rindex rd_ri; + struct gfs2_rindex_host rd_ri; struct gfs2_rgrp_host rd_rg; u64 rd_rg_vn; struct gfs2_bitmap *rd_bits; diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index b5aa7ab97f28..c4e099d582f7 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -97,7 +97,7 @@ void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf) memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN); } -void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf) +void gfs2_rindex_in(struct gfs2_rindex_host *ri, const void *buf) { const struct gfs2_rindex *str = buf; @@ -109,7 +109,7 @@ void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf) } -void gfs2_rindex_print(const struct gfs2_rindex *ri) +void gfs2_rindex_print(const struct gfs2_rindex_host *ri) { printk(KERN_INFO " ri_addr = %llu\n", (unsigned long long)ri->ri_addr); pv(ri, ri_length, "%u"); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index b261385c0065..07dfd6305058 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -253,7 +253,7 @@ void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd) } -static inline int rgrp_contains_block(struct gfs2_rindex *ri, u64 block) +static inline int rgrp_contains_block(struct gfs2_rindex_host *ri, u64 block) { u64 first = ri->ri_data0; u64 last = first + ri->ri_data; diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 76eb9e1bb773..7dd5e4c18a66 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -168,6 +168,14 @@ struct gfs2_rindex { __u8 ri_reserved[64]; }; +struct gfs2_rindex_host { + __u64 ri_addr; /* grp block disk address */ + __u64 ri_data0; /* first data location */ + __u32 ri_length; /* length of rgrp header in fs blocks */ + __u32 ri_data; /* num of data blocks in rgrp */ + __u32 ri_bitbytes; /* number of bytes in data bitmaps */ +}; + /* * resource group header structure */ @@ -498,8 +506,8 @@ struct gfs2_quota_change { extern void gfs2_inum_in(struct gfs2_inum *no, const void *buf); extern void gfs2_inum_out(const struct gfs2_inum *no, void *buf); extern void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf); -extern void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf); -extern void gfs2_rindex_out(const struct gfs2_rindex *ri, void *buf); +extern void gfs2_rindex_in(struct gfs2_rindex_host *ri, const void *buf); +extern void gfs2_rindex_out(const struct gfs2_rindex_host *ri, void *buf); extern void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf); extern void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf); extern void gfs2_quota_in(struct gfs2_quota *qu, const void *buf); @@ -517,7 +525,7 @@ extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf); /* Printing functions */ -extern void gfs2_rindex_print(const struct gfs2_rindex *ri); +extern void gfs2_rindex_print(const struct gfs2_rindex_host *ri); extern void gfs2_dinode_print(const struct gfs2_dinode_host *di); #endif /* __KERNEL__ */ -- cgit v1.2.3 From 629a21e7ecedf779c68dcaa9a186069f57a7c652 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 22:51:24 -0400 Subject: [GFS2] split and annotate gfs2_inum Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 8 ++++---- fs/gfs2/dir.h | 8 ++++---- fs/gfs2/incore.h | 2 +- fs/gfs2/inode.c | 22 +++++++++++----------- fs/gfs2/inode.h | 4 ++-- fs/gfs2/ondisk.c | 6 +++--- fs/gfs2/ops_dentry.c | 2 +- fs/gfs2/ops_export.c | 8 ++++---- fs/gfs2/ops_export.h | 2 +- fs/gfs2/ops_file.c | 2 +- fs/gfs2/ops_fstype.c | 4 ++-- include/linux/gfs2_ondisk.h | 19 ++++++++++++------- 12 files changed, 46 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index e24af28b1a12..d67a3760ca30 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1194,7 +1194,7 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, int *copied) { const struct gfs2_dirent *dent, *dent_next; - struct gfs2_inum inum; + struct gfs2_inum_host inum; u64 off, off_next; unsigned int x, y; int run = 0; @@ -1456,7 +1456,7 @@ out: */ int gfs2_dir_search(struct inode *dir, const struct qstr *name, - struct gfs2_inum *inum, unsigned int *type) + struct gfs2_inum_host *inum, unsigned int *type) { struct buffer_head *bh; struct gfs2_dirent *dent; @@ -1531,7 +1531,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) */ int gfs2_dir_add(struct inode *inode, const struct qstr *name, - const struct gfs2_inum *inum, unsigned type) + const struct gfs2_inum_host *inum, unsigned type) { struct gfs2_inode *ip = GFS2_I(inode); struct buffer_head *bh; @@ -1666,7 +1666,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) */ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, - struct gfs2_inum *inum, unsigned int new_type) + struct gfs2_inum_host *inum, unsigned int new_type) { struct buffer_head *bh; struct gfs2_dirent *dent; diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index 371233419b07..b21b33668a5b 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -31,17 +31,17 @@ struct gfs2_inum; typedef int (*gfs2_filldir_t) (void *opaque, const char *name, unsigned int length, u64 offset, - struct gfs2_inum *inum, unsigned int type); + struct gfs2_inum_host *inum, unsigned int type); int gfs2_dir_search(struct inode *dir, const struct qstr *filename, - struct gfs2_inum *inum, unsigned int *type); + struct gfs2_inum_host *inum, unsigned int *type); int gfs2_dir_add(struct inode *inode, const struct qstr *filename, - const struct gfs2_inum *inum, unsigned int type); + const struct gfs2_inum_host *inum, unsigned int type); int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename); int gfs2_dir_read(struct inode *inode, u64 * offset, void *opaque, gfs2_filldir_t filldir); int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, - struct gfs2_inum *new_inum, unsigned int new_type); + struct gfs2_inum_host *new_inum, unsigned int new_type); int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index e4afc2c4d609..20c9b4f0e52f 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -224,7 +224,7 @@ enum { struct gfs2_inode { struct inode i_inode; - struct gfs2_inum i_num; + struct gfs2_inum_host i_num; unsigned long i_flags; /* GIF_... */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 7eb6b440da6d..dadd1f35c864 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -112,7 +112,7 @@ void gfs2_inode_attr_out(struct gfs2_inode *ip) static int iget_test(struct inode *inode, void *opaque) { struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_inum *inum = opaque; + struct gfs2_inum_host *inum = opaque; if (ip && ip->i_num.no_addr == inum->no_addr) return 1; @@ -123,19 +123,19 @@ static int iget_test(struct inode *inode, void *opaque) static int iget_set(struct inode *inode, void *opaque) { struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_inum *inum = opaque; + struct gfs2_inum_host *inum = opaque; ip->i_num = *inum; return 0; } -struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum *inum) +struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum_host *inum) { return ilookup5(sb, (unsigned long)inum->no_formal_ino, iget_test, inum); } -static struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum) +static struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum_host *inum) { return iget5_locked(sb, (unsigned long)inum->no_formal_ino, iget_test, iget_set, inum); @@ -150,7 +150,7 @@ static struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum) * Returns: A VFS inode, or an error */ -struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, unsigned int type) +struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum_host *inum, unsigned int type) { struct inode *inode = gfs2_iget(sb, inum); struct gfs2_inode *ip = GFS2_I(inode); @@ -394,7 +394,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, struct super_block *sb = dir->i_sb; struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_holder d_gh; - struct gfs2_inum inum; + struct gfs2_inum_host inum; unsigned int type; int error = 0; struct inode *inode = NULL; @@ -610,7 +610,7 @@ static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, *gid = current->fsgid; } -static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum, +static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum_host *inum, u64 *generation) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); @@ -650,7 +650,7 @@ out: */ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - const struct gfs2_inum *inum, unsigned int mode, + const struct gfs2_inum_host *inum, unsigned int mode, unsigned int uid, unsigned int gid, const u64 *generation) { @@ -707,7 +707,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, } static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - unsigned int mode, const struct gfs2_inum *inum, + unsigned int mode, const struct gfs2_inum_host *inum, const u64 *generation) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); @@ -866,7 +866,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, struct gfs2_inode *dip = ghs->gh_gl->gl_object; struct inode *dir = &dip->i_inode; struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct gfs2_inum inum; + struct gfs2_inum_host inum; int error; u64 generation; @@ -1018,7 +1018,7 @@ int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, struct gfs2_inode *ip) { - struct gfs2_inum inum; + struct gfs2_inum_host inum; unsigned int type; int error; diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index f5d861760579..d699b9209750 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -27,8 +27,8 @@ static inline int gfs2_is_dir(struct gfs2_inode *ip) void gfs2_inode_attr_in(struct gfs2_inode *ip); void gfs2_inode_attr_out(struct gfs2_inode *ip); -struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, unsigned type); -struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum *inum); +struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum_host *inum, unsigned type); +struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum_host *inum); int gfs2_inode_refresh(struct gfs2_inode *ip); diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index c4e099d582f7..32f592f4a3c0 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -32,7 +32,7 @@ * first arg: the cpu-order structure */ -void gfs2_inum_in(struct gfs2_inum *no, const void *buf) +void gfs2_inum_in(struct gfs2_inum_host *no, const void *buf) { const struct gfs2_inum *str = buf; @@ -40,7 +40,7 @@ void gfs2_inum_in(struct gfs2_inum *no, const void *buf) no->no_addr = be64_to_cpu(str->no_addr); } -void gfs2_inum_out(const struct gfs2_inum *no, void *buf) +void gfs2_inum_out(const struct gfs2_inum_host *no, void *buf) { struct gfs2_inum *str = buf; @@ -48,7 +48,7 @@ void gfs2_inum_out(const struct gfs2_inum *no, void *buf) str->no_addr = cpu_to_be64(no->no_addr); } -static void gfs2_inum_print(const struct gfs2_inum *no) +static void gfs2_inum_print(const struct gfs2_inum_host *no) { printk(KERN_INFO " no_formal_ino = %llu\n", (unsigned long long)no->no_formal_ino); printk(KERN_INFO " no_addr = %llu\n", (unsigned long long)no->no_addr); diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index 00041b1b8025..c36f9e342e66 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -43,7 +43,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) struct inode *inode = dentry->d_inode; struct gfs2_holder d_gh; struct gfs2_inode *ip; - struct gfs2_inum inum; + struct gfs2_inum_host inum; unsigned int type; int error; diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 86127d93bd35..33423a5c329b 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -35,7 +35,7 @@ static struct dentry *gfs2_decode_fh(struct super_block *sb, void *context) { struct gfs2_fh_obj fh_obj; - struct gfs2_inum *this, parent; + struct gfs2_inum_host *this, parent; if (fh_type != fh_len) return NULL; @@ -114,12 +114,12 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len, } struct get_name_filldir { - struct gfs2_inum inum; + struct gfs2_inum_host inum; char *name; }; static int get_name_filldir(void *opaque, const char *name, unsigned int length, - u64 offset, struct gfs2_inum *inum, + u64 offset, struct gfs2_inum_host *inum, unsigned int type) { struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque; @@ -202,7 +202,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj) { struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_fh_obj *fh_obj = (struct gfs2_fh_obj *)inum_obj; - struct gfs2_inum *inum = &fh_obj->this; + struct gfs2_inum_host *inum = &fh_obj->this; struct gfs2_holder i_gh, ri_gh, rgd_gh; struct gfs2_rgrpd *rgd; struct inode *inode; diff --git a/fs/gfs2/ops_export.h b/fs/gfs2/ops_export.h index 09aca5046fb1..f925a955b3b8 100644 --- a/fs/gfs2/ops_export.h +++ b/fs/gfs2/ops_export.h @@ -15,7 +15,7 @@ extern struct export_operations gfs2_export_ops; struct gfs2_fh_obj { - struct gfs2_inum this; + struct gfs2_inum_host this; __u32 imode; }; diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 3064f133bf3c..359965c368bf 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -139,7 +139,7 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) */ static int filldir_func(void *opaque, const char *name, unsigned int length, - u64 offset, struct gfs2_inum *inum, + u64 offset, struct gfs2_inum_host *inum, unsigned int type) { struct filldir_reg *fdr = (struct filldir_reg *)opaque; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 882873a6bd69..d14e139d2674 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -237,7 +237,7 @@ fail: } static struct inode *gfs2_lookup_root(struct super_block *sb, - struct gfs2_inum *inum) + struct gfs2_inum_host *inum) { return gfs2_inode_lookup(sb, inum, DT_DIR); } @@ -246,7 +246,7 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) { struct super_block *sb = sdp->sd_vfs; struct gfs2_holder sb_gh; - struct gfs2_inum *inum; + struct gfs2_inum_host *inum; struct inode *inode; int error = 0; diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 7dd5e4c18a66..b16df6e8f55c 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -54,8 +54,13 @@ struct gfs2_inum { __be64 no_addr; }; -static inline int gfs2_inum_equal(const struct gfs2_inum *ino1, - const struct gfs2_inum *ino2) +struct gfs2_inum_host { + __u64 no_formal_ino; + __u64 no_addr; +}; + +static inline int gfs2_inum_equal(const struct gfs2_inum_host *ino1, + const struct gfs2_inum_host *ino2) { return ino1->no_formal_ino == ino2->no_formal_ino && ino1->no_addr == ino2->no_addr; @@ -143,8 +148,8 @@ struct gfs2_sb_host { __u32 sb_bsize; __u32 sb_bsize_shift; - struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ - struct gfs2_inum sb_root_dir; + struct gfs2_inum_host sb_master_dir; /* Was jindex dinode in gfs1 */ + struct gfs2_inum_host sb_root_dir; char sb_lockproto[GFS2_LOCKNAME_LEN]; char sb_locktable[GFS2_LOCKNAME_LEN]; @@ -313,7 +318,7 @@ struct gfs2_dinode { struct gfs2_dinode_host { struct gfs2_meta_header_host di_header; - struct gfs2_inum di_num; + struct gfs2_inum_host di_num; __u32 di_mode; /* mode of file */ __u32 di_uid; /* owner's user id */ @@ -503,8 +508,8 @@ struct gfs2_quota_change { #ifdef __KERNEL__ /* Translation functions */ -extern void gfs2_inum_in(struct gfs2_inum *no, const void *buf); -extern void gfs2_inum_out(const struct gfs2_inum *no, void *buf); +extern void gfs2_inum_in(struct gfs2_inum_host *no, const void *buf); +extern void gfs2_inum_out(const struct gfs2_inum_host *no, void *buf); extern void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf); extern void gfs2_rindex_in(struct gfs2_rindex_host *ri, const void *buf); extern void gfs2_rindex_out(const struct gfs2_rindex_host *ri, void *buf); -- cgit v1.2.3 From b5bc9e8b065dbcd4c675e8c158d6e524f221b8e1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 23:31:55 -0400 Subject: [GFS2] split and annotate gfs2_quota Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/ondisk.c | 2 +- fs/gfs2/quota.c | 2 +- include/linux/gfs2_ondisk.h | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 32f592f4a3c0..5db0737fcdb5 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -144,7 +144,7 @@ void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf) memset(&str->rg_reserved, 0, sizeof(str->rg_reserved)); } -void gfs2_quota_in(struct gfs2_quota *qu, const void *buf) +void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf) { const struct gfs2_quota *str = buf; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index a3deae7416c9..e3f5b8da484c 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -743,7 +743,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); struct gfs2_holder i_gh; - struct gfs2_quota q; + struct gfs2_quota_host q; char buf[sizeof(struct gfs2_quota)]; struct file_ra_state ra_state; int error; diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index b16df6e8f55c..431e03b85458 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -232,6 +232,12 @@ struct gfs2_quota { __u8 qu_reserved[64]; }; +struct gfs2_quota_host { + __u64 qu_limit; + __u64 qu_warn; + __u64 qu_value; +}; + /* * dinode structure */ @@ -515,8 +521,7 @@ extern void gfs2_rindex_in(struct gfs2_rindex_host *ri, const void *buf); extern void gfs2_rindex_out(const struct gfs2_rindex_host *ri, void *buf); extern void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf); extern void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf); -extern void gfs2_quota_in(struct gfs2_quota *qu, const void *buf); -extern void gfs2_quota_out(const struct gfs2_quota *qu, void *buf); +extern void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf); extern void gfs2_dinode_in(struct gfs2_dinode_host *di, const void *buf); extern void gfs2_dinode_out(const struct gfs2_dinode_host *di, void *buf); extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf); -- cgit v1.2.3 From bd209cc017f231e8536550bdab1bf5da93c32798 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 23:43:19 -0400 Subject: [GFS2] split and annotate gfs2_statfs_change Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 4 ++-- fs/gfs2/ondisk.c | 4 ++-- fs/gfs2/ops_super.c | 2 +- fs/gfs2/super.c | 22 +++++++++++----------- fs/gfs2/super.h | 4 ++-- include/linux/gfs2_ondisk.h | 10 ++++++++-- 6 files changed, 26 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 20c9b4f0e52f..c0a8c3b6a852 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -503,8 +503,8 @@ struct gfs2_sbd { spinlock_t sd_statfs_spin; struct mutex sd_statfs_mutex; - struct gfs2_statfs_change sd_statfs_master; - struct gfs2_statfs_change sd_statfs_local; + struct gfs2_statfs_change_host sd_statfs_master; + struct gfs2_statfs_change_host sd_statfs_local; unsigned long sd_statfs_sync_time; /* Resource group stuff */ diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 5db0737fcdb5..84c59b165b63 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -279,7 +279,7 @@ void gfs2_inum_range_out(const struct gfs2_inum_range_host *ir, void *buf) str->ir_length = cpu_to_be64(ir->ir_length); } -void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf) +void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf) { const struct gfs2_statfs_change *str = buf; @@ -288,7 +288,7 @@ void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf) sc->sc_dinodes = be64_to_cpu(str->sc_dinodes); } -void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf) +void gfs2_statfs_change_out(const struct gfs2_statfs_change_host *sc, void *buf) { struct gfs2_statfs_change *str = buf; diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index b47d9598c047..9c786d1e702d 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -215,7 +215,7 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_inode->i_sb; struct gfs2_sbd *sdp = sb->s_fs_info; - struct gfs2_statfs_change sc; + struct gfs2_statfs_change_host sc; int error; if (gfs2_tune_get(sdp, gt_statfs_slow)) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 0faf563c83a9..0ef831727086 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -587,9 +587,9 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp) int gfs2_statfs_init(struct gfs2_sbd *sdp) { struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); - struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; + struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); - struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; + struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; struct buffer_head *m_bh, *l_bh; struct gfs2_holder gh; int error; @@ -634,7 +634,7 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, s64 dinodes) { struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); - struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; + struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; struct buffer_head *l_bh; int error; @@ -660,8 +660,8 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp) { struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); - struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; - struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; + struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; + struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; struct gfs2_holder gh; struct buffer_head *m_bh, *l_bh; int error; @@ -727,10 +727,10 @@ out: * Returns: errno */ -int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc) +int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc) { - struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master; - struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local; + struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; + struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; spin_lock(&sdp->sd_statfs_spin); @@ -760,7 +760,7 @@ int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc) */ static int statfs_slow_fill(struct gfs2_rgrpd *rgd, - struct gfs2_statfs_change *sc) + struct gfs2_statfs_change_host *sc) { gfs2_rgrp_verify(rgd); sc->sc_total += rgd->rd_ri.ri_data; @@ -782,7 +782,7 @@ static int statfs_slow_fill(struct gfs2_rgrpd *rgd, * Returns: errno */ -int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc) +int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc) { struct gfs2_holder ri_gh; struct gfs2_rgrpd *rgd_next; @@ -792,7 +792,7 @@ int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc) int done; int error = 0, err; - memset(sc, 0, sizeof(struct gfs2_statfs_change)); + memset(sc, 0, sizeof(struct gfs2_statfs_change_host)); gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL); if (!gha) return -ENOMEM; diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index ac95064c1e5a..e590b2df11dc 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -45,8 +45,8 @@ int gfs2_statfs_init(struct gfs2_sbd *sdp); void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, s64 dinodes); int gfs2_statfs_sync(struct gfs2_sbd *sdp); -int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc); -int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc); +int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc); +int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc); int gfs2_freeze_fs(struct gfs2_sbd *sdp); void gfs2_unfreeze_fs(struct gfs2_sbd *sdp); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 431e03b85458..3ce3a47b720a 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -497,6 +497,12 @@ struct gfs2_statfs_change { __be64 sc_dinodes; }; +struct gfs2_statfs_change_host { + __u64 sc_total; + __u64 sc_free; + __u64 sc_dinodes; +}; + /* * Quota change * Describes an allocation change for a particular @@ -529,8 +535,8 @@ extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf); extern void gfs2_log_header_in(struct gfs2_log_header_host *lh, const void *buf); extern void gfs2_inum_range_in(struct gfs2_inum_range_host *ir, const void *buf); extern void gfs2_inum_range_out(const struct gfs2_inum_range_host *ir, void *buf); -extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf); -extern void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf); +extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf); +extern void gfs2_statfs_change_out(const struct gfs2_statfs_change_host *sc, void *buf); extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf); /* Printing functions */ -- cgit v1.2.3 From b62f963e1fdf838fed91faec21228d421a834f2d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 13 Oct 2006 23:46:46 -0400 Subject: [GFS2] split and annotate gfs2_quota_change Signed-off-by: Al Viro Signed-off-by: Steven Whitehouse --- fs/gfs2/ondisk.c | 2 +- fs/gfs2/quota.c | 2 +- include/linux/gfs2_ondisk.h | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 84c59b165b63..2d1682ded4b7 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -297,7 +297,7 @@ void gfs2_statfs_change_out(const struct gfs2_statfs_change_host *sc, void *buf) str->sc_dinodes = cpu_to_be64(sc->sc_dinodes); } -void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf) +void gfs2_quota_change_in(struct gfs2_quota_change_host *qc, const void *buf) { const struct gfs2_quota_change *str = buf; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index e3f5b8da484c..009d86c0008f 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1103,7 +1103,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) for (y = 0; y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots; y++, slot++) { - struct gfs2_quota_change qc; + struct gfs2_quota_change_host qc; struct gfs2_quota_data *qd; gfs2_quota_change_in(&qc, bh->b_data + diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 3ce3a47b720a..10a507dfd834 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -517,6 +517,12 @@ struct gfs2_quota_change { __be32 qc_id; }; +struct gfs2_quota_change_host { + __u64 qc_change; + __u32 qc_flags; /* GFS2_QCF_... */ + __u32 qc_id; +}; + #ifdef __KERNEL__ /* Translation functions */ @@ -537,7 +543,7 @@ extern void gfs2_inum_range_in(struct gfs2_inum_range_host *ir, const void *buf) extern void gfs2_inum_range_out(const struct gfs2_inum_range_host *ir, void *buf); extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf); extern void gfs2_statfs_change_out(const struct gfs2_statfs_change_host *sc, void *buf); -extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf); +extern void gfs2_quota_change_in(struct gfs2_quota_change_host *qc, const void *buf); /* Printing functions */ -- cgit v1.2.3 From 539e5d6b7ae8612c0393fe940d2da5b591318d3d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 31 Oct 2006 15:07:05 -0500 Subject: [GFS2] Change argument of gfs2_dinode_out Everywhere this was called, a struct gfs2_inode was available, but despite that, it was always called with a struct gfs2_dinode as an argument. By making this change it paves the way to start eliminating fields duplicated between the kernel's struct inode and the struct gfs2_dinode. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 2 +- fs/gfs2/bmap.c | 12 ++++++------ fs/gfs2/dir.c | 20 ++++++++++---------- fs/gfs2/eattr.c | 14 +++++++------- fs/gfs2/inode.c | 6 +++--- fs/gfs2/ondisk.c | 5 ++++- fs/gfs2/ops_file.c | 2 +- fs/gfs2/ops_inode.c | 10 +++++----- include/linux/gfs2_ondisk.h | 3 ++- 9 files changed, 39 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 5f959b8ce406..906e403b054f 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -201,7 +201,7 @@ static int munge_mode(struct gfs2_inode *ip, mode_t mode) (ip->i_di.di_mode & S_IFMT) == (mode & S_IFMT)); ip->i_di.di_mode = mode; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 51f6356bdcb5..8c092ab2b4ba 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -498,7 +498,7 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } set_buffer_new(bh_map); @@ -780,7 +780,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); up_write(&ip->i_rw_mutex); @@ -860,7 +860,7 @@ static int do_grow(struct gfs2_inode *ip, u64 size) goto out_end_trans; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); out_end_trans: @@ -970,7 +970,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size) ip->i_di.di_size = size; ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size); error = 1; @@ -983,7 +983,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size) ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); } } @@ -1057,7 +1057,7 @@ static int trunc_end(struct gfs2_inode *ip) ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); out: diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 59dc823c2833..0742761e1e02 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -132,7 +132,7 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, if (ip->i_di.di_size < offset + size) ip->i_di.di_size = offset + size; ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -232,7 +232,7 @@ out: ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); return copied; @@ -907,7 +907,7 @@ static int dir_make_exhash(struct inode *inode) for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; dip->i_di.di_depth = y; - gfs2_dinode_out(&dip->i_di, dibh->b_data); + gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); @@ -1039,7 +1039,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) error = gfs2_meta_inode_buffer(dip, &dibh); if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) { dip->i_di.di_blocks++; - gfs2_dinode_out(&dip->i_di, dibh->b_data); + gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); } @@ -1119,7 +1119,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) error = gfs2_meta_inode_buffer(dip, &dibh); if (!gfs2_assert_withdraw(sdp, !error)) { dip->i_di.di_depth++; - gfs2_dinode_out(&dip->i_di, dibh->b_data); + gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); } @@ -1517,7 +1517,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) return error; gfs2_trans_add_bh(ip->i_gl, bh, 1); ip->i_di.di_blocks++; - gfs2_dinode_out(&ip->i_di, bh->b_data); + gfs2_dinode_out(ip, bh->b_data); brelse(bh); return 0; } @@ -1561,7 +1561,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, gfs2_trans_add_bh(ip->i_gl, bh, 1); ip->i_di.di_entries++; ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); - gfs2_dinode_out(&ip->i_di, bh->b_data); + gfs2_dinode_out(ip, bh->b_data); brelse(bh); error = 0; break; @@ -1647,7 +1647,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) gfs2_trans_add_bh(dip->i_gl, bh, 1); dip->i_di.di_entries--; dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - gfs2_dinode_out(&dip->i_di, bh->b_data); + gfs2_dinode_out(dip, bh->b_data); brelse(bh); mark_inode_dirty(&dip->i_inode); @@ -1695,7 +1695,7 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, } dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - gfs2_dinode_out(&dip->i_di, bh->b_data); + gfs2_dinode_out(dip, bh->b_data); brelse(bh); return 0; } @@ -1875,7 +1875,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, goto out_end_trans; gfs2_trans_add_bh(dip->i_gl, dibh, 1); - gfs2_dinode_out(&dip->i_di, dibh->b_data); + gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); out_end_trans: diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 518f0c0786c8..9b7bb565b59d 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -302,7 +302,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, if (!error) { ip->i_di.di_ctime = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } @@ -717,7 +717,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, } ip->i_di.di_ctime = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } @@ -852,7 +852,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, } ip->i_di.di_ctime = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); out: gfs2_trans_end(GFS2_SB(&ip->i_inode)); @@ -1132,7 +1132,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) if (!error) { ip->i_di.di_ctime = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } @@ -1287,7 +1287,7 @@ int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); gfs2_inode_attr_out(ip); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } @@ -1397,7 +1397,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } @@ -1446,7 +1446,7 @@ static int ea_dealloc_block(struct gfs2_inode *ip) error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index fb969302f181..b861ddba8688 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -338,7 +338,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) ip->i_inode.i_nlink = nlink; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); mark_inode_dirty(&ip->i_inode); @@ -792,7 +792,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, goto fail_end_trans; ip->i_di.di_nlink = 1; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); return 0; @@ -1349,7 +1349,7 @@ __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) gfs2_inode_attr_out(ip); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } return error; diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 2d1682ded4b7..2c50fa0261f5 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -15,6 +15,8 @@ #include "gfs2.h" #include +#include +#include "incore.h" #define pv(struct, member, fmt) printk(KERN_INFO " "#member" = "fmt"\n", \ struct->member); @@ -187,8 +189,9 @@ void gfs2_dinode_in(struct gfs2_dinode_host *di, const void *buf) } -void gfs2_dinode_out(const struct gfs2_dinode_host *di, void *buf) +void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) { + const struct gfs2_dinode_host *di = &ip->i_di; struct gfs2_dinode *str = buf; gfs2_meta_header_out(&di->di_header, buf); diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 2fc8868e065c..7ea417573903 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -336,7 +336,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) goto out_trans_end; gfs2_trans_add_bh(ip->i_gl, bh, 1); ip->i_di.di_flags = new_flags; - gfs2_dinode_out(&ip->i_di, bh->b_data); + gfs2_dinode_out(ip, bh->b_data); brelse(bh); out_trans_end: gfs2_trans_end(sdp); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index ef6e5ed70e94..bd268852c674 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -339,7 +339,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, error = gfs2_meta_inode_buffer(ip, &dibh); if (!gfs2_assert_withdraw(sdp, !error)) { - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, size); brelse(dibh); @@ -414,7 +414,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) gfs2_inum_out(&dip->i_num, &dent->de_inum); dent->de_type = cpu_to_be16(DT_DIR); - gfs2_dinode_out(&ip->i_di, di); + gfs2_dinode_out(ip, di); brelse(dibh); } @@ -541,7 +541,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, error = gfs2_meta_inode_buffer(ip, &dibh); if (!gfs2_assert_withdraw(sdp, !error)) { - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } @@ -762,7 +762,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, goto out_end_trans; ip->i_di.di_ctime = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } @@ -949,7 +949,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) gfs2_inode_attr_out(ip); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 10a507dfd834..550effaf0c2b 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -535,7 +535,8 @@ extern void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf); extern void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf); extern void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf); extern void gfs2_dinode_in(struct gfs2_dinode_host *di, const void *buf); -extern void gfs2_dinode_out(const struct gfs2_dinode_host *di, void *buf); +struct gfs2_inode; +extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf); extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf); extern void gfs2_log_header_in(struct gfs2_log_header_host *lh, const void *buf); -- cgit v1.2.3 From 891ea14712da68e282de8583e5fa14f0d3f3731e Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 31 Oct 2006 15:22:10 -0500 Subject: [GFS2] Change argument to gfs2_dinode_in This is a preliminary patch to enable the removal of fields in gfs2_dinode_host which are duplicated in struct inode. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 2 +- fs/gfs2/ondisk.c | 4 ++-- include/linux/gfs2_ondisk.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index b861ddba8688..9875e9356cd3 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -229,7 +229,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) return -EIO; } - gfs2_dinode_in(&ip->i_di, dibh->b_data); + gfs2_dinode_in(ip, dibh->b_data); brelse(dibh); diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 2c50fa0261f5..edf87567bb2b 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -155,8 +155,9 @@ void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf) qu->qu_value = be64_to_cpu(str->qu_value); } -void gfs2_dinode_in(struct gfs2_dinode_host *di, const void *buf) +void gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) { + struct gfs2_dinode_host *di = &ip->i_di; const struct gfs2_dinode *str = buf; gfs2_meta_header_in(&di->di_header, buf); @@ -186,7 +187,6 @@ void gfs2_dinode_in(struct gfs2_dinode_host *di, const void *buf) di->di_entries = be32_to_cpu(str->di_entries); di->di_eattr = be64_to_cpu(str->di_eattr); - } void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 550effaf0c2b..08d8240ba533 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -534,8 +534,8 @@ extern void gfs2_rindex_out(const struct gfs2_rindex_host *ri, void *buf); extern void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf); extern void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf); extern void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf); -extern void gfs2_dinode_in(struct gfs2_dinode_host *di, const void *buf); struct gfs2_inode; +extern void gfs2_dinode_in(struct gfs2_inode *ip, const void *buf); extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf); extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf); -- cgit v1.2.3 From ea744d01c6a5acf1f6171b4c6e1658a742063613 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 31 Oct 2006 15:28:00 -0500 Subject: [GFS2] Move gfs2_dinode_in to inode.c gfs2_dinode_in() is only ever called from one place, so move it to that place (in inode.c) and make it static. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 34 ++++++++++++++++++++++++++++++++++ fs/gfs2/ondisk.c | 36 +----------------------------------- include/linux/gfs2_ondisk.h | 2 +- 3 files changed, 36 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 9875e9356cd3..b39cfcfe9276 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -208,6 +208,40 @@ fail: return ERR_PTR(error); } +static void gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) +{ + struct gfs2_dinode_host *di = &ip->i_di; + const struct gfs2_dinode *str = buf; + + gfs2_meta_header_in(&di->di_header, buf); + gfs2_inum_in(&di->di_num, &str->di_num); + + di->di_mode = be32_to_cpu(str->di_mode); + di->di_uid = be32_to_cpu(str->di_uid); + di->di_gid = be32_to_cpu(str->di_gid); + di->di_nlink = be32_to_cpu(str->di_nlink); + di->di_size = be64_to_cpu(str->di_size); + di->di_blocks = be64_to_cpu(str->di_blocks); + di->di_atime = be64_to_cpu(str->di_atime); + di->di_mtime = be64_to_cpu(str->di_mtime); + di->di_ctime = be64_to_cpu(str->di_ctime); + di->di_major = be32_to_cpu(str->di_major); + di->di_minor = be32_to_cpu(str->di_minor); + + di->di_goal_meta = be64_to_cpu(str->di_goal_meta); + di->di_goal_data = be64_to_cpu(str->di_goal_data); + di->di_generation = be64_to_cpu(str->di_generation); + + di->di_flags = be32_to_cpu(str->di_flags); + di->di_payload_format = be32_to_cpu(str->di_payload_format); + di->di_height = be16_to_cpu(str->di_height); + + di->di_depth = be16_to_cpu(str->di_depth); + di->di_entries = be32_to_cpu(str->di_entries); + + di->di_eattr = be64_to_cpu(str->di_eattr); +} + /** * gfs2_inode_refresh - Refresh the incore copy of the dinode * @ip: The GFS2 inode diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index edf87567bb2b..062a44f87fec 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -56,7 +56,7 @@ static void gfs2_inum_print(const struct gfs2_inum_host *no) printk(KERN_INFO " no_addr = %llu\n", (unsigned long long)no->no_addr); } -static void gfs2_meta_header_in(struct gfs2_meta_header_host *mh, const void *buf) +void gfs2_meta_header_in(struct gfs2_meta_header_host *mh, const void *buf) { const struct gfs2_meta_header *str = buf; @@ -155,40 +155,6 @@ void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf) qu->qu_value = be64_to_cpu(str->qu_value); } -void gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) -{ - struct gfs2_dinode_host *di = &ip->i_di; - const struct gfs2_dinode *str = buf; - - gfs2_meta_header_in(&di->di_header, buf); - gfs2_inum_in(&di->di_num, &str->di_num); - - di->di_mode = be32_to_cpu(str->di_mode); - di->di_uid = be32_to_cpu(str->di_uid); - di->di_gid = be32_to_cpu(str->di_gid); - di->di_nlink = be32_to_cpu(str->di_nlink); - di->di_size = be64_to_cpu(str->di_size); - di->di_blocks = be64_to_cpu(str->di_blocks); - di->di_atime = be64_to_cpu(str->di_atime); - di->di_mtime = be64_to_cpu(str->di_mtime); - di->di_ctime = be64_to_cpu(str->di_ctime); - di->di_major = be32_to_cpu(str->di_major); - di->di_minor = be32_to_cpu(str->di_minor); - - di->di_goal_meta = be64_to_cpu(str->di_goal_meta); - di->di_goal_data = be64_to_cpu(str->di_goal_data); - di->di_generation = be64_to_cpu(str->di_generation); - - di->di_flags = be32_to_cpu(str->di_flags); - di->di_payload_format = be32_to_cpu(str->di_payload_format); - di->di_height = be16_to_cpu(str->di_height); - - di->di_depth = be16_to_cpu(str->di_depth); - di->di_entries = be32_to_cpu(str->di_entries); - - di->di_eattr = be64_to_cpu(str->di_eattr); -} - void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) { const struct gfs2_dinode_host *di = &ip->i_di; diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 08d8240ba533..4fc297a1ef95 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -528,6 +528,7 @@ struct gfs2_quota_change_host { extern void gfs2_inum_in(struct gfs2_inum_host *no, const void *buf); extern void gfs2_inum_out(const struct gfs2_inum_host *no, void *buf); +extern void gfs2_meta_header_in(struct gfs2_meta_header_host *mh, const void *buf); extern void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf); extern void gfs2_rindex_in(struct gfs2_rindex_host *ri, const void *buf); extern void gfs2_rindex_out(const struct gfs2_rindex_host *ri, void *buf); @@ -535,7 +536,6 @@ extern void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf); extern void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf); extern void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf); struct gfs2_inode; -extern void gfs2_dinode_in(struct gfs2_inode *ip, const void *buf); extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf); extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf); -- cgit v1.2.3 From 4cc14f0b88bf3e0b508143e091eb5a8dff3e3b9c Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 31 Oct 2006 19:00:24 -0500 Subject: [GFS2] Change argument to gfs2_dinode_print Change argument for gfs2_dinode_print in order to prepare for removal of duplicate fields between struct inode and struct gfs2_dinode_host. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 8 ++++---- fs/gfs2/ondisk.c | 4 +++- fs/gfs2/ops_inode.c | 4 ++-- include/linux/gfs2_ondisk.h | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index b39cfcfe9276..4c5d286fefdb 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -269,7 +269,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) if (ip->i_num.no_addr != ip->i_di.di_num.no_addr) { if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); + gfs2_dinode_print(ip); return -EIO; } if (ip->i_num.no_formal_ino != ip->i_di.di_num.no_formal_ino) @@ -289,7 +289,7 @@ int gfs2_dinode_dealloc(struct gfs2_inode *ip) if (ip->i_di.di_blocks != 1) { if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); + gfs2_dinode_print(ip); return -EIO; } @@ -359,7 +359,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) bigger than the old one, we must have underflowed. */ if (diff < 0 && nlink > ip->i_di.di_nlink) { if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); + gfs2_dinode_print(ip); return -EIO; } @@ -1010,7 +1010,7 @@ int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, if (ip->i_di.di_entries != 2) { if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); + gfs2_dinode_print(ip); return -EIO; } diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 062a44f87fec..77bed440833d 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -190,8 +190,10 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) } -void gfs2_dinode_print(const struct gfs2_dinode_host *di) +void gfs2_dinode_print(const struct gfs2_inode *ip) { + const struct gfs2_dinode_host *di = &ip->i_di; + gfs2_meta_header_print(&di->di_header); gfs2_inum_print(&di->di_num); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index bd268852c674..b2c2fe613d70 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -467,7 +467,7 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) if (ip->i_di.di_entries < 2) { if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); + gfs2_dinode_print(ip); error = -EIO; goto out_gunlock; } @@ -640,7 +640,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (S_ISDIR(nip->i_di.di_mode)) { if (nip->i_di.di_entries < 2) { if (gfs2_consist_inode(nip)) - gfs2_dinode_print(&nip->i_di); + gfs2_dinode_print(nip); error = -EIO; goto out_gunlock; } diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 4fc297a1ef95..cf4c655d0d5f 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -549,7 +549,7 @@ extern void gfs2_quota_change_in(struct gfs2_quota_change_host *qc, const void * /* Printing functions */ extern void gfs2_rindex_print(const struct gfs2_rindex_host *ri); -extern void gfs2_dinode_print(const struct gfs2_dinode_host *di); +extern void gfs2_dinode_print(const struct gfs2_inode *ip); #endif /* __KERNEL__ */ -- cgit v1.2.3 From af339c0241d0dd3b35f9097b4f4999bb22ffe502 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 1 Nov 2006 10:34:15 -0500 Subject: [GFS2] Shrink gfs2_inode (1) - di_header/di_num The metadata header doesn't need to be stored in the incore struct gfs2_inode since its constant, and this patch removes it. Also, there is already a field for the inode's number in the struct gfs2_inode, so we don't need one in struct gfs2_dinode_host as well. This saves 28 bytes of space in the struct gfs2_inode. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 25 +++++++++++-------------- fs/gfs2/ondisk.c | 22 +++++++++------------- include/linux/gfs2_ondisk.h | 5 ----- 3 files changed, 20 insertions(+), 32 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 4c5d286fefdb..7ba05fc553aa 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -208,13 +208,18 @@ fail: return ERR_PTR(error); } -static void gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) +static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) { struct gfs2_dinode_host *di = &ip->i_di; const struct gfs2_dinode *str = buf; - gfs2_meta_header_in(&di->di_header, buf); - gfs2_inum_in(&di->di_num, &str->di_num); + if (ip->i_num.no_addr != be64_to_cpu(str->di_num.no_addr)) { + if (gfs2_consist_inode(ip)) + gfs2_dinode_print(ip); + return -EIO; + } + if (ip->i_num.no_formal_ino != be64_to_cpu(str->di_num.no_formal_ino)) + return -ESTALE; di->di_mode = be32_to_cpu(str->di_mode); di->di_uid = be32_to_cpu(str->di_uid); @@ -240,6 +245,7 @@ static void gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) di->di_entries = be32_to_cpu(str->di_entries); di->di_eattr = be64_to_cpu(str->di_eattr); + return 0; } /** @@ -263,21 +269,12 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) return -EIO; } - gfs2_dinode_in(ip, dibh->b_data); + error = gfs2_dinode_in(ip, dibh->b_data); brelse(dibh); - - if (ip->i_num.no_addr != ip->i_di.di_num.no_addr) { - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(ip); - return -EIO; - } - if (ip->i_num.no_formal_ino != ip->i_di.di_num.no_formal_ino) - return -ESTALE; - ip->i_vn = ip->i_gl->gl_vn; - return 0; + return error; } int gfs2_dinode_dealloc(struct gfs2_inode *ip) diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 77bed440833d..4bc590edb60e 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -56,7 +56,7 @@ static void gfs2_inum_print(const struct gfs2_inum_host *no) printk(KERN_INFO " no_addr = %llu\n", (unsigned long long)no->no_addr); } -void gfs2_meta_header_in(struct gfs2_meta_header_host *mh, const void *buf) +static void gfs2_meta_header_in(struct gfs2_meta_header_host *mh, const void *buf) { const struct gfs2_meta_header *str = buf; @@ -74,13 +74,6 @@ static void gfs2_meta_header_out(const struct gfs2_meta_header_host *mh, void *b str->mh_format = cpu_to_be32(mh->mh_format); } -static void gfs2_meta_header_print(const struct gfs2_meta_header_host *mh) -{ - pv(mh, mh_magic, "0x%.8X"); - pv(mh, mh_type, "%u"); - pv(mh, mh_format, "%u"); -} - void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf) { const struct gfs2_sb *str = buf; @@ -160,8 +153,13 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) const struct gfs2_dinode_host *di = &ip->i_di; struct gfs2_dinode *str = buf; - gfs2_meta_header_out(&di->di_header, buf); - gfs2_inum_out(&di->di_num, (char *)&str->di_num); + str->di_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + str->di_header.mh_type = cpu_to_be32(GFS2_METATYPE_DI); + str->di_header.__pad0 = 0; + str->di_header.mh_format = cpu_to_be32(GFS2_FORMAT_DI); + str->di_header.__pad1 = 0; + + gfs2_inum_out(&ip->i_num, &str->di_num); str->di_mode = cpu_to_be32(di->di_mode); str->di_uid = cpu_to_be32(di->di_uid); @@ -187,15 +185,13 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_entries = cpu_to_be32(di->di_entries); str->di_eattr = cpu_to_be64(di->di_eattr); - } void gfs2_dinode_print(const struct gfs2_inode *ip) { const struct gfs2_dinode_host *di = &ip->i_di; - gfs2_meta_header_print(&di->di_header); - gfs2_inum_print(&di->di_num); + gfs2_inum_print(&ip->i_num); pv(di, di_mode, "0%o"); pv(di, di_uid, "%u"); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index cf4c655d0d5f..c0e76fc718c7 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -322,10 +322,6 @@ struct gfs2_dinode { }; struct gfs2_dinode_host { - struct gfs2_meta_header_host di_header; - - struct gfs2_inum_host di_num; - __u32 di_mode; /* mode of file */ __u32 di_uid; /* owner's user id */ __u32 di_gid; /* owner's group id */ @@ -528,7 +524,6 @@ struct gfs2_quota_change_host { extern void gfs2_inum_in(struct gfs2_inum_host *no, const void *buf); extern void gfs2_inum_out(const struct gfs2_inum_host *no, void *buf); -extern void gfs2_meta_header_in(struct gfs2_meta_header_host *mh, const void *buf); extern void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf); extern void gfs2_rindex_in(struct gfs2_rindex_host *ri, const void *buf); extern void gfs2_rindex_out(const struct gfs2_rindex_host *ri, void *buf); -- cgit v1.2.3 From e7f14f4d094ea1a9ce1953375f5bc1500c760c79 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 31 Oct 2006 21:45:08 -0500 Subject: [GFS2] Shrink gfs2_inode (2) - di_major/di_minor This removes the device numbers from this structure by using inode->i_rdev instead. It also cleans up the code in gfs2_mknod. It results in shrinking the gfs2_inode by 8 bytes. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 36 ++++++++++++++++-------------------- fs/gfs2/inode.h | 2 +- fs/gfs2/ondisk.c | 4 ---- fs/gfs2/ops_inode.c | 38 +++++--------------------------------- include/linux/gfs2_ondisk.h | 2 -- 5 files changed, 22 insertions(+), 60 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 7ba05fc553aa..a99591956544 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -51,17 +51,6 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) struct gfs2_dinode_host *di = &ip->i_di; inode->i_ino = ip->i_num.no_addr; - - switch (di->di_mode & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - inode->i_rdev = MKDEV(di->di_major, di->di_minor); - break; - default: - inode->i_rdev = 0; - break; - }; - inode->i_mode = di->di_mode; inode->i_nlink = di->di_nlink; inode->i_uid = di->di_uid; @@ -222,6 +211,15 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) return -ESTALE; di->di_mode = be32_to_cpu(str->di_mode); + ip->i_inode.i_rdev = 0; + switch (di->di_mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major), + be32_to_cpu(str->di_minor)); + break; + }; + di->di_uid = be32_to_cpu(str->di_uid); di->di_gid = be32_to_cpu(str->di_gid); di->di_nlink = be32_to_cpu(str->di_nlink); @@ -230,8 +228,6 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) di->di_atime = be64_to_cpu(str->di_atime); di->di_mtime = be64_to_cpu(str->di_mtime); di->di_ctime = be64_to_cpu(str->di_ctime); - di->di_major = be32_to_cpu(str->di_major); - di->di_minor = be32_to_cpu(str->di_minor); di->di_goal_meta = be64_to_cpu(str->di_goal_meta); di->di_goal_data = be64_to_cpu(str->di_goal_data); @@ -270,7 +266,6 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) } error = gfs2_dinode_in(ip, dibh->b_data); - brelse(dibh); ip->i_vn = ip->i_gl->gl_vn; @@ -684,7 +679,7 @@ out: static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, const struct gfs2_inum_host *inum, unsigned int mode, unsigned int uid, unsigned int gid, - const u64 *generation) + const u64 *generation, dev_t dev) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_dinode *di; @@ -705,7 +700,8 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, di->di_size = cpu_to_be64(0); di->di_blocks = cpu_to_be64(1); di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds()); - di->di_major = di->di_minor = cpu_to_be32(0); + di->di_major = cpu_to_be32(MAJOR(dev)); + di->di_minor = cpu_to_be32(MINOR(dev)); di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); di->di_generation = cpu_to_be64(*generation); di->di_flags = cpu_to_be32(0); @@ -740,7 +736,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, unsigned int mode, const struct gfs2_inum_host *inum, - const u64 *generation) + const u64 *generation, dev_t dev) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); unsigned int uid, gid; @@ -761,7 +757,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, if (error) goto out_quota; - init_dinode(dip, gl, inum, mode, uid, gid, generation); + init_dinode(dip, gl, inum, mode, uid, gid, generation, dev); gfs2_quota_change(dip, +1, uid, gid); gfs2_trans_end(sdp); @@ -892,7 +888,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip) */ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, - unsigned int mode) + unsigned int mode, dev_t dev) { struct inode *inode; struct gfs2_inode *dip = ghs->gh_gl->gl_object; @@ -950,7 +946,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, goto fail_gunlock; } - error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation); + error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev); if (error) goto fail_gunlock2; diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index d699b9209750..33c9ea68f7e7 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -37,7 +37,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff); struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, int is_root, struct nameidata *nd); struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, - unsigned int mode); + unsigned int mode, dev_t dev); int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, struct gfs2_inode *ip); int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 4bc590edb60e..60dd943761ab 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -170,8 +170,6 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_atime = cpu_to_be64(di->di_atime); str->di_mtime = cpu_to_be64(di->di_mtime); str->di_ctime = cpu_to_be64(di->di_ctime); - str->di_major = cpu_to_be32(di->di_major); - str->di_minor = cpu_to_be32(di->di_minor); str->di_goal_meta = cpu_to_be64(di->di_goal_meta); str->di_goal_data = cpu_to_be64(di->di_goal_data); @@ -202,8 +200,6 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) printk(KERN_INFO " di_atime = %lld\n", (long long)di->di_atime); printk(KERN_INFO " di_mtime = %lld\n", (long long)di->di_mtime); printk(KERN_INFO " di_ctime = %lld\n", (long long)di->di_ctime); - pv(di, di_major, "%u"); - pv(di, di_minor, "%u"); printk(KERN_INFO " di_goal_meta = %llu\n", (unsigned long long)di->di_goal_meta); printk(KERN_INFO " di_goal_data = %llu\n", (unsigned long long)di->di_goal_data); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index b2c2fe613d70..c10b914bf8cc 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -59,7 +59,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, gfs2_holder_init(dip->i_gl, 0, 0, ghs); for (;;) { - inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode); + inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0); if (!IS_ERR(inode)) { gfs2_trans_end(sdp); if (dip->i_alloc.al_rgd) @@ -326,7 +326,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, gfs2_holder_init(dip->i_gl, 0, 0, ghs); - inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO); + inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO, 0); if (IS_ERR(inode)) { gfs2_holder_uninit(ghs); return PTR_ERR(inode); @@ -379,7 +379,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) gfs2_holder_init(dip->i_gl, 0, 0, ghs); - inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode); + inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode, 0); if (IS_ERR(inode)) { gfs2_holder_uninit(ghs); return PTR_ERR(inode); @@ -504,47 +504,19 @@ out: static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { - struct gfs2_inode *dip = GFS2_I(dir), *ip; + struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_holder ghs[2]; struct inode *inode; - struct buffer_head *dibh; - u32 major = 0, minor = 0; - int error; - - switch (mode & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - major = MAJOR(dev); - minor = MINOR(dev); - break; - case S_IFIFO: - case S_IFSOCK: - break; - default: - return -EOPNOTSUPP; - }; gfs2_holder_init(dip->i_gl, 0, 0, ghs); - inode = gfs2_createi(ghs, &dentry->d_name, mode); + inode = gfs2_createi(ghs, &dentry->d_name, mode, dev); if (IS_ERR(inode)) { gfs2_holder_uninit(ghs); return PTR_ERR(inode); } - ip = ghs[1].gh_gl->gl_object; - - ip->i_di.di_major = major; - ip->i_di.di_minor = minor; - - error = gfs2_meta_inode_buffer(ip, &dibh); - - if (!gfs2_assert_withdraw(sdp, !error)) { - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); - } - gfs2_trans_end(sdp); if (dip->i_alloc.al_rgd) gfs2_inplace_release(dip); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index c0e76fc718c7..5bcf895b2731 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -331,8 +331,6 @@ struct gfs2_dinode_host { __u64 di_atime; /* time last accessed */ __u64 di_mtime; /* time last modified */ __u64 di_ctime; /* time last changed */ - __u32 di_major; /* device major number */ - __u32 di_minor; /* device minor number */ /* This section varies from gfs1. Padding added to align with * remainder of dinode -- cgit v1.2.3 From b60623c238b6a819bd04090139704e2cb57a751f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 1 Nov 2006 12:22:46 -0500 Subject: [GFS2] Shrink gfs2_inode (3) - di_mode This removes the duplicate di_mode field in favour of using the inode->i_mode field. This saves 4 bytes. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 16 ++++++++-------- fs/gfs2/bmap.c | 2 +- fs/gfs2/eaops.c | 2 +- fs/gfs2/eattr.c | 8 ++++---- fs/gfs2/glock.c | 2 +- fs/gfs2/glops.c | 8 ++++---- fs/gfs2/inode.c | 18 +++++++----------- fs/gfs2/inode.h | 2 +- fs/gfs2/ondisk.c | 3 +-- fs/gfs2/ops_address.c | 1 - fs/gfs2/ops_dentry.c | 2 +- fs/gfs2/ops_file.c | 6 +++--- fs/gfs2/ops_inode.c | 17 ++++++++--------- fs/gfs2/ops_super.c | 2 +- include/linux/gfs2_ondisk.h | 1 - 15 files changed, 41 insertions(+), 49 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 906e403b054f..87f6304f2f54 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -76,9 +76,9 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) return -EOPNOTSUPP; if (current->fsuid != ip->i_di.di_uid && !capable(CAP_FOWNER)) return -EPERM; - if (S_ISLNK(ip->i_di.di_mode)) + if (S_ISLNK(ip->i_inode.i_mode)) return -EOPNOTSUPP; - if (!access && !S_ISDIR(ip->i_di.di_mode)) + if (!access && !S_ISDIR(ip->i_inode.i_mode)) return -EACCES; return 0; @@ -198,8 +198,8 @@ static int munge_mode(struct gfs2_inode *ip, mode_t mode) error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { gfs2_assert_withdraw(sdp, - (ip->i_di.di_mode & S_IFMT) == (mode & S_IFMT)); - ip->i_di.di_mode = mode; + (ip->i_inode.i_mode & S_IFMT) == (mode & S_IFMT)); + ip->i_inode.i_mode = mode; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -215,12 +215,12 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct posix_acl *acl = NULL, *clone; struct gfs2_ea_request er; - mode_t mode = ip->i_di.di_mode; + mode_t mode = ip->i_inode.i_mode; int error; if (!sdp->sd_args.ar_posix_acl) return 0; - if (S_ISLNK(ip->i_di.di_mode)) + if (S_ISLNK(ip->i_inode.i_mode)) return 0; memset(&er, 0, sizeof(struct gfs2_ea_request)); @@ -232,7 +232,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) return error; if (!acl) { mode &= ~current->fs->umask; - if (mode != ip->i_di.di_mode) + if (mode != ip->i_inode.i_mode) error = munge_mode(ip, mode); return error; } @@ -244,7 +244,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) posix_acl_release(acl); acl = clone; - if (S_ISDIR(ip->i_di.di_mode)) { + if (S_ISDIR(ip->i_inode.i_mode)) { er.er_name = GFS2_POSIX_ACL_DEFAULT; er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; error = gfs2_system_eaops.eo_set(ip, &er); diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 8c092ab2b4ba..481a06882544 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -1109,7 +1109,7 @@ int gfs2_truncatei(struct gfs2_inode *ip, u64 size) { int error; - if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_di.di_mode))) + if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_inode.i_mode))) return -EINVAL; if (size > ip->i_di.di_size) diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 92c54e9b0dc3..cd747c00f670 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -120,7 +120,7 @@ static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { if (!(er->er_flags & GFS2_ERF_MODE)) { - er->er_mode = ip->i_di.di_mode; + er->er_mode = ip->i_inode.i_mode; er->er_flags |= GFS2_ERF_MODE; } error = gfs2_acl_validate_set(ip, 1, er, diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 9b7bb565b59d..5208fa94aad2 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -711,9 +711,9 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, if (!error) { if (er->er_flags & GFS2_ERF_MODE) { gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), - (ip->i_di.di_mode & S_IFMT) == + (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT)); - ip->i_di.di_mode = er->er_mode; + ip->i_inode.i_mode = er->er_mode; } ip->i_di.di_ctime = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); @@ -847,8 +847,8 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, if (er->er_flags & GFS2_ERF_MODE) { gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), - (ip->i_di.di_mode & S_IFMT) == (er->er_mode & S_IFMT)); - ip->i_di.di_mode = er->er_mode; + (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT)); + ip->i_inode.i_mode = er->er_mode; } ip->i_di.di_ctime = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 78fe0fae23ff..44633c46717a 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -2078,7 +2078,7 @@ static int dump_inode(struct gfs2_inode *ip) printk(KERN_INFO " num = %llu %llu\n", (unsigned long long)ip->i_num.no_formal_ino, (unsigned long long)ip->i_num.no_addr); - printk(KERN_INFO " type = %u\n", IF2DT(ip->i_di.di_mode)); + printk(KERN_INFO " type = %u\n", IF2DT(ip->i_inode.i_mode)); printk(KERN_INFO " i_flags ="); for (x = 0; x < 32; x++) if (test_bit(x, &ip->i_flags)) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 5406b193227c..aad45b7a927d 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -92,7 +92,7 @@ static void gfs2_pte_inval(struct gfs2_glock *gl) ip = gl->gl_object; inode = &ip->i_inode; - if (!ip || !S_ISREG(ip->i_di.di_mode)) + if (!ip || !S_ISREG(inode->i_mode)) return; if (!test_bit(GIF_PAGED, &ip->i_flags)) @@ -119,7 +119,7 @@ static void gfs2_page_inval(struct gfs2_glock *gl) ip = gl->gl_object; inode = &ip->i_inode; - if (!ip || !S_ISREG(ip->i_di.di_mode)) + if (!ip || !S_ISREG(inode->i_mode)) return; truncate_inode_pages(inode->i_mapping, 0); @@ -142,7 +142,7 @@ static void gfs2_page_wait(struct gfs2_glock *gl) struct address_space *mapping = inode->i_mapping; int error; - if (!S_ISREG(ip->i_di.di_mode)) + if (!S_ISREG(inode->i_mode)) return; error = filemap_fdatawait(mapping); @@ -164,7 +164,7 @@ static void gfs2_page_writeback(struct gfs2_glock *gl) struct inode *inode = &ip->i_inode; struct address_space *mapping = inode->i_mapping; - if (!S_ISREG(ip->i_di.di_mode)) + if (!S_ISREG(inode->i_mode)) return; filemap_fdatawrite(mapping); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index a99591956544..de466043c91a 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -51,7 +51,6 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) struct gfs2_dinode_host *di = &ip->i_di; inode->i_ino = ip->i_num.no_addr; - inode->i_mode = di->di_mode; inode->i_nlink = di->di_nlink; inode->i_uid = di->di_uid; inode->i_gid = di->di_gid; @@ -88,9 +87,6 @@ void gfs2_inode_attr_out(struct gfs2_inode *ip) { struct inode *inode = &ip->i_inode; struct gfs2_dinode_host *di = &ip->i_di; - gfs2_assert_withdraw(GFS2_SB(inode), - (di->di_mode & S_IFMT) == (inode->i_mode & S_IFMT)); - di->di_mode = inode->i_mode; di->di_uid = inode->i_uid; di->di_gid = inode->i_gid; di->di_atime = inode->i_atime.tv_sec; @@ -210,9 +206,9 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) if (ip->i_num.no_formal_ino != be64_to_cpu(str->di_num.no_formal_ino)) return -ESTALE; - di->di_mode = be32_to_cpu(str->di_mode); + ip->i_inode.i_mode = be32_to_cpu(str->di_mode); ip->i_inode.i_rdev = 0; - switch (di->di_mode & S_IFMT) { + switch (ip->i_inode.i_mode & S_IFMT) { case S_IFBLK: case S_IFCHR: ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major), @@ -620,7 +616,7 @@ static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, unsigned int *uid, unsigned int *gid) { if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir && - (dip->i_di.di_mode & S_ISUID) && dip->i_di.di_uid) { + (dip->i_inode.i_mode & S_ISUID) && dip->i_di.di_uid) { if (S_ISDIR(*mode)) *mode |= S_ISUID; else if (dip->i_di.di_uid != current->fsuid) @@ -629,7 +625,7 @@ static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, } else *uid = current->fsuid; - if (dip->i_di.di_mode & S_ISGID) { + if (dip->i_inode.i_mode & S_ISGID) { if (S_ISDIR(*mode)) *mode |= S_ISGID; *gid = dip->i_di.di_gid; @@ -810,7 +806,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, goto fail_quota_locks; } - error = gfs2_dir_add(&dip->i_inode, name, &ip->i_num, IF2DT(ip->i_di.di_mode)); + error = gfs2_dir_add(&dip->i_inode, name, &ip->i_num, IF2DT(ip->i_inode.i_mode)); if (error) goto fail_end_trans; @@ -1053,7 +1049,7 @@ int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) return -EPERM; - if ((dip->i_di.di_mode & S_ISVTX) && + if ((dip->i_inode.i_mode & S_ISVTX) && dip->i_di.di_uid != current->fsuid && ip->i_di.di_uid != current->fsuid && !capable(CAP_FOWNER)) return -EPERM; @@ -1072,7 +1068,7 @@ int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, if (!gfs2_inum_equal(&inum, &ip->i_num)) return -ENOENT; - if (IF2DT(ip->i_di.di_mode) != type) { + if (IF2DT(ip->i_inode.i_mode) != type) { gfs2_consist_inode(dip); return -EIO; } diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 33c9ea68f7e7..69cbf98509a9 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -22,7 +22,7 @@ static inline int gfs2_is_jdata(struct gfs2_inode *ip) static inline int gfs2_is_dir(struct gfs2_inode *ip) { - return S_ISDIR(ip->i_di.di_mode); + return S_ISDIR(ip->i_inode.i_mode); } void gfs2_inode_attr_in(struct gfs2_inode *ip); diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 60dd943761ab..6b50a5731a51 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -161,7 +161,7 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) gfs2_inum_out(&ip->i_num, &str->di_num); - str->di_mode = cpu_to_be32(di->di_mode); + str->di_mode = cpu_to_be32(ip->i_inode.i_mode); str->di_uid = cpu_to_be32(di->di_uid); str->di_gid = cpu_to_be32(di->di_gid); str->di_nlink = cpu_to_be32(di->di_nlink); @@ -191,7 +191,6 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) gfs2_inum_print(&ip->i_num); - pv(di, di_mode, "0%o"); pv(di, di_uid, "%u"); pv(di, di_gid, "%u"); pv(di, di_nlink, "%u"); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 015640b3f123..45a3d85b1d68 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -498,7 +498,6 @@ static int gfs2_commit_write(struct file *file, struct page *page, di->di_size = cpu_to_be64(inode->i_size); } - di->di_mode = cpu_to_be32(inode->i_mode); di->di_atime = cpu_to_be64(inode->i_atime.tv_sec); di->di_mtime = cpu_to_be64(inode->i_mtime.tv_sec); di->di_ctime = cpu_to_be64(inode->i_ctime.tv_sec); diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index c36f9e342e66..d355899585d8 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -76,7 +76,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) if (!gfs2_inum_equal(&ip->i_num, &inum)) goto invalid_gunlock; - if (IF2DT(ip->i_di.di_mode) != type) { + if (IF2DT(ip->i_inode.i_mode) != type) { gfs2_consist_inode(dip); goto fail_gunlock; } diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 7ea417573903..b52b9db1a2bd 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -425,7 +425,7 @@ static int gfs2_open(struct inode *inode, struct file *file) gfs2_assert_warn(GFS2_SB(inode), !file->private_data); file->private_data = fp; - if (S_ISREG(ip->i_di.di_mode)) { + if (S_ISREG(ip->i_inode.i_mode)) { error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) @@ -515,7 +515,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) if (!(fl->fl_flags & FL_POSIX)) return -ENOLCK; - if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) return -ENOLCK; if (sdp->sd_args.ar_localflocks) { @@ -617,7 +617,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) if (!(fl->fl_flags & FL_FLOCK)) return -ENOLCK; - if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) return -ENOLCK; if (sdp->sd_args.ar_localflocks) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index c10b914bf8cc..cf7a5bae3957 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -144,7 +144,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, int alloc_required; int error; - if (S_ISDIR(ip->i_di.di_mode)) + if (S_ISDIR(inode->i_mode)) return -EPERM; gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); @@ -220,7 +220,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, } error = gfs2_dir_add(dir, &dentry->d_name, &ip->i_num, - IF2DT(ip->i_di.di_mode)); + IF2DT(inode->i_mode)); if (error) goto out_end_trans; @@ -564,11 +564,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, /* Make sure we aren't trying to move a dirctory into it's subdir */ - if (S_ISDIR(ip->i_di.di_mode) && odip != ndip) { + if (S_ISDIR(ip->i_inode.i_mode) && odip != ndip) { dir_rename = 1; - error = gfs2_glock_nq_init(sdp->sd_rename_gl, - LM_ST_EXCLUSIVE, 0, + error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, 0, &r_gh); if (error) goto out; @@ -609,7 +608,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (error) goto out_gunlock; - if (S_ISDIR(nip->i_di.di_mode)) { + if (S_ISDIR(nip->i_inode.i_mode)) { if (nip->i_di.di_entries < 2) { if (gfs2_consist_inode(nip)) gfs2_dinode_print(nip); @@ -646,7 +645,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, error = -EFBIG; goto out_gunlock; } - if (S_ISDIR(ip->i_di.di_mode) && + if (S_ISDIR(ip->i_inode.i_mode) && ndip->i_di.di_nlink == (u32)-1) { error = -EMLINK; goto out_gunlock; @@ -701,7 +700,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, /* Remove the target file, if it exists */ if (nip) { - if (S_ISDIR(nip->i_di.di_mode)) + if (S_ISDIR(nip->i_inode.i_mode)) error = gfs2_rmdiri(ndip, &ndentry->d_name, nip); else { error = gfs2_dir_del(ndip, &ndentry->d_name); @@ -743,7 +742,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, goto out_end_trans; error = gfs2_dir_add(ndir, &ndentry->d_name, &ip->i_num, - IF2DT(ip->i_di.di_mode)); + IF2DT(ip->i_inode.i_mode)); if (error) goto out_end_trans; diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 9c786d1e702d..863517569223 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -407,7 +407,7 @@ static void gfs2_delete_inode(struct inode *inode) if (error) goto out_uninit; - if (S_ISDIR(ip->i_di.di_mode) && + if (S_ISDIR(inode->i_mode) && (ip->i_di.di_flags & GFS2_DIF_EXHASH)) { error = gfs2_dir_exhash_dealloc(ip); if (error) diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 5bcf895b2731..f1ea0b48060b 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -322,7 +322,6 @@ struct gfs2_dinode { }; struct gfs2_dinode_host { - __u32 di_mode; /* mode of file */ __u32 di_uid; /* owner's user id */ __u32 di_gid; /* owner's group id */ __u32 di_nlink; /* number of links to this file */ -- cgit v1.2.3 From 2933f9254a6af33db25270778c998a42029da668 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 1 Nov 2006 13:23:29 -0500 Subject: [GFS2] Shrink gfs2_inode (4) - di_uid/di_gid Remove duplicate di_uid/di_gid fields in favour of using inode->i_uid/inode->i_gid instead. This saves 8 bytes. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 2 +- fs/gfs2/bmap.c | 2 +- fs/gfs2/eattr.c | 2 +- fs/gfs2/inode.c | 23 +++++++++-------------- fs/gfs2/ondisk.c | 6 ++---- fs/gfs2/ops_address.c | 2 +- fs/gfs2/ops_inode.c | 10 ++++------ fs/gfs2/ops_vm.c | 2 +- fs/gfs2/quota.c | 8 ++++---- fs/gfs2/rgrp.c | 11 +++++------ include/linux/gfs2_ondisk.h | 2 -- 11 files changed, 29 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 87f6304f2f54..3908992b27a2 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -74,7 +74,7 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) { if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl) return -EOPNOTSUPP; - if (current->fsuid != ip->i_di.di_uid && !capable(CAP_FOWNER)) + if (current->fsuid != ip->i_inode.i_uid && !capable(CAP_FOWNER)) return -EPERM; if (S_ISLNK(ip->i_inode.i_mode)) return -EOPNOTSUPP; diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 481a06882544..0c913eecf884 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -819,7 +819,7 @@ static int do_grow(struct gfs2_inode *ip, u64 size) if (error) goto out; - error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); if (error) goto out_gunlock_q; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 5208fa94aad2..935cc9a57168 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -687,7 +687,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, if (error) goto out; - error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); if (error) goto out_gunlock_q; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index de466043c91a..0de9b22f454b 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -52,8 +52,6 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) inode->i_ino = ip->i_num.no_addr; inode->i_nlink = di->di_nlink; - inode->i_uid = di->di_uid; - inode->i_gid = di->di_gid; i_size_write(inode, di->di_size); inode->i_atime.tv_sec = di->di_atime; inode->i_mtime.tv_sec = di->di_mtime; @@ -87,8 +85,6 @@ void gfs2_inode_attr_out(struct gfs2_inode *ip) { struct inode *inode = &ip->i_inode; struct gfs2_dinode_host *di = &ip->i_di; - di->di_uid = inode->i_uid; - di->di_gid = inode->i_gid; di->di_atime = inode->i_atime.tv_sec; di->di_mtime = inode->i_mtime.tv_sec; di->di_ctime = inode->i_ctime.tv_sec; @@ -216,8 +212,8 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) break; }; - di->di_uid = be32_to_cpu(str->di_uid); - di->di_gid = be32_to_cpu(str->di_gid); + ip->i_inode.i_uid = be32_to_cpu(str->di_uid); + ip->i_inode.i_gid = be32_to_cpu(str->di_gid); di->di_nlink = be32_to_cpu(str->di_nlink); di->di_size = be64_to_cpu(str->di_size); di->di_blocks = be64_to_cpu(str->di_blocks); @@ -616,19 +612,19 @@ static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, unsigned int *uid, unsigned int *gid) { if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir && - (dip->i_inode.i_mode & S_ISUID) && dip->i_di.di_uid) { + (dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) { if (S_ISDIR(*mode)) *mode |= S_ISUID; - else if (dip->i_di.di_uid != current->fsuid) + else if (dip->i_inode.i_uid != current->fsuid) *mode &= ~07111; - *uid = dip->i_di.di_uid; + *uid = dip->i_inode.i_uid; } else *uid = current->fsuid; if (dip->i_inode.i_mode & S_ISGID) { if (S_ISDIR(*mode)) *mode |= S_ISGID; - *gid = dip->i_di.di_gid; + *gid = dip->i_inode.i_gid; } else *gid = current->fsgid; } @@ -783,8 +779,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, if (alloc_required < 0) goto fail; if (alloc_required) { - error = gfs2_quota_check(dip, dip->i_di.di_uid, - dip->i_di.di_gid); + error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid); if (error) goto fail_quota_locks; @@ -1050,8 +1045,8 @@ int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, return -EPERM; if ((dip->i_inode.i_mode & S_ISVTX) && - dip->i_di.di_uid != current->fsuid && - ip->i_di.di_uid != current->fsuid && !capable(CAP_FOWNER)) + dip->i_inode.i_uid != current->fsuid && + ip->i_inode.i_uid != current->fsuid && !capable(CAP_FOWNER)) return -EPERM; if (IS_APPEND(&dip->i_inode)) diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 6b50a5731a51..e224f6a22641 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -162,8 +162,8 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) gfs2_inum_out(&ip->i_num, &str->di_num); str->di_mode = cpu_to_be32(ip->i_inode.i_mode); - str->di_uid = cpu_to_be32(di->di_uid); - str->di_gid = cpu_to_be32(di->di_gid); + str->di_uid = cpu_to_be32(ip->i_inode.i_uid); + str->di_gid = cpu_to_be32(ip->i_inode.i_gid); str->di_nlink = cpu_to_be32(di->di_nlink); str->di_size = cpu_to_be64(di->di_size); str->di_blocks = cpu_to_be64(di->di_blocks); @@ -191,8 +191,6 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) gfs2_inum_print(&ip->i_num); - pv(di, di_uid, "%u"); - pv(di, di_gid, "%u"); pv(di, di_nlink, "%u"); printk(KERN_INFO " di_size = %llu\n", (unsigned long long)di->di_size); printk(KERN_INFO " di_blocks = %llu\n", (unsigned long long)di->di_blocks); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 45a3d85b1d68..38b702a18244 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -386,7 +386,7 @@ static int gfs2_prepare_write(struct file *file, struct page *page, if (error) goto out_alloc_put; - error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); if (error) goto out_qunlock; diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index cf7a5bae3957..efbcec3311bb 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -196,8 +196,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (error) goto out_alloc; - error = gfs2_quota_check(dip, dip->i_di.di_uid, - dip->i_di.di_gid); + error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid); if (error) goto out_gunlock_q; @@ -673,8 +672,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (error) goto out_alloc; - error = gfs2_quota_check(ndip, ndip->i_di.di_uid, - ndip->i_di.di_gid); + error = gfs2_quota_check(ndip, ndip->i_inode.i_uid, ndip->i_inode.i_gid); if (error) goto out_gunlock_q; @@ -885,8 +883,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) u32 ouid, ogid, nuid, ngid; int error; - ouid = ip->i_di.di_uid; - ogid = ip->i_di.di_gid; + ouid = inode->i_uid; + ogid = inode->i_gid; nuid = attr->ia_uid; ngid = attr->ia_gid; diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 5453d2947ab3..45a5f11fc39a 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -76,7 +76,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) if (error) goto out; - error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); if (error) goto out_gunlock_q; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 5d00e9b20973..d0db881b55d2 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -452,19 +452,19 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) return 0; - error = qdsb_get(sdp, QUOTA_USER, ip->i_di.di_uid, CREATE, qd); + error = qdsb_get(sdp, QUOTA_USER, ip->i_inode.i_uid, CREATE, qd); if (error) goto out; al->al_qd_num++; qd++; - error = qdsb_get(sdp, QUOTA_GROUP, ip->i_di.di_gid, CREATE, qd); + error = qdsb_get(sdp, QUOTA_GROUP, ip->i_inode.i_gid, CREATE, qd); if (error) goto out; al->al_qd_num++; qd++; - if (uid != NO_QUOTA_CHANGE && uid != ip->i_di.di_uid) { + if (uid != NO_QUOTA_CHANGE && uid != ip->i_inode.i_uid) { error = qdsb_get(sdp, QUOTA_USER, uid, CREATE, qd); if (error) goto out; @@ -472,7 +472,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) qd++; } - if (gid != NO_QUOTA_CHANGE && gid != ip->i_di.di_gid) { + if (gid != NO_QUOTA_CHANGE && gid != ip->i_inode.i_gid) { error = qdsb_get(sdp, QUOTA_GROUP, gid, CREATE, qd); if (error) goto out; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 07dfd6305058..ff0846528d54 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1217,7 +1217,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) al->al_alloced++; gfs2_statfs_change(sdp, 0, -1, 0); - gfs2_quota_change(ip, +1, ip->i_di.di_uid, ip->i_di.di_gid); + gfs2_quota_change(ip, +1, ip->i_inode.i_uid, ip->i_inode.i_gid); spin_lock(&sdp->sd_rindex_spin); rgd->rd_free_clone--; @@ -1261,7 +1261,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) al->al_alloced++; gfs2_statfs_change(sdp, 0, -1, 0); - gfs2_quota_change(ip, +1, ip->i_di.di_uid, ip->i_di.di_gid); + gfs2_quota_change(ip, +1, ip->i_inode.i_uid, ip->i_inode.i_gid); gfs2_trans_add_unrevoke(sdp, block); spin_lock(&sdp->sd_rindex_spin); @@ -1337,8 +1337,7 @@ void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen) gfs2_trans_add_rg(rgd); gfs2_statfs_change(sdp, 0, +blen, 0); - gfs2_quota_change(ip, -(s64)blen, - ip->i_di.di_uid, ip->i_di.di_gid); + gfs2_quota_change(ip, -(s64)blen, ip->i_inode.i_uid, ip->i_inode.i_gid); } /** @@ -1366,7 +1365,7 @@ void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen) gfs2_trans_add_rg(rgd); gfs2_statfs_change(sdp, 0, +blen, 0); - gfs2_quota_change(ip, -(s64)blen, ip->i_di.di_uid, ip->i_di.di_gid); + gfs2_quota_change(ip, -(s64)blen, ip->i_inode.i_uid, ip->i_inode.i_gid); gfs2_meta_wipe(ip, bstart, blen); } @@ -1411,7 +1410,7 @@ static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno) void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip) { gfs2_free_uninit_di(rgd, ip->i_num.no_addr); - gfs2_quota_change(ip, -1, ip->i_di.di_uid, ip->i_di.di_gid); + gfs2_quota_change(ip, -1, ip->i_inode.i_uid, ip->i_inode.i_gid); gfs2_meta_wipe(ip, ip->i_num.no_addr, 1); } diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index f1ea0b48060b..896c7f81a637 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -322,8 +322,6 @@ struct gfs2_dinode { }; struct gfs2_dinode_host { - __u32 di_uid; /* owner's user id */ - __u32 di_gid; /* owner's group id */ __u32 di_nlink; /* number of links to this file */ __u64 di_size; /* number of bytes in file */ __u64 di_blocks; /* number of blocks in file */ -- cgit v1.2.3 From 4f56110a00af5fb2e22fbccfcaf944d62cae8fcf Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 1 Nov 2006 14:04:17 -0500 Subject: [GFS2] Shrink gfs2_inode (5) - di_nlink Remove the di_nlink field in favour of inode->i_nlink and update the nlink handling to use the proper macros. This saves 4 bytes. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 37 ++++++++++++++++++++++++------------- fs/gfs2/ondisk.c | 3 +-- fs/gfs2/ops_inode.c | 12 ++++++------ include/linux/gfs2_ondisk.h | 1 - 4 files changed, 31 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 0de9b22f454b..711203984823 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -51,7 +51,6 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) struct gfs2_dinode_host *di = &ip->i_di; inode->i_ino = ip->i_num.no_addr; - inode->i_nlink = di->di_nlink; i_size_write(inode, di->di_size); inode->i_atime.tv_sec = di->di_atime; inode->i_mtime.tv_sec = di->di_mtime; @@ -214,7 +213,12 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ip->i_inode.i_uid = be32_to_cpu(str->di_uid); ip->i_inode.i_gid = be32_to_cpu(str->di_gid); - di->di_nlink = be32_to_cpu(str->di_nlink); + /* + * We will need to review setting the nlink count here in the + * light of the forthcoming ro bind mount work. This is a reminder + * to do that. + */ + ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink); di->di_size = be64_to_cpu(str->di_size); di->di_blocks = be64_to_cpu(str->di_blocks); di->di_atime = be64_to_cpu(str->di_atime); @@ -336,12 +340,12 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) u32 nlink; int error; - BUG_ON(ip->i_di.di_nlink != ip->i_inode.i_nlink); - nlink = ip->i_di.di_nlink + diff; + BUG_ON(diff != 1 && diff != -1); + nlink = ip->i_inode.i_nlink + diff; /* If we are reducing the nlink count, but the new value ends up being bigger than the old one, we must have underflowed. */ - if (diff < 0 && nlink > ip->i_di.di_nlink) { + if (diff < 0 && nlink > ip->i_inode.i_nlink) { if (gfs2_consist_inode(ip)) gfs2_dinode_print(ip); return -EIO; @@ -351,16 +355,19 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) if (error) return error; - ip->i_di.di_nlink = nlink; + if (diff > 0) + inc_nlink(&ip->i_inode); + else + drop_nlink(&ip->i_inode); + ip->i_di.di_ctime = get_seconds(); - ip->i_inode.i_nlink = nlink; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); mark_inode_dirty(&ip->i_inode); - if (ip->i_di.di_nlink == 0) { + if (ip->i_inode.i_nlink == 0) { struct gfs2_rgrpd *rgd; struct gfs2_holder ri_gh, rg_gh; @@ -375,7 +382,6 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) if (error) goto out_norgrp; - clear_nlink(&ip->i_inode); gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */ gfs2_glock_dq_uninit(&rg_gh); out_norgrp: @@ -586,7 +592,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, return error; /* Don't create entries in an unlinked directory */ - if (!dip->i_di.di_nlink) + if (!dip->i_inode.i_nlink) return -EPERM; error = gfs2_dir_search(&dip->i_inode, name, NULL, NULL); @@ -602,7 +608,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, if (dip->i_di.di_entries == (u32)-1) return -EFBIG; - if (S_ISDIR(mode) && dip->i_di.di_nlink == (u32)-1) + if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1) return -EMLINK; return 0; @@ -808,7 +814,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto fail_end_trans; - ip->i_di.di_nlink = 1; + ip->i_inode.i_nlink = 1; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -1016,7 +1022,12 @@ int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, if (error) return error; - error = gfs2_change_nlink(ip, -2); + /* It looks odd, but it really should be done twice */ + error = gfs2_change_nlink(ip, -1); + if (error) + return error; + + error = gfs2_change_nlink(ip, -1); if (error) return error; diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index e224f6a22641..b4e354b18815 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -164,7 +164,7 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_mode = cpu_to_be32(ip->i_inode.i_mode); str->di_uid = cpu_to_be32(ip->i_inode.i_uid); str->di_gid = cpu_to_be32(ip->i_inode.i_gid); - str->di_nlink = cpu_to_be32(di->di_nlink); + str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink); str->di_size = cpu_to_be64(di->di_size); str->di_blocks = cpu_to_be64(di->di_blocks); str->di_atime = cpu_to_be64(di->di_atime); @@ -191,7 +191,6 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) gfs2_inum_print(&ip->i_num); - pv(di, di_nlink, "%u"); printk(KERN_INFO " di_size = %llu\n", (unsigned long long)di->di_size); printk(KERN_INFO " di_blocks = %llu\n", (unsigned long long)di->di_blocks); printk(KERN_INFO " di_atime = %lld\n", (long long)di->di_atime); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index efbcec3311bb..06176dee1550 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -169,7 +169,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, } error = -EINVAL; - if (!dip->i_di.di_nlink) + if (!dip->i_inode.i_nlink) goto out_gunlock; error = -EFBIG; if (dip->i_di.di_entries == (u32)-1) @@ -178,10 +178,10 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out_gunlock; error = -EINVAL; - if (!ip->i_di.di_nlink) + if (!ip->i_inode.i_nlink) goto out_gunlock; error = -EMLINK; - if (ip->i_di.di_nlink == (u32)-1) + if (ip->i_inode.i_nlink == (u32)-1) goto out_gunlock; alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name); @@ -386,7 +386,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) ip = ghs[1].gh_gl->gl_object; - ip->i_di.di_nlink = 2; + ip->i_inode.i_nlink = 2; ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode); ip->i_di.di_flags |= GFS2_DIF_JDATA; ip->i_di.di_payload_format = GFS2_FORMAT_DE; @@ -636,7 +636,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, }; if (odip != ndip) { - if (!ndip->i_di.di_nlink) { + if (!ndip->i_inode.i_nlink) { error = -EINVAL; goto out_gunlock; } @@ -645,7 +645,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, goto out_gunlock; } if (S_ISDIR(ip->i_inode.i_mode) && - ndip->i_di.di_nlink == (u32)-1) { + ndip->i_inode.i_nlink == (u32)-1) { error = -EMLINK; goto out_gunlock; } diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 896c7f81a637..c61517b35b2e 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -322,7 +322,6 @@ struct gfs2_dinode { }; struct gfs2_dinode_host { - __u32 di_nlink; /* number of links to this file */ __u64 di_size; /* number of bytes in file */ __u64 di_blocks; /* number of blocks in file */ __u64 di_atime; /* time last accessed */ -- cgit v1.2.3 From 1a7b1eed5802502fd649e04784becd58557fdcf1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 1 Nov 2006 14:35:17 -0500 Subject: [GFS2] Shrink gfs2_inode (6) - di_atime/di_mtime/di_ctime Remove the di_[amc]time fields and use inode->i_[amc]time fields instead. This saves 24 bytes from the gfs2_inode. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 10 +++++----- fs/gfs2/dir.c | 10 +++++----- fs/gfs2/eattr.c | 9 ++++----- fs/gfs2/inode.c | 44 +++++++++++--------------------------------- fs/gfs2/inode.h | 1 - fs/gfs2/ondisk.c | 10 +++------- fs/gfs2/ops_address.c | 4 ---- fs/gfs2/ops_inode.c | 3 +-- include/linux/gfs2_ondisk.h | 3 --- 9 files changed, 29 insertions(+), 65 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 0c913eecf884..692d4a3da1bc 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -778,7 +778,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, gfs2_free_data(ip, bstart, blen); } - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_dinode_out(ip, dibh->b_data); @@ -853,7 +853,7 @@ static int do_grow(struct gfs2_inode *ip, u64 size) } ip->i_di.di_size = size; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); error = gfs2_meta_inode_buffer(ip, &dibh); if (error) @@ -968,7 +968,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size) if (gfs2_is_stuffed(ip)) { ip->i_di.di_size = size; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size); @@ -980,7 +980,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size) if (!error) { ip->i_di.di_size = size; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); @@ -1053,7 +1053,7 @@ static int trunc_end(struct gfs2_inode *ip) ip->i_num.no_addr; gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); } - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG; gfs2_trans_add_bh(ip->i_gl, dibh, 1); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 0742761e1e02..ca23c8beb3f0 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -131,7 +131,7 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size); if (ip->i_di.di_size < offset + size) ip->i_di.di_size = offset + size; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -229,7 +229,7 @@ out: if (ip->i_di.di_size < offset + copied) ip->i_di.di_size = offset + copied; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); @@ -1560,7 +1560,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, break; gfs2_trans_add_bh(ip->i_gl, bh, 1); ip->i_di.di_entries++; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_dinode_out(ip, bh->b_data); brelse(bh); error = 0; @@ -1646,7 +1646,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) gfs2_consist_inode(dip); gfs2_trans_add_bh(dip->i_gl, bh, 1); dip->i_di.di_entries--; - dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + dip->i_inode.i_mtime.tv_sec = dip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_dinode_out(dip, bh->b_data); brelse(bh); mark_inode_dirty(&dip->i_inode); @@ -1694,7 +1694,7 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, gfs2_trans_add_bh(dip->i_gl, bh, 1); } - dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + dip->i_inode.i_mtime.tv_sec = dip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_dinode_out(dip, bh->b_data); brelse(bh); return 0; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 935cc9a57168..7dde84775ba7 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -300,7 +300,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { - ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -715,7 +715,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, (er->er_mode & S_IFMT)); ip->i_inode.i_mode = er->er_mode; } - ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -850,7 +850,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT)); ip->i_inode.i_mode = er->er_mode; } - ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -1130,7 +1130,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { - ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -1285,7 +1285,6 @@ int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, if (!error) { error = inode_setattr(&ip->i_inode, attr); gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); - gfs2_inode_attr_out(ip); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 711203984823..c22ae3c3a444 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -52,12 +52,6 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) inode->i_ino = ip->i_num.no_addr; i_size_write(inode, di->di_size); - inode->i_atime.tv_sec = di->di_atime; - inode->i_mtime.tv_sec = di->di_mtime; - inode->i_ctime.tv_sec = di->di_ctime; - inode->i_atime.tv_nsec = 0; - inode->i_mtime.tv_nsec = 0; - inode->i_ctime.tv_nsec = 0; inode->i_blocks = di->di_blocks << (GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT); @@ -72,23 +66,6 @@ void gfs2_inode_attr_in(struct gfs2_inode *ip) inode->i_flags &= ~S_APPEND; } -/** - * gfs2_inode_attr_out - Copy attributes from VFS inode into the dinode - * @ip: The GFS2 inode - * - * Only copy out the attributes that we want the VFS layer - * to be able to modify. - */ - -void gfs2_inode_attr_out(struct gfs2_inode *ip) -{ - struct inode *inode = &ip->i_inode; - struct gfs2_dinode_host *di = &ip->i_di; - di->di_atime = inode->i_atime.tv_sec; - di->di_mtime = inode->i_mtime.tv_sec; - di->di_ctime = inode->i_ctime.tv_sec; -} - static int iget_test(struct inode *inode, void *opaque) { struct gfs2_inode *ip = GFS2_I(inode); @@ -221,9 +198,12 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink); di->di_size = be64_to_cpu(str->di_size); di->di_blocks = be64_to_cpu(str->di_blocks); - di->di_atime = be64_to_cpu(str->di_atime); - di->di_mtime = be64_to_cpu(str->di_mtime); - di->di_ctime = be64_to_cpu(str->di_ctime); + ip->i_inode.i_atime.tv_sec = be64_to_cpu(str->di_atime); + ip->i_inode.i_atime.tv_nsec = 0; + ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime); + ip->i_inode.i_mtime.tv_nsec = 0; + ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime); + ip->i_inode.i_ctime.tv_nsec = 0; di->di_goal_meta = be64_to_cpu(str->di_goal_meta); di->di_goal_data = be64_to_cpu(str->di_goal_data); @@ -360,7 +340,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) else drop_nlink(&ip->i_inode); - ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); @@ -1224,7 +1204,7 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh) return 0; curtime = get_seconds(); - if (curtime - ip->i_di.di_atime >= quantum) { + if (curtime - ip->i_inode.i_atime.tv_sec >= quantum) { gfs2_glock_dq(gh); gfs2_holder_reinit(LM_ST_EXCLUSIVE, gh->gh_flags & ~LM_FLAG_ANY, gh); @@ -1236,7 +1216,7 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh) trying to get exclusive lock. */ curtime = get_seconds(); - if (curtime - ip->i_di.di_atime >= quantum) { + if (curtime - ip->i_inode.i_atime.tv_sec >= quantum) { struct buffer_head *dibh; struct gfs2_dinode *di; @@ -1250,11 +1230,11 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh) if (error) goto fail_end_trans; - ip->i_di.di_atime = curtime; + ip->i_inode.i_atime.tv_sec = curtime; gfs2_trans_add_bh(ip->i_gl, dibh, 1); di = (struct gfs2_dinode *)dibh->b_data; - di->di_atime = cpu_to_be64(ip->i_di.di_atime); + di->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec); brelse(dibh); gfs2_trans_end(sdp); @@ -1375,8 +1355,6 @@ __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) if (!error) { error = inode_setattr(&ip->i_inode, attr); gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); - gfs2_inode_attr_out(ip); - gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 69cbf98509a9..54d584eddf29 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -26,7 +26,6 @@ static inline int gfs2_is_dir(struct gfs2_inode *ip) } void gfs2_inode_attr_in(struct gfs2_inode *ip); -void gfs2_inode_attr_out(struct gfs2_inode *ip); struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum_host *inum, unsigned type); struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum_host *inum); diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index b4e354b18815..82003e872a37 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -167,9 +167,9 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink); str->di_size = cpu_to_be64(di->di_size); str->di_blocks = cpu_to_be64(di->di_blocks); - str->di_atime = cpu_to_be64(di->di_atime); - str->di_mtime = cpu_to_be64(di->di_mtime); - str->di_ctime = cpu_to_be64(di->di_ctime); + str->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec); + str->di_mtime = cpu_to_be64(ip->i_inode.i_mtime.tv_sec); + str->di_ctime = cpu_to_be64(ip->i_inode.i_ctime.tv_sec); str->di_goal_meta = cpu_to_be64(di->di_goal_meta); str->di_goal_data = cpu_to_be64(di->di_goal_data); @@ -193,10 +193,6 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) printk(KERN_INFO " di_size = %llu\n", (unsigned long long)di->di_size); printk(KERN_INFO " di_blocks = %llu\n", (unsigned long long)di->di_blocks); - printk(KERN_INFO " di_atime = %lld\n", (long long)di->di_atime); - printk(KERN_INFO " di_mtime = %lld\n", (long long)di->di_mtime); - printk(KERN_INFO " di_ctime = %lld\n", (long long)di->di_ctime); - printk(KERN_INFO " di_goal_meta = %llu\n", (unsigned long long)di->di_goal_meta); printk(KERN_INFO " di_goal_data = %llu\n", (unsigned long long)di->di_goal_data); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 38b702a18244..5c3962c80e88 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -498,10 +498,6 @@ static int gfs2_commit_write(struct file *file, struct page *page, di->di_size = cpu_to_be64(inode->i_size); } - di->di_atime = cpu_to_be64(inode->i_atime.tv_sec); - di->di_mtime = cpu_to_be64(inode->i_mtime.tv_sec); - di->di_ctime = cpu_to_be64(inode->i_ctime.tv_sec); - brelse(dibh); gfs2_trans_end(sdp); if (al->al_requested) { diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 06176dee1550..585b43a94ace 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -729,7 +729,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto out_end_trans; - ip->i_di.di_ctime = get_seconds(); + ip->i_inode.i_ctime.tv_sec = get_seconds(); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -915,7 +915,6 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) error = inode_setattr(inode, attr); gfs2_assert_warn(sdp, !error); - gfs2_inode_attr_out(ip); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index c61517b35b2e..7f5a4a16224b 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -324,9 +324,6 @@ struct gfs2_dinode { struct gfs2_dinode_host { __u64 di_size; /* number of bytes in file */ __u64 di_blocks; /* number of blocks in file */ - __u64 di_atime; /* time last accessed */ - __u64 di_mtime; /* time last modified */ - __u64 di_ctime; /* time last changed */ /* This section varies from gfs1. Padding added to align with * remainder of dinode -- cgit v1.2.3 From a9583c7983cbba9726bfe64ee46613d654fc9e26 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 1 Nov 2006 20:09:14 -0500 Subject: [GFS2] Shrink gfs2_inode (7) - di_payload_format This is almost never used. Its there for backward compatibility with GFS1. It doesn't need its own field since it can always be calculated from the inode mode & flags. This saves a bit more space in the gfs2_inode. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 1 - fs/gfs2/inode.c | 3 +-- fs/gfs2/ondisk.c | 6 +++--- fs/gfs2/ops_inode.c | 1 - include/linux/gfs2_ondisk.h | 1 - 5 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index ca23c8beb3f0..c82d7cb4a654 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -902,7 +902,6 @@ static int dir_make_exhash(struct inode *inode) dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2; dip->i_di.di_blocks++; dip->i_di.di_flags |= GFS2_DIF_EXHASH; - dip->i_di.di_payload_format = 0; for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; dip->i_di.di_depth = y; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index c22ae3c3a444..f6177fc68320 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -210,7 +210,6 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) di->di_generation = be64_to_cpu(str->di_generation); di->di_flags = be32_to_cpu(str->di_flags); - di->di_payload_format = be32_to_cpu(str->di_payload_format); di->di_height = be16_to_cpu(str->di_height); di->di_depth = be16_to_cpu(str->di_depth); @@ -699,7 +698,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, } di->__pad1 = 0; - di->di_payload_format = cpu_to_be32(0); + di->di_payload_format = cpu_to_be32(S_ISDIR(mode) ? GFS2_FORMAT_DE : 0); di->di_height = cpu_to_be32(0); di->__pad2 = 0; di->__pad3 = 0; diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 82003e872a37..b2baba5c50b7 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -176,9 +176,10 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_generation = cpu_to_be64(di->di_generation); str->di_flags = cpu_to_be32(di->di_flags); - str->di_payload_format = cpu_to_be32(di->di_payload_format); str->di_height = cpu_to_be16(di->di_height); - + str->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) && + !(ip->i_di.di_flags & GFS2_DIF_EXHASH) ? + GFS2_FORMAT_DE : 0); str->di_depth = cpu_to_be16(di->di_depth); str->di_entries = cpu_to_be32(di->di_entries); @@ -197,7 +198,6 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) printk(KERN_INFO " di_goal_data = %llu\n", (unsigned long long)di->di_goal_data); pv(di, di_flags, "0x%.8X"); - pv(di, di_payload_format, "%u"); pv(di, di_height, "%u"); pv(di, di_depth, "%u"); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 585b43a94ace..0e4eade47bf2 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -389,7 +389,6 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) ip->i_inode.i_nlink = 2; ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode); ip->i_di.di_flags |= GFS2_DIF_JDATA; - ip->i_di.di_payload_format = GFS2_FORMAT_DE; ip->i_di.di_entries = 2; error = gfs2_meta_inode_buffer(ip, &dibh); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 7f5a4a16224b..536575efb62a 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -333,7 +333,6 @@ struct gfs2_dinode_host { __u64 di_generation; /* generation number for NFS */ __u32 di_flags; /* GFS2_DIF_... */ - __u32 di_payload_format; /* GFS2_FORMAT_... */ __u16 di_height; /* height of metadata */ /* These only apply to directories */ -- cgit v1.2.3 From f6e58f01e8dc869803b9f73b2aa9d5bc3f32ca05 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 7 Nov 2006 15:14:58 -0500 Subject: [GFS2] Don't copy meta_header for rgrp in and out The meta_header for an ondisk rgrp never changes, so there is no point copying it in and back out to disk. Also there is no reason to keep a copy for each rgrp in memory. The code already checks to ensure that the header is correct before it calls the routine to copy the data in, so that we don't even need to check whether its correct on disk in the functions in ondisk.c Signed-off-by: Steven Whitehouse --- fs/gfs2/ondisk.c | 11 ----------- include/linux/gfs2_ondisk.h | 2 -- 2 files changed, 13 deletions(-) (limited to 'include/linux') diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index b2baba5c50b7..f2495f1e21ad 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -65,15 +65,6 @@ static void gfs2_meta_header_in(struct gfs2_meta_header_host *mh, const void *bu mh->mh_format = be32_to_cpu(str->mh_format); } -static void gfs2_meta_header_out(const struct gfs2_meta_header_host *mh, void *buf) -{ - struct gfs2_meta_header *str = buf; - - str->mh_magic = cpu_to_be32(mh->mh_magic); - str->mh_type = cpu_to_be32(mh->mh_type); - str->mh_format = cpu_to_be32(mh->mh_format); -} - void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf) { const struct gfs2_sb *str = buf; @@ -119,7 +110,6 @@ void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf) { const struct gfs2_rgrp *str = buf; - gfs2_meta_header_in(&rg->rg_header, buf); rg->rg_flags = be32_to_cpu(str->rg_flags); rg->rg_free = be32_to_cpu(str->rg_free); rg->rg_dinodes = be32_to_cpu(str->rg_dinodes); @@ -130,7 +120,6 @@ void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf) { struct gfs2_rgrp *str = buf; - gfs2_meta_header_out(&rg->rg_header, buf); str->rg_flags = cpu_to_be32(rg->rg_flags); str->rg_free = cpu_to_be32(rg->rg_free); str->rg_dinodes = cpu_to_be32(rg->rg_dinodes); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 536575efb62a..8b7e4c1e32ae 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -213,8 +213,6 @@ struct gfs2_rgrp { }; struct gfs2_rgrp_host { - struct gfs2_meta_header_host rg_header; - __u32 rg_flags; __u32 rg_free; __u32 rg_dinodes; -- cgit v1.2.3 From be1c63411addba3ad750eb4fdfc50b97bc82825e Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Fri, 1 Dec 2006 10:39:12 +0100 Subject: [PATCH] blktrace: add timestamp message This adds a new timestamp message to blktrace, giving the timeofday when we starting tracing. This helps user space correlate block trace events with eg an application strace. This requires a (compatible) update to blkparse. The changed blkparse is still able to process traces generated by older kernels, and older versions of blkparse should silently ignore the new records (because they have a pid of 0). Signed-off-by: Olaf Kirch Signed-off-by: Jens Axboe --- block/blktrace.c | 57 ++++++++++++++++++++++++++++++++++---------- include/linux/blktrace_api.h | 12 ++++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/block/blktrace.c b/block/blktrace.c index 135593c8e45b..562ca7cbf858 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -22,30 +22,61 @@ #include #include #include +#include #include static DEFINE_PER_CPU(unsigned long long, blk_trace_cpu_offset) = { 0, }; static unsigned int blktrace_seq __read_mostly = 1; +/* + * Send out a notify message. + */ +static inline unsigned int trace_note(struct blk_trace *bt, + pid_t pid, int action, + const void *data, size_t len) +{ + struct blk_io_trace *t; + int cpu = smp_processor_id(); + + t = relay_reserve(bt->rchan, sizeof(*t) + len); + if (t == NULL) + return 0; + + t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION; + t->time = sched_clock() - per_cpu(blk_trace_cpu_offset, cpu); + t->device = bt->dev; + t->action = action; + t->pid = pid; + t->cpu = cpu; + t->pdu_len = len; + memcpy((void *) t + sizeof(*t), data, len); + return blktrace_seq; +} + /* * Send out a notify for this process, if we haven't done so since a trace * started */ static void trace_note_tsk(struct blk_trace *bt, struct task_struct *tsk) { - struct blk_io_trace *t; + tsk->btrace_seq = trace_note(bt, tsk->pid, + BLK_TN_PROCESS, + tsk->comm, sizeof(tsk->comm)); +} - t = relay_reserve(bt->rchan, sizeof(*t) + sizeof(tsk->comm)); - if (t) { - t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION; - t->device = bt->dev; - t->action = BLK_TC_ACT(BLK_TC_NOTIFY); - t->pid = tsk->pid; - t->cpu = smp_processor_id(); - t->pdu_len = sizeof(tsk->comm); - memcpy((void *) t + sizeof(*t), tsk->comm, t->pdu_len); - tsk->btrace_seq = blktrace_seq; - } +static void trace_note_time(struct blk_trace *bt) +{ + struct timespec now; + unsigned long flags; + u32 words[2]; + + getnstimeofday(&now); + words[0] = now.tv_sec; + words[1] = now.tv_nsec; + + local_irq_save(flags); + trace_note(bt, 0, BLK_TN_TIMESTAMP, words, sizeof(words)); + local_irq_restore(flags); } static int act_log_check(struct blk_trace *bt, u32 what, sector_t sector, @@ -394,6 +425,8 @@ static int blk_trace_startstop(request_queue_t *q, int start) blktrace_seq++; smp_mb(); bt->trace_state = Blktrace_running; + + trace_note_time(bt); ret = 0; } } else { diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index b99a714fcac6..3680ff9a30ed 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -49,6 +49,15 @@ enum blktrace_act { __BLK_TA_REMAP, /* bio was remapped */ }; +/* + * Notify events. + */ +enum blktrace_notify { + __BLK_TN_PROCESS = 0, /* establish pid/name mapping */ + __BLK_TN_TIMESTAMP, /* include system clock */ +}; + + /* * Trace actions in full. Additionally, read or write is masked */ @@ -68,6 +77,9 @@ enum blktrace_act { #define BLK_TA_BOUNCE (__BLK_TA_BOUNCE) #define BLK_TA_REMAP (__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE)) +#define BLK_TN_PROCESS (__BLK_TN_PROCESS | BLK_TC_ACT(BLK_TC_NOTIFY)) +#define BLK_TN_TIMESTAMP (__BLK_TN_TIMESTAMP | BLK_TC_ACT(BLK_TC_NOTIFY)) + #define BLK_IO_TRACE_MAGIC 0x65617400 #define BLK_IO_TRACE_VERSION 0x07 -- cgit v1.2.3 From 0e75f9063f5c55fb0b0b546a7c356f8ec186825e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 1 Dec 2006 10:40:55 +0100 Subject: [PATCH] block: support larger block pc requests This patch modifies blk_rq_map/unmap_user() and the cdrom and scsi_ioctl.c users so that it supports requests larger than bio by chaining them together. Signed-off-by: Mike Christie Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 166 +++++++++++++++++++++++++++++++++++++------------ block/scsi_ioctl.c | 53 ++++++++-------- drivers/cdrom/cdrom.c | 6 +- fs/bio.c | 18 +----- include/linux/blkdev.h | 7 ++- 5 files changed, 160 insertions(+), 90 deletions(-) (limited to 'include/linux') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 9eaee6640535..0f82e12f7b67 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2322,6 +2322,84 @@ void blk_insert_request(request_queue_t *q, struct request *rq, EXPORT_SYMBOL(blk_insert_request); +static int __blk_rq_unmap_user(struct bio *bio) +{ + int ret = 0; + + if (bio) { + if (bio_flagged(bio, BIO_USER_MAPPED)) + bio_unmap_user(bio); + else + ret = bio_uncopy_user(bio); + } + + return ret; +} + +static int __blk_rq_map_user(request_queue_t *q, struct request *rq, + void __user *ubuf, unsigned int len) +{ + unsigned long uaddr; + struct bio *bio, *orig_bio; + int reading, ret; + + reading = rq_data_dir(rq) == READ; + + /* + * if alignment requirement is satisfied, map in user pages for + * direct dma. else, set up kernel bounce buffers + */ + uaddr = (unsigned long) ubuf; + if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q))) + bio = bio_map_user(q, NULL, uaddr, len, reading); + else + bio = bio_copy_user(q, uaddr, len, reading); + + if (IS_ERR(bio)) { + return PTR_ERR(bio); + } + + orig_bio = bio; + blk_queue_bounce(q, &bio); + /* + * We link the bounce buffer in and could have to traverse it + * later so we have to get a ref to prevent it from being freed + */ + bio_get(bio); + + /* + * for most (all? don't know of any) queues we could + * skip grabbing the queue lock here. only drivers with + * funky private ->back_merge_fn() function could be + * problematic. + */ + spin_lock_irq(q->queue_lock); + if (!rq->bio) + blk_rq_bio_prep(q, rq, bio); + else if (!q->back_merge_fn(q, rq, bio)) { + ret = -EINVAL; + spin_unlock_irq(q->queue_lock); + goto unmap_bio; + } else { + rq->biotail->bi_next = bio; + rq->biotail = bio; + + rq->nr_sectors += bio_sectors(bio); + rq->hard_nr_sectors = rq->nr_sectors; + rq->data_len += bio->bi_size; + } + spin_unlock_irq(q->queue_lock); + + return bio->bi_size; + +unmap_bio: + /* if it was boucned we must call the end io function */ + bio_endio(bio, bio->bi_size, 0); + __blk_rq_unmap_user(orig_bio); + bio_put(bio); + return ret; +} + /** * blk_rq_map_user - map user data to a request, for REQ_BLOCK_PC usage * @q: request queue where request should be inserted @@ -2343,42 +2421,44 @@ EXPORT_SYMBOL(blk_insert_request); * unmapping. */ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, - unsigned int len) + unsigned long len) { - unsigned long uaddr; - struct bio *bio; - int reading; + unsigned long bytes_read = 0; + int ret; if (len > (q->max_hw_sectors << 9)) return -EINVAL; if (!len || !ubuf) return -EINVAL; - reading = rq_data_dir(rq) == READ; + while (bytes_read != len) { + unsigned long map_len, end, start; - /* - * if alignment requirement is satisfied, map in user pages for - * direct dma. else, set up kernel bounce buffers - */ - uaddr = (unsigned long) ubuf; - if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q))) - bio = bio_map_user(q, NULL, uaddr, len, reading); - else - bio = bio_copy_user(q, uaddr, len, reading); + map_len = min_t(unsigned long, len - bytes_read, BIO_MAX_SIZE); + end = ((unsigned long)ubuf + map_len + PAGE_SIZE - 1) + >> PAGE_SHIFT; + start = (unsigned long)ubuf >> PAGE_SHIFT; - if (!IS_ERR(bio)) { - rq->bio = rq->biotail = bio; - blk_rq_bio_prep(q, rq, bio); + /* + * A bad offset could cause us to require BIO_MAX_PAGES + 1 + * pages. If this happens we just lower the requested + * mapping len by a page so that we can fit + */ + if (end - start > BIO_MAX_PAGES) + map_len -= PAGE_SIZE; - rq->buffer = rq->data = NULL; - rq->data_len = len; - return 0; + ret = __blk_rq_map_user(q, rq, ubuf, map_len); + if (ret < 0) + goto unmap_rq; + bytes_read += ret; + ubuf += ret; } - /* - * bio is the err-ptr - */ - return PTR_ERR(bio); + rq->buffer = rq->data = NULL; + return 0; +unmap_rq: + blk_rq_unmap_user(rq); + return ret; } EXPORT_SYMBOL(blk_rq_map_user); @@ -2404,7 +2484,7 @@ EXPORT_SYMBOL(blk_rq_map_user); * unmapping. */ int blk_rq_map_user_iov(request_queue_t *q, struct request *rq, - struct sg_iovec *iov, int iov_count) + struct sg_iovec *iov, int iov_count, unsigned int len) { struct bio *bio; @@ -2418,10 +2498,15 @@ int blk_rq_map_user_iov(request_queue_t *q, struct request *rq, if (IS_ERR(bio)) return PTR_ERR(bio); - rq->bio = rq->biotail = bio; + if (bio->bi_size != len) { + bio_endio(bio, bio->bi_size, 0); + bio_unmap_user(bio); + return -EINVAL; + } + + bio_get(bio); blk_rq_bio_prep(q, rq, bio); rq->buffer = rq->data = NULL; - rq->data_len = bio->bi_size; return 0; } @@ -2429,23 +2514,26 @@ EXPORT_SYMBOL(blk_rq_map_user_iov); /** * blk_rq_unmap_user - unmap a request with user data - * @bio: bio to be unmapped - * @ulen: length of user buffer + * @rq: rq to be unmapped * * Description: - * Unmap a bio previously mapped by blk_rq_map_user(). + * Unmap a rq previously mapped by blk_rq_map_user(). + * rq->bio must be set to the original head of the request. */ -int blk_rq_unmap_user(struct bio *bio, unsigned int ulen) +int blk_rq_unmap_user(struct request *rq) { - int ret = 0; + struct bio *bio, *mapped_bio; - if (bio) { - if (bio_flagged(bio, BIO_USER_MAPPED)) - bio_unmap_user(bio); + while ((bio = rq->bio)) { + if (bio_flagged(bio, BIO_BOUNCED)) + mapped_bio = bio->bi_private; else - ret = bio_uncopy_user(bio); - } + mapped_bio = bio; + __blk_rq_unmap_user(mapped_bio); + rq->bio = bio->bi_next; + bio_put(bio); + } return 0; } @@ -2476,11 +2564,8 @@ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, if (rq_data_dir(rq) == WRITE) bio->bi_rw |= (1 << BIO_RW); - rq->bio = rq->biotail = bio; blk_rq_bio_prep(q, rq, bio); - rq->buffer = rq->data = NULL; - rq->data_len = len; return 0; } @@ -3495,6 +3580,7 @@ void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio) rq->hard_cur_sectors = rq->current_nr_sectors; rq->hard_nr_sectors = rq->nr_sectors = bio_sectors(bio); rq->buffer = bio_data(bio); + rq->data_len = bio->bi_size; rq->bio = rq->biotail = bio; } diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index e55a75621437..5493c2fbbab1 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -226,7 +226,6 @@ static int sg_io(struct file *file, request_queue_t *q, unsigned long start_time; int writing = 0, ret = 0; struct request *rq; - struct bio *bio; char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char cmd[BLK_MAX_CDB]; @@ -258,30 +257,6 @@ static int sg_io(struct file *file, request_queue_t *q, if (!rq) return -ENOMEM; - if (hdr->iovec_count) { - const int size = sizeof(struct sg_iovec) * hdr->iovec_count; - struct sg_iovec *iov; - - iov = kmalloc(size, GFP_KERNEL); - if (!iov) { - ret = -ENOMEM; - goto out; - } - - if (copy_from_user(iov, hdr->dxferp, size)) { - kfree(iov); - ret = -EFAULT; - goto out; - } - - ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count); - kfree(iov); - } else if (hdr->dxfer_len) - ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); - - if (ret) - goto out; - /* * fill in request structure */ @@ -294,7 +269,6 @@ static int sg_io(struct file *file, request_queue_t *q, rq->sense_len = 0; rq->cmd_type = REQ_TYPE_BLOCK_PC; - bio = rq->bio; /* * bounce this after holding a reference to the original bio, it's @@ -309,6 +283,31 @@ static int sg_io(struct file *file, request_queue_t *q, if (!rq->timeout) rq->timeout = BLK_DEFAULT_TIMEOUT; + if (hdr->iovec_count) { + const int size = sizeof(struct sg_iovec) * hdr->iovec_count; + struct sg_iovec *iov; + + iov = kmalloc(size, GFP_KERNEL); + if (!iov) { + ret = -ENOMEM; + goto out; + } + + if (copy_from_user(iov, hdr->dxferp, size)) { + kfree(iov); + ret = -EFAULT; + goto out; + } + + ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count, + hdr->dxfer_len); + kfree(iov); + } else if (hdr->dxfer_len) + ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); + + if (ret) + goto out; + rq->retries = 0; start_time = jiffies; @@ -339,7 +338,7 @@ static int sg_io(struct file *file, request_queue_t *q, hdr->sb_len_wr = len; } - if (blk_rq_unmap_user(bio, hdr->dxfer_len)) + if (blk_rq_unmap_user(rq)) ret = -EFAULT; /* may not have succeeded, but output values written to control diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 7ea0f48f8fa6..2df5cf4ec743 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2133,16 +2133,14 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, rq->timeout = 60 * HZ; bio = rq->bio; - if (rq->bio) - blk_queue_bounce(q, &rq->bio); - if (blk_execute_rq(q, cdi->disk, rq, 0)) { struct request_sense *s = rq->sense; ret = -EIO; cdi->last_sense = s->sense_key; } - if (blk_rq_unmap_user(bio, len)) + rq->bio = bio; + if (blk_rq_unmap_user(rq)) ret = -EFAULT; if (ret) diff --git a/fs/bio.c b/fs/bio.c index d91cfbf7ebc4..aa4d09bd4e71 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -560,10 +560,8 @@ struct bio *bio_copy_user(request_queue_t *q, unsigned long uaddr, break; } - if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) { - ret = -EINVAL; + if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) break; - } len -= bytes; } @@ -750,7 +748,6 @@ struct bio *bio_map_user_iov(request_queue_t *q, struct block_device *bdev, int write_to_vm) { struct bio *bio; - int len = 0, i; bio = __bio_map_user_iov(q, bdev, iov, iov_count, write_to_vm); @@ -765,18 +762,7 @@ struct bio *bio_map_user_iov(request_queue_t *q, struct block_device *bdev, */ bio_get(bio); - for (i = 0; i < iov_count; i++) - len += iov[i].iov_len; - - if (bio->bi_size == len) - return bio; - - /* - * don't support partial mappings - */ - bio_endio(bio, bio->bi_size, 0); - bio_unmap_user(bio); - return ERR_PTR(-EINVAL); + return bio; } static void __bio_unmap_user(struct bio *bio) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 7bfcde2d5578..e1c7286165ff 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -678,10 +678,11 @@ extern void __blk_stop_queue(request_queue_t *q); extern void blk_run_queue(request_queue_t *); extern void blk_start_queueing(request_queue_t *); extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); -extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int); -extern int blk_rq_unmap_user(struct bio *, unsigned int); +extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned long); +extern int blk_rq_unmap_user(struct request *); extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t); -extern int blk_rq_map_user_iov(request_queue_t *, struct request *, struct sg_iovec *, int); +extern int blk_rq_map_user_iov(request_queue_t *, struct request *, + struct sg_iovec *, int, unsigned int); extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *, int); extern void blk_execute_rq_nowait(request_queue_t *, struct gendisk *, -- cgit v1.2.3 From bb37b94c68e7b37eecea8576039ae9396ca07839 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 1 Dec 2006 10:42:33 +0100 Subject: [BLOCK] Cleanup unused variable passing - ->init_queue() does not need the elevator passed in - ->put_request() is a hot path and need not have the queue passed in - cfq_update_io_seektime() does not need cfqd passed in Signed-off-by: Jens Axboe --- block/as-iosched.c | 2 +- block/cfq-iosched.c | 9 ++++----- block/deadline-iosched.c | 2 +- block/elevator.c | 4 ++-- block/noop-iosched.c | 2 +- include/linux/elevator.h | 4 ++-- 6 files changed, 11 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/block/as-iosched.c b/block/as-iosched.c index 50b95e4c1425..00242111a457 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -1317,7 +1317,7 @@ static void as_exit_queue(elevator_t *e) /* * initialize elevator private data (as_data). */ -static void *as_init_queue(request_queue_t *q, elevator_t *e) +static void *as_init_queue(request_queue_t *q) { struct as_data *ad; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 1d9c3c70a9a0..e9019ed39b73 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1464,8 +1464,7 @@ cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic) } static void -cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic, - struct request *rq) +cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq) { sector_t sdist; u64 total; @@ -1617,7 +1616,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, } cfq_update_io_thinktime(cfqd, cic); - cfq_update_io_seektime(cfqd, cic, rq); + cfq_update_io_seektime(cic, rq); cfq_update_idle_window(cfqd, cfqq, cic); cic->last_queue = jiffies; @@ -1770,7 +1769,7 @@ static int cfq_may_queue(request_queue_t *q, int rw) /* * queue lock held here */ -static void cfq_put_request(request_queue_t *q, struct request *rq) +static void cfq_put_request(struct request *rq) { struct cfq_queue *cfqq = RQ_CFQQ(rq); @@ -1951,7 +1950,7 @@ static void cfq_exit_queue(elevator_t *e) kfree(cfqd); } -static void *cfq_init_queue(request_queue_t *q, elevator_t *e) +static void *cfq_init_queue(request_queue_t *q) { struct cfq_data *cfqd; int i; diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index b7c5b34cb7b4..6d673e938d3e 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c @@ -356,7 +356,7 @@ static void deadline_exit_queue(elevator_t *e) /* * initialize elevator private data (deadline_data). */ -static void *deadline_init_queue(request_queue_t *q, elevator_t *e) +static void *deadline_init_queue(request_queue_t *q) { struct deadline_data *dd; diff --git a/block/elevator.c b/block/elevator.c index 8ccd163254b8..c0063f345c5d 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -129,7 +129,7 @@ static struct elevator_type *elevator_get(const char *name) static void *elevator_init_queue(request_queue_t *q, struct elevator_queue *eq) { - return eq->ops->elevator_init_fn(q, eq); + return eq->ops->elevator_init_fn(q); } static void elevator_attach(request_queue_t *q, struct elevator_queue *eq, @@ -810,7 +810,7 @@ void elv_put_request(request_queue_t *q, struct request *rq) elevator_t *e = q->elevator; if (e->ops->elevator_put_req_fn) - e->ops->elevator_put_req_fn(q, rq); + e->ops->elevator_put_req_fn(rq); } int elv_may_queue(request_queue_t *q, int rw) diff --git a/block/noop-iosched.c b/block/noop-iosched.c index 79af43179421..1c3de2b9a6b5 100644 --- a/block/noop-iosched.c +++ b/block/noop-iosched.c @@ -65,7 +65,7 @@ noop_latter_request(request_queue_t *q, struct request *rq) return list_entry(rq->queuelist.next, struct request, queuelist); } -static void *noop_init_queue(request_queue_t *q, elevator_t *e) +static void *noop_init_queue(request_queue_t *q) { struct noop_data *nd; diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 2fa9f1144228..a24931d24404 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -21,11 +21,11 @@ typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *); typedef int (elevator_may_queue_fn) (request_queue_t *, int); typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, gfp_t); -typedef void (elevator_put_req_fn) (request_queue_t *, struct request *); +typedef void (elevator_put_req_fn) (struct request *); typedef void (elevator_activate_req_fn) (request_queue_t *, struct request *); typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *); -typedef void *(elevator_init_fn) (request_queue_t *, elevator_t *); +typedef void *(elevator_init_fn) (request_queue_t *); typedef void (elevator_exit_fn) (elevator_t *); struct elevator_ops -- cgit v1.2.3 From bce40a36de574376f41f1ff3c4d212a7da2a3c90 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sat, 21 Oct 2006 12:35:02 +0200 Subject: [PATCH] mmc: Add support for mmc v4 high speed mode This adds support for the high-speed modes defined by mmc v4 (assuming the host controller is up to it). On a TI sdhci controller, it improves read speed from 1.3MBps to 2.3MBps. The TI controller can only go up to 24MHz, but everything helps. Another person has taken this basic patch and used it on a Nokia 770 to get a bigger boost because that controller can run at 48MHZ. Signed-off-by: Philip Langdale Signed-off-by: Pierre Ossman --- drivers/mmc/mmc.c | 121 ++++++++++++++++++++++++++++++++++++++++++- include/linux/mmc/card.h | 8 +++ include/linux/mmc/protocol.h | 47 +++++++++++++++-- 3 files changed, 171 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 766bc54406e5..2d5b93000dee 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -4,6 +4,7 @@ * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved. + * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -953,6 +954,114 @@ static void mmc_read_csds(struct mmc_host *host) } } +static void mmc_process_ext_csds(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + + struct scatterlist sg; + + /* + * As the ext_csd is so large and mostly unused, we don't store the + * raw block in mmc_card. + */ + u8 *ext_csd; + ext_csd = kmalloc(512, GFP_KERNEL); + if (!ext_csd) { + printk("%s: could not allocate a buffer to receive the ext_csd." + "mmc v4 cards will be treated as v3.\n", + mmc_hostname(host)); + return; + } + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (mmc_card_sd(card)) + continue; + if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SEND_EXT_CSD; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 512; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, ext_csd, 512); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + switch (ext_csd[EXT_CSD_CARD_TYPE]) { + case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 52000000; + break; + case EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 26000000; + break; + default: + /* MMC v4 spec says this cannot happen */ + printk("%s: card is mmc v4 but doesn't support " + "any high-speed modes.\n", + mmc_hostname(card->host)); + mmc_card_set_bad(card); + continue; + } + + /* Activate highspeed support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_HS_TIMING << 16) | + (1 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to mmc v4 " + "high-speed mode.\n", + mmc_hostname(card->host)); + continue; + } + + mmc_card_set_highspeed(card); + } + + kfree(ext_csd); + + mmc_deselect_cards(host); +} + static void mmc_read_scrs(struct mmc_host *host) { int err; @@ -1031,8 +1140,14 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) unsigned int max_dtr = host->f_max; list_for_each_entry(card, &host->cards, node) - if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) - max_dtr = card->csd.max_dtr; + if (!mmc_card_dead(card)) { + if (mmc_card_highspeed(card)) { + if (max_dtr > card->ext_csd.hs_max_dtr) + max_dtr = card->ext_csd.hs_max_dtr; + } else if (max_dtr > card->csd.max_dtr) { + max_dtr = card->csd.max_dtr; + } + } pr_debug("%s: selected %d.%03dMHz transfer rate\n", mmc_hostname(host), @@ -1152,6 +1267,8 @@ static void mmc_setup(struct mmc_host *host) if (host->mode == MMC_MODE_SD) mmc_read_scrs(host); + else + mmc_process_ext_csds(host); } diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 991a37382a22..ce25256f80d5 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -39,6 +39,10 @@ struct mmc_csd { write_misalign:1; }; +struct mmc_ext_csd { + unsigned int hs_max_dtr; +}; + struct sd_scr { unsigned char sda_vsn; unsigned char bus_widths; @@ -62,11 +66,13 @@ struct mmc_card { #define MMC_STATE_BAD (1<<2) /* unrecognised device */ #define MMC_STATE_SDCARD (1<<3) /* is an SD card */ #define MMC_STATE_READONLY (1<<4) /* card is read-only */ +#define MMC_STATE_HIGHSPEED (1<<5) /* card is in mmc4 highspeed mode */ u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ u32 raw_scr[2]; /* raw card SCR */ struct mmc_cid cid; /* card identification */ struct mmc_csd csd; /* card specific */ + struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ struct sd_scr scr; /* extra SD information */ }; @@ -75,12 +81,14 @@ struct mmc_card { #define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD) #define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) +#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD) #define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD) #define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) +#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED) #define mmc_card_name(c) ((c)->cid.prod_name) #define mmc_card_id(c) ((c)->dev.bus_id) diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 08dec8d9e703..311b6547f561 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -25,14 +25,16 @@ #ifndef MMC_MMC_PROTOCOL_H #define MMC_MMC_PROTOCOL_H -/* Standard MMC commands (3.1) type argument response */ +/* Standard MMC commands (4.1) type argument response */ /* class 1 */ #define MMC_GO_IDLE_STATE 0 /* bc */ #define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ #define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ #define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ #define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ @@ -87,6 +89,17 @@ #define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ #define SD_APP_SEND_SCR 51 /* adtc R1 */ +/* + * MMC_SWITCH argument format: + * + * [31:26] Always 0 + * [25:24] Access Mode + * [23:16] Location of target Byte in EXT_CSD + * [15:08] Value Byte + * [07:03] Always 0 + * [02:00] Command Set + */ + /* MMC status in R1 Type @@ -230,13 +243,41 @@ struct _mmc_csd { #define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ #define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ -#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */ +#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */ +#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */ #define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ #define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ #define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ -#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */ +#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */ +#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */ + +/* + * EXT_CSD fields + */ + +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_CMD_SET_NORMAL (1<<0) +#define EXT_CSD_CMD_SET_SECURE (1<<1) +#define EXT_CSD_CMD_SET_CPSECURE (1<<2) + +#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ + +/* + * MMC_SWITCH access modes + */ +#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ +#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ /* * SD bus widths -- cgit v1.2.3 From e45a1bd20fa5b920901879e85cdf5eda21f78d7c Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sun, 29 Oct 2006 10:14:19 +0100 Subject: mmc: Add support for mmc v4 wide-bus modes This change adds support for the mmc4 4-bit wide-bus mode. The mmc4 spec defines 8-bit and 4-bit transfer modes. As we do not support any 8-bit hardware, this patch only adds support for the 4-bit mode, but it can easily be built upon when the time comes. The 4-bit mode is electrically compatible with SD's 4-bit mode but the procedure for turning it on is different. This patch implements only the essential parts of the procedure as defined by the spec. Two additional steps are recommended but not compulsory. I am documenting them here so that there's a record. 1) A bus-test mechanism is implemented using dedicated mmc commands which allow for testing the functionality of the data bus at the electrical level. This is pretty paranoid and they way the commands work is not compatible with the mmc subsystem (they don't set valid CRC values). 2) MMC v4 cards can indicate they would like to draw more than the default amount of current in wide-bus modes. We currently will never switch the card into a higher draw mode. Supposedly, allowing the card to draw more current will let it perform better, but the specs seem to indicate that the card will function correctly without the mode change. Empirical testing supports this interpretation. Signed-off-by: Philip Langdale Signed-off-by: Pierre Ossman --- drivers/mmc/mmc.c | 51 ++++++++++++++++++++++++++++++++------------ include/linux/mmc/protocol.h | 5 +++++ 2 files changed, 42 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2d5b93000dee..1593a6a632cf 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -397,23 +397,23 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) return err; /* - * Default bus width is 1 bit. - */ - host->ios.bus_width = MMC_BUS_WIDTH_1; - - /* - * We can only change the bus width of the selected - * card so therefore we have to put the handling + * We can only change the bus width of SD cards when + * they are selected so we have to put the handling * here. + * + * The card is in 1 bit mode by default so + * we only need to change if it supports the + * wider version. */ - if (host->caps & MMC_CAP_4_BIT_DATA) { + if (mmc_card_sd(card) && + (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + /* - * The card is in 1 bit mode by default so - * we only need to change if it supports the - * wider version. - */ - if (mmc_card_sd(card) && - (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + * Default bus width is 1 bit. + */ + host->ios.bus_width = MMC_BUS_WIDTH_1; + + if (host->caps & MMC_CAP_4_BIT_DATA) { struct mmc_command cmd; cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.arg = SD_BUS_WIDTH_4; @@ -1055,6 +1055,29 @@ static void mmc_process_ext_csds(struct mmc_host *host) } mmc_card_set_highspeed(card); + + /* Check for host support for wide-bus modes. */ + if (!(host->caps & MMC_CAP_4_BIT_DATA)) { + continue; + } + + /* Activate 4-bit support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BUS_WIDTH << 16) | + (EXT_CSD_BUS_WIDTH_4 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to " + "mmc v4 4-bit bus mode.\n", + mmc_hostname(card->host)); + continue; + } + + host->ios.bus_width = MMC_BUS_WIDTH_4; } kfree(ext_csd); diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 311b6547f561..45c51fd85786 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -256,6 +256,7 @@ struct _mmc_csd { * EXT_CSD fields */ +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_CARD_TYPE 196 /* RO */ @@ -270,6 +271,10 @@ struct _mmc_csd { #define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ #define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ +#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ + /* * MMC_SWITCH access modes */ -- cgit v1.2.3 From 7ccd266e676a3f0c6f8f897f58b684cac3dd1650 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 8 Nov 2006 23:03:10 +0100 Subject: mmc: Support for high speed SD cards Modern SD cards support a clock speed of 50 MHz. Make sure we test for this capability and do the song and dance required to activate it. Activating high speed support actually modifies the TRAN_SPEED field of the CSD. But as the spec says that the cards must report 50 MHz, we might as well skip re-reading the CSD. Signed-off-by: Pierre Ossman --- drivers/mmc/mmc.c | 122 +++++++++++++++++++++++++++++++++++++++++-- include/linux/mmc/card.h | 7 ++- include/linux/mmc/protocol.h | 22 ++++++++ 3 files changed, 146 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 82b7643c1654..9d190022a490 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1157,6 +1157,116 @@ static void mmc_read_scrs(struct mmc_host *host) mmc_deselect_cards(host); } +static void mmc_read_switch_caps(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + unsigned char *status; + struct scatterlist sg; + + status = kmalloc(64, GFP_KERNEL); + if (!status) { + printk(KERN_WARNING "%s: Unable to allocate buffer for " + "reading switch capabilities.\n", + mmc_hostname(host)); + return; + } + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (!mmc_card_sd(card)) + continue; + if (card->scr.sda_vsn < SCR_SPEC_VER_1) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_SWITCH; + cmd.arg = 0x00FFFFF1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, status, 64); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + if (status[13] & 0x02) + card->sw_caps.hs_max_dtr = 50000000; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_SWITCH; + cmd.arg = 0x80FFFFF1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, status, 64); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + if ((status[16] & 0xF) != 1) { + printk(KERN_WARNING "%s: Problem switching card " + "into high-speed mode!\n", + mmc_hostname(host)); + continue; + } + + mmc_card_set_highspeed(card); + } + + kfree(status); + + mmc_deselect_cards(host); +} + static unsigned int mmc_calculate_clock(struct mmc_host *host) { struct mmc_card *card; @@ -1164,9 +1274,12 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) list_for_each_entry(card, &host->cards, node) if (!mmc_card_dead(card)) { - if (mmc_card_highspeed(card)) { + if (mmc_card_highspeed(card) && mmc_card_sd(card)) { + if (max_dtr > card->sw_caps.hs_max_dtr) + max_dtr = card->sw_caps.hs_max_dtr; + } else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) { if (max_dtr > card->ext_csd.hs_max_dtr) - max_dtr = card->ext_csd.hs_max_dtr; + max_dtr = card->ext_csd.hs_max_dtr; } else if (max_dtr > card->csd.max_dtr) { max_dtr = card->csd.max_dtr; } @@ -1288,9 +1401,10 @@ static void mmc_setup(struct mmc_host *host) mmc_read_csds(host); - if (host->mode == MMC_MODE_SD) + if (host->mode == MMC_MODE_SD) { mmc_read_scrs(host); - else + mmc_read_switch_caps(host); + } else mmc_process_ext_csds(host); } diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index ce25256f80d5..d0e6a5497614 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -50,6 +50,10 @@ struct sd_scr { #define SD_SCR_BUS_WIDTH_4 (1<<2) }; +struct sd_switch_caps { + unsigned int hs_max_dtr; +}; + struct mmc_host; /* @@ -66,7 +70,7 @@ struct mmc_card { #define MMC_STATE_BAD (1<<2) /* unrecognised device */ #define MMC_STATE_SDCARD (1<<3) /* is an SD card */ #define MMC_STATE_READONLY (1<<4) /* card is read-only */ -#define MMC_STATE_HIGHSPEED (1<<5) /* card is in mmc4 highspeed mode */ +#define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */ u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ u32 raw_scr[2]; /* raw card SCR */ @@ -74,6 +78,7 @@ struct mmc_card { struct mmc_csd csd; /* card specific */ struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ struct sd_scr scr; /* extra SD information */ + struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ }; #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 45c51fd85786..2dce60c43f4b 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -82,6 +82,7 @@ /* class 8 */ /* This is basically the same command as for MMC with some quirks. */ #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ +#define SD_SWITCH 6 /* adtc [31:0] See below R1 */ /* Application commands */ #define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ @@ -100,6 +101,19 @@ * [02:00] Command Set */ +/* + * SD_SWITCH argument format: + * + * [31] Check (0) or switch (1) + * [30:24] Reserved (0) + * [23:20] Function group 6 + * [19:16] Function group 5 + * [15:12] Function group 4 + * [11:8] Function group 3 + * [7:4] Function group 2 + * [3:0] Function group 1 + */ + /* MMC status in R1 Type @@ -284,6 +298,14 @@ struct _mmc_csd { #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ +/* + * SCR field definitions + */ + +#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ +#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ +#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */ + /* * SD bus widths */ -- cgit v1.2.3 From 437052516779fea608261a50682b124315f48f01 Mon Sep 17 00:00:00 2001 From: "inaky@linux.intel.com" Date: Wed, 11 Oct 2006 20:05:58 -0700 Subject: usb/hub: allow hubs up to 31 children Current Wireless USB host hardware (Intel i1480 for example) allows up to 22 devices to connect, thus bringing up the max number of children in the WUSB Host Controller to 22 'fake' ports. Upcoming hardware might raise that limit. Makes almost no difference to go to 31, as the bit arrays are byte-aligned (plus an extra bit in general), so 22 bits fit in 4 bytes as 31 do. As well, the only other array that depends on USB_MAXCHILDREN is 'struct usb_hub->indicator'. By declaring it 'u8' instead of 'enum hub_led_mode', we reduce the size of each entry from 4 bytes (in i386) to 1, which will add as we when are doubling USB_MAXCHILDREN (with 16 the size of that array is 64 bytes, with 31 would be 128; by using u8 that goes down to 31 bytes). Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.h | 2 +- include/linux/usb.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 0f8e82a4d480..1b05994de4dc 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -229,7 +229,7 @@ struct usb_hub { unsigned resume_root_hub:1; unsigned has_indicators:1; - enum hub_led_mode indicator[USB_MAXCHILDREN]; + u8 indicator[USB_MAXCHILDREN]; struct work_struct leds; }; diff --git a/include/linux/usb.h b/include/linux/usb.h index 5482bfb3303d..e5cb1690975a 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -313,8 +313,13 @@ struct usb_bus { /* This is arbitrary. * From USB 2.0 spec Table 11-13, offset 7, a hub can * have up to 255 ports. The most yet reported is 10. + * + * Current Wireless USB host hardware (Intel i1480 for example) allows + * up to 22 devices to connect. Upcoming hardware might raise that + * limit. Because the arrays need to add a bit for hub status data, we + * do 31, so plus one evens out to four bytes. */ -#define USB_MAXCHILDREN (16) +#define USB_MAXCHILDREN (31) struct usb_tt; -- cgit v1.2.3 From 0c1ac4f25f894f9df0ffe9b912c165fb6a185a3c Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Mon, 30 Oct 2006 14:53:03 -0300 Subject: USB: makes usb_endpoint_* functions inline. We have no benefits of having the usb_endpoint_* functions as functions, but making them inline saves text and data segment sizes: text data bss dec hex filename 14893634 3108770 1108840 19111244 1239d4c vmlinux.func 14893185 3108566 1108840 19110591 1239abf vmlinux.inline This is the result of a 2.6.19-rc3 kernel compiled with GCC 4.1.1 without CONFIG_MODULES, CONFIG_CC_OPTIMIZE_FOR_SIZE, CONFIG_REGPARM options set. USB support is fully enabled (while most of the other drivers are not), and that kernel has most of the USB code ported to use the endpoint functions. That happens because a call to those functions are expensive (in terms of bytes), while the function's size is smaller or have the same 'size' of the call. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 144 ------------------------------------------------- include/linux/usb.h | 142 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 131 insertions(+), 155 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 467cb02832f3..a83c2d5065c1 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -537,138 +537,6 @@ int usb_get_current_frame_number(struct usb_device *dev) return usb_hcd_get_frame_number (dev); } -/** - * usb_endpoint_dir_in - check if the endpoint has IN direction - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type IN, otherwise it returns false. - */ -int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); -} - -/** - * usb_endpoint_dir_out - check if the endpoint has OUT direction - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type OUT, otherwise it returns false. - */ -int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); -} - -/** - * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type bulk, otherwise it returns false. - */ -int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK); -} - -/** - * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type interrupt, otherwise it returns - * false. - */ -int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_INT); -} - -/** - * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type isochronous, otherwise it returns - * false. - */ -int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_ISOC); -} - -/** - * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN - * @epd: endpoint to be checked - * - * Returns true if the endpoint has bulk transfer type and IN direction, - * otherwise it returns false. - */ -int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd)); -} - -/** - * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT - * @epd: endpoint to be checked - * - * Returns true if the endpoint has bulk transfer type and OUT direction, - * otherwise it returns false. - */ -int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd)); -} - -/** - * usb_endpoint_is_int_in - check if the endpoint is interrupt IN - * @epd: endpoint to be checked - * - * Returns true if the endpoint has interrupt transfer type and IN direction, - * otherwise it returns false. - */ -int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd)); -} - -/** - * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT - * @epd: endpoint to be checked - * - * Returns true if the endpoint has interrupt transfer type and OUT direction, - * otherwise it returns false. - */ -int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd)); -} - -/** - * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN - * @epd: endpoint to be checked - * - * Returns true if the endpoint has isochronous transfer type and IN direction, - * otherwise it returns false. - */ -int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd)); -} - -/** - * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT - * @epd: endpoint to be checked - * - * Returns true if the endpoint has isochronous transfer type and OUT direction, - * otherwise it returns false. - */ -int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd)); -} - /*-------------------------------------------------------------------*/ /* * __usb_get_extra_descriptor() finds a descriptor of specific type in the @@ -1102,18 +970,6 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor); EXPORT_SYMBOL(usb_find_device); EXPORT_SYMBOL(usb_get_current_frame_number); -EXPORT_SYMBOL_GPL(usb_endpoint_dir_in); -EXPORT_SYMBOL_GPL(usb_endpoint_dir_out); -EXPORT_SYMBOL_GPL(usb_endpoint_xfer_bulk); -EXPORT_SYMBOL_GPL(usb_endpoint_xfer_int); -EXPORT_SYMBOL_GPL(usb_endpoint_xfer_isoc); -EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_in); -EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_out); -EXPORT_SYMBOL_GPL(usb_endpoint_is_int_in); -EXPORT_SYMBOL_GPL(usb_endpoint_is_int_out); -EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_in); -EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_out); - EXPORT_SYMBOL (usb_buffer_alloc); EXPORT_SYMBOL (usb_buffer_free); diff --git a/include/linux/usb.h b/include/linux/usb.h index e5cb1690975a..e732e024a141 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -495,17 +495,137 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, /*-------------------------------------------------------------------------*/ -extern int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd); +/** + * usb_endpoint_dir_in - check if the endpoint has IN direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type IN, otherwise it returns false. + */ +static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); +} + +/** + * usb_endpoint_dir_out - check if the endpoint has OUT direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type OUT, otherwise it returns false. + */ +static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); +} + +/** + * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type bulk, otherwise it returns false. + */ +static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK); +} + +/** + * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type interrupt, otherwise it returns + * false. + */ +static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT); +} + +/** + * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type isochronous, otherwise it returns + * false. + */ +static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_ISOC); +} + +/** + * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and IN direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and OUT direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd)); +} + +/** + * usb_endpoint_is_int_in - check if the endpoint is interrupt IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and IN direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and OUT direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd)); +} + +/** + * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and IN direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and OUT direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd)); +} /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From 692a186c9d5f12d43cef28d40c25247dc4f302f0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Oct 2006 17:07:51 -0500 Subject: USB: expand autosuspend/autoresume API This patch (as814) adds usb_autopm_set_interface() to the autosuspend API. It also provides convenient wrapper routines, usb_autopm_enable() and usb_autopm_disable(), for drivers that want to specify directly whether autosuspend should be allowed. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 22 ++++++++++++++++++++++ include/linux/usb.h | 29 ++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ca0e40ed2b72..204495fa6b3d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1322,6 +1322,28 @@ int usb_autopm_get_interface(struct usb_interface *intf) } EXPORT_SYMBOL_GPL(usb_autopm_get_interface); +/** + * usb_autopm_set_interface - set a USB interface's autosuspend state + * @intf: the usb_interface whose state should be set + * + * This routine sets the autosuspend state of @intf's device according + * to @intf's usage counter, which the caller must have set previously. + * If the counter is <= 0, the device is autosuspended (if it isn't + * already suspended and if nothing else prevents the autosuspend). If + * the counter is > 0, the device is autoresumed (if it isn't already + * awake). + */ +int usb_autopm_set_interface(struct usb_interface *intf) +{ + int status; + + status = usb_autopm_do_interface(intf, 0); + // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", + // __FUNCTION__, status, intf->pm_usage_cnt); + return status; +} +EXPORT_SYMBOL_GPL(usb_autopm_set_interface); + #endif /* CONFIG_USB_SUSPEND */ static int usb_suspend(struct device *dev, pm_message_t message) diff --git a/include/linux/usb.h b/include/linux/usb.h index e732e024a141..864c6c21c21e 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -415,14 +415,37 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); /* USB autosuspend and autoresume */ #ifdef CONFIG_USB_SUSPEND +extern int usb_autopm_set_interface(struct usb_interface *intf); extern int usb_autopm_get_interface(struct usb_interface *intf); extern void usb_autopm_put_interface(struct usb_interface *intf); +static inline void usb_autopm_enable(struct usb_interface *intf) +{ + intf->pm_usage_cnt = 0; + usb_autopm_set_interface(intf); +} + +static inline void usb_autopm_disable(struct usb_interface *intf) +{ + intf->pm_usage_cnt = 1; + usb_autopm_set_interface(intf); +} + #else -#define usb_autopm_get_interface(intf) 0 -#define usb_autopm_put_interface(intf) do {} while (0) -#endif +static inline int usb_autopm_set_interface(struct usb_interface *intf) +{ return 0; } + +static inline int usb_autopm_get_interface(struct usb_interface *intf) +{ return 0; } + +static inline void usb_autopm_put_interface(struct usb_interface *intf) +{ } +static inline void usb_autopm_enable(struct usb_interface *intf) +{ } +static inline void usb_autopm_disable(struct usb_interface *intf) +{ } +#endif /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From ce3615879ae85373c03744b45b7c2d7ae5e29b2a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 20 Nov 2006 11:12:22 -0500 Subject: USB: struct usb_device: change flag to bitflag This patch (as816) changes an existing flag in the usb_device structure to a bitflag, preparing the way for more bitflags to come in the future. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 2 +- include/linux/usb.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 7729c0744886..5684d8722922 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -764,7 +764,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) err = -EINVAL; goto errout; } else { - dev->have_langid = -1; + dev->have_langid = 1; dev->string_langid = tbuf[2] | (tbuf[3]<< 8); /* always use the first langid listed */ dev_dbg (&dev->dev, "default language 0x%04x\n", diff --git a/include/linux/usb.h b/include/linux/usb.h index 864c6c21c21e..5634a2d91ec0 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -362,7 +362,7 @@ struct usb_device { u8 portnum; /* Parent port number (origin 1) */ u8 level; /* Number of USB hub ancestors */ - int have_langid; /* whether string_langid is valid */ + unsigned have_langid:1; /* whether string_langid is valid */ int string_langid; /* language ID for strings */ /* static strings from the device */ -- cgit v1.2.3 From ee49fb5dc89d34f1794ac9362fa97c1a640f7ddd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 22 Nov 2006 16:55:54 -0500 Subject: USB: keep count of unsuspended children This patch (as818b) simplifies autosuspend processing by keeping track of the number of unsuspended children of each USB hub. This will permit us to avoid a good deal of unnecessary work all the time; we will no longer have to create a bunch of workqueue entries to carry out autosuspend requests, only to have them fail because one of the hub's children isn't suspended. The basic idea is simple. There already is a usage counter in the usb_device structure for preventing autosuspends. The patch just increments that counter for every unsuspended child. There's only one tricky part: When a device disconnects we need to remember whether it was suspended at the time (leave the counter alone) or not (decrement the counter). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 34 +++++++++++++++++++++++----------- drivers/usb/core/hub.c | 14 ++++++++++++++ include/linux/usb.h | 1 + 3 files changed, 38 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 40c1bf09b2b7..0fa15bd62c48 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1048,7 +1048,7 @@ int usb_suspend_both(struct usb_device *udev, pm_message_t msg) /* If the suspend succeeded, propagate it up the tree */ } else if (parent) - usb_autosuspend_device(parent, 0); + usb_autosuspend_device(parent, 1); // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); return status; @@ -1096,9 +1096,25 @@ int usb_resume_both(struct usb_device *udev) /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { if (parent) { - usb_pm_lock(parent); - parent->auto_pm = 1; - status = usb_resume_both(parent); + status = usb_autoresume_device(parent, 1); + if (status == 0) { + status = usb_resume_device(udev); + if (status) { + usb_autosuspend_device(parent, 1); + + /* It's possible usb_resume_device() + * failed after the port was + * unsuspended, causing udev to be + * logically disconnected. We don't + * want usb_disconnect() to autosuspend + * the parent again, so tell it that + * udev disconnected while still + * suspended. */ + if (udev->state == + USB_STATE_NOTATTACHED) + udev->discon_suspended = 1; + } + } } else { /* We can't progagate beyond the USB subsystem, @@ -1107,11 +1123,9 @@ int usb_resume_both(struct usb_device *udev) if (udev->dev.parent->power.power_state.event != PM_EVENT_ON) status = -EHOSTUNREACH; - } - if (status == 0) - status = usb_resume_device(udev); - if (parent) - usb_pm_unlock(parent); + else + status = usb_resume_device(udev); + } } else { /* Needed only for setting udev->dev.power.power_state.event @@ -1119,8 +1133,6 @@ int usb_resume_both(struct usb_device *udev) status = usb_resume_device(udev); } - /* Now the parent won't suspend until we are finished */ - if (status == 0 && udev->actconfig) { for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 46df5e60764b..e46d38b18249 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1039,6 +1039,8 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev) if (udev->children[i]) recursively_mark_NOTATTACHED(udev->children[i]); } + if (udev->state == USB_STATE_SUSPENDED) + udev->discon_suspended = 1; udev->state = USB_STATE_NOTATTACHED; } @@ -1228,6 +1230,14 @@ void usb_disconnect(struct usb_device **pdev) *pdev = NULL; spin_unlock_irq(&device_state_lock); + /* Decrement the parent's count of unsuspended children */ + if (udev->parent) { + usb_pm_lock(udev); + if (!udev->discon_suspended) + usb_autosuspend_device(udev->parent, 1); + usb_pm_unlock(udev); + } + put_device(&udev->dev); } @@ -1356,6 +1366,10 @@ static int __usb_new_device(void *void_data) goto fail; } + /* Increment the parent's count of unsuspended children */ + if (udev->parent) + usb_autoresume_device(udev->parent, 1); + exit: module_put(THIS_MODULE); return err; diff --git a/include/linux/usb.h b/include/linux/usb.h index 5634a2d91ec0..0cd73edeef13 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -362,6 +362,7 @@ struct usb_device { u8 portnum; /* Parent port number (origin 1) */ u8 level; /* Number of USB hub ancestors */ + unsigned discon_suspended:1; /* Disconnected while suspended */ unsigned have_langid:1; /* whether string_langid is valid */ int string_langid; /* language ID for strings */ -- cgit v1.2.3 From e65e5fb5ceb02aaea7b65bf8b3b0d0c9057718b6 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 7 Nov 2006 18:21:21 +1100 Subject: PCI: Make some MSI-X #defines generic Move some MSI-X #defines into pci_regs.h so they can be used outside of drivers/pci. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.h | 8 -------- include/linux/pci_regs.h | 6 ++++++ 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index f0cca1772f9c..3898f5237144 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -6,14 +6,6 @@ #ifndef MSI_H #define MSI_H -/* - * MSI-X Address Register - */ -#define PCI_MSIX_FLAGS_QSIZE 0x7FF -#define PCI_MSIX_FLAGS_ENABLE (1 << 15) -#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) -#define PCI_MSIX_FLAGS_BITMASK (1 << 0) - #define PCI_MSIX_ENTRY_SIZE 16 #define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0 #define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4 diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index c321316f1bc7..064b1dc71c22 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -292,6 +292,12 @@ #define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ #define PCI_MSI_MASK_BIT 16 /* Mask bits register */ +/* MSI-X registers (these are at offset PCI_MSI_FLAGS) */ +#define PCI_MSIX_FLAGS_QSIZE 0x7FF +#define PCI_MSIX_FLAGS_ENABLE (1 << 15) +#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) +#define PCI_MSIX_FLAGS_BITMASK (1 << 0) + /* CompactPCI Hotswap Register */ #define PCI_CHSWP_CSR 2 /* Control and Status Register */ -- cgit v1.2.3 From a2302c68d923537436b1114aa207787c1a31bd50 Mon Sep 17 00:00:00 2001 From: John Keller Date: Wed, 4 Oct 2006 16:49:52 -0500 Subject: Altix: Initial ACPI support - ROM shadowing. Support a shadowed ROM when running with an ACPI capable PROM. Define a new dev.resource flag IORESOURCE_ROM_BIOS_COPY to describe the case of a BIOS shadowed ROM, which can then be used to avoid pci_map_rom() making an unneeded call to pci_enable_rom(). Signed-off-by: John Keller Signed-off-by: Greg Kroah-Hartman --- arch/ia64/sn/kernel/io_acpi_init.c | 33 +++++++++++++++++++++++++++++++++ arch/ia64/sn/kernel/io_common.c | 5 +++-- arch/ia64/sn/kernel/io_init.c | 3 +++ drivers/pci/rom.c | 9 ++++++--- include/linux/ioport.h | 1 + 5 files changed, 46 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c index a9dc36901b19..99d7f278612a 100644 --- a/arch/ia64/sn/kernel/io_acpi_init.c +++ b/arch/ia64/sn/kernel/io_acpi_init.c @@ -169,6 +169,39 @@ sn_acpi_bus_fixup(struct pci_bus *bus) } } +/* + * sn_acpi_slot_fixup - Perform any SN specific slot fixup. + * At present there does not appear to be + * any generic way to handle a ROM image + * that has been shadowed by the PROM, so + * we pass a pointer to it within the + * pcidev_info structure. + */ + +void +sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) +{ + void __iomem *addr; + size_t size; + + if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) { + /* + * A valid ROM image exists and has been shadowed by the + * PROM. Setup the pci_dev ROM resource to point to + * the shadowed copy. + */ + size = dev->resource[PCI_ROM_RESOURCE].end - + dev->resource[PCI_ROM_RESOURCE].start; + addr = + ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE], + size); + dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) addr; + dev->resource[PCI_ROM_RESOURCE].end = + (unsigned long) addr + size; + dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY; + } +} + static struct acpi_driver acpi_sn_hubdev_driver = { .name = "SGI HUBDEV Driver", .ids = "SGIHUB,SGITIO", diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c index 12531de6754c..d4dd8f4b6b8d 100644 --- a/arch/ia64/sn/kernel/io_common.c +++ b/arch/ia64/sn/kernel/io_common.c @@ -286,9 +286,10 @@ void sn_pci_fixup_slot(struct pci_dev *dev) list_add_tail(&pcidev_info->pdi_list, &(SN_PLATFORM_DATA(dev->bus)->pcidev_info)); - if (!SN_ACPI_BASE_SUPPORT()) + if (SN_ACPI_BASE_SUPPORT()) + sn_acpi_slot_fixup(dev, pcidev_info); + else sn_more_slot_fixup(dev, pcidev_info); - /* * Using the PROMs values for the PCI host bus, get the Linux * PCI host_pci_dev struct and set up host bus linkages diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 990224a44121..9ad843e0383b 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -210,6 +210,9 @@ sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) dev->resource[idx].parent = &ioport_resource; else dev->resource[idx].parent = &iomem_resource; + /* If ROM, mark as shadowed in PROM */ + if (idx == PCI_ROM_RESOURCE) + dev->resource[idx].flags |= IORESOURCE_ROM_BIOS_COPY; } /* Create a pci_window in the pci_controller struct for * each device resource. diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index e1dcefc69bb4..d087e0817715 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -81,7 +81,8 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) start = (loff_t)0xC0000; *size = 0x20000; /* cover C000:0 through E000:0 */ } else { - if (res->flags & IORESOURCE_ROM_COPY) { + if (res->flags & + (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) { *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); return (void __iomem *)(unsigned long) pci_resource_start(pdev, PCI_ROM_RESOURCE); @@ -165,7 +166,8 @@ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size) if (!rom) return NULL; - if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW)) + if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW | + IORESOURCE_ROM_BIOS_COPY)) return rom; res->start = (unsigned long)kmalloc(*size, GFP_KERNEL); @@ -191,7 +193,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) { struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; - if (res->flags & IORESOURCE_ROM_COPY) + if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) return; iounmap(rom); @@ -215,6 +217,7 @@ void pci_remove_rom(struct pci_dev *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | + IORESOURCE_ROM_BIOS_COPY | IORESOURCE_ROM_COPY))) pci_disable_rom(pdev); } diff --git a/include/linux/ioport.h b/include/linux/ioport.h index d42c83399071..cf8696d4a138 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -89,6 +89,7 @@ struct resource_list { #define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */ #define IORESOURCE_ROM_SHADOW (1<<1) /* ROM is copy at C000:0 */ #define IORESOURCE_ROM_COPY (1<<2) /* ROM is alloc'd copy, resource field overlaid */ +#define IORESOURCE_ROM_BIOS_COPY (1<<3) /* ROM is BIOS copy, resource field overlaid */ /* PC/ISA/whatever - the normal PC address spaces: IO and memory */ extern struct resource ioport_resource; -- cgit v1.2.3 From bae94d02371c402408a4edfb95e71e88dbd3e973 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 22 Nov 2006 12:40:31 -0800 Subject: PCI: switch pci_{enable,disable}_device() to be nestable Changes the pci_{enable,disable}_device() functions to work in a nested basis, so that eg, three calls to enable_device() require three calls to disable_device(). The reason for this is to simplify PCI drivers for multi-interface/capability devices. These are devices that cram more than one interface in a single function. A relevant example of that is the Wireless [USB] Host Controller Interface (similar to EHCI) [see http://www.intel.com/technology/comms/wusb/whci.htm]. In these kind of devices, multiple interfaces are accessed through a single bar and IRQ line. For that, the drivers map only the smallest area of the bar to access their register banks and use shared IRQ handlers. However, because the order at which those drivers load cannot be known ahead of time, the sequence in which the calls to pci_enable_device() and pci_disable_device() cannot be predicted. Thus: 1. driverA starts pci_enable_device() 2. driverB starts pci_enable_device() 3. driverA shutdown pci_disable_device() 4. driverB shutdown pci_disable_device() between steps 3 and 4, driver B would loose access to it's device, even if it didn't intend to. By using this modification, the device won't be disabled until all the callers to enable() have called disable(). This is implemented by replacing 'struct pci_dev->is_enabled' from a bitfield to an atomic use count. Each caller to enable increments it, each caller to disable decrements it. When the count increments from 0 to 1, __pci_enable_device() is called to actually enable the device. When it drops to zero, pci_disable_device() actually does the disabling. We keep the backend __pci_enable_device() for pci_default_resume() to use and also change the sysfs method implementation, so that userspace enabling/disabling the device doesn't disable it one time too much. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 4 ++-- drivers/pci/pci-sysfs.c | 33 +++++++++++++++++++++------------ drivers/pci/pci.c | 40 +++++++++++++++++++++++++++++++++------- drivers/pci/pci.h | 1 + include/linux/pci.h | 3 ++- 5 files changed, 59 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 84ec9c8f6703..e5ae3a0c13bb 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -329,8 +329,8 @@ static int pci_default_resume(struct pci_dev *pci_dev) /* restore the PCI config space */ pci_restore_state(pci_dev); /* if the device was enabled before suspend, reenable */ - if (pci_dev->is_enabled) - retval = pci_enable_device(pci_dev); + if (atomic_read(&pci_dev->enable_cnt)) + retval = __pci_enable_device(pci_dev); /* if the device was busmaster before the suspend, make it busmaster again */ if (pci_dev->is_busmaster) pci_set_master(pci_dev); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index f952bfea48a6..7a94076752d0 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -42,7 +42,6 @@ pci_config_attr(subsystem_vendor, "0x%04x\n"); pci_config_attr(subsystem_device, "0x%04x\n"); pci_config_attr(class, "0x%06x\n"); pci_config_attr(irq, "%u\n"); -pci_config_attr(is_enabled, "%u\n"); static ssize_t broken_parity_status_show(struct device *dev, struct device_attribute *attr, @@ -112,26 +111,36 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), (u8)(pci_dev->class)); } -static ssize_t -is_enabled_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + +static ssize_t is_enabled_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { + ssize_t result = -EINVAL; struct pci_dev *pdev = to_pci_dev(dev); - int retval = 0; /* this can crash the machine when done on the "wrong" device */ if (!capable(CAP_SYS_ADMIN)) return count; - if (*buf == '0') - pci_disable_device(pdev); + if (*buf == '0') { + if (atomic_read(&pdev->enable_cnt) != 0) + pci_disable_device(pdev); + else + result = -EIO; + } else if (*buf == '1') + result = pci_enable_device(pdev); + + return result < 0 ? result : count; +} - if (*buf == '1') - retval = pci_enable_device(pdev); +static ssize_t is_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pci_dev *pdev; - if (retval) - return retval; - return count; + pdev = to_pci_dev (dev); + return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt)); } static ssize_t diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 427991741cf3..5a14b73cf3a1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -612,29 +612,50 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) } /** - * pci_enable_device - Initialize device before it's used by a driver. + * __pci_enable_device - Initialize device before it's used by a driver. * @dev: PCI device to be initialized * * Initialize device before it's used by a driver. Ask low-level code * to enable I/O and memory. Wake up the device if it was suspended. * Beware, this function can fail. + * + * Note this function is a backend and is not supposed to be called by + * normal code, use pci_enable_device() instead. */ int -pci_enable_device(struct pci_dev *dev) +__pci_enable_device(struct pci_dev *dev) { int err; - if (dev->is_enabled) - return 0; - err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); if (err) return err; pci_fixup_device(pci_fixup_enable, dev); - dev->is_enabled = 1; return 0; } +/** + * pci_enable_device - Initialize device before it's used by a driver. + * @dev: PCI device to be initialized + * + * Initialize device before it's used by a driver. Ask low-level code + * to enable I/O and memory. Wake up the device if it was suspended. + * Beware, this function can fail. + * + * Note we don't actually enable the device many times if we call + * this function repeatedly (we just increment the count). + */ +int pci_enable_device(struct pci_dev *dev) +{ + int result; + if (atomic_add_return(1, &dev->enable_cnt) > 1) + return 0; /* already enabled */ + result = __pci_enable_device(dev); + if (result < 0) + atomic_dec(&dev->enable_cnt); + return result; +} + /** * pcibios_disable_device - disable arch specific PCI resources for device dev * @dev: the PCI device to disable @@ -651,12 +672,18 @@ void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {} * * Signal to the system that the PCI device is not in use by the system * anymore. This only involves disabling PCI bus-mastering, if active. + * + * Note we don't actually disable the device until all callers of + * pci_device_enable() have called pci_device_disable(). */ void pci_disable_device(struct pci_dev *dev) { u16 pci_command; + if (atomic_sub_return(1, &dev->enable_cnt) != 0) + return; + if (dev->msi_enabled) disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), PCI_CAP_ID_MSI); @@ -672,7 +699,6 @@ pci_disable_device(struct pci_dev *dev) dev->is_busmaster = 0; pcibios_disable_device(dev); - dev->is_enabled = 0; } /** diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 6bf327db5c5e..398852f526a6 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,5 +1,6 @@ /* Functions internal to the PCI core code */ +extern int __must_check __pci_enable_device(struct pci_dev *); extern int pci_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); diff --git a/include/linux/pci.h b/include/linux/pci.h index 09be0f81b27b..01c707261f9c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -51,6 +51,7 @@ #include #include #include +#include #include /* File state for mmap()s on /proc/bus/pci/X/Y */ @@ -159,7 +160,6 @@ struct pci_dev { unsigned int transparent:1; /* Transparent PCI bridge */ unsigned int multifunction:1;/* Part of multi-function device */ /* keep track of device state */ - unsigned int is_enabled:1; /* pci_enable_device has been called */ unsigned int is_busmaster:1; /* device is busmaster */ unsigned int no_msi:1; /* device may not use msi */ unsigned int no_d1d2:1; /* only allow d0 or d3 */ @@ -167,6 +167,7 @@ struct pci_dev { unsigned int broken_parity_status:1; /* Device generates false positive parity */ unsigned int msi_enabled:1; unsigned int msix_enabled:1; + atomic_t enable_cnt; /* pci_enable_device has been called */ u32 saved_config_space[16]; /* config space saved at suspend time */ struct hlist_head saved_cap_space; -- cgit v1.2.3 From 3b59d52d8c7925e7a9a396f2e31a66eb060c6c37 Mon Sep 17 00:00:00 2001 From: Jason Gaston Date: Wed, 22 Nov 2006 15:15:08 -0800 Subject: PCI: irq: irq and pci_ids patch for Intel ICH9 This updated patch adds the Intel ICH9 LPC and SMBus Controller DID's. Signed-off-by: Jason Gaston Signed-off-by: Greg Kroah-Hartman --- arch/i386/pci/irq.c | 6 ++++++ include/linux/pci_ids.h | 7 +++++++ 2 files changed, 13 insertions(+) (limited to 'include/linux') diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 69163998adeb..e65551cd8216 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -543,6 +543,12 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route case PCI_DEVICE_ID_INTEL_ICH8_2: case PCI_DEVICE_ID_INTEL_ICH8_3: case PCI_DEVICE_ID_INTEL_ICH8_4: + case PCI_DEVICE_ID_INTEL_ICH9_0: + case PCI_DEVICE_ID_INTEL_ICH9_1: + case PCI_DEVICE_ID_INTEL_ICH9_2: + case PCI_DEVICE_ID_INTEL_ICH9_3: + case PCI_DEVICE_ID_INTEL_ICH9_4: + case PCI_DEVICE_ID_INTEL_ICH9_5: r->name = "PIIX/ICH"; r->get = pirq_piix_get; r->set = pirq_piix_set; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index fa4e1d799782..e060a7637947 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2211,6 +2211,13 @@ #define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 #define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e #define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 +#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2911 +#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 +#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 +#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 +#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2915 +#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 -- cgit v1.2.3 From 116af378201ef793424cd10508ccf18b06d8a021 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 25 Oct 2006 13:44:59 +1000 Subject: Driver core: add notification of bus events I finally did as you suggested and added the notifier to the struct bus_type itself. There are still problems to be expected is something attaches to a bus type where the code can hook in different struct device sub-classes (which is imho a big bogosity but I won't even try to argue that case now) but it will solve nicely a number of issues I've had so far. That also means that clients interested in registering for such notifications have to do it before devices are added and after bus types are registered. Fortunately, most bus types that matter for the various usage scenarios I have in mind are registerd at postcore_initcall time, which means I have a really nice spot at arch_initcall time to add my notifiers. There are 4 notifications provided. Device being added (before hooked to the bus) and removed (failure of previous case or after being unhooked from the bus), along with driver being bound to a device and about to be unbound. The usage I have for these are: - The 2 first ones are used to maintain a struct device_ext that is hooked to struct device.firmware_data. This structure contains for now a pointer to the Open Firmware node related to the device (if any), the NUMA node ID (for quick access to it) and the DMA operations pointers & iommu table instance for DMA to/from this device. For bus types I own (like IBM VIO or EBUS), I just maintain that structure directly from the bus code when creating the devices. But for bus types managed by generic code like PCI or platform (actually, of_platform which is a variation of platform linked to Open Firmware device-tree), I need this notifier. - The other two ones have a completely different usage scenario. I have cases where multiple devices and their drivers depend on each other. For example, the IBM EMAC network driver needs to attach to a MAL DMA engine which is a separate device, and a PHY interface which is also a separate device. They are all of_platform_device's (well, about to be with my upcoming patches) but there is no say in what precise order the core will "probe" them and instanciate the various modules. The solution I found for that is to have the drivers for emac to use multithread_probe, and wait for a driver to be bound to the target MAL and PHY control devices (the device-tree contains reference to the MAL and PHY interface nodes, which I can then match to of_platform_devices). Right now, I've been polling, but with that notifier, I can more cleanly wait (with a timeout of course). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 14 ++++++++++++++ drivers/base/core.c | 12 ++++++++++++ drivers/base/dd.c | 10 ++++++++++ include/linux/device.h | 25 +++++++++++++++++++++++++ 4 files changed, 61 insertions(+) (limited to 'include/linux') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 7d8a7ce73fb3..ed3e8a2be64a 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -724,6 +724,8 @@ int bus_register(struct bus_type * bus) { int retval; + BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier); + retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name); if (retval) goto out; @@ -782,6 +784,18 @@ void bus_unregister(struct bus_type * bus) subsystem_unregister(&bus->subsys); } +int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&bus->bus_notifier, nb); +} +EXPORT_SYMBOL_GPL(bus_register_notifier); + +int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&bus->bus_notifier, nb); +} +EXPORT_SYMBOL_GPL(bus_unregister_notifier); + int __init buses_init(void) { return subsystem_register(&bus_subsys); diff --git a/drivers/base/core.c b/drivers/base/core.c index 002fde46d38d..d4f35d8902a2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -428,6 +429,11 @@ int device_add(struct device *dev) if (platform_notify) platform_notify(dev); + /* notify clients of device entry (new way) */ + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_ADD_DEVICE, dev); + dev->uevent_attr.attr.name = "uevent"; dev->uevent_attr.attr.mode = S_IWUSR; if (dev->driver) @@ -504,6 +510,9 @@ int device_add(struct device *dev) BusError: device_pm_remove(dev); PMError: + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_DEL_DEVICE, dev); device_remove_groups(dev); GroupError: device_remove_attrs(dev); @@ -622,6 +631,9 @@ void device_del(struct device * dev) */ if (platform_notify_remove) platform_notify_remove(dev); + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_DEL_DEVICE, dev); bus_remove_device(dev); device_pm_remove(dev); kobject_uevent(&dev->kobj, KOBJ_REMOVE); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index c5d6bb4290ad..9c88b1e34bc3 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -52,6 +52,11 @@ int device_bind_driver(struct device *dev) pr_debug("bound device '%s' to driver '%s'\n", dev->bus_id, dev->driver->name); + + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_BOUND_DRIVER, dev); + klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, kobject_name(&dev->kobj)); @@ -288,6 +293,11 @@ static void __device_release_driver(struct device * dev) sysfs_remove_link(&dev->kobj, "driver"); klist_remove(&dev->knode_driver); + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_UNBIND_DRIVER, + dev); + if (dev->bus && dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) diff --git a/include/linux/device.h b/include/linux/device.h index 9d4f6a963936..b00e02711393 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -42,6 +42,8 @@ struct bus_type { struct klist klist_devices; struct klist klist_drivers; + struct blocking_notifier_head bus_notifier; + struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; struct driver_attribute * drv_attrs; @@ -75,6 +77,29 @@ int __must_check bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *)); +/* + * Bus notifiers: Get notified of addition/removal of devices + * and binding/unbinding of drivers to devices. + * In the long run, it should be a replacement for the platform + * notify hooks. + */ +struct notifier_block; + +extern int bus_register_notifier(struct bus_type *bus, + struct notifier_block *nb); +extern int bus_unregister_notifier(struct bus_type *bus, + struct notifier_block *nb); + +/* All 4 notifers below get called with the target struct device * + * as an argument. Note that those functions are likely to be called + * with the device semaphore held in the core, so be careful. + */ +#define BUS_NOTIFY_ADD_DEVICE 0x00000001 /* device added */ +#define BUS_NOTIFY_DEL_DEVICE 0x00000002 /* device removed */ +#define BUS_NOTIFY_BOUND_DRIVER 0x00000003 /* driver bound to device */ +#define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be + unbound */ + /* driverfs interface for exporting bus attributes */ struct bus_attribute { -- cgit v1.2.3 From f0ee61a6cecd100301a60d99feb187776533b2a2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 23 Oct 2006 10:40:54 -0700 Subject: Driver Core: Move virtual_device_parent() to core.c It doesn't need to be global or in device.h Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 17 ----------------- drivers/base/core.c | 17 +++++++++++++++++ include/linux/device.h | 2 -- 3 files changed, 17 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/class.c b/drivers/base/class.c index 0ff267a248db..2e705f6abb4c 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -893,23 +893,6 @@ void class_interface_unregister(struct class_interface *class_intf) class_put(parent); } -int virtual_device_parent(struct device *dev) -{ - if (!dev->class) - return -ENODEV; - - if (!dev->class->virtual_dir) { - static struct kobject *virtual_dir = NULL; - - if (!virtual_dir) - virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); - dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); - } - - dev->kobj.parent = dev->class->virtual_dir; - return 0; -} - int __init classes_init(void) { int retval; diff --git a/drivers/base/core.c b/drivers/base/core.c index d4f35d8902a2..dbcd40b987d2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -384,6 +384,23 @@ void device_initialize(struct device *dev) device_init_wakeup(dev, 0); } +static int virtual_device_parent(struct device *dev) +{ + if (!dev->class) + return -ENODEV; + + if (!dev->class->virtual_dir) { + static struct kobject *virtual_dir = NULL; + + if (!virtual_dir) + virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); + dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); + } + + dev->kobj.parent = dev->class->virtual_dir; + return 0; +} + /** * device_add - add device to device hierarchy. * @dev: device. diff --git a/include/linux/device.h b/include/linux/device.h index b00e02711393..00b29e0c5ce0 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -440,8 +440,6 @@ extern struct device *device_create(struct class *cls, struct device *parent, __attribute__((format(printf,4,5))); extern void device_destroy(struct class *cls, dev_t devt); -extern int virtual_device_parent(struct device *dev); - /* * Platform "fixup" functions - allow the platform to have their say * about devices and actions that the general device layer doesn't -- cgit v1.2.3 From 94fbcded4ea0dc14cbfb222a5c68372f150d1476 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Jul 2006 16:16:04 -0700 Subject: Driver core: change misc class_devices to be real devices This also ment that some of the misc drivers had to also be fixed up as they were assuming the device was a class_device. Signed-off-by: Greg Kroah-Hartman --- drivers/char/hw_random/core.c | 38 +++++++++++++++++++------------------- drivers/char/misc.c | 13 ++++--------- drivers/char/tpm/tpm.c | 2 +- drivers/input/serio/serio_raw.c | 2 +- include/linux/miscdevice.h | 5 ++--- 5 files changed, 27 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 154a81d328c1..ebace201bec6 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -162,7 +162,8 @@ static struct miscdevice rng_miscdev = { }; -static ssize_t hwrng_attr_current_store(struct class_device *class, +static ssize_t hwrng_attr_current_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) { int err; @@ -192,7 +193,8 @@ static ssize_t hwrng_attr_current_store(struct class_device *class, return err ? : len; } -static ssize_t hwrng_attr_current_show(struct class_device *class, +static ssize_t hwrng_attr_current_show(struct device *dev, + struct device_attribute *attr, char *buf) { int err; @@ -210,7 +212,8 @@ static ssize_t hwrng_attr_current_show(struct class_device *class, return ret; } -static ssize_t hwrng_attr_available_show(struct class_device *class, +static ssize_t hwrng_attr_available_show(struct device *dev, + struct device_attribute *attr, char *buf) { int err; @@ -234,20 +237,18 @@ static ssize_t hwrng_attr_available_show(struct class_device *class, return ret; } -static CLASS_DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, - hwrng_attr_current_show, - hwrng_attr_current_store); -static CLASS_DEVICE_ATTR(rng_available, S_IRUGO, - hwrng_attr_available_show, - NULL); +static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, + hwrng_attr_current_show, + hwrng_attr_current_store); +static DEVICE_ATTR(rng_available, S_IRUGO, + hwrng_attr_available_show, + NULL); static void unregister_miscdev(void) { - class_device_remove_file(rng_miscdev.class, - &class_device_attr_rng_available); - class_device_remove_file(rng_miscdev.class, - &class_device_attr_rng_current); + device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available); + device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); misc_deregister(&rng_miscdev); } @@ -258,20 +259,19 @@ static int register_miscdev(void) err = misc_register(&rng_miscdev); if (err) goto out; - err = class_device_create_file(rng_miscdev.class, - &class_device_attr_rng_current); + err = device_create_file(rng_miscdev.this_device, + &dev_attr_rng_current); if (err) goto err_misc_dereg; - err = class_device_create_file(rng_miscdev.class, - &class_device_attr_rng_available); + err = device_create_file(rng_miscdev.this_device, + &dev_attr_rng_available); if (err) goto err_remove_current; out: return err; err_remove_current: - class_device_remove_file(rng_miscdev.class, - &class_device_attr_rng_current); + device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); err_misc_dereg: misc_deregister(&rng_miscdev); goto out; diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 62ebe09656e3..7a484fc7cb9e 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -169,11 +169,6 @@ fail: return err; } -/* - * TODO for 2.7: - * - add a struct kref to struct miscdevice and make all usages of - * them dynamic. - */ static struct class *misc_class; static const struct file_operations misc_fops = { @@ -228,10 +223,10 @@ int misc_register(struct miscdevice * misc) misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); dev = MKDEV(MISC_MAJOR, misc->minor); - misc->class = class_device_create(misc_class, NULL, dev, misc->dev, + misc->this_device = device_create(misc_class, misc->parent, dev, "%s", misc->name); - if (IS_ERR(misc->class)) { - err = PTR_ERR(misc->class); + if (IS_ERR(misc->this_device)) { + err = PTR_ERR(misc->this_device); goto out; } @@ -264,7 +259,7 @@ int misc_deregister(struct miscdevice * misc) down(&misc_sem); list_del(&misc->list); - class_device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); + device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); } diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 6ad2d3bb945c..6e1329d404d2 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1130,7 +1130,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); chip->vendor.miscdev.name = devname; - chip->vendor.miscdev.dev = dev; + chip->vendor.miscdev.parent = dev; chip->dev = get_device(dev); if (misc_register(&chip->vendor.miscdev)) { diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index ba2a2035d648..7c8d0399ae82 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -297,7 +297,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) serio_raw->dev.minor = PSMOUSE_MINOR; serio_raw->dev.name = serio_raw->name; - serio_raw->dev.dev = &serio->dev; + serio_raw->dev.parent = &serio->dev; serio_raw->dev.fops = &serio_raw_fops; err = misc_register(&serio_raw->dev); diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index b03cfb91e228..326da7d500c7 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -31,15 +31,14 @@ #define HPET_MINOR 228 struct device; -struct class_device; struct miscdevice { int minor; const char *name; const struct file_operations *fops; struct list_head list; - struct device *dev; - struct class_device *class; + struct device *parent; + struct device *this_device; }; extern int misc_register(struct miscdevice * misc); -- cgit v1.2.3 From 01107d343076c34b9e1ce5d073292bd7f3097fda Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 7 Aug 2006 22:19:37 -0700 Subject: Driver core: convert tty core to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Also fixes up the isdn drivers that were putting something in the class device's directory. Signed-off-by: Greg Kroah-Hartman --- drivers/char/tty_io.c | 19 ++++++++++--------- drivers/isdn/gigaset/common.c | 2 +- drivers/isdn/gigaset/gigaset.h | 2 +- drivers/isdn/gigaset/interface.c | 10 +++++----- drivers/isdn/gigaset/proc.c | 19 ++++++++++--------- include/linux/tty.h | 5 ++--- 6 files changed, 29 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e90ea39c7c4b..50dc49205a23 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -3612,7 +3612,8 @@ static struct class *tty_class; * This field is optional, if there is no known struct device * for this tty device it can be set to NULL safely. * - * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). + * Returns a pointer to the struct device for this tty device + * (or ERR_PTR(-EFOO) on error). * * This call is required to be made to register an individual tty device * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If @@ -3622,8 +3623,8 @@ static struct class *tty_class; * Locking: ?? */ -struct class_device *tty_register_device(struct tty_driver *driver, - unsigned index, struct device *device) +struct device *tty_register_device(struct tty_driver *driver, unsigned index, + struct device *device) { char name[64]; dev_t dev = MKDEV(driver->major, driver->minor_start) + index; @@ -3639,7 +3640,7 @@ struct class_device *tty_register_device(struct tty_driver *driver, else tty_line_name(driver, index, name); - return class_device_create(tty_class, NULL, dev, device, "%s", name); + return device_create(tty_class, device, dev, name); } /** @@ -3655,7 +3656,7 @@ struct class_device *tty_register_device(struct tty_driver *driver, void tty_unregister_device(struct tty_driver *driver, unsigned index) { - class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); + device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); } EXPORT_SYMBOL(tty_register_device); @@ -3895,20 +3896,20 @@ static int __init tty_init(void) if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), "console"); #ifdef CONFIG_UNIX98_PTYS cdev_init(&ptmx_cdev, &ptmx_fops); if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), "ptmx"); #endif #ifdef CONFIG_VT @@ -3916,7 +3917,7 @@ static int __init tty_init(void) if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), "tty0"); vty_init(); #endif diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 5800beeebb85..defd5743dba6 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -702,7 +702,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, cs->open_count = 0; cs->dev = NULL; cs->tty = NULL; - cs->class = NULL; + cs->tty_dev = NULL; cs->cidmode = cidmode != 0; //if(onechannel) { //FIXME diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 884bd72c1bf4..06298cc52bf5 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -444,7 +444,7 @@ struct cardstate { struct gigaset_driver *driver; unsigned minor_index; struct device *dev; - struct class_device *class; + struct device *tty_dev; const struct gigaset_ops *ops; diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 596f3aebe2f7..7edea015867e 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -625,13 +625,13 @@ void gigaset_if_init(struct cardstate *cs) return; tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs); - cs->class = tty_register_device(drv->tty, cs->minor_index, NULL); + cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL); - if (!IS_ERR(cs->class)) - class_set_devdata(cs->class, cs); + if (!IS_ERR(cs->tty_dev)) + dev_set_drvdata(cs->tty_dev, cs); else { warn("could not register device to the tty subsystem"); - cs->class = NULL; + cs->tty_dev = NULL; } } @@ -645,7 +645,7 @@ void gigaset_if_free(struct cardstate *cs) tasklet_disable(&cs->if_wake_tasklet); tasklet_kill(&cs->if_wake_tasklet); - cs->class = NULL; + cs->tty_dev = NULL; tty_unregister_device(drv->tty, cs->minor_index); } diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c index 9ad840e95dbe..e767afa55abf 100644 --- a/drivers/isdn/gigaset/proc.c +++ b/drivers/isdn/gigaset/proc.c @@ -16,11 +16,12 @@ #include "gigaset.h" #include -static ssize_t show_cidmode(struct class_device *class, char *buf) +static ssize_t show_cidmode(struct device *dev, + struct device_attribute *attr, char *buf) { int ret; unsigned long flags; - struct cardstate *cs = class_get_devdata(class); + struct cardstate *cs = dev_get_drvdata(dev); spin_lock_irqsave(&cs->lock, flags); ret = sprintf(buf, "%u\n", cs->cidmode); @@ -29,10 +30,10 @@ static ssize_t show_cidmode(struct class_device *class, char *buf) return ret; } -static ssize_t set_cidmode(struct class_device *class, +static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct cardstate *cs = class_get_devdata(class); + struct cardstate *cs = dev_get_drvdata(dev); long int value; char *end; @@ -64,25 +65,25 @@ static ssize_t set_cidmode(struct class_device *class, return count; } -static CLASS_DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode); +static DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode); /* free sysfs for device */ void gigaset_free_dev_sysfs(struct cardstate *cs) { - if (!cs->class) + if (!cs->tty_dev) return; gig_dbg(DEBUG_INIT, "removing sysfs entries"); - class_device_remove_file(cs->class, &class_device_attr_cidmode); + device_remove_file(cs->tty_dev, &dev_attr_cidmode); } /* initialize sysfs for device */ void gigaset_init_dev_sysfs(struct cardstate *cs) { - if (!cs->class) + if (!cs->tty_dev) return; gig_dbg(DEBUG_INIT, "setting up sysfs"); - if (class_device_create_file(cs->class, &class_device_attr_cidmode)) + if (device_create_file(cs->tty_dev, &dev_attr_cidmode)) dev_err(cs->dev, "could not create sysfs attribute\n"); } diff --git a/include/linux/tty.h b/include/linux/tty.h index 44091c0db0b4..65321f911c1e 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -276,9 +276,8 @@ extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc); extern int tty_unregister_ldisc(int disc); extern int tty_register_driver(struct tty_driver *driver); extern int tty_unregister_driver(struct tty_driver *driver); -extern struct class_device *tty_register_device(struct tty_driver *driver, - unsigned index, - struct device *dev); +extern struct device *tty_register_device(struct tty_driver *driver, + unsigned index, struct device *dev); extern void tty_unregister_device(struct tty_driver *driver, unsigned index); extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen); -- cgit v1.2.3 From fcaf71fd51f9cfc504455d3e19ec242e4b2073ed Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 12 Sep 2006 17:00:10 +0200 Subject: Driver core: convert mmc code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/mmc_queue.c | 4 ++-- drivers/mmc/mmc_sysfs.c | 20 ++++++++++---------- drivers/mmc/wbsd.c | 6 +++--- include/linux/mmc/host.h | 8 ++++---- 4 files changed, 19 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c index 4ccdd82b680f..61a1de85cb23 100644 --- a/drivers/mmc/mmc_queue.c +++ b/drivers/mmc/mmc_queue.c @@ -130,8 +130,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock u64 limit = BLK_BOUNCE_HIGH; int ret; - if (host->dev->dma_mask && *host->dev->dma_mask) - limit = *host->dev->dma_mask; + if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) + limit = *mmc_dev(host)->dma_mask; mq->card = card; mq->queue = blk_init_queue(mmc_request, lock); diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index 10cc9734eaa0..ac5329636045 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -199,7 +199,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host) memset(card, 0, sizeof(struct mmc_card)); card->host = host; device_initialize(&card->dev); - card->dev.parent = card->host->dev; + card->dev.parent = mmc_dev(host); card->dev.bus = &mmc_bus_type; card->dev.release = mmc_release_card; } @@ -242,7 +242,7 @@ void mmc_remove_card(struct mmc_card *card) } -static void mmc_host_classdev_release(struct class_device *dev) +static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); kfree(host); @@ -250,7 +250,7 @@ static void mmc_host_classdev_release(struct class_device *dev) static struct class mmc_host_class = { .name = "mmc_host", - .release = mmc_host_classdev_release, + .dev_release = mmc_host_classdev_release, }; static DEFINE_IDR(mmc_host_idr); @@ -267,10 +267,10 @@ struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev) if (host) { memset(host, 0, sizeof(struct mmc_host) + extra); - host->dev = dev; - host->class_dev.dev = host->dev; + host->parent = dev; + host->class_dev.parent = dev; host->class_dev.class = &mmc_host_class; - class_device_initialize(&host->class_dev); + device_initialize(&host->class_dev); } return host; @@ -292,10 +292,10 @@ int mmc_add_host_sysfs(struct mmc_host *host) if (err) return err; - snprintf(host->class_dev.class_id, BUS_ID_SIZE, + snprintf(host->class_dev.bus_id, BUS_ID_SIZE, "mmc%d", host->index); - return class_device_add(&host->class_dev); + return device_add(&host->class_dev); } /* @@ -303,7 +303,7 @@ int mmc_add_host_sysfs(struct mmc_host *host) */ void mmc_remove_host_sysfs(struct mmc_host *host) { - class_device_del(&host->class_dev); + device_del(&host->class_dev); spin_lock(&mmc_host_lock); idr_remove(&mmc_host_idr, host->index); @@ -315,7 +315,7 @@ void mmc_remove_host_sysfs(struct mmc_host *host) */ void mmc_free_host_sysfs(struct mmc_host *host) { - class_device_put(&host->class_dev); + put_device(&host->class_dev); } static struct workqueue_struct *workqueue; diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index ced309b37a8f..682e62b0b09d 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1488,7 +1488,7 @@ static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma) /* * Translate the address to a physical address. */ - host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer, + host->dma_addr = dma_map_single(mmc_dev(host->mmc), host->dma_buffer, WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); /* @@ -1512,7 +1512,7 @@ kfree: */ BUG_ON(1); - dma_unmap_single(host->mmc->dev, host->dma_addr, + dma_unmap_single(mmc_dev(host->mmc), host->dma_addr, WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); host->dma_addr = (dma_addr_t)NULL; @@ -1530,7 +1530,7 @@ err: static void __devexit wbsd_release_dma(struct wbsd_host *host) { if (host->dma_addr) { - dma_unmap_single(host->mmc->dev, host->dma_addr, + dma_unmap_single(mmc_dev(host->mmc), host->dma_addr, WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); } kfree(host->dma_buffer); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 587264a58d56..528e7d3fecb1 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -74,8 +74,8 @@ struct mmc_card; struct device; struct mmc_host { - struct device *dev; - struct class_device class_dev; + struct device *parent; + struct device class_dev; int index; const struct mmc_host_ops *ops; unsigned int f_min; @@ -125,8 +125,8 @@ static inline void *mmc_priv(struct mmc_host *host) return (void *)host->private; } -#define mmc_dev(x) ((x)->dev) -#define mmc_hostname(x) ((x)->class_dev.class_id) +#define mmc_dev(x) ((x)->parent) +#define mmc_hostname(x) ((x)->class_dev.bus_id) extern int mmc_suspend_host(struct mmc_host *, pm_message_t); extern int mmc_resume_host(struct mmc_host *); -- cgit v1.2.3 From 78cde0887930f5d11a56fc51b013f2672fba0e6f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 14 Sep 2006 07:30:59 -0700 Subject: Driver core: convert fb code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbmem.c | 16 ++--- drivers/video/fbsysfs.c | 163 +++++++++++++++++++++++++++--------------------- include/linux/fb.h | 8 +-- 3 files changed, 103 insertions(+), 84 deletions(-) (limited to 'include/linux') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 93ffcdd95f50..e973a87fbb01 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1296,14 +1296,14 @@ register_framebuffer(struct fb_info *fb_info) break; fb_info->node = i; - fb_info->class_device = class_device_create(fb_class, NULL, MKDEV(FB_MAJOR, i), - fb_info->device, "fb%d", i); - if (IS_ERR(fb_info->class_device)) { + fb_info->dev = device_create(fb_class, fb_info->device, + MKDEV(FB_MAJOR, i), "fb%d", i); + if (IS_ERR(fb_info->dev)) { /* Not fatal */ - printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->class_device)); - fb_info->class_device = NULL; + printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev)); + fb_info->dev = NULL; } else - fb_init_class_device(fb_info); + fb_init_device(fb_info); if (fb_info->pixmap.addr == NULL) { fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); @@ -1356,8 +1356,8 @@ unregister_framebuffer(struct fb_info *fb_info) fb_destroy_modelist(&fb_info->modelist); registered_fb[i]=NULL; num_registered_fb--; - fb_cleanup_class_device(fb_info); - class_device_destroy(fb_class, MKDEV(FB_MAJOR, i)); + fb_cleanup_device(fb_info); + device_destroy(fb_class, MKDEV(FB_MAJOR, i)); event.info = fb_info; fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); return 0; diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index d3a50417ed9a..323bdf6fc7d5 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -73,7 +73,7 @@ EXPORT_SYMBOL(framebuffer_alloc); * * @info: frame buffer info structure * - * Drop the reference count of the class_device embedded in the + * Drop the reference count of the device embedded in the * framebuffer info structure. * */ @@ -120,10 +120,10 @@ static int mode_string(char *buf, unsigned int offset, m, mode->xres, mode->yres, v, mode->refresh); } -static ssize_t store_mode(struct class_device *class_device, const char * buf, - size_t count) +static ssize_t store_mode(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); char mstr[100]; struct fb_var_screeninfo var; struct fb_modelist *modelist; @@ -151,9 +151,10 @@ static ssize_t store_mode(struct class_device *class_device, const char * buf, return -EINVAL; } -static ssize_t show_mode(struct class_device *class_device, char *buf) +static ssize_t show_mode(struct device *device, struct device_attribute *attr, + char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); if (!fb_info->mode) return 0; @@ -161,10 +162,11 @@ static ssize_t show_mode(struct class_device *class_device, char *buf) return mode_string(buf, 0, fb_info->mode); } -static ssize_t store_modes(struct class_device *class_device, const char * buf, - size_t count) +static ssize_t store_modes(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); LIST_HEAD(old_list); int i = count / sizeof(struct fb_videomode); @@ -186,9 +188,10 @@ static ssize_t store_modes(struct class_device *class_device, const char * buf, return 0; } -static ssize_t show_modes(struct class_device *class_device, char *buf) +static ssize_t show_modes(struct device *device, struct device_attribute *attr, + char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); unsigned int i; struct list_head *pos; struct fb_modelist *modelist; @@ -203,10 +206,10 @@ static ssize_t show_modes(struct class_device *class_device, char *buf) return i; } -static ssize_t store_bpp(struct class_device *class_device, const char * buf, - size_t count) +static ssize_t store_bpp(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); struct fb_var_screeninfo var; char ** last = NULL; int err; @@ -218,16 +221,18 @@ static ssize_t store_bpp(struct class_device *class_device, const char * buf, return count; } -static ssize_t show_bpp(struct class_device *class_device, char *buf) +static ssize_t show_bpp(struct device *device, struct device_attribute *attr, + char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel); } -static ssize_t store_rotate(struct class_device *class_device, const char *buf, - size_t count) +static ssize_t store_rotate(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); struct fb_var_screeninfo var; char **last = NULL; int err; @@ -242,17 +247,19 @@ static ssize_t store_rotate(struct class_device *class_device, const char *buf, } -static ssize_t show_rotate(struct class_device *class_device, char *buf) +static ssize_t show_rotate(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate); } -static ssize_t store_virtual(struct class_device *class_device, - const char * buf, size_t count) +static ssize_t store_virtual(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); struct fb_var_screeninfo var; char *last = NULL; int err; @@ -269,23 +276,26 @@ static ssize_t store_virtual(struct class_device *class_device, return count; } -static ssize_t show_virtual(struct class_device *class_device, char *buf) +static ssize_t show_virtual(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual, fb_info->var.yres_virtual); } -static ssize_t show_stride(struct class_device *class_device, char *buf) +static ssize_t show_stride(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->fix.line_length); } -static ssize_t store_blank(struct class_device *class_device, const char * buf, - size_t count) +static ssize_t store_blank(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); char *last = NULL; int err; @@ -299,42 +309,48 @@ static ssize_t store_blank(struct class_device *class_device, const char * buf, return count; } -static ssize_t show_blank(struct class_device *class_device, char *buf) +static ssize_t show_blank(struct device *device, + struct device_attribute *attr, char *buf) { -// struct fb_info *fb_info = class_get_devdata(class_device); +// struct fb_info *fb_info = dev_get_drvdata(device); return 0; } -static ssize_t store_console(struct class_device *class_device, - const char * buf, size_t count) +static ssize_t store_console(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { -// struct fb_info *fb_info = class_get_devdata(class_device); +// struct fb_info *fb_info = dev_get_drvdata(device); return 0; } -static ssize_t show_console(struct class_device *class_device, char *buf) +static ssize_t show_console(struct device *device, + struct device_attribute *attr, char *buf) { -// struct fb_info *fb_info = class_get_devdata(class_device); +// struct fb_info *fb_info = dev_get_drvdata(device); return 0; } -static ssize_t store_cursor(struct class_device *class_device, - const char * buf, size_t count) +static ssize_t store_cursor(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { -// struct fb_info *fb_info = class_get_devdata(class_device); +// struct fb_info *fb_info = dev_get_drvdata(device); return 0; } -static ssize_t show_cursor(struct class_device *class_device, char *buf) +static ssize_t show_cursor(struct device *device, + struct device_attribute *attr, char *buf) { -// struct fb_info *fb_info = class_get_devdata(class_device); +// struct fb_info *fb_info = dev_get_drvdata(device); return 0; } -static ssize_t store_pan(struct class_device *class_device, const char * buf, - size_t count) +static ssize_t store_pan(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); struct fb_var_screeninfo var; char *last = NULL; int err; @@ -355,24 +371,27 @@ static ssize_t store_pan(struct class_device *class_device, const char * buf, return count; } -static ssize_t show_pan(struct class_device *class_device, char *buf) +static ssize_t show_pan(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset, fb_info->var.xoffset); } -static ssize_t show_name(struct class_device *class_device, char *buf) +static ssize_t show_name(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%s\n", fb_info->fix.id); } -static ssize_t store_fbstate(struct class_device *class_device, - const char *buf, size_t count) +static ssize_t store_fbstate(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); u32 state; char *last = NULL; @@ -385,17 +404,19 @@ static ssize_t store_fbstate(struct class_device *class_device, return count; } -static ssize_t show_fbstate(struct class_device *class_device, char *buf) +static ssize_t show_fbstate(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state); } #ifdef CONFIG_FB_BACKLIGHT -static ssize_t store_bl_curve(struct class_device *class_device, - const char *buf, size_t count) +static ssize_t store_bl_curve(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); u8 tmp_curve[FB_BACKLIGHT_LEVELS]; unsigned int i; @@ -432,9 +453,10 @@ static ssize_t store_bl_curve(struct class_device *class_device, return count; } -static ssize_t show_bl_curve(struct class_device *class_device, char *buf) +static ssize_t show_bl_curve(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); ssize_t len = 0; unsigned int i; @@ -465,7 +487,7 @@ static ssize_t show_bl_curve(struct class_device *class_device, char *buf) /* When cmap is added back in it should be a binary attribute * not a text one. Consideration should also be given to converting * fbdev to use configfs instead of sysfs */ -static struct class_device_attribute class_device_attrs[] = { +static struct device_attribute device_attrs[] = { __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp), __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank), __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console), @@ -483,17 +505,16 @@ static struct class_device_attribute class_device_attrs[] = { #endif }; -int fb_init_class_device(struct fb_info *fb_info) +int fb_init_device(struct fb_info *fb_info) { int i, error = 0; - class_set_devdata(fb_info->class_device, fb_info); + dev_set_drvdata(fb_info->dev, fb_info); fb_info->class_flag |= FB_SYSFS_FLAG_ATTR; - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { - error = class_device_create_file(fb_info->class_device, - &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { + error = device_create_file(fb_info->dev, &device_attrs[i]); if (error) break; @@ -501,22 +522,20 @@ int fb_init_class_device(struct fb_info *fb_info) if (error) { while (--i >= 0) - class_device_remove_file(fb_info->class_device, - &class_device_attrs[i]); + device_remove_file(fb_info->dev, &device_attrs[i]); fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR; } return 0; } -void fb_cleanup_class_device(struct fb_info *fb_info) +void fb_cleanup_device(struct fb_info *fb_info) { unsigned int i; if (fb_info->class_flag & FB_SYSFS_FLAG_ATTR) { - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) - class_device_remove_file(fb_info->class_device, - &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) + device_remove_file(fb_info->dev, &device_attrs[i]); fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR; } diff --git a/include/linux/fb.h b/include/linux/fb.h index 3e69241e6a81..fa23e0671bb3 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -774,8 +774,8 @@ struct fb_info { #endif struct fb_ops *fbops; - struct device *device; - struct class_device *class_device; /* sysfs per device attrs */ + struct device *device; /* This is the parent */ + struct device *dev; /* This is this fb device */ int class_flag; /* private sysfs flags */ #ifdef CONFIG_FB_TILEBLITTING struct fb_tile_ops *tileops; /* Tile Blitting */ @@ -910,8 +910,8 @@ static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, /* drivers/video/fbsysfs.c */ extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev); extern void framebuffer_release(struct fb_info *info); -extern int fb_init_class_device(struct fb_info *fb_info); -extern void fb_cleanup_class_device(struct fb_info *head); +extern int fb_init_device(struct fb_info *fb_info); +extern void fb_cleanup_device(struct fb_info *head); extern void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max); /* drivers/video/fbmon.c */ -- cgit v1.2.3 From c6dbaef22a2f78700e242915a13218dd780c89ff Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 11 Nov 2006 17:18:39 +1100 Subject: Driver core: add dev_archdata to struct device Add arch specific dev_archdata to struct device Adds an arch specific struct dev_arch to struct device. This enables architecture to add specific fields to every device in the system, like DMA operation pointers, NUMA node ID, firmware specific data, etc... Signed-off-by: Benjamin Herrenschmidt Acked-by: Andi Kleen Acked-By: David Howells Signed-off-by: Greg Kroah-Hartman --- include/asm-alpha/device.h | 7 +++++++ include/asm-arm/device.h | 7 +++++++ include/asm-arm26/device.h | 7 +++++++ include/asm-avr32/device.h | 7 +++++++ include/asm-cris/device.h | 7 +++++++ include/asm-frv/device.h | 7 +++++++ include/asm-generic/device.h | 12 ++++++++++++ include/asm-h8300/device.h | 7 +++++++ include/asm-i386/device.h | 7 +++++++ include/asm-ia64/device.h | 7 +++++++ include/asm-m32r/device.h | 7 +++++++ include/asm-m68k/device.h | 7 +++++++ include/asm-m68knommu/device.h | 7 +++++++ include/asm-mips/device.h | 7 +++++++ include/asm-parisc/device.h | 7 +++++++ include/asm-powerpc/device.h | 7 +++++++ include/asm-ppc/device.h | 7 +++++++ include/asm-s390/device.h | 7 +++++++ include/asm-sh/device.h | 7 +++++++ include/asm-sh64/device.h | 7 +++++++ include/asm-sparc/device.h | 7 +++++++ include/asm-sparc64/device.h | 7 +++++++ include/asm-um/device.h | 7 +++++++ include/asm-v850/device.h | 7 +++++++ include/asm-x86_64/device.h | 7 +++++++ include/asm-xtensa/device.h | 7 +++++++ include/linux/device.h | 3 +++ 27 files changed, 190 insertions(+) create mode 100644 include/asm-alpha/device.h create mode 100644 include/asm-arm/device.h create mode 100644 include/asm-arm26/device.h create mode 100644 include/asm-avr32/device.h create mode 100644 include/asm-cris/device.h create mode 100644 include/asm-frv/device.h create mode 100644 include/asm-generic/device.h create mode 100644 include/asm-h8300/device.h create mode 100644 include/asm-i386/device.h create mode 100644 include/asm-ia64/device.h create mode 100644 include/asm-m32r/device.h create mode 100644 include/asm-m68k/device.h create mode 100644 include/asm-m68knommu/device.h create mode 100644 include/asm-mips/device.h create mode 100644 include/asm-parisc/device.h create mode 100644 include/asm-powerpc/device.h create mode 100644 include/asm-ppc/device.h create mode 100644 include/asm-s390/device.h create mode 100644 include/asm-sh/device.h create mode 100644 include/asm-sh64/device.h create mode 100644 include/asm-sparc/device.h create mode 100644 include/asm-sparc64/device.h create mode 100644 include/asm-um/device.h create mode 100644 include/asm-v850/device.h create mode 100644 include/asm-x86_64/device.h create mode 100644 include/asm-xtensa/device.h (limited to 'include/linux') diff --git a/include/asm-alpha/device.h b/include/asm-alpha/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-alpha/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-arm/device.h b/include/asm-arm/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-arm/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-arm26/device.h b/include/asm-arm26/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-arm26/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-avr32/device.h b/include/asm-avr32/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-avr32/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-cris/device.h b/include/asm-cris/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-cris/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-frv/device.h b/include/asm-frv/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-frv/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-generic/device.h b/include/asm-generic/device.h new file mode 100644 index 000000000000..c17c9600f220 --- /dev/null +++ b/include/asm-generic/device.h @@ -0,0 +1,12 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#ifndef _ASM_GENERIC_DEVICE_H +#define _ASM_GENERIC_DEVICE_H + +struct dev_archdata { +}; + +#endif /* _ASM_GENERIC_DEVICE_H */ diff --git a/include/asm-h8300/device.h b/include/asm-h8300/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-h8300/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-i386/device.h b/include/asm-i386/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-i386/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-ia64/device.h b/include/asm-ia64/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-ia64/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-m32r/device.h b/include/asm-m32r/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-m32r/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-m68k/device.h b/include/asm-m68k/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-m68k/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-m68knommu/device.h b/include/asm-m68knommu/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-m68knommu/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-mips/device.h b/include/asm-mips/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-mips/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-parisc/device.h b/include/asm-parisc/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-parisc/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-powerpc/device.h b/include/asm-powerpc/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-powerpc/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-ppc/device.h b/include/asm-ppc/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-ppc/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-s390/device.h b/include/asm-s390/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-s390/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-sh/device.h b/include/asm-sh/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-sh/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-sh64/device.h b/include/asm-sh64/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-sh64/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-sparc/device.h b/include/asm-sparc/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-sparc/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-sparc64/device.h b/include/asm-sparc64/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-sparc64/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-um/device.h b/include/asm-um/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-um/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-v850/device.h b/include/asm-v850/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-v850/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-x86_64/device.h b/include/asm-x86_64/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-x86_64/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-xtensa/device.h b/include/asm-xtensa/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-xtensa/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/linux/device.h b/include/linux/device.h index 00b29e0c5ce0..5b54d756cd54 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -21,6 +21,7 @@ #include #include #include +#include #define DEVICE_NAME_SIZE 50 #define DEVICE_NAME_HALF __stringify(20) /* Less than half to accommodate slop */ @@ -383,6 +384,8 @@ struct device { struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */ + /* arch specific additions */ + struct dev_archdata archdata; /* class_device migration path */ struct list_head node; -- cgit v1.2.3 From 465ae641e4a3e5028aa9c85d3843259aa28a22ce Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 11 Nov 2006 17:18:42 +1100 Subject: ACPI: Change ACPI to use dev_archdata instead of firmware_data Change ACPI to use dev_archdata instead of firmware_data This patch changes ACPI to use the new dev_archdata on i386, x86_64 and ia64 (is there any other arch using ACPI ?) to store it's acpi_handle. It also removes the firmware_data field from struct device as this was the only user. Only build-tested on x86 Signed-off-by: Benjamin Herrenschmidt Cc: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/glue.c | 20 +++++++++++--------- include/acpi/acpi_bus.h | 2 +- include/asm-i386/device.h | 10 +++++++++- include/asm-ia64/device.h | 10 +++++++++- include/asm-x86_64/device.h | 10 +++++++++- include/linux/device.h | 2 -- 6 files changed, 39 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 10f160dc75b1..a2f46d587d55 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -267,9 +267,9 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) { acpi_status status; - if (dev->firmware_data) { + if (dev->archdata.acpi_handle) { printk(KERN_WARNING PREFIX - "Drivers changed 'firmware_data' for %s\n", dev->bus_id); + "Drivers changed 'acpi_handle' for %s\n", dev->bus_id); return -EINVAL; } get_device(dev); @@ -278,25 +278,26 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) put_device(dev); return -EINVAL; } - dev->firmware_data = handle; + dev->archdata.acpi_handle = handle; return 0; } static int acpi_unbind_one(struct device *dev) { - if (!dev->firmware_data) + if (!dev->archdata.acpi_handle) return 0; - if (dev == acpi_get_physical_device(dev->firmware_data)) { + if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) { /* acpi_get_physical_device increase refcnt by one */ put_device(dev); - acpi_detach_data(dev->firmware_data, acpi_glue_data_handler); - dev->firmware_data = NULL; + acpi_detach_data(dev->archdata.acpi_handle, + acpi_glue_data_handler); + dev->archdata.acpi_handle = NULL; /* acpi_bind_one increase refcnt by one */ put_device(dev); } else { printk(KERN_ERR PREFIX - "Oops, 'firmware_data' corrupt for %s\n", dev->bus_id); + "Oops, 'acpi_handle' corrupt for %s\n", dev->bus_id); } return 0; } @@ -328,7 +329,8 @@ static int acpi_platform_notify(struct device *dev) if (!ret) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_get_name(dev->firmware_data, ACPI_FULL_PATHNAME, &buffer); + acpi_get_name(dev->archdata.acpi_handle, + ACPI_FULL_PATHNAME, &buffer); DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer); kfree(buffer.pointer); } else diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index f338e40bd544..fdd10953b2b6 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -357,7 +357,7 @@ struct device *acpi_get_physical_device(acpi_handle); /* helper */ acpi_handle acpi_get_child(acpi_handle, acpi_integer); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); -#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->firmware_data)) +#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) #endif /* CONFIG_ACPI */ diff --git a/include/asm-i386/device.h b/include/asm-i386/device.h index d8f9872b0e2d..849604c70e6b 100644 --- a/include/asm-i386/device.h +++ b/include/asm-i386/device.h @@ -3,5 +3,13 @@ * * This file is released under the GPLv2 */ -#include +#ifndef _ASM_I386_DEVICE_H +#define _ASM_I386_DEVICE_H +struct dev_archdata { +#ifdef CONFIG_ACPI + void *acpi_handle; +#endif +}; + +#endif /* _ASM_I386_DEVICE_H */ diff --git a/include/asm-ia64/device.h b/include/asm-ia64/device.h index d8f9872b0e2d..3db6daf7f251 100644 --- a/include/asm-ia64/device.h +++ b/include/asm-ia64/device.h @@ -3,5 +3,13 @@ * * This file is released under the GPLv2 */ -#include +#ifndef _ASM_IA64_DEVICE_H +#define _ASM_IA64_DEVICE_H +struct dev_archdata { +#ifdef CONFIG_ACPI + void *acpi_handle; +#endif +}; + +#endif /* _ASM_IA64_DEVICE_H */ diff --git a/include/asm-x86_64/device.h b/include/asm-x86_64/device.h index d8f9872b0e2d..3afa03f33a36 100644 --- a/include/asm-x86_64/device.h +++ b/include/asm-x86_64/device.h @@ -3,5 +3,13 @@ * * This file is released under the GPLv2 */ -#include +#ifndef _ASM_X86_64_DEVICE_H +#define _ASM_X86_64_DEVICE_H +struct dev_archdata { +#ifdef CONFIG_ACPI + void *acpi_handle; +#endif +}; + +#endif /* _ASM_X86_64_DEVICE_H */ diff --git a/include/linux/device.h b/include/linux/device.h index 5b54d756cd54..2d9dc358c027 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -369,8 +369,6 @@ struct device { void *driver_data; /* data private to the driver */ void *platform_data; /* Platform specific data, device core doesn't touch it */ - void *firmware_data; /* Firmware specific data (e.g. ACPI, - BIOS data),reserved for device core*/ struct dev_pm_info power; u64 *dma_mask; /* dma mask (if dma'able device) */ -- cgit v1.2.3 From 5ab699810d46011ad2195c5916f3cbc684bfe3ee Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 16 Nov 2006 15:42:07 +0100 Subject: driver core: Introduce device_find_child(). Introduce device_find_child() to match device_for_each_child(). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 33 +++++++++++++++++++++++++++++++++ include/linux/device.h | 2 ++ 2 files changed, 35 insertions(+) (limited to 'include/linux') diff --git a/drivers/base/core.c b/drivers/base/core.c index 5d11bbdfbd2f..a29e68545462 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -750,12 +750,45 @@ int device_for_each_child(struct device * parent, void * data, return error; } +/** + * device_find_child - device iterator for locating a particular device. + * @parent: parent struct device + * @data: Data to pass to match function + * @match: Callback function to check device + * + * This is similar to the device_for_each_child() function above, but it + * returns a reference to a device that is 'found' for later use, as + * determined by the @match callback. + * + * The callback should return 0 if the device doesn't match and non-zero + * if it does. If the callback returns non-zero and a reference to the + * current device can be obtained, this function will return to the caller + * and not iterate over any more devices. + */ +struct device * device_find_child(struct device *parent, void *data, + int (*match)(struct device *, void *)) +{ + struct klist_iter i; + struct device *child; + + if (!parent) + return NULL; + + klist_iter_init(&parent->klist_children, &i); + while ((child = next_device(&i))) + if (match(child, data) && get_device(child)) + break; + klist_iter_exit(&i); + return child; +} + int __init devices_init(void) { return subsystem_register(&devices_subsys); } EXPORT_SYMBOL_GPL(device_for_each_child); +EXPORT_SYMBOL_GPL(device_find_child); EXPORT_SYMBOL_GPL(device_initialize); EXPORT_SYMBOL_GPL(device_add); diff --git a/include/linux/device.h b/include/linux/device.h index 2d9dc358c027..0a0370c74181 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -421,6 +421,8 @@ extern int __must_check device_add(struct device * dev); extern void device_del(struct device * dev); extern int device_for_each_child(struct device *, void *, int (*fn)(struct device *, void *)); +extern struct device *device_find_child(struct device *, void *data, + int (*match)(struct device *, void *)); extern int device_rename(struct device *dev, char *new_name); /* -- cgit v1.2.3 From 8a82472f86bf693b8e91ed56c9ca4f62fbbdcfa3 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 20 Nov 2006 17:07:51 +0100 Subject: driver core: Introduce device_move(): move a device to a new parent. Provide a function device_move() to move a device to a new parent device. Add auxilliary functions kobject_move() and sysfs_move_dir(). kobject_move() generates a new uevent of type KOBJ_MOVE, containing the previous path (DEVPATH_OLD) in addition to the usual values. For this, a new interface kobject_uevent_env() is created that allows to add further environmental data to the uevent at the kobject layer. Signed-off-by: Cornelia Huck Acked-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/sysfs/dir.c | 45 ++++++++++++++++++++++++ include/linux/device.h | 1 + include/linux/kobject.h | 8 +++++ include/linux/sysfs.h | 8 +++++ lib/kobject.c | 50 +++++++++++++++++++++++++++ lib/kobject_uevent.c | 28 ++++++++++++--- 7 files changed, 228 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/core.c b/drivers/base/core.c index 75b45a10935a..e4eaf46c4d93 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -955,3 +955,95 @@ int device_rename(struct device *dev, char *new_name) return error; } + + +static int device_move_class_links(struct device *dev, + struct device *old_parent, + struct device *new_parent) +{ +#ifdef CONFIG_SYSFS_DEPRECATED + int error; + char *class_name; + + class_name = make_class_name(dev->class->name, &dev->kobj); + if (!class_name) { + error = PTR_ERR(class_name); + class_name = NULL; + goto out; + } + if (old_parent) { + sysfs_remove_link(&dev->kobj, "device"); + sysfs_remove_link(&old_parent->kobj, class_name); + } + error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device"); + if (error) + goto out; + error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name); + if (error) + sysfs_remove_link(&dev->kobj, "device"); +out: + kfree(class_name); + return error; +#else + return 0; +#endif +} + +/** + * device_move - moves a device to a new parent + * @dev: the pointer to the struct device to be moved + * @new_parent: the new parent of the device + */ +int device_move(struct device *dev, struct device *new_parent) +{ + int error; + struct device *old_parent; + + dev = get_device(dev); + if (!dev) + return -EINVAL; + + if (!device_is_registered(dev)) { + error = -EINVAL; + goto out; + } + new_parent = get_device(new_parent); + if (!new_parent) { + error = -EINVAL; + goto out; + } + pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, + new_parent->bus_id); + error = kobject_move(&dev->kobj, &new_parent->kobj); + if (error) { + put_device(new_parent); + goto out; + } + old_parent = dev->parent; + dev->parent = new_parent; + if (old_parent) + klist_del(&dev->knode_parent); + klist_add_tail(&dev->knode_parent, &new_parent->klist_children); + if (!dev->class) + goto out_put; + error = device_move_class_links(dev, old_parent, new_parent); + if (error) { + /* We ignore errors on cleanup since we're hosed anyway... */ + device_move_class_links(dev, new_parent, old_parent); + if (!kobject_move(&dev->kobj, &old_parent->kobj)) { + klist_del(&dev->knode_parent); + if (old_parent) + klist_add_tail(&dev->knode_parent, + &old_parent->klist_children); + } + put_device(new_parent); + goto out; + } +out_put: + put_device(old_parent); +out: + put_device(dev); + return error; +} + +EXPORT_SYMBOL_GPL(device_move); diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 3aa3434621ca..a5782e8c7f07 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -372,6 +372,51 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) return error; } +int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent) +{ + struct dentry *old_parent_dentry, *new_parent_dentry, *new_dentry; + struct sysfs_dirent *new_parent_sd, *sd; + int error; + + if (!new_parent) + return -EINVAL; + + old_parent_dentry = kobj->parent ? + kobj->parent->dentry : sysfs_mount->mnt_sb->s_root; + new_parent_dentry = new_parent->dentry; + +again: + mutex_lock(&old_parent_dentry->d_inode->i_mutex); + if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) { + mutex_unlock(&old_parent_dentry->d_inode->i_mutex); + goto again; + } + + new_parent_sd = new_parent_dentry->d_fsdata; + sd = kobj->dentry->d_fsdata; + + new_dentry = lookup_one_len(kobj->name, new_parent_dentry, + strlen(kobj->name)); + if (IS_ERR(new_dentry)) { + error = PTR_ERR(new_dentry); + goto out; + } else + error = 0; + d_add(new_dentry, NULL); + d_move(kobj->dentry, new_dentry); + dput(new_dentry); + + /* Remove from old parent's list and insert into new parent's list. */ + list_del_init(&sd->s_sibling); + list_add(&sd->s_sibling, &new_parent_sd->s_children); + +out: + mutex_unlock(&new_parent_dentry->d_inode->i_mutex); + mutex_unlock(&old_parent_dentry->d_inode->i_mutex); + + return error; +} + static int sysfs_dir_open(struct inode *inode, struct file *file) { struct dentry * dentry = file->f_dentry; diff --git a/include/linux/device.h b/include/linux/device.h index 0a0370c74181..583a341e016c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -424,6 +424,7 @@ extern int device_for_each_child(struct device *, void *, extern struct device *device_find_child(struct device *, void *data, int (*match)(struct device *, void *)); extern int device_rename(struct device *dev, char *new_name); +extern int device_move(struct device *dev, struct device *new_parent); /* * Manual binding of a device to driver. See drivers/base/bus.c diff --git a/include/linux/kobject.h b/include/linux/kobject.h index bcd9cd173c2c..d1c8d28fa92e 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -47,6 +47,7 @@ enum kobject_action { KOBJ_UMOUNT = (__force kobject_action_t) 0x05, /* umount event for block devices (broken) */ KOBJ_OFFLINE = (__force kobject_action_t) 0x06, /* device offline */ KOBJ_ONLINE = (__force kobject_action_t) 0x07, /* device online */ + KOBJ_MOVE = (__force kobject_action_t) 0x08, /* device move */ }; struct kobject { @@ -76,6 +77,7 @@ extern int __must_check kobject_add(struct kobject *); extern void kobject_del(struct kobject *); extern int __must_check kobject_rename(struct kobject *, const char *new_name); +extern int __must_check kobject_move(struct kobject *, struct kobject *); extern int __must_check kobject_register(struct kobject *); extern void kobject_unregister(struct kobject *); @@ -264,6 +266,8 @@ extern int __must_check subsys_create_file(struct subsystem * , #if defined(CONFIG_HOTPLUG) void kobject_uevent(struct kobject *kobj, enum kobject_action action); +void kobject_uevent_env(struct kobject *kobj, enum kobject_action action, + char *envp[]); int add_uevent_var(char **envp, int num_envp, int *cur_index, char *buffer, int buffer_size, int *cur_len, @@ -271,6 +275,10 @@ int add_uevent_var(char **envp, int num_envp, int *cur_index, __attribute__((format (printf, 7, 8))); #else static inline void kobject_uevent(struct kobject *kobj, enum kobject_action action) { } +static inline void kobject_uevent_env(struct kobject *kobj, + enum kobject_action action, + char *envp[]) +{ } static inline int add_uevent_var(char **envp, int num_envp, int *cur_index, char *buffer, int buffer_size, int *cur_len, diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 6d5c43d31dec..2129d1b6c874 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -96,6 +96,9 @@ sysfs_remove_dir(struct kobject *); extern int __must_check sysfs_rename_dir(struct kobject *, const char *new_name); +extern int __must_check +sysfs_move_dir(struct kobject *, struct kobject *); + extern int __must_check sysfs_create_file(struct kobject *, const struct attribute *); @@ -142,6 +145,11 @@ static inline int sysfs_rename_dir(struct kobject * k, const char *new_name) return 0; } +static inline int sysfs_move_dir(struct kobject * k, struct kobject * new_parent) +{ + return 0; +} + static inline int sysfs_create_file(struct kobject * k, const struct attribute * a) { return 0; diff --git a/lib/kobject.c b/lib/kobject.c index 7dd5c0e9d996..744a4b102c7f 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -310,6 +310,56 @@ int kobject_rename(struct kobject * kobj, const char *new_name) return error; } +/** + * kobject_move - move object to another parent + * @kobj: object in question. + * @new_parent: object's new parent + */ + +int kobject_move(struct kobject *kobj, struct kobject *new_parent) +{ + int error; + struct kobject *old_parent; + const char *devpath = NULL; + char *devpath_string = NULL; + char *envp[2]; + + kobj = kobject_get(kobj); + if (!kobj) + return -EINVAL; + new_parent = kobject_get(new_parent); + if (!new_parent) { + error = -EINVAL; + goto out; + } + /* old object path */ + devpath = kobject_get_path(kobj, GFP_KERNEL); + if (!devpath) { + error = -ENOMEM; + goto out; + } + devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL); + if (!devpath_string) { + error = -ENOMEM; + goto out; + } + sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); + envp[0] = devpath_string; + envp[1] = NULL; + error = sysfs_move_dir(kobj, new_parent); + if (error) + goto out; + old_parent = kobj->parent; + kobj->parent = new_parent; + kobject_put(old_parent); + kobject_uevent_env(kobj, KOBJ_MOVE, envp); +out: + kobject_put(kobj); + kfree(devpath_string); + kfree(devpath); + return error; +} + /** * kobject_del - unlink kobject from hierarchy. * @kobj: object. diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 7f20e7b857cb..a1922765ff31 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -50,18 +50,22 @@ static char *action_to_string(enum kobject_action action) return "offline"; case KOBJ_ONLINE: return "online"; + case KOBJ_MOVE: + return "move"; default: return NULL; } } /** - * kobject_uevent - notify userspace by ending an uevent + * kobject_uevent_env - send an uevent with environmental data * - * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE) + * @action: action that is happening (usually KOBJ_MOVE) * @kobj: struct kobject that the action is happening to + * @envp_ext: pointer to environmental data */ -void kobject_uevent(struct kobject *kobj, enum kobject_action action) +void kobject_uevent_env(struct kobject *kobj, enum kobject_action action, + char *envp_ext[]) { char **envp; char *buffer; @@ -76,6 +80,7 @@ void kobject_uevent(struct kobject *kobj, enum kobject_action action) char *seq_buff; int i = 0; int retval; + int j; pr_debug("%s\n", __FUNCTION__); @@ -134,7 +139,8 @@ void kobject_uevent(struct kobject *kobj, enum kobject_action action) scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1; envp [i++] = scratch; scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1; - + for (j = 0; envp_ext && envp_ext[j]; j++) + envp[i++] = envp_ext[j]; /* just reserve the space, overwrite it after kset call has returned */ envp[i++] = seq_buff = scratch; scratch += strlen("SEQNUM=18446744073709551616") + 1; @@ -200,6 +206,20 @@ exit: kfree(envp); return; } + +EXPORT_SYMBOL_GPL(kobject_uevent_env); + +/** + * kobject_uevent - notify userspace by ending an uevent + * + * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE) + * @kobj: struct kobject that the action is happening to + */ +void kobject_uevent(struct kobject *kobj, enum kobject_action action) +{ + kobject_uevent_env(kobj, action, NULL); +} + EXPORT_SYMBOL_GPL(kobject_uevent); /** -- cgit v1.2.3 From c67334fbdfbba533af767610cf3fde8a49710e62 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 16 Nov 2006 23:28:47 -0800 Subject: Driver core: platform_driver_probe(), can save codespace This defines a new platform_driver_probe() method allowing the driver's probe() method, and its support code+data, to safely live in __init sections for typical system configurations. Many system-on-chip processors could benefit from this API, to the tune of recovering hundreds to thousands of bytes per driver. That's memory which is currently wasted holding code which can never be called after system startup, yet can not be removed. It can't be removed because of the linkage requirement that pointers to init section code (like, ideally, probe support) must not live in other sections (like driver method tables) after those pointers would be invalid. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 48 +++++++++++++++++++++++++++++++++++++++++ include/linux/platform_device.h | 6 ++++++ 2 files changed, 54 insertions(+) (limited to 'include/linux') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 940ce41f1887..d1df4a087924 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -388,6 +388,11 @@ static int platform_drv_probe(struct device *_dev) return drv->probe(dev); } +static int platform_drv_probe_fail(struct device *_dev) +{ + return -ENXIO; +} + static int platform_drv_remove(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); @@ -451,6 +456,49 @@ void platform_driver_unregister(struct platform_driver *drv) } EXPORT_SYMBOL_GPL(platform_driver_unregister); +/** + * platform_driver_probe - register driver for non-hotpluggable device + * @drv: platform driver structure + * @probe: the driver probe routine, probably from an __init section + * + * Use this instead of platform_driver_register() when you know the device + * is not hotpluggable and has already been registered, and you want to + * remove its run-once probe() infrastructure from memory after the driver + * has bound to the device. + * + * One typical use for this would be with drivers for controllers integrated + * into system-on-chip processors, where the controller devices have been + * configured as part of board setup. + * + * Returns zero if the driver registered and bound to a device, else returns + * a negative error code and with the driver not registered. + */ +int platform_driver_probe(struct platform_driver *drv, + int (*probe)(struct platform_device *)) +{ + int retval, code; + + /* temporary section violation during probe() */ + drv->probe = probe; + retval = code = platform_driver_register(drv); + + /* Fixup that section violation, being paranoid about code scanning + * the list of drivers in order to probe new devices. Check to see + * if the probe was successful, and make sure any forced probes of + * new devices fail. + */ + spin_lock(&platform_bus_type.klist_drivers.k_lock); + drv->probe = NULL; + if (code == 0 && list_empty(&drv->driver.klist_devices.k_list)) + retval = -ENODEV; + drv->driver.probe = platform_drv_probe_fail; + spin_unlock(&platform_bus_type.klist_drivers.k_lock); + + if (code != retval) + platform_driver_unregister(drv); + return retval; +} +EXPORT_SYMBOL_GPL(platform_driver_probe); /* modalias support enables more hands-off userspace setup: * (a) environment variable lets new-style hotplug events work once system is diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 29cd6dee13db..20f47b81d3fa 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -58,6 +58,12 @@ struct platform_driver { extern int platform_driver_register(struct platform_driver *); extern void platform_driver_unregister(struct platform_driver *); +/* non-hotpluggable platform devices may use this so that probe() and + * its support may live in __init sections, conserving runtime memory. + */ +extern int platform_driver_probe(struct platform_driver *driver, + int (*probe)(struct platform_device *)); + #define platform_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev) #define platform_set_drvdata(_dev,data) dev_set_drvdata(&(_dev)->dev, (data)) -- cgit v1.2.3 From e17e0f51aeea4e59c7e450a1c0f26605b91c1260 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Fri, 24 Nov 2006 12:15:25 +0100 Subject: Driver core: show drivers in /sys/module/ Show the drivers, which belong to the module: $ ls -l /sys/module/usbcore/drivers/ hub -> ../../../bus/usb/drivers/hub usb -> ../../../bus/usb/drivers/usb usbfs -> ../../../bus/usb/drivers/usbfs Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- include/linux/module.h | 1 + kernel/module.c | 31 +++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/module.h b/include/linux/module.h index d1d00ce8f4ed..9258ffd8a7f0 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -264,6 +264,7 @@ struct module struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; + struct kobject *drivers_dir; /* Exported symbols */ const struct kernel_symbol *syms; diff --git a/kernel/module.c b/kernel/module.c index f0166563c602..45e01cb60101 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1086,22 +1086,35 @@ static int mod_sysfs_setup(struct module *mod, goto out; kobj_set_kset_s(&mod->mkobj, module_subsys); mod->mkobj.mod = mod; - err = kobject_register(&mod->mkobj.kobj); + + /* delay uevent until full sysfs population */ + kobject_init(&mod->mkobj.kobj); + err = kobject_add(&mod->mkobj.kobj); if (err) goto out; + mod->drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers"); + if (!mod->drivers_dir) + goto out_unreg; + err = module_param_sysfs_setup(mod, kparam, num_params); if (err) - goto out_unreg; + goto out_unreg_drivers; err = module_add_modinfo_attrs(mod); if (err) - goto out_unreg; + goto out_unreg_param; + kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD); return 0; +out_unreg_drivers: + kobject_unregister(mod->drivers_dir); +out_unreg_param: + module_param_sysfs_remove(mod); out_unreg: - kobject_unregister(&mod->mkobj.kobj); + kobject_del(&mod->mkobj.kobj); + kobject_put(&mod->mkobj.kobj); out: return err; } @@ -1110,6 +1123,7 @@ static void mod_kobject_remove(struct module *mod) { module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); + kobject_unregister(mod->drivers_dir); kobject_unregister(&mod->mkobj.kobj); } @@ -2275,11 +2289,14 @@ void print_modules(void) void module_add_driver(struct module *mod, struct device_driver *drv) { + int no_warn; + if (!mod || !drv) return; - /* Don't check return code; this call is idempotent */ - sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module"); + /* Don't check return codes; these calls are idempotent */ + no_warn = sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module"); + no_warn = sysfs_create_link(mod->drivers_dir, &drv->kobj, drv->name); } EXPORT_SYMBOL(module_add_driver); @@ -2288,6 +2305,8 @@ void module_remove_driver(struct device_driver *drv) if (!drv) return; sysfs_remove_link(&drv->kobj, "module"); + if (drv->owner && drv->owner->drivers_dir) + sysfs_remove_link(drv->owner->drivers_dir, drv->name); } EXPORT_SYMBOL(module_remove_driver); -- cgit v1.2.3 From fc085150b491bfc186efbca90a14cf907a3060a9 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 10 Oct 2006 14:28:11 -0700 Subject: [PATCH] libata: add 40pin "short" cable support, honour drive side speed detection [deweerdt@free.fr: build fix] Signed-off-by: Alan Cox Signed-off-by: Frederik Deweerdt Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 31 ++++++++++++++++++++++++++++++- drivers/ata/libata-core.c | 7 +++++++ drivers/ata/pata_ali.c | 2 +- include/linux/ata.h | 14 ++++++++++++-- 4 files changed, 50 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 720174d628fa..14b726b9f985 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -93,7 +93,7 @@ #include #define DRV_NAME "ata_piix" -#define DRV_VERSION "2.00ac6" +#define DRV_VERSION "2.00ac7" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ @@ -571,6 +571,23 @@ module_param(force_pcs, int, 0444); MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)"); +struct ich_laptop { + u16 device; + u16 subvendor; + u16 subdevice; +}; + +/* + * List of laptops that use short cables rather than 80 wire + */ + +static const struct ich_laptop ich_laptop[] = { + /* devid, subvendor, subdev */ + { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ + /* end marker */ + { 0, } +}; + /** * piix_pata_cbl_detect - Probe host controller cable detect info * @ap: Port for which cable detect info is desired @@ -585,12 +602,24 @@ MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " static void ich_pata_cbl_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); + const struct ich_laptop *lap = &ich_laptop[0]; u8 tmp, mask; /* no 80c support in host controller? */ if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0) goto cbl40; + /* Check for specials - Acer Aspire 5602WLMi */ + while (lap->device) { + if (lap->device == pdev->device && + lap->subvendor == pdev->subsystem_vendor && + lap->subdevice == pdev->subsystem_device) { + ap->cbl = ATA_CBL_PATA40_SHORT; + return; + } + lap++; + } + /* check BIOS cable detect results */ mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 915a55a6cc14..b896119cccd3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3119,6 +3119,13 @@ static void ata_dev_xfermask(struct ata_device *dev) */ if (ap->cbl == ATA_CBL_PATA40) xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); + /* Apply drive side cable rule. Unknown or 80 pin cables reported + * host side are checked drive side as well. Cases where we know a + * 40wire cable is used safely for 80 are not checked here. + */ + if (ata_drive_40wire(dev->id) && (ap->cbl == ATA_CBL_PATA_UNK || ap->cbl == ATA_CBL_PATA80)) + xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); + xfer_mask &= ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask, dev->udma_mask); diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 64eed99f6814..e6d2b840e870 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -78,7 +78,7 @@ static int ali_c2_cable_detect(struct ata_port *ap) implement the detect logic */ if (ali_cable_override(pdev)) - return ATA_CBL_PATA80; + return ATA_CBL_PATA40_SHORT; /* Host view cable detect 0x4A bit 0 primary bit 1 secondary Bit set for 40 pin */ diff --git a/include/linux/ata.h b/include/linux/ata.h index d89441907024..1df941648a57 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -200,8 +200,9 @@ enum { ATA_CBL_NONE = 0, ATA_CBL_PATA40 = 1, ATA_CBL_PATA80 = 2, - ATA_CBL_PATA_UNK = 3, - ATA_CBL_SATA = 4, + ATA_CBL_PATA40_SHORT = 3, /* 40 wire cable to high UDMA spec */ + ATA_CBL_PATA_UNK = 4, + ATA_CBL_SATA = 5, /* SATA Status and Control Registers */ SCR_STATUS = 0, @@ -342,6 +343,15 @@ static inline int ata_id_is_cfa(const u16 *id) return 0; } +static inline int ata_drive_40wire(const u16 *dev_id) +{ + if (ata_id_major_version(dev_id) >= 5 && ata_id_is_sata(dev_id)) + return 0; /* SATA */ + if (dev_id[93] & 0x4000) + return 0; /* 80 wire */ + return 1; +} + static inline int atapi_cdb_len(const u16 *dev_id) { u16 tmp = dev_id[0] & 0x3; -- cgit v1.2.3 From 6919a0a6cfdad9e83d02cef5973826acd416560c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 27 Oct 2006 19:08:46 -0700 Subject: [PATCH] libata: Revamp blacklist support to allow multiple kinds of blacklisting flaws Signed-off-by: Alan Cox Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 123 ++++++++++++++++++++++++++++------------------ include/linux/libata.h | 3 ++ 2 files changed, 78 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b896119cccd3..b4fbfebafd26 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1345,7 +1345,10 @@ static void ata_dev_config_ncq(struct ata_device *dev, desc[0] = '\0'; return; } - + if (ata_device_blacklisted(dev) & ATA_HORKAGE_NONCQ) { + snprintf(desc, desc_sz, "NCQ (not used)"); + return; + } if (ap->flags & ATA_FLAG_NCQ) { hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1); dev->flags |= ATA_DFLAG_NCQ; @@ -3014,37 +3017,55 @@ int ata_dev_revalidate(struct ata_device *dev, int post_reset) return rc; } -static const char * const ata_dma_blacklist [] = { - "WDC AC11000H", NULL, - "WDC AC22100H", NULL, - "WDC AC32500H", NULL, - "WDC AC33100H", NULL, - "WDC AC31600H", NULL, - "WDC AC32100H", "24.09P07", - "WDC AC23200L", "21.10N21", - "Compaq CRD-8241B", NULL, - "CRD-8400B", NULL, - "CRD-8480B", NULL, - "CRD-8482B", NULL, - "CRD-84", NULL, - "SanDisk SDP3B", NULL, - "SanDisk SDP3B-64", NULL, - "SANYO CD-ROM CRD", NULL, - "HITACHI CDR-8", NULL, - "HITACHI CDR-8335", NULL, - "HITACHI CDR-8435", NULL, - "Toshiba CD-ROM XM-6202B", NULL, - "TOSHIBA CD-ROM XM-1702BC", NULL, - "CD-532E-A", NULL, - "E-IDE CD-ROM CR-840", NULL, - "CD-ROM Drive/F5A", NULL, - "WPI CDD-820", NULL, - "SAMSUNG CD-ROM SC-148C", NULL, - "SAMSUNG CD-ROM SC", NULL, - "SanDisk SDP3B-64", NULL, - "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL, - "_NEC DV5800A", NULL, - "SAMSUNG CD-ROM SN-124", "N001" +struct ata_blacklist_entry { + const char *model_num; + const char *model_rev; + unsigned long horkage; +}; + +static const struct ata_blacklist_entry ata_device_blacklist [] = { + /* Devices with DMA related problems under Linux */ + { "WDC AC11000H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC22100H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC32500H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC33100H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC31600H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC32100H", "24.09P07", ATA_HORKAGE_NODMA }, + { "WDC AC23200L", "21.10N21", ATA_HORKAGE_NODMA }, + { "Compaq CRD-8241B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8400B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8480B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8482B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-84", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA }, + { "SANYO CD-ROM CRD", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8335", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8435", NULL, ATA_HORKAGE_NODMA }, + { "Toshiba CD-ROM XM-6202B", NULL, ATA_HORKAGE_NODMA }, + { "TOSHIBA CD-ROM XM-1702BC", NULL, ATA_HORKAGE_NODMA }, + { "CD-532E-A", NULL, ATA_HORKAGE_NODMA }, + { "E-IDE CD-ROM CR-840",NULL, ATA_HORKAGE_NODMA }, + { "CD-ROM Drive/F5A", NULL, ATA_HORKAGE_NODMA }, + { "WPI CDD-820", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SC-148C", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SC", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA }, + { "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,ATA_HORKAGE_NODMA }, + { "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SN-124","N001", ATA_HORKAGE_NODMA }, + + /* Devices we expect to fail diagnostics */ + + /* Devices where NCQ should be avoided */ + /* NCQ is slow */ + { "WDC WD740ADFD-00", NULL, ATA_HORKAGE_NONCQ }, + + /* Devices with NCQ limits */ + + /* End Marker */ + { } }; static int ata_strim(char *s, size_t len) @@ -3059,20 +3080,12 @@ static int ata_strim(char *s, size_t len) return len; } -static int ata_dma_blacklisted(const struct ata_device *dev) +unsigned long ata_device_blacklisted(const struct ata_device *dev) { unsigned char model_num[40]; unsigned char model_rev[16]; unsigned int nlen, rlen; - int i; - - /* We don't support polling DMA. - * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) - * if the LLDD handles only interrupts in the HSM_ST_LAST state. - */ - if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && - (dev->flags & ATA_DFLAG_CDB_INTR)) - return 1; + const struct ata_blacklist_entry *ad = ata_device_blacklist; ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); @@ -3081,17 +3094,30 @@ static int ata_dma_blacklisted(const struct ata_device *dev) nlen = ata_strim(model_num, sizeof(model_num)); rlen = ata_strim(model_rev, sizeof(model_rev)); - for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i += 2) { - if (!strncmp(ata_dma_blacklist[i], model_num, nlen)) { - if (ata_dma_blacklist[i+1] == NULL) - return 1; - if (!strncmp(ata_dma_blacklist[i], model_rev, rlen)) - return 1; + while (ad->model_num) { + if (!strncmp(ad->model_num, model_num, nlen)) { + if (ad->model_rev == NULL) + return ad->horkage; + if (!strncmp(ad->model_rev, model_rev, rlen)) + return ad->horkage; } + ad++; } return 0; } +static int ata_dma_blacklisted(const struct ata_device *dev) +{ + /* We don't support polling DMA. + * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) + * if the LLDD handles only interrupts in the HSM_ST_LAST state. + */ + if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && + (dev->flags & ATA_DFLAG_CDB_INTR)) + return 1; + return (ata_device_blacklisted(dev) & ATA_HORKAGE_NODMA) ? 1 : 0; +} + /** * ata_dev_xfermask - Compute supported xfermask of the given device * @dev: Device to compute xfermask for @@ -6153,6 +6179,7 @@ EXPORT_SYMBOL_GPL(ata_host_suspend); EXPORT_SYMBOL_GPL(ata_host_resume); EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); +EXPORT_SYMBOL_GPL(ata_device_blacklisted); EXPORT_SYMBOL_GPL(ata_scsi_simulate); EXPORT_SYMBOL_GPL(ata_pio_need_iordy); diff --git a/include/linux/libata.h b/include/linux/libata.h index abd2debebca2..2300fcc37f80 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -307,6 +307,8 @@ enum { (some horkage may be drive/controller pair dependant */ ATA_HORKAGE_DIAGNOSTIC = (1 << 0), /* Failed boot diag */ + ATA_HORKAGE_NODMA = (1 << 1), /* DMA problems */ + ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */ }; enum hsm_task_states { @@ -787,6 +789,7 @@ extern void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); +extern unsigned long ata_device_blacklisted(const struct ata_device *dev); extern void ata_bmdma_setup (struct ata_queued_cmd *qc); extern void ata_bmdma_start (struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); -- cgit v1.2.3 From a20c9e820864e18b59d2a4f2f04e8b6053986c95 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 27 Oct 2006 19:08:48 -0700 Subject: [PATCH] ata: Generic platform_device libata driver needs a changelog Signed-off-by: Paul Mundt Acked-by: Russell King Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 ++ drivers/ata/Makefile | 1 + drivers/ata/pata_platform.c | 295 ++++++++++++++++++++++++++++++++++++++++++ include/linux/pata_platform.h | 13 ++ 4 files changed, 318 insertions(+) create mode 100644 drivers/ata/pata_platform.c create mode 100644 include/linux/pata_platform.h (limited to 'include/linux') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 9b07e70bee7d..98d0f01c90eb 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -499,6 +499,15 @@ config PATA_WINBOND_VLB Support for the Winbond W83759A controller on Vesa Local Bus systems. +config PATA_PLATFORM + tristate "Generic platform device PATA support" + depends on EMBEDDED + help + This option enables support for generic directly connected ATA + devices commonly found on embedded systems. + + If unsure, say N. + endif endmenu diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index ceba7d824a62..f2b3ea2d15d0 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o obj-$(CONFIG_PATA_SIS) += pata_sis.o obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o +obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c new file mode 100644 index 000000000000..63d6687f0ba9 --- /dev/null +++ b/drivers/ata/pata_platform.c @@ -0,0 +1,295 @@ +/* + * Generic platform device PATA driver + * + * Copyright (C) 2006 Paul Mundt + * + * Based on pata_pcmcia: + * + * Copyright 2005-2006 Red Hat Inc , all rights reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_platform" +#define DRV_VERSION "0.1.2" + +static int pio_mask = 1; + +/* + * Provide our own set_mode() as we don't want to change anything that has + * already been configured.. + */ +static void pata_platform_set_mode(struct ata_port *ap) +{ + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + + if (ata_dev_enabled(dev)) { + /* We don't really care */ + dev->pio_mode = dev->xfer_mode = XFER_PIO_0; + dev->xfer_shift = ATA_SHIFT_PIO; + dev->flags |= ATA_DFLAG_PIO; + } + } +} + +static void pata_platform_host_stop(struct ata_host *host) +{ + int i; + + /* + * Unmap the bases for MMIO + */ + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap->flags & ATA_FLAG_MMIO) { + iounmap((void __iomem *)ap->ioaddr.ctl_addr); + iounmap((void __iomem *)ap->ioaddr.cmd_addr); + } + } +} + +static struct scsi_host_template pata_platform_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations pata_platform_port_ops = { + .set_mode = pata_platform_set_mode, + + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_pio_data_xfer_noirq, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = pata_platform_host_stop +}; + +static void pata_platform_setup_port(struct ata_ioports *ioaddr, + struct pata_platform_info *info) +{ + unsigned int shift = 0; + + /* Fixup the port shift for platforms that need it */ + if (info && info->ioport_shift) + shift = info->ioport_shift; + + ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift); + ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift); + ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift); + ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << shift); + ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << shift); + ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << shift); + ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << shift); + ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << shift); + ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << shift); + ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << shift); +} + +/** + * pata_platform_probe - attach a platform interface + * @pdev: platform device + * + * Register a platform bus IDE interface. Such interfaces are PIO and we + * assume do not support IRQ sharing. + * + * Platform devices are expected to contain 3 resources per port: + * + * - I/O Base (IORESOURCE_IO or IORESOURCE_MEM) + * - CTL Base (IORESOURCE_IO or IORESOURCE_MEM) + * - IRQ (IORESOURCE_IRQ) + * + * If the base resources are both mem types, the ioremap() is handled + * here. For IORESOURCE_IO, it's assumed that there's no remapping + * necessary. + */ +static int __devinit pata_platform_probe(struct platform_device *pdev) +{ + struct resource *io_res, *ctl_res; + struct ata_probe_ent ae; + unsigned int mmio; + int ret; + + /* + * Simple resource validation .. + */ + if (unlikely(pdev->num_resources != 3)) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + /* + * Get the I/O base first + */ + io_res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (io_res == NULL) { + io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(io_res == NULL)) + return -EINVAL; + } + + /* + * Then the CTL base + */ + ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (ctl_res == NULL) { + ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (unlikely(ctl_res == NULL)) + return -EINVAL; + } + + /* + * Check for MMIO + */ + mmio = (( io_res->flags == IORESOURCE_MEM) && + (ctl_res->flags == IORESOURCE_MEM)); + + /* + * Now that that's out of the way, wire up the port.. + */ + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + ae.port_ops = &pata_platform_port_ops; + ae.sht = &pata_platform_sht; + ae.n_ports = 1; + ae.pio_mask = pio_mask; + ae.irq = platform_get_irq(pdev, 0); + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + + /* + * Handle the MMIO case + */ + if (mmio) { + ae.port_flags |= ATA_FLAG_MMIO; + + ae.port[0].cmd_addr = (unsigned long)ioremap(io_res->start, + io_res->end - io_res->start + 1); + if (unlikely(!ae.port[0].cmd_addr)) { + dev_err(&pdev->dev, "failed to remap IO base\n"); + return -ENXIO; + } + + ae.port[0].ctl_addr = (unsigned long)ioremap(ctl_res->start, + ctl_res->end - ctl_res->start + 1); + if (unlikely(!ae.port[0].ctl_addr)) { + dev_err(&pdev->dev, "failed to remap CTL base\n"); + ret = -ENXIO; + goto bad_remap; + } + } else { + ae.port[0].cmd_addr = io_res->start; + ae.port[0].ctl_addr = ctl_res->start; + } + + ae.port[0].altstatus_addr = ae.port[0].ctl_addr; + + pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data); + + if (unlikely(ata_device_add(&ae) == 0)) { + ret = -ENODEV; + goto add_failed; + } + + return 0; + +add_failed: + if (ae.port[0].ctl_addr && mmio) + iounmap((void __iomem *)ae.port[0].ctl_addr); +bad_remap: + if (ae.port[0].cmd_addr && mmio) + iounmap((void __iomem *)ae.port[0].cmd_addr); + + return ret; +} + +/** + * pata_platform_remove - unplug a platform interface + * @pdev: platform device + * + * A platform bus ATA device has been unplugged. Perform the needed + * cleanup. Also called on module unload for any active devices. + */ +static int __devexit pata_platform_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + + ata_host_remove(host); + dev_set_drvdata(dev, NULL); + + return 0; +} + +static struct platform_driver pata_platform_driver = { + .probe = pata_platform_probe, + .remove = __devexit_p(pata_platform_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init pata_platform_init(void) +{ + return platform_driver_register(&pata_platform_driver); +} + +static void __exit pata_platform_exit(void) +{ + platform_driver_unregister(&pata_platform_driver); +} +module_init(pata_platform_init); +module_exit(pata_platform_exit); + +module_param(pio_mask, int, 0); + +MODULE_AUTHOR("Paul Mundt"); +MODULE_DESCRIPTION("low-level driver for platform device ATA"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); diff --git a/include/linux/pata_platform.h b/include/linux/pata_platform.h new file mode 100644 index 000000000000..2d5fd647e0e9 --- /dev/null +++ b/include/linux/pata_platform.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_PATA_PLATFORM_H +#define __LINUX_PATA_PLATFORM_H + +struct pata_platform_info { + /* + * I/O port shift, for platforms with ports that are + * constantly spaced and need larger than the 1-byte + * spacing used by ata_std_ports(). + */ + unsigned int ioport_shift; +}; + +#endif /* __LINUX_PATA_PLATFORM_H */ -- cgit v1.2.3 From d1adc1bbd6dde3e05a91e2d3e6ab42d202ea61d5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 9 Oct 2006 18:32:15 +0900 Subject: [PATCH] libata: handle 0xff status properly libata waits for !BSY even when the status register reports 0xff. This causes long boot delays when D8 isn't pulled down properly. This patch does the followings. * don't wait if status register is 0xff in all wait functions * make ata_busy_sleep() return 0 on success and -errno on failure. -ENODEV is returned on 0xff status and -EBUSY on other failures. * make ata_bus_softreset() succeed on 0xff status. 0xff status is not reset failure. It indicates no device. This removes unnecessary retries on such ports. Note that the code change assumes unoccupied port reporting 0xff status does not produce valid device signature. Signed-off-by: Tejun Heo Cc: Joe Jin Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 30 ++++++++++++++++++------------ include/linux/libata.h | 9 ++++----- 2 files changed, 22 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b4fbfebafd26..d2336673601c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2328,11 +2328,14 @@ static inline void ata_tf_to_host(struct ata_port *ap, * Sleep until ATA Status register bit BSY clears, * or a timeout occurs. * - * LOCKING: None. + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. */ - -unsigned int ata_busy_sleep (struct ata_port *ap, - unsigned long tmout_pat, unsigned long tmout) +int ata_busy_sleep(struct ata_port *ap, + unsigned long tmout_pat, unsigned long tmout) { unsigned long timer_start, timeout; u8 status; @@ -2340,27 +2343,32 @@ unsigned int ata_busy_sleep (struct ata_port *ap, status = ata_busy_wait(ap, ATA_BUSY, 300); timer_start = jiffies; timeout = timer_start + tmout_pat; - while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) { + while (status != 0xff && (status & ATA_BUSY) && + time_before(jiffies, timeout)) { msleep(50); status = ata_busy_wait(ap, ATA_BUSY, 3); } - if (status & ATA_BUSY) + if (status != 0xff && (status & ATA_BUSY)) ata_port_printk(ap, KERN_WARNING, "port is slow to respond, please be patient " "(Status 0x%x)\n", status); timeout = timer_start + tmout; - while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) { + while (status != 0xff && (status & ATA_BUSY) && + time_before(jiffies, timeout)) { msleep(50); status = ata_chk_status(ap); } + if (status == 0xff) + return -ENODEV; + if (status & ATA_BUSY) { ata_port_printk(ap, KERN_ERR, "port failed to respond " "(%lu secs, Status 0x%x)\n", tmout / HZ, status); - return 1; + return -EBUSY; } return 0; @@ -2451,10 +2459,8 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, * the bus shows 0xFF because the odd clown forgets the D7 * pulldown resistor. */ - if (ata_check_status(ap) == 0xFF) { - ata_port_printk(ap, KERN_ERR, "SRST failed (status 0xFF)\n"); - return AC_ERR_OTHER; - } + if (ata_check_status(ap) == 0xFF) + return 0; ata_bus_post_reset(ap, devmask); diff --git a/include/linux/libata.h b/include/linux/libata.h index 2300fcc37f80..6c003d852a88 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -746,9 +746,8 @@ extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t mesg); extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); extern void ata_host_resume(struct ata_host *host); extern int ata_ratelimit(void); -extern unsigned int ata_busy_sleep(struct ata_port *ap, - unsigned long timeout_pat, - unsigned long timeout); +extern int ata_busy_sleep(struct ata_port *ap, + unsigned long timeout_pat, unsigned long timeout); extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, unsigned long delay); extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, @@ -1064,7 +1063,7 @@ static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits, udelay(10); status = ata_chk_status(ap); max--; - } while ((status & bits) && (max > 0)); + } while (status != 0xff && (status & bits) && (max > 0)); return status; } @@ -1085,7 +1084,7 @@ static inline u8 ata_wait_idle(struct ata_port *ap) { u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - if (status & (ATA_BUSY | ATA_DRQ)) { + if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ))) { unsigned long l = ap->ioaddr.status_addr; if (ata_msg_warn(ap)) printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%lX\n", -- cgit v1.2.3 From 90088bb41200b4da962282dfd45db82544adac3b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 9 Oct 2006 11:10:26 +0900 Subject: [PATCH] libata: move ata_irq_on() into libata-sff.c ata_irq_on() isn't used outside of libata core layer. The function is TF/SFF interface specific but currently used by core path with some hack too. Move it from include/linux/libata.h to drivers/ata/libata-sff.c. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-sff.c | 29 +++++++++++++++++++++++++++++ drivers/ata/libata.h | 3 +++ include/linux/libata.h | 31 ------------------------------- 3 files changed, 32 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index e178d6ae8b80..37471d3c1c28 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -38,6 +38,35 @@ #include "libata.h" +/** + * ata_irq_on - Enable interrupts on a port. + * @ap: Port on which interrupts are enabled. + * + * Enable interrupts on a legacy IDE device using MMIO or PIO, + * wait for idle, clear any pending interrupts. + * + * LOCKING: + * Inherited from caller. + */ +u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ap->flags & ATA_FLAG_MMIO) + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); + else + outb(ap->ctl, ioaddr->ctl_addr); + tmp = ata_wait_idle(ap); + + ap->ops->irq_clear(ap); + + return tmp; +} + /** * ata_tf_load_pio - send taskfile registers to host controller * @ap: Port to which output is sent diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0ed263be652a..c83300055ec5 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -120,4 +120,7 @@ extern void ata_scsi_error(struct Scsi_Host *host); extern void ata_port_wait_eh(struct ata_port *ap); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); +/* libata-sff.c */ +extern u8 ata_irq_on(struct ata_port *ap); + #endif /* __LIBATA_H__ */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 6c003d852a88..d3bf7b936c3f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1149,37 +1149,6 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) qc->result_tf.feature = 0; } -/** - * ata_irq_on - Enable interrupts on a port. - * @ap: Port on which interrupts are enabled. - * - * Enable interrupts on a legacy IDE device using MMIO or PIO, - * wait for idle, clear any pending interrupts. - * - * LOCKING: - * Inherited from caller. - */ - -static inline u8 ata_irq_on(struct ata_port *ap) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 tmp; - - ap->ctl &= ~ATA_NIEN; - ap->last_ctl = ap->ctl; - - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); - tmp = ata_wait_idle(ap); - - ap->ops->irq_clear(ap); - - return tmp; -} - - /** * ata_irq_ack - Acknowledge a device interrupt. * @ap: Port on which interrupts are enabled. -- cgit v1.2.3 From b6103f6d1659e2024776bc759d28613fb36344a8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 1 Nov 2006 17:59:53 +0900 Subject: [PATCH] libata: separate out and export sata_port_hardreset() Separate out sata_port_hardreset() from sata_std_hardreset(). This will be used by LLD hardreset implementation and later by PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 52 ++++++++++++++++++++++++++++++++++++++--------- include/linux/libata.h | 2 ++ 2 files changed, 44 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d2336673601c..315f46841f68 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2786,9 +2786,9 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) } /** - * sata_std_hardreset - reset host port via SATA phy reset + * sata_port_hardreset - reset port via SATA phy reset * @ap: port to reset - * @class: resulting class of attached device + * @timing: timing parameters { interval, duratinon, timeout } in msec * * SATA phy-reset host port using DET bits of SControl register. * @@ -2798,10 +2798,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) * RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset(struct ata_port *ap, unsigned int *class) +int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing) { - struct ata_eh_context *ehc = &ap->eh_context; - const unsigned long *timing = sata_ehc_deb_timing(ehc); u32 scontrol; int rc; @@ -2814,24 +2812,24 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) * and Sil3124. */ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) - return rc; + goto out; scontrol = (scontrol & 0x0f0) | 0x304; if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) - return rc; + goto out; sata_set_spd(ap); } /* issue phy wake/reset */ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) - return rc; + goto out; scontrol = (scontrol & 0x0f0) | 0x301; if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol))) - return rc; + goto out; /* Couldn't find anything in SATA I/II specs, but AHCI-1.1 * 10.4.2 says at least 1 ms. @@ -2839,7 +2837,40 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) msleep(1); /* bring phy back */ - sata_phy_resume(ap, timing); + rc = sata_phy_resume(ap, timing); + out: + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * sata_std_hardreset - reset host port via SATA phy reset + * @ap: port to reset + * @class: resulting class of attached device + * + * SATA phy-reset host port using DET bits of SControl register, + * wait for !BSY and classify the attached device. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int sata_std_hardreset(struct ata_port *ap, unsigned int *class) +{ + const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + int rc; + + DPRINTK("ENTER\n"); + + /* do hardreset */ + rc = sata_port_hardreset(ap, timing); + if (rc) { + ata_port_printk(ap, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + return rc; + } /* TODO: phy layer with polling, timeouts, etc. */ if (ata_port_offline(ap)) { @@ -6159,6 +6190,7 @@ EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); +EXPORT_SYMBOL_GPL(sata_port_hardreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); diff --git a/include/linux/libata.h b/include/linux/libata.h index d3bf7b936c3f..41fa0890dbfb 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -702,6 +702,8 @@ extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param); extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param); extern int ata_std_prereset(struct ata_port *ap); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); +extern int sata_port_hardreset(struct ata_port *ap, + const unsigned long *timing); extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); extern void ata_port_disable(struct ata_port *); -- cgit v1.2.3 From efdaedc443e935eda82e9e78a6e65d1f993d242f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 1 Nov 2006 18:38:52 +0900 Subject: [PATCH] libata: implement ATA_EHI_PRINTINFO Implement ehi flag ATA_EHI_PRINTINFO. This flag is set when device configuration needs to print out device info. This used to be handled by @print_info argument to ata_dev_configure() but LLDs also need to know about it in ->dev_config() callback. This patch replaces @print_info w/ ATA_EHI_PRINTINFO and make sata_sil print workaround messages only on the initial configuration. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 10 ++++++---- drivers/ata/libata-eh.c | 7 +++++-- drivers/ata/libata.h | 2 +- drivers/ata/sata_sil.c | 11 +++++++---- include/linux/libata.h | 1 + 5 files changed, 20 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 315f46841f68..e294731a7edd 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1377,7 +1377,6 @@ static void ata_set_port_max_cmd_len(struct ata_port *ap) /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure - * @print_info: Enable device info printout * * Configure @dev according to @dev->id. Generic and low-level * driver specific fixups are also applied. @@ -1388,9 +1387,10 @@ static void ata_set_port_max_cmd_len(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise */ -int ata_dev_configure(struct ata_device *dev, int print_info) +int ata_dev_configure(struct ata_device *dev) { struct ata_port *ap = dev->ap; + int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; unsigned int xfer_mask; char revbuf[7]; /* XYZ-99\0 */ @@ -1638,7 +1638,9 @@ int ata_bus_probe(struct ata_port *ap) if (rc) goto fail; - rc = ata_dev_configure(dev, 1); + ap->eh_context.i.flags |= ATA_EHI_PRINTINFO; + rc = ata_dev_configure(dev); + ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO; if (rc) goto fail; } @@ -3045,7 +3047,7 @@ int ata_dev_revalidate(struct ata_device *dev, int post_reset) memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS); /* configure device according to the new ID */ - rc = ata_dev_configure(dev, 0); + rc = ata_dev_configure(dev); if (rc == 0) return 0; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 02b2b2787d9b..7c446442616c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1661,8 +1661,11 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, dev->class = ehc->classes[dev->devno]; rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); - if (rc == 0) - rc = ata_dev_configure(dev, 1); + if (rc == 0) { + ehc->i.flags |= ATA_EHI_PRINTINFO; + rc = ata_dev_configure(dev); + ehc->i.flags &= ~ATA_EHI_PRINTINFO; + } if (rc) { dev->class = ATA_DEV_UNKNOWN; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index c83300055ec5..e4ffb2e38992 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -54,7 +54,7 @@ extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, int post_reset, u16 *id); extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); -extern int ata_dev_configure(struct ata_device *dev, int print_info); +extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0); diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index ca8d99312472..f844a1faba18 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -534,6 +534,7 @@ static void sil_thaw(struct ata_port *ap) */ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) { + int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; unsigned int n, quirks = 0; unsigned char model_num[41]; @@ -549,16 +550,18 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) if (slow_down || ((ap->flags & SIL_FLAG_MOD15WRITE) && (quirks & SIL_QUIRK_MOD15WRITE))) { - ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix " - "(mod15write workaround)\n"); + if (print_info) + ata_dev_printk(dev, KERN_INFO, "applying Seagate " + "errata fix (mod15write workaround)\n"); dev->max_sectors = 15; return; } /* limit to udma5 */ if (quirks & SIL_QUIRK_UDMA5MAX) { - ata_dev_printk(dev, KERN_INFO, - "applying Maxtor errata fix %s\n", model_num); + if (print_info) + ata_dev_printk(dev, KERN_INFO, "applying Maxtor " + "errata fix %s\n", model_num); dev->udma_mask &= ATA_UDMA5; return; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 41fa0890dbfb..949484627e67 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -283,6 +283,7 @@ enum { ATA_EHI_QUIET = (1 << 3), /* be quiet */ ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ + ATA_EHI_PRINTINFO = (1 << 17), /* print configuration info */ ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, -- cgit v1.2.3 From baa1e78a834c917984a4659fd282f712c17ee3bf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 1 Nov 2006 18:39:27 +0900 Subject: [PATCH] libata: implement ATA_EHI_SETMODE and ATA_EHI_POST_SETMODE libata EH used to perform ata_set_mode() iff the EH session performed reset as indicated by ATA_EHI_DID_RESET. This is incorrect because ->dev_config() called by revalidation is allowed to modify transfer mode which ata_set_mode() should take care of. This patch implements the following two flags. * ATA_EHI_SETMODE: set during EH to schedule ata_set_mode(). Both new device attachment and revalidation set this flag. * ATA_EHI_POST_SETMODE: set while the device is revalidated after ata_set_mode(). Post-setmode revalidation is different from initial configuaration and EH revalidation in that ->dev_config() is not allowed tune transfer mode. LLD can use this flag to determine whether it's allowed to tune transfer mode. Note that POST_SETMODE ->dev_config() is guaranteed to be preceded by non-POST_SETMODE ->dev_config(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 3 +++ drivers/ata/libata-eh.c | 13 +++++++++++-- include/linux/libata.h | 2 ++ 3 files changed, 16 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index e294731a7edd..5028396029b3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2158,6 +2158,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0) static int ata_dev_set_mode(struct ata_device *dev) { + struct ata_eh_context *ehc = &dev->ap->eh_context; unsigned int err_mask; int rc; @@ -2172,7 +2173,9 @@ static int ata_dev_set_mode(struct ata_device *dev) return -EIO; } + ehc->i.flags |= ATA_EHI_POST_SETMODE; rc = ata_dev_revalidate(dev, 0); + ehc->i.flags &= ~ATA_EHI_POST_SETMODE; if (rc) return rc; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7c446442616c..477648801a65 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1653,6 +1653,11 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, ata_eh_done(ap, dev, ATA_EH_REVALIDATE); + /* Configuration may have changed, reconfigure + * transfer mode. + */ + ehc->i.flags |= ATA_EHI_SETMODE; + /* schedule the scsi_rescan_device() here */ queue_work(ata_aux_wq, &(ap->scsi_rescan_task)); } else if (dev->class == ATA_DEV_UNKNOWN && @@ -1675,6 +1680,9 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, spin_lock_irqsave(ap->lock, flags); ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; spin_unlock_irqrestore(ap->lock, flags); + + /* new device discovered, configure transfer mode */ + ehc->i.flags |= ATA_EHI_SETMODE; } } @@ -1990,13 +1998,14 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (rc) goto dev_fail; - /* configure transfer mode if the port has been reset */ - if (ehc->i.flags & ATA_EHI_DID_RESET) { + /* configure transfer mode if necessary */ + if (ehc->i.flags & ATA_EHI_SETMODE) { rc = ata_set_mode(ap, &dev); if (rc) { down_xfermask = 1; goto dev_fail; } + ehc->i.flags &= ~ATA_EHI_SETMODE; } /* suspend devices */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 949484627e67..0d0ddeaee73f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -284,6 +284,8 @@ enum { ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ ATA_EHI_PRINTINFO = (1 << 17), /* print configuration info */ + ATA_EHI_SETMODE = (1 << 18), /* configure transfer mode */ + ATA_EHI_POST_SETMODE = (1 << 19), /* revaildating after setmode */ ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, -- cgit v1.2.3 From 6fc49adb9417b9c793e8f88d485387bb89ceb733 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 11 Nov 2006 20:10:45 +0900 Subject: [PATCH] libata: use FLUSH_EXT only when driver is larger than LBA28 limit Many drives support LBA48 even when its capacity is smaller than 1<<28, as LBA48 is required for many functionalities. FLUSH_EXT is mandatory for drives w/ LBA48 support. Interestingly, at least one of such drives (ST960812A) has problems dealing with FLUSH_EXT. It eventually completes the command but takes around 7 seconds to finish in many cases thus drastically slowing down IO transactions. This seems to be a firmware bug which sneaked into production probably because no other ATA driver including linux IDE issues FLUSH_EXT to drives which report support for LBA48 & FLUSH_EXT but is smaller than 1<<28 blocks. This patch adds ATA_DFLAG_FLUSH_EXT which is set iff the drive supports LBA48 & FLUSH_EXT and is larger than LBA28 limit. Both cache flush paths are updated to issue FLUSH_EXT only when the flag is set. Note that the changed behavior is more inline with the rest of libata. libata prefers shorter commands whenever possible. Signed-off-by: Tejun Heo Cc: Danny Kukawka Cc: Stefan Seyfried Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 6 +++++- drivers/ata/libata-scsi.c | 3 +-- include/linux/libata.h | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f531a89c26c9..d94b8a02c340 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1457,6 +1457,10 @@ int ata_dev_configure(struct ata_device *dev) if (ata_id_has_lba48(id)) { dev->flags |= ATA_DFLAG_LBA48; lba_desc = "LBA48"; + + if (dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + dev->flags |= ATA_DFLAG_FLUSH_EXT; } /* config NCQ */ @@ -5128,7 +5132,7 @@ int ata_flush_cache(struct ata_device *dev) if (!ata_try_flush_cache(dev)) return 0; - if (ata_id_has_flush_ext(dev->id)) + if (dev->flags & ATA_DFLAG_FLUSH_EXT) cmd = ATA_CMD_FLUSH_EXT; else cmd = ATA_CMD_FLUSH; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index f13dd07a5331..7a55c2e4ea6e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1027,8 +1027,7 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scs tf->flags |= ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - if ((qc->dev->flags & ATA_DFLAG_LBA48) && - (ata_id_has_flush_ext(qc->dev->id))) + if (qc->dev->flags & ATA_DFLAG_FLUSH_EXT) tf->command = ATA_CMD_FLUSH_EXT; else tf->command = ATA_CMD_FLUSH; diff --git a/include/linux/libata.h b/include/linux/libata.h index 0d0ddeaee73f..36e233cc3886 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -140,6 +140,7 @@ enum { ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ when ready for CDB */ ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */ + ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */ -- cgit v1.2.3 From 55a8e2c83ce50548dfef74bb19dfe2b809cb3099 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Nov 2006 18:08:10 +0900 Subject: [PATCH] libata: implement presence detection via polling IDENTIFY On some controllers (ICHs in piix mode), there is *NO* reliable way to determine device presence other than issuing IDENTIFY and see how the transaction proceeds by watching the TF status register. libata acted this way before irq-pio and phantom devices caused very little problem but now that IDENTIFY is performed using IRQ drive PIO, such phantom devices now result in multiple 30sec timeouts during boot. This patch implements ATA_FLAG_DETECT_POLLING. If a LLD sets this flag, libata core issues the initial IDENTIFY in polling mode and if the initial data transfer fails w/ HSM violation, the port is considered to be empty thus replicating the old libata and IDE behavior. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 19 +++++++++++++++++-- drivers/ata/libata-eh.c | 23 ++++++++++++++++++----- drivers/ata/libata.h | 2 ++ include/linux/libata.h | 3 +++ 4 files changed, 40 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 090abe443820..21f8d61e5879 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1272,9 +1272,20 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, tf.protocol = ATA_PROT_PIO; + /* presence detection using polling IDENTIFY? */ + if (flags & ATA_READID_DETECT) + tf.flags |= ATA_TFLAG_POLLING; + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, id, sizeof(id[0]) * ATA_ID_WORDS); if (err_mask) { + if ((flags & ATA_READID_DETECT) && + (err_mask & AC_ERR_NODEV_HINT)) { + DPRINTK("ata%u.%d: NODEV after polling detection\n", + ap->id, dev->devno); + return -ENOENT; + } + rc = -EIO; reason = "I/O error"; goto err_out; @@ -4285,8 +4296,12 @@ fsm_start: /* device stops HSM for abort/error */ qc->err_mask |= AC_ERR_DEV; else - /* HSM violation. Let EH handle this */ - qc->err_mask |= AC_ERR_HSM; + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | + AC_ERR_NODEV_HINT; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 755fc68b5374..e69f3df2ea39 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1667,12 +1667,23 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, ata_class_enabled(ehc->classes[dev->devno])) { dev->class = ehc->classes[dev->devno]; + if (ap->flags & ATA_FLAG_DETECT_POLLING) + readid_flags |= ATA_READID_DETECT; + rc = ata_dev_read_id(dev, &dev->class, readid_flags, dev->id); if (rc == 0) { ehc->i.flags |= ATA_EHI_PRINTINFO; rc = ata_dev_configure(dev); ehc->i.flags &= ~ATA_EHI_PRINTINFO; + } else if (rc == -ENOENT) { + /* IDENTIFY was issued to non-existent + * device. No need to reset. Just + * thaw and kill the device. + */ + ata_eh_thaw_port(ap); + dev->class = ATA_DEV_UNKNOWN; + rc = 0; } if (rc) { @@ -1680,12 +1691,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, break; } - spin_lock_irqsave(ap->lock, flags); - ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; - spin_unlock_irqrestore(ap->lock, flags); + if (ata_dev_enabled(dev)) { + spin_lock_irqsave(ap->lock, flags); + ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; + spin_unlock_irqrestore(ap->lock, flags); - /* new device discovered, configure transfer mode */ - ehc->i.flags |= ATA_EHI_SETMODE; + /* new device discovered, configure xfermode */ + ehc->i.flags |= ATA_EHI_SETMODE; + } } } diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index bb98390aa01a..be2ac39f013b 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -42,6 +42,8 @@ struct ata_scsi_args { enum { /* flags for ata_dev_read_id() */ ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ + ATA_READID_DETECT = (1 << 1), /* perform presence detection + * using polling IDENTIFY */ }; extern struct workqueue_struct *ata_aux_wq; diff --git a/include/linux/libata.h b/include/linux/libata.h index 36e233cc3886..9080789913f7 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -176,6 +176,8 @@ enum { ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H * Register FIS clearing BSY */ ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_DETECT_POLLING = (1 << 14), /* detect device presence by + * polling IDENTIFY */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be @@ -335,6 +337,7 @@ enum ata_completion_errors { AC_ERR_SYSTEM = (1 << 6), /* system error */ AC_ERR_INVALID = (1 << 7), /* invalid argument */ AC_ERR_OTHER = (1 << 8), /* unknown */ + AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */ }; /* forward declarations */ -- cgit v1.2.3 From 13df29f69749a61b5209d52b71fcbf7300e5d6fb Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 3 Oct 2006 16:18:28 +0100 Subject: [PATCH] 2.6.18: sb1250-mac: Missing inclusions from The uses some types and macros defined in , , and , but fails to include these headers. Signed-off-by: Maciej W. Rozycki patch-mips-2.6.18-20060920-include-phy-16 Signed-off-by: Jeff Garzik --- include/linux/phy.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/phy.h b/include/linux/phy.h index 9447a57ee8a9..ce8bc80b3c86 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -20,6 +20,10 @@ #include #include +#include +#include +#include +#include #define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ SUPPORTED_10baseT_Full | \ -- cgit v1.2.3 From fe75f7471ba5604fe65435f717e3612a482c28cb Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 2 Oct 2006 19:55:22 +0200 Subject: [PATCH] wext: extend MLME support This patch adds two new defines for the SIOCSIWMLME to cover all kinds MLMEs (well, except REASSOC) through a ioctl. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- include/linux/wireless.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/wireless.h b/include/linux/wireless.h index a50a0130fd9e..7c269f4992eb 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -546,6 +546,8 @@ /* MLME requests (SIOCSIWMLME / struct iw_mlme) */ #define IW_MLME_DEAUTH 0 #define IW_MLME_DISASSOC 1 +#define IW_MLME_AUTH 2 +#define IW_MLME_ASSOC 3 /* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ #define IW_AUTH_INDEX 0x0FFF -- cgit v1.2.3 From 52d78d63310d9818458fd9800d24a4d5425aeac7 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Mon, 6 Nov 2006 00:43:39 -0800 Subject: [PATCH] forcedeth: add new NVIDIA pci ids Add pci device ids for the NVIDIA MCP67 chip. Signed-off-by: Ayaz Abdulla Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- include/linux/pci_ids.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index e060a7637947..fd5033b8a927 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1213,6 +1213,10 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451 #define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452 #define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453 +#define PCI_DEVICE_ID_NVIDIA_NVENET_24 0x054C +#define PCI_DEVICE_ID_NVIDIA_NVENET_25 0x054D +#define PCI_DEVICE_ID_NVIDIA_NVENET_26 0x054E +#define PCI_DEVICE_ID_NVIDIA_NVENET_27 0x054F #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560 #define PCI_VENDOR_ID_IMS 0x10e0 -- cgit v1.2.3 From f789dfdc44d5bbc04fb7f06e1e4eb682169acaaf Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Thu, 30 Nov 2006 04:27:00 -0700 Subject: [PATCH] mv643xx_eth: fix unbalanced parentheses in macros Signed-off-by: Mariusz Kozlowski Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- include/linux/mv643xx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mv643xx.h b/include/linux/mv643xx.h index edfa012fad3a..aff25c000abf 100644 --- a/include/linux/mv643xx.h +++ b/include/linux/mv643xx.h @@ -724,7 +724,7 @@ #define MV643XX_ETH_RX_FIFO_URGENT_THRESHOLD_REG(port) (0x2470 + (port<<10)) #define MV643XX_ETH_TX_FIFO_URGENT_THRESHOLD_REG(port) (0x2474 + (port<<10)) #define MV643XX_ETH_RX_MINIMAL_FRAME_SIZE_REG(port) (0x247c + (port<<10)) -#define MV643XX_ETH_RX_DISCARDED_FRAMES_COUNTER(port) (0x2484 + (port<<10) +#define MV643XX_ETH_RX_DISCARDED_FRAMES_COUNTER(port) (0x2484 + (port<<10)) #define MV643XX_ETH_PORT_DEBUG_0_REG(port) (0x248c + (port<<10)) #define MV643XX_ETH_PORT_DEBUG_1_REG(port) (0x2490 + (port<<10)) #define MV643XX_ETH_PORT_INTERNAL_ADDR_ERROR_REG(port) (0x2494 + (port<<10)) @@ -1135,7 +1135,7 @@ struct mv64xxx_i2c_pdata { #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_1 (1<<19) #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_2 (1<<20) #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_3 ((1<<20) | (1<<19)) -#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_4 ((1<<21) +#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_4 (1<<21) #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_5 ((1<<21) | (1<<19)) #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_6 ((1<<21) | (1<<20)) #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_7 ((1<<21) | (1<<20) | (1<<19)) -- cgit v1.2.3 From e8a2b6a4207332a2d59628a12cece9e8c1d769e4 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Fri, 1 Dec 2006 12:01:06 -0600 Subject: [PATCH] PHY: Add support for configuring the PHY connection interface Most PHYs connect to an ethernet controller over a GMII or MII interface. However, a growing number are connected over different interfaces, such as RGMII or SGMII. The ethernet driver will tell the PHY what type of connection it is by setting it manually, or passing it in through phy_connect (or phy_attach). Changes include: * Updates to documentation * Updates to PHY Lib consumers * Changes to PHY Lib to add interface support * Some minor changes to whitespace in phy.h * gianfar driver now detects interface and passes appropriate value to PHY Lib Signed-off-by: Andrew Fleming Signed-off-by: Jeff Garzik --- Documentation/networking/phy.txt | 13 +++++++++---- drivers/net/au1000_eth.c | 3 ++- drivers/net/fs_enet/fs_enet-main.c | 3 ++- drivers/net/gianfar.c | 39 ++++++++++++++++++++++++++++++++++++-- drivers/net/gianfar.h | 3 +++ drivers/net/phy/phy_device.c | 29 +++++++++++++++++++--------- include/linux/phy.h | 26 +++++++++++++++++++------ 7 files changed, 93 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt index 29ccae409031..0bc95eab1512 100644 --- a/Documentation/networking/phy.txt +++ b/Documentation/networking/phy.txt @@ -1,7 +1,7 @@ ------- PHY Abstraction Layer -(Updated 2005-07-21) +(Updated 2006-11-30) Purpose @@ -97,11 +97,12 @@ Letting the PHY Abstraction Layer do Everything Next, you need to know the device name of the PHY connected to this device. The name will look something like, "phy0:0", where the first number is the - bus id, and the second is the PHY's address on that bus. + bus id, and the second is the PHY's address on that bus. Typically, + the bus is responsible for making its ID unique. Now, to connect, just call this function: - phydev = phy_connect(dev, phy_name, &adjust_link, flags); + phydev = phy_connect(dev, phy_name, &adjust_link, flags, interface); phydev is a pointer to the phy_device structure which represents the PHY. If phy_connect is successful, it will return the pointer. dev, here, is the @@ -115,6 +116,10 @@ Letting the PHY Abstraction Layer do Everything This is useful if the system has put hardware restrictions on the PHY/controller, of which the PHY needs to be aware. + interface is a u32 which specifies the connection type used + between the controller and the PHY. Examples are GMII, MII, + RGMII, and SGMII. For a full list, see include/linux/phy.h + Now just make sure that phydev->supported and phydev->advertising have any values pruned from them which don't make sense for your controller (a 10/100 controller may be connected to a gigabit capable PHY, so you would need to @@ -191,7 +196,7 @@ Doing it all yourself start, or disables then frees them for stop. struct phy_device * phy_attach(struct net_device *dev, const char *phy_id, - u32 flags); + u32 flags, phy_interface_t interface); Attaches a network device to a particular PHY, binding the PHY to a generic driver if none was found during bus initialization. Passes in diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 7db3c8af0894..f0b6879a1c7d 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -360,7 +360,8 @@ static int mii_probe (struct net_device *dev) BUG_ON(!phydev); BUG_ON(phydev->attached_dev); - phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0); + phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0, + PHY_INTERFACE_MODE_MII); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index cb3958704a87..889d3a13e95e 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -779,7 +779,8 @@ static int fs_init_phy(struct net_device *dev) fep->oldspeed = 0; fep->oldduplex = -1; if(fep->fpi->bus_id) - phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0); + phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0, + PHY_INTERFACE_MODE_MII); else { printk("No phy bus ID specified in BSP code\n"); return -EINVAL; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 6bf18c82083d..baa35144134c 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -9,7 +9,7 @@ * Author: Andy Fleming * Maintainer: Kumar Gala * - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * Copyright (c) 2002-2006 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -398,6 +398,38 @@ static int gfar_remove(struct platform_device *pdev) } +/* Reads the controller's registers to determine what interface + * connects it to the PHY. + */ +static phy_interface_t gfar_get_interface(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + u32 ecntrl = gfar_read(&priv->regs->ecntrl); + + if (ecntrl & ECNTRL_SGMII_MODE) + return PHY_INTERFACE_MODE_SGMII; + + if (ecntrl & ECNTRL_TBI_MODE) { + if (ecntrl & ECNTRL_REDUCED_MODE) + return PHY_INTERFACE_MODE_RTBI; + else + return PHY_INTERFACE_MODE_TBI; + } + + if (ecntrl & ECNTRL_REDUCED_MODE) { + if (ecntrl & ECNTRL_REDUCED_MII_MODE) + return PHY_INTERFACE_MODE_RMII; + else + return PHY_INTERFACE_MODE_RGMII; + } + + if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT) + return PHY_INTERFACE_MODE_GMII; + + return PHY_INTERFACE_MODE_MII; +} + + /* Initializes driver's PHY state, and attaches to the PHY. * Returns 0 on success. */ @@ -409,6 +441,7 @@ static int init_phy(struct net_device *dev) SUPPORTED_1000baseT_Full : 0; struct phy_device *phydev; char phy_id[BUS_ID_SIZE]; + phy_interface_t interface; priv->oldlink = 0; priv->oldspeed = 0; @@ -416,7 +449,9 @@ static int init_phy(struct net_device *dev) snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id); - phydev = phy_connect(dev, phy_id, &adjust_link, 0); + interface = gfar_get_interface(dev); + + phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 9e81a50cf2be..39e9e321fcbc 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -160,7 +160,10 @@ extern const char gfar_driver_version[]; #define ECNTRL_INIT_SETTINGS 0x00001000 #define ECNTRL_TBI_MODE 0x00000020 +#define ECNTRL_REDUCED_MODE 0x00000010 #define ECNTRL_R100 0x00000008 +#define ECNTRL_REDUCED_MII_MODE 0x00000004 +#define ECNTRL_SGMII_MODE 0x00000002 #define MRBLR_INIT_SETTINGS DEFAULT_RX_BUFFER_SIZE diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2a08b2b62c4c..b01fc70a57db 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -59,6 +59,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) dev->duplex = -1; dev->pause = dev->asym_pause = 0; dev->link = 1; + dev->interface = PHY_INTERFACE_MODE_GMII; dev->autoneg = AUTONEG_ENABLE; @@ -137,11 +138,12 @@ void phy_prepare_link(struct phy_device *phydev, * the desired functionality. */ struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, - void (*handler)(struct net_device *), u32 flags) + void (*handler)(struct net_device *), u32 flags, + u32 interface) { struct phy_device *phydev; - phydev = phy_attach(dev, phy_id, flags); + phydev = phy_attach(dev, phy_id, flags, interface); if (IS_ERR(phydev)) return phydev; @@ -186,7 +188,7 @@ static int phy_compare_id(struct device *dev, void *data) } struct phy_device *phy_attach(struct net_device *dev, - const char *phy_id, u32 flags) + const char *phy_id, u32 flags, u32 interface) { struct bus_type *bus = &mdio_bus_type; struct phy_device *phydev; @@ -231,6 +233,20 @@ struct phy_device *phy_attach(struct net_device *dev, phydev->dev_flags = flags; + phydev->interface = interface; + + /* Do initial configuration here, now that + * we have certain key parameters + * (dev_flags and interface) */ + if (phydev->drv->config_init) { + int err; + + err = phydev->drv->config_init(phydev); + + if (err < 0) + return ERR_PTR(err); + } + return phydev; } EXPORT_SYMBOL(phy_attach); @@ -612,13 +628,8 @@ static int phy_probe(struct device *dev) spin_unlock(&phydev->lock); - if (err < 0) - return err; - - if (phydev->drv->config_init) - err = phydev->drv->config_init(phydev); - return err; + } static int phy_remove(struct device *dev) diff --git a/include/linux/phy.h b/include/linux/phy.h index ce8bc80b3c86..edd4c88ca7d8 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -47,15 +47,26 @@ #define PHY_HAS_INTERRUPT 0x00000001 #define PHY_HAS_MAGICANEG 0x00000002 +/* Interface Mode definitions */ +typedef enum { + PHY_INTERFACE_MODE_MII, + PHY_INTERFACE_MODE_GMII, + PHY_INTERFACE_MODE_SGMII, + PHY_INTERFACE_MODE_TBI, + PHY_INTERFACE_MODE_RMII, + PHY_INTERFACE_MODE_RGMII, + PHY_INTERFACE_MODE_RTBI +} phy_interface_t; + #define MII_BUS_MAX 4 -#define PHY_INIT_TIMEOUT 100000 +#define PHY_INIT_TIMEOUT 100000 #define PHY_STATE_TIME 1 #define PHY_FORCE_TIMEOUT 10 #define PHY_AN_TIMEOUT 10 -#define PHY_MAX_ADDR 32 +#define PHY_MAX_ADDR 32 /* Used when trying to connect to a specific phy (mii bus id:phy device id) */ #define PHY_ID_FMT "%x:%02x" @@ -87,8 +98,8 @@ struct mii_bus { int *irq; }; -#define PHY_INTERRUPT_DISABLED 0x0 -#define PHY_INTERRUPT_ENABLED 0x80000000 +#define PHY_INTERRUPT_DISABLED 0x0 +#define PHY_INTERRUPT_ENABLED 0x80000000 /* PHY state machine states: * @@ -230,6 +241,8 @@ struct phy_device { u32 dev_flags; + phy_interface_t interface; + /* Bus address of the PHY (0-32) */ int addr; @@ -345,9 +358,10 @@ struct phy_device* get_phy_device(struct mii_bus *bus, int addr); int phy_clear_interrupt(struct phy_device *phydev); int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); struct phy_device * phy_attach(struct net_device *dev, - const char *phy_id, u32 flags); + const char *phy_id, u32 flags, phy_interface_t interface); struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, - void (*handler)(struct net_device *), u32 flags); + void (*handler)(struct net_device *), u32 flags, + phy_interface_t interface); void phy_disconnect(struct phy_device *phydev); void phy_detach(struct phy_device *phydev); void phy_start(struct phy_device *phydev); -- cgit v1.2.3 From 3e6c8cd5669c1202fe806ce3e13d701f20a71c7e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:19:09 -0800 Subject: [TIPC]: endianness annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/tipc_config.h | 32 ++++++++++++++++---------------- include/net/tipc/tipc_bearer.h | 2 +- include/net/tipc/tipc_msg.h | 2 +- net/tipc/config.c | 32 +++++++++++--------------------- net/tipc/dbg.c | 3 +-- net/tipc/name_distr.c | 10 +++++----- net/tipc/node.c | 9 +++------ 7 files changed, 38 insertions(+), 52 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tipc_config.h b/include/linux/tipc_config.h index 33a653913d94..b0c916d1f375 100644 --- a/include/linux/tipc_config.h +++ b/include/linux/tipc_config.h @@ -194,34 +194,34 @@ struct tipc_node_info { - __u32 addr; /* network address of node */ - __u32 up; /* 0=down, 1= up */ + __be32 addr; /* network address of node */ + __be32 up; /* 0=down, 1= up */ }; struct tipc_link_info { - __u32 dest; /* network address of peer node */ - __u32 up; /* 0=down, 1=up */ + __be32 dest; /* network address of peer node */ + __be32 up; /* 0=down, 1=up */ char str[TIPC_MAX_LINK_NAME]; /* link name */ }; struct tipc_bearer_config { - __u32 priority; /* Range [1,31]. Override per link */ - __u32 detect_scope; + __be32 priority; /* Range [1,31]. Override per link */ + __be32 detect_scope; char name[TIPC_MAX_BEARER_NAME]; }; struct tipc_link_config { - __u32 value; + __be32 value; char name[TIPC_MAX_LINK_NAME]; }; #define TIPC_NTQ_ALLTYPES 0x80000000 struct tipc_name_table_query { - __u32 depth; /* 1:type, 2:+name info, 3:+port info, 4+:+debug info */ - __u32 type; /* {t,l,u} info ignored if high bit of "depth" is set */ - __u32 lowbound; /* (i.e. displays all entries of name table) */ - __u32 upbound; + __be32 depth; /* 1:type, 2:+name info, 3:+port info, 4+:+debug info */ + __be32 type; /* {t,l,u} info ignored if high bit of "depth" is set */ + __be32 lowbound; /* (i.e. displays all entries of name table) */ + __be32 upbound; }; /* @@ -262,8 +262,8 @@ struct tipc_route_info { */ struct tlv_desc { - __u16 tlv_len; /* TLV length (descriptor + value) */ - __u16 tlv_type; /* TLV identifier */ + __be16 tlv_len; /* TLV length (descriptor + value) */ + __be16 tlv_type; /* TLV identifier */ }; #define TLV_ALIGNTO 4 @@ -377,9 +377,9 @@ struct tipc_genlmsghdr { struct tipc_cfg_msg_hdr { - __u32 tcm_len; /* Message length (including header) */ - __u16 tcm_type; /* Command type */ - __u16 tcm_flags; /* Additional flags */ + __be32 tcm_len; /* Message length (including header) */ + __be16 tcm_type; /* Command type */ + __be16 tcm_flags; /* Additional flags */ char tcm_reserved[8]; /* Unused */ }; diff --git a/include/net/tipc/tipc_bearer.h b/include/net/tipc/tipc_bearer.h index e07136d74c2f..2151a80cdf30 100644 --- a/include/net/tipc/tipc_bearer.h +++ b/include/net/tipc/tipc_bearer.h @@ -58,7 +58,7 @@ */ struct tipc_media_addr { - __u32 type; /* bearer type (network byte order) */ + __be32 type; /* bearer type (network byte order) */ union { __u8 eth_addr[6]; /* 48 bit Ethernet addr (byte array) */ #if 0 diff --git a/include/net/tipc/tipc_msg.h b/include/net/tipc/tipc_msg.h index 4d096eebc93f..fb42eb7a86a5 100644 --- a/include/net/tipc/tipc_msg.h +++ b/include/net/tipc/tipc_msg.h @@ -40,7 +40,7 @@ #ifdef __KERNEL__ struct tipc_msg { - u32 hdr[15]; + __be32 hdr[15]; }; diff --git a/net/tipc/config.c b/net/tipc/config.c index ed1351ed05e1..458a2c46cef3 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c @@ -107,7 +107,7 @@ int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type, struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value) { struct sk_buff *buf; - u32 value_net; + __be32 value_net; buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value))); if (buf) { @@ -284,8 +284,7 @@ static struct sk_buff *cfg_set_own_addr(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - addr = *(u32 *)TLV_DATA(req_tlv_area); - addr = ntohl(addr); + addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (addr == tipc_own_addr) return tipc_cfg_reply_none(); if (!tipc_addr_node_valid(addr)) @@ -319,8 +318,7 @@ static struct sk_buff *cfg_set_remote_mng(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); tipc_remote_management = (value != 0); return tipc_cfg_reply_none(); } @@ -332,8 +330,7 @@ static struct sk_buff *cfg_set_max_publications(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 1, 65535)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max publications must be 1-65535)"); @@ -348,8 +345,7 @@ static struct sk_buff *cfg_set_max_subscriptions(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 1, 65535)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max subscriptions must be 1-65535"); @@ -363,8 +359,7 @@ static struct sk_buff *cfg_set_max_ports(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_max_ports) return tipc_cfg_reply_none(); if (value != delimit(value, 127, 65535)) @@ -383,8 +378,7 @@ static struct sk_buff *cfg_set_max_zones(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_max_zones) return tipc_cfg_reply_none(); if (value != delimit(value, 1, 255)) @@ -403,8 +397,7 @@ static struct sk_buff *cfg_set_max_clusters(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 1, 1)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max clusters fixed at 1)"); @@ -417,8 +410,7 @@ static struct sk_buff *cfg_set_max_nodes(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_max_nodes) return tipc_cfg_reply_none(); if (value != delimit(value, 8, 2047)) @@ -437,8 +429,7 @@ static struct sk_buff *cfg_set_max_slaves(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != 0) return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (max secondary nodes fixed at 0)"); @@ -451,8 +442,7 @@ static struct sk_buff *cfg_set_netid(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_net_id) return tipc_cfg_reply_none(); if (value != delimit(value, 1, 9999)) diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c index d8af4c28695d..627f99b7afdf 100644 --- a/net/tipc/dbg.c +++ b/net/tipc/dbg.c @@ -393,8 +393,7 @@ struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 0, 32768)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (log size must be 0-32768)"); diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 03bd659c43ca..7bf87cb26ef3 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -66,11 +66,11 @@ */ struct distr_item { - u32 type; - u32 lower; - u32 upper; - u32 ref; - u32 key; + __be32 type; + __be32 lower; + __be32 upper; + __be32 ref; + __be32 key; }; /** diff --git a/net/tipc/node.c b/net/tipc/node.c index 886bda5e88db..106cd0dfac78 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -597,8 +597,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - domain = *(u32 *)TLV_DATA(req_tlv_area); - domain = ntohl(domain); + domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (!tipc_addr_domain_valid(domain)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (network address)"); @@ -642,8 +641,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - domain = *(u32 *)TLV_DATA(req_tlv_area); - domain = ntohl(domain); + domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (!tipc_addr_domain_valid(domain)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (network address)"); @@ -664,8 +662,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) /* Add TLV for broadcast link */ - link_info.dest = tipc_own_addr & 0xfffff00; - link_info.dest = htonl(link_info.dest); + link_info.dest = htonl(tipc_own_addr & 0xfffff00); link_info.up = htonl(1); sprintf(link_info.str, tipc_bclink_name); tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info)); -- cgit v1.2.3 From 5a874db4d9bfd8a4c6324d844a4d1c7cfa5cf2c4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:19:38 -0800 Subject: [NET]: ipconfig and nfsroot annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- fs/nfs/nfsroot.c | 13 +++--- include/linux/nfs_fs.h | 2 +- include/net/ipconfig.h | 8 ++-- net/ipv4/ipconfig.c | 105 +++++++++++++++++++++++++------------------------ 4 files changed, 64 insertions(+), 64 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 8dfefe41a8da..75f819dc0255 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -98,7 +98,7 @@ static char nfs_root_name[256] __initdata = ""; /* Address of NFS server */ -static __u32 servaddr __initdata = 0; +static __be32 servaddr __initdata = 0; /* Name of directory to mount */ static char nfs_path[NFS_MAXPATHLEN] __initdata = { 0, }; @@ -327,7 +327,7 @@ static int __init root_nfs_name(char *name) */ static int __init root_nfs_addr(void) { - if ((servaddr = root_server_addr) == INADDR_NONE) { + if ((servaddr = root_server_addr) == htonl(INADDR_NONE)) { printk(KERN_ERR "Root-NFS: No NFS server available, giving up.\n"); return -1; } @@ -411,7 +411,7 @@ __setup("nfsroot=", nfs_root_setup); * Construct sockaddr_in from address and port number. */ static inline void -set_sockaddr(struct sockaddr_in *sin, __u32 addr, __u16 port) +set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) { sin->sin_family = AF_INET; sin->sin_addr.s_addr = addr; @@ -468,14 +468,13 @@ static int __init root_nfs_ports(void) dprintk("Root-NFS: Portmapper on server returned %d " "as nfsd port\n", port); } - nfs_port = htons(nfs_port); if ((port = root_nfs_getport(NFS_MNT_PROGRAM, mountd_ver, proto)) < 0) { printk(KERN_ERR "Root-NFS: Unable to get mountd port " "number from server, using default\n"); port = mountd_port; } - mount_port = htons(port); + mount_port = port; dprintk("Root-NFS: mountd port is %d\n", port); return 0; @@ -496,7 +495,7 @@ static int __init root_nfs_get_handle(void) int version = (nfs_data.flags & NFS_MOUNT_VER3) ? NFS_MNT3_VERSION : NFS_MNT_VERSION; - set_sockaddr(&sin, servaddr, mount_port); + set_sockaddr(&sin, servaddr, htons(mount_port)); status = nfsroot_mount(&sin, nfs_path, &fh, version, protocol); if (status < 0) printk(KERN_ERR "Root-NFS: Server returned error %d " @@ -519,6 +518,6 @@ void * __init nfs_root_data(void) || root_nfs_ports() < 0 || root_nfs_get_handle() < 0) return NULL; - set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, nfs_port); + set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, htons(nfs_port)); return (void*)&nfs_data; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 45228c1a1195..625ffea98561 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -318,7 +318,7 @@ extern void put_nfs_open_context(struct nfs_open_context *ctx); extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode); /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ -extern u32 root_nfs_parse_addr(char *name); /*__init*/ +extern __be32 root_nfs_parse_addr(char *name); /*__init*/ static inline void nfs_fattr_init(struct nfs_fattr *fattr) { diff --git a/include/net/ipconfig.h b/include/net/ipconfig.h index 2a1fe996fbc6..3924d7d2cb11 100644 --- a/include/net/ipconfig.h +++ b/include/net/ipconfig.h @@ -11,12 +11,12 @@ extern int ic_proto_enabled; /* Protocols enabled (see IC_xxx) */ extern int ic_set_manually; /* IPconfig parameters set manually */ -extern u32 ic_myaddr; /* My IP address */ -extern u32 ic_gateway; /* Gateway IP address */ +extern __be32 ic_myaddr; /* My IP address */ +extern __be32 ic_gateway; /* Gateway IP address */ -extern u32 ic_servaddr; /* Boot server IP address */ +extern __be32 ic_servaddr; /* Boot server IP address */ -extern u32 root_server_addr; /* Address of NFS server */ +extern __be32 root_server_addr; /* Address of NFS server */ extern u8 root_server_path[]; /* Path to mount as root */ diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 955a07abb91d..afa60b9a003f 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -101,6 +101,7 @@ #define CONF_NAMESERVERS_MAX 3 /* Maximum number of nameservers - '3' from resolv.h */ +#define NONE __constant_htonl(INADDR_NONE) /* * Public IP configuration @@ -129,19 +130,19 @@ int ic_proto_enabled __initdata = 0 static int ic_host_name_set __initdata = 0; /* Host name set by us? */ -u32 ic_myaddr = INADDR_NONE; /* My IP address */ -static u32 ic_netmask = INADDR_NONE; /* Netmask for local subnet */ -u32 ic_gateway = INADDR_NONE; /* Gateway IP address */ +__be32 ic_myaddr = NONE; /* My IP address */ +static __be32 ic_netmask = NONE; /* Netmask for local subnet */ +__be32 ic_gateway = NONE; /* Gateway IP address */ -u32 ic_servaddr = INADDR_NONE; /* Boot server IP address */ +__be32 ic_servaddr = NONE; /* Boot server IP address */ -u32 root_server_addr = INADDR_NONE; /* Address of NFS server */ +__be32 root_server_addr = NONE; /* Address of NFS server */ u8 root_server_path[256] = { 0, }; /* Path to mount as root */ /* Persistent data: */ static int ic_proto_used; /* Protocol used, if any */ -static u32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */ +static __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */ static u8 ic_domain[64]; /* DNS (not NIS) domain name */ /* @@ -172,7 +173,7 @@ struct ic_device { struct net_device *dev; unsigned short flags; short able; - u32 xid; + __be32 xid; }; static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */ @@ -223,7 +224,7 @@ static int __init ic_open_devs(void) d->flags = oflags; d->able = able; if (able & IC_BOOTP) - get_random_bytes(&d->xid, sizeof(u32)); + get_random_bytes(&d->xid, sizeof(__be32)); else d->xid = 0; ic_proto_have_if |= able; @@ -269,7 +270,7 @@ static void __init ic_close_devs(void) */ static inline void -set_sockaddr(struct sockaddr_in *sin, u32 addr, u16 port) +set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) { sin->sin_family = AF_INET; sin->sin_addr.s_addr = addr; @@ -332,7 +333,7 @@ static int __init ic_setup_routes(void) { /* No need to setup device routes, only the default route... */ - if (ic_gateway != INADDR_NONE) { + if (ic_gateway != NONE) { struct rtentry rm; int err; @@ -368,10 +369,10 @@ static int __init ic_defaults(void) if (!ic_host_name_set) sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr)); - if (root_server_addr == INADDR_NONE) + if (root_server_addr == NONE) root_server_addr = ic_servaddr; - if (ic_netmask == INADDR_NONE) { + if (ic_netmask == NONE) { if (IN_CLASSA(ntohl(ic_myaddr))) ic_netmask = htonl(IN_CLASSA_NET); else if (IN_CLASSB(ntohl(ic_myaddr))) @@ -420,7 +421,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt { struct arphdr *rarp; unsigned char *rarp_ptr; - u32 sip, tip; + __be32 sip, tip; unsigned char *sha, *tha; /* s for "source", t for "target" */ struct ic_device *d; @@ -485,12 +486,12 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt goto drop_unlock; /* Discard packets which are not from specified server. */ - if (ic_servaddr != INADDR_NONE && ic_servaddr != sip) + if (ic_servaddr != NONE && ic_servaddr != sip) goto drop_unlock; /* We have a winner! */ ic_dev = dev; - if (ic_myaddr == INADDR_NONE) + if (ic_myaddr == NONE) ic_myaddr = tip; ic_servaddr = sip; ic_got_reply = IC_RARP; @@ -530,13 +531,13 @@ struct bootp_pkt { /* BOOTP packet format */ u8 htype; /* HW address type */ u8 hlen; /* HW address length */ u8 hops; /* Used only by gateways */ - u32 xid; /* Transaction ID */ - u16 secs; /* Seconds since we started */ - u16 flags; /* Just what it says */ - u32 client_ip; /* Client's IP address if known */ - u32 your_ip; /* Assigned IP address */ - u32 server_ip; /* (Next, e.g. NFS) Server's IP address */ - u32 relay_ip; /* IP address of BOOTP relay */ + __be32 xid; /* Transaction ID */ + __be16 secs; /* Seconds since we started */ + __be16 flags; /* Just what it says */ + __be32 client_ip; /* Client's IP address if known */ + __be32 your_ip; /* Assigned IP address */ + __be32 server_ip; /* (Next, e.g. NFS) Server's IP address */ + __be32 relay_ip; /* IP address of BOOTP relay */ u8 hw_addr[16]; /* Client's HW address */ u8 serv_name[64]; /* Server host name */ u8 boot_file[128]; /* Name of boot file */ @@ -576,7 +577,7 @@ static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 }; static void __init ic_dhcp_init_options(u8 *options) { - u8 mt = ((ic_servaddr == INADDR_NONE) + u8 mt = ((ic_servaddr == NONE) ? DHCPDISCOVER : DHCPREQUEST); u8 *e = options; @@ -666,7 +667,7 @@ static inline void ic_bootp_init(void) int i; for (i = 0; i < CONF_NAMESERVERS_MAX; i++) - ic_nameservers[i] = INADDR_NONE; + ic_nameservers[i] = NONE; dev_add_pack(&bootp_packet_type); } @@ -708,7 +709,7 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d h->frag_off = htons(IP_DF); h->ttl = 64; h->protocol = IPPROTO_UDP; - h->daddr = INADDR_BROADCAST; + h->daddr = htonl(INADDR_BROADCAST); h->check = ip_fast_csum((unsigned char *) h, h->ihl); /* Construct UDP header */ @@ -730,8 +731,8 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d b->htype = dev->type; /* can cause undefined behavior */ } b->hlen = dev->addr_len; - b->your_ip = INADDR_NONE; - b->server_ip = INADDR_NONE; + b->your_ip = NONE; + b->server_ip = NONE; memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); b->secs = htons(jiffies_diff / HZ); b->xid = d->xid; @@ -788,11 +789,11 @@ static void __init ic_do_bootp_ext(u8 *ext) switch (*ext++) { case 1: /* Subnet mask */ - if (ic_netmask == INADDR_NONE) + if (ic_netmask == NONE) memcpy(&ic_netmask, ext+1, 4); break; case 3: /* Default gateway */ - if (ic_gateway == INADDR_NONE) + if (ic_gateway == NONE) memcpy(&ic_gateway, ext+1, 4); break; case 6: /* DNS server */ @@ -800,7 +801,7 @@ static void __init ic_do_bootp_ext(u8 *ext) if (servers > CONF_NAMESERVERS_MAX) servers = CONF_NAMESERVERS_MAX; for (i = 0; i < servers; i++) { - if (ic_nameservers[i] == INADDR_NONE) + if (ic_nameservers[i] == NONE) memcpy(&ic_nameservers[i], ext+1+4*i, 4); } break; @@ -917,7 +918,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str #ifdef IPCONFIG_DHCP if (ic_proto_enabled & IC_USE_DHCP) { - u32 server_id = INADDR_NONE; + __be32 server_id = NONE; int mt = 0; ext = &b->exten[4]; @@ -949,7 +950,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str /* While in the process of accepting one offer, * ignore all others. */ - if (ic_myaddr != INADDR_NONE) + if (ic_myaddr != NONE) goto drop_unlock; /* Let's accept that offer. */ @@ -965,7 +966,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str * precedence over the bootp header one if * they are different. */ - if ((server_id != INADDR_NONE) && + if ((server_id != NONE) && (b->server_ip != server_id)) b->server_ip = ic_servaddr; break; @@ -979,8 +980,8 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str default: /* Urque. Forget it*/ - ic_myaddr = INADDR_NONE; - ic_servaddr = INADDR_NONE; + ic_myaddr = NONE; + ic_servaddr = NONE; goto drop_unlock; }; @@ -1004,9 +1005,9 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str ic_dev = dev; ic_myaddr = b->your_ip; ic_servaddr = b->server_ip; - if (ic_gateway == INADDR_NONE && b->relay_ip) + if (ic_gateway == NONE && b->relay_ip) ic_gateway = b->relay_ip; - if (ic_nameservers[0] == INADDR_NONE) + if (ic_nameservers[0] == NONE) ic_nameservers[0] = ic_servaddr; ic_got_reply = IC_BOOTP; @@ -1150,7 +1151,7 @@ static int __init ic_dynamic(void) #endif if (!ic_got_reply) { - ic_myaddr = INADDR_NONE; + ic_myaddr = NONE; return -1; } @@ -1182,12 +1183,12 @@ static int pnp_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "domain %s\n", ic_domain); for (i = 0; i < CONF_NAMESERVERS_MAX; i++) { - if (ic_nameservers[i] != INADDR_NONE) + if (ic_nameservers[i] != NONE) seq_printf(seq, "nameserver %u.%u.%u.%u\n", NIPQUAD(ic_nameservers[i])); } - if (ic_servaddr != INADDR_NONE) + if (ic_servaddr != NONE) seq_printf(seq, "bootserver %u.%u.%u.%u\n", NIPQUAD(ic_servaddr)); @@ -1213,9 +1214,9 @@ static struct file_operations pnp_seq_fops = { * need to have root_server_addr set _before_ IPConfig gets called as it * can override it. */ -u32 __init root_nfs_parse_addr(char *name) +__be32 __init root_nfs_parse_addr(char *name) { - u32 addr; + __be32 addr; int octets = 0; char *cp, *cq; @@ -1237,7 +1238,7 @@ u32 __init root_nfs_parse_addr(char *name) addr = in_aton(name); memmove(name, cp, strlen(cp) + 1); } else - addr = INADDR_NONE; + addr = NONE; return addr; } @@ -1248,7 +1249,7 @@ u32 __init root_nfs_parse_addr(char *name) static int __init ip_auto_config(void) { - u32 addr; + __be32 addr; #ifdef CONFIG_PROC_FS proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops); @@ -1277,11 +1278,11 @@ static int __init ip_auto_config(void) * interfaces and no default was set), use BOOTP or RARP to get the * missing values. */ - if (ic_myaddr == INADDR_NONE || + if (ic_myaddr == NONE || #ifdef CONFIG_ROOT_NFS (MAJOR(ROOT_DEV) == UNNAMED_MAJOR - && root_server_addr == INADDR_NONE - && ic_servaddr == INADDR_NONE) || + && root_server_addr == NONE + && ic_servaddr == NONE) || #endif ic_first_dev->next) { #ifdef IPCONFIG_DYNAMIC @@ -1334,7 +1335,7 @@ static int __init ip_auto_config(void) } addr = root_nfs_parse_addr(root_server_path); - if (root_server_addr == INADDR_NONE) + if (root_server_addr == NONE) root_server_addr = addr; /* @@ -1461,19 +1462,19 @@ static int __init ip_auto_config_setup(char *addrs) switch (num) { case 0: if ((ic_myaddr = in_aton(ip)) == INADDR_ANY) - ic_myaddr = INADDR_NONE; + ic_myaddr = NONE; break; case 1: if ((ic_servaddr = in_aton(ip)) == INADDR_ANY) - ic_servaddr = INADDR_NONE; + ic_servaddr = NONE; break; case 2: if ((ic_gateway = in_aton(ip)) == INADDR_ANY) - ic_gateway = INADDR_NONE; + ic_gateway = NONE; break; case 3: if ((ic_netmask = in_aton(ip)) == INADDR_ANY) - ic_netmask = INADDR_NONE; + ic_netmask = NONE; break; case 4: if ((dp = strchr(ip, '.'))) { -- cgit v1.2.3 From a27ee7a4dd30feda1954950b5840455a51ae1507 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:21:21 -0800 Subject: [IPV6]: annotate icmpv6 headers Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/icmpv6.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index c771a7db9871..dc79396aac25 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -7,17 +7,17 @@ struct icmp6hdr { __u8 icmp6_type; __u8 icmp6_code; - __u16 icmp6_cksum; + __be16 icmp6_cksum; union { - __u32 un_data32[1]; - __u16 un_data16[2]; + __be32 un_data32[1]; + __be16 un_data16[2]; __u8 un_data8[4]; struct icmpv6_echo { - __u16 identifier; - __u16 sequence; + __be16 identifier; + __be16 sequence; } u_echo; struct icmpv6_nd_advt { @@ -53,7 +53,7 @@ struct icmp6hdr { #else #error "Please fix " #endif - __u16 rt_lifetime; + __be16 rt_lifetime; } u_nd_ra; } icmp6_dataun; -- cgit v1.2.3 From d5a0a1e3109339090769e40fdaa62482fcf2a717 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:23:14 -0800 Subject: [IPV4]: encapsulation annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/if_tunnel.h | 8 ++++---- include/linux/xfrm.h | 4 ++-- net/ipv4/ah4.c | 4 ++-- net/ipv4/esp4.c | 4 ++-- net/ipv4/ip_gre.c | 52 +++++++++++++++++++++++------------------------ net/ipv4/ipip.c | 16 +++++++-------- 6 files changed, 44 insertions(+), 44 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index bef9f8fd93b3..8de079ba1107 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -19,10 +19,10 @@ struct ip_tunnel_parm { char name[IFNAMSIZ]; int link; - __u16 i_flags; - __u16 o_flags; - __u32 i_key; - __u32 o_key; + __be16 i_flags; + __be16 o_flags; + __be32 i_key; + __be32 o_key; struct iphdr iph; }; diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 8ae7f744917b..7907c42bd4e4 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -211,8 +211,8 @@ struct xfrm_user_tmpl { struct xfrm_encap_tmpl { __u16 encap_type; - __u16 encap_sport; - __u16 encap_dport; + __be16 encap_sport; + __be16 encap_dport; xfrm_address_t encap_oa; }; diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 99542977e47e..67a5509e26fc 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -14,7 +14,7 @@ * into IP header for icv calculation. Options are already checked * for validity, so paranoia is not required. */ -static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) +static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr) { unsigned char * optptr = (unsigned char*)(iph+1); int l = iph->ihl*4 - sizeof(struct iphdr); @@ -162,7 +162,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) iph->frag_off = 0; iph->check = 0; if (ihl > sizeof(*iph)) { - u32 dummy; + __be32 dummy; if (ip_clear_mutable_options(iph, &dummy)) goto out; } diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index b5c205b57669..f2c6776ea0e6 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -67,7 +67,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) if (x->encap) { struct xfrm_encap_tmpl *encap = x->encap; struct udphdr *uh; - u32 *udpdata32; + __be32 *udpdata32; uh = (struct udphdr *)esph; uh->source = encap->encap_sport; @@ -81,7 +81,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) esph = (struct ip_esp_hdr *)(uh + 1); break; case UDP_ENCAP_ESPINUDP_NON_IKE: - udpdata32 = (u32 *)(uh + 1); + udpdata32 = (__be32 *)(uh + 1); udpdata32[0] = udpdata32[1] = 0; esph = (struct ip_esp_hdr *)(udpdata32 + 2); break; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index d5b5dec075b8..25221146debb 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -144,7 +144,7 @@ static struct net_device *ipgre_fb_tunnel_dev; */ #define HASH_SIZE 16 -#define HASH(addr) ((addr^(addr>>4))&0xF) +#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) static struct ip_tunnel *tunnels[4][HASH_SIZE]; @@ -157,7 +157,7 @@ static DEFINE_RWLOCK(ipgre_lock); /* Given src, dst and key, find appropriate for input tunnel. */ -static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) +static struct ip_tunnel * ipgre_tunnel_lookup(__be32 remote, __be32 local, __be32 key) { unsigned h0 = HASH(remote); unsigned h1 = HASH(key); @@ -194,9 +194,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) static struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t) { - u32 remote = t->parms.iph.daddr; - u32 local = t->parms.iph.saddr; - u32 key = t->parms.i_key; + __be32 remote = t->parms.iph.daddr; + __be32 local = t->parms.iph.saddr; + __be32 key = t->parms.i_key; unsigned h = HASH(key); int prio = 0; @@ -236,9 +236,9 @@ static void ipgre_tunnel_unlink(struct ip_tunnel *t) static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int create) { - u32 remote = parms->iph.daddr; - u32 local = parms->iph.saddr; - u32 key = parms->i_key; + __be32 remote = parms->iph.daddr; + __be32 local = parms->iph.saddr; + __be32 key = parms->i_key; struct ip_tunnel *t, **tp, *nt; struct net_device *dev; unsigned h = HASH(key); @@ -319,12 +319,12 @@ static void ipgre_err(struct sk_buff *skb, u32 info) */ struct iphdr *iph = (struct iphdr*)skb->data; - u16 *p = (u16*)(skb->data+(iph->ihl<<2)); + __be16 *p = (__be16*)(skb->data+(iph->ihl<<2)); int grehlen = (iph->ihl<<2) + 4; int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct ip_tunnel *t; - u16 flags; + __be16 flags; flags = p[0]; if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { @@ -370,7 +370,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) } read_lock(&ipgre_lock); - t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((u32*)p) + (grehlen>>2) - 1) : 0); + t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((__be32*)p) + (grehlen>>2) - 1) : 0); if (t == NULL || t->parms.iph.daddr == 0 || MULTICAST(t->parms.iph.daddr)) goto out; @@ -388,14 +388,14 @@ out: #else struct iphdr *iph = (struct iphdr*)dp; struct iphdr *eiph; - u16 *p = (u16*)(dp+(iph->ihl<<2)); + __be16 *p = (__be16*)(dp+(iph->ihl<<2)); int type = skb->h.icmph->type; int code = skb->h.icmph->code; int rel_type = 0; int rel_code = 0; __be32 rel_info = 0; __u32 n = 0; - u16 flags; + __be16 flags; int grehlen = (iph->ihl<<2) + 4; struct sk_buff *skb2; struct flowi fl; @@ -556,9 +556,9 @@ static int ipgre_rcv(struct sk_buff *skb) { struct iphdr *iph; u8 *h; - u16 flags; + __be16 flags; u16 csum = 0; - u32 key = 0; + __be32 key = 0; u32 seqno = 0; struct ip_tunnel *tunnel; int offset = 4; @@ -568,7 +568,7 @@ static int ipgre_rcv(struct sk_buff *skb) iph = skb->nh.iph; h = skb->data; - flags = *(u16*)h; + flags = *(__be16*)h; if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) { /* - Version must be 0. @@ -592,11 +592,11 @@ static int ipgre_rcv(struct sk_buff *skb) offset += 4; } if (flags&GRE_KEY) { - key = *(u32*)(h + offset); + key = *(__be32*)(h + offset); offset += 4; } if (flags&GRE_SEQ) { - seqno = ntohl(*(u32*)(h + offset)); + seqno = ntohl(*(__be32*)(h + offset)); offset += 4; } } @@ -605,7 +605,7 @@ static int ipgre_rcv(struct sk_buff *skb) if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { secpath_reset(skb); - skb->protocol = *(u16*)(h + 2); + skb->protocol = *(__be16*)(h + 2); /* WCCP version 1 and 2 protocol decoding. * - Change protocol to IP * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header @@ -673,13 +673,13 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) struct iphdr *old_iph = skb->nh.iph; struct iphdr *tiph; u8 tos; - u16 df; + __be16 df; struct rtable *rt; /* Route to the other host */ struct net_device *tdev; /* Device to other host */ struct iphdr *iph; /* Our new IP header */ int max_headroom; /* The extra header space needed */ int gre_hlen; - u32 dst; + __be32 dst; int mtu; if (tunnel->recursion++) { @@ -860,11 +860,11 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT); } - ((u16*)(iph+1))[0] = tunnel->parms.o_flags; - ((u16*)(iph+1))[1] = skb->protocol; + ((__be16*)(iph+1))[0] = tunnel->parms.o_flags; + ((__be16*)(iph+1))[1] = skb->protocol; if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { - u32 *ptr = (u32*)(((u8*)iph) + tunnel->hlen - 4); + __be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4); if (tunnel->parms.o_flags&GRE_SEQ) { ++tunnel->o_seqno; @@ -877,7 +877,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } if (tunnel->parms.o_flags&GRE_CSUM) { *ptr = 0; - *(__u16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); + *(__be16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); } } @@ -1068,7 +1068,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned sh { struct ip_tunnel *t = netdev_priv(dev); struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen); - u16 *p = (u16*)(iph+1); + __be16 *p = (__be16*)(iph+1); memcpy(iph, &t->parms.iph, sizeof(struct iphdr)); p[0] = t->parms.o_flags; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 0c4556529228..9d719d664e5b 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -118,7 +118,7 @@ #include #define HASH_SIZE 16 -#define HASH(addr) ((addr^(addr>>4))&0xF) +#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) static int ipip_fb_tunnel_init(struct net_device *dev); static int ipip_tunnel_init(struct net_device *dev); @@ -134,7 +134,7 @@ static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunne static DEFINE_RWLOCK(ipip_lock); -static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local) +static struct ip_tunnel * ipip_tunnel_lookup(__be32 remote, __be32 local) { unsigned h0 = HASH(remote); unsigned h1 = HASH(local); @@ -160,8 +160,8 @@ static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local) static struct ip_tunnel **ipip_bucket(struct ip_tunnel *t) { - u32 remote = t->parms.iph.daddr; - u32 local = t->parms.iph.saddr; + __be32 remote = t->parms.iph.daddr; + __be32 local = t->parms.iph.saddr; unsigned h = 0; int prio = 0; @@ -203,8 +203,8 @@ static void ipip_tunnel_link(struct ip_tunnel *t) static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create) { - u32 remote = parms->iph.daddr; - u32 local = parms->iph.saddr; + __be32 remote = parms->iph.daddr; + __be32 local = parms->iph.saddr; struct ip_tunnel *t, **tp, *nt; struct net_device *dev; unsigned h = 0; @@ -519,13 +519,13 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) struct net_device_stats *stats = &tunnel->stat; struct iphdr *tiph = &tunnel->parms.iph; u8 tos = tunnel->parms.iph.tos; - u16 df = tiph->frag_off; + __be16 df = tiph->frag_off; struct rtable *rt; /* Route to the other host */ struct net_device *tdev; /* Device to other host */ struct iphdr *old_iph = skb->nh.iph; struct iphdr *iph; /* Our new IP header */ int max_headroom; /* The extra header space needed */ - u32 dst = tiph->daddr; + __be32 dst = tiph->daddr; int mtu; if (tunnel->recursion++) { -- cgit v1.2.3 From d29ef86b0a497dd2c4f9601644a15392f7e21f73 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:23:42 -0800 Subject: [AF_KEY]: annotate Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/pfkeyv2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index d5dd471da225..0f0b880c4280 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -32,7 +32,7 @@ struct sadb_ext { struct sadb_sa { uint16_t sadb_sa_len; uint16_t sadb_sa_exttype; - uint32_t sadb_sa_spi; + __be32 sadb_sa_spi; uint8_t sadb_sa_replay; uint8_t sadb_sa_state; uint8_t sadb_sa_auth; @@ -211,7 +211,7 @@ struct sadb_x_nat_t_type { struct sadb_x_nat_t_port { uint16_t sadb_x_nat_t_port_len; uint16_t sadb_x_nat_t_port_exttype; - uint16_t sadb_x_nat_t_port_port; + __be16 sadb_x_nat_t_port_port; uint16_t sadb_x_nat_t_port_reserved; } __attribute__((packed)); /* sizeof(struct sadb_x_nat_t_port) == 8 */ -- cgit v1.2.3 From 90bcaf7b4a33bb9b100cc06869f0c033a870d4a0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:25:17 -0800 Subject: [IPV6]: flowlabels are net-endian Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/in6.h | 4 ++-- include/linux/ip6_tunnel.h | 2 +- include/linux/ipv6.h | 2 +- include/net/flow.h | 2 +- include/net/ipv6.h | 4 ++-- net/ipv6/af_inet6.c | 2 +- net/ipv6/datagram.c | 10 +++++----- net/ipv6/ip6_flowlabel.c | 8 ++++---- net/ipv6/ip6_output.c | 4 ++-- net/ipv6/ip6_tunnel.c | 6 +++--- net/ipv6/route.c | 2 +- 11 files changed, 23 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/include/linux/in6.h b/include/linux/in6.h index f28621f638e0..4e8350ae8869 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -54,7 +54,7 @@ extern const struct in6_addr in6addr_loopback; struct sockaddr_in6 { unsigned short int sin6_family; /* AF_INET6 */ __be16 sin6_port; /* Transport layer port # */ - __u32 sin6_flowinfo; /* IPv6 flow information */ + __be32 sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ __u32 sin6_scope_id; /* scope id (new in RFC2553) */ }; @@ -72,7 +72,7 @@ struct ipv6_mreq { struct in6_flowlabel_req { struct in6_addr flr_dst; - __u32 flr_label; + __be32 flr_label; __u8 flr_action; __u8 flr_share; __u16 flr_flags; diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h index 5c23aeb104ca..af3f4a70f3df 100644 --- a/include/linux/ip6_tunnel.h +++ b/include/linux/ip6_tunnel.h @@ -25,7 +25,7 @@ struct ip6_tnl_parm { __u8 proto; /* tunnel protocol */ __u8 encap_limit; /* encapsulation limit for tunnel */ __u8 hop_limit; /* hop limit for tunnel */ - __u32 flowinfo; /* traffic class and flowlabel for tunnel */ + __be32 flowinfo; /* traffic class and flowlabel for tunnel */ __u32 flags; /* tunnel flags */ struct in6_addr laddr; /* local tunnel end-point address */ struct in6_addr raddr; /* remote tunnel end-point address */ diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 4f435c59de06..f8241130f5ea 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -274,7 +274,7 @@ struct ipv6_pinfo { struct in6_addr *saddr_cache; #endif - __u32 flow_label; + __be32 flow_label; __u32 frag_size; __s16 hop_limit; __s16 mcast_hops; diff --git a/include/net/flow.h b/include/net/flow.h index 5cda27cd9deb..270d4c1761af 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -27,7 +27,7 @@ struct flowi { struct in6_addr daddr; struct in6_addr saddr; __u32 fwmark; - __u32 flowlabel; + __be32 flowlabel; } ip6_u; struct { diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 4953fac1d070..0b8c9b990ac4 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -191,7 +191,7 @@ struct ipv6_txoptions struct ip6_flowlabel { struct ip6_flowlabel *next; - u32 label; + __be32 label; struct in6_addr dst; struct ipv6_txoptions *opt; atomic_t users; @@ -211,7 +211,7 @@ struct ipv6_fl_socklist struct ip6_flowlabel *fl; }; -extern struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, u32 label); +extern struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label); extern struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space, struct ip6_flowlabel * fl, struct ipv6_txoptions * fopt); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 858cae29581c..92bfccf62cb7 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -678,7 +678,7 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb) if (np->rxopt.all) { if ((opt->hop && (np->rxopt.bits.hopopts || np->rxopt.bits.ohopopts)) || - ((IPV6_FLOWINFO_MASK & *(u32*)skb->nh.raw) && + ((IPV6_FLOWINFO_MASK & *(__be32*)skb->nh.raw) && np->rxopt.bits.rxflow) || (opt->srcrt && (np->rxopt.bits.srcrt || np->rxopt.bits.osrcrt)) || diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 7206747022fc..a67434af691f 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -318,7 +318,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) ipv6_addr_copy(&sin->sin6_addr, (struct in6_addr *)(skb->nh.raw + serr->addr_offset)); if (np->sndflow) - sin->sin6_flowinfo = *(u32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK; + sin->sin6_flowinfo = *(__be32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK; if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin->sin6_scope_id = IP6CB(skb)->iif; } else { @@ -401,8 +401,8 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); } - if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) { - u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK; + if (np->rxopt.bits.rxflow && (*(__be32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) { + __be32 flowinfo = *(__be32*)skb->nh.raw & IPV6_FLOWINFO_MASK; put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); } @@ -560,12 +560,12 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, } if (fl->fl6_flowlabel&IPV6_FLOWINFO_MASK) { - if ((fl->fl6_flowlabel^*(u32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) { + if ((fl->fl6_flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) { err = -EINVAL; goto exit_f; } } - fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(u32 *)CMSG_DATA(cmsg); + fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg); break; case IPV6_2292HOPOPTS: diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 6d4533b58dca..624fae251f4e 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -61,7 +61,7 @@ static DEFINE_RWLOCK(ip6_fl_lock); static DEFINE_RWLOCK(ip6_sk_fl_lock); -static __inline__ struct ip6_flowlabel * __fl_lookup(u32 label) +static __inline__ struct ip6_flowlabel * __fl_lookup(__be32 label) { struct ip6_flowlabel *fl; @@ -72,7 +72,7 @@ static __inline__ struct ip6_flowlabel * __fl_lookup(u32 label) return NULL; } -static struct ip6_flowlabel * fl_lookup(u32 label) +static struct ip6_flowlabel * fl_lookup(__be32 label) { struct ip6_flowlabel *fl; @@ -153,7 +153,7 @@ static void ip6_fl_gc(unsigned long dummy) write_unlock(&ip6_fl_lock); } -static int fl_intern(struct ip6_flowlabel *fl, __u32 label) +static int fl_intern(struct ip6_flowlabel *fl, __be32 label) { fl->label = label & IPV6_FLOWLABEL_MASK; @@ -182,7 +182,7 @@ static int fl_intern(struct ip6_flowlabel *fl, __u32 label) /* Socket flowlabel lists */ -struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, u32 label) +struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label) { struct ipv6_fl_socklist *sfl; struct ipv6_pinfo *np = inet6_sk(sk); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 66716911962e..9ff1be1bc2e7 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -217,7 +217,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, if (tclass < 0) tclass = 0; - *(u32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; + *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; hdr->payload_len = htons(seg_len); hdr->nexthdr = proto; @@ -1311,7 +1311,7 @@ int ip6_push_pending_frames(struct sock *sk) skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr)); - *(u32*)hdr = fl->fl6_flowlabel | + *(__be32*)hdr = fl->fl6_flowlabel | htonl(0x60000000 | ((int)np->cork.tclass << 20)); if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 6a3026dd865a..4919f9294e2a 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -665,9 +665,9 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) dsfield = ipv6_get_dsfield(ipv6h); if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)) - fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_TCLASS_MASK); + fl.fl6_flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)) - fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_FLOWLABEL_MASK); + fl.fl6_flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK); if (encap_limit >= 0 && (opt = create_tel(encap_limit)) == NULL) goto tx_err; @@ -735,7 +735,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) skb->nh.raw = skb_push(skb, sizeof(struct ipv6hdr)); ipv6h = skb->nh.ipv6h; - *(u32*)ipv6h = fl.fl6_flowlabel | htonl(0x60000000); + *(__be32*)ipv6h = fl.fl6_flowlabel | htonl(0x60000000); dsfield = INET_ECN_encapsulate(0, dsfield); ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield); ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b39ae99122d5..e9c1fc5f21b1 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -714,7 +714,7 @@ void ip6_route_input(struct sk_buff *skb) #ifdef CONFIG_IPV6_ROUTE_FWMARK .fwmark = skb->nfmark, #endif - .flowlabel = (* (u32 *) iph)&IPV6_FLOWINFO_MASK, + .flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, }, }, .proto = iph->nexthdr, -- cgit v1.2.3 From 0e11c91e1e912bc4db5b71607d149e7e9a77e756 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:26:29 -0800 Subject: [AF_PACKET]: annotate Weirdness: the third argument of socket() is net-endian here. Oh, well - it's documented in packet(7). Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/if_packet.h | 6 ++++-- net/packet/af_packet.c | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h index b92558549d27..99393ef3af39 100644 --- a/include/linux/if_packet.h +++ b/include/linux/if_packet.h @@ -1,17 +1,19 @@ #ifndef __LINUX_IF_PACKET_H #define __LINUX_IF_PACKET_H +#include + struct sockaddr_pkt { unsigned short spkt_family; unsigned char spkt_device[14]; - unsigned short spkt_protocol; + __be16 spkt_protocol; }; struct sockaddr_ll { unsigned short sll_family; - unsigned short sll_protocol; + __be16 sll_protocol; int sll_ifindex; unsigned short sll_hatype; unsigned char sll_pkttype; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index f4ccb90e6739..271d2eed0699 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -201,7 +201,7 @@ struct packet_sock { spinlock_t bind_lock; char running; /* prot_hook is attached*/ int ifindex; /* bound device */ - unsigned short num; + __be16 num; #ifdef CONFIG_PACKET_MULTICAST struct packet_mclist *mclist; #endif @@ -331,7 +331,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name; struct sk_buff *skb; struct net_device *dev; - unsigned short proto=0; + __be16 proto=0; int err; /* @@ -704,7 +704,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name; struct sk_buff *skb; struct net_device *dev; - unsigned short proto; + __be16 proto; unsigned char *addr; int ifindex, err, reserve = 0; @@ -858,7 +858,7 @@ static int packet_release(struct socket *sock) * Attach a packet hook. */ -static int packet_do_bind(struct sock *sk, struct net_device *dev, int protocol) +static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protocol) { struct packet_sock *po = pkt_sk(sk); /* @@ -983,6 +983,7 @@ static int packet_create(struct socket *sock, int protocol) { struct sock *sk; struct packet_sock *po; + __be16 proto = (__force __be16)protocol; /* weird, but documented */ int err; if (!capable(CAP_NET_RAW)) @@ -1010,7 +1011,7 @@ static int packet_create(struct socket *sock, int protocol) po = pkt_sk(sk); sk->sk_family = PF_PACKET; - po->num = protocol; + po->num = proto; sk->sk_destruct = packet_sock_destruct; atomic_inc(&packet_socks_nr); @@ -1027,8 +1028,8 @@ static int packet_create(struct socket *sock, int protocol) #endif po->prot_hook.af_packet_priv = sk; - if (protocol) { - po->prot_hook.type = protocol; + if (proto) { + po->prot_hook.type = proto; dev_add_pack(&po->prot_hook); sock_hold(sk); po->running = 1; @@ -1624,7 +1625,8 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing { char **pg_vec = NULL; struct packet_sock *po = pkt_sk(sk); - int was_running, num, order = 0; + int was_running, order = 0; + __be16 num; int err = 0; if (req->tp_block_nr) { -- cgit v1.2.3 From 98a4a86128d7179b22365e16bf880e849e20bc7d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:26:51 -0800 Subject: [NETFILTER]: trivial annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter/nfnetlink.h | 2 +- include/linux/netfilter/nfnetlink_log.h | 10 +++++----- include/linux/netfilter/nfnetlink_queue.h | 18 +++++++++--------- include/linux/netfilter/xt_conntrack.h | 4 ++-- include/linux/netfilter/xt_policy.h | 2 +- include/linux/types.h | 2 ++ net/netfilter/nfnetlink_log.c | 22 ++++++++++------------ net/netfilter/nfnetlink_queue.c | 9 ++++----- net/netfilter/xt_multiport.c | 4 ++-- 9 files changed, 36 insertions(+), 37 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 6d8e3e5a80e9..1e9c821f152d 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -78,7 +78,7 @@ struct nfattr struct nfgenmsg { u_int8_t nfgen_family; /* AF_xxx */ u_int8_t version; /* nfnetlink version */ - u_int16_t res_id; /* resource id */ + __be16 res_id; /* resource id */ }; #define NFNETLINK_V0 0 diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h index 87b92f8b988f..55a2a2b814ed 100644 --- a/include/linux/netfilter/nfnetlink_log.h +++ b/include/linux/netfilter/nfnetlink_log.h @@ -16,20 +16,20 @@ enum nfulnl_msg_types { }; struct nfulnl_msg_packet_hdr { - u_int16_t hw_protocol; /* hw protocol (network order) */ + __be16 hw_protocol; /* hw protocol (network order) */ u_int8_t hook; /* netfilter hook */ u_int8_t _pad; }; struct nfulnl_msg_packet_hw { - u_int16_t hw_addrlen; + __be16 hw_addrlen; u_int16_t _pad; u_int8_t hw_addr[8]; }; struct nfulnl_msg_packet_timestamp { - aligned_u64 sec; - aligned_u64 usec; + aligned_be64 sec; + aligned_be64 usec; }; #define NFULNL_PREFIXLEN 30 /* just like old log target */ @@ -67,7 +67,7 @@ struct nfulnl_msg_config_cmd { } __attribute__ ((packed)); struct nfulnl_msg_config_mode { - u_int32_t copy_range; + __be32 copy_range; u_int8_t copy_mode; u_int8_t _pad; } __attribute__ ((packed)); diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h index 36af0360b56d..4beea3d6fda8 100644 --- a/include/linux/netfilter/nfnetlink_queue.h +++ b/include/linux/netfilter/nfnetlink_queue.h @@ -13,20 +13,20 @@ enum nfqnl_msg_types { }; struct nfqnl_msg_packet_hdr { - u_int32_t packet_id; /* unique ID of packet in queue */ - u_int16_t hw_protocol; /* hw protocol (network order) */ + __be32 packet_id; /* unique ID of packet in queue */ + __be16 hw_protocol; /* hw protocol (network order) */ u_int8_t hook; /* netfilter hook */ } __attribute__ ((packed)); struct nfqnl_msg_packet_hw { - u_int16_t hw_addrlen; + __be16 hw_addrlen; u_int16_t _pad; u_int8_t hw_addr[8]; }; struct nfqnl_msg_packet_timestamp { - aligned_u64 sec; - aligned_u64 usec; + aligned_be64 sec; + aligned_be64 usec; }; enum nfqnl_attr_type { @@ -47,8 +47,8 @@ enum nfqnl_attr_type { #define NFQA_MAX (__NFQA_MAX - 1) struct nfqnl_msg_verdict_hdr { - u_int32_t verdict; - u_int32_t id; + __be32 verdict; + __be32 id; }; @@ -63,7 +63,7 @@ enum nfqnl_msg_config_cmds { struct nfqnl_msg_config_cmd { u_int8_t command; /* nfqnl_msg_config_cmds */ u_int8_t _pad; - u_int16_t pf; /* AF_xxx for PF_[UN]BIND */ + __be16 pf; /* AF_xxx for PF_[UN]BIND */ }; enum nfqnl_config_mode { @@ -73,7 +73,7 @@ enum nfqnl_config_mode { }; struct nfqnl_msg_config_params { - u_int32_t copy_range; + __be32 copy_range; u_int8_t copy_mode; /* enum nfqnl_config_mode */ } __attribute__ ((packed)); diff --git a/include/linux/netfilter/xt_conntrack.h b/include/linux/netfilter/xt_conntrack.h index 4c2d9945ca54..70b6f718cf4c 100644 --- a/include/linux/netfilter/xt_conntrack.h +++ b/include/linux/netfilter/xt_conntrack.h @@ -29,14 +29,14 @@ struct ip_conntrack_old_tuple { struct { - __u32 ip; + __be32 ip; union { __u16 all; } u; } src; struct { - __u32 ip; + __be32 ip; union { __u16 all; } u; diff --git a/include/linux/netfilter/xt_policy.h b/include/linux/netfilter/xt_policy.h index a8132ec076fb..45654d359a68 100644 --- a/include/linux/netfilter/xt_policy.h +++ b/include/linux/netfilter/xt_policy.h @@ -39,7 +39,7 @@ struct xt_policy_elem union xt_policy_addr smask; union xt_policy_addr daddr; union xt_policy_addr dmask; - u_int32_t spi; + __be32 spi; u_int32_t reqid; u_int8_t proto; u_int8_t mode; diff --git a/include/linux/types.h b/include/linux/types.h index 750f085fa564..9f11fdd2bd72 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -128,6 +128,8 @@ typedef __s64 int64_t; /* this is a special 64bit data type that is 8-byte aligned */ #define aligned_u64 unsigned long long __attribute__((aligned(8))) +#define aligned_be64 __be64 __attribute__((aligned(8))) +#define aligned_le64 __le64 __attribute__((aligned(8))) /** * The type used for indexing onto a disc or disc partition. diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 1e5207b80fe5..856ed0d19974 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -414,7 +414,7 @@ __build_packet_message(struct nfulnl_instance *inst, struct nfulnl_msg_packet_hdr pmsg; struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - u_int32_t tmp_uint; + __be32 tmp_uint; UDEBUG("entered\n"); @@ -508,11 +508,9 @@ __build_packet_message(struct nfulnl_instance *inst, if (indev && skb->dev && skb->dev->hard_header_parse) { struct nfulnl_msg_packet_hw phw; - - phw.hw_addrlen = - skb->dev->hard_header_parse((struct sk_buff *)skb, + int len = skb->dev->hard_header_parse((struct sk_buff *)skb, phw.hw_addr); - phw.hw_addrlen = htons(phw.hw_addrlen); + phw.hw_addrlen = htons(len); NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); } @@ -529,7 +527,7 @@ __build_packet_message(struct nfulnl_instance *inst, if (skb->sk) { read_lock_bh(&skb->sk->sk_callback_lock); if (skb->sk->sk_socket && skb->sk->sk_socket->file) { - u_int32_t uid = htonl(skb->sk->sk_socket->file->f_uid); + __be32 uid = htonl(skb->sk->sk_socket->file->f_uid); /* need to unlock here since NFA_PUT may goto */ read_unlock_bh(&skb->sk->sk_callback_lock); NFA_PUT(inst->skb, NFULA_UID, sizeof(uid), &uid); @@ -882,15 +880,15 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } if (nfula[NFULA_CFG_TIMEOUT-1]) { - u_int32_t timeout = - *(u_int32_t *)NFA_DATA(nfula[NFULA_CFG_TIMEOUT-1]); + __be32 timeout = + *(__be32 *)NFA_DATA(nfula[NFULA_CFG_TIMEOUT-1]); nfulnl_set_timeout(inst, ntohl(timeout)); } if (nfula[NFULA_CFG_NLBUFSIZ-1]) { - u_int32_t nlbufsiz = - *(u_int32_t *)NFA_DATA(nfula[NFULA_CFG_NLBUFSIZ-1]); + __be32 nlbufsiz = + *(__be32 *)NFA_DATA(nfula[NFULA_CFG_NLBUFSIZ-1]); nfulnl_set_nlbufsiz(inst, ntohl(nlbufsiz)); } @@ -903,8 +901,8 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } if (nfula[NFULA_CFG_FLAGS-1]) { - u_int16_t flags = - *(u_int16_t *)NFA_DATA(nfula[NFULA_CFG_FLAGS-1]); + __be16 flags = + *(__be16 *)NFA_DATA(nfula[NFULA_CFG_FLAGS-1]); nfulnl_set_flags(inst, ntohs(flags)); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index e815a9aa6e95..4ab7b1416bb5 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -349,7 +349,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, struct sk_buff *entskb = entry->skb; struct net_device *indev; struct net_device *outdev; - unsigned int tmp_uint; + __be32 tmp_uint; QDEBUG("entered\n"); @@ -489,10 +489,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, && entskb->dev->hard_header_parse) { struct nfqnl_msg_packet_hw phw; - phw.hw_addrlen = - entskb->dev->hard_header_parse(entskb, + int len = entskb->dev->hard_header_parse(entskb, phw.hw_addr); - phw.hw_addrlen = htons(phw.hw_addrlen); + phw.hw_addrlen = htons(len); NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); } @@ -835,7 +834,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, } if (nfqa[NFQA_MARK-1]) - entry->skb->nfmark = ntohl(*(u_int32_t *) + entry->skb->nfmark = ntohl(*(__be32 *) NFA_DATA(nfqa[NFQA_MARK-1])); issue_verdict(entry, verdict); diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c index d3aefd380930..b4293058c6ff 100644 --- a/net/netfilter/xt_multiport.c +++ b/net/netfilter/xt_multiport.c @@ -104,7 +104,7 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - u16 _ports[2], *pptr; + __be16 _ports[2], *pptr; const struct xt_multiport *multiinfo = matchinfo; if (offset) @@ -135,7 +135,7 @@ match_v1(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - u16 _ports[2], *pptr; + __be16 _ports[2], *pptr; const struct xt_multiport_v1 *multiinfo = matchinfo; if (offset) -- cgit v1.2.3 From ae08e1f092210619fe49551aa3ed0dc0003d5880 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:27:11 -0800 Subject: [IPV6]: ip6_output annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/skbuff.h | 2 +- net/ipv6/ip6_output.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 85577a4ffa61..7fc9a3aaa1c9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -139,7 +139,7 @@ struct skb_shared_info { /* Warning: this field is not always filled in (UFO)! */ unsigned short gso_segs; unsigned short gso_type; - unsigned int ip6_frag_id; + __be32 ip6_frag_id; struct sk_buff *frag_list; skb_frag_t frags[MAX_SKB_FRAGS]; }; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9ff1be1bc2e7..93330685adfc 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -267,7 +267,7 @@ int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr)); skb->nh.ipv6h = hdr; - *(u32*)hdr = htonl(0x60000000); + *(__be32*)hdr = htonl(0x60000000); hdr->payload_len = htons(len); hdr->nexthdr = proto; @@ -571,7 +571,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; unsigned int mtu, hlen, left, len; - u32 frag_id = 0; + __be32 frag_id = 0; int ptr, offset = 0, err=0; u8 *prevhdr, nexthdr = 0; -- cgit v1.2.3 From c1a856c9640c9ff3d70bbd8214b6a0974609eef8 Mon Sep 17 00:00:00 2001 From: Venkat Yekkirala Date: Wed, 8 Nov 2006 17:03:44 -0600 Subject: SELinux: Various xfrm labeling fixes Since the upstreaming of the mlsxfrm modification a few months back, testing has resulted in the identification of the following issues/bugs that are resolved in this patch set. 1. Fix the security context used in the IKE negotiation to be the context of the socket as opposed to the context of the SPD rule. 2. Fix SO_PEERSEC for tcp sockets to return the security context of the peer as opposed to the source. 3. Fix the selection of an SA for an outgoing packet to be at the same context as the originating socket/flow. The following would be the result of applying this patchset: - SO_PEERSEC will now correctly return the peer's context. - IKE deamons will receive the context of the source socket/flow as opposed to the SPD rule's context so that the negotiated SA will be at the same context as the source socket/flow. - The SELinux policy will require one or more of the following for a socket to be able to communicate with/without SAs: 1. To enable a socket to communicate without using labeled-IPSec SAs: allow socket_t unlabeled_t:association { sendto recvfrom } 2. To enable a socket to communicate with labeled-IPSec SAs: allow socket_t self:association { sendto }; allow socket_t peer_sa_t:association { recvfrom }; This Patch: Pass correct security context to IKE for use in negotiation Fix the security context passed to IKE for use in negotiation to be the context of the socket as opposed to the context of the SPD rule so that the SA carries the label of the originating socket/flow. Signed-off-by: Venkat Yekkirala Signed-off-by: James Morris --- include/linux/security.h | 21 ++++++++++----------- security/dummy.c | 4 ++-- security/selinux/include/xfrm.h | 4 ++-- security/selinux/xfrm.c | 35 +++++++++-------------------------- 4 files changed, 23 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index b200b9856f32..a509329a669b 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -836,10 +836,8 @@ struct request_sock; * used by the XFRM system. * @sec_ctx contains the security context information being provided by * the user-level policy update program (e.g., setkey). - * @sk refers to the sock from which to derive the security context. * Allocate a security structure to the xp->security field; the security - * field is initialized to NULL when the xfrm_policy is allocated. Only - * one of sec_ctx or sock can be specified. + * field is initialized to NULL when the xfrm_policy is allocated. * Return 0 if operation was successful (memory to allocate, legal context) * @xfrm_policy_clone_security: * @old contains an existing xfrm_policy in the SPD. @@ -858,9 +856,6 @@ struct request_sock; * Database by the XFRM system. * @sec_ctx contains the security context information being provided by * the user-level SA generation program (e.g., setkey or racoon). - * @polsec contains the security context information associated with a xfrm - * policy rule from which to take the base context. polsec must be NULL - * when sec_ctx is specified. * @secid contains the secid from which to take the mls portion of the context. * Allocate a security structure to the x->security field; the security * field is initialized to NULL when the xfrm_state is allocated. Set the @@ -1378,12 +1373,12 @@ struct security_operations { #ifdef CONFIG_SECURITY_NETWORK_XFRM int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk); + struct xfrm_user_sec_ctx *sec_ctx); int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); void (*xfrm_policy_free_security) (struct xfrm_policy *xp); int (*xfrm_policy_delete_security) (struct xfrm_policy *xp); int (*xfrm_state_alloc_security) (struct xfrm_state *x, - struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *polsec, + struct xfrm_user_sec_ctx *sec_ctx, u32 secid); void (*xfrm_state_free_security) (struct xfrm_state *x); int (*xfrm_state_delete_security) (struct xfrm_state *x); @@ -3120,7 +3115,7 @@ static inline void security_inet_csk_clone(struct sock *newsk, #ifdef CONFIG_SECURITY_NETWORK_XFRM static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) { - return security_ops->xfrm_policy_alloc_security(xp, sec_ctx, NULL); + return security_ops->xfrm_policy_alloc_security(xp, sec_ctx); } static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) @@ -3141,7 +3136,7 @@ static inline int security_xfrm_policy_delete(struct xfrm_policy *xp) static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) { - return security_ops->xfrm_state_alloc_security(x, sec_ctx, NULL, 0); + return security_ops->xfrm_state_alloc_security(x, sec_ctx, 0); } static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x, @@ -3149,7 +3144,11 @@ static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x, { if (!polsec) return 0; - return security_ops->xfrm_state_alloc_security(x, NULL, polsec, secid); + /* + * We want the context to be taken from secid which is usually + * from the sock. + */ + return security_ops->xfrm_state_alloc_security(x, NULL, secid); } static inline int security_xfrm_state_delete(struct xfrm_state *x) diff --git a/security/dummy.c b/security/dummy.c index 43874c1e6e23..838d8442cf3c 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -836,7 +836,7 @@ static inline void dummy_req_classify_flow(const struct request_sock *req, #ifdef CONFIG_SECURITY_NETWORK_XFRM static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk) + struct xfrm_user_sec_ctx *sec_ctx) { return 0; } @@ -856,7 +856,7 @@ static int dummy_xfrm_policy_delete_security(struct xfrm_policy *xp) } static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, - struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid) + struct xfrm_user_sec_ctx *sec_ctx, u32 secid) { return 0; } diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 526b28019aca..8e329ddb5e37 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -8,12 +8,12 @@ #define _SELINUX_XFRM_H_ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk); + struct xfrm_user_sec_ctx *sec_ctx); int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); void selinux_xfrm_policy_free(struct xfrm_policy *xp); int selinux_xfrm_policy_delete(struct xfrm_policy *xp); int selinux_xfrm_state_alloc(struct xfrm_state *x, - struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid); + struct xfrm_user_sec_ctx *sec_ctx, u32 secid); void selinux_xfrm_state_free(struct xfrm_state *x); int selinux_xfrm_state_delete(struct xfrm_state *x); int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 675b995a67c3..4d5a043cdfa1 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -226,16 +226,15 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) * CTX does not have a meaningful value on input */ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, - struct xfrm_user_sec_ctx *uctx, struct xfrm_sec_ctx *pol, u32 sid) + struct xfrm_user_sec_ctx *uctx, u32 sid) { int rc = 0; struct task_security_struct *tsec = current->security; struct xfrm_sec_ctx *ctx = NULL; char *ctx_str = NULL; u32 str_len; - u32 ctx_sid; - BUG_ON(uctx && pol); + BUG_ON(uctx && sid); if (!uctx) goto not_from_user; @@ -279,15 +278,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, return rc; not_from_user: - if (pol) { - rc = security_sid_mls_copy(pol->ctx_sid, sid, &ctx_sid); - if (rc) - goto out; - } - else - ctx_sid = sid; - - rc = security_sid_to_context(ctx_sid, &ctx_str, &str_len); + rc = security_sid_to_context(sid, &ctx_str, &str_len); if (rc) goto out; @@ -302,7 +293,7 @@ not_from_user: ctx->ctx_doi = XFRM_SC_DOI_LSM; ctx->ctx_alg = XFRM_SC_ALG_SELINUX; - ctx->ctx_sid = ctx_sid; + ctx->ctx_sid = sid; ctx->ctx_len = str_len; memcpy(ctx->ctx_str, ctx_str, @@ -323,22 +314,14 @@ out2: * xfrm_policy. */ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *uctx, struct sock *sk) + struct xfrm_user_sec_ctx *uctx) { int err; - u32 sid; BUG_ON(!xp); - BUG_ON(uctx && sk); - - if (sk) { - struct sk_security_struct *ssec = sk->sk_security; - sid = ssec->sid; - } - else - sid = SECSID_NULL; + BUG_ON(!uctx); - err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, NULL, sid); + err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); return err; } @@ -399,13 +382,13 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp) * xfrm_state. */ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, - struct xfrm_sec_ctx *pol, u32 secid) + u32 secid) { int err; BUG_ON(!x); - err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, pol, secid); + err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); return err; } -- cgit v1.2.3 From 6b877699c6f1efede4545bcecc367786a472eedb Mon Sep 17 00:00:00 2001 From: Venkat Yekkirala Date: Wed, 8 Nov 2006 17:04:09 -0600 Subject: SELinux: Return correct context for SO_PEERSEC Fix SO_PEERSEC for tcp sockets to return the security context of the peer (as represented by the SA from the peer) as opposed to the SA used by the local/source socket. Signed-off-by: Venkat Yekkirala Signed-off-by: James Morris --- include/linux/security.h | 16 +++++++++++++++- include/net/request_sock.h | 1 + net/ipv4/tcp_input.c | 2 ++ security/dummy.c | 6 ++++++ security/selinux/hooks.c | 21 +++++++++++++++++---- security/selinux/include/xfrm.h | 12 ++++++------ security/selinux/xfrm.c | 40 +++------------------------------------- 7 files changed, 50 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index a509329a669b..84cebcdb3f83 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -826,6 +826,8 @@ struct request_sock; * Sets the openreq's sid to socket's sid with MLS portion taken from peer sid. * @inet_csk_clone: * Sets the new child socket's sid to the openreq sid. + * @inet_conn_established: + * Sets the connection's peersid to the secmark on skb. * @req_classify_flow: * Sets the flow's sid to the openreq sid. * @@ -1368,6 +1370,7 @@ struct security_operations { int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb, struct request_sock *req); void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req); + void (*inet_conn_established)(struct sock *sk, struct sk_buff *skb); void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl); #endif /* CONFIG_SECURITY_NETWORK */ @@ -2961,9 +2964,15 @@ static inline void security_inet_csk_clone(struct sock *newsk, { security_ops->inet_csk_clone(newsk, req); } + +static inline void security_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ + security_ops->inet_conn_established(sk, skb); +} #else /* CONFIG_SECURITY_NETWORK */ static inline int security_unix_stream_connect(struct socket * sock, - struct socket * other, + struct socket * other, struct sock * newsk) { return 0; @@ -3110,6 +3119,11 @@ static inline void security_inet_csk_clone(struct sock *newsk, const struct request_sock *req) { } + +static inline void security_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ +} #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 8e165ca16bd8..f743a941a4f2 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -54,6 +54,7 @@ struct request_sock { struct request_sock_ops *rsk_ops; struct sock *sk; u32 secid; + u32 peer_secid; }; static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index cf06accbe687..4a8c96cdec7d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4230,6 +4230,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, mb(); tcp_set_state(sk, TCP_ESTABLISHED); + security_inet_conn_established(sk, skb); + /* Make sure socket is routed, for correct metrics. */ icsk->icsk_af_ops->rebuild_header(sk); diff --git a/security/dummy.c b/security/dummy.c index 838d8442cf3c..0148d1518dd1 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -828,6 +828,11 @@ static inline void dummy_inet_csk_clone(struct sock *newsk, { } +static inline void dummy_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ +} + static inline void dummy_req_classify_flow(const struct request_sock *req, struct flowi *fl) { @@ -1108,6 +1113,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, sock_graft); set_to_dummy_if_null(ops, inet_conn_request); set_to_dummy_if_null(ops, inet_csk_clone); + set_to_dummy_if_null(ops, inet_conn_established); set_to_dummy_if_null(ops, req_classify_flow); #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 28ee187ed224..5bbd599a4471 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3535,8 +3535,10 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op } else if (isec->sclass == SECCLASS_TCP_SOCKET) { peer_sid = selinux_netlbl_socket_getpeersec_stream(sock); - if (peer_sid == SECSID_NULL) - peer_sid = selinux_socket_getpeer_stream(sock->sk); + if (peer_sid == SECSID_NULL) { + ssec = sock->sk->sk_security; + peer_sid = ssec->peer_sid; + } if (peer_sid == SECSID_NULL) { err = -ENOPROTOOPT; goto out; @@ -3647,11 +3649,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, return 0; } - err = selinux_xfrm_decode_session(skb, &peersid, 0); - BUG_ON(err); + selinux_skb_xfrm_sid(skb, &peersid); if (peersid == SECSID_NULL) { req->secid = sksec->sid; + req->peer_secid = 0; return 0; } @@ -3660,6 +3662,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, return err; req->secid = newsid; + req->peer_secid = peersid; return 0; } @@ -3669,6 +3672,7 @@ static void selinux_inet_csk_clone(struct sock *newsk, struct sk_security_struct *newsksec = newsk->sk_security; newsksec->sid = req->secid; + newsksec->peer_sid = req->peer_secid; /* NOTE: Ideally, we should also get the isec->sid for the new socket in sync, but we don't have the isec available yet. So we will wait until sock_graft to do it, by which @@ -3677,6 +3681,14 @@ static void selinux_inet_csk_clone(struct sock *newsk, selinux_netlbl_sk_security_init(newsksec, req->rsk_ops->family); } +static void selinux_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ + struct sk_security_struct *sksec = sk->sk_security; + + selinux_skb_xfrm_sid(skb, &sksec->peer_sid); +} + static void selinux_req_classify_flow(const struct request_sock *req, struct flowi *fl) { @@ -4739,6 +4751,7 @@ static struct security_operations selinux_ops = { .sock_graft = selinux_sock_graft, .inet_conn_request = selinux_inet_conn_request, .inet_csk_clone = selinux_inet_csk_clone, + .inet_conn_established = selinux_inet_conn_established, .req_classify_flow = selinux_req_classify_flow, #ifdef CONFIG_SECURITY_NETWORK_XFRM diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 8e329ddb5e37..27502365d706 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -39,7 +39,6 @@ int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, struct avc_audit_data *ad); int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, struct avc_audit_data *ad); -u32 selinux_socket_getpeer_stream(struct sock *sk); u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); #else @@ -55,11 +54,6 @@ static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, return 0; } -static inline int selinux_socket_getpeer_stream(struct sock *sk) -{ - return SECSID_NULL; -} - static inline int selinux_socket_getpeer_dgram(struct sk_buff *skb) { return SECSID_NULL; @@ -71,4 +65,10 @@ static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int } #endif +static inline void selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid) +{ + int err = selinux_xfrm_decode_session(skb, sid, 0); + BUG_ON(err); +} + #endif /* _SELINUX_XFRM_H_ */ diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 4d5a043cdfa1..8fef74271f22 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -184,7 +184,8 @@ int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, } /* - * LSM hook implementation that determines the sid for the session. + * LSM hook implementation that checks and/or returns the xfrm sid for the + * incoming packet. */ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) @@ -402,44 +403,9 @@ void selinux_xfrm_state_free(struct xfrm_state *x) kfree(ctx); } -/* - * SELinux internal function to retrieve the context of a connected - * (sk->sk_state == TCP_ESTABLISHED) TCP socket based on its security - * association used to connect to the remote socket. - * - * Retrieve via getsockopt SO_PEERSEC. - */ -u32 selinux_socket_getpeer_stream(struct sock *sk) -{ - struct dst_entry *dst, *dst_test; - u32 peer_sid = SECSID_NULL; - - if (sk->sk_state != TCP_ESTABLISHED) - goto out; - - dst = sk_dst_get(sk); - if (!dst) - goto out; - - for (dst_test = dst; dst_test != 0; - dst_test = dst_test->child) { - struct xfrm_state *x = dst_test->xfrm; - - if (x && selinux_authorizable_xfrm(x)) { - struct xfrm_sec_ctx *ctx = x->security; - peer_sid = ctx->ctx_sid; - break; - } - } - dst_release(dst); - -out: - return peer_sid; -} - /* * SELinux internal function to retrieve the context of a UDP packet - * based on its security association used to connect to the remote socket. + * based on its security association. * * Retrieve via setsockopt IP_PASSSEC and recvmsg with control message * type SCM_SECURITY. -- cgit v1.2.3 From 67f83cbf081a70426ff667e8d14f94e13ed3bdca Mon Sep 17 00:00:00 2001 From: Venkat Yekkirala Date: Wed, 8 Nov 2006 17:04:26 -0600 Subject: SELinux: Fix SA selection semantics Fix the selection of an SA for an outgoing packet to be at the same context as the originating socket/flow. This eliminates the SELinux policy's ability to use/sendto SAs with contexts other than the socket's. With this patch applied, the SELinux policy will require one or more of the following for a socket to be able to communicate with/without SAs: 1. To enable a socket to communicate without using labeled-IPSec SAs: allow socket_t unlabeled_t:association { sendto recvfrom } 2. To enable a socket to communicate with labeled-IPSec SAs: allow socket_t self:association { sendto }; allow socket_t peer_sa_t:association { recvfrom }; Signed-off-by: Venkat Yekkirala Signed-off-by: James Morris --- include/linux/security.h | 19 -------- net/xfrm/xfrm_policy.c | 3 +- security/dummy.c | 7 --- security/selinux/hooks.c | 26 +++++++---- security/selinux/include/xfrm.h | 7 +-- security/selinux/xfrm.c | 101 +++++++++++++++++++--------------------- 6 files changed, 70 insertions(+), 93 deletions(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index 84cebcdb3f83..83cdefae9931 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -886,11 +886,6 @@ struct request_sock; * @xp contains the policy to check for a match. * @fl contains the flow to check for a match. * Return 1 if there is a match. - * @xfrm_flow_state_match: - * @fl contains the flow key to match. - * @xfrm points to the xfrm_state to match. - * @xp points to the xfrm_policy to match. - * Return 1 if there is a match. * @xfrm_decode_session: * @skb points to skb to decode. * @secid points to the flow key secid to set. @@ -1388,8 +1383,6 @@ struct security_operations { int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir); int (*xfrm_state_pol_flow_match)(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); - int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm, - struct xfrm_policy *xp); int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall); #endif /* CONFIG_SECURITY_NETWORK_XFRM */ @@ -3186,12 +3179,6 @@ static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, return security_ops->xfrm_state_pol_flow_match(x, xp, fl); } -static inline int security_xfrm_flow_state_match(struct flowi *fl, - struct xfrm_state *xfrm, struct xfrm_policy *xp) -{ - return security_ops->xfrm_flow_state_match(fl, xfrm, xp); -} - static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) { return security_ops->xfrm_decode_session(skb, secid, 1); @@ -3255,12 +3242,6 @@ static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, return 1; } -static inline int security_xfrm_flow_state_match(struct flowi *fl, - struct xfrm_state *xfrm, struct xfrm_policy *xp) -{ - return 1; -} - static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) { return 0; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 7736b23c3f03..b88b038530c9 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1894,7 +1894,8 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) return 0; - if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm, pol)) + if (fl && pol && + !security_xfrm_state_pol_flow_match(dst->xfrm, pol, fl)) return 0; if (dst->xfrm->km.state != XFRM_STATE_VALID) return 0; diff --git a/security/dummy.c b/security/dummy.c index 0148d1518dd1..558795b237d6 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -886,12 +886,6 @@ static int dummy_xfrm_state_pol_flow_match(struct xfrm_state *x, return 1; } -static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, - struct xfrm_policy *xp) -{ - return 1; -} - static int dummy_xfrm_decode_session(struct sk_buff *skb, u32 *fl, int ckall) { return 0; @@ -1126,7 +1120,6 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, xfrm_state_delete_security); set_to_dummy_if_null(ops, xfrm_policy_lookup); set_to_dummy_if_null(ops, xfrm_state_pol_flow_match); - set_to_dummy_if_null(ops, xfrm_flow_state_match); set_to_dummy_if_null(ops, xfrm_decode_session); #endif /* CONFIG_SECURITY_NETWORK_XFRM */ #ifdef CONFIG_KEYS diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5bbd599a4471..956137baf3e7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2889,7 +2889,8 @@ static void selinux_task_to_inode(struct task_struct *p, } /* Returns error only if unable to parse addresses */ -static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad) +static int selinux_parse_skb_ipv4(struct sk_buff *skb, + struct avc_audit_data *ad, u8 *proto) { int offset, ihlen, ret = -EINVAL; struct iphdr _iph, *ih; @@ -2907,6 +2908,9 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad ad->u.net.v4info.daddr = ih->daddr; ret = 0; + if (proto) + *proto = ih->protocol; + switch (ih->protocol) { case IPPROTO_TCP: { struct tcphdr _tcph, *th; @@ -2950,7 +2954,8 @@ out: #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) /* Returns error only if unable to parse addresses */ -static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad) +static int selinux_parse_skb_ipv6(struct sk_buff *skb, + struct avc_audit_data *ad, u8 *proto) { u8 nexthdr; int ret = -EINVAL, offset; @@ -2971,6 +2976,9 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad if (offset < 0) goto out; + if (proto) + *proto = nexthdr; + switch (nexthdr) { case IPPROTO_TCP: { struct tcphdr _tcph, *th; @@ -3007,13 +3015,13 @@ out: #endif /* IPV6 */ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, - char **addrp, int *len, int src) + char **addrp, int *len, int src, u8 *proto) { int ret = 0; switch (ad->u.net.family) { case PF_INET: - ret = selinux_parse_skb_ipv4(skb, ad); + ret = selinux_parse_skb_ipv4(skb, ad, proto); if (ret || !addrp) break; *len = 4; @@ -3023,7 +3031,7 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case PF_INET6: - ret = selinux_parse_skb_ipv6(skb, ad); + ret = selinux_parse_skb_ipv6(skb, ad, proto); if (ret || !addrp) break; *len = 16; @@ -3494,7 +3502,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; ad.u.net.family = family; - err = selinux_parse_skb(skb, &ad, &addrp, &len, 1); + err = selinux_parse_skb(skb, &ad, &addrp, &len, 1, NULL); if (err) goto out; @@ -3820,6 +3828,7 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, struct avc_audit_data ad; struct net_device *dev = (struct net_device *)out; struct sk_security_struct *sksec; + u8 proto; sk = skb->sk; if (!sk) @@ -3831,7 +3840,7 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, ad.u.net.netif = dev->name; ad.u.net.family = family; - err = selinux_parse_skb(skb, &ad, &addrp, &len, 0); + err = selinux_parse_skb(skb, &ad, &addrp, &len, 0, &proto); if (err) goto out; @@ -3845,7 +3854,7 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, if (err) goto out; - err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad); + err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto); out: return err ? NF_DROP : NF_ACCEPT; } @@ -4764,7 +4773,6 @@ static struct security_operations selinux_ops = { .xfrm_state_delete_security = selinux_xfrm_state_delete, .xfrm_policy_lookup = selinux_xfrm_policy_lookup, .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match, - .xfrm_flow_state_match = selinux_xfrm_flow_state_match, .xfrm_decode_session = selinux_xfrm_decode_session, #endif diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 27502365d706..ebd7246a4be5 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -19,9 +19,6 @@ int selinux_xfrm_state_delete(struct xfrm_state *x); int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); -int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, - struct xfrm_policy *xp); - /* * Extract the security blob from the sock (it's actually on the socket) @@ -38,7 +35,7 @@ static inline struct inode_security_struct *get_sock_isec(struct sock *sk) int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, struct avc_audit_data *ad); int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad); + struct avc_audit_data *ad, u8 proto); u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); #else @@ -49,7 +46,7 @@ static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, } static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad) + struct avc_audit_data *ad, u8 proto) { return 0; } diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 8fef74271f22..9b777140068f 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -115,71 +115,40 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * struct flowi *fl) { u32 state_sid; - u32 pol_sid; - int err; + int rc; - if (xp->security) { - if (!x->security) - /* unlabeled SA and labeled policy can't match */ - return 0; - else - state_sid = x->security->ctx_sid; - pol_sid = xp->security->ctx_sid; - } else + if (!xp->security) if (x->security) /* unlabeled policy and labeled SA can't match */ return 0; else /* unlabeled policy and unlabeled SA match all flows */ return 1; - - err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION, - ASSOCIATION__POLMATCH, - NULL); - - if (err) - return 0; - - err = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, - ASSOCIATION__SENDTO, - NULL)? 0:1; - - return err; -} - -/* - * LSM hook implementation that authorizes that a particular outgoing flow - * can use a given security association. - */ - -int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, - struct xfrm_policy *xp) -{ - int rc = 0; - u32 sel_sid = SECINITSID_UNLABELED; - struct xfrm_sec_ctx *ctx; - - if (!xp->security) - if (!xfrm->security) - return 1; - else - return 0; else - if (!xfrm->security) + if (!x->security) + /* unlabeled SA and labeled policy can't match */ return 0; + else + if (!selinux_authorizable_xfrm(x)) + /* Not a SELinux-labeled SA */ + return 0; - /* Context sid is either set to label or ANY_ASSOC */ - if ((ctx = xfrm->security)) { - if (!selinux_authorizable_ctx(ctx)) - return 0; + state_sid = x->security->ctx_sid; - sel_sid = ctx->ctx_sid; - } + if (fl->secid != state_sid) + return 0; - rc = avc_has_perm(fl->secid, sel_sid, SECCLASS_ASSOCIATION, + rc = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, NULL)? 0:1; + /* + * We don't need a separate SA Vs. policy polmatch check + * since the SA is now of the same label as the flow and + * a flow Vs. policy polmatch check had already happened + * in selinux_xfrm_policy_lookup() above. + */ + return rc; } @@ -481,6 +450,13 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, } } + /* + * This check even when there's no association involved is + * intended, according to Trent Jaeger, to make sure a + * process can't engage in non-ipsec communication unless + * explicitly allowed by policy. + */ + rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad); @@ -492,10 +468,10 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, * If we have no security association, then we need to determine * whether the socket is allowed to send to an unlabelled destination. * If we do have a authorizable security association, then it has already been - * checked in xfrm_policy_lookup hook. + * checked in the selinux_xfrm_state_pol_flow_match hook above. */ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad) + struct avc_audit_data *ad, u8 proto) { struct dst_entry *dst; int rc = 0; @@ -514,6 +490,27 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, } } + switch (proto) { + case IPPROTO_AH: + case IPPROTO_ESP: + case IPPROTO_COMP: + /* + * We should have already seen this packet once before + * it underwent xfrm(s). No need to subject it to the + * unlabeled check. + */ + goto out; + default: + break; + } + + /* + * This check even when there's no association involved is + * intended, according to Trent Jaeger, to make sure a + * process can't engage in non-ipsec communication unless + * explicitly allowed by policy. + */ + rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad); out: -- cgit v1.2.3 From 82e91ffef60e6eba9848fe149ce1eecd2b5aef12 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:19:14 -0800 Subject: [NET]: Turn nfmark into generic mark nfmark is being used in various subsystems and has become the defacto mark field for all kinds of packets. Therefore it makes sense to rename it to `mark' and remove the dependency on CONFIG_NETFILTER. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++-- net/bridge/netfilter/ebt_mark.c | 8 ++++---- net/bridge/netfilter/ebt_mark_m.c | 4 ++-- net/bridge/netfilter/ebt_ulog.c | 2 +- net/core/skbuff.c | 4 ++-- net/decnet/dn_route.c | 4 ++-- net/ipv4/ip_output.c | 2 +- net/ipv4/ipvs/ip_vs_proto_tcp.c | 2 +- net/ipv4/ipvs/ip_vs_proto_udp.c | 2 +- net/ipv4/netfilter.c | 2 +- net/ipv4/netfilter/ip_queue.c | 2 +- net/ipv4/netfilter/ipt_REJECT.c | 2 +- net/ipv4/netfilter/ipt_ULOG.c | 2 +- net/ipv4/netfilter/iptable_mangle.c | 6 +++--- net/ipv4/route.c | 10 +++++----- net/ipv6/ip6_output.c | 2 +- net/ipv6/netfilter/ip6_queue.c | 2 +- net/ipv6/netfilter/ip6table_mangle.c | 9 ++++----- net/ipv6/route.c | 2 +- net/netfilter/nfnetlink_log.c | 4 ++-- net/netfilter/nfnetlink_queue.c | 8 ++++---- net/netfilter/xt_CONNMARK.c | 10 +++++----- net/netfilter/xt_MARK.c | 12 ++++++------ net/netfilter/xt_mark.c | 2 +- net/sched/Kconfig | 2 +- net/sched/cls_fw.c | 6 +----- net/sched/cls_u32.c | 2 +- net/sched/em_meta.c | 10 +++------- 28 files changed, 59 insertions(+), 68 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7fc9a3aaa1c9..e3ae544b3956 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -216,7 +216,7 @@ enum { * @tail: Tail pointer * @end: End pointer * @destructor: Destruct function - * @nfmark: Can be used for communication between hooks + * @mark: Generic packet mark * @nfct: Associated connection, if any * @ipvs_property: skbuff is owned by ipvs * @nfctinfo: Relationship of this skb to the connection @@ -295,7 +295,6 @@ struct sk_buff { #ifdef CONFIG_BRIDGE_NETFILTER struct nf_bridge_info *nf_bridge; #endif - __u32 nfmark; #endif /* CONFIG_NETFILTER */ #ifdef CONFIG_NET_SCHED __u16 tc_index; /* traffic control index */ @@ -310,6 +309,7 @@ struct sk_buff { __u32 secmark; #endif + __u32 mark; /* These elements must be at the end, see alloc_skb() for details. */ unsigned int truesize; diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c index b54306a934e5..2458638561cb 100644 --- a/net/bridge/netfilter/ebt_mark.c +++ b/net/bridge/netfilter/ebt_mark.c @@ -25,13 +25,13 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr, int action = info->target & -16; if (action == MARK_SET_VALUE) - (*pskb)->nfmark = info->mark; + (*pskb)->mark = info->mark; else if (action == MARK_OR_VALUE) - (*pskb)->nfmark |= info->mark; + (*pskb)->mark |= info->mark; else if (action == MARK_AND_VALUE) - (*pskb)->nfmark &= info->mark; + (*pskb)->mark &= info->mark; else - (*pskb)->nfmark ^= info->mark; + (*pskb)->mark ^= info->mark; return info->target | -16; } diff --git a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c index a6413e4b4982..025869ee0b68 100644 --- a/net/bridge/netfilter/ebt_mark_m.c +++ b/net/bridge/netfilter/ebt_mark_m.c @@ -19,8 +19,8 @@ static int ebt_filter_mark(const struct sk_buff *skb, struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data; if (info->bitmask & EBT_MARK_OR) - return !(!!(skb->nfmark & info->mask) ^ info->invert); - return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert); + return !(!!(skb->mark & info->mask) ^ info->invert); + return !(((skb->mark & info->mask) == info->mark) ^ info->invert); } static int ebt_mark_check(const char *tablename, unsigned int hookmask, diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index 9f950db3b76f..c1af68b5a29c 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c @@ -168,7 +168,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, if (ub->qlen == 1) skb_set_timestamp(ub->skb, &pm->stamp); pm->data_len = copy_len; - pm->mark = skb->nfmark; + pm->mark = skb->mark; pm->hook = hooknr; if (uloginfo->prefix != NULL) strcpy(pm->prefix, uloginfo->prefix); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index b8b106358040..b3dea1ef9535 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -473,8 +473,8 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) #endif C(protocol); n->destructor = NULL; + C(mark); #ifdef CONFIG_NETFILTER - C(nfmark); C(nfct); nf_conntrack_get(skb->nfct); C(nfctinfo); @@ -534,8 +534,8 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->pkt_type = old->pkt_type; new->tstamp = old->tstamp; new->destructor = NULL; + new->mark = old->mark; #ifdef CONFIG_NETFILTER - new->nfmark = old->nfmark; new->nfct = old->nfct; nf_conntrack_get(old->nfct); new->nfctinfo = old->nfctinfo; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 23489f7232d2..3482839af280 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1236,7 +1236,7 @@ static int dn_route_input_slow(struct sk_buff *skb) .saddr = cb->src, .scope = RT_SCOPE_UNIVERSE, #ifdef CONFIG_DECNET_ROUTE_FWMARK - .fwmark = skb->nfmark + .fwmark = skb->mark #endif } }, .iif = skb->dev->ifindex }; @@ -1458,7 +1458,7 @@ int dn_route_input(struct sk_buff *skb) (rt->fl.fld_dst == cb->dst) && (rt->fl.oif == 0) && #ifdef CONFIG_DECNET_ROUTE_FWMARK - (rt->fl.fld_fwmark == skb->nfmark) && + (rt->fl.fld_fwmark == skb->mark) && #endif (rt->fl.iif == cb->iif)) { rt->u.dst.lastuse = jiffies; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index fc195a44fc2e..23633bf042ba 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -386,6 +386,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) dst_release(to->dst); to->dst = dst_clone(from->dst); to->dev = from->dev; + to->mark = from->mark; /* Copy the flags to each fragment. */ IPCB(to)->flags = IPCB(from)->flags; @@ -394,7 +395,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->tc_index = from->tc_index; #endif #ifdef CONFIG_NETFILTER - to->nfmark = from->nfmark; /* Connection association is same as pre-frag packet */ nf_conntrack_put(to->nfct); to->nfct = from->nfct; diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c index 6ff05c3a32e6..7de385267b33 100644 --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c @@ -84,7 +84,7 @@ tcp_conn_schedule(struct sk_buff *skb, } if (th->syn && - (svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol, + (svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol, skb->nh.iph->daddr, th->dest))) { if (ip_vs_todrop()) { /* diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 691c8b637b29..452cb9c384b3 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c @@ -89,7 +89,7 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp, return 0; } - if ((svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol, + if ((svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol, skb->nh.iph->daddr, uh->dest))) { if (ip_vs_todrop()) { /* diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index e2005c6810a4..bfc8d753a23a 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -28,7 +28,7 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0; #ifdef CONFIG_IP_ROUTE_FWMARK - fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark; + fl.nl_u.ip4_u.fwmark = (*pskb)->mark; #endif if (ip_route_output_key(&rt, &fl) != 0) return -1; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 97556cc2e4e0..cd520df4dcf4 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -243,7 +243,7 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) pmsg->data_len = data_len; pmsg->timestamp_sec = entry->skb->tstamp.off_sec; pmsg->timestamp_usec = entry->skb->tstamp.off_usec; - pmsg->mark = entry->skb->nfmark; + pmsg->mark = entry->skb->mark; pmsg->hook = entry->info->hook; pmsg->hw_protocol = entry->skb->protocol; diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 264763adc39b..f0319e5ee437 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -76,7 +76,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) /* This packet will not be the same as the other: clear nf fields */ nf_reset(nskb); - nskb->nfmark = 0; + nskb->mark = 0; skb_init_secmark(nskb); tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 2b104ea54f48..dbd34783a64d 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -239,7 +239,7 @@ static void ipt_ulog_packet(unsigned int hooknum, pm->data_len = copy_len; pm->timestamp_sec = skb->tstamp.off_sec; pm->timestamp_usec = skb->tstamp.off_usec; - pm->mark = skb->nfmark; + pm->mark = skb->mark; pm->hook = hooknum; if (prefix != NULL) strncpy(pm->prefix, prefix, sizeof(pm->prefix)); diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index b91f3582359b..62d4ccc259ca 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -132,7 +132,7 @@ ipt_local_hook(unsigned int hook, unsigned int ret; u_int8_t tos; __be32 saddr, daddr; - unsigned long nfmark; + u_int32_t mark; /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) @@ -143,7 +143,7 @@ ipt_local_hook(unsigned int hook, } /* Save things which could affect route */ - nfmark = (*pskb)->nfmark; + mark = (*pskb)->mark; saddr = (*pskb)->nh.iph->saddr; daddr = (*pskb)->nh.iph->daddr; tos = (*pskb)->nh.iph->tos; @@ -154,7 +154,7 @@ ipt_local_hook(unsigned int hook, && ((*pskb)->nh.iph->saddr != saddr || (*pskb)->nh.iph->daddr != daddr #ifdef CONFIG_IP_ROUTE_FWMARK - || (*pskb)->nfmark != nfmark + || (*pskb)->mark != mark #endif || (*pskb)->nh.iph->tos != tos)) if (ip_route_me_harder(pskb, RTN_UNSPEC)) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 925ee4dfc32c..4de3e38fa1a8 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1644,7 +1644,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->rt_dst = daddr; rth->fl.fl4_tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->nfmark; + rth->fl.fl4_fwmark= skb->mark; #endif rth->fl.fl4_src = saddr; rth->rt_src = saddr; @@ -1790,7 +1790,7 @@ static inline int __mkroute_input(struct sk_buff *skb, rth->rt_dst = daddr; rth->fl.fl4_tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->nfmark; + rth->fl.fl4_fwmark= skb->mark; #endif rth->fl.fl4_src = saddr; rth->rt_src = saddr; @@ -1921,7 +1921,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, .tos = tos, .scope = RT_SCOPE_UNIVERSE, #ifdef CONFIG_IP_ROUTE_FWMARK - .fwmark = skb->nfmark + .fwmark = skb->mark #endif } }, .iif = dev->ifindex }; @@ -2035,7 +2035,7 @@ local_input: rth->rt_dst = daddr; rth->fl.fl4_tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->nfmark; + rth->fl.fl4_fwmark= skb->mark; #endif rth->fl.fl4_src = saddr; rth->rt_src = saddr; @@ -2114,7 +2114,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->fl.iif == iif && rth->fl.oif == 0 && #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark == skb->nfmark && + rth->fl.fl4_fwmark == skb->mark && #endif rth->fl.fl4_tos == tos) { rth->u.dst.lastuse = jiffies; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 93330685adfc..1bde3aca3466 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -499,12 +499,12 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) dst_release(to->dst); to->dst = dst_clone(from->dst); to->dev = from->dev; + to->mark = from->mark; #ifdef CONFIG_NET_SCHED to->tc_index = from->tc_index; #endif #ifdef CONFIG_NETFILTER - to->nfmark = from->nfmark; /* Connection association is same as pre-frag packet */ nf_conntrack_put(to->nfct); to->nfct = from->nfct; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 9fec832ee08b..21908c9a10da 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -241,7 +241,7 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) pmsg->data_len = data_len; pmsg->timestamp_sec = entry->skb->tstamp.off_sec; pmsg->timestamp_usec = entry->skb->tstamp.off_usec; - pmsg->mark = entry->skb->nfmark; + pmsg->mark = entry->skb->mark; pmsg->hook = entry->info->hook; pmsg->hw_protocol = entry->skb->protocol; diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 386ea260e767..6250e86a6ddc 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -149,11 +149,10 @@ ip6t_local_hook(unsigned int hook, int (*okfn)(struct sk_buff *)) { - unsigned long nfmark; unsigned int ret; struct in6_addr saddr, daddr; u_int8_t hop_limit; - u_int32_t flowlabel; + u_int32_t flowlabel, mark; #if 0 /* root is playing with raw sockets. */ @@ -165,10 +164,10 @@ ip6t_local_hook(unsigned int hook, } #endif - /* save source/dest address, nfmark, hoplimit, flowlabel, priority, */ + /* save source/dest address, mark, hoplimit, flowlabel, priority, */ memcpy(&saddr, &(*pskb)->nh.ipv6h->saddr, sizeof(saddr)); memcpy(&daddr, &(*pskb)->nh.ipv6h->daddr, sizeof(daddr)); - nfmark = (*pskb)->nfmark; + mark = (*pskb)->mark; hop_limit = (*pskb)->nh.ipv6h->hop_limit; /* flowlabel and prio (includes version, which shouldn't change either */ @@ -179,7 +178,7 @@ ip6t_local_hook(unsigned int hook, if (ret != NF_DROP && ret != NF_STOLEN && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr)) || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr)) - || (*pskb)->nfmark != nfmark + || (*pskb)->mark != mark || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) return ip6_route_me_harder(*pskb) == 0 ? ret : NF_DROP; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e9c1fc5f21b1..aaabb1fad1cf 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -712,7 +712,7 @@ void ip6_route_input(struct sk_buff *skb) .daddr = iph->daddr, .saddr = iph->saddr, #ifdef CONFIG_IPV6_ROUTE_FWMARK - .fwmark = skb->nfmark, + .fwmark = skb->mark, #endif .flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, }, diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 856ed0d19974..bd3ffa6f1a6d 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -501,8 +501,8 @@ __build_packet_message(struct nfulnl_instance *inst, #endif } - if (skb->nfmark) { - tmp_uint = htonl(skb->nfmark); + if (skb->mark) { + tmp_uint = htonl(skb->mark); NFA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 4ab7b1416bb5..82e4454659bf 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -480,8 +480,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, #endif } - if (entskb->nfmark) { - tmp_uint = htonl(entskb->nfmark); + if (entskb->mark) { + tmp_uint = htonl(entskb->mark); NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint); } @@ -834,8 +834,8 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, } if (nfqa[NFQA_MARK-1]) - entry->skb->nfmark = ntohl(*(__be32 *) - NFA_DATA(nfqa[NFQA_MARK-1])); + entry->skb->mark = ntohl(*(__be32 *) + NFA_DATA(nfqa[NFQA_MARK-1])); issue_verdict(entry, verdict); instance_put(queue); diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c index c01524f817f0..67ed53152999 100644 --- a/net/netfilter/xt_CONNMARK.c +++ b/net/netfilter/xt_CONNMARK.c @@ -42,7 +42,7 @@ target(struct sk_buff **pskb, { const struct xt_connmark_target_info *markinfo = targinfo; u_int32_t diff; - u_int32_t nfmark; + u_int32_t mark; u_int32_t newmark; u_int32_t ctinfo; u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo); @@ -62,7 +62,7 @@ target(struct sk_buff **pskb, break; case XT_CONNMARK_SAVE: newmark = (*ctmark & ~markinfo->mask) | - ((*pskb)->nfmark & markinfo->mask); + ((*pskb)->mark & markinfo->mask); if (*ctmark != newmark) { *ctmark = newmark; #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) @@ -73,10 +73,10 @@ target(struct sk_buff **pskb, } break; case XT_CONNMARK_RESTORE: - nfmark = (*pskb)->nfmark; - diff = (*ctmark ^ nfmark) & markinfo->mask; + mark = (*pskb)->mark; + diff = (*ctmark ^ mark) & markinfo->mask; if (diff != 0) - (*pskb)->nfmark = nfmark ^ diff; + (*pskb)->mark = mark ^ diff; break; } } diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c index c6e860a7114f..0b48547e8d64 100644 --- a/net/netfilter/xt_MARK.c +++ b/net/netfilter/xt_MARK.c @@ -31,8 +31,8 @@ target_v0(struct sk_buff **pskb, { const struct xt_mark_target_info *markinfo = targinfo; - if((*pskb)->nfmark != markinfo->mark) - (*pskb)->nfmark = markinfo->mark; + if((*pskb)->mark != markinfo->mark) + (*pskb)->mark = markinfo->mark; return XT_CONTINUE; } @@ -54,16 +54,16 @@ target_v1(struct sk_buff **pskb, break; case XT_MARK_AND: - mark = (*pskb)->nfmark & markinfo->mark; + mark = (*pskb)->mark & markinfo->mark; break; case XT_MARK_OR: - mark = (*pskb)->nfmark | markinfo->mark; + mark = (*pskb)->mark | markinfo->mark; break; } - if((*pskb)->nfmark != mark) - (*pskb)->nfmark = mark; + if((*pskb)->mark != mark) + (*pskb)->mark = mark; return XT_CONTINUE; } diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c index 934dddfbcd23..dfa1ee6914c0 100644 --- a/net/netfilter/xt_mark.c +++ b/net/netfilter/xt_mark.c @@ -31,7 +31,7 @@ match(const struct sk_buff *skb, { const struct xt_mark_info *info = matchinfo; - return ((skb->nfmark & info->mask) == info->mark) ^ info->invert; + return ((skb->mark & info->mask) == info->mark) ^ info->invert; } static int diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 8298ea9ffe19..b2437092978c 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -320,7 +320,7 @@ config CLS_U32_PERF config CLS_U32_MARK bool "Netfilter marks support" - depends on NET_CLS_U32 && NETFILTER + depends on NET_CLS_U32 ---help--- Say Y here to be able to use netfilter marks as u32 key. diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index e54acc6bcccd..f59a2c4aa039 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -101,11 +101,7 @@ static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp, struct fw_head *head = (struct fw_head*)tp->root; struct fw_filter *f; int r; -#ifdef CONFIG_NETFILTER - u32 id = skb->nfmark & head->mask; -#else - u32 id = 0; -#endif + u32 id = skb->mark & head->mask; if (head != NULL) { for (f=head->ht[fw_hash(id)]; f; f=f->next) { diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 0a6cfa0005be..8b5194801995 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -143,7 +143,7 @@ next_knode: #endif #ifdef CONFIG_CLS_U32_MARK - if ((skb->nfmark & n->mark.mask) != n->mark.val) { + if ((skb->mark & n->mark.mask) != n->mark.val) { n = n->next; goto next_knode; } else { diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 61e3b740ab1a..d3ff3503326a 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -208,13 +208,9 @@ META_COLLECTOR(int_maclen) * Netfilter **************************************************************************/ -META_COLLECTOR(int_nfmark) +META_COLLECTOR(int_mark) { -#ifdef CONFIG_NETFILTER - dst->value = skb->nfmark; -#else - dst->value = 0; -#endif + dst->value = skb->mark; } /************************************************************************** @@ -490,7 +486,7 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = { [META_ID(PKTLEN)] = META_FUNC(int_pktlen), [META_ID(DATALEN)] = META_FUNC(int_datalen), [META_ID(MACLEN)] = META_FUNC(int_maclen), - [META_ID(NFMARK)] = META_FUNC(int_nfmark), + [META_ID(NFMARK)] = META_FUNC(int_mark), [META_ID(TCINDEX)] = META_FUNC(int_tcindex), [META_ID(RTCLASSID)] = META_FUNC(int_rtclassid), [META_ID(RTIIF)] = META_FUNC(int_rtiif), -- cgit v1.2.3 From b8964ed9fa727109c9084abc807652ebfb681c18 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:22:18 -0800 Subject: [NET] rules: Protocol independant mark selector Move mark selector currently implemented per protocol into the protocol independant part. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/fib_rules.h | 2 +- include/net/fib_rules.h | 2 ++ net/core/fib_rules.c | 29 +++++++++++++++++++++++++++++ net/decnet/dn_rules.c | 27 --------------------------- net/ipv4/fib_rules.c | 29 ----------------------------- net/ipv6/fib6_rules.c | 32 -------------------------------- 6 files changed, 32 insertions(+), 89 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index 4418c8d9d479..adcdfbdd14d5 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -34,7 +34,7 @@ enum FRA_UNUSED3, FRA_UNUSED4, FRA_UNUSED5, - FRA_FWMARK, /* netfilter mark */ + FRA_FWMARK, /* mark */ FRA_FLOW, /* flow/class id */ FRA_UNUSED6, FRA_UNUSED7, diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 8e2f473d3e82..68542b565cf7 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -13,6 +13,8 @@ struct fib_rule atomic_t refcnt; int ifindex; char ifname[IFNAMSIZ]; + u32 mark; + u32 mark_mask; u32 pref; u32 flags; u32 table; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 6b0e63cacd93..da91bf2e6151 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -119,6 +119,9 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl, if (rule->ifindex && (rule->ifindex != fl->iif)) continue; + if ((rule->mark ^ fl->mark) & rule->mark_mask) + continue; + if (!ops->match(rule, fl, flags)) continue; @@ -179,6 +182,18 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) rule->ifindex = dev->ifindex; } + if (tb[FRA_FWMARK]) { + rule->mark = nla_get_u32(tb[FRA_FWMARK]); + if (rule->mark) + /* compatibility: if the mark value is non-zero all bits + * are compared unless a mask is explicitly specified. + */ + rule->mark_mask = 0xFFFFFFFF; + } + + if (tb[FRA_FWMASK]) + rule->mark_mask = nla_get_u32(tb[FRA_FWMASK]); + rule->action = frh->action; rule->flags = frh->flags; rule->table = frh_get_table(frh, tb); @@ -250,6 +265,14 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) nla_strcmp(tb[FRA_IFNAME], rule->ifname)) continue; + if (tb[FRA_FWMARK] && + (rule->mark != nla_get_u32(tb[FRA_FWMARK]))) + continue; + + if (tb[FRA_FWMASK] && + (rule->mark_mask != nla_get_u32(tb[FRA_FWMASK]))) + continue; + if (!ops->compare(rule, frh, tb)) continue; @@ -298,6 +321,12 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, if (rule->pref) NLA_PUT_U32(skb, FRA_PRIORITY, rule->pref); + if (rule->mark) + NLA_PUT_U32(skb, FRA_FWMARK, rule->mark); + + if (rule->mark_mask || rule->mark) + NLA_PUT_U32(skb, FRA_FWMASK, rule->mark_mask); + if (ops->fill(rule, skb, nlh, frh) < 0) goto nla_put_failure; diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index a09c09f5572d..1f5d23c96681 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -45,8 +45,6 @@ struct dn_fib_rule __le16 dstmask; __le16 srcmap; u8 flags; - u32 fwmark; - u32 fwmask; }; static struct dn_fib_rule default_rule = { @@ -129,9 +127,6 @@ static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) ((daddr ^ r->dst) & r->dstmask)) return 0; - if ((r->fwmark ^ fl->mark) & r->fwmask) - return 0; - return 1; } @@ -165,18 +160,6 @@ static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, if (tb[FRA_DST]) r->dst = nla_get_u16(tb[FRA_DST]); - if (tb[FRA_FWMARK]) { - r->fwmark = nla_get_u32(tb[FRA_FWMARK]); - if (r->fwmark) - /* compatibility: if the mark value is non-zero all bits - * are compared unless a mask is explicitly specified. - */ - r->fwmask = 0xFFFFFFFF; - } - - if (tb[FRA_FWMASK]) - r->fwmask = nla_get_u32(tb[FRA_FWMASK]); - r->src_len = frh->src_len; r->srcmask = dnet_make_mask(r->src_len); r->dst_len = frh->dst_len; @@ -197,12 +180,6 @@ static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, if (frh->dst_len && (r->dst_len != frh->dst_len)) return 0; - if (tb[FRA_FWMARK] && (r->fwmark != nla_get_u32(tb[FRA_FWMARK]))) - return 0; - - if (tb[FRA_FWMASK] && (r->fwmask != nla_get_u32(tb[FRA_FWMASK]))) - return 0; - if (tb[FRA_SRC] && (r->src != nla_get_u16(tb[FRA_SRC]))) return 0; @@ -240,10 +217,6 @@ static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb, frh->src_len = r->src_len; frh->tos = 0; - if (r->fwmark) - NLA_PUT_U32(skb, FRA_FWMARK, r->fwmark); - if (r->fwmask || r->fwmark) - NLA_PUT_U32(skb, FRA_FWMASK, r->fwmask); if (r->dst_len) NLA_PUT_U16(skb, FRA_DST, r->dst); if (r->src_len) diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index de8d5dd7099b..d2a190a35d65 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -44,8 +44,6 @@ struct fib4_rule __be32 srcmask; __be32 dst; __be32 dstmask; - u32 fwmark; - u32 fwmask; #ifdef CONFIG_NET_CLS_ROUTE u32 tclassid; #endif @@ -158,9 +156,6 @@ static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) if (r->tos && (r->tos != fl->fl4_tos)) return 0; - if ((r->fwmark ^ fl->mark) & r->fwmask) - return 0; - return 1; } @@ -216,18 +211,6 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, if (tb[FRA_DST]) rule4->dst = nla_get_be32(tb[FRA_DST]); - if (tb[FRA_FWMARK]) { - rule4->fwmark = nla_get_u32(tb[FRA_FWMARK]); - if (rule4->fwmark) - /* compatibility: if the mark value is non-zero all bits - * are compared unless a mask is explicitly specified. - */ - rule4->fwmask = 0xFFFFFFFF; - } - - if (tb[FRA_FWMASK]) - rule4->fwmask = nla_get_u32(tb[FRA_FWMASK]); - #ifdef CONFIG_NET_CLS_ROUTE if (tb[FRA_FLOW]) rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); @@ -258,12 +241,6 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, if (frh->tos && (rule4->tos != frh->tos)) return 0; - if (tb[FRA_FWMARK] && (rule4->fwmark != nla_get_u32(tb[FRA_FWMARK]))) - return 0; - - if (tb[FRA_FWMASK] && (rule4->fwmask != nla_get_u32(tb[FRA_FWMASK]))) - return 0; - #ifdef CONFIG_NET_CLS_ROUTE if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW]))) return 0; @@ -288,12 +265,6 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, frh->src_len = rule4->src_len; frh->tos = rule4->tos; - if (rule4->fwmark) - NLA_PUT_U32(skb, FRA_FWMARK, rule4->fwmark); - - if (rule4->fwmask || rule4->fwmark) - NLA_PUT_U32(skb, FRA_FWMASK, rule4->fwmask); - if (rule4->dst_len) NLA_PUT_BE32(skb, FRA_DST, rule4->dst); diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 89bea64eee1c..26374cbe2bc2 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -25,8 +25,6 @@ struct fib6_rule struct fib_rule common; struct rt6key src; struct rt6key dst; - u32 fwmark; - u32 fwmask; u8 tclass; }; @@ -128,9 +126,6 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff)) return 0; - if ((r->fwmark ^ fl->mark) & r->fwmask) - return 0; - return 1; } @@ -173,21 +168,6 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, nla_memcpy(&rule6->dst.addr, tb[FRA_DST], sizeof(struct in6_addr)); - if (tb[FRA_FWMARK]) { - rule6->fwmark = nla_get_u32(tb[FRA_FWMARK]); - if (rule6->fwmark) { - /* - * if the mark value is non-zero, - * all bits are compared by default - * unless a mask is explicitly specified. - */ - rule6->fwmask = 0xFFFFFFFF; - } - } - - if (tb[FRA_FWMASK]) - rule6->fwmask = nla_get_u32(tb[FRA_FWMASK]); - rule6->src.plen = frh->src_len; rule6->dst.plen = frh->dst_len; rule6->tclass = frh->tos; @@ -219,12 +199,6 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr))) return 0; - if (tb[FRA_FWMARK] && (rule6->fwmark != nla_get_u32(tb[FRA_FWMARK]))) - return 0; - - if (tb[FRA_FWMASK] && (rule6->fwmask != nla_get_u32(tb[FRA_FWMASK]))) - return 0; - return 1; } @@ -246,12 +220,6 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb, NLA_PUT(skb, FRA_SRC, sizeof(struct in6_addr), &rule6->src.addr); - if (rule6->fwmark) - NLA_PUT_U32(skb, FRA_FWMARK, rule6->fwmark); - - if (rule6->fwmask || rule6->fwmark) - NLA_PUT_U32(skb, FRA_FWMASK, rule6->fwmask); - return 0; nla_put_failure: -- cgit v1.2.3 From 3dfbcc411e461db51a1ac1aa1c6ebe2c5a0275a0 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:23:20 -0800 Subject: [NET] rules: Add support to invert selectors Introduces a new flag FIB_RULE_INVERT causing rules to apply if the specified selector doesn't match. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/fib_rules.h | 1 + net/core/fib_rules.c | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index adcdfbdd14d5..8270aac2aa5d 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -6,6 +6,7 @@ /* rule is permanent, and cannot be deleted */ #define FIB_RULE_PERMANENT 1 +#define FIB_RULE_INVERT 2 struct fib_rule_hdr { diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index da91bf2e6151..4148e274a204 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -107,6 +107,22 @@ out: EXPORT_SYMBOL_GPL(fib_rules_unregister); +static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, + struct flowi *fl, int flags) +{ + int ret = 0; + + if (rule->ifindex && (rule->ifindex != fl->iif)) + goto out; + + if ((rule->mark ^ fl->mark) & rule->mark_mask) + goto out; + + ret = ops->match(rule, fl, flags); +out: + return (rule->flags & FIB_RULE_INVERT) ? !ret : ret; +} + int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl, int flags, struct fib_lookup_arg *arg) { @@ -116,13 +132,7 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl, rcu_read_lock(); list_for_each_entry_rcu(rule, ops->rules_list, list) { - if (rule->ifindex && (rule->ifindex != fl->iif)) - continue; - - if ((rule->mark ^ fl->mark) & rule->mark_mask) - continue; - - if (!ops->match(rule, fl, flags)) + if (!fib_rule_match(rule, ops, fl, flags)) continue; err = ops->action(rule, fl, flags, arg); -- cgit v1.2.3 From 3ff825b28d3345ef381eceae22bf9d92231f23dc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Nov 2006 16:32:06 -0800 Subject: [TCP]: Add tcp_available_congestion_control sysctl. Create /proc/sys/net/ipv4/tcp_available_congestion_control that reflects currently available TCP choices. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 6 ++++++ include/linux/sysctl.h | 1 + include/net/tcp.h | 4 ++++ net/ipv4/sysctl_net_ipv4.c | 24 ++++++++++++++++++++++++ net/ipv4/tcp_cong.c | 16 ++++++++++++++++ 5 files changed, 51 insertions(+) (limited to 'include/linux') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index fd3c0c012351..db4280856588 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -351,10 +351,16 @@ tcp_frto - BOOLEAN where packet loss is typically due to random radio interference rather than intermediate router congestion. +tcp_available_congestion_control - STRING + Shows the available congestion control choices that are registered. + More congestion control algorithms may be available as modules, + but not loaded. + tcp_congestion_control - STRING Set the congestion control algorithm to be used for new connections. The algorithm "reno" is always available, but additional choices may be available based on kernel configuration. + Default is set as part of kernel configuration. somaxconn - INTEGER Limit of socket listen() backlog, known in userspace as SOMAXCONN. diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index d98562f1df76..28a48279654d 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -426,6 +426,7 @@ enum NET_CIPSOV4_CACHE_BUCKET_SIZE=119, NET_CIPSOV4_RBM_OPTFMT=120, NET_CIPSOV4_RBM_STRICTVALID=121, + NET_TCP_AVAIL_CONG_CONTROL=122, }; enum { diff --git a/include/net/tcp.h b/include/net/tcp.h index 246916c2321e..6af4baf5b769 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -620,6 +620,9 @@ enum tcp_ca_event { * Interface for adding new TCP congestion control handlers */ #define TCP_CA_NAME_MAX 16 +#define TCP_CA_MAX 128 +#define TCP_CA_BUF_MAX (TCP_CA_NAME_MAX*TCP_CA_MAX) + struct tcp_congestion_ops { struct list_head list; @@ -659,6 +662,7 @@ extern void tcp_init_congestion_control(struct sock *sk); extern void tcp_cleanup_congestion_control(struct sock *sk); extern int tcp_set_default_congestion_control(const char *name); extern void tcp_get_default_congestion_control(char *name); +extern void tcp_get_available_congestion_control(char *buf, size_t len); extern int tcp_set_congestion_control(struct sock *sk, const char *name); extern void tcp_slow_start(struct tcp_sock *tp); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 15061b314411..2e770f45d829 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -129,6 +129,23 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name, return ret; } +static int proc_tcp_available_congestion_control(ctl_table *ctl, + int write, struct file * filp, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX, }; + int ret; + + tbl.data = kmalloc(tbl.maxlen, GFP_USER); + if (!tbl.data) + return -ENOMEM; + tcp_get_available_congestion_control(tbl.data, TCP_CA_BUF_MAX); + ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); + kfree(tbl.data); + return ret; +} + ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_TCP_TIMESTAMPS, @@ -731,6 +748,13 @@ ctl_table ipv4_table[] = { .proc_handler = &proc_dointvec, }, #endif /* CONFIG_NETLABEL */ + { + .ctl_name = NET_TCP_AVAIL_CONG_CONTROL, + .procname = "tcp_available_congestion_control", + .maxlen = TCP_CA_BUF_MAX, + .mode = 0444, + .proc_handler = &proc_tcp_available_congestion_control, + }, { .ctl_name = 0 } }; diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 1e2982f4acd4..d846d7b95e1f 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -139,6 +139,22 @@ static int __init tcp_congestion_default(void) late_initcall(tcp_congestion_default); +/* Build string with list of available congestion control values */ +void tcp_get_available_congestion_control(char *buf, size_t maxlen) +{ + struct tcp_congestion_ops *ca; + size_t offs = 0; + + rcu_read_lock(); + list_for_each_entry_rcu(ca, &tcp_cong_list, list) { + offs += snprintf(buf + offs, maxlen - offs, + "%s%s", + offs == 0 ? "" : " ", ca->name); + + } + rcu_read_unlock(); +} + /* Get current default congestion control */ void tcp_get_default_congestion_control(char *name) { -- cgit v1.2.3 From ce7bc3bf15cbf5dc5a5587ccb6b04c5b4dde4336 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Nov 2006 16:35:15 -0800 Subject: [TCP]: Restrict congestion control choices. Allow normal users to only choose among a restricted set of congestion control choices. The default is reno and what ever has been configured as default. But the policy can be changed by administrator at any time. For example, to allow any choice: cp /proc/sys/net/ipv4/tcp_available_congestion_control \ /proc/sys/net/ipv4/tcp_allowed_congestion_control Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 6 ++++ include/linux/sysctl.h | 1 + include/net/tcp.h | 3 ++ net/ipv4/sysctl_net_ipv4.c | 52 ++++++++++++++++++++++++++++ net/ipv4/tcp_cong.c | 63 ++++++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+) (limited to 'include/linux') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index db4280856588..bbcc8deda172 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -351,6 +351,12 @@ tcp_frto - BOOLEAN where packet loss is typically due to random radio interference rather than intermediate router congestion. +tcp_allowed_congestion_control - STRING + Show/set the congestion control choices available to non-privileged + processes. The list is a subset of those listed in + tcp_available_congestion_control. + Default is "reno" and the default setting (tcp_congestion_control). + tcp_available_congestion_control - STRING Shows the available congestion control choices that are registered. More congestion control algorithms may be available as modules, diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 28a48279654d..0725441621d0 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -427,6 +427,7 @@ enum NET_CIPSOV4_RBM_OPTFMT=120, NET_CIPSOV4_RBM_STRICTVALID=121, NET_TCP_AVAIL_CONG_CONTROL=122, + NET_TCP_ALLOWED_CONG_CONTROL=123, }; enum { diff --git a/include/net/tcp.h b/include/net/tcp.h index 6af4baf5b769..e1a5d29d0a1f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -625,6 +625,7 @@ enum tcp_ca_event { struct tcp_congestion_ops { struct list_head list; + int non_restricted; /* initialize private data (optional) */ void (*init)(struct sock *sk); @@ -663,6 +664,8 @@ extern void tcp_cleanup_congestion_control(struct sock *sk); extern int tcp_set_default_congestion_control(const char *name); extern void tcp_get_default_congestion_control(char *name); extern void tcp_get_available_congestion_control(char *buf, size_t len); +extern void tcp_get_allowed_congestion_control(char *buf, size_t len); +extern int tcp_set_allowed_congestion_control(char *allowed); extern int tcp_set_congestion_control(struct sock *sk, const char *name); extern void tcp_slow_start(struct tcp_sock *tp); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 2e770f45d829..dfcf47f10f88 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -146,6 +146,50 @@ static int proc_tcp_available_congestion_control(ctl_table *ctl, return ret; } +static int proc_allowed_congestion_control(ctl_table *ctl, + int write, struct file * filp, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX }; + int ret; + + tbl.data = kmalloc(tbl.maxlen, GFP_USER); + if (!tbl.data) + return -ENOMEM; + + tcp_get_allowed_congestion_control(tbl.data, tbl.maxlen); + ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); + if (write && ret == 0) + ret = tcp_set_allowed_congestion_control(tbl.data); + kfree(tbl.data); + return ret; +} + +static int strategy_allowed_congestion_control(ctl_table *table, int __user *name, + int nlen, void __user *oldval, + size_t __user *oldlenp, + void __user *newval, size_t newlen, + void **context) +{ + ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX }; + int ret; + + tbl.data = kmalloc(tbl.maxlen, GFP_USER); + if (!tbl.data) + return -ENOMEM; + + tcp_get_available_congestion_control(tbl.data, tbl.maxlen); + ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen, + context); + if (ret == 0 && newval && newlen) + ret = tcp_set_allowed_congestion_control(tbl.data); + kfree(tbl.data); + + return ret; + +} + ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_TCP_TIMESTAMPS, @@ -755,6 +799,14 @@ ctl_table ipv4_table[] = { .mode = 0444, .proc_handler = &proc_tcp_available_congestion_control, }, + { + .ctl_name = NET_TCP_ALLOWED_CONG_CONTROL, + .procname = "tcp_allowed_congestion_control", + .maxlen = TCP_CA_BUF_MAX, + .mode = 0644, + .proc_handler = &proc_allowed_congestion_control, + .strategy = &strategy_allowed_congestion_control, + }, { .ctl_name = 0 } }; diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index d846d7b95e1f..343d6197c92e 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -123,6 +123,7 @@ int tcp_set_default_congestion_control(const char *name) #endif if (ca) { + ca->non_restricted = 1; /* default is always allowed */ list_move(&ca->list, &tcp_cong_list); ret = 0; } @@ -168,6 +169,64 @@ void tcp_get_default_congestion_control(char *name) rcu_read_unlock(); } +/* Built list of non-restricted congestion control values */ +void tcp_get_allowed_congestion_control(char *buf, size_t maxlen) +{ + struct tcp_congestion_ops *ca; + size_t offs = 0; + + *buf = '\0'; + rcu_read_lock(); + list_for_each_entry_rcu(ca, &tcp_cong_list, list) { + if (!ca->non_restricted) + continue; + offs += snprintf(buf + offs, maxlen - offs, + "%s%s", + offs == 0 ? "" : " ", ca->name); + + } + rcu_read_unlock(); +} + +/* Change list of non-restricted congestion control */ +int tcp_set_allowed_congestion_control(char *val) +{ + struct tcp_congestion_ops *ca; + char *clone, *name; + int ret = 0; + + clone = kstrdup(val, GFP_USER); + if (!clone) + return -ENOMEM; + + spin_lock(&tcp_cong_list_lock); + /* pass 1 check for bad entries */ + while ((name = strsep(&clone, " ")) && *name) { + ca = tcp_ca_find(name); + if (!ca) { + ret = -ENOENT; + goto out; + } + } + + /* pass 2 clear */ + list_for_each_entry_rcu(ca, &tcp_cong_list, list) + ca->non_restricted = 0; + + /* pass 3 mark as allowed */ + while ((name = strsep(&val, " ")) && *name) { + ca = tcp_ca_find(name); + WARN_ON(!ca); + if (ca) + ca->non_restricted = 1; + } +out: + spin_unlock(&tcp_cong_list_lock); + + return ret; +} + + /* Change congestion control for socket */ int tcp_set_congestion_control(struct sock *sk, const char *name) { @@ -183,6 +242,9 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) if (!ca) err = -ENOENT; + else if (!(ca->non_restricted || capable(CAP_NET_ADMIN))) + err = -EPERM; + else if (!try_module_get(ca->owner)) err = -EBUSY; @@ -284,6 +346,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd); struct tcp_congestion_ops tcp_reno = { .name = "reno", + .non_restricted = 1, .owner = THIS_MODULE, .ssthresh = tcp_reno_ssthresh, .cong_avoid = tcp_reno_cong_avoid, -- cgit v1.2.3 From 9b42078ed6edfe04e9dc9a59b946ad912aeef717 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Fri, 10 Nov 2006 11:22:32 -0200 Subject: [DCCP]: Combine allocating & zeroing header space on skb This is a code simplification: it combines three often recurring operations into one inline function, * allocate `len' bytes header space in skb * fill these `len' bytes with zeroes * cast the start of this header space as dccp_hdr Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/dccp.h | 7 +++++++ net/dccp/ipv4.c | 9 ++------- net/dccp/ipv6.c | 8 ++------ net/dccp/output.c | 14 +++----------- 4 files changed, 14 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 53553c99cad6..90d04ffddae8 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -256,6 +256,13 @@ static inline struct dccp_hdr *dccp_hdr(const struct sk_buff *skb) return (struct dccp_hdr *)skb->h.raw; } +static inline struct dccp_hdr *dccp_zeroed_hdr(struct sk_buff *skb, int headlen) +{ + skb->h.raw = skb_push(skb, headlen); + memset(skb->h.raw, 0, headlen); + return dccp_hdr(skb); +} + static inline struct dccp_hdr_ext *dccp_hdrx(const struct sk_buff *skb) { return (struct dccp_hdr_ext *)(skb->h.raw + sizeof(struct dccp_hdr)); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index de64e6c7f93d..ce8eed32dbeb 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -212,12 +212,9 @@ static void dccp_v4_reqsk_send_ack(struct sk_buff *rxskb, /* Reserve space for headers. */ skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header); - skb->dst = dst_clone(rxskb->dst); - skb->h.raw = skb_push(skb, dccp_hdr_ack_len); - dh = dccp_hdr(skb); - memset(dh, 0, dccp_hdr_ack_len); + dh = dccp_zeroed_hdr(skb, dccp_hdr_ack_len); /* Build DCCP header and checksum it. */ dh->dccph_type = DCCP_PKT_ACK; @@ -720,9 +717,7 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header); skb->dst = dst_clone(dst); - skb->h.raw = skb_push(skb, dccp_hdr_reset_len); - dh = dccp_hdr(skb); - memset(dh, 0, dccp_hdr_reset_len); + dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len); /* Build DCCP header and checksum it. */ dh->dccph_type = DCCP_PKT_RESET; diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 6f1c2ad88608..116bddb64b80 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -537,9 +537,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); - skb->h.raw = skb_push(skb, dccp_hdr_reset_len); - dh = dccp_hdr(skb); - memset(dh, 0, dccp_hdr_reset_len); + dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len); /* Swap the send and the receive. */ dh->dccph_type = DCCP_PKT_RESET; @@ -601,9 +599,7 @@ static void dccp_v6_reqsk_send_ack(struct sk_buff *rxskb, skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); - skb->h.raw = skb_push(skb, dccp_hdr_ack_len); - dh = dccp_hdr(skb); - memset(dh, 0, dccp_hdr_ack_len); + dh = dccp_zeroed_hdr(skb, dccp_hdr_ack_len); /* Build DCCP header and checksum it. */ dh->dccph_type = DCCP_PKT_ACK; diff --git a/net/dccp/output.c b/net/dccp/output.c index 2cc4f4b2a9dd..1ae2248557c6 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -88,11 +88,9 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) return -EPROTO; } - skb->h.raw = skb_push(skb, dccp_header_size); - dh = dccp_hdr(skb); /* Build DCCP header and checksum it. */ - memset(dh, 0, dccp_header_size); + dh = dccp_zeroed_hdr(skb, dccp_header_size); dh->dccph_type = dcb->dccpd_type; dh->dccph_sport = inet->sport; dh->dccph_dport = inet->dport; @@ -340,10 +338,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, return NULL; } - skb->h.raw = skb_push(skb, dccp_header_size); - - dh = dccp_hdr(skb); - memset(dh, 0, dccp_header_size); + dh = dccp_zeroed_hdr(skb, dccp_header_size); dh->dccph_sport = inet_sk(sk)->sport; dh->dccph_dport = inet_rsk(req)->rmt_port; @@ -392,10 +387,7 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, return NULL; } - skb->h.raw = skb_push(skb, dccp_header_size); - - dh = dccp_hdr(skb); - memset(dh, 0, dccp_header_size); + dh = dccp_zeroed_hdr(skb, dccp_header_size); dh->dccph_sport = inet_sk(sk)->sport; dh->dccph_dport = inet_sk(sk)->dport; -- cgit v1.2.3 From 6f4e5fff1e4d46714ea554fd83e44eab534e8b11 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Fri, 10 Nov 2006 17:43:06 -0200 Subject: [DCCP]: Support for partial checksums (RFC 4340, sec. 9.2) This patch does the following: a) introduces variable-length checksums as specified in [RFC 4340, sec. 9.2] b) provides necessary socket options and documentation as to how to use them c) basic support and infrastructure for the Minimum Checksum Coverage feature [RFC 4340, sec. 9.2.1]: acceptability tests, user notification and user interface In addition, it (1) fixes two bugs in the DCCPv4 checksum computation: * pseudo-header used checksum_len instead of skb->len * incorrect checksum coverage calculation based on dccph_x (2) removes dccp_v4_verify_checksum() since it reduplicates code of the checksum computation; code calling this function is updated accordingly. (3) now uses skb_checksum(), which is safer than checksum_partial() if the sk_buff has is a non-linear buffer (has pages attached to it). (4) fixes an outstanding TODO item: * If P.CsCov is too large for the packet size, drop packet and return. The code has been tested with applications, the latest version of tcpdump now comes with support for partial DCCP checksums. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- Documentation/networking/dccp.txt | 16 ++++++ include/linux/dccp.h | 7 +++ net/dccp/dccp.h | 29 +++++++++-- net/dccp/ipv4.c | 105 +++++++++++++++++++------------------- net/dccp/ipv6.c | 74 +++++++++++++++++---------- net/dccp/output.c | 13 ++--- net/dccp/proto.c | 26 ++++++++-- 7 files changed, 173 insertions(+), 97 deletions(-) (limited to 'include/linux') diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index 74563b38ffd9..a8142a81038a 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -47,6 +47,22 @@ the socket will fall back to 0 (which means that no meaningful service code is present). Connecting sockets set at most one service option; for listening sockets, multiple service codes can be specified. +DCCP_SOCKOPT_SEND_CSCOV and DCCP_SOCKOPT_RECV_CSCOV are used for setting the +partial checksum coverage (RFC 4340, sec. 9.2). The default is that checksums +always cover the entire packet and that only fully covered application data is +accepted by the receiver. Hence, when using this feature on the sender, it must +be enabled at the receiver, too with suitable choice of CsCov. + +DCCP_SOCKOPT_SEND_CSCOV sets the sender checksum coverage. Values in the + range 0..15 are acceptable. The default setting is 0 (full coverage), + values between 1..15 indicate partial coverage. +DCCP_SOCKOPT_SEND_CSCOV is for the receiver and has a different meaning: it + sets a threshold, where again values 0..15 are acceptable. The default + of 0 means that all packets with a partial coverage will be discarded. + Values in the range 1..15 indicate that packets with minimally such a + coverage value are also acceptable. The higher the number, the more + restrictive this setting (see [RFC 4340, sec. 9.2.1]). + Notes ===== diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 90d04ffddae8..0502dfa7f32c 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -183,6 +183,7 @@ enum { DCCPF_ACK_RATIO = 5, DCCPF_SEND_ACK_VECTOR = 6, DCCPF_SEND_NDP_COUNT = 7, + DCCPF_MIN_CSUM_COVER = 8, /* 10-127 reserved */ DCCPF_MIN_CCID_SPECIFIC = 128, DCCPF_MAX_CCID_SPECIFIC = 255, @@ -200,6 +201,8 @@ struct dccp_so_feat { #define DCCP_SOCKOPT_SERVICE 2 #define DCCP_SOCKOPT_CHANGE_L 3 #define DCCP_SOCKOPT_CHANGE_R 4 +#define DCCP_SOCKOPT_SEND_CSCOV 10 +#define DCCP_SOCKOPT_RECV_CSCOV 11 #define DCCP_SOCKOPT_CCID_RX_INFO 128 #define DCCP_SOCKOPT_CCID_TX_INFO 192 @@ -450,6 +453,8 @@ struct dccp_ackvec; * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option * @dccps_packet_size - Set thru setsockopt * @dccps_role - Role of this sock, one of %dccp_role + * @dccps_pcslen - sender partial checksum coverage (via sockopt) + * @dccps_pcrlen - receiver partial checksum coverage (via sockopt) * @dccps_ndp_count - number of Non Data Packets since last data packet * @dccps_hc_rx_ackvec - rx half connection ack vector * @dccps_xmit_timer - timer for when CCID is not ready to send @@ -474,6 +479,8 @@ struct dccp_sock { __u32 dccps_packet_size; __u16 dccps_l_ack_ratio; __u16 dccps_r_ack_ratio; + __u16 dccps_pcslen; + __u16 dccps_pcrlen; unsigned long dccps_ndp_count; __u32 dccps_mss_cache; struct dccp_minisock dccps_minisock; diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 2990bfb12587..d5c414bf7819 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -129,6 +129,30 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics); #define DCCP_ADD_STATS_USER(field, val) \ SNMP_ADD_STATS_USER(dccp_statistics, field, val) +/* + * Checksumming routines + */ +static inline int dccp_csum_coverage(const struct sk_buff *skb) +{ + const struct dccp_hdr* dh = dccp_hdr(skb); + + if (dh->dccph_cscov == 0) + return skb->len; + return (dh->dccph_doff + dh->dccph_cscov - 1) * sizeof(u32); +} + +static inline void dccp_csum_outgoing(struct sk_buff *skb) +{ + int cov = dccp_csum_coverage(skb); + + if (cov >= skb->len) + dccp_hdr(skb)->dccph_cscov = 0; + + skb->csum = skb_checksum(skb, 0, (cov > skb->len)? skb->len : cov, 0); +} + +extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); + extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); extern void dccp_send_ack(struct sock *sk); @@ -214,14 +238,9 @@ extern void dccp_shutdown(struct sock *sk, int how); extern int inet_dccp_listen(struct socket *sock, int backlog); extern unsigned int dccp_poll(struct file *file, struct socket *sock, poll_table *wait); -extern void dccp_v4_send_check(struct sock *sk, int len, - struct sk_buff *skb); extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); -extern int dccp_v4_checksum(const struct sk_buff *skb, - const __be32 saddr, const __be32 daddr); - extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); extern void dccp_send_close(struct sock *sk, const int active); extern int dccp_invalid_packet(struct sk_buff *skb); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 91bffaa761a6..496112080f3d 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -349,13 +349,19 @@ out: sock_put(sk); } -/* This routine computes an IPv4 DCCP checksum. */ -void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) +static inline u16 dccp_v4_csum_finish(struct sk_buff *skb, + __be32 src, __be32 dst) +{ + return csum_tcpudp_magic(src, dst, skb->len, IPPROTO_DCCP, skb->csum); +} + +void dccp_v4_send_check(struct sock *sk, int unused, struct sk_buff *skb) { const struct inet_sock *inet = inet_sk(sk); struct dccp_hdr *dh = dccp_hdr(skb); - dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr, inet->daddr); + dccp_csum_outgoing(skb); + dh->dccph_checksum = dccp_v4_csum_finish(skb, inet->saddr, inet->daddr); } EXPORT_SYMBOL_GPL(dccp_v4_send_check); @@ -454,47 +460,6 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) return sk; } -int dccp_v4_checksum(const struct sk_buff *skb, const __be32 saddr, - const __be32 daddr) -{ - const struct dccp_hdr* dh = dccp_hdr(skb); - int checksum_len; - u32 tmp; - - if (dh->dccph_cscov == 0) - checksum_len = skb->len; - else { - checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32); - checksum_len = checksum_len < skb->len ? checksum_len : - skb->len; - } - - tmp = csum_partial((unsigned char *)dh, checksum_len, 0); - return csum_tcpudp_magic(saddr, daddr, checksum_len, - IPPROTO_DCCP, tmp); -} - -EXPORT_SYMBOL_GPL(dccp_v4_checksum); - -static int dccp_v4_verify_checksum(struct sk_buff *skb, - const __be32 saddr, const __be32 daddr) -{ - struct dccp_hdr *dh = dccp_hdr(skb); - int checksum_len; - u32 tmp; - - if (dh->dccph_cscov == 0) - checksum_len = skb->len; - else { - checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32); - checksum_len = checksum_len < skb->len ? checksum_len : - skb->len; - } - tmp = csum_partial((unsigned char *)dh, checksum_len, 0); - return csum_tcpudp_magic(saddr, daddr, checksum_len, - IPPROTO_DCCP, tmp) == 0 ? 0 : -1; -} - static struct dst_entry* dccp_v4_route_skb(struct sock *sk, struct sk_buff *skb) { @@ -536,8 +501,8 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, const struct inet_request_sock *ireq = inet_rsk(req); struct dccp_hdr *dh = dccp_hdr(skb); - dh->dccph_checksum = dccp_v4_checksum(skb, ireq->loc_addr, - ireq->rmt_addr); + dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->loc_addr, + ireq->rmt_addr); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, @@ -602,8 +567,9 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); - dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr, - rxskb->nh.iph->daddr); + dccp_csum_outgoing(skb); + dh->dccph_checksum = dccp_v4_csum_finish(skb, rxskb->nh.iph->saddr, + rxskb->nh.iph->daddr); bh_lock_sock(dccp_v4_ctl_socket->sk); err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, @@ -779,6 +745,7 @@ EXPORT_SYMBOL_GPL(dccp_v4_do_rcv); int dccp_invalid_packet(struct sk_buff *skb) { const struct dccp_hdr *dh; + unsigned int cscov; if (skb->pkt_type != PACKET_HOST) return 1; @@ -830,6 +797,22 @@ int dccp_invalid_packet(struct sk_buff *skb) return 1; } + /* + * If P.CsCov is too large for the packet size, drop packet and return. + * This must come _before_ checksumming (not as RFC 4340 suggests). + */ + cscov = dccp_csum_coverage(skb); + if (cscov > skb->len) { + LIMIT_NETDEBUG(KERN_WARNING + "DCCP: P.CsCov %u exceeds packet length %d\n", + dh->dccph_cscov, skb->len); + return 1; + } + + /* If header checksum is incorrect, drop packet and return. + * (This step is completed in the AF-dependent functions.) */ + skb->csum = skb_checksum(skb, 0, cscov, 0); + return 0; } @@ -840,16 +823,17 @@ static int dccp_v4_rcv(struct sk_buff *skb) { const struct dccp_hdr *dh; struct sock *sk; + int min_cov; - /* Step 1: Check header basics: */ + /* Step 1: Check header basics */ if (dccp_invalid_packet(skb)) goto discard_it; - /* If the header checksum is incorrect, drop packet and return */ - if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr, - skb->nh.iph->daddr) < 0) { - LIMIT_NETDEBUG(KERN_WARNING "%s: incorrect header checksum\n", + /* Step 1: If header checksum is incorrect, drop packet and return */ + if (dccp_v4_csum_finish(skb, skb->nh.iph->saddr, skb->nh.iph->daddr)) { + LIMIT_NETDEBUG(KERN_WARNING + "%s: dropped packet with invalid checksum\n", __FUNCTION__); goto discard_it; } @@ -905,6 +889,21 @@ static int dccp_v4_rcv(struct sk_buff *skb) goto no_dccp_socket; } + /* + * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage + * o if MinCsCov = 0, only packets with CsCov = 0 are accepted + * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov + */ + min_cov = dccp_sk(sk)->dccps_pcrlen; + if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) { + dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n", + dh->dccph_cscov, min_cov); + /* FIXME: "Such packets SHOULD be reported using Data Dropped + * options (Section 11.7) with Drop Code 0, Protocol + * Constraints." */ + goto discard_and_relse; + } + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) goto discard_and_relse; nf_reset(skb); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 201801e1532d..193b946fd039 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -58,12 +58,22 @@ static void dccp_v6_hash(struct sock *sk) } } -static inline u16 dccp_v6_check(struct dccp_hdr *dh, int len, - struct in6_addr *saddr, - struct in6_addr *daddr, - unsigned long base) +/* add pseudo-header to DCCP checksum stored in skb->csum */ +static inline u16 dccp_v6_csum_finish(struct sk_buff *skb, + struct in6_addr *saddr, + struct in6_addr *daddr) { - return csum_ipv6_magic(saddr, daddr, len, IPPROTO_DCCP, base); + return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum); +} + +static inline void dccp_v6_send_check(struct sock *sk, int unused_value, + struct sk_buff *skb) +{ + struct ipv6_pinfo *np = inet6_sk(sk); + struct dccp_hdr *dh = dccp_hdr(skb); + + dccp_csum_outgoing(skb); + dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr); } static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb) @@ -280,12 +290,9 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, if (skb != NULL) { struct dccp_hdr *dh = dccp_hdr(skb); - dh->dccph_checksum = dccp_v6_check(dh, skb->len, - &ireq6->loc_addr, - &ireq6->rmt_addr, - csum_partial((char *)dh, - skb->len, - skb->csum)); + dh->dccph_checksum = dccp_v6_csum_finish(skb, + &ireq6->loc_addr, + &ireq6->rmt_addr); ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); err = ip6_xmit(sk, skb, &fl, opt, 0); if (err == NET_XMIT_CN) @@ -305,18 +312,6 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req) kfree_skb(inet6_rsk(req)->pktopts); } -static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct dccp_hdr *dh = dccp_hdr(skb); - - dh->dccph_checksum = csum_ipv6_magic(&np->saddr, &np->daddr, - len, IPPROTO_DCCP, - csum_partial((char *)dh, - dh->dccph_doff << 2, - skb->csum)); -} - static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) { struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; @@ -360,12 +355,14 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); + dccp_csum_outgoing(skb); + dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr, + &rxskb->nh.ipv6h->daddr); + memset(&fl, 0, sizeof(fl)); ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr); ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr); - dh->dccph_checksum = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst, - sizeof(*dh), IPPROTO_DCCP, - skb->csum); + fl.proto = IPPROTO_DCCP; fl.oif = inet6_iif(rxskb); fl.fl_ip_dport = dh->dccph_dport; @@ -825,12 +822,22 @@ static int dccp_v6_rcv(struct sk_buff **pskb) const struct dccp_hdr *dh; struct sk_buff *skb = *pskb; struct sock *sk; + int min_cov; - /* Step 1: Check header basics: */ + /* Step 1: Check header basics */ if (dccp_invalid_packet(skb)) goto discard_it; + /* Step 1: If header checksum is incorrect, drop packet and return. */ + if (dccp_v6_csum_finish(skb, &skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr)) { + LIMIT_NETDEBUG(KERN_WARNING + "%s: dropped packet with invalid checksum\n", + __FUNCTION__); + goto discard_it; + } + dh = dccp_hdr(skb); DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb); @@ -869,6 +876,19 @@ static int dccp_v6_rcv(struct sk_buff **pskb) goto no_dccp_socket; } + /* + * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage + * o if MinCsCov = 0, only packets with CsCov = 0 are accepted + * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov + */ + min_cov = dccp_sk(sk)->dccps_pcrlen; + if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) { + dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n", + dh->dccph_cscov, min_cov); + /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */ + goto discard_and_relse; + } + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) goto discard_and_relse; diff --git a/net/dccp/output.c b/net/dccp/output.c index 51654975e8ea..992caedd7725 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -96,6 +96,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) dh->dccph_dport = inet->dport; dh->dccph_doff = (dccp_header_size + dcb->dccpd_opt_len) / 4; dh->dccph_ccval = dcb->dccpd_ccval; + dh->dccph_cscov = dp->dccps_pcslen; /* XXX For now we're using only 48 bits sequence numbers */ dh->dccph_x = 1; @@ -115,7 +116,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) break; } - icsk->icsk_af_ops->send_check(sk, skb->len, skb); + icsk->icsk_af_ops->send_check(sk, 0, skb); if (set_ack) dccp_event_ack_sent(sk); @@ -329,7 +330,6 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, skb_reserve(skb, sk->sk_prot->max_header); skb->dst = dst_clone(dst); - skb->csum = 0; dreq = dccp_rsk(req); DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; @@ -352,6 +352,8 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr); dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service; + dccp_csum_outgoing(skb); + DCCP_INC_STATS(DCCP_MIB_OUTSEGS); return skb; } @@ -376,7 +378,6 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, skb_reserve(skb, sk->sk_prot->max_header); skb->dst = dst_clone(dst); - skb->csum = 0; dccp_inc_seqno(&dp->dccps_gss); @@ -401,7 +402,7 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr); dccp_hdr_reset(skb)->dccph_reset_code = code; - inet_csk(sk)->icsk_af_ops->send_check(sk, skb->len, skb); + inet_csk(sk)->icsk_af_ops->send_check(sk, 0, skb); DCCP_INC_STATS(DCCP_MIB_OUTSEGS); return skb; @@ -475,7 +476,6 @@ int dccp_connect(struct sock *sk) skb_reserve(skb, sk->sk_prot->max_header); DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; - skb->csum = 0; dccp_skb_entail(sk, skb); dccp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL)); @@ -507,7 +507,6 @@ void dccp_send_ack(struct sock *sk) /* Reserve space for headers */ skb_reserve(skb, sk->sk_prot->max_header); - skb->csum = 0; DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK; dccp_transmit_skb(sk, skb); } @@ -561,7 +560,6 @@ void dccp_send_sync(struct sock *sk, const u64 seq, /* Reserve space for headers and prepare control bits. */ skb_reserve(skb, sk->sk_prot->max_header); - skb->csum = 0; DCCP_SKB_CB(skb)->dccpd_type = pkt_type; DCCP_SKB_CB(skb)->dccpd_seq = seq; @@ -587,7 +585,6 @@ void dccp_send_close(struct sock *sk, const int active) /* Reserve space for headers and prepare control bits. */ skb_reserve(skb, sk->sk_prot->max_header); - skb->csum = 0; DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ? DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ; diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 047d170a363a..db54e557eff1 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -472,7 +472,6 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, case DCCP_SOCKOPT_PACKET_SIZE: dp->dccps_packet_size = val; break; - case DCCP_SOCKOPT_CHANGE_L: if (optlen != sizeof(struct dccp_so_feat)) err = -EINVAL; @@ -481,7 +480,6 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, (struct dccp_so_feat __user *) optval); break; - case DCCP_SOCKOPT_CHANGE_R: if (optlen != sizeof(struct dccp_so_feat)) err = -EINVAL; @@ -490,12 +488,26 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, (struct dccp_so_feat __user *) optval); break; - + case DCCP_SOCKOPT_SEND_CSCOV: /* sender side, RFC 4340, sec. 9.2 */ + if (val < 0 || val > 15) + err = -EINVAL; + else + dp->dccps_pcslen = val; + break; + case DCCP_SOCKOPT_RECV_CSCOV: /* receiver side, RFC 4340 sec. 9.2.1 */ + if (val < 0 || val > 15) + err = -EINVAL; + else { + dp->dccps_pcrlen = val; + /* FIXME: add feature negotiation, + * ChangeL(MinimumChecksumCoverage, val) */ + } + break; default: err = -ENOPROTOOPT; break; } - + release_sock(sk); return err; } @@ -575,6 +587,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, case DCCP_SOCKOPT_SERVICE: return dccp_getsockopt_service(sk, len, (__be32 __user *)optval, optlen); + case DCCP_SOCKOPT_SEND_CSCOV: + val = dp->dccps_pcslen; + break; + case DCCP_SOCKOPT_RECV_CSCOV: + val = dp->dccps_pcrlen; + break; case 128 ... 191: return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, len, (u32 __user *)optval, optlen); -- cgit v1.2.3 From 339bf98ffc6a8d8eb16fc532ac57ffbced2f8a68 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Fri, 10 Nov 2006 14:10:15 -0800 Subject: [NETLINK]: Do precise netlink message allocations where possible Account for the netlink message header size directly in nlmsg_new() instead of relying on the caller calculate it correctly. Replaces error handling of message construction functions when constructing notifications with bug traps since a failure implies a bug in calculating the size of the skb. Signed-off-by: Thomas Graf Acked-by: Paul Moore Signed-off-by: David S. Miller --- include/linux/netlink.h | 1 + include/net/fib_rules.h | 1 + include/net/netlink.h | 9 ++--- kernel/taskstats.c | 3 +- net/bridge/br_netlink.c | 21 ++++++++---- net/core/fib_rules.c | 24 +++++++++++--- net/core/neighbour.c | 17 +++++++--- net/core/rtnetlink.c | 39 ++++++++++++++-------- net/decnet/dn_rules.c | 6 ++++ net/decnet/dn_table.c | 34 ++++++++++++++++--- net/ipv4/devinet.c | 18 +++++++--- net/ipv4/fib_rules.c | 8 +++++ net/ipv4/fib_semantics.c | 36 ++++++++++++++++---- net/ipv6/addrconf.c | 70 ++++++++++++++++++--------------------- net/ipv6/fib6_rules.c | 7 ++++ net/ipv6/route.c | 23 +++++++++---- net/netlabel/netlabel_cipso_v4.c | 2 +- net/netlabel/netlabel_mgmt.c | 4 +-- net/netlabel/netlabel_unlabeled.c | 2 +- net/netlink/af_netlink.c | 13 ++++---- net/netlink/genetlink.c | 2 +- 21 files changed, 233 insertions(+), 107 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 66411622e06e..e61e1e138421 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -174,6 +174,7 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol); */ #define NLMSG_GOODORDER 0 #define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER)) +#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN) struct netlink_callback diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index e4ba781d289f..bc3c26494c3d 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -52,6 +52,7 @@ struct fib_rules_ops struct nlmsghdr *, struct fib_rule_hdr *); u32 (*default_pref)(void); + size_t (*nlmsg_payload)(struct fib_rule *); int nlgroup; struct nla_policy *policy; diff --git a/include/net/netlink.h b/include/net/netlink.h index ce5cba19c393..30021339157c 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -500,14 +500,15 @@ static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb, /** * nlmsg_new - Allocate a new netlink message - * @size: maximum size of message + * @payload: size of the message payload * @flags: the type of memory to allocate. * - * Use NLMSG_GOODSIZE if size isn't know and you need a good default size. + * Use NLMSG_DEFAULT_SIZE if the size of the payload isn't known + * and a good default is needed. */ -static inline struct sk_buff *nlmsg_new(int size, gfp_t flags) +static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags) { - return alloc_skb(size, flags); + return alloc_skb(nlmsg_total_size(payload), flags); } /** diff --git a/kernel/taskstats.c b/kernel/taskstats.c index f45c5e70773c..4f3f0e48c845 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -77,8 +77,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp, /* * If new attributes are added, please revisit this allocation */ - size = nlmsg_total_size(genlmsg_total_size(size)); - skb = nlmsg_new(size, GFP_KERNEL); + skb = nlmsg_new(genlmsg_total_size(size), GFP_KERNEL); if (!skb) return -ENOMEM; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 8f661195d09d..15d6efbe7519 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -15,6 +15,18 @@ #include #include "br_private.h" +static inline size_t br_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct ifinfomsg)) + + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ + + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ + + nla_total_size(4) /* IFLA_MASTER */ + + nla_total_size(4) /* IFLA_MTU */ + + nla_total_size(4) /* IFLA_LINK */ + + nla_total_size(1) /* IFLA_OPERSTATE */ + + nla_total_size(1); /* IFLA_PROTINFO */ +} + /* * Create one netlink message for one interface * Contains port and master info as well as carrier and bridge state. @@ -77,19 +89,16 @@ rtattr_failure: void br_ifinfo_notify(int event, struct net_bridge_port *port) { struct sk_buff *skb; - int payload = sizeof(struct ifinfomsg) + 128; int err = -ENOBUFS; pr_debug("bridge notify event=%d\n", event); - skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); + skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = br_fill_ifinfo(skb, port, 0, 0, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in br_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); errout: diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 4148e274a204..1df6cd4568d3 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -306,6 +306,22 @@ errout: return err; } +static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, + struct fib_rule *rule) +{ + size_t payload = NLMSG_ALIGN(sizeof(struct fib_rule_hdr)) + + nla_total_size(IFNAMSIZ) /* FRA_IFNAME */ + + nla_total_size(4) /* FRA_PRIORITY */ + + nla_total_size(4) /* FRA_TABLE */ + + nla_total_size(4) /* FRA_FWMARK */ + + nla_total_size(4); /* FRA_FWMASK */ + + if (ops->nlmsg_payload) + payload += ops->nlmsg_payload(rule); + + return payload; +} + static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, u32 pid, u32 seq, int type, int flags, struct fib_rules_ops *ops) @@ -384,15 +400,13 @@ static void notify_rule_change(int event, struct fib_rule *rule, struct sk_buff *skb; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(fib_rule_nlmsg_size(ops, rule), GFP_KERNEL); if (skb == NULL) goto errout; err = fib_nl_fill_rule(skb, rule, pid, nlh->nlmsg_seq, event, 0, ops); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in fib_rule_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL); errout: diff --git a/net/core/neighbour.c b/net/core/neighbour.c index b4b478353b27..0e097ba14d73 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2410,20 +2410,27 @@ static struct file_operations neigh_stat_seq_fops = { #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_ARPD +static inline size_t neigh_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct ndmsg)) + + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */ + + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */ + + nla_total_size(sizeof(struct nda_cacheinfo)) + + nla_total_size(4); /* NDA_PROBES */ +} + static void __neigh_notify(struct neighbour *n, int type, int flags) { struct sk_buff *skb; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = neigh_fill_info(skb, n, 0, 0, type, flags); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in neigh_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); errout: diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 02f3c7947898..50d6cb40c6e3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -273,6 +273,25 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a, a->tx_compressed = b->tx_compressed; }; +static inline size_t if_nlmsg_size(int iwbuflen) +{ + return NLMSG_ALIGN(sizeof(struct ifinfomsg)) + + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ + + nla_total_size(IFNAMSIZ) /* IFLA_QDISC */ + + nla_total_size(sizeof(struct rtnl_link_ifmap)) + + nla_total_size(sizeof(struct rtnl_link_stats)) + + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ + + nla_total_size(MAX_ADDR_LEN) /* IFLA_BROADCAST */ + + nla_total_size(4) /* IFLA_TXQLEN */ + + nla_total_size(4) /* IFLA_WEIGHT */ + + nla_total_size(4) /* IFLA_MTU */ + + nla_total_size(4) /* IFLA_LINK */ + + nla_total_size(4) /* IFLA_MASTER */ + + nla_total_size(1) /* IFLA_OPERSTATE */ + + nla_total_size(1) /* IFLA_LINKMODE */ + + nla_total_size(iwbuflen); +} + static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, void *iwbuf, int iwbuflen, int type, u32 pid, u32 seq, u32 change, unsigned int flags) @@ -558,7 +577,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) struct sk_buff *nskb; char *iw_buf = NULL, *iw = NULL; int iw_buf_len = 0; - int err, payload; + int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); if (err < 0) @@ -587,9 +606,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) } #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ - payload = NLMSG_ALIGN(sizeof(struct ifinfomsg) + - nla_total_size(iw_buf_len)); - nskb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); + nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL); if (nskb == NULL) { err = -ENOBUFS; goto errout; @@ -597,10 +614,8 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0); - if (err <= 0) { - kfree_skb(nskb); - goto errout; - } + /* failure impilies BUG in if_nlmsg_size or wireless_rtnetlink_get */ + BUG_ON(err < 0); err = rtnl_unicast(nskb, NETLINK_CB(skb).pid); errout: @@ -639,15 +654,13 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) struct sk_buff *skb; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(if_nlmsg_size(0), GFP_KERNEL); if (skb == NULL) goto errout; err = rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in if_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL); errout: diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index e32d0c3d5a96..b7dfd04a9638 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -241,6 +241,12 @@ static u32 dn_fib_rule_default_pref(void) return 0; } +static size_t dn_fib_rule_nlmsg_payload(struct fib_rule *rule) +{ + return nla_total_size(2) /* dst */ + + nla_total_size(2); /* src */ +} + int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) { return fib_rules_dump(skb, cb, AF_DECnet); diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index 317904bb5896..e74b744254ab 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -263,6 +263,32 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern return 0; } +static inline size_t dn_fib_nlmsg_size(struct dn_fib_info *fi) +{ + size_t payload = NLMSG_ALIGN(struct rtmsg) + + nla_total_size(4) /* RTA_TABLE */ + + nla_total_size(2) /* RTA_DST */ + + nla_total_size(4); /* RTA_PRIORITY */ + + /* space for nested metrics */ + payload += nla_total_size((RTAX_MAX * nla_total_size(4))); + + if (fi->fib_nhs) { + /* Also handles the special case fib_nhs == 1 */ + + /* each nexthop is packed in an attribute */ + size_t nhsize = nla_total_size(sizeof(struct rtnexthop)); + + /* may contain a gateway attribute */ + nhsize += nla_total_size(4); + + /* all nexthops are packed in a nested attribute */ + payload += nla_total_size(fi->fib_nhs * nhsize); + } + + return payload; +} + static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u32 tb_id, u8 type, u8 scope, void *dst, int dst_len, struct dn_fib_info *fi, unsigned int flags) @@ -335,17 +361,15 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id, u32 pid = req ? req->pid : 0; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(dn_fib_nlmsg_size(DN_FIB_INFO(f), GFP_KERNEL)); if (skb == NULL) goto errout; err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, f->fn_type, f->fn_scope, &f->fn_key, z, DN_FIB_INFO(f), 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in dn_fib_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL); errout: diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 7602c79a389b..f38cbbae0ae3 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1120,6 +1120,16 @@ static struct notifier_block ip_netdev_notifier = { .notifier_call =inetdev_event, }; +static inline size_t inet_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + + nla_total_size(4) /* IFA_ADDRESS */ + + nla_total_size(4) /* IFA_LOCAL */ + + nla_total_size(4) /* IFA_BROADCAST */ + + nla_total_size(4) /* IFA_ANYCAST */ + + nla_total_size(IFNAMSIZ); /* IFA_LABEL */ +} + static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, u32 pid, u32 seq, int event, unsigned int flags) { @@ -1208,15 +1218,13 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, u32 seq = nlh ? nlh->nlmsg_seq : 0; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL); if (skb == NULL) goto errout; err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in inet_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); errout: diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index fd4a8cd4c06e..b837c33e0404 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -299,6 +299,13 @@ static u32 fib4_rule_default_pref(void) return 0; } +static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule) +{ + return nla_total_size(4) /* dst */ + + nla_total_size(4) /* src */ + + nla_total_size(4); /* flow */ +} + static struct fib_rules_ops fib4_rules_ops = { .family = AF_INET, .rule_size = sizeof(struct fib4_rule), @@ -308,6 +315,7 @@ static struct fib_rules_ops fib4_rules_ops = { .compare = fib4_rule_compare, .fill = fib4_rule_fill, .default_pref = fib4_rule_default_pref, + .nlmsg_payload = fib4_rule_nlmsg_payload, .nlgroup = RTNLGRP_IPV4_RULE, .policy = fib4_rule_policy, .rules_list = &fib4_rules, diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 884d176e0082..e63b8a98fb4d 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -273,25 +273,49 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev) return -1; } +static inline size_t fib_nlmsg_size(struct fib_info *fi) +{ + size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg)) + + nla_total_size(4) /* RTA_TABLE */ + + nla_total_size(4) /* RTA_DST */ + + nla_total_size(4) /* RTA_PRIORITY */ + + nla_total_size(4); /* RTA_PREFSRC */ + + /* space for nested metrics */ + payload += nla_total_size((RTAX_MAX * nla_total_size(4))); + + if (fi->fib_nhs) { + /* Also handles the special case fib_nhs == 1 */ + + /* each nexthop is packed in an attribute */ + size_t nhsize = nla_total_size(sizeof(struct rtnexthop)); + + /* may contain flow and gateway attribute */ + nhsize += 2 * nla_total_size(4); + + /* all nexthops are packed in a nested attribute */ + payload += nla_total_size(fi->fib_nhs * nhsize); + } + + return payload; +} + void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len, u32 tb_id, struct nl_info *info) { struct sk_buff *skb; - int payload = sizeof(struct rtmsg) + 256; u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; int err = -ENOBUFS; - skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); + skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL); if (skb == NULL) goto errout; err = fib_dump_info(skb, info->pid, seq, event, tb_id, fa->fa_type, fa->fa_scope, key, dst_len, fa->fa_tos, fa->fa_info, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in fib_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, info->nlh, GFP_KERNEL); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6a98f68348cb..967ea320a9ca 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3098,10 +3098,9 @@ static inline int rt_scope(int ifa_scope) static inline int inet6_ifaddr_msgsize(void) { - return nlmsg_total_size(sizeof(struct ifaddrmsg) + - nla_total_size(16) + - nla_total_size(sizeof(struct ifa_cacheinfo)) + - 128); + return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + + nla_total_size(16) /* IFA_ADDRESS */ + + nla_total_size(sizeof(struct ifa_cacheinfo)); } static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, @@ -3329,10 +3328,8 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWADDR, 0); - if (err < 0) { - kfree_skb(skb); - goto errout_ifa; - } + /* failure implies BUG in inet6_ifaddr_msgsize() */ + BUG_ON(err < 0); err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); errout_ifa: @@ -3351,10 +3348,8 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) goto errout; err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in inet6_ifaddr_msgsize() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); errout: @@ -3397,16 +3392,19 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; } -/* Maximum length of ifinfomsg attributes */ -#define INET6_IFINFO_RTA_SPACE \ - RTA_SPACE(IFNAMSIZ) /* IFNAME */ + \ - RTA_SPACE(MAX_ADDR_LEN) /* ADDRESS */ + \ - RTA_SPACE(sizeof(u32)) /* MTU */ + \ - RTA_SPACE(sizeof(int)) /* LINK */ + \ - RTA_SPACE(0) /* PROTINFO */ + \ - RTA_SPACE(sizeof(u32)) /* FLAGS */ + \ - RTA_SPACE(sizeof(struct ifla_cacheinfo)) /* CACHEINFO */ + \ - RTA_SPACE(sizeof(__s32[DEVCONF_MAX])) /* CONF */ +static inline size_t inet6_if_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct ifinfomsg)) + + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ + + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ + + nla_total_size(4) /* IFLA_MTU */ + + nla_total_size(4) /* IFLA_LINK */ + + nla_total_size( /* IFLA_PROTINFO */ + nla_total_size(4) /* IFLA_INET6_FLAGS */ + + nla_total_size(sizeof(struct ifla_cacheinfo)) + + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ + ); +} static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, u32 pid, u32 seq, int event, unsigned int flags) @@ -3501,18 +3499,15 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) void inet6_ifinfo_notify(int event, struct inet6_dev *idev) { struct sk_buff *skb; - int payload = sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE; int err = -ENOBUFS; - skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); + skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in inet6_if_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); errout: @@ -3520,10 +3515,12 @@ errout: rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); } -/* Maximum length of prefix_cacheinfo attributes */ -#define INET6_PREFIX_RTA_SPACE \ - RTA_SPACE(sizeof(((struct prefix_info *)NULL)->prefix)) /* ADDRESS */ + \ - RTA_SPACE(sizeof(struct prefix_cacheinfo)) /* CACHEINFO */ +static inline size_t inet6_prefix_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct prefixmsg)) + + nla_total_size(sizeof(struct in6_addr)) + + nla_total_size(sizeof(struct prefix_cacheinfo)); +} static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, struct prefix_info *pinfo, u32 pid, u32 seq, @@ -3569,18 +3566,15 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, struct prefix_info *pinfo) { struct sk_buff *skb; - int payload = sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE; int err = -ENOBUFS; - skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); + skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in inet6_prefix_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); errout: diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 25804cb69cf0..d587dde5897e 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -232,6 +232,12 @@ static u32 fib6_rule_default_pref(void) return 0x3FFF; } +static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule) +{ + return nla_total_size(16) /* dst */ + + nla_total_size(16); /* src */ +} + static struct fib_rules_ops fib6_rules_ops = { .family = AF_INET6, .rule_size = sizeof(struct fib6_rule), @@ -241,6 +247,7 @@ static struct fib_rules_ops fib6_rules_ops = { .compare = fib6_rule_compare, .fill = fib6_rule_fill, .default_pref = fib6_rule_default_pref, + .nlmsg_payload = fib6_rule_nlmsg_payload, .nlgroup = RTNLGRP_IPV6_RULE, .policy = fib6_rule_policy, .rules_list = &fib6_rules, diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0ad07c9087a7..a6472cb9054c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2006,6 +2006,20 @@ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) return ip6_route_add(&cfg); } +static inline size_t rt6_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct rtmsg)) + + nla_total_size(16) /* RTA_SRC */ + + nla_total_size(16) /* RTA_DST */ + + nla_total_size(16) /* RTA_GATEWAY */ + + nla_total_size(16) /* RTA_PREFSRC */ + + nla_total_size(4) /* RTA_TABLE */ + + nla_total_size(4) /* RTA_IIF */ + + nla_total_size(4) /* RTA_OIF */ + + nla_total_size(4) /* RTA_PRIORITY */ + + nla_total_size(sizeof(struct rta_cacheinfo)); +} + static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, struct in6_addr *dst, struct in6_addr *src, int iif, int type, u32 pid, u32 seq, @@ -2200,7 +2214,6 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) struct sk_buff *skb; u32 pid = 0, seq = 0; struct nlmsghdr *nlh = NULL; - int payload = sizeof(struct rtmsg) + 256; int err = -ENOBUFS; if (info) { @@ -2210,15 +2223,13 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) seq = nlh->nlmsg_seq; } - skb = nlmsg_new(nlmsg_total_size(payload), gfp_any()); + skb = nlmsg_new(rt6_nlmsg_size(), gfp_any()); if (skb == NULL) goto errout; err = rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in rt6_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any()); errout: diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index a6ce1d6d5c59..f1788bd290f8 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -452,7 +452,7 @@ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info) } list_start: - ans_skb = nlmsg_new(NLMSG_GOODSIZE * nlsze_mult, GFP_KERNEL); + ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL); if (ans_skb == NULL) { ret_val = -ENOMEM; goto list_failure; diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 53c9079ad2c3..c529622ff0b7 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -356,7 +356,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) void *data; struct netlbl_dom_map *entry; - ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (ans_skb == NULL) return -ENOMEM; data = netlbl_netlink_hdr_put(ans_skb, @@ -492,7 +492,7 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) struct sk_buff *ans_skb = NULL; void *data; - ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (ans_skb == NULL) return -ENOMEM; data = netlbl_netlink_hdr_put(ans_skb, diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 1833ad233b39..219dccade4e1 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -138,7 +138,7 @@ static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info) struct sk_buff *ans_skb; void *data; - ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (ans_skb == NULL) goto list_failure; data = netlbl_netlink_hdr_put(ans_skb, diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d527c8977b1f..f61d81b3c61c 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1148,7 +1148,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, if (len > sk->sk_sndbuf - 32) goto out; err = -ENOBUFS; - skb = nlmsg_new(len, GFP_KERNEL); + skb = alloc_skb(len, GFP_KERNEL); if (skb==NULL) goto out; @@ -1435,14 +1435,13 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) struct sk_buff *skb; struct nlmsghdr *rep; struct nlmsgerr *errmsg; - int size; + size_t payload = sizeof(*errmsg); - if (err == 0) - size = nlmsg_total_size(sizeof(*errmsg)); - else - size = nlmsg_total_size(sizeof(*errmsg) + nlmsg_len(nlh)); + /* error messages get the original request appened */ + if (err) + payload += nlmsg_len(nlh); - skb = nlmsg_new(size, GFP_KERNEL); + skb = nlmsg_new(payload, GFP_KERNEL); if (!skb) { struct sock *sk; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 49bc2db7982b..70d60c818897 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -480,7 +480,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, struct sk_buff *skb; int err; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (skb == NULL) return ERR_PTR(-ENOBUFS); -- cgit v1.2.3 From 2e2e9e92bd723244ea20fa488b1780111f2b05e1 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 13 Nov 2006 13:23:52 -0200 Subject: [DCCP]: Add sysctls to control retransmission behaviour This adds 3 sysctls which govern the retransmission behaviour of DCCP control packets (3way handshake, feature negotiation). It removes 4 FIXMEs from the code. The close resemblance of sysctl variables to their TCP analogues is emphasised not only by their name, but also by giving them the same initial values. This is useful since there is not much practical experience with DCCP yet. Furthermore, with regard to the previous patch, it is now possible to limit the number of keepalive-Responses by setting net.dccp.default.request_retries (also a bit like in TCP). Lastly, added documentation of all existing DCCP sysctls. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- Documentation/networking/dccp.txt | 41 +++++++++++++++++++++++++++++++++++++++ include/linux/sysctl.h | 3 +++ net/dccp/dccp.h | 11 +++++++++++ net/dccp/feat.h | 7 ------- net/dccp/proto.c | 1 + net/dccp/sysctl.c | 25 ++++++++++++++++++++++++ net/dccp/timer.c | 16 +++++++++------ 7 files changed, 91 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index a8142a81038a..c2328c862e98 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -63,6 +63,47 @@ DCCP_SOCKOPT_SEND_CSCOV is for the receiver and has a different meaning: it coverage value are also acceptable. The higher the number, the more restrictive this setting (see [RFC 4340, sec. 9.2.1]). +Sysctl variables +================ +Several DCCP default parameters can be managed by the following sysctls +(sysctl net.dccp.default or /proc/sys/net/dccp/default): + +request_retries + The number of active connection initiation retries (the number of + Requests minus one) before timing out. In addition, it also governs + the behaviour of the other, passive side: this variable also sets + the number of times DCCP repeats sending a Response when the initial + handshake does not progress from RESPOND to OPEN (i.e. when no Ack + is received after the initial Request). This value should be greater + than 0, suggested is less than 10. Analogue of tcp_syn_retries. + +retries1 + How often a DCCP Response is retransmitted until the listening DCCP + side considers its connecting peer dead. Analogue of tcp_retries1. + +retries2 + The number of times a general DCCP packet is retransmitted. This has + importance for retransmitted acknowledgments and feature negotiation, + data packets are never retransmitted. Analogue of tcp_retries2. + +send_ndp = 1 + Whether or not to send NDP count options (sec. 7.7.2). + +send_ackvec = 1 + Whether or not to send Ack Vector options (sec. 11.5). + +ack_ratio = 2 + The default Ack Ratio (sec. 11.3) to use. + +tx_ccid = 2 + Default CCID for the sender-receiver half-connection. + +rx_ccid = 2 + Default CCID for the receiver-sender half-connection. + +seq_window = 100 + The initial sequence window (sec. 7.5.2). + Notes ===== diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 0725441621d0..2e8c5ad82793 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -614,6 +614,9 @@ enum { NET_DCCP_DEFAULT_ACK_RATIO = 4, NET_DCCP_DEFAULT_SEND_ACKVEC = 5, NET_DCCP_DEFAULT_SEND_NDP = 6, + NET_DCCP_DEFAULT_REQ_RETRIES = 7, + NET_DCCP_DEFAULT_RETRIES1 = 8, + NET_DCCP_DEFAULT_RETRIES2 = 9, }; /* /proc/sys/net/ipx */ diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index d5c414bf7819..e7b96074a1b1 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -64,6 +64,17 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo); #define DCCP_XMIT_TIMEO 30000 /* Time/msecs for blocking transmit per packet */ +/* sysctl variables for DCCP */ +extern int sysctl_dccp_request_retries; +extern int sysctl_dccp_retries1; +extern int sysctl_dccp_retries2; +extern int dccp_feat_default_sequence_window; +extern int dccp_feat_default_rx_ccid; +extern int dccp_feat_default_tx_ccid; +extern int dccp_feat_default_ack_ratio; +extern int dccp_feat_default_send_ack_vector; +extern int dccp_feat_default_send_ndp_count; + /* is seq1 < seq2 ? */ static inline int before48(const u64 seq1, const u64 seq2) { diff --git a/net/dccp/feat.h b/net/dccp/feat.h index cee553d416ca..6048373c7186 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h @@ -26,11 +26,4 @@ extern void dccp_feat_clean(struct dccp_minisock *dmsk); extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); extern int dccp_feat_init(struct dccp_minisock *dmsk); -extern int dccp_feat_default_sequence_window; -extern int dccp_feat_default_rx_ccid; -extern int dccp_feat_default_tx_ccid; -extern int dccp_feat_default_ack_ratio; -extern int dccp_feat_default_send_ack_vector; -extern int dccp_feat_default_send_ndp_count; - #endif /* _DCCP_FEAT_H */ diff --git a/net/dccp/proto.c b/net/dccp/proto.c index db54e557eff1..9c9c08cffdaf 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -212,6 +212,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) dccp_init_xmit_timers(sk); icsk->icsk_rto = DCCP_TIMEOUT_INIT; + icsk->icsk_syn_retries = sysctl_dccp_request_retries; sk->sk_state = DCCP_CLOSED; sk->sk_write_space = dccp_write_space; icsk->icsk_sync_mss = dccp_sync_mss; diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index 38bc157876f3..7b09f2179985 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c @@ -11,6 +11,7 @@ #include #include +#include "dccp.h" #include "feat.h" #ifndef CONFIG_SYSCTL @@ -66,6 +67,30 @@ static struct ctl_table dccp_default_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .ctl_name = NET_DCCP_DEFAULT_REQ_RETRIES, + .procname = "request_retries", + .data = &sysctl_dccp_request_retries, + .maxlen = sizeof(sysctl_dccp_request_retries), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .ctl_name = NET_DCCP_DEFAULT_RETRIES1, + .procname = "retries1", + .data = &sysctl_dccp_retries1, + .maxlen = sizeof(sysctl_dccp_retries1), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .ctl_name = NET_DCCP_DEFAULT_RETRIES2, + .procname = "retries2", + .data = &sysctl_dccp_retries2, + .maxlen = sizeof(sysctl_dccp_retries2), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { .ctl_name = 0, } }; diff --git a/net/dccp/timer.c b/net/dccp/timer.c index bda0af639ae4..7b3f16e29a97 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -15,6 +15,11 @@ #include "dccp.h" +/* sysctl variables governing numbers of retransmission attempts */ +int sysctl_dccp_request_retries __read_mostly = TCP_SYN_RETRIES; +int sysctl_dccp_retries1 __read_mostly = TCP_RETR1; +int sysctl_dccp_retries2 __read_mostly = TCP_RETR2; + static void dccp_write_timer(unsigned long data); static void dccp_keepalive_timer(unsigned long data); static void dccp_delack_timer(unsigned long data); @@ -44,11 +49,10 @@ static int dccp_write_timeout(struct sock *sk) if (sk->sk_state == DCCP_REQUESTING || sk->sk_state == DCCP_PARTOPEN) { if (icsk->icsk_retransmits != 0) dst_negative_advice(&sk->sk_dst_cache); - retry_until = icsk->icsk_syn_retries ? : - /* FIXME! */ 3 /* FIXME! sysctl_tcp_syn_retries */; + retry_until = icsk->icsk_syn_retries ? + : sysctl_dccp_request_retries; } else { - if (icsk->icsk_retransmits >= - /* FIXME! sysctl_tcp_retries1 */ 5 /* FIXME! */) { + if (icsk->icsk_retransmits >= sysctl_dccp_retries1) { /* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu black hole detection. :-( @@ -72,7 +76,7 @@ static int dccp_write_timeout(struct sock *sk) dst_negative_advice(&sk->sk_dst_cache); } - retry_until = /* FIXME! */ 15 /* FIXME! sysctl_tcp_retries2 */; + retry_until = sysctl_dccp_retries2; /* * FIXME: see tcp_write_timout and tcp_out_of_resources */ @@ -196,7 +200,7 @@ backoff: icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX); inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, DCCP_RTO_MAX); - if (icsk->icsk_retransmits > 3 /* FIXME: sysctl_dccp_retries1 */) + if (icsk->icsk_retransmits > sysctl_dccp_retries1) __sk_dst_reset(sk); out:; } -- cgit v1.2.3 From 90833aa4f496d69ca374af6acef7d1614c8693ff Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 13 Nov 2006 16:02:22 -0800 Subject: [NET]: The scheduled removal of the frame diverter. This patch contains the scheduled removal of the frame diverter. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- Documentation/feature-removal-schedule.txt | 15 - drivers/net/Space.c | 1 - include/linux/Kbuild | 1 - include/linux/divert.h | 132 ------- include/linux/netdevice.h | 6 - include/linux/sockios.h | 4 +- net/Kconfig | 27 -- net/core/Makefile | 1 - net/core/dev.c | 20 +- net/core/dv.c | 546 ----------------------------- net/core/sysctl_net_core.c | 14 - net/socket.c | 6 - 12 files changed, 6 insertions(+), 767 deletions(-) delete mode 100644 include/linux/divert.h delete mode 100644 net/core/dv.c (limited to 'include/linux') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index d52c4aaaf17f..b3949cd3d013 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -227,21 +227,6 @@ Who: Patrick McHardy --------------------------- -What: frame diverter -When: November 2006 -Why: The frame diverter is included in most distribution kernels, but is - broken. It does not correctly handle many things: - - IPV6 - - non-linear skb's - - network device RCU on removal - - input frames not correctly checked for protocol errors - It also adds allocation overhead even if not enabled. - It is not clear if anyone is still using it. -Who: Stephen Hemminger - ---------------------------- - - What: PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment When: October 2008 Why: The stacking of class devices makes these values misleading and diff --git a/drivers/net/Space.c b/drivers/net/Space.c index a67f5efc983f..602ed31a5dd9 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -33,7 +33,6 @@ #include #include #include -#include /* A unified ethernet device probe. This is the easiest way to have every ethernet adaptor have the name "eth[0123...]". diff --git a/include/linux/Kbuild b/include/linux/Kbuild index a1155a2beb32..d7e04689304c 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -193,7 +193,6 @@ unifdef-y += cuda.h unifdef-y += cyclades.h unifdef-y += dccp.h unifdef-y += dirent.h -unifdef-y += divert.h unifdef-y += dlm.h unifdef-y += elfcore.h unifdef-y += errno.h diff --git a/include/linux/divert.h b/include/linux/divert.h deleted file mode 100644 index 8fb4e9de6843..000000000000 --- a/include/linux/divert.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Frame Diversion, Benoit Locher - * - * Changes: - * 06/09/2000 BL: initial version - * - */ - -#ifndef _LINUX_DIVERT_H -#define _LINUX_DIVERT_H - -#include - -#define MAX_DIVERT_PORTS 8 /* Max number of ports to divert (tcp, udp) */ - -/* Divertable protocols */ -#define DIVERT_PROTO_NONE 0x0000 -#define DIVERT_PROTO_IP 0x0001 -#define DIVERT_PROTO_ICMP 0x0002 -#define DIVERT_PROTO_TCP 0x0004 -#define DIVERT_PROTO_UDP 0x0008 - -/* - * This is an Ethernet Frame Diverter option block - */ -struct divert_blk -{ - int divert; /* are we active */ - unsigned int protos; /* protocols */ - __u16 tcp_dst[MAX_DIVERT_PORTS]; /* specific tcp dst ports to divert */ - __u16 tcp_src[MAX_DIVERT_PORTS]; /* specific tcp src ports to divert */ - __u16 udp_dst[MAX_DIVERT_PORTS]; /* specific udp dst ports to divert */ - __u16 udp_src[MAX_DIVERT_PORTS]; /* specific udp src ports to divert */ -}; - -/* - * Diversion control block, for configuration with the userspace tool - * divert - */ - -typedef union _divert_cf_arg -{ - __s16 int16; - __u16 uint16; - __s32 int32; - __u32 uint32; - __s64 int64; - __u64 uint64; - void __user *ptr; -} divert_cf_arg; - - -struct divert_cf -{ - int cmd; /* Command */ - divert_cf_arg arg1, - arg2, - arg3; - int dev_index; /* device index (eth0=0, etc...) */ -}; - - -/* Diversion commands */ -#define DIVCMD_DIVERT 1 /* ENABLE/DISABLE diversion */ -#define DIVCMD_IP 2 /* ENABLE/DISABLE whold IP diversion */ -#define DIVCMD_TCP 3 /* ENABLE/DISABLE whold TCP diversion */ -#define DIVCMD_TCPDST 4 /* ADD/REMOVE TCP DST port for diversion */ -#define DIVCMD_TCPSRC 5 /* ADD/REMOVE TCP SRC port for diversion */ -#define DIVCMD_UDP 6 /* ENABLE/DISABLE whole UDP diversion */ -#define DIVCMD_UDPDST 7 /* ADD/REMOVE UDP DST port for diversion */ -#define DIVCMD_UDPSRC 8 /* ADD/REMOVE UDP SRC port for diversion */ -#define DIVCMD_ICMP 9 /* ENABLE/DISABLE whole ICMP diversion */ -#define DIVCMD_GETSTATUS 10 /* GET the status of the diverter */ -#define DIVCMD_RESET 11 /* Reset the diverter on the specified dev */ -#define DIVCMD_GETVERSION 12 /* Retrieve the diverter code version (char[32]) */ - -/* General syntax of the commands: - * - * DIVCMD_xxxxxx(arg1, arg2, arg3, dev_index) - * - * SIOCSIFDIVERT: - * DIVCMD_DIVERT(DIVARG1_ENABLE|DIVARG1_DISABLE, , ,ifindex) - * DIVCMD_IP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) - * DIVCMD_TCP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) - * DIVCMD_TCPDST(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) - * DIVCMD_TCPSRC(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) - * DIVCMD_UDP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) - * DIVCMD_UDPDST(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) - * DIVCMD_UDPSRC(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) - * DIVCMD_ICMP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) - * DIVCMD_RESET(, , , ifindex) - * - * SIOGIFDIVERT: - * DIVCMD_GETSTATUS(divert_blk, , , ifindex) - * DIVCMD_GETVERSION(string[3]) - */ - - -/* Possible values for arg1 */ -#define DIVARG1_ENABLE 0 /* ENABLE something */ -#define DIVARG1_DISABLE 1 /* DISABLE something */ -#define DIVARG1_ADD 2 /* ADD something */ -#define DIVARG1_REMOVE 3 /* REMOVE something */ - - -#ifdef __KERNEL__ - -/* diverter functions */ -#include - -#ifdef CONFIG_NET_DIVERT -#include - -int alloc_divert_blk(struct net_device *); -void free_divert_blk(struct net_device *); -int divert_ioctl(unsigned int cmd, struct divert_cf __user *arg); -void divert_frame(struct sk_buff *skb); -static inline void handle_diverter(struct sk_buff *skb) -{ - /* if diversion is supported on device, then divert */ - if (skb->dev->divert && skb->dev->divert->divert) - divert_frame(skb); -} - -#else -# define alloc_divert_blk(dev) (0) -# define free_divert_blk(dev) do {} while (0) -# define divert_ioctl(cmd, arg) (-ENOPKG) -# define handle_diverter(skb) do {} while (0) -#endif -#endif -#endif /* _LINUX_DIVERT_H */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 83b8c4f1d69d..4e967b2e22cc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -38,7 +38,6 @@ #include #include -struct divert_blk; struct vlan_group; struct ethtool_ops; struct netpoll_info; @@ -517,11 +516,6 @@ struct net_device /* bridge stuff */ struct net_bridge_port *br_port; -#ifdef CONFIG_NET_DIVERT - /* this will get initialized at each interface type init routine */ - struct divert_blk *divert; -#endif /* CONFIG_NET_DIVERT */ - /* class/net/name entry */ struct class_device class_dev; /* space for optional statistics and wireless sysfs groups */ diff --git a/include/linux/sockios.h b/include/linux/sockios.h index e6b9d1d36ea2..abef7596655a 100644 --- a/include/linux/sockios.h +++ b/include/linux/sockios.h @@ -72,8 +72,8 @@ #define SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */ #define SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */ -#define SIOCGIFDIVERT 0x8944 /* Frame diversion support */ -#define SIOCSIFDIVERT 0x8945 /* Set frame diversion options */ +/* SIOCGIFDIVERT was: 0x8944 Frame diversion support */ +/* SIOCSIFDIVERT was: 0x8945 Set frame diversion options */ #define SIOCETHTOOL 0x8946 /* Ethtool interface */ diff --git a/net/Kconfig b/net/Kconfig index 67e39ad8b8b6..867f95032513 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -175,33 +175,6 @@ source "net/ipx/Kconfig" source "drivers/net/appletalk/Kconfig" source "net/x25/Kconfig" source "net/lapb/Kconfig" - -config NET_DIVERT - bool "Frame Diverter (EXPERIMENTAL)" - depends on EXPERIMENTAL && BROKEN - ---help--- - The Frame Diverter allows you to divert packets from the - network, that are not aimed at the interface receiving it (in - promisc. mode). Typically, a Linux box setup as an Ethernet bridge - with the Frames Diverter on, can do some *really* transparent www - caching using a Squid proxy for example. - - This is very useful when you don't want to change your router's - config (or if you simply don't have access to it). - - The other possible usages of diverting Ethernet Frames are - numberous: - - reroute smtp traffic to another interface - - traffic-shape certain network streams - - transparently proxy smtp connections - - etc... - - For more informations, please refer to: - - - - If unsure, say N. - source "net/econet/Kconfig" source "net/wanrouter/Kconfig" source "net/sched/Kconfig" diff --git a/net/core/Makefile b/net/core/Makefile index 119568077dab..73272d506e93 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -12,7 +12,6 @@ obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \ obj-$(CONFIG_XFRM) += flow.o obj-$(CONFIG_SYSFS) += net-sysfs.o -obj-$(CONFIG_NET_DIVERT) += dv.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_WIRELESS_EXT) += wireless.o obj-$(CONFIG_NETPOLL) += netpoll.o diff --git a/net/core/dev.c b/net/core/dev.c index 411c2428d268..5bf13b132dd7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -98,7 +98,6 @@ #include #include #include -#include #include #include #include @@ -1827,8 +1826,6 @@ int netif_receive_skb(struct sk_buff *skb) ncls: #endif - handle_diverter(skb); - if (handle_bridge(&skb, &pt_prev, &ret, orig_dev)) goto out; @@ -2898,10 +2895,6 @@ int register_netdevice(struct net_device *dev) spin_lock_init(&dev->ingress_lock); #endif - ret = alloc_divert_blk(dev); - if (ret) - goto out; - dev->iflink = -1; /* Init, if this function is available */ @@ -2910,13 +2903,13 @@ int register_netdevice(struct net_device *dev) if (ret) { if (ret > 0) ret = -EIO; - goto out_err; + goto out; } } if (!dev_valid_name(dev->name)) { ret = -EINVAL; - goto out_err; + goto out; } dev->ifindex = dev_new_index(); @@ -2930,7 +2923,7 @@ int register_netdevice(struct net_device *dev) = hlist_entry(p, struct net_device, name_hlist); if (!strncmp(d->name, dev->name, IFNAMSIZ)) { ret = -EEXIST; - goto out_err; + goto out; } } @@ -2974,7 +2967,7 @@ int register_netdevice(struct net_device *dev) ret = netdev_register_sysfs(dev); if (ret) - goto out_err; + goto out; dev->reg_state = NETREG_REGISTERED; /* @@ -3001,9 +2994,6 @@ int register_netdevice(struct net_device *dev) out: return ret; -out_err: - free_divert_blk(dev); - goto out; } /** @@ -3320,8 +3310,6 @@ int unregister_netdevice(struct net_device *dev) /* Notifier chain MUST detach us from master device. */ BUG_TRAP(!dev->master); - free_divert_blk(dev); - /* Finish processing unregister after unlock */ net_set_todo(dev); diff --git a/net/core/dv.c b/net/core/dv.c deleted file mode 100644 index 29ee77f15932..000000000000 --- a/net/core/dv.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Generic frame diversion - * - * Authors: - * Benoit LOCHER: initial integration within the kernel with support for ethernet - * Dave Miller: improvement on the code (correctness, performance and source files) - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -const char sysctl_divert_version[32]="0.46"; /* Current version */ - -static int __init dv_init(void) -{ - return 0; -} -module_init(dv_init); - -/* - * Allocate a divert_blk for a device. This must be an ethernet nic. - */ -int alloc_divert_blk(struct net_device *dev) -{ - int alloc_size = (sizeof(struct divert_blk) + 3) & ~3; - - dev->divert = NULL; - if (dev->type == ARPHRD_ETHER) { - dev->divert = kzalloc(alloc_size, GFP_KERNEL); - if (dev->divert == NULL) { - printk(KERN_INFO "divert: unable to allocate divert_blk for %s\n", - dev->name); - return -ENOMEM; - } - dev_hold(dev); - } - - return 0; -} - -/* - * Free a divert_blk allocated by the above function, if it was - * allocated on that device. - */ -void free_divert_blk(struct net_device *dev) -{ - if (dev->divert) { - kfree(dev->divert); - dev->divert=NULL; - dev_put(dev); - } -} - -/* - * Adds a tcp/udp (source or dest) port to an array - */ -static int add_port(u16 ports[], u16 port) -{ - int i; - - if (port == 0) - return -EINVAL; - - /* Storing directly in network format for performance, - * thanks Dave :) - */ - port = htons(port); - - for (i = 0; i < MAX_DIVERT_PORTS; i++) { - if (ports[i] == port) - return -EALREADY; - } - - for (i = 0; i < MAX_DIVERT_PORTS; i++) { - if (ports[i] == 0) { - ports[i] = port; - return 0; - } - } - - return -ENOBUFS; -} - -/* - * Removes a port from an array tcp/udp (source or dest) - */ -static int remove_port(u16 ports[], u16 port) -{ - int i; - - if (port == 0) - return -EINVAL; - - /* Storing directly in network format for performance, - * thanks Dave ! - */ - port = htons(port); - - for (i = 0; i < MAX_DIVERT_PORTS; i++) { - if (ports[i] == port) { - ports[i] = 0; - return 0; - } - } - - return -EINVAL; -} - -/* Some basic sanity checks on the arguments passed to divert_ioctl() */ -static int check_args(struct divert_cf *div_cf, struct net_device **dev) -{ - char devname[32]; - int ret; - - if (dev == NULL) - return -EFAULT; - - /* GETVERSION: all other args are unused */ - if (div_cf->cmd == DIVCMD_GETVERSION) - return 0; - - /* Network device index should reasonably be between 0 and 1000 :) */ - if (div_cf->dev_index < 0 || div_cf->dev_index > 1000) - return -EINVAL; - - /* Let's try to find the ifname */ - sprintf(devname, "eth%d", div_cf->dev_index); - *dev = dev_get_by_name(devname); - - /* dev should NOT be null */ - if (*dev == NULL) - return -EINVAL; - - ret = 0; - - /* user issuing the ioctl must be a super one :) */ - if (!capable(CAP_SYS_ADMIN)) { - ret = -EPERM; - goto out; - } - - /* Device must have a divert_blk member NOT null */ - if ((*dev)->divert == NULL) - ret = -EINVAL; -out: - dev_put(*dev); - return ret; -} - -/* - * control function of the diverter - */ -#if 0 -#define DVDBG(a) \ - printk(KERN_DEBUG "divert_ioctl() line %d %s\n", __LINE__, (a)) -#else -#define DVDBG(a) -#endif - -int divert_ioctl(unsigned int cmd, struct divert_cf __user *arg) -{ - struct divert_cf div_cf; - struct divert_blk *div_blk; - struct net_device *dev; - int ret; - - switch (cmd) { - case SIOCGIFDIVERT: - DVDBG("SIOCGIFDIVERT, copy_from_user"); - if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf))) - return -EFAULT; - DVDBG("before check_args"); - ret = check_args(&div_cf, &dev); - if (ret) - return ret; - DVDBG("after checkargs"); - div_blk = dev->divert; - - DVDBG("befre switch()"); - switch (div_cf.cmd) { - case DIVCMD_GETSTATUS: - /* Now, just give the user the raw divert block - * for him to play with :) - */ - if (copy_to_user(div_cf.arg1.ptr, dev->divert, - sizeof(struct divert_blk))) - return -EFAULT; - break; - - case DIVCMD_GETVERSION: - DVDBG("GETVERSION: checking ptr"); - if (div_cf.arg1.ptr == NULL) - return -EINVAL; - DVDBG("GETVERSION: copying data to userland"); - if (copy_to_user(div_cf.arg1.ptr, - sysctl_divert_version, 32)) - return -EFAULT; - DVDBG("GETVERSION: data copied"); - break; - - default: - return -EINVAL; - } - - break; - - case SIOCSIFDIVERT: - if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf))) - return -EFAULT; - - ret = check_args(&div_cf, &dev); - if (ret) - return ret; - - div_blk = dev->divert; - - switch(div_cf.cmd) { - case DIVCMD_RESET: - div_blk->divert = 0; - div_blk->protos = DIVERT_PROTO_NONE; - memset(div_blk->tcp_dst, 0, - MAX_DIVERT_PORTS * sizeof(u16)); - memset(div_blk->tcp_src, 0, - MAX_DIVERT_PORTS * sizeof(u16)); - memset(div_blk->udp_dst, 0, - MAX_DIVERT_PORTS * sizeof(u16)); - memset(div_blk->udp_src, 0, - MAX_DIVERT_PORTS * sizeof(u16)); - return 0; - - case DIVCMD_DIVERT: - switch(div_cf.arg1.int32) { - case DIVARG1_ENABLE: - if (div_blk->divert) - return -EALREADY; - div_blk->divert = 1; - break; - - case DIVARG1_DISABLE: - if (!div_blk->divert) - return -EALREADY; - div_blk->divert = 0; - break; - - default: - return -EINVAL; - } - - break; - - case DIVCMD_IP: - switch(div_cf.arg1.int32) { - case DIVARG1_ENABLE: - if (div_blk->protos & DIVERT_PROTO_IP) - return -EALREADY; - div_blk->protos |= DIVERT_PROTO_IP; - break; - - case DIVARG1_DISABLE: - if (!(div_blk->protos & DIVERT_PROTO_IP)) - return -EALREADY; - div_blk->protos &= ~DIVERT_PROTO_IP; - break; - - default: - return -EINVAL; - } - - break; - - case DIVCMD_TCP: - switch(div_cf.arg1.int32) { - case DIVARG1_ENABLE: - if (div_blk->protos & DIVERT_PROTO_TCP) - return -EALREADY; - div_blk->protos |= DIVERT_PROTO_TCP; - break; - - case DIVARG1_DISABLE: - if (!(div_blk->protos & DIVERT_PROTO_TCP)) - return -EALREADY; - div_blk->protos &= ~DIVERT_PROTO_TCP; - break; - - default: - return -EINVAL; - } - - break; - - case DIVCMD_TCPDST: - switch(div_cf.arg1.int32) { - case DIVARG1_ADD: - return add_port(div_blk->tcp_dst, - div_cf.arg2.uint16); - - case DIVARG1_REMOVE: - return remove_port(div_blk->tcp_dst, - div_cf.arg2.uint16); - - default: - return -EINVAL; - } - - break; - - case DIVCMD_TCPSRC: - switch(div_cf.arg1.int32) { - case DIVARG1_ADD: - return add_port(div_blk->tcp_src, - div_cf.arg2.uint16); - - case DIVARG1_REMOVE: - return remove_port(div_blk->tcp_src, - div_cf.arg2.uint16); - - default: - return -EINVAL; - } - - break; - - case DIVCMD_UDP: - switch(div_cf.arg1.int32) { - case DIVARG1_ENABLE: - if (div_blk->protos & DIVERT_PROTO_UDP) - return -EALREADY; - div_blk->protos |= DIVERT_PROTO_UDP; - break; - - case DIVARG1_DISABLE: - if (!(div_blk->protos & DIVERT_PROTO_UDP)) - return -EALREADY; - div_blk->protos &= ~DIVERT_PROTO_UDP; - break; - - default: - return -EINVAL; - } - - break; - - case DIVCMD_UDPDST: - switch(div_cf.arg1.int32) { - case DIVARG1_ADD: - return add_port(div_blk->udp_dst, - div_cf.arg2.uint16); - - case DIVARG1_REMOVE: - return remove_port(div_blk->udp_dst, - div_cf.arg2.uint16); - - default: - return -EINVAL; - } - - break; - - case DIVCMD_UDPSRC: - switch(div_cf.arg1.int32) { - case DIVARG1_ADD: - return add_port(div_blk->udp_src, - div_cf.arg2.uint16); - - case DIVARG1_REMOVE: - return remove_port(div_blk->udp_src, - div_cf.arg2.uint16); - - default: - return -EINVAL; - } - - break; - - case DIVCMD_ICMP: - switch(div_cf.arg1.int32) { - case DIVARG1_ENABLE: - if (div_blk->protos & DIVERT_PROTO_ICMP) - return -EALREADY; - div_blk->protos |= DIVERT_PROTO_ICMP; - break; - - case DIVARG1_DISABLE: - if (!(div_blk->protos & DIVERT_PROTO_ICMP)) - return -EALREADY; - div_blk->protos &= ~DIVERT_PROTO_ICMP; - break; - - default: - return -EINVAL; - } - - break; - - default: - return -EINVAL; - } - - break; - - default: - return -EINVAL; - } - - return 0; -} - - -/* - * Check if packet should have its dest mac address set to the box itself - * for diversion - */ - -#define ETH_DIVERT_FRAME(skb) \ - memcpy(eth_hdr(skb), skb->dev->dev_addr, ETH_ALEN); \ - skb->pkt_type=PACKET_HOST - -void divert_frame(struct sk_buff *skb) -{ - struct ethhdr *eth = eth_hdr(skb); - struct iphdr *iph; - struct tcphdr *tcph; - struct udphdr *udph; - struct divert_blk *divert = skb->dev->divert; - int i, src, dst; - unsigned char *skb_data_end = skb->data + skb->len; - - /* Packet is already aimed at us, return */ - if (!compare_ether_addr(eth->h_dest, skb->dev->dev_addr)) - return; - - /* proto is not IP, do nothing */ - if (eth->h_proto != htons(ETH_P_IP)) - return; - - /* Divert all IP frames ? */ - if (divert->protos & DIVERT_PROTO_IP) { - ETH_DIVERT_FRAME(skb); - return; - } - - /* Check for possible (maliciously) malformed IP frame (thanks Dave) */ - iph = (struct iphdr *) skb->data; - if (((iph->ihl<<2)+(unsigned char*)(iph)) >= skb_data_end) { - printk(KERN_INFO "divert: malformed IP packet !\n"); - return; - } - - switch (iph->protocol) { - /* Divert all ICMP frames ? */ - case IPPROTO_ICMP: - if (divert->protos & DIVERT_PROTO_ICMP) { - ETH_DIVERT_FRAME(skb); - return; - } - break; - - /* Divert all TCP frames ? */ - case IPPROTO_TCP: - if (divert->protos & DIVERT_PROTO_TCP) { - ETH_DIVERT_FRAME(skb); - return; - } - - /* Check for possible (maliciously) malformed IP - * frame (thanx Dave) - */ - tcph = (struct tcphdr *) - (((unsigned char *)iph) + (iph->ihl<<2)); - if (((unsigned char *)(tcph+1)) >= skb_data_end) { - printk(KERN_INFO "divert: malformed TCP packet !\n"); - return; - } - - /* Divert some tcp dst/src ports only ?*/ - for (i = 0; i < MAX_DIVERT_PORTS; i++) { - dst = divert->tcp_dst[i]; - src = divert->tcp_src[i]; - if ((dst && dst == tcph->dest) || - (src && src == tcph->source)) { - ETH_DIVERT_FRAME(skb); - return; - } - } - break; - - /* Divert all UDP frames ? */ - case IPPROTO_UDP: - if (divert->protos & DIVERT_PROTO_UDP) { - ETH_DIVERT_FRAME(skb); - return; - } - - /* Check for possible (maliciously) malformed IP - * packet (thanks Dave) - */ - udph = (struct udphdr *) - (((unsigned char *)iph) + (iph->ihl<<2)); - if (((unsigned char *)(udph+1)) >= skb_data_end) { - printk(KERN_INFO - "divert: malformed UDP packet !\n"); - return; - } - - /* Divert some udp dst/src ports only ? */ - for (i = 0; i < MAX_DIVERT_PORTS; i++) { - dst = divert->udp_dst[i]; - src = divert->udp_src[i]; - if ((dst && dst == udph->dest) || - (src && src == udph->source)) { - ETH_DIVERT_FRAME(skb); - return; - } - } - break; - } -} diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 02534131d88e..1e75b1585460 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -21,10 +21,6 @@ extern __u32 sysctl_rmem_max; extern int sysctl_core_destroy_delay; -#ifdef CONFIG_NET_DIVERT -extern char sysctl_divert_version[]; -#endif /* CONFIG_NET_DIVERT */ - #ifdef CONFIG_XFRM extern u32 sysctl_xfrm_aevent_etime; extern u32 sysctl_xfrm_aevent_rseqth; @@ -105,16 +101,6 @@ ctl_table core_table[] = { .mode = 0644, .proc_handler = &proc_dointvec }, -#ifdef CONFIG_NET_DIVERT - { - .ctl_name = NET_CORE_DIVERT_VERSION, - .procname = "divert_version", - .data = (void *)sysctl_divert_version, - .maxlen = 32, - .mode = 0444, - .proc_handler = &proc_dostring - }, -#endif /* CONFIG_NET_DIVERT */ #ifdef CONFIG_XFRM { .ctl_name = NET_CORE_AEVENT_ETIME, diff --git a/net/socket.c b/net/socket.c index 6c9b9b326d76..e8db54702a69 100644 --- a/net/socket.c +++ b/net/socket.c @@ -77,7 +77,6 @@ #include #include #include -#include #include #include #include @@ -852,11 +851,6 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) err = vlan_ioctl_hook(argp); mutex_unlock(&vlan_ioctl_mutex); break; - case SIOCGIFDIVERT: - case SIOCSIFDIVERT: - /* Convert this to call through a hook */ - err = divert_ioctl(cmd, argp); - break; case SIOCADDDLCI: case SIOCDELDLCI: err = -ENOPKG; -- cgit v1.2.3 From b9df3cb8cf9a96e63dfdcd3056a9cbc71f2459e7 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 14 Nov 2006 11:21:36 -0200 Subject: [TCP/DCCP]: Introduce net_xmit_eval Throughout the TCP/DCCP (and tunnelling) code, it often happens that the return code of a transmit function needs to be tested against NET_XMIT_CN which is a value that does not indicate a strict error condition. This patch uses a macro for these recurring situations which is consistent with the already existing macro net_xmit_errno, saving on duplicated code. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/netdevice.h | 4 ++++ include/net/ipip.h | 2 +- net/dccp/ipv4.c | 5 ++--- net/dccp/ipv6.c | 3 +-- net/dccp/output.c | 14 ++------------ net/ipv4/tcp_ipv4.c | 3 +-- net/ipv4/tcp_output.c | 8 +------- net/ipv6/ip6_tunnel.c | 2 +- net/ipv6/tcp_ipv6.c | 3 +-- 9 files changed, 14 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4e967b2e22cc..caa3c2593719 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -66,6 +66,10 @@ struct netpoll_info; #define NET_RX_CN_HIGH 4 /* The storm is here */ #define NET_RX_BAD 5 /* packet dropped due to kernel error */ +/* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It + * indicates that the device will soon be dropping packets, or already drops + * some packets of the same priority; prompting us to send less aggressively. */ +#define net_xmit_eval(e) ((e) == NET_XMIT_CN? 0 : (e)) #define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0) #endif diff --git a/include/net/ipip.h b/include/net/ipip.h index f490c3cbe377..84058858eea7 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -35,7 +35,7 @@ struct ip_tunnel ip_send_check(iph); \ \ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output);\ - if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) { \ + if (net_xmit_eval(err) == 0) { \ stats->tx_bytes += pkt_len; \ stats->tx_packets++; \ } else { \ diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index bc400b2ba25e..61c09014dade 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -501,8 +501,7 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, ireq->opt); - if (err == NET_XMIT_CN) - err = 0; + err = net_xmit_eval(err); } out: @@ -571,7 +570,7 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) rxskb->nh.iph->saddr, NULL); bh_unlock_sock(dccp_v4_ctl_socket->sk); - if (err == NET_XMIT_CN || err == 0) { + if (net_xmit_eval(err) == 0) { DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 8d6ddb6389a7..2165b1740c7c 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -294,8 +294,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, &ireq6->rmt_addr); ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); err = ip6_xmit(sk, skb, &fl, opt, 0); - if (err == NET_XMIT_CN) - err = 0; + err = net_xmit_eval(err); } done: diff --git a/net/dccp/output.c b/net/dccp/output.c index 0994b13f0f15..ef22f3cc791a 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -125,16 +125,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = icsk->icsk_af_ops->queue_xmit(skb, sk, 0); - if (err <= 0) - return err; - - /* NET_XMIT_CN is special. It does not guarantee, - * that this packet is lost. It tells that device - * is about to start to drop packets or already - * drops some packets of the same priority and - * invokes us to send less aggressively. - */ - return err == NET_XMIT_CN ? 0 : err; + return net_xmit_eval(err); } return -ENOBUFS; } @@ -426,8 +417,7 @@ int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code) if (skb != NULL) { memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = inet_csk(sk)->icsk_af_ops->queue_xmit(skb, sk, 0); - if (err == NET_XMIT_CN) - err = 0; + return net_xmit_eval(err); } } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 2eb58844403c..0ad0904bf56c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -662,8 +662,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req, err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, ireq->opt); - if (err == NET_XMIT_CN) - err = 0; + err = net_xmit_eval(err); } out: diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f63e99aac2d5..6a8581ab9a23 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -484,13 +484,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, tcp_enter_cwr(sk); - /* NET_XMIT_CN is special. It does not guarantee, - * that this packet is lost. It tells that device - * is about to start to drop packets or already - * drops some packets of the same priority and - * invokes us to send less aggressively. - */ - return err == NET_XMIT_CN ? 0 : err; + return net_xmit_eval(err); #undef SYSCTL_FLAG_TSTAMPS #undef SYSCTL_FLAG_WSCALE diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 4919f9294e2a..80a11909159d 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -748,7 +748,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); - if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) { + if (net_xmit_eval(err) == 0) { stats->tx_bytes += pkt_len; stats->tx_packets++; } else { diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 9a8e690fdf7c..9a88395a7629 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -502,8 +502,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); err = ip6_xmit(sk, skb, &fl, opt, 0); - if (err == NET_XMIT_CN) - err = 0; + err = net_xmit_eval(err); } done: -- cgit v1.2.3 From c02fdc0e81e9c735d8d895af1e201b235df326d8 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 14 Nov 2006 12:48:10 -0200 Subject: [DCCP]: Make feature negotiation more readable This patch replaces cryptic feature negotiation messages of type Oct 31 15:42:20 kernel: dccp_feat_change: feat change type=32 feat=1 Oct 31 15:42:21 kernel: dccp_feat_change: feat change type=34 feat=1 Oct 31 15:42:21 kernel: dccp_feat_change: feat change type=32 feat=5 into ones of type: Nov 2 13:54:45 kernel: dccp_feat_change: ChangeL(CCID (1), 3) Nov 2 13:54:45 kernel: dccp_feat_change: ChangeR(CCID (1), 3) Nov 2 13:54:45 kernel: dccp_feat_change: ChangeL(Ack Ratio (5), 2) Also, * completed the feature number list wrt RFC 4340 sec. 6.4 * annotating which ones have been implemented so far * implemented rudimentary sanity checking in feat.c (FIXMEs) * some minor fixes Commiter note: uninlined dccp_feat_name and dccp_feat_typename, for consistency with dccp_{state,packet}_name, that, BTW, should be compiled only if CONFIG_IP_DCCP_DEBUG is selected, leaving this to another cset tho. Also shortened dccp_feat_negotiation_debug to dccp_feat_debug. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/dccp.h | 25 ++++++----- net/dccp/feat.c | 116 +++++++++++++++++++++++++++++++++++++++------------ net/dccp/feat.h | 41 +++++++++++++++++- net/dccp/options.c | 4 +- 4 files changed, 145 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 0502dfa7f32c..696319ee2d5b 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -175,18 +175,21 @@ enum { DCCPC_CCID3 = 3, }; -/* DCCP features */ -enum { - DCCPF_RESERVED = 0, - DCCPF_CCID = 1, - DCCPF_SEQUENCE_WINDOW = 3, - DCCPF_ACK_RATIO = 5, - DCCPF_SEND_ACK_VECTOR = 6, - DCCPF_SEND_NDP_COUNT = 7, +/* DCCP features (RFC 4340 section 6.4) */ + enum { + DCCPF_RESERVED = 0, + DCCPF_CCID = 1, + DCCPF_SHORT_SEQNOS = 2, /* XXX: not yet implemented */ + DCCPF_SEQUENCE_WINDOW = 3, + DCCPF_ECN_INCAPABLE = 4, /* XXX: not yet implemented */ + DCCPF_ACK_RATIO = 5, + DCCPF_SEND_ACK_VECTOR = 6, + DCCPF_SEND_NDP_COUNT = 7, DCCPF_MIN_CSUM_COVER = 8, - /* 10-127 reserved */ - DCCPF_MIN_CCID_SPECIFIC = 128, - DCCPF_MAX_CCID_SPECIFIC = 255, + DCCPF_DATA_CHECKSUM = 9, /* XXX: not yet implemented */ + /* 10-127 reserved */ + DCCPF_MIN_CCID_SPECIFIC = 128, + DCCPF_MAX_CCID_SPECIFIC = 255, }; /* this structure is argument to DCCP_SOCKOPT_CHANGE_X */ diff --git a/net/dccp/feat.c b/net/dccp/feat.c index a1b0682ee77c..12cde2f2f13b 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -12,7 +12,6 @@ #include -#include "dccp.h" #include "ccid.h" #include "feat.h" @@ -23,9 +22,17 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, { struct dccp_opt_pend *opt; - dccp_pr_debug("feat change type=%d feat=%d\n", type, feature); + dccp_feat_debug(type, feature, *val); - /* XXX sanity check feat change request */ + if (!dccp_feat_is_valid_type(type)) { + pr_info("option type %d invalid in negotiation\n", type); + return 1; + } + if (!dccp_feat_is_valid_length(type, feature, len)) { + pr_info("invalid length %d\n", len); + return 1; + } + /* XXX add further sanity checks */ /* check if that feature is already being negotiated */ list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { @@ -95,14 +102,14 @@ static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) /* XXX taking only u8 vals */ static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) { - dccp_pr_debug("changing [%d] feat %d to %d\n", type, feat, val); + dccp_feat_debug(type, feat, val); switch (feat) { case DCCPF_CCID: return dccp_feat_update_ccid(sk, type, val); default: - dccp_pr_debug("IMPLEMENT changing [%d] feat %d to %d\n", - type, feat, val); + dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n", + dccp_feat_typename(type), feat); break; } return 0; @@ -265,10 +272,10 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) u8 *copy; int rc; - /* NN features must be change L */ - if (type == DCCPO_CHANGE_R) { - dccp_pr_debug("received CHANGE_R %d for NN feat %d\n", - type, feature); + /* NN features must be Change L (sec. 6.3.2) */ + if (type != DCCPO_CHANGE_L) { + dccp_pr_debug("received %s for NN feature %d\n", + dccp_feat_typename(type), feature); return -EFAULT; } @@ -299,7 +306,8 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) return rc; } - dccp_pr_debug("Confirming NN feature %d (val=%d)\n", feature, *copy); + dccp_feat_debug(type, feature, *copy); + list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); return 0; @@ -318,14 +326,19 @@ static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, return; } - opt->dccpop_type = type == DCCPO_CHANGE_L ? DCCPO_CONFIRM_R : - DCCPO_CONFIRM_L; + switch (type) { + case DCCPO_CHANGE_L: opt->dccpop_type = DCCPO_CONFIRM_R; break; + case DCCPO_CHANGE_R: opt->dccpop_type = DCCPO_CONFIRM_L; break; + default: pr_info("invalid type %d\n", type); return; + + } opt->dccpop_feat = feature; opt->dccpop_val = NULL; opt->dccpop_len = 0; /* change feature */ - dccp_pr_debug("Empty confirm feature %d type %d\n", feature, type); + dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature); + list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); } @@ -359,7 +372,7 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) { int rc; - dccp_pr_debug("got feat change type=%d feat=%d\n", type, feature); + dccp_feat_debug(type, feature, *val); /* figure out if it's SP or NN feature */ switch (feature) { @@ -375,6 +388,8 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) /* XXX implement other features */ default: + dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n", + dccp_feat_typename(type), feature); rc = -EFAULT; break; } @@ -403,20 +418,27 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, u8 t; struct dccp_opt_pend *opt; struct dccp_minisock *dmsk = dccp_msk(sk); - int rc = 1; + int found = 0; int all_confirmed = 1; - dccp_pr_debug("got feat confirm type=%d feat=%d\n", type, feature); - - /* XXX sanity check type & feat */ + dccp_feat_debug(type, feature, *val); /* locate our change request */ - t = type == DCCPO_CONFIRM_L ? DCCPO_CHANGE_R : DCCPO_CHANGE_L; + switch (type) { + case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break; + case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break; + default: pr_info("invalid type %d\n", type); + return 1; + + } + /* XXX sanity check feature value */ list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { if (!opt->dccpop_conf && opt->dccpop_type == t && opt->dccpop_feat == feature) { - /* we found it */ + found = 1; + dccp_pr_debug("feature %d found\n", opt->dccpop_feat); + /* XXX do sanity check */ opt->dccpop_conf = 1; @@ -425,9 +447,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *val); - dccp_pr_debug("feat %d type %d confirmed %d\n", - feature, type, *val); - rc = 0; + /* XXX check the return value of dccp_feat_update */ break; } @@ -446,9 +466,9 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); } - if (rc) - dccp_pr_debug("feat %d type %d never requested\n", - feature, type); + if (!found) + dccp_pr_debug("%s(%d, ...) never requested\n", + dccp_feat_typename(type), feature); return 0; } @@ -583,3 +603,45 @@ out: } EXPORT_SYMBOL_GPL(dccp_feat_init); + +#ifdef CONFIG_IP_DCCP_DEBUG +const char *dccp_feat_typename(const u8 type) +{ + switch(type) { + case DCCPO_CHANGE_L: return("ChangeL"); + case DCCPO_CONFIRM_L: return("ConfirmL"); + case DCCPO_CHANGE_R: return("ChangeR"); + case DCCPO_CONFIRM_R: return("ConfirmR"); + /* the following case must not appear in feature negotation */ + default: dccp_pr_debug("unknown type %d [BUG!]\n", type); + } + return NULL; +} + +EXPORT_SYMBOL_GPL(dccp_feat_typename); + +const char *dccp_feat_name(const u8 feat) +{ + static const char *feature_names[] = { + [DCCPF_RESERVED] = "Reserved", + [DCCPF_CCID] = "CCID", + [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", + [DCCPF_SEQUENCE_WINDOW] = "Sequence Window", + [DCCPF_ECN_INCAPABLE] = "ECN Incapable", + [DCCPF_ACK_RATIO] = "Ack Ratio", + [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector", + [DCCPF_SEND_NDP_COUNT] = "Send NDP Count", + [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage", + [DCCPF_DATA_CHECKSUM] = "Send Data Checksum", + }; + if (feat >= DCCPF_MIN_CCID_SPECIFIC) + return "CCID-specific"; + + if (dccp_feat_is_reserved(feat)) + return feature_names[DCCPF_RESERVED]; + + return feature_names[feat]; +} + +EXPORT_SYMBOL_GPL(dccp_feat_name); +#endif /* CONFIG_IP_DCCP_DEBUG */ diff --git a/net/dccp/feat.h b/net/dccp/feat.h index 6048373c7186..2c373ad7edcf 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h @@ -12,9 +12,46 @@ */ #include +#include "dccp.h" -struct sock; -struct dccp_minisock; +static inline int dccp_feat_is_valid_length(u8 type, u8 feature, u8 len) +{ + /* sec. 6.1: Confirm has at least length 3, + * sec. 6.2: Change has at least length 4 */ + if (len < 3) + return 1; + if (len < 4 && (type == DCCPO_CHANGE_L || type == DCCPO_CHANGE_R)) + return 1; + /* XXX: add per-feature length validation (sec. 6.6.8) */ + return 0; +} + +static inline int dccp_feat_is_reserved(const u8 feat) +{ + return (feat > DCCPF_DATA_CHECKSUM && + feat < DCCPF_MIN_CCID_SPECIFIC) || + feat == DCCPF_RESERVED; +} + +/* feature negotiation knows only these four option types (RFC 4340, sec. 6) */ +static inline int dccp_feat_is_valid_type(const u8 optnum) +{ + return optnum >= DCCPO_CHANGE_L && optnum <= DCCPO_CONFIRM_R; + +} + +#ifdef CONFIG_IP_DCCP_DEBUG +extern const char *dccp_feat_typename(const u8 type); +extern const char *dccp_feat_name(const u8 feat); + +static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val) +{ + dccp_pr_debug("%s(%s (%d), %d)\n", dccp_feat_typename(type), + dccp_feat_name(feat), feat, val); +} +#else +#define dccp_feat_debug(type, feat, val) +#endif /* CONFIG_IP_DCCP_DEBUG */ extern int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, u8 *val, u8 len, gfp_t gfp); diff --git a/net/dccp/options.c b/net/dccp/options.c index 121e794fe454..2d0ef27f4ab9 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -465,8 +465,10 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, if (len) memcpy(to, val, len); - dccp_pr_debug("option %d feat %d len %d\n", type, feat, len); + dccp_pr_debug("%s(%s (%d), ...), length %d\n", + dccp_feat_typename(type), + dccp_feat_name(feat), feat, len); return 0; } -- cgit v1.2.3 From 09dbc3895e3242346bd434dae743c456fd28fc6a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 14 Nov 2006 12:57:34 -0200 Subject: [DCCP]: Miscellaneous code tidy-ups This patch does not change code; it performs some trivial clean/tidy-ups: * removal of a `debug_prefix' string in favour of the already existing dccp_role(sk) * add documentation of structures and constants * separated out the cases for invalid packets (step 1 of the packet validation) * removing duplicate statements * combining declaration & initialisation Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/dccp.h | 18 +++++++++++++++++- net/dccp/ackvec.c | 27 ++++++--------------------- net/dccp/ipv4.c | 39 +++++++++++++++++++-------------------- net/dccp/ipv6.c | 6 ++---- net/dccp/options.c | 18 +++++++----------- net/dccp/output.c | 1 + net/dccp/proto.c | 8 ++------ 7 files changed, 54 insertions(+), 63 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 696319ee2d5b..d308f1228b61 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -209,6 +209,7 @@ struct dccp_so_feat { #define DCCP_SOCKOPT_CCID_RX_INFO 128 #define DCCP_SOCKOPT_CCID_TX_INFO 192 +/* maximum number of services provided on the same listening port */ #define DCCP_SERVICE_LIST_MAX_LEN 32 #ifdef __KERNEL__ @@ -355,6 +356,9 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) * @dccpms_ccid - Congestion Control Id (CCID) (section 10) * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5) * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2) + * @dccpms_ack_ratio - Ack Ratio Feature (section 11.3) + * @dccpms_pending - List of features being negotiated + * @dccpms_conf - */ struct dccp_minisock { __u64 dccpms_sequence_window; @@ -452,14 +456,26 @@ struct dccp_ackvec; * @dccps_gss - greatest sequence number sent * @dccps_gsr - greatest valid sequence number received * @dccps_gar - greatest valid ack number received on a non-Sync; initialized to %dccps_iss + * @dccps_service - first (passive sock) or unique (active sock) service code + * @dccps_service_list - second .. last service code on passive socket * @dccps_timestamp_time - time of latest TIMESTAMP option * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option * @dccps_packet_size - Set thru setsockopt - * @dccps_role - Role of this sock, one of %dccp_role + * @dccps_l_ack_ratio - + * @dccps_r_ack_ratio - * @dccps_pcslen - sender partial checksum coverage (via sockopt) * @dccps_pcrlen - receiver partial checksum coverage (via sockopt) * @dccps_ndp_count - number of Non Data Packets since last data packet + * @dccps_mss_cache - + * @dccps_minisock - * @dccps_hc_rx_ackvec - rx half connection ack vector + * @dccps_hc_rx_ccid - + * @dccps_hc_tx_ccid - + * @dccps_options_received - + * @dccps_epoch - + * @dccps_role - Role of this sock, one of %dccp_role + * @dccps_hc_rx_insert_options - + * @dccps_hc_tx_insert_options - * @dccps_xmit_timer - timer for when CCID is not ready to send */ struct dccp_sock { diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index f8208874ac7d..0c54b89a4e9b 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -67,10 +67,6 @@ static void dccp_ackvec_insert_avr(struct dccp_ackvec *av, int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); -#ifdef CONFIG_IP_DCCP_DEBUG - const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT tx: " : "server tx: "; -#endif struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; int len = av->dccpav_vec_len + 2; struct timeval now; @@ -129,9 +125,9 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) dccp_ackvec_insert_avr(av, avr); - dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " + dccp_pr_debug("%s ACK Vector 0, len=%d, ack_seqno=%llu, " "ack_ackno=%llu\n", - debug_prefix, avr->dccpavr_sent_len, + dccp_role(sk), avr->dccpavr_sent_len, (unsigned long long)avr->dccpavr_ack_seqno, (unsigned long long)avr->dccpavr_ack_ackno); return 0; @@ -380,14 +376,9 @@ void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk, */ list_for_each_entry_reverse(avr, &av->dccpav_records, dccpavr_node) { if (ackno == avr->dccpavr_ack_seqno) { -#ifdef CONFIG_IP_DCCP_DEBUG - struct dccp_sock *dp = dccp_sk(sk); - const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT rx ack: " : "server rx ack: "; -#endif - dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " + dccp_pr_debug("%s ACK packet 0, len=%d, ack_seqno=%llu, " "ack_ackno=%llu, ACKED!\n", - debug_prefix, 1, + dccp_role(sk), 1, (unsigned long long)avr->dccpavr_ack_seqno, (unsigned long long)avr->dccpavr_ack_ackno); dccp_ackvec_throw_record(av, avr); @@ -437,16 +428,10 @@ found: if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) { const u8 state = *vector & DCCP_ACKVEC_STATE_MASK; if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) { -#ifdef CONFIG_IP_DCCP_DEBUG - struct dccp_sock *dp = dccp_sk(sk); - const char *debug_prefix = - dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT rx ack: " : "server rx ack: "; -#endif - dccp_pr_debug("%sACK vector 0, len=%d, " + dccp_pr_debug("%s ACK vector 0, len=%d, " "ack_seqno=%llu, ack_ackno=%llu, " "ACKED!\n", - debug_prefix, len, + dccp_role(sk), len, (unsigned long long) avr->dccpavr_ack_seqno, (unsigned long long) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 61c09014dade..34d6d197c3b2 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -518,7 +518,7 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) sizeof(struct dccp_hdr_reset); struct sk_buff *skb; struct dst_entry *dst; - u64 seqno; + u64 seqno = 0; /* Never send a reset in response to a reset. */ if (rxdh->dccph_type == DCCP_PKT_RESET) @@ -552,13 +552,11 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) DCCP_SKB_CB(rxskb)->dccpd_reset_code; /* See "8.3.1. Abnormal Termination" in RFC 4340 */ - seqno = 0; if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1); dccp_hdr_set_seq(dh, seqno); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), - DCCP_SKB_CB(rxskb)->dccpd_seq); + dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); dccp_csum_outgoing(skb); dh->dccph_checksum = dccp_v4_csum_finish(skb, rxskb->nh.iph->saddr, @@ -734,6 +732,11 @@ discard: EXPORT_SYMBOL_GPL(dccp_v4_do_rcv); +/** + * dccp_invalid_packet - check for malformed packets + * Implements RFC 4340, 8.5: Step 1: Check header basics + * Packets that fail these checks are ignored and do not receive Resets. + */ int dccp_invalid_packet(struct sk_buff *skb) { const struct dccp_hdr *dh; @@ -742,6 +745,7 @@ int dccp_invalid_packet(struct sk_buff *skb) if (skb->pkt_type != PACKET_HOST) return 1; + /* If the packet is shorter than 12 bytes, drop packet and return */ if (!pskb_may_pull(skb, sizeof(struct dccp_hdr))) { LIMIT_NETDEBUG(KERN_WARNING "DCCP: pskb_may_pull failed\n"); return 1; @@ -749,42 +753,37 @@ int dccp_invalid_packet(struct sk_buff *skb) dh = dccp_hdr(skb); - /* If the packet type is not understood, drop packet and return */ + /* If P.type is not understood, drop packet and return */ if (dh->dccph_type >= DCCP_PKT_INVALID) { LIMIT_NETDEBUG(KERN_WARNING "DCCP: invalid packet type\n"); return 1; } /* - * If P.Data Offset is too small for packet type, or too large for - * packet, drop packet and return + * If P.Data Offset is too small for packet type, drop packet and return */ if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) { LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) " - "too small 1\n", - dh->dccph_doff); + "too small\n", dh->dccph_doff); return 1; } - + /* + * If P.Data Offset is too too large for packet, drop packet and return + */ if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) { LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) " - "too small 2\n", - dh->dccph_doff); + "too large\n", dh->dccph_doff); return 1; } - dh = dccp_hdr(skb); - /* * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet * has short sequence numbers), drop packet and return */ - if (dh->dccph_x == 0 && - dh->dccph_type != DCCP_PKT_DATA && - dh->dccph_type != DCCP_PKT_ACK && - dh->dccph_type != DCCP_PKT_DATAACK) { - LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.type (%s) not Data, Ack " - "nor DataAck and P.X == 0\n", + if (dh->dccph_type >= DCCP_PKT_DATA && + dh->dccph_type <= DCCP_PKT_DATAACK && dh->dccph_x == 0) { + LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.type (%s) not Data||Ack||" + "DataAck, while P.X == 0\n", dccp_packet_name(dh->dccph_type)); return 1; } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 2165b1740c7c..fc326173c215 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -318,7 +318,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) sizeof(struct dccp_hdr_reset); struct sk_buff *skb; struct flowi fl; - u64 seqno; + u64 seqno = 0; if (rxdh->dccph_type == DCCP_PKT_RESET) return; @@ -345,13 +345,11 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) DCCP_SKB_CB(rxskb)->dccpd_reset_code; /* See "8.3.1. Abnormal Termination" in RFC 4340 */ - seqno = 0; if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1); dccp_hdr_set_seq(dh, seqno); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), - DCCP_SKB_CB(rxskb)->dccpd_seq); + dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); dccp_csum_outgoing(skb); dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr, diff --git a/net/dccp/options.c b/net/dccp/options.c index 2d0ef27f4ab9..7e50678e2471 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -60,10 +60,6 @@ static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) int dccp_parse_options(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); -#ifdef CONFIG_IP_DCCP_DEBUG - const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT rx opt: " : "server rx opt: "; -#endif const struct dccp_hdr *dh = dccp_hdr(skb); const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); @@ -119,7 +115,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) goto out_invalid_option; opt_recv->dccpor_ndp = dccp_decode_value_var(value, len); - dccp_pr_debug("%sNDP count=%d\n", debug_prefix, + dccp_pr_debug("%s rx opt: NDP count=%d\n", dccp_role(sk), opt_recv->dccpor_ndp); break; case DCCPO_CHANGE_L: @@ -165,8 +161,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; dccp_timestamp(sk, &dp->dccps_timestamp_time); - dccp_pr_debug("%sTIMESTAMP=%u, ackno=%llu\n", - debug_prefix, opt_recv->dccpor_timestamp, + dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu\n", + dccp_role(sk), opt_recv->dccpor_timestamp, (unsigned long long) DCCP_SKB_CB(skb)->dccpd_ack_seq); break; @@ -176,8 +172,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) opt_recv->dccpor_timestamp_echo = ntohl(*(__be32 *)value); - dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ", - debug_prefix, + dccp_pr_debug("%s rx opt: TIMESTAMP_ECHO=%u, len=%d, " + "ackno=%llu, ", dccp_role(sk), opt_recv->dccpor_timestamp_echo, len + 2, (unsigned long long) @@ -211,8 +207,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) if (elapsed_time > opt_recv->dccpor_elapsed_time) opt_recv->dccpor_elapsed_time = elapsed_time; - dccp_pr_debug("%sELAPSED_TIME=%d\n", debug_prefix, - elapsed_time); + dccp_pr_debug("%s rx opt: ELAPSED_TIME=%d\n", + dccp_role(sk), elapsed_time); break; /* * From RFC 4340, sec. 10.3: diff --git a/net/dccp/output.c b/net/dccp/output.c index ef22f3cc791a..c34eada7f025 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -333,6 +333,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, return NULL; } + /* Build and checksum header */ dh = dccp_zeroed_hdr(skb, dccp_header_size); dh->dccph_sport = inet_sk(sk)->sport; diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 9c9c08cffdaf..0225bdacd3b1 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -452,9 +452,8 @@ out_free_val: static int do_dccp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { - struct dccp_sock *dp; - int err; - int val; + struct dccp_sock *dp = dccp_sk(sk); + int val, err = 0; if (optlen < sizeof(int)) return -EINVAL; @@ -466,9 +465,6 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, return dccp_setsockopt_service(sk, val, optval, optlen); lock_sock(sk); - dp = dccp_sk(sk); - err = 0; - switch (optname) { case DCCP_SOCKOPT_PACKET_SIZE: dp->dccps_packet_size = val; -- cgit v1.2.3 From 93ec2c723e3f8a216dde2899aeb85c648672bc6b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Oct 2006 15:46:50 -0700 Subject: netpoll info leak After looking harder, Steve noticed that the netpoll beast leaked a little every time it shutdown for a nap. Not a big leak, but a nuisance kind of thing. He took out his refcount duct tape and patched the leak. It was overkill since there was already other locking in that area, but it looked clean and wouldn't attract fleas. Signed-off-by: Stephen Hemminger --- include/linux/netpoll.h | 1 + net/core/netpoll.c | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 1efe60c5c00c..39845fc975f9 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -25,6 +25,7 @@ struct netpoll { }; struct netpoll_info { + atomic_t refcnt; spinlock_t poll_lock; int poll_owner; int tries; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 4de62f1f4134..c66df2f45d26 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -658,8 +658,11 @@ int netpoll_setup(struct netpoll *np) npinfo->tries = MAX_RETRIES; spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); - } else + atomic_set(&npinfo->refcnt, 1); + } else { npinfo = ndev->npinfo; + atomic_inc(&npinfo->refcnt); + } if (!ndev->poll_controller) { printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", @@ -766,12 +769,22 @@ void netpoll_cleanup(struct netpoll *np) if (np->dev) { npinfo = np->dev->npinfo; - if (npinfo && npinfo->rx_np == np) { - spin_lock_irqsave(&npinfo->rx_lock, flags); - npinfo->rx_np = NULL; - npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; - spin_unlock_irqrestore(&npinfo->rx_lock, flags); + if (npinfo) { + if (npinfo->rx_np == np) { + spin_lock_irqsave(&npinfo->rx_lock, flags); + npinfo->rx_np = NULL; + npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; + spin_unlock_irqrestore(&npinfo->rx_lock, flags); + } + + np->dev->npinfo = NULL; + if (atomic_dec_and_test(&npinfo->refcnt)) { + skb_queue_purge(&npinfo->arp_tx); + + kfree(npinfo); + } } + dev_put(np->dev); } -- cgit v1.2.3 From b6cd27ed33886a5ffaf0925a6d98e13e18e8a1af Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Oct 2006 15:46:51 -0700 Subject: netpoll per device txq When the netpoll beast got really busy, it tended to clog things, so it stored them for later. But the beast was putting all it's skb's in one basket. This was bad because maybe some pipes were clogged and others were not. Signed-off-by: Stephen Hemminger --- include/linux/netpoll.h | 2 ++ net/core/netpoll.c | 50 +++++++++++++++---------------------------------- 2 files changed, 17 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 39845fc975f9..93a8b7664423 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -33,6 +33,8 @@ struct netpoll_info { spinlock_t rx_lock; struct netpoll *rx_np; /* netpoll that registered an rx_hook */ struct sk_buff_head arp_tx; /* list of arp requests to reply to */ + struct sk_buff_head txq; + struct work_struct tx_work; }; void netpoll_poll(struct netpoll *np); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index c66df2f45d26..ac4e8b8f57d1 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -38,10 +38,6 @@ static struct sk_buff_head skb_pool; -static DEFINE_SPINLOCK(queue_lock); -static int queue_depth; -static struct sk_buff *queue_head, *queue_tail; - static atomic_t trapped; #define NETPOLL_RX_ENABLED 1 @@ -56,46 +52,25 @@ static void arp_reply(struct sk_buff *skb); static void queue_process(void *p) { - unsigned long flags; + struct netpoll_info *npinfo = p; struct sk_buff *skb; - while (queue_head) { - spin_lock_irqsave(&queue_lock, flags); - - skb = queue_head; - queue_head = skb->next; - if (skb == queue_tail) - queue_head = NULL; - - queue_depth--; - - spin_unlock_irqrestore(&queue_lock, flags); - + while ((skb = skb_dequeue(&npinfo->txq))) dev_queue_xmit(skb); - } -} -static DECLARE_WORK(send_queue, queue_process, NULL); +} void netpoll_queue(struct sk_buff *skb) { - unsigned long flags; + struct net_device *dev = skb->dev; + struct netpoll_info *npinfo = dev->npinfo; - if (queue_depth == MAX_QUEUE_DEPTH) { - __kfree_skb(skb); - return; + if (!npinfo) + kfree_skb(skb); + else { + skb_queue_tail(&npinfo->txq, skb); + schedule_work(&npinfo->tx_work); } - - spin_lock_irqsave(&queue_lock, flags); - if (!queue_head) - queue_head = skb; - else - queue_tail->next = skb; - queue_tail = skb; - queue_depth++; - spin_unlock_irqrestore(&queue_lock, flags); - - schedule_work(&send_queue); } static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, @@ -658,6 +633,9 @@ int netpoll_setup(struct netpoll *np) npinfo->tries = MAX_RETRIES; spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); + skb_queue_head_init(&npinfo->txq); + INIT_WORK(&npinfo->tx_work, queue_process, npinfo); + atomic_set(&npinfo->refcnt, 1); } else { npinfo = ndev->npinfo; @@ -780,6 +758,8 @@ void netpoll_cleanup(struct netpoll *np) np->dev->npinfo = NULL; if (atomic_dec_and_test(&npinfo->refcnt)) { skb_queue_purge(&npinfo->arp_tx); + skb_queue_purge(&npinfo->txq); + flush_scheduled_work(); kfree(npinfo); } -- cgit v1.2.3 From 2bdfe0baeca0e2750037b8fba71905c00ac3c515 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Oct 2006 15:46:54 -0700 Subject: netpoll retry cleanup The netpoll beast was still not happy. If the beast got clogged pipes, it tended to stare blankly off in space for a long time. The problem couldn't be completely fixed because the beast talked with irq's disabled. But it could be made less painful and shorter. Signed-off-by: Stephen Hemminger --- include/linux/netpoll.h | 1 - net/core/netpoll.c | 71 +++++++++++++++++++++++-------------------------- 2 files changed, 33 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 93a8b7664423..c65d12ec7bb0 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -28,7 +28,6 @@ struct netpoll_info { atomic_t refcnt; spinlock_t poll_lock; int poll_owner; - int tries; int rx_flags; spinlock_t rx_lock; struct netpoll *rx_np; /* netpoll that registered an rx_hook */ diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 93cb828f3aaf..6b34c394672f 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -34,12 +34,12 @@ #define MAX_UDP_CHUNK 1460 #define MAX_SKBS 32 #define MAX_QUEUE_DEPTH (MAX_SKBS / 2) -#define MAX_RETRIES 20000 static struct sk_buff_head skb_pool; static atomic_t trapped; +#define USEC_PER_POLL 50 #define NETPOLL_RX_ENABLED 1 #define NETPOLL_RX_DROP 2 @@ -72,6 +72,7 @@ static void queue_process(void *p) schedule_delayed_work(&npinfo->tx_work, HZ/10); return; } + netif_tx_unlock_bh(dev); } } @@ -244,50 +245,44 @@ repeat: static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) { - int status; - struct netpoll_info *npinfo; + int status = NETDEV_TX_BUSY; + unsigned long tries; + struct net_device *dev = np->dev; + struct netpoll_info *npinfo = np->dev->npinfo; + + if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) { + __kfree_skb(skb); + return; + } + + /* don't get messages out of order, and no recursion */ + if ( !(np->drop == netpoll_queue && skb_queue_len(&npinfo->txq)) + && npinfo->poll_owner != smp_processor_id() + && netif_tx_trylock(dev)) { + + /* try until next clock tick */ + for(tries = jiffies_to_usecs(1)/USEC_PER_POLL; tries > 0; --tries) { + if (!netif_queue_stopped(dev)) + status = dev->hard_start_xmit(skb, dev); + + if (status == NETDEV_TX_OK) + break; - if (!np || !np->dev || !netif_running(np->dev)) { - __kfree_skb(skb); - return; - } + /* tickle device maybe there is some cleanup */ + netpoll_poll(np); - npinfo = np->dev->npinfo; + udelay(USEC_PER_POLL); + } + netif_tx_unlock(dev); + } - /* avoid recursion */ - if (npinfo->poll_owner == smp_processor_id() || - np->dev->xmit_lock_owner == smp_processor_id()) { + if (status != NETDEV_TX_OK) { + /* requeue for later */ if (np->drop) np->drop(skb); else __kfree_skb(skb); - return; } - - do { - npinfo->tries--; - netif_tx_lock(np->dev); - - /* - * network drivers do not expect to be called if the queue is - * stopped. - */ - status = NETDEV_TX_BUSY; - if (!netif_queue_stopped(np->dev)) - status = np->dev->hard_start_xmit(skb, np->dev); - - netif_tx_unlock(np->dev); - - /* success */ - if(!status) { - npinfo->tries = MAX_RETRIES; /* reset */ - return; - } - - /* transmit busy */ - netpoll_poll(np); - udelay(50); - } while (npinfo->tries > 0); } void netpoll_send_udp(struct netpoll *np, const char *msg, int len) @@ -649,7 +644,7 @@ int netpoll_setup(struct netpoll *np) npinfo->rx_np = NULL; spin_lock_init(&npinfo->poll_lock); npinfo->poll_owner = -1; - npinfo->tries = MAX_RETRIES; + spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); skb_queue_head_init(&npinfo->txq); -- cgit v1.2.3 From 5de4a473bda49554e4e9bd93b78f43c49a7ea69c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Oct 2006 15:46:55 -0700 Subject: netpoll queue cleanup The beast had a long and not very happy history. At one point, a friend (netdump) had asked that he open up a little. Well, the friend was long gone now, and the beast had this dangling piece hanging (netpoll_queue). It wasn't hard to stitch the netpoll_queue back in where it belonged and make everything tidy. Signed-off-by: Stephen Hemminger --- drivers/net/netconsole.c | 1 - include/linux/netpoll.h | 4 ++-- net/core/netpoll.c | 23 +++-------------------- 3 files changed, 5 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index e6e8a9797b6d..69233f6aa05c 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -60,7 +60,6 @@ static struct netpoll np = { .local_port = 6665, .remote_port = 6666, .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - .drop = netpoll_queue, }; static int configured = 0; diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index c65d12ec7bb0..b7eb008c43de 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -18,7 +18,7 @@ struct netpoll { struct net_device *dev; char dev_name[16], *name; void (*rx_hook)(struct netpoll *, int, char *, int); - void (*drop)(struct sk_buff *skb); + u32 local_ip, remote_ip; u16 local_port, remote_port; unsigned char local_mac[6], remote_mac[6]; @@ -44,7 +44,7 @@ int netpoll_trap(void); void netpoll_set_trap(int trap); void netpoll_cleanup(struct netpoll *np); int __netpoll_rx(struct sk_buff *skb); -void netpoll_queue(struct sk_buff *skb); + #ifdef CONFIG_NETPOLL static inline int netpoll_rx(struct sk_buff *skb) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 6b34c394672f..0d1de3c47a01 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -77,19 +77,6 @@ static void queue_process(void *p) } } -void netpoll_queue(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct netpoll_info *npinfo = dev->npinfo; - - if (!npinfo) - kfree_skb(skb); - else { - skb_queue_tail(&npinfo->txq, skb); - schedule_work(&npinfo->tx_work); - } -} - static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, unsigned short ulen, u32 saddr, u32 daddr) { @@ -256,7 +243,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) } /* don't get messages out of order, and no recursion */ - if ( !(np->drop == netpoll_queue && skb_queue_len(&npinfo->txq)) + if ( skb_queue_len(&npinfo->txq) == 0 && npinfo->poll_owner != smp_processor_id() && netif_tx_trylock(dev)) { @@ -277,11 +264,8 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) } if (status != NETDEV_TX_OK) { - /* requeue for later */ - if (np->drop) - np->drop(skb); - else - __kfree_skb(skb); + skb_queue_tail(&npinfo->txq, skb); + schedule_work(&npinfo->tx_work); } } @@ -809,4 +793,3 @@ EXPORT_SYMBOL(netpoll_setup); EXPORT_SYMBOL(netpoll_cleanup); EXPORT_SYMBOL(netpoll_send_udp); EXPORT_SYMBOL(netpoll_poll); -EXPORT_SYMBOL(netpoll_queue); -- cgit v1.2.3 From bf6bce71eae386dbc37f93af7e5ad173450d9945 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Oct 2006 15:46:56 -0700 Subject: netpoll header cleanup As Steve left netpoll beast, hopefully not to return soon. He noticed that the header was messy. He straightened it up and polished it a little, then waved goodbye. Signed-off-by: Stephen Hemminger --- include/linux/netpoll.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index b7eb008c43de..2cc9867b1626 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -12,16 +12,15 @@ #include #include -struct netpoll; - struct netpoll { struct net_device *dev; - char dev_name[16], *name; + char dev_name[IFNAMSIZ]; + const char *name; void (*rx_hook)(struct netpoll *, int, char *, int); u32 local_ip, remote_ip; u16 local_port, remote_port; - unsigned char local_mac[6], remote_mac[6]; + u8 local_mac[ETH_ALEN], remote_mac[ETH_ALEN]; }; struct netpoll_info { -- cgit v1.2.3 From cfb6eeb4c860592edd123fdea908d23c6ad1c7dc Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 14 Nov 2006 19:07:45 -0800 Subject: [TCP]: MD5 Signature Option (RFC2385) support. Based on implementation by Rick Payne. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- CREDITS | 3 + include/linux/tcp.h | 35 ++- include/net/request_sock.h | 3 +- include/net/tcp.h | 143 ++++++++++ include/net/timewait_sock.h | 3 + net/dccp/ipv4.c | 6 +- net/dccp/ipv6.c | 6 +- net/dccp/minisocks.c | 2 +- net/ipv4/Kconfig | 16 ++ net/ipv4/tcp.c | 137 +++++++++ net/ipv4/tcp_input.c | 8 + net/ipv4/tcp_ipv4.c | 673 ++++++++++++++++++++++++++++++++++++++++++-- net/ipv4/tcp_minisocks.c | 64 ++++- net/ipv4/tcp_output.c | 111 +++++++- net/ipv6/tcp_ipv6.c | 568 +++++++++++++++++++++++++++++++++++-- 15 files changed, 1714 insertions(+), 64 deletions(-) (limited to 'include/linux') diff --git a/CREDITS b/CREDITS index ccd4f9f4dd71..d0880082c19b 100644 --- a/CREDITS +++ b/CREDITS @@ -2598,6 +2598,9 @@ S: Ucitelska 1576 S: Prague 8 S: 182 00 Czech Republic +N: Rick Payne +D: RFC2385 Support for TCP + N: Barak A. Pearlmutter E: bap@cs.unm.edu W: http://www.cs.unm.edu/~bap/ diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 2d36f6db3706..0aecfc955591 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -19,6 +19,7 @@ #include #include +#include struct tcphdr { __be16 source; @@ -94,6 +95,7 @@ enum { #define TCP_INFO 11 /* Information about this connection. */ #define TCP_QUICKACK 12 /* Block/reenable quick acks */ #define TCP_CONGESTION 13 /* Congestion control algorithm */ +#define TCP_MD5SIG 14 /* TCP MD5 Signature (RFC2385) */ #define TCPI_OPT_TIMESTAMPS 1 #define TCPI_OPT_SACK 2 @@ -157,6 +159,17 @@ struct tcp_info __u32 tcpi_total_retrans; }; +/* for TCP_MD5SIG socket option */ +#define TCP_MD5SIG_MAXKEYLEN 80 + +struct tcp_md5sig { + struct __kernel_sockaddr_storage tcpm_addr; /* address associated */ + __u16 __tcpm_pad1; /* zero */ + __u16 tcpm_keylen; /* key length */ + __u32 __tcpm_pad2; /* zero */ + __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */ +}; + #ifdef __KERNEL__ #include @@ -197,9 +210,13 @@ struct tcp_options_received { }; struct tcp_request_sock { - struct inet_request_sock req; - __u32 rcv_isn; - __u32 snt_isn; + struct inet_request_sock req; +#ifdef CONFIG_TCP_MD5SIG + /* Only used by TCP MD5 Signature so far. */ + struct tcp_request_sock_ops *af_specific; +#endif + __u32 rcv_isn; + __u32 snt_isn; }; static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) @@ -363,6 +380,14 @@ struct tcp_sock { __u32 probe_seq_start; __u32 probe_seq_end; } mtu_probe; + +#ifdef CONFIG_TCP_MD5SIG +/* TCP AF-Specific parts; only used by MD5 Signature support so far */ + struct tcp_sock_af_ops *af_specific; + +/* TCP MD5 Signagure Option information */ + struct tcp_md5sig_info *md5sig_info; +#endif }; static inline struct tcp_sock *tcp_sk(const struct sock *sk) @@ -377,6 +402,10 @@ struct tcp_timewait_sock { __u32 tw_rcv_wnd; __u32 tw_ts_recent; long tw_ts_recent_stamp; +#ifdef CONFIG_TCP_MD5SIG + __u16 tw_md5_keylen; + __u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN]; +#endif }; static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) diff --git a/include/net/request_sock.h b/include/net/request_sock.h index b5b023e79e5f..e37baaf2080b 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -35,7 +35,8 @@ struct request_sock_ops { struct dst_entry *dst); void (*send_ack)(struct sk_buff *skb, struct request_sock *req); - void (*send_reset)(struct sk_buff *skb); + void (*send_reset)(struct sock *sk, + struct sk_buff *skb); void (*destructor)(struct request_sock *req); }; diff --git a/include/net/tcp.h b/include/net/tcp.h index e1a5d29d0a1f..363960872de0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -161,6 +162,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOPT_SACK_PERM 4 /* SACK Permitted */ #define TCPOPT_SACK 5 /* SACK Block */ #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ +#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ /* * TCP option lengths @@ -170,6 +172,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOLEN_WINDOW 3 #define TCPOLEN_SACK_PERM 2 #define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_MD5SIG 18 /* But this is what stacks really send out. */ #define TCPOLEN_TSTAMP_ALIGNED 12 @@ -178,6 +181,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOLEN_SACK_BASE 2 #define TCPOLEN_SACK_BASE_ALIGNED 4 #define TCPOLEN_SACK_PERBLOCK 8 +#define TCPOLEN_MD5SIG_ALIGNED 20 /* Flags in tp->nonagle */ #define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */ @@ -299,6 +303,8 @@ extern void tcp_cleanup_rbuf(struct sock *sk, int copied); extern int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp); +extern void tcp_twsk_destructor(struct sock *sk); + static inline void tcp_dec_quickack_mode(struct sock *sk, const unsigned int pkts) { @@ -1064,6 +1070,114 @@ static inline void clear_all_retrans_hints(struct tcp_sock *tp){ tp->fastpath_skb_hint = NULL; } +/* MD5 Signature */ +struct crypto_hash; + +/* - key database */ +struct tcp_md5sig_key { + u8 *key; + u8 keylen; +}; + +struct tcp4_md5sig_key { + u8 *key; + u16 keylen; + __be32 addr; +}; + +struct tcp6_md5sig_key { + u8 *key; + u16 keylen; +#if 0 + u32 scope_id; /* XXX */ +#endif + struct in6_addr addr; +}; + +/* - sock block */ +struct tcp_md5sig_info { + struct tcp4_md5sig_key *keys4; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct tcp6_md5sig_key *keys6; + u32 entries6; + u32 alloced6; +#endif + u32 entries4; + u32 alloced4; +}; + +/* - pseudo header */ +struct tcp4_pseudohdr { + __be32 saddr; + __be32 daddr; + __u8 pad; + __u8 protocol; + __be16 len; +}; + +struct tcp6_pseudohdr { + struct in6_addr saddr; + struct in6_addr daddr; + __be32 len; + __be32 protocol; /* including padding */ +}; + +union tcp_md5sum_block { + struct tcp4_pseudohdr ip4; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct tcp6_pseudohdr ip6; +#endif +}; + +/* - pool: digest algorithm, hash description and scratch buffer */ +struct tcp_md5sig_pool { + struct hash_desc md5_desc; + union tcp_md5sum_block md5_blk; +}; + +#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */ + +/* - functions */ +extern int tcp_v4_calc_md5_hash(char *md5_hash, + struct tcp_md5sig_key *key, + struct sock *sk, + struct dst_entry *dst, + struct request_sock *req, + struct tcphdr *th, + int protocol, int tcplen); +extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, + struct sock *addr_sk); + +extern int tcp_v4_md5_do_add(struct sock *sk, + __be32 addr, + u8 *newkey, + u8 newkeylen); + +extern int tcp_v4_md5_do_del(struct sock *sk, + u32 addr); + +extern struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void); +extern void tcp_free_md5sig_pool(void); + +extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu); +extern void __tcp_put_md5sig_pool(void); + +static inline +struct tcp_md5sig_pool *tcp_get_md5sig_pool(void) +{ + int cpu = get_cpu(); + struct tcp_md5sig_pool *ret = __tcp_get_md5sig_pool(cpu); + if (!ret) + put_cpu(); + return ret; +} + +static inline void tcp_put_md5sig_pool(void) +{ + __tcp_put_md5sig_pool(); + put_cpu(); +} + /* /proc */ enum tcp_seq_states { TCP_SEQ_STATE_LISTENING, @@ -1103,6 +1217,35 @@ extern int tcp4_proc_init(void); extern void tcp4_proc_exit(void); #endif +/* TCP af-specific functions */ +struct tcp_sock_af_ops { +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk, + struct sock *addr_sk); + int (*calc_md5_hash) (char *location, + struct tcp_md5sig_key *md5, + struct sock *sk, + struct dst_entry *dst, + struct request_sock *req, + struct tcphdr *th, + int protocol, int len); + int (*md5_add) (struct sock *sk, + struct sock *addr_sk, + u8 *newkey, + u8 len); + int (*md5_parse) (struct sock *sk, + char __user *optval, + int optlen); +#endif +}; + +struct tcp_request_sock_ops { +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk, + struct request_sock *req); +#endif +}; + extern void tcp_v4_init(struct net_proto_family *ops); extern void tcp_init(void); diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h index be293d795e38..d7a306ea560d 100644 --- a/include/net/timewait_sock.h +++ b/include/net/timewait_sock.h @@ -31,6 +31,9 @@ static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) static inline void twsk_destructor(struct sock *sk) { + BUG_ON(sk == NULL); + BUG_ON(sk->sk_prot == NULL); + BUG_ON(sk->sk_prot->twsk_prot == NULL); if (sk->sk_prot->twsk_prot->twsk_destructor != NULL) sk->sk_prot->twsk_prot->twsk_destructor(sk); } diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 34d6d197c3b2..35985334daee 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -509,7 +509,7 @@ out: return err; } -static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) +static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) { int err; struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; @@ -724,7 +724,7 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) return 0; reset: - dccp_v4_ctl_send_reset(skb); + dccp_v4_ctl_send_reset(sk, skb); discard: kfree_skb(skb); return 0; @@ -913,7 +913,7 @@ no_dccp_socket: if (dh->dccph_type != DCCP_PKT_RESET) { DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; - dccp_v4_ctl_send_reset(skb); + dccp_v4_ctl_send_reset(sk, skb); } discard_it: diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index fc326173c215..e0a0607862ef 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -310,7 +310,7 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req) kfree_skb(inet6_rsk(req)->pktopts); } -static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) +static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) { struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) + @@ -805,7 +805,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) return 0; reset: - dccp_v6_ctl_send_reset(skb); + dccp_v6_ctl_send_reset(sk, skb); discard: if (opt_skb != NULL) __kfree_skb(opt_skb); @@ -902,7 +902,7 @@ no_dccp_socket: if (dh->dccph_type != DCCP_PKT_RESET) { DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; - dccp_v6_ctl_send_reset(skb); + dccp_v6_ctl_send_reset(sk, skb); } discard_it: diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 0c49733f5be1..3975048d8094 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -246,7 +246,7 @@ listen_overflow: DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; drop: if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET) - req->rsk_ops->send_reset(skb); + req->rsk_ops->send_reset(sk, skb); inet_csk_reqsk_queue_drop(sk, req, prev); goto out; diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index bc298bcc344e..39e0cb763588 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -618,5 +618,21 @@ config DEFAULT_TCP_CONG default "reno" if DEFAULT_RENO default "cubic" +config TCP_MD5SIG + bool "TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL)" + depends on EXPERIMENTAL + select CRYPTO + select CRYPTO_MD5 + ---help--- + RFC2385 specifices a method of giving MD5 protection to TCP sessions. + Its main (only?) use is to protect BGP sessions between core routers + on the Internet. + + If unsure, say N. + +config TCP_MD5SIG_DEBUG + bool "TCP: MD5 Signature Option debugging" + depends on TCP_MD5SIG + source "net/ipv4/ipvs/Kconfig" diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c05e8edaf544..dadef867a3bb 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -258,6 +258,7 @@ #include #include #include +#include #include #include @@ -1942,6 +1943,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level, } break; +#ifdef CONFIG_TCP_MD5SIG + case TCP_MD5SIG: + /* Read the IP->Key mappings from userspace */ + err = tp->af_specific->md5_parse(sk, optval, optlen); + break; +#endif + default: err = -ENOPROTOOPT; break; @@ -2231,6 +2239,135 @@ out: } EXPORT_SYMBOL(tcp_tso_segment); +#ifdef CONFIG_TCP_MD5SIG +static unsigned long tcp_md5sig_users; +static struct tcp_md5sig_pool **tcp_md5sig_pool; +static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); + +static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) +{ + int cpu; + for_each_possible_cpu(cpu) { + struct tcp_md5sig_pool *p = *per_cpu_ptr(pool, cpu); + if (p) { + if (p->md5_desc.tfm) + crypto_free_hash(p->md5_desc.tfm); + kfree(p); + p = NULL; + } + } + free_percpu(pool); +} + +void tcp_free_md5sig_pool(void) +{ + struct tcp_md5sig_pool **pool = NULL; + + spin_lock(&tcp_md5sig_pool_lock); + if (--tcp_md5sig_users == 0) { + pool = tcp_md5sig_pool; + tcp_md5sig_pool = NULL; + } + spin_unlock(&tcp_md5sig_pool_lock); + if (pool) + __tcp_free_md5sig_pool(pool); +} + +EXPORT_SYMBOL(tcp_free_md5sig_pool); + +struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(void) +{ + int cpu; + struct tcp_md5sig_pool **pool; + + pool = alloc_percpu(struct tcp_md5sig_pool *); + if (!pool) + return NULL; + + for_each_possible_cpu(cpu) { + struct tcp_md5sig_pool *p; + struct crypto_hash *hash; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + goto out_free; + *per_cpu_ptr(pool, cpu) = p; + + hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); + if (!hash || IS_ERR(hash)) + goto out_free; + + p->md5_desc.tfm = hash; + } + return pool; +out_free: + __tcp_free_md5sig_pool(pool); + return NULL; +} + +struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void) +{ + struct tcp_md5sig_pool **pool; + int alloc = 0; + +retry: + spin_lock(&tcp_md5sig_pool_lock); + pool = tcp_md5sig_pool; + if (tcp_md5sig_users++ == 0) { + alloc = 1; + spin_unlock(&tcp_md5sig_pool_lock); + } else if (!pool) { + tcp_md5sig_users--; + spin_unlock(&tcp_md5sig_pool_lock); + cpu_relax(); + goto retry; + } else + spin_unlock(&tcp_md5sig_pool_lock); + + if (alloc) { + /* we cannot hold spinlock here because this may sleep. */ + struct tcp_md5sig_pool **p = __tcp_alloc_md5sig_pool(); + spin_lock(&tcp_md5sig_pool_lock); + if (!p) { + tcp_md5sig_users--; + spin_unlock(&tcp_md5sig_pool_lock); + return NULL; + } + pool = tcp_md5sig_pool; + if (pool) { + /* oops, it has already been assigned. */ + spin_unlock(&tcp_md5sig_pool_lock); + __tcp_free_md5sig_pool(p); + } else { + tcp_md5sig_pool = pool = p; + spin_unlock(&tcp_md5sig_pool_lock); + } + } + return pool; +} + +EXPORT_SYMBOL(tcp_alloc_md5sig_pool); + +struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu) +{ + struct tcp_md5sig_pool **p; + spin_lock(&tcp_md5sig_pool_lock); + p = tcp_md5sig_pool; + if (p) + tcp_md5sig_users++; + spin_unlock(&tcp_md5sig_pool_lock); + return (p ? *per_cpu_ptr(p, cpu) : NULL); +} + +EXPORT_SYMBOL(__tcp_get_md5sig_pool); + +void __tcp_put_md5sig_pool(void) { + __tcp_free_md5sig_pool(tcp_md5sig_pool); +} + +EXPORT_SYMBOL(__tcp_put_md5sig_pool); +#endif + extern void __skb_cb_too_small_for_tcp(int, int); extern struct tcp_congestion_ops tcp_reno; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4a8c96cdec7d..6ab3423674bb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2677,6 +2677,14 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, opt_rx->sack_ok) { TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th; } +#ifdef CONFIG_TCP_MD5SIG + case TCPOPT_MD5SIG: + /* + * The MD5 Hash has already been + * checked (see tcp_v{4,6}_do_rcv()). + */ + break; +#endif }; ptr+=opsize-2; length-=opsize; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0ad0904bf56c..8c8e8112f98d 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -78,6 +78,9 @@ #include #include +#include +#include + int sysctl_tcp_tw_reuse __read_mostly; int sysctl_tcp_low_latency __read_mostly; @@ -89,6 +92,13 @@ static struct socket *tcp_socket; void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); +#ifdef CONFIG_TCP_MD5SIG +static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr); +static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + __be32 saddr, __be32 daddr, struct tcphdr *th, + int protocol, int tcplen); +#endif + struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock), .lhash_users = ATOMIC_INIT(0), @@ -526,11 +536,19 @@ int tcp_v4_gso_send_check(struct sk_buff *skb) * Exception: precedence violation. We do not implement it in any case. */ -static void tcp_v4_send_reset(struct sk_buff *skb) +static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) { struct tcphdr *th = skb->h.th; - struct tcphdr rth; + struct { + struct tcphdr th; +#ifdef CONFIG_TCP_MD5SIG + u32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; +#endif + } rep; struct ip_reply_arg arg; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; +#endif /* Never send a reset in response to a reset. */ if (th->rst) @@ -540,29 +558,50 @@ static void tcp_v4_send_reset(struct sk_buff *skb) return; /* Swap the send and the receive. */ - memset(&rth, 0, sizeof(struct tcphdr)); - rth.dest = th->source; - rth.source = th->dest; - rth.doff = sizeof(struct tcphdr) / 4; - rth.rst = 1; + memset(&rep, 0, sizeof(rep)); + rep.th.dest = th->source; + rep.th.source = th->dest; + rep.th.doff = sizeof(struct tcphdr) / 4; + rep.th.rst = 1; if (th->ack) { - rth.seq = th->ack_seq; + rep.th.seq = th->ack_seq; } else { - rth.ack = 1; - rth.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + - skb->len - (th->doff << 2)); + rep.th.ack = 1; + rep.th.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + + skb->len - (th->doff << 2)); } memset(&arg, 0, sizeof arg); - arg.iov[0].iov_base = (unsigned char *)&rth; - arg.iov[0].iov_len = sizeof rth; + arg.iov[0].iov_base = (unsigned char *)&rep; + arg.iov[0].iov_len = sizeof(rep.th); + +#ifdef CONFIG_TCP_MD5SIG + key = sk ? tcp_v4_md5_do_lookup(sk, skb->nh.iph->daddr) : NULL; + if (key) { + rep.opt[0] = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + /* Update length and the length the header thinks exists */ + arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; + rep.th.doff = arg.iov[0].iov_len / 4; + + tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[1], + key, + skb->nh.iph->daddr, + skb->nh.iph->saddr, + &rep.th, IPPROTO_TCP, + arg.iov[0].iov_len); + } +#endif + arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, skb->nh.iph->saddr, /*XXX*/ sizeof(struct tcphdr), IPPROTO_TCP, 0); arg.csumoffset = offsetof(struct tcphdr, check) / 2; - ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth); + ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); @@ -572,15 +611,24 @@ static void tcp_v4_send_reset(struct sk_buff *skb) outside socket context is ugly, certainly. What can I do? */ -static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, +static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, + struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) { struct tcphdr *th = skb->h.th; struct { struct tcphdr th; - u32 tsopt[TCPOLEN_TSTAMP_ALIGNED >> 2]; + u32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) +#ifdef CONFIG_TCP_MD5SIG + + (TCPOLEN_MD5SIG_ALIGNED >> 2) +#endif + ]; } rep; struct ip_reply_arg arg; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; + struct tcp_md5sig_key tw_key; +#endif memset(&rep.th, 0, sizeof(struct tcphdr)); memset(&arg, 0, sizeof arg); @@ -588,12 +636,12 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, arg.iov[0].iov_base = (unsigned char *)&rep; arg.iov[0].iov_len = sizeof(rep.th); if (ts) { - rep.tsopt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | - TCPOLEN_TIMESTAMP); - rep.tsopt[1] = htonl(tcp_time_stamp); - rep.tsopt[2] = htonl(ts); - arg.iov[0].iov_len = sizeof(rep); + rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); + rep.opt[1] = htonl(tcp_time_stamp); + rep.opt[2] = htonl(ts); + arg.iov[0].iov_len = TCPOLEN_TSTAMP_ALIGNED; } /* Swap the send and the receive. */ @@ -605,6 +653,44 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, rep.th.ack = 1; rep.th.window = htons(win); +#ifdef CONFIG_TCP_MD5SIG + /* + * The SKB holds an imcoming packet, but may not have a valid ->sk + * pointer. This is especially the case when we're dealing with a + * TIME_WAIT ack, because the sk structure is long gone, and only + * the tcp_timewait_sock remains. So the md5 key is stashed in that + * structure, and we use it in preference. I believe that (twsk || + * skb->sk) holds true, but we program defensively. + */ + if (!twsk && skb->sk) { + key = tcp_v4_md5_do_lookup(skb->sk, skb->nh.iph->daddr); + } else if (twsk && twsk->tw_md5_keylen) { + tw_key.key = twsk->tw_md5_key; + tw_key.keylen = twsk->tw_md5_keylen; + key = &tw_key; + } else { + key = NULL; + } + + if (key) { + int offset = (ts) ? 3 : 0; + + rep.opt[offset++] = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; + rep.th.doff = arg.iov[0].iov_len/4; + + tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[offset], + key, + skb->nh.iph->daddr, + skb->nh.iph->saddr, + &rep.th, IPPROTO_TCP, + arg.iov[0].iov_len); + } +#endif + arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, skb->nh.iph->saddr, /*XXX*/ arg.iov[0].iov_len, IPPROTO_TCP, 0); @@ -618,9 +704,9 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) { struct inet_timewait_sock *tw = inet_twsk(sk); - const struct tcp_timewait_sock *tcptw = tcp_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_ts_recent); inet_twsk_put(tw); @@ -628,7 +714,8 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) { - tcp_v4_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, + tcp_v4_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, + tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); } @@ -714,6 +801,461 @@ static struct ip_options *tcp_v4_save_options(struct sock *sk, return dopt; } +#ifdef CONFIG_TCP_MD5SIG +/* + * RFC2385 MD5 checksumming requires a mapping of + * IP address->MD5 Key. + * We need to maintain these in the sk structure. + */ + +/* Find the Key structure for an address. */ +static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + if (!tp->md5sig_info || !tp->md5sig_info->entries4) + return NULL; + for (i = 0; i < tp->md5sig_info->entries4; i++) { + if (tp->md5sig_info->keys4[i].addr == addr) + return (struct tcp_md5sig_key *)&tp->md5sig_info->keys4[i]; + } + return NULL; +} + +struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, + struct sock *addr_sk) +{ + return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->daddr); +} + +EXPORT_SYMBOL(tcp_v4_md5_lookup); + +struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, + struct request_sock *req) +{ + return tcp_v4_md5_do_lookup(sk, inet_rsk(req)->rmt_addr); +} + +/* This can be called on a newly created socket, from other files */ +int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, + u8 *newkey, u8 newkeylen) +{ + /* Add Key to the list */ + struct tcp4_md5sig_key *key; + struct tcp_sock *tp = tcp_sk(sk); + struct tcp4_md5sig_key *keys; + + key = (struct tcp4_md5sig_key *) tcp_v4_md5_do_lookup(sk, addr); + if (key) { + /* Pre-existing entry - just update that one. */ + kfree (key->key); + key->key = newkey; + key->keylen = newkeylen; + } else { + if (!tp->md5sig_info) { + tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC); + if (!tp->md5sig_info) { + kfree(newkey); + return -ENOMEM; + } + } + if (tcp_alloc_md5sig_pool() == NULL) { + kfree(newkey); + return -ENOMEM; + } + if (tp->md5sig_info->alloced4 == tp->md5sig_info->entries4) { + keys = kmalloc((sizeof(struct tcp4_md5sig_key) * + (tp->md5sig_info->entries4 + 1)), GFP_ATOMIC); + if (!keys) { + kfree(newkey); + tcp_free_md5sig_pool(); + return -ENOMEM; + } + + if (tp->md5sig_info->entries4) + memcpy(keys, tp->md5sig_info->keys4, + (sizeof (struct tcp4_md5sig_key) * + tp->md5sig_info->entries4)); + + /* Free old key list, and reference new one */ + if (tp->md5sig_info->keys4) + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = keys; + tp->md5sig_info->alloced4++; + } + tp->md5sig_info->entries4++; + tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].addr = addr; + tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].key = newkey; + tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].keylen = newkeylen; + } + return 0; +} + +EXPORT_SYMBOL(tcp_v4_md5_do_add); + +static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk, + u8 *newkey, u8 newkeylen) +{ + return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->daddr, + newkey, newkeylen); +} + +int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + for (i = 0; i < tp->md5sig_info->entries4; i++) { + if (tp->md5sig_info->keys4[i].addr == addr) { + /* Free the key */ + kfree(tp->md5sig_info->keys4[i].key); + tp->md5sig_info->entries4--; + + if (tp->md5sig_info->entries4 == 0) { + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = NULL; + } else { + /* Need to do some manipulation */ + if (tp->md5sig_info->entries4 != i) + memcpy(&tp->md5sig_info->keys4[i], + &tp->md5sig_info->keys4[i+1], + (tp->md5sig_info->entries4 - i) + * sizeof (struct tcp4_md5sig_key)); + } + tcp_free_md5sig_pool(); + return 0; + } + } + return -ENOENT; +} + +EXPORT_SYMBOL(tcp_v4_md5_do_del); + +static void tcp_v4_clear_md5_list (struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + + /* Free each key, then the set of key keys, + * the crypto element, and then decrement our + * hold on the last resort crypto. + */ + if (tp->md5sig_info->entries4) { + int i; + for (i = 0; i < tp->md5sig_info->entries4; i++) + kfree(tp->md5sig_info->keys4[i].key); + tp->md5sig_info->entries4 = 0; + tcp_free_md5sig_pool(); + } + if (tp->md5sig_info->keys4) { + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = NULL; + tp->md5sig_info->alloced4 = 0; + } +} + +static int tcp_v4_parse_md5_keys (struct sock *sk, char __user *optval, + int optlen) +{ + struct tcp_md5sig cmd; + struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; + u8 *newkey; + + if (optlen < sizeof(cmd)) + return -EINVAL; + + if (copy_from_user (&cmd, optval, sizeof(cmd))) + return -EFAULT; + + if (sin->sin_family != AF_INET) + return -EINVAL; + + if (!cmd.tcpm_key || !cmd.tcpm_keylen) { + if (!tcp_sk(sk)->md5sig_info) + return -ENOENT; + return tcp_v4_md5_do_del(sk, sin->sin_addr.s_addr); + } + + if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) + return -EINVAL; + + if (!tcp_sk(sk)->md5sig_info) { + struct tcp_sock *tp = tcp_sk(sk); + struct tcp_md5sig_info *p; + + p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL); + if (!p) + return -EINVAL; + + tp->md5sig_info = p; + + } + + newkey = kmalloc(cmd.tcpm_keylen, GFP_KERNEL); + if (!newkey) + return -ENOMEM; + memcpy(newkey, cmd.tcpm_key, cmd.tcpm_keylen); + return tcp_v4_md5_do_add(sk, sin->sin_addr.s_addr, + newkey, cmd.tcpm_keylen); +} + +static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + __be32 saddr, __be32 daddr, + struct tcphdr *th, int protocol, + int tcplen) +{ + struct scatterlist sg[4]; + __u16 data_len; + int block = 0; +#ifdef CONFIG_TCP_MD5SIG_DEBUG + int i; +#endif + __u16 old_checksum; + struct tcp_md5sig_pool *hp; + struct tcp4_pseudohdr *bp; + struct hash_desc *desc; + int err; + unsigned int nbytes = 0; + + /* + * Okay, so RFC2385 is turned on for this connection, + * so we need to generate the MD5 hash for the packet now. + */ + + hp = tcp_get_md5sig_pool(); + if (!hp) + goto clear_hash_noput; + + bp = &hp->md5_blk.ip4; + desc = &hp->md5_desc; + + /* + * 1. the TCP pseudo-header (in the order: source IP address, + * destination IP address, zero-padded protocol number, and + * segment length) + */ + bp->saddr = saddr; + bp->daddr = daddr; + bp->pad = 0; + bp->protocol = protocol; + bp->len = htons(tcplen); + sg_set_buf(&sg[block++], bp, sizeof(*bp)); + nbytes += sizeof(*bp); + +#ifdef CONFIG_TCP_MD5SIG_DEBUG + printk("Calcuating hash for: "); + for (i = 0; i < sizeof (*bp); i++) + printk ("%02x ", (unsigned int)((unsigned char *)bp)[i]); + printk(" "); +#endif + + /* 2. the TCP header, excluding options, and assuming a + * checksum of zero/ + */ + old_checksum = th->check; + th->check = 0; + sg_set_buf(&sg[block++], th, sizeof(struct tcphdr)); + nbytes += sizeof(struct tcphdr); +#ifdef CONFIG_TCP_MD5SIG_DEBUG + for (i = 0; i < sizeof (struct tcphdr); i++) + printk (" %02x", (unsigned int)((unsigned char *)th)[i]); +#endif + /* 3. the TCP segment data (if any) */ + data_len = tcplen - (th->doff << 2); + if (data_len > 0) { + unsigned char *data = (unsigned char *)th + (th->doff << 2); + sg_set_buf(&sg[block++], data, data_len); + nbytes += data_len; + } + + /* 4. an independently-specified key or password, known to both + * TCPs and presumably connection-specific + */ + sg_set_buf(&sg[block++], key->key, key->keylen); + nbytes += key->keylen; + +#ifdef CONFIG_TCP_MD5SIG_DEBUG + printk (" and password: "); + for (i = 0; i < key->keylen; i++) + printk ("%02x ", (unsigned int)key->key[i]); +#endif + + /* Now store the Hash into the packet */ + err = crypto_hash_init(desc); + if (err) + goto clear_hash; + err = crypto_hash_update(desc, sg, nbytes); + if (err) + goto clear_hash; + err = crypto_hash_final(desc, md5_hash); + if (err) + goto clear_hash; + + /* Reset header, and free up the crypto */ + tcp_put_md5sig_pool(); + th->check = old_checksum; + +out: +#ifdef CONFIG_TCP_MD5SIG_DEBUG + printk(" result:"); + for (i = 0; i < 16; i++) + printk (" %02x", (unsigned int)(((u8*)md5_hash)[i])); + printk("\n"); +#endif + return 0; +clear_hash: + tcp_put_md5sig_pool(); +clear_hash_noput: + memset(md5_hash, 0, 16); + goto out; +} + +int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + struct sock *sk, + struct dst_entry *dst, + struct request_sock *req, + struct tcphdr *th, int protocol, + int tcplen) +{ + __be32 saddr, daddr; + + if (sk) { + saddr = inet_sk(sk)->saddr; + daddr = inet_sk(sk)->daddr; + } else { + struct rtable *rt = (struct rtable *)dst; + BUG_ON(!rt); + saddr = rt->rt_src; + daddr = rt->rt_dst; + } + return tcp_v4_do_calc_md5_hash(md5_hash, key, + saddr, daddr, + th, protocol, tcplen); +} + +EXPORT_SYMBOL(tcp_v4_calc_md5_hash); + +static int tcp_v4_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) +{ + /* + * This gets called for each TCP segment that arrives + * so we want to be efficient. + * We have 3 drop cases: + * o No MD5 hash and one expected. + * o MD5 hash and we're not expecting one. + * o MD5 hash and its wrong. + */ + __u8 *hash_location = NULL; + struct tcp_md5sig_key *hash_expected; + struct iphdr *iph = skb->nh.iph; + struct tcphdr *th = skb->h.th; + int length = (th->doff << 2) - sizeof (struct tcphdr); + int genhash; + unsigned char *ptr; + unsigned char newhash[16]; + + hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); + + /* + * If the TCP option length is less than the TCP_MD5SIG + * option length, then we can shortcut + */ + if (length < TCPOLEN_MD5SIG) { + if (hash_expected) + return 1; + else + return 0; + } + + /* Okay, we can't shortcut - we have to grub through the options */ + ptr = (unsigned char *)(th + 1); + while (length > 0) { + int opcode = *ptr++; + int opsize; + + switch (opcode) { + case TCPOPT_EOL: + goto done_opts; + case TCPOPT_NOP: + length--; + continue; + default: + opsize = *ptr++; + if (opsize < 2) + goto done_opts; + if (opsize > length) + goto done_opts; + + if (opcode == TCPOPT_MD5SIG) { + hash_location = ptr; + goto done_opts; + } + } + ptr += opsize-2; + length -= opsize; + } +done_opts: + /* We've parsed the options - do we have a hash? */ + if (!hash_expected && !hash_location) + return 0; + + if (hash_expected && !hash_location) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash NOT expected but found " + "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", + NIPQUAD (iph->saddr), ntohs(th->source), + NIPQUAD (iph->daddr), ntohs(th->dest)); + } + return 1; + } + + if (!hash_expected && hash_location) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash NOT expected but found " + "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", + NIPQUAD (iph->saddr), ntohs(th->source), + NIPQUAD (iph->daddr), ntohs(th->dest)); + } + return 1; + } + + /* Okay, so this is hash_expected and hash_location - + * so we need to calculate the checksum. + */ + genhash = tcp_v4_do_calc_md5_hash(newhash, + hash_expected, + iph->saddr, iph->daddr, + th, sk->sk_protocol, + skb->len); + + if (genhash || memcmp(hash_location, newhash, 16) != 0) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash failed for " + "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)%s\n", + NIPQUAD (iph->saddr), ntohs(th->source), + NIPQUAD (iph->daddr), ntohs(th->dest), + genhash ? " tcp_v4_calc_md5_hash failed" : ""); +#ifdef CONFIG_TCP_MD5SIG_DEBUG + do { + int i; + printk("Received: "); + for (i = 0; i < 16; i++) + printk("%02x ", 0xff & (int)hash_location[i]); + printk("\n"); + printk("Calculated: "); + for (i = 0; i < 16; i++) + printk("%02x ", 0xff & (int)newhash[i]); + printk("\n"); + } while(0); +#endif + } + return 1; + } + return 0; +} + +#endif + struct request_sock_ops tcp_request_sock_ops __read_mostly = { .family = PF_INET, .obj_size = sizeof(struct tcp_request_sock), @@ -723,9 +1265,16 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { .send_reset = tcp_v4_send_reset, }; +struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v4_reqsk_md5_lookup, +#endif +}; + static struct timewait_sock_ops tcp_timewait_sock_ops = { .twsk_obj_size = sizeof(struct tcp_timewait_sock), .twsk_unique = tcp_twsk_unique, + .twsk_destructor= tcp_twsk_destructor, }; int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) @@ -773,6 +1322,10 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (!req) goto drop; +#ifdef CONFIG_TCP_MD5SIG + tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops; +#endif + tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = 536; tmp_opt.user_mss = tcp_sk(sk)->rx_opt.user_mss; @@ -891,6 +1444,9 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, struct inet_sock *newinet; struct tcp_sock *newtp; struct sock *newsk; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; +#endif if (sk_acceptq_is_full(sk)) goto exit_overflow; @@ -925,6 +1481,24 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newtp->advmss = dst_metric(dst, RTAX_ADVMSS); tcp_initialize_rcv_mss(newsk); +#ifdef CONFIG_TCP_MD5SIG + /* Copy over the MD5 key from the original socket */ + if ((key = tcp_v4_md5_do_lookup(sk, newinet->daddr)) != NULL) { + /* + * We're using one, so create a matching key + * on the newsk structure. If we fail to get + * memory, then we end up not copying the key + * across. Shucks. + */ + char *newkey = kmalloc(key->keylen, GFP_ATOMIC); + if (newkey) { + memcpy(newkey, key->key, key->keylen); + tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, + newkey, key->keylen); + } + } +#endif + __inet_hash(&tcp_hashinfo, newsk, 0); __inet_inherit_port(&tcp_hashinfo, sk, newsk); @@ -1000,10 +1574,24 @@ static int tcp_v4_checksum_init(struct sk_buff *skb) */ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) { + struct sock *rsk; +#ifdef CONFIG_TCP_MD5SIG + /* + * We really want to reject the packet as early as possible + * if: + * o We're expecting an MD5'd packet and this is no MD5 tcp option + * o There is an MD5 option and we're not expecting one + */ + if (tcp_v4_inbound_md5_hash (sk, skb)) + goto discard; +#endif + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ TCP_CHECK_TIMER(sk); - if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) + if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) { + rsk = sk; goto reset; + } TCP_CHECK_TIMER(sk); return 0; } @@ -1017,20 +1605,24 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) goto discard; if (nsk != sk) { - if (tcp_child_process(sk, nsk, skb)) + if (tcp_child_process(sk, nsk, skb)) { + rsk = nsk; goto reset; + } return 0; } } TCP_CHECK_TIMER(sk); - if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) + if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) { + rsk = sk; goto reset; + } TCP_CHECK_TIMER(sk); return 0; reset: - tcp_v4_send_reset(skb); + tcp_v4_send_reset(rsk, skb); discard: kfree_skb(skb); /* Be careful here. If this function gets more complicated and @@ -1139,7 +1731,7 @@ no_tcp_socket: bad_packet: TCP_INC_STATS_BH(TCP_MIB_INERRS); } else { - tcp_v4_send_reset(skb); + tcp_v4_send_reset(NULL, skb); } discard_it: @@ -1262,6 +1854,15 @@ struct inet_connection_sock_af_ops ipv4_specific = { #endif }; +struct tcp_sock_af_ops tcp_sock_ipv4_specific = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v4_md5_lookup, + .calc_md5_hash = tcp_v4_calc_md5_hash, + .md5_add = tcp_v4_md5_add_func, + .md5_parse = tcp_v4_parse_md5_keys, +#endif +}; + /* NOTE: A lot of things set to zero explicitly by call to * sk_alloc() so need not be done here. */ @@ -1301,6 +1902,9 @@ static int tcp_v4_init_sock(struct sock *sk) icsk->icsk_af_ops = &ipv4_specific; icsk->icsk_sync_mss = tcp_sync_mss; +#ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv4_specific; +#endif sk->sk_sndbuf = sysctl_tcp_wmem[1]; sk->sk_rcvbuf = sysctl_tcp_rmem[1]; @@ -1324,6 +1928,15 @@ int tcp_v4_destroy_sock(struct sock *sk) /* Cleans up our, hopefully empty, out_of_order_queue. */ __skb_queue_purge(&tp->out_of_order_queue); +#ifdef CONFIG_TCP_MD5SIG + /* Clean up the MD5 key list, if any */ + if (tp->md5sig_info) { + tcp_v4_clear_md5_list(sk); + kfree(tp->md5sig_info); + tp->md5sig_info = NULL; + } +#endif + #ifdef CONFIG_NET_DMA /* Cleans up our sk_async_wait_queue */ __skb_queue_purge(&sk->sk_async_wait_queue); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 0163d9826907..ac55d8892cf1 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -306,6 +306,28 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) tw->tw_ipv6only = np->ipv6only; } #endif + +#ifdef CONFIG_TCP_MD5SIG + /* + * The timewait bucket does not have the key DB from the + * sock structure. We just make a quick copy of the + * md5 key being used (if indeed we are using one) + * so the timewait ack generating code has the key. + */ + do { + struct tcp_md5sig_key *key; + memset(tcptw->tw_md5_key, 0, sizeof(tcptw->tw_md5_key)); + tcptw->tw_md5_keylen = 0; + key = tp->af_specific->md5_lookup(sk, sk); + if (key != NULL) { + memcpy(&tcptw->tw_md5_key, key->key, key->keylen); + tcptw->tw_md5_keylen = key->keylen; + if (tcp_alloc_md5sig_pool() == NULL) + BUG(); + } + } while(0); +#endif + /* Linkage updates. */ __inet_twsk_hashdance(tw, sk, &tcp_hashinfo); @@ -337,6 +359,17 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) tcp_done(sk); } +void tcp_twsk_destructor(struct sock *sk) +{ + struct tcp_timewait_sock *twsk = tcp_twsk(sk); +#ifdef CONFIG_TCP_MD5SIG + if (twsk->tw_md5_keylen) + tcp_put_md5sig_pool(); +#endif +} + +EXPORT_SYMBOL_GPL(tcp_twsk_destructor); + /* This is not only more efficient than what we used to do, it eliminates * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM * @@ -435,6 +468,11 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newtp->rx_opt.ts_recent_stamp = 0; newtp->tcp_header_len = sizeof(struct tcphdr); } +#ifdef CONFIG_TCP_MD5SIG + newtp->md5sig_info = NULL; /*XXX*/ + if (newtp->af_specific->md5_lookup(sk, newsk)) + newtp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; +#endif if (skb->len >= TCP_MIN_RCVMSS+newtp->tcp_header_len) newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len; newtp->rx_opt.mss_clamp = req->mss; @@ -617,6 +655,30 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, req, NULL); if (child == NULL) goto listen_overflow; +#ifdef CONFIG_TCP_MD5SIG + else { + /* Copy over the MD5 key from the original socket */ + struct tcp_md5sig_key *key; + struct tcp_sock *tp = tcp_sk(sk); + key = tp->af_specific->md5_lookup(sk, child); + if (key != NULL) { + /* + * We're using one, so create a matching key on the + * newsk structure. If we fail to get memory then we + * end up not copying the key across. Shucks. + */ + char *newkey = kmalloc(key->keylen, GFP_ATOMIC); + if (newkey) { + if (!tcp_alloc_md5sig_pool()) + BUG(); + memcpy(newkey, key->key, key->keylen); + tp->af_specific->md5_add(child, child, + newkey, + key->keylen); + } + } + } +#endif inet_csk_reqsk_queue_unlink(sk, req, prev); inet_csk_reqsk_queue_removed(sk, req); @@ -633,7 +695,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, embryonic_reset: NET_INC_STATS_BH(LINUX_MIB_EMBRYONICRSTS); if (!(flg & TCP_FLAG_RST)) - req->rsk_ops->send_reset(skb); + req->rsk_ops->send_reset(sk, skb); inet_csk_reqsk_queue_drop(sk, req, prev); return NULL; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 6a8581ab9a23..32c1a972fa31 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -270,7 +270,7 @@ static u16 tcp_select_window(struct sock *sk) } static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, - __u32 tstamp) + __u32 tstamp, __u8 **md5_hash) { if (tp->rx_opt.tstamp_ok) { *ptr++ = htonl((TCPOPT_NOP << 24) | @@ -298,16 +298,29 @@ static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, tp->rx_opt.eff_sacks--; } } +#ifdef CONFIG_TCP_MD5SIG + if (md5_hash) { + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + *md5_hash = (__u8 *)ptr; + } +#endif } /* Construct a tcp options header for a SYN or SYN_ACK packet. * If this is every changed make sure to change the definition of * MAX_SYN_SIZE to match the new maximum number of options that you * can generate. + * + * Note - that with the RFC2385 TCP option, we make room for the + * 16 byte MD5 hash. This will be filled in later, so the pointer for the + * location to be filled is passed back up. */ static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, int offer_wscale, int wscale, __u32 tstamp, - __u32 ts_recent) + __u32 ts_recent, __u8 **md5_hash) { /* We always get an MSS option. * The option bytes which will be seen in normal data @@ -346,6 +359,20 @@ static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | (wscale)); +#ifdef CONFIG_TCP_MD5SIG + /* + * If MD5 is enabled, then we set the option, and include the size + * (always 18). The actual MD5 hash is added just before the + * packet is sent. + */ + if (md5_hash) { + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + *md5_hash = (__u8 *) ptr; + } +#endif } /* This routine actually transmits TCP packets queued in by @@ -366,6 +393,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, struct tcp_sock *tp; struct tcp_skb_cb *tcb; int tcp_header_size; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *md5; + __u8 *md5_hash_location; +#endif struct tcphdr *th; int sysctl_flags; int err; @@ -424,6 +455,16 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, if (tcp_packets_in_flight(tp) == 0) tcp_ca_event(sk, CA_EVENT_TX_START); +#ifdef CONFIG_TCP_MD5SIG + /* + * Are we doing MD5 on this segment? If so - make + * room for it. + */ + md5 = tp->af_specific->md5_lookup(sk, sk); + if (md5) + tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; +#endif + th = (struct tcphdr *) skb_push(skb, tcp_header_size); skb->h.th = th; @@ -460,13 +501,34 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, (sysctl_flags & SYSCTL_FLAG_WSCALE), tp->rx_opt.rcv_wscale, tcb->when, - tp->rx_opt.ts_recent); + tp->rx_opt.ts_recent, + +#ifdef CONFIG_TCP_MD5SIG + md5 ? &md5_hash_location : +#endif + NULL); } else { tcp_build_and_update_options((__be32 *)(th + 1), - tp, tcb->when); + tp, tcb->when, +#ifdef CONFIG_TCP_MD5SIG + md5 ? &md5_hash_location : +#endif + NULL); TCP_ECN_send(sk, tp, skb, tcp_header_size); } +#ifdef CONFIG_TCP_MD5SIG + /* Calculate the MD5 hash, as we have all we need now */ + if (md5) { + tp->af_specific->calc_md5_hash(md5_hash_location, + md5, + sk, NULL, NULL, + skb->h.th, + sk->sk_protocol, + skb->len); + } +#endif + icsk->icsk_af_ops->send_check(sk, skb->len, skb); if (likely(tcb->flags & TCPCB_FLAG_ACK)) @@ -840,6 +902,11 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed) mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK)); +#ifdef CONFIG_TCP_MD5SIG + if (tp->af_specific->md5_lookup(sk, sk)) + mss_now -= TCPOLEN_MD5SIG_ALIGNED; +#endif + xmit_size_goal = mss_now; if (doing_tso) { @@ -2033,6 +2100,10 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, struct tcphdr *th; int tcp_header_size; struct sk_buff *skb; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *md5; + __u8 *md5_hash_location; +#endif skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); if (skb == NULL) @@ -2048,6 +2119,13 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, (ireq->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) + /* SACK_PERM is in the place of NOP NOP of TS */ ((ireq->sack_ok && !ireq->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0)); + +#ifdef CONFIG_TCP_MD5SIG + /* Are we doing MD5 on this segment? If so - make room for it */ + md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); + if (md5) + tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; +#endif skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size); memset(th, 0, sizeof(struct tcphdr)); @@ -2085,11 +2163,29 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, TCP_SKB_CB(skb)->when, - req->ts_recent); + req->ts_recent, + ( +#ifdef CONFIG_TCP_MD5SIG + md5 ? &md5_hash_location : +#endif + NULL) + ); skb->csum = 0; th->doff = (tcp_header_size >> 2); TCP_INC_STATS(TCP_MIB_OUTSEGS); + +#ifdef CONFIG_TCP_MD5SIG + /* Okay, we have all we need - do the md5 hash if needed */ + if (md5) { + tp->af_specific->calc_md5_hash(md5_hash_location, + md5, + NULL, dst, req, + skb->h.th, sk->sk_protocol, + skb->len); + } +#endif + return skb; } @@ -2108,6 +2204,11 @@ static void tcp_connect_init(struct sock *sk) tp->tcp_header_len = sizeof(struct tcphdr) + (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); +#ifdef CONFIG_TCP_MD5SIG + if (tp->af_specific->md5_lookup(sk, sk) != NULL) + tp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; +#endif + /* If user gave his TCP_MAXSEG, record it to clamp */ if (tp->rx_opt.user_mss) tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 9a88395a7629..663d1d238014 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -66,10 +66,13 @@ #include #include +#include +#include + /* Socket used for sending RSTs and ACKs */ static struct socket *tcp6_socket; -static void tcp_v6_send_reset(struct sk_buff *skb); +static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req); static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb); @@ -78,6 +81,8 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); static struct inet_connection_sock_af_ops ipv6_mapped; static struct inet_connection_sock_af_ops ipv6_specific; +static struct tcp_sock_af_ops tcp_sock_ipv6_specific; +static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; static int tcp_v6_get_port(struct sock *sk, unsigned short snum) { @@ -208,6 +213,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, icsk->icsk_af_ops = &ipv6_mapped; sk->sk_backlog_rcv = tcp_v4_do_rcv; +#ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_mapped_specific; +#endif err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); @@ -215,6 +223,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, icsk->icsk_ext_hdr_len = exthdrlen; icsk->icsk_af_ops = &ipv6_specific; sk->sk_backlog_rcv = tcp_v6_do_rcv; +#ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_specific; +#endif goto failure; } else { ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF), @@ -518,6 +529,396 @@ static void tcp_v6_reqsk_destructor(struct request_sock *req) kfree_skb(inet6_rsk(req)->pktopts); } +#ifdef CONFIG_TCP_MD5SIG +static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, + struct in6_addr *addr) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + BUG_ON(tp == NULL); + + if (!tp->md5sig_info || !tp->md5sig_info->entries6) + return NULL; + + for (i = 0; i < tp->md5sig_info->entries6; i++) { + if (ipv6_addr_cmp(&tp->md5sig_info->keys6[i].addr, addr) == 0) + return (struct tcp_md5sig_key *)&tp->md5sig_info->keys6[i]; + } + return NULL; +} + +static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk, + struct sock *addr_sk) +{ + return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr); +} + +static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk, + struct request_sock *req) +{ + return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); +} + +static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer, + char *newkey, u8 newkeylen) +{ + /* Add key to the list */ + struct tcp6_md5sig_key *key; + struct tcp_sock *tp = tcp_sk(sk); + struct tcp6_md5sig_key *keys; + + key = (struct tcp6_md5sig_key*) tcp_v6_md5_do_lookup(sk, peer); + if (key) { + /* modify existing entry - just update that one */ + kfree(key->key); + key->key = newkey; + key->keylen = newkeylen; + } else { + /* reallocate new list if current one is full. */ + if (!tp->md5sig_info) { + tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC); + if (!tp->md5sig_info) { + kfree(newkey); + return -ENOMEM; + } + } + tcp_alloc_md5sig_pool(); + if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) { + keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) * + (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC); + + if (!keys) { + tcp_free_md5sig_pool(); + kfree(newkey); + return -ENOMEM; + } + + if (tp->md5sig_info->entries6) + memmove(keys, tp->md5sig_info->keys6, + (sizeof (tp->md5sig_info->keys6[0]) * + tp->md5sig_info->entries6)); + + kfree(tp->md5sig_info->keys6); + tp->md5sig_info->keys6 = keys; + tp->md5sig_info->alloced6++; + } + + ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr, + peer); + tp->md5sig_info->keys6[tp->md5sig_info->entries6].key = newkey; + tp->md5sig_info->keys6[tp->md5sig_info->entries6].keylen = newkeylen; + + tp->md5sig_info->entries6++; + } + return 0; +} + +static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk, + u8 *newkey, __u8 newkeylen) +{ + return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr, + newkey, newkeylen); +} + +static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + for (i = 0; i < tp->md5sig_info->entries6; i++) { + if (ipv6_addr_cmp(&tp->md5sig_info->keys6[i].addr, peer) == 0) { + /* Free the key */ + kfree(tp->md5sig_info->keys6[i].key); + tp->md5sig_info->entries6--; + + if (tp->md5sig_info->entries6 == 0) { + kfree(tp->md5sig_info->keys6); + tp->md5sig_info->keys6 = NULL; + + tcp_free_md5sig_pool(); + + return 0; + } else { + /* shrink the database */ + if (tp->md5sig_info->entries6 != i) + memmove(&tp->md5sig_info->keys6[i], + &tp->md5sig_info->keys6[i+1], + (tp->md5sig_info->entries6 - i) + * sizeof (tp->md5sig_info->keys6[0])); + } + } + } + return -ENOENT; +} + +static void tcp_v6_clear_md5_list (struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + if (tp->md5sig_info->entries6) { + for (i = 0; i < tp->md5sig_info->entries6; i++) + kfree(tp->md5sig_info->keys6[i].key); + tp->md5sig_info->entries6 = 0; + tcp_free_md5sig_pool(); + } + + kfree(tp->md5sig_info->keys6); + tp->md5sig_info->keys6 = NULL; + tp->md5sig_info->alloced6 = 0; + + if (tp->md5sig_info->entries4) { + for (i = 0; i < tp->md5sig_info->entries4; i++) + kfree(tp->md5sig_info->keys4[i].key); + tp->md5sig_info->entries4 = 0; + tcp_free_md5sig_pool(); + } + + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = NULL; + tp->md5sig_info->alloced4 = 0; +} + +static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, + int optlen) +{ + struct tcp_md5sig cmd; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; + u8 *newkey; + + if (optlen < sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, optval, sizeof(cmd))) + return -EFAULT; + + if (sin6->sin6_family != AF_INET6) + return -EINVAL; + + if (!cmd.tcpm_keylen) { + if (!tcp_sk(sk)->md5sig_info) + return -ENOENT; + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED) + return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]); + return tcp_v6_md5_do_del(sk, &sin6->sin6_addr); + } + + if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) + return -EINVAL; + + if (!tcp_sk(sk)->md5sig_info) { + struct tcp_sock *tp = tcp_sk(sk); + struct tcp_md5sig_info *p; + + p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL); + if (!p) + return -ENOMEM; + + tp->md5sig_info = p; + } + + newkey = kmalloc(cmd.tcpm_keylen, GFP_KERNEL); + if (!newkey) + return -ENOMEM; + memcpy(newkey, cmd.tcpm_key, cmd.tcpm_keylen); + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED) { + return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3], + newkey, cmd.tcpm_keylen); + } + return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); +} + +static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + struct in6_addr *saddr, + struct in6_addr *daddr, + struct tcphdr *th, int protocol, + int tcplen) +{ + struct scatterlist sg[4]; + __u16 data_len; + int block = 0; + __u16 cksum; + struct tcp_md5sig_pool *hp; + struct tcp6_pseudohdr *bp; + struct hash_desc *desc; + int err; + unsigned int nbytes = 0; + + hp = tcp_get_md5sig_pool(); + if (!hp) { + printk(KERN_WARNING "%s(): hash pool not found...\n", __FUNCTION__); + goto clear_hash_noput; + } + bp = &hp->md5_blk.ip6; + desc = &hp->md5_desc; + + /* 1. TCP pseudo-header (RFC2460) */ + ipv6_addr_copy(&bp->saddr, saddr); + ipv6_addr_copy(&bp->daddr, daddr); + bp->len = htonl(tcplen); + bp->protocol = htonl(protocol); + + sg_set_buf(&sg[block++], bp, sizeof(*bp)); + nbytes += sizeof(*bp); + + /* 2. TCP header, excluding options */ + cksum = th->check; + th->check = 0; + sg_set_buf(&sg[block++], th, sizeof(*th)); + nbytes += sizeof(*th); + + /* 3. TCP segment data (if any) */ + data_len = tcplen - (th->doff << 2); + if (data_len > 0) { + u8 *data = (u8 *)th + (th->doff << 2); + sg_set_buf(&sg[block++], data, data_len); + nbytes += data_len; + } + + /* 4. shared key */ + sg_set_buf(&sg[block++], key->key, key->keylen); + nbytes += key->keylen; + + /* Now store the hash into the packet */ + err = crypto_hash_init(desc); + if (err) { + printk(KERN_WARNING "%s(): hash_init failed\n", __FUNCTION__); + goto clear_hash; + } + err = crypto_hash_update(desc, sg, nbytes); + if (err) { + printk(KERN_WARNING "%s(): hash_update failed\n", __FUNCTION__); + goto clear_hash; + } + err = crypto_hash_final(desc, md5_hash); + if (err) { + printk(KERN_WARNING "%s(): hash_final failed\n", __FUNCTION__); + goto clear_hash; + } + + /* Reset header, and free up the crypto */ + tcp_put_md5sig_pool(); + th->check = cksum; +out: + return 0; +clear_hash: + tcp_put_md5sig_pool(); +clear_hash_noput: + memset(md5_hash, 0, 16); + goto out; +} + +static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + struct sock *sk, + struct dst_entry *dst, + struct request_sock *req, + struct tcphdr *th, int protocol, + int tcplen) +{ + struct in6_addr *saddr, *daddr; + + if (sk) { + saddr = &inet6_sk(sk)->saddr; + daddr = &inet6_sk(sk)->daddr; + } else { + saddr = &inet6_rsk(req)->loc_addr; + daddr = &inet6_rsk(req)->rmt_addr; + } + return tcp_v6_do_calc_md5_hash(md5_hash, key, + saddr, daddr, + th, protocol, tcplen); +} + +static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) +{ + __u8 *hash_location = NULL; + struct tcp_md5sig_key *hash_expected; + struct ipv6hdr *ip6h = skb->nh.ipv6h; + struct tcphdr *th = skb->h.th; + int length = (th->doff << 2) - sizeof (*th); + int genhash; + u8 *ptr; + u8 newhash[16]; + + hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); + + /* If the TCP option is too short, we can short cut */ + if (length < TCPOLEN_MD5SIG) + return hash_expected ? 1 : 0; + + /* parse options */ + ptr = (u8*)(th + 1); + while (length > 0) { + int opcode = *ptr++; + int opsize; + + switch(opcode) { + case TCPOPT_EOL: + goto done_opts; + case TCPOPT_NOP: + length--; + continue; + default: + opsize = *ptr++; + if (opsize < 2 || opsize > length) + goto done_opts; + if (opcode == TCPOPT_MD5SIG) { + hash_location = ptr; + goto done_opts; + } + } + ptr += opsize - 2; + length -= opsize; + } + +done_opts: + /* do we have a hash as expected? */ + if (!hash_expected) { + if (!hash_location) + return 0; + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash NOT expected but found " + "(" NIP6_FMT ", %u)->" + "(" NIP6_FMT ", %u)\n", + NIP6(ip6h->saddr), ntohs(th->source), + NIP6(ip6h->daddr), ntohs(th->dest)); + } + return 1; + } + + if (!hash_location) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash expected but NOT found " + "(" NIP6_FMT ", %u)->" + "(" NIP6_FMT ", %u)\n", + NIP6(ip6h->saddr), ntohs(th->source), + NIP6(ip6h->daddr), ntohs(th->dest)); + } + return 1; + } + + /* check the signature */ + genhash = tcp_v6_do_calc_md5_hash(newhash, + hash_expected, + &ip6h->saddr, &ip6h->daddr, + th, sk->sk_protocol, + skb->len); + if (genhash || memcmp(hash_location, newhash, 16) != 0) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash %s for " + "(" NIP6_FMT ", %u)->" + "(" NIP6_FMT ", %u)\n", + genhash ? "failed" : "mismatch", + NIP6(ip6h->saddr), ntohs(th->source), + NIP6(ip6h->daddr), ntohs(th->dest)); + } + return 1; + } + return 0; +} +#endif + static struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .family = AF_INET6, .obj_size = sizeof(struct tcp6_request_sock), @@ -527,9 +928,16 @@ static struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .send_reset = tcp_v6_send_reset }; +struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v6_reqsk_md5_lookup, +#endif +}; + static struct timewait_sock_ops tcp6_timewait_sock_ops = { .twsk_obj_size = sizeof(struct tcp6_timewait_sock), .twsk_unique = tcp_twsk_unique, + .twsk_destructor= tcp_twsk_destructor, }; static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) @@ -566,11 +974,15 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) return 0; } -static void tcp_v6_send_reset(struct sk_buff *skb) +static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) { struct tcphdr *th = skb->h.th, *t1; struct sk_buff *buff; struct flowi fl; + int tot_len = sizeof(*th); +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; +#endif if (th->rst) return; @@ -578,25 +990,35 @@ static void tcp_v6_send_reset(struct sk_buff *skb) if (!ipv6_unicast_destination(skb)) return; +#ifdef CONFIG_TCP_MD5SIG + if (sk) + key = tcp_v6_md5_do_lookup(sk, &skb->nh.ipv6h->daddr); + else + key = NULL; + + if (key) + tot_len += TCPOLEN_MD5SIG_ALIGNED; +#endif + /* * We need to grab some memory, and put together an RST, * and then put it into the queue to be sent. */ - buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr), + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, GFP_ATOMIC); if (buff == NULL) return; - skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr)); + skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); - t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr)); + t1 = (struct tcphdr *) skb_push(buff, tot_len); /* Swap the send and the receive. */ memset(t1, 0, sizeof(*t1)); t1->dest = th->source; t1->source = th->dest; - t1->doff = sizeof(*t1)/4; + t1->doff = tot_len / 4; t1->rst = 1; if(th->ack) { @@ -607,6 +1029,22 @@ static void tcp_v6_send_reset(struct sk_buff *skb) + skb->len - (th->doff<<2)); } +#ifdef CONFIG_TCP_MD5SIG + if (key) { + u32 *opt = (u32*)(t1 + 1); + opt[0] = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + tcp_v6_do_calc_md5_hash((__u8*)&opt[1], + key, + &skb->nh.ipv6h->daddr, + &skb->nh.ipv6h->saddr, + t1, IPPROTO_TCP, + tot_len); + } +#endif + buff->csum = csum_partial((char *)t1, sizeof(*t1), 0); memset(&fl, 0, sizeof(fl)); @@ -637,15 +1075,37 @@ static void tcp_v6_send_reset(struct sk_buff *skb) kfree_skb(buff); } -static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) +static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, + struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) { struct tcphdr *th = skb->h.th, *t1; struct sk_buff *buff; struct flowi fl; int tot_len = sizeof(struct tcphdr); + u32 *topt; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; + struct tcp_md5sig_key tw_key; +#endif + +#ifdef CONFIG_TCP_MD5SIG + if (!tw && skb->sk) { + key = tcp_v6_md5_do_lookup(skb->sk, &skb->nh.ipv6h->daddr); + } else if (tw && tw->tw_md5_keylen) { + tw_key.key = tw->tw_md5_key; + tw_key.keylen = tw->tw_md5_keylen; + key = &tw_key; + } else { + key = NULL; + } +#endif if (ts) tot_len += TCPOLEN_TSTAMP_ALIGNED; +#ifdef CONFIG_TCP_MD5SIG + if (key) + tot_len += TCPOLEN_MD5SIG_ALIGNED; +#endif buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, GFP_ATOMIC); @@ -665,15 +1125,29 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 t1->ack_seq = htonl(ack); t1->ack = 1; t1->window = htons(win); + + topt = (u32*)(t1 + 1); if (ts) { - u32 *ptr = (u32*)(t1 + 1); - *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); - *ptr++ = htonl(tcp_time_stamp); - *ptr = htonl(ts); + *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); + *topt++ = htonl(tcp_time_stamp); + *topt = htonl(ts); } +#ifdef CONFIG_TCP_MD5SIG + if (key) { + *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); + tcp_v6_do_calc_md5_hash((__u8 *)topt, + key, + &skb->nh.ipv6h->daddr, + &skb->nh.ipv6h->saddr, + t1, IPPROTO_TCP, + tot_len); + } +#endif + buff->csum = csum_partial((char *)t1, tot_len, 0); memset(&fl, 0, sizeof(fl)); @@ -704,9 +1178,9 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) { struct inet_timewait_sock *tw = inet_twsk(sk); - const struct tcp_timewait_sock *tcptw = tcp_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v6_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_ts_recent); @@ -715,7 +1189,7 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) { - tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); + tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); } @@ -786,6 +1260,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (req == NULL) goto drop; +#ifdef CONFIG_TCP_MD5SIG + tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops; +#endif + tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); tmp_opt.user_mss = tp->rx_opt.user_mss; @@ -844,6 +1322,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, struct tcp_sock *newtp; struct sock *newsk; struct ipv6_txoptions *opt; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; +#endif if (skb->protocol == htons(ETH_P_IP)) { /* @@ -874,6 +1355,10 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; newsk->sk_backlog_rcv = tcp_v4_do_rcv; +#ifdef CONFIG_TCP_MD5SIG + newtp->af_specific = &tcp_sock_ipv6_mapped_specific; +#endif + newnp->pktoptions = NULL; newnp->opt = NULL; newnp->mcast_oif = inet6_iif(skb); @@ -1008,6 +1493,23 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6; +#ifdef CONFIG_TCP_MD5SIG + /* Copy over the MD5 key from the original socket */ + if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) { + /* We're using one, so create a matching key + * on the newsk structure. If we fail to get + * memory, then we end up not copying the key + * across. Shucks. + */ + char *newkey = kmalloc(key->keylen, GFP_ATOMIC); + if (newkey) { + memcpy(newkey, key->key, key->keylen); + tcp_v6_md5_do_add(newsk, &inet6_sk(sk)->daddr, + newkey, key->keylen); + } + } +#endif + __inet6_hash(&tcp_hashinfo, newsk); inet_inherit_port(&tcp_hashinfo, sk, newsk); @@ -1067,6 +1569,11 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) if (skb->protocol == htons(ETH_P_IP)) return tcp_v4_do_rcv(sk, skb); +#ifdef CONFIG_TCP_MD5SIG + if (tcp_v6_inbound_md5_hash (sk, skb)) + goto discard; +#endif + if (sk_filter(sk, skb)) goto discard; @@ -1132,7 +1639,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) return 0; reset: - tcp_v6_send_reset(skb); + tcp_v6_send_reset(sk, skb); discard: if (opt_skb) __kfree_skb(opt_skb); @@ -1257,7 +1764,7 @@ no_tcp_socket: bad_packet: TCP_INC_STATS_BH(TCP_MIB_INERRS); } else { - tcp_v6_send_reset(skb); + tcp_v6_send_reset(NULL, skb); } discard_it: @@ -1336,6 +1843,15 @@ static struct inet_connection_sock_af_ops ipv6_specific = { #endif }; +static struct tcp_sock_af_ops tcp_sock_ipv6_specific = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v6_md5_lookup, + .calc_md5_hash = tcp_v6_calc_md5_hash, + .md5_add = tcp_v6_md5_add_func, + .md5_parse = tcp_v6_parse_md5_keys, +#endif +}; + /* * TCP over IPv4 via INET6 API */ @@ -1358,6 +1874,15 @@ static struct inet_connection_sock_af_ops ipv6_mapped = { #endif }; +static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v4_md5_lookup, + .calc_md5_hash = tcp_v4_calc_md5_hash, + .md5_add = tcp_v6_md5_add_func, + .md5_parse = tcp_v6_parse_md5_keys, +#endif +}; + /* NOTE: A lot of things set to zero explicitly by call to * sk_alloc() so need not be done here. */ @@ -1397,6 +1922,10 @@ static int tcp_v6_init_sock(struct sock *sk) sk->sk_write_space = sk_stream_write_space; sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); +#ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_specific; +#endif + sk->sk_sndbuf = sysctl_tcp_wmem[1]; sk->sk_rcvbuf = sysctl_tcp_rmem[1]; @@ -1407,6 +1936,11 @@ static int tcp_v6_init_sock(struct sock *sk) static int tcp_v6_destroy_sock(struct sock *sk) { +#ifdef CONFIG_TCP_MD5SIG + /* Clean up the MD5 key list */ + if (tcp_sk(sk)->md5sig_info) + tcp_v6_clear_md5_list(sk); +#endif tcp_v4_destroy_sock(sk); return inet6_destroy_sock(sk); } -- cgit v1.2.3 From 6051e2f4fb68fc8e5343db58fa680ece376f405c Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 14 Nov 2006 19:54:19 -0800 Subject: [IPv6] prefix: Convert RTM_NEWPREFIX notifications to use the new netlink api RTM_GETPREFIX is completely unused and is thus removed. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 -- net/core/rtnetlink.c | 1 - net/ipv6/addrconf.c | 30 ++++++++++++++---------------- security/selinux/nlmsgtab.c | 1 - 4 files changed, 14 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 3a18addaed4c..33b3d0ab3a91 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -81,8 +81,6 @@ enum { RTM_NEWPREFIX = 52, #define RTM_NEWPREFIX RTM_NEWPREFIX - RTM_GETPREFIX = 54, -#define RTM_GETPREFIX RTM_GETPREFIX RTM_GETMULTICAST = 58, #define RTM_GETMULTICAST RTM_GETMULTICAST diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 50d6cb40c6e3..0cb4d9e53a07 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -108,7 +108,6 @@ static const int rtm_min[RTM_NR_FAMILIES] = [RTM_FAM(RTM_NEWTCLASS)] = NLMSG_LENGTH(sizeof(struct tcmsg)), [RTM_FAM(RTM_NEWTFILTER)] = NLMSG_LENGTH(sizeof(struct tcmsg)), [RTM_FAM(RTM_NEWACTION)] = NLMSG_LENGTH(sizeof(struct tcamsg)), - [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 46cd941d296f..052f99eaf2ac 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3518,16 +3518,18 @@ static inline size_t inet6_prefix_nlmsg_size(void) } static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, - struct prefix_info *pinfo, u32 pid, u32 seq, - int event, unsigned int flags) + struct prefix_info *pinfo, u32 pid, u32 seq, + int event, unsigned int flags) { - struct prefixmsg *pmsg; - struct nlmsghdr *nlh; - unsigned char *b = skb->tail; + struct prefixmsg *pmsg; + struct nlmsghdr *nlh; struct prefix_cacheinfo ci; - nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*pmsg), flags); - pmsg = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, pid, seq, event, sizeof(*pmsg), flags); + if (nlh == NULL) + return -ENOBUFS; + + pmsg = nlmsg_data(nlh); pmsg->prefix_family = AF_INET6; pmsg->prefix_pad1 = 0; pmsg->prefix_pad2 = 0; @@ -3535,26 +3537,22 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, pmsg->prefix_len = pinfo->prefix_len; pmsg->prefix_type = pinfo->type; pmsg->prefix_pad3 = 0; - pmsg->prefix_flags = 0; if (pinfo->onlink) pmsg->prefix_flags |= IF_PREFIX_ONLINK; if (pinfo->autoconf) pmsg->prefix_flags |= IF_PREFIX_AUTOCONF; - RTA_PUT(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix); + NLA_PUT(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix); ci.preferred_time = ntohl(pinfo->prefered); ci.valid_time = ntohl(pinfo->valid); - RTA_PUT(skb, PREFIX_CACHEINFO, sizeof(ci), &ci); + NLA_PUT(skb, PREFIX_CACHEINFO, sizeof(ci), &ci); - nlh->nlmsg_len = skb->tail - b; - return skb->len; + return nlmsg_end(skb, nlh); -nlmsg_failure: -rtattr_failure: - skb_trim(skb, b - skb->data); - return -1; +nla_put_failure: + return nlmsg_cancel(skb, nlh); } static void inet6_prefix_notify(int event, struct inet6_dev *idev, diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index b8f4d25cf335..ccfe8755735e 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -60,7 +60,6 @@ static struct nlmsg_perm nlmsg_route_perms[] = { RTM_DELACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, { RTM_GETACTION, NETLINK_ROUTE_SOCKET__NLMSG_READ }, { RTM_NEWPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_READ }, { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, { RTM_GETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, -- cgit v1.2.3 From ba4e58eca8aa9473b44fdfd312f26c4a2e7798b3 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 27 Nov 2006 11:10:57 -0800 Subject: [NET]: Supporting UDP-Lite (RFC 3828) in Linux This is a revision of the previously submitted patch, which alters the way files are organized and compiled in the following manner: * UDP and UDP-Lite now use separate object files * source file dependencies resolved via header files net/ipv{4,6}/udp_impl.h * order of inclusion files in udp.c/udplite.c adapted accordingly [NET/IPv4]: Support for the UDP-Lite protocol (RFC 3828) This patch adds support for UDP-Lite to the IPv4 stack, provided as an extension to the existing UDPv4 code: * generic routines are all located in net/ipv4/udp.c * UDP-Lite specific routines are in net/ipv4/udplite.c * MIB/statistics support in /proc/net/snmp and /proc/net/udplite * shared API with extensions for partial checksum coverage [NET/IPv6]: Extension for UDP-Lite over IPv6 It extends the existing UDPv6 code base with support for UDP-Lite in the same manner as per UDPv4. In particular, * UDPv6 generic and shared code is in net/ipv6/udp.c * UDP-Litev6 specific extensions are in net/ipv6/udplite.c * MIB/statistics support in /proc/net/snmp6 and /proc/net/udplite6 * support for IPV6_ADDRFORM * aligned the coding style of protocol initialisation with af_inet6.c * made the error handling in udpv6_queue_rcv_skb consistent; to return `-1' on error on all error cases * consolidation of shared code [NET]: UDP-Lite Documentation and basic XFRM/Netfilter support The UDP-Lite patch further provides * API documentation for UDP-Lite * basic xfrm support * basic netfilter support for IPv4 and IPv6 (LOG target) Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- Documentation/networking/udplite.txt | 281 +++++++++++++++++++ include/linux/in.h | 1 + include/linux/socket.h | 1 + include/linux/udp.h | 12 + include/net/ipv6.h | 12 +- include/net/transp_v6.h | 2 + include/net/udp.h | 91 +++++- include/net/udplite.h | 149 ++++++++++ include/net/xfrm.h | 2 + net/ipv4/Makefile | 3 +- net/ipv4/af_inet.c | 8 +- net/ipv4/netfilter/ipt_LOG.c | 11 +- net/ipv4/proc.c | 13 + net/ipv4/udp.c | 518 ++++++++++++++++++++--------------- net/ipv4/udp_impl.h | 38 +++ net/ipv4/udplite.c | 119 ++++++++ net/ipv4/xfrm4_policy.c | 1 + net/ipv6/Makefile | 4 +- net/ipv6/af_inet6.c | 21 +- net/ipv6/ipv6_sockglue.c | 11 +- net/ipv6/netfilter/ip6t_LOG.c | 10 +- net/ipv6/proc.c | 11 + net/ipv6/udp.c | 361 +++++++++++++----------- net/ipv6/udp_impl.h | 34 +++ net/ipv6/udplite.c | 105 +++++++ net/ipv6/xfrm6_policy.c | 1 + net/netfilter/xt_multiport.c | 5 +- net/netfilter/xt_tcpudp.c | 20 +- 28 files changed, 1442 insertions(+), 403 deletions(-) create mode 100644 Documentation/networking/udplite.txt create mode 100644 include/net/udplite.h create mode 100644 net/ipv4/udp_impl.h create mode 100644 net/ipv4/udplite.c create mode 100644 net/ipv6/udp_impl.h create mode 100644 net/ipv6/udplite.c (limited to 'include/linux') diff --git a/Documentation/networking/udplite.txt b/Documentation/networking/udplite.txt new file mode 100644 index 000000000000..dd6f46b83dab --- /dev/null +++ b/Documentation/networking/udplite.txt @@ -0,0 +1,281 @@ + =========================================================================== + The UDP-Lite protocol (RFC 3828) + =========================================================================== + + + UDP-Lite is a Standards-Track IETF transport protocol whose characteristic + is a variable-length checksum. This has advantages for transport of multimedia + (video, VoIP) over wireless networks, as partly damaged packets can still be + fed into the codec instead of being discarded due to a failed checksum test. + + This file briefly describes the existing kernel support and the socket API. + For in-depth information, you can consult: + + o The UDP-Lite Homepage: http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/ + Fom here you can also download some example application source code. + + o The UDP-Lite HOWTO on + http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/files/UDP-Lite-HOWTO.txt + + o The Wireshark UDP-Lite WiKi (with capture files): + http://wiki.wireshark.org/Lightweight_User_Datagram_Protocol + + o The Protocol Spec, RFC 3828, http://www.ietf.org/rfc/rfc3828.txt + + + I) APPLICATIONS + + Several applications have been ported successfully to UDP-Lite. Ethereal + (now called wireshark) has UDP-Litev4/v6 support by default. The tarball on + + http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/files/udplite_linux.tar.gz + + has source code for several v4/v6 client-server and network testing examples. + + Porting applications to UDP-Lite is straightforward: only socket level and + IPPROTO need to be changed; senders additionally set the checksum coverage + length (default = header length = 8). Details are in the next section. + + + II) PROGRAMMING API + + UDP-Lite provides a connectionless, unreliable datagram service and hence + uses the same socket type as UDP. In fact, porting from UDP to UDP-Lite is + very easy: simply add `IPPROTO_UDPLITE' as the last argument of the socket(2) + call so that the statement looks like: + + s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE); + + or, respectively, + + s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE); + + With just the above change you are able to run UDP-Lite services or connect + to UDP-Lite servers. The kernel will assume that you are not interested in + using partial checksum coverage and so emulate UDP mode (full coverage). + + To make use of the partial checksum coverage facilities requires setting a + single socket option, which takes an integer specifying the coverage length: + + * Sender checksum coverage: UDPLITE_SEND_CSCOV + + For example, + + int val = 20; + setsockopt(s, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &val, sizeof(int)); + + sets the checksum coverage length to 20 bytes (12b data + 8b header). + Of each packet only the first 20 bytes (plus the pseudo-header) will be + checksummed. This is useful for RTP applications which have a 12-byte + base header. + + + * Receiver checksum coverage: UDPLITE_RECV_CSCOV + + This option is the receiver-side analogue. It is truly optional, i.e. not + required to enable traffic with partial checksum coverage. Its function is + that of a traffic filter: when enabled, it instructs the kernel to drop + all packets which have a coverage _less_ than this value. For example, if + RTP and UDP headers are to be protected, a receiver can enforce that only + packets with a minimum coverage of 20 are admitted: + + int min = 20; + setsockopt(s, SOL_UDPLITE, UDPLITE_RECV_CSCOV, &min, sizeof(int)); + + The calls to getsockopt(2) are analogous. Being an extension and not a stand- + alone protocol, all socket options known from UDP can be used in exactly the + same manner as before, e.g. UDP_CORK or UDP_ENCAP. + + A detailed discussion of UDP-Lite checksum coverage options is in section IV. + + + III) HEADER FILES + + The socket API requires support through header files in /usr/include: + + * /usr/include/netinet/in.h + to define IPPROTO_UDPLITE + + * /usr/include/netinet/udplite.h + for UDP-Lite header fields and protocol constants + + For testing purposes, the following can serve as a `mini' header file: + + #define IPPROTO_UDPLITE 136 + #define SOL_UDPLITE 136 + #define UDPLITE_SEND_CSCOV 10 + #define UDPLITE_RECV_CSCOV 11 + + Ready-made header files for various distros are in the UDP-Lite tarball. + + + IV) KERNEL BEHAVIOUR WITH REGARD TO THE VARIOUS SOCKET OPTIONS + + To enable debugging messages, the log level need to be set to 8, as most + messages use the KERN_DEBUG level (7). + + 1) Sender Socket Options + + If the sender specifies a value of 0 as coverage length, the module + assumes full coverage, transmits a packet with coverage length of 0 + and according checksum. If the sender specifies a coverage < 8 and + different from 0, the kernel assumes 8 as default value. Finally, + if the specified coverage length exceeds the packet length, the packet + length is used instead as coverage length. + + 2) Receiver Socket Options + + The receiver specifies the minimum value of the coverage length it + is willing to accept. A value of 0 here indicates that the receiver + always wants the whole of the packet covered. In this case, all + partially covered packets are dropped and an error is logged. + + It is not possible to specify illegal values (<0 and <8); in these + cases the default of 8 is assumed. + + All packets arriving with a coverage value less than the specified + threshold are discarded, these events are also logged. + + 3) Disabling the Checksum Computation + + On both sender and receiver, checksumming will always be performed + and can not be disabled using SO_NO_CHECK. Thus + + setsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK, ... ); + + will always will be ignored, while the value of + + getsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK, &value, ...); + + is meaningless (as in TCP). Packets with a zero checksum field are + illegal (cf. RFC 3828, sec. 3.1) will be silently discarded. + + 4) Fragmentation + + The checksum computation respects both buffersize and MTU. The size + of UDP-Lite packets is determined by the size of the send buffer. The + minimum size of the send buffer is 2048 (defined as SOCK_MIN_SNDBUF + in include/net/sock.h), the default value is configurable as + net.core.wmem_default or via setting the SO_SNDBUF socket(7) + option. The maximum upper bound for the send buffer is determined + by net.core.wmem_max. + + Given a payload size larger than the send buffer size, UDP-Lite will + split the payload into several individual packets, filling up the + send buffer size in each case. + + The precise value also depends on the interface MTU. The interface MTU, + in turn, may trigger IP fragmentation. In this case, the generated + UDP-Lite packet is split into several IP packets, of which only the + first one contains the L4 header. + + The send buffer size has implications on the checksum coverage length. + Consider the following example: + + Payload: 1536 bytes Send Buffer: 1024 bytes + MTU: 1500 bytes Coverage Length: 856 bytes + + UDP-Lite will ship the 1536 bytes in two separate packets: + + Packet 1: 1024 payload + 8 byte header + 20 byte IP header = 1052 bytes + Packet 2: 512 payload + 8 byte header + 20 byte IP header = 540 bytes + + The coverage packet covers the UDP-Lite header and 848 bytes of the + payload in the first packet, the second packet is fully covered. Note + that for the second packet, the coverage length exceeds the packet + length. The kernel always re-adjusts the coverage length to the packet + length in such cases. + + As an example of what happens when one UDP-Lite packet is split into + several tiny fragments, consider the following example. + + Payload: 1024 bytes Send buffer size: 1024 bytes + MTU: 300 bytes Coverage length: 575 bytes + + +-+-----------+--------------+--------------+--------------+ + |8| 272 | 280 | 280 | 280 | + +-+-----------+--------------+--------------+--------------+ + 280 560 840 1032 + ^ + *****checksum coverage************* + + The UDP-Lite module generates one 1032 byte packet (1024 + 8 byte + header). According to the interface MTU, these are split into 4 IP + packets (280 byte IP payload + 20 byte IP header). The kernel module + sums the contents of the entire first two packets, plus 15 bytes of + the last packet before releasing the fragments to the IP module. + + To see the analogous case for IPv6 fragmentation, consider a link + MTU of 1280 bytes and a write buffer of 3356 bytes. If the checksum + coverage is less than 1232 bytes (MTU minus IPv6/fragment header + lengths), only the first fragment needs to be considered. When using + larger checksum coverage lengths, each eligible fragment needs to be + checksummed. Suppose we have a checksum coverage of 3062. The buffer + of 3356 bytes will be split into the following fragments: + + Fragment 1: 1280 bytes carrying 1232 bytes of UDP-Lite data + Fragment 2: 1280 bytes carrying 1232 bytes of UDP-Lite data + Fragment 3: 948 bytes carrying 900 bytes of UDP-Lite data + + The first two fragments have to be checksummed in full, of the last + fragment only 598 (= 3062 - 2*1232) bytes are checksummed. + + While it is important that such cases are dealt with correctly, they + are (annoyingly) rare: UDP-Lite is designed for optimising multimedia + performance over wireless (or generally noisy) links and thus smaller + coverage lenghts are likely to be expected. + + + V) UDP-LITE RUNTIME STATISTICS AND THEIR MEANING + + Exceptional and error conditions are logged to syslog at the KERN_DEBUG + level. Live statistics about UDP-Lite are available in /proc/net/snmp + and can (with newer versions of netstat) be viewed using + + netstat -svu + + This displays UDP-Lite statistics variables, whose meaning is as follows. + + InDatagrams: Total number of received datagrams. + + NoPorts: Number of packets received to an unknown port. + These cases are counted separately (not as InErrors). + + InErrors: Number of erroneous UDP-Lite packets. Errors include: + * internal socket queue receive errors + * packet too short (less than 8 bytes or stated + coverage length exceeds received length) + * xfrm4_policy_check() returned with error + * application has specified larger min. coverage + length than that of incoming packet + * checksum coverage violated + * bad checksum + + OutDatagrams: Total number of sent datagrams. + + These statistics derive from the UDP MIB (RFC 2013). + + + VI) IPTABLES + + There is packet match support for UDP-Lite as well as support for the LOG target. + If you copy and paste the following line into /etc/protcols, + + udplite 136 UDP-Lite # UDP-Lite [RFC 3828] + + then + iptables -A INPUT -p udplite -j LOG + + will produce logging output to syslog. Dropping and rejecting packets also works. + + + VII) MAINTAINER ADDRESS + + The UDP-Lite patch was developed at + University of Aberdeen + Electronics Research Group + Department of Engineering + Fraser Noble Building + Aberdeen AB24 3UE; UK + The current maintainer is Gerrit Renker, . Initial + code was developed by William Stanislaus, . diff --git a/include/linux/in.h b/include/linux/in.h index 2619859f6e1b..1912e7c0bc26 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -45,6 +45,7 @@ enum { IPPROTO_COMP = 108, /* Compression Header protocol */ IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ + IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */ IPPROTO_RAW = 255, /* Raw IP packets */ IPPROTO_MAX diff --git a/include/linux/socket.h b/include/linux/socket.h index 361409094649..592b66679823 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -264,6 +264,7 @@ struct ucred { #define SOL_IPV6 41 #define SOL_ICMPV6 58 #define SOL_SCTP 132 +#define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */ #define SOL_RAW 255 #define SOL_IPX 256 #define SOL_AX25 257 diff --git a/include/linux/udp.h b/include/linux/udp.h index 014b41d1e308..564f3b050105 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -38,6 +38,7 @@ struct udphdr { #include #include +#define UDP_HTABLE_SIZE 128 struct udp_sock { /* inet_sock has to be the first member */ @@ -50,12 +51,23 @@ struct udp_sock { * when the socket is uncorked. */ __u16 len; /* total length of pending frames */ + /* + * Fields specific to UDP-Lite. + */ + __u16 pcslen; + __u16 pcrlen; +/* indicator bits used by pcflag: */ +#define UDPLITE_BIT 0x1 /* set by udplite proto init function */ +#define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */ +#define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */ + __u8 pcflag; /* marks socket as UDP-Lite if > 0 */ }; static inline struct udp_sock *udp_sk(const struct sock *sk) { return (struct udp_sock *)sk; } +#define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag) #endif diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 3c266ad99a02..9390649bbfec 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -158,9 +158,13 @@ DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); SNMP_INC_STATS_OFFSET_BH(icmpv6_statistics, field, _offset); \ }) DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6); -#define UDP6_INC_STATS(field) SNMP_INC_STATS(udp_stats_in6, field) -#define UDP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_stats_in6, field) -#define UDP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_stats_in6, field) +DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6); +#define UDP6_INC_STATS_BH(field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_BH(udplite_stats_in6, field); \ + else SNMP_INC_STATS_BH(udp_stats_in6, field); } while(0) +#define UDP6_INC_STATS_USER(field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field); \ + else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0) int snmp6_register_dev(struct inet6_dev *idev); int snmp6_unregister_dev(struct inet6_dev *idev); @@ -604,6 +608,8 @@ extern int tcp6_proc_init(void); extern void tcp6_proc_exit(void); extern int udp6_proc_init(void); extern void udp6_proc_exit(void); +extern int udplite6_proc_init(void); +extern void udplite6_proc_exit(void); extern int ipv6_misc_proc_init(void); extern void ipv6_misc_proc_exit(void); diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 61f724c1036f..409da3a9a455 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -11,6 +11,7 @@ extern struct proto rawv6_prot; extern struct proto udpv6_prot; +extern struct proto udplitev6_prot; extern struct proto tcpv6_prot; struct flowi; @@ -24,6 +25,7 @@ extern void ipv6_destopt_init(void); /* transport protocols */ extern void rawv6_init(void); extern void udpv6_init(void); +extern void udplitev6_init(void); extern void tcpv6_init(void); extern int udpv6_connect(struct sock *sk, diff --git a/include/net/udp.h b/include/net/udp.h index db0c05f67546..4f0626735ed3 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -26,9 +26,28 @@ #include #include #include +#include +#include #include -#define UDP_HTABLE_SIZE 128 +/** + * struct udp_skb_cb - UDP(-Lite) private variables + * + * @header: private variables used by IPv4/IPv6 + * @cscov: checksum coverage length (UDP-Lite only) + * @partial_cov: if set indicates partial csum coverage + */ +struct udp_skb_cb { + union { + struct inet_skb_parm h4; +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) + struct inet6_skb_parm h6; +#endif + } header; + __u16 cscov; + __u8 partial_cov; +}; +#define UDP_SKB_CB(__skb) ((struct udp_skb_cb *)((__skb)->cb)) extern struct hlist_head udp_hash[UDP_HTABLE_SIZE]; extern rwlock_t udp_hash_lock; @@ -47,6 +66,62 @@ extern struct proto udp_prot; struct sk_buff; +/* + * Generic checksumming routines for UDP(-Lite) v4 and v6 + */ +static inline u16 __udp_lib_checksum_complete(struct sk_buff *skb) +{ + if (! UDP_SKB_CB(skb)->partial_cov) + return __skb_checksum_complete(skb); + return csum_fold(skb_checksum(skb, 0, UDP_SKB_CB(skb)->cscov, + skb->csum)); +} + +static __inline__ int udp_lib_checksum_complete(struct sk_buff *skb) +{ + return skb->ip_summed != CHECKSUM_UNNECESSARY && + __udp_lib_checksum_complete(skb); +} + +/** + * udp_csum_outgoing - compute UDPv4/v6 checksum over fragments + * @sk: socket we are writing to + * @skb: sk_buff containing the filled-in UDP header + * (checksum field must be zeroed out) + */ +static inline u32 udp_csum_outgoing(struct sock *sk, struct sk_buff *skb) +{ + u32 csum = csum_partial(skb->h.raw, sizeof(struct udphdr), 0); + + skb_queue_walk(&sk->sk_write_queue, skb) { + csum = csum_add(csum, skb->csum); + } + return csum; +} + +/* hash routines shared between UDPv4/6 and UDP-Litev4/6 */ +static inline void udp_lib_hash(struct sock *sk) +{ + BUG(); +} + +static inline void udp_lib_unhash(struct sock *sk) +{ + write_lock_bh(&udp_hash_lock); + if (sk_del_node_init(sk)) { + inet_sk(sk)->num = 0; + sock_prot_dec_use(sk->sk_prot); + } + write_unlock_bh(&udp_hash_lock); +} + +static inline void udp_lib_close(struct sock *sk, long timeout) +{ + sk_common_release(sk); +} + + +/* net/ipv4/udp.c */ extern int udp_get_port(struct sock *sk, unsigned short snum, int (*saddr_cmp)(const struct sock *, const struct sock *)); extern void udp_err(struct sk_buff *, u32); @@ -61,21 +136,29 @@ extern unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait); DECLARE_SNMP_STAT(struct udp_mib, udp_statistics); -#define UDP_INC_STATS(field) SNMP_INC_STATS(udp_statistics, field) -#define UDP_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_statistics, field) -#define UDP_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_statistics, field) +/* + * SNMP statistics for UDP and UDP-Lite + */ +#define UDP_INC_STATS_USER(field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_USER(udplite_statistics, field); \ + else SNMP_INC_STATS_USER(udp_statistics, field); } while(0) +#define UDP_INC_STATS_BH(field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_BH(udplite_statistics, field); \ + else SNMP_INC_STATS_BH(udp_statistics, field); } while(0) /* /proc */ struct udp_seq_afinfo { struct module *owner; char *name; sa_family_t family; + struct hlist_head *hashtable; int (*seq_show) (struct seq_file *m, void *v); struct file_operations *seq_fops; }; struct udp_iter_state { sa_family_t family; + struct hlist_head *hashtable; int bucket; struct seq_operations seq_ops; }; diff --git a/include/net/udplite.h b/include/net/udplite.h new file mode 100644 index 000000000000..1473b3e49044 --- /dev/null +++ b/include/net/udplite.h @@ -0,0 +1,149 @@ +/* + * Definitions for the UDP-Lite (RFC 3828) code. + */ +#ifndef _UDPLITE_H +#define _UDPLITE_H + +/* UDP-Lite socket options */ +#define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */ +#define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */ + +extern struct proto udplite_prot; +extern struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; + +/* UDP-Lite does not have a standardized MIB yet, so we inherit from UDP */ +DECLARE_SNMP_STAT(struct udp_mib, udplite_statistics); + +/* + * Checksum computation is all in software, hence simpler getfrag. + */ +static __inline__ int udplite_getfrag(void *from, char *to, int offset, + int len, int odd, struct sk_buff *skb) +{ + return memcpy_fromiovecend(to, (struct iovec *) from, offset, len); +} + +/* Designate sk as UDP-Lite socket */ +static inline int udplite_sk_init(struct sock *sk) +{ + udp_sk(sk)->pcflag = UDPLITE_BIT; + return 0; +} + +/* + * Checksumming routines + */ +static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) +{ + u16 cscov; + + /* In UDPv4 a zero checksum means that the transmitter generated no + * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets + * with a zero checksum field are illegal. */ + if (uh->check == 0) { + LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: zeroed checksum field\n"); + return 1; + } + + UDP_SKB_CB(skb)->partial_cov = 0; + cscov = ntohs(uh->len); + + if (cscov == 0) /* Indicates that full coverage is required. */ + cscov = skb->len; + else if (cscov < 8 || cscov > skb->len) { + /* + * Coverage length violates RFC 3828: log and discard silently. + */ + LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: bad csum coverage %d/%d\n", + cscov, skb->len); + return 1; + + } else if (cscov < skb->len) + UDP_SKB_CB(skb)->partial_cov = 1; + + UDP_SKB_CB(skb)->cscov = cscov; + + /* + * There is no known NIC manufacturer supporting UDP-Lite yet, + * hence ip_summed is always (re-)set to CHECKSUM_NONE. + */ + skb->ip_summed = CHECKSUM_NONE; + + return 0; +} + +static __inline__ int udplite4_csum_init(struct sk_buff *skb, struct udphdr *uh) +{ + int rc = udplite_checksum_init(skb, uh); + + if (!rc) + skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, + skb->nh.iph->daddr, + skb->len, IPPROTO_UDPLITE, 0); + return rc; +} + +static __inline__ int udplite6_csum_init(struct sk_buff *skb, struct udphdr *uh) +{ + int rc = udplite_checksum_init(skb, uh); + + if (!rc) + skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr, + skb->len, IPPROTO_UDPLITE, 0); + return rc; +} + +static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) +{ + int cscov = up->len; + + /* + * Sender has set `partial coverage' option on UDP-Lite socket + */ + if (up->pcflag & UDPLITE_SEND_CC) { + if (up->pcslen < up->len) { + /* up->pcslen == 0 means that full coverage is required, + * partial coverage only if 0 < up->pcslen < up->len */ + if (0 < up->pcslen) { + cscov = up->pcslen; + } + uh->len = htons(up->pcslen); + } + /* + * NOTE: Causes for the error case `up->pcslen > up->len': + * (i) Application error (will not be penalized). + * (ii) Payload too big for send buffer: data is split + * into several packets, each with its own header. + * In this case (e.g. last segment), coverage may + * exceed packet length. + * Since packets with coverage length > packet length are + * illegal, we fall back to the defaults here. + */ + } + return cscov; +} + +static inline u32 udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) +{ + u32 csum = 0; + int off, len, cscov = udplite_sender_cscov(udp_sk(sk), skb->h.uh); + + skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ + + skb_queue_walk(&sk->sk_write_queue, skb) { + off = skb->h.raw - skb->data; + len = skb->len - off; + + csum = skb_checksum(skb, off, (cscov > len)? len : cscov, csum); + + if ((cscov -= len) <= 0) + break; + } + return csum; +} + +extern void udplite4_register(void); +extern int udplite_get_port(struct sock *sk, unsigned short snum, + int (*scmp)(const struct sock *, const struct sock *)); +#endif /* _UDPLITE_H */ diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 81c91e8a328f..3878a88ff618 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -468,6 +468,7 @@ __be16 xfrm_flowi_sport(struct flowi *fl) switch(fl->proto) { case IPPROTO_TCP: case IPPROTO_UDP: + case IPPROTO_UDPLITE: case IPPROTO_SCTP: port = fl->fl_ip_sport; break; @@ -493,6 +494,7 @@ __be16 xfrm_flowi_dport(struct flowi *fl) switch(fl->proto) { case IPPROTO_TCP: case IPPROTO_UDP: + case IPPROTO_UDPLITE: case IPPROTO_SCTP: port = fl->fl_ip_dport; break; diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 15645c51520c..7a068626feea 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -8,7 +8,8 @@ obj-y := route.o inetpeer.o protocol.o \ inet_timewait_sock.o inet_connection_sock.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ tcp_minisocks.o tcp_cong.o \ - datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ + datagram.o raw.o udp.o udplite.o \ + arp.o icmp.o devinet.o af_inet.o igmp.o \ sysctl_net_ipv4.o fib_frontend.o fib_semantics.o obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4a81d54a7569..8db39f7e3bf0 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -104,6 +104,7 @@ #include #include #include +#include #include #include #include @@ -1223,10 +1224,13 @@ static int __init init_ipv4_mibs(void) tcp_statistics[1] = alloc_percpu(struct tcp_mib); udp_statistics[0] = alloc_percpu(struct udp_mib); udp_statistics[1] = alloc_percpu(struct udp_mib); + udplite_statistics[0] = alloc_percpu(struct udp_mib); + udplite_statistics[1] = alloc_percpu(struct udp_mib); if (! (net_statistics[0] && net_statistics[1] && ip_statistics[0] && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] - && udp_statistics[0] && udp_statistics[1])) + && udp_statistics[0] && udp_statistics[1] + && udplite_statistics[0] && udplite_statistics[1] ) ) return -ENOMEM; (void) tcp_mib_init(); @@ -1313,6 +1317,8 @@ static int __init inet_init(void) /* Setup TCP slab cache for open requests. */ tcp_init(); + /* Add UDP-Lite (RFC 3828) */ + udplite4_register(); /* * Set the ICMP layer up diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 7dc820df8bc5..46eee64a11f6 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -171,11 +171,15 @@ static void dump_packet(const struct nf_loginfo *info, } break; } - case IPPROTO_UDP: { + case IPPROTO_UDP: + case IPPROTO_UDPLITE: { struct udphdr _udph, *uh; - /* Max length: 10 "PROTO=UDP " */ - printk("PROTO=UDP "); + if (ih->protocol == IPPROTO_UDP) + /* Max length: 10 "PROTO=UDP " */ + printk("PROTO=UDP " ); + else /* Max length: 14 "PROTO=UDPLITE " */ + printk("PROTO=UDPLITE "); if (ntohs(ih->frag_off) & IP_OFFSET) break; @@ -341,6 +345,7 @@ static void dump_packet(const struct nf_loginfo *info, /* IP: 40+46+6+11+127 = 230 */ /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ /* UDP: 10+max(25,20) = 35 */ + /* UDPLITE: 14+max(25,20) = 39 */ /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ /* ESP: 10+max(25)+15 = 50 */ /* AH: 9+max(25)+15 = 49 */ diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 9c6cbe3d9fb8..cd873da54cbe 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), atomic_read(&tcp_memory_allocated)); seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot)); + seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot)); seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot)); seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues, atomic_read(&ip_frag_mem)); @@ -304,6 +306,17 @@ static int snmp_seq_show(struct seq_file *seq, void *v) fold_field((void **) udp_statistics, snmp4_udp_list[i].entry)); + /* the UDP and UDP-Lite MIBs are the same */ + seq_puts(seq, "\nUdpLite:"); + for (i = 0; snmp4_udp_list[i].name != NULL; i++) + seq_printf(seq, " %s", snmp4_udp_list[i].name); + + seq_puts(seq, "\nUdpLite:"); + for (i = 0; snmp4_udp_list[i].name != NULL; i++) + seq_printf(seq, " %lu", + fold_field((void **) udplite_statistics, + snmp4_udp_list[i].entry) ); + seq_putc(seq, '\n'); return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9e1bd374875e..98ba75096175 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -92,22 +92,16 @@ #include #include #include -#include #include -#include -#include #include -#include #include #include #include -#include -#include #include #include -#include #include #include +#include "udp_impl.h" /* * Snmp MIB for the UDP layer @@ -120,26 +114,30 @@ DEFINE_RWLOCK(udp_hash_lock); static int udp_port_rover; -static inline int udp_lport_inuse(u16 num) +static inline int __udp_lib_lport_inuse(__be16 num, struct hlist_head udptable[]) { struct sock *sk; struct hlist_node *node; - sk_for_each(sk, node, &udp_hash[num & (UDP_HTABLE_SIZE - 1)]) + sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) if (inet_sk(sk)->num == num) return 1; return 0; } /** - * udp_get_port - common port lookup for IPv4 and IPv6 + * __udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 * * @sk: socket struct in question * @snum: port number to look up + * @udptable: hash list table, must be of UDP_HTABLE_SIZE + * @port_rover: pointer to record of last unallocated port * @saddr_comp: AF-dependent comparison of bound local IP addresses */ -int udp_get_port(struct sock *sk, unsigned short snum, - int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2)) +int __udp_lib_get_port(struct sock *sk, unsigned short snum, + struct hlist_head udptable[], int *port_rover, + int (*saddr_comp)(const struct sock *sk1, + const struct sock *sk2 ) ) { struct hlist_node *node; struct hlist_head *head; @@ -150,15 +148,15 @@ int udp_get_port(struct sock *sk, unsigned short snum, if (snum == 0) { int best_size_so_far, best, result, i; - if (udp_port_rover > sysctl_local_port_range[1] || - udp_port_rover < sysctl_local_port_range[0]) - udp_port_rover = sysctl_local_port_range[0]; + if (*port_rover > sysctl_local_port_range[1] || + *port_rover < sysctl_local_port_range[0]) + *port_rover = sysctl_local_port_range[0]; best_size_so_far = 32767; - best = result = udp_port_rover; + best = result = *port_rover; for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { int size; - head = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[result & (UDP_HTABLE_SIZE - 1)]; if (hlist_empty(head)) { if (result > sysctl_local_port_range[1]) result = sysctl_local_port_range[0] + @@ -179,15 +177,15 @@ int udp_get_port(struct sock *sk, unsigned short snum, result = sysctl_local_port_range[0] + ((result - sysctl_local_port_range[0]) & (UDP_HTABLE_SIZE - 1)); - if (!udp_lport_inuse(result)) + if (! __udp_lib_lport_inuse(result, udptable)) break; } if (i >= (1 << 16) / UDP_HTABLE_SIZE) goto fail; gotit: - udp_port_rover = snum = result; + *port_rover = snum = result; } else { - head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; sk_for_each(sk2, node, head) if (inet_sk(sk2)->num == snum && @@ -195,12 +193,12 @@ gotit: (!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && - (*saddr_cmp)(sk, sk2) ) + (*saddr_comp)(sk, sk2) ) goto fail; } inet_sk(sk)->num = snum; if (sk_unhashed(sk)) { - head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; sk_add_node(sk, head); sock_prot_inc_use(sk->sk_prot); } @@ -210,7 +208,13 @@ fail: return error; } -static inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) +__inline__ int udp_get_port(struct sock *sk, unsigned short snum, + int (*scmp)(const struct sock *, const struct sock *)) +{ + return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp); +} + +inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) { struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); @@ -224,34 +228,20 @@ static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); } - -static void udp_v4_hash(struct sock *sk) -{ - BUG(); -} - -static void udp_v4_unhash(struct sock *sk) -{ - write_lock_bh(&udp_hash_lock); - if (sk_del_node_init(sk)) { - inet_sk(sk)->num = 0; - sock_prot_dec_use(sk->sk_prot); - } - write_unlock_bh(&udp_hash_lock); -} - /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ -static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif) +static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport, + __be32 daddr, __be16 dport, + int dif, struct hlist_head udptable[]) { struct sock *sk, *result = NULL; struct hlist_node *node; unsigned short hnum = ntohs(dport); int badness = -1; - sk_for_each(sk, node, &udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]) { + read_lock(&udp_hash_lock); + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); if (inet->num == hnum && !ipv6_only_sock(sk)) { @@ -285,20 +275,10 @@ static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport, } } } - return result; -} - -static __inline__ struct sock *udp_v4_lookup(__be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif) -{ - struct sock *sk; - - read_lock(&udp_hash_lock); - sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif); - if (sk) - sock_hold(sk); + if (result) + sock_hold(result); read_unlock(&udp_hash_lock); - return sk; + return result; } static inline struct sock *udp_v4_mcast_next(struct sock *sk, @@ -340,7 +320,7 @@ found: * to find the appropriate port. */ -void udp_err(struct sk_buff *skb, u32 info) +void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) { struct inet_sock *inet; struct iphdr *iph = (struct iphdr*)skb->data; @@ -351,7 +331,8 @@ void udp_err(struct sk_buff *skb, u32 info) int harderr; int err; - sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); + sk = __udp4_lib_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, + skb->dev->ifindex, udptable ); if (sk == NULL) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; /* No socket for error */ @@ -405,6 +386,11 @@ out: sock_put(sk); } +__inline__ void udp_err(struct sk_buff *skb, u32 info) +{ + return __udp4_lib_err(skb, info, udp_hash); +} + /* * Throw away all pending data and cancel the corking. Socket is locked. */ @@ -419,16 +405,56 @@ static void udp_flush_pending_frames(struct sock *sk) } } +/** + * udp4_hwcsum_outgoing - handle outgoing HW checksumming + * @sk: socket we are sending on + * @skb: sk_buff containing the filled-in UDP header + * (checksum field must be zeroed out) + */ +static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, + __be32 src, __be32 dst, int len ) +{ + unsigned int csum = 0, offset; + struct udphdr *uh = skb->h.uh; + + if (skb_queue_len(&sk->sk_write_queue) == 1) { + /* + * Only one fragment on the socket. + */ + skb->csum = offsetof(struct udphdr, check); + uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); + } else { + /* + * HW-checksum won't work as there are two or more + * fragments on the socket so that all csums of sk_buffs + * should be together + */ + offset = skb->h.raw - skb->data; + skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + + skb->ip_summed = CHECKSUM_NONE; + + skb_queue_walk(&sk->sk_write_queue, skb) { + csum = csum_add(csum, skb->csum); + } + + uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); + if (uh->check == 0) + uh->check = -1; + } +} + /* * Push out all pending data as one UDP datagram. Socket is locked. */ -static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) +int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) { struct inet_sock *inet = inet_sk(sk); struct flowi *fl = &inet->cork.fl; struct sk_buff *skb; struct udphdr *uh; int err = 0; + u32 csum = 0; /* Grab the skbuff where UDP header space exists. */ if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) @@ -443,52 +469,28 @@ static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) uh->len = htons(up->len); uh->check = 0; - if (sk->sk_no_check == UDP_CSUM_NOXMIT) { + if (up->pcflag) /* UDP-Lite */ + csum = udplite_csum_outgoing(sk, skb); + + else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ + skb->ip_summed = CHECKSUM_NONE; goto send; - } - if (skb_queue_len(&sk->sk_write_queue) == 1) { - /* - * Only one fragment on the socket. - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - skb->csum = offsetof(struct udphdr, check); - uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, - up->len, IPPROTO_UDP, 0); - } else { - skb->csum = csum_partial((char *)uh, - sizeof(struct udphdr), skb->csum); - uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, - up->len, IPPROTO_UDP, skb->csum); - if (uh->check == 0) - uh->check = -1; - } - } else { - unsigned int csum = 0; - /* - * HW-checksum won't work as there are two or more - * fragments on the socket so that all csums of sk_buffs - * should be together. - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - int offset = (unsigned char *)uh - skb->data; - skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - skb->ip_summed = CHECKSUM_NONE; - } else { - skb->csum = csum_partial((char *)uh, - sizeof(struct udphdr), skb->csum); - } + udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); + goto send; + + } else /* `normal' UDP */ + csum = udp_csum_outgoing(sk, skb); + + /* add protocol-dependent pseudo-header */ + uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, + sk->sk_protocol, csum ); + if (uh->check == 0) + uh->check = -1; - skb_queue_walk(&sk->sk_write_queue, skb) { - csum = csum_add(csum, skb->csum); - } - uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, - up->len, IPPROTO_UDP, csum); - if (uh->check == 0) - uh->check = -1; - } send: err = ip_push_pending_frames(sk); out: @@ -497,12 +499,6 @@ out: return err; } - -static unsigned short udp_check(struct udphdr *uh, int len, __be32 saddr, __be32 daddr, unsigned long base) -{ - return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); -} - int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { @@ -516,8 +512,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, __be32 daddr, faddr, saddr; __be16 dport; u8 tos; - int err; + int err, is_udplite = up->pcflag; int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); if (len > 0xFFFF) return -EMSGSIZE; @@ -622,7 +619,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, { .daddr = faddr, .saddr = saddr, .tos = tos } }, - .proto = IPPROTO_UDP, + .proto = sk->sk_protocol, .uli_u = { .ports = { .sport = inet->sport, .dport = dport } } }; @@ -668,8 +665,9 @@ back_from_confirm: do_append_data: up->len += ulen; - err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), &ipc, rt, + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), &ipc, rt, corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); if (err) udp_flush_pending_frames(sk); @@ -684,7 +682,7 @@ out: if (free) kfree(ipc.opt); if (!err) { - UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); + UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); return len; } /* @@ -695,7 +693,7 @@ out: * seems like overkill. */ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); + UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); } return err; @@ -707,8 +705,8 @@ do_confirm: goto out; } -static int udp_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) +int udp_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags) { struct udp_sock *up = udp_sk(sk); int ret; @@ -795,29 +793,18 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) return(0); } -static __inline__ int __udp_checksum_complete(struct sk_buff *skb) -{ - return __skb_checksum_complete(skb); -} - -static __inline__ int udp_checksum_complete(struct sk_buff *skb) -{ - return skb->ip_summed != CHECKSUM_UNNECESSARY && - __udp_checksum_complete(skb); -} - /* * This should be easy, if there is something there we * return it, otherwise we block. */ -static int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len, int noblock, int flags, int *addr_len) +int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len) { struct inet_sock *inet = inet_sk(sk); struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; struct sk_buff *skb; - int copied, err; + int copied, err, copy_only, is_udplite = IS_UDPLITE(sk); /* * Check any passed addresses @@ -839,15 +826,25 @@ try_again: msg->msg_flags |= MSG_TRUNC; } - if (skb->ip_summed==CHECKSUM_UNNECESSARY) { - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, - copied); - } else if (msg->msg_flags&MSG_TRUNC) { - if (__udp_checksum_complete(skb)) + /* + * Decide whether to checksum and/or copy data. + * + * UDP: checksum may have been computed in HW, + * (re-)compute it if message is truncated. + * UDP-Lite: always needs to checksum, no HW support. + */ + copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY); + + if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { + if (__udp_lib_checksum_complete(skb)) goto csum_copy_err; - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, - copied); - } else { + copy_only = 1; + } + + if (copy_only) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); if (err == -EINVAL) @@ -880,7 +877,7 @@ out: return err; csum_copy_err: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); skb_kill_datagram(sk, skb, flags); @@ -912,11 +909,6 @@ int udp_disconnect(struct sock *sk, int flags) return 0; } -static void udp_close(struct sock *sk, long timeout) -{ - sk_common_release(sk); -} - /* return: * 1 if the the UDP system should process it * 0 if we should drop this packet @@ -1022,7 +1014,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) * Note that in the success and error cases, the skb is assumed to * have either been requeued or freed. */ -static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) { struct udp_sock *up = udp_sk(sk); int rc; @@ -1030,10 +1022,8 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) /* * Charge it to the socket, dropping if the queue is full. */ - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { - kfree_skb(skb); - return -1; - } + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; nf_reset(skb); if (up->encap_type) { @@ -1057,31 +1047,68 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) if (ret < 0) { /* process the ESP packet */ ret = xfrm4_rcv_encap(skb, up->encap_type); - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); return -ret; } /* FALLTHROUGH -- it's a UDP Packet */ } - if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { - if (__udp_checksum_complete(skb)) { - UDP_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return -1; + /* + * UDP-Lite specific tests, ignored on UDP sockets + */ + if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + /* + * MIB statistics other than incrementing the error count are + * disabled for the following two types of errors: these depend + * on the application settings, not on the functioning of the + * protocol stack as such. + * + * RFC 3828 here recommends (sec 3.3): "There should also be a + * way ... to ... at least let the receiving application block + * delivery of packets with coverage values less than a value + * provided by the application." + */ + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " + "%d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; } + /* The next case involves violating the min. coverage requested + * by the receiver. This is subtle: if receiver wants x and x is + * greater than the buffersize/MTU then receiver will complain + * that it wants x while sender emits packets of smaller size y. + * Therefore the above ...()->partial_cov statement is essential. + */ + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING + "UDPLITE: coverage %d too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } + } + + if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { + if (__udp_lib_checksum_complete(skb)) + goto drop; skb->ip_summed = CHECKSUM_UNNECESSARY; } if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { /* Note that an ENOMEM error is charged twice */ if (rc == -ENOMEM) - UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); - UDP_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return -1; + UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag); + goto drop; } - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); return 0; + +drop: + UDP_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag); + kfree_skb(skb); + return -1; } /* @@ -1090,14 +1117,16 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) * Note: called only from the BH handler context, * so we don't need to lock the hashes. */ -static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, - __be32 saddr, __be32 daddr) +static int __udp4_lib_mcast_deliver(struct sk_buff *skb, + struct udphdr *uh, + __be32 saddr, __be32 daddr, + struct hlist_head udptable[]) { struct sock *sk; int dif; read_lock(&udp_hash_lock); - sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); dif = skb->dev->ifindex; sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (sk) { @@ -1131,65 +1160,75 @@ static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, * Otherwise, csum completion requires chacksumming packet body, * including udp header and folding it to skb->csum. */ -static void udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, - unsigned short ulen, __be32 saddr, __be32 daddr) +static inline void udp4_csum_init(struct sk_buff *skb, struct udphdr *uh) { if (uh->check == 0) { skb->ip_summed = CHECKSUM_UNNECESSARY; } else if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) + if (!csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, + skb->len, IPPROTO_UDP, skb->csum )) skb->ip_summed = CHECKSUM_UNNECESSARY; } if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); + skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, + skb->nh.iph->daddr, + skb->len, IPPROTO_UDP, 0); /* Probably, we should checksum udp header (it should be in cache * in any case) and data in tiny packets (< rx copybreak). */ + + /* UDP = UDP-Lite with a non-partial checksum coverage */ + UDP_SKB_CB(skb)->partial_cov = 0; } /* * All we need to do is get the socket, and then do a checksum. */ -int udp_rcv(struct sk_buff *skb) +int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], + int is_udplite) { struct sock *sk; - struct udphdr *uh; + struct udphdr *uh = skb->h.uh; unsigned short ulen; struct rtable *rt = (struct rtable*)skb->dst; __be32 saddr = skb->nh.iph->saddr; __be32 daddr = skb->nh.iph->daddr; - int len = skb->len; /* - * Validate the packet and the UDP length. + * Validate the packet. */ if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto no_header; - - uh = skb->h.uh; + goto drop; /* No space for header. */ ulen = ntohs(uh->len); - - if (ulen > len || ulen < sizeof(*uh)) + if (ulen > skb->len) goto short_packet; - if (pskb_trim_rcsum(skb, ulen)) - goto short_packet; + if(! is_udplite ) { /* UDP validates ulen. */ + + if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) + goto short_packet; - udp_checksum_init(skb, uh, ulen, saddr, daddr); + udp4_csum_init(skb, uh); + + } else { /* UDP-Lite validates cscov. */ + if (udplite4_csum_init(skb, uh)) + goto csum_error; + } if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) - return udp_v4_mcast_deliver(skb, uh, saddr, daddr); + return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); - sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex); + sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest, + skb->dev->ifindex, udptable ); if (sk != NULL) { int ret = udp_queue_rcv_skb(sk, skb); sock_put(sk); /* a return value > 0 means to resubmit the input, but - * it it wants the return to be -protocol, or 0 + * it wants the return to be -protocol, or 0 */ if (ret > 0) return -ret; @@ -1201,10 +1240,10 @@ int udp_rcv(struct sk_buff *skb) nf_reset(skb); /* No socket. Drop packet silently, if checksum is wrong */ - if (udp_checksum_complete(skb)) + if (udp_lib_checksum_complete(skb)) goto csum_error; - UDP_INC_STATS_BH(UDP_MIB_NOPORTS); + UDP_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* @@ -1215,36 +1254,40 @@ int udp_rcv(struct sk_buff *skb) return(0); short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", + is_udplite? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), ulen, - len, + skb->len, NIPQUAD(daddr), ntohs(uh->dest)); -no_header: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return(0); + goto drop; csum_error: /* * RFC1122: OK. Discards the bad packet silently (as far as * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ - LIMIT_NETDEBUG(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", + is_udplite? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), NIPQUAD(daddr), ntohs(uh->dest), ulen); drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); kfree_skb(skb); return(0); } -static int udp_destroy_sock(struct sock *sk) +__inline__ int udp_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udp_hash, 0); +} + +int udp_destroy_sock(struct sock *sk) { lock_sock(sk); udp_flush_pending_frames(sk); @@ -1293,6 +1336,32 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, } break; + /* + * UDP-Lite's partial checksum coverage (RFC 3828). + */ + /* The sender sets actual checksum coverage length via this option. + * The case coverage > packet length is handled by send module. */ + case UDPLITE_SEND_CSCOV: + if (!up->pcflag) /* Disable the option on UDP sockets */ + return -ENOPROTOOPT; + if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ + val = 8; + up->pcslen = val; + up->pcflag |= UDPLITE_SEND_CC; + break; + + /* The receiver specifies a minimum checksum coverage value. To make + * sense, this should be set to at least 8 (as done below). If zero is + * used, this again means full checksum coverage. */ + case UDPLITE_RECV_CSCOV: + if (!up->pcflag) /* Disable the option on UDP sockets */ + return -ENOPROTOOPT; + if (val != 0 && val < 8) /* Avoid silly minimal values. */ + val = 8; + up->pcrlen = val; + up->pcflag |= UDPLITE_RECV_CC; + break; + default: err = -ENOPROTOOPT; break; @@ -1301,21 +1370,21 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, return err; } -static int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) { - if (level != SOL_UDP) - return ip_setsockopt(sk, level, optname, optval, optlen); - return do_udp_setsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_setsockopt(sk, level, optname, optval, optlen); + return ip_setsockopt(sk, level, optname, optval, optlen); } #ifdef CONFIG_COMPAT -static int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int compat_udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) { - if (level != SOL_UDP) - return compat_ip_setsockopt(sk, level, optname, optval, optlen); - return do_udp_setsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_setsockopt(sk, level, optname, optval, optlen); + return compat_ip_setsockopt(sk, level, optname, optval, optlen); } #endif @@ -1342,6 +1411,16 @@ static int do_udp_getsockopt(struct sock *sk, int level, int optname, val = up->encap_type; break; + /* The following two cannot be changed on UDP sockets, the return is + * always 0 (which corresponds to the full checksum coverage of UDP). */ + case UDPLITE_SEND_CSCOV: + val = up->pcslen; + break; + + case UDPLITE_RECV_CSCOV: + val = up->pcrlen; + break; + default: return -ENOPROTOOPT; }; @@ -1353,21 +1432,21 @@ static int do_udp_getsockopt(struct sock *sk, int level, int optname, return 0; } -static int udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) +int udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) { - if (level != SOL_UDP) - return ip_getsockopt(sk, level, optname, optval, optlen); - return do_udp_getsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_getsockopt(sk, level, optname, optval, optlen); + return ip_getsockopt(sk, level, optname, optval, optlen); } #ifdef CONFIG_COMPAT -static int compat_udp_getsockopt(struct sock *sk, int level, int optname, +int compat_udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level != SOL_UDP) - return compat_ip_getsockopt(sk, level, optname, optval, optlen); - return do_udp_getsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_getsockopt(sk, level, optname, optval, optlen); + return compat_ip_getsockopt(sk, level, optname, optval, optlen); } #endif /** @@ -1387,7 +1466,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) { unsigned int mask = datagram_poll(file, sock, wait); struct sock *sk = sock->sk; - + int is_lite = IS_UDPLITE(sk); + /* Check for false positives due to checksum errors */ if ( (mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) && @@ -1397,8 +1477,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) spin_lock_bh(&rcvq->lock); while ((skb = skb_peek(rcvq)) != NULL) { - if (udp_checksum_complete(skb)) { - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + if (udp_lib_checksum_complete(skb)) { + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite); __skb_unlink(skb, rcvq); kfree_skb(skb); } else { @@ -1420,7 +1500,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) struct proto udp_prot = { .name = "UDP", .owner = THIS_MODULE, - .close = udp_close, + .close = udp_lib_close, .connect = ip4_datagram_connect, .disconnect = udp_disconnect, .ioctl = udp_ioctl, @@ -1431,8 +1511,8 @@ struct proto udp_prot = { .recvmsg = udp_recvmsg, .sendpage = udp_sendpage, .backlog_rcv = udp_queue_rcv_skb, - .hash = udp_v4_hash, - .unhash = udp_v4_unhash, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, .get_port = udp_v4_get_port, .obj_size = sizeof(struct udp_sock), #ifdef CONFIG_COMPAT @@ -1451,7 +1531,7 @@ static struct sock *udp_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { struct hlist_node *node; - sk_for_each(sk, node, &udp_hash[state->bucket]) { + sk_for_each(sk, node, state->hashtable + state->bucket) { if (sk->sk_family == state->family) goto found; } @@ -1472,7 +1552,7 @@ try_again: } while (sk && sk->sk_family != state->family); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { - sk = sk_head(&udp_hash[state->bucket]); + sk = sk_head(state->hashtable + state->bucket); goto try_again; } return sk; @@ -1522,6 +1602,7 @@ static int udp_seq_open(struct inode *inode, struct file *file) if (!s) goto out; s->family = afinfo->family; + s->hashtable = afinfo->hashtable; s->seq_ops.start = udp_seq_start; s->seq_ops.next = udp_seq_next; s->seq_ops.show = afinfo->seq_show; @@ -1588,7 +1669,7 @@ static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) atomic_read(&sp->sk_refcnt), sp); } -static int udp4_seq_show(struct seq_file *seq, void *v) +int udp4_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) seq_printf(seq, "%-127s\n", @@ -1611,6 +1692,7 @@ static struct udp_seq_afinfo udp4_seq_afinfo = { .owner = THIS_MODULE, .name = "udp", .family = AF_INET, + .hashtable = udp_hash, .seq_show = udp4_seq_show, .seq_fops = &udp4_seq_fops, }; diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h new file mode 100644 index 000000000000..f6f4277ba6dc --- /dev/null +++ b/net/ipv4/udp_impl.h @@ -0,0 +1,38 @@ +#ifndef _UDP4_IMPL_H +#define _UDP4_IMPL_H +#include +#include +#include +#include + +extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); +extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); + +extern int __udp_lib_get_port(struct sock *sk, unsigned short snum, + struct hlist_head udptable[], int *port_rover, + int (*)(const struct sock*,const struct sock*)); +extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *); + + +extern int udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen); +extern int udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); + +#ifdef CONFIG_COMPAT +extern int compat_udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen); +extern int compat_udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +#endif +extern int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len); +extern int udp_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags); +extern int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); +extern int udp_destroy_sock(struct sock *sk); + +#ifdef CONFIG_PROC_FS +extern int udp4_seq_show(struct seq_file *seq, void *v); +#endif +#endif /* _UDP4_IMPL_H */ diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c new file mode 100644 index 000000000000..561de6d8c734 --- /dev/null +++ b/net/ipv4/udplite.c @@ -0,0 +1,119 @@ +/* + * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). + * + * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "udp_impl.h" +DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; + +struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; +static int udplite_port_rover; + +__inline__ int udplite_get_port(struct sock *sk, unsigned short p, + int (*c)(const struct sock *, const struct sock *)) +{ + return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c); +} + +static __inline__ int udplite_v4_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); +} + +__inline__ int udplite_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udplite_hash, 1); +} + +__inline__ void udplite_err(struct sk_buff *skb, u32 info) +{ + return __udp4_lib_err(skb, info, udplite_hash); +} + +static struct net_protocol udplite_protocol = { + .handler = udplite_rcv, + .err_handler = udplite_err, + .no_policy = 1, +}; + +struct proto udplite_prot = { + .name = "UDP-Lite", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip4_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udp_destroy_sock, + .setsockopt = udp_setsockopt, + .getsockopt = udp_getsockopt, + .sendmsg = udp_sendmsg, + .recvmsg = udp_recvmsg, + .sendpage = udp_sendpage, + .backlog_rcv = udp_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v4_get_port, + .obj_size = sizeof(struct udp_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udp_setsockopt, + .compat_getsockopt = compat_udp_getsockopt, +#endif +}; + +static struct inet_protosw udplite4_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplite_prot, + .ops = &inet_dgram_ops, + .capability = -1, + .no_check = 0, /* must checksum (RFC 3828) */ + .flags = INET_PROTOSW_PERMANENT, +}; + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite4_seq_fops; +static struct udp_seq_afinfo udplite4_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite", + .family = AF_INET, + .hashtable = udplite_hash, + .seq_show = udp4_seq_show, + .seq_fops = &udplite4_seq_fops, +}; +#endif + +void __init udplite4_register(void) +{ + if (proto_register(&udplite_prot, 1)) + goto out_register_err; + + if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) + goto out_unregister_proto; + + inet_register_protosw(&udplite4_protosw); + +#ifdef CONFIG_PROC_FS + if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ + printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__); +#endif + return; + +out_unregister_proto: + proto_unregister(&udplite_prot); +out_register_err: + printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __FUNCTION__); +} + +EXPORT_SYMBOL(udplite_hash); +EXPORT_SYMBOL(udplite_prot); +EXPORT_SYMBOL(udplite_get_port); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index da766234607b..d4107bb701b5 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -199,6 +199,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl) if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { switch (iph->protocol) { case IPPROTO_UDP: + case IPPROTO_UDPLITE: case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index addcc011bc01..8bacda109b7f 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -5,8 +5,8 @@ obj-$(CONFIG_IPV6) += ipv6.o ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ - route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \ - protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ + route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ + raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \ ip6_flowlabel.o ipv6_syms.o inet6_connection_sock.o diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 92bfccf62cb7..1eb1c7f261d4 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -737,8 +738,13 @@ static int __init init_ipv6_mibs(void) if (snmp6_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib), __alignof__(struct udp_mib)) < 0) goto err_udp_mib; + if (snmp6_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib), + __alignof__(struct udp_mib)) < 0) + goto err_udplite_mib; return 0; +err_udplite_mib: + snmp6_mib_free((void **)udp_stats_in6); err_udp_mib: snmp6_mib_free((void **)icmpv6_statistics); err_icmp_mib: @@ -753,6 +759,7 @@ static void cleanup_ipv6_mibs(void) snmp6_mib_free((void **)ipv6_statistics); snmp6_mib_free((void **)icmpv6_statistics); snmp6_mib_free((void **)udp_stats_in6); + snmp6_mib_free((void **)udplite_stats_in6); } static int __init inet6_init(void) @@ -780,10 +787,14 @@ static int __init inet6_init(void) if (err) goto out_unregister_tcp_proto; - err = proto_register(&rawv6_prot, 1); + err = proto_register(&udplitev6_prot, 1); if (err) goto out_unregister_udp_proto; + err = proto_register(&rawv6_prot, 1); + if (err) + goto out_unregister_udplite_proto; + /* Register the socket-side information for inet6_create. */ for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) @@ -837,6 +848,8 @@ static int __init inet6_init(void) goto proc_tcp6_fail; if (udp6_proc_init()) goto proc_udp6_fail; + if (udplite6_proc_init()) + goto proc_udplite6_fail; if (ipv6_misc_proc_init()) goto proc_misc6_fail; @@ -862,6 +875,7 @@ static int __init inet6_init(void) /* Init v6 transport protocols. */ udpv6_init(); + udplitev6_init(); tcpv6_init(); ipv6_packet_init(); @@ -879,6 +893,8 @@ proc_if6_fail: proc_anycast6_fail: ipv6_misc_proc_exit(); proc_misc6_fail: + udplite6_proc_exit(); +proc_udplite6_fail: udp6_proc_exit(); proc_udp6_fail: tcp6_proc_exit(); @@ -902,6 +918,8 @@ out_unregister_sock: sock_unregister(PF_INET6); out_unregister_raw_proto: proto_unregister(&rawv6_prot); +out_unregister_udplite_proto: + proto_unregister(&udplitev6_prot); out_unregister_udp_proto: proto_unregister(&udpv6_prot); out_unregister_tcp_proto: @@ -919,6 +937,7 @@ static void __exit inet6_exit(void) ac6_proc_exit(); ipv6_misc_proc_exit(); udp6_proc_exit(); + udplite6_proc_exit(); tcp6_proc_exit(); raw6_proc_exit(); #endif diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index de6b91981b30..1eafcfc95e81 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -239,6 +240,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, struct sk_buff *pktopt; if (sk->sk_protocol != IPPROTO_UDP && + sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) break; @@ -276,11 +278,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, sk->sk_family = PF_INET; tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); } else { + struct proto *prot = &udp_prot; + + if (sk->sk_protocol == IPPROTO_UDPLITE) + prot = &udplite_prot; local_bh_disable(); sock_prot_dec_use(sk->sk_prot); - sock_prot_inc_use(&udp_prot); + sock_prot_inc_use(prot); local_bh_enable(); - sk->sk_prot = &udp_prot; + sk->sk_prot = prot; sk->sk_socket->ops = &inet_dgram_ops; sk->sk_family = PF_INET; } @@ -813,6 +819,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && + sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) return -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 0cf537d30185..3cb6bb79cc05 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -270,11 +270,15 @@ static void dump_packet(const struct nf_loginfo *info, } break; } - case IPPROTO_UDP: { + case IPPROTO_UDP: + case IPPROTO_UDPLITE: { struct udphdr _udph, *uh; - /* Max length: 10 "PROTO=UDP " */ - printk("PROTO=UDP "); + if (currenthdr == IPPROTO_UDP) + /* Max length: 10 "PROTO=UDP " */ + printk("PROTO=UDP " ); + else /* Max length: 14 "PROTO=UDPLITE " */ + printk("PROTO=UDPLITE "); if (fragment) break; diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 4158d386b0aa..35249d8487bb 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -49,6 +49,8 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v) fold_prot_inuse(&tcpv6_prot)); seq_printf(seq, "UDP6: inuse %d\n", fold_prot_inuse(&udpv6_prot)); + seq_printf(seq, "UDPLITE6: inuse %d\n", + fold_prot_inuse(&udplitev6_prot)); seq_printf(seq, "RAW6: inuse %d\n", fold_prot_inuse(&rawv6_prot)); seq_printf(seq, "FRAG6: inuse %d memory %d\n", @@ -133,6 +135,14 @@ static struct snmp_mib snmp6_udp6_list[] = { SNMP_MIB_SENTINEL }; +static struct snmp_mib snmp6_udplite6_list[] = { + SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), + SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), + SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), + SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), + SNMP_MIB_SENTINEL +}; + static unsigned long fold_field(void *mib[], int offt) { @@ -167,6 +177,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list); snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list); snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list); + snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list); } return 0; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 886300d13a59..5a64027bf2fc 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -38,26 +38,18 @@ #include #include -#include -#include - -#include #include #include #include #include -#include -#include -#include #include -#include #include - #include #include #include #include +#include "udp_impl.h" DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; @@ -66,23 +58,9 @@ static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); } -static void udp_v6_hash(struct sock *sk) -{ - BUG(); -} - -static void udp_v6_unhash(struct sock *sk) -{ - write_lock_bh(&udp_hash_lock); - if (sk_del_node_init(sk)) { - inet_sk(sk)->num = 0; - sock_prot_dec_use(sk->sk_prot); - } - write_unlock_bh(&udp_hash_lock); -} - -static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, - struct in6_addr *daddr, u16 dport, int dif) +static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, + struct in6_addr *daddr, __be16 dport, + int dif, struct hlist_head udptable[]) { struct sock *sk, *result = NULL; struct hlist_node *node; @@ -90,7 +68,7 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, int badness = -1; read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]) { + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); if (inet->num == hnum && sk->sk_family == PF_INET6) { @@ -131,21 +109,12 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, return result; } -/* - * - */ - -static void udpv6_close(struct sock *sk, long timeout) -{ - sk_common_release(sk); -} - /* * This should be easy, if there is something there we * return it, otherwise we block. */ -static int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, +int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len) { @@ -153,7 +122,7 @@ static int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct inet_sock *inet = inet_sk(sk); struct sk_buff *skb; size_t copied; - int err; + int err, copy_only, is_udplite = IS_UDPLITE(sk); if (addr_len) *addr_len=sizeof(struct sockaddr_in6); @@ -172,15 +141,21 @@ try_again: msg->msg_flags |= MSG_TRUNC; } - if (skb->ip_summed==CHECKSUM_UNNECESSARY) { - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, - copied); - } else if (msg->msg_flags&MSG_TRUNC) { - if (__skb_checksum_complete(skb)) + /* + * Decide whether to checksum and/or copy data. + */ + copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY); + + if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { + if (__udp_lib_checksum_complete(skb)) goto csum_copy_err; - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, - copied); - } else { + copy_only = 1; + } + + if (copy_only) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); if (err == -EINVAL) goto csum_copy_err; @@ -231,14 +206,15 @@ csum_copy_err: skb_kill_datagram(sk, skb, flags); if (flags & MSG_DONTWAIT) { - UDP6_INC_STATS_USER(UDP_MIB_INERRORS); + UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); return -EAGAIN; } goto try_again; } -static void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) +void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __be32 info, + struct hlist_head udptable[] ) { struct ipv6_pinfo *np; struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; @@ -248,8 +224,8 @@ static void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct sock *sk; int err; - sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, inet6_iif(skb)); - + sk = __udp6_lib_lookup(daddr, uh->dest, + saddr, uh->source, inet6_iif(skb), udptable); if (sk == NULL) return; @@ -270,31 +246,55 @@ out: sock_put(sk); } -static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +static __inline__ void udpv6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, int type, + int code, int offset, __u32 info ) +{ + return __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); +} + +int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) { + struct udp_sock *up = udp_sk(sk); int rc; - if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { - kfree_skb(skb); - return -1; - } + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; - if (skb_checksum_complete(skb)) { - UDP6_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return 0; + /* + * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). + */ + if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" + " %d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; + } + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " + "too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } } + if (udp_lib_checksum_complete(skb)) + goto drop; + if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { /* Note that an ENOMEM error is charged twice */ if (rc == -ENOMEM) - UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); - UDP6_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return 0; + UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag); + goto drop; } - UDP6_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + UDP6_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); return 0; +drop: + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag); + kfree_skb(skb); + return -1; } static struct sock *udp_v6_mcast_next(struct sock *sk, @@ -338,15 +338,15 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, * Note: called only from the BH handler context, * so we don't need to lock the hashes. */ -static void udpv6_mcast_deliver(struct udphdr *uh, - struct in6_addr *saddr, struct in6_addr *daddr, - struct sk_buff *skb) +static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, + struct in6_addr *daddr, struct hlist_head udptable[]) { struct sock *sk, *sk2; + const struct udphdr *uh = skb->h.uh; int dif; read_lock(&udp_hash_lock); - sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); dif = inet6_iif(skb); sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (!sk) { @@ -364,9 +364,34 @@ static void udpv6_mcast_deliver(struct udphdr *uh, udpv6_queue_rcv_skb(sk, skb); out: read_unlock(&udp_hash_lock); + return 0; } -static int udpv6_rcv(struct sk_buff **pskb) +static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh) + +{ + if (uh->check == 0) { + /* RFC 2460 section 8.1 says that we SHOULD log + this error. Well, it is reasonable. + */ + LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); + return 1; + } + if (skb->ip_summed == CHECKSUM_COMPLETE && + !csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, + skb->len, IPPROTO_UDP, skb->csum )) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + if (skb->ip_summed != CHECKSUM_UNNECESSARY) + skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr, + skb->len, IPPROTO_UDP, 0); + + return (UDP_SKB_CB(skb)->partial_cov = 0); +} + +int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], + int is_udplite) { struct sk_buff *skb = *pskb; struct sock *sk; @@ -383,44 +408,39 @@ static int udpv6_rcv(struct sk_buff **pskb) uh = skb->h.uh; ulen = ntohs(uh->len); + if (ulen > skb->len) + goto short_packet; - /* Check for jumbo payload */ - if (ulen == 0) - ulen = skb->len; + if(! is_udplite ) { /* UDP validates ulen. */ - if (ulen > skb->len || ulen < sizeof(*uh)) - goto short_packet; + /* Check for jumbo payload */ + if (ulen == 0) + ulen = skb->len; - if (uh->check == 0) { - /* RFC 2460 section 8.1 says that we SHOULD log - this error. Well, it is reasonable. - */ - LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); - goto discard; - } + if (ulen < sizeof(*uh)) + goto short_packet; - if (ulen < skb->len) { - if (pskb_trim_rcsum(skb, ulen)) - goto discard; - saddr = &skb->nh.ipv6h->saddr; - daddr = &skb->nh.ipv6h->daddr; - uh = skb->h.uh; - } + if (ulen < skb->len) { + if (pskb_trim_rcsum(skb, ulen)) + goto short_packet; + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; + uh = skb->h.uh; + } - if (skb->ip_summed == CHECKSUM_COMPLETE && - !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; + if (udp6_csum_init(skb, uh)) + goto discard; - if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0); + } else { /* UDP-Lite validates cscov. */ + if (udplite6_csum_init(skb, uh)) + goto discard; + } /* * Multicast receive code */ - if (ipv6_addr_is_multicast(daddr)) { - udpv6_mcast_deliver(uh, saddr, daddr, skb); - return 0; - } + if (ipv6_addr_is_multicast(daddr)) + return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); /* Unicast */ @@ -428,15 +448,16 @@ static int udpv6_rcv(struct sk_buff **pskb) * check socket cache ... must talk to Alan about his plans * for sock caches... i'll skip this for now. */ - sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, inet6_iif(skb)); + sk = __udp6_lib_lookup(saddr, uh->source, + daddr, uh->dest, inet6_iif(skb), udptable); if (sk == NULL) { if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard; - if (skb_checksum_complete(skb)) + if (udp_lib_checksum_complete(skb)) goto discard; - UDP6_INC_STATS_BH(UDP_MIB_NOPORTS); + UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); @@ -451,14 +472,20 @@ static int udpv6_rcv(struct sk_buff **pskb) return(0); short_packet: - if (net_ratelimit()) - printk(KERN_DEBUG "UDP: short packet: %d/%u\n", ulen, skb->len); + LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", + is_udplite? "-Lite" : "", ulen, skb->len); discard: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS); + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); kfree_skb(skb); return(0); } + +static __inline__ int udpv6_rcv(struct sk_buff **pskb) +{ + return __udp6_lib_rcv(pskb, udp_hash, 0); +} + /* * Throw away all pending data and cancel the corking. Socket is locked. */ @@ -484,6 +511,7 @@ static int udp_v6_push_pending_frames(struct sock *sk, struct udp_sock *up) struct inet_sock *inet = inet_sk(sk); struct flowi *fl = &inet->cork.fl; int err = 0; + u32 csum = 0; /* Grab the skbuff where UDP header space exists. */ if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) @@ -498,35 +526,17 @@ static int udp_v6_push_pending_frames(struct sock *sk, struct udp_sock *up) uh->len = htons(up->len); uh->check = 0; - if (sk->sk_no_check == UDP_CSUM_NOXMIT) { - skb->ip_summed = CHECKSUM_NONE; - goto send; - } - - if (skb_queue_len(&sk->sk_write_queue) == 1) { - skb->csum = csum_partial((char *)uh, - sizeof(struct udphdr), skb->csum); - uh->check = csum_ipv6_magic(&fl->fl6_src, - &fl->fl6_dst, - up->len, fl->proto, skb->csum); - } else { - u32 tmp_csum = 0; - - skb_queue_walk(&sk->sk_write_queue, skb) { - tmp_csum = csum_add(tmp_csum, skb->csum); - } - tmp_csum = csum_partial((char *)uh, - sizeof(struct udphdr), tmp_csum); - tmp_csum = csum_ipv6_magic(&fl->fl6_src, - &fl->fl6_dst, - up->len, fl->proto, tmp_csum); - uh->check = tmp_csum; + if (up->pcflag) + csum = udplite_csum_outgoing(sk, skb); + else + csum = udp_csum_outgoing(sk, skb); - } + /* add protocol-dependent pseudo-header */ + uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, + up->len, fl->proto, csum ); if (uh->check == 0) uh->check = -1; -send: err = ip6_push_pending_frames(sk); out: up->len = 0; @@ -534,7 +544,7 @@ out: return err; } -static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, +int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { struct ipv6_txoptions opt_space; @@ -554,6 +564,8 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; int err; int connected = 0; + int is_udplite = up->pcflag; + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); /* destination address check */ if (sin6) { @@ -694,7 +706,7 @@ do_udp_sendmsg: opt = fl6_merge_options(&opt_space, flowlabel, opt); opt = ipv6_fixup_options(&opt_space, opt); - fl.proto = IPPROTO_UDP; + fl.proto = sk->sk_protocol; ipv6_addr_copy(&fl.fl6_dst, daddr); if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) ipv6_addr_copy(&fl.fl6_src, &np->saddr); @@ -761,7 +773,8 @@ back_from_confirm: do_append_data: up->len += ulen; - err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, sizeof(struct udphdr), hlimit, tclass, opt, &fl, (struct rt6_info*)dst, corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); @@ -793,7 +806,7 @@ do_append_data: out: fl6_sock_release(flowlabel); if (!err) { - UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); + UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); return len; } /* @@ -804,7 +817,7 @@ out: * seems like overkill. */ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); + UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); } return err; @@ -816,7 +829,7 @@ do_confirm: goto out; } -static int udpv6_destroy_sock(struct sock *sk) +int udpv6_destroy_sock(struct sock *sk) { lock_sock(sk); udp_v6_flush_pending_frames(sk); @@ -854,7 +867,6 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, release_sock(sk); } break; - case UDP_ENCAP: switch (val) { case 0: @@ -866,6 +878,24 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, } break; + case UDPLITE_SEND_CSCOV: + if (!up->pcflag) /* Disable the option on UDP sockets */ + return -ENOPROTOOPT; + if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ + val = 8; + up->pcslen = val; + up->pcflag |= UDPLITE_SEND_CC; + break; + + case UDPLITE_RECV_CSCOV: + if (!up->pcflag) /* Disable the option on UDP sockets */ + return -ENOPROTOOPT; + if (val != 0 && val < 8) /* Avoid silly minimal values. */ + val = 8; + up->pcrlen = val; + up->pcflag |= UDPLITE_RECV_CC; + break; + default: err = -ENOPROTOOPT; break; @@ -874,22 +904,21 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, return err; } -static int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) { - if (level != SOL_UDP) - return ipv6_setsockopt(sk, level, optname, optval, optlen); - return do_udpv6_setsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udpv6_setsockopt(sk, level, optname, optval, optlen); + return ipv6_setsockopt(sk, level, optname, optval, optlen); } #ifdef CONFIG_COMPAT -static int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) { - if (level != SOL_UDP) - return compat_ipv6_setsockopt(sk, level, optname, - optval, optlen); - return do_udpv6_setsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udpv6_setsockopt(sk, level, optname, optval, optlen); + return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); } #endif @@ -916,6 +945,14 @@ static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, val = up->encap_type; break; + case UDPLITE_SEND_CSCOV: + val = up->pcslen; + break; + + case UDPLITE_RECV_CSCOV: + val = up->pcrlen; + break; + default: return -ENOPROTOOPT; }; @@ -927,22 +964,21 @@ static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, return 0; } -static int udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) +int udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) { - if (level != SOL_UDP) - return ipv6_getsockopt(sk, level, optname, optval, optlen); - return do_udpv6_getsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udpv6_getsockopt(sk, level, optname, optval, optlen); + return ipv6_getsockopt(sk, level, optname, optval, optlen); } #ifdef CONFIG_COMPAT -static int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) +int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) { - if (level != SOL_UDP) - return compat_ipv6_getsockopt(sk, level, optname, - optval, optlen); - return do_udpv6_getsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udpv6_getsockopt(sk, level, optname, optval, optlen); + return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); } #endif @@ -983,7 +1019,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket atomic_read(&sp->sk_refcnt), sp); } -static int udp6_seq_show(struct seq_file *seq, void *v) +int udp6_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) seq_printf(seq, @@ -1002,6 +1038,7 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { .owner = THIS_MODULE, .name = "udp6", .family = AF_INET6, + .hashtable = udp_hash, .seq_show = udp6_seq_show, .seq_fops = &udp6_seq_fops, }; @@ -1021,7 +1058,7 @@ void udp6_proc_exit(void) { struct proto udpv6_prot = { .name = "UDPv6", .owner = THIS_MODULE, - .close = udpv6_close, + .close = udp_lib_close, .connect = ip6_datagram_connect, .disconnect = udp_disconnect, .ioctl = udp_ioctl, @@ -1031,8 +1068,8 @@ struct proto udpv6_prot = { .sendmsg = udpv6_sendmsg, .recvmsg = udpv6_recvmsg, .backlog_rcv = udpv6_queue_rcv_skb, - .hash = udp_v6_hash, - .unhash = udp_v6_unhash, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, .get_port = udp_v6_get_port, .obj_size = sizeof(struct udp6_sock), #ifdef CONFIG_COMPAT diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h new file mode 100644 index 000000000000..ec9878899128 --- /dev/null +++ b/net/ipv6/udp_impl.h @@ -0,0 +1,34 @@ +#ifndef _UDP6_IMPL_H +#define _UDP6_IMPL_H +#include +#include +#include +#include +#include + +extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int ); +extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, + int , int , int , __be32 , struct hlist_head []); + +extern int udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +extern int udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen); +#ifdef CONFIG_COMPAT +extern int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen); +extern int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +#endif +extern int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len); +extern int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len, + int noblock, int flags, int *addr_len); +extern int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); +extern int udpv6_destroy_sock(struct sock *sk); + +#ifdef CONFIG_PROC_FS +extern int udp6_seq_show(struct seq_file *seq, void *v); +#endif +#endif /* _UDP6_IMPL_H */ diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c new file mode 100644 index 000000000000..e0ec5e63004a --- /dev/null +++ b/net/ipv6/udplite.c @@ -0,0 +1,105 @@ +/* + * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. + * See also net/ipv4/udplite.c + * + * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "udp_impl.h" + +DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly; + +static __inline__ int udplitev6_rcv(struct sk_buff **pskb) +{ + return __udp6_lib_rcv(pskb, udplite_hash, 1); +} + +static __inline__ void udplitev6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info) +{ + return __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); +} + +static struct inet6_protocol udplitev6_protocol = { + .handler = udplitev6_rcv, + .err_handler = udplitev6_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + +static __inline__ int udplite_v6_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); +} + +struct proto udplitev6_prot = { + .name = "UDPLITEv6", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip6_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, + .sendmsg = udpv6_sendmsg, + .recvmsg = udpv6_recvmsg, + .backlog_rcv = udpv6_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v6_get_port, + .obj_size = sizeof(struct udp6_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udpv6_setsockopt, + .compat_getsockopt = compat_udpv6_getsockopt, +#endif +}; + +static struct inet_protosw udplite6_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplitev6_prot, + .ops = &inet6_dgram_ops, + .capability = -1, + .no_check = 0, + .flags = INET_PROTOSW_PERMANENT, +}; + +void __init udplitev6_init(void) +{ + if (inet6_add_protocol(&udplitev6_protocol, IPPROTO_UDPLITE) < 0) + printk(KERN_ERR "%s: Could not register.\n", __FUNCTION__); + + inet6_register_protosw(&udplite6_protosw); +} + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite6_seq_fops; +static struct udp_seq_afinfo udplite6_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite6", + .family = AF_INET6, + .hashtable = udplite_hash, + .seq_show = udp6_seq_show, + .seq_fops = &udplite6_seq_fops, +}; + +int __init udplite6_proc_init(void) +{ + return udp_proc_register(&udplite6_seq_afinfo); +} + +void udplite6_proc_exit(void) +{ + udp_proc_unregister(&udplite6_seq_afinfo); +} +#endif diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 2fba1f0739aa..8dffd4daae9c 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -274,6 +274,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl) break; case IPPROTO_UDP: + case IPPROTO_UDPLITE: case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c index b4293058c6ff..1602086c7fd6 100644 --- a/net/netfilter/xt_multiport.c +++ b/net/netfilter/xt_multiport.c @@ -1,5 +1,5 @@ -/* Kernel module to match one of a list of TCP/UDP/SCTP/DCCP ports: ports are in - the same place so we can treat them as equal. */ +/* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports: + ports are in the same place so we can treat them as equal. */ /* (C) 1999-2001 Paul `Rusty' Russell * (C) 2002-2004 Netfilter Core Team @@ -162,6 +162,7 @@ check(u_int16_t proto, { /* Must specify supported protocol, no unknown flags or bad count */ return (proto == IPPROTO_TCP || proto == IPPROTO_UDP + || proto == IPPROTO_UDPLITE || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP) && !(ip_invflags & XT_INV_PROTO) && (match_flags == XT_MULTIPORT_SOURCE diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c index e76a68e0bc66..46414b562a19 100644 --- a/net/netfilter/xt_tcpudp.c +++ b/net/netfilter/xt_tcpudp.c @@ -10,7 +10,7 @@ #include #include -MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6"); +MODULE_DESCRIPTION("x_tables match for TCP and UDP(-Lite), supports IPv4 and IPv6"); MODULE_LICENSE("GPL"); MODULE_ALIAS("xt_tcp"); MODULE_ALIAS("xt_udp"); @@ -234,6 +234,24 @@ static struct xt_match xt_tcpudp_match[] = { .proto = IPPROTO_UDP, .me = THIS_MODULE, }, + { + .name = "udplite", + .family = AF_INET, + .checkentry = udp_checkentry, + .match = udp_match, + .matchsize = sizeof(struct xt_udp), + .proto = IPPROTO_UDPLITE, + .me = THIS_MODULE, + }, + { + .name = "udplite", + .family = AF_INET6, + .checkentry = udp_checkentry, + .match = udp_match, + .matchsize = sizeof(struct xt_udp), + .proto = IPPROTO_UDPLITE, + .me = THIS_MODULE, + }, }; static int __init xt_tcpudp_init(void) -- cgit v1.2.3 From 714e85be3557222bc25f69c252326207c900a7db Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 20:51:49 -0800 Subject: [IPV6]: Assorted trivial endianness annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 14 ++++++++------ include/net/arp.h | 2 +- include/net/ip.h | 11 ++++++----- net/ipv4/af_inet.c | 6 +++--- net/ipv4/arp.c | 2 +- net/ipv4/cipso_ipv4.c | 8 ++++---- net/ipv4/devinet.c | 10 +++++----- net/ipv4/ip_output.c | 2 +- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/raw.c | 4 ++-- net/ipv4/route.c | 4 ++-- net/ipv4/syncookies.c | 18 +++++++++--------- net/ipv4/tcp_ipv4.c | 10 +++++----- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_timer.c | 2 +- 15 files changed, 50 insertions(+), 47 deletions(-) (limited to 'include/linux') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 5a0ab04627bc..c0f7aec331c2 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -124,12 +124,13 @@ static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa) * Check if a mask is acceptable. */ -static __inline__ int bad_mask(u32 mask, u32 addr) +static __inline__ int bad_mask(__be32 mask, __be32 addr) { + __u32 hmask; if (addr & (mask = ~mask)) return 1; - mask = ntohl(mask); - if (mask & (mask+1)) + hmask = ntohl(mask); + if (hmask & (hmask+1)) return 1; return 0; } @@ -190,11 +191,12 @@ static __inline__ __be32 inet_make_mask(int logmask) return 0; } -static __inline__ int inet_mask_len(__u32 mask) +static __inline__ int inet_mask_len(__be32 mask) { - if (!(mask = ntohl(mask))) + __u32 hmask = ntohl(mask); + if (!hmask) return 0; - return 32 - ffz(~mask); + return 32 - ffz(~hmask); } diff --git a/include/net/arp.h b/include/net/arp.h index 6a3d9a7d302b..f02664568600 100644 --- a/include/net/arp.h +++ b/include/net/arp.h @@ -16,7 +16,7 @@ extern void arp_send(int type, int ptype, __be32 dest_ip, struct net_device *dev, __be32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, unsigned char *th); extern int arp_bind_neighbour(struct dst_entry *dst); -extern int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir); +extern int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir); extern void arp_ifdown(struct net_device *dev); extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, diff --git a/include/net/ip.h b/include/net/ip.h index 949fa8683626..412e8114667d 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -123,7 +123,7 @@ extern int ip4_datagram_connect(struct sock *sk, * multicast packets. */ -static inline void ip_tr_mc_map(u32 addr, char *buf) +static inline void ip_tr_mc_map(__be32 addr, char *buf) { buf[0]=0xC0; buf[1]=0x00; @@ -238,9 +238,9 @@ static inline void ip_select_ident_more(struct iphdr *iph, struct dst_entry *dst * Map a multicast IP onto multicast MAC for type ethernet. */ -static inline void ip_eth_mc_map(u32 addr, char *buf) +static inline void ip_eth_mc_map(__be32 naddr, char *buf) { - addr=ntohl(addr); + __u32 addr=ntohl(naddr); buf[0]=0x01; buf[1]=0x00; buf[2]=0x5e; @@ -256,13 +256,14 @@ static inline void ip_eth_mc_map(u32 addr, char *buf) * Leave P_Key as 0 to be filled in by driver. */ -static inline void ip_ib_mc_map(u32 addr, char *buf) +static inline void ip_ib_mc_map(__be32 naddr, char *buf) { + __u32 addr; buf[0] = 0; /* Reserved */ buf[1] = 0xff; /* Multicast QPN */ buf[2] = 0xff; buf[3] = 0xff; - addr = ntohl(addr); + addr = ntohl(naddr); buf[4] = 0xff; buf[5] = 0x12; /* link local scope */ buf[6] = 0x40; /* IPv4 signature */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8db39f7e3bf0..1144900d37f6 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -644,7 +644,7 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr, sin->sin_port = inet->dport; sin->sin_addr.s_addr = inet->daddr; } else { - __u32 addr = inet->rcv_saddr; + __be32 addr = inet->rcv_saddr; if (!addr) addr = inet->saddr; sin->sin_port = inet->sport; @@ -995,8 +995,8 @@ static int inet_sk_reselect_saddr(struct sock *sk) struct inet_sock *inet = inet_sk(sk); int err; struct rtable *rt; - __u32 old_saddr = inet->saddr; - __u32 new_saddr; + __be32 old_saddr = inet->saddr; + __be32 new_saddr; __be32 daddr = inet->daddr; if (inet->opt && inet->opt->srr) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index cfb5d3de9c84..3981e8be9ab8 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -203,7 +203,7 @@ struct neigh_table arp_tbl = { .gc_thresh3 = 1024, }; -int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir) +int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) { switch (dev->type) { case ARPHRD_ETHER: diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 6460233407c7..c3a61ebbadef 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -966,7 +966,7 @@ static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, buf[0] = IPOPT_CIPSO; buf[1] = CIPSO_V4_HDR_LEN + len; - *(u32 *)&buf[2] = htonl(doi_def->doi); + *(__be32 *)&buf[2] = htonl(doi_def->doi); return 0; } @@ -1140,7 +1140,7 @@ int cipso_v4_validate(unsigned char **option) } rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *)&opt[2]))); + doi_def = cipso_v4_doi_getdef(ntohl(*((__be32 *)&opt[2]))); if (doi_def == NULL) { err_offset = 2; goto validate_return_locked; @@ -1370,7 +1370,7 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) if (ret_val == 0) return ret_val; - doi = ntohl(*(u32 *)&cipso_ptr[2]); + doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) { @@ -1436,7 +1436,7 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) return 0; - doi = ntohl(*(u32 *)&cipso_ptr[2]); + doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index f38cbbae0ae3..a1b356c8aa59 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -577,20 +577,20 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg * Determine a default network mask, based on the IP address. */ -static __inline__ int inet_abc_len(u32 addr) +static __inline__ int inet_abc_len(__be32 addr) { int rc = -1; /* Something else, probably a multicast. */ if (ZERONET(addr)) rc = 0; else { - addr = ntohl(addr); + __u32 haddr = ntohl(addr); - if (IN_CLASSA(addr)) + if (IN_CLASSA(haddr)) rc = 8; - else if (IN_CLASSB(addr)) + else if (IN_CLASSB(haddr)) rc = 16; - else if (IN_CLASSC(addr)) + else if (IN_CLASSC(haddr)) rc = 24; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index def32d8d3b06..90942a384a45 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -341,7 +341,7 @@ packet_routed: /* OK, we know where to send it, allocate and build IP header. */ iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); - *((__u16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); + *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); iph->tot_len = htons(skb->len); if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok) iph->frag_off = htons(IP_DF); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 4b132953bcc2..57d4bae6f080 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -355,7 +355,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) sin = (struct sockaddr_in *)msg->msg_name; if (sin) { sin->sin_family = AF_INET; - sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset); + sin->sin_addr.s_addr = *(__be32*)(skb->nh.raw + serr->addr_offset); sin->sin_port = serr->port; memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 5c31dead2bdc..a6c63bbd9ddb 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -854,8 +854,8 @@ static void raw_seq_stop(struct seq_file *seq, void *v) static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i) { struct inet_sock *inet = inet_sk(sp); - unsigned int dest = inet->daddr, - src = inet->rcv_saddr; + __be32 dest = inet->daddr, + src = inet->rcv_saddr; __u16 destp = 0, srcp = inet->num; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d7152b2b2c64..ee00b6506ab4 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -566,8 +566,8 @@ static inline u32 rt_score(struct rtable *rt) static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) { - return ((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | - (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) | + return ((__force u32)((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | + (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr)) | (fl1->mark ^ fl2->mark) | (*(u16 *)&fl1->nl_u.ip4_u.tos ^ *(u16 *)&fl2->nl_u.ip4_u.tos) | diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 661e0a4bca72..6b19530905af 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -35,23 +35,23 @@ module_init(init_syncookies); #define COOKIEBITS 24 /* Upper bits store count */ #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) -static u32 cookie_hash(u32 saddr, u32 daddr, u32 sport, u32 dport, +static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, u32 count, int c) { __u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS]; memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c])); - tmp[0] = saddr; - tmp[1] = daddr; - tmp[2] = (sport << 16) + dport; + tmp[0] = (__force u32)saddr; + tmp[1] = (__force u32)daddr; + tmp[2] = ((__force u32)sport << 16) + (__force u32)dport; tmp[3] = count; sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5); return tmp[17]; } -static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport, - __u16 dport, __u32 sseq, __u32 count, +static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport, + __be16 dport, __u32 sseq, __u32 count, __u32 data) { /* @@ -80,8 +80,8 @@ static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport, * "maxdiff" if the current (passed-in) "count". The return value * is (__u32)-1 if this test fails. */ -static __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, - __u16 sport, __u16 dport, __u32 sseq, +static __u32 check_tcp_syn_cookie(__u32 cookie, __be32 saddr, __be32 daddr, + __be16 sport, __be16 dport, __u32 sseq, __u32 count, __u32 maxdiff) { __u32 diff; @@ -220,7 +220,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, } ireq = inet_rsk(req); treq = tcp_rsk(req); - treq->rcv_isn = htonl(skb->h.th->seq) - 1; + treq->rcv_isn = ntohl(skb->h.th->seq) - 1; treq->snt_isn = cookie; req->mss = mss; ireq->rmt_port = skb->h.th->source; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 8c8e8112f98d..0ca8dead03b0 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -542,7 +542,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) struct { struct tcphdr th; #ifdef CONFIG_TCP_MD5SIG - u32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; + __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; #endif } rep; struct ip_reply_arg arg; @@ -618,9 +618,9 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, struct tcphdr *th = skb->h.th; struct { struct tcphdr th; - u32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) + __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) #ifdef CONFIG_TCP_MD5SIG - + (TCPOLEN_MD5SIG_ALIGNED >> 2) + + (TCPOLEN_MD5SIG_ALIGNED >> 2) #endif ]; } rep; @@ -2333,8 +2333,8 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) struct tcp_sock *tp = tcp_sk(sp); const struct inet_connection_sock *icsk = inet_csk(sp); struct inet_sock *inet = inet_sk(sp); - unsigned int dest = inet->daddr; - unsigned int src = inet->rcv_saddr; + __be32 dest = inet->daddr; + __be32 src = inet->rcv_saddr; __u16 destp = ntohs(inet->dport); __u16 srcp = ntohs(inet->sport); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 4a0ee901a888..383cb38461c5 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -493,7 +493,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, struct request_sock **prev) { struct tcphdr *th = skb->h.th; - u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); + __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); int paws_reject = 0; struct tcp_options_received tmp_opt; struct sock *child; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index fb09ade5897b..3355c276b611 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -297,7 +297,7 @@ static void tcp_retransmit_timer(struct sock *sk) if (net_ratelimit()) { struct inet_sock *inet = inet_sk(sk); printk(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n", - NIPQUAD(inet->daddr), htons(inet->dport), + NIPQUAD(inet->daddr), ntohs(inet->dport), inet->num, tp->snd_una, tp->snd_nxt); } #endif -- cgit v1.2.3 From b09b845ca6724c3bbdc00c0cb2313258c7189ca9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 20:52:19 -0800 Subject: [RANDOM]: Annotate random.h IP helpers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- drivers/char/random.c | 48 ++++++++++++++++++++++++------------------------ include/linux/random.h | 20 ++++++++++---------- 2 files changed, 34 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/random.c b/drivers/char/random.c index eb6b13f4211a..d40df30c2b10 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1466,8 +1466,8 @@ static __init int seqgen_init(void) late_initcall(seqgen_init); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -__u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, - __u16 sport, __u16 dport) +__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, + __be16 sport, __be16 dport) { struct timeval tv; __u32 seq; @@ -1479,10 +1479,10 @@ __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, */ memcpy(hash, saddr, 16); - hash[4]=(sport << 16) + dport; + hash[4]=((__force u16)sport << 16) + (__force u16)dport; memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); - seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK; + seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; seq += keyptr->count; do_gettimeofday(&tv); @@ -1496,7 +1496,7 @@ EXPORT_SYMBOL(secure_tcpv6_sequence_number); /* The code below is shamelessly stolen from secure_tcp_sequence_number(). * All blames to Andrey V. Savochkin . */ -__u32 secure_ip_id(__u32 daddr) +__u32 secure_ip_id(__be32 daddr) { struct keydata *keyptr; __u32 hash[4]; @@ -1508,7 +1508,7 @@ __u32 secure_ip_id(__u32 daddr) * The dest ip address is placed in the starting vector, * which is then hashed with random data. */ - hash[0] = daddr; + hash[0] = (__force __u32)daddr; hash[1] = keyptr->secret[9]; hash[2] = keyptr->secret[10]; hash[3] = keyptr->secret[11]; @@ -1518,8 +1518,8 @@ __u32 secure_ip_id(__u32 daddr) #ifdef CONFIG_INET -__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, - __u16 sport, __u16 dport) +__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) { struct timeval tv; __u32 seq; @@ -1532,9 +1532,9 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, * Note that the words are placed into the starting vector, which is * then mixed with a partial MD4 over random data. */ - hash[0]=saddr; - hash[1]=daddr; - hash[2]=(sport << 16) + dport; + hash[0]=(__force u32)saddr; + hash[1]=(__force u32)daddr; + hash[2]=((__force u16)sport << 16) + (__force u16)dport; hash[3]=keyptr->secret[11]; seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; @@ -1559,7 +1559,7 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, EXPORT_SYMBOL(secure_tcp_sequence_number); /* Generate secure starting point for ephemeral IPV4 transport port search */ -u32 secure_ipv4_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport) +u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) { struct keydata *keyptr = get_keyptr(); u32 hash[4]; @@ -1568,25 +1568,25 @@ u32 secure_ipv4_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport) * Pick a unique starting offset for each ephemeral port search * (saddr, daddr, dport) and 48bits of random data. */ - hash[0] = saddr; - hash[1] = daddr; - hash[2] = dport ^ keyptr->secret[10]; + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = (__force u32)dport ^ keyptr->secret[10]; hash[3] = keyptr->secret[11]; return half_md4_transform(hash, keyptr->secret); } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dport) +u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport) { struct keydata *keyptr = get_keyptr(); u32 hash[12]; memcpy(hash, saddr, 16); - hash[4] = dport; + hash[4] = (__force u32)dport; memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); - return twothirdsMD4Transform(daddr, hash); + return twothirdsMD4Transform((const __u32 *)daddr, hash); } #endif @@ -1595,17 +1595,17 @@ u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dpo * bit's 32-47 increase every key exchange * 0-31 hash(source, dest) */ -u64 secure_dccp_sequence_number(__u32 saddr, __u32 daddr, - __u16 sport, __u16 dport) +u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) { struct timeval tv; u64 seq; __u32 hash[4]; struct keydata *keyptr = get_keyptr(); - hash[0] = saddr; - hash[1] = daddr; - hash[2] = (sport << 16) + dport; + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = ((__force u16)sport << 16) + (__force u16)dport; hash[3] = keyptr->secret[11]; seq = half_md4_transform(hash, keyptr->secret); @@ -1641,7 +1641,7 @@ unsigned int get_random_int(void) * drain on it), and uses halfMD4Transform within the second. We * also mix it with jiffies and the PID: */ - return secure_ip_id(current->pid + jiffies); + return secure_ip_id((__force __be32)(current->pid + jiffies)); } /* diff --git a/include/linux/random.h b/include/linux/random.h index 0248b30e306d..01ad71033d65 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -51,16 +51,16 @@ extern void add_interrupt_randomness(int irq); extern void get_random_bytes(void *buf, int nbytes); void generate_random_uuid(unsigned char uuid_out[16]); -extern __u32 secure_ip_id(__u32 daddr); -extern u32 secure_ipv4_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport); -extern u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, - __u16 dport); -extern __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, - __u16 sport, __u16 dport); -extern __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, - __u16 sport, __u16 dport); -extern u64 secure_dccp_sequence_number(__u32 saddr, __u32 daddr, - __u16 sport, __u16 dport); +extern __u32 secure_ip_id(__be32 daddr); +extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport); +extern u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, + __be16 dport); +extern __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport); +extern __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, + __be16 sport, __be16 dport); +extern u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport); #ifndef MODULE extern struct file_operations random_fops, urandom_fops; -- cgit v1.2.3 From 42d224aa170a4f7446cea6c972d9302d524545e5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:11:08 -0800 Subject: [NETFILTER]: More trivial annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack_tftp.h | 2 +- net/ipv4/netfilter/ip_conntrack_amanda.c | 2 +- net/ipv4/netfilter/ip_conntrack_helper_h323.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tftp.h b/include/linux/netfilter_ipv4/ip_conntrack_tftp.h index cde9729aa173..a404fc0abf0e 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_tftp.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_tftp.h @@ -4,7 +4,7 @@ #define TFTP_PORT 69 struct tftphdr { - u_int16_t opcode; + __be16 opcode; }; #define TFTP_OPCODE_READ 1 diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index 6c7383a8e42b..7fca246615d5 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c @@ -180,7 +180,7 @@ static struct ip_conntrack_helper amanda_helper = { .help = help, .name = "amanda", - .tuple = { .src = { .u = { __constant_htons(10080) } }, + .tuple = { .src = { .u = { .udp = {.port = __constant_htons(10080) } } }, .dst = { .protonum = IPPROTO_UDP }, }, .mask = { .src = { .u = { 0xFFFF } }, diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index 6cb9070cd0bc..a06b340ea414 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -1153,7 +1153,7 @@ static struct ip_conntrack_helper ip_conntrack_helper_q931 = { .me = THIS_MODULE, .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ , .timeout = 240, - .tuple = {.src = {.u = {__constant_htons(Q931_PORT)}}, + .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(Q931_PORT)}}}, .dst = {.protonum = IPPROTO_TCP}}, .mask = {.src = {.u = {0xFFFF}}, .dst = {.protonum = 0xFF}}, @@ -1746,7 +1746,7 @@ static struct ip_conntrack_helper ip_conntrack_helper_ras = { .me = THIS_MODULE, .max_expected = 32, .timeout = 240, - .tuple = {.src = {.u = {__constant_htons(RAS_PORT)}}, + .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(RAS_PORT)}}}, .dst = {.protonum = IPPROTO_UDP}}, .mask = {.src = {.u = {0xFFFE}}, .dst = {.protonum = 0xFF}}, -- cgit v1.2.3 From 30d492da738a8d5f4ec884b3e1a13eef97714994 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:11:29 -0800 Subject: [ATM]: Annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/atmarp.h | 2 +- include/linux/atmbr2684.h | 4 ++-- include/linux/atmmpc.h | 16 ++++++++-------- include/net/atmclip.h | 2 +- net/atm/br2684.c | 2 +- net/atm/clip.c | 10 +++++----- net/atm/lec.c | 6 +++--- net/atm/lec.h | 6 +++--- net/atm/mpc.c | 26 +++++++++++++------------- net/atm/mpc.h | 6 +++--- net/atm/mpoa_caches.c | 14 +++++++------- net/atm/mpoa_caches.h | 16 ++++++++-------- net/atm/mpoa_proc.c | 6 +++--- 13 files changed, 58 insertions(+), 58 deletions(-) (limited to 'include/linux') diff --git a/include/linux/atmarp.h b/include/linux/atmarp.h index 24f82338f59a..ee108f9e9cb7 100644 --- a/include/linux/atmarp.h +++ b/include/linux/atmarp.h @@ -37,7 +37,7 @@ enum atmarp_ctrl_type { struct atmarp_ctrl { enum atmarp_ctrl_type type; /* message type */ int itf_num;/* interface number (if present) */ - uint32_t ip; /* IP address (act_need only) */ + __be32 ip; /* IP address (act_need only) */ }; #endif diff --git a/include/linux/atmbr2684.h b/include/linux/atmbr2684.h index 7981b733f1ef..969fb6c9e1cc 100644 --- a/include/linux/atmbr2684.h +++ b/include/linux/atmbr2684.h @@ -86,8 +86,8 @@ struct atm_backend_br2684 { * efficient per-if in/out filters, this support will be removed */ struct br2684_filter { - __u32 prefix; /* network byte order */ - __u32 netmask; /* 0 = disable filter */ + __be32 prefix; /* network byte order */ + __be32 netmask; /* 0 = disable filter */ }; struct br2684_filter_set { diff --git a/include/linux/atmmpc.h b/include/linux/atmmpc.h index 5fbfa68136d3..ea1650425a12 100644 --- a/include/linux/atmmpc.h +++ b/include/linux/atmmpc.h @@ -13,7 +13,7 @@ struct atmmpc_ioc { int dev_num; - uint32_t ipaddr; /* the IP address of the shortcut */ + __be32 ipaddr; /* the IP address of the shortcut */ int type; /* ingress or egress */ }; @@ -21,8 +21,8 @@ typedef struct in_ctrl_info { uint8_t Last_NHRP_CIE_code; uint8_t Last_Q2931_cause_value; uint8_t eg_MPC_ATM_addr[ATM_ESA_LEN]; - uint32_t tag; - uint32_t in_dst_ip; /* IP address this ingress MPC sends packets to */ + __be32 tag; + __be32 in_dst_ip; /* IP address this ingress MPC sends packets to */ uint16_t holding_time; uint32_t request_id; } in_ctrl_info; @@ -30,10 +30,10 @@ typedef struct in_ctrl_info { typedef struct eg_ctrl_info { uint8_t DLL_header[256]; uint8_t DH_length; - uint32_t cache_id; - uint32_t tag; - uint32_t mps_ip; - uint32_t eg_dst_ip; /* IP address to which ingress MPC sends packets */ + __be32 cache_id; + __be32 tag; + __be32 mps_ip; + __be32 eg_dst_ip; /* IP address to which ingress MPC sends packets */ uint8_t in_MPC_data_ATM_addr[ATM_ESA_LEN]; uint16_t holding_time; } eg_ctrl_info; @@ -49,7 +49,7 @@ struct mpc_parameters { struct k_message { uint16_t type; - uint32_t ip_mask; + __be32 ip_mask; uint8_t MPS_ctrl[ATM_ESA_LEN]; union { in_ctrl_info in_info; diff --git a/include/net/atmclip.h b/include/net/atmclip.h index 90fcc98e676f..b5a51a7bb364 100644 --- a/include/net/atmclip.h +++ b/include/net/atmclip.h @@ -36,7 +36,7 @@ struct clip_vcc { struct atmarp_entry { - u32 ip; /* IP address */ + __be32 ip; /* IP address */ struct clip_vcc *vccs; /* active VCCs; NULL if resolution is pending */ unsigned long expires; /* entry expiration time */ diff --git a/net/atm/br2684.c b/net/atm/br2684.c index d00cca97eb33..b04162f10d85 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -372,7 +372,7 @@ static int br2684_setfilt(struct atm_vcc *atmvcc, void __user *arg) /* Returns 1 if packet should be dropped */ static inline int -packet_fails_filter(u16 type, struct br2684_vcc *brvcc, struct sk_buff *skb) +packet_fails_filter(__be16 type, struct br2684_vcc *brvcc, struct sk_buff *skb) { if (brvcc->filter.netmask == 0) return 0; /* no filter in place */ diff --git a/net/atm/clip.c b/net/atm/clip.c index 7af2c411da82..1c416934b7c1 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -54,7 +54,7 @@ static struct atm_vcc *atmarpd; static struct neigh_table clip_tbl; static struct timer_list idle_timer; -static int to_atmarpd(enum atmarp_ctrl_type type, int itf, unsigned long ip) +static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip) { struct sock *sk; struct atmarp_ctrl *ctrl; @@ -220,7 +220,7 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb) || memcmp(skb->data, llc_oui, sizeof (llc_oui))) skb->protocol = htons(ETH_P_IP); else { - skb->protocol = ((u16 *) skb->data)[3]; + skb->protocol = ((__be16 *) skb->data)[3]; skb_pull(skb, RFC1483LLC_LEN); if (skb->protocol == htons(ETH_P_ARP)) { PRIV(skb->dev)->stats.rx_packets++; @@ -430,7 +430,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) here = skb_push(skb, RFC1483LLC_LEN); memcpy(here, llc_oui, sizeof(llc_oui)); - ((u16 *) here)[3] = skb->protocol; + ((__be16 *) here)[3] = skb->protocol; } atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); ATM_SKB(skb)->atm_options = vcc->atm_options; @@ -509,7 +509,7 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout) return 0; } -static int clip_setentry(struct atm_vcc *vcc, u32 ip) +static int clip_setentry(struct atm_vcc *vcc, __be32 ip) { struct neighbour *neigh; struct atmarp_entry *entry; @@ -752,7 +752,7 @@ static int clip_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) err = clip_mkip(vcc, arg); break; case ATMARP_SETENTRY: - err = clip_setentry(vcc, arg); + err = clip_setentry(vcc, (__force __be32)arg); break; case ATMARP_ENCAP: err = clip_encap(vcc, arg); diff --git a/net/atm/lec.c b/net/atm/lec.c index 66c57c1091a8..9f5f931743bd 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -204,9 +204,9 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc) memset(rdesc, 0, ETH_ALEN); /* offset 4 comes from LAN destination field in LE control frames */ if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT)) - memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(uint16_t)); + memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(__be16)); else { - memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t)); + memcpy(&rdesc[4], &trh->rseg[1], sizeof(__be16)); rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0)); } @@ -775,7 +775,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) unsigned char *src, *dst; atm_return(vcc, skb->truesize); - if (*(uint16_t *) skb->data == htons(priv->lecid) || + if (*(__be16 *) skb->data == htons(priv->lecid) || !priv->lecd || !(dev->flags & IFF_UP)) { /* * Probably looping back, or if lecd is missing, diff --git a/net/atm/lec.h b/net/atm/lec.h index 877f50939696..24cc95f86741 100644 --- a/net/atm/lec.h +++ b/net/atm/lec.h @@ -14,14 +14,14 @@ #define LEC_HEADER_LEN 16 struct lecdatahdr_8023 { - unsigned short le_header; + __be16 le_header; unsigned char h_dest[ETH_ALEN]; unsigned char h_source[ETH_ALEN]; - unsigned short h_type; + __be16 h_type; }; struct lecdatahdr_8025 { - unsigned short le_header; + __be16 le_header; unsigned char ac_pad; unsigned char fc; unsigned char h_dest[ETH_ALEN]; diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 0d2b994af511..f15f5d847860 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -152,7 +152,7 @@ static struct mpoa_client *find_mpc_by_lec(struct net_device *dev) /* * Overwrites the old entry or makes a new one. */ -struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos) +struct atm_mpoa_qos *atm_mpoa_add_qos(__be32 dst_ip, struct atm_qos *qos) { struct atm_mpoa_qos *entry; @@ -177,7 +177,7 @@ struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos) return entry; } -struct atm_mpoa_qos *atm_mpoa_search_qos(uint32_t dst_ip) +struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip) { struct atm_mpoa_qos *qos; @@ -460,11 +460,11 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) in_cache_entry *entry; struct iphdr *iph; char *buff; - uint32_t ipaddr = 0; + __be32 ipaddr = 0; static struct { struct llc_snap_hdr hdr; - uint32_t tag; + __be32 tag; } tagged_llc_snap_hdr = { {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}}, 0 @@ -559,7 +559,7 @@ static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg) struct mpoa_client *mpc; struct atmmpc_ioc ioc_data; in_cache_entry *in_entry; - uint32_t ipaddr; + __be32 ipaddr; bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmmpc_ioc)); if (bytes_left != 0) { @@ -638,7 +638,7 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) struct sk_buff *new_skb; eg_cache_entry *eg; struct mpoa_client *mpc; - uint32_t tag; + __be32 tag; char *tmp; ddprintk("mpoa: (%s) mpc_push:\n", dev->name); @@ -683,7 +683,7 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) } tmp = skb->data + sizeof(struct llc_snap_hdr); - tag = *(uint32_t *)tmp; + tag = *(__be32 *)tmp; eg = mpc->eg_ops->get_by_tag(tag, mpc); if (eg == NULL) { @@ -1029,7 +1029,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) { - uint32_t dst_ip = msg->content.in_info.in_dst_ip; + __be32 dst_ip = msg->content.in_info.in_dst_ip; in_cache_entry *entry; entry = mpc->in_ops->get(dst_ip, mpc); @@ -1066,7 +1066,7 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) */ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_client *client, in_cache_entry *entry) { - uint32_t dst_ip = msg->content.in_info.in_dst_ip; + __be32 dst_ip = msg->content.in_info.in_dst_ip; struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip); eg_cache_entry *eg_entry = client->eg_ops->get_by_src_ip(dst_ip, client); @@ -1102,7 +1102,7 @@ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_clien static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) { - uint32_t dst_ip = msg->content.in_info.in_dst_ip; + __be32 dst_ip = msg->content.in_info.in_dst_ip; in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc); dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(dst_ip)); @@ -1148,8 +1148,8 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) { - uint32_t dst_ip = msg->content.in_info.in_dst_ip; - uint32_t mask = msg->ip_mask; + __be32 dst_ip = msg->content.in_info.in_dst_ip; + __be32 mask = msg->ip_mask; in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask); if(entry == NULL){ @@ -1173,7 +1173,7 @@ static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) { - uint32_t cache_id = msg->content.eg_info.cache_id; + __be32 cache_id = msg->content.eg_info.cache_id; eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(cache_id, mpc); if (entry == NULL) { diff --git a/net/atm/mpc.h b/net/atm/mpc.h index 3c7981a229e8..51f460d005c3 100644 --- a/net/atm/mpc.h +++ b/net/atm/mpc.h @@ -36,14 +36,14 @@ struct mpoa_client { struct atm_mpoa_qos { struct atm_mpoa_qos *next; - uint32_t ipaddr; + __be32 ipaddr; struct atm_qos qos; }; /* MPOA QoS operations */ -struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos); -struct atm_mpoa_qos *atm_mpoa_search_qos(uint32_t dst_ip); +struct atm_mpoa_qos *atm_mpoa_add_qos(__be32 dst_ip, struct atm_qos *qos); +struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip); int atm_mpoa_delete_qos(struct atm_mpoa_qos *qos); /* Display QoS entries. This is for the procfs */ diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c index fbf13cdcf46e..f3b99b38c91b 100644 --- a/net/atm/mpoa_caches.c +++ b/net/atm/mpoa_caches.c @@ -22,7 +22,7 @@ #define ddprintk(format,args...) #endif -static in_cache_entry *in_cache_get(uint32_t dst_ip, +static in_cache_entry *in_cache_get(__be32 dst_ip, struct mpoa_client *client) { in_cache_entry *entry; @@ -42,9 +42,9 @@ static in_cache_entry *in_cache_get(uint32_t dst_ip, return NULL; } -static in_cache_entry *in_cache_get_with_mask(uint32_t dst_ip, +static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip, struct mpoa_client *client, - uint32_t mask) + __be32 mask) { in_cache_entry *entry; @@ -84,7 +84,7 @@ static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc, return NULL; } -static in_cache_entry *in_cache_add_entry(uint32_t dst_ip, +static in_cache_entry *in_cache_add_entry(__be32 dst_ip, struct mpoa_client *client) { in_cache_entry* entry = kmalloc(sizeof(in_cache_entry), GFP_KERNEL); @@ -319,7 +319,7 @@ static void in_destroy_cache(struct mpoa_client *mpc) return; } -static eg_cache_entry *eg_cache_get_by_cache_id(uint32_t cache_id, struct mpoa_client *mpc) +static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, struct mpoa_client *mpc) { eg_cache_entry *entry; @@ -339,7 +339,7 @@ static eg_cache_entry *eg_cache_get_by_cache_id(uint32_t cache_id, struct mpoa_c } /* This can be called from any context since it saves CPU flags */ -static eg_cache_entry *eg_cache_get_by_tag(uint32_t tag, struct mpoa_client *mpc) +static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc) { unsigned long flags; eg_cache_entry *entry; @@ -380,7 +380,7 @@ static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_clie return NULL; } -static eg_cache_entry *eg_cache_get_by_src_ip(uint32_t ipaddr, struct mpoa_client *mpc) +static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, struct mpoa_client *mpc) { eg_cache_entry *entry; diff --git a/net/atm/mpoa_caches.h b/net/atm/mpoa_caches.h index 6c9886a03d0b..84de977def2e 100644 --- a/net/atm/mpoa_caches.h +++ b/net/atm/mpoa_caches.h @@ -29,12 +29,12 @@ typedef struct in_cache_entry { } in_cache_entry; struct in_cache_ops{ - in_cache_entry *(*add_entry)(uint32_t dst_ip, + in_cache_entry *(*add_entry)(__be32 dst_ip, struct mpoa_client *client); - in_cache_entry *(*get)(uint32_t dst_ip, struct mpoa_client *client); - in_cache_entry *(*get_with_mask)(uint32_t dst_ip, + in_cache_entry *(*get)(__be32 dst_ip, struct mpoa_client *client); + in_cache_entry *(*get_with_mask)(__be32 dst_ip, struct mpoa_client *client, - uint32_t mask); + __be32 mask); in_cache_entry *(*get_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client); void (*put)(in_cache_entry *entry); @@ -56,17 +56,17 @@ typedef struct eg_cache_entry{ struct atm_vcc *shortcut; uint32_t packets_rcvd; uint16_t entry_state; - uint32_t latest_ip_addr; /* The src IP address of the last packet */ + __be32 latest_ip_addr; /* The src IP address of the last packet */ struct eg_ctrl_info ctrl_info; atomic_t use; } eg_cache_entry; struct eg_cache_ops{ eg_cache_entry *(*add_entry)(struct k_message *msg, struct mpoa_client *client); - eg_cache_entry *(*get_by_cache_id)(uint32_t cache_id, struct mpoa_client *client); - eg_cache_entry *(*get_by_tag)(uint32_t cache_id, struct mpoa_client *client); + eg_cache_entry *(*get_by_cache_id)(__be32 cache_id, struct mpoa_client *client); + eg_cache_entry *(*get_by_tag)(__be32 cache_id, struct mpoa_client *client); eg_cache_entry *(*get_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client); - eg_cache_entry *(*get_by_src_ip)(uint32_t ipaddr, struct mpoa_client *client); + eg_cache_entry *(*get_by_src_ip)(__be32 ipaddr, struct mpoa_client *client); void (*put)(eg_cache_entry *entry); void (*remove_entry)(eg_cache_entry *entry, struct mpoa_client *client); void (*update)(eg_cache_entry *entry, uint16_t holding_time); diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c index d37b8911b3ab..3844c85d602f 100644 --- a/net/atm/mpoa_proc.c +++ b/net/atm/mpoa_proc.c @@ -231,14 +231,14 @@ static int parse_qos(const char *buff) */ unsigned char ip[4]; int tx_pcr, tx_sdu, rx_pcr, rx_sdu; - uint32_t ipaddr; + __be32 ipaddr; struct atm_qos qos; memset(&qos, 0, sizeof(struct atm_qos)); if (sscanf(buff, "del %hhu.%hhu.%hhu.%hhu", ip, ip+1, ip+2, ip+3) == 4) { - ipaddr = *(uint32_t *)ip; + ipaddr = *(__be32 *)ip; return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr)); } @@ -250,7 +250,7 @@ static int parse_qos(const char *buff) ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu, &rx_pcr, &rx_sdu) != 8) return 0; - ipaddr = *(uint32_t *)ip; + ipaddr = *(__be32 *)ip; qos.txtp.traffic_class = ATM_CBR; qos.txtp.max_pcr = tx_pcr; qos.txtp.max_sdu = tx_sdu; -- cgit v1.2.3 From 47c183fa5ea7feebc356da8ccbd9105a41f8e534 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:11:51 -0800 Subject: [BRIDGE]: Annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_bridge.h | 2 +- include/linux/netfilter_bridge/ebt_802_3.h | 10 +++++----- include/linux/netfilter_bridge/ebt_among.h | 2 +- include/linux/netfilter_bridge/ebt_arp.h | 14 +++++++------- include/linux/netfilter_bridge/ebt_ip.h | 8 ++++---- include/linux/netfilter_bridge/ebt_vlan.h | 2 +- include/linux/netfilter_bridge/ebtables.h | 2 +- net/bridge/br_netfilter.c | 2 +- net/bridge/netfilter/ebt_802_3.c | 2 +- net/bridge/netfilter/ebt_among.c | 22 +++++++++++----------- net/bridge/netfilter/ebt_arp.c | 6 +++--- net/bridge/netfilter/ebt_ip.c | 4 ++-- net/bridge/netfilter/ebt_log.c | 6 +++--- net/bridge/netfilter/ebt_vlan.c | 2 +- 14 files changed, 42 insertions(+), 42 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index 9a4dd11af86e..6c4613f8ad75 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h @@ -64,7 +64,7 @@ static inline int nf_bridge_pad(const struct sk_buff *skb) struct bridge_skb_cb { union { - __u32 ipv4; + __be32 ipv4; } daddr; }; diff --git a/include/linux/netfilter_bridge/ebt_802_3.h b/include/linux/netfilter_bridge/ebt_802_3.h index b9f712c14a0a..07f044ff1a6b 100644 --- a/include/linux/netfilter_bridge/ebt_802_3.h +++ b/include/linux/netfilter_bridge/ebt_802_3.h @@ -28,21 +28,21 @@ struct hdr_ui { uint8_t ssap; uint8_t ctrl; uint8_t orig[3]; - uint16_t type; + __be16 type; }; struct hdr_ni { uint8_t dsap; uint8_t ssap; - uint16_t ctrl; + __be16 ctrl; uint8_t orig[3]; - uint16_t type; + __be16 type; }; struct ebt_802_3_hdr { uint8_t daddr[6]; uint8_t saddr[6]; - uint16_t len; + __be16 len; union { struct hdr_ui ui; struct hdr_ni ni; @@ -61,7 +61,7 @@ static inline struct ebt_802_3_hdr *ebt_802_3_hdr(const struct sk_buff *skb) struct ebt_802_3_info { uint8_t sap; - uint16_t type; + __be16 type; uint8_t bitmask; uint8_t invflags; }; diff --git a/include/linux/netfilter_bridge/ebt_among.h b/include/linux/netfilter_bridge/ebt_among.h index 307c1fed8511..7654069233ca 100644 --- a/include/linux/netfilter_bridge/ebt_among.h +++ b/include/linux/netfilter_bridge/ebt_among.h @@ -32,7 +32,7 @@ struct ebt_mac_wormhash_tuple { uint32_t cmp[2]; - uint32_t ip; + __be32 ip; }; struct ebt_mac_wormhash diff --git a/include/linux/netfilter_bridge/ebt_arp.h b/include/linux/netfilter_bridge/ebt_arp.h index 537ec6b487a2..97e4dbde1f89 100644 --- a/include/linux/netfilter_bridge/ebt_arp.h +++ b/include/linux/netfilter_bridge/ebt_arp.h @@ -14,13 +14,13 @@ struct ebt_arp_info { - uint16_t htype; - uint16_t ptype; - uint16_t opcode; - uint32_t saddr; - uint32_t smsk; - uint32_t daddr; - uint32_t dmsk; + __be16 htype; + __be16 ptype; + __be16 opcode; + __be32 saddr; + __be32 smsk; + __be32 daddr; + __be32 dmsk; unsigned char smaddr[ETH_ALEN]; unsigned char smmsk[ETH_ALEN]; unsigned char dmaddr[ETH_ALEN]; diff --git a/include/linux/netfilter_bridge/ebt_ip.h b/include/linux/netfilter_bridge/ebt_ip.h index 7247385cdcb1..d6847475bf2e 100644 --- a/include/linux/netfilter_bridge/ebt_ip.h +++ b/include/linux/netfilter_bridge/ebt_ip.h @@ -28,10 +28,10 @@ /* the same values are used for the invflags */ struct ebt_ip_info { - uint32_t saddr; - uint32_t daddr; - uint32_t smsk; - uint32_t dmsk; + __be32 saddr; + __be32 daddr; + __be32 smsk; + __be32 dmsk; uint8_t tos; uint8_t protocol; uint8_t bitmask; diff --git a/include/linux/netfilter_bridge/ebt_vlan.h b/include/linux/netfilter_bridge/ebt_vlan.h index cb1fcc41565f..1d98be4031e7 100644 --- a/include/linux/netfilter_bridge/ebt_vlan.h +++ b/include/linux/netfilter_bridge/ebt_vlan.h @@ -10,7 +10,7 @@ struct ebt_vlan_info { uint16_t id; /* VLAN ID {1-4095} */ uint8_t prio; /* VLAN User Priority {0-7} */ - uint16_t encap; /* VLAN Encapsulated frame code {0-65535} */ + __be16 encap; /* VLAN Encapsulated frame code {0-65535} */ uint8_t bitmask; /* Args bitmask bit 1=1 - ID arg, bit 2=1 User-Priority arg, bit 3=1 encap*/ uint8_t invflags; /* Inverse bitmask bit 1=1 - inversed ID arg, diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index b1a7cc90877b..e6ea70de24d5 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -141,7 +141,7 @@ struct ebt_entry { /* this needs to be the first field */ unsigned int bitmask; unsigned int invflags; - uint16_t ethproto; + __be16 ethproto; /* the physical in-dev */ char in[IFNAMSIZ]; /* the logical in-dev */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index ac181be13d83..2a5d31b1a196 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -381,7 +381,7 @@ static int check_hbh_len(struct sk_buff *skb) case IPV6_TLV_JUMBO: if (skb->nh.raw[off + 1] != 4 || (off & 3) != 2) goto bad; - pkt_len = ntohl(*(u32 *) (skb->nh.raw + off + 2)); + pkt_len = ntohl(*(__be32 *) (skb->nh.raw + off + 2)); if (pkt_len <= IPV6_MAXPLEN || skb->nh.ipv6h->payload_len) goto bad; diff --git a/net/bridge/netfilter/ebt_802_3.c b/net/bridge/netfilter/ebt_802_3.c index d42f63f5e9f8..9abbc09ccdc3 100644 --- a/net/bridge/netfilter/ebt_802_3.c +++ b/net/bridge/netfilter/ebt_802_3.c @@ -17,7 +17,7 @@ static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device * { struct ebt_802_3_info *info = (struct ebt_802_3_info *)data; struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb); - uint16_t type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type; + __be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type; if (info->bitmask & EBT_802_3_SAP) { if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP)) diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c index a614485828af..ce97c4285f9a 100644 --- a/net/bridge/netfilter/ebt_among.c +++ b/net/bridge/netfilter/ebt_among.c @@ -15,7 +15,7 @@ #include static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh, - const char *mac, uint32_t ip) + const char *mac, __be32 ip) { /* You may be puzzled as to how this code works. * Some tricks were used, refer to @@ -70,7 +70,7 @@ static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash return 0; } -static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr) +static int get_ip_dst(const struct sk_buff *skb, __be32 *addr) { if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) { struct iphdr _iph, *ih; @@ -81,16 +81,16 @@ static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr) *addr = ih->daddr; } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { struct arphdr _arph, *ah; - uint32_t buf, *bp; + __be32 buf, *bp; ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); if (ah == NULL || - ah->ar_pln != sizeof(uint32_t) || + ah->ar_pln != sizeof(__be32) || ah->ar_hln != ETH_ALEN) return -1; bp = skb_header_pointer(skb, sizeof(struct arphdr) + - 2 * ETH_ALEN + sizeof(uint32_t), - sizeof(uint32_t), &buf); + 2 * ETH_ALEN + sizeof(__be32), + sizeof(__be32), &buf); if (bp == NULL) return -1; *addr = *bp; @@ -98,7 +98,7 @@ static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr) return 0; } -static int get_ip_src(const struct sk_buff *skb, uint32_t *addr) +static int get_ip_src(const struct sk_buff *skb, __be32 *addr) { if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) { struct iphdr _iph, *ih; @@ -109,15 +109,15 @@ static int get_ip_src(const struct sk_buff *skb, uint32_t *addr) *addr = ih->saddr; } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { struct arphdr _arph, *ah; - uint32_t buf, *bp; + __be32 buf, *bp; ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); if (ah == NULL || - ah->ar_pln != sizeof(uint32_t) || + ah->ar_pln != sizeof(__be32) || ah->ar_hln != ETH_ALEN) return -1; bp = skb_header_pointer(skb, sizeof(struct arphdr) + - ETH_ALEN, sizeof(uint32_t), &buf); + ETH_ALEN, sizeof(__be32), &buf); if (bp == NULL) return -1; *addr = *bp; @@ -133,7 +133,7 @@ static int ebt_filter_among(const struct sk_buff *skb, struct ebt_among_info *info = (struct ebt_among_info *) data; const char *dmac, *smac; const struct ebt_mac_wormhash *wh_dst, *wh_src; - uint32_t dip = 0, sip = 0; + __be32 dip = 0, sip = 0; wh_dst = ebt_among_wh_dst(info); wh_src = ebt_among_wh_src(info); diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c index a6c81d9f73b8..9c599800a900 100644 --- a/net/bridge/netfilter/ebt_arp.c +++ b/net/bridge/netfilter/ebt_arp.c @@ -35,10 +35,10 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in return EBT_NOMATCH; if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) { - uint32_t _addr, *ap; + __be32 _addr, *ap; /* IPv4 addresses are always 4 bytes */ - if (ah->ar_pln != sizeof(uint32_t)) + if (ah->ar_pln != sizeof(__be32)) return EBT_NOMATCH; if (info->bitmask & EBT_ARP_SRC_IP) { ap = skb_header_pointer(skb, sizeof(struct arphdr) + @@ -53,7 +53,7 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in if (info->bitmask & EBT_ARP_DST_IP) { ap = skb_header_pointer(skb, sizeof(struct arphdr) + - 2*ah->ar_hln+sizeof(uint32_t), + 2*ah->ar_hln+sizeof(__be32), sizeof(_addr), &_addr); if (ap == NULL) return EBT_NOMATCH; diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c index 65b665ce57b5..e4c642448e1b 100644 --- a/net/bridge/netfilter/ebt_ip.c +++ b/net/bridge/netfilter/ebt_ip.c @@ -20,8 +20,8 @@ #include struct tcpudphdr { - uint16_t src; - uint16_t dst; + __be16 src; + __be16 dst; }; static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in, diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index 466ed3440b74..a184f879f253 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -38,8 +38,8 @@ static int ebt_log_check(const char *tablename, unsigned int hookmask, struct tcpudphdr { - uint16_t src; - uint16_t dst; + __be16 src; + __be16 dst; }; struct arppayload @@ -130,7 +130,7 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum, * then log the ARP payload */ if (ah->ar_hrd == htons(1) && ah->ar_hln == ETH_ALEN && - ah->ar_pln == sizeof(uint32_t)) { + ah->ar_pln == sizeof(__be32)) { struct arppayload _arpp, *ap; ap = skb_header_pointer(skb, sizeof(_arph), diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c index a2b452862b73..7ee377622964 100644 --- a/net/bridge/netfilter/ebt_vlan.c +++ b/net/bridge/netfilter/ebt_vlan.c @@ -55,7 +55,7 @@ ebt_filter_vlan(const struct sk_buff *skb, unsigned short id; /* VLAN ID, given from frame TCI */ unsigned char prio; /* user_priority, given from frame TCI */ /* VLAN encapsulated Type/Length field, given from orig frame */ - unsigned short encap; + __be16 encap; fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame); if (fp == NULL) -- cgit v1.2.3 From a64b78a077a71c9b9c0c1b0be699083379783c3d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:12:29 -0800 Subject: [NET]: Annotate net_srandom(). Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/net.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/net.h b/include/linux/net.h index 15c733b816f0..6f0dfeba509a 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -196,7 +196,7 @@ extern struct socket *sockfd_lookup(int fd, int *err); extern int net_ratelimit(void); #define net_random() random32() -#define net_srandom(seed) srandom32(seed) +#define net_srandom(seed) srandom32((__force u32)seed) extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t len); -- cgit v1.2.3 From 2bc357987a6510e61d33f3b20fa989fb2b6a10b8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:14:18 -0800 Subject: [NET]: Introduce types for checksums. New types - for 16bit checksums and "unfolded" 32bit variant. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/types.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/types.h b/include/linux/types.h index 9f11fdd2bd72..745c409ebbb5 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -182,6 +182,8 @@ typedef __u32 __bitwise __be32; typedef __u64 __bitwise __le64; typedef __u64 __bitwise __be64; #endif +typedef __u16 __bitwise __sum16; +typedef __u32 __bitwise __wsum; #ifdef __KERNEL__ typedef unsigned __bitwise__ gfp_t; -- cgit v1.2.3 From 9981a0e36a572e9fcf84bfab915fdc93bed0e3c9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:24:30 -0800 Subject: [NET]: Annotate checksums in on-the-wire packets. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/dccp.h | 2 +- include/linux/icmp.h | 2 +- include/linux/icmpv6.h | 2 +- include/linux/igmp.h | 2 +- include/linux/ip.h | 2 +- include/linux/tcp.h | 2 +- include/linux/udp.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index d308f1228b61..72cc355d7a03 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -30,7 +30,7 @@ struct dccp_hdr { #else #error "Adjust your defines" #endif - __u16 dccph_checksum; + __sum16 dccph_checksum; #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 dccph_x:1, dccph_type:4, diff --git a/include/linux/icmp.h b/include/linux/icmp.h index 878cfe4e587f..24da4fbc1a2f 100644 --- a/include/linux/icmp.h +++ b/include/linux/icmp.h @@ -68,7 +68,7 @@ struct icmphdr { __u8 type; __u8 code; - __be16 checksum; + __sum16 checksum; union { struct { __be16 id; diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index dc79396aac25..68d3526c3a05 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -7,7 +7,7 @@ struct icmp6hdr { __u8 icmp6_type; __u8 icmp6_code; - __be16 icmp6_cksum; + __sum16 icmp6_cksum; union { diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 21dd56905271..6e7ea2f0a57c 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -30,7 +30,7 @@ struct igmphdr { __u8 type; __u8 code; /* For newer IGMP */ - __be16 csum; + __sum16 csum; __be32 group; }; diff --git a/include/linux/ip.h b/include/linux/ip.h index ecee9bb27d0e..1d36b971a8b5 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -98,7 +98,7 @@ struct iphdr { __be16 frag_off; __u8 ttl; __u8 protocol; - __be16 check; + __sum16 check; __be32 saddr; __be32 daddr; /*The options start here. */ diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 0aecfc955591..dd61b172ac68 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -52,7 +52,7 @@ struct tcphdr { #error "Adjust your defines" #endif __be16 window; - __be16 check; + __sum16 check; __be16 urg_ptr; }; diff --git a/include/linux/udp.h b/include/linux/udp.h index 564f3b050105..7e08c07efe0f 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -23,7 +23,7 @@ struct udphdr { __be16 source; __be16 dest; __be16 len; - __be16 check; + __sum16 check; }; /* UDP socket options */ -- cgit v1.2.3 From 44bb93633f57a55979f3c2589b10fd6a2bfc7c08 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:36:14 -0800 Subject: [NET]: Annotate csum_partial() callers in net/* Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/socket.h | 2 +- include/linux/sunrpc/xdr.h | 2 +- net/core/iovec.c | 4 ++-- net/core/skbuff.c | 2 +- net/ipv4/ip_output.c | 8 ++++---- net/unix/af_unix.c | 3 ++- 6 files changed, 11 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/socket.h b/include/linux/socket.h index 592b66679823..92cd38efad7f 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -293,7 +293,7 @@ extern int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, extern int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, - unsigned int len, int *csump); + unsigned int len, __wsum *csump); extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode); extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index ac69e5511606..9a527c364394 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -151,7 +151,7 @@ typedef struct { struct sk_buff *skb; unsigned int offset; size_t count; - unsigned int csum; + __wsum csum; } skb_reader_t; typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); diff --git a/net/core/iovec.c b/net/core/iovec.c index 65e4b56fbc77..04b249c40b5b 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -158,9 +158,9 @@ int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, * call to this function will be unaligned also. */ int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, - int offset, unsigned int len, int *csump) + int offset, unsigned int len, __wsum *csump) { - int csum = *csump; + __wsum csum = *csump; int partial_cnt = 0, err = 0; /* Skip over the finished iovecs */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index dfa02cc8d687..c0e3427057fc 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1265,7 +1265,7 @@ unsigned int skb_checksum(const struct sk_buff *skb, int offset, end = start + skb_shinfo(skb)->frags[i].size; if ((copy = end - offset) > 0) { - unsigned int csum2; + __wsum csum2; u8 *vaddr; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 5f3e35c03637..f9194f7e39d3 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -682,7 +682,7 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk if (memcpy_fromiovecend(to, iov, offset, len) < 0) return -EFAULT; } else { - unsigned int csum = 0; + __wsum csum = 0; if (csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0) return -EFAULT; skb->csum = csum_block_add(skb->csum, csum, odd); @@ -690,11 +690,11 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk return 0; } -static inline unsigned int +static inline __wsum csum_page(struct page *page, int offset, int copy) { char *kaddr; - unsigned int csum; + __wsum csum; kaddr = kmap(page); csum = csum_partial(kaddr + offset, copy, 0); kunmap(page); @@ -1166,7 +1166,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, } if (skb->ip_summed == CHECKSUM_NONE) { - unsigned int csum; + __wsum csum; csum = csum_page(page, offset, len); skb->csum = csum_block_add(skb->csum, csum, skb->len); } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index b43a27828df5..2f208c7f4d43 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -151,8 +151,9 @@ static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) * each socket state is protected by separate rwlock. */ -static inline unsigned unix_hash_fold(unsigned hash) +static inline unsigned unix_hash_fold(__wsum n) { + unsigned hash = (__force unsigned)n; hash ^= hash>>16; hash ^= hash>>8; return hash&(UNIX_HASH_SIZE-1); -- cgit v1.2.3 From 5084205faf45384fff25c4cf77dd5c96279283ad Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:36:34 -0800 Subject: [NET]: Annotate callers of csum_partial_copy_...() and csum_and_copy...() in net/* Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/skbuff.h | 3 +-- include/net/sock.h | 2 +- net/core/datagram.c | 6 +++--- net/core/skbuff.c | 2 +- net/ipv4/ip_output.c | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e3ae544b3956..64fa7f4c702d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1199,8 +1199,7 @@ static inline int skb_add_data(struct sk_buff *skb, if (skb->ip_summed == CHECKSUM_NONE) { int err = 0; - unsigned int csum = csum_and_copy_from_user(from, - skb_put(skb, copy), + __wsum csum = csum_and_copy_from_user(from, skb_put(skb, copy), copy, 0, &err); if (!err) { skb->csum = csum_block_add(skb->csum, csum, off); diff --git a/include/net/sock.h b/include/net/sock.h index 35ffbdd35d3e..dc4b92b8abea 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1088,7 +1088,7 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from, { if (skb->ip_summed == CHECKSUM_NONE) { int err = 0; - unsigned int csum = csum_and_copy_from_user(from, + __wsum csum = csum_and_copy_from_user(from, page_address(page) + off, copy, 0, &err); if (err) diff --git a/net/core/datagram.c b/net/core/datagram.c index e5a05a046fef..0d9c9bac4006 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -321,7 +321,7 @@ fault: static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 __user *to, int len, - unsigned int *csump) + __wsum *csump) { int start = skb_headlen(skb); int pos = 0; @@ -350,7 +350,7 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, end = start + skb_shinfo(skb)->frags[i].size; if ((copy = end - offset) > 0) { - unsigned int csum2; + __wsum csum2; int err = 0; u8 *vaddr; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; @@ -386,7 +386,7 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, end = start + list->len; if ((copy = end - offset) > 0) { - unsigned int csum2 = 0; + __wsum csum2 = 0; if (copy > len) copy = len; if (skb_copy_and_csum_datagram(list, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c0e3427057fc..da6683f4b31d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1342,7 +1342,7 @@ unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, end = start + skb_shinfo(skb)->frags[i].size; if ((copy = end - offset) > 0) { - unsigned int csum2; + __wsum csum2; u8 *vaddr; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index f9194f7e39d3..1da3d32f8289 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1314,7 +1314,7 @@ void ip_flush_pending_frames(struct sock *sk) static int ip_reply_glue_bits(void *dptr, char *to, int offset, int len, int odd, struct sk_buff *skb) { - unsigned int csum; + __wsum csum; csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0); skb->csum = csum_block_add(skb->csum, csum, odd); -- cgit v1.2.3 From 2bbbc86890ac4c911c5057f69af93853e52a42a8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:37:14 -0800 Subject: [NET]: Annotate skb_checksum() and callers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++-- net/core/skbuff.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 64fa7f4c702d..784129fb61d4 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1334,8 +1334,8 @@ extern int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); extern void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags); -extern unsigned int skb_checksum(const struct sk_buff *skb, int offset, - int len, unsigned int csum); +extern __wsum skb_checksum(const struct sk_buff *skb, int offset, + int len, __wsum csum); extern int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); extern int skb_store_bits(const struct sk_buff *skb, int offset, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6e8c15b39eb8..be9b541f536f 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1240,8 +1240,8 @@ EXPORT_SYMBOL(skb_store_bits); /* Checksum skb data. */ -unsigned int skb_checksum(const struct sk_buff *skb, int offset, - int len, unsigned int csum) +__wsum skb_checksum(const struct sk_buff *skb, int offset, + int len, __wsum csum) { int start = skb_headlen(skb); int i, copy = start - offset; -- cgit v1.2.3 From 81d77662763ae527ba3a9b9275467901aaab7dfd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:37:33 -0800 Subject: [NET]: Annotate skb_copy_and_csum_bits() and callers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++-- net/core/skbuff.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 784129fb61d4..874ca029fbb9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1340,9 +1340,9 @@ extern int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); extern int skb_store_bits(const struct sk_buff *skb, int offset, void *from, int len); -extern unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, +extern __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, - unsigned int csum); + __wsum csum); extern void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); extern void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index be9b541f536f..07c25d601922 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1315,8 +1315,8 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, /* Both of above in one bottle. */ -unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, - u8 *to, int len, unsigned int csum) +__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, + u8 *to, int len, __wsum csum) { int start = skb_headlen(skb); int i, copy = start - offset; @@ -1368,7 +1368,7 @@ unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, struct sk_buff *list = skb_shinfo(skb)->frag_list; for (; list; list = list->next) { - unsigned int csum2; + __wsum csum2; int end; BUG_TRAP(start <= offset + len); -- cgit v1.2.3 From b51655b958dfb1176bfcf99466231fdbef8751ff Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:40:42 -0800 Subject: [NET]: Annotate __skb_checksum_complete() and friends. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter.h | 6 +++--- include/linux/netfilter_ipv4.h | 2 +- include/linux/netfilter_ipv6.h | 2 +- include/linux/skbuff.h | 2 +- include/net/tcp.h | 2 +- include/net/udp.h | 8 ++++---- net/core/datagram.c | 2 +- net/core/netpoll.c | 4 ++-- net/ipv4/netfilter.c | 4 ++-- net/ipv4/tcp_input.c | 4 ++-- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/netfilter.c | 4 ++-- net/ipv6/tcp_ipv6.c | 2 +- 13 files changed, 22 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index b7e67d1d4382..707bb2e53c4e 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -290,7 +290,7 @@ extern u_int16_t nf_proto_csum_update(struct sk_buff *skb, struct nf_afinfo { unsigned short family; - unsigned int (*checksum)(struct sk_buff *skb, unsigned int hook, + __sum16 (*checksum)(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); void (*saveroute)(const struct sk_buff *skb, struct nf_info *info); @@ -305,12 +305,12 @@ static inline struct nf_afinfo *nf_get_afinfo(unsigned short family) return rcu_dereference(nf_afinfo[family]); } -static inline unsigned int +static inline __sum16 nf_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol, unsigned short family) { struct nf_afinfo *afinfo; - unsigned int csum = 0; + __sum16 csum = 0; rcu_read_lock(); afinfo = nf_get_afinfo(family); diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index 5b63a231a76b..5821eb5a0a3e 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -79,7 +79,7 @@ enum nf_ip_hook_priorities { #ifdef __KERNEL__ extern int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type); extern int ip_xfrm_me_harder(struct sk_buff **pskb); -extern unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, +extern __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); #endif /*__KERNEL__*/ diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index d97e268cdfe5..ab81a6dc94ea 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h @@ -74,7 +74,7 @@ enum nf_ip6_hook_priorities { #ifdef CONFIG_NETFILTER extern int ip6_route_me_harder(struct sk_buff *skb); -extern unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, +extern __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); extern int ipv6_netfilter_init(void); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 874ca029fbb9..41753667541d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1398,7 +1398,7 @@ static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval * extern void __net_timestamp(struct sk_buff *skb); -extern unsigned int __skb_checksum_complete(struct sk_buff *skb); +extern __sum16 __skb_checksum_complete(struct sk_buff *skb); /** * skb_checksum_complete - Calculate checksum of an entire packet diff --git a/include/net/tcp.h b/include/net/tcp.h index 826aaecdb994..aa7989c53791 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -814,7 +814,7 @@ static inline __sum16 tcp_v4_check(struct tcphdr *th, int len, return csum_tcpudp_magic(saddr,daddr,len,IPPROTO_TCP,base); } -static inline int __tcp_checksum_complete(struct sk_buff *skb) +static inline __sum16 __tcp_checksum_complete(struct sk_buff *skb) { return __skb_checksum_complete(skb); } diff --git a/include/net/udp.h b/include/net/udp.h index 39e825a6909a..c5ccd9a3387b 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -69,15 +69,15 @@ struct sk_buff; /* * Generic checksumming routines for UDP(-Lite) v4 and v6 */ -static inline u16 __udp_lib_checksum_complete(struct sk_buff *skb) +static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb) { if (! UDP_SKB_CB(skb)->partial_cov) return __skb_checksum_complete(skb); - return csum_fold(skb_checksum(skb, 0, UDP_SKB_CB(skb)->cscov, - skb->csum)); + return csum_fold(skb_checksum(skb, 0, UDP_SKB_CB(skb)->cscov, + skb->csum)); } -static __inline__ int udp_lib_checksum_complete(struct sk_buff *skb) +static inline __sum16 udp_lib_checksum_complete(struct sk_buff *skb) { return skb->ip_summed != CHECKSUM_UNNECESSARY && __udp_lib_checksum_complete(skb); diff --git a/net/core/datagram.c b/net/core/datagram.c index 0d9c9bac4006..797fdd4352ce 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -411,7 +411,7 @@ fault: return -EFAULT; } -unsigned int __skb_checksum_complete(struct sk_buff *skb) +__sum16 __skb_checksum_complete(struct sk_buff *skb) { __sum16 sum; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 26ee1791aa02..8be3681d3d80 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -77,8 +77,8 @@ static void queue_process(void *p) } } -static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, - unsigned short ulen, __be32 saddr, __be32 daddr) +static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh, + unsigned short ulen, __be32 saddr, __be32 daddr) { __wsum psum; diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index b797a37c01ce..a68966059b50 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -162,11 +162,11 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info) return 0; } -unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, +__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol) { struct iphdr *iph = skb->nh.iph; - unsigned int csum = 0; + __sum16 csum = 0; switch (skb->ip_summed) { case CHECKSUM_COMPLETE: diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6ab3423674bb..9304034c0c47 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3790,9 +3790,9 @@ static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) return err; } -static int __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb) +static __sum16 __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb) { - int result; + __sum16 result; if (sock_owned_by_user(sk)) { local_bh_enable(); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0ca8dead03b0..dadf80272413 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1544,7 +1544,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) return sk; } -static int tcp_v4_checksum_init(struct sk_buff *skb) +static __sum16 tcp_v4_checksum_init(struct sk_buff *skb) { if (skb->ip_summed == CHECKSUM_COMPLETE) { if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 8d1b542806c1..f6294e5bcb31 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -80,11 +80,11 @@ static int nf_ip6_reroute(struct sk_buff **pskb, const struct nf_info *info) return 0; } -unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, +__sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol) { struct ipv6hdr *ip6h = skb->nh.ipv6h; - unsigned int csum = 0; + __sum16 csum = 0; switch (skb->ip_summed) { case CHECKSUM_COMPLETE: diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 394bc54c5c21..147ce499f509 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1527,7 +1527,7 @@ out: return NULL; } -static int tcp_v6_checksum_init(struct sk_buff *skb) +static __sum16 tcp_v6_checksum_init(struct sk_buff *skb) { if (skb->ip_summed == CHECKSUM_COMPLETE) { if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, -- cgit v1.2.3 From 43bc0ca7eadc024e9e5b935fa5e0892df4fec9eb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:43:23 -0800 Subject: [NET]: netfilter checksum annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter.h | 26 +++++++++++++++---- .../linux/netfilter_ipv4/ip_conntrack_proto_gre.h | 4 +-- net/ipv4/netfilter/ip_nat_core.c | 6 ++--- net/ipv4/netfilter/ip_nat_helper.c | 30 ++++++++-------------- net/ipv4/netfilter/ip_nat_proto_gre.c | 8 +++--- net/ipv4/netfilter/ip_nat_proto_icmp.c | 6 ++--- net/ipv4/netfilter/ip_nat_proto_tcp.c | 5 ++-- net/ipv4/netfilter/ip_nat_proto_udp.c | 7 ++--- net/ipv4/netfilter/ipt_ECN.c | 11 +++----- net/ipv4/netfilter/ipt_TCPMSS.c | 24 ++++++----------- net/ipv4/netfilter/ipt_TOS.c | 5 ++-- net/ipv4/netfilter/ipt_TTL.c | 5 ++-- net/netfilter/core.c | 27 ++++++++----------- 13 files changed, 70 insertions(+), 94 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 707bb2e53c4e..6ab5e2d6133e 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -282,11 +282,27 @@ extern void nf_invalidate_cache(int pf); Returns true or false. */ extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len); -extern u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval, - u_int32_t csum); -extern u_int16_t nf_proto_csum_update(struct sk_buff *skb, - u_int32_t oldval, u_int32_t newval, - u_int16_t csum, int pseudohdr); +static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to) +{ + __be32 diff[] = { ~from, to }; + + *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum))); +} + +static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to) +{ + nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to); +} + +extern void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, + __be32 from, __be32 to, int pseudohdr); + +static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb, + __be16 from, __be16 to, int pseudohdr) +{ + nf_proto_csum_replace4(sum, skb, (__force __be32)from, + (__force __be32)to, pseudohdr); +} struct nf_afinfo { unsigned short family; diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h index 1d853aa873eb..e371e0fc1672 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h @@ -102,11 +102,11 @@ static inline __be32 *gre_key(struct gre_hdr *greh) } /* get pointer ot gre csum, if present */ -static inline u_int16_t *gre_csum(struct gre_hdr *greh) +static inline __sum16 *gre_csum(struct gre_hdr *greh) { if (!greh->csum) return NULL; - return (u_int16_t *) (greh+sizeof(*greh)); + return (__sum16 *) (greh+sizeof(*greh)); } #endif /* __KERNEL__ */ diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 4b6260a97408..9d1a5175dcd4 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -362,12 +362,10 @@ manip_pkt(u_int16_t proto, iph = (void *)(*pskb)->data + iphdroff; if (maniptype == IP_NAT_MANIP_SRC) { - iph->check = nf_csum_update(~iph->saddr, target->src.ip, - iph->check); + nf_csum_replace4(&iph->check, iph->saddr, target->src.ip); iph->saddr = target->src.ip; } else { - iph->check = nf_csum_update(~iph->daddr, target->dst.ip, - iph->check); + nf_csum_replace4(&iph->check, iph->daddr, target->dst.ip); iph->daddr = target->dst.ip; } return 1; diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index 3e7fd64c2162..ee80feb4b2a9 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c @@ -188,10 +188,8 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb, csum_partial((char *)tcph, datalen, 0)); } else - tcph->check = nf_proto_csum_update(*pskb, - htons(oldlen) ^ htons(0xFFFF), - htons(datalen), - tcph->check, 1); + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(oldlen), htons(datalen), 1); if (rep_len != match_len) { set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); @@ -266,10 +264,8 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb, if (!udph->check) udph->check = CSUM_MANGLED_0; } else - udph->check = nf_proto_csum_update(*pskb, - htons(oldlen) ^ htons(0xFFFF), - htons(datalen), - udph->check, 1); + nf_proto_csum_replace2(&udph->check, *pskb, + htons(oldlen), htons(datalen), 1); return 1; } EXPORT_SYMBOL(ip_nat_mangle_udp_packet); @@ -307,14 +303,10 @@ sack_adjust(struct sk_buff *skb, ntohl(sack->start_seq), new_start_seq, ntohl(sack->end_seq), new_end_seq); - tcph->check = nf_proto_csum_update(skb, - ~sack->start_seq, - new_start_seq, - tcph->check, 0); - tcph->check = nf_proto_csum_update(skb, - ~sack->end_seq, - new_end_seq, - tcph->check, 0); + nf_proto_csum_replace4(&tcph->check, skb, + sack->start_seq, new_start_seq, 0); + nf_proto_csum_replace4(&tcph->check, skb, + sack->end_seq, new_end_seq, 0); sack->start_seq = new_start_seq; sack->end_seq = new_end_seq; sackoff += sizeof(*sack); @@ -397,10 +389,8 @@ ip_nat_seq_adjust(struct sk_buff **pskb, else newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); - tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq, - tcph->check, 0); - tcph->check = nf_proto_csum_update(*pskb, ~tcph->ack_seq, newack, - tcph->check, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c index bf91f9312b3c..95810202d849 100644 --- a/net/ipv4/netfilter/ip_nat_proto_gre.c +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c @@ -129,11 +129,9 @@ gre_manip_pkt(struct sk_buff **pskb, } if (greh->csum) { /* FIXME: Never tested this code... */ - *(gre_csum(greh)) = - nf_proto_csum_update(*pskb, - ~*(gre_key(greh)), - tuple->dst.u.gre.key, - *(gre_csum(greh)), 0); + nf_proto_csum_replace4(gre_csum(greh), *pskb, + *(gre_key(greh)), + tuple->dst.u.gre.key, 0); } *(gre_key(greh)) = tuple->dst.u.gre.key; break; diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c index 3f6efc13ac74..75266fe3e0fa 100644 --- a/net/ipv4/netfilter/ip_nat_proto_icmp.c +++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c @@ -66,10 +66,8 @@ icmp_manip_pkt(struct sk_buff **pskb, return 0; hdr = (struct icmphdr *)((*pskb)->data + hdroff); - hdr->checksum = nf_proto_csum_update(*pskb, - hdr->un.echo.id ^ htons(0xFFFF), - tuple->src.u.icmp.id, - hdr->checksum, 0); + nf_proto_csum_replace2(&hdr->checksum, *pskb, + hdr->un.echo.id, tuple->src.u.icmp.id, 0); hdr->un.echo.id = tuple->src.u.icmp.id; return 1; } diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c index 12deb13b93b1..b586d18b3fb3 100644 --- a/net/ipv4/netfilter/ip_nat_proto_tcp.c +++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c @@ -129,9 +129,8 @@ tcp_manip_pkt(struct sk_buff **pskb, if (hdrsize < sizeof(*hdr)) return 1; - hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1); - hdr->check = nf_proto_csum_update(*pskb, oldport ^ htons(0xFFFF), newport, - hdr->check, 0); + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); return 1; } diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c index 82f8a6ab07ec..5ced0877b32f 100644 --- a/net/ipv4/netfilter/ip_nat_proto_udp.c +++ b/net/ipv4/netfilter/ip_nat_proto_udp.c @@ -115,11 +115,8 @@ udp_manip_pkt(struct sk_buff **pskb, } if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { - hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, - hdr->check, 1); - hdr->check = nf_proto_csum_update(*pskb, - *portptr ^ htons(0xFFFF), newport, - hdr->check, 0); + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 0); if (!hdr->check) hdr->check = CSUM_MANGLED_0; } diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 1aa4517fbcdb..b55d670a24df 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -28,17 +28,16 @@ static inline int set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) { struct iphdr *iph = (*pskb)->nh.iph; - u_int16_t oldtos; if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { + __u8 oldtos; if (!skb_make_writable(pskb, sizeof(struct iphdr))) return 0; iph = (*pskb)->nh.iph; oldtos = iph->tos; iph->tos &= ~IPT_ECN_IP_MASK; iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK); - iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF), - htons(iph->tos), iph->check); + nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); } return 1; } @@ -72,10 +71,8 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) if (einfo->operation & IPT_ECN_OP_SET_CWR) tcph->cwr = einfo->proto.tcp.cwr; - tcph->check = nf_proto_csum_update((*pskb), - oldval ^ htons(0xFFFF), - ((__be16 *)tcph)[6], - tcph->check, 0); + nf_proto_csum_replace2(&tcph->check, *pskb, + oldval, ((__be16 *)tcph)[6], 0); return 1; } diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c index 108b6b76311f..93eb5c3c1884 100644 --- a/net/ipv4/netfilter/ipt_TCPMSS.c +++ b/net/ipv4/netfilter/ipt_TCPMSS.c @@ -97,10 +97,8 @@ ipt_tcpmss_target(struct sk_buff **pskb, opt[i+2] = (newmss & 0xff00) >> 8; opt[i+3] = (newmss & 0x00ff); - tcph->check = nf_proto_csum_update(*pskb, - htons(oldmss)^htons(0xFFFF), - htons(newmss), - tcph->check, 0); + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(oldmss), htons(newmss), 0); return IPT_CONTINUE; } } @@ -126,28 +124,22 @@ ipt_tcpmss_target(struct sk_buff **pskb, opt = (u_int8_t *)tcph + sizeof(struct tcphdr); memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); - tcph->check = nf_proto_csum_update(*pskb, - htons(tcplen) ^ htons(0xFFFF), - htons(tcplen + TCPOLEN_MSS), - tcph->check, 1); + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); opt[0] = TCPOPT_MSS; opt[1] = TCPOLEN_MSS; opt[2] = (newmss & 0xff00) >> 8; opt[3] = (newmss & 0x00ff); - tcph->check = nf_proto_csum_update(*pskb, htonl(~0), *((__be32 *)opt), - tcph->check, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0); oldval = ((__be16 *)tcph)[6]; tcph->doff += TCPOLEN_MSS/4; - tcph->check = nf_proto_csum_update(*pskb, - oldval ^ htons(0xFFFF), - ((__be16 *)tcph)[6], - tcph->check, 0); + nf_proto_csum_replace2(&tcph->check, *pskb, + oldval, ((__be16 *)tcph)[6], 0); newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS); - iph->check = nf_csum_update(iph->tot_len ^ htons(0xFFFF), - newtotlen, iph->check); + nf_csum_replace2(&iph->check, iph->tot_len, newtotlen); iph->tot_len = newtotlen; return IPT_CONTINUE; } diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c index 83b80b3a5d2f..18e74ac4d425 100644 --- a/net/ipv4/netfilter/ipt_TOS.c +++ b/net/ipv4/netfilter/ipt_TOS.c @@ -30,16 +30,15 @@ target(struct sk_buff **pskb, { const struct ipt_tos_target_info *tosinfo = targinfo; struct iphdr *iph = (*pskb)->nh.iph; - u_int16_t oldtos; if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { + __u8 oldtos; if (!skb_make_writable(pskb, sizeof(struct iphdr))) return NF_DROP; iph = (*pskb)->nh.iph; oldtos = iph->tos; iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; - iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF), - htons(iph->tos), iph->check); + nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); } return IPT_CONTINUE; } diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c index ac9517d62af0..fffe5ca82e91 100644 --- a/net/ipv4/netfilter/ipt_TTL.c +++ b/net/ipv4/netfilter/ipt_TTL.c @@ -54,9 +54,8 @@ ipt_ttl_target(struct sk_buff **pskb, } if (new_ttl != iph->ttl) { - iph->check = nf_csum_update(htons((iph->ttl << 8)) ^ htons(0xFFFF), - htons(new_ttl << 8), - iph->check); + nf_csum_replace2(&iph->check, htons(iph->ttl << 8), + htons(new_ttl << 8)); iph->ttl = new_ttl; } diff --git a/net/netfilter/core.c b/net/netfilter/core.c index d80b935b3a92..17f9e1cbc73b 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -222,28 +222,21 @@ copy_skb: } EXPORT_SYMBOL(skb_make_writable); -u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval, u_int32_t csum) -{ - u_int32_t diff[] = { oldval, newval }; - - return csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum)); -} -EXPORT_SYMBOL(nf_csum_update); - -u_int16_t nf_proto_csum_update(struct sk_buff *skb, - u_int32_t oldval, u_int32_t newval, - u_int16_t csum, int pseudohdr) +void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, + __be32 from, __be32 to, int pseudohdr) { + __be32 diff[] = { ~from, to }; if (skb->ip_summed != CHECKSUM_PARTIAL) { - csum = nf_csum_update(oldval, newval, csum); + *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), + ~csum_unfold(*sum))); if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) - skb->csum = nf_csum_update(oldval, newval, skb->csum); + skb->csum = ~csum_partial((char *)diff, sizeof(diff), + ~skb->csum); } else if (pseudohdr) - csum = ~nf_csum_update(oldval, newval, ~csum); - - return csum; + *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff), + csum_unfold(*sum))); } -EXPORT_SYMBOL(nf_proto_csum_update); +EXPORT_SYMBOL(nf_proto_csum_replace4); /* This does not belong here, but locally generated errors need it if connection tracking in use: without this, connection may not be in hash table, and hence -- cgit v1.2.3 From 1f61ab5ca5cca939a6509892d84b34849e155036 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:44:08 -0800 Subject: [NET]: Preliminaty annotation of skb->csum. It's still not completely right; we need to split it into anon unions of __wsum and unsigned - for cases when we use it for partial checksum and for offset of checksum in skb Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 41753667541d..fcab543d79ac 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -273,8 +273,8 @@ struct sk_buff { unsigned int len, data_len, - mac_len, - csum; + mac_len; + __wsum csum; __u32 priority; __u8 local_df:1, cloned:1, -- cgit v1.2.3 From bac0dff6cd194f7a28f7e840c9b6a7aa71c6ef97 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 19 Nov 2006 14:15:05 -0800 Subject: [BNX2]: Add 5709 PCI ID. Add PCI ID and detection for 5709 copper and SerDes chips. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 13 +++++++++++-- include/linux/pci_ids.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 92897efbc263..157463b4fa9f 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -86,6 +86,7 @@ typedef enum { NC370F, BCM5708, BCM5708S, + BCM5709, } board_t; /* indexed by board_t, above */ @@ -99,6 +100,7 @@ static const struct { { "HP NC370F Multifunction Gigabit Server Adapter" }, { "Broadcom NetXtreme II BCM5708 1000Base-T" }, { "Broadcom NetXtreme II BCM5708 1000Base-SX" }, + { "Broadcom NetXtreme II BCM5709 1000Base-T" }, }; static struct pci_device_id bnx2_pci_tbl[] = { @@ -116,6 +118,8 @@ static struct pci_device_id bnx2_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 }, { 0, } }; @@ -5854,10 +5858,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->phy_addr = 1; /* Disable WOL support if we are running on a SERDES chip. */ - if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) { + if (CHIP_NUM(bp) == CHIP_NUM_5709) { + if (CHIP_BOND_ID(bp) != BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C) + bp->phy_flags |= PHY_SERDES_FLAG; + } else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) bp->phy_flags |= PHY_SERDES_FLAG; + + if (bp->phy_flags & PHY_SERDES_FLAG) { bp->flags |= NO_WOL_FLAG; - if (CHIP_NUM(bp) == CHIP_NUM_5708) { + if (CHIP_NUM(bp) != CHIP_NUM_5706) { bp->phy_addr = 2; reg = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index fd5033b8a927..c09da1e30c54 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1897,6 +1897,7 @@ #define PCI_VENDOR_ID_BROADCOM 0x14e4 #define PCI_DEVICE_ID_TIGON3_5752 0x1600 #define PCI_DEVICE_ID_TIGON3_5752M 0x1601 +#define PCI_DEVICE_ID_NX2_5709 0x1639 #define PCI_DEVICE_ID_TIGON3_5700 0x1644 #define PCI_DEVICE_ID_TIGON3_5701 0x1645 #define PCI_DEVICE_ID_TIGON3_5702 0x1646 -- cgit v1.2.3 From 82e3ab9dbeebd5c8d5402ad1607d22086271a56d Mon Sep 17 00:00:00 2001 From: Ian McDonald Date: Mon, 20 Nov 2006 19:19:32 -0200 Subject: [DCCP]: Adds the tx buffer sysctls This one got lost on the way from Ian to Gerrit to me, fix it. Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- Documentation/networking/dccp.txt | 4 ++++ include/linux/sysctl.h | 1 + net/dccp/sysctl.c | 9 +++++++++ 3 files changed, 14 insertions(+) (limited to 'include/linux') diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index 1910d097a0ad..dda15886bcb5 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -100,6 +100,10 @@ rx_ccid = 2 seq_window = 100 The initial sequence window (sec. 7.5.2). +tx_qlen = 5 + The size of the transmit buffer in packets. A value of 0 corresponds + to an unbounded transmit buffer. + Notes ===== diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 2e8c5ad82793..61dd99c6c2a5 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -617,6 +617,7 @@ enum { NET_DCCP_DEFAULT_REQ_RETRIES = 7, NET_DCCP_DEFAULT_RETRIES1 = 8, NET_DCCP_DEFAULT_RETRIES2 = 9, + NET_DCCP_DEFAULT_TX_QLEN = 10, }; /* /proc/sys/net/ipx */ diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index 8b62061e5701..4775ba3faa04 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c @@ -91,6 +91,15 @@ static struct ctl_table dccp_default_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .ctl_name = NET_DCCP_DEFAULT_TX_QLEN, + .procname = "tx_qlen", + .data = &sysctl_dccp_tx_qlen, + .maxlen = sizeof(sysctl_dccp_tx_qlen), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { .ctl_name = 0, } }; -- cgit v1.2.3 From f3ffaf14681e3cad61006873be8656ab41b793e0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 16:59:12 -0800 Subject: [SCTP]: Annotate SCTP headers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/sctp.h | 72 ++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sctp.h b/include/linux/sctp.h index 6ec66dec29f7..35108fe7a686 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -57,17 +57,17 @@ /* Section 3.1. SCTP Common Header Format */ typedef struct sctphdr { - __u16 source; - __u16 dest; - __u32 vtag; - __u32 checksum; + __be16 source; + __be16 dest; + __be32 vtag; + __be32 checksum; } __attribute__((packed)) sctp_sctphdr_t; /* Section 3.2. Chunk Field Descriptions. */ typedef struct sctp_chunkhdr { __u8 type; __u8 flags; - __u16 length; + __be16 length; } __attribute__((packed)) sctp_chunkhdr_t; @@ -153,8 +153,8 @@ enum { SCTP_CHUNK_FLAG_T = 0x01 }; */ typedef struct sctp_paramhdr { - __u16 type; - __u16 length; + __be16 type; + __be16 length; } __attribute__((packed)) sctp_paramhdr_t; typedef enum { @@ -203,10 +203,10 @@ enum { SCTP_PARAM_ACTION_MASK = __constant_htons(0xc000), }; /* RFC 2960 Section 3.3.1 Payload Data (DATA) (0) */ typedef struct sctp_datahdr { - __u32 tsn; - __u16 stream; - __u16 ssn; - __u32 ppid; + __be32 tsn; + __be16 stream; + __be16 ssn; + __be32 ppid; __u8 payload[0]; } __attribute__((packed)) sctp_datahdr_t; @@ -232,11 +232,11 @@ enum { SCTP_DATA_FRAG_MASK = 0x03, }; * endpoints. */ typedef struct sctp_inithdr { - __u32 init_tag; - __u32 a_rwnd; - __u16 num_outbound_streams; - __u16 num_inbound_streams; - __u32 initial_tsn; + __be32 init_tag; + __be32 a_rwnd; + __be16 num_outbound_streams; + __be16 num_inbound_streams; + __be32 initial_tsn; __u8 params[0]; } __attribute__((packed)) sctp_inithdr_t; @@ -261,7 +261,7 @@ typedef struct sctp_ipv6addr_param { /* Section 3.3.2.1 Cookie Preservative (9) */ typedef struct sctp_cookie_preserve_param { sctp_paramhdr_t param_hdr; - uint32_t lifespan_increment; + __be32 lifespan_increment; } __attribute__((packed)) sctp_cookie_preserve_param_t; /* Section 3.3.2.1 Host Name Address (11) */ @@ -273,7 +273,7 @@ typedef struct sctp_hostname_param { /* Section 3.3.2.1 Supported Address Types (12) */ typedef struct sctp_supported_addrs_param { sctp_paramhdr_t param_hdr; - uint16_t types[0]; + __be16 types[0]; } __attribute__((packed)) sctp_supported_addrs_param_t; /* Appendix A. ECN Capable (32768) */ @@ -284,7 +284,7 @@ typedef struct sctp_ecn_capable_param { /* ADDIP Section 3.2.6 Adaption Layer Indication */ typedef struct sctp_adaption_ind_param { struct sctp_paramhdr param_hdr; - __u32 adaption_ind; + __be32 adaption_ind; } __attribute__((packed)) sctp_adaption_ind_param_t; /* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): @@ -316,11 +316,11 @@ typedef struct sctp_unrecognized_param { */ typedef struct sctp_gap_ack_block { - __u16 start; - __u16 end; + __be16 start; + __be16 end; } __attribute__((packed)) sctp_gap_ack_block_t; -typedef uint32_t sctp_dup_tsn_t; +typedef __be32 sctp_dup_tsn_t; typedef union { sctp_gap_ack_block_t gab; @@ -328,10 +328,10 @@ typedef union { } sctp_sack_variable_t; typedef struct sctp_sackhdr { - __u32 cum_tsn_ack; - __u32 a_rwnd; - __u16 num_gap_ack_blocks; - __u16 num_dup_tsns; + __be32 cum_tsn_ack; + __be32 a_rwnd; + __be16 num_gap_ack_blocks; + __be16 num_dup_tsns; sctp_sack_variable_t variable[0]; } __attribute__((packed)) sctp_sackhdr_t; @@ -371,7 +371,7 @@ typedef struct sctp_abort_chunk { * and the highest consecutive acking value. */ typedef struct sctp_shutdownhdr { - __u32 cum_tsn_ack; + __be32 cum_tsn_ack; } __attribute__((packed)) sctp_shutdownhdr_t; struct sctp_shutdown_chunk_t { @@ -382,8 +382,8 @@ struct sctp_shutdown_chunk_t { /* RFC 2960. Section 3.3.10 Operation Error (ERROR) (9) */ typedef struct sctp_errhdr { - __u16 cause; - __u16 length; + __be16 cause; + __be16 length; __u8 variable[0]; } __attribute__((packed)) sctp_errhdr_t; @@ -462,7 +462,7 @@ typedef enum { * Explicit Congestion Notification Echo (ECNE) (12) */ typedef struct sctp_ecnehdr { - __u32 lowest_tsn; + __be32 lowest_tsn; } sctp_ecnehdr_t; typedef struct sctp_ecne_chunk { @@ -474,7 +474,7 @@ typedef struct sctp_ecne_chunk { * Congestion Window Reduced (CWR) (13) */ typedef struct sctp_cwrhdr { - __u32 lowest_tsn; + __be32 lowest_tsn; } sctp_cwrhdr_t; typedef struct sctp_cwr_chunk { @@ -529,12 +529,12 @@ typedef struct sctp_cwr_chunk { * chunks this field MUST be filled in. */ struct sctp_fwdtsn_skip { - __u16 stream; - __u16 ssn; + __be16 stream; + __be16 ssn; } __attribute__((packed)); struct sctp_fwdtsn_hdr { - __u32 new_cum_tsn; + __be32 new_cum_tsn; struct sctp_fwdtsn_skip skip[0]; } __attribute((packed)); @@ -578,11 +578,11 @@ struct sctp_fwdtsn_chunk { */ typedef struct sctp_addip_param { sctp_paramhdr_t param_hdr; - __u32 crr_id; + __be32 crr_id; } __attribute__((packed)) sctp_addip_param_t; typedef struct sctp_addiphdr { - __u32 serial; + __be32 serial; __u8 params[0]; } __attribute__((packed)) sctp_addiphdr_t; -- cgit v1.2.3 From 962c837275e8a8c1df41f1882e971636093cdee4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 17:26:08 -0800 Subject: [SCTP]: Netfilter sctp annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sctp.h | 2 +- net/netfilter/xt_sctp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sctp.h b/include/linux/netfilter/nf_conntrack_sctp.h index b8994d9fd1a9..5cf2c115cce4 100644 --- a/include/linux/netfilter/nf_conntrack_sctp.h +++ b/include/linux/netfilter/nf_conntrack_sctp.h @@ -20,7 +20,7 @@ struct ip_ct_sctp { enum sctp_conntrack state; - u_int32_t vtag[IP_CT_DIR_MAX]; + __be32 vtag[IP_CT_DIR_MAX]; u_int32_t ttag[IP_CT_DIR_MAX]; }; diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index 7956acaaa24b..71bf036f833c 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c @@ -71,7 +71,7 @@ match_packet(const struct sk_buff *skb, duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", ++i, offset, sch->type, htons(sch->length), sch->flags); - offset += (htons(sch->length) + 3) & ~3; + offset += (ntohs(sch->length) + 3) & ~3; duprintf("skb->len: %d\toffset: %d\n", skb->len, offset); -- cgit v1.2.3 From ff1dcadb1b55dbf471c5ed109dbbdf06bd19ef3b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 18:07:29 -0800 Subject: [NET]: Split skb->csum ... into anonymous union of __wsum and __u32 (csum and csum_offset resp.) Signed-off-by: Al Viro Signed-off-by: David S. Miller --- drivers/net/cassini.c | 2 +- drivers/net/e1000/e1000_main.c | 2 +- drivers/net/ixgb/ixgb_main.c | 2 +- drivers/net/myri10ge/myri10ge.c | 2 +- drivers/net/sk98lin/skge.c | 4 ++-- drivers/net/skge.c | 2 +- drivers/net/sky2.c | 2 +- drivers/net/sungem.c | 2 +- drivers/net/sunhme.c | 2 +- include/linux/skbuff.h | 5 ++++- net/core/dev.c | 4 ++-- net/core/skbuff.c | 2 +- net/ipv4/tcp_ipv4.c | 4 ++-- net/ipv4/udp.c | 2 +- net/ipv6/tcp_ipv6.c | 4 ++-- 15 files changed, 22 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 521c5b71023c..fd2cc13f7d97 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2825,7 +2825,7 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring, u64 csum_start_off, csum_stuff_off; csum_start_off = (u64) (skb->h.raw - skb->data); - csum_stuff_off = (u64) ((skb->h.raw + skb->csum) - skb->data); + csum_stuff_off = csum_start_off + skb->csum_offset; ctrl = TX_DESC_CSUM_EN | CAS_BASE(TX_DESC_CSUM_START, csum_start_off) | diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7a0828869ecf..32dde0adb683 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2826,7 +2826,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, context_desc = E1000_CONTEXT_DESC(*tx_ring, i); context_desc->upper_setup.tcp_fields.tucss = css; - context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; + context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index e09f575a3a38..7b127212e62b 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1249,7 +1249,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb) if(likely(skb->ip_summed == CHECKSUM_PARTIAL)) { struct ixgb_buffer *buffer_info; css = skb->h.raw - skb->data; - cso = (skb->h.raw + skb->csum) - skb->data; + cso = css + skb->csum_offset; i = adapter->tx_ring.next_to_use; context_desc = IXGB_CONTEXT_DESC(adapter->tx_ring, i); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 806081b59733..36350e6db1c1 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1955,7 +1955,7 @@ again: flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST); if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { cksum_offset = (skb->h.raw - skb->data); - pseudo_hdr_offset = (skb->h.raw + skb->csum) - skb->data; + pseudo_hdr_offset = cksum_offset + skb->csum_offset; /* If the headers are excessively large, then we must * fall back to a software checksum */ if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) { diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index a5d41ebc9fb4..12cbfd190dd7 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -1562,7 +1562,7 @@ struct sk_buff *pMessage) /* pointer to send-message */ if (pMessage->ip_summed == CHECKSUM_PARTIAL) { u16 hdrlen = pMessage->h.raw - pMessage->data; - u16 offset = hdrlen + pMessage->csum; + u16 offset = hdrlen + pMessage->csum_offset; if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) && (pAC->GIni.GIChipRev == 0) && @@ -1681,7 +1681,7 @@ struct sk_buff *pMessage) /* pointer to send-message */ */ if (pMessage->ip_summed == CHECKSUM_PARTIAL) { u16 hdrlen = pMessage->h.raw - pMessage->data; - u16 offset = hdrlen + pMessage->csum; + u16 offset = hdrlen + pMessage->csum_offset; Control = BMU_STFWD; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 27b537c8d5e3..5513907e8393 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2565,7 +2565,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) td->csum_offs = 0; td->csum_start = offset; - td->csum_write = offset + skb->csum; + td->csum_write = offset + skb->csum_offset; } else control = BMU_CHECK; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 0ef1848b9761..842abd9396c6 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1350,7 +1350,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) u32 tcpsum; tcpsum = offset << 16; /* sum start */ - tcpsum |= offset + skb->csum; /* sum write */ + tcpsum |= offset + skb->csum_offset; /* sum write */ ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; if (skb->nh.iph->protocol == IPPROTO_UDP) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 253e96e7ad20..334c6cfd6595 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1030,7 +1030,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) u64 csum_start_off, csum_stuff_off; csum_start_off = (u64) (skb->h.raw - skb->data); - csum_stuff_off = (u64) ((skb->h.raw + skb->csum) - skb->data); + csum_stuff_off = csum_start_off + skb->csum_offset; ctrl = (TXDCTRL_CENAB | (csum_start_off << 15) | diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 9d7cd130c19d..ec432ea879fb 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2272,7 +2272,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 csum_start_off, csum_stuff_off; csum_start_off = (u32) (skb->h.raw - skb->data); - csum_stuff_off = (u32) ((skb->h.raw + skb->csum) - skb->data); + csum_stuff_off = csum_start_off + skb->csum_offset; tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE | ((csum_start_off << 14) & TXFLAG_CSBUFBEGIN) | diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index fcab543d79ac..14ec16d2d9ba 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -274,7 +274,10 @@ struct sk_buff { unsigned int len, data_len, mac_len; - __wsum csum; + union { + __wsum csum; + __u32 csum_offset; + }; __u32 priority; __u8 local_df:1, cloned:1, diff --git a/net/core/dev.c b/net/core/dev.c index 1a36b17f4b51..59d058a3b504 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1191,9 +1191,9 @@ int skb_checksum_help(struct sk_buff *skb) offset = skb->tail - skb->h.raw; BUG_ON(offset <= 0); - BUG_ON(skb->csum + 2 > offset); + BUG_ON(skb->csum_offset + 2 > offset); - *(__sum16*)(skb->h.raw + skb->csum) = csum_fold(csum); + *(__sum16*)(skb->h.raw + skb->csum_offset) = csum_fold(csum); out_set_summed: skb->ip_summed = CHECKSUM_NONE; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 07c25d601922..a90bc439488e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1414,7 +1414,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) skb->len - csstart, 0); if (skb->ip_summed == CHECKSUM_PARTIAL) { - long csstuff = csstart + skb->csum; + long csstuff = csstart + skb->csum_offset; *((__sum16 *)(to + csstuff)) = csum_fold(csum); } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index e9d467124c4d..4913f25e5ad5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -504,7 +504,7 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) if (skb->ip_summed == CHECKSUM_PARTIAL) { th->check = ~tcp_v4_check(th, len, inet->saddr, inet->daddr, 0); - skb->csum = offsetof(struct tcphdr, check); + skb->csum_offset = offsetof(struct tcphdr, check); } else { th->check = tcp_v4_check(th, len, inet->saddr, inet->daddr, csum_partial((char *)th, @@ -526,7 +526,7 @@ int tcp_v4_gso_send_check(struct sk_buff *skb) th->check = 0; th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); - skb->csum = offsetof(struct tcphdr, check); + skb->csum_offset = offsetof(struct tcphdr, check); skb->ip_summed = CHECKSUM_PARTIAL; return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 28e4cf662ce0..1807a30694d9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -422,7 +422,7 @@ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, /* * Only one fragment on the socket. */ - skb->csum = offsetof(struct udphdr, check); + skb->csum_offset = offsetof(struct udphdr, check); uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); } else { /* diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 0adb337c4b7e..517c50024bfc 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -948,7 +948,7 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) if (skb->ip_summed == CHECKSUM_PARTIAL) { th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); - skb->csum = offsetof(struct tcphdr, check); + skb->csum_offset = offsetof(struct tcphdr, check); } else { th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, csum_partial((char *)th, th->doff<<2, @@ -970,7 +970,7 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) th->check = 0; th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, IPPROTO_TCP, 0); - skb->csum = offsetof(struct tcphdr, check); + skb->csum_offset = offsetof(struct tcphdr, check); skb->ip_summed = CHECKSUM_PARTIAL; return 0; } -- cgit v1.2.3 From d61c167dd0797a16584f7a922dd5d50efad1d28a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 27 Nov 2006 12:31:45 -0200 Subject: [NET]: Add documentation for TFRC structures This adds documentation for the TFRC structure fields. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/tfrc.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tfrc.h b/include/linux/tfrc.h index 7dab7831c3cb..31a9b25276fe 100644 --- a/include/linux/tfrc.h +++ b/include/linux/tfrc.h @@ -1,7 +1,8 @@ #ifndef _LINUX_TFRC_H_ #define _LINUX_TFRC_H_ /* - * include/linux/tfrc.h + * TFRC - Data Structures for the TCP-Friendly Rate Control congestion + * control mechanism as specified in RFC 3448. * * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. * Copyright (c) 2005 Ian McDonald @@ -13,15 +14,30 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ - #include +/** tfrc_rx_info - TFRC Receiver Data Structure + * + * @tfrcrx_x_recv: receiver estimate of sending rate (3.2.2) + * @tfrcrx_rtt: round-trip-time (communicated by sender) + * @tfrcrx_p: current estimate of loss event rate (3.2.2) + */ struct tfrc_rx_info { __u32 tfrcrx_x_recv; __u32 tfrcrx_rtt; __u32 tfrcrx_p; }; +/** tfrc_tx_info - TFRC Sender Data Structure + * + * @tfrctx_x: computed transmit rate (4.3 (4)) + * @tfrctx_x_recv: receiver estimate of send rate (4.3) + * @tfrctx_x_calc: return value of throughput equation (3.1) + * @tfrctx_rtt: (moving average) estimate of RTT (4.3) + * @tfrctx_p: current loss event rate (5.4) + * @tfrctx_rto: estimate of RTO, equals 4*RTT (4.3) + * @tfrctx_ipi: inter-packet interval (4.6) + */ struct tfrc_tx_info { __u32 tfrctx_x; __u32 tfrctx_x_recv; -- cgit v1.2.3 From 4e9b82693542003b028c8494e9e3c49615b91ce7 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 27 Nov 2006 09:25:58 -0800 Subject: [NETLINK]: Remove unused dst_pid field in netlink_skb_parms The destination PID is passed directly to netlink_unicast() respectively netlink_multicast(). Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/netlink.h | 1 - net/decnet/dn_route.c | 2 -- net/ipv4/fib_frontend.c | 1 - net/ipv4/netfilter/ip_conntrack_netlink.c | 4 +--- net/netfilter/nf_conntrack_netlink.c | 4 +--- net/netlink/af_netlink.c | 1 - net/xfrm/xfrm_user.c | 2 -- 7 files changed, 2 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netlink.h b/include/linux/netlink.h index e61e1e138421..b3b9b609ee89 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -141,7 +141,6 @@ struct netlink_skb_parms { struct ucred creds; /* Skb credentials */ __u32 pid; - __u32 dst_pid; __u32 dst_group; kernel_cap_t eff_cap; __u32 loginuid; /* Login (audit) uid */ diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index f759d6f422ea..4eb985236aee 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1592,8 +1592,6 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; - NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; - err = dn_rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0, 0); if (err == 0) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 14025345cc56..d47b72af89ed 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -811,7 +811,6 @@ static void nl_fib_input(struct sock *sk, int len) pid = nlh->nlmsg_pid; /*pid of sending process */ NETLINK_CB(skb).pid = 0; /* from kernel */ - NETLINK_CB(skb).dst_pid = pid; NETLINK_CB(skb).dst_group = 0; /* unicast */ netlink_unicast(sk, skb, pid, MSG_DONTWAIT); } diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 55f0ae641081..1bb8ed33c5bc 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -743,7 +743,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, ip_conntrack_put(ct); return -ENOMEM; } - NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_CT_NEW, 1, ct); @@ -1273,8 +1272,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb2) goto out; - NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; - + err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, 1, exp); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index ab67c2be2b5d..cfb35fd8d9b9 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -752,7 +752,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, nf_ct_put(ct); return -ENOMEM; } - NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_CT_NEW, 1, ct); @@ -1300,8 +1299,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb2) goto out; - NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; - + err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, 1, exp); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index f61d81b3c61c..3baafb10f8f3 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1153,7 +1153,6 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; NETLINK_CB(skb).pid = nlk->pid; - NETLINK_CB(skb).dst_pid = dst_pid; NETLINK_CB(skb).dst_group = dst_group; NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context); selinux_get_task_sid(current, &(NETLINK_CB(skb).sid)); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 6c4d2f49d9e5..8dbb38b91de2 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -650,7 +650,6 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, if (!skb) return ERR_PTR(-ENOMEM); - NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; info.in_skb = in_skb; info.out_skb = skb; info.nlmsg_seq = seq; @@ -1168,7 +1167,6 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, if (!skb) return ERR_PTR(-ENOMEM); - NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; info.in_skb = in_skb; info.out_skb = skb; info.nlmsg_seq = seq; -- cgit v1.2.3 From e3703b3de1f049b38733ba520e5038f23063068e Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 27 Nov 2006 09:27:07 -0800 Subject: [RTNETLINK]: Add rtnl_put_cacheinfo() to unify some code IPv4, IPv6, and DECNet all use struct rta_cacheinfo in a similiar way, therefore rtnl_put_cacheinfo() is added to reuse code. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 3 +++ net/core/rtnetlink.c | 20 ++++++++++++++++++++ net/decnet/dn_route.c | 16 +++++----------- net/ipv4/route.c | 26 +++++++++++--------------- net/ipv6/route.c | 19 ++++++------------- 5 files changed, 45 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 33b3d0ab3a91..493297acdae8 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -585,6 +585,9 @@ extern int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group, struct nlmsghdr *nlh, gfp_t flags); extern void rtnl_set_sk_err(u32 group, int error); extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics); +extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, + u32 id, u32 ts, u32 tsage, long expires, + u32 error); extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 0cb4d9e53a07..e76539a5eb5e 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -212,6 +212,26 @@ nla_put_failure: return nla_nest_cancel(skb, mx); } +int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, + u32 ts, u32 tsage, long expires, u32 error) +{ + struct rta_cacheinfo ci = { + .rta_lastuse = jiffies_to_clock_t(jiffies - dst->lastuse), + .rta_used = dst->__use, + .rta_clntref = atomic_read(&(dst->__refcnt)), + .rta_error = error, + .rta_id = id, + .rta_ts = ts, + .rta_tsage = tsage, + }; + + if (expires) + ci.rta_expires = jiffies_to_clock_t(expires); + + return nla_put(skb, RTA_CACHEINFO, sizeof(ci), &ci); +} + +EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); static void set_operstate(struct net_device *dev, unsigned char transition) { diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 4eb985236aee..9881933167bd 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1469,7 +1469,7 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, struct rtmsg *r; struct nlmsghdr *nlh; unsigned char *b = skb->tail; - struct rta_cacheinfo ci; + long expires; nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags); r = NLMSG_DATA(nlh); @@ -1502,16 +1502,10 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway); if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) goto rtattr_failure; - ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); - ci.rta_used = rt->u.dst.__use; - ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); - if (rt->u.dst.expires) - ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies); - else - ci.rta_expires = 0; - ci.rta_error = rt->u.dst.error; - ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; - RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); + expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0; + if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0, expires, + rt->u.dst.error) < 0) + goto rtattr_failure; if (rt->fl.iif) RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ee00b6506ab4..9f3924c4905e 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2629,7 +2629,8 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, struct rtable *rt = (struct rtable*)skb->dst; struct rtmsg *r; struct nlmsghdr *nlh; - struct rta_cacheinfo ci; + long expires; + u32 id = 0, ts = 0, tsage = 0, error; nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags); if (nlh == NULL) @@ -2676,20 +2677,13 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) goto nla_put_failure; - ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); - ci.rta_used = rt->u.dst.__use; - ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); - if (rt->u.dst.expires) - ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies); - else - ci.rta_expires = 0; - ci.rta_error = rt->u.dst.error; - ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; + error = rt->u.dst.error; + expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0; if (rt->peer) { - ci.rta_id = rt->peer->ip_id_count; + id = rt->peer->ip_id_count; if (rt->peer->tcp_ts_stamp) { - ci.rta_ts = rt->peer->tcp_ts; - ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; + ts = rt->peer->tcp_ts; + tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; } } @@ -2708,7 +2702,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, } else { if (err == -EMSGSIZE) goto nla_put_failure; - ci.rta_error = err; + error = err; } } } else @@ -2716,7 +2710,9 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif); } - NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); + if (rtnl_put_cacheinfo(skb, &rt->u.dst, id, ts, tsage, + expires, error) < 0) + goto nla_put_failure; return nlmsg_end(skb, nlh); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0bf17a3cf085..9f80518aacbd 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2027,7 +2027,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, { struct rtmsg *rtm; struct nlmsghdr *nlh; - struct rta_cacheinfo ci; + long expires; u32 table; if (prefix) { /* user wants prefix routes only */ @@ -2101,18 +2101,11 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric); - ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); - if (rt->rt6i_expires) - ci.rta_expires = jiffies_to_clock_t(rt->rt6i_expires - jiffies); - else - ci.rta_expires = 0; - ci.rta_used = rt->u.dst.__use; - ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); - ci.rta_error = rt->u.dst.error; - ci.rta_id = 0; - ci.rta_ts = 0; - ci.rta_tsage = 0; - NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); + + expires = rt->rt6i_expires ? rt->rt6i_expires - jiffies : 0; + if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0, + expires, rt->u.dst.error) < 0) + goto nla_put_failure; return nlmsg_end(skb, nlh); -- cgit v1.2.3 From d5c42c0ec4f7fd5a4e19e33a2d561758b67c55c8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 27 Nov 2006 17:58:02 -0200 Subject: [NET]: Pack struct hh_cache [acme@newtoy net-2.6.20]$ pahole net/ipv4/tcp.o hh_cache /* /pub/scm/linux/kernel/git/acme/net-2.6.20/include/linux/netdevice.h:190 */ struct hh_cache { struct hh_cache * hh_next; /* 0 4 */ atomic_t hh_refcnt; /* 4 4 */ __be16 hh_type; /* 8 2 */ /* XXX 2 bytes hole, try to pack */ int hh_len; /* 12 4 */ int (*hh_output)(); /* 16 4 */ rwlock_t hh_lock; /* 20 36 */ long unsigned int hh_data[24]; /* 56 96 */ }; /* size: 152, sum members: 150, holes: 1, sum holes: 2 */ [acme@newtoy net-2.6.20]$ find net -name "*.[ch]" | xargs grep 'hh_len.\+=' | sort -u net/atm/br2684.c: hh->hh_len = PADLEN + ETH_HLEN; net/ethernet/eth.c: hh->hh_len = ETH_HLEN; net/ipv4/ipconfig.c: int hh_len = LL_RESERVED_SPACE(dev); net/ipv4/ip_output.c: hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); net/ipv4/ip_output.c: int hh_len = LL_RESERVED_SPACE(dev); net/ipv4/netfilter.c: hh_len = (*pskb)->dst->dev->hard_header_len; net/ipv4/raw.c: hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); net/ipv6/ip6_output.c: hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); net/ipv6/netfilter/ip6t_REJECT.c: hh_len = (dst->dev->hard_header_len + 15)&~15; net/ipv6/raw.c: hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); [acme@newtoy net-2.6.20]$ [acme@newtoy net-2.6.20]$ find include -name "*.h" | xargs grep 'define ETH_HLEN' include/linux/if_ether.h:#define ETH_HLEN 14 /* Total octets in header. */ (((dev)->hard_header_len&~(HH_DATA_MOD - 1)) + HH_DATA_MOD) [acme@newtoy net-2.6.20]$ pahole net/ipv4/tcp.o net_device | grep hard_header_len short unsigned int hard_header_len; /* 106 2 */ [acme@newtoy net-2.6.20]$ So I think we're safe in turning hh_len an u16, end result: [acme@newtoy net-2.6.20]$ codiff -sV /tmp/tcp.o.before net/ipv4/tcp.o /pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv4/tcp.c: struct hh_cache | -4 hh_len; from: int /* 12(0) 4(0) */ to: u16 /* 10(0) 2(0) */ 1 struct changed [acme@newtoy net-2.6.20]$ Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/netdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index caa3c2593719..949eada46ce1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -196,7 +196,7 @@ struct hh_cache * NOTE: For VLANs, this will be the * encapuslated type. --BLG */ - int hh_len; /* length of header */ + u16 hh_len; /* length of header */ int (*hh_output)(struct sk_buff *skb); rwlock_t hh_lock; -- cgit v1.2.3 From 2ff52f282cf287d60e9eda1f3b5ec83e00a86130 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 28 Nov 2006 00:48:32 -0200 Subject: [TCP]: Change tcp_header_len member in tcp_sock to u16 With this we eliminate the last hole in struct tcp_sock. End result: [acme@newtoy net-2.6.20]$ codiff -sV /tmp/tcp.o.before net/ipv4/tcp.o /pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv4/tcp.c: struct tcp_sock | -4 tcp_header_len; from: int /* 1000(0) 4(0) */ to: u16 /* 1000(0) 2(0) */ 1 struct changed [acme@newtoy net-2.6.20]$ Now sizeof(tcp_sock) is just... [acme@newtoy net-2.6.20]$ pahole --sizes ../OUTPUT/qemu/net-2.6.20/net/ipv4/tcp.o | grep -w tcp_sock struct tcp_sock: 1500 0 1500 bytes ;-) Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/tcp.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index dd61b172ac68..b42ff0efc2df 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -227,7 +227,8 @@ static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) struct tcp_sock { /* inet_connection_sock has to be the first member of tcp_sock */ struct inet_connection_sock inet_conn; - int tcp_header_len; /* Bytes of tcp header to send */ + u16 tcp_header_len; /* Bytes of tcp header to send */ + u16 xmit_size_goal; /* Goal for segmenting output packets */ /* * Header prediction flags @@ -268,8 +269,6 @@ struct tcp_sock { __u32 snd_wnd; /* The window we expect to receive */ __u32 max_window; /* Maximal window ever seen from peer */ __u32 mss_cache; /* Cached effective mss, not including SACKS */ - __u16 xmit_size_goal; /* Goal for segmenting output packets */ - /* XXX Two bytes hole, try to pack */ __u32 window_clamp; /* Maximal window to advertise */ __u32 rcv_ssthresh; /* Current window clamp */ -- cgit v1.2.3 From 3a137d2065571864be0301b9ebd72ddb01060997 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 28 Nov 2006 01:12:38 -0200 Subject: [TCP]: Renove the __ prefix on the struct tcp_sock members As this struct is not userland visible at all. Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/tcp.h | 156 ++++++++++++++++++++++++++-------------------------- 1 file changed, 78 insertions(+), 78 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index b42ff0efc2df..3cc70d1a3504 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -185,17 +185,17 @@ struct tcp_sack_block_wire { }; struct tcp_sack_block { - __u32 start_seq; - __u32 end_seq; + u32 start_seq; + u32 end_seq; }; struct tcp_options_received { /* PAWS/RTTM data */ long ts_recent_stamp;/* Time we stored ts_recent (for aging) */ - __u32 ts_recent; /* Time stamp to echo next */ - __u32 rcv_tsval; /* Time stamp value */ - __u32 rcv_tsecr; /* Time stamp echo reply */ - __u16 saw_tstamp : 1, /* Saw TIMESTAMP on last packet */ + u32 ts_recent; /* Time stamp to echo next */ + u32 rcv_tsval; /* Time stamp value */ + u32 rcv_tsecr; /* Time stamp echo reply */ + u16 saw_tstamp : 1, /* Saw TIMESTAMP on last packet */ tstamp_ok : 1, /* TIMESTAMP seen on SYN packet */ dsack : 1, /* D-SACK is scheduled */ wscale_ok : 1, /* Wscale seen on SYN packet */ @@ -203,10 +203,10 @@ struct tcp_options_received { snd_wscale : 4, /* Window scaling received from sender */ rcv_wscale : 4; /* Window scaling to send to receiver */ /* SACKs data */ - __u8 eff_sacks; /* Size of SACK array to send with next packet */ - __u8 num_sacks; /* Number of SACK blocks */ - __u16 user_mss; /* mss requested by user in ioctl */ - __u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ + u8 eff_sacks; /* Size of SACK array to send with next packet */ + u8 num_sacks; /* Number of SACK blocks */ + u16 user_mss; /* mss requested by user in ioctl */ + u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ }; struct tcp_request_sock { @@ -215,8 +215,8 @@ struct tcp_request_sock { /* Only used by TCP MD5 Signature so far. */ struct tcp_request_sock_ops *af_specific; #endif - __u32 rcv_isn; - __u32 snt_isn; + u32 rcv_isn; + u32 snt_isn; }; static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) @@ -241,13 +241,13 @@ struct tcp_sock { * read the code and the spec side by side (and laugh ...) * See RFC793 and RFC1122. The RFC writes these in capitals. */ - __u32 rcv_nxt; /* What we want to receive next */ - __u32 snd_nxt; /* Next sequence we send */ + u32 rcv_nxt; /* What we want to receive next */ + u32 snd_nxt; /* Next sequence we send */ - __u32 snd_una; /* First byte we want an ack for */ - __u32 snd_sml; /* Last byte of the most recently transmitted small packet */ - __u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ - __u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ + u32 snd_una; /* First byte we want an ack for */ + u32 snd_sml; /* Last byte of the most recently transmitted small packet */ + u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ + u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ /* Data for direct copy to user */ struct { @@ -265,30 +265,30 @@ struct tcp_sock { #endif } ucopy; - __u32 snd_wl1; /* Sequence for window update */ - __u32 snd_wnd; /* The window we expect to receive */ - __u32 max_window; /* Maximal window ever seen from peer */ - __u32 mss_cache; /* Cached effective mss, not including SACKS */ + u32 snd_wl1; /* Sequence for window update */ + u32 snd_wnd; /* The window we expect to receive */ + u32 max_window; /* Maximal window ever seen from peer */ + u32 mss_cache; /* Cached effective mss, not including SACKS */ - __u32 window_clamp; /* Maximal window to advertise */ - __u32 rcv_ssthresh; /* Current window clamp */ + u32 window_clamp; /* Maximal window to advertise */ + u32 rcv_ssthresh; /* Current window clamp */ - __u32 frto_highmark; /* snd_nxt when RTO occurred */ - __u8 reordering; /* Packet reordering metric. */ - __u8 frto_counter; /* Number of new acks after RTO */ - __u8 nonagle; /* Disable Nagle algorithm? */ - __u8 keepalive_probes; /* num of allowed keep alive probes */ + u32 frto_highmark; /* snd_nxt when RTO occurred */ + u8 reordering; /* Packet reordering metric. */ + u8 frto_counter; /* Number of new acks after RTO */ + u8 nonagle; /* Disable Nagle algorithm? */ + u8 keepalive_probes; /* num of allowed keep alive probes */ /* RTT measurement */ - __u32 srtt; /* smoothed round trip time << 3 */ - __u32 mdev; /* medium deviation */ - __u32 mdev_max; /* maximal mdev for the last rtt period */ - __u32 rttvar; /* smoothed mdev_max */ - __u32 rtt_seq; /* sequence number to update rttvar */ - - __u32 packets_out; /* Packets which are "in flight" */ - __u32 left_out; /* Packets which leaved network */ - __u32 retrans_out; /* Retransmitted packets out */ + u32 srtt; /* smoothed round trip time << 3 */ + u32 mdev; /* medium deviation */ + u32 mdev_max; /* maximal mdev for the last rtt period */ + u32 rttvar; /* smoothed mdev_max */ + u32 rtt_seq; /* sequence number to update rttvar */ + + u32 packets_out; /* Packets which are "in flight" */ + u32 left_out; /* Packets which leaved network */ + u32 retrans_out; /* Retransmitted packets out */ /* * Options received (usually on last packet, some only on SYN packets). */ @@ -297,20 +297,20 @@ struct tcp_sock { /* * Slow start and congestion control (see also Nagle, and Karn & Partridge) */ - __u32 snd_ssthresh; /* Slow start size threshold */ - __u32 snd_cwnd; /* Sending congestion window */ - __u16 snd_cwnd_cnt; /* Linear increase counter */ - __u16 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ - __u32 snd_cwnd_used; - __u32 snd_cwnd_stamp; + u32 snd_ssthresh; /* Slow start size threshold */ + u32 snd_cwnd; /* Sending congestion window */ + u16 snd_cwnd_cnt; /* Linear increase counter */ + u16 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ + u32 snd_cwnd_used; + u32 snd_cwnd_stamp; struct sk_buff_head out_of_order_queue; /* Out of order segments go here */ - __u32 rcv_wnd; /* Current receiver window */ - __u32 rcv_wup; /* rcv_nxt on last window update sent */ - __u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ - __u32 pushed_seq; /* Last pushed seq, required to talk to windows */ - __u32 copied_seq; /* Head of yet unread data */ + u32 rcv_wnd; /* Current receiver window */ + u32 rcv_wup; /* rcv_nxt on last window update sent */ + u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ + u32 pushed_seq; /* Last pushed seq, required to talk to windows */ + u32 copied_seq; /* Head of yet unread data */ /* SACKs data */ struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */ @@ -331,26 +331,26 @@ struct tcp_sock { int retransmit_cnt_hint; int forward_cnt_hint; - __u16 advmss; /* Advertised MSS */ - __u16 prior_ssthresh; /* ssthresh saved at recovery start */ - __u32 lost_out; /* Lost packets */ - __u32 sacked_out; /* SACK'd packets */ - __u32 fackets_out; /* FACK'd packets */ - __u32 high_seq; /* snd_nxt at onset of congestion */ + u16 advmss; /* Advertised MSS */ + u16 prior_ssthresh; /* ssthresh saved at recovery start */ + u32 lost_out; /* Lost packets */ + u32 sacked_out; /* SACK'd packets */ + u32 fackets_out; /* FACK'd packets */ + u32 high_seq; /* snd_nxt at onset of congestion */ - __u32 retrans_stamp; /* Timestamp of the last retransmit, + u32 retrans_stamp; /* Timestamp of the last retransmit, * also used in SYN-SENT to remember stamp of * the first SYN. */ - __u32 undo_marker; /* tracking retrans started here. */ + u32 undo_marker; /* tracking retrans started here. */ int undo_retrans; /* number of undoable retransmissions. */ - __u32 urg_seq; /* Seq of received urgent pointer */ - __u16 urg_data; /* Saved octet of OOB data and control flags */ - __u8 urg_mode; /* In urgent mode */ - __u8 ecn_flags; /* ECN status bits. */ - __u32 snd_up; /* Urgent pointer */ + u32 urg_seq; /* Seq of received urgent pointer */ + u16 urg_data; /* Saved octet of OOB data and control flags */ + u8 urg_mode; /* In urgent mode */ + u8 ecn_flags; /* ECN status bits. */ + u32 snd_up; /* Urgent pointer */ - __u32 total_retrans; /* Total retransmits for entire connection */ - __u32 bytes_acked; /* Appropriate Byte Counting - RFC3465 */ + u32 total_retrans; /* Total retransmits for entire connection */ + u32 bytes_acked; /* Appropriate Byte Counting - RFC3465 */ unsigned int keepalive_time; /* time before keep alive takes place */ unsigned int keepalive_intvl; /* time interval between keep alive probes */ @@ -358,26 +358,26 @@ struct tcp_sock { unsigned long last_synq_overflow; - __u32 tso_deferred; + u32 tso_deferred; /* Receiver side RTT estimation */ struct { - __u32 rtt; - __u32 seq; - __u32 time; + u32 rtt; + u32 seq; + u32 time; } rcv_rtt_est; /* Receiver queue space */ struct { int space; - __u32 seq; - __u32 time; + u32 seq; + u32 time; } rcvq_space; /* TCP-specific MTU probe information. */ struct { - __u32 probe_seq_start; - __u32 probe_seq_end; + u32 probe_seq_start; + u32 probe_seq_end; } mtu_probe; #ifdef CONFIG_TCP_MD5SIG @@ -396,14 +396,14 @@ static inline struct tcp_sock *tcp_sk(const struct sock *sk) struct tcp_timewait_sock { struct inet_timewait_sock tw_sk; - __u32 tw_rcv_nxt; - __u32 tw_snd_nxt; - __u32 tw_rcv_wnd; - __u32 tw_ts_recent; + u32 tw_rcv_nxt; + u32 tw_snd_nxt; + u32 tw_rcv_wnd; + u32 tw_ts_recent; long tw_ts_recent_stamp; #ifdef CONFIG_TCP_MD5SIG - __u16 tw_md5_keylen; - __u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN]; + u16 tw_md5_keylen; + u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN]; #endif }; -- cgit v1.2.3 From 4384260443efe90a2ec0d907568dbc58ae792cd0 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 28 Nov 2006 18:14:10 -0200 Subject: [DCCP]: Remove allocation of sysctl numbers This is in response to a request sent earlier by Eric W. Biederman and replaces all sysctl numbers for net.dccp.default with CTL_UNNUMBERED. It has been tested to compile and to work. Commiter note: I've removed the use of CTL_UNNUMBERED, not setting .ctl_name sets it to 0, that is the what CTL_UNNUMBERED is, reason is to avoid unneeded source code cluttering. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/sysctl.h | 14 -------------- net/dccp/sysctl.c | 10 ---------- 2 files changed, 24 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 61dd99c6c2a5..94316a98e0d0 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -606,20 +606,6 @@ enum { NET_DCCP_DEFAULT=1, }; -/* /proc/sys/net/dccp/default */ -enum { - NET_DCCP_DEFAULT_SEQ_WINDOW = 1, - NET_DCCP_DEFAULT_RX_CCID = 2, - NET_DCCP_DEFAULT_TX_CCID = 3, - NET_DCCP_DEFAULT_ACK_RATIO = 4, - NET_DCCP_DEFAULT_SEND_ACKVEC = 5, - NET_DCCP_DEFAULT_SEND_NDP = 6, - NET_DCCP_DEFAULT_REQ_RETRIES = 7, - NET_DCCP_DEFAULT_RETRIES1 = 8, - NET_DCCP_DEFAULT_RETRIES2 = 9, - NET_DCCP_DEFAULT_TX_QLEN = 10, -}; - /* /proc/sys/net/ipx */ enum { NET_IPX_PPROP_BROADCASTING=1, diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index 4775ba3faa04..fdcfca3e9208 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c @@ -20,7 +20,6 @@ static struct ctl_table dccp_default_table[] = { { - .ctl_name = NET_DCCP_DEFAULT_SEQ_WINDOW, .procname = "seq_window", .data = &sysctl_dccp_feat_sequence_window, .maxlen = sizeof(sysctl_dccp_feat_sequence_window), @@ -28,7 +27,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_RX_CCID, .procname = "rx_ccid", .data = &sysctl_dccp_feat_rx_ccid, .maxlen = sizeof(sysctl_dccp_feat_rx_ccid), @@ -36,7 +34,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_TX_CCID, .procname = "tx_ccid", .data = &sysctl_dccp_feat_tx_ccid, .maxlen = sizeof(sysctl_dccp_feat_tx_ccid), @@ -44,7 +41,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_ACK_RATIO, .procname = "ack_ratio", .data = &sysctl_dccp_feat_ack_ratio, .maxlen = sizeof(sysctl_dccp_feat_ack_ratio), @@ -52,7 +48,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_SEND_ACKVEC, .procname = "send_ackvec", .data = &sysctl_dccp_feat_send_ack_vector, .maxlen = sizeof(sysctl_dccp_feat_send_ack_vector), @@ -60,7 +55,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_SEND_NDP, .procname = "send_ndp", .data = &sysctl_dccp_feat_send_ndp_count, .maxlen = sizeof(sysctl_dccp_feat_send_ndp_count), @@ -68,7 +62,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_REQ_RETRIES, .procname = "request_retries", .data = &sysctl_dccp_request_retries, .maxlen = sizeof(sysctl_dccp_request_retries), @@ -76,7 +69,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_RETRIES1, .procname = "retries1", .data = &sysctl_dccp_retries1, .maxlen = sizeof(sysctl_dccp_retries1), @@ -84,7 +76,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_RETRIES2, .procname = "retries2", .data = &sysctl_dccp_retries2, .maxlen = sizeof(sysctl_dccp_retries2), @@ -92,7 +83,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_TX_QLEN, .procname = "tx_qlen", .data = &sysctl_dccp_tx_qlen, .maxlen = sizeof(sysctl_dccp_tx_qlen), -- cgit v1.2.3 From 5aed324369c94a2c38469c8288e42eb1a9fac400 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 28 Nov 2006 19:33:36 -0200 Subject: [DCCP]: Tidy up unused structures This removes and cleans up unused variables and structures which have become unnecessary following the introduction of the EWMA patch to automatically track the CCID 3 receiver/sender packet sizes `s'. It deprecates the PACKET_SIZE socket option by returning an error code and printing a deprecation warning if an application tries to read or write this socket option. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/dccp.h | 4 +--- net/dccp/ccids/ccid3.h | 4 ---- net/dccp/proto.c | 8 ++++---- 3 files changed, 5 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 72cc355d7a03..ed6cc8962d87 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -200,7 +200,7 @@ struct dccp_so_feat { }; /* DCCP socket options */ -#define DCCP_SOCKOPT_PACKET_SIZE 1 +#define DCCP_SOCKOPT_PACKET_SIZE 1 /* XXX deprecated, without effect */ #define DCCP_SOCKOPT_SERVICE 2 #define DCCP_SOCKOPT_CHANGE_L 3 #define DCCP_SOCKOPT_CHANGE_R 4 @@ -460,7 +460,6 @@ struct dccp_ackvec; * @dccps_service_list - second .. last service code on passive socket * @dccps_timestamp_time - time of latest TIMESTAMP option * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option - * @dccps_packet_size - Set thru setsockopt * @dccps_l_ack_ratio - * @dccps_r_ack_ratio - * @dccps_pcslen - sender partial checksum coverage (via sockopt) @@ -495,7 +494,6 @@ struct dccp_sock { struct dccp_service_list *dccps_service_list; struct timeval dccps_timestamp_time; __u32 dccps_timestamp_echo; - __u32 dccps_packet_size; __u16 dccps_l_ack_ratio; __u16 dccps_r_ack_ratio; __u16 dccps_pcslen; diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 970921700ce3..dbb884426dfa 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -42,10 +42,6 @@ #include #include "../ccid.h" -#define TFRC_MIN_PACKET_SIZE 16 -#define TFRC_STD_PACKET_SIZE 256 -#define TFRC_MAX_PACKET_SIZE 65535 - /* Two seconds as per RFC 3448 4.2 */ #define TFRC_INITIAL_TIMEOUT (2 * USEC_PER_SEC) diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 3c44d502e5c1..2604e34d8f38 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -470,7 +470,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, lock_sock(sk); switch (optname) { case DCCP_SOCKOPT_PACKET_SIZE: - dp->dccps_packet_size = val; + DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n"); + err = -EINVAL; break; case DCCP_SOCKOPT_CHANGE_L: if (optlen != sizeof(struct dccp_so_feat)) @@ -581,9 +582,8 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, switch (optname) { case DCCP_SOCKOPT_PACKET_SIZE: - val = dp->dccps_packet_size; - len = sizeof(dp->dccps_packet_size); - break; + DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n"); + return -EINVAL; case DCCP_SOCKOPT_SERVICE: return dccp_getsockopt_service(sk, len, (__be32 __user *)optval, optlen); -- cgit v1.2.3 From d62f9ed4a490309bd9e5df0b42ba5d096e7b5902 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:17 +0100 Subject: [NETFILTER]: nf_conntrack: automatic sysctl registation for conntrack protocols Add helper functions for sysctl registration with optional instantiating of common path elements (like net/netfilter) and use it for support for automatic registation of conntrack protocol sysctls. Signed-off-by: Patrick McHardy --- include/linux/netfilter.h | 10 ++ include/net/netfilter/nf_conntrack_l3proto.h | 6 ++ include/net/netfilter/nf_conntrack_l4proto.h | 6 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_proto.c | 102 ++++++++++++++++++++ net/netfilter/nf_sysctl.c | 134 +++++++++++++++++++++++++++ 6 files changed, 259 insertions(+) create mode 100644 net/netfilter/nf_sysctl.c (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 6ab5e2d6133e..f6f3fcbd70ed 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -117,6 +117,16 @@ void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n); int nf_register_sockopt(struct nf_sockopt_ops *reg); void nf_unregister_sockopt(struct nf_sockopt_ops *reg); +#ifdef CONFIG_SYSCTL +/* Sysctl registration */ +struct ctl_table_header *nf_register_sysctl_table(struct ctl_table *path, + struct ctl_table *table); +void nf_unregister_sysctl_table(struct ctl_table_header *header, + struct ctl_table *table); +extern struct ctl_table nf_net_netfilter_sysctl_path[]; +extern struct ctl_table nf_net_ipv4_netfilter_sysctl_path[]; +#endif /* CONFIG_SYSCTL */ + extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; /* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index 6364df059422..664ddcffe00d 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h @@ -75,6 +75,12 @@ struct nf_conntrack_l3proto int (*nfattr_to_tuple)(struct nfattr *tb[], struct nf_conntrack_tuple *t); +#ifdef CONFIG_SYSCTL + struct ctl_table_header *ctl_table_header; + struct ctl_table *ctl_table_path; + struct ctl_table *ctl_table; +#endif /* CONFIG_SYSCTL */ + /* Module (if any) which this is connected to. */ struct module *me; }; diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index c22804aa227e..fe1e8fa30d2f 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -76,6 +76,12 @@ struct nf_conntrack_l4proto int (*nfattr_to_tuple)(struct nfattr *tb[], struct nf_conntrack_tuple *t); +#ifdef CONFIG_SYSCTL + struct ctl_table_header **ctl_table_header; + struct ctl_table *ctl_table; + unsigned int *ctl_table_users; +#endif /* CONFIG_SYSCTL */ + /* Module (if any) which this is connected to. */ struct module *me; }; diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 627105df1040..84d529ded952 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -4,6 +4,7 @@ nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_exp nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o obj-$(CONFIG_NETFILTER) = netfilter.o +obj-$(CONFIG_SYSCTL) += nf_sysctl.o obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index a6a3b1ddd00d..941b5c3754af 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,34 @@ struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; +#ifdef CONFIG_SYSCTL +static DEFINE_MUTEX(nf_ct_proto_sysctl_mutex); + +static int +nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path, + struct ctl_table *table, unsigned int *users) +{ + if (*header == NULL) { + *header = nf_register_sysctl_table(path, table); + if (*header == NULL) + return -ENOMEM; + } + if (users != NULL) + (*users)++; + return 0; +} + +static void +nf_ct_unregister_sysctl(struct ctl_table_header **header, + struct ctl_table *table, unsigned int *users) +{ + if (users != NULL && --*users > 0) + return; + nf_unregister_sysctl_table(*header, table); + *header = NULL; +} +#endif + struct nf_conntrack_l4proto * __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) { @@ -124,6 +153,33 @@ static int kill_l4proto(struct nf_conn *i, void *data) l4proto->l3proto); } +static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) +{ + int err = 0; + +#ifdef CONFIG_SYSCTL + mutex_lock(&nf_ct_proto_sysctl_mutex); + if (l3proto->ctl_table != NULL) { + err = nf_ct_register_sysctl(&l3proto->ctl_table_header, + l3proto->ctl_table_path, + l3proto->ctl_table, NULL); + } + mutex_unlock(&nf_ct_proto_sysctl_mutex); +#endif + return err; +} + +static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto) +{ +#ifdef CONFIG_SYSCTL + mutex_lock(&nf_ct_proto_sysctl_mutex); + if (l3proto->ctl_table_header != NULL) + nf_ct_unregister_sysctl(&l3proto->ctl_table_header, + l3proto->ctl_table, NULL); + mutex_unlock(&nf_ct_proto_sysctl_mutex); +#endif +} + int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) { int ret = 0; @@ -139,6 +195,12 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) goto out_unlock; } nf_ct_l3protos[proto->l3proto] = proto; + write_unlock_bh(&nf_conntrack_lock); + + ret = nf_ct_l3proto_register_sysctl(proto); + if (ret < 0) + nf_conntrack_l3proto_unregister(proto); + return ret; out_unlock: write_unlock_bh(&nf_conntrack_lock); @@ -165,6 +227,8 @@ int nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) nf_ct_l3protos[proto->l3proto] = &nf_conntrack_l3proto_generic; write_unlock_bh(&nf_conntrack_lock); + nf_ct_l3proto_unregister_sysctl(proto); + /* Somebody could be still looking at the proto in bh. */ synchronize_net(); @@ -175,6 +239,36 @@ out: return ret; } +static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto) +{ + int err = 0; + +#ifdef CONFIG_SYSCTL + mutex_lock(&nf_ct_proto_sysctl_mutex); + if (l4proto->ctl_table != NULL) { + err = nf_ct_register_sysctl(l4proto->ctl_table_header, + nf_net_netfilter_sysctl_path, + l4proto->ctl_table, + l4proto->ctl_table_users); + } + mutex_unlock(&nf_ct_proto_sysctl_mutex); +#endif + return err; +} + +static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto) +{ +#ifdef CONFIG_SYSCTL + mutex_lock(&nf_ct_proto_sysctl_mutex); + if (l4proto->ctl_table_header != NULL && + *l4proto->ctl_table_header != NULL) + nf_ct_unregister_sysctl(l4proto->ctl_table_header, + l4proto->ctl_table, + l4proto->ctl_table_users); + mutex_unlock(&nf_ct_proto_sysctl_mutex); +#endif +} + /* FIXME: Allow NULL functions and sub in pointers to generic for them. --RR */ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) @@ -230,6 +324,12 @@ retry: } nf_ct_protos[l4proto->l3proto][l4proto->l4proto] = l4proto; + write_unlock_bh(&nf_conntrack_lock); + + ret = nf_ct_l4proto_register_sysctl(l4proto); + if (ret < 0) + nf_conntrack_l4proto_unregister(l4proto); + return ret; out_unlock: write_unlock_bh(&nf_conntrack_lock); @@ -257,6 +357,8 @@ int nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto) = &nf_conntrack_l4proto_generic; write_unlock_bh(&nf_conntrack_lock); + nf_ct_l4proto_unregister_sysctl(l4proto); + /* Somebody could be still looking at the proto in bh. */ synchronize_net(); diff --git a/net/netfilter/nf_sysctl.c b/net/netfilter/nf_sysctl.c new file mode 100644 index 000000000000..06ddddb2911f --- /dev/null +++ b/net/netfilter/nf_sysctl.c @@ -0,0 +1,134 @@ +/* nf_sysctl.c netfilter sysctl registration/unregistation + * + * Copyright (c) 2006 Patrick McHardy + */ +#include +#include +#include +#include + +static void +path_free(struct ctl_table *path, struct ctl_table *table) +{ + struct ctl_table *t, *next; + + for (t = path; t != NULL && t != table; t = next) { + next = t->child; + kfree(t); + } +} + +static struct ctl_table * +path_dup(struct ctl_table *path, struct ctl_table *table) +{ + struct ctl_table *t, *last = NULL, *tmp; + + for (t = path; t != NULL; t = t->child) { + /* twice the size since path elements are terminated by an + * empty element */ + tmp = kmemdup(t, 2 * sizeof(*t), GFP_KERNEL); + if (tmp == NULL) { + if (last != NULL) + path_free(path, table); + return NULL; + } + + if (last != NULL) + last->child = tmp; + else + path = tmp; + last = tmp; + } + + if (last != NULL) + last->child = table; + else + path = table; + + return path; +} + +struct ctl_table_header * +nf_register_sysctl_table(struct ctl_table *path, struct ctl_table *table) +{ + struct ctl_table_header *header; + + path = path_dup(path, table); + if (path == NULL) + return NULL; + header = register_sysctl_table(path, 0); + if (header == NULL) + path_free(path, table); + return header; +} +EXPORT_SYMBOL_GPL(nf_register_sysctl_table); + +void +nf_unregister_sysctl_table(struct ctl_table_header *header, + struct ctl_table *table) +{ + struct ctl_table *path = header->ctl_table; + + unregister_sysctl_table(header); + path_free(path, table); +} +EXPORT_SYMBOL_GPL(nf_unregister_sysctl_table); + +/* net/netfilter */ +static struct ctl_table nf_net_netfilter_table[] = { + { + .ctl_name = NET_NETFILTER, + .procname = "netfilter", + .mode = 0555, + }, + { + .ctl_name = 0 + } +}; +struct ctl_table nf_net_netfilter_sysctl_path[] = { + { + .ctl_name = CTL_NET, + .procname = "net", + .mode = 0555, + .child = nf_net_netfilter_table, + }, + { + .ctl_name = 0 + } +}; +EXPORT_SYMBOL_GPL(nf_net_netfilter_sysctl_path); + +/* net/ipv4/netfilter */ +static struct ctl_table nf_net_ipv4_netfilter_table[] = { + { + .ctl_name = NET_IPV4_NETFILTER, + .procname = "netfilter", + .mode = 0555, + }, + { + .ctl_name = 0 + } +}; +static struct ctl_table nf_net_ipv4_table[] = { + { + .ctl_name = NET_IPV4, + .procname = "ipv4", + .mode = 0555, + .child = nf_net_ipv4_netfilter_table, + }, + { + .ctl_name = 0 + } +}; +struct ctl_table nf_net_ipv4_netfilter_sysctl_path[] = { + { + .ctl_name = CTL_NET, + .procname = "net", + .mode = 0555, + .child = nf_net_ipv4_table, + }, + { + .ctl_name = 0 + } +}; +EXPORT_SYMBOL_GPL(nf_net_ipv4_netfilter_sysctl_path); -- cgit v1.2.3 From 468ec44bd5a863736d955f78b8c38896f26864a1 Mon Sep 17 00:00:00 2001 From: Yasuyuki Kozakai Date: Wed, 29 Nov 2006 02:35:23 +0100 Subject: [NETFILTER]: conntrack: add '_get' to {ip, nf}_conntrack_expect_find We usually uses 'xxx_find_get' for function which increments reference count. Signed-off-by: Yasuyuki Kozakai Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv4/ip_conntrack.h | 2 +- include/net/netfilter/nf_conntrack_expect.h | 2 +- net/ipv4/netfilter/ip_conntrack_core.c | 2 +- net/ipv4/netfilter/ip_conntrack_helper_pptp.c | 4 ++-- net/ipv4/netfilter/ip_conntrack_netlink.c | 4 ++-- net/ipv4/netfilter/ip_conntrack_standalone.c | 2 +- net/ipv4/netfilter/ip_nat_helper_pptp.c | 2 +- net/netfilter/nf_conntrack_expect.c | 2 +- net/netfilter/nf_conntrack_netlink.c | 4 ++-- net/netfilter/nf_conntrack_standalone.c | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 64e868034c4a..61da56941dce 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -277,7 +277,7 @@ extern struct ip_conntrack_expect * __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); extern struct ip_conntrack_expect * -ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple); extern struct ip_conntrack_tuple_hash * __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 5aa483e03455..2d335f024c85 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -53,7 +53,7 @@ struct nf_conntrack_expect * __nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple); struct nf_conntrack_expect * -nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple); +nf_conntrack_expect_find_get(const struct nf_conntrack_tuple *tuple); struct nf_conntrack_expect * find_expectation(const struct nf_conntrack_tuple *tuple); diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 8b848aa77bfc..4d1f954d459b 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -233,7 +233,7 @@ __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) /* Just find a expectation corresponding to a tuple. */ struct ip_conntrack_expect * -ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple) { struct ip_conntrack_expect *i; diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c index a2af5e0c7f99..a5c057bcecf4 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c @@ -142,7 +142,7 @@ static void pptp_expectfn(struct ip_conntrack *ct, DEBUGP("trying to unexpect other dir: "); DUMP_TUPLE(&inv_t); - exp_other = ip_conntrack_expect_find(&inv_t); + exp_other = ip_conntrack_expect_find_get(&inv_t); if (exp_other) { /* delete other expectation. */ DEBUGP("found\n"); @@ -176,7 +176,7 @@ static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) ip_conntrack_put(sibling); return 1; } else { - exp = ip_conntrack_expect_find(t); + exp = ip_conntrack_expect_find_get(t); if (exp) { DEBUGP("unexpect_related of expect %p\n", exp); ip_conntrack_unexpect_related(exp); diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 1bb8ed33c5bc..3d277aa869dd 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -1256,7 +1256,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - exp = ip_conntrack_expect_find(&tuple); + exp = ip_conntrack_expect_find_get(&tuple); if (!exp) return -ENOENT; @@ -1309,7 +1309,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return err; /* bump usage count to 2 */ - exp = ip_conntrack_expect_find(&tuple); + exp = ip_conntrack_expect_find_get(&tuple); if (!exp) return -ENOENT; diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 02135756562e..2df67538ffb0 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -926,7 +926,7 @@ EXPORT_SYMBOL(__ip_ct_refresh_acct); EXPORT_SYMBOL(ip_conntrack_expect_alloc); EXPORT_SYMBOL(ip_conntrack_expect_put); EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); -EXPORT_SYMBOL_GPL(ip_conntrack_expect_find); +EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get); EXPORT_SYMBOL(ip_conntrack_expect_related); EXPORT_SYMBOL(ip_conntrack_unexpect_related); EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c index 329fdcd7d702..acf55d863100 100644 --- a/net/ipv4/netfilter/ip_nat_helper_pptp.c +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c @@ -101,7 +101,7 @@ static void pptp_nat_expected(struct ip_conntrack *ct, DEBUGP("trying to unexpect other dir: "); DUMP_TUPLE(&t); - other_exp = ip_conntrack_expect_find(&t); + other_exp = ip_conntrack_expect_find_get(&t); if (other_exp) { ip_conntrack_unexpect_related(other_exp); ip_conntrack_expect_put(other_exp); diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 79cfd79a42f0..aa5903e4da11 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -68,7 +68,7 @@ __nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple) /* Just find a expectation corresponding to a tuple. */ struct nf_conntrack_expect * -nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple) +nf_conntrack_expect_find_get(const struct nf_conntrack_tuple *tuple) { struct nf_conntrack_expect *i; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index dc0830220130..7357b8f47acd 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1284,7 +1284,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - exp = nf_conntrack_expect_find(&tuple); + exp = nf_conntrack_expect_find_get(&tuple); if (!exp) return -ENOENT; @@ -1339,7 +1339,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return err; /* bump usage count to 2 */ - exp = nf_conntrack_expect_find(&tuple); + exp = nf_conntrack_expect_find_get(&tuple); if (!exp) return -ENOENT; diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 3db24f4f0f5b..be94b6359725 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -549,7 +549,7 @@ EXPORT_SYMBOL(__nf_conntrack_find); EXPORT_SYMBOL(nf_ct_unlink_expect); EXPORT_SYMBOL(nf_conntrack_hash_insert); EXPORT_SYMBOL(__nf_conntrack_expect_find); -EXPORT_SYMBOL(nf_conntrack_expect_find); +EXPORT_SYMBOL(nf_conntrack_expect_find_get); EXPORT_SYMBOL(nf_conntrack_expect_list); #if defined(CONFIG_NF_CT_NETLINK) || \ defined(CONFIG_NF_CT_NETLINK_MODULE) -- cgit v1.2.3 From 9d5b8baa4e9ace9be113c6151aaeeb3c07a26fc8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:26 +0100 Subject: [NETFILTER]: sip conntrack: minor cleanup - Use enum for header field enumeration - Use numerical value instead of pointer to header info structure to identify headers, unexport ct_sip_hdrs - group SIP and SDP entries in header info structure - remove double forward declaration of ct_sip_get_info Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv4/ip_conntrack_sip.h | 28 +++++------- net/ipv4/netfilter/ip_conntrack_sip.c | 60 +++++++++++++------------ net/ipv4/netfilter/ip_nat_sip.c | 30 ++++++------- 3 files changed, 55 insertions(+), 63 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sip.h b/include/linux/netfilter_ipv4/ip_conntrack_sip.h index 913dad66c0fb..2a15eb51fd6b 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_sip.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_sip.h @@ -5,23 +5,15 @@ #define SIP_PORT 5060 #define SIP_TIMEOUT 3600 -#define POS_VIA 0 -#define POS_CONTACT 1 -#define POS_CONTENT 2 -#define POS_MEDIA 3 -#define POS_OWNER 4 -#define POS_CONNECTION 5 -#define POS_REQ_HEADER 6 -#define POS_SDP_HEADER 7 - -struct sip_header_nfo { - const char *lname; - const char *sname; - const char *ln_str; - size_t lnlen; - size_t snlen; - size_t ln_strlen; - int (*match_len)(const char *, const char *, int *); +enum sip_header_pos { + POS_REQ_HEADER, + POS_VIA, + POS_CONTACT, + POS_CONTENT, + POS_MEDIA, + POS_OWNER, + POS_CONNECTION, + POS_SDP_HEADER, }; extern unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb, @@ -36,7 +28,7 @@ extern unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, extern int ct_sip_get_info(const char *dptr, size_t dlen, unsigned int *matchoff, unsigned int *matchlen, - struct sip_header_nfo *hnfo); + enum sip_header_pos pos); extern int ct_sip_lnlen(const char *line, const char *limit); extern const char *ct_sip_search(const char *needle, const char *haystack, size_t needle_len, size_t haystack_len); diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index bf423db4ed46..cc3176581667 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -52,20 +52,32 @@ unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, const char *dptr); EXPORT_SYMBOL_GPL(ip_nat_sdp_hook); -int ct_sip_get_info(const char *dptr, size_t dlen, - unsigned int *matchoff, - unsigned int *matchlen, - struct sip_header_nfo *hnfo); -EXPORT_SYMBOL_GPL(ct_sip_get_info); - - static int digits_len(const char *dptr, const char *limit, int *shift); static int epaddr_len(const char *dptr, const char *limit, int *shift); static int skp_digits_len(const char *dptr, const char *limit, int *shift); static int skp_epaddr_len(const char *dptr, const char *limit, int *shift); -struct sip_header_nfo ct_sip_hdrs[] = { - { /* Via header */ +struct sip_header_nfo { + const char *lname; + const char *sname; + const char *ln_str; + size_t lnlen; + size_t snlen; + size_t ln_strlen; + int (*match_len)(const char *, const char *, int *); +}; + +static struct sip_header_nfo ct_sip_hdrs[] = { + [POS_REQ_HEADER] = { /* SIP Requests headers */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .sname = "sip:", + .snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */ + .ln_str = "@", + .ln_strlen = sizeof("@") - 1, + .match_len = epaddr_len + }, + [POS_VIA] = { /* SIP Via header */ .lname = "Via:", .lnlen = sizeof("Via:") - 1, .sname = "\r\nv:", @@ -74,7 +86,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("UDP ") - 1, .match_len = epaddr_len, }, - { /* Contact header */ + [POS_CONTACT] = { /* SIP Contact header */ .lname = "Contact:", .lnlen = sizeof("Contact:") - 1, .sname = "\r\nm:", @@ -83,7 +95,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("sip:") - 1, .match_len = skp_epaddr_len }, - { /* Content length header */ + [POS_CONTENT] = { /* SIP Content length header */ .lname = "Content-Length:", .lnlen = sizeof("Content-Length:") - 1, .sname = "\r\nl:", @@ -92,7 +104,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof(":") - 1, .match_len = skp_digits_len }, - { /* SDP media info */ + [POS_MEDIA] = { /* SDP media info */ .lname = "\nm=", .lnlen = sizeof("\nm=") - 1, .sname = "\rm=", @@ -101,7 +113,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("audio ") - 1, .match_len = digits_len }, - { /* SDP owner address*/ + [POS_OWNER] = { /* SDP owner address*/ .lname = "\no=", .lnlen = sizeof("\no=") - 1, .sname = "\ro=", @@ -110,7 +122,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("IN IP4 ") - 1, .match_len = epaddr_len }, - { /* SDP connection info */ + [POS_CONNECTION] = { /* SDP connection info */ .lname = "\nc=", .lnlen = sizeof("\nc=") - 1, .sname = "\rc=", @@ -119,16 +131,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("IN IP4 ") - 1, .match_len = epaddr_len }, - { /* Requests headers */ - .lname = "sip:", - .lnlen = sizeof("sip:") - 1, - .sname = "sip:", - .snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */ - .ln_str = "@", - .ln_strlen = sizeof("@") - 1, - .match_len = epaddr_len - }, - { /* SDP version header */ + [POS_SDP_HEADER] = { /* SDP version header */ .lname = "\nv=", .lnlen = sizeof("\nv=") - 1, .sname = "\rv=", @@ -138,7 +141,6 @@ struct sip_header_nfo ct_sip_hdrs[] = { .match_len = digits_len } }; -EXPORT_SYMBOL_GPL(ct_sip_hdrs); /* get line lenght until first CR or LF seen. */ int ct_sip_lnlen(const char *line, const char *limit) @@ -263,8 +265,9 @@ static int skp_epaddr_len(const char *dptr, const char *limit, int *shift) int ct_sip_get_info(const char *dptr, size_t dlen, unsigned int *matchoff, unsigned int *matchlen, - struct sip_header_nfo *hnfo) + enum sip_header_pos pos) { + struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos]; const char *limit, *aux, *k = dptr; int shift = 0; @@ -298,6 +301,7 @@ int ct_sip_get_info(const char *dptr, size_t dlen, DEBUGP("%s header not found.\n", hnfo->lname); return 0; } +EXPORT_SYMBOL_GPL(ct_sip_get_info); static int set_expected_rtp(struct sk_buff **pskb, struct ip_conntrack *ct, @@ -393,7 +397,7 @@ static int sip_help(struct sk_buff **pskb, } /* Get ip and port address from SDP packet. */ if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, - &ct_sip_hdrs[POS_CONNECTION]) > 0) { + POS_CONNECTION) > 0) { /* We'll drop only if there are parse problems. */ if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr, @@ -402,7 +406,7 @@ static int sip_help(struct sk_buff **pskb, goto out; } if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, - &ct_sip_hdrs[POS_MEDIA]) > 0) { + POS_MEDIA) > 0) { port = simple_strtoul(dptr + matchoff, NULL, 10); if (port < 1024) { diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index 9fad98099532..47097aac63d8 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -29,18 +29,16 @@ MODULE_DESCRIPTION("SIP NAT helper"); #define DEBUGP(format, args...) #endif -extern struct sip_header_nfo ct_sip_hdrs[]; - static unsigned int mangle_sip_packet(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct ip_conntrack *ct, const char **dptr, size_t dlen, char *buffer, int bufflen, - struct sip_header_nfo *hnfo) + enum sip_header_pos pos) { unsigned int matchlen, matchoff; - if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, hnfo) <= 0) + if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) return 0; if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, @@ -80,14 +78,13 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, if ((ctinfo) < IP_CT_IS_REPLY) { mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, - &ct_sip_hdrs[POS_CONTACT]); + buffer, bufflen, POS_CONTACT); return 1; } if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_VIA])) + buffer, bufflen, POS_VIA)) return 0; /* This search should ignore case, but later.. */ @@ -102,25 +99,24 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, return mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, - &ct_sip_hdrs[POS_CONTACT]); + buffer, bufflen, POS_CONTACT); } if ((ctinfo) < IP_CT_IS_REPLY) { if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_VIA])) + buffer, bufflen, POS_VIA)) return 0; /* Mangle Contact if exists only. - watch udp_nat_mangle()! */ mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]); + buffer, bufflen, POS_CONTACT); return 1; } /* This mangle requests headers. */ return mangle_sip_packet(pskb, ctinfo, ct, dptr, ct_sip_lnlen(*dptr, *dptr + (*pskb)->len - dataoff), - buffer, bufflen, &ct_sip_hdrs[POS_REQ_HEADER]); + buffer, bufflen, POS_REQ_HEADER); } static int mangle_content_len(struct sk_buff **pskb, @@ -136,7 +132,7 @@ static int mangle_content_len(struct sk_buff **pskb, /* Get actual SDP lenght */ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, - &matchlen, &ct_sip_hdrs[POS_SDP_HEADER]) > 0) { + &matchlen, POS_SDP_HEADER) > 0) { /* since ct_sip_get_info() give us a pointer passing 'v=' we need to add 2 bytes in this count. */ @@ -144,7 +140,7 @@ static int mangle_content_len(struct sk_buff **pskb, /* Now, update SDP lenght */ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, - &matchlen, &ct_sip_hdrs[POS_CONTENT]) > 0) { + &matchlen, POS_CONTENT) > 0) { bufflen = sprintf(buffer, "%u", c_len); @@ -170,17 +166,17 @@ static unsigned int mangle_sdp(struct sk_buff **pskb, /* Mangle owner and contact info. */ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_OWNER])) + buffer, bufflen, POS_OWNER)) return 0; if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_CONNECTION])) + buffer, bufflen, POS_CONNECTION)) return 0; /* Mangle media port. */ bufflen = sprintf(buffer, "%u", port); if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_MEDIA])) + buffer, bufflen, POS_MEDIA)) return 0; return mangle_content_len(pskb, ctinfo, ct, dptr); -- cgit v1.2.3 From 40883e8184947879f135605a05c0764c60656cc5 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:27 +0100 Subject: [NETFILTER]: sip conntrack: do case insensitive SIP header search SIP headers are generally case-insensitive, only SDP headers are case sensitive. Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv4/ip_conntrack_sip.h | 3 ++- net/ipv4/netfilter/ip_conntrack_sip.c | 20 ++++++++++++++++---- net/ipv4/netfilter/ip_nat_sip.c | 7 ++++--- 3 files changed, 22 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sip.h b/include/linux/netfilter_ipv4/ip_conntrack_sip.h index 2a15eb51fd6b..51c65ac18c57 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_sip.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_sip.h @@ -31,6 +31,7 @@ extern int ct_sip_get_info(const char *dptr, size_t dlen, enum sip_header_pos pos); extern int ct_sip_lnlen(const char *line, const char *limit); extern const char *ct_sip_search(const char *needle, const char *haystack, - size_t needle_len, size_t haystack_len); + size_t needle_len, size_t haystack_len, + int case_sensitive); #endif /* __KERNEL__ */ #endif /* __IP_CONNTRACK_SIP_H__ */ diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index cc3176581667..a9c0d1d3e56f 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -64,6 +64,7 @@ struct sip_header_nfo { size_t lnlen; size_t snlen; size_t ln_strlen; + int case_sensitive; int (*match_len)(const char *, const char *, int *); }; @@ -105,6 +106,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = skp_digits_len }, [POS_MEDIA] = { /* SDP media info */ + .case_sensitive = 1, .lname = "\nm=", .lnlen = sizeof("\nm=") - 1, .sname = "\rm=", @@ -114,6 +116,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = digits_len }, [POS_OWNER] = { /* SDP owner address*/ + .case_sensitive = 1, .lname = "\no=", .lnlen = sizeof("\no=") - 1, .sname = "\ro=", @@ -123,6 +126,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = epaddr_len }, [POS_CONNECTION] = { /* SDP connection info */ + .case_sensitive = 1, .lname = "\nc=", .lnlen = sizeof("\nc=") - 1, .sname = "\rc=", @@ -132,6 +136,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = epaddr_len }, [POS_SDP_HEADER] = { /* SDP version header */ + .case_sensitive = 1, .lname = "\nv=", .lnlen = sizeof("\nv=") - 1, .sname = "\rv=", @@ -161,13 +166,19 @@ EXPORT_SYMBOL_GPL(ct_sip_lnlen); /* Linear string search, case sensitive. */ const char *ct_sip_search(const char *needle, const char *haystack, - size_t needle_len, size_t haystack_len) + size_t needle_len, size_t haystack_len, + int case_sensitive) { const char *limit = haystack + (haystack_len - needle_len); while (haystack <= limit) { - if (memcmp(haystack, needle, needle_len) == 0) - return haystack; + if (case_sensitive) { + if (strncmp(haystack, needle, needle_len) == 0) + return haystack; + } else { + if (strnicmp(haystack, needle, needle_len) == 0) + return haystack; + } haystack++; } return NULL; @@ -280,7 +291,8 @@ int ct_sip_get_info(const char *dptr, size_t dlen, continue; } aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, - ct_sip_lnlen(dptr, limit)); + ct_sip_lnlen(dptr, limit), + hnfo->case_sensitive); if (!aux) { DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, hnfo->lname); diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index 47097aac63d8..e16604c4339d 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -87,14 +87,15 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, buffer, bufflen, POS_VIA)) return 0; - /* This search should ignore case, but later.. */ aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1, - (*pskb)->len - dataoff); + (*pskb)->len - dataoff, 0); if (!aux) return 0; if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"), - ct_sip_lnlen(aux, *dptr + (*pskb)->len - dataoff))) + ct_sip_lnlen(aux, + *dptr + (*pskb)->len - dataoff), + 1)) return 1; return mangle_sip_packet(pskb, ctinfo, ct, dptr, -- cgit v1.2.3 From 1b683b551209ca46ae59b29572018001db5af078 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:30 +0100 Subject: [NETFILTER]: sip conntrack: better NAT handling The NAT handling of the SIP helper has a few problems: - Request headers are only mangled in the reply direction, From/To headers not at all, which can lead to authentication failures with DNAT in case the authentication domain is the IP address - Contact headers in responses are only mangled for REGISTER responses - Headers may be mangled even though they contain addresses not participating in the connection, like alternative addresses - Packets are droppen when domain names are used where the helper expects IP addresses This patch takes a different approach, instead of fixed rules what field to mangle to what content, it adds symetric mapping of From/To/Via/Contact headers, which allows to deal properly with echoed addresses in responses and foreign addresses not belonging to the connection. Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv4/ip_conntrack_sip.h | 5 +- net/ipv4/netfilter/ip_conntrack_sip.c | 29 +++- net/ipv4/netfilter/ip_nat_sip.c | 171 ++++++++++++++---------- 3 files changed, 135 insertions(+), 70 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sip.h b/include/linux/netfilter_ipv4/ip_conntrack_sip.h index 51c65ac18c57..bef6c646defa 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_sip.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_sip.h @@ -6,7 +6,10 @@ #define SIP_TIMEOUT 3600 enum sip_header_pos { - POS_REQ_HEADER, + POS_REG_REQ_URI, + POS_REQ_URI, + POS_FROM, + POS_TO, POS_VIA, POS_CONTACT, POS_CONTENT, diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index 0a6a13c45b07..3a26d63eed88 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -69,13 +69,38 @@ struct sip_header_nfo { }; static struct sip_header_nfo ct_sip_hdrs[] = { - [POS_REQ_HEADER] = { /* SIP Requests headers */ + [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .ln_str = ":", + .ln_strlen = sizeof(":") - 1, + .match_len = epaddr_len + }, + [POS_REQ_URI] = { /* SIP request URI */ .lname = "sip:", .lnlen = sizeof("sip:") - 1, .ln_str = "@", .ln_strlen = sizeof("@") - 1, .match_len = epaddr_len }, + [POS_FROM] = { /* SIP From header */ + .lname = "From:", + .lnlen = sizeof("From:") - 1, + .sname = "\r\nf:", + .snlen = sizeof("\r\nf:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len, + }, + [POS_TO] = { /* SIP To header */ + .lname = "To:", + .lnlen = sizeof("To:") - 1, + .sname = "\r\nt:", + .snlen = sizeof("\r\nt:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len, + }, [POS_VIA] = { /* SIP Via header */ .lname = "Via:", .lnlen = sizeof("Via:") - 1, @@ -284,7 +309,7 @@ int ct_sip_get_info(const char *dptr, size_t dlen, while (dptr <= limit) { if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && - (hinfo->sname == NULL || + (hnfo->sname == NULL || strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { dptr++; continue; diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index e16604c4339d..6223abc924ff 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -29,25 +29,70 @@ MODULE_DESCRIPTION("SIP NAT helper"); #define DEBUGP(format, args...) #endif -static unsigned int mangle_sip_packet(struct sk_buff **pskb, - enum ip_conntrack_info ctinfo, - struct ip_conntrack *ct, - const char **dptr, size_t dlen, - char *buffer, int bufflen, - enum sip_header_pos pos) +struct addr_map { + struct { + char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned int srclen, srciplen; + unsigned int dstlen, dstiplen; + } addr[IP_CT_DIR_MAX]; +}; + +static void addr_map_init(struct ip_conntrack *ct, struct addr_map *map) { - unsigned int matchlen, matchoff; + struct ip_conntrack_tuple *t; + enum ip_conntrack_dir dir; + unsigned int n; + + for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { + t = &ct->tuplehash[dir].tuple; + + n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", + NIPQUAD(t->src.ip)); + map->addr[dir].srciplen = n; + n += sprintf(map->addr[dir].src + n, ":%u", + ntohs(t->src.u.udp.port)); + map->addr[dir].srclen = n; + + n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", + NIPQUAD(t->dst.ip)); + map->addr[dir].dstiplen = n; + n += sprintf(map->addr[dir].dst + n, ":%u", + ntohs(t->dst.u.udp.port)); + map->addr[dir].dstlen = n; + } +} + +static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, const char **dptr, size_t dlen, + enum sip_header_pos pos, struct addr_map *map) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned int matchlen, matchoff, addrlen; + char *addr; if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) - return 0; + return 1; + + if ((matchlen == map->addr[dir].srciplen || + matchlen == map->addr[dir].srclen) && + memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { + addr = map->addr[!dir].dst; + addrlen = map->addr[!dir].dstlen; + } else if ((matchlen == map->addr[dir].dstiplen || + matchlen == map->addr[dir].dstlen) && + memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { + addr = map->addr[!dir].src; + addrlen = map->addr[!dir].srclen; + } else + return 1; if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, - matchoff, matchlen, buffer, bufflen)) + matchoff, matchlen, addr, addrlen)) return 0; - - /* We need to reload this. Thanks Patrick. */ *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); return 1; + } static unsigned int ip_nat_sip(struct sk_buff **pskb, @@ -55,69 +100,61 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, struct ip_conntrack *ct, const char **dptr) { - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; - unsigned int bufflen, dataoff; - __be32 ip; - __be16 port; + enum sip_header_pos pos; + struct addr_map map; + int dataoff, datalen; dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + datalen = (*pskb)->len - dataoff; + if (datalen < sizeof("SIP/2.0") - 1) + return NF_DROP; + + addr_map_init(ct, &map); + + /* Basic rules: requests and responses. */ + if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) { + /* 10.2: Constructing the REGISTER Request: + * + * The "userinfo" and "@" components of the SIP URI MUST NOT + * be present. + */ + if (datalen >= sizeof("REGISTER") - 1 && + strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) + pos = POS_REG_REQ_URI; + else + pos = POS_REQ_URI; + + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map)) + return NF_DROP; + } - ip = ct->tuplehash[!dir].tuple.dst.ip; - port = ct->tuplehash[!dir].tuple.dst.u.udp.port; - bufflen = sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(ip), ntohs(port)); + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) + return NF_DROP; + return NF_ACCEPT; +} + +static unsigned int mangle_sip_packet(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, + const char **dptr, size_t dlen, + char *buffer, int bufflen, + enum sip_header_pos pos) +{ + unsigned int matchlen, matchoff; - /* short packet ? */ - if (((*pskb)->len - dataoff) < (sizeof("SIP/2.0") - 1)) + if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) return 0; - /* Basic rules: requests and responses. */ - if (memcmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) == 0) { - const char *aux; - - if ((ctinfo) < IP_CT_IS_REPLY) { - mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_CONTACT); - return 1; - } + if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, buffer, bufflen)) + return 0; - if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_VIA)) - return 0; - - aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1, - (*pskb)->len - dataoff, 0); - if (!aux) - return 0; - - if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"), - ct_sip_lnlen(aux, - *dptr + (*pskb)->len - dataoff), - 1)) - return 1; - - return mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_CONTACT); - } - if ((ctinfo) < IP_CT_IS_REPLY) { - if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_VIA)) - return 0; - - /* Mangle Contact if exists only. - watch udp_nat_mangle()! */ - mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, POS_CONTACT); - return 1; - } - /* This mangle requests headers. */ - return mangle_sip_packet(pskb, ctinfo, ct, dptr, - ct_sip_lnlen(*dptr, - *dptr + (*pskb)->len - dataoff), - buffer, bufflen, POS_REQ_HEADER); + /* We need to reload this. Thanks Patrick. */ + *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + return 1; } static int mangle_content_len(struct sk_buff **pskb, -- cgit v1.2.3 From 829e17a1a602572ffa3beefe582dc103ee9fb9c7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 29 Nov 2006 02:35:33 +0100 Subject: [NETFILTER]: nfnetlink_queue: allow changing queue length through netlink Signed-off-by: Eric Leblond Signed-off-by: Patrick McHardy --- include/linux/netfilter/nfnetlink_queue.h | 1 + net/netfilter/nfnetlink_queue.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'include/linux') diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h index 4beea3d6fda8..83e789633e35 100644 --- a/include/linux/netfilter/nfnetlink_queue.h +++ b/include/linux/netfilter/nfnetlink_queue.h @@ -82,6 +82,7 @@ enum nfqnl_attr_config { NFQA_CFG_UNSPEC, NFQA_CFG_CMD, /* nfqnl_msg_config_cmd */ NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */ + NFQA_CFG_QUEUE_MAXLEN, /* u_int32_t */ __NFQA_CFG_MAX }; #define NFQA_CFG_MAX (__NFQA_CFG_MAX-1) diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 82e4454659bf..a88a017da22c 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -947,6 +947,14 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ntohl(params->copy_range)); } + if (nfqa[NFQA_CFG_QUEUE_MAXLEN-1]) { + __be32 *queue_maxlen; + queue_maxlen = NFA_DATA(nfqa[NFQA_CFG_QUEUE_MAXLEN-1]); + spin_lock_bh(&queue->lock); + queue->queue_maxlen = ntohl(*queue_maxlen); + spin_unlock_bh(&queue->lock); + } + out_put: instance_put(queue); return ret; -- cgit v1.2.3 From d7a5c32442ed3d528b9ddfd3d5b837bad0ffa9da Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:34 +0100 Subject: [NETFILTER]: nfnetlink_log: remove useless prefix length limitation There is no reason for limiting netlink attributes in size. Signed-off-by: Patrick McHardy --- include/linux/netfilter/nfnetlink_log.h | 2 -- net/netfilter/nfnetlink_log.c | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h index 55a2a2b814ed..5966afa026e9 100644 --- a/include/linux/netfilter/nfnetlink_log.h +++ b/include/linux/netfilter/nfnetlink_log.h @@ -32,8 +32,6 @@ struct nfulnl_msg_packet_timestamp { aligned_be64 usec; }; -#define NFULNL_PREFIXLEN 30 /* just like old log target */ - enum nfulnl_attr_type { NFULA_UNSPEC, NFULA_PACKET_HDR, diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index bd3ffa6f1a6d..d1505dd25c66 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -408,7 +408,7 @@ __build_packet_message(struct nfulnl_instance *inst, const struct net_device *indev, const struct net_device *outdev, const struct nf_loginfo *li, - const char *prefix) + const char *prefix, unsigned int plen) { unsigned char *old_tail; struct nfulnl_msg_packet_hdr pmsg; @@ -432,12 +432,8 @@ __build_packet_message(struct nfulnl_instance *inst, NFA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg); - if (prefix) { - int slen = strlen(prefix); - if (slen > NFULNL_PREFIXLEN) - slen = NFULNL_PREFIXLEN; - NFA_PUT(inst->skb, NFULA_PREFIX, slen, prefix); - } + if (prefix) + NFA_PUT(inst->skb, NFULA_PREFIX, plen, prefix); if (indev) { tmp_uint = htonl(indev->ifindex); @@ -601,6 +597,7 @@ nfulnl_log_packet(unsigned int pf, const struct nf_loginfo *li; unsigned int qthreshold; unsigned int nlbufsiz; + unsigned int plen; if (li_user && li_user->type == NF_LOG_TYPE_ULOG) li = li_user; @@ -616,6 +613,10 @@ nfulnl_log_packet(unsigned int pf, return; } + plen = 0; + if (prefix) + plen = strlen(prefix); + /* all macros expand to constant values at compile time */ /* FIXME: do we want to make the size calculation conditional based on * what is actually present? way more branches and checks, but more @@ -630,7 +631,7 @@ nfulnl_log_packet(unsigned int pf, #endif + NFA_SPACE(sizeof(u_int32_t)) /* mark */ + NFA_SPACE(sizeof(u_int32_t)) /* uid */ - + NFA_SPACE(NFULNL_PREFIXLEN) /* prefix */ + + NFA_SPACE(plen) /* prefix */ + NFA_SPACE(sizeof(struct nfulnl_msg_packet_hw)) + NFA_SPACE(sizeof(struct nfulnl_msg_packet_timestamp)); @@ -701,7 +702,7 @@ nfulnl_log_packet(unsigned int pf, inst->qlen++; __build_packet_message(inst, skb, data_len, pf, - hooknum, in, out, li, prefix); + hooknum, in, out, li, prefix, plen); /* timer_pending always called within inst->lock, so there * is no chance of a race here */ -- cgit v1.2.3 From 39b46fc6f0d1161a5585cd8af7b3a05e8118ab7e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:36 +0100 Subject: [NETFILTER]: x_tables: add port of hashlimit match for IPv4 and IPv6 Signed-off-by: Patrick McHardy --- include/linux/netfilter/Kbuild | 1 + include/linux/netfilter/xt_hashlimit.h | 40 ++ include/linux/netfilter_ipv4/ipt_hashlimit.h | 42 +- net/ipv4/netfilter/Kconfig | 14 - net/ipv4/netfilter/Makefile | 1 - net/ipv4/netfilter/ipt_hashlimit.c | 733 ------------------------- net/netfilter/Kconfig | 14 + net/netfilter/Makefile | 1 + net/netfilter/xt_hashlimit.c | 772 +++++++++++++++++++++++++++ 9 files changed, 836 insertions(+), 782 deletions(-) create mode 100644 include/linux/netfilter/xt_hashlimit.h delete mode 100644 net/ipv4/netfilter/ipt_hashlimit.c create mode 100644 net/netfilter/xt_hashlimit.c (limited to 'include/linux') diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index 312bd2ffee33..e379a2d89ea0 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -14,6 +14,7 @@ header-y += xt_dscp.h header-y += xt_DSCP.h header-y += xt_esp.h header-y += xt_helper.h +header-y += xt_hashlimit.h header-y += xt_length.h header-y += xt_limit.h header-y += xt_mac.h diff --git a/include/linux/netfilter/xt_hashlimit.h b/include/linux/netfilter/xt_hashlimit.h new file mode 100644 index 000000000000..b4556b8edbfd --- /dev/null +++ b/include/linux/netfilter/xt_hashlimit.h @@ -0,0 +1,40 @@ +#ifndef _XT_HASHLIMIT_H +#define _XT_HASHLIMIT_H + +/* timings are in milliseconds. */ +#define XT_HASHLIMIT_SCALE 10000 +/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 + seconds, or one every 59 hours. */ + +/* details of this structure hidden by the implementation */ +struct xt_hashlimit_htable; + +#define XT_HASHLIMIT_HASH_DIP 0x0001 +#define XT_HASHLIMIT_HASH_DPT 0x0002 +#define XT_HASHLIMIT_HASH_SIP 0x0004 +#define XT_HASHLIMIT_HASH_SPT 0x0008 + +struct hashlimit_cfg { + u_int32_t mode; /* bitmask of IPT_HASHLIMIT_HASH_* */ + u_int32_t avg; /* Average secs between packets * scale */ + u_int32_t burst; /* Period multiplier for upper limit. */ + + /* user specified */ + u_int32_t size; /* how many buckets */ + u_int32_t max; /* max number of entries */ + u_int32_t gc_interval; /* gc interval */ + u_int32_t expire; /* when do entries expire? */ +}; + +struct xt_hashlimit_info { + char name [IFNAMSIZ]; /* name */ + struct hashlimit_cfg cfg; + struct xt_hashlimit_htable *hinfo; + + /* Used internally by the kernel */ + union { + void *ptr; + struct xt_hashlimit_info *master; + } u; +}; +#endif /*_XT_HASHLIMIT_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_hashlimit.h b/include/linux/netfilter_ipv4/ipt_hashlimit.h index ac2cb64ecd76..5662120a3d7b 100644 --- a/include/linux/netfilter_ipv4/ipt_hashlimit.h +++ b/include/linux/netfilter_ipv4/ipt_hashlimit.h @@ -1,40 +1,14 @@ #ifndef _IPT_HASHLIMIT_H #define _IPT_HASHLIMIT_H -/* timings are in milliseconds. */ -#define IPT_HASHLIMIT_SCALE 10000 -/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 - seconds, or one every 59 hours. */ +#include -/* details of this structure hidden by the implementation */ -struct ipt_hashlimit_htable; +#define IPT_HASHLIMIT_SCALE XT_HASHLIMIT_SCALE +#define IPT_HASHLIMIT_HASH_DIP XT_HASHLIMIT_HASH_DIP +#define IPT_HASHLIMIT_HASH_DPT XT_HASHLIMIT_HASH_DPT +#define IPT_HASHLIMIT_HASH_SIP XT_HASHLIMIT_HASH_SIP +#define IPT_HASHLIMIT_HASH_SPT XT_HASHLIMIT_HASH_SPT -#define IPT_HASHLIMIT_HASH_DIP 0x0001 -#define IPT_HASHLIMIT_HASH_DPT 0x0002 -#define IPT_HASHLIMIT_HASH_SIP 0x0004 -#define IPT_HASHLIMIT_HASH_SPT 0x0008 +#define ipt_hashlimit_info xt_hashlimit_info -struct hashlimit_cfg { - u_int32_t mode; /* bitmask of IPT_HASHLIMIT_HASH_* */ - u_int32_t avg; /* Average secs between packets * scale */ - u_int32_t burst; /* Period multiplier for upper limit. */ - - /* user specified */ - u_int32_t size; /* how many buckets */ - u_int32_t max; /* max number of entries */ - u_int32_t gc_interval; /* gc interval */ - u_int32_t expire; /* when do entries expire? */ -}; - -struct ipt_hashlimit_info { - char name [IFNAMSIZ]; /* name */ - struct hashlimit_cfg cfg; - struct ipt_hashlimit_htable *hinfo; - - /* Used internally by the kernel */ - union { - void *ptr; - struct ipt_hashlimit_info *master; - } u; -}; -#endif /*_IPT_HASHLIMIT_H*/ +#endif /* _IPT_HASHLIMIT_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 4ac5b5c4678d..bc298a3f236f 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -326,20 +326,6 @@ config IP_NF_MATCH_ADDRTYPE If you want to compile it as a module, say M here and read . If unsure, say `N'. -config IP_NF_MATCH_HASHLIMIT - tristate 'hashlimit match support' - depends on IP_NF_IPTABLES - help - This option adds a new iptables `hashlimit' match. - - As opposed to `limit', this match dynamically creates a hash table - of limit buckets, based on your selection of source/destination - ip addresses and/or ports. - - It enables you to express policies like `10kpps for any given - destination IP' or `500pps from any given source IP' with a single - IPtables rule. - # `filter', generic and specific targets config IP_NF_FILTER tristate "Packet filtering" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 4ce20ebc4d6c..21359d83f0c7 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -53,7 +53,6 @@ obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o # matches -obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c deleted file mode 100644 index 33ccdbf8e794..000000000000 --- a/net/ipv4/netfilter/ipt_hashlimit.c +++ /dev/null @@ -1,733 +0,0 @@ -/* iptables match extension to limit the number of packets per second - * seperately for each hashbucket (sourceip/sourceport/dstip/dstport) - * - * (C) 2003-2004 by Harald Welte - * - * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $ - * - * Development of this code was funded by Astaro AG, http://www.astaro.com/ - * - * based on ipt_limit.c by: - * Jérôme de Vivie - * Hervé Eychenne - * Rusty Russell - * - * The general idea is to create a hash table for every dstip and have a - * seperate limit counter per tuple. This way you can do something like 'limit - * the number of syn packets for each of my internal addresses. - * - * Ideally this would just be implemented as a general 'hash' match, which would - * allow us to attach any iptables target to it's hash buckets. But this is - * not possible in the current iptables architecture. As always, pkttables for - * 2.7.x will help ;) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* FIXME: this is just for IP_NF_ASSERRT */ -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Harald Welte "); -MODULE_DESCRIPTION("iptables match for limiting per hash-bucket"); - -/* need to declare this at the top */ -static struct proc_dir_entry *hashlimit_procdir; -static struct file_operations dl_file_ops; - -/* hash table crap */ - -struct dsthash_dst { - __be32 src_ip; - __be32 dst_ip; - /* ports have to be consecutive !!! */ - __be16 src_port; - __be16 dst_port; -}; - -struct dsthash_ent { - /* static / read-only parts in the beginning */ - struct hlist_node node; - struct dsthash_dst dst; - - /* modified structure members in the end */ - unsigned long expires; /* precalculated expiry time */ - struct { - unsigned long prev; /* last modification */ - u_int32_t credit; - u_int32_t credit_cap, cost; - } rateinfo; -}; - -struct ipt_hashlimit_htable { - struct hlist_node node; /* global list of all htables */ - atomic_t use; - - struct hashlimit_cfg cfg; /* config */ - - /* used internally */ - spinlock_t lock; /* lock for list_head */ - u_int32_t rnd; /* random seed for hash */ - int rnd_initialized; - struct timer_list timer; /* timer for gc */ - atomic_t count; /* number entries in table */ - - /* seq_file stuff */ - struct proc_dir_entry *pde; - - struct hlist_head hash[0]; /* hashtable itself */ -}; - -static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ -static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ -static HLIST_HEAD(hashlimit_htables); -static kmem_cache_t *hashlimit_cachep __read_mostly; - -static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b) -{ - return (ent->dst.dst_ip == b->dst_ip - && ent->dst.dst_port == b->dst_port - && ent->dst.src_port == b->src_port - && ent->dst.src_ip == b->src_ip); -} - -static inline u_int32_t -hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst) -{ - return (jhash_3words((__force u32)dst->dst_ip, - ((__force u32)dst->dst_port<<16 | - (__force u32)dst->src_port), - (__force u32)dst->src_ip, ht->rnd) % ht->cfg.size); -} - -static inline struct dsthash_ent * -__dsthash_find(const struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst) -{ - struct dsthash_ent *ent; - struct hlist_node *pos; - u_int32_t hash = hash_dst(ht, dst); - - if (!hlist_empty(&ht->hash[hash])) - hlist_for_each_entry(ent, pos, &ht->hash[hash], node) { - if (dst_cmp(ent, dst)) { - return ent; - } - } - - return NULL; -} - -/* allocate dsthash_ent, initialize dst, put in htable and lock it */ -static struct dsthash_ent * -__dsthash_alloc_init(struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst) -{ - struct dsthash_ent *ent; - - /* initialize hash with random val at the time we allocate - * the first hashtable entry */ - if (!ht->rnd_initialized) { - get_random_bytes(&ht->rnd, 4); - ht->rnd_initialized = 1; - } - - if (ht->cfg.max && - atomic_read(&ht->count) >= ht->cfg.max) { - /* FIXME: do something. question is what.. */ - if (net_ratelimit()) - printk(KERN_WARNING - "ipt_hashlimit: max count of %u reached\n", - ht->cfg.max); - return NULL; - } - - ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC); - if (!ent) { - if (net_ratelimit()) - printk(KERN_ERR - "ipt_hashlimit: can't allocate dsthash_ent\n"); - return NULL; - } - - atomic_inc(&ht->count); - - ent->dst.dst_ip = dst->dst_ip; - ent->dst.dst_port = dst->dst_port; - ent->dst.src_ip = dst->src_ip; - ent->dst.src_port = dst->src_port; - - hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]); - - return ent; -} - -static inline void -__dsthash_free(struct ipt_hashlimit_htable *ht, struct dsthash_ent *ent) -{ - hlist_del(&ent->node); - kmem_cache_free(hashlimit_cachep, ent); - atomic_dec(&ht->count); -} -static void htable_gc(unsigned long htlong); - -static int htable_create(struct ipt_hashlimit_info *minfo) -{ - int i; - unsigned int size; - struct ipt_hashlimit_htable *hinfo; - - if (minfo->cfg.size) - size = minfo->cfg.size; - else { - size = (((num_physpages << PAGE_SHIFT) / 16384) - / sizeof(struct list_head)); - if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) - size = 8192; - if (size < 16) - size = 16; - } - /* FIXME: don't use vmalloc() here or anywhere else -HW */ - hinfo = vmalloc(sizeof(struct ipt_hashlimit_htable) - + (sizeof(struct list_head) * size)); - if (!hinfo) { - printk(KERN_ERR "ipt_hashlimit: Unable to create hashtable\n"); - return -1; - } - minfo->hinfo = hinfo; - - /* copy match config into hashtable config */ - memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg)); - hinfo->cfg.size = size; - if (!hinfo->cfg.max) - hinfo->cfg.max = 8 * hinfo->cfg.size; - else if (hinfo->cfg.max < hinfo->cfg.size) - hinfo->cfg.max = hinfo->cfg.size; - - for (i = 0; i < hinfo->cfg.size; i++) - INIT_HLIST_HEAD(&hinfo->hash[i]); - - atomic_set(&hinfo->count, 0); - atomic_set(&hinfo->use, 1); - hinfo->rnd_initialized = 0; - spin_lock_init(&hinfo->lock); - hinfo->pde = create_proc_entry(minfo->name, 0, hashlimit_procdir); - if (!hinfo->pde) { - vfree(hinfo); - return -1; - } - hinfo->pde->proc_fops = &dl_file_ops; - hinfo->pde->data = hinfo; - - init_timer(&hinfo->timer); - hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); - hinfo->timer.data = (unsigned long )hinfo; - hinfo->timer.function = htable_gc; - add_timer(&hinfo->timer); - - spin_lock_bh(&hashlimit_lock); - hlist_add_head(&hinfo->node, &hashlimit_htables); - spin_unlock_bh(&hashlimit_lock); - - return 0; -} - -static int select_all(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he) -{ - return 1; -} - -static int select_gc(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he) -{ - return (jiffies >= he->expires); -} - -static void htable_selective_cleanup(struct ipt_hashlimit_htable *ht, - int (*select)(struct ipt_hashlimit_htable *ht, - struct dsthash_ent *he)) -{ - int i; - - IP_NF_ASSERT(ht->cfg.size && ht->cfg.max); - - /* lock hash table and iterate over it */ - spin_lock_bh(&ht->lock); - for (i = 0; i < ht->cfg.size; i++) { - struct dsthash_ent *dh; - struct hlist_node *pos, *n; - hlist_for_each_entry_safe(dh, pos, n, &ht->hash[i], node) { - if ((*select)(ht, dh)) - __dsthash_free(ht, dh); - } - } - spin_unlock_bh(&ht->lock); -} - -/* hash table garbage collector, run by timer */ -static void htable_gc(unsigned long htlong) -{ - struct ipt_hashlimit_htable *ht = (struct ipt_hashlimit_htable *)htlong; - - htable_selective_cleanup(ht, select_gc); - - /* re-add the timer accordingly */ - ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval); - add_timer(&ht->timer); -} - -static void htable_destroy(struct ipt_hashlimit_htable *hinfo) -{ - /* remove timer, if it is pending */ - if (timer_pending(&hinfo->timer)) - del_timer(&hinfo->timer); - - /* remove proc entry */ - remove_proc_entry(hinfo->pde->name, hashlimit_procdir); - - htable_selective_cleanup(hinfo, select_all); - vfree(hinfo); -} - -static struct ipt_hashlimit_htable *htable_find_get(char *name) -{ - struct ipt_hashlimit_htable *hinfo; - struct hlist_node *pos; - - spin_lock_bh(&hashlimit_lock); - hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) { - if (!strcmp(name, hinfo->pde->name)) { - atomic_inc(&hinfo->use); - spin_unlock_bh(&hashlimit_lock); - return hinfo; - } - } - spin_unlock_bh(&hashlimit_lock); - - return NULL; -} - -static void htable_put(struct ipt_hashlimit_htable *hinfo) -{ - if (atomic_dec_and_test(&hinfo->use)) { - spin_lock_bh(&hashlimit_lock); - hlist_del(&hinfo->node); - spin_unlock_bh(&hashlimit_lock); - htable_destroy(hinfo); - } -} - - -/* The algorithm used is the Simple Token Bucket Filter (TBF) - * see net/sched/sch_tbf.c in the linux source tree - */ - -/* Rusty: This is my (non-mathematically-inclined) understanding of - this algorithm. The `average rate' in jiffies becomes your initial - amount of credit `credit' and the most credit you can ever have - `credit_cap'. The `peak rate' becomes the cost of passing the - test, `cost'. - - `prev' tracks the last packet hit: you gain one credit per jiffy. - If you get credit balance more than this, the extra credit is - discarded. Every time the match passes, you lose `cost' credits; - if you don't have that many, the test fails. - - See Alexey's formal explanation in net/sched/sch_tbf.c. - - To get the maximum range, we multiply by this factor (ie. you get N - credits per jiffy). We want to allow a rate as low as 1 per day - (slowest userspace tool allows), which means - CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie. -*/ -#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) - -/* Repeated shift and or gives us all 1s, final shift and add 1 gives - * us the power of 2 below the theoretical max, so GCC simply does a - * shift. */ -#define _POW2_BELOW2(x) ((x)|((x)>>1)) -#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) -#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) -#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) -#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) -#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) - -#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) - -/* Precision saver. */ -static inline u_int32_t -user2credits(u_int32_t user) -{ - /* If multiplying would overflow... */ - if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) - /* Divide first. */ - return (user / IPT_HASHLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; - - return (user * HZ * CREDITS_PER_JIFFY) / IPT_HASHLIMIT_SCALE; -} - -static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now) -{ - dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now)) - * CREDITS_PER_JIFFY; - if (dh->rateinfo.credit > dh->rateinfo.credit_cap) - dh->rateinfo.credit = dh->rateinfo.credit_cap; -} - -static int -hashlimit_match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct xt_match *match, - const void *matchinfo, - int offset, - unsigned int protoff, - int *hotdrop) -{ - struct ipt_hashlimit_info *r = - ((struct ipt_hashlimit_info *)matchinfo)->u.master; - struct ipt_hashlimit_htable *hinfo = r->hinfo; - unsigned long now = jiffies; - struct dsthash_ent *dh; - struct dsthash_dst dst; - - /* build 'dst' according to hinfo->cfg and current packet */ - memset(&dst, 0, sizeof(dst)); - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DIP) - dst.dst_ip = skb->nh.iph->daddr; - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SIP) - dst.src_ip = skb->nh.iph->saddr; - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT - ||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) { - __be16 _ports[2], *ports; - - switch (skb->nh.iph->protocol) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_SCTP: - case IPPROTO_DCCP: - ports = skb_header_pointer(skb, skb->nh.iph->ihl*4, - sizeof(_ports), &_ports); - break; - default: - _ports[0] = _ports[1] = 0; - ports = _ports; - break; - } - if (!ports) { - /* We've been asked to examine this packet, and we - can't. Hence, no choice but to drop. */ - *hotdrop = 1; - return 0; - } - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) - dst.src_port = ports[0]; - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT) - dst.dst_port = ports[1]; - } - - spin_lock_bh(&hinfo->lock); - dh = __dsthash_find(hinfo, &dst); - if (!dh) { - dh = __dsthash_alloc_init(hinfo, &dst); - - if (!dh) { - /* enomem... don't match == DROP */ - if (net_ratelimit()) - printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__); - spin_unlock_bh(&hinfo->lock); - return 0; - } - - dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); - - dh->rateinfo.prev = jiffies; - dh->rateinfo.credit = user2credits(hinfo->cfg.avg * - hinfo->cfg.burst); - dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * - hinfo->cfg.burst); - dh->rateinfo.cost = user2credits(hinfo->cfg.avg); - } else { - /* update expiration timeout */ - dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); - rateinfo_recalc(dh, now); - } - - if (dh->rateinfo.credit >= dh->rateinfo.cost) { - /* We're underlimit. */ - dh->rateinfo.credit -= dh->rateinfo.cost; - spin_unlock_bh(&hinfo->lock); - return 1; - } - - spin_unlock_bh(&hinfo->lock); - - /* default case: we're overlimit, thus don't match */ - return 0; -} - -static int -hashlimit_checkentry(const char *tablename, - const void *inf, - const struct xt_match *match, - void *matchinfo, - unsigned int hook_mask) -{ - struct ipt_hashlimit_info *r = matchinfo; - - /* Check for overflow. */ - if (r->cfg.burst == 0 - || user2credits(r->cfg.avg * r->cfg.burst) < - user2credits(r->cfg.avg)) { - printk(KERN_ERR "ipt_hashlimit: Overflow, try lower: %u/%u\n", - r->cfg.avg, r->cfg.burst); - return 0; - } - - if (r->cfg.mode == 0 - || r->cfg.mode > (IPT_HASHLIMIT_HASH_DPT - |IPT_HASHLIMIT_HASH_DIP - |IPT_HASHLIMIT_HASH_SIP - |IPT_HASHLIMIT_HASH_SPT)) - return 0; - - if (!r->cfg.gc_interval) - return 0; - - if (!r->cfg.expire) - return 0; - - if (r->name[sizeof(r->name) - 1] != '\0') - return 0; - - /* This is the best we've got: We cannot release and re-grab lock, - * since checkentry() is called before ip_tables.c grabs ipt_mutex. - * We also cannot grab the hashtable spinlock, since htable_create will - * call vmalloc, and that can sleep. And we cannot just re-search - * the list of htable's in htable_create(), since then we would - * create duplicate proc files. -HW */ - mutex_lock(&hlimit_mutex); - r->hinfo = htable_find_get(r->name); - if (!r->hinfo && (htable_create(r) != 0)) { - mutex_unlock(&hlimit_mutex); - return 0; - } - mutex_unlock(&hlimit_mutex); - - /* Ugly hack: For SMP, we only want to use one set */ - r->u.master = r; - - return 1; -} - -static void -hashlimit_destroy(const struct xt_match *match, void *matchinfo) -{ - struct ipt_hashlimit_info *r = matchinfo; - - htable_put(r->hinfo); -} - -#ifdef CONFIG_COMPAT -struct compat_ipt_hashlimit_info { - char name[IFNAMSIZ]; - struct hashlimit_cfg cfg; - compat_uptr_t hinfo; - compat_uptr_t master; -}; - -static void compat_from_user(void *dst, void *src) -{ - int off = offsetof(struct compat_ipt_hashlimit_info, hinfo); - - memcpy(dst, src, off); - memset(dst + off, 0, sizeof(struct compat_ipt_hashlimit_info) - off); -} - -static int compat_to_user(void __user *dst, void *src) -{ - int off = offsetof(struct compat_ipt_hashlimit_info, hinfo); - - return copy_to_user(dst, src, off) ? -EFAULT : 0; -} -#endif - -static struct ipt_match ipt_hashlimit = { - .name = "hashlimit", - .match = hashlimit_match, - .matchsize = sizeof(struct ipt_hashlimit_info), -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_ipt_hashlimit_info), - .compat_from_user = compat_from_user, - .compat_to_user = compat_to_user, -#endif - .checkentry = hashlimit_checkentry, - .destroy = hashlimit_destroy, - .me = THIS_MODULE -}; - -/* PROC stuff */ - -static void *dl_seq_start(struct seq_file *s, loff_t *pos) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket; - - spin_lock_bh(&htable->lock); - if (*pos >= htable->cfg.size) - return NULL; - - bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC); - if (!bucket) - return ERR_PTR(-ENOMEM); - - *bucket = *pos; - return bucket; -} - -static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket = (unsigned int *)v; - - *pos = ++(*bucket); - if (*pos >= htable->cfg.size) { - kfree(v); - return NULL; - } - return bucket; -} - -static void dl_seq_stop(struct seq_file *s, void *v) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket = (unsigned int *)v; - - kfree(bucket); - - spin_unlock_bh(&htable->lock); -} - -static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s) -{ - /* recalculate to show accurate numbers */ - rateinfo_recalc(ent, jiffies); - - return seq_printf(s, "%ld %u.%u.%u.%u:%u->%u.%u.%u.%u:%u %u %u %u\n", - (long)(ent->expires - jiffies)/HZ, - NIPQUAD(ent->dst.src_ip), ntohs(ent->dst.src_port), - NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.dst_port), - ent->rateinfo.credit, ent->rateinfo.credit_cap, - ent->rateinfo.cost); -} - -static int dl_seq_show(struct seq_file *s, void *v) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket = (unsigned int *)v; - struct dsthash_ent *ent; - struct hlist_node *pos; - - if (!hlist_empty(&htable->hash[*bucket])) - hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node) { - if (dl_seq_real_show(ent, s)) { - /* buffer was filled and unable to print that tuple */ - return 1; - } - } - - return 0; -} - -static struct seq_operations dl_seq_ops = { - .start = dl_seq_start, - .next = dl_seq_next, - .stop = dl_seq_stop, - .show = dl_seq_show -}; - -static int dl_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &dl_seq_ops); - - if (!ret) { - struct seq_file *sf = file->private_data; - sf->private = PDE(inode); - } - return ret; -} - -static struct file_operations dl_file_ops = { - .owner = THIS_MODULE, - .open = dl_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release -}; - -static int init_or_fini(int fini) -{ - int ret = 0; - - if (fini) - goto cleanup; - - if (ipt_register_match(&ipt_hashlimit)) { - ret = -EINVAL; - goto cleanup_nothing; - } - - hashlimit_cachep = kmem_cache_create("ipt_hashlimit", - sizeof(struct dsthash_ent), 0, - 0, NULL, NULL); - if (!hashlimit_cachep) { - printk(KERN_ERR "Unable to create ipt_hashlimit slab cache\n"); - ret = -ENOMEM; - goto cleanup_unreg_match; - } - - hashlimit_procdir = proc_mkdir("ipt_hashlimit", proc_net); - if (!hashlimit_procdir) { - printk(KERN_ERR "Unable to create proc dir entry\n"); - ret = -ENOMEM; - goto cleanup_free_slab; - } - - return ret; - -cleanup: - remove_proc_entry("ipt_hashlimit", proc_net); -cleanup_free_slab: - kmem_cache_destroy(hashlimit_cachep); -cleanup_unreg_match: - ipt_unregister_match(&ipt_hashlimit); -cleanup_nothing: - return ret; - -} - -static int __init ipt_hashlimit_init(void) -{ - return init_or_fini(0); -} - -static void __exit ipt_hashlimit_fini(void) -{ - init_or_fini(1); -} - -module_init(ipt_hashlimit_init); -module_exit(ipt_hashlimit_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f619c6527266..7e6125467c12 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -464,5 +464,19 @@ config NETFILTER_XT_MATCH_TCPMSS To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_MATCH_HASHLIMIT + tristate '"hashlimit" match support' + depends on NETFILTER_XTABLES + help + This option adds a `hashlimit' match. + + As opposed to `limit', this match dynamically creates a hash table + of limit buckets, based on your selection of source/destination + addresses and/or ports. + + It enables you to express policies like `10kpps for any given + destination address' or `500pps from any given source address' + with a single rule. + endmenu diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 84d529ded952..f85811bfcfe5 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -59,3 +59,4 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o +obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c new file mode 100644 index 000000000000..46de566d3721 --- /dev/null +++ b/net/netfilter/xt_hashlimit.c @@ -0,0 +1,772 @@ +/* iptables match extension to limit the number of packets per second + * seperately for each hashbucket (sourceip/sourceport/dstip/dstport) + * + * (C) 2003-2004 by Harald Welte + * + * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $ + * + * Development of this code was funded by Astaro AG, http://www.astaro.com/ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("iptables match for limiting per hash-bucket"); +MODULE_ALIAS("ipt_hashlimit"); +MODULE_ALIAS("ip6t_hashlimit"); + +/* need to declare this at the top */ +static struct proc_dir_entry *hashlimit_procdir4; +static struct proc_dir_entry *hashlimit_procdir6; +static struct file_operations dl_file_ops; + +/* hash table crap */ +struct dsthash_dst { + union { + struct { + __be32 src; + __be32 dst; + } ip; + struct { + __be32 src[4]; + __be32 dst[4]; + } ip6; + } addr; + __be16 src_port; + __be16 dst_port; +}; + +struct dsthash_ent { + /* static / read-only parts in the beginning */ + struct hlist_node node; + struct dsthash_dst dst; + + /* modified structure members in the end */ + unsigned long expires; /* precalculated expiry time */ + struct { + unsigned long prev; /* last modification */ + u_int32_t credit; + u_int32_t credit_cap, cost; + } rateinfo; +}; + +struct xt_hashlimit_htable { + struct hlist_node node; /* global list of all htables */ + atomic_t use; + int family; + + struct hashlimit_cfg cfg; /* config */ + + /* used internally */ + spinlock_t lock; /* lock for list_head */ + u_int32_t rnd; /* random seed for hash */ + int rnd_initialized; + unsigned int count; /* number entries in table */ + struct timer_list timer; /* timer for gc */ + + /* seq_file stuff */ + struct proc_dir_entry *pde; + + struct hlist_head hash[0]; /* hashtable itself */ +}; + +static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ +static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ +static HLIST_HEAD(hashlimit_htables); +static kmem_cache_t *hashlimit_cachep __read_mostly; + +static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b) +{ + return !memcmp(&ent->dst, b, sizeof(ent->dst)); +} + +static u_int32_t +hash_dst(const struct xt_hashlimit_htable *ht, const struct dsthash_dst *dst) +{ + return jhash(dst, sizeof(*dst), ht->rnd) % ht->cfg.size; +} + +static struct dsthash_ent * +dsthash_find(const struct xt_hashlimit_htable *ht, struct dsthash_dst *dst) +{ + struct dsthash_ent *ent; + struct hlist_node *pos; + u_int32_t hash = hash_dst(ht, dst); + + if (!hlist_empty(&ht->hash[hash])) { + hlist_for_each_entry(ent, pos, &ht->hash[hash], node) + if (dst_cmp(ent, dst)) + return ent; + } + return NULL; +} + +/* allocate dsthash_ent, initialize dst, put in htable and lock it */ +static struct dsthash_ent * +dsthash_alloc_init(struct xt_hashlimit_htable *ht, struct dsthash_dst *dst) +{ + struct dsthash_ent *ent; + + /* initialize hash with random val at the time we allocate + * the first hashtable entry */ + if (!ht->rnd_initialized) { + get_random_bytes(&ht->rnd, 4); + ht->rnd_initialized = 1; + } + + if (ht->cfg.max && ht->count >= ht->cfg.max) { + /* FIXME: do something. question is what.. */ + if (net_ratelimit()) + printk(KERN_WARNING + "xt_hashlimit: max count of %u reached\n", + ht->cfg.max); + return NULL; + } + + ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC); + if (!ent) { + if (net_ratelimit()) + printk(KERN_ERR + "xt_hashlimit: can't allocate dsthash_ent\n"); + return NULL; + } + memcpy(&ent->dst, dst, sizeof(ent->dst)); + + hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]); + ht->count++; + return ent; +} + +static inline void +dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent) +{ + hlist_del(&ent->node); + kmem_cache_free(hashlimit_cachep, ent); + ht->count--; +} +static void htable_gc(unsigned long htlong); + +static int htable_create(struct xt_hashlimit_info *minfo, int family) +{ + struct xt_hashlimit_htable *hinfo; + unsigned int size; + unsigned int i; + + if (minfo->cfg.size) + size = minfo->cfg.size; + else { + size = ((num_physpages << PAGE_SHIFT) / 16384) / + sizeof(struct list_head); + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) + size = 8192; + if (size < 16) + size = 16; + } + /* FIXME: don't use vmalloc() here or anywhere else -HW */ + hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + + sizeof(struct list_head) * size); + if (!hinfo) { + printk(KERN_ERR "xt_hashlimit: unable to create hashtable\n"); + return -1; + } + minfo->hinfo = hinfo; + + /* copy match config into hashtable config */ + memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg)); + hinfo->cfg.size = size; + if (!hinfo->cfg.max) + hinfo->cfg.max = 8 * hinfo->cfg.size; + else if (hinfo->cfg.max < hinfo->cfg.size) + hinfo->cfg.max = hinfo->cfg.size; + + for (i = 0; i < hinfo->cfg.size; i++) + INIT_HLIST_HEAD(&hinfo->hash[i]); + + atomic_set(&hinfo->use, 1); + hinfo->count = 0; + hinfo->family = family; + hinfo->rnd_initialized = 0; + spin_lock_init(&hinfo->lock); + hinfo->pde = create_proc_entry(minfo->name, 0, + family == AF_INET ? hashlimit_procdir4 : + hashlimit_procdir6); + if (!hinfo->pde) { + vfree(hinfo); + return -1; + } + hinfo->pde->proc_fops = &dl_file_ops; + hinfo->pde->data = hinfo; + + init_timer(&hinfo->timer); + hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); + hinfo->timer.data = (unsigned long )hinfo; + hinfo->timer.function = htable_gc; + add_timer(&hinfo->timer); + + spin_lock_bh(&hashlimit_lock); + hlist_add_head(&hinfo->node, &hashlimit_htables); + spin_unlock_bh(&hashlimit_lock); + + return 0; +} + +static int select_all(struct xt_hashlimit_htable *ht, struct dsthash_ent *he) +{ + return 1; +} + +static int select_gc(struct xt_hashlimit_htable *ht, struct dsthash_ent *he) +{ + return (jiffies >= he->expires); +} + +static void htable_selective_cleanup(struct xt_hashlimit_htable *ht, + int (*select)(struct xt_hashlimit_htable *ht, + struct dsthash_ent *he)) +{ + unsigned int i; + + /* lock hash table and iterate over it */ + spin_lock_bh(&ht->lock); + for (i = 0; i < ht->cfg.size; i++) { + struct dsthash_ent *dh; + struct hlist_node *pos, *n; + hlist_for_each_entry_safe(dh, pos, n, &ht->hash[i], node) { + if ((*select)(ht, dh)) + dsthash_free(ht, dh); + } + } + spin_unlock_bh(&ht->lock); +} + +/* hash table garbage collector, run by timer */ +static void htable_gc(unsigned long htlong) +{ + struct xt_hashlimit_htable *ht = (struct xt_hashlimit_htable *)htlong; + + htable_selective_cleanup(ht, select_gc); + + /* re-add the timer accordingly */ + ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval); + add_timer(&ht->timer); +} + +static void htable_destroy(struct xt_hashlimit_htable *hinfo) +{ + /* remove timer, if it is pending */ + if (timer_pending(&hinfo->timer)) + del_timer(&hinfo->timer); + + /* remove proc entry */ + remove_proc_entry(hinfo->pde->name, + hinfo->family == AF_INET ? hashlimit_procdir4 : + hashlimit_procdir6); + htable_selective_cleanup(hinfo, select_all); + vfree(hinfo); +} + +static struct xt_hashlimit_htable *htable_find_get(char *name, int family) +{ + struct xt_hashlimit_htable *hinfo; + struct hlist_node *pos; + + spin_lock_bh(&hashlimit_lock); + hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) { + if (!strcmp(name, hinfo->pde->name) && + hinfo->family == family) { + atomic_inc(&hinfo->use); + spin_unlock_bh(&hashlimit_lock); + return hinfo; + } + } + spin_unlock_bh(&hashlimit_lock); + return NULL; +} + +static void htable_put(struct xt_hashlimit_htable *hinfo) +{ + if (atomic_dec_and_test(&hinfo->use)) { + spin_lock_bh(&hashlimit_lock); + hlist_del(&hinfo->node); + spin_unlock_bh(&hashlimit_lock); + htable_destroy(hinfo); + } +} + +/* The algorithm used is the Simple Token Bucket Filter (TBF) + * see net/sched/sch_tbf.c in the linux source tree + */ + +/* Rusty: This is my (non-mathematically-inclined) understanding of + this algorithm. The `average rate' in jiffies becomes your initial + amount of credit `credit' and the most credit you can ever have + `credit_cap'. The `peak rate' becomes the cost of passing the + test, `cost'. + + `prev' tracks the last packet hit: you gain one credit per jiffy. + If you get credit balance more than this, the extra credit is + discarded. Every time the match passes, you lose `cost' credits; + if you don't have that many, the test fails. + + See Alexey's formal explanation in net/sched/sch_tbf.c. + + To get the maximum range, we multiply by this factor (ie. you get N + credits per jiffy). We want to allow a rate as low as 1 per day + (slowest userspace tool allows), which means + CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie. +*/ +#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) + +/* Repeated shift and or gives us all 1s, final shift and add 1 gives + * us the power of 2 below the theoretical max, so GCC simply does a + * shift. */ +#define _POW2_BELOW2(x) ((x)|((x)>>1)) +#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) +#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) +#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) +#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) +#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) + +#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) + +/* Precision saver. */ +static inline u_int32_t +user2credits(u_int32_t user) +{ + /* If multiplying would overflow... */ + if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) + /* Divide first. */ + return (user / XT_HASHLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; + + return (user * HZ * CREDITS_PER_JIFFY) / XT_HASHLIMIT_SCALE; +} + +static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now) +{ + dh->rateinfo.credit += (now - dh->rateinfo.prev) * CREDITS_PER_JIFFY; + if (dh->rateinfo.credit > dh->rateinfo.credit_cap) + dh->rateinfo.credit = dh->rateinfo.credit_cap; + dh->rateinfo.prev = now; +} + +static int +hashlimit_init_dst(struct xt_hashlimit_htable *hinfo, struct dsthash_dst *dst, + const struct sk_buff *skb, unsigned int protoff) +{ + __be16 _ports[2], *ports; + int nexthdr; + + memset(dst, 0, sizeof(*dst)); + + switch (hinfo->family) { + case AF_INET: + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) + dst->addr.ip.dst = skb->nh.iph->daddr; + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) + dst->addr.ip.src = skb->nh.iph->saddr; + + if (!(hinfo->cfg.mode & + (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT))) + return 0; + nexthdr = skb->nh.iph->protocol; + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) + memcpy(&dst->addr.ip6.dst, &skb->nh.ipv6h->daddr, + sizeof(dst->addr.ip6.dst)); + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) + memcpy(&dst->addr.ip6.src, &skb->nh.ipv6h->saddr, + sizeof(dst->addr.ip6.src)); + + if (!(hinfo->cfg.mode & + (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT))) + return 0; + nexthdr = ipv6_find_hdr(skb, &protoff, -1, NULL); + if (nexthdr < 0) + return -1; + break; +#endif + default: + BUG(); + return 0; + } + + switch (nexthdr) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_SCTP: + case IPPROTO_DCCP: + ports = skb_header_pointer(skb, protoff, sizeof(_ports), + &_ports); + break; + default: + _ports[0] = _ports[1] = 0; + ports = _ports; + break; + } + if (!ports) + return -1; + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SPT) + dst->src_port = ports[0]; + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DPT) + dst->dst_port = ports[1]; + return 0; +} + +static int +hashlimit_match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct xt_match *match, + const void *matchinfo, + int offset, + unsigned int protoff, + int *hotdrop) +{ + struct xt_hashlimit_info *r = + ((struct xt_hashlimit_info *)matchinfo)->u.master; + struct xt_hashlimit_htable *hinfo = r->hinfo; + unsigned long now = jiffies; + struct dsthash_ent *dh; + struct dsthash_dst dst; + + if (hashlimit_init_dst(hinfo, &dst, skb, protoff) < 0) + goto hotdrop; + + spin_lock_bh(&hinfo->lock); + dh = dsthash_find(hinfo, &dst); + if (!dh) { + dh = dsthash_alloc_init(hinfo, &dst); + if (!dh) { + spin_unlock_bh(&hinfo->lock); + goto hotdrop; + } + + dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); + dh->rateinfo.prev = jiffies; + dh->rateinfo.credit = user2credits(hinfo->cfg.avg * + hinfo->cfg.burst); + dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * + hinfo->cfg.burst); + dh->rateinfo.cost = user2credits(hinfo->cfg.avg); + } else { + /* update expiration timeout */ + dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); + rateinfo_recalc(dh, now); + } + + if (dh->rateinfo.credit >= dh->rateinfo.cost) { + /* We're underlimit. */ + dh->rateinfo.credit -= dh->rateinfo.cost; + spin_unlock_bh(&hinfo->lock); + return 1; + } + + spin_unlock_bh(&hinfo->lock); + + /* default case: we're overlimit, thus don't match */ + return 0; + +hotdrop: + *hotdrop = 1; + return 0; +} + +static int +hashlimit_checkentry(const char *tablename, + const void *inf, + const struct xt_match *match, + void *matchinfo, + unsigned int hook_mask) +{ + struct xt_hashlimit_info *r = matchinfo; + + /* Check for overflow. */ + if (r->cfg.burst == 0 || + user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) { + printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n", + r->cfg.avg, r->cfg.burst); + return 0; + } + if (r->cfg.mode == 0 || + r->cfg.mode > (XT_HASHLIMIT_HASH_DPT | + XT_HASHLIMIT_HASH_DIP | + XT_HASHLIMIT_HASH_SIP | + XT_HASHLIMIT_HASH_SPT)) + return 0; + if (!r->cfg.gc_interval) + return 0; + if (!r->cfg.expire) + return 0; + if (r->name[sizeof(r->name) - 1] != '\0') + return 0; + + /* This is the best we've got: We cannot release and re-grab lock, + * since checkentry() is called before x_tables.c grabs xt_mutex. + * We also cannot grab the hashtable spinlock, since htable_create will + * call vmalloc, and that can sleep. And we cannot just re-search + * the list of htable's in htable_create(), since then we would + * create duplicate proc files. -HW */ + mutex_lock(&hlimit_mutex); + r->hinfo = htable_find_get(r->name, match->family); + if (!r->hinfo && htable_create(r, match->family) != 0) { + mutex_unlock(&hlimit_mutex); + return 0; + } + mutex_unlock(&hlimit_mutex); + + /* Ugly hack: For SMP, we only want to use one set */ + r->u.master = r; + return 1; +} + +static void +hashlimit_destroy(const struct xt_match *match, void *matchinfo) +{ + struct xt_hashlimit_info *r = matchinfo; + + htable_put(r->hinfo); +} + +#ifdef CONFIG_COMPAT +struct compat_xt_hashlimit_info { + char name[IFNAMSIZ]; + struct hashlimit_cfg cfg; + compat_uptr_t hinfo; + compat_uptr_t master; +}; + +static void compat_from_user(void *dst, void *src) +{ + int off = offsetof(struct compat_xt_hashlimit_info, hinfo); + + memcpy(dst, src, off); + memset(dst + off, 0, sizeof(struct compat_xt_hashlimit_info) - off); +} + +static int compat_to_user(void __user *dst, void *src) +{ + int off = offsetof(struct compat_xt_hashlimit_info, hinfo); + + return copy_to_user(dst, src, off) ? -EFAULT : 0; +} +#endif + +static struct xt_match xt_hashlimit[] = { + { + .name = "hashlimit", + .family = AF_INET, + .match = hashlimit_match, + .matchsize = sizeof(struct xt_hashlimit_info), +#ifdef CONFIG_COMPAT + .compatsize = sizeof(struct compat_xt_hashlimit_info), + .compat_from_user = compat_from_user, + .compat_to_user = compat_to_user, +#endif + .checkentry = hashlimit_checkentry, + .destroy = hashlimit_destroy, + .me = THIS_MODULE + }, + { + .name = "hashlimit", + .family = AF_INET6, + .match = hashlimit_match, + .matchsize = sizeof(struct xt_hashlimit_info), +#ifdef CONFIG_COMPAT + .compatsize = sizeof(struct compat_xt_hashlimit_info), + .compat_from_user = compat_from_user, + .compat_to_user = compat_to_user, +#endif + .checkentry = hashlimit_checkentry, + .destroy = hashlimit_destroy, + .me = THIS_MODULE + }, +}; + +/* PROC stuff */ +static void *dl_seq_start(struct seq_file *s, loff_t *pos) +{ + struct proc_dir_entry *pde = s->private; + struct xt_hashlimit_htable *htable = pde->data; + unsigned int *bucket; + + spin_lock_bh(&htable->lock); + if (*pos >= htable->cfg.size) + return NULL; + + bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC); + if (!bucket) + return ERR_PTR(-ENOMEM); + + *bucket = *pos; + return bucket; +} + +static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct proc_dir_entry *pde = s->private; + struct xt_hashlimit_htable *htable = pde->data; + unsigned int *bucket = (unsigned int *)v; + + *pos = ++(*bucket); + if (*pos >= htable->cfg.size) { + kfree(v); + return NULL; + } + return bucket; +} + +static void dl_seq_stop(struct seq_file *s, void *v) +{ + struct proc_dir_entry *pde = s->private; + struct xt_hashlimit_htable *htable = pde->data; + unsigned int *bucket = (unsigned int *)v; + + kfree(bucket); + spin_unlock_bh(&htable->lock); +} + +static int dl_seq_real_show(struct dsthash_ent *ent, int family, + struct seq_file *s) +{ + /* recalculate to show accurate numbers */ + rateinfo_recalc(ent, jiffies); + + switch (family) { + case AF_INET: + return seq_printf(s, "%ld %u.%u.%u.%u:%u->" + "%u.%u.%u.%u:%u %u %u %u\n", + (long)(ent->expires - jiffies)/HZ, + NIPQUAD(ent->dst.addr.ip.src), + ntohs(ent->dst.src_port), + NIPQUAD(ent->dst.addr.ip.dst), + ntohs(ent->dst.dst_port), + ent->rateinfo.credit, ent->rateinfo.credit_cap, + ent->rateinfo.cost); + case AF_INET6: + return seq_printf(s, "%ld " NIP6_FMT ":%u->" + NIP6_FMT ":%u %u %u %u\n", + (long)(ent->expires - jiffies)/HZ, + NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.src), + ntohs(ent->dst.src_port), + NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.dst), + ntohs(ent->dst.dst_port), + ent->rateinfo.credit, ent->rateinfo.credit_cap, + ent->rateinfo.cost); + default: + BUG(); + return 0; + } +} + +static int dl_seq_show(struct seq_file *s, void *v) +{ + struct proc_dir_entry *pde = s->private; + struct xt_hashlimit_htable *htable = pde->data; + unsigned int *bucket = (unsigned int *)v; + struct dsthash_ent *ent; + struct hlist_node *pos; + + if (!hlist_empty(&htable->hash[*bucket])) { + hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node) + if (dl_seq_real_show(ent, htable->family, s)) + return 1; + } + return 0; +} + +static struct seq_operations dl_seq_ops = { + .start = dl_seq_start, + .next = dl_seq_next, + .stop = dl_seq_stop, + .show = dl_seq_show +}; + +static int dl_proc_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &dl_seq_ops); + + if (!ret) { + struct seq_file *sf = file->private_data; + sf->private = PDE(inode); + } + return ret; +} + +static struct file_operations dl_file_ops = { + .owner = THIS_MODULE, + .open = dl_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +static int __init xt_hashlimit_init(void) +{ + int err; + + err = xt_register_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit)); + if (err < 0) + goto err1; + + err = -ENOMEM; + hashlimit_cachep = kmem_cache_create("xt_hashlimit", + sizeof(struct dsthash_ent), 0, 0, + NULL, NULL); + if (!hashlimit_cachep) { + printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n"); + goto err2; + } + hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", proc_net); + if (!hashlimit_procdir4) { + printk(KERN_ERR "xt_hashlimit: unable to create proc dir " + "entry\n"); + goto err3; + } + hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", proc_net); + if (!hashlimit_procdir6) { + printk(KERN_ERR "xt_hashlimit: tnable to create proc dir " + "entry\n"); + goto err4; + } + return 0; +err4: + remove_proc_entry("ipt_hashlimit", proc_net); +err3: + kmem_cache_destroy(hashlimit_cachep); +err2: + xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit)); +err1: + return err; + +} + +static void __exit xt_hashlimit_fini(void) +{ + remove_proc_entry("ipt_hashlimit", proc_net); + remove_proc_entry("ip6t_hashlimit", proc_net); + kmem_cache_destroy(hashlimit_cachep); + xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit)); +} + +module_init(xt_hashlimit_init); +module_exit(xt_hashlimit_fini); -- cgit v1.2.3 From baf7b1e11282127e068d149825cccec002091d61 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:38 +0100 Subject: [NETFILTER]: x_tables: add NFLOG target Add new NFLOG target to allow use of nfnetlink_log for both IPv4 and IPv6. Currently we have two (unsupported by userspace) hacks in the LOG and ULOG targets to optionally call to the nflog API. They lack a few features, namely the IPv4 and IPv6 LOG targets can not specify a number of arguments related to nfnetlink_log, while the ULOG target is only available for IPv4. Remove those hacks and add a clean way to use nfnetlink_log. Signed-off-by: Patrick McHardy --- include/linux/netfilter/Kbuild | 1 + include/linux/netfilter/xt_NFLOG.h | 18 +++++++ include/linux/netfilter_ipv4/ipt_LOG.h | 2 +- include/linux/netfilter_ipv6/ip6t_LOG.h | 2 +- net/ipv4/netfilter/ipt_LOG.c | 9 +--- net/ipv6/netfilter/ip6t_LOG.c | 9 +--- net/netfilter/Kconfig | 11 +++++ net/netfilter/Makefile | 1 + net/netfilter/xt_NFLOG.c | 86 +++++++++++++++++++++++++++++++++ 9 files changed, 123 insertions(+), 16 deletions(-) create mode 100644 include/linux/netfilter/xt_NFLOG.h create mode 100644 net/netfilter/xt_NFLOG.c (limited to 'include/linux') diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index e379a2d89ea0..6328175a1c3a 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -22,6 +22,7 @@ header-y += xt_mark.h header-y += xt_MARK.h header-y += xt_multiport.h header-y += xt_NFQUEUE.h +header-y += xt_NFLOG.h header-y += xt_pkttype.h header-y += xt_policy.h header-y += xt_realm.h diff --git a/include/linux/netfilter/xt_NFLOG.h b/include/linux/netfilter/xt_NFLOG.h new file mode 100644 index 000000000000..cdcd0ed58f7a --- /dev/null +++ b/include/linux/netfilter/xt_NFLOG.h @@ -0,0 +1,18 @@ +#ifndef _XT_NFLOG_TARGET +#define _XT_NFLOG_TARGET + +#define XT_NFLOG_DEFAULT_GROUP 0x1 +#define XT_NFLOG_DEFAULT_THRESHOLD 1 + +#define XT_NFLOG_MASK 0x0 + +struct xt_nflog_info { + u_int32_t len; + u_int16_t group; + u_int16_t threshold; + u_int16_t flags; + u_int16_t pad; + char prefix[64]; +}; + +#endif /* _XT_NFLOG_TARGET */ diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h index 892f9a33fea8..90fa6525ef9c 100644 --- a/include/linux/netfilter_ipv4/ipt_LOG.h +++ b/include/linux/netfilter_ipv4/ipt_LOG.h @@ -6,7 +6,7 @@ #define IPT_LOG_TCPOPT 0x02 /* Log TCP options */ #define IPT_LOG_IPOPT 0x04 /* Log IP options */ #define IPT_LOG_UID 0x08 /* Log UID owning local socket */ -#define IPT_LOG_NFLOG 0x10 /* Log using nf_log backend */ +#define IPT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ #define IPT_LOG_MASK 0x1f struct ipt_log_info { diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/linux/netfilter_ipv6/ip6t_LOG.h index 060c1a1c6c60..0d0119b0458c 100644 --- a/include/linux/netfilter_ipv6/ip6t_LOG.h +++ b/include/linux/netfilter_ipv6/ip6t_LOG.h @@ -6,7 +6,7 @@ #define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */ #define IP6T_LOG_IPOPT 0x04 /* Log IP options */ #define IP6T_LOG_UID 0x08 /* Log UID owning local socket */ -#define IP6T_LOG_NFLOG 0x10 /* Log using nf_log backend */ +#define IP6T_LOG_NFLOG 0x10 /* Unsupported, don't use */ #define IP6T_LOG_MASK 0x1f struct ip6t_log_info { diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 46eee64a11f6..c96de16fefae 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -430,13 +430,8 @@ ipt_log_target(struct sk_buff **pskb, li.u.log.level = loginfo->level; li.u.log.logflags = loginfo->logflags; - if (loginfo->logflags & IPT_LOG_NFLOG) - nf_log_packet(PF_INET, hooknum, *pskb, in, out, &li, - "%s", loginfo->prefix); - else - ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, - loginfo->prefix); - + ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, + loginfo->prefix); return IPT_CONTINUE; } diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index f4857cf97f05..33b1faa90d74 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -440,13 +440,8 @@ ip6t_log_target(struct sk_buff **pskb, li.u.log.level = loginfo->level; li.u.log.logflags = loginfo->logflags; - if (loginfo->logflags & IP6T_LOG_NFLOG) - nf_log_packet(PF_INET6, hooknum, *pskb, in, out, &li, - "%s", loginfo->prefix); - else - ip6t_log_packet(PF_INET6, hooknum, *pskb, in, out, &li, - loginfo->prefix); - + ip6t_log_packet(PF_INET6, hooknum, *pskb, in, out, &li, + loginfo->prefix); return IP6T_CONTINUE; } diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 7e6125467c12..d191dacead5e 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -184,6 +184,17 @@ config NETFILTER_XT_TARGET_NFQUEUE To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_TARGET_NFLOG + tristate '"NFLOG" target support' + depends on NETFILTER_XTABLES + help + This option enables the NFLOG target, which allows to LOG + messages through the netfilter logging API, which can use + either the old LOG target, the old ULOG target or nfnetlink_log + as backend. + + To compile it as a module, choose M here. If unsure, say N. + config NETFILTER_XT_TARGET_NOTRACK tristate '"NOTRACK" target support' depends on NETFILTER_XTABLES diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index f85811bfcfe5..7f0089c584bf 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o +obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o diff --git a/net/netfilter/xt_NFLOG.c b/net/netfilter/xt_NFLOG.c new file mode 100644 index 000000000000..901ed7abaa1b --- /dev/null +++ b/net/netfilter/xt_NFLOG.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("x_tables NFLOG target"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_NFLOG"); +MODULE_ALIAS("ip6t_NFLOG"); + +static unsigned int +nflog_target(struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + unsigned int hooknum, const struct xt_target *target, + const void *targinfo) +{ + const struct xt_nflog_info *info = targinfo; + struct nf_loginfo li; + + li.type = NF_LOG_TYPE_ULOG; + li.u.ulog.copy_len = info->len; + li.u.ulog.group = info->group; + li.u.ulog.qthreshold = info->threshold; + + nf_log_packet(target->family, hooknum, *pskb, in, out, &li, + "%s", info->prefix); + return XT_CONTINUE; +} + +static int +nflog_checkentry(const char *tablename, const void *entry, + const struct xt_target *target, void *targetinfo, + unsigned int hookmask) +{ + struct xt_nflog_info *info = targetinfo; + + if (info->flags & ~XT_NFLOG_MASK) + return 0; + if (info->prefix[sizeof(info->prefix) - 1] != '\0') + return 0; + return 1; +} + +static struct xt_target xt_nflog_target[] = { + { + .name = "NFLOG", + .family = AF_INET, + .checkentry = nflog_checkentry, + .target = nflog_target, + .targetsize = sizeof(struct xt_nflog_info), + .me = THIS_MODULE, + }, + { + .name = "NFLOG", + .family = AF_INET6, + .checkentry = nflog_checkentry, + .target = nflog_target, + .targetsize = sizeof(struct xt_nflog_info), + .me = THIS_MODULE, + }, +}; + +static int __init xt_nflog_init(void) +{ + return xt_register_targets(xt_nflog_target, + ARRAY_SIZE(xt_nflog_target)); +} + +static void __exit xt_nflog_fini(void) +{ + xt_unregister_targets(xt_nflog_target, ARRAY_SIZE(xt_nflog_target)); +} + +module_init(xt_nflog_init); +module_exit(xt_nflog_fini); -- cgit v1.2.3 From d12cdc3ccf140bd2febef1c1be92284571da983f Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Wed, 29 Nov 2006 02:35:40 +0100 Subject: [NETFILTER]: ebtables: add --snap-arp option The attached patch adds --snat-arp support, which makes it possible to change the source mac address in both the mac header and the arp header with one rule. Signed-off-by: Bart De Schuymer Signed-off-by: Patrick McHardy --- include/linux/netfilter_bridge/ebt_nat.h | 1 + include/linux/netfilter_bridge/ebtables.h | 4 ++++ net/bridge/netfilter/ebt_mark.c | 6 +++--- net/bridge/netfilter/ebt_snat.c | 27 ++++++++++++++++++++++++--- 4 files changed, 32 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_bridge/ebt_nat.h b/include/linux/netfilter_bridge/ebt_nat.h index 26fd90da4cd6..435b886a51aa 100644 --- a/include/linux/netfilter_bridge/ebt_nat.h +++ b/include/linux/netfilter_bridge/ebt_nat.h @@ -1,6 +1,7 @@ #ifndef __LINUX_BRIDGE_EBT_NAT_H #define __LINUX_BRIDGE_EBT_NAT_H +#define NAT_ARP_BIT (0x00000010) struct ebt_nat_info { unsigned char mac[ETH_ALEN]; diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index e6ea70de24d5..87775264ff0b 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -26,6 +26,10 @@ #define EBT_CONTINUE -3 #define EBT_RETURN -4 #define NUM_STANDARD_TARGETS 4 +/* ebtables target modules store the verdict inside an int. We can + * reclaim a part of this int for backwards compatible extensions. + * The 4 lsb are more than enough to store the verdict. */ +#define EBT_VERDICT_BITS 0x0000000F struct ebt_counter { diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c index 2458638561cb..62d23c7b25e6 100644 --- a/net/bridge/netfilter/ebt_mark.c +++ b/net/bridge/netfilter/ebt_mark.c @@ -33,7 +33,7 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr, else (*pskb)->mark ^= info->mark; - return info->target | -16; + return info->target | ~EBT_VERDICT_BITS; } static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, @@ -44,13 +44,13 @@ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info))) return -EINVAL; - tmp = info->target | -16; + tmp = info->target | ~EBT_VERDICT_BITS; if (BASE_CHAIN && tmp == EBT_RETURN) return -EINVAL; CLEAR_BASE_CHAIN_BIT; if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) return -EINVAL; - tmp = info->target & -16; + tmp = info->target & ~EBT_VERDICT_BITS; if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE && tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE) return -EINVAL; diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c index cbb33e24ca8a..a50722182bfe 100644 --- a/net/bridge/netfilter/ebt_snat.c +++ b/net/bridge/netfilter/ebt_snat.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr, const struct net_device *in, const struct net_device *out, @@ -31,24 +33,43 @@ static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr, *pskb = nskb; } memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN); - return info->target; + if (!(info->target & NAT_ARP_BIT) && + eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) { + struct arphdr _ah, *ap; + + ap = skb_header_pointer(*pskb, 0, sizeof(_ah), &_ah); + if (ap == NULL) + return EBT_DROP; + if (ap->ar_hln != ETH_ALEN) + goto out; + if (skb_store_bits(*pskb, sizeof(_ah), info->mac,ETH_ALEN)) + return EBT_DROP; + } +out: + return info->target | ~EBT_VERDICT_BITS; } static int ebt_target_snat_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_nat_info *info = (struct ebt_nat_info *) data; + int tmp; if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info))) return -EINVAL; - if (BASE_CHAIN && info->target == EBT_RETURN) + tmp = info->target | ~EBT_VERDICT_BITS; + if (BASE_CHAIN && tmp == EBT_RETURN) return -EINVAL; CLEAR_BASE_CHAIN_BIT; if (strcmp(tablename, "nat")) return -EINVAL; if (hookmask & ~(1 << NF_BR_POST_ROUTING)) return -EINVAL; - if (INVALID_TARGET) + + if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) + return -EINVAL; + tmp = info->target | EBT_VERDICT_BITS; + if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT) return -EINVAL; return 0; } -- cgit v1.2.3 From 1e419cd9953f59d06d7b88d0e2911a68a0044f33 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 30 Nov 2006 19:28:48 -0800 Subject: [EBTABLES]: Split ebt_replace into user and kernel variants, annotate. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_bridge/ebtables.h | 19 ++++++++++++++++++- net/bridge/netfilter/ebtable_broute.c | 2 +- net/bridge/netfilter/ebtable_filter.c | 2 +- net/bridge/netfilter/ebtable_nat.c | 2 +- net/bridge/netfilter/ebtables.c | 19 ++++++++++--------- 5 files changed, 31 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index 87775264ff0b..94e0a7dc0cb2 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -38,6 +38,23 @@ struct ebt_counter }; struct ebt_replace +{ + char name[EBT_TABLE_MAXNAMELEN]; + unsigned int valid_hooks; + /* nr of rules in the table */ + unsigned int nentries; + /* total size of the entries */ + unsigned int entries_size; + /* start of the chains */ + struct ebt_entries __user *hook_entry[NF_BR_NUMHOOKS]; + /* nr of counters userspace expects back */ + unsigned int num_counters; + /* where the kernel will put the old counters */ + struct ebt_counter __user *counters; + char __user *entries; +}; + +struct ebt_replace_kernel { char name[EBT_TABLE_MAXNAMELEN]; unsigned int valid_hooks; @@ -255,7 +272,7 @@ struct ebt_table { struct list_head list; char name[EBT_TABLE_MAXNAMELEN]; - struct ebt_replace *table; + struct ebt_replace_kernel *table; unsigned int valid_hooks; rwlock_t lock; /* e.g. could be the table explicitly only allows certain diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index 9a6e548e148b..d37ce0478938 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c @@ -23,7 +23,7 @@ static struct ebt_entries initial_chain = { .policy = EBT_ACCEPT, }; -static struct ebt_replace initial_table = +static struct ebt_replace_kernel initial_table = { .name = "broute", .valid_hooks = 1 << NF_BR_BROUTING, diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index 3d5bd44f2395..127135ead2d5 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c @@ -30,7 +30,7 @@ static struct ebt_entries initial_chains[] = }, }; -static struct ebt_replace initial_table = +static struct ebt_replace_kernel initial_table = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index 04dd42efda1d..9c50488b62eb 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c @@ -30,7 +30,7 @@ static struct ebt_entries initial_chains[] = } }; -static struct ebt_replace initial_table = +static struct ebt_replace_kernel initial_table = { .name = "nat", .valid_hooks = NAT_VALID_HOOKS, diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 00a89705c1c4..bee558a41800 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -417,7 +417,8 @@ static int ebt_verify_pointers(struct ebt_replace *repl, for (i = 0; i < NF_BR_NUMHOOKS; i++) { if ((valid_hooks & (1 << i)) == 0) continue; - if ((char *)repl->hook_entry[i] == repl->entries + offset) + if ((char __user *)repl->hook_entry[i] == + repl->entries + offset) break; } @@ -1156,7 +1157,7 @@ int ebt_register_table(struct ebt_table *table) { struct ebt_table_info *newinfo; struct ebt_table *t; - struct ebt_replace *repl; + struct ebt_replace_kernel *repl; int ret, i, countersize; void *p; @@ -1320,33 +1321,33 @@ free_tmp: } static inline int ebt_make_matchname(struct ebt_entry_match *m, - char *base, char *ubase) + char *base, char __user *ubase) { - char *hlp = ubase - base + (char *)m; + char __user *hlp = ubase + ((char *)m - base); if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0; } static inline int ebt_make_watchername(struct ebt_entry_watcher *w, - char *base, char *ubase) + char *base, char __user *ubase) { - char *hlp = ubase - base + (char *)w; + char __user *hlp = ubase + ((char *)w - base); if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0; } -static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase) +static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase) { int ret; - char *hlp; + char __user *hlp; struct ebt_entry_target *t; if (e->bitmask == 0) return 0; - hlp = ubase - base + (char *)e + e->target_offset; + hlp = ubase + (((char *)e + e->target_offset) - base); t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase); -- cgit v1.2.3 From 9a7c9337a09b1ef07e55f95a4309957a2328a01f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:04:04 -0800 Subject: [NET]: Accept wildcard delimiters in in[46]_pton Accept -1 as delimiter to abort parsing without an error at the first unknown character. This is needed by the upcoming nf_conntrack SIP helper, where addresses are delimited by either '\r' or '\n' characters. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/inet.h | 4 ++-- net/core/utils.c | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/inet.h b/include/linux/inet.h index b7c6da7d6d32..675a7dbe86f8 100644 --- a/include/linux/inet.h +++ b/include/linux/inet.h @@ -46,7 +46,7 @@ #include extern __be32 in_aton(const char *str); -extern int in4_pton(const char *src, int srclen, u8 *dst, char delim, const char **end); -extern int in6_pton(const char *src, int srclen, u8 *dst, char delim, const char **end); +extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); +extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); #endif #endif /* _LINUX_INET_H */ diff --git a/net/core/utils.c b/net/core/utils.c index d93fe64f6693..61556065f07e 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -88,7 +88,7 @@ EXPORT_SYMBOL(in_aton); #define IN6PTON_NULL 0x20000000 /* first/tail */ #define IN6PTON_UNKNOWN 0x40000000 -static inline int digit2bin(char c, char delim) +static inline int digit2bin(char c, int delim) { if (c == delim || c == '\0') return IN6PTON_DELIM; @@ -99,7 +99,7 @@ static inline int digit2bin(char c, char delim) return IN6PTON_UNKNOWN; } -static inline int xdigit2bin(char c, char delim) +static inline int xdigit2bin(char c, int delim) { if (c == delim || c == '\0') return IN6PTON_DELIM; @@ -113,12 +113,14 @@ static inline int xdigit2bin(char c, char delim) return (IN6PTON_XDIGIT | (c - 'a' + 10)); if (c >= 'A' && c <= 'F') return (IN6PTON_XDIGIT | (c - 'A' + 10)); + if (delim == -1) + return IN6PTON_DELIM; return IN6PTON_UNKNOWN; } int in4_pton(const char *src, int srclen, u8 *dst, - char delim, const char **end) + int delim, const char **end) { const char *s; u8 *d; @@ -173,7 +175,7 @@ EXPORT_SYMBOL(in4_pton); int in6_pton(const char *src, int srclen, u8 *dst, - char delim, const char **end) + int delim, const char **end) { const char *s, *tok = NULL; u8 *d, *dc = NULL; -- cgit v1.2.3 From 5b1158e909ecbe1a052203e0d8df15633f829930 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Sat, 2 Dec 2006 22:07:13 -0800 Subject: [NETFILTER]: Add NAT support for nf_conntrack Add NAT support for nf_conntrack. Joint work of Jozsef Kadlecsik, Yasuyuki Kozakai, Martin Josefsson and myself. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter.h | 2 +- include/net/netfilter/ipv4/nf_conntrack_ipv4.h | 20 +- include/net/netfilter/nf_conntrack.h | 29 +- include/net/netfilter/nf_conntrack_expect.h | 2 +- include/net/netfilter/nf_nat.h | 77 +++ include/net/netfilter/nf_nat_core.h | 27 ++ include/net/netfilter/nf_nat_helper.h | 32 ++ include/net/netfilter/nf_nat_protocol.h | 70 +++ include/net/netfilter/nf_nat_rule.h | 35 ++ net/ipv4/netfilter/Kconfig | 30 +- net/ipv4/netfilter/Makefile | 7 + net/ipv4/netfilter/ip_nat_standalone.c | 6 - net/ipv4/netfilter/ipt_MASQUERADE.c | 29 +- net/ipv4/netfilter/ipt_NETMAP.c | 4 + net/ipv4/netfilter/ipt_REDIRECT.c | 6 +- net/ipv4/netfilter/ipt_SAME.c | 12 +- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 7 +- net/ipv4/netfilter/nf_nat_core.c | 647 +++++++++++++++++++++++++ net/ipv4/netfilter/nf_nat_helper.c | 433 +++++++++++++++++ net/ipv4/netfilter/nf_nat_proto_icmp.c | 86 ++++ net/ipv4/netfilter/nf_nat_proto_tcp.c | 148 ++++++ net/ipv4/netfilter/nf_nat_proto_udp.c | 138 ++++++ net/ipv4/netfilter/nf_nat_proto_unknown.c | 54 +++ net/ipv4/netfilter/nf_nat_rule.c | 343 +++++++++++++ net/ipv4/netfilter/nf_nat_standalone.c | 406 ++++++++++++++++ net/netfilter/nf_conntrack_core.c | 23 +- net/netfilter/nf_conntrack_netlink.c | 46 +- net/netfilter/nf_conntrack_proto_tcp.c | 2 +- net/netfilter/nf_conntrack_standalone.c | 5 +- 29 files changed, 2667 insertions(+), 59 deletions(-) create mode 100644 include/net/netfilter/nf_nat.h create mode 100644 include/net/netfilter/nf_nat_core.h create mode 100644 include/net/netfilter/nf_nat_helper.h create mode 100644 include/net/netfilter/nf_nat_protocol.h create mode 100644 include/net/netfilter/nf_nat_rule.h create mode 100644 net/ipv4/netfilter/nf_nat_core.c create mode 100644 net/ipv4/netfilter/nf_nat_helper.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_icmp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_tcp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_udp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_unknown.c create mode 100644 net/ipv4/netfilter/nf_nat_rule.c create mode 100644 net/ipv4/netfilter/nf_nat_standalone.c (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index f6f3fcbd70ed..d4c4c5120bc0 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -357,7 +357,7 @@ extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); static inline void nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) { -#ifdef CONFIG_IP_NF_NAT_NEEDED +#if defined(CONFIG_IP_NF_NAT_NEEDED) || defined(CONFIG_NF_NAT_NEEDED) void (*decodefn)(struct sk_buff *, struct flowi *); if (family == AF_INET && (decodefn = ip_nat_decode_session) != NULL) diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h index 34b453a81a63..a1c57ee0a4fa 100644 --- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h +++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h @@ -9,29 +9,23 @@ #ifndef _NF_CONNTRACK_IPV4_H #define _NF_CONNTRACK_IPV4_H -#ifdef CONFIG_IP_NF_NAT_NEEDED -#include +#ifdef CONFIG_NF_NAT_NEEDED +#include /* per conntrack: nat application helper private data */ -union ip_conntrack_nat_help { +union nf_conntrack_nat_help { /* insert nat helper private data here */ }; -struct nf_conntrack_ipv4_nat { - struct ip_nat_info info; - union ip_conntrack_nat_help help; +struct nf_conn_nat { + struct nf_nat_info info; + union nf_conntrack_nat_help help; #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) int masq_index; #endif }; -#endif /* CONFIG_IP_NF_NAT_NEEDED */ - -struct nf_conntrack_ipv4 { -#ifdef CONFIG_IP_NF_NAT_NEEDED - struct nf_conntrack_ipv4_nat *nat; -#endif -}; +#endif /* CONFIG_NF_NAT_NEEDED */ /* Returns new sk_buff, or NULL */ struct sk_buff * diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index b4beb8c799e5..9948af068688 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -264,18 +264,45 @@ nf_conntrack_unregister_cache(u_int32_t features); /* valid combinations: * basic: nf_conn, nf_conn .. nf_conn_help - * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat, nf_conn help + * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat .. nf_conn help */ +#ifdef CONFIG_NF_NAT_NEEDED +static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) +{ + unsigned int offset = sizeof(struct nf_conn); + + if (!(ct->features & NF_CT_F_NAT)) + return NULL; + + offset = ALIGN(offset, __alignof__(struct nf_conn_nat)); + return (struct nf_conn_nat *) ((void *)ct + offset); +} + static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) { unsigned int offset = sizeof(struct nf_conn); if (!(ct->features & NF_CT_F_HELP)) return NULL; + if (ct->features & NF_CT_F_NAT) { + offset = ALIGN(offset, __alignof__(struct nf_conn_nat)); + offset += sizeof(struct nf_conn_nat); + } offset = ALIGN(offset, __alignof__(struct nf_conn_help)); return (struct nf_conn_help *) ((void *)ct + offset); } +#else /* No NAT */ +static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) +{ + unsigned int offset = sizeof(struct nf_conn); + + if (!(ct->features & NF_CT_F_HELP)) + return NULL; + offset = ALIGN(offset, __alignof__(struct nf_conn_help)); + return (struct nf_conn_help *) ((void *)ct + offset); +} +#endif /* CONFIG_NF_NAT_NEEDED */ #endif /* __KERNEL__ */ #endif /* _NF_CONNTRACK_H */ diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 5d853e826d1d..b969c430b36a 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -43,7 +43,7 @@ struct nf_conntrack_expect #ifdef CONFIG_NF_NAT_NEEDED /* This is the original per-proto part, used to map the * expected connection the way the recipient expects. */ - union nf_conntrack_manip_proto saved_proto; + union nf_conntrack_man_proto saved_proto; /* Direction relative to the master connection. */ enum ip_conntrack_dir dir; #endif diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h new file mode 100644 index 000000000000..61c62068ca6b --- /dev/null +++ b/include/net/netfilter/nf_nat.h @@ -0,0 +1,77 @@ +#ifndef _NF_NAT_H +#define _NF_NAT_H +#include +#include + +#define NF_NAT_MAPPING_TYPE_MAX_NAMELEN 16 + +enum nf_nat_manip_type +{ + IP_NAT_MANIP_SRC, + IP_NAT_MANIP_DST +}; + +/* SRC manip occurs POST_ROUTING or LOCAL_IN */ +#define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN) + +#define IP_NAT_RANGE_MAP_IPS 1 +#define IP_NAT_RANGE_PROTO_SPECIFIED 2 + +/* NAT sequence number modifications */ +struct nf_nat_seq { + /* position of the last TCP sequence number modification (if any) */ + u_int32_t correction_pos; + + /* sequence number offset before and after last modification */ + int16_t offset_before, offset_after; +}; + +/* Single range specification. */ +struct nf_nat_range +{ + /* Set to OR of flags above. */ + unsigned int flags; + + /* Inclusive: network order. */ + __be32 min_ip, max_ip; + + /* Inclusive: network order */ + union nf_conntrack_man_proto min, max; +}; + +/* For backwards compat: don't use in modern code. */ +struct nf_nat_multi_range_compat +{ + unsigned int rangesize; /* Must be 1. */ + + /* hangs off end. */ + struct nf_nat_range range[1]; +}; + +#ifdef __KERNEL__ +#include + +/* The structure embedded in the conntrack structure. */ +struct nf_nat_info +{ + struct list_head bysource; + struct nf_nat_seq seq[IP_CT_DIR_MAX]; +}; + +struct nf_conn; + +/* Set up the info structure to map into this range. */ +extern unsigned int nf_nat_setup_info(struct nf_conn *ct, + const struct nf_nat_range *range, + unsigned int hooknum); + +/* Is this tuple already taken? (not by us)*/ +extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack); + +extern int nf_nat_module_is_loaded; + +#else /* !__KERNEL__: iptables wants this to compile. */ +#define nf_nat_multi_range nf_nat_multi_range_compat +#endif /*__KERNEL__*/ +#endif diff --git a/include/net/netfilter/nf_nat_core.h b/include/net/netfilter/nf_nat_core.h new file mode 100644 index 000000000000..9778ffa93440 --- /dev/null +++ b/include/net/netfilter/nf_nat_core.h @@ -0,0 +1,27 @@ +#ifndef _NF_NAT_CORE_H +#define _NF_NAT_CORE_H +#include +#include + +/* This header used to share core functionality between the standalone + NAT module, and the compatibility layer's use of NAT for masquerading. */ + +extern unsigned int nf_nat_packet(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb); + +extern int nf_nat_icmp_reply_translation(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb); + +static inline int nf_nat_initialized(struct nf_conn *ct, + enum nf_nat_manip_type manip) +{ + if (manip == IP_NAT_MANIP_SRC) + return test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); + else + return test_bit(IPS_DST_NAT_DONE_BIT, &ct->status); +} +#endif /* _NF_NAT_CORE_H */ diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h new file mode 100644 index 000000000000..ec98ecf95fc8 --- /dev/null +++ b/include/net/netfilter/nf_nat_helper.h @@ -0,0 +1,32 @@ +#ifndef _NF_NAT_HELPER_H +#define _NF_NAT_HELPER_H +/* NAT protocol helper routines. */ + +#include + +struct sk_buff; + +/* These return true or false. */ +extern int nf_nat_mangle_tcp_packet(struct sk_buff **skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len); +extern int nf_nat_mangle_udp_packet(struct sk_buff **skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len); +extern int nf_nat_seq_adjust(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo); + +/* Setup NAT on this expected conntrack so it follows master, but goes + * to port ct->master->saved_proto. */ +extern void nf_nat_follow_master(struct nf_conn *ct, + struct nf_conntrack_expect *this); +#endif diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h new file mode 100644 index 000000000000..a9ec5ef61468 --- /dev/null +++ b/include/net/netfilter/nf_nat_protocol.h @@ -0,0 +1,70 @@ +/* Header for use in defining a given protocol. */ +#ifndef _NF_NAT_PROTOCOL_H +#define _NF_NAT_PROTOCOL_H +#include +#include + +struct nf_nat_range; + +struct nf_nat_protocol +{ + /* Protocol name */ + const char *name; + + /* Protocol number. */ + unsigned int protonum; + + struct module *me; + + /* Translate a packet to the target according to manip type. + Return true if succeeded. */ + int (*manip_pkt)(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype); + + /* Is the manipable part of the tuple between min and max incl? */ + int (*in_range)(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max); + + /* Alter the per-proto part of the tuple (depending on + maniptype), to give a unique tuple in the given range if + possible; return false if not. Per-protocol part of tuple + is initialized to the incoming packet. */ + int (*unique_tuple)(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct); + + int (*range_to_nfattr)(struct sk_buff *skb, + const struct nf_nat_range *range); + + int (*nfattr_to_range)(struct nfattr *tb[], + struct nf_nat_range *range); +}; + +/* Protocol registration. */ +extern int nf_nat_protocol_register(struct nf_nat_protocol *proto); +extern void nf_nat_protocol_unregister(struct nf_nat_protocol *proto); + +extern struct nf_nat_protocol *nf_nat_proto_find_get(u_int8_t protocol); +extern void nf_nat_proto_put(struct nf_nat_protocol *proto); + +/* Built-in protocols. */ +extern struct nf_nat_protocol nf_nat_protocol_tcp; +extern struct nf_nat_protocol nf_nat_protocol_udp; +extern struct nf_nat_protocol nf_nat_protocol_icmp; +extern struct nf_nat_protocol nf_nat_unknown_protocol; + +extern int init_protocols(void) __init; +extern void cleanup_protocols(void); +extern struct nf_nat_protocol *find_nat_proto(u_int16_t protonum); + +extern int nf_nat_port_range_to_nfattr(struct sk_buff *skb, + const struct nf_nat_range *range); +extern int nf_nat_port_nfattr_to_range(struct nfattr *tb[], + struct nf_nat_range *range); + +#endif /*_NF_NAT_PROTO_H*/ diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h new file mode 100644 index 000000000000..f191c672bcc6 --- /dev/null +++ b/include/net/netfilter/nf_nat_rule.h @@ -0,0 +1,35 @@ +#ifndef _NF_NAT_RULE_H +#define _NF_NAT_RULE_H +#include +#include +#include + +/* Compatibility definitions for ipt_FOO modules */ +#define ip_nat_range nf_nat_range +#define ip_conntrack_tuple nf_conntrack_tuple +#define ip_conntrack_get nf_ct_get +#define ip_conntrack nf_conn +#define ip_nat_setup_info nf_nat_setup_info +#define ip_nat_multi_range_compat nf_nat_multi_range_compat +#define ip_ct_iterate_cleanup nf_ct_iterate_cleanup +#define IP_NF_ASSERT NF_CT_ASSERT + +extern int nf_nat_rule_init(void) __init; +extern void nf_nat_rule_cleanup(void); +extern int nf_nat_rule_find(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + struct nf_conn *ct, + struct nf_nat_info *info); + +extern unsigned int +alloc_null_binding(struct nf_conn *ct, + struct nf_nat_info *info, + unsigned int hooknum); + +extern unsigned int +alloc_null_binding_confirmed(struct nf_conn *ct, + struct nf_nat_info *info, + unsigned int hooknum); +#endif /* _NF_NAT_RULE_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 71485276b819..01789aeaeb5f 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -6,7 +6,7 @@ menu "IP: Netfilter Configuration" depends on INET && NETFILTER config NF_CONNTRACK_IPV4 - tristate "IPv4 support for new connection tracking (EXPERIMENTAL)" + tristate "IPv4 support for new connection tracking (required for NAT) (EXPERIMENTAL)" depends on EXPERIMENTAL && NF_CONNTRACK ---help--- Connection tracking keeps a record of what packets have passed @@ -387,7 +387,7 @@ config IP_NF_TARGET_TCPMSS To compile it as a module, choose M here. If unsure, say N. -# NAT + specific targets +# NAT + specific targets: ip_conntrack config IP_NF_NAT tristate "Full NAT" depends on IP_NF_IPTABLES && IP_NF_CONNTRACK @@ -398,14 +398,30 @@ config IP_NF_NAT To compile it as a module, choose M here. If unsure, say N. +# NAT + specific targets: nf_conntrack +config NF_NAT + tristate "Full NAT" + depends on IP_NF_IPTABLES && NF_CONNTRACK + help + The Full NAT option allows masquerading, port forwarding and other + forms of full Network Address Port Translation. It is controlled by + the `nat' table in iptables: see the man page for iptables(8). + + To compile it as a module, choose M here. If unsure, say N. + config IP_NF_NAT_NEEDED bool - depends on IP_NF_NAT != n + depends on IP_NF_NAT + default y + +config NF_NAT_NEEDED + bool + depends on NF_NAT default y config IP_NF_TARGET_MASQUERADE tristate "MASQUERADE target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help Masquerading is a special case of NAT: all outgoing connections are changed to seem to come from a particular interface's address, and @@ -417,7 +433,7 @@ config IP_NF_TARGET_MASQUERADE config IP_NF_TARGET_REDIRECT tristate "REDIRECT target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help REDIRECT is a special case of NAT: all incoming connections are mapped onto the incoming interface's address, causing the packets to @@ -428,7 +444,7 @@ config IP_NF_TARGET_REDIRECT config IP_NF_TARGET_NETMAP tristate "NETMAP target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help NETMAP is an implementation of static 1:1 NAT mapping of network addresses. It maps the network address part, while keeping the host @@ -439,7 +455,7 @@ config IP_NF_TARGET_NETMAP config IP_NF_TARGET_SAME tristate "SAME target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help This option adds a `SAME' target, which works like the standard SNAT target, but attempts to give clients the same IP for all connections. diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 21359d83f0c7..ec31690764ac 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -5,7 +5,12 @@ # objects for the standalone - connection tracking / NAT ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o ip_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o +nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o +ifneq ($(CONFIG_NF_NAT),) +iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o +else iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o +endif ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o @@ -16,6 +21,7 @@ ip_nat_h323-objs := ip_nat_helper_h323.o # connection tracking obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o obj-$(CONFIG_IP_NF_NAT) += ip_nat.o +obj-$(CONFIG_NF_NAT) += nf_nat.o # conntrack netlink interface obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o @@ -50,6 +56,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o +obj-$(CONFIG_NF_NAT) += iptable_nat.o obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o # matches diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index d85d2de50449..ad66328baa5d 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -44,12 +44,6 @@ #define DEBUGP(format, args...) #endif -#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ - : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ - : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ - : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ - : "*ERROR*"))) - #ifdef CONFIG_XFRM static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) { diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 3dbfcfac8a84..28b9233956b5 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -2,7 +2,7 @@ (depending on route). */ /* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team + * (C) 2002-2006 Netfilter Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,7 +20,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif #include MODULE_LICENSE("GPL"); @@ -65,23 +69,33 @@ masquerade_target(struct sk_buff **pskb, const struct xt_target *target, const void *targinfo) { +#ifdef CONFIG_NF_NAT_NEEDED + struct nf_conn_nat *nat; +#endif struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; - const struct ip_nat_multi_range_compat *mr; struct ip_nat_range newrange; + const struct ip_nat_multi_range_compat *mr; struct rtable *rt; __be32 newsrc; IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); ct = ip_conntrack_get(*pskb, &ctinfo); +#ifdef CONFIG_NF_NAT_NEEDED + nat = nfct_nat(ct); +#endif IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); /* Source address is 0.0.0.0 - locally generated packet that is * probably not supposed to be masqueraded. */ +#ifdef CONFIG_NF_NAT_NEEDED + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0) +#else if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0) +#endif return NF_ACCEPT; mr = targinfo; @@ -93,7 +107,11 @@ masquerade_target(struct sk_buff **pskb, } write_lock_bh(&masq_lock); +#ifdef CONFIG_NF_NAT_NEEDED + nat->masq_index = out->ifindex; +#else ct->nat.masq_index = out->ifindex; +#endif write_unlock_bh(&masq_lock); /* Transfer from original range. */ @@ -109,10 +127,17 @@ masquerade_target(struct sk_buff **pskb, static inline int device_cmp(struct ip_conntrack *i, void *ifindex) { +#ifdef CONFIG_NF_NAT_NEEDED + struct nf_conn_nat *nat = nfct_nat(i); +#endif int ret; read_lock_bh(&masq_lock); +#ifdef CONFIG_NF_NAT_NEEDED + ret = (nat->masq_index == (int)(long)ifindex); +#else ret = (i->nat.masq_index == (int)(long)ifindex); +#endif read_unlock_bh(&masq_lock); return ret; diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c index 58a88f227108..9390e90f2b25 100644 --- a/net/ipv4/netfilter/ipt_NETMAP.c +++ b/net/ipv4/netfilter/ipt_NETMAP.c @@ -15,7 +15,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif #define MODULENAME "NETMAP" MODULE_LICENSE("GPL"); diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c index c0dcfe9d610c..462eceb3a1b1 100644 --- a/net/ipv4/netfilter/ipt_REDIRECT.c +++ b/net/ipv4/netfilter/ipt_REDIRECT.c @@ -1,6 +1,6 @@ /* Redirect. Simple mapping which alters dst to a local IP address. */ /* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team + * (C) 2002-2006 Netfilter Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,7 +18,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c index b38b13328d73..3dcf29411337 100644 --- a/net/ipv4/netfilter/ipt_SAME.c +++ b/net/ipv4/netfilter/ipt_SAME.c @@ -34,7 +34,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif #include MODULE_LICENSE("GPL"); @@ -152,11 +156,17 @@ same_target(struct sk_buff **pskb, Here we calculate the index in same->iparray which holds the ipaddress we should use */ +#ifdef CONFIG_NF_NAT_NEEDED + tmpip = ntohl(t->src.u3.ip); + + if (!(same->info & IPT_SAME_NODST)) + tmpip += ntohl(t->dst.u3.ip); +#else tmpip = ntohl(t->src.ip); if (!(same->info & IPT_SAME_NODST)) tmpip += ntohl(t->dst.ip); - +#endif aindex = tmpip % same->ipnum; new_ip = htonl(same->iparray[aindex]); diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 653f57b8a107..5655109dcaff 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -111,10 +111,10 @@ ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff, return NF_ACCEPT; } -int nat_module_is_loaded = 0; +int nf_nat_module_is_loaded = 0; static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) { - if (nat_module_is_loaded) + if (nf_nat_module_is_loaded) return NF_CT_F_NAT; return NF_CT_F_BASIC; @@ -532,3 +532,6 @@ module_init(nf_conntrack_l3proto_ipv4_init); module_exit(nf_conntrack_l3proto_ipv4_fini); EXPORT_SYMBOL(nf_ct_ipv4_gather_frags); +#ifdef CONFIG_NF_NAT_NEEDED +EXPORT_SYMBOL(nf_nat_module_is_loaded); +#endif diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c new file mode 100644 index 000000000000..86a92272b053 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -0,0 +1,647 @@ +/* NAT for netfilter; shared with compatibility layer. */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For tcp_prot in getorigdst */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static DEFINE_RWLOCK(nf_nat_lock); + +static struct nf_conntrack_l3proto *l3proto = NULL; + +/* Calculated at init based on memory size */ +static unsigned int nf_nat_htable_size; + +static struct list_head *bysource; + +#define MAX_IP_NAT_PROTO 256 +static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]; + +static inline struct nf_nat_protocol * +__nf_nat_proto_find(u_int8_t protonum) +{ + return nf_nat_protos[protonum]; +} + +struct nf_nat_protocol * +nf_nat_proto_find_get(u_int8_t protonum) +{ + struct nf_nat_protocol *p; + + /* we need to disable preemption to make sure 'p' doesn't get + * removed until we've grabbed the reference */ + preempt_disable(); + p = __nf_nat_proto_find(protonum); + if (!try_module_get(p->me)) + p = &nf_nat_unknown_protocol; + preempt_enable(); + + return p; +} +EXPORT_SYMBOL_GPL(nf_nat_proto_find_get); + +void +nf_nat_proto_put(struct nf_nat_protocol *p) +{ + module_put(p->me); +} +EXPORT_SYMBOL_GPL(nf_nat_proto_put); + +/* We keep an extra hash for each conntrack, for fast searching. */ +static inline unsigned int +hash_by_src(const struct nf_conntrack_tuple *tuple) +{ + /* Original src, to ensure we map it consistently if poss. */ + return jhash_3words((__force u32)tuple->src.u3.ip, tuple->src.u.all, + tuple->dst.protonum, 0) % nf_nat_htable_size; +} + +/* Noone using conntrack by the time this called. */ +static void nf_nat_cleanup_conntrack(struct nf_conn *conn) +{ + struct nf_conn_nat *nat; + if (!(conn->status & IPS_NAT_DONE_MASK)) + return; + + nat = nfct_nat(conn); + write_lock_bh(&nf_nat_lock); + list_del(&nat->info.bysource); + write_unlock_bh(&nf_nat_lock); +} + +/* Is this tuple already taken? (not by us) */ +int +nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack) +{ + /* Conntrack tracking doesn't keep track of outgoing tuples; only + incoming ones. NAT means they don't have a fixed mapping, + so we invert the tuple and look for the incoming reply. + + We could keep a separate hash if this proves too slow. */ + struct nf_conntrack_tuple reply; + + nf_ct_invert_tuplepr(&reply, tuple); + return nf_conntrack_tuple_taken(&reply, ignored_conntrack); +} +EXPORT_SYMBOL(nf_nat_used_tuple); + +/* If we source map this tuple so reply looks like reply_tuple, will + * that meet the constraints of range. */ +static int +in_range(const struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range) +{ + struct nf_nat_protocol *proto; + + proto = __nf_nat_proto_find(tuple->dst.protonum); + /* If we are supposed to map IPs, then we must be in the + range specified, otherwise let this drag us onto a new src IP. */ + if (range->flags & IP_NAT_RANGE_MAP_IPS) { + if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) || + ntohl(tuple->src.u3.ip) > ntohl(range->max_ip)) + return 0; + } + + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || + proto->in_range(tuple, IP_NAT_MANIP_SRC, + &range->min, &range->max)) + return 1; + + return 0; +} + +static inline int +same_src(const struct nf_conn *ct, + const struct nf_conntrack_tuple *tuple) +{ + const struct nf_conntrack_tuple *t; + + t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + return (t->dst.protonum == tuple->dst.protonum && + t->src.u3.ip == tuple->src.u3.ip && + t->src.u.all == tuple->src.u.all); +} + +/* Only called for SRC manip */ +static int +find_appropriate_src(const struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *result, + const struct nf_nat_range *range) +{ + unsigned int h = hash_by_src(tuple); + struct nf_conn_nat *nat; + struct nf_conn *ct; + + read_lock_bh(&nf_nat_lock); + list_for_each_entry(nat, &bysource[h], info.bysource) { + ct = (struct nf_conn *)((char *)nat - offsetof(struct nf_conn, data)); + if (same_src(ct, tuple)) { + /* Copy source part from reply tuple. */ + nf_ct_invert_tuplepr(result, + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + result->dst = tuple->dst; + + if (in_range(result, range)) { + read_unlock_bh(&nf_nat_lock); + return 1; + } + } + } + read_unlock_bh(&nf_nat_lock); + return 0; +} + +/* For [FUTURE] fragmentation handling, we want the least-used + src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus + if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports + 1-65535, we don't do pro-rata allocation based on ports; we choose + the ip with the lowest src-ip/dst-ip/proto usage. +*/ +static void +find_best_ips_proto(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + const struct nf_conn *ct, + enum nf_nat_manip_type maniptype) +{ + __be32 *var_ipp; + /* Host order */ + u_int32_t minip, maxip, j; + + /* No IP mapping? Do nothing. */ + if (!(range->flags & IP_NAT_RANGE_MAP_IPS)) + return; + + if (maniptype == IP_NAT_MANIP_SRC) + var_ipp = &tuple->src.u3.ip; + else + var_ipp = &tuple->dst.u3.ip; + + /* Fast path: only one choice. */ + if (range->min_ip == range->max_ip) { + *var_ipp = range->min_ip; + return; + } + + /* Hashing source and destination IPs gives a fairly even + * spread in practice (if there are a small number of IPs + * involved, there usually aren't that many connections + * anyway). The consistency means that servers see the same + * client coming from the same IP (some Internet Banking sites + * like this), even across reboots. */ + minip = ntohl(range->min_ip); + maxip = ntohl(range->max_ip); + j = jhash_2words((__force u32)tuple->src.u3.ip, + (__force u32)tuple->dst.u3.ip, 0); + *var_ipp = htonl(minip + j % (maxip - minip + 1)); +} + +/* Manipulate the tuple into the range given. For NF_IP_POST_ROUTING, + * we change the source to map into the range. For NF_IP_PRE_ROUTING + * and NF_IP_LOCAL_OUT, we change the destination to map into the + * range. It might not be possible to get a unique tuple, but we try. + * At worst (or if we race), we will end up with a final duplicate in + * __ip_conntrack_confirm and drop the packet. */ +static void +get_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig_tuple, + const struct nf_nat_range *range, + struct nf_conn *ct, + enum nf_nat_manip_type maniptype) +{ + struct nf_nat_protocol *proto; + + /* 1) If this srcip/proto/src-proto-part is currently mapped, + and that same mapping gives a unique tuple within the given + range, use that. + + This is only required for source (ie. NAT/masq) mappings. + So far, we don't do local source mappings, so multiple + manips not an issue. */ + if (maniptype == IP_NAT_MANIP_SRC) { + if (find_appropriate_src(orig_tuple, tuple, range)) { + DEBUGP("get_unique_tuple: Found current src map\n"); + if (!nf_nat_used_tuple(tuple, ct)) + return; + } + } + + /* 2) Select the least-used IP/proto combination in the given + range. */ + *tuple = *orig_tuple; + find_best_ips_proto(tuple, range, ct, maniptype); + + /* 3) The per-protocol part of the manip is made to map into + the range to make a unique tuple. */ + + proto = nf_nat_proto_find_get(orig_tuple->dst.protonum); + + /* Only bother mapping if it's not already in range and unique */ + if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || + proto->in_range(tuple, maniptype, &range->min, &range->max)) && + !nf_nat_used_tuple(tuple, ct)) { + nf_nat_proto_put(proto); + return; + } + + /* Last change: get protocol to try to obtain unique tuple. */ + proto->unique_tuple(tuple, range, maniptype, ct); + + nf_nat_proto_put(proto); +} + +unsigned int +nf_nat_setup_info(struct nf_conn *ct, + const struct nf_nat_range *range, + unsigned int hooknum) +{ + struct nf_conntrack_tuple curr_tuple, new_tuple; + struct nf_conn_nat *nat = nfct_nat(ct); + struct nf_nat_info *info = &nat->info; + int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); + enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); + + NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || + hooknum == NF_IP_POST_ROUTING || + hooknum == NF_IP_LOCAL_IN || + hooknum == NF_IP_LOCAL_OUT); + BUG_ON(nf_nat_initialized(ct, maniptype)); + + /* What we've got will look like inverse of reply. Normally + this is what is in the conntrack, except for prior + manipulations (future optimization: if num_manips == 0, + orig_tp = + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */ + nf_ct_invert_tuplepr(&curr_tuple, + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + + get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype); + + if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) { + struct nf_conntrack_tuple reply; + + /* Alter conntrack table so will recognize replies. */ + nf_ct_invert_tuplepr(&reply, &new_tuple); + nf_conntrack_alter_reply(ct, &reply); + + /* Non-atomic: we own this at the moment. */ + if (maniptype == IP_NAT_MANIP_SRC) + ct->status |= IPS_SRC_NAT; + else + ct->status |= IPS_DST_NAT; + } + + /* Place in source hash if this is the first time. */ + if (have_to_hash) { + unsigned int srchash; + + srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + write_lock_bh(&nf_nat_lock); + list_add(&info->bysource, &bysource[srchash]); + write_unlock_bh(&nf_nat_lock); + } + + /* It's done. */ + if (maniptype == IP_NAT_MANIP_DST) + set_bit(IPS_DST_NAT_DONE_BIT, &ct->status); + else + set_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); + + return NF_ACCEPT; +} +EXPORT_SYMBOL(nf_nat_setup_info); + +/* Returns true if succeeded. */ +static int +manip_pkt(u_int16_t proto, + struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *target, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph; + struct nf_nat_protocol *p; + + if (!skb_make_writable(pskb, iphdroff + sizeof(*iph))) + return 0; + + iph = (void *)(*pskb)->data + iphdroff; + + /* Manipulate protcol part. */ + p = nf_nat_proto_find_get(proto); + if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) { + nf_nat_proto_put(p); + return 0; + } + nf_nat_proto_put(p); + + iph = (void *)(*pskb)->data + iphdroff; + + if (maniptype == IP_NAT_MANIP_SRC) { + nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip); + iph->saddr = target->src.u3.ip; + } else { + nf_csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip); + iph->daddr = target->dst.u3.ip; + } + return 1; +} + +/* Do packet manipulations according to nf_nat_setup_info. */ +unsigned int nf_nat_packet(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned long statusbit; + enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum); + + if (mtype == IP_NAT_MANIP_SRC) + statusbit = IPS_SRC_NAT; + else + statusbit = IPS_DST_NAT; + + /* Invert if this is reply dir. */ + if (dir == IP_CT_DIR_REPLY) + statusbit ^= IPS_NAT_MASK; + + /* Non-atomic: these bits don't change. */ + if (ct->status & statusbit) { + struct nf_conntrack_tuple target; + + /* We are aiming to look like inverse of other direction. */ + nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); + + if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype)) + return NF_DROP; + } + return NF_ACCEPT; +} +EXPORT_SYMBOL_GPL(nf_nat_packet); + +/* Dir is direction ICMP is coming from (opposite to packet it contains) */ +int nf_nat_icmp_reply_translation(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + struct { + struct icmphdr icmp; + struct iphdr ip; + } *inside; + struct nf_conntrack_tuple inner, target; + int hdrlen = (*pskb)->nh.iph->ihl * 4; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned long statusbit; + enum nf_nat_manip_type manip = HOOK2MANIP(hooknum); + + if (!skb_make_writable(pskb, hdrlen + sizeof(*inside))) + return 0; + + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + + /* We're actually going to mangle it beyond trivial checksum + adjustment, so make sure the current checksum is correct. */ + if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0)) + return 0; + + /* Must be RELATED */ + NF_CT_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED || + (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY); + + /* Redirects on non-null nats must be dropped, else they'll + start talking to each other without our translation, and be + confused... --RR */ + if (inside->icmp.type == ICMP_REDIRECT) { + /* If NAT isn't finished, assume it and drop. */ + if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK) + return 0; + + if (ct->status & IPS_NAT_MASK) + return 0; + } + + DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", + *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); + + if (!nf_ct_get_tuple(*pskb, + (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr), + (*pskb)->nh.iph->ihl*4 + + sizeof(struct icmphdr) + inside->ip.ihl*4, + (u_int16_t)AF_INET, + inside->ip.protocol, + &inner, + l3proto, + __nf_ct_l4proto_find((u_int16_t)PF_INET, + inside->ip.protocol))) + return 0; + + /* Change inner back to look like incoming packet. We do the + opposite manip on this hook to normal, because it might not + pass all hooks (locally-generated ICMP). Consider incoming + packet: PREROUTING (DST manip), routing produces ICMP, goes + through POSTROUTING (which must correct the DST manip). */ + if (!manip_pkt(inside->ip.protocol, pskb, + (*pskb)->nh.iph->ihl*4 + sizeof(inside->icmp), + &ct->tuplehash[!dir].tuple, + !manip)) + return 0; + + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { + /* Reloading "inside" here since manip_pkt inner. */ + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + inside->icmp.checksum = 0; + inside->icmp.checksum = + csum_fold(skb_checksum(*pskb, hdrlen, + (*pskb)->len - hdrlen, 0)); + } + + /* Change outer to look the reply to an incoming packet + * (proto 0 means don't invert per-proto part). */ + if (manip == IP_NAT_MANIP_SRC) + statusbit = IPS_SRC_NAT; + else + statusbit = IPS_DST_NAT; + + /* Invert if this is reply dir. */ + if (dir == IP_CT_DIR_REPLY) + statusbit ^= IPS_NAT_MASK; + + if (ct->status & statusbit) { + nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); + if (!manip_pkt(0, pskb, 0, &target, manip)) + return 0; + } + + return 1; +} +EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); + +/* Protocol registration. */ +int nf_nat_protocol_register(struct nf_nat_protocol *proto) +{ + int ret = 0; + + write_lock_bh(&nf_nat_lock); + if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) { + ret = -EBUSY; + goto out; + } + nf_nat_protos[proto->protonum] = proto; + out: + write_unlock_bh(&nf_nat_lock); + return ret; +} +EXPORT_SYMBOL(nf_nat_protocol_register); + +/* Noone stores the protocol anywhere; simply delete it. */ +void nf_nat_protocol_unregister(struct nf_nat_protocol *proto) +{ + write_lock_bh(&nf_nat_lock); + nf_nat_protos[proto->protonum] = &nf_nat_unknown_protocol; + write_unlock_bh(&nf_nat_lock); + + /* Someone could be still looking at the proto in a bh. */ + synchronize_net(); +} +EXPORT_SYMBOL(nf_nat_protocol_unregister); + +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) +int +nf_nat_port_range_to_nfattr(struct sk_buff *skb, + const struct nf_nat_range *range) +{ + NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), + &range->min.tcp.port); + NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), + &range->max.tcp.port); + + return 0; + +nfattr_failure: + return -1; +} +EXPORT_SYMBOL_GPL(nf_nat_port_nfattr_to_range); + +int +nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range) +{ + int ret = 0; + + /* we have to return whether we actually parsed something or not */ + + if (tb[CTA_PROTONAT_PORT_MIN-1]) { + ret = 1; + range->min.tcp.port = + *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); + } + + if (!tb[CTA_PROTONAT_PORT_MAX-1]) { + if (ret) + range->max.tcp.port = range->min.tcp.port; + } else { + ret = 1; + range->max.tcp.port = + *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); + } + + return ret; +} +EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); +#endif + +static int __init nf_nat_init(void) +{ + size_t i; + + /* Leave them the same for the moment. */ + nf_nat_htable_size = nf_conntrack_htable_size; + + /* One vmalloc for both hash tables */ + bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size); + if (!bysource) + return -ENOMEM; + + /* Sew in builtin protocols. */ + write_lock_bh(&nf_nat_lock); + for (i = 0; i < MAX_IP_NAT_PROTO; i++) + nf_nat_protos[i] = &nf_nat_unknown_protocol; + nf_nat_protos[IPPROTO_TCP] = &nf_nat_protocol_tcp; + nf_nat_protos[IPPROTO_UDP] = &nf_nat_protocol_udp; + nf_nat_protos[IPPROTO_ICMP] = &nf_nat_protocol_icmp; + write_unlock_bh(&nf_nat_lock); + + for (i = 0; i < nf_nat_htable_size; i++) { + INIT_LIST_HEAD(&bysource[i]); + } + + /* FIXME: Man, this is a hack. */ + NF_CT_ASSERT(nf_conntrack_destroyed == NULL); + nf_conntrack_destroyed = &nf_nat_cleanup_conntrack; + + /* Initialize fake conntrack so that NAT will skip it */ + nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; + + l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); + return 0; +} + +/* Clear NAT section of all conntracks, in case we're loaded again. */ +static int clean_nat(struct nf_conn *i, void *data) +{ + struct nf_conn_nat *nat = nfct_nat(i); + + if (!nat) + return 0; + memset(nat, 0, sizeof(nat)); + i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST); + return 0; +} + +static void __exit nf_nat_cleanup(void) +{ + nf_ct_iterate_cleanup(&clean_nat, NULL); + nf_conntrack_destroyed = NULL; + vfree(bysource); + nf_ct_l3proto_put(l3proto); +} + +MODULE_LICENSE("GPL"); + +module_init(nf_nat_init); +module_exit(nf_nat_cleanup); diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c new file mode 100644 index 000000000000..98fbfc84d183 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -0,0 +1,433 @@ +/* ip_nat_helper.c - generic support functions for NAT helpers + * + * (C) 2000-2002 Harald Welte + * (C) 2003-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos); +#else +#define DEBUGP(format, args...) +#define DUMP_OFFSET(x) +#endif + +static DEFINE_SPINLOCK(nf_nat_seqofs_lock); + +/* Setup TCP sequence correction given this change at this sequence */ +static inline void +adjust_tcp_sequence(u32 seq, + int sizediff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + int dir; + struct nf_nat_seq *this_way, *other_way; + struct nf_conn_nat *nat = nfct_nat(ct); + + DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n", + (*skb)->len, new_size); + + dir = CTINFO2DIR(ctinfo); + + this_way = &nat->info.seq[dir]; + other_way = &nat->info.seq[!dir]; + + DEBUGP("nf_nat_resize_packet: Seq_offset before: "); + DUMP_OFFSET(this_way); + + spin_lock_bh(&nf_nat_seqofs_lock); + + /* SYN adjust. If it's uninitialized, or this is after last + * correction, record it: we don't handle more than one + * adjustment in the window, but do deal with common case of a + * retransmit */ + if (this_way->offset_before == this_way->offset_after || + before(this_way->correction_pos, seq)) { + this_way->correction_pos = seq; + this_way->offset_before = this_way->offset_after; + this_way->offset_after += sizediff; + } + spin_unlock_bh(&nf_nat_seqofs_lock); + + DEBUGP("nf_nat_resize_packet: Seq_offset after: "); + DUMP_OFFSET(this_way); +} + +/* Frobs data inside this packet, which is linear. */ +static void mangle_contents(struct sk_buff *skb, + unsigned int dataoff, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + unsigned char *data; + + BUG_ON(skb_is_nonlinear(skb)); + data = (unsigned char *)skb->nh.iph + dataoff; + + /* move post-replacement */ + memmove(data + match_offset + rep_len, + data + match_offset + match_len, + skb->tail - (data + match_offset + match_len)); + + /* insert data from buffer */ + memcpy(data + match_offset, rep_buffer, rep_len); + + /* update skb info */ + if (rep_len > match_len) { + DEBUGP("nf_nat_mangle_packet: Extending packet by " + "%u from %u bytes\n", rep_len - match_len, + skb->len); + skb_put(skb, rep_len - match_len); + } else { + DEBUGP("nf_nat_mangle_packet: Shrinking packet from " + "%u from %u bytes\n", match_len - rep_len, + skb->len); + __skb_trim(skb, skb->len + rep_len - match_len); + } + + /* fix IP hdr checksum information */ + skb->nh.iph->tot_len = htons(skb->len); + ip_send_check(skb->nh.iph); +} + +/* Unusual, but possible case. */ +static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) +{ + struct sk_buff *nskb; + + if ((*pskb)->len + extra > 65535) + return 0; + + nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); + if (!nskb) + return 0; + + /* Transfer socket to new skb. */ + if ((*pskb)->sk) + skb_set_owner_w(nskb, (*pskb)->sk); + kfree_skb(*pskb); + *pskb = nskb; + return 1; +} + +/* Generic function for mangling variable-length address changes inside + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX + * command in FTP). + * + * Takes care about all the nasty sequence number changes, checksumming, + * skb enlargement, ... + * + * */ +int +nf_nat_mangle_tcp_packet(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + struct iphdr *iph; + struct tcphdr *tcph; + int oldlen, datalen; + + if (!skb_make_writable(pskb, (*pskb)->len)) + return 0; + + if (rep_len > match_len && + rep_len - match_len > skb_tailroom(*pskb) && + !enlarge_skb(pskb, rep_len - match_len)) + return 0; + + SKB_LINEAR_ASSERT(*pskb); + + iph = (*pskb)->nh.iph; + tcph = (void *)iph + iph->ihl*4; + + oldlen = (*pskb)->len - iph->ihl*4; + mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, + match_offset, match_len, rep_buffer, rep_len); + + datalen = (*pskb)->len - iph->ihl*4; + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, datalen, + iph->saddr, iph->daddr, + csum_partial((char *)tcph, + datalen, 0)); + } else + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(oldlen), htons(datalen), 1); + + if (rep_len != match_len) { + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); + adjust_tcp_sequence(ntohl(tcph->seq), + (int)rep_len - (int)match_len, + ct, ctinfo); + /* Tell TCP window tracking about seq change */ + nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, + ct, CTINFO2DIR(ctinfo)); + } + return 1; +} +EXPORT_SYMBOL(nf_nat_mangle_tcp_packet); + +/* Generic function for mangling variable-length address changes inside + * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX + * command in the Amanda protocol) + * + * Takes care about all the nasty sequence number changes, checksumming, + * skb enlargement, ... + * + * XXX - This function could be merged with nf_nat_mangle_tcp_packet which + * should be fairly easy to do. + */ +int +nf_nat_mangle_udp_packet(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + struct iphdr *iph; + struct udphdr *udph; + int datalen, oldlen; + + /* UDP helpers might accidentally mangle the wrong packet */ + iph = (*pskb)->nh.iph; + if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) + + match_offset + match_len) + return 0; + + if (!skb_make_writable(pskb, (*pskb)->len)) + return 0; + + if (rep_len > match_len && + rep_len - match_len > skb_tailroom(*pskb) && + !enlarge_skb(pskb, rep_len - match_len)) + return 0; + + iph = (*pskb)->nh.iph; + udph = (void *)iph + iph->ihl*4; + + oldlen = (*pskb)->len - iph->ihl*4; + mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph), + match_offset, match_len, rep_buffer, rep_len); + + /* update the length of the UDP packet */ + datalen = (*pskb)->len - iph->ihl*4; + udph->len = htons(datalen); + + /* fix udp checksum if udp checksum was previously calculated */ + if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL) + return 1; + + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { + udph->check = 0; + udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, + datalen, IPPROTO_UDP, + csum_partial((char *)udph, + datalen, 0)); + if (!udph->check) + udph->check = CSUM_MANGLED_0; + } else + nf_proto_csum_replace2(&udph->check, *pskb, + htons(oldlen), htons(datalen), 1); + + return 1; +} +EXPORT_SYMBOL(nf_nat_mangle_udp_packet); + +/* Adjust one found SACK option including checksum correction */ +static void +sack_adjust(struct sk_buff *skb, + struct tcphdr *tcph, + unsigned int sackoff, + unsigned int sackend, + struct nf_nat_seq *natseq) +{ + while (sackoff < sackend) { + struct tcp_sack_block_wire *sack; + __be32 new_start_seq, new_end_seq; + + sack = (void *)skb->data + sackoff; + if (after(ntohl(sack->start_seq) - natseq->offset_before, + natseq->correction_pos)) + new_start_seq = htonl(ntohl(sack->start_seq) + - natseq->offset_after); + else + new_start_seq = htonl(ntohl(sack->start_seq) + - natseq->offset_before); + + if (after(ntohl(sack->end_seq) - natseq->offset_before, + natseq->correction_pos)) + new_end_seq = htonl(ntohl(sack->end_seq) + - natseq->offset_after); + else + new_end_seq = htonl(ntohl(sack->end_seq) + - natseq->offset_before); + + DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", + ntohl(sack->start_seq), new_start_seq, + ntohl(sack->end_seq), new_end_seq); + + nf_proto_csum_replace4(&tcph->check, skb, + sack->start_seq, new_start_seq, 0); + nf_proto_csum_replace4(&tcph->check, skb, + sack->end_seq, new_end_seq, 0); + sack->start_seq = new_start_seq; + sack->end_seq = new_end_seq; + sackoff += sizeof(*sack); + } +} + +/* TCP SACK sequence number adjustment */ +static inline unsigned int +nf_nat_sack_adjust(struct sk_buff **pskb, + struct tcphdr *tcph, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + unsigned int dir, optoff, optend; + struct nf_conn_nat *nat = nfct_nat(ct); + + optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr); + optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4; + + if (!skb_make_writable(pskb, optend)) + return 0; + + dir = CTINFO2DIR(ctinfo); + + while (optoff < optend) { + /* Usually: option, length. */ + unsigned char *op = (*pskb)->data + optoff; + + switch (op[0]) { + case TCPOPT_EOL: + return 1; + case TCPOPT_NOP: + optoff++; + continue; + default: + /* no partial options */ + if (optoff + 1 == optend || + optoff + op[1] > optend || + op[1] < 2) + return 0; + if (op[0] == TCPOPT_SACK && + op[1] >= 2+TCPOLEN_SACK_PERBLOCK && + ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) + sack_adjust(*pskb, tcph, optoff+2, + optoff+op[1], + &nat->info.seq[!dir]); + optoff += op[1]; + } + } + return 1; +} + +/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ +int +nf_nat_seq_adjust(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct tcphdr *tcph; + int dir; + __be32 newseq, newack; + struct nf_conn_nat *nat = nfct_nat(ct); + struct nf_nat_seq *this_way, *other_way; + + dir = CTINFO2DIR(ctinfo); + + this_way = &nat->info.seq[dir]; + other_way = &nat->info.seq[!dir]; + + if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph))) + return 0; + + tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + if (after(ntohl(tcph->seq), this_way->correction_pos)) + newseq = htonl(ntohl(tcph->seq) + this_way->offset_after); + else + newseq = htonl(ntohl(tcph->seq) + this_way->offset_before); + + if (after(ntohl(tcph->ack_seq) - other_way->offset_before, + other_way->correction_pos)) + newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after); + else + newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); + + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); + + DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", + ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), + ntohl(newack)); + + tcph->seq = newseq; + tcph->ack_seq = newack; + + if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo)) + return 0; + + nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, ct, dir); + + return 1; +} +EXPORT_SYMBOL(nf_nat_seq_adjust); + +/* Setup NAT on this expected conntrack so it follows master. */ +/* If we fail to get a free NAT slot, we'll get dropped on confirm */ +void nf_nat_follow_master(struct nf_conn *ct, + struct nf_conntrack_expect *exp) +{ + struct nf_nat_range range; + + /* This must be a fresh one. */ + BUG_ON(ct->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = exp->saved_proto; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); +} +EXPORT_SYMBOL(nf_nat_follow_master); diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c new file mode 100644 index 000000000000..dcfd772972d7 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c @@ -0,0 +1,86 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static int +icmp_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) && + ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); +} + +static int +icmp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + static u_int16_t id; + unsigned int range_size; + unsigned int i; + + range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1; + /* If no range specified... */ + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) + range_size = 0xFFFF; + + for (i = 0; i < range_size; i++, id++) { + tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + + (id % range_size)); + if (!nf_nat_used_tuple(tuple, ct)) + return 1; + } + return 0; +} + +static int +icmp_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + struct icmphdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + + if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) + return 0; + + hdr = (struct icmphdr *)((*pskb)->data + hdroff); + nf_proto_csum_replace2(&hdr->checksum, *pskb, + hdr->un.echo.id, tuple->src.u.icmp.id, 0); + hdr->un.echo.id = tuple->src.u.icmp.id; + return 1; +} + +struct nf_nat_protocol nf_nat_protocol_icmp = { + .name = "ICMP", + .protonum = IPPROTO_ICMP, + .me = THIS_MODULE, + .manip_pkt = icmp_manip_pkt, + .in_range = icmp_in_range, + .unique_tuple = icmp_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c new file mode 100644 index 000000000000..7e26a7e9bee1 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c @@ -0,0 +1,148 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static int +tcp_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + __be16 port; + + if (maniptype == IP_NAT_MANIP_SRC) + port = tuple->src.u.tcp.port; + else + port = tuple->dst.u.tcp.port; + + return ntohs(port) >= ntohs(min->tcp.port) && + ntohs(port) <= ntohs(max->tcp.port); +} + +static int +tcp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + static u_int16_t port; + __be16 *portptr; + unsigned int range_size, min, i; + + if (maniptype == IP_NAT_MANIP_SRC) + portptr = &tuple->src.u.tcp.port; + else + portptr = &tuple->dst.u.tcp.port; + + /* If no range specified... */ + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + /* If it's dst rewrite, can't change port */ + if (maniptype == IP_NAT_MANIP_DST) + return 0; + + /* Map privileged onto privileged. */ + if (ntohs(*portptr) < 1024) { + /* Loose convention: >> 512 is credential passing */ + if (ntohs(*portptr)<512) { + min = 1; + range_size = 511 - min + 1; + } else { + min = 600; + range_size = 1023 - min + 1; + } + } else { + min = 1024; + range_size = 65535 - 1024 + 1; + } + } else { + min = ntohs(range->min.tcp.port); + range_size = ntohs(range->max.tcp.port) - min + 1; + } + + for (i = 0; i < range_size; i++, port++) { + *portptr = htons(min + port % range_size); + if (!nf_nat_used_tuple(tuple, ct)) + return 1; + } + return 0; +} + +static int +tcp_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + struct tcphdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + __be32 oldip, newip; + __be16 *portptr, newport, oldport; + int hdrsize = 8; /* TCP connection tracking guarantees this much */ + + /* this could be a inner header returned in icmp packet; in such + cases we cannot update the checksum field since it is outside of + the 8 bytes of transport layer headers we are guaranteed */ + if ((*pskb)->len >= hdroff + sizeof(struct tcphdr)) + hdrsize = sizeof(struct tcphdr); + + if (!skb_make_writable(pskb, hdroff + hdrsize)) + return 0; + + iph = (struct iphdr *)((*pskb)->data + iphdroff); + hdr = (struct tcphdr *)((*pskb)->data + hdroff); + + if (maniptype == IP_NAT_MANIP_SRC) { + /* Get rid of src ip and src pt */ + oldip = iph->saddr; + newip = tuple->src.u3.ip; + newport = tuple->src.u.tcp.port; + portptr = &hdr->source; + } else { + /* Get rid of dst ip and dst pt */ + oldip = iph->daddr; + newip = tuple->dst.u3.ip; + newport = tuple->dst.u.tcp.port; + portptr = &hdr->dest; + } + + oldport = *portptr; + *portptr = newport; + + if (hdrsize < sizeof(*hdr)) + return 1; + + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); + return 1; +} + +struct nf_nat_protocol nf_nat_protocol_tcp = { + .name = "TCP", + .protonum = IPPROTO_TCP, + .me = THIS_MODULE, + .manip_pkt = tcp_manip_pkt, + .in_range = tcp_in_range, + .unique_tuple = tcp_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c new file mode 100644 index 000000000000..ab0ce4c8699f --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c @@ -0,0 +1,138 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static int +udp_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + __be16 port; + + if (maniptype == IP_NAT_MANIP_SRC) + port = tuple->src.u.udp.port; + else + port = tuple->dst.u.udp.port; + + return ntohs(port) >= ntohs(min->udp.port) && + ntohs(port) <= ntohs(max->udp.port); +} + +static int +udp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + static u_int16_t port; + __be16 *portptr; + unsigned int range_size, min, i; + + if (maniptype == IP_NAT_MANIP_SRC) + portptr = &tuple->src.u.udp.port; + else + portptr = &tuple->dst.u.udp.port; + + /* If no range specified... */ + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + /* If it's dst rewrite, can't change port */ + if (maniptype == IP_NAT_MANIP_DST) + return 0; + + if (ntohs(*portptr) < 1024) { + /* Loose convention: >> 512 is credential passing */ + if (ntohs(*portptr)<512) { + min = 1; + range_size = 511 - min + 1; + } else { + min = 600; + range_size = 1023 - min + 1; + } + } else { + min = 1024; + range_size = 65535 - 1024 + 1; + } + } else { + min = ntohs(range->min.udp.port); + range_size = ntohs(range->max.udp.port) - min + 1; + } + + for (i = 0; i < range_size; i++, port++) { + *portptr = htons(min + port % range_size); + if (!nf_nat_used_tuple(tuple, ct)) + return 1; + } + return 0; +} + +static int +udp_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + struct udphdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + __be32 oldip, newip; + __be16 *portptr, newport; + + if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) + return 0; + + iph = (struct iphdr *)((*pskb)->data + iphdroff); + hdr = (struct udphdr *)((*pskb)->data + hdroff); + + if (maniptype == IP_NAT_MANIP_SRC) { + /* Get rid of src ip and src pt */ + oldip = iph->saddr; + newip = tuple->src.u3.ip; + newport = tuple->src.u.udp.port; + portptr = &hdr->source; + } else { + /* Get rid of dst ip and dst pt */ + oldip = iph->daddr; + newip = tuple->dst.u3.ip; + newport = tuple->dst.u.udp.port; + portptr = &hdr->dest; + } + if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, + 0); + if (!hdr->check) + hdr->check = CSUM_MANGLED_0; + } + *portptr = newport; + return 1; +} + +struct nf_nat_protocol nf_nat_protocol_udp = { + .name = "UDP", + .protonum = IPPROTO_UDP, + .me = THIS_MODULE, + .manip_pkt = udp_manip_pkt, + .in_range = udp_in_range, + .unique_tuple = udp_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c new file mode 100644 index 000000000000..f50d0203f9c0 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c @@ -0,0 +1,54 @@ +/* The "unknown" protocol. This is what is used for protocols we + * don't understand. It's returned by ip_ct_find_proto(). + */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +#include +#include +#include +#include + +static int unknown_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type manip_type, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + return 1; +} + +static int unknown_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + /* Sorry: we can't help you; if it's not unique, we can't frob + anything. */ + return 0; +} + +static int +unknown_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + return 1; +} + +struct nf_nat_protocol nf_nat_unknown_protocol = { + .name = "unknown", + /* .me isn't set: getting a ref to this cannot fail. */ + .manip_pkt = unknown_manip_pkt, + .in_range = unknown_in_range, + .unique_tuple = unknown_unique_tuple, +}; diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c new file mode 100644 index 000000000000..b868ee0195d4 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -0,0 +1,343 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Everything about the rules for NAT. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define NAT_VALID_HOOKS ((1<range[0], hooknum); +} + +/* Before 2.6.11 we did implicit source NAT if required. Warn about change. */ +static void warn_if_extra_mangle(__be32 dstip, __be32 srcip) +{ + static int warned = 0; + struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } }; + struct rtable *rt; + + if (ip_route_output_key(&rt, &fl) != 0) + return; + + if (rt->rt_src != srcip && !warned) { + printk("NAT: no longer support implicit source local NAT\n"); + printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n", + NIPQUAD(srcip), NIPQUAD(dstip)); + warned = 1; + } + ip_rt_put(rt); +} + +static unsigned int ipt_dnat_target(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const struct xt_target *target, + const void *targinfo) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + const struct nf_nat_multi_range_compat *mr = targinfo; + + NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || + hooknum == NF_IP_LOCAL_OUT); + + ct = nf_ct_get(*pskb, &ctinfo); + + /* Connection must be valid and new. */ + NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); + + if (hooknum == NF_IP_LOCAL_OUT && + mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) + warn_if_extra_mangle((*pskb)->nh.iph->daddr, + mr->range[0].min_ip); + + return nf_nat_setup_info(ct, &mr->range[0], hooknum); +} + +static int ipt_snat_checkentry(const char *tablename, + const void *entry, + const struct xt_target *target, + void *targinfo, + unsigned int hook_mask) +{ + struct nf_nat_multi_range_compat *mr = targinfo; + + /* Must be a valid range */ + if (mr->rangesize != 1) { + printk("SNAT: multiple ranges no longer supported\n"); + return 0; + } + return 1; +} + +static int ipt_dnat_checkentry(const char *tablename, + const void *entry, + const struct xt_target *target, + void *targinfo, + unsigned int hook_mask) +{ + struct nf_nat_multi_range_compat *mr = targinfo; + + /* Must be a valid range */ + if (mr->rangesize != 1) { + printk("DNAT: multiple ranges no longer supported\n"); + return 0; + } + return 1; +} + +inline unsigned int +alloc_null_binding(struct nf_conn *ct, + struct nf_nat_info *info, + unsigned int hooknum) +{ + /* Force range to this IP; let proto decide mapping for + per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). + Use reply in case it's already been mangled (eg local packet). + */ + __be32 ip + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); + struct nf_nat_range range + = { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } }; + + DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", + ct, NIPQUAD(ip)); + return nf_nat_setup_info(ct, &range, hooknum); +} + +unsigned int +alloc_null_binding_confirmed(struct nf_conn *ct, + struct nf_nat_info *info, + unsigned int hooknum) +{ + __be32 ip + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); + u_int16_t all + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); + struct nf_nat_range range + = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } }; + + DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n", + ct, NIPQUAD(ip)); + return nf_nat_setup_info(ct, &range, hooknum); +} + +int nf_nat_rule_find(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + struct nf_conn *ct, + struct nf_nat_info *info) +{ + int ret; + + ret = ipt_do_table(pskb, hooknum, in, out, &nat_table); + + if (ret == NF_ACCEPT) { + if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) + /* NUL mapping */ + ret = alloc_null_binding(ct, info, hooknum); + } + return ret; +} + +static struct ipt_target ipt_snat_reg = { + .name = "SNAT", + .target = ipt_snat_target, + .targetsize = sizeof(struct nf_nat_multi_range_compat), + .table = "nat", + .hooks = 1 << NF_IP_POST_ROUTING, + .checkentry = ipt_snat_checkentry, + .family = AF_INET, +}; + +static struct xt_target ipt_dnat_reg = { + .name = "DNAT", + .target = ipt_dnat_target, + .targetsize = sizeof(struct nf_nat_multi_range_compat), + .table = "nat", + .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT), + .checkentry = ipt_dnat_checkentry, + .family = AF_INET, +}; + +int __init nf_nat_rule_init(void) +{ + int ret; + + ret = ipt_register_table(&nat_table, &nat_initial_table.repl); + if (ret != 0) + return ret; + ret = xt_register_target(&ipt_snat_reg); + if (ret != 0) + goto unregister_table; + + ret = xt_register_target(&ipt_dnat_reg); + if (ret != 0) + goto unregister_snat; + + return ret; + + unregister_snat: + xt_unregister_target(&ipt_snat_reg); + unregister_table: + ipt_unregister_table(&nat_table); + + return ret; +} + +void nf_nat_rule_cleanup(void) +{ + xt_unregister_target(&ipt_dnat_reg); + xt_unregister_target(&ipt_snat_reg); + ipt_unregister_table(&nat_table); +} diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c new file mode 100644 index 000000000000..730a7a44c883 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -0,0 +1,406 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ + : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ + : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ + : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ + : "*ERROR*"))) + +#ifdef CONFIG_XFRM +static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) +{ + struct nf_conn *ct; + struct nf_conntrack_tuple *t; + enum ip_conntrack_info ctinfo; + enum ip_conntrack_dir dir; + unsigned long statusbit; + + ct = nf_ct_get(skb, &ctinfo); + if (ct == NULL) + return; + dir = CTINFO2DIR(ctinfo); + t = &ct->tuplehash[dir].tuple; + + if (dir == IP_CT_DIR_ORIGINAL) + statusbit = IPS_DST_NAT; + else + statusbit = IPS_SRC_NAT; + + if (ct->status & statusbit) { + fl->fl4_dst = t->dst.u3.ip; + if (t->dst.protonum == IPPROTO_TCP || + t->dst.protonum == IPPROTO_UDP) + fl->fl_ip_dport = t->dst.u.tcp.port; + } + + statusbit ^= IPS_NAT_MASK; + + if (ct->status & statusbit) { + fl->fl4_src = t->src.u3.ip; + if (t->dst.protonum == IPPROTO_TCP || + t->dst.protonum == IPPROTO_UDP) + fl->fl_ip_sport = t->src.u.tcp.port; + } +} +#endif + +static unsigned int +nf_nat_fn(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + struct nf_conn_nat *nat; + struct nf_nat_info *info; + /* maniptype == SRC for postrouting. */ + enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); + + /* We never see fragments: conntrack defrags on pre-routing + and local-out, and nf_nat_out protects post-routing. */ + NF_CT_ASSERT(!((*pskb)->nh.iph->frag_off + & htons(IP_MF|IP_OFFSET))); + + ct = nf_ct_get(*pskb, &ctinfo); + /* Can't track? It's not due to stress, or conntrack would + have dropped it. Hence it's the user's responsibilty to + packet filter it out, or implement conntrack/NAT for that + protocol. 8) --RR */ + if (!ct) { + /* Exception: ICMP redirect to new connection (not in + hash table yet). We must not let this through, in + case we're doing NAT to the same network. */ + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { + struct icmphdr _hdr, *hp; + + hp = skb_header_pointer(*pskb, + (*pskb)->nh.iph->ihl*4, + sizeof(_hdr), &_hdr); + if (hp != NULL && + hp->type == ICMP_REDIRECT) + return NF_DROP; + } + return NF_ACCEPT; + } + + /* Don't try to NAT if this packet is not conntracked */ + if (ct == &nf_conntrack_untracked) + return NF_ACCEPT; + + nat = nfct_nat(ct); + if (!nat) + return NF_DROP; + + switch (ctinfo) { + case IP_CT_RELATED: + case IP_CT_RELATED+IP_CT_IS_REPLY: + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { + if (!nf_nat_icmp_reply_translation(ct, ctinfo, + hooknum, pskb)) + return NF_DROP; + else + return NF_ACCEPT; + } + /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ + case IP_CT_NEW: + info = &nat->info; + + /* Seen it before? This can happen for loopback, retrans, + or local packets.. */ + if (!nf_nat_initialized(ct, maniptype)) { + unsigned int ret; + + if (unlikely(nf_ct_is_confirmed(ct))) + /* NAT module was loaded late */ + ret = alloc_null_binding_confirmed(ct, info, + hooknum); + else if (hooknum == NF_IP_LOCAL_IN) + /* LOCAL_IN hook doesn't have a chain! */ + ret = alloc_null_binding(ct, info, hooknum); + else + ret = nf_nat_rule_find(pskb, hooknum, in, out, + ct, info); + + if (ret != NF_ACCEPT) { + return ret; + } + } else + DEBUGP("Already setup manip %s for ct %p\n", + maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", + ct); + break; + + default: + /* ESTABLISHED */ + NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || + ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); + info = &nat->info; + } + + NF_CT_ASSERT(info); + return nf_nat_packet(ct, ctinfo, hooknum, pskb); +} + +static unsigned int +nf_nat_in(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + unsigned int ret; + __be32 daddr = (*pskb)->nh.iph->daddr; + + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); + if (ret != NF_DROP && ret != NF_STOLEN && + daddr != (*pskb)->nh.iph->daddr) { + dst_release((*pskb)->dst); + (*pskb)->dst = NULL; + } + return ret; +} + +static unsigned int +nf_nat_out(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ +#ifdef CONFIG_XFRM + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; +#endif + unsigned int ret; + + /* root is playing with raw sockets. */ + if ((*pskb)->len < sizeof(struct iphdr) || + (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) + return NF_ACCEPT; + + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); +#ifdef CONFIG_XFRM + if (ret != NF_DROP && ret != NF_STOLEN && + (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + + if (ct->tuplehash[dir].tuple.src.u3.ip != + ct->tuplehash[!dir].tuple.dst.u3.ip + || ct->tuplehash[dir].tuple.src.u.all != + ct->tuplehash[!dir].tuple.dst.u.all + ) + return ip_xfrm_me_harder(pskb) == 0 ? ret : NF_DROP; + } +#endif + return ret; +} + +static unsigned int +nf_nat_local_fn(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + unsigned int ret; + + /* root is playing with raw sockets. */ + if ((*pskb)->len < sizeof(struct iphdr) || + (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) + return NF_ACCEPT; + + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); + if (ret != NF_DROP && ret != NF_STOLEN && + (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + + if (ct->tuplehash[dir].tuple.dst.u3.ip != + ct->tuplehash[!dir].tuple.src.u3.ip +#ifdef CONFIG_XFRM + || ct->tuplehash[dir].tuple.dst.u.all != + ct->tuplehash[!dir].tuple.src.u.all +#endif + ) + if (ip_route_me_harder(pskb, RTN_UNSPEC)) + ret = NF_DROP; + } + return ret; +} + +static unsigned int +nf_nat_adjust(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + + ct = nf_ct_get(*pskb, &ctinfo); + if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { + DEBUGP("nf_nat_standalone: adjusting sequence number\n"); + if (!nf_nat_seq_adjust(pskb, ct, ctinfo)) + return NF_DROP; + } + return NF_ACCEPT; +} + +/* We must be after connection tracking and before packet filtering. */ + +static struct nf_hook_ops nf_nat_ops[] = { + /* Before packet filtering, change destination */ + { + .hook = nf_nat_in, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_NAT_DST, + }, + /* After packet filtering, change source */ + { + .hook = nf_nat_out, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_NAT_SRC, + }, + /* After conntrack, adjust sequence number */ + { + .hook = nf_nat_adjust, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, + }, + /* Before packet filtering, change destination */ + { + .hook = nf_nat_local_fn, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_NAT_DST, + }, + /* After packet filtering, change source */ + { + .hook = nf_nat_fn, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_NAT_SRC, + }, + /* After conntrack, adjust sequence number */ + { + .hook = nf_nat_adjust, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, + }, +}; + +static int __init nf_nat_standalone_init(void) +{ + int size, ret = 0; + + need_conntrack(); + + size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_nat)) + + sizeof(struct nf_conn_nat); + ret = nf_conntrack_register_cache(NF_CT_F_NAT, "nf_nat:base", size); + if (ret < 0) { + printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); + return ret; + } + + size = ALIGN(size, __alignof__(struct nf_conn_help)) + + sizeof(struct nf_conn_help); + ret = nf_conntrack_register_cache(NF_CT_F_NAT|NF_CT_F_HELP, + "nf_nat:help", size); + if (ret < 0) { + printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); + goto cleanup_register_cache; + } +#ifdef CONFIG_XFRM + BUG_ON(ip_nat_decode_session != NULL); + ip_nat_decode_session = nat_decode_session; +#endif + ret = nf_nat_rule_init(); + if (ret < 0) { + printk("nf_nat_init: can't setup rules.\n"); + goto cleanup_decode_session; + } + ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); + if (ret < 0) { + printk("nf_nat_init: can't register hooks.\n"); + goto cleanup_rule_init; + } + nf_nat_module_is_loaded = 1; + return ret; + + cleanup_rule_init: + nf_nat_rule_cleanup(); + cleanup_decode_session: +#ifdef CONFIG_XFRM + ip_nat_decode_session = NULL; + synchronize_net(); +#endif + nf_conntrack_unregister_cache(NF_CT_F_NAT|NF_CT_F_HELP); + cleanup_register_cache: + nf_conntrack_unregister_cache(NF_CT_F_NAT); + return ret; +} + +static void __exit nf_nat_standalone_fini(void) +{ + nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); + nf_nat_rule_cleanup(); + nf_nat_module_is_loaded = 0; +#ifdef CONFIG_XFRM + ip_nat_decode_session = NULL; + synchronize_net(); +#endif + /* Conntrack caches are unregistered in nf_conntrack_cleanup */ +} + +module_init(nf_nat_standalone_init); +module_exit(nf_nat_standalone_fini); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat"); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index f952a7fb6ae3..aa8beabfeebb 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -579,7 +579,8 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, /* FIXME: protect helper list per RCU */ read_lock_bh(&nf_conntrack_lock); helper = __nf_ct_helper_find(repl); - if (helper) + /* NAT might want to assign a helper later */ + if (helper || features & NF_CT_F_NAT) features |= NF_CT_F_HELP; read_unlock_bh(&nf_conntrack_lock); @@ -850,6 +851,26 @@ int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, orig->dst.protonum)); } +/* Alter reply tuple (maybe alter helper). This is for NAT, and is + implicitly racy: see __nf_conntrack_confirm */ +void nf_conntrack_alter_reply(struct nf_conn *ct, + const struct nf_conntrack_tuple *newreply) +{ + struct nf_conn_help *help = nfct_help(ct); + + write_lock_bh(&nf_conntrack_lock); + /* Should be unconfirmed, so not in hash table yet */ + NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); + + DEBUGP("Altering reply tuple of %p to ", ct); + NF_CT_DUMP_TUPLE(newreply); + + ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; + if (!ct->master && help && help->expecting == 0) + help->helper = __nf_ct_helper_find(newreply); + write_unlock_bh(&nf_conntrack_lock); +} + /* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */ void __nf_ct_refresh_acct(struct nf_conn *ct, enum ip_conntrack_info ctinfo, diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index f9c8ddd5973c..bd1d2de75e45 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -39,7 +39,11 @@ #include #include #include -#include +#include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#include +#endif #include #include @@ -430,7 +434,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) restart: list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { h = (struct nf_conntrack_tuple_hash *) i; - if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) + if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) continue; ct = nf_ct_tuplehash_to_ctrack(h); /* Dump entries of a given L3 protocol number. @@ -556,28 +560,28 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple, return 0; } -#ifdef CONFIG_IP_NF_NAT_NEEDED +#ifdef CONFIG_NF_NAT_NEEDED static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), }; -static int ctnetlink_parse_nat_proto(struct nfattr *attr, +static int nfnetlink_parse_nat_proto(struct nfattr *attr, const struct nf_conn *ct, - struct ip_nat_range *range) + struct nf_nat_range *range) { struct nfattr *tb[CTA_PROTONAT_MAX]; - struct ip_nat_protocol *npt; + struct nf_nat_protocol *npt; nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) return -EINVAL; - npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); + npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); if (!npt->nfattr_to_range) { - ip_nat_proto_put(npt); + nf_nat_proto_put(npt); return 0; } @@ -585,7 +589,7 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr, if (npt->nfattr_to_range(tb, range) > 0) range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; - ip_nat_proto_put(npt); + nf_nat_proto_put(npt); return 0; } @@ -596,8 +600,8 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = { }; static inline int -ctnetlink_parse_nat(struct nfattr *nat, - const struct nf_conn *ct, struct ip_nat_range *range) +nfnetlink_parse_nat(struct nfattr *nat, + const struct nf_conn *ct, struct nf_nat_range *range) { struct nfattr *tb[CTA_NAT_MAX]; int err; @@ -623,7 +627,7 @@ ctnetlink_parse_nat(struct nfattr *nat, if (!tb[CTA_NAT_PROTO-1]) return 0; - err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); + err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); if (err < 0) return err; @@ -798,35 +802,35 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) return -EINVAL; if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { -#ifndef CONFIG_IP_NF_NAT_NEEDED +#ifndef CONFIG_NF_NAT_NEEDED return -EINVAL; #else - struct ip_nat_range range; + struct nf_nat_range range; if (cda[CTA_NAT_DST-1]) { - if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, + if (nfnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, &range) < 0) return -EINVAL; - if (ip_nat_initialized(ct, + if (nf_nat_initialized(ct, HOOK2MANIP(NF_IP_PRE_ROUTING))) return -EEXIST; - ip_nat_setup_info(ct, &range, hooknum); + nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); } if (cda[CTA_NAT_SRC-1]) { - if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, + if (nfnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, &range) < 0) return -EINVAL; - if (ip_nat_initialized(ct, + if (nf_nat_initialized(ct, HOOK2MANIP(NF_IP_POST_ROUTING))) return -EEXIST; - ip_nat_setup_info(ct, &range, hooknum); + nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); } #endif } /* Be careful here, modifying NAT bits can screw up things, * so don't let users modify them directly if they don't pass - * ip_nat_range. */ + * nf_nat_range. */ ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); return 0; } diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 71f492fc6413..8156e429b885 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -730,7 +730,7 @@ static int tcp_in_window(struct ip_ct_tcp *state, return res; } -#ifdef CONFIG_IP_NF_NAT_NEEDED +#ifdef CONFIG_NF_NAT_NEEDED /* Update sender->td_end after NAT successfully mangled the packet */ /* Caller must linearize skb at tcp header. */ void nf_conntrack_tcp_update(struct sk_buff *skb, diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index be94b6359725..3f56a3a6c399 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -530,8 +530,11 @@ EXPORT_SYMBOL(nf_conntrack_lock); EXPORT_SYMBOL(nf_conntrack_hash); EXPORT_SYMBOL(nf_conntrack_untracked); EXPORT_SYMBOL_GPL(nf_conntrack_find_get); -#ifdef CONFIG_IP_NF_NAT_NEEDED +#ifdef CONFIG_NF_NAT_NEEDED EXPORT_SYMBOL(nf_conntrack_tcp_update); +EXPORT_SYMBOL(nf_conntrack_register_cache); +EXPORT_SYMBOL(nf_conntrack_unregister_cache); +EXPORT_SYMBOL(nf_conntrack_alter_reply); #endif EXPORT_SYMBOL(__nf_conntrack_confirm); EXPORT_SYMBOL(nf_ct_get_tuple); -- cgit v1.2.3 From 55a733247d6d2883d9bb77825fafac3dfca13fc2 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Sat, 2 Dec 2006 22:07:44 -0800 Subject: [NETFILTER]: nf_nat: add FTP NAT helper port Add FTP NAT helper. Split out from Jozsef's big nf_nat patch with a few small fixes by myself. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_ftp.h | 20 +-- include/linux/netfilter_ipv4/ip_conntrack_ftp.h | 40 +++++- include/net/netfilter/nf_conntrack.h | 2 +- net/ipv4/netfilter/Kconfig | 25 ++-- net/ipv4/netfilter/Makefile | 5 +- net/ipv4/netfilter/nf_nat_ftp.c | 179 ++++++++++++++++++++++++ net/netfilter/nf_conntrack_ftp.c | 20 +-- 7 files changed, 260 insertions(+), 31 deletions(-) create mode 100644 net/ipv4/netfilter/nf_nat_ftp.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_ftp.h b/include/linux/netfilter/nf_conntrack_ftp.h index ad4a41c9ce93..81453ea7e4c2 100644 --- a/include/linux/netfilter/nf_conntrack_ftp.h +++ b/include/linux/netfilter/nf_conntrack_ftp.h @@ -3,16 +3,16 @@ /* FTP tracking. */ /* This enum is exposed to userspace */ -enum ip_ct_ftp_type +enum nf_ct_ftp_type { /* PORT command from client */ - IP_CT_FTP_PORT, + NF_CT_FTP_PORT, /* PASV response from server */ - IP_CT_FTP_PASV, + NF_CT_FTP_PASV, /* EPRT command from client */ - IP_CT_FTP_EPRT, + NF_CT_FTP_EPRT, /* EPSV response from server */ - IP_CT_FTP_EPSV, + NF_CT_FTP_EPSV, }; #ifdef __KERNEL__ @@ -21,23 +21,23 @@ enum ip_ct_ftp_type #define NUM_SEQ_TO_REMEMBER 2 /* This structure exists only once per master */ -struct ip_ct_ftp_master { +struct nf_ct_ftp_master { /* Valid seq positions for cmd matching after newline */ u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER]; /* 0 means seq_match_aft_nl not set */ int seq_aft_nl_num[IP_CT_DIR_MAX]; }; -struct ip_conntrack_expect; +struct nf_conntrack_expect; /* For NAT to hook in when we find a packet which describes what other * connection we should expect. */ -extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, +extern unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, - enum ip_ct_ftp_type type, + enum nf_ct_ftp_type type, unsigned int matchoff, unsigned int matchlen, - struct ip_conntrack_expect *exp, + struct nf_conntrack_expect *exp, u32 *seq); #endif /* __KERNEL__ */ diff --git a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h index 63811934de4d..2129fc3972ac 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h @@ -1,6 +1,44 @@ #ifndef _IP_CONNTRACK_FTP_H #define _IP_CONNTRACK_FTP_H +/* FTP tracking. */ -#include +/* This enum is exposed to userspace */ +enum ip_ct_ftp_type +{ + /* PORT command from client */ + IP_CT_FTP_PORT, + /* PASV response from server */ + IP_CT_FTP_PASV, + /* EPRT command from client */ + IP_CT_FTP_EPRT, + /* EPSV response from server */ + IP_CT_FTP_EPSV, +}; + +#ifdef __KERNEL__ + +#define FTP_PORT 21 + +#define NUM_SEQ_TO_REMEMBER 2 +/* This structure exists only once per master */ +struct ip_ct_ftp_master { + /* Valid seq positions for cmd matching after newline */ + u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER]; + /* 0 means seq_match_aft_nl not set */ + int seq_aft_nl_num[IP_CT_DIR_MAX]; +}; + +struct ip_conntrack_expect; + +/* For NAT to hook in when we find a packet which describes what other + * connection we should expect. */ +extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + enum ip_ct_ftp_type type, + unsigned int matchoff, + unsigned int matchlen, + struct ip_conntrack_expect *exp, + u32 *seq); +#endif /* __KERNEL__ */ #endif /* _IP_CONNTRACK_FTP_H */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 9948af068688..83694cfdfa8f 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -45,7 +45,7 @@ union nf_conntrack_expect_proto { /* per conntrack: application helper private data */ union nf_conntrack_help { /* insert conntrack helper private data (master) here */ - struct ip_ct_ftp_master ct_ftp_info; + struct nf_ct_ftp_master ct_ftp_info; }; #include diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 01789aeaeb5f..52f876db68f4 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -477,20 +477,29 @@ config IP_NF_NAT_SNMP_BASIC To compile it as a module, choose M here. If unsure, say N. +# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), +# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. +# From kconfig-language.txt: +# +# '&&' (6) +# +# (6) Returns the result of min(/expr/, /expr/). +config IP_NF_NAT_FTP + tristate + depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT + default IP_NF_NAT && IP_NF_FTP + +config NF_NAT_FTP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_FTP + config IP_NF_NAT_IRC tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n default IP_NF_NAT if IP_NF_IRC=y default m if IP_NF_IRC=m -# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), -# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh. -config IP_NF_NAT_FTP - tristate - depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n - default IP_NF_NAT if IP_NF_FTP=y - default m if IP_NF_FTP=m - config IP_NF_NAT_TFTP tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index ec31690764ac..c0c6194bb275 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -40,7 +40,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o -# NAT helpers +# NAT helpers (ip_conntrack) obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o @@ -49,6 +49,9 @@ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o +# NAT helpers (nf_conntrack) +obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o + # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c new file mode 100644 index 000000000000..751b59801755 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_ftp.c @@ -0,0 +1,179 @@ +/* FTP extension for TCP NAT alteration. */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rusty Russell "); +MODULE_DESCRIPTION("ftp NAT helper"); +MODULE_ALIAS("ip_nat_ftp"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/* FIXME: Time out? --RR */ + +static int +mangle_rfc959_packet(struct sk_buff **pskb, + __be32 newip, + u_int16_t port, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + u32 *seq) +{ + char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")]; + + sprintf(buffer, "%u,%u,%u,%u,%u,%u", + NIPQUAD(newip), port>>8, port&0xFF); + + DEBUGP("calling nf_nat_mangle_tcp_packet\n"); + + *seq += strlen(buffer) - matchlen; + return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, + matchlen, buffer, strlen(buffer)); +} + +/* |1|132.235.1.2|6275| */ +static int +mangle_eprt_packet(struct sk_buff **pskb, + __be32 newip, + u_int16_t port, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + u32 *seq) +{ + char buffer[sizeof("|1|255.255.255.255|65535|")]; + + sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port); + + DEBUGP("calling nf_nat_mangle_tcp_packet\n"); + + *seq += strlen(buffer) - matchlen; + return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, + matchlen, buffer, strlen(buffer)); +} + +/* |1|132.235.1.2|6275| */ +static int +mangle_epsv_packet(struct sk_buff **pskb, + __be32 newip, + u_int16_t port, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + u32 *seq) +{ + char buffer[sizeof("|||65535|")]; + + sprintf(buffer, "|||%u|", port); + + DEBUGP("calling nf_nat_mangle_tcp_packet\n"); + + *seq += strlen(buffer) - matchlen; + return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, + matchlen, buffer, strlen(buffer)); +} + +static int (*mangle[])(struct sk_buff **, __be32, u_int16_t, + unsigned int, unsigned int, struct nf_conn *, + enum ip_conntrack_info, u32 *seq) += { + [NF_CT_FTP_PORT] = mangle_rfc959_packet, + [NF_CT_FTP_PASV] = mangle_rfc959_packet, + [NF_CT_FTP_EPRT] = mangle_eprt_packet, + [NF_CT_FTP_EPSV] = mangle_epsv_packet +}; + +/* So, this packet has hit the connection tracking matching code. + Mangle it, and change the expectation to match the new version. */ +static unsigned int nf_nat_ftp(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + enum nf_ct_ftp_type type, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp, + u32 *seq) +{ + __be32 newip; + u_int16_t port; + int dir = CTINFO2DIR(ctinfo); + struct nf_conn *ct = exp->master; + + DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen); + + /* Connection will come from wherever this packet goes, hence !dir */ + newip = ct->tuplehash[!dir].tuple.dst.u3.ip; + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->dir = !dir; + + /* When you see the packet, we need to NAT it the same as the + * this one. */ + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + exp->tuple.dst.u.tcp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo, + seq)) { + nf_conntrack_unexpect_related(exp); + return NF_DROP; + } + return NF_ACCEPT; +} + +static void __exit nf_nat_ftp_fini(void) +{ + rcu_assign_pointer(nf_nat_ftp_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_ftp_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_ftp_hook)); + rcu_assign_pointer(nf_nat_ftp_hook, nf_nat_ftp); + return 0; +} + +/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ +static int warn_set(const char *val, struct kernel_param *kp) +{ + printk(KERN_INFO KBUILD_MODNAME + ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); + return 0; +} +module_param_call(ports, warn_set, NULL, NULL, 0); + +module_init(nf_nat_ftp_init); +module_exit(nf_nat_ftp_fini); diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index e299d657e4fc..92a947168761 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -51,7 +51,7 @@ module_param(loose, bool, 0600); unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, - enum ip_ct_ftp_type type, + enum nf_ct_ftp_type type, unsigned int matchoff, unsigned int matchlen, struct nf_conntrack_expect *exp, @@ -74,7 +74,7 @@ static struct ftp_search { size_t plen; char skip; char term; - enum ip_ct_ftp_type ftptype; + enum nf_ct_ftp_type ftptype; int (*getnum)(const char *, size_t, struct nf_conntrack_man *, char); } search[IP_CT_DIR_MAX][2] = { [IP_CT_DIR_ORIGINAL] = { @@ -83,7 +83,7 @@ static struct ftp_search { .plen = sizeof("PORT") - 1, .skip = ' ', .term = '\r', - .ftptype = IP_CT_FTP_PORT, + .ftptype = NF_CT_FTP_PORT, .getnum = try_rfc959, }, { @@ -91,7 +91,7 @@ static struct ftp_search { .plen = sizeof("EPRT") - 1, .skip = ' ', .term = '\r', - .ftptype = IP_CT_FTP_EPRT, + .ftptype = NF_CT_FTP_EPRT, .getnum = try_eprt, }, }, @@ -101,7 +101,7 @@ static struct ftp_search { .plen = sizeof("227 ") - 1, .skip = '(', .term = ')', - .ftptype = IP_CT_FTP_PASV, + .ftptype = NF_CT_FTP_PASV, .getnum = try_rfc959, }, { @@ -109,7 +109,7 @@ static struct ftp_search { .plen = sizeof("229 ") - 1, .skip = '(', .term = ')', - .ftptype = IP_CT_FTP_EPSV, + .ftptype = NF_CT_FTP_EPSV, .getnum = try_epsv_response, }, }, @@ -320,7 +320,7 @@ static int find_pattern(const char *data, size_t dlen, } /* Look up to see if we're just after a \n. */ -static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir) +static int find_nl_seq(u32 seq, const struct nf_ct_ftp_master *info, int dir) { unsigned int i; @@ -331,7 +331,7 @@ static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir) } /* We don't update if it's older than what we have. */ -static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir, +static void update_nl_seq(u32 nl_seq, struct nf_ct_ftp_master *info, int dir, struct sk_buff *skb) { unsigned int i, oldest = NUM_SEQ_TO_REMEMBER; @@ -367,7 +367,7 @@ static int help(struct sk_buff **pskb, u32 seq; int dir = CTINFO2DIR(ctinfo); unsigned int matchlen, matchoff; - struct ip_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info; + struct nf_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info; struct nf_conntrack_expect *exp; struct nf_conntrack_man cmd = {}; unsigned int i; @@ -523,7 +523,7 @@ static int help(struct sk_buff **pskb, /* Now, NAT might want to mangle the packet, and register the * (possibly changed) expectation itself. */ nf_nat_ftp = rcu_dereference(nf_nat_ftp_hook); - if (nf_nat_ftp) + if (nf_nat_ftp && ct->status & IPS_NAT_MASK) ret = nf_nat_ftp(pskb, ctinfo, search[dir][i].ftptype, matchoff, matchlen, exp, &seq); else { -- cgit v1.2.3 From 16958900578b94585c2ab9a2d20d837b4d5e3ba6 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:08:26 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add amanda helper port Add IPv4 and IPv6 capable nf_conntrack port of the Amanda conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_amanda.h | 10 ++ net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_amanda.c | 78 +++++++++ net/netfilter/Kconfig | 15 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_amanda.c | 237 ++++++++++++++++++++++++++ 7 files changed, 347 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_amanda.h create mode 100644 net/ipv4/netfilter/nf_nat_amanda.c create mode 100644 net/netfilter/nf_conntrack_amanda.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_amanda.h b/include/linux/netfilter/nf_conntrack_amanda.h new file mode 100644 index 000000000000..26c223544ae8 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_amanda.h @@ -0,0 +1,10 @@ +#ifndef _NF_CONNTRACK_AMANDA_H +#define _NF_CONNTRACK_AMANDA_H +/* AMANDA tracking. */ + +extern unsigned int (*nf_nat_amanda_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp); +#endif /* _NF_CONNTRACK_AMANDA_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 52f876db68f4..6993ec53dc06 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -512,6 +512,11 @@ config IP_NF_NAT_AMANDA default IP_NF_NAT if IP_NF_AMANDA=y default m if IP_NF_AMANDA=m +config NF_NAT_AMANDA + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_AMANDA + config IP_NF_NAT_PPTP tristate depends on IP_NF_NAT!=n && IP_NF_PPTP!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index c0c6194bb275..8893249bbe98 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o # NAT helpers (nf_conntrack) +obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o # generic IP tables diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c new file mode 100644 index 000000000000..0f17098917bc --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_amanda.c @@ -0,0 +1,78 @@ +/* Amanda extension for TCP NAT alteration. + * (C) 2002 by Brian J. Murrell + * based on a copy of HW's ip_nat_irc.c as well as other modules + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Brian J. Murrell "); +MODULE_DESCRIPTION("Amanda NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_amanda"); + +static unsigned int help(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp) +{ + char buffer[sizeof("65535")]; + u_int16_t port; + unsigned int ret; + + /* Connection comes from client. */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->dir = IP_CT_DIR_ORIGINAL; + + /* When you see the packet, we need to NAT it the same as the + * this one (ie. same IP: it will be TCP and master is UDP). */ + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + exp->tuple.dst.u.tcp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + sprintf(buffer, "%u", port); + ret = nf_nat_mangle_udp_packet(pskb, exp->master, ctinfo, + matchoff, matchlen, + buffer, strlen(buffer)); + if (ret != NF_ACCEPT) + nf_conntrack_unexpect_related(exp); + return ret; +} + +static void __exit nf_nat_amanda_fini(void) +{ + rcu_assign_pointer(nf_nat_amanda_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_amanda_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_amanda_hook)); + rcu_assign_pointer(nf_nat_amanda_hook, help); + return 0; +} + +module_init(nf_nat_amanda_init); +module_exit(nf_nat_amanda_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index efe56f768f34..f85fd43b344b 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -131,6 +131,21 @@ config NF_CT_PROTO_SCTP If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +config NF_CONNTRACK_AMANDA + tristate "Amanda backup protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + select TEXTSEARCH + select TEXTSEARCH_KMP + help + If you are running the Amanda backup package + on this machine or machines that will be MASQUERADED through this + machine, then you may want to enable this feature. This allows the + connection tracking and natting code to allow the sub-channels that + Amanda requires for communication of the backup data, messages and + index. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CONNTRACK_FTP tristate "FTP support on new connection tracking (EXPERIMENTAL)" depends on EXPERIMENTAL && NF_CONNTRACK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 7f0089c584bf..a5ee93817427 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o # connection tracking helpers +obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o # generic X tables diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c new file mode 100644 index 000000000000..5c495dc9d942 --- /dev/null +++ b/net/netfilter/nf_conntrack_amanda.c @@ -0,0 +1,237 @@ +/* Amanda extension for IP connection tracking + * + * (C) 2002 by Brian J. Murrell + * based on HW's ip_conntrack_irc.c as well as other modules + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static unsigned int master_timeout __read_mostly = 300; +static char *ts_algo = "kmp"; + +MODULE_AUTHOR("Brian J. Murrell "); +MODULE_DESCRIPTION("Amanda connection tracking module"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_conntrack_amanda"); + +module_param(master_timeout, uint, 0600); +MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); +module_param(ts_algo, charp, 0400); +MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)"); + +unsigned int (*nf_nat_amanda_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp) + __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_amanda_hook); + +enum amanda_strings { + SEARCH_CONNECT, + SEARCH_NEWLINE, + SEARCH_DATA, + SEARCH_MESG, + SEARCH_INDEX, +}; + +static struct { + char *string; + size_t len; + struct ts_config *ts; +} search[] __read_mostly = { + [SEARCH_CONNECT] = { + .string = "CONNECT ", + .len = 8, + }, + [SEARCH_NEWLINE] = { + .string = "\n", + .len = 1, + }, + [SEARCH_DATA] = { + .string = "DATA ", + .len = 5, + }, + [SEARCH_MESG] = { + .string = "MESG ", + .len = 5, + }, + [SEARCH_INDEX] = { + .string = "INDEX ", + .len = 6, + }, +}; + +static int amanda_help(struct sk_buff **pskb, + unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct ts_state ts; + struct nf_conntrack_expect *exp; + struct nf_conntrack_tuple *tuple; + unsigned int dataoff, start, stop, off, i; + char pbuf[sizeof("65535")], *tmp; + u_int16_t len; + __be16 port; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + int ret = NF_ACCEPT; + typeof(nf_nat_amanda_hook) nf_nat_amanda; + + /* Only look at packets from the Amanda server */ + if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) + return NF_ACCEPT; + + /* increase the UDP timeout of the master connection as replies from + * Amanda clients to the server can be quite delayed */ + nf_ct_refresh(ct, *pskb, master_timeout * HZ); + + /* No data? */ + dataoff = protoff + sizeof(struct udphdr); + if (dataoff >= (*pskb)->len) { + if (net_ratelimit()) + printk("amanda_help: skblen = %u\n", (*pskb)->len); + return NF_ACCEPT; + } + + memset(&ts, 0, sizeof(ts)); + start = skb_find_text(*pskb, dataoff, (*pskb)->len, + search[SEARCH_CONNECT].ts, &ts); + if (start == UINT_MAX) + goto out; + start += dataoff + search[SEARCH_CONNECT].len; + + memset(&ts, 0, sizeof(ts)); + stop = skb_find_text(*pskb, start, (*pskb)->len, + search[SEARCH_NEWLINE].ts, &ts); + if (stop == UINT_MAX) + goto out; + stop += start; + + for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) { + memset(&ts, 0, sizeof(ts)); + off = skb_find_text(*pskb, start, stop, search[i].ts, &ts); + if (off == UINT_MAX) + continue; + off += start + search[i].len; + + len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off); + if (skb_copy_bits(*pskb, off, pbuf, len)) + break; + pbuf[len] = '\0'; + + port = htons(simple_strtoul(pbuf, &tmp, 10)); + len = tmp - pbuf; + if (port == 0 || len > 5) + break; + + exp = nf_conntrack_expect_alloc(ct); + if (exp == NULL) { + ret = NF_DROP; + goto out; + } + tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + nf_conntrack_expect_init(exp, family, + &tuple->src.u3, &tuple->dst.u3, + IPPROTO_TCP, NULL, &port); + + nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook); + if (nf_nat_amanda && ct->status & IPS_NAT_MASK) + ret = nf_nat_amanda(pskb, ctinfo, off - dataoff, + len, exp); + else if (nf_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + nf_conntrack_expect_put(exp); + } + +out: + return ret; +} + +static struct nf_conntrack_helper amanda_helper[2] __read_mostly = { + { + .name = "amanda", + .max_expected = 3, + .timeout = 180, + .me = THIS_MODULE, + .help = amanda_help, + .tuple.src.l3num = AF_INET, + .tuple.src.u.udp.port = __constant_htons(10080), + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + }, + { + .name = "amanda", + .max_expected = 3, + .timeout = 180, + .me = THIS_MODULE, + .help = amanda_help, + .tuple.src.l3num = AF_INET6, + .tuple.src.u.udp.port = __constant_htons(10080), + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + }, +}; + +static void __exit nf_conntrack_amanda_fini(void) +{ + int i; + + nf_conntrack_helper_unregister(&amanda_helper[0]); + nf_conntrack_helper_unregister(&amanda_helper[1]); + for (i = 0; i < ARRAY_SIZE(search); i++) + textsearch_destroy(search[i].ts); +} + +static int __init nf_conntrack_amanda_init(void) +{ + int ret, i; + + ret = -ENOMEM; + for (i = 0; i < ARRAY_SIZE(search); i++) { + search[i].ts = textsearch_prepare(ts_algo, search[i].string, + search[i].len, + GFP_KERNEL, TS_AUTOLOAD); + if (search[i].ts == NULL) + goto err1; + } + ret = nf_conntrack_helper_register(&amanda_helper[0]); + if (ret < 0) + goto err1; + ret = nf_conntrack_helper_register(&amanda_helper[1]); + if (ret < 0) + goto err2; + return 0; + +err2: + nf_conntrack_helper_unregister(&amanda_helper[0]); +err1: + for (; i >= 0; i--) { + if (search[i].ts) + textsearch_destroy(search[i].ts); + } + return ret; +} + +module_init(nf_conntrack_amanda_init); +module_exit(nf_conntrack_amanda_fini); -- cgit v1.2.3 From f587de0e2feb9eb9b94f98d0a7b7437e4d6617b4 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:08:46 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add H.323 helper port Add IPv4 and IPv6 capable nf_conntrack port of the H.323 conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_h323.h | 92 + include/linux/netfilter/nf_conntrack_h323_asn1.h | 98 + include/linux/netfilter/nf_conntrack_h323_types.h | 951 ++++++++++ include/linux/netfilter_ipv4/Kbuild | 2 - include/linux/netfilter_ipv4/ip_conntrack_h323.h | 2 +- .../netfilter_ipv4/ip_conntrack_helper_h323_asn1.h | 98 - .../ip_conntrack_helper_h323_types.h | 939 ---------- include/net/netfilter/nf_conntrack.h | 2 + include/net/netfilter/nf_conntrack_expect.h | 1 + net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 3 +- net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c | 874 --------- .../netfilter/ip_conntrack_helper_h323_types.c | 1926 ------------------- net/ipv4/netfilter/nf_nat_h323.c | 596 ++++++ net/netfilter/Kconfig | 19 + net/netfilter/Makefile | 3 + net/netfilter/nf_conntrack_h323_asn1.c | 874 +++++++++ net/netfilter/nf_conntrack_h323_main.c | 1856 +++++++++++++++++++ net/netfilter/nf_conntrack_h323_types.c | 1927 ++++++++++++++++++++ 19 files changed, 6427 insertions(+), 3841 deletions(-) create mode 100644 include/linux/netfilter/nf_conntrack_h323.h create mode 100644 include/linux/netfilter/nf_conntrack_h323_asn1.h create mode 100644 include/linux/netfilter/nf_conntrack_h323_types.h delete mode 100644 include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h delete mode 100644 include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h delete mode 100644 net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c delete mode 100644 net/ipv4/netfilter/ip_conntrack_helper_h323_types.c create mode 100644 net/ipv4/netfilter/nf_nat_h323.c create mode 100644 net/netfilter/nf_conntrack_h323_asn1.c create mode 100644 net/netfilter/nf_conntrack_h323_main.c create mode 100644 net/netfilter/nf_conntrack_h323_types.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_h323.h b/include/linux/netfilter/nf_conntrack_h323.h new file mode 100644 index 000000000000..08e2f4977c2e --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_h323.h @@ -0,0 +1,92 @@ +#ifndef _NF_CONNTRACK_H323_H +#define _NF_CONNTRACK_H323_H + +#ifdef __KERNEL__ + +#include + +#define RAS_PORT 1719 +#define Q931_PORT 1720 +#define H323_RTP_CHANNEL_MAX 4 /* Audio, video, FAX and other */ + +/* This structure exists only once per master */ +struct nf_ct_h323_master { + + /* Original and NATed Q.931 or H.245 signal ports */ + __be16 sig_port[IP_CT_DIR_MAX]; + + /* Original and NATed RTP ports */ + __be16 rtp_port[H323_RTP_CHANNEL_MAX][IP_CT_DIR_MAX]; + + union { + /* RAS connection timeout */ + u_int32_t timeout; + + /* Next TPKT length (for separate TPKT header and data) */ + u_int16_t tpkt_len[IP_CT_DIR_MAX]; + }; +}; + +struct nf_conn; + +extern int get_h225_addr(struct nf_conn *ct, unsigned char *data, + TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 *port); +extern void nf_conntrack_h245_expect(struct nf_conn *new, + struct nf_conntrack_expect *this); +extern void nf_conntrack_q931_expect(struct nf_conn *new, + struct nf_conntrack_expect *this); +extern int (*set_h245_addr_hook) (struct sk_buff **pskb, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + union nf_conntrack_address *addr, + __be16 port); +extern int (*set_h225_addr_hook) (struct sk_buff **pskb, + unsigned char **data, int dataoff, + TransportAddress *taddr, + union nf_conntrack_address *addr, + __be16 port); +extern int (*set_sig_addr_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count); +extern int (*set_ras_addr_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count); +extern int (*nat_rtp_rtcp_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + __be16 port, __be16 rtp_port, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp); +extern int (*nat_t120_hook) (struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp); +extern int (*nat_h245_hook) (struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp); +extern int (*nat_callforwarding_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, + __be16 port, + struct nf_conntrack_expect *exp); +extern int (*nat_q931_hook) (struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, TransportAddress *taddr, + int idx, __be16 port, + struct nf_conntrack_expect *exp); + +#endif + +#endif diff --git a/include/linux/netfilter/nf_conntrack_h323_asn1.h b/include/linux/netfilter/nf_conntrack_h323_asn1.h new file mode 100644 index 000000000000..8dab5968fc7e --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_h323_asn1.h @@ -0,0 +1,98 @@ +/**************************************************************************** + * ip_conntrack_h323_asn1.h - BER and PER decoding library for H.323 + * conntrack/NAT module. + * + * Copyright (c) 2006 by Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + * + * + * This library is based on H.225 version 4, H.235 version 2 and H.245 + * version 7. It is extremely optimized to decode only the absolutely + * necessary objects in a signal for Linux kernel NAT module use, so don't + * expect it to be a full ASN.1 library. + * + * Features: + * + * 1. Small. The total size of code plus data is less than 20 KB (IA32). + * 2. Fast. Decoding Netmeeting's Setup signal 1 million times on a PIII 866 + * takes only 3.9 seconds. + * 3. No memory allocation. It uses a static object. No need to initialize or + * cleanup. + * 4. Thread safe. + * 5. Support embedded architectures that has no misaligned memory access + * support. + * + * Limitations: + * + * 1. At most 30 faststart entries. Actually this is limited by ethernet's MTU. + * If a Setup signal contains more than 30 faststart, the packet size will + * very likely exceed the MTU size, then the TPKT will be fragmented. I + * don't know how to handle this in a Netfilter module. Anybody can help? + * Although I think 30 is enough for most of the cases. + * 2. IPv4 addresses only. + * + ****************************************************************************/ + +#ifndef _NF_CONNTRACK_HELPER_H323_ASN1_H_ +#define _NF_CONNTRACK_HELPER_H323_ASN1_H_ + +/***************************************************************************** + * H.323 Types + ****************************************************************************/ +#include "nf_conntrack_h323_types.h" + +typedef struct { + enum { + Q931_NationalEscape = 0x00, + Q931_Alerting = 0x01, + Q931_CallProceeding = 0x02, + Q931_Connect = 0x07, + Q931_ConnectAck = 0x0F, + Q931_Progress = 0x03, + Q931_Setup = 0x05, + Q931_SetupAck = 0x0D, + Q931_Resume = 0x26, + Q931_ResumeAck = 0x2E, + Q931_ResumeReject = 0x22, + Q931_Suspend = 0x25, + Q931_SuspendAck = 0x2D, + Q931_SuspendReject = 0x21, + Q931_UserInformation = 0x20, + Q931_Disconnect = 0x45, + Q931_Release = 0x4D, + Q931_ReleaseComplete = 0x5A, + Q931_Restart = 0x46, + Q931_RestartAck = 0x4E, + Q931_Segment = 0x60, + Q931_CongestionCtrl = 0x79, + Q931_Information = 0x7B, + Q931_Notify = 0x6E, + Q931_Status = 0x7D, + Q931_StatusEnquiry = 0x75, + Q931_Facility = 0x62 + } MessageType; + H323_UserInformation UUIE; +} Q931; + +/***************************************************************************** + * Decode Functions Return Codes + ****************************************************************************/ + +#define H323_ERROR_NONE 0 /* Decoded successfully */ +#define H323_ERROR_STOP 1 /* Decoding stopped, not really an error */ +#define H323_ERROR_BOUND -1 +#define H323_ERROR_RANGE -2 + + +/***************************************************************************** + * Decode Functions + ****************************************************************************/ + +int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras); +int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931); +int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, + MultimediaSystemControlMessage * + mscm); + +#endif diff --git a/include/linux/netfilter/nf_conntrack_h323_types.h b/include/linux/netfilter/nf_conntrack_h323_types.h new file mode 100644 index 000000000000..38d74d5c9700 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_h323_types.h @@ -0,0 +1,951 @@ +/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 + * + * Copyright (c) 2006 Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + */ + +typedef struct TransportAddress_ipAddress { /* SEQUENCE */ + int options; /* No use */ + unsigned ip; +} TransportAddress_ipAddress; + +typedef struct TransportAddress_ip6Address { /* SEQUENCE */ + int options; /* No use */ + unsigned ip6; +} TransportAddress_ip6Address; + +typedef struct TransportAddress { /* CHOICE */ + enum { + eTransportAddress_ipAddress, + eTransportAddress_ipSourceRoute, + eTransportAddress_ipxAddress, + eTransportAddress_ip6Address, + eTransportAddress_netBios, + eTransportAddress_nsap, + eTransportAddress_nonStandardAddress, + } choice; + union { + TransportAddress_ipAddress ipAddress; + TransportAddress_ip6Address ip6Address; + }; +} TransportAddress; + +typedef struct DataProtocolCapability { /* CHOICE */ + enum { + eDataProtocolCapability_nonStandard, + eDataProtocolCapability_v14buffered, + eDataProtocolCapability_v42lapm, + eDataProtocolCapability_hdlcFrameTunnelling, + eDataProtocolCapability_h310SeparateVCStack, + eDataProtocolCapability_h310SingleVCStack, + eDataProtocolCapability_transparent, + eDataProtocolCapability_segmentationAndReassembly, + eDataProtocolCapability_hdlcFrameTunnelingwSAR, + eDataProtocolCapability_v120, + eDataProtocolCapability_separateLANStack, + eDataProtocolCapability_v76wCompression, + eDataProtocolCapability_tcp, + eDataProtocolCapability_udp, + } choice; +} DataProtocolCapability; + +typedef struct DataApplicationCapability_application { /* CHOICE */ + enum { + eDataApplicationCapability_application_nonStandard, + eDataApplicationCapability_application_t120, + eDataApplicationCapability_application_dsm_cc, + eDataApplicationCapability_application_userData, + eDataApplicationCapability_application_t84, + eDataApplicationCapability_application_t434, + eDataApplicationCapability_application_h224, + eDataApplicationCapability_application_nlpid, + eDataApplicationCapability_application_dsvdControl, + eDataApplicationCapability_application_h222DataPartitioning, + eDataApplicationCapability_application_t30fax, + eDataApplicationCapability_application_t140, + eDataApplicationCapability_application_t38fax, + eDataApplicationCapability_application_genericDataCapability, + } choice; + union { + DataProtocolCapability t120; + }; +} DataApplicationCapability_application; + +typedef struct DataApplicationCapability { /* SEQUENCE */ + int options; /* No use */ + DataApplicationCapability_application application; +} DataApplicationCapability; + +typedef struct DataType { /* CHOICE */ + enum { + eDataType_nonStandard, + eDataType_nullData, + eDataType_videoData, + eDataType_audioData, + eDataType_data, + eDataType_encryptionData, + eDataType_h235Control, + eDataType_h235Media, + eDataType_multiplexedStream, + } choice; + union { + DataApplicationCapability data; + }; +} DataType; + +typedef struct UnicastAddress_iPAddress { /* SEQUENCE */ + int options; /* No use */ + unsigned network; +} UnicastAddress_iPAddress; + +typedef struct UnicastAddress_iP6Address { /* SEQUENCE */ + int options; /* No use */ + unsigned network; +} UnicastAddress_iP6Address; + +typedef struct UnicastAddress { /* CHOICE */ + enum { + eUnicastAddress_iPAddress, + eUnicastAddress_iPXAddress, + eUnicastAddress_iP6Address, + eUnicastAddress_netBios, + eUnicastAddress_iPSourceRouteAddress, + eUnicastAddress_nsap, + eUnicastAddress_nonStandardAddress, + } choice; + union { + UnicastAddress_iPAddress iPAddress; + UnicastAddress_iP6Address iP6Address; + }; +} UnicastAddress; + +typedef struct H245_TransportAddress { /* CHOICE */ + enum { + eH245_TransportAddress_unicastAddress, + eH245_TransportAddress_multicastAddress, + } choice; + union { + UnicastAddress unicastAddress; + }; +} H245_TransportAddress; + +typedef struct H2250LogicalChannelParameters { /* SEQUENCE */ + enum { + eH2250LogicalChannelParameters_nonStandard = (1 << 31), + eH2250LogicalChannelParameters_associatedSessionID = + (1 << 30), + eH2250LogicalChannelParameters_mediaChannel = (1 << 29), + eH2250LogicalChannelParameters_mediaGuaranteedDelivery = + (1 << 28), + eH2250LogicalChannelParameters_mediaControlChannel = + (1 << 27), + eH2250LogicalChannelParameters_mediaControlGuaranteedDelivery + = (1 << 26), + eH2250LogicalChannelParameters_silenceSuppression = (1 << 25), + eH2250LogicalChannelParameters_destination = (1 << 24), + eH2250LogicalChannelParameters_dynamicRTPPayloadType = + (1 << 23), + eH2250LogicalChannelParameters_mediaPacketization = (1 << 22), + eH2250LogicalChannelParameters_transportCapability = + (1 << 21), + eH2250LogicalChannelParameters_redundancyEncoding = (1 << 20), + eH2250LogicalChannelParameters_source = (1 << 19), + } options; + H245_TransportAddress mediaChannel; + H245_TransportAddress mediaControlChannel; +} H2250LogicalChannelParameters; + +typedef struct OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters { /* CHOICE */ + enum { + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters, + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_none, + } choice; + union { + H2250LogicalChannelParameters h2250LogicalChannelParameters; + }; +} OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters; + +typedef struct OpenLogicalChannel_forwardLogicalChannelParameters { /* SEQUENCE */ + enum { + eOpenLogicalChannel_forwardLogicalChannelParameters_portNumber + = (1 << 31), + eOpenLogicalChannel_forwardLogicalChannelParameters_forwardLogicalChannelDependency + = (1 << 30), + eOpenLogicalChannel_forwardLogicalChannelParameters_replacementFor + = (1 << 29), + } options; + DataType dataType; + OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters + multiplexParameters; +} OpenLogicalChannel_forwardLogicalChannelParameters; + +typedef struct OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ + enum { + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters, + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, + } choice; + union { + H2250LogicalChannelParameters h2250LogicalChannelParameters; + }; +} OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters; + +typedef struct OpenLogicalChannel_reverseLogicalChannelParameters { /* SEQUENCE */ + enum { + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters + = (1 << 31), + eOpenLogicalChannel_reverseLogicalChannelParameters_reverseLogicalChannelDependency + = (1 << 30), + eOpenLogicalChannel_reverseLogicalChannelParameters_replacementFor + = (1 << 29), + } options; + OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters + multiplexParameters; +} OpenLogicalChannel_reverseLogicalChannelParameters; + +typedef struct NetworkAccessParameters_networkAddress { /* CHOICE */ + enum { + eNetworkAccessParameters_networkAddress_q2931Address, + eNetworkAccessParameters_networkAddress_e164Address, + eNetworkAccessParameters_networkAddress_localAreaAddress, + } choice; + union { + H245_TransportAddress localAreaAddress; + }; +} NetworkAccessParameters_networkAddress; + +typedef struct NetworkAccessParameters { /* SEQUENCE */ + enum { + eNetworkAccessParameters_distribution = (1 << 31), + eNetworkAccessParameters_externalReference = (1 << 30), + eNetworkAccessParameters_t120SetupProcedure = (1 << 29), + } options; + NetworkAccessParameters_networkAddress networkAddress; +} NetworkAccessParameters; + +typedef struct OpenLogicalChannel { /* SEQUENCE */ + enum { + eOpenLogicalChannel_reverseLogicalChannelParameters = + (1 << 31), + eOpenLogicalChannel_separateStack = (1 << 30), + eOpenLogicalChannel_encryptionSync = (1 << 29), + } options; + OpenLogicalChannel_forwardLogicalChannelParameters + forwardLogicalChannelParameters; + OpenLogicalChannel_reverseLogicalChannelParameters + reverseLogicalChannelParameters; + NetworkAccessParameters separateStack; +} OpenLogicalChannel; + +typedef struct Setup_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Setup_UUIE_fastStart; + +typedef struct Setup_UUIE { /* SEQUENCE */ + enum { + eSetup_UUIE_h245Address = (1 << 31), + eSetup_UUIE_sourceAddress = (1 << 30), + eSetup_UUIE_destinationAddress = (1 << 29), + eSetup_UUIE_destCallSignalAddress = (1 << 28), + eSetup_UUIE_destExtraCallInfo = (1 << 27), + eSetup_UUIE_destExtraCRV = (1 << 26), + eSetup_UUIE_callServices = (1 << 25), + eSetup_UUIE_sourceCallSignalAddress = (1 << 24), + eSetup_UUIE_remoteExtensionAddress = (1 << 23), + eSetup_UUIE_callIdentifier = (1 << 22), + eSetup_UUIE_h245SecurityCapability = (1 << 21), + eSetup_UUIE_tokens = (1 << 20), + eSetup_UUIE_cryptoTokens = (1 << 19), + eSetup_UUIE_fastStart = (1 << 18), + eSetup_UUIE_mediaWaitForConnect = (1 << 17), + eSetup_UUIE_canOverlapSend = (1 << 16), + eSetup_UUIE_endpointIdentifier = (1 << 15), + eSetup_UUIE_multipleCalls = (1 << 14), + eSetup_UUIE_maintainConnection = (1 << 13), + eSetup_UUIE_connectionParameters = (1 << 12), + eSetup_UUIE_language = (1 << 11), + eSetup_UUIE_presentationIndicator = (1 << 10), + eSetup_UUIE_screeningIndicator = (1 << 9), + eSetup_UUIE_serviceControl = (1 << 8), + eSetup_UUIE_symmetricOperationRequired = (1 << 7), + eSetup_UUIE_capacity = (1 << 6), + eSetup_UUIE_circuitInfo = (1 << 5), + eSetup_UUIE_desiredProtocols = (1 << 4), + eSetup_UUIE_neededFeatures = (1 << 3), + eSetup_UUIE_desiredFeatures = (1 << 2), + eSetup_UUIE_supportedFeatures = (1 << 1), + eSetup_UUIE_parallelH245Control = (1 << 0), + } options; + TransportAddress h245Address; + TransportAddress destCallSignalAddress; + TransportAddress sourceCallSignalAddress; + Setup_UUIE_fastStart fastStart; +} Setup_UUIE; + +typedef struct CallProceeding_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} CallProceeding_UUIE_fastStart; + +typedef struct CallProceeding_UUIE { /* SEQUENCE */ + enum { + eCallProceeding_UUIE_h245Address = (1 << 31), + eCallProceeding_UUIE_callIdentifier = (1 << 30), + eCallProceeding_UUIE_h245SecurityMode = (1 << 29), + eCallProceeding_UUIE_tokens = (1 << 28), + eCallProceeding_UUIE_cryptoTokens = (1 << 27), + eCallProceeding_UUIE_fastStart = (1 << 26), + eCallProceeding_UUIE_multipleCalls = (1 << 25), + eCallProceeding_UUIE_maintainConnection = (1 << 24), + eCallProceeding_UUIE_fastConnectRefused = (1 << 23), + eCallProceeding_UUIE_featureSet = (1 << 22), + } options; + TransportAddress h245Address; + CallProceeding_UUIE_fastStart fastStart; +} CallProceeding_UUIE; + +typedef struct Connect_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Connect_UUIE_fastStart; + +typedef struct Connect_UUIE { /* SEQUENCE */ + enum { + eConnect_UUIE_h245Address = (1 << 31), + eConnect_UUIE_callIdentifier = (1 << 30), + eConnect_UUIE_h245SecurityMode = (1 << 29), + eConnect_UUIE_tokens = (1 << 28), + eConnect_UUIE_cryptoTokens = (1 << 27), + eConnect_UUIE_fastStart = (1 << 26), + eConnect_UUIE_multipleCalls = (1 << 25), + eConnect_UUIE_maintainConnection = (1 << 24), + eConnect_UUIE_language = (1 << 23), + eConnect_UUIE_connectedAddress = (1 << 22), + eConnect_UUIE_presentationIndicator = (1 << 21), + eConnect_UUIE_screeningIndicator = (1 << 20), + eConnect_UUIE_fastConnectRefused = (1 << 19), + eConnect_UUIE_serviceControl = (1 << 18), + eConnect_UUIE_capacity = (1 << 17), + eConnect_UUIE_featureSet = (1 << 16), + } options; + TransportAddress h245Address; + Connect_UUIE_fastStart fastStart; +} Connect_UUIE; + +typedef struct Alerting_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Alerting_UUIE_fastStart; + +typedef struct Alerting_UUIE { /* SEQUENCE */ + enum { + eAlerting_UUIE_h245Address = (1 << 31), + eAlerting_UUIE_callIdentifier = (1 << 30), + eAlerting_UUIE_h245SecurityMode = (1 << 29), + eAlerting_UUIE_tokens = (1 << 28), + eAlerting_UUIE_cryptoTokens = (1 << 27), + eAlerting_UUIE_fastStart = (1 << 26), + eAlerting_UUIE_multipleCalls = (1 << 25), + eAlerting_UUIE_maintainConnection = (1 << 24), + eAlerting_UUIE_alertingAddress = (1 << 23), + eAlerting_UUIE_presentationIndicator = (1 << 22), + eAlerting_UUIE_screeningIndicator = (1 << 21), + eAlerting_UUIE_fastConnectRefused = (1 << 20), + eAlerting_UUIE_serviceControl = (1 << 19), + eAlerting_UUIE_capacity = (1 << 18), + eAlerting_UUIE_featureSet = (1 << 17), + } options; + TransportAddress h245Address; + Alerting_UUIE_fastStart fastStart; +} Alerting_UUIE; + +typedef struct Information_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Information_UUIE_fastStart; + +typedef struct Information_UUIE { /* SEQUENCE */ + enum { + eInformation_UUIE_callIdentifier = (1 << 31), + eInformation_UUIE_tokens = (1 << 30), + eInformation_UUIE_cryptoTokens = (1 << 29), + eInformation_UUIE_fastStart = (1 << 28), + eInformation_UUIE_fastConnectRefused = (1 << 27), + eInformation_UUIE_circuitInfo = (1 << 26), + } options; + Information_UUIE_fastStart fastStart; +} Information_UUIE; + +typedef struct FacilityReason { /* CHOICE */ + enum { + eFacilityReason_routeCallToGatekeeper, + eFacilityReason_callForwarded, + eFacilityReason_routeCallToMC, + eFacilityReason_undefinedReason, + eFacilityReason_conferenceListChoice, + eFacilityReason_startH245, + eFacilityReason_noH245, + eFacilityReason_newTokens, + eFacilityReason_featureSetUpdate, + eFacilityReason_forwardedElements, + eFacilityReason_transportedInformation, + } choice; +} FacilityReason; + +typedef struct Facility_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Facility_UUIE_fastStart; + +typedef struct Facility_UUIE { /* SEQUENCE */ + enum { + eFacility_UUIE_alternativeAddress = (1 << 31), + eFacility_UUIE_alternativeAliasAddress = (1 << 30), + eFacility_UUIE_conferenceID = (1 << 29), + eFacility_UUIE_callIdentifier = (1 << 28), + eFacility_UUIE_destExtraCallInfo = (1 << 27), + eFacility_UUIE_remoteExtensionAddress = (1 << 26), + eFacility_UUIE_tokens = (1 << 25), + eFacility_UUIE_cryptoTokens = (1 << 24), + eFacility_UUIE_conferences = (1 << 23), + eFacility_UUIE_h245Address = (1 << 22), + eFacility_UUIE_fastStart = (1 << 21), + eFacility_UUIE_multipleCalls = (1 << 20), + eFacility_UUIE_maintainConnection = (1 << 19), + eFacility_UUIE_fastConnectRefused = (1 << 18), + eFacility_UUIE_serviceControl = (1 << 17), + eFacility_UUIE_circuitInfo = (1 << 16), + eFacility_UUIE_featureSet = (1 << 15), + eFacility_UUIE_destinationInfo = (1 << 14), + eFacility_UUIE_h245SecurityMode = (1 << 13), + } options; + TransportAddress alternativeAddress; + FacilityReason reason; + TransportAddress h245Address; + Facility_UUIE_fastStart fastStart; +} Facility_UUIE; + +typedef struct Progress_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Progress_UUIE_fastStart; + +typedef struct Progress_UUIE { /* SEQUENCE */ + enum { + eProgress_UUIE_h245Address = (1 << 31), + eProgress_UUIE_h245SecurityMode = (1 << 30), + eProgress_UUIE_tokens = (1 << 29), + eProgress_UUIE_cryptoTokens = (1 << 28), + eProgress_UUIE_fastStart = (1 << 27), + eProgress_UUIE_multipleCalls = (1 << 26), + eProgress_UUIE_maintainConnection = (1 << 25), + eProgress_UUIE_fastConnectRefused = (1 << 24), + } options; + TransportAddress h245Address; + Progress_UUIE_fastStart fastStart; +} Progress_UUIE; + +typedef struct H323_UU_PDU_h323_message_body { /* CHOICE */ + enum { + eH323_UU_PDU_h323_message_body_setup, + eH323_UU_PDU_h323_message_body_callProceeding, + eH323_UU_PDU_h323_message_body_connect, + eH323_UU_PDU_h323_message_body_alerting, + eH323_UU_PDU_h323_message_body_information, + eH323_UU_PDU_h323_message_body_releaseComplete, + eH323_UU_PDU_h323_message_body_facility, + eH323_UU_PDU_h323_message_body_progress, + eH323_UU_PDU_h323_message_body_empty, + eH323_UU_PDU_h323_message_body_status, + eH323_UU_PDU_h323_message_body_statusInquiry, + eH323_UU_PDU_h323_message_body_setupAcknowledge, + eH323_UU_PDU_h323_message_body_notify, + } choice; + union { + Setup_UUIE setup; + CallProceeding_UUIE callProceeding; + Connect_UUIE connect; + Alerting_UUIE alerting; + Information_UUIE information; + Facility_UUIE facility; + Progress_UUIE progress; + }; +} H323_UU_PDU_h323_message_body; + +typedef struct RequestMessage { /* CHOICE */ + enum { + eRequestMessage_nonStandard, + eRequestMessage_masterSlaveDetermination, + eRequestMessage_terminalCapabilitySet, + eRequestMessage_openLogicalChannel, + eRequestMessage_closeLogicalChannel, + eRequestMessage_requestChannelClose, + eRequestMessage_multiplexEntrySend, + eRequestMessage_requestMultiplexEntry, + eRequestMessage_requestMode, + eRequestMessage_roundTripDelayRequest, + eRequestMessage_maintenanceLoopRequest, + eRequestMessage_communicationModeRequest, + eRequestMessage_conferenceRequest, + eRequestMessage_multilinkRequest, + eRequestMessage_logicalChannelRateRequest, + } choice; + union { + OpenLogicalChannel openLogicalChannel; + }; +} RequestMessage; + +typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ + enum { + eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, + eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, + } choice; + union { + H2250LogicalChannelParameters h2250LogicalChannelParameters; + }; +} OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters; + +typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters { /* SEQUENCE */ + enum { + eOpenLogicalChannelAck_reverseLogicalChannelParameters_portNumber + = (1 << 31), + eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters + = (1 << 30), + eOpenLogicalChannelAck_reverseLogicalChannelParameters_replacementFor + = (1 << 29), + } options; + OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters + multiplexParameters; +} OpenLogicalChannelAck_reverseLogicalChannelParameters; + +typedef struct H2250LogicalChannelAckParameters { /* SEQUENCE */ + enum { + eH2250LogicalChannelAckParameters_nonStandard = (1 << 31), + eH2250LogicalChannelAckParameters_sessionID = (1 << 30), + eH2250LogicalChannelAckParameters_mediaChannel = (1 << 29), + eH2250LogicalChannelAckParameters_mediaControlChannel = + (1 << 28), + eH2250LogicalChannelAckParameters_dynamicRTPPayloadType = + (1 << 27), + eH2250LogicalChannelAckParameters_flowControlToZero = + (1 << 26), + eH2250LogicalChannelAckParameters_portNumber = (1 << 25), + } options; + H245_TransportAddress mediaChannel; + H245_TransportAddress mediaControlChannel; +} H2250LogicalChannelAckParameters; + +typedef struct OpenLogicalChannelAck_forwardMultiplexAckParameters { /* CHOICE */ + enum { + eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters, + } choice; + union { + H2250LogicalChannelAckParameters + h2250LogicalChannelAckParameters; + }; +} OpenLogicalChannelAck_forwardMultiplexAckParameters; + +typedef struct OpenLogicalChannelAck { /* SEQUENCE */ + enum { + eOpenLogicalChannelAck_reverseLogicalChannelParameters = + (1 << 31), + eOpenLogicalChannelAck_separateStack = (1 << 30), + eOpenLogicalChannelAck_forwardMultiplexAckParameters = + (1 << 29), + eOpenLogicalChannelAck_encryptionSync = (1 << 28), + } options; + OpenLogicalChannelAck_reverseLogicalChannelParameters + reverseLogicalChannelParameters; + OpenLogicalChannelAck_forwardMultiplexAckParameters + forwardMultiplexAckParameters; +} OpenLogicalChannelAck; + +typedef struct ResponseMessage { /* CHOICE */ + enum { + eResponseMessage_nonStandard, + eResponseMessage_masterSlaveDeterminationAck, + eResponseMessage_masterSlaveDeterminationReject, + eResponseMessage_terminalCapabilitySetAck, + eResponseMessage_terminalCapabilitySetReject, + eResponseMessage_openLogicalChannelAck, + eResponseMessage_openLogicalChannelReject, + eResponseMessage_closeLogicalChannelAck, + eResponseMessage_requestChannelCloseAck, + eResponseMessage_requestChannelCloseReject, + eResponseMessage_multiplexEntrySendAck, + eResponseMessage_multiplexEntrySendReject, + eResponseMessage_requestMultiplexEntryAck, + eResponseMessage_requestMultiplexEntryReject, + eResponseMessage_requestModeAck, + eResponseMessage_requestModeReject, + eResponseMessage_roundTripDelayResponse, + eResponseMessage_maintenanceLoopAck, + eResponseMessage_maintenanceLoopReject, + eResponseMessage_communicationModeResponse, + eResponseMessage_conferenceResponse, + eResponseMessage_multilinkResponse, + eResponseMessage_logicalChannelRateAcknowledge, + eResponseMessage_logicalChannelRateReject, + } choice; + union { + OpenLogicalChannelAck openLogicalChannelAck; + }; +} ResponseMessage; + +typedef struct MultimediaSystemControlMessage { /* CHOICE */ + enum { + eMultimediaSystemControlMessage_request, + eMultimediaSystemControlMessage_response, + eMultimediaSystemControlMessage_command, + eMultimediaSystemControlMessage_indication, + } choice; + union { + RequestMessage request; + ResponseMessage response; + }; +} MultimediaSystemControlMessage; + +typedef struct H323_UU_PDU_h245Control { /* SEQUENCE OF */ + int count; + MultimediaSystemControlMessage item[4]; +} H323_UU_PDU_h245Control; + +typedef struct H323_UU_PDU { /* SEQUENCE */ + enum { + eH323_UU_PDU_nonStandardData = (1 << 31), + eH323_UU_PDU_h4501SupplementaryService = (1 << 30), + eH323_UU_PDU_h245Tunneling = (1 << 29), + eH323_UU_PDU_h245Control = (1 << 28), + eH323_UU_PDU_nonStandardControl = (1 << 27), + eH323_UU_PDU_callLinkage = (1 << 26), + eH323_UU_PDU_tunnelledSignallingMessage = (1 << 25), + eH323_UU_PDU_provisionalRespToH245Tunneling = (1 << 24), + eH323_UU_PDU_stimulusControl = (1 << 23), + eH323_UU_PDU_genericData = (1 << 22), + } options; + H323_UU_PDU_h323_message_body h323_message_body; + H323_UU_PDU_h245Control h245Control; +} H323_UU_PDU; + +typedef struct H323_UserInformation { /* SEQUENCE */ + enum { + eH323_UserInformation_user_data = (1 << 31), + } options; + H323_UU_PDU h323_uu_pdu; +} H323_UserInformation; + +typedef struct GatekeeperRequest { /* SEQUENCE */ + enum { + eGatekeeperRequest_nonStandardData = (1 << 31), + eGatekeeperRequest_gatekeeperIdentifier = (1 << 30), + eGatekeeperRequest_callServices = (1 << 29), + eGatekeeperRequest_endpointAlias = (1 << 28), + eGatekeeperRequest_alternateEndpoints = (1 << 27), + eGatekeeperRequest_tokens = (1 << 26), + eGatekeeperRequest_cryptoTokens = (1 << 25), + eGatekeeperRequest_authenticationCapability = (1 << 24), + eGatekeeperRequest_algorithmOIDs = (1 << 23), + eGatekeeperRequest_integrity = (1 << 22), + eGatekeeperRequest_integrityCheckValue = (1 << 21), + eGatekeeperRequest_supportsAltGK = (1 << 20), + eGatekeeperRequest_featureSet = (1 << 19), + eGatekeeperRequest_genericData = (1 << 18), + } options; + TransportAddress rasAddress; +} GatekeeperRequest; + +typedef struct GatekeeperConfirm { /* SEQUENCE */ + enum { + eGatekeeperConfirm_nonStandardData = (1 << 31), + eGatekeeperConfirm_gatekeeperIdentifier = (1 << 30), + eGatekeeperConfirm_alternateGatekeeper = (1 << 29), + eGatekeeperConfirm_authenticationMode = (1 << 28), + eGatekeeperConfirm_tokens = (1 << 27), + eGatekeeperConfirm_cryptoTokens = (1 << 26), + eGatekeeperConfirm_algorithmOID = (1 << 25), + eGatekeeperConfirm_integrity = (1 << 24), + eGatekeeperConfirm_integrityCheckValue = (1 << 23), + eGatekeeperConfirm_featureSet = (1 << 22), + eGatekeeperConfirm_genericData = (1 << 21), + } options; + TransportAddress rasAddress; +} GatekeeperConfirm; + +typedef struct RegistrationRequest_callSignalAddress { /* SEQUENCE OF */ + int count; + TransportAddress item[10]; +} RegistrationRequest_callSignalAddress; + +typedef struct RegistrationRequest_rasAddress { /* SEQUENCE OF */ + int count; + TransportAddress item[10]; +} RegistrationRequest_rasAddress; + +typedef struct RegistrationRequest { /* SEQUENCE */ + enum { + eRegistrationRequest_nonStandardData = (1 << 31), + eRegistrationRequest_terminalAlias = (1 << 30), + eRegistrationRequest_gatekeeperIdentifier = (1 << 29), + eRegistrationRequest_alternateEndpoints = (1 << 28), + eRegistrationRequest_timeToLive = (1 << 27), + eRegistrationRequest_tokens = (1 << 26), + eRegistrationRequest_cryptoTokens = (1 << 25), + eRegistrationRequest_integrityCheckValue = (1 << 24), + eRegistrationRequest_keepAlive = (1 << 23), + eRegistrationRequest_endpointIdentifier = (1 << 22), + eRegistrationRequest_willSupplyUUIEs = (1 << 21), + eRegistrationRequest_maintainConnection = (1 << 20), + eRegistrationRequest_alternateTransportAddresses = (1 << 19), + eRegistrationRequest_additiveRegistration = (1 << 18), + eRegistrationRequest_terminalAliasPattern = (1 << 17), + eRegistrationRequest_supportsAltGK = (1 << 16), + eRegistrationRequest_usageReportingCapability = (1 << 15), + eRegistrationRequest_multipleCalls = (1 << 14), + eRegistrationRequest_supportedH248Packages = (1 << 13), + eRegistrationRequest_callCreditCapability = (1 << 12), + eRegistrationRequest_capacityReportingCapability = (1 << 11), + eRegistrationRequest_capacity = (1 << 10), + eRegistrationRequest_featureSet = (1 << 9), + eRegistrationRequest_genericData = (1 << 8), + } options; + RegistrationRequest_callSignalAddress callSignalAddress; + RegistrationRequest_rasAddress rasAddress; + unsigned timeToLive; +} RegistrationRequest; + +typedef struct RegistrationConfirm_callSignalAddress { /* SEQUENCE OF */ + int count; + TransportAddress item[10]; +} RegistrationConfirm_callSignalAddress; + +typedef struct RegistrationConfirm { /* SEQUENCE */ + enum { + eRegistrationConfirm_nonStandardData = (1 << 31), + eRegistrationConfirm_terminalAlias = (1 << 30), + eRegistrationConfirm_gatekeeperIdentifier = (1 << 29), + eRegistrationConfirm_alternateGatekeeper = (1 << 28), + eRegistrationConfirm_timeToLive = (1 << 27), + eRegistrationConfirm_tokens = (1 << 26), + eRegistrationConfirm_cryptoTokens = (1 << 25), + eRegistrationConfirm_integrityCheckValue = (1 << 24), + eRegistrationConfirm_willRespondToIRR = (1 << 23), + eRegistrationConfirm_preGrantedARQ = (1 << 22), + eRegistrationConfirm_maintainConnection = (1 << 21), + eRegistrationConfirm_serviceControl = (1 << 20), + eRegistrationConfirm_supportsAdditiveRegistration = (1 << 19), + eRegistrationConfirm_terminalAliasPattern = (1 << 18), + eRegistrationConfirm_supportedPrefixes = (1 << 17), + eRegistrationConfirm_usageSpec = (1 << 16), + eRegistrationConfirm_featureServerAlias = (1 << 15), + eRegistrationConfirm_capacityReportingSpec = (1 << 14), + eRegistrationConfirm_featureSet = (1 << 13), + eRegistrationConfirm_genericData = (1 << 12), + } options; + RegistrationConfirm_callSignalAddress callSignalAddress; + unsigned timeToLive; +} RegistrationConfirm; + +typedef struct UnregistrationRequest_callSignalAddress { /* SEQUENCE OF */ + int count; + TransportAddress item[10]; +} UnregistrationRequest_callSignalAddress; + +typedef struct UnregistrationRequest { /* SEQUENCE */ + enum { + eUnregistrationRequest_endpointAlias = (1 << 31), + eUnregistrationRequest_nonStandardData = (1 << 30), + eUnregistrationRequest_endpointIdentifier = (1 << 29), + eUnregistrationRequest_alternateEndpoints = (1 << 28), + eUnregistrationRequest_gatekeeperIdentifier = (1 << 27), + eUnregistrationRequest_tokens = (1 << 26), + eUnregistrationRequest_cryptoTokens = (1 << 25), + eUnregistrationRequest_integrityCheckValue = (1 << 24), + eUnregistrationRequest_reason = (1 << 23), + eUnregistrationRequest_endpointAliasPattern = (1 << 22), + eUnregistrationRequest_supportedPrefixes = (1 << 21), + eUnregistrationRequest_alternateGatekeeper = (1 << 20), + eUnregistrationRequest_genericData = (1 << 19), + } options; + UnregistrationRequest_callSignalAddress callSignalAddress; +} UnregistrationRequest; + +typedef struct AdmissionRequest { /* SEQUENCE */ + enum { + eAdmissionRequest_callModel = (1 << 31), + eAdmissionRequest_destinationInfo = (1 << 30), + eAdmissionRequest_destCallSignalAddress = (1 << 29), + eAdmissionRequest_destExtraCallInfo = (1 << 28), + eAdmissionRequest_srcCallSignalAddress = (1 << 27), + eAdmissionRequest_nonStandardData = (1 << 26), + eAdmissionRequest_callServices = (1 << 25), + eAdmissionRequest_canMapAlias = (1 << 24), + eAdmissionRequest_callIdentifier = (1 << 23), + eAdmissionRequest_srcAlternatives = (1 << 22), + eAdmissionRequest_destAlternatives = (1 << 21), + eAdmissionRequest_gatekeeperIdentifier = (1 << 20), + eAdmissionRequest_tokens = (1 << 19), + eAdmissionRequest_cryptoTokens = (1 << 18), + eAdmissionRequest_integrityCheckValue = (1 << 17), + eAdmissionRequest_transportQOS = (1 << 16), + eAdmissionRequest_willSupplyUUIEs = (1 << 15), + eAdmissionRequest_callLinkage = (1 << 14), + eAdmissionRequest_gatewayDataRate = (1 << 13), + eAdmissionRequest_capacity = (1 << 12), + eAdmissionRequest_circuitInfo = (1 << 11), + eAdmissionRequest_desiredProtocols = (1 << 10), + eAdmissionRequest_desiredTunnelledProtocol = (1 << 9), + eAdmissionRequest_featureSet = (1 << 8), + eAdmissionRequest_genericData = (1 << 7), + } options; + TransportAddress destCallSignalAddress; + TransportAddress srcCallSignalAddress; +} AdmissionRequest; + +typedef struct AdmissionConfirm { /* SEQUENCE */ + enum { + eAdmissionConfirm_irrFrequency = (1 << 31), + eAdmissionConfirm_nonStandardData = (1 << 30), + eAdmissionConfirm_destinationInfo = (1 << 29), + eAdmissionConfirm_destExtraCallInfo = (1 << 28), + eAdmissionConfirm_destinationType = (1 << 27), + eAdmissionConfirm_remoteExtensionAddress = (1 << 26), + eAdmissionConfirm_alternateEndpoints = (1 << 25), + eAdmissionConfirm_tokens = (1 << 24), + eAdmissionConfirm_cryptoTokens = (1 << 23), + eAdmissionConfirm_integrityCheckValue = (1 << 22), + eAdmissionConfirm_transportQOS = (1 << 21), + eAdmissionConfirm_willRespondToIRR = (1 << 20), + eAdmissionConfirm_uuiesRequested = (1 << 19), + eAdmissionConfirm_language = (1 << 18), + eAdmissionConfirm_alternateTransportAddresses = (1 << 17), + eAdmissionConfirm_useSpecifiedTransport = (1 << 16), + eAdmissionConfirm_circuitInfo = (1 << 15), + eAdmissionConfirm_usageSpec = (1 << 14), + eAdmissionConfirm_supportedProtocols = (1 << 13), + eAdmissionConfirm_serviceControl = (1 << 12), + eAdmissionConfirm_multipleCalls = (1 << 11), + eAdmissionConfirm_featureSet = (1 << 10), + eAdmissionConfirm_genericData = (1 << 9), + } options; + TransportAddress destCallSignalAddress; +} AdmissionConfirm; + +typedef struct LocationRequest { /* SEQUENCE */ + enum { + eLocationRequest_endpointIdentifier = (1 << 31), + eLocationRequest_nonStandardData = (1 << 30), + eLocationRequest_sourceInfo = (1 << 29), + eLocationRequest_canMapAlias = (1 << 28), + eLocationRequest_gatekeeperIdentifier = (1 << 27), + eLocationRequest_tokens = (1 << 26), + eLocationRequest_cryptoTokens = (1 << 25), + eLocationRequest_integrityCheckValue = (1 << 24), + eLocationRequest_desiredProtocols = (1 << 23), + eLocationRequest_desiredTunnelledProtocol = (1 << 22), + eLocationRequest_featureSet = (1 << 21), + eLocationRequest_genericData = (1 << 20), + eLocationRequest_hopCount = (1 << 19), + eLocationRequest_circuitInfo = (1 << 18), + } options; + TransportAddress replyAddress; +} LocationRequest; + +typedef struct LocationConfirm { /* SEQUENCE */ + enum { + eLocationConfirm_nonStandardData = (1 << 31), + eLocationConfirm_destinationInfo = (1 << 30), + eLocationConfirm_destExtraCallInfo = (1 << 29), + eLocationConfirm_destinationType = (1 << 28), + eLocationConfirm_remoteExtensionAddress = (1 << 27), + eLocationConfirm_alternateEndpoints = (1 << 26), + eLocationConfirm_tokens = (1 << 25), + eLocationConfirm_cryptoTokens = (1 << 24), + eLocationConfirm_integrityCheckValue = (1 << 23), + eLocationConfirm_alternateTransportAddresses = (1 << 22), + eLocationConfirm_supportedProtocols = (1 << 21), + eLocationConfirm_multipleCalls = (1 << 20), + eLocationConfirm_featureSet = (1 << 19), + eLocationConfirm_genericData = (1 << 18), + eLocationConfirm_circuitInfo = (1 << 17), + eLocationConfirm_serviceControl = (1 << 16), + } options; + TransportAddress callSignalAddress; + TransportAddress rasAddress; +} LocationConfirm; + +typedef struct InfoRequestResponse_callSignalAddress { /* SEQUENCE OF */ + int count; + TransportAddress item[10]; +} InfoRequestResponse_callSignalAddress; + +typedef struct InfoRequestResponse { /* SEQUENCE */ + enum { + eInfoRequestResponse_nonStandardData = (1 << 31), + eInfoRequestResponse_endpointAlias = (1 << 30), + eInfoRequestResponse_perCallInfo = (1 << 29), + eInfoRequestResponse_tokens = (1 << 28), + eInfoRequestResponse_cryptoTokens = (1 << 27), + eInfoRequestResponse_integrityCheckValue = (1 << 26), + eInfoRequestResponse_needResponse = (1 << 25), + eInfoRequestResponse_capacity = (1 << 24), + eInfoRequestResponse_irrStatus = (1 << 23), + eInfoRequestResponse_unsolicited = (1 << 22), + eInfoRequestResponse_genericData = (1 << 21), + } options; + TransportAddress rasAddress; + InfoRequestResponse_callSignalAddress callSignalAddress; +} InfoRequestResponse; + +typedef struct RasMessage { /* CHOICE */ + enum { + eRasMessage_gatekeeperRequest, + eRasMessage_gatekeeperConfirm, + eRasMessage_gatekeeperReject, + eRasMessage_registrationRequest, + eRasMessage_registrationConfirm, + eRasMessage_registrationReject, + eRasMessage_unregistrationRequest, + eRasMessage_unregistrationConfirm, + eRasMessage_unregistrationReject, + eRasMessage_admissionRequest, + eRasMessage_admissionConfirm, + eRasMessage_admissionReject, + eRasMessage_bandwidthRequest, + eRasMessage_bandwidthConfirm, + eRasMessage_bandwidthReject, + eRasMessage_disengageRequest, + eRasMessage_disengageConfirm, + eRasMessage_disengageReject, + eRasMessage_locationRequest, + eRasMessage_locationConfirm, + eRasMessage_locationReject, + eRasMessage_infoRequest, + eRasMessage_infoRequestResponse, + eRasMessage_nonStandardMessage, + eRasMessage_unknownMessageResponse, + eRasMessage_requestInProgress, + eRasMessage_resourcesAvailableIndicate, + eRasMessage_resourcesAvailableConfirm, + eRasMessage_infoRequestAck, + eRasMessage_infoRequestNak, + eRasMessage_serviceControlIndication, + eRasMessage_serviceControlResponse, + } choice; + union { + GatekeeperRequest gatekeeperRequest; + GatekeeperConfirm gatekeeperConfirm; + RegistrationRequest registrationRequest; + RegistrationConfirm registrationConfirm; + UnregistrationRequest unregistrationRequest; + AdmissionRequest admissionRequest; + AdmissionConfirm admissionConfirm; + LocationRequest locationRequest; + LocationConfirm locationConfirm; + InfoRequestResponse infoRequestResponse; + }; +} RasMessage; diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild index 591c1a809c00..180337801a86 100644 --- a/include/linux/netfilter_ipv4/Kbuild +++ b/include/linux/netfilter_ipv4/Kbuild @@ -1,6 +1,4 @@ header-y += ip_conntrack_helper.h -header-y += ip_conntrack_helper_h323_asn1.h -header-y += ip_conntrack_helper_h323_types.h header-y += ip_conntrack_protocol.h header-y += ip_conntrack_sctp.h header-y += ip_conntrack_tcp.h diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h index 943cc6a4871d..18f769818f4e 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h @@ -3,7 +3,7 @@ #ifdef __KERNEL__ -#include +#include #define RAS_PORT 1719 #define Q931_PORT 1720 diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h deleted file mode 100644 index c6e9a0b6d30b..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** - * ip_conntrack_helper_h323_asn1.h - BER and PER decoding library for H.323 - * conntrack/NAT module. - * - * Copyright (c) 2006 by Jing Min Zhao - * - * This source code is licensed under General Public License version 2. - * - * - * This library is based on H.225 version 4, H.235 version 2 and H.245 - * version 7. It is extremely optimized to decode only the absolutely - * necessary objects in a signal for Linux kernel NAT module use, so don't - * expect it to be a full ASN.1 library. - * - * Features: - * - * 1. Small. The total size of code plus data is less than 20 KB (IA32). - * 2. Fast. Decoding Netmeeting's Setup signal 1 million times on a PIII 866 - * takes only 3.9 seconds. - * 3. No memory allocation. It uses a static object. No need to initialize or - * cleanup. - * 4. Thread safe. - * 5. Support embedded architectures that has no misaligned memory access - * support. - * - * Limitations: - * - * 1. At most 30 faststart entries. Actually this is limited by ethernet's MTU. - * If a Setup signal contains more than 30 faststart, the packet size will - * very likely exceed the MTU size, then the TPKT will be fragmented. I - * don't know how to handle this in a Netfilter module. Anybody can help? - * Although I think 30 is enough for most of the cases. - * 2. IPv4 addresses only. - * - ****************************************************************************/ - -#ifndef _IP_CONNTRACK_HELPER_H323_ASN1_H_ -#define _IP_CONNTRACK_HELPER_H323_ASN1_H_ - -/***************************************************************************** - * H.323 Types - ****************************************************************************/ -#include "ip_conntrack_helper_h323_types.h" - -typedef struct { - enum { - Q931_NationalEscape = 0x00, - Q931_Alerting = 0x01, - Q931_CallProceeding = 0x02, - Q931_Connect = 0x07, - Q931_ConnectAck = 0x0F, - Q931_Progress = 0x03, - Q931_Setup = 0x05, - Q931_SetupAck = 0x0D, - Q931_Resume = 0x26, - Q931_ResumeAck = 0x2E, - Q931_ResumeReject = 0x22, - Q931_Suspend = 0x25, - Q931_SuspendAck = 0x2D, - Q931_SuspendReject = 0x21, - Q931_UserInformation = 0x20, - Q931_Disconnect = 0x45, - Q931_Release = 0x4D, - Q931_ReleaseComplete = 0x5A, - Q931_Restart = 0x46, - Q931_RestartAck = 0x4E, - Q931_Segment = 0x60, - Q931_CongestionCtrl = 0x79, - Q931_Information = 0x7B, - Q931_Notify = 0x6E, - Q931_Status = 0x7D, - Q931_StatusEnquiry = 0x75, - Q931_Facility = 0x62 - } MessageType; - H323_UserInformation UUIE; -} Q931; - -/***************************************************************************** - * Decode Functions Return Codes - ****************************************************************************/ - -#define H323_ERROR_NONE 0 /* Decoded successfully */ -#define H323_ERROR_STOP 1 /* Decoding stopped, not really an error */ -#define H323_ERROR_BOUND -1 -#define H323_ERROR_RANGE -2 - - -/***************************************************************************** - * Decode Functions - ****************************************************************************/ - -int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras); -int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931); -int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, - MultimediaSystemControlMessage * - mscm); - -#endif diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h deleted file mode 100644 index 3d4a773799fc..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h +++ /dev/null @@ -1,939 +0,0 @@ -/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 - * - * Copyright (c) 2006 Jing Min Zhao - * - * This source code is licensed under General Public License version 2. - */ - -typedef struct TransportAddress_ipAddress { /* SEQUENCE */ - int options; /* No use */ - unsigned ip; -} TransportAddress_ipAddress; - -typedef struct TransportAddress { /* CHOICE */ - enum { - eTransportAddress_ipAddress, - eTransportAddress_ipSourceRoute, - eTransportAddress_ipxAddress, - eTransportAddress_ip6Address, - eTransportAddress_netBios, - eTransportAddress_nsap, - eTransportAddress_nonStandardAddress, - } choice; - union { - TransportAddress_ipAddress ipAddress; - }; -} TransportAddress; - -typedef struct DataProtocolCapability { /* CHOICE */ - enum { - eDataProtocolCapability_nonStandard, - eDataProtocolCapability_v14buffered, - eDataProtocolCapability_v42lapm, - eDataProtocolCapability_hdlcFrameTunnelling, - eDataProtocolCapability_h310SeparateVCStack, - eDataProtocolCapability_h310SingleVCStack, - eDataProtocolCapability_transparent, - eDataProtocolCapability_segmentationAndReassembly, - eDataProtocolCapability_hdlcFrameTunnelingwSAR, - eDataProtocolCapability_v120, - eDataProtocolCapability_separateLANStack, - eDataProtocolCapability_v76wCompression, - eDataProtocolCapability_tcp, - eDataProtocolCapability_udp, - } choice; -} DataProtocolCapability; - -typedef struct DataApplicationCapability_application { /* CHOICE */ - enum { - eDataApplicationCapability_application_nonStandard, - eDataApplicationCapability_application_t120, - eDataApplicationCapability_application_dsm_cc, - eDataApplicationCapability_application_userData, - eDataApplicationCapability_application_t84, - eDataApplicationCapability_application_t434, - eDataApplicationCapability_application_h224, - eDataApplicationCapability_application_nlpid, - eDataApplicationCapability_application_dsvdControl, - eDataApplicationCapability_application_h222DataPartitioning, - eDataApplicationCapability_application_t30fax, - eDataApplicationCapability_application_t140, - eDataApplicationCapability_application_t38fax, - eDataApplicationCapability_application_genericDataCapability, - } choice; - union { - DataProtocolCapability t120; - }; -} DataApplicationCapability_application; - -typedef struct DataApplicationCapability { /* SEQUENCE */ - int options; /* No use */ - DataApplicationCapability_application application; -} DataApplicationCapability; - -typedef struct DataType { /* CHOICE */ - enum { - eDataType_nonStandard, - eDataType_nullData, - eDataType_videoData, - eDataType_audioData, - eDataType_data, - eDataType_encryptionData, - eDataType_h235Control, - eDataType_h235Media, - eDataType_multiplexedStream, - } choice; - union { - DataApplicationCapability data; - }; -} DataType; - -typedef struct UnicastAddress_iPAddress { /* SEQUENCE */ - int options; /* No use */ - unsigned network; -} UnicastAddress_iPAddress; - -typedef struct UnicastAddress { /* CHOICE */ - enum { - eUnicastAddress_iPAddress, - eUnicastAddress_iPXAddress, - eUnicastAddress_iP6Address, - eUnicastAddress_netBios, - eUnicastAddress_iPSourceRouteAddress, - eUnicastAddress_nsap, - eUnicastAddress_nonStandardAddress, - } choice; - union { - UnicastAddress_iPAddress iPAddress; - }; -} UnicastAddress; - -typedef struct H245_TransportAddress { /* CHOICE */ - enum { - eH245_TransportAddress_unicastAddress, - eH245_TransportAddress_multicastAddress, - } choice; - union { - UnicastAddress unicastAddress; - }; -} H245_TransportAddress; - -typedef struct H2250LogicalChannelParameters { /* SEQUENCE */ - enum { - eH2250LogicalChannelParameters_nonStandard = (1 << 31), - eH2250LogicalChannelParameters_associatedSessionID = - (1 << 30), - eH2250LogicalChannelParameters_mediaChannel = (1 << 29), - eH2250LogicalChannelParameters_mediaGuaranteedDelivery = - (1 << 28), - eH2250LogicalChannelParameters_mediaControlChannel = - (1 << 27), - eH2250LogicalChannelParameters_mediaControlGuaranteedDelivery - = (1 << 26), - eH2250LogicalChannelParameters_silenceSuppression = (1 << 25), - eH2250LogicalChannelParameters_destination = (1 << 24), - eH2250LogicalChannelParameters_dynamicRTPPayloadType = - (1 << 23), - eH2250LogicalChannelParameters_mediaPacketization = (1 << 22), - eH2250LogicalChannelParameters_transportCapability = - (1 << 21), - eH2250LogicalChannelParameters_redundancyEncoding = (1 << 20), - eH2250LogicalChannelParameters_source = (1 << 19), - } options; - H245_TransportAddress mediaChannel; - H245_TransportAddress mediaControlChannel; -} H2250LogicalChannelParameters; - -typedef struct OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters { /* CHOICE */ - enum { - eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, - eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters, - eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, - eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, - eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_none, - } choice; - union { - H2250LogicalChannelParameters h2250LogicalChannelParameters; - }; -} OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters; - -typedef struct OpenLogicalChannel_forwardLogicalChannelParameters { /* SEQUENCE */ - enum { - eOpenLogicalChannel_forwardLogicalChannelParameters_portNumber - = (1 << 31), - eOpenLogicalChannel_forwardLogicalChannelParameters_forwardLogicalChannelDependency - = (1 << 30), - eOpenLogicalChannel_forwardLogicalChannelParameters_replacementFor - = (1 << 29), - } options; - DataType dataType; - OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters - multiplexParameters; -} OpenLogicalChannel_forwardLogicalChannelParameters; - -typedef struct OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ - enum { - eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters, - eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, - eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, - } choice; - union { - H2250LogicalChannelParameters h2250LogicalChannelParameters; - }; -} OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters; - -typedef struct OpenLogicalChannel_reverseLogicalChannelParameters { /* SEQUENCE */ - enum { - eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters - = (1 << 31), - eOpenLogicalChannel_reverseLogicalChannelParameters_reverseLogicalChannelDependency - = (1 << 30), - eOpenLogicalChannel_reverseLogicalChannelParameters_replacementFor - = (1 << 29), - } options; - OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters - multiplexParameters; -} OpenLogicalChannel_reverseLogicalChannelParameters; - -typedef struct NetworkAccessParameters_networkAddress { /* CHOICE */ - enum { - eNetworkAccessParameters_networkAddress_q2931Address, - eNetworkAccessParameters_networkAddress_e164Address, - eNetworkAccessParameters_networkAddress_localAreaAddress, - } choice; - union { - H245_TransportAddress localAreaAddress; - }; -} NetworkAccessParameters_networkAddress; - -typedef struct NetworkAccessParameters { /* SEQUENCE */ - enum { - eNetworkAccessParameters_distribution = (1 << 31), - eNetworkAccessParameters_externalReference = (1 << 30), - eNetworkAccessParameters_t120SetupProcedure = (1 << 29), - } options; - NetworkAccessParameters_networkAddress networkAddress; -} NetworkAccessParameters; - -typedef struct OpenLogicalChannel { /* SEQUENCE */ - enum { - eOpenLogicalChannel_reverseLogicalChannelParameters = - (1 << 31), - eOpenLogicalChannel_separateStack = (1 << 30), - eOpenLogicalChannel_encryptionSync = (1 << 29), - } options; - OpenLogicalChannel_forwardLogicalChannelParameters - forwardLogicalChannelParameters; - OpenLogicalChannel_reverseLogicalChannelParameters - reverseLogicalChannelParameters; - NetworkAccessParameters separateStack; -} OpenLogicalChannel; - -typedef struct Setup_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Setup_UUIE_fastStart; - -typedef struct Setup_UUIE { /* SEQUENCE */ - enum { - eSetup_UUIE_h245Address = (1 << 31), - eSetup_UUIE_sourceAddress = (1 << 30), - eSetup_UUIE_destinationAddress = (1 << 29), - eSetup_UUIE_destCallSignalAddress = (1 << 28), - eSetup_UUIE_destExtraCallInfo = (1 << 27), - eSetup_UUIE_destExtraCRV = (1 << 26), - eSetup_UUIE_callServices = (1 << 25), - eSetup_UUIE_sourceCallSignalAddress = (1 << 24), - eSetup_UUIE_remoteExtensionAddress = (1 << 23), - eSetup_UUIE_callIdentifier = (1 << 22), - eSetup_UUIE_h245SecurityCapability = (1 << 21), - eSetup_UUIE_tokens = (1 << 20), - eSetup_UUIE_cryptoTokens = (1 << 19), - eSetup_UUIE_fastStart = (1 << 18), - eSetup_UUIE_mediaWaitForConnect = (1 << 17), - eSetup_UUIE_canOverlapSend = (1 << 16), - eSetup_UUIE_endpointIdentifier = (1 << 15), - eSetup_UUIE_multipleCalls = (1 << 14), - eSetup_UUIE_maintainConnection = (1 << 13), - eSetup_UUIE_connectionParameters = (1 << 12), - eSetup_UUIE_language = (1 << 11), - eSetup_UUIE_presentationIndicator = (1 << 10), - eSetup_UUIE_screeningIndicator = (1 << 9), - eSetup_UUIE_serviceControl = (1 << 8), - eSetup_UUIE_symmetricOperationRequired = (1 << 7), - eSetup_UUIE_capacity = (1 << 6), - eSetup_UUIE_circuitInfo = (1 << 5), - eSetup_UUIE_desiredProtocols = (1 << 4), - eSetup_UUIE_neededFeatures = (1 << 3), - eSetup_UUIE_desiredFeatures = (1 << 2), - eSetup_UUIE_supportedFeatures = (1 << 1), - eSetup_UUIE_parallelH245Control = (1 << 0), - } options; - TransportAddress h245Address; - TransportAddress destCallSignalAddress; - TransportAddress sourceCallSignalAddress; - Setup_UUIE_fastStart fastStart; -} Setup_UUIE; - -typedef struct CallProceeding_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} CallProceeding_UUIE_fastStart; - -typedef struct CallProceeding_UUIE { /* SEQUENCE */ - enum { - eCallProceeding_UUIE_h245Address = (1 << 31), - eCallProceeding_UUIE_callIdentifier = (1 << 30), - eCallProceeding_UUIE_h245SecurityMode = (1 << 29), - eCallProceeding_UUIE_tokens = (1 << 28), - eCallProceeding_UUIE_cryptoTokens = (1 << 27), - eCallProceeding_UUIE_fastStart = (1 << 26), - eCallProceeding_UUIE_multipleCalls = (1 << 25), - eCallProceeding_UUIE_maintainConnection = (1 << 24), - eCallProceeding_UUIE_fastConnectRefused = (1 << 23), - eCallProceeding_UUIE_featureSet = (1 << 22), - } options; - TransportAddress h245Address; - CallProceeding_UUIE_fastStart fastStart; -} CallProceeding_UUIE; - -typedef struct Connect_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Connect_UUIE_fastStart; - -typedef struct Connect_UUIE { /* SEQUENCE */ - enum { - eConnect_UUIE_h245Address = (1 << 31), - eConnect_UUIE_callIdentifier = (1 << 30), - eConnect_UUIE_h245SecurityMode = (1 << 29), - eConnect_UUIE_tokens = (1 << 28), - eConnect_UUIE_cryptoTokens = (1 << 27), - eConnect_UUIE_fastStart = (1 << 26), - eConnect_UUIE_multipleCalls = (1 << 25), - eConnect_UUIE_maintainConnection = (1 << 24), - eConnect_UUIE_language = (1 << 23), - eConnect_UUIE_connectedAddress = (1 << 22), - eConnect_UUIE_presentationIndicator = (1 << 21), - eConnect_UUIE_screeningIndicator = (1 << 20), - eConnect_UUIE_fastConnectRefused = (1 << 19), - eConnect_UUIE_serviceControl = (1 << 18), - eConnect_UUIE_capacity = (1 << 17), - eConnect_UUIE_featureSet = (1 << 16), - } options; - TransportAddress h245Address; - Connect_UUIE_fastStart fastStart; -} Connect_UUIE; - -typedef struct Alerting_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Alerting_UUIE_fastStart; - -typedef struct Alerting_UUIE { /* SEQUENCE */ - enum { - eAlerting_UUIE_h245Address = (1 << 31), - eAlerting_UUIE_callIdentifier = (1 << 30), - eAlerting_UUIE_h245SecurityMode = (1 << 29), - eAlerting_UUIE_tokens = (1 << 28), - eAlerting_UUIE_cryptoTokens = (1 << 27), - eAlerting_UUIE_fastStart = (1 << 26), - eAlerting_UUIE_multipleCalls = (1 << 25), - eAlerting_UUIE_maintainConnection = (1 << 24), - eAlerting_UUIE_alertingAddress = (1 << 23), - eAlerting_UUIE_presentationIndicator = (1 << 22), - eAlerting_UUIE_screeningIndicator = (1 << 21), - eAlerting_UUIE_fastConnectRefused = (1 << 20), - eAlerting_UUIE_serviceControl = (1 << 19), - eAlerting_UUIE_capacity = (1 << 18), - eAlerting_UUIE_featureSet = (1 << 17), - } options; - TransportAddress h245Address; - Alerting_UUIE_fastStart fastStart; -} Alerting_UUIE; - -typedef struct Information_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Information_UUIE_fastStart; - -typedef struct Information_UUIE { /* SEQUENCE */ - enum { - eInformation_UUIE_callIdentifier = (1 << 31), - eInformation_UUIE_tokens = (1 << 30), - eInformation_UUIE_cryptoTokens = (1 << 29), - eInformation_UUIE_fastStart = (1 << 28), - eInformation_UUIE_fastConnectRefused = (1 << 27), - eInformation_UUIE_circuitInfo = (1 << 26), - } options; - Information_UUIE_fastStart fastStart; -} Information_UUIE; - -typedef struct FacilityReason { /* CHOICE */ - enum { - eFacilityReason_routeCallToGatekeeper, - eFacilityReason_callForwarded, - eFacilityReason_routeCallToMC, - eFacilityReason_undefinedReason, - eFacilityReason_conferenceListChoice, - eFacilityReason_startH245, - eFacilityReason_noH245, - eFacilityReason_newTokens, - eFacilityReason_featureSetUpdate, - eFacilityReason_forwardedElements, - eFacilityReason_transportedInformation, - } choice; -} FacilityReason; - -typedef struct Facility_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Facility_UUIE_fastStart; - -typedef struct Facility_UUIE { /* SEQUENCE */ - enum { - eFacility_UUIE_alternativeAddress = (1 << 31), - eFacility_UUIE_alternativeAliasAddress = (1 << 30), - eFacility_UUIE_conferenceID = (1 << 29), - eFacility_UUIE_callIdentifier = (1 << 28), - eFacility_UUIE_destExtraCallInfo = (1 << 27), - eFacility_UUIE_remoteExtensionAddress = (1 << 26), - eFacility_UUIE_tokens = (1 << 25), - eFacility_UUIE_cryptoTokens = (1 << 24), - eFacility_UUIE_conferences = (1 << 23), - eFacility_UUIE_h245Address = (1 << 22), - eFacility_UUIE_fastStart = (1 << 21), - eFacility_UUIE_multipleCalls = (1 << 20), - eFacility_UUIE_maintainConnection = (1 << 19), - eFacility_UUIE_fastConnectRefused = (1 << 18), - eFacility_UUIE_serviceControl = (1 << 17), - eFacility_UUIE_circuitInfo = (1 << 16), - eFacility_UUIE_featureSet = (1 << 15), - eFacility_UUIE_destinationInfo = (1 << 14), - eFacility_UUIE_h245SecurityMode = (1 << 13), - } options; - TransportAddress alternativeAddress; - FacilityReason reason; - TransportAddress h245Address; - Facility_UUIE_fastStart fastStart; -} Facility_UUIE; - -typedef struct Progress_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Progress_UUIE_fastStart; - -typedef struct Progress_UUIE { /* SEQUENCE */ - enum { - eProgress_UUIE_h245Address = (1 << 31), - eProgress_UUIE_h245SecurityMode = (1 << 30), - eProgress_UUIE_tokens = (1 << 29), - eProgress_UUIE_cryptoTokens = (1 << 28), - eProgress_UUIE_fastStart = (1 << 27), - eProgress_UUIE_multipleCalls = (1 << 26), - eProgress_UUIE_maintainConnection = (1 << 25), - eProgress_UUIE_fastConnectRefused = (1 << 24), - } options; - TransportAddress h245Address; - Progress_UUIE_fastStart fastStart; -} Progress_UUIE; - -typedef struct H323_UU_PDU_h323_message_body { /* CHOICE */ - enum { - eH323_UU_PDU_h323_message_body_setup, - eH323_UU_PDU_h323_message_body_callProceeding, - eH323_UU_PDU_h323_message_body_connect, - eH323_UU_PDU_h323_message_body_alerting, - eH323_UU_PDU_h323_message_body_information, - eH323_UU_PDU_h323_message_body_releaseComplete, - eH323_UU_PDU_h323_message_body_facility, - eH323_UU_PDU_h323_message_body_progress, - eH323_UU_PDU_h323_message_body_empty, - eH323_UU_PDU_h323_message_body_status, - eH323_UU_PDU_h323_message_body_statusInquiry, - eH323_UU_PDU_h323_message_body_setupAcknowledge, - eH323_UU_PDU_h323_message_body_notify, - } choice; - union { - Setup_UUIE setup; - CallProceeding_UUIE callProceeding; - Connect_UUIE connect; - Alerting_UUIE alerting; - Information_UUIE information; - Facility_UUIE facility; - Progress_UUIE progress; - }; -} H323_UU_PDU_h323_message_body; - -typedef struct RequestMessage { /* CHOICE */ - enum { - eRequestMessage_nonStandard, - eRequestMessage_masterSlaveDetermination, - eRequestMessage_terminalCapabilitySet, - eRequestMessage_openLogicalChannel, - eRequestMessage_closeLogicalChannel, - eRequestMessage_requestChannelClose, - eRequestMessage_multiplexEntrySend, - eRequestMessage_requestMultiplexEntry, - eRequestMessage_requestMode, - eRequestMessage_roundTripDelayRequest, - eRequestMessage_maintenanceLoopRequest, - eRequestMessage_communicationModeRequest, - eRequestMessage_conferenceRequest, - eRequestMessage_multilinkRequest, - eRequestMessage_logicalChannelRateRequest, - } choice; - union { - OpenLogicalChannel openLogicalChannel; - }; -} RequestMessage; - -typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ - enum { - eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, - eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, - } choice; - union { - H2250LogicalChannelParameters h2250LogicalChannelParameters; - }; -} OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters; - -typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters { /* SEQUENCE */ - enum { - eOpenLogicalChannelAck_reverseLogicalChannelParameters_portNumber - = (1 << 31), - eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters - = (1 << 30), - eOpenLogicalChannelAck_reverseLogicalChannelParameters_replacementFor - = (1 << 29), - } options; - OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters - multiplexParameters; -} OpenLogicalChannelAck_reverseLogicalChannelParameters; - -typedef struct H2250LogicalChannelAckParameters { /* SEQUENCE */ - enum { - eH2250LogicalChannelAckParameters_nonStandard = (1 << 31), - eH2250LogicalChannelAckParameters_sessionID = (1 << 30), - eH2250LogicalChannelAckParameters_mediaChannel = (1 << 29), - eH2250LogicalChannelAckParameters_mediaControlChannel = - (1 << 28), - eH2250LogicalChannelAckParameters_dynamicRTPPayloadType = - (1 << 27), - eH2250LogicalChannelAckParameters_flowControlToZero = - (1 << 26), - eH2250LogicalChannelAckParameters_portNumber = (1 << 25), - } options; - H245_TransportAddress mediaChannel; - H245_TransportAddress mediaControlChannel; -} H2250LogicalChannelAckParameters; - -typedef struct OpenLogicalChannelAck_forwardMultiplexAckParameters { /* CHOICE */ - enum { - eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters, - } choice; - union { - H2250LogicalChannelAckParameters - h2250LogicalChannelAckParameters; - }; -} OpenLogicalChannelAck_forwardMultiplexAckParameters; - -typedef struct OpenLogicalChannelAck { /* SEQUENCE */ - enum { - eOpenLogicalChannelAck_reverseLogicalChannelParameters = - (1 << 31), - eOpenLogicalChannelAck_separateStack = (1 << 30), - eOpenLogicalChannelAck_forwardMultiplexAckParameters = - (1 << 29), - eOpenLogicalChannelAck_encryptionSync = (1 << 28), - } options; - OpenLogicalChannelAck_reverseLogicalChannelParameters - reverseLogicalChannelParameters; - OpenLogicalChannelAck_forwardMultiplexAckParameters - forwardMultiplexAckParameters; -} OpenLogicalChannelAck; - -typedef struct ResponseMessage { /* CHOICE */ - enum { - eResponseMessage_nonStandard, - eResponseMessage_masterSlaveDeterminationAck, - eResponseMessage_masterSlaveDeterminationReject, - eResponseMessage_terminalCapabilitySetAck, - eResponseMessage_terminalCapabilitySetReject, - eResponseMessage_openLogicalChannelAck, - eResponseMessage_openLogicalChannelReject, - eResponseMessage_closeLogicalChannelAck, - eResponseMessage_requestChannelCloseAck, - eResponseMessage_requestChannelCloseReject, - eResponseMessage_multiplexEntrySendAck, - eResponseMessage_multiplexEntrySendReject, - eResponseMessage_requestMultiplexEntryAck, - eResponseMessage_requestMultiplexEntryReject, - eResponseMessage_requestModeAck, - eResponseMessage_requestModeReject, - eResponseMessage_roundTripDelayResponse, - eResponseMessage_maintenanceLoopAck, - eResponseMessage_maintenanceLoopReject, - eResponseMessage_communicationModeResponse, - eResponseMessage_conferenceResponse, - eResponseMessage_multilinkResponse, - eResponseMessage_logicalChannelRateAcknowledge, - eResponseMessage_logicalChannelRateReject, - } choice; - union { - OpenLogicalChannelAck openLogicalChannelAck; - }; -} ResponseMessage; - -typedef struct MultimediaSystemControlMessage { /* CHOICE */ - enum { - eMultimediaSystemControlMessage_request, - eMultimediaSystemControlMessage_response, - eMultimediaSystemControlMessage_command, - eMultimediaSystemControlMessage_indication, - } choice; - union { - RequestMessage request; - ResponseMessage response; - }; -} MultimediaSystemControlMessage; - -typedef struct H323_UU_PDU_h245Control { /* SEQUENCE OF */ - int count; - MultimediaSystemControlMessage item[4]; -} H323_UU_PDU_h245Control; - -typedef struct H323_UU_PDU { /* SEQUENCE */ - enum { - eH323_UU_PDU_nonStandardData = (1 << 31), - eH323_UU_PDU_h4501SupplementaryService = (1 << 30), - eH323_UU_PDU_h245Tunneling = (1 << 29), - eH323_UU_PDU_h245Control = (1 << 28), - eH323_UU_PDU_nonStandardControl = (1 << 27), - eH323_UU_PDU_callLinkage = (1 << 26), - eH323_UU_PDU_tunnelledSignallingMessage = (1 << 25), - eH323_UU_PDU_provisionalRespToH245Tunneling = (1 << 24), - eH323_UU_PDU_stimulusControl = (1 << 23), - eH323_UU_PDU_genericData = (1 << 22), - } options; - H323_UU_PDU_h323_message_body h323_message_body; - H323_UU_PDU_h245Control h245Control; -} H323_UU_PDU; - -typedef struct H323_UserInformation { /* SEQUENCE */ - enum { - eH323_UserInformation_user_data = (1 << 31), - } options; - H323_UU_PDU h323_uu_pdu; -} H323_UserInformation; - -typedef struct GatekeeperRequest { /* SEQUENCE */ - enum { - eGatekeeperRequest_nonStandardData = (1 << 31), - eGatekeeperRequest_gatekeeperIdentifier = (1 << 30), - eGatekeeperRequest_callServices = (1 << 29), - eGatekeeperRequest_endpointAlias = (1 << 28), - eGatekeeperRequest_alternateEndpoints = (1 << 27), - eGatekeeperRequest_tokens = (1 << 26), - eGatekeeperRequest_cryptoTokens = (1 << 25), - eGatekeeperRequest_authenticationCapability = (1 << 24), - eGatekeeperRequest_algorithmOIDs = (1 << 23), - eGatekeeperRequest_integrity = (1 << 22), - eGatekeeperRequest_integrityCheckValue = (1 << 21), - eGatekeeperRequest_supportsAltGK = (1 << 20), - eGatekeeperRequest_featureSet = (1 << 19), - eGatekeeperRequest_genericData = (1 << 18), - } options; - TransportAddress rasAddress; -} GatekeeperRequest; - -typedef struct GatekeeperConfirm { /* SEQUENCE */ - enum { - eGatekeeperConfirm_nonStandardData = (1 << 31), - eGatekeeperConfirm_gatekeeperIdentifier = (1 << 30), - eGatekeeperConfirm_alternateGatekeeper = (1 << 29), - eGatekeeperConfirm_authenticationMode = (1 << 28), - eGatekeeperConfirm_tokens = (1 << 27), - eGatekeeperConfirm_cryptoTokens = (1 << 26), - eGatekeeperConfirm_algorithmOID = (1 << 25), - eGatekeeperConfirm_integrity = (1 << 24), - eGatekeeperConfirm_integrityCheckValue = (1 << 23), - eGatekeeperConfirm_featureSet = (1 << 22), - eGatekeeperConfirm_genericData = (1 << 21), - } options; - TransportAddress rasAddress; -} GatekeeperConfirm; - -typedef struct RegistrationRequest_callSignalAddress { /* SEQUENCE OF */ - int count; - TransportAddress item[10]; -} RegistrationRequest_callSignalAddress; - -typedef struct RegistrationRequest_rasAddress { /* SEQUENCE OF */ - int count; - TransportAddress item[10]; -} RegistrationRequest_rasAddress; - -typedef struct RegistrationRequest { /* SEQUENCE */ - enum { - eRegistrationRequest_nonStandardData = (1 << 31), - eRegistrationRequest_terminalAlias = (1 << 30), - eRegistrationRequest_gatekeeperIdentifier = (1 << 29), - eRegistrationRequest_alternateEndpoints = (1 << 28), - eRegistrationRequest_timeToLive = (1 << 27), - eRegistrationRequest_tokens = (1 << 26), - eRegistrationRequest_cryptoTokens = (1 << 25), - eRegistrationRequest_integrityCheckValue = (1 << 24), - eRegistrationRequest_keepAlive = (1 << 23), - eRegistrationRequest_endpointIdentifier = (1 << 22), - eRegistrationRequest_willSupplyUUIEs = (1 << 21), - eRegistrationRequest_maintainConnection = (1 << 20), - eRegistrationRequest_alternateTransportAddresses = (1 << 19), - eRegistrationRequest_additiveRegistration = (1 << 18), - eRegistrationRequest_terminalAliasPattern = (1 << 17), - eRegistrationRequest_supportsAltGK = (1 << 16), - eRegistrationRequest_usageReportingCapability = (1 << 15), - eRegistrationRequest_multipleCalls = (1 << 14), - eRegistrationRequest_supportedH248Packages = (1 << 13), - eRegistrationRequest_callCreditCapability = (1 << 12), - eRegistrationRequest_capacityReportingCapability = (1 << 11), - eRegistrationRequest_capacity = (1 << 10), - eRegistrationRequest_featureSet = (1 << 9), - eRegistrationRequest_genericData = (1 << 8), - } options; - RegistrationRequest_callSignalAddress callSignalAddress; - RegistrationRequest_rasAddress rasAddress; - unsigned timeToLive; -} RegistrationRequest; - -typedef struct RegistrationConfirm_callSignalAddress { /* SEQUENCE OF */ - int count; - TransportAddress item[10]; -} RegistrationConfirm_callSignalAddress; - -typedef struct RegistrationConfirm { /* SEQUENCE */ - enum { - eRegistrationConfirm_nonStandardData = (1 << 31), - eRegistrationConfirm_terminalAlias = (1 << 30), - eRegistrationConfirm_gatekeeperIdentifier = (1 << 29), - eRegistrationConfirm_alternateGatekeeper = (1 << 28), - eRegistrationConfirm_timeToLive = (1 << 27), - eRegistrationConfirm_tokens = (1 << 26), - eRegistrationConfirm_cryptoTokens = (1 << 25), - eRegistrationConfirm_integrityCheckValue = (1 << 24), - eRegistrationConfirm_willRespondToIRR = (1 << 23), - eRegistrationConfirm_preGrantedARQ = (1 << 22), - eRegistrationConfirm_maintainConnection = (1 << 21), - eRegistrationConfirm_serviceControl = (1 << 20), - eRegistrationConfirm_supportsAdditiveRegistration = (1 << 19), - eRegistrationConfirm_terminalAliasPattern = (1 << 18), - eRegistrationConfirm_supportedPrefixes = (1 << 17), - eRegistrationConfirm_usageSpec = (1 << 16), - eRegistrationConfirm_featureServerAlias = (1 << 15), - eRegistrationConfirm_capacityReportingSpec = (1 << 14), - eRegistrationConfirm_featureSet = (1 << 13), - eRegistrationConfirm_genericData = (1 << 12), - } options; - RegistrationConfirm_callSignalAddress callSignalAddress; - unsigned timeToLive; -} RegistrationConfirm; - -typedef struct UnregistrationRequest_callSignalAddress { /* SEQUENCE OF */ - int count; - TransportAddress item[10]; -} UnregistrationRequest_callSignalAddress; - -typedef struct UnregistrationRequest { /* SEQUENCE */ - enum { - eUnregistrationRequest_endpointAlias = (1 << 31), - eUnregistrationRequest_nonStandardData = (1 << 30), - eUnregistrationRequest_endpointIdentifier = (1 << 29), - eUnregistrationRequest_alternateEndpoints = (1 << 28), - eUnregistrationRequest_gatekeeperIdentifier = (1 << 27), - eUnregistrationRequest_tokens = (1 << 26), - eUnregistrationRequest_cryptoTokens = (1 << 25), - eUnregistrationRequest_integrityCheckValue = (1 << 24), - eUnregistrationRequest_reason = (1 << 23), - eUnregistrationRequest_endpointAliasPattern = (1 << 22), - eUnregistrationRequest_supportedPrefixes = (1 << 21), - eUnregistrationRequest_alternateGatekeeper = (1 << 20), - eUnregistrationRequest_genericData = (1 << 19), - } options; - UnregistrationRequest_callSignalAddress callSignalAddress; -} UnregistrationRequest; - -typedef struct AdmissionRequest { /* SEQUENCE */ - enum { - eAdmissionRequest_callModel = (1 << 31), - eAdmissionRequest_destinationInfo = (1 << 30), - eAdmissionRequest_destCallSignalAddress = (1 << 29), - eAdmissionRequest_destExtraCallInfo = (1 << 28), - eAdmissionRequest_srcCallSignalAddress = (1 << 27), - eAdmissionRequest_nonStandardData = (1 << 26), - eAdmissionRequest_callServices = (1 << 25), - eAdmissionRequest_canMapAlias = (1 << 24), - eAdmissionRequest_callIdentifier = (1 << 23), - eAdmissionRequest_srcAlternatives = (1 << 22), - eAdmissionRequest_destAlternatives = (1 << 21), - eAdmissionRequest_gatekeeperIdentifier = (1 << 20), - eAdmissionRequest_tokens = (1 << 19), - eAdmissionRequest_cryptoTokens = (1 << 18), - eAdmissionRequest_integrityCheckValue = (1 << 17), - eAdmissionRequest_transportQOS = (1 << 16), - eAdmissionRequest_willSupplyUUIEs = (1 << 15), - eAdmissionRequest_callLinkage = (1 << 14), - eAdmissionRequest_gatewayDataRate = (1 << 13), - eAdmissionRequest_capacity = (1 << 12), - eAdmissionRequest_circuitInfo = (1 << 11), - eAdmissionRequest_desiredProtocols = (1 << 10), - eAdmissionRequest_desiredTunnelledProtocol = (1 << 9), - eAdmissionRequest_featureSet = (1 << 8), - eAdmissionRequest_genericData = (1 << 7), - } options; - TransportAddress destCallSignalAddress; - TransportAddress srcCallSignalAddress; -} AdmissionRequest; - -typedef struct AdmissionConfirm { /* SEQUENCE */ - enum { - eAdmissionConfirm_irrFrequency = (1 << 31), - eAdmissionConfirm_nonStandardData = (1 << 30), - eAdmissionConfirm_destinationInfo = (1 << 29), - eAdmissionConfirm_destExtraCallInfo = (1 << 28), - eAdmissionConfirm_destinationType = (1 << 27), - eAdmissionConfirm_remoteExtensionAddress = (1 << 26), - eAdmissionConfirm_alternateEndpoints = (1 << 25), - eAdmissionConfirm_tokens = (1 << 24), - eAdmissionConfirm_cryptoTokens = (1 << 23), - eAdmissionConfirm_integrityCheckValue = (1 << 22), - eAdmissionConfirm_transportQOS = (1 << 21), - eAdmissionConfirm_willRespondToIRR = (1 << 20), - eAdmissionConfirm_uuiesRequested = (1 << 19), - eAdmissionConfirm_language = (1 << 18), - eAdmissionConfirm_alternateTransportAddresses = (1 << 17), - eAdmissionConfirm_useSpecifiedTransport = (1 << 16), - eAdmissionConfirm_circuitInfo = (1 << 15), - eAdmissionConfirm_usageSpec = (1 << 14), - eAdmissionConfirm_supportedProtocols = (1 << 13), - eAdmissionConfirm_serviceControl = (1 << 12), - eAdmissionConfirm_multipleCalls = (1 << 11), - eAdmissionConfirm_featureSet = (1 << 10), - eAdmissionConfirm_genericData = (1 << 9), - } options; - TransportAddress destCallSignalAddress; -} AdmissionConfirm; - -typedef struct LocationRequest { /* SEQUENCE */ - enum { - eLocationRequest_endpointIdentifier = (1 << 31), - eLocationRequest_nonStandardData = (1 << 30), - eLocationRequest_sourceInfo = (1 << 29), - eLocationRequest_canMapAlias = (1 << 28), - eLocationRequest_gatekeeperIdentifier = (1 << 27), - eLocationRequest_tokens = (1 << 26), - eLocationRequest_cryptoTokens = (1 << 25), - eLocationRequest_integrityCheckValue = (1 << 24), - eLocationRequest_desiredProtocols = (1 << 23), - eLocationRequest_desiredTunnelledProtocol = (1 << 22), - eLocationRequest_featureSet = (1 << 21), - eLocationRequest_genericData = (1 << 20), - eLocationRequest_hopCount = (1 << 19), - eLocationRequest_circuitInfo = (1 << 18), - } options; - TransportAddress replyAddress; -} LocationRequest; - -typedef struct LocationConfirm { /* SEQUENCE */ - enum { - eLocationConfirm_nonStandardData = (1 << 31), - eLocationConfirm_destinationInfo = (1 << 30), - eLocationConfirm_destExtraCallInfo = (1 << 29), - eLocationConfirm_destinationType = (1 << 28), - eLocationConfirm_remoteExtensionAddress = (1 << 27), - eLocationConfirm_alternateEndpoints = (1 << 26), - eLocationConfirm_tokens = (1 << 25), - eLocationConfirm_cryptoTokens = (1 << 24), - eLocationConfirm_integrityCheckValue = (1 << 23), - eLocationConfirm_alternateTransportAddresses = (1 << 22), - eLocationConfirm_supportedProtocols = (1 << 21), - eLocationConfirm_multipleCalls = (1 << 20), - eLocationConfirm_featureSet = (1 << 19), - eLocationConfirm_genericData = (1 << 18), - eLocationConfirm_circuitInfo = (1 << 17), - eLocationConfirm_serviceControl = (1 << 16), - } options; - TransportAddress callSignalAddress; - TransportAddress rasAddress; -} LocationConfirm; - -typedef struct InfoRequestResponse_callSignalAddress { /* SEQUENCE OF */ - int count; - TransportAddress item[10]; -} InfoRequestResponse_callSignalAddress; - -typedef struct InfoRequestResponse { /* SEQUENCE */ - enum { - eInfoRequestResponse_nonStandardData = (1 << 31), - eInfoRequestResponse_endpointAlias = (1 << 30), - eInfoRequestResponse_perCallInfo = (1 << 29), - eInfoRequestResponse_tokens = (1 << 28), - eInfoRequestResponse_cryptoTokens = (1 << 27), - eInfoRequestResponse_integrityCheckValue = (1 << 26), - eInfoRequestResponse_needResponse = (1 << 25), - eInfoRequestResponse_capacity = (1 << 24), - eInfoRequestResponse_irrStatus = (1 << 23), - eInfoRequestResponse_unsolicited = (1 << 22), - eInfoRequestResponse_genericData = (1 << 21), - } options; - TransportAddress rasAddress; - InfoRequestResponse_callSignalAddress callSignalAddress; -} InfoRequestResponse; - -typedef struct RasMessage { /* CHOICE */ - enum { - eRasMessage_gatekeeperRequest, - eRasMessage_gatekeeperConfirm, - eRasMessage_gatekeeperReject, - eRasMessage_registrationRequest, - eRasMessage_registrationConfirm, - eRasMessage_registrationReject, - eRasMessage_unregistrationRequest, - eRasMessage_unregistrationConfirm, - eRasMessage_unregistrationReject, - eRasMessage_admissionRequest, - eRasMessage_admissionConfirm, - eRasMessage_admissionReject, - eRasMessage_bandwidthRequest, - eRasMessage_bandwidthConfirm, - eRasMessage_bandwidthReject, - eRasMessage_disengageRequest, - eRasMessage_disengageConfirm, - eRasMessage_disengageReject, - eRasMessage_locationRequest, - eRasMessage_locationConfirm, - eRasMessage_locationReject, - eRasMessage_infoRequest, - eRasMessage_infoRequestResponse, - eRasMessage_nonStandardMessage, - eRasMessage_unknownMessageResponse, - eRasMessage_requestInProgress, - eRasMessage_resourcesAvailableIndicate, - eRasMessage_resourcesAvailableConfirm, - eRasMessage_infoRequestAck, - eRasMessage_infoRequestNak, - eRasMessage_serviceControlIndication, - eRasMessage_serviceControlResponse, - } choice; - union { - GatekeeperRequest gatekeeperRequest; - GatekeeperConfirm gatekeeperConfirm; - RegistrationRequest registrationRequest; - RegistrationConfirm registrationConfirm; - UnregistrationRequest unregistrationRequest; - AdmissionRequest admissionRequest; - AdmissionConfirm admissionConfirm; - LocationRequest locationRequest; - LocationConfirm locationConfirm; - InfoRequestResponse infoRequestResponse; - }; -} RasMessage; diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 83694cfdfa8f..1646076933b1 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -41,11 +41,13 @@ union nf_conntrack_expect_proto { /* Add protocol helper include file here */ #include +#include /* per conntrack: application helper private data */ union nf_conntrack_help { /* insert conntrack helper private data (master) here */ struct nf_ct_ftp_master ct_ftp_info; + struct nf_ct_h323_master ct_h323_info; }; #include diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 54a3d038beaa..cef3136e22a3 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -41,6 +41,7 @@ struct nf_conntrack_expect unsigned int flags; #ifdef CONFIG_NF_NAT_NEEDED + __be32 saved_ip; /* This is the original per-proto part, used to map the * expected connection the way the recipient expects. */ union nf_conntrack_man_proto saved_proto; diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 6993ec53dc06..e14156d1122e 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -529,6 +529,11 @@ config IP_NF_NAT_H323 default IP_NF_NAT if IP_NF_H323=y default m if IP_NF_H323=m +config NF_NAT_H323 + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_H323 + config IP_NF_NAT_SIP tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 8893249bbe98..bdaba4700e3b 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -15,7 +15,7 @@ endif ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o -ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ip_conntrack_helper_h323_asn1.o +ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ../../netfilter/nf_conntrack_h323_asn1.o ip_nat_h323-objs := ip_nat_helper_h323.o # connection tracking @@ -52,6 +52,7 @@ obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o # NAT helpers (nf_conntrack) obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o +obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c deleted file mode 100644 index 26dfecadb335..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +++ /dev/null @@ -1,874 +0,0 @@ -/**************************************************************************** - * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323 - * conntrack/NAT module. - * - * Copyright (c) 2006 by Jing Min Zhao - * - * This source code is licensed under General Public License version 2. - * - * See ip_conntrack_helper_h323_asn1.h for details. - * - ****************************************************************************/ - -#ifdef __KERNEL__ -#include -#else -#include -#endif -#include - -/* Trace Flag */ -#ifndef H323_TRACE -#define H323_TRACE 0 -#endif - -#if H323_TRACE -#define TAB_SIZE 4 -#define IFTHEN(cond, act) if(cond){act;} -#ifdef __KERNEL__ -#define PRINT printk -#else -#define PRINT printf -#endif -#define FNAME(name) name, -#else -#define IFTHEN(cond, act) -#define PRINT(fmt, args...) -#define FNAME(name) -#endif - -/* ASN.1 Types */ -#define NUL 0 -#define BOOL 1 -#define OID 2 -#define INT 3 -#define ENUM 4 -#define BITSTR 5 -#define NUMSTR 6 -#define NUMDGT 6 -#define TBCDSTR 6 -#define OCTSTR 7 -#define PRTSTR 7 -#define IA5STR 7 -#define GENSTR 7 -#define BMPSTR 8 -#define SEQ 9 -#define SET 9 -#define SEQOF 10 -#define SETOF 10 -#define CHOICE 11 - -/* Constraint Types */ -#define FIXD 0 -/* #define BITS 1-8 */ -#define BYTE 9 -#define WORD 10 -#define CONS 11 -#define SEMI 12 -#define UNCO 13 - -/* ASN.1 Type Attributes */ -#define SKIP 0 -#define STOP 1 -#define DECODE 2 -#define EXT 4 -#define OPEN 8 -#define OPT 16 - - -/* ASN.1 Field Structure */ -typedef struct field_t { -#if H323_TRACE - char *name; -#endif - unsigned char type; - unsigned char sz; - unsigned char lb; - unsigned char ub; - unsigned short attr; - unsigned short offset; - struct field_t *fields; -} field_t; - -/* Bit Stream */ -typedef struct { - unsigned char *buf; - unsigned char *beg; - unsigned char *end; - unsigned char *cur; - unsigned bit; -} bitstr_t; - -/* Tool Functions */ -#define INC_BIT(bs) if((++bs->bit)>7){bs->cur++;bs->bit=0;} -#define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;} -#define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;} -#define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND) -static unsigned get_len(bitstr_t * bs); -static unsigned get_bit(bitstr_t * bs); -static unsigned get_bits(bitstr_t * bs, unsigned b); -static unsigned get_bitmap(bitstr_t * bs, unsigned b); -static unsigned get_uint(bitstr_t * bs, int b); - -/* Decoder Functions */ -static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_int(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level); - -/* Decoder Functions Vector */ -typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int); -static decoder_t Decoders[] = { - decode_nul, - decode_bool, - decode_oid, - decode_int, - decode_enum, - decode_bitstr, - decode_numstr, - decode_octstr, - decode_bmpstr, - decode_seq, - decode_seqof, - decode_choice, -}; - -/**************************************************************************** - * H.323 Types - ****************************************************************************/ -#include "ip_conntrack_helper_h323_types.c" - -/**************************************************************************** - * Functions - ****************************************************************************/ -/* Assume bs is aligned && v < 16384 */ -unsigned get_len(bitstr_t * bs) -{ - unsigned v; - - v = *bs->cur++; - - if (v & 0x80) { - v &= 0x3f; - v <<= 8; - v += *bs->cur++; - } - - return v; -} - -/****************************************************************************/ -unsigned get_bit(bitstr_t * bs) -{ - unsigned b = (*bs->cur) & (0x80 >> bs->bit); - - INC_BIT(bs); - - return b; -} - -/****************************************************************************/ -/* Assume b <= 8 */ -unsigned get_bits(bitstr_t * bs, unsigned b) -{ - unsigned v, l; - - v = (*bs->cur) & (0xffU >> bs->bit); - l = b + bs->bit; - - if (l < 8) { - v >>= 8 - l; - bs->bit = l; - } else if (l == 8) { - bs->cur++; - bs->bit = 0; - } else { /* l > 8 */ - - v <<= 8; - v += *(++bs->cur); - v >>= 16 - l; - bs->bit = l - 8; - } - - return v; -} - -/****************************************************************************/ -/* Assume b <= 32 */ -unsigned get_bitmap(bitstr_t * bs, unsigned b) -{ - unsigned v, l, shift, bytes; - - if (!b) - return 0; - - l = bs->bit + b; - - if (l < 8) { - v = (unsigned) (*bs->cur) << (bs->bit + 24); - bs->bit = l; - } else if (l == 8) { - v = (unsigned) (*bs->cur++) << (bs->bit + 24); - bs->bit = 0; - } else { - for (bytes = l >> 3, shift = 24, v = 0; bytes; - bytes--, shift -= 8) - v |= (unsigned) (*bs->cur++) << shift; - - if (l < 32) { - v |= (unsigned) (*bs->cur) << shift; - v <<= bs->bit; - } else if (l > 32) { - v <<= bs->bit; - v |= (*bs->cur) >> (8 - bs->bit); - } - - bs->bit = l & 0x7; - } - - v &= 0xffffffff << (32 - b); - - return v; -} - -/**************************************************************************** - * Assume bs is aligned and sizeof(unsigned int) == 4 - ****************************************************************************/ -unsigned get_uint(bitstr_t * bs, int b) -{ - unsigned v = 0; - - switch (b) { - case 4: - v |= *bs->cur++; - v <<= 8; - case 3: - v |= *bs->cur++; - v <<= 8; - case 2: - v |= *bs->cur++; - v <<= 8; - case 1: - v |= *bs->cur++; - break; - } - return v; -} - -/****************************************************************************/ -int decode_nul(bitstr_t * bs, field_t * f, char *base, int level) -{ - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_bool(bitstr_t * bs, field_t * f, char *base, int level) -{ - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - INC_BIT(bs); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_oid(bitstr_t * bs, field_t * f, char *base, int level) -{ - int len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - len = *bs->cur++; - bs->cur += len; - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_int(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); - - switch (f->sz) { - case BYTE: /* Range == 256 */ - BYTE_ALIGN(bs); - bs->cur++; - break; - case WORD: /* 257 <= Range <= 64K */ - BYTE_ALIGN(bs); - bs->cur += 2; - break; - case CONS: /* 64K < Range < 4G */ - len = get_bits(bs, 2) + 1; - BYTE_ALIGN(bs); - if (base && (f->attr & DECODE)) { /* timeToLive */ - unsigned v = get_uint(bs, len) + f->lb; - PRINT(" = %u", v); - *((unsigned *) (base + f->offset)) = v; - } - bs->cur += len; - break; - case UNCO: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - len = get_len(bs); - bs->cur += len; - break; - default: /* 2 <= Range <= 255 */ - INC_BITS(bs, f->sz); - break; - } - - PRINT("\n"); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_enum(bitstr_t * bs, field_t * f, char *base, int level) -{ - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - if ((f->attr & EXT) && get_bit(bs)) { - INC_BITS(bs, 7); - } else { - INC_BITS(bs, f->sz); - } - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - BYTE_ALIGN(bs); - switch (f->sz) { - case FIXD: /* fixed length > 16 */ - len = f->lb; - break; - case WORD: /* 2-byte length */ - CHECK_BOUND(bs, 2); - len = (*bs->cur++) << 8; - len += (*bs->cur++) + f->lb; - break; - case SEMI: - CHECK_BOUND(bs, 2); - len = get_len(bs); - break; - default: - len = 0; - break; - } - - bs->cur += len >> 3; - bs->bit = len & 7; - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* 2 <= Range <= 255 */ - len = get_bits(bs, f->sz) + f->lb; - - BYTE_ALIGN(bs); - INC_BITS(bs, (len << 2)); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); - - switch (f->sz) { - case FIXD: /* Range == 1 */ - if (f->lb > 2) { - BYTE_ALIGN(bs); - if (base && (f->attr & DECODE)) { - /* The IP Address */ - IFTHEN(f->lb == 4, - PRINT(" = %d.%d.%d.%d:%d", - bs->cur[0], bs->cur[1], - bs->cur[2], bs->cur[3], - bs->cur[4] * 256 + bs->cur[5])); - *((unsigned *) (base + f->offset)) = - bs->cur - bs->buf; - } - } - len = f->lb; - break; - case BYTE: /* Range == 256 */ - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - len = (*bs->cur++) + f->lb; - break; - case SEMI: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - len = get_len(bs) + f->lb; - break; - default: /* 2 <= Range <= 255 */ - len = get_bits(bs, f->sz) + f->lb; - BYTE_ALIGN(bs); - break; - } - - bs->cur += len; - - PRINT("\n"); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - switch (f->sz) { - case BYTE: /* Range == 256 */ - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - len = (*bs->cur++) + f->lb; - break; - default: /* 2 <= Range <= 255 */ - len = get_bits(bs, f->sz) + f->lb; - BYTE_ALIGN(bs); - break; - } - - bs->cur += len << 1; - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len; - int err; - field_t *son; - unsigned char *beg = NULL; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* Decode? */ - base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; - - /* Extensible? */ - ext = (f->attr & EXT) ? get_bit(bs) : 0; - - /* Get fields bitmap */ - bmp = get_bitmap(bs, f->sz); - if (base) - *(unsigned *) base = bmp; - - /* Decode the root components */ - for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) { - if (son->attr & STOP) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - return H323_ERROR_STOP; - } - - if (son->attr & OPT) { /* Optional component */ - if (!((0x80000000U >> (opt++)) & bmp)) /* Not exist */ - continue; - } - - /* Decode */ - if (son->attr & OPEN) { /* Open field */ - CHECK_BOUND(bs, 2); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, - " ", son->name); - bs->cur += len; - continue; - } - beg = bs->cur; - - /* Decode */ - if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } else if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) < - H323_ERROR_NONE) - return err; - } - - /* No extension? */ - if (!ext) - return H323_ERROR_NONE; - - /* Get the extension bitmap */ - bmp2_len = get_bits(bs, 7) + 1; - CHECK_BOUND(bs, (bmp2_len + 7) >> 3); - bmp2 = get_bitmap(bs, bmp2_len); - bmp |= bmp2 >> f->sz; - if (base) - *(unsigned *) base = bmp; - BYTE_ALIGN(bs); - - /* Decode the extension components */ - for (opt = 0; opt < bmp2_len; opt++, i++, son++) { - if (i < f->ub && son->attr & STOP) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - return H323_ERROR_STOP; - } - - if (!((0x80000000 >> opt) & bmp2)) /* Not present */ - continue; - - /* Check Range */ - if (i >= f->ub) { /* Newer Version? */ - CHECK_BOUND(bs, 2); - len = get_len(bs); - CHECK_BOUND(bs, len); - bs->cur += len; - continue; - } - - CHECK_BOUND(bs, 2); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base || !(son->attr & DECODE)) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - bs->cur += len; - continue; - } - beg = bs->cur; - - if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned count, effective_count = 0, i, len = 0; - int err; - field_t *son; - unsigned char *beg = NULL; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* Decode? */ - base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; - - /* Decode item count */ - switch (f->sz) { - case BYTE: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - count = *bs->cur++; - break; - case WORD: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - count = *bs->cur++; - count <<= 8; - count = *bs->cur++; - break; - case SEMI: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - count = get_len(bs); - break; - default: - count = get_bits(bs, f->sz); - break; - } - count += f->lb; - - /* Write Count */ - if (base) { - effective_count = count > f->ub ? f->ub : count; - *(unsigned *) base = effective_count; - base += sizeof(unsigned); - } - - /* Decode nested field */ - son = f->fields; - if (base) - base -= son->offset; - for (i = 0; i < count; i++) { - if (son->attr & OPEN) { - BYTE_ALIGN(bs); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base || !(son->attr & DECODE)) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, - " ", son->name); - bs->cur += len; - continue; - } - beg = bs->cur; - - if ((err = (Decoders[son->type]) (bs, son, - i < - effective_count ? - base : NULL, - level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } else - if ((err = (Decoders[son->type]) (bs, son, - i < - effective_count ? - base : NULL, - level + 1)) < - H323_ERROR_NONE) - return err; - - if (base) - base += son->offset; - } - - return H323_ERROR_NONE; -} - - -/****************************************************************************/ -int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned type, ext, len = 0; - int err; - field_t *son; - unsigned char *beg = NULL; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* Decode? */ - base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; - - /* Decode the choice index number */ - if ((f->attr & EXT) && get_bit(bs)) { - ext = 1; - type = get_bits(bs, 7) + f->lb; - } else { - ext = 0; - type = get_bits(bs, f->sz); - } - - /* Write Type */ - if (base) - *(unsigned *) base = type; - - /* Check Range */ - if (type >= f->ub) { /* Newer version? */ - BYTE_ALIGN(bs); - len = get_len(bs); - CHECK_BOUND(bs, len); - bs->cur += len; - return H323_ERROR_NONE; - } - - /* Transfer to son level */ - son = &f->fields[type]; - if (son->attr & STOP) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name); - return H323_ERROR_STOP; - } - - if (ext || (son->attr & OPEN)) { - BYTE_ALIGN(bs); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base || !(son->attr & DECODE)) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - bs->cur += len; - return H323_ERROR_NONE; - } - beg = bs->cur; - - if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < - H323_ERROR_NONE) - return err; - - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras) -{ - static field_t ras_message = { - FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT, - 0, _RasMessage - }; - bitstr_t bs; - - bs.buf = bs.beg = bs.cur = buf; - bs.end = buf + sz; - bs.bit = 0; - - return decode_choice(&bs, &ras_message, (char *) ras, 0); -} - -/****************************************************************************/ -static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg, - size_t sz, H323_UserInformation * uuie) -{ - static field_t h323_userinformation = { - FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT, - 0, _H323_UserInformation - }; - bitstr_t bs; - - bs.buf = buf; - bs.beg = bs.cur = beg; - bs.end = beg + sz; - bs.bit = 0; - - return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0); -} - -/****************************************************************************/ -int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, - MultimediaSystemControlMessage * - mscm) -{ - static field_t multimediasystemcontrolmessage = { - FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4, - DECODE | EXT, 0, _MultimediaSystemControlMessage - }; - bitstr_t bs; - - bs.buf = bs.beg = bs.cur = buf; - bs.end = buf + sz; - bs.bit = 0; - - return decode_choice(&bs, &multimediasystemcontrolmessage, - (char *) mscm, 0); -} - -/****************************************************************************/ -int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931) -{ - unsigned char *p = buf; - int len; - - if (!p || sz < 1) - return H323_ERROR_BOUND; - - /* Protocol Discriminator */ - if (*p != 0x08) { - PRINT("Unknown Protocol Discriminator\n"); - return H323_ERROR_RANGE; - } - p++; - sz--; - - /* CallReferenceValue */ - if (sz < 1) - return H323_ERROR_BOUND; - len = *p++; - sz--; - if (sz < len) - return H323_ERROR_BOUND; - p += len; - sz -= len; - - /* Message Type */ - if (sz < 1) - return H323_ERROR_BOUND; - q931->MessageType = *p++; - PRINT("MessageType = %02X\n", q931->MessageType); - if (*p & 0x80) { - p++; - sz--; - } - - /* Decode Information Elements */ - while (sz > 0) { - if (*p == 0x7e) { /* UserUserIE */ - if (sz < 3) - break; - p++; - len = *p++ << 8; - len |= *p++; - sz -= 3; - if (sz < len) - break; - p++; - len--; - return DecodeH323_UserInformation(buf, p, len, - &q931->UUIE); - } - p++; - sz--; - if (sz < 1) - break; - len = *p++; - if (sz < len) - break; - p += len; - sz -= len; - } - - PRINT("Q.931 UUIE not found\n"); - - return H323_ERROR_BOUND; -} diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c deleted file mode 100644 index 4b359618bedd..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c +++ /dev/null @@ -1,1926 +0,0 @@ -/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 - * - * Copyright (c) 2006 Jing Min Zhao - * - * This source code is licensed under General Public License version 2. - */ - -static field_t _TransportAddress_ipAddress[] = { /* SEQUENCE */ - {FNAME("ip") OCTSTR, FIXD, 4, 0, DECODE, - offsetof(TransportAddress_ipAddress, ip), NULL}, - {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ipSourceRoute_route[] = { /* SEQUENCE OF */ - {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ipSourceRoute_routing[] = { /* CHOICE */ - {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ipSourceRoute[] = { /* SEQUENCE */ - {FNAME("ip") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, - _TransportAddress_ipSourceRoute_route}, - {FNAME("routing") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _TransportAddress_ipSourceRoute_routing}, -}; - -static field_t _TransportAddress_ipxAddress[] = { /* SEQUENCE */ - {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, - {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("port") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ip6Address[] = { /* SEQUENCE */ - {FNAME("ip") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H221NonStandard[] = { /* SEQUENCE */ - {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _NonStandardIdentifier[] = { /* CHOICE */ - {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP | EXT, 0, - _H221NonStandard}, -}; - -static field_t _NonStandardParameter[] = { /* SEQUENCE */ - {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _NonStandardIdentifier}, - {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress[] = { /* CHOICE */ - {FNAME("ipAddress") SEQ, 0, 2, 2, DECODE, - offsetof(TransportAddress, ipAddress), _TransportAddress_ipAddress}, - {FNAME("ipSourceRoute") SEQ, 0, 4, 4, SKIP | EXT, 0, - _TransportAddress_ipSourceRoute}, - {FNAME("ipxAddress") SEQ, 0, 3, 3, SKIP, 0, - _TransportAddress_ipxAddress}, - {FNAME("ip6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, - _TransportAddress_ip6Address}, - {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, - {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, - _NonStandardParameter}, -}; - -static field_t _AliasAddress[] = { /* CHOICE */ - {FNAME("dialedDigits") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("h323-ID") BMPSTR, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("url-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("transportID") CHOICE, 3, 7, 7, SKIP | EXT, 0, NULL}, - {FNAME("email-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("partyNumber") CHOICE, 3, 5, 5, SKIP | EXT, 0, NULL}, - {FNAME("mobileUIM") CHOICE, 1, 2, 2, SKIP | EXT, 0, NULL}, -}; - -static field_t _Setup_UUIE_sourceAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _VendorIdentifier[] = { /* SEQUENCE */ - {FNAME("vendor") SEQ, 0, 3, 3, SKIP | EXT, 0, _H221NonStandard}, - {FNAME("productId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("versionId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _GatekeeperInfo[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, -}; - -static field_t _H310Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H320Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H321Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H322Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H323Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H324Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _VoiceCaps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _T120OnlyCaps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _SupportedProtocols[] = { /* CHOICE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP, 0, - _NonStandardParameter}, - {FNAME("h310") SEQ, 1, 1, 3, SKIP | EXT, 0, _H310Caps}, - {FNAME("h320") SEQ, 1, 1, 3, SKIP | EXT, 0, _H320Caps}, - {FNAME("h321") SEQ, 1, 1, 3, SKIP | EXT, 0, _H321Caps}, - {FNAME("h322") SEQ, 1, 1, 3, SKIP | EXT, 0, _H322Caps}, - {FNAME("h323") SEQ, 1, 1, 3, SKIP | EXT, 0, _H323Caps}, - {FNAME("h324") SEQ, 1, 1, 3, SKIP | EXT, 0, _H324Caps}, - {FNAME("voice") SEQ, 1, 1, 3, SKIP | EXT, 0, _VoiceCaps}, - {FNAME("t120-only") SEQ, 1, 1, 3, SKIP | EXT, 0, _T120OnlyCaps}, - {FNAME("nonStandardProtocol") SEQ, 2, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("t38FaxAnnexbOnly") SEQ, 2, 5, 5, SKIP | EXT, 0, NULL}, -}; - -static field_t _GatewayInfo_protocol[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 4, 9, 11, SKIP | EXT, 0, _SupportedProtocols}, -}; - -static field_t _GatewayInfo[] = { /* SEQUENCE */ - {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _GatewayInfo_protocol}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, -}; - -static field_t _McuInfo[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _TerminalInfo[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, -}; - -static field_t _EndpointType[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("vendor") SEQ, 2, 3, 3, SKIP | EXT | OPT, 0, - _VendorIdentifier}, - {FNAME("gatekeeper") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, - _GatekeeperInfo}, - {FNAME("gateway") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, _GatewayInfo}, - {FNAME("mcu") SEQ, 1, 1, 2, SKIP | EXT | OPT, 0, _McuInfo}, - {FNAME("terminal") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, _TerminalInfo}, - {FNAME("mc") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("undefinedNode") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("set") BITSTR, FIXD, 32, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedTunnelledProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, - 0, NULL}, -}; - -static field_t _Setup_UUIE_destinationAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _Setup_UUIE_destExtraCallInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _Setup_UUIE_destExtraCRV[] = { /* SEQUENCE OF */ - {FNAME("item") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _Setup_UUIE_conferenceGoal[] = { /* CHOICE */ - {FNAME("create") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("join") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("invite") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("capability-negotiation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callIndependentSupplementaryService") NUL, FIXD, 0, 0, SKIP, - 0, NULL}, -}; - -static field_t _Q954Details[] = { /* SEQUENCE */ - {FNAME("conferenceCalling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("threePartyService") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _QseriesOptions[] = { /* SEQUENCE */ - {FNAME("q932Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q951Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q952Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q953Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q955Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q956Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q957Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q954Info") SEQ, 0, 2, 2, SKIP | EXT, 0, _Q954Details}, -}; - -static field_t _CallType[] = { /* CHOICE */ - {FNAME("pointToPoint") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("oneToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("nToOne") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("nToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H245_NonStandardIdentifier_h221NonStandard[] = { /* SEQUENCE */ - {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H245_NonStandardIdentifier[] = { /* CHOICE */ - {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP, 0, - _H245_NonStandardIdentifier_h221NonStandard}, -}; - -static field_t _H245_NonStandardParameter[] = { /* SEQUENCE */ - {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP, 0, - _H245_NonStandardIdentifier}, - {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H261VideoCapability[] = { /* SEQUENCE */ - {FNAME("qcifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, - NULL}, - {FNAME("maxBitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("stillImageTransmission") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H262VideoCapability[] = { /* SEQUENCE */ - {FNAME("profileAndLevel-SPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-SNRatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-SNRatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-SpatialatH-14") BOOL, FIXD, 0, 0, SKIP, 0, - NULL}, - {FNAME("profileAndLevel-HPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-HPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-HPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("framesPerSecond") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H263VideoCapability[] = { /* SEQUENCE */ - {FNAME("sqcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("qcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cif4MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cif16MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("maxBitRate") INT, CONS, 1, 0, SKIP, 0, NULL}, - {FNAME("unrestrictedVector") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("arithmeticCoding") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("advancedPrediction") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("pbFrames") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, - NULL}, - {FNAME("hrd-B") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("bppMaxKb") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowSqcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowQcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowCifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowCif4MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowCif16MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("errorCompensation") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("enhancementLayerInfo") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("h263Options") SEQ, 5, 29, 31, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _IS11172VideoCapability[] = { /* SEQUENCE */ - {FNAME("constrainedBitstream") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("pictureRate") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _VideoCapability[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("h261VideoCapability") SEQ, 2, 5, 6, SKIP | EXT, 0, - _H261VideoCapability}, - {FNAME("h262VideoCapability") SEQ, 6, 17, 18, SKIP | EXT, 0, - _H262VideoCapability}, - {FNAME("h263VideoCapability") SEQ, 7, 13, 21, SKIP | EXT, 0, - _H263VideoCapability}, - {FNAME("is11172VideoCapability") SEQ, 6, 7, 8, SKIP | EXT, 0, - _IS11172VideoCapability}, - {FNAME("genericVideoCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, -}; - -static field_t _AudioCapability_g7231[] = { /* SEQUENCE */ - {FNAME("maxAl-sduAudioFrames") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _IS11172AudioCapability[] = { /* SEQUENCE */ - {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, -}; - -static field_t _IS13818AudioCapability[] = { /* SEQUENCE */ - {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling16k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling22k05") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling24k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("threeChannels2-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("threeChannels3-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fourChannels2-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fourChannels2-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fourChannels3-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fiveChannels3-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fiveChannels3-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("lowFrequencyEnhancement") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("multilingual") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, -}; - -static field_t _AudioCapability[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("g711Alaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g711Alaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g711Ulaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g711Ulaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g722-64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g722-56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g722-48k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g7231") SEQ, 0, 2, 2, SKIP, 0, _AudioCapability_g7231}, - {FNAME("g728") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g729") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g729AnnexA") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("is11172AudioCapability") SEQ, 0, 9, 9, SKIP | EXT, 0, - _IS11172AudioCapability}, - {FNAME("is13818AudioCapability") SEQ, 0, 21, 21, SKIP | EXT, 0, - _IS13818AudioCapability}, - {FNAME("g729wAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g729AnnexAwAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g7231AnnexCCapability") SEQ, 1, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("gsmFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("gsmHalfRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("gsmEnhancedFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("genericAudioCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, - {FNAME("g729Extensions") SEQ, 1, 8, 8, SKIP | EXT, 0, NULL}, -}; - -static field_t _DataProtocolCapability[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("v14buffered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("v42lapm") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdlcFrameTunnelling") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h310SeparateVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h310SingleVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("transparent") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("segmentationAndReassembly") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdlcFrameTunnelingwSAR") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("v120") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("separateLANStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("v76wCompression") CHOICE, 2, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("tcp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("udp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _T84Profile_t84Restricted[] = { /* SEQUENCE */ - {FNAME("qcif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("cif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("ccir601Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("ccir601Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdtvSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdtvProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g3FacsMH200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g3FacsMH200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g4FacsMMR200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g4FacsMMR200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig200x200Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig200x200Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig300x300Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig300x300Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoLow") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoMedSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoMedProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoHighSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoHighProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _T84Profile[] = { /* CHOICE */ - {FNAME("t84Unrestricted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("t84Restricted") SEQ, 0, 19, 19, SKIP | EXT, 0, - _T84Profile_t84Restricted}, -}; - -static field_t _DataApplicationCapability_application_t84[] = { /* SEQUENCE */ - {FNAME("t84Protocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("t84Profile") CHOICE, 1, 2, 2, SKIP, 0, _T84Profile}, -}; - -static field_t _DataApplicationCapability_application_nlpid[] = { /* SEQUENCE */ - {FNAME("nlpidProtocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("nlpidData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _DataApplicationCapability_application[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("t120") CHOICE, 3, 7, 14, DECODE | EXT, - offsetof(DataApplicationCapability_application, t120), - _DataProtocolCapability}, - {FNAME("dsm-cc") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("userData") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("t84") SEQ, 0, 2, 2, SKIP, 0, - _DataApplicationCapability_application_t84}, - {FNAME("t434") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("h224") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("nlpid") SEQ, 0, 2, 2, SKIP, 0, - _DataApplicationCapability_application_nlpid}, - {FNAME("dsvdControl") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h222DataPartitioning") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("t30fax") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, - {FNAME("t140") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, - {FNAME("t38fax") SEQ, 0, 2, 2, SKIP, 0, NULL}, - {FNAME("genericDataCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, -}; - -static field_t _DataApplicationCapability[] = { /* SEQUENCE */ - {FNAME("application") CHOICE, 4, 10, 14, DECODE | EXT, - offsetof(DataApplicationCapability, application), - _DataApplicationCapability_application}, - {FNAME("maxBitRate") INT, CONS, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _EncryptionMode[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("h233Encryption") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _DataType[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("nullData") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoData") CHOICE, 3, 5, 6, SKIP | EXT, 0, _VideoCapability}, - {FNAME("audioData") CHOICE, 4, 14, 22, SKIP | EXT, 0, - _AudioCapability}, - {FNAME("data") SEQ, 0, 2, 2, DECODE | EXT, offsetof(DataType, data), - _DataApplicationCapability}, - {FNAME("encryptionData") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _EncryptionMode}, - {FNAME("h235Control") SEQ, 0, 2, 2, SKIP, 0, NULL}, - {FNAME("h235Media") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, - {FNAME("multiplexedStream") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, -}; - -static field_t _H222LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("resourceID") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("subChannelID") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("pcr-pid") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("programDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("streamDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = { /* SEQUENCE */ - {FNAME("controlFieldOctets") INT, 2, 0, 0, SKIP, 0, NULL}, - {FNAME("sendBufferSize") INT, CONS, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H223LogicalChannelParameters_adaptationLayerType[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("al1Framed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al1NotFramed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al2WithoutSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al2WithSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al3") SEQ, 0, 2, 2, SKIP, 0, - _H223LogicalChannelParameters_adaptationLayerType_al3}, - {FNAME("al1M") SEQ, 0, 7, 8, SKIP | EXT, 0, NULL}, - {FNAME("al2M") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, - {FNAME("al3M") SEQ, 0, 5, 6, SKIP | EXT, 0, NULL}, -}; - -static field_t _H223LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("adaptationLayerType") CHOICE, 3, 6, 9, SKIP | EXT, 0, - _H223LogicalChannelParameters_adaptationLayerType}, - {FNAME("segmentableFlag") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CRCLength[] = { /* CHOICE */ - {FNAME("crc8bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("crc16bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("crc32bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76HDLCParameters[] = { /* SEQUENCE */ - {FNAME("crcLength") CHOICE, 2, 3, 3, SKIP | EXT, 0, _CRCLength}, - {FNAME("n401") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("loopbackTestProcedure") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters_suspendResume[] = { /* CHOICE */ - {FNAME("noSuspendResume") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("suspendResumewAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("suspendResumewoAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = { /* CHOICE */ - {FNAME("rej") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("sREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("mSREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters_mode_eRM[] = { /* SEQUENCE */ - {FNAME("windowSize") INT, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("recovery") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _V76LogicalChannelParameters_mode_eRM_recovery}, -}; - -static field_t _V76LogicalChannelParameters_mode[] = { /* CHOICE */ - {FNAME("eRM") SEQ, 0, 2, 2, SKIP | EXT, 0, - _V76LogicalChannelParameters_mode_eRM}, - {FNAME("uNERM") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V75Parameters[] = { /* SEQUENCE */ - {FNAME("audioHeaderPresent") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("hdlcParameters") SEQ, 0, 3, 3, SKIP | EXT, 0, - _V76HDLCParameters}, - {FNAME("suspendResume") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _V76LogicalChannelParameters_suspendResume}, - {FNAME("uIH") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("mode") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _V76LogicalChannelParameters_mode}, - {FNAME("v75Parameters") SEQ, 0, 1, 1, SKIP | EXT, 0, _V75Parameters}, -}; - -static field_t _H2250LogicalChannelParameters_nonStandard[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, -}; - -static field_t _UnicastAddress_iPAddress[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 4, 0, DECODE, - offsetof(UnicastAddress_iPAddress, network), NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPXAddress[] = { /* SEQUENCE */ - {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, - {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iP6Address[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPSourceRouteAddress_routing[] = { /* CHOICE */ - {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPSourceRouteAddress_route[] = { /* SEQUENCE OF */ - {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPSourceRouteAddress[] = { /* SEQUENCE */ - {FNAME("routing") CHOICE, 1, 2, 2, SKIP, 0, - _UnicastAddress_iPSourceRouteAddress_routing}, - {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, - _UnicastAddress_iPSourceRouteAddress_route}, -}; - -static field_t _UnicastAddress[] = { /* CHOICE */ - {FNAME("iPAddress") SEQ, 0, 2, 2, DECODE | EXT, - offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress}, - {FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0, - _UnicastAddress_iPXAddress}, - {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, - _UnicastAddress_iP6Address}, - {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("iPSourceRouteAddress") SEQ, 0, 4, 4, SKIP | EXT, 0, - _UnicastAddress_iPSourceRouteAddress}, - {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, - {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, -}; - -static field_t _MulticastAddress_iPAddress[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _MulticastAddress_iP6Address[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _MulticastAddress[] = { /* CHOICE */ - {FNAME("iPAddress") SEQ, 0, 2, 2, SKIP | EXT, 0, - _MulticastAddress_iPAddress}, - {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, - _MulticastAddress_iP6Address}, - {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, - {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, -}; - -static field_t _H245_TransportAddress[] = { /* CHOICE */ - {FNAME("unicastAddress") CHOICE, 3, 5, 7, DECODE | EXT, - offsetof(H245_TransportAddress, unicastAddress), _UnicastAddress}, - {FNAME("multicastAddress") CHOICE, 1, 2, 4, SKIP | EXT, 0, - _MulticastAddress}, -}; - -static field_t _H2250LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _H2250LogicalChannelParameters_nonStandard}, - {FNAME("sessionID") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("associatedSessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelParameters, mediaChannel), - _H245_TransportAddress}, - {FNAME("mediaGuaranteedDelivery") BOOL, FIXD, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelParameters, mediaControlChannel), - _H245_TransportAddress}, - {FNAME("mediaControlGuaranteedDelivery") BOOL, FIXD, 0, 0, STOP | OPT, - 0, NULL}, - {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destination") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, STOP | OPT, 0, NULL}, - {FNAME("mediaPacketization") CHOICE, 0, 1, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("transportCapability") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, - NULL}, - {FNAME("redundancyEncoding") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("source") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ - {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, - _H222LogicalChannelParameters}, - {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, - _H223LogicalChannelParameters}, - {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, - _V76LogicalChannelParameters}, - {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, - offsetof - (OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters, - h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, - {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("dataType") CHOICE, 3, 6, 9, DECODE | EXT, - offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, - dataType), _DataType}, - {FNAME("multiplexParameters") CHOICE, 2, 3, 5, DECODE | EXT, - offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, - multiplexParameters), - _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters}, - {FNAME("forwardLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, - 0, NULL}, - {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ - {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, - _H223LogicalChannelParameters}, - {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, - _V76LogicalChannelParameters}, - {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, - offsetof - (OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters, - h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, -}; - -static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("dataType") CHOICE, 3, 6, 9, SKIP | EXT, 0, _DataType}, - {FNAME("multiplexParameters") CHOICE, 1, 2, 3, DECODE | EXT | OPT, - offsetof(OpenLogicalChannel_reverseLogicalChannelParameters, - multiplexParameters), - _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters}, - {FNAME("reverseLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, - 0, NULL}, - {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _NetworkAccessParameters_distribution[] = { /* CHOICE */ - {FNAME("unicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("multicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _Q2931Address_address[] = { /* CHOICE */ - {FNAME("internationalNumber") NUMSTR, 4, 1, 0, SKIP, 0, NULL}, - {FNAME("nsapAddress") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, -}; - -static field_t _Q2931Address[] = { /* SEQUENCE */ - {FNAME("address") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _Q2931Address_address}, - {FNAME("subaddress") OCTSTR, 5, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _NetworkAccessParameters_networkAddress[] = { /* CHOICE */ - {FNAME("q2931Address") SEQ, 1, 2, 2, SKIP | EXT, 0, _Q2931Address}, - {FNAME("e164Address") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("localAreaAddress") CHOICE, 1, 2, 2, DECODE | EXT, - offsetof(NetworkAccessParameters_networkAddress, localAreaAddress), - _H245_TransportAddress}, -}; - -static field_t _NetworkAccessParameters[] = { /* SEQUENCE */ - {FNAME("distribution") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, - _NetworkAccessParameters_distribution}, - {FNAME("networkAddress") CHOICE, 2, 3, 3, DECODE | EXT, - offsetof(NetworkAccessParameters, networkAddress), - _NetworkAccessParameters_networkAddress}, - {FNAME("associateConference") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("externalReference") OCTSTR, 8, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("t120SetupProcedure") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, -}; - -static field_t _OpenLogicalChannel[] = { /* SEQUENCE */ - {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("forwardLogicalChannelParameters") SEQ, 1, 3, 5, DECODE | EXT, - offsetof(OpenLogicalChannel, forwardLogicalChannelParameters), - _OpenLogicalChannel_forwardLogicalChannelParameters}, - {FNAME("reverseLogicalChannelParameters") SEQ, 1, 2, 4, - DECODE | EXT | OPT, offsetof(OpenLogicalChannel, - reverseLogicalChannelParameters), - _OpenLogicalChannel_reverseLogicalChannelParameters}, - {FNAME("separateStack") SEQ, 2, 4, 5, DECODE | EXT | OPT, - offsetof(OpenLogicalChannel, separateStack), - _NetworkAccessParameters}, - {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _Setup_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Setup_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Setup_UUIE, h245Address), _TransportAddress}, - {FNAME("sourceAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_sourceAddress}, - {FNAME("sourceInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, - {FNAME("destinationAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_destinationAddress}, - {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Setup_UUIE, destCallSignalAddress), _TransportAddress}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_destExtraCallInfo}, - {FNAME("destExtraCRV") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_destExtraCRV}, - {FNAME("activeMC") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("conferenceGoal") CHOICE, 2, 3, 5, SKIP | EXT, 0, - _Setup_UUIE_conferenceGoal}, - {FNAME("callServices") SEQ, 0, 8, 8, SKIP | EXT | OPT, 0, - _QseriesOptions}, - {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, - {FNAME("sourceCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Setup_UUIE, sourceCallSignalAddress), _TransportAddress}, - {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityCapability") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Setup_UUIE, fastStart), _Setup_UUIE_fastStart}, - {FNAME("mediaWaitForConnect") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("canOverlapSend") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("connectionParameters") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("symmetricOperationRequired") NUL, FIXD, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, - {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("neededFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("desiredFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("parallelH245Control") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("additionalSourceAddresses") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - NULL}, -}; - -static field_t _CallProceeding_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _CallProceeding_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(CallProceeding_UUIE, h245Address), _TransportAddress}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(CallProceeding_UUIE, fastStart), - _CallProceeding_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Connect_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Connect_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Connect_UUIE, h245Address), _TransportAddress}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Connect_UUIE, fastStart), _Connect_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("connectedAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Alerting_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Alerting_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Alerting_UUIE, h245Address), _TransportAddress}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Alerting_UUIE, fastStart), _Alerting_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("alertingAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Information_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Information_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Information_UUIE, fastStart), _Information_UUIE_fastStart}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _ReleaseCompleteReason[] = { /* CHOICE */ - {FNAME("noBandwidth") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("gatekeeperResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("unreachableDestination") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationRejection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("invalidRevision") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("noPermission") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("unreachableGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("gatewayResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("badFormatAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("adaptiveBusy") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("inConf") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("facilityCallDeflection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("securityDenied") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("calledPartyNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callerNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("newConnectionNeeded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardReason") SEQ, 0, 2, 2, SKIP, 0, NULL}, - {FNAME("replaceWithConferenceInvite") OCTSTR, FIXD, 16, 0, SKIP, 0, - NULL}, - {FNAME("genericDataReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("neededFeatureNotSupported") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("tunnelledSignallingRejected") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _ReleaseComplete_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("reason") CHOICE, 4, 12, 22, SKIP | EXT | OPT, 0, - _ReleaseCompleteReason}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("busyAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Facility_UUIE_alternativeAliasAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _FacilityReason[] = { /* CHOICE */ - {FNAME("routeCallToGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callForwarded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("routeCallToMC") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("conferenceListChoice") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("startH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("noH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("newTokens") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("featureSetUpdate") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("forwardedElements") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("transportedInformation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _Facility_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Facility_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Facility_UUIE, alternativeAddress), _TransportAddress}, - {FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Facility_UUIE_alternativeAliasAddress}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, - {FNAME("reason") CHOICE, 2, 4, 11, DECODE | EXT, - offsetof(Facility_UUIE, reason), _FacilityReason}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("conferences") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Facility_UUIE, h245Address), _TransportAddress}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Facility_UUIE, fastStart), _Facility_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT | OPT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, -}; - -static field_t _CallIdentifier[] = { /* SEQUENCE */ - {FNAME("guid") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, -}; - -static field_t _SecurityServiceMode[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, - {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("default") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _SecurityCapabilities[] = { /* SEQUENCE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("encryption") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _SecurityServiceMode}, - {FNAME("authenticaton") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _SecurityServiceMode}, - {FNAME("integrity") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _SecurityServiceMode}, -}; - -static field_t _H245Security[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, - {FNAME("noSecurity") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("tls") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, - {FNAME("ipsec") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, -}; - -static field_t _DHset[] = { /* SEQUENCE */ - {FNAME("halfkey") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("modSize") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("generator") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TypedCertificate[] = { /* SEQUENCE */ - {FNAME("type") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("certificate") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H235_NonStandardParameter[] = { /* SEQUENCE */ - {FNAME("nonStandardIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _ClearToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("timeStamp") INT, CONS, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("password") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("dhkey") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, _DHset}, - {FNAME("challenge") OCTSTR, 7, 8, 0, SKIP | OPT, 0, NULL}, - {FNAME("random") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("certificate") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, - _TypedCertificate}, - {FNAME("generalID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, - _H235_NonStandardParameter}, - {FNAME("eckasdhkey") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("sendersID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _Progress_UUIE_tokens[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, -}; - -static field_t _Params[] = { /* SEQUENCE */ - {FNAME("ranInt") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("iv8") OCTSTR, FIXD, 8, 0, SKIP | OPT, 0, NULL}, - {FNAME("iv16") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoEPPwdHash_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoEPPwdHash[] = { /* SEQUENCE */ - {FNAME("alias") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, - {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoEPPwdHash_token}, -}; - -static field_t _CryptoH323Token_cryptoGKPwdHash_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoGKPwdHash[] = { /* SEQUENCE */ - {FNAME("gatekeeperId") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoGKPwdHash_token}, -}; - -static field_t _CryptoH323Token_cryptoEPPwdEncr[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoGKPwdEncr[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoEPCert[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoGKCert[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoFastStart[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoEncryptedToken_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoEncryptedToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoEncryptedToken_token}, -}; - -static field_t _CryptoToken_cryptoSignedToken_token[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoSignedToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 4, 4, SKIP, 0, - _CryptoToken_cryptoSignedToken_token}, -}; - -static field_t _CryptoToken_cryptoHashedToken_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoHashedToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("hashedVals") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoHashedToken_token}, -}; - -static field_t _CryptoToken_cryptoPwdEncr[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken[] = { /* CHOICE */ - {FNAME("cryptoEncryptedToken") SEQ, 0, 2, 2, SKIP, 0, - _CryptoToken_cryptoEncryptedToken}, - {FNAME("cryptoSignedToken") SEQ, 0, 2, 2, SKIP, 0, - _CryptoToken_cryptoSignedToken}, - {FNAME("cryptoHashedToken") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoHashedToken}, - {FNAME("cryptoPwdEncr") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoPwdEncr}, -}; - -static field_t _CryptoH323Token[] = { /* CHOICE */ - {FNAME("cryptoEPPwdHash") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoEPPwdHash}, - {FNAME("cryptoGKPwdHash") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoGKPwdHash}, - {FNAME("cryptoEPPwdEncr") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoEPPwdEncr}, - {FNAME("cryptoGKPwdEncr") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoGKPwdEncr}, - {FNAME("cryptoEPCert") SEQ, 0, 4, 4, SKIP, 0, - _CryptoH323Token_cryptoEPCert}, - {FNAME("cryptoGKCert") SEQ, 0, 4, 4, SKIP, 0, - _CryptoH323Token_cryptoGKCert}, - {FNAME("cryptoFastStart") SEQ, 0, 4, 4, SKIP, 0, - _CryptoH323Token_cryptoFastStart}, - {FNAME("nestedcryptoToken") CHOICE, 2, 4, 4, SKIP | EXT, 0, - _CryptoToken}, -}; - -static field_t _Progress_UUIE_cryptoTokens[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 8, 8, SKIP | EXT, 0, _CryptoH323Token}, -}; - -static field_t _Progress_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Progress_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Progress_UUIE, h245Address), _TransportAddress}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, - _CallIdentifier}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - _H245Security}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Progress_UUIE_tokens}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Progress_UUIE_cryptoTokens}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Progress_UUIE, fastStart), _Progress_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _H323_UU_PDU_h323_message_body[] = { /* CHOICE */ - {FNAME("setup") SEQ, 7, 13, 39, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, setup), _Setup_UUIE}, - {FNAME("callProceeding") SEQ, 1, 3, 12, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, callProceeding), - _CallProceeding_UUIE}, - {FNAME("connect") SEQ, 1, 4, 19, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, connect), _Connect_UUIE}, - {FNAME("alerting") SEQ, 1, 3, 17, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, alerting), _Alerting_UUIE}, - {FNAME("information") SEQ, 0, 1, 7, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, information), - _Information_UUIE}, - {FNAME("releaseComplete") SEQ, 1, 2, 11, SKIP | EXT, 0, - _ReleaseComplete_UUIE}, - {FNAME("facility") SEQ, 3, 5, 21, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, facility), _Facility_UUIE}, - {FNAME("progress") SEQ, 5, 8, 11, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, progress), _Progress_UUIE}, - {FNAME("empty") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("status") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, - {FNAME("statusInquiry") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, - {FNAME("setupAcknowledge") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, - {FNAME("notify") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, -}; - -static field_t _RequestMessage[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("masterSlaveDetermination") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("terminalCapabilitySet") SEQ, 3, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("openLogicalChannel") SEQ, 1, 3, 5, DECODE | EXT, - offsetof(RequestMessage, openLogicalChannel), _OpenLogicalChannel}, - {FNAME("closeLogicalChannel") SEQ, 0, 2, 3, STOP | EXT, 0, NULL}, - {FNAME("requestChannelClose") SEQ, 0, 1, 3, STOP | EXT, 0, NULL}, - {FNAME("multiplexEntrySend") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("requestMultiplexEntry") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestMode") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("roundTripDelayRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("maintenanceLoopRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("communicationModeRequest") SEQ, 0, 0, 0, STOP | EXT, 0, NULL}, - {FNAME("conferenceRequest") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, - {FNAME("multilinkRequest") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("logicalChannelRateRequest") SEQ, 0, 3, 3, STOP | EXT, 0, - NULL}, -}; - -static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ - {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, - _H222LogicalChannelParameters}, - {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, - offsetof - (OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters, - h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, -}; - -static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("reverseLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("multiplexParameters") CHOICE, 0, 1, 2, DECODE | EXT | OPT, - offsetof(OpenLogicalChannelAck_reverseLogicalChannelParameters, - multiplexParameters), - _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters}, - {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _H2250LogicalChannelAckParameters_nonStandard[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, -}; - -static field_t _H2250LogicalChannelAckParameters[] = { /* SEQUENCE */ - {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _H2250LogicalChannelAckParameters_nonStandard}, - {FNAME("sessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelAckParameters, mediaChannel), - _H245_TransportAddress}, - {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelAckParameters, mediaControlChannel), - _H245_TransportAddress}, - {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, SKIP | OPT, 0, NULL}, - {FNAME("flowControlToZero") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = { /* CHOICE */ - {FNAME("h2250LogicalChannelAckParameters") SEQ, 5, 5, 7, DECODE | EXT, - offsetof(OpenLogicalChannelAck_forwardMultiplexAckParameters, - h2250LogicalChannelAckParameters), - _H2250LogicalChannelAckParameters}, -}; - -static field_t _OpenLogicalChannelAck[] = { /* SEQUENCE */ - {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("reverseLogicalChannelParameters") SEQ, 2, 3, 4, - DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, - reverseLogicalChannelParameters), - _OpenLogicalChannelAck_reverseLogicalChannelParameters}, - {FNAME("separateStack") SEQ, 2, 4, 5, SKIP | EXT | OPT, 0, NULL}, - {FNAME("forwardMultiplexAckParameters") CHOICE, 0, 1, 1, - DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, - forwardMultiplexAckParameters), - _OpenLogicalChannelAck_forwardMultiplexAckParameters}, - {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _ResponseMessage[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("masterSlaveDeterminationAck") SEQ, 0, 1, 1, STOP | EXT, 0, - NULL}, - {FNAME("masterSlaveDeterminationReject") SEQ, 0, 1, 1, STOP | EXT, 0, - NULL}, - {FNAME("terminalCapabilitySetAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("terminalCapabilitySetReject") SEQ, 0, 2, 2, STOP | EXT, 0, - NULL}, - {FNAME("openLogicalChannelAck") SEQ, 1, 2, 5, DECODE | EXT, - offsetof(ResponseMessage, openLogicalChannelAck), - _OpenLogicalChannelAck}, - {FNAME("openLogicalChannelReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("closeLogicalChannelAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestChannelCloseAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestChannelCloseReject") SEQ, 0, 2, 2, STOP | EXT, 0, - NULL}, - {FNAME("multiplexEntrySendAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("multiplexEntrySendReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("requestMultiplexEntryAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestMultiplexEntryReject") SEQ, 0, 2, 2, STOP | EXT, 0, - NULL}, - {FNAME("requestModeAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("requestModeReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("roundTripDelayResponse") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("maintenanceLoopAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("maintenanceLoopReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("communicationModeResponse") CHOICE, 0, 1, 1, STOP | EXT, 0, - NULL}, - {FNAME("conferenceResponse") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, - {FNAME("multilinkResponse") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("logicalChannelRateAcknowledge") SEQ, 0, 3, 3, STOP | EXT, 0, - NULL}, - {FNAME("logicalChannelRateReject") SEQ, 1, 4, 4, STOP | EXT, 0, NULL}, -}; - -static field_t _MultimediaSystemControlMessage[] = { /* CHOICE */ - {FNAME("request") CHOICE, 4, 11, 15, DECODE | EXT, - offsetof(MultimediaSystemControlMessage, request), _RequestMessage}, - {FNAME("response") CHOICE, 5, 19, 24, DECODE | EXT, - offsetof(MultimediaSystemControlMessage, response), - _ResponseMessage}, - {FNAME("command") CHOICE, 3, 7, 12, STOP | EXT, 0, NULL}, - {FNAME("indication") CHOICE, 4, 14, 23, STOP | EXT, 0, NULL}, -}; - -static field_t _H323_UU_PDU_h245Control[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 2, 4, 4, DECODE | OPEN | EXT, - sizeof(MultimediaSystemControlMessage), - _MultimediaSystemControlMessage} - , -}; - -static field_t _H323_UU_PDU[] = { /* SEQUENCE */ - {FNAME("h323-message-body") CHOICE, 3, 7, 13, DECODE | EXT, - offsetof(H323_UU_PDU, h323_message_body), - _H323_UU_PDU_h323_message_body}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("h4501SupplementaryService") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("h245Tunneling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h245Control") SEQOF, SEMI, 0, 4, DECODE | OPT, - offsetof(H323_UU_PDU, h245Control), _H323_UU_PDU_h245Control}, - {FNAME("nonStandardControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("tunnelledSignallingMessage") SEQ, 2, 4, 4, STOP | EXT | OPT, - 0, NULL}, - {FNAME("provisionalRespToH245Tunneling") NUL, FIXD, 0, 0, STOP | OPT, - 0, NULL}, - {FNAME("stimulusControl") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _H323_UserInformation[] = { /* SEQUENCE */ - {FNAME("h323-uu-pdu") SEQ, 1, 2, 11, DECODE | EXT, - offsetof(H323_UserInformation, h323_uu_pdu), _H323_UU_PDU}, - {FNAME("user-data") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _GatekeeperRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(GatekeeperRequest, rasAddress), _TransportAddress}, - {FNAME("endpointType") SEQ, 6, 8, 10, STOP | EXT, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, - {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("authenticationCapability") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("algorithmOIDs") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _GatekeeperConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(GatekeeperConfirm, rasAddress), _TransportAddress}, - {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("authenticationMode") CHOICE, 3, 7, 8, STOP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _RegistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _RegistrationRequest_rasAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _RegistrationRequest_terminalAlias[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _RegistrationRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("discoveryComplete") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(RegistrationRequest, callSignalAddress), - _RegistrationRequest_callSignalAddress}, - {FNAME("rasAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(RegistrationRequest, rasAddress), - _RegistrationRequest_rasAddress}, - {FNAME("terminalType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, - {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _RegistrationRequest_terminalAlias}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("endpointVendor") SEQ, 2, 3, 3, SKIP | EXT, 0, - _VendorIdentifier}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, - offsetof(RegistrationRequest, timeToLive), NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("keepAlive") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("additiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("usageReportingCapability") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, - NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("supportedH248Packages") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("callCreditCapability") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("capacityReportingCapability") SEQ, 0, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _RegistrationConfirm_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _RegistrationConfirm_terminalAlias[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _RegistrationConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(RegistrationConfirm, callSignalAddress), - _RegistrationConfirm_callSignalAddress}, - {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _RegistrationConfirm_terminalAlias}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, - offsetof(RegistrationConfirm, timeToLive), NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("preGrantedARQ") SEQ, 0, 4, 8, STOP | EXT | OPT, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("supportsAdditiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureServerAlias") CHOICE, 1, 2, 7, STOP | EXT | OPT, 0, - NULL}, - {FNAME("capacityReportingSpec") SEQ, 0, 1, 1, STOP | EXT | OPT, 0, - NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _UnregistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _UnregistrationRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(UnregistrationRequest, callSignalAddress), - _UnregistrationRequest_callSignalAddress}, - {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("reason") CHOICE, 2, 4, 5, STOP | EXT | OPT, 0, NULL}, - {FNAME("endpointAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _CallModel[] = { /* CHOICE */ - {FNAME("direct") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("gatekeeperRouted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _AdmissionRequest_destinationInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _AdmissionRequest_destExtraCallInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _AdmissionRequest_srcInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _AdmissionRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, - {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, _CallModel}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _AdmissionRequest_destinationInfo}, - {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(AdmissionRequest, destCallSignalAddress), - _TransportAddress}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _AdmissionRequest_destExtraCallInfo}, - {FNAME("srcInfo") SEQOF, SEMI, 0, 0, SKIP, 0, - _AdmissionRequest_srcInfo}, - {FNAME("srcCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(AdmissionRequest, srcCallSignalAddress), _TransportAddress}, - {FNAME("bandWidth") INT, CONS, 0, 0, STOP, 0, NULL}, - {FNAME("callReferenceValue") INT, WORD, 0, 0, STOP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, STOP, 0, NULL}, - {FNAME("activeMC") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("answerCall") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("srcAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("gatewayDataRate") SEQ, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _AdmissionConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("bandWidth") INT, CONS, 0, 0, SKIP, 0, NULL}, - {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT, 0, _CallModel}, - {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(AdmissionConfirm, destCallSignalAddress), - _TransportAddress}, - {FNAME("irrFrequency") INT, WORD, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, - {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("uuiesRequested") SEQ, 0, 9, 13, STOP | EXT, 0, NULL}, - {FNAME("language") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("useSpecifiedTransport") CHOICE, 1, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _LocationRequest_destinationInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _LocationRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP, 0, - _LocationRequest_destinationInfo}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("replyAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(LocationRequest, replyAddress), _TransportAddress}, - {FNAME("sourceInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("hopCount") INT, 8, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _LocationConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("callSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(LocationConfirm, callSignalAddress), _TransportAddress}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(LocationConfirm, rasAddress), _TransportAddress}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, - {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _InfoRequestResponse_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _InfoRequestResponse[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("endpointType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(InfoRequestResponse, rasAddress), _TransportAddress}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(InfoRequestResponse, callSignalAddress), - _InfoRequestResponse_callSignalAddress}, - {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("perCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("needResponse") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("irrStatus") CHOICE, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("unsolicited") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _RasMessage[] = { /* CHOICE */ - {FNAME("gatekeeperRequest") SEQ, 4, 8, 18, DECODE | EXT, - offsetof(RasMessage, gatekeeperRequest), _GatekeeperRequest}, - {FNAME("gatekeeperConfirm") SEQ, 2, 5, 14, DECODE | EXT, - offsetof(RasMessage, gatekeeperConfirm), _GatekeeperConfirm}, - {FNAME("gatekeeperReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, - {FNAME("registrationRequest") SEQ, 3, 10, 31, DECODE | EXT, - offsetof(RasMessage, registrationRequest), _RegistrationRequest}, - {FNAME("registrationConfirm") SEQ, 3, 7, 24, DECODE | EXT, - offsetof(RasMessage, registrationConfirm), _RegistrationConfirm}, - {FNAME("registrationReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, - {FNAME("unregistrationRequest") SEQ, 3, 5, 15, DECODE | EXT, - offsetof(RasMessage, unregistrationRequest), _UnregistrationRequest}, - {FNAME("unregistrationConfirm") SEQ, 1, 2, 6, STOP | EXT, 0, NULL}, - {FNAME("unregistrationReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, - {FNAME("admissionRequest") SEQ, 7, 16, 34, DECODE | EXT, - offsetof(RasMessage, admissionRequest), _AdmissionRequest}, - {FNAME("admissionConfirm") SEQ, 2, 6, 27, DECODE | EXT, - offsetof(RasMessage, admissionConfirm), _AdmissionConfirm}, - {FNAME("admissionReject") SEQ, 1, 3, 11, STOP | EXT, 0, NULL}, - {FNAME("bandwidthRequest") SEQ, 2, 7, 18, STOP | EXT, 0, NULL}, - {FNAME("bandwidthConfirm") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, - {FNAME("bandwidthReject") SEQ, 1, 4, 9, STOP | EXT, 0, NULL}, - {FNAME("disengageRequest") SEQ, 1, 6, 19, STOP | EXT, 0, NULL}, - {FNAME("disengageConfirm") SEQ, 1, 2, 9, STOP | EXT, 0, NULL}, - {FNAME("disengageReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, - {FNAME("locationRequest") SEQ, 2, 5, 17, DECODE | EXT, - offsetof(RasMessage, locationRequest), _LocationRequest}, - {FNAME("locationConfirm") SEQ, 1, 4, 19, DECODE | EXT, - offsetof(RasMessage, locationConfirm), _LocationConfirm}, - {FNAME("locationReject") SEQ, 1, 3, 10, STOP | EXT, 0, NULL}, - {FNAME("infoRequest") SEQ, 2, 4, 15, STOP | EXT, 0, NULL}, - {FNAME("infoRequestResponse") SEQ, 3, 8, 16, DECODE | EXT, - offsetof(RasMessage, infoRequestResponse), _InfoRequestResponse}, - {FNAME("nonStandardMessage") SEQ, 0, 2, 7, STOP | EXT, 0, NULL}, - {FNAME("unknownMessageResponse") SEQ, 0, 1, 5, STOP | EXT, 0, NULL}, - {FNAME("requestInProgress") SEQ, 4, 6, 6, STOP | EXT, 0, NULL}, - {FNAME("resourcesAvailableIndicate") SEQ, 4, 9, 11, STOP | EXT, 0, - NULL}, - {FNAME("resourcesAvailableConfirm") SEQ, 4, 6, 7, STOP | EXT, 0, - NULL}, - {FNAME("infoRequestAck") SEQ, 4, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("infoRequestNak") SEQ, 5, 7, 7, STOP | EXT, 0, NULL}, - {FNAME("serviceControlIndication") SEQ, 8, 10, 10, STOP | EXT, 0, - NULL}, - {FNAME("serviceControlResponse") SEQ, 7, 8, 8, STOP | EXT, 0, NULL}, -}; diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c new file mode 100644 index 000000000000..fb9ab0114c23 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_h323.c @@ -0,0 +1,596 @@ +/* + * H.323 extension for NAT alteration. + * + * Copyright (c) 2006 Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + * + * Based on the 'brute force' H.323 NAT module by + * Jozsef Kadlecsik + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/****************************************************************************/ +static int set_addr(struct sk_buff **pskb, + unsigned char **data, int dataoff, + unsigned int addroff, __be32 ip, __be16 port) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = ip_conntrack_get(*pskb, &ctinfo); + struct { + __be32 ip; + __be16 port; + } __attribute__ ((__packed__)) buf; + struct tcphdr _tcph, *th; + + buf.ip = ip; + buf.port = port; + addroff += dataoff; + + if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) { + if (!nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, + addroff, sizeof(buf), + (char *) &buf, sizeof(buf))) { + if (net_ratelimit()) + printk("nf_nat_h323: nf_nat_mangle_tcp_packet" + " error\n"); + return -1; + } + + /* Relocate data pointer */ + th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, + sizeof(_tcph), &_tcph); + if (th == NULL) + return -1; + *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + + th->doff * 4 + dataoff; + } else { + if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + addroff, sizeof(buf), + (char *) &buf, sizeof(buf))) { + if (net_ratelimit()) + printk("nf_nat_h323: nf_nat_mangle_udp_packet" + " error\n"); + return -1; + } + /* nf_nat_mangle_udp_packet uses skb_make_writable() to copy + * or pull everything in a linear buffer, so we can safely + * use the skb pointers now */ + *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + + sizeof(struct udphdr); + } + + return 0; +} + +/****************************************************************************/ +static int set_h225_addr(struct sk_buff **pskb, + unsigned char **data, int dataoff, + TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 port) +{ + return set_addr(pskb, data, dataoff, taddr->ipAddress.ip, + addr->ip, port); +} + +/****************************************************************************/ +static int set_h245_addr(struct sk_buff **pskb, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 port) +{ + return set_addr(pskb, data, dataoff, + taddr->unicastAddress.iPAddress.network, + addr->ip, port); +} + +/****************************************************************************/ +static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int i; + __be16 port; + union nf_conntrack_address addr; + + for (i = 0; i < count; i++) { + if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) { + if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && + port == info->sig_port[dir]) { + /* GW->GK */ + + /* Fix for Gnomemeeting */ + if (i > 0 && + get_h225_addr(ct, *data, &taddr[0], + &addr, &port) && + (ntohl(addr.ip) & 0xff000000) == 0x7f000000) + i = 0; + + DEBUGP + ("nf_nat_ras: set signal address " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(ip), port, + NIPQUAD(ct->tuplehash[!dir].tuple.dst. + ip), info->sig_port[!dir]); + return set_h225_addr(pskb, data, 0, &taddr[i], + &ct->tuplehash[!dir]. + tuple.dst.u3, + info->sig_port[!dir]); + } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && + port == info->sig_port[dir]) { + /* GK->GW */ + DEBUGP + ("nf_nat_ras: set signal address " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(ip), port, + NIPQUAD(ct->tuplehash[!dir].tuple.src. + ip), info->sig_port[!dir]); + return set_h225_addr(pskb, data, 0, &taddr[i], + &ct->tuplehash[!dir]. + tuple.src.u3, + info->sig_port[!dir]); + } + } + } + + return 0; +} + +/****************************************************************************/ +static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) +{ + int dir = CTINFO2DIR(ctinfo); + int i; + __be16 port; + union nf_conntrack_address addr; + + for (i = 0; i < count; i++) { + if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) && + addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && + port == ct->tuplehash[dir].tuple.src.u.udp.port) { + DEBUGP("nf_nat_ras: set rasAddress " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(ip), ntohs(port), + NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip), + ntohs(ct->tuplehash[!dir].tuple.dst.u.udp. + port)); + return set_h225_addr(pskb, data, 0, &taddr[i], + &ct->tuplehash[!dir].tuple.dst.u3, + ct->tuplehash[!dir].tuple. + dst.u.udp.port); + } + } + + return 0; +} + +/****************************************************************************/ +static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + __be16 port, __be16 rtp_port, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int i; + u_int16_t nated_port; + + /* Set expectations for NAT */ + rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; + rtp_exp->expectfn = nf_nat_follow_master; + rtp_exp->dir = !dir; + rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; + rtcp_exp->expectfn = nf_nat_follow_master; + rtcp_exp->dir = !dir; + + /* Lookup existing expects */ + for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) { + if (info->rtp_port[i][dir] == rtp_port) { + /* Expected */ + + /* Use allocated ports first. This will refresh + * the expects */ + rtp_exp->tuple.dst.u.udp.port = info->rtp_port[i][dir]; + rtcp_exp->tuple.dst.u.udp.port = + htons(ntohs(info->rtp_port[i][dir]) + 1); + break; + } else if (info->rtp_port[i][dir] == 0) { + /* Not expected */ + break; + } + } + + /* Run out of expectations */ + if (i >= H323_RTP_CHANNEL_MAX) { + if (net_ratelimit()) + printk("nf_nat_h323: out of expectations\n"); + return 0; + } + + /* Try to get a pair of ports. */ + for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port); + nated_port != 0; nated_port += 2) { + rtp_exp->tuple.dst.u.udp.port = htons(nated_port); + if (nf_conntrack_expect_related(rtp_exp) == 0) { + rtcp_exp->tuple.dst.u.udp.port = + htons(nated_port + 1); + if (nf_conntrack_expect_related(rtcp_exp) == 0) + break; + nf_conntrack_unexpect_related(rtp_exp); + } + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_h323: out of RTP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h245_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons((port & htons(1)) ? nated_port + 1 : + nated_port)) == 0) { + /* Save ports */ + info->rtp_port[i][dir] = rtp_port; + info->rtp_port[i][!dir] = htons(nated_port); + } else { + nf_conntrack_unexpect_related(rtp_exp); + nf_conntrack_unexpect_related(rtcp_exp); + return -1; + } + + /* Success */ + DEBUGP("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(rtp_exp->tuple.src.ip), + ntohs(rtp_exp->tuple.src.u.udp.port), + NIPQUAD(rtp_exp->tuple.dst.ip), + ntohs(rtp_exp->tuple.dst.u.udp.port)); + DEBUGP("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(rtcp_exp->tuple.src.ip), + ntohs(rtcp_exp->tuple.src.u.udp.port), + NIPQUAD(rtcp_exp->tuple.dst.ip), + ntohs(rtcp_exp->tuple.dst.u.udp.port)); + + return 0; +} + +/****************************************************************************/ +static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) +{ + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port = ntohs(port); + + /* Set expectations for NAT */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = nf_nat_follow_master; + exp->dir = !dir; + + /* Try to get same port: if not, try to change it. */ + for (; nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_h323: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h245_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) < 0) { + nf_conntrack_unexpect_related(exp); + return -1; + } + + DEBUGP("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/****************************************************************************/ +static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port = ntohs(port); + + /* Set expectations for NAT */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = nf_nat_follow_master; + exp->dir = !dir; + + /* Check existing expects */ + if (info->sig_port[dir] == port) + nated_port = ntohs(info->sig_port[!dir]); + + /* Try to get same port: if not, try to change it. */ + for (; nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_q931: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h225_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) == 0) { + /* Save ports */ + info->sig_port[dir] = port; + info->sig_port[!dir] = htons(nated_port); + } else { + nf_conntrack_unexpect_related(exp); + return -1; + } + + DEBUGP("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/**************************************************************************** + * This conntrack expect function replaces nf_conntrack_q931_expect() + * which was set by nf_conntrack_h323.c. + ****************************************************************************/ +static void ip_nat_q931_expect(struct nf_conn *new, + struct nf_conntrack_expect *this) +{ + struct ip_nat_range range; + + if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */ + nf_nat_follow_master(new, this); + return; + } + + /* This must be a fresh one. */ + BUG_ON(new->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; + + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = this->saved_proto; + range.min_ip = range.max_ip = + new->master->tuplehash[!this->dir].tuple.src.u3.ip; + + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); +} + +/****************************************************************************/ +static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, TransportAddress *taddr, int idx, + __be16 port, struct nf_conntrack_expect *exp) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port = ntohs(port); + union nf_conntrack_address addr; + + /* Set expectations for NAT */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = ip_nat_q931_expect; + exp->dir = !dir; + + /* Check existing expects */ + if (info->sig_port[dir] == port) + nated_port = ntohs(info->sig_port[!dir]); + + /* Try to get same port: if not, try to change it. */ + for (; nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_ras: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h225_addr(pskb, data, 0, &taddr[idx], + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) == 0) { + /* Save ports */ + info->sig_port[dir] = port; + info->sig_port[!dir] = htons(nated_port); + + /* Fix for Gnomemeeting */ + if (idx > 0 && + get_h225_addr(ct, *data, &taddr[0], &addr, &port) && + (ntohl(addr.ip) & 0xff000000) == 0x7f000000) { + set_h225_addr_hook(pskb, data, 0, &taddr[0], + &ct->tuplehash[!dir].tuple.dst.u3, + info->sig_port[!dir]); + } + } else { + nf_conntrack_unexpect_related(exp); + return -1; + } + + /* Success */ + DEBUGP("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/****************************************************************************/ +static void ip_nat_callforwarding_expect(struct nf_conn *new, + struct nf_conntrack_expect *this) +{ + struct nf_nat_range range; + + /* This must be a fresh one. */ + BUG_ON(new->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; + + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = this->saved_proto; + range.min_ip = range.max_ip = this->saved_ip; + + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); +} + +/****************************************************************************/ +static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) +{ + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port; + + /* Set expectations for NAT */ + exp->saved_ip = exp->tuple.dst.u3.ip; + exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip; + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = ip_nat_callforwarding_expect; + exp->dir = !dir; + + /* Try to get same port: if not, try to change it. */ + for (nated_port = ntohs(port); nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_q931: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (!set_h225_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) == 0) { + nf_conntrack_unexpect_related(exp); + return -1; + } + + /* Success */ + DEBUGP("nf_nat_q931: expect Call Forwarding " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/****************************************************************************/ +static int __init init(void) +{ + BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL); + BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL); + BUG_ON(rcu_dereference(nat_t120_hook) != NULL); + BUG_ON(rcu_dereference(nat_h245_hook) != NULL); + BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL); + BUG_ON(rcu_dereference(nat_q931_hook) != NULL); + + rcu_assign_pointer(set_h245_addr_hook, set_h245_addr); + rcu_assign_pointer(set_h225_addr_hook, set_h225_addr); + rcu_assign_pointer(set_sig_addr_hook, set_sig_addr); + rcu_assign_pointer(set_ras_addr_hook, set_ras_addr); + rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp); + rcu_assign_pointer(nat_t120_hook, nat_t120); + rcu_assign_pointer(nat_h245_hook, nat_h245); + rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding); + rcu_assign_pointer(nat_q931_hook, nat_q931); + + DEBUGP("nf_nat_h323: init success\n"); + return 0; +} + +/****************************************************************************/ +static void __exit fini(void) +{ + rcu_assign_pointer(set_h245_addr_hook, NULL); + rcu_assign_pointer(set_h225_addr_hook, NULL); + rcu_assign_pointer(set_sig_addr_hook, NULL); + rcu_assign_pointer(set_ras_addr_hook, NULL); + rcu_assign_pointer(nat_rtp_rtcp_hook, NULL); + rcu_assign_pointer(nat_t120_hook, NULL); + rcu_assign_pointer(nat_h245_hook, NULL); + rcu_assign_pointer(nat_callforwarding_hook, NULL); + rcu_assign_pointer(nat_q931_hook, NULL); + synchronize_rcu(); +} + +/****************************************************************************/ +module_init(init); +module_exit(fini); + +MODULE_AUTHOR("Jing Min Zhao "); +MODULE_DESCRIPTION("H.323 NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_h323"); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f85fd43b344b..d8f3451c95b6 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -160,6 +160,25 @@ config NF_CONNTRACK_FTP To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_H323 + tristate "H.323 protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + help + H.323 is a VoIP signalling protocol from ITU-T. As one of the most + important VoIP protocols, it is widely used by voice hardware and + software including voice gateways, IP phones, Netmeeting, OpenPhone, + Gnomemeeting, etc. + + With this module you can support H.323 on a connection tracking/NAT + firewall. + + This module supports RAS, Fast Start, H.245 Tunnelling, Call + Forwarding, RTP/RTCP and T.120 based audio, video, fax, chat, + whiteboard, file transfer, etc. For more information, please + visit http://nath323.sourceforge.net/. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CT_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index a5ee93817427..69b554576b6b 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -20,8 +20,11 @@ obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o # connection tracking helpers +nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o + obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o +obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o diff --git a/net/netfilter/nf_conntrack_h323_asn1.c b/net/netfilter/nf_conntrack_h323_asn1.c new file mode 100644 index 000000000000..f6fad713d484 --- /dev/null +++ b/net/netfilter/nf_conntrack_h323_asn1.c @@ -0,0 +1,874 @@ +/**************************************************************************** + * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323 + * conntrack/NAT module. + * + * Copyright (c) 2006 by Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + * + * See ip_conntrack_helper_h323_asn1.h for details. + * + ****************************************************************************/ + +#ifdef __KERNEL__ +#include +#else +#include +#endif +#include + +/* Trace Flag */ +#ifndef H323_TRACE +#define H323_TRACE 0 +#endif + +#if H323_TRACE +#define TAB_SIZE 4 +#define IFTHEN(cond, act) if(cond){act;} +#ifdef __KERNEL__ +#define PRINT printk +#else +#define PRINT printf +#endif +#define FNAME(name) name, +#else +#define IFTHEN(cond, act) +#define PRINT(fmt, args...) +#define FNAME(name) +#endif + +/* ASN.1 Types */ +#define NUL 0 +#define BOOL 1 +#define OID 2 +#define INT 3 +#define ENUM 4 +#define BITSTR 5 +#define NUMSTR 6 +#define NUMDGT 6 +#define TBCDSTR 6 +#define OCTSTR 7 +#define PRTSTR 7 +#define IA5STR 7 +#define GENSTR 7 +#define BMPSTR 8 +#define SEQ 9 +#define SET 9 +#define SEQOF 10 +#define SETOF 10 +#define CHOICE 11 + +/* Constraint Types */ +#define FIXD 0 +/* #define BITS 1-8 */ +#define BYTE 9 +#define WORD 10 +#define CONS 11 +#define SEMI 12 +#define UNCO 13 + +/* ASN.1 Type Attributes */ +#define SKIP 0 +#define STOP 1 +#define DECODE 2 +#define EXT 4 +#define OPEN 8 +#define OPT 16 + + +/* ASN.1 Field Structure */ +typedef struct field_t { +#if H323_TRACE + char *name; +#endif + unsigned char type; + unsigned char sz; + unsigned char lb; + unsigned char ub; + unsigned short attr; + unsigned short offset; + struct field_t *fields; +} field_t; + +/* Bit Stream */ +typedef struct { + unsigned char *buf; + unsigned char *beg; + unsigned char *end; + unsigned char *cur; + unsigned bit; +} bitstr_t; + +/* Tool Functions */ +#define INC_BIT(bs) if((++bs->bit)>7){bs->cur++;bs->bit=0;} +#define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;} +#define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;} +#define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND) +static unsigned get_len(bitstr_t * bs); +static unsigned get_bit(bitstr_t * bs); +static unsigned get_bits(bitstr_t * bs, unsigned b); +static unsigned get_bitmap(bitstr_t * bs, unsigned b); +static unsigned get_uint(bitstr_t * bs, int b); + +/* Decoder Functions */ +static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_int(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level); + +/* Decoder Functions Vector */ +typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int); +static decoder_t Decoders[] = { + decode_nul, + decode_bool, + decode_oid, + decode_int, + decode_enum, + decode_bitstr, + decode_numstr, + decode_octstr, + decode_bmpstr, + decode_seq, + decode_seqof, + decode_choice, +}; + +/**************************************************************************** + * H.323 Types + ****************************************************************************/ +#include "nf_conntrack_h323_types.c" + +/**************************************************************************** + * Functions + ****************************************************************************/ +/* Assume bs is aligned && v < 16384 */ +unsigned get_len(bitstr_t * bs) +{ + unsigned v; + + v = *bs->cur++; + + if (v & 0x80) { + v &= 0x3f; + v <<= 8; + v += *bs->cur++; + } + + return v; +} + +/****************************************************************************/ +unsigned get_bit(bitstr_t * bs) +{ + unsigned b = (*bs->cur) & (0x80 >> bs->bit); + + INC_BIT(bs); + + return b; +} + +/****************************************************************************/ +/* Assume b <= 8 */ +unsigned get_bits(bitstr_t * bs, unsigned b) +{ + unsigned v, l; + + v = (*bs->cur) & (0xffU >> bs->bit); + l = b + bs->bit; + + if (l < 8) { + v >>= 8 - l; + bs->bit = l; + } else if (l == 8) { + bs->cur++; + bs->bit = 0; + } else { /* l > 8 */ + + v <<= 8; + v += *(++bs->cur); + v >>= 16 - l; + bs->bit = l - 8; + } + + return v; +} + +/****************************************************************************/ +/* Assume b <= 32 */ +unsigned get_bitmap(bitstr_t * bs, unsigned b) +{ + unsigned v, l, shift, bytes; + + if (!b) + return 0; + + l = bs->bit + b; + + if (l < 8) { + v = (unsigned) (*bs->cur) << (bs->bit + 24); + bs->bit = l; + } else if (l == 8) { + v = (unsigned) (*bs->cur++) << (bs->bit + 24); + bs->bit = 0; + } else { + for (bytes = l >> 3, shift = 24, v = 0; bytes; + bytes--, shift -= 8) + v |= (unsigned) (*bs->cur++) << shift; + + if (l < 32) { + v |= (unsigned) (*bs->cur) << shift; + v <<= bs->bit; + } else if (l > 32) { + v <<= bs->bit; + v |= (*bs->cur) >> (8 - bs->bit); + } + + bs->bit = l & 0x7; + } + + v &= 0xffffffff << (32 - b); + + return v; +} + +/**************************************************************************** + * Assume bs is aligned and sizeof(unsigned int) == 4 + ****************************************************************************/ +unsigned get_uint(bitstr_t * bs, int b) +{ + unsigned v = 0; + + switch (b) { + case 4: + v |= *bs->cur++; + v <<= 8; + case 3: + v |= *bs->cur++; + v <<= 8; + case 2: + v |= *bs->cur++; + v <<= 8; + case 1: + v |= *bs->cur++; + break; + } + return v; +} + +/****************************************************************************/ +int decode_nul(bitstr_t * bs, field_t * f, char *base, int level) +{ + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_bool(bitstr_t * bs, field_t * f, char *base, int level) +{ + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + INC_BIT(bs); + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_oid(bitstr_t * bs, field_t * f, char *base, int level) +{ + int len; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 1); + len = *bs->cur++; + bs->cur += len; + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_int(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned len; + + PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); + + switch (f->sz) { + case BYTE: /* Range == 256 */ + BYTE_ALIGN(bs); + bs->cur++; + break; + case WORD: /* 257 <= Range <= 64K */ + BYTE_ALIGN(bs); + bs->cur += 2; + break; + case CONS: /* 64K < Range < 4G */ + len = get_bits(bs, 2) + 1; + BYTE_ALIGN(bs); + if (base && (f->attr & DECODE)) { /* timeToLive */ + unsigned v = get_uint(bs, len) + f->lb; + PRINT(" = %u", v); + *((unsigned *) (base + f->offset)) = v; + } + bs->cur += len; + break; + case UNCO: + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 2); + len = get_len(bs); + bs->cur += len; + break; + default: /* 2 <= Range <= 255 */ + INC_BITS(bs, f->sz); + break; + } + + PRINT("\n"); + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_enum(bitstr_t * bs, field_t * f, char *base, int level) +{ + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + if ((f->attr & EXT) && get_bit(bs)) { + INC_BITS(bs, 7); + } else { + INC_BITS(bs, f->sz); + } + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned len; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + BYTE_ALIGN(bs); + switch (f->sz) { + case FIXD: /* fixed length > 16 */ + len = f->lb; + break; + case WORD: /* 2-byte length */ + CHECK_BOUND(bs, 2); + len = (*bs->cur++) << 8; + len += (*bs->cur++) + f->lb; + break; + case SEMI: + CHECK_BOUND(bs, 2); + len = get_len(bs); + break; + default: + len = 0; + break; + } + + bs->cur += len >> 3; + bs->bit = len & 7; + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned len; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + /* 2 <= Range <= 255 */ + len = get_bits(bs, f->sz) + f->lb; + + BYTE_ALIGN(bs); + INC_BITS(bs, (len << 2)); + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned len; + + PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); + + switch (f->sz) { + case FIXD: /* Range == 1 */ + if (f->lb > 2) { + BYTE_ALIGN(bs); + if (base && (f->attr & DECODE)) { + /* The IP Address */ + IFTHEN(f->lb == 4, + PRINT(" = %d.%d.%d.%d:%d", + bs->cur[0], bs->cur[1], + bs->cur[2], bs->cur[3], + bs->cur[4] * 256 + bs->cur[5])); + *((unsigned *) (base + f->offset)) = + bs->cur - bs->buf; + } + } + len = f->lb; + break; + case BYTE: /* Range == 256 */ + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 1); + len = (*bs->cur++) + f->lb; + break; + case SEMI: + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 2); + len = get_len(bs) + f->lb; + break; + default: /* 2 <= Range <= 255 */ + len = get_bits(bs, f->sz) + f->lb; + BYTE_ALIGN(bs); + break; + } + + bs->cur += len; + + PRINT("\n"); + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned len; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + switch (f->sz) { + case BYTE: /* Range == 256 */ + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 1); + len = (*bs->cur++) + f->lb; + break; + default: /* 2 <= Range <= 255 */ + len = get_bits(bs, f->sz) + f->lb; + BYTE_ALIGN(bs); + break; + } + + bs->cur += len << 1; + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len; + int err; + field_t *son; + unsigned char *beg = NULL; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + /* Decode? */ + base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; + + /* Extensible? */ + ext = (f->attr & EXT) ? get_bit(bs) : 0; + + /* Get fields bitmap */ + bmp = get_bitmap(bs, f->sz); + if (base) + *(unsigned *) base = bmp; + + /* Decode the root components */ + for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) { + if (son->attr & STOP) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", + son->name); + return H323_ERROR_STOP; + } + + if (son->attr & OPT) { /* Optional component */ + if (!((0x80000000U >> (opt++)) & bmp)) /* Not exist */ + continue; + } + + /* Decode */ + if (son->attr & OPEN) { /* Open field */ + CHECK_BOUND(bs, 2); + len = get_len(bs); + CHECK_BOUND(bs, len); + if (!base) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, + " ", son->name); + bs->cur += len; + continue; + } + beg = bs->cur; + + /* Decode */ + if ((err = (Decoders[son->type]) (bs, son, base, + level + 1)) < + H323_ERROR_NONE) + return err; + + bs->cur = beg + len; + bs->bit = 0; + } else if ((err = (Decoders[son->type]) (bs, son, base, + level + 1)) < + H323_ERROR_NONE) + return err; + } + + /* No extension? */ + if (!ext) + return H323_ERROR_NONE; + + /* Get the extension bitmap */ + bmp2_len = get_bits(bs, 7) + 1; + CHECK_BOUND(bs, (bmp2_len + 7) >> 3); + bmp2 = get_bitmap(bs, bmp2_len); + bmp |= bmp2 >> f->sz; + if (base) + *(unsigned *) base = bmp; + BYTE_ALIGN(bs); + + /* Decode the extension components */ + for (opt = 0; opt < bmp2_len; opt++, i++, son++) { + if (i < f->ub && son->attr & STOP) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", + son->name); + return H323_ERROR_STOP; + } + + if (!((0x80000000 >> opt) & bmp2)) /* Not present */ + continue; + + /* Check Range */ + if (i >= f->ub) { /* Newer Version? */ + CHECK_BOUND(bs, 2); + len = get_len(bs); + CHECK_BOUND(bs, len); + bs->cur += len; + continue; + } + + CHECK_BOUND(bs, 2); + len = get_len(bs); + CHECK_BOUND(bs, len); + if (!base || !(son->attr & DECODE)) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", + son->name); + bs->cur += len; + continue; + } + beg = bs->cur; + + if ((err = (Decoders[son->type]) (bs, son, base, + level + 1)) < + H323_ERROR_NONE) + return err; + + bs->cur = beg + len; + bs->bit = 0; + } + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned count, effective_count = 0, i, len = 0; + int err; + field_t *son; + unsigned char *beg = NULL; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + /* Decode? */ + base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; + + /* Decode item count */ + switch (f->sz) { + case BYTE: + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 1); + count = *bs->cur++; + break; + case WORD: + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 2); + count = *bs->cur++; + count <<= 8; + count = *bs->cur++; + break; + case SEMI: + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 2); + count = get_len(bs); + break; + default: + count = get_bits(bs, f->sz); + break; + } + count += f->lb; + + /* Write Count */ + if (base) { + effective_count = count > f->ub ? f->ub : count; + *(unsigned *) base = effective_count; + base += sizeof(unsigned); + } + + /* Decode nested field */ + son = f->fields; + if (base) + base -= son->offset; + for (i = 0; i < count; i++) { + if (son->attr & OPEN) { + BYTE_ALIGN(bs); + len = get_len(bs); + CHECK_BOUND(bs, len); + if (!base || !(son->attr & DECODE)) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, + " ", son->name); + bs->cur += len; + continue; + } + beg = bs->cur; + + if ((err = (Decoders[son->type]) (bs, son, + i < + effective_count ? + base : NULL, + level + 1)) < + H323_ERROR_NONE) + return err; + + bs->cur = beg + len; + bs->bit = 0; + } else + if ((err = (Decoders[son->type]) (bs, son, + i < + effective_count ? + base : NULL, + level + 1)) < + H323_ERROR_NONE) + return err; + + if (base) + base += son->offset; + } + + return H323_ERROR_NONE; +} + + +/****************************************************************************/ +int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned type, ext, len = 0; + int err; + field_t *son; + unsigned char *beg = NULL; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + /* Decode? */ + base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; + + /* Decode the choice index number */ + if ((f->attr & EXT) && get_bit(bs)) { + ext = 1; + type = get_bits(bs, 7) + f->lb; + } else { + ext = 0; + type = get_bits(bs, f->sz); + } + + /* Write Type */ + if (base) + *(unsigned *) base = type; + + /* Check Range */ + if (type >= f->ub) { /* Newer version? */ + BYTE_ALIGN(bs); + len = get_len(bs); + CHECK_BOUND(bs, len); + bs->cur += len; + return H323_ERROR_NONE; + } + + /* Transfer to son level */ + son = &f->fields[type]; + if (son->attr & STOP) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name); + return H323_ERROR_STOP; + } + + if (ext || (son->attr & OPEN)) { + BYTE_ALIGN(bs); + len = get_len(bs); + CHECK_BOUND(bs, len); + if (!base || !(son->attr & DECODE)) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", + son->name); + bs->cur += len; + return H323_ERROR_NONE; + } + beg = bs->cur; + + if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < + H323_ERROR_NONE) + return err; + + bs->cur = beg + len; + bs->bit = 0; + } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < + H323_ERROR_NONE) + return err; + + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras) +{ + static field_t ras_message = { + FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT, + 0, _RasMessage + }; + bitstr_t bs; + + bs.buf = bs.beg = bs.cur = buf; + bs.end = buf + sz; + bs.bit = 0; + + return decode_choice(&bs, &ras_message, (char *) ras, 0); +} + +/****************************************************************************/ +static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg, + size_t sz, H323_UserInformation * uuie) +{ + static field_t h323_userinformation = { + FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT, + 0, _H323_UserInformation + }; + bitstr_t bs; + + bs.buf = buf; + bs.beg = bs.cur = beg; + bs.end = beg + sz; + bs.bit = 0; + + return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0); +} + +/****************************************************************************/ +int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, + MultimediaSystemControlMessage * + mscm) +{ + static field_t multimediasystemcontrolmessage = { + FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4, + DECODE | EXT, 0, _MultimediaSystemControlMessage + }; + bitstr_t bs; + + bs.buf = bs.beg = bs.cur = buf; + bs.end = buf + sz; + bs.bit = 0; + + return decode_choice(&bs, &multimediasystemcontrolmessage, + (char *) mscm, 0); +} + +/****************************************************************************/ +int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931) +{ + unsigned char *p = buf; + int len; + + if (!p || sz < 1) + return H323_ERROR_BOUND; + + /* Protocol Discriminator */ + if (*p != 0x08) { + PRINT("Unknown Protocol Discriminator\n"); + return H323_ERROR_RANGE; + } + p++; + sz--; + + /* CallReferenceValue */ + if (sz < 1) + return H323_ERROR_BOUND; + len = *p++; + sz--; + if (sz < len) + return H323_ERROR_BOUND; + p += len; + sz -= len; + + /* Message Type */ + if (sz < 1) + return H323_ERROR_BOUND; + q931->MessageType = *p++; + PRINT("MessageType = %02X\n", q931->MessageType); + if (*p & 0x80) { + p++; + sz--; + } + + /* Decode Information Elements */ + while (sz > 0) { + if (*p == 0x7e) { /* UserUserIE */ + if (sz < 3) + break; + p++; + len = *p++ << 8; + len |= *p++; + sz -= 3; + if (sz < len) + break; + p++; + len--; + return DecodeH323_UserInformation(buf, p, len, + &q931->UUIE); + } + p++; + sz--; + if (sz < 1) + break; + len = *p++; + if (sz < len) + break; + p += len; + sz -= len; + } + + PRINT("Q.931 UUIE not found\n"); + + return H323_ERROR_BOUND; +} diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c new file mode 100644 index 000000000000..6d8568959f82 --- /dev/null +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -0,0 +1,1856 @@ +/* + * H.323 connection tracking helper + * + * Copyright (c) 2006 Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + * + * Based on the 'brute force' H.323 connection tracking module by + * Jozsef Kadlecsik + * + * For more information, please see http://nath323.sourceforge.net/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/* Parameters */ +static unsigned int default_rrq_ttl __read_mostly = 300; +module_param(default_rrq_ttl, uint, 0600); +MODULE_PARM_DESC(default_rrq_ttl, "use this TTL if it's missing in RRQ"); + +static int gkrouted_only __read_mostly = 1; +module_param(gkrouted_only, int, 0600); +MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper"); + +static int callforward_filter __read_mostly = 1; +module_param(callforward_filter, bool, 0600); +MODULE_PARM_DESC(callforward_filter, "only create call forwarding expectations " + "if both endpoints are on different sides " + "(determined by routing information)"); + +/* Hooks for NAT */ +int (*set_h245_addr_hook) (struct sk_buff **pskb, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 port) + __read_mostly; +int (*set_h225_addr_hook) (struct sk_buff **pskb, + unsigned char **data, int dataoff, + TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 port) + __read_mostly; +int (*set_sig_addr_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) __read_mostly; +int (*set_ras_addr_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) __read_mostly; +int (*nat_rtp_rtcp_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + __be16 port, __be16 rtp_port, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp) __read_mostly; +int (*nat_t120_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) __read_mostly; +int (*nat_h245_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) __read_mostly; +int (*nat_callforwarding_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) __read_mostly; +int (*nat_q931_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, TransportAddress *taddr, int idx, + __be16 port, struct nf_conntrack_expect *exp) + __read_mostly; + +static DEFINE_SPINLOCK(nf_h323_lock); +static char *h323_buffer; + +static struct nf_conntrack_helper nf_conntrack_helper_h245; +static struct nf_conntrack_helper nf_conntrack_helper_q931[]; +static struct nf_conntrack_helper nf_conntrack_helper_ras[]; + +/****************************************************************************/ +static int get_tpkt_data(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + unsigned char **data, int *datalen, int *dataoff) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + struct tcphdr _tcph, *th; + int tcpdatalen; + int tcpdataoff; + unsigned char *tpkt; + int tpktlen; + int tpktoff; + + /* Get TCP header */ + th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph); + if (th == NULL) + return 0; + + /* Get TCP data offset */ + tcpdataoff = protoff + th->doff * 4; + + /* Get TCP data length */ + tcpdatalen = (*pskb)->len - tcpdataoff; + if (tcpdatalen <= 0) /* No TCP data */ + goto clear_out; + + if (*data == NULL) { /* first TPKT */ + /* Get first TPKT pointer */ + tpkt = skb_header_pointer(*pskb, tcpdataoff, tcpdatalen, + h323_buffer); + BUG_ON(tpkt == NULL); + + /* Validate TPKT identifier */ + if (tcpdatalen < 4 || tpkt[0] != 0x03 || tpkt[1] != 0) { + /* Netmeeting sends TPKT header and data separately */ + if (info->tpkt_len[dir] > 0) { + DEBUGP("nf_ct_h323: previous packet " + "indicated separate TPKT data of %hu " + "bytes\n", info->tpkt_len[dir]); + if (info->tpkt_len[dir] <= tcpdatalen) { + /* Yes, there was a TPKT header + * received */ + *data = tpkt; + *datalen = info->tpkt_len[dir]; + *dataoff = 0; + goto out; + } + + /* Fragmented TPKT */ + if (net_ratelimit()) + printk("nf_ct_h323: " + "fragmented TPKT\n"); + goto clear_out; + } + + /* It is not even a TPKT */ + return 0; + } + tpktoff = 0; + } else { /* Next TPKT */ + tpktoff = *dataoff + *datalen; + tcpdatalen -= tpktoff; + if (tcpdatalen <= 4) /* No more TPKT */ + goto clear_out; + tpkt = *data + *datalen; + + /* Validate TPKT identifier */ + if (tpkt[0] != 0x03 || tpkt[1] != 0) + goto clear_out; + } + + /* Validate TPKT length */ + tpktlen = tpkt[2] * 256 + tpkt[3]; + if (tpktlen < 4) + goto clear_out; + if (tpktlen > tcpdatalen) { + if (tcpdatalen == 4) { /* Separate TPKT header */ + /* Netmeeting sends TPKT header and data separately */ + DEBUGP("nf_ct_h323: separate TPKT header indicates " + "there will be TPKT data of %hu bytes\n", + tpktlen - 4); + info->tpkt_len[dir] = tpktlen - 4; + return 0; + } + + if (net_ratelimit()) + printk("nf_ct_h323: incomplete TPKT (fragmented?)\n"); + goto clear_out; + } + + /* This is the encapsulated data */ + *data = tpkt + 4; + *datalen = tpktlen - 4; + *dataoff = tpktoff + 4; + + out: + /* Clear TPKT length */ + info->tpkt_len[dir] = 0; + return 1; + + clear_out: + info->tpkt_len[dir] = 0; + return 0; +} + +/****************************************************************************/ +static int get_h245_addr(struct nf_conn *ct, unsigned char *data, + H245_TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 *port) +{ + unsigned char *p; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + int len; + + if (taddr->choice != eH245_TransportAddress_unicastAddress) + return 0; + + switch (taddr->unicastAddress.choice) { + case eUnicastAddress_iPAddress: + if (family != AF_INET) + return 0; + p = data + taddr->unicastAddress.iPAddress.network; + len = 4; + break; + case eUnicastAddress_iP6Address: + if (family != AF_INET6) + return 0; + p = data + taddr->unicastAddress.iP6Address.network; + len = 16; + break; + default: + return 0; + } + + memcpy(addr, p, len); + memset((void *)addr + len, 0, sizeof(*addr) - len); + memcpy(port, p + len, sizeof(__be16)); + + return 1; +} + +/****************************************************************************/ +static int expect_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + __be16 rtp_port, rtcp_port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *rtp_exp; + struct nf_conntrack_expect *rtcp_exp; + typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp; + + /* Read RTP or RTCP address */ + if (!get_h245_addr(ct, *data, taddr, &addr, &port) || + memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) || + port == 0) + return 0; + + /* RTP port is even */ + port &= htons(~1); + rtp_port = port; + rtcp_port = htons(ntohs(port) + 1); + + /* Create expect for RTP */ + if ((rtp_exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(rtp_exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_UDP, NULL, &rtp_port); + + /* Create expect for RTCP */ + if ((rtcp_exp = nf_conntrack_expect_alloc(ct)) == NULL) { + nf_conntrack_expect_put(rtp_exp); + return -1; + } + nf_conntrack_expect_init(rtcp_exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_UDP, NULL, &rtcp_port); + + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + sizeof(ct->tuplehash[dir].tuple.src.u3)) && + (nat_rtp_rtcp = rcu_dereference(nat_rtp_rtcp_hook)) && + ct->status & IPS_NAT_MASK) { + /* NAT needed */ + ret = nat_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + taddr, port, rtp_port, rtp_exp, rtcp_exp); + } else { /* Conntrack only */ + if (nf_conntrack_expect_related(rtp_exp) == 0) { + if (nf_conntrack_expect_related(rtcp_exp) == 0) { + DEBUGP("nf_ct_h323: expect RTP "); + NF_CT_DUMP_TUPLE(&rtp_exp->tuple); + DEBUGP("nf_ct_h323: expect RTCP "); + NF_CT_DUMP_TUPLE(&rtcp_exp->tuple); + } else { + nf_conntrack_unexpect_related(rtp_exp); + ret = -1; + } + } else + ret = -1; + } + + nf_conntrack_expect_put(rtp_exp); + nf_conntrack_expect_put(rtcp_exp); + + return ret; +} + +/****************************************************************************/ +static int expect_t120(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + typeof(nat_t120_hook) nat_t120; + + /* Read T.120 address */ + if (!get_h245_addr(ct, *data, taddr, &addr, &port) || + memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) || + port == 0) + return 0; + + /* Create expect for T.120 connections */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple channels */ + + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + sizeof(ct->tuplehash[dir].tuple.src.u3)) && + (nat_t120 = rcu_dereference(nat_t120_hook)) && + ct->status & IPS_NAT_MASK) { + /* NAT needed */ + ret = nat_t120(pskb, ct, ctinfo, data, dataoff, taddr, + port, exp); + } else { /* Conntrack only */ + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_h323: expect T.120 "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + } + + nf_conntrack_expect_put(exp); + + return ret; +} + +/****************************************************************************/ +static int process_h245_channel(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H2250LogicalChannelParameters *channel) +{ + int ret; + + if (channel->options & eH2250LogicalChannelParameters_mediaChannel) { + /* RTP */ + ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + &channel->mediaChannel); + if (ret < 0) + return -1; + } + + if (channel-> + options & eH2250LogicalChannelParameters_mediaControlChannel) { + /* RTCP */ + ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + &channel->mediaControlChannel); + if (ret < 0) + return -1; + } + + return 0; +} + +/****************************************************************************/ +static int process_olc(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + OpenLogicalChannel *olc) +{ + int ret; + + DEBUGP("nf_ct_h323: OpenLogicalChannel\n"); + + if (olc->forwardLogicalChannelParameters.multiplexParameters.choice == + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters) + { + ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff, + &olc-> + forwardLogicalChannelParameters. + multiplexParameters. + h2250LogicalChannelParameters); + if (ret < 0) + return -1; + } + + if ((olc->options & + eOpenLogicalChannel_reverseLogicalChannelParameters) && + (olc->reverseLogicalChannelParameters.options & + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters) + && (olc->reverseLogicalChannelParameters.multiplexParameters. + choice == + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)) + { + ret = + process_h245_channel(pskb, ct, ctinfo, data, dataoff, + &olc-> + reverseLogicalChannelParameters. + multiplexParameters. + h2250LogicalChannelParameters); + if (ret < 0) + return -1; + } + + if ((olc->options & eOpenLogicalChannel_separateStack) && + olc->forwardLogicalChannelParameters.dataType.choice == + eDataType_data && + olc->forwardLogicalChannelParameters.dataType.data.application. + choice == eDataApplicationCapability_application_t120 && + olc->forwardLogicalChannelParameters.dataType.data.application. + t120.choice == eDataProtocolCapability_separateLANStack && + olc->separateStack.networkAddress.choice == + eNetworkAccessParameters_networkAddress_localAreaAddress) { + ret = expect_t120(pskb, ct, ctinfo, data, dataoff, + &olc->separateStack.networkAddress. + localAreaAddress); + if (ret < 0) + return -1; + } + + return 0; +} + +/****************************************************************************/ +static int process_olca(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + OpenLogicalChannelAck *olca) +{ + H2250LogicalChannelAckParameters *ack; + int ret; + + DEBUGP("nf_ct_h323: OpenLogicalChannelAck\n"); + + if ((olca->options & + eOpenLogicalChannelAck_reverseLogicalChannelParameters) && + (olca->reverseLogicalChannelParameters.options & + eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters) + && (olca->reverseLogicalChannelParameters.multiplexParameters. + choice == + eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)) + { + ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff, + &olca-> + reverseLogicalChannelParameters. + multiplexParameters. + h2250LogicalChannelParameters); + if (ret < 0) + return -1; + } + + if ((olca->options & + eOpenLogicalChannelAck_forwardMultiplexAckParameters) && + (olca->forwardMultiplexAckParameters.choice == + eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters)) + { + ack = &olca->forwardMultiplexAckParameters. + h2250LogicalChannelAckParameters; + if (ack->options & + eH2250LogicalChannelAckParameters_mediaChannel) { + /* RTP */ + ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + &ack->mediaChannel); + if (ret < 0) + return -1; + } + + if (ack->options & + eH2250LogicalChannelAckParameters_mediaControlChannel) { + /* RTCP */ + ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + &ack->mediaControlChannel); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_h245(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + MultimediaSystemControlMessage *mscm) +{ + switch (mscm->choice) { + case eMultimediaSystemControlMessage_request: + if (mscm->request.choice == + eRequestMessage_openLogicalChannel) { + return process_olc(pskb, ct, ctinfo, data, dataoff, + &mscm->request.openLogicalChannel); + } + DEBUGP("nf_ct_h323: H.245 Request %d\n", + mscm->request.choice); + break; + case eMultimediaSystemControlMessage_response: + if (mscm->response.choice == + eResponseMessage_openLogicalChannelAck) { + return process_olca(pskb, ct, ctinfo, data, dataoff, + &mscm->response. + openLogicalChannelAck); + } + DEBUGP("nf_ct_h323: H.245 Response %d\n", + mscm->response.choice); + break; + default: + DEBUGP("nf_ct_h323: H.245 signal %d\n", mscm->choice); + break; + } + + return 0; +} + +/****************************************************************************/ +static int h245_help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) +{ + static MultimediaSystemControlMessage mscm; + unsigned char *data = NULL; + int datalen; + int dataoff; + int ret; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + return NF_ACCEPT; + } + DEBUGP("nf_ct_h245: skblen = %u\n", (*pskb)->len); + + spin_lock_bh(&nf_h323_lock); + + /* Process each TPKT */ + while (get_tpkt_data(pskb, protoff, ct, ctinfo, + &data, &datalen, &dataoff)) { + DEBUGP("nf_ct_h245: TPKT len=%d ", datalen); + NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); + + /* Decode H.245 signal */ + ret = DecodeMultimediaSystemControlMessage(data, datalen, + &mscm); + if (ret < 0) { + if (net_ratelimit()) + printk("nf_ct_h245: decoding error: %s\n", + ret == H323_ERROR_BOUND ? + "out of bound" : "out of range"); + /* We don't drop when decoding error */ + break; + } + + /* Process H.245 signal */ + if (process_h245(pskb, ct, ctinfo, &data, dataoff, &mscm) < 0) + goto drop; + } + + spin_unlock_bh(&nf_h323_lock); + return NF_ACCEPT; + + drop: + spin_unlock_bh(&nf_h323_lock); + if (net_ratelimit()) + printk("nf_ct_h245: packet dropped\n"); + return NF_DROP; +} + +/****************************************************************************/ +static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = { + .name = "H.245", + .me = THIS_MODULE, + .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */, + .timeout = 240, + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + .help = h245_help +}; + +/****************************************************************************/ +int get_h225_addr(struct nf_conn *ct, unsigned char *data, + TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 *port) +{ + unsigned char *p; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + int len; + + switch (taddr->choice) { + case eTransportAddress_ipAddress: + if (family != AF_INET) + return 0; + p = data + taddr->ipAddress.ip; + len = 4; + break; + case eTransportAddress_ip6Address: + if (family != AF_INET6) + return 0; + p = data + taddr->ip6Address.ip6; + len = 16; + break; + default: + return 0; + } + + memcpy(addr, p, len); + memset((void *)addr + len, 0, sizeof(*addr) - len); + memcpy(port, p + len, sizeof(__be16)); + + return 1; +} + +/****************************************************************************/ +static int expect_h245(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + typeof(nat_h245_hook) nat_h245; + + /* Read h245Address */ + if (!get_h225_addr(ct, *data, taddr, &addr, &port) || + memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) || + port == 0) + return 0; + + /* Create expect for h245 connection */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); + exp->helper = &nf_conntrack_helper_h245; + + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + sizeof(ct->tuplehash[dir].tuple.src.u3)) && + (nat_h245 = rcu_dereference(nat_h245_hook)) && + ct->status & IPS_NAT_MASK) { + /* NAT needed */ + ret = nat_h245(pskb, ct, ctinfo, data, dataoff, taddr, + port, exp); + } else { /* Conntrack only */ + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_q931: expect H.245 "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + } + + nf_conntrack_expect_put(exp); + + return ret; +} + +/* If the calling party is on the same side of the forward-to party, + * we don't need to track the second call */ +static int callforward_do_filter(union nf_conntrack_address *src, + union nf_conntrack_address *dst, + int family) +{ + struct flowi fl1, fl2; + int ret = 0; + + memset(&fl1, 0, sizeof(fl1)); + memset(&fl2, 0, sizeof(fl2)); + + switch (family) { + case AF_INET: { + struct rtable *rt1, *rt2; + + fl1.fl4_dst = src->ip; + fl2.fl4_dst = dst->ip; + if (ip_route_output_key(&rt1, &fl1) == 0) { + if (ip_route_output_key(&rt2, &fl2) == 0) { + if (rt1->rt_gateway == rt2->rt_gateway && + rt1->u.dst.dev == rt2->u.dst.dev) + ret = 1; + dst_release(&rt2->u.dst); + } + dst_release(&rt1->u.dst); + } + break; + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: { + struct rt6_info *rt1, *rt2; + + memcpy(&fl1.fl6_dst, src, sizeof(fl1.fl6_dst)); + memcpy(&fl2.fl6_dst, dst, sizeof(fl2.fl6_dst)); + rt1 = (struct rt6_info *)ip6_route_output(NULL, &fl1); + if (rt1) { + rt2 = (struct rt6_info *)ip6_route_output(NULL, &fl2); + if (rt2) { + if (!memcmp(&rt1->rt6i_gateway, &rt2->rt6i_gateway, + sizeof(rt1->rt6i_gateway)) && + rt1->u.dst.dev == rt2->u.dst.dev) + ret = 1; + dst_release(&rt2->u.dst); + } + dst_release(&rt1->u.dst); + } + break; + } +#endif + } + return ret; + +} + +/****************************************************************************/ +static int expect_callforwarding(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + typeof(nat_callforwarding_hook) nat_callforwarding; + + /* Read alternativeAddress */ + if (!get_h225_addr(ct, *data, taddr, &addr, &port) || port == 0) + return 0; + + /* If the calling party is on the same side of the forward-to party, + * we don't need to track the second call */ + if (callforward_filter && + callforward_do_filter(&addr, &ct->tuplehash[!dir].tuple.src.u3, + ct->tuplehash[!dir].tuple.src.l3num)) { + DEBUGP("nf_ct_q931: Call Forwarding not tracked\n"); + return 0; + } + + /* Create expect for the second call leg */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->helper = nf_conntrack_helper_q931; + + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + sizeof(ct->tuplehash[dir].tuple.src.u3)) && + (nat_callforwarding = rcu_dereference(nat_callforwarding_hook)) && + ct->status & IPS_NAT_MASK) { + /* Need NAT */ + ret = nat_callforwarding(pskb, ct, ctinfo, data, dataoff, + taddr, port, exp); + } else { /* Conntrack only */ + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_q931: expect Call Forwarding "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + } + + nf_conntrack_expect_put(exp); + + return ret; +} + +/****************************************************************************/ +static int process_setup(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Setup_UUIE *setup) +{ + int dir = CTINFO2DIR(ctinfo); + int ret; + int i; + __be16 port; + union nf_conntrack_address addr; + typeof(set_h225_addr_hook) set_h225_addr; + + DEBUGP("nf_ct_q931: Setup\n"); + + if (setup->options & eSetup_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &setup->h245Address); + if (ret < 0) + return -1; + } + + set_h225_addr = rcu_dereference(set_h225_addr_hook); + if ((setup->options & eSetup_UUIE_destCallSignalAddress) && + (set_h225_addr) && ct->status && IPS_NAT_MASK && + get_h225_addr(ct, *data, &setup->destCallSignalAddress, + &addr, &port) && + memcmp(&addr, &ct->tuplehash[!dir].tuple.src.u3, sizeof(addr))) { + DEBUGP("nf_ct_q931: set destCallSignalAddress " + NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n", + NIP6(*(struct in6_addr *)&addr), ntohs(port), + NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.src.u3), + ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port)); + ret = set_h225_addr(pskb, data, dataoff, + &setup->destCallSignalAddress, + &ct->tuplehash[!dir].tuple.src.u3, + ct->tuplehash[!dir].tuple.src.u.tcp.port); + if (ret < 0) + return -1; + } + + if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) && + (set_h225_addr) && ct->status & IPS_NAT_MASK && + get_h225_addr(ct, *data, &setup->sourceCallSignalAddress, + &addr, &port) && + memcmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3, sizeof(addr))) { + DEBUGP("nf_ct_q931: set sourceCallSignalAddress " + NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n", + NIP6(*(struct in6_addr *)&addr), ntohs(port), + NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.dst.u3), + ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port)); + ret = set_h225_addr(pskb, data, dataoff, + &setup->sourceCallSignalAddress, + &ct->tuplehash[!dir].tuple.dst.u3, + ct->tuplehash[!dir].tuple.dst.u.tcp.port); + if (ret < 0) + return -1; + } + + if (setup->options & eSetup_UUIE_fastStart) { + for (i = 0; i < setup->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &setup->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_callproceeding(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + CallProceeding_UUIE *callproc) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: CallProceeding\n"); + + if (callproc->options & eCallProceeding_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &callproc->h245Address); + if (ret < 0) + return -1; + } + + if (callproc->options & eCallProceeding_UUIE_fastStart) { + for (i = 0; i < callproc->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &callproc->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_connect(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Connect_UUIE *connect) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: Connect\n"); + + if (connect->options & eConnect_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &connect->h245Address); + if (ret < 0) + return -1; + } + + if (connect->options & eConnect_UUIE_fastStart) { + for (i = 0; i < connect->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &connect->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_alerting(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Alerting_UUIE *alert) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: Alerting\n"); + + if (alert->options & eAlerting_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &alert->h245Address); + if (ret < 0) + return -1; + } + + if (alert->options & eAlerting_UUIE_fastStart) { + for (i = 0; i < alert->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &alert->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_information(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Information_UUIE *info) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: Information\n"); + + if (info->options & eInformation_UUIE_fastStart) { + for (i = 0; i < info->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &info->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_facility(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Facility_UUIE *facility) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: Facility\n"); + + if (facility->reason.choice == eFacilityReason_callForwarded) { + if (facility->options & eFacility_UUIE_alternativeAddress) + return expect_callforwarding(pskb, ct, ctinfo, data, + dataoff, + &facility-> + alternativeAddress); + return 0; + } + + if (facility->options & eFacility_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &facility->h245Address); + if (ret < 0) + return -1; + } + + if (facility->options & eFacility_UUIE_fastStart) { + for (i = 0; i < facility->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &facility->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_progress(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Progress_UUIE *progress) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: Progress\n"); + + if (progress->options & eProgress_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &progress->h245Address); + if (ret < 0) + return -1; + } + + if (progress->options & eProgress_UUIE_fastStart) { + for (i = 0; i < progress->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &progress->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_q931(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, Q931 *q931) +{ + H323_UU_PDU *pdu = &q931->UUIE.h323_uu_pdu; + int i; + int ret = 0; + + switch (pdu->h323_message_body.choice) { + case eH323_UU_PDU_h323_message_body_setup: + ret = process_setup(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body.setup); + break; + case eH323_UU_PDU_h323_message_body_callProceeding: + ret = process_callproceeding(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body. + callProceeding); + break; + case eH323_UU_PDU_h323_message_body_connect: + ret = process_connect(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body.connect); + break; + case eH323_UU_PDU_h323_message_body_alerting: + ret = process_alerting(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body.alerting); + break; + case eH323_UU_PDU_h323_message_body_information: + ret = process_information(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body. + information); + break; + case eH323_UU_PDU_h323_message_body_facility: + ret = process_facility(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body.facility); + break; + case eH323_UU_PDU_h323_message_body_progress: + ret = process_progress(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body.progress); + break; + default: + DEBUGP("nf_ct_q931: Q.931 signal %d\n", + pdu->h323_message_body.choice); + break; + } + + if (ret < 0) + return -1; + + if (pdu->options & eH323_UU_PDU_h245Control) { + for (i = 0; i < pdu->h245Control.count; i++) { + ret = process_h245(pskb, ct, ctinfo, data, dataoff, + &pdu->h245Control.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int q931_help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) +{ + static Q931 q931; + unsigned char *data = NULL; + int datalen; + int dataoff; + int ret; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + return NF_ACCEPT; + } + DEBUGP("nf_ct_q931: skblen = %u\n", (*pskb)->len); + + spin_lock_bh(&nf_h323_lock); + + /* Process each TPKT */ + while (get_tpkt_data(pskb, protoff, ct, ctinfo, + &data, &datalen, &dataoff)) { + DEBUGP("nf_ct_q931: TPKT len=%d ", datalen); + NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); + + /* Decode Q.931 signal */ + ret = DecodeQ931(data, datalen, &q931); + if (ret < 0) { + if (net_ratelimit()) + printk("nf_ct_q931: decoding error: %s\n", + ret == H323_ERROR_BOUND ? + "out of bound" : "out of range"); + /* We don't drop when decoding error */ + break; + } + + /* Process Q.931 signal */ + if (process_q931(pskb, ct, ctinfo, &data, dataoff, &q931) < 0) + goto drop; + } + + spin_unlock_bh(&nf_h323_lock); + return NF_ACCEPT; + + drop: + spin_unlock_bh(&nf_h323_lock); + if (net_ratelimit()) + printk("nf_ct_q931: packet dropped\n"); + return NF_DROP; +} + +/****************************************************************************/ +static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = { + { + .name = "Q.931", + .me = THIS_MODULE, + /* T.120 and H.245 */ + .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4, + .timeout = 240, + .tuple.src.l3num = AF_INET, + .tuple.src.u.tcp.port = __constant_htons(Q931_PORT), + .tuple.dst.protonum = IPPROTO_TCP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.tcp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + .help = q931_help + }, + { + .name = "Q.931", + .me = THIS_MODULE, + /* T.120 and H.245 */ + .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4, + .timeout = 240, + .tuple.src.l3num = AF_INET6, + .tuple.src.u.tcp.port = __constant_htons(Q931_PORT), + .tuple.dst.protonum = IPPROTO_TCP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.tcp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + .help = q931_help + }, +}; + +/****************************************************************************/ +static unsigned char *get_udp_data(struct sk_buff **pskb, unsigned int protoff, + int *datalen) +{ + struct udphdr _uh, *uh; + int dataoff; + + uh = skb_header_pointer(*pskb, protoff, sizeof(_uh), &_uh); + if (uh == NULL) + return NULL; + dataoff = protoff + sizeof(_uh); + if (dataoff >= (*pskb)->len) + return NULL; + *datalen = (*pskb)->len - dataoff; + return skb_header_pointer(*pskb, dataoff, *datalen, h323_buffer); +} + +/****************************************************************************/ +static struct nf_conntrack_expect *find_expect(struct nf_conn *ct, + union nf_conntrack_address *addr, + __be16 port) +{ + struct nf_conntrack_expect *exp; + struct nf_conntrack_tuple tuple; + + memset(&tuple.src.u3, 0, sizeof(tuple.src.u3)); + tuple.src.u.tcp.port = 0; + memcpy(&tuple.dst.u3, addr, sizeof(tuple.dst.u3)); + tuple.dst.u.tcp.port = port; + tuple.dst.protonum = IPPROTO_TCP; + + exp = __nf_conntrack_expect_find(&tuple); + if (exp && exp->master == ct) + return exp; + return NULL; +} + +/****************************************************************************/ +static int set_expect_timeout(struct nf_conntrack_expect *exp, + unsigned timeout) +{ + if (!exp || !del_timer(&exp->timeout)) + return 0; + + exp->timeout.expires = jiffies + timeout * HZ; + add_timer(&exp->timeout); + + return 1; +} + +/****************************************************************************/ +static int expect_q931(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + int i; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + typeof(nat_q931_hook) nat_q931; + + /* Look for the first related address */ + for (i = 0; i < count; i++) { + if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) && + memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, + sizeof(addr)) == 0 && port != 0) + break; + } + + if (i >= count) /* Not found */ + return 0; + + /* Create expect for Q.931 */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + gkrouted_only ? /* only accept calls from GK? */ + &ct->tuplehash[!dir].tuple.src.u3 : + NULL, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); + exp->helper = nf_conntrack_helper_q931; + exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */ + + nat_q931 = rcu_dereference(nat_q931_hook); + if (nat_q931 && ct->status & IPS_NAT_MASK) { /* Need NAT */ + ret = nat_q931(pskb, ct, ctinfo, data, taddr, i, port, exp); + } else { /* Conntrack only */ + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_ras: expect Q.931 "); + NF_CT_DUMP_TUPLE(&exp->tuple); + + /* Save port for looking up expect in processing RCF */ + info->sig_port[dir] = port; + } else + ret = -1; + } + + nf_conntrack_expect_put(exp); + + return ret; +} + +/****************************************************************************/ +static int process_grq(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, GatekeeperRequest *grq) +{ + typeof(set_ras_addr_hook) set_ras_addr; + + DEBUGP("nf_ct_ras: GRQ\n"); + + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr && ct->status & IPS_NAT_MASK) /* NATed */ + return set_ras_addr(pskb, ct, ctinfo, data, + &grq->rasAddress, 1); + return 0; +} + +/****************************************************************************/ +static int process_gcf(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, GatekeeperConfirm *gcf) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + + DEBUGP("nf_ct_ras: GCF\n"); + + if (!get_h225_addr(ct, *data, &gcf->rasAddress, &addr, &port)) + return 0; + + /* Registration port is the same as discovery port */ + if (!memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) && + port == ct->tuplehash[dir].tuple.src.u.udp.port) + return 0; + + /* Avoid RAS expectation loops. A GCF is never expected. */ + if (test_bit(IPS_EXPECTED_BIT, &ct->status)) + return 0; + + /* Need new expect */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_UDP, NULL, &port); + exp->helper = nf_conntrack_helper_ras; + + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_ras: expect RAS "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + + nf_conntrack_expect_put(exp); + + return ret; +} + +/****************************************************************************/ +static int process_rrq(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, RegistrationRequest *rrq) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int ret; + typeof(set_ras_addr_hook) set_ras_addr; + + DEBUGP("nf_ct_ras: RRQ\n"); + + ret = expect_q931(pskb, ct, ctinfo, data, + rrq->callSignalAddress.item, + rrq->callSignalAddress.count); + if (ret < 0) + return -1; + + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr && ct->status & IPS_NAT_MASK) { + ret = set_ras_addr(pskb, ct, ctinfo, data, + rrq->rasAddress.item, + rrq->rasAddress.count); + if (ret < 0) + return -1; + } + + if (rrq->options & eRegistrationRequest_timeToLive) { + DEBUGP("nf_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive); + info->timeout = rrq->timeToLive; + } else + info->timeout = default_rrq_ttl; + + return 0; +} + +/****************************************************************************/ +static int process_rcf(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, RegistrationConfirm *rcf) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int ret; + struct nf_conntrack_expect *exp; + typeof(set_sig_addr_hook) set_sig_addr; + + DEBUGP("nf_ct_ras: RCF\n"); + + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr && ct->status & IPS_NAT_MASK) { + ret = set_sig_addr(pskb, ct, ctinfo, data, + rcf->callSignalAddress.item, + rcf->callSignalAddress.count); + if (ret < 0) + return -1; + } + + if (rcf->options & eRegistrationConfirm_timeToLive) { + DEBUGP("nf_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive); + info->timeout = rcf->timeToLive; + } + + if (info->timeout > 0) { + DEBUGP + ("nf_ct_ras: set RAS connection timeout to %u seconds\n", + info->timeout); + nf_ct_refresh(ct, *pskb, info->timeout * HZ); + + /* Set expect timeout */ + read_lock_bh(&nf_conntrack_lock); + exp = find_expect(ct, &ct->tuplehash[dir].tuple.dst.u3, + info->sig_port[!dir]); + if (exp) { + DEBUGP("nf_ct_ras: set Q.931 expect " + "timeout to %u seconds for", + info->timeout); + NF_CT_DUMP_TUPLE(&exp->tuple); + set_expect_timeout(exp, info->timeout); + } + read_unlock_bh(&nf_conntrack_lock); + } + + return 0; +} + +/****************************************************************************/ +static int process_urq(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, UnregistrationRequest *urq) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int ret; + typeof(set_sig_addr_hook) set_sig_addr; + + DEBUGP("nf_ct_ras: URQ\n"); + + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr && ct->status & IPS_NAT_MASK) { + ret = set_sig_addr(pskb, ct, ctinfo, data, + urq->callSignalAddress.item, + urq->callSignalAddress.count); + if (ret < 0) + return -1; + } + + /* Clear old expect */ + nf_ct_remove_expectations(ct); + info->sig_port[dir] = 0; + info->sig_port[!dir] = 0; + + /* Give it 30 seconds for UCF or URJ */ + nf_ct_refresh(ct, *pskb, 30 * HZ); + + return 0; +} + +/****************************************************************************/ +static int process_arq(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, AdmissionRequest *arq) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + __be16 port; + union nf_conntrack_address addr; + typeof(set_h225_addr_hook) set_h225_addr; + + DEBUGP("nf_ct_ras: ARQ\n"); + + set_h225_addr = rcu_dereference(set_h225_addr_hook); + if ((arq->options & eAdmissionRequest_destCallSignalAddress) && + get_h225_addr(ct, *data, &arq->destCallSignalAddress, + &addr, &port) && + !memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) && + port == info->sig_port[dir] && + set_h225_addr && ct->status & IPS_NAT_MASK) { + /* Answering ARQ */ + return set_h225_addr(pskb, data, 0, + &arq->destCallSignalAddress, + &ct->tuplehash[!dir].tuple.dst.u3, + info->sig_port[!dir]); + } + + if ((arq->options & eAdmissionRequest_srcCallSignalAddress) && + get_h225_addr(ct, *data, &arq->srcCallSignalAddress, + &addr, &port) && + !memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) && + set_h225_addr && ct->status & IPS_NAT_MASK) { + /* Calling ARQ */ + return set_h225_addr(pskb, data, 0, + &arq->srcCallSignalAddress, + &ct->tuplehash[!dir].tuple.dst.u3, + port); + } + + return 0; +} + +/****************************************************************************/ +static int process_acf(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, AdmissionConfirm *acf) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + typeof(set_sig_addr_hook) set_sig_addr; + + DEBUGP("nf_ct_ras: ACF\n"); + + if (!get_h225_addr(ct, *data, &acf->destCallSignalAddress, + &addr, &port)) + return 0; + + if (!memcmp(&addr, &ct->tuplehash[dir].tuple.dst.u3, sizeof(addr))) { + /* Answering ACF */ + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr && ct->status & IPS_NAT_MASK) + return set_sig_addr(pskb, ct, ctinfo, data, + &acf->destCallSignalAddress, 1); + return 0; + } + + /* Need new expect */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; + exp->helper = nf_conntrack_helper_q931; + + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_ras: expect Q.931 "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + + nf_conntrack_expect_put(exp); + + return ret; +} + +/****************************************************************************/ +static int process_lrq(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, LocationRequest *lrq) +{ + typeof(set_ras_addr_hook) set_ras_addr; + + DEBUGP("nf_ct_ras: LRQ\n"); + + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr && ct->status & IPS_NAT_MASK) + return set_ras_addr(pskb, ct, ctinfo, data, + &lrq->replyAddress, 1); + return 0; +} + +/****************************************************************************/ +static int process_lcf(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, LocationConfirm *lcf) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + + DEBUGP("nf_ct_ras: LCF\n"); + + if (!get_h225_addr(ct, *data, &lcf->callSignalAddress, + &addr, &port)) + return 0; + + /* Need new expect for call signal */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; + exp->helper = nf_conntrack_helper_q931; + + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_ras: expect Q.931 "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + + nf_conntrack_expect_put(exp); + + /* Ignore rasAddress */ + + return ret; +} + +/****************************************************************************/ +static int process_irr(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, InfoRequestResponse *irr) +{ + int ret; + typeof(set_ras_addr_hook) set_ras_addr; + typeof(set_sig_addr_hook) set_sig_addr; + + DEBUGP("nf_ct_ras: IRR\n"); + + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr && ct->status & IPS_NAT_MASK) { + ret = set_ras_addr(pskb, ct, ctinfo, data, + &irr->rasAddress, 1); + if (ret < 0) + return -1; + } + + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr && ct->status & IPS_NAT_MASK) { + ret = set_sig_addr(pskb, ct, ctinfo, data, + irr->callSignalAddress.item, + irr->callSignalAddress.count); + if (ret < 0) + return -1; + } + + return 0; +} + +/****************************************************************************/ +static int process_ras(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, RasMessage *ras) +{ + switch (ras->choice) { + case eRasMessage_gatekeeperRequest: + return process_grq(pskb, ct, ctinfo, data, + &ras->gatekeeperRequest); + case eRasMessage_gatekeeperConfirm: + return process_gcf(pskb, ct, ctinfo, data, + &ras->gatekeeperConfirm); + case eRasMessage_registrationRequest: + return process_rrq(pskb, ct, ctinfo, data, + &ras->registrationRequest); + case eRasMessage_registrationConfirm: + return process_rcf(pskb, ct, ctinfo, data, + &ras->registrationConfirm); + case eRasMessage_unregistrationRequest: + return process_urq(pskb, ct, ctinfo, data, + &ras->unregistrationRequest); + case eRasMessage_admissionRequest: + return process_arq(pskb, ct, ctinfo, data, + &ras->admissionRequest); + case eRasMessage_admissionConfirm: + return process_acf(pskb, ct, ctinfo, data, + &ras->admissionConfirm); + case eRasMessage_locationRequest: + return process_lrq(pskb, ct, ctinfo, data, + &ras->locationRequest); + case eRasMessage_locationConfirm: + return process_lcf(pskb, ct, ctinfo, data, + &ras->locationConfirm); + case eRasMessage_infoRequestResponse: + return process_irr(pskb, ct, ctinfo, data, + &ras->infoRequestResponse); + default: + DEBUGP("nf_ct_ras: RAS message %d\n", ras->choice); + break; + } + + return 0; +} + +/****************************************************************************/ +static int ras_help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) +{ + static RasMessage ras; + unsigned char *data; + int datalen = 0; + int ret; + + DEBUGP("nf_ct_ras: skblen = %u\n", (*pskb)->len); + + spin_lock_bh(&nf_h323_lock); + + /* Get UDP data */ + data = get_udp_data(pskb, protoff, &datalen); + if (data == NULL) + goto accept; + DEBUGP("nf_ct_ras: RAS message len=%d ", datalen); + NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); + + /* Decode RAS message */ + ret = DecodeRasMessage(data, datalen, &ras); + if (ret < 0) { + if (net_ratelimit()) + printk("nf_ct_ras: decoding error: %s\n", + ret == H323_ERROR_BOUND ? + "out of bound" : "out of range"); + goto accept; + } + + /* Process RAS message */ + if (process_ras(pskb, ct, ctinfo, &data, &ras) < 0) + goto drop; + + accept: + spin_unlock_bh(&nf_h323_lock); + return NF_ACCEPT; + + drop: + spin_unlock_bh(&nf_h323_lock); + if (net_ratelimit()) + printk("nf_ct_ras: packet dropped\n"); + return NF_DROP; +} + +/****************************************************************************/ +static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = { + { + .name = "RAS", + .me = THIS_MODULE, + .max_expected = 32, + .timeout = 240, + .tuple.src.l3num = AF_INET, + .tuple.src.u.udp.port = __constant_htons(RAS_PORT), + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + .help = ras_help, + }, + { + .name = "RAS", + .me = THIS_MODULE, + .max_expected = 32, + .timeout = 240, + .tuple.src.l3num = AF_INET6, + .tuple.src.u.udp.port = __constant_htons(RAS_PORT), + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + .help = ras_help, + }, +}; + +/****************************************************************************/ +static void __exit nf_conntrack_h323_fini(void) +{ + nf_conntrack_helper_unregister(&nf_conntrack_helper_ras[1]); + nf_conntrack_helper_unregister(&nf_conntrack_helper_ras[0]); + nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[1]); + nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[0]); + kfree(h323_buffer); + DEBUGP("nf_ct_h323: fini\n"); +} + +/****************************************************************************/ +static int __init nf_conntrack_h323_init(void) +{ + int ret; + + h323_buffer = kmalloc(65536, GFP_KERNEL); + if (!h323_buffer) + return -ENOMEM; + ret = nf_conntrack_helper_register(&nf_conntrack_helper_q931[0]); + if (ret < 0) + goto err1; + ret = nf_conntrack_helper_register(&nf_conntrack_helper_q931[1]); + if (ret < 0) + goto err2; + ret = nf_conntrack_helper_register(&nf_conntrack_helper_ras[0]); + if (ret < 0) + goto err3; + ret = nf_conntrack_helper_register(&nf_conntrack_helper_ras[1]); + if (ret < 0) + goto err4; + DEBUGP("nf_ct_h323: init success\n"); + return 0; + +err4: + nf_conntrack_helper_unregister(&nf_conntrack_helper_ras[0]); +err3: + nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[1]); +err2: + nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[0]); +err1: + return ret; +} + +/****************************************************************************/ +module_init(nf_conntrack_h323_init); +module_exit(nf_conntrack_h323_fini); + +EXPORT_SYMBOL_GPL(get_h225_addr); +EXPORT_SYMBOL_GPL(set_h245_addr_hook); +EXPORT_SYMBOL_GPL(set_h225_addr_hook); +EXPORT_SYMBOL_GPL(set_sig_addr_hook); +EXPORT_SYMBOL_GPL(set_ras_addr_hook); +EXPORT_SYMBOL_GPL(nat_rtp_rtcp_hook); +EXPORT_SYMBOL_GPL(nat_t120_hook); +EXPORT_SYMBOL_GPL(nat_h245_hook); +EXPORT_SYMBOL_GPL(nat_callforwarding_hook); +EXPORT_SYMBOL_GPL(nat_q931_hook); + +MODULE_AUTHOR("Jing Min Zhao "); +MODULE_DESCRIPTION("H.323 connection tracking helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_conntrack_h323"); diff --git a/net/netfilter/nf_conntrack_h323_types.c b/net/netfilter/nf_conntrack_h323_types.c new file mode 100644 index 000000000000..4c6f8b3b1208 --- /dev/null +++ b/net/netfilter/nf_conntrack_h323_types.c @@ -0,0 +1,1927 @@ +/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 + * + * Copyright (c) 2006 Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + */ + +static field_t _TransportAddress_ipAddress[] = { /* SEQUENCE */ + {FNAME("ip") OCTSTR, FIXD, 4, 0, DECODE, + offsetof(TransportAddress_ipAddress, ip), NULL}, + {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _TransportAddress_ipSourceRoute_route[] = { /* SEQUENCE OF */ + {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, +}; + +static field_t _TransportAddress_ipSourceRoute_routing[] = { /* CHOICE */ + {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _TransportAddress_ipSourceRoute[] = { /* SEQUENCE */ + {FNAME("ip") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, + {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, + _TransportAddress_ipSourceRoute_route}, + {FNAME("routing") CHOICE, 1, 2, 2, SKIP | EXT, 0, + _TransportAddress_ipSourceRoute_routing}, +}; + +static field_t _TransportAddress_ipxAddress[] = { /* SEQUENCE */ + {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, + {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, + {FNAME("port") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, +}; + +static field_t _TransportAddress_ip6Address[] = { /* SEQUENCE */ + {FNAME("ip") OCTSTR, FIXD, 16, 0, DECODE, + offsetof(TransportAddress_ip6Address, ip6), NULL}, + {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H221NonStandard[] = { /* SEQUENCE */ + {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _NonStandardIdentifier[] = { /* CHOICE */ + {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP | EXT, 0, + _H221NonStandard}, +}; + +static field_t _NonStandardParameter[] = { /* SEQUENCE */ + {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP | EXT, 0, + _NonStandardIdentifier}, + {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _TransportAddress[] = { /* CHOICE */ + {FNAME("ipAddress") SEQ, 0, 2, 2, DECODE, + offsetof(TransportAddress, ipAddress), _TransportAddress_ipAddress}, + {FNAME("ipSourceRoute") SEQ, 0, 4, 4, SKIP | EXT, 0, + _TransportAddress_ipSourceRoute}, + {FNAME("ipxAddress") SEQ, 0, 3, 3, SKIP, 0, + _TransportAddress_ipxAddress}, + {FNAME("ip6Address") SEQ, 0, 2, 2, DECODE | EXT, + offsetof(TransportAddress, ip6Address), _TransportAddress_ip6Address}, + {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, + {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, + _NonStandardParameter}, +}; + +static field_t _AliasAddress[] = { /* CHOICE */ + {FNAME("dialedDigits") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("h323-ID") BMPSTR, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("url-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("transportID") CHOICE, 3, 7, 7, SKIP | EXT, 0, NULL}, + {FNAME("email-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("partyNumber") CHOICE, 3, 5, 5, SKIP | EXT, 0, NULL}, + {FNAME("mobileUIM") CHOICE, 1, 2, 2, SKIP | EXT, 0, NULL}, +}; + +static field_t _Setup_UUIE_sourceAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _VendorIdentifier[] = { /* SEQUENCE */ + {FNAME("vendor") SEQ, 0, 3, 3, SKIP | EXT, 0, _H221NonStandard}, + {FNAME("productId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("versionId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _GatekeeperInfo[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, +}; + +static field_t _H310Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H320Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H321Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H322Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H323Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H324Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _VoiceCaps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _T120OnlyCaps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _SupportedProtocols[] = { /* CHOICE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP, 0, + _NonStandardParameter}, + {FNAME("h310") SEQ, 1, 1, 3, SKIP | EXT, 0, _H310Caps}, + {FNAME("h320") SEQ, 1, 1, 3, SKIP | EXT, 0, _H320Caps}, + {FNAME("h321") SEQ, 1, 1, 3, SKIP | EXT, 0, _H321Caps}, + {FNAME("h322") SEQ, 1, 1, 3, SKIP | EXT, 0, _H322Caps}, + {FNAME("h323") SEQ, 1, 1, 3, SKIP | EXT, 0, _H323Caps}, + {FNAME("h324") SEQ, 1, 1, 3, SKIP | EXT, 0, _H324Caps}, + {FNAME("voice") SEQ, 1, 1, 3, SKIP | EXT, 0, _VoiceCaps}, + {FNAME("t120-only") SEQ, 1, 1, 3, SKIP | EXT, 0, _T120OnlyCaps}, + {FNAME("nonStandardProtocol") SEQ, 2, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("t38FaxAnnexbOnly") SEQ, 2, 5, 5, SKIP | EXT, 0, NULL}, +}; + +static field_t _GatewayInfo_protocol[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 4, 9, 11, SKIP | EXT, 0, _SupportedProtocols}, +}; + +static field_t _GatewayInfo[] = { /* SEQUENCE */ + {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _GatewayInfo_protocol}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, +}; + +static field_t _McuInfo[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _TerminalInfo[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, +}; + +static field_t _EndpointType[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("vendor") SEQ, 2, 3, 3, SKIP | EXT | OPT, 0, + _VendorIdentifier}, + {FNAME("gatekeeper") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, + _GatekeeperInfo}, + {FNAME("gateway") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, _GatewayInfo}, + {FNAME("mcu") SEQ, 1, 1, 2, SKIP | EXT | OPT, 0, _McuInfo}, + {FNAME("terminal") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, _TerminalInfo}, + {FNAME("mc") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("undefinedNode") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("set") BITSTR, FIXD, 32, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedTunnelledProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, + 0, NULL}, +}; + +static field_t _Setup_UUIE_destinationAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _Setup_UUIE_destExtraCallInfo[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _Setup_UUIE_destExtraCRV[] = { /* SEQUENCE OF */ + {FNAME("item") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _Setup_UUIE_conferenceGoal[] = { /* CHOICE */ + {FNAME("create") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("join") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("invite") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("capability-negotiation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("callIndependentSupplementaryService") NUL, FIXD, 0, 0, SKIP, + 0, NULL}, +}; + +static field_t _Q954Details[] = { /* SEQUENCE */ + {FNAME("conferenceCalling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("threePartyService") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _QseriesOptions[] = { /* SEQUENCE */ + {FNAME("q932Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q951Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q952Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q953Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q955Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q956Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q957Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q954Info") SEQ, 0, 2, 2, SKIP | EXT, 0, _Q954Details}, +}; + +static field_t _CallType[] = { /* CHOICE */ + {FNAME("pointToPoint") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("oneToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("nToOne") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("nToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H245_NonStandardIdentifier_h221NonStandard[] = { /* SEQUENCE */ + {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H245_NonStandardIdentifier[] = { /* CHOICE */ + {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP, 0, + _H245_NonStandardIdentifier_h221NonStandard}, +}; + +static field_t _H245_NonStandardParameter[] = { /* SEQUENCE */ + {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP, 0, + _H245_NonStandardIdentifier}, + {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H261VideoCapability[] = { /* SEQUENCE */ + {FNAME("qcifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("cifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, + NULL}, + {FNAME("maxBitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("stillImageTransmission") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H262VideoCapability[] = { /* SEQUENCE */ + {FNAME("profileAndLevel-SPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-MPatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-MPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-MPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-MPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-SNRatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-SNRatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-SpatialatH-14") BOOL, FIXD, 0, 0, SKIP, 0, + NULL}, + {FNAME("profileAndLevel-HPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-HPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-HPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("framesPerSecond") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H263VideoCapability[] = { /* SEQUENCE */ + {FNAME("sqcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("qcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("cifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("cif4MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("cif16MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("maxBitRate") INT, CONS, 1, 0, SKIP, 0, NULL}, + {FNAME("unrestrictedVector") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("arithmeticCoding") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("advancedPrediction") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("pbFrames") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, + NULL}, + {FNAME("hrd-B") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("bppMaxKb") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("slowSqcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("slowQcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("slowCifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("slowCif4MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("slowCif16MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("errorCompensation") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("enhancementLayerInfo") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("h263Options") SEQ, 5, 29, 31, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _IS11172VideoCapability[] = { /* SEQUENCE */ + {FNAME("constrainedBitstream") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("pictureRate") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _VideoCapability[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("h261VideoCapability") SEQ, 2, 5, 6, SKIP | EXT, 0, + _H261VideoCapability}, + {FNAME("h262VideoCapability") SEQ, 6, 17, 18, SKIP | EXT, 0, + _H262VideoCapability}, + {FNAME("h263VideoCapability") SEQ, 7, 13, 21, SKIP | EXT, 0, + _H263VideoCapability}, + {FNAME("is11172VideoCapability") SEQ, 6, 7, 8, SKIP | EXT, 0, + _IS11172VideoCapability}, + {FNAME("genericVideoCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, +}; + +static field_t _AudioCapability_g7231[] = { /* SEQUENCE */ + {FNAME("maxAl-sduAudioFrames") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _IS11172AudioCapability[] = { /* SEQUENCE */ + {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, +}; + +static field_t _IS13818AudioCapability[] = { /* SEQUENCE */ + {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling16k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling22k05") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling24k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("threeChannels2-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("threeChannels3-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fourChannels2-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fourChannels2-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fourChannels3-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fiveChannels3-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fiveChannels3-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("lowFrequencyEnhancement") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("multilingual") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, +}; + +static field_t _AudioCapability[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("g711Alaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g711Alaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g711Ulaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g711Ulaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g722-64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g722-56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g722-48k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g7231") SEQ, 0, 2, 2, SKIP, 0, _AudioCapability_g7231}, + {FNAME("g728") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g729") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g729AnnexA") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("is11172AudioCapability") SEQ, 0, 9, 9, SKIP | EXT, 0, + _IS11172AudioCapability}, + {FNAME("is13818AudioCapability") SEQ, 0, 21, 21, SKIP | EXT, 0, + _IS13818AudioCapability}, + {FNAME("g729wAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g729AnnexAwAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g7231AnnexCCapability") SEQ, 1, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("gsmFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("gsmHalfRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("gsmEnhancedFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("genericAudioCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, + {FNAME("g729Extensions") SEQ, 1, 8, 8, SKIP | EXT, 0, NULL}, +}; + +static field_t _DataProtocolCapability[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("v14buffered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("v42lapm") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("hdlcFrameTunnelling") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("h310SeparateVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("h310SingleVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("transparent") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("segmentationAndReassembly") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("hdlcFrameTunnelingwSAR") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("v120") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("separateLANStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("v76wCompression") CHOICE, 2, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("tcp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("udp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _T84Profile_t84Restricted[] = { /* SEQUENCE */ + {FNAME("qcif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("cif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("ccir601Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("ccir601Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("hdtvSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("hdtvProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("g3FacsMH200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("g3FacsMH200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("g4FacsMMR200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("g4FacsMMR200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("jbig200x200Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("jbig200x200Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("jbig300x300Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("jbig300x300Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("digPhotoLow") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("digPhotoMedSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("digPhotoMedProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("digPhotoHighSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("digPhotoHighProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _T84Profile[] = { /* CHOICE */ + {FNAME("t84Unrestricted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("t84Restricted") SEQ, 0, 19, 19, SKIP | EXT, 0, + _T84Profile_t84Restricted}, +}; + +static field_t _DataApplicationCapability_application_t84[] = { /* SEQUENCE */ + {FNAME("t84Protocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("t84Profile") CHOICE, 1, 2, 2, SKIP, 0, _T84Profile}, +}; + +static field_t _DataApplicationCapability_application_nlpid[] = { /* SEQUENCE */ + {FNAME("nlpidProtocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("nlpidData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _DataApplicationCapability_application[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("t120") CHOICE, 3, 7, 14, DECODE | EXT, + offsetof(DataApplicationCapability_application, t120), + _DataProtocolCapability}, + {FNAME("dsm-cc") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("userData") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("t84") SEQ, 0, 2, 2, SKIP, 0, + _DataApplicationCapability_application_t84}, + {FNAME("t434") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("h224") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("nlpid") SEQ, 0, 2, 2, SKIP, 0, + _DataApplicationCapability_application_nlpid}, + {FNAME("dsvdControl") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("h222DataPartitioning") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("t30fax") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, + {FNAME("t140") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, + {FNAME("t38fax") SEQ, 0, 2, 2, SKIP, 0, NULL}, + {FNAME("genericDataCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, +}; + +static field_t _DataApplicationCapability[] = { /* SEQUENCE */ + {FNAME("application") CHOICE, 4, 10, 14, DECODE | EXT, + offsetof(DataApplicationCapability, application), + _DataApplicationCapability_application}, + {FNAME("maxBitRate") INT, CONS, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _EncryptionMode[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("h233Encryption") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _DataType[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("nullData") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("videoData") CHOICE, 3, 5, 6, SKIP | EXT, 0, _VideoCapability}, + {FNAME("audioData") CHOICE, 4, 14, 22, SKIP | EXT, 0, + _AudioCapability}, + {FNAME("data") SEQ, 0, 2, 2, DECODE | EXT, offsetof(DataType, data), + _DataApplicationCapability}, + {FNAME("encryptionData") CHOICE, 1, 2, 2, SKIP | EXT, 0, + _EncryptionMode}, + {FNAME("h235Control") SEQ, 0, 2, 2, SKIP, 0, NULL}, + {FNAME("h235Media") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, + {FNAME("multiplexedStream") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, +}; + +static field_t _H222LogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("resourceID") INT, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("subChannelID") INT, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("pcr-pid") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("programDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("streamDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = { /* SEQUENCE */ + {FNAME("controlFieldOctets") INT, 2, 0, 0, SKIP, 0, NULL}, + {FNAME("sendBufferSize") INT, CONS, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H223LogicalChannelParameters_adaptationLayerType[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("al1Framed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("al1NotFramed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("al2WithoutSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("al2WithSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("al3") SEQ, 0, 2, 2, SKIP, 0, + _H223LogicalChannelParameters_adaptationLayerType_al3}, + {FNAME("al1M") SEQ, 0, 7, 8, SKIP | EXT, 0, NULL}, + {FNAME("al2M") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, + {FNAME("al3M") SEQ, 0, 5, 6, SKIP | EXT, 0, NULL}, +}; + +static field_t _H223LogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("adaptationLayerType") CHOICE, 3, 6, 9, SKIP | EXT, 0, + _H223LogicalChannelParameters_adaptationLayerType}, + {FNAME("segmentableFlag") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CRCLength[] = { /* CHOICE */ + {FNAME("crc8bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("crc16bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("crc32bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V76HDLCParameters[] = { /* SEQUENCE */ + {FNAME("crcLength") CHOICE, 2, 3, 3, SKIP | EXT, 0, _CRCLength}, + {FNAME("n401") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("loopbackTestProcedure") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V76LogicalChannelParameters_suspendResume[] = { /* CHOICE */ + {FNAME("noSuspendResume") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("suspendResumewAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("suspendResumewoAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = { /* CHOICE */ + {FNAME("rej") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("sREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("mSREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V76LogicalChannelParameters_mode_eRM[] = { /* SEQUENCE */ + {FNAME("windowSize") INT, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("recovery") CHOICE, 2, 3, 3, SKIP | EXT, 0, + _V76LogicalChannelParameters_mode_eRM_recovery}, +}; + +static field_t _V76LogicalChannelParameters_mode[] = { /* CHOICE */ + {FNAME("eRM") SEQ, 0, 2, 2, SKIP | EXT, 0, + _V76LogicalChannelParameters_mode_eRM}, + {FNAME("uNERM") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V75Parameters[] = { /* SEQUENCE */ + {FNAME("audioHeaderPresent") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V76LogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("hdlcParameters") SEQ, 0, 3, 3, SKIP | EXT, 0, + _V76HDLCParameters}, + {FNAME("suspendResume") CHOICE, 2, 3, 3, SKIP | EXT, 0, + _V76LogicalChannelParameters_suspendResume}, + {FNAME("uIH") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("mode") CHOICE, 1, 2, 2, SKIP | EXT, 0, + _V76LogicalChannelParameters_mode}, + {FNAME("v75Parameters") SEQ, 0, 1, 1, SKIP | EXT, 0, _V75Parameters}, +}; + +static field_t _H2250LogicalChannelParameters_nonStandard[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, +}; + +static field_t _UnicastAddress_iPAddress[] = { /* SEQUENCE */ + {FNAME("network") OCTSTR, FIXD, 4, 0, DECODE, + offsetof(UnicastAddress_iPAddress, network), NULL}, + {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _UnicastAddress_iPXAddress[] = { /* SEQUENCE */ + {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, + {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, + {FNAME("tsapIdentifier") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, +}; + +static field_t _UnicastAddress_iP6Address[] = { /* SEQUENCE */ + {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _UnicastAddress_iPSourceRouteAddress_routing[] = { /* CHOICE */ + {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _UnicastAddress_iPSourceRouteAddress_route[] = { /* SEQUENCE OF */ + {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, +}; + +static field_t _UnicastAddress_iPSourceRouteAddress[] = { /* SEQUENCE */ + {FNAME("routing") CHOICE, 1, 2, 2, SKIP, 0, + _UnicastAddress_iPSourceRouteAddress_routing}, + {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, + {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, + _UnicastAddress_iPSourceRouteAddress_route}, +}; + +static field_t _UnicastAddress[] = { /* CHOICE */ + {FNAME("iPAddress") SEQ, 0, 2, 2, DECODE | EXT, + offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress}, + {FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0, + _UnicastAddress_iPXAddress}, + {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, + _UnicastAddress_iP6Address}, + {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("iPSourceRouteAddress") SEQ, 0, 4, 4, SKIP | EXT, 0, + _UnicastAddress_iPSourceRouteAddress}, + {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, + {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, +}; + +static field_t _MulticastAddress_iPAddress[] = { /* SEQUENCE */ + {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, + {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _MulticastAddress_iP6Address[] = { /* SEQUENCE */ + {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _MulticastAddress[] = { /* CHOICE */ + {FNAME("iPAddress") SEQ, 0, 2, 2, SKIP | EXT, 0, + _MulticastAddress_iPAddress}, + {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, + _MulticastAddress_iP6Address}, + {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, + {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, +}; + +static field_t _H245_TransportAddress[] = { /* CHOICE */ + {FNAME("unicastAddress") CHOICE, 3, 5, 7, DECODE | EXT, + offsetof(H245_TransportAddress, unicastAddress), _UnicastAddress}, + {FNAME("multicastAddress") CHOICE, 1, 2, 4, SKIP | EXT, 0, + _MulticastAddress}, +}; + +static field_t _H2250LogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _H2250LogicalChannelParameters_nonStandard}, + {FNAME("sessionID") INT, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("associatedSessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, + offsetof(H2250LogicalChannelParameters, mediaChannel), + _H245_TransportAddress}, + {FNAME("mediaGuaranteedDelivery") BOOL, FIXD, 0, 0, SKIP | OPT, 0, + NULL}, + {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, + offsetof(H2250LogicalChannelParameters, mediaControlChannel), + _H245_TransportAddress}, + {FNAME("mediaControlGuaranteedDelivery") BOOL, FIXD, 0, 0, STOP | OPT, + 0, NULL}, + {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destination") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, STOP | OPT, 0, NULL}, + {FNAME("mediaPacketization") CHOICE, 0, 1, 2, STOP | EXT | OPT, 0, + NULL}, + {FNAME("transportCapability") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, + NULL}, + {FNAME("redundancyEncoding") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("source") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ + {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, + _H222LogicalChannelParameters}, + {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, + _H223LogicalChannelParameters}, + {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, + _V76LogicalChannelParameters}, + {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, + offsetof + (OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters, + h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, + {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("dataType") CHOICE, 3, 6, 9, DECODE | EXT, + offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, + dataType), _DataType}, + {FNAME("multiplexParameters") CHOICE, 2, 3, 5, DECODE | EXT, + offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, + multiplexParameters), + _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters}, + {FNAME("forwardLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, + 0, NULL}, + {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ + {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, + _H223LogicalChannelParameters}, + {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, + _V76LogicalChannelParameters}, + {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, + offsetof + (OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters, + h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, +}; + +static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("dataType") CHOICE, 3, 6, 9, SKIP | EXT, 0, _DataType}, + {FNAME("multiplexParameters") CHOICE, 1, 2, 3, DECODE | EXT | OPT, + offsetof(OpenLogicalChannel_reverseLogicalChannelParameters, + multiplexParameters), + _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters}, + {FNAME("reverseLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, + 0, NULL}, + {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _NetworkAccessParameters_distribution[] = { /* CHOICE */ + {FNAME("unicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("multicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _Q2931Address_address[] = { /* CHOICE */ + {FNAME("internationalNumber") NUMSTR, 4, 1, 0, SKIP, 0, NULL}, + {FNAME("nsapAddress") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, +}; + +static field_t _Q2931Address[] = { /* SEQUENCE */ + {FNAME("address") CHOICE, 1, 2, 2, SKIP | EXT, 0, + _Q2931Address_address}, + {FNAME("subaddress") OCTSTR, 5, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _NetworkAccessParameters_networkAddress[] = { /* CHOICE */ + {FNAME("q2931Address") SEQ, 1, 2, 2, SKIP | EXT, 0, _Q2931Address}, + {FNAME("e164Address") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("localAreaAddress") CHOICE, 1, 2, 2, DECODE | EXT, + offsetof(NetworkAccessParameters_networkAddress, localAreaAddress), + _H245_TransportAddress}, +}; + +static field_t _NetworkAccessParameters[] = { /* SEQUENCE */ + {FNAME("distribution") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, + _NetworkAccessParameters_distribution}, + {FNAME("networkAddress") CHOICE, 2, 3, 3, DECODE | EXT, + offsetof(NetworkAccessParameters, networkAddress), + _NetworkAccessParameters_networkAddress}, + {FNAME("associateConference") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("externalReference") OCTSTR, 8, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("t120SetupProcedure") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, + NULL}, +}; + +static field_t _OpenLogicalChannel[] = { /* SEQUENCE */ + {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("forwardLogicalChannelParameters") SEQ, 1, 3, 5, DECODE | EXT, + offsetof(OpenLogicalChannel, forwardLogicalChannelParameters), + _OpenLogicalChannel_forwardLogicalChannelParameters}, + {FNAME("reverseLogicalChannelParameters") SEQ, 1, 2, 4, + DECODE | EXT | OPT, offsetof(OpenLogicalChannel, + reverseLogicalChannelParameters), + _OpenLogicalChannel_reverseLogicalChannelParameters}, + {FNAME("separateStack") SEQ, 2, 4, 5, DECODE | EXT | OPT, + offsetof(OpenLogicalChannel, separateStack), + _NetworkAccessParameters}, + {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, +}; + +static field_t _Setup_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Setup_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Setup_UUIE, h245Address), _TransportAddress}, + {FNAME("sourceAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Setup_UUIE_sourceAddress}, + {FNAME("sourceInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, + {FNAME("destinationAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Setup_UUIE_destinationAddress}, + {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Setup_UUIE, destCallSignalAddress), _TransportAddress}, + {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Setup_UUIE_destExtraCallInfo}, + {FNAME("destExtraCRV") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Setup_UUIE_destExtraCRV}, + {FNAME("activeMC") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("conferenceGoal") CHOICE, 2, 3, 5, SKIP | EXT, 0, + _Setup_UUIE_conferenceGoal}, + {FNAME("callServices") SEQ, 0, 8, 8, SKIP | EXT | OPT, 0, + _QseriesOptions}, + {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, + {FNAME("sourceCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Setup_UUIE, sourceCallSignalAddress), _TransportAddress}, + {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("h245SecurityCapability") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Setup_UUIE, fastStart), _Setup_UUIE_fastStart}, + {FNAME("mediaWaitForConnect") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("canOverlapSend") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("connectionParameters") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("symmetricOperationRequired") NUL, FIXD, 0, 0, SKIP | OPT, 0, + NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, + {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("neededFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("desiredFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("parallelH245Control") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("additionalSourceAddresses") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + NULL}, +}; + +static field_t _CallProceeding_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _CallProceeding_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, + _EndpointType}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(CallProceeding_UUIE, h245Address), _TransportAddress}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(CallProceeding_UUIE, fastStart), + _CallProceeding_UUIE_fastStart}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _Connect_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Connect_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Connect_UUIE, h245Address), _TransportAddress}, + {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, + _EndpointType}, + {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Connect_UUIE, fastStart), _Connect_UUIE_fastStart}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("connectedAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _Alerting_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Alerting_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, + _EndpointType}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Alerting_UUIE, h245Address), _TransportAddress}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Alerting_UUIE, fastStart), _Alerting_UUIE_fastStart}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("alertingAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _Information_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Information_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Information_UUIE, fastStart), _Information_UUIE_fastStart}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _ReleaseCompleteReason[] = { /* CHOICE */ + {FNAME("noBandwidth") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("gatekeeperResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("unreachableDestination") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("destinationRejection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("invalidRevision") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("noPermission") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("unreachableGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("gatewayResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("badFormatAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("adaptiveBusy") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("inConf") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("facilityCallDeflection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("securityDenied") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("calledPartyNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("callerNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("newConnectionNeeded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("nonStandardReason") SEQ, 0, 2, 2, SKIP, 0, NULL}, + {FNAME("replaceWithConferenceInvite") OCTSTR, FIXD, 16, 0, SKIP, 0, + NULL}, + {FNAME("genericDataReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("neededFeatureNotSupported") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("tunnelledSignallingRejected") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _ReleaseComplete_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("reason") CHOICE, 4, 12, 22, SKIP | EXT | OPT, 0, + _ReleaseCompleteReason}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("busyAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _Facility_UUIE_alternativeAliasAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _FacilityReason[] = { /* CHOICE */ + {FNAME("routeCallToGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("callForwarded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("routeCallToMC") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("conferenceListChoice") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("startH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("noH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("newTokens") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("featureSetUpdate") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("forwardedElements") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("transportedInformation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _Facility_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Facility_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Facility_UUIE, alternativeAddress), _TransportAddress}, + {FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Facility_UUIE_alternativeAliasAddress}, + {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, + {FNAME("reason") CHOICE, 2, 4, 11, DECODE | EXT, + offsetof(Facility_UUIE, reason), _FacilityReason}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("conferences") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Facility_UUIE, h245Address), _TransportAddress}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Facility_UUIE, fastStart), _Facility_UUIE_fastStart}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, + {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT | OPT, 0, NULL}, + {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, + NULL}, +}; + +static field_t _CallIdentifier[] = { /* SEQUENCE */ + {FNAME("guid") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, +}; + +static field_t _SecurityServiceMode[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, + {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("default") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _SecurityCapabilities[] = { /* SEQUENCE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("encryption") CHOICE, 2, 3, 3, SKIP | EXT, 0, + _SecurityServiceMode}, + {FNAME("authenticaton") CHOICE, 2, 3, 3, SKIP | EXT, 0, + _SecurityServiceMode}, + {FNAME("integrity") CHOICE, 2, 3, 3, SKIP | EXT, 0, + _SecurityServiceMode}, +}; + +static field_t _H245Security[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, + {FNAME("noSecurity") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("tls") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, + {FNAME("ipsec") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, +}; + +static field_t _DHset[] = { /* SEQUENCE */ + {FNAME("halfkey") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("modSize") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("generator") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _TypedCertificate[] = { /* SEQUENCE */ + {FNAME("type") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("certificate") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H235_NonStandardParameter[] = { /* SEQUENCE */ + {FNAME("nonStandardIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _ClearToken[] = { /* SEQUENCE */ + {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("timeStamp") INT, CONS, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("password") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("dhkey") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, _DHset}, + {FNAME("challenge") OCTSTR, 7, 8, 0, SKIP | OPT, 0, NULL}, + {FNAME("random") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("certificate") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, + _TypedCertificate}, + {FNAME("generalID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, + _H235_NonStandardParameter}, + {FNAME("eckasdhkey") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, NULL}, + {FNAME("sendersID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _Progress_UUIE_tokens[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, +}; + +static field_t _Params[] = { /* SEQUENCE */ + {FNAME("ranInt") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("iv8") OCTSTR, FIXD, 8, 0, SKIP | OPT, 0, NULL}, + {FNAME("iv16") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoEPPwdHash_token[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoEPPwdHash[] = { /* SEQUENCE */ + {FNAME("alias") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, + {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, + {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoEPPwdHash_token}, +}; + +static field_t _CryptoH323Token_cryptoGKPwdHash_token[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoGKPwdHash[] = { /* SEQUENCE */ + {FNAME("gatekeeperId") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, + {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoGKPwdHash_token}, +}; + +static field_t _CryptoH323Token_cryptoEPPwdEncr[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoGKPwdEncr[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoEPCert[] = { /* SEQUENCE */ + {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoGKCert[] = { /* SEQUENCE */ + {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoFastStart[] = { /* SEQUENCE */ + {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoToken_cryptoEncryptedToken_token[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoToken_cryptoEncryptedToken[] = { /* SEQUENCE */ + {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, + _CryptoToken_cryptoEncryptedToken_token}, +}; + +static field_t _CryptoToken_cryptoSignedToken_token[] = { /* SEQUENCE */ + {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoToken_cryptoSignedToken[] = { /* SEQUENCE */ + {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("token") SEQ, 0, 4, 4, SKIP, 0, + _CryptoToken_cryptoSignedToken_token}, +}; + +static field_t _CryptoToken_cryptoHashedToken_token[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoToken_cryptoHashedToken[] = { /* SEQUENCE */ + {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("hashedVals") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, + {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, + _CryptoToken_cryptoHashedToken_token}, +}; + +static field_t _CryptoToken_cryptoPwdEncr[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoToken[] = { /* CHOICE */ + {FNAME("cryptoEncryptedToken") SEQ, 0, 2, 2, SKIP, 0, + _CryptoToken_cryptoEncryptedToken}, + {FNAME("cryptoSignedToken") SEQ, 0, 2, 2, SKIP, 0, + _CryptoToken_cryptoSignedToken}, + {FNAME("cryptoHashedToken") SEQ, 0, 3, 3, SKIP, 0, + _CryptoToken_cryptoHashedToken}, + {FNAME("cryptoPwdEncr") SEQ, 0, 3, 3, SKIP, 0, + _CryptoToken_cryptoPwdEncr}, +}; + +static field_t _CryptoH323Token[] = { /* CHOICE */ + {FNAME("cryptoEPPwdHash") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoEPPwdHash}, + {FNAME("cryptoGKPwdHash") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoGKPwdHash}, + {FNAME("cryptoEPPwdEncr") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoEPPwdEncr}, + {FNAME("cryptoGKPwdEncr") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoGKPwdEncr}, + {FNAME("cryptoEPCert") SEQ, 0, 4, 4, SKIP, 0, + _CryptoH323Token_cryptoEPCert}, + {FNAME("cryptoGKCert") SEQ, 0, 4, 4, SKIP, 0, + _CryptoH323Token_cryptoGKCert}, + {FNAME("cryptoFastStart") SEQ, 0, 4, 4, SKIP, 0, + _CryptoH323Token_cryptoFastStart}, + {FNAME("nestedcryptoToken") CHOICE, 2, 4, 4, SKIP | EXT, 0, + _CryptoToken}, +}; + +static field_t _Progress_UUIE_cryptoTokens[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 8, 8, SKIP | EXT, 0, _CryptoH323Token}, +}; + +static field_t _Progress_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Progress_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, + _EndpointType}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Progress_UUIE, h245Address), _TransportAddress}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, + _CallIdentifier}, + {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, + _H245Security}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Progress_UUIE_tokens}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Progress_UUIE_cryptoTokens}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Progress_UUIE, fastStart), _Progress_UUIE_fastStart}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _H323_UU_PDU_h323_message_body[] = { /* CHOICE */ + {FNAME("setup") SEQ, 7, 13, 39, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, setup), _Setup_UUIE}, + {FNAME("callProceeding") SEQ, 1, 3, 12, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, callProceeding), + _CallProceeding_UUIE}, + {FNAME("connect") SEQ, 1, 4, 19, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, connect), _Connect_UUIE}, + {FNAME("alerting") SEQ, 1, 3, 17, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, alerting), _Alerting_UUIE}, + {FNAME("information") SEQ, 0, 1, 7, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, information), + _Information_UUIE}, + {FNAME("releaseComplete") SEQ, 1, 2, 11, SKIP | EXT, 0, + _ReleaseComplete_UUIE}, + {FNAME("facility") SEQ, 3, 5, 21, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, facility), _Facility_UUIE}, + {FNAME("progress") SEQ, 5, 8, 11, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, progress), _Progress_UUIE}, + {FNAME("empty") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("status") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, + {FNAME("statusInquiry") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, + {FNAME("setupAcknowledge") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, + {FNAME("notify") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, +}; + +static field_t _RequestMessage[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("masterSlaveDetermination") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("terminalCapabilitySet") SEQ, 3, 5, 5, STOP | EXT, 0, NULL}, + {FNAME("openLogicalChannel") SEQ, 1, 3, 5, DECODE | EXT, + offsetof(RequestMessage, openLogicalChannel), _OpenLogicalChannel}, + {FNAME("closeLogicalChannel") SEQ, 0, 2, 3, STOP | EXT, 0, NULL}, + {FNAME("requestChannelClose") SEQ, 0, 1, 3, STOP | EXT, 0, NULL}, + {FNAME("multiplexEntrySend") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("requestMultiplexEntry") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("requestMode") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("roundTripDelayRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("maintenanceLoopRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("communicationModeRequest") SEQ, 0, 0, 0, STOP | EXT, 0, NULL}, + {FNAME("conferenceRequest") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, + {FNAME("multilinkRequest") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, + {FNAME("logicalChannelRateRequest") SEQ, 0, 3, 3, STOP | EXT, 0, + NULL}, +}; + +static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ + {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, + _H222LogicalChannelParameters}, + {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, + offsetof + (OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters, + h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, +}; + +static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("reverseLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("multiplexParameters") CHOICE, 0, 1, 2, DECODE | EXT | OPT, + offsetof(OpenLogicalChannelAck_reverseLogicalChannelParameters, + multiplexParameters), + _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters}, + {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _H2250LogicalChannelAckParameters_nonStandard[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, +}; + +static field_t _H2250LogicalChannelAckParameters[] = { /* SEQUENCE */ + {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _H2250LogicalChannelAckParameters_nonStandard}, + {FNAME("sessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, + offsetof(H2250LogicalChannelAckParameters, mediaChannel), + _H245_TransportAddress}, + {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, + offsetof(H2250LogicalChannelAckParameters, mediaControlChannel), + _H245_TransportAddress}, + {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, SKIP | OPT, 0, NULL}, + {FNAME("flowControlToZero") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = { /* CHOICE */ + {FNAME("h2250LogicalChannelAckParameters") SEQ, 5, 5, 7, DECODE | EXT, + offsetof(OpenLogicalChannelAck_forwardMultiplexAckParameters, + h2250LogicalChannelAckParameters), + _H2250LogicalChannelAckParameters}, +}; + +static field_t _OpenLogicalChannelAck[] = { /* SEQUENCE */ + {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("reverseLogicalChannelParameters") SEQ, 2, 3, 4, + DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, + reverseLogicalChannelParameters), + _OpenLogicalChannelAck_reverseLogicalChannelParameters}, + {FNAME("separateStack") SEQ, 2, 4, 5, SKIP | EXT | OPT, 0, NULL}, + {FNAME("forwardMultiplexAckParameters") CHOICE, 0, 1, 1, + DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, + forwardMultiplexAckParameters), + _OpenLogicalChannelAck_forwardMultiplexAckParameters}, + {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, +}; + +static field_t _ResponseMessage[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("masterSlaveDeterminationAck") SEQ, 0, 1, 1, STOP | EXT, 0, + NULL}, + {FNAME("masterSlaveDeterminationReject") SEQ, 0, 1, 1, STOP | EXT, 0, + NULL}, + {FNAME("terminalCapabilitySetAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("terminalCapabilitySetReject") SEQ, 0, 2, 2, STOP | EXT, 0, + NULL}, + {FNAME("openLogicalChannelAck") SEQ, 1, 2, 5, DECODE | EXT, + offsetof(ResponseMessage, openLogicalChannelAck), + _OpenLogicalChannelAck}, + {FNAME("openLogicalChannelReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("closeLogicalChannelAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("requestChannelCloseAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("requestChannelCloseReject") SEQ, 0, 2, 2, STOP | EXT, 0, + NULL}, + {FNAME("multiplexEntrySendAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("multiplexEntrySendReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("requestMultiplexEntryAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("requestMultiplexEntryReject") SEQ, 0, 2, 2, STOP | EXT, 0, + NULL}, + {FNAME("requestModeAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("requestModeReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("roundTripDelayResponse") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("maintenanceLoopAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("maintenanceLoopReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("communicationModeResponse") CHOICE, 0, 1, 1, STOP | EXT, 0, + NULL}, + {FNAME("conferenceResponse") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, + {FNAME("multilinkResponse") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, + {FNAME("logicalChannelRateAcknowledge") SEQ, 0, 3, 3, STOP | EXT, 0, + NULL}, + {FNAME("logicalChannelRateReject") SEQ, 1, 4, 4, STOP | EXT, 0, NULL}, +}; + +static field_t _MultimediaSystemControlMessage[] = { /* CHOICE */ + {FNAME("request") CHOICE, 4, 11, 15, DECODE | EXT, + offsetof(MultimediaSystemControlMessage, request), _RequestMessage}, + {FNAME("response") CHOICE, 5, 19, 24, DECODE | EXT, + offsetof(MultimediaSystemControlMessage, response), + _ResponseMessage}, + {FNAME("command") CHOICE, 3, 7, 12, STOP | EXT, 0, NULL}, + {FNAME("indication") CHOICE, 4, 14, 23, STOP | EXT, 0, NULL}, +}; + +static field_t _H323_UU_PDU_h245Control[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 2, 4, 4, DECODE | OPEN | EXT, + sizeof(MultimediaSystemControlMessage), + _MultimediaSystemControlMessage} + , +}; + +static field_t _H323_UU_PDU[] = { /* SEQUENCE */ + {FNAME("h323-message-body") CHOICE, 3, 7, 13, DECODE | EXT, + offsetof(H323_UU_PDU, h323_message_body), + _H323_UU_PDU_h323_message_body}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("h4501SupplementaryService") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + NULL}, + {FNAME("h245Tunneling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("h245Control") SEQOF, SEMI, 0, 4, DECODE | OPT, + offsetof(H323_UU_PDU, h245Control), _H323_UU_PDU_h245Control}, + {FNAME("nonStandardControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("tunnelledSignallingMessage") SEQ, 2, 4, 4, STOP | EXT | OPT, + 0, NULL}, + {FNAME("provisionalRespToH245Tunneling") NUL, FIXD, 0, 0, STOP | OPT, + 0, NULL}, + {FNAME("stimulusControl") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _H323_UserInformation[] = { /* SEQUENCE */ + {FNAME("h323-uu-pdu") SEQ, 1, 2, 11, DECODE | EXT, + offsetof(H323_UserInformation, h323_uu_pdu), _H323_UU_PDU}, + {FNAME("user-data") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, +}; + +static field_t _GatekeeperRequest[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(GatekeeperRequest, rasAddress), _TransportAddress}, + {FNAME("endpointType") SEQ, 6, 8, 10, STOP | EXT, 0, NULL}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, + {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("authenticationCapability") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("algorithmOIDs") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _GatekeeperConfirm[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(GatekeeperConfirm, rasAddress), _TransportAddress}, + {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("authenticationMode") CHOICE, 3, 7, 8, STOP | EXT | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("algorithmOID") OID, BYTE, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _RegistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, + sizeof(TransportAddress), _TransportAddress} + , +}; + +static field_t _RegistrationRequest_rasAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, + sizeof(TransportAddress), _TransportAddress} + , +}; + +static field_t _RegistrationRequest_terminalAlias[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _RegistrationRequest[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("discoveryComplete") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, + offsetof(RegistrationRequest, callSignalAddress), + _RegistrationRequest_callSignalAddress}, + {FNAME("rasAddress") SEQOF, SEMI, 0, 10, DECODE, + offsetof(RegistrationRequest, rasAddress), + _RegistrationRequest_rasAddress}, + {FNAME("terminalType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, + {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _RegistrationRequest_terminalAlias}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("endpointVendor") SEQ, 2, 3, 3, SKIP | EXT, 0, + _VendorIdentifier}, + {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, + offsetof(RegistrationRequest, timeToLive), NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("keepAlive") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, + 0, NULL}, + {FNAME("additiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("usageReportingCapability") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, + NULL}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("supportedH248Packages") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("callCreditCapability") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, + NULL}, + {FNAME("capacityReportingCapability") SEQ, 0, 1, 1, STOP | EXT | OPT, + 0, NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _RegistrationConfirm_callSignalAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, + sizeof(TransportAddress), _TransportAddress} + , +}; + +static field_t _RegistrationConfirm_terminalAlias[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _RegistrationConfirm[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, + offsetof(RegistrationConfirm, callSignalAddress), + _RegistrationConfirm_callSignalAddress}, + {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _RegistrationConfirm_terminalAlias}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, + offsetof(RegistrationConfirm, timeToLive), NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("preGrantedARQ") SEQ, 0, 4, 8, STOP | EXT | OPT, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("supportsAdditiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("featureServerAlias") CHOICE, 1, 2, 7, STOP | EXT | OPT, 0, + NULL}, + {FNAME("capacityReportingSpec") SEQ, 0, 1, 1, STOP | EXT | OPT, 0, + NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _UnregistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, + sizeof(TransportAddress), _TransportAddress} + , +}; + +static field_t _UnregistrationRequest[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, + offsetof(UnregistrationRequest, callSignalAddress), + _UnregistrationRequest_callSignalAddress}, + {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("reason") CHOICE, 2, 4, 5, STOP | EXT | OPT, 0, NULL}, + {FNAME("endpointAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _CallModel[] = { /* CHOICE */ + {FNAME("direct") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("gatekeeperRouted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _AdmissionRequest_destinationInfo[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _AdmissionRequest_destExtraCallInfo[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _AdmissionRequest_srcInfo[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _AdmissionRequest[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, + {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, _CallModel}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _AdmissionRequest_destinationInfo}, + {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(AdmissionRequest, destCallSignalAddress), + _TransportAddress}, + {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _AdmissionRequest_destExtraCallInfo}, + {FNAME("srcInfo") SEQOF, SEMI, 0, 0, SKIP, 0, + _AdmissionRequest_srcInfo}, + {FNAME("srcCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(AdmissionRequest, srcCallSignalAddress), _TransportAddress}, + {FNAME("bandWidth") INT, CONS, 0, 0, STOP, 0, NULL}, + {FNAME("callReferenceValue") INT, WORD, 0, 0, STOP, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, + {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, STOP, 0, NULL}, + {FNAME("activeMC") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("answerCall") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("srcAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("gatewayDataRate") SEQ, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, + NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _AdmissionConfirm[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("bandWidth") INT, CONS, 0, 0, SKIP, 0, NULL}, + {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT, 0, _CallModel}, + {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(AdmissionConfirm, destCallSignalAddress), + _TransportAddress}, + {FNAME("irrFrequency") INT, WORD, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, + {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("uuiesRequested") SEQ, 0, 9, 13, STOP | EXT, 0, NULL}, + {FNAME("language") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, + 0, NULL}, + {FNAME("useSpecifiedTransport") CHOICE, 1, 2, 2, STOP | EXT | OPT, 0, + NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _LocationRequest_destinationInfo[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _LocationRequest[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP, 0, + _LocationRequest_destinationInfo}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("replyAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(LocationRequest, replyAddress), _TransportAddress}, + {FNAME("sourceInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, + NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("hopCount") INT, 8, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, +}; + +static field_t _LocationConfirm[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("callSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(LocationConfirm, callSignalAddress), _TransportAddress}, + {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(LocationConfirm, rasAddress), _TransportAddress}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, + {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, + 0, NULL}, + {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _InfoRequestResponse_callSignalAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, + sizeof(TransportAddress), _TransportAddress} + , +}; + +static field_t _InfoRequestResponse[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("endpointType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(InfoRequestResponse, rasAddress), _TransportAddress}, + {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, + offsetof(InfoRequestResponse, callSignalAddress), + _InfoRequestResponse_callSignalAddress}, + {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("perCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("needResponse") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("irrStatus") CHOICE, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("unsolicited") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _RasMessage[] = { /* CHOICE */ + {FNAME("gatekeeperRequest") SEQ, 4, 8, 18, DECODE | EXT, + offsetof(RasMessage, gatekeeperRequest), _GatekeeperRequest}, + {FNAME("gatekeeperConfirm") SEQ, 2, 5, 14, DECODE | EXT, + offsetof(RasMessage, gatekeeperConfirm), _GatekeeperConfirm}, + {FNAME("gatekeeperReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, + {FNAME("registrationRequest") SEQ, 3, 10, 31, DECODE | EXT, + offsetof(RasMessage, registrationRequest), _RegistrationRequest}, + {FNAME("registrationConfirm") SEQ, 3, 7, 24, DECODE | EXT, + offsetof(RasMessage, registrationConfirm), _RegistrationConfirm}, + {FNAME("registrationReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, + {FNAME("unregistrationRequest") SEQ, 3, 5, 15, DECODE | EXT, + offsetof(RasMessage, unregistrationRequest), _UnregistrationRequest}, + {FNAME("unregistrationConfirm") SEQ, 1, 2, 6, STOP | EXT, 0, NULL}, + {FNAME("unregistrationReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, + {FNAME("admissionRequest") SEQ, 7, 16, 34, DECODE | EXT, + offsetof(RasMessage, admissionRequest), _AdmissionRequest}, + {FNAME("admissionConfirm") SEQ, 2, 6, 27, DECODE | EXT, + offsetof(RasMessage, admissionConfirm), _AdmissionConfirm}, + {FNAME("admissionReject") SEQ, 1, 3, 11, STOP | EXT, 0, NULL}, + {FNAME("bandwidthRequest") SEQ, 2, 7, 18, STOP | EXT, 0, NULL}, + {FNAME("bandwidthConfirm") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, + {FNAME("bandwidthReject") SEQ, 1, 4, 9, STOP | EXT, 0, NULL}, + {FNAME("disengageRequest") SEQ, 1, 6, 19, STOP | EXT, 0, NULL}, + {FNAME("disengageConfirm") SEQ, 1, 2, 9, STOP | EXT, 0, NULL}, + {FNAME("disengageReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, + {FNAME("locationRequest") SEQ, 2, 5, 17, DECODE | EXT, + offsetof(RasMessage, locationRequest), _LocationRequest}, + {FNAME("locationConfirm") SEQ, 1, 4, 19, DECODE | EXT, + offsetof(RasMessage, locationConfirm), _LocationConfirm}, + {FNAME("locationReject") SEQ, 1, 3, 10, STOP | EXT, 0, NULL}, + {FNAME("infoRequest") SEQ, 2, 4, 15, STOP | EXT, 0, NULL}, + {FNAME("infoRequestResponse") SEQ, 3, 8, 16, DECODE | EXT, + offsetof(RasMessage, infoRequestResponse), _InfoRequestResponse}, + {FNAME("nonStandardMessage") SEQ, 0, 2, 7, STOP | EXT, 0, NULL}, + {FNAME("unknownMessageResponse") SEQ, 0, 1, 5, STOP | EXT, 0, NULL}, + {FNAME("requestInProgress") SEQ, 4, 6, 6, STOP | EXT, 0, NULL}, + {FNAME("resourcesAvailableIndicate") SEQ, 4, 9, 11, STOP | EXT, 0, + NULL}, + {FNAME("resourcesAvailableConfirm") SEQ, 4, 6, 7, STOP | EXT, 0, + NULL}, + {FNAME("infoRequestAck") SEQ, 4, 5, 5, STOP | EXT, 0, NULL}, + {FNAME("infoRequestNak") SEQ, 5, 7, 7, STOP | EXT, 0, NULL}, + {FNAME("serviceControlIndication") SEQ, 8, 10, 10, STOP | EXT, 0, + NULL}, + {FNAME("serviceControlResponse") SEQ, 7, 8, 8, STOP | EXT, 0, NULL}, +}; -- cgit v1.2.3 From 869f37d8e48f3911eb70f38a994feaa8f8380008 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:09:06 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add IRC helper port Add nf_conntrack port of the IRC conntrack/NAT helper. Since DCC doesn't support IPv6 yet, the helper is still IPv4 only. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_irc.h | 15 ++ net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_irc.c | 101 +++++++++++ net/netfilter/Kconfig | 15 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_irc.c | 281 +++++++++++++++++++++++++++++ 7 files changed, 419 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_irc.h create mode 100644 net/ipv4/netfilter/nf_nat_irc.c create mode 100644 net/netfilter/nf_conntrack_irc.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_irc.h b/include/linux/netfilter/nf_conntrack_irc.h new file mode 100644 index 000000000000..2ab6b8255911 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_irc.h @@ -0,0 +1,15 @@ +#ifndef _NF_CONNTRACK_IRC_H +#define _NF_CONNTRACK_IRC_H + +#ifdef __KERNEL__ + +#define IRC_PORT 6667 + +extern unsigned int (*nf_nat_irc_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp); + +#endif /* __KERNEL__ */ +#endif /* _NF_CONNTRACK_IRC_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index e14156d1122e..4555f721dfc1 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -500,6 +500,11 @@ config IP_NF_NAT_IRC default IP_NF_NAT if IP_NF_IRC=y default m if IP_NF_IRC=m +config NF_NAT_IRC + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_IRC + config IP_NF_NAT_TFTP tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index bdaba4700e3b..56733c370327 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o +obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c new file mode 100644 index 000000000000..9b8c0daea744 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_irc.c @@ -0,0 +1,101 @@ +/* IRC extension for TCP NAT alteration. + * + * (C) 2000-2001 by Harald Welte + * (C) 2004 Rusty Russell IBM Corporation + * based on a copy of RR's ip_nat_ftp.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IRC (DCC) NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_irc"); + +static unsigned int help(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp) +{ + char buffer[sizeof("4294967296 65635")]; + u_int32_t ip; + u_int16_t port; + unsigned int ret; + + DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n", + expect->seq, exp_irc_info->len, ntohl(tcph->seq)); + + /* Reply comes from server. */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->dir = IP_CT_DIR_REPLY; + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + exp->tuple.dst.u.tcp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip); + sprintf(buffer, "%u %u", ip, port); + DEBUGP("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n", + buffer, NIPQUAD(ip), port); + + ret = nf_nat_mangle_tcp_packet(pskb, exp->master, ctinfo, + matchoff, matchlen, buffer, + strlen(buffer)); + if (ret != NF_ACCEPT) + nf_conntrack_unexpect_related(exp); + return ret; +} + +static void __exit nf_nat_irc_fini(void) +{ + rcu_assign_pointer(nf_nat_irc_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_irc_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_irc_hook)); + rcu_assign_pointer(nf_nat_irc_hook, help); + return 0; +} + +/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ +static int warn_set(const char *val, struct kernel_param *kp) +{ + printk(KERN_INFO KBUILD_MODNAME + ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); + return 0; +} +module_param_call(ports, warn_set, NULL, NULL, 0); + +module_init(nf_nat_irc_init); +module_exit(nf_nat_irc_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index d8f3451c95b6..bd50897d8fbb 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -179,6 +179,21 @@ config NF_CONNTRACK_H323 To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_IRC + tristate "IRC protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + help + There is a commonly-used extension to IRC called + Direct Client-to-Client Protocol (DCC). This enables users to send + files to each other, and also chat to each other without the need + of a server. DCC Sending is used anywhere you send files over IRC, + and DCC Chat is most commonly used by Eggdrop bots. If you are + using NAT, this extension will enable you to send files and initiate + chats. Note that you do NOT need this extension to get files or + have others initiate chats, or everything else in IRC. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CT_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 69b554576b6b..343fd4896406 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -25,6 +25,7 @@ nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o +obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c new file mode 100644 index 000000000000..ed01db634399 --- /dev/null +++ b/net/netfilter/nf_conntrack_irc.c @@ -0,0 +1,281 @@ +/* IRC extension for IP connection tracking, Version 1.21 + * (C) 2000-2002 by Harald Welte + * based on RR's ip_conntrack_ftp.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_PORTS 8 +static unsigned short ports[MAX_PORTS]; +static int ports_c; +static unsigned int max_dcc_channels = 8; +static unsigned int dcc_timeout __read_mostly = 300; +/* This is slow, but it's simple. --RR */ +static char *irc_buffer; +static DEFINE_SPINLOCK(irc_buffer_lock); + +unsigned int (*nf_nat_irc_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_irc_hook); + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IRC (DCC) connection tracking helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_conntrack_irc"); + +module_param_array(ports, ushort, &ports_c, 0400); +MODULE_PARM_DESC(ports, "port numbers of IRC servers"); +module_param(max_dcc_channels, uint, 0400); +MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per " + "IRC session"); +module_param(dcc_timeout, uint, 0400); +MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); + +static const char *dccprotos[] = { + "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " +}; + +#define MINMATCHLEN 5 + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s:" format, \ + __FILE__, __FUNCTION__ , ## args) +#else +#define DEBUGP(format, args...) +#endif + +/* tries to get the ip_addr and port out of a dcc command + * return value: -1 on failure, 0 on success + * data pointer to first byte of DCC command data + * data_end pointer to last byte of dcc command data + * ip returns parsed ip of dcc command + * port returns parsed port of dcc command + * ad_beg_p returns pointer to first byte of addr data + * ad_end_p returns pointer to last byte of addr data + */ +static int parse_dcc(char *data, char *data_end, u_int32_t *ip, + u_int16_t *port, char **ad_beg_p, char **ad_end_p) +{ + /* at least 12: "AAAAAAAA P\1\n" */ + while (*data++ != ' ') + if (data > data_end - 12) + return -1; + + *ad_beg_p = data; + *ip = simple_strtoul(data, &data, 10); + + /* skip blanks between ip and port */ + while (*data == ' ') { + if (data >= data_end) + return -1; + data++; + } + + *port = simple_strtoul(data, &data, 10); + *ad_end_p = data; + + return 0; +} + +static int help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) +{ + unsigned int dataoff; + struct tcphdr _tcph, *th; + char *data, *data_limit, *ib_ptr; + int dir = CTINFO2DIR(ctinfo); + struct nf_conntrack_expect *exp; + struct nf_conntrack_tuple *tuple; + u_int32_t dcc_ip; + u_int16_t dcc_port; + __be16 port; + int i, ret = NF_ACCEPT; + char *addr_beg_p, *addr_end_p; + typeof(nf_nat_irc_hook) nf_nat_irc; + + /* If packet is coming from IRC server */ + if (dir == IP_CT_DIR_REPLY) + return NF_ACCEPT; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) + return NF_ACCEPT; + + /* Not a full tcp header? */ + th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph); + if (th == NULL) + return NF_ACCEPT; + + /* No data? */ + dataoff = protoff + th->doff*4; + if (dataoff >= (*pskb)->len) + return NF_ACCEPT; + + spin_lock_bh(&irc_buffer_lock); + ib_ptr = skb_header_pointer(*pskb, dataoff, (*pskb)->len - dataoff, + irc_buffer); + BUG_ON(ib_ptr == NULL); + + data = ib_ptr; + data_limit = ib_ptr + (*pskb)->len - dataoff; + + /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24 + * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ + while (data < data_limit - (19 + MINMATCHLEN)) { + if (memcmp(data, "\1DCC ", 5)) { + data++; + continue; + } + data += 5; + /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ + + DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", + NIPQUAD(iph->saddr), ntohs(th->source), + NIPQUAD(iph->daddr), ntohs(th->dest)); + + for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { + if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { + /* no match */ + continue; + } + data += strlen(dccprotos[i]); + DEBUGP("DCC %s detected\n", dccprotos[i]); + + /* we have at least + * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid + * data left (== 14/13 bytes) */ + if (parse_dcc((char *)data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + DEBUGP("unable to parse dcc command\n"); + continue; + } + DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n", + HIPQUAD(dcc_ip), dcc_port); + + /* dcc_ip can be the internal OR external (NAT'ed) IP */ + tuple = &ct->tuplehash[dir].tuple; + if (tuple->src.u3.ip != htonl(dcc_ip) && + tuple->dst.u3.ip != htonl(dcc_ip)) { + if (net_ratelimit()) + printk(KERN_WARNING + "Forged DCC command from " + "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", + NIPQUAD(tuple->src.u3.ip), + HIPQUAD(dcc_ip), dcc_port); + continue; + } + + exp = nf_conntrack_expect_alloc(ct); + if (exp == NULL) { + ret = NF_DROP; + goto out; + } + tuple = &ct->tuplehash[!dir].tuple; + port = htons(dcc_port); + nf_conntrack_expect_init(exp, tuple->src.l3num, + NULL, &tuple->dst.u3, + IPPROTO_TCP, NULL, &port); + + nf_nat_irc = rcu_dereference(nf_nat_irc_hook); + if (nf_nat_irc && ct->status & IPS_NAT_MASK) + ret = nf_nat_irc(pskb, ctinfo, + addr_beg_p - ib_ptr, + addr_end_p - addr_beg_p, + exp); + else if (nf_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + nf_conntrack_expect_put(exp); + goto out; + } + } + out: + spin_unlock_bh(&irc_buffer_lock); + return ret; +} + +static struct nf_conntrack_helper irc[MAX_PORTS] __read_mostly; +static char irc_names[MAX_PORTS][sizeof("irc-65535")] __read_mostly; + +static void nf_conntrack_irc_fini(void); + +static int __init nf_conntrack_irc_init(void) +{ + int i, ret; + char *tmpname; + + if (max_dcc_channels < 1) { + printk("nf_ct_irc: max_dcc_channels must not be zero\n"); + return -EINVAL; + } + + irc_buffer = kmalloc(65536, GFP_KERNEL); + if (!irc_buffer) + return -ENOMEM; + + /* If no port given, default to standard irc port */ + if (ports_c == 0) + ports[ports_c++] = IRC_PORT; + + for (i = 0; i < ports_c; i++) { + irc[i].tuple.src.l3num = AF_INET; + irc[i].tuple.src.u.tcp.port = htons(ports[i]); + irc[i].tuple.dst.protonum = IPPROTO_TCP; + irc[i].mask.src.l3num = 0xFFFF; + irc[i].mask.src.u.tcp.port = htons(0xFFFF); + irc[i].mask.dst.protonum = 0xFF; + irc[i].max_expected = max_dcc_channels; + irc[i].timeout = dcc_timeout; + irc[i].me = THIS_MODULE; + irc[i].help = help; + + tmpname = &irc_names[i][0]; + if (ports[i] == IRC_PORT) + sprintf(tmpname, "irc"); + else + sprintf(tmpname, "irc-%u", i); + irc[i].name = tmpname; + + ret = nf_conntrack_helper_register(&irc[i]); + if (ret) { + printk("nf_ct_irc: failed to register helper " + "for pf: %u port: %u\n", + irc[i].tuple.src.l3num, ports[i]); + nf_conntrack_irc_fini(); + return ret; + } + } + return 0; +} + +/* This function is intentionally _NOT_ defined as __exit, because + * it is needed by the init function */ +static void nf_conntrack_irc_fini(void) +{ + int i; + + for (i = 0; i < ports_c; i++) + nf_conntrack_helper_unregister(&irc[i]); + kfree(irc_buffer); +} + +module_init(nf_conntrack_irc_init); +module_exit(nf_conntrack_irc_fini); -- cgit v1.2.3 From f09943fefe6b702e40893d35b4f10fd1064037fe Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:09:41 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add PPTP helper port Add nf_conntrack port of the PPtP conntrack/NAT helper. Since there seems to be no IPv6-capable PPtP implementation the helper only support IPv4. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_pptp.h | 321 ++++++++++++ include/linux/netfilter/nf_conntrack_proto_gre.h | 112 +++++ include/net/netfilter/ipv4/nf_conntrack_ipv4.h | 2 + include/net/netfilter/nf_conntrack.h | 4 + include/net/netfilter/nf_conntrack_helper.h | 2 + include/net/netfilter/nf_conntrack_tuple.h | 6 + net/ipv4/netfilter/Kconfig | 10 + net/ipv4/netfilter/Makefile | 4 + net/ipv4/netfilter/nf_nat_pptp.c | 315 ++++++++++++ net/ipv4/netfilter/nf_nat_proto_gre.c | 179 +++++++ net/netfilter/Kconfig | 23 + net/netfilter/Makefile | 2 + net/netfilter/nf_conntrack_core.c | 4 + net/netfilter/nf_conntrack_pptp.c | 607 +++++++++++++++++++++++ net/netfilter/nf_conntrack_proto_gre.c | 305 ++++++++++++ 15 files changed, 1896 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_pptp.h create mode 100644 include/linux/netfilter/nf_conntrack_proto_gre.h create mode 100644 net/ipv4/netfilter/nf_nat_pptp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_gre.c create mode 100644 net/netfilter/nf_conntrack_pptp.c create mode 100644 net/netfilter/nf_conntrack_proto_gre.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_pptp.h b/include/linux/netfilter/nf_conntrack_pptp.h new file mode 100644 index 000000000000..fb049ec11ff2 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_pptp.h @@ -0,0 +1,321 @@ +/* PPTP constants and structs */ +#ifndef _NF_CONNTRACK_PPTP_H +#define _NF_CONNTRACK_PPTP_H + +/* state of the control session */ +enum pptp_ctrlsess_state { + PPTP_SESSION_NONE, /* no session present */ + PPTP_SESSION_ERROR, /* some session error */ + PPTP_SESSION_STOPREQ, /* stop_sess request seen */ + PPTP_SESSION_REQUESTED, /* start_sess request seen */ + PPTP_SESSION_CONFIRMED, /* session established */ +}; + +/* state of the call inside the control session */ +enum pptp_ctrlcall_state { + PPTP_CALL_NONE, + PPTP_CALL_ERROR, + PPTP_CALL_OUT_REQ, + PPTP_CALL_OUT_CONF, + PPTP_CALL_IN_REQ, + PPTP_CALL_IN_REP, + PPTP_CALL_IN_CONF, + PPTP_CALL_CLEAR_REQ, +}; + +/* conntrack private data */ +struct nf_ct_pptp_master { + enum pptp_ctrlsess_state sstate; /* session state */ + enum pptp_ctrlcall_state cstate; /* call state */ + __be16 pac_call_id; /* call id of PAC */ + __be16 pns_call_id; /* call id of PNS */ + + /* in pre-2.6.11 this used to be per-expect. Now it is per-conntrack + * and therefore imposes a fixed limit on the number of maps */ + struct nf_ct_gre_keymap *keymap[IP_CT_DIR_MAX]; +}; + +struct nf_nat_pptp { + __be16 pns_call_id; /* NAT'ed PNS call id */ + __be16 pac_call_id; /* NAT'ed PAC call id */ +}; + +#ifdef __KERNEL__ + +#define PPTP_CONTROL_PORT 1723 + +#define PPTP_PACKET_CONTROL 1 +#define PPTP_PACKET_MGMT 2 + +#define PPTP_MAGIC_COOKIE 0x1a2b3c4d + +struct pptp_pkt_hdr { + __u16 packetLength; + __be16 packetType; + __be32 magicCookie; +}; + +/* PptpControlMessageType values */ +#define PPTP_START_SESSION_REQUEST 1 +#define PPTP_START_SESSION_REPLY 2 +#define PPTP_STOP_SESSION_REQUEST 3 +#define PPTP_STOP_SESSION_REPLY 4 +#define PPTP_ECHO_REQUEST 5 +#define PPTP_ECHO_REPLY 6 +#define PPTP_OUT_CALL_REQUEST 7 +#define PPTP_OUT_CALL_REPLY 8 +#define PPTP_IN_CALL_REQUEST 9 +#define PPTP_IN_CALL_REPLY 10 +#define PPTP_IN_CALL_CONNECT 11 +#define PPTP_CALL_CLEAR_REQUEST 12 +#define PPTP_CALL_DISCONNECT_NOTIFY 13 +#define PPTP_WAN_ERROR_NOTIFY 14 +#define PPTP_SET_LINK_INFO 15 + +#define PPTP_MSG_MAX 15 + +/* PptpGeneralError values */ +#define PPTP_ERROR_CODE_NONE 0 +#define PPTP_NOT_CONNECTED 1 +#define PPTP_BAD_FORMAT 2 +#define PPTP_BAD_VALUE 3 +#define PPTP_NO_RESOURCE 4 +#define PPTP_BAD_CALLID 5 +#define PPTP_REMOVE_DEVICE_ERROR 6 + +struct PptpControlHeader { + __be16 messageType; + __u16 reserved; +}; + +/* FramingCapability Bitmap Values */ +#define PPTP_FRAME_CAP_ASYNC 0x1 +#define PPTP_FRAME_CAP_SYNC 0x2 + +/* BearerCapability Bitmap Values */ +#define PPTP_BEARER_CAP_ANALOG 0x1 +#define PPTP_BEARER_CAP_DIGITAL 0x2 + +struct PptpStartSessionRequest { + __be16 protocolVersion; + __u16 reserved1; + __be32 framingCapability; + __be32 bearerCapability; + __be16 maxChannels; + __be16 firmwareRevision; + __u8 hostName[64]; + __u8 vendorString[64]; +}; + +/* PptpStartSessionResultCode Values */ +#define PPTP_START_OK 1 +#define PPTP_START_GENERAL_ERROR 2 +#define PPTP_START_ALREADY_CONNECTED 3 +#define PPTP_START_NOT_AUTHORIZED 4 +#define PPTP_START_UNKNOWN_PROTOCOL 5 + +struct PptpStartSessionReply { + __be16 protocolVersion; + __u8 resultCode; + __u8 generalErrorCode; + __be32 framingCapability; + __be32 bearerCapability; + __be16 maxChannels; + __be16 firmwareRevision; + __u8 hostName[64]; + __u8 vendorString[64]; +}; + +/* PptpStopReasons */ +#define PPTP_STOP_NONE 1 +#define PPTP_STOP_PROTOCOL 2 +#define PPTP_STOP_LOCAL_SHUTDOWN 3 + +struct PptpStopSessionRequest { + __u8 reason; + __u8 reserved1; + __u16 reserved2; +}; + +/* PptpStopSessionResultCode */ +#define PPTP_STOP_OK 1 +#define PPTP_STOP_GENERAL_ERROR 2 + +struct PptpStopSessionReply { + __u8 resultCode; + __u8 generalErrorCode; + __u16 reserved1; +}; + +struct PptpEchoRequest { + __be32 identNumber; +}; + +/* PptpEchoReplyResultCode */ +#define PPTP_ECHO_OK 1 +#define PPTP_ECHO_GENERAL_ERROR 2 + +struct PptpEchoReply { + __be32 identNumber; + __u8 resultCode; + __u8 generalErrorCode; + __u16 reserved; +}; + +/* PptpFramingType */ +#define PPTP_ASYNC_FRAMING 1 +#define PPTP_SYNC_FRAMING 2 +#define PPTP_DONT_CARE_FRAMING 3 + +/* PptpCallBearerType */ +#define PPTP_ANALOG_TYPE 1 +#define PPTP_DIGITAL_TYPE 2 +#define PPTP_DONT_CARE_BEARER_TYPE 3 + +struct PptpOutCallRequest { + __be16 callID; + __be16 callSerialNumber; + __be32 minBPS; + __be32 maxBPS; + __be32 bearerType; + __be32 framingType; + __be16 packetWindow; + __be16 packetProcDelay; + __be16 phoneNumberLength; + __u16 reserved1; + __u8 phoneNumber[64]; + __u8 subAddress[64]; +}; + +/* PptpCallResultCode */ +#define PPTP_OUTCALL_CONNECT 1 +#define PPTP_OUTCALL_GENERAL_ERROR 2 +#define PPTP_OUTCALL_NO_CARRIER 3 +#define PPTP_OUTCALL_BUSY 4 +#define PPTP_OUTCALL_NO_DIAL_TONE 5 +#define PPTP_OUTCALL_TIMEOUT 6 +#define PPTP_OUTCALL_DONT_ACCEPT 7 + +struct PptpOutCallReply { + __be16 callID; + __be16 peersCallID; + __u8 resultCode; + __u8 generalErrorCode; + __be16 causeCode; + __be32 connectSpeed; + __be16 packetWindow; + __be16 packetProcDelay; + __be32 physChannelID; +}; + +struct PptpInCallRequest { + __be16 callID; + __be16 callSerialNumber; + __be32 callBearerType; + __be32 physChannelID; + __be16 dialedNumberLength; + __be16 dialingNumberLength; + __u8 dialedNumber[64]; + __u8 dialingNumber[64]; + __u8 subAddress[64]; +}; + +/* PptpInCallResultCode */ +#define PPTP_INCALL_ACCEPT 1 +#define PPTP_INCALL_GENERAL_ERROR 2 +#define PPTP_INCALL_DONT_ACCEPT 3 + +struct PptpInCallReply { + __be16 callID; + __be16 peersCallID; + __u8 resultCode; + __u8 generalErrorCode; + __be16 packetWindow; + __be16 packetProcDelay; + __u16 reserved; +}; + +struct PptpInCallConnected { + __be16 peersCallID; + __u16 reserved; + __be32 connectSpeed; + __be16 packetWindow; + __be16 packetProcDelay; + __be32 callFramingType; +}; + +struct PptpClearCallRequest { + __be16 callID; + __u16 reserved; +}; + +struct PptpCallDisconnectNotify { + __be16 callID; + __u8 resultCode; + __u8 generalErrorCode; + __be16 causeCode; + __u16 reserved; + __u8 callStatistics[128]; +}; + +struct PptpWanErrorNotify { + __be16 peersCallID; + __u16 reserved; + __be32 crcErrors; + __be32 framingErrors; + __be32 hardwareOverRuns; + __be32 bufferOverRuns; + __be32 timeoutErrors; + __be32 alignmentErrors; +}; + +struct PptpSetLinkInfo { + __be16 peersCallID; + __u16 reserved; + __be32 sendAccm; + __be32 recvAccm; +}; + +union pptp_ctrl_union { + struct PptpStartSessionRequest sreq; + struct PptpStartSessionReply srep; + struct PptpStopSessionRequest streq; + struct PptpStopSessionReply strep; + struct PptpOutCallRequest ocreq; + struct PptpOutCallReply ocack; + struct PptpInCallRequest icreq; + struct PptpInCallReply icack; + struct PptpInCallConnected iccon; + struct PptpClearCallRequest clrreq; + struct PptpCallDisconnectNotify disc; + struct PptpWanErrorNotify wanerr; + struct PptpSetLinkInfo setlink; +}; + +/* crap needed for nf_conntrack_compat.h */ +struct nf_conn; +struct nf_conntrack_expect; +enum ip_conntrack_info; + +extern int +(*nf_nat_pptp_hook_outbound)(struct sk_buff **pskb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +extern int +(*nf_nat_pptp_hook_inbound)(struct sk_buff **pskb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +extern void +(*nf_nat_pptp_hook_exp_gre)(struct nf_conntrack_expect *exp_orig, + struct nf_conntrack_expect *exp_reply); + +extern void +(*nf_nat_pptp_hook_expectfn)(struct nf_conn *ct, + struct nf_conntrack_expect *exp); + +#endif /* __KERNEL__ */ +#endif /* _NF_CONNTRACK_PPTP_H */ diff --git a/include/linux/netfilter/nf_conntrack_proto_gre.h b/include/linux/netfilter/nf_conntrack_proto_gre.h new file mode 100644 index 000000000000..4e6bbce04ff8 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_proto_gre.h @@ -0,0 +1,112 @@ +#ifndef _CONNTRACK_PROTO_GRE_H +#define _CONNTRACK_PROTO_GRE_H +#include + +/* GRE PROTOCOL HEADER */ + +/* GRE Version field */ +#define GRE_VERSION_1701 0x0 +#define GRE_VERSION_PPTP 0x1 + +/* GRE Protocol field */ +#define GRE_PROTOCOL_PPTP 0x880B + +/* GRE Flags */ +#define GRE_FLAG_C 0x80 +#define GRE_FLAG_R 0x40 +#define GRE_FLAG_K 0x20 +#define GRE_FLAG_S 0x10 +#define GRE_FLAG_A 0x80 + +#define GRE_IS_C(f) ((f)&GRE_FLAG_C) +#define GRE_IS_R(f) ((f)&GRE_FLAG_R) +#define GRE_IS_K(f) ((f)&GRE_FLAG_K) +#define GRE_IS_S(f) ((f)&GRE_FLAG_S) +#define GRE_IS_A(f) ((f)&GRE_FLAG_A) + +/* GRE is a mess: Four different standards */ +struct gre_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u16 rec:3, + srr:1, + seq:1, + key:1, + routing:1, + csum:1, + version:3, + reserved:4, + ack:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u16 csum:1, + routing:1, + key:1, + seq:1, + srr:1, + rec:3, + ack:1, + reserved:4, + version:3; +#else +#error "Adjust your defines" +#endif + __be16 protocol; +}; + +/* modified GRE header for PPTP */ +struct gre_hdr_pptp { + __u8 flags; /* bitfield */ + __u8 version; /* should be GRE_VERSION_PPTP */ + __be16 protocol; /* should be GRE_PROTOCOL_PPTP */ + __be16 payload_len; /* size of ppp payload, not inc. gre header */ + __be16 call_id; /* peer's call_id for this session */ + __be32 seq; /* sequence number. Present if S==1 */ + __be32 ack; /* seq number of highest packet recieved by */ + /* sender in this session */ +}; + +struct nf_ct_gre { + unsigned int stream_timeout; + unsigned int timeout; +}; + +#ifdef __KERNEL__ +#include + +struct nf_conn; + +/* structure for original <-> reply keymap */ +struct nf_ct_gre_keymap { + struct list_head list; + struct nf_conntrack_tuple tuple; +}; + +/* add new tuple->key_reply pair to keymap */ +int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, + struct nf_conntrack_tuple *t); + +/* delete keymap entries */ +void nf_ct_gre_keymap_destroy(struct nf_conn *ct); + +/* get pointer to gre key, if present */ +static inline __be32 *gre_key(struct gre_hdr *greh) +{ + if (!greh->key) + return NULL; + if (greh->csum || greh->routing) + return (__be32 *)(greh+sizeof(*greh)+4); + return (__be32 *)(greh+sizeof(*greh)); +} + +/* get pointer ot gre csum, if present */ +static inline __sum16 *gre_csum(struct gre_hdr *greh) +{ + if (!greh->csum) + return NULL; + return (__sum16 *)(greh+sizeof(*greh)); +} + +extern void nf_ct_gre_keymap_flush(void); +extern void nf_nat_need_gre(void); + +#endif /* __KERNEL__ */ +#endif /* _CONNTRACK_PROTO_GRE_H */ diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h index a1c57ee0a4fa..1401ccc051c4 100644 --- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h +++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h @@ -11,10 +11,12 @@ #ifdef CONFIG_NF_NAT_NEEDED #include +#include /* per conntrack: nat application helper private data */ union nf_conntrack_nat_help { /* insert nat helper private data here */ + struct nf_nat_pptp nat_pptp_info; }; struct nf_conn_nat { diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 1646076933b1..032b36a0e378 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -33,6 +34,7 @@ union nf_conntrack_proto { struct ip_ct_tcp tcp; struct ip_ct_icmp icmp; struct nf_ct_icmpv6 icmpv6; + struct nf_ct_gre gre; }; union nf_conntrack_expect_proto { @@ -41,12 +43,14 @@ union nf_conntrack_expect_proto { /* Add protocol helper include file here */ #include +#include #include /* per conntrack: application helper private data */ union nf_conntrack_help { /* insert conntrack helper private data (master) here */ struct nf_ct_ftp_master ct_ftp_info; + struct nf_ct_pptp_master ct_pptp_info; struct nf_ct_h323_master ct_h323_info; }; diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index fbba9e8b95fc..8c72ac9f0ab8 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -34,6 +34,8 @@ struct nf_conntrack_helper struct nf_conn *ct, enum ip_conntrack_info conntrackinfo); + void (*destroy)(struct nf_conn *ct); + int (*to_nfattr)(struct sk_buff *skb, const struct nf_conn *ct); }; diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index c96a9c576736..5d72b16e876f 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -49,6 +49,9 @@ union nf_conntrack_man_proto struct { __be16 port; } sctp; + struct { + __be16 key; /* GRE key is 32bit, PPtP only uses 16bit */ + } gre; }; /* The manipulable part of the tuple. */ @@ -84,6 +87,9 @@ struct nf_conntrack_tuple struct { __be16 port; } sctp; + struct { + __be16 key; + } gre; } u; /* The protocol. */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 4555f721dfc1..c3327ac024de 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -484,6 +484,10 @@ config IP_NF_NAT_SNMP_BASIC # '&&' (6) # # (6) Returns the result of min(/expr/, /expr/). +config NF_NAT_PROTO_GRE + tristate + depends on NF_NAT && NF_CT_PROTO_GRE + config IP_NF_NAT_FTP tristate depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT @@ -528,6 +532,12 @@ config IP_NF_NAT_PPTP default IP_NF_NAT if IP_NF_PPTP=y default m if IP_NF_PPTP=m +config NF_NAT_PPTP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_PPTP + select NF_NAT_PROTO_GRE + config IP_NF_NAT_H323 tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 56733c370327..ef33ff2cdda9 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -54,6 +54,10 @@ obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o +obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o + +# NAT protocols (nf_nat) +obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c new file mode 100644 index 000000000000..0ae45b79a4eb --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_pptp.c @@ -0,0 +1,315 @@ +/* + * nf_nat_pptp.c + * + * NAT support for PPTP (Point to Point Tunneling Protocol). + * PPTP is a a protocol for creating virtual private networks. + * It is a specification defined by Microsoft and some vendors + * working with Microsoft. PPTP is built on top of a modified + * version of the Internet Generic Routing Encapsulation Protocol. + * GRE is defined in RFC 1701 and RFC 1702. Documentation of + * PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + * TODO: - NAT to a unique tuple, not to TCP source port + * (needs netfilter tuple reservation) + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NF_NAT_PPTP_VERSION "3.0" + +#define REQ_CID(req, off) (*(__be16 *)((char *)(req) + (off))) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); +MODULE_ALIAS("ip_nat_pptp"); + +#if 0 +extern const char *pptp_msg_name[]; +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ + __FUNCTION__, ## args) +#else +#define DEBUGP(format, args...) +#endif + +static void pptp_nat_expected(struct nf_conn *ct, + struct nf_conntrack_expect *exp) +{ + struct nf_conn *master = ct->master; + struct nf_conntrack_expect *other_exp; + struct nf_conntrack_tuple t; + struct nf_ct_pptp_master *ct_pptp_info; + struct nf_nat_pptp *nat_pptp_info; + struct ip_nat_range range; + + ct_pptp_info = &nfct_help(master)->help.ct_pptp_info; + nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info; + + /* And here goes the grand finale of corrosion... */ + if (exp->dir == IP_CT_DIR_ORIGINAL) { + DEBUGP("we are PNS->PAC\n"); + /* therefore, build tuple for PAC->PNS */ + t.src.l3num = AF_INET; + t.src.u3.ip = master->tuplehash[!exp->dir].tuple.src.u3.ip; + t.src.u.gre.key = ct_pptp_info->pac_call_id; + t.dst.u3.ip = master->tuplehash[!exp->dir].tuple.dst.u3.ip; + t.dst.u.gre.key = ct_pptp_info->pns_call_id; + t.dst.protonum = IPPROTO_GRE; + } else { + DEBUGP("we are PAC->PNS\n"); + /* build tuple for PNS->PAC */ + t.src.l3num = AF_INET; + t.src.u3.ip = master->tuplehash[exp->dir].tuple.src.u3.ip; + t.src.u.gre.key = nat_pptp_info->pns_call_id; + t.dst.u3.ip = master->tuplehash[exp->dir].tuple.dst.u3.ip; + t.dst.u.gre.key = nat_pptp_info->pac_call_id; + t.dst.protonum = IPPROTO_GRE; + } + + DEBUGP("trying to unexpect other dir: "); + NF_CT_DUMP_TUPLE(&t); + other_exp = nf_conntrack_expect_find_get(&t); + if (other_exp) { + nf_conntrack_unexpect_related(other_exp); + nf_conntrack_expect_put(other_exp); + DEBUGP("success\n"); + } else { + DEBUGP("not found!\n"); + } + + /* This must be a fresh one. */ + BUG_ON(ct->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; + if (exp->dir == IP_CT_DIR_ORIGINAL) { + range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + range.min = range.max = exp->saved_proto; + } + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; + if (exp->dir == IP_CT_DIR_REPLY) { + range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + range.min = range.max = exp->saved_proto; + } + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); +} + +/* outbound packets == from PNS to PAC */ +static int +pptp_outbound_pkt(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) + +{ + struct nf_ct_pptp_master *ct_pptp_info; + struct nf_nat_pptp *nat_pptp_info; + u_int16_t msg; + __be16 new_callid; + unsigned int cid_off; + + ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; + nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; + + new_callid = ct_pptp_info->pns_call_id; + + switch (msg = ntohs(ctlh->messageType)) { + case PPTP_OUT_CALL_REQUEST: + cid_off = offsetof(union pptp_ctrl_union, ocreq.callID); + /* FIXME: ideally we would want to reserve a call ID + * here. current netfilter NAT core is not able to do + * this :( For now we use TCP source port. This breaks + * multiple calls within one control session */ + + /* save original call ID in nat_info */ + nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; + + /* don't use tcph->source since we are at a DSTmanip + * hook (e.g. PREROUTING) and pkt is not mangled yet */ + new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; + + /* save new call ID in ct info */ + ct_pptp_info->pns_call_id = new_callid; + break; + case PPTP_IN_CALL_REPLY: + cid_off = offsetof(union pptp_ctrl_union, icack.callID); + break; + case PPTP_CALL_CLEAR_REQUEST: + cid_off = offsetof(union pptp_ctrl_union, clrreq.callID); + break; + default: + DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, + (msg <= PPTP_MSG_MAX)? + pptp_msg_name[msg]:pptp_msg_name[0]); + /* fall through */ + case PPTP_SET_LINK_INFO: + /* only need to NAT in case PAC is behind NAT box */ + case PPTP_START_SESSION_REQUEST: + case PPTP_START_SESSION_REPLY: + case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* no need to alter packet */ + return NF_ACCEPT; + } + + /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass + * down to here */ + DEBUGP("altering call id from 0x%04x to 0x%04x\n", + ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid)); + + /* mangle packet */ + if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, + cid_off + sizeof(struct pptp_pkt_hdr) + + sizeof(struct PptpControlHeader), + sizeof(new_callid), (char *)&new_callid, + sizeof(new_callid)) == 0) + return NF_DROP; + return NF_ACCEPT; +} + +static void +pptp_exp_gre(struct nf_conntrack_expect *expect_orig, + struct nf_conntrack_expect *expect_reply) +{ + struct nf_conn *ct = expect_orig->master; + struct nf_ct_pptp_master *ct_pptp_info; + struct nf_nat_pptp *nat_pptp_info; + + ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; + nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; + + /* save original PAC call ID in nat_info */ + nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; + + /* alter expectation for PNS->PAC direction */ + expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id; + expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id; + expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id; + expect_orig->dir = IP_CT_DIR_ORIGINAL; + + /* alter expectation for PAC->PNS direction */ + expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id; + expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id; + expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id; + expect_reply->dir = IP_CT_DIR_REPLY; +} + +/* inbound packets == from PAC to PNS */ +static int +pptp_inbound_pkt(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) +{ + struct nf_nat_pptp *nat_pptp_info; + u_int16_t msg; + __be16 new_pcid; + unsigned int pcid_off; + + nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; + new_pcid = nat_pptp_info->pns_call_id; + + switch (msg = ntohs(ctlh->messageType)) { + case PPTP_OUT_CALL_REPLY: + pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID); + break; + case PPTP_IN_CALL_CONNECT: + pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID); + break; + case PPTP_IN_CALL_REQUEST: + /* only need to nat in case PAC is behind NAT box */ + return NF_ACCEPT; + case PPTP_WAN_ERROR_NOTIFY: + pcid_off = offsetof(union pptp_ctrl_union, wanerr.peersCallID); + break; + case PPTP_CALL_DISCONNECT_NOTIFY: + pcid_off = offsetof(union pptp_ctrl_union, disc.callID); + break; + case PPTP_SET_LINK_INFO: + pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID); + break; + default: + DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? + pptp_msg_name[msg]:pptp_msg_name[0]); + /* fall through */ + case PPTP_START_SESSION_REQUEST: + case PPTP_START_SESSION_REPLY: + case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* no need to alter packet */ + return NF_ACCEPT; + } + + /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST, + * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */ + + /* mangle packet */ + DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", + ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid)); + + if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, + pcid_off + sizeof(struct pptp_pkt_hdr) + + sizeof(struct PptpControlHeader), + sizeof(new_pcid), (char *)&new_pcid, + sizeof(new_pcid)) == 0) + return NF_DROP; + return NF_ACCEPT; +} + +static int __init nf_nat_helper_pptp_init(void) +{ + nf_nat_need_gre(); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_outbound)); + rcu_assign_pointer(nf_nat_pptp_hook_outbound, pptp_outbound_pkt); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_inbound)); + rcu_assign_pointer(nf_nat_pptp_hook_inbound, pptp_inbound_pkt); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_exp_gre)); + rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, pptp_exp_gre); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_expectfn)); + rcu_assign_pointer(nf_nat_pptp_hook_expectfn, pptp_nat_expected); + return 0; +} + +static void __exit nf_nat_helper_pptp_fini(void) +{ + rcu_assign_pointer(nf_nat_pptp_hook_expectfn, NULL); + rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, NULL); + rcu_assign_pointer(nf_nat_pptp_hook_inbound, NULL); + rcu_assign_pointer(nf_nat_pptp_hook_outbound, NULL); + synchronize_rcu(); +} + +module_init(nf_nat_helper_pptp_init); +module_exit(nf_nat_helper_pptp_fini); diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c new file mode 100644 index 000000000000..d3de579e09d2 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -0,0 +1,179 @@ +/* + * nf_nat_proto_gre.c + * + * NAT protocol helper module for GRE. + * + * GRE is a generic encapsulation protocol, which is generally not very + * suited for NAT, as it has no protocol-specific part as port numbers. + * + * It has an optional key field, which may help us distinguishing two + * connections between the same two hosts. + * + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 + * + * PPTP is built on top of a modified version of GRE, and has a mandatory + * field called "CallID", which serves us for the same purpose as the key + * field in plain GRE. + * + * Documentation about PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ + __FUNCTION__, ## args) +#else +#define DEBUGP(x, args...) +#endif + +/* is key in given range between min and max */ +static int +gre_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + __be16 key; + + if (maniptype == IP_NAT_MANIP_SRC) + key = tuple->src.u.gre.key; + else + key = tuple->dst.u.gre.key; + + return ntohs(key) >= ntohs(min->gre.key) && + ntohs(key) <= ntohs(max->gre.key); +} + +/* generate unique tuple ... */ +static int +gre_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *conntrack) +{ + static u_int16_t key; + __be16 *keyptr; + unsigned int min, i, range_size; + + if (maniptype == IP_NAT_MANIP_SRC) + keyptr = &tuple->src.u.gre.key; + else + keyptr = &tuple->dst.u.gre.key; + + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + DEBUGP("%p: NATing GRE PPTP\n", conntrack); + min = 1; + range_size = 0xffff; + } else { + min = ntohs(range->min.gre.key); + range_size = ntohs(range->max.gre.key) - min + 1; + } + + DEBUGP("min = %u, range_size = %u\n", min, range_size); + + for (i = 0; i < range_size; i++, key++) { + *keyptr = htons(min + key % range_size); + if (!nf_nat_used_tuple(tuple, conntrack)) + return 1; + } + + DEBUGP("%p: no NAT mapping\n", conntrack); + return 0; +} + +/* manipulate a GRE packet according to maniptype */ +static int +gre_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct gre_hdr *greh; + struct gre_hdr_pptp *pgreh; + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + unsigned int hdroff = iphdroff + iph->ihl * 4; + + /* pgreh includes two optional 32bit fields which are not required + * to be there. That's where the magic '8' comes from */ + if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh) - 8)) + return 0; + + greh = (void *)(*pskb)->data + hdroff; + pgreh = (struct gre_hdr_pptp *)greh; + + /* we only have destination manip of a packet, since 'source key' + * is not present in the packet itself */ + if (maniptype != IP_NAT_MANIP_DST) + return 1; + switch (greh->version) { + case 0: + if (!greh->key) { + DEBUGP("can't nat GRE w/o key\n"); + break; + } + if (greh->csum) { + /* FIXME: Never tested this code... */ + nf_proto_csum_replace4(gre_csum(greh), *pskb, + *(gre_key(greh)), + tuple->dst.u.gre.key, 0); + } + *(gre_key(greh)) = tuple->dst.u.gre.key; + break; + case GRE_VERSION_PPTP: + DEBUGP("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key)); + pgreh->call_id = tuple->dst.u.gre.key; + break; + default: + DEBUGP("can't nat unknown GRE version\n"); + return 0; + } + return 1; +} + +static struct nf_nat_protocol gre __read_mostly = { + .name = "GRE", + .protonum = IPPROTO_GRE, + .manip_pkt = gre_manip_pkt, + .in_range = gre_in_range, + .unique_tuple = gre_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; + +int __init nf_nat_proto_gre_init(void) +{ + return nf_nat_protocol_register(&gre); +} + +void __exit nf_nat_proto_gre_fini(void) +{ + nf_nat_protocol_unregister(&gre); +} + +module_init(nf_nat_proto_gre_init); +module_exit(nf_nat_proto_gre_fini); + +void nf_nat_need_gre(void) +{ + return; +} +EXPORT_SYMBOL_GPL(nf_nat_need_gre); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index d1a365d83c53..6b2eb26ae03f 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -120,6 +120,10 @@ config NF_CONNTRACK_EVENTS If unsure, say `N'. +config NF_CT_PROTO_GRE + tristate + depends on EXPERIMENTAL && NF_CONNTRACK + config NF_CT_PROTO_SCTP tristate 'SCTP protocol on new connection tracking support (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK @@ -213,6 +217,25 @@ config NF_CONNTRACK_NETBIOS_NS To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_PPTP + tristate "PPtP protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + select NF_CT_PROTO_GRE + help + This module adds support for PPTP (Point to Point Tunnelling + Protocol, RFC2637) connection tracking and NAT. + + If you are running PPTP sessions over a stateful firewall or NAT + box, you may want to enable this feature. + + Please note that not all PPTP modes of operation are supported yet. + Specifically these limitations exist: + - Blindy assumes that control connections are always established + in PNS->PAC direction. This is a violation of RFC2637. + - Only supports a single call within each session + + To compile it as a module, choose M here. If unsure, say N. + config NF_CT_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 67144b2af647..897bed4cbd79 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o # SCTP protocol connection tracking +obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o # netlink interface for nf_conntrack @@ -27,6 +28,7 @@ obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o +obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index aa8beabfeebb..ed756c928bc4 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -300,6 +300,7 @@ static void destroy_conntrack(struct nf_conntrack *nfct) { struct nf_conn *ct = (struct nf_conn *)nfct; + struct nf_conn_help *help = nfct_help(ct); struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; @@ -310,6 +311,9 @@ destroy_conntrack(struct nf_conntrack *nfct) nf_conntrack_event(IPCT_DESTROY, ct); set_bit(IPS_DYING_BIT, &ct->status); + if (help && help->helper && help->helper->destroy) + help->helper->destroy(ct); + /* To make sure we don't get any weird locking issues here: * destroy_conntrack() MUST NOT be called with a write lock * to nf_conntrack_lock!!! -HW */ diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c new file mode 100644 index 000000000000..f0ff00e0d052 --- /dev/null +++ b/net/netfilter/nf_conntrack_pptp.c @@ -0,0 +1,607 @@ +/* + * Connection tracking support for PPTP (Point to Point Tunneling Protocol). + * PPTP is a a protocol for creating virtual private networks. + * It is a specification defined by Microsoft and some vendors + * working with Microsoft. PPTP is built on top of a modified + * version of the Internet Generic Routing Encapsulation Protocol. + * GRE is defined in RFC 1701 and RFC 1702. Documentation of + * PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + * Limitations: + * - We blindly assume that control connections are always + * established in PNS->PAC direction. This is a violation + * of RFFC2673 + * - We can only support one single call within each session + * TODO: + * - testing of incoming PPTP calls + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define NF_CT_PPTP_VERSION "3.1" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); +MODULE_ALIAS("ip_conntrack_pptp"); + +static DEFINE_SPINLOCK(nf_pptp_lock); + +int +(*nf_nat_pptp_hook_outbound)(struct sk_buff **pskb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_outbound); + +int +(*nf_nat_pptp_hook_inbound)(struct sk_buff **pskb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_inbound); + +void +(*nf_nat_pptp_hook_exp_gre)(struct nf_conntrack_expect *expect_orig, + struct nf_conntrack_expect *expect_reply) + __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_exp_gre); + +void +(*nf_nat_pptp_hook_expectfn)(struct nf_conn *ct, + struct nf_conntrack_expect *exp) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn); + +#if 0 +/* PptpControlMessageType names */ +const char *pptp_msg_name[] = { + "UNKNOWN_MESSAGE", + "START_SESSION_REQUEST", + "START_SESSION_REPLY", + "STOP_SESSION_REQUEST", + "STOP_SESSION_REPLY", + "ECHO_REQUEST", + "ECHO_REPLY", + "OUT_CALL_REQUEST", + "OUT_CALL_REPLY", + "IN_CALL_REQUEST", + "IN_CALL_REPLY", + "IN_CALL_CONNECT", + "CALL_CLEAR_REQUEST", + "CALL_DISCONNECT_NOTIFY", + "WAN_ERROR_NOTIFY", + "SET_LINK_INFO" +}; +EXPORT_SYMBOL(pptp_msg_name); +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) +#else +#define DEBUGP(format, args...) +#endif + +#define SECS *HZ +#define MINS * 60 SECS +#define HOURS * 60 MINS + +#define PPTP_GRE_TIMEOUT (10 MINS) +#define PPTP_GRE_STREAM_TIMEOUT (5 HOURS) + +static void pptp_expectfn(struct nf_conn *ct, + struct nf_conntrack_expect *exp) +{ + typeof(nf_nat_pptp_hook_expectfn) nf_nat_pptp_expectfn; + DEBUGP("increasing timeouts\n"); + + /* increase timeout of GRE data channel conntrack entry */ + ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; + ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; + + /* Can you see how rusty this code is, compared with the pre-2.6.11 + * one? That's what happened to my shiny newnat of 2002 ;( -HW */ + + rcu_read_lock(); + nf_nat_pptp_expectfn = rcu_dereference(nf_nat_pptp_hook_expectfn); + if (nf_nat_pptp_expectfn && ct->status & IPS_NAT_MASK) + nf_nat_pptp_expectfn(ct, exp); + else { + struct nf_conntrack_tuple inv_t; + struct nf_conntrack_expect *exp_other; + + /* obviously this tuple inversion only works until you do NAT */ + nf_ct_invert_tuplepr(&inv_t, &exp->tuple); + DEBUGP("trying to unexpect other dir: "); + NF_CT_DUMP_TUPLE(&inv_t); + + exp_other = nf_conntrack_expect_find_get(&inv_t); + if (exp_other) { + /* delete other expectation. */ + DEBUGP("found\n"); + nf_conntrack_unexpect_related(exp_other); + nf_conntrack_expect_put(exp_other); + } else { + DEBUGP("not found\n"); + } + } + rcu_read_unlock(); +} + +static int destroy_sibling_or_exp(const struct nf_conntrack_tuple *t) +{ + struct nf_conntrack_tuple_hash *h; + struct nf_conntrack_expect *exp; + struct nf_conn *sibling; + + DEBUGP("trying to timeout ct or exp for tuple "); + NF_CT_DUMP_TUPLE(t); + + h = nf_conntrack_find_get(t, NULL); + if (h) { + sibling = nf_ct_tuplehash_to_ctrack(h); + DEBUGP("setting timeout of conntrack %p to 0\n", sibling); + sibling->proto.gre.timeout = 0; + sibling->proto.gre.stream_timeout = 0; + if (del_timer(&sibling->timeout)) + sibling->timeout.function((unsigned long)sibling); + nf_ct_put(sibling); + return 1; + } else { + exp = nf_conntrack_expect_find_get(t); + if (exp) { + DEBUGP("unexpect_related of expect %p\n", exp); + nf_conntrack_unexpect_related(exp); + nf_conntrack_expect_put(exp); + return 1; + } + } + return 0; +} + +/* timeout GRE data connections */ +static void pptp_destroy_siblings(struct nf_conn *ct) +{ + struct nf_conn_help *help = nfct_help(ct); + struct nf_conntrack_tuple t; + + nf_ct_gre_keymap_destroy(ct); + + /* try original (pns->pac) tuple */ + memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); + t.dst.protonum = IPPROTO_GRE; + t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id; + t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id; + if (!destroy_sibling_or_exp(&t)) + DEBUGP("failed to timeout original pns->pac ct/exp\n"); + + /* try reply (pac->pns) tuple */ + memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); + t.dst.protonum = IPPROTO_GRE; + t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id; + t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id; + if (!destroy_sibling_or_exp(&t)) + DEBUGP("failed to timeout reply pac->pns ct/exp\n"); +} + +/* expect GRE connections (PNS->PAC and PAC->PNS direction) */ +static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid) +{ + struct nf_conntrack_expect *exp_orig, *exp_reply; + enum ip_conntrack_dir dir; + int ret = 1; + typeof(nf_nat_pptp_hook_exp_gre) nf_nat_pptp_exp_gre; + + exp_orig = nf_conntrack_expect_alloc(ct); + if (exp_orig == NULL) + goto out; + + exp_reply = nf_conntrack_expect_alloc(ct); + if (exp_reply == NULL) + goto out_put_orig; + + /* original direction, PNS->PAC */ + dir = IP_CT_DIR_ORIGINAL; + nf_conntrack_expect_init(exp_orig, ct->tuplehash[dir].tuple.src.l3num, + &ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[dir].tuple.dst.u3, + IPPROTO_GRE, &peer_callid, &callid); + exp_orig->expectfn = pptp_expectfn; + + /* reply direction, PAC->PNS */ + dir = IP_CT_DIR_REPLY; + nf_conntrack_expect_init(exp_reply, ct->tuplehash[dir].tuple.src.l3num, + &ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[dir].tuple.dst.u3, + IPPROTO_GRE, &callid, &peer_callid); + exp_reply->expectfn = pptp_expectfn; + + nf_nat_pptp_exp_gre = rcu_dereference(nf_nat_pptp_hook_exp_gre); + if (nf_nat_pptp_exp_gre && ct->status & IPS_NAT_MASK) + nf_nat_pptp_exp_gre(exp_orig, exp_reply); + if (nf_conntrack_expect_related(exp_orig) != 0) + goto out_put_both; + if (nf_conntrack_expect_related(exp_reply) != 0) + goto out_unexpect_orig; + + /* Add GRE keymap entries */ + if (nf_ct_gre_keymap_add(ct, IP_CT_DIR_ORIGINAL, &exp_orig->tuple) != 0) + goto out_unexpect_both; + if (nf_ct_gre_keymap_add(ct, IP_CT_DIR_REPLY, &exp_reply->tuple) != 0) { + nf_ct_gre_keymap_destroy(ct); + goto out_unexpect_both; + } + ret = 0; + +out_put_both: + nf_conntrack_expect_put(exp_reply); +out_put_orig: + nf_conntrack_expect_put(exp_orig); +out: + return ret; + +out_unexpect_both: + nf_conntrack_unexpect_related(exp_reply); +out_unexpect_orig: + nf_conntrack_unexpect_related(exp_orig); + goto out_put_both; +} + +static inline int +pptp_inbound_pkt(struct sk_buff **pskb, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq, + unsigned int reqlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info; + u_int16_t msg; + __be16 cid = 0, pcid = 0; + typeof(nf_nat_pptp_hook_inbound) nf_nat_pptp_inbound; + + msg = ntohs(ctlh->messageType); + DEBUGP("inbound control message %s\n", pptp_msg_name[msg]); + + switch (msg) { + case PPTP_START_SESSION_REPLY: + /* server confirms new control session */ + if (info->sstate < PPTP_SESSION_REQUESTED) + goto invalid; + if (pptpReq->srep.resultCode == PPTP_START_OK) + info->sstate = PPTP_SESSION_CONFIRMED; + else + info->sstate = PPTP_SESSION_ERROR; + break; + + case PPTP_STOP_SESSION_REPLY: + /* server confirms end of control session */ + if (info->sstate > PPTP_SESSION_STOPREQ) + goto invalid; + if (pptpReq->strep.resultCode == PPTP_STOP_OK) + info->sstate = PPTP_SESSION_NONE; + else + info->sstate = PPTP_SESSION_ERROR; + break; + + case PPTP_OUT_CALL_REPLY: + /* server accepted call, we now expect GRE frames */ + if (info->sstate != PPTP_SESSION_CONFIRMED) + goto invalid; + if (info->cstate != PPTP_CALL_OUT_REQ && + info->cstate != PPTP_CALL_OUT_CONF) + goto invalid; + + cid = pptpReq->ocack.callID; + pcid = pptpReq->ocack.peersCallID; + if (info->pns_call_id != pcid) + goto invalid; + DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg], + ntohs(cid), ntohs(pcid)); + + if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) { + info->cstate = PPTP_CALL_OUT_CONF; + info->pac_call_id = cid; + exp_gre(ct, cid, pcid); + } else + info->cstate = PPTP_CALL_NONE; + break; + + case PPTP_IN_CALL_REQUEST: + /* server tells us about incoming call request */ + if (info->sstate != PPTP_SESSION_CONFIRMED) + goto invalid; + + cid = pptpReq->icreq.callID; + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); + info->cstate = PPTP_CALL_IN_REQ; + info->pac_call_id = cid; + break; + + case PPTP_IN_CALL_CONNECT: + /* server tells us about incoming call established */ + if (info->sstate != PPTP_SESSION_CONFIRMED) + goto invalid; + if (info->cstate != PPTP_CALL_IN_REP && + info->cstate != PPTP_CALL_IN_CONF) + goto invalid; + + pcid = pptpReq->iccon.peersCallID; + cid = info->pac_call_id; + + if (info->pns_call_id != pcid) + goto invalid; + + DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(pcid)); + info->cstate = PPTP_CALL_IN_CONF; + + /* we expect a GRE connection from PAC to PNS */ + exp_gre(ct, cid, pcid); + break; + + case PPTP_CALL_DISCONNECT_NOTIFY: + /* server confirms disconnect */ + cid = pptpReq->disc.callID; + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); + info->cstate = PPTP_CALL_NONE; + + /* untrack this call id, unexpect GRE packets */ + pptp_destroy_siblings(ct); + break; + + case PPTP_WAN_ERROR_NOTIFY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* I don't have to explain these ;) */ + break; + + default: + goto invalid; + } + + nf_nat_pptp_inbound = rcu_dereference(nf_nat_pptp_hook_inbound); + if (nf_nat_pptp_inbound && ct->status & IPS_NAT_MASK) + return nf_nat_pptp_inbound(pskb, ct, ctinfo, ctlh, pptpReq); + return NF_ACCEPT; + +invalid: + DEBUGP("invalid %s: type=%d cid=%u pcid=%u " + "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n", + msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0], + msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate, + ntohs(info->pns_call_id), ntohs(info->pac_call_id)); + return NF_ACCEPT; +} + +static inline int +pptp_outbound_pkt(struct sk_buff **pskb, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq, + unsigned int reqlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info; + u_int16_t msg; + __be16 cid = 0, pcid = 0; + typeof(nf_nat_pptp_hook_outbound) nf_nat_pptp_outbound; + + msg = ntohs(ctlh->messageType); + DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); + + switch (msg) { + case PPTP_START_SESSION_REQUEST: + /* client requests for new control session */ + if (info->sstate != PPTP_SESSION_NONE) + goto invalid; + info->sstate = PPTP_SESSION_REQUESTED; + break; + + case PPTP_STOP_SESSION_REQUEST: + /* client requests end of control session */ + info->sstate = PPTP_SESSION_STOPREQ; + break; + + case PPTP_OUT_CALL_REQUEST: + /* client initiating connection to server */ + if (info->sstate != PPTP_SESSION_CONFIRMED) + goto invalid; + info->cstate = PPTP_CALL_OUT_REQ; + /* track PNS call id */ + cid = pptpReq->ocreq.callID; + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); + info->pns_call_id = cid; + break; + + case PPTP_IN_CALL_REPLY: + /* client answers incoming call */ + if (info->cstate != PPTP_CALL_IN_REQ && + info->cstate != PPTP_CALL_IN_REP) + goto invalid; + + cid = pptpReq->icack.callID; + pcid = pptpReq->icack.peersCallID; + if (info->pac_call_id != pcid) + goto invalid; + DEBUGP("%s, CID=%X PCID=%X\n", pptp_msg_name[msg], + ntohs(cid), ntohs(pcid)); + + if (pptpReq->icack.resultCode == PPTP_INCALL_ACCEPT) { + /* part two of the three-way handshake */ + info->cstate = PPTP_CALL_IN_REP; + info->pns_call_id = cid; + } else + info->cstate = PPTP_CALL_NONE; + break; + + case PPTP_CALL_CLEAR_REQUEST: + /* client requests hangup of call */ + if (info->sstate != PPTP_SESSION_CONFIRMED) + goto invalid; + /* FUTURE: iterate over all calls and check if + * call ID is valid. We don't do this without newnat, + * because we only know about last call */ + info->cstate = PPTP_CALL_CLEAR_REQ; + break; + + case PPTP_SET_LINK_INFO: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* I don't have to explain these ;) */ + break; + + default: + goto invalid; + } + + nf_nat_pptp_outbound = rcu_dereference(nf_nat_pptp_hook_outbound); + if (nf_nat_pptp_outbound && ct->status & IPS_NAT_MASK) + return nf_nat_pptp_outbound(pskb, ct, ctinfo, ctlh, pptpReq); + return NF_ACCEPT; + +invalid: + DEBUGP("invalid %s: type=%d cid=%u pcid=%u " + "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n", + msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0], + msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate, + ntohs(info->pns_call_id), ntohs(info->pac_call_id)); + return NF_ACCEPT; +} + +static const unsigned int pptp_msg_size[] = { + [PPTP_START_SESSION_REQUEST] = sizeof(struct PptpStartSessionRequest), + [PPTP_START_SESSION_REPLY] = sizeof(struct PptpStartSessionReply), + [PPTP_STOP_SESSION_REQUEST] = sizeof(struct PptpStopSessionRequest), + [PPTP_STOP_SESSION_REPLY] = sizeof(struct PptpStopSessionReply), + [PPTP_OUT_CALL_REQUEST] = sizeof(struct PptpOutCallRequest), + [PPTP_OUT_CALL_REPLY] = sizeof(struct PptpOutCallReply), + [PPTP_IN_CALL_REQUEST] = sizeof(struct PptpInCallRequest), + [PPTP_IN_CALL_REPLY] = sizeof(struct PptpInCallReply), + [PPTP_IN_CALL_CONNECT] = sizeof(struct PptpInCallConnected), + [PPTP_CALL_CLEAR_REQUEST] = sizeof(struct PptpClearCallRequest), + [PPTP_CALL_DISCONNECT_NOTIFY] = sizeof(struct PptpCallDisconnectNotify), + [PPTP_WAN_ERROR_NOTIFY] = sizeof(struct PptpWanErrorNotify), + [PPTP_SET_LINK_INFO] = sizeof(struct PptpSetLinkInfo), +}; + +/* track caller id inside control connection, call expect_related */ +static int +conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) + +{ + int dir = CTINFO2DIR(ctinfo); + struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info; + struct tcphdr _tcph, *tcph; + struct pptp_pkt_hdr _pptph, *pptph; + struct PptpControlHeader _ctlh, *ctlh; + union pptp_ctrl_union _pptpReq, *pptpReq; + unsigned int tcplen = (*pskb)->len - protoff; + unsigned int datalen, reqlen, nexthdr_off; + int oldsstate, oldcstate; + int ret; + u_int16_t msg; + + /* don't do any tracking before tcp handshake complete */ + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) + return NF_ACCEPT; + + nexthdr_off = protoff; + tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph); + BUG_ON(!tcph); + nexthdr_off += tcph->doff * 4; + datalen = tcplen - tcph->doff * 4; + + pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph); + if (!pptph) { + DEBUGP("no full PPTP header, can't track\n"); + return NF_ACCEPT; + } + nexthdr_off += sizeof(_pptph); + datalen -= sizeof(_pptph); + + /* if it's not a control message we can't do anything with it */ + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { + DEBUGP("not a control packet\n"); + return NF_ACCEPT; + } + + ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); + if (!ctlh) + return NF_ACCEPT; + nexthdr_off += sizeof(_ctlh); + datalen -= sizeof(_ctlh); + + reqlen = datalen; + msg = ntohs(ctlh->messageType); + if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg]) + return NF_ACCEPT; + if (reqlen > sizeof(*pptpReq)) + reqlen = sizeof(*pptpReq); + + pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); + if (!pptpReq) + return NF_ACCEPT; + + oldsstate = info->sstate; + oldcstate = info->cstate; + + spin_lock_bh(&nf_pptp_lock); + + /* FIXME: We just blindly assume that the control connection is always + * established from PNS->PAC. However, RFC makes no guarantee */ + if (dir == IP_CT_DIR_ORIGINAL) + /* client -> server (PNS -> PAC) */ + ret = pptp_outbound_pkt(pskb, ctlh, pptpReq, reqlen, ct, + ctinfo); + else + /* server -> client (PAC -> PNS) */ + ret = pptp_inbound_pkt(pskb, ctlh, pptpReq, reqlen, ct, + ctinfo); + DEBUGP("sstate: %d->%d, cstate: %d->%d\n", + oldsstate, info->sstate, oldcstate, info->cstate); + spin_unlock_bh(&nf_pptp_lock); + + return ret; +} + +/* control protocol helper */ +static struct nf_conntrack_helper pptp __read_mostly = { + .name = "pptp", + .me = THIS_MODULE, + .max_expected = 2, + .timeout = 5 * 60, + .tuple.src.l3num = AF_INET, + .tuple.src.u.tcp.port = __constant_htons(PPTP_CONTROL_PORT), + .tuple.dst.protonum = IPPROTO_TCP, + .mask.src.l3num = 0xffff, + .mask.src.u.tcp.port = __constant_htons(0xffff), + .mask.dst.protonum = 0xff, + .help = conntrack_pptp_help, + .destroy = pptp_destroy_siblings, +}; + +static int __init nf_conntrack_pptp_init(void) +{ + return nf_conntrack_helper_register(&pptp); +} + +static void __exit nf_conntrack_pptp_fini(void) +{ + nf_conntrack_helper_unregister(&pptp); + nf_ct_gre_keymap_flush(); +} + +module_init(nf_conntrack_pptp_init); +module_exit(nf_conntrack_pptp_fini); diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c new file mode 100644 index 000000000000..ac193ce70249 --- /dev/null +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -0,0 +1,305 @@ +/* + * ip_conntrack_proto_gre.c - Version 3.0 + * + * Connection tracking protocol helper module for GRE. + * + * GRE is a generic encapsulation protocol, which is generally not very + * suited for NAT, as it has no protocol-specific part as port numbers. + * + * It has an optional key field, which may help us distinguishing two + * connections between the same two hosts. + * + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 + * + * PPTP is built on top of a modified version of GRE, and has a mandatory + * field called "CallID", which serves us for the same purpose as the key + * field in plain GRE. + * + * Documentation about PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define GRE_TIMEOUT (30 * HZ) +#define GRE_STREAM_TIMEOUT (180 * HZ) + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) +#else +#define DEBUGP(x, args...) +#endif + +static DEFINE_RWLOCK(nf_ct_gre_lock); +static LIST_HEAD(gre_keymap_list); + +void nf_ct_gre_keymap_flush(void) +{ + struct list_head *pos, *n; + + write_lock_bh(&nf_ct_gre_lock); + list_for_each_safe(pos, n, &gre_keymap_list) { + list_del(pos); + kfree(pos); + } + write_unlock_bh(&nf_ct_gre_lock); +} +EXPORT_SYMBOL(nf_ct_gre_keymap_flush); + +static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km, + const struct nf_conntrack_tuple *t) +{ + return km->tuple.src.l3num == t->src.l3num && + !memcmp(&km->tuple.src.u3, &t->src.u3, sizeof(t->src.u3)) && + !memcmp(&km->tuple.dst.u3, &t->dst.u3, sizeof(t->dst.u3)) && + km->tuple.dst.protonum == t->dst.protonum && + km->tuple.dst.u.all == t->dst.u.all; +} + +/* look up the source key for a given tuple */ +static __be16 gre_keymap_lookup(struct nf_conntrack_tuple *t) +{ + struct nf_ct_gre_keymap *km; + __be16 key = 0; + + read_lock_bh(&nf_ct_gre_lock); + list_for_each_entry(km, &gre_keymap_list, list) { + if (gre_key_cmpfn(km, t)) { + key = km->tuple.src.u.gre.key; + break; + } + } + read_unlock_bh(&nf_ct_gre_lock); + + DEBUGP("lookup src key 0x%x for ", key); + NF_CT_DUMP_TUPLE(t); + + return key; +} + +/* add a single keymap entry, associate with specified master ct */ +int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, + struct nf_conntrack_tuple *t) +{ + struct nf_conn_help *help = nfct_help(ct); + struct nf_ct_gre_keymap **kmp, *km; + + BUG_ON(strcmp(help->helper->name, "pptp")); + kmp = &help->help.ct_pptp_info.keymap[dir]; + if (*kmp) { + /* check whether it's a retransmission */ + list_for_each_entry(km, &gre_keymap_list, list) { + if (gre_key_cmpfn(km, t) && km == *kmp) + return 0; + } + DEBUGP("trying to override keymap_%s for ct %p\n", + dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct); + return -EEXIST; + } + + km = kmalloc(sizeof(*km), GFP_ATOMIC); + if (!km) + return -ENOMEM; + memcpy(&km->tuple, t, sizeof(*t)); + *kmp = km; + + DEBUGP("adding new entry %p: ", km); + NF_CT_DUMP_TUPLE(&km->tuple); + + write_lock_bh(&nf_ct_gre_lock); + list_add_tail(&km->list, &gre_keymap_list); + write_unlock_bh(&nf_ct_gre_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add); + +/* destroy the keymap entries associated with specified master ct */ +void nf_ct_gre_keymap_destroy(struct nf_conn *ct) +{ + struct nf_conn_help *help = nfct_help(ct); + enum ip_conntrack_dir dir; + + DEBUGP("entering for ct %p\n", ct); + BUG_ON(strcmp(help->helper->name, "pptp")); + + write_lock_bh(&nf_ct_gre_lock); + for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) { + if (help->help.ct_pptp_info.keymap[dir]) { + DEBUGP("removing %p from list\n", + help->help.ct_pptp_info.keymap[dir]); + list_del(&help->help.ct_pptp_info.keymap[dir]->list); + kfree(help->help.ct_pptp_info.keymap[dir]); + help->help.ct_pptp_info.keymap[dir] = NULL; + } + } + write_unlock_bh(&nf_ct_gre_lock); +} +EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy); + +/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ + +/* invert gre part of tuple */ +static int gre_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) +{ + tuple->dst.u.gre.key = orig->src.u.gre.key; + tuple->src.u.gre.key = orig->dst.u.gre.key; + return 1; +} + +/* gre hdr info to tuple */ +static int gre_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, + struct nf_conntrack_tuple *tuple) +{ + struct gre_hdr_pptp _pgrehdr, *pgrehdr; + __be16 srckey; + struct gre_hdr _grehdr, *grehdr; + + /* first only delinearize old RFC1701 GRE header */ + grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr); + if (!grehdr || grehdr->version != GRE_VERSION_PPTP) { + /* try to behave like "nf_conntrack_proto_generic" */ + tuple->src.u.all = 0; + tuple->dst.u.all = 0; + return 1; + } + + /* PPTP header is variable length, only need up to the call_id field */ + pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr); + if (!pgrehdr) + return 1; + + if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { + DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); + return 0; + } + + tuple->dst.u.gre.key = pgrehdr->call_id; + srckey = gre_keymap_lookup(tuple); + tuple->src.u.gre.key = srckey; + + return 1; +} + +/* print gre part of tuple */ +static int gre_print_tuple(struct seq_file *s, + const struct nf_conntrack_tuple *tuple) +{ + return seq_printf(s, "srckey=0x%x dstkey=0x%x ", + ntohs(tuple->src.u.gre.key), + ntohs(tuple->dst.u.gre.key)); +} + +/* print private data for conntrack */ +static int gre_print_conntrack(struct seq_file *s, + const struct nf_conn *ct) +{ + return seq_printf(s, "timeout=%u, stream_timeout=%u ", + (ct->proto.gre.timeout / HZ), + (ct->proto.gre.stream_timeout / HZ)); +} + +/* Returns verdict for packet, and may modify conntrack */ +static int gre_packet(struct nf_conn *ct, + const struct sk_buff *skb, + unsigned int dataoff, + enum ip_conntrack_info ctinfo, + int pf, + unsigned int hooknum) +{ + /* If we've seen traffic both ways, this is a GRE connection. + * Extend timeout. */ + if (ct->status & IPS_SEEN_REPLY) { + nf_ct_refresh_acct(ct, ctinfo, skb, + ct->proto.gre.stream_timeout); + /* Also, more likely to be important, and not a probe. */ + set_bit(IPS_ASSURED_BIT, &ct->status); + nf_conntrack_event_cache(IPCT_STATUS, skb); + } else + nf_ct_refresh_acct(ct, ctinfo, skb, + ct->proto.gre.timeout); + + return NF_ACCEPT; +} + +/* Called when a new connection for this protocol found. */ +static int gre_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) +{ + DEBUGP(": "); + NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + + /* initialize to sane value. Ideally a conntrack helper + * (e.g. in case of pptp) is increasing them */ + ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; + ct->proto.gre.timeout = GRE_TIMEOUT; + + return 1; +} + +/* Called when a conntrack entry has already been removed from the hashes + * and is about to be deleted from memory */ +static void gre_destroy(struct nf_conn *ct) +{ + struct nf_conn *master = ct->master; + DEBUGP(" entering\n"); + + if (!master) + DEBUGP("no master !?!\n"); + else + nf_ct_gre_keymap_destroy(master); +} + +/* protocol helper struct */ +static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = { + .l3proto = AF_INET, + .l4proto = IPPROTO_GRE, + .name = "gre", + .pkt_to_tuple = gre_pkt_to_tuple, + .invert_tuple = gre_invert_tuple, + .print_tuple = gre_print_tuple, + .print_conntrack = gre_print_conntrack, + .packet = gre_packet, + .new = gre_new, + .destroy = gre_destroy, + .me = THIS_MODULE, +#if defined(CONFIG_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_NF_CONNTRACK_NETLINK_MODULE) + .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, + .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, +#endif +}; + +static int __init nf_ct_proto_gre_init(void) +{ + return nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4); +} + +static void nf_ct_proto_gre_fini(void) +{ + nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); + nf_ct_gre_keymap_flush(); +} + +module_init(nf_ct_proto_gre_init); +module_exit(nf_ct_proto_gre_fini); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 9fafcd7b203229c3f3893a475741afc27e276306 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:09:57 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add SIP helper port Add IPv4 and IPv6 capable nf_conntrack port of the SIP conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 41 +++ net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_sip.c | 283 +++++++++++++++ net/netfilter/Kconfig | 12 + net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_sip.c | 530 +++++++++++++++++++++++++++++ 7 files changed, 873 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_sip.h create mode 100644 net/ipv4/netfilter/nf_nat_sip.c create mode 100644 net/netfilter/nf_conntrack_sip.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h new file mode 100644 index 000000000000..bb7f2041db74 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -0,0 +1,41 @@ +#ifndef __NF_CONNTRACK_SIP_H__ +#define __NF_CONNTRACK_SIP_H__ +#ifdef __KERNEL__ + +#define SIP_PORT 5060 +#define SIP_TIMEOUT 3600 + +enum sip_header_pos { + POS_REG_REQ_URI, + POS_REQ_URI, + POS_FROM, + POS_TO, + POS_VIA, + POS_CONTACT, + POS_CONTENT, + POS_MEDIA, + POS_OWNER_IP4, + POS_CONNECTION_IP4, + POS_OWNER_IP6, + POS_CONNECTION_IP6, + POS_SDP_HEADER, +}; + +extern unsigned int (*nf_nat_sip_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char **dptr); +extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp, + const char *dptr); + +extern int ct_sip_get_info(struct nf_conn *ct, const char *dptr, size_t dlen, + unsigned int *matchoff, unsigned int *matchlen, + enum sip_header_pos pos); +extern int ct_sip_lnlen(const char *line, const char *limit); +extern const char *ct_sip_search(const char *needle, const char *haystack, + size_t needle_len, size_t haystack_len, + int case_sensitive); +#endif /* __KERNEL__ */ +#endif /* __NF_CONNTRACK_SIP_H__ */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index c3327ac024de..83e83f553ccb 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -555,6 +555,11 @@ config IP_NF_NAT_SIP default IP_NF_NAT if IP_NF_SIP=y default m if IP_NF_SIP=m +config NF_NAT_SIP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_SIP + # mangle + specific targets config IP_NF_MANGLE tristate "Packet mangling" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index ef33ff2cdda9..167b65e89aca 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o +obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o # NAT protocols (nf_nat) obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c new file mode 100644 index 000000000000..3d524b957310 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -0,0 +1,283 @@ +/* SIP extension for UDP NAT alteration. + * + * (C) 2005 by Christian Hentschel + * based on RR's ip_nat_ftp.c and other modules. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hentschel "); +MODULE_DESCRIPTION("SIP NAT helper"); +MODULE_ALIAS("ip_nat_sip"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +struct addr_map { + struct { + char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned int srclen, srciplen; + unsigned int dstlen, dstiplen; + } addr[IP_CT_DIR_MAX]; +}; + +static void addr_map_init(struct nf_conn *ct, struct addr_map *map) +{ + struct nf_conntrack_tuple *t; + enum ip_conntrack_dir dir; + unsigned int n; + + for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { + t = &ct->tuplehash[dir].tuple; + + n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", + NIPQUAD(t->src.u3.ip)); + map->addr[dir].srciplen = n; + n += sprintf(map->addr[dir].src + n, ":%u", + ntohs(t->src.u.udp.port)); + map->addr[dir].srclen = n; + + n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", + NIPQUAD(t->dst.u3.ip)); + map->addr[dir].dstiplen = n; + n += sprintf(map->addr[dir].dst + n, ":%u", + ntohs(t->dst.u.udp.port)); + map->addr[dir].dstlen = n; + } +} + +static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, + struct nf_conn *ct, const char **dptr, size_t dlen, + enum sip_header_pos pos, struct addr_map *map) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned int matchlen, matchoff, addrlen; + char *addr; + + if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) + return 1; + + if ((matchlen == map->addr[dir].srciplen || + matchlen == map->addr[dir].srclen) && + memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { + addr = map->addr[!dir].dst; + addrlen = map->addr[!dir].dstlen; + } else if ((matchlen == map->addr[dir].dstiplen || + matchlen == map->addr[dir].dstlen) && + memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { + addr = map->addr[!dir].src; + addrlen = map->addr[!dir].srclen; + } else + return 1; + + if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, addr, addrlen)) + return 0; + *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + return 1; + +} + +static unsigned int ip_nat_sip(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char **dptr) +{ + enum sip_header_pos pos; + struct addr_map map; + int dataoff, datalen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + datalen = (*pskb)->len - dataoff; + if (datalen < sizeof("SIP/2.0") - 1) + return NF_DROP; + + addr_map_init(ct, &map); + + /* Basic rules: requests and responses. */ + if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) { + /* 10.2: Constructing the REGISTER Request: + * + * The "userinfo" and "@" components of the SIP URI MUST NOT + * be present. + */ + if (datalen >= sizeof("REGISTER") - 1 && + strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) + pos = POS_REG_REQ_URI; + else + pos = POS_REQ_URI; + + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map)) + return NF_DROP; + } + + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) + return NF_DROP; + return NF_ACCEPT; +} + +static unsigned int mangle_sip_packet(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char **dptr, size_t dlen, + char *buffer, int bufflen, + enum sip_header_pos pos) +{ + unsigned int matchlen, matchoff; + + if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) + return 0; + + if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, buffer, bufflen)) + return 0; + + /* We need to reload this. Thanks Patrick. */ + *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + return 1; +} + +static int mangle_content_len(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char *dptr) +{ + unsigned int dataoff, matchoff, matchlen; + char buffer[sizeof("65536")]; + int bufflen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + + /* Get actual SDP lenght */ + if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff, + &matchlen, POS_SDP_HEADER) > 0) { + + /* since ct_sip_get_info() give us a pointer passing 'v=' + we need to add 2 bytes in this count. */ + int c_len = (*pskb)->len - dataoff - matchoff + 2; + + /* Now, update SDP length */ + if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff, + &matchlen, POS_CONTENT) > 0) { + + bufflen = sprintf(buffer, "%u", c_len); + return nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, + buffer, bufflen); + } + } + return 0; +} + +static unsigned int mangle_sdp(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + __be32 newip, u_int16_t port, + const char *dptr) +{ + char buffer[sizeof("nnn.nnn.nnn.nnn")]; + unsigned int dataoff, bufflen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + + /* Mangle owner and contact info. */ + bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, POS_OWNER_IP4)) + return 0; + + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, POS_CONNECTION_IP4)) + return 0; + + /* Mangle media port. */ + bufflen = sprintf(buffer, "%u", port); + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, POS_MEDIA)) + return 0; + + return mangle_content_len(pskb, ctinfo, ct, dptr); +} + +/* So, this packet has hit the connection tracking matching code. + Mangle it, and change the expectation to match the new version. */ +static unsigned int ip_nat_sdp(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp, + const char *dptr) +{ + struct nf_conn *ct = exp->master; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + __be32 newip; + u_int16_t port; + + DEBUGP("ip_nat_sdp():\n"); + + /* Connection will come from reply */ + newip = ct->tuplehash[!dir].tuple.dst.u3.ip; + + exp->tuple.dst.u3.ip = newip; + exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; + exp->dir = !dir; + + /* When you see the packet, we need to NAT it the same as the + this one. */ + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { + exp->tuple.dst.u.udp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) { + nf_conntrack_unexpect_related(exp); + return NF_DROP; + } + return NF_ACCEPT; +} + +static void __exit nf_nat_sip_fini(void) +{ + rcu_assign_pointer(nf_nat_sip_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_sip_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_sip_hook)); + BUG_ON(rcu_dereference(nf_nat_sdp_hook)); + rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); + rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); + return 0; +} + +module_init(nf_nat_sip_init); +module_exit(nf_nat_sip_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 6b2eb26ae03f..e73891194b31 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -236,6 +236,18 @@ config NF_CONNTRACK_PPTP To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_SIP + tristate "SIP protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + help + SIP is an application-layer control protocol that can establish, + modify, and terminate multimedia sessions (conferences) such as + Internet telephony calls. With the ip_conntrack_sip and + the nf_nat_sip modules you can support the protocol on a connection + tracking/NATing firewall. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CT_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 897bed4cbd79..86da21700aa3 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o +obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c new file mode 100644 index 000000000000..e0c06795a943 --- /dev/null +++ b/net/netfilter/nf_conntrack_sip.c @@ -0,0 +1,530 @@ +/* SIP extension for IP connection tracking. + * + * (C) 2005 by Christian Hentschel + * based on RR's ip_conntrack_ftp.c and other modules. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hentschel "); +MODULE_DESCRIPTION("SIP connection tracking helper"); +MODULE_ALIAS("ip_conntrack_sip"); + +#define MAX_PORTS 8 +static unsigned short ports[MAX_PORTS]; +static int ports_c; +module_param_array(ports, ushort, &ports_c, 0400); +MODULE_PARM_DESC(ports, "port numbers of SIP servers"); + +static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT; +module_param(sip_timeout, uint, 0600); +MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); + +unsigned int (*nf_nat_sip_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char **dptr) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sip_hook); + +unsigned int (*nf_nat_sdp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp, + const char *dptr) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); + +static int digits_len(struct nf_conn *, const char *, const char *, int *); +static int epaddr_len(struct nf_conn *, const char *, const char *, int *); +static int skp_digits_len(struct nf_conn *, const char *, const char *, int *); +static int skp_epaddr_len(struct nf_conn *, const char *, const char *, int *); + +struct sip_header_nfo { + const char *lname; + const char *sname; + const char *ln_str; + size_t lnlen; + size_t snlen; + size_t ln_strlen; + int case_sensitive; + int (*match_len)(struct nf_conn *, const char *, + const char *, int *); +}; + +static const struct sip_header_nfo ct_sip_hdrs[] = { + [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .ln_str = ":", + .ln_strlen = sizeof(":") - 1, + .match_len = epaddr_len, + }, + [POS_REQ_URI] = { /* SIP request URI */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .ln_str = "@", + .ln_strlen = sizeof("@") - 1, + .match_len = epaddr_len, + }, + [POS_FROM] = { /* SIP From header */ + .lname = "From:", + .lnlen = sizeof("From:") - 1, + .sname = "\r\nf:", + .snlen = sizeof("\r\nf:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len, + }, + [POS_TO] = { /* SIP To header */ + .lname = "To:", + .lnlen = sizeof("To:") - 1, + .sname = "\r\nt:", + .snlen = sizeof("\r\nt:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len + }, + [POS_VIA] = { /* SIP Via header */ + .lname = "Via:", + .lnlen = sizeof("Via:") - 1, + .sname = "\r\nv:", + .snlen = sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */ + .ln_str = "UDP ", + .ln_strlen = sizeof("UDP ") - 1, + .match_len = epaddr_len, + }, + [POS_CONTACT] = { /* SIP Contact header */ + .lname = "Contact:", + .lnlen = sizeof("Contact:") - 1, + .sname = "\r\nm:", + .snlen = sizeof("\r\nm:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len + }, + [POS_CONTENT] = { /* SIP Content length header */ + .lname = "Content-Length:", + .lnlen = sizeof("Content-Length:") - 1, + .sname = "\r\nl:", + .snlen = sizeof("\r\nl:") - 1, + .ln_str = ":", + .ln_strlen = sizeof(":") - 1, + .match_len = skp_digits_len + }, + [POS_MEDIA] = { /* SDP media info */ + .case_sensitive = 1, + .lname = "\nm=", + .lnlen = sizeof("\nm=") - 1, + .sname = "\rm=", + .snlen = sizeof("\rm=") - 1, + .ln_str = "audio ", + .ln_strlen = sizeof("audio ") - 1, + .match_len = digits_len + }, + [POS_OWNER_IP4] = { /* SDP owner address*/ + .case_sensitive = 1, + .lname = "\no=", + .lnlen = sizeof("\no=") - 1, + .sname = "\ro=", + .snlen = sizeof("\ro=") - 1, + .ln_str = "IN IP4 ", + .ln_strlen = sizeof("IN IP4 ") - 1, + .match_len = epaddr_len + }, + [POS_CONNECTION_IP4] = {/* SDP connection info */ + .case_sensitive = 1, + .lname = "\nc=", + .lnlen = sizeof("\nc=") - 1, + .sname = "\rc=", + .snlen = sizeof("\rc=") - 1, + .ln_str = "IN IP4 ", + .ln_strlen = sizeof("IN IP4 ") - 1, + .match_len = epaddr_len + }, + [POS_OWNER_IP6] = { /* SDP owner address*/ + .case_sensitive = 1, + .lname = "\no=", + .lnlen = sizeof("\no=") - 1, + .sname = "\ro=", + .snlen = sizeof("\ro=") - 1, + .ln_str = "IN IP6 ", + .ln_strlen = sizeof("IN IP6 ") - 1, + .match_len = epaddr_len + }, + [POS_CONNECTION_IP6] = {/* SDP connection info */ + .case_sensitive = 1, + .lname = "\nc=", + .lnlen = sizeof("\nc=") - 1, + .sname = "\rc=", + .snlen = sizeof("\rc=") - 1, + .ln_str = "IN IP6 ", + .ln_strlen = sizeof("IN IP6 ") - 1, + .match_len = epaddr_len + }, + [POS_SDP_HEADER] = { /* SDP version header */ + .case_sensitive = 1, + .lname = "\nv=", + .lnlen = sizeof("\nv=") - 1, + .sname = "\rv=", + .snlen = sizeof("\rv=") - 1, + .ln_str = "=", + .ln_strlen = sizeof("=") - 1, + .match_len = digits_len + } +}; + +/* get line lenght until first CR or LF seen. */ +int ct_sip_lnlen(const char *line, const char *limit) +{ + const char *k = line; + + while ((line <= limit) && (*line == '\r' || *line == '\n')) + line++; + + while (line <= limit) { + if (*line == '\r' || *line == '\n') + break; + line++; + } + return line - k; +} +EXPORT_SYMBOL_GPL(ct_sip_lnlen); + +/* Linear string search, case sensitive. */ +const char *ct_sip_search(const char *needle, const char *haystack, + size_t needle_len, size_t haystack_len, + int case_sensitive) +{ + const char *limit = haystack + (haystack_len - needle_len); + + while (haystack <= limit) { + if (case_sensitive) { + if (strncmp(haystack, needle, needle_len) == 0) + return haystack; + } else { + if (strnicmp(haystack, needle, needle_len) == 0) + return haystack; + } + haystack++; + } + return NULL; +} +EXPORT_SYMBOL_GPL(ct_sip_search); + +static int digits_len(struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + int len = 0; + while (dptr <= limit && isdigit(*dptr)) { + dptr++; + len++; + } + return len; +} + +/* get digits lenght, skiping blank spaces. */ +static int skp_digits_len(struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + for (; dptr <= limit && *dptr == ' '; dptr++) + (*shift)++; + + return digits_len(ct, dptr, limit, shift); +} + +static int parse_addr(struct nf_conn *ct, const char *cp, const char **endp, + union nf_conntrack_address *addr, const char *limit) +{ + const char *end; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + int ret = 0; + + switch (family) { + case AF_INET: + ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); + break; + case AF_INET6: + ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); + break; + default: + BUG(); + } + + if (ret == 0 || end == cp) + return 0; + if (endp) + *endp = end; + return 1; +} + +/* skip ip address. returns its length. */ +static int epaddr_len(struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + union nf_conntrack_address addr; + const char *aux = dptr; + + if (!parse_addr(ct, dptr, &dptr, &addr, limit)) { + DEBUGP("ip: %s parse failed.!\n", dptr); + return 0; + } + + /* Port number */ + if (*dptr == ':') { + dptr++; + dptr += digits_len(ct, dptr, limit, shift); + } + return dptr - aux; +} + +/* get address length, skiping user info. */ +static int skp_epaddr_len(struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + int s = *shift; + + for (; dptr <= limit && *dptr != '@'; dptr++) + (*shift)++; + + if (*dptr == '@') { + dptr++; + (*shift)++; + } else + *shift = s; + + return epaddr_len(ct, dptr, limit, shift); +} + +/* Returns 0 if not found, -1 error parsing. */ +int ct_sip_get_info(struct nf_conn *ct, + const char *dptr, size_t dlen, + unsigned int *matchoff, + unsigned int *matchlen, + enum sip_header_pos pos) +{ + const struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos]; + const char *limit, *aux, *k = dptr; + int shift = 0; + + limit = dptr + (dlen - hnfo->lnlen); + + while (dptr <= limit) { + if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && + (strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { + dptr++; + continue; + } + aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, + ct_sip_lnlen(dptr, limit), + hnfo->case_sensitive); + if (!aux) { + DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, + hnfo->lname); + return -1; + } + aux += hnfo->ln_strlen; + + *matchlen = hnfo->match_len(ct, aux, limit, &shift); + if (!*matchlen) + return -1; + + *matchoff = (aux - k) + shift; + + DEBUGP("%s match succeeded! - len: %u\n", hnfo->lname, + *matchlen); + return 1; + } + DEBUGP("%s header not found.\n", hnfo->lname); + return 0; +} +EXPORT_SYMBOL_GPL(ct_sip_get_info); + +static int set_expected_rtp(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + union nf_conntrack_address *addr, + __be16 port, + const char *dptr) +{ + struct nf_conntrack_expect *exp; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + int family = ct->tuplehash[!dir].tuple.src.l3num; + int ret; + typeof(nf_nat_sdp_hook) nf_nat_sdp; + + exp = nf_conntrack_expect_alloc(ct); + if (exp == NULL) + return NF_DROP; + nf_conntrack_expect_init(exp, family, + &ct->tuplehash[!dir].tuple.src.u3, addr, + IPPROTO_UDP, NULL, &port); + + nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); + if (nf_nat_sdp && ct->status & IPS_NAT_MASK) + ret = nf_nat_sdp(pskb, ctinfo, exp, dptr); + else { + if (nf_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + else + ret = NF_ACCEPT; + } + nf_conntrack_expect_put(exp); + + return ret; +} + +static int sip_help(struct sk_buff **pskb, + unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + union nf_conntrack_address addr; + unsigned int dataoff, datalen; + const char *dptr; + int ret = NF_ACCEPT; + int matchoff, matchlen; + u_int16_t port; + enum sip_header_pos pos; + typeof(nf_nat_sip_hook) nf_nat_sip; + + /* No Data ? */ + dataoff = protoff + sizeof(struct udphdr); + if (dataoff >= (*pskb)->len) + return NF_ACCEPT; + + nf_ct_refresh(ct, *pskb, sip_timeout * HZ); + + if (!skb_is_nonlinear(*pskb)) + dptr = (*pskb)->data + dataoff; + else { + DEBUGP("Copy of skbuff not supported yet.\n"); + goto out; + } + + nf_nat_sip = rcu_dereference(nf_nat_sip_hook); + if (nf_nat_sip && ct->status & IPS_NAT_MASK) { + if (!nf_nat_sip(pskb, ctinfo, ct, &dptr)) { + ret = NF_DROP; + goto out; + } + } + + datalen = (*pskb)->len - dataoff; + if (datalen < sizeof("SIP/2.0 200") - 1) + goto out; + + /* RTP info only in some SDP pkts */ + if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 && + memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) { + goto out; + } + /* Get address and port from SDP packet. */ + pos = family == AF_INET ? POS_CONNECTION_IP4 : POS_CONNECTION_IP6; + if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, pos) > 0) { + + /* We'll drop only if there are parse problems. */ + if (!parse_addr(ct, dptr + matchoff, NULL, &addr, + dptr + datalen)) { + ret = NF_DROP; + goto out; + } + if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, + POS_MEDIA) > 0) { + + port = simple_strtoul(dptr + matchoff, NULL, 10); + if (port < 1024) { + ret = NF_DROP; + goto out; + } + ret = set_expected_rtp(pskb, ct, ctinfo, &addr, + htons(port), dptr); + } + } +out: + return ret; +} + +static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; +static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly; + +static void nf_conntrack_sip_fini(void) +{ + int i, j; + + for (i = 0; i < ports_c; i++) { + for (j = 0; j < 2; j++) { + if (sip[i][j].me == NULL) + continue; + nf_conntrack_helper_unregister(&sip[i][j]); + } + } +} + +static int __init nf_conntrack_sip_init(void) +{ + int i, j, ret; + char *tmpname; + + if (ports_c == 0) + ports[ports_c++] = SIP_PORT; + + for (i = 0; i < ports_c; i++) { + memset(&sip[i], 0, sizeof(sip[i])); + + sip[i][0].tuple.src.l3num = AF_INET; + sip[i][1].tuple.src.l3num = AF_INET6; + for (j = 0; j < 2; j++) { + sip[i][j].tuple.dst.protonum = IPPROTO_UDP; + sip[i][j].tuple.src.u.udp.port = htons(ports[i]); + sip[i][j].mask.src.l3num = 0xFFFF; + sip[i][j].mask.src.u.udp.port = htons(0xFFFF); + sip[i][j].mask.dst.protonum = 0xFF; + sip[i][j].max_expected = 2; + sip[i][j].timeout = 3 * 60; /* 3 minutes */ + sip[i][j].me = THIS_MODULE; + sip[i][j].help = sip_help; + + tmpname = &sip_names[i][j][0]; + if (ports[i] == SIP_PORT) + sprintf(tmpname, "sip"); + else + sprintf(tmpname, "sip-%u", i); + sip[i][j].name = tmpname; + + DEBUGP("port #%u: %u\n", i, ports[i]); + + ret = nf_conntrack_helper_register(&sip[i][j]); + if (ret) { + printk("nf_ct_sip: failed to register helper " + "for pf: %u port: %u\n", + sip[i][j].tuple.src.l3num, ports[i]); + nf_conntrack_sip_fini(); + return ret; + } + } + } + return 0; +} + +module_init(nf_conntrack_sip_init); +module_exit(nf_conntrack_sip_fini); -- cgit v1.2.3 From a536df35b3a58caa9015bf7887a374b20f658368 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:10:18 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add TFTP helper port Add IPv4 and IPv6 capable nf_conntrack port of the TFTP conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_tftp.h | 20 ++++ net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_tftp.c | 52 +++++++++ net/netfilter/Kconfig | 11 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_tftp.c | 159 ++++++++++++++++++++++++++++ 7 files changed, 249 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_tftp.h create mode 100644 net/ipv4/netfilter/nf_nat_tftp.c create mode 100644 net/netfilter/nf_conntrack_tftp.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_tftp.h b/include/linux/netfilter/nf_conntrack_tftp.h new file mode 100644 index 000000000000..0d79b7ae051f --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_tftp.h @@ -0,0 +1,20 @@ +#ifndef _NF_CONNTRACK_TFTP_H +#define _NF_CONNTRACK_TFTP_H + +#define TFTP_PORT 69 + +struct tftphdr { + __be16 opcode; +}; + +#define TFTP_OPCODE_READ 1 +#define TFTP_OPCODE_WRITE 2 +#define TFTP_OPCODE_DATA 3 +#define TFTP_OPCODE_ACK 4 +#define TFTP_OPCODE_ERROR 5 + +extern unsigned int (*nf_nat_tftp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp); + +#endif /* _NF_CONNTRACK_TFTP_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 83e83f553ccb..1c0018b6bea4 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -515,6 +515,11 @@ config IP_NF_NAT_TFTP default IP_NF_NAT if IP_NF_TFTP=y default m if IP_NF_TFTP=m +config NF_NAT_TFTP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_TFTP + config IP_NF_NAT_AMANDA tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 167b65e89aca..3ca0af0ed5f0 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o +obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o # NAT protocols (nf_nat) obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c new file mode 100644 index 000000000000..2566b79de224 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_tftp.c @@ -0,0 +1,52 @@ +/* (C) 2001-2002 Magnus Boden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Magnus Boden "); +MODULE_DESCRIPTION("TFTP NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_tftp"); + +static unsigned int help(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp) +{ + struct nf_conn *ct = exp->master; + + exp->saved_proto.udp.port + = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; + exp->dir = IP_CT_DIR_REPLY; + exp->expectfn = nf_nat_follow_master; + if (nf_conntrack_expect_related(exp) != 0) + return NF_DROP; + return NF_ACCEPT; +} + +static void __exit nf_nat_tftp_fini(void) +{ + rcu_assign_pointer(nf_nat_tftp_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_tftp_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_tftp_hook)); + rcu_assign_pointer(nf_nat_tftp_hook, help); + return 0; +} + +module_init(nf_nat_tftp_init); +module_exit(nf_nat_tftp_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index e73891194b31..e0deac17df12 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -248,6 +248,17 @@ config NF_CONNTRACK_SIP To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_TFTP + tristate "TFTP protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + help + TFTP connection tracking helper, this is required depending + on how restrictive your ruleset is. + If you are using a tftp client behind -j SNAT or -j MASQUERADING + you will need this. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CT_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 86da21700aa3..5dc5574f7e99 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o +obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c new file mode 100644 index 000000000000..d46a1263fcb5 --- /dev/null +++ b/net/netfilter/nf_conntrack_tftp.c @@ -0,0 +1,159 @@ +/* (C) 2001-2002 Magnus Boden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Magnus Boden "); +MODULE_DESCRIPTION("TFTP connection tracking helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_conntrack_tftp"); + +#define MAX_PORTS 8 +static unsigned short ports[MAX_PORTS]; +static int ports_c; +module_param_array(ports, ushort, &ports_c, 0400); +MODULE_PARM_DESC(ports, "Port numbers of TFTP servers"); + +#if 0 +#define DEBUGP(format, args...) printk("%s:%s:" format, \ + __FILE__, __FUNCTION__ , ## args) +#else +#define DEBUGP(format, args...) +#endif + +unsigned int (*nf_nat_tftp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_tftp_hook); + +static int tftp_help(struct sk_buff **pskb, + unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct tftphdr _tftph, *tfh; + struct nf_conntrack_expect *exp; + struct nf_conntrack_tuple *tuple; + unsigned int ret = NF_ACCEPT; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + typeof(nf_nat_tftp_hook) nf_nat_tftp; + + tfh = skb_header_pointer(*pskb, protoff + sizeof(struct udphdr), + sizeof(_tftph), &_tftph); + if (tfh == NULL) + return NF_ACCEPT; + + switch (ntohs(tfh->opcode)) { + case TFTP_OPCODE_READ: + case TFTP_OPCODE_WRITE: + /* RRQ and WRQ works the same way */ + DEBUGP(""); + NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); + + exp = nf_conntrack_expect_alloc(ct); + if (exp == NULL) + return NF_DROP; + tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; + nf_conntrack_expect_init(exp, family, + &tuple->src.u3, &tuple->dst.u3, + IPPROTO_UDP, + NULL, &tuple->dst.u.udp.port); + + DEBUGP("expect: "); + NF_CT_DUMP_TUPLE(&exp->tuple); + NF_CT_DUMP_TUPLE(&exp->mask); + + nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook); + if (nf_nat_tftp && ct->status & IPS_NAT_MASK) + ret = nf_nat_tftp(pskb, ctinfo, exp); + else if (nf_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + nf_conntrack_expect_put(exp); + break; + case TFTP_OPCODE_DATA: + case TFTP_OPCODE_ACK: + DEBUGP("Data/ACK opcode\n"); + break; + case TFTP_OPCODE_ERROR: + DEBUGP("Error opcode\n"); + break; + default: + DEBUGP("Unknown opcode\n"); + } + return ret; +} + +static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly; +static char tftp_names[MAX_PORTS][2][sizeof("tftp-65535")] __read_mostly; + +static void nf_conntrack_tftp_fini(void) +{ + int i, j; + + for (i = 0; i < ports_c; i++) { + for (j = 0; j < 2; j++) + nf_conntrack_helper_unregister(&tftp[i][j]); + } +} + +static int __init nf_conntrack_tftp_init(void) +{ + int i, j, ret; + char *tmpname; + + if (ports_c == 0) + ports[ports_c++] = TFTP_PORT; + + for (i = 0; i < ports_c; i++) { + memset(&tftp[i], 0, sizeof(tftp[i])); + + tftp[i][0].tuple.src.l3num = AF_INET; + tftp[i][1].tuple.src.l3num = AF_INET6; + for (j = 0; j < 2; j++) { + tftp[i][j].tuple.dst.protonum = IPPROTO_UDP; + tftp[i][j].tuple.src.u.udp.port = htons(ports[i]); + tftp[i][j].mask.src.l3num = 0xFFFF; + tftp[i][j].mask.dst.protonum = 0xFF; + tftp[i][j].mask.src.u.udp.port = htons(0xFFFF); + tftp[i][j].max_expected = 1; + tftp[i][j].timeout = 5 * 60; /* 5 minutes */ + tftp[i][j].me = THIS_MODULE; + tftp[i][j].help = tftp_help; + + tmpname = &tftp_names[i][j][0]; + if (ports[i] == TFTP_PORT) + sprintf(tmpname, "tftp"); + else + sprintf(tmpname, "tftp-%u", i); + tftp[i][j].name = tmpname; + + ret = nf_conntrack_helper_register(&tftp[i][j]); + if (ret) { + printk("nf_ct_tftp: failed to register helper " + "for pf: %u port: %u\n", + tftp[i][j].tuple.src.l3num, ports[i]); + nf_conntrack_tftp_fini(); + return ret; + } + } + } + return 0; +} + +module_init(nf_conntrack_tftp_init); +module_exit(nf_conntrack_tftp_fini); -- cgit v1.2.3 From 2b5f6dcce5bf94b9b119e9ed8d537098ec61c3d2 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sat, 2 Dec 2006 22:22:25 -0800 Subject: [XFRM]: Fix aevent structuring to be more complete. aevents can not uniquely identify an SA. We break the ABI with this patch, but consensus is that since it is not yet utilized by any (known) application then it is fine (better do it now than later). Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- Documentation/networking/xfrm_sync.txt | 5 ++++- include/linux/xfrm.h | 2 ++ net/xfrm/xfrm_user.c | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/Documentation/networking/xfrm_sync.txt b/Documentation/networking/xfrm_sync.txt index 8be626f7c0b8..d7aac9dedeb4 100644 --- a/Documentation/networking/xfrm_sync.txt +++ b/Documentation/networking/xfrm_sync.txt @@ -47,10 +47,13 @@ aevent_id structure looks like: struct xfrm_aevent_id { struct xfrm_usersa_id sa_id; + xfrm_address_t saddr; __u32 flags; + __u32 reqid; }; -xfrm_usersa_id in this message layout identifies the SA. +The unique SA is identified by the combination of xfrm_usersa_id, +reqid and saddr. flags are used to indicate different things. The possible flags are: diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 7907c42bd4e4..088ba8113f7e 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -289,7 +289,9 @@ struct xfrm_usersa_id { struct xfrm_aevent_id { struct xfrm_usersa_id sa_id; + xfrm_address_t saddr; __u32 flags; + __u32 reqid; }; struct xfrm_userspi_info { diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 055b72fb37bc..6f97665983d2 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1281,10 +1281,12 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve id = NLMSG_DATA(nlh); nlh->nlmsg_flags = 0; - id->sa_id.daddr = x->id.daddr; + memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr)); id->sa_id.spi = x->id.spi; id->sa_id.family = x->props.family; id->sa_id.proto = x->id.proto; + memcpy(&id->saddr, &x->props.saddr,sizeof(x->props.saddr)); + id->reqid = x->props.reqid; id->flags = c->data.aevent; RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); -- cgit v1.2.3 From 582982e6991d6718ddadf8751072b50a850dde48 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 17 Nov 2006 12:05:11 +0900 Subject: [PATCH] libata: remove unused HSM_ST_UNKNOWN HSM_ST_UNKNOWN is not used anywhere. Its value is zero and supposed to serve sanity check purpose but HSM_ST_IDLE is used for that purpose. This unused state causes confusion. After a port is initialized but before the first command is executed, the idle hsm state is UNKNOWN. However, once a command has completed, the idle hsm state is IDLE. This defeats sanity check in ata_pio_task() for the first command. This patch removes HSM_ST_UNKNOWN and consequently make HSM_ST_IDLE the default state. Signed-off-by: Tejun Heo --- include/linux/libata.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index 9080789913f7..6013211ac7de 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -318,7 +318,6 @@ enum { }; enum hsm_task_states { - HSM_ST_UNKNOWN, /* state unknown */ HSM_ST_IDLE, /* no command on going */ HSM_ST, /* (waiting the device to) transfer data */ HSM_ST_LAST, /* (waiting the device to) complete command */ -- cgit v1.2.3 From 3d3cca37559e3ab2b574eda11ed5207ccdb8980a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 16 Nov 2006 10:50:50 +0900 Subject: [PATCH] libata: implement ATA_FLAG_SETXFER_POLLING and use it in pata_via, take #2 This patch implements ATA_FLAG_SETXFER_POLLING and use in pata_via. If this flag is set, transfer mode setting performed by polling not by interrupt. This should help those controllers which raise interrupt before the command is actually complete on SETXFER. Rationale for this approach. * uses existing facility and relatively simple * no busy sleep in the interrupt handler * updating drivers is easy While at it, kill now unused flag ATA_FLAG_SRST in pata_via. Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 8 ++++++++ drivers/ata/pata_via.c | 12 ++++++------ include/linux/libata.h | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3fd7c7932707..b35fdcb104ec 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4821,6 +4821,14 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) } } + /* Some controllers show flaky interrupt behavior after + * setting xfer mode. Use polling instead. + */ + if (unlikely(qc->tf.command == ATA_CMD_SET_FEATURES && + qc->tf.feature == SETFEATURES_XFER) && + (ap->flags & ATA_FLAG_SETXFER_POLLING)) + qc->tf.flags |= ATA_TFLAG_POLLING; + /* select the device */ ata_dev_select(ap, qc->dev->devno, 1, 0); diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index ee93dd0169be..a9077b617b8d 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -418,7 +418,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Early VIA without UDMA support */ static struct ata_port_info via_mwdma_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &via_port_ops @@ -426,7 +426,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Ditto with IRQ masking required */ static struct ata_port_info via_mwdma_info_borked = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &via_port_ops_noirq, @@ -434,7 +434,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* VIA UDMA 33 devices (and borked 66) */ static struct ata_port_info via_udma33_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x7, @@ -443,7 +443,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* VIA UDMA 66 devices */ static struct ata_port_info via_udma66_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x1f, @@ -452,7 +452,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* VIA UDMA 100 devices */ static struct ata_port_info via_udma100_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x3f, @@ -461,7 +461,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* UDMA133 with bad AST (All current 133) */ static struct ata_port_info via_udma133_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x7f, /* FIXME: should check north bridge */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 6013211ac7de..8b57b6a806cc 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -178,6 +178,7 @@ enum { ATA_FLAG_DEBUGMSG = (1 << 13), ATA_FLAG_DETECT_POLLING = (1 << 14), /* detect device presence by * polling IDENTIFY */ + ATA_FLAG_SETXFER_POLLING= (1 << 15), /* use polling for SETXFER */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be -- cgit v1.2.3 From 800b399669ad495ad4361d134df87401ae36f44f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 3 Dec 2006 21:34:13 +0900 Subject: [PATCH] libata: always use polling IDENTIFY libata switched to IRQ-driven IDENTIFY when IRQ-driven PIO was introduced. This has caused a lot of problems including device misdetection and phantom device. ATA_FLAG_DETECT_POLLING was added recently to selectively use polling IDENTIFY on problemetic drivers but many controllers and devices are affected by this problem and trying to adding ATA_FLAG_DETECT_POLLING for each such case is diffcult and not very rewarding. This patch makes libata always use polling IDENTIFY. This is consistent with libata's original behavior and drivers/ide's behavior. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 5 ++--- drivers/ata/libata-core.c | 8 ++------ drivers/ata/libata-eh.c | 3 --- drivers/ata/libata.h | 2 -- include/linux/libata.h | 4 +--- 5 files changed, 5 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 788a269206e6..a2d84f7cf2bc 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -105,9 +105,8 @@ enum { PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */ - PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS | ATA_FLAG_DETECT_POLLING, - PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | - ATA_FLAG_DETECT_POLLING, + PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, + PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, /* combined mode. if set, PATA is channel 0. * if clear, PATA is channel 1. diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 883276388207..f8ec3896b793 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1473,16 +1473,12 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, } tf.protocol = ATA_PROT_PIO; - - /* presence detection using polling IDENTIFY? */ - if (flags & ATA_READID_DETECT) - tf.flags |= ATA_TFLAG_POLLING; + tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, id, sizeof(id[0]) * ATA_ID_WORDS); if (err_mask) { - if ((flags & ATA_READID_DETECT) && - (err_mask & AC_ERR_NODEV_HINT)) { + if (err_mask & AC_ERR_NODEV_HINT) { DPRINTK("ata%u.%d: NODEV after polling detection\n", ap->id, dev->devno); return -ENOENT; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 2aad7b79d6dd..76a85dfb7307 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1692,9 +1692,6 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, ata_class_enabled(ehc->classes[dev->devno])) { dev->class = ehc->classes[dev->devno]; - if (ap->flags & ATA_FLAG_DETECT_POLLING) - readid_flags |= ATA_READID_DETECT; - rc = ata_dev_read_id(dev, &dev->class, readid_flags, dev->id); if (rc == 0) { diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 1ff3f59504c9..107b2b565229 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -42,8 +42,6 @@ struct ata_scsi_args { enum { /* flags for ata_dev_read_id() */ ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ - ATA_READID_DETECT = (1 << 1), /* perform presence detection - * using polling IDENTIFY */ }; extern struct workqueue_struct *ata_aux_wq; diff --git a/include/linux/libata.h b/include/linux/libata.h index 8b57b6a806cc..202283b5df96 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -176,9 +176,7 @@ enum { ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H * Register FIS clearing BSY */ ATA_FLAG_DEBUGMSG = (1 << 13), - ATA_FLAG_DETECT_POLLING = (1 << 14), /* detect device presence by - * polling IDENTIFY */ - ATA_FLAG_SETXFER_POLLING= (1 << 15), /* use polling for SETXFER */ + ATA_FLAG_SETXFER_POLLING= (1 << 14), /* use polling for SETXFER */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be -- cgit v1.2.3 From d916faace3efc0bf19fe9a615a1ab8fa1a24cd93 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 3 Dec 2006 22:22:41 -0500 Subject: Remove long-unmaintained ftape driver subsystem. It's bitrotten, long unmaintained, long hidden under BROKEN_ON_SMP, etc. As scheduled in feature-removal-schedule.txt, and ack'd several times on lkml. Signed-off-by: Jeff Garzik --- Documentation/00-INDEX | 2 - Documentation/feature-removal-schedule.txt | 8 - Documentation/ftape.txt | 307 ----- Documentation/kernel-parameters.txt | 3 - MAINTAINERS | 5 - drivers/char/Kconfig | 33 - drivers/char/Makefile | 1 - drivers/char/ftape/Kconfig | 330 ------ drivers/char/ftape/Makefile | 28 - drivers/char/ftape/README.PCI | 81 -- drivers/char/ftape/RELEASE-NOTES | 966 --------------- drivers/char/ftape/compressor/Makefile | 31 - drivers/char/ftape/compressor/lzrw3.c | 743 ------------ drivers/char/ftape/compressor/lzrw3.h | 253 ---- drivers/char/ftape/compressor/zftape-compress.c | 1203 ------------------- drivers/char/ftape/compressor/zftape-compress.h | 83 -- drivers/char/ftape/lowlevel/Makefile | 43 - drivers/char/ftape/lowlevel/fc-10.c | 175 --- drivers/char/ftape/lowlevel/fc-10.h | 39 - drivers/char/ftape/lowlevel/fdc-io.c | 1349 --------------------- drivers/char/ftape/lowlevel/fdc-io.h | 252 ---- drivers/char/ftape/lowlevel/fdc-isr.c | 1170 ------------------- drivers/char/ftape/lowlevel/fdc-isr.h | 55 - drivers/char/ftape/lowlevel/ftape-bsm.c | 491 -------- drivers/char/ftape/lowlevel/ftape-bsm.h | 66 -- drivers/char/ftape/lowlevel/ftape-buffer.c | 130 --- drivers/char/ftape/lowlevel/ftape-buffer.h | 32 - drivers/char/ftape/lowlevel/ftape-calibr.c | 275 ----- drivers/char/ftape/lowlevel/ftape-calibr.h | 37 - drivers/char/ftape/lowlevel/ftape-ctl.c | 896 -------------- drivers/char/ftape/lowlevel/ftape-ctl.h | 162 --- drivers/char/ftape/lowlevel/ftape-ecc.c | 853 -------------- drivers/char/ftape/lowlevel/ftape-ecc.h | 84 -- drivers/char/ftape/lowlevel/ftape-format.c | 344 ------ drivers/char/ftape/lowlevel/ftape-format.h | 37 - drivers/char/ftape/lowlevel/ftape-init.c | 160 --- drivers/char/ftape/lowlevel/ftape-init.h | 43 - drivers/char/ftape/lowlevel/ftape-io.c | 992 ---------------- drivers/char/ftape/lowlevel/ftape-io.h | 90 -- drivers/char/ftape/lowlevel/ftape-proc.c | 214 ---- drivers/char/ftape/lowlevel/ftape-proc.h | 35 - drivers/char/ftape/lowlevel/ftape-read.c | 621 ---------- drivers/char/ftape/lowlevel/ftape-read.h | 51 - drivers/char/ftape/lowlevel/ftape-rw.c | 1092 ----------------- drivers/char/ftape/lowlevel/ftape-rw.h | 111 -- drivers/char/ftape/lowlevel/ftape-setup.c | 104 -- drivers/char/ftape/lowlevel/ftape-tracing.c | 118 -- drivers/char/ftape/lowlevel/ftape-tracing.h | 179 --- drivers/char/ftape/lowlevel/ftape-write.c | 336 ------ drivers/char/ftape/lowlevel/ftape-write.h | 53 - drivers/char/ftape/lowlevel/ftape_syms.c | 87 -- drivers/char/ftape/zftape/Makefile | 36 - drivers/char/ftape/zftape/zftape-buffers.c | 149 --- drivers/char/ftape/zftape/zftape-buffers.h | 55 - drivers/char/ftape/zftape/zftape-ctl.c | 1417 ----------------------- drivers/char/ftape/zftape/zftape-ctl.h | 58 - drivers/char/ftape/zftape/zftape-eof.c | 199 ---- drivers/char/ftape/zftape/zftape-eof.h | 52 - drivers/char/ftape/zftape/zftape-init.c | 377 ------ drivers/char/ftape/zftape/zftape-init.h | 77 -- drivers/char/ftape/zftape/zftape-read.c | 377 ------ drivers/char/ftape/zftape/zftape-read.h | 53 - drivers/char/ftape/zftape/zftape-rw.c | 375 ------ drivers/char/ftape/zftape/zftape-rw.h | 101 -- drivers/char/ftape/zftape/zftape-vtbl.c | 757 ------------ drivers/char/ftape/zftape/zftape-vtbl.h | 227 ---- drivers/char/ftape/zftape/zftape-write.c | 483 -------- drivers/char/ftape/zftape/zftape-write.h | 38 - drivers/char/ftape/zftape/zftape_syms.c | 43 - include/linux/Kbuild | 4 - include/linux/ftape-header-segment.h | 122 -- include/linux/ftape-vendors.h | 137 --- include/linux/ftape.h | 201 ---- include/linux/zftape.h | 87 -- 74 files changed, 20278 deletions(-) delete mode 100644 Documentation/ftape.txt delete mode 100644 drivers/char/ftape/Kconfig delete mode 100644 drivers/char/ftape/Makefile delete mode 100644 drivers/char/ftape/README.PCI delete mode 100644 drivers/char/ftape/RELEASE-NOTES delete mode 100644 drivers/char/ftape/compressor/Makefile delete mode 100644 drivers/char/ftape/compressor/lzrw3.c delete mode 100644 drivers/char/ftape/compressor/lzrw3.h delete mode 100644 drivers/char/ftape/compressor/zftape-compress.c delete mode 100644 drivers/char/ftape/compressor/zftape-compress.h delete mode 100644 drivers/char/ftape/lowlevel/Makefile delete mode 100644 drivers/char/ftape/lowlevel/fc-10.c delete mode 100644 drivers/char/ftape/lowlevel/fc-10.h delete mode 100644 drivers/char/ftape/lowlevel/fdc-io.c delete mode 100644 drivers/char/ftape/lowlevel/fdc-io.h delete mode 100644 drivers/char/ftape/lowlevel/fdc-isr.c delete mode 100644 drivers/char/ftape/lowlevel/fdc-isr.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-bsm.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-bsm.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-buffer.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-buffer.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-calibr.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-calibr.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-ctl.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-ctl.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-ecc.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-ecc.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-format.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-format.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-init.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-init.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-io.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-io.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-proc.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-proc.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-read.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-read.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-rw.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-rw.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-setup.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-tracing.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-tracing.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-write.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-write.h delete mode 100644 drivers/char/ftape/lowlevel/ftape_syms.c delete mode 100644 drivers/char/ftape/zftape/Makefile delete mode 100644 drivers/char/ftape/zftape/zftape-buffers.c delete mode 100644 drivers/char/ftape/zftape/zftape-buffers.h delete mode 100644 drivers/char/ftape/zftape/zftape-ctl.c delete mode 100644 drivers/char/ftape/zftape/zftape-ctl.h delete mode 100644 drivers/char/ftape/zftape/zftape-eof.c delete mode 100644 drivers/char/ftape/zftape/zftape-eof.h delete mode 100644 drivers/char/ftape/zftape/zftape-init.c delete mode 100644 drivers/char/ftape/zftape/zftape-init.h delete mode 100644 drivers/char/ftape/zftape/zftape-read.c delete mode 100644 drivers/char/ftape/zftape/zftape-read.h delete mode 100644 drivers/char/ftape/zftape/zftape-rw.c delete mode 100644 drivers/char/ftape/zftape/zftape-rw.h delete mode 100644 drivers/char/ftape/zftape/zftape-vtbl.c delete mode 100644 drivers/char/ftape/zftape/zftape-vtbl.h delete mode 100644 drivers/char/ftape/zftape/zftape-write.c delete mode 100644 drivers/char/ftape/zftape/zftape-write.h delete mode 100644 drivers/char/ftape/zftape/zftape_syms.c delete mode 100644 include/linux/ftape-header-segment.h delete mode 100644 include/linux/ftape-vendors.h delete mode 100644 include/linux/ftape.h delete mode 100644 include/linux/zftape.h (limited to 'include/linux') diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 02457ec9c94f..f08ca9535733 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -104,8 +104,6 @@ firmware_class/ - request_firmware() hotplug interface info. floppy.txt - notes and driver options for the floppy disk driver. -ftape.txt - - notes about the floppy tape device driver. hayes-esp.txt - info on using the Hayes ESP serial driver. highuid.txt diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f81819364b7a..226ecf2ffd56 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -234,14 +234,6 @@ Who: Jean Delvare --------------------------- -What: ftape -When: 2.6.20 -Why: Orphaned for ages. SMP bugs long unfixed. Few users left - in the world. -Who: Jeff Garzik - ---------------------------- - What: IPv4 only connection tracking/NAT/helpers When: 2.6.22 Why: The new layer 3 independant connection tracking replaces the old diff --git a/Documentation/ftape.txt b/Documentation/ftape.txt deleted file mode 100644 index 7d8bb3384031..000000000000 --- a/Documentation/ftape.txt +++ /dev/null @@ -1,307 +0,0 @@ -Intro -===== - -This file describes some issues involved when using the "ftape" -floppy tape device driver that comes with the Linux kernel. - -ftape has a home page at - -http://ftape.dot-heine.de/ - -which contains further information about ftape. Please cross check -this WWW address against the address given (if any) in the MAINTAINERS -file located in the top level directory of the Linux kernel source -tree. - -NOTE: This is an unmaintained set of drivers, and it is not guaranteed to work. -If you are interested in taking over maintenance, contact Claus-Justus Heine -, the former maintainer. - -Contents -======== - -A minus 1: Ftape documentation - -A. Changes - 1. Goal - 2. I/O Block Size - 3. Write Access when not at EOD (End Of Data) or BOT (Begin Of Tape) - 4. Formatting - 5. Interchanging cartridges with other operating systems - -B. Debugging Output - 1. Introduction - 2. Tuning the debugging output - -C. Boot and load time configuration - 1. Setting boot time parameters - 2. Module load time parameters - 3. Ftape boot- and load time options - 4. Example kernel parameter setting - 5. Example module parameter setting - -D. Support and contacts - -******************************************************************************* - -A minus 1. Ftape documentation -============================== - -Unluckily, the ftape-HOWTO is out of date. This really needs to be -changed. Up to date documentation as well as recent development -versions of ftape and useful links to related topics can be found at -the ftape home page at - -http://ftape.dot-heine.de/ - -******************************************************************************* - -A. Changes -========== - -1. Goal - ~~~~ - The goal of all that incompatibilities was to give ftape an interface - that resembles the interface provided by SCSI tape drives as close - as possible. Thus any Unix backup program that is known to work - with SCSI tape drives should also work. - - The concept of a fixed block size for read/write transfers is - rather unrelated to this SCSI tape compatibility at the file system - interface level. It developed out of a feature of zftape, a - block wise user transparent on-the-fly compression. That compression - support will not be dropped in future releases for compatibility - reasons with previous releases of zftape. - -2. I/O Block Size - ~~~~~~~~~~~~~~ - The block size defaults to 10k which is the default block size of - GNU tar. - - The block size can be tuned either during kernel configuration or - at runtime with the MTIOCTOP ioctl using the MTSETBLK operation - (i.e. do "mt -f /dev/qft0" setblk #BLKSZ). A block size of 0 - switches to variable block size mode i.e. "mt setblk 0" switches - off the block size restriction. However, this disables zftape's - built in on-the-fly compression which doesn't work with variable - block size mode. - - The BLKSZ parameter must be given as a byte count and must be a - multiple of 32k or 0, i.e. use "mt setblk 32768" to switch to a - block size of 32k. - - The typical symptom of a block size mismatch is an "invalid - argument" error message. - -3. Write Access when not at EOD (End Of Data) or BOT (Begin Of Tape) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - zftape (the file system interface of ftape-3.x) denies write access - to the tape cartridge when it isn't positioned either at BOT or - EOD. - -4. Formatting - ~~~~~~~~~~ - ftape DOES support formatting of floppy tape cartridges. You need the - `ftformat' program that is shipped with the modules version of ftape. - Please get the latest version of ftape from - - ftp://sunsite.unc.edu/pub/Linux/kernel/tapes - - or from the ftape home page at - - http://ftape.dot-heine.de/ - - `ftformat' is contained in the `./contrib/' subdirectory of that - separate ftape package. - -5. Interchanging cartridges with other operating systems - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - The internal emulation of Unix tape device file marks has changed - completely. ftape now uses the volume table segment as specified - by the QIC-40/80/3010/3020/113 standards to emulate file marks. As - a consequence there is limited support to interchange cartridges - with other operating systems. - - To be more precise: ftape will detect volumes written by other OS's - programs and other OS's programs will detect volumes written by - ftape. - - However, it isn't possible to extract the data dumped to the tape - by some MSDOS program with ftape. This exceeds the scope of a - kernel device driver. If you need such functionality, then go ahead - and write a user space utility that is able to do that. ftape already - provides all kernel level support necessary to do that. - -******************************************************************************* - -B. Debugging Output - ================ - -1. Introduction - ~~~~~~~~~~~~ - The ftape driver can be very noisy in that is can print lots of - debugging messages to the kernel log files and the system console. - While this is useful for debugging it might be annoying during - normal use and enlarges the size of the driver by several kilobytes. - - To reduce the size of the driver you can trim the maximal amount of - debugging information available during kernel configuration. Please - refer to the kernel configuration script and its on-line help - functionality. - - The amount of debugging output maps to the "tracing" boot time - option and the "ft_tracing" modules option as follows: - - 0 bugs - 1 + errors (with call-stack dump) - 2 + warnings - 3 + information - 4 + more information - 5 + program flow - 6 + fdc/dma info - 7 + data flow - 8 + everything else - -2. Tuning the debugging output - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - To reduce the amount of debugging output printed to the system - console you can - - i) trim the debugging output at run-time with - - mt -f /dev/nqft0 setdensity #DBGLVL - - where "#DBGLVL" is a number between 0 and 9 - - ii) trim the debugging output at module load time with - - modprobe ftape ft_tracing=#DBGLVL - - Of course, this applies only if you have configured ftape to be - compiled as a module. - - iii) trim the debugging output during system boot time. Add the - following to the kernel command line: - - ftape=#DBGLVL,tracing - - Please refer also to the next section if you don't know how to - set boot time parameters. - -******************************************************************************* - -C. Boot and load time configuration - ================================ - -1. Setting boot time parameters - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Assuming that you use lilo, the LI)nux LO)ader, boot time kernel - parameters can be set by adding a line - - append some_kernel_boot_time_parameter - - to `/etc/lilo.conf' or at real boot time by typing in the options - at the prompt provided by LILO. I can't give you advice on how to - specify those parameters with other loaders as I don't use them. - - For ftape, each "some_kernel_boot_time_parameter" looks like - "ftape=value,option". As an example, the debugging output can be - increased with - - ftape=4,tracing - - NOTE: the value precedes the option name. - -2. Module load time parameters - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Module parameters can be specified either directly when invoking - the program 'modprobe' at the shell prompt: - - modprobe ftape ft_tracing=4 - - or by editing the file `/etc/modprobe.conf' in which case they take - effect each time when the module is loaded with `modprobe' (please - refer to the respective manual pages). Thus, you should add a line - - options ftape ft_tracing=4 - - to `/etc/modprobe.conf` if you intend to increase the debugging - output of the driver. - - -3. Ftape boot- and load time options - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - i. Controlling the amount of debugging output - DBGLVL has to be replaced by a number between 0 and 8. - - module | kernel command line - -----------------------|---------------------- - ft_tracing=DBGLVL | ftape=DBGLVL,tracing - - ii. Hardware setup - BASE is the base address of your floppy disk controller, - IRQ and DMA give its interrupt and DMA channel, respectively. - BOOL is an integer, "0" means "no"; any other value means - "yes". You don't need to specify anything if connecting your tape - drive to the standard floppy disk controller. All of these - values have reasonable defaults. The defaults can be modified - during kernel configuration, i.e. while running "make config", - "make menuconfig" or "make xconfig" in the top level directory - of the Linux kernel source tree. Please refer also to the on - line documentation provided during that kernel configuration - process. - - ft_probe_fc10 is set to a non-zero value if you wish for ftape to - probe for a Colorado FC-10 or FC-20 controller. - - ft_mach2 is set to a non-zero value if you wish for ftape to probe - for a Mountain MACH-2 controller. - - module | kernel command line - -----------------------|---------------------- - ft_fdc_base=BASE | ftape=BASE,ioport - ft_fdc_irq=IRQ | ftape=IRQ,irq - ft_fdc_dma=DMA | ftape=DMA,dma - ft_probe_fc10=BOOL | ftape=BOOL,fc10 - ft_mach2=BOOL | ftape=BOOL,mach2 - ft_fdc_threshold=THR | ftape=THR,threshold - ft_fdc_rate_limit=RATE | ftape=RATE,datarate - -4. Example kernel parameter setting - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - To configure ftape to probe for a Colorado FC-10/FC-20 controller - and to increase the amount of debugging output a little bit, add - the following line to `/etc/lilo.conf': - - append ftape=1,fc10 ftape=4,tracing - -5. Example module parameter setting - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - To do the same, but with ftape compiled as a loadable kernel - module, add the following line to `/etc/modprobe.conf': - - options ftape ft_probe_fc10=1 ft_tracing=4 - -******************************************************************************* - -D. Support and contacts - ==================== - - Ftape is distributed under the GNU General Public License. There is - absolutely no warranty for this software. However, you can reach - the current maintainer of the ftape package under the email address - given in the MAINTAINERS file which is located in the top level - directory of the Linux kernel source tree. There you'll find also - the relevant mailing list to use as a discussion forum and the web - page to query for the most recent documentation, related work and - development versions of ftape. - - Changelog: - ========== - -~1996: Original Document - -10-24-2004: General cleanup and updating, noting additional module options. - James Nelson diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 67473849f20e..15e4fed127f6 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -557,9 +557,6 @@ and is between 256 and 4096 characters. It is defined in the file floppy= [HW] See Documentation/floppy.txt. - ftape= [HW] Floppy Tape subsystem debugging options. - See Documentation/ftape.txt. - gamecon.map[2|3]= [HW,JOY] Multisystem joystick and NES/SNES/PSX pad support via parallel port (up to 5 devices per port) diff --git a/MAINTAINERS b/MAINTAINERS index 45df5d4e2ab3..8385a69138a8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1166,11 +1166,6 @@ P: David Howells M: dhowells@redhat.com S: Maintained -FTAPE/QIC-117 -L: linux-tape@vger.kernel.org -W: http://sourceforge.net/projects/ftape -S: Orphan - FUSE: FILESYSTEM IN USERSPACE P: Miklos Szeredi M: miklos@szeredi.hu diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ad8b537ad47b..24f922f12783 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -855,39 +855,6 @@ config TANBAC_TB0219 depends TANBAC_TB022X select GPIO_VR41XX -menu "Ftape, the floppy tape device driver" - -config FTAPE - tristate "Ftape (QIC-80/Travan) support" - depends on BROKEN_ON_SMP && (ALPHA || X86) - ---help--- - If you have a tape drive that is connected to your floppy - controller, say Y here. - - Some tape drives (like the Seagate "Tape Store 3200" or the Iomega - "Ditto 3200" or the Exabyte "Eagle TR-3") come with a "high speed" - controller of their own. These drives (and their companion - controllers) are also supported if you say Y here. - - If you have a special controller (such as the CMS FC-10, FC-20, - Mountain Mach-II, or any controller that is based on the Intel 82078 - FDC like the high speed controllers by Seagate and Exabyte and - Iomega's "Ditto Dash") you must configure it by selecting the - appropriate entries from the "Floppy tape controllers" sub-menu - below and possibly modify the default values for the IRQ and DMA - channel and the IO base in ftape's configuration menu. - - If you want to use your floppy tape drive on a PCI-bus based system, - please read the file . - - The ftape kernel driver is also available as a runtime loadable - module. To compile this driver as a module, choose M here: the - module will be called ftape. - -source "drivers/char/ftape/Kconfig" - -endmenu - source "drivers/char/agp/Kconfig" source "drivers/char/drm/Kconfig" diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 777cad045094..b1fcdab90947 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -78,7 +78,6 @@ obj-$(CONFIG_TOSHIBA) += toshiba.o obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_HW_RANDOM) += hw_random/ -obj-$(CONFIG_FTAPE) += ftape/ obj-$(CONFIG_COBALT_LCD) += lcd.o obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_NWBUTTON) += nwbutton.o diff --git a/drivers/char/ftape/Kconfig b/drivers/char/ftape/Kconfig deleted file mode 100644 index 0d65189a7ae8..000000000000 --- a/drivers/char/ftape/Kconfig +++ /dev/null @@ -1,330 +0,0 @@ -# -# Ftape configuration -# -config ZFTAPE - tristate "Zftape, the VFS interface" - depends on FTAPE - ---help--- - Normally, you want to say Y or M. DON'T say N here or you - WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE. - - The ftape module itself no longer contains the routines necessary - to interface with the kernel VFS layer (i.e. to actually write data - to and read data from the tape drive). Instead the file system - interface (i.e. the hardware independent part of the driver) has - been moved to a separate module. - - To compile this driver as a module, choose M here: the - module will be called zftape. - - Regardless of whether you say Y or M here, an additional runtime - loadable module called `zft-compressor' which contains code to - support user transparent on-the-fly compression based on Ross - William's lzrw3 algorithm will be produced. If you have enabled the - kernel module loader (i.e. have said Y to "Kernel module loader - support", above) then `zft-compressor' will be loaded - automatically by zftape when needed. - - Despite its name, zftape does NOT use compression by default. - -config ZFT_DFLT_BLK_SZ - int "Default block size" - depends on ZFTAPE - default "10240" - ---help--- - If unsure leave this at its default value, i.e. 10240. Note that - you specify only the default block size here. The block size can be - changed at run time using the MTSETBLK tape operation with the - MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the - shell command line). - - The probably most striking difference between zftape and previous - versions of ftape is the fact that all data must be written or read - in multiples of a fixed block size. The block size defaults to - 10240 which is what GNU tar uses. The values for the block size - should be either 1 or multiples of 1024 up to a maximum value of - 63488 (i.e. 62 K). If you specify `1' then zftape's builtin - compression will be disabled. - - Reasonable values are `10240' (GNU tar's default block size), - `5120' (afio's default block size), `32768' (default block size some - backup programs assume for SCSI tape drives) or `1' (no restriction - on block size, but disables builtin compression). - -comment "The compressor will be built as a module only!" - depends on FTAPE && ZFTAPE - -config ZFT_COMPRESSOR - tristate - depends on FTAPE!=n && ZFTAPE!=n - default m - -config FT_NR_BUFFERS - int "Number of ftape buffers (EXPERIMENTAL)" - depends on FTAPE && EXPERIMENTAL - default "3" - help - Please leave this at `3' unless you REALLY know what you are doing. - It is not necessary to change this value. Values below 3 make the - proper use of ftape impossible, values greater than 3 are a waste of - memory. You can change the amount of DMA memory used by ftape at - runtime with "mt -f /dev/qft0 setdrvbuffer #NUMBUFFERS". Each buffer - wastes 32 KB of memory. Please note that this memory cannot be - swapped out. - -config FT_PROC_FS - bool "Enable procfs status report (+2kb)" - depends on FTAPE && PROC_FS - ---help--- - Optional. Saying Y will result in creation of a directory - `/proc/ftape' under the /proc file system. The files can be viewed - with your favorite pager (i.e. use "more /proc/ftape/history" or - "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The - file will contain some status information about the inserted - cartridge, the kernel driver, your tape drive, the floppy disk - controller and the error history for the most recent use of the - kernel driver. Saying Y will enlarge the size of the ftape driver - by approximately 2 KB. - - WARNING: When compiling ftape as a module (i.e. saying M to "Floppy - tape drive") it is dangerous to use ftape's /proc file system - interface. Accessing `/proc/ftape' while the module is unloaded will - result in a kernel Oops. This cannot be fixed from inside ftape. - -choice - prompt "Debugging output" - depends on FTAPE - default FT_NORMAL_DEBUG - -config FT_NORMAL_DEBUG - bool "Normal" - ---help--- - This option controls the amount of debugging output the ftape driver - is ABLE to produce; it does not increase or diminish the debugging - level itself. If unsure, leave this at its default setting, - i.e. choose "Normal". - - Ftape can print lots of debugging messages to the system console - resp. kernel log files. Reducing the amount of possible debugging - output reduces the size of the kernel module by some KB, so it might - be a good idea to use "None" for emergency boot floppies. - - If you want to save memory then the following strategy is - recommended: leave this option at its default setting "Normal" until - you know that the driver works as expected, afterwards reconfigure - the kernel, this time specifying "Reduced" or "None" and recompile - and install the kernel as usual. Note that choosing "Excessive" - debugging output does not increase the amount of debugging output - printed to the console but only makes it possible to produce - "Excessive" debugging output. - - Please read for a short description - how to control the amount of debugging output. - -config FT_FULL_DEBUG - bool "Excessive" - help - Extremely verbose output for driver debugging purposes. - -config FT_NO_TRACE - bool "Reduced" - help - Reduced tape driver debugging output. - -config FT_NO_TRACE_AT_ALL - bool "None" - help - Suppress all debugging output from the tape drive. - -endchoice - -comment "Hardware configuration" - depends on FTAPE - -choice - prompt "Floppy tape controllers" - depends on FTAPE - default FT_STD_FDC - -config FT_STD_FDC - bool "Standard" - ---help--- - Only change this setting if you have a special controller. If you - didn't plug any add-on card into your computer system but just - plugged the floppy tape cable into the already existing floppy drive - controller then you don't want to change the default setting, - i.e. choose "Standard". - - Choose "MACH-2" if you have a Mountain Mach-2 controller. - Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20 - controller. - Choose "Alt/82078" if you have another controller that is located at - an IO base address different from the standard floppy drive - controller's base address of `0x3f0', or uses an IRQ (interrupt) - channel different from `6', or a DMA channel different from - `2'. This is necessary for any controller card that is based on - Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high - speed" controllers. - - If you choose something other than "Standard" then please make - sure that the settings for the IO base address and the IRQ and DMA - channel in the configuration menus below are correct. Use the manual - of your tape drive to determine the correct settings! - - If you are already successfully using your tape drive with another - operating system then you definitely should use the same settings - for the IO base, the IRQ and DMA channel that have proven to work - with that other OS. - - Note that this menu lets you specify only the default setting for - the hardware setup. The hardware configuration can be changed at - boot time (when ftape is compiled into the kernel, i.e. if you - have said Y to "Floppy tape drive") or module load time (i.e. if you - have said M to "Floppy tape drive"). - - Please read also the file which - contains a short description of the parameters that can be set at - boot or load time. If you want to use your floppy tape drive on a - PCI-bus based system, please read the file - . - -config FT_MACH2 - bool "MACH-2" - -config FT_PROBE_FC10 - bool "FC-10/FC-20" - -config FT_ALT_FDC - bool "Alt/82078" - -endchoice - -comment "Consult the manuals of your tape drive for the correct settings!" - depends on FTAPE && !FT_STD_FDC - -config FT_FDC_BASE - hex "IO base of the floppy disk controller" - depends on FTAPE && !FT_STD_FDC - default "0" - ---help--- - You don't need to specify a value if the following default - settings for the base IO address are correct: - <<< MACH-2 : 0x1E0 >>> - <<< FC-10/FC-20: 0x180 >>> - <<< Secondary : 0x370 >>> - Secondary refers to a secondary FDC controller like the "high speed" - controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. - Please make sure that the setting for the IO base address - specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR - CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already - successfully using the tape drive with another operating system then - you definitely should use the same settings for the IO base that has - proven to work with that other OS. - - Note that this menu lets you specify only the default setting for - the IO base. The hardware configuration can be changed at boot time - (when ftape is compiled into the kernel, i.e. if you specified Y to - "Floppy tape drive") or module load time (i.e. if you have said M to - "Floppy tape drive"). - - Please read also the file which - contains a short description of the parameters that can be set at - boot or load time. - -config FT_FDC_IRQ - int "IRQ channel of the floppy disk controller" - depends on FTAPE && !FT_STD_FDC - default "0" - ---help--- - You don't need to specify a value if the following default - settings for the interrupt channel are correct: - <<< MACH-2 : 6 >>> - <<< FC-10/FC-20: 9 >>> - <<< Secondary : 6 >>> - Secondary refers to secondary a FDC controller like the "high speed" - controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. - Please make sure that the setting for the IO base address - specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR - CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already - successfully using the tape drive with another operating system then - you definitely should use the same settings for the IO base that has - proven to work with that other OS. - - Note that this menu lets you specify only the default setting for - the IRQ channel. The hardware configuration can be changed at boot - time (when ftape is compiled into the kernel, i.e. if you said Y to - "Floppy tape drive") or module load time (i.e. if you said M to - "Floppy tape drive"). - - Please read also the file which - contains a short description of the parameters that can be set at - boot or load time. - -config FT_FDC_DMA - int "DMA channel of the floppy disk controller" - depends on FTAPE && !FT_STD_FDC - default "0" - ---help--- - You don't need to specify a value if the following default - settings for the DMA channel are correct: - <<< MACH-2 : 2 >>> - <<< FC-10/FC-20: 3 >>> - <<< Secondary : 2 >>> - Secondary refers to a secondary FDC controller like the "high speed" - controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. - Please make sure that the setting for the IO base address - specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR - CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already - successfully using the tape drive with another operating system then - you definitely should use the same settings for the IO base that has - proven to work with that other OS. - - Note that this menu lets you specify only the default setting for - the DMA channel. The hardware configuration can be changed at boot - time (when ftape is compiled into the kernel, i.e. if you said Y to - "Floppy tape drive") or module load time (i.e. if you said M to - "Floppy tape drive"). - - Please read also the file which - contains a short description of the parameters that can be set at - boot or load time. - -config FT_FDC_THR - int "Default FIFO threshold (EXPERIMENTAL)" - depends on FTAPE && EXPERIMENTAL - default "8" - help - Set the FIFO threshold of the FDC. If this is higher the DMA - controller may serve the FDC after a higher latency time. If this is - lower, fewer DMA transfers occur leading to less bus contention. - You may try to tune this if ftape annoys you with "reduced data - rate because of excessive overrun errors" messages. However, this - doesn't seem to have too much effect. - - If unsure, don't touch the initial value, i.e. leave it at "8". - -config FT_FDC_MAX_RATE - int "Maximal data rate to use (EXPERIMENTAL)" - depends on FTAPE && EXPERIMENTAL - default "2000" - ---help--- - With some motherboard/FDC combinations ftape will not be able to - run your FDC/tape drive combination at the highest available - speed. If this is the case you'll encounter "reduced data rate - because of excessive overrun errors" messages and lots of retries - before ftape finally decides to reduce the data rate. - - In this case it might be desirable to tell ftape beforehand that - it need not try to run the tape drive at the highest available - speed. If unsure, leave this disabled, i.e. leave it at 2000 - bits/sec. - -config FT_ALPHA_CLOCK - int "CPU clock frequency of your DEC Alpha" if ALPHA - depends on FTAPE - default "0" - help - On some DEC Alpha machines the CPU clock frequency cannot be - determined automatically, so you need to specify it here ONLY if - running a DEC Alpha, otherwise this setting has no effect. - diff --git a/drivers/char/ftape/Makefile b/drivers/char/ftape/Makefile deleted file mode 100644 index 0e67d2f8b7ec..000000000000 --- a/drivers/char/ftape/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 1997 Claus Heine. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to -# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -# -# $Source: /homes/cvs/ftape-stacked/ftape/Makefile,v $ -# $Revision: 1.4 $ -# $Date: 1997/10/05 19:17:56 $ -# -# Makefile for the QIC-40/80/3010/3020 floppy-tape driver for -# Linux. -# - -obj-$(CONFIG_FTAPE) += lowlevel/ -obj-$(CONFIG_ZFTAPE) += zftape/ -obj-$(CONFIG_ZFT_COMPRESSOR) += compressor/ diff --git a/drivers/char/ftape/README.PCI b/drivers/char/ftape/README.PCI deleted file mode 100644 index 18de159d36e0..000000000000 --- a/drivers/char/ftape/README.PCI +++ /dev/null @@ -1,81 +0,0 @@ -Some notes for ftape users with PCI motherboards: -================================================= - -The problem: ------------- - -There have been some problem reports from people using PCI-bus based -systems getting overrun errors. -I wasn't able to reproduce these until I ran ftape on a Intel Plato -(Premiere PCI II) motherboard with bios version 1.00.08AX1. -It turned out that if GAT (Guaranteed Access Timing) is enabled (?) -ftape gets a lot of overrun errors. -The problem disappears when disabling GAT in the bios. -Note that Intel removed this setting (permanently disabled) from the -1.00.10AX1 bios ! - -It looks like that if GAT is enabled there are often large periods -(greater than 120 us !??) on the ISA bus that the DMA controller cannot -service the floppy disk controller. -I cannot imagine this being acceptable in a decent PCI implementation. -Maybe this is a `feature' of the chipset. I can only speculate why -Intel choose to remove the option from the latest Bios... - -The lesson of this all is that there may be other motherboard -implementations having the same of similar problems. -If you experience a lot of overrun errors during a backup to tape, -see if there is some setting in the Bios that may influence the -bus timing. - -I judge this a hardware problem and not a limitation of ftape ;-) -My DOS backup software seems to be suffering from the same problems -and even refuses to run at 1 Mbps ! -Ftape will reduce the data-rate from 1 Mbps to 500 Kbps if the number -of overrun errors on a track exceeds a threshold. - - -Possible solutions: -------------------- - -Some of the problems were solved by upgrading the (flash) bios. -Other suggest that it has to do with the FDC being on the PCI -bus, but that is not the case with the Intel Premiere II boards. -[If upgrading the bios doesn't solve the problem you could try -a floppy disk controller on the isa-bus]. - -Here is a list of systems and recommended BIOS settings: - - - Intel Premiere PCI (Revenge): - -Bios version 1.00.09.AF2 is reported to work. - - - - Intel Premiere PCI II (Plato): - -Bios version 1.00.10.AX1 and version 11 beta are ok. -If using version 1.00.08.AX1, GAT must be disabled ! - - - - ASUS PCI/I-SP3G: - -Preferred settings: ISA-GAT-mode : disabled - DMA-linebuffer-mode : standard - ISA-masterbuffer-mode : standard - - - DELL Dimension XPS P90 - -Bios version A2 is reported to be broken, while bios version A5 works. -You can get a flash bios upgrade from http://www.dell.com - - -To see if you're having the GAT problem, try making a backup -under DOS. If it's very slow and often repositions you're -probably having this problem. - - --//-- - LocalWords: ftape PCI bios GAT ISA DMA chipset Mbps Kbps FDC isa AF ok ASUS - LocalWords: SP linebuffer masterbuffer XPS http www com diff --git a/drivers/char/ftape/RELEASE-NOTES b/drivers/char/ftape/RELEASE-NOTES deleted file mode 100644 index 03799dbc05a4..000000000000 --- a/drivers/char/ftape/RELEASE-NOTES +++ /dev/null @@ -1,966 +0,0 @@ -Hey, Emacs, we're -*-Text-*- mode! - -===== Release notes for ftape-3.04d 25/11/97 ===== -- The correct pre-processor statement for "else if" is "#elif" not - "elsif". -- Need to call zft_reset_position() when overwriting cartridges - previously written with ftape-2.x, sftape, or ancient - (pre-ftape-3.x) versions of zftape. - -===== Release notes for ftape-3.04c 16/11/97 ===== -- fdc_probe() was calling DUMPREGS with a result length of "1" which - was just fine. Undo previous change. - -===== Release notes for ftape-3.04b 14/11/97 ===== - -- patches/2.x.x/floppy.c.diff was somewhat broken, releasing i/o - regions it never had allocated. -- fdc_probe() was calling DUMPREGS with a result length of "1" instead - of "10" -- Writing deleted data marks if the first segents on track zero are - should work now. -- ftformat should now be able to handle those cases where the tape - drive sets the read only status bit (QIC-40/80 cartridges with - QIC-3010/3020 tape drives) because the header segment is damaged. -- the MTIOCFTCMD ioctl may now be issued by the superuser ONLY. - -===== Release notes for ftape-3.04a 12/11/97 ===== -- Fix an "infinite loop can't be killed by signal" bug in - ftape_get_drive_status(). Only relevant when trying to access - buggy/misconfigured hardware -- Try to compensate a bug in the HP Colorado T3000's firmware: it - doesn't set the write protect bit for QIC80/QIC40 cartridges. - -===== Release notes for ftape-3.04 06/11/97 ===== -- If positioning with fast seeking fails fall back to a slow seek - before giving up. -- (nearly) no retries on "no data errors" when verifying after - formatting. Improved tuning of the bad sector map after formatting. -- the directory layout has changed again to allow for easier kernel - integration -- Module parameter "ftape_tracing" now is called "ft_tracing" because - the "ftape_tracing" variable has the version checksum attached to it. -- `/proc/ftape' interface for 2.0.* kernels. `/proc/ftape' no longer - is a directory but a file that contains all the information formerly - provided in separate files under the `/proc/ftape/' directory. -- Most of the configuration options have been prefixed by "CONFIG_FT_" - in preparation of the kernel inclusion. The Makefiles under - "./ftape/" should be directly usable by the kernel. -- The MODVERSIONS stuff is now auto-detected. -- Broke backslashed multi line options in MCONFIG into separate lines - using GNU-make's "+=" feature. -- The html and dvi version of the manual is now installed under - '/usr/doc/ftape` with 'make install` -- New SMP define in MCONFIG. ftape works with SMP if this is defined. -- attempt to cope with "excessive overrun errors" by gradually - increasing FDC FIFO threshold. But this doesn't seem to have too - much an effect. -- New load time configuration parameter "ft_fdc_rate_limit". If you - encounter too many overrun errors with a 2Mb controller then you - might want to set this to 1000. -- overrun errors on the last sector in a segment sometimes result in - a zero DMA residue. Dunno why, but compensate for it. -- there were still fdc_read() timeout errors. I think I have fixed it - now, please FIXME. -- Sometimes ftape_write() failed to re-start the tape drive when a - segment without a good sector was reached ("wait for empty segment - failed"). This is fixed. Especially important for > QIC-3010. -- sftape (aka ftape-2.x) has vanished. I didn't work on it for - ages. It is probably still possible to use the old code with - ftape-3.04, if one really needs it (BUT RECOMPILE IT) -- zftape no longer alters the contents of already existing volume - table entries, which makes it possible to fill in missing fields, - like time stamps using some user space program. -- ./contrib/vtblc/ contains such a program. -- new perl script ./contrib/scripts/listtape that list the contents of a - floppy tape cartridge parsing the output of "mt volinfo" + "mt fsf" -- the MTWEOF implementation has changed a little bit (after I had a - look at amanda). Calling MTWEOF while the tape is still held open - after writing something to the tape now will terminate the current - volume, and start a new one at the current position. -- the volume table maintained by zftape now is a doubly linked list - that grows dynamically as needed. - - formatting floppy tape cartridges - --------------------------------- - * there is a new user space formatting program that does most of the - dirty work in user space (auto-detect, computing the sector - coordinates, adjusting time stamps and statistics). It has a - simple command line interface. - * ftape-format.o has vanished, it has been folded into the low level - ftape.o module, and the ioctl interface into zftape.o. Most of the - complicated stuff has been moved to user space, so there was no - need for a separate module anymore. - * there is a new ioctl MTIOCFTCMD that sends a bare QIC-117 command - to the tape drive. - * there is a new mmap() feature to map the dma buffers into user - space to be used by the user level formatting program. - * Formatting of yet unformatted or totally degaussed cartridges - should be possible now. FIXME. - -===== Release notes for ftape-3.03b, ==== - -ftape-3.03b was released as a beta release only. Its main new feature -was support of the DITTO-2GB drive. This was made possible by reverse -engineering done by after Iomega failed to support -ftape. Although they had promised to do so (this makes me feel a bit -sad and uncomfortable about Iomega). - -===== Release notes for ftape-3.03a, 22/05/97 ==== - -- Finally fixed auto-un-loading of modules for kernels > 2.1.18 -- Add an "uninstall" target to the Makefile -- removed the kdtime hack -- texi2www didn't properly set the back-reference from a footnote back - to the regular text. - - zftape specific - --------------- - * hide the old compression map volume. Taper doesn't accept the - presence of non-Taper volumes and Taper-written volume on the same - tape. - * EOD (End Of Data) handling was still broken: the expected behavior - is to return a zero byte count at the first attempt to read past - EOD, return a zero byte count at the second attempt to read past - EOD and THEN return -EIO. - - ftape-format specific - --------------------- - * Detection of QIC-40 cartridges in select_tape_format() was broken - and made it impossible to format QIC-3010/3020 cartridges. - * There are strange "TR-1 Extra" cartridges out there which weren't - detected properly because the don't strictly conform to the - QIC-80, Rev. N, spec. - -===== Release notes for ftape-3.03, 30/04/97 ===== - -- Removed kernel integration code from the package. I plan to provide - a package that can be integrated into the stock kernel separately - (hopefully soon). - As a result, a simple `make' command now will build everything. -- ALL compile time configuration options have been moved to the file - `MCONFIG'. -- Quite a few `low level' changes to allow formatting of cartridges. -- formatting is implemented as a separate module `ftape-format.o'. The - modified `mt' program contains sample code that shows how to use it. -- The VFS interface has been moved from the `ftape.o' module to the - high level modules `zftape.o' resp. `sftape.o'. `ftape.o' contains - the hardware support only. -- A bit of /proc support for kernels > 2.1.28 -- Moved documentation to Doc subdir. INSTALL now contains some real - installation notes. -- `install' target in Makefile. - -zftape specific: ----------------- - -- zftape works for large cartridges now ( > 2^31 bytes) -- MTIOCVOLINFO and MTIOCGETSIZE now return the size in KILOBYTES, - NO LONGER in bytes. - -- permissions for write access to a cartridge have changed: - * zftape now also takes the file access mode into account - * zftape no longer allows writing in the middle of the recorded - media. The tape has to be positioned at BOT or EOD for write - access. - -- MTBSF has changed. It used to position at the beginning of the - previous file when called with count 1. This was different from the - expected behavior for other Un*x tape drivers (i.e. SCSI). MTBSF - with count 1 should merely position at the beginning of the current - volume. Fixed. As a result, `tar --verify' now produces the desired - result: it verifies the last written volume, not the pre-last - written volume. - -- The compression map has vanished --> no need for `mt erase' any - more. Fast seeking in a compressed volume is still be possible, but - takes slightly longer. As a side effect, you may experience an - additional volume showing up in front of all others for old - cartridges. This is the tape volume that holds the compression map. - -- The compression support for zftape has been moved to a separate - module `zft-compressor'. DON'T forget to load it before trying to - read back compressed volumes. The stock `zftape.o' module probes for - the module `zft-compressor' using the kerneld message channel; you - have to install `zft-compressor.o' in a place where modprobe can - find it if you want to use this. - -- New experimental feature that tries to get the broken down GMT time - from user space via a kernel daemon message channel. You need to - compile and start the `kdtime' daemon contained in the contrib - directory to use it. Needed (?) for time stamps in the header - segments and the volume table. - -- variable block size mode via MTSETBLK 0 - -- keep modules locked in memory after the block size has been changed - -sftape specific: ----------------- - -- end of tape handling should be fixed, i.e. multi volume archives - written with `afio' can be read back now. - - -===== Release notes for ftape-3.02a, 09/01/97 ===== - -No big news: -- call zft_init() resp. sft_init() when compiling the entire stuff - into the kernel image. -- fix bug in ftape-setup.c when NO_TRACE_AT_ALL was defined. -- fix bug in sftape-eof.c/zftape-eof.c for old kernels (1.2.*) -- add support for new module interface for recent kernels - -===== Release notes for ftape-3.02, 16/12/96 ===== -- Fixed the `FDC unlock command failed' bug in fdc-io.c. When the FIFO - was already locked when ftape was loaded, ftape failed to unlock it. -- Fixed compilation of `contrib/gnumt'. It now finds `mtio.h' even if - ftape is NOT included into the kernel source tree. -- fc-10.c: include for inb() and outb(). -- ftape/sftape/zftape: all global variable now have either a `ftape_', - a `ft_', `sft_', `zft_' or `qic_' prefix to prevent name clashes - with other parts of the kernel when including ftape into the kernel - source tree. -- Kerneld support has changed. `ftape' now searches for a module - `ftape-frontend' when none of the frontend (`sftape' or `zftape') is - loaded. Please refer to the `Installation/Loading ftape' section of - the TeXinfo manual. -- Add load resp. boot-time configuration of ftape. There are now - variables ft_fdc_base, ft_fdc_dma and ft_fdc_irq corresponding to - the former FDC_BASE etc. compile time definitions. One can also use - the kernel command line parameters to configure the driver if it is - compiled into the kernel. Also, the FC-10/FC-20 support is load-time - configurable now as well as the MACH-II hack (ft_probe_fc10, - resp. ft_mach2). Please refer to the section `Installation/Configure - ftape' of the TeXinfo manual. -- I removed the MODVERSIONS option from `Makefile.module'. Let me alone - with ftape and MODVERSIONS unless you include the ftape sources into - the kernel source tree. -- new vendors in `vendors.h': - * HP Colorado T3000 - * ComByte DoublePlay (including a bug fix for their broken - formatting software, thanks to whraven@njackn.com) - * Iomega DITTO 2GIG. NOTE: this drive cannot work with ftape because - the logical data layout of the cartridges used by this drive does - NOT conform to the QIC standards, it is a special Iomega specific - format. I've sent mail to Iomega but didn't receive an answer - yet. If you want this drive to be supported by ftape, ask Iomega - to give me information about it. -- zftape: - * re-introduced the MTIOC_ZFTAPE_GETBLKSZ ioctl for compatibility - with zftape 1.06a and earlier. Please don't use it when writing - new software, use the MTIOCVOLINFO ioctl instead. - * Major overhaul of the code that updates the header segments. Never - change the tape label unless erasing the tape. Thus we almost - never need to write the header segments, unless we would modify - the bad sector map which isn't done yet. Updating of volume table - and compression map more secure now although it takes a bit - longer. - * Fixed bug when aborting a write operation with a signal: zftape - now finishes the current volume (i.e. writes an eof marker) at the - current position. It didn't before which led to somehow *strange* - behavior in this cases. - * Keep module locked in memory when using it with the non-rewinding - devices and the tape is not logical at BOT. Needed for kerneld - support. -- sftape: - * Keep module locked in memory when using it with the non-rewinding - devices and the tape is not logical at BOT. Needed for kerneld - support. - -===== Release notes for ftape-3.01, 14/11/96 ===== - -- Fixed silly bugs in ftape-3.00: - * MAKEDEV.ftape: major device number must be 27, not 23 - * sftape/sftape-read.c: sftape_read_header_segments() called - itself recursively instead of calling ftape_read_header_segment() - * zftape/qic-vtbl.h: conversion of ftape's file marks to zftape's - internal volume table was broken. - * patches/2.x.x/linux-2.0.21.dif: my RCS (resp. CVS) system replaced - the `$Revison:' etc. macros in the `ftape.h' concerning part of the - patch :-( Fixed. - * info/ftape.info: Fixed misspellings (`cp' <-> `cp -r' etc.) - * when ftape/sftape or ftape/zftape was compiled into the kernel the - variable ftape_status was declared twice. Fixed. - * removed reference to undeclared variable kernel_version when not - compiling as module - * fixed a bug introduced by the use of bit-fields for some flags - (i.e. write_protected, no_cartridge, formatted) - * flag `header_read' is now reset correctly to zero when tape is - removed. -- fixed a bug in sftape/sftape-eof.c that was already in the original - ftape code. MTFSF/BSF was not handled correctly when positioned - right before the file mark (think of tar) -- Changed TRACE macros (following a suggestion of Marcin Dalecki) to use - the predefined __FUNCTION__ macro of GCC. Spares about 4k of code. -- added new vendor id for Iomega DITTO 2GIG -- fixed a bug already present in zftape-1.06 when aborting a write - with a signal: we now finish the current volume at that - position. Header segments remain NOT up to date until an explicit call - to MTREW or MTOFFL is done. - -===== Release notes for ftape-3.00, 14/10/96 ===== - -- Merged ftape with zftape. There are three modules now: - ftape for the hardware support, sftape for the implementation of the - original ftape eof mark stuff and zftape that implements zftape's way - of handling things (compression, volume table, tape blocks of - constant length) -- Documentation in TeXinfo format in the `info' subdirectory. -- New ioctls for zftape. See zftape/zftape.h -- Dummy formatting ioctl for ftape. See ftape.h -- Kernel patch files for the 2.*.* series to include ftape-3.00 in the - kernel source tree. These includes a kernel compatible Config.in - script and fairly large online information for the kernel configure - script. -- Support for compiling with Linux-1.2.13. -- Modified GNU mt from their cpio package that can handle the new - ioctls. -- ftape/sftape/zftape is kerneld save now! - -Notes on sftape: -- sftape implements the eof handling code of the original ftape. If - you like to stick with the original ftape stuff, you have to use - this module, not zftape. -- sftape is kerneld save, unlike the original ftape. -- we keep the entire header segment now in memory, so no need to read - it before updating the header segments. Additional memory - consumption: 256 bytes. - -Notes for zftape: -- zftape has support for tapes with format code 6 now, which use a - slightly different volume table format compared with other floppy - tapes. -- new ioctls for zftape. Have a look at zftape/zftape.h -- The internal volume table representation has changed for zftape. Old - cartridges are converted automatically. -- zftape no longer uses compression map segments, which have vanished - from the QIC specs, but creates volume table entry that reserves - enough space for the compression map. -- zftape is kerneld save now. -- we keep the entire header segment now in memory, so no need to read - it before updating the header segments. Additional memory - consumption: 256 bytes. - -Notes for contrib/gnumt: -- modified mt from the GNU cpio package that supports all the new - ioctls of zftape. -Notes for contrib/swapout: -- This contains the swapout.c program that was written by Kai - Harrekilde-Pederson. I simply added a Makefile. - -===== Release notes for ftape-2.10, 14/10/96 ===== - -The ftape maintainer has changed. -Kai Harrekilde-Petersen -has resigned from maintaining ftape, and I, -Claus-Justus Heine , -have taken over. - -- Added support for tapes with `format code 6', i.e. QIC-3020 tapes - with more than 2^16 segments. -- merged changes made by Bas Laarhoven with ftape-2.09. Refer - to his release notes below. I've included them into this - file unchanged for your reference. -- disabled call stack back trace for now. This new feature - introduced by the interim release 2.0.x still seems to - be buggy. -- Tried to minimize differences between the ftape version - to be included into the kernel source tree and the standalone - module version. -- Reintroduced support for Linux-1.2.13. Please refer to the - Install-guide. - -===== Release notes for ftape-2.09, 16/06/96 ===== - -There aren't any really big news in this release, mostly just that I -(the maintainer) have changed my email address (due to a new job). My -new address is - -- The CLK_48MHZ and FDC_82078SL options has gone (all 2Mbps cards seem - to use a 48MHz oscillator anyway and I haven't heard of an 'SL - chip out there). -- The S82078B has been `downgraded' to i82077AA compability. -- TESTING option revived. Right now, it'll enable the (seriously broken) - 2Mbps code. If you enable it, you'll experience a tape drive that's - *really* out to lunch! -- Some (bold) changes in the init code. Please notify me if they - break things for you. - -===== Release notes for ftape-2.08, 14/03/96 ===== - -If you correct a problem with ftape, please send your patch to -khp@dolphinics.no too. - -- Updated to reflect that NR_MEM_LISTS is gone in 1.3.74 -- Teac 700 added to list of known drives. -- The registered device name is now "ft" rather than "ftape". - -===== Release notes for ftape-2.07a, 14/03/96 ===== - -Bugfixes by Marcin Dalecki : -- In the last release it just compiled against 1.3.70; - now the params to request_irq() and free_irq are() are fixed, so it also - works in 1.3.73 :-) -- Support for modules is now correct for newer kernels. - -===== Release notes for ftape-2.07, 04/03/96 ===== - - -- ftape updated to compile against 1.3.70. -- Iomega 700 and Wangtek 3200 recognised. - - -===== Release notes for ftape-2.06b, 13/02/96 ===== - -Another simple bugfix version. - -- Jumbo 700 recognised. -- Typo in vendors.h fixed. - - -===== Release notes for ftape-2.06a, 10/02/96 ===== - -This release is a simple bugfix version. - -- Linux/SMP: ftape *should* work. -- FC-10/20: Only accepts IRQs 3-7, or 9. If IRQ 9, properly tell the card - to use IRQ 2. Thanks to Greg Crider (gcrider@iclnet.org) for finding and - locating this bug and testing the patch. -- Insight drive recognised correctly again. -- Motor-on wakeup version of the Iomega 250 drive added - - -===== Release notes for ftape-2.06, 28/01/96 ===== - -Special thanks go to Neal Friedman and Steven Sorbom for their -help in producing and testing this release. - -I have continued to clean up the code, with an eye towards inclusion -of ftape in Linus' official kernel (In fact, as I type this, I am -running on a kernel with ftape support statically linked). I have -test-compiled ftape against my 1.2.13 tree without problems. -Hopefully, everything should be OK for the v1.2.x people. - -WARNING! Alan Cox has mailed me that ftape does *NOT* work with -Linux/SMP. If you try to run ftape under Linux/SMP, it will cause a -kernel deadlock (which is worse than a panic). - -- QIC-3020/TR-3: 1Mbps support works. Neal is capable of reading and - writing data to a tape. ftape will automatically detect the type of - tape (e.g. TR-3 vs QIC-80) and move the fdc in and out of - "perpendicular mode" as necessary. -- 2Mbps support is disabled by default, since it is not fully - debugged. If you are adventurous, remove -DFDC_82078SL in the - Makefile and see what happens :-) -- fdc detection: silly bugs removed (Only 2Mbps fdcs were affected) - and added detection of the National Semiconductors PC8744 fdc chip - (used in the PC873xx "super-IO" chips). -- Removed warning about incompatible types when compiling with Linux - 1.2.x. -- README.PCI updated with info about the DELL Dimension XPS P90. -- Connor TST3200R added to detected drives. -- `swapout' utility added to distribution. It will dirty 5Meg of - memory, trying to swap out other programs. Just say `make swapout' - to build it. ftape will do this automatically Real Soon Now (ie: - when I have found out which kernel memory alloc function to call). - - -===== Release notes for ftape-2.05, 08/01/96 ===== - -- For v1.2.x Kernels, you must apply the patch linux-1.2/ksyms.patch to - the kernel and rebuild it (it adds the __get_dma_pages symbol to - ksyms.c). -- Included new asm-i386/io.h file from v1.3.x kernel series, to enable - gcc v.2.7.[12] to compile v1.2.x kernels (linux-1.2/io.h). -- Module versions: If you wish to compile ftape as a versioned module, - you must first compile your kernel with CONFIG_MODVERSIONS=y. - Otherwise, you will get complaints that does not - exist (if that happens, a `touch modversions.h' will help you out). -- CLK_48MHZ: new define in the Makefile (default: non-zero). If you have - a tape controller card that uses the i82078(-1) chip, but cannot get - it to work with ftape, try set it to 0 (and please report this). -- QIC-3010/3020: Complete support is still missing, but will hopefully - come soon. Steven Sorbom has kindly provided me with hints about - this. Writing of QIC-3020 tapes definitely does NOT work (do not try - it! - the drive will not be in "perpendicular mode" and this will ruin - the formatting info on the tape). -- ftape_num_buffers is out of fashion: use NR_BUFFERS instead (and - recompile if you want to change it :-). - - -===== Release notes for ftape-2.04, 01/01/96 ===== - -This version by Kai Harrekilde-Petersen - -- ALERT! Support for Kernels earlier then v1.1.85 is about to go away. - I intend to clean up some of the code (getting rid of an annoyingly - large numbers of #ifdef mostly), which means that support for - pre-1.1.85 kernels must go as well. -- NR_FTAPE_BUFFERS is gone; You can instead select the number of dma - buffers by saying `insmod ftape.o ftape_num_buffer=' instead. -- Configure script gone. ftape will now automagically determine your - kernel version by /usr/include/linux/version.h instead. -- CONFIG_MODVERSIONS now work. All combinations of versioned / - unversioned kernel and ftape module works (at least with my 1.3.52 - kernel). -- If you have problems with inserting ftape into an old (1.2.x) - kernel (e.g. insmod says "1.2.8 does not match 1.2.8), recompile - your modules utilities with your new compiler. -- Reveal TB1400 drive added to vendors.h -- Support for the i82078-1 (2Mbps) chip is coming along. The - biggest problem is that I don't have such a card, which makes - testing / debugging somewhat problematic. The second biggest - problem is that I do not have the QIC-3010/3020 standards either. - Status right now is that the chip is detected, and it should be - possible to put it into 2Mbps mode. However, I do not know what - "extras" are needed to complete the support. Although putting the - i82078 into 1Mbps mode ought to work out of the box, it doesn't - (right now, ftape complains about id am errors). - - -===== Release notes for ftape-2.04beta5, 29/12/95 ===== - -Bas offline linux-tape ----------------------- -For reasons only known to the majordomo mail list processor, Bas was -kicked off the linux-tape list sometime during the summer. Being -overworked at his for-pay job, he didn't notice it much. Instead I -(Kai, khp@dolphinics.no) has worked on ftape to produce the 2.04(beta) -version. - -zftape ------- -Note that there exists a much improved version of ftape, written by -Claus-Justus Heine which is named -zftape, which conforms to the QIC-80 specs on how to mark backups, and -is capable of doing automatic compression. However, zftape makes -substantial changes to ftape, and I (Kai) have therefore declined to -integrate zftape into ftape. Hopefully, this will happen soon. - -CONFIG_QIC117 removed from the kernel -------------------------------------- -The biggest change of all is that ftape now will allocate its dma -buffers when it is inserted. The means that the CONFIG_QIC117 option -has disappeared from the Linux kernel as of v1.3.34. If you have an -earlier kernel, simply answer 'no' to the question will do the trick -(if you get complains about __get_free_pages() missing, contact the -linux-tape mailing list). - -Note that ftape-2.04beta will work equally well on kernels with and -without `ftape support'. The only catch is, that you will waste -around 96-128Kb of precious DMA'able memory on a box that has ftape -support compiled in. - -Now for the real changes: - -- FC-20 can now use DMA channels 1, 2, and 3. Thanks to Daniel - Cohen, catman@wpi.edu. -- ftape no longer requires a (gigantic) 96Kb buffer to be statically - allocated by the kernel. -- Added new Iomega drive (8882) to vendors.h -- -fno-strength-reduce added to Makefile, since GCC is broken. -- i82078-1 (2Mbps) FDC support started. - - -===== Release notes for ftape-2.03b, 27/05/95 ===== - -- Prevented verify_area to return error if called with zero length. -- Fixed a bug in flush_buffers that caused too much padding to be - written when a final segment had bad sectors. -- Increased maximum fast-seek overshoot value from 5 to 10 segments. -- Breaking loop after 5 retries when positioning fails. -- Fixed wrong calculation of tape length for QIC-3010 and QIC-3020 - tapes (densities were swapped). -- Fixed wrong calculation of overshoot on seek_forward: Wrong sign - of error. -- Suppress (false) error message due to new tape loaded. -- Added two new CMS drives (11c3 and 11c5) to vendors.h. - - -===== Release notes for ftape-2.03a, 09/05/95 ===== - -- Fixed display of old error (even if already cleared) in ftape_open. -- Improved tape length detection, ioctls would fail for 425 ft tapes. - Until the tape length is calculated with data from the header - segment, we'll use worst-case values. -- Clear eof_mark after rewinding ioctls. -- Fixed wrong version message (2.03 had 2.02g id). -- Fixed bug that caused the fdc to be reset very frequently. - This shouldn't affect normal operation but the timing of the - report routines has changed again and that may cause problems. - We'll just have to find out.... -- Implemented correct write precompensation setting for QIC-3010/3020. -- Cleaned up fdc_interrupt_wait routine. Hope it still works :-) -- Finally removed (already disabled) special eof mark handling for - gnu tar. -- Changed order of get_dma_residue and disable_dma in fdc-isr.c - because the current order would fail on at least one system. - We're back to the original order again, hope (and expect) this - doesn't break any other system. - - -===== Release notes for ftape-2.03, 07/05/95 ===== - -(Changes refer to the first ftape-2.02 release) - -Support for wide and extended length tapes ------------------------------------------- -The Conner TSM 420 and 850 drives are reported to be working. -I haven't received any reports about other brands; the TSM 420 -and 850 seem to be the most widely used wide drives. -Extended length tapes (425 ft) with normal QIC-80 drives -are operating too (At least I've had no reports stating otherwise). -_Not_ yet completely supported (although they may work) are -QIC-3020 drives and 2 Mbps floppy disk controllers won't work at -the highest speed. -If someone is kind enough to send me one of these, I'll include -support for it too ;-) - -Easier configuration --------------------- -Problems due to wrong settings in the Makefile are prevented -by using a configuration script that sets the necessary (kernel -version dependent) compile time options. -This kernel version is now determined from the sources found -at /usr/src/linux, or if not found, the old way using -/proc/version. -Versioned modules will be used automatically when supported -by- and configured in- the kernel. -Note that the current modules code (1.1.87) is still broken -and _needs_ the fix included in the insmod directory. -Please don't send me any more Oops reports caused by insmod :-( - -Reduced module size -------------------- -The standard module size is much reduced and some compile time -options can even reduce it further. (I don't recommend this -for normal use but it can be handy for rescue diskettes) - -Option: Approx. module size: - - 150 Kb -NO_TRACE 125 Kb -NO_TRACE_AT_ALL 67 Kb - - -Much improved driver interruption ---------------------------------- -Most possible loops have been broken and signal detection -has been improved. -In most cases the driver can be aborted by ^C (SIGINT) and -SIGKILL (kill -9) will generate be a sure kill. -(Note that aborting a tape operation may damage the last -data written to tape) - -Improved error recovery ------------------------ -Ftape now returns an error (ENODATA) to the application if -a segment proves to be unrecoverable and then skips the -bad segment. -This causes most applications to continue to work (tar -and afio) loosing only a small amount (up to 29 Kb) of data. -Retried read operations will now be done slightly off-track -to improve the chance of success. Serious head off-track -errors will be detected. - -FC-10 and FC-20 controllers ---------------------------- -Ftape now supports both the old CMS FC-10 and the newer FC-20 -controllers. -Because the operation of these cards is still undocumented, -thus far they will only work with the default settings (See -Makefile). Any feed-back on how to use them with other settings -will be welcome ! -Compilation will fail if one changes the settings to illegal -values. - -Kernels and compilers ---------------------- -Ftape is currently being developed using the 2.5.8 compiler. -The older 2.4.5 probably works too (Set option in Makefile!). -I have no experience with any later compilers nor Elf support. -Any information on this is welcome. -The latest kernel I have tested ftape with is 1.2.6. - -Compression ------------ -An impressive collection of changes for ftape including -on-the-fly compression is still lying on my desk. -If 2.03 proves to be reliable I might start integrating these -but as usual, I'm short in time :-( - -Formatting ----------- -There is still no way to format tapes under Linux. As far as -I know all attempts to write such a program have died now. -Since formatted tapes are rather common now, I think all we -need is a utility that writes a worst case pattern and verifies -that with the drive put in verify mode, reducing margins. -Any takers ? - -Furthermore ------------ -Cleaned up messages. -Prepared to support multiple tape drives on one fdc. -Thanks to all the people who sent bug reports and helped me -improve the driver. Without trying to be complete I'll mention -Gary Anderson (without his accurate reports and unreliable -hardware there wouldn't be a 2.03), Stefan Kneifel (FC-20), -Robert Broughton (FC-20, you were almost there ;-), Bjorn -Ekwall (for the versioned modules and buggy insmod ;-), Peter -Fox, Christopher Oliver, Ralph Whittaker and not the least -Linus Torvalds (for Linux and keeping me busy because of -changes to the kernel ;-) -Thanks to anyone I forgot, for the bug reports, the ftape -bashing and the mental support... - - -That's it for now. Have Fun, - -Bas. - - -===== Release notes for ftape-2.02g, 06/05/95 ===== - -- Added extra test to break read-id loop with signal. -- Changed rewind code to handle negative overshoot for drives - that take very long to start or stop. -- Let use of get/set i/o-regions depend on kernel version. -- Changed code to use a more general test for conditional - compilations depending on kernel version. -- Improved micro-step functionality to go off-track only - while reading (id & data). -- Added failure on tape-not-referenced bit in ftape_command. -- Added FOREVER option to read-wait routine. -- Changed read-id to use shorter timeout causing smaller - rewinds on timeout. -- Made kernel-interface functions static. - - -===== Release notes for ftape-2.02f, 03/05/95 ===== - -- Added support for dual tape drives on my system, extended Configure - script to detect host 'dodo'. -- Log media defect in history if ecc failed and no data was returned. -- Fixed Configure script that was failing for kernel versions with - double digit version or revision numbers. - - -===== Release notes for ftape-2.02e, 01/05/95 ===== - -- Fixed reposition loop at logical eot (failing read_id). -- Fixed 34 segment offset when rewinding. -- Added fast seek capability for more than 255 segments. -- Fixed wrong busy result from ftape_command causing reverse - seek to fail. -- Added breakout from infinite rewind loop (if something fails). - - -===== Release notes for ftape-2.02d, 30/04/95 ===== - -- Improved abortion on signals: Interrupt will make a graceful - exit, Kill will be less nice and should be used if everything - else fails. -- Included check for tape-head off track. -- Implemented exit from tape-start loop. -- Added kernel io-port registration. -- Implemented skip of failing segment (ENODATA) on ecc failure. - This allows afio and tar to continue when the tape is damaged. -- Made distinction between drive names with different codes. - - -===== Release notes for ftape-2.02c, 22/04/95 ===== - -- Fixed too tight command queueing after tape stop/pause command - issued from within interrupt service routine (Showed as timeout - on Acknowledge errors during retries on some systems) -- Tried to fix timeouts when using 425 ft tape because the extended - length doesn't seem to be detected by the hardware. - We now use the format code from the header segment so adjust the - timing after reading the header segment. -- Fixed some messages stating 'unexpected something...' being not - unexpected anymore. -- Started preparations for merge of dynamic buffer allocation and - compression code. -- Changed some debug messages to include relevant segment information - at level 4. -- Included early bail-out when drive offline, preventing a lot of - false messages. -- Moved ftape_parameter_xxx() offsets into function instead of in calls. -- Removed 'weird, drive busy but no data' error when caused by - an error during a read-id. -- Improved 'timeout on acknowledge' diagnostics. -- Moved MODULE option into Configure. -- Reduced code size when no tracing at all was set (Claus Heine). -- No longer log error code 0 (no error) as an error. - - -===== Release notes for ftape-2.02b, 09/04/95 ===== - -- Relaxed timing for status operation and displaying - abnormal results. Hopefully this shows what's going - wrong with the Conner TSM850R drives. -- Created script for configuration, using version number - of kernel source if available, otherwise /proc/version. -- Fixed conditionals in kernel-interface.c. -- Removed unavoidable TRACE output. - - -===== Release notes for ftape-2.02a, 01/04/95 ===== - -- Implemented `new-style' (versioned) modules support for new - kernels. -- Reduced size of module by moving static data to bss. -- Now using version number of kernel source instead of running - kernel for kernel versions >= 1.1.82 -- Added feedback on drive speeds to vendor information. -- Included fixed insmod sources to distribution (Let's hope - the modules distribution get fixed soon :-/). - -Note that I haven't yet implemented any of the code extension I -received. I hope to find some time to do this soon. - - -===== Release notes for ftape-2.02, 15/01/95 ===== - - -- Fixed failing repositioning when overshoot was incremented. -- Fixed rate selection: Because of a deficiency in the QIC-117 - specification one cannot distinguish between a not implemented - and a failing command. Therefor we now try to find out if the - drive does support this command before usage. -- Fixed error retry using wrong offset in fdc-isr. -- Improved retry code to retry only once on a single no-data - error in a segment. -- Validate sector number extracted from eof mark because an - invalid file mark (due to ???) could cause kernel panic. -- Split ftape-io.c into ftape-io.c and ftape-ctl.c files. -- Corrected too high media error count after writing to - a bad tape. -- Added #include again because old kernel versions - need it. -- Fixed fdc not being disabled when open failed because no tape - drive was found. -- Fixed problem with soft error in sector 32 (shift operator with - shiftcount 32 is not defined). - - -===== Release notes for ftape-2.01, 08/01/95 ===== - - -- Removed TESTING setting from distributed Makefile. -- Fixed `mt asf' failure: Rewind was deferred to close which - overruled the fsf ioctl. -- Prevented non-interruptible commands being interrupted. -- Added missing timeout.pause setting. -- Maximum tape speed read from drive type information table. - If the information is not in the table (0) the drive will - determine the speed itself and put a message in the logfile. - This information should then be added to the table in the - vendors.h file (and reported to me). -- Added call to ftape_init_drive after soft reset for those - (antique) drives that don't do an implicit seek_load_point - after a reset or power up. -- Don't try to set data rate if reset failed. -- Prevent update of seek variables when starting from the - beginning or the end of the tape. -- Fixed wrong adjustment of overshoot in seek_forward(). -- Added sync to Makefile (again). -- Added code to diagnose timer problems (calibr.c). -- Replaced time differences by timediff calls. -- Removed reference to do_floppy from object for recent kernels. -- Fixed wrong display of 'failing dma controller' message. -- Removed various no longer used #include statements. -- Added max. tape speed value to vendor-struct. -- Changed ftape-command to check pre-conditions and wait - if needed. -- Further updated qic117.h to rev G. -- Combined command name table and restrictions table to one. - Extended this table with some new fields. -- Increased timeout on Ack timer value and included code to - report out of spec behaviour. -- Increased rewind timeout margin to calculated + 20%. -- Improved data rate selection so it won't fail on some - older (pre standard) drives. -- Changed initialisation code so drive will be rewound if the - driver is reloaded and the tape is not at bot. -- Moved some of the flush operations from close to the ioctls. -- Added exit code value to failing verify area message. -- Loop until tape halted in smart-stop. -- Fast seek handled specially if located at bot or eot. -- Being more conservative on overshoot value. - - -===== Release notes for ftape-2.00, 31/12/94 ===== - - The Install-guide is completely rewritten and now also includes -some information on how to use the driver. If you're either new -to ftape or new to Unix tape devices make sure to read it ! - - If you own a pci system and experience problems with the -ftape driver make sure to read the README.PCI file. It contains -some hints on how to fix your hardware. - - For anybody who hasn't noticed: The version number of the -driver has been incremented (The latest released version has -been version 1.14d). - This has been done for two major reasons: - - o A new (better) error recovery scheme is implemented. - o Support for new drive types has been added. - - All these improvements/changes will probably include a couple -of new (and old?) bugs. If you encounter any problems that you think -I'm not yet aware of, feel free to send a report to . - I recommend keeping a version of ftape-1.14d available, just -in case ;-) - - This version should work with all kernel versions from 1.0.9 up -to 1.1.72 (and probably earlier and later versions too). - - -Major new features: - -- Better handling of tapes with defects: When a sector repeatedly - (SOFT_RETRIES in ftape.h) cannot be written to or read from it is - marked as an hard error and gets skipped. - The error correction code can handle up to three of these hard - errors provided there are no other errors in that segment (32 Kb). - -- Allows writing to tapes with defects (although the risk of loosing - data increases !) - Look for the media-defects entry printed with the statistics when - the tape is closed. A non-zero value here shows a bad tape. - [the actual count is wrong (too high), this is a known bug]. - -- Use of backup header segment if first one is failing. - -- Support for extended length tapes with QIC-80: both 425 and 1100 ft. - 0.25 inch tapes are now recognized and handled. - -- Support for new QIC-80 drives with 8 mm `wide' tapes (e.g. Conner - TSM 420). - -- Support for new QIC-3010 and QIC-3020 drives (experimental) with - both 0.25 inch and 8 mm tapes. - -Some minor features were added, a couple of small bugs were fixed and -probably some new ones introduced ;-). - -[lseek() didn't make it into this version] - -Have fun, - -Bas. ----- - LocalWords: ftape MCONFIG mt VFS zftape resp sftape proc subdir MTIOCVOLINFO - LocalWords: MTIOCGETSIZE BOT EOD MTBSF zft kerneld modprobe kdtime contrib TR - LocalWords: MTSETBLK afio uninstall texi www EIO QIC init sft eof aka dma GB - LocalWords: SIGKILL MTIOCFTCMD mmap Iomega FDC fdc io gnumt mtio fc asm inb - LocalWords: outb ft qic frontend TeXinfo irq mach MODVERSIONS CONFIG html dvi - LocalWords: usr doc SMP Mb Dunno FIXME vtblc perl listtape volinfo fsf MTWEOF - LocalWords: amanda degaussed ComByte DoublePlay whraven njackn com MTIOC vtbl - LocalWords: GETBLKSZ MAKEDEV zftape's linux dif CVS Revison cp MTREW MTOFFL - LocalWords: MTFSF BSF Marcin Dalecki GCC Config cpio swapout Kai Harrekilde - LocalWords: Pederson khp dolphinics Justus claus momo rwth aachen Laarhoven diff --git a/drivers/char/ftape/compressor/Makefile b/drivers/char/ftape/compressor/Makefile deleted file mode 100644 index 1fbd6c4019db..000000000000 --- a/drivers/char/ftape/compressor/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (C) 1997 Claus-Justus Heine. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to -# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -# -# $Source: /homes/cvs/ftape-stacked/ftape/compressor/Makefile,v $ -# $Revision: 1.1 $ -# $Date: 1997/10/05 19:12:28 $ -# -# Makefile for the optional compressor for th zftape VFS -# interface to the QIC-40/80/3010/3020 floppy-tape driver for -# Linux. -# - -obj-$(CONFIG_ZFT_COMPRESSOR) += zft-compressor.o - -zft-compressor-objs := zftape-compress.o lzrw3.o - -CFLAGS_lzrw3.o := -O6 -funroll-all-loops diff --git a/drivers/char/ftape/compressor/lzrw3.c b/drivers/char/ftape/compressor/lzrw3.c deleted file mode 100644 index a032a0ee2a99..000000000000 --- a/drivers/char/ftape/compressor/lzrw3.c +++ /dev/null @@ -1,743 +0,0 @@ -/* - * $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.c,v $ - * $Revision: 1.1 $ - * $Date: 1997/10/05 19:12:29 $ - * - * Implementation of Ross Williams lzrw3 algorithm. Adaption for zftape. - * - */ - -#include "../compressor/lzrw3.h" /* Defines single exported function "compress". */ - -/******************************************************************************/ -/* */ -/* LZRW3.C */ -/* */ -/******************************************************************************/ -/* */ -/* Author : Ross Williams. */ -/* Date : 30-Jun-1991. */ -/* Release : 1. */ -/* */ -/******************************************************************************/ -/* */ -/* This file contains an implementation of the LZRW3 data compression */ -/* algorithm in C. */ -/* */ -/* The algorithm is a general purpose compression algorithm that runs fast */ -/* and gives reasonable compression. The algorithm is a member of the Lempel */ -/* Ziv family of algorithms and bases its compression on the presence in the */ -/* data of repeated substrings. */ -/* */ -/* This algorithm is unpatented and the code is public domain. As the */ -/* algorithm is based on the LZ77 class of algorithms, it is unlikely to be */ -/* the subject of a patent challenge. */ -/* */ -/* Unlike the LZRW1 and LZRW1-A algorithms, the LZRW3 algorithm is */ -/* deterministic and is guaranteed to yield the same compressed */ -/* representation for a given file each time it is run. */ -/* */ -/* The LZRW3 algorithm was originally designed and implemented */ -/* by Ross Williams on 31-Dec-1990. */ -/* */ -/* Here are the results of applying this code, compiled under THINK C 4.0 */ -/* and running on a Mac-SE (8MHz 68000), to the standard calgary corpus. */ -/* */ -/* +----------------------------------------------------------------+ */ -/* | DATA COMPRESSION TEST | */ -/* | ===================== | */ -/* | Time of run : Sun 30-Jun-1991 09:31PM | */ -/* | Timing accuracy : One part in 100 | */ -/* | Context length : 262144 bytes (= 256.0000K) | */ -/* | Test suite : Calgary Corpus Suite | */ -/* | Files in suite : 14 | */ -/* | Algorithm : LZRW3 | */ -/* | Note: All averages are calculated from the un-rounded values. | */ -/* +----------------------------------------------------------------+ */ -/* | File Name Length CxB ComLen %Remn Bits Com K/s Dec K/s | */ -/* | ---------- ------ --- ------ ----- ---- ------- ------- | */ -/* | rpus:Bib.D 111261 1 55033 49.5 3.96 19.46 32.27 | */ -/* | us:Book1.D 768771 3 467962 60.9 4.87 17.03 31.07 | */ -/* | us:Book2.D 610856 3 317102 51.9 4.15 19.39 34.15 | */ -/* | rpus:Geo.D 102400 1 82424 80.5 6.44 11.65 18.18 | */ -/* | pus:News.D 377109 2 205670 54.5 4.36 17.14 27.47 | */ -/* | pus:Obj1.D 21504 1 13027 60.6 4.85 13.40 18.95 | */ -/* | pus:Obj2.D 246814 1 116286 47.1 3.77 19.31 30.10 | */ -/* | s:Paper1.D 53161 1 27522 51.8 4.14 18.60 31.15 | */ -/* | s:Paper2.D 82199 1 45160 54.9 4.40 18.45 32.84 | */ -/* | rpus:Pic.D 513216 2 122388 23.8 1.91 35.29 51.05 | */ -/* | us:Progc.D 39611 1 19669 49.7 3.97 18.87 30.64 | */ -/* | us:Progl.D 71646 1 28247 39.4 3.15 24.34 40.66 | */ -/* | us:Progp.D 49379 1 19377 39.2 3.14 23.91 39.23 | */ -/* | us:Trans.D 93695 1 33481 35.7 2.86 25.48 40.37 | */ -/* +----------------------------------------------------------------+ */ -/* | Average 224401 1 110953 50.0 4.00 20.17 32.72 | */ -/* +----------------------------------------------------------------+ */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ - -/* The following structure is returned by the "compress" function below when */ -/* the user asks the function to return identifying information. */ -/* The most important field in the record is the working memory field which */ -/* tells the calling program how much working memory should be passed to */ -/* "compress" when it is called to perform a compression or decompression. */ -/* LZRW3 uses the same amount of memory during compression and decompression. */ -/* For more information on this structure see "compress.h". */ - -#define U(X) ((ULONG) X) -#define SIZE_P_BYTE (U(sizeof(UBYTE *))) -#define SIZE_WORD (U(sizeof(UWORD ))) -#define ALIGNMENT_FUDGE (U(16)) -#define MEM_REQ ( U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE ) - -static struct compress_identity identity = -{ - U(0x032DDEA8), /* Algorithm identification number. */ - MEM_REQ, /* Working memory (bytes) required. */ - "LZRW3", /* Name of algorithm. */ - "1.0", /* Version number of algorithm. */ - "31-Dec-1990", /* Date of algorithm. */ - "Public Domain", /* Copyright notice. */ - "Ross N. Williams", /* Author of algorithm. */ - "Renaissance Software", /* Affiliation of author. */ - "Public Domain" /* Vendor of algorithm. */ -}; - -LOCAL void compress_compress (UBYTE *,UBYTE *,ULONG,UBYTE *, LONG *); -LOCAL void compress_decompress(UBYTE *,UBYTE *,LONG, UBYTE *, ULONG *); - -/******************************************************************************/ - -/* This function is the only function exported by this module. */ -/* Depending on its first parameter, the function can be requested to */ -/* compress a block of memory, decompress a block of memory, or to identify */ -/* itself. For more information, see the specification file "compress.h". */ - -EXPORT void lzrw3_compress( - UWORD action, /* Action to be performed. */ - UBYTE *wrk_mem, /* Address of working memory we can use.*/ - UBYTE *src_adr, /* Address of input data. */ - LONG src_len, /* Length of input data. */ - UBYTE *dst_adr, /* Address to put output data. */ - void *p_dst_len /* Address of longword for length of output data.*/ -) -{ - switch (action) - { - case COMPRESS_ACTION_IDENTITY: - *((struct compress_identity **)p_dst_len)= &identity; - break; - case COMPRESS_ACTION_COMPRESS: - compress_compress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len); - break; - case COMPRESS_ACTION_DECOMPRESS: - compress_decompress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len); - break; - } -} - -/******************************************************************************/ -/* */ -/* BRIEF DESCRIPTION OF THE LZRW3 ALGORITHM */ -/* ======================================== */ -/* The LZRW3 algorithm is identical to the LZRW1-A algorithm except that */ -/* instead of transmitting history offsets, it transmits hash table indexes. */ -/* In order to decode the indexes, the decompressor must maintain an */ -/* identical hash table. Copy items are straightforward:when the decompressor */ -/* receives a copy item, it simply looks up the hash table to translate the */ -/* index into a pointer into the data already decompressed. To update the */ -/* hash table, it replaces the same table entry with a pointer to the start */ -/* of the newly decoded phrase. The tricky part is with literal items, for at */ -/* the time that the decompressor receives a literal item the decompressor */ -/* does not have the three bytes in the Ziv (that the compressor has) to */ -/* perform the three-byte hash. To solve this problem, in LZRW3, both the */ -/* compressor and decompressor are wired up so that they "buffer" these */ -/* literals and update their hash tables only when three bytes are available. */ -/* This makes the maximum buffering 2 bytes. */ -/* */ -/* Replacement of offsets by hash table indexes yields a few percent extra */ -/* compression at the cost of some speed. LZRW3 is slower than LZRW1, LZRW1-A */ -/* and LZRW2, but yields better compression. */ -/* */ -/* Extra compression could be obtained by using a hash table of depth two. */ -/* However, increasing the depth above one incurs a significant decrease in */ -/* compression speed which was not considered worthwhile. Another reason for */ -/* keeping the depth down to one was to allow easy comparison with the */ -/* LZRW1-A and LZRW2 algorithms so as to demonstrate the exact effect of the */ -/* use of direct hash indexes. */ -/* */ -/* +---+ */ -/* |___|4095 */ -/* |___| */ -/* +---------------------*_|<---+ /----+---\ */ -/* | |___| +---|Hash | */ -/* | |___| |Function| */ -/* | |___| \--------/ */ -/* | |___|0 ^ */ -/* | +---+ | */ -/* | Hash +-----+ */ -/* | Table | */ -/* | --- */ -/* v ^^^ */ -/* +-------------------------------------|----------------+ */ -/* |||||||||||||||||||||||||||||||||||||||||||||||||||||||| */ -/* +-------------------------------------|----------------+ */ -/* | |1......18| | */ -/* |<------- Lempel=History ------------>|<--Ziv-->| | */ -/* | (=bytes already processed) |<-Still to go-->| */ -/* |<-------------------- INPUT BLOCK ------------------->| */ -/* */ -/* The diagram above for LZRW3 looks almost identical to the diagram for */ -/* LZRW1. The difference is that in LZRW3, the compressor transmits hash */ -/* table indices instead of Lempel offsets. For this to work, the */ -/* decompressor must maintain a hash table as well as the compressor and both */ -/* compressor and decompressor must "buffer" literals, as the decompressor */ -/* cannot hash phrases commencing with a literal until another two bytes have */ -/* arrived. */ -/* */ -/* LZRW3 Algorithm Execution Summary */ -/* --------------------------------- */ -/* 1. Hash the first three bytes of the Ziv to yield a hash table index h. */ -/* 2. Look up the hash table yielding history pointer p. */ -/* 3. Match where p points with the Ziv. If there is a match of three or */ -/* more bytes, code those bytes (in the Ziv) as a copy item, otherwise */ -/* code the next byte in the Ziv as a literal item. */ -/* 4. Update the hash table as possible subject to the constraint that only */ -/* phrases commencing three bytes back from the Ziv can be hashed and */ -/* entered into the hash table. (This enables the decompressor to keep */ -/* pace). See the description and code for more details. */ -/* */ -/******************************************************************************/ -/* */ -/* DEFINITION OF COMPRESSED FILE FORMAT */ -/* ==================================== */ -/* * A compressed file consists of a COPY FLAG followed by a REMAINDER. */ -/* * The copy flag CF uses up four bytes with the first byte being the */ -/* least significant. */ -/* * If CF=1, then the compressed file represents the remainder of the file */ -/* exactly. Otherwise CF=0 and the remainder of the file consists of zero */ -/* or more GROUPS, each of which represents one or more bytes. */ -/* * Each group consists of two bytes of CONTROL information followed by */ -/* sixteen ITEMs except for the last group which can contain from one */ -/* to sixteen items. */ -/* * An item can be either a LITERAL item or a COPY item. */ -/* * Each item corresponds to a bit in the control bytes. */ -/* * The first control byte corresponds to the first 8 items in the group */ -/* with bit 0 corresponding to the first item in the group and bit 7 to */ -/* the eighth item in the group. */ -/* * The second control byte corresponds to the second 8 items in the group */ -/* with bit 0 corresponding to the ninth item in the group and bit 7 to */ -/* the sixteenth item in the group. */ -/* * A zero bit in a control word means that the corresponding item is a */ -/* literal item. A one bit corresponds to a copy item. */ -/* * A literal item consists of a single byte which represents itself. */ -/* * A copy item consists of two bytes that represent from 3 to 18 bytes. */ -/* * The first byte in a copy item will be denoted C1. */ -/* * The second byte in a copy item will be denoted C2. */ -/* * Bits will be selected using square brackets. */ -/* For example: C1[0..3] is the low nibble of the first control byte. */ -/* of copy item C1. */ -/* * The LENGTH of a copy item is defined to be C1[0..3]+3 which is a number */ -/* in the range [3,18]. */ -/* * The INDEX of a copy item is defined to be C1[4..7]*256+C2[0..8] which */ -/* is a number in the range [0,4095]. */ -/* * A copy item represents the sequence of bytes */ -/* text[POS-OFFSET..POS-OFFSET+LENGTH-1] where */ -/* text is the entire text of the uncompressed string. */ -/* POS is the index in the text of the character following the */ -/* string represented by all the items preceeding the item */ -/* being defined. */ -/* OFFSET is obtained from INDEX by looking up the hash table. */ -/* */ -/******************************************************************************/ - -/* The following #define defines the length of the copy flag that appears at */ -/* the start of the compressed file. The value of four bytes was chosen */ -/* because the fast_copy routine on my Macintosh runs faster if the source */ -/* and destination blocks are relatively longword aligned. */ -/* The actual flag data appears in the first byte. The rest are zeroed so as */ -/* to normalize the compressed representation (i.e. not non-deterministic). */ -#define FLAG_BYTES 4 - -/* The following #defines define the meaning of the values of the copy */ -/* flag at the start of the compressed file. */ -#define FLAG_COMPRESS 0 /* Signals that output was result of compression. */ -#define FLAG_COPY 1 /* Signals that output was simply copied over. */ - -/* The 68000 microprocessor (on which this algorithm was originally developed */ -/* is fussy about non-aligned arrays of words. To avoid these problems the */ -/* following macro can be used to "waste" from 0 to 3 bytes so as to align */ -/* the argument pointer. */ -#define ULONG_ALIGN_UP(X) ((((ULONG)X)+sizeof(ULONG)-1)&~(sizeof(ULONG)-1)) - - -/* The following constant defines the maximum length of an uncompressed item. */ -/* This definition must not be changed; its value is hardwired into the code. */ -/* The longest number of bytes that can be spanned by a single item is 18 */ -/* for the longest copy item. */ -#define MAX_RAW_ITEM (18) - -/* The following constant defines the maximum length of an uncompressed group.*/ -/* This definition must not be changed; its value is hardwired into the code. */ -/* A group contains at most 16 items which explains this definition. */ -#define MAX_RAW_GROUP (16*MAX_RAW_ITEM) - -/* The following constant defines the maximum length of a compressed group. */ -/* This definition must not be changed; its value is hardwired into the code. */ -/* A compressed group consists of two control bytes followed by up to 16 */ -/* compressed items each of which can have a maximum length of two bytes. */ -#define MAX_CMP_GROUP (2+16*2) - -/* The following constant defines the number of entries in the hash table. */ -/* This definition must not be changed; its value is hardwired into the code. */ -#define HASH_TABLE_LENGTH (4096) - -/* LZRW3, unlike LZRW1(-A), must initialize its hash table so as to enable */ -/* the compressor and decompressor to stay in step maintaining identical hash */ -/* tables. In an early version of the algorithm, the tables were simply */ -/* initialized to zero and a check for zero was included just before the */ -/* matching code. However, this test costs time. A better solution is to */ -/* initialize all the entries in the hash table to point to a constant */ -/* string. The decompressor does the same. This solution requires no extra */ -/* test. The contents of the string do not matter so long as the string is */ -/* the same for the compressor and decompressor and contains at least */ -/* MAX_RAW_ITEM bytes. I chose consecutive decimal digits because they do not */ -/* have white space problems (e.g. there is no chance that the compiler will */ -/* replace more than one space by a TAB) and because they make the length of */ -/* the string obvious by inspection. */ -#define START_STRING_18 ((UBYTE *) "123456789012345678") - -/* In this algorithm, hash values have to be calculated at more than one */ -/* point. The following macro neatens the code up for this. */ -#define HASH(PTR) \ - (((40543*(((*(PTR))<<8)^((*((PTR)+1))<<4)^(*((PTR)+2))))>>4) & 0xFFF) - -/******************************************************************************/ - -/* Input : Hand over the required amount of working memory in p_wrk_mem. */ -/* Input : Specify input block using p_src_first and src_len. */ -/* Input : Point p_dst_first to the start of the output zone (OZ). */ -/* Input : Point p_dst_len to a ULONG to receive the output length. */ -/* Input : Input block and output zone must not overlap. */ -/* Output : Length of output block written to *p_dst_len. */ -/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. May */ -/* Output : write in OZ=Mem[p_dst_first..p_dst_first+src_len+MAX_CMP_GROUP-1].*/ -/* Output : Upon completion guaranteed *p_dst_len<=src_len+FLAG_BYTES. */ -LOCAL void compress_compress(UBYTE *p_wrk_mem, - UBYTE *p_src_first, ULONG src_len, - UBYTE *p_dst_first, LONG *p_dst_len) -{ - /* p_src and p_dst step through the source and destination blocks. */ - register UBYTE *p_src = p_src_first; - register UBYTE *p_dst = p_dst_first; - - /* The following variables are never modified and are used in the */ - /* calculations that determine when the main loop terminates. */ - UBYTE *p_src_post = p_src_first+src_len; - UBYTE *p_dst_post = p_dst_first+src_len; - UBYTE *p_src_max1 = p_src_first+src_len-MAX_RAW_ITEM; - UBYTE *p_src_max16 = p_src_first+src_len-MAX_RAW_ITEM*16; - - /* The variables 'p_control' and 'control' are used to buffer control bits. */ - /* Before each group is processed, the next two bytes of the output block */ - /* are set aside for the control word for the group about to be processed. */ - /* 'p_control' is set to point to the first byte of that word. Meanwhile, */ - /* 'control' buffers the control bits being generated during the processing */ - /* of the group. Instead of having a counter to keep track of how many items */ - /* have been processed (=the number of bits in the control word), at the */ - /* start of each group, the top word of 'control' is filled with 1 bits. */ - /* As 'control' is shifted for each item, the 1 bits in the top word are */ - /* absorbed or destroyed. When they all run out (i.e. when the top word is */ - /* all zero bits, we know that we are at the end of a group. */ -# define TOPWORD 0xFFFF0000 - UBYTE *p_control; - register ULONG control=TOPWORD; - - /* THe variable 'hash' always points to the first element of the hash table. */ - UBYTE **hash= (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem); - - /* The following two variables represent the literal buffer. p_h1 points to */ - /* the hash table entry corresponding to the youngest literal. p_h2 points */ - /* to the hash table entry corresponding to the second youngest literal. */ - /* Note: p_h1=0=>p_h2=0 because zero values denote absence of a pending */ - /* literal. The variables are initialized to zero meaning an empty "buffer". */ - UBYTE **p_h1=NULL; - UBYTE **p_h2=NULL; - - /* To start, we write the flag bytes. Being optimistic, we set the flag to */ - /* FLAG_COMPRESS. The remaining flag bytes are zeroed so as to keep the */ - /* algorithm deterministic. */ - *p_dst++=FLAG_COMPRESS; - {UWORD i; for (i=2;i<=FLAG_BYTES;i++) *p_dst++=0;} - - /* Reserve the first word of output as the control word for the first group. */ - /* Note: This is undone at the end if the input block is empty. */ - p_control=p_dst; p_dst+=2; - - /* Initialize all elements of the hash table to point to a constant string. */ - /* Use of an unrolled loop speeds this up considerably. */ - {UWORD i; UBYTE **p_h=hash; -# define ZH *p_h++=START_STRING_18 - for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ - {ZH;ZH;ZH;ZH; - ZH;ZH;ZH;ZH; - ZH;ZH;ZH;ZH; - ZH;ZH;ZH;ZH;} - } - - /* The main loop processes either 1 or 16 items per iteration. As its */ - /* termination logic is complicated, I have opted for an infinite loop */ - /* structure containing 'break' and 'goto' statements. */ - while (TRUE) - {/* Begin main processing loop. */ - - /* Note: All the variables here except unroll should be defined within */ - /* the inner loop. Unfortunately the loop hasn't got a block. */ - register UBYTE *p; /* Scans through targ phrase during matching. */ - register UBYTE *p_ziv= NULL ; /* Points to first byte of current Ziv. */ - register UWORD unroll; /* Loop counter for unrolled inner loop. */ - register UWORD index; /* Index of current hash table entry. */ - register UBYTE **p_h0 = NULL ; /* Pointer to current hash table entry. */ - - /* Test for overrun and jump to overrun code if necessary. */ - if (p_dst>p_dst_post) - goto overrun; - - /* The following cascade of if statements efficiently catches and deals */ - /* with varying degrees of closeness to the end of the input block. */ - /* When we get very close to the end, we stop updating the table and */ - /* code the remaining bytes as literals. This makes the code simpler. */ - unroll=16; - if (p_src>p_src_max16) - { - unroll=1; - if (p_src>p_src_max1) - { - if (p_src==p_src_post) - break; - else - goto literal; - } - } - - /* This inner unrolled loop processes 'unroll' (whose value is either 1 */ - /* or 16) items. I have chosen to implement this loop with labels and */ - /* gotos to heighten the ease with which the loop may be implemented with */ - /* a single decrement and branch instruction in assembly language and */ - /* also because the labels act as highly readable place markers. */ - /* (Also because we jump into the loop for endgame literals (see above)). */ - - begin_unrolled_loop: - - /* To process the next phrase, we hash the next three bytes and use */ - /* the resultant hash table index to look up the hash table. A pointer */ - /* to the entry is stored in p_h0 so as to avoid an array lookup. The */ - /* hash table entry *p_h0 is looked up yielding a pointer p to a */ - /* potential match of the Ziv in the history. */ - index=HASH(p_src); - p_h0=&hash[index]; - p=*p_h0; - - /* Having looked up the candidate position, we are in a position to */ - /* attempt a match. The match loop has been unrolled using the PS */ - /* macro so that failure within the first three bytes automatically */ - /* results in the literal branch being taken. The coding is simple. */ - /* p_ziv saves p_src so we can let p_src wander. */ -# define PS *p++!=*p_src++ - p_ziv=p_src; - if (PS || PS || PS) - { - /* Literal. */ - - /* Code the literal byte as itself and a zero control bit. */ - p_src=p_ziv; literal: *p_dst++=*p_src++; control&=0xFFFEFFFF; - - /* We have just coded a literal. If we had two pending ones, that */ - /* makes three and we can update the hash table. */ - if (p_h2!=0) - {*p_h2=p_ziv-2;} - - /* In any case, rotate the hash table pointers for next time. */ - p_h2=p_h1; p_h1=p_h0; - - } - else - { - /* Copy */ - - /* Match up to 15 remaining bytes using an unrolled loop and code. */ -#if 0 - PS || PS || PS || PS || PS || PS || PS || PS || - PS || PS || PS || PS || PS || PS || PS || p_src++; -#else - if ( - !( PS || PS || PS || PS || PS || PS || PS || PS || - PS || PS || PS || PS || PS || PS || PS ) - ) p_src++; -#endif - *p_dst++=((index&0xF00)>>4)|(--p_src-p_ziv-3); - *p_dst++=index&0xFF; - - /* As we have just coded three bytes, we are now in a position to */ - /* update the hash table with the literal bytes that were pending */ - /* upon the arrival of extra context bytes. */ - if (p_h1!=0) - { - if (p_h2) - {*p_h2=p_ziv-2; p_h2=NULL;} - *p_h1=p_ziv-1; p_h1=NULL; - } - - /* In any case, we can update the hash table based on the current */ - /* position as we just coded at least three bytes in a copy items. */ - *p_h0=p_ziv; - - } - control>>=1; - - /* This loop is all set up for a decrement and jump instruction! */ -#ifndef linux -` end_unrolled_loop: if (--unroll) goto begin_unrolled_loop; -#else - /* end_unrolled_loop: */ if (--unroll) goto begin_unrolled_loop; -#endif - - /* At this point it will nearly always be the end of a group in which */ - /* case, we have to do some control-word processing. However, near the */ - /* end of the input block, the inner unrolled loop is only executed once. */ - /* This necessitates the 'if' test. */ - if ((control&TOPWORD)==0) - { - /* Write the control word to the place we saved for it in the output. */ - *p_control++= control &0xFF; - *p_control = (control>>8) &0xFF; - - /* Reserve the next word in the output block for the control word */ - /* for the group about to be processed. */ - p_control=p_dst; p_dst+=2; - - /* Reset the control bits buffer. */ - control=TOPWORD; - } - - } /* End main processing loop. */ - - /* After the main processing loop has executed, all the input bytes have */ - /* been processed. However, the control word has still to be written to the */ - /* word reserved for it in the output at the start of the most recent group. */ - /* Before writing, the control word has to be shifted so that all the bits */ - /* are in the right place. The "empty" bit positions are filled with 1s */ - /* which partially fill the top word. */ - while(control&TOPWORD) control>>=1; - *p_control++= control &0xFF; - *p_control++=(control>>8) &0xFF; - - /* If the last group contained no items, delete the control word too. */ - if (p_control==p_dst) p_dst-=2; - - /* Write the length of the output block to the dst_len parameter and return. */ - *p_dst_len=p_dst-p_dst_first; - return; - - /* Jump here as soon as an overrun is detected. An overrun is defined to */ - /* have occurred if p_dst>p_dst_first+src_len. That is, the moment the */ - /* length of the output written so far exceeds the length of the input block.*/ - /* The algorithm checks for overruns at least at the end of each group */ - /* which means that the maximum overrun is MAX_CMP_GROUP bytes. */ - /* Once an overrun occurs, the only thing to do is to set the copy flag and */ - /* copy the input over. */ - overrun: -#if 0 - *p_dst_first=FLAG_COPY; - fast_copy(p_src_first,p_dst_first+FLAG_BYTES,src_len); - *p_dst_len=src_len+FLAG_BYTES; -#else - fast_copy(p_src_first,p_dst_first,src_len); - *p_dst_len= -src_len; /* return a negative number to indicate uncompressed data */ -#endif -} - -/******************************************************************************/ - -/* Input : Hand over the required amount of working memory in p_wrk_mem. */ -/* Input : Specify input block using p_src_first and src_len. */ -/* Input : Point p_dst_first to the start of the output zone. */ -/* Input : Point p_dst_len to a ULONG to receive the output length. */ -/* Input : Input block and output zone must not overlap. User knows */ -/* Input : upperbound on output block length from earlier compression. */ -/* Input : In any case, maximum expansion possible is nine times. */ -/* Output : Length of output block written to *p_dst_len. */ -/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */ -/* Output : Writes only in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */ -LOCAL void compress_decompress( UBYTE *p_wrk_mem, - UBYTE *p_src_first, LONG src_len, - UBYTE *p_dst_first, ULONG *p_dst_len) -{ - /* Byte pointers p_src and p_dst scan through the input and output blocks. */ - register UBYTE *p_src = p_src_first+FLAG_BYTES; - register UBYTE *p_dst = p_dst_first; - /* we need to avoid a SEGV when trying to uncompress corrupt data */ - register UBYTE *p_dst_post = p_dst_first + *p_dst_len; - - /* The following two variables are never modified and are used to control */ - /* the main loop. */ - UBYTE *p_src_post = p_src_first+src_len; - UBYTE *p_src_max16 = p_src_first+src_len-(MAX_CMP_GROUP-2); - - /* The hash table is the only resident of the working memory. The hash table */ - /* contains HASH_TABLE_LENGTH=4096 pointers to positions in the history. To */ - /* keep Macintoshes happy, it is longword aligned. */ - UBYTE **hash = (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem); - - /* The variable 'control' is used to buffer the control bits which appear in */ - /* groups of 16 bits (control words) at the start of each compressed group. */ - /* When each group is read, bit 16 of the register is set to one. Whenever */ - /* a new bit is needed, the register is shifted right. When the value of the */ - /* register becomes 1, we know that we have reached the end of a group. */ - /* Initializing the register to 1 thus instructs the code to follow that it */ - /* should read a new control word immediately. */ - register ULONG control=1; - - /* The value of 'literals' is always in the range 0..3. It is the number of */ - /* consecutive literal items just seen. We have to record this number so as */ - /* to know when to update the hash table. When literals gets to 3, there */ - /* have been three consecutive literals and we can update at the position of */ - /* the oldest of the three. */ - register UWORD literals=0; - - /* Check the leading copy flag to see if the compressor chose to use a copy */ - /* operation instead of a compression operation. If a copy operation was */ - /* used, then all we need to do is copy the data over, set the output length */ - /* and return. */ -#if 0 - if (*p_src_first==FLAG_COPY) - { - fast_copy(p_src_first+FLAG_BYTES,p_dst_first,src_len-FLAG_BYTES); - *p_dst_len=src_len-FLAG_BYTES; - return; - } -#else - if ( src_len < 0 ) - { - fast_copy(p_src_first,p_dst_first,-src_len ); - *p_dst_len = (ULONG)-src_len; - return; - } -#endif - - /* Initialize all elements of the hash table to point to a constant string. */ - /* Use of an unrolled loop speeds this up considerably. */ - {UWORD i; UBYTE **p_h=hash; -# define ZJ *p_h++=START_STRING_18 - for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ - {ZJ;ZJ;ZJ;ZJ; - ZJ;ZJ;ZJ;ZJ; - ZJ;ZJ;ZJ;ZJ; - ZJ;ZJ;ZJ;ZJ;} - } - - /* The outer loop processes either 1 or 16 items per iteration depending on */ - /* how close p_src is to the end of the input block. */ - while (p_src!=p_src_post) - {/* Start of outer loop */ - - register UWORD unroll; /* Counts unrolled loop executions. */ - - /* When 'control' has the value 1, it means that the 16 buffered control */ - /* bits that were read in at the start of the current group have all been */ - /* shifted out and that all that is left is the 1 bit that was injected */ - /* into bit 16 at the start of the current group. When we reach the end */ - /* of a group, we have to load a new control word and inject a new 1 bit. */ - if (control==1) - { - control=0x10000|*p_src++; - control|=(*p_src++)<<8; - } - - /* If it is possible that we are within 16 groups from the end of the */ - /* input, execute the unrolled loop only once, else process a whole group */ - /* of 16 items by looping 16 times. */ - unroll= p_src<=p_src_max16 ? 16 : 1; - - /* This inner loop processes one phrase (item) per iteration. */ - while (unroll--) - { /* Begin unrolled inner loop. */ - - /* Process a literal or copy item depending on the next control bit. */ - if (control&1) - { - /* Copy item. */ - - register UBYTE *p; /* Points to place from which to copy. */ - register UWORD lenmt; /* Length of copy item minus three. */ - register UBYTE **p_hte; /* Pointer to current hash table entry.*/ - register UBYTE *p_ziv=p_dst; /* Pointer to start of current Ziv. */ - - /* Read and dismantle the copy word. Work out from where to copy. */ - lenmt=*p_src++; - p_hte=&hash[((lenmt&0xF0)<<4)|*p_src++]; - p=*p_hte; - lenmt&=0xF; - - /* Now perform the copy using a half unrolled loop. */ - *p_dst++=*p++; - *p_dst++=*p++; - *p_dst++=*p++; - while (lenmt--) - *p_dst++=*p++; - - /* Because we have just received 3 or more bytes in a copy item */ - /* (whose bytes we have just installed in the output), we are now */ - /* in a position to flush all the pending literal hashings that had */ - /* been postponed for lack of bytes. */ - if (literals>0) - { - register UBYTE *r=p_ziv-literals; - hash[HASH(r)]=r; - if (literals==2) - {r++; hash[HASH(r)]=r;} - literals=0; - } - - /* In any case, we can immediately update the hash table with the */ - /* current position. We don't need to do a HASH(...) to work out */ - /* where to put the pointer, as the compressor just told us!!! */ - *p_hte=p_ziv; - - } - else - { - /* Literal item. */ - - /* Copy over the literal byte. */ - *p_dst++=*p_src++; - - /* If we now have three literals waiting to be hashed into the hash */ - /* table, we can do one of them now (because there are three). */ - if (++literals == 3) - {register UBYTE *p=p_dst-3; hash[HASH(p)]=p; literals=2;} - } - - /* Shift the control buffer so the next control bit is in bit 0. */ - control>>=1; -#if 1 - if (p_dst > p_dst_post) - { - /* Shit: we tried to decompress corrupt data */ - *p_dst_len = 0; - return; - } -#endif - } /* End unrolled inner loop. */ - - } /* End of outer loop */ - - /* Write the length of the decompressed data before returning. */ - *p_dst_len=p_dst-p_dst_first; -} - -/******************************************************************************/ -/* End of LZRW3.C */ -/******************************************************************************/ diff --git a/drivers/char/ftape/compressor/lzrw3.h b/drivers/char/ftape/compressor/lzrw3.h deleted file mode 100644 index 533feba47526..000000000000 --- a/drivers/char/ftape/compressor/lzrw3.h +++ /dev/null @@ -1,253 +0,0 @@ -#ifndef _LZRW3_H -#define _LZRW3_H -/* - * $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.h,v $ - * $Revision: 1.1 $ - * $Date: 1997/10/05 19:12:30 $ - * - * include files for lzrw3. Only slighty modified from the original - * version. Assembles the three include files compress.h, port.h and - * fastcopy.h from the original lzrw3 package. - * - */ - -#include -#include - -/******************************************************************************/ -/* */ -/* COMPRESS.H */ -/* */ -/******************************************************************************/ -/* */ -/* Author : Ross Williams. */ -/* Date : December 1989. */ -/* */ -/* This header file defines the interface to a set of functions called */ -/* 'compress', each member of which implements a particular data compression */ -/* algorithm. */ -/* */ -/* Normally in C programming, for each .H file, there is a corresponding .C */ -/* file that implements the functions promised in the .H file. */ -/* Here, there are many .C files corresponding to this header file. */ -/* Each comforming implementation file contains a single function */ -/* called 'compress' that implements a single data compression */ -/* algorithm that conforms with the interface specified in this header file. */ -/* Only one algorithm can be linked in at a time in this organization. */ -/* */ -/******************************************************************************/ -/* */ -/* DEFINITION OF FUNCTION COMPRESS */ -/* =============================== */ -/* */ -/* Summary of Function Compress */ -/* ---------------------------- */ -/* The action that 'compress' takes depends on its first argument called */ -/* 'action'. The function provides three actions: */ -/* */ -/* - Return information about the algorithm. */ -/* - Compress a block of memory. */ -/* - Decompress a block of memory. */ -/* */ -/* Parameters */ -/* ---------- */ -/* See the formal C definition later for a description of the parameters. */ -/* */ -/* Constants */ -/* --------- */ -/* COMPRESS_OVERRUN: The constant COMPRESS_OVERRUN defines by how many bytes */ -/* an algorithm is allowed to expand a block during a compression operation. */ -/* */ -/* Although compression algorithms usually compress data, there will always */ -/* be data that a given compressor will expand (this can be proven). */ -/* Fortunately, the degree of expansion can be limited to a single bit, by */ -/* copying over the input data if the data gets bigger during compression. */ -/* To allow for this possibility, the first bit of a compressed */ -/* representation can be used as a flag indicating whether the */ -/* input data was copied over, or truly compressed. In practice, the first */ -/* byte would be used to store this bit so as to maintain byte alignment. */ -/* */ -/* Unfortunately, in general, the only way to tell if an algorithm will */ -/* expand a particular block of data is to run the algorithm on the data. */ -/* If the algorithm does not continuously monitor how many output bytes it */ -/* has written, it might write an output block far larger than the input */ -/* block before realizing that it has done so. */ -/* On the other hand, continuous checks on output length are inefficient. */ -/* */ -/* To cater for all these problems, this interface definition: */ -/* > Allows a compression algorithm to return an output block that is up to */ -/* COMPRESS_OVERRUN bytes longer than the input block. */ -/* > Allows a compression algorithm to write up to COMPRESS_OVERRUN bytes */ -/* more than the length of the input block to the memory of the output */ -/* block regardless of the length of the output block eventually returned. */ -/* This allows an algorithm to overrun the length of the input block in the */ -/* output block by up to COMPRESS_OVERRUN bytes between expansion checks. */ -/* */ -/* The problem does not arise for decompression. */ -/* */ -/* Identity Action */ -/* --------------- */ -/* > action must be COMPRESS_ACTION_IDENTITY. */ -/* > p_dst_len must point to a longword to receive a longword address. */ -/* > The value of the other parameters does not matter. */ -/* > After execution, the longword that p_dst_len points to will be a pointer */ -/* to a structure of type compress_identity. */ -/* Thus, for example, after the call, (*p_dst_len)->memory will return the */ -/* number of bytes of working memory that the algorithm requires to run. */ -/* > The values of the identity structure returned are fixed constant */ -/* attributes of the algorithm and must not vary from call to call. */ -/* */ -/* Common Requirements for Compression and Decompression Actions */ -/* ------------------------------------------------------------- */ -/* > wrk_mem must point to an unused block of memory of a length specified in */ -/* the algorithm's identity block. The identity block can be obtained by */ -/* making a separate call to compress, specifying the identity action. */ -/* > The INPUT BLOCK is defined to be Memory[src_addr,src_addr+src_len-1]. */ -/* > dst_len will be used to denote *p_dst_len. */ -/* > dst_len is not read by compress, only written. */ -/* > The value of dst_len is defined only upon termination. */ -/* > The OUTPUT BLOCK is defined to be Memory[dst_addr,dst_addr+dst_len-1]. */ -/* */ -/* Compression Action */ -/* ------------------ */ -/* > action must be COMPRESS_ACTION_COMPRESS. */ -/* > src_len must be in the range [0,COMPRESS_MAX_ORG]. */ -/* > The OUTPUT ZONE is defined to be */ -/* Memory[dst_addr,dst_addr+src_len-1+COMPRESS_OVERRUN]. */ -/* > The function can modify any part of the output zone regardless of the */ -/* final length of the output block. */ -/* > The input block and the output zone must not overlap. */ -/* > dst_len will be in the range [0,src_len+COMPRESS_OVERRUN]. */ -/* > dst_len will be in the range [0,COMPRESS_MAX_COM] (from prev fact). */ -/* > The output block will consist of a representation of the input block. */ -/* */ -/* Decompression Action */ -/* -------------------- */ -/* > action must be COMPRESS_ACTION_DECOMPRESS. */ -/* > The input block must be the result of an earlier compression operation. */ -/* > If the previous fact is true, the following facts must also be true: */ -/* > src_len will be in the range [0,COMPRESS_MAX_COM]. */ -/* > dst_len will be in the range [0,COMPRESS_MAX_ORG]. */ -/* > The input and output blocks must not overlap. */ -/* > Only the output block is modified. */ -/* > Upon termination, the output block will consist of the bytes contained */ -/* in the input block passed to the earlier compression operation. */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* */ -/* PORT.H */ -/* */ -/******************************************************************************/ -/* */ -/* This module contains macro definitions and types that are likely to */ -/* change between computers. */ -/* */ -/******************************************************************************/ - -#ifndef DONE_PORT /* Only do this if not previously done. */ - - #ifdef THINK_C - #define UBYTE unsigned char /* Unsigned byte */ - #define UWORD unsigned int /* Unsigned word (2 bytes) */ - #define ULONG unsigned long /* Unsigned word (4 bytes) */ - #define BOOL unsigned char /* Boolean */ - #define FOPEN_BINARY_READ "rb" /* Mode string for binary reading. */ - #define FOPEN_BINARY_WRITE "wb" /* Mode string for binary writing. */ - #define FOPEN_TEXT_APPEND "a" /* Mode string for text appending. */ - #define REAL double /* USed for floating point stuff. */ - #endif - #if defined(LINUX) || defined(linux) - #define UBYTE __u8 /* Unsigned byte */ - #define UWORD __u16 /* Unsigned word (2 bytes) */ - #define ULONG __u32 /* Unsigned word (4 bytes) */ - #define LONG __s32 /* Signed word (4 bytes) */ - #define BOOL is not used here /* Boolean */ - #define FOPEN_BINARY_READ not used /* Mode string for binary reading. */ - #define FOPEN_BINARY_WRITE not used /* Mode string for binary writing. */ - #define FOPEN_TEXT_APPEND not used /* Mode string for text appending. */ - #define REAL not used /* USed for floating point stuff. */ - #ifndef TRUE - #define TRUE 1 - #endif - #endif - - #define DONE_PORT /* Don't do all this again. */ - #define MALLOC_FAIL NULL /* Failure status from malloc() */ - #define LOCAL static /* For non-exported routines. */ - #define EXPORT /* Signals exported function. */ - #define then /* Useful for aligning ifs. */ - -#endif - -/******************************************************************************/ -/* End of PORT.H */ -/******************************************************************************/ - -#define COMPRESS_ACTION_IDENTITY 0 -#define COMPRESS_ACTION_COMPRESS 1 -#define COMPRESS_ACTION_DECOMPRESS 2 - -#define COMPRESS_OVERRUN 1024 -#define COMPRESS_MAX_COM 0x70000000 -#define COMPRESS_MAX_ORG (COMPRESS_MAX_COM-COMPRESS_OVERRUN) - -#define COMPRESS_MAX_STRLEN 255 - -/* The following structure provides information about the algorithm. */ -/* > The top bit of id must be zero. The remaining bits must be chosen by */ -/* the author of the algorithm by tossing a coin 31 times. */ -/* > The amount of memory requested by the algorithm is specified in bytes */ -/* and must be in the range [0,0x70000000]. */ -/* > All strings s must be such that strlen(s)<=COMPRESS_MAX_STRLEN. */ -struct compress_identity - { - ULONG id; /* Identifying number of algorithm. */ - ULONG memory; /* Number of bytes of working memory required. */ - - char *name; /* Name of algorithm. */ - char *version; /* Version number. */ - char *date; /* Date of release of this version. */ - char *copyright; /* Copyright message. */ - - char *author; /* Author of algorithm. */ - char *affiliation; /* Affiliation of author. */ - char *vendor; /* Where the algorithm can be obtained. */ - }; - -void lzrw3_compress( /* Single function interface to compression algorithm. */ -UWORD action, /* Action to be performed. */ -UBYTE *wrk_mem, /* Working memory temporarily given to routine to use. */ -UBYTE *src_adr, /* Address of input data. */ -LONG src_len, /* Length of input data. */ -UBYTE *dst_adr, /* Address of output data. */ -void *p_dst_len /* Pointer to a longword where routine will write: */ - /* If action=..IDENTITY => Adr of id structure. */ - /* If action=..COMPRESS => Length of output data. */ - /* If action=..DECOMPRESS => Length of output data. */ -); - -/******************************************************************************/ -/* End of COMPRESS.H */ -/******************************************************************************/ - - -/******************************************************************************/ -/* fast_copy.h */ -/******************************************************************************/ - -/* This function copies a block of memory very quickly. */ -/* The exact speed depends on the relative alignment of the blocks of memory. */ -/* PRE : 0<=src_len<=(2^32)-1 . */ -/* PRE : Source and destination blocks must not overlap. */ -/* POST : MEM[dst_adr,dst_adr+src_len-1]=MEM[src_adr,src_adr+src_len-1]. */ -/* POST : MEM[dst_adr,dst_adr+src_len-1] is the only memory changed. */ - -#define fast_copy(src,dst,len) memcpy(dst,src,len) - -/******************************************************************************/ -/* End of fast_copy.h */ -/******************************************************************************/ - -#endif diff --git a/drivers/char/ftape/compressor/zftape-compress.c b/drivers/char/ftape/compressor/zftape-compress.c deleted file mode 100644 index 65ffc0be3df9..000000000000 --- a/drivers/char/ftape/compressor/zftape-compress.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* - * Copyright (C) 1994-1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - USA. - - * - * This file implements a "generic" interface between the * - * zftape-driver and a compression-algorithm. The * - * compression-algorithm currently used is a LZ77. I use the * - * implementation lzrw3 by Ross N. Williams (Renaissance * - * Software). The compression program itself is in the file - * lzrw3.c * and lzrw3.h. To adopt another compression algorithm - * the functions * zft_compress() and zft_uncompress() must be - * changed * appropriately. See below. - */ - -#include -#include -#include - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../compressor/zftape-compress.h" -#include "../zftape/zftape-vtbl.h" -#include "../compressor/lzrw3.h" - -/* - * global variables - */ - -/* I handle the allocation of this buffer as a special case, because - * it's size varies depending on the tape length inserted. - */ - -/* local variables - */ -static void *zftc_wrk_mem = NULL; -static __u8 *zftc_buf = NULL; -static void *zftc_scratch_buf = NULL; - -/* compression statistics - */ -static unsigned int zftc_wr_uncompressed = 0; -static unsigned int zftc_wr_compressed = 0; -static unsigned int zftc_rd_uncompressed = 0; -static unsigned int zftc_rd_compressed = 0; - -/* forward */ -static int zftc_write(int *write_cnt, - __u8 *dst_buf, const int seg_sz, - const __u8 __user *src_buf, const int req_len, - const zft_position *pos, const zft_volinfo *volume); -static int zftc_read(int *read_cnt, - __u8 __user *dst_buf, const int to_do, - const __u8 *src_buf, const int seg_sz, - const zft_position *pos, const zft_volinfo *volume); -static int zftc_seek(unsigned int new_block_pos, - zft_position *pos, const zft_volinfo *volume, - __u8 *buffer); -static void zftc_lock (void); -static void zftc_reset (void); -static void zftc_cleanup(void); -static void zftc_stats (void); - -/* compressed segment. This conforms to QIC-80-MC, Revision K. - * - * Rev. K applies to tapes with `fixed length format' which is - * indicated by format code 2,3 and 5. See below for format code 4 and 6 - * - * 2 bytes: offset of compression segment structure - * 29k > offset >= 29k-18: data from previous segment ens in this - * segment and no compressed block starts - * in this segment - * offset == 0: data from previous segment occupies entire - * segment and continues in next segment - * n bytes: remainder from previous segment - * - * Rev. K: - * 4 bytes: 4 bytes: files set byte offset - * Post Rev. K and QIC-3020/3020: - * 8 bytes: 8 bytes: files set byte offset - * 2 bytes: byte count N (amount of data following) - * bit 15 is set if data is compressed, bit 15 is not - * set if data is uncompressed - * N bytes: data (as much as specified in the byte count) - * 2 bytes: byte count N_1 of next cluster - * N_1 bytes: data of next cluset - * 2 bytes: byte count N_2 of next cluster - * N_2 bytes: ... - * - * Note that the `N' byte count accounts only for the bytes that in the - * current segment if the cluster spans to the next segment. - */ - -typedef struct -{ - int cmpr_pos; /* actual position in compression buffer */ - int cmpr_sz; /* what is left in the compression buffer - * when copying the compressed data to the - * deblock buffer - */ - unsigned int first_block; /* location of header information in - * this segment - */ - unsigned int count; /* amount of data of current block - * contained in current segment - */ - unsigned int offset; /* offset in current segment */ - unsigned int spans:1; /* might continue in next segment */ - unsigned int uncmpr; /* 0x8000 if this block contains - * uncompressed data - */ - __s64 foffs; /* file set byte offset, same as in - * compression map segment - */ -} cmpr_info; - -static cmpr_info cseg; /* static data. Must be kept uptodate and shared by - * read, write and seek functions - */ - -#define DUMP_CMPR_INFO(level, msg, info) \ - TRACE(level, msg "\n" \ - KERN_INFO "cmpr_pos : %d\n" \ - KERN_INFO "cmpr_sz : %d\n" \ - KERN_INFO "first_block: %d\n" \ - KERN_INFO "count : %d\n" \ - KERN_INFO "offset : %d\n" \ - KERN_INFO "spans : %d\n" \ - KERN_INFO "uncmpr : 0x%04x\n" \ - KERN_INFO "foffs : " LL_X, \ - (info)->cmpr_pos, (info)->cmpr_sz, (info)->first_block, \ - (info)->count, (info)->offset, (info)->spans == 1, \ - (info)->uncmpr, LL((info)->foffs)) - -/* dispatch compression segment info, return error code - * - * afterwards, cseg->offset points to start of data of the NEXT - * compressed block, and cseg->count contains the amount of data - * left in the actual compressed block. cseg->spans is set to 1 if - * the block is continued in the following segment. Otherwise it is - * set to 0. - */ -static int get_cseg (cmpr_info *cinfo, const __u8 *buff, - const unsigned int seg_sz, - const zft_volinfo *volume) -{ - TRACE_FUN(ft_t_flow); - - cinfo->first_block = GET2(buff, 0); - if (cinfo->first_block == 0) { /* data spans to next segment */ - cinfo->count = seg_sz - sizeof(__u16); - cinfo->offset = seg_sz; - cinfo->spans = 1; - } else { /* cluster definetely ends in this segment */ - if (cinfo->first_block > seg_sz) { - /* data corrupted */ - TRACE_ABORT(-EIO, ft_t_err, "corrupted data:\n" - KERN_INFO "segment size: %d\n" - KERN_INFO "first block : %d", - seg_sz, cinfo->first_block); - } - cinfo->count = cinfo->first_block - sizeof(__u16); - cinfo->offset = cinfo->first_block; - cinfo->spans = 0; - } - /* now get the offset the first block should have in the - * uncompressed data stream. - * - * For this magic `18' refer to CRF-3 standard or QIC-80MC, - * Rev. K. - */ - if ((seg_sz - cinfo->offset) > 18) { - if (volume->qic113) { /* > revision K */ - TRACE(ft_t_data_flow, "New QIC-113 compliance"); - cinfo->foffs = GET8(buff, cinfo->offset); - cinfo->offset += sizeof(__s64); - } else { - TRACE(/* ft_t_data_flow */ ft_t_noise, "pre QIC-113 version"); - cinfo->foffs = (__s64)GET4(buff, cinfo->offset); - cinfo->offset += sizeof(__u32); - } - } - if (cinfo->foffs > volume->size) { - TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n" - KERN_INFO "offset in current volume: %d\n" - KERN_INFO "size of current volume : %d", - (int)(cinfo->foffs>>10), (int)(volume->size>>10)); - } - if (cinfo->cmpr_pos + cinfo->count > volume->blk_sz) { - TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n" - KERN_INFO "block size : %d\n" - KERN_INFO "data record: %d", - volume->blk_sz, cinfo->cmpr_pos + cinfo->count); - } - DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", cinfo); - TRACE_EXIT 0; -} - -/* This one is called, when a new cluster starts in same segment. - * - * Note: if this is the first cluster in the current segment, we must - * not check whether there are more than 18 bytes available because - * this have already been done in get_cseg() and there may be less - * than 18 bytes available due to header information. - * - */ -static void get_next_cluster(cmpr_info *cluster, const __u8 *buff, - const int seg_sz, const int finish) -{ - TRACE_FUN(ft_t_flow); - - if (seg_sz - cluster->offset > 18 || cluster->foffs != 0) { - cluster->count = GET2(buff, cluster->offset); - cluster->uncmpr = cluster->count & 0x8000; - cluster->count -= cluster->uncmpr; - cluster->offset += sizeof(__u16); - cluster->foffs = 0; - if ((cluster->offset + cluster->count) < seg_sz) { - cluster->spans = 0; - } else if (cluster->offset + cluster->count == seg_sz) { - cluster->spans = !finish; - } else { - /* either an error or a volume written by an - * old version. If this is a data error, then we'll - * catch it later. - */ - TRACE(ft_t_data_flow, "Either error or old volume"); - cluster->spans = 1; - cluster->count = seg_sz - cluster->offset; - } - } else { - cluster->count = 0; - cluster->spans = 0; - cluster->foffs = 0; - } - DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */ , "", cluster); - TRACE_EXIT; -} - -static void zftc_lock(void) -{ -} - -/* this function is needed for zftape_reset_position in zftape-io.c - */ -static void zftc_reset(void) -{ - TRACE_FUN(ft_t_flow); - - memset((void *)&cseg, '\0', sizeof(cseg)); - zftc_stats(); - TRACE_EXIT; -} - -static int cmpr_mem_initialized = 0; -static unsigned int alloc_blksz = 0; - -static int zft_allocate_cmpr_mem(unsigned int blksz) -{ - TRACE_FUN(ft_t_flow); - - if (cmpr_mem_initialized && blksz == alloc_blksz) { - TRACE_EXIT 0; - } - TRACE_CATCH(zft_vmalloc_once(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE), - zftc_cleanup()); - TRACE_CATCH(zft_vmalloc_always(&zftc_buf, blksz + CMPR_OVERRUN), - zftc_cleanup()); - alloc_blksz = blksz; - TRACE_CATCH(zft_vmalloc_always(&zftc_scratch_buf, blksz+CMPR_OVERRUN), - zftc_cleanup()); - cmpr_mem_initialized = 1; - TRACE_EXIT 0; -} - -static void zftc_cleanup(void) -{ - TRACE_FUN(ft_t_flow); - - zft_vfree(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE); - zft_vfree(&zftc_buf, alloc_blksz + CMPR_OVERRUN); - zft_vfree(&zftc_scratch_buf, alloc_blksz + CMPR_OVERRUN); - cmpr_mem_initialized = alloc_blksz = 0; - TRACE_EXIT; -} - -/***************************************************************************** - * * - * The following two functions "ftape_compress()" and * - * "ftape_uncompress()" are the interface to the actual compression * - * algorithm (i.e. they are calling the "compress()" function from * - * the lzrw3 package for now). These routines could quite easily be * - * changed to adopt another compression algorithm instead of lzrw3, * - * which currently is used. * - * * - *****************************************************************************/ - -/* called by zft_compress_write() to perform the compression. Must - * return the size of the compressed data. - * - * NOTE: The size of the compressed data should not exceed the size of - * the uncompressed data. Most compression algorithms have means - * to store data unchanged if the "compressed" data amount would - * exceed the original one. Mostly this is done by storing some - * flag-bytes in front of the compressed data to indicate if it - * is compressed or not. Thus the worst compression result - * length is the original length plus those flag-bytes. - * - * We don't want that, as the QIC-80 standard provides a means - * of marking uncompressed blocks by simply setting bit 15 of - * the compressed block's length. Thus a compessed block can - * have at most a length of 2^15-1 bytes. The QIC-80 standard - * restricts the block-length even further, allowing only 29k - - * 6 bytes. - * - * Currently, the maximum blocksize used by zftape is 28k. - * - * In short: don't exceed the length of the input-package, set - * bit 15 of the compressed size to 1 if you have copied data - * instead of compressing it. - */ -static int zft_compress(__u8 *in_buffer, unsigned int in_sz, __u8 *out_buffer) -{ - __s32 compressed_sz; - TRACE_FUN(ft_t_flow); - - - lzrw3_compress(COMPRESS_ACTION_COMPRESS, zftc_wrk_mem, - in_buffer, in_sz, out_buffer, &compressed_sz); - if (TRACE_LEVEL >= ft_t_info) { - /* the compiler will optimize this away when - * compiled with NO_TRACE_AT_ALL option - */ - TRACE(ft_t_data_flow, "\n" - KERN_INFO "before compression: %d bytes\n" - KERN_INFO "after compresison : %d bytes", - in_sz, - (int)(compressed_sz < 0 - ? -compressed_sz : compressed_sz)); - /* for statistical purposes - */ - zftc_wr_compressed += (compressed_sz < 0 - ? -compressed_sz : compressed_sz); - zftc_wr_uncompressed += in_sz; - } - TRACE_EXIT (int)compressed_sz; -} - -/* called by zft_compress_read() to decompress the data. Must - * return the size of the decompressed data for sanity checks - * (compared with zft_blk_sz) - * - * NOTE: Read the note for zft_compress() above! If bit 15 of the - * parameter in_sz is set, then the data in in_buffer isn't - * compressed, which must be handled by the un-compression - * algorithm. (I changed lzrw3 to handle this.) - * - * The parameter max_out_sz is needed to prevent buffer overruns when - * uncompressing corrupt data. - */ -static unsigned int zft_uncompress(__u8 *in_buffer, - int in_sz, - __u8 *out_buffer, - unsigned int max_out_sz) -{ - TRACE_FUN(ft_t_flow); - - lzrw3_compress(COMPRESS_ACTION_DECOMPRESS, zftc_wrk_mem, - in_buffer, (__s32)in_sz, - out_buffer, (__u32 *)&max_out_sz); - - if (TRACE_LEVEL >= ft_t_info) { - TRACE(ft_t_data_flow, "\n" - KERN_INFO "before decompression: %d bytes\n" - KERN_INFO "after decompression : %d bytes", - in_sz < 0 ? -in_sz : in_sz,(int)max_out_sz); - /* for statistical purposes - */ - zftc_rd_compressed += in_sz < 0 ? -in_sz : in_sz; - zftc_rd_uncompressed += max_out_sz; - } - TRACE_EXIT (unsigned int)max_out_sz; -} - -/* print some statistics about the efficiency of the compression to - * the kernel log - */ -static void zftc_stats(void) -{ - TRACE_FUN(ft_t_flow); - - if (TRACE_LEVEL < ft_t_info) { - TRACE_EXIT; - } - if (zftc_wr_uncompressed != 0) { - if (zftc_wr_compressed > (1<<14)) { - TRACE(ft_t_info, "compression statistics (writing):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - (((zftc_wr_compressed>>10) * 100) - / (zftc_wr_uncompressed>>10))); - } else { - TRACE(ft_t_info, "compression statistics (writing):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - ((zftc_wr_compressed * 100) - / zftc_wr_uncompressed)); - } - } - if (zftc_rd_uncompressed != 0) { - if (zftc_rd_compressed > (1<<14)) { - TRACE(ft_t_info, "compression statistics (reading):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - (((zftc_rd_compressed>>10) * 100) - / (zftc_rd_uncompressed>>10))); - } else { - TRACE(ft_t_info, "compression statistics (reading):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - ((zftc_rd_compressed * 100) - / zftc_rd_uncompressed)); - } - } - /* only print it once: */ - zftc_wr_uncompressed = - zftc_wr_compressed = - zftc_rd_uncompressed = - zftc_rd_compressed = 0; - TRACE_EXIT; -} - -/* start new compressed block - */ -static int start_new_cseg(cmpr_info *cluster, - char *dst_buf, - const zft_position *pos, - const unsigned int blk_sz, - const char *src_buf, - const int this_segs_sz, - const int qic113) -{ - int size_left; - int cp_cnt; - int buf_pos; - TRACE_FUN(ft_t_flow); - - size_left = this_segs_sz - sizeof(__u16) - cluster->cmpr_sz; - TRACE(ft_t_data_flow,"\n" - KERN_INFO "segment size : %d\n" - KERN_INFO "compressed_sz: %d\n" - KERN_INFO "size_left : %d", - this_segs_sz, cluster->cmpr_sz, size_left); - if (size_left > 18) { /* start a new cluseter */ - cp_cnt = cluster->cmpr_sz; - cluster->cmpr_sz = 0; - buf_pos = cp_cnt + sizeof(__u16); - PUT2(dst_buf, 0, buf_pos); - - if (qic113) { - __s64 foffs = pos->volume_pos; - if (cp_cnt) foffs += (__s64)blk_sz; - - TRACE(ft_t_data_flow, "new style QIC-113 header"); - PUT8(dst_buf, buf_pos, foffs); - buf_pos += sizeof(__s64); - } else { - __u32 foffs = (__u32)pos->volume_pos; - if (cp_cnt) foffs += (__u32)blk_sz; - - TRACE(ft_t_data_flow, "old style QIC-80MC header"); - PUT4(dst_buf, buf_pos, foffs); - buf_pos += sizeof(__u32); - } - } else if (size_left >= 0) { - cp_cnt = cluster->cmpr_sz; - cluster->cmpr_sz = 0; - buf_pos = cp_cnt + sizeof(__u16); - PUT2(dst_buf, 0, buf_pos); - /* zero unused part of segment. */ - memset(dst_buf + buf_pos, '\0', size_left); - buf_pos = this_segs_sz; - } else { /* need entire segment and more space */ - PUT2(dst_buf, 0, 0); - cp_cnt = this_segs_sz - sizeof(__u16); - cluster->cmpr_sz -= cp_cnt; - buf_pos = this_segs_sz; - } - memcpy(dst_buf + sizeof(__u16), src_buf + cluster->cmpr_pos, cp_cnt); - cluster->cmpr_pos += cp_cnt; - TRACE_EXIT buf_pos; -} - -/* return-value: the number of bytes removed from the user-buffer - * `src_buf' or error code - * - * int *write_cnt : how much actually has been moved to the - * dst_buf. Need not be initialized when - * function returns with an error code - * (negativ return value) - * __u8 *dst_buf : kernel space buffer where the has to be - * copied to. The contents of this buffers - * goes to a specific segment. - * const int seg_sz : the size of the segment dst_buf will be - * copied to. - * const zft_position *pos : struct containing the coordinates in - * the current volume (byte position, - * segment id of current segment etc) - * const zft_volinfo *volume: information about the current volume, - * size etc. - * const __u8 *src_buf : user space buffer that contains the - * data the user wants to be written to - * tape. - * const int req_len : the amount of data the user wants to be - * written to tape. - */ -static int zftc_write(int *write_cnt, - __u8 *dst_buf, const int seg_sz, - const __u8 __user *src_buf, const int req_len, - const zft_position *pos, const zft_volinfo *volume) -{ - int req_len_left = req_len; - int result; - int len_left; - int buf_pos_write = pos->seg_byte_pos; - TRACE_FUN(ft_t_flow); - - /* Note: we do not unlock the module because - * there are some values cached in that `cseg' variable. We - * don't don't want to use this information when being - * unloaded by kerneld even when the tape is full or when we - * cannot allocate enough memory. - */ - if (pos->tape_pos > (volume->size-volume->blk_sz-ZFT_CMPR_OVERHEAD)) { - TRACE_EXIT -ENOSPC; - } - if (zft_allocate_cmpr_mem(volume->blk_sz) < 0) { - /* should we unlock the module? But it shouldn't - * be locked anyway ... - */ - TRACE_EXIT -ENOMEM; - } - if (buf_pos_write == 0) { /* fill a new segment */ - *write_cnt = buf_pos_write = start_new_cseg(&cseg, - dst_buf, - pos, - volume->blk_sz, - zftc_buf, - seg_sz, - volume->qic113); - if (cseg.cmpr_sz == 0 && cseg.cmpr_pos != 0) { - req_len_left -= result = volume->blk_sz; - cseg.cmpr_pos = 0; - } else { - result = 0; - } - } else { - *write_cnt = result = 0; - } - - len_left = seg_sz - buf_pos_write; - while ((req_len_left > 0) && (len_left > 18)) { - /* now we have some size left for a new compressed - * block. We know, that the compression buffer is - * empty (else there wouldn't be any space left). - */ - if (copy_from_user(zftc_scratch_buf, src_buf + result, - volume->blk_sz) != 0) { - TRACE_EXIT -EFAULT; - } - req_len_left -= volume->blk_sz; - cseg.cmpr_sz = zft_compress(zftc_scratch_buf, volume->blk_sz, - zftc_buf); - if (cseg.cmpr_sz < 0) { - cseg.uncmpr = 0x8000; - cseg.cmpr_sz = -cseg.cmpr_sz; - } else { - cseg.uncmpr = 0; - } - /* increment "result" iff we copied the entire - * compressed block to the zft_deblock_buf - */ - len_left -= sizeof(__u16); - if (len_left >= cseg.cmpr_sz) { - len_left -= cseg.count = cseg.cmpr_sz; - cseg.cmpr_pos = cseg.cmpr_sz = 0; - result += volume->blk_sz; - } else { - cseg.cmpr_sz -= - cseg.cmpr_pos = - cseg.count = len_left; - len_left = 0; - } - PUT2(dst_buf, buf_pos_write, cseg.uncmpr | cseg.count); - buf_pos_write += sizeof(__u16); - memcpy(dst_buf + buf_pos_write, zftc_buf, cseg.count); - buf_pos_write += cseg.count; - *write_cnt += cseg.count + sizeof(__u16); - FT_SIGNAL_EXIT(_DONT_BLOCK); - } - /* erase the remainder of the segment if less than 18 bytes - * left (18 bytes is due to the QIC-80 standard) - */ - if (len_left <= 18) { - memset(dst_buf + buf_pos_write, '\0', len_left); - (*write_cnt) += len_left; - } - TRACE(ft_t_data_flow, "returning %d", result); - TRACE_EXIT result; -} - -/* out: - * - * int *read_cnt: the number of bytes we removed from the zft_deblock_buf - * (result) - * int *to_do : the remaining size of the read-request. - * - * in: - * - * char *buff : buff is the address of the upper part of the user - * buffer, that hasn't been filled with data yet. - - * int buf_pos_read : copy of from _ftape_read() - * int buf_len_read : copy of buf_len_rd from _ftape_read() - * char *zft_deblock_buf: zft_deblock_buf - * unsigned short blk_sz: the block size valid for this volume, may differ - * from zft_blk_sz. - * int finish: if != 0 means that this is the last segment belonging - * to this volume - * returns the amount of data actually copied to the user-buffer - * - * to_do MUST NOT SHRINK except to indicate an EOF. In this case *to_do has to - * be set to 0 - */ -static int zftc_read (int *read_cnt, - __u8 __user *dst_buf, const int to_do, - const __u8 *src_buf, const int seg_sz, - const zft_position *pos, const zft_volinfo *volume) -{ - int uncompressed_sz; - int result = 0; - int remaining = to_do; - TRACE_FUN(ft_t_flow); - - TRACE_CATCH(zft_allocate_cmpr_mem(volume->blk_sz),); - if (pos->seg_byte_pos == 0) { - /* new segment just read - */ - TRACE_CATCH(get_cseg(&cseg, src_buf, seg_sz, volume), - *read_cnt = 0); - memcpy(zftc_buf + cseg.cmpr_pos, src_buf + sizeof(__u16), - cseg.count); - cseg.cmpr_pos += cseg.count; - *read_cnt = cseg.offset; - DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", &cseg); - } else { - *read_cnt = 0; - } - /* loop and uncompress until user buffer full or - * deblock-buffer empty - */ - TRACE(ft_t_data_flow, "compressed_sz: %d, compos : %d, *read_cnt: %d", - cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); - while ((cseg.spans == 0) && (remaining > 0)) { - if (cseg.cmpr_pos != 0) { /* cmpr buf is not empty */ - uncompressed_sz = - zft_uncompress(zftc_buf, - cseg.uncmpr == 0x8000 ? - -cseg.cmpr_pos : cseg.cmpr_pos, - zftc_scratch_buf, - volume->blk_sz); - if (uncompressed_sz != volume->blk_sz) { - *read_cnt = 0; - TRACE_ABORT(-EIO, ft_t_warn, - "Uncompressed blk (%d) != blk size (%d)", - uncompressed_sz, volume->blk_sz); - } - if (copy_to_user(dst_buf + result, - zftc_scratch_buf, - uncompressed_sz) != 0 ) { - TRACE_EXIT -EFAULT; - } - remaining -= uncompressed_sz; - result += uncompressed_sz; - cseg.cmpr_pos = 0; - } - if (remaining > 0) { - get_next_cluster(&cseg, src_buf, seg_sz, - volume->end_seg == pos->seg_pos); - if (cseg.count != 0) { - memcpy(zftc_buf, src_buf + cseg.offset, - cseg.count); - cseg.cmpr_pos = cseg.count; - cseg.offset += cseg.count; - *read_cnt += cseg.count + sizeof(__u16); - } else { - remaining = 0; - } - } - TRACE(ft_t_data_flow, "\n" - KERN_INFO "compressed_sz: %d\n" - KERN_INFO "compos : %d\n" - KERN_INFO "*read_cnt : %d", - cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); - } - if (seg_sz - cseg.offset <= 18) { - *read_cnt += seg_sz - cseg.offset; - TRACE(ft_t_data_flow, "expanding read cnt to: %d", *read_cnt); - } - TRACE(ft_t_data_flow, "\n" - KERN_INFO "segment size : %d\n" - KERN_INFO "read count : %d\n" - KERN_INFO "buf_pos_read : %d\n" - KERN_INFO "remaining : %d", - seg_sz, *read_cnt, pos->seg_byte_pos, - seg_sz - *read_cnt - pos->seg_byte_pos); - TRACE(ft_t_data_flow, "returning: %d", result); - TRACE_EXIT result; -} - -/* seeks to the new data-position. Reads sometimes a segment. - * - * start_seg and end_seg give the boundaries of the current volume - * blk_sz is the blk_sz of the current volume as stored in the - * volume label - * - * We don't allow blocksizes less than 1024 bytes, therefore we don't need - * a 64 bit argument for new_block_pos. - */ - -static int seek_in_segment(const unsigned int to_do, cmpr_info *c_info, - const char *src_buf, const int seg_sz, - const int seg_pos, const zft_volinfo *volume); -static int slow_seek_forward_until_error(const unsigned int distance, - cmpr_info *c_info, zft_position *pos, - const zft_volinfo *volume, __u8 *buf); -static int search_valid_segment(unsigned int segment, - const unsigned int end_seg, - const unsigned int max_foffs, - zft_position *pos, cmpr_info *c_info, - const zft_volinfo *volume, __u8 *buf); -static int slow_seek_forward(unsigned int dest, cmpr_info *c_info, - zft_position *pos, const zft_volinfo *volume, - __u8 *buf); -static int compute_seg_pos(unsigned int dest, zft_position *pos, - const zft_volinfo *volume); - -#define ZFT_SLOW_SEEK_THRESHOLD 10 /* segments */ -#define ZFT_FAST_SEEK_MAX_TRIALS 10 /* times */ -#define ZFT_FAST_SEEK_BACKUP 10 /* segments */ - -static int zftc_seek(unsigned int new_block_pos, - zft_position *pos, const zft_volinfo *volume, __u8 *buf) -{ - unsigned int dest; - int limit; - int distance; - int result = 0; - int seg_dist; - int new_seg; - int old_seg = 0; - int fast_seek_trials = 0; - TRACE_FUN(ft_t_flow); - - if (new_block_pos == 0) { - pos->seg_pos = volume->start_seg; - pos->seg_byte_pos = 0; - pos->volume_pos = 0; - zftc_reset(); - TRACE_EXIT 0; - } - dest = new_block_pos * (volume->blk_sz >> 10); - distance = dest - (pos->volume_pos >> 10); - while (distance != 0) { - seg_dist = compute_seg_pos(dest, pos, volume); - TRACE(ft_t_noise, "\n" - KERN_INFO "seg_dist: %d\n" - KERN_INFO "distance: %d\n" - KERN_INFO "dest : %d\n" - KERN_INFO "vpos : %d\n" - KERN_INFO "seg_pos : %d\n" - KERN_INFO "trials : %d", - seg_dist, distance, dest, - (unsigned int)(pos->volume_pos>>10), pos->seg_pos, - fast_seek_trials); - if (distance > 0) { - if (seg_dist < 0) { - TRACE(ft_t_bug, "BUG: distance %d > 0, " - "segment difference %d < 0", - distance, seg_dist); - result = -EIO; - break; - } - new_seg = pos->seg_pos + seg_dist; - if (new_seg > volume->end_seg) { - new_seg = volume->end_seg; - } - if (old_seg == new_seg || /* loop */ - seg_dist <= ZFT_SLOW_SEEK_THRESHOLD || - fast_seek_trials >= ZFT_FAST_SEEK_MAX_TRIALS) { - TRACE(ft_t_noise, "starting slow seek:\n" - KERN_INFO "fast seek failed too often: %s\n" - KERN_INFO "near target position : %s\n" - KERN_INFO "looping between two segs : %s", - (fast_seek_trials >= - ZFT_FAST_SEEK_MAX_TRIALS) - ? "yes" : "no", - (seg_dist <= ZFT_SLOW_SEEK_THRESHOLD) - ? "yes" : "no", - (old_seg == new_seg) - ? "yes" : "no"); - result = slow_seek_forward(dest, &cseg, - pos, volume, buf); - break; - } - old_seg = new_seg; - limit = volume->end_seg; - fast_seek_trials ++; - for (;;) { - result = search_valid_segment(new_seg, limit, - volume->size, - pos, &cseg, - volume, buf); - if (result == 0 || result == -EINTR) { - break; - } - if (new_seg == volume->start_seg) { - result = -EIO; /* set errror - * condition - */ - break; - } - limit = new_seg; - new_seg -= ZFT_FAST_SEEK_BACKUP; - if (new_seg < volume->start_seg) { - new_seg = volume->start_seg; - } - } - if (result < 0) { - TRACE(ft_t_warn, - "Couldn't find a readable segment"); - break; - } - } else /* if (distance < 0) */ { - if (seg_dist > 0) { - TRACE(ft_t_bug, "BUG: distance %d < 0, " - "segment difference %d >0", - distance, seg_dist); - result = -EIO; - break; - } - new_seg = pos->seg_pos + seg_dist; - if (fast_seek_trials > 0 && seg_dist == 0) { - /* this avoids sticking to the same - * segment all the time. On the other hand: - * if we got here for the first time, and the - * deblock_buffer still contains a valid - * segment, then there is no need to skip to - * the previous segment if the desired position - * is inside this segment. - */ - new_seg --; - } - if (new_seg < volume->start_seg) { - new_seg = volume->start_seg; - } - limit = pos->seg_pos; - fast_seek_trials ++; - for (;;) { - result = search_valid_segment(new_seg, limit, - pos->volume_pos, - pos, &cseg, - volume, buf); - if (result == 0 || result == -EINTR) { - break; - } - if (new_seg == volume->start_seg) { - result = -EIO; /* set errror - * condition - */ - break; - } - limit = new_seg; - new_seg -= ZFT_FAST_SEEK_BACKUP; - if (new_seg < volume->start_seg) { - new_seg = volume->start_seg; - } - } - if (result < 0) { - TRACE(ft_t_warn, - "Couldn't find a readable segment"); - break; - } - } - distance = dest - (pos->volume_pos >> 10); - } - TRACE_EXIT result; -} - - -/* advance inside the given segment at most to_do bytes. - * of kilobytes moved - */ - -static int seek_in_segment(const unsigned int to_do, - cmpr_info *c_info, - const char *src_buf, - const int seg_sz, - const int seg_pos, - const zft_volinfo *volume) -{ - int result = 0; - int blk_sz = volume->blk_sz >> 10; - int remaining = to_do; - TRACE_FUN(ft_t_flow); - - if (c_info->offset == 0) { - /* new segment just read - */ - TRACE_CATCH(get_cseg(c_info, src_buf, seg_sz, volume),); - c_info->cmpr_pos += c_info->count; - DUMP_CMPR_INFO(ft_t_noise, "", c_info); - } - /* loop and uncompress until user buffer full or - * deblock-buffer empty - */ - TRACE(ft_t_noise, "compressed_sz: %d, compos : %d", - c_info->cmpr_sz, c_info->cmpr_pos); - while (c_info->spans == 0 && remaining > 0) { - if (c_info->cmpr_pos != 0) { /* cmpr buf is not empty */ - result += blk_sz; - remaining -= blk_sz; - c_info->cmpr_pos = 0; - } - if (remaining > 0) { - get_next_cluster(c_info, src_buf, seg_sz, - volume->end_seg == seg_pos); - if (c_info->count != 0) { - c_info->cmpr_pos = c_info->count; - c_info->offset += c_info->count; - } else { - break; - } - } - /* Allow escape from this loop on signal! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - DUMP_CMPR_INFO(ft_t_noise, "", c_info); - TRACE(ft_t_noise, "to_do: %d", remaining); - } - if (seg_sz - c_info->offset <= 18) { - c_info->offset = seg_sz; - } - TRACE(ft_t_noise, "\n" - KERN_INFO "segment size : %d\n" - KERN_INFO "buf_pos_read : %d\n" - KERN_INFO "remaining : %d", - seg_sz, c_info->offset, - seg_sz - c_info->offset); - TRACE_EXIT result; -} - -static int slow_seek_forward_until_error(const unsigned int distance, - cmpr_info *c_info, - zft_position *pos, - const zft_volinfo *volume, - __u8 *buf) -{ - unsigned int remaining = distance; - int seg_sz; - int seg_pos; - int result; - TRACE_FUN(ft_t_flow); - - seg_pos = pos->seg_pos; - do { - TRACE_CATCH(seg_sz = zft_fetch_segment(seg_pos, buf, - FT_RD_AHEAD),); - /* now we have the contents of the actual segment in - * the deblock buffer - */ - TRACE_CATCH(result = seek_in_segment(remaining, c_info, buf, - seg_sz, seg_pos,volume),); - remaining -= result; - pos->volume_pos += result<<10; - pos->seg_pos = seg_pos; - pos->seg_byte_pos = c_info->offset; - seg_pos ++; - if (seg_pos <= volume->end_seg && c_info->offset == seg_sz) { - pos->seg_pos ++; - pos->seg_byte_pos = 0; - c_info->offset = 0; - } - /* Allow escape from this loop on signal! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE(ft_t_noise, "\n" - KERN_INFO "remaining: %d\n" - KERN_INFO "seg_pos: %d\n" - KERN_INFO "end_seg: %d\n" - KERN_INFO "result: %d", - remaining, seg_pos, volume->end_seg, result); - } while (remaining > 0 && seg_pos <= volume->end_seg); - TRACE_EXIT 0; -} - -/* return segment id of next segment containing valid data, -EIO otherwise - */ -static int search_valid_segment(unsigned int segment, - const unsigned int end_seg, - const unsigned int max_foffs, - zft_position *pos, - cmpr_info *c_info, - const zft_volinfo *volume, - __u8 *buf) -{ - cmpr_info tmp_info; - int seg_sz; - TRACE_FUN(ft_t_flow); - - memset(&tmp_info, 0, sizeof(cmpr_info)); - while (segment <= end_seg) { - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE(ft_t_noise, - "Searching readable segment between %d and %d", - segment, end_seg); - seg_sz = zft_fetch_segment(segment, buf, FT_RD_AHEAD); - if ((seg_sz > 0) && - (get_cseg (&tmp_info, buf, seg_sz, volume) >= 0) && - (tmp_info.foffs != 0 || segment == volume->start_seg)) { - if ((tmp_info.foffs>>10) > max_foffs) { - TRACE_ABORT(-EIO, ft_t_noise, "\n" - KERN_INFO "cseg.foff: %d\n" - KERN_INFO "dest : %d", - (int)(tmp_info.foffs >> 10), - max_foffs); - } - DUMP_CMPR_INFO(ft_t_noise, "", &tmp_info); - *c_info = tmp_info; - pos->seg_pos = segment; - pos->volume_pos = c_info->foffs; - pos->seg_byte_pos = c_info->offset; - TRACE(ft_t_noise, "found segment at %d", segment); - TRACE_EXIT 0; - } - segment++; - } - TRACE_EXIT -EIO; -} - -static int slow_seek_forward(unsigned int dest, - cmpr_info *c_info, - zft_position *pos, - const zft_volinfo *volume, - __u8 *buf) -{ - unsigned int distance; - int result = 0; - TRACE_FUN(ft_t_flow); - - distance = dest - (pos->volume_pos >> 10); - while ((distance > 0) && - (result = slow_seek_forward_until_error(distance, - c_info, - pos, - volume, - buf)) < 0) { - if (result == -EINTR) { - break; - } - TRACE(ft_t_noise, "seg_pos: %d", pos->seg_pos); - /* the failing segment is either pos->seg_pos or - * pos->seg_pos + 1. There is no need to further try - * that segment, because ftape_read_segment() already - * has tried very much to read it. So we start with - * following segment, which is pos->seg_pos + 1 - */ - if(search_valid_segment(pos->seg_pos+1, volume->end_seg, dest, - pos, c_info, - volume, buf) < 0) { - TRACE(ft_t_noise, "search_valid_segment() failed"); - result = -EIO; - break; - } - distance = dest - (pos->volume_pos >> 10); - result = 0; - TRACE(ft_t_noise, "segment: %d", pos->seg_pos); - /* found valid segment, retry the seek */ - } - TRACE_EXIT result; -} - -static int compute_seg_pos(const unsigned int dest, - zft_position *pos, - const zft_volinfo *volume) -{ - int segment; - int distance = dest - (pos->volume_pos >> 10); - unsigned int raw_size; - unsigned int virt_size; - unsigned int factor; - TRACE_FUN(ft_t_flow); - - if (distance >= 0) { - raw_size = volume->end_seg - pos->seg_pos + 1; - virt_size = ((unsigned int)(volume->size>>10) - - (unsigned int)(pos->volume_pos>>10) - + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1); - virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS; - if (virt_size == 0 || raw_size == 0) { - TRACE_EXIT 0; - } - if (raw_size >= (1<<25)) { - factor = raw_size/(virt_size>>7); - } else { - factor = (raw_size<<7)/virt_size; - } - segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS); - segment = (segment * factor)>>7; - } else { - raw_size = pos->seg_pos - volume->start_seg + 1; - virt_size = ((unsigned int)(pos->volume_pos>>10) - + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1); - virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS; - if (virt_size == 0 || raw_size == 0) { - TRACE_EXIT 0; - } - if (raw_size >= (1<<25)) { - factor = raw_size/(virt_size>>7); - } else { - factor = (raw_size<<7)/virt_size; - } - segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS); - } - TRACE(ft_t_noise, "factor: %d/%d", factor, 1<<7); - TRACE_EXIT segment; -} - -static struct zft_cmpr_ops cmpr_ops = { - zftc_write, - zftc_read, - zftc_seek, - zftc_lock, - zftc_reset, - zftc_cleanup -}; - -int zft_compressor_init(void) -{ - TRACE_FUN(ft_t_flow); - -#ifdef MODULE - printk(KERN_INFO "zftape compressor v1.00a 970514 for " FTAPE_VERSION "\n"); - if (TRACE_LEVEL >= ft_t_info) { - printk( -KERN_INFO "(c) 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" -KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n"); - } -#else /* !MODULE */ - /* print a short no-nonsense boot message */ - printk(KERN_INFO "zftape compressor v1.00a 970514\n"); - printk(KERN_INFO "For use with " FTAPE_VERSION "\n"); -#endif /* MODULE */ - TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init); - TRACE(ft_t_info, "installing compressor for zftape ..."); - TRACE_CATCH(zft_cmpr_register(&cmpr_ops),); - TRACE_EXIT 0; -} - -#ifdef MODULE - -MODULE_AUTHOR( - "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de"); -MODULE_DESCRIPTION( -"Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams"); -MODULE_LICENSE("GPL"); - -/* Called by modules package when installing the driver - */ -int init_module(void) -{ - return zft_compressor_init(); -} - -#endif /* MODULE */ diff --git a/drivers/char/ftape/compressor/zftape-compress.h b/drivers/char/ftape/compressor/zftape-compress.h deleted file mode 100644 index f200741e33bf..000000000000 --- a/drivers/char/ftape/compressor/zftape-compress.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _ZFTAPE_COMPRESS_H -#define _ZFTAPE_COMPRESS_H -/* - * Copyright (c) 1994-1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/compressor/zftape-compress.h,v $ - * $Revision: 1.1 $ - * $Date: 1997/10/05 19:12:32 $ - * - * This file contains macros and definitions for zftape's - * builtin compression code. - * - */ - -#include "../zftape/zftape-buffers.h" -#include "../zftape/zftape-vtbl.h" -#include "../compressor/lzrw3.h" - -/* CMPR_WRK_MEM_SIZE gives the size of the compression wrk_mem */ -/* I got these out of lzrw3.c */ -#define U(X) ((__u32) X) -#define SIZE_P_BYTE (U(sizeof(__u8 *))) -#define ALIGNMENT_FUDGE (U(16)) - -#define CMPR_WRK_MEM_SIZE (U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE) - -/* the maximum number of bytes the size of the "compressed" data can - * exceed the uncompressed data. As it is quite useless to compress - * data twice it is sometimes the case that it is more efficient to - * copy a block of data but to feed it to the "compression" - * algorithm. In this case there are some flag bytes or the like - * proceding the "compressed" data. THAT MUST NOT BE THE CASE for the - * algorithm we use for this driver. Instead, the high bit 15 of - * compressed_size: - * - * compressed_size = ftape_compress() - * - * must be set in such a case. - * - * Nevertheless, it might also be as for lzrw3 that there is an - * "intermediate" overrun that exceeds the amount of the compressed - * data that is actually produced. During the algorithm we need in the - * worst case MAX_CMP_GROUP bytes more than the input-size. - */ -#define MAX_CMP_GROUP (2+16*2) /* from lzrw3.c */ - -#define CMPR_OVERRUN MAX_CMP_GROUP /* during compression */ - -/****************************************************/ - -#define CMPR_BUFFER_SIZE (MAX_BLOCK_SIZE + CMPR_OVERRUN) - -/* the compression map stores the byte offset compressed blocks within - * the current volume for catridges with format code 2,3 and 5 - * (and old versions of zftape) and the offset measured in kilobytes for - * format code 4 and 6. This gives us a possible max. size of a - * compressed volume of 1024*4GIG which should be enough. - */ -typedef __u32 CmprMap; - -/* globals - */ - -/* exported functions - */ - -#endif /* _ZFTAPE_COMPRESS_H */ diff --git a/drivers/char/ftape/lowlevel/Makefile b/drivers/char/ftape/lowlevel/Makefile deleted file mode 100644 index febab07ba427..000000000000 --- a/drivers/char/ftape/lowlevel/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright (C) 1996, 1997 Clau-Justus Heine. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to -# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -# -# $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/Makefile,v $ -# $Revision: 1.4 $ -# $Date: 1997/10/07 09:26:02 $ -# -# Makefile for the lowlevel part QIC-40/80/3010/3020 floppy-tape -# driver for Linux. -# - -obj-$(CONFIG_FTAPE) += ftape.o - -ftape-objs := ftape-init.o fdc-io.o fdc-isr.o \ - ftape-bsm.o ftape-ctl.o ftape-read.o ftape-rw.o \ - ftape-write.o ftape-io.o ftape-calibr.o ftape-ecc.o fc-10.o \ - ftape-buffer.o ftape-format.o ftape_syms.o - -ifeq ($(CONFIG_FTAPE),y) -ftape-objs += ftape-setup.o -endif - -ifndef CONFIG_FT_NO_TRACE_AT_ALL -ftape-objs += ftape-tracing.o -endif - -ifeq ($(CONFIG_FT_PROC_FS),y) -ftape-objs += ftape-proc.o -endif diff --git a/drivers/char/ftape/lowlevel/fc-10.c b/drivers/char/ftape/lowlevel/fc-10.c deleted file mode 100644 index 9bc1cddade76..000000000000 --- a/drivers/char/ftape/lowlevel/fc-10.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - - Copyright (C) 1993,1994 Jon Tombs. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The entire guts of this program was written by dosemu, modified to - record reads and writes to the ports in the 0x180-0x188 address space, - while running the CMS program TAPE.EXE V2.0.5 supplied with the drive. - - Modified to use an array of addresses and generally cleaned up (made - much shorter) 4 June 94, dosemu isn't that good at writing short code it - would seem :-). Made independent of 0x180, but I doubt it will work - at any other address. - - Modified for distribution with ftape source. 21 June 94, SJL. - - Modifications on 20 October 95, by Daniel Cohen (catman@wpi.edu): - Modified to support different DMA, IRQ, and IO Ports. Borland's - Turbo Debugger in virtual 8086 mode (TD386.EXE with hardware breakpoints - provided by the TDH386.SYS Device Driver) was used on the CMS program - TAPE V4.0.5. I set breakpoints on I/O to ports 0x180-0x187. Note that - CMS's program will not successfully configure the tape drive if you set - breakpoints on IO Reads, but you can set them on IO Writes without problems. - Known problems: - - You can not use DMA Channels 5 or 7. - - Modification on 29 January 96, by Daniel Cohen (catman@wpi.edu): - Modified to only accept IRQs 3 - 7, or 9. Since we can only send a 3 bit - number representing the IRQ to the card, special handling is required when - IRQ 9 is selected. IRQ 2 and 9 are the same, and we should request IRQ 9 - from the kernel while telling the card to use IRQ 2. Thanks to Greg - Crider (gcrider@iclnet.org) for finding and locating this bug, as well as - testing the patch. - - Modification on 11 December 96, by Claus Heine (claus@momo.math.rwth-aachen.de): - Modified a little to use variahle ft_fdc_base, ft_fdc_irq, ft_fdc_dma - instead of preprocessor symbols. Thus we can compile this into the module - or kernel and let the user specify the options as command line arguments. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:04 $ - * - * This file contains code for the CMS FC-10/FC-20 card. - */ - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/fc-10.h" - -static __u16 inbs_magic[] = { - 0x3, 0x3, 0x0, 0x4, 0x7, 0x2, 0x5, 0x3, 0x1, 0x4, - 0x3, 0x5, 0x2, 0x0, 0x3, 0x7, 0x4, 0x2, - 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 -}; - -static __u16 fc10_ports[] = { - 0x180, 0x210, 0x2A0, 0x300, 0x330, 0x340, 0x370 -}; - -int fc10_enable(void) -{ - int i; - __u8 cardConfig = 0x00; - __u8 x; - TRACE_FUN(ft_t_flow); - -/* This code will only work if the FC-10 (or FC-20) is set to - * use DMA channels 1, 2, or 3. DMA channels 5 and 7 seem to be - * initialized by the same command as channels 1 and 3, respectively. - */ - if (ft_fdc_dma > 3) { - TRACE_ABORT(0, ft_t_err, -"Error: The FC-10/20 must be set to use DMA channels 1, 2, or 3!"); - } -/* Only allow the FC-10/20 to use IRQ 3-7, or 9. Note that CMS's program - * only accepts IRQ's 2-7, but in linux, IRQ 2 is the same as IRQ 9. - */ - if (ft_fdc_irq < 3 || ft_fdc_irq == 8 || ft_fdc_irq > 9) { - TRACE_ABORT(0, ft_t_err, -"Error: The FC-10/20 must be set to use IRQ levels 3 - 7, or 9!\n" -KERN_INFO "Note: IRQ 9 is the same as IRQ 2"); - } - /* Clear state machine ??? - */ - for (i = 0; i < NR_ITEMS(inbs_magic); i++) { - inb(ft_fdc_base + inbs_magic[i]); - } - outb(0x0, ft_fdc_base); - - x = inb(ft_fdc_base); - if (x == 0x13 || x == 0x93) { - for (i = 1; i < 8; i++) { - if (inb(ft_fdc_base + i) != x) { - TRACE_EXIT 0; - } - } - } else { - TRACE_EXIT 0; - } - - outb(0x8, ft_fdc_base); - - for (i = 0; i < 8; i++) { - if (inb(ft_fdc_base + i) != 0x0) { - TRACE_EXIT 0; - } - } - outb(0x10, ft_fdc_base); - - for (i = 0; i < 8; i++) { - if (inb(ft_fdc_base + i) != 0xff) { - TRACE_EXIT 0; - } - } - - /* Okay, we found a FC-10 card ! ??? - */ - outb(0x0, fdc.ccr); - - /* Clear state machine again ??? - */ - for (i = 0; i < NR_ITEMS(inbs_magic); i++) { - inb(ft_fdc_base + inbs_magic[i]); - } - /* Send io port */ - for (i = 0; i < NR_ITEMS(fc10_ports); i++) - if (ft_fdc_base == fc10_ports[i]) - cardConfig = i + 1; - if (cardConfig == 0) { - TRACE_EXIT 0; /* Invalid I/O Port */ - } - /* and IRQ - If using IRQ 9, tell the FC card it is actually IRQ 2 */ - if (ft_fdc_irq != 9) - cardConfig |= ft_fdc_irq << 3; - else - cardConfig |= 2 << 3; - - /* and finally DMA Channel */ - cardConfig |= ft_fdc_dma << 6; - outb(cardConfig, ft_fdc_base); /* DMA [2 bits]/IRQ [3 bits]/BASE [3 bits] */ - - /* Enable FC-10 ??? - */ - outb(0, fdc.ccr); - outb(0, fdc.dor2); - outb(FDC_DMA_MODE /* 8 */, fdc.dor); - outb(FDC_DMA_MODE /* 8 */, fdc.dor); - outb(1, fdc.dor2); - - /************************************* - * - * cH: why the hell should this be necessary? This is done - * by fdc_reset()!!! - * - *************************************/ - /* Initialize fdc, select drive B: - */ - outb(FDC_DMA_MODE, fdc.dor); /* assert reset, dma & irq enabled */ - /* 0x08 */ - outb(FDC_DMA_MODE|FDC_RESET_NOT, fdc.dor); /* release reset */ - /* 0x08 | 0x04 = 0x0c */ - outb(FDC_DMA_MODE|FDC_RESET_NOT|FDC_MOTOR_1|FTAPE_SEL_B, fdc.dor); - /* 0x08 | 0x04 | 0x20 | 0x01 = 0x2d */ - /* select drive 1 */ /* why not drive 0 ???? */ - TRACE_EXIT (x == 0x93) ? 2 : 1; -} diff --git a/drivers/char/ftape/lowlevel/fc-10.h b/drivers/char/ftape/lowlevel/fc-10.h deleted file mode 100644 index da7b88bca889..000000000000 --- a/drivers/char/ftape/lowlevel/fc-10.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _FC_10_H -#define _FC_10_H - -/* - * Copyright (C) 1994-1996 Bas Laarhoven. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.h,v $ - * $Revision: 1.1 $ - * $Date: 1997/09/19 09:05:22 $ - * - * This file contains definitions for the FC-10 code - * of the QIC-40/80 floppy-tape driver for Linux. - */ - -/* - * fc-10.c defined global vars. - */ - -/* - * fc-10.c defined global functions. - */ -extern int fc10_enable(void); - -#endif diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c deleted file mode 100644 index bbcf918f056f..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ /dev/null @@ -1,1349 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-io.c,v $ - * $Revision: 1.7.4.2 $ - * $Date: 1997/11/16 14:48:17 $ - * - * This file contains the low-level floppy disk interface code - * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for - * Linux. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/fdc-isr.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-calibr.h" -#include "../lowlevel/fc-10.h" - -/* Global vars. - */ -static int ftape_motor; -volatile int ftape_current_cylinder = -1; -volatile fdc_mode_enum fdc_mode = fdc_idle; -fdc_config_info fdc; -DECLARE_WAIT_QUEUE_HEAD(ftape_wait_intr); - -unsigned int ft_fdc_base = CONFIG_FT_FDC_BASE; -unsigned int ft_fdc_irq = CONFIG_FT_FDC_IRQ; -unsigned int ft_fdc_dma = CONFIG_FT_FDC_DMA; -unsigned int ft_fdc_threshold = CONFIG_FT_FDC_THR; /* bytes */ -unsigned int ft_fdc_rate_limit = CONFIG_FT_FDC_MAX_RATE; /* bits/sec */ -int ft_probe_fc10 = CONFIG_FT_PROBE_FC10; -int ft_mach2 = CONFIG_FT_MACH2; - -/* Local vars. - */ -static spinlock_t fdc_io_lock; -static unsigned int fdc_calibr_count; -static unsigned int fdc_calibr_time; -static int fdc_status; -volatile __u8 fdc_head; /* FDC head from sector id */ -volatile __u8 fdc_cyl; /* FDC track from sector id */ -volatile __u8 fdc_sect; /* FDC sector from sector id */ -static int fdc_data_rate = 500; /* data rate (Kbps) */ -static int fdc_rate_code; /* data rate code (0 == 500 Kbps) */ -static int fdc_seek_rate = 2; /* step rate (msec) */ -static void (*do_ftape) (void); -static int fdc_fifo_state; /* original fifo setting - fifo enabled */ -static int fdc_fifo_thr; /* original fifo setting - threshold */ -static int fdc_lock_state; /* original lock setting - locked */ -static int fdc_fifo_locked; /* has fifo && lock set ? */ -static __u8 fdc_precomp; /* default precomp. value (nsec) */ -static __u8 fdc_prec_code; /* fdc precomp. select code */ - -static char ftape_id[] = "ftape"; /* used by request irq and free irq */ - -static int fdc_set_seek_rate(int seek_rate); - -void fdc_catch_stray_interrupts(int count) -{ - unsigned long flags; - - spin_lock_irqsave(&fdc_io_lock, flags); - if (count == 0) { - ft_expected_stray_interrupts = 0; - } else { - ft_expected_stray_interrupts += count; - } - spin_unlock_irqrestore(&fdc_io_lock, flags); -} - -/* Wait during a timeout period for a given FDC status. - * If usecs == 0 then just test status, else wait at least for usecs. - * Returns -ETIME on timeout. Function must be calibrated first ! - */ -static int fdc_wait(unsigned int usecs, __u8 mask, __u8 state) -{ - int count_1 = (fdc_calibr_count * usecs + - fdc_calibr_count - 1) / fdc_calibr_time; - - do { - fdc_status = inb_p(fdc.msr); - if ((fdc_status & mask) == state) { - return 0; - } - } while (count_1-- >= 0); - return -ETIME; -} - -int fdc_ready_wait(unsigned int usecs) -{ - return fdc_wait(usecs, FDC_DATA_READY | FDC_BUSY, FDC_DATA_READY); -} - -/* Why can't we just use udelay()? - */ -static void fdc_usec_wait(unsigned int usecs) -{ - fdc_wait(usecs, 0, 1); /* will always timeout ! */ -} - -static int fdc_ready_out_wait(unsigned int usecs) -{ - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_OUT_READY); -} - -void fdc_wait_calibrate(void) -{ - ftape_calibrate("fdc_wait", - fdc_usec_wait, &fdc_calibr_count, &fdc_calibr_time); -} - -/* Wait for a (short) while for the FDC to become ready - * and transfer the next command byte. - * Return -ETIME on timeout on getting ready (depends on hardware!). - */ -static int fdc_write(const __u8 data) -{ - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_IN_READY) < 0) { - return -ETIME; - } else { - outb(data, fdc.fifo); - return 0; - } -} - -/* Wait for a (short) while for the FDC to become ready - * and transfer the next result byte. - * Return -ETIME if timeout on getting ready (depends on hardware!). - */ -static int fdc_read(__u8 * data) -{ - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_OUT_READY) < 0) { - return -ETIME; - } else { - *data = inb(fdc.fifo); - return 0; - } -} - -/* Output a cmd_len long command string to the FDC. - * The FDC should be ready to receive a new command or - * an error (EBUSY or ETIME) will occur. - */ -int fdc_command(const __u8 * cmd_data, int cmd_len) -{ - int result = 0; - unsigned long flags; - int count = cmd_len; - int retry = 0; -#ifdef TESTING - static unsigned int last_time; - unsigned int time; -#endif - TRACE_FUN(ft_t_any); - - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - spin_lock_irqsave(&fdc_io_lock, flags); - if (!in_interrupt()) - /* Yes, I know, too much comments inside this function - * ... - * - * Yet another bug in the original driver. All that - * havoc is caused by the fact that the isr() sends - * itself a command to the floppy tape driver (pause, - * micro step pause). Now, the problem is that - * commands are transmitted via the fdc_seek - * command. But: the fdc performs seeks in the - * background i.e. it doesn't signal busy while - * sending the step pulses to the drive. Therefore the - * non-interrupt level driver has no chance to tell - * whether the isr() just has issued a seek. Therefore - * we HAVE TO have a look at the ft_hide_interrupt - * flag: it signals the non-interrupt level part of - * the driver that it has to wait for the fdc until it - * has completet seeking. - * - * THIS WAS PRESUMABLY THE REASON FOR ALL THAT - * "fdc_read timeout" errors, I HOPE :-) - */ - if (ft_hide_interrupt) { - restore_flags(flags); - TRACE(ft_t_info, - "Waiting for the isr() completing fdc_seek()"); - if (fdc_interrupt_wait(2 * FT_SECOND) < 0) { - TRACE(ft_t_warn, - "Warning: timeout waiting for isr() seek to complete"); - } - if (ft_hide_interrupt || !ft_seek_completed) { - /* There cannot be another - * interrupt. The isr() only stops - * the tape and the next interrupt - * won't come until we have send our - * command to the drive. - */ - TRACE_ABORT(-EIO, ft_t_bug, - "BUG? isr() is still seeking?\n" - KERN_INFO "hide: %d\n" - KERN_INFO "seek: %d", - ft_hide_interrupt, - ft_seek_completed); - - } - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - spin_lock_irqsave(&fdc_io_lock, flags); - } - fdc_status = inb(fdc.msr); - if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_IN_READY) { - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_ABORT(-EBUSY, ft_t_err, "fdc not ready"); - } - fdc_mode = *cmd_data; /* used by isr */ -#ifdef TESTING - if (fdc_mode == FDC_SEEK) { - time = ftape_timediff(last_time, ftape_timestamp()); - if (time < 6000) { - TRACE(ft_t_bug,"Warning: short timeout between seek commands: %d", - time); - } - } -#endif - if (!in_interrupt()) { - /* shouldn't be cleared if called from isr - */ - ft_interrupt_seen = 0; - } - while (count) { - result = fdc_write(*cmd_data); - if (result < 0) { - TRACE(ft_t_fdc_dma, - "fdc_mode = %02x, status = %02x at index %d", - (int) fdc_mode, (int) fdc_status, - cmd_len - count); - if (++retry <= 3) { - TRACE(ft_t_warn, "fdc_write timeout, retry"); - } else { - TRACE(ft_t_err, "fdc_write timeout, fatal"); - /* recover ??? */ - break; - } - } else { - --count; - ++cmd_data; - } - } -#ifdef TESTING - if (fdc_mode == FDC_SEEK) { - last_time = ftape_timestamp(); - } -#endif - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_EXIT result; -} - -/* Input a res_len long result string from the FDC. - * The FDC should be ready to send the result or an error - * (EBUSY or ETIME) will occur. - */ -int fdc_result(__u8 * res_data, int res_len) -{ - int result = 0; - unsigned long flags; - int count = res_len; - int retry = 0; - TRACE_FUN(ft_t_any); - - spin_lock_irqsave(&fdc_io_lock, flags); - fdc_status = inb(fdc.msr); - if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_OUT_READY) { - TRACE(ft_t_err, "fdc not ready"); - result = -EBUSY; - } else while (count) { - if (!(fdc_status & FDC_BUSY)) { - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_ABORT(-EIO, ft_t_err, "premature end of result phase"); - } - result = fdc_read(res_data); - if (result < 0) { - TRACE(ft_t_fdc_dma, - "fdc_mode = %02x, status = %02x at index %d", - (int) fdc_mode, - (int) fdc_status, - res_len - count); - if (++retry <= 3) { - TRACE(ft_t_warn, "fdc_read timeout, retry"); - } else { - TRACE(ft_t_err, "fdc_read timeout, fatal"); - /* recover ??? */ - break; - ++retry; - } - } else { - --count; - ++res_data; - } - } - spin_unlock_irqrestore(&fdc_io_lock, flags); - fdc_usec_wait(FT_RQM_DELAY); /* allow FDC to negate BSY */ - TRACE_EXIT result; -} - -/* Handle command and result phases for - * commands without data phase. - */ -static int fdc_issue_command(const __u8 * out_data, int out_count, - __u8 * in_data, int in_count) -{ - TRACE_FUN(ft_t_any); - - if (out_count > 0) { - TRACE_CATCH(fdc_command(out_data, out_count),); - } - /* will take 24 - 30 usec for fdc_sense_drive_status and - * fdc_sense_interrupt_status commands. - * 35 fails sometimes (5/9/93 SJL) - * On a loaded system it incidentally takes longer than - * this for the fdc to get ready ! ?????? WHY ?????? - * So until we know what's going on use a very long timeout. - */ - TRACE_CATCH(fdc_ready_out_wait(500 /* usec */),); - if (in_count > 0) { - TRACE_CATCH(fdc_result(in_data, in_count), - TRACE(ft_t_err, "result phase aborted")); - } - TRACE_EXIT 0; -} - -/* Wait for FDC interrupt with timeout (in milliseconds). - * Signals are blocked so the wait will not be aborted. - * Note: interrupts must be enabled ! (23/05/93 SJL) - */ -int fdc_interrupt_wait(unsigned int time) -{ - DECLARE_WAITQUEUE(wait,current); - sigset_t old_sigmask; - static int resetting; - long timeout; - - TRACE_FUN(ft_t_fdc_dma); - - if (waitqueue_active(&ftape_wait_intr)) { - TRACE_ABORT(-EIO, ft_t_err, "error: nested call"); - } - /* timeout time will be up to USPT microseconds too long ! */ - timeout = (1000 * time + FT_USPT - 1) / FT_USPT; - - spin_lock_irq(¤t->sighand->siglock); - old_sigmask = current->blocked; - sigfillset(¤t->blocked); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&ftape_wait_intr, &wait); - while (!ft_interrupt_seen && timeout) - timeout = schedule_timeout_interruptible(timeout); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = old_sigmask; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - remove_wait_queue(&ftape_wait_intr, &wait); - /* the following IS necessary. True: as well - * wake_up_interruptible() as the schedule() set TASK_RUNNING - * when they wakeup a task, BUT: it may very well be that - * ft_interrupt_seen is already set to 1 when we enter here - * in which case schedule() gets never called, and - * TASK_RUNNING never set. This has the funny effect that we - * execute all the code until we leave kernel space, but then - * the task is stopped (a task CANNOT be preempted while in - * kernel mode. Sending a pair of SIGSTOP/SIGCONT to the - * tasks wakes it up again. Funny! :-) - */ - current->state = TASK_RUNNING; - if (ft_interrupt_seen) { /* woken up by interrupt */ - ft_interrupt_seen = 0; - TRACE_EXIT 0; - } - /* Original comment: - * In first instance, next statement seems unnecessary since - * it will be cleared in fdc_command. However, a small part of - * the software seems to rely on this being cleared here - * (ftape_close might fail) so stick to it until things get fixed ! - */ - /* My deeply sought of knowledge: - * Behold NO! It is obvious. fdc_reset() doesn't call fdc_command() - * but nevertheless uses fdc_interrupt_wait(). OF COURSE this needs to - * be reset here. - */ - ft_interrupt_seen = 0; /* clear for next call */ - if (!resetting) { - resetting = 1; /* break infinite recursion if reset fails */ - TRACE(ft_t_any, "cleanup reset"); - fdc_reset(); - resetting = 0; - } - TRACE_EXIT (signal_pending(current)) ? -EINTR : -ETIME; -} - -/* Start/stop drive motor. Enable DMA mode. - */ -void fdc_motor(int motor) -{ - int unit = ft_drive_sel; - int data = unit | FDC_RESET_NOT | FDC_DMA_MODE; - TRACE_FUN(ft_t_any); - - ftape_motor = motor; - if (ftape_motor) { - data |= FDC_MOTOR_0 << unit; - TRACE(ft_t_noise, "turning motor %d on", unit); - } else { - TRACE(ft_t_noise, "turning motor %d off", unit); - } - if (ft_mach2) { - outb_p(data, fdc.dor2); - } else { - outb_p(data, fdc.dor); - } - ftape_sleep(10 * FT_MILLISECOND); - TRACE_EXIT; -} - -static void fdc_update_dsr(void) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "rate = %d Kbps, precomp = %d ns", - fdc_data_rate, fdc_precomp); - if (fdc.type >= i82077) { - outb_p((fdc_rate_code & 0x03) | fdc_prec_code, fdc.dsr); - } else { - outb_p(fdc_rate_code & 0x03, fdc.ccr); - } - TRACE_EXIT; -} - -void fdc_set_write_precomp(int precomp) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_noise, "New precomp: %d nsec", precomp); - fdc_precomp = precomp; - /* write precompensation can be set in multiples of 41.67 nsec. - * round the parameter to the nearest multiple and convert it - * into a fdc setting. Note that 0 means default to the fdc, - * 7 is used instead of that. - */ - fdc_prec_code = ((fdc_precomp + 21) / 42) << 2; - if (fdc_prec_code == 0 || fdc_prec_code > (6 << 2)) { - fdc_prec_code = 7 << 2; - } - fdc_update_dsr(); - TRACE_EXIT; -} - -/* Reprogram the 82078 registers to use Data Rate Table 1 on all drives. - */ -static void fdc_set_drive_specs(void) -{ - __u8 cmd[] = { FDC_DRIVE_SPEC, 0x00, 0x00, 0x00, 0x00, 0xc0}; - int result; - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "Setting of drive specs called"); - if (fdc.type >= i82078_1) { - cmd[1] = (0 << 5) | (2 << 2); - cmd[2] = (1 << 5) | (2 << 2); - cmd[3] = (2 << 5) | (2 << 2); - cmd[4] = (3 << 5) | (2 << 2); - result = fdc_command(cmd, NR_ITEMS(cmd)); - if (result < 0) { - TRACE(ft_t_err, "Setting of drive specs failed"); - } - } - TRACE_EXIT; -} - -/* Select clock for fdc, must correspond with tape drive setting ! - * This also influences the fdc timing so we must adjust some values. - */ -int fdc_set_data_rate(int rate) -{ - int bad_rate = 0; - TRACE_FUN(ft_t_any); - - /* Select clock for fdc, must correspond with tape drive setting ! - * This also influences the fdc timing so we must adjust some values. - */ - TRACE(ft_t_fdc_dma, "new rate = %d", rate); - switch (rate) { - case 250: - fdc_rate_code = fdc_data_rate_250; - break; - case 500: - fdc_rate_code = fdc_data_rate_500; - break; - case 1000: - if (fdc.type < i82077) { - bad_rate = 1; - } else { - fdc_rate_code = fdc_data_rate_1000; - } - break; - case 2000: - if (fdc.type < i82078_1) { - bad_rate = 1; - } else { - fdc_rate_code = fdc_data_rate_2000; - } - break; - default: - bad_rate = 1; - } - if (bad_rate) { - TRACE_ABORT(-EIO, - ft_t_fdc_dma, "%d is not a valid data rate", rate); - } - fdc_data_rate = rate; - fdc_update_dsr(); - fdc_set_seek_rate(fdc_seek_rate); /* clock changed! */ - ftape_udelay(1000); - TRACE_EXIT 0; -} - -/* keep the unit select if keep_select is != 0, - */ -static void fdc_dor_reset(int keep_select) -{ - __u8 fdc_ctl = ft_drive_sel; - - if (keep_select != 0) { - fdc_ctl |= FDC_DMA_MODE; - if (ftape_motor) { - fdc_ctl |= FDC_MOTOR_0 << ft_drive_sel; - } - } - ftape_udelay(10); /* ??? but seems to be necessary */ - if (ft_mach2) { - outb_p(fdc_ctl & 0x0f, fdc.dor); - outb_p(fdc_ctl, fdc.dor2); - } else { - outb_p(fdc_ctl, fdc.dor); - } - fdc_usec_wait(10); /* delay >= 14 fdc clocks */ - if (keep_select == 0) { - fdc_ctl = 0; - } - fdc_ctl |= FDC_RESET_NOT; - if (ft_mach2) { - outb_p(fdc_ctl & 0x0f, fdc.dor); - outb_p(fdc_ctl, fdc.dor2); - } else { - outb_p(fdc_ctl, fdc.dor); - } -} - -/* Reset the floppy disk controller. Leave the ftape_unit selected. - */ -void fdc_reset(void) -{ - int st0; - int i; - int dummy; - unsigned long flags; - TRACE_FUN(ft_t_any); - - spin_lock_irqsave(&fdc_io_lock, flags); - - fdc_dor_reset(1); /* keep unit selected */ - - fdc_mode = fdc_idle; - - /* maybe the spin_lock_irq* pair is not necessary, BUT: - * the following line MUST be here. Otherwise fdc_interrupt_wait() - * won't wait. Note that fdc_reset() is called from - * ftape_dumb_stop() when the fdc is busy transferring data. In this - * case fdc_isr() MOST PROBABLY sets ft_interrupt_seen, and tries - * to get the result bytes from the fdc etc. CLASH. - */ - ft_interrupt_seen = 0; - - /* Program data rate - */ - fdc_update_dsr(); /* restore data rate and precomp */ - - spin_unlock_irqrestore(&fdc_io_lock, flags); - - /* - * Wait for first polling cycle to complete - */ - if (fdc_interrupt_wait(1 * FT_SECOND) < 0) { - TRACE(ft_t_err, "no drive polling interrupt!"); - } else { /* clear all disk-changed statuses */ - for (i = 0; i < 4; ++i) { - if(fdc_sense_interrupt_status(&st0, &dummy) != 0) { - TRACE(ft_t_err, "sense failed for %d", i); - } - if (i == ft_drive_sel) { - ftape_current_cylinder = dummy; - } - } - TRACE(ft_t_noise, "drive polling completed"); - } - /* - * SPECIFY COMMAND - */ - fdc_set_seek_rate(fdc_seek_rate); - /* - * DRIVE SPECIFICATION COMMAND (if fdc type known) - */ - if (fdc.type >= i82078_1) { - fdc_set_drive_specs(); - } - TRACE_EXIT; -} - -#if !defined(CLK_48MHZ) -# define CLK_48MHZ 1 -#endif - -/* When we're done, put the fdc into reset mode so that the regular - * floppy disk driver will figure out that something is wrong and - * initialize the controller the way it wants. - */ -void fdc_disable(void) -{ - __u8 cmd1[] = {FDC_CONFIGURE, 0x00, 0x00, 0x00}; - __u8 cmd2[] = {FDC_LOCK}; - __u8 cmd3[] = {FDC_UNLOCK}; - __u8 stat[1]; - TRACE_FUN(ft_t_flow); - - if (!fdc_fifo_locked) { - fdc_reset(); - TRACE_EXIT; - } - if (fdc_issue_command(cmd3, 1, stat, 1) < 0 || stat[0] != 0x00) { - fdc_dor_reset(0); - TRACE_ABORT(/**/, ft_t_bug, - "couldn't unlock fifo, configuration remains changed"); - } - fdc_fifo_locked = 0; - if (CLK_48MHZ && fdc.type >= i82078) { - cmd1[0] |= FDC_CLK48_BIT; - } - cmd1[2] = ((fdc_fifo_state) ? 0 : 0x20) + (fdc_fifo_thr - 1); - if (fdc_command(cmd1, NR_ITEMS(cmd1)) < 0) { - fdc_dor_reset(0); - TRACE_ABORT(/**/, ft_t_bug, - "couldn't reconfigure fifo to old state"); - } - if (fdc_lock_state && - fdc_issue_command(cmd2, 1, stat, 1) < 0) { - fdc_dor_reset(0); - TRACE_ABORT(/**/, ft_t_bug, "couldn't lock old state again"); - } - TRACE(ft_t_noise, "fifo restored: %sabled, thr. %d, %slocked", - fdc_fifo_state ? "en" : "dis", - fdc_fifo_thr, (fdc_lock_state) ? "" : "not "); - fdc_dor_reset(0); - TRACE_EXIT; -} - -/* Specify FDC seek-rate (milliseconds) - */ -static int fdc_set_seek_rate(int seek_rate) -{ - /* set step rate, dma mode, and minimal head load and unload times - */ - __u8 in[3] = { FDC_SPECIFY, 1, (1 << 1)}; - - fdc_seek_rate = seek_rate; - in[1] |= (16 - (fdc_data_rate * fdc_seek_rate) / 500) << 4; - - return fdc_command(in, 3); -} - -/* Sense drive status: get unit's drive status (ST3) - */ -int fdc_sense_drive_status(int *st3) -{ - __u8 out[2]; - __u8 in[1]; - TRACE_FUN(ft_t_any); - - out[0] = FDC_SENSED; - out[1] = ft_drive_sel; - TRACE_CATCH(fdc_issue_command(out, 2, in, 1),); - *st3 = in[0]; - TRACE_EXIT 0; -} - -/* Sense Interrupt Status command: - * should be issued at the end of each seek. - * get ST0 and current cylinder. - */ -int fdc_sense_interrupt_status(int *st0, int *current_cylinder) -{ - __u8 out[1]; - __u8 in[2]; - TRACE_FUN(ft_t_any); - - out[0] = FDC_SENSEI; - TRACE_CATCH(fdc_issue_command(out, 1, in, 2),); - *st0 = in[0]; - *current_cylinder = in[1]; - TRACE_EXIT 0; -} - -/* step to track - */ -int fdc_seek(int track) -{ - __u8 out[3]; - int st0, pcn; -#ifdef TESTING - unsigned int time; -#endif - TRACE_FUN(ft_t_any); - - out[0] = FDC_SEEK; - out[1] = ft_drive_sel; - out[2] = track; -#ifdef TESTING - time = ftape_timestamp(); -#endif - /* We really need this command to work ! - */ - ft_seek_completed = 0; - TRACE_CATCH(fdc_command(out, 3), - fdc_reset(); - TRACE(ft_t_noise, "destination was: %d, resetting FDC...", - track)); - /* Handle interrupts until ft_seek_completed or timeout. - */ - for (;;) { - TRACE_CATCH(fdc_interrupt_wait(2 * FT_SECOND),); - if (ft_seek_completed) { - TRACE_CATCH(fdc_sense_interrupt_status(&st0, &pcn),); - if ((st0 & ST0_SEEK_END) == 0) { - TRACE_ABORT(-EIO, ft_t_err, - "no seek-end after seek completion !??"); - } - break; - } - } -#ifdef TESTING - time = ftape_timediff(time, ftape_timestamp()) / abs(track - ftape_current_cylinder); - if ((time < 900 || time > 3100) && abs(track - ftape_current_cylinder) > 5) { - TRACE(ft_t_warn, "Wrong FDC STEP interval: %d usecs (%d)", - time, track - ftape_current_cylinder); - } -#endif - /* Verify whether we issued the right tape command. - */ - /* Verify that we seek to the proper track. */ - if (pcn != track) { - TRACE_ABORT(-EIO, ft_t_err, "bad seek.."); - } - ftape_current_cylinder = track; - TRACE_EXIT 0; -} - -static int perpend_mode; /* set if fdc is in perpendicular mode */ - -static int perpend_off(void) -{ - __u8 perpend[] = {FDC_PERPEND, 0x00}; - TRACE_FUN(ft_t_any); - - if (perpend_mode) { - /* Turn off perpendicular mode */ - perpend[1] = 0x80; - TRACE_CATCH(fdc_command(perpend, 2), - TRACE(ft_t_err,"Perpendicular mode exit failed!")); - perpend_mode = 0; - } - TRACE_EXIT 0; -} - -static int handle_perpend(int segment_id) -{ - __u8 perpend[] = {FDC_PERPEND, 0x00}; - TRACE_FUN(ft_t_any); - - /* When writing QIC-3020 tapes, turn on perpendicular mode - * if tape is moving in forward direction (even tracks). - */ - if (ft_qic_std == QIC_TAPE_QIC3020 && - ((segment_id / ft_segments_per_track) & 1) == 0) { -/* FIXME: some i82077 seem to support perpendicular mode as - * well. - */ -#if 0 - if (fdc.type < i82077AA) {} -#else - if (fdc.type < i82077 && ft_data_rate < 1000) { -#endif - /* fdc does not support perpendicular mode: complain - */ - TRACE_ABORT(-EIO, ft_t_err, - "Your FDC does not support QIC-3020."); - } - perpend[1] = 0x03 /* 0x83 + (0x4 << ft_drive_sel) */ ; - TRACE_CATCH(fdc_command(perpend, 2), - TRACE(ft_t_err,"Perpendicular mode entry failed!")); - TRACE(ft_t_flow, "Perpendicular mode set"); - perpend_mode = 1; - TRACE_EXIT 0; - } - TRACE_EXIT perpend_off(); -} - -static inline void fdc_setup_dma(char mode, - volatile void *addr, unsigned int count) -{ - /* Program the DMA controller. - */ - disable_dma(fdc.dma); - clear_dma_ff(fdc.dma); - set_dma_mode(fdc.dma, mode); - set_dma_addr(fdc.dma, virt_to_bus((void*)addr)); - set_dma_count(fdc.dma, count); - enable_dma(fdc.dma); -} - -/* Setup fdc and dma for formatting the next segment - */ -int fdc_setup_formatting(buffer_struct * buff) -{ - unsigned long flags; - __u8 out[6] = { - FDC_FORMAT, 0x00, 3, 4 * FT_SECTORS_PER_SEGMENT, 0x00, 0x6b - }; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(handle_perpend(buff->segment_id),); - /* Program the DMA controller. - */ - TRACE(ft_t_fdc_dma, - "phys. addr. = %lx", virt_to_bus((void*) buff->ptr)); - spin_lock_irqsave(&fdc_io_lock, flags); - fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4); - /* Issue FDC command to start reading/writing. - */ - out[1] = ft_drive_sel; - out[4] = buff->gap3; - TRACE_CATCH(fdc_setup_error = fdc_command(out, sizeof(out)), - restore_flags(flags); fdc_mode = fdc_idle); - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_EXIT 0; -} - - -/* Setup Floppy Disk Controller and DMA to read or write the next cluster - * of good sectors from or to the current segment. - */ -int fdc_setup_read_write(buffer_struct * buff, __u8 operation) -{ - unsigned long flags; - __u8 out[9]; - int dma_mode; - TRACE_FUN(ft_t_any); - - switch(operation) { - case FDC_VERIFY: - if (fdc.type < i82077) { - operation = FDC_READ; - } - case FDC_READ: - case FDC_READ_DELETED: - dma_mode = DMA_MODE_READ; - TRACE(ft_t_fdc_dma, "xfer %d sectors to 0x%p", - buff->sector_count, buff->ptr); - TRACE_CATCH(perpend_off(),); - break; - case FDC_WRITE_DELETED: - TRACE(ft_t_noise, "deleting segment %d", buff->segment_id); - case FDC_WRITE: - dma_mode = DMA_MODE_WRITE; - /* When writing QIC-3020 tapes, turn on perpendicular mode - * if tape is moving in forward direction (even tracks). - */ - TRACE_CATCH(handle_perpend(buff->segment_id),); - TRACE(ft_t_fdc_dma, "xfer %d sectors from 0x%p", - buff->sector_count, buff->ptr); - break; - default: - TRACE_ABORT(-EIO, - ft_t_bug, "bug: invalid operation parameter"); - } - TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr)); - spin_lock_irqsave(&fdc_io_lock, flags); - if (operation != FDC_VERIFY) { - fdc_setup_dma(dma_mode, buff->ptr, - FT_SECTOR_SIZE * buff->sector_count); - } - /* Issue FDC command to start reading/writing. - */ - out[0] = operation; - out[1] = ft_drive_sel; - out[2] = buff->cyl; - out[3] = buff->head; - out[4] = buff->sect + buff->sector_offset; - out[5] = 3; /* Sector size of 1K. */ - out[6] = out[4] + buff->sector_count - 1; /* last sector */ - out[7] = 109; /* Gap length. */ - out[8] = 0xff; /* No limit to transfer size. */ - TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x", - out[2], out[3], out[4], out[6] - out[4] + 1); - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_CATCH(fdc_setup_error = fdc_command(out, 9),fdc_mode = fdc_idle); - TRACE_EXIT 0; -} - -int fdc_fifo_threshold(__u8 threshold, - int *fifo_state, int *lock_state, int *fifo_thr) -{ - const __u8 cmd0[] = {FDC_DUMPREGS}; - __u8 cmd1[] = {FDC_CONFIGURE, 0, (0x0f & (threshold - 1)), 0}; - const __u8 cmd2[] = {FDC_LOCK}; - const __u8 cmd3[] = {FDC_UNLOCK}; - __u8 reg[10]; - __u8 stat; - int i; - int result; - TRACE_FUN(ft_t_any); - - if (CLK_48MHZ && fdc.type >= i82078) { - cmd1[0] |= FDC_CLK48_BIT; - } - /* Dump fdc internal registers for examination - */ - TRACE_CATCH(fdc_command(cmd0, NR_ITEMS(cmd0)), - TRACE(ft_t_warn, "dumpreg cmd failed, fifo unchanged")); - /* Now read fdc internal registers from fifo - */ - for (i = 0; i < (int)NR_ITEMS(reg); ++i) { - fdc_read(®[i]); - TRACE(ft_t_fdc_dma, "Register %d = 0x%02x", i, reg[i]); - } - if (fifo_state && lock_state && fifo_thr) { - *fifo_state = (reg[8] & 0x20) == 0; - *lock_state = reg[7] & 0x80; - *fifo_thr = 1 + (reg[8] & 0x0f); - } - TRACE(ft_t_noise, - "original fifo state: %sabled, threshold %d, %slocked", - ((reg[8] & 0x20) == 0) ? "en" : "dis", - 1 + (reg[8] & 0x0f), (reg[7] & 0x80) ? "" : "not "); - /* If fdc is already locked, unlock it first ! */ - if (reg[7] & 0x80) { - fdc_ready_wait(100); - TRACE_CATCH(fdc_issue_command(cmd3, NR_ITEMS(cmd3), &stat, 1), - TRACE(ft_t_bug, "FDC unlock command failed, " - "configuration unchanged")); - } - fdc_fifo_locked = 0; - /* Enable fifo and set threshold at xx bytes to allow a - * reasonably large latency and reduce number of dma bursts. - */ - fdc_ready_wait(100); - if ((result = fdc_command(cmd1, NR_ITEMS(cmd1))) < 0) { - TRACE(ft_t_bug, "configure cmd failed, fifo unchanged"); - } - /* Now lock configuration so reset will not change it - */ - if(fdc_issue_command(cmd2, NR_ITEMS(cmd2), &stat, 1) < 0 || - stat != 0x10) { - TRACE_ABORT(-EIO, ft_t_bug, - "FDC lock command failed, stat = 0x%02x", stat); - } - fdc_fifo_locked = 1; - TRACE_EXIT result; -} - -static int fdc_fifo_enable(void) -{ - TRACE_FUN(ft_t_any); - - if (fdc_fifo_locked) { - TRACE_ABORT(0, ft_t_warn, "Fifo not enabled because locked"); - } - TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, - &fdc_fifo_state, - &fdc_lock_state, - &fdc_fifo_thr),); - TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, - NULL, NULL, NULL),); - TRACE_EXIT 0; -} - -/* Determine fd controller type - */ -static __u8 fdc_save_state[2]; - -static int fdc_probe(void) -{ - __u8 cmd[1]; - __u8 stat[16]; /* must be able to hold dumpregs & save results */ - int i; - TRACE_FUN(ft_t_any); - - /* Try to find out what kind of fd controller we have to deal with - * Scheme borrowed from floppy driver: - * first try if FDC_DUMPREGS command works - * (this indicates that we have a 82072 or better) - * then try the FDC_VERSION command (82072 doesn't support this) - * then try the FDC_UNLOCK command (some older 82077's don't support this) - * then try the FDC_PARTID command (82078's support this) - */ - cmd[0] = FDC_DUMPREGS; - if (fdc_issue_command(cmd, 1, stat, 1) != 0) { - TRACE_ABORT(no_fdc, ft_t_bug, "No FDC found"); - } - if (stat[0] == 0x80) { - /* invalid command: must be pre 82072 */ - TRACE_ABORT(i8272, - ft_t_warn, "Type 8272A/765A compatible FDC found"); - } - fdc_result(&stat[1], 9); - fdc_save_state[0] = stat[7]; - fdc_save_state[1] = stat[8]; - cmd[0] = FDC_VERSION; - if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { - TRACE_ABORT(i8272, ft_t_warn, "Type 82072 FDC found"); - } - if (*stat != 0x90) { - TRACE_ABORT(i8272, ft_t_warn, "Unknown FDC found"); - } - cmd[0] = FDC_UNLOCK; - if(fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] != 0x00) { - TRACE_ABORT(i8272, ft_t_warn, - "Type pre-1991 82077 FDC found, " - "treating it like a 82072"); - } - if (fdc_save_state[0] & 0x80) { /* was locked */ - cmd[0] = FDC_LOCK; /* restore lock */ - (void)fdc_issue_command(cmd, 1, stat, 1); - TRACE(ft_t_warn, "FDC is already locked"); - } - /* Test for a i82078 FDC */ - cmd[0] = FDC_PARTID; - if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { - /* invalid command: not a i82078xx type FDC */ - for (i = 0; i < 4; ++i) { - outb_p(i, fdc.tdr); - if ((inb_p(fdc.tdr) & 0x03) != i) { - TRACE_ABORT(i82077, - ft_t_warn, "Type 82077 FDC found"); - } - } - TRACE_ABORT(i82077AA, ft_t_warn, "Type 82077AA FDC found"); - } - /* FDC_PARTID cmd succeeded */ - switch (stat[0] >> 5) { - case 0x0: - /* i82078SL or i82078-1. The SL part cannot run at - * 2Mbps (the SL and -1 dies are identical; they are - * speed graded after production, according to Intel). - * Some SL's can be detected by doing a SAVE cmd and - * look at bit 7 of the first byte (the SEL3V# bit). - * If it is 0, the part runs off 3Volts, and hence it - * is a SL. - */ - cmd[0] = FDC_SAVE; - if(fdc_issue_command(cmd, 1, stat, 16) < 0) { - TRACE(ft_t_err, "FDC_SAVE failed. Dunno why"); - /* guess we better claim the fdc to be a i82078 */ - TRACE_ABORT(i82078, - ft_t_warn, - "Type i82078 FDC (i suppose) found"); - } - if ((stat[0] & FDC_SEL3V_BIT)) { - /* fdc running off 5Volts; Pray that it's a i82078-1 - */ - TRACE_ABORT(i82078_1, ft_t_warn, - "Type i82078-1 or 5Volt i82078SL FDC found"); - } - TRACE_ABORT(i82078, ft_t_warn, - "Type 3Volt i82078SL FDC (1Mbps) found"); - case 0x1: - case 0x2: /* S82078B */ - /* The '78B isn't '78 compatible. Detect it as a '77AA */ - TRACE_ABORT(i82077AA, ft_t_warn, "Type i82077AA FDC found"); - case 0x3: /* NSC PC8744 core; used in several super-IO chips */ - TRACE_ABORT(i82077AA, - ft_t_warn, "Type 82077AA compatible FDC found"); - default: - TRACE(ft_t_warn, "A previously undetected FDC found"); - TRACE_ABORT(i82077AA, ft_t_warn, - "Treating it as a 82077AA. Please report partid= %d", - stat[0]); - } /* switch(stat[ 0] >> 5) */ - TRACE_EXIT no_fdc; -} - -static int fdc_request_regions(void) -{ - TRACE_FUN(ft_t_flow); - - if (ft_mach2 || ft_probe_fc10) { - if (!request_region(fdc.sra, 8, "fdc (ft)")) { -#ifndef BROKEN_FLOPPY_DRIVER - TRACE_EXIT -EBUSY; -#else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); -#endif - } - } else { - if (!request_region(fdc.sra, 6, "fdc (ft)")) { -#ifndef BROKEN_FLOPPY_DRIVER - TRACE_EXIT -EBUSY; -#else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); -#endif - } - if (!request_region(fdc.sra + 7, 1, "fdc (ft)")) { -#ifndef BROKEN_FLOPPY_DRIVER - release_region(fdc.sra, 6); - TRACE_EXIT -EBUSY; -#else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra + 7); -#endif - } - } - TRACE_EXIT 0; -} - -void fdc_release_regions(void) -{ - TRACE_FUN(ft_t_flow); - - if (fdc.sra != 0) { - if (fdc.dor2 != 0) { - release_region(fdc.sra, 8); - } else { - release_region(fdc.sra, 6); - release_region(fdc.dir, 1); - } - } - TRACE_EXIT; -} - -static int fdc_config_regs(unsigned int fdc_base, - unsigned int fdc_irq, - unsigned int fdc_dma) -{ - TRACE_FUN(ft_t_flow); - - fdc.irq = fdc_irq; - fdc.dma = fdc_dma; - fdc.sra = fdc_base; - fdc.srb = fdc_base + 1; - fdc.dor = fdc_base + 2; - fdc.tdr = fdc_base + 3; - fdc.msr = fdc.dsr = fdc_base + 4; - fdc.fifo = fdc_base + 5; - fdc.dir = fdc.ccr = fdc_base + 7; - fdc.dor2 = (ft_mach2 || ft_probe_fc10) ? fdc_base + 6 : 0; - TRACE_CATCH(fdc_request_regions(), fdc.sra = 0); - TRACE_EXIT 0; -} - -static int fdc_config(void) -{ - static int already_done; - TRACE_FUN(ft_t_any); - - if (already_done) { - TRACE_CATCH(fdc_request_regions(),); - *(fdc.hook) = fdc_isr; /* hook our handler in */ - TRACE_EXIT 0; - } - if (ft_probe_fc10) { - int fc_type; - - TRACE_CATCH(fdc_config_regs(ft_fdc_base, - ft_fdc_irq, ft_fdc_dma),); - fc_type = fc10_enable(); - if (fc_type != 0) { - TRACE(ft_t_warn, "FC-%c0 controller found", '0' + fc_type); - fdc.type = fc10; - fdc.hook = &do_ftape; - *(fdc.hook) = fdc_isr; /* hook our handler in */ - already_done = 1; - TRACE_EXIT 0; - } else { - TRACE(ft_t_warn, "FC-10/20 controller not found"); - fdc_release_regions(); - fdc.type = no_fdc; - ft_probe_fc10 = 0; - ft_fdc_base = 0x3f0; - ft_fdc_irq = 6; - ft_fdc_dma = 2; - } - } - TRACE(ft_t_warn, "fdc base: 0x%x, irq: %d, dma: %d", - ft_fdc_base, ft_fdc_irq, ft_fdc_dma); - TRACE_CATCH(fdc_config_regs(ft_fdc_base, ft_fdc_irq, ft_fdc_dma),); - fdc.hook = &do_ftape; - *(fdc.hook) = fdc_isr; /* hook our handler in */ - already_done = 1; - TRACE_EXIT 0; -} - -static irqreturn_t ftape_interrupt(int irq, void *dev_id) -{ - void (*handler) (void) = *fdc.hook; - int handled = 0; - TRACE_FUN(ft_t_any); - - *fdc.hook = NULL; - if (handler) { - handled = 1; - handler(); - } else { - TRACE(ft_t_bug, "Unexpected ftape interrupt"); - } - TRACE_EXIT IRQ_RETVAL(handled); -} - -static int fdc_grab_irq_and_dma(void) -{ - TRACE_FUN(ft_t_any); - - if (fdc.hook == &do_ftape) { - /* Get fast interrupt handler. - */ - if (request_irq(fdc.irq, ftape_interrupt, - IRQF_DISABLED, "ft", ftape_id)) { - TRACE_ABORT(-EIO, ft_t_bug, - "Unable to grab IRQ%d for ftape driver", - fdc.irq); - } - if (request_dma(fdc.dma, ftape_id)) { - free_irq(fdc.irq, ftape_id); - TRACE_ABORT(-EIO, ft_t_bug, - "Unable to grab DMA%d for ftape driver", - fdc.dma); - } - } - if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { - /* Using same dma channel or irq as standard fdc, need - * to disable the dma-gate on the std fdc. This - * couldn't be done in the floppy driver as some - * laptops are using the dma-gate to enter a low power - * or even suspended state :-( - */ - outb_p(FDC_RESET_NOT, 0x3f2); - TRACE(ft_t_noise, "DMA-gate on standard fdc disabled"); - } - TRACE_EXIT 0; -} - -int fdc_release_irq_and_dma(void) -{ - TRACE_FUN(ft_t_any); - - if (fdc.hook == &do_ftape) { - disable_dma(fdc.dma); /* just in case... */ - free_dma(fdc.dma); - free_irq(fdc.irq, ftape_id); - } - if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { - /* Using same dma channel as standard fdc, need to - * disable the dma-gate on the std fdc. This couldn't - * be done in the floppy driver as some laptops are - * using the dma-gate to enter a low power or even - * suspended state :-( - */ - outb_p(FDC_RESET_NOT | FDC_DMA_MODE, 0x3f2); - TRACE(ft_t_noise, "DMA-gate on standard fdc enabled again"); - } - TRACE_EXIT 0; -} - -int fdc_init(void) -{ - TRACE_FUN(ft_t_any); - - /* find a FDC to use */ - TRACE_CATCH(fdc_config(),); - TRACE_CATCH(fdc_grab_irq_and_dma(), fdc_release_regions()); - ftape_motor = 0; - fdc_catch_stray_interrupts(0); /* clear number of awainted - * stray interrupte - */ - fdc_catch_stray_interrupts(1); /* one always comes (?) */ - TRACE(ft_t_flow, "resetting fdc"); - fdc_set_seek_rate(2); /* use nominal QIC step rate */ - fdc_reset(); /* init fdc & clear track counters */ - if (fdc.type == no_fdc) { /* no FC-10 or FC-20 found */ - fdc.type = fdc_probe(); - fdc_reset(); /* update with new knowledge */ - } - if (fdc.type == no_fdc) { - fdc_release_irq_and_dma(); - fdc_release_regions(); - TRACE_EXIT -ENXIO; - } - if (fdc.type >= i82077) { - if (fdc_fifo_enable() < 0) { - TRACE(ft_t_warn, "couldn't enable fdc fifo !"); - } else { - TRACE(ft_t_flow, "fdc fifo enabled and locked"); - } - } - TRACE_EXIT 0; -} diff --git a/drivers/char/ftape/lowlevel/fdc-io.h b/drivers/char/ftape/lowlevel/fdc-io.h deleted file mode 100644 index 7ec3c72178bb..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-io.h +++ /dev/null @@ -1,252 +0,0 @@ -#ifndef _FDC_IO_H -#define _FDC_IO_H - -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-io.h,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/05 19:18:06 $ - * - * This file contains the declarations for the low level - * functions that communicate with the floppy disk controller, - * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for - * Linux. - */ - -#include - -#include "../lowlevel/ftape-bsm.h" - -#define FDC_SK_BIT (0x20) -#define FDC_MT_BIT (0x80) - -#define FDC_READ (FD_READ & ~(FDC_SK_BIT | FDC_MT_BIT)) -#define FDC_WRITE (FD_WRITE & ~FDC_MT_BIT) -#define FDC_READ_DELETED (0x4c) -#define FDC_WRITE_DELETED (0x49) -#define FDC_VERIFY (0x56) -#define FDC_READID (0x4a) -#define FDC_SENSED (0x04) -#define FDC_SENSEI (FD_SENSEI) -#define FDC_FORMAT (FD_FORMAT) -#define FDC_RECAL (FD_RECALIBRATE) -#define FDC_SEEK (FD_SEEK) -#define FDC_SPECIFY (FD_SPECIFY) -#define FDC_RECALIBR (FD_RECALIBRATE) -#define FDC_VERSION (FD_VERSION) -#define FDC_PERPEND (FD_PERPENDICULAR) -#define FDC_DUMPREGS (FD_DUMPREGS) -#define FDC_LOCK (FD_LOCK) -#define FDC_UNLOCK (FD_UNLOCK) -#define FDC_CONFIGURE (FD_CONFIGURE) -#define FDC_DRIVE_SPEC (0x8e) /* i82078 has this (any others?) */ -#define FDC_PARTID (0x18) /* i82078 has this */ -#define FDC_SAVE (0x2e) /* i82078 has this (any others?) */ -#define FDC_RESTORE (0x4e) /* i82078 has this (any others?) */ - -#define FDC_STATUS_MASK (STATUS_BUSY | STATUS_DMA | STATUS_DIR | STATUS_READY) -#define FDC_DATA_READY (STATUS_READY) -#define FDC_DATA_OUTPUT (STATUS_DIR) -#define FDC_DATA_READY_MASK (STATUS_READY | STATUS_DIR) -#define FDC_DATA_OUT_READY (STATUS_READY | STATUS_DIR) -#define FDC_DATA_IN_READY (STATUS_READY) -#define FDC_BUSY (STATUS_BUSY) -#define FDC_CLK48_BIT (0x80) -#define FDC_SEL3V_BIT (0x40) - -#define ST0_INT_MASK (ST0_INTR) -#define FDC_INT_NORMAL (ST0_INTR & 0x00) -#define FDC_INT_ABNORMAL (ST0_INTR & 0x40) -#define FDC_INT_INVALID (ST0_INTR & 0x80) -#define FDC_INT_READYCH (ST0_INTR & 0xC0) -#define ST0_SEEK_END (ST0_SE) -#define ST3_TRACK_0 (ST3_TZ) - -#define FDC_RESET_NOT (0x04) -#define FDC_DMA_MODE (0x08) -#define FDC_MOTOR_0 (0x10) -#define FDC_MOTOR_1 (0x20) - -typedef struct { - void (**hook) (void); /* our wedge into the isr */ - enum { - no_fdc, i8272, i82077, i82077AA, fc10, - i82078, i82078_1 - } type; /* FDC type */ - unsigned int irq; /* FDC irq nr */ - unsigned int dma; /* FDC dma channel nr */ - __u16 sra; /* Status register A (PS/2 only) */ - __u16 srb; /* Status register B (PS/2 only) */ - __u16 dor; /* Digital output register */ - __u16 tdr; /* Tape Drive Register (82077SL-1 & - 82078 only) */ - __u16 msr; /* Main Status Register */ - __u16 dsr; /* Datarate Select Register (8207x only) */ - __u16 fifo; /* Data register / Fifo on 8207x */ - __u16 dir; /* Digital Input Register */ - __u16 ccr; /* Configuration Control Register */ - __u16 dor2; /* Alternate dor on MACH-2 controller, - also used with FC-10, meaning unknown */ -} fdc_config_info; - -typedef enum { - fdc_data_rate_250 = 2, - fdc_data_rate_300 = 1, /* any fdc in default configuration */ - fdc_data_rate_500 = 0, - fdc_data_rate_1000 = 3, - fdc_data_rate_2000 = 1, /* i82078-1: when using Data Rate Table #2 */ -} fdc_data_rate_type; - -typedef enum { - fdc_idle = 0, - fdc_reading_data = FDC_READ, - fdc_seeking = FDC_SEEK, - fdc_writing_data = FDC_WRITE, - fdc_deleting = FDC_WRITE_DELETED, - fdc_reading_id = FDC_READID, - fdc_recalibrating = FDC_RECAL, - fdc_formatting = FDC_FORMAT, - fdc_verifying = FDC_VERIFY -} fdc_mode_enum; - -typedef enum { - waiting = 0, - reading, - writing, - formatting, - verifying, - deleting, - done, - error, - mmapped, -} buffer_state_enum; - -typedef struct { - __u8 *address; - volatile buffer_state_enum status; - volatile __u8 *ptr; - volatile unsigned int bytes; - volatile unsigned int segment_id; - - /* bitmap for remainder of segment not yet handled. - * one bit set for each bad sector that must be skipped. - */ - volatile SectorMap bad_sector_map; - - /* bitmap with bad data blocks in data buffer. - * the errors in this map may be retried. - */ - volatile SectorMap soft_error_map; - - /* bitmap with bad data blocks in data buffer - * the errors in this map may not be retried. - */ - volatile SectorMap hard_error_map; - - /* retry counter for soft errors. - */ - volatile int retry; - - /* sectors to skip on retry ??? - */ - volatile unsigned int skip; - - /* nr of data blocks in data buffer - */ - volatile unsigned int data_offset; - - /* offset in segment for first sector to be handled. - */ - volatile unsigned int sector_offset; - - /* size of cluster of good sectors to be handled. - */ - volatile unsigned int sector_count; - - /* size of remaining part of segment to be handled. - */ - volatile unsigned int remaining; - - /* points to next segment (contiguous) to be handled, - * or is zero if no read-ahead is allowed. - */ - volatile unsigned int next_segment; - - /* flag being set if deleted data was read. - */ - volatile int deleted; - - /* floppy coordinates of first sector in segment */ - volatile __u8 head; - volatile __u8 cyl; - volatile __u8 sect; - - /* gap to use when formatting */ - __u8 gap3; - /* flag set when buffer is mmaped */ - int mmapped; -} buffer_struct; - -/* - * fdc-io.c defined public variables - */ -extern volatile fdc_mode_enum fdc_mode; -extern int fdc_setup_error; /* outdated ??? */ -extern wait_queue_head_t ftape_wait_intr; -extern volatile int ftape_current_cylinder; /* track nr FDC thinks we're on */ -extern volatile __u8 fdc_head; /* FDC head */ -extern volatile __u8 fdc_cyl; /* FDC track */ -extern volatile __u8 fdc_sect; /* FDC sector */ -extern fdc_config_info fdc; /* FDC hardware configuration */ - -extern unsigned int ft_fdc_base; -extern unsigned int ft_fdc_irq; -extern unsigned int ft_fdc_dma; -extern unsigned int ft_fdc_threshold; -extern unsigned int ft_fdc_rate_limit; -extern int ft_probe_fc10; -extern int ft_mach2; -/* - * fdc-io.c defined public functions - */ -extern void fdc_catch_stray_interrupts(int count); -extern int fdc_ready_wait(unsigned int timeout); -extern int fdc_command(const __u8 * cmd_data, int cmd_len); -extern int fdc_result(__u8 * res_data, int res_len); -extern int fdc_interrupt_wait(unsigned int time); -extern int fdc_seek(int track); -extern int fdc_sense_drive_status(int *st3); -extern void fdc_motor(int motor); -extern void fdc_reset(void); -extern void fdc_disable(void); -extern int fdc_fifo_threshold(__u8 threshold, - int *fifo_state, int *lock_state, int *fifo_thr); -extern void fdc_wait_calibrate(void); -extern int fdc_sense_interrupt_status(int *st0, int *current_cylinder); -extern void fdc_save_drive_specs(void); -extern void fdc_restore_drive_specs(void); -extern int fdc_set_data_rate(int rate); -extern void fdc_set_write_precomp(int precomp); -extern int fdc_release_irq_and_dma(void); -extern void fdc_release_regions(void); -extern int fdc_init(void); -extern int fdc_setup_read_write(buffer_struct * buff, __u8 operation); -extern int fdc_setup_formatting(buffer_struct * buff); -#endif diff --git a/drivers/char/ftape/lowlevel/fdc-isr.c b/drivers/char/ftape/lowlevel/fdc-isr.c deleted file mode 100644 index ad2bc733ae1b..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-isr.c +++ /dev/null @@ -1,1170 +0,0 @@ -/* - * Copyright (C) 1994-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-isr.c,v $ - * $Revision: 1.9 $ - * $Date: 1997/10/17 23:01:53 $ - * - * This file contains the interrupt service routine and - * associated code for the QIC-40/80/3010/3020 floppy-tape driver - * "ftape" for Linux. - */ - -#include -#include - -#define volatile /* */ - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-isr.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-calibr.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ -volatile int ft_expected_stray_interrupts; -volatile int ft_interrupt_seen; -volatile int ft_seek_completed; -volatile int ft_hide_interrupt; -/* Local vars. - */ -typedef enum { - no_error = 0, id_am_error = 0x01, id_crc_error = 0x02, - data_am_error = 0x04, data_crc_error = 0x08, - no_data_error = 0x10, overrun_error = 0x20, -} error_cause; -static int stop_read_ahead; - - -static void print_error_cause(int cause) -{ - TRACE_FUN(ft_t_any); - - switch (cause) { - case no_data_error: - TRACE(ft_t_noise, "no data error"); - break; - case id_am_error: - TRACE(ft_t_noise, "id am error"); - break; - case id_crc_error: - TRACE(ft_t_noise, "id crc error"); - break; - case data_am_error: - TRACE(ft_t_noise, "data am error"); - break; - case data_crc_error: - TRACE(ft_t_noise, "data crc error"); - break; - case overrun_error: - TRACE(ft_t_noise, "overrun error"); - break; - default:; - } - TRACE_EXIT; -} - -static char *fdc_mode_txt(fdc_mode_enum mode) -{ - switch (mode) { - case fdc_idle: - return "fdc_idle"; - case fdc_reading_data: - return "fdc_reading_data"; - case fdc_seeking: - return "fdc_seeking"; - case fdc_writing_data: - return "fdc_writing_data"; - case fdc_reading_id: - return "fdc_reading_id"; - case fdc_recalibrating: - return "fdc_recalibrating"; - case fdc_formatting: - return "fdc_formatting"; - case fdc_verifying: - return "fdc_verifying"; - default: - return "unknown"; - } -} - -static inline error_cause decode_irq_cause(fdc_mode_enum mode, __u8 st[]) -{ - error_cause cause = no_error; - TRACE_FUN(ft_t_any); - - /* Valid st[], decode cause of interrupt. - */ - switch (st[0] & ST0_INT_MASK) { - case FDC_INT_NORMAL: - TRACE(ft_t_fdc_dma,"normal completion: %s",fdc_mode_txt(mode)); - break; - case FDC_INT_ABNORMAL: - TRACE(ft_t_flow, "abnormal completion %s", fdc_mode_txt(mode)); - TRACE(ft_t_fdc_dma, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x", - st[0], st[1], st[2]); - TRACE(ft_t_fdc_dma, - "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x", - st[3], st[4], st[5], st[6]); - if (st[1] & 0x01) { - if (st[2] & 0x01) { - cause = data_am_error; - } else { - cause = id_am_error; - } - } else if (st[1] & 0x20) { - if (st[2] & 0x20) { - cause = data_crc_error; - } else { - cause = id_crc_error; - } - } else if (st[1] & 0x04) { - cause = no_data_error; - } else if (st[1] & 0x10) { - cause = overrun_error; - } - print_error_cause(cause); - break; - case FDC_INT_INVALID: - TRACE(ft_t_flow, "invalid completion %s", fdc_mode_txt(mode)); - break; - case FDC_INT_READYCH: - if (st[0] & ST0_SEEK_END) { - TRACE(ft_t_flow, "drive poll completed"); - } else { - TRACE(ft_t_flow, "ready change %s",fdc_mode_txt(mode)); - } - break; - default: - break; - } - TRACE_EXIT cause; -} - -static void update_history(error_cause cause) -{ - switch (cause) { - case id_am_error: - ft_history.id_am_errors++; - break; - case id_crc_error: - ft_history.id_crc_errors++; - break; - case data_am_error: - ft_history.data_am_errors++; - break; - case data_crc_error: - ft_history.data_crc_errors++; - break; - case overrun_error: - ft_history.overrun_errors++; - break; - case no_data_error: - ft_history.no_data_errors++; - break; - default:; - } -} - -static void skip_bad_sector(buffer_struct * buff) -{ - TRACE_FUN(ft_t_any); - - /* Mark sector as soft error and skip it - */ - if (buff->remaining > 0) { - ++buff->sector_offset; - ++buff->data_offset; - --buff->remaining; - buff->ptr += FT_SECTOR_SIZE; - buff->bad_sector_map >>= 1; - } else { - /* Hey, what is this????????????? C code: if we shift - * more than 31 bits, we get no shift. That's bad!!!!!! - */ - ++buff->sector_offset; /* hack for error maps */ - TRACE(ft_t_warn, "skipping last sector in segment"); - } - TRACE_EXIT; -} - -static void update_error_maps(buffer_struct * buff, unsigned int error_offset) -{ - int hard = 0; - TRACE_FUN(ft_t_any); - - if (buff->retry < FT_SOFT_RETRIES) { - buff->soft_error_map |= (1 << error_offset); - } else { - buff->hard_error_map |= (1 << error_offset); - buff->soft_error_map &= ~buff->hard_error_map; - buff->retry = -1; /* will be set to 0 in setup_segment */ - hard = 1; - } - TRACE(ft_t_noise, "sector %d : %s error\n" - KERN_INFO "hard map: 0x%08lx\n" - KERN_INFO "soft map: 0x%08lx", - FT_SECTOR(error_offset), hard ? "hard" : "soft", - (long) buff->hard_error_map, (long) buff->soft_error_map); - TRACE_EXIT; -} - -static void print_progress(buffer_struct *buff, error_cause cause) -{ - TRACE_FUN(ft_t_any); - - switch (cause) { - case no_error: - TRACE(ft_t_flow,"%d Sector(s) transferred", buff->sector_count); - break; - case no_data_error: - TRACE(ft_t_flow, "Sector %d not found", - FT_SECTOR(buff->sector_offset)); - break; - case overrun_error: - /* got an overrun error on the first byte, must be a - * hardware problem - */ - TRACE(ft_t_bug, - "Unexpected error: failing DMA or FDC controller ?"); - break; - case data_crc_error: - TRACE(ft_t_flow, "Error in sector %d", - FT_SECTOR(buff->sector_offset - 1)); - break; - case id_crc_error: - case id_am_error: - case data_am_error: - TRACE(ft_t_flow, "Error in sector %d", - FT_SECTOR(buff->sector_offset)); - break; - default: - TRACE(ft_t_flow, "Unexpected error at sector %d", - FT_SECTOR(buff->sector_offset)); - break; - } - TRACE_EXIT; -} - -/* - * Error cause: Amount xferred: Action: - * - * id_am_error 0 mark bad and skip - * id_crc_error 0 mark bad and skip - * data_am_error 0 mark bad and skip - * data_crc_error % 1024 mark bad and skip - * no_data_error 0 retry on write - * mark bad and skip on read - * overrun_error [ 0..all-1 ] mark bad and skip - * no_error all continue - */ - -/* the arg `sector' is returned by the fdc and tells us at which sector we - * are positioned at (relative to starting sector of segment) - */ -static void determine_verify_progress(buffer_struct *buff, - error_cause cause, - __u8 sector) -{ - TRACE_FUN(ft_t_any); - - if (cause == no_error && sector == 1) { - buff->sector_offset = FT_SECTORS_PER_SEGMENT; - buff->remaining = 0; - if (TRACE_LEVEL >= ft_t_flow) { - print_progress(buff, cause); - } - } else { - buff->sector_offset = sector - buff->sect; - buff->remaining = FT_SECTORS_PER_SEGMENT - buff->sector_offset; - TRACE(ft_t_noise, "%ssector offset: 0x%04x", - (cause == no_error) ? "unexpected " : "", - buff->sector_offset); - switch (cause) { - case overrun_error: - break; -#if 0 - case no_data_error: - buff->retry = FT_SOFT_RETRIES; - if (buff->hard_error_map && - buff->sector_offset > 1 && - (buff->hard_error_map & - (1 << (buff->sector_offset-2)))) { - buff->retry --; - } - break; -#endif - default: - buff->retry = FT_SOFT_RETRIES; - break; - } - if (TRACE_LEVEL >= ft_t_flow) { - print_progress(buff, cause); - } - /* Sector_offset points to the problem area Now adjust - * sector_offset so it always points one past he failing - * sector. I.e. skip the bad sector. - */ - ++buff->sector_offset; - --buff->remaining; - update_error_maps(buff, buff->sector_offset - 1); - } - TRACE_EXIT; -} - -static void determine_progress(buffer_struct *buff, - error_cause cause, - __u8 sector) -{ - unsigned int dma_residue; - TRACE_FUN(ft_t_any); - - /* Using less preferred order of disable_dma and - * get_dma_residue because this seems to fail on at least one - * system if reversed! - */ - dma_residue = get_dma_residue(fdc.dma); - disable_dma(fdc.dma); - if (cause != no_error || dma_residue != 0) { - TRACE(ft_t_noise, "%sDMA residue: 0x%04x", - (cause == no_error) ? "unexpected " : "", - dma_residue); - /* adjust to actual value: */ - if (dma_residue == 0) { - /* this happens sometimes with overrun errors. - * I don't know whether we could ignore the - * overrun error. Play save. - */ - buff->sector_count --; - } else { - buff->sector_count -= ((dma_residue + - (FT_SECTOR_SIZE - 1)) / - FT_SECTOR_SIZE); - } - } - /* Update var's influenced by the DMA operation. - */ - if (buff->sector_count > 0) { - buff->sector_offset += buff->sector_count; - buff->data_offset += buff->sector_count; - buff->ptr += (buff->sector_count * - FT_SECTOR_SIZE); - buff->remaining -= buff->sector_count; - buff->bad_sector_map >>= buff->sector_count; - } - if (TRACE_LEVEL >= ft_t_flow) { - print_progress(buff, cause); - } - if (cause != no_error) { - if (buff->remaining == 0) { - TRACE(ft_t_warn, "foo?\n" - KERN_INFO "count : %d\n" - KERN_INFO "offset: %d\n" - KERN_INFO "soft : %08x\n" - KERN_INFO "hard : %08x", - buff->sector_count, - buff->sector_offset, - buff->soft_error_map, - buff->hard_error_map); - } - /* Sector_offset points to the problem area, except if we got - * a data_crc_error. In that case it points one past the - * failing sector. - * - * Now adjust sector_offset so it always points one past he - * failing sector. I.e. skip the bad sector. - */ - if (cause != data_crc_error) { - skip_bad_sector(buff); - } - update_error_maps(buff, buff->sector_offset - 1); - } - TRACE_EXIT; -} - -static int calc_steps(int cmd) -{ - if (ftape_current_cylinder > cmd) { - return ftape_current_cylinder - cmd; - } else { - return ftape_current_cylinder + cmd; - } -} - -static void pause_tape(int retry, int mode) -{ - int result; - __u8 out[3] = {FDC_SEEK, ft_drive_sel, 0}; - TRACE_FUN(ft_t_any); - - /* We'll use a raw seek command to get the tape to rewind and - * stop for a retry. - */ - ++ft_history.rewinds; - if (qic117_cmds[ftape_current_command].non_intr) { - TRACE(ft_t_warn, "motion command may be issued too soon"); - } - if (retry && (mode == fdc_reading_data || - mode == fdc_reading_id || - mode == fdc_verifying)) { - ftape_current_command = QIC_MICRO_STEP_PAUSE; - ftape_might_be_off_track = 1; - } else { - ftape_current_command = QIC_PAUSE; - } - out[2] = calc_steps(ftape_current_command); - result = fdc_command(out, 3); /* issue QIC_117 command */ - ftape_current_cylinder = out[ 2]; - if (result < 0) { - TRACE(ft_t_noise, "qic-pause failed, status = %d", result); - } else { - ft_location.known = 0; - ft_runner_status = idle; - ft_hide_interrupt = 1; - ftape_tape_running = 0; - } - TRACE_EXIT; -} - -static void continue_xfer(buffer_struct *buff, - fdc_mode_enum mode, - unsigned int skip) -{ - int write = 0; - TRACE_FUN(ft_t_any); - - if (mode == fdc_writing_data || mode == fdc_deleting) { - write = 1; - } - /* This part can be removed if it never happens - */ - if (skip > 0 && - (ft_runner_status != running || - (write && (buff->status != writing)) || - (!write && (buff->status != reading && - buff->status != verifying)))) { - TRACE(ft_t_err, "unexpected runner/buffer state %d/%d", - ft_runner_status, buff->status); - buff->status = error; - /* finish this buffer: */ - (void)ftape_next_buffer(ft_queue_head); - ft_runner_status = aborting; - fdc_mode = fdc_idle; - } else if (buff->remaining > 0 && ftape_calc_next_cluster(buff) > 0) { - /* still sectors left in current segment, continue - * with this segment - */ - if (fdc_setup_read_write(buff, mode) < 0) { - /* failed, abort operation - */ - buff->bytes = buff->ptr - buff->address; - buff->status = error; - /* finish this buffer: */ - (void)ftape_next_buffer(ft_queue_head); - ft_runner_status = aborting; - fdc_mode = fdc_idle; - } - } else { - /* current segment completed - */ - unsigned int last_segment = buff->segment_id; - int eot = ((last_segment + 1) % ft_segments_per_track) == 0; - unsigned int next = buff->next_segment; /* 0 means stop ! */ - - buff->bytes = buff->ptr - buff->address; - buff->status = done; - buff = ftape_next_buffer(ft_queue_head); - if (eot) { - /* finished last segment on current track, - * can't continue - */ - ft_runner_status = logical_eot; - fdc_mode = fdc_idle; - TRACE_EXIT; - } - if (next <= 0) { - /* don't continue with next segment - */ - TRACE(ft_t_noise, "no %s allowed, stopping tape", - (write) ? "write next" : "read ahead"); - pause_tape(0, mode); - ft_runner_status = idle; /* not quite true until - * next irq - */ - TRACE_EXIT; - } - /* continue with next segment - */ - if (buff->status != waiting) { - TRACE(ft_t_noise, "all input buffers %s, pausing tape", - (write) ? "empty" : "full"); - pause_tape(0, mode); - ft_runner_status = idle; /* not quite true until - * next irq - */ - TRACE_EXIT; - } - if (write && next != buff->segment_id) { - TRACE(ft_t_noise, - "segments out of order, aborting write"); - ft_runner_status = do_abort; - fdc_mode = fdc_idle; - TRACE_EXIT; - } - ftape_setup_new_segment(buff, next, 0); - if (stop_read_ahead) { - buff->next_segment = 0; - stop_read_ahead = 0; - } - if (ftape_calc_next_cluster(buff) == 0 || - fdc_setup_read_write(buff, mode) != 0) { - TRACE(ft_t_err, "couldn't start %s-ahead", - write ? "write" : "read"); - ft_runner_status = do_abort; - fdc_mode = fdc_idle; - } else { - /* keep on going */ - switch (ft_driver_state) { - case reading: buff->status = reading; break; - case verifying: buff->status = verifying; break; - case writing: buff->status = writing; break; - case deleting: buff->status = deleting; break; - default: - TRACE(ft_t_err, - "BUG: ft_driver_state %d should be one out of " - "{reading, writing, verifying, deleting}", - ft_driver_state); - buff->status = write ? writing : reading; - break; - } - } - } - TRACE_EXIT; -} - -static void retry_sector(buffer_struct *buff, - int mode, - unsigned int skip) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_noise, "%s error, will retry", - (mode == fdc_writing_data || mode == fdc_deleting) ? "write" : "read"); - pause_tape(1, mode); - ft_runner_status = aborting; - buff->status = error; - buff->skip = skip; - TRACE_EXIT; -} - -static unsigned int find_resume_point(buffer_struct *buff) -{ - int i = 0; - SectorMap mask; - SectorMap map; - TRACE_FUN(ft_t_any); - - /* This function is to be called after all variables have been - * updated to point past the failing sector. - * If there are any soft errors before the failing sector, - * find the first soft error and return the sector offset. - * Otherwise find the last hard error. - * Note: there should always be at least one hard or soft error ! - */ - if (buff->sector_offset < 1 || buff->sector_offset > 32) { - TRACE(ft_t_bug, "BUG: sector_offset = %d", - buff->sector_offset); - TRACE_EXIT 0; - } - if (buff->sector_offset >= 32) { /* C-limitation on shift ! */ - mask = 0xffffffff; - } else { - mask = (1 << buff->sector_offset) - 1; - } - map = buff->soft_error_map & mask; - if (map) { - while ((map & (1 << i)) == 0) { - ++i; - } - TRACE(ft_t_noise, "at sector %d", FT_SECTOR(i)); - } else { - map = buff->hard_error_map & mask; - i = buff->sector_offset - 1; - if (map) { - while ((map & (1 << i)) == 0) { - --i; - } - TRACE(ft_t_noise, "after sector %d", FT_SECTOR(i)); - ++i; /* first sector after last hard error */ - } else { - TRACE(ft_t_bug, "BUG: no soft or hard errors"); - } - } - TRACE_EXIT i; -} - -/* check possible dma residue when formatting, update position record in - * buffer struct. This is, of course, modelled after determine_progress(), but - * we don't need to set up for retries because the format process cannot be - * interrupted (except at the end of the tape track). - */ -static int determine_fmt_progress(buffer_struct *buff, error_cause cause) -{ - unsigned int dma_residue; - TRACE_FUN(ft_t_any); - - /* Using less preferred order of disable_dma and - * get_dma_residue because this seems to fail on at least one - * system if reversed! - */ - dma_residue = get_dma_residue(fdc.dma); - disable_dma(fdc.dma); - if (cause != no_error || dma_residue != 0) { - TRACE(ft_t_info, "DMA residue = 0x%04x", dma_residue); - fdc_mode = fdc_idle; - switch(cause) { - case no_error: - ft_runner_status = aborting; - buff->status = idle; - break; - case overrun_error: - /* got an overrun error on the first byte, must be a - * hardware problem - */ - TRACE(ft_t_bug, - "Unexpected error: failing DMA controller ?"); - ft_runner_status = do_abort; - buff->status = error; - break; - default: - TRACE(ft_t_noise, "Unexpected error at segment %d", - buff->segment_id); - ft_runner_status = do_abort; - buff->status = error; - break; - } - TRACE_EXIT -EIO; /* can only retry entire track in format mode - */ - } - /* Update var's influenced by the DMA operation. - */ - buff->ptr += FT_SECTORS_PER_SEGMENT * 4; - buff->bytes -= FT_SECTORS_PER_SEGMENT * 4; - buff->remaining -= FT_SECTORS_PER_SEGMENT; - buff->segment_id ++; /* done with segment */ - TRACE_EXIT 0; -} - -/* - * Continue formatting, switch buffers if there is no data left in - * current buffer. This is, of course, modelled after - * continue_xfer(), but we don't need to set up for retries because - * the format process cannot be interrupted (except at the end of the - * tape track). - */ -static void continue_formatting(buffer_struct *buff) -{ - TRACE_FUN(ft_t_any); - - if (buff->remaining <= 0) { /* no space left in dma buffer */ - unsigned int next = buff->next_segment; - - if (next == 0) { /* end of tape track */ - buff->status = done; - ft_runner_status = logical_eot; - fdc_mode = fdc_idle; - TRACE(ft_t_noise, "Done formatting track %d", - ft_location.track); - TRACE_EXIT; - } - /* - * switch to next buffer! - */ - buff->status = done; - buff = ftape_next_buffer(ft_queue_head); - - if (buff->status != waiting || next != buff->segment_id) { - goto format_setup_error; - } - } - if (fdc_setup_formatting(buff) < 0) { - goto format_setup_error; - } - buff->status = formatting; - TRACE(ft_t_fdc_dma, "Formatting segment %d on track %d", - buff->segment_id, ft_location.track); - TRACE_EXIT; - format_setup_error: - ft_runner_status = do_abort; - fdc_mode = fdc_idle; - buff->status = error; - TRACE(ft_t_err, "Error setting up for segment %d on track %d", - buff->segment_id, ft_location.track); - TRACE_EXIT; - -} - -/* this handles writing, read id, reading and formatting - */ -static void handle_fdc_busy(buffer_struct *buff) -{ - static int no_data_error_count; - int retry = 0; - error_cause cause; - __u8 in[7]; - int skip; - fdc_mode_enum fmode = fdc_mode; - TRACE_FUN(ft_t_any); - - if (fdc_result(in, 7) < 0) { /* better get it fast ! */ - TRACE(ft_t_err, - "Probably fatal error during FDC Result Phase\n" - KERN_INFO - "drive may hang until (power on) reset :-("); - /* what to do next ???? - */ - TRACE_EXIT; - } - cause = decode_irq_cause(fdc_mode, in); -#ifdef TESTING - { int i; - for (i = 0; i < (int)ft_nr_buffers; ++i) - TRACE(ft_t_any, "buffer[%d] status: %d, segment_id: %d", - i, ft_buffer[i]->status, ft_buffer[i]->segment_id); - } -#endif - if (fmode == fdc_reading_data && ft_driver_state == verifying) { - fmode = fdc_verifying; - } - switch (fmode) { - case fdc_verifying: - if (ft_runner_status == aborting || - ft_runner_status == do_abort) { - TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode)); - break; - } - if (buff->retry > 0) { - TRACE(ft_t_flow, "this is retry nr %d", buff->retry); - } - switch (cause) { - case no_error: - no_data_error_count = 0; - determine_verify_progress(buff, cause, in[5]); - if (in[2] & 0x40) { - /* This should not happen when verifying - */ - TRACE(ft_t_warn, - "deleted data in segment %d/%d", - buff->segment_id, - FT_SECTOR(buff->sector_offset - 1)); - buff->remaining = 0; /* abort transfer */ - buff->hard_error_map = EMPTY_SEGMENT; - skip = 1; - } else { - skip = 0; - } - continue_xfer(buff, fdc_mode, skip); - break; - case no_data_error: - no_data_error_count ++; - case overrun_error: - retry ++; - case id_am_error: - case id_crc_error: - case data_am_error: - case data_crc_error: - determine_verify_progress(buff, cause, in[5]); - if (cause == no_data_error) { - if (no_data_error_count >= 2) { - TRACE(ft_t_warn, - "retrying because of successive " - "no data errors"); - no_data_error_count = 0; - } else { - retry --; - } - } else { - no_data_error_count = 0; - } - if (retry) { - skip = find_resume_point(buff); - } else { - skip = buff->sector_offset; - } - if (retry && skip < 32) { - retry_sector(buff, fdc_mode, skip); - } else { - continue_xfer(buff, fdc_mode, skip); - } - update_history(cause); - break; - default: - /* Don't know why this could happen - * but find out. - */ - determine_verify_progress(buff, cause, in[5]); - retry_sector(buff, fdc_mode, 0); - TRACE(ft_t_err, "Error: unexpected error"); - break; - } - break; - case fdc_reading_data: -#ifdef TESTING - /* I'm sorry, but: NOBODY ever used this trace - * messages for ages. I guess that Bas was the last person - * that ever really used this (thank you, between the lines) - */ - if (cause == no_error) { - TRACE(ft_t_flow,"reading segment %d",buff->segment_id); - } else { - TRACE(ft_t_noise, "error reading segment %d", - buff->segment_id); - TRACE(ft_t_noise, "\n" - KERN_INFO - "IRQ:C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x\n" - KERN_INFO - "BUF:C: 0x%02x, H: 0x%02x, R: 0x%02x", - in[3], in[4], in[5], in[6], - buff->cyl, buff->head, buff->sect); - } -#endif - if (ft_runner_status == aborting || - ft_runner_status == do_abort) { - TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode)); - break; - } - if (buff->bad_sector_map == FAKE_SEGMENT) { - /* This condition occurs when reading a `fake' - * sector that's not accessible. Doesn't - * really matter as we would have ignored it - * anyway ! - * - * Chance is that we're past the next segment - * now, so the next operation may fail and - * result in a retry. - */ - buff->remaining = 0; /* skip failing sector */ - /* buff->ptr = buff->address; */ - /* fake success: */ - continue_xfer(buff, fdc_mode, 1); - /* trace calls are expensive: place them AFTER - * the real stuff has been done. - * - */ - TRACE(ft_t_noise, "skipping empty segment %d (read), size? %d", - buff->segment_id, buff->ptr - buff->address); - TRACE_EXIT; - } - if (buff->retry > 0) { - TRACE(ft_t_flow, "this is retry nr %d", buff->retry); - } - switch (cause) { - case no_error: - determine_progress(buff, cause, in[5]); - if (in[2] & 0x40) { - /* Handle deleted data in header segments. - * Skip segment and force read-ahead. - */ - TRACE(ft_t_warn, - "deleted data in segment %d/%d", - buff->segment_id, - FT_SECTOR(buff->sector_offset - 1)); - buff->deleted = 1; - buff->remaining = 0;/*abort transfer */ - buff->soft_error_map |= - (-1L << buff->sector_offset); - if (buff->segment_id == 0) { - /* stop on next segment */ - stop_read_ahead = 1; - } - /* force read-ahead: */ - buff->next_segment = - buff->segment_id + 1; - skip = (FT_SECTORS_PER_SEGMENT - - buff->sector_offset); - } else { - skip = 0; - } - continue_xfer(buff, fdc_mode, skip); - break; - case no_data_error: - /* Tape started too far ahead of or behind the - * right sector. This may also happen in the - * middle of a segment ! - * - * Handle no-data as soft error. If next - * sector fails too, a retry (with needed - * reposition) will follow. - */ - retry ++; - case id_am_error: - case id_crc_error: - case data_am_error: - case data_crc_error: - case overrun_error: - retry += (buff->soft_error_map != 0 || - buff->hard_error_map != 0); - determine_progress(buff, cause, in[5]); -#if 1 || defined(TESTING) - if (cause == overrun_error) retry ++; -#endif - if (retry) { - skip = find_resume_point(buff); - } else { - skip = buff->sector_offset; - } - /* Try to resume with next sector on single - * errors (let ecc correct it), but retry on - * no_data (we'll be past the target when we - * get here so we cannot retry) or on - * multiple errors (reduce chance on ecc - * failure). - */ - /* cH: 23/02/97: if the last sector in the - * segment was a hard error, then there is - * no sense in a retry. This occasion seldom - * occurs but ... @:³²¸`@%&§$ - */ - if (retry && skip < 32) { - retry_sector(buff, fdc_mode, skip); - } else { - continue_xfer(buff, fdc_mode, skip); - } - update_history(cause); - break; - default: - /* Don't know why this could happen - * but find out. - */ - determine_progress(buff, cause, in[5]); - retry_sector(buff, fdc_mode, 0); - TRACE(ft_t_err, "Error: unexpected error"); - break; - } - break; - case fdc_reading_id: - if (cause == no_error) { - fdc_cyl = in[3]; - fdc_head = in[4]; - fdc_sect = in[5]; - TRACE(ft_t_fdc_dma, - "id read: C: 0x%02x, H: 0x%02x, R: 0x%02x", - fdc_cyl, fdc_head, fdc_sect); - } else { /* no valid information, use invalid sector */ - fdc_cyl = fdc_head = fdc_sect = 0; - TRACE(ft_t_flow, "Didn't find valid sector Id"); - } - fdc_mode = fdc_idle; - break; - case fdc_deleting: - case fdc_writing_data: -#ifdef TESTING - if (cause == no_error) { - TRACE(ft_t_flow, "writing segment %d", buff->segment_id); - } else { - TRACE(ft_t_noise, "error writing segment %d", - buff->segment_id); - } -#endif - if (ft_runner_status == aborting || - ft_runner_status == do_abort) { - TRACE(ft_t_flow, "aborting %s",fdc_mode_txt(fdc_mode)); - break; - } - if (buff->retry > 0) { - TRACE(ft_t_flow, "this is retry nr %d", buff->retry); - } - if (buff->bad_sector_map == FAKE_SEGMENT) { - /* This condition occurs when trying to write to a - * `fake' sector that's not accessible. Doesn't really - * matter as it isn't used anyway ! Might be located - * at wrong segment, then we'll fail on the next - * segment. - */ - TRACE(ft_t_noise, "skipping empty segment (write)"); - buff->remaining = 0; /* skip failing sector */ - /* fake success: */ - continue_xfer(buff, fdc_mode, 1); - break; - } - switch (cause) { - case no_error: - determine_progress(buff, cause, in[5]); - continue_xfer(buff, fdc_mode, 0); - break; - case no_data_error: - case id_am_error: - case id_crc_error: - case data_am_error: - case overrun_error: - update_history(cause); - determine_progress(buff, cause, in[5]); - skip = find_resume_point(buff); - retry_sector(buff, fdc_mode, skip); - break; - default: - if (in[1] & 0x02) { - TRACE(ft_t_err, "media not writable"); - } else { - TRACE(ft_t_bug, "unforeseen write error"); - } - fdc_mode = fdc_idle; - break; - } - break; /* fdc_deleting || fdc_writing_data */ - case fdc_formatting: - /* The interrupt comes after formatting a segment. We then - * have to set up QUICKLY for the next segment. But - * afterwards, there is plenty of time. - */ - switch (cause) { - case no_error: - /* would like to keep most of the formatting stuff - * outside the isr code, but timing is too critical - */ - if (determine_fmt_progress(buff, cause) >= 0) { - continue_formatting(buff); - } - break; - case no_data_error: - case id_am_error: - case id_crc_error: - case data_am_error: - case overrun_error: - default: - determine_fmt_progress(buff, cause); - update_history(cause); - if (in[1] & 0x02) { - TRACE(ft_t_err, "media not writable"); - } else { - TRACE(ft_t_bug, "unforeseen write error"); - } - break; - } /* cause */ - break; - default: - TRACE(ft_t_warn, "Warning: unexpected irq during: %s", - fdc_mode_txt(fdc_mode)); - fdc_mode = fdc_idle; - break; - } - TRACE_EXIT; -} - -/* FDC interrupt service routine. - */ -void fdc_isr(void) -{ - static int isr_active; -#ifdef TESTING - unsigned int t0 = ftape_timestamp(); -#endif - TRACE_FUN(ft_t_any); - - if (isr_active++) { - --isr_active; - TRACE(ft_t_bug, "BUG: nested interrupt, not good !"); - *fdc.hook = fdc_isr; /* hook our handler into the fdc - * code again - */ - TRACE_EXIT; - } - sti(); - if (inb_p(fdc.msr) & FDC_BUSY) { /* Entering Result Phase */ - ft_hide_interrupt = 0; - handle_fdc_busy(ftape_get_buffer(ft_queue_head)); - if (ft_runner_status == do_abort) { - /* cease operation, remember tape position - */ - TRACE(ft_t_flow, "runner aborting"); - ft_runner_status = aborting; - ++ft_expected_stray_interrupts; - } - } else { /* !FDC_BUSY */ - /* clear interrupt, cause should be gotten by issuing - * a Sense Interrupt Status command. - */ - if (fdc_mode == fdc_recalibrating || fdc_mode == fdc_seeking) { - if (ft_hide_interrupt) { - int st0; - int pcn; - - if (fdc_sense_interrupt_status(&st0, &pcn) < 0) - TRACE(ft_t_err, - "sense interrupt status failed"); - ftape_current_cylinder = pcn; - TRACE(ft_t_flow, "handled hidden interrupt"); - } - ft_seek_completed = 1; - fdc_mode = fdc_idle; - } else if (!waitqueue_active(&ftape_wait_intr)) { - if (ft_expected_stray_interrupts == 0) { - TRACE(ft_t_warn, "unexpected stray interrupt"); - } else { - TRACE(ft_t_flow, "expected stray interrupt"); - --ft_expected_stray_interrupts; - } - } else { - if (fdc_mode == fdc_reading_data || - fdc_mode == fdc_verifying || - fdc_mode == fdc_writing_data || - fdc_mode == fdc_deleting || - fdc_mode == fdc_formatting || - fdc_mode == fdc_reading_id) { - if (inb_p(fdc.msr) & FDC_BUSY) { - TRACE(ft_t_bug, - "***** FDC failure, busy too late"); - } else { - TRACE(ft_t_bug, - "***** FDC failure, no busy"); - } - } else { - TRACE(ft_t_fdc_dma, "awaited stray interrupt"); - } - } - ft_hide_interrupt = 0; - } - /* Handle sleep code. - */ - if (!ft_hide_interrupt) { - ft_interrupt_seen ++; - if (waitqueue_active(&ftape_wait_intr)) { - wake_up_interruptible(&ftape_wait_intr); - } - } else { - TRACE(ft_t_flow, "hiding interrupt while %s", - waitqueue_active(&ftape_wait_intr) ? "waiting":"active"); - } -#ifdef TESTING - t0 = ftape_timediff(t0, ftape_timestamp()); - if (t0 >= 1000) { - /* only tell us about long calls */ - TRACE(ft_t_noise, "isr() duration: %5d usec", t0); - } -#endif - *fdc.hook = fdc_isr; /* hook our handler into the fdc code again */ - --isr_active; - TRACE_EXIT; -} diff --git a/drivers/char/ftape/lowlevel/fdc-isr.h b/drivers/char/ftape/lowlevel/fdc-isr.h deleted file mode 100644 index 065aa978942d..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-isr.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _FDC_ISR_H -#define _FDC_ISR_H - -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-isr.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:07 $ - * - * This file declares the global variables necessary to - * synchronize the interrupt service routine (isr) with the - * remainder of the QIC-40/80/3010/3020 floppy-tape driver - * "ftape" for Linux. - */ - -/* - * fdc-isr.c defined public variables - */ -extern volatile int ft_expected_stray_interrupts; /* masks stray interrupts */ -extern volatile int ft_seek_completed; /* flag set by isr */ -extern volatile int ft_interrupt_seen; /* flag set by isr */ -extern volatile int ft_hide_interrupt; /* flag set by isr */ - -/* - * fdc-io.c defined public functions - */ -extern void fdc_isr(void); - -/* - * A kernel hook that steals one interrupt from the floppy - * driver (Should be fixed when the new fdc driver gets ready) - * See the linux kernel source files: - * drivers/block/floppy.c & drivers/block/blk.h - * for the details. - */ -extern void (*do_floppy) (void); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.c b/drivers/char/ftape/lowlevel/ftape-bsm.c deleted file mode 100644 index d1a301cc344f..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-bsm.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (C) 1994-1996 Bas Laarhoven, - * (C) 1996-1997 Claus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-bsm.c,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/05 19:15:15 $ - * - * This file contains the bad-sector map handling code for - * the QIC-117 floppy tape driver for Linux. - * QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented. - */ - -#include - -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-bsm.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" - -/* Global vars. - */ - -/* Local vars. - */ -static __u8 *bad_sector_map; -static SectorCount *bsm_hash_ptr; - -typedef enum { - forward, backward -} mode_type; - -#if 0 -static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map); -#endif - -#if 0 -/* fix_tape converts a normal QIC-80 tape into a 'wide' tape. - * For testing purposes only ! - */ -void fix_tape(__u8 * buffer, ft_format_type new_code) -{ - static __u8 list[BAD_SECTOR_MAP_SIZE]; - SectorMap *src_ptr = (SectorMap *) list; - __u8 *dst_ptr = bad_sector_map; - SectorMap map; - unsigned int sector = 1; - int i; - - if (format_code != fmt_var && format_code != fmt_big) { - memcpy(list, bad_sector_map, sizeof(list)); - memset(bad_sector_map, 0, sizeof(bad_sector_map)); - while ((__u8 *) src_ptr - list < sizeof(list)) { - map = *src_ptr++; - if (map == EMPTY_SEGMENT) { - *(SectorMap *) dst_ptr = 0x800000 + sector; - dst_ptr += 3; - sector += SECTORS_PER_SEGMENT; - } else { - for (i = 0; i < SECTORS_PER_SEGMENT; ++i) { - if (map & 1) { - *(SewctorMap *) dst_ptr = sector; - dst_ptr += 3; - } - map >>= 1; - ++sector; - } - } - } - } - bad_sector_map_changed = 1; - *(buffer + 4) = new_code; /* put new format code */ - if (format_code != fmt_var && new_code == fmt_big) { - PUT4(buffer, FT_6_HSEG_1, (__u32)GET2(buffer, 6)); - PUT4(buffer, FT_6_HSEG_2, (__u32)GET2(buffer, 8)); - PUT4(buffer, FT_6_FRST_SEG, (__u32)GET2(buffer, 10)); - PUT4(buffer, FT_6_LAST_SEG, (__u32)GET2(buffer, 12)); - memset(buffer+6, '\0', 8); - } - format_code = new_code; -} - -#endif - -/* given buffer that contains a header segment, find the end of - * of the bsm list - */ -__u8 * ftape_find_end_of_bsm_list(__u8 * address) -{ - __u8 *ptr = address + FT_HEADER_END; /* start of bsm list */ - __u8 *limit = address + FT_SEGMENT_SIZE; - while (ptr + 2 < limit) { - if (ptr[0] || ptr[1] || ptr[2]) { - ptr += 3; - } else { - return ptr; - } - } - return NULL; -} - -static inline void put_sector(SectorCount *ptr, unsigned int sector) -{ - ptr->bytes[0] = sector & 0xff; - sector >>= 8; - ptr->bytes[1] = sector & 0xff; - sector >>= 8; - ptr->bytes[2] = sector & 0xff; -} - -static inline unsigned int get_sector(SectorCount *ptr) -{ -#if 1 - unsigned int sector; - - sector = ptr->bytes[0]; - sector += ptr->bytes[1] << 8; - sector += ptr->bytes[2] << 16; - - return sector; -#else - /* GET4 gets the next four bytes in Intel little endian order - * and converts them to host byte order and handles unaligned - * access. - */ - return (GET4(ptr, 0) & 0x00ffffff); /* back to host byte order */ -#endif -} - -static void bsm_debug_fake(void) -{ - /* for testing of bad sector handling at end of tape - */ -#if 0 - ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 3, - 0x000003e0; - ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 2, - 0xff3fffff; - ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 1, - 0xffffe000; -#endif - /* Enable to test bad sector handling - */ -#if 0 - ftape_put_bad_sector_entry(30, 0xfffffffe) - ftape_put_bad_sector_entry(32, 0x7fffffff); - ftape_put_bad_sector_entry(34, 0xfffeffff); - ftape_put_bad_sector_entry(36, 0x55555555); - ftape_put_bad_sector_entry(38, 0xffffffff); - ftape_put_bad_sector_entry(50, 0xffff0000); - ftape_put_bad_sector_entry(51, 0xffffffff); - ftape_put_bad_sector_entry(52, 0xffffffff); - ftape_put_bad_sector_entry(53, 0x0000ffff); -#endif - /* Enable when testing multiple volume tar dumps. - */ -#if 0 - { - int i; - - for (i = ft_first_data_segment; - i <= ft_last_data_segment - 7; ++i) { - ftape_put_bad_sector_entry(i, EMPTY_SEGMENT); - } - } -#endif - /* Enable when testing bit positions in *_error_map - */ -#if 0 - { - int i; - - for (i = first_data_segment; i <= last_data_segment; ++i) { - ftape_put_bad_sector_entry(i, - ftape_get_bad_sector_entry(i) - | 0x00ff00ff); - } - } -#endif -} - -static void print_bad_sector_map(void) -{ - unsigned int good_sectors; - unsigned int total_bad = 0; - int i; - TRACE_FUN(ft_t_flow); - - if (ft_format_code == fmt_big || - ft_format_code == fmt_var || - ft_format_code == fmt_1100ft) { - SectorCount *ptr = (SectorCount *)bad_sector_map; - unsigned int sector; - __u16 *ptr16; - - while((sector = get_sector(ptr++)) != 0) { - if ((ft_format_code == fmt_big || - ft_format_code == fmt_var) && - sector & 0x800000) { - total_bad += FT_SECTORS_PER_SEGMENT - 3; - TRACE(ft_t_noise, "bad segment at sector: %6d", - sector & 0x7fffff); - } else { - ++total_bad; - TRACE(ft_t_noise, "bad sector: %6d", sector); - } - } - /* Display old ftape's end-of-file marks - */ - ptr16 = (__u16*)ptr; - while ((sector = get_unaligned(ptr16++)) != 0) { - TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d", - sector, get_unaligned(ptr16++)); - } - } else { /* fixed size format */ - for (i = ft_first_data_segment; - i < (int)(ft_segments_per_track * ft_tracks_per_tape); ++i) { - SectorMap map = ((SectorMap *) bad_sector_map)[i]; - - if (map) { - TRACE(ft_t_noise, - "bsm for segment %4d: 0x%08x", i, (unsigned int)map); - total_bad += ((map == EMPTY_SEGMENT) - ? FT_SECTORS_PER_SEGMENT - 3 - : count_ones(map)); - } - } - } - good_sectors = - ((ft_segments_per_track * ft_tracks_per_tape - ft_first_data_segment) - * (FT_SECTORS_PER_SEGMENT - 3)) - total_bad; - TRACE(ft_t_info, "%d Kb usable on this tape", good_sectors); - if (total_bad == 0) { - TRACE(ft_t_info, - "WARNING: this tape has no bad blocks registered !"); - } else { - TRACE(ft_t_info, "%d bad sectors", total_bad); - } - TRACE_EXIT; -} - - -void ftape_extract_bad_sector_map(__u8 * buffer) -{ - TRACE_FUN(ft_t_any); - - /* Fill the bad sector map with the contents of buffer. - */ - if (ft_format_code == fmt_var || ft_format_code == fmt_big) { - /* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed - * sector log but use this area to extend the bad sector map. - */ - bad_sector_map = &buffer[FT_HEADER_END]; - } else { - /* non-wide QIC-80 tapes have a failed sector log area that - * mustn't be included in the bad sector map. - */ - bad_sector_map = &buffer[FT_FSL + FT_FSL_SIZE]; - } - if (ft_format_code == fmt_1100ft || - ft_format_code == fmt_var || - ft_format_code == fmt_big) { - bsm_hash_ptr = (SectorCount *)bad_sector_map; - } else { - bsm_hash_ptr = NULL; - } - bsm_debug_fake(); - if (TRACE_LEVEL >= ft_t_info) { - print_bad_sector_map(); - } - TRACE_EXIT; -} - -static inline SectorMap cvt2map(unsigned int sector) -{ - return 1 << (((sector & 0x7fffff) - 1) % FT_SECTORS_PER_SEGMENT); -} - -static inline int cvt2segment(unsigned int sector) -{ - return ((sector & 0x7fffff) - 1) / FT_SECTORS_PER_SEGMENT; -} - -static int forward_seek_entry(int segment_id, - SectorCount **ptr, - SectorMap *map) -{ - unsigned int sector; - int segment; - - do { - sector = get_sector((*ptr)++); - segment = cvt2segment(sector); - } while (sector != 0 && segment < segment_id); - (*ptr) --; /* point to first sector >= segment_id */ - /* Get all sectors in segment_id - */ - if (sector == 0 || segment != segment_id) { - *map = 0; - return 0; - } else if ((sector & 0x800000) && - (ft_format_code == fmt_var || ft_format_code == fmt_big)) { - *map = EMPTY_SEGMENT; - return FT_SECTORS_PER_SEGMENT; - } else { - int count = 1; - SectorCount *tmp_ptr = (*ptr) + 1; - - *map = cvt2map(sector); - while ((sector = get_sector(tmp_ptr++)) != 0 && - (segment = cvt2segment(sector)) == segment_id) { - *map |= cvt2map(sector); - ++count; - } - return count; - } -} - -static int backwards_seek_entry(int segment_id, - SectorCount **ptr, - SectorMap *map) -{ - unsigned int sector; - int segment; /* max unsigned int */ - - if (*ptr <= (SectorCount *)bad_sector_map) { - *map = 0; - return 0; - } - do { - sector = get_sector(--(*ptr)); - segment = cvt2segment(sector); - } while (*ptr > (SectorCount *)bad_sector_map && segment > segment_id); - if (segment > segment_id) { /* at start of list, no entry found */ - *map = 0; - return 0; - } else if (segment < segment_id) { - /* before smaller entry, adjust for overshoot */ - (*ptr) ++; - *map = 0; - return 0; - } else if ((sector & 0x800000) && - (ft_format_code == fmt_big || ft_format_code == fmt_var)) { - *map = EMPTY_SEGMENT; - return FT_SECTORS_PER_SEGMENT; - } else { /* get all sectors in segment_id */ - int count = 1; - - *map = cvt2map(sector); - while(*ptr > (SectorCount *)bad_sector_map) { - sector = get_sector(--(*ptr)); - segment = cvt2segment(sector); - if (segment != segment_id) { - break; - } - *map |= cvt2map(sector); - ++count; - } - if (segment < segment_id) { - (*ptr) ++; - } - return count; - } -} - -#if 0 -static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map) -{ - SectorCount *ptr = (SectorCount *)bad_sector_map; - int count; - int new_count; - SectorMap map; - TRACE_FUN(ft_t_any); - - if (ft_format_code == fmt_1100ft || - ft_format_code == fmt_var || - ft_format_code == fmt_big) { - count = forward_seek_entry(segment_id, &ptr, &map); - new_count = count_ones(new_map); - /* If format code == 4 put empty segment instead of 32 - * bad sectors. - */ - if (ft_format_code == fmt_var || ft_format_code == fmt_big) { - if (new_count == FT_SECTORS_PER_SEGMENT) { - new_count = 1; - } - if (count == FT_SECTORS_PER_SEGMENT) { - count = 1; - } - } - if (count != new_count) { - /* insert (or delete if < 0) new_count - count - * entries. Move trailing part of list - * including terminating 0. - */ - SectorCount *hi_ptr = ptr; - - do { - } while (get_sector(hi_ptr++) != 0); - /* Note: ptr is of type byte *, and each bad sector - * consumes 3 bytes. - */ - memmove(ptr + new_count, ptr + count, - (size_t)(hi_ptr - (ptr + count))*sizeof(SectorCount)); - } - TRACE(ft_t_noise, "putting map 0x%08x at %p, segment %d", - (unsigned int)new_map, ptr, segment_id); - if (new_count == 1 && new_map == EMPTY_SEGMENT) { - put_sector(ptr++, (0x800001 + - segment_id * - FT_SECTORS_PER_SEGMENT)); - } else { - int i = 0; - - while (new_map) { - if (new_map & 1) { - put_sector(ptr++, - 1 + segment_id * - FT_SECTORS_PER_SEGMENT + i); - } - ++i; - new_map >>= 1; - } - } - } else { - ((SectorMap *) bad_sector_map)[segment_id] = new_map; - } - TRACE_EXIT; -} -#endif /* 0 */ - -SectorMap ftape_get_bad_sector_entry(int segment_id) -{ - if (ft_used_header_segment == -1) { - /* When reading header segment we'll need a blank map. - */ - return 0; - } else if (bsm_hash_ptr != NULL) { - /* Invariants: - * map - mask value returned on last call. - * bsm_hash_ptr - points to first sector greater or equal to - * first sector in last_referenced segment. - * last_referenced - segment id used in the last call, - * sector and map belong to this id. - * This code is designed for sequential access and retries. - * For true random access it may have to be redesigned. - */ - static int last_reference = -1; - static SectorMap map; - - if (segment_id > last_reference) { - /* Skip all sectors before segment_id - */ - forward_seek_entry(segment_id, &bsm_hash_ptr, &map); - } else if (segment_id < last_reference) { - /* Skip backwards until begin of buffer or - * first sector in segment_id - */ - backwards_seek_entry(segment_id, &bsm_hash_ptr, &map); - } /* segment_id == last_reference : keep map */ - last_reference = segment_id; - return map; - } else { - return ((SectorMap *) bad_sector_map)[segment_id]; - } -} - -/* This is simply here to prevent us from overwriting other kernel - * data. Writes will result in NULL Pointer dereference. - */ -void ftape_init_bsm(void) -{ - bad_sector_map = NULL; - bsm_hash_ptr = NULL; -} diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.h b/drivers/char/ftape/lowlevel/ftape-bsm.h deleted file mode 100644 index ed45465af4d4..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-bsm.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef _FTAPE_BSM_H -#define _FTAPE_BSM_H - -/* - * Copyright (C) 1994-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-bsm.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:07 $ - * - * This file contains definitions for the bad sector map handling - * routines for the QIC-117 floppy-tape driver for Linux. - */ - -#include -#include - -#define EMPTY_SEGMENT (0xffffffff) -#define FAKE_SEGMENT (0xfffffffe) - -/* maximum (format code 4) bad sector map size (bytes). - */ -#define BAD_SECTOR_MAP_SIZE (29 * SECTOR_SIZE - 256) - -/* format code 4 bad sector entry, ftape uses this - * internally for all format codes - */ -typedef __u32 SectorMap; -/* variable and 1100 ft bad sector map entry. These three bytes represent - * a single sector address measured from BOT. - */ -typedef struct NewSectorMap { - __u8 bytes[3]; -} SectorCount; - - -/* - * ftape-bsm.c defined global vars. - */ - -/* - * ftape-bsm.c defined global functions. - */ -extern void update_bad_sector_map(__u8 * buffer); -extern void ftape_extract_bad_sector_map(__u8 * buffer); -extern SectorMap ftape_get_bad_sector_entry(int segment_id); -extern __u8 *ftape_find_end_of_bsm_list(__u8 * address); -extern void ftape_init_bsm(void); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.c b/drivers/char/ftape/lowlevel/ftape-buffer.c deleted file mode 100644 index c706ff162771..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-buffer.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-buffer.c,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/16 23:33:11 $ - * - * This file contains the allocator/dealloctor for ftape's dynamic dma - * buffer. - */ - -#include -#include -#include -#include - -#include -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-buffer.h" - -/* DMA'able memory allocation stuff. - */ - -static inline void *dmaalloc(size_t size) -{ - unsigned long addr; - - if (size == 0) { - return NULL; - } - addr = __get_dma_pages(GFP_KERNEL, get_order(size)); - if (addr) { - struct page *page; - - for (page = virt_to_page(addr); page < virt_to_page(addr+size); page++) - SetPageReserved(page); - } - return (void *)addr; -} - -static inline void dmafree(void *addr, size_t size) -{ - if (size > 0) { - struct page *page; - - for (page = virt_to_page((unsigned long)addr); - page < virt_to_page((unsigned long)addr+size); page++) - ClearPageReserved(page); - free_pages((unsigned long) addr, get_order(size)); - } -} - -static int add_one_buffer(void) -{ - TRACE_FUN(ft_t_flow); - - if (ft_nr_buffers >= FT_MAX_NR_BUFFERS) { - TRACE_EXIT -ENOMEM; - } - ft_buffer[ft_nr_buffers] = kmalloc(sizeof(buffer_struct), GFP_KERNEL); - if (ft_buffer[ft_nr_buffers] == NULL) { - TRACE_EXIT -ENOMEM; - } - memset(ft_buffer[ft_nr_buffers], 0, sizeof(buffer_struct)); - ft_buffer[ft_nr_buffers]->address = dmaalloc(FT_BUFF_SIZE); - if (ft_buffer[ft_nr_buffers]->address == NULL) { - kfree(ft_buffer[ft_nr_buffers]); - ft_buffer[ft_nr_buffers] = NULL; - TRACE_EXIT -ENOMEM; - } - ft_nr_buffers ++; - TRACE(ft_t_info, "buffer nr #%d @ %p, dma area @ %p", - ft_nr_buffers, - ft_buffer[ft_nr_buffers-1], - ft_buffer[ft_nr_buffers-1]->address); - TRACE_EXIT 0; -} - -static void del_one_buffer(void) -{ - TRACE_FUN(ft_t_flow); - if (ft_nr_buffers > 0) { - TRACE(ft_t_info, "releasing buffer nr #%d @ %p, dma area @ %p", - ft_nr_buffers, - ft_buffer[ft_nr_buffers-1], - ft_buffer[ft_nr_buffers-1]->address); - ft_nr_buffers --; - dmafree(ft_buffer[ft_nr_buffers]->address, FT_BUFF_SIZE); - kfree(ft_buffer[ft_nr_buffers]); - ft_buffer[ft_nr_buffers] = NULL; - } - TRACE_EXIT; -} - -int ftape_set_nr_buffers(int cnt) -{ - int delta = cnt - ft_nr_buffers; - TRACE_FUN(ft_t_flow); - - if (delta > 0) { - while (delta--) { - if (add_one_buffer() < 0) { - TRACE_EXIT -ENOMEM; - } - } - } else if (delta < 0) { - while (delta++) { - del_one_buffer(); - } - } - ftape_zap_read_buffers(); - TRACE_EXIT 0; -} diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.h b/drivers/char/ftape/lowlevel/ftape-buffer.h deleted file mode 100644 index eec99cee8f82..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-buffer.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _FTAPE_BUFFER_H -#define _FTAPE_BUFFER_H - -/* - * Copyright (C) 1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-buffer.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:08 $ - * - * This file contains the allocator/dealloctor for ftape's dynamic dma - * buffer. - */ - -extern int ftape_set_nr_buffers(int cnt); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c deleted file mode 100644 index 8e50bfd35a52..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-calibr.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-calibr.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:08 $ - * - * GP calibration routine for processor speed dependent - * functions. - */ - -#include -#include -#include -#include -#if defined(__alpha__) -# include -#elif defined(__x86_64__) -# include -# include -#elif defined(__i386__) -# include -#endif -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-calibr.h" -#include "../lowlevel/fdc-io.h" - -#undef DEBUG - -#if !defined(__alpha__) && !defined(__i386__) && !defined(__x86_64__) -# error Ftape is not implemented for this architecture! -#endif - -#if defined(__alpha__) || defined(__x86_64__) -static unsigned long ps_per_cycle = 0; -#endif - -static spinlock_t calibr_lock; - -/* - * Note: On Intel PCs, the clock ticks at 100 Hz (HZ==100) which is - * too slow for certain timeouts (and that clock doesn't even tick - * when interrupts are disabled). For that reason, the 8254 timer is - * used directly to implement fine-grained timeouts. However, on - * Alpha PCs, the 8254 is *not* used to implement the clock tick - * (which is 1024 Hz, normally) and the 8254 timer runs at some - * "random" frequency (it seems to run at 18Hz, but it's not safe to - * rely on this value). Instead, we use the Alpha's "rpcc" - * instruction to read cycle counts. As this is a 32 bit counter, - * it will overflow only once per 30 seconds (on a 200MHz machine), - * which is plenty. - */ - -unsigned int ftape_timestamp(void) -{ -#if defined(__alpha__) - unsigned long r; - - asm volatile ("rpcc %0" : "=r" (r)); - return r; -#elif defined(__x86_64__) - unsigned long r; - rdtscl(r); - return r; -#elif defined(__i386__) - -/* - * Note that there is some time between counter underflowing and jiffies - * increasing, so the code below won't always give correct output. - * -Vojtech - */ - - unsigned long flags; - __u16 lo; - __u16 hi; - - spin_lock_irqsave(&calibr_lock, flags); - outb_p(0x00, 0x43); /* latch the count ASAP */ - lo = inb_p(0x40); /* read the latched count */ - lo |= inb(0x40) << 8; - hi = jiffies; - spin_unlock_irqrestore(&calibr_lock, flags); - return ((hi + 1) * (unsigned int) LATCH) - lo; /* downcounter ! */ -#endif -} - -static unsigned int short_ftape_timestamp(void) -{ -#if defined(__alpha__) || defined(__x86_64__) - return ftape_timestamp(); -#elif defined(__i386__) - unsigned int count; - unsigned long flags; - - spin_lock_irqsave(&calibr_lock, flags); - outb_p(0x00, 0x43); /* latch the count ASAP */ - count = inb_p(0x40); /* read the latched count */ - count |= inb(0x40) << 8; - spin_unlock_irqrestore(&calibr_lock, flags); - return (LATCH - count); /* normal: downcounter */ -#endif -} - -static unsigned int diff(unsigned int t0, unsigned int t1) -{ -#if defined(__alpha__) || defined(__x86_64__) - return (t1 - t0); -#elif defined(__i386__) - /* - * This is tricky: to work for both short and full ftape_timestamps - * we'll have to discriminate between these. - * If it _looks_ like short stamps with wrapping around we'll - * asume it are. This will generate a small error if it really - * was a (very large) delta from full ftape_timestamps. - */ - return (t1 <= t0 && t0 <= LATCH) ? t1 + LATCH - t0 : t1 - t0; -#endif -} - -static unsigned int usecs(unsigned int count) -{ -#if defined(__alpha__) || defined(__x86_64__) - return (ps_per_cycle * count) / 1000000UL; -#elif defined(__i386__) - return (10000 * count) / ((CLOCK_TICK_RATE + 50) / 100); -#endif -} - -unsigned int ftape_timediff(unsigned int t0, unsigned int t1) -{ - /* - * Calculate difference in usec for ftape_timestamp results t0 & t1. - * Note that on the i386 platform with short time-stamps, the - * maximum allowed timespan is 1/HZ or we'll lose ticks! - */ - return usecs(diff(t0, t1)); -} - -/* To get an indication of the I/O performance, - * measure the duration of the inb() function. - */ -static void time_inb(void) -{ - int i; - int t0, t1; - unsigned long flags; - int status; - TRACE_FUN(ft_t_any); - - spin_lock_irqsave(&calibr_lock, flags); - t0 = short_ftape_timestamp(); - for (i = 0; i < 1000; ++i) { - status = inb(fdc.msr); - } - t1 = short_ftape_timestamp(); - spin_unlock_irqrestore(&calibr_lock, flags); - TRACE(ft_t_info, "inb() duration: %d nsec", ftape_timediff(t0, t1)); - TRACE_EXIT; -} - -static void init_clock(void) -{ - TRACE_FUN(ft_t_any); - -#if defined(__x86_64__) - ps_per_cycle = 1000000000UL / cpu_khz; -#elif defined(__alpha__) - extern struct hwrpb_struct *hwrpb; - ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq; -#endif - TRACE_EXIT; -} - -/* - * Input: function taking int count as parameter. - * pointers to calculated calibration variables. - */ -void ftape_calibrate(char *name, - void (*fun) (unsigned int), - unsigned int *calibr_count, - unsigned int *calibr_time) -{ - static int first_time = 1; - int i; - unsigned int tc = 0; - unsigned int count; - unsigned int time; -#if defined(__i386__) - unsigned int old_tc = 0; - unsigned int old_count = 1; - unsigned int old_time = 1; -#endif - TRACE_FUN(ft_t_flow); - - if (first_time) { /* get idea of I/O performance */ - init_clock(); - time_inb(); - first_time = 0; - } - /* value of timeout must be set so that on very slow systems - * it will give a time less than one jiffy, and on - * very fast systems it'll give reasonable precision. - */ - - count = 40; - for (i = 0; i < 15; ++i) { - unsigned int t0; - unsigned int t1; - unsigned int once; - unsigned int multiple; - unsigned long flags; - - *calibr_count = - *calibr_time = count; /* set TC to 1 */ - spin_lock_irqsave(&calibr_lock, flags); - fun(0); /* dummy, get code into cache */ - t0 = short_ftape_timestamp(); - fun(0); /* overhead + one test */ - t1 = short_ftape_timestamp(); - once = diff(t0, t1); - t0 = short_ftape_timestamp(); - fun(count); /* overhead + count tests */ - t1 = short_ftape_timestamp(); - multiple = diff(t0, t1); - spin_unlock_irqrestore(&calibr_lock, flags); - time = ftape_timediff(0, multiple - once); - tc = (1000 * time) / (count - 1); - TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns", - usecs(once), count - 1, usecs(multiple), tc); -#if defined(__alpha__) || defined(__x86_64__) - /* - * Increase the calibration count exponentially until the - * calibration time exceeds 100 ms. - */ - if (time >= 100*1000) { - break; - } -#elif defined(__i386__) - /* - * increase the count until the resulting time nears 2/HZ, - * then the tc will drop sharply because we lose LATCH counts. - */ - if (tc <= old_tc / 2) { - time = old_time; - count = old_count; - break; - } - old_tc = tc; - old_count = count; - old_time = time; -#endif - count *= 2; - } - *calibr_count = count - 1; - *calibr_time = time; - TRACE(ft_t_info, "TC for `%s()' = %d nsec (at %d counts)", - name, (1000 * *calibr_time) / *calibr_count, *calibr_count); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.h b/drivers/char/ftape/lowlevel/ftape-calibr.h deleted file mode 100644 index 0c7e75246c7d..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-calibr.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _FTAPE_CALIBR_H -#define _FTAPE_CALIBR_H - -/* - * Copyright (C) 1993-1996 Bas Laarhoven. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-calibr.h,v $ - * $Revision: 1.1 $ - * $Date: 1997/09/19 09:05:26 $ - * - * This file contains a gp calibration routine for - * hardware dependent timeout functions. - */ - -extern void ftape_calibrate(char *name, - void (*fun) (unsigned int), - unsigned int *calibr_count, - unsigned int *calibr_time); -extern unsigned int ftape_timestamp(void); -extern unsigned int ftape_timediff(unsigned int t0, unsigned int t1); - -#endif /* _FTAPE_CALIBR_H */ diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.c b/drivers/char/ftape/lowlevel/ftape-ctl.c deleted file mode 100644 index 5d7c1ce92d59..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ctl.c +++ /dev/null @@ -1,896 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ctl.c,v $ - * $Revision: 1.4 $ - * $Date: 1997/11/11 14:37:44 $ - * - * This file contains the non-read/write ftape functions for the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include -#include -#include - -#include -#include -#include -#include - -/* ease porting between pre-2.4.x and later kernels */ -#define vma_get_pgoff(v) ((v)->vm_pgoff) - -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ -ftape_info ftape_status = { -/* vendor information */ - { 0, }, /* drive type */ -/* data rates */ - 500, /* used data rate */ - 500, /* drive max rate */ - 500, /* fdc max rate */ -/* drive selection, either FTAPE_SEL_A/B/C/D */ - -1, /* drive selection */ -/* flags set after decode the drive and tape status */ - 0, /* formatted */ - 1, /* no tape */ - 1, /* write protected */ - 1, /* new tape */ -/* values of last queried drive/tape status and error */ - {{0,}}, /* last error code */ - {{0,}}, /* drive status, configuration, tape status */ -/* cartridge geometry */ - 20, /* tracks_per_tape */ - 102, /* segments_per_track */ -/* location of header segments, etc. */ - -1, /* used_header_segment */ - -1, /* header_segment_1 */ - -1, /* header_segment_2 */ - -1, /* first_data_segment */ - -1, /* last_data_segment */ -/* the format code as stored in the header segment */ - fmt_normal, /* format code */ -/* the default for the qic std: unknown */ - -1, -/* is tape running? */ - idle, /* runner_state */ -/* is tape reading/writing/verifying/formatting/deleting */ - idle, /* driver state */ -/* flags fatal hardware error */ - 1, /* failure */ -/* history record */ - { 0, } /* history record */ -}; - -int ftape_segments_per_head = 1020; -int ftape_segments_per_cylinder = 4; -int ftape_init_drive_needed = 1; /* need to be global for ftape_reset_drive() - * in ftape-io.c - */ - -/* Local vars. - */ -static const vendor_struct vendors[] = QIC117_VENDORS; -static const wakeup_method methods[] = WAKEUP_METHODS; - -const ftape_info *ftape_get_status(void) -{ -#if defined(STATUS_PARANOYA) - static ftape_info get_status; - - get_status = ftape_status; - return &get_status; -#else - return &ftape_status; /* maybe return only a copy of it to assure - * read only access - */ -#endif -} - -static int ftape_not_operational(int status) -{ - /* return true if status indicates tape can not be used. - */ - return ((status ^ QIC_STATUS_CARTRIDGE_PRESENT) & - (QIC_STATUS_ERROR | - QIC_STATUS_CARTRIDGE_PRESENT | - QIC_STATUS_NEW_CARTRIDGE)); -} - -int ftape_seek_to_eot(void) -{ - int status; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); - while ((status & QIC_STATUS_AT_EOT) == 0) { - if (ftape_not_operational(status)) { - TRACE_EXIT -EIO; - } - TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_FORWARD, - ftape_timeout.rewind,&status),); - } - TRACE_EXIT 0; -} - -int ftape_seek_to_bot(void) -{ - int status; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); - while ((status & QIC_STATUS_AT_BOT) == 0) { - if (ftape_not_operational(status)) { - TRACE_EXIT -EIO; - } - TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_REVERSE, - ftape_timeout.rewind,&status),); - } - TRACE_EXIT 0; -} - -static int ftape_new_cartridge(void) -{ - ft_location.track = -1; /* force seek on first access */ - ftape_zap_read_buffers(); - ftape_zap_write_buffers(); - return 0; -} - -int ftape_abort_operation(void) -{ - int result = 0; - int status; - TRACE_FUN(ft_t_flow); - - if (ft_runner_status == running) { - TRACE(ft_t_noise, "aborting runner, waiting"); - - ft_runner_status = do_abort; - /* set timeout so that the tape will run to logical EOT - * if we missed the last sector and there are no queue pulses. - */ - result = ftape_dumb_stop(); - } - if (ft_runner_status != idle) { - if (ft_runner_status == do_abort) { - TRACE(ft_t_noise, "forcing runner abort"); - } - TRACE(ft_t_noise, "stopping tape"); - result = ftape_stop_tape(&status); - ft_location.known = 0; - ft_runner_status = idle; - } - ftape_reset_buffer(); - ftape_zap_read_buffers(); - ftape_set_state(idle); - TRACE_EXIT result; -} - -static int lookup_vendor_id(unsigned int vendor_id) -{ - int i = 0; - - while (vendors[i].vendor_id != vendor_id) { - if (++i >= NR_ITEMS(vendors)) { - return -1; - } - } - return i; -} - -static void ftape_detach_drive(void) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "disabling tape drive and fdc"); - ftape_put_drive_to_sleep(ft_drive_type.wake_up); - fdc_catch_stray_interrupts(1); /* one always comes */ - fdc_disable(); - fdc_release_irq_and_dma(); - fdc_release_regions(); - TRACE_EXIT; -} - -static void clear_history(void) -{ - ft_history.used = 0; - ft_history.id_am_errors = - ft_history.id_crc_errors = - ft_history.data_am_errors = - ft_history.data_crc_errors = - ft_history.overrun_errors = - ft_history.no_data_errors = - ft_history.retries = - ft_history.crc_errors = - ft_history.crc_failures = - ft_history.ecc_failures = - ft_history.corrected = - ft_history.defects = - ft_history.rewinds = 0; -} - -static int ftape_activate_drive(vendor_struct * drive_type) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - /* If we already know the drive type, wake it up. - * Else try to find out what kind of drive is attached. - */ - if (drive_type->wake_up != unknown_wake_up) { - TRACE(ft_t_flow, "enabling tape drive and fdc"); - result = ftape_wakeup_drive(drive_type->wake_up); - if (result < 0) { - TRACE(ft_t_err, "known wakeup method failed"); - } - } else { - wake_up_types method; - const ft_trace_t old_tracing = TRACE_LEVEL; - if (TRACE_LEVEL < ft_t_flow) { - SET_TRACE_LEVEL(ft_t_bug); - } - - /* Try to awaken the drive using all known methods. - * Lower tracing for a while. - */ - for (method=no_wake_up; method < NR_ITEMS(methods); ++method) { - drive_type->wake_up = method; -#ifdef CONFIG_FT_TWO_DRIVES - /* Test setup for dual drive configuration. - * /dev/rft2 uses mountain wakeup - * /dev/rft3 uses colorado wakeup - * Other systems will use the normal scheme. - */ - if ((ft_drive_sel < 2) || - (ft_drive_sel == 2 && method == FT_WAKE_UP_1) || - (ft_drive_sel == 3 && method == FT_WAKE_UP_2)) { - result=ftape_wakeup_drive(drive_type->wake_up); - } else { - result = -EIO; - } -#else - result = ftape_wakeup_drive(drive_type->wake_up); -#endif - if (result >= 0) { - TRACE(ft_t_warn, "drive wakeup method: %s", - methods[drive_type->wake_up].name); - break; - } - } - SET_TRACE_LEVEL(old_tracing); - - if (method >= NR_ITEMS(methods)) { - /* no response at all, cannot open this drive */ - drive_type->wake_up = unknown_wake_up; - TRACE(ft_t_err, "no tape drive found !"); - result = -ENODEV; - } - } - TRACE_EXIT result; -} - -static int ftape_get_drive_status(void) -{ - int result; - int status; - TRACE_FUN(ft_t_flow); - - ft_no_tape = ft_write_protected = 0; - /* Tape drive is activated now. - * First clear error status if present. - */ - do { - result = ftape_ready_wait(ftape_timeout.reset, &status); - if (result < 0) { - if (result == -ETIME) { - TRACE(ft_t_err, "ftape_ready_wait timeout"); - } else if (result == -EINTR) { - TRACE(ft_t_err, "ftape_ready_wait aborted"); - } else { - TRACE(ft_t_err, "ftape_ready_wait failed"); - } - TRACE_EXIT -EIO; - } - /* Clear error condition (drive is ready !) - */ - if (status & QIC_STATUS_ERROR) { - unsigned int error; - qic117_cmd_t command; - - TRACE(ft_t_err, "error status set"); - result = ftape_report_error(&error, &command, 1); - if (result < 0) { - TRACE(ft_t_err, - "report_error_code failed: %d", result); - /* hope it's working next time */ - ftape_reset_drive(); - TRACE_EXIT -EIO; - } else if (error != 0) { - TRACE(ft_t_noise, "error code : %d", error); - TRACE(ft_t_noise, "error command: %d", command); - } - } - if (status & QIC_STATUS_NEW_CARTRIDGE) { - unsigned int error; - qic117_cmd_t command; - const ft_trace_t old_tracing = TRACE_LEVEL; - SET_TRACE_LEVEL(ft_t_bug); - - /* Undocumented feature: Must clear (not present!) - * error here or we'll fail later. - */ - ftape_report_error(&error, &command, 1); - - SET_TRACE_LEVEL(old_tracing); - TRACE(ft_t_info, "status: new cartridge"); - ft_new_tape = 1; - } else { - ft_new_tape = 0; - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - } while (status & QIC_STATUS_ERROR); - - ft_no_tape = !(status & QIC_STATUS_CARTRIDGE_PRESENT); - ft_write_protected = (status & QIC_STATUS_WRITE_PROTECT) != 0; - if (ft_no_tape) { - TRACE(ft_t_warn, "no cartridge present"); - } else { - if (ft_write_protected) { - TRACE(ft_t_noise, "Write protected cartridge"); - } - } - TRACE_EXIT 0; -} - -static void ftape_log_vendor_id(void) -{ - int vendor_index; - TRACE_FUN(ft_t_flow); - - ftape_report_vendor_id(&ft_drive_type.vendor_id); - vendor_index = lookup_vendor_id(ft_drive_type.vendor_id); - if (ft_drive_type.vendor_id == UNKNOWN_VENDOR && - ft_drive_type.wake_up == wake_up_colorado) { - vendor_index = 0; - /* hack to get rid of all this mail */ - ft_drive_type.vendor_id = 0; - } - if (vendor_index < 0) { - /* Unknown vendor id, first time opening device. The - * drive_type remains set to type found at wakeup - * time, this will probably keep the driver operating - * for this new vendor. - */ - TRACE(ft_t_warn, "\n" - KERN_INFO "============ unknown vendor id ===========\n" - KERN_INFO "A new, yet unsupported tape drive is found\n" - KERN_INFO "Please report the following values:\n" - KERN_INFO " Vendor id : 0x%04x\n" - KERN_INFO " Wakeup method : %s\n" - KERN_INFO "And a description of your tape drive\n" - KERN_INFO "to "THE_FTAPE_MAINTAINER"\n" - KERN_INFO "==========================================", - ft_drive_type.vendor_id, - methods[ft_drive_type.wake_up].name); - ft_drive_type.speed = 0; /* unknown */ - } else { - ft_drive_type.name = vendors[vendor_index].name; - ft_drive_type.speed = vendors[vendor_index].speed; - TRACE(ft_t_info, "tape drive type: %s", ft_drive_type.name); - /* scan all methods for this vendor_id in table */ - while(ft_drive_type.wake_up != vendors[vendor_index].wake_up) { - if (vendor_index < NR_ITEMS(vendors) - 1 && - vendors[vendor_index + 1].vendor_id - == - ft_drive_type.vendor_id) { - ++vendor_index; - } else { - break; - } - } - if (ft_drive_type.wake_up != vendors[vendor_index].wake_up) { - TRACE(ft_t_warn, "\n" - KERN_INFO "==========================================\n" - KERN_INFO "wakeup type mismatch:\n" - KERN_INFO "found: %s, expected: %s\n" - KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n" - KERN_INFO "==========================================", - methods[ft_drive_type.wake_up].name, - methods[vendors[vendor_index].wake_up].name); - } - } - TRACE_EXIT; -} - -void ftape_calc_timeouts(unsigned int qic_std, - unsigned int data_rate, - unsigned int tape_len) -{ - int speed; /* deci-ips ! */ - int ff_speed; - int length; - TRACE_FUN(ft_t_any); - - /* tape transport speed - * data rate: QIC-40 QIC-80 QIC-3010 QIC-3020 - * - * 250 Kbps 25 ips n/a n/a n/a - * 500 Kbps 50 ips 34 ips 22.6 ips n/a - * 1 Mbps n/a 68 ips 45.2 ips 22.6 ips - * 2 Mbps n/a n/a n/a 45.2 ips - * - * fast tape transport speed is at least 68 ips. - */ - switch (qic_std) { - case QIC_TAPE_QIC40: - speed = (data_rate == 250) ? 250 : 500; - break; - case QIC_TAPE_QIC80: - speed = (data_rate == 500) ? 340 : 680; - break; - case QIC_TAPE_QIC3010: - speed = (data_rate == 500) ? 226 : 452; - break; - case QIC_TAPE_QIC3020: - speed = (data_rate == 1000) ? 226 : 452; - break; - default: - TRACE(ft_t_bug, "Unknown qic_std (bug) ?"); - speed = 500; - break; - } - if (ft_drive_type.speed == 0) { - unsigned long t0; - static int dt = 0; /* keep gcc from complaining */ - static int first_time = 1; - - /* Measure the time it takes to wind to EOT and back to BOT. - * If the tape length is known, calculate the rewind speed. - * Else keep the time value for calculation of the rewind - * speed later on, when the length _is_ known. - * Ask for a report only when length and speed are both known. - */ - if (first_time) { - ftape_seek_to_bot(); - t0 = jiffies; - ftape_seek_to_eot(); - ftape_seek_to_bot(); - dt = (int) (((jiffies - t0) * FT_USPT) / 1000); - if (dt < 1) { - dt = 1; /* prevent div by zero on failures */ - } - first_time = 0; - TRACE(ft_t_info, - "trying to determine seek timeout, got %d msec", - dt); - } - if (tape_len != 0) { - ft_drive_type.speed = - (2 * 12 * tape_len * 1000) / dt; - TRACE(ft_t_warn, "\n" - KERN_INFO "==========================================\n" - KERN_INFO "drive type: %s\n" - KERN_INFO "delta time = %d ms, length = %d ft\n" - KERN_INFO "has a maximum tape speed of %d ips\n" - KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n" - KERN_INFO "==========================================", - ft_drive_type.name, dt, tape_len, - ft_drive_type.speed); - } - } - /* Handle unknown length tapes as very long ones. We'll - * determine the actual length from a header segment later. - * This is normal for all modern (Wide,TR1/2/3) formats. - */ - if (tape_len <= 0) { - TRACE(ft_t_noise, - "Unknown tape length, using maximal timeouts"); - length = QIC_TOP_TAPE_LEN; /* use worst case values */ - } else { - length = tape_len; /* use actual values */ - } - if (ft_drive_type.speed == 0) { - ff_speed = speed; - } else { - ff_speed = ft_drive_type.speed; - } - /* time to go from bot to eot at normal speed (data rate): - * time = (1+delta) * length (ft) * 12 (inch/ft) / speed (ips) - * delta = 10 % for seek speed, 20 % for rewind speed. - */ - ftape_timeout.seek = (length * 132 * FT_SECOND) / speed; - ftape_timeout.rewind = (length * 144 * FT_SECOND) / (10 * ff_speed); - ftape_timeout.reset = 20 * FT_SECOND + ftape_timeout.rewind; - TRACE(ft_t_noise, "timeouts for speed = %d, length = %d\n" - KERN_INFO "seek timeout : %d sec\n" - KERN_INFO "rewind timeout: %d sec\n" - KERN_INFO "reset timeout : %d sec", - speed, length, - (ftape_timeout.seek + 500) / 1000, - (ftape_timeout.rewind + 500) / 1000, - (ftape_timeout.reset + 500) / 1000); - TRACE_EXIT; -} - -/* This function calibrates the datarate (i.e. determines the maximal - * usable data rate) and sets the global variable ft_qic_std to qic_std - * - */ -int ftape_calibrate_data_rate(unsigned int qic_std) -{ - int rate = ft_fdc_rate_limit; - int result; - TRACE_FUN(ft_t_flow); - - ft_qic_std = qic_std; - - if (ft_qic_std == -1) { - TRACE_ABORT(-EIO, ft_t_err, - "Unable to determine data rate if QIC standard is unknown"); - } - - /* Select highest rate supported by both fdc and drive. - * Start with highest rate supported by the fdc. - */ - while (fdc_set_data_rate(rate) < 0 && rate > 250) { - rate /= 2; - } - TRACE(ft_t_info, - "Highest FDC supported data rate: %d Kbps", rate); - ft_fdc_max_rate = rate; - do { - result = ftape_set_data_rate(rate, ft_qic_std); - } while (result == -EINVAL && (rate /= 2) > 250); - if (result < 0) { - TRACE_ABORT(-EIO, ft_t_err, "set datarate failed"); - } - ft_data_rate = rate; - TRACE_EXIT 0; -} - -static int ftape_init_drive(void) -{ - int status; - qic_model model; - unsigned int qic_std; - unsigned int data_rate; - TRACE_FUN(ft_t_flow); - - ftape_init_drive_needed = 0; /* don't retry if this fails ? */ - TRACE_CATCH(ftape_report_raw_drive_status(&status),); - if (status & QIC_STATUS_CARTRIDGE_PRESENT) { - if (!(status & QIC_STATUS_AT_BOT)) { - /* Antique drives will get here after a soft reset, - * modern ones only if the driver is loaded when the - * tape wasn't rewound properly. - */ - /* Tape should be at bot if new cartridge ! */ - ftape_seek_to_bot(); - } - if (!(status & QIC_STATUS_REFERENCED)) { - TRACE(ft_t_flow, "starting seek_load_point"); - TRACE_CATCH(ftape_command_wait(QIC_SEEK_LOAD_POINT, - ftape_timeout.reset, - &status),); - } - } - ft_formatted = (status & QIC_STATUS_REFERENCED) != 0; - if (!ft_formatted) { - TRACE(ft_t_warn, "Warning: tape is not formatted !"); - } - - /* report configuration aborts when ftape_tape_len == -1 - * unknown qic_std is okay if not formatted. - */ - TRACE_CATCH(ftape_report_configuration(&model, - &data_rate, - &qic_std, - &ftape_tape_len),); - - /* Maybe add the following to the /proc entry - */ - TRACE(ft_t_info, "%s drive @ %d Kbps", - (model == prehistoric) ? "prehistoric" : - ((model == pre_qic117c) ? "pre QIC-117C" : - ((model == post_qic117b) ? "post QIC-117B" : - "post QIC-117D")), data_rate); - - if (ft_formatted) { - /* initialize ft_used_data_rate to maximum value - * and set ft_qic_std - */ - TRACE_CATCH(ftape_calibrate_data_rate(qic_std),); - if (ftape_tape_len == 0) { - TRACE(ft_t_info, "unknown length QIC-%s tape", - (ft_qic_std == QIC_TAPE_QIC40) ? "40" : - ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : - ((ft_qic_std == QIC_TAPE_QIC3010) - ? "3010" : "3020"))); - } else { - TRACE(ft_t_info, "%d ft. QIC-%s tape", ftape_tape_len, - (ft_qic_std == QIC_TAPE_QIC40) ? "40" : - ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : - ((ft_qic_std == QIC_TAPE_QIC3010) - ? "3010" : "3020"))); - } - ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); - /* soft write-protect QIC-40/QIC-80 cartridges used with a - * Colorado T3000 drive. Buggy hardware! - */ - if ((ft_drive_type.vendor_id == 0x011c6) && - ((ft_qic_std == QIC_TAPE_QIC40 || - ft_qic_std == QIC_TAPE_QIC80) && - !ft_write_protected)) { - TRACE(ft_t_warn, "\n" - KERN_INFO "The famous Colorado T3000 bug:\n" - KERN_INFO "%s drives can't write QIC40 and QIC80\n" - KERN_INFO "cartridges but don't set the write-protect flag!", - ft_drive_type.name); - ft_write_protected = 1; - } - } else { - /* Doesn't make too much sense to set the data rate - * because we don't know what to use for the write - * precompensation. - * Need to do this again when formatting the cartridge. - */ - ft_data_rate = data_rate; - ftape_calc_timeouts(QIC_TAPE_QIC40, - data_rate, - ftape_tape_len); - } - ftape_new_cartridge(); - TRACE_EXIT 0; -} - -static void ftape_munmap(void) -{ - int i; - TRACE_FUN(ft_t_flow); - - for (i = 0; i < ft_nr_buffers; i++) { - ft_buffer[i]->mmapped = 0; - } - TRACE_EXIT; -} - -/* Map the dma buffers into the virtual address range given by vma. - * We only check the caller doesn't map non-existent buffers. We - * don't check for multiple mappings. - */ -int ftape_mmap(struct vm_area_struct *vma) -{ - int num_buffers; - int i; - TRACE_FUN(ft_t_flow); - - if (ft_failure) { - TRACE_EXIT -ENODEV; - } - if (!(vma->vm_flags & (VM_READ|VM_WRITE))) { - TRACE_ABORT(-EINVAL, ft_t_err, "Undefined mmap() access"); - } - if (vma_get_pgoff(vma) != 0) { - TRACE_ABORT(-EINVAL, ft_t_err, "page offset must be 0"); - } - if ((vma->vm_end - vma->vm_start) % FT_BUFF_SIZE != 0) { - TRACE_ABORT(-EINVAL, ft_t_err, - "size = %ld, should be a multiple of %d", - vma->vm_end - vma->vm_start, - FT_BUFF_SIZE); - } - num_buffers = (vma->vm_end - vma->vm_start) / FT_BUFF_SIZE; - if (num_buffers > ft_nr_buffers) { - TRACE_ABORT(-EINVAL, - ft_t_err, "size = %ld, should be less than %d", - vma->vm_end - vma->vm_start, - ft_nr_buffers * FT_BUFF_SIZE); - } - if (ft_driver_state != idle) { - /* this also clears the buffer states - */ - ftape_abort_operation(); - } else { - ftape_reset_buffer(); - } - for (i = 0; i < num_buffers; i++) { - unsigned long pfn; - - pfn = virt_to_phys(ft_buffer[i]->address) >> PAGE_SHIFT; - TRACE_CATCH(remap_pfn_range(vma, vma->vm_start + - i * FT_BUFF_SIZE, - pfn, - FT_BUFF_SIZE, - vma->vm_page_prot), - _res = -EAGAIN); - TRACE(ft_t_noise, "remapped dma buffer @ %p to location @ %p", - ft_buffer[i]->address, - (void *)(vma->vm_start + i * FT_BUFF_SIZE)); - } - for (i = 0; i < num_buffers; i++) { - memset(ft_buffer[i]->address, 0xAA, FT_BUFF_SIZE); - ft_buffer[i]->mmapped++; - } - TRACE_EXIT 0; -} - -static void ftape_init_driver(void); /* forward declaration */ - -/* OPEN routine called by kernel-interface code - */ -int ftape_enable(int drive_selection) -{ - TRACE_FUN(ft_t_any); - - if (ft_drive_sel == -1 || ft_drive_sel != drive_selection) { - /* Other selection than last time - */ - ftape_init_driver(); - } - ft_drive_sel = FTAPE_SEL(drive_selection); - ft_failure = 0; - TRACE_CATCH(fdc_init(),); /* init & detect fdc */ - TRACE_CATCH(ftape_activate_drive(&ft_drive_type), - fdc_disable(); - fdc_release_irq_and_dma(); - fdc_release_regions()); - TRACE_CATCH(ftape_get_drive_status(), ftape_detach_drive()); - if (ft_drive_type.vendor_id == UNKNOWN_VENDOR) { - ftape_log_vendor_id(); - } - if (ft_new_tape) { - ftape_init_drive_needed = 1; - } - if (!ft_no_tape && ftape_init_drive_needed) { - TRACE_CATCH(ftape_init_drive(), ftape_detach_drive()); - } - ftape_munmap(); /* clear the mmap flag */ - clear_history(); - TRACE_EXIT 0; -} - -/* release routine called by the high level interface modules - * zftape or sftape. - */ -void ftape_disable(void) -{ - int i; - TRACE_FUN(ft_t_any); - - for (i = 0; i < ft_nr_buffers; i++) { - if (ft_buffer[i]->mmapped) { - TRACE(ft_t_noise, "first byte of buffer %d: 0x%02x", - i, *ft_buffer[i]->address); - } - } - if (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK) && - !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK)) && - ftape_tape_running) { - TRACE(ft_t_warn, - "Interrupted by fatal signal and tape still running"); - ftape_dumb_stop(); - ftape_abort_operation(); /* it's annoying */ - } else { - ftape_set_state(idle); - } - ftape_detach_drive(); - if (ft_history.used) { - TRACE(ft_t_info, "== Non-fatal errors this run: =="); - TRACE(ft_t_info, "fdc isr statistics:\n" - KERN_INFO " id_am_errors : %3d\n" - KERN_INFO " id_crc_errors : %3d\n" - KERN_INFO " data_am_errors : %3d\n" - KERN_INFO " data_crc_errors : %3d\n" - KERN_INFO " overrun_errors : %3d\n" - KERN_INFO " no_data_errors : %3d\n" - KERN_INFO " retries : %3d", - ft_history.id_am_errors, ft_history.id_crc_errors, - ft_history.data_am_errors, ft_history.data_crc_errors, - ft_history.overrun_errors, ft_history.no_data_errors, - ft_history.retries); - if (ft_history.used & 1) { - TRACE(ft_t_info, "ecc statistics:\n" - KERN_INFO " crc_errors : %3d\n" - KERN_INFO " crc_failures : %3d\n" - KERN_INFO " ecc_failures : %3d\n" - KERN_INFO " sectors corrected: %3d", - ft_history.crc_errors, ft_history.crc_failures, - ft_history.ecc_failures, ft_history.corrected); - } - if (ft_history.defects > 0) { - TRACE(ft_t_warn, "Warning: %d media defects!", - ft_history.defects); - } - if (ft_history.rewinds > 0) { - TRACE(ft_t_info, "tape motion statistics:\n" - KERN_INFO "repositions : %3d", - ft_history.rewinds); - } - } - ft_failure = 1; - TRACE_EXIT; -} - -static void ftape_init_driver(void) -{ - TRACE_FUN(ft_t_flow); - - ft_drive_type.vendor_id = UNKNOWN_VENDOR; - ft_drive_type.speed = 0; - ft_drive_type.wake_up = unknown_wake_up; - ft_drive_type.name = "Unknown"; - - ftape_timeout.seek = 650 * FT_SECOND; - ftape_timeout.reset = 670 * FT_SECOND; - ftape_timeout.rewind = 650 * FT_SECOND; - ftape_timeout.head_seek = 15 * FT_SECOND; - ftape_timeout.stop = 5 * FT_SECOND; - ftape_timeout.pause = 16 * FT_SECOND; - - ft_qic_std = -1; - ftape_tape_len = 0; /* unknown */ - ftape_current_command = 0; - ftape_current_cylinder = -1; - - ft_segments_per_track = 102; - ftape_segments_per_head = 1020; - ftape_segments_per_cylinder = 4; - ft_tracks_per_tape = 20; - - ft_failure = 1; - - ft_formatted = 0; - ft_no_tape = 1; - ft_write_protected = 1; - ft_new_tape = 1; - - ft_driver_state = idle; - - ft_data_rate = - ft_fdc_max_rate = 500; - ft_drive_max_rate = 0; /* triggers set_rate_test() */ - - ftape_init_drive_needed = 1; - - ft_header_segment_1 = -1; - ft_header_segment_2 = -1; - ft_used_header_segment = -1; - ft_first_data_segment = -1; - ft_last_data_segment = -1; - - ft_location.track = -1; - ft_location.known = 0; - - ftape_tape_running = 0; - ftape_might_be_off_track = 1; - - ftape_new_cartridge(); /* init some tape related variables */ - ftape_init_bsm(); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.h b/drivers/char/ftape/lowlevel/ftape-ctl.h deleted file mode 100644 index 5f5e30bc3615..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ctl.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef _FTAPE_CTL_H -#define _FTAPE_CTL_H - -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ctl.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:09 $ - * - * This file contains the non-standard IOCTL related definitions - * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for - * Linux. - */ - -#include -#include -#include - -#include "../lowlevel/ftape-rw.h" -#include - -typedef struct { - int used; /* any reading or writing done */ - /* isr statistics */ - unsigned int id_am_errors; /* id address mark not found */ - unsigned int id_crc_errors; /* crc error in id address mark */ - unsigned int data_am_errors; /* data address mark not found */ - unsigned int data_crc_errors; /* crc error in data field */ - unsigned int overrun_errors; /* fdc access timing problem */ - unsigned int no_data_errors; /* sector not found */ - unsigned int retries; /* number of tape retries */ - /* ecc statistics */ - unsigned int crc_errors; /* crc error in data */ - unsigned int crc_failures; /* bad data without crc error */ - unsigned int ecc_failures; /* failed to correct */ - unsigned int corrected; /* total sectors corrected */ - /* general statistics */ - unsigned int rewinds; /* number of tape rewinds */ - unsigned int defects; /* bad sectors due to media defects */ -} history_record; - -/* this structure contains * ALL * information that we want - * our child modules to know about, but don't want them to - * modify. - */ -typedef struct { - /* vendor information */ - vendor_struct fti_drive_type; - /* data rates */ - unsigned int fti_used_data_rate; - unsigned int fti_drive_max_rate; - unsigned int fti_fdc_max_rate; - /* drive selection, either FTAPE_SEL_A/B/C/D */ - int fti_drive_sel; - /* flags set after decode the drive and tape status */ - unsigned int fti_formatted :1; - unsigned int fti_no_tape :1; - unsigned int fti_write_protected:1; - unsigned int fti_new_tape :1; - /* values of last queried drive/tape status and error */ - ft_drive_error fti_last_error; - ft_drive_status fti_last_status; - /* cartridge geometry */ - unsigned int fti_tracks_per_tape; - unsigned int fti_segments_per_track; - /* location of header segments, etc. */ - int fti_used_header_segment; - int fti_header_segment_1; - int fti_header_segment_2; - int fti_first_data_segment; - int fti_last_data_segment; - /* the format code as stored in the header segment */ - ft_format_type fti_format_code; - /* the following is the sole reason for the ftape_set_status() call */ - unsigned int fti_qic_std; - /* is tape running? */ - volatile enum runner_status_enum fti_runner_status; - /* is tape reading/writing/verifying/formatting/deleting */ - buffer_state_enum fti_state; - /* flags fatal hardware error */ - unsigned int fti_failure:1; - /* history record */ - history_record fti_history; -} ftape_info; - -/* vendor information */ -#define ft_drive_type ftape_status.fti_drive_type -/* data rates */ -#define ft_data_rate ftape_status.fti_used_data_rate -#define ft_drive_max_rate ftape_status.fti_drive_max_rate -#define ft_fdc_max_rate ftape_status.fti_fdc_max_rate -/* drive selection, either FTAPE_SEL_A/B/C/D */ -#define ft_drive_sel ftape_status.fti_drive_sel -/* flags set after decode the drive and tape status */ -#define ft_formatted ftape_status.fti_formatted -#define ft_no_tape ftape_status.fti_no_tape -#define ft_write_protected ftape_status.fti_write_protected -#define ft_new_tape ftape_status.fti_new_tape -/* values of last queried drive/tape status and error */ -#define ft_last_error ftape_status.fti_last_error -#define ft_last_status ftape_status.fti_last_status -/* cartridge geometry */ -#define ft_tracks_per_tape ftape_status.fti_tracks_per_tape -#define ft_segments_per_track ftape_status.fti_segments_per_track -/* the format code as stored in the header segment */ -#define ft_format_code ftape_status.fti_format_code -/* the qic status as returned by report drive configuration */ -#define ft_qic_std ftape_status.fti_qic_std -#define ft_used_header_segment ftape_status.fti_used_header_segment -#define ft_header_segment_1 ftape_status.fti_header_segment_1 -#define ft_header_segment_2 ftape_status.fti_header_segment_2 -#define ft_first_data_segment ftape_status.fti_first_data_segment -#define ft_last_data_segment ftape_status.fti_last_data_segment -/* is tape running? */ -#define ft_runner_status ftape_status.fti_runner_status -/* is tape reading/writing/verifying/formatting/deleting */ -#define ft_driver_state ftape_status.fti_state -/* flags fatal hardware error */ -#define ft_failure ftape_status.fti_failure -/* history record */ -#define ft_history ftape_status.fti_history - -/* - * ftape-ctl.c defined global vars. - */ -extern ftape_info ftape_status; -extern int ftape_segments_per_head; -extern int ftape_segments_per_cylinder; -extern int ftape_init_drive_needed; - -/* - * ftape-ctl.c defined global functions. - */ -extern int ftape_mmap(struct vm_area_struct *vma); -extern int ftape_enable(int drive_selection); -extern void ftape_disable(void); -extern int ftape_seek_to_bot(void); -extern int ftape_seek_to_eot(void); -extern int ftape_abort_operation(void); -extern void ftape_calc_timeouts(unsigned int qic_std, - unsigned int data_rate, - unsigned int tape_len); -extern int ftape_calibrate_data_rate(unsigned int qic_std); -extern const ftape_info *ftape_get_status(void); -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-ecc.c b/drivers/char/ftape/lowlevel/ftape-ecc.c deleted file mode 100644 index e5632f674bc8..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ecc.c +++ /dev/null @@ -1,853 +0,0 @@ -/* - * - * Copyright (c) 1993 Ning and David Mosberger. - - This is based on code originally written by Bas Laarhoven (bas@vimec.nl) - and David L. Brown, Jr., and incorporates improvements suggested by - Kai Harrekilde-Petersen. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ecc.c,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/05 19:18:10 $ - * - * This file contains the Reed-Solomon error correction code - * for the QIC-40/80 floppy-tape driver for Linux. - */ - -#include - -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-ecc.h" - -/* Machines that are big-endian should define macro BIG_ENDIAN. - * Unfortunately, there doesn't appear to be a standard include file - * that works for all OSs. - */ - -#if defined(__sparc__) || defined(__hppa) -#define BIG_ENDIAN -#endif /* __sparc__ || __hppa */ - -#if defined(__mips__) -#error Find a smart way to determine the Endianness of the MIPS CPU -#endif - -/* Notice: to minimize the potential for confusion, we use r to - * denote the independent variable of the polynomials in the - * Galois Field GF(2^8). We reserve x for polynomials that - * that have coefficients in GF(2^8). - * - * The Galois Field in which coefficient arithmetic is performed are - * the polynomials over Z_2 (i.e., 0 and 1) modulo the irreducible - * polynomial f(r), where f(r)=r^8 + r^7 + r^2 + r + 1. A polynomial - * is represented as a byte with the MSB as the coefficient of r^7 and - * the LSB as the coefficient of r^0. For example, the binary - * representation of f(x) is 0x187 (of course, this doesn't fit into 8 - * bits). In this field, the polynomial r is a primitive element. - * That is, r^i with i in 0,...,255 enumerates all elements in the - * field. - * - * The generator polynomial for the QIC-80 ECC is - * - * g(x) = x^3 + r^105*x^2 + r^105*x + 1 - * - * which can be factored into: - * - * g(x) = (x-r^-1)(x-r^0)(x-r^1) - * - * the byte representation of the coefficients are: - * - * r^105 = 0xc0 - * r^-1 = 0xc3 - * r^0 = 0x01 - * r^1 = 0x02 - * - * Notice that r^-1 = r^254 as exponent arithmetic is performed - * modulo 2^8-1 = 255. - * - * For more information on Galois Fields and Reed-Solomon codes, refer - * to any good book. I found _An Introduction to Error Correcting - * Codes with Applications_ by S. A. Vanstone and P. C. van Oorschot - * to be a good introduction into the former. _CODING THEORY: The - * Essentials_ I found very useful for its concise description of - * Reed-Solomon encoding/decoding. - * - */ - -typedef __u8 Matrix[3][3]; - -/* - * gfpow[] is defined such that gfpow[i] returns r^i if - * i is in the range [0..255]. - */ -static const __u8 gfpow[] = -{ - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, - 0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4, - 0x6f, 0xde, 0x3b, 0x76, 0xec, 0x5f, 0xbe, 0xfb, - 0x71, 0xe2, 0x43, 0x86, 0x8b, 0x91, 0xa5, 0xcd, - 0x1d, 0x3a, 0x74, 0xe8, 0x57, 0xae, 0xdb, 0x31, - 0x62, 0xc4, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0x67, - 0xce, 0x1b, 0x36, 0x6c, 0xd8, 0x37, 0x6e, 0xdc, - 0x3f, 0x7e, 0xfc, 0x7f, 0xfe, 0x7b, 0xf6, 0x6b, - 0xd6, 0x2b, 0x56, 0xac, 0xdf, 0x39, 0x72, 0xe4, - 0x4f, 0x9e, 0xbb, 0xf1, 0x65, 0xca, 0x13, 0x26, - 0x4c, 0x98, 0xb7, 0xe9, 0x55, 0xaa, 0xd3, 0x21, - 0x42, 0x84, 0x8f, 0x99, 0xb5, 0xed, 0x5d, 0xba, - 0xf3, 0x61, 0xc2, 0x03, 0x06, 0x0c, 0x18, 0x30, - 0x60, 0xc0, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, - 0x47, 0x8e, 0x9b, 0xb1, 0xe5, 0x4d, 0x9a, 0xb3, - 0xe1, 0x45, 0x8a, 0x93, 0xa1, 0xc5, 0x0d, 0x1a, - 0x34, 0x68, 0xd0, 0x27, 0x4e, 0x9c, 0xbf, 0xf9, - 0x75, 0xea, 0x53, 0xa6, 0xcb, 0x11, 0x22, 0x44, - 0x88, 0x97, 0xa9, 0xd5, 0x2d, 0x5a, 0xb4, 0xef, - 0x59, 0xb2, 0xe3, 0x41, 0x82, 0x83, 0x81, 0x85, - 0x8d, 0x9d, 0xbd, 0xfd, 0x7d, 0xfa, 0x73, 0xe6, - 0x4b, 0x96, 0xab, 0xd1, 0x25, 0x4a, 0x94, 0xaf, - 0xd9, 0x35, 0x6a, 0xd4, 0x2f, 0x5e, 0xbc, 0xff, - 0x79, 0xf2, 0x63, 0xc6, 0x0b, 0x16, 0x2c, 0x58, - 0xb0, 0xe7, 0x49, 0x92, 0xa3, 0xc1, 0x05, 0x0a, - 0x14, 0x28, 0x50, 0xa0, 0xc7, 0x09, 0x12, 0x24, - 0x48, 0x90, 0xa7, 0xc9, 0x15, 0x2a, 0x54, 0xa8, - 0xd7, 0x29, 0x52, 0xa4, 0xcf, 0x19, 0x32, 0x64, - 0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2, - 0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda, - 0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77, - 0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3, 0x01 -}; - -/* - * This is a log table. That is, gflog[r^i] returns i (modulo f(r)). - * gflog[0] is undefined and the first element is therefore not valid. - */ -static const __u8 gflog[256] = -{ - 0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a, - 0x03, 0xcd, 0xc7, 0xbc, 0x65, 0x7e, 0x6b, 0x2a, - 0x04, 0x8d, 0xce, 0x4e, 0xc8, 0xd4, 0xbd, 0xe1, - 0x66, 0xdd, 0x7f, 0x31, 0x6c, 0x20, 0x2b, 0xf3, - 0x05, 0x57, 0x8e, 0xe8, 0xcf, 0xac, 0x4f, 0x83, - 0xc9, 0xd9, 0xd5, 0x41, 0xbe, 0x94, 0xe2, 0xb4, - 0x67, 0x27, 0xde, 0xf0, 0x80, 0xb1, 0x32, 0x35, - 0x6d, 0x45, 0x21, 0x12, 0x2c, 0x0d, 0xf4, 0x38, - 0x06, 0x9b, 0x58, 0x1a, 0x8f, 0x79, 0xe9, 0x70, - 0xd0, 0xc2, 0xad, 0xa8, 0x50, 0x75, 0x84, 0x48, - 0xca, 0xfc, 0xda, 0x8a, 0xd6, 0x54, 0x42, 0x24, - 0xbf, 0x98, 0x95, 0xf9, 0xe3, 0x5e, 0xb5, 0x15, - 0x68, 0x61, 0x28, 0xba, 0xdf, 0x4c, 0xf1, 0x2f, - 0x81, 0xe6, 0xb2, 0x3f, 0x33, 0xee, 0x36, 0x10, - 0x6e, 0x18, 0x46, 0xa6, 0x22, 0x88, 0x13, 0xf7, - 0x2d, 0xb8, 0x0e, 0x3d, 0xf5, 0xa4, 0x39, 0x3b, - 0x07, 0x9e, 0x9c, 0x9d, 0x59, 0x9f, 0x1b, 0x08, - 0x90, 0x09, 0x7a, 0x1c, 0xea, 0xa0, 0x71, 0x5a, - 0xd1, 0x1d, 0xc3, 0x7b, 0xae, 0x0a, 0xa9, 0x91, - 0x51, 0x5b, 0x76, 0x72, 0x85, 0xa1, 0x49, 0xeb, - 0xcb, 0x7c, 0xfd, 0xc4, 0xdb, 0x1e, 0x8b, 0xd2, - 0xd7, 0x92, 0x55, 0xaa, 0x43, 0x0b, 0x25, 0xaf, - 0xc0, 0x73, 0x99, 0x77, 0x96, 0x5c, 0xfa, 0x52, - 0xe4, 0xec, 0x5f, 0x4a, 0xb6, 0xa2, 0x16, 0x86, - 0x69, 0xc5, 0x62, 0xfe, 0x29, 0x7d, 0xbb, 0xcc, - 0xe0, 0xd3, 0x4d, 0x8c, 0xf2, 0x1f, 0x30, 0xdc, - 0x82, 0xab, 0xe7, 0x56, 0xb3, 0x93, 0x40, 0xd8, - 0x34, 0xb0, 0xef, 0x26, 0x37, 0x0c, 0x11, 0x44, - 0x6f, 0x78, 0x19, 0x9a, 0x47, 0x74, 0xa7, 0xc1, - 0x23, 0x53, 0x89, 0xfb, 0x14, 0x5d, 0xf8, 0x97, - 0x2e, 0x4b, 0xb9, 0x60, 0x0f, 0xed, 0x3e, 0xe5, - 0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7 -}; - -/* This is a multiplication table for the factor 0xc0 (i.e., r^105 (mod f(r)). - * gfmul_c0[f] returns r^105 * f(r) (modulo f(r)). - */ -static const __u8 gfmul_c0[256] = -{ - 0x00, 0xc0, 0x07, 0xc7, 0x0e, 0xce, 0x09, 0xc9, - 0x1c, 0xdc, 0x1b, 0xdb, 0x12, 0xd2, 0x15, 0xd5, - 0x38, 0xf8, 0x3f, 0xff, 0x36, 0xf6, 0x31, 0xf1, - 0x24, 0xe4, 0x23, 0xe3, 0x2a, 0xea, 0x2d, 0xed, - 0x70, 0xb0, 0x77, 0xb7, 0x7e, 0xbe, 0x79, 0xb9, - 0x6c, 0xac, 0x6b, 0xab, 0x62, 0xa2, 0x65, 0xa5, - 0x48, 0x88, 0x4f, 0x8f, 0x46, 0x86, 0x41, 0x81, - 0x54, 0x94, 0x53, 0x93, 0x5a, 0x9a, 0x5d, 0x9d, - 0xe0, 0x20, 0xe7, 0x27, 0xee, 0x2e, 0xe9, 0x29, - 0xfc, 0x3c, 0xfb, 0x3b, 0xf2, 0x32, 0xf5, 0x35, - 0xd8, 0x18, 0xdf, 0x1f, 0xd6, 0x16, 0xd1, 0x11, - 0xc4, 0x04, 0xc3, 0x03, 0xca, 0x0a, 0xcd, 0x0d, - 0x90, 0x50, 0x97, 0x57, 0x9e, 0x5e, 0x99, 0x59, - 0x8c, 0x4c, 0x8b, 0x4b, 0x82, 0x42, 0x85, 0x45, - 0xa8, 0x68, 0xaf, 0x6f, 0xa6, 0x66, 0xa1, 0x61, - 0xb4, 0x74, 0xb3, 0x73, 0xba, 0x7a, 0xbd, 0x7d, - 0x47, 0x87, 0x40, 0x80, 0x49, 0x89, 0x4e, 0x8e, - 0x5b, 0x9b, 0x5c, 0x9c, 0x55, 0x95, 0x52, 0x92, - 0x7f, 0xbf, 0x78, 0xb8, 0x71, 0xb1, 0x76, 0xb6, - 0x63, 0xa3, 0x64, 0xa4, 0x6d, 0xad, 0x6a, 0xaa, - 0x37, 0xf7, 0x30, 0xf0, 0x39, 0xf9, 0x3e, 0xfe, - 0x2b, 0xeb, 0x2c, 0xec, 0x25, 0xe5, 0x22, 0xe2, - 0x0f, 0xcf, 0x08, 0xc8, 0x01, 0xc1, 0x06, 0xc6, - 0x13, 0xd3, 0x14, 0xd4, 0x1d, 0xdd, 0x1a, 0xda, - 0xa7, 0x67, 0xa0, 0x60, 0xa9, 0x69, 0xae, 0x6e, - 0xbb, 0x7b, 0xbc, 0x7c, 0xb5, 0x75, 0xb2, 0x72, - 0x9f, 0x5f, 0x98, 0x58, 0x91, 0x51, 0x96, 0x56, - 0x83, 0x43, 0x84, 0x44, 0x8d, 0x4d, 0x8a, 0x4a, - 0xd7, 0x17, 0xd0, 0x10, 0xd9, 0x19, 0xde, 0x1e, - 0xcb, 0x0b, 0xcc, 0x0c, 0xc5, 0x05, 0xc2, 0x02, - 0xef, 0x2f, 0xe8, 0x28, 0xe1, 0x21, 0xe6, 0x26, - 0xf3, 0x33, 0xf4, 0x34, 0xfd, 0x3d, 0xfa, 0x3a -}; - - -/* Returns V modulo 255 provided V is in the range -255,-254,...,509. - */ -static inline __u8 mod255(int v) -{ - if (v > 0) { - if (v < 255) { - return v; - } else { - return v - 255; - } - } else { - return v + 255; - } -} - - -/* Add two numbers in the field. Addition in this field is equivalent - * to a bit-wise exclusive OR operation---subtraction is therefore - * identical to addition. - */ -static inline __u8 gfadd(__u8 a, __u8 b) -{ - return a ^ b; -} - - -/* Add two vectors of numbers in the field. Each byte in A and B gets - * added individually. - */ -static inline unsigned long gfadd_long(unsigned long a, unsigned long b) -{ - return a ^ b; -} - - -/* Multiply two numbers in the field: - */ -static inline __u8 gfmul(__u8 a, __u8 b) -{ - if (a && b) { - return gfpow[mod255(gflog[a] + gflog[b])]; - } else { - return 0; - } -} - - -/* Just like gfmul, except we have already looked up the log of the - * second number. - */ -static inline __u8 gfmul_exp(__u8 a, int b) -{ - if (a) { - return gfpow[mod255(gflog[a] + b)]; - } else { - return 0; - } -} - - -/* Just like gfmul_exp, except that A is a vector of numbers. That - * is, each byte in A gets multiplied by gfpow[mod255(B)]. - */ -static inline unsigned long gfmul_exp_long(unsigned long a, int b) -{ - __u8 t; - - if (sizeof(long) == 4) { - return ( - ((t = (__u32)a >> 24 & 0xff) ? - (((__u32) gfpow[mod255(gflog[t] + b)]) << 24) : 0) | - ((t = (__u32)a >> 16 & 0xff) ? - (((__u32) gfpow[mod255(gflog[t] + b)]) << 16) : 0) | - ((t = (__u32)a >> 8 & 0xff) ? - (((__u32) gfpow[mod255(gflog[t] + b)]) << 8) : 0) | - ((t = (__u32)a >> 0 & 0xff) ? - (((__u32) gfpow[mod255(gflog[t] + b)]) << 0) : 0)); - } else if (sizeof(long) == 8) { - return ( - ((t = (__u64)a >> 56 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 56) : 0) | - ((t = (__u64)a >> 48 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 48) : 0) | - ((t = (__u64)a >> 40 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 40) : 0) | - ((t = (__u64)a >> 32 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 32) : 0) | - ((t = (__u64)a >> 24 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 24) : 0) | - ((t = (__u64)a >> 16 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 16) : 0) | - ((t = (__u64)a >> 8 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 8) : 0) | - ((t = (__u64)a >> 0 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 0) : 0)); - } else { - TRACE_FUN(ft_t_any); - TRACE_ABORT(-1, ft_t_err, "Error: size of long is %d bytes", - (int)sizeof(long)); - } -} - - -/* Divide two numbers in the field. Returns a/b (modulo f(x)). - */ -static inline __u8 gfdiv(__u8 a, __u8 b) -{ - if (!b) { - TRACE_FUN(ft_t_any); - TRACE_ABORT(0xff, ft_t_bug, "Error: division by zero"); - } else if (a == 0) { - return 0; - } else { - return gfpow[mod255(gflog[a] - gflog[b])]; - } -} - - -/* The following functions return the inverse of the matrix of the - * linear system that needs to be solved to determine the error - * magnitudes. The first deals with matrices of rank 3, while the - * second deals with matrices of rank 2. The error indices are passed - * in arguments L0,..,L2 (0=first sector, 31=last sector). The error - * indices must be sorted in ascending order, i.e., L00 CRC failures)"); - } - log_det = 255 - gflog[det]; - - /* Now, calculate all of the coefficients: - */ - Ainv[0][0]= gfmul_exp(gfadd(gfpow[l1], gfpow[l2]), log_det); - Ainv[0][1]= gfmul_exp(gfadd(t21, t12), log_det); - Ainv[0][2]= gfmul_exp(gfadd(gfpow[255 - l1], gfpow[255 - l2]),log_det); - - Ainv[1][0]= gfmul_exp(gfadd(gfpow[l0], gfpow[l2]), log_det); - Ainv[1][1]= gfmul_exp(gfadd(t20, t02), log_det); - Ainv[1][2]= gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l2]),log_det); - - Ainv[2][0]= gfmul_exp(gfadd(gfpow[l0], gfpow[l1]), log_det); - Ainv[2][1]= gfmul_exp(gfadd(t10, t01), log_det); - Ainv[2][2]= gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l1]),log_det); - - return 1; -} - - -static inline int gfinv2(__u8 l0, __u8 l1, Matrix Ainv) -{ - __u8 det; - __u8 t1, t2; - int log_det; - - t1 = gfpow[255 - l0]; - t2 = gfpow[255 - l1]; - det = gfadd(t1, t2); - if (!det) { - TRACE_FUN(ft_t_any); - TRACE_ABORT(0, ft_t_err, - "Inversion failed (2 CRC errors, >0 CRC failures)"); - } - log_det = 255 - gflog[det]; - - /* Now, calculate all of the coefficients: - */ - Ainv[0][0] = Ainv[1][0] = gfpow[log_det]; - - Ainv[0][1] = gfmul_exp(t2, log_det); - Ainv[1][1] = gfmul_exp(t1, log_det); - - return 1; -} - - -/* Multiply matrix A by vector S and return result in vector B. M is - * assumed to be of order NxN, S and B of order Nx1. - */ -static inline void gfmat_mul(int n, Matrix A, - __u8 *s, __u8 *b) -{ - int i, j; - __u8 dot_prod; - - for (i = 0; i < n; ++i) { - dot_prod = 0; - for (j = 0; j < n; ++j) { - dot_prod = gfadd(dot_prod, gfmul(A[i][j], s[j])); - } - b[i] = dot_prod; - } -} - - - -/* The Reed Solomon ECC codes are computed over the N-th byte of each - * block, where N=SECTOR_SIZE. There are up to 29 blocks of data, and - * 3 blocks of ECC. The blocks are stored contiguously in memory. A - * segment, consequently, is assumed to have at least 4 blocks: one or - * more data blocks plus three ECC blocks. - * - * Notice: In QIC-80 speak, a CRC error is a sector with an incorrect - * CRC. A CRC failure is a sector with incorrect data, but - * a valid CRC. In the error control literature, the former - * is usually called "erasure", the latter "error." - */ -/* Compute the parity bytes for C columns of data, where C is the - * number of bytes that fit into a long integer. We use a linear - * feed-back register to do this. The parity bytes P[0], P[STRIDE], - * P[2*STRIDE] are computed such that: - * - * x^k * p(x) + m(x) = 0 (modulo g(x)) - * - * where k = NBLOCKS, - * p(x) = P[0] + P[STRIDE]*x + P[2*STRIDE]*x^2, and - * m(x) = sum_{i=0}^k m_i*x^i. - * m_i = DATA[i*SECTOR_SIZE] - */ -static inline void set_parity(unsigned long *data, - int nblocks, - unsigned long *p, - int stride) -{ - unsigned long p0, p1, p2, t1, t2, *end; - - end = data + nblocks * (FT_SECTOR_SIZE / sizeof(long)); - p0 = p1 = p2 = 0; - while (data < end) { - /* The new parity bytes p0_i, p1_i, p2_i are computed - * from the old values p0_{i-1}, p1_{i-1}, p2_{i-1} - * recursively as: - * - * p0_i = p1_{i-1} + r^105 * (m_{i-1} - p0_{i-1}) - * p1_i = p2_{i-1} + r^105 * (m_{i-1} - p0_{i-1}) - * p2_i = (m_{i-1} - p0_{i-1}) - * - * With the initial condition: p0_0 = p1_0 = p2_0 = 0. - */ - t1 = gfadd_long(*data, p0); - /* - * Multiply each byte in t1 by 0xc0: - */ - if (sizeof(long) == 4) { - t2= (((__u32) gfmul_c0[(__u32)t1 >> 24 & 0xff]) << 24 | - ((__u32) gfmul_c0[(__u32)t1 >> 16 & 0xff]) << 16 | - ((__u32) gfmul_c0[(__u32)t1 >> 8 & 0xff]) << 8 | - ((__u32) gfmul_c0[(__u32)t1 >> 0 & 0xff]) << 0); - } else if (sizeof(long) == 8) { - t2= (((__u64) gfmul_c0[(__u64)t1 >> 56 & 0xff]) << 56 | - ((__u64) gfmul_c0[(__u64)t1 >> 48 & 0xff]) << 48 | - ((__u64) gfmul_c0[(__u64)t1 >> 40 & 0xff]) << 40 | - ((__u64) gfmul_c0[(__u64)t1 >> 32 & 0xff]) << 32 | - ((__u64) gfmul_c0[(__u64)t1 >> 24 & 0xff]) << 24 | - ((__u64) gfmul_c0[(__u64)t1 >> 16 & 0xff]) << 16 | - ((__u64) gfmul_c0[(__u64)t1 >> 8 & 0xff]) << 8 | - ((__u64) gfmul_c0[(__u64)t1 >> 0 & 0xff]) << 0); - } else { - TRACE_FUN(ft_t_any); - TRACE(ft_t_err, "Error: long is of size %d", - (int) sizeof(long)); - TRACE_EXIT; - } - p0 = gfadd_long(t2, p1); - p1 = gfadd_long(t2, p2); - p2 = t1; - data += FT_SECTOR_SIZE / sizeof(long); - } - *p = p0; - p += stride; - *p = p1; - p += stride; - *p = p2; - return; -} - - -/* Compute the 3 syndrome values. DATA should point to the first byte - * of the column for which the syndromes are desired. The syndromes - * are computed over the first NBLOCKS of rows. The three bytes will - * be placed in S[0], S[1], and S[2]. - * - * S[i] is the value of the "message" polynomial m(x) evaluated at the - * i-th root of the generator polynomial g(x). - * - * As g(x)=(x-r^-1)(x-1)(x-r^1) we evaluate the message polynomial at - * x=r^-1 to get S[0], at x=r^0=1 to get S[1], and at x=r to get S[2]. - * This could be done directly and efficiently via the Horner scheme. - * However, it would require multiplication tables for the factors - * r^-1 (0xc3) and r (0x02). The following scheme does not require - * any multiplication tables beyond what's needed for set_parity() - * anyway and is slightly faster if there are no errors and slightly - * slower if there are errors. The latter is hopefully the infrequent - * case. - * - * To understand the alternative algorithm, notice that set_parity(m, - * k, p) computes parity bytes such that: - * - * x^k * p(x) = m(x) (modulo g(x)). - * - * That is, to evaluate m(r^m), where r^m is a root of g(x), we can - * simply evaluate (r^m)^k*p(r^m). Also, notice that p is 0 if and - * only if s is zero. That is, if all parity bytes are 0, we know - * there is no error in the data and consequently there is no need to - * compute s(x) at all! In all other cases, we compute s(x) from p(x) - * by evaluating (r^m)^k*p(r^m) for m=-1, m=0, and m=1. The p(x) - * polynomial is evaluated via the Horner scheme. - */ -static int compute_syndromes(unsigned long *data, int nblocks, unsigned long *s) -{ - unsigned long p[3]; - - set_parity(data, nblocks, p, 1); - if (p[0] | p[1] | p[2]) { - /* Some of the checked columns do not have a zero - * syndrome. For simplicity, we compute the syndromes - * for all columns that we have computed the - * remainders for. - */ - s[0] = gfmul_exp_long( - gfadd_long(p[0], - gfmul_exp_long( - gfadd_long(p[1], - gfmul_exp_long(p[2], -1)), - -1)), - -nblocks); - s[1] = gfadd_long(gfadd_long(p[2], p[1]), p[0]); - s[2] = gfmul_exp_long( - gfadd_long(p[0], - gfmul_exp_long( - gfadd_long(p[1], - gfmul_exp_long(p[2], 1)), - 1)), - nblocks); - return 0; - } else { - return 1; - } -} - - -/* Correct the block in the column pointed to by DATA. There are NBAD - * CRC errors and their indices are in BAD_LOC[0], up to - * BAD_LOC[NBAD-1]. If NBAD>1, Ainv holds the inverse of the matrix - * of the linear system that needs to be solved to determine the error - * magnitudes. S[0], S[1], and S[2] are the syndrome values. If row - * j gets corrected, then bit j will be set in CORRECTION_MAP. - */ -static inline int correct_block(__u8 *data, int nblocks, - int nbad, int *bad_loc, Matrix Ainv, - __u8 *s, - SectorMap * correction_map) -{ - int ncorrected = 0; - int i; - __u8 t1, t2; - __u8 c0, c1, c2; /* check bytes */ - __u8 error_mag[3], log_error_mag; - __u8 *dp, l, e; - TRACE_FUN(ft_t_any); - - switch (nbad) { - case 0: - /* might have a CRC failure: */ - if (s[0] == 0) { - /* more than one error */ - TRACE_ABORT(-1, ft_t_err, - "ECC failed (0 CRC errors, >1 CRC failures)"); - } - t1 = gfdiv(s[1], s[0]); - if ((bad_loc[nbad++] = gflog[t1]) >= nblocks) { - TRACE(ft_t_err, - "ECC failed (0 CRC errors, >1 CRC failures)"); - TRACE_ABORT(-1, ft_t_err, - "attempt to correct data at %d", bad_loc[0]); - } - error_mag[0] = s[1]; - break; - case 1: - t1 = gfadd(gfmul_exp(s[1], bad_loc[0]), s[2]); - t2 = gfadd(gfmul_exp(s[0], bad_loc[0]), s[1]); - if (t1 == 0 && t2 == 0) { - /* one erasure, no error: */ - Ainv[0][0] = gfpow[bad_loc[0]]; - } else if (t1 == 0 || t2 == 0) { - /* one erasure and more than one error: */ - TRACE_ABORT(-1, ft_t_err, - "ECC failed (1 erasure, >1 error)"); - } else { - /* one erasure, one error: */ - if ((bad_loc[nbad++] = gflog[gfdiv(t1, t2)]) - >= nblocks) { - TRACE(ft_t_err, "ECC failed " - "(1 CRC errors, >1 CRC failures)"); - TRACE_ABORT(-1, ft_t_err, - "attempt to correct data at %d", - bad_loc[1]); - } - if (!gfinv2(bad_loc[0], bad_loc[1], Ainv)) { - /* inversion failed---must have more - * than one error - */ - TRACE_EXIT -1; - } - } - /* FALL THROUGH TO ERROR MAGNITUDE COMPUTATION: - */ - case 2: - case 3: - /* compute error magnitudes: */ - gfmat_mul(nbad, Ainv, s, error_mag); - break; - - default: - TRACE_ABORT(-1, ft_t_err, - "Internal Error: number of CRC errors > 3"); - } - - /* Perform correction by adding ERROR_MAG[i] to the byte at - * offset BAD_LOC[i]. Also add the value of the computed - * error polynomial to the syndrome values. If the correction - * was successful, the resulting check bytes should be zero - * (i.e., the corrected data is a valid code word). - */ - c0 = s[0]; - c1 = s[1]; - c2 = s[2]; - for (i = 0; i < nbad; ++i) { - e = error_mag[i]; - if (e) { - /* correct the byte at offset L by magnitude E: */ - l = bad_loc[i]; - dp = &data[l * FT_SECTOR_SIZE]; - *dp = gfadd(*dp, e); - *correction_map |= 1 << l; - ++ncorrected; - - log_error_mag = gflog[e]; - c0 = gfadd(c0, gfpow[mod255(log_error_mag - l)]); - c1 = gfadd(c1, e); - c2 = gfadd(c2, gfpow[mod255(log_error_mag + l)]); - } - } - if (c0 || c1 || c2) { - TRACE_ABORT(-1, ft_t_err, - "ECC self-check failed, too many errors"); - } - TRACE_EXIT ncorrected; -} - - -#if defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) - -/* Perform a sanity check on the computed parity bytes: - */ -static int sanity_check(unsigned long *data, int nblocks) -{ - TRACE_FUN(ft_t_any); - unsigned long s[3]; - - if (!compute_syndromes(data, nblocks, s)) { - TRACE_ABORT(0, ft_bug, - "Internal Error: syndrome self-check failed"); - } - TRACE_EXIT 1; -} - -#endif /* defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) */ - -/* Compute the parity for an entire segment of data. - */ -int ftape_ecc_set_segment_parity(struct memory_segment *mseg) -{ - int i; - __u8 *parity_bytes; - - parity_bytes = &mseg->data[(mseg->blocks - 3) * FT_SECTOR_SIZE]; - for (i = 0; i < FT_SECTOR_SIZE; i += sizeof(long)) { - set_parity((unsigned long *) &mseg->data[i], mseg->blocks - 3, - (unsigned long *) &parity_bytes[i], - FT_SECTOR_SIZE / sizeof(long)); -#ifdef ECC_PARANOID - if (!sanity_check((unsigned long *) &mseg->data[i], - mseg->blocks)) { - return -1; - } -#endif /* ECC_PARANOID */ - } - return 0; -} - - -/* Checks and corrects (if possible) the segment MSEG. Returns one of - * ECC_OK, ECC_CORRECTED, and ECC_FAILED. - */ -int ftape_ecc_correct_data(struct memory_segment *mseg) -{ - int col, i, result; - int ncorrected = 0; - int nerasures = 0; /* # of erasures (CRC errors) */ - int erasure_loc[3]; /* erasure locations */ - unsigned long ss[3]; - __u8 s[3]; - Matrix Ainv; - TRACE_FUN(ft_t_flow); - - mseg->corrected = 0; - - /* find first column that has non-zero syndromes: */ - for (col = 0; col < FT_SECTOR_SIZE; col += sizeof(long)) { - if (!compute_syndromes((unsigned long *) &mseg->data[col], - mseg->blocks, ss)) { - /* something is wrong---have to fix things */ - break; - } - } - if (col >= FT_SECTOR_SIZE) { - /* all syndromes are ok, therefore nothing to correct */ - TRACE_EXIT ECC_OK; - } - /* count the number of CRC errors if there were any: */ - if (mseg->read_bad) { - for (i = 0; i < mseg->blocks; i++) { - if (BAD_CHECK(mseg->read_bad, i)) { - if (nerasures >= 3) { - /* this is too much for ECC */ - TRACE_ABORT(ECC_FAILED, ft_t_err, - "ECC failed (>3 CRC errors)"); - } /* if */ - erasure_loc[nerasures++] = i; - } - } - } - /* - * If there are at least 2 CRC errors, determine inverse of matrix - * of linear system to be solved: - */ - switch (nerasures) { - case 2: - if (!gfinv2(erasure_loc[0], erasure_loc[1], Ainv)) { - TRACE_EXIT ECC_FAILED; - } - break; - case 3: - if (!gfinv3(erasure_loc[0], erasure_loc[1], - erasure_loc[2], Ainv)) { - TRACE_EXIT ECC_FAILED; - } - break; - default: - /* this is not an error condition... */ - break; - } - - do { - for (i = 0; i < sizeof(long); ++i) { - s[0] = ss[0]; - s[1] = ss[1]; - s[2] = ss[2]; - if (s[0] | s[1] | s[2]) { -#ifdef BIG_ENDIAN - result = correct_block( - &mseg->data[col + sizeof(long) - 1 - i], - mseg->blocks, - nerasures, - erasure_loc, - Ainv, - s, - &mseg->corrected); -#else - result = correct_block(&mseg->data[col + i], - mseg->blocks, - nerasures, - erasure_loc, - Ainv, - s, - &mseg->corrected); -#endif - if (result < 0) { - TRACE_EXIT ECC_FAILED; - } - ncorrected += result; - } - ss[0] >>= 8; - ss[1] >>= 8; - ss[2] >>= 8; - } - -#ifdef ECC_SANITY_CHECK - if (!sanity_check((unsigned long *) &mseg->data[col], - mseg->blocks)) { - TRACE_EXIT ECC_FAILED; - } -#endif /* ECC_SANITY_CHECK */ - - /* find next column with non-zero syndromes: */ - while ((col += sizeof(long)) < FT_SECTOR_SIZE) { - if (!compute_syndromes((unsigned long *) - &mseg->data[col], mseg->blocks, ss)) { - /* something is wrong---have to fix things */ - break; - } - } - } while (col < FT_SECTOR_SIZE); - if (ncorrected && nerasures == 0) { - TRACE(ft_t_warn, "block contained error not caught by CRC"); - } - TRACE((ncorrected > 0) ? ft_t_noise : ft_t_any, "number of corrections: %d", ncorrected); - TRACE_EXIT ncorrected ? ECC_CORRECTED : ECC_OK; -} diff --git a/drivers/char/ftape/lowlevel/ftape-ecc.h b/drivers/char/ftape/lowlevel/ftape-ecc.h deleted file mode 100644 index 4829146fe9a0..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ecc.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _FTAPE_ECC_H_ -#define _FTAPE_ECC_H_ - -/* - * Copyright (C) 1993 Ning and David Mosberger. - * Original: - * Copyright (C) 1993 Bas Laarhoven. - * Copyright (C) 1992 David L. Brown, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ecc.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:11 $ - * - * This file contains the definitions for the - * Reed-Solomon error correction code - * for the QIC-40/80 tape streamer device driver. - */ - -#include "../lowlevel/ftape-bsm.h" - -#define BAD_CLEAR(entry) ((entry)=0) -#define BAD_SET(entry,sector) ((entry)|=(1<<(sector))) -#define BAD_CHECK(entry,sector) ((entry)&(1<<(sector))) - -/* - * Return values for ecc_correct_data: - */ -enum { - ECC_OK, /* Data was correct. */ - ECC_CORRECTED, /* Correctable error in data. */ - ECC_FAILED, /* Could not correct data. */ -}; - -/* - * Representation of an in memory segment. MARKED_BAD lists the - * sectors that were marked bad during formatting. If the N-th sector - * in a segment is marked bad, bit 1< -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-ecc.h" -#include "../lowlevel/ftape-bsm.h" -#include "../lowlevel/ftape-format.h" - -#if defined(TESTING) -#define FT_FMT_SEGS_PER_BUF 50 -#else -#define FT_FMT_SEGS_PER_BUF (FT_BUFF_SIZE/(4*FT_SECTORS_PER_SEGMENT)) -#endif - -static spinlock_t ftape_format_lock; - -/* - * first segment of the new buffer - */ -static int switch_segment; - -/* - * at most 256 segments fit into one 32 kb buffer. Even TR-1 cartridges have - * more than this many segments per track, so better be careful. - * - * buffer_struct *buff: buffer to store the formatting coordinates in - * int start: starting segment for this buffer. - * int spt: segments per track - * - * Note: segment ids are relative to the start of the track here. - */ -static void setup_format_buffer(buffer_struct *buff, int start, int spt, - __u8 gap3) -{ - int to_do = spt - start; - TRACE_FUN(ft_t_flow); - - if (to_do > FT_FMT_SEGS_PER_BUF) { - to_do = FT_FMT_SEGS_PER_BUF; - } - buff->ptr = buff->address; - buff->remaining = to_do * FT_SECTORS_PER_SEGMENT; /* # sectors */ - buff->bytes = buff->remaining * 4; /* need 4 bytes per sector */ - buff->gap3 = gap3; - buff->segment_id = start; - buff->next_segment = start + to_do; - if (buff->next_segment >= spt) { - buff->next_segment = 0; /* 0 means: stop runner */ - } - buff->status = waiting; /* tells the isr that it can use - * this buffer - */ - TRACE_EXIT; -} - - -/* - * start formatting a new track. - */ -int ftape_format_track(const unsigned int track, const __u8 gap3) -{ - unsigned long flags; - buffer_struct *tail, *head; - int status; - TRACE_FUN(ft_t_flow); - - TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); - if (track & 1) { - if (!(status & QIC_STATUS_AT_EOT)) { - TRACE_CATCH(ftape_seek_to_eot(),); - } - } else { - if (!(status & QIC_STATUS_AT_BOT)) { - TRACE_CATCH(ftape_seek_to_bot(),); - } - } - ftape_abort_operation(); /* this sets ft_head = ft_tail = 0 */ - ftape_set_state(formatting); - - TRACE(ft_t_noise, - "Formatting track %d, logical: from segment %d to %d", - track, track * ft_segments_per_track, - (track + 1) * ft_segments_per_track - 1); - - /* - * initialize the buffer switching protocol for this track - */ - head = ftape_get_buffer(ft_queue_head); /* tape isn't running yet */ - tail = ftape_get_buffer(ft_queue_tail); /* tape isn't running yet */ - switch_segment = 0; - do { - FT_SIGNAL_EXIT(_DONT_BLOCK); - setup_format_buffer(tail, switch_segment, - ft_segments_per_track, gap3); - switch_segment = tail->next_segment; - } while ((switch_segment != 0) && - ((tail = ftape_next_buffer(ft_queue_tail)) != head)); - /* go */ - head->status = formatting; - TRACE_CATCH(ftape_seek_head_to_track(track),); - TRACE_CATCH(ftape_command(QIC_LOGICAL_FORWARD),); - spin_lock_irqsave(&ftape_format_lock, flags); - TRACE_CATCH(fdc_setup_formatting(head), restore_flags(flags)); - spin_unlock_irqrestore(&ftape_format_lock, flags); - TRACE_EXIT 0; -} - -/* return segment id of segment currently being formatted and do the - * buffer switching stuff. - */ -int ftape_format_status(unsigned int *segment_id) -{ - buffer_struct *tail = ftape_get_buffer(ft_queue_tail); - int result; - TRACE_FUN(ft_t_flow); - - while (switch_segment != 0 && - ftape_get_buffer(ft_queue_head) != tail) { - FT_SIGNAL_EXIT(_DONT_BLOCK); - /* need more buffers, first wait for empty buffer - */ - TRACE_CATCH(ftape_wait_segment(formatting),); - /* don't worry for gap3. If we ever hit this piece of code, - * then all buffer already have the correct gap3 set! - */ - setup_format_buffer(tail, switch_segment, - ft_segments_per_track, tail->gap3); - switch_segment = tail->next_segment; - if (switch_segment != 0) { - tail = ftape_next_buffer(ft_queue_tail); - } - } - /* should runner stop ? - */ - if (ft_runner_status == aborting || ft_runner_status == do_abort) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - TRACE(ft_t_warn, "Error formatting segment %d", - ftape_get_buffer(ft_queue_head)->segment_id); - (void)ftape_abort_operation(); - TRACE_EXIT (head->status != error) ? -EAGAIN : -EIO; - } - /* - * don't care if the timer expires, this is just kind of a - * "select" operation that lets the calling process sleep - * until something has happened - */ - if (fdc_interrupt_wait(5 * FT_SECOND) < 0) { - TRACE(ft_t_noise, "End of track %d at segment %d", - ft_location.track, - ftape_get_buffer(ft_queue_head)->segment_id); - result = 1; /* end of track, unlock module */ - } else { - result = 0; - } - /* - * the calling process should use the seg id to determine - * which parts of the dma buffers can be safely overwritten - * with new data. - */ - *segment_id = ftape_get_buffer(ft_queue_head)->segment_id; - /* - * Internally we start counting segment ids from the start of - * each track when formatting, but externally we keep them - * relative to the start of the tape: - */ - *segment_id += ft_location.track * ft_segments_per_track; - TRACE_EXIT result; -} - -/* - * The segment id is relative to the start of the tape - */ -int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm) -{ - int result; - int verify_done = 0; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Verifying segment %d", segment_id); - - if (ft_driver_state != verifying) { - TRACE(ft_t_noise, "calling ftape_abort_operation"); - if (ftape_abort_operation() < 0) { - TRACE(ft_t_err, "ftape_abort_operation failed"); - TRACE_EXIT -EIO; - } - } - *bsm = 0x00000000; - ftape_set_state(verifying); - for (;;) { - buffer_struct *tail; - /* - * Allow escape from this loop on signal - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - /* - * Search all full buffers for the first matching the - * wanted segment. Clear other buffers on the fly. - */ - tail = ftape_get_buffer(ft_queue_tail); - while (!verify_done && tail->status == done) { - /* - * Allow escape from this loop on signal ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - if (tail->segment_id == segment_id) { - /* If out buffer is already full, - * return its contents. - */ - TRACE(ft_t_flow, "found segment in cache: %d", - segment_id); - if ((tail->soft_error_map | - tail->hard_error_map) != 0) { - TRACE(ft_t_info,"bsm[%d] = 0x%08lx", - segment_id, - (unsigned long) - (tail->soft_error_map | - tail->hard_error_map)); - *bsm = (tail->soft_error_map | - tail->hard_error_map); - } - verify_done = 1; - } else { - TRACE(ft_t_flow,"zapping segment in cache: %d", - tail->segment_id); - } - tail->status = waiting; - tail = ftape_next_buffer(ft_queue_tail); - } - if (!verify_done && tail->status == verifying) { - if (tail->segment_id == segment_id) { - switch(ftape_wait_segment(verifying)) { - case 0: - break; - case -EINTR: - TRACE_ABORT(-EINTR, ft_t_warn, - "interrupted by " - "non-blockable signal"); - break; - default: - ftape_abort_operation(); - ftape_set_state(verifying); - /* be picky */ - TRACE_ABORT(-EIO, ft_t_warn, - "wait_segment failed"); - } - } else { - /* We're reading the wrong segment, - * stop runner. - */ - TRACE(ft_t_noise, "verifying wrong segment"); - ftape_abort_operation(); - ftape_set_state(verifying); - } - } - /* should runner stop ? - */ - if (ft_runner_status == aborting) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - if (head->status == error || - head->status == verifying) { - /* no data or overrun error */ - head->status = waiting; - } - TRACE_CATCH(ftape_dumb_stop(),); - } else { - /* If just passed last segment on tape: wait - * for BOT or EOT mark. Sets ft_runner_status to - * idle if at lEOT and successful - */ - TRACE_CATCH(ftape_handle_logical_eot(),); - } - if (verify_done) { - TRACE_EXIT 0; - } - /* Now at least one buffer is idle! - * Restart runner & tape if needed. - */ - /* We could optimize the following a little bit. We know that - * the bad sector map is empty. - */ - tail = ftape_get_buffer(ft_queue_tail); - if (tail->status == waiting) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - - ftape_setup_new_segment(head, segment_id, -1); - ftape_calc_next_cluster(head); - if (ft_runner_status == idle) { - result = ftape_start_tape(segment_id, - head->sector_offset); - switch(result) { - case 0: - break; - case -ETIME: - case -EINTR: - TRACE_ABORT(result, ft_t_err, "Error: " - "segment %d unreachable", - segment_id); - break; - default: - *bsm = EMPTY_SEGMENT; - TRACE_EXIT 0; - break; - } - } - head->status = verifying; - fdc_setup_read_write(head, FDC_VERIFY); - } - } - /* not reached */ - TRACE_EXIT -EIO; -} diff --git a/drivers/char/ftape/lowlevel/ftape-format.h b/drivers/char/ftape/lowlevel/ftape-format.h deleted file mode 100644 index f15161566643..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-format.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _FTAPE_FORMAT_H -#define _FTAPE_FORMAT_H - -/* - * Copyright (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-format.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:13 $ - * - * This file contains the low level definitions for the - * formatting support for the QIC-40/80/3010/3020 floppy-tape - * driver "ftape" for Linux. - */ - -#ifdef __KERNEL__ -extern int ftape_format_track(const unsigned int track, const __u8 gap3); -extern int ftape_format_status(unsigned int *segment_id); -extern int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm); -#endif /* __KERNEL__ */ - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-init.c b/drivers/char/ftape/lowlevel/ftape-init.c deleted file mode 100644 index 4998132a81d1..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-init.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * This file contains the code that interfaces the kernel - * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#ifdef CONFIG_ZFTAPE -#include -#endif - -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-buffer.h" -#include "../lowlevel/ftape-proc.h" -#include "../lowlevel/ftape-tracing.h" - - -#if defined(MODULE) && !defined(CONFIG_FT_NO_TRACE_AT_ALL) -static int ft_tracing = -1; -#endif - - -/* Called by modules package when installing the driver - * or by kernel during the initialization phase - */ -static int __init ftape_init(void) -{ - TRACE_FUN(ft_t_flow); - -#ifdef MODULE -#ifndef CONFIG_FT_NO_TRACE_AT_ALL - if (ft_tracing != -1) { - ftape_tracing = ft_tracing; - } -#endif - printk(KERN_INFO FTAPE_VERSION "\n"); - if (TRACE_LEVEL >= ft_t_info) { - printk( -KERN_INFO "(c) 1993-1996 Bas Laarhoven (bas@vimec.nl)\n" -KERN_INFO "(c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no)\n" -KERN_INFO "(c) 1996-1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" -KERN_INFO "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives\n"); - } -#else /* !MODULE */ - /* print a short no-nonsense boot message */ - printk(KERN_INFO FTAPE_VERSION "\n"); -#endif /* MODULE */ - TRACE(ft_t_info, "installing QIC-117 floppy tape hardware drive ... "); - TRACE(ft_t_info, "ftape_init @ 0x%p", ftape_init); - /* Allocate the DMA buffers. They are deallocated at cleanup() time. - */ -#ifdef TESTING -#ifdef MODULE - while (ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS) < 0) { - ftape_sleep(FT_SECOND/20); - if (signal_pending(current)) { - (void)ftape_set_nr_buffers(0); - TRACE(ft_t_bug, - "Killed by signal while allocating buffers."); - TRACE_ABORT(-EINTR, - ft_t_bug, "Free up memory and retry"); - } - } -#else - TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS), - (void)ftape_set_nr_buffers(0)); -#endif -#else - TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS), - (void)ftape_set_nr_buffers(0)); -#endif - ft_drive_sel = -1; - ft_failure = 1; /* inhibit any operation but open */ - ftape_udelay_calibrate(); /* must be before fdc_wait_calibrate ! */ - fdc_wait_calibrate(); -#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) - (void)ftape_proc_init(); -#endif -#ifdef CONFIG_ZFTAPE - (void)zft_init(); -#endif - TRACE_EXIT 0; -} - -module_param(ft_fdc_base, uint, 0); -MODULE_PARM_DESC(ft_fdc_base, "Base address of FDC controller."); -module_param(ft_fdc_irq, uint, 0); -MODULE_PARM_DESC(ft_fdc_irq, "IRQ (interrupt channel) to use."); -module_param(ft_fdc_dma, uint, 0); -MODULE_PARM_DESC(ft_fdc_dma, "DMA channel to use."); -module_param(ft_fdc_threshold, uint, 0); -MODULE_PARM_DESC(ft_fdc_threshold, "Threshold of the FDC Fifo."); -module_param(ft_fdc_rate_limit, uint, 0); -MODULE_PARM_DESC(ft_fdc_rate_limit, "Maximal data rate for FDC."); -module_param(ft_probe_fc10, bool, 0); -MODULE_PARM_DESC(ft_probe_fc10, - "If non-zero, probe for a Colorado FC-10/FC-20 controller."); -module_param(ft_mach2, bool, 0); -MODULE_PARM_DESC(ft_mach2, - "If non-zero, probe for a Mountain MACH-2 controller."); -#if defined(MODULE) && !defined(CONFIG_FT_NO_TRACE_AT_ALL) -module_param(ft_tracing, int, 0644); -MODULE_PARM_DESC(ft_tracing, - "Amount of debugging output, 0 <= tracing <= 8, default 3."); -#endif - -MODULE_AUTHOR( - "(c) 1993-1996 Bas Laarhoven (bas@vimec.nl), " - "(c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no), " - "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)"); -MODULE_DESCRIPTION( - "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives."); -MODULE_LICENSE("GPL"); - -static void __exit ftape_exit(void) -{ - TRACE_FUN(ft_t_flow); - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) - ftape_proc_destroy(); -#endif - (void)ftape_set_nr_buffers(0); - printk(KERN_INFO "ftape: unloaded.\n"); - TRACE_EXIT; -} - -module_init(ftape_init); -module_exit(ftape_exit); diff --git a/drivers/char/ftape/lowlevel/ftape-init.h b/drivers/char/ftape/lowlevel/ftape-init.h deleted file mode 100644 index 99a7b8ab086f..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-init.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _FTAPE_INIT_H -#define _FTAPE_INIT_H - -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-init.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:16 $ - * - * This file contains the definitions for the interface to - * the Linux kernel for floppy tape driver ftape. - * - */ - -#include -#include - -#define _NEVER_BLOCK (sigmask(SIGKILL) | sigmask(SIGSTOP)) -#define _DONT_BLOCK (_NEVER_BLOCK | sigmask(SIGINT)) -#define _DO_BLOCK (sigmask(SIGPIPE)) - -#ifndef QIC117_TAPE_MAJOR -#define QIC117_TAPE_MAJOR 27 -#endif - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-io.c b/drivers/char/ftape/lowlevel/ftape-io.c deleted file mode 100644 index 259015aeff55..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-io.c +++ /dev/null @@ -1,992 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996 Kai Harrekilde-Petersen, - * (C) 1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-io.c,v $ - * $Revision: 1.4 $ - * $Date: 1997/11/11 14:02:36 $ - * - * This file contains the general control functions for the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/ftape-calibr.h" - -/* Global vars. - */ -/* NOTE: sectors start numbering at 1, all others at 0 ! */ -ft_timeout_table ftape_timeout; -unsigned int ftape_tape_len; -volatile qic117_cmd_t ftape_current_command; -const struct qic117_command_table qic117_cmds[] = QIC117_COMMANDS; -int ftape_might_be_off_track; - -/* Local vars. - */ -static int diagnostic_mode; -static unsigned int ftape_udelay_count; -static unsigned int ftape_udelay_time; - -void ftape_udelay(unsigned int usecs) -{ - volatile int count = (ftape_udelay_count * usecs + - ftape_udelay_count - 1) / ftape_udelay_time; - volatile int i; - - while (count-- > 0) { - for (i = 0; i < 20; ++i); - } -} - -void ftape_udelay_calibrate(void) -{ - ftape_calibrate("ftape_udelay", - ftape_udelay, &ftape_udelay_count, &ftape_udelay_time); -} - -/* Delay (msec) routine. - */ -void ftape_sleep(unsigned int time) -{ - TRACE_FUN(ft_t_any); - - time *= 1000; /* msecs -> usecs */ - if (time < FT_USPT) { - /* Time too small for scheduler, do a busy wait ! */ - ftape_udelay(time); - } else { - long timeout; - unsigned long flags; - unsigned int ticks = (time + FT_USPT - 1) / FT_USPT; - - TRACE(ft_t_any, "%d msec, %d ticks", time/1000, ticks); - timeout = ticks; - save_flags(flags); - sti(); - msleep_interruptible(jiffies_to_msecs(timeout)); - /* Mmm. Isn't current->blocked == 0xffffffff ? - */ - if (signal_pending(current)) { - TRACE(ft_t_err, "awoken by non-blocked signal :-("); - } - restore_flags(flags); - } - TRACE_EXIT; -} - -/* send a command or parameter to the drive - * Generates # of step pulses. - */ -static inline int ft_send_to_drive(int arg) -{ - /* Always wait for a command_timeout period to separate - * individuals commands and/or parameters. - */ - ftape_sleep(3 * FT_MILLISECOND); - /* Keep cylinder nr within range, step towards home if possible. - */ - if (ftape_current_cylinder >= arg) { - return fdc_seek(ftape_current_cylinder - arg); - } else { - return fdc_seek(ftape_current_cylinder + arg); - } -} - -/* forward */ int ftape_report_raw_drive_status(int *status); - -static int ft_check_cmd_restrictions(qic117_cmd_t command) -{ - int status = -1; - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "%s", qic117_cmds[command].name); - /* A new motion command during an uninterruptible (motion) - * command requires a ready status before the new command can - * be issued. Otherwise a new motion command needs to be - * checked against required status. - */ - if (qic117_cmds[command].cmd_type == motion && - qic117_cmds[ftape_current_command].non_intr) { - ftape_report_raw_drive_status(&status); - if ((status & QIC_STATUS_READY) == 0) { - TRACE(ft_t_noise, - "motion cmd (%d) during non-intr cmd (%d)", - command, ftape_current_command); - TRACE(ft_t_noise, "waiting until drive gets ready"); - ftape_ready_wait(ftape_timeout.seek, - &status); - } - } - if (qic117_cmds[command].mask != 0) { - __u8 difference; - /* Some commands do require a certain status: - */ - if (status == -1) { /* not yet set */ - ftape_report_raw_drive_status(&status); - } - difference = ((status ^ qic117_cmds[command].state) & - qic117_cmds[command].mask); - /* Wait until the drive gets - * ready. This may last forever if - * the drive never gets ready... - */ - while ((difference & QIC_STATUS_READY) != 0) { - TRACE(ft_t_noise, "command %d issued while not ready", - command); - TRACE(ft_t_noise, "waiting until drive gets ready"); - if (ftape_ready_wait(ftape_timeout.seek, - &status) == -EINTR) { - /* Bail out on signal ! - */ - TRACE_ABORT(-EINTR, ft_t_warn, - "interrupted by non-blockable signal"); - } - difference = ((status ^ qic117_cmds[command].state) & - qic117_cmds[command].mask); - } - while ((difference & QIC_STATUS_ERROR) != 0) { - int err; - qic117_cmd_t cmd; - - TRACE(ft_t_noise, - "command %d issued while error pending", - command); - TRACE(ft_t_noise, "clearing error status"); - ftape_report_error(&err, &cmd, 1); - ftape_report_raw_drive_status(&status); - difference = ((status ^ qic117_cmds[command].state) & - qic117_cmds[command].mask); - if ((difference & QIC_STATUS_ERROR) != 0) { - /* Bail out on fatal signal ! - */ - FT_SIGNAL_EXIT(_NEVER_BLOCK); - } - } - if (difference) { - /* Any remaining difference can't be solved - * here. - */ - if (difference & (QIC_STATUS_CARTRIDGE_PRESENT | - QIC_STATUS_NEW_CARTRIDGE | - QIC_STATUS_REFERENCED)) { - TRACE(ft_t_warn, - "Fatal: tape removed or reinserted !"); - ft_failure = 1; - } else { - TRACE(ft_t_err, "wrong state: 0x%02x should be: 0x%02x", - status & qic117_cmds[command].mask, - qic117_cmds[command].state); - } - TRACE_EXIT -EIO; - } - if (~status & QIC_STATUS_READY & qic117_cmds[command].mask) { - TRACE_ABORT(-EBUSY, ft_t_err, "Bad: still busy!"); - } - } - TRACE_EXIT 0; -} - -/* Issue a tape command: - */ -int ftape_command(qic117_cmd_t command) -{ - int result = 0; - static int level; - TRACE_FUN(ft_t_any); - - if ((unsigned int)command > NR_ITEMS(qic117_cmds)) { - /* This is a bug we'll want to know about too. - */ - TRACE_ABORT(-EIO, ft_t_bug, "bug - bad command: %d", command); - } - if (++level > 5) { /* This is a bug we'll want to know about. */ - --level; - TRACE_ABORT(-EIO, ft_t_bug, "bug - recursion for command: %d", - command); - } - /* disable logging and restriction check for some commands, - * check all other commands that have a prescribed starting - * status. - */ - if (diagnostic_mode) { - TRACE(ft_t_flow, "diagnostic command %d", command); - } else if (command == QIC_REPORT_DRIVE_STATUS || - command == QIC_REPORT_NEXT_BIT) { - TRACE(ft_t_any, "%s", qic117_cmds[command].name); - } else { - TRACE_CATCH(ft_check_cmd_restrictions(command), --level); - } - /* Now all conditions are met or result was < 0. - */ - result = ft_send_to_drive((unsigned int)command); - if (qic117_cmds[command].cmd_type == motion && - command != QIC_LOGICAL_FORWARD && command != QIC_STOP_TAPE) { - ft_location.known = 0; - } - ftape_current_command = command; - --level; - TRACE_EXIT result; -} - -/* Send a tape command parameter: - * Generates command # of step pulses. - * Skips tape-status call ! - */ -int ftape_parameter(unsigned int parameter) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "called with parameter = %d", parameter); - TRACE_EXIT ft_send_to_drive(parameter + 2); -} - -/* Wait for the drive to get ready. - * timeout time in milli-seconds - * Returned status is valid if result != -EIO - * - * Should we allow to be killed by SIGINT? (^C) - * Would be nice at least for large timeouts. - */ -int ftape_ready_wait(unsigned int timeout, int *status) -{ - unsigned long t0; - unsigned int poll_delay; - int signal_retries; - TRACE_FUN(ft_t_any); - - /* the following ** REALLY ** reduces the system load when - * e.g. one simply rewinds or retensions. The tape is slow - * anyway. It is really not necessary to detect error - * conditions with 1/10 seconds granularity - * - * On my AMD 133MHZ 486: 100 ms: 23% system load - * 1 sec: 5% - * 5 sec: 0.6%, yeah - */ - if (timeout <= FT_SECOND) { - poll_delay = 100 * FT_MILLISECOND; - signal_retries = 20; /* two seconds */ - } else if (timeout < 20 * FT_SECOND) { - TRACE(ft_t_flow, "setting poll delay to 1 second"); - poll_delay = FT_SECOND; - signal_retries = 2; /* two seconds */ - } else { - TRACE(ft_t_flow, "setting poll delay to 5 seconds"); - poll_delay = 5 * FT_SECOND; - signal_retries = 1; /* five seconds */ - } - for (;;) { - t0 = jiffies; - TRACE_CATCH(ftape_report_raw_drive_status(status),); - if (*status & QIC_STATUS_READY) { - TRACE_EXIT 0; - } - if (!signal_retries--) { - FT_SIGNAL_EXIT(_NEVER_BLOCK); - } - if ((int)timeout >= 0) { - /* this will fail when jiffies wraps around about - * once every year :-) - */ - timeout -= ((jiffies - t0) * FT_SECOND) / HZ; - if (timeout <= 0) { - TRACE_ABORT(-ETIME, ft_t_err, "timeout"); - } - ftape_sleep(poll_delay); - timeout -= poll_delay; - } else { - ftape_sleep(poll_delay); - } - } - TRACE_EXIT -ETIME; -} - -/* Issue command and wait up to timeout milli seconds for drive ready - */ -int ftape_command_wait(qic117_cmd_t command, unsigned int timeout, int *status) -{ - int result; - - /* Drive should be ready, issue command - */ - result = ftape_command(command); - if (result >= 0) { - result = ftape_ready_wait(timeout, status); - } - return result; -} - -static int ftape_parameter_wait(unsigned int parm, unsigned int timeout, int *status) -{ - int result; - - /* Drive should be ready, issue command - */ - result = ftape_parameter(parm); - if (result >= 0) { - result = ftape_ready_wait(timeout, status); - } - return result; -} - -/*-------------------------------------------------------------------------- - * Report operations - */ - -/* Query the drive about its status. The command is sent and - result_length bits of status are returned (2 extra bits are read - for start and stop). */ - -int ftape_report_operation(int *status, - qic117_cmd_t command, - int result_length) -{ - int i, st3; - unsigned int t0; - unsigned int dt; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_command(command),); - t0 = ftape_timestamp(); - i = 0; - do { - ++i; - ftape_sleep(3 * FT_MILLISECOND); /* see remark below */ - TRACE_CATCH(fdc_sense_drive_status(&st3),); - dt = ftape_timediff(t0, ftape_timestamp()); - /* Ack should be asserted within Ttimout + Tack = 6 msec. - * Looks like some drives fail to do this so extend this - * period to 300 msec. - */ - } while (!(st3 & ST3_TRACK_0) && dt < 300000); - if (!(st3 & ST3_TRACK_0)) { - TRACE(ft_t_err, - "No acknowledge after %u msec. (%i iter)", dt / 1000, i); - TRACE_ABORT(-EIO, ft_t_err, "timeout on Acknowledge"); - } - /* dt may be larger than expected because of other tasks - * scheduled while we were sleeping. - */ - if (i > 1 && dt > 6000) { - TRACE(ft_t_err, "Acknowledge after %u msec. (%i iter)", - dt / 1000, i); - } - *status = 0; - for (i = 0; i < result_length + 1; i++) { - TRACE_CATCH(ftape_command(QIC_REPORT_NEXT_BIT),); - TRACE_CATCH(fdc_sense_drive_status(&st3),); - if (i < result_length) { - *status |= ((st3 & ST3_TRACK_0) ? 1 : 0) << i; - } else if ((st3 & ST3_TRACK_0) == 0) { - TRACE_ABORT(-EIO, ft_t_err, "missing status stop bit"); - } - } - /* this command will put track zero and index back into normal state */ - (void)ftape_command(QIC_REPORT_NEXT_BIT); - TRACE_EXIT 0; -} - -/* Report the current drive status. */ - -int ftape_report_raw_drive_status(int *status) -{ - int result; - int count = 0; - TRACE_FUN(ft_t_any); - - do { - result = ftape_report_operation(status, - QIC_REPORT_DRIVE_STATUS, 8); - } while (result < 0 && ++count <= 3); - if (result < 0) { - TRACE_ABORT(-EIO, ft_t_err, - "report_operation failed after %d trials", count); - } - if ((*status & 0xff) == 0xff) { - TRACE_ABORT(-EIO, ft_t_err, - "impossible drive status 0xff"); - } - if (*status & QIC_STATUS_READY) { - ftape_current_command = QIC_NO_COMMAND; /* completed */ - } - ft_last_status.status.drive_status = (__u8)(*status & 0xff); - TRACE_EXIT 0; -} - -int ftape_report_drive_status(int *status) -{ - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_report_raw_drive_status(status),); - if (*status & QIC_STATUS_NEW_CARTRIDGE || - !(*status & QIC_STATUS_CARTRIDGE_PRESENT)) { - ft_failure = 1; /* will inhibit further operations */ - TRACE_EXIT -EIO; - } - if (*status & QIC_STATUS_READY && *status & QIC_STATUS_ERROR) { - /* Let caller handle all errors */ - TRACE_ABORT(1, ft_t_warn, "warning: error status set!"); - } - TRACE_EXIT 0; -} - -int ftape_report_error(unsigned int *error, - qic117_cmd_t *command, int report) -{ - static const ftape_error ftape_errors[] = QIC117_ERRORS; - int code; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_report_operation(&code, QIC_REPORT_ERROR_CODE, 16),); - *error = (unsigned int)(code & 0xff); - *command = (qic117_cmd_t)((code>>8)&0xff); - /* remember hardware status, maybe useful for status ioctls - */ - ft_last_error.error.command = (__u8)*command; - ft_last_error.error.error = (__u8)*error; - if (!report) { - TRACE_EXIT 0; - } - if (*error == 0) { - TRACE_ABORT(0, ft_t_info, "No error"); - } - TRACE(ft_t_info, "errorcode: %d", *error); - if (*error < NR_ITEMS(ftape_errors)) { - TRACE(ft_t_noise, "%sFatal ERROR:", - (ftape_errors[*error].fatal ? "" : "Non-")); - TRACE(ft_t_noise, "%s ...", ftape_errors[*error].message); - } else { - TRACE(ft_t_noise, "Unknown ERROR !"); - } - if ((unsigned int)*command < NR_ITEMS(qic117_cmds) && - qic117_cmds[*command].name != NULL) { - TRACE(ft_t_noise, "... caused by command \'%s\'", - qic117_cmds[*command].name); - } else { - TRACE(ft_t_noise, "... caused by unknown command %d", - *command); - } - TRACE_EXIT 0; -} - -int ftape_report_configuration(qic_model *model, - unsigned int *rate, - int *qic_std, - int *tape_len) -{ - int result; - int config; - int status; - static const unsigned int qic_rates[ 4] = { 250, 2000, 500, 1000 }; - TRACE_FUN(ft_t_any); - - result = ftape_report_operation(&config, - QIC_REPORT_DRIVE_CONFIGURATION, 8); - if (result < 0) { - ft_last_status.status.drive_config = (__u8)0x00; - *model = prehistoric; - *rate = 500; - *qic_std = QIC_TAPE_QIC40; - *tape_len = 205; - TRACE_EXIT 0; - } else { - ft_last_status.status.drive_config = (__u8)(config & 0xff); - } - *rate = qic_rates[(config & QIC_CONFIG_RATE_MASK) >> QIC_CONFIG_RATE_SHIFT]; - result = ftape_report_operation(&status, QIC_REPORT_TAPE_STATUS, 8); - if (result < 0) { - ft_last_status.status.tape_status = (__u8)0x00; - /* pre- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is valid. - */ - *qic_std = (config & QIC_CONFIG_80) ? - QIC_TAPE_QIC80 : QIC_TAPE_QIC40; - /* ?? how's about 425ft tapes? */ - *tape_len = (config & QIC_CONFIG_LONG) ? 307 : 0; - *model = pre_qic117c; - result = 0; - } else { - ft_last_status.status.tape_status = (__u8)(status & 0xff); - *model = post_qic117b; - TRACE(ft_t_any, "report tape status result = %02x", status); - /* post- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is - * invalid. - */ - switch (status & QIC_TAPE_STD_MASK) { - case QIC_TAPE_QIC40: - case QIC_TAPE_QIC80: - case QIC_TAPE_QIC3020: - case QIC_TAPE_QIC3010: - *qic_std = status & QIC_TAPE_STD_MASK; - break; - default: - *qic_std = -1; - break; - } - switch (status & QIC_TAPE_LEN_MASK) { - case QIC_TAPE_205FT: - /* 205 or 425+ ft 550 Oe tape */ - *tape_len = 0; - break; - case QIC_TAPE_307FT: - /* 307.5 ft 550 Oe Extended Length (XL) tape */ - *tape_len = 307; - break; - case QIC_TAPE_VARIABLE: - /* Variable length 550 Oe tape */ - *tape_len = 0; - break; - case QIC_TAPE_1100FT: - /* 1100 ft 550 Oe tape */ - *tape_len = 1100; - break; - case QIC_TAPE_FLEX: - /* Variable length 900 Oe tape */ - *tape_len = 0; - break; - default: - *tape_len = -1; - break; - } - if (*qic_std == -1 || *tape_len == -1) { - TRACE(ft_t_any, - "post qic-117b spec drive with unknown tape"); - } - result = *tape_len == -1 ? -EIO : 0; - if (status & QIC_TAPE_WIDE) { - switch (*qic_std) { - case QIC_TAPE_QIC80: - TRACE(ft_t_info, "TR-1 tape detected"); - break; - case QIC_TAPE_QIC3010: - TRACE(ft_t_info, "TR-2 tape detected"); - break; - case QIC_TAPE_QIC3020: - TRACE(ft_t_info, "TR-3 tape detected"); - break; - default: - TRACE(ft_t_warn, - "Unknown Travan tape type detected"); - break; - } - } - } - TRACE_EXIT (result < 0) ? -EIO : 0; -} - -static int ftape_report_rom_version(int *version) -{ - - if (ftape_report_operation(version, QIC_REPORT_ROM_VERSION, 8) < 0) { - return -EIO; - } else { - return 0; - } -} - -void ftape_report_vendor_id(unsigned int *id) -{ - int result; - TRACE_FUN(ft_t_any); - - /* We'll try to get a vendor id from the drive. First - * according to the QIC-117 spec, a 16-bit id is requested. - * If that fails we'll try an 8-bit version, otherwise we'll - * try an undocumented query. - */ - result = ftape_report_operation((int *) id, QIC_REPORT_VENDOR_ID, 16); - if (result < 0) { - result = ftape_report_operation((int *) id, - QIC_REPORT_VENDOR_ID, 8); - if (result < 0) { - /* The following is an undocumented call found - * in the CMS code. - */ - result = ftape_report_operation((int *) id, 24, 8); - if (result < 0) { - *id = UNKNOWN_VENDOR; - } else { - TRACE(ft_t_noise, "got old 8 bit id: %04x", - *id); - *id |= 0x20000; - } - } else { - TRACE(ft_t_noise, "got 8 bit id: %04x", *id); - *id |= 0x10000; - } - } else { - TRACE(ft_t_noise, "got 16 bit id: %04x", *id); - } - if (*id == 0x0047) { - int version; - int sign; - - if (ftape_report_rom_version(&version) < 0) { - TRACE(ft_t_bug, "report rom version failed"); - TRACE_EXIT; - } - TRACE(ft_t_noise, "CMS rom version: %d", version); - ftape_command(QIC_ENTER_DIAGNOSTIC_1); - ftape_command(QIC_ENTER_DIAGNOSTIC_1); - diagnostic_mode = 1; - if (ftape_report_operation(&sign, 9, 8) < 0) { - unsigned int error; - qic117_cmd_t command; - - ftape_report_error(&error, &command, 1); - ftape_command(QIC_ENTER_PRIMARY_MODE); - diagnostic_mode = 0; - TRACE_EXIT; /* failure ! */ - } else { - TRACE(ft_t_noise, "CMS signature: %02x", sign); - } - if (sign == 0xa5) { - result = ftape_report_operation(&sign, 37, 8); - if (result < 0) { - if (version >= 63) { - *id = 0x8880; - TRACE(ft_t_noise, - "This is an Iomega drive !"); - } else { - *id = 0x0047; - TRACE(ft_t_noise, - "This is a real CMS drive !"); - } - } else { - *id = 0x0047; - TRACE(ft_t_noise, "CMS status: %d", sign); - } - } else { - *id = UNKNOWN_VENDOR; - } - ftape_command(QIC_ENTER_PRIMARY_MODE); - diagnostic_mode = 0; - } - TRACE_EXIT; -} - -static int qic_rate_code(unsigned int rate) -{ - switch (rate) { - case 250: - return QIC_CONFIG_RATE_250; - case 500: - return QIC_CONFIG_RATE_500; - case 1000: - return QIC_CONFIG_RATE_1000; - case 2000: - return QIC_CONFIG_RATE_2000; - default: - return QIC_CONFIG_RATE_500; - } -} - -static int ftape_set_rate_test(unsigned int *max_rate) -{ - unsigned int error; - qic117_cmd_t command; - int status; - int supported = 0; - TRACE_FUN(ft_t_any); - - /* Check if the drive does support the select rate command - * by testing all different settings. If any one is accepted - * we assume the command is supported, else not. - */ - for (*max_rate = 2000; *max_rate >= 250; *max_rate /= 2) { - if (ftape_command(QIC_SELECT_RATE) < 0) { - continue; - } - if (ftape_parameter_wait(qic_rate_code(*max_rate), - 1 * FT_SECOND, &status) < 0) { - continue; - } - if (status & QIC_STATUS_ERROR) { - ftape_report_error(&error, &command, 0); - continue; - } - supported = 1; /* did accept a request */ - break; - } - TRACE(ft_t_noise, "Select Rate command is%s supported", - supported ? "" : " not"); - TRACE_EXIT supported; -} - -int ftape_set_data_rate(unsigned int new_rate /* Kbps */, unsigned int qic_std) -{ - int status; - int result = 0; - unsigned int data_rate = new_rate; - static int supported; - int rate_changed = 0; - qic_model dummy_model; - unsigned int dummy_qic_std, dummy_tape_len; - TRACE_FUN(ft_t_any); - - if (ft_drive_max_rate == 0) { /* first time */ - supported = ftape_set_rate_test(&ft_drive_max_rate); - } - if (supported) { - ftape_command(QIC_SELECT_RATE); - result = ftape_parameter_wait(qic_rate_code(new_rate), - 1 * FT_SECOND, &status); - if (result >= 0 && !(status & QIC_STATUS_ERROR)) { - rate_changed = 1; - } - } - TRACE_CATCH(result = ftape_report_configuration(&dummy_model, - &data_rate, - &dummy_qic_std, - &dummy_tape_len),); - if (data_rate != new_rate) { - if (!supported) { - TRACE(ft_t_warn, "Rate change not supported!"); - } else if (rate_changed) { - TRACE(ft_t_warn, "Requested: %d, got %d", - new_rate, data_rate); - } else { - TRACE(ft_t_warn, "Rate change failed!"); - } - result = -EINVAL; - } - /* - * Set data rate and write precompensation as specified: - * - * | QIC-40/80 | QIC-3010/3020 - * rate | precomp | precomp - * ----------+-------------+-------------- - * 250 Kbps. | 250 ns. | 0 ns. - * 500 Kbps. | 125 ns. | 0 ns. - * 1 Mbps. | 42 ns. | 0 ns. - * 2 Mbps | N/A | 0 ns. - */ - if ((qic_std == QIC_TAPE_QIC40 && data_rate > 500) || - (qic_std == QIC_TAPE_QIC80 && data_rate > 1000)) { - TRACE_ABORT(-EINVAL, - ft_t_warn, "Datarate too high for QIC-mode"); - } - TRACE_CATCH(fdc_set_data_rate(data_rate),_res = -EINVAL); - ft_data_rate = data_rate; - if (qic_std == QIC_TAPE_QIC40 || qic_std == QIC_TAPE_QIC80) { - switch (data_rate) { - case 250: - fdc_set_write_precomp(250); - break; - default: - case 500: - fdc_set_write_precomp(125); - break; - case 1000: - fdc_set_write_precomp(42); - break; - } - } else { - fdc_set_write_precomp(0); - } - TRACE_EXIT result; -} - -/* The next two functions are used to cope with excessive overrun errors - */ -int ftape_increase_threshold(void) -{ - TRACE_FUN(ft_t_flow); - - if (fdc.type < i82077 || ft_fdc_threshold >= 12) { - TRACE_ABORT(-EIO, ft_t_err, "cannot increase fifo threshold"); - } - if (fdc_fifo_threshold(++ft_fdc_threshold, NULL, NULL, NULL) < 0) { - TRACE(ft_t_err, "cannot increase fifo threshold"); - ft_fdc_threshold --; - fdc_reset(); - } - TRACE(ft_t_info, "New FIFO threshold: %d", ft_fdc_threshold); - TRACE_EXIT 0; -} - -int ftape_half_data_rate(void) -{ - if (ft_data_rate < 500) { - return -1; - } - if (ftape_set_data_rate(ft_data_rate / 2, ft_qic_std) < 0) { - return -EIO; - } - ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); - return 0; -} - -/* Seek the head to the specified track. - */ -int ftape_seek_head_to_track(unsigned int track) -{ - int status; - TRACE_FUN(ft_t_any); - - ft_location.track = -1; /* remains set in case of error */ - if (track >= ft_tracks_per_tape) { - TRACE_ABORT(-EINVAL, ft_t_bug, "track out of bounds"); - } - TRACE(ft_t_flow, "seeking track %d", track); - TRACE_CATCH(ftape_command(QIC_SEEK_HEAD_TO_TRACK),); - TRACE_CATCH(ftape_parameter_wait(track, ftape_timeout.head_seek, - &status),); - ft_location.track = track; - ftape_might_be_off_track = 0; - TRACE_EXIT 0; -} - -int ftape_wakeup_drive(wake_up_types method) -{ - int status; - int motor_on = 0; - TRACE_FUN(ft_t_any); - - switch (method) { - case wake_up_colorado: - TRACE_CATCH(ftape_command(QIC_PHANTOM_SELECT),); - TRACE_CATCH(ftape_parameter(0 /* ft_drive_sel ?? */),); - break; - case wake_up_mountain: - TRACE_CATCH(ftape_command(QIC_SOFT_SELECT),); - ftape_sleep(FT_MILLISECOND); /* NEEDED */ - TRACE_CATCH(ftape_parameter(18),); - break; - case wake_up_insight: - ftape_sleep(100 * FT_MILLISECOND); - motor_on = 1; - fdc_motor(motor_on); /* enable is done by motor-on */ - case no_wake_up: - break; - default: - TRACE_EXIT -ENODEV; /* unknown wakeup method */ - break; - } - /* If wakeup succeeded we shouldn't get an error here.. - */ - TRACE_CATCH(ftape_report_raw_drive_status(&status), - if (motor_on) { - fdc_motor(0); - }); - TRACE_EXIT 0; -} - -int ftape_put_drive_to_sleep(wake_up_types method) -{ - TRACE_FUN(ft_t_any); - - switch (method) { - case wake_up_colorado: - TRACE_CATCH(ftape_command(QIC_PHANTOM_DESELECT),); - break; - case wake_up_mountain: - TRACE_CATCH(ftape_command(QIC_SOFT_DESELECT),); - break; - case wake_up_insight: - fdc_motor(0); /* enable is done by motor-on */ - case no_wake_up: /* no wakeup / no sleep ! */ - break; - default: - TRACE_EXIT -ENODEV; /* unknown wakeup method */ - } - TRACE_EXIT 0; -} - -int ftape_reset_drive(void) -{ - int result = 0; - int status; - unsigned int err_code; - qic117_cmd_t err_command; - int i; - TRACE_FUN(ft_t_any); - - /* We want to re-establish contact with our drive. Fire a - * number of reset commands (single step pulses) and pray for - * success. - */ - for (i = 0; i < 2; ++i) { - TRACE(ft_t_flow, "Resetting fdc"); - fdc_reset(); - ftape_sleep(10 * FT_MILLISECOND); - TRACE(ft_t_flow, "Reset command to drive"); - result = ftape_command(QIC_RESET); - if (result == 0) { - ftape_sleep(1 * FT_SECOND); /* drive not - * accessible - * during 1 second - */ - TRACE(ft_t_flow, "Re-selecting drive"); - - /* Strange, the QIC-117 specs don't mention - * this but the drive gets deselected after a - * soft reset ! So we need to enable it - * again. - */ - if (ftape_wakeup_drive(ft_drive_type.wake_up) < 0) { - TRACE(ft_t_err, "Wakeup failed !"); - } - TRACE(ft_t_flow, "Waiting until drive gets ready"); - result= ftape_ready_wait(ftape_timeout.reset, &status); - if (result == 0 && (status & QIC_STATUS_ERROR)) { - result = ftape_report_error(&err_code, - &err_command, 1); - if (result == 0 && err_code == 27) { - /* Okay, drive saw reset - * command and responded as it - * should - */ - break; - } else { - result = -EIO; - } - } else { - result = -EIO; - } - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - } - if (result != 0) { - TRACE(ft_t_err, "General failure to reset tape drive"); - } else { - /* Restore correct settings: keep original rate - */ - ftape_set_data_rate(ft_data_rate, ft_qic_std); - } - ftape_init_drive_needed = 1; - TRACE_EXIT result; -} diff --git a/drivers/char/ftape/lowlevel/ftape-io.h b/drivers/char/ftape/lowlevel/ftape-io.h deleted file mode 100644 index 26a7baad8717..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-io.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef _FTAPE_IO_H -#define _FTAPE_IO_H - -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-io.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:18 $ - * - * This file contains definitions for the glue part of the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include -#include - -typedef struct { - unsigned int seek; - unsigned int reset; - unsigned int rewind; - unsigned int head_seek; - unsigned int stop; - unsigned int pause; -} ft_timeout_table; - -typedef enum { - prehistoric, pre_qic117c, post_qic117b, post_qic117d -} qic_model; - -/* - * ftape-io.c defined global vars. - */ -extern ft_timeout_table ftape_timeout; -extern unsigned int ftape_tape_len; -extern volatile qic117_cmd_t ftape_current_command; -extern const struct qic117_command_table qic117_cmds[]; -extern int ftape_might_be_off_track; - -/* - * ftape-io.c defined global functions. - */ -extern void ftape_udelay(unsigned int usecs); -extern void ftape_udelay_calibrate(void); -extern void ftape_sleep(unsigned int time); -extern void ftape_report_vendor_id(unsigned int *id); -extern int ftape_command(qic117_cmd_t command); -extern int ftape_command_wait(qic117_cmd_t command, - unsigned int timeout, - int *status); -extern int ftape_parameter(unsigned int parameter); -extern int ftape_report_operation(int *status, - qic117_cmd_t command, - int result_length); -extern int ftape_report_configuration(qic_model *model, - unsigned int *rate, - int *qic_std, - int *tape_len); -extern int ftape_report_drive_status(int *status); -extern int ftape_report_raw_drive_status(int *status); -extern int ftape_report_status(int *status); -extern int ftape_ready_wait(unsigned int timeout, int *status); -extern int ftape_seek_head_to_track(unsigned int track); -extern int ftape_set_data_rate(unsigned int new_rate, unsigned int qic_std); -extern int ftape_report_error(unsigned int *error, - qic117_cmd_t *command, - int report); -extern int ftape_reset_drive(void); -extern int ftape_put_drive_to_sleep(wake_up_types method); -extern int ftape_wakeup_drive(wake_up_types method); -extern int ftape_increase_threshold(void); -extern int ftape_half_data_rate(void); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-proc.c b/drivers/char/ftape/lowlevel/ftape-proc.c deleted file mode 100644 index e805b15e0a12..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-proc.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-proc.c,v $ - * $Revision: 1.11 $ - * $Date: 1997/10/24 14:47:37 $ - * - * This file contains the procfs interface for the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - - * Old code removed, switched to dynamic proc entry. - */ - - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) - -#include - -#include -#include -#include - -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-proc.h" -#include "../lowlevel/ftape-tracing.h" - -static size_t get_driver_info(char *buf) -{ - const char *debug_level[] = { "bugs" , - "errors", - "warnings", - "informational", - "noisy", - "program flow", - "fdc and dma", - "data flow", - "anything" }; - - return sprintf(buf, - "version : %s\n" - "used data rate: %d kbit/sec\n" - "dma memory : %d kb\n" - "debug messages: %s\n", - FTAPE_VERSION, - ft_data_rate, - FT_BUFF_SIZE * ft_nr_buffers >> 10, - debug_level[TRACE_LEVEL]); -} - -static size_t get_tapedrive_info(char *buf) -{ - return sprintf(buf, - "vendor id : 0x%04x\n" - "drive name: %s\n" - "wind speed: %d ips\n" - "wakeup : %s\n" - "max. rate : %d kbit/sec\n", - ft_drive_type.vendor_id, - ft_drive_type.name, - ft_drive_type.speed, - ((ft_drive_type.wake_up == no_wake_up) - ? "No wakeup needed" : - ((ft_drive_type.wake_up == wake_up_colorado) - ? "Colorado" : - ((ft_drive_type.wake_up == wake_up_mountain) - ? "Mountain" : - ((ft_drive_type.wake_up == wake_up_insight) - ? "Motor on" : - "Unknown")))), - ft_drive_max_rate); -} - -static size_t get_cartridge_info(char *buf) -{ - if (ftape_init_drive_needed) { - return sprintf(buf, "uninitialized\n"); - } - if (ft_no_tape) { - return sprintf(buf, "no cartridge inserted\n"); - } - return sprintf(buf, - "segments : %5d\n" - "tracks : %5d\n" - "length : %5dft\n" - "formatted : %3s\n" - "writable : %3s\n" - "QIC spec. : QIC-%s\n" - "fmt-code : %1d\n", - ft_segments_per_track, - ft_tracks_per_tape, - ftape_tape_len, - (ft_formatted == 1) ? "yes" : "no", - (ft_write_protected == 1) ? "no" : "yes", - ((ft_qic_std == QIC_TAPE_QIC40) ? "40" : - ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : - ((ft_qic_std == QIC_TAPE_QIC3010) ? "3010" : - ((ft_qic_std == QIC_TAPE_QIC3020) ? "3020" : - "???")))), - ft_format_code); -} - -static size_t get_controller_info(char *buf) -{ - const char *fdc_name[] = { "no fdc", - "i8272", - "i82077", - "i82077AA", - "Colorado FC-10 or FC-20", - "i82078", - "i82078_1" }; - - return sprintf(buf, - "FDC type : %s\n" - "FDC base : 0x%03x\n" - "FDC irq : %d\n" - "FDC dma : %d\n" - "FDC thr. : %d\n" - "max. rate : %d kbit/sec\n", - ft_mach2 ? "Mountain MACH-2" : fdc_name[fdc.type], - fdc.sra, fdc.irq, fdc.dma, - ft_fdc_threshold, ft_fdc_max_rate); -} - -static size_t get_history_info(char *buf) -{ - size_t len; - - len = sprintf(buf, - "\nFDC isr statistics\n" - " id_am_errors : %3d\n" - " id_crc_errors : %3d\n" - " data_am_errors : %3d\n" - " data_crc_errors : %3d\n" - " overrun_errors : %3d\n" - " no_data_errors : %3d\n" - " retries : %3d\n", - ft_history.id_am_errors, ft_history.id_crc_errors, - ft_history.data_am_errors, ft_history.data_crc_errors, - ft_history.overrun_errors, ft_history.no_data_errors, - ft_history.retries); - len += sprintf(buf + len, - "\nECC statistics\n" - " crc_errors : %3d\n" - " crc_failures : %3d\n" - " ecc_failures : %3d\n" - " sectors corrected: %3d\n", - ft_history.crc_errors, ft_history.crc_failures, - ft_history.ecc_failures, ft_history.corrected); - len += sprintf(buf + len, - "\ntape quality statistics\n" - " media defects : %3d\n", - ft_history.defects); - len += sprintf(buf + len, - "\ntape motion statistics\n" - " repositions : %3d\n", - ft_history.rewinds); - return len; -} - -static int ftape_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - char *ptr = page; - size_t len; - - ptr += sprintf(ptr, "Kernel Driver\n\n"); - ptr += get_driver_info(ptr); - ptr += sprintf(ptr, "\nTape Drive\n\n"); - ptr += get_tapedrive_info(ptr); - ptr += sprintf(ptr, "\nFDC Controller\n\n"); - ptr += get_controller_info(ptr); - ptr += sprintf(ptr, "\nTape Cartridge\n\n"); - ptr += get_cartridge_info(ptr); - ptr += sprintf(ptr, "\nHistory Record\n\n"); - ptr += get_history_info(ptr); - - len = strlen(page); - *start = NULL; - if (off+count >= len) { - *eof = 1; - } else { - *eof = 0; - } - return len; -} - -int __init ftape_proc_init(void) -{ - return create_proc_read_entry("ftape", 0, &proc_root, - ftape_read_proc, NULL) != NULL; -} - -void ftape_proc_destroy(void) -{ - remove_proc_entry("ftape", &proc_root); -} - -#endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) */ diff --git a/drivers/char/ftape/lowlevel/ftape-proc.h b/drivers/char/ftape/lowlevel/ftape-proc.h deleted file mode 100644 index 264dfcc1d22d..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-proc.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _FTAPE_PROC_H -#define _FTAPE_PROC_H - -/* - * Copyright (C) 1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-proc.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:20 $ - * - * This file contains definitions for the procfs interface of the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include - -extern int ftape_proc_init(void); -extern void ftape_proc_destroy(void); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-read.c b/drivers/char/ftape/lowlevel/ftape-read.c deleted file mode 100644 index d967d8cd86dc..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-read.c +++ /dev/null @@ -1,621 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-read.c,v $ - * $Revision: 1.6 $ - * $Date: 1997/10/21 14:39:22 $ - * - * This file contains the reading code - * for the QIC-117 floppy-tape driver for Linux. - * - */ - -#include -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-ecc.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ - -/* Local vars. - */ - -void ftape_zap_read_buffers(void) -{ - int i; - - for (i = 0; i < ft_nr_buffers; ++i) { -/* changed to "fit" with dynamic allocation of tape_buffer. --khp */ - ft_buffer[i]->status = waiting; - ft_buffer[i]->bytes = 0; - ft_buffer[i]->skip = 0; - ft_buffer[i]->retry = 0; - } -/* ftape_reset_buffer(); */ -} - -static SectorMap convert_sector_map(buffer_struct * buff) -{ - int i = 0; - SectorMap bad_map = ftape_get_bad_sector_entry(buff->segment_id); - SectorMap src_map = buff->soft_error_map | buff->hard_error_map; - SectorMap dst_map = 0; - TRACE_FUN(ft_t_any); - - if (bad_map || src_map) { - TRACE(ft_t_flow, "bad_map = 0x%08lx", (long) bad_map); - TRACE(ft_t_flow, "src_map = 0x%08lx", (long) src_map); - } - while (bad_map) { - while ((bad_map & 1) == 0) { - if (src_map & 1) { - dst_map |= (1 << i); - } - src_map >>= 1; - bad_map >>= 1; - ++i; - } - /* (bad_map & 1) == 1 */ - src_map >>= 1; - bad_map >>= 1; - } - if (src_map) { - dst_map |= (src_map << i); - } - if (dst_map) { - TRACE(ft_t_flow, "dst_map = 0x%08lx", (long) dst_map); - } - TRACE_EXIT dst_map; -} - -static int correct_and_copy_fraction(buffer_struct *buff, __u8 * destination, - int start, int size) -{ - struct memory_segment mseg; - int result; - SectorMap read_bad; - TRACE_FUN(ft_t_any); - - mseg.read_bad = convert_sector_map(buff); - mseg.marked_bad = 0; /* not used... */ - mseg.blocks = buff->bytes / FT_SECTOR_SIZE; - mseg.data = buff->address; - /* If there are no data sectors we can skip this segment. - */ - if (mseg.blocks <= 3) { - TRACE_ABORT(0, ft_t_noise, "empty segment"); - } - read_bad = mseg.read_bad; - ft_history.crc_errors += count_ones(read_bad); - result = ftape_ecc_correct_data(&mseg); - if (read_bad != 0 || mseg.corrected != 0) { - TRACE(ft_t_noise, "crc error map: 0x%08lx", (unsigned long)read_bad); - TRACE(ft_t_noise, "corrected map: 0x%08lx", (unsigned long)mseg.corrected); - ft_history.corrected += count_ones(mseg.corrected); - } - if (result == ECC_CORRECTED || result == ECC_OK) { - if (result == ECC_CORRECTED) { - TRACE(ft_t_info, "ecc corrected segment: %d", buff->segment_id); - } - if(start < 0) { - start= 0; - } - if((start+size) > ((mseg.blocks - 3) * FT_SECTOR_SIZE)) { - size = (mseg.blocks - 3) * FT_SECTOR_SIZE - start; - } - if (size < 0) { - size= 0; - } - if(size > 0) { - memcpy(destination + start, mseg.data + start, size); - } - if ((read_bad ^ mseg.corrected) & mseg.corrected) { - /* sectors corrected without crc errors set */ - ft_history.crc_failures++; - } - TRACE_EXIT size; /* (mseg.blocks - 3) * FT_SECTOR_SIZE; */ - } else { - ft_history.ecc_failures++; - TRACE_ABORT(-EAGAIN, - ft_t_err, "ecc failure on segment %d", - buff->segment_id); - } - TRACE_EXIT 0; -} - -/* Read given segment into buffer at address. - */ -int ftape_read_segment_fraction(const int segment_id, - void *address, - const ft_read_mode_t read_mode, - const int start, - const int size) -{ - int result = 0; - int retry = 0; - int bytes_read = 0; - int read_done = 0; - TRACE_FUN(ft_t_flow); - - ft_history.used |= 1; - TRACE(ft_t_data_flow, "segment_id = %d", segment_id); - if (ft_driver_state != reading) { - TRACE(ft_t_noise, "calling ftape_abort_operation"); - TRACE_CATCH(ftape_abort_operation(),); - ftape_set_state(reading); - } - for(;;) { - buffer_struct *tail; - /* Allow escape from this loop on signal ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - /* Search all full buffers for the first matching the - * wanted segment. Clear other buffers on the fly. - */ - tail = ftape_get_buffer(ft_queue_tail); - while (!read_done && tail->status == done) { - /* Allow escape from this loop on signal ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - if (tail->segment_id == segment_id) { - /* If out buffer is already full, - * return its contents. - */ - TRACE(ft_t_flow, "found segment in cache: %d", - segment_id); - if (tail->deleted) { - /* Return a value that - * read_header_segment - * understands. As this - * should only occur when - * searching for the header - * segments it shouldn't be - * misinterpreted elsewhere. - */ - TRACE_EXIT 0; - } - result = correct_and_copy_fraction( - tail, - address, - start, - size); - TRACE(ft_t_flow, "segment contains (bytes): %d", - result); - if (result < 0) { - if (result != -EAGAIN) { - TRACE_EXIT result; - } - /* keep read_done == 0, will - * trigger - * ftape_abort_operation - * because reading wrong - * segment. - */ - TRACE(ft_t_err, "ecc failed, retry"); - ++retry; - } else { - read_done = 1; - bytes_read = result; - } - } else { - TRACE(ft_t_flow,"zapping segment in cache: %d", - tail->segment_id); - } - tail->status = waiting; - tail = ftape_next_buffer(ft_queue_tail); - } - if (!read_done && tail->status == reading) { - if (tail->segment_id == segment_id) { - switch(ftape_wait_segment(reading)) { - case 0: - break; - case -EINTR: - TRACE_ABORT(-EINTR, ft_t_warn, - "interrupted by " - "non-blockable signal"); - break; - default: - TRACE(ft_t_noise, - "wait_segment failed"); - ftape_abort_operation(); - ftape_set_state(reading); - break; - } - } else { - /* We're reading the wrong segment, - * stop runner. - */ - TRACE(ft_t_noise, "reading wrong segment"); - ftape_abort_operation(); - ftape_set_state(reading); - } - } - /* should runner stop ? - */ - if (ft_runner_status == aborting) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - switch(head->status) { - case error: - ft_history.defects += - count_ones(head->hard_error_map); - case reading: - head->status = waiting; - break; - default: - break; - } - TRACE_CATCH(ftape_dumb_stop(),); - } else { - /* If just passed last segment on tape: wait - * for BOT or EOT mark. Sets ft_runner_status to - * idle if at lEOT and successful - */ - TRACE_CATCH(ftape_handle_logical_eot(),); - } - /* If we got a segment: quit, or else retry up to limit. - * - * If segment to read is empty, do not start runner for it, - * but wait for next read call. - */ - if (read_done || - ftape_get_bad_sector_entry(segment_id) == EMPTY_SEGMENT ) { - /* bytes_read = 0; should still be zero */ - TRACE_EXIT bytes_read; - - } - if (retry > FT_RETRIES_ON_ECC_ERROR) { - ft_history.defects++; - TRACE_ABORT(-ENODATA, ft_t_err, - "too many retries on ecc failure"); - } - /* Now at least one buffer is empty ! - * Restart runner & tape if needed. - */ - TRACE(ft_t_any, "head: %d, tail: %d, ft_runner_status: %d", - ftape_buffer_id(ft_queue_head), - ftape_buffer_id(ft_queue_tail), - ft_runner_status); - TRACE(ft_t_any, "buffer[].status, [head]: %d, [tail]: %d", - ftape_get_buffer(ft_queue_head)->status, - ftape_get_buffer(ft_queue_tail)->status); - tail = ftape_get_buffer(ft_queue_tail); - if (tail->status == waiting) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - - ftape_setup_new_segment(head, segment_id, -1); - if (read_mode == FT_RD_SINGLE) { - /* disable read-ahead */ - head->next_segment = 0; - } - ftape_calc_next_cluster(head); - if (ft_runner_status == idle) { - result = ftape_start_tape(segment_id, - head->sector_offset); - if (result < 0) { - TRACE_ABORT(result, ft_t_err, "Error: " - "segment %d unreachable", - segment_id); - } - } - head->status = reading; - fdc_setup_read_write(head, FDC_READ); - } - } - /* not reached */ - TRACE_EXIT -EIO; -} - -int ftape_read_header_segment(__u8 *address) -{ - int result; - int header_segment; - int first_failed = 0; - int status; - TRACE_FUN(ft_t_flow); - - ft_used_header_segment = -1; - TRACE_CATCH(ftape_report_drive_status(&status),); - TRACE(ft_t_flow, "reading..."); - /* We're looking for the first header segment. - * A header segment cannot contain bad sectors, therefor at the - * tape start, segments with bad sectors are (according to QIC-40/80) - * written with deleted data marks and must be skipped. - */ - memset(address, '\0', (FT_SECTORS_PER_SEGMENT - 3) * FT_SECTOR_SIZE); - result = 0; -#define HEADER_SEGMENT_BOUNDARY 68 /* why not 42? */ - for (header_segment = 0; - header_segment < HEADER_SEGMENT_BOUNDARY && result == 0; - ++header_segment) { - /* Set no read-ahead, the isr will force read-ahead whenever - * it encounters deleted data ! - */ - result = ftape_read_segment(header_segment, - address, - FT_RD_SINGLE); - if (result < 0 && !first_failed) { - TRACE(ft_t_err, "header segment damaged, trying backup"); - first_failed = 1; - result = 0; /* force read of next (backup) segment */ - } - } - if (result < 0 || header_segment >= HEADER_SEGMENT_BOUNDARY) { - TRACE_ABORT(-EIO, ft_t_err, - "no readable header segment found"); - } - TRACE_CATCH(ftape_abort_operation(),); - ft_used_header_segment = header_segment; - result = ftape_decode_header_segment(address); - TRACE_EXIT result; -} - -int ftape_decode_header_segment(__u8 *address) -{ - unsigned int max_floppy_side; - unsigned int max_floppy_track; - unsigned int max_floppy_sector; - unsigned int new_tape_len; - TRACE_FUN(ft_t_flow); - - if (GET4(address, FT_SIGNATURE) == FT_D2G_MAGIC) { - /* Ditto 2GB header segment. They encrypt the bad sector map. - * We decrypt it and store them in normal format. - * I hope this is correct. - */ - int i; - TRACE(ft_t_warn, - "Found Ditto 2GB tape, " - "trying to decrypt bad sector map"); - for (i=256; i < 29 * FT_SECTOR_SIZE; i++) { - address[i] = ~(address[i] - (i&0xff)); - } - PUT4(address, 0,FT_HSEG_MAGIC); - } else if (GET4(address, FT_SIGNATURE) != FT_HSEG_MAGIC) { - TRACE_ABORT(-EIO, ft_t_err, - "wrong signature in header segment"); - } - ft_format_code = (ft_format_type) address[FT_FMT_CODE]; - if (ft_format_code != fmt_big) { - ft_header_segment_1 = GET2(address, FT_HSEG_1); - ft_header_segment_2 = GET2(address, FT_HSEG_2); - ft_first_data_segment = GET2(address, FT_FRST_SEG); - ft_last_data_segment = GET2(address, FT_LAST_SEG); - } else { - ft_header_segment_1 = GET4(address, FT_6_HSEG_1); - ft_header_segment_2 = GET4(address, FT_6_HSEG_2); - ft_first_data_segment = GET4(address, FT_6_FRST_SEG); - ft_last_data_segment = GET4(address, FT_6_LAST_SEG); - } - TRACE(ft_t_noise, "first data segment: %d", ft_first_data_segment); - TRACE(ft_t_noise, "last data segment: %d", ft_last_data_segment); - TRACE(ft_t_noise, "header segments are %d and %d", - ft_header_segment_1, ft_header_segment_2); - - /* Verify tape parameters... - * QIC-40/80 spec: tape_parameters: - * - * segments-per-track segments_per_track - * tracks-per-cartridge tracks_per_tape - * max-floppy-side (segments_per_track * - * tracks_per_tape - 1) / - * ftape_segments_per_head - * max-floppy-track ftape_segments_per_head / - * ftape_segments_per_cylinder - 1 - * max-floppy-sector ftape_segments_per_cylinder * - * FT_SECTORS_PER_SEGMENT - */ - ft_segments_per_track = GET2(address, FT_SPT); - ft_tracks_per_tape = address[FT_TPC]; - max_floppy_side = address[FT_FHM]; - max_floppy_track = address[FT_FTM]; - max_floppy_sector = address[FT_FSM]; - TRACE(ft_t_noise, "(fmt/spt/tpc/fhm/ftm/fsm) = %d/%d/%d/%d/%d/%d", - ft_format_code, ft_segments_per_track, ft_tracks_per_tape, - max_floppy_side, max_floppy_track, max_floppy_sector); - new_tape_len = ftape_tape_len; - switch (ft_format_code) { - case fmt_425ft: - new_tape_len = 425; - break; - case fmt_normal: - if (ftape_tape_len == 0) { /* otherwise 307 ft */ - new_tape_len = 205; - } - break; - case fmt_1100ft: - new_tape_len = 1100; - break; - case fmt_var:{ - int segments_per_1000_inch = 1; /* non-zero default for switch */ - switch (ft_qic_std) { - case QIC_TAPE_QIC40: - segments_per_1000_inch = 332; - break; - case QIC_TAPE_QIC80: - segments_per_1000_inch = 488; - break; - case QIC_TAPE_QIC3010: - segments_per_1000_inch = 730; - break; - case QIC_TAPE_QIC3020: - segments_per_1000_inch = 1430; - break; - } - new_tape_len = (1000 * ft_segments_per_track + - (segments_per_1000_inch - 1)) / segments_per_1000_inch; - break; - } - case fmt_big:{ - int segments_per_1000_inch = 1; /* non-zero default for switch */ - switch (ft_qic_std) { - case QIC_TAPE_QIC40: - segments_per_1000_inch = 332; - break; - case QIC_TAPE_QIC80: - segments_per_1000_inch = 488; - break; - case QIC_TAPE_QIC3010: - segments_per_1000_inch = 730; - break; - case QIC_TAPE_QIC3020: - segments_per_1000_inch = 1430; - break; - default: - TRACE_ABORT(-EIO, ft_t_bug, - "%x QIC-standard with fmt-code %d, please report", - ft_qic_std, ft_format_code); - } - new_tape_len = ((1000 * ft_segments_per_track + - (segments_per_1000_inch - 1)) / - segments_per_1000_inch); - break; - } - default: - TRACE_ABORT(-EIO, ft_t_err, - "unknown tape format, please report !"); - } - if (new_tape_len != ftape_tape_len) { - ftape_tape_len = new_tape_len; - TRACE(ft_t_info, "calculated tape length is %d ft", - ftape_tape_len); - ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); - } - if (ft_segments_per_track == 0 && ft_tracks_per_tape == 0 && - max_floppy_side == 0 && max_floppy_track == 0 && - max_floppy_sector == 0) { - /* QIC-40 Rev E and earlier has no values in the header. - */ - ft_segments_per_track = 68; - ft_tracks_per_tape = 20; - max_floppy_side = 1; - max_floppy_track = 169; - max_floppy_sector = 128; - } - /* This test will compensate for the wrong parameter on tapes - * formatted by Conner software. - */ - if (ft_segments_per_track == 150 && - ft_tracks_per_tape == 28 && - max_floppy_side == 7 && - max_floppy_track == 149 && - max_floppy_sector == 128) { -TRACE(ft_t_info, "the famous CONNER bug: max_floppy_side off by one !"); - max_floppy_side = 6; - } - /* These tests will compensate for the wrong parameter on tapes - * formatted by ComByte Windows software. - * - * First, for 205 foot tapes - */ - if (ft_segments_per_track == 100 && - ft_tracks_per_tape == 28 && - max_floppy_side == 9 && - max_floppy_track == 149 && - max_floppy_sector == 128) { -TRACE(ft_t_info, "the ComByte bug: max_floppy_side incorrect!"); - max_floppy_side = 4; - } - /* Next, for 307 foot tapes. */ - if (ft_segments_per_track == 150 && - ft_tracks_per_tape == 28 && - max_floppy_side == 9 && - max_floppy_track == 149 && - max_floppy_sector == 128) { -TRACE(ft_t_info, "the ComByte bug: max_floppy_side incorrect!"); - max_floppy_side = 6; - } - /* This test will compensate for the wrong parameter on tapes - * formatted by Colorado Windows software. - */ - if (ft_segments_per_track == 150 && - ft_tracks_per_tape == 28 && - max_floppy_side == 6 && - max_floppy_track == 150 && - max_floppy_sector == 128) { -TRACE(ft_t_info, "the famous Colorado bug: max_floppy_track off by one !"); - max_floppy_track = 149; - } - ftape_segments_per_head = ((max_floppy_sector/FT_SECTORS_PER_SEGMENT) * - (max_floppy_track + 1)); - /* This test will compensate for some bug reported by Dima - * Brodsky. Seems to be a Colorado bug, either. (freebee - * Imation tape shipped together with Colorado T3000 - */ - if ((ft_format_code == fmt_var || ft_format_code == fmt_big) && - ft_tracks_per_tape == 50 && - max_floppy_side == 54 && - max_floppy_track == 255 && - max_floppy_sector == 128) { -TRACE(ft_t_info, "the famous ??? bug: max_floppy_track off by one !"); - max_floppy_track = 254; - } - /* - * Verify drive_configuration with tape parameters - */ - if (ftape_segments_per_head == 0 || ftape_segments_per_cylinder == 0 || - ((ft_segments_per_track * ft_tracks_per_tape - 1) / ftape_segments_per_head - != max_floppy_side) || - (ftape_segments_per_head / ftape_segments_per_cylinder - 1 != max_floppy_track) || - (ftape_segments_per_cylinder * FT_SECTORS_PER_SEGMENT != max_floppy_sector) -#ifdef TESTING - || ((ft_format_code == fmt_var || ft_format_code == fmt_big) && - (max_floppy_track != 254 || max_floppy_sector != 128)) -#endif - ) { - char segperheadz = ftape_segments_per_head ? ' ' : '?'; - char segpercylz = ftape_segments_per_cylinder ? ' ' : '?'; - TRACE(ft_t_err,"Tape parameters inconsistency, please report"); - TRACE(ft_t_err, "reported = %d/%d/%d/%d/%d/%d", - ft_format_code, - ft_segments_per_track, - ft_tracks_per_tape, - max_floppy_side, - max_floppy_track, - max_floppy_sector); - TRACE(ft_t_err, "required = %d/%d/%d/%d%c/%d%c/%d", - ft_format_code, - ft_segments_per_track, - ft_tracks_per_tape, - ftape_segments_per_head ? - ((ft_segments_per_track * ft_tracks_per_tape -1) / - ftape_segments_per_head ) : - (ft_segments_per_track * ft_tracks_per_tape -1), - segperheadz, - ftape_segments_per_cylinder ? - (ftape_segments_per_head / - ftape_segments_per_cylinder - 1 ) : - ftape_segments_per_head - 1, - segpercylz, - (ftape_segments_per_cylinder * FT_SECTORS_PER_SEGMENT)); - TRACE_EXIT -EIO; - } - ftape_extract_bad_sector_map(address); - TRACE_EXIT 0; -} diff --git a/drivers/char/ftape/lowlevel/ftape-read.h b/drivers/char/ftape/lowlevel/ftape-read.h deleted file mode 100644 index 069f99f2a984..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-read.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef _FTAPE_READ_H -#define _FTAPE_READ_H - -/* - * Copyright (C) 1994-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-read.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:22 $ - * - * This file contains the definitions for the read functions - * for the QIC-117 floppy-tape driver for Linux. - * - */ - -/* ftape-read.c defined global functions. - */ -typedef enum { - FT_RD_SINGLE = 0, - FT_RD_AHEAD = 1, -} ft_read_mode_t; - -extern int ftape_read_header_segment(__u8 *address); -extern int ftape_decode_header_segment(__u8 *address); -extern int ftape_read_segment_fraction(const int segment, - void *address, - const ft_read_mode_t read_mode, - const int start, - const int size); -#define ftape_read_segment(segment, address, read_mode) \ - ftape_read_segment_fraction(segment, address, read_mode, \ - 0, FT_SEGMENT_SIZE) -extern void ftape_zap_read_buffers(void); - -#endif /* _FTAPE_READ_H */ diff --git a/drivers/char/ftape/lowlevel/ftape-rw.c b/drivers/char/ftape/lowlevel/ftape-rw.c deleted file mode 100644 index c0d6dc2cbfd3..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-rw.c +++ /dev/null @@ -1,1092 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-rw.c,v $ - * $Revision: 1.7 $ - * $Date: 1997/10/28 14:26:49 $ - * - * This file contains some common code for the segment read and - * segment write routines for the QIC-117 floppy-tape driver for - * Linux. - */ - -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-ecc.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ -int ft_nr_buffers; -buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS]; -static volatile int ft_head; -static volatile int ft_tail; /* not volatile but need same type as head */ -int fdc_setup_error; -location_record ft_location = {-1, 0}; -volatile int ftape_tape_running; - -/* Local vars. - */ -static int overrun_count_offset; -static int inhibit_correction; - -/* maxmimal allowed overshoot when fast seeking - */ -#define OVERSHOOT_LIMIT 10 - -/* Increment cyclic buffer nr. - */ -buffer_struct *ftape_next_buffer(ft_buffer_queue_t pos) -{ - switch (pos) { - case ft_queue_head: - if (++ft_head >= ft_nr_buffers) { - ft_head = 0; - } - return ft_buffer[ft_head]; - case ft_queue_tail: - if (++ft_tail >= ft_nr_buffers) { - ft_tail = 0; - } - return ft_buffer[ft_tail]; - default: - return NULL; - } -} -int ftape_buffer_id(ft_buffer_queue_t pos) -{ - switch(pos) { - case ft_queue_head: return ft_head; - case ft_queue_tail: return ft_tail; - default: return -1; - } -} -buffer_struct *ftape_get_buffer(ft_buffer_queue_t pos) -{ - switch(pos) { - case ft_queue_head: return ft_buffer[ft_head]; - case ft_queue_tail: return ft_buffer[ft_tail]; - default: return NULL; - } -} -void ftape_reset_buffer(void) -{ - ft_head = ft_tail = 0; -} - -buffer_state_enum ftape_set_state(buffer_state_enum new_state) -{ - buffer_state_enum old_state = ft_driver_state; - - ft_driver_state = new_state; - return old_state; -} -/* Calculate Floppy Disk Controller and DMA parameters for a segment. - * head: selects buffer struct in array. - * offset: number of physical sectors to skip (including bad ones). - * count: number of physical sectors to handle (including bad ones). - */ -static int setup_segment(buffer_struct * buff, - int segment_id, - unsigned int sector_offset, - unsigned int sector_count, - int retry) -{ - SectorMap offset_mask; - SectorMap mask; - TRACE_FUN(ft_t_any); - - buff->segment_id = segment_id; - buff->sector_offset = sector_offset; - buff->remaining = sector_count; - buff->head = segment_id / ftape_segments_per_head; - buff->cyl = (segment_id % ftape_segments_per_head) / ftape_segments_per_cylinder; - buff->sect = (segment_id % ftape_segments_per_cylinder) * FT_SECTORS_PER_SEGMENT + 1; - buff->deleted = 0; - offset_mask = (1 << buff->sector_offset) - 1; - mask = ftape_get_bad_sector_entry(segment_id) & offset_mask; - while (mask) { - if (mask & 1) { - offset_mask >>= 1; /* don't count bad sector */ - } - mask >>= 1; - } - buff->data_offset = count_ones(offset_mask); /* good sectors to skip */ - buff->ptr = buff->address + buff->data_offset * FT_SECTOR_SIZE; - TRACE(ft_t_flow, "data offset = %d sectors", buff->data_offset); - if (retry) { - buff->soft_error_map &= offset_mask; /* keep skipped part */ - } else { - buff->hard_error_map = buff->soft_error_map = 0; - } - buff->bad_sector_map = ftape_get_bad_sector_entry(buff->segment_id); - if (buff->bad_sector_map != 0) { - TRACE(ft_t_noise, "segment: %d, bad sector map: %08lx", - buff->segment_id, (long)buff->bad_sector_map); - } else { - TRACE(ft_t_flow, "segment: %d", buff->segment_id); - } - if (buff->sector_offset > 0) { - buff->bad_sector_map >>= buff->sector_offset; - } - if (buff->sector_offset != 0 || buff->remaining != FT_SECTORS_PER_SEGMENT) { - TRACE(ft_t_flow, "sector offset = %d, count = %d", - buff->sector_offset, buff->remaining); - } - /* Segments with 3 or less sectors are not written with valid - * data because there is no space left for the ecc. The - * data written is whatever happens to be in the buffer. - * Reading such a segment will return a zero byte-count. - * To allow us to read/write segments with all bad sectors - * we fake one readable sector in the segment. This - * prevents having to handle these segments in a very - * special way. It is not important if the reading of this - * bad sector fails or not (the data is ignored). It is - * only read to keep the driver running. - * - * The QIC-40/80 spec. has no information on how to handle - * this case, so this is my interpretation. - */ - if (buff->bad_sector_map == EMPTY_SEGMENT) { - TRACE(ft_t_flow, "empty segment %d, fake first sector good", - buff->segment_id); - if (buff->ptr != buff->address) { - TRACE(ft_t_bug, "This is a bug: %p/%p", - buff->ptr, buff->address); - } - buff->bad_sector_map = FAKE_SEGMENT; - } - fdc_setup_error = 0; - buff->next_segment = segment_id + 1; - TRACE_EXIT 0; -} - -/* Calculate Floppy Disk Controller and DMA parameters for a new segment. - */ -int ftape_setup_new_segment(buffer_struct * buff, int segment_id, int skip) -{ - int result = 0; - static int old_segment_id = -1; - static buffer_state_enum old_ft_driver_state = idle; - int retry = 0; - unsigned offset = 0; - int count = FT_SECTORS_PER_SEGMENT; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_flow, "%s segment %d (old = %d)", - (ft_driver_state == reading || ft_driver_state == verifying) - ? "reading" : "writing", - segment_id, old_segment_id); - if (ft_driver_state != old_ft_driver_state) { /* when verifying */ - old_segment_id = -1; - old_ft_driver_state = ft_driver_state; - } - if (segment_id == old_segment_id) { - ++buff->retry; - ++ft_history.retries; - TRACE(ft_t_flow, "setting up for retry nr %d", buff->retry); - retry = 1; - if (skip && buff->skip > 0) { /* allow skip on retry */ - offset = buff->skip; - count -= offset; - TRACE(ft_t_flow, "skipping %d sectors", offset); - } - } else { - buff->retry = 0; - buff->skip = 0; - old_segment_id = segment_id; - } - result = setup_segment(buff, segment_id, offset, count, retry); - TRACE_EXIT result; -} - -/* Determine size of next cluster of good sectors. - */ -int ftape_calc_next_cluster(buffer_struct * buff) -{ - /* Skip bad sectors. - */ - while (buff->remaining > 0 && (buff->bad_sector_map & 1) != 0) { - buff->bad_sector_map >>= 1; - ++buff->sector_offset; - --buff->remaining; - } - /* Find next cluster of good sectors - */ - if (buff->bad_sector_map == 0) { /* speed up */ - buff->sector_count = buff->remaining; - } else { - SectorMap map = buff->bad_sector_map; - - buff->sector_count = 0; - while (buff->sector_count < buff->remaining && (map & 1) == 0) { - ++buff->sector_count; - map >>= 1; - } - } - return buff->sector_count; -} - -/* if just passed the last segment on a track, wait for BOT - * or EOT mark. - */ -int ftape_handle_logical_eot(void) -{ - TRACE_FUN(ft_t_flow); - - if (ft_runner_status == logical_eot) { - int status; - - TRACE(ft_t_noise, "tape at logical EOT"); - TRACE_CATCH(ftape_ready_wait(ftape_timeout.seek, &status),); - if ((status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) == 0) { - TRACE_ABORT(-EIO, ft_t_err, "eot/bot not reached"); - } - ft_runner_status = end_of_tape; - } - if (ft_runner_status == end_of_tape) { - TRACE(ft_t_noise, "runner stopped because of logical EOT"); - ft_runner_status = idle; - } - TRACE_EXIT 0; -} - -static int check_bot_eot(int status) -{ - TRACE_FUN(ft_t_flow); - - if (status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) { - ft_location.bot = ((ft_location.track & 1) == 0 ? - (status & QIC_STATUS_AT_BOT) != 0: - (status & QIC_STATUS_AT_EOT) != 0); - ft_location.eot = !ft_location.bot; - ft_location.segment = (ft_location.track + - (ft_location.bot ? 0 : 1)) * ft_segments_per_track - 1; - ft_location.sector = -1; - ft_location.known = 1; - TRACE(ft_t_flow, "tape at logical %s", - ft_location.bot ? "bot" : "eot"); - TRACE(ft_t_flow, "segment = %d", ft_location.segment); - } else { - ft_location.known = 0; - } - TRACE_EXIT ft_location.known; -} - -/* Read Id of first sector passing tape head. - */ -static int ftape_read_id(void) -{ - int status; - __u8 out[2]; - TRACE_FUN(ft_t_any); - - /* Assume tape is running on entry, be able to handle - * situation where it stopped or is stopping. - */ - ft_location.known = 0; /* default is location not known */ - out[0] = FDC_READID; - out[1] = ft_drive_sel; - TRACE_CATCH(fdc_command(out, 2),); - switch (fdc_interrupt_wait(20 * FT_SECOND)) { - case 0: - if (fdc_sect == 0) { - if (ftape_report_drive_status(&status) >= 0 && - (status & QIC_STATUS_READY)) { - ftape_tape_running = 0; - TRACE(ft_t_flow, "tape has stopped"); - check_bot_eot(status); - } - } else { - ft_location.known = 1; - ft_location.segment = (ftape_segments_per_head - * fdc_head - + ftape_segments_per_cylinder - * fdc_cyl - + (fdc_sect - 1) - / FT_SECTORS_PER_SEGMENT); - ft_location.sector = ((fdc_sect - 1) - % FT_SECTORS_PER_SEGMENT); - ft_location.eot = ft_location.bot = 0; - } - break; - case -ETIME: - /* Didn't find id on tape, must be near end: Wait - * until stopped. - */ - if (ftape_ready_wait(FT_FOREVER, &status) >= 0) { - ftape_tape_running = 0; - TRACE(ft_t_flow, "tape has stopped"); - check_bot_eot(status); - } - break; - default: - /* Interrupted or otherwise failing - * fdc_interrupt_wait() - */ - TRACE(ft_t_err, "fdc_interrupt_wait failed"); - break; - } - if (!ft_location.known) { - TRACE_ABORT(-EIO, ft_t_flow, "no id found"); - } - if (ft_location.sector == 0) { - TRACE(ft_t_flow, "passing segment %d/%d", - ft_location.segment, ft_location.sector); - } else { - TRACE(ft_t_fdc_dma, "passing segment %d/%d", - ft_location.segment, ft_location.sector); - } - TRACE_EXIT 0; -} - -static int logical_forward(void) -{ - ftape_tape_running = 1; - return ftape_command(QIC_LOGICAL_FORWARD); -} - -int ftape_stop_tape(int *pstatus) -{ - int retry = 0; - int result; - TRACE_FUN(ft_t_flow); - - do { - result = ftape_command_wait(QIC_STOP_TAPE, - ftape_timeout.stop, pstatus); - if (result == 0) { - if ((*pstatus & QIC_STATUS_READY) == 0) { - result = -EIO; - } else { - ftape_tape_running = 0; - } - } - } while (result < 0 && ++retry <= 3); - if (result < 0) { - TRACE(ft_t_err, "failed ! (fatal)"); - } - TRACE_EXIT result; -} - -int ftape_dumb_stop(void) -{ - int result; - int status; - TRACE_FUN(ft_t_flow); - - /* Abort current fdc operation if it's busy (probably read - * or write operation pending) with a reset. - */ - if (fdc_ready_wait(100 /* usec */) < 0) { - TRACE(ft_t_noise, "aborting fdc operation"); - fdc_reset(); - } - /* Reading id's after the last segment on a track may fail - * but eventually the drive will become ready (logical eot). - */ - result = ftape_report_drive_status(&status); - ft_location.known = 0; - do { - if (result == 0 && status & QIC_STATUS_READY) { - /* Tape is not running any more. - */ - TRACE(ft_t_noise, "tape already halted"); - check_bot_eot(status); - ftape_tape_running = 0; - } else if (ftape_tape_running) { - /* Tape is (was) still moving. - */ -#ifdef TESTING - ftape_read_id(); -#endif - result = ftape_stop_tape(&status); - } else { - /* Tape not yet ready but stopped. - */ - result = ftape_ready_wait(ftape_timeout.pause,&status); - } - } while (ftape_tape_running - && !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK))); -#ifndef TESTING - ft_location.known = 0; -#endif - if (ft_runner_status == aborting || ft_runner_status == do_abort) { - ft_runner_status = idle; - } - TRACE_EXIT result; -} - -/* Wait until runner has finished tail buffer. - * - */ -int ftape_wait_segment(buffer_state_enum state) -{ - int status; - int result = 0; - TRACE_FUN(ft_t_flow); - - while (ft_buffer[ft_tail]->status == state) { - TRACE(ft_t_flow, "state: %d", ft_buffer[ft_tail]->status); - /* First buffer still being worked on, wait up to timeout. - * - * Note: we check two times for being killed. 50 - * seconds are quite long. Note that - * fdc_interrupt_wait() is not killable by any - * means. ftape_read_segment() wants us to return - * -EINTR in case of a signal. - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - result = fdc_interrupt_wait(50 * FT_SECOND); - FT_SIGNAL_EXIT(_DONT_BLOCK); - if (result < 0) { - TRACE_ABORT(result, - ft_t_err, "fdc_interrupt_wait failed"); - } - if (fdc_setup_error) { - /* recover... FIXME */ - TRACE_ABORT(-EIO, ft_t_err, "setup error"); - } - } - if (ft_buffer[ft_tail]->status != error) { - TRACE_EXIT 0; - } - TRACE_CATCH(ftape_report_drive_status(&status),); - TRACE(ft_t_noise, "ftape_report_drive_status: 0x%02x", status); - if ((status & QIC_STATUS_READY) && - (status & QIC_STATUS_ERROR)) { - unsigned int error; - qic117_cmd_t command; - - /* Report and clear error state. - * In case the drive can't operate at the selected - * rate, select the next lower data rate. - */ - ftape_report_error(&error, &command, 1); - if (error == 31 && command == QIC_LOGICAL_FORWARD) { - /* drive does not accept this data rate */ - if (ft_data_rate > 250) { - TRACE(ft_t_info, - "Probable data rate conflict"); - TRACE(ft_t_info, - "Lowering data rate to %d Kbps", - ft_data_rate / 2); - ftape_half_data_rate(); - if (ft_buffer[ft_tail]->retry > 0) { - /* give it a chance */ - --ft_buffer[ft_tail]->retry; - } - } else { - /* no rate is accepted... */ - TRACE(ft_t_err, "We're dead :("); - } - } else { - TRACE(ft_t_err, "Unknown error"); - } - TRACE_EXIT -EIO; /* g.p. error */ - } - TRACE_EXIT 0; -} - -/* forward */ static int seek_forward(int segment_id, int fast); - -static int fast_seek(int count, int reverse) -{ - int result = 0; - int status; - TRACE_FUN(ft_t_flow); - - if (count > 0) { - /* If positioned at begin or end of tape, fast seeking needs - * special treatment. - * Starting from logical bot needs a (slow) seek to the first - * segment before the high speed seek. Most drives do this - * automatically but some older don't, so we treat them - * all the same. - * Starting from logical eot is even more difficult because - * we cannot (slow) reverse seek to the last segment. - * TO BE IMPLEMENTED. - */ - inhibit_correction = 0; - if (ft_location.known && - ((ft_location.bot && !reverse) || - (ft_location.eot && reverse))) { - if (!reverse) { - /* (slow) skip to first segment on a track - */ - seek_forward(ft_location.track * ft_segments_per_track, 0); - --count; - } else { - /* When seeking backwards from - * end-of-tape the number of erased - * gaps found seems to be higher than - * expected. Therefor the drive must - * skip some more segments than - * calculated, but we don't know how - * many. Thus we will prevent the - * re-calculation of offset and - * overshoot when seeking backwards. - */ - inhibit_correction = 1; - count += 3; /* best guess */ - } - } - } else { - TRACE(ft_t_flow, "warning: zero or negative count: %d", count); - } - if (count > 0) { - int i; - int nibbles = count > 255 ? 3 : 2; - - if (count > 4095) { - TRACE(ft_t_noise, "skipping clipped at 4095 segment"); - count = 4095; - } - /* Issue this tape command first. */ - if (!reverse) { - TRACE(ft_t_noise, "skipping %d segment(s)", count); - result = ftape_command(nibbles == 3 ? - QIC_SKIP_EXTENDED_FORWARD : QIC_SKIP_FORWARD); - } else { - TRACE(ft_t_noise, "backing up %d segment(s)", count); - result = ftape_command(nibbles == 3 ? - QIC_SKIP_EXTENDED_REVERSE : QIC_SKIP_REVERSE); - } - if (result < 0) { - TRACE(ft_t_noise, "Skip command failed"); - } else { - --count; /* 0 means one gap etc. */ - for (i = 0; i < nibbles; ++i) { - if (result >= 0) { - result = ftape_parameter(count & 15); - count /= 16; - } - } - result = ftape_ready_wait(ftape_timeout.rewind, &status); - if (result >= 0) { - ftape_tape_running = 0; - } - } - } - TRACE_EXIT result; -} - -static int validate(int id) -{ - /* Check to see if position found is off-track as reported - * once. Because all tracks in one direction lie next to - * each other, if off-track the error will be approximately - * 2 * ft_segments_per_track. - */ - if (ft_location.track == -1) { - return 1; /* unforseen situation, don't generate error */ - } else { - /* Use margin of ft_segments_per_track on both sides - * because ftape needs some margin and the error we're - * looking for is much larger ! - */ - int lo = (ft_location.track - 1) * ft_segments_per_track; - int hi = (ft_location.track + 2) * ft_segments_per_track; - - return (id >= lo && id < hi); - } -} - -static int seek_forward(int segment_id, int fast) -{ - int failures = 0; - int count; - static int margin = 1; /* fixed: stop this before target */ - static int overshoot = 1; - static int min_count = 8; - int expected = -1; - int target = segment_id - margin; - int fast_seeking; - int prev_segment = ft_location.segment; - TRACE_FUN(ft_t_flow); - - if (!ft_location.known) { - TRACE_ABORT(-EIO, ft_t_err, - "fatal: cannot seek from unknown location"); - } - if (!validate(segment_id)) { - ftape_sleep(1 * FT_SECOND); - ft_failure = 1; - TRACE_ABORT(-EIO, ft_t_err, - "fatal: head off track (bad hardware?)"); - } - TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", - ft_location.segment, ft_location.sector,segment_id,margin); - count = target - ft_location.segment - overshoot; - fast_seeking = (fast && - count > (min_count + (ft_location.bot ? 1 : 0))); - if (fast_seeking) { - TRACE(ft_t_noise, "fast skipping %d segments", count); - expected = segment_id - margin; - fast_seek(count, 0); - } - if (!ftape_tape_running) { - logical_forward(); - } - while (ft_location.segment < segment_id) { - /* This requires at least one sector in a (bad) segment to - * have a valid and readable sector id ! - * It looks like this is not guaranteed, so we must try - * to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!! - */ - if (ftape_read_id() < 0 || !ft_location.known || - sigtestsetmask(¤t->pending.signal, _DONT_BLOCK)) { - ft_location.known = 0; - if (!ftape_tape_running || - ++failures > FT_SECTORS_PER_SEGMENT) { - TRACE_ABORT(-EIO, ft_t_err, - "read_id failed completely"); - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE(ft_t_flow, "read_id failed, retry (%d)", - failures); - continue; - } - if (fast_seeking) { - TRACE(ft_t_noise, "ended at %d/%d (%d,%d)", - ft_location.segment, ft_location.sector, - overshoot, inhibit_correction); - if (!inhibit_correction && - (ft_location.segment < expected || - ft_location.segment > expected + margin)) { - int error = ft_location.segment - expected; - TRACE(ft_t_noise, - "adjusting overshoot from %d to %d", - overshoot, overshoot + error); - overshoot += error; - /* All overshoots have the same - * direction, so it should never - * become negative, but who knows. - */ - if (overshoot < -5 || - overshoot > OVERSHOOT_LIMIT) { - if (overshoot < 0) { - /* keep sane value */ - overshoot = -5; - } else { - /* keep sane value */ - overshoot = OVERSHOOT_LIMIT; - } - TRACE(ft_t_noise, - "clipped overshoot to %d", - overshoot); - } - } - fast_seeking = 0; - } - if (ft_location.known) { - if (ft_location.segment > prev_segment + 1) { - TRACE(ft_t_noise, - "missed segment %d while skipping", - prev_segment + 1); - } - prev_segment = ft_location.segment; - } - } - if (ft_location.segment > segment_id) { - TRACE_ABORT(-EIO, - ft_t_noise, "failed: skip ended at segment %d/%d", - ft_location.segment, ft_location.sector); - } - TRACE_EXIT 0; -} - -static int skip_reverse(int segment_id, int *pstatus) -{ - int failures = 0; - static int overshoot = 1; - static int min_rewind = 2; /* 1 + overshoot */ - static const int margin = 1; /* stop this before target */ - int expected = 0; - int count = 1; - int short_seek; - int target = segment_id - margin; - TRACE_FUN(ft_t_flow); - - if (ft_location.known && !validate(segment_id)) { - ftape_sleep(1 * FT_SECOND); - ft_failure = 1; - TRACE_ABORT(-EIO, ft_t_err, - "fatal: head off track (bad hardware?)"); - } - do { - if (!ft_location.known) { - TRACE(ft_t_warn, "warning: location not known"); - } - TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", - ft_location.segment, ft_location.sector, - segment_id, margin); - /* min_rewind == 1 + overshoot_when_doing_minimum_rewind - * overshoot == overshoot_when_doing_larger_rewind - * Initially min_rewind == 1 + overshoot, optimization - * of both values will be done separately. - * overshoot and min_rewind can be negative as both are - * sums of three components: - * any_overshoot == rewind_overshoot - - * stop_overshoot - - * start_overshoot - */ - if (ft_location.segment - target - (min_rewind - 1) < 1) { - short_seek = 1; - } else { - count = ft_location.segment - target - overshoot; - short_seek = (count < 1); - } - if (short_seek) { - count = 1; /* do shortest rewind */ - expected = ft_location.segment - min_rewind; - if (expected/ft_segments_per_track != ft_location.track) { - expected = (ft_location.track * - ft_segments_per_track); - } - } else { - expected = target; - } - fast_seek(count, 1); - logical_forward(); - if (ftape_read_id() < 0 || !ft_location.known || - (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { - if ((!ftape_tape_running && !ft_location.known) || - ++failures > FT_SECTORS_PER_SEGMENT) { - TRACE_ABORT(-EIO, ft_t_err, - "read_id failed completely"); - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE_CATCH(ftape_report_drive_status(pstatus),); - TRACE(ft_t_noise, "ftape_read_id failed, retry (%d)", - failures); - continue; - } - TRACE(ft_t_noise, "ended at %d/%d (%d,%d,%d)", - ft_location.segment, ft_location.sector, - min_rewind, overshoot, inhibit_correction); - if (!inhibit_correction && - (ft_location.segment < expected || - ft_location.segment > expected + margin)) { - int error = expected - ft_location.segment; - if (short_seek) { - TRACE(ft_t_noise, - "adjusting min_rewind from %d to %d", - min_rewind, min_rewind + error); - min_rewind += error; - if (min_rewind < -5) { - /* is this right ? FIXME ! */ - /* keep sane value */ - min_rewind = -5; - TRACE(ft_t_noise, - "clipped min_rewind to %d", - min_rewind); - } - } else { - TRACE(ft_t_noise, - "adjusting overshoot from %d to %d", - overshoot, overshoot + error); - overshoot += error; - if (overshoot < -5 || - overshoot > OVERSHOOT_LIMIT) { - if (overshoot < 0) { - /* keep sane value */ - overshoot = -5; - } else { - /* keep sane value */ - overshoot = OVERSHOOT_LIMIT; - } - TRACE(ft_t_noise, - "clipped overshoot to %d", - overshoot); - } - } - } - } while (ft_location.segment > segment_id); - if (ft_location.known) { - TRACE(ft_t_noise, "current location: %d/%d", - ft_location.segment, ft_location.sector); - } - TRACE_EXIT 0; -} - -static int determine_position(void) -{ - int retry = 0; - int status; - int result; - TRACE_FUN(ft_t_flow); - - if (!ftape_tape_running) { - /* This should only happen if tape is stopped by isr. - */ - TRACE(ft_t_flow, "waiting for tape stop"); - if (ftape_ready_wait(ftape_timeout.pause, &status) < 0) { - TRACE(ft_t_flow, "drive still running (fatal)"); - ftape_tape_running = 1; /* ? */ - } - } else { - ftape_report_drive_status(&status); - } - if (status & QIC_STATUS_READY) { - /* Drive must be ready to check error state ! - */ - TRACE(ft_t_flow, "drive is ready"); - if (status & QIC_STATUS_ERROR) { - unsigned int error; - qic117_cmd_t command; - - /* Report and clear error state, try to continue. - */ - TRACE(ft_t_flow, "error status set"); - ftape_report_error(&error, &command, 1); - ftape_ready_wait(ftape_timeout.reset, &status); - ftape_tape_running = 0; /* ? */ - } - if (check_bot_eot(status)) { - if (ft_location.bot) { - if ((status & QIC_STATUS_READY) == 0) { - /* tape moving away from - * bot/eot, let's see if we - * can catch up with the first - * segment on this track. - */ - } else { - TRACE(ft_t_flow, - "start tape from logical bot"); - logical_forward(); /* start moving */ - } - } else { - if ((status & QIC_STATUS_READY) == 0) { - TRACE(ft_t_noise, "waiting for logical end of track"); - result = ftape_ready_wait(ftape_timeout.reset, &status); - /* error handling needed ? */ - } else { - TRACE(ft_t_noise, - "tape at logical end of track"); - } - } - } else { - TRACE(ft_t_flow, "start tape"); - logical_forward(); /* start moving */ - ft_location.known = 0; /* not cleared by logical forward ! */ - } - } - /* tape should be moving now, start reading id's - */ - while (!ft_location.known && - retry++ < FT_SECTORS_PER_SEGMENT && - (result = ftape_read_id()) < 0) { - - TRACE(ft_t_flow, "location unknown"); - - /* exit on signal - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - - /* read-id somehow failed, tape may - * have reached end or some other - * error happened. - */ - TRACE(ft_t_flow, "read-id failed"); - TRACE_CATCH(ftape_report_drive_status(&status),); - TRACE(ft_t_err, "ftape_report_drive_status: 0x%02x", status); - if (status & QIC_STATUS_READY) { - ftape_tape_running = 0; - TRACE(ft_t_noise, "tape stopped for unknown reason! " - "status = 0x%02x", status); - if (status & QIC_STATUS_ERROR || - !check_bot_eot(status)) { - /* oops, tape stopped but not at end! - */ - TRACE_EXIT -EIO; - } - } - } - TRACE(ft_t_flow, - "tape is positioned at segment %d", ft_location.segment); - TRACE_EXIT ft_location.known ? 0 : -EIO; -} - -/* Get the tape running and position it just before the - * requested segment. - * Seek tape-track and reposition as needed. - */ -int ftape_start_tape(int segment_id, int sector_offset) -{ - int track = segment_id / ft_segments_per_track; - int result = -EIO; - int status; - static int last_segment = -1; - static int bad_bus_timing = 0; - /* number of segments passing the head between starting the tape - * and being able to access the first sector. - */ - static int start_offset = 1; - int retry; - TRACE_FUN(ft_t_flow); - - /* If sector_offset > 0, seek into wanted segment instead of - * into previous. - * This allows error recovery if a part of the segment is bad - * (erased) causing the tape drive to generate an index pulse - * thus causing a no-data error before the requested sector - * is reached. - */ - ftape_tape_running = 0; - TRACE(ft_t_noise, "target segment: %d/%d%s", segment_id, sector_offset, - ft_buffer[ft_head]->retry > 0 ? " retry" : ""); - if (ft_buffer[ft_head]->retry > 0) { /* this is a retry */ - int dist = segment_id - last_segment; - - if ((int)ft_history.overrun_errors < overrun_count_offset) { - overrun_count_offset = ft_history.overrun_errors; - } else if (dist < 0 || dist > 50) { - overrun_count_offset = ft_history.overrun_errors; - } else if ((ft_history.overrun_errors - - overrun_count_offset) >= 8) { - if (ftape_increase_threshold() >= 0) { - --ft_buffer[ft_head]->retry; - overrun_count_offset = - ft_history.overrun_errors; - TRACE(ft_t_warn, "increased threshold because " - "of excessive overrun errors"); - } else if (!bad_bus_timing && ft_data_rate >= 1000) { - ftape_half_data_rate(); - --ft_buffer[ft_head]->retry; - bad_bus_timing = 1; - overrun_count_offset = - ft_history.overrun_errors; - TRACE(ft_t_warn, "reduced datarate because " - "of excessive overrun errors"); - } - } - } - last_segment = segment_id; - if (ft_location.track != track || - (ftape_might_be_off_track && ft_buffer[ft_head]->retry== 0)) { - /* current track unknown or not equal to destination - */ - ftape_ready_wait(ftape_timeout.seek, &status); - ftape_seek_head_to_track(track); - /* overrun_count_offset = ft_history.overrun_errors; */ - } - result = -EIO; - retry = 0; - while (result < 0 && - retry++ <= 5 && - !ft_failure && - !(sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { - - if (retry && start_offset < 5) { - start_offset ++; - } - /* Check if we are able to catch the requested - * segment in time. - */ - if ((ft_location.known || (determine_position() == 0)) && - ft_location.segment >= - (segment_id - - ((ftape_tape_running || ft_location.bot) - ? 0 : start_offset))) { - /* Too far ahead (in or past target segment). - */ - if (ftape_tape_running) { - if ((result = ftape_stop_tape(&status)) < 0) { - TRACE(ft_t_err, - "stop tape failed with code %d", - result); - break; - } - TRACE(ft_t_noise, "tape stopped"); - ftape_tape_running = 0; - } - TRACE(ft_t_noise, "repositioning"); - ++ft_history.rewinds; - if (segment_id % ft_segments_per_track < start_offset){ - TRACE(ft_t_noise, "end of track condition\n" - KERN_INFO "segment_id : %d\n" - KERN_INFO "ft_segments_per_track: %d\n" - KERN_INFO "start_offset : %d", - segment_id, ft_segments_per_track, - start_offset); - - /* If seeking to first segments on - * track better do a complete rewind - * to logical begin of track to get a - * more steady tape motion. - */ - result = ftape_command_wait( - (ft_location.track & 1) - ? QIC_PHYSICAL_FORWARD - : QIC_PHYSICAL_REVERSE, - ftape_timeout.rewind, &status); - check_bot_eot(status); /* update location */ - } else { - result= skip_reverse(segment_id - start_offset, - &status); - } - } - if (!ft_location.known) { - TRACE(ft_t_bug, "panic: location not known"); - result = -EIO; - continue; /* while() will check for failure */ - } - TRACE(ft_t_noise, "current segment: %d/%d", - ft_location.segment, ft_location.sector); - /* We're on the right track somewhere before the - * wanted segment. Start tape movement if needed and - * skip to just before or inside the requested - * segment. Keep tape running. - */ - result = 0; - if (ft_location.segment < - (segment_id - ((ftape_tape_running || ft_location.bot) - ? 0 : start_offset))) { - if (sector_offset > 0) { - result = seek_forward(segment_id, - retry <= 3); - } else { - result = seek_forward(segment_id - 1, - retry <= 3); - } - } - if (result == 0 && - ft_location.segment != - (segment_id - (sector_offset > 0 ? 0 : 1))) { - result = -EIO; - } - } - if (result < 0) { - TRACE(ft_t_err, "failed to reposition"); - } else { - ft_runner_status = running; - } - TRACE_EXIT result; -} diff --git a/drivers/char/ftape/lowlevel/ftape-rw.h b/drivers/char/ftape/lowlevel/ftape-rw.h deleted file mode 100644 index 32f4feeb887c..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-rw.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _FTAPE_RW_H -#define _FTAPE_RW_H - -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-rw.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:25 $ - * - * This file contains the definitions for the read and write - * functions for the QIC-117 floppy-tape driver for Linux. - * - * Claus-Justus Heine (1996/09/20): Add definition of format code 6 - * Claus-Justus Heine (1996/10/04): Changed GET/PUT macros to cast to (__u8 *) - * - */ - -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/ftape-bsm.h" - -#include - -#define GET2(address, offset) get_unaligned((__u16*)((__u8 *)address + offset)) -#define GET4(address, offset) get_unaligned((__u32*)((__u8 *)address + offset)) -#define GET8(address, offset) get_unaligned((__u64*)((__u8 *)address + offset)) -#define PUT2(address, offset , value) put_unaligned((value), (__u16*)((__u8 *)address + offset)) -#define PUT4(address, offset , value) put_unaligned((value), (__u32*)((__u8 *)address + offset)) -#define PUT8(address, offset , value) put_unaligned((value), (__u64*)((__u8 *)address + offset)) - -enum runner_status_enum { - idle = 0, - running, - do_abort, - aborting, - logical_eot, - end_of_tape, -}; - -typedef enum ft_buffer_queue { - ft_queue_head = 0, - ft_queue_tail = 1 -} ft_buffer_queue_t; - - -typedef struct { - int track; /* tape head position */ - volatile int segment; /* current segment */ - volatile int sector; /* sector offset within current segment */ - volatile unsigned int bot; /* logical begin of track */ - volatile unsigned int eot; /* logical end of track */ - volatile unsigned int known; /* validates bot, segment, sector */ -} location_record; - -/* Count nr of 1's in pattern. - */ -static inline int count_ones(unsigned long mask) -{ - int bits; - - for (bits = 0; mask != 0; mask >>= 1) { - if (mask & 1) { - ++bits; - } - } - return bits; -} - -#define FT_MAX_NR_BUFFERS 16 /* arbitrary value */ -/* ftape-rw.c defined global vars. - */ -extern buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS]; -extern int ft_nr_buffers; -extern location_record ft_location; -extern volatile int ftape_tape_running; - -/* ftape-rw.c defined global functions. - */ -extern int ftape_setup_new_segment(buffer_struct * buff, - int segment_id, - int offset); -extern int ftape_calc_next_cluster(buffer_struct * buff); -extern buffer_struct *ftape_next_buffer (ft_buffer_queue_t pos); -extern buffer_struct *ftape_get_buffer (ft_buffer_queue_t pos); -extern int ftape_buffer_id (ft_buffer_queue_t pos); -extern void ftape_reset_buffer(void); -extern void ftape_tape_parameters(__u8 drive_configuration); -extern int ftape_wait_segment(buffer_state_enum state); -extern int ftape_dumb_stop(void); -extern int ftape_start_tape(int segment_id, int offset); -extern int ftape_stop_tape(int *pstatus); -extern int ftape_handle_logical_eot(void); -extern buffer_state_enum ftape_set_state(buffer_state_enum new_state); -#endif /* _FTAPE_RW_H */ diff --git a/drivers/char/ftape/lowlevel/ftape-setup.c b/drivers/char/ftape/lowlevel/ftape-setup.c deleted file mode 100644 index 678340acd0b7..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-setup.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-setup.c,v $ - * $Revision: 1.7 $ - * $Date: 1997/10/10 09:57:06 $ - * - * This file contains the code for processing the kernel command - * line options for the QIC-40/80/3010/3020 floppy-tape driver - * "ftape" for Linux. - */ - -#include -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-io.h" - -static struct param_table { - const char *name; - int *var; - int def_param; - int min; - int max; -} config_params[] __initdata = { -#ifndef CONFIG_FT_NO_TRACE_AT_ALL - { "tracing", &ftape_tracing, 3, ft_t_bug, ft_t_any}, -#endif - { "ioport", &ft_fdc_base, CONFIG_FT_FDC_BASE, 0x0, 0xfff}, - { "irq", &ft_fdc_irq, CONFIG_FT_FDC_IRQ, 2, 15}, - { "dma", &ft_fdc_dma, CONFIG_FT_FDC_DMA, 0, 3}, - { "threshold", &ft_fdc_threshold, CONFIG_FT_FDC_THR, 1, 16}, - { "datarate", &ft_fdc_rate_limit, CONFIG_FT_FDC_MAX_RATE, 500, 2000}, - { "fc10", &ft_probe_fc10, CONFIG_FT_PROBE_FC10, 0, 1}, - { "mach2", &ft_mach2, CONFIG_FT_MACH2, 0, 1} -}; - -static int __init ftape_setup(char *str) -{ - int i; - int param; - int ints[2]; - - TRACE_FUN(ft_t_flow); - - str = get_options(str, ARRAY_SIZE(ints), ints); - if (str) { - for (i=0; i < NR_ITEMS(config_params); i++) { - if (strcmp(str,config_params[i].name) == 0){ - if (ints[0]) { - param = ints[1]; - } else { - param = config_params[i].def_param; - } - if (param < config_params[i].min || - param > config_params[i].max) { - TRACE(ft_t_err, - "parameter %s out of range %d ... %d", - config_params[i].name, - config_params[i].min, - config_params[i].max); - goto out; - } - if(config_params[i].var) { - TRACE(ft_t_info, "%s=%d", str, param); - *config_params[i].var = param; - } - goto out; - } - } - } - if (str) { - TRACE(ft_t_err, "unknown ftape option [%s]", str); - - TRACE(ft_t_err, "allowed options are:"); - for (i=0; i < NR_ITEMS(config_params); i++) { - TRACE(ft_t_err, " %s",config_params[i].name); - } - } else { - TRACE(ft_t_err, "botched ftape option"); - } - out: - TRACE_EXIT 1; -} - -__setup("ftape=", ftape_setup); diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.c b/drivers/char/ftape/lowlevel/ftape-tracing.c deleted file mode 100644 index 7fdc6567440b..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-tracing.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-tracing.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:27 $ - * - * This file contains the reading code - * for the QIC-117 floppy-tape driver for Linux. - */ - -#include -#include "../lowlevel/ftape-tracing.h" - -/* Global vars. - */ -/* tracing - * set it to: to log : - * 0 bugs - * 1 + errors - * 2 + warnings - * 3 + information - * 4 + more information - * 5 + program flow - * 6 + fdc/dma info - * 7 + data flow - * 8 + everything else - */ -ft_trace_t ftape_tracing = ft_t_info; /* Default level: information and up */ -int ftape_function_nest_level; - -/* Local vars. - */ -static __u8 trace_id; -static char spacing[] = "* "; - -void ftape_trace_call(const char *file, const char *name) -{ - char *indent; - - /* Since printk seems not to work with "%*s" format - * we'll use this work-around. - */ - if (ftape_function_nest_level < 0) { - printk(KERN_INFO "function nest level (%d) < 0\n", - ftape_function_nest_level); - ftape_function_nest_level = 0; - } - if (ftape_function_nest_level < sizeof(spacing)) { - indent = (spacing + - sizeof(spacing) - 1 - - ftape_function_nest_level); - } else { - indent = spacing; - } - printk(KERN_INFO "[%03d]%s+%s (%s)\n", - (int) trace_id++, indent, file, name); -} - -void ftape_trace_exit(const char *file, const char *name) -{ - char *indent; - - /* Since printk seems not to work with "%*s" format - * we'll use this work-around. - */ - if (ftape_function_nest_level < 0) { - printk(KERN_INFO "function nest level (%d) < 0\n", ftape_function_nest_level); - ftape_function_nest_level = 0; - } - if (ftape_function_nest_level < sizeof(spacing)) { - indent = (spacing + - sizeof(spacing) - 1 - - ftape_function_nest_level); - } else { - indent = spacing; - } - printk(KERN_INFO "[%03d]%s-%s (%s)\n", - (int) trace_id++, indent, file, name); -} - -void ftape_trace_log(const char *file, const char *function) -{ - char *indent; - - /* Since printk seems not to work with "%*s" format - * we'll use this work-around. - */ - if (ftape_function_nest_level < 0) { - printk(KERN_INFO "function nest level (%d) < 0\n", ftape_function_nest_level); - ftape_function_nest_level = 0; - } - if (ftape_function_nest_level < sizeof(spacing)) { - indent = (spacing + - sizeof(spacing) - 1 - - ftape_function_nest_level); - } else { - indent = spacing; - } - printk(KERN_INFO "[%03d]%s%s (%s) - ", - (int) trace_id++, indent, file, function); -} diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.h b/drivers/char/ftape/lowlevel/ftape-tracing.h deleted file mode 100644 index 2950810c7085..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-tracing.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef _FTAPE_TRACING_H -#define _FTAPE_TRACING_H - -/* - * Copyright (C) 1994-1996 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-tracing.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:28 $ - * - * This file contains definitions that eases the debugging of the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include - -/* - * Be very careful with TRACE_EXIT and TRACE_ABORT. - * - * if (something) TRACE_EXIT error; - * - * will NOT work. Use - * - * if (something) { - * TRACE_EXIT error; - * } - * - * instead. Maybe a bit dangerous, but save lots of lines of code. - */ - -#define LL_X "%d/%d KB" -#define LL(x) (unsigned int)((__u64)(x)>>10), (unsigned int)((x)&1023) - -typedef enum { - ft_t_nil = -1, - ft_t_bug, - ft_t_err, - ft_t_warn, - ft_t_info, - ft_t_noise, - ft_t_flow, - ft_t_fdc_dma, - ft_t_data_flow, - ft_t_any -} ft_trace_t; - -#ifdef CONFIG_FT_NO_TRACE_AT_ALL -/* the compiler will optimize away most TRACE() macros - */ -#define FT_TRACE_TOP_LEVEL ft_t_bug -#define TRACE_FUN(level) do {} while(0) -#define TRACE_EXIT return -#define TRACE(l, m, i...) \ -{ \ - if ((ft_trace_t)(l) == FT_TRACE_TOP_LEVEL) { \ - printk(KERN_INFO"ftape%s(%s):\n" \ - KERN_INFO m".\n" ,__FILE__, __FUNCTION__ , ##i); \ - } \ -} -#define SET_TRACE_LEVEL(l) if ((l) == (l)) do {} while(0) -#define TRACE_LEVEL FT_TRACE_TOP_LEVEL - -#else - -#ifdef CONFIG_FT_NO_TRACE -/* the compiler will optimize away many TRACE() macros - * the ftape_simple_trace_call() function simply increments - * the function nest level. - */ -#define FT_TRACE_TOP_LEVEL ft_t_warn -#define TRACE_FUN(level) ftape_function_nest_level++ -#define TRACE_EXIT ftape_function_nest_level--; return - -#else -#ifdef CONFIG_FT_FULL_DEBUG -#define FT_TRACE_TOP_LEVEL ft_t_any -#else -#define FT_TRACE_TOP_LEVEL ft_t_flow -#endif -#define TRACE_FUN(level) \ - const ft_trace_t _tracing = level; \ - if (ftape_tracing >= (ft_trace_t)(level) && \ - (ft_trace_t)(level) <= FT_TRACE_TOP_LEVEL) \ - ftape_trace_call(__FILE__, __FUNCTION__); \ - ftape_function_nest_level ++; - -#define TRACE_EXIT \ - --ftape_function_nest_level; \ - if (ftape_tracing >= (ft_trace_t)(_tracing) && \ - (ft_trace_t)(_tracing) <= FT_TRACE_TOP_LEVEL) \ - ftape_trace_exit(__FILE__, __FUNCTION__); \ - return - -#endif - -#define TRACE(l, m, i...) \ -{ \ - if (ftape_tracing >= (ft_trace_t)(l) && \ - (ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \ - ftape_trace_log(__FILE__, __FUNCTION__); \ - printk(m".\n" ,##i); \ - } \ -} - -#define SET_TRACE_LEVEL(l) \ -{ \ - if ((ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \ - ftape_tracing = (ft_trace_t)(l); \ - } else { \ - ftape_tracing = FT_TRACE_TOP_LEVEL; \ - } \ -} -#define TRACE_LEVEL \ -((ftape_tracing <= FT_TRACE_TOP_LEVEL) ? ftape_tracing : FT_TRACE_TOP_LEVEL) - - -/* Global variables declared in tracing.c - */ -extern ft_trace_t ftape_tracing; /* sets default level */ -extern int ftape_function_nest_level; - -/* Global functions declared in tracing.c - */ -extern void ftape_trace_call(const char *file, const char *name); -extern void ftape_trace_exit(const char *file, const char *name); -extern void ftape_trace_log (const char *file, const char *name); - -#endif /* !defined(CONFIG_FT_NO_TRACE_AT_ALL) */ - -/* - * Abort with a message. - */ -#define TRACE_ABORT(res, i...) \ -{ \ - TRACE(i); \ - TRACE_EXIT res; \ -} - -/* The following transforms the common "if(result < 0) ... " into a - * one-liner. - */ -#define _TRACE_CATCH(level, fun, action) \ -{ \ - int _res = (fun); \ - if (_res < 0) { \ - do { action /* */ ; } while(0); \ - TRACE_ABORT(_res, level, "%s failed: %d", #fun, _res); \ - } \ -} - -#define TRACE_CATCH(fun, fail) _TRACE_CATCH(ft_t_err, fun, fail) - -/* Abort the current function when signalled. This doesn't belong here, - * but rather into ftape-rw.h (maybe) - */ -#define FT_SIGNAL_EXIT(sig_mask) \ - if (sigtestsetmask(¤t->pending.signal, sig_mask)) { \ - TRACE_ABORT(-EINTR, \ - ft_t_warn, \ - "interrupted by non-blockable signal"); \ - } - -#endif /* _FTAPE_TRACING_H */ diff --git a/drivers/char/ftape/lowlevel/ftape-write.c b/drivers/char/ftape/lowlevel/ftape-write.c deleted file mode 100644 index 45601ec801ee..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-write.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (C) 1993-1995 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-write.c,v $ - * $Revision: 1.3.4.1 $ - * $Date: 1997/11/14 18:07:04 $ - * - * This file contains the writing code - * for the QIC-117 floppy-tape driver for Linux. - */ - -#include -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-ecc.h" -#include "../lowlevel/ftape-bsm.h" -#include "../lowlevel/fdc-isr.h" - -/* Global vars. - */ - -/* Local vars. - */ -static int last_write_failed; - -void ftape_zap_write_buffers(void) -{ - int i; - - for (i = 0; i < ft_nr_buffers; ++i) { - ft_buffer[i]->status = done; - } - ftape_reset_buffer(); -} - -static int copy_and_gen_ecc(void *destination, - const void *source, - const SectorMap bad_sector_map) -{ - int result; - struct memory_segment mseg; - int bads = count_ones(bad_sector_map); - TRACE_FUN(ft_t_any); - - if (bads > 0) { - TRACE(ft_t_noise, "bad sectors in map: %d", bads); - } - if (bads + 3 >= FT_SECTORS_PER_SEGMENT) { - TRACE(ft_t_noise, "empty segment"); - mseg.blocks = 0; /* skip entire segment */ - result = 0; /* nothing written */ - } else { - mseg.blocks = FT_SECTORS_PER_SEGMENT - bads; - mseg.data = destination; - memcpy(mseg.data, source, (mseg.blocks - 3) * FT_SECTOR_SIZE); - result = ftape_ecc_set_segment_parity(&mseg); - if (result < 0) { - TRACE(ft_t_err, "ecc_set_segment_parity failed"); - } else { - result = (mseg.blocks - 3) * FT_SECTOR_SIZE; - } - } - TRACE_EXIT result; -} - - -int ftape_start_writing(const ft_write_mode_t mode) -{ - buffer_struct *head = ftape_get_buffer(ft_queue_head); - int segment_id = head->segment_id; - int result; - buffer_state_enum wanted_state = (mode == FT_WR_DELETE - ? deleting - : writing); - TRACE_FUN(ft_t_flow); - - if ((ft_driver_state != wanted_state) || head->status != waiting) { - TRACE_EXIT 0; - } - ftape_setup_new_segment(head, segment_id, 1); - if (mode == FT_WR_SINGLE) { - /* stop tape instead of pause */ - head->next_segment = 0; - } - ftape_calc_next_cluster(head); /* prepare */ - head->status = ft_driver_state; /* either writing or deleting */ - if (ft_runner_status == idle) { - TRACE(ft_t_noise, - "starting runner for segment %d", segment_id); - TRACE_CATCH(ftape_start_tape(segment_id,head->sector_offset),); - } else { - TRACE(ft_t_noise, "runner not idle, not starting tape"); - } - /* go */ - result = fdc_setup_read_write(head, (mode == FT_WR_DELETE - ? FDC_WRITE_DELETED : FDC_WRITE)); - ftape_set_state(wanted_state); /* should not be necessary */ - TRACE_EXIT result; -} - -/* Wait until all data is actually written to tape. - * - * There is a problem: when the tape runs into logical EOT, then this - * failes. We need to restart the runner in this case. - */ -int ftape_loop_until_writes_done(void) -{ - buffer_struct *head; - TRACE_FUN(ft_t_flow); - - while ((ft_driver_state == writing || ft_driver_state == deleting) && - ftape_get_buffer(ft_queue_head)->status != done) { - /* set the runner status to idle if at lEOT */ - TRACE_CATCH(ftape_handle_logical_eot(), last_write_failed = 1); - /* restart the tape if necessary */ - if (ft_runner_status == idle) { - TRACE(ft_t_noise, "runner is idle, restarting"); - if (ft_driver_state == deleting) { - TRACE_CATCH(ftape_start_writing(FT_WR_DELETE), - last_write_failed = 1); - } else { - TRACE_CATCH(ftape_start_writing(FT_WR_MULTI), - last_write_failed = 1); - } - } - TRACE(ft_t_noise, "tail: %d, head: %d", - ftape_buffer_id(ft_queue_tail), - ftape_buffer_id(ft_queue_head)); - TRACE_CATCH(fdc_interrupt_wait(5 * FT_SECOND), - last_write_failed = 1); - head = ftape_get_buffer(ft_queue_head); - if (head->status == error) { - /* Allow escape from loop when signaled ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - if (head->hard_error_map != 0) { - /* Implement hard write error recovery here - */ - } - /* retry this one */ - head->status = waiting; - if (ft_runner_status == aborting) { - ftape_dumb_stop(); - } - if (ft_runner_status != idle) { - TRACE_ABORT(-EIO, ft_t_err, - "unexpected state: " - "ft_runner_status != idle"); - } - ftape_start_writing(ft_driver_state == deleting - ? FT_WR_MULTI : FT_WR_DELETE); - } - TRACE(ft_t_noise, "looping until writes done"); - } - ftape_set_state(idle); - TRACE_EXIT 0; -} - -/* Write given segment from buffer at address to tape. - */ -static int write_segment(const int segment_id, - const void *address, - const ft_write_mode_t write_mode) -{ - int bytes_written = 0; - buffer_struct *tail; - buffer_state_enum wanted_state = (write_mode == FT_WR_DELETE - ? deleting : writing); - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "segment_id = %d", segment_id); - if (ft_driver_state != wanted_state) { - if (ft_driver_state == deleting || - wanted_state == deleting) { - TRACE_CATCH(ftape_loop_until_writes_done(),); - } - TRACE(ft_t_noise, "calling ftape_abort_operation"); - TRACE_CATCH(ftape_abort_operation(),); - ftape_zap_write_buffers(); - ftape_set_state(wanted_state); - } - /* if all buffers full we'll have to wait... - */ - ftape_wait_segment(wanted_state); - tail = ftape_get_buffer(ft_queue_tail); - switch(tail->status) { - case done: - ft_history.defects += count_ones(tail->hard_error_map); - break; - case waiting: - /* this could happen with multiple EMPTY_SEGMENTs, but - * shouldn't happen any more as we re-start the runner even - * with an empty segment. - */ - bytes_written = -EAGAIN; - break; - case error: - /* setup for a retry - */ - tail->status = waiting; - bytes_written = -EAGAIN; /* force retry */ - if (tail->hard_error_map != 0) { - TRACE(ft_t_warn, - "warning: %d hard error(s) in written segment", - count_ones(tail->hard_error_map)); - TRACE(ft_t_noise, "hard_error_map = 0x%08lx", - (long)tail->hard_error_map); - /* Implement hard write error recovery here - */ - } - break; - default: - TRACE_ABORT(-EIO, ft_t_err, - "wait for empty segment failed, tail status: %d", - tail->status); - } - /* should runner stop ? - */ - if (ft_runner_status == aborting) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - if (head->status == wanted_state) { - head->status = done; /* ???? */ - } - /* don't call abort_operation(), we don't want to zap - * the dma buffers - */ - TRACE_CATCH(ftape_dumb_stop(),); - } else { - /* If just passed last segment on tape: wait for BOT - * or EOT mark. Sets ft_runner_status to idle if at lEOT - * and successful - */ - TRACE_CATCH(ftape_handle_logical_eot(),); - } - if (tail->status == done) { - /* now at least one buffer is empty, fill it with our - * data. skip bad sectors and generate ecc. - * copy_and_gen_ecc return nr of bytes written, range - * 0..29 Kb inclusive! - * - * Empty segments are handled inside coyp_and_gen_ecc() - */ - if (write_mode != FT_WR_DELETE) { - TRACE_CATCH(bytes_written = copy_and_gen_ecc( - tail->address, address, - ftape_get_bad_sector_entry(segment_id)),); - } - tail->segment_id = segment_id; - tail->status = waiting; - tail = ftape_next_buffer(ft_queue_tail); - } - /* Start tape only if all buffers full or flush mode. - * This will give higher probability of streaming. - */ - if (ft_runner_status != running && - ((tail->status == waiting && - ftape_get_buffer(ft_queue_head) == tail) || - write_mode != FT_WR_ASYNC)) { - TRACE_CATCH(ftape_start_writing(write_mode),); - } - TRACE_EXIT bytes_written; -} - -/* Write as much as fits from buffer to the given segment on tape - * and handle retries. - * Return the number of bytes written (>= 0), or: - * -EIO write failed - * -EINTR interrupted by signal - * -ENOSPC device full - */ -int ftape_write_segment(const int segment_id, - const void *buffer, - const ft_write_mode_t flush) -{ - int retry = 0; - int result; - TRACE_FUN(ft_t_flow); - - ft_history.used |= 2; - if (segment_id >= ft_tracks_per_tape*ft_segments_per_track) { - /* tape full */ - TRACE_ABORT(-ENOSPC, ft_t_err, - "invalid segment id: %d (max %d)", - segment_id, - ft_tracks_per_tape * ft_segments_per_track -1); - } - for (;;) { - if ((result = write_segment(segment_id, buffer, flush)) >= 0) { - if (result == 0) { /* empty segment */ - TRACE(ft_t_noise, - "empty segment, nothing written"); - } - TRACE_EXIT result; - } - if (result == -EAGAIN) { - if (++retry > 100) { /* give up */ - TRACE_ABORT(-EIO, ft_t_err, - "write failed, >100 retries in segment"); - } - TRACE(ft_t_warn, "write error, retry %d (%d)", - retry, - ftape_get_buffer(ft_queue_tail)->segment_id); - } else { - TRACE_ABORT(result, ft_t_err, - "write_segment failed, error: %d", result); - } - /* Allow escape from loop when signaled ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - } -} diff --git a/drivers/char/ftape/lowlevel/ftape-write.h b/drivers/char/ftape/lowlevel/ftape-write.h deleted file mode 100644 index 0e7f898b7af9..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-write.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _FTAPE_WRITE_H -#define _FTAPE_WRITE_H - -/* - * Copyright (C) 1994-1995 Bas Laarhoven, - * (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-write.h,v $ - $Author: claus $ - * - $Revision: 1.2 $ - $Date: 1997/10/05 19:18:30 $ - $State: Exp $ - * - * This file contains the definitions for the write functions - * for the QIC-117 floppy-tape driver for Linux. - * - */ - - -/* ftape-write.c defined global functions. - */ -typedef enum { - FT_WR_ASYNC = 0, /* start tape only when all buffers are full */ - FT_WR_MULTI = 1, /* start tape, but don't necessarily stop */ - FT_WR_SINGLE = 2, /* write a single segment and stop afterwards */ - FT_WR_DELETE = 3 /* write deleted data marks */ -} ft_write_mode_t; - -extern int ftape_start_writing(const ft_write_mode_t mode); -extern int ftape_write_segment(const int segment, - const void *address, - const ft_write_mode_t flushing); -extern void ftape_zap_write_buffers(void); -extern int ftape_loop_until_writes_done(void); - -#endif /* _FTAPE_WRITE_H */ - diff --git a/drivers/char/ftape/lowlevel/ftape_syms.c b/drivers/char/ftape/lowlevel/ftape_syms.c deleted file mode 100644 index 8e0dc4a07ca6..000000000000 --- a/drivers/char/ftape/lowlevel/ftape_syms.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 1996-1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape_syms.c,v $ - * $Revision: 1.4 $ - * $Date: 1997/10/17 00:03:51 $ - * - * This file contains the symbols that the ftape low level - * part of the QIC-40/80/3010/3020 floppy-tape driver "ftape" - * exports to its high level clients - */ - -#include - -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-bsm.h" -#include "../lowlevel/ftape-buffer.h" -#include "../lowlevel/ftape-format.h" - -/* bad sector handling from ftape-bsm.c */ -EXPORT_SYMBOL(ftape_get_bad_sector_entry); -EXPORT_SYMBOL(ftape_find_end_of_bsm_list); -/* from ftape-rw.c */ -EXPORT_SYMBOL(ftape_set_state); -/* from ftape-ctl.c */ -EXPORT_SYMBOL(ftape_seek_to_bot); -EXPORT_SYMBOL(ftape_seek_to_eot); -EXPORT_SYMBOL(ftape_abort_operation); -EXPORT_SYMBOL(ftape_get_status); -EXPORT_SYMBOL(ftape_enable); -EXPORT_SYMBOL(ftape_disable); -EXPORT_SYMBOL(ftape_mmap); -EXPORT_SYMBOL(ftape_calibrate_data_rate); -/* from ftape-io.c */ -EXPORT_SYMBOL(ftape_reset_drive); -EXPORT_SYMBOL(ftape_command); -EXPORT_SYMBOL(ftape_parameter); -EXPORT_SYMBOL(ftape_ready_wait); -EXPORT_SYMBOL(ftape_report_operation); -EXPORT_SYMBOL(ftape_report_error); -/* from ftape-read.c */ -EXPORT_SYMBOL(ftape_read_segment_fraction); -EXPORT_SYMBOL(ftape_zap_read_buffers); -EXPORT_SYMBOL(ftape_read_header_segment); -EXPORT_SYMBOL(ftape_decode_header_segment); -/* from ftape-write.c */ -EXPORT_SYMBOL(ftape_write_segment); -EXPORT_SYMBOL(ftape_start_writing); -EXPORT_SYMBOL(ftape_loop_until_writes_done); -/* from ftape-buffer.h */ -EXPORT_SYMBOL(ftape_set_nr_buffers); -/* from ftape-format.h */ -EXPORT_SYMBOL(ftape_format_track); -EXPORT_SYMBOL(ftape_format_status); -EXPORT_SYMBOL(ftape_verify_segment); -/* from tracing.c */ -#ifndef CONFIG_FT_NO_TRACE_AT_ALL -EXPORT_SYMBOL(ftape_tracing); -EXPORT_SYMBOL(ftape_function_nest_level); -EXPORT_SYMBOL(ftape_trace_call); -EXPORT_SYMBOL(ftape_trace_exit); -EXPORT_SYMBOL(ftape_trace_log); -#endif - diff --git a/drivers/char/ftape/zftape/Makefile b/drivers/char/ftape/zftape/Makefile deleted file mode 100644 index 6d91c1f77c05..000000000000 --- a/drivers/char/ftape/zftape/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (C) 1996, 1997 Claus-Justus Heine. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to -# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -# -# $Source: /homes/cvs/ftape-stacked/ftape/zftape/Makefile,v $ -# $Revision: 1.4 $ -# $Date: 1997/10/05 19:18:58 $ -# -# Makefile for the QIC-40/80/3010/3020 zftape interface VFS to -# ftape -# - - -# ZFT_OBSOLETE - enable the MTIOC_ZFTAPE_GETBLKSZ ioctl. You should -# leave this enabled for compatibility with taper. - -obj-$(CONFIG_ZFTAPE) += zftape.o - -zftape-objs := zftape-rw.o zftape-ctl.o zftape-read.o \ - zftape-write.o zftape-vtbl.o zftape-eof.o \ - zftape-init.o zftape-buffers.o zftape_syms.o - -EXTRA_CFLAGS := -DZFT_OBSOLETE diff --git a/drivers/char/ftape/zftape/zftape-buffers.c b/drivers/char/ftape/zftape/zftape-buffers.c deleted file mode 100644 index 7ebce2ec7897..000000000000 --- a/drivers/char/ftape/zftape/zftape-buffers.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 1995-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-buffers.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:59 $ - * - * This file contains the dynamic buffer allocation routines - * of zftape - */ - -#include -#include -#include -#include - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -/* global variables - */ - -/* local varibales - */ -static unsigned int used_memory; -static unsigned int peak_memory; - -void zft_memory_stats(void) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Memory usage (vmalloc allocations):\n" - KERN_INFO "total allocated: %d\n" - KERN_INFO "peak allocation: %d", - used_memory, peak_memory); - peak_memory = used_memory; - TRACE_EXIT; -} - -int zft_vcalloc_once(void *new, size_t size) -{ - TRACE_FUN(ft_t_flow); - if (zft_vmalloc_once(new, size) < 0) { - TRACE_EXIT -ENOMEM; - } - memset(*(void **)new, '\0', size); - TRACE_EXIT 0; -} -int zft_vmalloc_once(void *new, size_t size) -{ - TRACE_FUN(ft_t_flow); - - if (*(void **)new != NULL || size == 0) { - TRACE_EXIT 0; - } - if ((*(void **)new = vmalloc(size)) == NULL) { - TRACE_EXIT -ENOMEM; - } - used_memory += size; - if (peak_memory < used_memory) { - peak_memory = used_memory; - } - TRACE_ABORT(0, ft_t_noise, - "allocated buffer @ %p, %zd bytes", *(void **)new, size); -} -int zft_vmalloc_always(void *new, size_t size) -{ - TRACE_FUN(ft_t_flow); - - zft_vfree(new, size); - TRACE_EXIT zft_vmalloc_once(new, size); -} -void zft_vfree(void *old, size_t size) -{ - TRACE_FUN(ft_t_flow); - - if (*(void **)old) { - vfree(*(void **)old); - used_memory -= size; - TRACE(ft_t_noise, "released buffer @ %p, %zd bytes", - *(void **)old, size); - *(void **)old = NULL; - } - TRACE_EXIT; -} - -void *zft_kmalloc(size_t size) -{ - void *new; - - while ((new = kmalloc(size, GFP_KERNEL)) == NULL) { - msleep_interruptible(100); - } - memset(new, 0, size); - used_memory += size; - if (peak_memory < used_memory) { - peak_memory = used_memory; - } - return new; -} - -void zft_kfree(void *old, size_t size) -{ - kfree(old); - used_memory -= size; -} - -/* there are some more buffers that are allocated on demand. - * cleanup_module() calles this function to be sure to have released - * them - */ -void zft_uninit_mem(void) -{ - TRACE_FUN(ft_t_flow); - - zft_vfree(&zft_hseg_buf, FT_SEGMENT_SIZE); - zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); zft_deblock_segment = -1; - zft_free_vtbl(); - if (zft_cmpr_lock(0 /* don't load */) == 0) { - (*zft_cmpr_ops->cleanup)(); - (*zft_cmpr_ops->reset)(); /* unlock it again */ - } - zft_memory_stats(); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/zftape/zftape-buffers.h b/drivers/char/ftape/zftape/zftape-buffers.h deleted file mode 100644 index 798e3128c682..000000000000 --- a/drivers/char/ftape/zftape/zftape-buffers.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _FTAPE_DYNMEM_H -#define _FTAPE_DYNMEM_H - -/* - * Copyright (C) 1995-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-buffers.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:59 $ - * - * memory allocation routines. - * - */ - -/* we do not allocate all of the really large buffer memory before - * someone tries to open the drive. ftape_open() may fail with - * -ENOMEM, but that's better having 200k of vmalloced memory which - * cannot be swapped out. - */ - -extern void zft_memory_stats(void); -extern int zft_vmalloc_once(void *new, size_t size); -extern int zft_vcalloc_once(void *new, size_t size); -extern int zft_vmalloc_always(void *new, size_t size); -extern void zft_vfree(void *old, size_t size); -extern void *zft_kmalloc(size_t size); -extern void zft_kfree(void *old, size_t size); - -/* called by cleanup_module() - */ -extern void zft_uninit_mem(void); - -#endif - - - - - - - diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c deleted file mode 100644 index 22ba0f5d00cf..000000000000 --- a/drivers/char/ftape/zftape/zftape-ctl.c +++ /dev/null @@ -1,1417 +0,0 @@ -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-ctl.c,v $ - * $Revision: 1.2.6.2 $ - * $Date: 1997/11/14 18:07:33 $ - * - * This file contains the non-read/write zftape functions - * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. - */ - -#include -#include -#include -#include - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -/* Global vars. - */ -int zft_write_protected; /* this is when cartridge rdonly or O_RDONLY */ -int zft_header_read; -int zft_offline; -unsigned int zft_unit; -int zft_resid; -int zft_mt_compression; - -/* Local vars. - */ -static int going_offline; - -typedef int (mt_fun)(int *argptr); -typedef int (*mt_funp)(int *argptr); -typedef struct -{ - mt_funp function; - unsigned offline : 1; /* op permitted if offline or no_tape */ - unsigned write_protected : 1; /* op permitted if write-protected */ - unsigned not_formatted : 1; /* op permitted if tape not formatted */ - unsigned raw_mode : 1; /* op permitted if zft_mode == 0 */ - unsigned need_idle_state : 1; /* need to call def_idle_state */ - char *name; -} fun_entry; - -static mt_fun mt_dummy, mt_reset, mt_fsr, mt_bsr, mt_rew, mt_offl, mt_nop, - mt_weof, mt_erase, mt_ras2, mt_setblk, mt_setdensity, - mt_seek, mt_tell, mt_reten, mt_eom, mt_fsf, mt_bsf, - mt_fsfm, mt_bsfm, mt_setdrvbuffer, mt_compression; - -static fun_entry mt_funs[]= -{ - {mt_reset , 1, 1, 1, 1, 0, "MT_RESET" }, /* 0 */ - {mt_fsf , 0, 1, 0, 0, 1, "MT_FSF" }, - {mt_bsf , 0, 1, 0, 0, 1, "MT_BSF" }, - {mt_fsr , 0, 1, 0, 1, 1, "MT_FSR" }, - {mt_bsr , 0, 1, 0, 1, 1, "MT_BSR" }, - {mt_weof , 0, 0, 0, 0, 0, "MT_WEOF" }, /* 5 */ - {mt_rew , 0, 1, 1, 1, 0, "MT_REW" }, - {mt_offl , 0, 1, 1, 1, 0, "MT_OFFL" }, - {mt_nop , 1, 1, 1, 1, 0, "MT_NOP" }, - {mt_reten , 0, 1, 1, 1, 0, "MT_RETEN" }, - {mt_bsfm , 0, 1, 0, 0, 1, "MT_BSFM" }, /* 10 */ - {mt_fsfm , 0, 1, 0, 0, 1, "MT_FSFM" }, - {mt_eom , 0, 1, 0, 0, 1, "MT_EOM" }, - {mt_erase , 0, 0, 0, 1, 0, "MT_ERASE" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS1" }, - {mt_ras2 , 0, 0, 0, 1, 0, "MT_RAS2" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS3" }, - {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, - {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, - {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, - {mt_setblk , 1, 1, 1, 1, 1, "MT_SETBLK"}, /* 20 */ - {mt_setdensity , 1, 1, 1, 1, 0, "MT_SETDENSITY"}, - {mt_seek , 0, 1, 0, 1, 1, "MT_SEEK" }, - {mt_dummy , 0, 1, 0, 1, 1, "MT_TELL" }, /* wr-only ?! */ - {mt_setdrvbuffer, 1, 1, 1, 1, 0, "MT_SETDRVBUFFER" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_FSS" }, /* 25 */ - {mt_dummy , 1, 1, 1, 1, 0, "MT_BSS" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_WSM" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_LOCK" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOCK"}, - {mt_dummy , 1, 1, 1, 1, 0, "MT_LOAD" }, /* 30 */ - {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOAD"}, - {mt_compression , 1, 1, 1, 0, 1, "MT_COMPRESSION"}, - {mt_dummy , 1, 1, 1, 1, 0, "MT_SETPART"}, - {mt_dummy , 1, 1, 1, 1, 0, "MT_MKPART"} -}; - -#define NR_MT_CMDS NR_ITEMS(mt_funs) - -void zft_reset_position(zft_position *pos) -{ - TRACE_FUN(ft_t_flow); - - pos->seg_byte_pos = - pos->volume_pos = 0; - if (zft_header_read) { - /* need to keep track of the volume table and - * compression map. We therefor simply - * position at the beginning of the first - * volume. This covers old ftape archives as - * well has various flavours of the - * compression map segments. The worst case is - * that the compression map shows up as a - * additional volume in front of all others. - */ - pos->seg_pos = zft_find_volume(0)->start_seg; - pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); - } else { - pos->tape_pos = 0; - pos->seg_pos = -1; - } - zft_just_before_eof = 0; - zft_deblock_segment = -1; - zft_io_state = zft_idle; - zft_zap_read_buffers(); - zft_prevent_flush(); - /* unlock the compresison module if it is loaded. - * The zero arg means not to try to load the module. - */ - if (zft_cmpr_lock(0) == 0) { - (*zft_cmpr_ops->reset)(); /* unlock */ - } - TRACE_EXIT; -} - -static void zft_init_driver(void) -{ - TRACE_FUN(ft_t_flow); - - zft_resid = - zft_header_read = - zft_old_ftape = - zft_offline = - zft_write_protected = - going_offline = - zft_mt_compression = - zft_header_changed = - zft_volume_table_changed = - zft_written_segments = 0; - zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; - zft_reset_position(&zft_pos); /* does most of the stuff */ - ftape_zap_read_buffers(); - ftape_set_state(idle); - TRACE_EXIT; -} - -int zft_def_idle_state(void) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (!zft_header_read) { - result = zft_read_header_segments(); - } else if ((result = zft_flush_buffers()) >= 0 && zft_qic_mode) { - /* don't move past eof - */ - (void)zft_close_volume(&zft_pos); - } - if (ftape_abort_operation() < 0) { - TRACE(ft_t_warn, "ftape_abort_operation() failed"); - result = -EIO; - } - /* clear remaining read buffers */ - zft_zap_read_buffers(); - zft_io_state = zft_idle; - TRACE_EXIT result; -} - -/***************************************************************************** - * * - * functions for the MTIOCTOP commands * - * * - *****************************************************************************/ - -static int mt_dummy(int *dummy) -{ - TRACE_FUN(ft_t_flow); - - TRACE_EXIT -ENOSYS; -} - -static int mt_reset(int *dummy) -{ - TRACE_FUN(ft_t_flow); - - (void)ftape_seek_to_bot(); - TRACE_CATCH(ftape_reset_drive(), - zft_init_driver(); zft_uninit_mem(); zft_offline = 1); - /* fake a re-open of the device. This will set all flage and - * allocate buffers as appropriate. The new tape condition will - * force the open routine to do anything we need. - */ - TRACE_CATCH(_zft_open(-1 /* fake reopen */, 0 /* dummy */),); - TRACE_EXIT 0; -} - -static int mt_fsf(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = zft_skip_volumes(*arg, &zft_pos); - zft_just_before_eof = 0; - TRACE_EXIT result; -} - -static int mt_bsf(int *arg) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (*arg != 0) { - result = zft_skip_volumes(-*arg + 1, &zft_pos); - } - TRACE_EXIT result; -} - -static int seek_block(__s64 data_offset, - __s64 block_increment, - zft_position *pos) -{ - int result = 0; - __s64 new_block_pos; - __s64 vol_block_count; - const zft_volinfo *volume; - int exceed; - TRACE_FUN(ft_t_flow); - - volume = zft_find_volume(pos->seg_pos); - if (volume->start_seg == 0 || volume->end_seg == 0) { - TRACE_EXIT -EIO; - } - new_block_pos = (zft_div_blksz(data_offset, volume->blk_sz) - + block_increment); - vol_block_count = zft_div_blksz(volume->size, volume->blk_sz); - if (new_block_pos < 0) { - TRACE(ft_t_noise, - "new_block_pos " LL_X " < 0", LL(new_block_pos)); - zft_resid = (int)new_block_pos; - new_block_pos = 0; - exceed = 1; - } else if (new_block_pos > vol_block_count) { - TRACE(ft_t_noise, - "new_block_pos " LL_X " exceeds size of volume " LL_X, - LL(new_block_pos), LL(vol_block_count)); - zft_resid = (int)(vol_block_count - new_block_pos); - new_block_pos = vol_block_count; - exceed = 1; - } else { - exceed = 0; - } - if (zft_use_compression && volume->use_compression) { - TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); - result = (*zft_cmpr_ops->seek)(new_block_pos, pos, volume, - zft_deblock_buf); - pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); - pos->tape_pos += pos->seg_byte_pos; - } else { - pos->volume_pos = zft_mul_blksz(new_block_pos, volume->blk_sz); - pos->tape_pos = zft_calc_tape_pos(volume->start_seg); - pos->tape_pos += pos->volume_pos; - pos->seg_pos = zft_calc_seg_byte_coord(&pos->seg_byte_pos, - pos->tape_pos); - } - zft_just_before_eof = volume->size == pos->volume_pos; - if (zft_just_before_eof) { - /* why this? because zft_file_no checks agains start - * and end segment of a volume. We do not want to - * advance to the next volume with this function. - */ - TRACE(ft_t_noise, "set zft_just_before_eof"); - zft_position_before_eof(pos, volume); - } - TRACE(ft_t_noise, "\n" - KERN_INFO "new_seg_pos : %d\n" - KERN_INFO "new_tape_pos: " LL_X "\n" - KERN_INFO "vol_size : " LL_X "\n" - KERN_INFO "seg_byte_pos: %d\n" - KERN_INFO "blk_sz : %d", - pos->seg_pos, LL(pos->tape_pos), - LL(volume->size), pos->seg_byte_pos, - volume->blk_sz); - if (!exceed) { - zft_resid = new_block_pos - zft_div_blksz(pos->volume_pos, - volume->blk_sz); - } - if (zft_resid < 0) { - zft_resid = -zft_resid; - } - TRACE_EXIT ((exceed || zft_resid != 0) && result >= 0) ? -EINVAL : result; -} - -static int mt_fsr(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = seek_block(zft_pos.volume_pos, *arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_bsr(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = seek_block(zft_pos.volume_pos, -*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_weof(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - TRACE_CATCH(zft_flush_buffers(),); - result = zft_weof(*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_rew(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - if(zft_header_read) { - (void)zft_def_idle_state(); - } - result = ftape_seek_to_bot(); - zft_reset_position(&zft_pos); - TRACE_EXIT result; -} - -static int mt_offl(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - going_offline= 1; - result = mt_rew(NULL); - TRACE_EXIT result; -} - -static int mt_nop(int *dummy) -{ - TRACE_FUN(ft_t_flow); - /* should we set tape status? - */ - if (!zft_offline) { /* offline includes no_tape */ - (void)zft_def_idle_state(); - } - TRACE_EXIT 0; -} - -static int mt_reten(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - if(zft_header_read) { - (void)zft_def_idle_state(); - } - result = ftape_seek_to_eot(); - if (result >= 0) { - result = ftape_seek_to_bot(); - } - TRACE_EXIT(result); -} - -static int fsfbsfm(int arg, zft_position *pos) -{ - const zft_volinfo *vtbl; - __s64 block_pos; - TRACE_FUN(ft_t_flow); - - /* What to do? This should seek to the next file-mark and - * position BEFORE. That is, a next write would just extend - * the current file. Well. Let's just seek to the end of the - * current file, if count == 1. If count > 1, then do a - * "mt_fsf(count - 1)", and then seek to the end of that file. - * If count == 0, do nothing - */ - if (arg == 0) { - TRACE_EXIT 0; - } - zft_just_before_eof = 0; - TRACE_CATCH(zft_skip_volumes(arg < 0 ? arg : arg-1, pos), - if (arg > 0) { - zft_resid ++; - }); - vtbl = zft_find_volume(pos->seg_pos); - block_pos = zft_div_blksz(vtbl->size, vtbl->blk_sz); - (void)seek_block(0, block_pos, pos); - if (pos->volume_pos != vtbl->size) { - zft_just_before_eof = 0; - zft_resid = 1; - /* we didn't managed to go there */ - TRACE_ABORT(-EIO, ft_t_err, - "wanted file position " LL_X ", arrived at " LL_X, - LL(vtbl->size), LL(pos->volume_pos)); - } - zft_just_before_eof = 1; - TRACE_EXIT 0; -} - -static int mt_bsfm(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = fsfbsfm(-*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_fsfm(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = fsfbsfm(*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_eom(int *dummy) -{ - TRACE_FUN(ft_t_flow); - - zft_skip_to_eom(&zft_pos); - TRACE_EXIT 0; -} - -static int mt_erase(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = zft_erase(); - TRACE_EXIT result; -} - -static int mt_ras2(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = -ENOSYS; - TRACE_EXIT result; -} - -/* Sets the new blocksize in BYTES - * - */ -static int mt_setblk(int *new_size) -{ - TRACE_FUN(ft_t_flow); - - if((unsigned int)(*new_size) > ZFT_MAX_BLK_SZ) { - TRACE_ABORT(-EINVAL, ft_t_info, - "desired blk_sz (%d) should be <= %d bytes", - *new_size, ZFT_MAX_BLK_SZ); - } - if ((*new_size & (FT_SECTOR_SIZE-1)) != 0) { - TRACE_ABORT(-EINVAL, ft_t_info, - "desired blk_sz (%d) must be a multiple of %d bytes", - *new_size, FT_SECTOR_SIZE); - } - if (*new_size == 0) { - if (zft_use_compression) { - TRACE_ABORT(-EINVAL, ft_t_info, - "Variable block size not yet " - "supported with compression"); - } - *new_size = 1; - } - zft_blk_sz = *new_size; - TRACE_EXIT 0; -} - -static int mt_setdensity(int *arg) -{ - TRACE_FUN(ft_t_flow); - - SET_TRACE_LEVEL(*arg); - TRACE(TRACE_LEVEL, "tracing set to %d", TRACE_LEVEL); - if ((int)TRACE_LEVEL != *arg) { - TRACE_EXIT -EINVAL; - } - TRACE_EXIT 0; -} - -static int mt_seek(int *new_block_pos) -{ - int result= 0; - TRACE_FUN(ft_t_any); - - result = seek_block(0, (__s64)*new_block_pos, &zft_pos); - TRACE_EXIT result; -} - -/* OK, this is totally different from SCSI, but the worst thing that can - * happen is that there is not enough defragmentated memory that can be - * allocated. Also, there is a hardwired limit of 16 dma buffers in the - * stock ftape module. This shouldn't bring the system down. - * - * NOTE: the argument specifies the total number of dma buffers to use. - * The driver needs at least 3 buffers to function at all. - * - */ -static int mt_setdrvbuffer(int *cnt) -{ - TRACE_FUN(ft_t_flow); - - if (*cnt < 3) { - TRACE_EXIT -EINVAL; - } - TRACE_CATCH(ftape_set_nr_buffers(*cnt),); - TRACE_EXIT 0; -} -/* return the block position from start of volume - */ -static int mt_tell(int *arg) -{ - TRACE_FUN(ft_t_flow); - - *arg = zft_div_blksz(zft_pos.volume_pos, - zft_find_volume(zft_pos.seg_pos)->blk_sz); - TRACE_EXIT 0; -} - -static int mt_compression(int *arg) -{ - TRACE_FUN(ft_t_flow); - - /* Ok. We could also check whether compression is available at - * all by trying to load the compression module. We could - * also check for a block size of 1 byte which is illegal - * with compression. Instead of doing it here we rely on - * zftape_write() to do the proper checks. - */ - if ((unsigned int)*arg > 1) { - TRACE_EXIT -EINVAL; - } - if (*arg != 0 && zft_blk_sz == 1) { /* variable block size */ - TRACE_ABORT(-EINVAL, ft_t_info, - "Compression not yet supported " - "with variable block size"); - } - zft_mt_compression = *arg; - if ((zft_unit & ZFT_ZIP_MODE) == 0) { - zft_use_compression = zft_mt_compression; - } - TRACE_EXIT 0; -} - -/* check whether write access is allowed. Write access is denied when - * + zft_write_protected == 1 -- this accounts for either hard write - * protection of the cartridge or for - * O_RDONLY access mode of the tape device - * + zft_offline == 1 -- this meany that there is either no tape - * or that the MTOFFLINE ioctl has been - * previously issued (`soft eject') - * + ft_formatted == 0 -- this means that the cartridge is not - * formatted - * Then we distinuguish two cases. When zft_qic_mode is TRUE, then we try - * to emulate a `traditional' (aka SCSI like) UN*X tape device. Therefore we - * deny writes when - * + zft_qic_mode ==1 && - * (!zft_tape_at_lbot() && -- tape no at logical BOT - * !(zft_tape_at_eom() || -- tape not at logical EOM (or EOD) - * (zft_tape_at_eom() && - * zft_old_ftape()))) -- we can't add new volume to tapes - * written by old ftape because ftape - * don't use the volume table - * - * when the drive is in true raw mode (aka /dev/rawft0) then we don't - * care about LBOT and EOM conditions. This device is intended for a - * user level program that wants to truly implement the QIC-80 compliance - * at the logical data layout level of the cartridge, i.e. implement all - * that volume table and volume directory stuff etc.< - */ -int zft_check_write_access(zft_position *pos) -{ - TRACE_FUN(ft_t_flow); - - if (zft_offline) { /* offline includes no_tape */ - TRACE_ABORT(-ENXIO, - ft_t_info, "tape is offline or no cartridge"); - } - if (!ft_formatted) { - TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); - } - if (zft_write_protected) { - TRACE_ABORT(-EACCES, ft_t_info, "cartridge write protected"); - } - if (zft_qic_mode) { - /* check BOT condition */ - if (!zft_tape_at_lbot(pos)) { - /* protect cartridges written by old ftape if - * not at BOT because they use the vtbl - * segment for storing data - */ - if (zft_old_ftape) { - TRACE_ABORT(-EACCES, ft_t_warn, - "Cannot write to cartridges written by old ftape when not at BOT"); - } - /* not at BOT, but allow writes at EOD, of course - */ - if (!zft_tape_at_eod(pos)) { - TRACE_ABORT(-EACCES, ft_t_info, - "tape not at BOT and not at EOD"); - } - } - /* fine. Now the tape is either at BOT or at EOD. */ - } - /* or in raw mode in which case we don't care about BOT and EOD */ - TRACE_EXIT 0; -} - -/* OPEN routine called by kernel-interface code - * - * NOTE: this is also called by mt_reset() with dev_minor == -1 - * to fake a reopen after a reset. - */ -int _zft_open(unsigned int dev_minor, unsigned int access_mode) -{ - static unsigned int tape_unit; - static unsigned int file_access_mode; - int result; - TRACE_FUN(ft_t_flow); - - if ((int)dev_minor == -1) { - /* fake reopen */ - zft_unit = tape_unit; - access_mode = file_access_mode; - zft_init_driver(); /* reset all static data to defaults */ - } else { - tape_unit = dev_minor; - file_access_mode = access_mode; - if ((result = ftape_enable(FTAPE_SEL(dev_minor))) < 0) { - TRACE_ABORT(-ENXIO, ft_t_err, - "ftape_enable failed: %d", result); - } - if (ft_new_tape || ft_no_tape || !ft_formatted || - (FTAPE_SEL(zft_unit) != FTAPE_SEL(dev_minor)) || - (zft_unit & ZFT_RAW_MODE) != (dev_minor & ZFT_RAW_MODE)) { - /* reset all static data to defaults, - */ - zft_init_driver(); - } - zft_unit = dev_minor; - } - zft_set_flags(zft_unit); /* decode the minor bits */ - if (zft_blk_sz == 1 && zft_use_compression) { - ftape_disable(); /* resets ft_no_tape */ - TRACE_ABORT(-ENODEV, ft_t_warn, "Variable block size not yet " - "supported with compression"); - } - /* no need for most of the buffers when no tape or not - * formatted. for the read/write operations, it is the - * regardless whether there is no tape, a not-formatted tape - * or the whether the driver is soft offline. - * Nevertheless we allow some ioctls with non-formatted tapes, - * like rewind and reset. - */ - if (ft_no_tape || !ft_formatted) { - zft_uninit_mem(); - } - if (ft_no_tape) { - zft_offline = 1; /* so we need not test two variables */ - } - if ((access_mode == O_WRONLY || access_mode == O_RDWR) && - (ft_write_protected || ft_no_tape)) { - ftape_disable(); /* resets ft_no_tape */ - TRACE_ABORT(ft_no_tape ? -ENXIO : -EROFS, - ft_t_warn, "wrong access mode %s cartridge", - ft_no_tape ? "without a" : "with write protected"); - } - zft_write_protected = (access_mode == O_RDONLY || - ft_write_protected != 0); - if (zft_write_protected) { - TRACE(ft_t_noise, - "read only access mode: %d, " - "drive write protected: %d", - access_mode == O_RDONLY, - ft_write_protected != 0); - } - if (!zft_offline) { - TRACE_CATCH(zft_vmalloc_once(&zft_deblock_buf,FT_SEGMENT_SIZE), - ftape_disable()); - } - /* zft_seg_pos should be greater than the vtbl segpos but not - * if in compatibility mode and only after we read in the - * header segments - * - * might also be a problem if the user makes a backup with a - * *qft* device and rewinds it with a raw device. - */ - if (zft_qic_mode && - !zft_old_ftape && - zft_pos.seg_pos >= 0 && - zft_header_read && - zft_pos.seg_pos <= ft_first_data_segment) { - TRACE(ft_t_noise, "you probably mixed up the zftape devices!"); - zft_reset_position(&zft_pos); - } - TRACE_EXIT 0; -} - -/* RELEASE routine called by kernel-interface code - */ -int _zft_close(void) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (zft_offline) { - /* call the hardware release routine. Puts the drive offline */ - ftape_disable(); - TRACE_EXIT 0; - } - if (!(ft_write_protected || zft_old_ftape)) { - result = zft_flush_buffers(); - TRACE(ft_t_noise, "writing file mark at current position"); - if (zft_qic_mode && zft_close_volume(&zft_pos) == 0) { - zft_move_past_eof(&zft_pos); - } - if ((zft_tape_at_lbot(&zft_pos) || - !(zft_unit & FTAPE_NO_REWIND))) { - if (result >= 0) { - result = zft_update_header_segments(); - } else { - TRACE(ft_t_err, - "Error: unable to update header segments"); - } - } - } - ftape_abort_operation(); - if (!(zft_unit & FTAPE_NO_REWIND)) { - TRACE(ft_t_noise, "rewinding tape"); - if (ftape_seek_to_bot() < 0 && result >= 0) { - result = -EIO; /* keep old value */ - } - zft_reset_position(&zft_pos); - } - zft_zap_read_buffers(); - /* now free up memory as much as possible. We don't destroy - * the deblock buffer if it containes a valid segment. - */ - if (zft_deblock_segment == -1) { - zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); - } - /* high level driver status, forces creation of a new volume - * when calling ftape_write again and not zft_just_before_eof - */ - zft_io_state = zft_idle; - if (going_offline) { - zft_init_driver(); - zft_uninit_mem(); - going_offline = 0; - zft_offline = 1; - } else if (zft_cmpr_lock(0 /* don't load */) == 0) { - (*zft_cmpr_ops->reset)(); /* unlock it again */ - } - zft_memory_stats(); - /* call the hardware release routine. Puts the drive offline */ - ftape_disable(); - TRACE_EXIT result; -} - -/* - * the wrapper function around the wrapper MTIOCTOP ioctl - */ -static int mtioctop(struct mtop *mtop, int arg_size) -{ - int result = 0; - fun_entry *mt_fun_entry; - TRACE_FUN(ft_t_flow); - - if (arg_size != sizeof(struct mtop) || mtop->mt_op >= NR_MT_CMDS) { - TRACE_EXIT -EINVAL; - } - TRACE(ft_t_noise, "calling MTIOCTOP command: %s", - mt_funs[mtop->mt_op].name); - mt_fun_entry= &mt_funs[mtop->mt_op]; - zft_resid = mtop->mt_count; - if (!mt_fun_entry->offline && zft_offline) { - if (ft_no_tape) { - TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); - } else { - TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); - } - } - if (!mt_fun_entry->not_formatted && !ft_formatted) { - TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); - } - if (!mt_fun_entry->write_protected) { - TRACE_CATCH(zft_check_write_access(&zft_pos),); - } - if (mt_fun_entry->need_idle_state && !(zft_offline || !ft_formatted)) { - TRACE_CATCH(zft_def_idle_state(),); - } - if (!zft_qic_mode && !mt_fun_entry->raw_mode) { - TRACE_ABORT(-EACCES, ft_t_info, -"Drive needs to be in QIC-80 compatibility mode for this command"); - } - result = (mt_fun_entry->function)(&mtop->mt_count); - if (zft_tape_at_lbot(&zft_pos)) { - TRACE_CATCH(zft_update_header_segments(),); - } - if (result >= 0) { - zft_resid = 0; - } - TRACE_EXIT result; -} - -/* - * standard MTIOCGET ioctl - */ -static int mtiocget(struct mtget *mtget, int arg_size) -{ - const zft_volinfo *volume; - __s64 max_tape_pos; - TRACE_FUN(ft_t_flow); - - if (arg_size != sizeof(struct mtget)) { - TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", - arg_size); - } - mtget->mt_type = ft_drive_type.vendor_id + 0x800000; - mtget->mt_dsreg = ft_last_status.space; - mtget->mt_erreg = ft_last_error.space; /* error register */ - mtget->mt_resid = zft_resid; /* residuum of writes, reads and - * MTIOCTOP commands - */ - if (!zft_offline) { /* neither no_tape nor soft offline */ - mtget->mt_gstat = GMT_ONLINE(~0UL); - /* should rather return the status of the cartridge - * than the access mode of the file, therefor use - * ft_write_protected, not zft_write_protected - */ - if (ft_write_protected) { - mtget->mt_gstat |= GMT_WR_PROT(~0UL); - } - if(zft_header_read) { /* this catches non-formatted */ - volume = zft_find_volume(zft_pos.seg_pos); - mtget->mt_fileno = volume->count; - max_tape_pos = zft_capacity - zft_blk_sz; - if (zft_use_compression) { - max_tape_pos -= ZFT_CMPR_OVERHEAD; - } - if (zft_tape_at_eod(&zft_pos)) { - mtget->mt_gstat |= GMT_EOD(~0UL); - } - if (zft_pos.tape_pos > max_tape_pos) { - mtget->mt_gstat |= GMT_EOT(~0UL); - } - mtget->mt_blkno = zft_div_blksz(zft_pos.volume_pos, - volume->blk_sz); - if (zft_just_before_eof) { - mtget->mt_gstat |= GMT_EOF(~0UL); - } - if (zft_tape_at_lbot(&zft_pos)) { - mtget->mt_gstat |= GMT_BOT(~0UL); - } - } else { - mtget->mt_fileno = mtget->mt_blkno = -1; - if (mtget->mt_dsreg & QIC_STATUS_AT_BOT) { - mtget->mt_gstat |= GMT_BOT(~0UL); - } - } - } else { - if (ft_no_tape) { - mtget->mt_gstat = GMT_DR_OPEN(~0UL); - } else { - mtget->mt_gstat = 0UL; - } - mtget->mt_fileno = mtget->mt_blkno = -1; - } - TRACE_EXIT 0; -} - -#ifdef MTIOCRDFTSEG -/* - * Read a floppy tape segment. This is useful for manipulating the - * volume table, and read the old header segment before re-formatting - * the cartridge. - */ -static int mtiocrdftseg(struct mtftseg * mtftseg, int arg_size) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCRDFTSEG"); - if (zft_qic_mode) { - TRACE_ABORT(-EACCES, ft_t_info, - "driver needs to be in raw mode for this ioctl"); - } - if (arg_size != sizeof(struct mtftseg)) { - TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", - arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (mtftseg->mt_mode != FT_RD_SINGLE && - mtftseg->mt_mode != FT_RD_AHEAD) { - TRACE_ABORT(-EINVAL, ft_t_info, "invalid read mode"); - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; /* -ENXIO ? */ - - } - if (!zft_header_read) { - TRACE_CATCH(zft_def_idle_state(),); - } - if (mtftseg->mt_segno > ft_last_data_segment) { - TRACE_ABORT(-EINVAL, ft_t_info, "segment number is too large"); - } - mtftseg->mt_result = ftape_read_segment(mtftseg->mt_segno, - zft_deblock_buf, - mtftseg->mt_mode); - if (mtftseg->mt_result < 0) { - /* a negativ result is not an ioctl error. if - * the user wants to read damaged tapes, - * it's up to her/him - */ - TRACE_EXIT 0; - } - if (copy_to_user(mtftseg->mt_data, - zft_deblock_buf, - mtftseg->mt_result) != 0) { - TRACE_EXIT -EFAULT; - } - TRACE_EXIT 0; -} -#endif - -#ifdef MTIOCWRFTSEG -/* - * write a floppy tape segment. This version features writing of - * deleted address marks, and gracefully ignores the (software) - * ft_formatted flag to support writing of header segments after - * formatting. - */ -static int mtiocwrftseg(struct mtftseg * mtftseg, int arg_size) -{ - int result; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCWRFTSEG"); - if (zft_write_protected || zft_qic_mode) { - TRACE_EXIT -EACCES; - } - if (arg_size != sizeof(struct mtftseg)) { - TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", - arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (mtftseg->mt_mode != FT_WR_ASYNC && - mtftseg->mt_mode != FT_WR_MULTI && - mtftseg->mt_mode != FT_WR_SINGLE && - mtftseg->mt_mode != FT_WR_DELETE) { - TRACE_ABORT(-EINVAL, ft_t_info, "invalid write mode"); - } - /* - * We don't check for ft_formatted, because this gives - * only the software status of the driver. - * - * We assume that the user knows what it is - * doing. And rely on the low level stuff to fail - * when the tape isn't formatted. We only make sure - * that The header segment buffer is allocated, - * because it holds the bad sector map. - */ - if (zft_hseg_buf == NULL) { - TRACE_EXIT -ENXIO; - } - if (mtftseg->mt_mode != FT_WR_DELETE) { - if (copy_from_user(zft_deblock_buf, - mtftseg->mt_data, - FT_SEGMENT_SIZE) != 0) { - TRACE_EXIT -EFAULT; - } - } - mtftseg->mt_result = ftape_write_segment(mtftseg->mt_segno, - zft_deblock_buf, - mtftseg->mt_mode); - if (mtftseg->mt_result >= 0 && mtftseg->mt_mode == FT_WR_SINGLE) { - /* - * a negativ result is not an ioctl error. if - * the user wants to write damaged tapes, - * it's up to her/him - */ - if ((result = ftape_loop_until_writes_done()) < 0) { - mtftseg->mt_result = result; - } - } - TRACE_EXIT 0; -} -#endif - -#ifdef MTIOCVOLINFO -/* - * get information about volume positioned at. - */ -static int mtiocvolinfo(struct mtvolinfo *volinfo, int arg_size) -{ - const zft_volinfo *volume; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCVOLINFO"); - if (arg_size != sizeof(struct mtvolinfo)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; - } - TRACE_CATCH(zft_def_idle_state(),); - volume = zft_find_volume(zft_pos.seg_pos); - volinfo->mt_volno = volume->count; - volinfo->mt_blksz = volume->blk_sz == 1 ? 0 : volume->blk_sz; - volinfo->mt_size = volume->size >> 10; - volinfo->mt_rawsize = ((zft_calc_tape_pos(volume->end_seg + 1) >> 10) - - (zft_calc_tape_pos(volume->start_seg) >> 10)); - volinfo->mt_cmpr = volume->use_compression; - TRACE_EXIT 0; -} -#endif - -#ifdef ZFT_OBSOLETE -static int mtioc_zftape_getblksz(struct mtblksz *blksz, int arg_size) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "\n" - KERN_INFO "Mag tape ioctl command: MTIOC_ZTAPE_GETBLKSZ\n" - KERN_INFO "This ioctl is here merely for compatibility.\n" - KERN_INFO "Please use MTIOCVOLINFO instead"); - if (arg_size != sizeof(struct mtblksz)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; - } - TRACE_CATCH(zft_def_idle_state(),); - blksz->mt_blksz = zft_find_volume(zft_pos.seg_pos)->blk_sz; - TRACE_EXIT 0; -} -#endif - -#ifdef MTIOCGETSIZE -/* - * get the capacity of the tape cartridge. - */ -static int mtiocgetsize(struct mttapesize *size, int arg_size) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOC_ZFTAPE_GETSIZE"); - if (arg_size != sizeof(struct mttapesize)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; - } - TRACE_CATCH(zft_def_idle_state(),); - size->mt_capacity = (unsigned int)(zft_capacity>>10); - size->mt_used = (unsigned int)(zft_get_eom_pos()>>10); - TRACE_EXIT 0; -} -#endif - -static int mtiocpos(struct mtpos *mtpos, int arg_size) -{ - int result; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCPOS"); - if (arg_size != sizeof(struct mtpos)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - result = mt_tell((int *)&mtpos->mt_blkno); - TRACE_EXIT result; -} - -#ifdef MTIOCFTFORMAT -/* - * formatting of floppy tape cartridges. This is intended to be used - * together with the MTIOCFTCMD ioctl and the new mmap feature - */ - -/* - * This function uses ftape_decode_header_segment() to inform the low - * level ftape module about the new parameters. - * - * It erases the hseg_buf. The calling process must specify all - * parameters to assure proper operation. - * - * return values: -EINVAL - wrong argument size - * -EINVAL - if ftape_decode_header_segment() failed. - */ -static int set_format_parms(struct ftfmtparms *p, __u8 *hseg_buf) -{ - ft_trace_t old_level = TRACE_LEVEL; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_SETPARMS"); - memset(hseg_buf, 0, FT_SEGMENT_SIZE); - PUT4(hseg_buf, FT_SIGNATURE, FT_HSEG_MAGIC); - - /* fill in user specified parameters - */ - hseg_buf[FT_FMT_CODE] = (__u8)p->ft_fmtcode; - PUT2(hseg_buf, FT_SPT, p->ft_spt); - hseg_buf[FT_TPC] = (__u8)p->ft_tpc; - hseg_buf[FT_FHM] = (__u8)p->ft_fhm; - hseg_buf[FT_FTM] = (__u8)p->ft_ftm; - - /* fill in sane defaults to make ftape happy. - */ - hseg_buf[FT_FSM] = (__u8)128; /* 128 is hard wired all over ftape */ - if (p->ft_fmtcode == fmt_big) { - PUT4(hseg_buf, FT_6_HSEG_1, 0); - PUT4(hseg_buf, FT_6_HSEG_2, 1); - PUT4(hseg_buf, FT_6_FRST_SEG, 2); - PUT4(hseg_buf, FT_6_LAST_SEG, p->ft_spt * p->ft_tpc - 1); - } else { - PUT2(hseg_buf, FT_HSEG_1, 0); - PUT2(hseg_buf, FT_HSEG_2, 1); - PUT2(hseg_buf, FT_FRST_SEG, 2); - PUT2(hseg_buf, FT_LAST_SEG, p->ft_spt * p->ft_tpc - 1); - } - - /* Synchronize with the low level module. This is particularly - * needed for unformatted cartridges as the QIC std was previously - * unknown BUT is needed to set data rate and to calculate timeouts. - */ - TRACE_CATCH(ftape_calibrate_data_rate(p->ft_qicstd&QIC_TAPE_STD_MASK), - _res = -EINVAL); - - /* The following will also recalcualte the timeouts for the tape - * length and QIC std we want to format to. - * abort with -EINVAL rather than -EIO - */ - SET_TRACE_LEVEL(ft_t_warn); - TRACE_CATCH(ftape_decode_header_segment(hseg_buf), - SET_TRACE_LEVEL(old_level); _res = -EINVAL); - SET_TRACE_LEVEL(old_level); - TRACE_EXIT 0; -} - -/* - * Return the internal SOFTWARE status of the kernel driver. This does - * NOT query the tape drive about its status. - */ -static int get_format_parms(struct ftfmtparms *p, __u8 *hseg_buffer) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_GETPARMS"); - p->ft_qicstd = ft_qic_std; - p->ft_fmtcode = ft_format_code; - p->ft_fhm = hseg_buffer[FT_FHM]; - p->ft_ftm = hseg_buffer[FT_FTM]; - p->ft_spt = ft_segments_per_track; - p->ft_tpc = ft_tracks_per_tape; - TRACE_EXIT 0; -} - -static int mtiocftformat(struct mtftformat *mtftformat, int arg_size) -{ - int result; - union fmt_arg *arg = &mtftformat->fmt_arg; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTFORMAT"); - if (zft_offline) { - if (ft_no_tape) { - TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); - } else { - TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); - } - } - if (zft_qic_mode) { - TRACE_ABORT(-EACCES, ft_t_info, - "driver needs to be in raw mode for this ioctl"); - } - if (zft_hseg_buf == NULL) { - TRACE_CATCH(zft_vcalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); - } - zft_header_read = 0; - switch(mtftformat->fmt_op) { - case FTFMT_SET_PARMS: - TRACE_CATCH(set_format_parms(&arg->fmt_parms, zft_hseg_buf),); - TRACE_EXIT 0; - case FTFMT_GET_PARMS: - TRACE_CATCH(get_format_parms(&arg->fmt_parms, zft_hseg_buf),); - TRACE_EXIT 0; - case FTFMT_FORMAT_TRACK: - if ((ft_formatted && zft_check_write_access(&zft_pos) < 0) || - (!ft_formatted && zft_write_protected)) { - TRACE_ABORT(-EACCES, ft_t_info, "Write access denied"); - } - TRACE_CATCH(ftape_format_track(arg->fmt_track.ft_track, - arg->fmt_track.ft_gap3),); - TRACE_EXIT 0; - case FTFMT_STATUS: - TRACE_CATCH(ftape_format_status(&arg->fmt_status.ft_segment),); - TRACE_EXIT 0; - case FTFMT_VERIFY: - TRACE_CATCH(ftape_verify_segment(arg->fmt_verify.ft_segment, - (SectorMap *)&arg->fmt_verify.ft_bsm),); - TRACE_EXIT 0; - default: - TRACE_ABORT(-EINVAL, ft_t_err, "Invalid format operation"); - } - TRACE_EXIT result; -} -#endif - -#ifdef MTIOCFTCMD -/* - * send a QIC-117 command to the drive, with optional timeouts, - * parameter and result bits. This is intended to be used together - * with the formatting ioctl. - */ -static int mtiocftcmd(struct mtftcmd *ftcmd, int arg_size) -{ - int i; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTCMD"); - if (!capable(CAP_SYS_ADMIN)) { - TRACE_ABORT(-EPERM, ft_t_info, - "need CAP_SYS_ADMIN capability to send raw qic-117 commands"); - } - if (zft_qic_mode) { - TRACE_ABORT(-EACCES, ft_t_info, - "driver needs to be in raw mode for this ioctl"); - } - if (arg_size != sizeof(struct mtftcmd)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (ftcmd->ft_wait_before) { - TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_before, - &ftcmd->ft_status),); - } - if (ftcmd->ft_status & QIC_STATUS_ERROR) - goto ftmtcmd_error; - if (ftcmd->ft_result_bits != 0) { - TRACE_CATCH(ftape_report_operation(&ftcmd->ft_result, - ftcmd->ft_cmd, - ftcmd->ft_result_bits),); - } else { - TRACE_CATCH(ftape_command(ftcmd->ft_cmd),); - if (ftcmd->ft_status & QIC_STATUS_ERROR) - goto ftmtcmd_error; - for (i = 0; i < ftcmd->ft_parm_cnt; i++) { - TRACE_CATCH(ftape_parameter(ftcmd->ft_parms[i]&0x0f),); - if (ftcmd->ft_status & QIC_STATUS_ERROR) - goto ftmtcmd_error; - } - } - if (ftcmd->ft_wait_after != 0) { - TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_after, - &ftcmd->ft_status),); - } -ftmtcmd_error: - if (ftcmd->ft_status & QIC_STATUS_ERROR) { - TRACE(ft_t_noise, "error status set"); - TRACE_CATCH(ftape_report_error(&ftcmd->ft_error, - &ftcmd->ft_cmd, 1),); - } - TRACE_EXIT 0; /* this is not an i/o error */ -} -#endif - -/* IOCTL routine called by kernel-interface code - */ -int _zft_ioctl(unsigned int command, void __user * arg) -{ - int result; - union { struct mtop mtop; - struct mtget mtget; - struct mtpos mtpos; -#ifdef MTIOCRDFTSEG - struct mtftseg mtftseg; -#endif -#ifdef MTIOCVOLINFO - struct mtvolinfo mtvolinfo; -#endif -#ifdef MTIOCGETSIZE - struct mttapesize mttapesize; -#endif -#ifdef MTIOCFTFORMAT - struct mtftformat mtftformat; -#endif -#ifdef ZFT_OBSOLETE - struct mtblksz mtblksz; -#endif -#ifdef MTIOCFTCMD - struct mtftcmd mtftcmd; -#endif - } krnl_arg; - int arg_size = _IOC_SIZE(command); - int dir = _IOC_DIR(command); - TRACE_FUN(ft_t_flow); - - /* This check will only catch arguments that are too large ! - */ - if (dir & (_IOC_READ | _IOC_WRITE) && arg_size > sizeof(krnl_arg)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (dir & _IOC_WRITE) { - if (copy_from_user(&krnl_arg, arg, arg_size) != 0) { - TRACE_EXIT -EFAULT; - } - } - TRACE(ft_t_flow, "called with ioctl command: 0x%08x", command); - switch (command) { - case MTIOCTOP: - result = mtioctop(&krnl_arg.mtop, arg_size); - break; - case MTIOCGET: - result = mtiocget(&krnl_arg.mtget, arg_size); - break; - case MTIOCPOS: - result = mtiocpos(&krnl_arg.mtpos, arg_size); - break; -#ifdef MTIOCVOLINFO - case MTIOCVOLINFO: - result = mtiocvolinfo(&krnl_arg.mtvolinfo, arg_size); - break; -#endif -#ifdef ZFT_OBSOLETE - case MTIOC_ZFTAPE_GETBLKSZ: - result = mtioc_zftape_getblksz(&krnl_arg.mtblksz, arg_size); - break; -#endif -#ifdef MTIOCRDFTSEG - case MTIOCRDFTSEG: /* read a segment via ioctl */ - result = mtiocrdftseg(&krnl_arg.mtftseg, arg_size); - break; -#endif -#ifdef MTIOCWRFTSEG - case MTIOCWRFTSEG: /* write a segment via ioctl */ - result = mtiocwrftseg(&krnl_arg.mtftseg, arg_size); - break; -#endif -#ifdef MTIOCGETSIZE - case MTIOCGETSIZE: - result = mtiocgetsize(&krnl_arg.mttapesize, arg_size); - break; -#endif -#ifdef MTIOCFTFORMAT - case MTIOCFTFORMAT: - result = mtiocftformat(&krnl_arg.mtftformat, arg_size); - break; -#endif -#ifdef MTIOCFTCMD - case MTIOCFTCMD: - result = mtiocftcmd(&krnl_arg.mtftcmd, arg_size); - break; -#endif - default: - result = -EINVAL; - break; - } - if ((result >= 0) && (dir & _IOC_READ)) { - if (copy_to_user(arg, &krnl_arg, arg_size) != 0) { - TRACE_EXIT -EFAULT; - } - } - TRACE_EXIT result; -} diff --git a/drivers/char/ftape/zftape/zftape-ctl.h b/drivers/char/ftape/zftape/zftape-ctl.h deleted file mode 100644 index 8e6f2d7ac74e..000000000000 --- a/drivers/char/ftape/zftape/zftape-ctl.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _ZFTAPE_CTL_H -#define _ZFTAPE_CTL_H - -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-ctl.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:02 $ - * - * This file contains the non-standard IOCTL related definitions - * for the QIC-40/80 floppy-tape driver for Linux. - */ - -#include -#include - -#include "../zftape/zftape-rw.h" - -#ifdef CONFIG_ZFTAPE_MODULE -#define ftape_status (*zft_status) -#endif - -extern int zft_offline; -extern int zft_mt_compression; -extern int zft_write_protected; -extern int zft_header_read; -extern unsigned int zft_unit; -extern int zft_resid; - -extern void zft_reset_position(zft_position *pos); -extern int zft_check_write_access(zft_position *pos); -extern int zft_def_idle_state(void); - -/* hooks for the VFS interface - */ -extern int _zft_open(unsigned int dev_minor, unsigned int access_mode); -extern int _zft_close(void); -extern int _zft_ioctl(unsigned int command, void __user *arg); -#endif - - - diff --git a/drivers/char/ftape/zftape/zftape-eof.c b/drivers/char/ftape/zftape/zftape-eof.c deleted file mode 100644 index dcadcaee9ac1..000000000000 --- a/drivers/char/ftape/zftape/zftape-eof.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * I use these routines just to decide when I have to fake a - * volume-table to preserve compatibility to original ftape. - */ -/* - * Copyright (C) 1994-1995 Bas Laarhoven. - * - * Modified for zftape 1996, 1997 Claus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:02 $ - * - * This file contains the eof mark handling code - * for the QIC-40/80 floppy-tape driver for Linux. - */ - -#include -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-eof.h" - -/* Global vars. - */ - -/* a copy of the failed sector log from the header segment. - */ -eof_mark_union *zft_eof_map; - -/* number of eof marks (entries in bad sector log) on tape. - */ -int zft_nr_eof_marks = -1; - - -/* Local vars. - */ - -static char linux_tape_label[] = "Linux raw format V"; -enum { - min_fmt_version = 1, max_fmt_version = 2 -}; -static unsigned ftape_fmt_version = 0; - - -/* Ftape (mis)uses the bad sector log to record end-of-file marks. - * Initially (when the tape is erased) all entries in the bad sector - * log are added to the tape's bad sector map. The bad sector log then - * is cleared. - * - * The bad sector log normally contains entries of the form: - * even 16-bit word: segment number of bad sector - * odd 16-bit word: encoded date - * There can be a total of 448 entries (1792 bytes). - * - * My guess is that no program is using this bad sector log (the * - * format seems useless as there is no indication of the bad sector - * itself, only the segment) However, if any program does use the bad - * sector log, the format used by ftape will let the program think - * there are some bad sectors and no harm is done. - * - * The eof mark entries that ftape stores in the bad sector log: even - * 16-bit word: segment number of eof mark odd 16-bit word: sector - * number of eof mark [1..32] - * - * The zft_eof_map as maintained is a sorted list of eof mark entries. - * - * - * The tape name field in the header segments is used to store a linux - * tape identification string and a version number. This way the tape - * can be recognized as a Linux raw format tape when using tools under - * other OS's. - * - * 'Wide' QIC tapes (format code 4) don't have a failed sector list - * anymore. That space is used for the (longer) bad sector map that - * now is a variable length list too. We now store our end-of-file - * marker list after the bad-sector-map on tape. The list is delimited - * by a (__u32) 0 entry. - */ - -int zft_ftape_validate_label(char *label) -{ - static char tmp_label[45]; - int result = 0; - TRACE_FUN(ft_t_any); - - memcpy(tmp_label, label, FT_LABEL_SZ); - tmp_label[FT_LABEL_SZ] = '\0'; - TRACE(ft_t_noise, "tape label = `%s'", tmp_label); - ftape_fmt_version = 0; - if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) { - int pos = strlen(linux_tape_label); - while (label[pos] >= '0' && label[pos] <= '9') { - ftape_fmt_version *= 10; - ftape_fmt_version = label[ pos++] - '0'; - } - result = (ftape_fmt_version >= min_fmt_version && - ftape_fmt_version <= max_fmt_version); - } - TRACE(ft_t_noise, "format version = %d", ftape_fmt_version); - TRACE_EXIT result; -} - -static __u8 * find_end_of_eof_list(__u8 * ptr, __u8 * limit) -{ - while (ptr + 3 < limit) { - - if (get_unaligned((__u32*)ptr)) { - ptr += sizeof(__u32); - } else { - return ptr; - } - } - return NULL; -} - -void zft_ftape_extract_file_marks(__u8* address) -{ - int i; - TRACE_FUN(ft_t_any); - - zft_eof_map = NULL; - if (ft_format_code == fmt_var || ft_format_code == fmt_big) { - __u8* end; - __u8* start = ftape_find_end_of_bsm_list(address); - - zft_nr_eof_marks = 0; - if (start) { - start += 3; /* skip end of list mark */ - end = find_end_of_eof_list(start, - address + FT_SEGMENT_SIZE); - if (end && end - start <= FT_FSL_SIZE) { - zft_nr_eof_marks = ((end - start) / - sizeof(eof_mark_union)); - zft_eof_map = (eof_mark_union *)start; - } else { - TRACE(ft_t_err, - "EOF Mark List is too long or damaged!"); - } - } else { - TRACE(ft_t_err, - "Bad Sector List is too long or damaged !"); - } - } else { - zft_eof_map = (eof_mark_union *)&address[FT_FSL]; - zft_nr_eof_marks = GET2(address, FT_FSL_CNT); - } - TRACE(ft_t_noise, "number of file marks: %d", zft_nr_eof_marks); - if (ftape_fmt_version == 1) { - TRACE(ft_t_info, "swapping version 1 fields"); - /* version 1 format uses swapped sector and segment - * fields, correct that ! - */ - for (i = 0; i < zft_nr_eof_marks; ++i) { - __u16 tmp = GET2(&zft_eof_map[i].mark.segment,0); - PUT2(&zft_eof_map[i].mark.segment, 0, - GET2(&zft_eof_map[i].mark.date,0)); - PUT2(&zft_eof_map[i].mark.date, 0, tmp); - } - } - for (i = 0; i < zft_nr_eof_marks; ++i) { - TRACE(ft_t_noise, "eof mark: %5d/%2d", - GET2(&zft_eof_map[i].mark.segment, 0), - GET2(&zft_eof_map[i].mark.date,0)); - } - TRACE_EXIT; -} - -void zft_clear_ftape_file_marks(void) -{ - TRACE_FUN(ft_t_flow); - /* Clear failed sector log: remove all tape marks. We - * don't use old ftape-style EOF-marks. - */ - TRACE(ft_t_info, "Clearing old ftape's eof map"); - memset(zft_eof_map, 0, zft_nr_eof_marks * sizeof(__u32)); - zft_nr_eof_marks = 0; - PUT2(zft_hseg_buf, FT_FSL_CNT, 0); /* nr of eof-marks */ - zft_header_changed = 1; - zft_update_label(zft_hseg_buf); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/zftape/zftape-eof.h b/drivers/char/ftape/zftape/zftape-eof.h deleted file mode 100644 index 26568c26c518..000000000000 --- a/drivers/char/ftape/zftape/zftape-eof.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef _ZFTAPE_EOF_H -#define _ZFTAPE_EOF_H - -/* - * Copyright (C) 1994-1995 Bas Laarhoven. - * adaptaed for zftape 1996, 1997 by Claus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:03 $ - * - * Definitions and declarations for the end of file markers - * for the QIC-40/80 floppy-tape driver for Linux. - */ - -#include -#include "../zftape/zftape-buffers.h" -/* failed sector log size (only used if format code != 4). - */ - -typedef union { - ft_fsl_entry mark; - __u32 entry; -} eof_mark_union; - -/* ftape-eof.c defined global vars. - */ -extern int zft_nr_eof_marks; -extern eof_mark_union *zft_eof_map; - -/* ftape-eof.c defined global functions. - */ -extern void zft_ftape_extract_file_marks(__u8* address); -extern int zft_ftape_validate_label(char* label); -extern void zft_clear_ftape_file_marks(void); - -#endif diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c deleted file mode 100644 index 164a1aa77a2f..000000000000 --- a/drivers/char/ftape/zftape/zftape-init.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * This file contains the code that registers the zftape frontend - * to the ftape floppy tape driver for Linux - */ - -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_KMOD -#include -#endif -#include -#include - -#include -#include -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-buffers.h" - -MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine " - "(claus@momo.math.rwth-aachen.de)"); -MODULE_DESCRIPTION(ZFTAPE_VERSION " - " - "VFS interface for the Linux floppy tape driver. " - "Support for QIC-113 compatible volume table " - "and builtin compression (lzrw3 algorithm)"); -MODULE_SUPPORTED_DEVICE("char-major-27"); -MODULE_LICENSE("GPL"); - -/* Global vars. - */ -struct zft_cmpr_ops *zft_cmpr_ops = NULL; -const ftape_info *zft_status; - -/* Local vars. - */ -static unsigned long busy_flag; - -static sigset_t orig_sigmask; - -/* the interface to the kernel vfs layer - */ - -/* Note about llseek(): - * - * st.c and tpqic.c update fp->f_pos but don't implment llseek() and - * initialize the llseek component of the file_ops struct with NULL. - * This means that the user will get the default seek, but the tape - * device will not respect the new position, but happily read from the - * old position. Think a zftape specific llseek() function would be - * better, returning -ESPIPE. TODO. - */ - -static int zft_open (struct inode *ino, struct file *filep); -static int zft_close(struct inode *ino, struct file *filep); -static int zft_ioctl(struct inode *ino, struct file *filep, - unsigned int command, unsigned long arg); -static int zft_mmap(struct file *filep, struct vm_area_struct *vma); -static ssize_t zft_read (struct file *fp, char __user *buff, - size_t req_len, loff_t *ppos); -static ssize_t zft_write(struct file *fp, const char __user *buff, - size_t req_len, loff_t *ppos); - -static const struct file_operations zft_cdev = -{ - .owner = THIS_MODULE, - .read = zft_read, - .write = zft_write, - .ioctl = zft_ioctl, - .mmap = zft_mmap, - .open = zft_open, - .release = zft_close, -}; - -static struct class *zft_class; - -/* Open floppy tape device - */ -static int zft_open(struct inode *ino, struct file *filep) -{ - int result; - TRACE_FUN(ft_t_flow); - - nonseekable_open(ino, filep); - TRACE(ft_t_flow, "called for minor %d", iminor(ino)); - if ( test_and_set_bit(0,&busy_flag) ) { - TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy"); - } - if ((iminor(ino) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND)) - > - FTAPE_SEL_D) { - clear_bit(0,&busy_flag); - TRACE_ABORT(-ENXIO, ft_t_err, "failed: invalid unit nr"); - } - orig_sigmask = current->blocked; - sigfillset(¤t->blocked); - result = _zft_open(iminor(ino), filep->f_flags & O_ACCMODE); - if (result < 0) { - current->blocked = orig_sigmask; /* restore mask */ - clear_bit(0,&busy_flag); - TRACE_ABORT(result, ft_t_err, "_ftape_open failed"); - } else { - /* Mask signals that will disturb proper operation of the - * program that is calling. - */ - current->blocked = orig_sigmask; - sigaddsetmask (¤t->blocked, _DO_BLOCK); - TRACE_EXIT 0; - } -} - -/* Close floppy tape device - */ -static int zft_close(struct inode *ino, struct file *filep) -{ - int result; - TRACE_FUN(ft_t_flow); - - if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit) { - TRACE(ft_t_err, "failed: not busy or wrong unit"); - TRACE_EXIT 0; - } - sigfillset(¤t->blocked); - result = _zft_close(); - if (result < 0) { - TRACE(ft_t_err, "_zft_close failed"); - } - current->blocked = orig_sigmask; /* restore before open state */ - clear_bit(0,&busy_flag); - TRACE_EXIT 0; -} - -/* Ioctl for floppy tape device - */ -static int zft_ioctl(struct inode *ino, struct file *filep, - unsigned int command, unsigned long arg) -{ - int result = -EIO; - sigset_t old_sigmask; - TRACE_FUN(ft_t_flow); - - if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - /* This will work as long as sizeof(void *) == sizeof(long) */ - result = _zft_ioctl(command, (void __user *) arg); - current->blocked = old_sigmask; /* restore mask */ - TRACE_EXIT result; -} - -/* Ioctl for floppy tape device - */ -static int zft_mmap(struct file *filep, struct vm_area_struct *vma) -{ - int result = -EIO; - sigset_t old_sigmask; - TRACE_FUN(ft_t_flow); - - if ( !test_bit(0,&busy_flag) || - iminor(filep->f_dentry->d_inode) != zft_unit || - ft_failure) - { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - if ((result = ftape_mmap(vma)) >= 0) { -#ifndef MSYNC_BUG_WAS_FIXED - static struct vm_operations_struct dummy = { NULL, }; - vma->vm_ops = &dummy; -#endif - } - current->blocked = old_sigmask; /* restore mask */ - TRACE_EXIT result; -} - -/* Read from floppy tape device - */ -static ssize_t zft_read(struct file *fp, char __user *buff, - size_t req_len, loff_t *ppos) -{ - int result = -EIO; - sigset_t old_sigmask; - struct inode *ino = fp->f_dentry->d_inode; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len); - if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - result = _zft_read(buff, req_len); - current->blocked = old_sigmask; /* restore mask */ - TRACE(ft_t_data_flow, "return with count: %d", result); - TRACE_EXIT result; -} - -/* Write to tape device - */ -static ssize_t zft_write(struct file *fp, const char __user *buff, - size_t req_len, loff_t *ppos) -{ - int result = -EIO; - sigset_t old_sigmask; - struct inode *ino = fp->f_dentry->d_inode; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len); - if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - result = _zft_write(buff, req_len); - current->blocked = old_sigmask; /* restore mask */ - TRACE(ft_t_data_flow, "return with count: %d", result); - TRACE_EXIT result; -} - -/* END OF VFS INTERFACE - * - *****************************************************************************/ - -/* driver/module initialization - */ - -/* the compression module has to call this function to hook into the zftape - * code - */ -int zft_cmpr_register(struct zft_cmpr_ops *new_ops) -{ - TRACE_FUN(ft_t_flow); - - if (zft_cmpr_ops != NULL) { - TRACE_EXIT -EBUSY; - } else { - zft_cmpr_ops = new_ops; - TRACE_EXIT 0; - } -} - -/* lock the zft-compressor() module. - */ -int zft_cmpr_lock(int try_to_load) -{ - if (zft_cmpr_ops == NULL) { -#ifdef CONFIG_KMOD - if (try_to_load) { - request_module("zft-compressor"); - if (zft_cmpr_ops == NULL) { - return -ENOSYS; - } - } else { - return -ENOSYS; - } -#else - return -ENOSYS; -#endif - } - (*zft_cmpr_ops->lock)(); - return 0; -} - -#ifdef CONFIG_ZFT_COMPRESSOR -extern int zft_compressor_init(void); -#endif - -/* Called by modules package when installing the driver or by kernel - * during the initialization phase - */ -int __init zft_init(void) -{ - int i; - TRACE_FUN(ft_t_flow); - -#ifdef MODULE - printk(KERN_INFO ZFTAPE_VERSION "\n"); - if (TRACE_LEVEL >= ft_t_info) { - printk( -KERN_INFO -"(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" -KERN_INFO -"vfs interface for ftape floppy tape driver.\n" -KERN_INFO -"Support for QIC-113 compatible volume table, dynamic memory allocation\n" -KERN_INFO -"and builtin compression (lzrw3 algorithm).\n"); - } -#else /* !MODULE */ - /* print a short no-nonsense boot message */ - printk(KERN_INFO ZFTAPE_VERSION "\n"); -#endif /* MODULE */ - TRACE(ft_t_info, "zft_init @ 0x%p", zft_init); - TRACE(ft_t_info, - "installing zftape VFS interface for ftape driver ..."); - TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); - - zft_class = class_create(THIS_MODULE, "zft"); - for (i = 0; i < 4; i++) { - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); - } - -#ifdef CONFIG_ZFT_COMPRESSOR - (void)zft_compressor_init(); -#endif - zft_status = ftape_get_status(); /* fetch global data of ftape - * hardware driver - */ - TRACE_EXIT 0; -} - - -/* Called by modules package when removing the driver - */ -static void zft_exit(void) -{ - int i; - TRACE_FUN(ft_t_flow); - - if (unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) { - TRACE(ft_t_warn, "failed"); - } else { - TRACE(ft_t_info, "successful"); - } - for (i = 0; i < 4; i++) { - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36)); - } - class_destroy(zft_class); - zft_uninit_mem(); /* release remaining memory, if any */ - printk(KERN_INFO "zftape successfully unloaded.\n"); - TRACE_EXIT; -} - -module_init(zft_init); -module_exit(zft_exit); diff --git a/drivers/char/ftape/zftape/zftape-init.h b/drivers/char/ftape/zftape/zftape-init.h deleted file mode 100644 index 937e5d48c20e..000000000000 --- a/drivers/char/ftape/zftape/zftape-init.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _ZFTAPE_INIT_H -#define _ZFTAPE_INIT_H - -/* - * Copyright (C) 1996, 1997 Claus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-init.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:05 $ - * - * This file contains definitions and macro for the vfs - * interface defined by zftape - * - */ - -#include - -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-bsm.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-buffer.h" -#include "../lowlevel/ftape-format.h" - -#include "../zftape/zftape-rw.h" - -#ifdef MODULE -#define ftape_status (*zft_status) -#endif - -extern const ftape_info *zft_status; /* needed for zftape-vtbl.h */ - -#include "../zftape/zftape-vtbl.h" - -struct zft_cmpr_ops { - int (*write)(int *write_cnt, - __u8 *dst_buf, const int seg_sz, - const __u8 __user *src_buf, const int req_len, - const zft_position *pos, const zft_volinfo *volume); - int (*read)(int *read_cnt, - __u8 __user *dst_buf, const int req_len, - const __u8 *src_buf, const int seg_sz, - const zft_position *pos, const zft_volinfo *volume); - int (*seek)(unsigned int new_block_pos, - zft_position *pos, const zft_volinfo *volume, - __u8 *buffer); - void (*lock) (void); - void (*reset) (void); - void (*cleanup)(void); -}; - -extern struct zft_cmpr_ops *zft_cmpr_ops; -/* zftape-init.c defined global functions. - */ -extern int zft_cmpr_register(struct zft_cmpr_ops *new_ops); -extern int zft_cmpr_lock(int try_to_load); - -#endif - - diff --git a/drivers/char/ftape/zftape/zftape-read.c b/drivers/char/ftape/zftape/zftape-read.c deleted file mode 100644 index 214bf03dce68..000000000000 --- a/drivers/char/ftape/zftape/zftape-read.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-read.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:06 $ - * - * This file contains the high level reading code - * for the QIC-117 floppy-tape driver for Linux. - */ - -#include -#include - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -/* Global vars. - */ -int zft_just_before_eof; - -/* Local vars. - */ -static int buf_len_rd; - -void zft_zap_read_buffers(void) -{ - buf_len_rd = 0; -} - -int zft_read_header_segments(void) -{ - TRACE_FUN(ft_t_flow); - - zft_header_read = 0; - TRACE_CATCH(zft_vmalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); - TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),); - TRACE(ft_t_info, "Segments written since first format: %d", - (int)GET4(zft_hseg_buf, FT_SEG_CNT)); - zft_qic113 = (ft_format_code != fmt_normal && - ft_format_code != fmt_1100ft && - ft_format_code != fmt_425ft); - TRACE(ft_t_info, "ft_first_data_segment: %d, ft_last_data_segment: %d", - ft_first_data_segment, ft_last_data_segment); - zft_capacity = zft_get_capacity(); - zft_old_ftape = zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]); - if (zft_old_ftape) { - TRACE(ft_t_info, -"Found old ftaped tape, emulating eof marks, entering read-only mode"); - zft_ftape_extract_file_marks(zft_hseg_buf); - TRACE_CATCH(zft_fake_volume_headers(zft_eof_map, - zft_nr_eof_marks),); - } else { - /* the specs say that the volume table must be - * initialized with zeroes during formatting, so it - * MUST be readable, i.e. contain vaid ECC - * information. - */ - TRACE_CATCH(ftape_read_segment(ft_first_data_segment, - zft_deblock_buf, - FT_RD_SINGLE),); - TRACE_CATCH(zft_extract_volume_headers(zft_deblock_buf),); - } - zft_header_read = 1; - zft_set_flags(zft_unit); - zft_reset_position(&zft_pos); - TRACE_EXIT 0; -} - -int zft_fetch_segment_fraction(const unsigned int segment, void *buffer, - const ft_read_mode_t read_mode, - const unsigned int start, - const unsigned int size) -{ - int seg_sz; - TRACE_FUN(ft_t_flow); - - if (segment == zft_deblock_segment) { - TRACE(ft_t_data_flow, - "re-using segment %d already in deblock buffer", - segment); - seg_sz = zft_get_seg_sz(segment); - if (start > seg_sz) { - TRACE_ABORT(-EINVAL, ft_t_bug, - "trying to read beyond end of segment:\n" - KERN_INFO "seg_sz : %d\n" - KERN_INFO "start : %d\n" - KERN_INFO "segment: %d", - seg_sz, start, segment); - } - if ((start + size) > seg_sz) { - TRACE_EXIT seg_sz - start; - } - TRACE_EXIT size; - } - seg_sz = ftape_read_segment_fraction(segment, buffer, read_mode, - start, size); - TRACE(ft_t_data_flow, "segment %d, result %d", segment, seg_sz); - if ((int)seg_sz >= 0 && start == 0 && size == FT_SEGMENT_SIZE) { - /* this implicitly assumes that we are always called with - * buffer == zft_deblock_buf - */ - zft_deblock_segment = segment; - } else { - zft_deblock_segment = -1; - } - TRACE_EXIT seg_sz; -} - -/* - * out: - * - * int *read_cnt: the number of bytes we removed from the - * zft_deblock_buf (result) - * - * int *to_do : the remaining size of the read-request. Is changed. - * - * in: - * - * char *buff : buff is the address of the upper part of the user - * buffer, that hasn't been filled with data yet. - * int buf_pos_read: copy of buf_pos_rd - * int buf_len_read: copy of buf_len_rd - * char *zft_deblock_buf: ftape_zft_deblock_buf - * - * returns the amount of data actually copied to the user-buffer - * - * to_do MUST NOT SHRINK except to indicate an EOT. In this case to_do - * has to be set to 0. We cannot return -ENOSPC, because we return the - * amount of data actually * copied to the user-buffer - */ -static int zft_simple_read (int *read_cnt, - __u8 __user *dst_buf, - const int to_do, - const __u8 *src_buf, - const int seg_sz, - const zft_position *pos, - const zft_volinfo *volume) -{ - TRACE_FUN(ft_t_flow); - - if (seg_sz - pos->seg_byte_pos < to_do) { - *read_cnt = seg_sz - pos->seg_byte_pos; - } else { - *read_cnt = to_do; - } - if (copy_to_user(dst_buf, - src_buf + pos->seg_byte_pos, *read_cnt) != 0) { - TRACE_EXIT -EFAULT; - } - TRACE(ft_t_noise, "nr bytes just read: %d", *read_cnt); - TRACE_EXIT *read_cnt; -} - -/* req_len: gets clipped due to EOT of EOF. - * req_clipped: is a flag indicating whether req_len was clipped or not - * volume: contains information on current volume (blk_sz etc.) - */ -static int check_read_access(int *req_len, - const zft_volinfo **volume, - int *req_clipped, - const zft_position *pos) -{ - static __s64 remaining; - static int eod; - TRACE_FUN(ft_t_flow); - - if (zft_io_state != zft_reading) { - if (zft_offline) { /* offline includes no_tape */ - TRACE_ABORT(-ENXIO, ft_t_warn, - "tape is offline or no cartridge"); - } - if (!ft_formatted) { - TRACE_ABORT(-EACCES, - ft_t_warn, "tape is not formatted"); - } - /* now enter defined state, read header segment if not - * already done and flush write buffers - */ - TRACE_CATCH(zft_def_idle_state(),); - zft_io_state = zft_reading; - if (zft_tape_at_eod(pos)) { - eod = 1; - TRACE_EXIT 1; - } - eod = 0; - *volume = zft_find_volume(pos->seg_pos); - /* get the space left until EOF */ - remaining = zft_check_for_eof(*volume, pos); - buf_len_rd = 0; - TRACE(ft_t_noise, "remaining: " LL_X ", vol_no: %d", - LL(remaining), (*volume)->count); - } else if (zft_tape_at_eod(pos)) { - if (++eod > 2) { - TRACE_EXIT -EIO; /* st.c also returns -EIO */ - } else { - TRACE_EXIT 1; - } - } - if ((*req_len % (*volume)->blk_sz) != 0) { - /* this message is informational only. The user gets the - * proper return value - */ - TRACE_ABORT(-EINVAL, ft_t_info, - "req_len %d not a multiple of block size %d", - *req_len, (*volume)->blk_sz); - } - /* As GNU tar doesn't accept partial read counts when the - * multiple volume flag is set, we make sure to return the - * requested amount of data. Except, of course, at the end of - * the tape or file mark. - */ - remaining -= *req_len; - if (remaining <= 0) { - TRACE(ft_t_noise, - "clipped request from %d to %d.", - *req_len, (int)(*req_len + remaining)); - *req_len += remaining; - *req_clipped = 1; - } else { - *req_clipped = 0; - } - TRACE_EXIT 0; -} - -/* this_segs_size: the current segment's size. - * buff: the USER-SPACE buffer provided by the calling function. - * req_len: how much data should be read at most. - * volume: contains information on current volume (blk_sz etc.) - */ -static int empty_deblock_buf(__u8 __user *usr_buf, const int req_len, - const __u8 *src_buf, const int seg_sz, - zft_position *pos, - const zft_volinfo *volume) -{ - int cnt; - int result = 0; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_data_flow, "this_segs_size: %d", seg_sz); - if (zft_use_compression && volume->use_compression) { - TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); - TRACE_CATCH(result= (*zft_cmpr_ops->read)(&cnt, - usr_buf, req_len, - src_buf, seg_sz, - pos, volume),); - } else { - TRACE_CATCH(result= zft_simple_read (&cnt, - usr_buf, req_len, - src_buf, seg_sz, - pos, volume),); - } - pos->volume_pos += result; - pos->tape_pos += cnt; - pos->seg_byte_pos += cnt; - buf_len_rd -= cnt; /* remaining bytes in buffer */ - TRACE(ft_t_data_flow, "buf_len_rd: %d, cnt: %d", buf_len_rd, cnt); - if(pos->seg_byte_pos >= seg_sz) { - pos->seg_pos++; - pos->seg_byte_pos = 0; - } - TRACE(ft_t_data_flow, "bytes moved out of deblock-buffer: %d", cnt); - TRACE_EXIT result; -} - - -/* note: we store the segment id of the segment that is inside the - * deblock buffer. This spares a lot of ftape_read_segment()s when we - * use small block-sizes. The block-size may be 1kb (SECTOR_SIZE). In - * this case a MTFSR 28 maybe still inside the same segment. - */ -int _zft_read(char __user *buff, int req_len) -{ - int req_clipped; - int result = 0; - int bytes_read = 0; - static unsigned int seg_sz = 0; - static const zft_volinfo *volume = NULL; - TRACE_FUN(ft_t_flow); - - zft_resid = req_len; - result = check_read_access(&req_len, &volume, - &req_clipped, &zft_pos); - switch(result) { - case 0: - break; /* nothing special */ - case 1: - TRACE(ft_t_noise, "EOD reached"); - TRACE_EXIT 0; /* EOD */ - default: - TRACE_ABORT(result, ft_t_noise, - "check_read_access() failed with result %d", - result); - TRACE_EXIT result; - } - while (req_len > 0) { - /* Allow escape from this loop on signal ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - /* buf_len_rd == 0 means that we need to read a new - * segment. - */ - if (buf_len_rd == 0) { - while((result = zft_fetch_segment(zft_pos.seg_pos, - zft_deblock_buf, - FT_RD_AHEAD)) == 0) { - zft_pos.seg_pos ++; - zft_pos.seg_byte_pos = 0; - } - if (result < 0) { - zft_resid -= bytes_read; - TRACE_ABORT(result, ft_t_noise, - "zft_fetch_segment(): %d", - result); - } - seg_sz = result; - buf_len_rd = seg_sz - zft_pos.seg_byte_pos; - } - TRACE_CATCH(result = empty_deblock_buf(buff, - req_len, - zft_deblock_buf, - seg_sz, - &zft_pos, - volume), - zft_resid -= bytes_read); - TRACE(ft_t_data_flow, "bytes just read: %d", result); - bytes_read += result; /* what we got so far */ - buff += result; /* index in user-buffer */ - req_len -= result; /* what's left from req_len */ - } /* while (req_len > 0) */ - if (req_clipped) { - TRACE(ft_t_data_flow, - "maybe partial count because of eof mark"); - if (zft_just_before_eof && bytes_read == 0) { - /* req_len was > 0, but user didn't get - * anything the user has read in the eof-mark - */ - zft_move_past_eof(&zft_pos); - ftape_abort_operation(); - } else { - /* don't skip to the next file before the user - * tried to read a second time past EOF Just - * mark that we are at EOF and maybe decrement - * zft_seg_pos to stay in the same volume; - */ - zft_just_before_eof = 1; - zft_position_before_eof(&zft_pos, volume); - TRACE(ft_t_noise, "just before eof"); - } - } - zft_resid -= result; /* for MTSTATUS */ - TRACE_EXIT bytes_read; -} diff --git a/drivers/char/ftape/zftape/zftape-read.h b/drivers/char/ftape/zftape/zftape-read.h deleted file mode 100644 index 42941de0c23a..000000000000 --- a/drivers/char/ftape/zftape/zftape-read.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _ZFTAPE_READ_H -#define _ZFTAPE_READ_H - -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-read.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:07 $ - * - * This file contains the definitions for the read functions - * for the zftape driver for Linux. - * - */ - -#include "../lowlevel/ftape-read.h" - -/* ftape-read.c defined global vars. - */ -extern int zft_just_before_eof; - -/* ftape-read.c defined global functions. - */ -extern void zft_zap_read_buffers(void); -extern int zft_read_header_segments(void); -extern int zft_fetch_segment_fraction(const unsigned int segment, - void *buffer, - const ft_read_mode_t read_mode, - const unsigned int start, - const unsigned int size); -#define zft_fetch_segment(segment, address, read_mode) \ - zft_fetch_segment_fraction(segment, address, read_mode, \ - 0, FT_SEGMENT_SIZE) -/* hook for the VFS interface - */ -extern int _zft_read(char __user *buff, int req_len); - -#endif /* _ZFTAPE_READ_H */ diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c deleted file mode 100644 index dab634686885..000000000000 --- a/drivers/char/ftape/zftape/zftape-rw.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-rw.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:08 $ - * - * This file contains some common code for the r/w code for - * zftape. - */ - -#include -#include - -#include -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -/* Global vars. - */ - -__u8 *zft_deblock_buf; -__u8 *zft_hseg_buf; -int zft_deblock_segment = -1; -zft_status_enum zft_io_state = zft_idle; -int zft_header_changed; -int zft_qic113; /* conform to old specs. and old zftape */ -int zft_use_compression; -zft_position zft_pos = { - -1, /* seg_pos */ - 0, /* seg_byte_pos */ - 0, /* tape_pos */ - 0 /* volume_pos */ -}; -unsigned int zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; -__s64 zft_capacity; - -unsigned int zft_written_segments; -int zft_label_changed; - -/* Local vars. - */ - -unsigned int zft_get_seg_sz(unsigned int segment) -{ - int size; - TRACE_FUN(ft_t_any); - - size = FT_SEGMENT_SIZE - - count_ones(ftape_get_bad_sector_entry(segment))*FT_SECTOR_SIZE; - if (size > 0) { - TRACE_EXIT (unsigned)size; - } else { - TRACE_EXIT 0; - } -} - -/* ftape_set_flags(). Claus-Justus Heine, 1994/1995 - */ -void zft_set_flags(unsigned minor_unit) -{ - TRACE_FUN(ft_t_flow); - - zft_use_compression = zft_qic_mode = 0; - switch (minor_unit & ZFT_MINOR_OP_MASK) { - case (ZFT_Q80_MODE | ZFT_ZIP_MODE): - case ZFT_ZIP_MODE: - zft_use_compression = 1; - case 0: - case ZFT_Q80_MODE: - zft_qic_mode = 1; - if (zft_mt_compression) { /* override the default */ - zft_use_compression = 1; - } - break; - case ZFT_RAW_MODE: - TRACE(ft_t_noise, "switching to raw mode"); - break; - default: - TRACE(ft_t_warn, "Warning:\n" - KERN_INFO "Wrong combination of minor device bits.\n" - KERN_INFO "Switching to raw read-only mode."); - zft_write_protected = 1; - break; - } - TRACE_EXIT; -} - -/* computes the segment and byte offset inside the segment - * corresponding to tape_pos. - * - * tape_pos gives the offset in bytes from the beginning of the - * ft_first_data_segment *seg_byte_pos is the offset in the current - * segment in bytes - * - * Of, if this routine was called often one should cache the last data - * pos it was called with, but actually this is only needed in - * ftape_seek_block(), that is, almost never. - */ -int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos) -{ - int segment; - int seg_sz; - TRACE_FUN(ft_t_flow); - - if (tape_pos == 0) { - *seg_byte_pos = 0; - segment = ft_first_data_segment; - } else { - seg_sz = 0; - - for (segment = ft_first_data_segment; - ((tape_pos > 0) && (segment <= ft_last_data_segment)); - segment++) { - seg_sz = zft_get_seg_sz(segment); - tape_pos -= seg_sz; - } - if(tape_pos >= 0) { - /* the case tape_pos > != 0 means that the - * argument tape_pos lies beyond the EOT. - */ - *seg_byte_pos= 0; - } else { /* tape_pos < 0 */ - segment--; - *seg_byte_pos= tape_pos + seg_sz; - } - } - TRACE_EXIT(segment); -} - -/* ftape_calc_tape_pos(). - * - * computes the offset in bytes from the beginning of the - * ft_first_data_segment inverse to ftape_calc_seg_byte_coord - * - * We should do some caching. But how: - * - * Each time the header segments are read in, this routine is called - * with ft_tracks_per_tape*segments_per_track argumnet. So this should be - * the time to reset the cache. - * - * Also, it might be in the future that the bad sector map gets - * changed. -> reset the cache - */ -static int seg_pos; -static __s64 tape_pos; - -__s64 zft_get_capacity(void) -{ - seg_pos = ft_first_data_segment; - tape_pos = 0; - - while (seg_pos <= ft_last_data_segment) { - tape_pos += zft_get_seg_sz(seg_pos ++); - } - return tape_pos; -} - -__s64 zft_calc_tape_pos(int segment) -{ - int d1, d2, d3; - TRACE_FUN(ft_t_any); - - if (segment > ft_last_data_segment) { - TRACE_EXIT zft_capacity; - } - if (segment < ft_first_data_segment) { - TRACE_EXIT 0; - } - d2 = segment - seg_pos; - if (-d2 > 10) { - d1 = segment - ft_first_data_segment; - if (-d2 > d1) { - tape_pos = 0; - seg_pos = ft_first_data_segment; - d2 = d1; - } - } - if (d2 > 10) { - d3 = ft_last_data_segment - segment; - if (d2 > d3) { - tape_pos = zft_capacity; - seg_pos = ft_last_data_segment + 1; - d2 = -d3; - } - } - if (d2 > 0) { - while (seg_pos < segment) { - tape_pos += zft_get_seg_sz(seg_pos++); - } - } else { - while (seg_pos > segment) { - tape_pos -= zft_get_seg_sz(--seg_pos); - } - } - TRACE(ft_t_noise, "new cached pos: %d", seg_pos); - - TRACE_EXIT tape_pos; -} - -/* copy Z-label string to buffer, keeps track of the correct offset in - * `buffer' - */ -void zft_update_label(__u8 *buffer) -{ - TRACE_FUN(ft_t_flow); - - if (strncmp(&buffer[FT_LABEL], ZFTAPE_LABEL, - sizeof(ZFTAPE_LABEL)-1) != 0) { - TRACE(ft_t_info, "updating label from \"%s\" to \"%s\"", - &buffer[FT_LABEL], ZFTAPE_LABEL); - strcpy(&buffer[FT_LABEL], ZFTAPE_LABEL); - memset(&buffer[FT_LABEL] + sizeof(ZFTAPE_LABEL) - 1, ' ', - FT_LABEL_SZ - sizeof(ZFTAPE_LABEL + 1)); - PUT4(buffer, FT_LABEL_DATE, 0); - zft_label_changed = zft_header_changed = 1; /* changed */ - } - TRACE_EXIT; -} - -int zft_verify_write_segments(unsigned int segment, - __u8 *data, size_t size, - __u8 *buffer) -{ - int result; - __u8 *write_buf; - __u8 *src_buf; - int single; - int seg_pos; - int seg_sz; - int remaining; - ft_write_mode_t write_mode; - TRACE_FUN(ft_t_flow); - - seg_pos = segment; - seg_sz = zft_get_seg_sz(seg_pos); - src_buf = data; - single = size <= seg_sz; - remaining = size; - do { - TRACE(ft_t_noise, "\n" - KERN_INFO "remaining: %d\n" - KERN_INFO "seg_sz : %d\n" - KERN_INFO "segment : %d", - remaining, seg_sz, seg_pos); - if (remaining == seg_sz) { - write_buf = src_buf; - write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI; - remaining = 0; - } else if (remaining > seg_sz) { - write_buf = src_buf; - write_mode = FT_WR_ASYNC; /* don't start tape */ - remaining -= seg_sz; - } else { /* remaining < seg_sz */ - write_buf = buffer; - memcpy(write_buf, src_buf, remaining); - memset(&write_buf[remaining],'\0',seg_sz-remaining); - write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI; - remaining = 0; - } - if ((result = ftape_write_segment(seg_pos, - write_buf, - write_mode)) != seg_sz) { - TRACE(ft_t_err, "Error: " - "Couldn't write segment %d", seg_pos); - TRACE_EXIT result < 0 ? result : -EIO; /* bail out */ - } - zft_written_segments ++; - seg_sz = zft_get_seg_sz(++seg_pos); - src_buf += result; - } while (remaining > 0); - if (ftape_get_status()->fti_state == writing) { - TRACE_CATCH(ftape_loop_until_writes_done(),); - TRACE_CATCH(ftape_abort_operation(),); - zft_prevent_flush(); - } - seg_pos = segment; - src_buf = data; - remaining = size; - do { - TRACE_CATCH(result = ftape_read_segment(seg_pos, buffer, - single ? FT_RD_SINGLE - : FT_RD_AHEAD),); - if (memcmp(src_buf, buffer, - remaining > result ? result : remaining) != 0) { - TRACE_ABORT(-EIO, ft_t_err, - "Failed to verify written segment %d", - seg_pos); - } - remaining -= result; - TRACE(ft_t_noise, "verify successful:\n" - KERN_INFO "segment : %d\n" - KERN_INFO "segsize : %d\n" - KERN_INFO "remaining: %d", - seg_pos, result, remaining); - src_buf += seg_sz; - seg_pos++; - } while (remaining > 0); - TRACE_EXIT size; -} - - -/* zft_erase(). implemented compression-handling - * - * calculate the first data-segment when using/not using compression. - * - * update header-segment and compression-map-segment. - */ -int zft_erase(void) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (!zft_header_read) { - TRACE_CATCH(zft_vmalloc_once((void **)&zft_hseg_buf, - FT_SEGMENT_SIZE),); - /* no need to read the vtbl and compression map */ - TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),); - if ((zft_old_ftape = - zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]))) { - zft_ftape_extract_file_marks(zft_hseg_buf); - } - TRACE(ft_t_noise, - "ft_first_data_segment: %d, ft_last_data_segment: %d", - ft_first_data_segment, ft_last_data_segment); - zft_qic113 = (ft_format_code != fmt_normal && - ft_format_code != fmt_1100ft && - ft_format_code != fmt_425ft); - } - if (zft_old_ftape) { - zft_clear_ftape_file_marks(); - zft_old_ftape = 0; /* no longer old ftape */ - } - PUT2(zft_hseg_buf, FT_CMAP_START, 0); - zft_volume_table_changed = 1; - zft_capacity = zft_get_capacity(); - zft_init_vtbl(); - /* the rest must be done in ftape_update_header_segments - */ - zft_header_read = 1; - zft_header_changed = 1; /* force update of timestamp */ - result = zft_update_header_segments(); - - ftape_abort_operation(); - - zft_reset_position(&zft_pos); - zft_set_flags (zft_unit); - TRACE_EXIT result; -} - -unsigned int zft_get_time(void) -{ - unsigned int date = FT_TIME_STAMP(2097, 11, 30, 23, 59, 59); /* fun */ - return date; -} diff --git a/drivers/char/ftape/zftape/zftape-rw.h b/drivers/char/ftape/zftape/zftape-rw.h deleted file mode 100644 index 1ceec22b60bd..000000000000 --- a/drivers/char/ftape/zftape/zftape-rw.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef _ZFTAPE_RW_H -#define _ZFTAPE_RW_H - -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-rw.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:09 $ - * - * This file contains the definitions for the read and write - * functions for the QIC-117 floppy-tape driver for Linux. - * - */ - -#include "../zftape/zftape-buffers.h" - -#define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape) - -/* QIC-113 Rev. G says that `a maximum of 63488 raw bytes may be - * compressed into a single frame'. - * Maybe we should stick to 32kb to make it more `beautiful' - */ -#define ZFT_MAX_BLK_SZ (62*1024) /* bytes */ -#if !defined(CONFIG_ZFT_DFLT_BLK_SZ) -# define CONFIG_ZFT_DFLT_BLK_SZ (10*1024) /* bytes, default of gnu tar */ -#elif CONFIG_ZFT_DFLT_BLK_SZ == 0 -# undef CONFIG_ZFT_DFLT_BLK_SZ -# define CONFIG_ZFT_DFLT_BLK_SZ 1 -#elif (CONFIG_ZFT_DFLT_BLK_SZ % 1024) != 0 -# error CONFIG_ZFT_DFLT_BLK_SZ must be 1 or a multiple of 1024 -#endif -/* The *optional* compression routines need some overhead per tape - * block for their purposes. Instead of asking the actual compression - * implementation how much it needs, we restrict this overhead to be - * maximal of ZFT_CMPT_OVERHEAD size. We need this for EOT - * conditions. The tape is assumed to be logical at EOT when the - * distance from the physical EOT is less than - * one tape block + ZFT_CMPR_OVERHEAD - */ -#define ZFT_CMPR_OVERHEAD 16 /* bytes */ - -typedef enum -{ - zft_idle = 0, - zft_reading, - zft_writing, -} zft_status_enum; - -typedef struct /* all values measured in bytes */ -{ - int seg_pos; /* segment currently positioned at */ - int seg_byte_pos; /* offset in current segment */ - __s64 tape_pos; /* real offset from BOT */ - __s64 volume_pos; /* pos. in uncompressed data stream in - * current volume - */ -} zft_position; - -extern zft_position zft_pos; -extern __u8 *zft_deblock_buf; -extern __u8 *zft_hseg_buf; -extern int zft_deblock_segment; -extern zft_status_enum zft_io_state; -extern int zft_header_changed; -extern int zft_qic113; /* conform to old specs. and old zftape */ -extern int zft_use_compression; -extern unsigned int zft_blk_sz; -extern __s64 zft_capacity; -extern unsigned int zft_written_segments; -extern int zft_label_changed; - -/* zftape-rw.c exported functions - */ -extern unsigned int zft_get_seg_sz(unsigned int segment); -extern void zft_set_flags(unsigned int minor_unit); -extern int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos); -extern __s64 zft_calc_tape_pos(int segment); -extern __s64 zft_get_capacity(void); -extern void zft_update_label(__u8 *buffer); -extern int zft_erase(void); -extern int zft_verify_write_segments(unsigned int segment, - __u8 *data, size_t size, __u8 *buffer); -extern unsigned int zft_get_time(void); -#endif /* _ZFTAPE_RW_H */ - diff --git a/drivers/char/ftape/zftape/zftape-vtbl.c b/drivers/char/ftape/zftape/zftape-vtbl.c deleted file mode 100644 index ad7f8be6340b..000000000000 --- a/drivers/char/ftape/zftape/zftape-vtbl.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Copyright (c) 1995-1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.c,v $ - * $Revision: 1.7.6.1 $ - * $Date: 1997/11/24 13:48:31 $ - * - * This file defines a volume table as defined in various QIC - * standards. - * - * This is a minimal implementation, just allowing ordinary DOS - * :( prgrams to identify the cartridge as used. - */ - -#include -#include -#include - -#include -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -#define ZFT_CMAP_HACK /* leave this defined to hide the compression map */ - -/* - * global variables - */ -int zft_qic_mode = 1; /* use the vtbl */ -int zft_old_ftape; /* prevents old ftaped tapes to be overwritten */ -int zft_volume_table_changed; /* for write_header_segments() */ - -/* - * private variables (only exported for inline functions) - */ -LIST_HEAD(zft_vtbl); - -/* We could also allocate these dynamically when extracting the volume table - * sizeof(zft_volinfo) is about 32 or something close to that - */ -static zft_volinfo tape_vtbl; -static zft_volinfo eot_vtbl; -static zft_volinfo *cur_vtbl; - -static inline void zft_new_vtbl_entry(void) -{ - struct list_head *tmp = &zft_last_vtbl->node; - zft_volinfo *new = zft_kmalloc(sizeof(zft_volinfo)); - - list_add(&new->node, tmp); - new->count = zft_eom_vtbl->count ++; -} - -void zft_free_vtbl(void) -{ - for (;;) { - struct list_head *tmp = zft_vtbl.prev; - zft_volinfo *vtbl; - - if (tmp == &zft_vtbl) - break; - list_del(tmp); - vtbl = list_entry(tmp, zft_volinfo, node); - zft_kfree(vtbl, sizeof(zft_volinfo)); - } - INIT_LIST_HEAD(&zft_vtbl); - cur_vtbl = NULL; -} - -/* initialize vtbl, called by ftape_new_cartridge() - */ -void zft_init_vtbl(void) -{ - zft_volinfo *new; - - zft_free_vtbl(); - - /* Create the two dummy vtbl entries - */ - new = zft_kmalloc(sizeof(zft_volinfo)); - list_add(&new->node, &zft_vtbl); - new = zft_kmalloc(sizeof(zft_volinfo)); - list_add(&new->node, &zft_vtbl); - zft_head_vtbl->end_seg = ft_first_data_segment; - zft_head_vtbl->blk_sz = zft_blk_sz; - zft_head_vtbl->count = -1; - zft_eom_vtbl->start_seg = ft_first_data_segment + 1; - zft_eom_vtbl->end_seg = ft_last_data_segment + 1; - zft_eom_vtbl->blk_sz = zft_blk_sz; - zft_eom_vtbl->count = 0; - - /* Reset the pointer for zft_find_volume() - */ - cur_vtbl = zft_eom_vtbl; - - /* initialize the dummy vtbl entries for zft_qic_mode == 0 - */ - eot_vtbl.start_seg = ft_last_data_segment + 1; - eot_vtbl.end_seg = ft_last_data_segment + 1; - eot_vtbl.blk_sz = zft_blk_sz; - eot_vtbl.count = -1; - tape_vtbl.start_seg = ft_first_data_segment; - tape_vtbl.end_seg = ft_last_data_segment; - tape_vtbl.blk_sz = zft_blk_sz; - tape_vtbl.size = zft_capacity; - tape_vtbl.count = 0; -} - -/* check for a valid VTBL signature. - */ -static int vtbl_signature_valid(__u8 signature[4]) -{ - const char *vtbl_ids[] = VTBL_IDS; /* valid signatures */ - int j; - - for (j = 0; - (j < NR_ITEMS(vtbl_ids)) && (memcmp(signature, vtbl_ids[j], 4) != 0); - j++); - return j < NR_ITEMS(vtbl_ids); -} - -/* We used to store the block-size of the volume in the volume-label, - * using the keyword "blocksize". The blocksize written to the - * volume-label is in bytes. - * - * We use this now only for compatibility with old zftape version. We - * store the blocksize directly as binary number in the vendor - * extension part of the volume entry. - */ -static int check_volume_label(const char *label, int *blk_sz) -{ - int valid_format; - char *blocksize; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "called with \"%s\" / \"%s\"", label, ZFT_VOL_NAME); - if (strncmp(label, ZFT_VOL_NAME, strlen(ZFT_VOL_NAME)) != 0) { - *blk_sz = 1; /* smallest block size that we allow */ - valid_format = 0; - } else { - TRACE(ft_t_noise, "got old style zftape vtbl entry"); - /* get the default blocksize */ - /* use the kernel strstr() */ - blocksize= strstr(label, " blocksize "); - if (blocksize) { - blocksize += strlen(" blocksize "); - for(*blk_sz= 0; - *blocksize >= '0' && *blocksize <= '9'; - blocksize++) { - *blk_sz *= 10; - *blk_sz += *blocksize - '0'; - } - if (*blk_sz > ZFT_MAX_BLK_SZ) { - *blk_sz= 1; - valid_format= 0; - } else { - valid_format = 1; - } - } else { - *blk_sz= 1; - valid_format= 0; - } - } - TRACE_EXIT valid_format; -} - -/* check for a zftape volume - */ -static int check_volume(__u8 *entry, zft_volinfo *volume) -{ - TRACE_FUN(ft_t_flow); - - if(strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, - strlen(ZFTAPE_SIG)) == 0) { - TRACE(ft_t_noise, "got new style zftape vtbl entry"); - volume->blk_sz = GET2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ); - volume->qic113 = entry[VTBL_EXT+EXT_ZFTAPE_QIC113]; - TRACE_EXIT 1; - } else { - TRACE_EXIT check_volume_label(&entry[VTBL_DESC], &volume->blk_sz); - } -} - - -/* create zftape specific vtbl entry, the volume bounds are inserted - * in the calling function, zft_create_volume_headers() - */ -static void create_zft_volume(__u8 *entry, zft_volinfo *vtbl) -{ - TRACE_FUN(ft_t_flow); - - memset(entry, 0, VTBL_SIZE); - memcpy(&entry[VTBL_SIG], VTBL_ID, 4); - sprintf(&entry[VTBL_DESC], ZFT_VOL_NAME" %03d", vtbl->count); - entry[VTBL_FLAGS] = (VTBL_FL_NOT_VERIFIED | VTBL_FL_SEG_SPANNING); - entry[VTBL_M_NO] = 1; /* multi_cartridge_count */ - strcpy(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG); - PUT2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ, vtbl->blk_sz); - if (zft_qic113) { - PUT8(entry, VTBL_DATA_SIZE, vtbl->size); - entry[VTBL_CMPR] = VTBL_CMPR_UNREG; - if (vtbl->use_compression) { /* use compression: */ - entry[VTBL_CMPR] |= VTBL_CMPR_USED; - } - entry[VTBL_EXT+EXT_ZFTAPE_QIC113] = 1; - } else { - PUT4(entry, VTBL_DATA_SIZE, vtbl->size); - entry[VTBL_K_CMPR] = VTBL_CMPR_UNREG; - if (vtbl->use_compression) { /* use compression: */ - entry[VTBL_K_CMPR] |= VTBL_CMPR_USED; - } - } - if (ft_format_code == fmt_big) { - /* SCSI like vtbl, store the number of used - * segments as 4 byte value - */ - PUT4(entry, VTBL_SCSI_SEGS, vtbl->end_seg-vtbl->start_seg + 1); - } else { - /* normal, QIC-80MC like vtbl - */ - PUT2(entry, VTBL_START, vtbl->start_seg); - PUT2(entry, VTBL_END, vtbl->end_seg); - } - TRACE_EXIT; -} - -/* this one creates the volume headers for each volume. It is assumed - * that buffer already contains the old volume-table, so that vtbl - * entries without the zft_volume flag set can savely be ignored. - */ -static void zft_create_volume_headers(__u8 *buffer) -{ - __u8 *entry; - struct list_head *tmp; - zft_volinfo *vtbl; - TRACE_FUN(ft_t_flow); - -#ifdef ZFT_CMAP_HACK - if((strncmp(&buffer[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, - strlen(ZFTAPE_SIG)) == 0) && - buffer[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { - TRACE(ft_t_noise, "deleting cmap volume"); - memmove(buffer, buffer + VTBL_SIZE, - FT_SEGMENT_SIZE - VTBL_SIZE); - } -#endif - entry = buffer; - for (tmp = zft_head_vtbl->node.next; - tmp != &zft_eom_vtbl->node; - tmp = tmp->next) { - vtbl = list_entry(tmp, zft_volinfo, node); - /* we now fill in the values only for newly created volumes. - */ - if (vtbl->new_volume) { - create_zft_volume(entry, vtbl); - vtbl->new_volume = 0; /* clear the flag */ - } - - DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], vtbl); - entry += VTBL_SIZE; - } - memset(entry, 0, FT_SEGMENT_SIZE - zft_eom_vtbl->count * VTBL_SIZE); - TRACE_EXIT; -} - -/* write volume table to tape. Calls zft_create_volume_headers() - */ -int zft_update_volume_table(unsigned int segment) -{ - int result = 0; - __u8 *verify_buf = NULL; - TRACE_FUN(ft_t_flow); - - TRACE_CATCH(result = ftape_read_segment(ft_first_data_segment, - zft_deblock_buf, - FT_RD_SINGLE),); - zft_create_volume_headers(zft_deblock_buf); - TRACE(ft_t_noise, "writing volume table segment %d", segment); - if (zft_vmalloc_once(&verify_buf, FT_SEGMENT_SIZE) == 0) { - TRACE_CATCH(zft_verify_write_segments(segment, - zft_deblock_buf, result, - verify_buf), - zft_vfree(&verify_buf, FT_SEGMENT_SIZE)); - zft_vfree(&verify_buf, FT_SEGMENT_SIZE); - } else { - TRACE_CATCH(ftape_write_segment(segment, zft_deblock_buf, - FT_WR_SINGLE),); - } - TRACE_EXIT 0; -} - -/* non zftape volumes are handled in raw mode. Thus we need to - * calculate the raw amount of data contained in those segments. - */ -static void extract_alien_volume(__u8 *entry, zft_volinfo *vtbl) -{ - TRACE_FUN(ft_t_flow); - - vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) - - zft_calc_tape_pos(zft_last_vtbl->start_seg)); - vtbl->use_compression = 0; - vtbl->qic113 = zft_qic113; - if (vtbl->qic113) { - TRACE(ft_t_noise, - "Fake alien volume's size from " LL_X " to " LL_X, - LL(GET8(entry, VTBL_DATA_SIZE)), LL(vtbl->size)); - } else { - TRACE(ft_t_noise, - "Fake alien volume's size from %d to " LL_X, - (int)GET4(entry, VTBL_DATA_SIZE), LL(vtbl->size)); - } - TRACE_EXIT; -} - - -/* extract an zftape specific volume - */ -static void extract_zft_volume(__u8 *entry, zft_volinfo *vtbl) -{ - TRACE_FUN(ft_t_flow); - - if (vtbl->qic113) { - vtbl->size = GET8(entry, VTBL_DATA_SIZE); - vtbl->use_compression = - (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; - } else { - vtbl->size = GET4(entry, VTBL_DATA_SIZE); - if (entry[VTBL_K_CMPR] & VTBL_CMPR_UNREG) { - vtbl->use_compression = - (entry[VTBL_K_CMPR] & VTBL_CMPR_USED) != 0; - } else if (entry[VTBL_CMPR] & VTBL_CMPR_UNREG) { - vtbl->use_compression = - (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; - } else { - TRACE(ft_t_warn, "Geeh! There is something wrong:\n" - KERN_INFO "QIC compression (Rev = K): %x\n" - KERN_INFO "QIC compression (Rev > K): %x", - entry[VTBL_K_CMPR], entry[VTBL_CMPR]); - } - } - TRACE_EXIT; -} - -/* extract the volume table from buffer. "buffer" must already contain - * the vtbl-segment - */ -int zft_extract_volume_headers(__u8 *buffer) -{ - __u8 *entry; - TRACE_FUN(ft_t_flow); - - zft_init_vtbl(); - entry = buffer; -#ifdef ZFT_CMAP_HACK - if ((strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, - strlen(ZFTAPE_SIG)) == 0) && - entry[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { - TRACE(ft_t_noise, "ignoring cmap volume"); - entry += VTBL_SIZE; - } -#endif - /* the end of the vtbl is indicated by an invalid signature - */ - while (vtbl_signature_valid(&entry[VTBL_SIG]) && - (entry - buffer) < FT_SEGMENT_SIZE) { - zft_new_vtbl_entry(); - if (ft_format_code == fmt_big) { - /* SCSI like vtbl, stores only the number of - * segments used - */ - unsigned int num_segments= GET4(entry, VTBL_SCSI_SEGS); - zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; - zft_last_vtbl->end_seg = - zft_last_vtbl->start_seg + num_segments - 1; - } else { - /* `normal', QIC-80 like vtbl - */ - zft_last_vtbl->start_seg = GET2(entry, VTBL_START); - zft_last_vtbl->end_seg = GET2(entry, VTBL_END); - } - zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1; - /* check if we created this volume and get the - * blk_sz - */ - zft_last_vtbl->zft_volume = check_volume(entry, zft_last_vtbl); - if (zft_last_vtbl->zft_volume == 0) { - extract_alien_volume(entry, zft_last_vtbl); - } else { - extract_zft_volume(entry, zft_last_vtbl); - } - DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], zft_last_vtbl); - entry +=VTBL_SIZE; - } -#if 0 -/* - * undefine to test end of tape handling - */ - zft_new_vtbl_entry(); - zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; - zft_last_vtbl->end_seg = ft_last_data_segment - 10; - zft_last_vtbl->blk_sz = zft_blk_sz; - zft_last_vtbl->zft_volume = 1; - zft_last_vtbl->qic113 = zft_qic113; - zft_last_vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) - - zft_calc_tape_pos(zft_last_vtbl->start_seg)); -#endif - TRACE_EXIT 0; -} - -/* this functions translates the failed_sector_log, misused as - * EOF-marker list, into a virtual volume table. The table mustn't be - * written to tape, because this would occupy the first data segment, - * which should be the volume table, but is actually the first segment - * that is filled with data (when using standard ftape). We assume, - * that we get a non-empty failed_sector_log. - */ -int zft_fake_volume_headers (eof_mark_union *eof_map, int num_failed_sectors) -{ - unsigned int segment, sector; - int have_eom = 0; - int vol_no; - TRACE_FUN(ft_t_flow); - - if ((num_failed_sectors >= 2) && - (GET2(&eof_map[num_failed_sectors - 1].mark.segment, 0) - == - GET2(&eof_map[num_failed_sectors - 2].mark.segment, 0) + 1) && - (GET2(&eof_map[num_failed_sectors - 1].mark.date, 0) == 1)) { - /* this should be eom. We keep the remainder of the - * tape as another volume. - */ - have_eom = 1; - } - zft_init_vtbl(); - zft_eom_vtbl->start_seg = ft_first_data_segment; - for(vol_no = 0; vol_no < num_failed_sectors - have_eom; vol_no ++) { - zft_new_vtbl_entry(); - - segment = GET2(&eof_map[vol_no].mark.segment, 0); - sector = GET2(&eof_map[vol_no].mark.date, 0); - - zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; - zft_last_vtbl->end_seg = segment; - zft_eom_vtbl->start_seg = segment + 1; - zft_last_vtbl->blk_sz = 1; - zft_last_vtbl->size = - (zft_calc_tape_pos(zft_last_vtbl->end_seg) - - zft_calc_tape_pos(zft_last_vtbl->start_seg) - + (sector-1) * FT_SECTOR_SIZE); - TRACE(ft_t_noise, - "failed sector log: segment: %d, sector: %d", - segment, sector); - DUMP_VOLINFO(ft_t_noise, "Faked volume", zft_last_vtbl); - } - if (!have_eom) { - zft_new_vtbl_entry(); - zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; - zft_last_vtbl->end_seg = ft_last_data_segment; - zft_eom_vtbl->start_seg = ft_last_data_segment + 1; - zft_last_vtbl->size = zft_capacity; - zft_last_vtbl->size -= zft_calc_tape_pos(zft_last_vtbl->start_seg); - zft_last_vtbl->blk_sz = 1; - DUMP_VOLINFO(ft_t_noise, "Faked volume",zft_last_vtbl); - } - TRACE_EXIT 0; -} - -/* update the internal volume table - * - * if before start of last volume: erase all following volumes if - * inside a volume: set end of volume to infinity - * - * this function is intended to be called every time _ftape_write() is - * called - * - * return: 0 if no new volume was created, 1 if a new volume was - * created - * - * NOTE: we don't need to check for zft_mode as ftape_write() does - * that already. This function gets never called without accessing - * zftape via the *qft* devices - */ - -int zft_open_volume(zft_position *pos, int blk_sz, int use_compression) -{ - TRACE_FUN(ft_t_flow); - - if (!zft_qic_mode) { - TRACE_EXIT 0; - } - if (zft_tape_at_lbot(pos)) { - zft_init_vtbl(); - if(zft_old_ftape) { - /* clear old ftape's eof marks */ - zft_clear_ftape_file_marks(); - zft_old_ftape = 0; /* no longer old ftape */ - } - zft_reset_position(pos); - } - if (pos->seg_pos != zft_last_vtbl->end_seg + 1) { - TRACE_ABORT(-EIO, ft_t_bug, - "BUG: seg_pos: %d, zft_last_vtbl->end_seg: %d", - pos->seg_pos, zft_last_vtbl->end_seg); - } - TRACE(ft_t_noise, "create new volume"); - if (zft_eom_vtbl->count >= ZFT_MAX_VOLUMES) { - TRACE_ABORT(-ENOSPC, ft_t_err, - "Error: maxmimal number of volumes exhausted " - "(maxmimum is %d)", ZFT_MAX_VOLUMES); - } - zft_new_vtbl_entry(); - pos->volume_pos = pos->seg_byte_pos = 0; - zft_last_vtbl->start_seg = pos->seg_pos; - zft_last_vtbl->end_seg = ft_last_data_segment; /* infinity */ - zft_last_vtbl->blk_sz = blk_sz; - zft_last_vtbl->size = zft_capacity; - zft_last_vtbl->zft_volume = 1; - zft_last_vtbl->use_compression = use_compression; - zft_last_vtbl->qic113 = zft_qic113; - zft_last_vtbl->new_volume = 1; - zft_last_vtbl->open = 1; - zft_volume_table_changed = 1; - zft_eom_vtbl->start_seg = ft_last_data_segment + 1; - TRACE_EXIT 0; -} - -/* perform mtfsf, mtbsf, not allowed without zft_qic_mode - */ -int zft_skip_volumes(int count, zft_position *pos) -{ - const zft_volinfo *vtbl; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "count: %d", count); - - vtbl= zft_find_volume(pos->seg_pos); - while (count > 0 && vtbl != zft_eom_vtbl) { - vtbl = list_entry(vtbl->node.next, zft_volinfo, node); - count --; - } - while (count < 0 && vtbl != zft_first_vtbl) { - vtbl = list_entry(vtbl->node.prev, zft_volinfo, node); - count ++; - } - pos->seg_pos = vtbl->start_seg; - pos->seg_byte_pos = 0; - pos->volume_pos = 0; - pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); - zft_just_before_eof = vtbl->size == 0; - if (zft_cmpr_ops) { - (*zft_cmpr_ops->reset)(); - } - zft_deblock_segment = -1; /* no need to keep cache */ - TRACE(ft_t_noise, "repositioning to:\n" - KERN_INFO "zft_seg_pos : %d\n" - KERN_INFO "zft_seg_byte_pos : %d\n" - KERN_INFO "zft_tape_pos : " LL_X "\n" - KERN_INFO "zft_volume_pos : " LL_X "\n" - KERN_INFO "file number : %d", - pos->seg_pos, pos->seg_byte_pos, - LL(pos->tape_pos), LL(pos->volume_pos), vtbl->count); - zft_resid = count < 0 ? -count : count; - TRACE_EXIT zft_resid ? -EINVAL : 0; -} - -/* the following simply returns the raw data position of the EOM - * marker, MTIOCSIZE ioctl - */ -__s64 zft_get_eom_pos(void) -{ - if (zft_qic_mode) { - return zft_calc_tape_pos(zft_eom_vtbl->start_seg); - } else { - /* there is only one volume in raw mode */ - return zft_capacity; - } -} - -/* skip to eom, used for MTEOM - */ -void zft_skip_to_eom(zft_position *pos) -{ - TRACE_FUN(ft_t_flow); - pos->seg_pos = zft_eom_vtbl->start_seg; - pos->seg_byte_pos = - pos->volume_pos = - zft_just_before_eof = 0; - pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); - TRACE(ft_t_noise, "ftape positioned to segment %d, data pos " LL_X, - pos->seg_pos, LL(pos->tape_pos)); - TRACE_EXIT; -} - -/* write an EOF-marker by setting zft_last_vtbl->end_seg to seg_pos. - * NOTE: this function assumes that zft_last_vtbl points to a valid - * vtbl entry - * - * NOTE: this routine always positions before the EOF marker - */ -int zft_close_volume(zft_position *pos) -{ - TRACE_FUN(ft_t_any); - - if (zft_vtbl_empty || !zft_last_vtbl->open) { /* should not happen */ - TRACE(ft_t_noise, "There are no volumes to finish"); - TRACE_EXIT -EIO; - } - if (pos->seg_byte_pos == 0 && - pos->seg_pos != zft_last_vtbl->start_seg) { - pos->seg_pos --; - pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos); - } - zft_last_vtbl->end_seg = pos->seg_pos; - zft_last_vtbl->size = pos->volume_pos; - zft_volume_table_changed = 1; - zft_just_before_eof = 1; - zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1; - zft_last_vtbl->open = 0; /* closed */ - TRACE_EXIT 0; -} - -/* write count file-marks at current position. - * - * The tape is positioned after the eof-marker, that is at byte 0 of - * the segment following the eof-marker - * - * this function is only allowed in zft_qic_mode - * - * Only allowed when tape is at BOT or EOD. - */ -int zft_weof(unsigned int count, zft_position *pos) -{ - - TRACE_FUN(ft_t_flow); - - if (!count) { /* write zero EOF marks should be a real no-op */ - TRACE_EXIT 0; - } - zft_volume_table_changed = 1; - if (zft_tape_at_lbot(pos)) { - zft_init_vtbl(); - if(zft_old_ftape) { - /* clear old ftape's eof marks */ - zft_clear_ftape_file_marks(); - zft_old_ftape = 0; /* no longer old ftape */ - } - } - if (zft_last_vtbl->open) { - zft_close_volume(pos); - zft_move_past_eof(pos); - count --; - } - /* now it's easy, just append eof-marks, that is empty - * volumes, to the end of the already recorded media. - */ - while (count > 0 && - pos->seg_pos <= ft_last_data_segment && - zft_eom_vtbl->count < ZFT_MAX_VOLUMES) { - TRACE(ft_t_noise, - "Writing zero sized file at segment %d", pos->seg_pos); - zft_new_vtbl_entry(); - zft_last_vtbl->start_seg = pos->seg_pos; - zft_last_vtbl->end_seg = pos->seg_pos; - zft_last_vtbl->size = 0; - zft_last_vtbl->blk_sz = zft_blk_sz; - zft_last_vtbl->zft_volume = 1; - zft_last_vtbl->use_compression = 0; - pos->tape_pos += zft_get_seg_sz(pos->seg_pos); - zft_eom_vtbl->start_seg = ++ pos->seg_pos; - count --; - } - if (count > 0) { - /* there are two possibilities: end of tape, or the - * maximum number of files is exhausted. - */ - zft_resid = count; - TRACE(ft_t_noise,"Number of marks NOT written: %d", zft_resid); - if (zft_eom_vtbl->count == ZFT_MAX_VOLUMES) { - TRACE_ABORT(-EINVAL, ft_t_warn, - "maximum allowed number of files " - "exhausted: %d", ZFT_MAX_VOLUMES); - } else { - TRACE_ABORT(-ENOSPC, - ft_t_noise, "reached end of tape"); - } - } - TRACE_EXIT 0; -} - -const zft_volinfo *zft_find_volume(unsigned int seg_pos) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_any, "called with seg_pos %d",seg_pos); - if (!zft_qic_mode) { - if (seg_pos > ft_last_data_segment) { - TRACE_EXIT &eot_vtbl; - } - tape_vtbl.blk_sz = zft_blk_sz; - TRACE_EXIT &tape_vtbl; - } - if (seg_pos < zft_first_vtbl->start_seg) { - TRACE_EXIT (cur_vtbl = zft_first_vtbl); - } - while (seg_pos > cur_vtbl->end_seg) { - cur_vtbl = list_entry(cur_vtbl->node.next, zft_volinfo, node); - TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg); - } - while (seg_pos < cur_vtbl->start_seg) { - cur_vtbl = list_entry(cur_vtbl->node.prev, zft_volinfo, node); - TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg); - } - if (seg_pos > cur_vtbl->end_seg || seg_pos < cur_vtbl->start_seg) { - TRACE(ft_t_bug, "This cannot happen"); - } - DUMP_VOLINFO(ft_t_noise, "", cur_vtbl); - TRACE_EXIT cur_vtbl; -} - -/* this function really assumes that we are just before eof - */ -void zft_move_past_eof(zft_position *pos) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "old seg. pos: %d", pos->seg_pos); - pos->tape_pos += zft_get_seg_sz(pos->seg_pos++) - pos->seg_byte_pos; - pos->seg_byte_pos = 0; - pos->volume_pos = 0; - if (zft_cmpr_ops) { - (*zft_cmpr_ops->reset)(); - } - zft_just_before_eof = 0; - zft_deblock_segment = -1; /* no need to cache it anymore */ - TRACE(ft_t_noise, "new seg. pos: %d", pos->seg_pos); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/zftape/zftape-vtbl.h b/drivers/char/ftape/zftape/zftape-vtbl.h deleted file mode 100644 index f31d196d1759..000000000000 --- a/drivers/char/ftape/zftape/zftape-vtbl.h +++ /dev/null @@ -1,227 +0,0 @@ -#ifndef _ZFTAPE_VTBL_H -#define _ZFTAPE_VTBL_H - -/* - * Copyright (c) 1995-1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.h,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/28 14:30:09 $ - * - * This file defines a volume table as defined in the QIC-80 - * development standards. - */ - -#include - -#include "../lowlevel/ftape-tracing.h" - -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-rw.h" - -#define VTBL_SIZE 128 /* bytes */ - -/* The following are offsets in the vtbl. */ -#define VTBL_SIG 0 -#define VTBL_START 4 -#define VTBL_END 6 -#define VTBL_DESC 8 -#define VTBL_DATE 52 -#define VTBL_FLAGS 56 -#define VTBL_FL_VENDOR_SPECIFIC (1<<0) -#define VTBL_FL_MUTLI_CARTRIDGE (1<<1) -#define VTBL_FL_NOT_VERIFIED (1<<2) -#define VTBL_FL_REDIR_INHIBIT (1<<3) -#define VTBL_FL_SEG_SPANNING (1<<4) -#define VTBL_FL_DIRECTORY_LAST (1<<5) -#define VTBL_FL_RESERVED_6 (1<<6) -#define VTBL_FL_RESERVED_7 (1<<7) -#define VTBL_M_NO 57 -#define VTBL_EXT 58 -#define EXT_ZFTAPE_SIG 0 -#define EXT_ZFTAPE_BLKSZ 10 -#define EXT_ZFTAPE_CMAP 12 -#define EXT_ZFTAPE_QIC113 13 -#define VTBL_PWD 84 -#define VTBL_DIR_SIZE 92 -#define VTBL_DATA_SIZE 96 -#define VTBL_OS_VERSION 104 -#define VTBL_SRC_DRIVE 106 -#define VTBL_DEV 122 -#define VTBL_RESERVED_1 123 -#define VTBL_CMPR 124 -#define VTBL_CMPR_UNREG 0x3f -#define VTBL_CMPR_USED 0x80 -#define VTBL_FMT 125 -#define VTBL_RESERVED_2 126 -#define VTBL_RESERVED_3 127 -/* compatibility with pre revision K */ -#define VTBL_K_CMPR 120 - -/* the next is used by QIC-3020 tapes with format code 6 (>2^16 - * segments) It is specified in QIC-113, Rev. G, Section 5 (SCSI - * volume table). The difference is simply, that we only store the - * number of segments used, not the starting segment. - */ -#define VTBL_SCSI_SEGS 4 /* is a 4 byte value */ - -/* one vtbl is 128 bytes, that results in a maximum number of - * 29*1024/128 = 232 volumes. - */ -#define ZFT_MAX_VOLUMES (FT_SEGMENT_SIZE/VTBL_SIZE) -#define VTBL_ID "VTBL" -#define VTBL_IDS { VTBL_ID, "XTBL", "UTID", "EXVT" } /* other valid ids */ -#define ZFT_VOL_NAME "zftape volume" /* volume label used by me */ -#define ZFTAPE_SIG "LINUX ZFT" - -/* global variables - */ -typedef struct zft_internal_vtbl -{ - struct list_head node; - int count; - unsigned int start_seg; /* 32 bits are enough for now */ - unsigned int end_seg; /* 32 bits are enough for now */ - __s64 size; /* uncompressed size */ - unsigned int blk_sz; /* block size for this volume */ - unsigned int zft_volume :1; /* zftape created this volume */ - unsigned int use_compression:1; /* compressed volume */ - unsigned int qic113 :1; /* layout of compressed block - * info and vtbl conforms to - * QIC-113, Rev. G - */ - unsigned int new_volume :1; /* it was created by us, this - * run. this allows the - * fields that aren't really - * used by zftape to be filled - * in by some user level - * program. - */ - unsigned int open :1; /* just in progress of being - * written - */ -} zft_volinfo; - -extern struct list_head zft_vtbl; -#define zft_head_vtbl list_entry(zft_vtbl.next, zft_volinfo, node) -#define zft_eom_vtbl list_entry(zft_vtbl.prev, zft_volinfo, node) -#define zft_last_vtbl list_entry(zft_eom_vtbl->node.prev, zft_volinfo, node) -#define zft_first_vtbl list_entry(zft_head_vtbl->node.next, zft_volinfo, node) -#define zft_vtbl_empty (zft_eom_vtbl->node.prev == &zft_head_vtbl->node) - -#define DUMP_VOLINFO(level, desc, info) \ -{ \ - char tmp[21]; \ - strlcpy(tmp, desc, sizeof(tmp)); \ - TRACE(level, "Volume %d:\n" \ - KERN_INFO "description : %s\n" \ - KERN_INFO "first segment: %d\n" \ - KERN_INFO "last segment: %d\n" \ - KERN_INFO "size : " LL_X "\n" \ - KERN_INFO "block size : %d\n" \ - KERN_INFO "compression : %d\n" \ - KERN_INFO "zftape volume: %d\n" \ - KERN_INFO "QIC-113 conf.: %d", \ - (info)->count, tmp, (info)->start_seg, (info)->end_seg, \ - LL((info)->size), (info)->blk_sz, \ - (info)->use_compression != 0, (info)->zft_volume != 0, \ - (info)->qic113 != 0); \ -} - -extern int zft_qic_mode; -extern int zft_old_ftape; -extern int zft_volume_table_changed; - -/* exported functions */ -extern void zft_init_vtbl (void); -extern void zft_free_vtbl (void); -extern int zft_extract_volume_headers(__u8 *buffer); -extern int zft_update_volume_table (unsigned int segment); -extern int zft_open_volume (zft_position *pos, - int blk_sz, int use_compression); -extern int zft_close_volume (zft_position *pos); -extern const zft_volinfo *zft_find_volume(unsigned int seg_pos); -extern int zft_skip_volumes (int count, zft_position *pos); -extern __s64 zft_get_eom_pos (void); -extern void zft_skip_to_eom (zft_position *pos); -extern int zft_fake_volume_headers (eof_mark_union *eof_map, - int num_failed_sectors); -extern int zft_weof (unsigned int count, zft_position *pos); -extern void zft_move_past_eof (zft_position *pos); - -static inline int zft_tape_at_eod (const zft_position *pos); -static inline int zft_tape_at_lbot (const zft_position *pos); -static inline void zft_position_before_eof (zft_position *pos, - const zft_volinfo *volume); -static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, - const zft_position *pos); - -/* this function decrements the zft_seg_pos counter if we are right - * at the beginning of a segment. This is to handle fsfm/bsfm -- we - * need to position before the eof mark. NOTE: zft_tape_pos is not - * changed - */ -static inline void zft_position_before_eof(zft_position *pos, - const zft_volinfo *volume) -{ - TRACE_FUN(ft_t_flow); - - if (pos->seg_pos == volume->end_seg + 1 && pos->seg_byte_pos == 0) { - pos->seg_pos --; - pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos); - } - TRACE_EXIT; -} - -/* Mmmh. Is the position at the end of the last volume, that is right - * before the last EOF mark also logical an EOD condition? - */ -static inline int zft_tape_at_eod(const zft_position *pos) -{ - TRACE_FUN(ft_t_any); - - if (zft_qic_mode) { - TRACE_EXIT (pos->seg_pos >= zft_eom_vtbl->start_seg || - zft_last_vtbl->open); - } else { - TRACE_EXIT pos->seg_pos > ft_last_data_segment; - } -} - -static inline int zft_tape_at_lbot(const zft_position *pos) -{ - if (zft_qic_mode) { - return (pos->seg_pos <= zft_first_vtbl->start_seg && - pos->volume_pos == 0); - } else { - return (pos->seg_pos <= ft_first_data_segment && - pos->volume_pos == 0); - } -} - -/* This one checks for EOF. return remaing space (may be negative) - */ -static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, - const zft_position *pos) -{ - return (__s64)(vtbl->size - pos->volume_pos); -} - -#endif /* _ZFTAPE_VTBL_H */ diff --git a/drivers/char/ftape/zftape/zftape-write.c b/drivers/char/ftape/zftape/zftape-write.c deleted file mode 100644 index 94327b8c97b9..000000000000 --- a/drivers/char/ftape/zftape/zftape-write.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright (C) 1996, 1997 Claus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-write.c,v $ - * $Revision: 1.3 $ - * $Date: 1997/11/06 00:50:29 $ - * - * This file contains the writing code - * for the QIC-117 floppy-tape driver for Linux. - */ - -#include -#include - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -/* Global vars. - */ - -/* Local vars. - */ -static int last_write_failed; -static int need_flush; - -void zft_prevent_flush(void) -{ - need_flush = 0; -} - -static int zft_write_header_segments(__u8* buffer) -{ - int header_1_ok = 0; - int header_2_ok = 0; - unsigned int time_stamp; - TRACE_FUN(ft_t_noise); - - TRACE_CATCH(ftape_abort_operation(),); - ftape_seek_to_bot(); /* prevents extra rewind */ - if (GET4(buffer, 0) != FT_HSEG_MAGIC) { - TRACE_ABORT(-EIO, ft_t_err, - "wrong header signature found, aborting"); - } - /* Be optimistic: */ - PUT4(buffer, FT_SEG_CNT, - zft_written_segments + GET4(buffer, FT_SEG_CNT) + 2); - if ((time_stamp = zft_get_time()) != 0) { - PUT4(buffer, FT_WR_DATE, time_stamp); - if (zft_label_changed) { - PUT4(buffer, FT_LABEL_DATE, time_stamp); - } - } - TRACE(ft_t_noise, - "writing first header segment %d", ft_header_segment_1); - header_1_ok = zft_verify_write_segments(ft_header_segment_1, - buffer, FT_SEGMENT_SIZE, - zft_deblock_buf) >= 0; - TRACE(ft_t_noise, - "writing second header segment %d", ft_header_segment_2); - header_2_ok = zft_verify_write_segments(ft_header_segment_2, - buffer, FT_SEGMENT_SIZE, - zft_deblock_buf) >= 0; - if (!header_1_ok) { - TRACE(ft_t_warn, "Warning: " - "update of first header segment failed"); - } - if (!header_2_ok) { - TRACE(ft_t_warn, "Warning: " - "update of second header segment failed"); - } - if (!header_1_ok && !header_2_ok) { - TRACE_ABORT(-EIO, ft_t_err, "Error: " - "update of both header segments failed."); - } - TRACE_EXIT 0; -} - -int zft_update_header_segments(void) -{ - TRACE_FUN(ft_t_noise); - - /* must NOT use zft_write_protected, as it also includes the - * file access mode. But we also want to update when soft - * write protection is enabled (O_RDONLY) - */ - if (ft_write_protected || zft_old_ftape) { - TRACE_ABORT(0, ft_t_noise, "Tape set read-only: no update"); - } - if (!zft_header_read) { - TRACE_ABORT(0, ft_t_noise, "Nothing to update"); - } - if (!zft_header_changed) { - zft_header_changed = zft_written_segments > 0; - } - if (!zft_header_changed && !zft_volume_table_changed) { - TRACE_ABORT(0, ft_t_noise, "Nothing to update"); - } - TRACE(ft_t_noise, "Updating header segments"); - if (ftape_get_status()->fti_state == writing) { - TRACE_CATCH(ftape_loop_until_writes_done(),); - } - TRACE_CATCH(ftape_abort_operation(),); - - zft_deblock_segment = -1; /* invalidate the cache */ - if (zft_header_changed) { - TRACE_CATCH(zft_write_header_segments(zft_hseg_buf),); - } - if (zft_volume_table_changed) { - TRACE_CATCH(zft_update_volume_table(ft_first_data_segment),); - } - zft_header_changed = - zft_volume_table_changed = - zft_label_changed = - zft_written_segments = 0; - TRACE_CATCH(ftape_abort_operation(),); - ftape_seek_to_bot(); - TRACE_EXIT 0; -} - -static int read_merge_buffer(int seg_pos, __u8 *buffer, int offset, int seg_sz) -{ - int result = 0; - const ft_trace_t old_tracing = TRACE_LEVEL; - TRACE_FUN(ft_t_flow); - - if (zft_qic_mode) { - /* writing in the middle of a volume is NOT allowed - * - */ - TRACE(ft_t_noise, "No need to read a segment"); - memset(buffer + offset, 0, seg_sz - offset); - TRACE_EXIT 0; - } - TRACE(ft_t_any, "waiting"); - ftape_start_writing(FT_WR_MULTI); - TRACE_CATCH(ftape_loop_until_writes_done(),); - - TRACE(ft_t_noise, "trying to read segment %d from offset %d", - seg_pos, offset); - SET_TRACE_LEVEL(ft_t_bug); - result = zft_fetch_segment_fraction(seg_pos, buffer, - FT_RD_SINGLE, - offset, seg_sz - offset); - SET_TRACE_LEVEL(old_tracing); - if (result != (seg_sz - offset)) { - TRACE(ft_t_noise, "Ignore error: read_segment() result: %d", - result); - memset(buffer + offset, 0, seg_sz - offset); - } - TRACE_EXIT 0; -} - -/* flush the write buffer to tape and write an eof-marker at the - * current position if not in raw mode. This function always - * positions the tape before the eof-marker. _ftape_close() should - * then advance to the next segment. - * - * the parameter "finish_volume" describes whether to position before - * or after the possibly created file-mark. We always position after - * the file-mark when called from ftape_close() and a flush was needed - * (that is ftape_write() was the last tape operation before calling - * ftape_flush) But we always position before the file-mark when this - * function get's called from outside ftape_close() - */ -int zft_flush_buffers(void) -{ - int result; - int data_remaining; - int this_segs_size; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_data_flow, - "entered, ftape_state = %d", ftape_get_status()->fti_state); - if (ftape_get_status()->fti_state != writing && !need_flush) { - TRACE_ABORT(0, ft_t_noise, "no need for flush"); - } - zft_io_state = zft_idle; /* triggers some initializations for the - * read and write routines - */ - if (last_write_failed) { - ftape_abort_operation(); - TRACE_EXIT -EIO; - } - TRACE(ft_t_noise, "flushing write buffers"); - this_segs_size = zft_get_seg_sz(zft_pos.seg_pos); - if (this_segs_size == zft_pos.seg_byte_pos) { - zft_pos.seg_pos ++; - data_remaining = zft_pos.seg_byte_pos = 0; - } else { - data_remaining = zft_pos.seg_byte_pos; - } - /* If there is any data not written to tape yet, append zero's - * up to the end of the sector (if using compression) or merge - * it with the data existing on the tape Then write the - * segment(s) to tape. - */ - TRACE(ft_t_noise, "Position:\n" - KERN_INFO "seg_pos : %d\n" - KERN_INFO "byte pos : %d\n" - KERN_INFO "remaining: %d", - zft_pos.seg_pos, zft_pos.seg_byte_pos, data_remaining); - if (data_remaining > 0) { - do { - this_segs_size = zft_get_seg_sz(zft_pos.seg_pos); - if (this_segs_size > data_remaining) { - TRACE_CATCH(read_merge_buffer(zft_pos.seg_pos, - zft_deblock_buf, - data_remaining, - this_segs_size), - last_write_failed = 1); - } - result = ftape_write_segment(zft_pos.seg_pos, - zft_deblock_buf, - FT_WR_MULTI); - if (result != this_segs_size) { - TRACE(ft_t_err, "flush buffers failed"); - zft_pos.tape_pos -= zft_pos.seg_byte_pos; - zft_pos.seg_byte_pos = 0; - - last_write_failed = 1; - TRACE_EXIT result; - } - zft_written_segments ++; - TRACE(ft_t_data_flow, - "flush, moved out buffer: %d", result); - /* need next segment for more data (empty segments?) - */ - if (result < data_remaining) { - if (result > 0) { - /* move remainder to buffer beginning - */ - memmove(zft_deblock_buf, - zft_deblock_buf + result, - FT_SEGMENT_SIZE - result); - } - } - data_remaining -= result; - zft_pos.seg_pos ++; - } while (data_remaining > 0); - TRACE(ft_t_any, "result: %d", result); - zft_deblock_segment = --zft_pos.seg_pos; - if (data_remaining == 0) { /* first byte next segment */ - zft_pos.seg_byte_pos = this_segs_size; - } else { /* after data previous segment, data_remaining < 0 */ - zft_pos.seg_byte_pos = data_remaining + result; - } - } else { - TRACE(ft_t_noise, "zft_deblock_buf empty"); - zft_pos.seg_pos --; - zft_pos.seg_byte_pos = zft_get_seg_sz (zft_pos.seg_pos); - ftape_start_writing(FT_WR_MULTI); - } - TRACE(ft_t_any, "waiting"); - if ((result = ftape_loop_until_writes_done()) < 0) { - /* that's really bad. What to to with zft_tape_pos? - */ - TRACE(ft_t_err, "flush buffers failed"); - } - TRACE(ft_t_any, "zft_seg_pos: %d, zft_seg_byte_pos: %d", - zft_pos.seg_pos, zft_pos.seg_byte_pos); - last_write_failed = - need_flush = 0; - TRACE_EXIT result; -} - -/* return-value: the number of bytes removed from the user-buffer - * - * out: - * int *write_cnt: how much actually has been moved to the - * zft_deblock_buf - * int req_len : MUST NOT BE CHANGED, except at EOT, in - * which case it may be adjusted - * in : - * char *buff : the user buffer - * int buf_pos_write : copy of buf_len_wr int - * this_segs_size : the size in bytes of the actual segment - * char - * *zft_deblock_buf : zft_deblock_buf - */ -static int zft_simple_write(int *cnt, - __u8 *dst_buf, const int seg_sz, - const __u8 __user *src_buf, const int req_len, - const zft_position *pos,const zft_volinfo *volume) -{ - int space_left; - TRACE_FUN(ft_t_flow); - - /* volume->size holds the tape capacity while volume is open */ - if (pos->tape_pos + volume->blk_sz > volume->size) { - TRACE_EXIT -ENOSPC; - } - /* remaining space in this segment, NOT zft_deblock_buf - */ - space_left = seg_sz - pos->seg_byte_pos; - *cnt = req_len < space_left ? req_len : space_left; - if (copy_from_user(dst_buf + pos->seg_byte_pos, src_buf, *cnt) != 0) { - TRACE_EXIT -EFAULT; - } - TRACE_EXIT *cnt; -} - -static int check_write_access(int req_len, - const zft_volinfo **volume, - zft_position *pos, - const unsigned int blk_sz) -{ - int result; - TRACE_FUN(ft_t_flow); - - if ((req_len % zft_blk_sz) != 0) { - TRACE_ABORT(-EINVAL, ft_t_info, - "write-count %d must be multiple of block-size %d", - req_len, blk_sz); - } - if (zft_io_state == zft_writing) { - /* all other error conditions have been checked earlier - */ - TRACE_EXIT 0; - } - zft_io_state = zft_idle; - TRACE_CATCH(zft_check_write_access(pos),); - /* If we haven't read the header segment yet, do it now. - * This will verify the configuration, get the bad sector - * table and read the volume table segment - */ - if (!zft_header_read) { - TRACE_CATCH(zft_read_header_segments(),); - } - /* fine. Now the tape is either at BOT or at EOD, - * Write start of volume now - */ - TRACE_CATCH(zft_open_volume(pos, blk_sz, zft_use_compression),); - *volume = zft_find_volume(pos->seg_pos); - DUMP_VOLINFO(ft_t_noise, "", *volume); - zft_just_before_eof = 0; - /* now merge with old data if necessary */ - if (!zft_qic_mode && pos->seg_byte_pos != 0){ - result = zft_fetch_segment(pos->seg_pos, - zft_deblock_buf, - FT_RD_SINGLE); - if (result < 0) { - if (result == -EINTR || result == -ENOSPC) { - TRACE_EXIT result; - } - TRACE(ft_t_noise, - "ftape_read_segment() result: %d. " - "This might be normal when using " - "a newly\nformatted tape", result); - memset(zft_deblock_buf, '\0', pos->seg_byte_pos); - } - } - zft_io_state = zft_writing; - TRACE_EXIT 0; -} - -static int fill_deblock_buf(__u8 *dst_buf, const int seg_sz, - zft_position *pos, const zft_volinfo *volume, - const char __user *usr_buf, const int req_len) -{ - int cnt = 0; - int result = 0; - TRACE_FUN(ft_t_flow); - - if (seg_sz == 0) { - TRACE_ABORT(0, ft_t_data_flow, "empty segment"); - } - TRACE(ft_t_data_flow, "\n" - KERN_INFO "remaining req_len: %d\n" - KERN_INFO " buf_pos: %d", - req_len, pos->seg_byte_pos); - /* zft_deblock_buf will not contain a valid segment any longer */ - zft_deblock_segment = -1; - if (zft_use_compression) { - TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); - TRACE_CATCH(result= (*zft_cmpr_ops->write)(&cnt, - dst_buf, seg_sz, - usr_buf, req_len, - pos, volume),); - } else { - TRACE_CATCH(result= zft_simple_write(&cnt, - dst_buf, seg_sz, - usr_buf, req_len, - pos, volume),); - } - pos->volume_pos += result; - pos->seg_byte_pos += cnt; - pos->tape_pos += cnt; - TRACE(ft_t_data_flow, "\n" - KERN_INFO "removed from user-buffer : %d bytes.\n" - KERN_INFO "copied to zft_deblock_buf: %d bytes.\n" - KERN_INFO "zft_tape_pos : " LL_X " bytes.", - result, cnt, LL(pos->tape_pos)); - TRACE_EXIT result; -} - - -/* called by the kernel-interface routine "zft_write()" - */ -int _zft_write(const char __user *buff, int req_len) -{ - int result = 0; - int written = 0; - int write_cnt; - int seg_sz; - static const zft_volinfo *volume = NULL; - TRACE_FUN(ft_t_flow); - - zft_resid = req_len; - last_write_failed = 1; /* reset to 0 when successful */ - /* check if write is allowed - */ - TRACE_CATCH(check_write_access(req_len, &volume,&zft_pos,zft_blk_sz),); - while (req_len > 0) { - /* Allow us to escape from this loop with a signal ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - seg_sz = zft_get_seg_sz(zft_pos.seg_pos); - if ((write_cnt = fill_deblock_buf(zft_deblock_buf, - seg_sz, - &zft_pos, - volume, - buff, - req_len)) < 0) { - zft_resid -= written; - if (write_cnt == -ENOSPC) { - /* leave the remainder to flush_buffers() - */ - TRACE(ft_t_info, "No space left on device"); - last_write_failed = 0; - if (!need_flush) { - need_flush = written > 0; - } - TRACE_EXIT written > 0 ? written : -ENOSPC; - } else { - TRACE_EXIT result; - } - } - if (zft_pos.seg_byte_pos == seg_sz) { - TRACE_CATCH(ftape_write_segment(zft_pos.seg_pos, - zft_deblock_buf, - FT_WR_ASYNC), - zft_resid -= written); - zft_written_segments ++; - zft_pos.seg_byte_pos = 0; - zft_deblock_segment = zft_pos.seg_pos; - ++zft_pos.seg_pos; - } - written += write_cnt; - buff += write_cnt; - req_len -= write_cnt; - } /* while (req_len > 0) */ - TRACE(ft_t_data_flow, "remaining in blocking buffer: %d", - zft_pos.seg_byte_pos); - TRACE(ft_t_data_flow, "just written bytes: %d", written); - last_write_failed = 0; - zft_resid -= written; - need_flush = need_flush || written > 0; - TRACE_EXIT written; /* bytes written */ -} diff --git a/drivers/char/ftape/zftape/zftape-write.h b/drivers/char/ftape/zftape/zftape-write.h deleted file mode 100644 index ea887015b493..000000000000 --- a/drivers/char/ftape/zftape/zftape-write.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _ZFTAPE_WRITE_H -#define _ZFTAPE_WRITE_H - -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-write.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:13 $ - * - * This file contains the definitions for the write functions - * for the zftape driver for Linux. - * - */ - -extern int zft_flush_buffers(void); -extern int zft_update_header_segments(void); -extern void zft_prevent_flush(void); - -/* hook for the VFS interface - */ -extern int _zft_write(const char __user *buff, int req_len); -#endif /* _ZFTAPE_WRITE_H */ diff --git a/drivers/char/ftape/zftape/zftape_syms.c b/drivers/char/ftape/zftape/zftape_syms.c deleted file mode 100644 index 2db1401682df..000000000000 --- a/drivers/char/ftape/zftape/zftape_syms.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 1997 Claus-Justus Heine - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape_syms.c,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/05 19:19:14 $ - * - * This file contains the symbols that the zftape frontend to - * the ftape floppy tape driver exports - */ - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-buffers.h" -#include "../zftape/zftape-ctl.h" - -/* zftape-init.c */ -EXPORT_SYMBOL(zft_cmpr_register); -/* zftape-read.c */ -EXPORT_SYMBOL(zft_fetch_segment_fraction); -/* zftape-buffers.c */ -EXPORT_SYMBOL(zft_vmalloc_once); -EXPORT_SYMBOL(zft_vmalloc_always); -EXPORT_SYMBOL(zft_vfree); diff --git a/include/linux/Kbuild b/include/linux/Kbuild index d7e04689304c..ff433126361f 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -60,8 +60,6 @@ header-y += fadvise.h header-y += fd.h header-y += fdreg.h header-y += fib_rules.h -header-y += ftape-header-segment.h -header-y += ftape-vendors.h header-y += fuse.h header-y += futex.h header-y += genetlink.h @@ -206,7 +204,6 @@ unifdef-y += fcntl.h unifdef-y += filter.h unifdef-y += flat.h unifdef-y += fs.h -unifdef-y += ftape.h unifdef-y += gameport.h unifdef-y += generic_serial.h unifdef-y += genhd.h @@ -341,6 +338,5 @@ unifdef-y += wait.h unifdef-y += wanrouter.h unifdef-y += watchdog.h unifdef-y += xfrm.h -unifdef-y += zftape.h objhdr-y += version.h diff --git a/include/linux/ftape-header-segment.h b/include/linux/ftape-header-segment.h deleted file mode 100644 index 4732218f0708..000000000000 --- a/include/linux/ftape-header-segment.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef _FTAPE_HEADER_SEGMENT_H -#define _FTAPE_HEADER_SEGMENT_H - -/* - * Copyright (C) 1996-1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/include/linux/ftape-header-segment.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:28 $ - * - * This file defines some offsets into the header segment of a - * floppy tape cartridge. For use with the QIC-40/80/3010/3020 - * floppy-tape driver "ftape" for Linux. - */ - -#define FT_SIGNATURE 0 /* must be 0xaa55aa55 */ -#define FT_FMT_CODE 4 -#define FT_REV_LEVEL 5 /* only for QIC-80 since. Rev. L (== 0x0c) */ -#define FT_HSEG_1 6 /* first header segment, except for format code 6 */ -#define FT_HSEG_2 8 /* second header segment, except for format code 6 */ -#define FT_FRST_SEG 10 /* first data segment, except for format code 6 */ -#define FT_LAST_SEG 12 /* last data segment, except for format code 6 */ -#define FT_FMT_DATE 14 /* date and time of most recent format, see below */ -#define FT_WR_DATE 18 /* date and time of most recent write or format */ -#define FT_SPT 24 /* segments per track */ -#define FT_TPC 26 /* tracks per cartridge */ -#define FT_FHM 27 /* floppy drive head (maximum of it) */ -#define FT_FTM 28 /* floppy track max. */ -#define FT_FSM 29 /* floppy sector max. (128) */ -#define FT_LABEL 30 /* floppy tape label */ -#define FT_LABEL_DATE 74 /* date and time the tape label was written */ -#define FT_LABEL_SZ (FT_LABEL_DATE - FT_LABEL) -#define FT_CMAP_START 78 /* starting segment of compression map */ -#define FT_FMT_ERROR 128 /* must be set to 0xff if remainder gets lost during - * tape format - */ -#define FT_SEG_CNT 130 /* number of seg. written, formatted or verified - * through lifetime of tape (why not read?) - */ -#define FT_INIT_DATE 138 /* date and time of initial tape format */ -#define FT_FMT_CNT 142 /* number of times tape has been formatted */ -#define FT_FSL_CNT 144 /* number of segments in failed sector log */ -#define FT_MK_CODE 146 /* id string of tape manufacturer */ -#define FT_LOT_CODE 190 /* tape manufacturer lot code */ -#define FT_6_HSEG_1 234 /* first header segment for format code 6 */ -#define FT_6_HSEG_2 238 /* second header segment for format code 6 */ -#define FT_6_FRST_SEG 242 /* first data segment for format code 6 */ -#define FT_6_LAST_SEG 246 /* last data segment for format code 6 */ - -#define FT_FSL 256 -#define FT_HEADER_END 256 /* space beyond this point: - * format codes 2, 3 and 5: - * - failed sector log until byte 2047 - * - bad sector map in the reamining part of segment - * format codes 4 and 6: - * - bad sector map starts hear - */ - - -/* value to be stored at the FT_SIGNATURE offset - */ -#define FT_HSEG_MAGIC 0xaa55aa55 -#define FT_D2G_MAGIC 0x82288228 /* Ditto 2GB */ - -/* data and time encoding: */ -#define FT_YEAR_SHIFT 25 -#define FT_YEAR_MASK 0xfe000000 -#define FT_YEAR_0 1970 -#define FT_YEAR_MAX 127 -#define FT_YEAR(year) ((((year)-FT_YEAR_0)< -#include -#endif -#include -#include - -#define FT_SECTOR(x) (x+1) /* sector offset into real sector */ -#define FT_SECTOR_SIZE 1024 -#define FT_SECTORS_PER_SEGMENT 32 -#define FT_ECC_SECTORS 3 -#define FT_SEGMENT_SIZE ((FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS) * FT_SECTOR_SIZE) -#define FT_BUFF_SIZE (FT_SECTORS_PER_SEGMENT * FT_SECTOR_SIZE) - -/* - * bits of the minor device number that define drive selection - * methods. Could be used one day to access multiple tape - * drives on the same controller. - */ -#define FTAPE_SEL_A 0 -#define FTAPE_SEL_B 1 -#define FTAPE_SEL_C 2 -#define FTAPE_SEL_D 3 -#define FTAPE_SEL_MASK 3 -#define FTAPE_SEL(unit) ((unit) & FTAPE_SEL_MASK) -#define FTAPE_NO_REWIND 4 /* mask for minor nr */ - -/* the following two may be reported when MTIOCGET is requested ... */ -typedef union { - struct { - __u8 error; - __u8 command; - } error; - long space; -} ft_drive_error; -typedef union { - struct { - __u8 drive_status; - __u8 drive_config; - __u8 tape_status; - } status; - long space; -} ft_drive_status; - -#ifdef __KERNEL__ - -#define FT_RQM_DELAY 12 -#define FT_MILLISECOND 1 -#define FT_SECOND 1000 -#define FT_FOREVER -1 -#ifndef HZ -#error "HZ undefined." -#endif -#define FT_USPT (1000000/HZ) /* microseconds per tick */ - -/* This defines the number of retries that the driver will allow - * before giving up (and letting a higher level handle the error). - */ -#ifdef TESTING -#define FT_SOFT_RETRIES 1 /* number of low level retries */ -#define FT_RETRIES_ON_ECC_ERROR 3 /* ecc error when correcting segment */ -#else -#define FT_SOFT_RETRIES 6 /* number of low level retries (triple) */ -#define FT_RETRIES_ON_ECC_ERROR 3 /* ecc error when correcting segment */ -#endif - -#ifndef THE_FTAPE_MAINTAINER -#define THE_FTAPE_MAINTAINER "the ftape maintainer" -#endif - -/* Initialize missing configuration parameters. - */ -#ifndef CONFIG_FT_NR_BUFFERS -# define CONFIG_FT_NR_BUFFERS 3 -#endif -#ifndef CONFIG_FT_FDC_THR -# define CONFIG_FT_FDC_THR 8 -#endif -#ifndef CONFIG_FT_FDC_MAX_RATE -# define CONFIG_FT_FDC_MAX_RATE 2000 -#endif -#ifndef CONFIG_FT_FDC_BASE -# define CONFIG_FT_FDC_BASE 0 -#endif -#ifndef CONFIG_FT_FDC_IRQ -# define CONFIG_FT_FDC_IRQ 0 -#endif -#ifndef CONFIG_FT_FDC_DMA -# define CONFIG_FT_FDC_DMA 0 -#endif - -/* Turn some booleans into numbers. - */ -#ifdef CONFIG_FT_PROBE_FC10 -# undef CONFIG_FT_PROBE_FC10 -# define CONFIG_FT_PROBE_FC10 1 -#else -# define CONFIG_FT_PROBE_FC10 0 -#endif -#ifdef CONFIG_FT_MACH2 -# undef CONFIG_FT_MACH2 -# define CONFIG_FT_MACH2 1 -#else -# define CONFIG_FT_MACH2 0 -#endif - -/* Insert default settings - */ -#if CONFIG_FT_PROBE_FC10 == 1 -# if CONFIG_FT_FDC_BASE == 0 -# undef CONFIG_FT_FDC_BASE -# define CONFIG_FT_FDC_BASE 0x180 -# endif -# if CONFIG_FT_FDC_IRQ == 0 -# undef CONFIG_FT_FDC_IRQ -# define CONFIG_FT_FDC_IRQ 9 -# endif -# if CONFIG_FT_FDC_DMA == 0 -# undef CONFIG_FT_FDC_DMA -# define CONFIG_FT_FDC_DMA 3 -# endif -#elif CONFIG_FT_MACH2 == 1 /* CONFIG_FT_PROBE_FC10 == 1 */ -# if CONFIG_FT_FDC_BASE == 0 -# undef CONFIG_FT_FDC_BASE -# define CONFIG_FT_FDC_BASE 0x1E0 -# endif -# if CONFIG_FT_FDC_IRQ == 0 -# undef CONFIG_FT_FDC_IRQ -# define CONFIG_FT_FDC_IRQ 6 -# endif -# if CONFIG_FT_FDC_DMA == 0 -# undef CONFIG_FT_FDC_DMA -# define CONFIG_FT_FDC_DMA 2 -# endif -#elif defined(CONFIG_FT_ALT_FDC) /* CONFIG_FT_MACH2 */ -# if CONFIG_FT_FDC_BASE == 0 -# undef CONFIG_FT_FDC_BASE -# define CONFIG_FT_FDC_BASE 0x370 -# endif -# if CONFIG_FT_FDC_IRQ == 0 -# undef CONFIG_FT_FDC_IRQ -# define CONFIG_FT_FDC_IRQ 6 -# endif -# if CONFIG_FT_FDC_DMA == 0 -# undef CONFIG_FT_FDC_DMA -# define CONFIG_FT_FDC_DMA 2 -# endif -#else /* CONFIG_FT_ALT_FDC */ -# if CONFIG_FT_FDC_BASE == 0 -# undef CONFIG_FT_FDC_BASE -# define CONFIG_FT_FDC_BASE 0x3f0 -# endif -# if CONFIG_FT_FDC_IRQ == 0 -# undef CONFIG_FT_FDC_IRQ -# define CONFIG_FT_FDC_IRQ 6 -# endif -# if CONFIG_FT_FDC_DMA == 0 -# undef CONFIG_FT_FDC_DMA -# define CONFIG_FT_FDC_DMA 2 -# endif -#endif /* standard FDC */ - -/* some useful macro's - */ -#define NR_ITEMS(x) (int)(sizeof(x)/ sizeof(*x)) - -#endif /* __KERNEL__ */ - -#endif diff --git a/include/linux/zftape.h b/include/linux/zftape.h deleted file mode 100644 index b057c65366c6..000000000000 --- a/include/linux/zftape.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef _ZFTAPE_H -#define _ZFTAPE_H - -/* - * Copyright (C) 1996, 1997 Claus-Justus Heine. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - * - * $Source: /homes/cvs/ftape-stacked/include/linux/zftape.h,v $ - * $Revision: 1.12 $ - * $Date: 1997/10/21 11:02:37 $ - * - * Special ioctl and other global info for the zftape VFS - * interface for the QIC-40/80/3010/3020 floppy-tape driver for - * Linux. - */ - -#define ZFTAPE_VERSION "zftape for " FTAPE_VERSION - -#include - -#define ZFTAPE_LABEL "Ftape - The Linux Floppy Tape Project!" - -/* Bits of the minor device number that control the operation mode */ -#define ZFT_Q80_MODE (1 << 3) -#define ZFT_ZIP_MODE (1 << 4) -#define ZFT_RAW_MODE (1 << 5) -#define ZFT_MINOR_OP_MASK (ZFT_Q80_MODE | \ - ZFT_ZIP_MODE | \ - ZFT_RAW_MODE) -#define ZFT_MINOR_MASK (FTAPE_SEL_MASK | \ - ZFT_MINOR_OP_MASK | \ - FTAPE_NO_REWIND) - -#ifdef ZFT_OBSOLETE -struct mtblksz { - unsigned int mt_blksz; -}; -#define MTIOC_ZFTAPE_GETBLKSZ _IOR('m', 104, struct mtblksz) -#endif - -#ifdef __KERNEL__ - -extern int zft_init(void); - -static inline __s64 zft_div_blksz(__s64 value, __u32 blk_sz) -{ - if (blk_sz == 1) { - return value; - } else { - return (__s64)(((__u32)(value >> 10) + (blk_sz >> 10) - 1) - / (blk_sz >> 10)); - } -} - -static inline __s64 zft_mul_blksz(__s64 value, __u32 blk_sz) -{ - if (blk_sz == 1) { - return value; - } else { - /* if blk_sz != 1, then it is a multiple of 1024. In - * this case, `value' will also fit into 32 bits. - * - * Actually, this limits the capacity to 42 - * bits. This is (2^32)*1024, roughly a thousand - * times 2GB, or 3 Terabytes. Hopefully this is enough - */ - return(__s64)(((__u32)(value)*(blk_sz>>10))<<10); - } -} - -#endif - -#endif -- cgit v1.2.3 From f6a570333e554b48ad589e7137c77c57809eee81 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 18 Oct 2006 01:47:25 -0400 Subject: [PATCH] severing module.h->sched.h Signed-off-by: Al Viro --- arch/i386/kernel/alternative.c | 1 + arch/i386/kernel/cpu/mcheck/therm_throt.c | 1 + drivers/base/cpu.c | 1 + drivers/hwmon/abituguru.c | 1 + drivers/leds/ledtrig-ide-disk.c | 1 + drivers/leds/ledtrig-timer.c | 1 + drivers/pci/access.c | 1 + drivers/scsi/scsi_transport_sas.c | 1 + drivers/w1/slaves/w1_therm.c | 1 + include/asm-x86_64/elf.h | 1 - include/linux/acct.h | 1 + include/linux/module.h | 13 +------------ include/scsi/libiscsi.h | 2 ++ kernel/latency.c | 1 + kernel/module.c | 15 ++++++++++++++- lib/random32.c | 1 + 16 files changed, 29 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c index 583c238e17fb..535f9794fba1 100644 --- a/arch/i386/kernel/alternative.c +++ b/arch/i386/kernel/alternative.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/i386/kernel/cpu/mcheck/therm_throt.c index 2d8703b7ce65..bad8b4420709 100644 --- a/arch/i386/kernel/cpu/mcheck/therm_throt.c +++ b/arch/i386/kernel/cpu/mcheck/therm_throt.c @@ -20,6 +20,7 @@ #include #include #include +#include #include /* How long to wait between reporting thermal events */ diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 4bef76a2f3f2..1f745f12f94e 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index e5cb0fdab9b1..b1dc63e4ac7b 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -21,6 +21,7 @@ etc voltage & frequency control is not supported! */ #include +#include #include #include #include diff --git a/drivers/leds/ledtrig-ide-disk.c b/drivers/leds/ledtrig-ide-disk.c index fa651886ab4f..54b155c7026f 100644 --- a/drivers/leds/ledtrig-ide-disk.c +++ b/drivers/leds/ledtrig-ide-disk.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c index 29a8818a32ec..d756bdb01c59 100644 --- a/drivers/leds/ledtrig-timer.c +++ b/drivers/leds/ledtrig-timer.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 73a58c73d526..fc405f0165d9 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -1,5 +1,6 @@ #include #include +#include #include #include diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index b5b0c2cba96b..5c0b75bbfa10 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 5372cfcbd054..b022fffd8c51 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/include/asm-x86_64/elf.h b/include/asm-x86_64/elf.h index a406fcb1e924..6d24ea7c4d9d 100644 --- a/include/asm-x86_64/elf.h +++ b/include/asm-x86_64/elf.h @@ -45,7 +45,6 @@ typedef struct user_i387_struct elf_fpregset_t; #ifdef __KERNEL__ #include -#include /* * This is used to ensure we don't load something for the wrong architecture. diff --git a/include/linux/acct.h b/include/linux/acct.h index 0496d1f09952..302eb727ecb8 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h @@ -119,6 +119,7 @@ struct acct_v3 #ifdef CONFIG_BSD_PROCESS_ACCT struct vfsmount; struct super_block; +struct pacct_struct; extern void acct_auto_close_mnt(struct vfsmount *m); extern void acct_auto_close(struct super_block *sb); extern void acct_init_pacct(struct pacct_struct *pacct); diff --git a/include/linux/module.h b/include/linux/module.h index 9258ffd8a7f0..d33df2408e05 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -6,7 +6,6 @@ * Rewritten by Richard Henderson Dec 1996 * Rewritten again by Rusty Russell, 2002 */ -#include #include #include #include @@ -411,17 +410,7 @@ static inline int try_module_get(struct module *module) return ret; } -static inline void module_put(struct module *module) -{ - if (module) { - unsigned int cpu = get_cpu(); - local_dec(&module->ref[cpu].count); - /* Maybe they're waiting for us to drop reference? */ - if (unlikely(!module_is_live(module))) - wake_up_process(module->waiter); - put_cpu(); - } -} +extern void module_put(struct module *module); #else /*!CONFIG_MODULE_UNLOAD*/ static inline int try_module_get(struct module *module) diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 61eebec00a7b..ea0816d4904d 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include diff --git a/kernel/latency.c b/kernel/latency.c index 258f2555abbc..e63fcacb61a7 100644 --- a/kernel/latency.c +++ b/kernel/latency.c @@ -36,6 +36,7 @@ #include #include #include +#include #include struct latency_info { diff --git a/kernel/module.c b/kernel/module.c index 45e01cb60101..e2d09d604ca0 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -34,10 +34,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -790,6 +790,19 @@ static struct module_attribute refcnt = { .show = show_refcnt, }; +void module_put(struct module *module) +{ + if (module) { + unsigned int cpu = get_cpu(); + local_dec(&module->ref[cpu].count); + /* Maybe they're waiting for us to drop reference? */ + if (unlikely(!module_is_live(module))) + wake_up_process(module->waiter); + put_cpu(); + } +} +EXPORT_SYMBOL(module_put); + #else /* !CONFIG_MODULE_UNLOAD */ static void print_unload_info(struct seq_file *m, struct module *mod) { diff --git a/lib/random32.c b/lib/random32.c index 4a15ce51cea7..ec7f81d3fb18 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -36,6 +36,7 @@ #include #include #include +#include #include struct rnd_state { -- cgit v1.2.3 From 914e26379decf1fd984b22e51fd2e4209b7a7f1b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 18 Oct 2006 13:55:46 -0400 Subject: [PATCH] severing fs.h, radix-tree.h -> sched.h Signed-off-by: Al Viro --- arch/i386/kernel/acpi/cstate.c | 1 + drivers/acpi/dock.c | 1 + drivers/char/hw_random/core.c | 1 + drivers/char/tpm/tpm.h | 1 + drivers/hwmon/hdaps.c | 1 + drivers/spi/spi_butterfly.c | 1 + fs/9p/conv.c | 1 + fs/9p/fcall.c | 1 + fs/9p/fid.c | 1 + fs/9p/v9fs.c | 1 + fs/9p/vfs_dir.c | 1 + fs/9p/vfs_file.c | 1 + fs/inotify.c | 1 + fs/jffs2/acl.c | 1 + fs/jffs2/wbuf.c | 1 + fs/jfs/ioctl.c | 1 + fs/proc/root.c | 1 + fs/super.c | 18 ++++++++++++++++++ fs/sync.c | 1 + fs/utimes.c | 1 + include/linux/fs.h | 37 +++++++------------------------------ include/linux/radix-tree.h | 1 - 22 files changed, 44 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c index 20563e52c622..4664b55f623e 100644 --- a/arch/i386/kernel/acpi/cstate.c +++ b/arch/i386/kernel/acpi/cstate.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 578b99b71d9c..bf5b79ed3613 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index ebace201bec6..26a860adcb38 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 050ced247f68..bb9a43c6cf3d 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index 26be4ea8a38a..e8ef62b83d6b 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */ diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c index 39d9b20f2038..c2f601f8e4f2 100644 --- a/drivers/spi/spi_butterfly.c +++ b/drivers/spi/spi_butterfly.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/fs/9p/conv.c b/fs/9p/conv.c index 56d88c1a09c5..a3ed571eee31 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include "debug.h" diff --git a/fs/9p/fcall.c b/fs/9p/fcall.c index 8556097fcda8..dc336a67592f 100644 --- a/fs/9p/fcall.c +++ b/fs/9p/fcall.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "debug.h" diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 70492ccb4385..27507201f9e7 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "debug.h" diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 0f628041e3f7..0b96fae8b479 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index e32d5971039b..905c882f4e2f 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index c3c47eda7574..79e6f9cd7340 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/inotify.c b/fs/inotify.c index 723836a1f718..f5099d86fd91 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 0ae3cd10702c..73f0d60f73a5 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index b9b700730dfe..70707309dfa1 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "nodelist.h" diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c index 37db52488262..ed814b1ff4d9 100644 --- a/fs/jfs/ioctl.c +++ b/fs/jfs/ioctl.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/fs/proc/root.c b/fs/proc/root.c index ffe66c38488b..64d242b6dcfa 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/super.c b/fs/super.c index 47e554c12e76..84c320f6ad7e 100644 --- a/fs/super.c +++ b/fs/super.c @@ -220,6 +220,24 @@ static int grab_super(struct super_block *s) __releases(sb_lock) return 0; } +/* + * Superblock locking. We really ought to get rid of these two. + */ +void lock_super(struct super_block * sb) +{ + get_fs_excl(); + mutex_lock(&sb->s_lock); +} + +void unlock_super(struct super_block * sb) +{ + put_fs_excl(); + mutex_unlock(&sb->s_lock); +} + +EXPORT_SYMBOL(lock_super); +EXPORT_SYMBOL(unlock_super); + /* * Write out and wait upon all dirty data associated with this * superblock. Filesystem data as well as the underlying block diff --git a/fs/sync.c b/fs/sync.c index 1de747b5ddb9..865f32be386e 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/utimes.c b/fs/utimes.c index 1bcd852fc4a9..99cf2cb11fec 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/include/linux/fs.h b/include/linux/fs.h index 2fe6e3f900ba..cac7b1ef9543 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -276,7 +276,7 @@ extern int dir_notify_enable; #include #include #include -#include +#include #include #include @@ -977,36 +977,13 @@ enum { #define vfs_check_frozen(sb, level) \ wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) -static inline void get_fs_excl(void) -{ - atomic_inc(¤t->fs_excl); -} - -static inline void put_fs_excl(void) -{ - atomic_dec(¤t->fs_excl); -} - -static inline int has_fs_excl(void) -{ - return atomic_read(¤t->fs_excl); -} +#define get_fs_excl() atomic_inc(¤t->fs_excl) +#define put_fs_excl() atomic_dec(¤t->fs_excl) +#define has_fs_excl() atomic_read(¤t->fs_excl) - -/* - * Superblock locking. - */ -static inline void lock_super(struct super_block * sb) -{ - get_fs_excl(); - mutex_lock(&sb->s_lock); -} - -static inline void unlock_super(struct super_block * sb) -{ - put_fs_excl(); - mutex_unlock(&sb->s_lock); -} +/* not quite ready to be deprecated, but... */ +extern void lock_super(struct super_block *); +extern void unlock_super(struct super_block *); /* * VFS helper functions.. diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index 9158a68140c9..cbfa11537421 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -19,7 +19,6 @@ #ifndef _LINUX_RADIX_TREE_H #define _LINUX_RADIX_TREE_H -#include #include #include -- cgit v1.2.3 From a1f8e7f7fb9d7e2cbcb53170edca7c0ac4680697 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 16:08:53 -0400 Subject: [PATCH] severing skbuff.h -> highmem.h Signed-off-by: Al Viro --- drivers/infiniband/ulp/iser/iser_memory.c | 1 + drivers/net/sun3lance.c | 1 + fs/compat.c | 1 + include/linux/skbuff.h | 19 ------------------- kernel/auditsc.c | 1 + net/appletalk/ddp.c | 1 + net/core/kmap_skb.h | 19 +++++++++++++++++++ net/core/skbuff.c | 3 ++- net/core/sock.c | 1 + net/ipv4/ip_output.c | 1 + net/packet/af_packet.c | 1 + 11 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 net/core/kmap_skb.h (limited to 'include/linux') diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 0606744c3f84..5e122501fd80 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index b865db363ba0..47a1c09d19ac 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -38,6 +38,7 @@ static char *version = "sun3lance.c: v1.2 1/12/2001 Sam Creasey (sammy@sammy.ne #include #include +#include #include #include #include diff --git a/fs/compat.c b/fs/compat.c index 8d0a0018a7d2..fde52d40c0b6 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include /* siocdevprivate_ioctl */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 14ec16d2d9ba..24ce0add6c54 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -1295,24 +1294,6 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) return __pskb_trim(skb, len); } -static inline void *kmap_skb_frag(const skb_frag_t *frag) -{ -#ifdef CONFIG_HIGHMEM - BUG_ON(in_irq()); - - local_bh_disable(); -#endif - return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ); -} - -static inline void kunmap_skb_frag(void *vaddr) -{ - kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); -#ifdef CONFIG_HIGHMEM - local_bh_enable(); -#endif -} - #define skb_queue_walk(queue, skb) \ for (skb = (queue)->next; \ prefetch(skb->next), (skb != (struct sk_buff *)(queue)); \ diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 42f2f1179711..ab97e5101232 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include "audit.h" diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 485e35c3b28b..3a7052207708 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -61,6 +61,7 @@ #include #include #include +#include "../core/kmap_skb.h" struct datalink_proto *ddp_dl, *aarp_dl; static const struct proto_ops atalk_dgram_ops; diff --git a/net/core/kmap_skb.h b/net/core/kmap_skb.h new file mode 100644 index 000000000000..283c2b993fb8 --- /dev/null +++ b/net/core/kmap_skb.h @@ -0,0 +1,19 @@ +#include + +static inline void *kmap_skb_frag(const skb_frag_t *frag) +{ +#ifdef CONFIG_HIGHMEM + BUG_ON(in_irq()); + + local_bh_disable(); +#endif + return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ); +} + +static inline void kunmap_skb_frag(void *vaddr) +{ + kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); +#ifdef CONFIG_HIGHMEM + local_bh_enable(); +#endif +} diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a90bc439488e..8e1c385e5ba9 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -56,7 +56,6 @@ #include #include #include -#include #include #include @@ -67,6 +66,8 @@ #include #include +#include "kmap_skb.h" + static kmem_cache_t *skbuff_head_cache __read_mostly; static kmem_cache_t *skbuff_fclone_cache __read_mostly; diff --git a/net/core/sock.c b/net/core/sock.c index ab8fafadb4ba..419c7d3289c7 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -111,6 +111,7 @@ #include #include #include +#include #include #include diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 1da3d32f8289..a35209d517ad 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 271d2eed0699..08e68b67bbf6 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -71,6 +71,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From bd01f843c3368dcee735c19603251669f23f4477 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 17:23:57 -0400 Subject: [PATCH] severing skbuff.h -> poll.h Signed-off-by: Al Viro --- fs/compat.c | 1 + fs/gfs2/locking/dlm/plock.c | 1 + include/linux/skbuff.h | 1 - include/net/inet_connection_sock.h | 1 + include/net/udp.h | 1 + 5 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/fs/compat.c b/fs/compat.c index fde52d40c0b6..06dad665b88f 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include /* siocdevprivate_ioctl */ diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 7365aec9511b..3799f19b282f 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -8,6 +8,7 @@ #include #include +#include #include "lock_dlm.h" diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 24ce0add6c54..5c5a08576dcc 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index cccea051e922..bf16d98d372c 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff --git a/include/net/udp.h b/include/net/udp.h index 1548d68d45da..1b921fa81474 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -29,6 +29,7 @@ #include #include #include +#include /** * struct udp_skb_cb - UDP(-Lite) private variables -- cgit v1.2.3 From d7fe0f241dceade9c8d4af75498765c5ff7f27e6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 3 Dec 2006 23:15:30 -0500 Subject: [PATCH] severing skbuff.h -> mm.h Signed-off-by: Al Viro --- drivers/isdn/divert/isdn_divert.c | 2 ++ drivers/net/ehea/ehea_qmr.c | 1 + drivers/net/lance.c | 1 + drivers/net/ne3210.c | 1 + drivers/net/sk98lin/skge.c | 1 + drivers/net/starfire.c | 1 + drivers/net/sungem.c | 1 + drivers/net/sunhme.c | 1 + drivers/net/typhoon.c | 1 + include/linux/igmp.h | 1 + include/linux/kernelcapi.h | 1 + include/linux/netdevice.h | 1 + include/linux/netfilter_ipv4/ip_conntrack.h | 1 + include/linux/skbuff.h | 1 - include/net/irda/timer.h | 1 + include/net/netfilter/nf_conntrack.h | 1 + include/net/netlink.h | 1 + include/net/sock.h | 1 + net/ieee80211/ieee80211_crypt_tkip.c | 1 + net/ieee80211/ieee80211_crypt_wep.c | 1 + net/ipv4/ipvs/ip_vs_lblc.c | 1 + net/ipv4/ipvs/ip_vs_lblcr.c | 1 + net/irda/discovery.c | 1 + net/irda/iriap.c | 1 + net/irda/irttp.c | 1 + net/netfilter/nf_conntrack_core.c | 1 + net/netfilter/x_tables.c | 1 + net/netfilter/xt_hashlimit.c | 1 + 28 files changed, 28 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c index 1f5ebe9ee72c..03319ea5aa0c 100644 --- a/drivers/isdn/divert/isdn_divert.c +++ b/drivers/isdn/divert/isdn_divert.c @@ -10,6 +10,8 @@ */ #include +#include +#include #include "isdn_divert.h" diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 72ef7bde3346..f143e13b229d 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -26,6 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include "ehea.h" #include "ehea_phyp.h" #include "ehea_qmr.h" diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 6efbd499d752..4256c13c73c2 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -57,6 +57,7 @@ static const char version[] = "lance.c:v1.16 2006/11/09 dplatt@3do.com, becker@c #include #include #include +#include #include #include diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index d66328975425..1a6fed76d4cc 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 12cbfd190dd7..92d11b961db8 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -114,6 +114,7 @@ #include #include #include +#include #include "h/skdrv1st.h" #include "h/skdrv2nd.h" diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 7a0aee6c869d..bf873ea25797 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -41,6 +41,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 334c6cfd6595..cf44e72399b9 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index ec432ea879fb..4d59ece67292 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 8ddea1da7c05..9781b16bb8b6 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -117,6 +117,7 @@ static const int multicast_filter_limit = 32; #include #include #include +#include #include #include #include diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 6e7ea2f0a57c..9dbb525c5178 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -127,6 +127,7 @@ struct igmpv3_query { #ifdef __KERNEL__ #include +#include #include extern int sysctl_igmp_max_memberships; diff --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h index 891bb2cf0aa8..f8a0ff86dacc 100644 --- a/include/linux/kernelcapi.h +++ b/include/linux/kernelcapi.h @@ -47,6 +47,7 @@ typedef struct kcapi_carddef { #include #include +#include #define KCI_CONTRUP 0 /* arg: struct capi_profile */ #define KCI_CONTRDOWN 1 /* arg: NULL */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 949eada46ce1..c57088f575a3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -30,6 +30,7 @@ #include #ifdef __KERNEL__ +#include #include #include #include diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 61da56941dce..33581c13d947 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 5c5a08576dcc..6bdff9b148d0 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/include/net/irda/timer.h b/include/net/irda/timer.h index 2c5d8864ab77..cb61568547d1 100644 --- a/include/net/irda/timer.h +++ b/include/net/irda/timer.h @@ -28,6 +28,7 @@ #define TIMER_H #include +#include #include /* for HZ */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 032b36a0e378..bd01b4633ee2 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -56,6 +56,7 @@ union nf_conntrack_help { #include #include +#include #ifdef CONFIG_NETFILTER_DEBUG #define NF_CT_ASSERT(x) \ diff --git a/include/net/netlink.h b/include/net/netlink.h index fd75fd65d59e..bcaf67b7a19d 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -3,6 +3,7 @@ #include #include +#include /* ======================================================================== * Netlink Messages and Attributes Interface (As Seen On TV) diff --git a/include/net/sock.h b/include/net/sock.h index 26fc0b16bc0c..fe3a33fad03f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -47,6 +47,7 @@ #include #include #include /* struct sk_buff */ +#include #include #include diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 4200ec509866..fc1f99a59732 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index 1b2efff11d39..7a95c3d81314 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c index 524751e031de..a4385a2180ee 100644 --- a/net/ipv4/ipvs/ip_vs_lblc.c +++ b/net/ipv4/ipvs/ip_vs_lblc.c @@ -45,6 +45,7 @@ #include #include #include +#include /* for sysctl */ #include diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c index 08990192b6ec..fe1af5d079af 100644 --- a/net/ipv4/ipvs/ip_vs_lblcr.c +++ b/net/ipv4/ipvs/ip_vs_lblcr.c @@ -43,6 +43,7 @@ #include #include #include +#include /* for sysctl */ #include diff --git a/net/irda/discovery.c b/net/irda/discovery.c index 3fefc822c1c0..89fd2a2cbca6 100644 --- a/net/irda/discovery.c +++ b/net/irda/discovery.c @@ -32,6 +32,7 @@ #include #include +#include #include #include diff --git a/net/irda/iriap.c b/net/irda/iriap.c index 8cfd076c4c12..8f1c6d65b247 100644 --- a/net/irda/iriap.c +++ b/net/irda/iriap.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 9c446a72ff1f..252f11012566 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -26,6 +26,7 @@ #include #include +#include #include #include diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 93d97d9f9da8..eaa0f8a1adb6 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 58522fc65d33..8996584b8499 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 501c564e247f..a98de0b54d65 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From f23f6e08c47acbdd20e9c49a79da8c404ea168e1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 20 Oct 2006 15:17:02 -0400 Subject: [PATCH] severing poll.h -> mm.h Signed-off-by: Al Viro --- drivers/char/hpet.c | 1 + drivers/media/dvb/cinergyT2/cinergyT2.c | 1 + include/linux/poll.h | 3 ++- include/sound/pcm.h | 1 + sound/oss/cs46xx.c | 1 + sound/oss/dmabuf.c | 1 + sound/oss/emu10k1/audio.c | 1 + sound/oss/es1371.c | 1 + sound/oss/i810_audio.c | 1 + sound/oss/soundcard.c | 1 + sound/oss/sscape.c | 1 + sound/oss/trident.c | 1 + 12 files changed, 13 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 091a11cd878c..20dc3be5ecfc 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 55bc891768c2..8a7dd507cf6e 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "dmxdev.h" #include "dvb_demux.h" diff --git a/include/linux/poll.h b/include/linux/poll.h index 51e1b56741fb..27690798623f 100644 --- a/include/linux/poll.h +++ b/include/linux/poll.h @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include /* ~832 bytes of stack space used max in sys_select/sys_poll before allocating diff --git a/include/sound/pcm.h b/include/sound/pcm.h index afaf3e88e086..2f645dfd7f70 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #define snd_pcm_substream_chip(substream) ((substream)->private_data) diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c index b1c5d8286e40..147c8a951137 100644 --- a/sound/oss/cs46xx.c +++ b/sound/oss/cs46xx.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c index b256c0401161..eaf69971bf92 100644 --- a/sound/oss/dmabuf.c +++ b/sound/oss/dmabuf.c @@ -25,6 +25,7 @@ #define BE_CONSERVATIVE #define SAMPLE_ROUNDUP 0 +#include #include "sound_config.h" #define DMAP_FREE_ON_CLOSE 0 diff --git a/sound/oss/emu10k1/audio.c b/sound/oss/emu10k1/audio.c index cde4d59d5430..86dd23974e05 100644 --- a/sound/oss/emu10k1/audio.c +++ b/sound/oss/emu10k1/audio.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "hwaccess.h" diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c index ddf6b0a0bca5..cc282a0cd539 100644 --- a/sound/oss/es1371.c +++ b/sound/oss/es1371.c @@ -130,6 +130,7 @@ #include #include #include +#include #include #include diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c index 240cc7939b69..c3c8a720d555 100644 --- a/sound/oss/i810_audio.c +++ b/sound/oss/i810_audio.c @@ -101,6 +101,7 @@ #include #include #include +#include #include diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 75c5e745705f..8fb8e7f99556 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -42,6 +42,7 @@ #include #include #include +#include /* * This ought to be moved into include/asm/dma.h diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c index 51f2fa615413..30c36d1f35d7 100644 --- a/sound/oss/sscape.c +++ b/sound/oss/sscape.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "coproc.h" diff --git a/sound/oss/trident.c b/sound/oss/trident.c index 7a363a178afd..6b1f8c9cdcf8 100644 --- a/sound/oss/trident.c +++ b/sound/oss/trident.c @@ -216,6 +216,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From bf1ab978be2318c5a564de9aa0f1a217b44170d4 Mon Sep 17 00:00:00 2001 From: Dwayne Grant McConnell Date: Thu, 23 Nov 2006 00:46:37 +0100 Subject: [POWERPC] coredump: Add SPU elf notes to coredump. This patch adds SPU elf notes to the coredump. It creates a separate note for each of /regs, /fpcr, /lslr, /decr, /decr_status, /mem, /signal1, /signal1_type, /signal2, /signal2_type, /event_mask, /event_status, /mbox_info, /ibox_info, /wbox_info, /dma_info, /proxydma_info, /object-id. A new macro, ARCH_HAVE_EXTRA_NOTES, was created for architectures to specify they have extra elf core notes. A new macro, ELF_CORE_EXTRA_NOTES_SIZE, was created so the size of the additional notes could be calculated and added to the notes phdr entry. A new macro, ELF_CORE_WRITE_EXTRA_NOTES, was created so the new notes would be written after the existing notes. The SPU coredump code resides in spufs. Stub functions are provided in the kernel which are hooked into the spufs code which does the actual work via register_arch_coredump_calls(). A new set of __spufs__read/get() functions was provided to allow the coredump code to read from the spufs files without having to lock the SPU context for each file read from. Cc: Signed-off-by: Dwayne Grant McConnell Signed-off-by: Arnd Bergmann --- arch/powerpc/platforms/cell/Makefile | 1 + arch/powerpc/platforms/cell/spu_coredump.c | 81 +++++++ arch/powerpc/platforms/cell/spufs/Makefile | 2 +- arch/powerpc/platforms/cell/spufs/coredump.c | 238 +++++++++++++++++++ arch/powerpc/platforms/cell/spufs/file.c | 327 ++++++++++++++++++++------- arch/powerpc/platforms/cell/spufs/inode.c | 7 + arch/powerpc/platforms/cell/spufs/spufs.h | 11 + fs/binfmt_elf.c | 8 + include/asm-powerpc/elf.h | 13 ++ include/asm-powerpc/spu.h | 10 + include/linux/elf.h | 7 + 11 files changed, 618 insertions(+), 87 deletions(-) create mode 100644 arch/powerpc/platforms/cell/spu_coredump.c create mode 100644 arch/powerpc/platforms/cell/spufs/coredump.c (limited to 'include/linux') diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index 62c011e80929..f90e8337796c 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -15,5 +15,6 @@ spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ + spu_coredump.o \ $(spufs-modular-m) \ $(spu-priv1-y) spufs/ diff --git a/arch/powerpc/platforms/cell/spu_coredump.c b/arch/powerpc/platforms/cell/spu_coredump.c new file mode 100644 index 000000000000..6915b418ee73 --- /dev/null +++ b/arch/powerpc/platforms/cell/spu_coredump.c @@ -0,0 +1,81 @@ +/* + * SPU core dump code + * + * (C) Copyright 2006 IBM Corp. + * + * Author: Dwayne Grant McConnell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include + +static struct spu_coredump_calls spu_coredump_calls; +static DEFINE_MUTEX(spu_coredump_mutex); + +int arch_notes_size(void) +{ + long ret; + struct module *owner = spu_coredump_calls.owner; + + ret = -ENOSYS; + mutex_lock(&spu_coredump_mutex); + if (owner && try_module_get(owner)) { + ret = spu_coredump_calls.arch_notes_size(); + module_put(owner); + } + mutex_unlock(&spu_coredump_mutex); + return ret; +} + +void arch_write_notes(struct file *file) +{ + struct module *owner = spu_coredump_calls.owner; + + mutex_lock(&spu_coredump_mutex); + if (owner && try_module_get(owner)) { + spu_coredump_calls.arch_write_notes(file); + module_put(owner); + } + mutex_unlock(&spu_coredump_mutex); +} + +int register_arch_coredump_calls(struct spu_coredump_calls *calls) +{ + if (spu_coredump_calls.owner) + return -EBUSY; + + mutex_lock(&spu_coredump_mutex); + spu_coredump_calls.arch_notes_size = calls->arch_notes_size; + spu_coredump_calls.arch_write_notes = calls->arch_write_notes; + spu_coredump_calls.owner = calls->owner; + mutex_unlock(&spu_coredump_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(register_arch_coredump_calls); + +void unregister_arch_coredump_calls(struct spu_coredump_calls *calls) +{ + BUG_ON(spu_coredump_calls.owner != calls->owner); + + mutex_lock(&spu_coredump_mutex); + spu_coredump_calls.owner = NULL; + mutex_unlock(&spu_coredump_mutex); +} +EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls); diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index ecdfbb35f82e..472217d19faf 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -1,7 +1,7 @@ obj-y += switch.o obj-$(CONFIG_SPU_FS) += spufs.o -spufs-y += inode.o file.o context.o syscalls.o +spufs-y += inode.o file.o context.o syscalls.o coredump.o spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o # Rules to build switch.o with the help of SPU tool chain diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c new file mode 100644 index 000000000000..26945c491f6b --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -0,0 +1,238 @@ +/* + * SPU core dump code + * + * (C) Copyright 2006 IBM Corp. + * + * Author: Dwayne Grant McConnell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "spufs.h" + +struct spufs_ctx_info { + struct list_head list; + int dfd; + int memsize; /* in bytes */ + struct spu_context *ctx; +}; + +static LIST_HEAD(ctx_info_list); + +static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *buffer, + size_t size, loff_t *off) +{ + u64 data; + int ret; + + if (spufs_coredump_read[num].read) + return spufs_coredump_read[num].read(ctx, buffer, size, off); + + data = spufs_coredump_read[num].get(ctx); + ret = copy_to_user(buffer, &data, 8); + return ret ? -EFAULT : 8; +} + +/* + * These are the only things you should do on a core-file: use only these + * functions to write out all the necessary info. + */ +static int spufs_dump_write(struct file *file, const void *addr, int nr) +{ + return file->f_op->write(file, addr, nr, &file->f_pos) == nr; +} + +static int spufs_dump_seek(struct file *file, loff_t off) +{ + if (file->f_op->llseek) { + if (file->f_op->llseek(file, off, 0) != off) + return 0; + } else + file->f_pos = off; + return 1; +} + +static void spufs_fill_memsize(struct spufs_ctx_info *ctx_info) +{ + struct spu_context *ctx; + unsigned long long lslr; + + ctx = ctx_info->ctx; + lslr = ctx->csa.priv2.spu_lslr_RW; + ctx_info->memsize = lslr + 1; +} + +static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info) +{ + int dfd, memsize, i, sz, total = 0; + char *name; + char fullname[80]; + + dfd = ctx_info->dfd; + memsize = ctx_info->memsize; + + for (i = 0; spufs_coredump_read[i].name; i++) { + name = spufs_coredump_read[i].name; + sz = spufs_coredump_read[i].size; + + sprintf(fullname, "SPU/%d/%s", dfd, name); + + total += sizeof(struct elf_note); + total += roundup(strlen(fullname) + 1, 4); + if (!strcmp(name, "mem")) + total += roundup(memsize, 4); + else + total += roundup(sz, 4); + } + + return total; +} + +static int spufs_add_one_context(struct file *file, int dfd) +{ + struct spu_context *ctx; + struct spufs_ctx_info *ctx_info; + int size; + + ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx; + if (ctx->flags & SPU_CREATE_NOSCHED) + return 0; + + ctx_info = kzalloc(sizeof(*ctx_info), GFP_KERNEL); + if (unlikely(!ctx_info)) + return -ENOMEM; + + ctx_info->dfd = dfd; + ctx_info->ctx = ctx; + + spufs_fill_memsize(ctx_info); + + size = spufs_ctx_note_size(ctx_info); + list_add(&ctx_info->list, &ctx_info_list); + return size; +} + +/* + * The additional architecture-specific notes for Cell are various + * context files in the spu context. + * + * This function iterates over all open file descriptors and sees + * if they are a directory in spufs. In that case we use spufs + * internal functionality to dump them without needing to actually + * open the files. + */ +static int spufs_arch_notes_size(void) +{ + struct fdtable *fdt = files_fdtable(current->files); + int size = 0, fd; + + for (fd = 0; fd < fdt->max_fdset && fd < fdt->max_fds; fd++) { + if (FD_ISSET(fd, fdt->open_fds)) { + struct file *file = fcheck(fd); + + if (file && file->f_op == &spufs_context_fops) { + int rval = spufs_add_one_context(file, fd); + if (rval < 0) + break; + size += rval; + } + } + } + + return size; +} + +static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, + struct file *file) +{ + struct spu_context *ctx; + loff_t pos = 0; + int sz, dfd, rc, total = 0; + const int bufsz = 4096; + char *name; + char fullname[80], *buf; + struct elf_note en; + + buf = kmalloc(bufsz, GFP_KERNEL); + if (!buf) + return; + + dfd = ctx_info->dfd; + name = spufs_coredump_read[i].name; + + if (!strcmp(name, "mem")) + sz = ctx_info->memsize; + else + sz = spufs_coredump_read[i].size; + + ctx = ctx_info->ctx; + if (!ctx) { + return; + } + + sprintf(fullname, "SPU/%d/%s", dfd, name); + en.n_namesz = strlen(fullname) + 1; + en.n_descsz = sz; + en.n_type = NT_SPU; + + if (!spufs_dump_write(file, &en, sizeof(en))) + return; + if (!spufs_dump_write(file, fullname, en.n_namesz)) + return; + if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4))) + return; + + do { + rc = do_coredump_read(i, ctx, buf, bufsz, &pos); + if (rc > 0) { + if (!spufs_dump_write(file, buf, rc)) + return; + total += rc; + } + } while (rc == bufsz && total < sz); + + spufs_dump_seek(file, roundup((unsigned long)file->f_pos + - total + sz, 4)); +} + +static void spufs_arch_write_notes(struct file *file) +{ + int j; + struct spufs_ctx_info *ctx_info, *next; + + list_for_each_entry_safe(ctx_info, next, &ctx_info_list, list) { + spu_acquire_saved(ctx_info->ctx); + for (j = 0; j < spufs_coredump_num_notes; j++) + spufs_arch_write_note(ctx_info, j, file); + spu_release(ctx_info->ctx); + list_del(&ctx_info->list); + kfree(ctx_info); + } +} + +struct spu_coredump_calls spufs_coredump_calls = { + .arch_notes_size = spufs_arch_notes_size, + .arch_write_notes = spufs_arch_write_notes, + .owner = THIS_MODULE, +}; diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 50e0afc46ad2..347eff56fcbd 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -39,7 +39,6 @@ #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) - static int spufs_mem_open(struct inode *inode, struct file *file) { @@ -51,19 +50,24 @@ spufs_mem_open(struct inode *inode, struct file *file) return 0; } +static ssize_t +__spufs_mem_read(struct spu_context *ctx, char __user *buffer, + size_t size, loff_t *pos) +{ + char *local_store = ctx->ops->get_ls(ctx); + return simple_read_from_buffer(buffer, size, pos, local_store, + LS_SIZE); +} + static ssize_t spufs_mem_read(struct file *file, char __user *buffer, size_t size, loff_t *pos) { - struct spu_context *ctx = file->private_data; - char *local_store; int ret; + struct spu_context *ctx = file->private_data; spu_acquire(ctx); - - local_store = ctx->ops->get_ls(ctx); - ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE); - + ret = __spufs_mem_read(ctx, buffer, size, pos); spu_release(ctx); return ret; } @@ -261,19 +265,24 @@ spufs_regs_open(struct inode *inode, struct file *file) return 0; } +static ssize_t +__spufs_regs_read(struct spu_context *ctx, char __user *buffer, + size_t size, loff_t *pos) +{ + struct spu_lscsa *lscsa = ctx->csa.lscsa; + return simple_read_from_buffer(buffer, size, pos, + lscsa->gprs, sizeof lscsa->gprs); +} + static ssize_t spufs_regs_read(struct file *file, char __user *buffer, size_t size, loff_t *pos) { - struct spu_context *ctx = file->private_data; - struct spu_lscsa *lscsa = ctx->csa.lscsa; int ret; + struct spu_context *ctx = file->private_data; spu_acquire_saved(ctx); - - ret = simple_read_from_buffer(buffer, size, pos, - lscsa->gprs, sizeof lscsa->gprs); - + ret = __spufs_regs_read(ctx, buffer, size, pos); spu_release(ctx); return ret; } @@ -307,19 +316,24 @@ static struct file_operations spufs_regs_fops = { .llseek = generic_file_llseek, }; +static ssize_t +__spufs_fpcr_read(struct spu_context *ctx, char __user * buffer, + size_t size, loff_t * pos) +{ + struct spu_lscsa *lscsa = ctx->csa.lscsa; + return simple_read_from_buffer(buffer, size, pos, + &lscsa->fpcr, sizeof(lscsa->fpcr)); +} + static ssize_t spufs_fpcr_read(struct file *file, char __user * buffer, size_t size, loff_t * pos) { - struct spu_context *ctx = file->private_data; - struct spu_lscsa *lscsa = ctx->csa.lscsa; int ret; + struct spu_context *ctx = file->private_data; spu_acquire_saved(ctx); - - ret = simple_read_from_buffer(buffer, size, pos, - &lscsa->fpcr, sizeof(lscsa->fpcr)); - + ret = __spufs_fpcr_read(ctx, buffer, size, pos); spu_release(ctx); return ret; } @@ -719,22 +733,19 @@ static int spufs_signal1_open(struct inode *inode, struct file *file) return nonseekable_open(inode, file); } -static ssize_t spufs_signal1_read(struct file *file, char __user *buf, +static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx = file->private_data; int ret = 0; u32 data; if (len < 4) return -EINVAL; - spu_acquire_saved(ctx); if (ctx->csa.spu_chnlcnt_RW[3]) { data = ctx->csa.spu_chnldata_RW[3]; ret = 4; } - spu_release(ctx); if (!ret) goto out; @@ -746,6 +757,19 @@ out: return ret; } +static ssize_t spufs_signal1_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + int ret; + struct spu_context *ctx = file->private_data; + + spu_acquire_saved(ctx); + ret = __spufs_signal1_read(ctx, buf, len, pos); + spu_release(ctx); + + return ret; +} + static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, size_t len, loff_t *pos) { @@ -816,22 +840,19 @@ static int spufs_signal2_open(struct inode *inode, struct file *file) return nonseekable_open(inode, file); } -static ssize_t spufs_signal2_read(struct file *file, char __user *buf, +static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx = file->private_data; int ret = 0; u32 data; if (len < 4) return -EINVAL; - spu_acquire_saved(ctx); if (ctx->csa.spu_chnlcnt_RW[4]) { data = ctx->csa.spu_chnldata_RW[4]; ret = 4; } - spu_release(ctx); if (!ret) goto out; @@ -840,7 +861,20 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf, return -EFAULT; out: - return 4; + return ret; +} + +static ssize_t spufs_signal2_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx = file->private_data; + int ret; + + spu_acquire_saved(ctx); + ret = __spufs_signal2_read(ctx, buf, len, pos); + spu_release(ctx); + + return ret; } static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, @@ -916,13 +950,19 @@ static void spufs_signal1_type_set(void *data, u64 val) spu_release(ctx); } +static u64 __spufs_signal1_type_get(void *data) +{ + struct spu_context *ctx = data; + return ctx->ops->signal1_type_get(ctx); +} + static u64 spufs_signal1_type_get(void *data) { struct spu_context *ctx = data; u64 ret; spu_acquire(ctx); - ret = ctx->ops->signal1_type_get(ctx); + ret = __spufs_signal1_type_get(data); spu_release(ctx); return ret; @@ -939,13 +979,19 @@ static void spufs_signal2_type_set(void *data, u64 val) spu_release(ctx); } +static u64 __spufs_signal2_type_get(void *data) +{ + struct spu_context *ctx = data; + return ctx->ops->signal2_type_get(ctx); +} + static u64 spufs_signal2_type_get(void *data) { struct spu_context *ctx = data; u64 ret; spu_acquire(ctx); - ret = ctx->ops->signal2_type_get(ctx); + ret = __spufs_signal2_type_get(data); spu_release(ctx); return ret; @@ -1387,13 +1433,19 @@ static void spufs_decr_set(void *data, u64 val) spu_release(ctx); } -static u64 spufs_decr_get(void *data) +static u64 __spufs_decr_get(void *data) { struct spu_context *ctx = data; struct spu_lscsa *lscsa = ctx->csa.lscsa; + return lscsa->decr.slot[0]; +} + +static u64 spufs_decr_get(void *data) +{ + struct spu_context *ctx = data; u64 ret; spu_acquire_saved(ctx); - ret = lscsa->decr.slot[0]; + ret = __spufs_decr_get(data); spu_release(ctx); return ret; } @@ -1409,13 +1461,19 @@ static void spufs_decr_status_set(void *data, u64 val) spu_release(ctx); } -static u64 spufs_decr_status_get(void *data) +static u64 __spufs_decr_status_get(void *data) { struct spu_context *ctx = data; struct spu_lscsa *lscsa = ctx->csa.lscsa; + return lscsa->decr_status.slot[0]; +} + +static u64 spufs_decr_status_get(void *data) +{ + struct spu_context *ctx = data; u64 ret; spu_acquire_saved(ctx); - ret = lscsa->decr_status.slot[0]; + ret = __spufs_decr_status_get(data); spu_release(ctx); return ret; } @@ -1431,30 +1489,43 @@ static void spufs_event_mask_set(void *data, u64 val) spu_release(ctx); } -static u64 spufs_event_mask_get(void *data) +static u64 __spufs_event_mask_get(void *data) { struct spu_context *ctx = data; struct spu_lscsa *lscsa = ctx->csa.lscsa; + return lscsa->event_mask.slot[0]; +} + +static u64 spufs_event_mask_get(void *data) +{ + struct spu_context *ctx = data; u64 ret; spu_acquire_saved(ctx); - ret = lscsa->event_mask.slot[0]; + ret = __spufs_event_mask_get(data); spu_release(ctx); return ret; } DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, spufs_event_mask_set, "0x%llx\n") -static u64 spufs_event_status_get(void *data) +static u64 __spufs_event_status_get(void *data) { struct spu_context *ctx = data; struct spu_state *state = &ctx->csa; - u64 ret = 0; u64 stat; - - spu_acquire_saved(ctx); stat = state->spu_chnlcnt_RW[0]; if (stat) - ret = state->spu_chnldata_RW[0]; + return state->spu_chnldata_RW[0]; + return 0; +} + +static u64 spufs_event_status_get(void *data) +{ + struct spu_context *ctx = data; + u64 ret = 0; + + spu_acquire_saved(ctx); + ret = __spufs_event_status_get(data); spu_release(ctx); return ret; } @@ -1499,12 +1570,18 @@ static u64 spufs_id_get(void *data) } DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n") -static u64 spufs_object_id_get(void *data) +static u64 __spufs_object_id_get(void *data) { struct spu_context *ctx = data; return ctx->object_id; } +static u64 spufs_object_id_get(void *data) +{ + /* FIXME: Should there really be no locking here? */ + return __spufs_object_id_get(data); +} + static void spufs_object_id_set(void *data, u64 id) { struct spu_context *ctx = data; @@ -1514,13 +1591,19 @@ static void spufs_object_id_set(void *data, u64 id) DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, spufs_object_id_set, "0x%llx\n"); +static u64 __spufs_lslr_get(void *data) +{ + struct spu_context *ctx = data; + return ctx->csa.priv2.spu_lslr_RW; +} + static u64 spufs_lslr_get(void *data) { struct spu_context *ctx = data; u64 ret; spu_acquire_saved(ctx); - ret = ctx->csa.priv2.spu_lslr_RW; + ret = __spufs_lslr_get(data); spu_release(ctx); return ret; @@ -1535,26 +1618,36 @@ static int spufs_info_open(struct inode *inode, struct file *file) return 0; } +static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, + char __user *buf, size_t len, loff_t *pos) +{ + u32 mbox_stat; + u32 data; + + mbox_stat = ctx->csa.prob.mb_stat_R; + if (mbox_stat & 0x0000ff) { + data = ctx->csa.prob.pu_mb_R; + } + + return simple_read_from_buffer(buf, len, pos, &data, sizeof data); +} + static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { + int ret; struct spu_context *ctx = file->private_data; - u32 mbox_stat; - u32 data; if (!access_ok(VERIFY_WRITE, buf, len)) return -EFAULT; spu_acquire_saved(ctx); spin_lock(&ctx->csa.register_lock); - mbox_stat = ctx->csa.prob.mb_stat_R; - if (mbox_stat & 0x0000ff) { - data = ctx->csa.prob.pu_mb_R; - } + ret = __spufs_mbox_info_read(ctx, buf, len, pos); spin_unlock(&ctx->csa.register_lock); spu_release(ctx); - return simple_read_from_buffer(buf, len, pos, &data, sizeof data); + return ret; } static struct file_operations spufs_mbox_info_fops = { @@ -1563,26 +1656,36 @@ static struct file_operations spufs_mbox_info_fops = { .llseek = generic_file_llseek, }; +static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, + char __user *buf, size_t len, loff_t *pos) +{ + u32 ibox_stat; + u32 data; + + ibox_stat = ctx->csa.prob.mb_stat_R; + if (ibox_stat & 0xff0000) { + data = ctx->csa.priv2.puint_mb_R; + } + + return simple_read_from_buffer(buf, len, pos, &data, sizeof data); +} + static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx = file->private_data; - u32 ibox_stat; - u32 data; + int ret; if (!access_ok(VERIFY_WRITE, buf, len)) return -EFAULT; spu_acquire_saved(ctx); spin_lock(&ctx->csa.register_lock); - ibox_stat = ctx->csa.prob.mb_stat_R; - if (ibox_stat & 0xff0000) { - data = ctx->csa.priv2.puint_mb_R; - } + ret = __spufs_ibox_info_read(ctx, buf, len, pos); spin_unlock(&ctx->csa.register_lock); spu_release(ctx); - return simple_read_from_buffer(buf, len, pos, &data, sizeof data); + return ret; } static struct file_operations spufs_ibox_info_fops = { @@ -1591,29 +1694,39 @@ static struct file_operations spufs_ibox_info_fops = { .llseek = generic_file_llseek, }; -static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, - size_t len, loff_t *pos) +static ssize_t __spufs_wbox_info_read(struct spu_context *ctx, + char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx = file->private_data; int i, cnt; u32 data[4]; u32 wbox_stat; + wbox_stat = ctx->csa.prob.mb_stat_R; + cnt = 4 - ((wbox_stat & 0x00ff00) >> 8); + for (i = 0; i < cnt; i++) { + data[i] = ctx->csa.spu_mailbox_data[i]; + } + + return simple_read_from_buffer(buf, len, pos, &data, + cnt * sizeof(u32)); +} + +static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx = file->private_data; + int ret; + if (!access_ok(VERIFY_WRITE, buf, len)) return -EFAULT; spu_acquire_saved(ctx); spin_lock(&ctx->csa.register_lock); - wbox_stat = ctx->csa.prob.mb_stat_R; - cnt = (wbox_stat & 0x00ff00) >> 8; - for (i = 0; i < cnt; i++) { - data[i] = ctx->csa.spu_mailbox_data[i]; - } + ret = __spufs_wbox_info_read(ctx, buf, len, pos); spin_unlock(&ctx->csa.register_lock); spu_release(ctx); - return simple_read_from_buffer(buf, len, pos, &data, - cnt * sizeof(u32)); + return ret; } static struct file_operations spufs_wbox_info_fops = { @@ -1622,19 +1735,13 @@ static struct file_operations spufs_wbox_info_fops = { .llseek = generic_file_llseek, }; -static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, - size_t len, loff_t *pos) +static ssize_t __spufs_dma_info_read(struct spu_context *ctx, + char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx = file->private_data; struct spu_dma_info info; struct mfc_cq_sr *qp, *spuqp; int i; - if (!access_ok(VERIFY_WRITE, buf, len)) - return -EFAULT; - - spu_acquire_saved(ctx); - spin_lock(&ctx->csa.register_lock); info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; info.dma_info_status = ctx->csa.spu_chnldata_RW[24]; @@ -1649,25 +1756,40 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; } - spin_unlock(&ctx->csa.register_lock); - spu_release(ctx); return simple_read_from_buffer(buf, len, pos, &info, sizeof info); } +static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx = file->private_data; + int ret; + + if (!access_ok(VERIFY_WRITE, buf, len)) + return -EFAULT; + + spu_acquire_saved(ctx); + spin_lock(&ctx->csa.register_lock); + ret = __spufs_dma_info_read(ctx, buf, len, pos); + spin_unlock(&ctx->csa.register_lock); + spu_release(ctx); + + return ret; +} + static struct file_operations spufs_dma_info_fops = { .open = spufs_info_open, .read = spufs_dma_info_read, }; -static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, - size_t len, loff_t *pos) +static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, + char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx = file->private_data; struct spu_proxydma_info info; - int ret = sizeof info; struct mfc_cq_sr *qp, *puqp; + int ret = sizeof info; int i; if (len < ret) @@ -1676,8 +1798,6 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, if (!access_ok(VERIFY_WRITE, buf, len)) return -EFAULT; - spu_acquire_saved(ctx); - spin_lock(&ctx->csa.register_lock); info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; @@ -1690,12 +1810,23 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; } + + return simple_read_from_buffer(buf, len, pos, &info, + sizeof info); +} + +static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx = file->private_data; + int ret; + + spu_acquire_saved(ctx); + spin_lock(&ctx->csa.register_lock); + ret = __spufs_proxydma_info_read(ctx, buf, len, pos); spin_unlock(&ctx->csa.register_lock); spu_release(ctx); - if (copy_to_user(buf, &info, sizeof info)) - ret = -EFAULT; - return ret; } @@ -1760,3 +1891,27 @@ struct tree_descr spufs_dir_nosched_contents[] = { { "object-id", &spufs_object_id_ops, 0666, }, {}, }; + +struct spufs_coredump_reader spufs_coredump_read[] = { + { "regs", __spufs_regs_read, NULL, 128 * 16 }, + { "fpcr", __spufs_fpcr_read, NULL, 16 }, + { "lslr", NULL, __spufs_lslr_get, 11 }, + { "decr", NULL, __spufs_decr_get, 11 }, + { "decr_status", NULL, __spufs_decr_status_get, 11 }, + { "mem", __spufs_mem_read, NULL, 256 * 1024, }, + { "signal1", __spufs_signal1_read, NULL, 4 }, + { "signal1_type", NULL, __spufs_signal1_type_get, 2 }, + { "signal2", __spufs_signal2_read, NULL, 4 }, + { "signal2_type", NULL, __spufs_signal2_type_get, 2 }, + { "event_mask", NULL, __spufs_event_mask_get, 8 }, + { "event_status", NULL, __spufs_event_status_get, 8 }, + { "mbox_info", __spufs_mbox_info_read, NULL, 4 }, + { "ibox_info", __spufs_ibox_info_read, NULL, 4 }, + { "wbox_info", __spufs_wbox_info_read, NULL, 16 }, + { "dma_info", __spufs_dma_info_read, NULL, 69 * 8 }, + { "proxydma_info", __spufs_proxydma_info_read, NULL, 35 * 8 }, + { "object-id", NULL, __spufs_object_id_get, 19 }, + { }, +}; +int spufs_coredump_num_notes = ARRAY_SIZE(spufs_coredump_read) - 1; + diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index d5f0a21a19d8..a3ca06bd0ca1 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -232,6 +232,7 @@ struct file_operations spufs_context_fops = { .readdir = dcache_readdir, .fsync = simple_sync_file, }; +EXPORT_SYMBOL_GPL(spufs_context_fops); static int spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, @@ -647,6 +648,7 @@ static struct file_system_type spufs_type = { static int __init spufs_init(void) { int ret; + ret = -ENOMEM; spufs_inode_cache = kmem_cache_create("spufs_inode_cache", sizeof(struct spufs_inode_info), 0, @@ -662,10 +664,14 @@ static int __init spufs_init(void) if (ret) goto out_cache; ret = register_spu_syscalls(&spufs_calls); + if (ret) + goto out_fs; + ret = register_arch_coredump_calls(&spufs_coredump_calls); if (ret) goto out_fs; spufs_init_isolated_loader(); + return 0; out_fs: unregister_filesystem(&spufs_type); @@ -679,6 +685,7 @@ module_init(spufs_init); static void __exit spufs_exit(void) { spu_sched_exit(); + unregister_arch_coredump_calls(&spufs_coredump_calls); unregister_spu_syscalls(&spufs_calls); unregister_filesystem(&spufs_type); kmem_cache_destroy(spufs_inode_cache); diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 23d20f380560..70fb13395c04 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -223,4 +223,15 @@ void spufs_stop_callback(struct spu *spu); void spufs_mfc_callback(struct spu *spu); void spufs_dma_callback(struct spu *spu, int type); +extern struct spu_coredump_calls spufs_coredump_calls; +struct spufs_coredump_reader { + char *name; + ssize_t (*read)(struct spu_context *ctx, + char __user *buffer, size_t size, loff_t *pos); + u64 (*get)(void *data); + size_t size; +}; +extern struct spufs_coredump_reader spufs_coredump_read[]; +extern int spufs_coredump_num_notes; + #endif diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 79b05a1a4365..cc72bb43061d 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1582,6 +1582,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) sz += thread_status_size; +#ifdef ELF_CORE_WRITE_EXTRA_NOTES + sz += ELF_CORE_EXTRA_NOTES_SIZE; +#endif + fill_elf_note_phdr(&phdr, sz, offset); offset += sz; DUMP_WRITE(&phdr, sizeof(phdr)); @@ -1622,6 +1626,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) if (!writenote(notes + i, file, &foffset)) goto end_coredump; +#ifdef ELF_CORE_WRITE_EXTRA_NOTES + ELF_CORE_WRITE_EXTRA_NOTES; +#endif + /* write out the thread status notes section */ list_for_each(t, &thread_list) { struct elf_thread_status *tmp = diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h index 9a83a987d396..4545aa682509 100644 --- a/include/asm-powerpc/elf.h +++ b/include/asm-powerpc/elf.h @@ -411,4 +411,17 @@ do { \ /* Keep this the last entry. */ #define R_PPC64_NUM 107 +#ifdef CONFIG_PPC_CELL +/* Notes used in ET_CORE. Note name is "SPU//". */ +#define NT_SPU 1 + +extern int arch_notes_size(void); +extern void arch_write_notes(struct file *file); + +#define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size() +#define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file) + +#define ARCH_HAVE_EXTRA_ELF_NOTES +#endif /* CONFIG_PPC_CELL */ + #endif /* _ASM_POWERPC_ELF_H */ diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index ffa4df083609..f968f8697538 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -172,6 +172,13 @@ extern struct spufs_calls { struct module *owner; } spufs_calls; +/* coredump calls implemented in spufs */ +struct spu_coredump_calls { + asmlinkage int (*arch_notes_size)(void); + asmlinkage void (*arch_write_notes)(struct file *file); + struct module *owner; +}; + /* return status from spu_run, same as in libspe */ #define SPE_EVENT_DMA_ALIGNMENT 0x0008 /*A DMA alignment error */ #define SPE_EVENT_SPE_ERROR 0x0010 /*An illegal instruction error*/ @@ -203,6 +210,9 @@ static inline void unregister_spu_syscalls(struct spufs_calls *calls) } #endif /* MODULE */ +int register_arch_coredump_calls(struct spu_coredump_calls *calls); +void unregister_arch_coredump_calls(struct spu_coredump_calls *calls); + int spu_add_sysdev_attr(struct sysdev_attribute *attr); void spu_remove_sysdev_attr(struct sysdev_attribute *attr); diff --git a/include/linux/elf.h b/include/linux/elf.h index b70d1d2c8d28..743d5c8e6d36 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -368,5 +368,12 @@ extern Elf64_Dyn _DYNAMIC []; #endif +#ifndef ARCH_HAVE_EXTRA_ELF_NOTES +static inline int arch_notes_size(void) { return 0; } +static inline void arch_write_notes(struct file *file) { } + +#define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size() +#define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file) +#endif /* ARCH_HAVE_EXTRA_ELF_NOTES */ #endif /* _LINUX_ELF_H */ -- cgit v1.2.3 From 0c789ff64e874bbece03b607f200566ab24ea9ab Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 4 Dec 2006 10:52:29 -0800 Subject: netfilter.h needs rcuupdate.h for RCU locking functions This was exposed by Al's recent header file dependency reduction patches.. Cc: Al Viro Cc: David S. Miller Signed-off-by: Linus Torvalds --- include/linux/netfilter.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index d4c4c5120bc0..9389cf7d4062 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -11,6 +11,7 @@ #include #endif #include +#include /* Responses from hook functions. */ #define NF_DROP 0 -- cgit v1.2.3 From a80958f4849316a18c06f75b9e850ccecbf20df8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 4 Dec 2006 20:41:19 +0000 Subject: [PATCH] fix fallout from header dependency trimming OK, that seems to be enough to deal with the mess. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/kernelcapi.h | 1 + include/linux/netfilter.h | 1 - include/linux/skbuff.h | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h index f8a0ff86dacc..aea34e74c496 100644 --- a/include/linux/kernelcapi.h +++ b/include/linux/kernelcapi.h @@ -48,6 +48,7 @@ typedef struct kcapi_carddef { #include #include #include +#include #define KCI_CONTRUP 0 /* arg: struct capi_profile */ #define KCI_CONTRDOWN 1 /* arg: NULL */ diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 9389cf7d4062..d4c4c5120bc0 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -11,7 +11,6 @@ #include #endif #include -#include /* Responses from hook functions. */ #define NF_DROP 0 diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 6bdff9b148d0..a05a5f7c0b73 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #define HAVE_ALLOC_SKB /* For the drivers to know */ -- cgit v1.2.3 From e62438630ca37539c8cc1553710bbfaa3cf960a7 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 4 Dec 2006 03:38:31 -0700 Subject: [PATCH] Centralise definitions of sector_t and blkcnt_t CONFIG_LBD and CONFIG_LSF are spread into asm/types.h for no particularly good reason. Centralising the definition in linux/types.h means that arch maintainers don't need to bother adding it, as well as fixing the problem with x86-64 users being asked to make a decision that has absolutely no effect. The H8/300 porters seem particularly confused since I'm not aware of any microcontrollers that need to support 2TB filesystems. Signed-off-by: Matthew Wilcox Signed-off-by: Linus Torvalds --- block/Kconfig | 6 ++---- include/asm-avr32/types.h | 5 ----- include/asm-h8300/types.h | 6 ------ include/asm-i386/types.h | 10 ---------- include/asm-mips/types.h | 10 ---------- include/asm-powerpc/types.h | 10 ---------- include/asm-s390/types.h | 10 ---------- include/asm-sh/types.h | 10 ---------- include/asm-x86_64/types.h | 3 --- include/linux/types.h | 14 +++++++++----- 10 files changed, 11 insertions(+), 73 deletions(-) (limited to 'include/linux') diff --git a/block/Kconfig b/block/Kconfig index 83766a6bdee2..a50f48111647 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -19,11 +19,9 @@ config BLOCK if BLOCK -#XXX - it makes sense to enable this only for 32-bit subarch's, not for x86_64 -#for instance. config LBD bool "Support for Large Block Devices" - depends on X86 || (MIPS && 32BIT) || PPC32 || (S390 && !64BIT) || SUPERH || UML + depends on !64BIT help Say Y here if you want to attach large (bigger than 2TB) discs to your machine, or if you want to have a raid or loopback device @@ -44,7 +42,7 @@ config BLK_DEV_IO_TRACE config LSF bool "Support for Large Single Files" - depends on X86 || (MIPS && 32BIT) || PPC32 || ARCH_S390_31 || SUPERH || UML + depends on !64BIT help Say Y here if you want to be able to handle very large files (bigger than 2TB), otherwise say N. diff --git a/include/asm-avr32/types.h b/include/asm-avr32/types.h index 3f47db9675af..2bff153a32ed 100644 --- a/include/asm-avr32/types.h +++ b/include/asm-avr32/types.h @@ -57,11 +57,6 @@ typedef unsigned long long u64; typedef u32 dma_addr_t; -#ifdef CONFIG_LBD -typedef u64 sector_t; -#define HAVE_SECTOR_T -#endif - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-h8300/types.h b/include/asm-h8300/types.h index da2402b86540..2a8b1b2be782 100644 --- a/include/asm-h8300/types.h +++ b/include/asm-h8300/types.h @@ -55,12 +55,6 @@ typedef unsigned long long u64; typedef u32 dma_addr_t; -#define HAVE_SECTOR_T -typedef u64 sector_t; - -#define HAVE_BLKCNT_T -typedef u64 blkcnt_t; - #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff --git a/include/asm-i386/types.h b/include/asm-i386/types.h index 4b4b295ccdb9..ad0a55bd782f 100644 --- a/include/asm-i386/types.h +++ b/include/asm-i386/types.h @@ -57,16 +57,6 @@ typedef u32 dma_addr_t; #endif typedef u64 dma64_addr_t; -#ifdef CONFIG_LBD -typedef u64 sector_t; -#define HAVE_SECTOR_T -#endif - -#ifdef CONFIG_LSF -typedef u64 blkcnt_t; -#define HAVE_BLKCNT_T -#endif - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-mips/types.h b/include/asm-mips/types.h index 2b52e180c6f2..63a13c5bd832 100644 --- a/include/asm-mips/types.h +++ b/include/asm-mips/types.h @@ -93,16 +93,6 @@ typedef unsigned long long phys_t; typedef unsigned long phys_t; #endif -#ifdef CONFIG_LBD -typedef u64 sector_t; -#define HAVE_SECTOR_T -#endif - -#ifdef CONFIG_LSF -typedef u64 blkcnt_t; -#define HAVE_BLKCNT_T -#endif - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/types.h b/include/asm-powerpc/types.h index d6fb56b80453..3b363757a2bb 100644 --- a/include/asm-powerpc/types.h +++ b/include/asm-powerpc/types.h @@ -97,16 +97,6 @@ typedef struct { unsigned long env; } func_descr_t; -#ifdef CONFIG_LBD -typedef u64 sector_t; -#define HAVE_SECTOR_T -#endif - -#ifdef CONFIG_LSF -typedef u64 blkcnt_t; -#define HAVE_BLKCNT_T -#endif - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-s390/types.h b/include/asm-s390/types.h index ae2951cc83ac..fc5d7cf19324 100644 --- a/include/asm-s390/types.h +++ b/include/asm-s390/types.h @@ -87,16 +87,6 @@ typedef union { } subreg; } register_pair; -#ifdef CONFIG_LBD -typedef u64 sector_t; -#define HAVE_SECTOR_T -#endif - -#ifdef CONFIG_LSF -typedef u64 blkcnt_t; -#define HAVE_BLKCNT_T -#endif - #endif /* ! __s390x__ */ #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-sh/types.h b/include/asm-sh/types.h index 3c09dd4ca31c..fd00dbb82f84 100644 --- a/include/asm-sh/types.h +++ b/include/asm-sh/types.h @@ -52,16 +52,6 @@ typedef unsigned long long u64; typedef u32 dma_addr_t; -#ifdef CONFIG_LBD -typedef u64 sector_t; -#define HAVE_SECTOR_T -#endif - -#ifdef CONFIG_LSF -typedef u64 blkcnt_t; -#define HAVE_BLKCNT_T -#endif - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-x86_64/types.h b/include/asm-x86_64/types.h index c86c2e6793e2..2d4491aae281 100644 --- a/include/asm-x86_64/types.h +++ b/include/asm-x86_64/types.h @@ -48,9 +48,6 @@ typedef unsigned long long u64; typedef u64 dma64_addr_t; typedef u64 dma_addr_t; -typedef u64 sector_t; -#define HAVE_SECTOR_T - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/include/linux/types.h b/include/linux/types.h index 745c409ebbb5..0351bf2fac85 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -136,15 +136,19 @@ typedef __s64 int64_t; * * Linux always considers sectors to be 512 bytes long independently * of the devices real block size. - * - * If required, asm/types.h can override it and define - * HAVE_SECTOR_T */ -#ifndef HAVE_SECTOR_T +#ifdef CONFIG_LBD +typedef u64 sector_t; +#else typedef unsigned long sector_t; #endif -#ifndef HAVE_BLKCNT_T +/* + * The type of the inode's block count. + */ +#ifdef CONFIG_LSF +typedef u64 blkcnt_t; +#else typedef unsigned long blkcnt_t; #endif -- cgit v1.2.3 From 6d5aefb8eaa38e44b5b8cf60c812aceafc02d924 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 5 Dec 2006 19:36:26 +0000 Subject: WorkQueue: Fix up arch-specific work items where possible Fix up arch-specific work items where possible to use the new work_struct and delayed_work structs. Three places that enqueue bits of their stack and then return have been marked with #error as this is not permitted. Signed-Off-By: David Howells --- arch/arm/common/sharpsl_pm.c | 22 +++++++++++----------- arch/arm/mach-omap1/board-h3.c | 3 ++- arch/arm/mach-omap1/board-nokia770.c | 6 +++--- arch/arm/mach-omap1/leds-osk.c | 4 ++-- arch/arm/mach-omap2/board-h4.c | 3 ++- arch/arm/mach-pxa/akita-ioexp.c | 6 +++--- arch/ia64/hp/sim/simserial.c | 4 ++-- arch/ia64/kernel/mca.c | 8 ++++---- arch/ia64/kernel/smpboot.c | 12 +++++++----- arch/mips/kernel/kspd.c | 4 ++-- arch/powerpc/platforms/embedded6xx/ls_uart.c | 4 ++-- arch/powerpc/platforms/powermac/backlight.c | 12 ++++++------ arch/ppc/8260_io/fcc_enet.c | 21 +++++++++++++-------- arch/ppc/8xx_io/fec.c | 21 +++++++++++++-------- arch/s390/appldata/appldata_base.c | 6 +++--- arch/um/drivers/chan_kern.c | 2 +- arch/um/drivers/mconsole_kern.c | 4 ++-- arch/um/drivers/net_kern.c | 1 + arch/um/drivers/port_kern.c | 4 ++-- drivers/macintosh/rack-meter.c | 16 ++++++++++------ drivers/net/chelsio/cphy.h | 2 +- drivers/net/chelsio/my3126.c | 8 +++++--- drivers/net/netxen/netxen_nic.h | 3 ++- drivers/net/netxen/netxen_nic_init.c | 5 +++-- drivers/net/netxen/netxen_nic_main.c | 19 ++++++++++--------- drivers/net/smc91x.c | 15 +++++++++------ drivers/net/wireless/zd1211rw/zd_mac.c | 23 +++++++++++++---------- drivers/net/wireless/zd1211rw/zd_mac.h | 4 ++-- drivers/spi/pxa2xx_spi.c | 9 +++++---- drivers/usb/core/hub.c | 2 +- drivers/usb/misc/appledisplay.c | 11 ++++++----- drivers/video/pxafb.c | 7 ++++--- include/asm-arm/arch-omap/irda.h | 2 +- include/linux/netpoll.h | 2 +- 34 files changed, 154 insertions(+), 121 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c index 605dedf96790..b3599743093b 100644 --- a/arch/arm/common/sharpsl_pm.c +++ b/arch/arm/common/sharpsl_pm.c @@ -60,16 +60,16 @@ static int sharpsl_ac_check(void); static int sharpsl_fatal_check(void); static int sharpsl_average_value(int ad); static void sharpsl_average_clear(void); -static void sharpsl_charge_toggle(void *private_); -static void sharpsl_battery_thread(void *private_); +static void sharpsl_charge_toggle(struct work_struct *private_); +static void sharpsl_battery_thread(struct work_struct *private_); /* * Variables */ struct sharpsl_pm_status sharpsl_pm; -DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL); -DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL); +DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle); +DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread); DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger); @@ -116,7 +116,7 @@ void sharpsl_battery_kick(void) EXPORT_SYMBOL(sharpsl_battery_kick); -static void sharpsl_battery_thread(void *private_) +static void sharpsl_battery_thread(struct work_struct *private_) { int voltage, percent, apm_status, i = 0; @@ -128,7 +128,7 @@ static void sharpsl_battery_thread(void *private_) /* Corgi cannot confirm when battery fully charged so periodically kick! */ if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON) && time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_ON_TIME_INTERVAL)) - schedule_work(&toggle_charger); + schedule_delayed_work(&toggle_charger, 0); while(1) { voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); @@ -212,7 +212,7 @@ static void sharpsl_charge_off(void) sharpsl_pm_led(SHARPSL_LED_OFF); sharpsl_pm.charge_mode = CHRG_OFF; - schedule_work(&sharpsl_bat); + schedule_delayed_work(&sharpsl_bat, 0); } static void sharpsl_charge_error(void) @@ -222,7 +222,7 @@ static void sharpsl_charge_error(void) sharpsl_pm.charge_mode = CHRG_ERROR; } -static void sharpsl_charge_toggle(void *private_) +static void sharpsl_charge_toggle(struct work_struct *private_) { dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies); @@ -254,7 +254,7 @@ static void sharpsl_ac_timer(unsigned long data) else if (sharpsl_pm.charge_mode == CHRG_ON) sharpsl_charge_off(); - schedule_work(&sharpsl_bat); + schedule_delayed_work(&sharpsl_bat, 0); } @@ -279,10 +279,10 @@ static void sharpsl_chrg_full_timer(unsigned long data) sharpsl_charge_off(); } else if (sharpsl_pm.full_count < 2) { dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n"); - schedule_work(&toggle_charger); + schedule_delayed_work(&toggle_charger, 0); } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) { dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n"); - schedule_work(&toggle_charger); + schedule_delayed_work(&toggle_charger, 0); } else { sharpsl_charge_off(); sharpsl_pm.charge_mode = CHRG_DONE; diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index f225a083dee1..9d2346fb68f4 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -323,7 +323,8 @@ static int h3_transceiver_mode(struct device *dev, int mode) cancel_delayed_work(&irda_config->gpio_expa); PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode); - schedule_work(&irda_config->gpio_expa); +#error this is not permitted - mode is an argument variable + schedule_delayed_work(&irda_config->gpio_expa, 0); return 0; } diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index dbc555d209ff..cbe909bad79b 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -74,7 +74,7 @@ static struct omap_kp_platform_data nokia770_kp_data = { .rows = 8, .cols = 8, .keymap = nokia770_keymap, - .keymapsize = ARRAY_SIZE(nokia770_keymap) + .keymapsize = ARRAY_SIZE(nokia770_keymap), .delay = 4, }; @@ -191,7 +191,7 @@ static void nokia770_audio_pwr_up(void) printk("HP connected\n"); } -static void codec_delayed_power_down(void *arg) +static void codec_delayed_power_down(struct work_struct *work) { down(&audio_pwr_sem); if (audio_pwr_state == -1) @@ -200,7 +200,7 @@ static void codec_delayed_power_down(void *arg) up(&audio_pwr_sem); } -static DECLARE_WORK(codec_power_down_work, codec_delayed_power_down, NULL); +static DECLARE_DELAYED_WORK(codec_power_down_work, codec_delayed_power_down); static void nokia770_audio_pwr_down(void) { diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c index 3b29e59b0e6f..0cbf1b0071f8 100644 --- a/arch/arm/mach-omap1/leds-osk.c +++ b/arch/arm/mach-omap1/leds-osk.c @@ -35,7 +35,7 @@ static u8 hw_led_state; static u8 tps_leds_change; -static void tps_work(void *unused) +static void tps_work(struct work_struct *unused) { for (;;) { u8 leds; @@ -61,7 +61,7 @@ static void tps_work(void *unused) } } -static DECLARE_WORK(work, tps_work, NULL); +static DECLARE_WORK(work, tps_work); #ifdef CONFIG_OMAP_OSK_MISTRAL diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index 26a95a642ad7..3b1ad1d981a3 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -206,7 +206,8 @@ static int h4_transceiver_mode(struct device *dev, int mode) cancel_delayed_work(&irda_config->gpio_expa); PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode); - schedule_work(&irda_config->gpio_expa); +#error this is not permitted - mode is an argument variable + schedule_delayed_work(&irda_config->gpio_expa, 0); return 0; } diff --git a/arch/arm/mach-pxa/akita-ioexp.c b/arch/arm/mach-pxa/akita-ioexp.c index 1b398742ab56..12d2fe0ceff6 100644 --- a/arch/arm/mach-pxa/akita-ioexp.c +++ b/arch/arm/mach-pxa/akita-ioexp.c @@ -36,11 +36,11 @@ I2C_CLIENT_INSMOD; static int max7310_write(struct i2c_client *client, int address, int data); static struct i2c_client max7310_template; -static void akita_ioexp_work(void *private_); +static void akita_ioexp_work(struct work_struct *private_); static struct device *akita_ioexp_device; static unsigned char ioexp_output_value = AKITA_IOEXP_IO_OUT; -DECLARE_WORK(akita_ioexp, akita_ioexp_work, NULL); +DECLARE_WORK(akita_ioexp, akita_ioexp_work); /* @@ -158,7 +158,7 @@ void akita_reset_ioexp(struct device *dev, unsigned char bit) EXPORT_SYMBOL(akita_set_ioexp); EXPORT_SYMBOL(akita_reset_ioexp); -static void akita_ioexp_work(void *private_) +static void akita_ioexp_work(struct work_struct *private_) { if (akita_ioexp_device) max7310_set_ouputs(akita_ioexp_device, ioexp_output_value); diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index caab986af70c..b62f0c4d2c7c 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -209,7 +209,7 @@ static void do_serial_bh(void) } #endif -static void do_softint(void *private_) +static void do_softint(struct work_struct *private_) { printk(KERN_ERR "simserial: do_softint called\n"); } @@ -698,7 +698,7 @@ static int get_async_struct(int line, struct async_struct **ret_info) info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; info->line = line; - INIT_WORK(&info->work, do_softint, info); + INIT_WORK(&info->work, do_softint); info->state = sstate; if (sstate->info) { kfree(info); diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 7cfa63a98cb3..6bedd97570ca 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -678,7 +678,7 @@ ia64_mca_cmc_vector_enable (void *dummy) * disable the cmc interrupt vector. */ static void -ia64_mca_cmc_vector_disable_keventd(void *unused) +ia64_mca_cmc_vector_disable_keventd(struct work_struct *unused) { on_each_cpu(ia64_mca_cmc_vector_disable, NULL, 1, 0); } @@ -690,7 +690,7 @@ ia64_mca_cmc_vector_disable_keventd(void *unused) * enable the cmc interrupt vector. */ static void -ia64_mca_cmc_vector_enable_keventd(void *unused) +ia64_mca_cmc_vector_enable_keventd(struct work_struct *unused) { on_each_cpu(ia64_mca_cmc_vector_enable, NULL, 1, 0); } @@ -1247,8 +1247,8 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, monarch_cpu = -1; } -static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd, NULL); -static DECLARE_WORK(cmc_enable_work, ia64_mca_cmc_vector_enable_keventd, NULL); +static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd); +static DECLARE_WORK(cmc_enable_work, ia64_mca_cmc_vector_enable_keventd); /* * ia64_mca_cmc_int_handler diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index f7d7f5668144..b21ddecea943 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -463,15 +463,17 @@ struct pt_regs * __devinit idle_regs(struct pt_regs *regs) } struct create_idle { + struct work_struct work; struct task_struct *idle; struct completion done; int cpu; }; void -do_fork_idle(void *_c_idle) +do_fork_idle(struct work_struct *work) { - struct create_idle *c_idle = _c_idle; + struct create_idle *c_idle = + container_of(work, struct create_idle, work); c_idle->idle = fork_idle(c_idle->cpu); complete(&c_idle->done); @@ -482,10 +484,10 @@ do_boot_cpu (int sapicid, int cpu) { int timeout; struct create_idle c_idle = { + .work = __WORK_INITIALIZER(c_idle.work, do_fork_idle), .cpu = cpu, .done = COMPLETION_INITIALIZER(c_idle.done), }; - DECLARE_WORK(work, do_fork_idle, &c_idle); c_idle.idle = get_idle_for_cpu(cpu); if (c_idle.idle) { @@ -497,9 +499,9 @@ do_boot_cpu (int sapicid, int cpu) * We can't use kernel_thread since we must avoid to reschedule the child. */ if (!keventd_up() || current_is_keventd()) - work.func(work.data); + c_idle.work.func(&c_idle.work); else { - schedule_work(&work); + schedule_work(&c_idle.work); wait_for_completion(&c_idle.done); } diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c index f06a144c7881..2c82412b9efe 100644 --- a/arch/mips/kernel/kspd.c +++ b/arch/mips/kernel/kspd.c @@ -319,7 +319,7 @@ static void sp_cleanup(void) static int channel_open = 0; /* the work handler */ -static void sp_work(void *data) +static void sp_work(struct work_struct *unused) { if (!channel_open) { if( rtlx_open(RTLX_CHANNEL_SYSIO, 1) != 0) { @@ -354,7 +354,7 @@ static void startwork(int vpe) return; } - INIT_WORK(&work, sp_work, NULL); + INIT_WORK(&work, sp_work); queue_work(workqueue, &work); } else queue_work(workqueue, &work); diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c index 31bcdae84823..0e837762cc5b 100644 --- a/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c @@ -14,7 +14,7 @@ static unsigned long avr_clock; static struct work_struct wd_work; -static void wd_stop(void *unused) +static void wd_stop(struct work_struct *unused) { const char string[] = "AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK"; int i = 0, rescue = 8; @@ -122,7 +122,7 @@ static int __init ls_uarts_init(void) ls_uart_init(); - INIT_WORK(&wd_work, wd_stop, NULL); + INIT_WORK(&wd_work, wd_stop); schedule_work(&wd_work); return 0; diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c index afa593a8544a..c3a89414ddc0 100644 --- a/arch/powerpc/platforms/powermac/backlight.c +++ b/arch/powerpc/platforms/powermac/backlight.c @@ -18,11 +18,11 @@ #define OLD_BACKLIGHT_MAX 15 -static void pmac_backlight_key_worker(void *data); -static void pmac_backlight_set_legacy_worker(void *data); +static void pmac_backlight_key_worker(struct work_struct *work); +static void pmac_backlight_set_legacy_worker(struct work_struct *work); -static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker, NULL); -static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker, NULL); +static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker); +static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker); /* Although these variables are used in interrupt context, it makes no sense to * protect them. No user is able to produce enough key events per second and @@ -94,7 +94,7 @@ int pmac_backlight_curve_lookup(struct fb_info *info, int value) return level; } -static void pmac_backlight_key_worker(void *data) +static void pmac_backlight_key_worker(struct work_struct *work) { if (atomic_read(&kernel_backlight_disabled)) return; @@ -166,7 +166,7 @@ static int __pmac_backlight_set_legacy_brightness(int brightness) return error; } -static void pmac_backlight_set_legacy_worker(void *data) +static void pmac_backlight_set_legacy_worker(struct work_struct *work) { if (atomic_read(&kernel_backlight_disabled)) return; diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c index 2e1943e27819..709952c25f29 100644 --- a/arch/ppc/8260_io/fcc_enet.c +++ b/arch/ppc/8260_io/fcc_enet.c @@ -385,6 +385,7 @@ struct fcc_enet_private { phy_info_t *phy; struct work_struct phy_relink; struct work_struct phy_display_config; + struct net_device *dev; uint sequence_done; @@ -1391,10 +1392,11 @@ static phy_info_t *phy_info[] = { NULL }; -static void mii_display_status(void *data) +static void mii_display_status(struct work_struct *work) { - struct net_device *dev = data; - volatile struct fcc_enet_private *fep = dev->priv; + volatile struct fcc_enet_private *fep = + container_of(work, struct fcc_enet_private, phy_relink); + struct net_device *dev = fep->dev; uint s = fep->phy_status; if (!fep->link && !fep->old_link) { @@ -1428,10 +1430,12 @@ static void mii_display_status(void *data) printk(".\n"); } -static void mii_display_config(void *data) +static void mii_display_config(struct work_struct *work) { - struct net_device *dev = data; - volatile struct fcc_enet_private *fep = dev->priv; + volatile struct fcc_enet_private *fep = + container_of(work, struct fcc_enet_private, + phy_display_config); + struct net_device *dev = fep->dev; uint s = fep->phy_status; printk("%s: config: auto-negotiation ", dev->name); @@ -1758,8 +1762,9 @@ static int __init fec_enet_init(void) cep->phy_id_done = 0; cep->phy_addr = fip->fc_phyaddr; mii_queue(dev, mk_mii_read(MII_PHYSID1), mii_discover_phy); - INIT_WORK(&cep->phy_relink, mii_display_status, dev); - INIT_WORK(&cep->phy_display_config, mii_display_config, dev); + INIT_WORK(&cep->phy_relink, mii_display_status); + INIT_WORK(&cep->phy_display_config, mii_display_config); + cep->dev = dev; #endif /* CONFIG_USE_MDIO */ fip++; diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c index 2f9fa9e3d331..e6c28fb423b2 100644 --- a/arch/ppc/8xx_io/fec.c +++ b/arch/ppc/8xx_io/fec.c @@ -173,6 +173,7 @@ struct fec_enet_private { uint phy_speed; phy_info_t *phy; struct work_struct phy_task; + struct net_device *dev; uint sequence_done; @@ -1263,10 +1264,11 @@ static void mii_display_status(struct net_device *dev) printk(".\n"); } -static void mii_display_config(void *priv) +static void mii_display_config(struct work_struct *work) { - struct net_device *dev = (struct net_device *)priv; - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = + container_of(work, struct fec_enet_private, phy_task); + struct net_device *dev = fep->dev; volatile uint *s = &(fep->phy_status); printk("%s: config: auto-negotiation ", dev->name); @@ -1295,10 +1297,11 @@ static void mii_display_config(void *priv) fep->sequence_done = 1; } -static void mii_relink(void *priv) +static void mii_relink(struct work_struct *work) { - struct net_device *dev = (struct net_device *)priv; - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = + container_of(work, struct fec_enet_private, phy_task); + struct net_device *dev = fep->dev; int duplex; fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; @@ -1325,7 +1328,8 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = dev->priv; - INIT_WORK(&fep->phy_task, mii_relink, (void *)dev); + fep->dev = dev; + INIT_WORK(&fep->phy_task, mii_relink); schedule_work(&fep->phy_task); } @@ -1333,7 +1337,8 @@ static void mii_queue_config(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = dev->priv; - INIT_WORK(&fep->phy_task, mii_display_config, (void *)dev); + fep->dev = dev; + INIT_WORK(&fep->phy_task, mii_display_config); schedule_work(&fep->phy_task); } diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index af1e8fc7d985..67d5cf9cba83 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -92,8 +92,8 @@ static int appldata_timer_active; * Work queue */ static struct workqueue_struct *appldata_wq; -static void appldata_work_fn(void *data); -static DECLARE_WORK(appldata_work, appldata_work_fn, NULL); +static void appldata_work_fn(struct work_struct *work); +static DECLARE_WORK(appldata_work, appldata_work_fn); /* @@ -125,7 +125,7 @@ static void appldata_timer_function(unsigned long data) * * call data gathering function for each (active) module */ -static void appldata_work_fn(void *data) +static void appldata_work_fn(struct work_struct *work) { struct list_head *lh; struct appldata_ops *ops; diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 3576b3cc505e..7d4190e55654 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -638,7 +638,7 @@ int chan_out_fd(struct list_head *chans) return -1; } -void chan_interrupt(struct list_head *chans, struct work_struct *task, +void chan_interrupt(struct list_head *chans, struct delayed_work *task, struct tty_struct *tty, int irq) { struct list_head *ele, *next; diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 7b172160fe04..96f0189327af 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -56,7 +56,7 @@ static struct notifier_block reboot_notifier = { static LIST_HEAD(mc_requests); -static void mc_work_proc(void *unused) +static void mc_work_proc(struct work_struct *unused) { struct mconsole_entry *req; unsigned long flags; @@ -72,7 +72,7 @@ static void mc_work_proc(void *unused) } } -static DECLARE_WORK(mconsole_work, mc_work_proc, NULL); +static DECLARE_WORK(mconsole_work, mc_work_proc); static irqreturn_t mconsole_interrupt(int irq, void *dev_id) { diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index ec9eb8bd9432..286bc0b3207f 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -99,6 +99,7 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id) * same device, since it tests for (dev->flags & IFF_UP). So * there's no harm in delaying the device shutdown. */ schedule_work(&close_work); +#error this is not permitted - close_work will go out of scope goto out; } reactivate_fd(lp->fd, UM_ETH_IRQ); diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index ce9f3733f73e..6dfe632f1c14 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -132,7 +132,7 @@ static int port_accept(struct port_list *port) DECLARE_MUTEX(ports_sem); struct list_head ports = LIST_HEAD_INIT(ports); -void port_work_proc(void *unused) +void port_work_proc(struct work_struct *unused) { struct port_list *port; struct list_head *ele; @@ -150,7 +150,7 @@ void port_work_proc(void *unused) local_irq_restore(flags); } -DECLARE_WORK(port_work, port_work_proc, NULL); +DECLARE_WORK(port_work, port_work_proc); static irqreturn_t port_interrupt(int irq, void *data) { diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index f1b6f563673a..5ed41fe84e57 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -48,7 +48,8 @@ struct rackmeter_dma { } ____cacheline_aligned; struct rackmeter_cpu { - struct work_struct sniffer; + struct delayed_work sniffer; + struct rackmeter *rm; cputime64_t prev_wall; cputime64_t prev_idle; int zero; @@ -208,11 +209,12 @@ static void rackmeter_setup_dbdma(struct rackmeter *rm) rackmeter_do_pause(rm, 0); } -static void rackmeter_do_timer(void *data) +static void rackmeter_do_timer(struct work_struct *work) { - struct rackmeter *rm = data; + struct rackmeter_cpu *rcpu = + container_of(work, struct rackmeter_cpu, sniffer.work); + struct rackmeter *rm = rcpu->rm; unsigned int cpu = smp_processor_id(); - struct rackmeter_cpu *rcpu = &rm->cpu[cpu]; cputime64_t cur_jiffies, total_idle_ticks; unsigned int total_ticks, idle_ticks; int i, offset, load, cumm, pause; @@ -263,8 +265,10 @@ static void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm) * on those machines yet */ - INIT_WORK(&rm->cpu[0].sniffer, rackmeter_do_timer, rm); - INIT_WORK(&rm->cpu[1].sniffer, rackmeter_do_timer, rm); + rm->cpu[0].rm = rm; + INIT_DELAYED_WORK(&rm->cpu[0].sniffer, rackmeter_do_timer); + rm->cpu[1].rm = rm; + INIT_DELAYED_WORK(&rm->cpu[1].sniffer, rackmeter_do_timer); for_each_online_cpu(cpu) { struct rackmeter_cpu *rcpu; diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h index 60901f25014e..cf9143499882 100644 --- a/drivers/net/chelsio/cphy.h +++ b/drivers/net/chelsio/cphy.h @@ -91,7 +91,7 @@ struct cphy { int state; /* Link status state machine */ adapter_t *adapter; /* associated adapter */ - struct work_struct phy_update; + struct delayed_work phy_update; u16 bmsr; int count; diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index 0b90014d5b3e..c7731b6f9de3 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c @@ -93,9 +93,11 @@ static int my3126_interrupt_handler(struct cphy *cphy) return cphy_cause_link_change; } -static void my3216_poll(void *arg) +static void my3216_poll(struct work_struct *work) { - my3126_interrupt_handler(arg); + struct cphy *cphy = container_of(work, struct cphy, phy_update.work); + + my3126_interrupt_handler(cphy); } static int my3126_set_loopback(struct cphy *cphy, int on) @@ -171,7 +173,7 @@ static struct cphy *my3126_phy_create(adapter_t *adapter, if (cphy) cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); - INIT_WORK(&cphy->phy_update, my3216_poll, cphy); + INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); cphy->bmsr = 0; return (cphy); diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d925053fe597..9c588af8ab74 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -714,6 +714,7 @@ struct netxen_adapter { spinlock_t lock; struct work_struct watchdog_task; struct work_struct tx_timeout_task; + struct net_device *netdev; struct timer_list watchdog_timer; u32 curr_window; @@ -921,7 +922,7 @@ netxen_nic_do_ioctl(struct netxen_adapter *adapter, void *u_data, struct netxen_port *port); int netxen_nic_rx_has_work(struct netxen_adapter *adapter); int netxen_nic_tx_has_work(struct netxen_adapter *adapter); -void netxen_watchdog_task(unsigned long v); +void netxen_watchdog_task(struct work_struct *work); void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid); void netxen_process_cmd_ring(unsigned long data); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 0dca029bc3e5..eae18236aefa 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -710,12 +710,13 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter) return rv; } -void netxen_watchdog_task(unsigned long v) +void netxen_watchdog_task(struct work_struct *work) { int port_num; struct netxen_port *port; struct net_device *netdev; - struct netxen_adapter *adapter = (struct netxen_adapter *)v; + struct netxen_adapter *adapter = + container_of(work, struct netxen_adapter, watchdog_task); if (netxen_nic_check_temp(adapter)) return; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 1cb662d5bd76..df0bb36a1cfb 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -64,7 +64,7 @@ static int netxen_nic_open(struct net_device *netdev); static int netxen_nic_close(struct net_device *netdev); static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); -static void netxen_tx_timeout_task(struct net_device *netdev); +static void netxen_tx_timeout_task(struct work_struct *work); static void netxen_watchdog(unsigned long); static int netxen_handle_int(struct netxen_adapter *, struct net_device *); static int netxen_nic_ioctl(struct net_device *netdev, @@ -274,8 +274,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->ahw.xg_linkup = 0; adapter->watchdog_timer.function = &netxen_watchdog; adapter->watchdog_timer.data = (unsigned long)adapter; - INIT_WORK(&adapter->watchdog_task, - (void (*)(void *))netxen_watchdog_task, adapter); + INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task); adapter->ahw.pdev = pdev; adapter->proc_cmd_buf_counter = 0; pci_read_config_byte(pdev, PCI_REVISION_ID, &adapter->ahw.revision_id); @@ -379,8 +378,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_addr); } } - INIT_WORK(&adapter->tx_timeout_task, - (void (*)(void *))netxen_tx_timeout_task, netdev); + adapter->netdev = netdev; + INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task); netif_carrier_off(netdev); netif_stop_queue(netdev); @@ -938,18 +937,20 @@ static void netxen_tx_timeout(struct net_device *netdev) schedule_work(&adapter->tx_timeout_task); } -static void netxen_tx_timeout_task(struct net_device *netdev) +static void netxen_tx_timeout_task(struct work_struct *work) { - struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev); + struct netxen_adapter *adapter = + container_of(work, struct netxen_adapter, tx_timeout_task); + struct net_device *netdev = adapter->netdev; unsigned long flags; printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", netxen_nic_driver_name, netdev->name); - spin_lock_irqsave(&port->adapter->lock, flags); + spin_lock_irqsave(&adapter->lock, flags); netxen_nic_close(netdev); netxen_nic_open(netdev); - spin_unlock_irqrestore(&port->adapter->lock, flags); + spin_unlock_irqrestore(&adapter->lock, flags); netdev->trans_start = jiffies; netif_wake_queue(netdev); } diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 95b6478f55c6..e62a9586fb95 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -210,6 +210,7 @@ struct smc_local { /* work queue */ struct work_struct phy_configure; + struct net_device *dev; int work_pending; spinlock_t lock; @@ -1114,10 +1115,11 @@ static void smc_phy_check_media(struct net_device *dev, int init) * of autonegotiation.) If the RPC ANEG bit is cleared, the selection * is controlled by the RPC SPEED and RPC DPLX bits. */ -static void smc_phy_configure(void *data) +static void smc_phy_configure(struct work_struct *work) { - struct net_device *dev = data; - struct smc_local *lp = netdev_priv(dev); + struct smc_local *lp = + container_of(work, struct smc_local, phy_configure); + struct net_device *dev = lp->dev; void __iomem *ioaddr = lp->base; int phyaddr = lp->mii.phy_id; int my_phy_caps; /* My PHY capabilities */ @@ -1592,7 +1594,7 @@ smc_open(struct net_device *dev) /* Configure the PHY, initialize the link state */ if (lp->phy_type != 0) - smc_phy_configure(dev); + smc_phy_configure(&lp->phy_configure); else { spin_lock_irq(&lp->lock); smc_10bt_check_media(dev, 1); @@ -1972,7 +1974,8 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) #endif tasklet_init(&lp->tx_task, smc_hardware_send_pkt, (unsigned long)dev); - INIT_WORK(&lp->phy_configure, smc_phy_configure, dev); + INIT_WORK(&lp->phy_configure, smc_phy_configure); + lp->dev = dev; lp->mii.phy_id_mask = 0x1f; lp->mii.reg_num_mask = 0x1f; lp->mii.force_media = 0; @@ -2322,7 +2325,7 @@ static int smc_drv_resume(struct platform_device *dev) smc_reset(ndev); smc_enable(ndev); if (lp->phy_type != 0) - smc_phy_configure(ndev); + smc_phy_configure(&lp->phy_configure); netif_device_attach(ndev); } } diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 44f3cfd4cc1d..f1573a9c2336 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -32,8 +32,8 @@ static void ieee_init(struct ieee80211_device *ieee); static void softmac_init(struct ieee80211softmac_device *sm); -static void set_rts_cts_work(void *d); -static void set_basic_rates_work(void *d); +static void set_rts_cts_work(struct work_struct *work); +static void set_basic_rates_work(struct work_struct *work); static void housekeeping_init(struct zd_mac *mac); static void housekeeping_enable(struct zd_mac *mac); @@ -48,8 +48,8 @@ int zd_mac_init(struct zd_mac *mac, memset(mac, 0, sizeof(*mac)); spin_lock_init(&mac->lock); mac->netdev = netdev; - INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work, mac); - INIT_WORK(&mac->set_basic_rates_work, set_basic_rates_work, mac); + INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work); + INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work); ieee_init(ieee); softmac_init(ieee80211_priv(netdev)); @@ -366,9 +366,10 @@ static void try_enable_tx(struct zd_mac *mac) spin_unlock_irqrestore(&mac->lock, flags); } -static void set_rts_cts_work(void *d) +static void set_rts_cts_work(struct work_struct *work) { - struct zd_mac *mac = d; + struct zd_mac *mac = + container_of(work, struct zd_mac, set_rts_cts_work.work); unsigned long flags; u8 rts_rate; unsigned int short_preamble; @@ -387,9 +388,10 @@ static void set_rts_cts_work(void *d) try_enable_tx(mac); } -static void set_basic_rates_work(void *d) +static void set_basic_rates_work(struct work_struct *work) { - struct zd_mac *mac = d; + struct zd_mac *mac = + container_of(work, struct zd_mac, set_basic_rates_work.work); unsigned long flags; u16 basic_rates; @@ -467,12 +469,13 @@ static void bssinfo_change(struct net_device *netdev, u32 changes) if (need_set_rts_cts && !mac->updating_rts_rate) { mac->updating_rts_rate = 1; netif_stop_queue(mac->netdev); - queue_work(zd_workqueue, &mac->set_rts_cts_work); + queue_delayed_work(zd_workqueue, &mac->set_rts_cts_work, 0); } if (need_set_rates && !mac->updating_basic_rates) { mac->updating_basic_rates = 1; netif_stop_queue(mac->netdev); - queue_work(zd_workqueue, &mac->set_basic_rates_work); + queue_delayed_work(zd_workqueue, &mac->set_basic_rates_work, + 0); } spin_unlock_irqrestore(&mac->lock, flags); } diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 08d6b8c08e75..d4e8b870409d 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -133,8 +133,8 @@ struct zd_mac { struct iw_statistics iw_stats; struct housekeeping housekeeping; - struct work_struct set_rts_cts_work; - struct work_struct set_basic_rates_work; + struct delayed_work set_rts_cts_work; + struct delayed_work set_basic_rates_work; unsigned int stats_count; u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE]; diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 72025df5561d..494d9b856488 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -148,7 +148,7 @@ struct chip_data { void (*cs_control)(u32 command); }; -static void pump_messages(void *data); +static void pump_messages(struct work_struct *work); static int flush(struct driver_data *drv_data) { @@ -884,9 +884,10 @@ static void pump_transfers(unsigned long data) } } -static void pump_messages(void *data) +static void pump_messages(struct work_struct *work) { - struct driver_data *drv_data = data; + struct driver_data *drv_data = + container_of(work, struct driver_data, pump_messages); unsigned long flags; /* Lock queue and check for queue work */ @@ -1098,7 +1099,7 @@ static int init_queue(struct driver_data *drv_data) tasklet_init(&drv_data->pump_transfers, pump_transfers, (unsigned long)drv_data); - INIT_WORK(&drv_data->pump_messages, pump_messages, drv_data); + INIT_WORK(&drv_data->pump_messages, pump_messages); drv_data->workqueue = create_singlethread_workqueue( drv_data->master->cdev.dev->bus_id); if (drv_data->workqueue == NULL) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 39186db1015f..9be41ed1f9a6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -68,7 +68,7 @@ struct usb_hub { unsigned has_indicators:1; u8 indicator[USB_MAXCHILDREN]; - struct work_struct leds; + struct delayed_work leds; }; diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index ba30ca6a14aa..02cbb7fff24f 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -76,7 +76,7 @@ struct appledisplay { char *urbdata; /* interrupt URB data buffer */ char *msgdata; /* control message data buffer */ - struct work_struct work; + struct delayed_work work; int button_pressed; spinlock_t lock; }; @@ -117,7 +117,7 @@ static void appledisplay_complete(struct urb *urb) case ACD_BTN_BRIGHT_UP: case ACD_BTN_BRIGHT_DOWN: pdata->button_pressed = 1; - queue_work(wq, &pdata->work); + queue_delayed_work(wq, &pdata->work, 0); break; case ACD_BTN_NONE: default: @@ -184,9 +184,10 @@ static struct backlight_properties appledisplay_bl_data = { .max_brightness = 0xFF }; -static void appledisplay_work(void *private) +static void appledisplay_work(struct work_struct *work) { - struct appledisplay *pdata = private; + struct appledisplay *pdata = + container_of(work, struct appledisplay, work.work); int retval; up(&pdata->bd->sem); @@ -238,7 +239,7 @@ static int appledisplay_probe(struct usb_interface *iface, pdata->udev = udev; spin_lock_init(&pdata->lock); - INIT_WORK(&pdata->work, appledisplay_work, pdata); + INIT_DELAYED_WORK(&pdata->work, appledisplay_work); /* Allocate buffer for control messages */ pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL); diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 8a8ae55a7403..38eb0b69c2d7 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -964,9 +964,10 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state) * Our LCD controller task (which is called when we blank or unblank) * via keventd. */ -static void pxafb_task(void *dummy) +static void pxafb_task(struct work_struct *work) { - struct pxafb_info *fbi = dummy; + struct pxafb_info *fbi = + container_of(work, struct pxafb_info, task); u_int state = xchg(&fbi->task_state, -1); set_ctrlr_state(fbi, state); @@ -1159,7 +1160,7 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev) } init_waitqueue_head(&fbi->ctrlr_wait); - INIT_WORK(&fbi->task, pxafb_task, fbi); + INIT_WORK(&fbi->task, pxafb_task); init_MUTEX(&fbi->ctrlr_sem); return fbi; diff --git a/include/asm-arm/arch-omap/irda.h b/include/asm-arm/arch-omap/irda.h index 805ae3575e44..345a649ec838 100644 --- a/include/asm-arm/arch-omap/irda.h +++ b/include/asm-arm/arch-omap/irda.h @@ -24,7 +24,7 @@ struct omap_irda_config { /* Very specific to the needs of some platforms (h3,h4) * having calls which can sleep in irda_set_speed. */ - struct work_struct gpio_expa; + struct delayed_work gpio_expa; int rx_channel; int tx_channel; unsigned long dest_start; diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 2cc9867b1626..29930b71a9aa 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -32,7 +32,7 @@ struct netpoll_info { struct netpoll *rx_np; /* netpoll that registered an rx_hook */ struct sk_buff_head arp_tx; /* list of arp requests to reply to */ struct sk_buff_head txq; - struct work_struct tx_work; + struct delayed_work tx_work; }; void netpoll_poll(struct netpoll *np); -- cgit v1.2.3 From e6b3c4db6fbcd0d33720696f37790d6b8be12313 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 11 Nov 2006 22:18:03 -0500 Subject: Fix a second potential rpc_wakeup race... Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 12 +++---- include/linux/sunrpc/sched.h | 8 +---- net/sunrpc/clnt.c | 19 ++++++----- net/sunrpc/pmap_clnt.c | 2 +- net/sunrpc/sched.c | 80 ++++++++++++++++++++++++++------------------ net/sunrpc/sunrpc_syms.c | 1 - 6 files changed, 65 insertions(+), 57 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8118036cc449..93ac05889cbc 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -636,7 +636,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) smp_wmb(); } else status = data->rpc_status; - rpc_release_task(task); + rpc_put_task(task); return status; } @@ -742,7 +742,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) smp_wmb(); } else status = data->rpc_status; - rpc_release_task(task); + rpc_put_task(task); if (status != 0) return status; @@ -3067,7 +3067,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co if (status == 0) nfs_post_op_update_inode(inode, &data->fattr); } - rpc_release_task(task); + rpc_put_task(task); return status; } @@ -3314,7 +3314,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * if (IS_ERR(task)) goto out; status = nfs4_wait_for_completion_rpc_task(task); - rpc_release_task(task); + rpc_put_task(task); out: return status; } @@ -3430,7 +3430,7 @@ static void nfs4_lock_release(void *calldata) task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, data->arg.lock_seqid); if (!IS_ERR(task)) - rpc_release_task(task); + rpc_put_task(task); dprintk("%s: cancelling lock!\n", __FUNCTION__); } else nfs_free_seqid(data->arg.lock_seqid); @@ -3472,7 +3472,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f ret = -EAGAIN; } else data->cancelled = 1; - rpc_release_task(task); + rpc_put_task(task); dprintk("%s: done, ret = %d!\n", __FUNCTION__, ret); return ret; } diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index f399c138f79d..9fdb8c9d09f2 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -178,13 +178,6 @@ struct rpc_call_ops { } while (0) #define RPC_IS_ACTIVATED(t) (test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate)) -#define rpc_set_active(t) (set_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate)) -#define rpc_clear_active(t) \ - do { \ - smp_mb__before_clear_bit(); \ - clear_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate); \ - smp_mb__after_clear_bit(); \ - } while(0) /* * Task priorities. @@ -254,6 +247,7 @@ struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *ops, void *data); +void rpc_put_task(struct rpc_task *); void rpc_release_task(struct rpc_task *); void rpc_exit_task(struct rpc_task *); void rpc_killall_tasks(struct rpc_clnt *); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index dfeea4fea95a..a323abc7ea85 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -466,10 +466,9 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) BUG_ON(flags & RPC_TASK_ASYNC); - status = -ENOMEM; task = rpc_new_task(clnt, flags, &rpc_default_ops, NULL); if (task == NULL) - goto out; + return -ENOMEM; /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */ rpc_task_sigmask(task, &oldset); @@ -478,15 +477,17 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) /* Set up the call info struct and execute the task */ status = task->tk_status; - if (status == 0) { - atomic_inc(&task->tk_count); - status = rpc_execute(task); - if (status == 0) - status = task->tk_status; + if (status != 0) { + rpc_release_task(task); + goto out; } - rpc_restore_sigmask(&oldset); - rpc_release_task(task); + atomic_inc(&task->tk_count); + status = rpc_execute(task); + if (status == 0) + status = task->tk_status; + rpc_put_task(task); out: + rpc_restore_sigmask(&oldset); return status; } diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index e52afab413de..8d2e10fc3df9 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -134,7 +134,7 @@ void rpc_getport(struct rpc_task *task) child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map); if (IS_ERR(child)) goto bailout; - rpc_release_task(child); + rpc_put_task(child); task->tk_xprt->stat.bind_count++; return; diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index b57d4062d429..66d01365f3a5 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -266,12 +266,28 @@ static int rpc_wait_bit_interruptible(void *word) return 0; } +static void rpc_set_active(struct rpc_task *task) +{ + if (test_and_set_bit(RPC_TASK_ACTIVE, &task->tk_runstate) != 0) + return; + spin_lock(&rpc_sched_lock); +#ifdef RPC_DEBUG + task->tk_magic = RPC_TASK_MAGIC_ID; + task->tk_pid = rpc_task_id++; +#endif + /* Add to global list of all tasks */ + list_add_tail(&task->tk_task, &all_tasks); + spin_unlock(&rpc_sched_lock); +} + /* * Mark an RPC call as having completed by clearing the 'active' bit */ -static inline void rpc_mark_complete_task(struct rpc_task *task) +static void rpc_mark_complete_task(struct rpc_task *task) { - rpc_clear_active(task); + smp_mb__before_clear_bit(); + clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate); + smp_mb__after_clear_bit(); wake_up_bit(&task->tk_runstate, RPC_TASK_ACTIVE); } @@ -335,9 +351,6 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, return; } - /* Mark the task as being activated if so needed */ - rpc_set_active(task); - __rpc_add_wait_queue(q, task); BUG_ON(task->tk_callback != NULL); @@ -348,6 +361,9 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, rpc_action action, rpc_action timer) { + /* Mark the task as being activated if so needed */ + rpc_set_active(task); + /* * Protect the queue operations. */ @@ -673,8 +689,6 @@ static int __rpc_execute(struct rpc_task *task) } dprintk("RPC: %4d, return %d, status %d\n", task->tk_pid, status, task->tk_status); - /* Wake up anyone who is waiting for task completion */ - rpc_mark_complete_task(task); /* Release all resources associated with the task */ rpc_release_task(task); return status; @@ -788,15 +802,6 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons task->tk_flags |= RPC_TASK_NOINTR; } -#ifdef RPC_DEBUG - task->tk_magic = RPC_TASK_MAGIC_ID; - task->tk_pid = rpc_task_id++; -#endif - /* Add to global list of all tasks */ - spin_lock(&rpc_sched_lock); - list_add_tail(&task->tk_task, &all_tasks); - spin_unlock(&rpc_sched_lock); - BUG_ON(task->tk_ops == NULL); /* starting timestamp */ @@ -849,16 +854,35 @@ cleanup: goto out; } -void rpc_release_task(struct rpc_task *task) + +void rpc_put_task(struct rpc_task *task) { const struct rpc_call_ops *tk_ops = task->tk_ops; void *calldata = task->tk_calldata; + if (!atomic_dec_and_test(&task->tk_count)) + return; + /* Release resources */ + if (task->tk_rqstp) + xprt_release(task); + if (task->tk_msg.rpc_cred) + rpcauth_unbindcred(task); + if (task->tk_client) { + rpc_release_client(task->tk_client); + task->tk_client = NULL; + } + if (task->tk_flags & RPC_TASK_DYNAMIC) + rpc_free_task(task); + if (tk_ops->rpc_release) + tk_ops->rpc_release(calldata); +} +EXPORT_SYMBOL(rpc_put_task); + +void rpc_release_task(struct rpc_task *task) +{ #ifdef RPC_DEBUG BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID); #endif - if (!atomic_dec_and_test(&task->tk_count)) - return; dprintk("RPC: %4d release task\n", task->tk_pid); /* Remove from global task list */ @@ -871,23 +895,13 @@ void rpc_release_task(struct rpc_task *task) /* Synchronously delete any running timer */ rpc_delete_timer(task); - /* Release resources */ - if (task->tk_rqstp) - xprt_release(task); - if (task->tk_msg.rpc_cred) - rpcauth_unbindcred(task); - if (task->tk_client) { - rpc_release_client(task->tk_client); - task->tk_client = NULL; - } - #ifdef RPC_DEBUG task->tk_magic = 0; #endif - if (task->tk_flags & RPC_TASK_DYNAMIC) - rpc_free_task(task); - if (tk_ops->rpc_release) - tk_ops->rpc_release(calldata); + /* Wake up anyone who is waiting for task completion */ + rpc_mark_complete_task(task); + + rpc_put_task(task); } /** diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 192dff5dabcb..faaf81e97720 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -33,7 +33,6 @@ EXPORT_SYMBOL(rpciod_down); EXPORT_SYMBOL(rpciod_up); EXPORT_SYMBOL(rpc_new_task); EXPORT_SYMBOL(rpc_wake_up_status); -EXPORT_SYMBOL(rpc_release_task); /* RPC client functions */ EXPORT_SYMBOL(rpc_clone_client); -- cgit v1.2.3 From 8aca67f0ae2d8811165c22326825a645cc8e1b48 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 13 Nov 2006 16:23:44 -0500 Subject: SUNRPC: Fix a potential race in rpc_wake_up_task() Use RCU to ensure that we can safely call rpc_finish_wakeup after we've called __rpc_do_wake_up_task. If not, there is a theoretical race, in which the rpc_task finishes executing, and gets freed first. Signed-off-by: Trond Myklebust --- fs/nfs/read.c | 8 +++++++- fs/nfs/write.c | 20 ++++++++++++++++---- include/linux/nfs_fs.h | 7 ++----- include/linux/sunrpc/sched.h | 2 ++ net/sunrpc/sched.c | 30 ++++++++++++++++++++---------- 5 files changed, 47 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/read.c b/fs/nfs/read.c index c2e49c397a27..8b58bbf6e39e 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -65,13 +65,19 @@ struct nfs_read_data *nfs_readdata_alloc(size_t len) return p; } -static void nfs_readdata_free(struct nfs_read_data *p) +static void nfs_readdata_rcu_free(struct rcu_head *head) { + struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu); if (p && (p->pagevec != &p->page_array[0])) kfree(p->pagevec); mempool_free(p, nfs_rdata_mempool); } +static void nfs_readdata_free(struct nfs_read_data *rdata) +{ + call_rcu_bh(&rdata->task.u.tk_rcu, nfs_readdata_rcu_free); +} + void nfs_readdata_release(void *data) { nfs_readdata_free(data); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 883dd4a1c157..29d88209199d 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -102,13 +102,19 @@ struct nfs_write_data *nfs_commit_alloc(void) return p; } -void nfs_commit_free(struct nfs_write_data *p) +void nfs_commit_rcu_free(struct rcu_head *head) { + struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); if (p && (p->pagevec != &p->page_array[0])) kfree(p->pagevec); mempool_free(p, nfs_commit_mempool); } +void nfs_commit_free(struct nfs_write_data *wdata) +{ + call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); +} + struct nfs_write_data *nfs_writedata_alloc(size_t len) { unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -131,13 +137,19 @@ struct nfs_write_data *nfs_writedata_alloc(size_t len) return p; } -static void nfs_writedata_free(struct nfs_write_data *p) +static void nfs_writedata_rcu_free(struct rcu_head *head) { + struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); if (p && (p->pagevec != &p->page_array[0])) kfree(p->pagevec); mempool_free(p, nfs_wdata_mempool); } +static void nfs_writedata_free(struct nfs_write_data *wdata) +{ + call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free); +} + void nfs_writedata_release(void *wdata) { nfs_writedata_free(wdata); @@ -258,7 +270,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, io_error: nfs_end_data_update(inode); end_page_writeback(page); - nfs_writedata_free(wdata); + nfs_writedata_release(wdata); return written ? written : result; } @@ -1043,7 +1055,7 @@ out_bad: while (!list_empty(&list)) { data = list_entry(list.next, struct nfs_write_data, pages); list_del(&data->pages); - nfs_writedata_free(data); + nfs_writedata_release(data); } nfs_mark_request_dirty(req); nfs_clear_page_writeback(req); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 625ffea98561..02f38189d180 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -428,11 +428,6 @@ extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); extern void nfs_writedata_release(void *); -#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) -struct nfs_write_data *nfs_commit_alloc(void); -void nfs_commit_free(struct nfs_write_data *p); -#endif - /* * Try to write back everything synchronously (but check the * return value!) @@ -440,6 +435,8 @@ void nfs_commit_free(struct nfs_write_data *p); extern int nfs_sync_inode_wait(struct inode *, unsigned long, unsigned int, int); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) extern int nfs_commit_inode(struct inode *, int); +extern struct nfs_write_data *nfs_commit_alloc(void); +extern void nfs_commit_free(struct nfs_write_data *wdata); extern void nfs_commit_release(void *wdata); #else static inline int diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 9fdb8c9d09f2..14fc813ddd0c 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -85,6 +86,7 @@ struct rpc_task { union { struct work_struct tk_work; /* Async task work queue */ struct rpc_wait tk_wait; /* RPC wait */ + struct rcu_head tk_rcu; /* for task deletion */ } u; unsigned short tk_timeouts; /* maj timeouts */ diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 66d01365f3a5..6b808c03fb72 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -427,16 +427,19 @@ __rpc_default_timer(struct rpc_task *task) */ void rpc_wake_up_task(struct rpc_task *task) { + rcu_read_lock_bh(); if (rpc_start_wakeup(task)) { if (RPC_IS_QUEUED(task)) { struct rpc_wait_queue *queue = task->u.tk_wait.rpc_waitq; - spin_lock_bh(&queue->lock); + /* Note: we're already in a bh-safe context */ + spin_lock(&queue->lock); __rpc_do_wake_up_task(task); - spin_unlock_bh(&queue->lock); + spin_unlock(&queue->lock); } rpc_finish_wakeup(task); } + rcu_read_unlock_bh(); } /* @@ -499,14 +502,16 @@ struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue) struct rpc_task *task = NULL; dprintk("RPC: wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue)); - spin_lock_bh(&queue->lock); + rcu_read_lock_bh(); + spin_lock(&queue->lock); if (RPC_IS_PRIORITY(queue)) task = __rpc_wake_up_next_priority(queue); else { task_for_first(task, &queue->tasks[0]) __rpc_wake_up_task(task); } - spin_unlock_bh(&queue->lock); + spin_unlock(&queue->lock); + rcu_read_unlock_bh(); return task; } @@ -522,7 +527,8 @@ void rpc_wake_up(struct rpc_wait_queue *queue) struct rpc_task *task, *next; struct list_head *head; - spin_lock_bh(&queue->lock); + rcu_read_lock_bh(); + spin_lock(&queue->lock); head = &queue->tasks[queue->maxpriority]; for (;;) { list_for_each_entry_safe(task, next, head, u.tk_wait.list) @@ -531,7 +537,8 @@ void rpc_wake_up(struct rpc_wait_queue *queue) break; head--; } - spin_unlock_bh(&queue->lock); + spin_unlock(&queue->lock); + rcu_read_unlock_bh(); } /** @@ -546,7 +553,8 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) struct rpc_task *task, *next; struct list_head *head; - spin_lock_bh(&queue->lock); + rcu_read_lock_bh(); + spin_lock(&queue->lock); head = &queue->tasks[queue->maxpriority]; for (;;) { list_for_each_entry_safe(task, next, head, u.tk_wait.list) { @@ -557,7 +565,8 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) break; head--; } - spin_unlock_bh(&queue->lock); + spin_unlock(&queue->lock); + rcu_read_unlock_bh(); } static void __rpc_atrun(struct rpc_task *task) @@ -817,8 +826,9 @@ rpc_alloc_task(void) return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS); } -static void rpc_free_task(struct rpc_task *task) +static void rpc_free_task(struct rcu_head *rcu) { + struct rpc_task *task = container_of(rcu, struct rpc_task, u.tk_rcu); dprintk("RPC: %4d freeing task\n", task->tk_pid); mempool_free(task, rpc_task_mempool); } @@ -872,7 +882,7 @@ void rpc_put_task(struct rpc_task *task) task->tk_client = NULL; } if (task->tk_flags & RPC_TASK_DYNAMIC) - rpc_free_task(task); + call_rcu_bh(&task->u.tk_rcu, rpc_free_task); if (tk_ops->rpc_release) tk_ops->rpc_release(calldata); } -- cgit v1.2.3 From 3e32a5d99a467b9d4d416323c8c292479b4915e5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 16 Nov 2006 11:37:27 -0500 Subject: SUNRPC: Give cloned RPC clients their own rpc_pipefs directory Signed-off-by: Trond Myklebust --- include/linux/sunrpc/clnt.h | 1 + net/sunrpc/clnt.c | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index f6d1d646ce05..a1be89deb3af 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -53,6 +53,7 @@ struct rpc_clnt { struct dentry * cl_dentry; /* inode */ struct rpc_clnt * cl_parent; /* Points to parent of clones */ struct rpc_rtt cl_rtt_default; + struct rpc_program * cl_program; char cl_inline_name[32]; }; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index de8bbfcd5030..8b78177e7575 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -144,6 +144,7 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s err = -ENOMEM; if (clnt->cl_metrics == NULL) goto out_no_stats; + clnt->cl_program = program; if (!xprt_bound(clnt->cl_xprt)) clnt->cl_autobind = 1; @@ -257,6 +258,7 @@ struct rpc_clnt * rpc_clone_client(struct rpc_clnt *clnt) { struct rpc_clnt *new; + int err = -ENOMEM; new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); if (!new) @@ -266,6 +268,9 @@ rpc_clone_client(struct rpc_clnt *clnt) new->cl_metrics = rpc_alloc_iostats(clnt); if (new->cl_metrics == NULL) goto out_no_stats; + err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); + if (err != 0) + goto out_no_path; new->cl_parent = clnt; atomic_inc(&clnt->cl_count); new->cl_xprt = xprt_get(clnt->cl_xprt); @@ -273,17 +278,17 @@ rpc_clone_client(struct rpc_clnt *clnt) new->cl_autobind = 0; new->cl_oneshot = 0; new->cl_dead = 0; - if (!IS_ERR(new->cl_dentry)) - dget(new->cl_dentry); rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); if (new->cl_auth) atomic_inc(&new->cl_auth->au_count); return new; +out_no_path: + rpc_free_iostats(new->cl_metrics); out_no_stats: kfree(new); out_no_clnt: - printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); - return ERR_PTR(-ENOMEM); + dprintk("RPC: %s returned error %d\n", __FUNCTION__, err); + return ERR_PTR(err); } /* @@ -336,16 +341,14 @@ rpc_destroy_client(struct rpc_clnt *clnt) rpcauth_destroy(clnt->cl_auth); clnt->cl_auth = NULL; } - if (clnt->cl_parent != clnt) { - if (!IS_ERR(clnt->cl_dentry)) - dput(clnt->cl_dentry); - rpc_destroy_client(clnt->cl_parent); - goto out_free; - } if (!IS_ERR(clnt->cl_dentry)) { rpc_rmdir(clnt->cl_dentry); rpc_put_mount(); } + if (clnt->cl_parent != clnt) { + rpc_destroy_client(clnt->cl_parent); + goto out_free; + } if (clnt->cl_server != clnt->cl_inline_name) kfree(clnt->cl_server); out_free: -- cgit v1.2.3 From bbd5a1f9fc9fad0f8725812d91c51b052e847de8 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 18 Oct 2006 16:01:05 -0400 Subject: SUNRPC: Fix up missing BKL in asynchronous RPC callback functions Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 1 + net/sunrpc/clnt.c | 3 +-- net/sunrpc/sched.c | 15 +++++++++++---- 3 files changed, 13 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 14fc813ddd0c..b6b6ad6253b4 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -252,6 +252,7 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, void rpc_put_task(struct rpc_task *); void rpc_release_task(struct rpc_task *); void rpc_exit_task(struct rpc_task *); +void rpc_release_calldata(const struct rpc_call_ops *, void *); void rpc_killall_tasks(struct rpc_clnt *); int rpc_execute(struct rpc_task *); void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 8b78177e7575..37d345c04aa5 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -541,8 +541,7 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, rpc_restore_sigmask(&oldset); return status; out_release: - if (tk_ops->rpc_release != NULL) - tk_ops->rpc_release(data); + rpc_release_calldata(tk_ops, data); return status; } diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 6b808c03fb72..9c13050d23eb 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -608,6 +608,15 @@ void rpc_exit_task(struct rpc_task *task) } EXPORT_SYMBOL(rpc_exit_task); +void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) +{ + if (ops->rpc_release != NULL) { + lock_kernel(); + ops->rpc_release(calldata); + unlock_kernel(); + } +} + /* * This is the RPC `scheduler' (or rather, the finite state machine). */ @@ -883,8 +892,7 @@ void rpc_put_task(struct rpc_task *task) } if (task->tk_flags & RPC_TASK_DYNAMIC) call_rcu_bh(&task->u.tk_rcu, rpc_free_task); - if (tk_ops->rpc_release) - tk_ops->rpc_release(calldata); + rpc_release_calldata(tk_ops, calldata); } EXPORT_SYMBOL(rpc_put_task); @@ -928,8 +936,7 @@ struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, struct rpc_task *task; task = rpc_new_task(clnt, flags, ops, data); if (task == NULL) { - if (ops->rpc_release != NULL) - ops->rpc_release(data); + rpc_release_calldata(ops, data); return ERR_PTR(-ENOMEM); } atomic_inc(&task->tk_count); -- cgit v1.2.3 From 1e78957e0a8f882df6a3660b62f9aae441f54891 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 31 Aug 2006 15:09:19 -0400 Subject: SUNRPC: Clean up argument types in xdr.c Converts various integer buffer offsets and sizes to unsigned integer. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xdr.h | 12 +++---- net/sunrpc/xdr.c | 86 +++++++++++++++++++++++----------------------- 2 files changed, 49 insertions(+), 49 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 9a527c364394..441b91dbafe5 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -139,10 +139,10 @@ xdr_adjust_iovec(struct kvec *iov, __be32 *p) */ extern void xdr_shift_buf(struct xdr_buf *, size_t); extern void xdr_buf_from_iov(struct kvec *, struct xdr_buf *); -extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, int, int); -extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, int); -extern int read_bytes_from_xdr_buf(struct xdr_buf *, int, void *, int); -extern int write_bytes_to_xdr_buf(struct xdr_buf *, int, void *, int); +extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, unsigned int, unsigned int); +extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, unsigned int); +extern int read_bytes_from_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int); +extern int write_bytes_to_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int); /* * Helper structure for copying from an sk_buff. @@ -160,8 +160,8 @@ extern int csum_partial_copy_to_xdr(struct xdr_buf *, struct sk_buff *); extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, skb_reader_t *, skb_read_actor_t); -extern int xdr_encode_word(struct xdr_buf *, int, u32); -extern int xdr_decode_word(struct xdr_buf *, int, u32 *); +extern int xdr_encode_word(struct xdr_buf *, unsigned int, u32); +extern int xdr_decode_word(struct xdr_buf *, unsigned int, u32 *); struct xdr_array2_desc; typedef int (*xdr_xcode_elem_t)(struct xdr_array2_desc *desc, void *elem); diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 9022eb8b37ed..b474edbab3f1 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -640,41 +640,30 @@ xdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf) buf->buflen = buf->len = iov->iov_len; } -/* Sets subiov to the intersection of iov with the buffer of length len - * starting base bytes after iov. Indicates empty intersection by setting - * length of subiov to zero. Decrements len by length of subiov, sets base - * to zero (or decrements it by length of iov if subiov is empty). */ -static void -iov_subsegment(struct kvec *iov, struct kvec *subiov, int *base, int *len) -{ - if (*base > iov->iov_len) { - subiov->iov_base = NULL; - subiov->iov_len = 0; - *base -= iov->iov_len; - } else { - subiov->iov_base = iov->iov_base + *base; - subiov->iov_len = min(*len, (int)iov->iov_len - *base); - *base = 0; - } - *len -= subiov->iov_len; -} - /* Sets subbuf to the portion of buf of length len beginning base bytes * from the start of buf. Returns -1 if base of length are out of bounds. */ int xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf, - int base, int len) + unsigned int base, unsigned int len) { - int i; - subbuf->buflen = subbuf->len = len; - iov_subsegment(buf->head, subbuf->head, &base, &len); + if (base < buf->head[0].iov_len) { + subbuf->head[0].iov_base = buf->head[0].iov_base + base; + subbuf->head[0].iov_len = min_t(unsigned int, len, + buf->head[0].iov_len - base); + len -= subbuf->head[0].iov_len; + base = 0; + } else { + subbuf->head[0].iov_base = NULL; + subbuf->head[0].iov_len = 0; + base -= buf->head[0].iov_len; + } if (base < buf->page_len) { - i = (base + buf->page_base) >> PAGE_CACHE_SHIFT; - subbuf->pages = &buf->pages[i]; - subbuf->page_base = (base + buf->page_base) & ~PAGE_CACHE_MASK; - subbuf->page_len = min((int)buf->page_len - base, len); + subbuf->page_len = min(buf->page_len - base, len); + base += buf->page_base; + subbuf->page_base = base & ~PAGE_CACHE_MASK; + subbuf->pages = &buf->pages[base >> PAGE_CACHE_SHIFT]; len -= subbuf->page_len; base = 0; } else { @@ -682,7 +671,18 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf, subbuf->page_len = 0; } - iov_subsegment(buf->tail, subbuf->tail, &base, &len); + if (base < buf->tail[0].iov_len) { + subbuf->tail[0].iov_base = buf->tail[0].iov_base + base; + subbuf->tail[0].iov_len = min_t(unsigned int, len, + buf->tail[0].iov_len - base); + len -= subbuf->tail[0].iov_len; + base = 0; + } else { + subbuf->tail[0].iov_base = NULL; + subbuf->tail[0].iov_len = 0; + base -= buf->tail[0].iov_len; + } + if (base || len) return -1; return 0; @@ -690,25 +690,25 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf, /* obj is assumed to point to allocated memory of size at least len: */ int -read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len) +read_bytes_from_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, unsigned int len) { struct xdr_buf subbuf; - int this_len; + unsigned int this_len; int status; status = xdr_buf_subsegment(buf, &subbuf, base, len); if (status) goto out; - this_len = min(len, (int)subbuf.head[0].iov_len); + this_len = min_t(unsigned int, len, subbuf.head[0].iov_len); memcpy(obj, subbuf.head[0].iov_base, this_len); len -= this_len; obj += this_len; - this_len = min(len, (int)subbuf.page_len); + this_len = min_t(unsigned int, len, subbuf.page_len); if (this_len) _copy_from_pages(obj, subbuf.pages, subbuf.page_base, this_len); len -= this_len; obj += this_len; - this_len = min(len, (int)subbuf.tail[0].iov_len); + this_len = min_t(unsigned int, len, subbuf.tail[0].iov_len); memcpy(obj, subbuf.tail[0].iov_base, this_len); out: return status; @@ -716,32 +716,32 @@ out: /* obj is assumed to point to allocated memory of size at least len: */ int -write_bytes_to_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len) +write_bytes_to_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, unsigned int len) { struct xdr_buf subbuf; - int this_len; + unsigned int this_len; int status; status = xdr_buf_subsegment(buf, &subbuf, base, len); if (status) goto out; - this_len = min(len, (int)subbuf.head[0].iov_len); + this_len = min_t(unsigned int, len, subbuf.head[0].iov_len); memcpy(subbuf.head[0].iov_base, obj, this_len); len -= this_len; obj += this_len; - this_len = min(len, (int)subbuf.page_len); + this_len = min_t(unsigned int, len, subbuf.page_len); if (this_len) _copy_to_pages(subbuf.pages, subbuf.page_base, obj, this_len); len -= this_len; obj += this_len; - this_len = min(len, (int)subbuf.tail[0].iov_len); + this_len = min_t(unsigned int, len, subbuf.tail[0].iov_len); memcpy(subbuf.tail[0].iov_base, obj, this_len); out: return status; } int -xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj) +xdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj) { __be32 raw; int status; @@ -754,7 +754,7 @@ xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj) } int -xdr_encode_word(struct xdr_buf *buf, int base, u32 obj) +xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj) { __be32 raw = htonl(obj); @@ -766,10 +766,10 @@ xdr_encode_word(struct xdr_buf *buf, int base, u32 obj) * try to find space for it at the end of the tail, copy it there, and * set obj to point to it. */ int -xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset) +xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned int offset) { - u32 tail_offset = buf->head[0].iov_len + buf->page_len; - u32 obj_end_offset; + unsigned int tail_offset = buf->head[0].iov_len + buf->page_len; + unsigned int obj_end_offset; if (xdr_decode_word(buf, offset, &obj->len)) goto out; -- cgit v1.2.3 From e744cf2e3ab8535a8494a4cf0177de26f94586da Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 17 Oct 2006 14:44:24 -0400 Subject: SUNRPC: minor optimization of "xid" field in rpc_xprt Move the xid field in the rpc_xprt structure to be in the same cache line as the reserve_lock, since these are used at the same time. Test plan: None. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 60394fbc4c70..0321fb53bd02 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -157,11 +157,6 @@ struct rpc_xprt { unsigned char shutdown : 1, /* being shut down */ resvport : 1; /* use a reserved port */ - /* - * XID - */ - __u32 xid; /* Next XID value to use */ - /* * State of TCP reply receive stuff */ @@ -193,8 +188,8 @@ struct rpc_xprt { */ spinlock_t transport_lock; /* lock transport info */ spinlock_t reserve_lock; /* lock slot table */ + u32 xid; /* Next XID value to use */ struct rpc_task * snd_task; /* Task blocked in send */ - struct list_head recv; struct { -- cgit v1.2.3 From c8541ecdd5692bcfbcb5305cab9a873288d29175 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 17 Oct 2006 14:44:27 -0400 Subject: SUNRPC: Make the transport-specific setup routine allocate rpc_xprt Change the location where the rpc_xprt structure is allocated so each transport implementation can allocate a private area from the same chunk of memory. Note also that xprt->ops->destroy, rather than xprt_destroy, is now responsible for freeing rpc_xprt when the transport is destroyed. Test plan: Connectathon. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 4 +-- net/sunrpc/xprt.c | 31 +++++++------------ net/sunrpc/xprtsock.c | 73 ++++++++++++++++++++++++++++++--------------- 3 files changed, 61 insertions(+), 47 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 0321fb53bd02..d7919010863d 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -265,8 +265,8 @@ void xprt_disconnect(struct rpc_xprt *xprt); /* * Socket transport setup operations */ -int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to); -int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to); +struct rpc_xprt * xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to); +struct rpc_xprt * xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to); /* * Reserved bit positions in xprt->state diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 80857470dc11..8cc2afa2942c 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -891,39 +891,25 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i */ struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t size, struct rpc_timeout *to) { - int result; struct rpc_xprt *xprt; struct rpc_rqst *req; - if ((xprt = kzalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) { - dprintk("RPC: xprt_create_transport: no memory\n"); - return ERR_PTR(-ENOMEM); - } - if (size <= sizeof(xprt->addr)) { - memcpy(&xprt->addr, ap, size); - xprt->addrlen = size; - } else { - kfree(xprt); - dprintk("RPC: xprt_create_transport: address too large\n"); - return ERR_PTR(-EBADF); - } - switch (proto) { case IPPROTO_UDP: - result = xs_setup_udp(xprt, to); + xprt = xs_setup_udp(ap, size, to); break; case IPPROTO_TCP: - result = xs_setup_tcp(xprt, to); + xprt = xs_setup_tcp(ap, size, to); break; default: printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n", proto); return ERR_PTR(-EIO); } - if (result) { - kfree(xprt); - dprintk("RPC: xprt_create_transport: failed, %d\n", result); - return ERR_PTR(result); + if (IS_ERR(xprt)) { + dprintk("RPC: xprt_create_transport: failed, %ld\n", + -PTR_ERR(xprt)); + return xprt; } kref_init(&xprt->kref); @@ -969,8 +955,11 @@ static void xprt_destroy(struct kref *kref) dprintk("RPC: destroying transport %p\n", xprt); xprt->shutdown = 1; del_timer_sync(&xprt->timer); + + /* + * Tear down transport state and free the rpc_xprt + */ xprt->ops->destroy(xprt); - kfree(xprt); } /** diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 25620851d4bf..ec3462f141b4 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -518,6 +518,7 @@ static void xs_destroy(struct rpc_xprt *xprt) xs_close(xprt); xs_free_peer_addresses(xprt); kfree(xprt->slot); + kfree(xprt); } static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) @@ -1339,26 +1340,53 @@ static struct rpc_xprt_ops xs_tcp_ops = { .print_stats = xs_tcp_print_stats, }; +static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, unsigned int slot_table_size) +{ + struct rpc_xprt *xprt; + + if (addrlen > sizeof(xprt->addr)) { + dprintk("RPC: xs_setup_xprt: address too large\n"); + return ERR_PTR(-EBADF); + } + + xprt = kzalloc(sizeof(struct rpc_xprt), GFP_KERNEL); + if (xprt == NULL) { + dprintk("RPC: xs_setup_xprt: couldn't allocate rpc_xprt\n"); + return ERR_PTR(-ENOMEM); + } + + xprt->max_reqs = slot_table_size; + xprt->slot = kcalloc(xprt->max_reqs, sizeof(struct rpc_rqst), GFP_KERNEL); + if (xprt->slot == NULL) { + kfree(xprt); + dprintk("RPC: xs_setup_xprt: couldn't allocate slot table\n"); + return ERR_PTR(-ENOMEM); + } + + memcpy(&xprt->addr, addr, addrlen); + xprt->addrlen = addrlen; + xprt->port = xs_get_random_port(); + + return xprt; +} + /** * xs_setup_udp - Set up transport to use a UDP socket - * @xprt: transport to set up + * @addr: address of remote server + * @addrlen: length of address in bytes * @to: timeout parameters * */ -int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) +struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to) { - size_t slot_table_size; - struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr; + struct rpc_xprt *xprt; - xprt->max_reqs = xprt_udp_slot_table_entries; - slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]); - xprt->slot = kzalloc(slot_table_size, GFP_KERNEL); - if (xprt->slot == NULL) - return -ENOMEM; + xprt = xs_setup_xprt(addr, addrlen, xprt_udp_slot_table_entries); + if (IS_ERR(xprt)) + return xprt; - if (ntohs(addr->sin_port) != 0) + if (ntohs(((struct sockaddr_in *)addr)->sin_port) != 0) xprt_set_bound(xprt); - xprt->port = xs_get_random_port(); xprt->prot = IPPROTO_UDP; xprt->tsh_size = 0; @@ -1382,29 +1410,26 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) dprintk("RPC: set up transport to address %s\n", xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); - return 0; + return xprt; } /** * xs_setup_tcp - Set up transport to use a TCP socket - * @xprt: transport to set up + * @addr: address of remote server + * @addrlen: length of address in bytes * @to: timeout parameters * */ -int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) +struct rpc_xprt *xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to) { - size_t slot_table_size; - struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr; + struct rpc_xprt *xprt; - xprt->max_reqs = xprt_tcp_slot_table_entries; - slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]); - xprt->slot = kzalloc(slot_table_size, GFP_KERNEL); - if (xprt->slot == NULL) - return -ENOMEM; + xprt = xs_setup_xprt(addr, addrlen, xprt_tcp_slot_table_entries); + if (IS_ERR(xprt)) + return xprt; - if (ntohs(addr->sin_port) != 0) + if (ntohs(((struct sockaddr_in *)addr)->sin_port) != 0) xprt_set_bound(xprt); - xprt->port = xs_get_random_port(); xprt->prot = IPPROTO_TCP; xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); @@ -1427,5 +1452,5 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) dprintk("RPC: set up transport to address %s\n", xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); - return 0; + return xprt; } -- cgit v1.2.3 From 3f442547b76bf9fb70d7aecc41cf1980459253c9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 17 Sep 2006 14:46:44 -0400 Subject: NFS: Clean up nfs_scan_dirty() Pass down struct writeback control. Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 76 ++++++++++++++++++++++++++++++++---------------- fs/nfs/write.c | 54 ++++++++++------------------------ include/linux/nfs_fs.h | 2 +- include/linux/nfs_page.h | 5 ++-- 4 files changed, 71 insertions(+), 66 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 829af323f288..e046c9b6a9dd 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -17,6 +17,7 @@ #include #include #include +#include #define NFS_PARANOIA 1 @@ -268,11 +269,10 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst, #define NFS_SCAN_MAXENTRIES 16 /** - * nfs_scan_lock_dirty - Scan the radix tree for dirty requests - * @nfsi: NFS inode + * nfs_scan_dirty - Scan the radix tree for dirty requests + * @mapping: pointer to address space + * @wbc: writeback_control structure * @dst: Destination list - * @idx_start: lower bound of page->index to scan - * @npages: idx_start + npages sets the upper bound to scan. * * Moves elements from one of the inode request lists. * If the number of requests is set to 0, the entire address_space @@ -280,46 +280,72 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst, * The requests are *not* checked to ensure that they form a contiguous set. * You must be holding the inode's req_lock when calling this function */ -int -nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, - unsigned long idx_start, unsigned int npages) +long nfs_scan_dirty(struct address_space *mapping, + struct writeback_control *wbc, + struct list_head *dst) { + struct nfs_inode *nfsi = NFS_I(mapping->host); struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; struct nfs_page *req; - unsigned long idx_end; + pgoff_t idx_start, idx_end; + long count = wbc->nr_to_write; + long res = 0; int found, i; - int res; - res = 0; - if (npages == 0) - idx_end = ~0; - else - idx_end = idx_start + npages - 1; + if (nfsi->ndirty == 0 || count <= 0) + return 0; + if (wbc->range_cyclic) { + idx_start = 0; + idx_end = ULONG_MAX; + } else if (wbc->range_end == 0) { + idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; + idx_end = ULONG_MAX; + } else { + idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; + idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; + } for (;;) { + unsigned int toscan = NFS_SCAN_MAXENTRIES; + + if (toscan > count) + toscan = count; found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, - (void **)&pgvec[0], idx_start, NFS_SCAN_MAXENTRIES, + (void **)&pgvec[0], idx_start, toscan, NFS_PAGE_TAG_DIRTY); + + /* Did we make progress? */ if (found <= 0) break; + for (i = 0; i < found; i++) { req = pgvec[i]; - if (req->wb_index > idx_end) + if (!wbc->range_cyclic && req->wb_index > idx_end) goto out; - idx_start = req->wb_index + 1; + /* Try to lock request and mark it for writeback */ + if (!nfs_set_page_writeback_locked(req)) + goto next; + radix_tree_tag_clear(&nfsi->nfs_page_tree, + req->wb_index, NFS_PAGE_TAG_DIRTY); + nfsi->ndirty--; + nfs_list_remove_request(req); + nfs_list_add_request(req, dst); + dec_zone_page_state(req->wb_page, NR_FILE_DIRTY); + res++; + if (res == LONG_MAX) + goto out; + count--; + if (count == 0) + goto out; - if (nfs_set_page_writeback_locked(req)) { - radix_tree_tag_clear(&nfsi->nfs_page_tree, - req->wb_index, NFS_PAGE_TAG_DIRTY); - nfs_list_remove_request(req); - nfs_list_add_request(req, dst); - dec_zone_page_state(req->wb_page, NR_FILE_DIRTY); - res++; - } +next: + idx_start = req->wb_index + 1; } } out: + wbc->nr_to_write = count; + WARN_ON ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)); return res; } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 1d72096c4d22..dbc89fa7e9d5 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -79,7 +79,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*, unsigned int, unsigned int); static int nfs_wait_on_write_congestion(struct address_space *, int); static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); -static int nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); +static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); static const struct rpc_call_ops nfs_write_partial_ops; static const struct rpc_call_ops nfs_write_full_ops; static const struct rpc_call_ops nfs_commit_ops; @@ -400,10 +400,8 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) goto out; } err = nfs_commit_inode(inode, wb_priority(wbc)); - if (err > 0) { - wbc->nr_to_write -= err; + if (err > 0) err = 0; - } out: clear_bit(BDI_write_congested, &bdi->state); wake_up_all(&nfs_write_congestion); @@ -607,31 +605,6 @@ static void nfs_cancel_commit_list(struct list_head *head) } } -/* - * nfs_scan_dirty - Scan an inode for dirty requests - * @inode: NFS inode to scan - * @dst: destination list - * @idx_start: lower bound of page->index to scan. - * @npages: idx_start + npages sets the upper bound to scan. - * - * Moves requests from the inode's dirty page list. - * The requests are *not* checked to ensure that they form a contiguous set. - */ -static int -nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) -{ - struct nfs_inode *nfsi = NFS_I(inode); - int res = 0; - - if (nfsi->ndirty != 0) { - res = nfs_scan_lock_dirty(nfsi, dst, idx_start, npages); - nfsi->ndirty -= res; - if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) - printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); - } - return res; -} - #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) /* * nfs_scan_commit - Scan an inode for commit requests @@ -1467,22 +1440,19 @@ static inline int nfs_commit_list(struct inode *inode, struct list_head *head, i } #endif -static int nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how) +static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how) { struct nfs_inode *nfsi = NFS_I(mapping->host); LIST_HEAD(head); - pgoff_t index = wbc->range_start >> PAGE_CACHE_SHIFT; - unsigned long npages = 1 + (wbc->range_end >> PAGE_CACHE_SHIFT) - index; - int res; + long res; spin_lock(&nfsi->req_lock); - res = nfs_scan_dirty(mapping->host, &head, index, npages); + res = nfs_scan_dirty(mapping, wbc, &head); spin_unlock(&nfsi->req_lock); if (res) { int error = nfs_flush_list(mapping->host, &head, res, how); if (error < 0) return error; - wbc->nr_to_write -= res; } return res; } @@ -1506,13 +1476,21 @@ int nfs_commit_inode(struct inode *inode, int how) } #endif -int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, +long nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, unsigned int npages, int how) { struct nfs_inode *nfsi = NFS_I(inode); + struct address_space *mapping = inode->i_mapping; + struct writeback_control wbc = { + .bdi = mapping->backing_dev_info, + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .range_start = ((loff_t)idx_start) << PAGE_CACHE_SHIFT, + .range_end = ((loff_t)(idx_start + npages - 1)) << PAGE_CACHE_SHIFT, + }; LIST_HEAD(head); int nocommit = how & FLUSH_NOCOMMIT; - int pages, ret; + long pages, ret; how &= ~FLUSH_NOCOMMIT; spin_lock(&nfsi->req_lock); @@ -1520,7 +1498,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, ret = nfs_wait_on_requests_locked(inode, idx_start, npages); if (ret != 0) continue; - pages = nfs_scan_dirty(inode, &head, idx_start, npages); + pages = nfs_scan_dirty(mapping, &wbc, &head); if (pages != 0) { spin_unlock(&nfsi->req_lock); if (how & FLUSH_INVALIDATE) { diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 02f38189d180..f8190ae9e3fb 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -432,7 +432,7 @@ extern void nfs_writedata_release(void *); * Try to write back everything synchronously (but check the * return value!) */ -extern int nfs_sync_inode_wait(struct inode *, unsigned long, unsigned int, int); +extern long nfs_sync_inode_wait(struct inode *, unsigned long, unsigned int, int); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) extern int nfs_commit_inode(struct inode *, int); extern struct nfs_write_data *nfs_commit_alloc(void); diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 1f7bd287c230..38aa15fea638 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -60,8 +60,9 @@ extern void nfs_clear_request(struct nfs_page *req); extern void nfs_release_request(struct nfs_page *req); -extern int nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, - unsigned long idx_start, unsigned int npages); +extern long nfs_scan_dirty(struct address_space *mapping, + struct writeback_control *wbc, + struct list_head *dst); extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst, unsigned long idx_start, unsigned int npages); extern int nfs_coalesce_requests(struct list_head *, struct list_head *, -- cgit v1.2.3 From 1c75950b9a2254ef08f986e00ad20266ae9ba7f1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 9 Oct 2006 16:18:38 -0400 Subject: NFS: cleanup of nfs_sync_inode_wait() Allow callers to directly pass it a struct writeback_control. Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 9 +++-- fs/nfs/inode.c | 2 +- fs/nfs/write.c | 93 +++++++++++++++++++++++++++++++++++++++++++------- include/linux/nfs_fs.h | 27 +++------------ 4 files changed, 92 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/file.c b/fs/nfs/file.c index cc93865cea93..d6ee60fc3ba6 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -307,11 +307,14 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse static void nfs_invalidate_page(struct page *page, unsigned long offset) { - struct inode *inode = page->mapping->host; + loff_t range_start, range_end; + if (offset != 0) + return; /* Cancel any unstarted writes on this page */ - if (offset == 0) - nfs_sync_inode_wait(inode, page->index, 1, FLUSH_INVALIDATE); + range_start = page_offset(page); + range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); + nfs_sync_mapping_range(page->mapping, range_start, range_end, FLUSH_INVALIDATE); } static int nfs_release_page(struct page *page, gfp_t gfp) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 08cc4c5919ab..7c32187f953e 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -422,7 +422,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) int err; /* Flush out writes to the server in order to update c/mtime */ - nfs_sync_inode_wait(inode, 0, 0, FLUSH_NOCOMMIT); + nfs_sync_mapping_range(inode->i_mapping, 0, 0, FLUSH_NOCOMMIT); /* * We may force a getattr if the user cares about atime. diff --git a/fs/nfs/write.c b/fs/nfs/write.c index dbc89fa7e9d5..310fdeca6250 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -80,6 +80,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*, static int nfs_wait_on_write_congestion(struct address_space *, int); static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); +static int nfs_wb_page_priority(struct inode *inode, struct page *page, int how); static const struct rpc_call_ops nfs_write_partial_ops; static const struct rpc_call_ops nfs_write_full_ops; static const struct rpc_call_ops nfs_commit_ops; @@ -1476,29 +1477,38 @@ int nfs_commit_inode(struct inode *inode, int how) } #endif -long nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, - unsigned int npages, int how) +long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) { + struct inode *inode = mapping->host; struct nfs_inode *nfsi = NFS_I(inode); - struct address_space *mapping = inode->i_mapping; - struct writeback_control wbc = { - .bdi = mapping->backing_dev_info, - .sync_mode = WB_SYNC_ALL, - .nr_to_write = LONG_MAX, - .range_start = ((loff_t)idx_start) << PAGE_CACHE_SHIFT, - .range_end = ((loff_t)(idx_start + npages - 1)) << PAGE_CACHE_SHIFT, - }; + unsigned long idx_start, idx_end; + unsigned int npages = 0; LIST_HEAD(head); int nocommit = how & FLUSH_NOCOMMIT; long pages, ret; + /* FIXME */ + if (wbc->range_cyclic) + idx_start = 0; + else { + idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; + idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; + if (idx_end > idx_start) { + unsigned long l_npages = 1 + idx_end - idx_start; + npages = l_npages; + if (sizeof(npages) != sizeof(l_npages) && + (unsigned long)npages != l_npages) + npages = 0; + } + } how &= ~FLUSH_NOCOMMIT; spin_lock(&nfsi->req_lock); do { + wbc->pages_skipped = 0; ret = nfs_wait_on_requests_locked(inode, idx_start, npages); if (ret != 0) continue; - pages = nfs_scan_dirty(mapping, &wbc, &head); + pages = nfs_scan_dirty(mapping, wbc, &head); if (pages != 0) { spin_unlock(&nfsi->req_lock); if (how & FLUSH_INVALIDATE) { @@ -1509,11 +1519,16 @@ long nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, spin_lock(&nfsi->req_lock); continue; } + if (wbc->pages_skipped != 0) + continue; if (nocommit) break; pages = nfs_scan_commit(inode, &head, idx_start, npages); - if (pages == 0) + if (pages == 0) { + if (wbc->pages_skipped != 0) + continue; break; + } if (how & FLUSH_INVALIDATE) { spin_unlock(&nfsi->req_lock); nfs_cancel_commit_list(&head); @@ -1530,6 +1545,60 @@ long nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, return ret; } +/* + * flush the inode to disk. + */ +int nfs_wb_all(struct inode *inode) +{ + struct address_space *mapping = inode->i_mapping; + struct writeback_control wbc = { + .bdi = mapping->backing_dev_info, + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .range_cyclic = 1, + }; + int ret; + + ret = nfs_sync_mapping_wait(mapping, &wbc, 0); + if (ret >= 0) + return 0; + return ret; +} + +int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, loff_t range_end, int how) +{ + struct writeback_control wbc = { + .bdi = mapping->backing_dev_info, + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .range_start = range_start, + .range_end = range_end, + }; + int ret; + + ret = nfs_sync_mapping_wait(mapping, &wbc, how); + if (ret >= 0) + return 0; + return ret; +} + +static int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) +{ + loff_t range_start = page_offset(page); + loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); + + return nfs_sync_mapping_range(inode->i_mapping, range_start, range_end, how | FLUSH_STABLE); +} + +/* + * Write back all requests on one page - we do this before reading it. + */ +int nfs_wb_page(struct inode *inode, struct page* page) +{ + return nfs_wb_page_priority(inode, page, 0); +} + + int __init nfs_init_writepagecache(void) { nfs_wdata_cachep = kmem_cache_create("nfs_write_data", diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index f8190ae9e3fb..f2ec9be1e22f 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -432,7 +432,10 @@ extern void nfs_writedata_release(void *); * Try to write back everything synchronously (but check the * return value!) */ -extern long nfs_sync_inode_wait(struct inode *, unsigned long, unsigned int, int); +extern long nfs_sync_mapping_wait(struct address_space *, struct writeback_control *, int); +extern int nfs_sync_mapping_range(struct address_space *, loff_t, loff_t, int); +extern int nfs_wb_all(struct inode *inode); +extern int nfs_wb_page(struct inode *inode, struct page* page); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) extern int nfs_commit_inode(struct inode *, int); extern struct nfs_write_data *nfs_commit_alloc(void); @@ -452,28 +455,6 @@ nfs_have_writebacks(struct inode *inode) return NFS_I(inode)->npages != 0; } -static inline int -nfs_wb_all(struct inode *inode) -{ - int error = nfs_sync_inode_wait(inode, 0, 0, 0); - return (error < 0) ? error : 0; -} - -/* - * Write back all requests on one page - we do this before reading it. - */ -static inline int nfs_wb_page_priority(struct inode *inode, struct page* page, int how) -{ - int error = nfs_sync_inode_wait(inode, page->index, 1, - how | FLUSH_STABLE); - return (error < 0) ? error : 0; -} - -static inline int nfs_wb_page(struct inode *inode, struct page* page) -{ - return nfs_wb_page_priority(inode, page, 0); -} - /* * Allocate nfs_write_data structures */ -- cgit v1.2.3 From 200baa2112012dd8a13db9da3ee6885403f9c013 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Dec 2006 00:35:40 -0500 Subject: NFS: Remove nfs_writepage_sync() Maintaining two parallel ways of doing synchronous writes is rather pointless. This patch gets rid of the legacy nfs_writepage_sync(), and replaces it with the faster asynchronous writes. Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 6 +++ fs/nfs/nfs3proc.c | 47 ----------------------- fs/nfs/nfs4proc.c | 85 ---------------------------------------- fs/nfs/proc.c | 28 -------------- fs/nfs/write.c | 100 ++---------------------------------------------- include/linux/nfs_xdr.h | 2 - 6 files changed, 10 insertions(+), 258 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/file.c b/fs/nfs/file.c index d6ee60fc3ba6..143a19037ce8 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -378,6 +378,12 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); result = generic_file_aio_write(iocb, iov, nr_segs, pos); + /* Return error values for O_SYNC and IS_SYNC() */ + if (result >= 0 && (IS_SYNC(inode) || (iocb->ki_filp->f_flags & O_SYNC))) { + int err = nfs_fsync(iocb->ki_filp, dentry, 1); + if (err < 0) + result = err; + } out: return result; diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 7fba06306b82..510ae524f3fd 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -276,51 +276,6 @@ static int nfs3_proc_read(struct nfs_read_data *rdata) return status; } -static int nfs3_proc_write(struct nfs_write_data *wdata) -{ - int rpcflags = wdata->flags; - struct inode * inode = wdata->inode; - struct nfs_fattr * fattr = wdata->res.fattr; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], - .rpc_argp = &wdata->args, - .rpc_resp = &wdata->res, - .rpc_cred = wdata->cred, - }; - int status; - - dprintk("NFS call write %d @ %Ld\n", wdata->args.count, - (long long) wdata->args.offset); - nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); - if (status >= 0) - nfs_post_op_update_inode(inode, fattr); - dprintk("NFS reply write: %d\n", status); - return status < 0? status : wdata->res.count; -} - -static int nfs3_proc_commit(struct nfs_write_data *cdata) -{ - struct inode * inode = cdata->inode; - struct nfs_fattr * fattr = cdata->res.fattr; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], - .rpc_argp = &cdata->args, - .rpc_resp = &cdata->res, - .rpc_cred = cdata->cred, - }; - int status; - - dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, - (long long) cdata->args.offset); - nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); - if (status >= 0) - nfs_post_op_update_inode(inode, fattr); - dprintk("NFS reply commit: %d\n", status); - return status; -} - /* * Create a regular file. * For now, we don't implement O_EXCL. @@ -901,8 +856,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = { .access = nfs3_proc_access, .readlink = nfs3_proc_readlink, .read = nfs3_proc_read, - .write = nfs3_proc_write, - .commit = nfs3_proc_commit, .create = nfs3_proc_create, .remove = nfs3_proc_remove, .unlink_setup = nfs3_proc_unlink_setup, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4b5fc714d786..ee458aeab24a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1775,89 +1775,6 @@ static int nfs4_proc_read(struct nfs_read_data *rdata) return err; } -static int _nfs4_proc_write(struct nfs_write_data *wdata) -{ - int rpcflags = wdata->flags; - struct inode *inode = wdata->inode; - struct nfs_fattr *fattr = wdata->res.fattr; - struct nfs_server *server = NFS_SERVER(inode); - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], - .rpc_argp = &wdata->args, - .rpc_resp = &wdata->res, - .rpc_cred = wdata->cred, - }; - int status; - - dprintk("NFS call write %d @ %Ld\n", wdata->args.count, - (long long) wdata->args.offset); - - wdata->args.bitmask = server->attr_bitmask; - wdata->res.server = server; - wdata->timestamp = jiffies; - nfs_fattr_init(fattr); - status = rpc_call_sync(server->client, &msg, rpcflags); - dprintk("NFS reply write: %d\n", status); - if (status < 0) - return status; - renew_lease(server, wdata->timestamp); - nfs_post_op_update_inode(inode, fattr); - return wdata->res.count; -} - -static int nfs4_proc_write(struct nfs_write_data *wdata) -{ - struct nfs4_exception exception = { }; - int err; - do { - err = nfs4_handle_exception(NFS_SERVER(wdata->inode), - _nfs4_proc_write(wdata), - &exception); - } while (exception.retry); - return err; -} - -static int _nfs4_proc_commit(struct nfs_write_data *cdata) -{ - struct inode *inode = cdata->inode; - struct nfs_fattr *fattr = cdata->res.fattr; - struct nfs_server *server = NFS_SERVER(inode); - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], - .rpc_argp = &cdata->args, - .rpc_resp = &cdata->res, - .rpc_cred = cdata->cred, - }; - int status; - - dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, - (long long) cdata->args.offset); - - cdata->args.bitmask = server->attr_bitmask; - cdata->res.server = server; - cdata->timestamp = jiffies; - nfs_fattr_init(fattr); - status = rpc_call_sync(server->client, &msg, 0); - if (status >= 0) - renew_lease(server, cdata->timestamp); - dprintk("NFS reply commit: %d\n", status); - if (status >= 0) - nfs_post_op_update_inode(inode, fattr); - return status; -} - -static int nfs4_proc_commit(struct nfs_write_data *cdata) -{ - struct nfs4_exception exception = { }; - int err; - do { - err = nfs4_handle_exception(NFS_SERVER(cdata->inode), - _nfs4_proc_commit(cdata), - &exception); - } while (exception.retry); - return err; -} - /* * Got race? * We will need to arrange for the VFS layer to provide an atomic open. @@ -3730,8 +3647,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = { .access = nfs4_proc_access, .readlink = nfs4_proc_readlink, .read = nfs4_proc_read, - .write = nfs4_proc_write, - .commit = nfs4_proc_commit, .create = nfs4_proc_create, .remove = nfs4_proc_remove, .unlink_setup = nfs4_proc_unlink_setup, diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 7a9013dd5d0a..10f5e80ca157 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -215,32 +215,6 @@ static int nfs_proc_read(struct nfs_read_data *rdata) return status; } -static int nfs_proc_write(struct nfs_write_data *wdata) -{ - int flags = wdata->flags; - struct inode * inode = wdata->inode; - struct nfs_fattr * fattr = wdata->res.fattr; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_WRITE], - .rpc_argp = &wdata->args, - .rpc_resp = &wdata->res, - .rpc_cred = wdata->cred, - }; - int status; - - dprintk("NFS call write %d @ %Ld\n", wdata->args.count, - (long long) wdata->args.offset); - nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); - if (status >= 0) { - nfs_post_op_update_inode(inode, fattr); - wdata->res.count = wdata->args.count; - wdata->verf.committed = NFS_FILE_SYNC; - } - dprintk("NFS reply write: %d\n", status); - return status < 0? status : wdata->res.count; -} - static int nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags, struct nameidata *nd) @@ -693,8 +667,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = { .access = NULL, /* access */ .readlink = nfs_proc_readlink, .read = nfs_proc_read, - .write = nfs_proc_write, - .commit = NULL, /* commit */ .create = nfs_proc_create, .remove = nfs_proc_remove, .unlink_setup = nfs_proc_unlink_setup, diff --git a/fs/nfs/write.c b/fs/nfs/write.c index de9a16a8f7e4..f0720b544b12 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -210,78 +210,6 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int SetPageUptodate(page); } -/* - * Write a page synchronously. - * Offset is the data offset within the page. - */ -static int nfs_writepage_sync(struct nfs_open_context *ctx, struct page *page, - unsigned int offset, unsigned int count, int how) -{ - struct inode *inode = page->mapping->host; - unsigned int wsize = NFS_SERVER(inode)->wsize; - int result, written = 0; - struct nfs_write_data *wdata; - - wdata = nfs_writedata_alloc(wsize); - if (!wdata) - return -ENOMEM; - - wdata->flags = how; - wdata->cred = ctx->cred; - wdata->inode = inode; - wdata->args.fh = NFS_FH(inode); - wdata->args.context = ctx; - wdata->args.pages = &page; - wdata->args.stable = NFS_FILE_SYNC; - wdata->args.pgbase = offset; - wdata->args.count = wsize; - wdata->res.fattr = &wdata->fattr; - wdata->res.verf = &wdata->verf; - - dprintk("NFS: nfs_writepage_sync(%s/%Ld %d@%Ld)\n", - inode->i_sb->s_id, - (long long)NFS_FILEID(inode), - count, (long long)(page_offset(page) + offset)); - - set_page_writeback(page); - nfs_begin_data_update(inode); - do { - if (count < wsize) - wdata->args.count = count; - wdata->args.offset = page_offset(page) + wdata->args.pgbase; - - result = NFS_PROTO(inode)->write(wdata); - - if (result < 0) { - /* Must mark the page invalid after I/O error */ - ClearPageUptodate(page); - goto io_error; - } - if (result < wdata->args.count) - printk(KERN_WARNING "NFS: short write, count=%u, result=%d\n", - wdata->args.count, result); - - wdata->args.offset += result; - wdata->args.pgbase += result; - written += result; - count -= result; - nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, result); - } while (count); - /* Update file length */ - nfs_grow_file(page, offset, written); - /* Set the PG_uptodate flag? */ - nfs_mark_uptodate(page, offset, written); - - if (PageError(page)) - ClearPageError(page); - -io_error: - nfs_end_data_update(inode); - end_page_writeback(page); - nfs_writedata_release(wdata); - return written ? written : result; -} - static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, unsigned int offset, unsigned int count) { @@ -342,22 +270,12 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) err = -EBADF; goto out; } - lock_kernel(); - if (!IS_SYNC(inode)) { - err = nfs_writepage_setup(ctx, page, 0, offset); - if (!wbc->for_writepages) - nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); - } else { - err = nfs_writepage_sync(ctx, page, 0, offset, wb_priority(wbc)); - if (err >= 0) { - if (err != offset) - redirty_page_for_writepage(wbc, page); - err = 0; - } - } - unlock_kernel(); + err = nfs_writepage_setup(ctx, page, 0, offset); put_nfs_open_context(ctx); + out: + if (!wbc->for_writepages) + nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); unlock_page(page); return err; } @@ -777,16 +695,6 @@ int nfs_updatepage(struct file *file, struct page *page, file->f_dentry->d_name.name, count, (long long)(page_offset(page) +offset)); - if (IS_SYNC(inode)) { - status = nfs_writepage_sync(ctx, page, offset, count, 0); - if (status > 0) { - if (offset == 0 && status == PAGE_CACHE_SIZE) - SetPageUptodate(page); - return 0; - } - return status; - } - /* If we're not using byte range locks, and we know the page * is entirely in cache, it may be more efficient to avoid * fragmenting write requests. diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 768c1ad5ff6f..9ee9da5e1cc9 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -785,8 +785,6 @@ struct nfs_rpc_ops { int (*readlink)(struct inode *, struct page *, unsigned int, unsigned int); int (*read) (struct nfs_read_data *); - int (*write) (struct nfs_write_data *); - int (*commit) (struct nfs_write_data *); int (*create) (struct inode *, struct dentry *, struct iattr *, int, struct nameidata *); int (*remove) (struct inode *, struct qstr *); -- cgit v1.2.3 From 1a54533ec8d92a5edae97ec6ae10023ee71c4b46 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Dec 2006 00:35:40 -0500 Subject: NFS: Add nfs_set_page_dirty() We will want to allow nfs_writepage() to distinguish between pages that have been marked as dirty by the VM, and those that have been marked as dirty by nfs_updatepage(). In the former case, the entire page will want to be written out, and so any requests that were pending need to be flushed out first. Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 2 +- fs/nfs/write.c | 49 +++++++++++++++++++++++++++++++++++------------- include/linux/nfs_fs.h | 1 + include/linux/nfs_page.h | 1 + 4 files changed, 39 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 143a19037ce8..c2fe3bd83ab1 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -331,7 +331,7 @@ static int nfs_release_page(struct page *page, gfp_t gfp) const struct address_space_operations nfs_file_aops = { .readpage = nfs_readpage, .readpages = nfs_readpages, - .set_page_dirty = __set_page_dirty_nobuffers, + .set_page_dirty = nfs_set_page_dirty, .writepage = nfs_writepage, .writepages = nfs_writepages, .prepare_write = nfs_prepare_write, diff --git a/fs/nfs/write.c b/fs/nfs/write.c index f0720b544b12..266fea71cfc0 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -251,16 +251,23 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) { struct nfs_open_context *ctx; struct inode *inode = page->mapping->host; + struct nfs_page *req; unsigned offset; - int err; + int err = 0; nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); - /* Ensure we've flushed out any previous writes */ - nfs_wb_page_priority(inode, page, wb_priority(wbc)); + req = nfs_page_find_request(page); + if (req != NULL) { + int flushme = test_bit(PG_NEED_FLUSH, &req->wb_flags); + nfs_release_request(req); + if (!flushme) + goto out; + /* Ensure we've flushed out the invalid write */ + nfs_wb_page_priority(inode, page, wb_priority(wbc)); + } - err = 0; offset = nfs_page_length(page); if (!offset) goto out; @@ -655,7 +662,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page) { struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; struct nfs_page *req; - int status = 0; + int do_flush, status; /* * Look for a request corresponding to this page. If there * is one, and it belongs to another file, we flush it out @@ -664,15 +671,18 @@ int nfs_flush_incompatible(struct file *file, struct page *page) * Also do the same if we find a request from an existing * dropped page. */ - req = nfs_page_find_request(page); - if (req != NULL) { - int do_flush = req->wb_page != page || req->wb_context != ctx; - + do { + req = nfs_page_find_request(page); + if (req == NULL) + return 0; + do_flush = req->wb_page != page || req->wb_context != ctx + || test_bit(PG_NEED_FLUSH, &req->wb_flags); nfs_release_request(req); - if (do_flush) - status = nfs_wb_page(page->mapping->host, page); - } - return (status < 0) ? status : 0; + if (!do_flush) + return 0; + status = nfs_wb_page(page->mapping->host, page); + } while (status == 0); + return status; } /* @@ -1437,6 +1447,19 @@ int nfs_wb_page(struct inode *inode, struct page* page) return nfs_wb_page_priority(inode, page, 0); } +int nfs_set_page_dirty(struct page *page) +{ + struct nfs_page *req; + + req = nfs_page_find_request(page); + if (req != NULL) { + /* Mark any existing write requests for flushing */ + set_bit(PG_NEED_FLUSH, &req->wb_flags); + nfs_release_request(req); + } + return __set_page_dirty_nobuffers(page); +} + int __init nfs_init_writepagecache(void) { diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index f2ec9be1e22f..1b38c2085a53 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -427,6 +427,7 @@ extern int nfs_flush_incompatible(struct file *file, struct page *page); extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); extern void nfs_writedata_release(void *); +extern int nfs_set_page_dirty(struct page *); /* * Try to write back everything synchronously (but check the diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 38aa15fea638..d111be639140 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -30,6 +30,7 @@ #define PG_BUSY 0 #define PG_NEED_COMMIT 1 #define PG_NEED_RESCHED 2 +#define PG_NEED_FLUSH 3 struct nfs_inode; struct nfs_page { -- cgit v1.2.3 From 4d770ccf4257b23a7ca2a85de1b1c22657b581d8 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Dec 2006 00:35:41 -0500 Subject: NFS: Ensure that nfs_wb_page() calls writepage when necessary. Signed-off-by: Trond Myklebust --- fs/nfs/write.c | 34 ++++++++++++++++++++++++++++++---- include/linux/nfs_fs.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 266fea71cfc0..0eca6a542106 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -247,7 +247,7 @@ static int wb_priority(struct writeback_control *wbc) /* * Write an mmapped page to the server. */ -int nfs_writepage(struct page *page, struct writeback_control *wbc) +static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) { struct nfs_open_context *ctx; struct inode *inode = page->mapping->host; @@ -265,7 +265,7 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) if (!flushme) goto out; /* Ensure we've flushed out the invalid write */ - nfs_wb_page_priority(inode, page, wb_priority(wbc)); + nfs_wb_page_priority(inode, page, wb_priority(wbc) | FLUSH_STABLE | FLUSH_NOWRITEPAGE); } offset = nfs_page_length(page); @@ -283,6 +283,14 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) out: if (!wbc->for_writepages) nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); + return err; +} + +int nfs_writepage(struct page *page, struct writeback_control *wbc) +{ + int err; + + err = nfs_writepage_locked(page, wbc); unlock_page(page); return err; } @@ -1435,8 +1443,26 @@ static int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) { loff_t range_start = page_offset(page); loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); + struct writeback_control wbc = { + .bdi = page->mapping->backing_dev_info, + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .range_start = range_start, + .range_end = range_end, + }; + int ret; - return nfs_sync_mapping_range(inode->i_mapping, range_start, range_end, how | FLUSH_STABLE); + BUG_ON(!PageLocked(page)); + if (!(how & FLUSH_NOWRITEPAGE) && clear_page_dirty_for_io(page)) { + ret = nfs_writepage_locked(page, &wbc); + if (ret < 0) + goto out; + } + ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); + if (ret >= 0) + return 0; +out: + return ret; } /* @@ -1444,7 +1470,7 @@ static int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) */ int nfs_wb_page(struct inode *inode, struct page* page) { - return nfs_wb_page_priority(inode, page, 0); + return nfs_wb_page_priority(inode, page, FLUSH_STABLE); } int nfs_set_page_dirty(struct page *page) diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 1b38c2085a53..3de334c72b1f 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -33,6 +33,7 @@ #define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */ #define FLUSH_NOCOMMIT 32 /* Don't send the NFSv3/v4 COMMIT */ #define FLUSH_INVALIDATE 64 /* Invalidate the page cache */ +#define FLUSH_NOWRITEPAGE 128 /* Don't call writepage() */ #ifdef __KERNEL__ -- cgit v1.2.3 From e261f51f25b98c213e0b3d7f2109b117d714f69d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Dec 2006 00:35:41 -0500 Subject: NFS: Make nfs_updatepage() mark the page as dirty. This will ensure that we can call set_page_writeback() from within nfs_writepage(), which is always called with the page lock set. Signed-off-by: Trond Myklebust --- fs/nfs/write.c | 73 +++++++++++++++++++++++++++++++++++++----------- include/linux/nfs_page.h | 1 + 2 files changed, 57 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 0eca6a542106..130528d09a26 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -77,6 +77,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*, struct page *, unsigned int, unsigned int); +static void nfs_mark_request_dirty(struct nfs_page *req); static int nfs_wait_on_write_congestion(struct address_space *, int); static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); @@ -244,6 +245,48 @@ static int wb_priority(struct writeback_control *wbc) return 0; } +/* + * Find an associated nfs write request, and prepare to flush it out + * Returns 1 if there was no write request, or if the request was + * already tagged by nfs_set_page_dirty.Returns 0 if the request + * was not tagged. + * May also return an error if the user signalled nfs_wait_on_request(). + */ +static int nfs_page_mark_flush(struct page *page) +{ + struct nfs_page *req; + spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; + int ret; + + spin_lock(req_lock); + for(;;) { + req = nfs_page_find_request_locked(page); + if (req == NULL) { + spin_unlock(req_lock); + return 1; + } + if (nfs_lock_request_dontget(req)) + break; + /* Note: If we hold the page lock, as is the case in nfs_writepage, + * then the call to nfs_lock_request_dontget() will always + * succeed provided that someone hasn't already marked the + * request as dirty (in which case we don't care). + */ + spin_unlock(req_lock); + ret = nfs_wait_on_request(req); + nfs_release_request(req); + if (ret != 0) + return ret; + spin_lock(req_lock); + } + spin_unlock(req_lock); + if (test_and_set_bit(PG_FLUSHING, &req->wb_flags) == 0) + nfs_mark_request_dirty(req); + ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); + nfs_unlock_request(req); + return ret; +} + /* * Write an mmapped page to the server. */ @@ -251,23 +294,16 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc { struct nfs_open_context *ctx; struct inode *inode = page->mapping->host; - struct nfs_page *req; unsigned offset; - int err = 0; + int err; nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); - req = nfs_page_find_request(page); - if (req != NULL) { - int flushme = test_bit(PG_NEED_FLUSH, &req->wb_flags); - nfs_release_request(req); - if (!flushme) - goto out; - /* Ensure we've flushed out the invalid write */ - nfs_wb_page_priority(inode, page, wb_priority(wbc) | FLUSH_STABLE | FLUSH_NOWRITEPAGE); - } - + err = nfs_page_mark_flush(page); + if (err <= 0) + goto out; + err = 0; offset = nfs_page_length(page); if (!offset) goto out; @@ -279,7 +315,11 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc } err = nfs_writepage_setup(ctx, page, 0, offset); put_nfs_open_context(ctx); - + if (err != 0) + goto out; + err = nfs_page_mark_flush(page); + if (err > 0) + err = 0; out: if (!wbc->for_writepages) nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); @@ -409,8 +449,7 @@ nfs_mark_request_dirty(struct nfs_page *req) static inline int nfs_dirty_request(struct nfs_page *req) { - struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); - return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty; + return test_bit(PG_FLUSHING, &req->wb_flags) == 0; } #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) @@ -628,7 +667,6 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, return ERR_PTR(error); } spin_unlock(&nfsi->req_lock); - nfs_mark_request_dirty(new); return new; } spin_unlock(&nfsi->req_lock); @@ -684,7 +722,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page) if (req == NULL) return 0; do_flush = req->wb_page != page || req->wb_context != ctx - || test_bit(PG_NEED_FLUSH, &req->wb_flags); + || !nfs_dirty_request(req); nfs_release_request(req); if (!do_flush) return 0; @@ -723,6 +761,7 @@ int nfs_updatepage(struct file *file, struct page *page, } status = nfs_writepage_setup(ctx, page, offset, count); + __set_page_dirty_nobuffers(page); dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", status, (long long)i_size_read(inode)); diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index d111be639140..2e555d49c9b7 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -31,6 +31,7 @@ #define PG_NEED_COMMIT 1 #define PG_NEED_RESCHED 2 #define PG_NEED_FLUSH 3 +#define PG_FLUSHING 4 struct nfs_inode; struct nfs_page { -- cgit v1.2.3 From 61822ab5e3ed09fcfc49e37227b655202adf6130 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Dec 2006 00:35:42 -0500 Subject: NFS: Ensure we only call set_page_writeback() under the page lock Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 6 +----- fs/nfs/write.c | 38 ++++++++++++++++++++++++++++---------- include/linux/nfs_fs.h | 1 + 3 files changed, 30 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/file.c b/fs/nfs/file.c index c2fe3bd83ab1..238fb6641aae 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -307,14 +307,10 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse static void nfs_invalidate_page(struct page *page, unsigned long offset) { - loff_t range_start, range_end; - if (offset != 0) return; /* Cancel any unstarted writes on this page */ - range_start = page_offset(page); - range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); - nfs_sync_mapping_range(page->mapping, range_start, range_end, FLUSH_INVALIDATE); + nfs_wb_page_priority(page->mapping->host, page, FLUSH_INVALIDATE); } static int nfs_release_page(struct page *page, gfp_t gfp) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 130528d09a26..bd4dff9dbd69 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -81,7 +81,6 @@ static void nfs_mark_request_dirty(struct nfs_page *req); static int nfs_wait_on_write_congestion(struct address_space *, int); static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); -static int nfs_wb_page_priority(struct inode *inode, struct page *page, int how); static const struct rpc_call_ops nfs_write_partial_ops; static const struct rpc_call_ops nfs_write_full_ops; static const struct rpc_call_ops nfs_commit_ops; @@ -280,8 +279,10 @@ static int nfs_page_mark_flush(struct page *page) spin_lock(req_lock); } spin_unlock(req_lock); - if (test_and_set_bit(PG_FLUSHING, &req->wb_flags) == 0) + if (test_and_set_bit(PG_FLUSHING, &req->wb_flags) == 0) { nfs_mark_request_dirty(req); + set_page_writeback(page); + } ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); nfs_unlock_request(req); return ret; @@ -443,6 +444,13 @@ nfs_mark_request_dirty(struct nfs_page *req) mark_inode_dirty(inode); } +static void +nfs_redirty_request(struct nfs_page *req) +{ + clear_bit(PG_FLUSHING, &req->wb_flags); + __set_page_dirty_nobuffers(req->wb_page); +} + /* * Check if a request is dirty */ @@ -777,7 +785,7 @@ static void nfs_writepage_release(struct nfs_page *req) #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) if (!PageError(req->wb_page)) { if (NFS_NEED_RESCHED(req)) { - nfs_mark_request_dirty(req); + nfs_redirty_request(req); goto out; } else if (NFS_NEED_COMMIT(req)) { nfs_mark_request_commit(req); @@ -893,7 +901,6 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how) atomic_set(&req->wb_complete, requests); ClearPageError(page); - set_page_writeback(page); offset = 0; nbytes = req->wb_bytes; do { @@ -923,7 +930,7 @@ out_bad: list_del(&data->pages); nfs_writedata_release(data); } - nfs_mark_request_dirty(req); + nfs_redirty_request(req); nfs_clear_page_writeback(req); return -ENOMEM; } @@ -954,7 +961,6 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) nfs_list_remove_request(req); nfs_list_add_request(req, &data->pages); ClearPageError(req->wb_page); - set_page_writeback(req->wb_page); *pages++ = req->wb_page; count += req->wb_bytes; } @@ -969,7 +975,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) while (!list_empty(head)) { struct nfs_page *req = nfs_list_entry(head->next); nfs_list_remove_request(req); - nfs_mark_request_dirty(req); + nfs_redirty_request(req); nfs_clear_page_writeback(req); } return -ENOMEM; @@ -1004,7 +1010,7 @@ out_err: while (!list_empty(head)) { req = nfs_list_entry(head->next); nfs_list_remove_request(req); - nfs_mark_request_dirty(req); + nfs_redirty_request(req); nfs_clear_page_writeback(req); } return error; @@ -1320,7 +1326,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) } /* We have a mismatch. Write the page again */ dprintk(" mismatch\n"); - nfs_mark_request_dirty(req); + nfs_redirty_request(req); next: nfs_clear_page_writeback(req); } @@ -1451,13 +1457,18 @@ int nfs_wb_all(struct inode *inode) .bdi = mapping->backing_dev_info, .sync_mode = WB_SYNC_ALL, .nr_to_write = LONG_MAX, + .for_writepages = 1, .range_cyclic = 1, }; int ret; + ret = generic_writepages(mapping, &wbc); + if (ret < 0) + goto out; ret = nfs_sync_mapping_wait(mapping, &wbc, 0); if (ret >= 0) return 0; +out: return ret; } @@ -1469,16 +1480,23 @@ int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, lo .nr_to_write = LONG_MAX, .range_start = range_start, .range_end = range_end, + .for_writepages = 1, }; int ret; + if (!(how & FLUSH_NOWRITEPAGE)) { + ret = generic_writepages(mapping, &wbc); + if (ret < 0) + goto out; + } ret = nfs_sync_mapping_wait(mapping, &wbc, how); if (ret >= 0) return 0; +out: return ret; } -static int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) +int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) { loff_t range_start = page_offset(page); loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 3de334c72b1f..04963063e620 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -438,6 +438,7 @@ extern long nfs_sync_mapping_wait(struct address_space *, struct writeback_contr extern int nfs_sync_mapping_range(struct address_space *, loff_t, loff_t, int); extern int nfs_wb_all(struct inode *inode); extern int nfs_wb_page(struct inode *inode, struct page* page); +extern int nfs_wb_page_priority(struct inode *inode, struct page* page, int how); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) extern int nfs_commit_inode(struct inode *, int); extern struct nfs_write_data *nfs_commit_alloc(void); -- cgit v1.2.3 From 8fc7500bb8ea3b5c909869d00628635e964ae882 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 4 Dec 2006 20:22:31 -0500 Subject: rpc: gss: eliminate print_hexl()'s Dumping all this data to the logs is wasteful (even when debugging is turned off), and creates too much output to be useful when it's turned on. Fix a minor style bug or two while we're at it. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/auth_gss.h | 2 -- net/sunrpc/auth_gss/auth_gss.c | 40 ---------------------------------- net/sunrpc/auth_gss/gss_krb5_crypto.c | 16 ++------------ net/sunrpc/auth_gss/gss_krb5_seal.c | 3 --- net/sunrpc/auth_gss/gss_krb5_wrap.c | 3 --- net/sunrpc/auth_gss/gss_spkm3_unseal.c | 4 ---- 6 files changed, 2 insertions(+), 66 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h index 97b62e97dd8d..2db2fbf34947 100644 --- a/include/linux/sunrpc/auth_gss.h +++ b/include/linux/sunrpc/auth_gss.h @@ -90,8 +90,6 @@ struct gss_cred { #define gc_flags gc_base.cr_flags #define gc_expire gc_base.cr_expire -void print_hexl(u32 *p, u_int length, u_int offset); - #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_AUTH_GSS_H */ diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index e5a84a482e57..d12ee5f54c0c 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -94,46 +94,6 @@ struct gss_auth { static void gss_destroy_ctx(struct gss_cl_ctx *); static struct rpc_pipe_ops gss_upcall_ops; -void -print_hexl(u32 *p, u_int length, u_int offset) -{ - u_int i, j, jm; - u8 c, *cp; - - dprintk("RPC: print_hexl: length %d\n",length); - dprintk("\n"); - cp = (u8 *) p; - - for (i = 0; i < length; i += 0x10) { - dprintk(" %04x: ", (u_int)(i + offset)); - jm = length - i; - jm = jm > 16 ? 16 : jm; - - for (j = 0; j < jm; j++) { - if ((j % 2) == 1) - dprintk("%02x ", (u_int)cp[i+j]); - else - dprintk("%02x", (u_int)cp[i+j]); - } - for (; j < 16; j++) { - if ((j % 2) == 1) - dprintk(" "); - else - dprintk(" "); - } - dprintk(" "); - - for (j = 0; j < jm; j++) { - c = cp[i+j]; - c = isprint(c) ? c : '.'; - dprintk("%c", c); - } - dprintk("\n"); - } -} - -EXPORT_SYMBOL(print_hexl); - static inline struct gss_cl_ctx * gss_get_ctx(struct gss_cl_ctx *ctx) { diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index e11a40b25cce..4c53896f1b08 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -61,9 +61,6 @@ krb5_encrypt( u8 local_iv[16] = {0}; struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv }; - dprintk("RPC: krb5_encrypt: input data:\n"); - print_hexl((u32 *)in, length, 0); - if (length % crypto_blkcipher_blocksize(tfm) != 0) goto out; @@ -80,12 +77,9 @@ krb5_encrypt( sg_set_buf(sg, out, length); ret = crypto_blkcipher_encrypt_iv(&desc, sg, sg, length); - - dprintk("RPC: krb5_encrypt: output data:\n"); - print_hexl((u32 *)out, length, 0); out: dprintk("RPC: krb5_encrypt returns %d\n",ret); - return(ret); + return ret; } EXPORT_SYMBOL(krb5_encrypt); @@ -103,9 +97,6 @@ krb5_decrypt( u8 local_iv[16] = {0}; struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv }; - dprintk("RPC: krb5_decrypt: input data:\n"); - print_hexl((u32 *)in, length, 0); - if (length % crypto_blkcipher_blocksize(tfm) != 0) goto out; @@ -121,12 +112,9 @@ krb5_decrypt( sg_set_buf(sg, out, length); ret = crypto_blkcipher_decrypt_iv(&desc, sg, sg, length); - - dprintk("RPC: krb5_decrypt: output_data:\n"); - print_hexl((u32 *)out, length, 0); out: dprintk("RPC: gss_k5decrypt returns %d\n",ret); - return(ret); + return ret; } EXPORT_SYMBOL(krb5_decrypt); diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 08601ee4cd73..dc58af0b8b4c 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -129,9 +129,6 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, KRB5_CKSUM_LENGTH); - - dprintk("RPC: make_seal_token: cksum data: \n"); - print_hexl((u32 *) (krb5_hdr + 16), KRB5_CKSUM_LENGTH, 0); break; default: BUG(); diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index cc45c1605f80..0f512e8e0d19 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -199,9 +199,6 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, KRB5_CKSUM_LENGTH); - - dprintk("RPC: make_seal_token: cksum data: \n"); - print_hexl((u32 *) (krb5_hdr + 16), KRB5_CKSUM_LENGTH, 0); break; default: BUG(); diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c index 8537f581ef9b..544eb6fd9094 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_unseal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_unseal.c @@ -103,10 +103,6 @@ spkm3_read_token(struct spkm3_ctx *ctx, dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n", wire_cksum.len); - dprintk(" md5cksum.data\n"); - print_hexl((u32 *) md5cksum.data, 16, 0); - dprintk(" cksum.data:\n"); - print_hexl((u32 *) wire_cksum.data, wire_cksum.len, 0); ret = GSS_S_BAD_SIG; code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len); -- cgit v1.2.3 From 37a4e6cb0391f2293ba3d59e3a63ec0e56ed720d Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Mon, 4 Dec 2006 20:22:33 -0500 Subject: rpc: move process_xdr_buf Since process_xdr_buf() is useful outside of the kerberos-specific code, we move it to net/sunrpc/xdr.c, export it, and rename it in keeping with xdr_* naming convention of xdr.c. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xdr.h | 2 + net/sunrpc/auth_gss/gss_krb5_crypto.c | 73 ++--------------------------------- net/sunrpc/xdr.c | 68 ++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 69 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 441b91dbafe5..4d17846cd78a 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -11,6 +11,7 @@ #include #include +#include /* * Buffer adjustment @@ -196,6 +197,7 @@ extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes); extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len); extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len); +extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data); #endif /* __KERNEL__ */ diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 4c53896f1b08..10d05ea37213 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH @@ -119,72 +120,6 @@ out: EXPORT_SYMBOL(krb5_decrypt); -static int -process_xdr_buf(struct xdr_buf *buf, int offset, int len, - int (*actor)(struct scatterlist *, void *), void *data) -{ - int i, page_len, thislen, page_offset, ret = 0; - struct scatterlist sg[1]; - - if (offset >= buf->head[0].iov_len) { - offset -= buf->head[0].iov_len; - } else { - thislen = buf->head[0].iov_len - offset; - if (thislen > len) - thislen = len; - sg_set_buf(sg, buf->head[0].iov_base + offset, thislen); - ret = actor(sg, data); - if (ret) - goto out; - offset = 0; - len -= thislen; - } - if (len == 0) - goto out; - - if (offset >= buf->page_len) { - offset -= buf->page_len; - } else { - page_len = buf->page_len - offset; - if (page_len > len) - page_len = len; - len -= page_len; - page_offset = (offset + buf->page_base) & (PAGE_CACHE_SIZE - 1); - i = (offset + buf->page_base) >> PAGE_CACHE_SHIFT; - thislen = PAGE_CACHE_SIZE - page_offset; - do { - if (thislen > page_len) - thislen = page_len; - sg->page = buf->pages[i]; - sg->offset = page_offset; - sg->length = thislen; - ret = actor(sg, data); - if (ret) - goto out; - page_len -= thislen; - i++; - page_offset = 0; - thislen = PAGE_CACHE_SIZE; - } while (page_len != 0); - offset = 0; - } - if (len == 0) - goto out; - - if (offset < buf->tail[0].iov_len) { - thislen = buf->tail[0].iov_len - offset; - if (thislen > len) - thislen = len; - sg_set_buf(sg, buf->tail[0].iov_base + offset, thislen); - ret = actor(sg, data); - len -= thislen; - } - if (len != 0) - ret = -EINVAL; -out: - return ret; -} - static int checksummer(struct scatterlist *sg, void *data) { @@ -225,7 +160,7 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, err = crypto_hash_update(&desc, sg, hdrlen); if (err) goto out; - err = process_xdr_buf(body, body_offset, body->len - body_offset, + err = xdr_process_buf(body, body_offset, body->len - body_offset, checksummer, &desc); if (err) goto out; @@ -323,7 +258,7 @@ gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf, desc.fragno = 0; desc.fraglen = 0; - ret = process_xdr_buf(buf, offset, buf->len - offset, encryptor, &desc); + ret = xdr_process_buf(buf, offset, buf->len - offset, encryptor, &desc); return ret; } @@ -389,7 +324,7 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf, desc.desc.flags = 0; desc.fragno = 0; desc.fraglen = 0; - return process_xdr_buf(buf, offset, buf->len - offset, decryptor, &desc); + return xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc); } EXPORT_SYMBOL(gss_decrypt_xdr_buf); diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 5a6485946f3c..a0af250ca319 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -1021,3 +1021,71 @@ xdr_encode_array2(struct xdr_buf *buf, unsigned int base, return xdr_xcode_array2(buf, base, desc, 1); } + +int +xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, + int (*actor)(struct scatterlist *, void *), void *data) +{ + int i, ret = 0; + unsigned page_len, thislen, page_offset; + struct scatterlist sg[1]; + + if (offset >= buf->head[0].iov_len) { + offset -= buf->head[0].iov_len; + } else { + thislen = buf->head[0].iov_len - offset; + if (thislen > len) + thislen = len; + sg_set_buf(sg, buf->head[0].iov_base + offset, thislen); + ret = actor(sg, data); + if (ret) + goto out; + offset = 0; + len -= thislen; + } + if (len == 0) + goto out; + + if (offset >= buf->page_len) { + offset -= buf->page_len; + } else { + page_len = buf->page_len - offset; + if (page_len > len) + page_len = len; + len -= page_len; + page_offset = (offset + buf->page_base) & (PAGE_CACHE_SIZE - 1); + i = (offset + buf->page_base) >> PAGE_CACHE_SHIFT; + thislen = PAGE_CACHE_SIZE - page_offset; + do { + if (thislen > page_len) + thislen = page_len; + sg->page = buf->pages[i]; + sg->offset = page_offset; + sg->length = thislen; + ret = actor(sg, data); + if (ret) + goto out; + page_len -= thislen; + i++; + page_offset = 0; + thislen = PAGE_CACHE_SIZE; + } while (page_len != 0); + offset = 0; + } + if (len == 0) + goto out; + if (offset < buf->tail[0].iov_len) { + thislen = buf->tail[0].iov_len - offset; + if (thislen > len) + thislen = len; + sg_set_buf(sg, buf->tail[0].iov_base + offset, thislen); + ret = actor(sg, data); + len -= thislen; + } + if (len != 0) + ret = -EINVAL; +out: + return ret; +} +EXPORT_SYMBOL(xdr_process_buf); + -- cgit v1.2.3 From adeb8133dd57f380e70a389a89a2ea3ae227f9e2 Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Mon, 4 Dec 2006 20:22:34 -0500 Subject: rpc: spkm3 update This updates the spkm3 code to bring it up to date with our current understanding of the spkm3 spec. In doing so, we're changing the downcall format used by gssd in the spkm3 case, which will cause an incompatilibity with old userland spkm3 support. Since the old code a) didn't implement the protocol correctly, and b) was never distributed except in the form of some experimental patches from the citi web site, we're assuming this is OK. We do detect the old downcall format and print warning (and fail). We also include a version number in the new downcall format, to be used in the future in case any further change is required. In some more detail: - fix integrity support - removed dependency on NIDs. instead OIDs are used - known OID values for algorithms added. - fixed some context fields and types Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_spkm3.h | 34 ++++----- net/sunrpc/auth_gss/auth_gss.c | 2 +- net/sunrpc/auth_gss/gss_spkm3_mech.c | 131 +++++++++------------------------ net/sunrpc/auth_gss/gss_spkm3_seal.c | 101 +++++++++++++++++++------ net/sunrpc/auth_gss/gss_spkm3_token.c | 6 +- net/sunrpc/auth_gss/gss_spkm3_unseal.c | 88 +++++++++++----------- 6 files changed, 180 insertions(+), 182 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/gss_spkm3.h b/include/linux/sunrpc/gss_spkm3.h index 2cf3fbb40b4f..e3e6a3437f8b 100644 --- a/include/linux/sunrpc/gss_spkm3.h +++ b/include/linux/sunrpc/gss_spkm3.h @@ -12,27 +12,19 @@ #include struct spkm3_ctx { - struct xdr_netobj ctx_id; /* per message context id */ - int qop; /* negotiated qop */ + struct xdr_netobj ctx_id; /* per message context id */ + int endtime; /* endtime of the context */ struct xdr_netobj mech_used; unsigned int ret_flags ; - unsigned int req_flags ; - struct xdr_netobj share_key; - int conf_alg; - struct crypto_blkcipher *derived_conf_key; - int intg_alg; - struct crypto_blkcipher *derived_integ_key; - int keyestb_alg; /* alg used to get share_key */ - int owf_alg; /* one way function */ + struct xdr_netobj conf_alg; + struct xdr_netobj derived_conf_key; + struct xdr_netobj intg_alg; + struct xdr_netobj derived_integ_key; }; -/* from openssl/objects.h */ -/* XXX need SEAL_ALG_NONE */ -#define NID_md5 4 -#define NID_dhKeyAgreement 28 -#define NID_des_cbc 31 -#define NID_sha1 64 -#define NID_cast5_cbc 108 +/* OIDs declarations for K-ALG, I-ALG, C-ALG, and OWF-ALG */ +extern const struct xdr_netobj hmac_md5_oid; +extern const struct xdr_netobj cast5_cbc_oid; /* SPKM InnerContext Token types */ @@ -46,11 +38,13 @@ u32 spkm3_make_token(struct spkm3_ctx *ctx, struct xdr_buf * text, struct xdr_ne u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int toktype); #define CKSUMTYPE_RSA_MD5 0x0007 +#define CKSUMTYPE_HMAC_MD5 0x0008 -s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, - int body_offset, struct xdr_netobj *cksum); +s32 make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header, + unsigned int hdrlen, struct xdr_buf *body, + unsigned int body_offset, struct xdr_netobj *cksum); void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits); -int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, +int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen); void spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, unsigned char *ctxhdr, int elen, int zbit); diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index d12ee5f54c0c..a02ecc1f230d 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -68,7 +68,7 @@ static struct rpc_credops gss_credops; #define GSS_CRED_SLACK 1024 /* XXX: unused */ /* length of a krb5 verifier (48), plus data added before arguments when * using integrity (two 4-byte integers): */ -#define GSS_VERF_SLACK 56 +#define GSS_VERF_SLACK 100 /* XXX this define must match the gssd define * as it is passed to gssd to signal the use of diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c index d57f60838895..41465072d0b5 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c @@ -82,133 +82,73 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) return q; } -static inline const void * -get_key(const void *p, const void *end, struct crypto_blkcipher **res, - int *resalg) -{ - struct xdr_netobj key = { 0 }; - int setkey = 0; - char *alg_name; - - p = simple_get_bytes(p, end, resalg, sizeof(*resalg)); - if (IS_ERR(p)) - goto out_err; - p = simple_get_netobj(p, end, &key); - if (IS_ERR(p)) - goto out_err; - - switch (*resalg) { - case NID_des_cbc: - alg_name = "cbc(des)"; - setkey = 1; - break; - case NID_cast5_cbc: - /* XXXX here in name only, not used */ - alg_name = "cbc(cast5)"; - setkey = 0; /* XXX will need to set to 1 */ - break; - case NID_md5: - if (key.len == 0) { - dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n"); - } - alg_name = "md5"; - setkey = 0; - break; - default: - dprintk("gss_spkm3_mech: unsupported algorithm %d\n", *resalg); - goto out_err_free_key; - } - *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(*res)) { - printk("gss_spkm3_mech: unable to initialize crypto algorthm %s\n", alg_name); - *res = NULL; - goto out_err_free_key; - } - if (setkey) { - if (crypto_blkcipher_setkey(*res, key.data, key.len)) { - printk("gss_spkm3_mech: error setting key for crypto algorthm %s\n", alg_name); - goto out_err_free_tfm; - } - } - - if(key.len > 0) - kfree(key.data); - return p; - -out_err_free_tfm: - crypto_free_blkcipher(*res); -out_err_free_key: - if(key.len > 0) - kfree(key.data); - p = ERR_PTR(-EINVAL); -out_err: - return p; -} - static int gss_import_sec_context_spkm3(const void *p, size_t len, struct gss_ctx *ctx_id) { const void *end = (const void *)((const char *)p + len); struct spkm3_ctx *ctx; + int version; if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL))) goto out_err; + p = simple_get_bytes(p, end, &version, sizeof(version)); + if (IS_ERR(p)) + goto out_err_free_ctx; + if (version != 1) { + dprintk("RPC: unknown spkm3 token format: obsolete nfs-utils?\n"); + goto out_err_free_ctx; + } + p = simple_get_netobj(p, end, &ctx->ctx_id); if (IS_ERR(p)) goto out_err_free_ctx; - p = simple_get_bytes(p, end, &ctx->qop, sizeof(ctx->qop)); + p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); if (IS_ERR(p)) goto out_err_free_ctx_id; p = simple_get_netobj(p, end, &ctx->mech_used); if (IS_ERR(p)) - goto out_err_free_mech; + goto out_err_free_ctx_id; p = simple_get_bytes(p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)); if (IS_ERR(p)) goto out_err_free_mech; - p = simple_get_bytes(p, end, &ctx->req_flags, sizeof(ctx->req_flags)); + p = simple_get_netobj(p, end, &ctx->conf_alg); if (IS_ERR(p)) goto out_err_free_mech; - p = simple_get_netobj(p, end, &ctx->share_key); - if (IS_ERR(p)) - goto out_err_free_s_key; - - p = get_key(p, end, &ctx->derived_conf_key, &ctx->conf_alg); + p = simple_get_netobj(p, end, &ctx->derived_conf_key); if (IS_ERR(p)) - goto out_err_free_s_key; + goto out_err_free_conf_alg; - p = get_key(p, end, &ctx->derived_integ_key, &ctx->intg_alg); + p = simple_get_netobj(p, end, &ctx->intg_alg); if (IS_ERR(p)) - goto out_err_free_key1; + goto out_err_free_conf_key; - p = simple_get_bytes(p, end, &ctx->keyestb_alg, sizeof(ctx->keyestb_alg)); + p = simple_get_netobj(p, end, &ctx->derived_integ_key); if (IS_ERR(p)) - goto out_err_free_key2; - - p = simple_get_bytes(p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)); - if (IS_ERR(p)) - goto out_err_free_key2; + goto out_err_free_intg_alg; if (p != end) - goto out_err_free_key2; + goto out_err_free_intg_key; ctx_id->internal_ctx_id = ctx; dprintk("Successfully imported new spkm context.\n"); return 0; -out_err_free_key2: - crypto_free_blkcipher(ctx->derived_integ_key); -out_err_free_key1: - crypto_free_blkcipher(ctx->derived_conf_key); -out_err_free_s_key: - kfree(ctx->share_key.data); +out_err_free_intg_key: + kfree(ctx->derived_integ_key.data); +out_err_free_intg_alg: + kfree(ctx->intg_alg.data); +out_err_free_conf_key: + kfree(ctx->derived_conf_key.data); +out_err_free_conf_alg: + kfree(ctx->conf_alg.data); out_err_free_mech: kfree(ctx->mech_used.data); out_err_free_ctx_id: @@ -220,13 +160,16 @@ out_err: } static void -gss_delete_sec_context_spkm3(void *internal_ctx) { +gss_delete_sec_context_spkm3(void *internal_ctx) +{ struct spkm3_ctx *sctx = internal_ctx; - crypto_free_blkcipher(sctx->derived_integ_key); - crypto_free_blkcipher(sctx->derived_conf_key); - kfree(sctx->share_key.data); + kfree(sctx->derived_integ_key.data); + kfree(sctx->intg_alg.data); + kfree(sctx->derived_conf_key.data); + kfree(sctx->conf_alg.data); kfree(sctx->mech_used.data); + kfree(sctx->ctx_id.data); kfree(sctx); } @@ -238,7 +181,6 @@ gss_verify_mic_spkm3(struct gss_ctx *ctx, u32 maj_stat = 0; struct spkm3_ctx *sctx = ctx->internal_ctx_id; - dprintk("RPC: gss_verify_mic_spkm3 calling spkm3_read_token\n"); maj_stat = spkm3_read_token(sctx, checksum, signbuf, SPKM_MIC_TOK); dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat); @@ -253,10 +195,9 @@ gss_get_mic_spkm3(struct gss_ctx *ctx, u32 err = 0; struct spkm3_ctx *sctx = ctx->internal_ctx_id; - dprintk("RPC: gss_get_mic_spkm3\n"); - err = spkm3_make_token(sctx, message_buffer, - message_token, SPKM_MIC_TOK); + message_token, SPKM_MIC_TOK); + dprintk("RPC: gss_get_mic_spkm3 returning %d\n", err); return err; } diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c index 18c7862bc234..b179d58c6249 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_seal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c @@ -39,11 +39,17 @@ #include #include #include +#include +#include +#include #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH #endif +const struct xdr_netobj hmac_md5_oid = { 8, "\x2B\x06\x01\x05\x05\x08\x01\x01"}; +const struct xdr_netobj cast5_cbc_oid = {9, "\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0A"}; + /* * spkm3_make_token() * @@ -66,29 +72,23 @@ spkm3_make_token(struct spkm3_ctx *ctx, int ctxelen = 0, ctxzbit = 0; int md5elen = 0, md5zbit = 0; - dprintk("RPC: spkm3_make_token\n"); - now = jiffies; if (ctx->ctx_id.len != 16) { dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n", - ctx->ctx_id.len); + ctx->ctx_id.len); goto out_err; } - - switch (ctx->intg_alg) { - case NID_md5: - checksum_type = CKSUMTYPE_RSA_MD5; - break; - default: - dprintk("RPC: gss_spkm3_seal: ctx->signalg %d not" - " supported\n", ctx->intg_alg); - goto out_err; - } - /* XXX since we don't support WRAP, perhaps we don't care... */ - if (ctx->conf_alg != NID_cast5_cbc) { - dprintk("RPC: gss_spkm3_seal: ctx->sealalg %d not supported\n", - ctx->conf_alg); + + if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) { + dprintk("RPC: gss_spkm3_seal: unsupported I-ALG algorithm." + "only support hmac-md5 I-ALG.\n"); + goto out_err; + } else + checksum_type = CKSUMTYPE_HMAC_MD5; + + if (!g_OID_equal(&ctx->conf_alg, &cast5_cbc_oid)) { + dprintk("RPC: gss_spkm3_seal: unsupported C-ALG algorithm\n"); goto out_err; } @@ -96,10 +96,10 @@ spkm3_make_token(struct spkm3_ctx *ctx, /* Calculate checksum over the mic-header */ asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit); spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data, - ctxelen, ctxzbit); - - if (make_checksum(checksum_type, mic_hdr.data, mic_hdr.len, - text, 0, &md5cksum)) + ctxelen, ctxzbit); + if (make_spkm3_checksum(checksum_type, &ctx->derived_integ_key, + (char *)mic_hdr.data, mic_hdr.len, + text, 0, &md5cksum)) goto out_err; asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit); @@ -121,7 +121,66 @@ spkm3_make_token(struct spkm3_ctx *ctx, return GSS_S_COMPLETE; out_err: + if (md5cksum.data) + kfree(md5cksum.data); + token->data = NULL; token->len = 0; return GSS_S_FAILURE; } + +static int +spkm3_checksummer(struct scatterlist *sg, void *data) +{ + struct hash_desc *desc = data; + + return crypto_hash_update(desc, sg, sg->length); +} + +/* checksum the plaintext data and hdrlen bytes of the token header */ +s32 +make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header, + unsigned int hdrlen, struct xdr_buf *body, + unsigned int body_offset, struct xdr_netobj *cksum) +{ + char *cksumname; + struct hash_desc desc; /* XXX add to ctx? */ + struct scatterlist sg[1]; + int err; + + switch (cksumtype) { + case CKSUMTYPE_HMAC_MD5: + cksumname = "md5"; + break; + default: + dprintk("RPC: spkm3_make_checksum:" + " unsupported checksum %d", cksumtype); + return GSS_S_FAILURE; + } + + if (key->data == NULL || key->len <= 0) return GSS_S_FAILURE; + + desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(desc.tfm)) + return GSS_S_FAILURE; + cksum->len = crypto_hash_digestsize(desc.tfm); + desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; + + err = crypto_hash_setkey(desc.tfm, key->data, key->len); + if (err) + goto out; + + sg_set_buf(sg, header, hdrlen); + crypto_hash_update(&desc, sg, 1); + + xdr_process_buf(body, body_offset, body->len - body_offset, + spkm3_checksummer, &desc); + crypto_hash_final(&desc, cksum->data); + +out: + crypto_free_hash(desc.tfm); + + return err ? GSS_S_FAILURE : 0; +} + +EXPORT_SYMBOL(make_spkm3_checksum); diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c index 854a983ccf26..35188b6ea8f7 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_token.c +++ b/net/sunrpc/auth_gss/gss_spkm3_token.c @@ -172,10 +172,10 @@ spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, unsigned char *ct *(u8 *)hptr++ = zbit; memcpy(hptr, ctxdata, elen); hptr += elen; - *hdrlen = hptr - top; + *hdrlen = hptr - top; } - -/* + +/* * spkm3_mic_innercontext_token() * * *tokp points to the beginning of the SPKM_MIC token described diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c index 544eb6fd9094..e54581ca7570 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_unseal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_unseal.c @@ -54,66 +54,70 @@ spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_buf *message_buffer, /* signbuf */ int toktype) { + s32 checksum_type; s32 code; struct xdr_netobj wire_cksum = {.len =0, .data = NULL}; char cksumdata[16]; struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; unsigned char *ptr = (unsigned char *)read_token->data; - unsigned char *cksum; + unsigned char *cksum; int bodysize, md5elen; int mic_hdrlen; u32 ret = GSS_S_DEFECTIVE_TOKEN; - dprintk("RPC: spkm3_read_token read_token->len %d\n", read_token->len); - if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used, &bodysize, &ptr, read_token->len)) goto out; /* decode the token */ - if (toktype == SPKM_MIC_TOK) { - - if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum))) - goto out; - - if (*cksum++ != 0x03) { - dprintk("RPC: spkm3_read_token BAD checksum type\n"); - goto out; - } - md5elen = *cksum++; - cksum++; /* move past the zbit */ - - if(!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16)) - goto out; - - /* HARD CODED FOR MD5 */ - - /* compute the checksum of the message. - * ptr + 2 = start of header piece of checksum - * mic_hdrlen + 2 = length of header piece of checksum - */ - ret = GSS_S_DEFECTIVE_TOKEN; - code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2, - mic_hdrlen + 2, - message_buffer, 0, &md5cksum); - - if (code) - goto out; - - dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n", - wire_cksum.len); - - ret = GSS_S_BAD_SIG; - code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len); - if (code) - goto out; - - } else { - dprintk("RPC: BAD or UNSUPPORTED SPKM3 token type: %d\n",toktype); + if (toktype != SPKM_MIC_TOK) { + dprintk("RPC: BAD SPKM3 token type: %d\n", toktype); + goto out; + } + + if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum))) + goto out; + + if (*cksum++ != 0x03) { + dprintk("RPC: spkm3_read_token BAD checksum type\n"); + goto out; + } + md5elen = *cksum++; + cksum++; /* move past the zbit */ + + if (!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16)) + goto out; + + /* HARD CODED FOR MD5 */ + + /* compute the checksum of the message. + * ptr + 2 = start of header piece of checksum + * mic_hdrlen + 2 = length of header piece of checksum + */ + ret = GSS_S_DEFECTIVE_TOKEN; + if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) { + dprintk("RPC: gss_spkm3_seal: unsupported I-ALG algorithm\n"); + goto out; + } + + checksum_type = CKSUMTYPE_HMAC_MD5; + + code = make_spkm3_checksum(checksum_type, + &ctx->derived_integ_key, ptr + 2, mic_hdrlen + 2, + message_buffer, 0, &md5cksum); + + if (code) + goto out; + + ret = GSS_S_BAD_SIG; + code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len); + if (code) { + dprintk("RPC: bad MIC checksum\n"); goto out; } + /* XXX: need to add expiration and sequencing */ ret = GSS_S_COMPLETE; out: -- cgit v1.2.3 From e678e06bf8fa25981a6fa1f08b979fd086d713f8 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 4 Dec 2006 20:22:35 -0500 Subject: gss: krb5: remove signalg and sealalg We designed the krb5 context import without completely understanding the context. Now it's clear that there are a number of fields that we ignore, or that we depend on having one single value. In particular, we only support one value of signalg currently; so let's check the signalg field in the downcall (in case we decide there's something else we could support here eventually), but ignore it otherwise. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_krb5.h | 1 - net/sunrpc/auth_gss/gss_krb5_mech.c | 5 ++++- net/sunrpc/auth_gss/gss_krb5_seal.c | 34 ++++++++++------------------------ net/sunrpc/auth_gss/gss_krb5_wrap.c | 30 ++++++++---------------------- 4 files changed, 22 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index e30ba201910a..f680ed3b1b5e 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -44,7 +44,6 @@ struct krb5_ctx { int initiate; /* 1 = initiating, 0 = accepting */ int seed_init; unsigned char seed[16]; - int signalg; int sealalg; struct crypto_blkcipher *enc; struct crypto_blkcipher *seq; diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 754b8cd6439f..17587163fcae 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -129,6 +129,7 @@ gss_import_sec_context_kerberos(const void *p, { const void *end = (const void *)((const char *)p + len); struct krb5_ctx *ctx; + int tmp; if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL))) goto out_err; @@ -142,9 +143,11 @@ gss_import_sec_context_kerberos(const void *p, p = simple_get_bytes(p, end, ctx->seed, sizeof(ctx->seed)); if (IS_ERR(p)) goto out_err_free_ctx; - p = simple_get_bytes(p, end, &ctx->signalg, sizeof(ctx->signalg)); + p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); if (IS_ERR(p)) goto out_err_free_ctx; + if (tmp != SGN_ALG_DES_MAC_MD5) + goto out_err_free_ctx; p = simple_get_bytes(p, end, &ctx->sealalg, sizeof(ctx->sealalg)); if (IS_ERR(p)) goto out_err_free_ctx; diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index dc58af0b8b4c..a496af585a08 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -88,15 +88,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, now = get_seconds(); - switch (ctx->signalg) { - case SGN_ALG_DES_MAC_MD5: - checksum_type = CKSUMTYPE_RSA_MD5; - break; - default: - dprintk("RPC: gss_krb5_seal: ctx->signalg %d not" - " supported\n", ctx->signalg); - goto out_err; - } + checksum_type = CKSUMTYPE_RSA_MD5; if (ctx->sealalg != SEAL_ALG_NONE && ctx->sealalg != SEAL_ALG_DES) { dprintk("RPC: gss_krb5_seal: ctx->sealalg %d not supported\n", ctx->sealalg); @@ -115,24 +107,18 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, krb5_hdr = ptr - 2; msg_start = krb5_hdr + 24; - *(__be16 *)(krb5_hdr + 2) = htons(ctx->signalg); + *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5); memset(krb5_hdr + 4, 0xff, 4); if (make_checksum(checksum_type, krb5_hdr, 8, text, 0, &md5cksum)) - goto out_err; - - switch (ctx->signalg) { - case SGN_ALG_DES_MAC_MD5: - if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, - md5cksum.data, md5cksum.len)) - goto out_err; - memcpy(krb5_hdr + 16, - md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, - KRB5_CKSUM_LENGTH); - break; - default: - BUG(); - } + goto out_err; + + if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, + md5cksum.data, md5cksum.len)) + goto out_err; + memcpy(krb5_hdr + 16, + md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, + KRB5_CKSUM_LENGTH); spin_lock(&krb5_seq_lock); seq_send = ctx->seq_send++; diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index ad243872f547..eee49f4c4c6a 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -134,15 +134,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, now = get_seconds(); - switch (kctx->signalg) { - case SGN_ALG_DES_MAC_MD5: - checksum_type = CKSUMTYPE_RSA_MD5; - break; - default: - dprintk("RPC: gss_krb5_seal: kctx->signalg %d not" - " supported\n", kctx->signalg); - goto out_err; - } + checksum_type = CKSUMTYPE_RSA_MD5; if (kctx->sealalg != SEAL_ALG_NONE && kctx->sealalg != SEAL_ALG_DES) { dprintk("RPC: gss_krb5_seal: kctx->sealalg %d not supported\n", kctx->sealalg); @@ -177,7 +169,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, msg_start = krb5_hdr + 24; /* XXXJBF: */ BUG_ON(buf->head[0].iov_base + offset + headlen != msg_start + blocksize); - *(__be16 *)(krb5_hdr + 2) = htons(kctx->signalg); + *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5); memset(krb5_hdr + 4, 0xff, 4); *(__be16 *)(krb5_hdr + 4) = htons(kctx->sealalg); @@ -191,18 +183,12 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, goto out_err; buf->pages = tmp_pages; - switch (kctx->signalg) { - case SGN_ALG_DES_MAC_MD5: - if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, - md5cksum.data, md5cksum.len)) - goto out_err; - memcpy(krb5_hdr + 16, - md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, - KRB5_CKSUM_LENGTH); - break; - default: - BUG(); - } + if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, + md5cksum.data, md5cksum.len)) + goto out_err; + memcpy(krb5_hdr + 16, + md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, + KRB5_CKSUM_LENGTH); spin_lock(&krb5_seq_lock); seq_send = kctx->seq_send++; -- cgit v1.2.3 From ca54f896454852f0bc8d50e6e4c55d9defedbd0a Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 4 Dec 2006 20:22:38 -0500 Subject: rpcgss: simplify make_checksum We're doing some pointless translation between krb5 constants and kernel crypto string names. Also clean up some related spkm3 code as necessary. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_krb5.h | 2 +- net/sunrpc/auth_gss/gss_krb5_crypto.c | 12 +----------- net/sunrpc/auth_gss/gss_krb5_seal.c | 2 +- net/sunrpc/auth_gss/gss_krb5_unseal.c | 3 +-- net/sunrpc/auth_gss/gss_krb5_wrap.c | 4 ++-- 5 files changed, 6 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index f680ed3b1b5e..abfa1f32d914 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -116,7 +116,7 @@ enum seal_alg { #define ENCTYPE_UNKNOWN 0x01ff s32 -make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, +make_checksum(char *, char *header, int hdrlen, struct xdr_buf *body, int body_offset, struct xdr_netobj *cksum); u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *, diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 10d05ea37213..d926cda88623 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -130,23 +130,13 @@ checksummer(struct scatterlist *sg, void *data) /* checksum the plaintext data and hdrlen bytes of the token header */ s32 -make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, +make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body, int body_offset, struct xdr_netobj *cksum) { - char *cksumname; struct hash_desc desc; /* XXX add to ctx? */ struct scatterlist sg[1]; int err; - switch (cksumtype) { - case CKSUMTYPE_RSA_MD5: - cksumname = "md5"; - break; - default: - dprintk("RPC: krb5_make_checksum:" - " unsupported checksum %d", cksumtype); - return GSS_S_FAILURE; - } desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(desc.tfm)) return GSS_S_FAILURE; diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 2bc22776be55..c187f7f1520f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -108,7 +108,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5); memset(krb5_hdr + 4, 0xff, 4); - if (make_checksum(CKSUMTYPE_RSA_MD5, krb5_hdr, 8, text, 0, &md5cksum)) + if (make_checksum("md5", krb5_hdr, 8, text, 0, &md5cksum)) goto out_err; if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index 60469d9ab226..62807ac1e2ca 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c @@ -114,8 +114,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, if (signalg != SGN_ALG_DES_MAC_MD5) goto out; - ret = make_checksum(CKSUMTYPE_RSA_MD5, ptr - 2, 8, - message_buffer, 0, &md5cksum); + ret = make_checksum("md5", ptr - 2, 8, message_buffer, 0, &md5cksum); if (ret) goto out; diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 206937187274..6d508d77adf9 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -176,7 +176,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, /* XXXJBF: UGH!: */ tmp_pages = buf->pages; buf->pages = pages; - if (make_checksum(CKSUMTYPE_RSA_MD5, krb5_hdr, 8, buf, + if (make_checksum("md5", krb5_hdr, 8, buf, offset + headlen - blocksize, &md5cksum)) goto out_err; buf->pages = tmp_pages; @@ -272,7 +272,7 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) ptr + 22 - (unsigned char *)buf->head[0].iov_base)) goto out; - ret = make_checksum(CKSUMTYPE_RSA_MD5, ptr - 2, 8, buf, + ret = make_checksum("md5", ptr - 2, 8, buf, ptr + 22 - (unsigned char *)buf->head[0].iov_base, &md5cksum); if (ret) goto out; -- cgit v1.2.3 From d922a84a8bf1d627810906d033223d4fa629fdbf Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 4 Dec 2006 20:22:40 -0500 Subject: rpcgss: krb5: sanity check sealalg value in the downcall The sealalg is checked in several places, giving the impression it could be either SEAL_ALG_NONE or SEAL_ALG_DES. But in fact SEAL_ALG_NONE seems to be sufficient only for making mic's, and all the contexts we get must be capable of wrapping as well. So the sealalg must be SEAL_ALG_DES. As with signalg, just check for the right value on the downcall and ignore it otherwise. Similarly, tighten expectations for the sealalg on incoming tokens, in case we do support other values eventually. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_krb5.h | 1 - net/sunrpc/auth_gss/gss_krb5_mech.c | 4 +++- net/sunrpc/auth_gss/gss_krb5_seal.c | 6 ------ net/sunrpc/auth_gss/gss_krb5_wrap.c | 25 ++----------------------- 4 files changed, 5 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index abfa1f32d914..01c5e4314632 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -44,7 +44,6 @@ struct krb5_ctx { int initiate; /* 1 = initiating, 0 = accepting */ int seed_init; unsigned char seed[16]; - int sealalg; struct crypto_blkcipher *enc; struct crypto_blkcipher *seq; s32 endtime; diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 17587163fcae..bf5435db8785 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -148,9 +148,11 @@ gss_import_sec_context_kerberos(const void *p, goto out_err_free_ctx; if (tmp != SGN_ALG_DES_MAC_MD5) goto out_err_free_ctx; - p = simple_get_bytes(p, end, &ctx->sealalg, sizeof(ctx->sealalg)); + p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); if (IS_ERR(p)) goto out_err_free_ctx; + if (tmp != SEAL_ALG_DES) + goto out_err_free_ctx; p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); if (IS_ERR(p)) goto out_err_free_ctx; diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index f3f42a4465cf..f42e453e63ea 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -87,12 +87,6 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, now = get_seconds(); - if (ctx->sealalg != SEAL_ALG_NONE && ctx->sealalg != SEAL_ALG_DES) { - dprintk("RPC: gss_krb5_seal: ctx->sealalg %d not supported\n", - ctx->sealalg); - return GSS_S_FAILURE; - } - token->len = g_token_size(&ctx->mech_used, 22); ptr = token->data; diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 63b06ee2d542..bf25f4d9acd1 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -133,12 +133,6 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, now = get_seconds(); - if (kctx->sealalg != SEAL_ALG_NONE && kctx->sealalg != SEAL_ALG_DES) { - dprintk("RPC: gss_krb5_seal: kctx->sealalg %d not supported\n", - kctx->sealalg); - return GSS_S_FAILURE; - } - blocksize = crypto_blkcipher_blocksize(kctx->enc); gss_krb5_add_padding(buf, offset, blocksize); BUG_ON((buf->len - offset) % blocksize); @@ -169,7 +163,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5); memset(krb5_hdr + 4, 0xff, 4); - *(__be16 *)(krb5_hdr + 4) = htons(kctx->sealalg); + *(__be16 *)(krb5_hdr + 4) = htons(SEAL_ALG_DES); make_confounder(msg_start, blocksize); @@ -245,26 +239,11 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) return GSS_S_DEFECTIVE_TOKEN; - if (sealalg == 0xffff) + if (sealalg != SEAL_ALG_DES) return GSS_S_DEFECTIVE_TOKEN; if (signalg != SGN_ALG_DES_MAC_MD5) return GSS_S_DEFECTIVE_TOKEN; - /* in the current spec, there is only one valid seal algorithm per - key type, so a simple comparison is ok */ - - if (sealalg != kctx->sealalg) - return GSS_S_DEFECTIVE_TOKEN; - - /* there are several mappings of seal algorithms to sign algorithms, - but few enough that we can try them all. */ - - if ((kctx->sealalg == SEAL_ALG_NONE && signalg > 1) || - (kctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) || - (kctx->sealalg == SEAL_ALG_DES3KD && - signalg != SGN_ALG_HMAC_SHA1_DES3_KD)) - return GSS_S_DEFECTIVE_TOKEN; - if (gss_decrypt_xdr_buf(kctx->enc, buf, ptr + 22 - (unsigned char *)buf->head[0].iov_base)) return GSS_S_DEFECTIVE_TOKEN; -- cgit v1.2.3 From 717757ad1038ab6aacb89bad579c89b006efd913 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 4 Dec 2006 20:22:41 -0500 Subject: rpcgss: krb5: ignore seed We're currently not actually using seed or seed_init. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_krb5.h | 2 -- net/sunrpc/auth_gss/gss_krb5_mech.c | 11 ++++++----- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index 01c5e4314632..5a4b1e0206e3 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -42,8 +42,6 @@ struct krb5_ctx { int initiate; /* 1 = initiating, 0 = accepting */ - int seed_init; - unsigned char seed[16]; struct crypto_blkcipher *enc; struct crypto_blkcipher *seq; s32 endtime; diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index bf5435db8785..05d4bee86fc0 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -137,12 +137,13 @@ gss_import_sec_context_kerberos(const void *p, p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); if (IS_ERR(p)) goto out_err_free_ctx; - p = simple_get_bytes(p, end, &ctx->seed_init, sizeof(ctx->seed_init)); - if (IS_ERR(p)) - goto out_err_free_ctx; - p = simple_get_bytes(p, end, ctx->seed, sizeof(ctx->seed)); - if (IS_ERR(p)) + /* The downcall format was designed before we completely understood + * the uses of the context fields; so it includes some stuff we + * just give some minimal sanity-checking, and some we ignore + * completely (like the next twenty bytes): */ + if (unlikely(p + 20 > end || p + 20 < p)) goto out_err_free_ctx; + p += 20; p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); if (IS_ERR(p)) goto out_err_free_ctx; -- cgit v1.2.3 From ee0ac0c227c2a2b6dd1b33c23831100ee895dacf Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 5 Dec 2006 16:35:15 -0500 Subject: SUNRPC: Remove sock and inet fields from rpc_xprt The "sock" and "inet" fields are socket-specific. Move them to a private data structure maintained entirely within net/sunrpc/xprtsock.c Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 4 +-- net/sunrpc/xprtsock.c | 62 ++++++++++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index d7919010863d..4c074a73670c 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -17,6 +17,8 @@ #include #include +#include + extern unsigned int xprt_udp_slot_table_entries; extern unsigned int xprt_tcp_slot_table_entries; @@ -126,8 +128,6 @@ struct rpc_xprt_ops { struct rpc_xprt { struct kref kref; /* Reference count */ struct rpc_xprt_ops * ops; /* transport methods */ - struct socket * sock; /* BSD socket layer */ - struct sock * inet; /* INET layer */ struct rpc_timeout timeout; /* timeout parms */ struct sockaddr_storage addr; /* server address */ diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index dc4a21f1a129..0f455fd1820c 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -127,6 +127,12 @@ static inline void xs_pktdump(char *msg, u32 *packet, unsigned int count) struct sock_xprt { struct rpc_xprt xprt; + + /* + * Network layer + */ + struct socket * sock; + struct sock * inet; }; static void xs_format_peer_addresses(struct rpc_xprt *xprt) @@ -285,19 +291,20 @@ static void xs_nospace(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); dprintk("RPC: %4d xmit incomplete (%u left of %u)\n", task->tk_pid, req->rq_slen - req->rq_bytes_sent, req->rq_slen); - if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { + if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) { /* Protect against races with write_space */ spin_lock_bh(&xprt->transport_lock); /* Don't race with disconnect */ if (!xprt_connected(xprt)) task->tk_status = -ENOTCONN; - else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) + else if (test_bit(SOCK_NOSPACE, &transport->sock->flags)) xprt_wait_for_buffer_space(task); spin_unlock_bh(&xprt->transport_lock); @@ -321,6 +328,7 @@ static int xs_udp_send_request(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct xdr_buf *xdr = &req->rq_snd_buf; int status; @@ -329,8 +337,10 @@ static int xs_udp_send_request(struct rpc_task *task) req->rq_svec->iov_len); req->rq_xtime = jiffies; - status = xs_sendpages(xprt->sock, (struct sockaddr *) &xprt->addr, - xprt->addrlen, xdr, req->rq_bytes_sent); + status = xs_sendpages(transport->sock, + (struct sockaddr *) &xprt->addr, + xprt->addrlen, xdr, + req->rq_bytes_sent); dprintk("RPC: xs_udp_send_request(%u) = %d\n", xdr->len - req->rq_bytes_sent, status); @@ -386,6 +396,7 @@ static int xs_tcp_send_request(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct xdr_buf *xdr = &req->rq_snd_buf; int status, retry = 0; @@ -400,8 +411,8 @@ static int xs_tcp_send_request(struct rpc_task *task) * called sendmsg(). */ while (1) { req->rq_xtime = jiffies; - status = xs_sendpages(xprt->sock, NULL, 0, xdr, - req->rq_bytes_sent); + status = xs_sendpages(transport->sock, + NULL, 0, xdr, req->rq_bytes_sent); dprintk("RPC: xs_tcp_send_request(%u) = %d\n", xdr->len - req->rq_bytes_sent, status); @@ -479,8 +490,9 @@ out_release: */ static void xs_close(struct rpc_xprt *xprt) { - struct socket *sock = xprt->sock; - struct sock *sk = xprt->inet; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + struct socket *sock = transport->sock; + struct sock *sk = transport->inet; if (!sk) goto clear_close_wait; @@ -488,8 +500,8 @@ static void xs_close(struct rpc_xprt *xprt) dprintk("RPC: xs_close xprt %p\n", xprt); write_lock_bh(&sk->sk_callback_lock); - xprt->inet = NULL; - xprt->sock = NULL; + transport->inet = NULL; + transport->sock = NULL; sk->sk_user_data = NULL; sk->sk_data_ready = xprt->old_data_ready; @@ -946,7 +958,8 @@ static void xs_tcp_write_space(struct sock *sk) static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt) { - struct sock *sk = xprt->inet; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + struct sock *sk = transport->inet; if (xprt->rcvsize) { sk->sk_userlocks |= SOCK_RCVBUF_LOCK; @@ -1062,7 +1075,8 @@ static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) static void xs_udp_connect_worker(void *args) { struct rpc_xprt *xprt = (struct rpc_xprt *) args; - struct socket *sock = xprt->sock; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + struct socket *sock = transport->sock; int err, status = -EIO; if (xprt->shutdown || !xprt_bound(xprt)) @@ -1084,7 +1098,7 @@ static void xs_udp_connect_worker(void *args) dprintk("RPC: worker connecting xprt %p to address: %s\n", xprt, xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); - if (!xprt->inet) { + if (!transport->inet) { struct sock *sk = sock->sk; write_lock_bh(&sk->sk_callback_lock); @@ -1101,8 +1115,8 @@ static void xs_udp_connect_worker(void *args) xprt_set_connected(xprt); /* Reset to new socket */ - xprt->sock = sock; - xprt->inet = sk; + transport->sock = sock; + transport->inet = sk; write_unlock_bh(&sk->sk_callback_lock); } @@ -1120,7 +1134,7 @@ out: static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) { int result; - struct socket *sock = xprt->sock; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct sockaddr any; dprintk("RPC: disconnecting xprt %p to reuse port\n", xprt); @@ -1131,7 +1145,7 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) */ memset(&any, 0, sizeof(any)); any.sa_family = AF_UNSPEC; - result = kernel_connect(sock, &any, sizeof(any), 0); + result = kernel_connect(transport->sock, &any, sizeof(any), 0); if (result) dprintk("RPC: AF_UNSPEC connect return code %d\n", result); @@ -1146,13 +1160,14 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) static void xs_tcp_connect_worker(void *args) { struct rpc_xprt *xprt = (struct rpc_xprt *)args; - struct socket *sock = xprt->sock; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + struct socket *sock = transport->sock; int err, status = -EIO; if (xprt->shutdown || !xprt_bound(xprt)) goto out; - if (!xprt->sock) { + if (!sock) { /* start from scratch */ if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { dprintk("RPC: can't create TCP transport socket (%d).\n", -err); @@ -1170,7 +1185,7 @@ static void xs_tcp_connect_worker(void *args) dprintk("RPC: worker connecting xprt %p to address: %s\n", xprt, xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); - if (!xprt->inet) { + if (!transport->inet) { struct sock *sk = sock->sk; write_lock_bh(&sk->sk_callback_lock); @@ -1193,8 +1208,8 @@ static void xs_tcp_connect_worker(void *args) xprt_clear_connected(xprt); /* Reset to new socket */ - xprt->sock = sock; - xprt->inet = sk; + transport->sock = sock; + transport->inet = sk; write_unlock_bh(&sk->sk_callback_lock); } @@ -1243,11 +1258,12 @@ out_clear: static void xs_connect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); if (xprt_test_and_set_connecting(xprt)) return; - if (xprt->sock != NULL) { + if (transport->sock != NULL) { dprintk("RPC: xs_connect delayed xprt %p for %lu seconds\n", xprt, xprt->reestablish_timeout / HZ); schedule_delayed_work(&xprt->connect_worker, -- cgit v1.2.3 From 51971139b2342fa1005e87bbfcb52305da3fe891 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 5 Dec 2006 16:35:19 -0500 Subject: SUNRPC: Move TCP receive state variables into private data structure Move the TCP receive state variables from the generic rpc_xprt structure to a private structure maintained inside net/sunrpc/xprtsock.c. Also rename a function/variable pair to refer to RPC fragment headers instead of record markers, to be consistent with types defined in sunrpc/*.h. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 9 --- net/sunrpc/xprtsock.c | 154 +++++++++++++++++++++++++------------------- 2 files changed, 86 insertions(+), 77 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 4c074a73670c..0a0ad1ce70e4 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -157,15 +157,6 @@ struct rpc_xprt { unsigned char shutdown : 1, /* being shut down */ resvport : 1; /* use a reserved port */ - /* - * State of TCP reply receive stuff - */ - __be32 tcp_recm, /* Fragment header */ - tcp_xid; /* Current XID */ - u32 tcp_reclen, /* fragment length */ - tcp_offset; /* fragment offset */ - unsigned long tcp_copied, /* copied to request */ - tcp_flags; /* * Connection of transports */ diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 0f455fd1820c..417bd91ea53e 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -133,6 +133,18 @@ struct sock_xprt { */ struct socket * sock; struct sock * inet; + + /* + * State of TCP reply receive + */ + __be32 tcp_fraghdr, + tcp_xid; + + u32 tcp_offset, + tcp_reclen; + + unsigned long tcp_copied, + tcp_flags; }; static void xs_format_peer_addresses(struct rpc_xprt *xprt) @@ -628,73 +640,73 @@ static inline size_t xs_tcp_copy_data(skb_reader_t *desc, void *p, size_t len) static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) { + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); size_t len, used; char *p; - p = ((char *) &xprt->tcp_recm) + xprt->tcp_offset; - len = sizeof(xprt->tcp_recm) - xprt->tcp_offset; + p = ((char *) &transport->tcp_fraghdr) + transport->tcp_offset; + len = sizeof(transport->tcp_fraghdr) - transport->tcp_offset; used = xs_tcp_copy_data(desc, p, len); - xprt->tcp_offset += used; + transport->tcp_offset += used; if (used != len) return; - xprt->tcp_reclen = ntohl(xprt->tcp_recm); - if (xprt->tcp_reclen & RPC_LAST_STREAM_FRAGMENT) - xprt->tcp_flags |= XPRT_LAST_FRAG; + transport->tcp_reclen = ntohl(transport->tcp_fraghdr); + if (transport->tcp_reclen & RPC_LAST_STREAM_FRAGMENT) + transport->tcp_flags |= XPRT_LAST_FRAG; else - xprt->tcp_flags &= ~XPRT_LAST_FRAG; - xprt->tcp_reclen &= RPC_FRAGMENT_SIZE_MASK; + transport->tcp_flags &= ~XPRT_LAST_FRAG; + transport->tcp_reclen &= RPC_FRAGMENT_SIZE_MASK; - xprt->tcp_flags &= ~XPRT_COPY_RECM; - xprt->tcp_offset = 0; + transport->tcp_flags &= ~XPRT_COPY_RECM; + transport->tcp_offset = 0; /* Sanity check of the record length */ - if (unlikely(xprt->tcp_reclen < 4)) { + if (unlikely(transport->tcp_reclen < 4)) { dprintk("RPC: invalid TCP record fragment length\n"); xprt_disconnect(xprt); return; } dprintk("RPC: reading TCP record fragment of length %d\n", - xprt->tcp_reclen); + transport->tcp_reclen); } -static void xs_tcp_check_recm(struct rpc_xprt *xprt) +static void xs_tcp_check_fraghdr(struct sock_xprt *transport) { - dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u, tcp_flags = %lx\n", - xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_flags); - if (xprt->tcp_offset == xprt->tcp_reclen) { - xprt->tcp_flags |= XPRT_COPY_RECM; - xprt->tcp_offset = 0; - if (xprt->tcp_flags & XPRT_LAST_FRAG) { - xprt->tcp_flags &= ~XPRT_COPY_DATA; - xprt->tcp_flags |= XPRT_COPY_XID; - xprt->tcp_copied = 0; + if (transport->tcp_offset == transport->tcp_reclen) { + transport->tcp_flags |= XPRT_COPY_RECM; + transport->tcp_offset = 0; + if (transport->tcp_flags & XPRT_LAST_FRAG) { + transport->tcp_flags &= ~XPRT_COPY_DATA; + transport->tcp_flags |= XPRT_COPY_XID; + transport->tcp_copied = 0; } } } -static inline void xs_tcp_read_xid(struct rpc_xprt *xprt, skb_reader_t *desc) +static inline void xs_tcp_read_xid(struct sock_xprt *transport, skb_reader_t *desc) { size_t len, used; char *p; - len = sizeof(xprt->tcp_xid) - xprt->tcp_offset; + len = sizeof(transport->tcp_xid) - transport->tcp_offset; dprintk("RPC: reading XID (%Zu bytes)\n", len); - p = ((char *) &xprt->tcp_xid) + xprt->tcp_offset; + p = ((char *) &transport->tcp_xid) + transport->tcp_offset; used = xs_tcp_copy_data(desc, p, len); - xprt->tcp_offset += used; + transport->tcp_offset += used; if (used != len) return; - xprt->tcp_flags &= ~XPRT_COPY_XID; - xprt->tcp_flags |= XPRT_COPY_DATA; - xprt->tcp_copied = 4; + transport->tcp_flags &= ~XPRT_COPY_XID; + transport->tcp_flags |= XPRT_COPY_DATA; + transport->tcp_copied = 4; dprintk("RPC: reading reply for XID %08x\n", - ntohl(xprt->tcp_xid)); - xs_tcp_check_recm(xprt); + ntohl(transport->tcp_xid)); + xs_tcp_check_fraghdr(transport); } static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) { + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct rpc_rqst *req; struct xdr_buf *rcvbuf; size_t len; @@ -702,34 +714,34 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc /* Find and lock the request corresponding to this xid */ spin_lock(&xprt->transport_lock); - req = xprt_lookup_rqst(xprt, xprt->tcp_xid); + req = xprt_lookup_rqst(xprt, transport->tcp_xid); if (!req) { - xprt->tcp_flags &= ~XPRT_COPY_DATA; + transport->tcp_flags &= ~XPRT_COPY_DATA; dprintk("RPC: XID %08x request not found!\n", - ntohl(xprt->tcp_xid)); + ntohl(transport->tcp_xid)); spin_unlock(&xprt->transport_lock); return; } rcvbuf = &req->rq_private_buf; len = desc->count; - if (len > xprt->tcp_reclen - xprt->tcp_offset) { + if (len > transport->tcp_reclen - transport->tcp_offset) { skb_reader_t my_desc; - len = xprt->tcp_reclen - xprt->tcp_offset; + len = transport->tcp_reclen - transport->tcp_offset; memcpy(&my_desc, desc, sizeof(my_desc)); my_desc.count = len; - r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, + r = xdr_partial_copy_from_skb(rcvbuf, transport->tcp_copied, &my_desc, xs_tcp_copy_data); desc->count -= r; desc->offset += r; } else - r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, + r = xdr_partial_copy_from_skb(rcvbuf, transport->tcp_copied, desc, xs_tcp_copy_data); if (r > 0) { - xprt->tcp_copied += r; - xprt->tcp_offset += r; + transport->tcp_copied += r; + transport->tcp_offset += r; } if (r != len) { /* Error when copying to the receive buffer, @@ -741,77 +753,79 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc * Any remaining data from this record will * be discarded. */ - xprt->tcp_flags &= ~XPRT_COPY_DATA; + transport->tcp_flags &= ~XPRT_COPY_DATA; dprintk("RPC: XID %08x truncated request\n", - ntohl(xprt->tcp_xid)); + ntohl(transport->tcp_xid)); dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", - xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); + xprt, transport->tcp_copied, transport->tcp_offset, + transport->tcp_reclen); goto out; } dprintk("RPC: XID %08x read %Zd bytes\n", - ntohl(xprt->tcp_xid), r); + ntohl(transport->tcp_xid), r); dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", - xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); - - if (xprt->tcp_copied == req->rq_private_buf.buflen) - xprt->tcp_flags &= ~XPRT_COPY_DATA; - else if (xprt->tcp_offset == xprt->tcp_reclen) { - if (xprt->tcp_flags & XPRT_LAST_FRAG) - xprt->tcp_flags &= ~XPRT_COPY_DATA; + xprt, transport->tcp_copied, transport->tcp_offset, + transport->tcp_reclen); + + if (transport->tcp_copied == req->rq_private_buf.buflen) + transport->tcp_flags &= ~XPRT_COPY_DATA; + else if (transport->tcp_offset == transport->tcp_reclen) { + if (transport->tcp_flags & XPRT_LAST_FRAG) + transport->tcp_flags &= ~XPRT_COPY_DATA; } out: - if (!(xprt->tcp_flags & XPRT_COPY_DATA)) - xprt_complete_rqst(req->rq_task, xprt->tcp_copied); + if (!(transport->tcp_flags & XPRT_COPY_DATA)) + xprt_complete_rqst(req->rq_task, transport->tcp_copied); spin_unlock(&xprt->transport_lock); - xs_tcp_check_recm(xprt); + xs_tcp_check_fraghdr(transport); } -static inline void xs_tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) +static inline void xs_tcp_read_discard(struct sock_xprt *transport, skb_reader_t *desc) { size_t len; - len = xprt->tcp_reclen - xprt->tcp_offset; + len = transport->tcp_reclen - transport->tcp_offset; if (len > desc->count) len = desc->count; desc->count -= len; desc->offset += len; - xprt->tcp_offset += len; + transport->tcp_offset += len; dprintk("RPC: discarded %Zu bytes\n", len); - xs_tcp_check_recm(xprt); + xs_tcp_check_fraghdr(transport); } static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, unsigned int offset, size_t len) { struct rpc_xprt *xprt = rd_desc->arg.data; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); skb_reader_t desc = { .skb = skb, .offset = offset, .count = len, - .csum = 0 }; dprintk("RPC: xs_tcp_data_recv started\n"); do { /* Read in a new fragment marker if necessary */ /* Can we ever really expect to get completely empty fragments? */ - if (xprt->tcp_flags & XPRT_COPY_RECM) { + if (transport->tcp_flags & XPRT_COPY_RECM) { xs_tcp_read_fraghdr(xprt, &desc); continue; } /* Read in the xid if necessary */ - if (xprt->tcp_flags & XPRT_COPY_XID) { - xs_tcp_read_xid(xprt, &desc); + if (transport->tcp_flags & XPRT_COPY_XID) { + xs_tcp_read_xid(transport, &desc); continue; } /* Read in the request data */ - if (xprt->tcp_flags & XPRT_COPY_DATA) { + if (transport->tcp_flags & XPRT_COPY_DATA) { xs_tcp_read_request(xprt, &desc); continue; } /* Skip over any trailing bytes on short reads */ - xs_tcp_read_discard(xprt, &desc); + xs_tcp_read_discard(transport, &desc); } while (desc.count); dprintk("RPC: xs_tcp_data_recv done\n"); return len - desc.count; @@ -865,11 +879,15 @@ static void xs_tcp_state_change(struct sock *sk) case TCP_ESTABLISHED: spin_lock_bh(&xprt->transport_lock); if (!xprt_test_and_set_connected(xprt)) { + struct sock_xprt *transport = container_of(xprt, + struct sock_xprt, xprt); + /* Reset TCP record info */ - xprt->tcp_offset = 0; - xprt->tcp_reclen = 0; - xprt->tcp_copied = 0; - xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; + transport->tcp_offset = 0; + transport->tcp_reclen = 0; + transport->tcp_copied = 0; + transport->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; + xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; xprt_wake_pending_tasks(xprt, 0); } -- cgit v1.2.3 From e136d0926ef6a048f6e65b35263c0a9faae3abbe Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 5 Dec 2006 16:35:23 -0500 Subject: SUNRPC: Move TCP state flags into xprtsock.c Move "XPRT_LAST_FRAG" and friends from xprt.h into xprtsock.c, and rename them to use the naming scheme in use in xprtsock.c. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 5 ----- net/sunrpc/xprtsock.c | 49 +++++++++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 0a0ad1ce70e4..3ff8230c7dd9 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -203,11 +203,6 @@ struct rpc_xprt { char * address_strings[RPC_DISPLAY_MAX]; }; -#define XPRT_LAST_FRAG (1 << 0) -#define XPRT_COPY_RECM (1 << 1) -#define XPRT_COPY_XID (1 << 2) -#define XPRT_COPY_DATA (1 << 3) - #ifdef __KERNEL__ /* diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 417bd91ea53e..c737acf61c75 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -147,6 +147,14 @@ struct sock_xprt { tcp_flags; }; +/* + * TCP receive state flags + */ +#define TCP_RCV_LAST_FRAG (1UL << 0) +#define TCP_RCV_COPY_FRAGHDR (1UL << 1) +#define TCP_RCV_COPY_XID (1UL << 2) +#define TCP_RCV_COPY_DATA (1UL << 3) + static void xs_format_peer_addresses(struct rpc_xprt *xprt) { struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr; @@ -653,12 +661,12 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc transport->tcp_reclen = ntohl(transport->tcp_fraghdr); if (transport->tcp_reclen & RPC_LAST_STREAM_FRAGMENT) - transport->tcp_flags |= XPRT_LAST_FRAG; + transport->tcp_flags |= TCP_RCV_LAST_FRAG; else - transport->tcp_flags &= ~XPRT_LAST_FRAG; + transport->tcp_flags &= ~TCP_RCV_LAST_FRAG; transport->tcp_reclen &= RPC_FRAGMENT_SIZE_MASK; - transport->tcp_flags &= ~XPRT_COPY_RECM; + transport->tcp_flags &= ~TCP_RCV_COPY_FRAGHDR; transport->tcp_offset = 0; /* Sanity check of the record length */ @@ -674,11 +682,11 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc static void xs_tcp_check_fraghdr(struct sock_xprt *transport) { if (transport->tcp_offset == transport->tcp_reclen) { - transport->tcp_flags |= XPRT_COPY_RECM; + transport->tcp_flags |= TCP_RCV_COPY_FRAGHDR; transport->tcp_offset = 0; - if (transport->tcp_flags & XPRT_LAST_FRAG) { - transport->tcp_flags &= ~XPRT_COPY_DATA; - transport->tcp_flags |= XPRT_COPY_XID; + if (transport->tcp_flags & TCP_RCV_LAST_FRAG) { + transport->tcp_flags &= ~TCP_RCV_COPY_DATA; + transport->tcp_flags |= TCP_RCV_COPY_XID; transport->tcp_copied = 0; } } @@ -696,8 +704,8 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, skb_reader_t *de transport->tcp_offset += used; if (used != len) return; - transport->tcp_flags &= ~XPRT_COPY_XID; - transport->tcp_flags |= XPRT_COPY_DATA; + transport->tcp_flags &= ~TCP_RCV_COPY_XID; + transport->tcp_flags |= TCP_RCV_COPY_DATA; transport->tcp_copied = 4; dprintk("RPC: reading reply for XID %08x\n", ntohl(transport->tcp_xid)); @@ -716,7 +724,7 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc spin_lock(&xprt->transport_lock); req = xprt_lookup_rqst(xprt, transport->tcp_xid); if (!req) { - transport->tcp_flags &= ~XPRT_COPY_DATA; + transport->tcp_flags &= ~TCP_RCV_COPY_DATA; dprintk("RPC: XID %08x request not found!\n", ntohl(transport->tcp_xid)); spin_unlock(&xprt->transport_lock); @@ -747,13 +755,13 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc /* Error when copying to the receive buffer, * usually because we weren't able to allocate * additional buffer pages. All we can do now - * is turn off XPRT_COPY_DATA, so the request + * is turn off TCP_RCV_COPY_DATA, so the request * will not receive any additional updates, * and time out. * Any remaining data from this record will * be discarded. */ - transport->tcp_flags &= ~XPRT_COPY_DATA; + transport->tcp_flags &= ~TCP_RCV_COPY_DATA; dprintk("RPC: XID %08x truncated request\n", ntohl(transport->tcp_xid)); dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", @@ -769,14 +777,14 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc transport->tcp_reclen); if (transport->tcp_copied == req->rq_private_buf.buflen) - transport->tcp_flags &= ~XPRT_COPY_DATA; + transport->tcp_flags &= ~TCP_RCV_COPY_DATA; else if (transport->tcp_offset == transport->tcp_reclen) { - if (transport->tcp_flags & XPRT_LAST_FRAG) - transport->tcp_flags &= ~XPRT_COPY_DATA; + if (transport->tcp_flags & TCP_RCV_LAST_FRAG) + transport->tcp_flags &= ~TCP_RCV_COPY_DATA; } out: - if (!(transport->tcp_flags & XPRT_COPY_DATA)) + if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) xprt_complete_rqst(req->rq_task, transport->tcp_copied); spin_unlock(&xprt->transport_lock); xs_tcp_check_fraghdr(transport); @@ -810,17 +818,17 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns do { /* Read in a new fragment marker if necessary */ /* Can we ever really expect to get completely empty fragments? */ - if (transport->tcp_flags & XPRT_COPY_RECM) { + if (transport->tcp_flags & TCP_RCV_COPY_FRAGHDR) { xs_tcp_read_fraghdr(xprt, &desc); continue; } /* Read in the xid if necessary */ - if (transport->tcp_flags & XPRT_COPY_XID) { + if (transport->tcp_flags & TCP_RCV_COPY_XID) { xs_tcp_read_xid(transport, &desc); continue; } /* Read in the request data */ - if (transport->tcp_flags & XPRT_COPY_DATA) { + if (transport->tcp_flags & TCP_RCV_COPY_DATA) { xs_tcp_read_request(xprt, &desc); continue; } @@ -886,7 +894,8 @@ static void xs_tcp_state_change(struct sock *sk) transport->tcp_offset = 0; transport->tcp_reclen = 0; transport->tcp_copied = 0; - transport->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; + transport->tcp_flags = + TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; xprt_wake_pending_tasks(xprt, 0); -- cgit v1.2.3 From c8475461829fd94f30208fbfa4eab7e5584c6495 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 5 Dec 2006 16:35:26 -0500 Subject: SUNRPC: Move rpc_xprt socket connect fields into private data structure Move the socket-specific connection management fields out of the generic rpc_xprt structure into a private data structure maintained in net/sunrpc/xprtsock.c. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 -- net/sunrpc/xprtsock.c | 51 +++++++++++++++++++++++++++++---------------- 2 files changed, 33 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 3ff8230c7dd9..18bf72c06488 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -163,8 +163,6 @@ struct rpc_xprt { unsigned long connect_timeout, bind_timeout, reestablish_timeout; - struct work_struct connect_worker; - unsigned short port; /* * Disconnection of idle transports diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index c737acf61c75..4797a4608c07 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -145,6 +145,12 @@ struct sock_xprt { unsigned long tcp_copied, tcp_flags; + + /* + * Connection of transports + */ + struct work_struct connect_worker; + unsigned short port; }; /* @@ -545,9 +551,11 @@ clear_close_wait: */ static void xs_destroy(struct rpc_xprt *xprt) { + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + dprintk("RPC: xs_destroy xprt %p\n", xprt); - cancel_delayed_work(&xprt->connect_worker); + cancel_delayed_work(&transport->connect_worker); flush_scheduled_work(); xprt_disconnect(xprt); @@ -1065,20 +1073,20 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) sap->sin_port = htons(port); } -static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) +static int xs_bindresvport(struct sock_xprt *transport, struct socket *sock) { struct sockaddr_in myaddr = { .sin_family = AF_INET, }; int err; - unsigned short port = xprt->port; + unsigned short port = transport->port; do { myaddr.sin_port = htons(port); err = kernel_bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)); if (err == 0) { - xprt->port = port; + transport->port = port; dprintk("RPC: xs_bindresvport bound to port %u\n", port); return 0; @@ -1087,7 +1095,7 @@ static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) port = xprt_max_resvport; else port--; - } while (err == -EADDRINUSE && port != xprt->port); + } while (err == -EADDRINUSE && port != transport->port); dprintk("RPC: can't bind to reserved port (%d).\n", -err); return err; @@ -1101,8 +1109,8 @@ static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) */ static void xs_udp_connect_worker(void *args) { - struct rpc_xprt *xprt = (struct rpc_xprt *) args; - struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + struct sock_xprt *transport = (struct sock_xprt *)args; + struct rpc_xprt *xprt = &transport->xprt; struct socket *sock = transport->sock; int err, status = -EIO; @@ -1117,7 +1125,7 @@ static void xs_udp_connect_worker(void *args) goto out; } - if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) { + if (xprt->resvport && xs_bindresvport(transport, sock) < 0) { sock_release(sock); goto out; } @@ -1186,8 +1194,8 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) */ static void xs_tcp_connect_worker(void *args) { - struct rpc_xprt *xprt = (struct rpc_xprt *)args; - struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + struct sock_xprt *transport = (struct sock_xprt *)args; + struct rpc_xprt *xprt = &transport->xprt; struct socket *sock = transport->sock; int err, status = -EIO; @@ -1201,7 +1209,7 @@ static void xs_tcp_connect_worker(void *args) goto out; } - if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) { + if (xprt->resvport && xs_bindresvport(transport, sock) < 0) { sock_release(sock); goto out; } @@ -1293,14 +1301,14 @@ static void xs_connect(struct rpc_task *task) if (transport->sock != NULL) { dprintk("RPC: xs_connect delayed xprt %p for %lu seconds\n", xprt, xprt->reestablish_timeout / HZ); - schedule_delayed_work(&xprt->connect_worker, + schedule_delayed_work(&transport->connect_worker, xprt->reestablish_timeout); xprt->reestablish_timeout <<= 1; if (xprt->reestablish_timeout > XS_TCP_MAX_REEST_TO) xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO; } else { dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); - schedule_work(&xprt->connect_worker); + schedule_work(&transport->connect_worker); /* flush_scheduled_work can sleep... */ if (!RPC_IS_ASYNC(task)) @@ -1316,8 +1324,10 @@ static void xs_connect(struct rpc_task *task) */ static void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) { + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n", - xprt->port, + transport->port, xprt->stat.bind_count, xprt->stat.sends, xprt->stat.recvs, @@ -1334,13 +1344,14 @@ static void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) */ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) { + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); long idle_time = 0; if (xprt_connected(xprt)) idle_time = (long)(jiffies - xprt->last_used) / HZ; seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n", - xprt->port, + transport->port, xprt->stat.bind_count, xprt->stat.connect_count, xprt->stat.connect_time, @@ -1414,7 +1425,7 @@ static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, uns memcpy(&xprt->addr, addr, addrlen); xprt->addrlen = addrlen; - xprt->port = xs_get_random_port(); + new->port = xs_get_random_port(); return xprt; } @@ -1429,10 +1440,12 @@ static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, uns struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to) { struct rpc_xprt *xprt; + struct sock_xprt *transport; xprt = xs_setup_xprt(addr, addrlen, xprt_udp_slot_table_entries); if (IS_ERR(xprt)) return xprt; + transport = container_of(xprt, struct sock_xprt, xprt); if (ntohs(((struct sockaddr_in *)addr)->sin_port) != 0) xprt_set_bound(xprt); @@ -1442,7 +1455,7 @@ struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_ /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); - INIT_WORK(&xprt->connect_worker, xs_udp_connect_worker, xprt); + INIT_WORK(&transport->connect_worker, xs_udp_connect_worker, transport); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_UDP_CONN_TO; xprt->reestablish_timeout = XS_UDP_REEST_TO; @@ -1472,10 +1485,12 @@ struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_ struct rpc_xprt *xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to) { struct rpc_xprt *xprt; + struct sock_xprt *transport; xprt = xs_setup_xprt(addr, addrlen, xprt_tcp_slot_table_entries); if (IS_ERR(xprt)) return xprt; + transport = container_of(xprt, struct sock_xprt, xprt); if (ntohs(((struct sockaddr_in *)addr)->sin_port) != 0) xprt_set_bound(xprt); @@ -1484,7 +1499,7 @@ struct rpc_xprt *xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_ xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; - INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); + INIT_WORK(&transport->connect_worker, xs_tcp_connect_worker, transport); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_TCP_CONN_TO; xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; -- cgit v1.2.3 From 7c6e066ec29290bf062f5bff2984bad9be5809c7 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 5 Dec 2006 16:35:30 -0500 Subject: SUNRPC: Move the UDP socket bufsize parameters to a private data structure Move the socket-specific buffer size parameters for UDP sockets to a private data structure maintained in net/sunrpc/xprtsock.c. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 3 --- net/sunrpc/xprtsock.c | 24 ++++++++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 18bf72c06488..21beb56fb84c 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -137,9 +137,6 @@ struct rpc_xprt { unsigned long cong; /* current congestion */ unsigned long cwnd; /* congestion window */ - size_t rcvsize, /* transport rcv buffer size */ - sndsize; /* transport send buffer size */ - size_t max_payload; /* largest RPC payload size, in bytes */ unsigned int tsh_size; /* size of transport specific diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 4797a4608c07..b804381d5bee 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -151,6 +151,12 @@ struct sock_xprt { */ struct work_struct connect_worker; unsigned short port; + + /* + * UDP socket buffer size parameters + */ + size_t rcvsize, + sndsize; }; /* @@ -996,13 +1002,13 @@ static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt) struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct sock *sk = transport->inet; - if (xprt->rcvsize) { + if (transport->rcvsize) { sk->sk_userlocks |= SOCK_RCVBUF_LOCK; - sk->sk_rcvbuf = xprt->rcvsize * xprt->max_reqs * 2; + sk->sk_rcvbuf = transport->rcvsize * xprt->max_reqs * 2; } - if (xprt->sndsize) { + if (transport->sndsize) { sk->sk_userlocks |= SOCK_SNDBUF_LOCK; - sk->sk_sndbuf = xprt->sndsize * xprt->max_reqs * 2; + sk->sk_sndbuf = transport->sndsize * xprt->max_reqs * 2; sk->sk_write_space(sk); } } @@ -1017,12 +1023,14 @@ static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt) */ static void xs_udp_set_buffer_size(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize) { - xprt->sndsize = 0; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + + transport->sndsize = 0; if (sndsize) - xprt->sndsize = sndsize + 1024; - xprt->rcvsize = 0; + transport->sndsize = sndsize + 1024; + transport->rcvsize = 0; if (rcvsize) - xprt->rcvsize = rcvsize + 1024; + transport->rcvsize = rcvsize + 1024; xs_udp_do_set_buffer_size(xprt); } -- cgit v1.2.3 From 314dfd7987c71d7ba0c43ac3bf3d243c102ce025 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 5 Dec 2006 16:35:34 -0500 Subject: SUNRPC: move saved socket callback functions to a private data structure Move the three fields for saving socket callback functions out of the rpc_xprt structure and into a private data structure maintained in net/sunrpc/xprtsock.c. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 6 ------ net/sunrpc/xprtsock.c | 25 ++++++++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 21beb56fb84c..17f322794e91 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -17,8 +17,6 @@ #include #include -#include - extern unsigned int xprt_udp_slot_table_entries; extern unsigned int xprt_tcp_slot_table_entries; @@ -191,10 +189,6 @@ struct rpc_xprt { bklog_u; /* backlog queue utilization */ } stat; - void (*old_data_ready)(struct sock *, int); - void (*old_state_change)(struct sock *); - void (*old_write_space)(struct sock *); - char * address_strings[RPC_DISPLAY_MAX]; }; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index b804381d5bee..faa6bfebf258 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -157,6 +157,13 @@ struct sock_xprt { */ size_t rcvsize, sndsize; + + /* + * Saved socket callback addresses + */ + void (*old_data_ready)(struct sock *, int); + void (*old_state_change)(struct sock *); + void (*old_write_space)(struct sock *); }; /* @@ -536,9 +543,9 @@ static void xs_close(struct rpc_xprt *xprt) transport->sock = NULL; sk->sk_user_data = NULL; - sk->sk_data_ready = xprt->old_data_ready; - sk->sk_state_change = xprt->old_state_change; - sk->sk_write_space = xprt->old_write_space; + sk->sk_data_ready = transport->old_data_ready; + sk->sk_state_change = transport->old_state_change; + sk->sk_write_space = transport->old_write_space; write_unlock_bh(&sk->sk_callback_lock); sk->sk_no_check = 0; @@ -1147,9 +1154,9 @@ static void xs_udp_connect_worker(void *args) write_lock_bh(&sk->sk_callback_lock); sk->sk_user_data = xprt; - xprt->old_data_ready = sk->sk_data_ready; - xprt->old_state_change = sk->sk_state_change; - xprt->old_write_space = sk->sk_write_space; + transport->old_data_ready = sk->sk_data_ready; + transport->old_state_change = sk->sk_state_change; + transport->old_write_space = sk->sk_write_space; sk->sk_data_ready = xs_udp_data_ready; sk->sk_write_space = xs_udp_write_space; sk->sk_no_check = UDP_CSUM_NORCV; @@ -1234,9 +1241,9 @@ static void xs_tcp_connect_worker(void *args) write_lock_bh(&sk->sk_callback_lock); sk->sk_user_data = xprt; - xprt->old_data_ready = sk->sk_data_ready; - xprt->old_state_change = sk->sk_state_change; - xprt->old_write_space = sk->sk_write_space; + transport->old_data_ready = sk->sk_data_ready; + transport->old_state_change = sk->sk_state_change; + transport->old_write_space = sk->sk_write_space; sk->sk_data_ready = xs_tcp_data_ready; sk->sk_state_change = xs_tcp_state_change; sk->sk_write_space = xs_tcp_write_space; -- cgit v1.2.3 From 7559c7a28fbcaa0bca028eeebd5f251b09befe6b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 5 Dec 2006 16:35:37 -0500 Subject: SUNRPC: Make address format buffers more generic For now we will assume that all transports will use the address format buffers in the rpc_xprt struct to store their addresses. Change rpc_peer2str() to be a generic routine to handle this, and get rid of the print_address() op in the rpc_xprt_ops vector. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 - net/sunrpc/clnt.c | 6 +++++- net/sunrpc/xprtsock.c | 23 ++++------------------- 3 files changed, 9 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 17f322794e91..f780e72fc417 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -106,7 +106,6 @@ struct rpc_rqst { struct rpc_xprt_ops { void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); - char * (*print_addr)(struct rpc_xprt *xprt, enum rpc_display_format_t format); int (*reserve_xprt)(struct rpc_task *task); void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); void (*rpcbind)(struct rpc_task *task); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 7d65e19550cc..aba528b9ae76 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -594,7 +594,11 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr); char *rpc_peeraddr2str(struct rpc_clnt *clnt, enum rpc_display_format_t format) { struct rpc_xprt *xprt = clnt->cl_xprt; - return xprt->ops->print_addr(xprt, format); + + if (xprt->address_strings[format] != NULL) + return xprt->address_strings[format]; + else + return "unprintable"; } EXPORT_SYMBOL_GPL(rpc_peeraddr2str); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index faa6bfebf258..a94aff42d08c 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1060,19 +1060,6 @@ static unsigned short xs_get_random_port(void) return rand + xprt_min_resvport; } -/** - * xs_print_peer_address - format an IPv4 address for printing - * @xprt: generic transport - * @format: flags field indicating which parts of the address to render - */ -static char *xs_print_peer_address(struct rpc_xprt *xprt, enum rpc_display_format_t format) -{ - if (xprt->address_strings[format] != NULL) - return xprt->address_strings[format]; - else - return "unprintable"; -} - /** * xs_set_port - reset the port number in the remote endpoint address * @xprt: generic transport @@ -1146,7 +1133,7 @@ static void xs_udp_connect_worker(void *args) } dprintk("RPC: worker connecting xprt %p to address: %s\n", - xprt, xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); + xprt, xprt->address_strings[RPC_DISPLAY_ALL]); if (!transport->inet) { struct sock *sk = sock->sk; @@ -1233,7 +1220,7 @@ static void xs_tcp_connect_worker(void *args) xs_tcp_reuse_connection(xprt); dprintk("RPC: worker connecting xprt %p to address: %s\n", - xprt, xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); + xprt, xprt->address_strings[RPC_DISPLAY_ALL]); if (!transport->inet) { struct sock *sk = sock->sk; @@ -1380,7 +1367,6 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) static struct rpc_xprt_ops xs_udp_ops = { .set_buffer_size = xs_udp_set_buffer_size, - .print_addr = xs_print_peer_address, .reserve_xprt = xprt_reserve_xprt_cong, .release_xprt = xprt_release_xprt_cong, .rpcbind = rpc_getport, @@ -1398,7 +1384,6 @@ static struct rpc_xprt_ops xs_udp_ops = { }; static struct rpc_xprt_ops xs_tcp_ops = { - .print_addr = xs_print_peer_address, .reserve_xprt = xprt_reserve_xprt, .release_xprt = xs_tcp_release_xprt, .rpcbind = rpc_getport, @@ -1485,7 +1470,7 @@ struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_ xs_format_peer_addresses(xprt); dprintk("RPC: set up transport to address %s\n", - xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); + xprt->address_strings[RPC_DISPLAY_ALL]); return xprt; } @@ -1529,7 +1514,7 @@ struct rpc_xprt *xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_ xs_format_peer_addresses(xprt); dprintk("RPC: set up transport to address %s\n", - xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); + xprt->address_strings[RPC_DISPLAY_ALL]); return xprt; } -- cgit v1.2.3 From 9d29231690925915015c21c1fff73c7118099843 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 5 Dec 2006 16:35:41 -0500 Subject: SUNRPC: skb_read_bits is the same as xs_tcp_copy_data Clean-up: eliminate xs_tcp_copy_data -- it's exactly the same logic as the common routine skb_read_bits. The UDP and TCP socket read code now share the same routine for copying data into an xdr_buf. Now that skb_read_bits() is exported, rename it to avoid confusing it with a generic skb_* function. As these functions are XDR-specific, they should not have names that suggest they are of generic use. Also rename skb_read_and_csum_bits() to be consistent. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xdr.h | 1 + net/sunrpc/socklib.c | 14 +++++++------- net/sunrpc/xprtsock.c | 24 ++++-------------------- 3 files changed, 12 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 4d17846cd78a..a06aab278fe0 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -157,6 +157,7 @@ typedef struct { typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); +size_t xdr_skb_read_bits(skb_reader_t *desc, void *to, size_t len); extern int csum_partial_copy_to_xdr(struct xdr_buf *, struct sk_buff *); extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, skb_reader_t *, skb_read_actor_t); diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index 2635c543ba06..9c40d67c1ffb 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c @@ -16,7 +16,7 @@ /** - * skb_read_bits - copy some data bits from skb to internal buffer + * xdr_skb_read_bits - copy some data bits from skb to internal buffer * @desc: sk_buff copy helper * @to: copy destination * @len: number of bytes to copy @@ -24,11 +24,11 @@ * Possibly called several times to iterate over an sk_buff and copy * data out of it. */ -static size_t skb_read_bits(skb_reader_t *desc, void *to, size_t len) +size_t xdr_skb_read_bits(skb_reader_t *desc, void *to, size_t len) { if (len > desc->count) len = desc->count; - if (skb_copy_bits(desc->skb, desc->offset, to, len)) + if (unlikely(skb_copy_bits(desc->skb, desc->offset, to, len))) return 0; desc->count -= len; desc->offset += len; @@ -36,14 +36,14 @@ static size_t skb_read_bits(skb_reader_t *desc, void *to, size_t len) } /** - * skb_read_and_csum_bits - copy and checksum from skb to buffer + * xdr_skb_read_and_csum_bits - copy and checksum from skb to buffer * @desc: sk_buff copy helper * @to: copy destination * @len: number of bytes to copy * * Same as skb_read_bits, but calculate a checksum at the same time. */ -static size_t skb_read_and_csum_bits(skb_reader_t *desc, void *to, size_t len) +static size_t xdr_skb_read_and_csum_bits(skb_reader_t *desc, void *to, size_t len) { unsigned int pos; __wsum csum2; @@ -158,7 +158,7 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) goto no_checksum; desc.csum = csum_partial(skb->data, desc.offset, skb->csum); - if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits) < 0) + if (xdr_partial_copy_from_skb(xdr, 0, &desc, xdr_skb_read_and_csum_bits) < 0) return -1; if (desc.offset != skb->len) { __wsum csum2; @@ -173,7 +173,7 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) netdev_rx_csum_fault(skb->dev); return 0; no_checksum: - if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0) + if (xdr_partial_copy_from_skb(xdr, 0, &desc, xdr_skb_read_bits) < 0) return -1; if (desc.count) return -1; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index a94aff42d08c..450c350a0c62 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -651,22 +651,6 @@ static void xs_udp_data_ready(struct sock *sk, int len) read_unlock(&sk->sk_callback_lock); } -static inline size_t xs_tcp_copy_data(skb_reader_t *desc, void *p, size_t len) -{ - if (len > desc->count) - len = desc->count; - if (skb_copy_bits(desc->skb, desc->offset, p, len)) { - dprintk("RPC: failed to copy %zu bytes from skb. %zu bytes remain\n", - len, desc->count); - return 0; - } - desc->offset += len; - desc->count -= len; - dprintk("RPC: copied %zu bytes from skb. %zu bytes remain\n", - len, desc->count); - return len; -} - static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); @@ -675,7 +659,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc p = ((char *) &transport->tcp_fraghdr) + transport->tcp_offset; len = sizeof(transport->tcp_fraghdr) - transport->tcp_offset; - used = xs_tcp_copy_data(desc, p, len); + used = xdr_skb_read_bits(desc, p, len); transport->tcp_offset += used; if (used != len) return; @@ -721,7 +705,7 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, skb_reader_t *de len = sizeof(transport->tcp_xid) - transport->tcp_offset; dprintk("RPC: reading XID (%Zu bytes)\n", len); p = ((char *) &transport->tcp_xid) + transport->tcp_offset; - used = xs_tcp_copy_data(desc, p, len); + used = xdr_skb_read_bits(desc, p, len); transport->tcp_offset += used; if (used != len) return; @@ -761,12 +745,12 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc memcpy(&my_desc, desc, sizeof(my_desc)); my_desc.count = len; r = xdr_partial_copy_from_skb(rcvbuf, transport->tcp_copied, - &my_desc, xs_tcp_copy_data); + &my_desc, xdr_skb_read_bits); desc->count -= r; desc->offset += r; } else r = xdr_partial_copy_from_skb(rcvbuf, transport->tcp_copied, - desc, xs_tcp_copy_data); + desc, xdr_skb_read_bits); if (r > 0) { transport->tcp_copied += r; -- cgit v1.2.3 From dd4564715eae2c4136f278da9ae1c3bb5af3e509 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 5 Dec 2006 16:35:44 -0500 Subject: SUNRPC: Rename skb_reader_t and friends Clean-up: hch suggested that the RPC client shouldn't pollute the name space used by the generic skb manipulation routines in net/core/skbuff.c. Rename a couple of types in xdr.h to adhere to this convention. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xdr.h | 10 +++++----- net/sunrpc/socklib.c | 8 ++++---- net/sunrpc/xprtsock.c | 12 ++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index a06aab278fe0..9e340fa23c06 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -148,19 +148,19 @@ extern int write_bytes_to_xdr_buf(struct xdr_buf *, unsigned int, void *, unsign /* * Helper structure for copying from an sk_buff. */ -typedef struct { +struct xdr_skb_reader { struct sk_buff *skb; unsigned int offset; size_t count; __wsum csum; -} skb_reader_t; +}; -typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); +typedef size_t (*xdr_skb_read_actor)(struct xdr_skb_reader *desc, void *to, size_t len); -size_t xdr_skb_read_bits(skb_reader_t *desc, void *to, size_t len); +size_t xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len); extern int csum_partial_copy_to_xdr(struct xdr_buf *, struct sk_buff *); extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, - skb_reader_t *, skb_read_actor_t); + struct xdr_skb_reader *, xdr_skb_read_actor); extern int xdr_encode_word(struct xdr_buf *, unsigned int, u32); extern int xdr_decode_word(struct xdr_buf *, unsigned int, u32 *); diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index 9c40d67c1ffb..634885b0c04d 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c @@ -24,7 +24,7 @@ * Possibly called several times to iterate over an sk_buff and copy * data out of it. */ -size_t xdr_skb_read_bits(skb_reader_t *desc, void *to, size_t len) +size_t xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len) { if (len > desc->count) len = desc->count; @@ -43,7 +43,7 @@ size_t xdr_skb_read_bits(skb_reader_t *desc, void *to, size_t len) * * Same as skb_read_bits, but calculate a checksum at the same time. */ -static size_t xdr_skb_read_and_csum_bits(skb_reader_t *desc, void *to, size_t len) +static size_t xdr_skb_read_and_csum_bits(struct xdr_skb_reader *desc, void *to, size_t len) { unsigned int pos; __wsum csum2; @@ -66,7 +66,7 @@ static size_t xdr_skb_read_and_csum_bits(skb_reader_t *desc, void *to, size_t le * @copy_actor: virtual method for copying data * */ -ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, skb_reader_t *desc, skb_read_actor_t copy_actor) +ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct xdr_skb_reader *desc, xdr_skb_read_actor copy_actor) { struct page **ppage = xdr->pages; unsigned int len, pglen = xdr->page_len; @@ -148,7 +148,7 @@ out: */ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) { - skb_reader_t desc; + struct xdr_skb_reader desc; desc.skb = skb; desc.offset = sizeof(struct udphdr); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 450c350a0c62..ad61b3e9123b 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -651,7 +651,7 @@ static void xs_udp_data_ready(struct sock *sk, int len) read_unlock(&sk->sk_callback_lock); } -static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) +static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); size_t len, used; @@ -697,7 +697,7 @@ static void xs_tcp_check_fraghdr(struct sock_xprt *transport) } } -static inline void xs_tcp_read_xid(struct sock_xprt *transport, skb_reader_t *desc) +static inline void xs_tcp_read_xid(struct sock_xprt *transport, struct xdr_skb_reader *desc) { size_t len, used; char *p; @@ -717,7 +717,7 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, skb_reader_t *de xs_tcp_check_fraghdr(transport); } -static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) +static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct rpc_rqst *req; @@ -739,7 +739,7 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc rcvbuf = &req->rq_private_buf; len = desc->count; if (len > transport->tcp_reclen - transport->tcp_offset) { - skb_reader_t my_desc; + struct xdr_skb_reader my_desc; len = transport->tcp_reclen - transport->tcp_offset; memcpy(&my_desc, desc, sizeof(my_desc)); @@ -795,7 +795,7 @@ out: xs_tcp_check_fraghdr(transport); } -static inline void xs_tcp_read_discard(struct sock_xprt *transport, skb_reader_t *desc) +static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_skb_reader *desc) { size_t len; @@ -813,7 +813,7 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns { struct rpc_xprt *xprt = rd_desc->arg.data; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - skb_reader_t desc = { + struct xdr_skb_reader desc = { .skb = skb, .offset = offset, .count = len, -- cgit v1.2.3 From 5847e1f4d058677c5e46dc6c3e3c70e8855ea3ba Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 5 Dec 2006 16:36:14 -0500 Subject: SUNRPC: Remove pprintk() from net/sunrpc/xprt.c These appear to be deprecated. Removing them also gets rid of some sparse noise. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/debug.h | 6 ------ net/sunrpc/xprt.c | 2 -- 2 files changed, 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index e4729aa67654..60fce3c92857 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -62,12 +62,6 @@ extern unsigned int nlm_debug; # define RPC_IFDEBUG(x) #endif -#ifdef RPC_PROFILE -# define pprintk(args...) printk(## args) -#else -# define pprintk(args...) do ; while (0) -#endif - /* * Sysctl interface for RPC debugging */ diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 8cc2afa2942c..f8ca0a93454c 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -459,7 +459,6 @@ int xprt_adjust_timeout(struct rpc_rqst *req) if (to->to_maxval && req->rq_timeout >= to->to_maxval) req->rq_timeout = to->to_maxval; req->rq_retries++; - pprintk("RPC: %lu retrans\n", jiffies); } else { req->rq_timeout = to->to_initval; req->rq_retries = 0; @@ -468,7 +467,6 @@ int xprt_adjust_timeout(struct rpc_rqst *req) spin_lock_bh(&xprt->transport_lock); rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval); spin_unlock_bh(&xprt->transport_lock); - pprintk("RPC: %lu timeout\n", jiffies); status = -ETIMEDOUT; } -- cgit v1.2.3 From bb81a09e55eaf7e5f798468ab971469b6f66a259 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 7 Dec 2006 02:14:01 +0100 Subject: [PATCH] x86: all cpu backtrace When a spinlock lockup occurs, arrange for the NMI code to emit an all-cpu backtrace, so we get to see which CPU is holding the lock, and where. Cc: Andi Kleen Cc: Ingo Molnar Cc: Badari Pulavarty Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen --- arch/i386/kernel/nmi.c | 26 ++++++++++++++++++++++++++ arch/x86_64/kernel/nmi.c | 29 ++++++++++++++++++++++++++++- include/asm-i386/nmi.h | 8 ++++++++ include/asm-x86_64/nmi.h | 3 +++ include/linux/nmi.h | 5 +++++ lib/spinlock_debug.c | 4 ++++ 6 files changed, 74 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index eaafe233a5da..171194ccb7bc 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,8 @@ int nmi_watchdog_enabled; static DEFINE_PER_CPU(unsigned long, perfctr_nmi_owner); static DEFINE_PER_CPU(unsigned long, evntsel_nmi_owner[3]); +static cpumask_t backtrace_mask = CPU_MASK_NONE; + /* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now) */ @@ -907,6 +910,16 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) touched = 1; } + if (cpu_isset(cpu, backtrace_mask)) { + static DEFINE_SPINLOCK(lock); /* Serialise the printks */ + + spin_lock(&lock); + printk("NMI backtrace for cpu %d\n", cpu); + dump_stack(); + spin_unlock(&lock); + cpu_clear(cpu, backtrace_mask); + } + sum = per_cpu(irq_stat, cpu).apic_timer_irqs; /* if the apic timer isn't firing, this cpu isn't doing much */ @@ -1033,6 +1046,19 @@ int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file, #endif +void __trigger_all_cpu_backtrace(void) +{ + int i; + + backtrace_mask = cpu_online_map; + /* Wait for up to 10 seconds for all CPUs to do the backtrace */ + for (i = 0; i < 10 * 1000; i++) { + if (cpus_empty(backtrace_mask)) + break; + mdelay(1); + } +} + EXPORT_SYMBOL(nmi_active); EXPORT_SYMBOL(nmi_watchdog); EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi); diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index 7af9cb3e2d99..27e95e7922c1 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -12,14 +12,15 @@ * Mikael Pettersson : PM converted to driver model. Disable/enable API. */ +#include #include #include #include #include #include -#include #include #include +#include #include #include @@ -41,6 +42,8 @@ int panic_on_unrecovered_nmi; static DEFINE_PER_CPU(unsigned, perfctr_nmi_owner); static DEFINE_PER_CPU(unsigned, evntsel_nmi_owner[2]); +static cpumask_t backtrace_mask = CPU_MASK_NONE; + /* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now) */ @@ -782,6 +785,7 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) { int sum; int touched = 0; + int cpu = smp_processor_id(); struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); u64 dummy; int rc=0; @@ -799,6 +803,16 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) touched = 1; } + if (cpu_isset(cpu, backtrace_mask)) { + static DEFINE_SPINLOCK(lock); /* Serialise the printks */ + + spin_lock(&lock); + printk("NMI backtrace for cpu %d\n", cpu); + dump_stack(); + spin_unlock(&lock); + cpu_clear(cpu, backtrace_mask); + } + #ifdef CONFIG_X86_MCE /* Could check oops_in_progress here too, but it's safer not too */ @@ -931,6 +945,19 @@ int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file, #endif +void __trigger_all_cpu_backtrace(void) +{ + int i; + + backtrace_mask = cpu_online_map; + /* Wait for up to 10 seconds for all CPUs to do the backtrace */ + for (i = 0; i < 10 * 1000; i++) { + if (cpus_empty(backtrace_mask)) + break; + mdelay(1); + } +} + EXPORT_SYMBOL(nmi_active); EXPORT_SYMBOL(nmi_watchdog); EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi); diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h index 269d315719ca..b04333ea6f31 100644 --- a/include/asm-i386/nmi.h +++ b/include/asm-i386/nmi.h @@ -5,6 +5,9 @@ #define ASM_NMI_H #include +#include + +#ifdef ARCH_HAS_NMI_WATCHDOG /** * do_nmi_callback @@ -42,4 +45,9 @@ extern int proc_nmi_enabled(struct ctl_table *, int , struct file *, void __user *, size_t *, loff_t *); extern int unknown_nmi_panic; +void __trigger_all_cpu_backtrace(void); +#define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace() + +#endif + #endif /* ASM_NMI_H */ diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h index f367d4014b42..72375e7d32a8 100644 --- a/include/asm-x86_64/nmi.h +++ b/include/asm-x86_64/nmi.h @@ -77,4 +77,7 @@ extern int proc_nmi_enabled(struct ctl_table *, int , struct file *, extern int unknown_nmi_panic; +void __trigger_all_cpu_backtrace(void); +#define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace() + #endif /* ASM_NMI_H */ diff --git a/include/linux/nmi.h b/include/linux/nmi.h index e16904e28c3a..acb4ed130247 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -15,9 +15,14 @@ * disables interrupts for a long time. This call is stateless. */ #ifdef ARCH_HAS_NMI_WATCHDOG +#include extern void touch_nmi_watchdog(void); #else # define touch_nmi_watchdog() touch_softlockup_watchdog() #endif +#ifndef trigger_all_cpu_backtrace +#define trigger_all_cpu_backtrace() do { } while (0) +#endif + #endif diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c index b6c4f898197c..479fd462eaa9 100644 --- a/lib/spinlock_debug.c +++ b/lib/spinlock_debug.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -117,6 +118,9 @@ static void __spin_lock_debug(spinlock_t *lock) raw_smp_processor_id(), current->comm, current->pid, lock); dump_stack(); +#ifdef CONFIG_SMP + trigger_all_cpu_backtrace(); +#endif } } } -- cgit v1.2.3 From 968de4f02621db35b8ae5239c8cfc6664fb872d8 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 7 Dec 2006 02:14:04 +0100 Subject: [PATCH] i386: Relocatable kernel support This patch modifies the i386 kernel so that if CONFIG_RELOCATABLE is selected it will be able to be loaded at any 4K aligned address below 1G. The technique used is to compile the decompressor with -fPIC and modify it so the decompressor is fully relocatable. For the main kernel relocations are generated. Resulting in a kernel that is relocatable with no runtime overhead and no need to modify the source code. A reserved 32bit word in the parameters has been assigned to serve as a stack so we figure out where are running. Signed-off-by: Eric W. Biederman Signed-off-by: Vivek Goyal Signed-off-by: Andi Kleen --- arch/i386/Kconfig | 12 + arch/i386/Makefile | 4 +- arch/i386/boot/compressed/Makefile | 28 +- arch/i386/boot/compressed/head.S | 184 +++++++---- arch/i386/boot/compressed/misc.c | 261 ++++++++-------- arch/i386/boot/compressed/relocs.c | 563 ++++++++++++++++++++++++++++++++++ arch/i386/boot/compressed/vmlinux.lds | 43 +++ arch/i386/boot/compressed/vmlinux.scr | 3 +- arch/i386/boot/setup.S | 29 +- include/linux/screen_info.h | 3 +- 10 files changed, 920 insertions(+), 210 deletions(-) create mode 100644 arch/i386/boot/compressed/relocs.c create mode 100644 arch/i386/boot/compressed/vmlinux.lds (limited to 'include/linux') diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 8ff1c6fb5aa1..d588ca874bb4 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -773,6 +773,18 @@ config CRASH_DUMP PHYSICAL_START. For more details see Documentation/kdump/kdump.txt +config RELOCATABLE + bool "Build a relocatable kernel" + help + This build a kernel image that retains relocation information + so it can be loaded someplace besides the default 1MB. + The relocations tend to the kernel binary about 10% larger, + but are discarded at runtime. + + One use is for the kexec on panic case where the recovery kernel + must live at a different physical address than the primary + kernel. + config PHYSICAL_START hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 0677908dfa06..d1aca52bf690 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -26,7 +26,9 @@ endif LDFLAGS := -m elf_i386 OBJCOPYFLAGS := -O binary -R .note -R .comment -S -LDFLAGS_vmlinux := +ifdef CONFIG_RELOCATABLE +LDFLAGS_vmlinux := --emit-relocs +endif CHECKFLAGS += -D__i386__ CFLAGS += -pipe -msoft-float diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile index 258ea95224f6..cc28da3a881e 100644 --- a/arch/i386/boot/compressed/Makefile +++ b/arch/i386/boot/compressed/Makefile @@ -4,22 +4,42 @@ # create a compressed vmlinux image from the original vmlinux # -targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o +targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o \ + vmlinux.bin.all vmlinux.relocs EXTRA_AFLAGS := -traditional -LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 +LDFLAGS_vmlinux := -T +CFLAGS_misc.o += -fPIC +hostprogs-y := relocs -$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE +$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: $(obj)/vmlinux.bin: vmlinux FORCE $(call if_changed,objcopy) +quiet_cmd_relocs = RELOCS $@ + cmd_relocs = $(obj)/relocs $< > $@ +$(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE + $(call if_changed,relocs) + +vmlinux.bin.all-y := $(obj)/vmlinux.bin +vmlinux.bin.all-$(CONFIG_RELOCATABLE) += $(obj)/vmlinux.relocs +quiet_cmd_relocbin = BUILD $@ + cmd_relocbin = cat $(filter-out FORCE,$^) > $@ +$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE + $(call if_changed,relocbin) + +ifdef CONFIG_RELOCATABLE +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE + $(call if_changed,gzip) +else $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE $(call if_changed,gzip) +endif LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T -$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE +$(obj)/piggy.o: $(src)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE $(call if_changed,ld) diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S index 40a8de8270a9..e4dd7a6b9b0f 100644 --- a/arch/i386/boot/compressed/head.S +++ b/arch/i386/boot/compressed/head.S @@ -25,9 +25,11 @@ #include #include +#include +.section ".text.head" .globl startup_32 - + startup_32: cld cli @@ -36,93 +38,141 @@ startup_32: movl %eax,%es movl %eax,%fs movl %eax,%gs + movl %eax,%ss - lss stack_start,%esp - xorl %eax,%eax -1: incl %eax # check that A20 really IS enabled - movl %eax,0x000000 # loop forever if it isn't - cmpl %eax,0x100000 - je 1b +/* Calculate the delta between where we were compiled to run + * at and where we were actually loaded at. This can only be done + * with a short local call on x86. Nothing else will tell us what + * address we are running at. The reserved chunk of the real-mode + * data at 0x34-0x3f are used as the stack for this calculation. + * Only 4 bytes are needed. + */ + leal 0x40(%esi), %esp + call 1f +1: popl %ebp + subl $1b, %ebp + +/* Compute the delta between where we were compiled to run at + * and where the code will actually run at. + */ + /* Start with the delta to where the kernel will run at. If we are + * a relocatable kernel this is the delta to our load address otherwise + * this is the delta to CONFIG_PHYSICAL start. + */ +#ifdef CONFIG_RELOCATABLE + movl %ebp, %ebx +#else + movl $(CONFIG_PHYSICAL_START - startup_32), %ebx +#endif + + /* Replace the compressed data size with the uncompressed size */ + subl input_len(%ebp), %ebx + movl output_len(%ebp), %eax + addl %eax, %ebx + /* Add 8 bytes for every 32K input block */ + shrl $12, %eax + addl %eax, %ebx + /* Add 32K + 18 bytes of extra slack */ + addl $(32768 + 18), %ebx + /* Align on a 4K boundary */ + addl $4095, %ebx + andl $~4095, %ebx + +/* Copy the compressed kernel to the end of our buffer + * where decompression in place becomes safe. + */ + pushl %esi + leal _end(%ebp), %esi + leal _end(%ebx), %edi + movl $(_end - startup_32), %ecx + std + rep + movsb + cld + popl %esi + +/* Compute the kernel start address. + */ +#ifdef CONFIG_RELOCATABLE + leal startup_32(%ebp), %ebp +#else + movl $CONFIG_PHYSICAL_START, %ebp +#endif /* - * Initialize eflags. Some BIOS's leave bits like NT set. This would - * confuse the debugger if this code is traced. - * XXX - best to initialize before switching to protected mode. + * Jump to the relocated address. */ - pushl $0 - popfl + leal relocated(%ebx), %eax + jmp *%eax +.section ".text" +relocated: + /* * Clear BSS */ xorl %eax,%eax - movl $_edata,%edi - movl $_end,%ecx + leal _edata(%ebx),%edi + leal _end(%ebx), %ecx subl %edi,%ecx cld rep stosb + +/* + * Setup the stack for the decompressor + */ + leal stack_end(%ebx), %esp + /* * Do the decompression, and jump to the new kernel.. */ - subl $16,%esp # place for structure on the stack - movl %esp,%eax + movl output_len(%ebx), %eax + pushl %eax + pushl %ebp # output address + movl input_len(%ebx), %eax + pushl %eax # input_len + leal input_data(%ebx), %eax + pushl %eax # input_data + leal _end(%ebx), %eax + pushl %eax # end of the image as third argument pushl %esi # real mode pointer as second arg - pushl %eax # address of structure as first arg call decompress_kernel - orl %eax,%eax - jnz 3f - popl %esi # discard address - popl %esi # real mode pointer - xorl %ebx,%ebx - ljmp $(__BOOT_CS), $CONFIG_PHYSICAL_START + addl $20, %esp + popl %ecx + +#if CONFIG_RELOCATABLE +/* Find the address of the relocations. + */ + movl %ebp, %edi + addl %ecx, %edi + +/* Calculate the delta between where vmlinux was compiled to run + * and where it was actually loaded. + */ + movl %ebp, %ebx + subl $CONFIG_PHYSICAL_START, %ebx /* - * We come here, if we were loaded high. - * We need to move the move-in-place routine down to 0x1000 - * and then start it with the buffer addresses in registers, - * which we got from the stack. + * Process relocations. */ -3: - movl $move_routine_start,%esi - movl $0x1000,%edi - movl $move_routine_end,%ecx - subl %esi,%ecx - addl $3,%ecx - shrl $2,%ecx - cld - rep - movsl - - popl %esi # discard the address - popl %ebx # real mode pointer - popl %esi # low_buffer_start - popl %ecx # lcount - popl %edx # high_buffer_start - popl %eax # hcount - movl $CONFIG_PHYSICAL_START,%edi - cli # make sure we don't get interrupted - ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine + +1: subl $4, %edi + movl 0(%edi), %ecx + testl %ecx, %ecx + jz 2f + addl %ebx, -__PAGE_OFFSET(%ebx, %ecx) + jmp 1b +2: +#endif /* - * Routine (template) for moving the decompressed kernel in place, - * if we were high loaded. This _must_ PIC-code ! + * Jump to the decompressed kernel. */ -move_routine_start: - movl %ecx,%ebp - shrl $2,%ecx - rep - movsl - movl %ebp,%ecx - andl $3,%ecx - rep - movsb - movl %edx,%esi - movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0 - addl $3,%ecx - shrl $2,%ecx - rep - movsl - movl %ebx,%esi # Restore setup pointer xorl %ebx,%ebx - ljmp $(__BOOT_CS), $CONFIG_PHYSICAL_START -move_routine_end: + jmp *%ebp + +.bss +.balign 4 +stack: + .fill 4096, 1, 0 +stack_end: diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c index 20970ff44119..4eac24e95a10 100644 --- a/arch/i386/boot/compressed/misc.c +++ b/arch/i386/boot/compressed/misc.c @@ -13,6 +13,88 @@ #include #include #include +#include + +/* WARNING!! + * This code is compiled with -fPIC and it is relocated dynamically + * at run time, but no relocation processing is performed. + * This means that it is not safe to place pointers in static structures. + */ + +/* + * Getting to provable safe in place decompression is hard. + * Worst case behaviours need to be analized. + * Background information: + * + * The file layout is: + * magic[2] + * method[1] + * flags[1] + * timestamp[4] + * extraflags[1] + * os[1] + * compressed data blocks[N] + * crc[4] orig_len[4] + * + * resulting in 18 bytes of non compressed data overhead. + * + * Files divided into blocks + * 1 bit (last block flag) + * 2 bits (block type) + * + * 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved. + * The smallest block type encoding is always used. + * + * stored: + * 32 bits length in bytes. + * + * fixed: + * magic fixed tree. + * symbols. + * + * dynamic: + * dynamic tree encoding. + * symbols. + * + * + * The buffer for decompression in place is the length of the + * uncompressed data, plus a small amount extra to keep the algorithm safe. + * The compressed data is placed at the end of the buffer. The output + * pointer is placed at the start of the buffer and the input pointer + * is placed where the compressed data starts. Problems will occur + * when the output pointer overruns the input pointer. + * + * The output pointer can only overrun the input pointer if the input + * pointer is moving faster than the output pointer. A condition only + * triggered by data whose compressed form is larger than the uncompressed + * form. + * + * The worst case at the block level is a growth of the compressed data + * of 5 bytes per 32767 bytes. + * + * The worst case internal to a compressed block is very hard to figure. + * The worst case can at least be boundined by having one bit that represents + * 32764 bytes and then all of the rest of the bytes representing the very + * very last byte. + * + * All of which is enough to compute an amount of extra data that is required + * to be safe. To avoid problems at the block level allocating 5 extra bytes + * per 32767 bytes of data is sufficient. To avoind problems internal to a block + * adding an extra 32767 bytes (the worst case uncompressed block size) is + * sufficient, to ensure that in the worst case the decompressed data for + * block will stop the byte before the compressed data for a block begins. + * To avoid problems with the compressed data's meta information an extra 18 + * bytes are needed. Leading to the formula: + * + * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size. + * + * Adding 8 bytes per 32K is a bit excessive but much easier to calculate. + * Adding 32768 instead of 32767 just makes for round numbers. + * Adding the decompressor_size is necessary as it musht live after all + * of the data as well. Last I measured the decompressor is about 14K. + * 10K of actuall data and 4K of bss. + * + */ /* * gzip declarations @@ -29,15 +111,20 @@ typedef unsigned char uch; typedef unsigned short ush; typedef unsigned long ulg; -#define WSIZE 0x8000 /* Window size must be at least 32k, */ - /* and a power of two */ +#define WSIZE 0x80000000 /* Window size must be at least 32k, + * and a power of two + * We don't actually have a window just + * a huge output buffer so I report + * a 2G windows size, as that should + * always be larger than our output buffer. + */ -static uch *inbuf; /* input buffer */ -static uch window[WSIZE]; /* Sliding window buffer */ +static uch *inbuf; /* input buffer */ +static uch *window; /* Sliding window buffer, (and final output buffer) */ -static unsigned insize = 0; /* valid bytes in inbuf */ -static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ -static unsigned outcnt = 0; /* bytes in output buffer */ +static unsigned insize; /* valid bytes in inbuf */ +static unsigned inptr; /* index of next byte to be processed in inbuf */ +static unsigned outcnt; /* bytes in output buffer */ /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ @@ -88,8 +175,6 @@ extern unsigned char input_data[]; extern int input_len; static long bytes_out = 0; -static uch *output_data; -static unsigned long output_ptr = 0; static void *malloc(int size); static void free(void *where); @@ -99,17 +184,10 @@ static void *memcpy(void *dest, const void *src, unsigned n); static void putstr(const char *); -extern int end; -static long free_mem_ptr = (long)&end; -static long free_mem_end_ptr; +static unsigned long free_mem_ptr; +static unsigned long free_mem_end_ptr; -#define INPLACE_MOVE_ROUTINE 0x1000 -#define LOW_BUFFER_START 0x2000 -#define LOW_BUFFER_MAX 0x90000 #define HEAP_SIZE 0x3000 -static unsigned int low_buffer_end, low_buffer_size; -static int high_loaded =0; -static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; static char *vidmem = (char *)0xb8000; static int vidport; @@ -150,7 +228,7 @@ static void gzip_mark(void **ptr) static void gzip_release(void **ptr) { - free_mem_ptr = (long) *ptr; + free_mem_ptr = (unsigned long) *ptr; } static void scroll(void) @@ -178,7 +256,7 @@ static void putstr(const char *s) y--; } } else { - vidmem [ ( x + cols * y ) * 2 ] = c; + vidmem [ ( x + cols * y ) * 2 ] = c; if ( ++x >= cols ) { x = 0; if ( ++y >= lines ) { @@ -223,58 +301,31 @@ static void* memcpy(void* dest, const void* src, unsigned n) */ static int fill_inbuf(void) { - if (insize != 0) { - error("ran out of input data"); - } - - inbuf = input_data; - insize = input_len; - inptr = 1; - return inbuf[0]; + error("ran out of input data"); + return 0; } /* =========================================================================== * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ -static void flush_window_low(void) -{ - ulg c = crc; /* temporary variable */ - unsigned n; - uch *in, *out, ch; - - in = window; - out = &output_data[output_ptr]; - for (n = 0; n < outcnt; n++) { - ch = *out++ = *in++; - c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); - } - crc = c; - bytes_out += (ulg)outcnt; - output_ptr += (ulg)outcnt; - outcnt = 0; -} - -static void flush_window_high(void) -{ - ulg c = crc; /* temporary variable */ - unsigned n; - uch *in, ch; - in = window; - for (n = 0; n < outcnt; n++) { - ch = *output_data++ = *in++; - if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start; - c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); - } - crc = c; - bytes_out += (ulg)outcnt; - outcnt = 0; -} - static void flush_window(void) { - if (high_loaded) flush_window_high(); - else flush_window_low(); + /* With my window equal to my output buffer + * I only need to compute the crc here. + */ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, ch; + + in = window; + for (n = 0; n < outcnt; n++) { + ch = *in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + outcnt = 0; } static void error(char *x) @@ -286,66 +337,8 @@ static void error(char *x) while(1); /* Halt */ } -#define STACK_SIZE (4096) - -long user_stack [STACK_SIZE]; - -struct { - long * a; - short b; - } stack_start = { & user_stack [STACK_SIZE] , __BOOT_DS }; - -static void setup_normal_output_buffer(void) -{ -#ifdef STANDARD_MEMORY_BIOS_CALL - if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory"); -#else - if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory"); -#endif - output_data = (unsigned char *)CONFIG_PHYSICAL_START; /* Normally Points to 1M */ - free_mem_end_ptr = (long)real_mode; -} - -struct moveparams { - uch *low_buffer_start; int lcount; - uch *high_buffer_start; int hcount; -}; - -static void setup_output_buffer_if_we_run_high(struct moveparams *mv) -{ - high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); -#ifdef STANDARD_MEMORY_BIOS_CALL - if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory"); -#else - if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory"); -#endif - mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START; - low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX - ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff; - low_buffer_size = low_buffer_end - LOW_BUFFER_START; - high_loaded = 1; - free_mem_end_ptr = (long)high_buffer_start; - if ( (CONFIG_PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) { - high_buffer_start = (uch *)(CONFIG_PHYSICAL_START + low_buffer_size); - mv->hcount = 0; /* say: we need not to move high_buffer */ - } - else mv->hcount = -1; - mv->high_buffer_start = high_buffer_start; -} - -static void close_output_buffer_if_we_run_high(struct moveparams *mv) -{ - if (bytes_out > low_buffer_size) { - mv->lcount = low_buffer_size; - if (mv->hcount) - mv->hcount = bytes_out - low_buffer_size; - } else { - mv->lcount = bytes_out; - mv->hcount = 0; - } -} - -asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode) +asmlinkage void decompress_kernel(void *rmode, unsigned long end, + uch *input_data, unsigned long input_len, uch *output) { real_mode = rmode; @@ -360,13 +353,25 @@ asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode) lines = RM_SCREEN_INFO.orig_video_lines; cols = RM_SCREEN_INFO.orig_video_cols; - if (free_mem_ptr < 0x100000) setup_normal_output_buffer(); - else setup_output_buffer_if_we_run_high(mv); + window = output; /* Output buffer (Normally at 1M) */ + free_mem_ptr = end; /* Heap */ + free_mem_end_ptr = end + HEAP_SIZE; + inbuf = input_data; /* Input buffer */ + insize = input_len; + inptr = 0; + + if (((u32)output - CONFIG_PHYSICAL_START) & 0x3fffff) + error("Destination address not 4M aligned"); + if (end > ((-__PAGE_OFFSET-(512 <<20)-1) & 0x7fffffff)) + error("Destination address too large"); +#ifndef CONFIG_RELOCATABLE + if ((u32)output != CONFIG_PHYSICAL_START) + error("Wrong destination address"); +#endif makecrc(); putstr("Uncompressing Linux... "); gunzip(); putstr("Ok, booting the kernel.\n"); - if (high_loaded) close_output_buffer_if_we_run_high(mv); - return high_loaded; + return; } diff --git a/arch/i386/boot/compressed/relocs.c b/arch/i386/boot/compressed/relocs.c new file mode 100644 index 000000000000..0551ceb21bed --- /dev/null +++ b/arch/i386/boot/compressed/relocs.c @@ -0,0 +1,563 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define USE_BSD +#include + +#define MAX_SHDRS 100 +static Elf32_Ehdr ehdr; +static Elf32_Shdr shdr[MAX_SHDRS]; +static Elf32_Sym *symtab[MAX_SHDRS]; +static Elf32_Rel *reltab[MAX_SHDRS]; +static char *strtab[MAX_SHDRS]; +static unsigned long reloc_count, reloc_idx; +static unsigned long *relocs; + +static void die(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +static const char *sym_type(unsigned type) +{ + static const char *type_name[] = { +#define SYM_TYPE(X) [X] = #X + SYM_TYPE(STT_NOTYPE), + SYM_TYPE(STT_OBJECT), + SYM_TYPE(STT_FUNC), + SYM_TYPE(STT_SECTION), + SYM_TYPE(STT_FILE), + SYM_TYPE(STT_COMMON), + SYM_TYPE(STT_TLS), +#undef SYM_TYPE + }; + const char *name = "unknown sym type name"; + if (type < sizeof(type_name)/sizeof(type_name[0])) { + name = type_name[type]; + } + return name; +} + +static const char *sym_bind(unsigned bind) +{ + static const char *bind_name[] = { +#define SYM_BIND(X) [X] = #X + SYM_BIND(STB_LOCAL), + SYM_BIND(STB_GLOBAL), + SYM_BIND(STB_WEAK), +#undef SYM_BIND + }; + const char *name = "unknown sym bind name"; + if (bind < sizeof(bind_name)/sizeof(bind_name[0])) { + name = bind_name[bind]; + } + return name; +} + +static const char *sym_visibility(unsigned visibility) +{ + static const char *visibility_name[] = { +#define SYM_VISIBILITY(X) [X] = #X + SYM_VISIBILITY(STV_DEFAULT), + SYM_VISIBILITY(STV_INTERNAL), + SYM_VISIBILITY(STV_HIDDEN), + SYM_VISIBILITY(STV_PROTECTED), +#undef SYM_VISIBILITY + }; + const char *name = "unknown sym visibility name"; + if (visibility < sizeof(visibility_name)/sizeof(visibility_name[0])) { + name = visibility_name[visibility]; + } + return name; +} + +static const char *rel_type(unsigned type) +{ + static const char *type_name[] = { +#define REL_TYPE(X) [X] = #X + REL_TYPE(R_386_NONE), + REL_TYPE(R_386_32), + REL_TYPE(R_386_PC32), + REL_TYPE(R_386_GOT32), + REL_TYPE(R_386_PLT32), + REL_TYPE(R_386_COPY), + REL_TYPE(R_386_GLOB_DAT), + REL_TYPE(R_386_JMP_SLOT), + REL_TYPE(R_386_RELATIVE), + REL_TYPE(R_386_GOTOFF), + REL_TYPE(R_386_GOTPC), +#undef REL_TYPE + }; + const char *name = "unknown type rel type name"; + if (type < sizeof(type_name)/sizeof(type_name[0])) { + name = type_name[type]; + } + return name; +} + +static const char *sec_name(unsigned shndx) +{ + const char *sec_strtab; + const char *name; + sec_strtab = strtab[ehdr.e_shstrndx]; + name = ""; + if (shndx < ehdr.e_shnum) { + name = sec_strtab + shdr[shndx].sh_name; + } + else if (shndx == SHN_ABS) { + name = "ABSOLUTE"; + } + else if (shndx == SHN_COMMON) { + name = "COMMON"; + } + return name; +} + +static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym) +{ + const char *name; + name = ""; + if (sym->st_name) { + name = sym_strtab + sym->st_name; + } + else { + name = sec_name(shdr[sym->st_shndx].sh_name); + } + return name; +} + + + +#if BYTE_ORDER == LITTLE_ENDIAN +#define le16_to_cpu(val) (val) +#define le32_to_cpu(val) (val) +#endif +#if BYTE_ORDER == BIG_ENDIAN +#define le16_to_cpu(val) bswap_16(val) +#define le32_to_cpu(val) bswap_32(val) +#endif + +static uint16_t elf16_to_cpu(uint16_t val) +{ + return le16_to_cpu(val); +} + +static uint32_t elf32_to_cpu(uint32_t val) +{ + return le32_to_cpu(val); +} + +static void read_ehdr(FILE *fp) +{ + if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { + die("Cannot read ELF header: %s\n", + strerror(errno)); + } + if (memcmp(ehdr.e_ident, ELFMAG, 4) != 0) { + die("No ELF magic\n"); + } + if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) { + die("Not a 32 bit executable\n"); + } + if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { + die("Not a LSB ELF executable\n"); + } + if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) { + die("Unknown ELF version\n"); + } + /* Convert the fields to native endian */ + ehdr.e_type = elf16_to_cpu(ehdr.e_type); + ehdr.e_machine = elf16_to_cpu(ehdr.e_machine); + ehdr.e_version = elf32_to_cpu(ehdr.e_version); + ehdr.e_entry = elf32_to_cpu(ehdr.e_entry); + ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff); + ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff); + ehdr.e_flags = elf32_to_cpu(ehdr.e_flags); + ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize); + ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize); + ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum); + ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize); + ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum); + ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx); + + if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) { + die("Unsupported ELF header type\n"); + } + if (ehdr.e_machine != EM_386) { + die("Not for x86\n"); + } + if (ehdr.e_version != EV_CURRENT) { + die("Unknown ELF version\n"); + } + if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) { + die("Bad Elf header size\n"); + } + if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) { + die("Bad program header entry\n"); + } + if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) { + die("Bad section header entry\n"); + } + if (ehdr.e_shstrndx >= ehdr.e_shnum) { + die("String table index out of bounds\n"); + } +} + +static void read_shdrs(FILE *fp) +{ + int i; + if (ehdr.e_shnum > MAX_SHDRS) { + die("%d section headers supported: %d\n", + ehdr.e_shnum, MAX_SHDRS); + } + if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + ehdr.e_shoff, strerror(errno)); + } + if (fread(&shdr, sizeof(shdr[0]), ehdr.e_shnum, fp) != ehdr.e_shnum) { + die("Cannot read ELF section headers: %s\n", + strerror(errno)); + } + for(i = 0; i < ehdr.e_shnum; i++) { + shdr[i].sh_name = elf32_to_cpu(shdr[i].sh_name); + shdr[i].sh_type = elf32_to_cpu(shdr[i].sh_type); + shdr[i].sh_flags = elf32_to_cpu(shdr[i].sh_flags); + shdr[i].sh_addr = elf32_to_cpu(shdr[i].sh_addr); + shdr[i].sh_offset = elf32_to_cpu(shdr[i].sh_offset); + shdr[i].sh_size = elf32_to_cpu(shdr[i].sh_size); + shdr[i].sh_link = elf32_to_cpu(shdr[i].sh_link); + shdr[i].sh_info = elf32_to_cpu(shdr[i].sh_info); + shdr[i].sh_addralign = elf32_to_cpu(shdr[i].sh_addralign); + shdr[i].sh_entsize = elf32_to_cpu(shdr[i].sh_entsize); + } + +} + +static void read_strtabs(FILE *fp) +{ + int i; + for(i = 0; i < ehdr.e_shnum; i++) { + if (shdr[i].sh_type != SHT_STRTAB) { + continue; + } + strtab[i] = malloc(shdr[i].sh_size); + if (!strtab[i]) { + die("malloc of %d bytes for strtab failed\n", + shdr[i].sh_size); + } + if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + shdr[i].sh_offset, strerror(errno)); + } + if (fread(strtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + } +} + +static void read_symtabs(FILE *fp) +{ + int i,j; + for(i = 0; i < ehdr.e_shnum; i++) { + if (shdr[i].sh_type != SHT_SYMTAB) { + continue; + } + symtab[i] = malloc(shdr[i].sh_size); + if (!symtab[i]) { + die("malloc of %d bytes for symtab failed\n", + shdr[i].sh_size); + } + if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + shdr[i].sh_offset, strerror(errno)); + } + if (fread(symtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + for(j = 0; j < shdr[i].sh_size/sizeof(symtab[i][0]); j++) { + symtab[i][j].st_name = elf32_to_cpu(symtab[i][j].st_name); + symtab[i][j].st_value = elf32_to_cpu(symtab[i][j].st_value); + symtab[i][j].st_size = elf32_to_cpu(symtab[i][j].st_size); + symtab[i][j].st_shndx = elf16_to_cpu(symtab[i][j].st_shndx); + } + } +} + + +static void read_relocs(FILE *fp) +{ + int i,j; + for(i = 0; i < ehdr.e_shnum; i++) { + if (shdr[i].sh_type != SHT_REL) { + continue; + } + reltab[i] = malloc(shdr[i].sh_size); + if (!reltab[i]) { + die("malloc of %d bytes for relocs failed\n", + shdr[i].sh_size); + } + if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + shdr[i].sh_offset, strerror(errno)); + } + if (fread(reltab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) { + reltab[i][j].r_offset = elf32_to_cpu(reltab[i][j].r_offset); + reltab[i][j].r_info = elf32_to_cpu(reltab[i][j].r_info); + } + } +} + + +static void print_absolute_symbols(void) +{ + int i; + printf("Absolute symbols\n"); + printf(" Num: Value Size Type Bind Visibility Name\n"); + for(i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf32_Sym *sh_symtab; + int j; + if (shdr[i].sh_type != SHT_SYMTAB) { + continue; + } + sh_symtab = symtab[i]; + sym_strtab = strtab[shdr[i].sh_link]; + for(j = 0; j < shdr[i].sh_size/sizeof(symtab[0][0]); j++) { + Elf32_Sym *sym; + const char *name; + sym = &symtab[i][j]; + name = sym_name(sym_strtab, sym); + if (sym->st_shndx != SHN_ABS) { + continue; + } + printf("%5d %08x %5d %10s %10s %12s %s\n", + j, sym->st_value, sym->st_size, + sym_type(ELF32_ST_TYPE(sym->st_info)), + sym_bind(ELF32_ST_BIND(sym->st_info)), + sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)), + name); + } + } + printf("\n"); +} + +static void print_absolute_relocs(void) +{ + int i; + printf("Absolute relocations\n"); + printf("Offset Info Type Sym.Value Sym.Name\n"); + for(i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf32_Sym *sh_symtab; + unsigned sec_applies, sec_symtab; + int j; + if (shdr[i].sh_type != SHT_REL) { + continue; + } + sec_symtab = shdr[i].sh_link; + sec_applies = shdr[i].sh_info; + if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) { + continue; + } + sh_symtab = symtab[sec_symtab]; + sym_strtab = strtab[shdr[sec_symtab].sh_link]; + for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) { + Elf32_Rel *rel; + Elf32_Sym *sym; + const char *name; + rel = &reltab[i][j]; + sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; + name = sym_name(sym_strtab, sym); + if (sym->st_shndx != SHN_ABS) { + continue; + } + printf("%08x %08x %10s %08x %s\n", + rel->r_offset, + rel->r_info, + rel_type(ELF32_R_TYPE(rel->r_info)), + sym->st_value, + name); + } + } + printf("\n"); +} + +static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) +{ + int i; + /* Walk through the relocations */ + for(i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf32_Sym *sh_symtab; + unsigned sec_applies, sec_symtab; + int j; + if (shdr[i].sh_type != SHT_REL) { + continue; + } + sec_symtab = shdr[i].sh_link; + sec_applies = shdr[i].sh_info; + if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) { + continue; + } + sh_symtab = symtab[sec_symtab]; + sym_strtab = strtab[shdr[sec_symtab].sh_link]; + for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) { + Elf32_Rel *rel; + Elf32_Sym *sym; + unsigned r_type; + rel = &reltab[i][j]; + sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; + r_type = ELF32_R_TYPE(rel->r_info); + /* Don't visit relocations to absolute symbols */ + if (sym->st_shndx == SHN_ABS) { + continue; + } + if (r_type == R_386_PC32) { + /* PC relative relocations don't need to be adjusted */ + } + else if (r_type == R_386_32) { + /* Visit relocations that need to be adjusted */ + visit(rel, sym); + } + else { + die("Unsupported relocation type: %d\n", r_type); + } + } + } +} + +static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym) +{ + reloc_count += 1; +} + +static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) +{ + /* Remember the address that needs to be adjusted. */ + relocs[reloc_idx++] = rel->r_offset; +} + +static int cmp_relocs(const void *va, const void *vb) +{ + const unsigned long *a, *b; + a = va; b = vb; + return (*a == *b)? 0 : (*a > *b)? 1 : -1; +} + +static void emit_relocs(int as_text) +{ + int i; + /* Count how many relocations I have and allocate space for them. */ + reloc_count = 0; + walk_relocs(count_reloc); + relocs = malloc(reloc_count * sizeof(relocs[0])); + if (!relocs) { + die("malloc of %d entries for relocs failed\n", + reloc_count); + } + /* Collect up the relocations */ + reloc_idx = 0; + walk_relocs(collect_reloc); + + /* Order the relocations for more efficient processing */ + qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); + + /* Print the relocations */ + if (as_text) { + /* Print the relocations in a form suitable that + * gas will like. + */ + printf(".section \".data.reloc\",\"a\"\n"); + printf(".balign 4\n"); + for(i = 0; i < reloc_count; i++) { + printf("\t .long 0x%08lx\n", relocs[i]); + } + printf("\n"); + } + else { + unsigned char buf[4]; + buf[0] = buf[1] = buf[2] = buf[3] = 0; + /* Print a stop */ + printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); + /* Now print each relocation */ + for(i = 0; i < reloc_count; i++) { + buf[0] = (relocs[i] >> 0) & 0xff; + buf[1] = (relocs[i] >> 8) & 0xff; + buf[2] = (relocs[i] >> 16) & 0xff; + buf[3] = (relocs[i] >> 24) & 0xff; + printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); + } + } +} + +static void usage(void) +{ + die("i386_reloc [--abs | --text] vmlinux\n"); +} + +int main(int argc, char **argv) +{ + int show_absolute; + int as_text; + const char *fname; + FILE *fp; + int i; + + show_absolute = 0; + as_text = 0; + fname = NULL; + for(i = 1; i < argc; i++) { + char *arg = argv[i]; + if (*arg == '-') { + if (strcmp(argv[1], "--abs") == 0) { + show_absolute = 1; + continue; + } + else if (strcmp(argv[1], "--text") == 0) { + as_text = 1; + continue; + } + } + else if (!fname) { + fname = arg; + continue; + } + usage(); + } + if (!fname) { + usage(); + } + fp = fopen(fname, "r"); + if (!fp) { + die("Cannot open %s: %s\n", + fname, strerror(errno)); + } + read_ehdr(fp); + read_shdrs(fp); + read_strtabs(fp); + read_symtabs(fp); + read_relocs(fp); + if (show_absolute) { + print_absolute_symbols(); + print_absolute_relocs(); + return 0; + } + emit_relocs(as_text); + return 0; +} diff --git a/arch/i386/boot/compressed/vmlinux.lds b/arch/i386/boot/compressed/vmlinux.lds new file mode 100644 index 000000000000..cc4854f6c6c1 --- /dev/null +++ b/arch/i386/boot/compressed/vmlinux.lds @@ -0,0 +1,43 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(startup_32) +SECTIONS +{ + /* Be careful parts of head.S assume startup_32 is at + * address 0. + */ + . = 0 ; + .text.head : { + _head = . ; + *(.text.head) + _ehead = . ; + } + .data.compressed : { + *(.data.compressed) + } + .text : { + _text = .; /* Text */ + *(.text) + *(.text.*) + _etext = . ; + } + .rodata : { + _rodata = . ; + *(.rodata) /* read-only data */ + *(.rodata.*) + _erodata = . ; + } + .data : { + _data = . ; + *(.data) + *(.data.*) + _edata = . ; + } + .bss : { + _bss = . ; + *(.bss) + *(.bss.*) + *(COMMON) + _end = . ; + } +} diff --git a/arch/i386/boot/compressed/vmlinux.scr b/arch/i386/boot/compressed/vmlinux.scr index 1ed9d791f863..707a88f7f29e 100644 --- a/arch/i386/boot/compressed/vmlinux.scr +++ b/arch/i386/boot/compressed/vmlinux.scr @@ -1,9 +1,10 @@ SECTIONS { - .data : { + .data.compressed : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) + output_len = . - 4; input_data_end = .; } } diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index 3aec4538a113..9aa8b0518184 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -588,11 +588,6 @@ rmodeswtch_normal: call default_switch rmodeswtch_end: -# we get the code32 start address and modify the below 'jmpi' -# (loader may have changed it) - movl %cs:code32_start, %eax - movl %eax, %cs:code32 - # Now we move the system to its rightful place ... but we check if we have a # big-kernel. In that case we *must* not move it ... testb $LOADED_HIGH, %cs:loadflags @@ -788,11 +783,12 @@ a20_err_msg: a20_done: #endif /* CONFIG_X86_VOYAGER */ -# set up gdt and idt +# set up gdt and idt and 32bit start address lidt idt_48 # load idt with 0,0 xorl %eax, %eax # Compute gdt_base movw %ds, %ax # (Convert %ds:gdt to a linear ptr) shll $4, %eax + addl %eax, code32 addl $gdt, %eax movl %eax, (gdt_48+2) lgdt gdt_48 # load gdt with whatever is @@ -851,9 +847,26 @@ flush_instr: # Manual, Mixing 16-bit and 32-bit code, page 16-6) .byte 0x66, 0xea # prefix + jmpi-opcode -code32: .long 0x1000 # will be set to 0x100000 - # for big kernels +code32: .long startup_32 # will be set to %cs+startup_32 .word __BOOT_CS +.code32 +startup_32: + movl $(__BOOT_DS), %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + xorl %eax, %eax +1: incl %eax # check that A20 really IS enabled + movl %eax, 0x00000000 # loop forever if it isn't + cmpl %eax, 0x00100000 + je 1b + + # Jump to the 32bit entry point + jmpl *(code32_start - start + (DELTA_INITSEG << 4))(%esi) +.code16 # Here's a bunch of information about your current kernel.. kernel_version: .ascii UTS_RELEASE diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h index 2925e66a6732..b02308ee7667 100644 --- a/include/linux/screen_info.h +++ b/include/linux/screen_info.h @@ -42,7 +42,8 @@ struct screen_info { u16 pages; /* 0x32 */ u16 vesa_attributes; /* 0x34 */ u32 capabilities; /* 0x36 */ - /* 0x3a -- 0x3f reserved for future expansion */ + /* 0x3a -- 0x3b reserved for future expansion */ + /* 0x3c -- 0x3f micro stack for relocatable kernels */ }; extern struct screen_info screen_info; -- cgit v1.2.3 From 2fff0a48416af891dce38fd425246e337831e0bb Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 7 Dec 2006 02:14:05 +0100 Subject: [PATCH] Generic: Move __user cast into probe_kernel_address Caller of probe_kernel_address shouldn't need to know that pka is internally implemented with __get_user. So move the __user cast into pka. Signed-off-by: Andi Kleen --- include/linux/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index a48d7f11c7be..65a68da8bd5d 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -36,7 +36,7 @@ static inline unsigned long __copy_from_user_nocache(void *to, long ret; \ \ inc_preempt_count(); \ - ret = __get_user(retval, addr); \ + ret = __get_user(retval, (__force typeof(*addr) __user *)addr);\ dec_preempt_count(); \ ret; \ }) -- cgit v1.2.3 From d7cd56111f30259e1b532a12e06f59f8e0a20355 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 7 Dec 2006 02:14:08 +0100 Subject: [PATCH] i386: cpu_detect extraction Both lhype and Xen want to call the core of the x86 cpu detect code before calling start_kernel. (extracted from larger patch) AK: folded in start_kernel header patch Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Rusty Russell Signed-off-by: Andi Kleen Cc: Jeremy Fitzhardinge Cc: Andi Kleen Signed-off-by: Andrew Morton --- arch/i386/kernel/cpu/common.c | 37 +++++++++++++++++++++---------------- include/asm-i386/processor.h | 3 +++ include/linux/start_kernel.h | 12 ++++++++++++ init/main.c | 1 + 4 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 include/linux/start_kernel.h (limited to 'include/linux') diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index cda41aef79ad..68bcb687019a 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -236,29 +236,14 @@ static int __cpuinit have_cpuid_p(void) return flag_is_changeable_p(X86_EFLAGS_ID); } -/* Do minimum CPU detection early. - Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment. - The others are not touched to avoid unwanted side effects. - - WARNING: this function is only called on the BP. Don't add code here - that is supposed to run on all CPUs. */ -static void __init early_cpu_detect(void) +void __init cpu_detect(struct cpuinfo_x86 *c) { - struct cpuinfo_x86 *c = &boot_cpu_data; - - c->x86_cache_alignment = 32; - - if (!have_cpuid_p()) - return; - /* Get vendor name */ cpuid(0x00000000, &c->cpuid_level, (int *)&c->x86_vendor_id[0], (int *)&c->x86_vendor_id[8], (int *)&c->x86_vendor_id[4]); - get_cpu_vendor(c, 1); - c->x86 = 4; if (c->cpuid_level >= 0x00000001) { u32 junk, tfms, cap0, misc; @@ -275,6 +260,26 @@ static void __init early_cpu_detect(void) } } +/* Do minimum CPU detection early. + Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment. + The others are not touched to avoid unwanted side effects. + + WARNING: this function is only called on the BP. Don't add code here + that is supposed to run on all CPUs. */ +static void __init early_cpu_detect(void) +{ + struct cpuinfo_x86 *c = &boot_cpu_data; + + c->x86_cache_alignment = 32; + + if (!have_cpuid_p()) + return; + + cpu_detect(c); + + get_cpu_vendor(c, 1); +} + static void __cpuinit generic_identify(struct cpuinfo_x86 * c) { u32 tfms, xlvl; diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 5f0418d0078c..a52d65440429 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -20,6 +20,7 @@ #include #include #include +#include /* flag for disabling the tsc */ extern int tsc_disable; @@ -112,6 +113,8 @@ extern struct cpuinfo_x86 cpu_data[]; extern int cpu_llc_id[NR_CPUS]; extern char ignore_fpu_irq; +void __init cpu_detect(struct cpuinfo_x86 *c); + extern void identify_cpu(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *); extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); diff --git a/include/linux/start_kernel.h b/include/linux/start_kernel.h new file mode 100644 index 000000000000..d3e5f2756545 --- /dev/null +++ b/include/linux/start_kernel.h @@ -0,0 +1,12 @@ +#ifndef _LINUX_START_KERNEL_H +#define _LINUX_START_KERNEL_H + +#include +#include + +/* Define the prototype for start_kernel here, rather than cluttering + up something else. */ + +extern asmlinkage void __init start_kernel(void); + +#endif /* _LINUX_START_KERNEL_H */ diff --git a/init/main.c b/init/main.c index 36f608a7cfba..985c9ed86050 100644 --- a/init/main.c +++ b/init/main.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 72486f1f8f0a2bc828b9d30cf4690cf2dd6807fc Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" Date: Thu, 7 Dec 2006 02:14:10 +0100 Subject: [PATCH] i386: change the 'no_control' field to 'hotpluggable' in the struct cpu Change the 'no_control' field in the cpu struct to a more positive and better term 'hotpluggable'. And change(/cleanup) the logic accordingly. Signed-off-by: Suresh Siddha Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: "Li, Shaohua" Signed-off-by: Andrew Morton --- arch/i386/kernel/topology.c | 4 ++-- arch/ia64/kernel/topology.c | 8 ++++---- arch/powerpc/kernel/sysfs.c | 8 ++++---- drivers/base/cpu.c | 6 +++--- include/linux/cpu.h | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/topology.c b/arch/i386/kernel/topology.c index 844c08fdb225..79cf608e14ca 100644 --- a/arch/i386/kernel/topology.c +++ b/arch/i386/kernel/topology.c @@ -44,8 +44,8 @@ int arch_register_cpu(int num) * Also certain PCI quirks require not to enable hotplug control * for all CPU's. */ - if (!num || !enable_cpu_hotplug) - cpu_devices[num].cpu.no_control = 1; + if (num && enable_cpu_hotplug) + cpu_devices[num].cpu.hotpluggable = 1; return register_cpu(&cpu_devices[num].cpu, num); } diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c index 5629b45e89c6..687500ddb4b8 100644 --- a/arch/ia64/kernel/topology.c +++ b/arch/ia64/kernel/topology.c @@ -31,11 +31,11 @@ int arch_register_cpu(int num) { #if defined (CONFIG_ACPI) && defined (CONFIG_HOTPLUG_CPU) /* - * If CPEI cannot be re-targetted, and this is - * CPEI target, then dont create the control file + * If CPEI can be re-targetted or if this is not + * CPEI target, then it is hotpluggable */ - if (!can_cpei_retarget() && is_cpu_cpei_target(num)) - sysfs_cpus[num].cpu.no_control = 1; + if (can_cpei_retarget() || !is_cpu_cpei_target(num)) + sysfs_cpus[num].cpu.hotpluggable = 1; map_cpu_to_node(num, node_cpuid[num].nid); #endif diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 22123a0d5416..63ed265b7f09 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -239,7 +239,7 @@ static void unregister_cpu_online(unsigned int cpu) struct cpu *c = &per_cpu(cpu_devices, cpu); struct sys_device *s = &c->sysdev; - BUG_ON(c->no_control); + BUG_ON(!c->hotpluggable); if (!firmware_has_feature(FW_FEATURE_ISERIES) && cpu_has_feature(CPU_FTR_SMT)) @@ -424,10 +424,10 @@ static int __init topology_init(void) * CPU. For instance, the boot cpu might never be valid * for hotplugging. */ - if (!ppc_md.cpu_die) - c->no_control = 1; + if (ppc_md.cpu_die) + c->hotpluggable = 1; - if (cpu_online(cpu) || (c->no_control == 0)) { + if (cpu_online(cpu) || c->hotpluggable) { register_cpu(c, cpu); sysdev_create_file(&c->sysdev, &attr_physical_id); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 1f745f12f94e..7fd095efaebd 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -104,8 +104,8 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL); /* * register_cpu - Setup a driverfs device for a CPU. - * @cpu - Callers can set the cpu->no_control field to 1, to indicate not to - * generate a control file in sysfs for this CPU. + * @cpu - cpu->hotpluggable field set to 1 will generate a control file in + * sysfs for this CPU. * @num - CPU number to use when creating the device. * * Initialize and register the CPU device. @@ -119,7 +119,7 @@ int __devinit register_cpu(struct cpu *cpu, int num) error = sysdev_register(&cpu->sysdev); - if (!error && !cpu->no_control) + if (!error && cpu->hotpluggable) register_cpu_control(cpu); if (!error) cpu_sys_devices[num] = &cpu->sysdev; diff --git a/include/linux/cpu.h b/include/linux/cpu.h index f02d71bf6894..ad90340e7dba 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -27,7 +27,7 @@ struct cpu { int node_id; /* The node which contains the CPU */ - int no_control; /* Should the sysfs control file be created? */ + int hotpluggable; /* creates sysfs control file if hotpluggable */ struct sys_device sysdev; }; -- cgit v1.2.3 From e1cccf48b182dd743c3c83a4fdf8dc570a43b393 Mon Sep 17 00:00:00 2001 From: Artiom Myaskouvskey Date: Thu, 7 Dec 2006 02:14:11 +0100 Subject: [PATCH] i386: call efi_get_time during suspend Function efi_get_time called not only during init kernel phase but also during suspend (from get_cmos_time). When it is called from get_cmos_time the corresponding runtime service should be called in virtual and not in physical mode. Signed-off-by: Artiom Myaskouvskey Signed-off-by: Andi Kleen Cc: "Narayanan, Chandramouli" Cc: "Jiossy, Rami" Cc: "Satt, Shai" Cc: Andi Kleen Cc: Matt Domsch Signed-off-by: Andrew Morton --- arch/i386/kernel/efi.c | 17 ++++++++++++----- include/linux/efi.h | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c index 8b40648d0ef0..b92c7f0a358a 100644 --- a/arch/i386/kernel/efi.c +++ b/arch/i386/kernel/efi.c @@ -194,17 +194,24 @@ inline int efi_set_rtc_mmss(unsigned long nowtime) return 0; } /* - * This should only be used during kernel init and before runtime - * services have been remapped, therefore, we'll need to call in physical - * mode. Note, this call isn't used later, so mark it __init. + * This is used during kernel init before runtime + * services have been remapped and also during suspend, therefore, + * we'll need to call both in physical and virtual modes. */ -inline unsigned long __init efi_get_time(void) +inline unsigned long efi_get_time(void) { efi_status_t status; efi_time_t eft; efi_time_cap_t cap; - status = phys_efi_get_time(&eft, &cap); + if (efi.get_time) { + /* if we are in virtual mode use remapped function */ + status = efi.get_time(&eft, &cap); + } else { + /* we are in physical mode */ + status = phys_efi_get_time(&eft, &cap); + } + if (status != EFI_SUCCESS) printk("Oops: efitime: can't read time status: 0x%lx\n",status); diff --git a/include/linux/efi.h b/include/linux/efi.h index 66d621dbcb6c..91ecf49fbf21 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -300,7 +300,7 @@ extern int efi_mem_attribute_range (unsigned long phys_addr, unsigned long size, extern int __init efi_uart_console_only (void); extern void efi_initialize_iomem_resources(struct resource *code_resource, struct resource *data_resource); -extern unsigned long __init efi_get_time(void); +extern unsigned long efi_get_time(void); extern int __init efi_set_rtc_mmss(unsigned long nowtime); extern struct efi_memory_map memmap; -- cgit v1.2.3 From bf7e6a196318316e921f357557fca9d11d15f486 Mon Sep 17 00:00:00 2001 From: Artiom Myaskouvskey Date: Thu, 7 Dec 2006 02:14:11 +0100 Subject: [PATCH] i386: Preserve EFI run time regions with memmap parameter When using memmap kernel parameter in EFI boot we should also add to memory map memory regions of runtime services to enable their mapping later. AK: merged and cleaned up the patch Signed-off-by: Artiom Myaskouvskey Signed-off-by: Andi Kleen --- arch/i386/kernel/e820.c | 60 +++++++++++++++++++++++++++++++++++-------------- arch/i386/mm/init.c | 2 -- include/linux/efi.h | 1 + 3 files changed, 44 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/e820.c b/arch/i386/kernel/e820.c index b704790f7969..2f7d0a92fd7c 100644 --- a/arch/i386/kernel/e820.c +++ b/arch/i386/kernel/e820.c @@ -742,29 +742,55 @@ void __init print_memory_map(char *who) } } -void __init limit_regions(unsigned long long size) +static __init __always_inline void efi_limit_regions(unsigned long long size) { unsigned long long current_addr = 0; + efi_memory_desc_t *md, *next_md; + void *p, *p1; + int i, j; + + j = 0; + p1 = memmap.map; + for (p = p1, i = 0; p < memmap.map_end; p += memmap.desc_size, i++) { + md = p; + next_md = p1; + current_addr = md->phys_addr + + PFN_PHYS(md->num_pages); + if (is_available_memory(md)) { + if (md->phys_addr >= size) continue; + memcpy(next_md, md, memmap.desc_size); + if (current_addr >= size) { + next_md->num_pages -= + PFN_UP(current_addr-size); + } + p1 += memmap.desc_size; + next_md = p1; + j++; + } else if ((md->attribute & EFI_MEMORY_RUNTIME) == + EFI_MEMORY_RUNTIME) { + /* In order to make runtime services + * available we have to include runtime + * memory regions in memory map */ + memcpy(next_md, md, memmap.desc_size); + p1 += memmap.desc_size; + next_md = p1; + j++; + } + } + memmap.nr_map = j; + memmap.map_end = memmap.map + + (memmap.nr_map * memmap.desc_size); +} + +void __init limit_regions(unsigned long long size) +{ + unsigned long long current_addr; int i; print_memory_map("limit_regions start"); if (efi_enabled) { - efi_memory_desc_t *md; - void *p; - - for (p = memmap.map, i = 0; p < memmap.map_end; - p += memmap.desc_size, i++) { - md = p; - current_addr = md->phys_addr + (md->num_pages << 12); - if (md->type == EFI_CONVENTIONAL_MEMORY) { - if (current_addr >= size) { - md->num_pages -= - (((current_addr-size) + PAGE_SIZE-1) >> PAGE_SHIFT); - memmap.nr_map = i + 1; - return; - } - } - } + efi_limit_regions(size); + return; } for (i = 0; i < e820.nr_map; i++) { current_addr = e820.map[i].addr + e820.map[i].size; diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 167416155ee4..f4dd048187ff 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -192,8 +192,6 @@ static inline int page_kills_ppro(unsigned long pagenr) return 0; } -extern int is_available_memory(efi_memory_desc_t *); - int page_is_ram(unsigned long pagenr) { int i; diff --git a/include/linux/efi.h b/include/linux/efi.h index 91ecf49fbf21..df1c91855f0e 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -302,6 +302,7 @@ extern void efi_initialize_iomem_resources(struct resource *code_resource, struct resource *data_resource); extern unsigned long efi_get_time(void); extern int __init efi_set_rtc_mmss(unsigned long nowtime); +extern int is_available_memory(efi_memory_desc_t * md); extern struct efi_memory_map memmap; /** -- cgit v1.2.3 From 334c29a64507dda187565dd0db0403de3d70ec8b Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Mon, 4 Dec 2006 19:31:51 -0800 Subject: [GENETLINK]: Move command capabilities to flags. This patch moves command capabilities to command flags. Other than being cleaner, saves several bytes. We increment the nlctrl version so as to signal to user space that to not expect the attributes. We will try to be careful not to do this too often ;-> Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/linux/genetlink.h | 6 +++--- net/netlink/genetlink.c | 18 ++++++++---------- 2 files changed, 11 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h index 9049dc65ae51..f7a93770e1be 100644 --- a/include/linux/genetlink.h +++ b/include/linux/genetlink.h @@ -17,6 +17,9 @@ struct genlmsghdr { #define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) #define GENL_ADMIN_PERM 0x01 +#define GENL_CMD_CAP_DO 0x02 +#define GENL_CMD_CAP_DUMP 0x04 +#define GENL_CMD_CAP_HASPOL 0x08 /* * List of reserved static generic netlink identifiers: @@ -58,9 +61,6 @@ enum { CTRL_ATTR_OP_UNSPEC, CTRL_ATTR_OP_ID, CTRL_ATTR_OP_FLAGS, - CTRL_ATTR_OP_POLICY, - CTRL_ATTR_OP_DOIT, - CTRL_ATTR_OP_DUMPIT, __CTRL_ATTR_OP_MAX, }; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index b9b03747c1f3..b5df749cba8f 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -143,6 +143,13 @@ int genl_register_ops(struct genl_family *family, struct genl_ops *ops) goto errout; } + if (ops->dumpit) + ops->flags |= GENL_CMD_CAP_DO; + if (ops->doit) + ops->flags |= GENL_CMD_CAP_DUMP; + if (ops->policy) + ops->flags |= GENL_CMD_CAP_HASPOL; + genl_lock(); list_add_tail(&ops->ops_list, &family->ops_list); genl_unlock(); @@ -387,7 +394,7 @@ static void genl_rcv(struct sock *sk, int len) static struct genl_family genl_ctrl = { .id = GENL_ID_CTRL, .name = "nlctrl", - .version = 0x1, + .version = 0x2, .maxattr = CTRL_ATTR_MAX, }; @@ -425,15 +432,6 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd); NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags); - if (ops->policy) - NLA_PUT_FLAG(skb, CTRL_ATTR_OP_POLICY); - - if (ops->doit) - NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DOIT); - - if (ops->dumpit) - NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DUMPIT); - nla_nest_end(skb, nest); } -- cgit v1.2.3 From 7cf4c1a5fd13820d7591179c0b925d739b2be9a7 Mon Sep 17 00:00:00 2001 From: Kazunori MIYAZAWA Date: Sat, 28 Oct 2006 13:21:22 +1000 Subject: [IPSEC]: Add support for AES-XCBC-MAC The glue of xfrm. Signed-off-by: Kazunori MIYAZAWA Signed-off-by: Herbert Xu --- include/linux/pfkeyv2.h | 1 + net/xfrm/xfrm_algo.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index 0f0b880c4280..265bafab6494 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -285,6 +285,7 @@ struct sadb_x_sec_ctx { #define SADB_X_AALG_SHA2_384HMAC 6 #define SADB_X_AALG_SHA2_512HMAC 7 #define SADB_X_AALG_RIPEMD160HMAC 8 +#define SADB_X_AALG_AES_XCBC_MAC 9 #define SADB_X_AALG_NULL 251 /* kame */ #define SADB_AALG_MAX 251 diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 5a0dbeb6bbe8..6b381fc0383d 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -119,6 +119,23 @@ static struct xfrm_algo_desc aalg_list[] = { .sadb_alg_maxbits = 160 } }, +{ + .name = "xcbc(aes)", + + .uinfo = { + .auth = { + .icv_truncbits = 96, + .icv_fullbits = 128, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_AALG_AES_XCBC_MAC, + .sadb_alg_ivlen = 0, + .sadb_alg_minbits = 128, + .sadb_alg_maxbits = 128 + } +}, }; static struct xfrm_algo_desc ealg_list[] = { -- cgit v1.2.3 From cc44215eaaa5e4032946b962353526ae6c370c0e Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 22 Nov 2006 17:55:00 +1100 Subject: [CRYPTO] api: Remove unused functions This patch removes the following no longer used functions: - api.c: crypto_alg_available() - digest.c: crypto_digest_init() - digest.c: crypto_digest_update() - digest.c: crypto_digest_final() - digest.c: crypto_digest_digest() Signed-off-by: Adrian Bunk Signed-off-by: Herbert Xu --- crypto/api.c | 15 --------------- crypto/digest.c | 48 ------------------------------------------------ include/linux/crypto.h | 22 ---------------------- 3 files changed, 85 deletions(-) (limited to 'include/linux') diff --git a/crypto/api.c b/crypto/api.c index 4fb7fa45cb0d..8c446871cd5b 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -466,23 +466,8 @@ void crypto_free_tfm(struct crypto_tfm *tfm) kfree(tfm); } -int crypto_alg_available(const char *name, u32 flags) -{ - int ret = 0; - struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, - CRYPTO_ALG_ASYNC); - - if (!IS_ERR(alg)) { - crypto_mod_put(alg); - ret = 1; - } - - return ret; -} - EXPORT_SYMBOL_GPL(crypto_alloc_tfm); EXPORT_SYMBOL_GPL(crypto_free_tfm); -EXPORT_SYMBOL_GPL(crypto_alg_available); int crypto_has_alg(const char *name, u32 type, u32 mask) { diff --git a/crypto/digest.c b/crypto/digest.c index 0155a94e4b15..8f4593268ce0 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -21,54 +21,6 @@ #include "internal.h" #include "scatterwalk.h" -void crypto_digest_init(struct crypto_tfm *tfm) -{ - struct crypto_hash *hash = crypto_hash_cast(tfm); - struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags }; - - crypto_hash_init(&desc); -} -EXPORT_SYMBOL_GPL(crypto_digest_init); - -void crypto_digest_update(struct crypto_tfm *tfm, - struct scatterlist *sg, unsigned int nsg) -{ - struct crypto_hash *hash = crypto_hash_cast(tfm); - struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags }; - unsigned int nbytes = 0; - unsigned int i; - - for (i = 0; i < nsg; i++) - nbytes += sg[i].length; - - crypto_hash_update(&desc, sg, nbytes); -} -EXPORT_SYMBOL_GPL(crypto_digest_update); - -void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) -{ - struct crypto_hash *hash = crypto_hash_cast(tfm); - struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags }; - - crypto_hash_final(&desc, out); -} -EXPORT_SYMBOL_GPL(crypto_digest_final); - -void crypto_digest_digest(struct crypto_tfm *tfm, - struct scatterlist *sg, unsigned int nsg, u8 *out) -{ - struct crypto_hash *hash = crypto_hash_cast(tfm); - struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags }; - unsigned int nbytes = 0; - unsigned int i; - - for (i = 0; i < nsg; i++) - nbytes += sg[i].length; - - crypto_hash_digest(&desc, sg, nbytes, out); -} -EXPORT_SYMBOL_GPL(crypto_digest_digest); - static int init(struct hash_desc *desc) { struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 6485e9716b36..4aa9046601da 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -241,12 +241,8 @@ int crypto_unregister_alg(struct crypto_alg *alg); * Algorithm query interface. */ #ifdef CONFIG_CRYPTO -int crypto_alg_available(const char *name, u32 flags) - __deprecated_for_modules; int crypto_has_alg(const char *name, u32 type, u32 mask); #else -static int crypto_alg_available(const char *name, u32 flags) - __deprecated_for_modules; static inline int crypto_alg_available(const char *name, u32 flags) { return 0; @@ -707,16 +703,6 @@ static inline void crypto_cipher_decrypt_one(struct crypto_cipher *tfm, dst, src); } -void crypto_digest_init(struct crypto_tfm *tfm) __deprecated_for_modules; -void crypto_digest_update(struct crypto_tfm *tfm, - struct scatterlist *sg, unsigned int nsg) - __deprecated_for_modules; -void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) - __deprecated_for_modules; -void crypto_digest_digest(struct crypto_tfm *tfm, - struct scatterlist *sg, unsigned int nsg, u8 *out) - __deprecated_for_modules; - static inline struct crypto_hash *__crypto_hash_cast(struct crypto_tfm *tfm) { return (struct crypto_hash *)tfm; @@ -729,14 +715,6 @@ static inline struct crypto_hash *crypto_hash_cast(struct crypto_tfm *tfm) return __crypto_hash_cast(tfm); } -static int crypto_digest_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) __deprecated; -static inline int crypto_digest_setkey(struct crypto_tfm *tfm, - const u8 *key, unsigned int keylen) -{ - return tfm->crt_hash.setkey(crypto_hash_cast(tfm), key, keylen); -} - static inline struct crypto_hash *crypto_alloc_hash(const char *alg_name, u32 type, u32 mask) { -- cgit v1.2.3 From 9ee0779e994c6916863045297b831212e285da3b Mon Sep 17 00:00:00 2001 From: Yasuyuki Kozakai Date: Tue, 5 Dec 2006 13:44:31 -0800 Subject: [NETFILTER]: nf_conntrack: fix warning in PPTP helper Signed-off-by: Yasuyuki Kozakai Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_pptp.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_pptp.h b/include/linux/netfilter/nf_conntrack_pptp.h index fb049ec11ff2..9d8144a488cd 100644 --- a/include/linux/netfilter/nf_conntrack_pptp.h +++ b/include/linux/netfilter/nf_conntrack_pptp.h @@ -2,6 +2,8 @@ #ifndef _NF_CONNTRACK_PPTP_H #define _NF_CONNTRACK_PPTP_H +#include + /* state of the control session */ enum pptp_ctrlsess_state { PPTP_SESSION_NONE, /* no session present */ @@ -295,7 +297,6 @@ union pptp_ctrl_union { /* crap needed for nf_conntrack_compat.h */ struct nf_conn; struct nf_conntrack_expect; -enum ip_conntrack_info; extern int (*nf_nat_pptp_hook_outbound)(struct sk_buff **pskb, -- cgit v1.2.3 From 161a09e737f0761ca064ee6a907313402f7a54b6 Mon Sep 17 00:00:00 2001 From: Joy Latten Date: Mon, 27 Nov 2006 13:11:54 -0600 Subject: audit: Add auditing to ipsec An audit message occurs when an ipsec SA or ipsec policy is created/deleted. Signed-off-by: Joy Latten Signed-off-by: James Morris Signed-off-by: David S. Miller --- include/linux/audit.h | 6 +++ include/net/xfrm.h | 19 +++++--- kernel/auditsc.c | 6 ++- net/key/af_key.c | 27 +++++++++-- net/xfrm/xfrm_policy.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++- net/xfrm/xfrm_state.c | 17 ++++++- net/xfrm/xfrm_user.c | 33 ++++++++++++-- 7 files changed, 213 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/audit.h b/include/linux/audit.h index b2ca666d9997..0e07db6cc0d0 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -101,6 +101,10 @@ #define AUDIT_MAC_CIPSOV4_DEL 1408 /* NetLabel: del CIPSOv4 DOI entry */ #define AUDIT_MAC_MAP_ADD 1409 /* NetLabel: add LSM domain mapping */ #define AUDIT_MAC_MAP_DEL 1410 /* NetLabel: del LSM domain mapping */ +#define AUDIT_MAC_IPSEC_ADDSA 1411 /* Add a XFRM state */ +#define AUDIT_MAC_IPSEC_DELSA 1412 /* Delete a XFRM state */ +#define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Add a XFRM policy */ +#define AUDIT_MAC_IPSEC_DELSPD 1414 /* Delete a XFRM policy */ #define AUDIT_FIRST_KERN_ANOM_MSG 1700 #define AUDIT_LAST_KERN_ANOM_MSG 1799 @@ -377,6 +381,7 @@ extern void auditsc_get_stamp(struct audit_context *ctx, struct timespec *t, unsigned int *serial); extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); extern uid_t audit_get_loginuid(struct audit_context *ctx); +extern void audit_log_task_context(struct audit_buffer *ab); extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp); extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); extern int audit_bprm(struct linux_binprm *bprm); @@ -449,6 +454,7 @@ extern int audit_n_rules; #define audit_inode_update(i) do { ; } while (0) #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) #define audit_get_loginuid(c) ({ -1; }) +#define audit_log_task_context(b) do { ; } while (0) #define audit_ipc_obj(i) ({ 0; }) #define audit_ipc_set_perm(q,u,g,m) ({ 0; }) #define audit_bprm(p) ({ 0; }) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 15ec19dcf9c8..f699cdcab406 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -392,6 +392,15 @@ extern int xfrm_unregister_km(struct xfrm_mgr *km); extern unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; +/* Audit Information */ +struct xfrm_audit +{ + uid_t loginuid; + u32 secid; +}; +void xfrm_audit_log(uid_t auid, u32 secid, int type, int result, + struct xfrm_policy *xp, struct xfrm_state *x); + static inline void xfrm_pol_hold(struct xfrm_policy *policy) { if (likely(policy != NULL)) @@ -906,7 +915,7 @@ static inline int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **s #endif extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); extern int xfrm_state_delete(struct xfrm_state *x); -extern void xfrm_state_flush(u8 proto); +extern void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info); extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq); extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq); extern void xfrm_replay_notify(struct xfrm_state *x, int event); @@ -959,13 +968,13 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, struct xfrm_selector *sel, struct xfrm_sec_ctx *ctx, int delete); struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete); -void xfrm_policy_flush(u8 type); +void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info); u32 xfrm_get_acqseq(void); void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi); -struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, - xfrm_address_t *daddr, xfrm_address_t *saddr, +struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, + xfrm_address_t *daddr, xfrm_address_t *saddr, int create, unsigned short family); -extern void xfrm_policy_flush(u8 type); +extern void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info); extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst, struct flowi *fl, int family, int strict); diff --git a/kernel/auditsc.c b/kernel/auditsc.c index ab97e5101232..40722e26de98 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -731,7 +731,7 @@ static inline void audit_free_context(struct audit_context *context) printk(KERN_ERR "audit: freed %d contexts\n", count); } -static void audit_log_task_context(struct audit_buffer *ab) +void audit_log_task_context(struct audit_buffer *ab) { char *ctx = NULL; ssize_t len = 0; @@ -760,6 +760,8 @@ error_path: return; } +EXPORT_SYMBOL(audit_log_task_context); + static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk) { char name[sizeof(tsk->comm)]; @@ -1488,6 +1490,8 @@ uid_t audit_get_loginuid(struct audit_context *ctx) return ctx ? ctx->loginuid : -1; } +EXPORT_SYMBOL(audit_get_loginuid); + /** * __audit_mq_open - record audit data for a POSIX MQ open * @oflag: open flag diff --git a/net/key/af_key.c b/net/key/af_key.c index 0e1dbfbb9b10..5dd5094659a1 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -1420,6 +1421,9 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, else err = xfrm_state_update(x); + xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, + AUDIT_MAC_IPSEC_ADDSA, err ? 0 : 1, NULL, x); + if (err < 0) { x->km.state = XFRM_STATE_DEAD; __xfrm_state_put(x); @@ -1460,8 +1464,12 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h err = -EPERM; goto out; } - + err = xfrm_state_delete(x); + + xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, + AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x); + if (err < 0) goto out; @@ -1637,12 +1645,15 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd { unsigned proto; struct km_event c; + struct xfrm_audit audit_info; proto = pfkey_satype2proto(hdr->sadb_msg_satype); if (proto == 0) return -EINVAL; - xfrm_state_flush(proto); + audit_info.loginuid = audit_get_loginuid(current->audit_context); + audit_info.secid = 0; + xfrm_state_flush(proto, &audit_info); c.data.proto = proto; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; @@ -2205,6 +2216,9 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, hdr->sadb_msg_type != SADB_X_SPDUPDATE); + xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, + AUDIT_MAC_IPSEC_ADDSPD, err ? 0 : 1, xp, NULL); + if (err) goto out; @@ -2282,6 +2296,10 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1, &sel, tmp.security, 1); security_xfrm_policy_free(&tmp); + + xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, + AUDIT_MAC_IPSEC_DELSPD, (xp) ? 1 : 0, xp, NULL); + if (xp == NULL) return -ENOENT; @@ -2416,8 +2434,11 @@ static int key_notify_policy_flush(struct km_event *c) static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { struct km_event c; + struct xfrm_audit audit_info; - xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN); + audit_info.loginuid = audit_get_loginuid(current->audit_context); + audit_info.secid = 0; + xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info); c.data.type = XFRM_POLICY_TYPE_MAIN; c.event = XFRM_MSG_FLUSHPOLICY; c.pid = hdr->sadb_msg_pid; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 4f04222698d9..47c13649bac1 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "xfrm_hash.h" @@ -804,7 +805,7 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete) } EXPORT_SYMBOL(xfrm_policy_byid); -void xfrm_policy_flush(u8 type) +void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) { int dir; @@ -824,6 +825,9 @@ void xfrm_policy_flush(u8 type) hlist_del(&pol->byidx); write_unlock_bh(&xfrm_policy_lock); + xfrm_audit_log(audit_info->loginuid, audit_info->secid, + AUDIT_MAC_IPSEC_DELSPD, 1, pol, NULL); + xfrm_policy_kill(pol); killed++; @@ -842,6 +846,11 @@ void xfrm_policy_flush(u8 type) hlist_del(&pol->byidx); write_unlock_bh(&xfrm_policy_lock); + xfrm_audit_log(audit_info->loginuid, + audit_info->secid, + AUDIT_MAC_IPSEC_DELSPD, 1, + pol, NULL); + xfrm_policy_kill(pol); killed++; @@ -1977,6 +1986,115 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, EXPORT_SYMBOL(xfrm_bundle_ok); +/* Audit addition and deletion of SAs and ipsec policy */ + +void xfrm_audit_log(uid_t auid, u32 sid, int type, int result, + struct xfrm_policy *xp, struct xfrm_state *x) +{ + + char *secctx; + u32 secctx_len; + struct xfrm_sec_ctx *sctx = NULL; + struct audit_buffer *audit_buf; + int family; + extern int audit_enabled; + + if (audit_enabled == 0) + return; + + audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC, type); + if (audit_buf == NULL) + return; + + switch(type) { + case AUDIT_MAC_IPSEC_ADDSA: + audit_log_format(audit_buf, "SAD add: auid=%u", auid); + break; + case AUDIT_MAC_IPSEC_DELSA: + audit_log_format(audit_buf, "SAD delete: auid=%u", auid); + break; + case AUDIT_MAC_IPSEC_ADDSPD: + audit_log_format(audit_buf, "SPD add: auid=%u", auid); + break; + case AUDIT_MAC_IPSEC_DELSPD: + audit_log_format(audit_buf, "SPD delete: auid=%u", auid); + break; + default: + return; + } + + if (sid != 0 && + security_secid_to_secctx(sid, &secctx, &secctx_len) == 0) + audit_log_format(audit_buf, " subj=%s", secctx); + else + audit_log_task_context(audit_buf); + + if (xp) { + family = xp->selector.family; + if (xp->security) + sctx = xp->security; + } else { + family = x->props.family; + if (x->security) + sctx = x->security; + } + + if (sctx) + audit_log_format(audit_buf, + " sec_alg=%u sec_doi=%u sec_obj=%s", + sctx->ctx_alg, sctx->ctx_doi, sctx->ctx_str); + + switch(family) { + case AF_INET: + { + struct in_addr saddr, daddr; + if (xp) { + saddr.s_addr = xp->selector.saddr.a4; + daddr.s_addr = xp->selector.daddr.a4; + } else { + saddr.s_addr = x->props.saddr.a4; + daddr.s_addr = x->id.daddr.a4; + } + audit_log_format(audit_buf, + " src=%u.%u.%u.%u dst=%u.%u.%u.%u", + NIPQUAD(saddr), NIPQUAD(daddr)); + } + break; + case AF_INET6: + { + struct in6_addr saddr6, daddr6; + if (xp) { + memcpy(&saddr6, xp->selector.saddr.a6, + sizeof(struct in6_addr)); + memcpy(&daddr6, xp->selector.daddr.a6, + sizeof(struct in6_addr)); + } else { + memcpy(&saddr6, x->props.saddr.a6, + sizeof(struct in6_addr)); + memcpy(&daddr6, x->id.daddr.a6, + sizeof(struct in6_addr)); + } + audit_log_format(audit_buf, + " src=" NIP6_FMT "dst=" NIP6_FMT, + NIP6(saddr6), NIP6(daddr6)); + } + break; + } + + if (x) + audit_log_format(audit_buf, " spi=%lu(0x%lx) protocol=%s", + (unsigned long)ntohl(x->id.spi), + (unsigned long)ntohl(x->id.spi), + x->id.proto == IPPROTO_AH ? "AH" : + (x->id.proto == IPPROTO_ESP ? + "ESP" : "IPCOMP")); + + audit_log_format(audit_buf, " res=%u", result); + audit_log_end(audit_buf); +} + +EXPORT_SYMBOL(xfrm_audit_log); + int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) { int err = 0; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index a14c88bf17f0..d5d3a6f1f609 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "xfrm_hash.h" @@ -238,6 +239,7 @@ static void xfrm_timer_handler(unsigned long data) unsigned long now = (unsigned long)xtime.tv_sec; long next = LONG_MAX; int warn = 0; + int err = 0; spin_lock(&x->lock); if (x->km.state == XFRM_STATE_DEAD) @@ -295,9 +297,14 @@ expired: next = 2; goto resched; } - if (!__xfrm_state_delete(x) && x->id.spi) + + err = __xfrm_state_delete(x); + if (!err && x->id.spi) km_state_expired(x, 1, 0); + xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, + AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x); + out: spin_unlock(&x->lock); } @@ -384,9 +391,10 @@ int xfrm_state_delete(struct xfrm_state *x) } EXPORT_SYMBOL(xfrm_state_delete); -void xfrm_state_flush(u8 proto) +void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) { int i; + int err = 0; spin_lock_bh(&xfrm_state_lock); for (i = 0; i <= xfrm_state_hmask; i++) { @@ -400,6 +408,11 @@ restart: spin_unlock_bh(&xfrm_state_lock); xfrm_state_delete(x); + err = xfrm_state_delete(x); + xfrm_audit_log(audit_info->loginuid, + audit_info->secid, + AUDIT_MAC_IPSEC_DELSA, + err ? 0 : 1, NULL, x); xfrm_state_put(x); spin_lock_bh(&xfrm_state_lock); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 311205ffa775..e5372b11fc8f 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -31,6 +31,7 @@ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #include #endif +#include static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) { @@ -454,6 +455,9 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) else err = xfrm_state_update(x); + xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, + AUDIT_MAC_IPSEC_ADDSA, err ? 0 : 1, NULL, x); + if (err < 0) { x->km.state = XFRM_STATE_DEAD; __xfrm_state_put(x); @@ -523,6 +527,10 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) } err = xfrm_state_delete(x); + + xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, + AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x); + if (err < 0) goto out; @@ -1030,6 +1038,9 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr * a type XFRM_MSG_UPDPOLICY - JHS */ excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; err = xfrm_policy_insert(p->dir, xp, excl); + xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, + AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL); + if (err) { security_xfrm_policy_free(xp); kfree(xp); @@ -1257,6 +1268,10 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, delete); security_xfrm_policy_free(&tmp); } + if (delete) + xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, + AUDIT_MAC_IPSEC_DELSPD, (xp) ? 1 : 0, xp, NULL); + if (xp == NULL) return -ENOENT; @@ -1291,8 +1306,11 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma { struct km_event c; struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); + struct xfrm_audit audit_info; - xfrm_state_flush(p->proto); + audit_info.loginuid = NETLINK_CB(skb).loginuid; + audit_info.secid = NETLINK_CB(skb).sid; + xfrm_state_flush(p->proto, &audit_info); c.data.proto = p->proto; c.event = nlh->nlmsg_type; c.seq = nlh->nlmsg_seq; @@ -1442,12 +1460,15 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **x struct km_event c; u8 type = XFRM_POLICY_TYPE_MAIN; int err; + struct xfrm_audit audit_info; err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); if (err) return err; - xfrm_policy_flush(type); + audit_info.loginuid = NETLINK_CB(skb).loginuid; + audit_info.secid = NETLINK_CB(skb).sid; + xfrm_policy_flush(type, &audit_info); c.data.type = type; c.event = nlh->nlmsg_type; c.seq = nlh->nlmsg_seq; @@ -1502,6 +1523,9 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * err = 0; if (up->hard) { xfrm_policy_delete(xp, p->dir); + xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, + AUDIT_MAC_IPSEC_DELSPD, 1, xp, NULL); + } else { // reset the timers here? printk("Dont know what to do with soft policy expire\n"); @@ -1533,8 +1557,11 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void ** goto out; km_state_expired(x, ue->hard, current->pid); - if (ue->hard) + if (ue->hard) { __xfrm_state_delete(x); + xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, + AUDIT_MAC_IPSEC_DELSA, 1, NULL, x); + } out: spin_unlock_bh(&x->lock); xfrm_state_put(x); -- cgit v1.2.3 From 676917d488212303ce4a7d033815ce8799201010 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 7 Dec 2006 00:20:22 -0800 Subject: [TG3]: Add 5787F device ID. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 +++- include/linux/pci_ids.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e6561c1d85d6..5514828b7929 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -192,6 +192,7 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787F)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715)}, @@ -10859,7 +10860,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) || (tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM && (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F || - tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)) || + tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F || + tp->pdev->device == PCI_DEVICE_ID_TIGON3_5787F)) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->tg3_flags |= TG3_FLAG_10_100_ONLY; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c09da1e30c54..edddcce68b94 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1931,6 +1931,7 @@ #define PCI_DEVICE_ID_TIGON3_5750M 0x167c #define PCI_DEVICE_ID_TIGON3_5751M 0x167d #define PCI_DEVICE_ID_TIGON3_5751F 0x167e +#define PCI_DEVICE_ID_TIGON3_5787F 0x167f #define PCI_DEVICE_ID_TIGON3_5787M 0x1693 #define PCI_DEVICE_ID_TIGON3_5782 0x1696 #define PCI_DEVICE_ID_TIGON3_5786 0x169a -- cgit v1.2.3 From 9d26e213423923c9e033ccd373705118131827c9 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 7 Dec 2006 00:21:14 -0800 Subject: [TG3]: Add TG3_FLG2_IS_NIC flag. Add Tg3_FLG2_IS_NIC flag to unambiguously determine whether the device is NIC or onboard. Previously, the EEPROM_WRITE_PROT flag was overloaded to also mean onboard. With the separation, we can support some devices that are onboard but do not use eeprom write protect. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 37 ++++++++++++++++++++++++------------- drivers/net/tg3.h | 1 + include/linux/pci_ids.h | 2 ++ 3 files changed, 27 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5514828b7929..16bc05fe531f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1062,7 +1062,7 @@ static void tg3_frob_aux_power(struct tg3 *tp) { struct tg3 *tp_peer = tp; - if ((tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) != 0) + if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0) return; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || @@ -1213,8 +1213,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) power_control); udelay(100); /* Delay after power state change */ - /* Switch out of Vaux if it is not a LOM */ - if (!(tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT)) + /* Switch out of Vaux if it is a NIC */ + if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl, 100); return 0; @@ -6397,16 +6397,17 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(40); /* tp->grc_local_ctrl is partially set up during tg3_get_invariants(). - * If TG3_FLAG_EEPROM_WRITE_PROT is set, we should read the + * If TG3_FLG2_IS_NIC is zero, we should read the * register to preserve the GPIO settings for LOMs. The GPIOs, * whether used as inputs or outputs, are set by boot code after * reset. */ - if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { + if (!(tp->tg3_flags2 & TG3_FLG2_IS_NIC)) { u32 gpio_mask; - gpio_mask = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE2 | - GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT2; + gpio_mask = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 | + GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_GPIO_OUTPUT2; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) gpio_mask |= GRC_LCLCTRL_GPIO_OE3 | @@ -6418,8 +6419,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask; /* GPIO1 must be driven high for eeprom write protect */ - tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | - GRC_LCLCTRL_GPIO_OUTPUT1); + if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) + tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OUTPUT1); } tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); @@ -9963,8 +9965,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM)) + if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM)) { tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; + tp->tg3_flags2 |= TG3_FLG2_IS_NIC; + } return; } @@ -10064,10 +10068,17 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL) tp->led_ctrl = LED_CTRL_MODE_PHY_2; - if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) + if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) { tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; - else + if ((tp->pdev->subsystem_vendor == + PCI_VENDOR_ID_ARIMA) && + (tp->pdev->subsystem_device == 0x205a || + tp->pdev->subsystem_device == 0x2063)) + tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; + } else { tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; + tp->tg3_flags2 |= TG3_FLG2_IS_NIC; + } if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; @@ -10693,7 +10704,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; /* Get eeprom hw config before calling tg3_set_power_state(). - * In particular, the TG3_FLAG_EEPROM_WRITE_PROT flag must be + * In particular, the TG3_FLG2_IS_NIC flag must be * determined before calling tg3_set_power_state() so that * we know whether or not to switch out of Vaux power. * When the flag is set, it means that GPIO1 is used for eeprom diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 92f53000bce6..dfaf4ed127bd 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2233,6 +2233,7 @@ struct tg3 { #define TG3_FLG2_PCI_EXPRESS 0x00000200 #define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400 #define TG3_FLG2_HW_AUTONEG 0x00000800 +#define TG3_FLG2_IS_NIC 0x00001000 #define TG3_FLG2_PHY_SERDES 0x00002000 #define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000 #define TG3_FLG2_FLASH 0x00008000 diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index edddcce68b94..ebc597d57242 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2003,6 +2003,8 @@ #define PCI_DEVICE_ID_FARSITE_TE1 0x1610 #define PCI_DEVICE_ID_FARSITE_TE1C 0x1612 +#define PCI_VENDOR_ID_ARIMA 0x161f + #define PCI_VENDOR_ID_SIBYTE 0x166d #define PCI_DEVICE_ID_BCM1250_PCI 0x0001 #define PCI_DEVICE_ID_BCM1250_HT 0x0002 -- cgit v1.2.3 From 676dcb8bc2ec78d80091037773598d6ec8c673d6 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 6 Dec 2006 20:31:30 -0800 Subject: [PATCH] add bottom_half.h With CONFIG_SMP=n: drivers/input/ff-memless.c:384: warning: implicit declaration of function 'local_bh_disable' drivers/input/ff-memless.c:393: warning: implicit declaration of function 'local_bh_enable' Really linux/spinlock.h should include linux/interrupt.h. But interrupt.h includes sched.h which will need spinlock.h. So the patch breaks the _bh declarations out into a separate header and includes it in both interrupt.h and spinlock.h. Cc: "Randy.Dunlap" Cc: Andi Kleen Cc: Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/bottom_half.h | 10 ++++++++++ include/linux/interrupt.h | 7 +------ include/linux/spinlock.h | 1 + 3 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 include/linux/bottom_half.h (limited to 'include/linux') diff --git a/include/linux/bottom_half.h b/include/linux/bottom_half.h new file mode 100644 index 000000000000..777dbf695d44 --- /dev/null +++ b/include/linux/bottom_half.h @@ -0,0 +1,10 @@ +#ifndef _LINUX_BH_H +#define _LINUX_BH_H + +extern void local_bh_disable(void); +extern void __local_bh_enable(void); +extern void _local_bh_enable(void); +extern void local_bh_enable(void); +extern void local_bh_enable_ip(unsigned long ip); + +#endif /* _LINUX_BH_H */ diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 5b83e7b59621..de7593f4e895 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -217,12 +218,6 @@ static inline void __deprecated save_and_cli(unsigned long *x) #define save_and_cli(x) save_and_cli(&x) #endif /* CONFIG_SMP */ -extern void local_bh_disable(void); -extern void __local_bh_enable(void); -extern void _local_bh_enable(void); -extern void local_bh_enable(void); -extern void local_bh_enable_ip(unsigned long ip); - /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high frequency threaded job scheduling. For almost all the purposes tasklets are more than enough. F.e. all serial device BHs et diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 8451052ca66f..94b767d64275 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -52,6 +52,7 @@ #include #include #include +#include #include -- cgit v1.2.3 From 89689ae7f95995723fbcd5c116c47933a3bb8b13 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:31:45 -0800 Subject: [PATCH] Get rid of zone_table[] The zone table is mostly not needed. If we have a node in the page flags then we can get to the zone via NODE_DATA() which is much more likely to be already in the cpu cache. In case of SMP and UP NODE_DATA() is a constant pointer which allows us to access an exact replica of zonetable in the node_zones field. In all of the above cases there will be no need at all for the zone table. The only remaining case is if in a NUMA system the node numbers do not fit into the page flags. In that case we make sparse generate a table that maps sections to nodes and use that table to to figure out the node number. This table is sized to fit in a single cache line for the known 32 bit NUMA platform which makes it very likely that the information can be obtained without a cache miss. For sparsemem the zone table seems to be have been fairly large based on the maximum possible number of sections and the number of zones per node. There is some memory saving by removing zone_table. The main benefit is to reduce the cache foootprint of the VM from the frequent lookups of zones. Plus it simplifies the page allocator. [akpm@osdl.org: build fix] Signed-off-by: Christoph Lameter Cc: Dave Hansen Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 57 +++++++++++++++++++++++++++++++++-------------------- mm/memory_hotplug.c | 1 - mm/page_alloc.c | 22 --------------------- mm/sparse.c | 23 +++++++++++++++++++++ 4 files changed, 59 insertions(+), 44 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index d538de901965..ab6e4974f379 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -396,7 +396,9 @@ void split_page(struct page *page, unsigned int order); * We are going to use the flags for the page to node mapping if its in * there. This includes the case where there is no node, so it is implicit. */ -#define FLAGS_HAS_NODE (NODES_WIDTH > 0 || NODES_SHIFT == 0) +#if !(NODES_WIDTH > 0 || NODES_SHIFT == 0) +#define NODE_NOT_IN_PAGE_FLAGS +#endif #ifndef PFN_SECTION_SHIFT #define PFN_SECTION_SHIFT 0 @@ -411,13 +413,18 @@ void split_page(struct page *page, unsigned int order); #define NODES_PGSHIFT (NODES_PGOFF * (NODES_WIDTH != 0)) #define ZONES_PGSHIFT (ZONES_PGOFF * (ZONES_WIDTH != 0)) -/* NODE:ZONE or SECTION:ZONE is used to lookup the zone from a page. */ -#if FLAGS_HAS_NODE -#define ZONETABLE_SHIFT (NODES_SHIFT + ZONES_SHIFT) +/* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allcator */ +#ifdef NODE_NOT_IN_PAGEFLAGS +#define ZONEID_SHIFT (SECTIONS_SHIFT + ZONES_SHIFT) #else -#define ZONETABLE_SHIFT (SECTIONS_SHIFT + ZONES_SHIFT) +#define ZONEID_SHIFT (NODES_SHIFT + ZONES_SHIFT) +#endif + +#if ZONES_WIDTH > 0 +#define ZONEID_PGSHIFT ZONES_PGSHIFT +#else +#define ZONEID_PGSHIFT NODES_PGOFF #endif -#define ZONETABLE_PGSHIFT ZONES_PGSHIFT #if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED #error SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED @@ -426,23 +433,25 @@ void split_page(struct page *page, unsigned int order); #define ZONES_MASK ((1UL << ZONES_WIDTH) - 1) #define NODES_MASK ((1UL << NODES_WIDTH) - 1) #define SECTIONS_MASK ((1UL << SECTIONS_WIDTH) - 1) -#define ZONETABLE_MASK ((1UL << ZONETABLE_SHIFT) - 1) +#define ZONEID_MASK ((1UL << ZONEID_SHIFT) - 1) static inline enum zone_type page_zonenum(struct page *page) { return (page->flags >> ZONES_PGSHIFT) & ZONES_MASK; } -struct zone; -extern struct zone *zone_table[]; - +/* + * The identification function is only used by the buddy allocator for + * determining if two pages could be buddies. We are not really + * identifying a zone since we could be using a the section number + * id if we have not node id available in page flags. + * We guarantee only that it will return the same value for two + * combinable pages in a zone. + */ static inline int page_zone_id(struct page *page) { - return (page->flags >> ZONETABLE_PGSHIFT) & ZONETABLE_MASK; -} -static inline struct zone *page_zone(struct page *page) -{ - return zone_table[page_zone_id(page)]; + BUILD_BUG_ON(ZONEID_PGSHIFT == 0 && ZONEID_MASK); + return (page->flags >> ZONEID_PGSHIFT) & ZONEID_MASK; } static inline unsigned long zone_to_nid(struct zone *zone) @@ -454,13 +463,20 @@ static inline unsigned long zone_to_nid(struct zone *zone) #endif } +#ifdef NODE_NOT_IN_PAGE_FLAGS +extern unsigned long page_to_nid(struct page *page); +#else static inline unsigned long page_to_nid(struct page *page) { - if (FLAGS_HAS_NODE) - return (page->flags >> NODES_PGSHIFT) & NODES_MASK; - else - return zone_to_nid(page_zone(page)); + return (page->flags >> NODES_PGSHIFT) & NODES_MASK; } +#endif + +static inline struct zone *page_zone(struct page *page) +{ + return &NODE_DATA(page_to_nid(page))->node_zones[page_zonenum(page)]; +} + static inline unsigned long page_to_section(struct page *page) { return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK; @@ -477,6 +493,7 @@ static inline void set_page_node(struct page *page, unsigned long node) page->flags &= ~(NODES_MASK << NODES_PGSHIFT); page->flags |= (node & NODES_MASK) << NODES_PGSHIFT; } + static inline void set_page_section(struct page *page, unsigned long section) { page->flags &= ~(SECTIONS_MASK << SECTIONS_PGSHIFT); @@ -947,8 +964,6 @@ extern void mem_init(void); extern void show_mem(void); extern void si_meminfo(struct sysinfo * val); extern void si_meminfo_node(struct sysinfo *val, int nid); -extern void zonetable_add(struct zone *zone, int nid, enum zone_type zid, - unsigned long pfn, unsigned long size); #ifdef CONFIG_NUMA extern void setup_per_cpu_pageset(void); diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index fd678a662eae..0c055a090f4d 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -72,7 +72,6 @@ static int __add_zone(struct zone *zone, unsigned long phys_start_pfn) return ret; } memmap_init_zone(nr_pages, nid, zone_type, phys_start_pfn); - zonetable_add(zone, nid, zone_type, phys_start_pfn, nr_pages); return 0; } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 08360aa111f9..23bc5bcbdcf9 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -83,13 +83,6 @@ int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = { EXPORT_SYMBOL(totalram_pages); -/* - * Used by page_zone() to look up the address of the struct zone whose - * id is encoded in the upper bits of page->flags - */ -struct zone *zone_table[1 << ZONETABLE_SHIFT] __read_mostly; -EXPORT_SYMBOL(zone_table); - static char *zone_names[MAX_NR_ZONES] = { "DMA", #ifdef CONFIG_ZONE_DMA32 @@ -1715,20 +1708,6 @@ void zone_init_free_lists(struct pglist_data *pgdat, struct zone *zone, } } -#define ZONETABLE_INDEX(x, zone_nr) ((x << ZONES_SHIFT) | zone_nr) -void zonetable_add(struct zone *zone, int nid, enum zone_type zid, - unsigned long pfn, unsigned long size) -{ - unsigned long snum = pfn_to_section_nr(pfn); - unsigned long end = pfn_to_section_nr(pfn + size); - - if (FLAGS_HAS_NODE) - zone_table[ZONETABLE_INDEX(nid, zid)] = zone; - else - for (; snum <= end; snum++) - zone_table[ZONETABLE_INDEX(snum, zid)] = zone; -} - #ifndef __HAVE_ARCH_MEMMAP_INIT #define memmap_init(size, nid, zone, start_pfn) \ memmap_init_zone((size), (nid), (zone), (start_pfn)) @@ -2421,7 +2400,6 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat, if (!size) continue; - zonetable_add(zone, nid, j, zone_start_pfn, size); ret = init_currently_empty_zone(zone, zone_start_pfn, size); BUG_ON(ret); zone_start_pfn += size; diff --git a/mm/sparse.c b/mm/sparse.c index b3c82ba30012..158d6a2a5263 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -24,6 +24,25 @@ struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT] #endif EXPORT_SYMBOL(mem_section); +#ifdef NODE_NOT_IN_PAGE_FLAGS +/* + * If we did not store the node number in the page then we have to + * do a lookup in the section_to_node_table in order to find which + * node the page belongs to. + */ +#if MAX_NUMNODES <= 256 +static u8 section_to_node_table[NR_MEM_SECTIONS] __cacheline_aligned; +#else +static u16 section_to_node_table[NR_MEM_SECTIONS] __cacheline_aligned; +#endif + +unsigned long page_to_nid(struct page *page) +{ + return section_to_node_table[page_to_section(page)]; +} +EXPORT_SYMBOL(page_to_nid); +#endif + #ifdef CONFIG_SPARSEMEM_EXTREME static struct mem_section *sparse_index_alloc(int nid) { @@ -49,6 +68,10 @@ static int sparse_index_init(unsigned long section_nr, int nid) struct mem_section *section; int ret = 0; +#ifdef NODE_NOT_IN_PAGE_FLAGS + section_to_node_table[section_nr] = nid; +#endif + if (mem_section[root]) return -EEXIST; -- cgit v1.2.3 From 9276b1bc96a132f4068fdee00983c532f43d3a26 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Wed, 6 Dec 2006 20:31:48 -0800 Subject: [PATCH] memory page_alloc zonelist caching speedup Optimize the critical zonelist scanning for free pages in the kernel memory allocator by caching the zones that were found to be full recently, and skipping them. Remembers the zones in a zonelist that were short of free memory in the last second. And it stashes a zone-to-node table in the zonelist struct, to optimize that conversion (minimize its cache footprint.) Recent changes: This differs in a significant way from a similar patch that I posted a week ago. Now, instead of having a nodemask_t of recently full nodes, I have a bitmask of recently full zones. This solves a problem that last weeks patch had, which on systems with multiple zones per node (such as DMA zone) would take seeing any of these zones full as meaning that all zones on that node were full. Also I changed names - from "zonelist faster" to "zonelist cache", as that seemed to better convey what we're doing here - caching some of the key zonelist state (for faster access.) See below for some performance benchmark results. After all that discussion with David on why I didn't need them, I went and got some ;). I wanted to verify that I had not hurt the normal case of memory allocation noticeably. At least for my one little microbenchmark, I found (1) the normal case wasn't affected, and (2) workloads that forced scanning across multiple nodes for memory improved up to 10% fewer System CPU cycles and lower elapsed clock time ('sys' and 'real'). Good. See details, below. I didn't have the logic in get_page_from_freelist() for various full nodes and zone reclaim failures correct. That should be fixed up now - notice the new goto labels zonelist_scan, this_zone_full, and try_next_zone, in get_page_from_freelist(). There are two reasons I persued this alternative, over some earlier proposals that would have focused on optimizing the fake numa emulation case by caching the last useful zone: 1) Contrary to what I said before, we (SGI, on large ia64 sn2 systems) have seen real customer loads where the cost to scan the zonelist was a problem, due to many nodes being full of memory before we got to a node we could use. Or at least, I think we have. This was related to me by another engineer, based on experiences from some time past. So this is not guaranteed. Most likely, though. The following approach should help such real numa systems just as much as it helps fake numa systems, or any combination thereof. 2) The effort to distinguish fake from real numa, using node_distance, so that we could cache a fake numa node and optimize choosing it over equivalent distance fake nodes, while continuing to properly scan all real nodes in distance order, was going to require a nasty blob of zonelist and node distance munging. The following approach has no new dependency on node distances or zone sorting. See comment in the patch below for a description of what it actually does. Technical details of note (or controversy): - See the use of "zlc_active" and "did_zlc_setup" below, to delay adding any work for this new mechanism until we've looked at the first zone in zonelist. I figured the odds of the first zone having the memory we needed were high enough that we should just look there, first, then get fancy only if we need to keep looking. - Some odd hackery was needed to add items to struct zonelist, while not tripping up the custom zonelists built by the mm/mempolicy.c code for MPOL_BIND. My usual wordy comments below explain this. Search for "MPOL_BIND". - Some per-node data in the struct zonelist is now modified frequently, with no locking. Multiple CPU cores on a node could hit and mangle this data. The theory is that this is just performance hint data, and the memory allocator will work just fine despite any such mangling. The fields at risk are the struct 'zonelist_cache' fields 'fullzones' (a bitmask) and 'last_full_zap' (unsigned long jiffies). It should all be self correcting after at most a one second delay. - This still does a linear scan of the same lengths as before. All I've optimized is making the scan faster, not algorithmically shorter. It is now able to scan a compact array of 'unsigned short' in the case of many full nodes, so one cache line should cover quite a few nodes, rather than each node hitting another one or two new and distinct cache lines. - If both Andi and Nick don't find this too complicated, I will be (pleasantly) flabbergasted. - I removed the comment claiming we only use one cachline's worth of zonelist. We seem, at least in the fake numa case, to have put the lie to that claim. - I pay no attention to the various watermarks and such in this performance hint. A node could be marked full for one watermark, and then skipped over when searching for a page using a different watermark. I think that's actually quite ok, as it will tend to slightly increase the spreading of memory over other nodes, away from a memory stressed node. =============== Performance - some benchmark results and analysis: This benchmark runs a memory hog program that uses multiple threads to touch alot of memory as quickly as it can. Multiple runs were made, touching 12, 38, 64 or 90 GBytes out of the total 96 GBytes on the system, and using 1, 19, 37, or 55 threads (on a 56 CPU system.) System, user and real (elapsed) timings were recorded for each run, shown in units of seconds, in the table below. Two kernels were tested - 2.6.18-mm3 and the same kernel with this zonelist caching patch added. The table also shows the percentage improvement the zonelist caching sys time is over (lower than) the stock *-mm kernel. number 2.6.18-mm3 zonelist-cache delta (< 0 good) percent GBs N ------------ -------------- ---------------- systime mem threads sys user real sys user real sys user real better 12 1 153 24 177 151 24 176 -2 0 -1 1% 12 19 99 22 8 99 22 8 0 0 0 0% 12 37 111 25 6 112 25 6 1 0 0 -0% 12 55 115 25 5 110 23 5 -5 -2 0 4% 38 1 502 74 576 497 73 570 -5 -1 -6 0% 38 19 426 78 48 373 76 39 -53 -2 -9 12% 38 37 544 83 36 547 82 36 3 -1 0 -0% 38 55 501 77 23 511 80 24 10 3 1 -1% 64 1 917 125 1042 890 124 1014 -27 -1 -28 2% 64 19 1118 138 119 965 141 103 -153 3 -16 13% 64 37 1202 151 94 1136 150 81 -66 -1 -13 5% 64 55 1118 141 61 1072 140 58 -46 -1 -3 4% 90 1 1342 177 1519 1275 174 1450 -67 -3 -69 4% 90 19 2392 199 192 2116 189 176 -276 -10 -16 11% 90 37 3313 238 175 2972 225 145 -341 -13 -30 10% 90 55 1948 210 104 1843 213 100 -105 3 -4 5% Notes: 1) This test ran a memory hog program that started a specified number N of threads, and had each thread allocate and touch 1/N'th of the total memory to be used in the test run in a single loop, writing a constant word to memory, one store every 4096 bytes. Watching this test during some earlier trial runs, I would see each of these threads sit down on one CPU and stay there, for the remainder of the pass, a different CPU for each thread. 2) The 'real' column is not comparable to the 'sys' or 'user' columns. The 'real' column is seconds wall clock time elapsed, from beginning to end of that test pass. The 'sys' and 'user' columns are total CPU seconds spent on that test pass. For a 19 thread test run, for example, the sum of 'sys' and 'user' could be up to 19 times the number of 'real' elapsed wall clock seconds. 3) Tests were run on a fresh, single-user boot, to minimize the amount of memory already in use at the start of the test, and to minimize the amount of background activity that might interfere. 4) Tests were done on a 56 CPU, 28 Node system with 96 GBytes of RAM. 5) Notice that the 'real' time gets large for the single thread runs, even though the measured 'sys' and 'user' times are modest. I'm not sure what that means - probably something to do with it being slow for one thread to be accessing memory along ways away. Perhaps the fake numa system, running ostensibly the same workload, would not show this substantial degradation of 'real' time for one thread on many nodes -- lets hope not. 6) The high thread count passes (one thread per CPU - on 55 of 56 CPUs) ran quite efficiently, as one might expect. Each pair of threads needed to allocate and touch the memory on the node the two threads shared, a pleasantly parallizable workload. 7) The intermediate thread count passes, when asking for alot of memory forcing them to go to a few neighboring nodes, improved the most with this zonelist caching patch. Conclusions: * This zonelist cache patch probably makes little difference one way or the other for most workloads on real numa hardware, if those workloads avoid heavy off node allocations. * For memory intensive workloads requiring substantial off-node allocations on real numa hardware, this patch improves both kernel and elapsed timings up to ten per-cent. * For fake numa systems, I'm optimistic, but will have to leave that up to Rohit Seth to actually test (once I get him a 2.6.18 backport.) Signed-off-by: Paul Jackson Cc: Rohit Seth Cc: Christoph Lameter Cc: David Rientjes Cc: Paul Menage Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cpuset.h | 2 + include/linux/mmzone.h | 85 ++++++++++++++++++++-- mm/mempolicy.c | 2 + mm/page_alloc.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 265 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 4d8adf663681..748d2c996631 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -23,6 +23,7 @@ extern void cpuset_fork(struct task_struct *p); extern void cpuset_exit(struct task_struct *p); extern cpumask_t cpuset_cpus_allowed(struct task_struct *p); extern nodemask_t cpuset_mems_allowed(struct task_struct *p); +#define cpuset_current_mems_allowed (current->mems_allowed) void cpuset_init_current_mems_allowed(void); void cpuset_update_task_memory_state(void); #define cpuset_nodes_subset_current_mems_allowed(nodes) \ @@ -83,6 +84,7 @@ static inline nodemask_t cpuset_mems_allowed(struct task_struct *p) return node_possible_map; } +#define cpuset_current_mems_allowed (node_online_map) static inline void cpuset_init_current_mems_allowed(void) {} static inline void cpuset_update_task_memory_state(void) {} #define cpuset_nodes_subset_current_mems_allowed(nodes) (1) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index e06683e2bea3..09bf9d8d7b72 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -288,19 +288,94 @@ struct zone { */ #define DEF_PRIORITY 12 +/* Maximum number of zones on a zonelist */ +#define MAX_ZONES_PER_ZONELIST (MAX_NUMNODES * MAX_NR_ZONES) + +#ifdef CONFIG_NUMA +/* + * We cache key information from each zonelist for smaller cache + * footprint when scanning for free pages in get_page_from_freelist(). + * + * 1) The BITMAP fullzones tracks which zones in a zonelist have come + * up short of free memory since the last time (last_fullzone_zap) + * we zero'd fullzones. + * 2) The array z_to_n[] maps each zone in the zonelist to its node + * id, so that we can efficiently evaluate whether that node is + * set in the current tasks mems_allowed. + * + * Both fullzones and z_to_n[] are one-to-one with the zonelist, + * indexed by a zones offset in the zonelist zones[] array. + * + * The get_page_from_freelist() routine does two scans. During the + * first scan, we skip zones whose corresponding bit in 'fullzones' + * is set or whose corresponding node in current->mems_allowed (which + * comes from cpusets) is not set. During the second scan, we bypass + * this zonelist_cache, to ensure we look methodically at each zone. + * + * Once per second, we zero out (zap) fullzones, forcing us to + * reconsider nodes that might have regained more free memory. + * The field last_full_zap is the time we last zapped fullzones. + * + * This mechanism reduces the amount of time we waste repeatedly + * reexaming zones for free memory when they just came up low on + * memory momentarilly ago. + * + * The zonelist_cache struct members logically belong in struct + * zonelist. However, the mempolicy zonelists constructed for + * MPOL_BIND are intentionally variable length (and usually much + * shorter). A general purpose mechanism for handling structs with + * multiple variable length members is more mechanism than we want + * here. We resort to some special case hackery instead. + * + * The MPOL_BIND zonelists don't need this zonelist_cache (in good + * part because they are shorter), so we put the fixed length stuff + * at the front of the zonelist struct, ending in a variable length + * zones[], as is needed by MPOL_BIND. + * + * Then we put the optional zonelist cache on the end of the zonelist + * struct. This optional stuff is found by a 'zlcache_ptr' pointer in + * the fixed length portion at the front of the struct. This pointer + * both enables us to find the zonelist cache, and in the case of + * MPOL_BIND zonelists, (which will just set the zlcache_ptr to NULL) + * to know that the zonelist cache is not there. + * + * The end result is that struct zonelists come in two flavors: + * 1) The full, fixed length version, shown below, and + * 2) The custom zonelists for MPOL_BIND. + * The custom MPOL_BIND zonelists have a NULL zlcache_ptr and no zlcache. + * + * Even though there may be multiple CPU cores on a node modifying + * fullzones or last_full_zap in the same zonelist_cache at the same + * time, we don't lock it. This is just hint data - if it is wrong now + * and then, the allocator will still function, perhaps a bit slower. + */ + + +struct zonelist_cache { + DECLARE_BITMAP(fullzones, MAX_ZONES_PER_ZONELIST); /* zone full? */ + unsigned short z_to_n[MAX_ZONES_PER_ZONELIST]; /* zone->nid */ + unsigned long last_full_zap; /* when last zap'd (jiffies) */ +}; +#else +struct zonelist_cache; +#endif + /* * One allocation request operates on a zonelist. A zonelist * is a list of zones, the first one is the 'goal' of the * allocation, the other zones are fallback zones, in decreasing * priority. * - * Right now a zonelist takes up less than a cacheline. We never - * modify it apart from boot-up, and only a few indices are used, - * so despite the zonelist table being relatively big, the cache - * footprint of this construct is very small. + * If zlcache_ptr is not NULL, then it is just the address of zlcache, + * as explained above. If zlcache_ptr is NULL, there is no zlcache. */ + struct zonelist { - struct zone *zones[MAX_NUMNODES * MAX_NR_ZONES + 1]; // NULL delimited + struct zonelist_cache *zlcache_ptr; // NULL or &zlcache + struct zone *zones[MAX_ZONES_PER_ZONELIST + 1]; // NULL delimited +#ifdef CONFIG_NUMA + struct zonelist_cache zlcache; // optional ... +#endif }; #ifdef CONFIG_ARCH_POPULATES_NODE_MAP diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 617fb31086ee..fb907236bbd8 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -141,9 +141,11 @@ static struct zonelist *bind_zonelist(nodemask_t *nodes) enum zone_type k; max = 1 + MAX_NR_ZONES * nodes_weight(*nodes); + max++; /* space for zlcache_ptr (see mmzone.h) */ zl = kmalloc(sizeof(struct zone *) * max, GFP_KERNEL); if (!zl) return NULL; + zl->zlcache_ptr = NULL; num = 0; /* First put in the highest zones from all nodes, then all the next lower zones etc. Avoid empty zones because the memory allocator diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 23bc5bcbdcf9..230771d3c6b6 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -918,6 +918,126 @@ int zone_watermark_ok(struct zone *z, int order, unsigned long mark, return 1; } +#ifdef CONFIG_NUMA +/* + * zlc_setup - Setup for "zonelist cache". Uses cached zone data to + * skip over zones that are not allowed by the cpuset, or that have + * been recently (in last second) found to be nearly full. See further + * comments in mmzone.h. Reduces cache footprint of zonelist scans + * that have to skip over alot of full or unallowed zones. + * + * If the zonelist cache is present in the passed in zonelist, then + * returns a pointer to the allowed node mask (either the current + * tasks mems_allowed, or node_online_map.) + * + * If the zonelist cache is not available for this zonelist, does + * nothing and returns NULL. + * + * If the fullzones BITMAP in the zonelist cache is stale (more than + * a second since last zap'd) then we zap it out (clear its bits.) + * + * We hold off even calling zlc_setup, until after we've checked the + * first zone in the zonelist, on the theory that most allocations will + * be satisfied from that first zone, so best to examine that zone as + * quickly as we can. + */ +static nodemask_t *zlc_setup(struct zonelist *zonelist, int alloc_flags) +{ + struct zonelist_cache *zlc; /* cached zonelist speedup info */ + nodemask_t *allowednodes; /* zonelist_cache approximation */ + + zlc = zonelist->zlcache_ptr; + if (!zlc) + return NULL; + + if (jiffies - zlc->last_full_zap > 1 * HZ) { + bitmap_zero(zlc->fullzones, MAX_ZONES_PER_ZONELIST); + zlc->last_full_zap = jiffies; + } + + allowednodes = !in_interrupt() && (alloc_flags & ALLOC_CPUSET) ? + &cpuset_current_mems_allowed : + &node_online_map; + return allowednodes; +} + +/* + * Given 'z' scanning a zonelist, run a couple of quick checks to see + * if it is worth looking at further for free memory: + * 1) Check that the zone isn't thought to be full (doesn't have its + * bit set in the zonelist_cache fullzones BITMAP). + * 2) Check that the zones node (obtained from the zonelist_cache + * z_to_n[] mapping) is allowed in the passed in allowednodes mask. + * Return true (non-zero) if zone is worth looking at further, or + * else return false (zero) if it is not. + * + * This check -ignores- the distinction between various watermarks, + * such as GFP_HIGH, GFP_ATOMIC, PF_MEMALLOC, ... If a zone is + * found to be full for any variation of these watermarks, it will + * be considered full for up to one second by all requests, unless + * we are so low on memory on all allowed nodes that we are forced + * into the second scan of the zonelist. + * + * In the second scan we ignore this zonelist cache and exactly + * apply the watermarks to all zones, even it is slower to do so. + * We are low on memory in the second scan, and should leave no stone + * unturned looking for a free page. + */ +static int zlc_zone_worth_trying(struct zonelist *zonelist, struct zone **z, + nodemask_t *allowednodes) +{ + struct zonelist_cache *zlc; /* cached zonelist speedup info */ + int i; /* index of *z in zonelist zones */ + int n; /* node that zone *z is on */ + + zlc = zonelist->zlcache_ptr; + if (!zlc) + return 1; + + i = z - zonelist->zones; + n = zlc->z_to_n[i]; + + /* This zone is worth trying if it is allowed but not full */ + return node_isset(n, *allowednodes) && !test_bit(i, zlc->fullzones); +} + +/* + * Given 'z' scanning a zonelist, set the corresponding bit in + * zlc->fullzones, so that subsequent attempts to allocate a page + * from that zone don't waste time re-examining it. + */ +static void zlc_mark_zone_full(struct zonelist *zonelist, struct zone **z) +{ + struct zonelist_cache *zlc; /* cached zonelist speedup info */ + int i; /* index of *z in zonelist zones */ + + zlc = zonelist->zlcache_ptr; + if (!zlc) + return; + + i = z - zonelist->zones; + + set_bit(i, zlc->fullzones); +} + +#else /* CONFIG_NUMA */ + +static nodemask_t *zlc_setup(struct zonelist *zonelist, int alloc_flags) +{ + return NULL; +} + +static int zlc_zone_worth_trying(struct zonelist *zonelist, struct zone **z, + nodemask_t *allowednodes) +{ + return 1; +} + +static void zlc_mark_zone_full(struct zonelist *zonelist, struct zone **z) +{ +} +#endif /* CONFIG_NUMA */ + /* * get_page_from_freelist goes through the zonelist trying to allocate * a page. @@ -926,23 +1046,32 @@ static struct page * get_page_from_freelist(gfp_t gfp_mask, unsigned int order, struct zonelist *zonelist, int alloc_flags) { - struct zone **z = zonelist->zones; + struct zone **z; struct page *page = NULL; - int classzone_idx = zone_idx(*z); + int classzone_idx = zone_idx(zonelist->zones[0]); struct zone *zone; + nodemask_t *allowednodes = NULL;/* zonelist_cache approximation */ + int zlc_active = 0; /* set if using zonelist_cache */ + int did_zlc_setup = 0; /* just call zlc_setup() one time */ +zonelist_scan: /* - * Go through the zonelist once, looking for a zone with enough free. + * Scan zonelist, looking for a zone with enough free. * See also cpuset_zone_allowed() comment in kernel/cpuset.c. */ + z = zonelist->zones; + do { + if (NUMA_BUILD && zlc_active && + !zlc_zone_worth_trying(zonelist, z, allowednodes)) + continue; zone = *z; if (unlikely(NUMA_BUILD && (gfp_mask & __GFP_THISNODE) && zone->zone_pgdat != zonelist->zones[0]->zone_pgdat)) break; if ((alloc_flags & ALLOC_CPUSET) && !cpuset_zone_allowed(zone, gfp_mask)) - continue; + goto try_next_zone; if (!(alloc_flags & ALLOC_NO_WATERMARKS)) { unsigned long mark; @@ -956,15 +1085,30 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, classzone_idx, alloc_flags)) { if (!zone_reclaim_mode || !zone_reclaim(zone, gfp_mask, order)) - continue; + goto this_zone_full; } } page = buffered_rmqueue(zonelist, zone, order, gfp_mask); if (page) break; - +this_zone_full: + if (NUMA_BUILD) + zlc_mark_zone_full(zonelist, z); +try_next_zone: + if (NUMA_BUILD && !did_zlc_setup) { + /* we do zlc_setup after the first zone is tried */ + allowednodes = zlc_setup(zonelist, alloc_flags); + zlc_active = 1; + did_zlc_setup = 1; + } } while (*(++z) != NULL); + + if (unlikely(NUMA_BUILD && page == NULL && zlc_active)) { + /* Disable zlc cache for second zonelist scan */ + zlc_active = 0; + goto zonelist_scan; + } return page; } @@ -1535,6 +1679,24 @@ static void __meminit build_zonelists(pg_data_t *pgdat) } } +/* Construct the zonelist performance cache - see further mmzone.h */ +static void __meminit build_zonelist_cache(pg_data_t *pgdat) +{ + int i; + + for (i = 0; i < MAX_NR_ZONES; i++) { + struct zonelist *zonelist; + struct zonelist_cache *zlc; + struct zone **z; + + zonelist = pgdat->node_zonelists + i; + zonelist->zlcache_ptr = zlc = &zonelist->zlcache; + bitmap_zero(zlc->fullzones, MAX_ZONES_PER_ZONELIST); + for (z = zonelist->zones; *z; z++) + zlc->z_to_n[z - zonelist->zones] = zone_to_nid(*z); + } +} + #else /* CONFIG_NUMA */ static void __meminit build_zonelists(pg_data_t *pgdat) @@ -1572,14 +1734,26 @@ static void __meminit build_zonelists(pg_data_t *pgdat) } } +/* non-NUMA variant of zonelist performance cache - just NULL zlcache_ptr */ +static void __meminit build_zonelist_cache(pg_data_t *pgdat) +{ + int i; + + for (i = 0; i < MAX_NR_ZONES; i++) + pgdat->node_zonelists[i].zlcache_ptr = NULL; +} + #endif /* CONFIG_NUMA */ /* return values int ....just for stop_machine_run() */ static int __meminit __build_all_zonelists(void *dummy) { int nid; - for_each_online_node(nid) + + for_each_online_node(nid) { build_zonelists(NODE_DATA(nid)); + build_zonelist_cache(NODE_DATA(nid)); + } return 0; } -- cgit v1.2.3 From 7253f4ef04b1cd138baf2b29a95473743ac0a307 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Wed, 6 Dec 2006 20:31:49 -0800 Subject: [PATCH] memory page_alloc zonelist caching reorder structure Rearrange the struct members in the 'struct zonelist_cache' structure, so as to put the readonly (once initialized) z_to_n[] array first, where it will come right after the zones[] array in struct zonelist. This pretty much eliminates the chance that the two frequently written elements of 'struct zonelist_cache', the fullzones bitmap and last_full_zap times, will end up on the same cache line as the performance sensitive, frequently read, never (after init) written zones[] array. Keeping frequently written data off frequently read cache lines is good for performance. Thanks to Rohit Seth for the suggestion. Signed-off-by: Paul Jackson Cc: Rohit Seth Cc: Paul Menage Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 09bf9d8d7b72..da6002dec205 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -352,8 +352,8 @@ struct zone { struct zonelist_cache { - DECLARE_BITMAP(fullzones, MAX_ZONES_PER_ZONELIST); /* zone full? */ unsigned short z_to_n[MAX_ZONES_PER_ZONELIST]; /* zone->nid */ + DECLARE_BITMAP(fullzones, MAX_ZONES_PER_ZONELIST); /* zone full? */ unsigned long last_full_zap; /* when last zap'd (jiffies) */ }; #else -- cgit v1.2.3 From 7602bdf2fd14a40dd9b104e516fdc05e1bd17952 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Wed, 6 Dec 2006 20:31:57 -0800 Subject: [PATCH] new scheme to preempt swap token The new swap token patches replace the current token traversal algo. The old algo had a crude timeout parameter that was used to handover the token from one task to another. This algo, transfers the token to the tasks that are in need of the token. The urgency for the token is based on the number of times a task is required to swap-in pages. Accordingly, the priority of a task is incremented if it has been badly affected due to swap-outs. To ensure that the token doesnt bounce around rapidly, the token holders are given a priority boost. The priority of tasks is also decremented, if their rate of swap-in's keeps reducing. This way, the condition to check whether to pre-empt the swap token, is a matter of comparing two task's priority fields. [akpm@osdl.org: cleanups] Signed-off-by: Ashwin Chaugule Cc: Rik van Riel Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 13 ++++-- include/linux/swap.h | 1 - kernel/fork.c | 8 ++++ kernel/sysctl.c | 11 ----- mm/thrash.c | 116 ++++++++++++++++++++------------------------------ 5 files changed, 63 insertions(+), 86 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index eafe4a7b8237..cad6a16260f7 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -344,9 +344,16 @@ struct mm_struct { /* Architecture-specific MM context */ mm_context_t context; - /* Token based thrashing protection. */ - unsigned long swap_token_time; - char recent_pagein; + /* Swap token stuff */ + /* + * Last value of global fault stamp as seen by this process. + * In other words, this value gives an indication of how long + * it has been since this task got the token. + * Look at mm/thrash.c + */ + unsigned int faultstamp; + unsigned int token_priority; + unsigned int last_interval; /* coredumping support */ int core_waiters; diff --git a/include/linux/swap.h b/include/linux/swap.h index e7c36ba2a2db..89f8a39773bf 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -259,7 +259,6 @@ extern spinlock_t swap_lock; /* linux/mm/thrash.c */ extern struct mm_struct * swap_token_mm; -extern unsigned long swap_token_default_timeout; extern void grab_swap_token(void); extern void __put_swap_token(struct mm_struct *); diff --git a/kernel/fork.c b/kernel/fork.c index 8cdd3e72ba55..5678e6c61ef2 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -479,6 +479,10 @@ static struct mm_struct *dup_mm(struct task_struct *tsk) memcpy(mm, oldmm, sizeof(*mm)); + /* Initializing for Swap token stuff */ + mm->token_priority = 0; + mm->last_interval = 0; + if (!mm_init(mm)) goto fail_nomem; @@ -542,6 +546,10 @@ static int copy_mm(unsigned long clone_flags, struct task_struct * tsk) goto fail_nomem; good_mm: + /* Initializing for Swap token stuff */ + mm->token_priority = 0; + mm->last_interval = 0; + tsk->mm = mm; tsk->active_mm = mm; return 0; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 09e569f4792b..7abe9704e75a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -977,17 +977,6 @@ static ctl_table vm_table[] = { .extra1 = &zero, }, #endif -#ifdef CONFIG_SWAP - { - .ctl_name = VM_SWAP_TOKEN_TIMEOUT, - .procname = "swap_token_timeout", - .data = &swap_token_default_timeout, - .maxlen = sizeof(swap_token_default_timeout), - .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, - }, -#endif #ifdef CONFIG_NUMA { .ctl_name = VM_ZONE_RECLAIM_MODE, diff --git a/mm/thrash.c b/mm/thrash.c index f4c560b4a2b7..19e428ca8b03 100644 --- a/mm/thrash.c +++ b/mm/thrash.c @@ -7,100 +7,74 @@ * * Simple token based thrashing protection, using the algorithm * described in: http://www.cs.wm.edu/~sjiang/token.pdf + * + * Sep 2006, Ashwin Chaugule + * Improved algorithm to pass token: + * Each task has a priority which is incremented if it contended + * for the token in an interval less than its previous attempt. + * If the token is acquired, that task's priority is boosted to prevent + * the token from bouncing around too often and to let the task make + * some progress in its execution. */ + #include #include #include #include static DEFINE_SPINLOCK(swap_token_lock); -static unsigned long swap_token_timeout; -static unsigned long swap_token_check; -struct mm_struct * swap_token_mm = &init_mm; - -#define SWAP_TOKEN_CHECK_INTERVAL (HZ * 2) -#define SWAP_TOKEN_TIMEOUT (300 * HZ) -/* - * Currently disabled; Needs further code to work at HZ * 300. - */ -unsigned long swap_token_default_timeout = SWAP_TOKEN_TIMEOUT; - -/* - * Take the token away if the process had no page faults - * in the last interval, or if it has held the token for - * too long. - */ -#define SWAP_TOKEN_ENOUGH_RSS 1 -#define SWAP_TOKEN_TIMED_OUT 2 -static int should_release_swap_token(struct mm_struct *mm) -{ - int ret = 0; - if (!mm->recent_pagein) - ret = SWAP_TOKEN_ENOUGH_RSS; - else if (time_after(jiffies, swap_token_timeout)) - ret = SWAP_TOKEN_TIMED_OUT; - mm->recent_pagein = 0; - return ret; -} +struct mm_struct *swap_token_mm; +unsigned int global_faults; -/* - * Try to grab the swapout protection token. We only try to - * grab it once every TOKEN_CHECK_INTERVAL, both to prevent - * SMP lock contention and to check that the process that held - * the token before is no longer thrashing. - */ void grab_swap_token(void) { - struct mm_struct *mm; - int reason; + int current_interval; - /* We have the token. Let others know we still need it. */ - if (has_swap_token(current->mm)) { - current->mm->recent_pagein = 1; - if (unlikely(!swap_token_default_timeout)) - disable_swap_token(); - return; - } - - if (time_after(jiffies, swap_token_check)) { + global_faults++; - if (!swap_token_default_timeout) { - swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL; - return; - } - - /* ... or if we recently held the token. */ - if (time_before(jiffies, current->mm->swap_token_time)) - return; + current_interval = global_faults - current->mm->faultstamp; - if (!spin_trylock(&swap_token_lock)) - return; + if (!spin_trylock(&swap_token_lock)) + return; - swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL; + /* First come first served */ + if (swap_token_mm == NULL) { + current->mm->token_priority = current->mm->token_priority + 2; + swap_token_mm = current->mm; + goto out; + } - mm = swap_token_mm; - if ((reason = should_release_swap_token(mm))) { - unsigned long eligible = jiffies; - if (reason == SWAP_TOKEN_TIMED_OUT) { - eligible += swap_token_default_timeout; - } - mm->swap_token_time = eligible; - swap_token_timeout = jiffies + swap_token_default_timeout; + if (current->mm != swap_token_mm) { + if (current_interval < current->mm->last_interval) + current->mm->token_priority++; + else { + current->mm->token_priority--; + if (unlikely(current->mm->token_priority < 0)) + current->mm->token_priority = 0; + } + /* Check if we deserve the token */ + if (current->mm->token_priority > + swap_token_mm->token_priority) { + current->mm->token_priority += 2; swap_token_mm = current->mm; } - spin_unlock(&swap_token_lock); + } else { + /* Token holder came in again! */ + current->mm->token_priority += 2; } - return; + +out: + current->mm->faultstamp = global_faults; + current->mm->last_interval = current_interval; + spin_unlock(&swap_token_lock); +return; } /* Called on process exit. */ void __put_swap_token(struct mm_struct *mm) { spin_lock(&swap_token_lock); - if (likely(mm == swap_token_mm)) { - mm->swap_token_time = jiffies + SWAP_TOKEN_CHECK_INTERVAL; - swap_token_mm = &init_mm; - swap_token_check = jiffies; - } + if (likely(mm == swap_token_mm)) + swap_token_mm = NULL; spin_unlock(&swap_token_lock); } -- cgit v1.2.3 From cc102509074bba0316f2b5deebd7ef4447da295e Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 6 Dec 2006 20:32:00 -0800 Subject: [PATCH] mm: add arch_alloc_page Add an arch_alloc_page to match arch_free_page. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/gfp.h | 3 +++ mm/page_alloc.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/gfp.h b/include/linux/gfp.h index bf2b6bc3f6fd..00c314aedab7 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -116,6 +116,9 @@ static inline enum zone_type gfp_zone(gfp_t flags) #ifndef HAVE_ARCH_FREE_PAGE static inline void arch_free_page(struct page *page, int order) { } #endif +#ifndef HAVE_ARCH_ALLOC_PAGE +static inline void arch_alloc_page(struct page *page, int order) { } +#endif extern struct page * FASTCALL(__alloc_pages(gfp_t, unsigned int, struct zonelist *)); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 230771d3c6b6..cd47e8f7bd5b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -598,6 +598,8 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) 1 << PG_checked | 1 << PG_mappedtodisk); set_page_private(page, 0); set_page_refcounted(page); + + arch_alloc_page(page, order); kernel_map_pages(page, 1 << order, 1); if (gfp_flags & __GFP_ZERO) -- cgit v1.2.3 From 39dde65c9940c97fcd178a3d2b1c57ed8b7b68aa Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" Date: Wed, 6 Dec 2006 20:32:03 -0800 Subject: [PATCH] shared page table for hugetlb page Following up with the work on shared page table done by Dave McCracken. This set of patch target shared page table for hugetlb memory only. The shared page table is particular useful in the situation of large number of independent processes sharing large shared memory segments. In the normal page case, the amount of memory saved from process' page table is quite significant. For hugetlb, the saving on page table memory is not the primary objective (as hugetlb itself already cuts down page table overhead significantly), instead, the purpose of using shared page table on hugetlb is to allow faster TLB refill and smaller cache pollution upon TLB miss. With PT sharing, pte entries are shared among hundreds of processes, the cache consumption used by all the page table is smaller and in return, application gets much higher cache hit ratio. One other effect is that cache hit ratio with hardware page walker hitting on pte in cache will be higher and this helps to reduce tlb miss latency. These two effects contribute to higher application performance. Signed-off-by: Ken Chen Acked-by: Hugh Dickins Cc: Dave McCracken Cc: William Lee Irwin III Cc: "Luck, Tony" Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: David Gibson Cc: Adam Litke Cc: Paul Mundt Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/mm/hugetlbpage.c | 112 +++++++++++++++++++++++++++++++++++++++++- arch/ia64/mm/hugetlbpage.c | 5 ++ arch/powerpc/mm/hugetlbpage.c | 5 ++ arch/sh/mm/hugetlbpage.c | 5 ++ arch/sh64/mm/hugetlbpage.c | 5 ++ arch/sparc64/mm/hugetlbpage.c | 5 ++ include/linux/hugetlb.h | 1 + mm/hugetlb.c | 7 +++ 8 files changed, 144 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c index 1719a8141f81..34728e4afe48 100644 --- a/arch/i386/mm/hugetlbpage.c +++ b/arch/i386/mm/hugetlbpage.c @@ -17,6 +17,113 @@ #include #include +static unsigned long page_table_shareable(struct vm_area_struct *svma, + struct vm_area_struct *vma, + unsigned long addr, pgoff_t idx) +{ + unsigned long saddr = ((idx - svma->vm_pgoff) << PAGE_SHIFT) + + svma->vm_start; + unsigned long sbase = saddr & PUD_MASK; + unsigned long s_end = sbase + PUD_SIZE; + + /* + * match the virtual addresses, permission and the alignment of the + * page table page. + */ + if (pmd_index(addr) != pmd_index(saddr) || + vma->vm_flags != svma->vm_flags || + sbase < svma->vm_start || svma->vm_end < s_end) + return 0; + + return saddr; +} + +static int vma_shareable(struct vm_area_struct *vma, unsigned long addr) +{ + unsigned long base = addr & PUD_MASK; + unsigned long end = base + PUD_SIZE; + + /* + * check on proper vm_flags and page table alignment + */ + if (vma->vm_flags & VM_MAYSHARE && + vma->vm_start <= base && end <= vma->vm_end) + return 1; + return 0; +} + +/* + * search for a shareable pmd page for hugetlb. + */ +static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud) +{ + struct vm_area_struct *vma = find_vma(mm, addr); + struct address_space *mapping = vma->vm_file->f_mapping; + pgoff_t idx = ((addr - vma->vm_start) >> PAGE_SHIFT) + + vma->vm_pgoff; + struct prio_tree_iter iter; + struct vm_area_struct *svma; + unsigned long saddr; + pte_t *spte = NULL; + + if (!vma_shareable(vma, addr)) + return; + + spin_lock(&mapping->i_mmap_lock); + vma_prio_tree_foreach(svma, &iter, &mapping->i_mmap, idx, idx) { + if (svma == vma) + continue; + + saddr = page_table_shareable(svma, vma, addr, idx); + if (saddr) { + spte = huge_pte_offset(svma->vm_mm, saddr); + if (spte) { + get_page(virt_to_page(spte)); + break; + } + } + } + + if (!spte) + goto out; + + spin_lock(&mm->page_table_lock); + if (pud_none(*pud)) + pud_populate(mm, pud, (unsigned long) spte & PAGE_MASK); + else + put_page(virt_to_page(spte)); + spin_unlock(&mm->page_table_lock); +out: + spin_unlock(&mapping->i_mmap_lock); +} + +/* + * unmap huge page backed by shared pte. + * + * Hugetlb pte page is ref counted at the time of mapping. If pte is shared + * indicated by page_count > 1, unmap is achieved by clearing pud and + * decrementing the ref count. If count == 1, the pte page is not shared. + * + * called with vma->vm_mm->page_table_lock held. + * + * returns: 1 successfully unmapped a shared pte page + * 0 the underlying pte page is not shared, or it is the last user + */ +int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) +{ + pgd_t *pgd = pgd_offset(mm, *addr); + pud_t *pud = pud_offset(pgd, *addr); + + BUG_ON(page_count(virt_to_page(ptep)) == 0); + if (page_count(virt_to_page(ptep)) == 1) + return 0; + + pud_clear(pud); + put_page(virt_to_page(ptep)); + *addr = ALIGN(*addr, HPAGE_SIZE * PTRS_PER_PTE) - HPAGE_SIZE; + return 1; +} + pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; @@ -25,8 +132,11 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) pgd = pgd_offset(mm, addr); pud = pud_alloc(mm, pgd, addr); - if (pud) + if (pud) { + if (pud_none(*pud)) + huge_pmd_share(mm, addr, pud); pte = (pte_t *) pmd_alloc(mm, pud, addr); + } BUG_ON(pte && !pte_none(*pte) && !pte_huge(*pte)); return pte; diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index f3a9585e98a8..0c7e94edc20e 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c @@ -64,6 +64,11 @@ huge_pte_offset (struct mm_struct *mm, unsigned long addr) return pte; } +int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) +{ + return 0; +} + #define mk_pte_huge(entry) { pte_val(entry) |= _PAGE_P; } /* diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 506d89768d45..424a8f57e155 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -146,6 +146,11 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) return hugepte_offset(hpdp, addr); } +int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) +{ + return 0; +} + static void free_hugepte_range(struct mmu_gather *tlb, hugepd_t *hpdp) { pte_t *hugepte = hugepd_page(*hpdp); diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c index 329059d6b54a..cf2c2ee35a37 100644 --- a/arch/sh/mm/hugetlbpage.c +++ b/arch/sh/mm/hugetlbpage.c @@ -63,6 +63,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) return pte; } +int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) +{ + return 0; +} + struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) { diff --git a/arch/sh64/mm/hugetlbpage.c b/arch/sh64/mm/hugetlbpage.c index 187cf01750b8..4b455f611146 100644 --- a/arch/sh64/mm/hugetlbpage.c +++ b/arch/sh64/mm/hugetlbpage.c @@ -53,6 +53,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) return pte; } +int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) +{ + return 0; +} + void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t entry) { diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c index 53b9b1f528e5..33fd0b265e70 100644 --- a/arch/sparc64/mm/hugetlbpage.c +++ b/arch/sparc64/mm/hugetlbpage.c @@ -235,6 +235,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) return pte; } +int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) +{ + return 0; +} + void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t entry) { diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index ace64e57e17f..a60995afe334 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -35,6 +35,7 @@ extern int sysctl_hugetlb_shm_group; pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr); pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr); +int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep); struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, int write); struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, diff --git a/mm/hugetlb.c b/mm/hugetlb.c index f7355bf2f285..9244971b6791 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -386,6 +386,9 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, if (!ptep) continue; + if (huge_pmd_unshare(mm, &address, ptep)) + continue; + pte = huge_ptep_get_and_clear(mm, address, ptep); if (pte_none(pte)) continue; @@ -658,11 +661,14 @@ void hugetlb_change_protection(struct vm_area_struct *vma, BUG_ON(address >= end); flush_cache_range(vma, address, end); + spin_lock(&vma->vm_file->f_mapping->i_mmap_lock); spin_lock(&mm->page_table_lock); for (; address < end; address += HPAGE_SIZE) { ptep = huge_pte_offset(mm, address); if (!ptep) continue; + if (huge_pmd_unshare(mm, &address, ptep)) + continue; if (!pte_none(*ptep)) { pte = huge_ptep_get_and_clear(mm, address, ptep); pte = pte_mkhuge(pte_modify(pte, newprot)); @@ -671,6 +677,7 @@ void hugetlb_change_protection(struct vm_area_struct *vma, } } spin_unlock(&mm->page_table_lock); + spin_unlock(&vma->vm_file->f_mapping->i_mmap_lock); flush_tlb_range(vma, start, end); } -- cgit v1.2.3 From a866374aecc90c7d90619727ccd851ac096b2fc7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 6 Dec 2006 20:32:20 -0800 Subject: [PATCH] mm: pagefault_{disable,enable}() Introduce pagefault_{disable,enable}() and use these where previously we did manual preempt increments/decrements to make the pagefault handler do the atomic thing. Currently they still rely on the increased preempt count, but do not rely on the disabled preemption, this might go away in the future. (NOTE: the extra barrier() in pagefault_disable might fix some holes on machines which have too many registers for their own good) [heiko.carstens@de.ibm.com: s390 fix] Signed-off-by: Peter Zijlstra Acked-by: Nick Piggin Cc: Martin Schwidefsky Signed-off-by: Heiko Carstens Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/kernel/futex.c | 4 ++-- arch/i386/mm/highmem.c | 10 ++++------ arch/mips/mm/highmem.c | 10 ++++------ arch/s390/lib/uaccess_std.c | 6 +++--- arch/sparc/mm/highmem.c | 8 +++----- include/asm-frv/highmem.h | 5 ++--- include/asm-generic/futex.h | 4 ++-- include/asm-i386/futex.h | 4 ++-- include/asm-ia64/futex.h | 4 ++-- include/asm-mips/futex.h | 4 ++-- include/asm-parisc/futex.h | 4 ++-- include/asm-powerpc/futex.h | 4 ++-- include/asm-ppc/highmem.h | 8 +++----- include/asm-sparc64/futex.h | 4 ++-- include/asm-x86_64/futex.h | 4 ++-- include/linux/uaccess.h | 39 +++++++++++++++++++++++++++++++++++++-- kernel/futex.c | 28 ++++++++++++++-------------- 17 files changed, 88 insertions(+), 62 deletions(-) (limited to 'include/linux') diff --git a/arch/frv/kernel/futex.c b/arch/frv/kernel/futex.c index eae874a970c6..53dc5ed1ebda 100644 --- a/arch/frv/kernel/futex.c +++ b/arch/frv/kernel/futex.c @@ -200,7 +200,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr) if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) return -EFAULT; - inc_preempt_count(); + pagefault_disable(); switch (op) { case FUTEX_OP_SET: @@ -223,7 +223,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr) break; } - dec_preempt_count(); + pagefault_enable(); if (!ret) { switch (cmp) { diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c index f9f647cdbc7b..178bbfe6cbac 100644 --- a/arch/i386/mm/highmem.c +++ b/arch/i386/mm/highmem.c @@ -32,7 +32,7 @@ void *kmap_atomic(struct page *page, enum km_type type) unsigned long vaddr; /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ - inc_preempt_count(); + pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -52,8 +52,7 @@ void kunmap_atomic(void *kvaddr, enum km_type type) #ifdef CONFIG_DEBUG_HIGHMEM if (vaddr >= PAGE_OFFSET && vaddr < (unsigned long)high_memory) { - dec_preempt_count(); - preempt_check_resched(); + pagefault_enable(); return; } @@ -68,8 +67,7 @@ void kunmap_atomic(void *kvaddr, enum km_type type) */ kpte_clear_flush(kmap_pte-idx, vaddr); - dec_preempt_count(); - preempt_check_resched(); + pagefault_enable(); } /* This is the same as kmap_atomic() but can map memory that doesn't @@ -80,7 +78,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) enum fixed_addresses idx; unsigned long vaddr; - inc_preempt_count(); + pagefault_disable(); idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 99ebf3ccc222..675502ada5a2 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -39,7 +39,7 @@ void *__kmap_atomic(struct page *page, enum km_type type) unsigned long vaddr; /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ - inc_preempt_count(); + pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -62,8 +62,7 @@ void __kunmap_atomic(void *kvaddr, enum km_type type) enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); if (vaddr < FIXADDR_START) { // FIXME - dec_preempt_count(); - preempt_check_resched(); + pagefault_enable(); return; } @@ -78,8 +77,7 @@ void __kunmap_atomic(void *kvaddr, enum km_type type) local_flush_tlb_one(vaddr); #endif - dec_preempt_count(); - preempt_check_resched(); + pagefault_enable(); } #ifndef CONFIG_LIMITED_DMA @@ -92,7 +90,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) enum fixed_addresses idx; unsigned long vaddr; - inc_preempt_count(); + pagefault_disable(); idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c index 2d549ed2e113..bbaca66fa293 100644 --- a/arch/s390/lib/uaccess_std.c +++ b/arch/s390/lib/uaccess_std.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #ifndef __s390x__ @@ -258,7 +258,7 @@ int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old) { int oldval = 0, newval, ret; - inc_preempt_count(); + pagefault_disable(); switch (op) { case FUTEX_OP_SET: @@ -284,7 +284,7 @@ int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old) default: ret = -ENOSYS; } - dec_preempt_count(); + pagefault_enable(); *old = oldval; return ret; } diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index 4d8ed9c65182..01fc6c254292 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -35,7 +35,7 @@ void *kmap_atomic(struct page *page, enum km_type type) unsigned long vaddr; /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ - inc_preempt_count(); + pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -70,8 +70,7 @@ void kunmap_atomic(void *kvaddr, enum km_type type) unsigned long idx = type + KM_TYPE_NR*smp_processor_id(); if (vaddr < FIXADDR_START) { // FIXME - dec_preempt_count(); - preempt_check_resched(); + pagefault_enable(); return; } @@ -97,8 +96,7 @@ void kunmap_atomic(void *kvaddr, enum km_type type) #endif #endif - dec_preempt_count(); - preempt_check_resched(); + pagefault_enable(); } /* We may be fed a pagetable here by ptep_to_xxx and others. */ diff --git a/include/asm-frv/highmem.h b/include/asm-frv/highmem.h index 0f390f41f816..ff4d6cdeb152 100644 --- a/include/asm-frv/highmem.h +++ b/include/asm-frv/highmem.h @@ -115,7 +115,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type type) { unsigned long paddr; - inc_preempt_count(); + pagefault_disable(); paddr = page_to_phys(page); switch (type) { @@ -170,8 +170,7 @@ static inline void kunmap_atomic(void *kvaddr, enum km_type type) default: BUG(); } - dec_preempt_count(); - preempt_check_resched(); + pagefault_enable(); } #endif /* !__ASSEMBLY__ */ diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h index df893c160318..f422df0956a2 100644 --- a/include/asm-generic/futex.h +++ b/include/asm-generic/futex.h @@ -21,7 +21,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) return -EFAULT; - inc_preempt_count(); + pagefault_disable(); switch (op) { case FUTEX_OP_SET: @@ -33,7 +33,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) ret = -ENOSYS; } - dec_preempt_count(); + pagefault_enable(); if (!ret) { switch (cmp) { diff --git a/include/asm-i386/futex.h b/include/asm-i386/futex.h index 946d97cfea23..438ef0ec7101 100644 --- a/include/asm-i386/futex.h +++ b/include/asm-i386/futex.h @@ -56,7 +56,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) return -EFAULT; - inc_preempt_count(); + pagefault_disable(); if (op == FUTEX_OP_SET) __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg); @@ -88,7 +88,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) } } - dec_preempt_count(); + pagefault_enable(); if (!ret) { switch (cmp) { diff --git a/include/asm-ia64/futex.h b/include/asm-ia64/futex.h index 07d77f3a8cbe..8a98a2654139 100644 --- a/include/asm-ia64/futex.h +++ b/include/asm-ia64/futex.h @@ -59,7 +59,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) return -EFAULT; - inc_preempt_count(); + pagefault_disable(); switch (op) { case FUTEX_OP_SET: @@ -83,7 +83,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) ret = -ENOSYS; } - dec_preempt_count(); + pagefault_enable(); if (!ret) { switch (cmp) { diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h index 927a216bd530..47e5679c2353 100644 --- a/include/asm-mips/futex.h +++ b/include/asm-mips/futex.h @@ -88,7 +88,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) return -EFAULT; - inc_preempt_count(); + pagefault_disable(); switch (op) { case FUTEX_OP_SET: @@ -115,7 +115,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) ret = -ENOSYS; } - dec_preempt_count(); + pagefault_enable(); if (!ret) { switch (cmp) { diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h index d84bbb283fd1..dbee6e60aa81 100644 --- a/include/asm-parisc/futex.h +++ b/include/asm-parisc/futex.h @@ -21,7 +21,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) return -EFAULT; - inc_preempt_count(); + pagefault_disable(); switch (op) { case FUTEX_OP_SET: @@ -33,7 +33,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) ret = -ENOSYS; } - dec_preempt_count(); + pagefault_enable(); if (!ret) { switch (cmp) { diff --git a/include/asm-powerpc/futex.h b/include/asm-powerpc/futex.h index 936422e54891..3f3673fd3ff3 100644 --- a/include/asm-powerpc/futex.h +++ b/include/asm-powerpc/futex.h @@ -43,7 +43,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr) if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) return -EFAULT; - inc_preempt_count(); + pagefault_disable(); switch (op) { case FUTEX_OP_SET: @@ -65,7 +65,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr) ret = -ENOSYS; } - dec_preempt_count(); + pagefault_enable(); if (!ret) { switch (cmp) { diff --git a/include/asm-ppc/highmem.h b/include/asm-ppc/highmem.h index 1d2c4ef81c22..f7b21ee302b4 100644 --- a/include/asm-ppc/highmem.h +++ b/include/asm-ppc/highmem.h @@ -79,7 +79,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type type) unsigned long vaddr; /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ - inc_preempt_count(); + pagefault_disable(); if (!PageHighMem(page)) return page_address(page); @@ -101,8 +101,7 @@ static inline void kunmap_atomic(void *kvaddr, enum km_type type) unsigned int idx = type + KM_TYPE_NR*smp_processor_id(); if (vaddr < KMAP_FIX_BEGIN) { // FIXME - dec_preempt_count(); - preempt_check_resched(); + pagefault_enable(); return; } @@ -115,8 +114,7 @@ static inline void kunmap_atomic(void *kvaddr, enum km_type type) pte_clear(&init_mm, vaddr, kmap_pte+idx); flush_tlb_page(NULL, vaddr); #endif - dec_preempt_count(); - preempt_check_resched(); + pagefault_enable(); } static inline struct page *kmap_atomic_to_page(void *ptr) diff --git a/include/asm-sparc64/futex.h b/include/asm-sparc64/futex.h index 7392fc4a954e..876312fe82cc 100644 --- a/include/asm-sparc64/futex.h +++ b/include/asm-sparc64/futex.h @@ -45,7 +45,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr) if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; - inc_preempt_count(); + pagefault_disable(); switch (op) { case FUTEX_OP_SET: @@ -67,7 +67,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr) ret = -ENOSYS; } - dec_preempt_count(); + pagefault_enable(); if (!ret) { switch (cmp) { diff --git a/include/asm-x86_64/futex.h b/include/asm-x86_64/futex.h index 9804bf07b092..5cdfb08013c3 100644 --- a/include/asm-x86_64/futex.h +++ b/include/asm-x86_64/futex.h @@ -55,7 +55,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) return -EFAULT; - inc_preempt_count(); + pagefault_disable(); switch (op) { case FUTEX_OP_SET: @@ -78,7 +78,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) ret = -ENOSYS; } - dec_preempt_count(); + pagefault_enable(); if (!ret) { switch (cmp) { diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index a48d7f11c7be..67918c22339c 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -1,8 +1,43 @@ #ifndef __LINUX_UACCESS_H__ #define __LINUX_UACCESS_H__ +#include #include +/* + * These routines enable/disable the pagefault handler in that + * it will not take any locks and go straight to the fixup table. + * + * They have great resemblance to the preempt_disable/enable calls + * and in fact they are identical; this is because currently there is + * no other way to make the pagefault handlers do this. So we do + * disable preemption but we don't necessarily care about that. + */ +static inline void pagefault_disable(void) +{ + inc_preempt_count(); + /* + * make sure to have issued the store before a pagefault + * can hit. + */ + barrier(); +} + +static inline void pagefault_enable(void) +{ + /* + * make sure to issue those last loads/stores before enabling + * the pagefault handler again. + */ + barrier(); + dec_preempt_count(); + /* + * make sure we do.. + */ + barrier(); + preempt_check_resched(); +} + #ifndef ARCH_HAS_NOCACHE_UACCESS static inline unsigned long __copy_from_user_inatomic_nocache(void *to, @@ -35,9 +70,9 @@ static inline unsigned long __copy_from_user_nocache(void *to, ({ \ long ret; \ \ - inc_preempt_count(); \ + pagefault_disable(); \ ret = __get_user(retval, addr); \ - dec_preempt_count(); \ + pagefault_enable(); \ ret; \ }) diff --git a/kernel/futex.c b/kernel/futex.c index 93ef30ba209f..af7b81cbde30 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -282,9 +282,9 @@ static inline int get_futex_value_locked(u32 *dest, u32 __user *from) { int ret; - inc_preempt_count(); + pagefault_disable(); ret = __copy_from_user_inatomic(dest, from, sizeof(u32)); - dec_preempt_count(); + pagefault_enable(); return ret ? -EFAULT : 0; } @@ -585,9 +585,9 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) if (!(uval & FUTEX_OWNER_DIED)) { newval = FUTEX_WAITERS | new_owner->pid; - inc_preempt_count(); + pagefault_disable(); curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval); - dec_preempt_count(); + pagefault_enable(); if (curval == -EFAULT) return -EFAULT; if (curval != uval) @@ -618,9 +618,9 @@ static int unlock_futex_pi(u32 __user *uaddr, u32 uval) * There is no waiter, so we unlock the futex. The owner died * bit has not to be preserved here. We are the owner: */ - inc_preempt_count(); + pagefault_disable(); oldval = futex_atomic_cmpxchg_inatomic(uaddr, uval, 0); - dec_preempt_count(); + pagefault_enable(); if (oldval == -EFAULT) return oldval; @@ -1158,9 +1158,9 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec, */ newval = current->pid; - inc_preempt_count(); + pagefault_disable(); curval = futex_atomic_cmpxchg_inatomic(uaddr, 0, newval); - dec_preempt_count(); + pagefault_enable(); if (unlikely(curval == -EFAULT)) goto uaddr_faulted; @@ -1183,9 +1183,9 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec, uval = curval; newval = uval | FUTEX_WAITERS; - inc_preempt_count(); + pagefault_disable(); curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval); - dec_preempt_count(); + pagefault_enable(); if (unlikely(curval == -EFAULT)) goto uaddr_faulted; @@ -1215,10 +1215,10 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec, newval = current->pid | FUTEX_OWNER_DIED | FUTEX_WAITERS; - inc_preempt_count(); + pagefault_disable(); curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval); - dec_preempt_count(); + pagefault_enable(); if (unlikely(curval == -EFAULT)) goto uaddr_faulted; @@ -1390,9 +1390,9 @@ retry_locked: * anyone else up: */ if (!(uval & FUTEX_OWNER_DIED)) { - inc_preempt_count(); + pagefault_disable(); uval = futex_atomic_cmpxchg_inatomic(uaddr, current->pid, 0); - dec_preempt_count(); + pagefault_enable(); } if (unlikely(uval == -EFAULT)) -- cgit v1.2.3 From ad76fb6b5a5183255279e0ab5260715481770678 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 6 Dec 2006 20:32:21 -0800 Subject: [PATCH] mm: k{,um}map_atomic() vs in_atomic() Make kmap_atomic/kunmap_atomic denote a pagefault disabled scope. All non trivial implementations already do this anyway. Signed-off-by: Peter Zijlstra Acked-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-mips/highmem.h | 10 ++++++++-- include/linux/highmem.h | 8 +++++--- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/asm-mips/highmem.h b/include/asm-mips/highmem.h index c976bfaaba83..f8c8182f7f2e 100644 --- a/include/asm-mips/highmem.h +++ b/include/asm-mips/highmem.h @@ -21,6 +21,7 @@ #include #include +#include #include /* undef for production */ @@ -70,11 +71,16 @@ static inline void *kmap(struct page *page) static inline void *kmap_atomic(struct page *page, enum km_type type) { + pagefault_disable(); return page_address(page); } -static inline void kunmap_atomic(void *kvaddr, enum km_type type) { } -#define kmap_atomic_pfn(pfn, idx) page_address(pfn_to_page(pfn)) +static inline void kunmap_atomic(void *kvaddr, enum km_type type) +{ + pagefault_enable(); +} + +#define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx)) #define kmap_atomic_to_page(ptr) virt_to_page(ptr) diff --git a/include/linux/highmem.h b/include/linux/highmem.h index fd7d12daa94f..3d8768b619e9 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -3,6 +3,7 @@ #include #include +#include #include @@ -41,9 +42,10 @@ static inline void *kmap(struct page *page) #define kunmap(page) do { (void) (page); } while (0) -#define kmap_atomic(page, idx) page_address(page) -#define kunmap_atomic(addr, idx) do { } while (0) -#define kmap_atomic_pfn(pfn, idx) page_address(pfn_to_page(pfn)) +#define kmap_atomic(page, idx) \ + ({ pagefault_disable(); page_address(page); }) +#define kunmap_atomic(addr, idx) do { pagefault_enable(); } while (0) +#define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx)) #define kmap_atomic_to_page(ptr) virt_to_page(ptr) #endif -- cgit v1.2.3 From 8b98c1699eba23cfd2e8b366625c50ff5fd1415b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 6 Dec 2006 20:32:30 -0800 Subject: [PATCH] leak tracking for kmalloc_node We have variants of kmalloc and kmem_cache_alloc that leave leak tracking to the caller. This is used for subsystem-specific allocators like skb_alloc. To make skb_alloc node-aware we need similar routines for the node-aware slab allocator, which this patch adds. Note that the code is rather ugly, but it mirrors the non-node-aware code 1:1: [akpm@osdl.org: add module export] Signed-off-by: Christoph Hellwig Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 23 ++++++++++++++++++++++ mm/slab.c | 55 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 65 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index c4947b8a2c03..66c4640d3656 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -236,7 +236,25 @@ found: } return __kmalloc_node(size, flags, node); } + +/* + * kmalloc_node_track_caller is a special version of kmalloc_node that + * records the calling function of the routine calling it for slab leak + * tracking instead of just the calling function (confusing, eh?). + * It's useful when the call to kmalloc_node comes from a widely-used + * standard allocator where we care about the real place the memory + * allocation request comes from. + */ +#ifndef CONFIG_DEBUG_SLAB +#define kmalloc_node_track_caller(size, flags, node) \ + __kmalloc_node(size, flags, node) #else +extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *); +#define kmalloc_node_track_caller(size, flags, node) \ + __kmalloc_node_track_caller(size, flags, node, \ + __builtin_return_address(0)) +#endif +#else /* CONFIG_NUMA */ static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int node) { return kmem_cache_alloc(cachep, flags); @@ -245,6 +263,9 @@ static inline void *kmalloc_node(size_t size, gfp_t flags, int node) { return kmalloc(size, flags); } + +#define kmalloc_node_track_caller(size, flags, node) \ + kmalloc_track_caller(size, flags) #endif extern int FASTCALL(kmem_cache_reap(int)); @@ -283,6 +304,8 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) #define kzalloc(s, f) __kzalloc(s, f) #define kmalloc_track_caller kmalloc +#define kmalloc_node_track_caller kmalloc_node + #endif /* CONFIG_SLOB */ /* System wide caches */ diff --git a/mm/slab.c b/mm/slab.c index bfd654c0ef41..8f3f61cacb5c 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1015,7 +1015,7 @@ static inline void *alternate_node_alloc(struct kmem_cache *cachep, return NULL; } -static inline void *__cache_alloc_node(struct kmem_cache *cachep, +static inline void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) { return NULL; @@ -1023,7 +1023,7 @@ static inline void *__cache_alloc_node(struct kmem_cache *cachep, #else /* CONFIG_NUMA */ -static void *__cache_alloc_node(struct kmem_cache *, gfp_t, int); +static void *____cache_alloc_node(struct kmem_cache *, gfp_t, int); static void *alternate_node_alloc(struct kmem_cache *, gfp_t); static struct array_cache **alloc_alien_cache(int node, int limit) @@ -3130,10 +3130,10 @@ static __always_inline void *__cache_alloc(struct kmem_cache *cachep, objp = ____cache_alloc(cachep, flags); /* * We may just have run out of memory on the local node. - * __cache_alloc_node() knows how to locate memory on other nodes + * ____cache_alloc_node() knows how to locate memory on other nodes */ if (NUMA_BUILD && !objp) - objp = __cache_alloc_node(cachep, flags, numa_node_id()); + objp = ____cache_alloc_node(cachep, flags, numa_node_id()); local_irq_restore(save_flags); objp = cache_alloc_debugcheck_after(cachep, flags, objp, caller); @@ -3160,7 +3160,7 @@ static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags) else if (current->mempolicy) nid_alloc = slab_node(current->mempolicy); if (nid_alloc != nid_here) - return __cache_alloc_node(cachep, flags, nid_alloc); + return ____cache_alloc_node(cachep, flags, nid_alloc); return NULL; } @@ -3183,7 +3183,7 @@ void *fallback_alloc(struct kmem_cache *cache, gfp_t flags) if (zone_idx(*z) <= ZONE_NORMAL && cpuset_zone_allowed(*z, flags) && cache->nodelists[nid]) - obj = __cache_alloc_node(cache, + obj = ____cache_alloc_node(cache, flags | __GFP_THISNODE, nid); } return obj; @@ -3192,7 +3192,7 @@ void *fallback_alloc(struct kmem_cache *cache, gfp_t flags) /* * A interface to enable slab creation on nodeid */ -static void *__cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, +static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) { struct list_head *entry; @@ -3465,7 +3465,9 @@ out: * New and improved: it will now make sure that the object gets * put on the correct node list so that there is no false sharing. */ -void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) +static __always_inline void * +__cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, + int nodeid, void *caller) { unsigned long save_flags; void *ptr; @@ -3477,17 +3479,23 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) !cachep->nodelists[nodeid]) ptr = ____cache_alloc(cachep, flags); else - ptr = __cache_alloc_node(cachep, flags, nodeid); + ptr = ____cache_alloc_node(cachep, flags, nodeid); local_irq_restore(save_flags); - ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, - __builtin_return_address(0)); + ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, caller); return ptr; } + +void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) +{ + return __cache_alloc_node(cachep, flags, nodeid, + __builtin_return_address(0)); +} EXPORT_SYMBOL(kmem_cache_alloc_node); -void *__kmalloc_node(size_t size, gfp_t flags, int node) +static __always_inline void * +__do_kmalloc_node(size_t size, gfp_t flags, int node, void *caller) { struct kmem_cache *cachep; @@ -3496,8 +3504,29 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node) return NULL; return kmem_cache_alloc_node(cachep, flags, node); } + +#ifdef CONFIG_DEBUG_SLAB +void *__kmalloc_node(size_t size, gfp_t flags, int node) +{ + return __do_kmalloc_node(size, flags, node, + __builtin_return_address(0)); +} EXPORT_SYMBOL(__kmalloc_node); -#endif + +void *__kmalloc_node_track_caller(size_t size, gfp_t flags, + int node, void *caller) +{ + return __do_kmalloc_node(size, flags, node, caller); +} +EXPORT_SYMBOL(__kmalloc_node_track_caller); +#else +void *__kmalloc_node(size_t size, gfp_t flags, int node) +{ + return __do_kmalloc_node(size, flags, node, NULL); +} +EXPORT_SYMBOL(__kmalloc_node); +#endif /* CONFIG_DEBUG_SLAB */ +#endif /* CONFIG_NUMA */ /** * __do_kmalloc - allocate memory -- cgit v1.2.3 From 873481367edb18a7d0d7e5a285e6728c16bb44a9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 6 Dec 2006 20:32:33 -0800 Subject: [PATCH] add numa node information to struct device For node-aware skb allocations we need information about the node in struct net_device or struct device. Davem suggested to put it into struct device which this patch does. In particular: - struct device gets a new int numa_node member if CONFIG_NUMA is set - there are two new helpers, dev_to_node and set_dev_node to transparently deal with the non-numa case - for pci devices the node-info is set to the value we get from pcibus_to_node. Note that for some architectures pcibus_to_node doesn't work yet at the time we call it currently. This is harmless and will just mean skb allocations aren't node-local on this architectures until the implementation of pcibus_to_node on these architectures have been updated (There are patches for x86 and x86_64 floating around) [akpm@osdl.org: cleanup] Signed-off-by: Christoph Hellwig Cc: Christoph Lameter Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/core.c | 1 + drivers/pci/probe.c | 1 + include/linux/device.h | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+) (limited to 'include/linux') diff --git a/drivers/base/core.c b/drivers/base/core.c index e4b530ef757d..67b79a7592a9 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -386,6 +386,7 @@ void device_initialize(struct device *dev) INIT_LIST_HEAD(&dev->node); init_MUTEX(&dev->sem); device_init_wakeup(dev, 0); + set_dev_node(dev, -1); } #ifdef CONFIG_SYSFS_DEPRECATED diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0eeac60042b3..6a3c1e728900 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -873,6 +873,7 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.release = pci_release_dev; pci_dev_get(dev); + set_dev_node(&dev->dev, pcibus_to_node(bus)); dev->dev.dma_mask = &dev->dma_mask; dev->dev.coherent_dma_mask = 0xffffffffull; diff --git a/include/linux/device.h b/include/linux/device.h index 583a341e016c..49ab53ce92dc 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -371,6 +371,9 @@ struct device { core doesn't touch it */ struct dev_pm_info power; +#ifdef CONFIG_NUMA + int numa_node; /* NUMA node this device is close to */ +#endif u64 *dma_mask; /* dma mask (if dma'able device) */ u64 coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as @@ -394,6 +397,25 @@ struct device { void (*release)(struct device * dev); }; +#ifdef CONFIG_NUMA +static inline int dev_to_node(struct device *dev) +{ + return dev->numa_node; +} +static inline void set_dev_node(struct device *dev, int node) +{ + dev->numa_node = node; +} +#else +static inline int dev_to_node(struct device *dev) +{ + return -1; +} +static inline void set_dev_node(struct device *dev, int node) +{ +} +#endif + static inline void * dev_get_drvdata (struct device *dev) { -- cgit v1.2.3 From b30973f877fea1a3fb84e05599890fcc082a88e5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 6 Dec 2006 20:32:36 -0800 Subject: [PATCH] node-aware skb allocation Node-aware allocation of skbs for the receive path. Details: - __alloc_skb gets a new node argument and cals the node-aware slab functions with it. - netdev_alloc_skb passed the node number it gets from dev_to_node to it, everyone else passes -1 (any node) Signed-off-by: Christoph Hellwig Cc: Christoph Lameter Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/skbuff.h | 6 +++--- net/core/skbuff.c | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index a05a5f7c0b73..1d649f3eb006 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -332,17 +332,17 @@ struct sk_buff { extern void kfree_skb(struct sk_buff *skb); extern void __kfree_skb(struct sk_buff *skb); extern struct sk_buff *__alloc_skb(unsigned int size, - gfp_t priority, int fclone); + gfp_t priority, int fclone, int node); static inline struct sk_buff *alloc_skb(unsigned int size, gfp_t priority) { - return __alloc_skb(size, priority, 0); + return __alloc_skb(size, priority, 0, -1); } static inline struct sk_buff *alloc_skb_fclone(unsigned int size, gfp_t priority) { - return __alloc_skb(size, priority, 1); + return __alloc_skb(size, priority, 1, -1); } extern struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 8e1c385e5ba9..7217fb8928f2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -132,6 +132,7 @@ EXPORT_SYMBOL(skb_truesize_bug); * @gfp_mask: allocation mask * @fclone: allocate from fclone cache instead of head cache * and allocate a cloned (child) skb + * @node: numa node to allocate memory on * * Allocate a new &sk_buff. The returned buffer has no headroom and a * tail room of size bytes. The object has a reference count of one. @@ -141,7 +142,7 @@ EXPORT_SYMBOL(skb_truesize_bug); * %GFP_ATOMIC. */ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, - int fclone) + int fclone, int node) { kmem_cache_t *cache; struct skb_shared_info *shinfo; @@ -151,14 +152,14 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, cache = fclone ? skbuff_fclone_cache : skbuff_head_cache; /* Get the HEAD */ - skb = kmem_cache_alloc(cache, gfp_mask & ~__GFP_DMA); + skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node); if (!skb) goto out; /* Get the DATA. Size must match skb_add_mtu(). */ size = SKB_DATA_ALIGN(size); - data = kmalloc_track_caller(size + sizeof(struct skb_shared_info), - gfp_mask); + data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info), + gfp_mask, node); if (!data) goto nodata; @@ -267,9 +268,10 @@ nodata: struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int length, gfp_t gfp_mask) { + int node = dev->class_dev.dev ? dev_to_node(dev->class_dev.dev) : -1; struct sk_buff *skb; - skb = alloc_skb(length + NET_SKB_PAD, gfp_mask); + skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node); if (likely(skb)) { skb_reserve(skb, NET_SKB_PAD); skb->dev = dev; -- cgit v1.2.3 From 54cc211ce3fc73a9d21c6316886db0676beaca95 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:32:45 -0800 Subject: [PATCH] Remove bio_cachep from slab.h Remove bio_cachep from slab.h - it no longer exists. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index 66c4640d3656..6b7d096f056b 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -315,7 +315,6 @@ extern kmem_cache_t *files_cachep; extern kmem_cache_t *filp_cachep; extern kmem_cache_t *fs_cachep; extern kmem_cache_t *sighand_cachep; -extern kmem_cache_t *bio_cachep; #endif /* __KERNEL__ */ -- cgit v1.2.3 From 298ec1e2ac85cecce3eddd167286359358c44d5d Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:32:47 -0800 Subject: [PATCH] Move sighand_cachep to include/signal.h Move sighand_cachep definitioni to linux/signal.h The sighand cache is only used in fs/exec.c and kernel/fork.c. It is defined in kernel/fork.c but only used in fs/exec.c. The sighand_cachep is related to signal processing. So add the definition to signal.h. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/signal.h | 2 ++ include/linux/slab.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/signal.h b/include/linux/signal.h index 117135e33d67..14749056dd63 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -241,6 +241,8 @@ extern int sigprocmask(int, sigset_t *, sigset_t *); struct pt_regs; extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie); +extern struct kmem_cache *sighand_cachep; + #endif /* __KERNEL__ */ #endif /* _LINUX_SIGNAL_H */ diff --git a/include/linux/slab.h b/include/linux/slab.h index 6b7d096f056b..467b297d2c6f 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -314,7 +314,6 @@ extern kmem_cache_t *names_cachep; extern kmem_cache_t *files_cachep; extern kmem_cache_t *filp_cachep; extern kmem_cache_t *fs_cachep; -extern kmem_cache_t *sighand_cachep; #endif /* __KERNEL__ */ -- cgit v1.2.3 From c43692e85f306667545b91194c748a6e46c1f8b4 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:32:48 -0800 Subject: [PATCH] Move vm_area_cachep to include/mm.h vm_area_cachep is used to store vm_area_structs. So move to mm.h. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 2 ++ include/linux/slab.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index ab6e4974f379..840303769c11 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -114,6 +114,8 @@ struct vm_area_struct { #endif }; +extern struct kmem_cache *vm_area_cachep; + /* * This struct defines the per-mm list of VMAs for uClinux. If CONFIG_MMU is * disabled, then there's a single shared list of VMAs maintained by the diff --git a/include/linux/slab.h b/include/linux/slab.h index 467b297d2c6f..a30a4028a92e 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -309,7 +309,6 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) #endif /* CONFIG_SLOB */ /* System wide caches */ -extern kmem_cache_t *vm_area_cachep; extern kmem_cache_t *names_cachep; extern kmem_cache_t *files_cachep; extern kmem_cache_t *filp_cachep; -- cgit v1.2.3 From 5d6538fcf231faccb2ac42f92851d259d00e62f9 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:32:50 -0800 Subject: [PATCH] Move files_cachep to include/file.h Proper place is in file.h since files_cachep uses are rated to file I/O. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/file.h | 2 ++ include/linux/slab.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/file.h b/include/linux/file.h index 74183e6f7f45..be37423e9920 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -114,4 +114,6 @@ struct files_struct *get_files_struct(struct task_struct *); void FASTCALL(put_files_struct(struct files_struct *fs)); void reset_files_struct(struct task_struct *, struct files_struct *); +extern struct kmem_cache *files_cachep; + #endif /* __LINUX_FILE_H */ diff --git a/include/linux/slab.h b/include/linux/slab.h index a30a4028a92e..dd9efecff410 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -310,7 +310,6 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) /* System wide caches */ extern kmem_cache_t *names_cachep; -extern kmem_cache_t *files_cachep; extern kmem_cache_t *filp_cachep; extern kmem_cache_t *fs_cachep; -- cgit v1.2.3 From 8b7d91eb7f6a3e8f0caaa613937bda5ab7dc7dc2 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:32:52 -0800 Subject: [PATCH] Move filep_cachep to include/file.h filp_cachep is only used in fs/file_table.c and in fs/dcache.c where it is defined. Move it to related definitions in linux/file.h. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/file.h | 2 ++ include/linux/slab.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/file.h b/include/linux/file.h index be37423e9920..6e77b9177f9e 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -64,6 +64,8 @@ struct files_struct { #define files_fdtable(files) (rcu_dereference((files)->fdt)) +extern struct kmem_cache *filp_cachep; + extern void FASTCALL(__fput(struct file *)); extern void FASTCALL(fput(struct file *)); diff --git a/include/linux/slab.h b/include/linux/slab.h index dd9efecff410..f9202d60d769 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -310,7 +310,6 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) /* System wide caches */ extern kmem_cache_t *names_cachep; -extern kmem_cache_t *filp_cachep; extern kmem_cache_t *fs_cachep; #endif /* __KERNEL__ */ -- cgit v1.2.3 From aa362a83e78d2e9320da588805cf2a0b53356bc3 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:32:54 -0800 Subject: [PATCH] Move fs_cachep to linux/fs_struct.h fs_cachep is only used in kernel/exit.c and in kernel/fork.c. It is used to store fs_struct items so it should be placed in linux/fs_struct.h Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs_struct.h | 2 ++ include/linux/slab.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h index c623d12a486e..11a36ceddf73 100644 --- a/include/linux/fs_struct.h +++ b/include/linux/fs_struct.h @@ -18,6 +18,8 @@ struct fs_struct { .umask = 0022, \ } +extern struct kmem_cache *fs_cachep; + extern void exit_fs(struct task_struct *); extern void set_fs_altroot(void); extern void set_fs_root(struct fs_struct *, struct vfsmount *, struct dentry *); diff --git a/include/linux/slab.h b/include/linux/slab.h index f9202d60d769..bfc063ee94e8 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -310,7 +310,6 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) /* System wide caches */ extern kmem_cache_t *names_cachep; -extern kmem_cache_t *fs_cachep; #endif /* __KERNEL__ */ -- cgit v1.2.3 From b86c089b83b8ae2bc814db865057768a9ba787b5 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:32:57 -0800 Subject: [PATCH] Move names_cachep to linux/fs.h The names_cachep is used for getname() and putname(). So lets put it into fs.h near those two definitions. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 2 ++ include/linux/slab.h | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index cac7b1ef9543..a8039c8d8cbb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1481,6 +1481,8 @@ extern char * getname(const char __user *); extern void __init vfs_caches_init_early(void); extern void __init vfs_caches_init(unsigned long); +extern struct kmem_cache *names_cachep; + #define __getname() kmem_cache_alloc(names_cachep, SLAB_KERNEL) #define __putname(name) kmem_cache_free(names_cachep, (void *)(name)) #ifndef CONFIG_AUDITSYSCALL diff --git a/include/linux/slab.h b/include/linux/slab.h index bfc063ee94e8..e67314e4a0a0 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -308,9 +308,6 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) #endif /* CONFIG_SLOB */ -/* System wide caches */ -extern kmem_cache_t *names_cachep; - #endif /* __KERNEL__ */ #endif /* _LINUX_SLAB_H */ -- cgit v1.2.3 From ebe29738f3934ad6a93c8bd76e30aa5d797a269d Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:32:59 -0800 Subject: [PATCH] Remove uses of kmem_cache_t from mm/* and include/linux/slab.h Remove all uses of kmem_cache_t (the most were left in slab.h). The typedef for kmem_cache_t is then only necessary for other kernel subsystems. Add a comment to that effect. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index e67314e4a0a0..b831776b2fc7 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -9,6 +9,7 @@ #if defined(__KERNEL__) +/* kmem_cache_t exists for legacy reasons and is not used by code in mm */ typedef struct kmem_cache kmem_cache_t; #include @@ -57,22 +58,23 @@ typedef struct kmem_cache kmem_cache_t; /* prototypes */ extern void __init kmem_cache_init(void); -extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long, - void (*)(void *, kmem_cache_t *, unsigned long), - void (*)(void *, kmem_cache_t *, unsigned long)); -extern void kmem_cache_destroy(kmem_cache_t *); -extern int kmem_cache_shrink(kmem_cache_t *); -extern void *kmem_cache_alloc(kmem_cache_t *, gfp_t); +extern struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, + unsigned long, + void (*)(void *, struct kmem_cache *, unsigned long), + void (*)(void *, struct kmem_cache *, unsigned long)); +extern void kmem_cache_destroy(struct kmem_cache *); +extern int kmem_cache_shrink(struct kmem_cache *); +extern void *kmem_cache_alloc(struct kmem_cache *, gfp_t); extern void *kmem_cache_zalloc(struct kmem_cache *, gfp_t); -extern void kmem_cache_free(kmem_cache_t *, void *); -extern unsigned int kmem_cache_size(kmem_cache_t *); -extern const char *kmem_cache_name(kmem_cache_t *); +extern void kmem_cache_free(struct kmem_cache *, void *); +extern unsigned int kmem_cache_size(struct kmem_cache *); +extern const char *kmem_cache_name(struct kmem_cache *); /* Size description struct for general caches. */ struct cache_sizes { - size_t cs_size; - kmem_cache_t *cs_cachep; - kmem_cache_t *cs_dmacachep; + size_t cs_size; + struct kmem_cache *cs_cachep; + struct kmem_cache *cs_dmacachep; }; extern struct cache_sizes malloc_sizes[]; @@ -211,7 +213,7 @@ extern unsigned int ksize(const void *); extern int slab_is_available(void); #ifdef CONFIG_NUMA -extern void *kmem_cache_alloc_node(kmem_cache_t *, gfp_t flags, int node); +extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); extern void *__kmalloc_node(size_t size, gfp_t flags, int node); static inline void *kmalloc_node(size_t size, gfp_t flags, int node) @@ -255,7 +257,8 @@ extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *); __builtin_return_address(0)) #endif #else /* CONFIG_NUMA */ -static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int node) +static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep, + gfp_t flags, int node) { return kmem_cache_alloc(cachep, flags); } @@ -269,7 +272,7 @@ static inline void *kmalloc_node(size_t size, gfp_t flags, int node) #endif extern int FASTCALL(kmem_cache_reap(int)); -extern int FASTCALL(kmem_ptr_validate(kmem_cache_t *cachep, void *ptr)); +extern int FASTCALL(kmem_ptr_validate(struct kmem_cache *cachep, void *ptr)); #else /* CONFIG_SLOB */ -- cgit v1.2.3 From 25ba77c141dbcd2602dd0171824d0d72aa023a01 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Wed, 6 Dec 2006 20:33:03 -0800 Subject: [PATCH] numa node ids are int, page_to_nid and zone_to_nid should return int NUMA node ids are passed as either int or unsigned int almost exclusivly page_to_nid and zone_to_nid both return unsigned long. This is a throw back to when page_to_nid was a #define and was thus exposing the real type of the page flags field. In addition to fixing up the definitions of page_to_nid and zone_to_nid I audited the users of these functions identifying the following incorrect uses: 1) mm/page_alloc.c show_node() -- printk dumping the node id, 2) include/asm-ia64/pgalloc.h pgtable_quicklist_free() -- comparison against numa_node_id() which returns an int from cpu_to_node(), and 3) mm/mpolicy.c check_pte_range -- used as an index in node_isset which uses bit_set which in generic code takes an int. Signed-off-by: Andy Whitcroft Cc: Christoph Lameter Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-ia64/pgalloc.h | 2 +- include/linux/mm.h | 6 +++--- mm/mempolicy.c | 2 +- mm/page_alloc.c | 2 +- mm/sparse.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h index 9cb68e9b377e..393e04c42a2c 100644 --- a/include/asm-ia64/pgalloc.h +++ b/include/asm-ia64/pgalloc.h @@ -60,7 +60,7 @@ static inline void *pgtable_quicklist_alloc(void) static inline void pgtable_quicklist_free(void *pgtable_entry) { #ifdef CONFIG_NUMA - unsigned long nid = page_to_nid(virt_to_page(pgtable_entry)); + int nid = page_to_nid(virt_to_page(pgtable_entry)); if (unlikely(nid != numa_node_id())) { free_page((unsigned long)pgtable_entry); diff --git a/include/linux/mm.h b/include/linux/mm.h index 840303769c11..0e266fe1b4c4 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -456,7 +456,7 @@ static inline int page_zone_id(struct page *page) return (page->flags >> ZONEID_PGSHIFT) & ZONEID_MASK; } -static inline unsigned long zone_to_nid(struct zone *zone) +static inline int zone_to_nid(struct zone *zone) { #ifdef CONFIG_NUMA return zone->node; @@ -466,9 +466,9 @@ static inline unsigned long zone_to_nid(struct zone *zone) } #ifdef NODE_NOT_IN_PAGE_FLAGS -extern unsigned long page_to_nid(struct page *page); +extern int page_to_nid(struct page *page); #else -static inline unsigned long page_to_nid(struct page *page) +static inline int page_to_nid(struct page *page) { return (page->flags >> NODES_PGSHIFT) & NODES_MASK; } diff --git a/mm/mempolicy.c b/mm/mempolicy.c index fb907236bbd8..e7b69c90cfd6 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -221,7 +221,7 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, orig_pte = pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); do { struct page *page; - unsigned int nid; + int nid; if (!pte_present(*pte)) continue; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 86f2984f8b79..614d427854a8 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1407,7 +1407,7 @@ unsigned int nr_free_pagecache_pages(void) static inline void show_node(struct zone *zone) { if (NUMA_BUILD) - printk("Node %ld ", zone_to_nid(zone)); + printk("Node %d ", zone_to_nid(zone)); } void si_meminfo(struct sysinfo *val) diff --git a/mm/sparse.c b/mm/sparse.c index 158d6a2a5263..ac26eb0d73cd 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -36,7 +36,7 @@ static u8 section_to_node_table[NR_MEM_SECTIONS] __cacheline_aligned; static u16 section_to_node_table[NR_MEM_SECTIONS] __cacheline_aligned; #endif -unsigned long page_to_nid(struct page *page) +int page_to_nid(struct page *page) { return section_to_node_table[page_to_section(page)]; } -- cgit v1.2.3 From 6e0eaa4b05cf53ca5caa702fd2760a5b3376be69 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:33:10 -0800 Subject: [PATCH] slab: remove SLAB_NO_GROW It is only used internally in the slab. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 2 -- mm/slab.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index b831776b2fc7..9ffd1c1616bd 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -28,8 +28,6 @@ typedef struct kmem_cache kmem_cache_t; #define SLAB_LEVEL_MASK GFP_LEVEL_MASK -#define SLAB_NO_GROW __GFP_NO_GROW /* don't grow a cache */ - /* flags to pass to kmem_cache_create(). * The first 3 are only valid when the allocator as been build * SLAB_DEBUG_SUPPORT. diff --git a/mm/slab.c b/mm/slab.c index 8f3f61cacb5c..e853dfe8fd7b 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2721,8 +2721,8 @@ static int cache_grow(struct kmem_cache *cachep, gfp_t flags, int nodeid) * Be lazy and only check for valid flags here, keeping it out of the * critical path in kmem_cache_alloc(). */ - BUG_ON(flags & ~(SLAB_DMA | SLAB_LEVEL_MASK | SLAB_NO_GROW)); - if (flags & SLAB_NO_GROW) + BUG_ON(flags & ~(SLAB_DMA | SLAB_LEVEL_MASK | __GFP_NO_GROW)); + if (flags & __GFP_NO_GROW) return 0; ctor_flags = SLAB_CTOR_CONSTRUCTOR; -- cgit v1.2.3 From a06d72c1dcbff015250df6ad9f0b1d18c02113bf Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:33:12 -0800 Subject: [PATCH] slab: remove SLAB_LEVEL_MASK SLAB_LEVEL_MASK is only used internally to the slab and is and alias of GFP_LEVEL_MASK. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 2 -- mm/slab.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index 9ffd1c1616bd..6f7b9bb43065 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -26,8 +26,6 @@ typedef struct kmem_cache kmem_cache_t; #define SLAB_KERNEL GFP_KERNEL #define SLAB_DMA GFP_DMA -#define SLAB_LEVEL_MASK GFP_LEVEL_MASK - /* flags to pass to kmem_cache_create(). * The first 3 are only valid when the allocator as been build * SLAB_DEBUG_SUPPORT. diff --git a/mm/slab.c b/mm/slab.c index e853dfe8fd7b..9f34b4946fba 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2721,12 +2721,12 @@ static int cache_grow(struct kmem_cache *cachep, gfp_t flags, int nodeid) * Be lazy and only check for valid flags here, keeping it out of the * critical path in kmem_cache_alloc(). */ - BUG_ON(flags & ~(SLAB_DMA | SLAB_LEVEL_MASK | __GFP_NO_GROW)); + BUG_ON(flags & ~(SLAB_DMA | GFP_LEVEL_MASK | __GFP_NO_GROW)); if (flags & __GFP_NO_GROW) return 0; ctor_flags = SLAB_CTOR_CONSTRUCTOR; - local_flags = (flags & SLAB_LEVEL_MASK); + local_flags = (flags & GFP_LEVEL_MASK); if (!(local_flags & __GFP_WAIT)) /* * Not allowed to sleep. Need to tell a constructor about -- cgit v1.2.3 From 55acbda0965ca0a29b0ca276e7d17a55edc11d1b Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:33:13 -0800 Subject: [PATCH] slab: remove SLAB_NOIO SLAB_NOIO is an alias of GFP_NOIO with a single instance of use. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/storage/transport.c | 2 +- include/linux/slab.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 47644b5b6155..323293a3e61f 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -427,7 +427,7 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__, length, num_sg); result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0, - sg, num_sg, length, SLAB_NOIO); + sg, num_sg, length, GFP_NOIO); if (result) { US_DEBUGP("usb_sg_init returned %d\n", result); return USB_STOR_XFER_ERROR; diff --git a/include/linux/slab.h b/include/linux/slab.h index 6f7b9bb43065..43ced80c327b 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -20,7 +20,6 @@ typedef struct kmem_cache kmem_cache_t; /* flags for kmem_cache_alloc() */ #define SLAB_NOFS GFP_NOFS -#define SLAB_NOIO GFP_NOIO #define SLAB_ATOMIC GFP_ATOMIC #define SLAB_USER GFP_USER #define SLAB_KERNEL GFP_KERNEL -- cgit v1.2.3 From e6b4f8da3a88457148038bc952043e99a7fdba64 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:33:14 -0800 Subject: [PATCH] slab: remove SLAB_NOFS SLAB_NOFS is an alias of GFP_NOFS. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/cifs/misc.c | 4 ++-- fs/cifs/transport.c | 2 +- fs/dquot.c | 2 +- fs/ext3/super.c | 2 +- fs/ext4/super.c | 2 +- fs/hpfs/super.c | 2 +- fs/nfs/read.c | 2 +- fs/nfs/write.c | 4 ++-- fs/ntfs/attrib.c | 2 +- fs/ntfs/index.c | 2 +- fs/ntfs/inode.c | 4 ++-- fs/ntfs/unistr.c | 2 +- fs/ocfs2/dlm/dlmfs.c | 2 +- fs/ocfs2/super.c | 2 +- include/linux/slab.h | 1 - 15 files changed, 17 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index bbc9cd34b6ea..8355daff504c 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -153,7 +153,7 @@ cifs_buf_get(void) albeit slightly larger than necessary and maxbuffersize defaults to this and can not be bigger */ ret_buf = - (struct smb_hdr *) mempool_alloc(cifs_req_poolp, SLAB_KERNEL | SLAB_NOFS); + (struct smb_hdr *) mempool_alloc(cifs_req_poolp, SLAB_KERNEL | GFP_NOFS); /* clear the first few header bytes */ /* for most paths, more is cleared in header_assemble */ @@ -192,7 +192,7 @@ cifs_small_buf_get(void) albeit slightly larger than necessary and maxbuffersize defaults to this and can not be bigger */ ret_buf = - (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, SLAB_KERNEL | SLAB_NOFS); + (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, SLAB_KERNEL | GFP_NOFS); if (ret_buf) { /* No need to clear memory here, cleared in header assemble */ /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 48d47b46b1fb..7514237cf31a 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -51,7 +51,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) } temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp, - SLAB_KERNEL | SLAB_NOFS); + SLAB_KERNEL | GFP_NOFS); if (temp == NULL) return temp; else { diff --git a/fs/dquot.c b/fs/dquot.c index 9af789567e51..c6ae6c0e0cfc 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -600,7 +600,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) { struct dquot *dquot; - dquot = kmem_cache_alloc(dquot_cachep, SLAB_NOFS); + dquot = kmem_cache_alloc(dquot_cachep, GFP_NOFS); if(!dquot) return NODQUOT; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index afc2d4f42d77..0cf633f0cfa3 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -445,7 +445,7 @@ static struct inode *ext3_alloc_inode(struct super_block *sb) { struct ext3_inode_info *ei; - ei = kmem_cache_alloc(ext3_inode_cachep, SLAB_NOFS); + ei = kmem_cache_alloc(ext3_inode_cachep, GFP_NOFS); if (!ei) return NULL; #ifdef CONFIG_EXT3_FS_POSIX_ACL diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b4b022aa2bc2..c730cbc84030 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -495,7 +495,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) { struct ext4_inode_info *ei; - ei = kmem_cache_alloc(ext4_inode_cachep, SLAB_NOFS); + ei = kmem_cache_alloc(ext4_inode_cachep, GFP_NOFS); if (!ei) return NULL; #ifdef CONFIG_EXT4DEV_FS_POSIX_ACL diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 450b5e0b4785..46ceadd6f16a 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -165,7 +165,7 @@ static kmem_cache_t * hpfs_inode_cachep; static struct inode *hpfs_alloc_inode(struct super_block *sb) { struct hpfs_inode_info *ei; - ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, SLAB_NOFS); + ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS); if (!ei) return NULL; ei->vfs_inode.i_version = 1; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index c2e49c397a27..56f66f0ccb6a 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -46,7 +46,7 @@ static mempool_t *nfs_rdata_mempool; struct nfs_read_data *nfs_readdata_alloc(size_t len) { unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; - struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, SLAB_NOFS); + struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS); if (p) { memset(p, 0, sizeof(*p)); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 883dd4a1c157..f7dd0d005957 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -93,7 +93,7 @@ static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion); struct nfs_write_data *nfs_commit_alloc(void) { - struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); + struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); if (p) { memset(p, 0, sizeof(*p)); @@ -112,7 +112,7 @@ void nfs_commit_free(struct nfs_write_data *p) struct nfs_write_data *nfs_writedata_alloc(size_t len) { unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; - struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, SLAB_NOFS); + struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); if (p) { memset(p, 0, sizeof(*p)); diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 9f08e851cfb6..c577d8e1bd95 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1272,7 +1272,7 @@ ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) { ntfs_attr_search_ctx *ctx; - ctx = kmem_cache_alloc(ntfs_attr_ctx_cache, SLAB_NOFS); + ctx = kmem_cache_alloc(ntfs_attr_ctx_cache, GFP_NOFS); if (ctx) ntfs_attr_init_search_ctx(ctx, ni, mrec); return ctx; diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index e32cde486362..2194eff49743 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -38,7 +38,7 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni) { ntfs_index_context *ictx; - ictx = kmem_cache_alloc(ntfs_index_ctx_cache, SLAB_NOFS); + ictx = kmem_cache_alloc(ntfs_index_ctx_cache, GFP_NOFS); if (ictx) *ictx = (ntfs_index_context){ .idx_ni = idx_ni }; return ictx; diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 2d3de9c89818..247989891b4b 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -324,7 +324,7 @@ struct inode *ntfs_alloc_big_inode(struct super_block *sb) ntfs_inode *ni; ntfs_debug("Entering."); - ni = kmem_cache_alloc(ntfs_big_inode_cache, SLAB_NOFS); + ni = kmem_cache_alloc(ntfs_big_inode_cache, GFP_NOFS); if (likely(ni != NULL)) { ni->state = 0; return VFS_I(ni); @@ -349,7 +349,7 @@ static inline ntfs_inode *ntfs_alloc_extent_inode(void) ntfs_inode *ni; ntfs_debug("Entering."); - ni = kmem_cache_alloc(ntfs_inode_cache, SLAB_NOFS); + ni = kmem_cache_alloc(ntfs_inode_cache, GFP_NOFS); if (likely(ni != NULL)) { ni->state = 0; return ni; diff --git a/fs/ntfs/unistr.c b/fs/ntfs/unistr.c index 6a495f7369f9..005ca4b0f132 100644 --- a/fs/ntfs/unistr.c +++ b/fs/ntfs/unistr.c @@ -266,7 +266,7 @@ int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins, /* We do not trust outside sources. */ if (likely(ins)) { - ucs = kmem_cache_alloc(ntfs_name_cache, SLAB_NOFS); + ucs = kmem_cache_alloc(ntfs_name_cache, GFP_NOFS); if (likely(ucs)) { for (i = o = 0; i < ins_len; i += wc_len) { wc_len = nls->char2uni(ins + i, ins_len - i, diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index 16b8d1ba7066..01f91501f70a 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c @@ -276,7 +276,7 @@ static struct inode *dlmfs_alloc_inode(struct super_block *sb) { struct dlmfs_inode_private *ip; - ip = kmem_cache_alloc(dlmfs_inode_cache, SLAB_NOFS); + ip = kmem_cache_alloc(dlmfs_inode_cache, GFP_NOFS); if (!ip) return NULL; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index d9b4214a12da..7574d26ee0ff 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -303,7 +303,7 @@ static struct inode *ocfs2_alloc_inode(struct super_block *sb) { struct ocfs2_inode_info *oi; - oi = kmem_cache_alloc(ocfs2_inode_cachep, SLAB_NOFS); + oi = kmem_cache_alloc(ocfs2_inode_cachep, GFP_NOFS); if (!oi) return NULL; diff --git a/include/linux/slab.h b/include/linux/slab.h index 43ced80c327b..5b70d52b4f86 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -19,7 +19,6 @@ typedef struct kmem_cache kmem_cache_t; #include /* kmalloc_sizes.h needs L1_CACHE_BYTES */ /* flags for kmem_cache_alloc() */ -#define SLAB_NOFS GFP_NOFS #define SLAB_ATOMIC GFP_ATOMIC #define SLAB_USER GFP_USER #define SLAB_KERNEL GFP_KERNEL -- cgit v1.2.3 From f7267c0c0721fd02ad3dc37c3d6dd24ccd81d4d6 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:33:15 -0800 Subject: [PATCH] slab: remove SLAB_USER SLAB_USER is an alias of GFP_USER Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ecryptfs/crypto.c | 4 ++-- fs/ecryptfs/inode.c | 2 +- include/linux/slab.h | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index f63a7755fe86..776b2eed371e 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1334,7 +1334,7 @@ int ecryptfs_write_headers(struct dentry *ecryptfs_dentry, goto out; } /* Released in this function */ - page_virt = kmem_cache_alloc(ecryptfs_header_cache_0, SLAB_USER); + page_virt = kmem_cache_alloc(ecryptfs_header_cache_0, GFP_USER); if (!page_virt) { ecryptfs_printk(KERN_ERR, "Out of memory\n"); rc = -ENOMEM; @@ -1493,7 +1493,7 @@ int ecryptfs_read_headers(struct dentry *ecryptfs_dentry, &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; /* Read the first page from the underlying file */ - page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, SLAB_USER); + page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, GFP_USER); if (!page_virt) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Unable to allocate page_virt\n"); diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index dfcc68484f47..70911412044d 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -404,7 +404,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, /* Released in this function */ page_virt = (char *)kmem_cache_alloc(ecryptfs_header_cache_2, - SLAB_USER); + GFP_USER); if (!page_virt) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, diff --git a/include/linux/slab.h b/include/linux/slab.h index 5b70d52b4f86..d7ee28e51330 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -20,7 +20,6 @@ typedef struct kmem_cache kmem_cache_t; /* flags for kmem_cache_alloc() */ #define SLAB_ATOMIC GFP_ATOMIC -#define SLAB_USER GFP_USER #define SLAB_KERNEL GFP_KERNEL #define SLAB_DMA GFP_DMA -- cgit v1.2.3 From 54e6ecb23951b195d02433a741c7f7cb0b796c78 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:33:16 -0800 Subject: [PATCH] slab: remove SLAB_ATOMIC SLAB_ATOMIC is an alias of GFP_ATOMIC Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/atm/he.c | 2 +- drivers/base/dmapool.c | 2 +- drivers/block/DAC960.c | 4 ++-- drivers/char/watchdog/pcwd_usb.c | 2 +- drivers/ieee1394/raw1394.c | 30 +++++++++++++++--------------- drivers/infiniband/hw/amso1100/c2_vq.c | 2 +- drivers/infiniband/hw/mthca/mthca_av.c | 2 +- drivers/isdn/gigaset/bas-gigaset.c | 20 ++++++++++---------- drivers/isdn/gigaset/usb-gigaset.c | 6 +++--- drivers/media/dvb/dvb-usb/usb-urb.c | 2 +- drivers/media/dvb/ttusb-dec/ttusb_dec.c | 2 +- drivers/s390/scsi/zfcp_fsf.c | 2 +- drivers/usb/core/hub.c | 2 +- drivers/usb/core/message.c | 2 +- drivers/usb/host/ehci-dbg.c | 2 +- drivers/usb/host/hc_crisv10.c | 10 +++++----- drivers/usb/host/ohci-dbg.c | 2 +- drivers/usb/host/uhci-q.c | 2 +- drivers/usb/input/aiptek.c | 2 +- drivers/usb/input/ati_remote.c | 6 +++--- drivers/usb/input/hid-core.c | 10 +++++----- drivers/usb/input/keyspan_remote.c | 2 +- drivers/usb/input/mtouchusb.c | 2 +- drivers/usb/input/powermate.c | 4 ++-- drivers/usb/input/touchkitusb.c | 2 +- drivers/usb/input/usbkbd.c | 8 ++++---- drivers/usb/input/usbmouse.c | 4 ++-- drivers/usb/input/xpad.c | 2 +- drivers/usb/input/yealink.c | 6 +++--- drivers/usb/misc/phidgetkit.c | 4 ++-- drivers/usb/misc/phidgetmotorcontrol.c | 4 ++-- drivers/usb/misc/usbtest.c | 8 ++++---- drivers/usb/mon/mon_text.c | 4 ++-- drivers/usb/net/catc.c | 2 +- drivers/usb/net/net1080.c | 2 +- drivers/usb/net/pegasus.c | 2 +- drivers/usb/net/rtl8150.c | 2 +- drivers/usb/serial/mos7720.c | 2 +- drivers/usb/serial/mos7840.c | 4 ++-- drivers/usb/storage/onetouch.c | 4 ++-- include/linux/slab.h | 1 - include/net/request_sock.h | 2 +- net/core/dst.c | 2 +- net/core/flow.c | 2 +- net/core/neighbour.c | 2 +- net/dccp/ccids/ccid3.c | 6 +++--- net/dccp/ccids/lib/loss_interval.c | 2 +- net/ipv4/inet_hashtables.c | 2 +- net/ipv4/inet_timewait_sock.c | 2 +- net/ipv6/ip6_fib.c | 2 +- net/ipv6/xfrm6_tunnel.c | 2 +- net/sctp/sm_make_chunk.c | 2 +- net/sctp/socket.c | 2 +- net/xfrm/xfrm_input.c | 2 +- security/selinux/avc.c | 2 +- 55 files changed, 107 insertions(+), 108 deletions(-) (limited to 'include/linux') diff --git a/drivers/atm/he.c b/drivers/atm/he.c index c7314a79da0f..2a2f0fc2288f 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -1724,7 +1724,7 @@ __alloc_tpd(struct he_dev *he_dev) struct he_tpd *tpd; dma_addr_t dma_handle; - tpd = pci_pool_alloc(he_dev->tpd_pool, SLAB_ATOMIC|SLAB_DMA, &dma_handle); + tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|SLAB_DMA, &dma_handle); if (tpd == NULL) return NULL; diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index b2efbd4cf710..fa4675254f67 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c @@ -297,7 +297,7 @@ restart: } } } - if (!(page = pool_alloc_page (pool, SLAB_ATOMIC))) { + if (!(page = pool_alloc_page (pool, GFP_ATOMIC))) { if (mem_flags & __GFP_WAIT) { DECLARE_WAITQUEUE (wait, current); diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 742d07403101..8d81a3a64c07 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -324,13 +324,13 @@ static boolean DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller) Command->Next = Controller->FreeCommands; Controller->FreeCommands = Command; Controller->Commands[CommandIdentifier-1] = Command; - ScatterGatherCPU = pci_pool_alloc(ScatterGatherPool, SLAB_ATOMIC, + ScatterGatherCPU = pci_pool_alloc(ScatterGatherPool, GFP_ATOMIC, &ScatterGatherDMA); if (ScatterGatherCPU == NULL) return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION"); if (RequestSensePool != NULL) { - RequestSenseCPU = pci_pool_alloc(RequestSensePool, SLAB_ATOMIC, + RequestSenseCPU = pci_pool_alloc(RequestSensePool, GFP_ATOMIC, &RequestSenseDMA); if (RequestSenseCPU == NULL) { pci_pool_free(ScatterGatherPool, ScatterGatherCPU, diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index e275dd4a705d..61138726b501 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c @@ -634,7 +634,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8); /* set up the memory buffer's */ - if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, SLAB_ATOMIC, &usb_pcwd->intr_dma))) { + if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma))) { printk(KERN_ERR PFX "Out of memory\n"); goto error; } diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 5ec4f5eb6b19..47f6a4e29b40 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -259,7 +259,7 @@ static void host_reset(struct hpsb_host *host) if (hi != NULL) { list_for_each_entry(fi, &hi->file_info_list, list) { if (fi->notification == RAW1394_NOTIFY_ON) { - req = __alloc_pending_request(SLAB_ATOMIC); + req = __alloc_pending_request(GFP_ATOMIC); if (req != NULL) { req->file_info = fi; @@ -306,13 +306,13 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t * data, if (!(fi->listen_channels & (1ULL << channel))) continue; - req = __alloc_pending_request(SLAB_ATOMIC); + req = __alloc_pending_request(GFP_ATOMIC); if (!req) break; if (!ibs) { ibs = kmalloc(sizeof(*ibs) + length, - SLAB_ATOMIC); + GFP_ATOMIC); if (!ibs) { kfree(req); break; @@ -367,13 +367,13 @@ static void fcp_request(struct hpsb_host *host, int nodeid, int direction, if (!fi->fcp_buffer) continue; - req = __alloc_pending_request(SLAB_ATOMIC); + req = __alloc_pending_request(GFP_ATOMIC); if (!req) break; if (!ibs) { ibs = kmalloc(sizeof(*ibs) + length, - SLAB_ATOMIC); + GFP_ATOMIC); if (!ibs) { kfree(req); break; @@ -593,7 +593,7 @@ static int state_initialized(struct file_info *fi, struct pending_request *req) switch (req->req.type) { case RAW1394_REQ_LIST_CARDS: spin_lock_irqsave(&host_info_lock, flags); - khl = kmalloc(sizeof(*khl) * host_count, SLAB_ATOMIC); + khl = kmalloc(sizeof(*khl) * host_count, GFP_ATOMIC); if (khl) { req->req.misc = host_count; @@ -1045,7 +1045,7 @@ static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer, } if (arm_addr->notification_options & ARM_READ) { DBGMSG("arm_read -> entering notification-section"); - req = __alloc_pending_request(SLAB_ATOMIC); + req = __alloc_pending_request(GFP_ATOMIC); if (!req) { DBGMSG("arm_read -> rcode_conflict_error"); spin_unlock_irqrestore(&host_info_lock, irqflags); @@ -1064,7 +1064,7 @@ static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer, sizeof(struct arm_response) + sizeof(struct arm_request_response); } - req->data = kmalloc(size, SLAB_ATOMIC); + req->data = kmalloc(size, GFP_ATOMIC); if (!(req->data)) { free_pending_request(req); DBGMSG("arm_read -> rcode_conflict_error"); @@ -1198,7 +1198,7 @@ static int arm_write(struct hpsb_host *host, int nodeid, int destid, } if (arm_addr->notification_options & ARM_WRITE) { DBGMSG("arm_write -> entering notification-section"); - req = __alloc_pending_request(SLAB_ATOMIC); + req = __alloc_pending_request(GFP_ATOMIC); if (!req) { DBGMSG("arm_write -> rcode_conflict_error"); spin_unlock_irqrestore(&host_info_lock, irqflags); @@ -1209,7 +1209,7 @@ static int arm_write(struct hpsb_host *host, int nodeid, int destid, sizeof(struct arm_request) + sizeof(struct arm_response) + (length) * sizeof(byte_t) + sizeof(struct arm_request_response); - req->data = kmalloc(size, SLAB_ATOMIC); + req->data = kmalloc(size, GFP_ATOMIC); if (!(req->data)) { free_pending_request(req); DBGMSG("arm_write -> rcode_conflict_error"); @@ -1400,7 +1400,7 @@ static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store, if (arm_addr->notification_options & ARM_LOCK) { byte_t *buf1, *buf2; DBGMSG("arm_lock -> entering notification-section"); - req = __alloc_pending_request(SLAB_ATOMIC); + req = __alloc_pending_request(GFP_ATOMIC); if (!req) { DBGMSG("arm_lock -> rcode_conflict_error"); spin_unlock_irqrestore(&host_info_lock, irqflags); @@ -1408,7 +1408,7 @@ static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store, The request may be retried */ } size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response); /* maximum */ - req->data = kmalloc(size, SLAB_ATOMIC); + req->data = kmalloc(size, GFP_ATOMIC); if (!(req->data)) { free_pending_request(req); DBGMSG("arm_lock -> rcode_conflict_error"); @@ -1628,7 +1628,7 @@ static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store, if (arm_addr->notification_options & ARM_LOCK) { byte_t *buf1, *buf2; DBGMSG("arm_lock64 -> entering notification-section"); - req = __alloc_pending_request(SLAB_ATOMIC); + req = __alloc_pending_request(GFP_ATOMIC); if (!req) { spin_unlock_irqrestore(&host_info_lock, irqflags); DBGMSG("arm_lock64 -> rcode_conflict_error"); @@ -1636,7 +1636,7 @@ static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store, The request may be retried */ } size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response); /* maximum */ - req->data = kmalloc(size, SLAB_ATOMIC); + req->data = kmalloc(size, GFP_ATOMIC); if (!(req->data)) { free_pending_request(req); spin_unlock_irqrestore(&host_info_lock, irqflags); @@ -2443,7 +2443,7 @@ static void queue_rawiso_event(struct file_info *fi) /* only one ISO activity event may be in the queue */ if (!__rawiso_event_in_queue(fi)) { struct pending_request *req = - __alloc_pending_request(SLAB_ATOMIC); + __alloc_pending_request(GFP_ATOMIC); if (req) { req->file_info = fi; diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c index 40caeb5f41b4..36620a22413c 100644 --- a/drivers/infiniband/hw/amso1100/c2_vq.c +++ b/drivers/infiniband/hw/amso1100/c2_vq.c @@ -164,7 +164,7 @@ void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r) */ void *vq_repbuf_alloc(struct c2_dev *c2dev) { - return kmem_cache_alloc(c2dev->host_msg_cache, SLAB_ATOMIC); + return kmem_cache_alloc(c2dev->host_msg_cache, GFP_ATOMIC); } /* diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c index 57cdc1bc5f50..27caf3b0648a 100644 --- a/drivers/infiniband/hw/mthca/mthca_av.c +++ b/drivers/infiniband/hw/mthca/mthca_av.c @@ -189,7 +189,7 @@ int mthca_create_ah(struct mthca_dev *dev, on_hca_fail: if (ah->type == MTHCA_AH_PCI_POOL) { ah->av = pci_pool_alloc(dev->av_table.pool, - SLAB_ATOMIC, &ah->avdma); + GFP_ATOMIC, &ah->avdma); if (!ah->av) return -ENOMEM; diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 0c937325a1b3..5857e7e23f84 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -572,7 +572,7 @@ static int atread_submit(struct cardstate *cs, int timeout) ucs->rcvbuf, ucs->rcvbuf_size, read_ctrl_callback, cs->inbuf); - if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) { + if ((ret = usb_submit_urb(ucs->urb_cmd_in, GFP_ATOMIC)) != 0) { update_basstate(ucs, 0, BS_ATRDPEND); dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", get_usb_rcmsg(ret)); @@ -747,7 +747,7 @@ static void read_int_callback(struct urb *urb) check_pending(ucs); resubmit: - rc = usb_submit_urb(urb, SLAB_ATOMIC); + rc = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(rc != 0 && rc != -ENODEV)) { dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", get_usb_rcmsg(rc)); @@ -807,7 +807,7 @@ static void read_iso_callback(struct urb *urb) urb->number_of_packets = BAS_NUMFRAMES; gig_dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit", __func__); - rc = usb_submit_urb(urb, SLAB_ATOMIC); + rc = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(rc != 0 && rc != -ENODEV)) { dev_err(bcs->cs->dev, "could not resubmit isochronous read " @@ -900,7 +900,7 @@ static int starturbs(struct bc_state *bcs) } dump_urb(DEBUG_ISO, "Initial isoc read", urb); - if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) + if ((rc = usb_submit_urb(urb, GFP_ATOMIC)) != 0) goto error; } @@ -935,7 +935,7 @@ static int starturbs(struct bc_state *bcs) /* submit two URBs, keep third one */ for (k = 0; k < 2; ++k) { dump_urb(DEBUG_ISO, "Initial isoc write", urb); - rc = usb_submit_urb(ubc->isoouturbs[k].urb, SLAB_ATOMIC); + rc = usb_submit_urb(ubc->isoouturbs[k].urb, GFP_ATOMIC); if (rc != 0) goto error; } @@ -1042,7 +1042,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) return 0; /* no data to send */ urb->number_of_packets = nframe; - rc = usb_submit_urb(urb, SLAB_ATOMIC); + rc = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(rc)) { if (rc == -ENODEV) /* device removed - give up silently */ @@ -1341,7 +1341,7 @@ static void read_iso_tasklet(unsigned long data) urb->dev = bcs->cs->hw.bas->udev; urb->transfer_flags = URB_ISO_ASAP; urb->number_of_packets = BAS_NUMFRAMES; - rc = usb_submit_urb(urb, SLAB_ATOMIC); + rc = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(rc != 0 && rc != -ENODEV)) { dev_err(cs->dev, "could not resubmit isochronous read URB: %s\n", @@ -1458,7 +1458,7 @@ static void write_ctrl_callback(struct urb *urb) ucs->retry_ctrl); /* urb->dev is clobbered by USB subsystem */ urb->dev = ucs->udev; - rc = usb_submit_urb(urb, SLAB_ATOMIC); + rc = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(rc)) { dev_err(&ucs->interface->dev, "could not resubmit request 0x%02x: %s\n", @@ -1517,7 +1517,7 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) (unsigned char*) &ucs->dr_ctrl, NULL, 0, write_ctrl_callback, ucs); ucs->retry_ctrl = 0; - ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC); + ret = usb_submit_urb(ucs->urb_ctrl, GFP_ATOMIC); if (unlikely(ret)) { dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n", req, get_usb_rcmsg(ret)); @@ -1763,7 +1763,7 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) usb_sndctrlpipe(ucs->udev, 0), (unsigned char*) &ucs->dr_cmd_out, buf, len, write_command_callback, cs); - rc = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC); + rc = usb_submit_urb(ucs->urb_cmd_out, GFP_ATOMIC); if (unlikely(rc)) { update_basstate(ucs, 0, BS_ATWRPEND); dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n", diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 5ebf49ac9b23..af89ce188f2a 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -410,7 +410,7 @@ static void gigaset_read_int_callback(struct urb *urb) if (resubmit) { spin_lock_irqsave(&cs->lock, flags); - r = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; + r = cs->connected ? usb_submit_urb(urb, GFP_ATOMIC) : -ENODEV; spin_unlock_irqrestore(&cs->lock, flags); if (r) dev_err(cs->dev, "error %d when resubmitting urb.\n", @@ -486,7 +486,7 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) atomic_set(&ucs->busy, 1); spin_lock_irqsave(&cs->lock, flags); - status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC) : -ENODEV; + status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : -ENODEV; spin_unlock_irqrestore(&cs->lock, flags); if (status) { @@ -664,7 +664,7 @@ static int write_modem(struct cardstate *cs) ucs->bulk_out_endpointAddr & 0x0f), ucs->bulk_out_buffer, count, gigaset_write_bulk_callback, cs); - ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC); + ret = usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC); } else { ret = -ENODEV; } diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c index 78035ee824ca..397f51a7b2ad 100644 --- a/drivers/media/dvb/dvb-usb/usb-urb.c +++ b/drivers/media/dvb/dvb-usb/usb-urb.c @@ -116,7 +116,7 @@ static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { deb_mem("allocating buffer %d\n",stream->buf_num); if (( stream->buf_list[stream->buf_num] = - usb_buffer_alloc(stream->udev, size, SLAB_ATOMIC, + usb_buffer_alloc(stream->udev, size, GFP_ATOMIC, &stream->dma_addr[stream->buf_num]) ) == NULL) { deb_mem("not enough memory for urb-buffer allocation.\n"); usb_free_stream_buffers(stream); diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 8135f3e76aeb..10b121ada833 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1244,7 +1244,7 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec) return -ENOMEM; } dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE, - SLAB_ATOMIC, &dec->irq_dma_handle); + GFP_ATOMIC, &dec->irq_dma_handle); if(!dec->irq_buffer) { return -ENOMEM; } diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 277826cdd0c8..067f1519eb04 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -109,7 +109,7 @@ zfcp_fsf_req_alloc(mempool_t *pool, int req_flags) ptr = kmalloc(size, GFP_ATOMIC); else ptr = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache, - SLAB_ATOMIC); + GFP_ATOMIC); } if (unlikely(!ptr)) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 9be41ed1f9a6..0a46acf557ac 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -460,7 +460,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) * since each TT has "at least two" buffers that can need it (and * there can be many TTs per hub). even if they're uncommon. */ - if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == NULL) { + if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) { dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); /* FIXME recover somehow ... RESET_TT? */ return; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 7390b67c609d..149aa8bfb1fe 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -488,7 +488,7 @@ void usb_sg_wait (struct usb_sg_request *io) int retval; io->urbs [i]->dev = io->dev; - retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC); + retval = usb_submit_urb (io->urbs [i], GFP_ATOMIC); /* after we submit, let completions or cancelations fire; * we handshake using io->status. diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 34b7a31cd85b..56349d21e6ea 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -492,7 +492,7 @@ show_periodic (struct class_device *class_dev, char *buf) unsigned i; __le32 tag; - if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC))) + if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC))) return 0; seen_count = 0; diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 87eca6aeacf2..396dc69d4b4c 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -188,7 +188,7 @@ static DEFINE_TIMER(bulk_eot_timer, NULL, 0, 0); #define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \ {panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);} -#define SLAB_FLAG (in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL) +#define SLAB_FLAG (in_interrupt() ? GFP_ATOMIC : SLAB_KERNEL) #define KMALLOC_FLAG (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) /* Most helpful debugging aid */ @@ -1743,7 +1743,7 @@ static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc) *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do); - comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, SLAB_ATOMIC); + comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, GFP_ATOMIC); assert(comp_data != NULL); INIT_WORK(&comp_data->usb_bh, etrax_usb_isoc_descr_interrupt_bottom_half, comp_data); @@ -3010,7 +3010,7 @@ static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid) if (!urb->iso_frame_desc[i].length) continue; - next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC); + next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_ATOMIC); assert(next_sb_desc != NULL); if (urb->iso_frame_desc[i].length > 0) { @@ -3063,7 +3063,7 @@ static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid) if (TxIsocEPList[epid].sub == 0) { dbg_isoc("Isoc traffic not already running, allocating SB"); - next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC); + next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_ATOMIC); assert(next_sb_desc != NULL); next_sb_desc->command = (IO_STATE(USB_SB_command, tt, in) | @@ -3317,7 +3317,7 @@ static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc) restore_flags(flags); - reg = (usb_interrupt_registers_t *)kmem_cache_alloc(top_half_reg_cache, SLAB_ATOMIC); + reg = (usb_interrupt_registers_t *)kmem_cache_alloc(top_half_reg_cache, GFP_ATOMIC); assert(reg != NULL); diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 8293c1d4be3f..0f47a57dac28 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -505,7 +505,7 @@ show_periodic (struct class_device *class_dev, char *buf) char *next; unsigned i; - if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC))) + if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC))) return 0; seen_count = 0; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 06115f22a4fa..30b88459ac7d 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -498,7 +498,7 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, { struct urb_priv *urbp; - urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC); + urbp = kmem_cache_alloc(uhci_up_cachep, GFP_ATOMIC); if (!urbp) return NULL; diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index bf428184608f..9f52429ce654 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -1988,7 +1988,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) goto fail1; aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH, - SLAB_ATOMIC, &aiptek->data_dma); + GFP_ATOMIC, &aiptek->data_dma); if (!aiptek->data) goto fail1; diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index ff23318dc301..b724e36f7b92 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -592,7 +592,7 @@ static void ati_remote_irq_in(struct urb *urb) __FUNCTION__, urb->status); } - retval = usb_submit_urb(urb, SLAB_ATOMIC); + retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", __FUNCTION__, retval); @@ -604,12 +604,12 @@ static void ati_remote_irq_in(struct urb *urb) static int ati_remote_alloc_buffers(struct usb_device *udev, struct ati_remote *ati_remote) { - ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC, &ati_remote->inbuf_dma); if (!ati_remote->inbuf) return -1; - ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC, &ati_remote->outbuf_dma); if (!ati_remote->outbuf) return -1; diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 4295bab4f1e2..f1d0e1d69828 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1079,7 +1079,7 @@ static void hid_irq_in(struct urb *urb) warn("input irq status %d received", urb->status); } - status = usb_submit_urb(urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { clear_bit(HID_IN_RUNNING, &hid->iofl); if (status != -EPERM) { @@ -1864,13 +1864,13 @@ static void hid_find_max_report(struct hid_device *hid, unsigned int type, int * static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) { - if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->inbuf_dma))) + if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->inbuf_dma))) return -1; - if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->outbuf_dma))) + if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->outbuf_dma))) return -1; - if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), SLAB_ATOMIC, &hid->cr_dma))) + if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), GFP_ATOMIC, &hid->cr_dma))) return -1; - if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->ctrlbuf_dma))) + if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->ctrlbuf_dma))) return -1; return 0; diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c index 50aa8108a50b..98bd323369c7 100644 --- a/drivers/usb/input/keyspan_remote.c +++ b/drivers/usb/input/keyspan_remote.c @@ -456,7 +456,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic remote->in_endpoint = endpoint; remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */ - remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma); + remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma); if (!remote->in_buffer) { retval = -ENOMEM; goto fail1; diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index 79a85d46cb13..92c4e07da4c8 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -164,7 +164,7 @@ static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *m dbg("%s - called", __FUNCTION__); mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE, - SLAB_ATOMIC, &mtouch->data_dma); + GFP_ATOMIC, &mtouch->data_dma); if (!mtouch->data) return -1; diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index 0bf91778c40d..fea97e5437f8 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c @@ -277,12 +277,12 @@ static int powermate_input_event(struct input_dev *dev, unsigned int type, unsig static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm) { pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE_MAX, - SLAB_ATOMIC, &pm->data_dma); + GFP_ATOMIC, &pm->data_dma); if (!pm->data) return -1; pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)), - SLAB_ATOMIC, &pm->configcr_dma); + GFP_ATOMIC, &pm->configcr_dma); if (!pm->configcr) return -1; diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index 05c0d1ca39ab..2a314b065922 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c @@ -248,7 +248,7 @@ static int touchkit_alloc_buffers(struct usb_device *udev, struct touchkit_usb *touchkit) { touchkit->data = usb_buffer_alloc(udev, TOUCHKIT_REPORT_DATA_SIZE, - SLAB_ATOMIC, &touchkit->data_dma); + GFP_ATOMIC, &touchkit->data_dma); if (!touchkit->data) return -1; diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index dac88640eab6..8505824848f6 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -122,7 +122,7 @@ static void usb_kbd_irq(struct urb *urb) memcpy(kbd->old, kbd->new, 8); resubmit: - i = usb_submit_urb (urb, SLAB_ATOMIC); + i = usb_submit_urb (urb, GFP_ATOMIC); if (i) err ("can't resubmit intr, %s-%s/input0, status %d", kbd->usbdev->bus->bus_name, @@ -196,11 +196,11 @@ static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) return -1; if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL))) return -1; - if (!(kbd->new = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kbd->new_dma))) + if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma))) return -1; - if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), SLAB_ATOMIC, &kbd->cr_dma))) + if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma))) return -1; - if (!(kbd->leds = usb_buffer_alloc(dev, 1, SLAB_ATOMIC, &kbd->leds_dma))) + if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma))) return -1; return 0; diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index 68a55642c082..64a33e420cfb 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -86,7 +86,7 @@ static void usb_mouse_irq(struct urb *urb) input_sync(dev); resubmit: - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb (urb, GFP_ATOMIC); if (status) err ("can't resubmit intr, %s-%s/input0, status %d", mouse->usbdev->bus->bus_name, @@ -137,7 +137,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i if (!mouse || !input_dev) goto fail1; - mouse->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &mouse->data_dma); + mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma); if (!mouse->data) goto fail1; diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index df97e5c803f9..e4bc76ebc835 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -325,7 +325,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto fail1; xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN, - SLAB_ATOMIC, &xpad->idata_dma); + GFP_ATOMIC, &xpad->idata_dma); if (!xpad->idata) goto fail1; diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c index 2268ca311ade..caff8e6d7448 100644 --- a/drivers/usb/input/yealink.c +++ b/drivers/usb/input/yealink.c @@ -874,17 +874,17 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) /* allocate usb buffers */ yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN, - SLAB_ATOMIC, &yld->irq_dma); + GFP_ATOMIC, &yld->irq_dma); if (yld->irq_data == NULL) return usb_cleanup(yld, -ENOMEM); yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN, - SLAB_ATOMIC, &yld->ctl_dma); + GFP_ATOMIC, &yld->ctl_dma); if (!yld->ctl_data) return usb_cleanup(yld, -ENOMEM); yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)), - SLAB_ATOMIC, &yld->ctl_req_dma); + GFP_ATOMIC, &yld->ctl_req_dma); if (yld->ctl_req == NULL) return usb_cleanup(yld, -ENOMEM); diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index 9659c79e187e..371bf2b1197d 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -377,7 +377,7 @@ static void interfacekit_irq(struct urb *urb) schedule_delayed_work(&kit->do_notify, 0); resubmit: - status = usb_submit_urb(urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) err("can't resubmit intr, %s-%s/interfacekit0, status %d", kit->udev->bus->bus_name, @@ -568,7 +568,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic kit->dev_no = -1; kit->ifkit = ifkit; - kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &kit->data_dma); + kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, GFP_ATOMIC, &kit->data_dma); if (!kit->data) goto out; diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c index 2bb4fa572bb7..5727e1ea2f91 100644 --- a/drivers/usb/misc/phidgetmotorcontrol.c +++ b/drivers/usb/misc/phidgetmotorcontrol.c @@ -151,7 +151,7 @@ static void motorcontrol_irq(struct urb *urb) schedule_delayed_work(&mc->do_notify, 0); resubmit: - status = usb_submit_urb(urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) dev_err(&mc->intf->dev, "can't resubmit intr, %s-%s/motorcontrol0, status %d", @@ -338,7 +338,7 @@ static int motorcontrol_probe(struct usb_interface *intf, const struct usb_devic goto out; mc->dev_no = -1; - mc->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &mc->data_dma); + mc->data = usb_buffer_alloc(dev, URB_INT_SIZE, GFP_ATOMIC, &mc->data_dma); if (!mc->data) goto out; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 194065dbb51f..ea04dccdc651 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -819,7 +819,7 @@ error: /* resubmit if we need to, else mark this as done */ if ((status == 0) && (ctx->pending < ctx->count)) { - if ((status = usb_submit_urb (urb, SLAB_ATOMIC)) != 0) { + if ((status = usb_submit_urb (urb, GFP_ATOMIC)) != 0) { dbg ("can't resubmit ctrl %02x.%02x, err %d", reqp->bRequestType, reqp->bRequest, status); urb->dev = NULL; @@ -999,7 +999,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) context.urb = urb; spin_lock_irq (&context.lock); for (i = 0; i < param->sglen; i++) { - context.status = usb_submit_urb (urb [i], SLAB_ATOMIC); + context.status = usb_submit_urb (urb [i], GFP_ATOMIC); if (context.status != 0) { dbg ("can't submit urb[%d], status %d", i, context.status); @@ -1041,7 +1041,7 @@ static void unlink1_callback (struct urb *urb) // we "know" -EPIPE (stall) never happens if (!status) - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb (urb, GFP_ATOMIC); if (status) { urb->status = status; complete ((struct completion *) urb->context); @@ -1481,7 +1481,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, spin_lock_irq (&context.lock); for (i = 0; i < param->sglen; i++) { ++context.pending; - status = usb_submit_urb (urbs [i], SLAB_ATOMIC); + status = usb_submit_urb (urbs [i], GFP_ATOMIC); if (status < 0) { ERROR (dev, "submit iso[%d], error %d\n", i, status); if (i == 0) { diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 7a2346c53284..46aecc8754f1 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -147,7 +147,7 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, stamp = mon_get_timestamp(); if (rp->nevents >= EVENT_MAX || - (ep = kmem_cache_alloc(rp->e_slab, SLAB_ATOMIC)) == NULL) { + (ep = kmem_cache_alloc(rp->e_slab, GFP_ATOMIC)) == NULL) { rp->r.m_bus->cnt_text_lost++; return; } @@ -188,7 +188,7 @@ static void mon_text_error(void *data, struct urb *urb, int error) struct mon_event_text *ep; if (rp->nevents >= EVENT_MAX || - (ep = kmem_cache_alloc(rp->e_slab, SLAB_ATOMIC)) == NULL) { + (ep = kmem_cache_alloc(rp->e_slab, GFP_ATOMIC)) == NULL) { rp->r.m_bus->cnt_text_lost++; return; } diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c index 907b820a5faf..4852012735f6 100644 --- a/drivers/usb/net/catc.c +++ b/drivers/usb/net/catc.c @@ -345,7 +345,7 @@ static void catc_irq_done(struct urb *urb) } } resubmit: - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb (urb, GFP_ATOMIC); if (status) err ("can't resubmit intr, %s-%s, status %d", catc->usbdev->bus->bus_name, diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c index a77410562e12..493635954513 100644 --- a/drivers/usb/net/net1080.c +++ b/drivers/usb/net/net1080.c @@ -383,7 +383,7 @@ static void nc_ensure_sync(struct usbnet *dev) int status; /* Send a flush */ - urb = usb_alloc_urb(0, SLAB_ATOMIC); + urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return; diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index b5690b3834e3..d48c024cff59 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -856,7 +856,7 @@ static void intr_callback(struct urb *urb) pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; } - status = usb_submit_urb(urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status == -ENODEV) netif_device_detach(pegasus->net); if (status && netif_msg_timer(pegasus)) diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 72171f94ded4..c54235f73cb6 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -587,7 +587,7 @@ static void intr_callback(struct urb *urb) } resubmit: - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb (urb, GFP_ATOMIC); if (status == -ENODEV) netif_device_detach(dev->netdev); else if (status) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 82cd15b894b0..70f93b18292f 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -363,7 +363,7 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp) /* Initialising the write urb pool */ for (j = 0; j < NUM_URBS; ++j) { - urb = usb_alloc_urb(0,SLAB_ATOMIC); + urb = usb_alloc_urb(0,GFP_ATOMIC); mos7720_port->write_urb_pool[j] = urb; if (urb == NULL) { diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 02c89e10b2cf..5432c6340086 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -826,7 +826,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) /* Initialising the write urb pool */ for (j = 0; j < NUM_URBS; ++j) { - urb = usb_alloc_urb(0, SLAB_ATOMIC); + urb = usb_alloc_urb(0, GFP_ATOMIC); mos7840_port->write_urb_pool[j] = urb; if (urb == NULL) { @@ -2786,7 +2786,7 @@ static int mos7840_startup(struct usb_serial *serial) i + 1, status); } - mos7840_port->control_urb = usb_alloc_urb(0, SLAB_ATOMIC); + mos7840_port->control_urb = usb_alloc_urb(0, GFP_ATOMIC); mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL); } diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 3a158d58441f..e565d3d2ab29 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -76,7 +76,7 @@ static void usb_onetouch_irq(struct urb *urb) input_sync(dev); resubmit: - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb (urb, GFP_ATOMIC); if (status) err ("can't resubmit intr, %s-%s/input0, status %d", onetouch->udev->bus->bus_name, @@ -154,7 +154,7 @@ int onetouch_connect_input(struct us_data *ss) goto fail1; onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN, - SLAB_ATOMIC, &onetouch->data_dma); + GFP_ATOMIC, &onetouch->data_dma); if (!onetouch->data) goto fail1; diff --git a/include/linux/slab.h b/include/linux/slab.h index d7ee28e51330..34b046ea88f1 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -19,7 +19,6 @@ typedef struct kmem_cache kmem_cache_t; #include /* kmalloc_sizes.h needs L1_CACHE_BYTES */ /* flags for kmem_cache_alloc() */ -#define SLAB_ATOMIC GFP_ATOMIC #define SLAB_KERNEL GFP_KERNEL #define SLAB_DMA GFP_DMA diff --git a/include/net/request_sock.h b/include/net/request_sock.h index e37baaf2080b..426f0fe774ef 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -60,7 +60,7 @@ struct request_sock { static inline struct request_sock *reqsk_alloc(const struct request_sock_ops *ops) { - struct request_sock *req = kmem_cache_alloc(ops->slab, SLAB_ATOMIC); + struct request_sock *req = kmem_cache_alloc(ops->slab, GFP_ATOMIC); if (req != NULL) req->rsk_ops = ops; diff --git a/net/core/dst.c b/net/core/dst.c index 1a5e49da0e77..836ec6606925 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -125,7 +125,7 @@ void * dst_alloc(struct dst_ops * ops) if (ops->gc()) return NULL; } - dst = kmem_cache_alloc(ops->kmem_cachep, SLAB_ATOMIC); + dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC); if (!dst) return NULL; memset(dst, 0, ops->entry_size); diff --git a/net/core/flow.c b/net/core/flow.c index b16d31ae5e54..5df3e297f817 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -211,7 +211,7 @@ void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, if (flow_count(cpu) > flow_hwm) flow_cache_shrink(cpu); - fle = kmem_cache_alloc(flow_cachep, SLAB_ATOMIC); + fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC); if (fle) { fle->next = *head; *head = fle; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index ba509a4a8e92..0ab1987b9348 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -251,7 +251,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl) goto out_entries; } - n = kmem_cache_alloc(tbl->kmem_cachep, SLAB_ATOMIC); + n = kmem_cache_alloc(tbl->kmem_cachep, GFP_ATOMIC); if (!n) goto out_entries; diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index cf8c07b2704f..66a27b9688ca 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -295,7 +295,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) new_packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist); if (new_packet == NULL || new_packet->dccphtx_sent) { new_packet = dccp_tx_hist_entry_new(ccid3_tx_hist, - SLAB_ATOMIC); + GFP_ATOMIC); if (unlikely(new_packet == NULL)) { DCCP_WARN("%s, sk=%p, not enough mem to add to history," @@ -889,7 +889,7 @@ static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss) /* new loss event detected */ /* calculate last interval length */ seq_temp = dccp_delta_seqno(head->dccplih_seqno, seq_loss); - entry = dccp_li_hist_entry_new(ccid3_li_hist, SLAB_ATOMIC); + entry = dccp_li_hist_entry_new(ccid3_li_hist, GFP_ATOMIC); if (entry == NULL) { DCCP_BUG("out of memory - can not allocate entry"); @@ -1011,7 +1011,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) } packet = dccp_rx_hist_entry_new(ccid3_rx_hist, sk, opt_recv->dccpor_ndp, - skb, SLAB_ATOMIC); + skb, GFP_ATOMIC); if (unlikely(packet == NULL)) { DCCP_WARN("%s, sk=%p, Not enough mem to add rx packet " "to history, consider it lost!\n", dccp_role(sk), sk); diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c index 48b9b93f8acb..0a0baef16b3e 100644 --- a/net/dccp/ccids/lib/loss_interval.c +++ b/net/dccp/ccids/lib/loss_interval.c @@ -125,7 +125,7 @@ int dccp_li_hist_interval_new(struct dccp_li_hist *hist, int i; for (i = 0; i < DCCP_LI_HIST_IVAL_F_LENGTH; i++) { - entry = dccp_li_hist_entry_new(hist, SLAB_ATOMIC); + entry = dccp_li_hist_entry_new(hist, GFP_ATOMIC); if (entry == NULL) { dccp_li_hist_purge(hist, list); DCCP_BUG("loss interval list entry is NULL"); diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 244c4f445c7d..bd6c9bc41893 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -31,7 +31,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(kmem_cache_t *cachep, struct inet_bind_hashbucket *head, const unsigned short snum) { - struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, SLAB_ATOMIC); + struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC); if (tb != NULL) { tb->port = snum; diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 8c74f9168b7d..e28330aa4139 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -91,7 +91,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat { struct inet_timewait_sock *tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab, - SLAB_ATOMIC); + GFP_ATOMIC); if (tw != NULL) { const struct inet_sock *inet = inet_sk(sk); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index bf526115e518..97a8cfbb61a1 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -150,7 +150,7 @@ static __inline__ struct fib6_node * node_alloc(void) { struct fib6_node *fn; - if ((fn = kmem_cache_alloc(fib6_node_kmem, SLAB_ATOMIC)) != NULL) + if ((fn = kmem_cache_alloc(fib6_node_kmem, GFP_ATOMIC)) != NULL) memset(fn, 0, sizeof(struct fib6_node)); return fn; diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 01a5c52a2be3..d4f68b0f27d5 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -180,7 +180,7 @@ try_next_2:; spi = 0; goto out; alloc_spi: - x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, SLAB_ATOMIC); + x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); if (!x6spi) goto out; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 04954e5f6846..8d55d10041f9 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -979,7 +979,7 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, { struct sctp_chunk *retval; - retval = kmem_cache_alloc(sctp_chunk_cachep, SLAB_ATOMIC); + retval = kmem_cache_alloc(sctp_chunk_cachep, GFP_ATOMIC); if (!retval) goto nodata; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 02b27145b279..49607792cbd3 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4989,7 +4989,7 @@ static struct sctp_bind_bucket *sctp_bucket_create( { struct sctp_bind_bucket *pp; - pp = kmem_cache_alloc(sctp_bucket_cachep, SLAB_ATOMIC); + pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC); SCTP_DBG_OBJCNT_INC(bind_bucket); if (pp) { pp->port = snum; diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index e8198a2c785d..a898a6a83a56 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -27,7 +27,7 @@ struct sec_path *secpath_dup(struct sec_path *src) { struct sec_path *sp; - sp = kmem_cache_alloc(secpath_cachep, SLAB_ATOMIC); + sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC); if (!sp) return NULL; diff --git a/security/selinux/avc.c b/security/selinux/avc.c index e73ac1ab7cfd..65b4ec9c699a 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -332,7 +332,7 @@ static struct avc_node *avc_alloc_node(void) { struct avc_node *node; - node = kmem_cache_alloc(avc_node_cachep, SLAB_ATOMIC); + node = kmem_cache_alloc(avc_node_cachep, GFP_ATOMIC); if (!node) goto out; -- cgit v1.2.3 From e94b1766097d53e6f3ccfb36c8baa562ffeda3fc Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:33:17 -0800 Subject: [PATCH] slab: remove SLAB_KERNEL SLAB_KERNEL is an alias of GFP_KERNEL. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/sysenter.c | 2 +- arch/ia64/ia32/binfmt_elf32.c | 8 ++++---- arch/ia64/kernel/perfmon.c | 2 +- arch/ia64/mm/init.c | 4 ++-- arch/powerpc/kernel/vdso.c | 2 +- arch/powerpc/platforms/cell/spufs/inode.c | 2 +- arch/sh/kernel/vsyscall/vsyscall.c | 2 +- arch/x86_64/ia32/ia32_binfmt.c | 2 +- arch/x86_64/ia32/syscall32.c | 2 +- drivers/atm/he.c | 4 ++-- drivers/base/dmapool.c | 2 +- drivers/dma/ioatdma.c | 4 ++-- drivers/ieee1394/hosts.c | 2 +- drivers/ieee1394/ohci1394.c | 8 ++++---- drivers/ieee1394/pcilynx.c | 2 +- drivers/ieee1394/raw1394.c | 10 +++++----- drivers/infiniband/hw/ehca/ehca_av.c | 2 +- drivers/infiniband/hw/ehca/ehca_cq.c | 2 +- drivers/infiniband/hw/ehca/ehca_main.c | 2 +- drivers/infiniband/hw/ehca/ehca_mrmw.c | 4 ++-- drivers/infiniband/hw/ehca/ehca_pd.c | 2 +- drivers/infiniband/hw/ehca/ehca_qp.c | 2 +- drivers/input/touchscreen/ads7846.c | 2 +- drivers/isdn/gigaset/bas-gigaset.c | 14 +++++++------- drivers/isdn/gigaset/usb-gigaset.c | 6 +++--- drivers/media/dvb/cinergyT2/cinergyT2.c | 2 +- drivers/mtd/devices/m25p80.c | 2 +- drivers/scsi/ipr.c | 2 +- drivers/spi/spi.c | 4 ++-- drivers/spi/spi_bitbang.c | 2 +- drivers/usb/core/hub.c | 4 ++-- drivers/usb/gadget/gmidi.c | 2 +- drivers/usb/gadget/goku_udc.c | 2 +- drivers/usb/gadget/inode.c | 6 +++--- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/zero.c | 2 +- drivers/usb/host/hc_crisv10.c | 2 +- drivers/usb/host/ohci-pnx4008.c | 2 +- drivers/usb/input/acecad.c | 2 +- drivers/usb/input/usbtouchscreen.c | 2 +- drivers/usb/misc/usbtest.c | 28 ++++++++++++++-------------- drivers/usb/net/rndis_host.c | 2 +- drivers/usb/net/usbnet.c | 4 ++-- fs/adfs/super.c | 2 +- fs/affs/super.c | 2 +- fs/afs/super.c | 2 +- fs/befs/linuxvfs.c | 2 +- fs/bfs/inode.c | 2 +- fs/block_dev.c | 2 +- fs/cifs/cifsfs.c | 2 +- fs/cifs/misc.c | 4 ++-- fs/cifs/transport.c | 4 ++-- fs/coda/inode.c | 2 +- fs/dnotify.c | 2 +- fs/ecryptfs/crypto.c | 2 +- fs/ecryptfs/file.c | 2 +- fs/ecryptfs/inode.c | 4 ++-- fs/ecryptfs/keystore.c | 2 +- fs/ecryptfs/main.c | 4 ++-- fs/ecryptfs/super.c | 2 +- fs/efs/super.c | 2 +- fs/eventpoll.c | 4 ++-- fs/exec.c | 2 +- fs/ext2/super.c | 2 +- fs/fat/cache.c | 2 +- fs/fat/inode.c | 2 +- fs/fcntl.c | 2 +- fs/freevxfs/vxfs_inode.c | 4 ++-- fs/fuse/dev.c | 2 +- fs/fuse/inode.c | 2 +- fs/hfs/super.c | 2 +- fs/hfsplus/super.c | 2 +- fs/hugetlbfs/inode.c | 2 +- fs/inode.c | 2 +- fs/isofs/inode.c | 2 +- fs/jffs2/super.c | 2 +- fs/locks.c | 2 +- fs/minix/inode.c | 2 +- fs/ncpfs/inode.c | 2 +- fs/nfs/direct.c | 2 +- fs/nfs/inode.c | 2 +- fs/nfs/pagelist.c | 2 +- fs/openpromfs/inode.c | 2 +- fs/proc/inode.c | 2 +- fs/qnx4/inode.c | 2 +- fs/reiserfs/super.c | 2 +- fs/romfs/inode.c | 2 +- fs/smbfs/inode.c | 2 +- fs/smbfs/request.c | 2 +- fs/sysv/inode.c | 2 +- fs/udf/super.c | 2 +- fs/ufs/super.c | 2 +- include/linux/fs.h | 2 +- include/linux/rmap.h | 2 +- include/linux/slab.h | 1 - include/linux/taskstats_kern.h | 2 +- ipc/mqueue.c | 2 +- kernel/delayacct.c | 2 +- kernel/fork.c | 6 +++--- kernel/taskstats.c | 2 +- kernel/user.c | 2 +- mm/mempolicy.c | 2 +- mm/mmap.c | 4 ++-- mm/shmem.c | 2 +- mm/slab.c | 2 +- net/decnet/dn_table.c | 2 +- net/ipv4/fib_hash.c | 4 ++-- net/ipv4/fib_trie.c | 4 ++-- net/socket.c | 2 +- net/sunrpc/rpc_pipe.c | 2 +- security/keys/key.c | 2 +- security/selinux/hooks.c | 2 +- security/selinux/ss/avtab.c | 2 +- 114 files changed, 164 insertions(+), 165 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c index 713ba39d32c6..0bbacd0ec175 100644 --- a/arch/i386/kernel/sysenter.c +++ b/arch/i386/kernel/sysenter.c @@ -132,7 +132,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) goto up_fail; } - vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (!vma) { ret = -ENOMEM; goto up_fail; diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c index daa6b91bc921..578737ec7629 100644 --- a/arch/ia64/ia32/binfmt_elf32.c +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -91,7 +91,7 @@ ia64_elf32_init (struct pt_regs *regs) * it with privilege level 3 because the IVE uses non-privileged accesses to these * tables. IA-32 segmentation is used to protect against IA-32 accesses to them. */ - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (vma) { memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; @@ -117,7 +117,7 @@ ia64_elf32_init (struct pt_regs *regs) * code is locked in specific gate page, which is pointed by pretcode * when setup_frame_ia32 */ - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (vma) { memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; @@ -142,7 +142,7 @@ ia64_elf32_init (struct pt_regs *regs) * Install LDT as anonymous memory. This gives us all-zero segment descriptors * until a task modifies them via modify_ldt(). */ - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (vma) { memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; @@ -214,7 +214,7 @@ ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack) bprm->loader += stack_base; bprm->exec += stack_base; - mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + mpnt = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!mpnt) return -ENOMEM; diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 3aaede0d6981..e2321536ee4c 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -2302,7 +2302,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon DPRINT(("smpl_buf @%p\n", smpl_buf)); /* allocate vma */ - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!vma) { DPRINT(("Cannot allocate vma\n")); goto error_kmem; diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index ff87a5cba399..56dc2024220e 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -156,7 +156,7 @@ ia64_init_addr_space (void) * the problem. When the process attempts to write to the register backing store * for the first time, it will get a SEGFAULT in this case. */ - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (vma) { memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; @@ -175,7 +175,7 @@ ia64_init_addr_space (void) /* map NaT-page at address zero to speed up speculative dereferencing of NULL: */ if (!(current->personality & MMAP_PAGE_ZERO)) { - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (vma) { memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index c913ad5cad29..a4b28c73bba0 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -264,7 +264,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, /* Allocate a VMA structure and fill it up */ - vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (vma == NULL) { rc = -ENOMEM; goto fail_mmapsem; diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index c7d010749a18..7edfcc9d2853 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -48,7 +48,7 @@ spufs_alloc_inode(struct super_block *sb) { struct spufs_inode_info *ei; - ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL); + ei = kmem_cache_alloc(spufs_inode_cache, GFP_KERNEL); if (!ei) return NULL; diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c index 075d6cc1a2d7..deb46941f315 100644 --- a/arch/sh/kernel/vsyscall/vsyscall.c +++ b/arch/sh/kernel/vsyscall/vsyscall.c @@ -97,7 +97,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, goto up_fail; } - vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (!vma) { ret = -ENOMEM; goto up_fail; diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c index 82ef182de6ae..932a62ad6c83 100644 --- a/arch/x86_64/ia32/ia32_binfmt.c +++ b/arch/x86_64/ia32/ia32_binfmt.c @@ -351,7 +351,7 @@ int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, bprm->loader += stack_base; bprm->exec += stack_base; - mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + mpnt = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!mpnt) return -ENOMEM; diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c index 3a01329473ab..3e5ed20cba45 100644 --- a/arch/x86_64/ia32/syscall32.c +++ b/arch/x86_64/ia32/syscall32.c @@ -49,7 +49,7 @@ int syscall32_setup_pages(struct linux_binprm *bprm, int exstack) struct mm_struct *mm = current->mm; int ret; - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!vma) return -ENOMEM; diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 2a2f0fc2288f..ec8a7a633e68 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -820,7 +820,7 @@ he_init_group(struct he_dev *he_dev, int group) void *cpuaddr; #ifdef USE_RBPS_POOL - cpuaddr = pci_pool_alloc(he_dev->rbps_pool, SLAB_KERNEL|SLAB_DMA, &dma_handle); + cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|SLAB_DMA, &dma_handle); if (cpuaddr == NULL) return -ENOMEM; #else @@ -884,7 +884,7 @@ he_init_group(struct he_dev *he_dev, int group) void *cpuaddr; #ifdef USE_RBPL_POOL - cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, SLAB_KERNEL|SLAB_DMA, &dma_handle); + cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|SLAB_DMA, &dma_handle); if (cpuaddr == NULL) return -ENOMEM; #else diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index fa4675254f67..dbe0735f8c9e 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c @@ -126,7 +126,7 @@ dma_pool_create (const char *name, struct device *dev, } else if (allocation < size) return NULL; - if (!(retval = kmalloc (sizeof *retval, SLAB_KERNEL))) + if (!(retval = kmalloc (sizeof *retval, GFP_KERNEL))) return retval; strlcpy (retval->name, name, sizeof retval->name); diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c index 0358419a0e48..8e8726104619 100644 --- a/drivers/dma/ioatdma.c +++ b/drivers/dma/ioatdma.c @@ -636,10 +636,10 @@ static int ioat_self_test(struct ioat_device *device) dma_cookie_t cookie; int err = 0; - src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, SLAB_KERNEL); + src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL); if (!src) return -ENOMEM; - dest = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, SLAB_KERNEL); + dest = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL); if (!dest) { kfree(src); return -ENOMEM; diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c index 8f4378a1631c..b935e08695a9 100644 --- a/drivers/ieee1394/hosts.c +++ b/drivers/ieee1394/hosts.c @@ -123,7 +123,7 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra, int i; int hostnum = 0; - h = kzalloc(sizeof(*h) + extra, SLAB_KERNEL); + h = kzalloc(sizeof(*h) + extra, GFP_KERNEL); if (!h) return NULL; diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 6e8ea9110c46..eae97d8dcf03 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -1225,7 +1225,7 @@ static int ohci_iso_recv_init(struct hpsb_iso *iso) int ctx; int ret = -ENOMEM; - recv = kmalloc(sizeof(*recv), SLAB_KERNEL); + recv = kmalloc(sizeof(*recv), GFP_KERNEL); if (!recv) return -ENOMEM; @@ -1918,7 +1918,7 @@ static int ohci_iso_xmit_init(struct hpsb_iso *iso) int ctx; int ret = -ENOMEM; - xmit = kmalloc(sizeof(*xmit), SLAB_KERNEL); + xmit = kmalloc(sizeof(*xmit), GFP_KERNEL); if (!xmit) return -ENOMEM; @@ -3021,7 +3021,7 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, return -ENOMEM; } - d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, SLAB_KERNEL, d->prg_bus+i); + d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i); OHCI_DMA_ALLOC("pool dma_rcv prg[%d]", i); if (d->prg_cpu[i] != NULL) { @@ -3117,7 +3117,7 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, OHCI_DMA_ALLOC("dma_rcv prg pool"); for (i = 0; i < d->num_desc; i++) { - d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, SLAB_KERNEL, d->prg_bus+i); + d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i); OHCI_DMA_ALLOC("pool dma_trm prg[%d]", i); if (d->prg_cpu[i] != NULL) { diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index 0a7412e27eb4..9cab1d661472 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -1428,7 +1428,7 @@ static int __devinit add_card(struct pci_dev *dev, struct i2c_algo_bit_data i2c_adapter_data; error = -ENOMEM; - i2c_ad = kmalloc(sizeof(*i2c_ad), SLAB_KERNEL); + i2c_ad = kmalloc(sizeof(*i2c_ad), GFP_KERNEL); if (!i2c_ad) FAIL("failed to allocate I2C adapter memory"); memcpy(i2c_ad, &bit_ops, sizeof(struct i2c_adapter)); diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 47f6a4e29b40..bf71e069eaf5 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -112,7 +112,7 @@ static struct pending_request *__alloc_pending_request(gfp_t flags) static inline struct pending_request *alloc_pending_request(void) { - return __alloc_pending_request(SLAB_KERNEL); + return __alloc_pending_request(GFP_KERNEL); } static void free_pending_request(struct pending_request *req) @@ -1737,7 +1737,7 @@ static int arm_register(struct file_info *fi, struct pending_request *req) return (-EINVAL); } /* addr-list-entry for fileinfo */ - addr = kmalloc(sizeof(*addr), SLAB_KERNEL); + addr = kmalloc(sizeof(*addr), GFP_KERNEL); if (!addr) { req->req.length = 0; return (-ENOMEM); @@ -2103,7 +2103,7 @@ static int write_phypacket(struct file_info *fi, struct pending_request *req) static int get_config_rom(struct file_info *fi, struct pending_request *req) { int ret = sizeof(struct raw1394_request); - quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL); + quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL); int status; if (!data) @@ -2133,7 +2133,7 @@ static int get_config_rom(struct file_info *fi, struct pending_request *req) static int update_config_rom(struct file_info *fi, struct pending_request *req) { int ret = sizeof(struct raw1394_request); - quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL); + quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL); if (!data) return -ENOMEM; if (copy_from_user(data, int2ptr(req->req.sendb), req->req.length)) { @@ -2779,7 +2779,7 @@ static int raw1394_open(struct inode *inode, struct file *file) { struct file_info *fi; - fi = kzalloc(sizeof(*fi), SLAB_KERNEL); + fi = kzalloc(sizeof(*fi), GFP_KERNEL); if (!fi) return -ENOMEM; diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c index 214e2fdddeef..0d6e2c4bb245 100644 --- a/drivers/infiniband/hw/ehca/ehca_av.c +++ b/drivers/infiniband/hw/ehca/ehca_av.c @@ -57,7 +57,7 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) struct ehca_shca *shca = container_of(pd->device, struct ehca_shca, ib_device); - av = kmem_cache_alloc(av_cache, SLAB_KERNEL); + av = kmem_cache_alloc(av_cache, GFP_KERNEL); if (!av) { ehca_err(pd->device, "Out of memory pd=%p ah_attr=%p", pd, ah_attr); diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 458fe19648a1..93995b658d94 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -134,7 +134,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, if (cqe >= 0xFFFFFFFF - 64 - additional_cqe) return ERR_PTR(-EINVAL); - my_cq = kmem_cache_alloc(cq_cache, SLAB_KERNEL); + my_cq = kmem_cache_alloc(cq_cache, GFP_KERNEL); if (!my_cq) { ehca_err(device, "Out of memory for ehca_cq struct device=%p", device); diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 3d1c1c535038..cc47e4c13a18 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -108,7 +108,7 @@ static struct kmem_cache *ctblk_cache = NULL; void *ehca_alloc_fw_ctrlblock(void) { - void *ret = kmem_cache_zalloc(ctblk_cache, SLAB_KERNEL); + void *ret = kmem_cache_zalloc(ctblk_cache, GFP_KERNEL); if (!ret) ehca_gen_err("Out of memory for ctblk"); return ret; diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index abce676c0ae0..0a5e2214cc5f 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -53,7 +53,7 @@ static struct ehca_mr *ehca_mr_new(void) { struct ehca_mr *me; - me = kmem_cache_alloc(mr_cache, SLAB_KERNEL); + me = kmem_cache_alloc(mr_cache, GFP_KERNEL); if (me) { memset(me, 0, sizeof(struct ehca_mr)); spin_lock_init(&me->mrlock); @@ -72,7 +72,7 @@ static struct ehca_mw *ehca_mw_new(void) { struct ehca_mw *me; - me = kmem_cache_alloc(mw_cache, SLAB_KERNEL); + me = kmem_cache_alloc(mw_cache, GFP_KERNEL); if (me) { memset(me, 0, sizeof(struct ehca_mw)); spin_lock_init(&me->mwlock); diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c index 2c3cdc6f7b39..d5345e5b3cd6 100644 --- a/drivers/infiniband/hw/ehca/ehca_pd.c +++ b/drivers/infiniband/hw/ehca/ehca_pd.c @@ -50,7 +50,7 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device, { struct ehca_pd *pd; - pd = kmem_cache_alloc(pd_cache, SLAB_KERNEL); + pd = kmem_cache_alloc(pd_cache, GFP_KERNEL); if (!pd) { ehca_err(device, "device=%p context=%p out of memory", device, context); diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 8682aa50c707..c6c9cef203e3 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -450,7 +450,7 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd, if (pd->uobject && udata) context = pd->uobject->context; - my_qp = kmem_cache_alloc(qp_cache, SLAB_KERNEL); + my_qp = kmem_cache_alloc(qp_cache, GFP_KERNEL); if (!my_qp) { ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd); return ERR_PTR(-ENOMEM); diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index f56d6a0f0624..0517c7387d67 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -189,7 +189,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) { struct spi_device *spi = to_spi_device(dev); struct ads7846 *ts = dev_get_drvdata(dev); - struct ser_req *req = kzalloc(sizeof *req, SLAB_KERNEL); + struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL); int status; int sample; int i; diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 5857e7e23f84..63b629b1cdb2 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -2218,21 +2218,21 @@ static int gigaset_probe(struct usb_interface *interface, * - three for the different uses of the default control pipe * - three for each isochronous pipe */ - if (!(ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL)) || - !(ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL)) || - !(ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL)) || - !(ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL))) + if (!(ucs->urb_int_in = usb_alloc_urb(0, GFP_KERNEL)) || + !(ucs->urb_cmd_in = usb_alloc_urb(0, GFP_KERNEL)) || + !(ucs->urb_cmd_out = usb_alloc_urb(0, GFP_KERNEL)) || + !(ucs->urb_ctrl = usb_alloc_urb(0, GFP_KERNEL))) goto allocerr; for (j = 0; j < 2; ++j) { ubc = cs->bcs[j].hw.bas; for (i = 0; i < BAS_OUTURBS; ++i) if (!(ubc->isoouturbs[i].urb = - usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL))) + usb_alloc_urb(BAS_NUMFRAMES, GFP_KERNEL))) goto allocerr; for (i = 0; i < BAS_INURBS; ++i) if (!(ubc->isoinurbs[i] = - usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL))) + usb_alloc_urb(BAS_NUMFRAMES, GFP_KERNEL))) goto allocerr; } @@ -2246,7 +2246,7 @@ static int gigaset_probe(struct usb_interface *interface, (endpoint->bEndpointAddress) & 0x0f), ucs->int_in_buf, 3, read_int_callback, cs, endpoint->bInterval); - if ((rc = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL)) != 0) { + if ((rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL)) != 0) { dev_err(cs->dev, "could not submit interrupt URB: %s\n", get_usb_rcmsg(rc)); goto error; diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index af89ce188f2a..04f2ad7ba8b0 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -763,7 +763,7 @@ static int gigaset_probe(struct usb_interface *interface, goto error; } - ucs->bulk_out_urb = usb_alloc_urb(0, SLAB_KERNEL); + ucs->bulk_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!ucs->bulk_out_urb) { dev_err(cs->dev, "Couldn't allocate bulk_out_urb\n"); retval = -ENOMEM; @@ -774,7 +774,7 @@ static int gigaset_probe(struct usb_interface *interface, atomic_set(&ucs->busy, 0); - ucs->read_urb = usb_alloc_urb(0, SLAB_KERNEL); + ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL); if (!ucs->read_urb) { dev_err(cs->dev, "No free urbs available\n"); retval = -ENOMEM; @@ -797,7 +797,7 @@ static int gigaset_probe(struct usb_interface *interface, gigaset_read_int_callback, cs->inbuf + 0, endpoint->bInterval); - retval = usb_submit_urb(ucs->read_urb, SLAB_KERNEL); + retval = usb_submit_urb(ucs->read_urb, GFP_KERNEL); if (retval) { dev_err(cs->dev, "Could not submit URB (error %d)\n", -retval); goto error; diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 206c13e47a06..9123147e376f 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -287,7 +287,7 @@ static int cinergyt2_alloc_stream_urbs (struct cinergyt2 *cinergyt2) int i; cinergyt2->streambuf = usb_buffer_alloc(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE, - SLAB_KERNEL, &cinergyt2->streambuf_dmahandle); + GFP_KERNEL, &cinergyt2->streambuf_dmahandle); if (!cinergyt2->streambuf) { dprintk(1, "failed to alloc consistent stream memory area, bailing out!\n"); return -ENOMEM; diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index ef4a731ca5c2..334e078ffaff 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -451,7 +451,7 @@ static int __devinit m25p_probe(struct spi_device *spi) return -ENODEV; } - flash = kzalloc(sizeof *flash, SLAB_KERNEL); + flash = kzalloc(sizeof *flash, GFP_KERNEL); if (!flash) return -ENOMEM; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index ccd4dafce8e2..b318500785e5 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6940,7 +6940,7 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) return -ENOMEM; for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { - ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, SLAB_KERNEL, &dma_addr); + ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr); if (!ipr_cmd) { ipr_free_cmd_blks(ioa_cfg); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index c3c0626f550b..09f2c74a40c5 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -360,7 +360,7 @@ spi_alloc_master(struct device *dev, unsigned size) if (!dev) return NULL; - master = kzalloc(size + sizeof *master, SLAB_KERNEL); + master = kzalloc(size + sizeof *master, GFP_KERNEL); if (!master) return NULL; @@ -607,7 +607,7 @@ static int __init spi_init(void) { int status; - buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL); + buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); if (!buf) { status = -ENOMEM; goto err0; diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 08c1c57c6128..57289b61d0be 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -196,7 +196,7 @@ int spi_bitbang_setup(struct spi_device *spi) return -EINVAL; if (!cs) { - cs = kzalloc(sizeof *cs, SLAB_KERNEL); + cs = kzalloc(sizeof *cs, GFP_KERNEL); if (!cs) return -ENOMEM; spi->controller_state = cs; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0a46acf557ac..77c05be5241a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2371,7 +2371,7 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) struct usb_qualifier_descriptor *qual; int status; - qual = kmalloc (sizeof *qual, SLAB_KERNEL); + qual = kmalloc (sizeof *qual, GFP_KERNEL); if (qual == NULL) return; @@ -2922,7 +2922,7 @@ static int config_descriptors_changed(struct usb_device *udev) if (len < le16_to_cpu(udev->config[index].desc.wTotalLength)) len = le16_to_cpu(udev->config[index].desc.wTotalLength); } - buf = kmalloc (len, SLAB_KERNEL); + buf = kmalloc (len, GFP_KERNEL); if (buf == NULL) { dev_err(&udev->dev, "no mem to re-read configs after reset\n"); /* assume the worst */ diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 64554acad63f..31351826f2ba 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -1236,7 +1236,7 @@ autoconf_fail: /* ok, we made sense of the hardware ... */ - dev = kzalloc(sizeof(*dev), SLAB_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { return -ENOMEM; } diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index a3076da3f4eb..805a9826842d 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1864,7 +1864,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* alloc, and start init */ - dev = kmalloc (sizeof *dev, SLAB_KERNEL); + dev = kmalloc (sizeof *dev, GFP_KERNEL); if (dev == NULL){ pr_debug("enomem %s\n", pci_name(pdev)); retval = -ENOMEM; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 86924f9cdd7e..3fb1044a4db0 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -412,7 +412,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */ value = -ENOMEM; - kbuf = kmalloc (len, SLAB_KERNEL); + kbuf = kmalloc (len, GFP_KERNEL); if (unlikely (!kbuf)) goto free1; @@ -456,7 +456,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */ value = -ENOMEM; - kbuf = kmalloc (len, SLAB_KERNEL); + kbuf = kmalloc (len, GFP_KERNEL); if (!kbuf) goto free1; if (copy_from_user (kbuf, buf, len)) { @@ -1898,7 +1898,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) buf += 4; length -= 4; - kbuf = kmalloc (length, SLAB_KERNEL); + kbuf = kmalloc (length, GFP_KERNEL); if (!kbuf) return -ENOMEM; if (copy_from_user (kbuf, buf, length)) { diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 0b590831582c..3024c679e38e 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2861,7 +2861,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) } /* alloc, and start init */ - dev = kzalloc (sizeof *dev, SLAB_KERNEL); + dev = kzalloc (sizeof *dev, GFP_KERNEL); if (dev == NULL){ retval = -ENOMEM; goto done; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 48a09fd89d18..030d87c28c2f 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2581,7 +2581,7 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) /* UDC_PULLUP_EN gates the chip clock */ // OTG_SYSCON_1_REG |= DEV_IDLE_EN; - udc = kzalloc(sizeof(*udc), SLAB_KERNEL); + udc = kzalloc(sizeof(*udc), GFP_KERNEL); if (!udc) return -ENOMEM; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 0f809dd68492..40710ea1b490 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1190,7 +1190,7 @@ autoconf_fail: /* ok, we made sense of the hardware ... */ - dev = kzalloc(sizeof(*dev), SLAB_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; spin_lock_init (&dev->lock); diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 396dc69d4b4c..7fd872aa654a 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -188,7 +188,7 @@ static DEFINE_TIMER(bulk_eot_timer, NULL, 0, 0); #define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \ {panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);} -#define SLAB_FLAG (in_interrupt() ? GFP_ATOMIC : SLAB_KERNEL) +#define SLAB_FLAG (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) #define KMALLOC_FLAG (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) /* Most helpful debugging aid */ diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 2dbb77414905..7f26f9bdbaf1 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -134,7 +134,7 @@ static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind) { struct i2c_client *c; - c = (struct i2c_client *)kzalloc(sizeof(*c), SLAB_KERNEL); + c = (struct i2c_client *)kzalloc(sizeof(*c), GFP_KERNEL); if (!c) return -ENOMEM; diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c index 0096373b5f98..909138e5aa04 100644 --- a/drivers/usb/input/acecad.c +++ b/drivers/usb/input/acecad.c @@ -152,7 +152,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ if (!acecad || !input_dev) goto fail1; - acecad->data = usb_buffer_alloc(dev, 8, SLAB_KERNEL, &acecad->data_dma); + acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma); if (!acecad->data) goto fail1; diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index 49704d4ed0e2..7f3c57da9bc0 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -680,7 +680,7 @@ static int usbtouch_probe(struct usb_interface *intf, type->process_pkt = usbtouch_process_pkt; usbtouch->data = usb_buffer_alloc(udev, type->rept_size, - SLAB_KERNEL, &usbtouch->data_dma); + GFP_KERNEL, &usbtouch->data_dma); if (!usbtouch->data) goto out_free; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index ea04dccdc651..fb321864a92d 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -213,7 +213,7 @@ static struct urb *simple_alloc_urb ( if (bytes < 0) return NULL; - urb = usb_alloc_urb (0, SLAB_KERNEL); + urb = usb_alloc_urb (0, GFP_KERNEL); if (!urb) return urb; usb_fill_bulk_urb (urb, udev, pipe, NULL, bytes, simple_callback, NULL); @@ -223,7 +223,7 @@ static struct urb *simple_alloc_urb ( urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; if (usb_pipein (pipe)) urb->transfer_flags |= URB_SHORT_NOT_OK; - urb->transfer_buffer = usb_buffer_alloc (udev, bytes, SLAB_KERNEL, + urb->transfer_buffer = usb_buffer_alloc (udev, bytes, GFP_KERNEL, &urb->transfer_dma); if (!urb->transfer_buffer) { usb_free_urb (urb); @@ -315,7 +315,7 @@ static int simple_io ( init_completion (&completion); if (usb_pipeout (urb->pipe)) simple_fill_buf (urb); - if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) + if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) break; /* NOTE: no timeouts; can't be broken out of by interrupt */ @@ -374,7 +374,7 @@ alloc_sglist (int nents, int max, int vary) unsigned i; unsigned size = max; - sg = kmalloc (nents * sizeof *sg, SLAB_KERNEL); + sg = kmalloc (nents * sizeof *sg, GFP_KERNEL); if (!sg) return NULL; @@ -382,7 +382,7 @@ alloc_sglist (int nents, int max, int vary) char *buf; unsigned j; - buf = kzalloc (size, SLAB_KERNEL); + buf = kzalloc (size, GFP_KERNEL); if (!buf) { free_sglist (sg, i); return NULL; @@ -428,7 +428,7 @@ static int perform_sglist ( (udev->speed == USB_SPEED_HIGH) ? (INTERRUPT_RATE << 3) : INTERRUPT_RATE, - sg, nents, 0, SLAB_KERNEL); + sg, nents, 0, GFP_KERNEL); if (retval) break; @@ -855,7 +855,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) * as with bulk/intr sglists, sglen is the queue depth; it also * controls which subtests run (more tests than sglen) or rerun. */ - urb = kcalloc(param->sglen, sizeof(struct urb *), SLAB_KERNEL); + urb = kcalloc(param->sglen, sizeof(struct urb *), GFP_KERNEL); if (!urb) return -ENOMEM; for (i = 0; i < param->sglen; i++) { @@ -981,7 +981,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) if (!u) goto cleanup; - reqp = usb_buffer_alloc (udev, sizeof *reqp, SLAB_KERNEL, + reqp = usb_buffer_alloc (udev, sizeof *reqp, GFP_KERNEL, &u->setup_dma); if (!reqp) goto cleanup; @@ -1067,7 +1067,7 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async) * FIXME want additional tests for when endpoint is STALLing * due to errors, or is just NAKing requests. */ - if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) { + if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) { dev_dbg (&dev->intf->dev, "submit fail %d\n", retval); return retval; } @@ -1251,7 +1251,7 @@ static int ctrl_out (struct usbtest_dev *dev, if (length < 1 || length > 0xffff || vary >= length) return -EINVAL; - buf = kmalloc(length, SLAB_KERNEL); + buf = kmalloc(length, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1403,7 +1403,7 @@ static struct urb *iso_alloc_urb ( maxp *= 1 + (0x3 & (le16_to_cpu(desc->wMaxPacketSize) >> 11)); packets = (bytes + maxp - 1) / maxp; - urb = usb_alloc_urb (packets, SLAB_KERNEL); + urb = usb_alloc_urb (packets, GFP_KERNEL); if (!urb) return urb; urb->dev = udev; @@ -1411,7 +1411,7 @@ static struct urb *iso_alloc_urb ( urb->number_of_packets = packets; urb->transfer_buffer_length = bytes; - urb->transfer_buffer = usb_buffer_alloc (udev, bytes, SLAB_KERNEL, + urb->transfer_buffer = usb_buffer_alloc (udev, bytes, GFP_KERNEL, &urb->transfer_dma); if (!urb->transfer_buffer) { usb_free_urb (urb); @@ -1900,7 +1900,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) } #endif - dev = kzalloc(sizeof(*dev), SLAB_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; info = (struct usbtest_info *) id->driver_info; @@ -1910,7 +1910,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) dev->intf = intf; /* cacheline-aligned scratch for i/o */ - if ((dev->buf = kmalloc (TBUF_SIZE, SLAB_KERNEL)) == NULL) { + if ((dev->buf = kmalloc (TBUF_SIZE, GFP_KERNEL)) == NULL) { kfree (dev); return -ENOMEM; } diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index c2a28d88ef3c..99f26b3e502f 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -469,7 +469,7 @@ static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) struct rndis_halt *halt; /* try to clear any rndis state/activity (no i/o from stack!) */ - halt = kcalloc(1, sizeof *halt, SLAB_KERNEL); + halt = kcalloc(1, sizeof *halt, GFP_KERNEL); if (halt) { halt->msg_type = RNDIS_MSG_HALT; halt->msg_len = ccpu2(sizeof *halt); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 327f97555679..6e39e9988259 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -179,9 +179,9 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf) period = max ((int) dev->status->desc.bInterval, (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3); - buf = kmalloc (maxp, SLAB_KERNEL); + buf = kmalloc (maxp, GFP_KERNEL); if (buf) { - dev->interrupt = usb_alloc_urb (0, SLAB_KERNEL); + dev->interrupt = usb_alloc_urb (0, GFP_KERNEL); if (!dev->interrupt) { kfree (buf); return -ENOMEM; diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 9ade139086fc..52eb10ca654e 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -217,7 +217,7 @@ static kmem_cache_t *adfs_inode_cachep; static struct inode *adfs_alloc_inode(struct super_block *sb) { struct adfs_inode_info *ei; - ei = (struct adfs_inode_info *)kmem_cache_alloc(adfs_inode_cachep, SLAB_KERNEL); + ei = (struct adfs_inode_info *)kmem_cache_alloc(adfs_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/affs/super.c b/fs/affs/super.c index 5ea72c3a16c3..81c73ec09f66 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -71,7 +71,7 @@ static kmem_cache_t * affs_inode_cachep; static struct inode *affs_alloc_inode(struct super_block *sb) { struct affs_inode_info *ei; - ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, SLAB_KERNEL); + ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL); if (!ei) return NULL; ei->vfs_inode.i_version = 1; diff --git a/fs/afs/super.c b/fs/afs/super.c index 67d1f5c819ec..c6ead009bf78 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -412,7 +412,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb) struct afs_vnode *vnode; vnode = (struct afs_vnode *) - kmem_cache_alloc(afs_inode_cachep, SLAB_KERNEL); + kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); if (!vnode) return NULL; diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 07f7144f0e2e..995348df94ad 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -277,7 +277,7 @@ befs_alloc_inode(struct super_block *sb) { struct befs_inode_info *bi; bi = (struct befs_inode_info *)kmem_cache_alloc(befs_inode_cachep, - SLAB_KERNEL); + GFP_KERNEL); if (!bi) return NULL; return &bi->vfs_inode; diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index ed27ffb3459e..2e45123c8f7a 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -233,7 +233,7 @@ static kmem_cache_t * bfs_inode_cachep; static struct inode *bfs_alloc_inode(struct super_block *sb) { struct bfs_inode_info *bi; - bi = kmem_cache_alloc(bfs_inode_cachep, SLAB_KERNEL); + bi = kmem_cache_alloc(bfs_inode_cachep, GFP_KERNEL); if (!bi) return NULL; return &bi->vfs_inode; diff --git a/fs/block_dev.c b/fs/block_dev.c index 36c0e7af9d0f..063506705f27 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -239,7 +239,7 @@ static kmem_cache_t * bdev_cachep __read_mostly; static struct inode *bdev_alloc_inode(struct super_block *sb) { - struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, SLAB_KERNEL); + struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 84976cdbe713..84168629cea3 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -245,7 +245,7 @@ static struct inode * cifs_alloc_inode(struct super_block *sb) { struct cifsInodeInfo *cifs_inode; - cifs_inode = kmem_cache_alloc(cifs_inode_cachep, SLAB_KERNEL); + cifs_inode = kmem_cache_alloc(cifs_inode_cachep, GFP_KERNEL); if (!cifs_inode) return NULL; cifs_inode->cifsAttrs = 0x20; /* default */ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 8355daff504c..aedf683f011f 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -153,7 +153,7 @@ cifs_buf_get(void) albeit slightly larger than necessary and maxbuffersize defaults to this and can not be bigger */ ret_buf = - (struct smb_hdr *) mempool_alloc(cifs_req_poolp, SLAB_KERNEL | GFP_NOFS); + (struct smb_hdr *) mempool_alloc(cifs_req_poolp, GFP_KERNEL | GFP_NOFS); /* clear the first few header bytes */ /* for most paths, more is cleared in header_assemble */ @@ -192,7 +192,7 @@ cifs_small_buf_get(void) albeit slightly larger than necessary and maxbuffersize defaults to this and can not be bigger */ ret_buf = - (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, SLAB_KERNEL | GFP_NOFS); + (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, GFP_KERNEL | GFP_NOFS); if (ret_buf) { /* No need to clear memory here, cleared in header assemble */ /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 7514237cf31a..1f727765a8ea 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -51,7 +51,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) } temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp, - SLAB_KERNEL | GFP_NOFS); + GFP_KERNEL | GFP_NOFS); if (temp == NULL) return temp; else { @@ -118,7 +118,7 @@ AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon) return NULL; } temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep, - SLAB_KERNEL); + GFP_KERNEL); if (temp == NULL) return temp; else { diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 88d123321164..50cedd2617d6 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -43,7 +43,7 @@ static kmem_cache_t * coda_inode_cachep; static struct inode *coda_alloc_inode(struct super_block *sb) { struct coda_inode_info *ei; - ei = (struct coda_inode_info *)kmem_cache_alloc(coda_inode_cachep, SLAB_KERNEL); + ei = (struct coda_inode_info *)kmem_cache_alloc(coda_inode_cachep, GFP_KERNEL); if (!ei) return NULL; memset(&ei->c_fid, 0, sizeof(struct CodaFid)); diff --git a/fs/dnotify.c b/fs/dnotify.c index 2b0442db67e0..e778b1737b79 100644 --- a/fs/dnotify.c +++ b/fs/dnotify.c @@ -77,7 +77,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) inode = filp->f_dentry->d_inode; if (!S_ISDIR(inode->i_mode)) return -ENOTDIR; - dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL); + dn = kmem_cache_alloc(dn_cache, GFP_KERNEL); if (dn == NULL) return -ENOMEM; spin_lock(&inode->i_lock); diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 776b2eed371e..7196f50fe152 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -628,7 +628,7 @@ int ecryptfs_decrypt_page(struct file *file, struct page *page) num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size; base_extent = (page->index * num_extents_per_page); lower_page_virt = kmem_cache_alloc(ecryptfs_lower_page_cache, - SLAB_KERNEL); + GFP_KERNEL); if (!lower_page_virt) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Error getting page for encrypted " diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index a92ef05eff8f..42099e779a56 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -250,7 +250,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) int lower_flags; /* Released in ecryptfs_release or end of function if failure */ - file_info = kmem_cache_alloc(ecryptfs_file_info_cache, SLAB_KERNEL); + file_info = kmem_cache_alloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 70911412044d..8a1945a84c36 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -369,7 +369,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, BUG_ON(!atomic_read(&lower_dentry->d_count)); ecryptfs_set_dentry_private(dentry, kmem_cache_alloc(ecryptfs_dentry_info_cache, - SLAB_KERNEL)); + GFP_KERNEL)); if (!ecryptfs_dentry_to_private(dentry)) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Out of memory whilst attempting " @@ -795,7 +795,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) /* Released at out_free: label */ ecryptfs_set_file_private(&fake_ecryptfs_file, kmem_cache_alloc(ecryptfs_file_info_cache, - SLAB_KERNEL)); + GFP_KERNEL)); if (unlikely(!ecryptfs_file_to_private(&fake_ecryptfs_file))) { rc = -ENOMEM; goto out; diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index c3746f56d162..745c0f1bfbbd 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -207,7 +207,7 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, /* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or * at end of function upon failure */ auth_tok_list_item = - kmem_cache_alloc(ecryptfs_auth_tok_list_item_cache, SLAB_KERNEL); + kmem_cache_alloc(ecryptfs_auth_tok_list_item_cache, GFP_KERNEL); if (!auth_tok_list_item) { ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); rc = -ENOMEM; diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index a78d87d14baf..a2c6ccbce300 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -378,7 +378,7 @@ ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent) /* Released in ecryptfs_put_super() */ ecryptfs_set_superblock_private(sb, kmem_cache_alloc(ecryptfs_sb_info_cache, - SLAB_KERNEL)); + GFP_KERNEL)); if (!ecryptfs_superblock_to_private(sb)) { ecryptfs_printk(KERN_WARNING, "Out of memory\n"); rc = -ENOMEM; @@ -402,7 +402,7 @@ ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent) /* through deactivate_super(sb) from get_sb_nodev() */ ecryptfs_set_dentry_private(sb->s_root, kmem_cache_alloc(ecryptfs_dentry_info_cache, - SLAB_KERNEL)); + GFP_KERNEL)); if (!ecryptfs_dentry_to_private(sb->s_root)) { ecryptfs_printk(KERN_ERR, "dentry_info_cache alloc failed\n"); diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 825757ae4867..eaa5daaf106e 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -50,7 +50,7 @@ static struct inode *ecryptfs_alloc_inode(struct super_block *sb) struct inode *inode = NULL; ecryptfs_inode = kmem_cache_alloc(ecryptfs_inode_info_cache, - SLAB_KERNEL); + GFP_KERNEL); if (unlikely(!ecryptfs_inode)) goto out; ecryptfs_init_crypt_stat(&ecryptfs_inode->crypt_stat); diff --git a/fs/efs/super.c b/fs/efs/super.c index b3f50651eb6b..69b15a996cfc 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -57,7 +57,7 @@ static kmem_cache_t * efs_inode_cachep; static struct inode *efs_alloc_inode(struct super_block *sb) { struct efs_inode_info *ei; - ei = (struct efs_inode_info *)kmem_cache_alloc(efs_inode_cachep, SLAB_KERNEL); + ei = (struct efs_inode_info *)kmem_cache_alloc(efs_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/eventpoll.c b/fs/eventpoll.c index ae228ec54e94..f5c88435c6be 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -961,7 +961,7 @@ static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, struct epitem *epi = ep_item_from_epqueue(pt); struct eppoll_entry *pwq; - if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, SLAB_KERNEL))) { + if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, GFP_KERNEL))) { init_waitqueue_func_entry(&pwq->wait, ep_poll_callback); pwq->whead = whead; pwq->base = epi; @@ -1004,7 +1004,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, struct ep_pqueue epq; error = -ENOMEM; - if (!(epi = kmem_cache_alloc(epi_cache, SLAB_KERNEL))) + if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL))) goto eexit_1; /* Item initialization follow here ... */ diff --git a/fs/exec.c b/fs/exec.c index d993ea1a81ae..2092bd207463 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -404,7 +404,7 @@ int setup_arg_pages(struct linux_binprm *bprm, bprm->loader += stack_base; bprm->exec += stack_base; - mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + mpnt = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!mpnt) return -ENOMEM; diff --git a/fs/ext2/super.c b/fs/ext2/super.c index d8b9abd95d07..85c237e73853 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -140,7 +140,7 @@ static kmem_cache_t * ext2_inode_cachep; static struct inode *ext2_alloc_inode(struct super_block *sb) { struct ext2_inode_info *ei; - ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, SLAB_KERNEL); + ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL); if (!ei) return NULL; #ifdef CONFIG_EXT2_FS_POSIX_ACL diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 82cc4f59e3ba..8c272278455c 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -63,7 +63,7 @@ void fat_cache_destroy(void) static inline struct fat_cache *fat_cache_alloc(struct inode *inode) { - return kmem_cache_alloc(fat_cache_cachep, SLAB_KERNEL); + return kmem_cache_alloc(fat_cache_cachep, GFP_KERNEL); } static inline void fat_cache_free(struct fat_cache *cache) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 78945b53b0f8..b58fd0c9f3cd 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -482,7 +482,7 @@ static kmem_cache_t *fat_inode_cachep; static struct inode *fat_alloc_inode(struct super_block *sb) { struct msdos_inode_info *ei; - ei = kmem_cache_alloc(fat_inode_cachep, SLAB_KERNEL); + ei = kmem_cache_alloc(fat_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/fcntl.c b/fs/fcntl.c index e4f26165f12a..c03dc9cb21cb 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -567,7 +567,7 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap int result = 0; if (on) { - new = kmem_cache_alloc(fasync_cache, SLAB_KERNEL); + new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); if (!new) return -ENOMEM; } diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index 4786d51ad3bd..d2dd0d700077 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c @@ -103,7 +103,7 @@ vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino) struct vxfs_inode_info *vip; struct vxfs_dinode *dip; - if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, SLAB_KERNEL))) + if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL))) goto fail; dip = (struct vxfs_dinode *)(bp->b_data + offset); memcpy(vip, dip, sizeof(*vip)); @@ -145,7 +145,7 @@ __vxfs_iget(ino_t ino, struct inode *ilistp) struct vxfs_dinode *dip; caddr_t kaddr = (char *)page_address(pp); - if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, SLAB_KERNEL))) + if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL))) goto fail; dip = (struct vxfs_dinode *)(kaddr + offset); memcpy(vip, dip, sizeof(*vip)); diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 66571eafbb1e..8c15139f2756 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -41,7 +41,7 @@ static void fuse_request_init(struct fuse_req *req) struct fuse_req *fuse_request_alloc(void) { - struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL); + struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_KERNEL); if (req) fuse_request_init(req); return req; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index fc4203570370..e039e2047cce 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -46,7 +46,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) struct inode *inode; struct fuse_inode *fi; - inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL); + inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL); if (!inode) return NULL; diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 85b17b3fa4a0..ffc6409132c8 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -145,7 +145,7 @@ static struct inode *hfs_alloc_inode(struct super_block *sb) { struct hfs_inode_info *i; - i = kmem_cache_alloc(hfs_inode_cachep, SLAB_KERNEL); + i = kmem_cache_alloc(hfs_inode_cachep, GFP_KERNEL); return i ? &i->vfs_inode : NULL; } diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 194eede52fa4..4a0c70c76c8a 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -440,7 +440,7 @@ static struct inode *hfsplus_alloc_inode(struct super_block *sb) { struct hfsplus_inode_info *i; - i = kmem_cache_alloc(hfsplus_inode_cachep, SLAB_KERNEL); + i = kmem_cache_alloc(hfsplus_inode_cachep, GFP_KERNEL); return i ? &i->vfs_inode : NULL; } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 7f4756963d05..36e52173a54a 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -522,7 +522,7 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb) if (unlikely(!hugetlbfs_dec_free_inodes(sbinfo))) return NULL; - p = kmem_cache_alloc(hugetlbfs_inode_cachep, SLAB_KERNEL); + p = kmem_cache_alloc(hugetlbfs_inode_cachep, GFP_KERNEL); if (unlikely(!p)) { hugetlbfs_inc_free_inodes(sbinfo); return NULL; diff --git a/fs/inode.c b/fs/inode.c index 26cdb115ce67..dd15984d51a8 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -109,7 +109,7 @@ static struct inode *alloc_inode(struct super_block *sb) if (sb->s_op->alloc_inode) inode = sb->s_op->alloc_inode(sb); else - inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL); + inode = (struct inode *) kmem_cache_alloc(inode_cachep, GFP_KERNEL); if (inode) { struct address_space * const mapping = &inode->i_data; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index c34b862cdbf2..4b6381cd2cf4 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -62,7 +62,7 @@ static kmem_cache_t *isofs_inode_cachep; static struct inode *isofs_alloc_inode(struct super_block *sb) { struct iso_inode_info *ei; - ei = kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL); + ei = kmem_cache_alloc(isofs_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index bc4b8106a490..77be534ce422 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -33,7 +33,7 @@ static kmem_cache_t *jffs2_inode_cachep; static struct inode *jffs2_alloc_inode(struct super_block *sb) { struct jffs2_inode_info *ei; - ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL); + ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/locks.c b/fs/locks.c index e0b6a80649a0..a7b97d50c1e0 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -147,7 +147,7 @@ static kmem_cache_t *filelock_cache __read_mostly; /* Allocate an empty lock structure. */ static struct file_lock *locks_alloc_lock(void) { - return kmem_cache_alloc(filelock_cache, SLAB_KERNEL); + return kmem_cache_alloc(filelock_cache, GFP_KERNEL); } static void locks_release_private(struct file_lock *fl) diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 1e36bae4d0eb..ce532c2deda8 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -56,7 +56,7 @@ static kmem_cache_t * minix_inode_cachep; static struct inode *minix_alloc_inode(struct super_block *sb) { struct minix_inode_info *ei; - ei = (struct minix_inode_info *)kmem_cache_alloc(minix_inode_cachep, SLAB_KERNEL); + ei = (struct minix_inode_info *)kmem_cache_alloc(minix_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 72dad552aa00..ed84d899220c 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -45,7 +45,7 @@ static kmem_cache_t * ncp_inode_cachep; static struct inode *ncp_alloc_inode(struct super_block *sb) { struct ncp_inode_info *ei; - ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, SLAB_KERNEL); + ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index bdfabf854a51..769fd0a0c772 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -143,7 +143,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) { struct nfs_direct_req *dreq; - dreq = kmem_cache_alloc(nfs_direct_cachep, SLAB_KERNEL); + dreq = kmem_cache_alloc(nfs_direct_cachep, GFP_KERNEL); if (!dreq) return NULL; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 08cc4c5919ab..6b53aae4ed2c 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1080,7 +1080,7 @@ void nfs4_clear_inode(struct inode *inode) struct inode *nfs_alloc_inode(struct super_block *sb) { struct nfs_inode *nfsi; - nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, SLAB_KERNEL); + nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, GFP_KERNEL); if (!nfsi) return NULL; nfsi->flags = 0UL; diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 829af323f288..a1561a820abe 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -26,7 +26,7 @@ static inline struct nfs_page * nfs_page_alloc(void) { struct nfs_page *p; - p = kmem_cache_alloc(nfs_page_cachep, SLAB_KERNEL); + p = kmem_cache_alloc(nfs_page_cachep, GFP_KERNEL); if (p) { memset(p, 0, sizeof(*p)); INIT_LIST_HEAD(&p->wb_list); diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index 592a6402e851..911d1bcfc567 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -336,7 +336,7 @@ static struct inode *openprom_alloc_inode(struct super_block *sb) { struct op_inode_info *oi; - oi = kmem_cache_alloc(op_inode_cachep, SLAB_KERNEL); + oi = kmem_cache_alloc(op_inode_cachep, GFP_KERNEL); if (!oi) return NULL; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 49dfb2ab783e..b24cdb2f17c1 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -88,7 +88,7 @@ static struct inode *proc_alloc_inode(struct super_block *sb) struct proc_inode *ei; struct inode *inode; - ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, SLAB_KERNEL); + ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, GFP_KERNEL); if (!ei) return NULL; ei->pid = NULL; diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 5a41db2a218d..5b943eb11d76 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -520,7 +520,7 @@ static kmem_cache_t *qnx4_inode_cachep; static struct inode *qnx4_alloc_inode(struct super_block *sb) { struct qnx4_inode_info *ei; - ei = kmem_cache_alloc(qnx4_inode_cachep, SLAB_KERNEL); + ei = kmem_cache_alloc(qnx4_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 17249994110f..32332516d656 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -496,7 +496,7 @@ static struct inode *reiserfs_alloc_inode(struct super_block *sb) { struct reiserfs_inode_info *ei; ei = (struct reiserfs_inode_info *) - kmem_cache_alloc(reiserfs_inode_cachep, SLAB_KERNEL); + kmem_cache_alloc(reiserfs_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index ddcd9e1ef282..d1b455f9b669 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -555,7 +555,7 @@ static kmem_cache_t * romfs_inode_cachep; static struct inode *romfs_alloc_inode(struct super_block *sb) { struct romfs_inode_info *ei; - ei = (struct romfs_inode_info *)kmem_cache_alloc(romfs_inode_cachep, SLAB_KERNEL); + ei = (struct romfs_inode_info *)kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 2c122ee83adb..221617103484 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -55,7 +55,7 @@ static kmem_cache_t *smb_inode_cachep; static struct inode *smb_alloc_inode(struct super_block *sb) { struct smb_inode_info *ei; - ei = (struct smb_inode_info *)kmem_cache_alloc(smb_inode_cachep, SLAB_KERNEL); + ei = (struct smb_inode_info *)kmem_cache_alloc(smb_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c index 0fb74697abc4..3eb1402191b9 100644 --- a/fs/smbfs/request.c +++ b/fs/smbfs/request.c @@ -61,7 +61,7 @@ static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server, struct smb_request *req; unsigned char *buf = NULL; - req = kmem_cache_alloc(req_cachep, SLAB_KERNEL); + req = kmem_cache_alloc(req_cachep, GFP_KERNEL); VERBOSE("allocating request: %p\n", req); if (!req) goto out; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index d63c5e48b050..a6ca12b747cf 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -307,7 +307,7 @@ static struct inode *sysv_alloc_inode(struct super_block *sb) { struct sysv_inode_info *si; - si = kmem_cache_alloc(sysv_inode_cachep, SLAB_KERNEL); + si = kmem_cache_alloc(sysv_inode_cachep, GFP_KERNEL); if (!si) return NULL; return &si->vfs_inode; diff --git a/fs/udf/super.c b/fs/udf/super.c index 1aea6a4f9a4a..e50f24221dea 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -112,7 +112,7 @@ static kmem_cache_t * udf_inode_cachep; static struct inode *udf_alloc_inode(struct super_block *sb) { struct udf_inode_info *ei; - ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, SLAB_KERNEL); + ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, GFP_KERNEL); if (!ei) return NULL; diff --git a/fs/ufs/super.c b/fs/ufs/super.c index ec79e3091d1b..85a88c0c5e68 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1209,7 +1209,7 @@ static kmem_cache_t * ufs_inode_cachep; static struct inode *ufs_alloc_inode(struct super_block *sb) { struct ufs_inode_info *ei; - ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, SLAB_KERNEL); + ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, GFP_KERNEL); if (!ei) return NULL; ei->vfs_inode.i_version = 1; diff --git a/include/linux/fs.h b/include/linux/fs.h index a8039c8d8cbb..94b831b8157c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1483,7 +1483,7 @@ extern void __init vfs_caches_init(unsigned long); extern struct kmem_cache *names_cachep; -#define __getname() kmem_cache_alloc(names_cachep, SLAB_KERNEL) +#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL) #define __putname(name) kmem_cache_free(names_cachep, (void *)(name)) #ifndef CONFIG_AUDITSYSCALL #define putname(name) __putname(name) diff --git a/include/linux/rmap.h b/include/linux/rmap.h index db2c1df4fef9..61c2ab634b00 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -34,7 +34,7 @@ extern kmem_cache_t *anon_vma_cachep; static inline struct anon_vma *anon_vma_alloc(void) { - return kmem_cache_alloc(anon_vma_cachep, SLAB_KERNEL); + return kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL); } static inline void anon_vma_free(struct anon_vma *anon_vma) diff --git a/include/linux/slab.h b/include/linux/slab.h index 34b046ea88f1..639f65efa46e 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -19,7 +19,6 @@ typedef struct kmem_cache kmem_cache_t; #include /* kmalloc_sizes.h needs L1_CACHE_BYTES */ /* flags for kmem_cache_alloc() */ -#define SLAB_KERNEL GFP_KERNEL #define SLAB_DMA GFP_DMA /* flags to pass to kmem_cache_create(). diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h index 6562a2050a25..f81a5af8a4f8 100644 --- a/include/linux/taskstats_kern.h +++ b/include/linux/taskstats_kern.h @@ -35,7 +35,7 @@ static inline void taskstats_tgid_alloc(struct task_struct *tsk) return; /* No problem if kmem_cache_zalloc() fails */ - stats = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL); + stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); spin_lock_irq(&tsk->sighand->siglock); if (!sig->stats) { diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 7c274002c9f5..813bb941342b 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -224,7 +224,7 @@ static struct inode *mqueue_alloc_inode(struct super_block *sb) { struct mqueue_inode_info *ei; - ei = kmem_cache_alloc(mqueue_inode_cachep, SLAB_KERNEL); + ei = kmem_cache_alloc(mqueue_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 66a0ea48751d..70e9ec603082 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -41,7 +41,7 @@ void delayacct_init(void) void __delayacct_tsk_init(struct task_struct *tsk) { - tsk->delays = kmem_cache_zalloc(delayacct_cache, SLAB_KERNEL); + tsk->delays = kmem_cache_zalloc(delayacct_cache, GFP_KERNEL); if (tsk->delays) spin_lock_init(&tsk->delays->lock); } diff --git a/kernel/fork.c b/kernel/fork.c index 5678e6c61ef2..711aa5f10da7 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -237,7 +237,7 @@ static inline int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) goto fail_nomem; charge = len; } - tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + tmp = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!tmp) goto fail_nomem; *tmp = *mpnt; @@ -319,7 +319,7 @@ static inline void mm_free_pgd(struct mm_struct * mm) __cacheline_aligned_in_smp DEFINE_SPINLOCK(mmlist_lock); -#define allocate_mm() (kmem_cache_alloc(mm_cachep, SLAB_KERNEL)) +#define allocate_mm() (kmem_cache_alloc(mm_cachep, GFP_KERNEL)) #define free_mm(mm) (kmem_cache_free(mm_cachep, (mm))) #include @@ -621,7 +621,7 @@ static struct files_struct *alloc_files(void) struct files_struct *newf; struct fdtable *fdt; - newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); + newf = kmem_cache_alloc(files_cachep, GFP_KERNEL); if (!newf) goto out; diff --git a/kernel/taskstats.c b/kernel/taskstats.c index d3d28919d4b4..1b2b326cf703 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -425,7 +425,7 @@ void taskstats_exit_alloc(struct taskstats **ptidstats, unsigned int *mycpu) *mycpu = raw_smp_processor_id(); *ptidstats = NULL; - tmp = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL); + tmp = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); if (!tmp) return; diff --git a/kernel/user.c b/kernel/user.c index 220e586127a0..c1f93c164c93 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -132,7 +132,7 @@ struct user_struct * alloc_uid(uid_t uid) if (!up) { struct user_struct *new; - new = kmem_cache_alloc(uid_cachep, SLAB_KERNEL); + new = kmem_cache_alloc(uid_cachep, GFP_KERNEL); if (!new) return NULL; new->uid = uid; diff --git a/mm/mempolicy.c b/mm/mempolicy.c index e7b69c90cfd6..ad864f8708b0 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1326,7 +1326,7 @@ struct mempolicy *__mpol_copy(struct mempolicy *old) atomic_set(&new->refcnt, 1); if (new->policy == MPOL_BIND) { int sz = ksize(old->v.zonelist); - new->v.zonelist = kmemdup(old->v.zonelist, sz, SLAB_KERNEL); + new->v.zonelist = kmemdup(old->v.zonelist, sz, GFP_KERNEL); if (!new->v.zonelist) { kmem_cache_free(policy_cache, new); return ERR_PTR(-ENOMEM); diff --git a/mm/mmap.c b/mm/mmap.c index 7b40abd7cba2..7be110e98d4c 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1736,7 +1736,7 @@ int split_vma(struct mm_struct * mm, struct vm_area_struct * vma, if (mm->map_count >= sysctl_max_map_count) return -ENOMEM; - new = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!new) return -ENOMEM; @@ -2057,7 +2057,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, vma_start < new_vma->vm_end) *vmap = new_vma; } else { - new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + new_vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (new_vma) { *new_vma = *vma; pol = mpol_copy(vma_policy(vma)); diff --git a/mm/shmem.c b/mm/shmem.c index 4959535fc14c..bdaecfdaabd4 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2263,7 +2263,7 @@ static struct kmem_cache *shmem_inode_cachep; static struct inode *shmem_alloc_inode(struct super_block *sb) { struct shmem_inode_info *p; - p = (struct shmem_inode_info *)kmem_cache_alloc(shmem_inode_cachep, SLAB_KERNEL); + p = (struct shmem_inode_info *)kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL); if (!p) return NULL; return &p->vfs_inode; diff --git a/mm/slab.c b/mm/slab.c index 9f34b4946fba..1f374c1df018 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2237,7 +2237,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, align = ralign; /* Get cache's description obj. */ - cachep = kmem_cache_zalloc(&cache_cache, SLAB_KERNEL); + cachep = kmem_cache_zalloc(&cache_cache, GFP_KERNEL); if (!cachep) goto oops; diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index bdbc3f431668..101e5ccaf096 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -590,7 +590,7 @@ create: replace: err = -ENOBUFS; - new_f = kmem_cache_alloc(dn_hash_kmem, SLAB_KERNEL); + new_f = kmem_cache_alloc(dn_hash_kmem, GFP_KERNEL); if (new_f == NULL) goto out; diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 107bb6cbb0b3..4463443e42cd 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -485,13 +485,13 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) goto out; err = -ENOBUFS; - new_fa = kmem_cache_alloc(fn_alias_kmem, SLAB_KERNEL); + new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); if (new_fa == NULL) goto out; new_f = NULL; if (!f) { - new_f = kmem_cache_alloc(fn_hash_kmem, SLAB_KERNEL); + new_f = kmem_cache_alloc(fn_hash_kmem, GFP_KERNEL); if (new_f == NULL) goto out_free_new_fa; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index d17990ec724f..6be6caf1af37 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1187,7 +1187,7 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg) u8 state; err = -ENOBUFS; - new_fa = kmem_cache_alloc(fn_alias_kmem, SLAB_KERNEL); + new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); if (new_fa == NULL) goto out; @@ -1232,7 +1232,7 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg) goto out; err = -ENOBUFS; - new_fa = kmem_cache_alloc(fn_alias_kmem, SLAB_KERNEL); + new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); if (new_fa == NULL) goto out; diff --git a/net/socket.c b/net/socket.c index e8db54702a69..4f417c2ddc15 100644 --- a/net/socket.c +++ b/net/socket.c @@ -236,7 +236,7 @@ static struct inode *sock_alloc_inode(struct super_block *sb) { struct socket_alloc *ei; - ei = kmem_cache_alloc(sock_inode_cachep, SLAB_KERNEL); + ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); if (!ei) return NULL; init_waitqueue_head(&ei->socket.wait); diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 49dba5febbbd..df753d0a884b 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -143,7 +143,7 @@ static struct inode * rpc_alloc_inode(struct super_block *sb) { struct rpc_inode *rpci; - rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, SLAB_KERNEL); + rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); if (!rpci) return NULL; return &rpci->vfs_inode; diff --git a/security/keys/key.c b/security/keys/key.c index 70eacbe5abde..157bac658bf9 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -285,7 +285,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, } /* allocate and initialise the key and its description */ - key = kmem_cache_alloc(key_jar, SLAB_KERNEL); + key = kmem_cache_alloc(key_jar, GFP_KERNEL); if (!key) goto no_memory_2; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 78f98fe084eb..ac1aeed0b289 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -181,7 +181,7 @@ static int inode_alloc_security(struct inode *inode) struct task_security_struct *tsec = current->security; struct inode_security_struct *isec; - isec = kmem_cache_alloc(sel_inode_cache, SLAB_KERNEL); + isec = kmem_cache_alloc(sel_inode_cache, GFP_KERNEL); if (!isec) return -ENOMEM; diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index d049c7acbc8b..2dfc6134c2c2 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -36,7 +36,7 @@ avtab_insert_node(struct avtab *h, int hvalue, struct avtab_key *key, struct avtab_datum *datum) { struct avtab_node * newnode; - newnode = kmem_cache_alloc(avtab_node_cachep, SLAB_KERNEL); + newnode = kmem_cache_alloc(avtab_node_cachep, GFP_KERNEL); if (newnode == NULL) return NULL; memset(newnode, 0, sizeof(struct avtab_node)); -- cgit v1.2.3 From 441e143e95f5aa1e04026cb0aa71c801ba53982f Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:33:19 -0800 Subject: [PATCH] slab: remove SLAB_DMA SLAB_DMA is an alias of GFP_DMA. This is the last one so we remove the leftover comment too. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/atm/he.c | 6 +++--- drivers/s390/block/dasd_eckd.c | 2 +- drivers/s390/block/dasd_fba.c | 2 +- drivers/usb/core/buffer.c | 2 +- include/linux/slab.h | 3 --- mm/slab.c | 4 ++-- 6 files changed, 8 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/atm/he.c b/drivers/atm/he.c index ec8a7a633e68..7d9b4e52f0bf 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -820,7 +820,7 @@ he_init_group(struct he_dev *he_dev, int group) void *cpuaddr; #ifdef USE_RBPS_POOL - cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|SLAB_DMA, &dma_handle); + cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|GFP_DMA, &dma_handle); if (cpuaddr == NULL) return -ENOMEM; #else @@ -884,7 +884,7 @@ he_init_group(struct he_dev *he_dev, int group) void *cpuaddr; #ifdef USE_RBPL_POOL - cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|SLAB_DMA, &dma_handle); + cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &dma_handle); if (cpuaddr == NULL) return -ENOMEM; #else @@ -1724,7 +1724,7 @@ __alloc_tpd(struct he_dev *he_dev) struct he_tpd *tpd; dma_addr_t dma_handle; - tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|SLAB_DMA, &dma_handle); + tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &dma_handle); if (tpd == NULL) return NULL; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 5ecea3e4fdef..fdaa471e845f 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1215,7 +1215,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) dst = page_address(bv->bv_page) + bv->bv_offset; if (dasd_page_cache) { char *copy = kmem_cache_alloc(dasd_page_cache, - SLAB_DMA | __GFP_NOWARN); + GFP_DMA | __GFP_NOWARN); if (copy && rq_data_dir(req) == WRITE) memcpy(copy + bv->bv_offset, dst, bv->bv_len); if (copy) diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 80926c548228..b857fd5893fd 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -308,7 +308,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) dst = page_address(bv->bv_page) + bv->bv_offset; if (dasd_page_cache) { char *copy = kmem_cache_alloc(dasd_page_cache, - SLAB_DMA | __GFP_NOWARN); + GFP_DMA | __GFP_NOWARN); if (copy && rq_data_dir(req) == WRITE) memcpy(copy + bv->bv_offset, dst, bv->bv_len); if (copy) diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 840442a25b61..c3915dc28608 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -93,7 +93,7 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) } -/* sometimes alloc/free could use kmalloc with SLAB_DMA, for +/* sometimes alloc/free could use kmalloc with GFP_DMA, for * better sharing and to leverage mm/slab.c intelligence. */ diff --git a/include/linux/slab.h b/include/linux/slab.h index 639f65efa46e..fbcfc208f52b 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -18,9 +18,6 @@ typedef struct kmem_cache kmem_cache_t; #include /* kmalloc_sizes.h needs PAGE_SIZE */ #include /* kmalloc_sizes.h needs L1_CACHE_BYTES */ -/* flags for kmem_cache_alloc() */ -#define SLAB_DMA GFP_DMA - /* flags to pass to kmem_cache_create(). * The first 3 are only valid when the allocator as been build * SLAB_DEBUG_SUPPORT. diff --git a/mm/slab.c b/mm/slab.c index 1f374c1df018..bb831ba63e1e 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2637,7 +2637,7 @@ static void cache_init_objs(struct kmem_cache *cachep, static void kmem_flagcheck(struct kmem_cache *cachep, gfp_t flags) { - if (flags & SLAB_DMA) + if (flags & GFP_DMA) BUG_ON(!(cachep->gfpflags & GFP_DMA)); else BUG_ON(cachep->gfpflags & GFP_DMA); @@ -2721,7 +2721,7 @@ static int cache_grow(struct kmem_cache *cachep, gfp_t flags, int nodeid) * Be lazy and only check for valid flags here, keeping it out of the * critical path in kmem_cache_alloc(). */ - BUG_ON(flags & ~(SLAB_DMA | GFP_LEVEL_MASK | __GFP_NO_GROW)); + BUG_ON(flags & ~(GFP_DMA | GFP_LEVEL_MASK | __GFP_NO_GROW)); if (flags & __GFP_NO_GROW) return 0; -- cgit v1.2.3 From e18b890bb0881bbab6f4f1a6cd20d9c60d66b003 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 6 Dec 2006 20:33:20 -0800 Subject: [PATCH] slab: remove kmem_cache_t Replace all uses of kmem_cache_t with struct kmem_cache. The patch was generated using the following script: #!/bin/sh # # Replace one string by another in all the kernel sources. # set -e for file in `find * -name "*.c" -o -name "*.h"|xargs grep -l $1`; do quilt add $file sed -e "1,\$s/$1/$2/g" $file >/tmp/$$ mv /tmp/$$ $file quilt refresh done The script was run like this sh replace kmem_cache_t "struct kmem_cache" Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/DMA-API.txt | 4 ++-- arch/arm/mach-s3c2410/dma.c | 4 ++-- arch/arm26/mm/memc.c | 6 +++--- arch/frv/mm/pgalloc.c | 6 +++--- arch/i386/mm/init.c | 4 ++-- arch/i386/mm/pgtable.c | 6 +++--- arch/ia64/ia32/ia32_support.c | 2 +- arch/ia64/ia32/sys_ia32.c | 2 +- arch/powerpc/kernel/rtas_flash.c | 4 ++-- arch/powerpc/mm/hugetlbpage.c | 2 +- arch/powerpc/mm/init_64.c | 6 +++--- arch/powerpc/platforms/cell/spufs/inode.c | 4 ++-- arch/sh/kernel/cpu/sh4/sq.c | 2 +- arch/sh/mm/pmb.c | 6 +++--- arch/sparc64/mm/init.c | 4 ++-- arch/sparc64/mm/tsb.c | 2 +- block/cfq-iosched.c | 4 ++-- block/ll_rw_blk.c | 6 +++--- drivers/block/aoe/aoeblk.c | 2 +- drivers/ieee1394/eth1394.c | 2 +- drivers/md/dm-crypt.c | 2 +- drivers/md/dm-mpath.c | 2 +- drivers/md/dm-snap.c | 6 +++--- drivers/md/dm.c | 4 ++-- drivers/md/kcopyd.c | 2 +- drivers/md/raid5.c | 4 ++-- drivers/message/i2o/i2o_block.h | 2 +- drivers/pci/msi.c | 2 +- drivers/s390/block/dasd_devmap.c | 2 +- drivers/s390/block/dasd_int.h | 2 +- drivers/s390/scsi/zfcp_def.h | 6 +++--- drivers/scsi/aic94xx/aic94xx.h | 4 ++-- drivers/scsi/aic94xx/aic94xx_hwi.c | 2 +- drivers/scsi/aic94xx/aic94xx_init.c | 4 ++-- drivers/scsi/libsas/sas_init.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 2 +- drivers/scsi/qla4xxx/ql4_os.c | 2 +- drivers/scsi/scsi.c | 2 +- drivers/scsi/scsi_lib.c | 4 ++-- drivers/scsi/scsi_tgt_lib.c | 2 +- drivers/usb/host/hc_crisv10.c | 6 +++--- drivers/usb/host/uhci-hcd.c | 2 +- drivers/usb/mon/mon_text.c | 6 +++--- fs/adfs/super.c | 4 ++-- fs/affs/super.c | 4 ++-- fs/afs/super.c | 6 +++--- fs/aio.c | 4 ++-- fs/befs/linuxvfs.c | 4 ++-- fs/bfs/inode.c | 4 ++-- fs/bio.c | 4 ++-- fs/block_dev.c | 4 ++-- fs/buffer.c | 4 ++-- fs/cifs/cifsfs.c | 14 +++++++------- fs/cifs/transport.c | 2 +- fs/coda/inode.c | 4 ++-- fs/configfs/configfs_internal.h | 2 +- fs/configfs/mount.c | 2 +- fs/dcache.c | 6 +++--- fs/dcookies.c | 2 +- fs/dlm/memory.c | 2 +- fs/dnotify.c | 2 +- fs/dquot.c | 2 +- fs/ecryptfs/main.c | 2 +- fs/efs/super.c | 4 ++-- fs/eventpoll.c | 4 ++-- fs/ext2/super.c | 4 ++-- fs/ext3/super.c | 4 ++-- fs/ext4/super.c | 4 ++-- fs/fat/cache.c | 4 ++-- fs/fat/inode.c | 4 ++-- fs/fcntl.c | 2 +- fs/freevxfs/vxfs_inode.c | 2 +- fs/fuse/dev.c | 2 +- fs/fuse/inode.c | 4 ++-- fs/gfs2/main.c | 4 ++-- fs/gfs2/util.c | 6 +++--- fs/gfs2/util.h | 6 +++--- fs/hfs/super.c | 4 ++-- fs/hfsplus/super.c | 4 ++-- fs/hpfs/super.c | 4 ++-- fs/hugetlbfs/inode.c | 4 ++-- fs/inode.c | 4 ++-- fs/inotify_user.c | 4 ++-- fs/isofs/inode.c | 4 ++-- fs/jbd/journal.c | 6 +++--- fs/jbd/revoke.c | 4 ++-- fs/jbd2/journal.c | 6 +++--- fs/jbd2/revoke.c | 4 ++-- fs/jffs/inode-v23.c | 4 ++-- fs/jffs/jffs_fm.c | 4 ++-- fs/jffs2/malloc.c | 18 +++++++++--------- fs/jffs2/super.c | 4 ++-- fs/jfs/jfs_metapage.c | 4 ++-- fs/jfs/super.c | 4 ++-- fs/locks.c | 4 ++-- fs/mbcache.c | 2 +- fs/minix/inode.c | 4 ++-- fs/namespace.c | 2 +- fs/ncpfs/inode.c | 4 ++-- fs/nfs/direct.c | 2 +- fs/nfs/inode.c | 4 ++-- fs/nfs/pagelist.c | 2 +- fs/nfs/read.c | 2 +- fs/nfs/write.c | 2 +- fs/nfsd/nfs4state.c | 10 +++++----- fs/ocfs2/dlm/dlmfs.c | 4 ++-- fs/ocfs2/dlm/dlmmaster.c | 2 +- fs/ocfs2/extent_map.c | 2 +- fs/ocfs2/inode.h | 2 +- fs/ocfs2/super.c | 4 ++-- fs/ocfs2/uptodate.c | 2 +- fs/openpromfs/inode.c | 4 ++-- fs/proc/inode.c | 4 ++-- fs/qnx4/inode.c | 4 ++-- fs/reiserfs/super.c | 4 ++-- fs/romfs/inode.c | 4 ++-- fs/smbfs/inode.c | 4 ++-- fs/smbfs/request.c | 2 +- fs/sysfs/mount.c | 2 +- fs/sysfs/sysfs.h | 2 +- fs/sysv/inode.c | 4 ++-- fs/udf/super.c | 4 ++-- fs/ufs/super.c | 4 ++-- include/acpi/platform/aclinux.h | 2 +- include/asm-arm26/pgalloc.h | 2 +- include/asm-i386/pgtable.h | 10 +++++----- include/asm-powerpc/pgalloc.h | 2 +- include/asm-sparc64/pgalloc.h | 2 +- include/linux/delayacct.h | 2 +- include/linux/i2o.h | 2 +- include/linux/jbd.h | 2 +- include/linux/jbd2.h | 2 +- include/linux/raid/raid5.h | 2 +- include/linux/rmap.h | 2 +- include/linux/skbuff.h | 2 +- include/linux/taskstats_kern.h | 2 +- include/net/dst.h | 2 +- include/net/inet_hashtables.h | 6 +++--- include/net/neighbour.h | 2 +- include/net/netfilter/nf_conntrack_expect.h | 2 +- include/net/request_sock.h | 2 +- include/net/sock.h | 2 +- include/net/timewait_sock.h | 2 +- include/scsi/libsas.h | 4 ++-- ipc/mqueue.c | 4 ++-- kernel/delayacct.c | 2 +- kernel/fork.c | 16 ++++++++-------- kernel/pid.c | 2 +- kernel/posix-timers.c | 2 +- kernel/signal.c | 2 +- kernel/taskstats.c | 2 +- kernel/user.c | 2 +- lib/idr.c | 4 ++-- lib/radix-tree.c | 4 ++-- net/bridge/br_fdb.c | 2 +- net/core/flow.c | 2 +- net/core/skbuff.c | 8 ++++---- net/core/sock.c | 2 +- net/dccp/ackvec.c | 4 ++-- net/dccp/ccid.c | 6 +++--- net/dccp/ccid.h | 4 ++-- net/dccp/ccids/lib/loss_interval.h | 2 +- net/dccp/ccids/lib/packet_history.h | 4 ++-- net/decnet/dn_table.c | 2 +- net/ipv4/fib_hash.c | 4 ++-- net/ipv4/fib_trie.c | 2 +- net/ipv4/inet_hashtables.c | 4 ++-- net/ipv4/inetpeer.c | 2 +- net/ipv4/ipmr.c | 2 +- net/ipv4/ipvs/ip_vs_conn.c | 2 +- net/ipv4/netfilter/ip_conntrack_core.c | 4 ++-- net/ipv6/ip6_fib.c | 2 +- net/ipv6/xfrm6_tunnel.c | 2 +- net/netfilter/nf_conntrack_core.c | 6 +++--- net/netfilter/nf_conntrack_expect.c | 2 +- net/netfilter/xt_hashlimit.c | 2 +- net/sctp/protocol.c | 4 ++-- net/sctp/sm_make_chunk.c | 2 +- net/sctp/socket.c | 2 +- net/socket.c | 4 ++-- net/sunrpc/rpc_pipe.c | 4 ++-- net/sunrpc/sched.c | 4 ++-- net/tipc/handler.c | 2 +- net/xfrm/xfrm_input.c | 2 +- net/xfrm/xfrm_policy.c | 2 +- security/keys/key.c | 2 +- security/selinux/avc.c | 2 +- security/selinux/hooks.c | 2 +- security/selinux/ss/avtab.c | 2 +- 189 files changed, 332 insertions(+), 332 deletions(-) (limited to 'include/linux') diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt index 05431621c861..8621a064f7e1 100644 --- a/Documentation/DMA-API.txt +++ b/Documentation/DMA-API.txt @@ -77,7 +77,7 @@ To get this part of the dma_ API, you must #include Many drivers need lots of small dma-coherent memory regions for DMA descriptors or I/O buffers. Rather than allocating in units of a page or more using dma_alloc_coherent(), you can use DMA pools. These work -much like a kmem_cache_t, except that they use the dma-coherent allocator +much like a struct kmem_cache, except that they use the dma-coherent allocator not __get_free_pages(). Also, they understand common hardware constraints for alignment, like queue heads needing to be aligned on N byte boundaries. @@ -94,7 +94,7 @@ The pool create() routines initialize a pool of dma-coherent buffers for use with a given device. It must be called in a context which can sleep. -The "name" is for diagnostics (like a kmem_cache_t name); dev and size +The "name" is for diagnostics (like a struct kmem_cache name); dev and size are like what you'd pass to dma_alloc_coherent(). The device's hardware alignment requirement for this type of data is "align" (which is expressed in bytes, and must be a power of two). If your device has no boundary diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c index 3d211dc2f2f9..01abb0ace234 100644 --- a/arch/arm/mach-s3c2410/dma.c +++ b/arch/arm/mach-s3c2410/dma.c @@ -40,7 +40,7 @@ /* io map for dma */ static void __iomem *dma_base; -static kmem_cache_t *dma_kmem; +static struct kmem_cache *dma_kmem; struct s3c24xx_dma_selection dma_sel; @@ -1271,7 +1271,7 @@ struct sysdev_class dma_sysclass = { /* kmem cache implementation */ -static void s3c2410_dma_cache_ctor(void *p, kmem_cache_t *c, unsigned long f) +static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long f) { memset(p, 0, sizeof(struct s3c2410_dma_buf)); } diff --git a/arch/arm26/mm/memc.c b/arch/arm26/mm/memc.c index 34def6397c3c..f2901581d4da 100644 --- a/arch/arm26/mm/memc.c +++ b/arch/arm26/mm/memc.c @@ -24,7 +24,7 @@ #define MEMC_TABLE_SIZE (256*sizeof(unsigned long)) -kmem_cache_t *pte_cache, *pgd_cache; +struct kmem_cache *pte_cache, *pgd_cache; int page_nr; /* @@ -162,12 +162,12 @@ void __init create_memmap_holes(struct meminfo *mi) { } -static void pte_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags) +static void pte_cache_ctor(void *pte, struct kmem_cache *cache, unsigned long flags) { memzero(pte, sizeof(pte_t) * PTRS_PER_PTE); } -static void pgd_cache_ctor(void *pgd, kmem_cache_t *cache, unsigned long flags) +static void pgd_cache_ctor(void *pgd, struct kmem_cache *cache, unsigned long flags) { memzero(pgd + MEMC_TABLE_SIZE, USER_PTRS_PER_PGD * sizeof(pgd_t)); } diff --git a/arch/frv/mm/pgalloc.c b/arch/frv/mm/pgalloc.c index f76dd03ddd99..19b13be114a2 100644 --- a/arch/frv/mm/pgalloc.c +++ b/arch/frv/mm/pgalloc.c @@ -18,7 +18,7 @@ #include pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((aligned(PAGE_SIZE))); -kmem_cache_t *pgd_cache; +struct kmem_cache *pgd_cache; pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) { @@ -100,7 +100,7 @@ static inline void pgd_list_del(pgd_t *pgd) set_page_private(next, (unsigned long) pprev); } -void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) +void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused) { unsigned long flags; @@ -120,7 +120,7 @@ void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) } /* never called when PTRS_PER_PMD > 1 */ -void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused) +void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused) { unsigned long flags; /* can be called from interrupt context */ diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 167416155ee4..a6a8e397dd88 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -699,8 +699,8 @@ int remove_memory(u64 start, u64 size) #endif #endif -kmem_cache_t *pgd_cache; -kmem_cache_t *pmd_cache; +struct kmem_cache *pgd_cache; +struct kmem_cache *pmd_cache; void __init pgtable_cache_init(void) { diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c index 10126e3f8174..33be236fc6af 100644 --- a/arch/i386/mm/pgtable.c +++ b/arch/i386/mm/pgtable.c @@ -193,7 +193,7 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) return pte; } -void pmd_ctor(void *pmd, kmem_cache_t *cache, unsigned long flags) +void pmd_ctor(void *pmd, struct kmem_cache *cache, unsigned long flags) { memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); } @@ -233,7 +233,7 @@ static inline void pgd_list_del(pgd_t *pgd) set_page_private(next, (unsigned long)pprev); } -void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) +void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused) { unsigned long flags; @@ -253,7 +253,7 @@ void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) } /* never called when PTRS_PER_PMD > 1 */ -void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused) +void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused) { unsigned long flags; /* can be called from interrupt context */ diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c index c187743965a0..6af400a12ca1 100644 --- a/arch/ia64/ia32/ia32_support.c +++ b/arch/ia64/ia32/ia32_support.c @@ -249,7 +249,7 @@ ia32_init (void) #if PAGE_SHIFT > IA32_PAGE_SHIFT { - extern kmem_cache_t *partial_page_cachep; + extern struct kmem_cache *partial_page_cachep; partial_page_cachep = kmem_cache_create("partial_page_cache", sizeof(struct partial_page), 0, 0, diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index 9d6a3f210148..a4a6e1463af8 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -254,7 +254,7 @@ mmap_subpage (struct file *file, unsigned long start, unsigned long end, int pro } /* SLAB cache for partial_page structures */ -kmem_cache_t *partial_page_cachep; +struct kmem_cache *partial_page_cachep; /* * init partial_page_list. diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index b9561d300516..7d0f13fecc0e 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -101,7 +101,7 @@ struct flash_block_list_header { /* just the header of flash_block_list */ static struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; /* Use slab cache to guarantee 4k alignment */ -static kmem_cache_t *flash_block_cache = NULL; +static struct kmem_cache *flash_block_cache = NULL; #define FLASH_BLOCK_LIST_VERSION (1UL) @@ -286,7 +286,7 @@ static ssize_t rtas_flash_read(struct file *file, char __user *buf, } /* constructor for flash_block_cache */ -void rtas_block_ctor(void *ptr, kmem_cache_t *cache, unsigned long flags) +void rtas_block_ctor(void *ptr, struct kmem_cache *cache, unsigned long flags) { memset(ptr, 0, RTAS_BLK_SIZE); } diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 424a8f57e155..89c836d54809 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -1047,7 +1047,7 @@ repeat: return err; } -static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags) +static void zero_ctor(void *addr, struct kmem_cache *cache, unsigned long flags) { memset(addr, 0, kmem_cache_size(cache)); } diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index 9a178549cbcf..d12a87ec5ae9 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -141,7 +141,7 @@ static int __init setup_kcore(void) } module_init(setup_kcore); -static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags) +static void zero_ctor(void *addr, struct kmem_cache *cache, unsigned long flags) { memset(addr, 0, kmem_cache_size(cache)); } @@ -166,9 +166,9 @@ static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = { /* Hugepages need one extra cache, initialized in hugetlbpage.c. We * can't put into the tables above, because HPAGE_SHIFT is not compile * time constant. */ -kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)+1]; +struct kmem_cache *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)+1]; #else -kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)]; +struct kmem_cache *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)]; #endif void pgtable_cache_init(void) diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 7edfcc9d2853..e3af9112c026 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -40,7 +40,7 @@ #include "spufs.h" -static kmem_cache_t *spufs_inode_cache; +static struct kmem_cache *spufs_inode_cache; char *isolated_loader; static struct inode * @@ -65,7 +65,7 @@ spufs_destroy_inode(struct inode *inode) } static void -spufs_init_once(void *p, kmem_cache_t * cachep, unsigned long flags) +spufs_init_once(void *p, struct kmem_cache * cachep, unsigned long flags) { struct spufs_inode_info *ei = p; diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 55f43506995a..0c9ea38d2caa 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -38,7 +38,7 @@ struct sq_mapping { static struct sq_mapping *sq_mapping_list; static DEFINE_SPINLOCK(sq_mapping_lock); -static kmem_cache_t *sq_cache; +static struct kmem_cache *sq_cache; static unsigned long *sq_bitmap; #define store_queue_barrier() \ diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 92e745341e4d..b60ad83a7635 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -30,7 +30,7 @@ #define NR_PMB_ENTRIES 16 -static kmem_cache_t *pmb_cache; +static struct kmem_cache *pmb_cache; static unsigned long pmb_map; static struct pmb_entry pmb_init_map[] = { @@ -283,7 +283,7 @@ void pmb_unmap(unsigned long addr) } while (pmbe); } -static void pmb_cache_ctor(void *pmb, kmem_cache_t *cachep, unsigned long flags) +static void pmb_cache_ctor(void *pmb, struct kmem_cache *cachep, unsigned long flags) { struct pmb_entry *pmbe = pmb; @@ -297,7 +297,7 @@ static void pmb_cache_ctor(void *pmb, kmem_cache_t *cachep, unsigned long flags) spin_unlock_irq(&pmb_list_lock); } -static void pmb_cache_dtor(void *pmb, kmem_cache_t *cachep, unsigned long flags) +static void pmb_cache_dtor(void *pmb, struct kmem_cache *cachep, unsigned long flags) { spin_lock_irq(&pmb_list_lock); pmb_list_del(pmb); diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 09cb7fccc03a..a8e8802eed4d 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -176,9 +176,9 @@ unsigned long sparc64_kern_sec_context __read_mostly; int bigkernel = 0; -kmem_cache_t *pgtable_cache __read_mostly; +struct kmem_cache *pgtable_cache __read_mostly; -static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags) +static void zero_ctor(void *addr, struct kmem_cache *cache, unsigned long flags) { clear_page(addr); } diff --git a/arch/sparc64/mm/tsb.c b/arch/sparc64/mm/tsb.c index beaa02810f0e..236d02f41a01 100644 --- a/arch/sparc64/mm/tsb.c +++ b/arch/sparc64/mm/tsb.c @@ -239,7 +239,7 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign } } -static kmem_cache_t *tsb_caches[8] __read_mostly; +static struct kmem_cache *tsb_caches[8] __read_mostly; static const char *tsb_cache_names[8] = { "tsb_8KB", diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 84e9be073180..78c6b312bd30 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -43,8 +43,8 @@ static int cfq_slice_idle = HZ / 125; #define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private) #define RQ_CFQQ(rq) ((rq)->elevator_private2) -static kmem_cache_t *cfq_pool; -static kmem_cache_t *cfq_ioc_pool; +static struct kmem_cache *cfq_pool; +static struct kmem_cache *cfq_ioc_pool; static DEFINE_PER_CPU(unsigned long, ioc_count); static struct completion *ioc_gone; diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index cc6e95f8e5d9..a4ff3271d4a8 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -44,17 +44,17 @@ static struct io_context *current_io_context(gfp_t gfp_flags, int node); /* * For the allocated request tables */ -static kmem_cache_t *request_cachep; +static struct kmem_cache *request_cachep; /* * For queue allocation */ -static kmem_cache_t *requestq_cachep; +static struct kmem_cache *requestq_cachep; /* * For io context allocations */ -static kmem_cache_t *iocontext_cachep; +static struct kmem_cache *iocontext_cachep; /* * Controlling structure to kblockd diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index aa25f8b09fe3..478489c568a4 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -12,7 +12,7 @@ #include #include "aoe.h" -static kmem_cache_t *buf_pool_cache; +static struct kmem_cache *buf_pool_cache; static ssize_t aoedisk_show_state(struct gendisk * disk, char *page) { diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 31e5cc49d61a..27d6c642415d 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -133,7 +133,7 @@ struct eth1394_node_info { #define ETH1394_DRIVER_NAME "eth1394" static const char driver_name[] = ETH1394_DRIVER_NAME; -static kmem_cache_t *packet_task_cache; +static struct kmem_cache *packet_task_cache; static struct hpsb_highlevel eth1394_highlevel; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index ed2d4ef27fd8..c7bee4f2eedb 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -101,7 +101,7 @@ struct crypt_config { #define MIN_POOL_PAGES 32 #define MIN_BIO_PAGES 8 -static kmem_cache_t *_crypt_io_pool; +static struct kmem_cache *_crypt_io_pool; /* * Different IV generation algorithms: diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index e77ee6fd1044..cf8bf052138e 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -101,7 +101,7 @@ typedef int (*action_fn) (struct pgpath *pgpath); #define MIN_IOS 256 /* Mempool size */ -static kmem_cache_t *_mpio_cache; +static struct kmem_cache *_mpio_cache; struct workqueue_struct *kmultipathd; static void process_queued_ios(struct work_struct *work); diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 91c7aa1fed0e..b0ce2ce82278 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -88,8 +88,8 @@ struct pending_exception { * Hash table mapping origin volumes to lists of snapshots and * a lock to protect it */ -static kmem_cache_t *exception_cache; -static kmem_cache_t *pending_cache; +static struct kmem_cache *exception_cache; +static struct kmem_cache *pending_cache; static mempool_t *pending_pool; /* @@ -228,7 +228,7 @@ static int init_exception_table(struct exception_table *et, uint32_t size) return 0; } -static void exit_exception_table(struct exception_table *et, kmem_cache_t *mem) +static void exit_exception_table(struct exception_table *et, struct kmem_cache *mem) { struct list_head *slot; struct exception *ex, *next; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index fc4f743f3b53..7ec1b112a6d5 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -121,8 +121,8 @@ struct mapped_device { }; #define MIN_IOS 256 -static kmem_cache_t *_io_cache; -static kmem_cache_t *_tio_cache; +static struct kmem_cache *_io_cache; +static struct kmem_cache *_tio_cache; static int __init local_init(void) { diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c index b3c01496c737..b46f6c575f7e 100644 --- a/drivers/md/kcopyd.c +++ b/drivers/md/kcopyd.c @@ -203,7 +203,7 @@ struct kcopyd_job { /* FIXME: this should scale with the number of pages */ #define MIN_JOBS 512 -static kmem_cache_t *_job_cache; +static struct kmem_cache *_job_cache; static mempool_t *_job_pool; /* diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 69c3e201fa3b..52914d5cec76 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -348,7 +348,7 @@ static int grow_one_stripe(raid5_conf_t *conf) static int grow_stripes(raid5_conf_t *conf, int num) { - kmem_cache_t *sc; + struct kmem_cache *sc; int devs = conf->raid_disks; sprintf(conf->cache_name[0], "raid5/%s", mdname(conf->mddev)); @@ -397,7 +397,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize) LIST_HEAD(newstripes); struct disk_info *ndisks; int err = 0; - kmem_cache_t *sc; + struct kmem_cache *sc; int i; if (newsize <= conf->pool_size) diff --git a/drivers/message/i2o/i2o_block.h b/drivers/message/i2o/i2o_block.h index d9fdc95b440d..67f921b4419b 100644 --- a/drivers/message/i2o/i2o_block.h +++ b/drivers/message/i2o/i2o_block.h @@ -64,7 +64,7 @@ /* I2O Block OSM mempool struct */ struct i2o_block_mempool { - kmem_cache_t *slab; + struct kmem_cache *slab; mempool_t *pool; }; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9fc9a34ef24a..9168401401bc 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -26,7 +26,7 @@ static DEFINE_SPINLOCK(msi_lock); static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; -static kmem_cache_t* msi_cachep; +static struct kmem_cache* msi_cachep; static int pci_msi_enable = 1; diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 17fdd8c9f740..cf28ccc57948 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -25,7 +25,7 @@ #include "dasd_int.h" -kmem_cache_t *dasd_page_cache; +struct kmem_cache *dasd_page_cache; EXPORT_SYMBOL_GPL(dasd_page_cache); /* diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 9f52004f6fc2..dc5dd509434d 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -474,7 +474,7 @@ extern struct dasd_profile_info_t dasd_global_profile; extern unsigned int dasd_profile_level; extern struct block_device_operations dasd_device_operations; -extern kmem_cache_t *dasd_page_cache; +extern struct kmem_cache *dasd_page_cache; struct dasd_ccw_req * dasd_kmalloc_request(char *, int, int, struct dasd_device *); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 74c0eac083e4..32933ed54b8a 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -1032,9 +1032,9 @@ struct zfcp_data { wwn_t init_wwpn; fcp_lun_t init_fcp_lun; char *driver_version; - kmem_cache_t *fsf_req_qtcb_cache; - kmem_cache_t *sr_buffer_cache; - kmem_cache_t *gid_pn_cache; + struct kmem_cache *fsf_req_qtcb_cache; + struct kmem_cache *sr_buffer_cache; + struct kmem_cache *gid_pn_cache; }; /** diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h index 71a031df7a34..32f513b1b78a 100644 --- a/drivers/scsi/aic94xx/aic94xx.h +++ b/drivers/scsi/aic94xx/aic94xx.h @@ -56,8 +56,8 @@ /* 2*ITNL timeout + 1 second */ #define AIC94XX_SCB_TIMEOUT (5*HZ) -extern kmem_cache_t *asd_dma_token_cache; -extern kmem_cache_t *asd_ascb_cache; +extern struct kmem_cache *asd_dma_token_cache; +extern struct kmem_cache *asd_ascb_cache; extern char sas_addr_str[2*SAS_ADDR_SIZE + 1]; static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr) diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index af7e01134364..da94e126ca83 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -1047,7 +1047,7 @@ irqreturn_t asd_hw_isr(int irq, void *dev_id) static inline struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha, gfp_t gfp_flags) { - extern kmem_cache_t *asd_ascb_cache; + extern struct kmem_cache *asd_ascb_cache; struct asd_seq_data *seq = &asd_ha->seq; struct asd_ascb *ascb; unsigned long flags; diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 42302ef05ee5..fbc82b00a418 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -450,8 +450,8 @@ static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha) asd_ha->scb_pool = NULL; } -kmem_cache_t *asd_dma_token_cache; -kmem_cache_t *asd_ascb_cache; +struct kmem_cache *asd_dma_token_cache; +struct kmem_cache *asd_ascb_cache; static int asd_create_global_caches(void) { diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index d65bc4e0f214..2f0c07fc3f48 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -36,7 +36,7 @@ #include "../scsi_sas_internal.h" -kmem_cache_t *sas_task_cache; +struct kmem_cache *sas_task_cache; /*------------ SAS addr hash -----------*/ void sas_hash_addr(u8 *hashed, const u8 *sas_addr) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index cbe0cad83b68..d03523d3bf38 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -24,7 +24,7 @@ char qla2x00_version_str[40]; /* * SRB allocation cache */ -static kmem_cache_t *srb_cachep; +static struct kmem_cache *srb_cachep; /* * Ioctl related information. diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 969c9e431028..9ef693c8809a 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -19,7 +19,7 @@ char qla4xxx_version_str[40]; /* * SRB allocation cache */ -static kmem_cache_t *srb_cachep; +static struct kmem_cache *srb_cachep; /* * Module parameter information and variables diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index fafc00deaade..24cffd98ee63 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -136,7 +136,7 @@ const char * scsi_device_type(unsigned type) EXPORT_SYMBOL(scsi_device_type); struct scsi_host_cmd_pool { - kmem_cache_t *slab; + struct kmem_cache *slab; unsigned int users; char *name; unsigned int slab_flags; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index fb616c69151f..1748e27501cd 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -36,7 +36,7 @@ struct scsi_host_sg_pool { size_t size; char *name; - kmem_cache_t *slab; + struct kmem_cache *slab; mempool_t *pool; }; @@ -241,7 +241,7 @@ struct scsi_io_context { char sense[SCSI_SENSE_BUFFERSIZE]; }; -static kmem_cache_t *scsi_io_context_cache; +static struct kmem_cache *scsi_io_context_cache; static void scsi_end_async(struct request *req, int uptodate) { diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 386dbae17b44..d402aff5f314 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -33,7 +33,7 @@ #include "scsi_tgt_priv.h" static struct workqueue_struct *scsi_tgtd; -static kmem_cache_t *scsi_tgt_cmd_cache; +static struct kmem_cache *scsi_tgt_cmd_cache; /* * TODO: this struct will be killed when the block layer supports large bios diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 7fd872aa654a..9325e46a68c0 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -275,13 +275,13 @@ static volatile USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4))); static int zout_buffer[4] __attribute__ ((aligned (4))); /* Cache for allocating new EP and SB descriptors. */ -static kmem_cache_t *usb_desc_cache; +static struct kmem_cache *usb_desc_cache; /* Cache for the registers allocated in the top half. */ -static kmem_cache_t *top_half_reg_cache; +static struct kmem_cache *top_half_reg_cache; /* Cache for the data allocated in the isoc descr top half. */ -static kmem_cache_t *isoc_compl_cache; +static struct kmem_cache *isoc_compl_cache; static struct usb_bus *etrax_usb_bus; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 226bf3de8edd..e87692c31be4 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -81,7 +81,7 @@ MODULE_PARM_DESC(debug, "Debug level"); static char *errbuf; #define ERRBUF_LEN (32 * 1024) -static kmem_cache_t *uhci_up_cachep; /* urb_priv */ +static struct kmem_cache *uhci_up_cachep; /* urb_priv */ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state); static void wakeup_rh(struct uhci_hcd *uhci); diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 46aecc8754f1..05cf2c9a8f84 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -50,7 +50,7 @@ struct mon_event_text { #define SLAB_NAME_SZ 30 struct mon_reader_text { - kmem_cache_t *e_slab; + struct kmem_cache *e_slab; int nevents; struct list_head e_list; struct mon_reader r; /* In C, parent class can be placed anywhere */ @@ -63,7 +63,7 @@ struct mon_reader_text { char slab_name[SLAB_NAME_SZ]; }; -static void mon_text_ctor(void *, kmem_cache_t *, unsigned long); +static void mon_text_ctor(void *, struct kmem_cache *, unsigned long); /* * mon_text_submit @@ -450,7 +450,7 @@ const struct file_operations mon_fops_text = { /* * Slab interface: constructor. */ -static void mon_text_ctor(void *mem, kmem_cache_t *slab, unsigned long sflags) +static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sflags) { /* * Nothing to initialize. No, really! diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 52eb10ca654e..e5a205c9f42f 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -212,7 +212,7 @@ static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static kmem_cache_t *adfs_inode_cachep; +static struct kmem_cache *adfs_inode_cachep; static struct inode *adfs_alloc_inode(struct super_block *sb) { @@ -228,7 +228,7 @@ static void adfs_destroy_inode(struct inode *inode) kmem_cache_free(adfs_inode_cachep, ADFS_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct adfs_inode_info *ei = (struct adfs_inode_info *) foo; diff --git a/fs/affs/super.c b/fs/affs/super.c index 81c73ec09f66..3de93e799949 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -66,7 +66,7 @@ affs_write_super(struct super_block *sb) pr_debug("AFFS: write_super() at %lu, clean=%d\n", get_seconds(), clean); } -static kmem_cache_t * affs_inode_cachep; +static struct kmem_cache * affs_inode_cachep; static struct inode *affs_alloc_inode(struct super_block *sb) { @@ -83,7 +83,7 @@ static void affs_destroy_inode(struct inode *inode) kmem_cache_free(affs_inode_cachep, AFFS_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct affs_inode_info *ei = (struct affs_inode_info *) foo; diff --git a/fs/afs/super.c b/fs/afs/super.c index c6ead009bf78..9a351c4c7564 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -35,7 +35,7 @@ struct afs_mount_params { struct afs_volume *volume; }; -static void afs_i_init_once(void *foo, kmem_cache_t *cachep, +static void afs_i_init_once(void *foo, struct kmem_cache *cachep, unsigned long flags); static int afs_get_sb(struct file_system_type *fs_type, @@ -65,7 +65,7 @@ static struct super_operations afs_super_ops = { .put_super = afs_put_super, }; -static kmem_cache_t *afs_inode_cachep; +static struct kmem_cache *afs_inode_cachep; static atomic_t afs_count_active_inodes; /*****************************************************************************/ @@ -384,7 +384,7 @@ static void afs_put_super(struct super_block *sb) /* * initialise an inode cache slab element prior to any use */ -static void afs_i_init_once(void *_vnode, kmem_cache_t *cachep, +static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep, unsigned long flags) { struct afs_vnode *vnode = (struct afs_vnode *) _vnode; diff --git a/fs/aio.c b/fs/aio.c index 287a1bc7a182..13aa9298abf4 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -47,8 +47,8 @@ unsigned long aio_nr; /* current system wide number of aio requests */ unsigned long aio_max_nr = 0x10000; /* system wide maximum number of aio requests */ /*----end sysctl variables---*/ -static kmem_cache_t *kiocb_cachep; -static kmem_cache_t *kioctx_cachep; +static struct kmem_cache *kiocb_cachep; +static struct kmem_cache *kioctx_cachep; static struct workqueue_struct *aio_wq; diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 995348df94ad..bce402eee554 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -61,7 +61,7 @@ static const struct super_operations befs_sops = { }; /* slab cache for befs_inode_info objects */ -static kmem_cache_t *befs_inode_cachep; +static struct kmem_cache *befs_inode_cachep; static const struct file_operations befs_dir_operations = { .read = generic_read_dir, @@ -289,7 +289,7 @@ befs_destroy_inode(struct inode *inode) kmem_cache_free(befs_inode_cachep, BEFS_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct befs_inode_info *bi = (struct befs_inode_info *) foo; diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 2e45123c8f7a..eac175ed9f44 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -228,7 +228,7 @@ static void bfs_write_super(struct super_block *s) unlock_kernel(); } -static kmem_cache_t * bfs_inode_cachep; +static struct kmem_cache * bfs_inode_cachep; static struct inode *bfs_alloc_inode(struct super_block *sb) { @@ -244,7 +244,7 @@ static void bfs_destroy_inode(struct inode *inode) kmem_cache_free(bfs_inode_cachep, BFS_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct bfs_inode_info *bi = foo; diff --git a/fs/bio.c b/fs/bio.c index 50c40ce2cead..7ec737eda72b 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -30,7 +30,7 @@ #define BIO_POOL_SIZE 256 -static kmem_cache_t *bio_slab __read_mostly; +static struct kmem_cache *bio_slab __read_mostly; #define BIOVEC_NR_POOLS 6 @@ -44,7 +44,7 @@ mempool_t *bio_split_pool __read_mostly; struct biovec_slab { int nr_vecs; char *name; - kmem_cache_t *slab; + struct kmem_cache *slab; }; /* diff --git a/fs/block_dev.c b/fs/block_dev.c index 063506705f27..13816b4d76f6 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -235,7 +235,7 @@ static int block_fsync(struct file *filp, struct dentry *dentry, int datasync) */ static __cacheline_aligned_in_smp DEFINE_SPINLOCK(bdev_lock); -static kmem_cache_t * bdev_cachep __read_mostly; +static struct kmem_cache * bdev_cachep __read_mostly; static struct inode *bdev_alloc_inode(struct super_block *sb) { @@ -253,7 +253,7 @@ static void bdev_destroy_inode(struct inode *inode) kmem_cache_free(bdev_cachep, bdi); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct bdev_inode *ei = (struct bdev_inode *) foo; struct block_device *bdev = &ei->bdev; diff --git a/fs/buffer.c b/fs/buffer.c index 35527dca1dbc..a8ca0ac21488 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2908,7 +2908,7 @@ asmlinkage long sys_bdflush(int func, long data) /* * Buffer-head allocation */ -static kmem_cache_t *bh_cachep; +static struct kmem_cache *bh_cachep; /* * Once the number of bh's in the machine exceeds this level, we start @@ -2961,7 +2961,7 @@ void free_buffer_head(struct buffer_head *bh) EXPORT_SYMBOL(free_buffer_head); static void -init_buffer_head(void *data, kmem_cache_t *cachep, unsigned long flags) +init_buffer_head(void *data, struct kmem_cache *cachep, unsigned long flags) { if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 84168629cea3..e6b5866e5001 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -81,7 +81,7 @@ extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_mid_poolp; -extern kmem_cache_t *cifs_oplock_cachep; +extern struct kmem_cache *cifs_oplock_cachep; static int cifs_read_super(struct super_block *sb, void *data, @@ -232,11 +232,11 @@ static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) return generic_permission(inode, mask, NULL); } -static kmem_cache_t *cifs_inode_cachep; -static kmem_cache_t *cifs_req_cachep; -static kmem_cache_t *cifs_mid_cachep; -kmem_cache_t *cifs_oplock_cachep; -static kmem_cache_t *cifs_sm_req_cachep; +static struct kmem_cache *cifs_inode_cachep; +static struct kmem_cache *cifs_req_cachep; +static struct kmem_cache *cifs_mid_cachep; +struct kmem_cache *cifs_oplock_cachep; +static struct kmem_cache *cifs_sm_req_cachep; mempool_t *cifs_sm_req_poolp; mempool_t *cifs_req_poolp; mempool_t *cifs_mid_poolp; @@ -668,7 +668,7 @@ const struct file_operations cifs_dir_ops = { }; static void -cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags) +cifs_init_once(void *inode, struct kmem_cache * cachep, unsigned long flags) { struct cifsInodeInfo *cifsi = inode; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 1f727765a8ea..f80007eaebf4 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -34,7 +34,7 @@ #include "cifs_debug.h" extern mempool_t *cifs_mid_poolp; -extern kmem_cache_t *cifs_oplock_cachep; +extern struct kmem_cache *cifs_oplock_cachep; static struct mid_q_entry * AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 50cedd2617d6..b64659fa82d0 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -38,7 +38,7 @@ static void coda_clear_inode(struct inode *); static void coda_put_super(struct super_block *); static int coda_statfs(struct dentry *dentry, struct kstatfs *buf); -static kmem_cache_t * coda_inode_cachep; +static struct kmem_cache * coda_inode_cachep; static struct inode *coda_alloc_inode(struct super_block *sb) { @@ -58,7 +58,7 @@ static void coda_destroy_inode(struct inode *inode) kmem_cache_free(coda_inode_cachep, ITOC(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct coda_inode_info *ei = (struct coda_inode_info *) foo; diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index 3f4ff7a242b9..f92cd303d2c9 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h @@ -49,7 +49,7 @@ struct configfs_dirent { #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR) extern struct vfsmount * configfs_mount; -extern kmem_cache_t *configfs_dir_cachep; +extern struct kmem_cache *configfs_dir_cachep; extern int configfs_is_root(struct config_item *item); diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 68bd5c93ca52..ed678529ebb2 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -38,7 +38,7 @@ struct vfsmount * configfs_mount = NULL; struct super_block * configfs_sb = NULL; -kmem_cache_t *configfs_dir_cachep; +struct kmem_cache *configfs_dir_cachep; static int configfs_mnt_count = 0; static struct super_operations configfs_ops = { diff --git a/fs/dcache.c b/fs/dcache.c index fd4a428998ef..a7c67cee5d83 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -43,7 +43,7 @@ static __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); EXPORT_SYMBOL(dcache_lock); -static kmem_cache_t *dentry_cache __read_mostly; +static struct kmem_cache *dentry_cache __read_mostly; #define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname)) @@ -2072,10 +2072,10 @@ static void __init dcache_init(unsigned long mempages) } /* SLAB cache for __getname() consumers */ -kmem_cache_t *names_cachep __read_mostly; +struct kmem_cache *names_cachep __read_mostly; /* SLAB cache for file structures */ -kmem_cache_t *filp_cachep __read_mostly; +struct kmem_cache *filp_cachep __read_mostly; EXPORT_SYMBOL(d_genocide); diff --git a/fs/dcookies.c b/fs/dcookies.c index 0c4b0674854b..21af1629f9bc 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c @@ -37,7 +37,7 @@ struct dcookie_struct { static LIST_HEAD(dcookie_users); static DEFINE_MUTEX(dcookie_mutex); -static kmem_cache_t *dcookie_cache __read_mostly; +static struct kmem_cache *dcookie_cache __read_mostly; static struct list_head *dcookie_hashtable __read_mostly; static size_t hash_size __read_mostly; diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c index 989b608fd836..5352b03ff5aa 100644 --- a/fs/dlm/memory.c +++ b/fs/dlm/memory.c @@ -15,7 +15,7 @@ #include "config.h" #include "memory.h" -static kmem_cache_t *lkb_cache; +static struct kmem_cache *lkb_cache; int dlm_memory_init(void) diff --git a/fs/dnotify.c b/fs/dnotify.c index e778b1737b79..1f26a2b9eee1 100644 --- a/fs/dnotify.c +++ b/fs/dnotify.c @@ -23,7 +23,7 @@ int dir_notify_enable __read_mostly = 1; -static kmem_cache_t *dn_cache __read_mostly; +static struct kmem_cache *dn_cache __read_mostly; static void redo_inode_mask(struct inode *inode) { diff --git a/fs/dquot.c b/fs/dquot.c index c6ae6c0e0cfc..f9cd5e23ebdf 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -131,7 +131,7 @@ 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; +static struct kmem_cache *dquot_cachep; int register_quota_format(struct quota_format_type *fmt) { diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index a2c6ccbce300..306f8fbd1a08 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -546,7 +546,7 @@ inode_info_init_once(void *vptr, struct kmem_cache *cachep, unsigned long flags) } static struct ecryptfs_cache_info { - kmem_cache_t **cache; + struct kmem_cache **cache; const char *name; size_t size; void (*ctor)(void*, struct kmem_cache *, unsigned long); diff --git a/fs/efs/super.c b/fs/efs/super.c index 69b15a996cfc..dfebf21289f4 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -52,7 +52,7 @@ static struct pt_types sgi_pt_types[] = { }; -static kmem_cache_t * efs_inode_cachep; +static struct kmem_cache * efs_inode_cachep; static struct inode *efs_alloc_inode(struct super_block *sb) { @@ -68,7 +68,7 @@ static void efs_destroy_inode(struct inode *inode) kmem_cache_free(efs_inode_cachep, INODE_INFO(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct efs_inode_info *ei = (struct efs_inode_info *) foo; diff --git a/fs/eventpoll.c b/fs/eventpoll.c index f5c88435c6be..88a6f8d0b88e 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -283,10 +283,10 @@ static struct mutex epmutex; static struct poll_safewake psw; /* Slab cache used to allocate "struct epitem" */ -static kmem_cache_t *epi_cache __read_mostly; +static struct kmem_cache *epi_cache __read_mostly; /* Slab cache used to allocate "struct eppoll_entry" */ -static kmem_cache_t *pwq_cache __read_mostly; +static struct kmem_cache *pwq_cache __read_mostly; /* Virtual fs used to allocate inodes for eventpoll files */ static struct vfsmount *eventpoll_mnt __read_mostly; diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 85c237e73853..3aafb1dd917a 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -135,7 +135,7 @@ static void ext2_put_super (struct super_block * sb) return; } -static kmem_cache_t * ext2_inode_cachep; +static struct kmem_cache * ext2_inode_cachep; static struct inode *ext2_alloc_inode(struct super_block *sb) { @@ -156,7 +156,7 @@ static void ext2_destroy_inode(struct inode *inode) kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct ext2_inode_info *ei = (struct ext2_inode_info *) foo; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 0cf633f0cfa3..9856565d4ddc 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -436,7 +436,7 @@ static void ext3_put_super (struct super_block * sb) return; } -static kmem_cache_t *ext3_inode_cachep; +static struct kmem_cache *ext3_inode_cachep; /* * Called inside transaction, so use GFP_NOFS @@ -462,7 +462,7 @@ static void ext3_destroy_inode(struct inode *inode) kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct ext3_inode_info *ei = (struct ext3_inode_info *) foo; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c730cbc84030..f2e8c4aa0fd2 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -486,7 +486,7 @@ static void ext4_put_super (struct super_block * sb) return; } -static kmem_cache_t *ext4_inode_cachep; +static struct kmem_cache *ext4_inode_cachep; /* * Called inside transaction, so use GFP_NOFS @@ -513,7 +513,7 @@ static void ext4_destroy_inode(struct inode *inode) kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 8c272278455c..05c2941c74f2 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -34,9 +34,9 @@ static inline int fat_max_cache(struct inode *inode) return FAT_MAX_CACHE; } -static kmem_cache_t *fat_cache_cachep; +static struct kmem_cache *fat_cache_cachep; -static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) +static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) { struct fat_cache *cache = (struct fat_cache *)foo; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index b58fd0c9f3cd..a9e4688582a2 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -477,7 +477,7 @@ static void fat_put_super(struct super_block *sb) kfree(sbi); } -static kmem_cache_t *fat_inode_cachep; +static struct kmem_cache *fat_inode_cachep; static struct inode *fat_alloc_inode(struct super_block *sb) { @@ -493,7 +493,7 @@ static void fat_destroy_inode(struct inode *inode) kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; diff --git a/fs/fcntl.c b/fs/fcntl.c index c03dc9cb21cb..4740d35e52cd 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -553,7 +553,7 @@ int send_sigurg(struct fown_struct *fown) } static DEFINE_RWLOCK(fasync_lock); -static kmem_cache_t *fasync_cache __read_mostly; +static struct kmem_cache *fasync_cache __read_mostly; /* * fasync_helper() is used by some character device drivers (mainly mice) diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index d2dd0d700077..0b7ae897cb78 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c @@ -46,7 +46,7 @@ extern const struct address_space_operations vxfs_immed_aops; extern struct inode_operations vxfs_immed_symlink_iops; -kmem_cache_t *vxfs_inode_cachep; +struct kmem_cache *vxfs_inode_cachep; #ifdef DIAGNOSTIC diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 8c15139f2756..357764d85ff1 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -19,7 +19,7 @@ MODULE_ALIAS_MISCDEV(FUSE_MINOR); -static kmem_cache_t *fuse_req_cachep; +static struct kmem_cache *fuse_req_cachep; static struct fuse_conn *fuse_get_conn(struct file *file) { diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index e039e2047cce..2bdc652b8b46 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -22,7 +22,7 @@ MODULE_AUTHOR("Miklos Szeredi "); MODULE_DESCRIPTION("Filesystem in Userspace"); MODULE_LICENSE("GPL"); -static kmem_cache_t *fuse_inode_cachep; +static struct kmem_cache *fuse_inode_cachep; struct list_head fuse_conn_list; DEFINE_MUTEX(fuse_mutex); @@ -601,7 +601,7 @@ static struct file_system_type fuse_fs_type = { static decl_subsys(fuse, NULL, NULL); static decl_subsys(connections, NULL, NULL); -static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, +static void fuse_inode_init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) { struct inode * inode = foo; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 9889c1eacec1..7c1a9e22a526 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -25,7 +25,7 @@ #include "util.h" #include "glock.h" -static void gfs2_init_inode_once(void *foo, kmem_cache_t *cachep, unsigned long flags) +static void gfs2_init_inode_once(void *foo, struct kmem_cache *cachep, unsigned long flags) { struct gfs2_inode *ip = foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == @@ -37,7 +37,7 @@ static void gfs2_init_inode_once(void *foo, kmem_cache_t *cachep, unsigned long } } -static void gfs2_init_glock_once(void *foo, kmem_cache_t *cachep, unsigned long flags) +static void gfs2_init_glock_once(void *foo, struct kmem_cache *cachep, unsigned long flags) { struct gfs2_glock *gl = foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 196c604faadc..e5707a9f78c2 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -23,9 +23,9 @@ #include "lm.h" #include "util.h" -kmem_cache_t *gfs2_glock_cachep __read_mostly; -kmem_cache_t *gfs2_inode_cachep __read_mostly; -kmem_cache_t *gfs2_bufdata_cachep __read_mostly; +struct kmem_cache *gfs2_glock_cachep __read_mostly; +struct kmem_cache *gfs2_inode_cachep __read_mostly; +struct kmem_cache *gfs2_bufdata_cachep __read_mostly; void gfs2_assert_i(struct gfs2_sbd *sdp) { diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 76a50899fe9e..7984dcf89ad0 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -146,9 +146,9 @@ int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, gfs2_io_error_bh_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__); -extern kmem_cache_t *gfs2_glock_cachep; -extern kmem_cache_t *gfs2_inode_cachep; -extern kmem_cache_t *gfs2_bufdata_cachep; +extern struct kmem_cache *gfs2_glock_cachep; +extern struct kmem_cache *gfs2_inode_cachep; +extern struct kmem_cache *gfs2_bufdata_cachep; static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt, unsigned int *p) diff --git a/fs/hfs/super.c b/fs/hfs/super.c index ffc6409132c8..a36987966004 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -24,7 +24,7 @@ #include "hfs_fs.h" #include "btree.h" -static kmem_cache_t *hfs_inode_cachep; +static struct kmem_cache *hfs_inode_cachep; MODULE_LICENSE("GPL"); @@ -430,7 +430,7 @@ static struct file_system_type hfs_fs_type = { .fs_flags = FS_REQUIRES_DEV, }; -static void hfs_init_once(void *p, kmem_cache_t *cachep, unsigned long flags) +static void hfs_init_once(void *p, struct kmem_cache *cachep, unsigned long flags) { struct hfs_inode_info *i = p; diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 4a0c70c76c8a..0f513c6bf843 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -434,7 +434,7 @@ MODULE_AUTHOR("Brad Boyer"); MODULE_DESCRIPTION("Extended Macintosh Filesystem"); MODULE_LICENSE("GPL"); -static kmem_cache_t *hfsplus_inode_cachep; +static struct kmem_cache *hfsplus_inode_cachep; static struct inode *hfsplus_alloc_inode(struct super_block *sb) { @@ -467,7 +467,7 @@ static struct file_system_type hfsplus_fs_type = { .fs_flags = FS_REQUIRES_DEV, }; -static void hfsplus_init_once(void *p, kmem_cache_t *cachep, unsigned long flags) +static void hfsplus_init_once(void *p, struct kmem_cache *cachep, unsigned long flags) { struct hfsplus_inode_info *i = p; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 46ceadd6f16a..34d68e211714 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -160,7 +160,7 @@ static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static kmem_cache_t * hpfs_inode_cachep; +static struct kmem_cache * hpfs_inode_cachep; static struct inode *hpfs_alloc_inode(struct super_block *sb) { @@ -177,7 +177,7 @@ static void hpfs_destroy_inode(struct inode *inode) kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 36e52173a54a..0706f5aac6a2 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -513,7 +513,7 @@ static void hugetlbfs_inc_free_inodes(struct hugetlbfs_sb_info *sbinfo) } -static kmem_cache_t *hugetlbfs_inode_cachep; +static struct kmem_cache *hugetlbfs_inode_cachep; static struct inode *hugetlbfs_alloc_inode(struct super_block *sb) { @@ -545,7 +545,7 @@ static const struct address_space_operations hugetlbfs_aops = { }; -static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) +static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) { struct hugetlbfs_inode_info *ei = (struct hugetlbfs_inode_info *)foo; diff --git a/fs/inode.c b/fs/inode.c index dd15984d51a8..699aa4f7aa74 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -97,7 +97,7 @@ static DEFINE_MUTEX(iprune_mutex); */ struct inodes_stat_t inodes_stat; -static kmem_cache_t * inode_cachep __read_mostly; +static struct kmem_cache * inode_cachep __read_mostly; static struct inode *alloc_inode(struct super_block *sb) { @@ -209,7 +209,7 @@ void inode_init_once(struct inode *inode) EXPORT_SYMBOL(inode_init_once); -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct inode * inode = (struct inode *) foo; diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 017cb0f134d6..e1956e6f116c 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -34,8 +34,8 @@ #include -static kmem_cache_t *watch_cachep __read_mostly; -static kmem_cache_t *event_cachep __read_mostly; +static struct kmem_cache *watch_cachep __read_mostly; +static struct kmem_cache *event_cachep __read_mostly; static struct vfsmount *inotify_mnt __read_mostly; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 4b6381cd2cf4..ea55b6c469ec 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -57,7 +57,7 @@ static void isofs_put_super(struct super_block *sb) static void isofs_read_inode(struct inode *); static int isofs_statfs (struct dentry *, struct kstatfs *); -static kmem_cache_t *isofs_inode_cachep; +static struct kmem_cache *isofs_inode_cachep; static struct inode *isofs_alloc_inode(struct super_block *sb) { @@ -73,7 +73,7 @@ static void isofs_destroy_inode(struct inode *inode) kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); } -static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags) { struct iso_inode_info *ei = foo; diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index b85c686b60db..a8774bed20b6 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1630,7 +1630,7 @@ void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry) #define JBD_MAX_SLABS 5 #define JBD_SLAB_INDEX(size) (size >> 11) -static kmem_cache_t *jbd_slab[JBD_MAX_SLABS]; +static struct kmem_cache *jbd_slab[JBD_MAX_SLABS]; static const char *jbd_slab_names[JBD_MAX_SLABS] = { "jbd_1k", "jbd_2k", "jbd_4k", NULL, "jbd_8k" }; @@ -1693,7 +1693,7 @@ void jbd_slab_free(void *ptr, size_t size) /* * Journal_head storage management */ -static kmem_cache_t *journal_head_cache; +static struct kmem_cache *journal_head_cache; #ifdef CONFIG_JBD_DEBUG static atomic_t nr_journal_heads = ATOMIC_INIT(0); #endif @@ -1996,7 +1996,7 @@ static void __exit remove_jbd_proc_entry(void) #endif -kmem_cache_t *jbd_handle_cache; +struct kmem_cache *jbd_handle_cache; static int __init journal_init_handle_cache(void) { diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index c532429d8d9b..d204ab394f36 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -70,8 +70,8 @@ #include #endif -static kmem_cache_t *revoke_record_cache; -static kmem_cache_t *revoke_table_cache; +static struct kmem_cache *revoke_record_cache; +static struct kmem_cache *revoke_table_cache; /* Each revoke record represents one single revoked block. During journal replay, this involves recording the transaction ID of the diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index c60f378b0f76..50356019ae30 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1641,7 +1641,7 @@ void * __jbd2_kmalloc (const char *where, size_t size, gfp_t flags, int retry) #define JBD_MAX_SLABS 5 #define JBD_SLAB_INDEX(size) (size >> 11) -static kmem_cache_t *jbd_slab[JBD_MAX_SLABS]; +static struct kmem_cache *jbd_slab[JBD_MAX_SLABS]; static const char *jbd_slab_names[JBD_MAX_SLABS] = { "jbd2_1k", "jbd2_2k", "jbd2_4k", NULL, "jbd2_8k" }; @@ -1704,7 +1704,7 @@ void jbd2_slab_free(void *ptr, size_t size) /* * Journal_head storage management */ -static kmem_cache_t *jbd2_journal_head_cache; +static struct kmem_cache *jbd2_journal_head_cache; #ifdef CONFIG_JBD_DEBUG static atomic_t nr_journal_heads = ATOMIC_INIT(0); #endif @@ -2007,7 +2007,7 @@ static void __exit jbd2_remove_jbd_proc_entry(void) #endif -kmem_cache_t *jbd2_handle_cache; +struct kmem_cache *jbd2_handle_cache; static int __init journal_init_handle_cache(void) { diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 380d19917f37..f506646ad0ff 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -70,8 +70,8 @@ #include #endif -static kmem_cache_t *jbd2_revoke_record_cache; -static kmem_cache_t *jbd2_revoke_table_cache; +static struct kmem_cache *jbd2_revoke_record_cache; +static struct kmem_cache *jbd2_revoke_table_cache; /* Each revoke record represents one single revoked block. During journal replay, this involves recording the transaction ID of the diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 3f7899ea4cba..9f15bce92022 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -61,8 +61,8 @@ static const struct file_operations jffs_dir_operations; static struct inode_operations jffs_dir_inode_operations; static const struct address_space_operations jffs_address_operations; -kmem_cache_t *node_cache = NULL; -kmem_cache_t *fm_cache = NULL; +struct kmem_cache *node_cache = NULL; +struct kmem_cache *fm_cache = NULL; /* Called by the VFS at mount time to initialize the whole file system. */ static int jffs_fill_super(struct super_block *sb, void *data, int silent) diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c index 29b68d939bd9..077258b2103e 100644 --- a/fs/jffs/jffs_fm.c +++ b/fs/jffs/jffs_fm.c @@ -29,8 +29,8 @@ static int jffs_mark_obsolete(struct jffs_fmcontrol *fmc, __u32 fm_offset); static struct jffs_fm *jffs_alloc_fm(void); static void jffs_free_fm(struct jffs_fm *n); -extern kmem_cache_t *fm_cache; -extern kmem_cache_t *node_cache; +extern struct kmem_cache *fm_cache; +extern struct kmem_cache *node_cache; #if CONFIG_JFFS_FS_VERBOSE > 0 void diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 33f291005012..83f9881ec4cc 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -19,16 +19,16 @@ /* These are initialised to NULL in the kernel startup code. If you're porting to other operating systems, beware */ -static kmem_cache_t *full_dnode_slab; -static kmem_cache_t *raw_dirent_slab; -static kmem_cache_t *raw_inode_slab; -static kmem_cache_t *tmp_dnode_info_slab; -static kmem_cache_t *raw_node_ref_slab; -static kmem_cache_t *node_frag_slab; -static kmem_cache_t *inode_cache_slab; +static struct kmem_cache *full_dnode_slab; +static struct kmem_cache *raw_dirent_slab; +static struct kmem_cache *raw_inode_slab; +static struct kmem_cache *tmp_dnode_info_slab; +static struct kmem_cache *raw_node_ref_slab; +static struct kmem_cache *node_frag_slab; +static struct kmem_cache *inode_cache_slab; #ifdef CONFIG_JFFS2_FS_XATTR -static kmem_cache_t *xattr_datum_cache; -static kmem_cache_t *xattr_ref_cache; +static struct kmem_cache *xattr_datum_cache; +static struct kmem_cache *xattr_ref_cache; #endif int __init jffs2_create_slab_caches(void) diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 77be534ce422..7deb78254021 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -28,7 +28,7 @@ static void jffs2_put_super(struct super_block *); -static kmem_cache_t *jffs2_inode_cachep; +static struct kmem_cache *jffs2_inode_cachep; static struct inode *jffs2_alloc_inode(struct super_block *sb) { @@ -44,7 +44,7 @@ static void jffs2_destroy_inode(struct inode *inode) kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); } -static void jffs2_i_init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void jffs2_i_init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 0cccd1c39d75..b1a1c7296014 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -74,7 +74,7 @@ static inline void lock_metapage(struct metapage *mp) } #define METAPOOL_MIN_PAGES 32 -static kmem_cache_t *metapage_cache; +static struct kmem_cache *metapage_cache; static mempool_t *metapage_mempool; #define MPS_PER_PAGE (PAGE_CACHE_SIZE >> L2PSIZE) @@ -180,7 +180,7 @@ static inline void remove_metapage(struct page *page, struct metapage *mp) #endif -static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) +static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) { struct metapage *mp = (struct metapage *)foo; diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 9c1c6e0e633d..ca3e19128532 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -44,7 +44,7 @@ MODULE_DESCRIPTION("The Journaled Filesystem (JFS)"); MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM"); MODULE_LICENSE("GPL"); -static kmem_cache_t * jfs_inode_cachep; +static struct kmem_cache * jfs_inode_cachep; static struct super_operations jfs_super_operations; static struct export_operations jfs_export_operations; @@ -748,7 +748,7 @@ static struct file_system_type jfs_fs_type = { .fs_flags = FS_REQUIRES_DEV, }; -static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags) { struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo; diff --git a/fs/locks.c b/fs/locks.c index a7b97d50c1e0..1cb0c57fedbd 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -142,7 +142,7 @@ int lease_break_time = 45; static LIST_HEAD(file_lock_list); static LIST_HEAD(blocked_list); -static kmem_cache_t *filelock_cache __read_mostly; +static struct kmem_cache *filelock_cache __read_mostly; /* Allocate an empty lock structure. */ static struct file_lock *locks_alloc_lock(void) @@ -199,7 +199,7 @@ EXPORT_SYMBOL(locks_init_lock); * Initialises the fields of the file lock which are invariant for * free file_locks. */ -static void init_once(void *foo, kmem_cache_t *cache, unsigned long flags) +static void init_once(void *foo, struct kmem_cache *cache, unsigned long flags) { struct file_lock *lock = (struct file_lock *) foo; diff --git a/fs/mbcache.c b/fs/mbcache.c index 0ff71256e65b..deeb9dc062d9 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -85,7 +85,7 @@ struct mb_cache { #ifndef MB_CACHE_INDEXES_COUNT int c_indexes_count; #endif - kmem_cache_t *c_entry_cache; + struct kmem_cache *c_entry_cache; struct list_head *c_block_hash; struct list_head *c_indexes_hash[0]; }; diff --git a/fs/minix/inode.c b/fs/minix/inode.c index ce532c2deda8..629e09b38c5c 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -51,7 +51,7 @@ static void minix_put_super(struct super_block *sb) return; } -static kmem_cache_t * minix_inode_cachep; +static struct kmem_cache * minix_inode_cachep; static struct inode *minix_alloc_inode(struct super_block *sb) { @@ -67,7 +67,7 @@ static void minix_destroy_inode(struct inode *inode) kmem_cache_free(minix_inode_cachep, minix_i(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct minix_inode_info *ei = (struct minix_inode_info *) foo; diff --git a/fs/namespace.c b/fs/namespace.c index 55442a6cf221..b00ac84ebbdd 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -36,7 +36,7 @@ static int event; static struct list_head *mount_hashtable __read_mostly; static int hash_mask __read_mostly, hash_bits __read_mostly; -static kmem_cache_t *mnt_cache __read_mostly; +static struct kmem_cache *mnt_cache __read_mostly; static struct rw_semaphore namespace_sem; /* /sys/fs */ diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index ed84d899220c..fae53243bb92 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -40,7 +40,7 @@ static void ncp_delete_inode(struct inode *); static void ncp_put_super(struct super_block *); static int ncp_statfs(struct dentry *, struct kstatfs *); -static kmem_cache_t * ncp_inode_cachep; +static struct kmem_cache * ncp_inode_cachep; static struct inode *ncp_alloc_inode(struct super_block *sb) { @@ -56,7 +56,7 @@ static void ncp_destroy_inode(struct inode *inode) kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 769fd0a0c772..2f488e1d9b6c 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -58,7 +58,7 @@ #define NFSDBG_FACILITY NFSDBG_VFS -static kmem_cache_t *nfs_direct_cachep; +static struct kmem_cache *nfs_direct_cachep; /* * This represents a set of asynchronous requests that we're waiting on diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6b53aae4ed2c..15afa460e629 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -55,7 +55,7 @@ static int nfs_update_inode(struct inode *, struct nfs_fattr *); static void nfs_zap_acl_cache(struct inode *); -static kmem_cache_t * nfs_inode_cachep; +static struct kmem_cache * nfs_inode_cachep; static inline unsigned long nfs_fattr_to_ino_t(struct nfs_fattr *fattr) @@ -1111,7 +1111,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi) #endif } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct nfs_inode *nfsi = (struct nfs_inode *) foo; diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index a1561a820abe..3fbfc2f03307 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -20,7 +20,7 @@ #define NFS_PARANOIA 1 -static kmem_cache_t *nfs_page_cachep; +static struct kmem_cache *nfs_page_cachep; static inline struct nfs_page * nfs_page_alloc(void) diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 56f66f0ccb6a..244a8c45b68e 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -38,7 +38,7 @@ static int nfs_pagein_one(struct list_head *, struct inode *); static const struct rpc_call_ops nfs_read_partial_ops; static const struct rpc_call_ops nfs_read_full_ops; -static kmem_cache_t *nfs_rdata_cachep; +static struct kmem_cache *nfs_rdata_cachep; static mempool_t *nfs_rdata_mempool; #define MIN_POOL_READ (32) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index f7dd0d005957..41b07288f99e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -85,7 +85,7 @@ static const struct rpc_call_ops nfs_write_partial_ops; static const struct rpc_call_ops nfs_write_full_ops; static const struct rpc_call_ops nfs_commit_ops; -static kmem_cache_t *nfs_wdata_cachep; +static struct kmem_cache *nfs_wdata_cachep; static mempool_t *nfs_wdata_mempool; static mempool_t *nfs_commit_mempool; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e431e93ab503..640c92b2a9f7 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -84,10 +84,10 @@ static void nfs4_set_recdir(char *recdir); */ static DEFINE_MUTEX(client_mutex); -static kmem_cache_t *stateowner_slab = NULL; -static kmem_cache_t *file_slab = NULL; -static kmem_cache_t *stateid_slab = NULL; -static kmem_cache_t *deleg_slab = NULL; +static struct kmem_cache *stateowner_slab = NULL; +static struct kmem_cache *file_slab = NULL; +static struct kmem_cache *stateid_slab = NULL; +static struct kmem_cache *deleg_slab = NULL; void nfs4_lock_state(void) @@ -1003,7 +1003,7 @@ alloc_init_file(struct inode *ino) } static void -nfsd4_free_slab(kmem_cache_t **slab) +nfsd4_free_slab(struct kmem_cache **slab) { if (*slab == NULL) return; diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index 01f91501f70a..941acf14e61f 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c @@ -66,7 +66,7 @@ static struct file_operations dlmfs_file_operations; static struct inode_operations dlmfs_dir_inode_operations; static struct inode_operations dlmfs_root_inode_operations; static struct inode_operations dlmfs_file_inode_operations; -static kmem_cache_t *dlmfs_inode_cache; +static struct kmem_cache *dlmfs_inode_cache; struct workqueue_struct *user_dlm_worker; @@ -257,7 +257,7 @@ static ssize_t dlmfs_file_write(struct file *filp, } static void dlmfs_init_once(void *foo, - kmem_cache_t *cachep, + struct kmem_cache *cachep, unsigned long flags) { struct dlmfs_inode_private *ip = diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index f784177b6241..856012b4fa49 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -221,7 +221,7 @@ EXPORT_SYMBOL_GPL(dlm_dump_all_mles); #endif /* 0 */ -static kmem_cache_t *dlm_mle_cache = NULL; +static struct kmem_cache *dlm_mle_cache = NULL; static void dlm_mle_release(struct kref *kref); diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index fcd4475d1f89..80ac69f11d9f 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c @@ -61,7 +61,7 @@ struct ocfs2_em_insert_context { struct ocfs2_extent_map_entry *right_ent; }; -static kmem_cache_t *ocfs2_em_ent_cachep = NULL; +static struct kmem_cache *ocfs2_em_ent_cachep = NULL; static struct ocfs2_extent_map_entry * diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h index 46a378fbc40b..1a7dd2945b34 100644 --- a/fs/ocfs2/inode.h +++ b/fs/ocfs2/inode.h @@ -106,7 +106,7 @@ static inline struct ocfs2_inode_info *OCFS2_I(struct inode *inode) #define INODE_JOURNAL(i) (OCFS2_I(i)->ip_flags & OCFS2_INODE_JOURNAL) #define SET_INODE_JOURNAL(i) (OCFS2_I(i)->ip_flags |= OCFS2_INODE_JOURNAL) -extern kmem_cache_t *ocfs2_inode_cache; +extern struct kmem_cache *ocfs2_inode_cache; extern const struct address_space_operations ocfs2_aops; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 7574d26ee0ff..0524f8a04ad6 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -68,7 +68,7 @@ #include "buffer_head_io.h" -static kmem_cache_t *ocfs2_inode_cachep = NULL; +static struct kmem_cache *ocfs2_inode_cachep = NULL; /* OCFS2 needs to schedule several differnt types of work which * require cluster locking, disk I/O, recovery waits, etc. Since these @@ -914,7 +914,7 @@ bail: } static void ocfs2_inode_init_once(void *data, - kmem_cache_t *cachep, + struct kmem_cache *cachep, unsigned long flags) { struct ocfs2_inode_info *oi = data; diff --git a/fs/ocfs2/uptodate.c b/fs/ocfs2/uptodate.c index 9707ed7a3206..39814b900fc0 100644 --- a/fs/ocfs2/uptodate.c +++ b/fs/ocfs2/uptodate.c @@ -69,7 +69,7 @@ struct ocfs2_meta_cache_item { sector_t c_block; }; -static kmem_cache_t *ocfs2_uptodate_cachep = NULL; +static struct kmem_cache *ocfs2_uptodate_cachep = NULL; void ocfs2_metadata_cache_init(struct inode *inode) { diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index 911d1bcfc567..26f44e0074ec 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -330,7 +330,7 @@ out: return 0; } -static kmem_cache_t *op_inode_cachep; +static struct kmem_cache *op_inode_cachep; static struct inode *openprom_alloc_inode(struct super_block *sb) { @@ -415,7 +415,7 @@ static struct file_system_type openprom_fs_type = { .kill_sb = kill_anon_super, }; -static void op_inode_init_once(void *data, kmem_cache_t * cachep, unsigned long flags) +static void op_inode_init_once(void *data, struct kmem_cache * cachep, unsigned long flags) { struct op_inode_info *oi = (struct op_inode_info *) data; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index b24cdb2f17c1..e26945ba685b 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -81,7 +81,7 @@ static void proc_read_inode(struct inode * inode) inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; } -static kmem_cache_t * proc_inode_cachep; +static struct kmem_cache * proc_inode_cachep; static struct inode *proc_alloc_inode(struct super_block *sb) { @@ -105,7 +105,7 @@ static void proc_destroy_inode(struct inode *inode) kmem_cache_free(proc_inode_cachep, PROC_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct proc_inode *ei = (struct proc_inode *) foo; diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 5b943eb11d76..c047dc654d5c 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -515,7 +515,7 @@ static void qnx4_read_inode(struct inode *inode) brelse(bh); } -static kmem_cache_t *qnx4_inode_cachep; +static struct kmem_cache *qnx4_inode_cachep; static struct inode *qnx4_alloc_inode(struct super_block *sb) { @@ -531,7 +531,7 @@ static void qnx4_destroy_inode(struct inode *inode) kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode)); } -static void init_once(void *foo, kmem_cache_t * cachep, +static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags) { struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 32332516d656..745bc714ba91 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -490,7 +490,7 @@ static void reiserfs_put_super(struct super_block *s) return; } -static kmem_cache_t *reiserfs_inode_cachep; +static struct kmem_cache *reiserfs_inode_cachep; static struct inode *reiserfs_alloc_inode(struct super_block *sb) { @@ -507,7 +507,7 @@ static void reiserfs_destroy_inode(struct inode *inode) kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode)); } -static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags) { struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo; diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index d1b455f9b669..c5af088d4a4c 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -550,7 +550,7 @@ romfs_read_inode(struct inode *i) } } -static kmem_cache_t * romfs_inode_cachep; +static struct kmem_cache * romfs_inode_cachep; static struct inode *romfs_alloc_inode(struct super_block *sb) { @@ -566,7 +566,7 @@ static void romfs_destroy_inode(struct inode *inode) kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct romfs_inode_info *ei = (struct romfs_inode_info *) foo; diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 221617103484..4af4cd729a5a 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -50,7 +50,7 @@ static void smb_put_super(struct super_block *); static int smb_statfs(struct dentry *, struct kstatfs *); static int smb_show_options(struct seq_file *, struct vfsmount *); -static kmem_cache_t *smb_inode_cachep; +static struct kmem_cache *smb_inode_cachep; static struct inode *smb_alloc_inode(struct super_block *sb) { @@ -66,7 +66,7 @@ static void smb_destroy_inode(struct inode *inode) kmem_cache_free(smb_inode_cachep, SMB_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct smb_inode_info *ei = (struct smb_inode_info *) foo; unsigned long flagmask = SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR; diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c index 3eb1402191b9..a4bcae8a9aff 100644 --- a/fs/smbfs/request.c +++ b/fs/smbfs/request.c @@ -25,7 +25,7 @@ #define ROUND_UP(x) (((x)+3) & ~3) /* cache for request structures */ -static kmem_cache_t *req_cachep; +static struct kmem_cache *req_cachep; static int smb_request_send_req(struct smb_request *req); diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 20551a1b8a56..e503f858fba8 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -16,7 +16,7 @@ struct vfsmount *sysfs_mount; struct super_block * sysfs_sb = NULL; -kmem_cache_t *sysfs_dir_cachep; +struct kmem_cache *sysfs_dir_cachep; static struct super_operations sysfs_ops = { .statfs = simple_statfs, diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 6f3d6bd52887..bd7cec295dab 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,6 +1,6 @@ extern struct vfsmount * sysfs_mount; -extern kmem_cache_t *sysfs_dir_cachep; +extern struct kmem_cache *sysfs_dir_cachep; extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index a6ca12b747cf..ead9864567e3 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -301,7 +301,7 @@ static void sysv_delete_inode(struct inode *inode) unlock_kernel(); } -static kmem_cache_t *sysv_inode_cachep; +static struct kmem_cache *sysv_inode_cachep; static struct inode *sysv_alloc_inode(struct super_block *sb) { @@ -318,7 +318,7 @@ static void sysv_destroy_inode(struct inode *inode) kmem_cache_free(sysv_inode_cachep, SYSV_I(inode)); } -static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags) +static void init_once(void *p, struct kmem_cache *cachep, unsigned long flags) { struct sysv_inode_info *si = (struct sysv_inode_info *)p; diff --git a/fs/udf/super.c b/fs/udf/super.c index e50f24221dea..397f54aaf667 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -107,7 +107,7 @@ static struct file_system_type udf_fstype = { .fs_flags = FS_REQUIRES_DEV, }; -static kmem_cache_t * udf_inode_cachep; +static struct kmem_cache * udf_inode_cachep; static struct inode *udf_alloc_inode(struct super_block *sb) { @@ -130,7 +130,7 @@ static void udf_destroy_inode(struct inode *inode) kmem_cache_free(udf_inode_cachep, UDF_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct udf_inode_info *ei = (struct udf_inode_info *) foo; diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 85a88c0c5e68..0b18d2cc2efa 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1204,7 +1204,7 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static kmem_cache_t * ufs_inode_cachep; +static struct kmem_cache * ufs_inode_cachep; static struct inode *ufs_alloc_inode(struct super_block *sb) { @@ -1221,7 +1221,7 @@ static void ufs_destroy_inode(struct inode *inode) kmem_cache_free(ufs_inode_cachep, UFS_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct ufs_inode_info *ei = (struct ufs_inode_info *) foo; diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 47faf27913a5..7f1e92930b62 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -64,7 +64,7 @@ /* Host-dependent types and defines */ #define ACPI_MACHINE_WIDTH BITS_PER_LONG -#define acpi_cache_t kmem_cache_t +#define acpi_cache_t struct kmem_cache #define acpi_spinlock spinlock_t * #define ACPI_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol); #define strtoul simple_strtoul diff --git a/include/asm-arm26/pgalloc.h b/include/asm-arm26/pgalloc.h index 6437167b1ffe..7725af3ddb4d 100644 --- a/include/asm-arm26/pgalloc.h +++ b/include/asm-arm26/pgalloc.h @@ -15,7 +15,7 @@ #include #include -extern kmem_cache_t *pte_cache; +extern struct kmem_cache *pte_cache; static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr){ return kmem_cache_alloc(pte_cache, GFP_KERNEL); diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 7d398f493dde..bfee7ddfff53 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -34,14 +34,14 @@ struct vm_area_struct; #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) extern unsigned long empty_zero_page[1024]; extern pgd_t swapper_pg_dir[1024]; -extern kmem_cache_t *pgd_cache; -extern kmem_cache_t *pmd_cache; +extern struct kmem_cache *pgd_cache; +extern struct kmem_cache *pmd_cache; extern spinlock_t pgd_lock; extern struct page *pgd_list; -void pmd_ctor(void *, kmem_cache_t *, unsigned long); -void pgd_ctor(void *, kmem_cache_t *, unsigned long); -void pgd_dtor(void *, kmem_cache_t *, unsigned long); +void pmd_ctor(void *, struct kmem_cache *, unsigned long); +void pgd_ctor(void *, struct kmem_cache *, unsigned long); +void pgd_dtor(void *, struct kmem_cache *, unsigned long); void pgtable_cache_init(void); void paging_init(void); diff --git a/include/asm-powerpc/pgalloc.h b/include/asm-powerpc/pgalloc.h index ae63db7b3e7d..b0830db68f8a 100644 --- a/include/asm-powerpc/pgalloc.h +++ b/include/asm-powerpc/pgalloc.h @@ -11,7 +11,7 @@ #include #include -extern kmem_cache_t *pgtable_cache[]; +extern struct kmem_cache *pgtable_cache[]; #ifdef CONFIG_PPC_64K_PAGES #define PTE_CACHE_NUM 0 diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h index 010f9cd0a672..5891ff7ba760 100644 --- a/include/asm-sparc64/pgalloc.h +++ b/include/asm-sparc64/pgalloc.h @@ -13,7 +13,7 @@ #include /* Page table allocation/freeing. */ -extern kmem_cache_t *pgtable_cache; +extern struct kmem_cache *pgtable_cache; static inline pgd_t *pgd_alloc(struct mm_struct *mm) { diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h index 561e2a77805c..55d1ca5e60f5 100644 --- a/include/linux/delayacct.h +++ b/include/linux/delayacct.h @@ -30,7 +30,7 @@ #ifdef CONFIG_TASK_DELAY_ACCT extern int delayacct_on; /* Delay accounting turned on/off */ -extern kmem_cache_t *delayacct_cache; +extern struct kmem_cache *delayacct_cache; extern void delayacct_init(void); extern void __delayacct_tsk_init(struct task_struct *); extern void __delayacct_tsk_exit(struct task_struct *); diff --git a/include/linux/i2o.h b/include/linux/i2o.h index 1fb02e17f6f6..2514f4e286b7 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -490,7 +490,7 @@ struct i2o_dma { */ struct i2o_pool { char *name; - kmem_cache_t *slab; + struct kmem_cache *slab; mempool_t *mempool; }; diff --git a/include/linux/jbd.h b/include/linux/jbd.h index fe89444b1c6f..dacd566c9f6c 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -949,7 +949,7 @@ void journal_put_journal_head(struct journal_head *jh); /* * handle management */ -extern kmem_cache_t *jbd_handle_cache; +extern struct kmem_cache *jbd_handle_cache; static inline handle_t *jbd_alloc_handle(gfp_t gfp_flags) { diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index ddb128795781..98a0ae52660f 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -958,7 +958,7 @@ void jbd2_journal_put_journal_head(struct journal_head *jh); /* * handle management */ -extern kmem_cache_t *jbd2_handle_cache; +extern struct kmem_cache *jbd2_handle_cache; static inline handle_t *jbd_alloc_handle(gfp_t gfp_flags) { diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h index f13299a15591..03636d7918fe 100644 --- a/include/linux/raid/raid5.h +++ b/include/linux/raid/raid5.h @@ -235,7 +235,7 @@ struct raid5_private_data { */ int active_name; char cache_name[2][20]; - kmem_cache_t *slab_cache; /* for allocating stripes */ + struct kmem_cache *slab_cache; /* for allocating stripes */ int seq_flush, seq_write; int quiesce; diff --git a/include/linux/rmap.h b/include/linux/rmap.h index 61c2ab634b00..36f850373d2c 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -30,7 +30,7 @@ struct anon_vma { #ifdef CONFIG_MMU -extern kmem_cache_t *anon_vma_cachep; +extern struct kmem_cache *anon_vma_cachep; static inline struct anon_vma *anon_vma_alloc(void) { diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 1d649f3eb006..4ff3940210d8 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -345,7 +345,7 @@ static inline struct sk_buff *alloc_skb_fclone(unsigned int size, return __alloc_skb(size, priority, 1, -1); } -extern struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp, +extern struct sk_buff *alloc_skb_from_cache(struct kmem_cache *cp, unsigned int size, gfp_t priority); extern void kfree_skbmem(struct sk_buff *skb); diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h index f81a5af8a4f8..ce8a912e5426 100644 --- a/include/linux/taskstats_kern.h +++ b/include/linux/taskstats_kern.h @@ -12,7 +12,7 @@ #include #ifdef CONFIG_TASKSTATS -extern kmem_cache_t *taskstats_cache; +extern struct kmem_cache *taskstats_cache; extern struct mutex taskstats_exit_mutex; static inline void taskstats_exit_free(struct taskstats *tidstats) diff --git a/include/net/dst.h b/include/net/dst.h index e156e38e4ac3..62b7e7598e9a 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -98,7 +98,7 @@ struct dst_ops int entry_size; atomic_t entries; - kmem_cache_t *kmem_cachep; + struct kmem_cache *kmem_cachep; }; #ifdef __KERNEL__ diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index a9eb2eaf094e..34cc76e3ddb4 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -125,7 +125,7 @@ struct inet_hashinfo { rwlock_t lhash_lock ____cacheline_aligned; atomic_t lhash_users; wait_queue_head_t lhash_wait; - kmem_cache_t *bind_bucket_cachep; + struct kmem_cache *bind_bucket_cachep; }; static inline struct inet_ehash_bucket *inet_ehash_bucket( @@ -136,10 +136,10 @@ static inline struct inet_ehash_bucket *inet_ehash_bucket( } extern struct inet_bind_bucket * - inet_bind_bucket_create(kmem_cache_t *cachep, + inet_bind_bucket_create(struct kmem_cache *cachep, struct inet_bind_hashbucket *head, const unsigned short snum); -extern void inet_bind_bucket_destroy(kmem_cache_t *cachep, +extern void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket *tb); static inline int inet_bhashfn(const __u16 lport, const int bhash_size) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index c8aacbd2e333..23967031ddb7 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -160,7 +160,7 @@ struct neigh_table atomic_t entries; rwlock_t lock; unsigned long last_rand; - kmem_cache_t *kmem_cachep; + struct kmem_cache *kmem_cachep; struct neigh_statistics *stats; struct neighbour **hash_buckets; unsigned int hash_mask; diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index cef3136e22a3..41bcc9eb4206 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -7,7 +7,7 @@ #include extern struct list_head nf_conntrack_expect_list; -extern kmem_cache_t *nf_conntrack_expect_cachep; +extern struct kmem_cache *nf_conntrack_expect_cachep; extern struct file_operations exp_file_ops; struct nf_conntrack_expect diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 426f0fe774ef..7aed02ce2b65 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -29,7 +29,7 @@ struct proto; struct request_sock_ops { int family; int obj_size; - kmem_cache_t *slab; + struct kmem_cache *slab; int (*rtx_syn_ack)(struct sock *sk, struct request_sock *req, struct dst_entry *dst); diff --git a/include/net/sock.h b/include/net/sock.h index fe3a33fad03f..730899ce5162 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -571,7 +571,7 @@ struct proto { int *sysctl_rmem; int max_header; - kmem_cache_t *slab; + struct kmem_cache *slab; unsigned int obj_size; atomic_t *orphan_count; diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h index d7a306ea560d..1e1ee3253fd8 100644 --- a/include/net/timewait_sock.h +++ b/include/net/timewait_sock.h @@ -15,7 +15,7 @@ #include struct timewait_sock_ops { - kmem_cache_t *twsk_slab; + struct kmem_cache *twsk_slab; unsigned int twsk_obj_size; int (*twsk_unique)(struct sock *sk, struct sock *sktw, void *twp); diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 9233ed5de664..0c775fceb675 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -557,7 +557,7 @@ struct sas_task { static inline struct sas_task *sas_alloc_task(gfp_t flags) { - extern kmem_cache_t *sas_task_cache; + extern struct kmem_cache *sas_task_cache; struct sas_task *task = kmem_cache_alloc(sas_task_cache, flags); if (task) { @@ -575,7 +575,7 @@ static inline struct sas_task *sas_alloc_task(gfp_t flags) static inline void sas_free_task(struct sas_task *task) { if (task) { - extern kmem_cache_t *sas_task_cache; + extern struct kmem_cache *sas_task_cache; BUG_ON(!list_empty(&task->list)); kmem_cache_free(sas_task_cache, task); } diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 813bb941342b..3acc1661e517 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -90,7 +90,7 @@ static struct super_operations mqueue_super_ops; static void remove_notification(struct mqueue_inode_info *info); static spinlock_t mq_lock; -static kmem_cache_t *mqueue_inode_cachep; +static struct kmem_cache *mqueue_inode_cachep; static struct vfsmount *mqueue_mnt; static unsigned int queues_count; @@ -211,7 +211,7 @@ static int mqueue_get_sb(struct file_system_type *fs_type, return get_sb_single(fs_type, flags, data, mqueue_fill_super, mnt); } -static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags) { struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo; diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 70e9ec603082..766d5912b26a 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -20,7 +20,7 @@ #include int delayacct_on __read_mostly = 1; /* Delay accounting turned on/off */ -kmem_cache_t *delayacct_cache; +struct kmem_cache *delayacct_cache; static int __init delayacct_setup_disable(char *str) { diff --git a/kernel/fork.c b/kernel/fork.c index 711aa5f10da7..2cf74edd3295 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -82,26 +82,26 @@ int nr_processes(void) #ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR # define alloc_task_struct() kmem_cache_alloc(task_struct_cachep, GFP_KERNEL) # define free_task_struct(tsk) kmem_cache_free(task_struct_cachep, (tsk)) -static kmem_cache_t *task_struct_cachep; +static struct kmem_cache *task_struct_cachep; #endif /* SLAB cache for signal_struct structures (tsk->signal) */ -static kmem_cache_t *signal_cachep; +static struct kmem_cache *signal_cachep; /* SLAB cache for sighand_struct structures (tsk->sighand) */ -kmem_cache_t *sighand_cachep; +struct kmem_cache *sighand_cachep; /* SLAB cache for files_struct structures (tsk->files) */ -kmem_cache_t *files_cachep; +struct kmem_cache *files_cachep; /* SLAB cache for fs_struct structures (tsk->fs) */ -kmem_cache_t *fs_cachep; +struct kmem_cache *fs_cachep; /* SLAB cache for vm_area_struct structures */ -kmem_cache_t *vm_area_cachep; +struct kmem_cache *vm_area_cachep; /* SLAB cache for mm_struct structures (tsk->mm) */ -static kmem_cache_t *mm_cachep; +static struct kmem_cache *mm_cachep; void free_task(struct task_struct *tsk) { @@ -1421,7 +1421,7 @@ long do_fork(unsigned long clone_flags, #define ARCH_MIN_MMSTRUCT_ALIGN 0 #endif -static void sighand_ctor(void *data, kmem_cache_t *cachep, unsigned long flags) +static void sighand_ctor(void *data, struct kmem_cache *cachep, unsigned long flags) { struct sighand_struct *sighand = data; diff --git a/kernel/pid.c b/kernel/pid.c index b914392085f9..a48879b0b921 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -31,7 +31,7 @@ #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) static struct hlist_head *pid_hash; static int pidhash_shift; -static kmem_cache_t *pid_cachep; +static struct kmem_cache *pid_cachep; int pid_max = PID_MAX_DEFAULT; diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index 9cbb5d1be06f..5fe87de10ff0 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c @@ -70,7 +70,7 @@ /* * Lets keep our timers in a slab cache :-) */ -static kmem_cache_t *posix_timers_cache; +static struct kmem_cache *posix_timers_cache; static struct idr posix_timers_id; static DEFINE_SPINLOCK(idr_lock); diff --git a/kernel/signal.c b/kernel/signal.c index df18c167a2a7..8e19d2785486 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -33,7 +33,7 @@ * SLAB caches for signal bits. */ -static kmem_cache_t *sigqueue_cachep; +static struct kmem_cache *sigqueue_cachep; /* * In POSIX a signal is sent either to a specific thread (Linux task) diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 1b2b326cf703..f5f92014ae98 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -34,7 +34,7 @@ static DEFINE_PER_CPU(__u32, taskstats_seqnum) = { 0 }; static int family_registered; -kmem_cache_t *taskstats_cache; +struct kmem_cache *taskstats_cache; static struct genl_family family = { .id = GENL_ID_GENERATE, diff --git a/kernel/user.c b/kernel/user.c index c1f93c164c93..4869563080e9 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -26,7 +26,7 @@ #define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK) #define uidhashentry(uid) (uidhash_table + __uidhashfn((uid))) -static kmem_cache_t *uid_cachep; +static struct kmem_cache *uid_cachep; static struct list_head uidhash_table[UIDHASH_SZ]; /* diff --git a/lib/idr.c b/lib/idr.c index 16d2143fea48..71853531d3b0 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -33,7 +33,7 @@ #include #include -static kmem_cache_t *idr_layer_cache; +static struct kmem_cache *idr_layer_cache; static struct idr_layer *alloc_layer(struct idr *idp) { @@ -445,7 +445,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id) } EXPORT_SYMBOL(idr_replace); -static void idr_cache_ctor(void * idr_layer, kmem_cache_t *idr_layer_cache, +static void idr_cache_ctor(void * idr_layer, struct kmem_cache *idr_layer_cache, unsigned long flags) { memset(idr_layer, 0, sizeof(struct idr_layer)); diff --git a/lib/radix-tree.c b/lib/radix-tree.c index aa9bfd0bdbd1..9eb25955019f 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -63,7 +63,7 @@ static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH] __read_mostly; /* * Radix tree node cache. */ -static kmem_cache_t *radix_tree_node_cachep; +static struct kmem_cache *radix_tree_node_cachep; /* * Per-cpu pool of preloaded nodes @@ -846,7 +846,7 @@ int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag) EXPORT_SYMBOL(radix_tree_tagged); static void -radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags) +radix_tree_node_ctor(void *node, struct kmem_cache *cachep, unsigned long flags) { memset(node, 0, sizeof(struct radix_tree_node)); } diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index d9f04864d15d..8ca448db7a0d 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -23,7 +23,7 @@ #include #include "br_private.h" -static kmem_cache_t *br_fdb_cache __read_mostly; +static struct kmem_cache *br_fdb_cache __read_mostly; static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr); diff --git a/net/core/flow.c b/net/core/flow.c index 5df3e297f817..104c25d00a1d 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -44,7 +44,7 @@ static DEFINE_PER_CPU(struct flow_cache_entry **, flow_tables) = { NULL }; #define flow_table(cpu) (per_cpu(flow_tables, cpu)) -static kmem_cache_t *flow_cachep __read_mostly; +static struct kmem_cache *flow_cachep __read_mostly; static int flow_lwm, flow_hwm; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 7217fb8928f2..de7801d589e7 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -68,8 +68,8 @@ #include "kmap_skb.h" -static kmem_cache_t *skbuff_head_cache __read_mostly; -static kmem_cache_t *skbuff_fclone_cache __read_mostly; +static struct kmem_cache *skbuff_head_cache __read_mostly; +static struct kmem_cache *skbuff_fclone_cache __read_mostly; /* * Keep out-of-line to prevent kernel bloat. @@ -144,7 +144,7 @@ EXPORT_SYMBOL(skb_truesize_bug); struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, int fclone, int node) { - kmem_cache_t *cache; + struct kmem_cache *cache; struct skb_shared_info *shinfo; struct sk_buff *skb; u8 *data; @@ -211,7 +211,7 @@ nodata: * Buffers may only be allocated from interrupts using a @gfp_mask of * %GFP_ATOMIC. */ -struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp, +struct sk_buff *alloc_skb_from_cache(struct kmem_cache *cp, unsigned int size, gfp_t gfp_mask) { diff --git a/net/core/sock.c b/net/core/sock.c index 419c7d3289c7..4a432da441e9 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -841,7 +841,7 @@ struct sock *sk_alloc(int family, gfp_t priority, struct proto *prot, int zero_it) { struct sock *sk = NULL; - kmem_cache_t *slab = prot->slab; + struct kmem_cache *slab = prot->slab; if (slab != NULL) sk = kmem_cache_alloc(slab, priority); diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index bdf1bb7a82c0..1f4727ddbdbf 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -21,8 +21,8 @@ #include -static kmem_cache_t *dccp_ackvec_slab; -static kmem_cache_t *dccp_ackvec_record_slab; +static struct kmem_cache *dccp_ackvec_slab; +static struct kmem_cache *dccp_ackvec_record_slab; static struct dccp_ackvec_record *dccp_ackvec_record_new(void) { diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c index ff05e59043cd..d8cf92f09e68 100644 --- a/net/dccp/ccid.c +++ b/net/dccp/ccid.c @@ -55,9 +55,9 @@ static inline void ccids_read_unlock(void) #define ccids_read_unlock() do { } while(0) #endif -static kmem_cache_t *ccid_kmem_cache_create(int obj_size, const char *fmt,...) +static struct kmem_cache *ccid_kmem_cache_create(int obj_size, const char *fmt,...) { - kmem_cache_t *slab; + struct kmem_cache *slab; char slab_name_fmt[32], *slab_name; va_list args; @@ -75,7 +75,7 @@ static kmem_cache_t *ccid_kmem_cache_create(int obj_size, const char *fmt,...) return slab; } -static void ccid_kmem_cache_destroy(kmem_cache_t *slab) +static void ccid_kmem_cache_destroy(struct kmem_cache *slab) { if (slab != NULL) { const char *name = kmem_cache_name(slab); diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h index c7c29514dce8..bcc2d12ae81c 100644 --- a/net/dccp/ccid.h +++ b/net/dccp/ccid.h @@ -27,9 +27,9 @@ struct ccid_operations { unsigned char ccid_id; const char *ccid_name; struct module *ccid_owner; - kmem_cache_t *ccid_hc_rx_slab; + struct kmem_cache *ccid_hc_rx_slab; __u32 ccid_hc_rx_obj_size; - kmem_cache_t *ccid_hc_tx_slab; + struct kmem_cache *ccid_hc_tx_slab; __u32 ccid_hc_tx_obj_size; int (*ccid_hc_rx_init)(struct ccid *ccid, struct sock *sk); int (*ccid_hc_tx_init)(struct ccid *ccid, struct sock *sk); diff --git a/net/dccp/ccids/lib/loss_interval.h b/net/dccp/ccids/lib/loss_interval.h index 0ae85f0340b2..eb257014dd74 100644 --- a/net/dccp/ccids/lib/loss_interval.h +++ b/net/dccp/ccids/lib/loss_interval.h @@ -20,7 +20,7 @@ #define DCCP_LI_HIST_IVAL_F_LENGTH 8 struct dccp_li_hist { - kmem_cache_t *dccplih_slab; + struct kmem_cache *dccplih_slab; }; extern struct dccp_li_hist *dccp_li_hist_new(const char *name); diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h index 067cf1c85a37..9a8bcf224aa7 100644 --- a/net/dccp/ccids/lib/packet_history.h +++ b/net/dccp/ccids/lib/packet_history.h @@ -68,14 +68,14 @@ struct dccp_rx_hist_entry { }; struct dccp_tx_hist { - kmem_cache_t *dccptxh_slab; + struct kmem_cache *dccptxh_slab; }; extern struct dccp_tx_hist *dccp_tx_hist_new(const char *name); extern void dccp_tx_hist_delete(struct dccp_tx_hist *hist); struct dccp_rx_hist { - kmem_cache_t *dccprxh_slab; + struct kmem_cache *dccprxh_slab; }; extern struct dccp_rx_hist *dccp_rx_hist_new(const char *name); diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index 101e5ccaf096..13b2421991ba 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -79,7 +79,7 @@ for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_n static struct hlist_head dn_fib_table_hash[DN_FIB_TABLE_HASHSZ]; static DEFINE_RWLOCK(dn_fib_tables_lock); -static kmem_cache_t *dn_hash_kmem __read_mostly; +static struct kmem_cache *dn_hash_kmem __read_mostly; static int dn_fib_hash_zombies; static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz) diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 4463443e42cd..648f47c1c399 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -45,8 +45,8 @@ #include "fib_lookup.h" -static kmem_cache_t *fn_hash_kmem __read_mostly; -static kmem_cache_t *fn_alias_kmem __read_mostly; +static struct kmem_cache *fn_hash_kmem __read_mostly; +static struct kmem_cache *fn_alias_kmem __read_mostly; struct fib_node { struct hlist_node fn_hash; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 6be6caf1af37..cfb249cc0a58 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -172,7 +172,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn); static struct tnode *halve(struct trie *t, struct tnode *tn); static void tnode_free(struct tnode *tn); -static kmem_cache_t *fn_alias_kmem __read_mostly; +static struct kmem_cache *fn_alias_kmem __read_mostly; static struct trie *trie_local = NULL, *trie_main = NULL; diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index bd6c9bc41893..8c79c8a4ea5c 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -27,7 +27,7 @@ * Allocate and initialize a new local port bind bucket. * The bindhash mutex for snum's hash chain must be held here. */ -struct inet_bind_bucket *inet_bind_bucket_create(kmem_cache_t *cachep, +struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep, struct inet_bind_hashbucket *head, const unsigned short snum) { @@ -45,7 +45,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(kmem_cache_t *cachep, /* * Caller must hold hashbucket lock for this tb with local BH disabled */ -void inet_bind_bucket_destroy(kmem_cache_t *cachep, struct inet_bind_bucket *tb) +void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket *tb) { if (hlist_empty(&tb->owners)) { __hlist_del(&tb->node); diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index f072f3875af8..711eb6d0285a 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -73,7 +73,7 @@ /* Exported for inet_getid inline function. */ DEFINE_SPINLOCK(inet_peer_idlock); -static kmem_cache_t *peer_cachep __read_mostly; +static struct kmem_cache *peer_cachep __read_mostly; #define node_height(x) x->avl_height static struct inet_peer peer_fake_node = { diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index efcf45ecc818..ecb5422ea237 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -105,7 +105,7 @@ static DEFINE_SPINLOCK(mfc_unres_lock); In this case data path is free of exclusive locks at all. */ -static kmem_cache_t *mrt_cachep __read_mostly; +static struct kmem_cache *mrt_cachep __read_mostly; static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local); static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert); diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c index 8832eb517d52..8086787a2c51 100644 --- a/net/ipv4/ipvs/ip_vs_conn.c +++ b/net/ipv4/ipvs/ip_vs_conn.c @@ -44,7 +44,7 @@ static struct list_head *ip_vs_conn_tab; /* SLAB cache for IPVS connections */ -static kmem_cache_t *ip_vs_conn_cachep __read_mostly; +static struct kmem_cache *ip_vs_conn_cachep __read_mostly; /* counter for current IPVS connections */ static atomic_t ip_vs_conn_count = ATOMIC_INIT(0); diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index f4b0e68a16d2..8556a4f4f60a 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -65,8 +65,8 @@ static LIST_HEAD(helpers); unsigned int ip_conntrack_htable_size __read_mostly = 0; int ip_conntrack_max __read_mostly; struct list_head *ip_conntrack_hash __read_mostly; -static kmem_cache_t *ip_conntrack_cachep __read_mostly; -static kmem_cache_t *ip_conntrack_expect_cachep __read_mostly; +static struct kmem_cache *ip_conntrack_cachep __read_mostly; +static struct kmem_cache *ip_conntrack_expect_cachep __read_mostly; struct ip_conntrack ip_conntrack_untracked; unsigned int ip_ct_log_invalid __read_mostly; static LIST_HEAD(unconfirmed); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 97a8cfbb61a1..96d8310ae9c8 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -50,7 +50,7 @@ struct rt6_statistics rt6_stats; -static kmem_cache_t * fib6_node_kmem __read_mostly; +static struct kmem_cache * fib6_node_kmem __read_mostly; enum fib_walk_state_t { diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index d4f68b0f27d5..12e426b9aacd 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -50,7 +50,7 @@ static u32 xfrm6_tunnel_spi; #define XFRM6_TUNNEL_SPI_MIN 1 #define XFRM6_TUNNEL_SPI_MAX 0xffffffff -static kmem_cache_t *xfrm6_tunnel_spi_kmem __read_mostly; +static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index eaa0f8a1adb6..a9638ff52a72 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -108,7 +108,7 @@ static struct { size_t size; /* slab cache pointer */ - kmem_cache_t *cachep; + struct kmem_cache *cachep; /* allocated slab cache + modules which uses this slab cache */ int use; @@ -147,7 +147,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name, { int ret = 0; char *cache_name; - kmem_cache_t *cachep; + struct kmem_cache *cachep; DEBUGP("nf_conntrack_register_cache: features=0x%x, name=%s, size=%d\n", features, name, size); @@ -226,7 +226,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_register_cache); /* FIXME: In the current, only nf_conntrack_cleanup() can call this function. */ void nf_conntrack_unregister_cache(u_int32_t features) { - kmem_cache_t *cachep; + struct kmem_cache *cachep; char *name; /* diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 588d37937046..c20f901fa177 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -29,7 +29,7 @@ LIST_HEAD(nf_conntrack_expect_list); EXPORT_SYMBOL_GPL(nf_conntrack_expect_list); -kmem_cache_t *nf_conntrack_expect_cachep __read_mostly; +struct kmem_cache *nf_conntrack_expect_cachep __read_mostly; static unsigned int nf_conntrack_expect_next_id; /* nf_conntrack_expect helper functions */ diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index a98de0b54d65..a5a6e192ac2d 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -92,7 +92,7 @@ struct xt_hashlimit_htable { static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ static HLIST_HEAD(hashlimit_htables); -static kmem_cache_t *hashlimit_cachep __read_mostly; +static struct kmem_cache *hashlimit_cachep __read_mostly; static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b) { diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 11f3b549f4a4..f2ba8615895b 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -79,8 +79,8 @@ static struct sctp_pf *sctp_pf_inet_specific; static struct sctp_af *sctp_af_v4_specific; static struct sctp_af *sctp_af_v6_specific; -kmem_cache_t *sctp_chunk_cachep __read_mostly; -kmem_cache_t *sctp_bucket_cachep __read_mostly; +struct kmem_cache *sctp_chunk_cachep __read_mostly; +struct kmem_cache *sctp_bucket_cachep __read_mostly; /* Return the address of the control sock. */ struct sock *sctp_get_ctl_sock(void) diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 8d55d10041f9..30927d3a597f 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -65,7 +65,7 @@ #include #include -extern kmem_cache_t *sctp_chunk_cachep; +extern struct kmem_cache *sctp_chunk_cachep; SCTP_STATIC struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 49607792cbd3..1e8132b8c4d9 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -107,7 +107,7 @@ static void sctp_sock_migrate(struct sock *, struct sock *, struct sctp_association *, sctp_socket_type_t); static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; -extern kmem_cache_t *sctp_bucket_cachep; +extern struct kmem_cache *sctp_bucket_cachep; /* Get the sndbuf space available at the time on the association. */ static inline int sctp_wspace(struct sctp_association *asoc) diff --git a/net/socket.c b/net/socket.c index 4f417c2ddc15..43eff489c878 100644 --- a/net/socket.c +++ b/net/socket.c @@ -230,7 +230,7 @@ int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, #define SOCKFS_MAGIC 0x534F434B -static kmem_cache_t *sock_inode_cachep __read_mostly; +static struct kmem_cache *sock_inode_cachep __read_mostly; static struct inode *sock_alloc_inode(struct super_block *sb) { @@ -257,7 +257,7 @@ static void sock_destroy_inode(struct inode *inode) container_of(inode, struct socket_alloc, vfs_inode)); } -static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) +static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) { struct socket_alloc *ei = (struct socket_alloc *)foo; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index df753d0a884b..19703aa9659e 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -33,7 +33,7 @@ static int rpc_mount_count; static struct file_system_type rpc_pipe_fs_type; -static kmem_cache_t *rpc_inode_cachep __read_mostly; +static struct kmem_cache *rpc_inode_cachep __read_mostly; #define RPC_UPCALL_TIMEOUT (30*HZ) @@ -824,7 +824,7 @@ static struct file_system_type rpc_pipe_fs_type = { }; static void -init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct rpc_inode *rpci = (struct rpc_inode *) foo; diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index eff44bcdc95a..225e6510b523 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -34,8 +34,8 @@ static int rpc_task_id; #define RPC_BUFFER_MAXSIZE (2048) #define RPC_BUFFER_POOLSIZE (8) #define RPC_TASK_POOLSIZE (8) -static kmem_cache_t *rpc_task_slabp __read_mostly; -static kmem_cache_t *rpc_buffer_slabp __read_mostly; +static struct kmem_cache *rpc_task_slabp __read_mostly; +static struct kmem_cache *rpc_buffer_slabp __read_mostly; static mempool_t *rpc_task_mempool __read_mostly; static mempool_t *rpc_buffer_mempool __read_mostly; diff --git a/net/tipc/handler.c b/net/tipc/handler.c index ae6ddf00a1aa..eb80778d6d9c 100644 --- a/net/tipc/handler.c +++ b/net/tipc/handler.c @@ -42,7 +42,7 @@ struct queue_item { unsigned long data; }; -static kmem_cache_t *tipc_queue_item_cache; +static struct kmem_cache *tipc_queue_item_cache; static struct list_head signal_queue_head; static DEFINE_SPINLOCK(qitem_lock); static int handler_enabled = 0; diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index a898a6a83a56..414f89070380 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -12,7 +12,7 @@ #include #include -static kmem_cache_t *secpath_cachep __read_mostly; +static struct kmem_cache *secpath_cachep __read_mostly; void __secpath_destroy(struct sec_path *sp) { diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index f6c77bd36fdd..3f3f563eb4ab 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -39,7 +39,7 @@ EXPORT_SYMBOL(xfrm_policy_count); static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; -static kmem_cache_t *xfrm_dst_cache __read_mostly; +static struct kmem_cache *xfrm_dst_cache __read_mostly; static struct work_struct xfrm_policy_gc_work; static HLIST_HEAD(xfrm_policy_gc_list); diff --git a/security/keys/key.c b/security/keys/key.c index 157bac658bf9..0db816f10f85 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -20,7 +20,7 @@ #include #include "internal.h" -static kmem_cache_t *key_jar; +static struct kmem_cache *key_jar; struct rb_root key_serial_tree; /* tree of keys indexed by serial */ DEFINE_SPINLOCK(key_serial_lock); diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 65b4ec9c699a..e7c0b5e2066b 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -124,7 +124,7 @@ DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; static struct avc_cache avc_cache; static struct avc_callback_node *avc_callbacks; -static kmem_cache_t *avc_node_cachep; +static struct kmem_cache *avc_node_cachep; static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ac1aeed0b289..44e9cd470543 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -124,7 +124,7 @@ static struct security_operations *secondary_ops = NULL; static LIST_HEAD(superblock_security_head); static DEFINE_SPINLOCK(sb_security_lock); -static kmem_cache_t *sel_inode_cache; +static struct kmem_cache *sel_inode_cache; /* Return security context for a given sid or just the context length if the buffer is null or length is 0 */ diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 2dfc6134c2c2..ebb993c5c244 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -28,7 +28,7 @@ (keyp->source_type << 9)) & \ AVTAB_HASH_MASK) -static kmem_cache_t *avtab_node_cachep; +static struct kmem_cache *avtab_node_cachep; static struct avtab_node* avtab_insert_node(struct avtab *h, int hvalue, -- cgit v1.2.3 From 1b1cec4bbc59feac89670d5d6d222a02545bac94 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 6 Dec 2006 20:33:22 -0800 Subject: [PATCH] slab: deprecate kmem_cache_t Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index fbcfc208f52b..2271886744f8 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -7,16 +7,17 @@ #ifndef _LINUX_SLAB_H #define _LINUX_SLAB_H -#if defined(__KERNEL__) +#ifdef __KERNEL__ -/* kmem_cache_t exists for legacy reasons and is not used by code in mm */ -typedef struct kmem_cache kmem_cache_t; +#include +#include +#include +#include /* kmalloc_sizes.h needs PAGE_SIZE */ +#include /* kmalloc_sizes.h needs L1_CACHE_BYTES */ +#include -#include -#include -#include -#include /* kmalloc_sizes.h needs PAGE_SIZE */ -#include /* kmalloc_sizes.h needs L1_CACHE_BYTES */ +/* kmem_cache_t exists for legacy reasons and is not used by code in mm */ +typedef struct kmem_cache kmem_cache_t __deprecated; /* flags to pass to kmem_cache_create(). * The first 3 are only valid when the allocator as been build -- cgit v1.2.3 From 33f2ef89f8e181486b63fdbdc97c6afa6ca9f34b Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Wed, 6 Dec 2006 20:33:32 -0800 Subject: [PATCH] mm: make compound page destructor handling explicit Currently we we use the lru head link of the second page of a compound page to hold its destructor. This was ok when it was purely an internal implmentation detail. However, hugetlbfs overrides this destructor violating the layering. Abstract this out as explicit calls, also introduce a type for the callback function allowing them to be type checked. For each callback we pre-declare the function, causing a type error on definition rather than on use elsewhere. [akpm@osdl.org: cleanups] Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 18 ++++++++++++++++++ mm/hugetlb.c | 2 +- mm/page_alloc.c | 2 +- mm/swap.c | 4 ++-- 4 files changed, 22 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index 0e266fe1b4c4..a17b147c61e7 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -295,6 +295,24 @@ void put_pages_list(struct list_head *pages); void split_page(struct page *page, unsigned int order); +/* + * Compound pages have a destructor function. Provide a + * prototype for that function and accessor functions. + * These are _only_ valid on the head of a PG_compound page. + */ +typedef void compound_page_dtor(struct page *); + +static inline void set_compound_page_dtor(struct page *page, + compound_page_dtor *dtor) +{ + page[1].lru.next = (void *)dtor; +} + +static inline compound_page_dtor *get_compound_page_dtor(struct page *page) +{ + return (compound_page_dtor *)page[1].lru.next; +} + /* * Multiple processes may "see" the same page. E.g. for untouched * mappings of /dev/null, all processes see the same page full of diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 2911a364481e..0ccc7f230252 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -109,7 +109,7 @@ static int alloc_fresh_huge_page(void) if (nid == MAX_NUMNODES) nid = first_node(node_online_map); if (page) { - page[1].lru.next = (void *)free_huge_page; /* dtor */ + set_compound_page_dtor(page, free_huge_page); spin_lock(&hugetlb_lock); nr_huge_pages++; nr_huge_pages_node[page_to_nid(page)]++; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index dc8753bdd47e..d539f83c62b6 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -230,7 +230,7 @@ static void prep_compound_page(struct page *page, unsigned long order) int i; int nr_pages = 1 << order; - page[1].lru.next = (void *)free_compound_page; /* set dtor */ + set_compound_page_dtor(page, free_compound_page); page[1].lru.prev = (void *)order; for (i = 0; i < nr_pages; i++) { struct page *p = page + i; diff --git a/mm/swap.c b/mm/swap.c index d9a3770d8f3c..017e72ca9bbb 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -57,9 +57,9 @@ static void put_compound_page(struct page *page) { page = (struct page *)page_private(page); if (put_page_testzero(page)) { - void (*dtor)(struct page *page); + compound_page_dtor *dtor; - dtor = (void (*)(struct page *))page[1].lru.next; + dtor = get_compound_page_dtor(page); (*dtor)(page); } } -- cgit v1.2.3 From 36de6437866bbb1d37e2312ff4f95ee4ed6d2b61 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 6 Dec 2006 20:33:42 -0800 Subject: [PATCH] Save some bytes in struct mm_struct Before: [acme@newtoy net-2.6.20]$ pahole --cacheline 32 kernel/sched.o mm_struct /* include2/asm/processor.h:542 */ struct mm_struct { struct vm_area_struct * mmap; /* 0 4 */ struct rb_root mm_rb; /* 4 4 */ struct vm_area_struct * mmap_cache; /* 8 4 */ long unsigned int (*get_unmapped_area)(); /* 12 4 */ void (*unmap_area)(); /* 16 4 */ long unsigned int mmap_base; /* 20 4 */ long unsigned int task_size; /* 24 4 */ long unsigned int cached_hole_size; /* 28 4 */ /* ---------- cacheline 1 boundary ---------- */ long unsigned int free_area_cache; /* 32 4 */ pgd_t * pgd; /* 36 4 */ atomic_t mm_users; /* 40 4 */ atomic_t mm_count; /* 44 4 */ int map_count; /* 48 4 */ struct rw_semaphore mmap_sem; /* 52 64 */ spinlock_t page_table_lock; /* 116 40 */ struct list_head mmlist; /* 156 8 */ mm_counter_t _file_rss; /* 164 4 */ mm_counter_t _anon_rss; /* 168 4 */ long unsigned int hiwater_rss; /* 172 4 */ long unsigned int hiwater_vm; /* 176 4 */ long unsigned int total_vm; /* 180 4 */ long unsigned int locked_vm; /* 184 4 */ long unsigned int shared_vm; /* 188 4 */ /* ---------- cacheline 6 boundary ---------- */ long unsigned int exec_vm; /* 192 4 */ long unsigned int stack_vm; /* 196 4 */ long unsigned int reserved_vm; /* 200 4 */ long unsigned int def_flags; /* 204 4 */ long unsigned int nr_ptes; /* 208 4 */ long unsigned int start_code; /* 212 4 */ long unsigned int end_code; /* 216 4 */ long unsigned int start_data; /* 220 4 */ /* ---------- cacheline 7 boundary ---------- */ long unsigned int end_data; /* 224 4 */ long unsigned int start_brk; /* 228 4 */ long unsigned int brk; /* 232 4 */ long unsigned int start_stack; /* 236 4 */ long unsigned int arg_start; /* 240 4 */ long unsigned int arg_end; /* 244 4 */ long unsigned int env_start; /* 248 4 */ long unsigned int env_end; /* 252 4 */ /* ---------- cacheline 8 boundary ---------- */ long unsigned int saved_auxv[44]; /* 256 176 */ unsigned int dumpable:2; /* 432 4 */ cpumask_t cpu_vm_mask; /* 436 4 */ mm_context_t context; /* 440 68 */ long unsigned int swap_token_time; /* 508 4 */ /* ---------- cacheline 16 boundary ---------- */ char recent_pagein; /* 512 1 */ /* XXX 3 bytes hole, try to pack */ int core_waiters; /* 516 4 */ struct completion * core_startup_done; /* 520 4 */ struct completion core_done; /* 524 52 */ rwlock_t ioctx_list_lock; /* 576 36 */ struct kioctx * ioctx_list; /* 612 4 */ }; /* size: 616, sum members: 613, holes: 1, sum holes: 3, cachelines: 20, last cacheline: 8 bytes */ After: [acme@newtoy net-2.6.20]$ pahole --cacheline 32 kernel/sched.o mm_struct /* include2/asm/processor.h:542 */ struct mm_struct { struct vm_area_struct * mmap; /* 0 4 */ struct rb_root mm_rb; /* 4 4 */ struct vm_area_struct * mmap_cache; /* 8 4 */ long unsigned int (*get_unmapped_area)(); /* 12 4 */ void (*unmap_area)(); /* 16 4 */ long unsigned int mmap_base; /* 20 4 */ long unsigned int task_size; /* 24 4 */ long unsigned int cached_hole_size; /* 28 4 */ /* ---------- cacheline 1 boundary ---------- */ long unsigned int free_area_cache; /* 32 4 */ pgd_t * pgd; /* 36 4 */ atomic_t mm_users; /* 40 4 */ atomic_t mm_count; /* 44 4 */ int map_count; /* 48 4 */ struct rw_semaphore mmap_sem; /* 52 64 */ spinlock_t page_table_lock; /* 116 40 */ struct list_head mmlist; /* 156 8 */ mm_counter_t _file_rss; /* 164 4 */ mm_counter_t _anon_rss; /* 168 4 */ long unsigned int hiwater_rss; /* 172 4 */ long unsigned int hiwater_vm; /* 176 4 */ long unsigned int total_vm; /* 180 4 */ long unsigned int locked_vm; /* 184 4 */ long unsigned int shared_vm; /* 188 4 */ /* ---------- cacheline 6 boundary ---------- */ long unsigned int exec_vm; /* 192 4 */ long unsigned int stack_vm; /* 196 4 */ long unsigned int reserved_vm; /* 200 4 */ long unsigned int def_flags; /* 204 4 */ long unsigned int nr_ptes; /* 208 4 */ long unsigned int start_code; /* 212 4 */ long unsigned int end_code; /* 216 4 */ long unsigned int start_data; /* 220 4 */ /* ---------- cacheline 7 boundary ---------- */ long unsigned int end_data; /* 224 4 */ long unsigned int start_brk; /* 228 4 */ long unsigned int brk; /* 232 4 */ long unsigned int start_stack; /* 236 4 */ long unsigned int arg_start; /* 240 4 */ long unsigned int arg_end; /* 244 4 */ long unsigned int env_start; /* 248 4 */ long unsigned int env_end; /* 252 4 */ /* ---------- cacheline 8 boundary ---------- */ long unsigned int saved_auxv[44]; /* 256 176 */ cpumask_t cpu_vm_mask; /* 432 4 */ mm_context_t context; /* 436 68 */ long unsigned int swap_token_time; /* 504 4 */ char recent_pagein; /* 508 1 */ unsigned char dumpable:2; /* 509 1 */ /* XXX 2 bytes hole, try to pack */ int core_waiters; /* 512 4 */ struct completion * core_startup_done; /* 516 4 */ struct completion core_done; /* 520 52 */ rwlock_t ioctx_list_lock; /* 572 36 */ struct kioctx * ioctx_list; /* 608 4 */ }; /* size: 612, sum members: 610, holes: 1, sum holes: 2, cachelines: 20, last cacheline: 4 bytes */ [acme@newtoy net-2.6.20]$ codiff -V /tmp/sched.o.before kernel/sched.o /pub/scm/linux/kernel/git/acme/net-2.6.20/kernel/sched.c: struct mm_struct | -4 dumpable:2; from: unsigned int /* 432(30) 4(2) */ to: unsigned char /* 509(6) 1(2) */ < SNIP other offset changes > 1 struct changed [acme@newtoy net-2.6.20]$ I'm not aware of any problem about using 2 byte wide bitfields where previously a 4 byte wide one was, holler if there is any, I wouldn't be surprised, bitfields are things from hell. For the curious, 432(30) means: at offset 432 from the struct start, at offset 30 in the bitfield (yeah, it comes backwards, hellish, huh?) ditto for 509(6), while 4(2) and 1(2) means "struct field size(bitfield size)". Now we have a 2 bytes hole and are using only 4 bytes of the last 32 bytes cacheline, any takers? :-) Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index cad6a16260f7..acfd2e15c5f2 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -338,7 +338,6 @@ struct mm_struct { unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */ - unsigned dumpable:2; cpumask_t cpu_vm_mask; /* Architecture-specific MM context */ @@ -355,6 +354,8 @@ struct mm_struct { unsigned int token_priority; unsigned int last_interval; + unsigned char dumpable:2; + /* coredumping support */ int core_waiters; struct completion *core_startup_done, core_done; -- cgit v1.2.3 From 7cf9c2c76c1a17b32f2da85b50cd4fe468ed44b5 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 6 Dec 2006 20:33:44 -0800 Subject: [PATCH] radix-tree: RCU lockless readside Make radix tree lookups safe to be performed without locks. Readers are protected against nodes being deleted by using RCU based freeing. Readers are protected against new node insertion by using memory barriers to ensure the node itself will be properly written before it is visible in the radix tree. Each radix tree node keeps a record of their height (above leaf nodes). This height does not change after insertion -- when the radix tree is extended, higher nodes are only inserted in the top. So a lookup can take the pointer to what is *now* the root node, and traverse down it even if the tree is concurrently extended and this node becomes a subtree of a new root. "Direct" pointers (tree height of 0, where root->rnode points directly to the data item) are handled by using the low bit of the pointer to signal whether rnode is a direct pointer or a pointer to a radix tree node. When a reader wants to traverse the next branch, they will take a copy of the pointer. This pointer will be either NULL (and the branch is empty) or non-NULL (and will point to a valid node). [akpm@osdl.org: cleanups] [Lee.Schermerhorn@hp.com: bugfixes, comments, simplifications] [clameter@sgi.com: build fix] Signed-off-by: Nick Piggin Cc: "Paul E. McKenney" Signed-off-by: Lee Schermerhorn Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/radix-tree.h | 101 ++++++++++++++ lib/radix-tree.c | 327 +++++++++++++++++++++++++++++++-------------- mm/migrate.c | 19 ++- 3 files changed, 340 insertions(+), 107 deletions(-) (limited to 'include/linux') diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index cbfa11537421..0deb842541ac 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2001 Momchil Velikov * Portions Copyright (C) 2001 Christoph Hellwig + * Copyright (C) 2006 Nick Piggin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -21,6 +22,35 @@ #include #include +#include +#include + +/* + * A direct pointer (root->rnode pointing directly to a data item, + * rather than another radix_tree_node) is signalled by the low bit + * set in the root->rnode pointer. + * + * In this case root->height is also NULL, but the direct pointer tests are + * needed for RCU lookups when root->height is unreliable. + */ +#define RADIX_TREE_DIRECT_PTR 1 + +static inline void *radix_tree_ptr_to_direct(void *ptr) +{ + return (void *)((unsigned long)ptr | RADIX_TREE_DIRECT_PTR); +} + +static inline void *radix_tree_direct_to_ptr(void *ptr) +{ + return (void *)((unsigned long)ptr & ~RADIX_TREE_DIRECT_PTR); +} + +static inline int radix_tree_is_direct_ptr(void *ptr) +{ + return (int)((unsigned long)ptr & RADIX_TREE_DIRECT_PTR); +} + +/*** radix-tree API starts here ***/ #define RADIX_TREE_MAX_TAGS 2 @@ -47,6 +77,77 @@ do { \ (root)->rnode = NULL; \ } while (0) +/** + * Radix-tree synchronization + * + * The radix-tree API requires that users provide all synchronisation (with + * specific exceptions, noted below). + * + * Synchronization of access to the data items being stored in the tree, and + * management of their lifetimes must be completely managed by API users. + * + * For API usage, in general, + * - any function _modifying_ the the tree or tags (inserting or deleting + * items, setting or clearing tags must exclude other modifications, and + * exclude any functions reading the tree. + * - any function _reading_ the the tree or tags (looking up items or tags, + * gang lookups) must exclude modifications to the tree, but may occur + * concurrently with other readers. + * + * The notable exceptions to this rule are the following functions: + * radix_tree_lookup + * radix_tree_tag_get + * radix_tree_gang_lookup + * radix_tree_gang_lookup_tag + * radix_tree_tagged + * + * The first 4 functions are able to be called locklessly, using RCU. The + * caller must ensure calls to these functions are made within rcu_read_lock() + * regions. Other readers (lock-free or otherwise) and modifications may be + * running concurrently. + * + * It is still required that the caller manage the synchronization and lifetimes + * of the items. So if RCU lock-free lookups are used, typically this would mean + * that the items have their own locks, or are amenable to lock-free access; and + * that the items are freed by RCU (or only freed after having been deleted from + * the radix tree *and* a synchronize_rcu() grace period). + * + * (Note, rcu_assign_pointer and rcu_dereference are not needed to control + * access to data items when inserting into or looking up from the radix tree) + * + * radix_tree_tagged is able to be called without locking or RCU. + */ + +/** + * radix_tree_deref_slot - dereference a slot + * @pslot: pointer to slot, returned by radix_tree_lookup_slot + * Returns: item that was stored in that slot with any direct pointer flag + * removed. + * + * For use with radix_tree_lookup_slot(). Caller must hold tree at least read + * locked across slot lookup and dereference. More likely, will be used with + * radix_tree_replace_slot(), as well, so caller will hold tree write locked. + */ +static inline void *radix_tree_deref_slot(void **pslot) +{ + return radix_tree_direct_to_ptr(*pslot); +} +/** + * radix_tree_replace_slot - replace item in a slot + * @pslot: pointer to slot, returned by radix_tree_lookup_slot + * @item: new item to store in the slot. + * + * For use with radix_tree_lookup_slot(). Caller must hold tree write locked + * across slot lookup and replacement. + */ +static inline void radix_tree_replace_slot(void **pslot, void *item) +{ + BUG_ON(radix_tree_is_direct_ptr(item)); + rcu_assign_pointer(*pslot, + (void *)((unsigned long)item | + ((unsigned long)*pslot & RADIX_TREE_DIRECT_PTR))); +} + int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); void *radix_tree_lookup(struct radix_tree_root *, unsigned long); void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 9eb25955019f..e2cefabb5aa0 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -2,6 +2,7 @@ * Copyright (C) 2001 Momchil Velikov * Portions Copyright (C) 2001 Christoph Hellwig * Copyright (C) 2005 SGI, Christoph Lameter + * Copyright (C) 2006 Nick Piggin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -30,6 +31,7 @@ #include #include #include +#include #ifdef __KERNEL__ @@ -45,7 +47,9 @@ ((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG) struct radix_tree_node { + unsigned int height; /* Height from the bottom */ unsigned int count; + struct rcu_head rcu_head; void *slots[RADIX_TREE_MAP_SIZE]; unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; }; @@ -100,13 +104,21 @@ radix_tree_node_alloc(struct radix_tree_root *root) rtp->nr--; } } + BUG_ON(radix_tree_is_direct_ptr(ret)); return ret; } +static void radix_tree_node_rcu_free(struct rcu_head *head) +{ + struct radix_tree_node *node = + container_of(head, struct radix_tree_node, rcu_head); + kmem_cache_free(radix_tree_node_cachep, node); +} + static inline void radix_tree_node_free(struct radix_tree_node *node) { - kmem_cache_free(radix_tree_node_cachep, node); + call_rcu(&node->rcu_head, radix_tree_node_rcu_free); } /* @@ -222,11 +234,12 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) } do { + unsigned int newheight; if (!(node = radix_tree_node_alloc(root))) return -ENOMEM; /* Increase the height. */ - node->slots[0] = root->rnode; + node->slots[0] = radix_tree_direct_to_ptr(root->rnode); /* Propagate the aggregated tag info into the new root */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { @@ -234,9 +247,11 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) tag_set(node, tag, 0); } + newheight = root->height+1; + node->height = newheight; node->count = 1; - root->rnode = node; - root->height++; + rcu_assign_pointer(root->rnode, node); + root->height = newheight; } while (height > root->height); out: return 0; @@ -258,6 +273,8 @@ int radix_tree_insert(struct radix_tree_root *root, int offset; int error; + BUG_ON(radix_tree_is_direct_ptr(item)); + /* Make sure the tree is high enough. */ if (index > radix_tree_maxindex(root->height)) { error = radix_tree_extend(root, index); @@ -275,11 +292,12 @@ int radix_tree_insert(struct radix_tree_root *root, /* Have to add a child node. */ if (!(slot = radix_tree_node_alloc(root))) return -ENOMEM; + slot->height = height; if (node) { - node->slots[offset] = slot; + rcu_assign_pointer(node->slots[offset], slot); node->count++; } else - root->rnode = slot; + rcu_assign_pointer(root->rnode, slot); } /* Go a level down */ @@ -295,11 +313,11 @@ int radix_tree_insert(struct radix_tree_root *root, if (node) { node->count++; - node->slots[offset] = item; + rcu_assign_pointer(node->slots[offset], item); BUG_ON(tag_get(node, 0, offset)); BUG_ON(tag_get(node, 1, offset)); } else { - root->rnode = item; + rcu_assign_pointer(root->rnode, radix_tree_ptr_to_direct(item)); BUG_ON(root_tag_get(root, 0)); BUG_ON(root_tag_get(root, 1)); } @@ -308,49 +326,54 @@ int radix_tree_insert(struct radix_tree_root *root, } EXPORT_SYMBOL(radix_tree_insert); -static inline void **__lookup_slot(struct radix_tree_root *root, - unsigned long index) +/** + * radix_tree_lookup_slot - lookup a slot in a radix tree + * @root: radix tree root + * @index: index key + * + * Returns: the slot corresponding to the position @index in the + * radix tree @root. This is useful for update-if-exists operations. + * + * This function cannot be called under rcu_read_lock, it must be + * excluded from writers, as must the returned slot for subsequent + * use by radix_tree_deref_slot() and radix_tree_replace slot. + * Caller must hold tree write locked across slot lookup and + * replace. + */ +void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) { unsigned int height, shift; - struct radix_tree_node **slot; - - height = root->height; + struct radix_tree_node *node, **slot; - if (index > radix_tree_maxindex(height)) + node = root->rnode; + if (node == NULL) return NULL; - if (height == 0 && root->rnode) + if (radix_tree_is_direct_ptr(node)) { + if (index > 0) + return NULL; return (void **)&root->rnode; + } + + height = node->height; + if (index > radix_tree_maxindex(height)) + return NULL; shift = (height-1) * RADIX_TREE_MAP_SHIFT; - slot = &root->rnode; - while (height > 0) { - if (*slot == NULL) + do { + slot = (struct radix_tree_node **) + (node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK)); + node = *slot; + if (node == NULL) return NULL; - slot = (struct radix_tree_node **) - ((*slot)->slots + - ((index >> shift) & RADIX_TREE_MAP_MASK)); shift -= RADIX_TREE_MAP_SHIFT; height--; - } + } while (height > 0); return (void **)slot; } - -/** - * radix_tree_lookup_slot - lookup a slot in a radix tree - * @root: radix tree root - * @index: index key - * - * Lookup the slot corresponding to the position @index in the radix tree - * @root. This is useful for update-if-exists operations. - */ -void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) -{ - return __lookup_slot(root, index); -} EXPORT_SYMBOL(radix_tree_lookup_slot); /** @@ -359,13 +382,45 @@ EXPORT_SYMBOL(radix_tree_lookup_slot); * @index: index key * * Lookup the item at the position @index in the radix tree @root. + * + * This function can be called under rcu_read_lock, however the caller + * must manage lifetimes of leaf nodes (eg. RCU may also be used to free + * them safely). No RCU barriers are required to access or modify the + * returned item, however. */ void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) { - void **slot; + unsigned int height, shift; + struct radix_tree_node *node, **slot; + + node = rcu_dereference(root->rnode); + if (node == NULL) + return NULL; + + if (radix_tree_is_direct_ptr(node)) { + if (index > 0) + return NULL; + return radix_tree_direct_to_ptr(node); + } + + height = node->height; + if (index > radix_tree_maxindex(height)) + return NULL; + + shift = (height-1) * RADIX_TREE_MAP_SHIFT; - slot = __lookup_slot(root, index); - return slot != NULL ? *slot : NULL; + do { + slot = (struct radix_tree_node **) + (node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK)); + node = rcu_dereference(*slot); + if (node == NULL) + return NULL; + + shift -= RADIX_TREE_MAP_SHIFT; + height--; + } while (height > 0); + + return node; } EXPORT_SYMBOL(radix_tree_lookup); @@ -495,27 +550,30 @@ int radix_tree_tag_get(struct radix_tree_root *root, unsigned long index, unsigned int tag) { unsigned int height, shift; - struct radix_tree_node *slot; + struct radix_tree_node *node; int saw_unset_tag = 0; - height = root->height; - if (index > radix_tree_maxindex(height)) - return 0; - /* check the root's tag bit */ if (!root_tag_get(root, tag)) return 0; - if (height == 0) - return 1; + node = rcu_dereference(root->rnode); + if (node == NULL) + return 0; + + if (radix_tree_is_direct_ptr(node)) + return (index == 0); + + height = node->height; + if (index > radix_tree_maxindex(height)) + return 0; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; - slot = root->rnode; for ( ; ; ) { int offset; - if (slot == NULL) + if (node == NULL) return 0; offset = (index >> shift) & RADIX_TREE_MAP_MASK; @@ -524,15 +582,15 @@ int radix_tree_tag_get(struct radix_tree_root *root, * This is just a debug check. Later, we can bale as soon as * we see an unset tag. */ - if (!tag_get(slot, tag, offset)) + if (!tag_get(node, tag, offset)) saw_unset_tag = 1; if (height == 1) { - int ret = tag_get(slot, tag, offset); + int ret = tag_get(node, tag, offset); BUG_ON(ret && saw_unset_tag); return !!ret; } - slot = slot->slots[offset]; + node = rcu_dereference(node->slots[offset]); shift -= RADIX_TREE_MAP_SHIFT; height--; } @@ -541,47 +599,45 @@ EXPORT_SYMBOL(radix_tree_tag_get); #endif static unsigned int -__lookup(struct radix_tree_root *root, void **results, unsigned long index, +__lookup(struct radix_tree_node *slot, void **results, unsigned long index, unsigned int max_items, unsigned long *next_index) { unsigned int nr_found = 0; unsigned int shift, height; - struct radix_tree_node *slot; unsigned long i; - height = root->height; - if (height == 0) { - if (root->rnode && index == 0) - results[nr_found++] = root->rnode; + height = slot->height; + if (height == 0) goto out; - } - shift = (height-1) * RADIX_TREE_MAP_SHIFT; - slot = root->rnode; for ( ; height > 1; height--) { - - for (i = (index >> shift) & RADIX_TREE_MAP_MASK ; - i < RADIX_TREE_MAP_SIZE; i++) { + i = (index >> shift) & RADIX_TREE_MAP_MASK; + for (;;) { if (slot->slots[i] != NULL) break; index &= ~((1UL << shift) - 1); index += 1UL << shift; if (index == 0) goto out; /* 32-bit wraparound */ + i++; + if (i == RADIX_TREE_MAP_SIZE) + goto out; } - if (i == RADIX_TREE_MAP_SIZE) - goto out; shift -= RADIX_TREE_MAP_SHIFT; - slot = slot->slots[i]; + slot = rcu_dereference(slot->slots[i]); + if (slot == NULL) + goto out; } /* Bottom level: grab some items */ for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) { + struct radix_tree_node *node; index++; - if (slot->slots[i]) { - results[nr_found++] = slot->slots[i]; + node = slot->slots[i]; + if (node) { + results[nr_found++] = rcu_dereference(node); if (nr_found == max_items) goto out; } @@ -603,28 +659,51 @@ out: * *@results. * * The implementation is naive. + * + * Like radix_tree_lookup, radix_tree_gang_lookup may be called under + * rcu_read_lock. In this case, rather than the returned results being + * an atomic snapshot of the tree at a single point in time, the semantics + * of an RCU protected gang lookup are as though multiple radix_tree_lookups + * have been issued in individual locks, and results stored in 'results'. */ unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items) { - const unsigned long max_index = radix_tree_maxindex(root->height); + unsigned long max_index; + struct radix_tree_node *node; unsigned long cur_index = first_index; - unsigned int ret = 0; + unsigned int ret; + + node = rcu_dereference(root->rnode); + if (!node) + return 0; + if (radix_tree_is_direct_ptr(node)) { + if (first_index > 0) + return 0; + node = radix_tree_direct_to_ptr(node); + results[0] = rcu_dereference(node); + return 1; + } + + max_index = radix_tree_maxindex(node->height); + + ret = 0; while (ret < max_items) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; - nr_found = __lookup(root, results + ret, cur_index, + nr_found = __lookup(node, results + ret, cur_index, max_items - ret, &next_index); ret += nr_found; if (next_index == 0) break; cur_index = next_index; } + return ret; } EXPORT_SYMBOL(radix_tree_gang_lookup); @@ -634,55 +713,64 @@ EXPORT_SYMBOL(radix_tree_gang_lookup); * open-coding the search. */ static unsigned int -__lookup_tag(struct radix_tree_root *root, void **results, unsigned long index, +__lookup_tag(struct radix_tree_node *slot, void **results, unsigned long index, unsigned int max_items, unsigned long *next_index, unsigned int tag) { unsigned int nr_found = 0; - unsigned int shift; - unsigned int height = root->height; - struct radix_tree_node *slot; + unsigned int shift, height; - if (height == 0) { - if (root->rnode && index == 0) - results[nr_found++] = root->rnode; + height = slot->height; + if (height == 0) goto out; - } - - shift = (height - 1) * RADIX_TREE_MAP_SHIFT; - slot = root->rnode; + shift = (height-1) * RADIX_TREE_MAP_SHIFT; - do { - unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK; + while (height > 0) { + unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK ; - for ( ; i < RADIX_TREE_MAP_SIZE; i++) { - if (tag_get(slot, tag, i)) { - BUG_ON(slot->slots[i] == NULL); + for (;;) { + if (tag_get(slot, tag, i)) break; - } index &= ~((1UL << shift) - 1); index += 1UL << shift; if (index == 0) goto out; /* 32-bit wraparound */ + i++; + if (i == RADIX_TREE_MAP_SIZE) + goto out; } - if (i == RADIX_TREE_MAP_SIZE) - goto out; height--; if (height == 0) { /* Bottom level: grab some items */ unsigned long j = index & RADIX_TREE_MAP_MASK; for ( ; j < RADIX_TREE_MAP_SIZE; j++) { + struct radix_tree_node *node; index++; - if (tag_get(slot, tag, j)) { - BUG_ON(slot->slots[j] == NULL); - results[nr_found++] = slot->slots[j]; + if (!tag_get(slot, tag, j)) + continue; + node = slot->slots[j]; + /* + * Even though the tag was found set, we need to + * recheck that we have a non-NULL node, because + * if this lookup is lockless, it may have been + * subsequently deleted. + * + * Similar care must be taken in any place that + * lookup ->slots[x] without a lock (ie. can't + * rely on its value remaining the same). + */ + if (node) { + node = rcu_dereference(node); + results[nr_found++] = node; if (nr_found == max_items) goto out; } } } shift -= RADIX_TREE_MAP_SHIFT; - slot = slot->slots[i]; - } while (height > 0); + slot = rcu_dereference(slot->slots[i]); + if (slot == NULL) + break; + } out: *next_index = index; return nr_found; @@ -706,27 +794,44 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items, unsigned int tag) { - const unsigned long max_index = radix_tree_maxindex(root->height); + struct radix_tree_node *node; + unsigned long max_index; unsigned long cur_index = first_index; - unsigned int ret = 0; + unsigned int ret; /* check the root's tag bit */ if (!root_tag_get(root, tag)) return 0; + node = rcu_dereference(root->rnode); + if (!node) + return 0; + + if (radix_tree_is_direct_ptr(node)) { + if (first_index > 0) + return 0; + node = radix_tree_direct_to_ptr(node); + results[0] = rcu_dereference(node); + return 1; + } + + max_index = radix_tree_maxindex(node->height); + + ret = 0; while (ret < max_items) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; - nr_found = __lookup_tag(root, results + ret, cur_index, + nr_found = __lookup_tag(node, results + ret, cur_index, max_items - ret, &next_index, tag); ret += nr_found; if (next_index == 0) break; cur_index = next_index; } + return ret; } EXPORT_SYMBOL(radix_tree_gang_lookup_tag); @@ -742,8 +847,19 @@ static inline void radix_tree_shrink(struct radix_tree_root *root) root->rnode->count == 1 && root->rnode->slots[0]) { struct radix_tree_node *to_free = root->rnode; + void *newptr; - root->rnode = to_free->slots[0]; + /* + * We don't need rcu_assign_pointer(), since we are simply + * moving the node from one part of the tree to another. If + * it was safe to dereference the old pointer to it + * (to_free->slots[0]), it will be safe to dereference the new + * one (root->rnode). + */ + newptr = to_free->slots[0]; + if (root->height == 1) + newptr = radix_tree_ptr_to_direct(newptr); + root->rnode = newptr; root->height--; /* must only free zeroed nodes into the slab */ tag_clear(to_free, 0, 0); @@ -767,6 +883,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) { struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; struct radix_tree_node *slot = NULL; + struct radix_tree_node *to_free; unsigned int height, shift; int tag; int offset; @@ -777,6 +894,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) slot = root->rnode; if (height == 0 && root->rnode) { + slot = radix_tree_direct_to_ptr(slot); root_tag_clear_all(root); root->rnode = NULL; goto out; @@ -809,10 +927,17 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) radix_tree_tag_clear(root, index, tag); } + to_free = NULL; /* Now free the nodes we do not need anymore */ while (pathp->node) { pathp->node->slots[pathp->offset] = NULL; pathp->node->count--; + /* + * Queue the node for deferred freeing after the + * last reference to it disappears (set NULL, above). + */ + if (to_free) + radix_tree_node_free(to_free); if (pathp->node->count) { if (pathp->node == root->rnode) @@ -821,13 +946,15 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) } /* Node with zero slots in use so free it */ - radix_tree_node_free(pathp->node); - + to_free = pathp->node; pathp--; + } root_tag_clear_all(root); root->height = 0; root->rnode = NULL; + if (to_free) + radix_tree_node_free(to_free); out: return slot; diff --git a/mm/migrate.c b/mm/migrate.c index b4979d423d2b..e9b161bde95b 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -294,7 +294,7 @@ out: static int migrate_page_move_mapping(struct address_space *mapping, struct page *newpage, struct page *page) { - struct page **radix_pointer; + void **pslot; if (!mapping) { /* Anonymous page */ @@ -305,12 +305,11 @@ static int migrate_page_move_mapping(struct address_space *mapping, write_lock_irq(&mapping->tree_lock); - radix_pointer = (struct page **)radix_tree_lookup_slot( - &mapping->page_tree, - page_index(page)); + pslot = radix_tree_lookup_slot(&mapping->page_tree, + page_index(page)); if (page_count(page) != 2 + !!PagePrivate(page) || - *radix_pointer != page) { + (struct page *)radix_tree_deref_slot(pslot) != page) { write_unlock_irq(&mapping->tree_lock); return -EAGAIN; } @@ -318,7 +317,7 @@ static int migrate_page_move_mapping(struct address_space *mapping, /* * Now we know that no one else is looking at the page. */ - get_page(newpage); + get_page(newpage); /* add cache reference */ #ifdef CONFIG_SWAP if (PageSwapCache(page)) { SetPageSwapCache(newpage); @@ -326,8 +325,14 @@ static int migrate_page_move_mapping(struct address_space *mapping, } #endif - *radix_pointer = newpage; + radix_tree_replace_slot(pslot, newpage); + + /* + * Drop cache reference from old page. + * We know this isn't the last reference. + */ __put_page(page); + write_unlock_irq(&mapping->tree_lock); return 0; -- cgit v1.2.3 From 915bae9ebe41e52d71ad8b06d50e4ab26189f964 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 6 Dec 2006 20:34:07 -0800 Subject: [PATCH] swsusp: use partition device and offset to identify swap areas The Linux kernel handles swap files almost in the same way as it handles swap partitions and there are only two differences between these two types of swap areas: (1) swap files need not be contiguous, (2) the header of a swap file is not in the first block of the partition that holds it. From the swsusp's point of view (1) is not a problem, because it is already taken care of by the swap-handling code, but (2) has to be taken into consideration. In principle the location of a swap file's header may be determined with the help of appropriate filesystem driver. Unfortunately, however, it requires the filesystem holding the swap file to be mounted, and if this filesystem is journaled, it cannot be mounted during a resume from disk. For this reason we need some other means by which swap areas can be identified. For example, to identify a swap area we can use the partition that holds the area and the offset from the beginning of this partition at which the swap header is located. The following patch allows swsusp to identify swap areas this way. It changes swap_type_of() so that it takes an additional argument representing an offset of the swap header within the partition represented by its first argument. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 2 +- kernel/power/swap.c | 2 +- kernel/power/user.c | 5 +++-- mm/swapfile.c | 38 ++++++++++++++++++++++++++------------ 4 files changed, 31 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/include/linux/swap.h b/include/linux/swap.h index 89f8a39773bf..d51e35e4e168 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -247,7 +247,7 @@ extern int swap_duplicate(swp_entry_t); extern int valid_swaphandles(swp_entry_t, unsigned long *); extern void swap_free(swp_entry_t); extern void free_swap_and_cache(swp_entry_t); -extern int swap_type_of(dev_t); +extern int swap_type_of(dev_t, sector_t); extern unsigned int count_swap_pages(int, int); extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); extern struct swap_info_struct *get_swap_info_struct(unsigned); diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 1a3b0dd2c3fc..7b10da16389e 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -74,7 +74,7 @@ static int mark_swapfiles(swp_entry_t start) static int swsusp_swap_check(void) /* This is called before saving image */ { - int res = swap_type_of(swsusp_resume_device); + int res = swap_type_of(swsusp_resume_device, 0); if (res >= 0) { root_swap = res; diff --git a/kernel/power/user.c b/kernel/power/user.c index 4c24ca5d62e3..a327b18a5ffd 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -55,7 +55,8 @@ static int snapshot_open(struct inode *inode, struct file *filp) filp->private_data = data; memset(&data->handle, 0, sizeof(struct snapshot_handle)); if ((filp->f_flags & O_ACCMODE) == O_RDONLY) { - data->swap = swsusp_resume_device ? swap_type_of(swsusp_resume_device) : -1; + data->swap = swsusp_resume_device ? + swap_type_of(swsusp_resume_device, 0) : -1; data->mode = O_RDONLY; } else { data->swap = -1; @@ -265,7 +266,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, * so we need to recode them */ if (old_decode_dev(arg)) { - data->swap = swap_type_of(old_decode_dev(arg)); + data->swap = swap_type_of(old_decode_dev(arg), 0); if (data->swap < 0) error = -ENODEV; } else { diff --git a/mm/swapfile.c b/mm/swapfile.c index f315131db006..2bfacbac0f4c 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -427,34 +427,48 @@ void free_swap_and_cache(swp_entry_t entry) #ifdef CONFIG_SOFTWARE_SUSPEND /* - * Find the swap type that corresponds to given device (if any) + * Find the swap type that corresponds to given device (if any). * - * This is needed for software suspend and is done in such a way that inode - * aliasing is allowed. + * @offset - number of the PAGE_SIZE-sized block of the device, starting + * from 0, in which the swap header is expected to be located. + * + * This is needed for the suspend to disk (aka swsusp). */ -int swap_type_of(dev_t device) +int swap_type_of(dev_t device, sector_t offset) { + struct block_device *bdev = NULL; int i; + if (device) + bdev = bdget(device); + spin_lock(&swap_lock); for (i = 0; i < nr_swapfiles; i++) { - struct inode *inode; + struct swap_info_struct *sis = swap_info + i; - if (!(swap_info[i].flags & SWP_WRITEOK)) + if (!(sis->flags & SWP_WRITEOK)) continue; - if (!device) { + if (!bdev) { spin_unlock(&swap_lock); return i; } - inode = swap_info[i].swap_file->f_dentry->d_inode; - if (S_ISBLK(inode->i_mode) && - device == MKDEV(imajor(inode), iminor(inode))) { - spin_unlock(&swap_lock); - return i; + if (bdev == sis->bdev) { + struct swap_extent *se; + + se = list_entry(sis->extent_list.next, + struct swap_extent, list); + if (se->start_block == offset) { + spin_unlock(&swap_lock); + bdput(bdev); + return i; + } } } spin_unlock(&swap_lock); + if (bdev) + bdput(bdev); + return -ENODEV; } -- cgit v1.2.3 From 3aef83e0ef1ffb8ea3bea97be46821a45c952173 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 6 Dec 2006 20:34:10 -0800 Subject: [PATCH] swsusp: use block device offsets to identify swap locations Make swsusp use block device offsets instead of swap offsets to identify swap locations and make it use the same code paths for writing as well as for reading data. This allows us to use the same code for handling swap files and swap partitions and to simplify the code, eg. by dropping rw_swap_page_sync(). Signed-off-by: Rafael J. Wysocki Cc: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 3 +- kernel/power/power.h | 2 +- kernel/power/swap.c | 133 ++++++++++++++++++++++++++------------------------ kernel/power/swsusp.c | 10 ++-- kernel/power/user.c | 7 +-- mm/page_io.c | 45 ----------------- mm/swapfile.c | 17 +++++++ 7 files changed, 98 insertions(+), 119 deletions(-) (limited to 'include/linux') diff --git a/include/linux/swap.h b/include/linux/swap.h index d51e35e4e168..add51cebc8d9 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -218,8 +218,6 @@ extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *); /* linux/mm/page_io.c */ extern int swap_readpage(struct file *, struct page *); extern int swap_writepage(struct page *page, struct writeback_control *wbc); -extern int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page, - struct bio **bio_chain); extern int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err); /* linux/mm/swap_state.c */ @@ -250,6 +248,7 @@ extern void free_swap_and_cache(swp_entry_t); extern int swap_type_of(dev_t, sector_t); extern unsigned int count_swap_pages(int, int); extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); +extern sector_t swapdev_block(int, pgoff_t); extern struct swap_info_struct *get_swap_info_struct(unsigned); extern int can_share_swap_page(struct page *); extern int remove_exclusive_swap_page(struct page *); diff --git a/kernel/power/power.h b/kernel/power/power.h index 87ecb1856ee8..210ebba26020 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -146,7 +146,7 @@ struct bitmap_page { extern void free_bitmap(struct bitmap_page *bitmap); extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits); -extern unsigned long alloc_swap_page(int swap, struct bitmap_page *bitmap); +extern sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap); extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap); extern int swsusp_check(void); diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 7768c2ba7550..1b08f46bbb7e 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -34,8 +34,8 @@ extern char resume_file[]; #define SWSUSP_SIG "S1SUSPEND" static struct swsusp_header { - char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)]; - swp_entry_t image; + char reserved[PAGE_SIZE - 20 - sizeof(sector_t)]; + sector_t image; char orig_sig[10]; char sig[10]; } __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header; @@ -100,9 +100,9 @@ static int bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain) return submit(READ, page_off, virt_to_page(addr), bio_chain); } -static int bio_write_page(pgoff_t page_off, void *addr) +static int bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain) { - return submit(WRITE, page_off, virt_to_page(addr), NULL); + return submit(WRITE, page_off, virt_to_page(addr), bio_chain); } static int wait_on_bio_chain(struct bio **bio_chain) @@ -157,22 +157,19 @@ static void show_speed(struct timeval *start, struct timeval *stop, * Saving part */ -static int mark_swapfiles(swp_entry_t start) +static int mark_swapfiles(sector_t start) { int error; - rw_swap_page_sync(READ, swp_entry(root_swap, 0), - virt_to_page((unsigned long)&swsusp_header), NULL); + bio_read_page(0, &swsusp_header, NULL); if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); memcpy(swsusp_header.sig,SWSUSP_SIG, 10); swsusp_header.image = start; - error = rw_swap_page_sync(WRITE, swp_entry(root_swap, 0), - virt_to_page((unsigned long)&swsusp_header), - NULL); + error = bio_write_page(0, &swsusp_header, NULL); } else { - pr_debug("swsusp: Partition is not swap space.\n"); + printk(KERN_ERR "swsusp: Swap header not found!\n"); error = -ENODEV; } return error; @@ -185,12 +182,21 @@ static int mark_swapfiles(swp_entry_t start) static int swsusp_swap_check(void) /* This is called before saving image */ { - int res = swap_type_of(swsusp_resume_device, 0); + int res; + + res = swap_type_of(swsusp_resume_device, 0); + if (res < 0) + return res; + + root_swap = res; + resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_WRITE); + if (IS_ERR(resume_bdev)) + return PTR_ERR(resume_bdev); + + res = set_blocksize(resume_bdev, PAGE_SIZE); + if (res < 0) + blkdev_put(resume_bdev); - if (res >= 0) { - root_swap = res; - return 0; - } return res; } @@ -201,36 +207,26 @@ static int swsusp_swap_check(void) /* This is called before saving image */ * @bio_chain: Link the next write BIO here */ -static int write_page(void *buf, unsigned long offset, struct bio **bio_chain) +static int write_page(void *buf, sector_t offset, struct bio **bio_chain) { - swp_entry_t entry; - int error = -ENOSPC; - - if (offset) { - struct page *page = virt_to_page(buf); - - if (bio_chain) { - /* - * Whether or not we successfully allocated a copy page, - * we take a ref on the page here. It gets undone in - * wait_on_bio_chain(). - */ - struct page *page_copy; - page_copy = alloc_page(GFP_ATOMIC); - if (page_copy == NULL) { - WARN_ON_ONCE(1); - bio_chain = NULL; /* Go synchronous */ - get_page(page); - } else { - memcpy(page_address(page_copy), - page_address(page), PAGE_SIZE); - page = page_copy; - } + void *src; + + if (!offset) + return -ENOSPC; + + if (bio_chain) { + src = (void *)__get_free_page(GFP_ATOMIC); + if (src) { + memcpy(src, buf, PAGE_SIZE); + } else { + WARN_ON_ONCE(1); + bio_chain = NULL; /* Go synchronous */ + src = buf; } - entry = swp_entry(root_swap, offset); - error = rw_swap_page_sync(WRITE, entry, page, bio_chain); + } else { + src = buf; } - return error; + return bio_write_page(offset, src, bio_chain); } /* @@ -248,11 +244,11 @@ static int write_page(void *buf, unsigned long offset, struct bio **bio_chain) * at a time. */ -#define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(long) - 1) +#define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(sector_t) - 1) struct swap_map_page { - unsigned long entries[MAP_PAGE_ENTRIES]; - unsigned long next_swap; + sector_t entries[MAP_PAGE_ENTRIES]; + sector_t next_swap; }; /** @@ -262,7 +258,7 @@ struct swap_map_page { struct swap_map_handle { struct swap_map_page *cur; - unsigned long cur_swap; + sector_t cur_swap; struct bitmap_page *bitmap; unsigned int k; }; @@ -287,7 +283,7 @@ static int get_swap_writer(struct swap_map_handle *handle) release_swap_writer(handle); return -ENOMEM; } - handle->cur_swap = alloc_swap_page(root_swap, handle->bitmap); + handle->cur_swap = alloc_swapdev_block(root_swap, handle->bitmap); if (!handle->cur_swap) { release_swap_writer(handle); return -ENOSPC; @@ -300,11 +296,11 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, struct bio **bio_chain) { int error = 0; - unsigned long offset; + sector_t offset; if (!handle->cur) return -EINVAL; - offset = alloc_swap_page(root_swap, handle->bitmap); + offset = alloc_swapdev_block(root_swap, handle->bitmap); error = write_page(buf, offset, bio_chain); if (error) return error; @@ -313,7 +309,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, error = wait_on_bio_chain(bio_chain); if (error) goto out; - offset = alloc_swap_page(root_swap, handle->bitmap); + offset = alloc_swapdev_block(root_swap, handle->bitmap); if (!offset) return -ENOSPC; handle->cur->next_swap = offset; @@ -413,37 +409,47 @@ int swsusp_write(void) struct swsusp_info *header; int error; - if ((error = swsusp_swap_check())) { + error = swsusp_swap_check(); + if (error) { printk(KERN_ERR "swsusp: Cannot find swap device, try " "swapon -a.\n"); return error; } memset(&snapshot, 0, sizeof(struct snapshot_handle)); error = snapshot_read_next(&snapshot, PAGE_SIZE); - if (error < PAGE_SIZE) - return error < 0 ? error : -EFAULT; + if (error < PAGE_SIZE) { + if (error >= 0) + error = -EFAULT; + + goto out; + } header = (struct swsusp_info *)data_of(snapshot); if (!enough_swap(header->pages)) { printk(KERN_ERR "swsusp: Not enough free swap\n"); - return -ENOSPC; + error = -ENOSPC; + goto out; } error = get_swap_writer(&handle); if (!error) { - unsigned long start = handle.cur_swap; + sector_t start = handle.cur_swap; + error = swap_write_page(&handle, header, NULL); if (!error) error = save_image(&handle, &snapshot, header->pages - 1); + if (!error) { flush_swap_writer(&handle); printk("S"); - error = mark_swapfiles(swp_entry(root_swap, start)); + error = mark_swapfiles(start); printk("|\n"); } } if (error) free_all_swap_pages(root_swap, handle.bitmap); release_swap_writer(&handle); +out: + swsusp_close(); return error; } @@ -459,17 +465,18 @@ static void release_swap_reader(struct swap_map_handle *handle) handle->cur = NULL; } -static int get_swap_reader(struct swap_map_handle *handle, - swp_entry_t start) +static int get_swap_reader(struct swap_map_handle *handle, sector_t start) { int error; - if (!swp_offset(start)) + if (!start) return -EINVAL; + handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC); if (!handle->cur) return -ENOMEM; - error = bio_read_page(swp_offset(start), handle->cur, NULL); + + error = bio_read_page(start, handle->cur, NULL); if (error) { release_swap_reader(handle); return error; @@ -481,7 +488,7 @@ static int get_swap_reader(struct swap_map_handle *handle, static int swap_read_page(struct swap_map_handle *handle, void *buf, struct bio **bio_chain) { - unsigned long offset; + sector_t offset; int error; if (!handle->cur) @@ -608,7 +615,7 @@ int swsusp_check(void) if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) { memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10); /* Reset swap signature now */ - error = bio_write_page(0, &swsusp_header); + error = bio_write_page(0, &swsusp_header, NULL); } else { return -EINVAL; } diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 0b66659dc516..4147a756a8c7 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -134,18 +134,18 @@ static int bitmap_set(struct bitmap_page *bitmap, unsigned long bit) return 0; } -unsigned long alloc_swap_page(int swap, struct bitmap_page *bitmap) +sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap) { unsigned long offset; offset = swp_offset(get_swap_page_of_type(swap)); if (offset) { - if (bitmap_set(bitmap, offset)) { + if (bitmap_set(bitmap, offset)) swap_free(swp_entry(swap, offset)); - offset = 0; - } + else + return swapdev_block(swap, offset); } - return offset; + return 0; } void free_all_swap_pages(int swap, struct bitmap_page *bitmap) diff --git a/kernel/power/user.c b/kernel/power/user.c index a327b18a5ffd..f0b7ef8bdd74 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -126,7 +126,8 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, { int error = 0; struct snapshot_data *data; - loff_t offset, avail; + loff_t avail; + sector_t offset; if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC) return -ENOTTY; @@ -240,10 +241,10 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, break; } } - offset = alloc_swap_page(data->swap, data->bitmap); + offset = alloc_swapdev_block(data->swap, data->bitmap); if (offset) { offset <<= PAGE_SHIFT; - error = put_user(offset, (loff_t __user *)arg); + error = put_user(offset, (sector_t __user *)arg); } else { error = -ENOSPC; } diff --git a/mm/page_io.c b/mm/page_io.c index d4840ecbf8f9..dbffec0d78c9 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -147,48 +147,3 @@ int swap_readpage(struct file *file, struct page *page) out: return ret; } - -#ifdef CONFIG_SOFTWARE_SUSPEND -/* - * A scruffy utility function to read or write an arbitrary swap page - * and wait on the I/O. The caller must have a ref on the page. - * - * We use end_swap_bio_read() even for writes, because it happens to do what - * we want. - */ -int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page, - struct bio **bio_chain) -{ - struct bio *bio; - int ret = 0; - int bio_rw; - - lock_page(page); - - bio = get_swap_bio(GFP_KERNEL, entry.val, page, end_swap_bio_read); - if (bio == NULL) { - unlock_page(page); - ret = -ENOMEM; - goto out; - } - - bio_rw = rw; - if (!bio_chain) - bio_rw |= (1 << BIO_RW_SYNC); - if (bio_chain) - bio_get(bio); - submit_bio(bio_rw, bio); - if (bio_chain == NULL) { - wait_on_page_locked(page); - - if (!PageUptodate(page) || PageError(page)) - ret = -EIO; - } - if (bio_chain) { - bio->bi_private = *bio_chain; - *bio_chain = bio; - } -out: - return ret; -} -#endif diff --git a/mm/swapfile.c b/mm/swapfile.c index 2bfacbac0f4c..55242363de64 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -945,6 +945,23 @@ sector_t map_swap_page(struct swap_info_struct *sis, pgoff_t offset) } } +#ifdef CONFIG_SOFTWARE_SUSPEND +/* + * Get the (PAGE_SIZE) block corresponding to given offset on the swapdev + * corresponding to given index in swap_info (swap type). + */ +sector_t swapdev_block(int swap_type, pgoff_t offset) +{ + struct swap_info_struct *sis; + + if (swap_type >= nr_swapfiles) + return 0; + + sis = swap_info + swap_type; + return (sis->flags & SWP_WRITEOK) ? map_swap_page(sis, offset) : 0; +} +#endif /* CONFIG_SOFTWARE_SUSPEND */ + /* * Free all of a swapdev's extent information */ -- cgit v1.2.3 From 8357376d3df21b7d6f857931a57ac50da9c66e26 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 6 Dec 2006 20:34:18 -0800 Subject: [PATCH] swsusp: Improve handling of highmem Currently swsusp saves the contents of highmem pages by copying them to the normal zone which is quite inefficient (eg. it requires two normal pages to be used for saving one highmem page). This may be improved by using highmem for saving the contents of saveable highmem pages. Namely, during the suspend phase of the suspend-resume cycle we try to allocate as many free highmem pages as there are saveable highmem pages. If there are not enough highmem image pages to store the contents of all of the saveable highmem pages, some of them will be stored in the "normal" memory. Next, we allocate as many free "normal" pages as needed to store the (remaining) image data. We use a memory bitmap to mark the allocated free pages (ie. highmem as well as "normal" image pages). Now, we use another memory bitmap to mark all of the saveable pages (highmem as well as "normal") and the contents of the saveable pages are copied into the image pages. Then, the second bitmap is used to save the pfns corresponding to the saveable pages and the first one is used to save their data. During the resume phase the pfns of the pages that were saveable during the suspend are loaded from the image and used to mark the "unsafe" page frames. Next, we try to allocate as many free highmem page frames as to load all of the image data that had been in the highmem before the suspend and we allocate so many free "normal" page frames that the total number of allocated free pages (highmem and "normal") is equal to the size of the image. While doing this we have to make sure that there will be some extra free "normal" and "safe" page frames for two lists of PBEs constructed later. Now, the image data are loaded, if possible, into their "original" page frames. The image data that cannot be written into their "original" page frames are loaded into "safe" page frames and their "original" kernel virtual addresses, as well as the addresses of the "safe" pages containing their copies, are stored in one of two lists of PBEs. One list of PBEs is for the copies of "normal" suspend pages (ie. "normal" pages that were saveable during the suspend) and it is used in the same way as previously (ie. by the architecture-dependent parts of swsusp). The other list of PBEs is for the copies of highmem suspend pages. The pages in this list are restored (in a reversible way) right before the arch-dependent code is called. Signed-off-by: Rafael J. Wysocki Cc: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/suspend.h | 9 +- kernel/power/power.h | 2 +- kernel/power/snapshot.c | 851 ++++++++++++++++++++++++++++++++++++------------ kernel/power/swap.c | 2 +- kernel/power/swsusp.c | 53 +-- kernel/power/user.c | 2 +- mm/vmscan.c | 3 + 7 files changed, 680 insertions(+), 242 deletions(-) (limited to 'include/linux') diff --git a/include/linux/suspend.h b/include/linux/suspend.h index b1237f16ecde..bf99bd49f8ef 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -9,10 +9,13 @@ #include #include -/* page backup entry */ +/* struct pbe is used for creating lists of pages that should be restored + * atomically during the resume from disk, because the page frames they have + * occupied before the suspend are in use. + */ struct pbe { - unsigned long address; /* address of the copy */ - unsigned long orig_address; /* original address of page */ + void *address; /* address of the copy */ + void *orig_address; /* original address of a page */ struct pbe *next; }; diff --git a/kernel/power/power.h b/kernel/power/power.h index 7dbfd9f67e1c..3763343bde2f 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -103,8 +103,8 @@ struct snapshot_handle { extern unsigned int snapshot_additional_pages(struct zone *zone); extern int snapshot_read_next(struct snapshot_handle *handle, size_t count); extern int snapshot_write_next(struct snapshot_handle *handle, size_t count); +extern void snapshot_write_finalize(struct snapshot_handle *handle); extern int snapshot_image_loaded(struct snapshot_handle *handle); -extern void snapshot_free_unused_memory(struct snapshot_handle *handle); /* * This structure is used to pass the values needed for the identification diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 99f9b7d177d6..fd8251d40eb8 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1,15 +1,15 @@ /* * linux/kernel/power/snapshot.c * - * This file provide system snapshot/restore functionality. + * This file provides system snapshot/restore functionality for swsusp. * * Copyright (C) 1998-2005 Pavel Machek + * Copyright (C) 2006 Rafael J. Wysocki * - * This file is released under the GPLv2, and is based on swsusp.c. + * This file is released under the GPLv2. * */ - #include #include #include @@ -34,137 +34,24 @@ #include "power.h" -/* List of PBEs used for creating and restoring the suspend image */ +/* List of PBEs needed for restoring the pages that were allocated before + * the suspend and included in the suspend image, but have also been + * allocated by the "resume" kernel, so their contents cannot be written + * directly to their "original" page frames. + */ struct pbe *restore_pblist; -static unsigned int nr_copy_pages; -static unsigned int nr_meta_pages; +/* Pointer to an auxiliary buffer (1 page) */ static void *buffer; -#ifdef CONFIG_HIGHMEM -unsigned int count_highmem_pages(void) -{ - struct zone *zone; - unsigned long zone_pfn; - unsigned int n = 0; - - for_each_zone (zone) - if (is_highmem(zone)) { - mark_free_pages(zone); - for (zone_pfn = 0; zone_pfn < zone->spanned_pages; zone_pfn++) { - struct page *page; - unsigned long pfn = zone_pfn + zone->zone_start_pfn; - if (!pfn_valid(pfn)) - continue; - page = pfn_to_page(pfn); - if (PageReserved(page)) - continue; - if (PageNosaveFree(page)) - continue; - n++; - } - } - return n; -} - -struct highmem_page { - char *data; - struct page *page; - struct highmem_page *next; -}; - -static struct highmem_page *highmem_copy; - -static int save_highmem_zone(struct zone *zone) -{ - unsigned long zone_pfn; - mark_free_pages(zone); - for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { - struct page *page; - struct highmem_page *save; - void *kaddr; - unsigned long pfn = zone_pfn + zone->zone_start_pfn; - - if (!(pfn%10000)) - printk("."); - if (!pfn_valid(pfn)) - continue; - page = pfn_to_page(pfn); - /* - * This condition results from rvmalloc() sans vmalloc_32() - * and architectural memory reservations. This should be - * corrected eventually when the cases giving rise to this - * are better understood. - */ - if (PageReserved(page)) - continue; - BUG_ON(PageNosave(page)); - if (PageNosaveFree(page)) - continue; - save = kmalloc(sizeof(struct highmem_page), GFP_ATOMIC); - if (!save) - return -ENOMEM; - save->next = highmem_copy; - save->page = page; - save->data = (void *) get_zeroed_page(GFP_ATOMIC); - if (!save->data) { - kfree(save); - return -ENOMEM; - } - kaddr = kmap_atomic(page, KM_USER0); - memcpy(save->data, kaddr, PAGE_SIZE); - kunmap_atomic(kaddr, KM_USER0); - highmem_copy = save; - } - return 0; -} - -int save_highmem(void) -{ - struct zone *zone; - int res = 0; - - pr_debug("swsusp: Saving Highmem"); - drain_local_pages(); - for_each_zone (zone) { - if (is_highmem(zone)) - res = save_highmem_zone(zone); - if (res) - return res; - } - printk("\n"); - return 0; -} - -int restore_highmem(void) -{ - printk("swsusp: Restoring Highmem\n"); - while (highmem_copy) { - struct highmem_page *save = highmem_copy; - void *kaddr; - highmem_copy = save->next; - - kaddr = kmap_atomic(save->page, KM_USER0); - memcpy(kaddr, save->data, PAGE_SIZE); - kunmap_atomic(kaddr, KM_USER0); - free_page((long) save->data); - kfree(save); - } - return 0; -} -#else -static inline unsigned int count_highmem_pages(void) {return 0;} -static inline int save_highmem(void) {return 0;} -static inline int restore_highmem(void) {return 0;} -#endif - /** * @safe_needed - on resume, for storing the PBE list and the image, * we can only use memory pages that do not conflict with the pages - * used before suspend. + * used before suspend. The unsafe pages have PageNosaveFree set + * and we count them using unsafe_pages. * - * The unsafe pages are marked with the PG_nosave_free flag - * and we count them using unsafe_pages + * Each allocated image page is marked as PageNosave and PageNosaveFree + * so that swsusp_free() can release it. */ #define PG_ANY 0 @@ -174,7 +61,7 @@ static inline int restore_highmem(void) {return 0;} static unsigned int allocated_unsafe_pages; -static void *alloc_image_page(gfp_t gfp_mask, int safe_needed) +static void *get_image_page(gfp_t gfp_mask, int safe_needed) { void *res; @@ -195,20 +82,38 @@ static void *alloc_image_page(gfp_t gfp_mask, int safe_needed) unsigned long get_safe_page(gfp_t gfp_mask) { - return (unsigned long)alloc_image_page(gfp_mask, PG_SAFE); + return (unsigned long)get_image_page(gfp_mask, PG_SAFE); +} + +static struct page *alloc_image_page(gfp_t gfp_mask) { + struct page *page; + + page = alloc_page(gfp_mask); + if (page) { + SetPageNosave(page); + SetPageNosaveFree(page); + } + return page; } /** * free_image_page - free page represented by @addr, allocated with - * alloc_image_page (page flags set by it must be cleared) + * get_image_page (page flags set by it must be cleared) */ static inline void free_image_page(void *addr, int clear_nosave_free) { - ClearPageNosave(virt_to_page(addr)); + struct page *page; + + BUG_ON(!virt_addr_valid(addr)); + + page = virt_to_page(addr); + + ClearPageNosave(page); if (clear_nosave_free) - ClearPageNosaveFree(virt_to_page(addr)); - free_page((unsigned long)addr); + ClearPageNosaveFree(page); + + __free_page(page); } /* struct linked_page is used to build chains of pages */ @@ -269,7 +174,7 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size) if (LINKED_PAGE_DATA_SIZE - ca->used_space < size) { struct linked_page *lp; - lp = alloc_image_page(ca->gfp_mask, ca->safe_needed); + lp = get_image_page(ca->gfp_mask, ca->safe_needed); if (!lp) return NULL; @@ -446,8 +351,8 @@ memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed) /* Compute the number of zones */ nr = 0; - for_each_zone (zone) - if (populated_zone(zone) && !is_highmem(zone)) + for_each_zone(zone) + if (populated_zone(zone)) nr++; /* Allocate the list of zones bitmap objects */ @@ -459,10 +364,10 @@ memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed) } /* Initialize the zone bitmap objects */ - for_each_zone (zone) { + for_each_zone(zone) { unsigned long pfn; - if (!populated_zone(zone) || is_highmem(zone)) + if (!populated_zone(zone)) continue; zone_bm->start_pfn = zone->zone_start_pfn; @@ -481,7 +386,7 @@ memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed) while (bb) { unsigned long *ptr; - ptr = alloc_image_page(gfp_mask, safe_needed); + ptr = get_image_page(gfp_mask, safe_needed); bb->data = ptr; if (!ptr) goto Free; @@ -669,9 +574,81 @@ unsigned int snapshot_additional_pages(struct zone *zone) res = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); res += DIV_ROUND_UP(res * sizeof(struct bm_block), PAGE_SIZE); - return res; + return 2 * res; } +#ifdef CONFIG_HIGHMEM +/** + * count_free_highmem_pages - compute the total number of free highmem + * pages, system-wide. + */ + +static unsigned int count_free_highmem_pages(void) +{ + struct zone *zone; + unsigned int cnt = 0; + + for_each_zone(zone) + if (populated_zone(zone) && is_highmem(zone)) + cnt += zone->free_pages; + + return cnt; +} + +/** + * saveable_highmem_page - Determine whether a highmem page should be + * included in the suspend image. + * + * We should save the page if it isn't Nosave or NosaveFree, or Reserved, + * and it isn't a part of a free chunk of pages. + */ + +static struct page *saveable_highmem_page(unsigned long pfn) +{ + struct page *page; + + if (!pfn_valid(pfn)) + return NULL; + + page = pfn_to_page(pfn); + + BUG_ON(!PageHighMem(page)); + + if (PageNosave(page) || PageReserved(page) || PageNosaveFree(page)) + return NULL; + + return page; +} + +/** + * count_highmem_pages - compute the total number of saveable highmem + * pages. + */ + +unsigned int count_highmem_pages(void) +{ + struct zone *zone; + unsigned int n = 0; + + for_each_zone(zone) { + unsigned long pfn, max_zone_pfn; + + if (!is_highmem(zone)) + continue; + + mark_free_pages(zone); + max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; + for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) + if (saveable_highmem_page(pfn)) + n++; + } + return n; +} +#else +static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; } +static inline unsigned int count_highmem_pages(void) { return 0; } +#endif /* CONFIG_HIGHMEM */ + /** * pfn_is_nosave - check if given pfn is in the 'nosave' section */ @@ -684,12 +661,12 @@ static inline int pfn_is_nosave(unsigned long pfn) } /** - * saveable - Determine whether a page should be cloned or not. - * @pfn: The page + * saveable - Determine whether a non-highmem page should be included in + * the suspend image. * - * We save a page if it isn't Nosave, and is not in the range of pages - * statically defined as 'unsaveable', and it - * isn't a part of a free chunk of pages. + * We should save the page if it isn't Nosave, and is not in the range + * of pages statically defined as 'unsaveable', and it isn't a part of + * a free chunk of pages. */ static struct page *saveable_page(unsigned long pfn) @@ -701,76 +678,130 @@ static struct page *saveable_page(unsigned long pfn) page = pfn_to_page(pfn); - if (PageNosave(page)) + BUG_ON(PageHighMem(page)); + + if (PageNosave(page) || PageNosaveFree(page)) return NULL; + if (PageReserved(page) && pfn_is_nosave(pfn)) return NULL; - if (PageNosaveFree(page)) - return NULL; return page; } +/** + * count_data_pages - compute the total number of saveable non-highmem + * pages. + */ + unsigned int count_data_pages(void) { struct zone *zone; unsigned long pfn, max_zone_pfn; unsigned int n = 0; - for_each_zone (zone) { + for_each_zone(zone) { if (is_highmem(zone)) continue; + mark_free_pages(zone); max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) - n += !!saveable_page(pfn); + if(saveable_page(pfn)) + n++; } return n; } -static inline void copy_data_page(long *dst, long *src) +/* This is needed, because copy_page and memcpy are not usable for copying + * task structs. + */ +static inline void do_copy_page(long *dst, long *src) { int n; - /* copy_page and memcpy are not usable for copying task structs. */ for (n = PAGE_SIZE / sizeof(long); n; n--) *dst++ = *src++; } +#ifdef CONFIG_HIGHMEM +static inline struct page * +page_is_saveable(struct zone *zone, unsigned long pfn) +{ + return is_highmem(zone) ? + saveable_highmem_page(pfn) : saveable_page(pfn); +} + +static inline void +copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) +{ + struct page *s_page, *d_page; + void *src, *dst; + + s_page = pfn_to_page(src_pfn); + d_page = pfn_to_page(dst_pfn); + if (PageHighMem(s_page)) { + src = kmap_atomic(s_page, KM_USER0); + dst = kmap_atomic(d_page, KM_USER1); + do_copy_page(dst, src); + kunmap_atomic(src, KM_USER0); + kunmap_atomic(dst, KM_USER1); + } else { + src = page_address(s_page); + if (PageHighMem(d_page)) { + /* Page pointed to by src may contain some kernel + * data modified by kmap_atomic() + */ + do_copy_page(buffer, src); + dst = kmap_atomic(pfn_to_page(dst_pfn), KM_USER0); + memcpy(dst, buffer, PAGE_SIZE); + kunmap_atomic(dst, KM_USER0); + } else { + dst = page_address(d_page); + do_copy_page(dst, src); + } + } +} +#else +#define page_is_saveable(zone, pfn) saveable_page(pfn) + +static inline void +copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) +{ + do_copy_page(page_address(pfn_to_page(dst_pfn)), + page_address(pfn_to_page(src_pfn))); +} +#endif /* CONFIG_HIGHMEM */ + static void copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm) { struct zone *zone; unsigned long pfn; - for_each_zone (zone) { + for_each_zone(zone) { unsigned long max_zone_pfn; - if (is_highmem(zone)) - continue; - mark_free_pages(zone); max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) - if (saveable_page(pfn)) + if (page_is_saveable(zone, pfn)) memory_bm_set_bit(orig_bm, pfn); } memory_bm_position_reset(orig_bm); memory_bm_position_reset(copy_bm); do { pfn = memory_bm_next_pfn(orig_bm); - if (likely(pfn != BM_END_OF_MAP)) { - struct page *page; - void *src; - - page = pfn_to_page(pfn); - src = page_address(page); - page = pfn_to_page(memory_bm_next_pfn(copy_bm)); - copy_data_page(page_address(page), src); - } + if (likely(pfn != BM_END_OF_MAP)) + copy_data_page(memory_bm_next_pfn(copy_bm), pfn); } while (pfn != BM_END_OF_MAP); } +/* Total number of image pages */ +static unsigned int nr_copy_pages; +/* Number of pages needed for saving the original pfns of the image pages */ +static unsigned int nr_meta_pages; + /** * swsusp_free - free pages allocated for the suspend. * @@ -792,7 +823,7 @@ void swsusp_free(void) if (PageNosave(page) && PageNosaveFree(page)) { ClearPageNosave(page); ClearPageNosaveFree(page); - free_page((long) page_address(page)); + __free_page(page); } } } @@ -802,34 +833,108 @@ void swsusp_free(void) buffer = NULL; } +#ifdef CONFIG_HIGHMEM +/** + * count_pages_for_highmem - compute the number of non-highmem pages + * that will be necessary for creating copies of highmem pages. + */ + +static unsigned int count_pages_for_highmem(unsigned int nr_highmem) +{ + unsigned int free_highmem = count_free_highmem_pages(); + + if (free_highmem >= nr_highmem) + nr_highmem = 0; + else + nr_highmem -= free_highmem; + + return nr_highmem; +} +#else +static unsigned int +count_pages_for_highmem(unsigned int nr_highmem) { return 0; } +#endif /* CONFIG_HIGHMEM */ /** - * enough_free_mem - Make sure we enough free memory to snapshot. - * - * Returns TRUE or FALSE after checking the number of available - * free pages. + * enough_free_mem - Make sure we have enough free memory for the + * snapshot image. */ -static int enough_free_mem(unsigned int nr_pages) +static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem) { struct zone *zone; unsigned int free = 0, meta = 0; - for_each_zone (zone) - if (!is_highmem(zone)) { + for_each_zone(zone) { + meta += snapshot_additional_pages(zone); + if (!is_highmem(zone)) free += zone->free_pages; - meta += snapshot_additional_pages(zone); - } + } - pr_debug("swsusp: pages needed: %u + %u + %u, available pages: %u\n", + nr_pages += count_pages_for_highmem(nr_highmem); + pr_debug("swsusp: Normal pages needed: %u + %u + %u, available pages: %u\n", nr_pages, PAGES_FOR_IO, meta, free); return free > nr_pages + PAGES_FOR_IO + meta; } +#ifdef CONFIG_HIGHMEM +/** + * get_highmem_buffer - if there are some highmem pages in the suspend + * image, we may need the buffer to copy them and/or load their data. + */ + +static inline int get_highmem_buffer(int safe_needed) +{ + buffer = get_image_page(GFP_ATOMIC | __GFP_COLD, safe_needed); + return buffer ? 0 : -ENOMEM; +} + +/** + * alloc_highmem_image_pages - allocate some highmem pages for the image. + * Try to allocate as many pages as needed, but if the number of free + * highmem pages is lesser than that, allocate them all. + */ + +static inline unsigned int +alloc_highmem_image_pages(struct memory_bitmap *bm, unsigned int nr_highmem) +{ + unsigned int to_alloc = count_free_highmem_pages(); + + if (to_alloc > nr_highmem) + to_alloc = nr_highmem; + + nr_highmem -= to_alloc; + while (to_alloc-- > 0) { + struct page *page; + + page = alloc_image_page(__GFP_HIGHMEM); + memory_bm_set_bit(bm, page_to_pfn(page)); + } + return nr_highmem; +} +#else +static inline int get_highmem_buffer(int safe_needed) { return 0; } + +static inline unsigned int +alloc_highmem_image_pages(struct memory_bitmap *bm, unsigned int n) { return 0; } +#endif /* CONFIG_HIGHMEM */ + +/** + * swsusp_alloc - allocate memory for the suspend image + * + * We first try to allocate as many highmem pages as there are + * saveable highmem pages in the system. If that fails, we allocate + * non-highmem pages for the copies of the remaining highmem ones. + * + * In this approach it is likely that the copies of highmem pages will + * also be located in the high memory, because of the way in which + * copy_data_pages() works. + */ + static int swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm, - unsigned int nr_pages) + unsigned int nr_pages, unsigned int nr_highmem) { int error; @@ -841,13 +946,19 @@ swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm, if (error) goto Free; + if (nr_highmem > 0) { + error = get_highmem_buffer(PG_ANY); + if (error) + goto Free; + + nr_pages += alloc_highmem_image_pages(copy_bm, nr_highmem); + } while (nr_pages-- > 0) { - struct page *page = alloc_page(GFP_ATOMIC | __GFP_COLD); + struct page *page = alloc_image_page(GFP_ATOMIC | __GFP_COLD); + if (!page) goto Free; - SetPageNosave(page); - SetPageNosaveFree(page); memory_bm_set_bit(copy_bm, page_to_pfn(page)); } return 0; @@ -857,30 +968,39 @@ Free: return -ENOMEM; } -/* Memory bitmap used for marking saveable pages */ +/* Memory bitmap used for marking saveable pages (during suspend) or the + * suspend image pages (during resume) + */ static struct memory_bitmap orig_bm; -/* Memory bitmap used for marking allocated pages that will contain the copies - * of saveable pages +/* Memory bitmap used on suspend for marking allocated pages that will contain + * the copies of saveable pages. During resume it is initially used for + * marking the suspend image pages, but then its set bits are duplicated in + * @orig_bm and it is released. Next, on systems with high memory, it may be + * used for marking "safe" highmem pages, but it has to be reinitialized for + * this purpose. */ static struct memory_bitmap copy_bm; asmlinkage int swsusp_save(void) { - unsigned int nr_pages; + unsigned int nr_pages, nr_highmem; - pr_debug("swsusp: critical section: \n"); + printk("swsusp: critical section: \n"); drain_local_pages(); nr_pages = count_data_pages(); - printk("swsusp: Need to copy %u pages\n", nr_pages); + nr_highmem = count_highmem_pages(); + printk("swsusp: Need to copy %u pages\n", nr_pages + nr_highmem); - if (!enough_free_mem(nr_pages)) { + if (!enough_free_mem(nr_pages, nr_highmem)) { printk(KERN_ERR "swsusp: Not enough free memory\n"); return -ENOMEM; } - if (swsusp_alloc(&orig_bm, ©_bm, nr_pages)) + if (swsusp_alloc(&orig_bm, ©_bm, nr_pages, nr_highmem)) { + printk(KERN_ERR "swsusp: Memory allocation failed\n"); return -ENOMEM; + } /* During allocating of suspend pagedir, new cold pages may appear. * Kill them. @@ -894,10 +1014,12 @@ asmlinkage int swsusp_save(void) * touch swap space! Except we must write out our image of course. */ + nr_pages += nr_highmem; nr_copy_pages = nr_pages; - nr_meta_pages = (nr_pages * sizeof(long) + PAGE_SIZE - 1) >> PAGE_SHIFT; + nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE); printk("swsusp: critical section/: done (%d pages copied)\n", nr_pages); + return 0; } @@ -960,7 +1082,7 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count) if (!buffer) { /* This makes the buffer be freed by swsusp_free() */ - buffer = alloc_image_page(GFP_ATOMIC, PG_ANY); + buffer = get_image_page(GFP_ATOMIC, PG_ANY); if (!buffer) return -ENOMEM; } @@ -975,9 +1097,23 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count) memset(buffer, 0, PAGE_SIZE); pack_pfns(buffer, &orig_bm); } else { - unsigned long pfn = memory_bm_next_pfn(©_bm); + struct page *page; - handle->buffer = page_address(pfn_to_page(pfn)); + page = pfn_to_page(memory_bm_next_pfn(©_bm)); + if (PageHighMem(page)) { + /* Highmem pages are copied to the buffer, + * because we can't return with a kmapped + * highmem page (we may not be called again). + */ + void *kaddr; + + kaddr = kmap_atomic(page, KM_USER0); + memcpy(buffer, kaddr, PAGE_SIZE); + kunmap_atomic(kaddr, KM_USER0); + handle->buffer = buffer; + } else { + handle->buffer = page_address(page); + } } handle->prev = handle->cur; } @@ -1005,7 +1141,7 @@ static int mark_unsafe_pages(struct memory_bitmap *bm) unsigned long pfn, max_zone_pfn; /* Clear page flags */ - for_each_zone (zone) { + for_each_zone(zone) { max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) if (pfn_valid(pfn)) @@ -1101,6 +1237,218 @@ unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) } } +/* List of "safe" pages that may be used to store data loaded from the suspend + * image + */ +static struct linked_page *safe_pages_list; + +#ifdef CONFIG_HIGHMEM +/* struct highmem_pbe is used for creating the list of highmem pages that + * should be restored atomically during the resume from disk, because the page + * frames they have occupied before the suspend are in use. + */ +struct highmem_pbe { + struct page *copy_page; /* data is here now */ + struct page *orig_page; /* data was here before the suspend */ + struct highmem_pbe *next; +}; + +/* List of highmem PBEs needed for restoring the highmem pages that were + * allocated before the suspend and included in the suspend image, but have + * also been allocated by the "resume" kernel, so their contents cannot be + * written directly to their "original" page frames. + */ +static struct highmem_pbe *highmem_pblist; + +/** + * count_highmem_image_pages - compute the number of highmem pages in the + * suspend image. The bits in the memory bitmap @bm that correspond to the + * image pages are assumed to be set. + */ + +static unsigned int count_highmem_image_pages(struct memory_bitmap *bm) +{ + unsigned long pfn; + unsigned int cnt = 0; + + memory_bm_position_reset(bm); + pfn = memory_bm_next_pfn(bm); + while (pfn != BM_END_OF_MAP) { + if (PageHighMem(pfn_to_page(pfn))) + cnt++; + + pfn = memory_bm_next_pfn(bm); + } + return cnt; +} + +/** + * prepare_highmem_image - try to allocate as many highmem pages as + * there are highmem image pages (@nr_highmem_p points to the variable + * containing the number of highmem image pages). The pages that are + * "safe" (ie. will not be overwritten when the suspend image is + * restored) have the corresponding bits set in @bm (it must be + * unitialized). + * + * NOTE: This function should not be called if there are no highmem + * image pages. + */ + +static unsigned int safe_highmem_pages; + +static struct memory_bitmap *safe_highmem_bm; + +static int +prepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p) +{ + unsigned int to_alloc; + + if (memory_bm_create(bm, GFP_ATOMIC, PG_SAFE)) + return -ENOMEM; + + if (get_highmem_buffer(PG_SAFE)) + return -ENOMEM; + + to_alloc = count_free_highmem_pages(); + if (to_alloc > *nr_highmem_p) + to_alloc = *nr_highmem_p; + else + *nr_highmem_p = to_alloc; + + safe_highmem_pages = 0; + while (to_alloc-- > 0) { + struct page *page; + + page = alloc_page(__GFP_HIGHMEM); + if (!PageNosaveFree(page)) { + /* The page is "safe", set its bit the bitmap */ + memory_bm_set_bit(bm, page_to_pfn(page)); + safe_highmem_pages++; + } + /* Mark the page as allocated */ + SetPageNosave(page); + SetPageNosaveFree(page); + } + memory_bm_position_reset(bm); + safe_highmem_bm = bm; + return 0; +} + +/** + * get_highmem_page_buffer - for given highmem image page find the buffer + * that suspend_write_next() should set for its caller to write to. + * + * If the page is to be saved to its "original" page frame or a copy of + * the page is to be made in the highmem, @buffer is returned. Otherwise, + * the copy of the page is to be made in normal memory, so the address of + * the copy is returned. + * + * If @buffer is returned, the caller of suspend_write_next() will write + * the page's contents to @buffer, so they will have to be copied to the + * right location on the next call to suspend_write_next() and it is done + * with the help of copy_last_highmem_page(). For this purpose, if + * @buffer is returned, @last_highmem page is set to the page to which + * the data will have to be copied from @buffer. + */ + +static struct page *last_highmem_page; + +static void * +get_highmem_page_buffer(struct page *page, struct chain_allocator *ca) +{ + struct highmem_pbe *pbe; + void *kaddr; + + if (PageNosave(page) && PageNosaveFree(page)) { + /* We have allocated the "original" page frame and we can + * use it directly to store the loaded page. + */ + last_highmem_page = page; + return buffer; + } + /* The "original" page frame has not been allocated and we have to + * use a "safe" page frame to store the loaded page. + */ + pbe = chain_alloc(ca, sizeof(struct highmem_pbe)); + if (!pbe) { + swsusp_free(); + return NULL; + } + pbe->orig_page = page; + if (safe_highmem_pages > 0) { + struct page *tmp; + + /* Copy of the page will be stored in high memory */ + kaddr = buffer; + tmp = pfn_to_page(memory_bm_next_pfn(safe_highmem_bm)); + safe_highmem_pages--; + last_highmem_page = tmp; + pbe->copy_page = tmp; + } else { + /* Copy of the page will be stored in normal memory */ + kaddr = safe_pages_list; + safe_pages_list = safe_pages_list->next; + pbe->copy_page = virt_to_page(kaddr); + } + pbe->next = highmem_pblist; + highmem_pblist = pbe; + return kaddr; +} + +/** + * copy_last_highmem_page - copy the contents of a highmem image from + * @buffer, where the caller of snapshot_write_next() has place them, + * to the right location represented by @last_highmem_page . + */ + +static void copy_last_highmem_page(void) +{ + if (last_highmem_page) { + void *dst; + + dst = kmap_atomic(last_highmem_page, KM_USER0); + memcpy(dst, buffer, PAGE_SIZE); + kunmap_atomic(dst, KM_USER0); + last_highmem_page = NULL; + } +} + +static inline int last_highmem_page_copied(void) +{ + return !last_highmem_page; +} + +static inline void free_highmem_data(void) +{ + if (safe_highmem_bm) + memory_bm_free(safe_highmem_bm, PG_UNSAFE_CLEAR); + + if (buffer) + free_image_page(buffer, PG_UNSAFE_CLEAR); +} +#else +static inline int get_safe_write_buffer(void) { return 0; } + +static unsigned int +count_highmem_image_pages(struct memory_bitmap *bm) { return 0; } + +static inline int +prepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p) +{ + return 0; +} + +static inline void * +get_highmem_page_buffer(struct page *page, struct chain_allocator *ca) +{ + return NULL; +} + +static inline void copy_last_highmem_page(void) {} +static inline int last_highmem_page_copied(void) { return 1; } +static inline void free_highmem_data(void) {} +#endif /* CONFIG_HIGHMEM */ + /** * prepare_image - use the memory bitmap @bm to mark the pages that will * be overwritten in the process of restoring the system memory state @@ -1110,20 +1458,25 @@ unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) * The idea is to allocate a new memory bitmap first and then allocate * as many pages as needed for the image data, but not to assign these * pages to specific tasks initially. Instead, we just mark them as - * allocated and create a list of "safe" pages that will be used later. + * allocated and create a lists of "safe" pages that will be used + * later. On systems with high memory a list of "safe" highmem pages is + * also created. */ #define PBES_PER_LINKED_PAGE (LINKED_PAGE_DATA_SIZE / sizeof(struct pbe)) -static struct linked_page *safe_pages_list; - static int prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) { - unsigned int nr_pages; + unsigned int nr_pages, nr_highmem; struct linked_page *sp_list, *lp; int error; + /* If there is no highmem, the buffer will not be necessary */ + free_image_page(buffer, PG_UNSAFE_CLEAR); + buffer = NULL; + + nr_highmem = count_highmem_image_pages(bm); error = mark_unsafe_pages(bm); if (error) goto Free; @@ -1134,6 +1487,11 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) duplicate_memory_bitmap(new_bm, bm); memory_bm_free(bm, PG_UNSAFE_KEEP); + if (nr_highmem > 0) { + error = prepare_highmem_image(bm, &nr_highmem); + if (error) + goto Free; + } /* Reserve some safe pages for potential later use. * * NOTE: This way we make sure there will be enough safe pages for the @@ -1142,10 +1500,10 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) */ sp_list = NULL; /* nr_copy_pages cannot be lesser than allocated_unsafe_pages */ - nr_pages = nr_copy_pages - allocated_unsafe_pages; + nr_pages = nr_copy_pages - nr_highmem - allocated_unsafe_pages; nr_pages = DIV_ROUND_UP(nr_pages, PBES_PER_LINKED_PAGE); while (nr_pages > 0) { - lp = alloc_image_page(GFP_ATOMIC, PG_SAFE); + lp = get_image_page(GFP_ATOMIC, PG_SAFE); if (!lp) { error = -ENOMEM; goto Free; @@ -1156,7 +1514,7 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) } /* Preallocate memory for the image */ safe_pages_list = NULL; - nr_pages = nr_copy_pages - allocated_unsafe_pages; + nr_pages = nr_copy_pages - nr_highmem - allocated_unsafe_pages; while (nr_pages > 0) { lp = (struct linked_page *)get_zeroed_page(GFP_ATOMIC); if (!lp) { @@ -1196,6 +1554,9 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) struct pbe *pbe; struct page *page = pfn_to_page(memory_bm_next_pfn(bm)); + if (PageHighMem(page)) + return get_highmem_page_buffer(page, ca); + if (PageNosave(page) && PageNosaveFree(page)) /* We have allocated the "original" page frame and we can * use it directly to store the loaded page. @@ -1210,12 +1571,12 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) swsusp_free(); return NULL; } - pbe->orig_address = (unsigned long)page_address(page); - pbe->address = (unsigned long)safe_pages_list; + pbe->orig_address = page_address(page); + pbe->address = safe_pages_list; safe_pages_list = safe_pages_list->next; pbe->next = restore_pblist; restore_pblist = pbe; - return (void *)pbe->address; + return pbe->address; } /** @@ -1249,14 +1610,16 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count) if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) return 0; - if (!buffer) { - /* This makes the buffer be freed by swsusp_free() */ - buffer = alloc_image_page(GFP_ATOMIC, PG_ANY); + if (handle->offset == 0) { + if (!buffer) + /* This makes the buffer be freed by swsusp_free() */ + buffer = get_image_page(GFP_ATOMIC, PG_ANY); + if (!buffer) return -ENOMEM; - } - if (!handle->offset) + handle->buffer = buffer; + } handle->sync_read = 1; if (handle->prev < handle->cur) { if (handle->prev == 0) { @@ -1284,8 +1647,10 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count) return -ENOMEM; } } else { + copy_last_highmem_page(); handle->buffer = get_buffer(&orig_bm, &ca); - handle->sync_read = 0; + if (handle->buffer != buffer) + handle->sync_read = 0; } handle->prev = handle->cur; } @@ -1301,15 +1666,73 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count) return count; } +/** + * snapshot_write_finalize - must be called after the last call to + * snapshot_write_next() in case the last page in the image happens + * to be a highmem page and its contents should be stored in the + * highmem. Additionally, it releases the memory that will not be + * used any more. + */ + +void snapshot_write_finalize(struct snapshot_handle *handle) +{ + copy_last_highmem_page(); + /* Free only if we have loaded the image entirely */ + if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) { + memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR); + free_highmem_data(); + } +} + int snapshot_image_loaded(struct snapshot_handle *handle) { - return !(!nr_copy_pages || + return !(!nr_copy_pages || !last_highmem_page_copied() || handle->cur <= nr_meta_pages + nr_copy_pages); } -void snapshot_free_unused_memory(struct snapshot_handle *handle) +#ifdef CONFIG_HIGHMEM +/* Assumes that @buf is ready and points to a "safe" page */ +static inline void +swap_two_pages_data(struct page *p1, struct page *p2, void *buf) { - /* Free only if we have loaded the image entirely */ - if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) - memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR); + void *kaddr1, *kaddr2; + + kaddr1 = kmap_atomic(p1, KM_USER0); + kaddr2 = kmap_atomic(p2, KM_USER1); + memcpy(buf, kaddr1, PAGE_SIZE); + memcpy(kaddr1, kaddr2, PAGE_SIZE); + memcpy(kaddr2, buf, PAGE_SIZE); + kunmap_atomic(kaddr1, KM_USER0); + kunmap_atomic(kaddr2, KM_USER1); +} + +/** + * restore_highmem - for each highmem page that was allocated before + * the suspend and included in the suspend image, and also has been + * allocated by the "resume" kernel swap its current (ie. "before + * resume") contents with the previous (ie. "before suspend") one. + * + * If the resume eventually fails, we can call this function once + * again and restore the "before resume" highmem state. + */ + +int restore_highmem(void) +{ + struct highmem_pbe *pbe = highmem_pblist; + void *buf; + + if (!pbe) + return 0; + + buf = get_image_page(GFP_ATOMIC, PG_SAFE); + if (!buf) + return -ENOMEM; + + while (pbe) { + swap_two_pages_data(pbe->copy_page, pbe->orig_page, buf); + pbe = pbe->next; + } + free_image_page(buf, PG_UNSAFE_CLEAR); + return 0; } +#endif /* CONFIG_HIGHMEM */ diff --git a/kernel/power/swap.c b/kernel/power/swap.c index aa5a9bff01f1..cbd187e90410 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -558,7 +558,7 @@ static int load_image(struct swap_map_handle *handle, error = err2; if (!error) { printk("\b\b\b\bdone\n"); - snapshot_free_unused_memory(snapshot); + snapshot_write_finalize(snapshot); if (!snapshot_image_loaded(snapshot)) error = -ENODATA; } diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 4147a756a8c7..68de5c1dbd78 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -64,10 +64,8 @@ int in_suspend __nosavedata = 0; #ifdef CONFIG_HIGHMEM unsigned int count_highmem_pages(void); -int save_highmem(void); int restore_highmem(void); #else -static inline int save_highmem(void) { return 0; } static inline int restore_highmem(void) { return 0; } static inline unsigned int count_highmem_pages(void) { return 0; } #endif @@ -184,7 +182,7 @@ static inline unsigned long __shrink_memory(long tmp) int swsusp_shrink_memory(void) { - long size, tmp; + long tmp; struct zone *zone; unsigned long pages = 0; unsigned int i = 0; @@ -192,15 +190,27 @@ int swsusp_shrink_memory(void) printk("Shrinking memory... "); do { - size = 2 * count_highmem_pages(); - size += size / 50 + count_data_pages() + PAGES_FOR_IO; + long size, highmem_size; + + highmem_size = count_highmem_pages(); + size = count_data_pages() + PAGES_FOR_IO; tmp = size; + size += highmem_size; for_each_zone (zone) - if (!is_highmem(zone) && populated_zone(zone)) { - tmp -= zone->free_pages; - tmp += zone->lowmem_reserve[ZONE_NORMAL]; - tmp += snapshot_additional_pages(zone); + if (populated_zone(zone)) { + if (is_highmem(zone)) { + highmem_size -= zone->free_pages; + } else { + tmp -= zone->free_pages; + tmp += zone->lowmem_reserve[ZONE_NORMAL]; + tmp += snapshot_additional_pages(zone); + } } + + if (highmem_size < 0) + highmem_size = 0; + + tmp += highmem_size; if (tmp > 0) { tmp = __shrink_memory(tmp); if (!tmp) @@ -223,6 +233,7 @@ int swsusp_suspend(void) if ((error = arch_prepare_suspend())) return error; + local_irq_disable(); /* At this point, device_suspend() has been called, but *not* * device_power_down(). We *must* device_power_down() now. @@ -235,18 +246,11 @@ int swsusp_suspend(void) goto Enable_irqs; } - if ((error = save_highmem())) { - printk(KERN_ERR "swsusp: Not enough free pages for highmem\n"); - goto Restore_highmem; - } - save_processor_state(); if ((error = swsusp_arch_suspend())) printk(KERN_ERR "Error %d suspending\n", error); /* Restore control flow magically appears here */ restore_processor_state(); -Restore_highmem: - restore_highmem(); /* NOTE: device_power_up() is just a resume() for devices * that suspended with irqs off ... no overall powerup. */ @@ -268,18 +272,23 @@ int swsusp_resume(void) printk(KERN_ERR "Some devices failed to power down, very bad\n"); /* We'll ignore saved state, but this gets preempt count (etc) right */ save_processor_state(); - error = swsusp_arch_resume(); - /* Code below is only ever reached in case of failure. Otherwise - * execution continues at place where swsusp_arch_suspend was called - */ - BUG_ON(!error); + error = restore_highmem(); + if (!error) { + error = swsusp_arch_resume(); + /* The code below is only ever reached in case of a failure. + * Otherwise execution continues at place where + * swsusp_arch_suspend() was called + */ + BUG_ON(!error); + /* This call to restore_highmem() undos the previous one */ + restore_highmem(); + } /* The only reason why swsusp_arch_resume() can fail is memory being * very tight, so we have to free it as soon as we can to avoid * subsequent failures */ swsusp_free(); restore_processor_state(); - restore_highmem(); touch_softlockup_watchdog(); device_power_up(); local_irq_enable(); diff --git a/kernel/power/user.c b/kernel/power/user.c index 05c58a2c0dd4..a63b25c63b49 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -194,12 +194,12 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, break; case SNAPSHOT_ATOMIC_RESTORE: + snapshot_write_finalize(&data->handle); if (data->mode != O_WRONLY || !data->frozen || !snapshot_image_loaded(&data->handle)) { error = -EPERM; break; } - snapshot_free_unused_memory(&data->handle); down(&pm_sem); pm_prepare_console(); suspend_console(); diff --git a/mm/vmscan.c b/mm/vmscan.c index 2e97baa3b2aa..2a6a79f68138 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1260,6 +1260,9 @@ out: } if (!all_zones_ok) { cond_resched(); + + try_to_freeze(); + goto loop_again; } -- cgit v1.2.3 From 7dfb71030f7636a0d65200158113c37764552f93 Mon Sep 17 00:00:00 2001 From: Nigel Cunningham Date: Wed, 6 Dec 2006 20:34:23 -0800 Subject: [PATCH] Add include/linux/freezer.h and move definitions from sched.h Move process freezing functions from include/linux/sched.h to freezer.h, so that modifications to the freezer or the kernel configuration don't require recompiling just about everything. [akpm@osdl.org: fix ueagle driver] Signed-off-by: Nigel Cunningham Cc: "Rafael J. Wysocki" Cc: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/kernel/signal.c | 1 + arch/avr32/kernel/signal.c | 2 +- arch/frv/kernel/signal.c | 2 +- arch/h8300/kernel/signal.c | 2 +- arch/i386/kernel/io_apic.c | 1 + arch/m32r/kernel/signal.c | 2 +- arch/powerpc/kernel/signal_32.c | 2 +- arch/sh/kernel/signal.c | 1 + arch/sh64/kernel/signal.c | 2 +- drivers/block/pktcdvd.c | 2 +- drivers/char/hvc_console.c | 1 + drivers/edac/edac_mc.c | 1 + drivers/ieee1394/nodemgr.c | 1 + drivers/input/gameport/gameport.c | 1 + drivers/input/serio/serio.c | 1 + drivers/macintosh/therm_adt746x.c | 1 + drivers/macintosh/via-pmu.c | 2 +- drivers/macintosh/windfarm_core.c | 1 + drivers/md/md.c | 2 +- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- drivers/media/video/msp3400-driver.c | 2 +- drivers/media/video/tvaudio.c | 1 + drivers/media/video/video-buf-dvb.c | 2 +- drivers/media/video/vivi.c | 1 + drivers/mfd/ucb1x00-ts.c | 2 +- drivers/net/irda/stir4200.c | 1 + drivers/net/wireless/airo.c | 1 + drivers/pcmcia/cs.c | 1 + drivers/pnp/pnpbios/core.c | 1 + drivers/usb/atm/ueagle-atm.c | 2 + drivers/usb/core/hub.c | 1 + drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/storage/usb.c | 2 +- drivers/w1/w1.c | 1 + fs/afs/kafsasyncd.c | 1 + fs/afs/kafstimod.c | 1 + fs/cifs/cifsfs.c | 1 + fs/cifs/connect.c | 1 + fs/jbd/journal.c | 2 +- fs/jbd2/journal.c | 2 +- fs/jffs/intrep.c | 1 + fs/jffs2/background.c | 1 + fs/jfs/jfs_logmgr.c | 2 +- fs/jfs/jfs_txnmgr.c | 2 +- fs/lockd/clntproc.c | 1 + fs/xfs/linux-2.6/xfs_buf.c | 1 + fs/xfs/linux-2.6/xfs_super.c | 1 + include/linux/freezer.h | 84 +++++++++++++++++++++++++++++++ include/linux/sched.h | 81 ----------------------------- init/do_mounts_initrd.c | 1 + kernel/audit.c | 1 + kernel/power/disk.c | 1 + kernel/power/main.c | 1 + kernel/power/process.c | 1 + kernel/power/user.c | 1 + kernel/rtmutex-tester.c | 1 + kernel/sched.c | 2 +- kernel/signal.c | 1 + mm/pdflush.c | 1 + mm/vmscan.c | 1 + net/rxrpc/krxiod.c | 1 + net/rxrpc/krxsecd.c | 1 + net/rxrpc/krxtimod.c | 1 + net/sunrpc/svcsock.c | 1 + 64 files changed, 147 insertions(+), 101 deletions(-) create mode 100644 include/linux/freezer.h (limited to 'include/linux') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 48cf7fffddf2..f38a60a03b8c 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 33096651c24f..0ec14854a200 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index b8a5882b8625..85baeae9666a 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index 7787f70a05bb..02955604d760 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 3b7a63e0ed1a..44c5a3206b2a 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index b60cea4aebaa..092ea86bb079 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 320353f0926f..e4ebe1a6228e 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #endif #include diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index 50d7c4993bef..bb1c480a59c7 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c index 9e2ffc45c0e0..1666d3efb52e 100644 --- a/arch/sh64/kernel/signal.c +++ b/arch/sh64/kernel/signal.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index f2904f67af47..e45eaa264119 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 9902ffad3b12..cc2cd46bedc6 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -38,6 +38,7 @@ #include #include #include +#include #include diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 75e9e38330ff..1b4fc9221803 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 8e7b83f84485..e829c9336b3c 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "csr.h" diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index a0af97efe6ac..79dfb4b25c97 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -23,6 +23,7 @@ #include #include /* HZ */ #include +#include /*#include */ diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 211943f85cb6..5f1d4032fd57 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -35,6 +35,7 @@ #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Serio abstraction core"); diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 13b953ae8ebc..3d3bf1643e73 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index e63ea1c1f3c1..c8558d4ed506 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index ab3faa702d58..e947af982f93 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include diff --git a/drivers/md/md.c b/drivers/md/md.c index 8cbf9c9df1c3..6c4345bde07e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -39,10 +39,10 @@ #include #include #include /* for invalidate_bdev */ -#include #include #include #include +#include #include diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index a2ab2eebfc68..e85972222ab4 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index cf43df3fe708..e1b56dc13c3f 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -56,7 +56,7 @@ #include #include #include -#include +#include #include "msp3400-driver.h" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index fcaef4bf8289..d506dfaa45a9 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index f53edf1923b7..fcc5467e7636 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 3c8dc72dc8e9..9986de5cb3d6 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -36,6 +36,7 @@ #include #include #include +#include /* Wake up at about 30 fps */ #define WAKE_NUMERATOR 30 diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 82938ad6ddbd..ce1a48108210 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 3b4c47875935..c14a74634fd5 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index efcdaf1c5f73..44a22701da97 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -49,6 +49,7 @@ #include #include #include +#include #include "airo.h" diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index f9cd831a3f31..606a46740338 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 81a6c83d89a6..81186f479a3f 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index f2d196fa1e8b..dae4ef1e8fe5 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -64,6 +64,8 @@ #include #include #include +#include + #include #include "usbatm.h" diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 77c05be5241a..2651c2e2a89f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 8b975d15538d..c98316ce8384 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -250,7 +250,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index b401084b3d22..70644506651f 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index de3e9791f80d..63c07243993c 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -31,6 +31,7 @@ #include #include #include +#include #include diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c index f09a794f248e..615df2407cb2 100644 --- a/fs/afs/kafsasyncd.c +++ b/fs/afs/kafsasyncd.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "cell.h" #include "server.h" #include "volume.h" diff --git a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c index 65bc05ab8182..694344e4d3c7 100644 --- a/fs/afs/kafstimod.c +++ b/fs/afs/kafstimod.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "cell.h" #include "volume.h" #include "kafstimod.h" diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e6b5866e5001..71bc87a37fc1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "cifsfs.h" #include "cifspdu.h" #define DECLARE_GLOBALS_HERE diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 71f77914ce93..2caca06b4bae 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include "cifspdu.h" diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index a8774bed20b6..10fff9443938 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 50356019ae30..44fc32bfd7f1 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c index 4a543e114970..478a74e2e9d5 100644 --- a/fs/jffs/intrep.c +++ b/fs/jffs/intrep.c @@ -66,6 +66,7 @@ #include #include #include +#include #include "intrep.h" #include "jffs_fm.h" diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index ff2a872e80e7..6eb3daebd563 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "nodelist.h" diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index b89c9aba0466..5065baa530b6 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -67,7 +67,7 @@ #include #include /* for sync_blockdev() */ #include -#include +#include #include #include #include "jfs_incore.h" diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 81f6f04af192..d558e51b0df8 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 3d84f600b633..50643b6a5556 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index eef4a0ba11e9..b971237c5a9f 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -32,6 +32,7 @@ #include #include #include +#include STATIC kmem_zone_t *xfs_buf_zone; STATIC kmem_shaker_t xfs_buf_shake; diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index de05abbbe7fd..b93265b7c79c 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -56,6 +56,7 @@ #include #include #include +#include STATIC struct quotactl_ops xfs_quotactl_operations; STATIC struct super_operations xfs_super_operations; diff --git a/include/linux/freezer.h b/include/linux/freezer.h new file mode 100644 index 000000000000..266373f74445 --- /dev/null +++ b/include/linux/freezer.h @@ -0,0 +1,84 @@ +/* Freezer declarations */ + +#ifdef CONFIG_PM +/* + * Check if a process has been frozen + */ +static inline int frozen(struct task_struct *p) +{ + return p->flags & PF_FROZEN; +} + +/* + * Check if there is a request to freeze a process + */ +static inline int freezing(struct task_struct *p) +{ + return p->flags & PF_FREEZE; +} + +/* + * Request that a process be frozen + * FIXME: SMP problem. We may not modify other process' flags! + */ +static inline void freeze(struct task_struct *p) +{ + p->flags |= PF_FREEZE; +} + +/* + * Sometimes we may need to cancel the previous 'freeze' request + */ +static inline void do_not_freeze(struct task_struct *p) +{ + p->flags &= ~PF_FREEZE; +} + +/* + * Wake up a frozen process + */ +static inline int thaw_process(struct task_struct *p) +{ + if (frozen(p)) { + p->flags &= ~PF_FROZEN; + wake_up_process(p); + return 1; + } + return 0; +} + +/* + * freezing is complete, mark process as frozen + */ +static inline void frozen_process(struct task_struct *p) +{ + p->flags = (p->flags & ~PF_FREEZE) | PF_FROZEN; +} + +extern void refrigerator(void); +extern int freeze_processes(void); +extern void thaw_processes(void); + +static inline int try_to_freeze(void) +{ + if (freezing(current)) { + refrigerator(); + return 1; + } else + return 0; +} +#else +static inline int frozen(struct task_struct *p) { return 0; } +static inline int freezing(struct task_struct *p) { return 0; } +static inline void freeze(struct task_struct *p) { BUG(); } +static inline int thaw_process(struct task_struct *p) { return 1; } +static inline void frozen_process(struct task_struct *p) { BUG(); } + +static inline void refrigerator(void) {} +static inline int freeze_processes(void) { BUG(); return 0; } +static inline void thaw_processes(void) {} + +static inline int try_to_freeze(void) { return 0; } + + +#endif diff --git a/include/linux/sched.h b/include/linux/sched.h index acfd2e15c5f2..837a012f573c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1618,87 +1618,6 @@ extern int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls); extern void normalize_rt_tasks(void); -#ifdef CONFIG_PM -/* - * Check if a process has been frozen - */ -static inline int frozen(struct task_struct *p) -{ - return p->flags & PF_FROZEN; -} - -/* - * Check if there is a request to freeze a process - */ -static inline int freezing(struct task_struct *p) -{ - return p->flags & PF_FREEZE; -} - -/* - * Request that a process be frozen - * FIXME: SMP problem. We may not modify other process' flags! - */ -static inline void freeze(struct task_struct *p) -{ - p->flags |= PF_FREEZE; -} - -/* - * Sometimes we may need to cancel the previous 'freeze' request - */ -static inline void do_not_freeze(struct task_struct *p) -{ - p->flags &= ~PF_FREEZE; -} - -/* - * Wake up a frozen process - */ -static inline int thaw_process(struct task_struct *p) -{ - if (frozen(p)) { - p->flags &= ~PF_FROZEN; - wake_up_process(p); - return 1; - } - return 0; -} - -/* - * freezing is complete, mark process as frozen - */ -static inline void frozen_process(struct task_struct *p) -{ - p->flags = (p->flags & ~PF_FREEZE) | PF_FROZEN; -} - -extern void refrigerator(void); -extern int freeze_processes(void); -extern void thaw_processes(void); - -static inline int try_to_freeze(void) -{ - if (freezing(current)) { - refrigerator(); - return 1; - } else - return 0; -} -#else -static inline int frozen(struct task_struct *p) { return 0; } -static inline int freezing(struct task_struct *p) { return 0; } -static inline void freeze(struct task_struct *p) { BUG(); } -static inline int thaw_process(struct task_struct *p) { return 1; } -static inline void frozen_process(struct task_struct *p) { BUG(); } - -static inline void refrigerator(void) {} -static inline int freeze_processes(void) { BUG(); return 0; } -static inline void thaw_processes(void) {} - -static inline int try_to_freeze(void) { return 0; } - -#endif /* CONFIG_PM */ #endif /* __KERNEL__ */ #endif diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index 919a80cb322e..2cfd7cb36e79 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "do_mounts.h" diff --git a/kernel/audit.c b/kernel/audit.c index 98106f6078b0..d9b690ac684b 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "audit.h" diff --git a/kernel/power/disk.c b/kernel/power/disk.c index f5079231383e..53b3b57c0223 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "power.h" diff --git a/kernel/power/main.c b/kernel/power/main.c index 873228c71dab..6096c71b182b 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "power.h" diff --git a/kernel/power/process.c b/kernel/power/process.c index 72e72d2c61e6..29be608e8349 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -13,6 +13,7 @@ #include #include #include +#include /* * Timeout for stopping processes diff --git a/kernel/power/user.c b/kernel/power/user.c index a63b25c63b49..26c66941c001 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -22,6 +22,7 @@ #include #include #include +#include #include diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c index 6dcea9dd8c94..015fc633c96c 100644 --- a/kernel/rtmutex-tester.c +++ b/kernel/rtmutex-tester.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "rtmutex.h" diff --git a/kernel/sched.c b/kernel/sched.c index 3399701c680e..12fdbef1d9bf 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/kernel/signal.c b/kernel/signal.c index 8e19d2785486..bc972d7e6319 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/mm/pdflush.c b/mm/pdflush.c index b02102feeb4b..8ce0900dc95c 100644 --- a/mm/pdflush.c +++ b/mm/pdflush.c @@ -21,6 +21,7 @@ #include // Prototypes pdflush_operation() #include #include +#include /* diff --git a/mm/vmscan.c b/mm/vmscan.c index 2a6a79f68138..f6616e81fac7 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff --git a/net/rxrpc/krxiod.c b/net/rxrpc/krxiod.c index dada34a77b21..49effd92144e 100644 --- a/net/rxrpc/krxiod.c +++ b/net/rxrpc/krxiod.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c index cea4eb5e2497..3ab0f77409f4 100644 --- a/net/rxrpc/krxsecd.c +++ b/net/rxrpc/krxsecd.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "internal.h" diff --git a/net/rxrpc/krxtimod.c b/net/rxrpc/krxtimod.c index 3e7466900bd4..9a9b6132dba4 100644 --- a/net/rxrpc/krxtimod.c +++ b/net/rxrpc/krxtimod.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 64ca1f61dd94..1c68956824e3 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From ff39593ad0ff7a79a3717edac6634407aa8200c2 Mon Sep 17 00:00:00 2001 From: Nigel Cunningham Date: Wed, 6 Dec 2006 20:34:28 -0800 Subject: [PATCH] swsusp: thaw userspace and kernel space separately Modify process thawing so that we can thaw kernel space without thawing userspace, and thaw kernelspace first. This will be useful in later patches, where I intend to get swsusp thawing kernel threads only before seeking to free memory. Signed-off-by: Nigel Cunningham Cc: Pavel Machek Cc: "Rafael J. Wysocki" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/freezer.h | 9 ++++++++- kernel/power/process.c | 25 ++++++++++++++++++------- 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 266373f74445..294ebea859c9 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -1,5 +1,8 @@ /* Freezer declarations */ +#define FREEZER_KERNEL_THREADS 0 +#define FREEZER_ALL_THREADS 1 + #ifdef CONFIG_PM /* * Check if a process has been frozen @@ -57,7 +60,8 @@ static inline void frozen_process(struct task_struct *p) extern void refrigerator(void); extern int freeze_processes(void); -extern void thaw_processes(void); +#define thaw_processes() do { thaw_some_processes(FREEZER_ALL_THREADS); } while(0) +#define thaw_kernel_threads() do { thaw_some_processes(FREEZER_KERNEL_THREADS); } while(0) static inline int try_to_freeze(void) { @@ -67,6 +71,9 @@ static inline int try_to_freeze(void) } else return 0; } + +extern void thaw_some_processes(int all); + #else static inline int frozen(struct task_struct *p) { return 0; } static inline int freezing(struct task_struct *p) { return 0; } diff --git a/kernel/power/process.c b/kernel/power/process.c index fedabad5a180..cba8a5890eda 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -153,18 +153,29 @@ int freeze_processes(void) return 0; } -void thaw_processes(void) +void thaw_some_processes(int all) { struct task_struct *g, *p; + int pass = 0; /* Pass 0 = Kernel space, 1 = Userspace */ printk("Restarting tasks... "); read_lock(&tasklist_lock); - do_each_thread(g, p) { - if (!freezeable(p)) - continue; - if (!thaw_process(p)) - printk(KERN_INFO "Strange, %s not stopped\n", p->comm); - } while_each_thread(g, p); + do { + do_each_thread(g, p) { + /* + * is_user = 0 if kernel thread or borrowed mm, + * 1 otherwise. + */ + int is_user = !!(p->mm && !(p->flags & PF_BORROWED_MM)); + if (!freezeable(p) || (is_user != pass)) + continue; + if (!thaw_process(p)) + printk(KERN_INFO + "Strange, %s not stopped\n", p->comm); + } while_each_thread(g, p); + + pass++; + } while (pass < 2 && all); read_unlock(&tasklist_lock); schedule(); -- cgit v1.2.3 From a9b6f562f14dc28fb4b2415f0f275cede0abe9b5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 6 Dec 2006 20:34:37 -0800 Subject: [PATCH] swsusp: Untangle thaw_processes Move the loop from thaw_processes() to a separate function and call it independently for kernel threads and user space processes so that the order of thawing tasks is clearly visible. Drop thaw_kernel_threads() which is never used. Signed-off-by: Rafael J. Wysocki Cc: Pavel Machek Cc: Nigel Cunningham Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/freezer.h | 6 +----- kernel/power/process.c | 49 +++++++++++++++++++++++++++---------------------- 2 files changed, 28 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 294ebea859c9..6e05e3e7ce39 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -1,8 +1,5 @@ /* Freezer declarations */ -#define FREEZER_KERNEL_THREADS 0 -#define FREEZER_ALL_THREADS 1 - #ifdef CONFIG_PM /* * Check if a process has been frozen @@ -60,8 +57,7 @@ static inline void frozen_process(struct task_struct *p) extern void refrigerator(void); extern int freeze_processes(void); -#define thaw_processes() do { thaw_some_processes(FREEZER_ALL_THREADS); } while(0) -#define thaw_kernel_threads() do { thaw_some_processes(FREEZER_KERNEL_THREADS); } while(0) +extern void thaw_processes(void); static inline int try_to_freeze(void) { diff --git a/kernel/power/process.c b/kernel/power/process.c index 1badb9a89ade..fd0ebb942f50 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -20,6 +20,8 @@ */ #define TIMEOUT (20 * HZ) +#define FREEZER_KERNEL_THREADS 0 +#define FREEZER_USER_SPACE 1 static inline int freezeable(struct task_struct * p) { @@ -79,6 +81,11 @@ static void cancel_freezing(struct task_struct *p) } } +static inline int is_user_space(struct task_struct *p) +{ + return p->mm && !(p->flags & PF_BORROWED_MM); +} + /* 0 = success, else # of processes that we failed to stop */ int freeze_processes(void) { @@ -103,10 +110,9 @@ int freeze_processes(void) cancel_freezing(p); continue; } - if (p->mm && !(p->flags & PF_BORROWED_MM)) { - /* The task is a user-space one. - * Freeze it unless there's a vfork completion - * pending + if (is_user_space(p)) { + /* Freeze the task unless there is a vfork + * completion pending */ if (!p->vfork_done) freeze_process(p); @@ -155,31 +161,30 @@ int freeze_processes(void) return 0; } -void thaw_some_processes(int all) +static void thaw_tasks(int thaw_user_space) { struct task_struct *g, *p; - int pass = 0; /* Pass 0 = Kernel space, 1 = Userspace */ - printk("Restarting tasks... "); read_lock(&tasklist_lock); - do { - do_each_thread(g, p) { - /* - * is_user = 0 if kernel thread or borrowed mm, - * 1 otherwise. - */ - int is_user = !!(p->mm && !(p->flags & PF_BORROWED_MM)); - if (!freezeable(p) || (is_user != pass)) - continue; - if (!thaw_process(p)) - printk(KERN_INFO - "Strange, %s not stopped\n", p->comm); - } while_each_thread(g, p); + do_each_thread(g, p) { + if (!freezeable(p)) + continue; - pass++; - } while (pass < 2 && all); + if (is_user_space(p) == !thaw_user_space) + continue; + if (!thaw_process(p)) + printk(KERN_WARNING " Strange, %s not stopped\n", + p->comm ); + } while_each_thread(g, p); read_unlock(&tasklist_lock); +} + +void thaw_processes(void) +{ + printk("Restarting tasks ... "); + thaw_tasks(FREEZER_KERNEL_THREADS); + thaw_tasks(FREEZER_USER_SPACE); schedule(); printk("done.\n"); } -- cgit v1.2.3 From 341a595850dac1b0503df34260257d71b4fdf72c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 6 Dec 2006 20:34:49 -0800 Subject: [PATCH] Support for freezeable workqueues Make it possible to create a workqueue the worker thread of which will be frozen during suspend, along with other kernel threads. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Cc: Nigel Cunningham Cc: David Chinner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/workqueue.h | 8 +++++--- kernel/workqueue.c | 20 ++++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 4a3ea83c6d16..f0cb1df7b475 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -147,9 +147,11 @@ struct execute_work { extern struct workqueue_struct *__create_workqueue(const char *name, - int singlethread); -#define create_workqueue(name) __create_workqueue((name), 0) -#define create_singlethread_workqueue(name) __create_workqueue((name), 1) + int singlethread, + int freezeable); +#define create_workqueue(name) __create_workqueue((name), 0, 0) +#define create_freezeable_workqueue(name) __create_workqueue((name), 0, 1) +#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0) extern void destroy_workqueue(struct workqueue_struct *wq); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 8d1e7cb8a51a..2945b094d871 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -29,6 +29,7 @@ #include #include #include +#include /* * The per-CPU workqueue (if single thread, we always use the first @@ -55,6 +56,8 @@ struct cpu_workqueue_struct { struct task_struct *thread; int run_depth; /* Detect run_workqueue() recursion depth */ + + int freezeable; /* Freeze the thread during suspend */ } ____cacheline_aligned; /* @@ -265,7 +268,8 @@ static int worker_thread(void *__cwq) struct k_sigaction sa; sigset_t blocked; - current->flags |= PF_NOFREEZE; + if (!cwq->freezeable) + current->flags |= PF_NOFREEZE; set_user_nice(current, -5); @@ -288,6 +292,9 @@ static int worker_thread(void *__cwq) set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { + if (cwq->freezeable) + try_to_freeze(); + add_wait_queue(&cwq->more_work, &wait); if (list_empty(&cwq->worklist)) schedule(); @@ -364,7 +371,7 @@ void fastcall flush_workqueue(struct workqueue_struct *wq) EXPORT_SYMBOL_GPL(flush_workqueue); static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq, - int cpu) + int cpu, int freezeable) { struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu); struct task_struct *p; @@ -374,6 +381,7 @@ static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq, cwq->thread = NULL; cwq->insert_sequence = 0; cwq->remove_sequence = 0; + cwq->freezeable = freezeable; INIT_LIST_HEAD(&cwq->worklist); init_waitqueue_head(&cwq->more_work); init_waitqueue_head(&cwq->work_done); @@ -389,7 +397,7 @@ static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq, } struct workqueue_struct *__create_workqueue(const char *name, - int singlethread) + int singlethread, int freezeable) { int cpu, destroy = 0; struct workqueue_struct *wq; @@ -409,7 +417,7 @@ struct workqueue_struct *__create_workqueue(const char *name, mutex_lock(&workqueue_mutex); if (singlethread) { INIT_LIST_HEAD(&wq->list); - p = create_workqueue_thread(wq, singlethread_cpu); + p = create_workqueue_thread(wq, singlethread_cpu, freezeable); if (!p) destroy = 1; else @@ -417,7 +425,7 @@ struct workqueue_struct *__create_workqueue(const char *name, } else { list_add(&wq->list, &workqueues); for_each_online_cpu(cpu) { - p = create_workqueue_thread(wq, cpu); + p = create_workqueue_thread(wq, cpu, freezeable); if (p) { kthread_bind(p, cpu); wake_up_process(p); @@ -667,7 +675,7 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb, mutex_lock(&workqueue_mutex); /* Create a new workqueue thread for it. */ list_for_each_entry(wq, &workqueues, list) { - if (!create_workqueue_thread(wq, hotcpu)) { + if (!create_workqueue_thread(wq, hotcpu, 0)) { printk("workqueue for %i failed\n", hotcpu); return NOTIFY_BAD; } -- cgit v1.2.3 From 799202cbd0ef6a201446d99fcbd78b9f0bda6ae5 Mon Sep 17 00:00:00 2001 From: Mike Miller Date: Wed, 6 Dec 2006 20:35:12 -0800 Subject: [PATCH] cciss: add support for 1024 logical volumes Add the support for a large number of logical volumes. We will soon have hardware that support up to 1024 logical volumes. Signed-off-by: Mike Miller Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/cciss.c | 114 ++++++++++++++++++++++++++++++-------------- drivers/block/cciss.h | 3 +- drivers/block/cciss_cmd.h | 2 +- include/linux/cciss_ioctl.h | 2 +- 4 files changed, 80 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 70cf9321ef54..c99cb7ed57f7 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1315,6 +1315,11 @@ static void cciss_update_drive_info(int ctlr, int drv_index) /* if it's the controller it's already added */ if (drv_index) { disk->queue = blk_init_queue(do_cciss_request, &h->lock); + sprintf(disk->disk_name, "cciss/c%dd%d", ctlr, drv_index); + disk->major = h->major; + disk->first_minor = drv_index << NWD_SHIFT; + disk->fops = &cciss_fops; + disk->private_data = &h->drv[drv_index]; /* Set up queue information */ disk->queue->backing_dev_info.ra_pages = READ_AHEAD; @@ -1393,11 +1398,6 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) /* Set busy_configuring flag for this operation */ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); - if (h->num_luns >= CISS_MAX_LUN) { - spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); - return -EINVAL; - } - if (h->busy_configuring) { spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); return -EBUSY; @@ -1430,17 +1430,8 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) 0, 0, TYPE_CMD); if (return_code == IO_OK) { - listlength |= - (0xff & (unsigned int)(ld_buff->LUNListLength[0])) - << 24; - listlength |= - (0xff & (unsigned int)(ld_buff->LUNListLength[1])) - << 16; - listlength |= - (0xff & (unsigned int)(ld_buff->LUNListLength[2])) - << 8; - listlength |= - 0xff & (unsigned int)(ld_buff->LUNListLength[3]); + listlength = + be32_to_cpu(*(__u32 *) ld_buff->LUNListLength); } else { /* reading number of logical volumes failed */ printk(KERN_WARNING "cciss: report logical volume" " command failed\n"); @@ -1491,6 +1482,14 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) if (drv_index == -1) goto freeret; + /*Check if the gendisk needs to be allocated */ + if (!h->gendisk[drv_index]){ + h->gendisk[drv_index] = alloc_disk(1 << NWD_SHIFT); + if (!h->gendisk[drv_index]){ + printk(KERN_ERR "cciss: could not allocate new disk %d\n", drv_index); + goto mem_msg; + } + } } h->drv[drv_index].LunID = lunid; cciss_update_drive_info(ctlr, drv_index); @@ -1528,6 +1527,7 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all) { + int i; ctlr_info_t *h = get_host(disk); if (!capable(CAP_SYS_RAWIO)) @@ -1551,9 +1551,35 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, del_gendisk(disk); if (q) { blk_cleanup_queue(q); + /* Set drv->queue to NULL so that we do not try + * to call blk_start_queue on this queue in the + * interrupt handler + */ drv->queue = NULL; } + /* If clear_all is set then we are deleting the logical + * drive, not just refreshing its info. For drives + * other than disk 0 we will call put_disk. We do not + * do this for disk 0 as we need it to be able to + * configure the controller. + */ + if (clear_all){ + /* This isn't pretty, but we need to find the + * disk in our array and NULL our the pointer. + * This is so that we will call alloc_disk if + * this index is used again later. + */ + for (i=0; i < CISS_MAX_LUN; i++){ + if(h->gendisk[i] == disk){ + h->gendisk[i] = NULL; + break; + } + } + put_disk(disk); + } } + } else { + set_capacity(disk, 0); } --h->num_luns; @@ -3119,13 +3145,7 @@ geo_inq: /* Returns -1 if no free entries are left. */ static int alloc_cciss_hba(void) { - struct gendisk *disk[NWD]; - int i, n; - for (n = 0; n < NWD; n++) { - disk[n] = alloc_disk(1 << NWD_SHIFT); - if (!disk[n]) - goto out; - } + int i; for (i = 0; i < MAX_CTLR; i++) { if (!hba[i]) { @@ -3133,20 +3153,18 @@ static int alloc_cciss_hba(void) p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL); if (!p) goto Enomem; - for (n = 0; n < NWD; n++) - p->gendisk[n] = disk[n]; + p->gendisk[0] = alloc_disk(1 << NWD_SHIFT); + if (!p->gendisk[0]) + goto Enomem; hba[i] = p; return i; } } printk(KERN_WARNING "cciss: This driver supports a maximum" " of %d controllers.\n", MAX_CTLR); - goto out; - Enomem: + return -1; +Enomem: printk(KERN_ERR "cciss: out of memory.\n"); - out: - while (n--) - put_disk(disk[n]); return -1; } @@ -3156,7 +3174,7 @@ static void free_hba(int i) int n; hba[i] = NULL; - for (n = 0; n < NWD; n++) + for (n = 0; n < CISS_MAX_LUN; n++) put_disk(p->gendisk[n]); kfree(p); } @@ -3169,9 +3187,8 @@ static void free_hba(int i) static int __devinit cciss_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - request_queue_t *q; int i; - int j; + int j = 0; int rc; int dac; @@ -3283,16 +3300,29 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, hba[i]->busy_initializing = 0; - for (j = 0; j < NWD; j++) { /* mfm */ + do { drive_info_struct *drv = &(hba[i]->drv[j]); struct gendisk *disk = hba[i]->gendisk[j]; + request_queue_t *q; + + /* Check if the disk was allocated already */ + if (!disk){ + hba[i]->gendisk[j] = alloc_disk(1 << NWD_SHIFT); + disk = hba[i]->gendisk[j]; + } + + /* Check that the disk was able to be allocated */ + if (!disk) { + printk(KERN_ERR "cciss: unable to allocate memory for disk %d\n", j); + goto clean4; + } q = blk_init_queue(do_cciss_request, &hba[i]->lock); if (!q) { printk(KERN_ERR "cciss: unable to allocate queue for disk %d\n", j); - break; + goto clean4; } drv->queue = q; @@ -3324,7 +3354,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, blk_queue_hardsect_size(q, drv->block_size); set_capacity(disk, drv->nr_blocks); add_disk(disk); - } + j++; + } while (j <= hba[i]->highest_lun); return 1; @@ -3347,6 +3378,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, unregister_blkdev(hba[i]->major, hba[i]->devname); clean1: hba[i]->busy_initializing = 0; + /* cleanup any queues that may have been initialized */ + for (j=0; j <= hba[i]->highest_lun; j++){ + drive_info_struct *drv = &(hba[i]->drv[j]); + if (drv->queue) + blk_cleanup_queue(drv->queue); + } + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); free_hba(i); return -1; } @@ -3394,7 +3434,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) remove_proc_entry(hba[i]->devname, proc_cciss); /* remove it from the disk list */ - for (j = 0; j < NWD; j++) { + for (j = 0; j < CISS_MAX_LUN; j++) { struct gendisk *disk = hba[i]->gendisk[j]; if (disk) { request_queue_t *q = disk->queue; diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index c3df673f860b..b70988dd33ec 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -6,7 +6,6 @@ #include "cciss_cmd.h" -#define NWD 16 #define NWD_SHIFT 4 #define MAX_PART (1 << NWD_SHIFT) @@ -112,7 +111,7 @@ struct ctlr_info int next_to_run; // Disk structures we need to pass back - struct gendisk *gendisk[NWD]; + struct gendisk *gendisk[CISS_MAX_LUN]; #ifdef CONFIG_CISS_SCSI_TAPE void *scsi_ctlr; /* ptr to structure containing scsi related stuff */ /* list of block side commands the scsi error handling sucked up */ diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index b2147cca5acd..43bf5593b59b 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h @@ -89,7 +89,7 @@ typedef union _u64bit //########################################################################### //STRUCTURES //########################################################################### -#define CISS_MAX_LUN 16 +#define CISS_MAX_LUN 1024 #define CISS_MAX_PHYS_LUN 1024 // SCSI-3 Cmmands diff --git a/include/linux/cciss_ioctl.h b/include/linux/cciss_ioctl.h index 6e27f42e3a57..cb57c30081a8 100644 --- a/include/linux/cciss_ioctl.h +++ b/include/linux/cciss_ioctl.h @@ -80,7 +80,7 @@ typedef __u32 DriverVer_type; #define HWORD __u16 #define DWORD __u32 -#define CISS_MAX_LUN 16 +#define CISS_MAX_LUN 1024 #define LEVEL2LUN 1 // index into Target(x) structure, due to byte swapping #define LEVEL3LUN 0 -- cgit v1.2.3 From 238b8721a554a33a451a3f13bdb5be8fe5cfc927 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 6 Dec 2006 20:35:17 -0800 Subject: [PATCH] serial uartlite driver Add a driver for the Xilinx uartlite serial controller used in boards with the PPC405 core in the Xilinx V2P/V4 fpgas. The hardware is very simple (baudrate/start/stopbits fixed and no break support). See the datasheet for details: http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf See http://thread.gmane.org/gmane.linux.serial/1237/ for the email thread. Signed-off-by: Peter Korsgaard Acked-by: Olof Johansson Cc: Russell King Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 6 + drivers/serial/Kconfig | 19 ++ drivers/serial/Makefile | 1 + drivers/serial/uartlite.c | 505 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/serial_core.h | 2 + 5 files changed, 533 insertions(+) create mode 100644 drivers/serial/uartlite.c (limited to 'include/linux') diff --git a/MAINTAINERS b/MAINTAINERS index 5dff26814a06..fa1bba8de1f8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3454,6 +3454,12 @@ W: http://oss.sgi.com/projects/xfs T: git git://oss.sgi.com:8090/xfs/xfs-2.6 S: Supported +XILINX UARTLITE SERIAL DRIVER +P: Peter Korsgaard +M: jacmet@sunsite.dk +L: linux-serial@vger.kernel.org +S: Maintained + X86 3-LEVEL PAGING (PAE) SUPPORT P: Ingo Molnar M: mingo@redhat.com diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 0b71e7d18903..e936c91640b4 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -511,6 +511,25 @@ config SERIAL_IMX_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) +config SERIAL_UARTLITE + tristate "Xilinx uartlite serial port support" + depends on PPC32 + select SERIAL_CORE + help + Say Y here if you want to use the Xilinx uartlite serial controller. + + To compile this driver as a module, choose M here: the + module will be called uartlite.ko. + +config SERIAL_UARTLITE_CONSOLE + bool "Support for console on Xilinx uartlite serial port" + depends on SERIAL_UARTLITE=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use a Xilinx uartlite as the system + console (the system console is the device which receives all kernel + messages and warnings and which allows logins in single user mode). + config SERIAL_SUNCORE bool depends on SPARC diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index b4d8a7c182e3..0dba0017a006 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -55,4 +55,5 @@ obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o +obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c new file mode 100644 index 000000000000..83690653b78b --- /dev/null +++ b/drivers/serial/uartlite.c @@ -0,0 +1,505 @@ +/* + * uartlite.c: Serial driver for Xilinx uartlite serial controller + * + * Peter Korsgaard + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ULITE_MAJOR 204 +#define ULITE_MINOR 187 +#define ULITE_NR_UARTS 4 + +/* For register details see datasheet: + http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf +*/ +#define ULITE_RX 0x00 +#define ULITE_TX 0x04 +#define ULITE_STATUS 0x08 +#define ULITE_CONTROL 0x0c + +#define ULITE_REGION 16 + +#define ULITE_STATUS_RXVALID 0x01 +#define ULITE_STATUS_RXFULL 0x02 +#define ULITE_STATUS_TXEMPTY 0x04 +#define ULITE_STATUS_TXFULL 0x08 +#define ULITE_STATUS_IE 0x10 +#define ULITE_STATUS_OVERRUN 0x20 +#define ULITE_STATUS_FRAME 0x40 +#define ULITE_STATUS_PARITY 0x80 + +#define ULITE_CONTROL_RST_TX 0x01 +#define ULITE_CONTROL_RST_RX 0x02 +#define ULITE_CONTROL_IE 0x10 + + +static struct uart_port ports[ULITE_NR_UARTS]; + +static int ulite_receive(struct uart_port *port, int stat) +{ + struct tty_struct *tty = port->info->tty; + unsigned char ch = 0; + char flag = TTY_NORMAL; + + if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN + | ULITE_STATUS_FRAME)) == 0) + return 0; + + /* stats */ + if (stat & ULITE_STATUS_RXVALID) { + port->icount.rx++; + ch = readb(port->membase + ULITE_RX); + + if (stat & ULITE_STATUS_PARITY) + port->icount.parity++; + } + + if (stat & ULITE_STATUS_OVERRUN) + port->icount.overrun++; + + if (stat & ULITE_STATUS_FRAME) + port->icount.frame++; + + + /* drop byte with parity error if IGNPAR specificed */ + if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY) + stat &= ~ULITE_STATUS_RXVALID; + + stat &= port->read_status_mask; + + if (stat & ULITE_STATUS_PARITY) + flag = TTY_PARITY; + + + stat &= ~port->ignore_status_mask; + + if (stat & ULITE_STATUS_RXVALID) + tty_insert_flip_char(tty, ch, flag); + + if (stat & ULITE_STATUS_FRAME) + tty_insert_flip_char(tty, 0, TTY_FRAME); + + if (stat & ULITE_STATUS_OVERRUN) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + return 1; +} + +static int ulite_transmit(struct uart_port *port, int stat) +{ + struct circ_buf *xmit = &port->info->xmit; + + if (stat & ULITE_STATUS_TXFULL) + return 0; + + if (port->x_char) { + writeb(port->x_char, port->membase + ULITE_TX); + port->x_char = 0; + port->icount.tx++; + return 1; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return 0; + + writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); + port->icount.tx++; + + /* wake up */ + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + return 1; +} + +static irqreturn_t ulite_isr(int irq, void *dev_id) +{ + struct uart_port *port = (struct uart_port *)dev_id; + int busy; + + do { + int stat = readb(port->membase + ULITE_STATUS); + busy = ulite_receive(port, stat); + busy |= ulite_transmit(port, stat); + } while (busy); + + tty_flip_buffer_push(port->info->tty); + + return IRQ_HANDLED; +} + +static unsigned int ulite_tx_empty(struct uart_port *port) +{ + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&port->lock, flags); + ret = readb(port->membase + ULITE_STATUS); + spin_unlock_irqrestore(&port->lock, flags); + + return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; +} + +static unsigned int ulite_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* N/A */ +} + +static void ulite_stop_tx(struct uart_port *port) +{ + /* N/A */ +} + +static void ulite_start_tx(struct uart_port *port) +{ + ulite_transmit(port, readb(port->membase + ULITE_STATUS)); +} + +static void ulite_stop_rx(struct uart_port *port) +{ + /* don't forward any more data (like !CREAD) */ + port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; +} + +static void ulite_enable_ms(struct uart_port *port) +{ + /* N/A */ +} + +static void ulite_break_ctl(struct uart_port *port, int ctl) +{ + /* N/A */ +} + +static int ulite_startup(struct uart_port *port) +{ + int ret; + + ret = request_irq(port->irq, ulite_isr, + IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "uartlite", port); + if (ret) + return ret; + + writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, + port->membase + ULITE_CONTROL); + writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + + return 0; +} + +static void ulite_shutdown(struct uart_port *port) +{ + writeb(0, port->membase + ULITE_CONTROL); + readb(port->membase + ULITE_CONTROL); /* dummy */ + free_irq(port->irq, port); +} + +static void ulite_set_termios(struct uart_port *port, struct termios *termios, + struct termios *old) +{ + unsigned long flags; + unsigned int baud; + + spin_lock_irqsave(&port->lock, flags); + + port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN + | ULITE_STATUS_TXFULL; + + if (termios->c_iflag & INPCK) + port->read_status_mask |= + ULITE_STATUS_PARITY | ULITE_STATUS_FRAME; + + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= ULITE_STATUS_PARITY + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; + + /* ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= + ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; + + /* update timeout */ + baud = uart_get_baud_rate(port, termios, old, 0, 460800); + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *ulite_type(struct uart_port *port) +{ + return port->type == PORT_UARTLITE ? "uartlite" : NULL; +} + +static void ulite_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, ULITE_REGION); + iounmap(port->membase); + port->membase = 0; +} + +static int ulite_request_port(struct uart_port *port) +{ + if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) { + dev_err(port->dev, "Memory region busy\n"); + return -EBUSY; + } + + port->membase = ioremap(port->mapbase, ULITE_REGION); + if (!port->membase) { + dev_err(port->dev, "Unable to map registers\n"); + release_mem_region(port->mapbase, ULITE_REGION); + return -EBUSY; + } + + return 0; +} + +static void ulite_config_port(struct uart_port *port, int flags) +{ + ulite_request_port(port); + port->type = PORT_UARTLITE; +} + +static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + /* we don't want the core code to modify any port params */ + return -EINVAL; +} + +static struct uart_ops ulite_ops = { + .tx_empty = ulite_tx_empty, + .set_mctrl = ulite_set_mctrl, + .get_mctrl = ulite_get_mctrl, + .stop_tx = ulite_stop_tx, + .start_tx = ulite_start_tx, + .stop_rx = ulite_stop_rx, + .enable_ms = ulite_enable_ms, + .break_ctl = ulite_break_ctl, + .startup = ulite_startup, + .shutdown = ulite_shutdown, + .set_termios = ulite_set_termios, + .type = ulite_type, + .release_port = ulite_release_port, + .request_port = ulite_request_port, + .config_port = ulite_config_port, + .verify_port = ulite_verify_port +}; + +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE +static void ulite_console_wait_tx(struct uart_port *port) +{ + int i; + + /* wait up to 10ms for the character(s) to be sent */ + for (i = 0; i < 10000; i++) { + if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY) + break; + udelay(1); + } +} + +static void ulite_console_putchar(struct uart_port *port, int ch) +{ + ulite_console_wait_tx(port); + writeb(ch, port->membase + ULITE_TX); +} + +static void ulite_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port = &ports[co->index]; + unsigned long flags; + unsigned int ier; + int locked = 1; + + if (oops_in_progress) { + locked = spin_trylock_irqsave(&port->lock, flags); + } else + spin_lock_irqsave(&port->lock, flags); + + /* save and disable interrupt */ + ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE; + writeb(0, port->membase + ULITE_CONTROL); + + uart_console_write(port, s, count, ulite_console_putchar); + + ulite_console_wait_tx(port); + + /* restore interrupt state */ + if (ier) + writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + + if (locked) + spin_unlock_irqrestore(&port->lock, flags); +} + +static int __init ulite_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= ULITE_NR_UARTS) + return -EINVAL; + + port = &ports[co->index]; + + /* not initialized yet? */ + if (!port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver ulite_uart_driver; + +static struct console ulite_console = { + .name = "ttyUL", + .write = ulite_console_write, + .device = uart_console_device, + .setup = ulite_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */ + .data = &ulite_uart_driver, +}; + +static int __init ulite_console_init(void) +{ + register_console(&ulite_console); + return 0; +} + +console_initcall(ulite_console_init); + +#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */ + +static struct uart_driver ulite_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "uartlite", + .dev_name = "ttyUL", + .major = ULITE_MAJOR, + .minor = ULITE_MINOR, + .nr = ULITE_NR_UARTS, +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE + .cons = &ulite_console, +#endif +}; + +static int __devinit ulite_probe(struct platform_device *pdev) +{ + struct resource *res, *res2; + struct uart_port *port; + + if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS) + return -EINVAL; + + if (ports[pdev->id].membase) + return -EBUSY; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res2) + return -ENODEV; + + port = &ports[pdev->id]; + + port->fifosize = 16; + port->regshift = 2; + port->iotype = UPIO_MEM; + port->iobase = 1; /* mark port in use */ + port->mapbase = res->start; + port->membase = 0; + port->ops = &ulite_ops; + port->irq = res2->start; + port->flags = UPF_BOOT_AUTOCONF; + port->dev = &pdev->dev; + port->type = PORT_UNKNOWN; + port->line = pdev->id; + + uart_add_one_port(&ulite_uart_driver, port); + platform_set_drvdata(pdev, port); + + return 0; +} + +static int ulite_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (port) + uart_remove_one_port(&ulite_uart_driver, port); + + /* mark port as free */ + port->membase = 0; + + return 0; +} + +static struct platform_driver ulite_platform_driver = { + .probe = ulite_probe, + .remove = ulite_remove, + .driver = { + .owner = THIS_MODULE, + .name = "uartlite", + }, +}; + +int __init ulite_init(void) +{ + int ret; + + ret = uart_register_driver(&ulite_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&ulite_platform_driver); + if (ret) + uart_unregister_driver(&ulite_uart_driver); + + return ret; +} + +void __exit ulite_exit(void) +{ + platform_driver_unregister(&ulite_platform_driver); + uart_unregister_driver(&ulite_uart_driver); +} + +module_init(ulite_init); +module_exit(ulite_exit); + +MODULE_AUTHOR("Peter Korsgaard "); +MODULE_DESCRIPTION("Xilinx uartlite serial driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 463ab953b092..827672136646 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -132,6 +132,8 @@ #define PORT_S3C2412 73 +/* Xilinx uartlite */ +#define PORT_UARTLITE 74 #ifdef __KERNEL__ -- cgit v1.2.3 From 48ed214d10ae3c3999af938970f7b5b58df77be3 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 6 Dec 2006 20:35:37 -0800 Subject: [PATCH] constify inode accessors Change the signature of i_size_read(), IMINOR() and IMAJOR() because they, or the functions they call, will never modify the argument. Signed-off-by: Jan Engelhardt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 94b831b8157c..d791bae9de9c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -636,7 +636,7 @@ extern void inode_double_unlock(struct inode *inode1, struct inode *inode2); * cmpxchg8b without the need of the lock prefix). For SMP compiles * and 64bit archs it makes no difference if preempt is enabled or not. */ -static inline loff_t i_size_read(struct inode *inode) +static inline loff_t i_size_read(const struct inode *inode) { #if BITS_PER_LONG==32 && defined(CONFIG_SMP) loff_t i_size; @@ -679,12 +679,12 @@ static inline void i_size_write(struct inode *inode, loff_t i_size) #endif } -static inline unsigned iminor(struct inode *inode) +static inline unsigned iminor(const struct inode *inode) { return MINOR(inode->i_rdev); } -static inline unsigned imajor(struct inode *inode) +static inline unsigned imajor(const struct inode *inode) { return MAJOR(inode->i_rdev); } -- cgit v1.2.3 From e9168c189fd54171124b5d25644024d99869e6a8 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 6 Dec 2006 20:35:38 -0800 Subject: [PATCH] fuse: update userspace interface to version 7.8 Add a flag to the RELEASE message which specifies that a FLUSH operation should be performed as well. This interface update is needed for the FreeBSD port, and doesn't actually touch the Linux implementation at all. Also rename the unused 'flush_flags' in the FLUSH message to 'unused'. Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fuse.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 9fc48a674b82..76336327a941 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -15,7 +15,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 7 +#define FUSE_KERNEL_MINOR_VERSION 8 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -92,6 +92,11 @@ struct fuse_file_lock { #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) +/** + * Release flags + */ +#define FUSE_RELEASE_FLUSH (1 << 0) + enum fuse_opcode { FUSE_LOOKUP = 1, FUSE_FORGET = 2, /* no reply */ @@ -205,12 +210,13 @@ struct fuse_open_out { struct fuse_release_in { __u64 fh; __u32 flags; - __u32 padding; + __u32 release_flags; + __u64 lock_owner; }; struct fuse_flush_in { __u64 fh; - __u32 flush_flags; + __u32 unused; __u32 padding; __u64 lock_owner; }; -- cgit v1.2.3 From b2d2272fae1e1df26ec8f93a6d5baea891dcce37 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 6 Dec 2006 20:35:51 -0800 Subject: [PATCH] fuse: add bmap support Add support for the BMAP operation for block device based filesystems. This is needed to support swap-files and lilo. Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fuse/dir.c | 2 ++ fs/fuse/file.c | 37 +++++++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 3 +++ include/linux/fuse.h | 11 +++++++++++ 4 files changed, 53 insertions(+) (limited to 'include/linux') diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 677f3ed7f987..1cabdb229adb 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1024,6 +1024,8 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) if (attr->ia_valid & ATTR_SIZE) { unsigned long limit; is_truncate = 1; + if (IS_SWAPFILE(inode)) + return -ETXTBSY; limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { send_sig(SIGXFSZ, current, 0); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 763a50daf1c0..128f79c40803 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -754,6 +754,42 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) return err; } +static sector_t fuse_bmap(struct address_space *mapping, sector_t block) +{ + struct inode *inode = mapping->host; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + struct fuse_bmap_in inarg; + struct fuse_bmap_out outarg; + int err; + + if (!inode->i_sb->s_bdev || fc->no_bmap) + return 0; + + req = fuse_get_req(fc); + if (IS_ERR(req)) + return 0; + + memset(&inarg, 0, sizeof(inarg)); + inarg.block = block; + inarg.blocksize = inode->i_sb->s_blocksize; + req->in.h.opcode = FUSE_BMAP; + req->in.h.nodeid = get_node_id(inode); + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (err == -ENOSYS) + fc->no_bmap = 1; + + return err ? 0 : outarg.block; +} + static const struct file_operations fuse_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, @@ -787,6 +823,7 @@ static const struct address_space_operations fuse_file_aops = { .commit_write = fuse_commit_write, .readpages = fuse_readpages, .set_page_dirty = fuse_set_page_dirty, + .bmap = fuse_bmap, }; void fuse_init_file_inode(struct inode *inode) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 91edb8932d90..58d482d9f6bb 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -339,6 +339,9 @@ struct fuse_conn { /** Is interrupt not implemented by fs? */ unsigned no_interrupt : 1; + /** Is bmap not implemented by fs? */ + unsigned no_bmap : 1; + /** The number of requests waiting for completion */ atomic_t num_waiting; diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 76336327a941..162a754f4db7 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -132,6 +132,7 @@ enum fuse_opcode { FUSE_ACCESS = 34, FUSE_CREATE = 35, FUSE_INTERRUPT = 36, + FUSE_BMAP = 37, }; /* The read buffer is required to be at least 8k, but may be much larger */ @@ -302,6 +303,16 @@ struct fuse_interrupt_in { __u64 unique; }; +struct fuse_bmap_in { + __u64 block; + __u32 blocksize; + __u32 padding; +}; + +struct fuse_bmap_out { + __u64 block; +}; + struct fuse_in_header { __u32 len; __u32 opcode; -- cgit v1.2.3 From 0ec7ca41f6f0f74a394a7d686bc0ee8afef84887 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 6 Dec 2006 20:35:52 -0800 Subject: [PATCH] fuse: add DESTROY operation Add a DESTROY operation for block device based filesystems. With the help of this operation, such a filesystem can flush dirty data to the device synchronously before the umount returns. This is needed in situations where the filesystem is assumed to be clean immediately after unmount (e.g. ejecting removable media). Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fuse/fuse_i.h | 6 ++++++ fs/fuse/inode.c | 22 ++++++++++++++++++++++ include/linux/fuse.h | 1 + 3 files changed, 29 insertions(+) (limited to 'include/linux') diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 58d482d9f6bb..b98b20de7405 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -298,6 +298,9 @@ struct fuse_conn { reply, before any other request, and never cleared */ unsigned conn_error : 1; + /** Connection successful. Only set in INIT */ + unsigned conn_init : 1; + /** Do readpages asynchronously? Only set in INIT */ unsigned async_read : 1; @@ -368,6 +371,9 @@ struct fuse_conn { /** Key for lock owner ID scrambling */ u32 scramble_key[4]; + + /** Reserved request for the DESTROY message */ + struct fuse_req *destroy_req; }; static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 1baaaeb2e850..437d61c65268 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -206,10 +206,23 @@ static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags) fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); } +static void fuse_send_destroy(struct fuse_conn *fc) +{ + struct fuse_req *req = fc->destroy_req; + if (req && fc->conn_init) { + fc->destroy_req = NULL; + req->in.h.opcode = FUSE_DESTROY; + req->force = 1; + request_send(fc, req); + fuse_put_request(fc, req); + } +} + static void fuse_put_super(struct super_block *sb) { struct fuse_conn *fc = get_fuse_conn_super(sb); + fuse_send_destroy(fc); spin_lock(&fc->lock); fc->connected = 0; fc->blocked = 0; @@ -410,6 +423,8 @@ static struct fuse_conn *new_conn(void) void fuse_conn_put(struct fuse_conn *fc) { if (atomic_dec_and_test(&fc->count)) { + if (fc->destroy_req) + fuse_request_free(fc->destroy_req); mutex_destroy(&fc->inst_mutex); kfree(fc); } @@ -466,6 +481,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); fc->minor = arg->minor; fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; + fc->conn_init = 1; } fuse_put_request(fc, req); fc->blocked = 0; @@ -563,6 +579,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) if (!init_req) goto err_put_root; + if (is_bdev) { + fc->destroy_req = fuse_request_alloc(); + if (!fc->destroy_req) + goto err_put_root; + } + mutex_lock(&fuse_mutex); err = -EINVAL; if (file->private_data) diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 162a754f4db7..534744efe30d 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -133,6 +133,7 @@ enum fuse_opcode { FUSE_CREATE = 35, FUSE_INTERRUPT = 36, FUSE_BMAP = 37, + FUSE_DESTROY = 38, }; /* The read buffer is required to be at least 8k, but may be much larger */ -- cgit v1.2.3 From e59e2ae2c29700117a54e85c106017c24837119f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 6 Dec 2006 20:35:59 -0800 Subject: [PATCH] SysRq-X: show blocked tasks Add SysRq-X support: show blocked (TASK_UNINTERRUPTIBLE) tasks only. Useful for debugging IO stalls. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/sysrq.c | 14 +++++++++++++- include/linux/sched.h | 11 ++++++++++- kernel/sched.c | 11 ++++++++--- 3 files changed, 31 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index c64f5bcff947..05810c8d20bc 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -182,6 +182,18 @@ static struct sysrq_key_op sysrq_showstate_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; +static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty) +{ + show_state_filter(TASK_UNINTERRUPTIBLE); +} +static struct sysrq_key_op sysrq_showstate_blocked_op = { + .handler = sysrq_handle_showstate_blocked, + .help_msg = "showBlockedTasks", + .action_msg = "Show Blocked State", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; + + static void sysrq_handle_showmem(int key, struct tty_struct *tty) { show_mem(); @@ -304,7 +316,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = { /* May be assigned at init time by SMP VOYAGER */ NULL, /* v */ NULL, /* w */ - NULL, /* x */ + &sysrq_showstate_blocked_op, /* x */ NULL, /* y */ NULL /* z */ }; diff --git a/include/linux/sched.h b/include/linux/sched.h index 837a012f573c..0a90cefb0b0d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -194,7 +194,16 @@ extern void init_idle(struct task_struct *idle, int cpu); extern cpumask_t nohz_cpu_mask; -extern void show_state(void); +/* + * Only dump TASK_* tasks. (-1 for all tasks) + */ +extern void show_state_filter(unsigned long state_filter); + +static inline void show_state(void) +{ + show_state_filter(-1); +} + extern void show_regs(struct pt_regs *); /* diff --git a/kernel/sched.c b/kernel/sched.c index 12fdbef1d9bf..1848e280504d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4804,7 +4804,7 @@ static void show_task(struct task_struct *p) show_stack(p, NULL); } -void show_state(void) +void show_state_filter(unsigned long state_filter) { struct task_struct *g, *p; @@ -4824,11 +4824,16 @@ void show_state(void) * console might take alot of time: */ touch_nmi_watchdog(); - show_task(p); + if (p->state & state_filter) + show_task(p); } while_each_thread(g, p); read_unlock(&tasklist_lock); - debug_show_all_locks(); + /* + * Only show locks if all tasks are dumped: + */ + if (state_filter == -1) + debug_show_all_locks(); } /** -- cgit v1.2.3 From 5ec68b2e310437e99c297ba04e1afc5297aa6de1 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 6 Dec 2006 20:36:14 -0800 Subject: [PATCH] pull in necessary header files for cdev.h linux/cdev.h uses struct kobject and other structs and should therefore include them. Currently, a module either needs to add the missing includes itself, or, in case a module includes other headers already, needs to put last, which goes against a alphabetically-sorted include list. Signed-off-by: Jan Engelhardt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cdev.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/cdev.h b/include/linux/cdev.h index ee5f53f2ca15..f309b00e986e 100644 --- a/include/linux/cdev.h +++ b/include/linux/cdev.h @@ -2,6 +2,10 @@ #define _LINUX_CDEV_H #ifdef __KERNEL__ +#include +#include +#include + struct cdev { struct kobject kobj; struct module *owner; -- cgit v1.2.3 From c140e110019f25ffa1c6f3f365b0c9103d0b8475 Mon Sep 17 00:00:00 2001 From: Ryan Underwood Date: Wed, 6 Dec 2006 20:36:38 -0800 Subject: [PATCH] parport_pc: Add support for OX16PCI952 parallel port Add support for the parallel port (implemented as separate PCI function) on the Oxford Semiconductor OX16PCI952. Signed-off-by: Ryan Underwood Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/parport/parport_pc.c | 4 ++++ include/linux/pci_ids.h | 1 + 2 files changed, 5 insertions(+) (limited to 'include/linux') diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 39c96641bc72..5749500f45f0 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2747,6 +2747,7 @@ enum parport_pc_pci_cards { titan_1284p2, avlab_1p, avlab_2p, + oxsemi_952, oxsemi_954, oxsemi_840, aks_0100, @@ -2822,6 +2823,7 @@ static struct parport_pc_pci { /* avlab_2p */ { 2, { { 0, 1}, { 2, 3 },} }, /* The Oxford Semi cards are unusual: 954 doesn't support ECP, * and 840 locks up if you write 1 to bit 2! */ + /* oxsemi_952 */ { 1, { { 0, 1 }, } }, /* oxsemi_954 */ { 1, { { 0, -1 }, } }, /* oxsemi_840 */ { 1, { { 0, -1 }, } }, /* aks_0100 */ { 1, { { 0, -1 }, } }, @@ -2895,6 +2897,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = { /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, /* AFAVLAB_TK9902 */ { 0x14db, 0x2121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2p}, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952PP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_952 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954PP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_954 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_12PCI840, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c09da1e30c54..dcdb90f06d73 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1864,6 +1864,7 @@ #define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511 #define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513 #define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521 +#define PCI_DEVICE_ID_OXSEMI_16PCI952PP 0x9523 #define PCI_VENDOR_ID_SAMSUNG 0x144d -- cgit v1.2.3 From 20aa7b21b1cbd1aa3fbf5fc14da5f7484a61a824 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 6 Dec 2006 20:36:40 -0800 Subject: [PATCH] probe_kernel_address() needs to do set_fs() probe_kernel_address() purports to be generic, only it forgot to select KERNEL_DS, so it presently won't work right on all architectures. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/uaccess.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/linux') diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index 67918c22339c..76c3fe325101 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -65,14 +65,22 @@ static inline unsigned long __copy_from_user_nocache(void *to, * do_page_fault() doesn't attempt to take mmap_sem. This makes * probe_kernel_address() suitable for use within regions where the caller * already holds mmap_sem, or other locks which nest inside mmap_sem. + * This must be a macro because __get_user() needs to know the types of the + * args. + * + * We don't include enough header files to be able to do the set_fs(). We + * require that the probe_kernel_address() caller will do that. */ #define probe_kernel_address(addr, retval) \ ({ \ long ret; \ + mm_segment_t old_fs = get_fs(); \ \ + set_fs(KERNEL_DS); \ pagefault_disable(); \ ret = __get_user(retval, addr); \ pagefault_enable(); \ + set_fs(old_fs); \ ret; \ }) -- cgit v1.2.3 From 115085ea0794c0f339be8f9d25505c7f9861d824 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 6 Dec 2006 20:36:51 -0800 Subject: [PATCH] taskstats: cleanup do_exit() path do_exit: taskstats_exit_alloc() ... taskstats_exit_send() taskstats_exit_free() I think this is not good, let it be a single function exported to the core kernel, taskstats_exit(), which does alloc + send + free itself. Signed-off-by: Oleg Nesterov Cc: Balbir Singh Cc: Shailabh Nagar Cc: Jay Lan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/taskstats_kern.h | 17 ++--------------- kernel/exit.c | 8 ++------ kernel/taskstats.c | 41 +++++++++++++++-------------------------- 3 files changed, 19 insertions(+), 47 deletions(-) (limited to 'include/linux') diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h index ce8a912e5426..f1261a532496 100644 --- a/include/linux/taskstats_kern.h +++ b/include/linux/taskstats_kern.h @@ -15,12 +15,6 @@ extern struct kmem_cache *taskstats_cache; extern struct mutex taskstats_exit_mutex; -static inline void taskstats_exit_free(struct taskstats *tidstats) -{ - if (tidstats) - kmem_cache_free(taskstats_cache, tidstats); -} - static inline void taskstats_tgid_init(struct signal_struct *sig) { sig->stats = NULL; @@ -54,17 +48,10 @@ static inline void taskstats_tgid_free(struct signal_struct *sig) kmem_cache_free(taskstats_cache, sig->stats); } -extern void taskstats_exit_alloc(struct taskstats **, unsigned int *); -extern void taskstats_exit_send(struct task_struct *, struct taskstats *, int, unsigned int); +extern void taskstats_exit(struct task_struct *, int group_dead); extern void taskstats_init_early(void); #else -static inline void taskstats_exit_alloc(struct taskstats **ptidstats, unsigned int *mycpu) -{} -static inline void taskstats_exit_free(struct taskstats *ptidstats) -{} -static inline void taskstats_exit_send(struct task_struct *tsk, - struct taskstats *tidstats, - int group_dead, unsigned int cpu) +static inline void taskstats_exit(struct task_struct *tsk, int group_dead) {} static inline void taskstats_tgid_init(struct signal_struct *sig) {} diff --git a/kernel/exit.c b/kernel/exit.c index 06de6c4e8ca3..4e3f919edc48 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -850,9 +850,7 @@ static void exit_notify(struct task_struct *tsk) fastcall NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; - struct taskstats *tidstats; int group_dead; - unsigned int mycpu; profile_task_exit(tsk); @@ -890,8 +888,6 @@ fastcall NORET_TYPE void do_exit(long code) current->comm, current->pid, preempt_count()); - taskstats_exit_alloc(&tidstats, &mycpu); - acct_update_integrals(tsk); if (tsk->mm) { update_hiwater_rss(tsk->mm); @@ -911,8 +907,8 @@ fastcall NORET_TYPE void do_exit(long code) #endif if (unlikely(tsk->audit_context)) audit_free(tsk); - taskstats_exit_send(tsk, tidstats, group_dead, mycpu); - taskstats_exit_free(tidstats); + + taskstats_exit(tsk, group_dead); exit_mm(tsk); diff --git a/kernel/taskstats.c b/kernel/taskstats.c index d9d7c3576238..2654886fe058 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -119,10 +119,10 @@ static int send_reply(struct sk_buff *skb, pid_t pid) /* * Send taskstats data in @skb to listeners registered for @cpu's exit data */ -static void send_cpu_listeners(struct sk_buff *skb, unsigned int cpu) +static void send_cpu_listeners(struct sk_buff *skb, + struct listener_list *listeners) { struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data); - struct listener_list *listeners; struct listener *s, *tmp; struct sk_buff *skb_next, *skb_cur = skb; void *reply = genlmsg_data(genlhdr); @@ -135,7 +135,6 @@ static void send_cpu_listeners(struct sk_buff *skb, unsigned int cpu) } rc = 0; - listeners = &per_cpu(listener_array, cpu); down_read(&listeners->sem); list_for_each_entry(s, &listeners->list, list) { skb_next = NULL; @@ -413,28 +412,12 @@ err: return rc; } -void taskstats_exit_alloc(struct taskstats **ptidstats, unsigned int *mycpu) -{ - struct listener_list *listeners; - /* - * This is the cpu on which the task is exiting currently and will - * be the one for which the exit event is sent, even if the cpu - * on which this function is running changes later. - */ - *mycpu = raw_smp_processor_id(); - - listeners = &per_cpu(listener_array, *mycpu); - - *ptidstats = NULL; - if (!list_empty(&listeners->list)) - *ptidstats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); -} - /* Send pid data out on exit */ -void taskstats_exit_send(struct task_struct *tsk, struct taskstats *tidstats, - int group_dead, unsigned int mycpu) +void taskstats_exit(struct task_struct *tsk, int group_dead) { int rc; + struct listener_list *listeners; + struct taskstats *tidstats; struct sk_buff *rep_skb; void *reply; size_t size; @@ -458,12 +441,17 @@ void taskstats_exit_send(struct task_struct *tsk, struct taskstats *tidstats, fill_tgid_exit(tsk); } + listeners = &__raw_get_cpu_var(listener_array); + if (list_empty(&listeners->list)) + return; + + tidstats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); if (!tidstats) return; rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, &reply, size); if (rc < 0) - goto ret; + goto free_stats; rc = fill_pid(tsk->pid, tsk, tidstats); if (rc < 0) @@ -492,15 +480,16 @@ void taskstats_exit_send(struct task_struct *tsk, struct taskstats *tidstats, nla_nest_end(rep_skb, na); send: - send_cpu_listeners(rep_skb, mycpu); + send_cpu_listeners(rep_skb, listeners); +free_stats: + kmem_cache_free(taskstats_cache, tidstats); return; nla_put_failure: genlmsg_cancel(rep_skb, reply); err_skb: nlmsg_free(rep_skb); -ret: - return; + goto free_stats; } static struct genl_ops taskstats_ops = { -- cgit v1.2.3 From 34ec12349c8a9505adc59d72f92b4595bc2483ff Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 6 Dec 2006 20:36:52 -0800 Subject: [PATCH] taskstats: cleanup ->signal->stats allocation Allocate ->signal->stats on demand in taskstats_exit(), this allows us to remove taskstats_tgid_alloc() (the last non-trivial inline) from taskstat's public interface. Signed-off-by: Oleg Nesterov Cc: Balbir Singh Cc: Shailabh Nagar Cc: Jay Lan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/taskstats_kern.h | 24 ------------------------ kernel/fork.c | 1 - kernel/taskstats.c | 26 +++++++++++++++++++++++++- 3 files changed, 25 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h index f1261a532496..7e9680f4afdd 100644 --- a/include/linux/taskstats_kern.h +++ b/include/linux/taskstats_kern.h @@ -20,28 +20,6 @@ static inline void taskstats_tgid_init(struct signal_struct *sig) sig->stats = NULL; } -static inline void taskstats_tgid_alloc(struct task_struct *tsk) -{ - struct signal_struct *sig = tsk->signal; - struct taskstats *stats; - - if (sig->stats != NULL) - return; - - /* No problem if kmem_cache_zalloc() fails */ - stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); - - spin_lock_irq(&tsk->sighand->siglock); - if (!sig->stats) { - sig->stats = stats; - stats = NULL; - } - spin_unlock_irq(&tsk->sighand->siglock); - - if (stats) - kmem_cache_free(taskstats_cache, stats); -} - static inline void taskstats_tgid_free(struct signal_struct *sig) { if (sig->stats) @@ -55,8 +33,6 @@ static inline void taskstats_exit(struct task_struct *tsk, int group_dead) {} static inline void taskstats_tgid_init(struct signal_struct *sig) {} -static inline void taskstats_tgid_alloc(struct task_struct *tsk) -{} static inline void taskstats_tgid_free(struct signal_struct *sig) {} static inline void taskstats_init_early(void) diff --git a/kernel/fork.c b/kernel/fork.c index f37980df1d58..658838148647 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -847,7 +847,6 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts if (clone_flags & CLONE_THREAD) { atomic_inc(¤t->signal->count); atomic_inc(¤t->signal->live); - taskstats_tgid_alloc(current); return 0; } sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL); diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 2654886fe058..7d793d6b1e90 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -412,6 +412,30 @@ err: return rc; } +static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk) +{ + struct signal_struct *sig = tsk->signal; + struct taskstats *stats; + + if (sig->stats || thread_group_empty(tsk)) + goto ret; + + /* No problem if kmem_cache_zalloc() fails */ + stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); + + spin_lock_irq(&tsk->sighand->siglock); + if (!sig->stats) { + sig->stats = stats; + stats = NULL; + } + spin_unlock_irq(&tsk->sighand->siglock); + + if (stats) + kmem_cache_free(taskstats_cache, stats); +ret: + return sig->stats; +} + /* Send pid data out on exit */ void taskstats_exit(struct task_struct *tsk, int group_dead) { @@ -433,7 +457,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead) size = nla_total_size(sizeof(u32)) + nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); - is_thread_group = (tsk->signal->stats != NULL); + is_thread_group = !!taskstats_tgid_alloc(tsk); if (is_thread_group) { /* PID + STATS + TGID + STATS */ size = 2 * size; -- cgit v1.2.3 From 9774a1f54f173ad18e816496c8979f1bf8ef666a Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 6 Dec 2006 20:36:56 -0800 Subject: [PATCH] Compile-time check re world-writeable module params One of the mistakes a module_param() user can make is to supply default value of module parameter as the last argument. module_param() accepts permissions instead. If default value is, say, 3 (-------wx), parameter becomes world-writeable. So far, the only remedy was to apply grep(1) and read drivers submitted to -mm. BTDT. With this patch applied, compiler will finally do some job. *) bounds checking on permissions *) world-writeable bit checking on permissions *) compile breakage if checks trigger First version of this check (only "& 2" part) directly caught 4 out of 7 places during my last grep. Subject: Neverending module_param() bugs [X] drivers/acpi/sbs.c:101:module_param(capacity_mode, int, CAPACITY_UNIT); [X] drivers/acpi/sbs.c:102:module_param(update_mode, int, UPDATE_MODE); [ ] drivers/acpi/sbs.c:103:module_param(update_info_mode, int, UPDATE_INFO_MODE); [ ] drivers/acpi/sbs.c:104:module_param(update_time, int, UPDATE_TIME); [ ] drivers/acpi/sbs.c:105:module_param(update_time2, int, UPDATE_TIME2); [X] drivers/char/watchdog/sbc8360.c:203:module_param(timeout, int, 27); [X] drivers/media/video/tuner-simple.c:13:module_param(offset, int, 0666); Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/moduleparam.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 7c0c2c198f1f..4a189dadb160 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -63,6 +63,9 @@ struct kparam_array not there, read bits mean it's readable, write bits mean it's writable. */ #define __module_param_call(prefix, name, set, get, arg, perm) \ + /* Default value instead of permissions? */ \ + static int __param_perm_check_##name __attribute__((unused)) = \ + BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)); \ static char __param_str_##name[] = prefix #name; \ static struct kernel_param const __param_##name \ __attribute_used__ \ -- cgit v1.2.3 From e0980dafa329d33bb88edc8a3ef9fab4e070590c Mon Sep 17 00:00:00 2001 From: Paul B Schroeder Date: Wed, 6 Dec 2006 20:37:03 -0800 Subject: [PATCH] Exar quad port serial This is on our "Envoy" boxes which we have, according to the documentation, an "Exar ST16C554/554D Quad UART with 16-byte Fifo's". The box also has two other "on-board" serial ports and a modem chip. The two on-board serial UARTs were being detected along with the first two Exar UARTs. The last two Exar UARTs were not showing up and neither was the modem. This patch was the only way I could the kernel to see beyond the standard four serial ports and get all four of the Exar UARTs to show up. [akpm@osdl.org: build fix] Signed-off-by: Paul B Schroeder Cc: Lennart Sorensen Acked-by: Alan Cox Cc: Russell King Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/serial/8250_exar_st16c554.c | 52 +++++++++++++++++++++++++++++++++++++ drivers/serial/Kconfig | 11 ++++++++ drivers/serial/Makefile | 1 + include/linux/serial_8250.h | 1 + 4 files changed, 65 insertions(+) create mode 100644 drivers/serial/8250_exar_st16c554.c (limited to 'include/linux') diff --git a/drivers/serial/8250_exar_st16c554.c b/drivers/serial/8250_exar_st16c554.c new file mode 100644 index 000000000000..567143ace159 --- /dev/null +++ b/drivers/serial/8250_exar_st16c554.c @@ -0,0 +1,52 @@ +/* + * linux/drivers/serial/8250_exar.c + * + * Written by Paul B Schroeder < pschroeder "at" uplogix "dot" com > + * Based on 8250_boca. + * + * Copyright (C) 2005 Russell King. + * Data taken from include/asm-i386/serial.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#define PORT(_base,_irq) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF, \ + } + +static struct plat_serial8250_port exar_data[] = { + PORT(0x100, 5), + PORT(0x108, 5), + PORT(0x110, 5), + PORT(0x118, 5), + { }, +}; + +static struct platform_device exar_device = { + .name = "serial8250", + .id = PLAT8250_DEV_EXAR_ST16C554, + .dev = { + .platform_data = exar_data, + }, +}; + +static int __init exar_init(void) +{ + return platform_device_register(&exar_device); +} + +module_init(exar_init); + +MODULE_AUTHOR("Paul B Schroeder"); +MODULE_DESCRIPTION("8250 serial probe module for Exar cards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e936c91640b4..fc12d5df10e2 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -210,6 +210,17 @@ config SERIAL_8250_BOCA To compile this driver as a module, choose M here: the module will be called 8250_boca. +config SERIAL_8250_EXAR_ST16C554 + tristate "Support Exar ST16C554/554D Quad UART" + depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS + help + The Uplogix Envoy TU301 uses this Exar Quad UART. If you are + tinkering with your Envoy TU301, or have a machine with this UART, + say Y here. + + To compile this driver as a module, choose M here: the module + will be called 8250_exar_st16c554. + config SERIAL_8250_HUB6 tristate "Support Hub6 cards" depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 0dba0017a006..df3632cd7df9 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o +obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o obj-$(CONFIG_SERIAL_8250_AU1X00) += 8250_au1x00.o diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 8e9681413726..71310d80c09a 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -41,6 +41,7 @@ enum { PLAT8250_DEV_FOURPORT, PLAT8250_DEV_ACCENT, PLAT8250_DEV_BOCA, + PLAT8250_DEV_EXAR_ST16C554, PLAT8250_DEV_HUB6, PLAT8250_DEV_MCA, PLAT8250_DEV_AU1X00, -- cgit v1.2.3 From 3a229b39eb8497ae5f8077f81f7c8c3e1aacd624 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 6 Dec 2006 20:37:14 -0800 Subject: [PATCH] ext3: uninline large functions Saves nearly 4kbytes on x86. Cc: Arnaldo Carvalho de Melo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/Makefile | 2 +- fs/ext3/ext3_jbd.c | 59 +++++++++++++++++++++++++++++++++++++ include/linux/ext3_jbd.h | 76 +++++++++++------------------------------------- 3 files changed, 77 insertions(+), 60 deletions(-) create mode 100644 fs/ext3/ext3_jbd.c (limited to 'include/linux') diff --git a/fs/ext3/Makefile b/fs/ext3/Makefile index 704cd44a40c2..e77766a8b3f0 100644 --- a/fs/ext3/Makefile +++ b/fs/ext3/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_EXT3_FS) += ext3.o ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o hash.o resize.o + ioctl.o namei.o super.o symlink.o hash.o resize.o ext3_jbd.o ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o diff --git a/fs/ext3/ext3_jbd.c b/fs/ext3/ext3_jbd.c new file mode 100644 index 000000000000..e1f91fd26a93 --- /dev/null +++ b/fs/ext3/ext3_jbd.c @@ -0,0 +1,59 @@ +/* + * Interface between ext3 and JBD + */ + +#include + +int __ext3_journal_get_undo_access(const char *where, handle_t *handle, + struct buffer_head *bh) +{ + int err = journal_get_undo_access(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +int __ext3_journal_get_write_access(const char *where, handle_t *handle, + struct buffer_head *bh) +{ + int err = journal_get_write_access(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +int __ext3_journal_forget(const char *where, handle_t *handle, + struct buffer_head *bh) +{ + int err = journal_forget(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +int __ext3_journal_revoke(const char *where, handle_t *handle, + unsigned long blocknr, struct buffer_head *bh) +{ + int err = journal_revoke(handle, blocknr, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +int __ext3_journal_get_create_access(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = journal_get_create_access(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +int __ext3_journal_dirty_metadata(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = journal_dirty_metadata(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h index ce0e6109aff0..8c43b13a02fe 100644 --- a/include/linux/ext3_jbd.h +++ b/include/linux/ext3_jbd.h @@ -109,74 +109,32 @@ int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode); * been done yet. */ -void ext3_journal_abort_handle(const char *caller, const char *err_fn, - struct buffer_head *bh, handle_t *handle, int err); - -static inline int -__ext3_journal_get_undo_access(const char *where, handle_t *handle, - struct buffer_head *bh) +static inline void ext3_journal_release_buffer(handle_t *handle, + struct buffer_head *bh) { - int err = journal_get_undo_access(handle, bh); - if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; + journal_release_buffer(handle, bh); } -static inline int -__ext3_journal_get_write_access(const char *where, handle_t *handle, - struct buffer_head *bh) -{ - int err = journal_get_write_access(handle, bh); - if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} +void ext3_journal_abort_handle(const char *caller, const char *err_fn, + struct buffer_head *bh, handle_t *handle, int err); -static inline void -ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh) -{ - journal_release_buffer(handle, bh); -} +int __ext3_journal_get_undo_access(const char *where, handle_t *handle, + struct buffer_head *bh); -static inline int -__ext3_journal_forget(const char *where, handle_t *handle, struct buffer_head *bh) -{ - int err = journal_forget(handle, bh); - if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} +int __ext3_journal_get_write_access(const char *where, handle_t *handle, + struct buffer_head *bh); -static inline int -__ext3_journal_revoke(const char *where, handle_t *handle, - unsigned long blocknr, struct buffer_head *bh) -{ - int err = journal_revoke(handle, blocknr, bh); - if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} +int __ext3_journal_forget(const char *where, handle_t *handle, + struct buffer_head *bh); -static inline int -__ext3_journal_get_create_access(const char *where, - handle_t *handle, struct buffer_head *bh) -{ - int err = journal_get_create_access(handle, bh); - if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} +int __ext3_journal_revoke(const char *where, handle_t *handle, + unsigned long blocknr, struct buffer_head *bh); -static inline int -__ext3_journal_dirty_metadata(const char *where, - handle_t *handle, struct buffer_head *bh) -{ - int err = journal_dirty_metadata(handle, bh); - if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} +int __ext3_journal_get_create_access(const char *where, + handle_t *handle, struct buffer_head *bh); +int __ext3_journal_dirty_metadata(const char *where, + handle_t *handle, struct buffer_head *bh); #define ext3_journal_get_undo_access(handle, bh) \ __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh)) -- cgit v1.2.3 From 8984d137df669a6e94dbce7b87095e4ce80b9e67 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 6 Dec 2006 20:37:15 -0800 Subject: [PATCH] ext4: uninline large functions Saves nearly 4kbytes on x86. Cc: Arnaldo Carvalho de Melo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/Makefile | 3 +- fs/ext4/ext4_jbd2.c | 59 ++++++++++++++++++++++++++++++++++++ include/linux/ext4_jbd2.h | 76 +++++++++++------------------------------------ 3 files changed, 78 insertions(+), 60 deletions(-) create mode 100644 fs/ext4/ext4_jbd2.c (limited to 'include/linux') diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index a6acb96ebeb9..ae6e7e502ac9 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -5,7 +5,8 @@ obj-$(CONFIG_EXT4DEV_FS) += ext4dev.o ext4dev-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o + ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ + ext4_jbd2.o ext4dev-$(CONFIG_EXT4DEV_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o ext4dev-$(CONFIG_EXT4DEV_FS_POSIX_ACL) += acl.o diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c new file mode 100644 index 000000000000..d6afe4e27340 --- /dev/null +++ b/fs/ext4/ext4_jbd2.c @@ -0,0 +1,59 @@ +/* + * Interface between ext4 and JBD + */ + +#include + +int __ext4_journal_get_undo_access(const char *where, handle_t *handle, + struct buffer_head *bh) +{ + int err = jbd2_journal_get_undo_access(handle, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +int __ext4_journal_get_write_access(const char *where, handle_t *handle, + struct buffer_head *bh) +{ + int err = jbd2_journal_get_write_access(handle, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +int __ext4_journal_forget(const char *where, handle_t *handle, + struct buffer_head *bh) +{ + int err = jbd2_journal_forget(handle, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +int __ext4_journal_revoke(const char *where, handle_t *handle, + ext4_fsblk_t blocknr, struct buffer_head *bh) +{ + int err = jbd2_journal_revoke(handle, blocknr, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +int __ext4_journal_get_create_access(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = jbd2_journal_get_create_access(handle, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +int __ext4_journal_dirty_metadata(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = jbd2_journal_dirty_metadata(handle, bh); + if (err) + ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} diff --git a/include/linux/ext4_jbd2.h b/include/linux/ext4_jbd2.h index 72dd631912e4..d716e6392cf6 100644 --- a/include/linux/ext4_jbd2.h +++ b/include/linux/ext4_jbd2.h @@ -114,74 +114,32 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode); * been done yet. */ -void ext4_journal_abort_handle(const char *caller, const char *err_fn, - struct buffer_head *bh, handle_t *handle, int err); - -static inline int -__ext4_journal_get_undo_access(const char *where, handle_t *handle, - struct buffer_head *bh) +static inline void ext4_journal_release_buffer(handle_t *handle, + struct buffer_head *bh) { - int err = jbd2_journal_get_undo_access(handle, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; + jbd2_journal_release_buffer(handle, bh); } -static inline int -__ext4_journal_get_write_access(const char *where, handle_t *handle, - struct buffer_head *bh) -{ - int err = jbd2_journal_get_write_access(handle, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} +void ext4_journal_abort_handle(const char *caller, const char *err_fn, + struct buffer_head *bh, handle_t *handle, int err); -static inline void -ext4_journal_release_buffer(handle_t *handle, struct buffer_head *bh) -{ - jbd2_journal_release_buffer(handle, bh); -} +int __ext4_journal_get_undo_access(const char *where, handle_t *handle, + struct buffer_head *bh); -static inline int -__ext4_journal_forget(const char *where, handle_t *handle, struct buffer_head *bh) -{ - int err = jbd2_journal_forget(handle, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} +int __ext4_journal_get_write_access(const char *where, handle_t *handle, + struct buffer_head *bh); -static inline int -__ext4_journal_revoke(const char *where, handle_t *handle, - ext4_fsblk_t blocknr, struct buffer_head *bh) -{ - int err = jbd2_journal_revoke(handle, blocknr, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} +int __ext4_journal_forget(const char *where, handle_t *handle, + struct buffer_head *bh); -static inline int -__ext4_journal_get_create_access(const char *where, - handle_t *handle, struct buffer_head *bh) -{ - int err = jbd2_journal_get_create_access(handle, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} +int __ext4_journal_revoke(const char *where, handle_t *handle, + ext4_fsblk_t blocknr, struct buffer_head *bh); -static inline int -__ext4_journal_dirty_metadata(const char *where, - handle_t *handle, struct buffer_head *bh) -{ - int err = jbd2_journal_dirty_metadata(handle, bh); - if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} +int __ext4_journal_get_create_access(const char *where, + handle_t *handle, struct buffer_head *bh); +int __ext4_journal_dirty_metadata(const char *where, + handle_t *handle, struct buffer_head *bh); #define ext4_journal_get_undo_access(handle, bh) \ __ext4_journal_get_undo_access(__FUNCTION__, (handle), (bh)) -- cgit v1.2.3 From 6cfd76a26d9fe2ba54b9d496a48c1d9285e5c5ed Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 6 Dec 2006 20:37:22 -0800 Subject: [PATCH] lockdep: name some old style locks Name some of the remaning 'old_style_spin_init' locks Signed-off-by: Peter Zijlstra Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/traps.c | 2 +- include/asm-i386/rwsem.h | 4 ++-- include/linux/init_task.h | 2 +- include/linux/mutex.h | 2 +- include/linux/rtmutex.h | 2 +- include/linux/rwsem-spinlock.h | 3 ++- include/linux/sunrpc/sched.h | 4 ++-- kernel/acct.c | 3 ++- kernel/irq/handle.c | 2 +- net/sunrpc/svcauth.c | 3 ++- security/keys/process_keys.c | 2 +- 11 files changed, 16 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index fe9c5e8e7e6f..3124f1b04d67 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -452,7 +452,7 @@ void die(const char * str, struct pt_regs * regs, long err) u32 lock_owner; int lock_owner_depth; } die = { - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(die.lock), .lock_owner = -1, .lock_owner_depth = 0 }; diff --git a/include/asm-i386/rwsem.h b/include/asm-i386/rwsem.h index bc598d6388e3..041906f3c6df 100644 --- a/include/asm-i386/rwsem.h +++ b/include/asm-i386/rwsem.h @@ -75,8 +75,8 @@ struct rw_semaphore { #define __RWSEM_INITIALIZER(name) \ -{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \ - __RWSEM_DEP_MAP_INIT(name) } +{ RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \ + LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) } #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 33c5daacc743..733790d4f7db 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -73,7 +73,7 @@ extern struct nsproxy init_nsproxy; #define INIT_NSPROXY(nsproxy) { \ .count = ATOMIC_INIT(1), \ - .nslock = SPIN_LOCK_UNLOCKED, \ + .nslock = __SPIN_LOCK_UNLOCKED(nsproxy.nslock), \ .uts_ns = &init_uts_ns, \ .namespace = NULL, \ INIT_IPC_NS(ipc_ns) \ diff --git a/include/linux/mutex.h b/include/linux/mutex.h index 27c48daa3183..b2b91c477563 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -94,7 +94,7 @@ do { \ #define __MUTEX_INITIALIZER(lockname) \ { .count = ATOMIC_INIT(1) \ - , .wait_lock = SPIN_LOCK_UNLOCKED \ + , .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \ , .wait_list = LIST_HEAD_INIT(lockname.wait_list) \ __DEBUG_MUTEX_INITIALIZER(lockname) \ __DEP_MAP_MUTEX_INITIALIZER(lockname) } diff --git a/include/linux/rtmutex.h b/include/linux/rtmutex.h index 5d41dee82f80..b0090e9f7884 100644 --- a/include/linux/rtmutex.h +++ b/include/linux/rtmutex.h @@ -63,7 +63,7 @@ struct hrtimer_sleeper; #endif #define __RT_MUTEX_INITIALIZER(mutexname) \ - { .wait_lock = SPIN_LOCK_UNLOCKED \ + { .wait_lock = __SPIN_LOCK_UNLOCKED(mutexname.wait_lock) \ , .wait_list = PLIST_HEAD_INIT(mutexname.wait_list, mutexname.wait_lock) \ , .owner = NULL \ __DEBUG_RT_MUTEX_INITIALIZER(mutexname)} diff --git a/include/linux/rwsem-spinlock.h b/include/linux/rwsem-spinlock.h index ae1fcadd598e..813cee13da0d 100644 --- a/include/linux/rwsem-spinlock.h +++ b/include/linux/rwsem-spinlock.h @@ -44,7 +44,8 @@ struct rw_semaphore { #endif #define __RWSEM_INITIALIZER(name) \ -{ 0, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) } +{ 0, __SPIN_LOCK_UNLOCKED(name.wait_lock), LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) } #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index f399c138f79d..0746c3b16f3a 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -222,7 +222,7 @@ struct rpc_wait_queue { #ifndef RPC_DEBUG # define RPC_WAITQ_INIT(var,qname) { \ - .lock = SPIN_LOCK_UNLOCKED, \ + .lock = __SPIN_LOCK_UNLOCKED(var.lock), \ .tasks = { \ [0] = LIST_HEAD_INIT(var.tasks[0]), \ [1] = LIST_HEAD_INIT(var.tasks[1]), \ @@ -231,7 +231,7 @@ struct rpc_wait_queue { } #else # define RPC_WAITQ_INIT(var,qname) { \ - .lock = SPIN_LOCK_UNLOCKED, \ + .lock = __SPIN_LOCK_UNLOCKED(var.lock), \ .tasks = { \ [0] = LIST_HEAD_INIT(var.tasks[0]), \ [1] = LIST_HEAD_INIT(var.tasks[1]), \ diff --git a/kernel/acct.c b/kernel/acct.c index 0aad5ca36a81..dc12db8600e7 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -89,7 +89,8 @@ struct acct_glbs { struct timer_list timer; }; -static struct acct_glbs acct_globals __cacheline_aligned = {SPIN_LOCK_UNLOCKED}; +static struct acct_glbs acct_globals __cacheline_aligned = + {__SPIN_LOCK_UNLOCKED(acct_globals.lock)}; /* * Called whenever the timer says to check the free space. diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index a681912bc89a..aff1f0fabb0d 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -54,7 +54,7 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned = { .chip = &no_irq_chip, .handle_irq = handle_bad_irq, .depth = 1, - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock), #ifdef CONFIG_SMP .affinity = CPU_MASK_ALL #endif diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index ee9bb1522d5e..c7bb5f7f21a5 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c @@ -119,7 +119,8 @@ EXPORT_SYMBOL(svc_auth_unregister); #define DN_HASHMASK (DN_HASHMAX-1) static struct hlist_head auth_domain_table[DN_HASHMAX]; -static spinlock_t auth_domain_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t auth_domain_lock = + __SPIN_LOCK_UNLOCKED(auth_domain_lock); void auth_domain_put(struct auth_domain *dom) { diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 32150cf7c37f..b6f86808475a 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -27,7 +27,7 @@ static DEFINE_MUTEX(key_session_mutex); struct key_user root_key_user = { .usage = ATOMIC_INIT(3), .consq = LIST_HEAD_INIT(root_key_user.consq), - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), .nkeys = ATOMIC_INIT(2), .nikeys = ATOMIC_INIT(2), .uid = 0, -- cgit v1.2.3 From ece8a684c75df215320b4155944979e3f78c5c93 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 6 Dec 2006 20:37:24 -0800 Subject: [PATCH] sleep profiling Implement prof=sleep profiling. TASK_UNINTERRUPTIBLE sleeps will be taken as a profile hit, and every millisecond spent sleeping causes a profile-hit for the call site that initiated the sleep. Sample readprofile output on i386: 306 ps2_sendbyte 1.3973 432 call_usermodehelper_keys 1.9548 484 ps2_command 0.6453 790 __driver_attach 4.7879 1593 msleep 44.2500 3976 sync_buffer 64.1290 4076 do_lookup 12.4648 8587 sync_page 122.6714 20820 total 0.0067 (NOTE: architectures need to check whether get_wchan() can be called from deep within the wakeup path.) akpm: we need to mark more functions __sched. lock_sock(), msleep(), others.. akpm: the contention in do_lookup() is a surprise. Presumably doing disk reads for directory contents while holding i_mutex. [akpm@osdl.org: various fixes] Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 1 + include/linux/profile.h | 24 ++++++++++++++++++++++- kernel/profile.c | 39 ++++++++++++++++++++++++++++--------- kernel/sched.c | 11 +++++++++++ 4 files changed, 65 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 8fe6b834ef27..2a40d9f6ffad 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1294,6 +1294,7 @@ and is between 256 and 4096 characters. It is defined in the file Param: "schedule" - profile schedule points. Param: - step/bucket size as a power of 2 for statistical time based profiling. + Param: "sleep" - profile D-state sleeping (millisecs) processor.max_cstate= [HW,ACPI] Limit processor to maximum C-state diff --git a/include/linux/profile.h b/include/linux/profile.h index acce53fd38b6..5670b340c4ef 100644 --- a/include/linux/profile.h +++ b/include/linux/profile.h @@ -6,10 +6,15 @@ #include #include #include +#include + #include +extern int prof_on __read_mostly; + #define CPU_PROFILING 1 #define SCHED_PROFILING 2 +#define SLEEP_PROFILING 3 struct proc_dir_entry; struct pt_regs; @@ -18,7 +23,24 @@ struct notifier_block; /* init basic kernel profiler */ void __init profile_init(void); void profile_tick(int); -void profile_hit(int, void *); + +/* + * Add multiple profiler hits to a given address: + */ +void profile_hits(int, void *ip, unsigned int nr_hits); + +/* + * Single profiler hit: + */ +static inline void profile_hit(int type, void *ip) +{ + /* + * Speedup for the common (no profiling enabled) case: + */ + if (unlikely(prof_on == type)) + profile_hits(type, ip, 1); +} + #ifdef CONFIG_PROC_FS void create_prof_cpu_mask(struct proc_dir_entry *); #else diff --git a/kernel/profile.c b/kernel/profile.c index 15b012df4ff1..04fd84e8cdbe 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -40,7 +40,7 @@ int (*timer_hook)(struct pt_regs *) __read_mostly; static atomic_t *prof_buffer; static unsigned long prof_len, prof_shift; -static int prof_on __read_mostly; +int prof_on __read_mostly; static cpumask_t prof_cpu_mask = CPU_MASK_ALL; #ifdef CONFIG_SMP static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits); @@ -51,9 +51,19 @@ static DEFINE_MUTEX(profile_flip_mutex); static int __init profile_setup(char * str) { static char __initdata schedstr[] = "schedule"; + static char __initdata sleepstr[] = "sleep"; int par; - if (!strncmp(str, schedstr, strlen(schedstr))) { + if (!strncmp(str, sleepstr, strlen(sleepstr))) { + prof_on = SLEEP_PROFILING; + if (str[strlen(sleepstr)] == ',') + str += strlen(sleepstr) + 1; + if (get_option(&str, &par)) + prof_shift = par; + printk(KERN_INFO + "kernel sleep profiling enabled (shift: %ld)\n", + prof_shift); + } else if (!strncmp(str, sleepstr, strlen(sleepstr))) { prof_on = SCHED_PROFILING; if (str[strlen(schedstr)] == ',') str += strlen(schedstr) + 1; @@ -204,7 +214,8 @@ EXPORT_SYMBOL_GPL(profile_event_unregister); * positions to which hits are accounted during short intervals (e.g. * several seconds) is usually very small. Exclusion from buffer * flipping is provided by interrupt disablement (note that for - * SCHED_PROFILING profile_hit() may be called from process context). + * SCHED_PROFILING or SLEEP_PROFILING profile_hit() may be called from + * process context). * The hash function is meant to be lightweight as opposed to strong, * and was vaguely inspired by ppc64 firmware-supported inverted * pagetable hash functions, but uses a full hashtable full of finite @@ -257,7 +268,7 @@ static void profile_discard_flip_buffers(void) mutex_unlock(&profile_flip_mutex); } -void profile_hit(int type, void *__pc) +void profile_hits(int type, void *__pc, unsigned int nr_hits) { unsigned long primary, secondary, flags, pc = (unsigned long)__pc; int i, j, cpu; @@ -274,21 +285,31 @@ void profile_hit(int type, void *__pc) put_cpu(); return; } + /* + * We buffer the global profiler buffer into a per-CPU + * queue and thus reduce the number of global (and possibly + * NUMA-alien) accesses. The write-queue is self-coalescing: + */ local_irq_save(flags); do { for (j = 0; j < PROFILE_GRPSZ; ++j) { if (hits[i + j].pc == pc) { - hits[i + j].hits++; + hits[i + j].hits += nr_hits; goto out; } else if (!hits[i + j].hits) { hits[i + j].pc = pc; - hits[i + j].hits = 1; + hits[i + j].hits = nr_hits; goto out; } } i = (i + secondary) & (NR_PROFILE_HIT - 1); } while (i != primary); - atomic_inc(&prof_buffer[pc]); + + /* + * Add the current hit(s) and flush the write-queue out + * to the global buffer: + */ + atomic_add(nr_hits, &prof_buffer[pc]); for (i = 0; i < NR_PROFILE_HIT; ++i) { atomic_add(hits[i].hits, &prof_buffer[hits[i].pc]); hits[i].pc = hits[i].hits = 0; @@ -356,14 +377,14 @@ static int __devinit profile_cpu_callback(struct notifier_block *info, #define profile_flip_buffers() do { } while (0) #define profile_discard_flip_buffers() do { } while (0) -void profile_hit(int type, void *__pc) +void profile_hits(int type, void *__pc, unsigned int nr_hits) { unsigned long pc; if (prof_on != type || !prof_buffer) return; pc = ((unsigned long)__pc - (unsigned long)_stext) >> prof_shift; - atomic_inc(&prof_buffer[min(pc, prof_len - 1)]); + atomic_add(nr_hits, &prof_buffer[min(pc, prof_len - 1)]); } #endif /* !CONFIG_SMP */ diff --git a/kernel/sched.c b/kernel/sched.c index 343e1794233e..75a005ed4eda 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -948,6 +948,17 @@ static void activate_task(struct task_struct *p, struct rq *rq, int local) } #endif + /* + * Sleep time is in units of nanosecs, so shift by 20 to get a + * milliseconds-range estimation of the amount of time that the task + * spent sleeping: + */ + if (unlikely(prof_on == SLEEP_PROFILING)) { + if (p->state == TASK_UNINTERRUPTIBLE) + profile_hits(SLEEP_PROFILING, (void *)get_wchan(p), + (now - p->timestamp) >> 20); + } + if (!rt_task(p)) p->prio = recalc_task_prio(p, now); -- cgit v1.2.3 From d5abe669172f20a4129a711de0f250a4e07db298 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 6 Dec 2006 20:37:26 -0800 Subject: [PATCH] debug: workqueue locking sanity Workqueue functions should not leak locks, assert so, printing the last function ran. Use macros in lockdep.h to avoid include dependency pains. [akpm@osdl.org: build fix] Signed-off-by: Peter Zijlstra Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/lockdep.h | 5 +++++ kernel/workqueue.c | 13 +++++++++++++ 2 files changed, 18 insertions(+) (limited to 'include/linux') diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 819f08f1310d..da19aeb0dbe8 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -243,6 +243,8 @@ extern void lock_release(struct lockdep_map *lock, int nested, # define INIT_LOCKDEP .lockdep_recursion = 0, +#define lockdep_depth(tsk) ((tsk)->lockdep_depth) + #else /* !LOCKDEP */ static inline void lockdep_off(void) @@ -277,6 +279,9 @@ static inline int lockdep_internal(void) * The class key takes no space if lockdep is disabled: */ struct lock_class_key { }; + +#define lockdep_depth(tsk) (0) + #endif /* !LOCKDEP */ #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 2945b094d871..5484d6e045c2 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include /* * The per-CPU workqueue (if single thread, we always use the first @@ -253,6 +255,17 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq) work_release(work); f(work); + if (unlikely(in_atomic() || lockdep_depth(current) > 0)) { + printk(KERN_ERR "BUG: workqueue leaked lock or atomic: " + "%s/0x%08x/%d\n", + current->comm, preempt_count(), + current->pid); + printk(KERN_ERR " last function: "); + print_symbol("%s\n", (unsigned long)f); + debug_show_held_locks(current); + dump_stack(); + } + spin_lock_irqsave(&cwq->lock, flags); cwq->remove_sequence++; wake_up(&cwq->work_done); -- cgit v1.2.3 From 04903664325acb3f199dd8a4b8f1aa437e9fd6b2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 6 Dec 2006 20:37:33 -0800 Subject: [PATCH] remove HASH_HIGHMEM It has no users and it's doubtful that we'll need it again. Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/bootmem.h | 3 +-- mm/page_alloc.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 31e9abb6d977..2275f2748708 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -119,8 +119,7 @@ extern void *alloc_large_system_hash(const char *tablename, unsigned int *_hash_mask, unsigned long limit); -#define HASH_HIGHMEM 0x00000001 /* Consider highmem? */ -#define HASH_EARLY 0x00000002 /* Allocating during early boot? */ +#define HASH_EARLY 0x00000001 /* Allocating during early boot? */ /* Only NUMA needs hash distribution. * IA64 is known to have sufficient vmalloc space. diff --git a/mm/page_alloc.c b/mm/page_alloc.c index d539f83c62b6..2273952300d4 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3226,7 +3226,7 @@ void *__init alloc_large_system_hash(const char *tablename, /* allow the kernel cmdline to have a say */ if (!numentries) { /* round applicable memory size up to nearest megabyte */ - numentries = (flags & HASH_HIGHMEM) ? nr_all_pages : nr_kernel_pages; + numentries = nr_kernel_pages; numentries += (1UL << (20 - PAGE_SHIFT)) - 1; numentries >>= 20 - PAGE_SHIFT; numentries <<= 20 - PAGE_SHIFT; -- cgit v1.2.3 From cfd1893477fa94bb0915e39afa2f044ac978b5c6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 6 Dec 2006 20:37:38 -0800 Subject: [PATCH] ktime: Fix signed / unsigned mismatch in ktime_to_ns The 32 bit implementation of ktime_to_ns returns unsigned value, while the 64 bit version correctly returns an signed value. There is no current user affected by this, but it has to be fixed, as ktime values can be negative. Pointed-out-by: Helmut Duregger Signed-off-by: Thomas Gleixner Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/ktime.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ktime.h b/include/linux/ktime.h index 84eeecd60a02..611f17f79eef 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -248,9 +248,9 @@ static inline struct timeval ktime_to_timeval(const ktime_t kt) * * Returns the scalar nanoseconds representation of kt */ -static inline u64 ktime_to_ns(const ktime_t kt) +static inline s64 ktime_to_ns(const ktime_t kt) { - return (u64) kt.tv.sec * NSEC_PER_SEC + kt.tv.nsec; + return (s64) kt.tv.sec * NSEC_PER_SEC + kt.tv.nsec; } #endif -- cgit v1.2.3 From 651971cb7242e8f6d7ebd153e69bd271cb731223 Mon Sep 17 00:00:00 2001 From: suzuki Date: Wed, 6 Dec 2006 20:37:48 -0800 Subject: [PATCH] Fix the size limit of compat space msgsize Currently we allocate 64k space on the user stack and use it the msgbuf for sys_{msgrcv,msgsnd} for compat and the results are later copied in user [ by copy_in_user]. This patch introduces helper routines for sys_{msgrcv,msgsnd} as below: do_msgsnd() : Accepts the mtype and user space ptr to the buffer along with the msqid and msgflg. do_msgrcv() : Accepts a kernel space ptr to mtype and a userspace ptr to the buffer. The mtype has to be copied back the user space msgbuf by the caller. These changes avoid the need to allocate the msgsize on the userspace ( thus removing the size limt ) and the overhead of an extra copy_in_user(). Signed-off-by: Suzuki K P Cc: Arnd Bergmann Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/msg.h | 6 ++++++ ipc/compat.c | 23 +++++++---------------- ipc/msg.c | 44 +++++++++++++++++++++++++++++++++----------- 3 files changed, 46 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/include/linux/msg.h b/include/linux/msg.h index acc7c174ff00..f1b60740d641 100644 --- a/include/linux/msg.h +++ b/include/linux/msg.h @@ -92,6 +92,12 @@ struct msg_queue { struct list_head q_senders; }; +/* Helper routines for sys_msgsnd and sys_msgrcv */ +extern long do_msgsnd(int msqid, long mtype, void __user *mtext, + size_t msgsz, int msgflg); +extern long do_msgrcv(int msqid, long *pmtype, void __user *mtext, + size_t msgsz, long msgtyp, int msgflg); + #endif /* __KERNEL__ */ #endif /* _LINUX_MSG_H */ diff --git a/ipc/compat.c b/ipc/compat.c index 4d20cfd38f0a..fa18141539fb 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -115,7 +115,6 @@ struct compat_shm_info { extern int sem_ctls[]; #define sc_semopm (sem_ctls[2]) -#define MAXBUF (64*1024) static inline int compat_ipc_parse_version(int *cmd) { @@ -307,35 +306,30 @@ long compat_sys_semctl(int first, int second, int third, void __user *uptr) long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) { - struct msgbuf __user *p; struct compat_msgbuf __user *up = uptr; long type; if (first < 0) return -EINVAL; - if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) + if (second < 0) return -EINVAL; - p = compat_alloc_user_space(second + sizeof(struct msgbuf)); - if (get_user(type, &up->mtype) || - put_user(type, &p->mtype) || - copy_in_user(p->mtext, up->mtext, second)) + if (get_user(type, &up->mtype)) return -EFAULT; - return sys_msgsnd(first, p, second, third); + return do_msgsnd(first, type, up->mtext, second, third); } long compat_sys_msgrcv(int first, int second, int msgtyp, int third, int version, void __user *uptr) { - struct msgbuf __user *p; struct compat_msgbuf __user *up; long type; int err; if (first < 0) return -EINVAL; - if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) + if (second < 0) return -EINVAL; if (!version) { @@ -349,14 +343,11 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third, uptr = compat_ptr(ipck.msgp); msgtyp = ipck.msgtyp; } - p = compat_alloc_user_space(second + sizeof(struct msgbuf)); - err = sys_msgrcv(first, p, second, msgtyp, third); + up = uptr; + err = do_msgrcv(first, &type, up->mtext, second, msgtyp, third); if (err < 0) goto out; - up = uptr; - if (get_user(type, &p->mtype) || - put_user(type, &up->mtype) || - copy_in_user(up->mtext, p->mtext, err)) + if (put_user(type, &up->mtype)) err = -EFAULT; out: return err; diff --git a/ipc/msg.c b/ipc/msg.c index 1266b1d0c8e3..a388824740e7 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -626,12 +626,11 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) return 0; } -asmlinkage long -sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) +long do_msgsnd(int msqid, long mtype, void __user *mtext, + size_t msgsz, int msgflg) { struct msg_queue *msq; struct msg_msg *msg; - long mtype; int err; struct ipc_namespace *ns; @@ -639,12 +638,10 @@ sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0) return -EINVAL; - if (get_user(mtype, &msgp->mtype)) - return -EFAULT; if (mtype < 1) return -EINVAL; - msg = load_msg(msgp->mtext, msgsz); + msg = load_msg(mtext, msgsz); if (IS_ERR(msg)) return PTR_ERR(msg); @@ -723,6 +720,16 @@ out_free: return err; } +asmlinkage long +sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) +{ + long mtype; + + if (get_user(mtype, &msgp->mtype)) + return -EFAULT; + return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg); +} + static inline int convert_mode(long *msgtyp, int msgflg) { /* @@ -742,8 +749,8 @@ static inline int convert_mode(long *msgtyp, int msgflg) return SEARCH_EQUAL; } -asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, - long msgtyp, int msgflg) +long do_msgrcv(int msqid, long *pmtype, void __user *mtext, + size_t msgsz, long msgtyp, int msgflg) { struct msg_queue *msq; struct msg_msg *msg; @@ -889,15 +896,30 @@ out_unlock: return PTR_ERR(msg); msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; - if (put_user (msg->m_type, &msgp->mtype) || - store_msg(msgp->mtext, msg, msgsz)) { + *pmtype = msg->m_type; + if (store_msg(mtext, msg, msgsz)) msgsz = -EFAULT; - } + free_msg(msg); return msgsz; } +asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, + long msgtyp, int msgflg) +{ + long err, mtype; + + err = do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg); + if (err < 0) + goto out; + + if (put_user(mtype, &msgp->mtype)) + err = -EFAULT; +out: + return err; +} + #ifdef CONFIG_PROC_FS static int sysvipc_msg_proc_show(struct seq_file *s, void *it) { -- cgit v1.2.3 From 386d9a7edd9f3492c99124b0a659e9ed7abb30f9 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 6 Dec 2006 20:37:53 -0800 Subject: [PATCH] elf: Always define elf_addr_t in linux/elf.h Define elf_addr_t in linux/elf.h. The size of the type is determined using ELF_CLASS. This allows us to remove the defines that today are spread all over .c and .h files. Signed-off-by: Magnus Damm Cc: Daniel Jacobowitz Cc: Roland McGrath Cc: Jakub Jelinek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ia64/ia32/ia32priv.h | 2 -- arch/mips/kernel/binfmt_elfn32.c | 1 - arch/mips/kernel/binfmt_elfo32.c | 1 - arch/mips/kernel/irixelf.c | 4 ---- arch/parisc/kernel/binfmt_elf32.c | 1 - arch/s390/kernel/binfmt_elf32.c | 1 - arch/sparc64/kernel/binfmt_elf32.c | 1 - arch/x86_64/ia32/ia32_binfmt.c | 2 -- fs/binfmt_elf.c | 4 ---- fs/binfmt_elf_fdpic.c | 3 --- include/asm-powerpc/elf.h | 2 -- include/linux/elf.h | 2 ++ 12 files changed, 2 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/ia32/ia32priv.h b/arch/ia64/ia32/ia32priv.h index 703a67c934f8..cfa0bc0026b5 100644 --- a/arch/ia64/ia32/ia32priv.h +++ b/arch/ia64/ia32/ia32priv.h @@ -330,8 +330,6 @@ struct old_linux32_dirent { void ia64_elf32_init(struct pt_regs *regs); #define ELF_PLAT_INIT(_r, load_addr) ia64_elf32_init(_r) -#define elf_addr_t u32 - /* This macro yields a bitmask that programs can use to figure out what instruction set this CPU supports. */ #define ELF_HWCAP 0 diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c index 4a9f1ecefaf2..9b34238d41c0 100644 --- a/arch/mips/kernel/binfmt_elfn32.c +++ b/arch/mips/kernel/binfmt_elfn32.c @@ -90,7 +90,6 @@ struct elf_prpsinfo32 char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ }; -#define elf_addr_t u32 #define elf_caddr_t u32 #define init_elf_binfmt init_elfn32_binfmt diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index e31813779895..993f7ec70f35 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -92,7 +92,6 @@ struct elf_prpsinfo32 char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ }; -#define elf_addr_t u32 #define elf_caddr_t u32 #define init_elf_binfmt init_elf32_binfmt diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index ab12c8f01518..a82fae221ce4 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -52,10 +52,6 @@ static struct linux_binfmt irix_format = { irix_core_dump, PAGE_SIZE }; -#ifndef elf_addr_t -#define elf_addr_t unsigned long -#endif - #ifdef DEBUG /* Debugging routines. */ static char *get_elf_p_type(Elf32_Word p_type) diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c index 1e64e7b88110..ecb10a4f63c6 100644 --- a/arch/parisc/kernel/binfmt_elf32.c +++ b/arch/parisc/kernel/binfmt_elf32.c @@ -75,7 +75,6 @@ struct elf_prpsinfo32 char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ }; -#define elf_addr_t unsigned int #define init_elf_binfmt init_elf32_binfmt #define ELF_PLATFORM ("PARISC32\0") diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c index 9565a2dcfadc..5c46054195cb 100644 --- a/arch/s390/kernel/binfmt_elf32.c +++ b/arch/s390/kernel/binfmt_elf32.c @@ -176,7 +176,6 @@ struct elf_prpsinfo32 #include -#define elf_addr_t u32 /* #define init_elf_binfmt init_elf32_binfmt */ diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c index a98f3ae175a3..9ad84ff10a17 100644 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ b/arch/sparc64/kernel/binfmt_elf32.c @@ -141,7 +141,6 @@ cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) value->tv_sec = jiffies / HZ; } -#define elf_addr_t u32 #undef start_thread #define start_thread start_thread32 #define init_elf_binfmt init_elf32_binfmt diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c index 932a62ad6c83..543ef4f405e9 100644 --- a/arch/x86_64/ia32/ia32_binfmt.c +++ b/arch/x86_64/ia32/ia32_binfmt.c @@ -305,8 +305,6 @@ MODULE_AUTHOR("Eric Youngdale, Andi Kleen"); #undef MODULE_DESCRIPTION #undef MODULE_AUTHOR -#define elf_addr_t __u32 - static void elf32_init(struct pt_regs *); #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 68e20d5bfe1b..14ea630a857c 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -47,10 +47,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); static int load_elf_library(struct file *); static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); -#ifndef elf_addr_t -#define elf_addr_t unsigned long -#endif - /* * If we don't support core dumping, then supply a NULL so we * don't even try. diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index f86d5c9ce5eb..ed9a61c6beb3 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -40,9 +40,6 @@ #include typedef char *elf_caddr_t; -#ifndef elf_addr_t -#define elf_addr_t unsigned long -#endif #if 0 #define kdebug(fmt, ...) printk("FDPIC "fmt"\n" ,##__VA_ARGS__ ) diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h index b5436642a109..d36426c01b6b 100644 --- a/include/asm-powerpc/elf.h +++ b/include/asm-powerpc/elf.h @@ -124,12 +124,10 @@ typedef elf_greg_t32 elf_gregset_t32[ELF_NGREG]; # define ELF_DATA ELFDATA2MSB typedef elf_greg_t64 elf_greg_t; typedef elf_gregset_t64 elf_gregset_t; -# define elf_addr_t unsigned long #else /* Assumption: ELF_ARCH == EM_PPC and ELF_CLASS == ELFCLASS32 */ typedef elf_greg_t32 elf_greg_t; typedef elf_gregset_t32 elf_gregset_t; -# define elf_addr_t __u32 #endif /* ELF_ARCH */ /* Floating point registers */ diff --git a/include/linux/elf.h b/include/linux/elf.h index 743d5c8e6d36..b403516d5c3d 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -358,6 +358,7 @@ extern Elf32_Dyn _DYNAMIC []; #define elfhdr elf32_hdr #define elf_phdr elf32_phdr #define elf_note elf32_note +#define elf_addr_t Elf32_Off #else @@ -365,6 +366,7 @@ extern Elf64_Dyn _DYNAMIC []; #define elfhdr elf64_hdr #define elf_phdr elf64_phdr #define elf_note elf64_note +#define elf_addr_t Elf64_Off #endif -- cgit v1.2.3 From b4c6c34a530b4d1c626f4ac0a884e0a9b849378c Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 6 Dec 2006 20:38:11 -0800 Subject: [PATCH] kprobes: enable booster on the preemptible kernel When we are unregistering a kprobe-booster, we can't release its instruction buffer immediately on the preemptive kernel, because some processes might be preempted on the buffer. The freeze_processes() and thaw_processes() functions can clean most of processes up from the buffer. There are still some non-frozen threads who have the PF_NOFREEZE flag. If those threads are sleeping (not preempted) at the known place outside the buffer, we can ensure safety of freeing. However, the processing of this check routine takes a long time. So, this patch introduces the garbage collection mechanism of insn_slot. It also introduces the "dirty" flag to free_insn_slot because of efficiency. The "clean" instruction slots (dirty flag is cleared) are released immediately. But the "dirty" slots which are used by boosted kprobes, are marked as garbages. collect_garbage_slots() will be invoked to release "dirty" slots if there are more than INSNS_PER_PAGE garbage slots or if there are no unused slots. Cc: "Keshavamurthy, Anil S" Cc: Ananth N Mavinakayanahalli Cc: "bibo,mao" Cc: Prasanna S Panchamukhi Cc: Yumiko Sugita Cc: Satoshi Oshima Cc: Hideo Aoki Signed-off-by: Masami Hiramatsu Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/kprobes.c | 4 +- arch/ia64/kernel/kprobes.c | 2 +- arch/powerpc/kernel/kprobes.c | 2 +- arch/s390/kernel/kprobes.c | 2 +- arch/x86_64/kernel/kprobes.c | 2 +- include/linux/kprobes.h | 2 +- kernel/kprobes.c | 117 ++++++++++++++++++++++++++++++++++-------- 7 files changed, 103 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c index fc79e1e859c4..af1d53344993 100644 --- a/arch/i386/kernel/kprobes.c +++ b/arch/i386/kernel/kprobes.c @@ -184,7 +184,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_remove_kprobe(struct kprobe *p) { mutex_lock(&kprobe_mutex); - free_insn_slot(p->ainsn.insn); + free_insn_slot(p->ainsn.insn, (p->ainsn.boostable == 1)); mutex_unlock(&kprobe_mutex); } @@ -333,7 +333,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) return 1; ss_probe: -#ifndef CONFIG_PREEMPT +#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM) if (p->ainsn.boostable == 1 && !p->post_handler){ /* Boost up -- we can execute copied instructions directly */ reset_current_kprobe(); diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 51217d63285e..4d592ee9300b 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c @@ -481,7 +481,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_remove_kprobe(struct kprobe *p) { mutex_lock(&kprobe_mutex); - free_insn_slot(p->ainsn.insn); + free_insn_slot(p->ainsn.insn, 0); mutex_unlock(&kprobe_mutex); } /* diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 7b8d12b9026c..4657563f8813 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -85,7 +85,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_remove_kprobe(struct kprobe *p) { mutex_lock(&kprobe_mutex); - free_insn_slot(p->ainsn.insn); + free_insn_slot(p->ainsn.insn, 0); mutex_unlock(&kprobe_mutex); } diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 67914fe7f317..576368c4f605 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -200,7 +200,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_remove_kprobe(struct kprobe *p) { mutex_lock(&kprobe_mutex); - free_insn_slot(p->ainsn.insn); + free_insn_slot(p->ainsn.insn, 0); mutex_unlock(&kprobe_mutex); } diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c index ac241567e682..209c8c0bec71 100644 --- a/arch/x86_64/kernel/kprobes.c +++ b/arch/x86_64/kernel/kprobes.c @@ -224,7 +224,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_remove_kprobe(struct kprobe *p) { mutex_lock(&kprobe_mutex); - free_insn_slot(p->ainsn.insn); + free_insn_slot(p->ainsn.insn, 0); mutex_unlock(&kprobe_mutex); } diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index ac4c0559f751..769be39b9681 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -165,7 +165,7 @@ extern void arch_disarm_kprobe(struct kprobe *p); extern int arch_init_kprobes(void); extern void show_registers(struct pt_regs *regs); extern kprobe_opcode_t *get_insn_slot(void); -extern void free_insn_slot(kprobe_opcode_t *slot); +extern void free_insn_slot(kprobe_opcode_t *slot, int dirty); extern void kprobes_inc_nmissed_count(struct kprobe *p); /* Get the kprobe at this addr (if any) - called with preemption disabled */ diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 610c837ad9e0..17ec4afb0994 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -83,9 +84,36 @@ struct kprobe_insn_page { kprobe_opcode_t *insns; /* Page of instruction slots */ char slot_used[INSNS_PER_PAGE]; int nused; + int ngarbage; }; static struct hlist_head kprobe_insn_pages; +static int kprobe_garbage_slots; +static int collect_garbage_slots(void); + +static int __kprobes check_safety(void) +{ + int ret = 0; +#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM) + ret = freeze_processes(); + if (ret == 0) { + struct task_struct *p, *q; + do_each_thread(p, q) { + if (p != current && p->state == TASK_RUNNING && + p->pid != 0) { + printk("Check failed: %s is running\n",p->comm); + ret = -1; + goto loop_end; + } + } while_each_thread(p, q); + } +loop_end: + thaw_processes(); +#else + synchronize_sched(); +#endif + return ret; +} /** * get_insn_slot() - Find a slot on an executable page for an instruction. @@ -96,6 +124,7 @@ kprobe_opcode_t __kprobes *get_insn_slot(void) struct kprobe_insn_page *kip; struct hlist_node *pos; + retry: hlist_for_each(pos, &kprobe_insn_pages) { kip = hlist_entry(pos, struct kprobe_insn_page, hlist); if (kip->nused < INSNS_PER_PAGE) { @@ -112,7 +141,11 @@ kprobe_opcode_t __kprobes *get_insn_slot(void) } } - /* All out of space. Need to allocate a new page. Use slot 0.*/ + /* If there are any garbage slots, collect it and try again. */ + if (kprobe_garbage_slots && collect_garbage_slots() == 0) { + goto retry; + } + /* All out of space. Need to allocate a new page. Use slot 0. */ kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL); if (!kip) { return NULL; @@ -133,10 +166,62 @@ kprobe_opcode_t __kprobes *get_insn_slot(void) memset(kip->slot_used, 0, INSNS_PER_PAGE); kip->slot_used[0] = 1; kip->nused = 1; + kip->ngarbage = 0; return kip->insns; } -void __kprobes free_insn_slot(kprobe_opcode_t *slot) +/* Return 1 if all garbages are collected, otherwise 0. */ +static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx) +{ + kip->slot_used[idx] = 0; + kip->nused--; + if (kip->nused == 0) { + /* + * Page is no longer in use. Free it unless + * it's the last one. We keep the last one + * so as not to have to set it up again the + * next time somebody inserts a probe. + */ + hlist_del(&kip->hlist); + if (hlist_empty(&kprobe_insn_pages)) { + INIT_HLIST_NODE(&kip->hlist); + hlist_add_head(&kip->hlist, + &kprobe_insn_pages); + } else { + module_free(NULL, kip->insns); + kfree(kip); + } + return 1; + } + return 0; +} + +static int __kprobes collect_garbage_slots(void) +{ + struct kprobe_insn_page *kip; + struct hlist_node *pos, *next; + + /* Ensure no-one is preepmted on the garbages */ + if (check_safety() != 0) + return -EAGAIN; + + hlist_for_each_safe(pos, next, &kprobe_insn_pages) { + int i; + kip = hlist_entry(pos, struct kprobe_insn_page, hlist); + if (kip->ngarbage == 0) + continue; + kip->ngarbage = 0; /* we will collect all garbages */ + for (i = 0; i < INSNS_PER_PAGE; i++) { + if (kip->slot_used[i] == -1 && + collect_one_slot(kip, i)) + break; + } + } + kprobe_garbage_slots = 0; + return 0; +} + +void __kprobes free_insn_slot(kprobe_opcode_t * slot, int dirty) { struct kprobe_insn_page *kip; struct hlist_node *pos; @@ -146,28 +231,18 @@ void __kprobes free_insn_slot(kprobe_opcode_t *slot) if (kip->insns <= slot && slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) { int i = (slot - kip->insns) / MAX_INSN_SIZE; - kip->slot_used[i] = 0; - kip->nused--; - if (kip->nused == 0) { - /* - * Page is no longer in use. Free it unless - * it's the last one. We keep the last one - * so as not to have to set it up again the - * next time somebody inserts a probe. - */ - hlist_del(&kip->hlist); - if (hlist_empty(&kprobe_insn_pages)) { - INIT_HLIST_NODE(&kip->hlist); - hlist_add_head(&kip->hlist, - &kprobe_insn_pages); - } else { - module_free(NULL, kip->insns); - kfree(kip); - } + if (dirty) { + kip->slot_used[i] = -1; + kip->ngarbage++; + } else { + collect_one_slot(kip, i); } - return; + break; } } + if (dirty && (++kprobe_garbage_slots > INSNS_PER_PAGE)) { + collect_garbage_slots(); + } } #endif -- cgit v1.2.3 From 83df8db9e62129975fab6d800fb381faf0dfee74 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 6 Dec 2006 20:38:14 -0800 Subject: [PATCH] declare smp_call_function_single in generic code smp_call_function_single() needs to be visible in non-SMP builds, to fix: arch/x86_64/kernel/vsyscall.c:283: warning: implicit declaration of function 'smp_call_function_single' Signed-off-by: Randy Dunlap Cc: Ingo Molnar Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-x86_64/smp.h | 7 ------- include/linux/smp.h | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h index d6b7c057edba..f1bdd500d7ac 100644 --- a/include/asm-x86_64/smp.h +++ b/include/asm-x86_64/smp.h @@ -118,13 +118,6 @@ static __inline int logical_smp_processor_id(void) #define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu] #else #define cpu_physical_id(cpu) boot_cpu_id -static inline int smp_call_function_single(int cpuid, void (*func) (void *info), - void *info, int retry, int wait) -{ - /* Disable interrupts here? */ - func(info); - return 0; -} #endif /* !CONFIG_SMP */ #endif diff --git a/include/linux/smp.h b/include/linux/smp.h index 51649987f691..7ba23ec8211b 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -99,6 +99,13 @@ static inline int up_smp_call_function(void) static inline void smp_send_reschedule(int cpu) { } #define num_booting_cpus() 1 #define smp_prepare_boot_cpu() do {} while (0) +static inline int smp_call_function_single(int cpuid, void (*func) (void *info), + void *info, int retry, int wait) +{ + /* Disable interrupts here? */ + func(info); + return 0; +} #endif /* !SMP */ -- cgit v1.2.3 From 02316067852187b8bec781bec07410e91af79627 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 6 Dec 2006 20:38:17 -0800 Subject: [PATCH] hotplug CPU: clean up hotcpu_notifier() use There was lots of #ifdef noise in the kernel due to hotcpu_notifier(fn, prio) not correctly marking 'fn' as used in the !HOTPLUG_CPU case, and thus generating compiler warnings of unused symbols, hence forcing people to add #ifdefs. the compiler can skip truly unused functions just fine: text data bss dec hex filename 1624412 728710 3674856 6027978 5bfaca vmlinux.before 1624412 728710 3674856 6027978 5bfaca vmlinux.after [akpm@osdl.org: topology.c fix] Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/mcheck/therm_throt.c | 2 -- arch/i386/kernel/cpuid.c | 2 -- arch/i386/kernel/microcode.c | 2 -- arch/i386/kernel/msr.c | 2 -- arch/ia64/kernel/palinfo.c | 2 -- arch/ia64/kernel/salinfo.c | 2 -- arch/s390/appldata/appldata_base.c | 2 -- arch/x86_64/kernel/mce.c | 2 -- arch/x86_64/kernel/mce_amd.c | 4 ++-- arch/x86_64/kernel/vsyscall.c | 2 -- block/ll_rw_blk.c | 4 ---- drivers/base/topology.c | 2 -- drivers/cpufreq/cpufreq.c | 2 -- fs/buffer.c | 2 -- include/linux/cpu.h | 6 +++--- kernel/cpuset.c | 4 ---- kernel/profile.c | 3 +-- kernel/sched.c | 3 --- kernel/workqueue.c | 2 -- lib/radix-tree.c | 2 -- mm/page_alloc.c | 4 ---- mm/swap.c | 2 ++ mm/vmscan.c | 2 -- net/core/dev.c | 2 -- net/core/flow.c | 2 -- 25 files changed, 8 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/i386/kernel/cpu/mcheck/therm_throt.c index bad8b4420709..065005c3f168 100644 --- a/arch/i386/kernel/cpu/mcheck/therm_throt.c +++ b/arch/i386/kernel/cpu/mcheck/therm_throt.c @@ -116,7 +116,6 @@ static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev) return sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group); } -#ifdef CONFIG_HOTPLUG_CPU static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev) { return sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group); @@ -153,7 +152,6 @@ static struct notifier_block thermal_throttle_cpu_notifier = { .notifier_call = thermal_throttle_cpu_callback, }; -#endif /* CONFIG_HOTPLUG_CPU */ static __init int thermal_throttle_init_device(void) { diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c index ab0c327e79dc..23b2cc748d4e 100644 --- a/arch/i386/kernel/cpuid.c +++ b/arch/i386/kernel/cpuid.c @@ -167,7 +167,6 @@ static int cpuid_device_create(int i) return err; } -#ifdef CONFIG_HOTPLUG_CPU static int cpuid_class_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; @@ -187,7 +186,6 @@ static struct notifier_block __cpuinitdata cpuid_class_cpu_notifier = { .notifier_call = cpuid_class_cpu_callback, }; -#endif /* !CONFIG_HOTPLUG_CPU */ static int __init cpuid_init(void) { diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index 23f5984d0654..972346604f9d 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -703,7 +703,6 @@ static struct sysdev_driver mc_sysdev_driver = { .resume = mc_sysdev_resume, }; -#ifdef CONFIG_HOTPLUG_CPU static __cpuinit int mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) { @@ -726,7 +725,6 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) static struct notifier_block mc_cpu_notifier = { .notifier_call = mc_cpu_callback, }; -#endif static int __init microcode_init (void) { diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c index a773f776c9ea..7763c67ca282 100644 --- a/arch/i386/kernel/msr.c +++ b/arch/i386/kernel/msr.c @@ -250,7 +250,6 @@ static int msr_device_create(int i) return err; } -#ifdef CONFIG_HOTPLUG_CPU static int msr_class_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { @@ -271,7 +270,6 @@ static struct notifier_block __cpuinitdata msr_class_cpu_notifier = { .notifier_call = msr_class_cpu_callback, }; -#endif static int __init msr_init(void) { diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c index 0b546e2b36ac..c4c10a0b99d9 100644 --- a/arch/ia64/kernel/palinfo.c +++ b/arch/ia64/kernel/palinfo.c @@ -952,7 +952,6 @@ remove_palinfo_proc_entries(unsigned int hcpu) } } -#ifdef CONFIG_HOTPLUG_CPU static int palinfo_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { @@ -974,7 +973,6 @@ static struct notifier_block palinfo_cpu_notifier = .notifier_call = palinfo_cpu_callback, .priority = 0, }; -#endif static int __init palinfo_init(void) diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c index e63b8ca5344a..fd607ca51a8d 100644 --- a/arch/ia64/kernel/salinfo.c +++ b/arch/ia64/kernel/salinfo.c @@ -575,7 +575,6 @@ static struct file_operations salinfo_data_fops = { .write = salinfo_log_write, }; -#ifdef CONFIG_HOTPLUG_CPU static int __devinit salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) { @@ -620,7 +619,6 @@ static struct notifier_block salinfo_cpu_notifier = .notifier_call = salinfo_cpu_callback, .priority = 0, }; -#endif /* CONFIG_HOTPLUG_CPU */ static int __init salinfo_init(void) diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 67d5cf9cba83..b8c237290263 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -561,7 +561,6 @@ appldata_offline_cpu(int cpu) spin_unlock(&appldata_timer_lock); } -#ifdef CONFIG_HOTPLUG_CPU static int __cpuinit appldata_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) @@ -582,7 +581,6 @@ appldata_cpu_notify(struct notifier_block *self, static struct notifier_block appldata_nb = { .notifier_call = appldata_cpu_notify, }; -#endif /* * appldata_init() diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index c7587fc39015..bc863c464a1f 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -641,7 +641,6 @@ static __cpuinit int mce_create_device(unsigned int cpu) return err; } -#ifdef CONFIG_HOTPLUG_CPU static void mce_remove_device(unsigned int cpu) { int i; @@ -674,7 +673,6 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) static struct notifier_block mce_cpu_notifier = { .notifier_call = mce_cpu_callback, }; -#endif static __init int mce_init_device(void) { diff --git a/arch/x86_64/kernel/mce_amd.c b/arch/x86_64/kernel/mce_amd.c index 883fe747f64c..fa09debad4b7 100644 --- a/arch/x86_64/kernel/mce_amd.c +++ b/arch/x86_64/kernel/mce_amd.c @@ -551,7 +551,6 @@ out: return err; } -#ifdef CONFIG_HOTPLUG_CPU /* * let's be hotplug friendly. * in case of multiple core processors, the first core always takes ownership @@ -594,12 +593,14 @@ static void threshold_remove_bank(unsigned int cpu, int bank) sprintf(name, "threshold_bank%i", bank); +#ifdef CONFIG_SMP /* sibling symlink */ if (shared_bank[bank] && b->blocks->cpu != cpu) { sysfs_remove_link(&per_cpu(device_mce, cpu).kobj, name); per_cpu(threshold_banks, cpu)[bank] = NULL; return; } +#endif /* remove all sibling symlinks before unregistering */ for_each_cpu_mask(i, b->cpus) { @@ -656,7 +657,6 @@ static int threshold_cpu_callback(struct notifier_block *nfb, static struct notifier_block threshold_cpu_notifier = { .notifier_call = threshold_cpu_callback, }; -#endif /* CONFIG_HOTPLUG_CPU */ static __init int threshold_init_device(void) { diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index 630036c06c75..3785e4954734 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -275,7 +275,6 @@ static void __cpuinit cpu_vsyscall_init(void *arg) vsyscall_set_cpu(raw_smp_processor_id()); } -#ifdef CONFIG_HOTPLUG_CPU static int __cpuinit cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg) { @@ -284,7 +283,6 @@ cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg) smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1); return NOTIFY_DONE; } -#endif static void __init map_vsyscall(void) { diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index a4ff3271d4a8..31512cd9f3ad 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -3459,8 +3459,6 @@ static void blk_done_softirq(struct softirq_action *h) } } -#ifdef CONFIG_HOTPLUG_CPU - static int blk_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { @@ -3486,8 +3484,6 @@ static struct notifier_block __devinitdata blk_cpu_notifier = { .notifier_call = blk_cpu_notify, }; -#endif /* CONFIG_HOTPLUG_CPU */ - /** * blk_complete_request - end I/O on a request * @req: the request being processed diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 3d12b85b0962..067a9e8bc377 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -108,7 +108,6 @@ static int __cpuinit topology_add_dev(unsigned int cpu) return rc; } -#ifdef CONFIG_HOTPLUG_CPU static void __cpuinit topology_remove_dev(unsigned int cpu) { struct sys_device *sys_dev = get_cpu_sysdev(cpu); @@ -136,7 +135,6 @@ static int __cpuinit topology_cpu_callback(struct notifier_block *nfb, } return rc ? NOTIFY_BAD : NOTIFY_OK; } -#endif static int __cpuinit topology_sysfs_init(void) { diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7a7c6e6dfe4f..47ab42db122a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1537,7 +1537,6 @@ int cpufreq_update_policy(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_update_policy); -#ifdef CONFIG_HOTPLUG_CPU static int cpufreq_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { @@ -1577,7 +1576,6 @@ static struct notifier_block __cpuinitdata cpufreq_cpu_notifier = { .notifier_call = cpufreq_cpu_callback, }; -#endif /* CONFIG_HOTPLUG_CPU */ /********************************************************************* * REGISTER / UNREGISTER CPUFREQ DRIVER * diff --git a/fs/buffer.c b/fs/buffer.c index a8ca0ac21488..517860f2d75b 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2972,7 +2972,6 @@ init_buffer_head(void *data, struct kmem_cache *cachep, unsigned long flags) } } -#ifdef CONFIG_HOTPLUG_CPU static void buffer_exit_cpu(int cpu) { int i; @@ -2994,7 +2993,6 @@ static int buffer_cpu_notify(struct notifier_block *self, buffer_exit_cpu((unsigned long)hcpu); return NOTIFY_OK; } -#endif /* CONFIG_HOTPLUG_CPU */ void __init buffer_init(void) { diff --git a/include/linux/cpu.h b/include/linux/cpu.h index f02d71bf6894..71dc6ba4f73f 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -89,9 +89,9 @@ int cpu_down(unsigned int cpu); #define lock_cpu_hotplug() do { } while (0) #define unlock_cpu_hotplug() do { } while (0) #define lock_cpu_hotplug_interruptible() 0 -#define hotcpu_notifier(fn, pri) do { } while (0) -#define register_hotcpu_notifier(nb) do { } while (0) -#define unregister_hotcpu_notifier(nb) do { } while (0) +#define hotcpu_notifier(fn, pri) do { (void)(fn); } while (0) +#define register_hotcpu_notifier(nb) do { (void)(nb); } while (0) +#define unregister_hotcpu_notifier(nb) do { (void)(nb); } while (0) /* CPUs don't go offline once they're online w/o CONFIG_HOTPLUG_CPU */ static inline int cpu_is_offline(int cpu) { return 0; } diff --git a/kernel/cpuset.c b/kernel/cpuset.c index bd1e89c4c96a..9b62b4c03ad0 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -2044,7 +2044,6 @@ out: return err; } -#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG) /* * If common_cpu_mem_hotplug_unplug(), below, unplugs any CPUs * or memory nodes, we need to walk over the cpuset hierarchy, @@ -2108,9 +2107,7 @@ static void common_cpu_mem_hotplug_unplug(void) mutex_unlock(&callback_mutex); mutex_unlock(&manage_mutex); } -#endif -#ifdef CONFIG_HOTPLUG_CPU /* * The top_cpuset tracks what CPUs and Memory Nodes are online, * period. This is necessary in order to make cpusets transparent @@ -2127,7 +2124,6 @@ static int cpuset_handle_cpuhp(struct notifier_block *nb, common_cpu_mem_hotplug_unplug(); return 0; } -#endif #ifdef CONFIG_MEMORY_HOTPLUG /* diff --git a/kernel/profile.c b/kernel/profile.c index 04fd84e8cdbe..0961d93e1d91 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -319,7 +319,6 @@ out: put_cpu(); } -#ifdef CONFIG_HOTPLUG_CPU static int __devinit profile_cpu_callback(struct notifier_block *info, unsigned long action, void *__cpu) { @@ -372,10 +371,10 @@ static int __devinit profile_cpu_callback(struct notifier_block *info, } return NOTIFY_OK; } -#endif /* CONFIG_HOTPLUG_CPU */ #else /* !CONFIG_SMP */ #define profile_flip_buffers() do { } while (0) #define profile_discard_flip_buffers() do { } while (0) +#define profile_cpu_callback NULL void profile_hits(int type, void *__pc, unsigned int nr_hits) { diff --git a/kernel/sched.c b/kernel/sched.c index 75a005ed4eda..c83f531c2886 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6740,8 +6740,6 @@ SYSDEV_ATTR(sched_smt_power_savings, 0644, sched_smt_power_savings_show, sched_smt_power_savings_store); #endif - -#ifdef CONFIG_HOTPLUG_CPU /* * Force a reinitialization of the sched domains hierarchy. The domains * and groups cannot be updated in place without racing with the balancing @@ -6774,7 +6772,6 @@ static int update_sched_domains(struct notifier_block *nfb, return NOTIFY_OK; } -#endif void __init sched_init_smp(void) { diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 5484d6e045c2..c5257316f4b9 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -655,7 +655,6 @@ int current_is_keventd(void) } -#ifdef CONFIG_HOTPLUG_CPU /* Take the work from this (downed) CPU. */ static void take_over_work(struct workqueue_struct *wq, unsigned int cpu) { @@ -738,7 +737,6 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -#endif void init_workqueues(void) { diff --git a/lib/radix-tree.c b/lib/radix-tree.c index e2cefabb5aa0..d69ddbe43865 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -996,7 +996,6 @@ static __init void radix_tree_init_maxindex(void) height_to_maxindex[i] = __maxindex(i); } -#ifdef CONFIG_HOTPLUG_CPU static int radix_tree_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) @@ -1016,7 +1015,6 @@ static int radix_tree_callback(struct notifier_block *nfb, } return NOTIFY_OK; } -#endif /* CONFIG_HOTPLUG_CPU */ void __init radix_tree_init(void) { diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 2273952300d4..27ec7a1b8022 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -701,7 +701,6 @@ void drain_node_pages(int nodeid) } #endif -#if defined(CONFIG_PM) || defined(CONFIG_HOTPLUG_CPU) static void __drain_pages(unsigned int cpu) { unsigned long flags; @@ -723,7 +722,6 @@ static void __drain_pages(unsigned int cpu) } } } -#endif /* CONFIG_PM || CONFIG_HOTPLUG_CPU */ #ifdef CONFIG_PM @@ -2907,7 +2905,6 @@ void __init free_area_init(unsigned long *zones_size) __pa(PAGE_OFFSET) >> PAGE_SHIFT, NULL); } -#ifdef CONFIG_HOTPLUG_CPU static int page_alloc_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { @@ -2922,7 +2919,6 @@ static int page_alloc_cpu_notify(struct notifier_block *self, } return NOTIFY_OK; } -#endif /* CONFIG_HOTPLUG_CPU */ void __init page_alloc_init(void) { diff --git a/mm/swap.c b/mm/swap.c index 017e72ca9bbb..2ed7be39795e 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -514,5 +514,7 @@ void __init swap_setup(void) * Right now other parts of the system means that we * _really_ don't want to cluster much more */ +#ifdef CONFIG_HOTPLUG_CPU hotcpu_notifier(cpu_swap_callback, 0); +#endif } diff --git a/mm/vmscan.c b/mm/vmscan.c index f6616e81fac7..093f5fe6dd77 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1513,7 +1513,6 @@ out: } #endif -#ifdef CONFIG_HOTPLUG_CPU /* It's optimal to keep kswapds on the same CPUs as their memory, but not required for correctness. So if the last cpu in a node goes away, we get changed to run anywhere: as the first one comes back, @@ -1534,7 +1533,6 @@ static int __devinit cpu_callback(struct notifier_block *nfb, } return NOTIFY_OK; } -#endif /* CONFIG_HOTPLUG_CPU */ /* * This kswapd start function will be called by init and node-hot-add. diff --git a/net/core/dev.c b/net/core/dev.c index 59d058a3b504..e660cb57e42a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3340,7 +3340,6 @@ void unregister_netdev(struct net_device *dev) EXPORT_SYMBOL(unregister_netdev); -#ifdef CONFIG_HOTPLUG_CPU static int dev_cpu_callback(struct notifier_block *nfb, unsigned long action, void *ocpu) @@ -3384,7 +3383,6 @@ static int dev_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -#endif /* CONFIG_HOTPLUG_CPU */ #ifdef CONFIG_NET_DMA /** diff --git a/net/core/flow.c b/net/core/flow.c index 104c25d00a1d..d137f971f97d 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -340,7 +340,6 @@ static void __devinit flow_cache_cpu_prepare(int cpu) tasklet_init(tasklet, flow_cache_flush_tasklet, 0); } -#ifdef CONFIG_HOTPLUG_CPU static int flow_cache_cpu(struct notifier_block *nfb, unsigned long action, void *hcpu) @@ -349,7 +348,6 @@ static int flow_cache_cpu(struct notifier_block *nfb, __flow_cache_shrink((unsigned long)hcpu, 0); return NOTIFY_OK; } -#endif /* CONFIG_HOTPLUG_CPU */ static int __init flow_cache_init(void) { -- cgit v1.2.3 From ebe7e5fe4b41deeb2731c5b52d8c8e6ac08b1f74 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 6 Dec 2006 20:38:21 -0800 Subject: [PATCH] remove kernel/lockdep.c:lockdep_internal Remove the no longer used lockdep_internal(). Signed-off-by: Adrian Bunk Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/lockdep.h | 6 ------ kernel/lockdep.c | 7 ------- 2 files changed, 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index da19aeb0dbe8..498bfbd3b4e1 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -193,7 +193,6 @@ extern void lockdep_free_key_range(void *start, unsigned long size); extern void lockdep_off(void); extern void lockdep_on(void); -extern int lockdep_internal(void); /* * These methods are used by specific locking variants (spinlocks, @@ -255,11 +254,6 @@ static inline void lockdep_on(void) { } -static inline int lockdep_internal(void) -{ - return 0; -} - # define lock_acquire(l, s, t, r, c, i) do { } while (0) # define lock_release(l, n, i) do { } while (0) # define lockdep_init() do { } while (0) diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 300d61bb314b..3926c3674354 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -140,13 +140,6 @@ void lockdep_on(void) EXPORT_SYMBOL(lockdep_on); -int lockdep_internal(void) -{ - return current->lockdep_recursion != 0; -} - -EXPORT_SYMBOL(lockdep_internal); - /* * Debugging switches: */ -- cgit v1.2.3 From d3228a887cae75ef2b8b1211c31c539bef5a5698 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 6 Dec 2006 20:38:22 -0800 Subject: [PATCH] make kernel/signal.c:kill_proc_info() static Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 - kernel/signal.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 0a90cefb0b0d..3a767242e72f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1305,7 +1305,6 @@ extern int kill_pgrp(struct pid *pid, int sig, int priv); extern int kill_pid(struct pid *pid, int sig, int priv); extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); extern int kill_pg_info(int, struct siginfo *, pid_t); -extern int kill_proc_info(int, struct siginfo *, pid_t); extern void do_notify_parent(struct task_struct *, int); extern void force_sig(int, struct task_struct *); extern void force_sig_specific(int, struct task_struct *); diff --git a/kernel/signal.c b/kernel/signal.c index bc972d7e6319..ec81defde339 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1134,8 +1134,7 @@ int kill_pid_info(int sig, struct siginfo *info, struct pid *pid) return error; } -int -kill_proc_info(int sig, struct siginfo *info, pid_t pid) +static int kill_proc_info(int sig, struct siginfo *info, pid_t pid) { int error; rcu_read_lock(); -- cgit v1.2.3 From d394e122bc1adba0f3eb1ebec1cedb8a8c524741 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 6 Dec 2006 20:38:26 -0800 Subject: [PATCH] make fs/jbd/transaction.c:__journal_temp_unlink_buffer() static Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd/transaction.c | 4 +++- include/linux/jbd.h | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 4f82bcd63e48..d38e0d575e48 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -27,6 +27,8 @@ #include #include +static void __journal_temp_unlink_buffer(struct journal_head *jh); + /* * get_transaction: obtain a new transaction_t object. * @@ -1499,7 +1501,7 @@ __blist_del_buffer(struct journal_head **list, struct journal_head *jh) * * Called under j_list_lock. The journal may not be locked. */ -void __journal_temp_unlink_buffer(struct journal_head *jh) +static void __journal_temp_unlink_buffer(struct journal_head *jh) { struct journal_head **list = NULL; transaction_t *transaction; diff --git a/include/linux/jbd.h b/include/linux/jbd.h index dacd566c9f6c..452737551260 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -839,7 +839,6 @@ struct journal_s */ /* Filing buffers */ -extern void __journal_temp_unlink_buffer(struct journal_head *jh); extern void journal_unfile_buffer(journal_t *, struct journal_head *); extern void __journal_unfile_buffer(struct journal_head *); extern void __journal_refile_buffer(struct journal_head *); -- cgit v1.2.3 From 7ddae86095794cce4364740edd8463c77654a265 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 6 Dec 2006 20:38:27 -0800 Subject: [PATCH] make fs/jbd2/transaction.c:__kbd2_journal_temp_unlink_buffer() static Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd2/transaction.c | 2 ++ include/linux/jbd2.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index c051a94c8a97..3a8700153cb0 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -27,6 +27,8 @@ #include #include +static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh); + /* * jbd2_get_transaction: obtain a new transaction_t object. * diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 98a0ae52660f..0e0fedd2039a 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -848,7 +848,6 @@ struct journal_s */ /* Filing buffers */ -extern void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh); extern void jbd2_journal_unfile_buffer(journal_t *, struct journal_head *); extern void __jbd2_journal_unfile_buffer(struct journal_head *); extern void __jbd2_journal_refile_buffer(struct journal_head *); -- cgit v1.2.3 From c585646dd1d98caf0a5f2e85c794c1441df6fac1 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 6 Dec 2006 20:38:29 -0800 Subject: [PATCH] fs/lockd/host.c: make 2 functions static Make the following needlessly global functions static: - nlm_lookup_host() - nsm_find() Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/host.c | 53 ++++++++++++++++++++++++--------------------- include/linux/lockd/lockd.h | 2 -- 2 files changed, 28 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index fb24a9730345..3d4610c2a266 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -36,34 +36,14 @@ static DEFINE_MUTEX(nlm_host_mutex); static void nlm_gc_hosts(void); static struct nsm_handle * __nsm_find(const struct sockaddr_in *, const char *, int, int); - -/* - * Find an NLM server handle in the cache. If there is none, create it. - */ -struct nlm_host * -nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version, - const char *hostname, int hostname_len) -{ - return nlm_lookup_host(0, sin, proto, version, - hostname, hostname_len); -} - -/* - * Find an NLM client handle in the cache. If there is none, create it. - */ -struct nlm_host * -nlmsvc_lookup_host(struct svc_rqst *rqstp, - const char *hostname, int hostname_len) -{ - return nlm_lookup_host(1, &rqstp->rq_addr, - rqstp->rq_prot, rqstp->rq_vers, - hostname, hostname_len); -} +static struct nsm_handle * nsm_find(const struct sockaddr_in *sin, + const char *hostname, + int hostname_len); /* * Common host lookup routine for server & client */ -struct nlm_host * +static struct nlm_host * nlm_lookup_host(int server, const struct sockaddr_in *sin, int proto, int version, const char *hostname, @@ -194,6 +174,29 @@ nlm_destroy_host(struct nlm_host *host) kfree(host); } +/* + * Find an NLM server handle in the cache. If there is none, create it. + */ +struct nlm_host * +nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version, + const char *hostname, int hostname_len) +{ + return nlm_lookup_host(0, sin, proto, version, + hostname, hostname_len); +} + +/* + * Find an NLM client handle in the cache. If there is none, create it. + */ +struct nlm_host * +nlmsvc_lookup_host(struct svc_rqst *rqstp, + const char *hostname, int hostname_len) +{ + return nlm_lookup_host(1, &rqstp->rq_addr, + rqstp->rq_prot, rqstp->rq_vers, + hostname, hostname_len); +} + /* * Create the NLM RPC client for an NLM peer */ @@ -495,7 +498,7 @@ out: return nsm; } -struct nsm_handle * +static struct nsm_handle * nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len) { return __nsm_find(sin, hostname, hostname_len, 1); diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 862d9730a60d..8c39654549d8 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -164,14 +164,12 @@ void nlmclnt_next_cookie(struct nlm_cookie *); */ struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int, const char *, int); struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *, const char *, int); -struct nlm_host * nlm_lookup_host(int server, const struct sockaddr_in *, int, int, const char *, int); struct rpc_clnt * nlm_bind_host(struct nlm_host *); void nlm_rebind_host(struct nlm_host *); struct nlm_host * nlm_get_host(struct nlm_host *); void nlm_release_host(struct nlm_host *); void nlm_shutdown_hosts(void); extern void nlm_host_rebooted(const struct sockaddr_in *, const char *, int, u32); -struct nsm_handle *nsm_find(const struct sockaddr_in *, const char *, int); void nsm_release(struct nsm_handle *); -- cgit v1.2.3 From d9489fb60614794cbca4b6b173c60ed9388974c6 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 6 Dec 2006 20:38:43 -0800 Subject: [PATCH] kernel-doc: fix fusion and i2o docs Correct lots of typos, kernel-doc warnings, & kernel-doc usage in fusion and i2o drivers. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/message/fusion/mptbase.c | 255 ++++++++++++++++++++------------------ drivers/message/fusion/mptfc.c | 5 +- drivers/message/fusion/mptscsih.c | 24 ++-- drivers/message/fusion/mptspi.c | 4 +- drivers/message/i2o/bus-osm.c | 3 + drivers/message/i2o/device.c | 8 +- drivers/message/i2o/driver.c | 20 ++- drivers/message/i2o/exec-osm.c | 10 +- drivers/message/i2o/i2o_block.c | 15 ++- drivers/message/i2o/i2o_proc.c | 2 +- drivers/message/i2o/i2o_scsi.c | 11 +- drivers/message/i2o/pci.c | 5 +- include/linux/i2o.h | 18 +-- 13 files changed, 203 insertions(+), 177 deletions(-) (limited to 'include/linux') diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 051b7c5b8f03..6e068cf1049b 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -347,7 +347,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. * @irq: irq number (not used) * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure @@ -387,14 +387,16 @@ mpt_interrupt(int irq, void *bus_id) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mpt_base_reply - MPT base driver's callback routine; all base driver - * "internal" request/reply processing is routed here. - * Currently used for EventNotification and EventAck handling. +/** + * mpt_base_reply - MPT base driver's callback routine * @ioc: Pointer to MPT_ADAPTER structure * @mf: Pointer to original MPT request frame * @reply: Pointer to MPT reply frame (NULL if TurboReply) * + * MPT base driver's callback routine; all base driver + * "internal" request/reply processing is routed here. + * Currently used for EventNotification and EventAck handling. + * * Returns 1 indicating original alloc'd request frame ptr * should be freed, or 0 if it shouldn't. */ @@ -530,7 +532,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value) * * This routine is called by a protocol-specific driver (SCSI host, - * LAN, SCSI target) to register it's reply callback routine. Each + * LAN, SCSI target) to register its reply callback routine. Each * protocol-specific driver must do this before it will be able to * use any IOC resources, such as obtaining request frames. * @@ -572,7 +574,7 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) * mpt_deregister - Deregister a protocol drivers resources. * @cb_idx: previously registered callback handle * - * Each protocol-specific driver should call this routine when it's + * Each protocol-specific driver should call this routine when its * module is unloaded. */ void @@ -617,7 +619,7 @@ mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc) * * Each protocol-specific driver should call this routine * when it does not (or can no longer) handle events, - * or when it's module is unloaded. + * or when its module is unloaded. */ void mpt_event_deregister(int cb_idx) @@ -656,7 +658,7 @@ mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func) * * Each protocol-specific driver should call this routine * when it does not (or can no longer) handle IOC reset handling, - * or when it's module is unloaded. + * or when its module is unloaded. */ void mpt_reset_deregister(int cb_idx) @@ -670,6 +672,8 @@ mpt_reset_deregister(int cb_idx) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_device_driver_register - Register device driver hooks + * @dd_cbfunc: driver callbacks struct + * @cb_idx: MPT protocol driver index */ int mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx) @@ -696,6 +700,7 @@ mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_device_driver_deregister - DeRegister device driver hooks + * @cb_idx: MPT protocol driver index */ void mpt_device_driver_deregister(int cb_idx) @@ -887,8 +892,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_send_handshake_request - Send MPT request via doorbell - * handshake method. + * mpt_send_handshake_request - Send MPT request via doorbell handshake method. * @handle: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * @reqBytes: Size of the request in bytes @@ -981,10 +985,13 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_host_page_access_control - provides mechanism for the host - * driver to control the IOC's Host Page Buffer access. + * mpt_host_page_access_control - control the IOC's Host Page Buffer access * @ioc: Pointer to MPT adapter structure * @access_control_value: define bits below + * @sleepFlag: Specifies whether the process can sleep + * + * Provides mechanism for the host driver to control the IOC's + * Host Page Buffer access. * * Access Control Value - bits[15:12] * 0h Reserved @@ -1022,10 +1029,10 @@ mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int slee /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_host_page_alloc - allocate system memory for the fw - * If we already allocated memory in past, then resend the same pointer. - * ioc@: Pointer to pointer to IOC adapter - * ioc_init@: Pointer to ioc init config page + * @ioc: Pointer to pointer to IOC adapter + * @ioc_init: Pointer to ioc init config page * + * If we already allocated memory in past, then resend the same pointer. * Returns 0 for success, non-zero for failure. */ static int @@ -1091,12 +1098,15 @@ return 0; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_verify_adapter - Given a unique IOC identifier, set pointer to - * the associated MPT adapter structure. + * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure. * @iocid: IOC unique identifier (integer) * @iocpp: Pointer to pointer to IOC adapter * - * Returns iocid and sets iocpp. + * Given a unique IOC identifier, set pointer to the associated MPT + * adapter structure. + * + * Returns iocid and sets iocpp if iocid is found. + * Returns -1 if iocid is not found. */ int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) @@ -1115,9 +1125,10 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_attach - Install a PCI intelligent MPT adapter. * @pdev: Pointer to pci_dev structure + * @id: PCI device ID information * * This routine performs all the steps necessary to bring the IOC of * a MPT adapter to a OPERATIONAL state. This includes registering @@ -1417,10 +1428,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_detach - Remove a PCI intelligent MPT adapter. * @pdev: Pointer to pci_dev structure - * */ void @@ -1466,10 +1476,10 @@ mpt_detach(struct pci_dev *pdev) */ #ifdef CONFIG_PM /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_suspend - Fusion MPT base driver suspend routine. - * - * + * @pdev: Pointer to pci_dev structure + * @state: new state to enter */ int mpt_suspend(struct pci_dev *pdev, pm_message_t state) @@ -1505,10 +1515,9 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_resume - Fusion MPT base driver resume routine. - * - * + * @pdev: Pointer to pci_dev structure */ int mpt_resume(struct pci_dev *pdev) @@ -1566,7 +1575,7 @@ mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_do_ioc_recovery - Initialize or recover MPT adapter. * @ioc: Pointer to MPT adapter structure * @reason: Event word / reason @@ -1892,13 +1901,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mpt_detect_bound_ports - Search for PCI bus/dev_function - * which matches PCI bus/dev_function (+/-1) for newly discovered 929, - * 929X, 1030 or 1035. +/** + * mpt_detect_bound_ports - Search for matching PCI bus/dev_function * @ioc: Pointer to MPT adapter structure * @pdev: Pointer to (struct pci_dev) structure * + * Search for PCI bus/dev_function which matches + * PCI bus/dev_function (+/-1) for newly discovered 929, + * 929X, 1030 or 1035. + * * If match on PCI dev_function +/-1 is found, bind the two MPT adapters * using alt_ioc pointer fields in their %MPT_ADAPTER structures. */ @@ -1945,9 +1956,9 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_adapter_disable - Disable misbehaving MPT adapter. - * @this: Pointer to MPT adapter structure + * @ioc: Pointer to MPT adapter structure */ static void mpt_adapter_disable(MPT_ADAPTER *ioc) @@ -2046,9 +2057,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mpt_adapter_dispose - Free all resources associated with a MPT - * adapter. +/** + * mpt_adapter_dispose - Free all resources associated with an MPT adapter * @ioc: Pointer to MPT adapter structure * * This routine unregisters h/w resources and frees all alloc'd memory @@ -2099,8 +2109,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * MptDisplayIocCapabilities - Disply IOC's capacilities. +/** + * MptDisplayIocCapabilities - Disply IOC's capabilities. * @ioc: Pointer to MPT adapter structure */ static void @@ -2142,7 +2152,7 @@ MptDisplayIocCapabilities(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * MakeIocReady - Get IOC to a READY state, using KickStart if needed. * @ioc: Pointer to MPT_ADAPTER structure * @force: Force hard KickStart of IOC @@ -2279,7 +2289,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_GetIocState - Get the current state of a MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @cooked: Request raw or cooked IOC state @@ -2304,7 +2314,7 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int cooked) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * GetIocFacts - Send IOCFacts request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @sleepFlag: Specifies whether the process can sleep @@ -2478,7 +2488,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * GetPortFacts - Send PortFacts request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @portnum: Port number @@ -2545,7 +2555,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * SendIocInit - Send IOCInit request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @sleepFlag: Specifies whether the process can sleep @@ -2630,7 +2640,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) } /* No need to byte swap the multibyte fields in the reply - * since we don't even look at it's contents. + * since we don't even look at its contents. */ dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n", @@ -2672,7 +2682,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * SendPortEnable - Send PortEnable request to MPT adapter port. * @ioc: Pointer to MPT_ADAPTER structure * @portnum: Port number to enable @@ -2723,9 +2733,13 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) return rc; } -/* - * ioc: Pointer to MPT_ADAPTER structure - * size - total FW bytes +/** + * mpt_alloc_fw_memory - allocate firmware memory + * @ioc: Pointer to MPT_ADAPTER structure + * @size: total FW bytes + * + * If memory has already been allocated, the same (cached) value + * is returned. */ void mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) @@ -2742,9 +2756,12 @@ mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) ioc->alloc_total += size; } } -/* - * If alt_img is NULL, delete from ioc structure. - * Else, delete a secondary image in same format. +/** + * mpt_free_fw_memory - free firmware memory + * @ioc: Pointer to MPT_ADAPTER structure + * + * If alt_img is NULL, delete from ioc structure. + * Else, delete a secondary image in same format. */ void mpt_free_fw_memory(MPT_ADAPTER *ioc) @@ -2763,7 +2780,7 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port. * @ioc: Pointer to MPT_ADAPTER structure * @sleepFlag: Specifies whether the process can sleep @@ -2865,10 +2882,10 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_downloadboot - DownloadBoot code * @ioc: Pointer to MPT_ADAPTER structure - * @flag: Specify which part of IOC memory is to be uploaded. + * @pFwHeader: Pointer to firmware header info * @sleepFlag: Specifies whether the process can sleep * * FwDownloadBoot requires Programmed IO access. @@ -3071,7 +3088,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * KickStart - Perform hard reset of MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @force: Force hard reset @@ -3145,12 +3162,12 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_diag_reset - Perform hard reset of the adapter. * @ioc: Pointer to MPT_ADAPTER structure * @ignore: Set if to honor and clear to ignore * the reset history bit - * @sleepflag: CAN_SLEEP if called in a non-interrupt thread, + * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread, * else set to NO_SLEEP (use mdelay instead) * * This routine places the adapter in diagnostic mode via the @@ -3436,11 +3453,12 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * SendIocReset - Send IOCReset request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @reset_type: reset type, expected values are * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET + * @sleepFlag: Specifies whether the process can sleep * * Send IOCReset request to the MPT adapter. * @@ -3494,11 +3512,12 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * initChainBuffers - Allocate memory for and initialize - * chain buffers, chain buffer control arrays and spinlock. - * @hd: Pointer to MPT_SCSI_HOST structure - * @init: If set, initialize the spin lock. +/** + * initChainBuffers - Allocate memory for and initialize chain buffers + * @ioc: Pointer to MPT_ADAPTER structure + * + * Allocates memory for and initializes chain buffers, + * chain buffer control arrays and spinlock. */ static int initChainBuffers(MPT_ADAPTER *ioc) @@ -3594,7 +3613,7 @@ initChainBuffers(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * PrimeIocFifos - Initialize IOC request and reply FIFOs. * @ioc: Pointer to MPT_ADAPTER structure * @@ -3891,15 +3910,15 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit - * in it's IntStatus register. +/** + * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge * @ioc: Pointer to MPT_ADAPTER structure * @howlong: How long to wait (in seconds) * @sleepFlag: Specifies whether the process can sleep * * This routine waits (up to ~2 seconds max) for IOC doorbell - * handshake ACKnowledge. + * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS + * bit in its IntStatus register being clear. * * Returns a negative value on failure, else wait loop count. */ @@ -3942,14 +3961,14 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit - * in it's IntStatus register. +/** + * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit * @ioc: Pointer to MPT_ADAPTER structure * @howlong: How long to wait (in seconds) * @sleepFlag: Specifies whether the process can sleep * - * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt. + * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt + * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register. * * Returns a negative value on failure, else wait loop count. */ @@ -3991,8 +4010,8 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * WaitForDoorbellReply - Wait for and capture a IOC handshake reply. +/** + * WaitForDoorbellReply - Wait for and capture an IOC handshake reply. * @ioc: Pointer to MPT_ADAPTER structure * @howlong: How long to wait (in seconds) * @sleepFlag: Specifies whether the process can sleep @@ -4077,7 +4096,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * GetLanConfigPages - Fetch LANConfig pages. * @ioc: Pointer to MPT_ADAPTER structure * @@ -4188,12 +4207,9 @@ GetLanConfigPages(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table +/** + * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table * @ioc: Pointer to MPT_ADAPTER structure - * @sas_address: 64bit SAS Address for operation. - * @target_id: specified target for operation - * @bus: specified bus for operation * @persist_opcode: see below * * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for @@ -4202,7 +4218,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc) * * NOTE: Don't use not this function during interrupt time. * - * Returns: 0 for success, non-zero error + * Returns 0 for success, non-zero error */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -4399,7 +4415,7 @@ mptbase_raid_process_event_data(MPT_ADAPTER *ioc, } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * GetIoUnitPage2 - Retrieve BIOS version and boot order information. * @ioc: Pointer to MPT_ADAPTER structure * @@ -4457,7 +4473,8 @@ GetIoUnitPage2(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 +/** + * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 * @ioc: Pointer to a Adapter Strucutre * @portnum: IOC port number * @@ -4644,7 +4661,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mpt_readScsiDevicePageHeaders - save version and length of SDP1 +/** + * mpt_readScsiDevicePageHeaders - save version and length of SDP1 * @ioc: Pointer to a Adapter Strucutre * @portnum: IOC port number * @@ -4996,9 +5014,8 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * SendEventNotification - Send EventNotification (on or off) request - * to MPT adapter. +/** + * SendEventNotification - Send EventNotification (on or off) request to adapter * @ioc: Pointer to MPT_ADAPTER structure * @EvSwitch: Event switch flags */ @@ -5062,8 +5079,8 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_config - Generic function to issue config message - * @ioc - Pointer to an adapter structure - * @cfg - Pointer to a configuration structure. Struct contains + * @ioc: Pointer to an adapter structure + * @pCfg: Pointer to a configuration structure. Struct contains * action, page address, direction, physical address * and pointer to a configuration page header * Page header is updated. @@ -5188,8 +5205,8 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mpt_timer_expired - Call back for timer process. +/** + * mpt_timer_expired - Callback for timer process. * Used only internal config functionality. * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long */ @@ -5214,12 +5231,12 @@ mpt_timer_expired(unsigned long data) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_ioc_reset - Base cleanup for hard reset * @ioc: Pointer to the adapter structure * @reset_phase: Indicates pre- or post-reset functionality * - * Remark: Free's resources with internally generated commands. + * Remark: Frees resources with internally generated commands. */ static int mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) @@ -5271,7 +5288,7 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. * * Returns 0 for success, non-zero for failure. @@ -5297,7 +5314,7 @@ procmpt_create(void) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries. * * Returns 0 for success, non-zero for failure. @@ -5311,16 +5328,16 @@ procmpt_destroy(void) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * procmpt_summary_read - Handle read request from /proc/mpt/summary - * or from /proc/mpt/iocN/summary. +/** + * procmpt_summary_read - Handle read request of a summary file * @buf: Pointer to area to write information * @start: Pointer to start pointer * @offset: Offset to start writing - * @request: + * @request: Amount of read data requested * @eof: Pointer to EOF integer * @data: Pointer * + * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary. * Returns number of characters written to process performing the read. */ static int @@ -5355,12 +5372,12 @@ procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eo } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * procmpt_version_read - Handle read request from /proc/mpt/version. * @buf: Pointer to area to write information * @start: Pointer to start pointer * @offset: Offset to start writing - * @request: + * @request: Amount of read data requested * @eof: Pointer to EOF integer * @data: Pointer * @@ -5411,12 +5428,12 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info. * @buf: Pointer to area to write information * @start: Pointer to start pointer * @offset: Offset to start writing - * @request: + * @request: Amount of read data requested * @eof: Pointer to EOF integer * @data: Pointer * @@ -5577,16 +5594,17 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_HardResetHandler - Generic reset handler, issue SCSI Task - * Management call based on input arg values. If TaskMgmt fails, - * return associated SCSI request. + * mpt_HardResetHandler - Generic reset handler * @ioc: Pointer to MPT_ADAPTER structure * @sleepFlag: Indicates if sleep or schedule must be called. * + * Issues SCSI Task Management call based on input arg values. + * If TaskMgmt fails, returns associated SCSI request. + * * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) * or a non-interrupt thread. In the former, must not call schedule(). * - * Remark: A return of -1 is a FATAL error case, as it means a + * Note: A return of -1 is a FATAL error case, as it means a * FW reload/initialization failed. * * Returns 0 for SUCCESS or -1 if FAILED. @@ -5935,13 +5953,14 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * ProcessEventNotification - Route a received EventNotificationReply to - * all currently regeistered event handlers. +/** + * ProcessEventNotification - Route EventNotificationReply to all event handlers * @ioc: Pointer to MPT_ADAPTER structure * @pEventReply: Pointer to EventNotification reply frame * @evHandlers: Pointer to integer, number of event handlers * + * Routes a received EventNotificationReply to all currently registered + * event handlers. * Returns sum of event handlers return values. */ static int @@ -6056,7 +6075,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_fc_log_info - Log information returned from Fibre Channel IOC. * @ioc: Pointer to MPT_ADAPTER structure * @log_info: U32 LogInfo reply word from the IOC @@ -6077,7 +6096,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_spi_log_info - Log information returned from SCSI Parallel IOC. * @ioc: Pointer to MPT_ADAPTER structure * @mr: Pointer to MPT reply frame @@ -6200,7 +6219,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) }; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_sas_log_info - Log information returned from SAS IOC. * @ioc: Pointer to MPT_ADAPTER structure * @log_info: U32 LogInfo reply word from the IOC @@ -6255,7 +6274,7 @@ union loginfo_type { } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC. * @ioc: Pointer to MPT_ADAPTER structure * @ioc_status: U32 IOCStatus word from IOC @@ -6416,7 +6435,7 @@ EXPORT_SYMBOL(mpt_free_fw_memory); EXPORT_SYMBOL(mptbase_sas_persist_operation); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * fusion_init - Fusion MPT base driver initialization routine. * * Returns 0 for success, non-zero for failure. @@ -6456,7 +6475,7 @@ fusion_init(void) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * fusion_exit - Perform driver unload cleanup. * * This routine frees all resources associated with each MPT adapter diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index ef2b55e19910..ca2f9107f145 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -1395,8 +1395,7 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptfc_init - Register MPT adapter(s) as SCSI host(s) with - * linux scsi mid-layer. + * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer. * * Returns 0 for success, non-zero for failure. */ @@ -1440,7 +1439,7 @@ mptfc_init(void) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptfc_remove - Removed fc infrastructure for devices + * mptfc_remove - Remove fc infrastructure for devices * @pdev: Pointer to pci_dev structure * */ diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 30524dc54b16..2c72c36b8171 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1230,15 +1230,15 @@ mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_proc_info - Return information about MPT adapter + * @host: scsi host struct + * @buffer: if write, user data; if read, buffer for user + * @start: returns the buffer address + * @offset: if write, 0; if read, the current offset into the buffer from + * the previous read. + * @length: if write, return length; + * @func: write = 1; read = 0 * * (linux scsi_host_template.info routine) - * - * buffer: if write, user data; if read, buffer for user - * length: if write, return length; - * offset: if write, 0; if read, the current offset into the buffer from - * the previous read. - * hostno: scsi host number - * func: if write = 1; if read = 0 */ int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, @@ -1902,8 +1902,7 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_host_reset - Perform a SCSI host adapter RESET! - * new_eh variant + * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant) * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to * * (linux scsi_host_template.eh_host_reset_handler routine) @@ -1949,8 +1948,7 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_tm_pending_wait - wait for pending task management request to - * complete. + * mptscsih_tm_pending_wait - wait for pending task management request to complete * @hd: Pointer to MPT host structure. * * Returns {SUCCESS,FAILED}. @@ -1982,6 +1980,7 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd) /** * mptscsih_tm_wait_for_completion - wait for completion of TM task * @hd: Pointer to MPT host structure. + * @timeout: timeout in seconds * * Returns {SUCCESS,FAILED}. */ @@ -3429,8 +3428,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) /** * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks. * @hd: Pointer to a SCSI HOST structure - * @vtarget: per device private data - * @lun: lun + * @vdevice: virtual target device * * Uses the ISR, but with special processing. * MUST be single-threaded. diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index f422c0d0621c..36641da59289 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -1100,8 +1100,7 @@ static struct pci_driver mptspi_driver = { /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptspi_init - Register MPT adapter(s) as SCSI host(s) with - * linux scsi mid-layer. + * mptspi_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer. * * Returns 0 for success, non-zero for failure. */ @@ -1135,7 +1134,6 @@ mptspi_init(void) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptspi_exit - Unregisters MPT adapter(s) - * */ static void __exit mptspi_exit(void) diff --git a/drivers/message/i2o/bus-osm.c b/drivers/message/i2o/bus-osm.c index d96c687aee93..c463dc2efc09 100644 --- a/drivers/message/i2o/bus-osm.c +++ b/drivers/message/i2o/bus-osm.c @@ -56,6 +56,9 @@ static int i2o_bus_scan(struct i2o_device *dev) /** * i2o_bus_store_scan - Scan the I2O Bus Adapter * @d: device which should be scanned + * @attr: device_attribute + * @buf: output buffer + * @count: buffer size * * Returns count. */ diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c index 55757af4e3b2..b9df143e4ff1 100644 --- a/drivers/message/i2o/device.c +++ b/drivers/message/i2o/device.c @@ -54,8 +54,8 @@ static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd, * @dev: I2O device to claim * @drv: I2O driver which wants to claim the device * - * Do the leg work to assign a device to a given OSM. If the claim succeed - * the owner of the rimary. If the attempt fails a negative errno code + * Do the leg work to assign a device to a given OSM. If the claim succeeds, + * the owner is the primary. If the attempt fails a negative errno code * is returned. On success zero is returned. */ int i2o_device_claim(struct i2o_device *dev) @@ -208,7 +208,7 @@ static struct i2o_device *i2o_device_alloc(void) /** * i2o_device_add - allocate a new I2O device and add it to the IOP - * @iop: I2O controller where the device is on + * @c: I2O controller that the device is on * @entry: LCT entry of the I2O device * * Allocate a new I2O device and initialize it with the LCT entry. The @@ -280,7 +280,7 @@ err: /** * i2o_device_remove - remove an I2O device from the I2O core - * @dev: I2O device which should be released + * @i2o_dev: I2O device which should be released * * Is used on I2O controller removal or LCT modification, when the device * is removed from the system. Note that the device could still hang diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c index 7fc7399bd2ec..9104b65ff70f 100644 --- a/drivers/message/i2o/driver.c +++ b/drivers/message/i2o/driver.c @@ -34,9 +34,7 @@ static spinlock_t i2o_drivers_lock; static struct i2o_driver **i2o_drivers; /** - * i2o_bus_match - Tell if a I2O device class id match the class ids of - * the I2O driver (OSM) - * + * i2o_bus_match - Tell if I2O device class id matches the class ids of the I2O driver (OSM) * @dev: device which should be verified * @drv: the driver to match against * @@ -248,7 +246,7 @@ int i2o_driver_dispatch(struct i2o_controller *c, u32 m) /** * i2o_driver_notify_controller_add_all - Send notify of added controller - * to all I2O drivers + * @c: newly added controller * * Send notifications to all registered drivers that a new controller was * added. @@ -267,8 +265,8 @@ void i2o_driver_notify_controller_add_all(struct i2o_controller *c) } /** - * i2o_driver_notify_controller_remove_all - Send notify of removed - * controller to all I2O drivers + * i2o_driver_notify_controller_remove_all - Send notify of removed controller + * @c: controller that is being removed * * Send notifications to all registered drivers that a controller was * removed. @@ -287,8 +285,8 @@ void i2o_driver_notify_controller_remove_all(struct i2o_controller *c) } /** - * i2o_driver_notify_device_add_all - Send notify of added device to all - * I2O drivers + * i2o_driver_notify_device_add_all - Send notify of added device + * @i2o_dev: newly added I2O device * * Send notifications to all registered drivers that a device was added. */ @@ -306,8 +304,8 @@ void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev) } /** - * i2o_driver_notify_device_remove_all - Send notify of removed device to - * all I2O drivers + * i2o_driver_notify_device_remove_all - Send notify of removed device + * @i2o_dev: device that is being removed * * Send notifications to all registered drivers that a device was removed. */ @@ -362,7 +360,7 @@ int __init i2o_driver_init(void) /** * i2o_driver_exit - clean up I2O drivers (OSMs) * - * Unregisters the I2O bus and free driver array. + * Unregisters the I2O bus and frees driver array. */ void __exit i2o_driver_exit(void) { diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index 9e529d8dd5cb..902753b2c661 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -94,8 +94,8 @@ static struct i2o_exec_wait *i2o_exec_wait_alloc(void) }; /** - * i2o_exec_wait_free - Free a i2o_exec_wait struct - * @i2o_exec_wait: I2O wait data which should be cleaned up + * i2o_exec_wait_free - Free an i2o_exec_wait struct + * @wait: I2O wait data which should be cleaned up */ static void i2o_exec_wait_free(struct i2o_exec_wait *wait) { @@ -105,7 +105,7 @@ static void i2o_exec_wait_free(struct i2o_exec_wait *wait) /** * i2o_msg_post_wait_mem - Post and wait a message with DMA buffers * @c: controller - * @m: message to post + * @msg: message to post * @timeout: time in seconds to wait * @dma: i2o_dma struct of the DMA buffer to free on failure * @@ -269,6 +269,7 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, /** * i2o_exec_show_vendor_id - Displays Vendor ID of controller * @d: device of which the Vendor ID should be displayed + * @attr: device_attribute to display * @buf: buffer into which the Vendor ID should be printed * * Returns number of bytes printed into buffer. @@ -290,6 +291,7 @@ static ssize_t i2o_exec_show_vendor_id(struct device *d, /** * i2o_exec_show_product_id - Displays Product ID of controller * @d: device of which the Product ID should be displayed + * @attr: device_attribute to display * @buf: buffer into which the Product ID should be printed * * Returns number of bytes printed into buffer. @@ -365,7 +367,7 @@ static int i2o_exec_remove(struct device *dev) /** * i2o_exec_lct_modified - Called on LCT NOTIFY reply - * @c: I2O controller on which the LCT has modified + * @work: work struct for a specific controller * * This function handles asynchronus LCT NOTIFY replies. It parses the * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 70ae00253321..da9859f2caf2 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -259,7 +259,7 @@ static int i2o_block_device_unlock(struct i2o_device *dev, u32 media_id) /** * i2o_block_device_power - Power management for device dev * @dev: I2O device which should receive the power management request - * @operation: Operation which should be send + * @op: Operation to send * * Send a power management request to the device dev. * @@ -315,7 +315,7 @@ static inline struct i2o_block_request *i2o_block_request_alloc(void) * i2o_block_request_free - Frees a I2O block request * @ireq: I2O block request which should be freed * - * Fres the allocated memory (give it back to the request mempool). + * Frees the allocated memory (give it back to the request mempool). */ static inline void i2o_block_request_free(struct i2o_block_request *ireq) { @@ -326,6 +326,7 @@ static inline void i2o_block_request_free(struct i2o_block_request *ireq) * i2o_block_sglist_alloc - Allocate the SG list and map it * @c: I2O controller to which the request belongs * @ireq: I2O block request + * @mptr: message body pointer * * Builds the SG list and map it to be accessable by the controller. * @@ -490,7 +491,7 @@ static void i2o_block_end_request(struct request *req, int uptodate, * i2o_block_reply - Block OSM reply handler. * @c: I2O controller from which the message arrives * @m: message id of reply - * qmsg: the actuall I2O message reply + * @msg: the actual I2O message reply * * This function gets all the message replies. * @@ -602,6 +603,8 @@ static void i2o_block_biosparam(unsigned long capacity, unsigned short *cyls, /** * i2o_block_open - Open the block device + * @inode: inode for block device being opened + * @file: file to open * * Power up the device, mount and lock the media. This function is called, * if the block device is opened for access. @@ -629,6 +632,8 @@ static int i2o_block_open(struct inode *inode, struct file *file) /** * i2o_block_release - Release the I2O block device + * @inode: inode for block device being released + * @file: file to close * * Unlock and unmount the media, and power down the device. Gets called if * the block device is closed. @@ -675,6 +680,8 @@ static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo) /** * i2o_block_ioctl - Issue device specific ioctl calls. + * @inode: inode for block device ioctl + * @file: file for ioctl * @cmd: ioctl command * @arg: arg * @@ -902,7 +909,7 @@ static int i2o_block_transfer(struct request *req) /** * i2o_block_request_fn - request queue handling function - * q: request queue from which the request could be fetched + * @q: request queue from which the request could be fetched * * Takes the next request from the queue, transfers it and if no error * occurs dequeue it from the queue. On arrival of the reply the message diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c index 3d2e76eea93e..a61cb17c5c12 100644 --- a/drivers/message/i2o/i2o_proc.c +++ b/drivers/message/i2o/i2o_proc.c @@ -163,7 +163,7 @@ static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len) * i2o_get_class_name - do i2o class name lookup * @class: class number * - * Return a descriptive string for an i2o class + * Return a descriptive string for an i2o class. */ static const char *i2o_get_class_name(int class) { diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index d5f93b12b6f1..1045c8a518bb 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -411,8 +411,7 @@ static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev) }; /** - * i2o_scsi_notify_device_remove - Retrieve notifications of removed - * devices + * i2o_scsi_notify_device_remove - Retrieve notifications of removed devices * @i2o_dev: the I2O device which was removed * * If a I2O device is removed, we catch the notification to remove the @@ -432,8 +431,7 @@ static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev) }; /** - * i2o_scsi_notify_controller_add - Retrieve notifications of added - * controllers + * i2o_scsi_notify_controller_add - Retrieve notifications of added controllers * @c: the controller which was added * * If a I2O controller is added, we catch the notification to add a @@ -463,8 +461,7 @@ static void i2o_scsi_notify_controller_add(struct i2o_controller *c) }; /** - * i2o_scsi_notify_controller_remove - Retrieve notifications of removed - * controllers + * i2o_scsi_notify_controller_remove - Retrieve notifications of removed controllers * @c: the controller which was removed * * If a I2O controller is removed, we catch the notification to remove the @@ -751,7 +748,7 @@ static int i2o_scsi_abort(struct scsi_cmnd *SCpnt) * @capacity: size in sectors * @ip: geometry array * - * This is anyones guess quite frankly. We use the same rules everyone + * This is anyone's guess quite frankly. We use the same rules everyone * else appears to and hope. It seems to work. */ diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c index 8287f95c8c42..3661e6e065d2 100644 --- a/drivers/message/i2o/pci.c +++ b/drivers/message/i2o/pci.c @@ -259,6 +259,7 @@ static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id) /** * i2o_pci_irq_enable - Allocate interrupt for I2O controller + * @c: i2o_controller that the request is for * * Allocate an interrupt for the I2O controller, and activate interrupts * on the I2O controller. @@ -305,7 +306,7 @@ static void i2o_pci_irq_disable(struct i2o_controller *c) /** * i2o_pci_probe - Probe the PCI device for an I2O controller - * @dev: PCI device to test + * @pdev: PCI device to test * @id: id which matched with the PCI device id table * * Probe the PCI device for any device which is a memory of the @@ -447,7 +448,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev, /** * i2o_pci_remove - Removes a I2O controller from the system - * pdev: I2O controller which should be removed + * @pdev: I2O controller which should be removed * * Reset the I2O controller, disable interrupts and remove all allocated * resources. diff --git a/include/linux/i2o.h b/include/linux/i2o.h index 2514f4e286b7..52f53e2e70c3 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -986,7 +986,8 @@ extern void i2o_driver_unregister(struct i2o_driver *); /** * i2o_driver_notify_controller_add - Send notification of added controller - * to a single I2O driver + * @drv: I2O driver + * @c: I2O controller * * Send notification of added controller to a single registered driver. */ @@ -998,8 +999,9 @@ static inline void i2o_driver_notify_controller_add(struct i2o_driver *drv, }; /** - * i2o_driver_notify_controller_remove - Send notification of removed - * controller to a single I2O driver + * i2o_driver_notify_controller_remove - Send notification of removed controller + * @drv: I2O driver + * @c: I2O controller * * Send notification of removed controller to a single registered driver. */ @@ -1011,8 +1013,9 @@ static inline void i2o_driver_notify_controller_remove(struct i2o_driver *drv, }; /** - * i2o_driver_notify_device_add - Send notification of added device to a - * single I2O driver + * i2o_driver_notify_device_add - Send notification of added device + * @drv: I2O driver + * @i2o_dev: the added i2o_device * * Send notification of added device to a single registered driver. */ @@ -1025,7 +1028,8 @@ static inline void i2o_driver_notify_device_add(struct i2o_driver *drv, /** * i2o_driver_notify_device_remove - Send notification of removed device - * to a single I2O driver + * @drv: I2O driver + * @i2o_dev: the added i2o_device * * Send notification of removed device to a single registered driver. */ @@ -1148,7 +1152,7 @@ static inline void i2o_msg_post(struct i2o_controller *c, /** * i2o_msg_post_wait - Post and wait a message and wait until return * @c: controller - * @m: message to post + * @msg: message to post * @timeout: time in seconds to wait * * This API allows an OSM to post a message and then be told whether or -- cgit v1.2.3 From 83b7b44e1c1e9e493ccd4146558481ab5af0116a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 6 Dec 2006 20:38:53 -0800 Subject: [PATCH] fs: reorder some 'struct inode' fields to speedup i_size manipulations On 32bits SMP platforms, 64bits i_size is protected by a seqcount (i_size_seqcount). When i_size is read or written, i_size_seqcount is read/written as well, so it make sense to group these two fields together in the same cache line. This patch moves i_size_seqcount next to i_size, and also moves i_version to let offsetof(struct inode, i_size) being 0x40 instead of 0x3c (for 32bits platforms). For 64 bits platforms, i_size_seqcount doesnt exist, and the move of a 'long i_version' should not introduce a new hole because of padding. Signed-off-by: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index d791bae9de9c..3a1927e516d0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -548,12 +548,15 @@ struct inode { uid_t i_uid; gid_t i_gid; dev_t i_rdev; + unsigned long i_version; loff_t i_size; +#ifdef __NEED_I_SIZE_ORDERED + seqcount_t i_size_seqcount; +#endif struct timespec i_atime; struct timespec i_mtime; struct timespec i_ctime; unsigned int i_blkbits; - unsigned long i_version; blkcnt_t i_blocks; unsigned short i_bytes; spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ @@ -598,9 +601,6 @@ struct inode { void *i_security; #endif void *i_private; /* fs or device private pointer */ -#ifdef __NEED_I_SIZE_ORDERED - seqcount_t i_size_seqcount; -#endif }; /* -- cgit v1.2.3 From f7dff2b12654149c9cac8d8c79b6588759edd5a9 Mon Sep 17 00:00:00 2001 From: Gautham R Shenoy Date: Wed, 6 Dec 2006 20:38:58 -0800 Subject: [PATCH] Handle per-subsystem mutexes for CONFIG_HOTPLUG_CPU not set Provide a common interface for all the subsystems to lock and unlock their per-subsystem hotcpu mutexes. When CONFIG_HOTPLUG_CPU is not set, these operations would be no-ops. [akpm@osdl.org: macros -> inlines] Signed-off-by: Gautham R Shenoy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cpu.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 71dc6ba4f73f..bf00ce6ecadf 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -24,6 +24,7 @@ #include #include #include +#include struct cpu { int node_id; /* The node which contains the CPU */ @@ -74,6 +75,17 @@ extern struct sysdev_class cpu_sysdev_class; #ifdef CONFIG_HOTPLUG_CPU /* Stop CPUs going up and down. */ + +static inline void cpuhotplug_mutex_lock(struct mutex *cpu_hp_mutex) +{ + mutex_lock(cpu_hp_mutex); +} + +static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex) +{ + mutex_unlock(cpu_hp_mutex); +} + extern void lock_cpu_hotplug(void); extern void unlock_cpu_hotplug(void); #define hotcpu_notifier(fn, pri) { \ @@ -85,7 +97,14 @@ extern void unlock_cpu_hotplug(void); #define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb) int cpu_down(unsigned int cpu); #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu)) -#else + +#else /* CONFIG_HOTPLUG_CPU */ + +static inline void cpuhotplug_mutex_lock(struct mutex *cpu_hp_mutex) +{ } +static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex) +{ } + #define lock_cpu_hotplug() do { } while (0) #define unlock_cpu_hotplug() do { } while (0) #define lock_cpu_hotplug_interruptible() 0 @@ -95,7 +114,7 @@ int cpu_down(unsigned int cpu); /* CPUs don't go offline once they're online w/o CONFIG_HOTPLUG_CPU */ static inline int cpu_is_offline(int cpu) { return 0; } -#endif +#endif /* CONFIG_HOTPLUG_CPU */ #ifdef CONFIG_SUSPEND_SMP extern int disable_nonboot_cpus(void); -- cgit v1.2.3 From 0b71c8e76d20d0329bf7e54f172389f3c343dc41 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Wed, 6 Dec 2006 20:39:15 -0800 Subject: [PATCH] remove useless carta_random32.h Remove the carta_random32.h header file. The carta_random32() function was was put in and removed in favor of random32(). In the removal process, the header file was forgotten. Signed-off-by: Stephane Eranian Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/carta_random32.h | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 include/linux/carta_random32.h (limited to 'include/linux') diff --git a/include/linux/carta_random32.h b/include/linux/carta_random32.h deleted file mode 100644 index f6f3bd9f20b5..000000000000 --- a/include/linux/carta_random32.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Fast, simple, yet decent quality random number generator based on - * a paper by David G. Carta ("Two Fast Implementations of the - * `Minimal Standard' Random Number Generator," Communications of the - * ACM, January, 1990). - * - * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P. - * Contributed by Stephane Eranian - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -#ifndef _LINUX_CARTA_RANDOM32_H_ -#define _LINUX_CARTA_RANDOM32_H_ - -u64 carta_random32(u64 seed); - -#endif /* _LINUX_CARTA_RANDOM32_H_ */ -- cgit v1.2.3 From 2ee91f197c0bc654b24eed5831fd12aa0d566a7d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 6 Dec 2006 20:39:32 -0800 Subject: [PATCH] lockdep: show more details about self-test failures Make the locking self-test failures (of 'FAILURE' type) easier to debug by printing more information. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/debug_locks.h | 2 +- kernel/mutex-debug.c | 3 +++ lib/locking-selftest.c | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h index 952bee79a8f3..a1c10b0c4cf0 100644 --- a/include/linux/debug_locks.h +++ b/include/linux/debug_locks.h @@ -24,7 +24,7 @@ extern int debug_locks_off(void); int __ret = 0; \ \ if (unlikely(c)) { \ - if (debug_locks_off()) \ + if (debug_locks_silent || debug_locks_off()) \ WARN_ON(1); \ __ret = 1; \ } \ diff --git a/kernel/mutex-debug.c b/kernel/mutex-debug.c index 18651641a7b5..841539d72c55 100644 --- a/kernel/mutex-debug.c +++ b/kernel/mutex-debug.c @@ -77,6 +77,9 @@ void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter, void debug_mutex_unlock(struct mutex *lock) { + if (unlikely(!debug_locks)) + return; + DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info()); DEBUG_LOCKS_WARN_ON(lock->magic != lock); DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next); diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c index 7945787f439a..280332c1827c 100644 --- a/lib/locking-selftest.c +++ b/lib/locking-selftest.c @@ -963,7 +963,9 @@ static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask) printk("failed|"); } else { unexpected_testcase_failures++; + printk("FAILED|"); + dump_stack(); } } else { testcase_successes++; -- cgit v1.2.3 From 12d40e43d251de4fa1f982567fc8b4ee5e858367 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 6 Dec 2006 20:39:53 -0800 Subject: [PATCH] Save some bytes in struct inode [acme@newtoy net-2.6.20]$ pahole --cacheline 64 fs/inode.o inode /* /pub/scm/linux/kernel/git/acme/net-2.6.20/include/linux/dcache.h:86 */ struct inode { struct hlist_node i_hash; /* 0 8 */ struct list_head i_list; /* 8 8 */ struct list_head i_sb_list; /* 16 8 */ struct list_head i_dentry; /* 24 8 */ long unsigned int i_ino; /* 32 4 */ atomic_t i_count; /* 36 4 */ umode_t i_mode; /* 40 2 */ /* XXX 2 bytes hole, try to pack */ unsigned int i_nlink; /* 44 4 */ uid_t i_uid; /* 48 4 */ gid_t i_gid; /* 52 4 */ dev_t i_rdev; /* 56 4 */ loff_t i_size; /* 60 8 */ struct timespec i_atime; /* 68 8 */ struct timespec i_mtime; /* 76 8 */ struct timespec i_ctime; /* 84 8 */ unsigned int i_blkbits; /* 92 4 */ long unsigned int i_version; /* 96 4 */ blkcnt_t i_blocks; /* 100 4 */ short unsigned int i_bytes; /* 104 2 */ /* XXX 2 bytes hole, try to pack */ spinlock_t i_lock; /* 108 40 */ struct mutex i_mutex; /* 148 76 */ struct rw_semaphore i_alloc_sem; /* 224 64 */ struct inode_operations * i_op; /* 288 4 */ const struct file_operations * i_fop; /* 292 4 */ struct super_block * i_sb; /* 296 4 */ struct file_lock * i_flock; /* 300 4 */ struct address_space * i_mapping; /* 304 4 */ struct address_space i_data; /* 308 188 */ struct list_head i_devices; /* 496 8 */ union ; /* 504 4 */ int i_cindex; /* 508 4 */ __u32 i_generation; /* 512 4 */ /* ---------- cacheline 8 boundary ---------- */ long unsigned int i_dnotify_mask; /* 516 4 */ struct dnotify_struct * i_dnotify; /* 520 4 */ struct list_head inotify_watches; /* 524 8 */ struct mutex inotify_mutex; /* 532 76 */ long unsigned int i_state; /* 608 4 */ long unsigned int dirtied_when; /* 612 4 */ unsigned int i_flags; /* 616 4 */ atomic_t i_writecount; /* 620 4 */ void * i_security; /* 624 4 */ void * i_private; /* 628 4 */ }; /* size: 632, sum members: 628, holes: 2, sum holes: 4 */ [acme@newtoy net-2.6.20]$ So just moving i_mode to after i_bytes we save 4 bytes by nuking both holes: [acme@newtoy net-2.6.20]$ codiff -V /tmp/inode.o.before fs/inode.o /pub/scm/linux/kernel/git/acme/net-2.6.20/fs/inode.c: struct inode | -4 i_mode; from: umode_t /* 40(0) 2(0) */ to: umode_t /* 102(0) 2(0) */ 1 struct changed [acme@newtoy net-2.6.20]$ I've prunned all the other offset changes, only this one is of interest here. So now we have: [acme@newtoy net-2.6.20]$ pahole --cacheline 64 ../OUTPUT/qemu/net-2.6.20/fs/inode.o inode /* /pub/scm/linux/kernel/git/acme/net-2.6.20/include/linux/dcache.h:86 */ struct inode { struct hlist_node i_hash; /* 0 8 */ struct list_head i_list; /* 8 8 */ struct list_head i_sb_list; /* 16 8 */ struct list_head i_dentry; /* 24 8 */ long unsigned int i_ino; /* 32 4 */ atomic_t i_count; /* 36 4 */ unsigned int i_nlink; /* 40 4 */ uid_t i_uid; /* 44 4 */ gid_t i_gid; /* 48 4 */ dev_t i_rdev; /* 52 4 */ loff_t i_size; /* 56 8 */ /* ---------- cacheline 1 boundary ---------- */ struct timespec i_atime; /* 64 8 */ struct timespec i_mtime; /* 72 8 */ struct timespec i_ctime; /* 80 8 */ unsigned int i_blkbits; /* 88 4 */ long unsigned int i_version; /* 92 4 */ blkcnt_t i_blocks; /* 96 4 */ short unsigned int i_bytes; /* 100 2 */ umode_t i_mode; /* 102 2 */ spinlock_t i_lock; /* 104 40 */ struct mutex i_mutex; /* 144 76 */ struct rw_semaphore i_alloc_sem; /* 220 64 */ struct inode_operations * i_op; /* 284 4 */ const struct file_operations * i_fop; /* 288 4 */ struct super_block * i_sb; /* 292 4 */ struct file_lock * i_flock; /* 296 4 */ struct address_space * i_mapping; /* 300 4 */ struct address_space i_data; /* 304 188 */ struct list_head i_devices; /* 492 8 */ union ; /* 500 4 */ int i_cindex; /* 504 4 */ __u32 i_generation; /* 508 4 */ /* ---------- cacheline 8 boundary ---------- */ long unsigned int i_dnotify_mask; /* 512 4 */ struct dnotify_struct * i_dnotify; /* 516 4 */ struct list_head inotify_watches; /* 520 8 */ struct mutex inotify_mutex; /* 528 76 */ long unsigned int i_state; /* 604 4 */ long unsigned int dirtied_when; /* 608 4 */ unsigned int i_flags; /* 612 4 */ atomic_t i_writecount; /* 616 4 */ void * i_security; /* 620 4 */ void * i_private; /* 624 4 */ }; /* size: 628 */ [acme@newtoy net-2.6.20]$ Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 3a1927e516d0..70b99fbb560b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -543,7 +543,6 @@ struct inode { struct list_head i_dentry; unsigned long i_ino; atomic_t i_count; - umode_t i_mode; unsigned int i_nlink; uid_t i_uid; gid_t i_gid; @@ -559,6 +558,7 @@ struct inode { unsigned int i_blkbits; blkcnt_t i_blocks; unsigned short i_bytes; + umode_t i_mode; spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ struct mutex i_mutex; struct rw_semaphore i_alloc_sem; -- cgit v1.2.3 From 0da1480ec33d4bac8c32051c1d33202be6dc439f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 6 Dec 2006 20:40:03 -0800 Subject: [PATCH] proper prototype for remove_inode_dquot_ref() Add a proper prototype for remove_inode_dquot_ref() in include/linux/quotaops.h Signed-off-by: Adrian Bunk Acked-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/inode.c | 3 --- include/linux/quotaops.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/fs/inode.c b/fs/inode.c index 699aa4f7aa74..9ecccab7326d 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1242,9 +1242,6 @@ EXPORT_SYMBOL(inode_needs_sync); */ #ifdef CONFIG_QUOTA -/* Function back in dquot.c */ -int remove_inode_dquot_ref(struct inode *, int, struct list_head *); - void remove_dquot_ref(struct super_block *sb, int type, struct list_head *tofree_head) { diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 5110201a4159..90c23f690c0d 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -37,6 +37,9 @@ extern int dquot_release(struct dquot *dquot); extern int dquot_commit_info(struct super_block *sb, int type); extern int dquot_mark_dquot_dirty(struct dquot *dquot); +int remove_inode_dquot_ref(struct inode *inode, int type, + struct list_head *tofree_head); + extern int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path); extern int vfs_quota_on_mount(struct super_block *sb, char *qf_name, int format_id, int type); -- cgit v1.2.3 From 65867beb0de4d055637476327b533e5ffbec2b97 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 6 Dec 2006 20:40:07 -0800 Subject: [PATCH] Trivial cleanup in the PCI IDs for the CS5535 Rename a poorly worded PCI ID for the Geode GX and CS5535 companion chips. The graphics processor and host bridge actually live in the northbridge on the integrated processor, not in the companion chip. Signed-off-by: Jordan Crouse Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/geode/gxfb_core.c | 2 +- include/linux/pci_ids.h | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index 0d3643fc6293..a454dcb8e215 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -380,7 +380,7 @@ static void gxfb_remove(struct pci_dev *pdev) } static struct pci_device_id gxfb_id_table[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_VIDEO, + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO, PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0 }, { 0, } diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index dcdb90f06d73..ff2dcb436cd0 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -390,7 +390,7 @@ #define PCI_DEVICE_ID_NS_CS5535_IDE 0x002d #define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e #define PCI_DEVICE_ID_NS_CS5535_USB 0x002f -#define PCI_DEVICE_ID_NS_CS5535_VIDEO 0x0030 +#define PCI_DEVICE_ID_NS_GX_VIDEO 0x0030 #define PCI_DEVICE_ID_NS_SATURN 0x0035 #define PCI_DEVICE_ID_NS_SCx200_BRIDGE 0x0500 #define PCI_DEVICE_ID_NS_SCx200_SMI 0x0501 @@ -403,8 +403,7 @@ #define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515 #define PCI_DEVICE_ID_NS_87410 0xd001 -#define PCI_DEVICE_ID_NS_CS5535_HOST_BRIDGE 0x0028 -#define PCI_DEVICE_ID_NS_CS5535_ISA_BRIDGE 0x002b +#define PCI_DEVICE_ID_NS_GX_HOST_BRIDGE 0x0028 #define PCI_VENDOR_ID_TSENG 0x100c #define PCI_DEVICE_ID_TSENG_W32P_2 0x3202 -- cgit v1.2.3 From 5296c7bec8c85aa0a6964eca9ff4a1a8847fba8a Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 6 Dec 2006 20:40:10 -0800 Subject: [PATCH] fs: reiserfs add missing brackets Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/reiserfs_fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index 7bc6bfb86253..d0e4dce33ad5 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -739,7 +739,7 @@ struct block_head { #define PUT_B_FREE_SPACE(p_s_bh,val) do { set_blkh_free_space(B_BLK_HEAD(p_s_bh),val); } while (0) /* Get right delimiting key. -- little endian */ -#define B_PRIGHT_DELIM_KEY(p_s_bh) (&(blk_right_delim_key(B_BLK_HEAD(p_s_bh)) +#define B_PRIGHT_DELIM_KEY(p_s_bh) (&(blk_right_delim_key(B_BLK_HEAD(p_s_bh)))) /* Does the buffer contain a disk leaf. */ #define B_IS_ITEMS_LEVEL(p_s_bh) (B_LEVEL(p_s_bh) == DISK_LEAF_NODE_LEVEL) -- cgit v1.2.3 From a0e7688df1484fbf4d6d61c31f7d61a5d8cacf3c Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 6 Dec 2006 20:40:12 -0800 Subject: [PATCH] Kbuild: add 3 more header files to get properly "unifdef"ed Add 3 more files to get "unifdef"ed when creating sanitized headers with "make headers_install". Signed-off-by: Robert P. J. Day Acked-by: David Woodhouse Acked-by: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/Kbuild | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index ff433126361f..e618b25b5add 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -221,6 +221,7 @@ unifdef-y += if_bridge.h unifdef-y += if_ec.h unifdef-y += if_eql.h unifdef-y += if_ether.h +unifdef-y += if_fddi.h unifdef-y += if_frad.h unifdef-y += if_ltalk.h unifdef-y += if_pppox.h @@ -282,6 +283,7 @@ unifdef-y += nvram.h unifdef-y += parport.h unifdef-y += patchkey.h unifdef-y += pci.h +unifdef-y += personality.h unifdef-y += pktcdvd.h unifdef-y += pmu.h unifdef-y += poll.h @@ -337,6 +339,7 @@ unifdef-y += videodev.h unifdef-y += wait.h unifdef-y += wanrouter.h unifdef-y += watchdog.h +unifdef-y += wireless.h unifdef-y += xfrm.h objhdr-y += version.h -- cgit v1.2.3 From 15ad7cdcfd76450d4beebc789ec646664238184d Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 6 Dec 2006 20:40:36 -0800 Subject: [PATCH] struct seq_operations and struct file_operations constification - move some file_operations structs into the .rodata section - move static strings from policy_types[] array into the .rodata section - fix generic seq_operations usages, so that those structs may be defined as "const" as well [akpm@osdl.org: couple of fixes] Signed-off-by: Helge Deller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/seq_file.c | 4 ++-- include/linux/cpuset.h | 2 +- include/linux/mmzone.h | 2 +- include/linux/relay.h | 2 +- include/linux/sched.h | 2 +- include/linux/seq_file.h | 4 ++-- kernel/configs.c | 2 +- kernel/cpuset.c | 4 ++-- kernel/dma.c | 2 +- kernel/futex.c | 2 +- kernel/kallsyms.c | 4 ++-- kernel/lockdep_proc.c | 6 +++--- kernel/module.c | 2 +- kernel/power/user.c | 2 +- kernel/profile.c | 2 +- kernel/relay.c | 2 +- kernel/resource.c | 6 +++--- kernel/sched.c | 2 +- kernel/sysctl.c | 2 +- mm/mempolicy.c | 4 ++-- mm/page_alloc.c | 2 +- mm/shmem.c | 4 ++-- mm/slab.c | 4 ++-- mm/swapfile.c | 4 ++-- mm/vmstat.c | 8 ++++---- 25 files changed, 40 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/fs/seq_file.c b/fs/seq_file.c index 555b9ac04c25..10690aa401c7 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -26,7 +26,7 @@ * ERR_PTR(error). In the end of sequence they return %NULL. ->show() * returns 0 in case of success and negative number in case of error. */ -int seq_open(struct file *file, struct seq_operations *op) +int seq_open(struct file *file, const struct seq_operations *op) { struct seq_file *p = file->private_data; @@ -408,7 +408,7 @@ EXPORT_SYMBOL(single_open); int single_release(struct inode *inode, struct file *file) { - struct seq_operations *op = ((struct seq_file *)file->private_data)->op; + const struct seq_operations *op = ((struct seq_file *)file->private_data)->op; int res = seq_release(inode, file); kfree(op); return res; diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 748d2c996631..8821e1f75b44 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -46,7 +46,7 @@ extern int cpuset_excl_nodes_overlap(const struct task_struct *p); extern int cpuset_memory_pressure_enabled; extern void __cpuset_memory_pressure_bump(void); -extern struct file_operations proc_cpuset_operations; +extern const struct file_operations proc_cpuset_operations; extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer); extern void cpuset_lock(void); diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index da6002dec205..e339a7345f25 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -278,7 +278,7 @@ struct zone { /* * rarely used fields: */ - char *name; + const char *name; } ____cacheline_internodealigned_in_smp; /* diff --git a/include/linux/relay.h b/include/linux/relay.h index 0e3d91b76996..c6a48bfc8b14 100644 --- a/include/linux/relay.h +++ b/include/linux/relay.h @@ -274,7 +274,7 @@ static inline void subbuf_start_reserve(struct rchan_buf *buf, /* * exported relay file operations, kernel/relay.c */ -extern struct file_operations relay_file_operations; +extern const struct file_operations relay_file_operations; #endif /* _LINUX_RELAY_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 3a767242e72f..dede82c63445 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -573,7 +573,7 @@ struct sched_info { #endif /* defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) */ #ifdef CONFIG_SCHEDSTATS -extern struct file_operations proc_schedstat_operations; +extern const struct file_operations proc_schedstat_operations; #endif /* CONFIG_SCHEDSTATS */ #ifdef CONFIG_TASK_DELAY_ACCT diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index b95f6eb7254c..3e3cccbb1cac 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -20,7 +20,7 @@ struct seq_file { loff_t index; loff_t version; struct mutex lock; - struct seq_operations *op; + const struct seq_operations *op; void *private; }; @@ -31,7 +31,7 @@ struct seq_operations { int (*show) (struct seq_file *m, void *v); }; -int seq_open(struct file *, struct seq_operations *); +int seq_open(struct file *, const struct seq_operations *); ssize_t seq_read(struct file *, char __user *, size_t, loff_t *); loff_t seq_lseek(struct file *, loff_t, int); int seq_release(struct inode *, struct file *); diff --git a/kernel/configs.c b/kernel/configs.c index f9e31974f4ad..8fa1fb28f8a7 100644 --- a/kernel/configs.c +++ b/kernel/configs.c @@ -75,7 +75,7 @@ ikconfig_read_current(struct file *file, char __user *buf, return count; } -static struct file_operations ikconfig_file_ops = { +static const struct file_operations ikconfig_file_ops = { .owner = THIS_MODULE, .read = ikconfig_read_current, }; diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 9b62b4c03ad0..4ef1d29297ca 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1531,7 +1531,7 @@ static int cpuset_rename(struct inode *old_dir, struct dentry *old_dentry, return simple_rename(old_dir, old_dentry, new_dir, new_dentry); } -static struct file_operations cpuset_file_operations = { +static const struct file_operations cpuset_file_operations = { .read = cpuset_file_read, .write = cpuset_file_write, .llseek = generic_file_llseek, @@ -2605,7 +2605,7 @@ static int cpuset_open(struct inode *inode, struct file *file) return single_open(file, proc_cpuset_show, pid); } -struct file_operations proc_cpuset_operations = { +const struct file_operations proc_cpuset_operations = { .open = cpuset_open, .read = seq_read, .llseek = seq_lseek, diff --git a/kernel/dma.c b/kernel/dma.c index 2020644c938a..937b13ca33ba 100644 --- a/kernel/dma.c +++ b/kernel/dma.c @@ -140,7 +140,7 @@ static int proc_dma_open(struct inode *inode, struct file *file) return single_open(file, proc_dma_show, NULL); } -static struct file_operations proc_dma_operations = { +static const struct file_operations proc_dma_operations = { .open = proc_dma_open, .read = seq_read, .llseek = seq_lseek, diff --git a/kernel/futex.c b/kernel/futex.c index a8302a1620ea..95989a3b4168 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1492,7 +1492,7 @@ static unsigned int futex_poll(struct file *filp, return ret; } -static struct file_operations futex_fops = { +static const struct file_operations futex_fops = { .release = futex_close, .poll = futex_poll, }; diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 54befe36ee0b..ab63cfc42992 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -398,7 +398,7 @@ static int s_show(struct seq_file *m, void *p) return 0; } -static struct seq_operations kallsyms_op = { +static const struct seq_operations kallsyms_op = { .start = s_start, .next = s_next, .stop = s_stop, @@ -433,7 +433,7 @@ static int kallsyms_release(struct inode *inode, struct file *file) return seq_release(inode, file); } -static struct file_operations kallsyms_operations = { +static const struct file_operations kallsyms_operations = { .open = kallsyms_open, .read = seq_read, .llseek = seq_lseek, diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index f6e72eaab3fa..b554b40a4aa6 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -113,7 +113,7 @@ static int l_show(struct seq_file *m, void *v) return 0; } -static struct seq_operations lockdep_ops = { +static const struct seq_operations lockdep_ops = { .start = l_start, .next = l_next, .stop = l_stop, @@ -135,7 +135,7 @@ static int lockdep_open(struct inode *inode, struct file *file) return res; } -static struct file_operations proc_lockdep_operations = { +static const struct file_operations proc_lockdep_operations = { .open = lockdep_open, .read = seq_read, .llseek = seq_lseek, @@ -319,7 +319,7 @@ static int lockdep_stats_open(struct inode *inode, struct file *file) return single_open(file, lockdep_stats_show, NULL); } -static struct file_operations proc_lockdep_stats_operations = { +static const struct file_operations proc_lockdep_stats_operations = { .open = lockdep_stats_open, .read = seq_read, .llseek = seq_lseek, diff --git a/kernel/module.c b/kernel/module.c index e2d09d604ca0..d9eae45d0145 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2209,7 +2209,7 @@ static int m_show(struct seq_file *m, void *p) Where refcount is a number or -, and deps is a comma-separated list of depends or -. */ -struct seq_operations modules_op = { +const struct seq_operations modules_op = { .start = m_start, .next = m_next, .stop = m_stop, diff --git a/kernel/power/user.c b/kernel/power/user.c index 069732e5695c..89443b85163b 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -383,7 +383,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, return error; } -static struct file_operations snapshot_fops = { +static const struct file_operations snapshot_fops = { .open = snapshot_open, .release = snapshot_release, .read = snapshot_read, diff --git a/kernel/profile.c b/kernel/profile.c index 0961d93e1d91..fb5e03d57e9d 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -501,7 +501,7 @@ static ssize_t write_profile(struct file *file, const char __user *buf, return count; } -static struct file_operations proc_profile_operations = { +static const struct file_operations proc_profile_operations = { .read = read_profile, .write = write_profile, }; diff --git a/kernel/relay.c b/kernel/relay.c index 2b92e8ece85b..75a3a9a7efc2 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -1013,7 +1013,7 @@ static ssize_t relay_file_sendfile(struct file *filp, actor, &desc); } -struct file_operations relay_file_operations = { +const struct file_operations relay_file_operations = { .open = relay_file_open, .poll = relay_file_poll, .mmap = relay_file_mmap, diff --git a/kernel/resource.c b/kernel/resource.c index 6de60c12143e..7b9a497419d9 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -88,7 +88,7 @@ static int r_show(struct seq_file *m, void *v) return 0; } -static struct seq_operations resource_op = { +static const struct seq_operations resource_op = { .start = r_start, .next = r_next, .stop = r_stop, @@ -115,14 +115,14 @@ static int iomem_open(struct inode *inode, struct file *file) return res; } -static struct file_operations proc_ioports_operations = { +static const struct file_operations proc_ioports_operations = { .open = ioports_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; -static struct file_operations proc_iomem_operations = { +static const struct file_operations proc_iomem_operations = { .open = iomem_open, .read = seq_read, .llseek = seq_lseek, diff --git a/kernel/sched.c b/kernel/sched.c index b43cef02ce5b..f385eff4682d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -505,7 +505,7 @@ static int schedstat_open(struct inode *inode, struct file *file) return res; } -struct file_operations proc_schedstat_operations = { +const struct file_operations proc_schedstat_operations = { .open = schedstat_open, .read = seq_read, .llseek = seq_lseek, diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 6d7147cf66bb..758dbbf972a5 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -170,7 +170,7 @@ static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *); static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *); static int proc_opensys(struct inode *, struct file *); -struct file_operations proc_sys_file_operations = { +const struct file_operations proc_sys_file_operations = { .open = proc_opensys, .read = proc_readsys, .write = proc_writesys, diff --git a/mm/mempolicy.c b/mm/mempolicy.c index ad864f8708b0..b917d6fdc1bb 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1707,8 +1707,8 @@ void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new) * Display pages allocated per node and memory policy via /proc. */ -static const char *policy_types[] = { "default", "prefer", "bind", - "interleave" }; +static const char * const policy_types[] = + { "default", "prefer", "bind", "interleave" }; /* * Convert a mempolicy into a string. diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 27ec7a1b8022..cace22b3ac25 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -83,7 +83,7 @@ int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = { EXPORT_SYMBOL(totalram_pages); -static char *zone_names[MAX_NR_ZONES] = { +static char * const zone_names[MAX_NR_ZONES] = { "DMA", #ifdef CONFIG_ZONE_DMA32 "DMA32", diff --git a/mm/shmem.c b/mm/shmem.c index 007653680a75..c820b4f77b8d 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -177,7 +177,7 @@ static inline void shmem_unacct_blocks(unsigned long flags, long pages) static struct super_operations shmem_ops; static const struct address_space_operations shmem_aops; -static struct file_operations shmem_file_operations; +static const struct file_operations shmem_file_operations; static struct inode_operations shmem_inode_operations; static struct inode_operations shmem_dir_inode_operations; static struct inode_operations shmem_special_inode_operations; @@ -2319,7 +2319,7 @@ static const struct address_space_operations shmem_aops = { .migratepage = migrate_page, }; -static struct file_operations shmem_file_operations = { +static const struct file_operations shmem_file_operations = { .mmap = shmem_mmap, #ifdef CONFIG_TMPFS .llseek = generic_file_llseek, diff --git a/mm/slab.c b/mm/slab.c index 86f5d6e995bb..068cb4503c15 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -4142,7 +4142,7 @@ static int s_show(struct seq_file *m, void *p) * + further values on SMP and with statistics enabled */ -struct seq_operations slabinfo_op = { +const struct seq_operations slabinfo_op = { .start = s_start, .next = s_next, .stop = s_stop, @@ -4340,7 +4340,7 @@ static int leaks_show(struct seq_file *m, void *p) return 0; } -struct seq_operations slabstats_op = { +const struct seq_operations slabstats_op = { .start = leaks_start, .next = s_next, .stop = s_stop, diff --git a/mm/swapfile.c b/mm/swapfile.c index 55242363de64..c5431072f422 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1368,7 +1368,7 @@ static int swap_show(struct seq_file *swap, void *v) return 0; } -static struct seq_operations swaps_op = { +static const struct seq_operations swaps_op = { .start = swap_start, .next = swap_next, .stop = swap_stop, @@ -1380,7 +1380,7 @@ static int swaps_open(struct inode *inode, struct file *file) return seq_open(file, &swaps_op); } -static struct file_operations proc_swaps_operations = { +static const struct file_operations proc_swaps_operations = { .open = swaps_open, .read = seq_read, .llseek = seq_lseek, diff --git a/mm/vmstat.c b/mm/vmstat.c index ef4176843d9e..dc005a0c96ae 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -430,7 +430,7 @@ static int frag_show(struct seq_file *m, void *arg) return 0; } -struct seq_operations fragmentation_op = { +const struct seq_operations fragmentation_op = { .start = frag_start, .next = frag_next, .stop = frag_stop, @@ -452,7 +452,7 @@ struct seq_operations fragmentation_op = { #define TEXTS_FOR_ZONES(xx) xx "_dma", TEXT_FOR_DMA32(xx) xx "_normal", \ TEXT_FOR_HIGHMEM(xx) -static char *vmstat_text[] = { +static const char * const vmstat_text[] = { /* Zoned VM counters */ "nr_anon_pages", "nr_mapped", @@ -597,7 +597,7 @@ static int zoneinfo_show(struct seq_file *m, void *arg) return 0; } -struct seq_operations zoneinfo_op = { +const struct seq_operations zoneinfo_op = { .start = frag_start, /* iterate over all zones. The same as in * fragmentation. */ .next = frag_next, @@ -660,7 +660,7 @@ static void vmstat_stop(struct seq_file *m, void *arg) m->private = NULL; } -struct seq_operations vmstat_op = { +const struct seq_operations vmstat_op = { .start = vmstat_start, .next = vmstat_next, .stop = vmstat_stop, -- cgit v1.2.3 From 85916f8166b59eeac63d2b4f7f1df8de849334b4 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 6 Dec 2006 20:40:41 -0800 Subject: [PATCH] Kexec / Kdump: Unify elf note code The elf note saving code is currently duplicated over several architectures. This cleanup patch simply adds code to a common file and then replaces the arch-specific code with calls to the newly added code. The only drawback with this approach is that s390 doesn't fully support kexec-on-panic which for that arch leads to introduction of unused code. Signed-off-by: Magnus Damm Cc: Vivek Goyal Cc: Andi Kleen Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/crash.c | 66 ++----------------------------------------- arch/powerpc/kernel/crash.c | 59 ++------------------------------------ arch/x86_64/kernel/crash.c | 69 ++------------------------------------------- include/linux/kexec.h | 1 + kernel/kexec.c | 56 ++++++++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 188 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c index 144b43288965..a5e0e990ea95 100644 --- a/arch/i386/kernel/crash.c +++ b/arch/i386/kernel/crash.c @@ -31,68 +31,6 @@ /* This keeps a track of which one is crashing cpu. */ static int crashing_cpu; -static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, - size_t data_len) -{ - struct elf_note note; - - note.n_namesz = strlen(name) + 1; - note.n_descsz = data_len; - note.n_type = type; - memcpy(buf, ¬e, sizeof(note)); - buf += (sizeof(note) +3)/4; - memcpy(buf, name, note.n_namesz); - buf += (note.n_namesz + 3)/4; - memcpy(buf, data, note.n_descsz); - buf += (note.n_descsz + 3)/4; - - return buf; -} - -static void final_note(u32 *buf) -{ - struct elf_note note; - - note.n_namesz = 0; - note.n_descsz = 0; - note.n_type = 0; - memcpy(buf, ¬e, sizeof(note)); -} - -static void crash_save_this_cpu(struct pt_regs *regs, int cpu) -{ - struct elf_prstatus prstatus; - u32 *buf; - - if ((cpu < 0) || (cpu >= NR_CPUS)) - return; - - /* Using ELF notes here is opportunistic. - * I need a well defined structure format - * for the data I pass, and I need tags - * on the data to indicate what information I have - * squirrelled away. ELF notes happen to provide - * all of that, so there is no need to invent something new. - */ - buf = (u32*)per_cpu_ptr(crash_notes, cpu); - if (!buf) - return; - memset(&prstatus, 0, sizeof(prstatus)); - prstatus.pr_pid = current->pid; - elf_core_copy_regs(&prstatus.pr_reg, regs); - buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, - sizeof(prstatus)); - final_note(buf); -} - -static void crash_save_self(struct pt_regs *regs) -{ - int cpu; - - cpu = safe_smp_processor_id(); - crash_save_this_cpu(regs, cpu); -} - #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) static atomic_t waiting_for_crash_ipi; @@ -121,7 +59,7 @@ static int crash_nmi_callback(struct notifier_block *self, crash_fixup_ss_esp(&fixed_regs, regs); regs = &fixed_regs; } - crash_save_this_cpu(regs, cpu); + crash_save_cpu(regs, cpu); disable_local_APIC(); atomic_dec(&waiting_for_crash_ipi); /* Assume hlt works */ @@ -195,5 +133,5 @@ void machine_crash_shutdown(struct pt_regs *regs) #if defined(CONFIG_X86_IO_APIC) disable_IO_APIC(); #endif - crash_save_self(regs); + crash_save_cpu(regs, safe_smp_processor_id()); } diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 89b03c8da9d2..d3f2080d2eee 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -46,61 +46,6 @@ int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; cpumask_t cpus_in_sr = CPU_MASK_NONE; -static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, - size_t data_len) -{ - struct elf_note note; - - note.n_namesz = strlen(name) + 1; - note.n_descsz = data_len; - note.n_type = type; - memcpy(buf, ¬e, sizeof(note)); - buf += (sizeof(note) +3)/4; - memcpy(buf, name, note.n_namesz); - buf += (note.n_namesz + 3)/4; - memcpy(buf, data, note.n_descsz); - buf += (note.n_descsz + 3)/4; - - return buf; -} - -static void final_note(u32 *buf) -{ - struct elf_note note; - - note.n_namesz = 0; - note.n_descsz = 0; - note.n_type = 0; - memcpy(buf, ¬e, sizeof(note)); -} - -static void crash_save_this_cpu(struct pt_regs *regs, int cpu) -{ - struct elf_prstatus prstatus; - u32 *buf; - - if ((cpu < 0) || (cpu >= NR_CPUS)) - return; - - /* Using ELF notes here is opportunistic. - * I need a well defined structure format - * for the data I pass, and I need tags - * on the data to indicate what information I have - * squirrelled away. ELF notes happen to provide - * all of that that no need to invent something new. - */ - buf = (u32*)per_cpu_ptr(crash_notes, cpu); - if (!buf) - return; - - memset(&prstatus, 0, sizeof(prstatus)); - prstatus.pr_pid = current->pid; - elf_core_copy_regs(&prstatus.pr_reg, regs); - buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, - sizeof(prstatus)); - final_note(buf); -} - #ifdef CONFIG_SMP static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); @@ -113,7 +58,7 @@ void crash_ipi_callback(struct pt_regs *regs) hard_irq_disable(); if (!cpu_isset(cpu, cpus_in_crash)) - crash_save_this_cpu(regs, cpu); + crash_save_cpu(regs, cpu); cpu_set(cpu, cpus_in_crash); /* @@ -306,7 +251,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) * such that another IPI will not be sent. */ crashing_cpu = smp_processor_id(); - crash_save_this_cpu(regs, crashing_cpu); + crash_save_cpu(regs, crashing_cpu); crash_kexec_prepare_cpus(crashing_cpu); cpu_set(crashing_cpu, cpus_in_crash); if (ppc_md.kexec_cpu_down) diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c index 3525f884af82..95a7a2c13131 100644 --- a/arch/x86_64/kernel/crash.c +++ b/arch/x86_64/kernel/crash.c @@ -28,71 +28,6 @@ /* This keeps a track of which one is crashing cpu. */ static int crashing_cpu; -static u32 *append_elf_note(u32 *buf, char *name, unsigned type, - void *data, size_t data_len) -{ - struct elf_note note; - - note.n_namesz = strlen(name) + 1; - note.n_descsz = data_len; - note.n_type = type; - memcpy(buf, ¬e, sizeof(note)); - buf += (sizeof(note) +3)/4; - memcpy(buf, name, note.n_namesz); - buf += (note.n_namesz + 3)/4; - memcpy(buf, data, note.n_descsz); - buf += (note.n_descsz + 3)/4; - - return buf; -} - -static void final_note(u32 *buf) -{ - struct elf_note note; - - note.n_namesz = 0; - note.n_descsz = 0; - note.n_type = 0; - memcpy(buf, ¬e, sizeof(note)); -} - -static void crash_save_this_cpu(struct pt_regs *regs, int cpu) -{ - struct elf_prstatus prstatus; - u32 *buf; - - if ((cpu < 0) || (cpu >= NR_CPUS)) - return; - - /* Using ELF notes here is opportunistic. - * I need a well defined structure format - * for the data I pass, and I need tags - * on the data to indicate what information I have - * squirrelled away. ELF notes happen to provide - * all of that, no need to invent something new. - */ - - buf = (u32*)per_cpu_ptr(crash_notes, cpu); - - if (!buf) - return; - - memset(&prstatus, 0, sizeof(prstatus)); - prstatus.pr_pid = current->pid; - elf_core_copy_regs(&prstatus.pr_reg, regs); - buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, - sizeof(prstatus)); - final_note(buf); -} - -static void crash_save_self(struct pt_regs *regs) -{ - int cpu; - - cpu = smp_processor_id(); - crash_save_this_cpu(regs, cpu); -} - #ifdef CONFIG_SMP static atomic_t waiting_for_crash_ipi; @@ -117,7 +52,7 @@ static int crash_nmi_callback(struct notifier_block *self, return NOTIFY_STOP; local_irq_disable(); - crash_save_this_cpu(regs, cpu); + crash_save_cpu(regs, cpu); disable_local_APIC(); atomic_dec(&waiting_for_crash_ipi); /* Assume hlt works */ @@ -196,5 +131,5 @@ void machine_crash_shutdown(struct pt_regs *regs) disable_IO_APIC(); - crash_save_self(regs); + crash_save_cpu(regs, smp_processor_id()); } diff --git a/include/linux/kexec.h b/include/linux/kexec.h index a4ede62b339d..e3abcec6c51c 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -105,6 +105,7 @@ extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order); extern void crash_kexec(struct pt_regs *); int kexec_should_crash(struct task_struct *); +void crash_save_cpu(struct pt_regs *regs, int cpu); extern struct kimage *kexec_image; extern struct kimage *kexec_crash_image; diff --git a/kernel/kexec.c b/kernel/kexec.c index d43692cf2321..afbbbe981be2 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -1066,6 +1068,60 @@ void crash_kexec(struct pt_regs *regs) } } +static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, + size_t data_len) +{ + struct elf_note note; + + note.n_namesz = strlen(name) + 1; + note.n_descsz = data_len; + note.n_type = type; + memcpy(buf, ¬e, sizeof(note)); + buf += (sizeof(note) + 3)/4; + memcpy(buf, name, note.n_namesz); + buf += (note.n_namesz + 3)/4; + memcpy(buf, data, note.n_descsz); + buf += (note.n_descsz + 3)/4; + + return buf; +} + +static void final_note(u32 *buf) +{ + struct elf_note note; + + note.n_namesz = 0; + note.n_descsz = 0; + note.n_type = 0; + memcpy(buf, ¬e, sizeof(note)); +} + +void crash_save_cpu(struct pt_regs *regs, int cpu) +{ + struct elf_prstatus prstatus; + u32 *buf; + + if ((cpu < 0) || (cpu >= NR_CPUS)) + return; + + /* Using ELF notes here is opportunistic. + * I need a well defined structure format + * for the data I pass, and I need tags + * on the data to indicate what information I have + * squirrelled away. ELF notes happen to provide + * all of that, so there is no need to invent something new. + */ + buf = (u32*)per_cpu_ptr(crash_notes, cpu); + if (!buf) + return; + memset(&prstatus, 0, sizeof(prstatus)); + prstatus.pr_pid = current->pid; + elf_core_copy_regs(&prstatus.pr_reg, regs); + buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, + sizeof(prstatus)); + final_note(buf); +} + static int __init crash_notes_memory_init(void) { /* Allocate memory for saving cpu registers. */ -- cgit v1.2.3 From 97d2a80584b30b5cd32da411deca1986ef61877a Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Wed, 6 Dec 2006 20:40:45 -0800 Subject: [PATCH] aio: remove ki_retried debugging member Remove the ki_retried member from struct kiocb. I think the idea was bounced around a while back, but Arnaldo pointed out another reason that we should dig it up when he pointed out that the last cacheline of struct kiocb only contains 4 bytes. By removing the debugging member, we save more than the 8 byte on 64 bit machines. Signed-off-by: Benjamin LaHaise Acked-by: Ken Chen Acked-by: Zach Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/aio.c | 15 --------------- include/linux/aio.h | 2 -- 2 files changed, 17 deletions(-) (limited to 'include/linux') diff --git a/fs/aio.c b/fs/aio.c index f02ad2677fc5..d3a6ec2c9627 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -666,17 +666,6 @@ static ssize_t aio_run_iocb(struct kiocb *iocb) ssize_t (*retry)(struct kiocb *); ssize_t ret; - if (iocb->ki_retried++ > 1024*1024) { - printk("Maximal retry count. Bytes done %Zd\n", - iocb->ki_nbytes - iocb->ki_left); - return -EAGAIN; - } - - if (!(iocb->ki_retried & 0xff)) { - pr_debug("%ld retry: %zd of %zd\n", iocb->ki_retried, - iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes); - } - if (!(retry = iocb->ki_retry)) { printk("aio_run_iocb: iocb->ki_retry = NULL\n"); return 0; @@ -1005,9 +994,6 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2) kunmap_atomic(ring, KM_IRQ1); pr_debug("added to ring %p at [%lu]\n", iocb, tail); - - pr_debug("%ld retries: %zd of %zd\n", iocb->ki_retried, - iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes); put_rq: /* everything turned out well, dispose of the aiocb. */ ret = __aio_put_req(ctx, iocb); @@ -1590,7 +1576,6 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, req->ki_opcode = iocb->aio_lio_opcode; init_waitqueue_func_entry(&req->ki_wait, aio_wake_function); INIT_LIST_HEAD(&req->ki_wait.task_list); - req->ki_retried = 0; ret = aio_setup_iocb(req); diff --git a/include/linux/aio.h b/include/linux/aio.h index 9e350fd44d77..3372ec6bf53a 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -111,7 +111,6 @@ struct kiocb { size_t ki_nbytes; /* copy of iocb->aio_nbytes */ char __user *ki_buf; /* remaining iocb->aio_buf */ size_t ki_left; /* remaining bytes */ - long ki_retried; /* just for testing */ struct iovec ki_inline_vec; /* inline vector */ struct iovec *ki_iovec; unsigned long ki_nr_segs; @@ -238,7 +237,6 @@ do { \ } while (0) #define io_wait_to_kiocb(wait) container_of(wait, struct kiocb, ki_wait) -#define is_retried_kiocb(iocb) ((iocb)->ki_retried > 1) #include -- cgit v1.2.3 From 6b39bb6548d60b9a18826134b5ccd5c3cef85fe2 Mon Sep 17 00:00:00 2001 From: Paul Clements Date: Wed, 6 Dec 2006 20:40:53 -0800 Subject: [PATCH] nbd: show nbd client pid in sysfs Allow nbd to expose the nbd-client daemon's PID in /sys/block/nbd/pid. This is helpful for tracking connection status of a device and for determining which nbd devices are currently in use. Signed-off-by: Paul Clements Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/nbd.c | 16 ++++++++++++++++ include/linux/nbd.h | 1 + 2 files changed, 17 insertions(+) (limited to 'include/linux') diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 9d1035e8d9d8..7bf2cfbd6285 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -355,14 +355,30 @@ harderror: return NULL; } +static ssize_t pid_show(struct gendisk *disk, char *page) +{ + return sprintf(page, "%ld\n", + (long) ((struct nbd_device *)disk->private_data)->pid); +} + +static struct disk_attribute pid_attr = { + .attr = { .name = "pid", .mode = S_IRUGO }, + .show = pid_show, +}; + static void nbd_do_it(struct nbd_device *lo) { struct request *req; BUG_ON(lo->magic != LO_MAGIC); + lo->pid = current->pid; + sysfs_create_file(&lo->disk->kobj, &pid_attr.attr); + while ((req = nbd_read_stat(lo)) != NULL) nbd_end_request(req); + + sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr); return; } diff --git a/include/linux/nbd.h b/include/linux/nbd.h index d6b6dc09ad97..0f3e69302540 100644 --- a/include/linux/nbd.h +++ b/include/linux/nbd.h @@ -64,6 +64,7 @@ struct nbd_device { struct gendisk *disk; int blksize; u64 bytesize; + pid_t pid; /* pid of nbd-client, if attached */ }; #endif -- cgit v1.2.3 From 759643b874907e76ae81e34df62f41ab6683f5c2 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Wed, 6 Dec 2006 20:40:59 -0800 Subject: [PATCH] IPMI: pass sysfs name from lower level driver Pass in the sysfs name from the lower-level IPMI driver, as the coming IPMI serial driver will need that to link properly from the serial device sysfs directory. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_msghandler.c | 34 ++++++++++++++++++++++++++++------ drivers/char/ipmi/ipmi_si_intf.c | 1 + include/linux/ipmi_smi.h | 1 + 3 files changed, 30 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 761ed2699204..6a77b264eb2c 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -205,6 +205,7 @@ struct ipmi_smi struct bmc_device *bmc; char *my_dev_name; + char *sysfs_name; /* This is the lower-layer's sender routine. */ struct ipmi_smi_handlers *handlers; @@ -2004,7 +2005,11 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) { struct bmc_device *bmc = intf->bmc; - sysfs_remove_link(&intf->si_dev->kobj, "bmc"); + if (intf->sysfs_name) { + sysfs_remove_link(&intf->si_dev->kobj, intf->sysfs_name); + kfree(intf->sysfs_name); + intf->sysfs_name = NULL; + } if (intf->my_dev_name) { sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name); kfree(intf->my_dev_name); @@ -2140,7 +2145,8 @@ out: return err; } -static int ipmi_bmc_register(ipmi_smi_t intf) +static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum, + const char *sysfs_name) { int rv; struct bmc_device *bmc = intf->bmc; @@ -2257,29 +2263,44 @@ static int ipmi_bmc_register(ipmi_smi_t intf) * create symlink from system interface device to bmc device * and back. */ + intf->sysfs_name = kstrdup(sysfs_name, GFP_KERNEL); + if (!intf->sysfs_name) { + rv = -ENOMEM; + printk(KERN_ERR + "ipmi_msghandler: allocate link to BMC: %d\n", + rv); + goto out_err; + } + rv = sysfs_create_link(&intf->si_dev->kobj, - &bmc->dev->dev.kobj, "bmc"); + &bmc->dev->dev.kobj, intf->sysfs_name); if (rv) { + kfree(intf->sysfs_name); + intf->sysfs_name = NULL; printk(KERN_ERR "ipmi_msghandler: Unable to create bmc symlink: %d\n", rv); goto out_err; } - size = snprintf(dummy, 0, "ipmi%d", intf->intf_num); + size = snprintf(dummy, 0, "ipmi%d", ifnum); intf->my_dev_name = kmalloc(size+1, GFP_KERNEL); if (!intf->my_dev_name) { + kfree(intf->sysfs_name); + intf->sysfs_name = NULL; rv = -ENOMEM; printk(KERN_ERR "ipmi_msghandler: allocate link from BMC: %d\n", rv); goto out_err; } - snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num); + snprintf(intf->my_dev_name, size+1, "ipmi%d", ifnum); rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj, intf->my_dev_name); if (rv) { + kfree(intf->sysfs_name); + intf->sysfs_name = NULL; kfree(intf->my_dev_name); intf->my_dev_name = NULL; printk(KERN_ERR @@ -2464,6 +2485,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, void *send_info, struct ipmi_device_id *device_id, struct device *si_dev, + const char *sysfs_name, unsigned char slave_addr) { int i, j; @@ -2579,7 +2601,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, if (rv == 0) rv = add_proc_entries(intf, i); - rv = ipmi_bmc_register(intf); + rv = ipmi_bmc_register(intf, i, sysfs_name); out: if (rv) { diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index bb1fac104fda..89cdb928061c 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2362,6 +2362,7 @@ static int try_smi_init(struct smi_info *new_smi) new_smi, &new_smi->device_id, new_smi->dev, + "bmc", new_smi->slave_addr); if (rv) { printk(KERN_ERR diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index 6d9c7e4da472..2cc960da4176 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h @@ -173,6 +173,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, void *send_info, struct ipmi_device_id *device_id, struct device *dev, + const char *sysfs_name, unsigned char slave_addr); /* -- cgit v1.2.3 From b9675136e2ad95156fb93be6155f17590bb26fd7 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Wed, 6 Dec 2006 20:41:02 -0800 Subject: [PATCH] IPMI: Add maintenance mode Some commands and operations on a BMC can cause the BMC to "go away" for a while. This can cause the automatic flag processing and other things of that nature to timeout and generate annoying logs, or possibly cause other bad things to happen when in firmware update mode. Add detection of those commands (cold reset, warm reset, and any firmware command) and turns off automatic processing for 30 seconds. It also add a manual override either way. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_devintf.c | 25 ++++++++ drivers/char/ipmi/ipmi_msghandler.c | 117 +++++++++++++++++++++++++++++++++++- drivers/char/ipmi/ipmi_si_intf.c | 9 +++ include/linux/ipmi.h | 45 ++++++++++++++ include/linux/ipmi_msgdefs.h | 5 ++ include/linux/ipmi_smi.h | 7 +++ 6 files changed, 207 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 81fcf0ce21d1..375d3378eecd 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -596,6 +596,31 @@ static int ipmi_ioctl(struct inode *inode, rv = 0; break; } + + case IPMICTL_GET_MAINTENANCE_MODE_CMD: + { + int mode; + + mode = ipmi_get_maintenance_mode(priv->user); + if (copy_to_user(arg, &mode, sizeof(mode))) { + rv = -EFAULT; + break; + } + rv = 0; + break; + } + + case IPMICTL_SET_MAINTENANCE_MODE_CMD: + { + int mode; + + if (copy_from_user(&mode, arg, sizeof(mode))) { + rv = -EFAULT; + break; + } + rv = ipmi_set_maintenance_mode(priv->user, mode); + break; + } } return rv; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 03f32611831d..ff0e68f0386b 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -48,7 +48,7 @@ #define PFX "IPMI message handler: " -#define IPMI_DRIVER_VERSION "39.0" +#define IPMI_DRIVER_VERSION "39.1" static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); @@ -59,6 +59,9 @@ static int initialized = 0; static struct proc_dir_entry *proc_ipmi_root = NULL; #endif /* CONFIG_PROC_FS */ +/* Remain in auto-maintenance mode for this amount of time (in ms). */ +#define IPMI_MAINTENANCE_MODE_TIMEOUT 30000 + #define MAX_EVENTS_IN_QUEUE 25 /* Don't let a message sit in a queue forever, always time it with at lest @@ -262,6 +265,12 @@ struct ipmi_smi unsigned char local_sel_device; unsigned char local_event_generator; + /* For handling of maintenance mode. */ + int maintenance_mode; + int maintenance_mode_enable; + int auto_maintenance_timeout; + spinlock_t maintenance_mode_lock; /* Used in a timer... */ + /* A cheap hack, if this is non-null and a message to an interface comes in with a NULL user, call this routine with it. Note that the message will still be freed by the @@ -985,6 +994,65 @@ int ipmi_get_my_LUN(ipmi_user_t user, return 0; } +int ipmi_get_maintenance_mode(ipmi_user_t user) +{ + int mode; + unsigned long flags; + + spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags); + mode = user->intf->maintenance_mode; + spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags); + + return mode; +} +EXPORT_SYMBOL(ipmi_get_maintenance_mode); + +static void maintenance_mode_update(ipmi_smi_t intf) +{ + if (intf->handlers->set_maintenance_mode) + intf->handlers->set_maintenance_mode( + intf->send_info, intf->maintenance_mode_enable); +} + +int ipmi_set_maintenance_mode(ipmi_user_t user, int mode) +{ + int rv = 0; + unsigned long flags; + ipmi_smi_t intf = user->intf; + + spin_lock_irqsave(&intf->maintenance_mode_lock, flags); + if (intf->maintenance_mode != mode) { + switch (mode) { + case IPMI_MAINTENANCE_MODE_AUTO: + intf->maintenance_mode = mode; + intf->maintenance_mode_enable + = (intf->auto_maintenance_timeout > 0); + break; + + case IPMI_MAINTENANCE_MODE_OFF: + intf->maintenance_mode = mode; + intf->maintenance_mode_enable = 0; + break; + + case IPMI_MAINTENANCE_MODE_ON: + intf->maintenance_mode = mode; + intf->maintenance_mode_enable = 1; + break; + + default: + rv = -EINVAL; + goto out_unlock; + } + + maintenance_mode_update(intf); + } + out_unlock: + spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags); + + return rv; +} +EXPORT_SYMBOL(ipmi_set_maintenance_mode); + int ipmi_set_gets_events(ipmi_user_t user, int val) { unsigned long flags; @@ -1322,6 +1390,24 @@ static int i_ipmi_request(ipmi_user_t user, goto out_err; } + if (((msg->netfn == IPMI_NETFN_APP_REQUEST) + && ((msg->cmd == IPMI_COLD_RESET_CMD) + || (msg->cmd == IPMI_WARM_RESET_CMD))) + || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) + { + spin_lock_irqsave(&intf->maintenance_mode_lock, flags); + intf->auto_maintenance_timeout + = IPMI_MAINTENANCE_MODE_TIMEOUT; + if (!intf->maintenance_mode + && !intf->maintenance_mode_enable) + { + intf->maintenance_mode_enable = 1; + maintenance_mode_update(intf); + } + spin_unlock_irqrestore(&intf->maintenance_mode_lock, + flags); + } + if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; @@ -2605,6 +2691,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, INIT_LIST_HEAD(&intf->waiting_events); intf->waiting_events_count = 0; mutex_init(&intf->cmd_rcvrs_mutex); + spin_lock_init(&intf->maintenance_mode_lock); INIT_LIST_HEAD(&intf->cmd_rcvrs); init_waitqueue_head(&intf->waitq); @@ -3593,6 +3680,30 @@ static void ipmi_timeout_handler(long timeout_period) list_for_each_entry_safe(msg, msg2, &timeouts, link) deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE); + + /* + * Maintenance mode handling. Check the timeout + * optimistically before we claim the lock. It may + * mean a timeout gets missed occasionally, but that + * only means the timeout gets extended by one period + * in that case. No big deal, and it avoids the lock + * most of the time. + */ + if (intf->auto_maintenance_timeout > 0) { + spin_lock_irqsave(&intf->maintenance_mode_lock, flags); + if (intf->auto_maintenance_timeout > 0) { + intf->auto_maintenance_timeout + -= timeout_period; + if (!intf->maintenance_mode + && (intf->auto_maintenance_timeout <= 0)) + { + intf->maintenance_mode_enable = 0; + maintenance_mode_update(intf); + } + } + spin_unlock_irqrestore(&intf->maintenance_mode_lock, + flags); + } } rcu_read_unlock(); } @@ -3606,6 +3717,10 @@ static void ipmi_request_event(void) /* Called from the timer, no need to check if handlers is * valid. */ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { + /* No event requests when in maintenance mode. */ + if (intf->maintenance_mode_enable) + continue; + handlers = intf->handlers; if (handlers) handlers->request_events(intf->send_info); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 89cdb928061c..f04bee76ba2b 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -949,12 +949,21 @@ static int smi_start_processing(void *send_info, return 0; } +static void set_maintenance_mode(void *send_info, int enable) +{ + struct smi_info *smi_info = send_info; + + if (!enable) + atomic_set(&smi_info->req_events, 0); +} + static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, .start_processing = smi_start_processing, .sender = sender, .request_events = request_events, + .set_maintenance_mode = set_maintenance_mode, .set_run_to_completion = set_run_to_completion, .poll = poll, }; diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index 796ca009fd46..7a9db390c56a 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h @@ -208,6 +208,15 @@ struct kernel_ipmi_msg code as the first byte of the incoming data, unlike a response. */ +/* + * Modes for ipmi_set_maint_mode() and the userland IOCTL. The AUTO + * setting is the default and means it will be set on certain + * commands. Hard setting it on and off will override automatic + * operation. + */ +#define IPMI_MAINTENANCE_MODE_AUTO 0 +#define IPMI_MAINTENANCE_MODE_OFF 1 +#define IPMI_MAINTENANCE_MODE_ON 2 #ifdef __KERNEL__ @@ -373,6 +382,35 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, unsigned char cmd, unsigned int chans); +/* + * Go into a mode where the driver will not autonomously attempt to do + * things with the interface. It will still respond to attentions and + * interrupts, and it will expect that commands will complete. It + * will not automatcially check for flags, events, or things of that + * nature. + * + * This is primarily used for firmware upgrades. The idea is that + * when you go into firmware upgrade mode, you do this operation + * and the driver will not attempt to do anything but what you tell + * it or what the BMC asks for. + * + * Note that if you send a command that resets the BMC, the driver + * will still expect a response from that command. So the BMC should + * reset itself *after* the response is sent. Resetting before the + * response is just silly. + * + * If in auto maintenance mode, the driver will automatically go into + * maintenance mode for 30 seconds if it sees a cold reset, a warm + * reset, or a firmware NetFN. This means that code that uses only + * firmware NetFN commands to do upgrades will work automatically + * without change, assuming it sends a message every 30 seconds or + * less. + * + * See the IPMI_MAINTENANCE_MODE_xxx defines for what the mode means. + */ +int ipmi_get_maintenance_mode(ipmi_user_t user); +int ipmi_set_maintenance_mode(ipmi_user_t user, int mode); + /* * Allow run-to-completion mode to be set for the interface of * a specific user. @@ -656,4 +694,11 @@ struct ipmi_timing_parms #define IPMICTL_GET_TIMING_PARMS_CMD _IOR(IPMI_IOC_MAGIC, 23, \ struct ipmi_timing_parms) +/* + * Set the maintenance mode. See ipmi_set_maintenance_mode() above + * for a description of what this does. + */ +#define IPMICTL_GET_MAINTENANCE_MODE_CMD _IOR(IPMI_IOC_MAGIC, 30, int) +#define IPMICTL_SET_MAINTENANCE_MODE_CMD _IOW(IPMI_IOC_MAGIC, 31, int) + #endif /* __LINUX_IPMI_H */ diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h index 4d04d8b58a0a..8d6759cc1a71 100644 --- a/include/linux/ipmi_msgdefs.h +++ b/include/linux/ipmi_msgdefs.h @@ -46,6 +46,8 @@ #define IPMI_NETFN_APP_REQUEST 0x06 #define IPMI_NETFN_APP_RESPONSE 0x07 #define IPMI_GET_DEVICE_ID_CMD 0x01 +#define IPMI_COLD_RESET_CMD 0x02 +#define IPMI_WARM_RESET_CMD 0x03 #define IPMI_CLEAR_MSG_FLAGS_CMD 0x30 #define IPMI_GET_DEVICE_GUID_CMD 0x08 #define IPMI_GET_MSG_FLAGS_CMD 0x31 @@ -60,6 +62,9 @@ #define IPMI_NETFN_STORAGE_RESPONSE 0x0b #define IPMI_ADD_SEL_ENTRY_CMD 0x44 +#define IPMI_NETFN_FIRMWARE_REQUEST 0x08 +#define IPMI_NETFN_FIRMWARE_RESPONSE 0x09 + /* The default slave address */ #define IPMI_BMC_SLAVE_ADDR 0x20 diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index 2cc960da4176..c0633108d05d 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h @@ -115,6 +115,13 @@ struct ipmi_smi_handlers poll for operations during things like crash dumps. */ void (*poll)(void *send_info); + /* Enable/disable firmware maintenance mode. Note that this + is *not* the modes defined, this is simply an on/off + setting. The message handler does the mode handling. Note + that this is called from interupt context, so it cannot + block. */ + void (*set_maintenance_mode)(void *send_info, int enable); + /* Tell the handler that we are using it/not using it. The message handler get the modules that this handler belongs to; this function lets the SMI claim any modules that it -- cgit v1.2.3 From 4d7cbac7c870ca66d8fb27d68188efbb5de2dffa Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Wed, 6 Dec 2006 20:41:14 -0800 Subject: [PATCH] IPMI: Fix BT long busy The IPMI BT subdriver has been patched to survive "long busy" timeouts seen during firmware upgrades and resets. The patch never returns the HOSED state, synthesizes response messages with meaningful completion codes, and recovers gracefully when the hardware finishes the long busy. The subdriver now issues a "Get BT Capabilities" command and properly uses those results. More informative completion codes are returned on error from transaction starts; this logic was propogated to the KCS and SMIC subdrivers. Finally, indent and other style quirks were normalized. Signed-off-by: Rocky Craig Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_bt_sm.c | 641 ++++++++++++++++++++++++--------------- drivers/char/ipmi/ipmi_kcs_sm.c | 14 +- drivers/char/ipmi/ipmi_si_intf.c | 12 +- drivers/char/ipmi/ipmi_smic_sm.c | 14 +- include/linux/ipmi_msgdefs.h | 8 +- 5 files changed, 423 insertions(+), 266 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 0030cd8e2e95..6c59baa887a8 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -33,11 +33,13 @@ #include /* for completion codes */ #include "ipmi_si_sm.h" -static int bt_debug = 0x00; /* Production value 0, see following flags */ +#define BT_DEBUG_OFF 0 /* Used in production */ +#define BT_DEBUG_ENABLE 1 /* Generic messages */ +#define BT_DEBUG_MSG 2 /* Prints all request/response buffers */ +#define BT_DEBUG_STATES 4 /* Verbose look at state changes */ + +static int bt_debug = BT_DEBUG_OFF; -#define BT_DEBUG_ENABLE 1 -#define BT_DEBUG_MSG 2 -#define BT_DEBUG_STATES 4 module_param(bt_debug, int, 0644); MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); @@ -47,38 +49,54 @@ MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); Since the Open IPMI architecture is single-message oriented at this stage, the queue depth of BT is of no concern. */ -#define BT_NORMAL_TIMEOUT 5000000 /* seconds in microseconds */ -#define BT_RETRY_LIMIT 2 -#define BT_RESET_DELAY 6000000 /* 6 seconds after warm reset */ +#define BT_NORMAL_TIMEOUT 5 /* seconds */ +#define BT_NORMAL_RETRY_LIMIT 2 +#define BT_RESET_DELAY 6 /* seconds after warm reset */ + +/* States are written in chronological order and usually cover + multiple rows of the state table discussion in the IPMI spec. */ enum bt_states { - BT_STATE_IDLE, + BT_STATE_IDLE = 0, /* Order is critical in this list */ BT_STATE_XACTION_START, BT_STATE_WRITE_BYTES, - BT_STATE_WRITE_END, BT_STATE_WRITE_CONSUME, - BT_STATE_B2H_WAIT, - BT_STATE_READ_END, - BT_STATE_RESET1, /* These must come last */ + BT_STATE_READ_WAIT, + BT_STATE_CLEAR_B2H, + BT_STATE_READ_BYTES, + BT_STATE_RESET1, /* These must come last */ BT_STATE_RESET2, BT_STATE_RESET3, BT_STATE_RESTART, - BT_STATE_HOSED + BT_STATE_PRINTME, + BT_STATE_CAPABILITIES_BEGIN, + BT_STATE_CAPABILITIES_END, + BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */ }; +/* Macros seen at the end of state "case" blocks. They help with legibility + and debugging. */ + +#define BT_STATE_CHANGE(X,Y) { bt->state = X; return Y; } + +#define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; } + struct si_sm_data { enum bt_states state; - enum bt_states last_state; /* assist printing and resets */ unsigned char seq; /* BT sequence number */ struct si_sm_io *io; - unsigned char write_data[IPMI_MAX_MSG_LENGTH]; - int write_count; - unsigned char read_data[IPMI_MAX_MSG_LENGTH]; - int read_count; - int truncated; - long timeout; - unsigned int error_retries; /* end of "common" fields */ + unsigned char write_data[IPMI_MAX_MSG_LENGTH]; + int write_count; + unsigned char read_data[IPMI_MAX_MSG_LENGTH]; + int read_count; + int truncated; + long timeout; /* microseconds countdown */ + int error_retries; /* end of "common" fields */ int nonzero_status; /* hung BMCs stay all 0 */ + enum bt_states complete; /* to divert the state machine */ + int BT_CAP_outreqs; + long BT_CAP_req2rsp; + int BT_CAP_retries; /* Recommended retries */ }; #define BT_CLR_WR_PTR 0x01 /* See IPMI 1.5 table 11.6.4 */ @@ -111,86 +129,118 @@ struct si_sm_data { static char *state2txt(unsigned char state) { switch (state) { - case BT_STATE_IDLE: return("IDLE"); - case BT_STATE_XACTION_START: return("XACTION"); - case BT_STATE_WRITE_BYTES: return("WR_BYTES"); - case BT_STATE_WRITE_END: return("WR_END"); - case BT_STATE_WRITE_CONSUME: return("WR_CONSUME"); - case BT_STATE_B2H_WAIT: return("B2H_WAIT"); - case BT_STATE_READ_END: return("RD_END"); - case BT_STATE_RESET1: return("RESET1"); - case BT_STATE_RESET2: return("RESET2"); - case BT_STATE_RESET3: return("RESET3"); - case BT_STATE_RESTART: return("RESTART"); - case BT_STATE_HOSED: return("HOSED"); + case BT_STATE_IDLE: return("IDLE"); + case BT_STATE_XACTION_START: return("XACTION"); + case BT_STATE_WRITE_BYTES: return("WR_BYTES"); + case BT_STATE_WRITE_CONSUME: return("WR_CONSUME"); + case BT_STATE_READ_WAIT: return("RD_WAIT"); + case BT_STATE_CLEAR_B2H: return("CLEAR_B2H"); + case BT_STATE_READ_BYTES: return("RD_BYTES"); + case BT_STATE_RESET1: return("RESET1"); + case BT_STATE_RESET2: return("RESET2"); + case BT_STATE_RESET3: return("RESET3"); + case BT_STATE_RESTART: return("RESTART"); + case BT_STATE_LONG_BUSY: return("LONG_BUSY"); + case BT_STATE_CAPABILITIES_BEGIN: return("CAP_BEGIN"); + case BT_STATE_CAPABILITIES_END: return("CAP_END"); } return("BAD STATE"); } #define STATE2TXT state2txt(bt->state) -static char *status2txt(unsigned char status, char *buf) +static char *status2txt(unsigned char status) { + /* + * This cannot be called by two threads at the same time and + * the buffer is always consumed immediately, so the static is + * safe to use. + */ + static char buf[40]; + strcpy(buf, "[ "); - if (status & BT_B_BUSY) strcat(buf, "B_BUSY "); - if (status & BT_H_BUSY) strcat(buf, "H_BUSY "); - if (status & BT_OEM0) strcat(buf, "OEM0 "); - if (status & BT_SMS_ATN) strcat(buf, "SMS "); - if (status & BT_B2H_ATN) strcat(buf, "B2H "); - if (status & BT_H2B_ATN) strcat(buf, "H2B "); + if (status & BT_B_BUSY) + strcat(buf, "B_BUSY "); + if (status & BT_H_BUSY) + strcat(buf, "H_BUSY "); + if (status & BT_OEM0) + strcat(buf, "OEM0 "); + if (status & BT_SMS_ATN) + strcat(buf, "SMS "); + if (status & BT_B2H_ATN) + strcat(buf, "B2H "); + if (status & BT_H2B_ATN) + strcat(buf, "H2B "); strcat(buf, "]"); return buf; } -#define STATUS2TXT(buf) status2txt(status, buf) +#define STATUS2TXT status2txt(status) + +/* called externally at insmod time, and internally on cleanup */ -/* This will be called from within this module on a hosed condition */ -#define FIRST_SEQ 0 static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io) { - bt->state = BT_STATE_IDLE; - bt->last_state = BT_STATE_IDLE; - bt->seq = FIRST_SEQ; - bt->io = io; - bt->write_count = 0; - bt->read_count = 0; - bt->error_retries = 0; - bt->nonzero_status = 0; - bt->truncated = 0; - bt->timeout = BT_NORMAL_TIMEOUT; + memset(bt, 0, sizeof(struct si_sm_data)); + if (bt->io != io) { /* external: one-time only things */ + bt->io = io; + bt->seq = 0; + } + bt->state = BT_STATE_IDLE; /* start here */ + bt->complete = BT_STATE_IDLE; /* end here */ + bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * 1000000; + bt->BT_CAP_retries = BT_NORMAL_RETRY_LIMIT; + /* BT_CAP_outreqs == zero is a flag to read BT Capabilities */ return 3; /* We claim 3 bytes of space; ought to check SPMI table */ } +/* Jam a completion code (probably an error) into a response */ + +static void force_result(struct si_sm_data *bt, unsigned char completion_code) +{ + bt->read_data[0] = 4; /* # following bytes */ + bt->read_data[1] = bt->write_data[1] | 4; /* Odd NetFn/LUN */ + bt->read_data[2] = bt->write_data[2]; /* seq (ignored) */ + bt->read_data[3] = bt->write_data[3]; /* Command */ + bt->read_data[4] = completion_code; + bt->read_count = 5; +} + +/* The upper state machine starts here */ + static int bt_start_transaction(struct si_sm_data *bt, unsigned char *data, unsigned int size) { unsigned int i; - if ((size < 2) || (size > (IPMI_MAX_MSG_LENGTH - 2))) - return -1; + if (size < 2) + return IPMI_REQ_LEN_INVALID_ERR; + if (size > IPMI_MAX_MSG_LENGTH) + return IPMI_REQ_LEN_EXCEEDED_ERR; - if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED)) - return -2; + if (bt->state == BT_STATE_LONG_BUSY) + return IPMI_NODE_BUSY_ERR; + + if (bt->state != BT_STATE_IDLE) + return IPMI_NOT_IN_MY_STATE_ERR; if (bt_debug & BT_DEBUG_MSG) { - printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n"); - printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq); + printk(KERN_WARNING "BT: +++++++++++++++++ New command\n"); + printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2); for (i = 0; i < size; i ++) - printk (" %02x", data[i]); + printk (" %02x", data[i]); printk("\n"); } bt->write_data[0] = size + 1; /* all data plus seq byte */ bt->write_data[1] = *data; /* NetFn/LUN */ - bt->write_data[2] = bt->seq; + bt->write_data[2] = bt->seq++; memcpy(bt->write_data + 3, data + 1, size - 1); bt->write_count = size + 2; - bt->error_retries = 0; bt->nonzero_status = 0; - bt->read_count = 0; bt->truncated = 0; bt->state = BT_STATE_XACTION_START; - bt->last_state = BT_STATE_IDLE; - bt->timeout = BT_NORMAL_TIMEOUT; + bt->timeout = bt->BT_CAP_req2rsp; + force_result(bt, IPMI_ERR_UNSPECIFIED); return 0; } @@ -198,38 +248,30 @@ static int bt_start_transaction(struct si_sm_data *bt, it calls this. Strip out the length and seq bytes. */ static int bt_get_result(struct si_sm_data *bt, - unsigned char *data, - unsigned int length) + unsigned char *data, + unsigned int length) { int i, msg_len; msg_len = bt->read_count - 2; /* account for length & seq */ - /* Always NetFn, Cmd, cCode */ if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) { - printk(KERN_DEBUG "BT results: bad msg_len = %d\n", msg_len); - data[0] = bt->write_data[1] | 0x4; /* Kludge a response */ - data[1] = bt->write_data[3]; - data[2] = IPMI_ERR_UNSPECIFIED; + force_result(bt, IPMI_ERR_UNSPECIFIED); msg_len = 3; - } else { - data[0] = bt->read_data[1]; - data[1] = bt->read_data[3]; - if (length < msg_len) - bt->truncated = 1; - if (bt->truncated) { /* can be set in read_all_bytes() */ - data[2] = IPMI_ERR_MSG_TRUNCATED; - msg_len = 3; - } else - memcpy(data + 2, bt->read_data + 4, msg_len - 2); + } + data[0] = bt->read_data[1]; + data[1] = bt->read_data[3]; + if (length < msg_len || bt->truncated) { + data[2] = IPMI_ERR_MSG_TRUNCATED; + msg_len = 3; + } else + memcpy(data + 2, bt->read_data + 4, msg_len - 2); - if (bt_debug & BT_DEBUG_MSG) { - printk (KERN_WARNING "BT: res (raw)"); - for (i = 0; i < msg_len; i++) - printk(" %02x", data[i]); - printk ("\n"); - } + if (bt_debug & BT_DEBUG_MSG) { + printk (KERN_WARNING "BT: result %d bytes:", msg_len); + for (i = 0; i < msg_len; i++) + printk(" %02x", data[i]); + printk ("\n"); } - bt->read_count = 0; /* paranoia */ return msg_len; } @@ -238,22 +280,40 @@ static int bt_get_result(struct si_sm_data *bt, static void reset_flags(struct si_sm_data *bt) { + if (bt_debug) + printk(KERN_WARNING "IPMI BT: flag reset %s\n", + status2txt(BT_STATUS)); if (BT_STATUS & BT_H_BUSY) - BT_CONTROL(BT_H_BUSY); - if (BT_STATUS & BT_B_BUSY) - BT_CONTROL(BT_B_BUSY); - BT_CONTROL(BT_CLR_WR_PTR); - BT_CONTROL(BT_SMS_ATN); - - if (BT_STATUS & BT_B2H_ATN) { - int i; - BT_CONTROL(BT_H_BUSY); - BT_CONTROL(BT_B2H_ATN); - BT_CONTROL(BT_CLR_RD_PTR); - for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) - BMC2HOST; - BT_CONTROL(BT_H_BUSY); - } + BT_CONTROL(BT_H_BUSY); /* force clear */ + BT_CONTROL(BT_CLR_WR_PTR); /* always reset */ + BT_CONTROL(BT_SMS_ATN); /* always clear */ + BT_INTMASK_W(BT_BMC_HWRST); +} + +/* Get rid of an unwanted/stale response. This should only be needed for + BMCs that support multiple outstanding requests. */ + +static void drain_BMC2HOST(struct si_sm_data *bt) +{ + int i, size; + + if (!(BT_STATUS & BT_B2H_ATN)) /* Not signalling a response */ + return; + + BT_CONTROL(BT_H_BUSY); /* now set */ + BT_CONTROL(BT_B2H_ATN); /* always clear */ + BT_STATUS; /* pause */ + BT_CONTROL(BT_B2H_ATN); /* some BMCs are stubborn */ + BT_CONTROL(BT_CLR_RD_PTR); /* always reset */ + if (bt_debug) + printk(KERN_WARNING "IPMI BT: stale response %s; ", + status2txt(BT_STATUS)); + size = BMC2HOST; + for (i = 0; i < size ; i++) + BMC2HOST; + BT_CONTROL(BT_H_BUSY); /* now clear */ + if (bt_debug) + printk("drained %d bytes\n", size + 1); } static inline void write_all_bytes(struct si_sm_data *bt) @@ -261,201 +321,256 @@ static inline void write_all_bytes(struct si_sm_data *bt) int i; if (bt_debug & BT_DEBUG_MSG) { - printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", + printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", bt->write_count, bt->seq); for (i = 0; i < bt->write_count; i++) printk (" %02x", bt->write_data[i]); printk ("\n"); } for (i = 0; i < bt->write_count; i++) - HOST2BMC(bt->write_data[i]); + HOST2BMC(bt->write_data[i]); } static inline int read_all_bytes(struct si_sm_data *bt) { unsigned char i; + /* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode. + Keep layout of first four bytes aligned with write_data[] */ + bt->read_data[0] = BMC2HOST; bt->read_count = bt->read_data[0]; - if (bt_debug & BT_DEBUG_MSG) - printk(KERN_WARNING "BT: read %d bytes:", bt->read_count); - /* minimum: length, NetFn, Seq, Cmd, cCode == 5 total, or 4 more - following the length byte. */ if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) { if (bt_debug & BT_DEBUG_MSG) - printk("bad length %d\n", bt->read_count); + printk(KERN_WARNING "BT: bad raw rsp len=%d\n", + bt->read_count); bt->truncated = 1; return 1; /* let next XACTION START clean it up */ } for (i = 1; i <= bt->read_count; i++) - bt->read_data[i] = BMC2HOST; - bt->read_count++; /* account for the length byte */ + bt->read_data[i] = BMC2HOST; + bt->read_count++; /* Account internally for length byte */ if (bt_debug & BT_DEBUG_MSG) { - for (i = 0; i < bt->read_count; i++) + int max = bt->read_count; + + printk(KERN_WARNING "BT: got %d bytes seq=0x%02X", + max, bt->read_data[2]); + if (max > 16) + max = 16; + for (i = 0; i < max; i++) printk (" %02x", bt->read_data[i]); - printk ("\n"); + printk ("%s\n", bt->read_count == max ? "" : " ..."); } - if (bt->seq != bt->write_data[2]) /* idiot check */ - printk(KERN_DEBUG "BT: internal error: sequence mismatch\n"); - /* per the spec, the (NetFn, Seq, Cmd) tuples should match */ - if ((bt->read_data[3] == bt->write_data[3]) && /* Cmd */ - (bt->read_data[2] == bt->write_data[2]) && /* Sequence */ - ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) + /* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */ + if ((bt->read_data[3] == bt->write_data[3]) && + (bt->read_data[2] == bt->write_data[2]) && + ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) return 1; if (bt_debug & BT_DEBUG_MSG) - printk(KERN_WARNING "BT: bad packet: " + printk(KERN_WARNING "IPMI BT: bad packet: " "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", - bt->write_data[1], bt->write_data[2], bt->write_data[3], + bt->write_data[1] | 0x04, bt->write_data[2], bt->write_data[3], bt->read_data[1], bt->read_data[2], bt->read_data[3]); return 0; } -/* Modifies bt->state appropriately, need to get into the bt_event() switch */ +/* Restart if retries are left, or return an error completion code */ -static void error_recovery(struct si_sm_data *bt, char *reason) +static enum si_sm_result error_recovery(struct si_sm_data *bt, + unsigned char status, + unsigned char cCode) { - unsigned char status; - char buf[40]; /* For getting status */ + char *reason; - bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */ + bt->timeout = bt->BT_CAP_req2rsp; - status = BT_STATUS; - printk(KERN_DEBUG "BT: %s in %s %s\n", reason, STATE2TXT, - STATUS2TXT(buf)); + switch (cCode) { + case IPMI_TIMEOUT_ERR: + reason = "timeout"; + break; + default: + reason = "internal error"; + break; + } + + printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */ + reason, STATE2TXT, STATUS2TXT); + /* Per the IPMI spec, retries are based on the sequence number + known only to this module, so manage a restart here. */ (bt->error_retries)++; - if (bt->error_retries > BT_RETRY_LIMIT) { - printk(KERN_DEBUG "retry limit (%d) exceeded\n", BT_RETRY_LIMIT); - bt->state = BT_STATE_HOSED; - if (!bt->nonzero_status) - printk(KERN_ERR "IPMI: BT stuck, try power cycle\n"); - else if (bt->error_retries <= BT_RETRY_LIMIT + 1) { - printk(KERN_DEBUG "IPMI: BT reset (takes 5 secs)\n"); - bt->state = BT_STATE_RESET1; - } - return; + if (bt->error_retries < bt->BT_CAP_retries) { + printk("%d retries left\n", + bt->BT_CAP_retries - bt->error_retries); + bt->state = BT_STATE_RESTART; + return SI_SM_CALL_WITHOUT_DELAY; } - /* Sometimes the BMC queues get in an "off-by-one" state...*/ - if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) { - printk(KERN_DEBUG "retry B2H_WAIT\n"); - return; + printk("failed %d retries, sending error response\n", + bt->BT_CAP_retries); + if (!bt->nonzero_status) + printk(KERN_ERR "IPMI BT: stuck, try power cycle\n"); + + /* this is most likely during insmod */ + else if (bt->seq <= (unsigned char)(bt->BT_CAP_retries & 0xFF)) { + printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n"); + bt->state = BT_STATE_RESET1; + return SI_SM_CALL_WITHOUT_DELAY; } - printk(KERN_DEBUG "restart command\n"); - bt->state = BT_STATE_RESTART; + /* Concoct a useful error message, set up the next state, and + be done with this sequence. */ + + bt->state = BT_STATE_IDLE; + switch (cCode) { + case IPMI_TIMEOUT_ERR: + if (status & BT_B_BUSY) { + cCode = IPMI_NODE_BUSY_ERR; + bt->state = BT_STATE_LONG_BUSY; + } + break; + default: + break; + } + force_result(bt, cCode); + return SI_SM_TRANSACTION_COMPLETE; } -/* Check the status and (possibly) advance the BT state machine. The - default return is SI_SM_CALL_WITH_DELAY. */ +/* Check status and (usually) take action and change this state machine. */ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) { - unsigned char status; - char buf[40]; /* For getting status */ + unsigned char status, BT_CAP[8]; + static enum bt_states last_printed = BT_STATE_PRINTME; int i; status = BT_STATUS; bt->nonzero_status |= status; - - if ((bt_debug & BT_DEBUG_STATES) && (bt->state != bt->last_state)) + if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) { printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n", STATE2TXT, - STATUS2TXT(buf), + STATUS2TXT, bt->timeout, time); - bt->last_state = bt->state; + last_printed = bt->state; + } - if (bt->state == BT_STATE_HOSED) - return SI_SM_HOSED; + /* Commands that time out may still (eventually) provide a response. + This stale response will get in the way of a new response so remove + it if possible (hopefully during IDLE). Even if it comes up later + it will be rejected by its (now-forgotten) seq number. */ + + if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) { + drain_BMC2HOST(bt); + BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); + } - if (bt->state != BT_STATE_IDLE) { /* do timeout test */ + if ((bt->state != BT_STATE_IDLE) && + (bt->state < BT_STATE_PRINTME)) { /* check timeout */ bt->timeout -= time; - if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) { - error_recovery(bt, "timed out"); - return SI_SM_CALL_WITHOUT_DELAY; - } + if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) + return error_recovery(bt, + status, + IPMI_TIMEOUT_ERR); } switch (bt->state) { - case BT_STATE_IDLE: /* check for asynchronous messages */ + /* Idle state first checks for asynchronous messages from another + channel, then does some opportunistic housekeeping. */ + + case BT_STATE_IDLE: if (status & BT_SMS_ATN) { BT_CONTROL(BT_SMS_ATN); /* clear it */ return SI_SM_ATTN; } - return SI_SM_IDLE; - case BT_STATE_XACTION_START: - if (status & BT_H_BUSY) { + if (status & BT_H_BUSY) /* clear a leftover H_BUSY */ BT_CONTROL(BT_H_BUSY); - break; - } - if (status & BT_B2H_ATN) - break; - bt->state = BT_STATE_WRITE_BYTES; - return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ - case BT_STATE_WRITE_BYTES: + /* Read BT capabilities if it hasn't been done yet */ + if (!bt->BT_CAP_outreqs) + BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN, + SI_SM_CALL_WITHOUT_DELAY); + bt->timeout = bt->BT_CAP_req2rsp; + BT_SI_SM_RETURN(SI_SM_IDLE); + + case BT_STATE_XACTION_START: if (status & (BT_B_BUSY | BT_H2B_ATN)) - break; + BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); + if (BT_STATUS & BT_H_BUSY) + BT_CONTROL(BT_H_BUSY); /* force clear */ + BT_STATE_CHANGE(BT_STATE_WRITE_BYTES, + SI_SM_CALL_WITHOUT_DELAY); + + case BT_STATE_WRITE_BYTES: + if (status & BT_H_BUSY) + BT_CONTROL(BT_H_BUSY); /* clear */ BT_CONTROL(BT_CLR_WR_PTR); write_all_bytes(bt); - BT_CONTROL(BT_H2B_ATN); /* clears too fast to catch? */ - bt->state = BT_STATE_WRITE_CONSUME; - return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */ - - case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */ - if (status & (BT_H2B_ATN | BT_B_BUSY)) - break; - bt->state = BT_STATE_B2H_WAIT; - /* fall through with status */ - - /* Stay in BT_STATE_B2H_WAIT until a packet matches. However, spinning - hard here, constantly reading status, seems to hold off the - generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */ - - case BT_STATE_B2H_WAIT: - if (!(status & BT_B2H_ATN)) - break; - - /* Assume ordered, uncached writes: no need to wait */ - if (!(status & BT_H_BUSY)) - BT_CONTROL(BT_H_BUSY); /* set */ - BT_CONTROL(BT_B2H_ATN); /* clear it, ACK to the BMC */ - BT_CONTROL(BT_CLR_RD_PTR); /* reset the queue */ - i = read_all_bytes(bt); - BT_CONTROL(BT_H_BUSY); /* clear */ - if (!i) /* Try this state again */ - break; - bt->state = BT_STATE_READ_END; - return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ - - case BT_STATE_READ_END: - - /* I could wait on BT_H_BUSY to go clear for a truly clean - exit. However, this is already done in XACTION_START - and the (possible) extra loop/status/possible wait affects - performance. So, as long as it works, just ignore H_BUSY */ - -#ifdef MAKE_THIS_TRUE_IF_NECESSARY + BT_CONTROL(BT_H2B_ATN); /* can clear too fast to catch */ + BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME, + SI_SM_CALL_WITHOUT_DELAY); - if (status & BT_H_BUSY) - break; -#endif - bt->seq++; - bt->state = BT_STATE_IDLE; - return SI_SM_TRANSACTION_COMPLETE; + case BT_STATE_WRITE_CONSUME: + if (status & (BT_B_BUSY | BT_H2B_ATN)) + BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); + BT_STATE_CHANGE(BT_STATE_READ_WAIT, + SI_SM_CALL_WITHOUT_DELAY); + + /* Spinning hard can suppress B2H_ATN and force a timeout */ + + case BT_STATE_READ_WAIT: + if (!(status & BT_B2H_ATN)) + BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); + BT_CONTROL(BT_H_BUSY); /* set */ + + /* Uncached, ordered writes should just proceeed serially but + some BMCs don't clear B2H_ATN with one hit. Fast-path a + workaround without too much penalty to the general case. */ + + BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */ + BT_STATE_CHANGE(BT_STATE_CLEAR_B2H, + SI_SM_CALL_WITHOUT_DELAY); + + case BT_STATE_CLEAR_B2H: + if (status & BT_B2H_ATN) { /* keep hitting it */ + BT_CONTROL(BT_B2H_ATN); + BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); + } + BT_STATE_CHANGE(BT_STATE_READ_BYTES, + SI_SM_CALL_WITHOUT_DELAY); + + case BT_STATE_READ_BYTES: + if (!(status & BT_H_BUSY)) /* check in case of retry */ + BT_CONTROL(BT_H_BUSY); + BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */ + i = read_all_bytes(bt); /* true == packet seq match */ + BT_CONTROL(BT_H_BUSY); /* NOW clear */ + if (!i) /* Not my message */ + BT_STATE_CHANGE(BT_STATE_READ_WAIT, + SI_SM_CALL_WITHOUT_DELAY); + bt->state = bt->complete; + return bt->state == BT_STATE_IDLE ? /* where to next? */ + SI_SM_TRANSACTION_COMPLETE : /* normal */ + SI_SM_CALL_WITHOUT_DELAY; /* Startup magic */ + + case BT_STATE_LONG_BUSY: /* For example: after FW update */ + if (!(status & BT_B_BUSY)) { + reset_flags(bt); /* next state is now IDLE */ + bt_init_data(bt, bt->io); + } + return SI_SM_CALL_WITH_DELAY; /* No repeat printing */ case BT_STATE_RESET1: - reset_flags(bt); - bt->timeout = BT_RESET_DELAY; - bt->state = BT_STATE_RESET2; - break; + reset_flags(bt); + drain_BMC2HOST(bt); + BT_STATE_CHANGE(BT_STATE_RESET2, + SI_SM_CALL_WITH_DELAY); case BT_STATE_RESET2: /* Send a soft reset */ BT_CONTROL(BT_CLR_WR_PTR); @@ -464,29 +579,59 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) HOST2BMC(42); /* Sequence number */ HOST2BMC(3); /* Cmd == Soft reset */ BT_CONTROL(BT_H2B_ATN); - bt->state = BT_STATE_RESET3; - break; + bt->timeout = BT_RESET_DELAY * 1000000; + BT_STATE_CHANGE(BT_STATE_RESET3, + SI_SM_CALL_WITH_DELAY); - case BT_STATE_RESET3: + case BT_STATE_RESET3: /* Hold off everything for a bit */ if (bt->timeout > 0) - return SI_SM_CALL_WITH_DELAY; - bt->state = BT_STATE_RESTART; /* printk in debug modes */ - break; + return SI_SM_CALL_WITH_DELAY; + drain_BMC2HOST(bt); + BT_STATE_CHANGE(BT_STATE_RESTART, + SI_SM_CALL_WITH_DELAY); - case BT_STATE_RESTART: /* don't reset retries! */ - reset_flags(bt); - bt->write_data[2] = ++bt->seq; + case BT_STATE_RESTART: /* don't reset retries or seq! */ bt->read_count = 0; bt->nonzero_status = 0; - bt->timeout = BT_NORMAL_TIMEOUT; - bt->state = BT_STATE_XACTION_START; - break; - - default: /* HOSED is supposed to be caught much earlier */ - error_recovery(bt, "internal logic error"); - break; - } - return SI_SM_CALL_WITH_DELAY; + bt->timeout = bt->BT_CAP_req2rsp; + BT_STATE_CHANGE(BT_STATE_XACTION_START, + SI_SM_CALL_WITH_DELAY); + + /* Get BT Capabilities, using timing of upper level state machine. + Set outreqs to prevent infinite loop on timeout. */ + case BT_STATE_CAPABILITIES_BEGIN: + bt->BT_CAP_outreqs = 1; + { + unsigned char GetBT_CAP[] = { 0x18, 0x36 }; + bt->state = BT_STATE_IDLE; + bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP)); + } + bt->complete = BT_STATE_CAPABILITIES_END; + BT_STATE_CHANGE(BT_STATE_XACTION_START, + SI_SM_CALL_WITH_DELAY); + + case BT_STATE_CAPABILITIES_END: + i = bt_get_result(bt, BT_CAP, sizeof(BT_CAP)); + bt_init_data(bt, bt->io); + if ((i == 8) && !BT_CAP[2]) { + bt->BT_CAP_outreqs = BT_CAP[3]; + bt->BT_CAP_req2rsp = BT_CAP[6] * 1000000; + bt->BT_CAP_retries = BT_CAP[7]; + } else + printk(KERN_WARNING "IPMI BT: using default values\n"); + if (!bt->BT_CAP_outreqs) + bt->BT_CAP_outreqs = 1; + printk(KERN_WARNING "IPMI BT: req2rsp=%ld secs retries=%d\n", + bt->BT_CAP_req2rsp / 1000000L, bt->BT_CAP_retries); + bt->timeout = bt->BT_CAP_req2rsp; + return SI_SM_CALL_WITHOUT_DELAY; + + default: /* should never occur */ + return error_recovery(bt, + status, + IPMI_ERR_UNSPECIFIED); + } + return SI_SM_CALL_WITH_DELAY; } static int bt_detect(struct si_sm_data *bt) @@ -497,7 +642,7 @@ static int bt_detect(struct si_sm_data *bt) test that first. The calling routine uses negative logic. */ if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) - return 1; + return 1; reset_flags(bt); return 0; } @@ -513,11 +658,11 @@ static int bt_size(void) struct si_sm_handlers bt_smi_handlers = { - .init_data = bt_init_data, - .start_transaction = bt_start_transaction, - .get_result = bt_get_result, - .event = bt_event, - .detect = bt_detect, - .cleanup = bt_cleanup, - .size = bt_size, + .init_data = bt_init_data, + .start_transaction = bt_start_transaction, + .get_result = bt_get_result, + .event = bt_event, + .detect = bt_detect, + .cleanup = bt_cleanup, + .size = bt_size, }; diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index 2062675f9e99..fb46979567e3 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -261,12 +261,14 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, { unsigned int i; - if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) { - return -1; - } - if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) { - return -2; - } + if (size < 2) + return IPMI_REQ_LEN_INVALID_ERR; + if (size > MAX_KCS_WRITE_SIZE) + return IPMI_REQ_LEN_EXCEEDED_ERR; + + if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) + return IPMI_NOT_IN_MY_STATE_ERR; + if (kcs_debug & KCS_DEBUG_MSG) { printk(KERN_DEBUG "start_kcs_transaction -"); for (i = 0; i < size; i ++) { diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index c7de2e86a6dc..81a0c89598e7 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -247,14 +247,18 @@ static void deliver_recv_msg(struct smi_info *smi_info, spin_lock(&(smi_info->si_lock)); } -static void return_hosed_msg(struct smi_info *smi_info) +static void return_hosed_msg(struct smi_info *smi_info, int cCode) { struct ipmi_smi_msg *msg = smi_info->curr_msg; + if (cCode < 0 || cCode > IPMI_ERR_UNSPECIFIED) + cCode = IPMI_ERR_UNSPECIFIED; + /* else use it as is */ + /* Make it a reponse */ msg->rsp[0] = msg->data[0] | 4; msg->rsp[1] = msg->data[1]; - msg->rsp[2] = IPMI_ERR_UNSPECIFIED; + msg->rsp[2] = cCode; msg->rsp_size = 3; smi_info->curr_msg = NULL; @@ -305,7 +309,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) smi_info->curr_msg->data, smi_info->curr_msg->data_size); if (err) { - return_hosed_msg(smi_info); + return_hosed_msg(smi_info, err); } rv = SI_SM_CALL_WITHOUT_DELAY; @@ -647,7 +651,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, /* If we were handling a user message, format a response to send to the upper layer to tell it about the error. */ - return_hosed_msg(smi_info); + return_hosed_msg(smi_info, IPMI_ERR_UNSPECIFIED); } si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); } diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index 39d7e5ef1a2b..e64ea7d25d24 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -141,12 +141,14 @@ static int start_smic_transaction(struct si_sm_data *smic, { unsigned int i; - if ((size < 2) || (size > MAX_SMIC_WRITE_SIZE)) { - return -1; - } - if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) { - return -2; - } + if (size < 2) + return IPMI_REQ_LEN_INVALID_ERR; + if (size > MAX_SMIC_WRITE_SIZE) + return IPMI_REQ_LEN_EXCEEDED_ERR; + + if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) + return IPMI_NOT_IN_MY_STATE_ERR; + if (smic_debug & SMIC_DEBUG_MSG) { printk(KERN_INFO "start_smic_transaction -"); for (i = 0; i < size; i ++) { diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h index 8d6759cc1a71..b56a158d587a 100644 --- a/include/linux/ipmi_msgdefs.h +++ b/include/linux/ipmi_msgdefs.h @@ -71,14 +71,18 @@ /* The BT interface on high-end HP systems supports up to 255 bytes in * one transfer. Its "virtual" BMC supports some commands that are longer * than 128 bytes. Use the full 256, plus NetFn/LUN, Cmd, cCode, plus - * some overhead. It would be nice to base this on the "BT Capabilities" - * but that's too hard to propagate to the rest of the driver. */ + * some overhead; it's not worth the effort to dynamically size this based + * on the results of the "Get BT Capabilities" command. */ #define IPMI_MAX_MSG_LENGTH 272 /* multiple of 16 */ #define IPMI_CC_NO_ERROR 0x00 #define IPMI_NODE_BUSY_ERR 0xc0 #define IPMI_INVALID_COMMAND_ERR 0xc1 +#define IPMI_TIMEOUT_ERR 0xc3 #define IPMI_ERR_MSG_TRUNCATED 0xc6 +#define IPMI_REQ_LEN_INVALID_ERR 0xc7 +#define IPMI_REQ_LEN_EXCEEDED_ERR 0xc8 +#define IPMI_NOT_IN_MY_STATE_ERR 0xd5 /* IPMI 2.0 */ #define IPMI_LOST_ARBITRATION_ERR 0x81 #define IPMI_BUS_ERR 0x82 #define IPMI_NAK_ON_WRITE_ERR 0x83 -- cgit v1.2.3 From 6cf24f031bc97cb5a7c9df3b6e73c45b628b2b28 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 6 Dec 2006 20:41:39 -0800 Subject: [PATCH] elf.h: forward declare struct file In file included from include/asm/patch.h:14, from arch/ia64/kernel/patch.c:10: include/linux/elf.h:375: warning: "struct file" declared inside parameter list include/linux/elf.h:375: warning: its scope is only this definition or declaration, which is probably not what you want Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/elf.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/elf.h b/include/linux/elf.h index b403516d5c3d..60713e6ea297 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -6,6 +6,8 @@ #include #include +struct file; + #ifndef elf_read_implies_exec /* Executables for which elf_read_implies_exec() returns TRUE will have the READ_IMPLIES_EXEC personality flag set automatically. -- cgit v1.2.3 From 68380b581383c028830f79ec2670f4a193854aa6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 7 Dec 2006 09:28:19 -0800 Subject: Add "run_scheduled_work()" workqueue function This allows workqueue users to run just their own pending work, rather than wait for the whole workqueue to finish running. This solves the deadlock with networking libphy that was due to other workqueue entries possibly needing a lock that was held by the routine that wanted to flush its own work. It's not wonderful: if you absolutely need to synchronize with the work function having been executed, any user strictly speaking should have its own completion tracking logic, since when we run things explicitly by hand, the generic workqueue layer can no longer help us synchronize. Also, this is strictly only usable for work that has been scheduled without any delayed timers. You can not mix the new interface with schedule_delayed_work(). But it's better than what we had currently. Acked-by: Maciej W. Rozycki Signed-off-by: Linus Torvalds --- drivers/net/phy/phy.c | 3 +- include/linux/workqueue.h | 1 + kernel/workqueue.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 4044bb1ada86..e175f3910b18 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -587,8 +587,7 @@ int phy_stop_interrupts(struct phy_device *phydev) * Finish any pending work; we might have been scheduled * to be called from keventd ourselves, though. */ - if (!current_is_keventd()) - flush_scheduled_work(); + run_scheduled_work(&phydev->phy_queue); free_irq(phydev->irq, phydev); diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index f0cb1df7b475..edef8d50b26b 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -162,6 +162,7 @@ extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq)); extern int FASTCALL(schedule_work(struct work_struct *work)); +extern int FASTCALL(run_scheduled_work(struct work_struct *work)); extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay)); extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c5257316f4b9..6b186750e9be 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -108,6 +108,79 @@ static inline void *get_wq_data(struct work_struct *work) return (void *) (work->management & WORK_STRUCT_WQ_DATA_MASK); } +static int __run_work(struct cpu_workqueue_struct *cwq, struct work_struct *work) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&cwq->lock, flags); + /* + * We need to re-validate the work info after we've gotten + * the cpu_workqueue lock. We can run the work now iff: + * + * - the wq_data still matches the cpu_workqueue_struct + * - AND the work is still marked pending + * - AND the work is still on a list (which will be this + * workqueue_struct list) + * + * All these conditions are important, because we + * need to protect against the work being run right + * now on another CPU (all but the last one might be + * true if it's currently running and has not been + * released yet, for example). + */ + if (get_wq_data(work) == cwq + && work_pending(work) + && !list_empty(&work->entry)) { + work_func_t f = work->func; + list_del_init(&work->entry); + spin_unlock_irqrestore(&cwq->lock, flags); + + if (!test_bit(WORK_STRUCT_NOAUTOREL, &work->management)) + work_release(work); + f(work); + + spin_lock_irqsave(&cwq->lock, flags); + cwq->remove_sequence++; + wake_up(&cwq->work_done); + ret = 1; + } + spin_unlock_irqrestore(&cwq->lock, flags); + return ret; +} + +/** + * run_scheduled_work - run scheduled work synchronously + * @work: work to run + * + * This checks if the work was pending, and runs it + * synchronously if so. It returns a boolean to indicate + * whether it had any scheduled work to run or not. + * + * NOTE! This _only_ works for normal work_structs. You + * CANNOT use this for delayed work, because the wq data + * for delayed work will not point properly to the per- + * CPU workqueue struct, but will change! + */ +int fastcall run_scheduled_work(struct work_struct *work) +{ + for (;;) { + struct cpu_workqueue_struct *cwq; + + if (!work_pending(work)) + return 0; + if (list_empty(&work->entry)) + return 0; + /* NOTE! This depends intimately on __queue_work! */ + cwq = get_wq_data(work); + if (!cwq) + return 0; + if (__run_work(cwq, work)) + return 1; + } +} +EXPORT_SYMBOL(run_scheduled_work); + /* Preempt must be disabled. */ static void __queue_work(struct cpu_workqueue_struct *cwq, struct work_struct *work) -- cgit v1.2.3 From a79561134f38de12dce14ed72138f38e55ef53fc Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Thu, 7 Dec 2006 09:51:35 -0800 Subject: [IA64] IA64 Kexec/kdump Changes and updates. 1. Remove fake rendz path and related code according to discuss with Khalid Aziz. 2. fc.i offset fix in relocate_kernel.S. 3. iospic shutdown code eoi and mask race fix from Fujitsu. 4. Warm boot hook in machine_kexec to SN SAL code from Jack Steiner. 5. Send slave to SAL slave loop patch from Jay Lan. 6. Kdump on non-recoverable MCA event patch from Jay Lan 7. Use CTL_UNNUMBERED in kdump_on_init sysctl. Signed-off-by: Zou Nan hai Signed-off-by: Tony Luck --- arch/ia64/Kconfig | 23 +++ arch/ia64/kernel/Makefile | 1 + arch/ia64/kernel/crash.c | 245 +++++++++++++++++++++++++++ arch/ia64/kernel/efi.c | 65 +++++++- arch/ia64/kernel/entry.S | 2 +- arch/ia64/kernel/iosapic.c | 21 +++ arch/ia64/kernel/machine_kexec.c | 133 +++++++++++++++ arch/ia64/kernel/mca.c | 5 + arch/ia64/kernel/relocate_kernel.S | 334 +++++++++++++++++++++++++++++++++++++ arch/ia64/kernel/setup.c | 38 +++++ arch/ia64/kernel/smp.c | 28 +++- arch/ia64/sn/kernel/setup.c | 8 + include/asm-ia64/kexec.h | 47 ++++++ include/asm-ia64/machvec.h | 5 + include/asm-ia64/machvec_sn2.h | 2 + include/asm-ia64/meminit.h | 3 +- include/asm-ia64/sn/sn_sal.h | 9 + include/linux/kexec.h | 5 + kernel/kexec.c | 1 + 19 files changed, 969 insertions(+), 6 deletions(-) create mode 100644 arch/ia64/kernel/crash.c create mode 100644 arch/ia64/kernel/machine_kexec.c create mode 100644 arch/ia64/kernel/relocate_kernel.S create mode 100644 include/asm-ia64/kexec.h (limited to 'include/linux') diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 683b12c6f76c..75d839715b2f 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -434,6 +434,29 @@ config IA64_ESI source "drivers/sn/Kconfig" +config KEXEC + bool "kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU) + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + +config CRASH_DUMP + bool "kernel crash dumps (EXPERIMENTAL)" + depends on EXPERIMENTAL && IA64_MCA_RECOVERY && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU) + help + Generate crash dump after being started by kexec. + source "drivers/firmware/Kconfig" source "fs/Kconfig.binfmt" diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index cfa099b04cda..8ae384eb5357 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_IA64_CYCLONE) += cyclone.o obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o obj-$(CONFIG_AUDIT) += audit.o obj-$(CONFIG_PCI_MSI) += msi_ia64.o diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c new file mode 100644 index 000000000000..0aabedf95dad --- /dev/null +++ b/arch/ia64/kernel/crash.c @@ -0,0 +1,245 @@ +/* + * arch/ia64/kernel/crash.c + * + * Architecture specific (ia64) functions for kexec based crash dumps. + * + * Created by: Khalid Aziz + * Copyright (C) 2005 Hewlett-Packard Development Company, L.P. + * Copyright (C) 2005 Intel Corp Zou Nan hai + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int kdump_status[NR_CPUS]; +atomic_t kdump_cpu_freezed; +atomic_t kdump_in_progress; +int kdump_on_init = 1; +ssize_t +copy_oldmem_page(unsigned long pfn, char *buf, + size_t csize, unsigned long offset, int userbuf) +{ + void *vaddr; + + if (!csize) + return 0; + vaddr = __va(pfn<n_namesz = strlen(name) + 1; + note->n_descsz = data_len; + note->n_type = type; + buf += (sizeof(*note) + 3)/4; + memcpy(buf, name, note->n_namesz); + buf += (note->n_namesz + 3)/4; + memcpy(buf, data, data_len); + buf += (data_len + 3)/4; + return buf; +} + +static void +final_note(void *buf) +{ + memset(buf, 0, sizeof(struct elf_note)); +} + +extern void ia64_dump_cpu_regs(void *); + +static DEFINE_PER_CPU(struct elf_prstatus, elf_prstatus); + +void +crash_save_this_cpu() +{ + void *buf; + unsigned long cfm, sof, sol; + + int cpu = smp_processor_id(); + struct elf_prstatus *prstatus = &per_cpu(elf_prstatus, cpu); + + elf_greg_t *dst = (elf_greg_t *)&(prstatus->pr_reg); + memset(prstatus, 0, sizeof(*prstatus)); + prstatus->pr_pid = current->pid; + + ia64_dump_cpu_regs(dst); + cfm = dst[43]; + sol = (cfm >> 7) & 0x7f; + sof = cfm & 0x7f; + dst[46] = (unsigned long)ia64_rse_skip_regs((unsigned long *)dst[46], + sof - sol); + + buf = (u64 *) per_cpu_ptr(crash_notes, cpu); + if (!buf) + return; + buf = append_elf_note(buf, "CORE", NT_PRSTATUS, prstatus, + sizeof(*prstatus)); + final_note(buf); +} + +static int +kdump_wait_cpu_freeze(void) +{ + int cpu_num = num_online_cpus() - 1; + int timeout = 1000; + while(timeout-- > 0) { + if (atomic_read(&kdump_cpu_freezed) == cpu_num) + return 0; + udelay(1000); + } + return 1; +} + +void +machine_crash_shutdown(struct pt_regs *pt) +{ + /* This function is only called after the system + * has paniced or is otherwise in a critical state. + * The minimum amount of code to allow a kexec'd kernel + * to run successfully needs to happen here. + * + * In practice this means shooting down the other cpus in + * an SMP system. + */ + kexec_disable_iosapic(); +#ifdef CONFIG_SMP + kdump_smp_send_stop(); + if (kdump_wait_cpu_freeze() && kdump_on_init) { + //not all cpu response to IPI, send INIT to freeze them + kdump_smp_send_init(); + } +#endif +} + +static void +machine_kdump_on_init(void) +{ + local_irq_disable(); + kexec_disable_iosapic(); + machine_kexec(ia64_kimage); +} + +void +kdump_cpu_freeze(struct unw_frame_info *info, void *arg) +{ + int cpuid; + local_irq_disable(); + cpuid = smp_processor_id(); + crash_save_this_cpu(); + current->thread.ksp = (__u64)info->sw - 16; + atomic_inc(&kdump_cpu_freezed); + kdump_status[cpuid] = 1; + mb(); + if (cpuid == 0) { + for (;;) + cpu_relax(); + } else + ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]); +} + +static int +kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data) +{ + struct ia64_mca_notify_die *nd; + struct die_args *args = data; + + if (!kdump_on_init) + return NOTIFY_DONE; + + if (val != DIE_INIT_MONARCH_ENTER && + val != DIE_INIT_SLAVE_ENTER && + val != DIE_MCA_RENDZVOUS_LEAVE && + val != DIE_MCA_MONARCH_LEAVE) + return NOTIFY_DONE; + + nd = (struct ia64_mca_notify_die *)args->err; + /* Reason code 1 means machine check rendezous*/ + if ((val == DIE_INIT_MONARCH_ENTER || DIE_INIT_SLAVE_ENTER) && + nd->sos->rv_rc == 1) + return NOTIFY_DONE; + + switch (val) { + case DIE_INIT_MONARCH_ENTER: + machine_kdump_on_init(); + break; + case DIE_INIT_SLAVE_ENTER: + unw_init_running(kdump_cpu_freeze, NULL); + break; + case DIE_MCA_RENDZVOUS_LEAVE: + if (atomic_read(&kdump_in_progress)) + unw_init_running(kdump_cpu_freeze, NULL); + break; + case DIE_MCA_MONARCH_LEAVE: + /* die_register->signr indicate if MCA is recoverable */ + if (!args->signr) + machine_kdump_on_init(); + break; + } + return NOTIFY_DONE; +} + +#ifdef CONFIG_SYSCTL +static ctl_table kdump_on_init_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "kdump_on_init", + .data = &kdump_on_init, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = 0 } +}; + +static ctl_table sys_table[] = { + { + .ctl_name = CTL_KERN, + .procname = "kernel", + .mode = 0555, + .child = kdump_on_init_table, + }, + { .ctl_name = 0 } +}; +#endif + +static int +machine_crash_setup(void) +{ + char *from = strstr(saved_command_line, "elfcorehdr="); + static struct notifier_block kdump_init_notifier_nb = { + .notifier_call = kdump_init_notifier, + }; + int ret; + if (from) + elfcorehdr_addr = memparse(from+11, &from); + saved_max_pfn = (unsigned long)-1; + if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0) + return ret; +#ifdef CONFIG_SYSCTL + register_sysctl_table(sys_table, 0); +#endif + return 0; +} + +__initcall(machine_crash_setup); + diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index bb8770a177b5..9b96e7dbaf67 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,7 @@ extern efi_status_t efi_call_phys (void *, ...); struct efi efi; EXPORT_SYMBOL(efi); static efi_runtime_services_t *runtime; -static unsigned long mem_limit = ~0UL, max_addr = ~0UL; +static unsigned long mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL; #define efi_call_virt(f, args...) (*(f))(args) @@ -421,6 +422,8 @@ efi_init (void) mem_limit = memparse(cp + 4, &cp); } else if (memcmp(cp, "max_addr=", 9) == 0) { max_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); + } else if (memcmp(cp, "min_addr=", 9) == 0) { + min_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); } else { while (*cp != ' ' && *cp) ++cp; @@ -428,6 +431,8 @@ efi_init (void) ++cp; } } + if (min_addr != 0UL) + printk(KERN_INFO "Ignoring memory below %luMB\n", min_addr >> 20); if (max_addr != ~0UL) printk(KERN_INFO "Ignoring memory above %luMB\n", max_addr >> 20); @@ -894,7 +899,8 @@ find_memmap_space (void) as = max(contig_low, md->phys_addr); ae = min(contig_high, efi_md_end(md)); - /* keep within max_addr= command line arg */ + /* keep within max_addr= and min_addr= command line arg */ + as = max(as, min_addr); ae = min(ae, max_addr); if (ae <= as) continue; @@ -1004,7 +1010,8 @@ efi_memmap_init(unsigned long *s, unsigned long *e) } else ae = efi_md_end(md); - /* keep within max_addr= command line arg */ + /* keep within max_addr= and min_addr= command line arg */ + as = max(as, min_addr); ae = min(ae, max_addr); if (ae <= as) continue; @@ -1116,6 +1123,58 @@ efi_initialize_iomem_resources(struct resource *code_resource, */ insert_resource(res, code_resource); insert_resource(res, data_resource); +#ifdef CONFIG_KEXEC + insert_resource(res, &efi_memmap_res); + insert_resource(res, &boot_param_res); + if (crashk_res.end > crashk_res.start) + insert_resource(res, &crashk_res); +#endif } } } + +#ifdef CONFIG_KEXEC +/* find a block of memory aligned to 64M exclude reserved regions + rsvd_regions are sorted + */ +unsigned long +kdump_find_rsvd_region (unsigned long size, + struct rsvd_region *r, int n) +{ + int i; + u64 start, end; + u64 alignment = 1UL << _PAGE_SIZE_64M; + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size; + + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + if (!efi_wb(md)) + continue; + start = ALIGN(md->phys_addr, alignment); + end = efi_md_end(md); + for (i = 0; i < n; i++) { + if (__pa(r[i].start) >= start && __pa(r[i].end) < end) { + if (__pa(r[i].start) > start + size) + return start; + start = ALIGN(__pa(r[i].end), alignment); + if (i < n-1 && __pa(r[i+1].start) < start + size) + continue; + else + break; + } + } + if (end > start + size) + return start; + } + + printk(KERN_WARNING "Cannot reserve 0x%lx byte of memory for crashdump\n", + size); + return ~0UL; +} +#endif diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 3390b7c5a63f..15234ed3a341 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1575,7 +1575,7 @@ sys_call_table: data8 sys_mq_timedreceive // 1265 data8 sys_mq_notify data8 sys_mq_getsetattr - data8 sys_ni_syscall // reserved for kexec_load + data8 sys_kexec_load data8 sys_ni_syscall // reserved for vserver data8 sys_waitid // 1270 data8 sys_add_key diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 60d64950e3c2..0fc5fb7865cf 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -288,6 +288,27 @@ nop (unsigned int irq) /* do nothing... */ } + +#ifdef CONFIG_KEXEC +void +kexec_disable_iosapic(void) +{ + struct iosapic_intr_info *info; + struct iosapic_rte_info *rte; + u8 vec = 0; + for (info = iosapic_intr_info; info < + iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) { + list_for_each_entry(rte, &info->rtes, + rte_list) { + iosapic_write(rte->addr, + IOSAPIC_RTE_LOW(rte->rte_index), + IOSAPIC_MASK|vec); + iosapic_eoi(rte->addr, vec); + } + } +} +#endif + static void mask_irq (unsigned int irq) { diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c new file mode 100644 index 000000000000..468233fa2cee --- /dev/null +++ b/arch/ia64/kernel/machine_kexec.c @@ -0,0 +1,133 @@ +/* + * arch/ia64/kernel/machine_kexec.c + * + * Handle transition of Linux booting another kernel + * Copyright (C) 2005 Hewlett-Packard Development Comapny, L.P. + * Copyright (C) 2005 Khalid Aziz + * Copyright (C) 2006 Intel Corp, Zou Nan hai + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef void (*relocate_new_kernel_t)(unsigned long, unsigned long, + struct ia64_boot_param *, unsigned long); + +struct kimage *ia64_kimage; + +struct resource efi_memmap_res = { + .name = "EFI Memory Map", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + +struct resource boot_param_res = { + .name = "Boot parameter", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + + +/* + * Do what every setup is needed on image and the + * reboot code buffer to allow us to avoid allocations + * later. + */ +int machine_kexec_prepare(struct kimage *image) +{ + void *control_code_buffer; + const unsigned long *func; + + func = (unsigned long *)&relocate_new_kernel; + /* Pre-load control code buffer to minimize work in kexec path */ + control_code_buffer = page_address(image->control_code_page); + memcpy((void *)control_code_buffer, (const void *)func[0], + relocate_new_kernel_size); + flush_icache_range((unsigned long)control_code_buffer, + (unsigned long)control_code_buffer + relocate_new_kernel_size); + ia64_kimage = image; + + return 0; +} + +void machine_kexec_cleanup(struct kimage *image) +{ +} + +void machine_shutdown(void) +{ + int cpu; + + for_each_online_cpu(cpu) { + if (cpu != smp_processor_id()) + cpu_down(cpu); + } + kexec_disable_iosapic(); +} + +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + */ +extern void *efi_get_pal_addr(void); +static void ia64_machine_kexec(struct unw_frame_info *info, void *arg) +{ + struct kimage *image = arg; + relocate_new_kernel_t rnk; + void *pal_addr = efi_get_pal_addr(); + unsigned long code_addr = (unsigned long)page_address(image->control_code_page); + unsigned long vector; + int ii; + + if (image->type == KEXEC_TYPE_CRASH) { + crash_save_this_cpu(); + current->thread.ksp = (__u64)info->sw - 16; + } + + /* Interrupts aren't acceptable while we reboot */ + local_irq_disable(); + + /* Mask CMC and Performance Monitor interrupts */ + ia64_setreg(_IA64_REG_CR_PMV, 1 << 16); + ia64_setreg(_IA64_REG_CR_CMCV, 1 << 16); + + /* Mask ITV and Local Redirect Registers */ + ia64_set_itv(1 << 16); + ia64_set_lrr0(1 << 16); + ia64_set_lrr1(1 << 16); + + /* terminate possible nested in-service interrupts */ + for (ii = 0; ii < 16; ii++) + ia64_eoi(); + + /* unmask TPR and clear any pending interrupts */ + ia64_setreg(_IA64_REG_CR_TPR, 0); + ia64_srlz_d(); + vector = ia64_get_ivr(); + while (vector != IA64_SPURIOUS_INT_VECTOR) { + ia64_eoi(); + vector = ia64_get_ivr(); + } + platform_kernel_launch_event(); + rnk = (relocate_new_kernel_t)&code_addr; + (*rnk)(image->head, image->start, ia64_boot_param, + GRANULEROUNDDOWN((unsigned long) pal_addr)); + BUG(); +} + +void machine_kexec(struct kimage *image) +{ + unw_init_running(ia64_machine_kexec, image); + for(;;); +} diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 6bedd97570ca..87c1c4f42872 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -82,6 +82,7 @@ #include #include #include +#include #include #include @@ -1238,6 +1239,10 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, } else { /* Dump buffered message to console */ ia64_mlogbuf_finish(1); +#ifdef CONFIG_CRASH_DUMP + atomic_set(&kdump_in_progress, 1); + monarch_cpu = -1; +#endif } if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover) == NOTIFY_STOP) diff --git a/arch/ia64/kernel/relocate_kernel.S b/arch/ia64/kernel/relocate_kernel.S new file mode 100644 index 000000000000..ae473e3f2a0d --- /dev/null +++ b/arch/ia64/kernel/relocate_kernel.S @@ -0,0 +1,334 @@ +/* + * arch/ia64/kernel/relocate_kernel.S + * + * Relocate kexec'able kernel and start it + * + * Copyright (C) 2005 Hewlett-Packard Development Company, L.P. + * Copyright (C) 2005 Khalid Aziz + * Copyright (C) 2005 Intel Corp, Zou Nan hai + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ +#include +#include +#include +#include +#include + + /* Must be relocatable PIC code callable as a C function + */ +GLOBAL_ENTRY(relocate_new_kernel) + .prologue + alloc r31=ar.pfs,4,0,0,0 + .body +.reloc_entry: +{ + rsm psr.i| psr.ic + mov r2=ip +} + ;; +{ + flushrs // must be first insn in group + srlz.i +} + ;; + dep r2=0,r2,61,3 //to physical address + ;; + //first switch to physical mode + add r3=1f-.reloc_entry, r2 + movl r16 = IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC + mov ar.rsc=0 // put RSE in enforced lazy mode + ;; + add sp=(memory_stack_end - 16 - .reloc_entry),r2 + add r8=(register_stack - .reloc_entry),r2 + ;; + mov r18=ar.rnat + mov ar.bspstore=r8 + ;; + mov cr.ipsr=r16 + mov cr.iip=r3 + mov cr.ifs=r0 + srlz.i + ;; + mov ar.rnat=r18 + rfi + ;; +1: + //physical mode code begin + mov b6=in1 + dep r28=0,in2,61,3 //to physical address + + // purge all TC entries +#define O(member) IA64_CPUINFO_##member##_OFFSET + GET_THIS_PADDR(r2, cpu_info) // load phys addr of cpu_info into r2 + ;; + addl r17=O(PTCE_STRIDE),r2 + addl r2=O(PTCE_BASE),r2 + ;; + ld8 r18=[r2],(O(PTCE_COUNT)-O(PTCE_BASE));; // r18=ptce_base + ld4 r19=[r2],4 // r19=ptce_count[0] + ld4 r21=[r17],4 // r21=ptce_stride[0] + ;; + ld4 r20=[r2] // r20=ptce_count[1] + ld4 r22=[r17] // r22=ptce_stride[1] + mov r24=r0 + ;; + adds r20=-1,r20 + ;; +#undef O +2: + cmp.ltu p6,p7=r24,r19 +(p7) br.cond.dpnt.few 4f + mov ar.lc=r20 +3: + ptc.e r18 + ;; + add r18=r22,r18 + br.cloop.sptk.few 3b + ;; + add r18=r21,r18 + add r24=1,r24 + ;; + br.sptk.few 2b +4: + srlz.i + ;; + //purge TR entry for kernel text and data + movl r16=KERNEL_START + mov r18=KERNEL_TR_PAGE_SHIFT<<2 + ;; + ptr.i r16, r18 + ptr.d r16, r18 + ;; + srlz.i + ;; + + // purge TR entry for percpu data + movl r16=PERCPU_ADDR + mov r18=PERCPU_PAGE_SHIFT<<2 + ;; + ptr.d r16,r18 + ;; + srlz.d + ;; + + // purge TR entry for pal code + mov r16=in3 + mov r18=IA64_GRANULE_SHIFT<<2 + ;; + ptr.i r16,r18 + ;; + srlz.i + ;; + + // purge TR entry for stack + mov r16=IA64_KR(CURRENT_STACK) + ;; + shl r16=r16,IA64_GRANULE_SHIFT + movl r19=PAGE_OFFSET + ;; + add r16=r19,r16 + mov r18=IA64_GRANULE_SHIFT<<2 + ;; + ptr.d r16,r18 + ;; + srlz.i + ;; + + //copy segments + movl r16=PAGE_MASK + mov r30=in0 // in0 is page_list + br.sptk.few .dest_page + ;; +.loop: + ld8 r30=[in0], 8;; +.dest_page: + tbit.z p0, p6=r30, 0;; // 0x1 dest page +(p6) and r17=r30, r16 +(p6) br.cond.sptk.few .loop;; + + tbit.z p0, p6=r30, 1;; // 0x2 indirect page +(p6) and in0=r30, r16 +(p6) br.cond.sptk.few .loop;; + + tbit.z p0, p6=r30, 2;; // 0x4 end flag +(p6) br.cond.sptk.few .end_loop;; + + tbit.z p6, p0=r30, 3;; // 0x8 source page +(p6) br.cond.sptk.few .loop + + and r18=r30, r16 + + // simple copy page, may optimize later + movl r14=PAGE_SIZE/8 - 1;; + mov ar.lc=r14;; +1: + ld8 r14=[r18], 8;; + st8 [r17]=r14;; + fc.i r17 + add r17=8, r17 + br.ctop.sptk.few 1b + br.sptk.few .loop + ;; + +.end_loop: + sync.i // for fc.i + ;; + srlz.i + ;; + srlz.d + ;; + br.call.sptk.many b0=b6;; + +.align 32 +memory_stack: + .fill 8192, 1, 0 +memory_stack_end: +register_stack: + .fill 8192, 1, 0 +register_stack_end: +relocate_new_kernel_end: +END(relocate_new_kernel) + +.global relocate_new_kernel_size +relocate_new_kernel_size: + data8 relocate_new_kernel_end - relocate_new_kernel + +GLOBAL_ENTRY(ia64_dump_cpu_regs) + .prologue + alloc loc0=ar.pfs,1,2,0,0 + .body + mov ar.rsc=0 // put RSE in enforced lazy mode + add loc1=4*8, in0 // save r4 and r5 first + ;; +{ + flushrs // flush dirty regs to backing store + srlz.i +} + st8 [loc1]=r4, 8 + ;; + st8 [loc1]=r5, 8 + ;; + add loc1=32*8, in0 + mov r4=ar.rnat + ;; + st8 [in0]=r0, 8 // r0 + st8 [loc1]=r4, 8 // rnat + mov r5=pr + ;; + st8 [in0]=r1, 8 // r1 + st8 [loc1]=r5, 8 // pr + mov r4=b0 + ;; + st8 [in0]=r2, 8 // r2 + st8 [loc1]=r4, 8 // b0 + mov r5=b1; + ;; + st8 [in0]=r3, 24 // r3 + st8 [loc1]=r5, 8 // b1 + mov r4=b2 + ;; + st8 [in0]=r6, 8 // r6 + st8 [loc1]=r4, 8 // b2 + mov r5=b3 + ;; + st8 [in0]=r7, 8 // r7 + st8 [loc1]=r5, 8 // b3 + mov r4=b4 + ;; + st8 [in0]=r8, 8 // r8 + st8 [loc1]=r4, 8 // b4 + mov r5=b5 + ;; + st8 [in0]=r9, 8 // r9 + st8 [loc1]=r5, 8 // b5 + mov r4=b6 + ;; + st8 [in0]=r10, 8 // r10 + st8 [loc1]=r5, 8 // b6 + mov r5=b7 + ;; + st8 [in0]=r11, 8 // r11 + st8 [loc1]=r5, 8 // b7 + mov r4=b0 + ;; + st8 [in0]=r12, 8 // r12 + st8 [loc1]=r4, 8 // ip + mov r5=loc0 + ;; + st8 [in0]=r13, 8 // r13 + extr.u r5=r5, 0, 38 // ar.pfs.pfm + mov r4=r0 // user mask + ;; + st8 [in0]=r14, 8 // r14 + st8 [loc1]=r5, 8 // cfm + ;; + st8 [in0]=r15, 8 // r15 + st8 [loc1]=r4, 8 // user mask + mov r5=ar.rsc + ;; + st8 [in0]=r16, 8 // r16 + st8 [loc1]=r5, 8 // ar.rsc + mov r4=ar.bsp + ;; + st8 [in0]=r17, 8 // r17 + st8 [loc1]=r4, 8 // ar.bsp + mov r5=ar.bspstore + ;; + st8 [in0]=r18, 8 // r18 + st8 [loc1]=r5, 8 // ar.bspstore + mov r4=ar.rnat + ;; + st8 [in0]=r19, 8 // r19 + st8 [loc1]=r4, 8 // ar.rnat + mov r5=ar.ccv + ;; + st8 [in0]=r20, 8 // r20 + st8 [loc1]=r5, 8 // ar.ccv + mov r4=ar.unat + ;; + st8 [in0]=r21, 8 // r21 + st8 [loc1]=r4, 8 // ar.unat + mov r5 = ar.fpsr + ;; + st8 [in0]=r22, 8 // r22 + st8 [loc1]=r5, 8 // ar.fpsr + mov r4 = ar.unat + ;; + st8 [in0]=r23, 8 // r23 + st8 [loc1]=r4, 8 // unat + mov r5 = ar.fpsr + ;; + st8 [in0]=r24, 8 // r24 + st8 [loc1]=r5, 8 // fpsr + mov r4 = ar.pfs + ;; + st8 [in0]=r25, 8 // r25 + st8 [loc1]=r4, 8 // ar.pfs + mov r5 = ar.lc + ;; + st8 [in0]=r26, 8 // r26 + st8 [loc1]=r5, 8 // ar.lc + mov r4 = ar.ec + ;; + st8 [in0]=r27, 8 // r27 + st8 [loc1]=r4, 8 // ar.ec + mov r5 = ar.csd + ;; + st8 [in0]=r28, 8 // r28 + st8 [loc1]=r5, 8 // ar.csd + mov r4 = ar.ssd + ;; + st8 [in0]=r29, 8 // r29 + st8 [loc1]=r4, 8 // ar.ssd + ;; + st8 [in0]=r30, 8 // r30 + ;; + st8 [in0]=r31, 8 // r31 + mov ar.pfs=loc0 + ;; + br.ret.sptk.many rp +END(ia64_dump_cpu_regs) + + diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index d10404a41756..14e1200376a9 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include @@ -252,6 +254,41 @@ reserve_memory (void) efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end); n++; +#ifdef CONFIG_KEXEC + /* crashkernel=size@offset specifies the size to reserve for a crash + * kernel.(offset is ingored for keep compatibility with other archs) + * By reserving this memory we guarantee that linux never set's it + * up as a DMA target.Useful for holding code to do something + * appropriate after a kernel panic. + */ + { + char *from = strstr(saved_command_line, "crashkernel="); + unsigned long base, size; + if (from) { + size = memparse(from + 12, &from); + if (size) { + sort_regions(rsvd_region, n); + base = kdump_find_rsvd_region(size, + rsvd_region, n); + if (base != ~0UL) { + rsvd_region[n].start = + (unsigned long)__va(base); + rsvd_region[n].end = + (unsigned long)__va(base + size); + n++; + crashk_res.start = base; + crashk_res.end = base + size - 1; + } + } + } + efi_memmap_res.start = ia64_boot_param->efi_memmap; + efi_memmap_res.end = efi_memmap_res.start + + ia64_boot_param->efi_memmap_size; + boot_param_res.start = __pa(ia64_boot_param); + boot_param_res.end = boot_param_res.start + + sizeof(*ia64_boot_param); + } +#endif /* end of memory marker */ rsvd_region[n].start = ~0UL; rsvd_region[n].end = ~0UL; @@ -263,6 +300,7 @@ reserve_memory (void) sort_regions(rsvd_region, num_rsvd_regions); } + /** * find_initrd - get initrd parameters from the boot parameter structure * diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index 6ab95ceaf9d4..b1b9aa4364b9 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,7 @@ static volatile struct call_data_struct *call_data; #define IPI_CALL_FUNC 0 #define IPI_CPU_STOP 1 +#define IPI_KDUMP_CPU_STOP 3 /* This needs to be cacheline aligned because it is written to by *other* CPUs. */ static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned; @@ -155,7 +157,11 @@ handle_IPI (int irq, void *dev_id) case IPI_CPU_STOP: stop_this_cpu(); break; - +#ifdef CONFIG_CRASH_DUMP + case IPI_KDUMP_CPU_STOP: + unw_init_running(kdump_cpu_freeze, NULL); + break; +#endif default: printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); break; @@ -213,6 +219,26 @@ send_IPI_self (int op) send_IPI_single(smp_processor_id(), op); } +#ifdef CONFIG_CRASH_DUMP +void +kdump_smp_send_stop() +{ + send_IPI_allbutself(IPI_KDUMP_CPU_STOP); +} + +void +kdump_smp_send_init() +{ + unsigned int cpu, self_cpu; + self_cpu = smp_processor_id(); + for_each_online_cpu(cpu) { + if (cpu != self_cpu) { + if(kdump_status[cpu] == 0) + platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); + } + } +} +#endif /* * Called with preeemption disabled. */ diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 1d009f93244d..a934ad069425 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -769,5 +769,13 @@ int sn_prom_feature_available(int id) return 0; return test_bit(id, sn_prom_features); } + +void +sn_kernel_launch_event(void) +{ + /* ignore status until we understand possible failure, if any*/ + if (ia64_sn_kernel_launch_event()) + printk(KERN_ERR "KEXEC is not supported in this PROM, Please update the PROM.\n"); +} EXPORT_SYMBOL(sn_prom_feature_available); diff --git a/include/asm-ia64/kexec.h b/include/asm-ia64/kexec.h new file mode 100644 index 000000000000..01c36b004747 --- /dev/null +++ b/include/asm-ia64/kexec.h @@ -0,0 +1,47 @@ +#ifndef _ASM_IA64_KEXEC_H +#define _ASM_IA64_KEXEC_H + + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) +/* Maximum address we can use for the control code buffer */ +#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE + +#define KEXEC_CONTROL_CODE_SIZE (8192 + 8192 + 4096) + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_IA_64 + +#define MAX_NOTE_BYTES 1024 + +#define kexec_flush_icache_page(page) do { \ + unsigned long page_addr = (unsigned long)page_address(page); \ + flush_icache_range(page_addr, page_addr + PAGE_SIZE); \ + } while(0) + +extern struct kimage *ia64_kimage; +DECLARE_PER_CPU(u64, ia64_mca_pal_base); +const extern unsigned int relocate_new_kernel_size; +extern void relocate_new_kernel(unsigned long, unsigned long, + struct ia64_boot_param *, unsigned long); +static inline void +crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) +{ +} +extern struct resource efi_memmap_res; +extern struct resource boot_param_res; +extern void kdump_smp_send_stop(void); +extern void kdump_smp_send_init(void); +extern void kexec_disable_iosapic(void); +extern void crash_save_this_cpu(void); +struct rsvd_region; +extern unsigned long kdump_find_rsvd_region(unsigned long size, + struct rsvd_region *rsvd_regions, int n); +extern void kdump_cpu_freeze(struct unw_frame_info *info, void *arg); +extern int kdump_status[]; +extern atomic_t kdump_cpu_freezed; +extern atomic_t kdump_in_progress; + +#endif /* _ASM_IA64_KEXEC_H */ diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h index 8f784f8e45b0..a3891eb3f217 100644 --- a/include/asm-ia64/machvec.h +++ b/include/asm-ia64/machvec.h @@ -37,6 +37,7 @@ typedef int ia64_mv_pci_legacy_write_t (struct pci_bus *, u16 port, u32 val, u8 size); typedef void ia64_mv_migrate_t(struct task_struct * task); typedef void ia64_mv_pci_fixup_bus_t (struct pci_bus *); +typedef void ia64_mv_kernel_launch_event_t(void); /* DMA-mapping interface: */ typedef void ia64_mv_dma_init (void); @@ -218,6 +219,7 @@ struct ia64_machine_vector { ia64_mv_setup_msi_irq_t *setup_msi_irq; ia64_mv_teardown_msi_irq_t *teardown_msi_irq; ia64_mv_pci_fixup_bus_t *pci_fixup_bus; + ia64_mv_kernel_launch_event_t *kernel_launch_event; } __attribute__((__aligned__(16))); /* align attrib? see above comment */ #define MACHVEC_INIT(name) \ @@ -318,6 +320,9 @@ extern ia64_mv_dma_supported swiotlb_dma_supported; #ifndef platform_tlb_migrate_finish # define platform_tlb_migrate_finish machvec_noop_mm #endif +#ifndef platform_kernel_launch_event +# define platform_kernel_launch_event machvec_noop +#endif #ifndef platform_dma_init # define platform_dma_init swiotlb_init #endif diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h index 83325f6db03e..eaa2fce0fecd 100644 --- a/include/asm-ia64/machvec_sn2.h +++ b/include/asm-ia64/machvec_sn2.h @@ -67,6 +67,7 @@ extern ia64_mv_dma_sync_sg_for_device sn_dma_sync_sg_for_device; extern ia64_mv_dma_mapping_error sn_dma_mapping_error; extern ia64_mv_dma_supported sn_dma_supported; extern ia64_mv_migrate_t sn_migrate; +extern ia64_mv_kernel_launch_event_t sn_kernel_launch_event; extern ia64_mv_setup_msi_irq_t sn_setup_msi_irq; extern ia64_mv_teardown_msi_irq_t sn_teardown_msi_irq; extern ia64_mv_pci_fixup_bus_t sn_pci_fixup_bus; @@ -121,6 +122,7 @@ extern ia64_mv_pci_fixup_bus_t sn_pci_fixup_bus; #define platform_dma_mapping_error sn_dma_mapping_error #define platform_dma_supported sn_dma_supported #define platform_migrate sn_migrate +#define platform_kernel_launch_event sn_kernel_launch_event #ifdef CONFIG_PCI_MSI #define platform_setup_msi_irq sn_setup_msi_irq #define platform_teardown_msi_irq sn_teardown_msi_irq diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h index c3b1f862e6e7..c8df75901083 100644 --- a/include/asm-ia64/meminit.h +++ b/include/asm-ia64/meminit.h @@ -15,11 +15,12 @@ * - initrd (optional) * - command line string * - kernel code & data + * - crash dumping code reserved region * - Kernel memory map built from EFI memory map * * More could be added if necessary */ -#define IA64_MAX_RSVD_REGIONS 6 +#define IA64_MAX_RSVD_REGIONS 7 struct rsvd_region { unsigned long start; /* virtual address of beginning of element */ diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index be5d83ad7cb1..2c4004eb5a68 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -88,6 +88,8 @@ #define SN_SAL_INJECT_ERROR 0x02000067 #define SN_SAL_SET_CPU_NUMBER 0x02000068 +#define SN_SAL_KERNEL_LAUNCH_EVENT 0x02000069 + /* * Service-specific constants */ @@ -1155,4 +1157,11 @@ ia64_sn_set_cpu_number(int cpu) SAL_CALL_NOLOCK(rv, SN_SAL_SET_CPU_NUMBER, cpu, 0, 0, 0, 0, 0, 0); return rv.status; } +static inline int +ia64_sn_kernel_launch_event(void) +{ + struct ia64_sal_retval rv; + SAL_CALL_NOLOCK(rv, SN_SAL_KERNEL_LAUNCH_EVENT, 0, 0, 0, 0, 0, 0, 0); + return rv.status; +} #endif /* _ASM_IA64_SN_SN_SAL_H */ diff --git a/include/linux/kexec.h b/include/linux/kexec.h index a4ede62b339d..e14cd388c65b 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -108,6 +108,10 @@ int kexec_should_crash(struct task_struct *); extern struct kimage *kexec_image; extern struct kimage *kexec_crash_image; +#ifndef kexec_flush_icache_page +#define kexec_flush_icache_page(page) +#endif + #define KEXEC_ON_CRASH 0x00000001 #define KEXEC_ARCH_MASK 0xffff0000 @@ -133,6 +137,7 @@ extern struct resource crashk_res; typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; extern note_buf_t *crash_notes; + #else /* !CONFIG_KEXEC */ struct pt_regs; struct task_struct; diff --git a/kernel/kexec.c b/kernel/kexec.c index fcdd5d2bc3f4..05aada293592 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -851,6 +851,7 @@ static int kimage_load_crash_segment(struct kimage *image, memset(ptr + uchunk, 0, mchunk - uchunk); } result = copy_from_user(ptr, buf, uchunk); + kexec_flush_icache_page(page); kunmap(page); if (result) { result = (result < 0) ? result : -EIO; -- cgit v1.2.3 From 24ec839c431eb79bb8f6abc00c4e1eb3b8c4d517 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 8 Dec 2006 02:36:04 -0800 Subject: [PATCH] tty: ->signal->tty locking Fix the locking of signal->tty. Use ->sighand->siglock to protect ->signal->tty; this lock is already used by most other members of ->signal/->sighand. And unless we are 'current' or the tasklist_lock is held we need ->siglock to access ->signal anyway. (NOTE: sys_unshare() is broken wrt ->sighand locking rules) Note that tty_mutex is held over tty destruction, so while holding tty_mutex any tty pointer remains valid. Otherwise the lifetime of ttys are governed by their open file handles. This leaves some holes for tty access from signal->tty (or any other non file related tty access). It solves the tty SLAB scribbles we were seeing. (NOTE: the change from group_send_sig_info to __group_send_sig_info needs to be examined by someone familiar with the security framework, I think it is safe given the SEND_SIG_PRIV from other __group_send_sig_info invocations) [schwidefsky@de.ibm.com: 3270 fix] [akpm@osdl.org: various post-viro fixes] Signed-off-by: Peter Zijlstra Acked-by: Alan Cox Cc: Oleg Nesterov Cc: Prarit Bhargava Cc: Chris Wright Cc: Roland McGrath Cc: Stephen Smalley Cc: James Morris Cc: "David S. Miller" Cc: Jeff Dike Cc: Martin Schwidefsky Cc: Jan Kara Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/sparc64/solaris/misc.c | 4 +- arch/um/kernel/exec.c | 7 +- drivers/char/tty_io.c | 237 ++++++++++++++++++++++++++------------------ drivers/s390/char/fs3270.c | 12 ++- fs/dquot.c | 14 +-- fs/open.c | 1 + include/linux/tty.h | 11 +- kernel/acct.c | 9 +- kernel/auditsc.c | 2 + kernel/exit.c | 4 +- kernel/sys.c | 6 +- security/selinux/hooks.c | 11 +- 12 files changed, 186 insertions(+), 132 deletions(-) (limited to 'include/linux') diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 9ed997982f8d..e84241d5f7f4 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -423,9 +423,7 @@ asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid) Solaris setpgrp and setsid? */ ret = sys_setpgid(0, 0); if (ret) return ret; - mutex_lock(&tty_mutex); - current->signal->tty = NULL; - mutex_unlock(&tty_mutex); + proc_clear_tty(current); return process_group(current); } case 2: /* getsid */ diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index 0561c43b4685..8d56ec6cca79 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c @@ -39,12 +39,13 @@ static long execve1(char *file, char __user * __user *argv, char __user *__user *env) { long error; + struct tty_struct *tty; #ifdef CONFIG_TTY_LOG mutex_lock(&tty_mutex); - task_lock(current); /* FIXME: is this needed ? */ - log_exec(argv, current->signal->tty); - task_unlock(current); + tty = get_current_tty(); + if (tty) + log_exec(argv, tty); mutex_unlock(&tty_mutex); #endif error = do_execve(file, argv, env, ¤t->thread.regs); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index b3cfc8bc613c..0c856a6f3677 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -126,7 +126,7 @@ EXPORT_SYMBOL(tty_std_termios); LIST_HEAD(tty_drivers); /* linked list of tty drivers */ -/* Semaphore to protect creating and releasing a tty. This is shared with +/* Mutex to protect creating and releasing a tty. This is shared with vt.c for deeply disgusting hack reasons */ DEFINE_MUTEX(tty_mutex); EXPORT_SYMBOL(tty_mutex); @@ -250,7 +250,7 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) "!= #fd's(%d) in %s\n", tty->name, tty->count, count, routine); return count; - } + } #endif return 0; } @@ -259,18 +259,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) * Tty buffer allocation management */ - -/** - * tty_buffer_free_all - free buffers used by a tty - * @tty: tty to free from - * - * Remove all the buffers pending on a tty whether queued with data - * or in the free ring. Must be called when the tty is no longer in use - * - * Locking: none - */ - - /** * tty_buffer_free_all - free buffers used by a tty * @tty: tty to free from @@ -614,7 +602,7 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); * they are not on hot paths so a little discipline won't do * any harm. * - * Locking: takes termios_sem + * Locking: takes termios_mutex */ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) @@ -915,7 +903,7 @@ static void tty_ldisc_enable(struct tty_struct *tty) * context. * * Locking: takes tty_ldisc_lock. - * called functions take termios_sem + * called functions take termios_mutex */ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) @@ -1267,12 +1255,12 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); * * Locking: * BKL - * redirect lock for undoing redirection - * file list lock for manipulating list of ttys - * tty_ldisc_lock from called functions - * termios_sem resetting termios data - * tasklist_lock to walk task list for hangup event - * + * redirect lock for undoing redirection + * file list lock for manipulating list of ttys + * tty_ldisc_lock from called functions + * termios_mutex resetting termios data + * tasklist_lock to walk task list for hangup event + * ->siglock to protect ->signal/->sighand */ static void do_tty_hangup(struct work_struct *work) { @@ -1354,14 +1342,18 @@ static void do_tty_hangup(struct work_struct *work) read_lock(&tasklist_lock); if (tty->session > 0) { do_each_task_pid(tty->session, PIDTYPE_SID, p) { + spin_lock_irq(&p->sighand->siglock); if (p->signal->tty == tty) p->signal->tty = NULL; - if (!p->signal->leader) + if (!p->signal->leader) { + spin_unlock_irq(&p->sighand->siglock); continue; - group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); - group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); + } + __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); + __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); if (tty->pgrp > 0) p->signal->tty_old_pgrp = tty->pgrp; + spin_unlock_irq(&p->sighand->siglock); } while_each_task_pid(tty->session, PIDTYPE_SID, p); } read_unlock(&tasklist_lock); @@ -1453,6 +1445,14 @@ int tty_hung_up_p(struct file * filp) EXPORT_SYMBOL(tty_hung_up_p); +static void session_clear_tty(pid_t session) +{ + struct task_struct *p; + do_each_task_pid(session, PIDTYPE_SID, p) { + proc_clear_tty(p); + } while_each_task_pid(session, PIDTYPE_SID, p); +} + /** * disassociate_ctty - disconnect controlling tty * @on_exit: true if exiting so need to "hang up" the session @@ -1469,31 +1469,35 @@ EXPORT_SYMBOL(tty_hung_up_p); * The argument on_exit is set to 1 if called when a process is * exiting; it is 0 if called by the ioctl TIOCNOTTY. * - * Locking: tty_mutex is taken to protect current->signal->tty + * Locking: * BKL is taken for hysterical raisins - * Tasklist lock is taken (under tty_mutex) to walk process - * lists for the session. + * tty_mutex is taken to protect tty + * ->siglock is taken to protect ->signal/->sighand + * tasklist_lock is taken to walk process list for sessions + * ->siglock is taken to protect ->signal/->sighand */ void disassociate_ctty(int on_exit) { struct tty_struct *tty; - struct task_struct *p; int tty_pgrp = -1; + int session; lock_kernel(); mutex_lock(&tty_mutex); - tty = current->signal->tty; + tty = get_current_tty(); if (tty) { tty_pgrp = tty->pgrp; mutex_unlock(&tty_mutex); + /* XXX: here we race, there is nothing protecting tty */ if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); } else { - if (current->signal->tty_old_pgrp) { - kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit); - kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit); + pid_t old_pgrp = current->signal->tty_old_pgrp; + if (old_pgrp) { + kill_pg(old_pgrp, SIGHUP, on_exit); + kill_pg(old_pgrp, SIGCONT, on_exit); } mutex_unlock(&tty_mutex); unlock_kernel(); @@ -1505,19 +1509,29 @@ void disassociate_ctty(int on_exit) kill_pg(tty_pgrp, SIGCONT, on_exit); } - /* Must lock changes to tty_old_pgrp */ - mutex_lock(&tty_mutex); + spin_lock_irq(¤t->sighand->siglock); current->signal->tty_old_pgrp = 0; - tty->session = 0; - tty->pgrp = -1; + session = current->signal->session; + spin_unlock_irq(¤t->sighand->siglock); + + mutex_lock(&tty_mutex); + /* It is possible that do_tty_hangup has free'd this tty */ + tty = get_current_tty(); + if (tty) { + tty->session = 0; + tty->pgrp = 0; + } else { +#ifdef TTY_DEBUG_HANGUP + printk(KERN_DEBUG "error attempted to write to tty [0x%p]" + " = NULL", tty); +#endif + } + mutex_unlock(&tty_mutex); /* Now clear signal->tty under the lock */ read_lock(&tasklist_lock); - do_each_task_pid(current->signal->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(current->signal->session, PIDTYPE_SID, p); + session_clear_tty(session); read_unlock(&tasklist_lock); - mutex_unlock(&tty_mutex); unlock_kernel(); } @@ -2337,16 +2351,10 @@ static void release_dev(struct file * filp) * tty. */ if (tty_closing || o_tty_closing) { - struct task_struct *p; - read_lock(&tasklist_lock); - do_each_task_pid(tty->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(tty->session, PIDTYPE_SID, p); + session_clear_tty(tty->session); if (o_tty) - do_each_task_pid(o_tty->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(o_tty->session, PIDTYPE_SID, p); + session_clear_tty(o_tty->session); read_unlock(&tasklist_lock); } @@ -2443,9 +2451,9 @@ static void release_dev(struct file * filp) * The termios state of a pty is reset on first open so that * settings don't persist across reuse. * - * Locking: tty_mutex protects current->signal->tty, get_tty_driver and - * init_dev work. tty->count should protect the rest. - * task_lock is held to update task details for sessions + * Locking: tty_mutex protects tty, get_tty_driver and init_dev work. + * tty->count should protect the rest. + * ->siglock protects ->signal/->sighand */ static int tty_open(struct inode * inode, struct file * filp) @@ -2467,12 +2475,13 @@ retry_open: mutex_lock(&tty_mutex); if (device == MKDEV(TTYAUX_MAJOR,0)) { - if (!current->signal->tty) { + tty = get_current_tty(); + if (!tty) { mutex_unlock(&tty_mutex); return -ENXIO; } - driver = current->signal->tty->driver; - index = current->signal->tty->index; + driver = tty->driver; + index = tty->index; filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ /* noctty = 1; */ goto got_driver; @@ -2547,17 +2556,16 @@ got_driver: filp->f_op = &tty_fops; goto retry_open; } + + mutex_lock(&tty_mutex); + spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && !current->signal->tty && - tty->session == 0) { - task_lock(current); - current->signal->tty = tty; - task_unlock(current); - current->signal->tty_old_pgrp = 0; - tty->session = current->signal->session; - tty->pgrp = process_group(current); - } + tty->session == 0) + __proc_set_tty(current, tty); + spin_unlock_irq(¤t->sighand->siglock); + mutex_unlock(&tty_mutex); return 0; } @@ -2747,7 +2755,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p) * * Copies the kernel idea of the window size into the user buffer. * - * Locking: tty->termios_sem is taken to ensure the winsize data + * Locking: tty->termios_mutex is taken to ensure the winsize data * is consistent. */ @@ -2774,8 +2782,8 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) * Locking: * Called function use the console_sem is used to ensure we do * not try and resize the console twice at once. - * The tty->termios_sem is used to ensure we don't double - * resize and get confused. Lock order - tty->termios.sem before + * The tty->termios_mutex is used to ensure we don't double + * resize and get confused. Lock order - tty->termios_mutex before * console sem */ @@ -2880,25 +2888,28 @@ static int fionbio(struct file *file, int __user *p) * leader to set this tty as the controlling tty for the session. * * Locking: - * Takes tasklist lock internally to walk sessions - * Takes task_lock() when updating signal->tty * Takes tty_mutex() to protect tty instance - * + * Takes tasklist_lock internally to walk sessions + * Takes ->siglock() when updating signal->tty */ static int tiocsctty(struct tty_struct *tty, int arg) { - struct task_struct *p; - + int ret = 0; if (current->signal->leader && (current->signal->session == tty->session)) - return 0; + return ret; + + mutex_lock(&tty_mutex); /* * The process must be a session leader and * not have a controlling tty already. */ - if (!current->signal->leader || current->signal->tty) - return -EPERM; + if (!current->signal->leader || current->signal->tty) { + ret = -EPERM; + goto unlock; + } + if (tty->session > 0) { /* * This tty is already the controlling @@ -2908,24 +2919,18 @@ static int tiocsctty(struct tty_struct *tty, int arg) /* * Steal it away */ - read_lock(&tasklist_lock); - do_each_task_pid(tty->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(tty->session, PIDTYPE_SID, p); + session_clear_tty(tty->session); read_unlock(&tasklist_lock); - } else - return -EPERM; + } else { + ret = -EPERM; + goto unlock; + } } - mutex_lock(&tty_mutex); - task_lock(current); - current->signal->tty = tty; - task_unlock(current); + proc_set_tty(current, tty); +unlock: mutex_unlock(&tty_mutex); - current->signal->tty_old_pgrp = 0; - tty->session = current->signal->session; - tty->pgrp = process_group(current); - return 0; + return ret; } /** @@ -2937,7 +2942,7 @@ static int tiocsctty(struct tty_struct *tty, int arg) * Obtain the process group of the tty. If there is no process group * return an error. * - * Locking: none. Reference to ->signal->tty is safe. + * Locking: none. Reference to current->signal->tty is safe. */ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) @@ -2995,7 +3000,7 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t * Obtain the session id of the tty. If there is no session * return an error. * - * Locking: none. Reference to ->signal->tty is safe. + * Locking: none. Reference to current->signal->tty is safe. */ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) @@ -3214,14 +3219,11 @@ int tty_ioctl(struct inode * inode, struct file * file, clear_bit(TTY_EXCLUSIVE, &tty->flags); return 0; case TIOCNOTTY: - /* FIXME: taks lock or tty_mutex ? */ if (current->signal->tty != tty) return -ENOTTY; if (current->signal->leader) disassociate_ctty(0); - task_lock(current); - current->signal->tty = NULL; - task_unlock(current); + proc_clear_tty(current); return 0; case TIOCSCTTY: return tiocsctty(tty, arg); @@ -3321,7 +3323,7 @@ static void __do_SAK(struct work_struct *work) if (!tty) return; - session = tty->session; + session = tty->session; /* We don't want an ldisc switch during this */ disc = tty_ldisc_ref(tty); @@ -3834,9 +3836,52 @@ int tty_unregister_driver(struct tty_driver *driver) cdev_del(&driver->cdev); return 0; } - EXPORT_SYMBOL(tty_unregister_driver); +dev_t tty_devnum(struct tty_struct *tty) +{ + return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index; +} +EXPORT_SYMBOL(tty_devnum); + +void proc_clear_tty(struct task_struct *p) +{ + spin_lock_irq(&p->sighand->siglock); + p->signal->tty = NULL; + spin_unlock_irq(&p->sighand->siglock); +} +EXPORT_SYMBOL(proc_clear_tty); + +void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) +{ + if (tty) { + tty->session = tsk->signal->session; + tty->pgrp = process_group(tsk); + } + tsk->signal->tty = tty; + tsk->signal->tty_old_pgrp = 0; +} + +void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) +{ + spin_lock_irq(&tsk->sighand->siglock); + __proc_set_tty(tsk, tty); + spin_unlock_irq(&tsk->sighand->siglock); +} + +struct tty_struct *get_current_tty(void) +{ + struct tty_struct *tty; + WARN_ON_ONCE(!mutex_is_locked(&tty_mutex)); + tty = current->signal->tty; + /* + * session->tty can be changed/cleared from under us, make sure we + * issue the load. The obtained pointer, when not NULL, is valid as + * long as we hold tty_mutex. + */ + barrier(); + return tty; +} /* * Initialize the console device. This is called *early*, so diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 78f8bda81dae..ef205ddd31a4 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -424,11 +424,15 @@ fs3270_open(struct inode *inode, struct file *filp) minor = iminor(filp->f_dentry->d_inode); /* Check for minor 0 multiplexer. */ if (minor == 0) { - if (!current->signal->tty) + struct tty_struct *tty; + mutex_lock(&tty_mutex); + tty = get_current_tty(); + if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) { + mutex_unlock(&tty_mutex); return -ENODEV; - if (current->signal->tty->driver->major != IBM_TTY3270_MAJOR) - return -ENODEV; - minor = current->signal->tty->index + RAW3270_FIRSTMINOR; + } + minor = tty->index + RAW3270_FIRSTMINOR; + mutex_unlock(&tty_mutex); } /* Check if some other program is already using fullscreen mode. */ fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor); diff --git a/fs/dquot.c b/fs/dquot.c index f9cd5e23ebdf..89066b19124d 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -828,6 +828,7 @@ static inline int need_print_warning(struct dquot *dquot) static void print_warning(struct dquot *dquot, const char warntype) { char *msg = NULL; + struct tty_struct *tty; int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS_B : ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES_B : 0); @@ -835,14 +836,15 @@ static void print_warning(struct dquot *dquot, const char warntype) return; mutex_lock(&tty_mutex); - if (!current->signal->tty) + tty = get_current_tty(); + if (!tty) goto out_lock; - tty_write_message(current->signal->tty, dquot->dq_sb->s_id); + tty_write_message(tty, dquot->dq_sb->s_id); if (warntype == ISOFTWARN || warntype == BSOFTWARN) - tty_write_message(current->signal->tty, ": warning, "); + tty_write_message(tty, ": warning, "); else - tty_write_message(current->signal->tty, ": write failed, "); - tty_write_message(current->signal->tty, quotatypes[dquot->dq_type]); + tty_write_message(tty, ": write failed, "); + tty_write_message(tty, quotatypes[dquot->dq_type]); switch (warntype) { case IHARDWARN: msg = " file limit reached.\r\n"; @@ -863,7 +865,7 @@ static void print_warning(struct dquot *dquot, const char warntype) msg = " block quota exceeded.\r\n"; break; } - tty_write_message(current->signal->tty, msg); + tty_write_message(tty, msg); out_lock: mutex_unlock(&tty_mutex); } diff --git a/fs/open.c b/fs/open.c index 89e0c237a636..3b56192816ca 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1087,6 +1087,7 @@ EXPORT_SYMBOL(sys_close); asmlinkage long sys_vhangup(void) { if (capable(CAP_SYS_TTY_CONFIG)) { + /* XXX: this needs locking */ tty_vhangup(current->signal->tty); return 0; } diff --git a/include/linux/tty.h b/include/linux/tty.h index f717f0898238..1d29999a3439 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -309,6 +309,12 @@ extern void tty_ldisc_flush(struct tty_struct *tty); extern int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +extern dev_t tty_devnum(struct tty_struct *tty); +extern void proc_clear_tty(struct task_struct *p); +extern void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); +extern void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); +extern struct tty_struct *get_current_tty(void); + extern struct mutex tty_mutex; /* n_tty.c */ @@ -335,10 +341,5 @@ extern void console_print(const char *); extern int vt_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); -static inline dev_t tty_devnum(struct tty_struct *tty) -{ - return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index; -} - #endif /* __KERNEL__ */ #endif diff --git a/kernel/acct.c b/kernel/acct.c index dc12db8600e7..ca5619039367 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -428,6 +428,7 @@ static void do_acct_process(struct file *file) u64 elapsed; u64 run_time; struct timespec uptime; + struct tty_struct *tty; /* * First check to see if there is enough free_space to continue @@ -485,12 +486,8 @@ static void do_acct_process(struct file *file) #endif mutex_lock(&tty_mutex); - /* FIXME: Whoever is responsible for current->signal locking needs - to use the same locking all over the kernel and document it */ - read_lock(&tasklist_lock); - ac.ac_tty = current->signal->tty ? - old_encode_dev(tty_devnum(current->signal->tty)) : 0; - read_unlock(&tasklist_lock); + tty = get_current_tty(); + ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0; mutex_unlock(&tty_mutex); spin_lock_irq(¤t->sighand->siglock); diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 40722e26de98..b6cb802fbcd1 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -826,10 +826,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts context->return_code); mutex_lock(&tty_mutex); + read_lock(&tasklist_lock); if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name) tty = tsk->signal->tty->name; else tty = "(none)"; + read_unlock(&tasklist_lock); audit_log_format(ab, " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" " ppid=%d pid=%d auid=%u uid=%u gid=%u" diff --git a/kernel/exit.c b/kernel/exit.c index 4e3f919edc48..fa235779b6a3 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -384,9 +384,7 @@ void daemonize(const char *name, ...) exit_mm(current); set_special_pids(1, 1); - mutex_lock(&tty_mutex); - current->signal->tty = NULL; - mutex_unlock(&tty_mutex); + proc_clear_tty(current); /* Block and flush all signals */ sigfillset(&blocked); diff --git a/kernel/sys.c b/kernel/sys.c index a0c1a29a507f..1ac2d1c5d84e 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1484,7 +1484,6 @@ asmlinkage long sys_setsid(void) pid_t session; int err = -EPERM; - mutex_lock(&tty_mutex); write_lock_irq(&tasklist_lock); /* Fail if I am already a session leader */ @@ -1504,12 +1503,15 @@ asmlinkage long sys_setsid(void) group_leader->signal->leader = 1; __set_special_pids(session, session); + + spin_lock(&group_leader->sighand->siglock); group_leader->signal->tty = NULL; group_leader->signal->tty_old_pgrp = 0; + spin_unlock(&group_leader->sighand->siglock); + err = process_group(group_leader); out: write_unlock_irq(&tasklist_lock); - mutex_unlock(&tty_mutex); return err; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 44e9cd470543..f5df8c70a9b5 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1695,9 +1695,10 @@ static inline void flush_unauthorized_files(struct files_struct * files) struct tty_struct *tty; struct fdtable *fdt; long j = -1; + int drop_tty = 0; mutex_lock(&tty_mutex); - tty = current->signal->tty; + tty = get_current_tty(); if (tty) { file_list_lock(); file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list); @@ -1710,12 +1711,14 @@ static inline void flush_unauthorized_files(struct files_struct * files) struct inode *inode = file->f_dentry->d_inode; if (inode_has_perm(current, inode, FILE__READ | FILE__WRITE, NULL)) { - /* Reset controlling tty. */ - current->signal->tty = NULL; - current->signal->tty_old_pgrp = 0; + drop_tty = 1; } } file_list_unlock(); + + /* Reset controlling tty. */ + if (drop_tty) + proc_set_tty(current, NULL); } mutex_unlock(&tty_mutex); -- cgit v1.2.3 From ae424ae4b5bcd820ad6ee6f0b986c4e14ed4d6cf Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 8 Dec 2006 02:36:08 -0800 Subject: [PATCH] make set_special_pids() static Make set_special_pids() static, the only caller is daemonize(). Signed-off-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 - kernel/exit.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index dede82c63445..5e8a0ba61749 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1240,7 +1240,6 @@ extern struct mm_struct init_mm; #define find_task_by_pid(nr) find_task_by_pid_type(PIDTYPE_PID, nr) extern struct task_struct *find_task_by_pid_type(int type, int pid); -extern void set_special_pids(pid_t session, pid_t pgrp); extern void __set_special_pids(pid_t session, pid_t pgrp); /* per-UID process charging. */ diff --git a/kernel/exit.c b/kernel/exit.c index fa235779b6a3..fa0495e167e9 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -314,7 +314,7 @@ void __set_special_pids(pid_t session, pid_t pgrp) } } -void set_special_pids(pid_t session, pid_t pgrp) +static void set_special_pids(pid_t session, pid_t pgrp) { write_lock_irq(&tasklist_lock); __set_special_pids(session, pgrp); -- cgit v1.2.3 From 0a0fc9601dd1024ec7171993bf075a789246e1ed Mon Sep 17 00:00:00 2001 From: Thomas Maier Date: Fri, 8 Dec 2006 02:36:11 -0800 Subject: [PATCH] pktcdvd: bio write congestion using congestion_wait() This adds a bio write queue congestion control to the pktcdvd driver with fixed on/off marks. It prevents that the driver consumes a unlimited amount of write requests. [akpm@osdl.org: sync with congestion_wait() renaming] Signed-off-by: Thomas Maier Cc: Peter Osterlund Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 32 ++++++++++++++++++++++++++++++++ include/linux/pktcdvd.h | 9 +++++++++ 2 files changed, 41 insertions(+) (limited to 'include/linux') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 7e7b892f621a..91fbe7fd6d0b 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -84,6 +84,8 @@ static struct pktcdvd_device *pkt_devs[MAX_WRITERS]; static struct proc_dir_entry *pkt_proc; static int pktdev_major; +static int write_congestion_on = PKT_WRITE_CONGESTION_ON; +static int write_congestion_off = PKT_WRITE_CONGESTION_OFF; static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */ static mempool_t *psd_pool; @@ -894,6 +896,7 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) sector_t zone = 0; /* Suppress gcc warning */ struct pkt_rb_node *node, *first_node; struct rb_node *n; + int wakeup; VPRINTK("handle_queue\n"); @@ -966,7 +969,13 @@ try_next_bio: pkt->write_size += bio->bi_size / CD_FRAMESIZE; spin_unlock(&pkt->lock); } + /* check write congestion marks, and if bio_queue_size is + below, wake up any waiters */ + wakeup = (pd->write_congestion_on > 0 + && pd->bio_queue_size <= pd->write_congestion_off); spin_unlock(&pd->lock); + if (wakeup) + blk_clear_queue_congested(pd->disk->queue, WRITE); pkt->sleep_time = max(PACKET_WAIT_TIME, 1); pkt_set_state(pkt, PACKET_WAITING_STATE); @@ -2179,6 +2188,23 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio) } spin_unlock(&pd->cdrw.active_list_lock); + /* + * Test if there is enough room left in the bio work queue + * (queue size >= congestion on mark). + * If not, wait till the work queue size is below the congestion off mark. + */ + spin_lock(&pd->lock); + if (pd->write_congestion_on > 0 + && pd->bio_queue_size >= pd->write_congestion_on) { + blk_set_queue_congested(q, WRITE); + do { + spin_unlock(&pd->lock); + congestion_wait(WRITE, HZ); + spin_lock(&pd->lock); + } while(pd->bio_queue_size > pd->write_congestion_off); + } + spin_unlock(&pd->lock); + /* * No matching packet found. Store the bio in the work queue. */ @@ -2298,6 +2324,9 @@ static int pkt_seq_show(struct seq_file *m, void *p) seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", states[0], states[1], states[2], states[3], states[4], states[5]); + seq_printf(m, "\twrite congestion marks:\toff=%d on=%d\n", + pd->write_congestion_off, + pd->write_congestion_on); return 0; } @@ -2474,6 +2503,9 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) init_waitqueue_head(&pd->wqueue); pd->bio_queue = RB_ROOT; + pd->write_congestion_on = write_congestion_on; + pd->write_congestion_off = write_congestion_off; + disk = alloc_disk(1); if (!disk) goto out_mem; diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h index 8a94c717c266..9b1a185fb1e5 100644 --- a/include/linux/pktcdvd.h +++ b/include/linux/pktcdvd.h @@ -112,6 +112,12 @@ struct pkt_ctrl_command { #include #include + +/* default bio write queue congestion marks */ +#define PKT_WRITE_CONGESTION_ON 10000 +#define PKT_WRITE_CONGESTION_OFF 9000 + + struct packet_settings { __u32 size; /* packet size in (512 byte) sectors */ @@ -271,6 +277,9 @@ struct pktcdvd_device struct packet_iosched iosched; struct gendisk *disk; + + int write_congestion_off; + int write_congestion_on; }; #endif /* __KERNEL__ */ -- cgit v1.2.3 From 32694850a91bd4fedcdd4a46292f870588be81d1 Mon Sep 17 00:00:00 2001 From: Thomas Maier Date: Fri, 8 Dec 2006 02:36:12 -0800 Subject: [PATCH] pktcdvd: add sysfs and debugfs interface Add a sysfs and debugfs interface to the pktcdvd driver. Look into the Documentation/ABI/testing/* files in the patch for more info. Signed-off-by: Thomas Maier Signed-off-by: Peter Osterlund Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/testing/debugfs-pktcdvd | 20 ++ Documentation/ABI/testing/sysfs-class-pktcdvd | 72 +++++ Documentation/cdrom/packet-writing.txt | 35 ++ drivers/block/pktcdvd.c | 443 +++++++++++++++++++++++++- include/linux/pktcdvd.h | 18 +- 5 files changed, 583 insertions(+), 5 deletions(-) create mode 100644 Documentation/ABI/testing/debugfs-pktcdvd create mode 100644 Documentation/ABI/testing/sysfs-class-pktcdvd (limited to 'include/linux') diff --git a/Documentation/ABI/testing/debugfs-pktcdvd b/Documentation/ABI/testing/debugfs-pktcdvd new file mode 100644 index 000000000000..03dbd883cc41 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-pktcdvd @@ -0,0 +1,20 @@ +What: /debug/pktcdvd/pktcdvd[0-7] +Date: Oct. 2006 +KernelVersion: 2.6.19 +Contact: Thomas Maier +Description: + +debugfs interface +----------------- + +The pktcdvd module (packet writing driver) creates +these files in debugfs: + +/debug/pktcdvd/pktcdvd[0-7]/ + info (0444) Lots of human readable driver + statistics and infos. Multiple lines! + +Example: +------- + +cat /debug/pktcdvd/pktcdvd0/info diff --git a/Documentation/ABI/testing/sysfs-class-pktcdvd b/Documentation/ABI/testing/sysfs-class-pktcdvd new file mode 100644 index 000000000000..c4c55edc9a5c --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-pktcdvd @@ -0,0 +1,72 @@ +What: /sys/class/pktcdvd/ +Date: Oct. 2006 +KernelVersion: 2.6.19 +Contact: Thomas Maier +Description: + +sysfs interface +--------------- + +The pktcdvd module (packet writing driver) creates +these files in the sysfs: +( is in format major:minor ) + +/sys/class/pktcdvd/ + add (0200) Write a block device id (major:minor) + to create a new pktcdvd device and map + it to the block device. + + remove (0200) Write the pktcdvd device id (major:minor) + to it to remove the pktcdvd device. + + device_map (0444) Shows the device mapping in format: + pktcdvd[0-7] + +/sys/class/pktcdvd/pktcdvd[0-7]/ + dev (0444) Device id + uevent (0200) To send an uevent. + +/sys/class/pktcdvd/pktcdvd[0-7]/stat/ + packets_started (0444) Number of started packets. + packets_finished (0444) Number of finished packets. + + kb_written (0444) kBytes written. + kb_read (0444) kBytes read. + kb_read_gather (0444) kBytes read to fill write packets. + + reset (0200) Write any value to it to reset + pktcdvd device statistic values, like + bytes read/written. + +/sys/class/pktcdvd/pktcdvd[0-7]/write_queue/ + size (0444) Contains the size of the bio write + queue. + + congestion_off (0644) If bio write queue size is below + this mark, accept new bio requests + from the block layer. + + congestion_on (0644) If bio write queue size is higher + as this mark, do no longer accept + bio write requests from the block + layer and wait till the pktcdvd + device has processed enough bio's + so that bio write queue size is + below congestion off mark. + A value of <= 0 disables congestion + control. + + +Example: +-------- +To use the pktcdvd sysfs interface directly, you can do: + +# create a new pktcdvd device mapped to /dev/hdc +echo "22:0" >/sys/class/pktcdvd/add +cat /sys/class/pktcdvd/device_map +# assuming device pktcdvd0 was created, look at stat's +cat /sys/class/pktcdvd/pktcdvd0/stat/kb_written +# print the device id of the mapped block device +fgrep pktcdvd0 /sys/class/pktcdvd/device_map +# remove device, using pktcdvd0 device id 253:0 +echo "253:0" >/sys/class/pktcdvd/remove diff --git a/Documentation/cdrom/packet-writing.txt b/Documentation/cdrom/packet-writing.txt index 3d44c561fe6d..7715d2247c4d 100644 --- a/Documentation/cdrom/packet-writing.txt +++ b/Documentation/cdrom/packet-writing.txt @@ -90,6 +90,41 @@ Notes to create an ext2 filesystem on the disc. +Using the pktcdvd sysfs interface +--------------------------------- + +Since Linux 2.6.19, the pktcdvd module has a sysfs interface +and can be controlled by it. For example the "pktcdvd" tool uses +this interface. (see http://people.freenet.de/BalaGi#pktcdvd ) + +"pktcdvd" works similar to "pktsetup", e.g.: + + # pktcdvd -a dev_name /dev/hdc + # mkudffs /dev/pktcdvd/dev_name + # mount -t udf -o rw,noatime /dev/pktcdvd/dev_name /dvdram + # cp files /dvdram + # umount /dvdram + # pktcdvd -r dev_name + + +For a description of the sysfs interface look into the file: + + Documentation/ABI/testing/sysfs-block-pktcdvd + + +Using the pktcdvd debugfs interface +----------------------------------- + +To read pktcdvd device infos in human readable form, do: + + # cat /debug/pktcdvd/pktcdvd[0-7]/info + +For a description of the debugfs interface look into the file: + + Documentation/ABI/testing/debugfs-pktcdvd + + + Links ----- diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 91fbe7fd6d0b..7c95c762950f 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -60,6 +60,8 @@ #include #include #include +#include +#include #include @@ -89,6 +91,419 @@ static int write_congestion_off = PKT_WRITE_CONGESTION_OFF; static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */ static mempool_t *psd_pool; +static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */ +static struct dentry *pkt_debugfs_root = NULL; /* /debug/pktcdvd */ + +/* forward declaration */ +static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev); +static int pkt_remove_dev(dev_t pkt_dev); +static int pkt_seq_show(struct seq_file *m, void *p); + + + +/* + * create and register a pktcdvd kernel object. + */ +static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd, + const char* name, + struct kobject* parent, + struct kobj_type* ktype) +{ + struct pktcdvd_kobj *p; + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return NULL; + kobject_set_name(&p->kobj, "%s", name); + p->kobj.parent = parent; + p->kobj.ktype = ktype; + p->pd = pd; + if (kobject_register(&p->kobj) != 0) + return NULL; + return p; +} +/* + * remove a pktcdvd kernel object. + */ +static void pkt_kobj_remove(struct pktcdvd_kobj *p) +{ + if (p) + kobject_unregister(&p->kobj); +} +/* + * default release function for pktcdvd kernel objects. + */ +static void pkt_kobj_release(struct kobject *kobj) +{ + kfree(to_pktcdvdkobj(kobj)); +} + + +/********************************************************** + * + * sysfs interface for pktcdvd + * by (C) 2006 Thomas Maier + * + **********************************************************/ + +#define DEF_ATTR(_obj,_name,_mode) \ + static struct attribute _obj = { \ + .name = _name, .owner = THIS_MODULE, .mode = _mode } + +/********************************************************** + /sys/class/pktcdvd/pktcdvd[0-7]/ + stat/reset + stat/packets_started + stat/packets_finished + stat/kb_written + stat/kb_read + stat/kb_read_gather + write_queue/size + write_queue/congestion_off + write_queue/congestion_on + **********************************************************/ + +DEF_ATTR(kobj_pkt_attr_st1, "reset", 0200); +DEF_ATTR(kobj_pkt_attr_st2, "packets_started", 0444); +DEF_ATTR(kobj_pkt_attr_st3, "packets_finished", 0444); +DEF_ATTR(kobj_pkt_attr_st4, "kb_written", 0444); +DEF_ATTR(kobj_pkt_attr_st5, "kb_read", 0444); +DEF_ATTR(kobj_pkt_attr_st6, "kb_read_gather", 0444); + +static struct attribute *kobj_pkt_attrs_stat[] = { + &kobj_pkt_attr_st1, + &kobj_pkt_attr_st2, + &kobj_pkt_attr_st3, + &kobj_pkt_attr_st4, + &kobj_pkt_attr_st5, + &kobj_pkt_attr_st6, + NULL +}; + +DEF_ATTR(kobj_pkt_attr_wq1, "size", 0444); +DEF_ATTR(kobj_pkt_attr_wq2, "congestion_off", 0644); +DEF_ATTR(kobj_pkt_attr_wq3, "congestion_on", 0644); + +static struct attribute *kobj_pkt_attrs_wqueue[] = { + &kobj_pkt_attr_wq1, + &kobj_pkt_attr_wq2, + &kobj_pkt_attr_wq3, + NULL +}; + +/* declares a char buffer[64] _dbuf, copies data from + * _b with length _l into it and ensures that _dbuf ends + * with a \0 character. + */ +#define DECLARE_BUF_AS_STRING(_dbuf, _b, _l) \ + char _dbuf[64]; int dlen = (_l) < 0 ? 0 : (_l); \ + if (dlen >= sizeof(_dbuf)) dlen = sizeof(_dbuf)-1; \ + memcpy(_dbuf, _b, dlen); _dbuf[dlen] = 0 + +static ssize_t kobj_pkt_show(struct kobject *kobj, + struct attribute *attr, char *data) +{ + struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd; + int n = 0; + int v; + if (strcmp(attr->name, "packets_started") == 0) { + n = sprintf(data, "%lu\n", pd->stats.pkt_started); + + } else if (strcmp(attr->name, "packets_finished") == 0) { + n = sprintf(data, "%lu\n", pd->stats.pkt_ended); + + } else if (strcmp(attr->name, "kb_written") == 0) { + n = sprintf(data, "%lu\n", pd->stats.secs_w >> 1); + + } else if (strcmp(attr->name, "kb_read") == 0) { + n = sprintf(data, "%lu\n", pd->stats.secs_r >> 1); + + } else if (strcmp(attr->name, "kb_read_gather") == 0) { + n = sprintf(data, "%lu\n", pd->stats.secs_rg >> 1); + + } else if (strcmp(attr->name, "size") == 0) { + spin_lock(&pd->lock); + v = pd->bio_queue_size; + spin_unlock(&pd->lock); + n = sprintf(data, "%d\n", v); + + } else if (strcmp(attr->name, "congestion_off") == 0) { + spin_lock(&pd->lock); + v = pd->write_congestion_off; + spin_unlock(&pd->lock); + n = sprintf(data, "%d\n", v); + + } else if (strcmp(attr->name, "congestion_on") == 0) { + spin_lock(&pd->lock); + v = pd->write_congestion_on; + spin_unlock(&pd->lock); + n = sprintf(data, "%d\n", v); + } + return n; +} + +static void init_write_congestion_marks(int* lo, int* hi) +{ + if (*hi > 0) { + *hi = max(*hi, 500); + *hi = min(*hi, 1000000); + if (*lo <= 0) + *lo = *hi - 100; + else { + *lo = min(*lo, *hi - 100); + *lo = max(*lo, 100); + } + } else { + *hi = -1; + *lo = -1; + } +} + +static ssize_t kobj_pkt_store(struct kobject *kobj, + struct attribute *attr, + const char *data, size_t len) +{ + struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd; + int val; + DECLARE_BUF_AS_STRING(dbuf, data, len); /* ensure sscanf scans a string */ + + if (strcmp(attr->name, "reset") == 0 && dlen > 0) { + pd->stats.pkt_started = 0; + pd->stats.pkt_ended = 0; + pd->stats.secs_w = 0; + pd->stats.secs_rg = 0; + pd->stats.secs_r = 0; + + } else if (strcmp(attr->name, "congestion_off") == 0 + && sscanf(dbuf, "%d", &val) == 1) { + spin_lock(&pd->lock); + pd->write_congestion_off = val; + init_write_congestion_marks(&pd->write_congestion_off, + &pd->write_congestion_on); + spin_unlock(&pd->lock); + + } else if (strcmp(attr->name, "congestion_on") == 0 + && sscanf(dbuf, "%d", &val) == 1) { + spin_lock(&pd->lock); + pd->write_congestion_on = val; + init_write_congestion_marks(&pd->write_congestion_off, + &pd->write_congestion_on); + spin_unlock(&pd->lock); + } + return len; +} + +static struct sysfs_ops kobj_pkt_ops = { + .show = kobj_pkt_show, + .store = kobj_pkt_store +}; +static struct kobj_type kobj_pkt_type_stat = { + .release = pkt_kobj_release, + .sysfs_ops = &kobj_pkt_ops, + .default_attrs = kobj_pkt_attrs_stat +}; +static struct kobj_type kobj_pkt_type_wqueue = { + .release = pkt_kobj_release, + .sysfs_ops = &kobj_pkt_ops, + .default_attrs = kobj_pkt_attrs_wqueue +}; + +static void pkt_sysfs_dev_new(struct pktcdvd_device *pd) +{ + if (class_pktcdvd) { + pd->clsdev = class_device_create(class_pktcdvd, + NULL, pd->pkt_dev, + NULL, "%s", pd->name); + if (IS_ERR(pd->clsdev)) + pd->clsdev = NULL; + } + if (pd->clsdev) { + pd->kobj_stat = pkt_kobj_create(pd, "stat", + &pd->clsdev->kobj, + &kobj_pkt_type_stat); + pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue", + &pd->clsdev->kobj, + &kobj_pkt_type_wqueue); + } +} + +static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd) +{ + pkt_kobj_remove(pd->kobj_stat); + pkt_kobj_remove(pd->kobj_wqueue); + if (class_pktcdvd) + class_device_destroy(class_pktcdvd, pd->pkt_dev); +} + + +/******************************************************************** + /sys/class/pktcdvd/ + add map block device + remove unmap packet dev + device_map show mappings + *******************************************************************/ + +static void class_pktcdvd_release(struct class *cls) +{ + kfree(cls); +} +static ssize_t class_pktcdvd_show_map(struct class *c, char *data) +{ + int n = 0; + int idx; + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + for (idx = 0; idx < MAX_WRITERS; idx++) { + struct pktcdvd_device *pd = pkt_devs[idx]; + if (!pd) + continue; + n += sprintf(data+n, "%s %u:%u %u:%u\n", + pd->name, + MAJOR(pd->pkt_dev), MINOR(pd->pkt_dev), + MAJOR(pd->bdev->bd_dev), + MINOR(pd->bdev->bd_dev)); + } + mutex_unlock(&ctl_mutex); + return n; +} + +static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf, + size_t count) +{ + unsigned int major, minor; + DECLARE_BUF_AS_STRING(dbuf, buf, count); + if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) { + pkt_setup_dev(MKDEV(major, minor), NULL); + return count; + } + return -EINVAL; +} + +static ssize_t class_pktcdvd_store_remove(struct class *c, const char *buf, + size_t count) +{ + unsigned int major, minor; + DECLARE_BUF_AS_STRING(dbuf, buf, count); + if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) { + pkt_remove_dev(MKDEV(major, minor)); + return count; + } + return -EINVAL; +} + +static struct class_attribute class_pktcdvd_attrs[] = { + __ATTR(add, 0200, NULL, class_pktcdvd_store_add), + __ATTR(remove, 0200, NULL, class_pktcdvd_store_remove), + __ATTR(device_map, 0444, class_pktcdvd_show_map, NULL), + __ATTR_NULL +}; + + +static int pkt_sysfs_init(void) +{ + int ret = 0; + + /* + * create control files in sysfs + * /sys/class/pktcdvd/... + */ + class_pktcdvd = kzalloc(sizeof(*class_pktcdvd), GFP_KERNEL); + if (!class_pktcdvd) + return -ENOMEM; + class_pktcdvd->name = DRIVER_NAME; + class_pktcdvd->owner = THIS_MODULE; + class_pktcdvd->class_release = class_pktcdvd_release; + class_pktcdvd->class_attrs = class_pktcdvd_attrs; + ret = class_register(class_pktcdvd); + if (ret) { + kfree(class_pktcdvd); + class_pktcdvd = NULL; + printk(DRIVER_NAME": failed to create class pktcdvd\n"); + return ret; + } + return 0; +} + +static void pkt_sysfs_cleanup(void) +{ + if (class_pktcdvd) + class_destroy(class_pktcdvd); + class_pktcdvd = NULL; +} + +/******************************************************************** + entries in debugfs + + /debugfs/pktcdvd[0-7]/ + info + + *******************************************************************/ + +static int pkt_debugfs_seq_show(struct seq_file *m, void *p) +{ + return pkt_seq_show(m, p); +} + +static int pkt_debugfs_fops_open(struct inode *inode, struct file *file) +{ + return single_open(file, pkt_debugfs_seq_show, inode->i_private); +} + +static struct file_operations debug_fops = { + .open = pkt_debugfs_fops_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static void pkt_debugfs_dev_new(struct pktcdvd_device *pd) +{ + if (!pkt_debugfs_root) + return; + pd->dfs_f_info = NULL; + pd->dfs_d_root = debugfs_create_dir(pd->name, pkt_debugfs_root); + if (IS_ERR(pd->dfs_d_root)) { + pd->dfs_d_root = NULL; + return; + } + pd->dfs_f_info = debugfs_create_file("info", S_IRUGO, + pd->dfs_d_root, pd, &debug_fops); + if (IS_ERR(pd->dfs_f_info)) { + pd->dfs_f_info = NULL; + return; + } +} + +static void pkt_debugfs_dev_remove(struct pktcdvd_device *pd) +{ + if (!pkt_debugfs_root) + return; + if (pd->dfs_f_info) + debugfs_remove(pd->dfs_f_info); + pd->dfs_f_info = NULL; + if (pd->dfs_d_root) + debugfs_remove(pd->dfs_d_root); + pd->dfs_d_root = NULL; +} + +static void pkt_debugfs_init(void) +{ + pkt_debugfs_root = debugfs_create_dir(DRIVER_NAME, NULL); + if (IS_ERR(pkt_debugfs_root)) { + pkt_debugfs_root = NULL; + return; + } +} + +static void pkt_debugfs_cleanup(void) +{ + if (!pkt_debugfs_root) + return; + debugfs_remove(pkt_debugfs_root); + pkt_debugfs_root = NULL; +} + +/* ----------------------------------------------------------*/ + static void pkt_bio_finished(struct pktcdvd_device *pd) { @@ -2527,6 +2942,9 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) add_disk(disk); + pkt_sysfs_dev_new(pd); + pkt_debugfs_dev_new(pd); + pkt_devs[idx] = pd; if (pkt_dev) *pkt_dev = pd->pkt_dev; @@ -2577,6 +2995,11 @@ static int pkt_remove_dev(dev_t pkt_dev) if (!IS_ERR(pd->cdrw.thread)) kthread_stop(pd->cdrw.thread); + pkt_devs[idx] = NULL; + + pkt_debugfs_dev_remove(pd); + pkt_sysfs_dev_remove(pd); + blkdev_put(pd->bdev); remove_proc_entry(pd->name, pkt_proc); @@ -2586,7 +3009,6 @@ static int pkt_remove_dev(dev_t pkt_dev) blk_cleanup_queue(pd->disk->queue); put_disk(pd->disk); - pkt_devs[idx] = NULL; mempool_destroy(pd->rb_pool); kfree(pd); @@ -2670,6 +3092,8 @@ static int __init pkt_init(void) { int ret; + mutex_init(&ctl_mutex); + psd_pool = mempool_create_kmalloc_pool(PSD_POOL_SIZE, sizeof(struct packet_stacked_data)); if (!psd_pool) @@ -2683,18 +3107,25 @@ static int __init pkt_init(void) if (!pktdev_major) pktdev_major = ret; + ret = pkt_sysfs_init(); + if (ret) + goto out; + + pkt_debugfs_init(); + ret = misc_register(&pkt_misc); if (ret) { printk(DRIVER_NAME": Unable to register misc device\n"); - goto out; + goto out_misc; } - mutex_init(&ctl_mutex); - pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver); return 0; +out_misc: + pkt_debugfs_cleanup(); + pkt_sysfs_cleanup(); out: unregister_blkdev(pktdev_major, DRIVER_NAME); out2: @@ -2706,6 +3137,10 @@ static void __exit pkt_exit(void) { remove_proc_entry(DRIVER_NAME, proc_root_driver); misc_deregister(&pkt_misc); + + pkt_debugfs_cleanup(); + pkt_sysfs_cleanup(); + unregister_blkdev(pktdev_major, DRIVER_NAME); mempool_destroy(psd_pool); } diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h index 9b1a185fb1e5..5ea4f05683f6 100644 --- a/include/linux/pktcdvd.h +++ b/include/linux/pktcdvd.h @@ -111,7 +111,8 @@ struct pkt_ctrl_command { #include #include #include - +#include +#include /* default bio write queue congestion marks */ #define PKT_WRITE_CONGESTION_ON 10000 @@ -247,6 +248,14 @@ struct packet_stacked_data }; #define PSD_POOL_SIZE 64 +struct pktcdvd_kobj +{ + struct kobject kobj; + struct pktcdvd_device *pd; +}; +#define to_pktcdvdkobj(_k) \ + ((struct pktcdvd_kobj*)container_of(_k,struct pktcdvd_kobj,kobj)) + struct pktcdvd_device { struct block_device *bdev; /* dev attached */ @@ -280,6 +289,13 @@ struct pktcdvd_device int write_congestion_off; int write_congestion_on; + + struct class_device *clsdev; /* sysfs pktcdvd[0-7] class dev */ + struct pktcdvd_kobj *kobj_stat; /* sysfs pktcdvd[0-7]/stat/ */ + struct pktcdvd_kobj *kobj_wqueue; /* sysfs pktcdvd[0-7]/write_queue/ */ + + struct dentry *dfs_d_root; /* debugfs: devname directory */ + struct dentry *dfs_f_info; /* debugfs: info file */ }; #endif /* __KERNEL__ */ -- cgit v1.2.3 From 2e7b651df113c8a463853e4169951c52c39f9d19 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 8 Dec 2006 02:36:13 -0800 Subject: [PATCH] remove the old bd_mutex lockdep annotation Remove the old complex and crufty bd_mutex annotation. Signed-off-by: Peter Zijlstra Cc: Neil Brown Cc: Ingo Molnar Cc: Arjan van de Ven Cc: Jason Baron Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- block/ioctl.c | 4 +- drivers/md/md.c | 6 +- fs/block_dev.c | 180 ++++++++++++++++------------------------------------- include/linux/fs.h | 17 ----- 4 files changed, 60 insertions(+), 147 deletions(-) (limited to 'include/linux') diff --git a/block/ioctl.c b/block/ioctl.c index 58aab630dfc1..9fddb99c3efb 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -72,7 +72,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user bdevp = bdget_disk(disk, part); if (!bdevp) return -ENOMEM; - mutex_lock_nested(&bdevp->bd_mutex, BD_MUTEX_PARTITION); + mutex_lock(&bdevp->bd_mutex); if (bdevp->bd_openers) { mutex_unlock(&bdevp->bd_mutex); bdput(bdevp); @@ -82,7 +82,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user fsync_bdev(bdevp); invalidate_bdev(bdevp, 0); - mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_WHOLE); + mutex_lock(&bdev->bd_mutex); delete_partition(disk, part); mutex_unlock(&bdev->bd_mutex); mutex_unlock(&bdevp->bd_mutex); diff --git a/drivers/md/md.c b/drivers/md/md.c index 6c4345bde07e..d2bcb410e3ab 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1413,7 +1413,7 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev) struct block_device *bdev; char b[BDEVNAME_SIZE]; - bdev = open_partition_by_devnum(dev, FMODE_READ|FMODE_WRITE); + bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); if (IS_ERR(bdev)) { printk(KERN_ERR "md: could not open %s.\n", __bdevname(dev, b)); @@ -1423,7 +1423,7 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev) if (err) { printk(KERN_ERR "md: could not bd_claim %s.\n", bdevname(bdev, b)); - blkdev_put_partition(bdev); + blkdev_put(bdev); return err; } rdev->bdev = bdev; @@ -1437,7 +1437,7 @@ static void unlock_rdev(mdk_rdev_t *rdev) if (!bdev) MD_BUG(); bd_release(bdev); - blkdev_put_partition(bdev); + blkdev_put(bdev); } void md_autodetect_dev(dev_t dev); diff --git a/fs/block_dev.c b/fs/block_dev.c index 13816b4d76f6..36c38f48a4ed 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -762,7 +762,7 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder, if (!bo) return -ENOMEM; - mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); + mutex_lock(&bdev->bd_mutex); res = bd_claim(bdev, holder); if (res == 0) { found = find_bd_holder(bdev, bo); @@ -796,7 +796,7 @@ static void bd_release_from_kobject(struct block_device *bdev, if (!kobj) return; - mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); + mutex_lock(&bdev->bd_mutex); bd_release(bdev); if ((bo = del_bd_holder(bdev, kobj))) free_bd_holder(bo); @@ -854,22 +854,6 @@ struct block_device *open_by_devnum(dev_t dev, unsigned mode) EXPORT_SYMBOL(open_by_devnum); -static int -blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags); - -struct block_device *open_partition_by_devnum(dev_t dev, unsigned mode) -{ - struct block_device *bdev = bdget(dev); - int err = -ENOMEM; - int flags = mode & FMODE_WRITE ? O_RDWR : O_RDONLY; - if (bdev) - err = blkdev_get_partition(bdev, mode, flags); - return err ? ERR_PTR(err) : bdev; -} - -EXPORT_SYMBOL(open_partition_by_devnum); - - /* * This routine checks whether a removable media has been changed, * and invalidates all buffer-cache-entries in that case. This @@ -916,66 +900,7 @@ void bd_set_size(struct block_device *bdev, loff_t size) } EXPORT_SYMBOL(bd_set_size); -static int __blkdev_put(struct block_device *bdev, unsigned int subclass) -{ - int ret = 0; - struct inode *bd_inode = bdev->bd_inode; - struct gendisk *disk = bdev->bd_disk; - - mutex_lock_nested(&bdev->bd_mutex, subclass); - lock_kernel(); - if (!--bdev->bd_openers) { - sync_blockdev(bdev); - kill_bdev(bdev); - } - if (bdev->bd_contains == bdev) { - if (disk->fops->release) - ret = disk->fops->release(bd_inode, NULL); - } else { - mutex_lock_nested(&bdev->bd_contains->bd_mutex, - subclass + 1); - bdev->bd_contains->bd_part_count--; - mutex_unlock(&bdev->bd_contains->bd_mutex); - } - if (!bdev->bd_openers) { - struct module *owner = disk->fops->owner; - - put_disk(disk); - module_put(owner); - - if (bdev->bd_contains != bdev) { - kobject_put(&bdev->bd_part->kobj); - bdev->bd_part = NULL; - } - bdev->bd_disk = NULL; - bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; - if (bdev != bdev->bd_contains) - __blkdev_put(bdev->bd_contains, subclass + 1); - bdev->bd_contains = NULL; - } - unlock_kernel(); - mutex_unlock(&bdev->bd_mutex); - bdput(bdev); - return ret; -} - -int blkdev_put(struct block_device *bdev) -{ - return __blkdev_put(bdev, BD_MUTEX_NORMAL); -} -EXPORT_SYMBOL(blkdev_put); - -int blkdev_put_partition(struct block_device *bdev) -{ - return __blkdev_put(bdev, BD_MUTEX_PARTITION); -} -EXPORT_SYMBOL(blkdev_put_partition); - -static int -blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags); - -static int -do_open(struct block_device *bdev, struct file *file, unsigned int subclass) +static int do_open(struct block_device *bdev, struct file *file) { struct module *owner = NULL; struct gendisk *disk; @@ -992,8 +917,7 @@ do_open(struct block_device *bdev, struct file *file, unsigned int subclass) } owner = disk->fops->owner; - mutex_lock_nested(&bdev->bd_mutex, subclass); - + mutex_lock(&bdev->bd_mutex); if (!bdev->bd_openers) { bdev->bd_disk = disk; bdev->bd_contains = bdev; @@ -1020,11 +944,11 @@ do_open(struct block_device *bdev, struct file *file, unsigned int subclass) ret = -ENOMEM; if (!whole) goto out_first; - ret = blkdev_get_whole(whole, file->f_mode, file->f_flags); + ret = blkdev_get(whole, file->f_mode, file->f_flags); if (ret) goto out_first; bdev->bd_contains = whole; - mutex_lock_nested(&whole->bd_mutex, BD_MUTEX_WHOLE); + mutex_lock(&whole->bd_mutex); whole->bd_part_count++; p = disk->part[part - 1]; bdev->bd_inode->i_data.backing_dev_info = @@ -1052,8 +976,7 @@ do_open(struct block_device *bdev, struct file *file, unsigned int subclass) if (bdev->bd_invalidated) rescan_partitions(bdev->bd_disk, bdev); } else { - mutex_lock_nested(&bdev->bd_contains->bd_mutex, - BD_MUTEX_WHOLE); + mutex_lock(&bdev->bd_contains->bd_mutex); bdev->bd_contains->bd_part_count++; mutex_unlock(&bdev->bd_contains->bd_mutex); } @@ -1067,7 +990,7 @@ out_first: bdev->bd_disk = NULL; bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; if (bdev != bdev->bd_contains) - __blkdev_put(bdev->bd_contains, BD_MUTEX_WHOLE); + blkdev_put(bdev->bd_contains); bdev->bd_contains = NULL; put_disk(disk); module_put(owner); @@ -1094,49 +1017,11 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags) fake_file.f_dentry = &fake_dentry; fake_dentry.d_inode = bdev->bd_inode; - return do_open(bdev, &fake_file, BD_MUTEX_NORMAL); + return do_open(bdev, &fake_file); } EXPORT_SYMBOL(blkdev_get); -static int -blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags) -{ - /* - * This crockload is due to bad choice of ->open() type. - * It will go away. - * For now, block device ->open() routine must _not_ - * examine anything in 'inode' argument except ->i_rdev. - */ - struct file fake_file = {}; - struct dentry fake_dentry = {}; - fake_file.f_mode = mode; - fake_file.f_flags = flags; - fake_file.f_dentry = &fake_dentry; - fake_dentry.d_inode = bdev->bd_inode; - - return do_open(bdev, &fake_file, BD_MUTEX_WHOLE); -} - -static int -blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags) -{ - /* - * This crockload is due to bad choice of ->open() type. - * It will go away. - * For now, block device ->open() routine must _not_ - * examine anything in 'inode' argument except ->i_rdev. - */ - struct file fake_file = {}; - struct dentry fake_dentry = {}; - fake_file.f_mode = mode; - fake_file.f_flags = flags; - fake_file.f_dentry = &fake_dentry; - fake_dentry.d_inode = bdev->bd_inode; - - return do_open(bdev, &fake_file, BD_MUTEX_PARTITION); -} - static int blkdev_open(struct inode * inode, struct file * filp) { struct block_device *bdev; @@ -1154,7 +1039,7 @@ static int blkdev_open(struct inode * inode, struct file * filp) if (bdev == NULL) return -ENOMEM; - res = do_open(bdev, filp, BD_MUTEX_NORMAL); + res = do_open(bdev, filp); if (res) return res; @@ -1168,6 +1053,51 @@ static int blkdev_open(struct inode * inode, struct file * filp) return res; } +int blkdev_put(struct block_device *bdev) +{ + int ret = 0; + struct inode *bd_inode = bdev->bd_inode; + struct gendisk *disk = bdev->bd_disk; + + mutex_lock(&bdev->bd_mutex); + lock_kernel(); + if (!--bdev->bd_openers) { + sync_blockdev(bdev); + kill_bdev(bdev); + } + if (bdev->bd_contains == bdev) { + if (disk->fops->release) + ret = disk->fops->release(bd_inode, NULL); + } else { + mutex_lock(&bdev->bd_contains->bd_mutex); + bdev->bd_contains->bd_part_count--; + mutex_unlock(&bdev->bd_contains->bd_mutex); + } + if (!bdev->bd_openers) { + struct module *owner = disk->fops->owner; + + put_disk(disk); + module_put(owner); + + if (bdev->bd_contains != bdev) { + kobject_put(&bdev->bd_part->kobj); + bdev->bd_part = NULL; + } + bdev->bd_disk = NULL; + bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; + if (bdev != bdev->bd_contains) { + blkdev_put(bdev->bd_contains); + } + bdev->bd_contains = NULL; + } + unlock_kernel(); + mutex_unlock(&bdev->bd_mutex); + bdput(bdev); + return ret; +} + +EXPORT_SYMBOL(blkdev_put); + static int blkdev_close(struct inode * inode, struct file * filp) { struct block_device *bdev = I_BDEV(filp->f_mapping->host); diff --git a/include/linux/fs.h b/include/linux/fs.h index 70b99fbb560b..45f2cabb8c75 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -481,21 +481,6 @@ struct block_device { unsigned long bd_private; }; -/* - * bdev->bd_mutex nesting subclasses for the lock validator: - * - * 0: normal - * 1: 'whole' - * 2: 'partition' - */ -enum bdev_bd_mutex_lock_class -{ - BD_MUTEX_NORMAL, - BD_MUTEX_WHOLE, - BD_MUTEX_PARTITION -}; - - /* * Radix-tree tags, for tagging dirty and writeback pages within the pagecache * radix trees @@ -1499,7 +1484,6 @@ extern void bd_set_size(struct block_device *, loff_t size); extern void bd_forget(struct inode *inode); extern void bdput(struct block_device *); extern struct block_device *open_by_devnum(dev_t, unsigned); -extern struct block_device *open_partition_by_devnum(dev_t, unsigned); extern const struct address_space_operations def_blk_aops; #else static inline void bd_forget(struct inode *inode) {} @@ -1517,7 +1501,6 @@ extern int blkdev_driver_ioctl(struct inode *inode, struct file *file, extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long); extern int blkdev_get(struct block_device *, mode_t, unsigned); extern int blkdev_put(struct block_device *); -extern int blkdev_put_partition(struct block_device *); extern int bd_claim(struct block_device *, void *); extern void bd_release(struct block_device *); #ifdef CONFIG_SYSFS -- cgit v1.2.3 From d63a5a74dee87883fda6b7d170244acaac5b05e8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 8 Dec 2006 02:36:17 -0800 Subject: [PATCH] lockdep: avoid lockdep warning in md md_open takes ->reconfig_mutex which causes lockdep to complain. This (normally) doesn't have deadlock potential as the possible conflict is with a reconfig_mutex in a different device. I say "normally" because if a loop were created in the array->member hierarchy a deadlock could happen. However that causes bigger problems than a deadlock and should be fixed independently. So we flag the lock in md_open as a nested lock. This requires defining mutex_lock_interruptible_nested. Cc: Ingo Molnar Acked-by: Peter Zijlstra Acked-by: Ingo Molnar Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/md.c | 2 +- include/linux/mutex.h | 2 ++ kernel/mutex.c | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index d2bcb410e3ab..3ce7a5d81d81 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4423,7 +4423,7 @@ static int md_open(struct inode *inode, struct file *file) mddev_t *mddev = inode->i_bdev->bd_disk->private_data; int err; - if ((err = mddev_lock(mddev))) + if ((err = mutex_lock_interruptible_nested(&mddev->reconfig_mutex, 1))) goto out; err = 0; diff --git a/include/linux/mutex.h b/include/linux/mutex.h index b2b91c477563..a7544afd7582 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -125,8 +125,10 @@ extern int fastcall mutex_lock_interruptible(struct mutex *lock); #ifdef CONFIG_DEBUG_LOCK_ALLOC extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass); +extern int mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass); #else # define mutex_lock_nested(lock, subclass) mutex_lock(lock) +# define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock) #endif /* diff --git a/kernel/mutex.c b/kernel/mutex.c index 8c71cf72a497..e7cbbb82765b 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -206,6 +206,15 @@ mutex_lock_nested(struct mutex *lock, unsigned int subclass) } EXPORT_SYMBOL_GPL(mutex_lock_nested); + +int __sched +mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass) +{ + might_sleep(); + return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, subclass); +} + +EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested); #endif /* -- cgit v1.2.3 From 7664c5a1da4711bb6383117f51b94c8dc8f3f1cd Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 8 Dec 2006 02:36:19 -0800 Subject: [PATCH] Generic BUG implementation This patch adds common handling for kernel BUGs, for use by architectures as they wish. The code is derived from arch/powerpc. The advantages of having common BUG handling are: - consistent BUG reporting across architectures - shared implementation of out-of-line file/line data - implement CONFIG_DEBUG_BUGVERBOSE consistently This means that in inline impact of BUG is just the illegal instruction itself, which is an improvement for i386 and x86-64. A BUG is represented in the instruction stream as an illegal instruction, which has file/line information associated with it. This extra information is stored in the __bug_table section in the ELF file. When the kernel gets an illegal instruction, it first confirms it might possibly be from a BUG (ie, in kernel mode, the right illegal instruction). It then calls report_bug(). This searches __bug_table for a matching instruction pointer, and if found, prints the corresponding file/line information. If report_bug() determines that it wasn't a BUG which caused the trap, it returns BUG_TRAP_TYPE_NONE. Some architectures (powerpc) implement WARN using the same mechanism; if the illegal instruction was the result of a WARN, then report_bug(Q) returns CONFIG_DEBUG_BUGVERBOSE; otherwise it returns BUG_TRAP_TYPE_BUG. lib/bug.c keeps a list of loaded modules which can be searched for __bug_table entries. The architecture must call module_bug_finalize()/module_bug_cleanup() from its corresponding module_finalize/cleanup functions. Unsetting CONFIG_DEBUG_BUGVERBOSE will reduce the kernel size by some amount. At the very least, filename and line information will not be recorded for each but, but architectures may decide to store no extra information per BUG at all. Unfortunately, gcc doesn't have a general way to mark an asm() as noreturn, so architectures will generally have to include an infinite loop (or similar) in the BUG code, so that gcc knows execution won't continue beyond that point. gcc does have a __builtin_trap() operator which may be useful to achieve the same effect, unfortunately it cannot be used to actually implement the BUG itself, because there's no way to get the instruction's address for use in generating the __bug_table entry. [randy.dunlap@oracle.com: Handle BUG=n, GENERIC_BUG=n to prevent build errors] [bunk@stusta.de: include/linux/bug.h must always #include Cc: Andi Kleen Cc: Hugh Dickens Cc: Michael Ellerman Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Rusty Russell Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-generic/bug.h | 16 ++++ include/asm-generic/vmlinux.lds.h | 8 ++ include/linux/bug.h | 47 +++++++++++ include/linux/module.h | 7 ++ lib/Kconfig.debug | 2 +- lib/Makefile | 2 + lib/bug.c | 163 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 include/linux/bug.h create mode 100644 lib/bug.c (limited to 'include/linux') diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h index c92ae0f166ff..47e3561638b1 100644 --- a/include/asm-generic/bug.h +++ b/include/asm-generic/bug.h @@ -4,6 +4,22 @@ #include #ifdef CONFIG_BUG + +#ifdef CONFIG_GENERIC_BUG +#ifndef __ASSEMBLY__ +struct bug_entry { + unsigned long bug_addr; +#ifdef CONFIG_DEBUG_BUGVERBOSE + const char *file; + unsigned short line; +#endif + unsigned short flags; +}; +#endif /* __ASSEMBLY__ */ + +#define BUGFLAG_WARNING (1<<0) +#endif /* CONFIG_GENERIC_BUG */ + #ifndef HAVE_ARCH_BUG #define BUG() do { \ printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \ diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 4d4c62d11059..6e9fcebbf89f 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -218,6 +218,14 @@ .stab.indexstr 0 : { *(.stab.indexstr) } \ .comment 0 : { *(.comment) } +#define BUG_TABLE \ + . = ALIGN(8); \ + __bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) { \ + __start___bug_table = .; \ + *(__bug_table) \ + __stop___bug_table = .; \ + } + #define NOTES \ .notes : { *(.note.*) } :note diff --git a/include/linux/bug.h b/include/linux/bug.h new file mode 100644 index 000000000000..42aa0a54b6f4 --- /dev/null +++ b/include/linux/bug.h @@ -0,0 +1,47 @@ +#ifndef _LINUX_BUG_H +#define _LINUX_BUG_H + +#include +#include + +enum bug_trap_type { + BUG_TRAP_TYPE_NONE = 0, + BUG_TRAP_TYPE_WARN = 1, + BUG_TRAP_TYPE_BUG = 2, +}; + +#ifdef CONFIG_GENERIC_BUG +#include + +static inline int is_warning_bug(const struct bug_entry *bug) +{ + return bug->flags & BUGFLAG_WARNING; +} + +const struct bug_entry *find_bug(unsigned long bugaddr); + +enum bug_trap_type report_bug(unsigned long bug_addr); + +int module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *, + struct module *); +void module_bug_cleanup(struct module *); + +/* These are defined by the architecture */ +int is_valid_bugaddr(unsigned long addr); + +#else /* !CONFIG_GENERIC_BUG */ + +static inline enum bug_trap_type report_bug(unsigned long bug_addr) +{ + return BUG_TRAP_TYPE_BUG; +} +static inline int module_bug_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *mod) +{ + return 0; +} +static inline void module_bug_cleanup(struct module *mod) {} + +#endif /* CONFIG_GENERIC_BUG */ +#endif /* _LINUX_BUG_H */ diff --git a/include/linux/module.h b/include/linux/module.h index d33df2408e05..10f771a49997 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -319,6 +319,13 @@ struct module unsigned int taints; /* same bits as kernel:tainted */ +#ifdef CONFIG_GENERIC_BUG + /* Support for BUG */ + struct list_head bug_list; + struct bug_entry *bug_table; + unsigned num_bugs; +#endif + #ifdef CONFIG_MODULE_UNLOAD /* Reference counts */ struct module_ref ref[NR_CPUS]; diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index b75fed737f25..ee46fb335d24 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -285,7 +285,7 @@ config DEBUG_HIGHMEM config DEBUG_BUGVERBOSE bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED depends on BUG - depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV || SUPERH + depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV || SUPERH || GENERIC_BUG default !EMBEDDED help Say Y here to make BUG() panics output the file name and line number diff --git a/lib/Makefile b/lib/Makefile index fea8f9035f07..7ab486b883a8 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -55,6 +55,8 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o obj-$(CONFIG_SWIOTLB) += swiotlb.o +lib-$(CONFIG_GENERIC_BUG) += bug.o + hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/bug.c b/lib/bug.c new file mode 100644 index 000000000000..014b582c5c4b --- /dev/null +++ b/lib/bug.c @@ -0,0 +1,163 @@ +/* + Generic support for BUG() + + This respects the following config options: + + CONFIG_BUG - emit BUG traps. Nothing happens without this. + CONFIG_GENERIC_BUG - enable this code. + CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG + + CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable + (though they're generally always on). + + CONFIG_GENERIC_BUG is set by each architecture using this code. + + To use this, your architecture must: + + 1. Set up the config options: + - Enable CONFIG_GENERIC_BUG if CONFIG_BUG + + 2. Implement BUG (and optionally BUG_ON, WARN, WARN_ON) + - Define HAVE_ARCH_BUG + - Implement BUG() to generate a faulting instruction + - NOTE: struct bug_entry does not have "file" or "line" entries + when CONFIG_DEBUG_BUGVERBOSE is not enabled, so you must generate + the values accordingly. + + 3. Implement the trap + - In the illegal instruction trap handler (typically), verify + that the fault was in kernel mode, and call report_bug() + - report_bug() will return whether it was a false alarm, a warning, + or an actual bug. + - You must implement the is_valid_bugaddr(bugaddr) callback which + returns true if the eip is a real kernel address, and it points + to the expected BUG trap instruction. + + Jeremy Fitzhardinge 2006 + */ +#include +#include +#include + +extern const struct bug_entry __start___bug_table[], __stop___bug_table[]; + +#ifdef CONFIG_MODULES +static LIST_HEAD(module_bug_list); + +static const struct bug_entry *module_find_bug(unsigned long bugaddr) +{ + struct module *mod; + + list_for_each_entry(mod, &module_bug_list, bug_list) { + const struct bug_entry *bug = mod->bug_table; + unsigned i; + + for (i = 0; i < mod->num_bugs; ++i, ++bug) + if (bugaddr == bug->bug_addr) + return bug; + } + return NULL; +} + +int module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, + struct module *mod) +{ + char *secstrings; + unsigned int i; + + mod->bug_table = NULL; + mod->num_bugs = 0; + + /* Find the __bug_table section, if present */ + secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + for (i = 1; i < hdr->e_shnum; i++) { + if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) + continue; + mod->bug_table = (void *) sechdrs[i].sh_addr; + mod->num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); + break; + } + + /* + * Strictly speaking this should have a spinlock to protect against + * traversals, but since we only traverse on BUG()s, a spinlock + * could potentially lead to deadlock and thus be counter-productive. + */ + list_add(&mod->bug_list, &module_bug_list); + + return 0; +} + +void module_bug_cleanup(struct module *mod) +{ + list_del(&mod->bug_list); +} + +#else + +static inline const struct bug_entry *module_find_bug(unsigned long bugaddr) +{ + return NULL; +} +#endif + +const struct bug_entry *find_bug(unsigned long bugaddr) +{ + const struct bug_entry *bug; + + for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) + if (bugaddr == bug->bug_addr) + return bug; + + return module_find_bug(bugaddr); +} + +enum bug_trap_type report_bug(unsigned long bugaddr) +{ + const struct bug_entry *bug; + const char *file; + unsigned line, warning; + + if (!is_valid_bugaddr(bugaddr)) + return BUG_TRAP_TYPE_NONE; + + bug = find_bug(bugaddr); + + printk(KERN_EMERG "------------[ cut here ]------------\n"); + + file = NULL; + line = 0; + warning = 0; + + if (bug) { +#ifdef CONFIG_DEBUG_BUGVERBOSE + file = bug->file; + line = bug->line; +#endif + warning = (bug->flags & BUGFLAG_WARNING) != 0; + } + + if (warning) { + /* this is a WARN_ON rather than BUG/BUG_ON */ + if (file) + printk(KERN_ERR "Badness at %s:%u\n", + file, line); + else + printk(KERN_ERR "Badness at %p " + "[verbose debug info unavailable]\n", + (void *)bugaddr); + + dump_stack(); + return BUG_TRAP_TYPE_WARN; + } + + if (file) + printk(KERN_CRIT "kernel BUG at %s:%u!\n", + file, line); + else + printk(KERN_CRIT "Kernel BUG at %p " + "[verbose debug info unavailable]\n", + (void *)bugaddr); + + return BUG_TRAP_TYPE_BUG; +} -- cgit v1.2.3 From a5cfc1ec58a07074dacb6aa8c79eff864c966d12 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 8 Dec 2006 02:36:25 -0800 Subject: [PATCH] bit reverse library This patch provides two bit reverse functions and bit reverse table. - reverse the order of bits in a u32 value u8 bitrev8(u8 x); - reverse the order of bits in a u32 value u32 bitrev32(u32 x); - byte reverse table const u8 byte_rev_table[256]; Signed-off-by: Akinobu Mita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/bitrev.h | 15 ++++++++++++++ lib/Kconfig | 3 +++ lib/Makefile | 1 + lib/bitrev.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 include/linux/bitrev.h create mode 100644 lib/bitrev.c (limited to 'include/linux') diff --git a/include/linux/bitrev.h b/include/linux/bitrev.h new file mode 100644 index 000000000000..05e540d6963a --- /dev/null +++ b/include/linux/bitrev.h @@ -0,0 +1,15 @@ +#ifndef _LINUX_BITREV_H +#define _LINUX_BITREV_H + +#include + +extern u8 const byte_rev_table[256]; + +static inline u8 bitrev8(u8 byte) +{ + return byte_rev_table[byte]; +} + +extern u32 bitrev32(u32 in); + +#endif /* _LINUX_BITREV_H */ diff --git a/lib/Kconfig b/lib/Kconfig index 734ce95a93d1..0d683559080e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -4,6 +4,9 @@ menu "Library routines" +config BITREVERSE + tristate + config CRC_CCITT tristate "CRC-CCITT functions" help diff --git a/lib/Makefile b/lib/Makefile index 7ab486b883a8..6f675c6149a7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -35,6 +35,7 @@ ifneq ($(CONFIG_HAVE_DEC_LOCK),y) lib-y += dec_and_lock.o endif +obj-$(CONFIG_BITREVERSE) += bitrev.o obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o obj-$(CONFIG_CRC16) += crc16.o obj-$(CONFIG_CRC32) += crc32.o diff --git a/lib/bitrev.c b/lib/bitrev.c new file mode 100644 index 000000000000..f4e1c49c825a --- /dev/null +++ b/lib/bitrev.c @@ -0,0 +1,54 @@ +#include +#include +#include + +const u8 byte_rev_table[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; +EXPORT_SYMBOL_GPL(byte_rev_table); + +static __always_inline u16 bitrev16(u16 x) +{ + return (bitrev8(x & 0xff) << 8) | bitrev8(x >> 8); +} + +/** + * bitrev32 - reverse the order of bits in a u32 value + * @x: value to be bit-reversed + */ +u32 bitrev32(u32 x) +{ + return (bitrev16(x & 0xffff) << 16) | bitrev16(x >> 16); +} +EXPORT_SYMBOL(bitrev32); -- cgit v1.2.3 From 906d66df18faa4aac8d898ae6920d1014694a932 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 8 Dec 2006 02:36:25 -0800 Subject: [PATCH] crc32: replace bitreverse by bitrev32 This patch replaces bitreverse() by bitrev32. The only users of bitreverse() are crc32 itself and via-velocity. Cc: Jeff Garzik Cc: Matt Domsch Signed-off-by: Akinobu Mita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/via-velocity.c | 2 +- include/linux/crc32.h | 4 ++-- lib/Kconfig | 1 + lib/crc32.c | 28 +++++----------------------- 4 files changed, 9 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 74f894795a1b..4587f23f4e4b 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -3132,7 +3132,7 @@ static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) } /* Finally, invert the result once to get the correct data */ crc = ~crc; - return bitreverse(crc) >> 16; + return bitrev32(crc) >> 16; } /** diff --git a/include/linux/crc32.h b/include/linux/crc32.h index 56c0645789a9..e20dd1f9b40a 100644 --- a/include/linux/crc32.h +++ b/include/linux/crc32.h @@ -6,10 +6,10 @@ #define _LINUX_CRC32_H #include +#include extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len); extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len); -extern u32 bitreverse(u32 in); #define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)data, length) @@ -21,7 +21,7 @@ extern u32 bitreverse(u32 in); * is in bit nr 0], thus it must be reversed before use. Except for * nics that bit swap the result internally... */ -#define ether_crc(length, data) bitreverse(crc32_le(~0, data, length)) +#define ether_crc(length, data) bitrev32(crc32_le(~0, data, length)) #define ether_crc_le(length, data) crc32_le(~0, data, length) #endif /* _LINUX_CRC32_H */ diff --git a/lib/Kconfig b/lib/Kconfig index 0d683559080e..47b172df3e31 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -26,6 +26,7 @@ config CRC16 config CRC32 tristate "CRC32 functions" default y + select BITREVERSE help This option is provided for the case where no in-kernel-tree modules require CRC32 functions, but a module built outside the diff --git a/lib/crc32.c b/lib/crc32.c index 285fd9bc61be..bfc33314c720 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -235,23 +235,8 @@ u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len) } #endif -/** - * bitreverse - reverse the order of bits in a u32 value - * @x: value to be bit-reversed - */ -u32 bitreverse(u32 x) -{ - x = (x >> 16) | (x << 16); - x = (x >> 8 & 0x00ff00ff) | (x << 8 & 0xff00ff00); - x = (x >> 4 & 0x0f0f0f0f) | (x << 4 & 0xf0f0f0f0); - x = (x >> 2 & 0x33333333) | (x << 2 & 0xcccccccc); - x = (x >> 1 & 0x55555555) | (x << 1 & 0xaaaaaaaa); - return x; -} - EXPORT_SYMBOL(crc32_le); EXPORT_SYMBOL(crc32_be); -EXPORT_SYMBOL(bitreverse); /* * A brief CRC tutorial. @@ -400,10 +385,7 @@ buf_dump(char const *prefix, unsigned char const *buf, size_t len) static void bytereverse(unsigned char *buf, size_t len) { while (len--) { - unsigned char x = *buf; - x = (x >> 4) | (x << 4); - x = (x >> 2 & 0x33) | (x << 2 & 0xcc); - x = (x >> 1 & 0x55) | (x << 1 & 0xaa); + unsigned char x = bitrev8(*buf); *buf++ = x; } } @@ -460,11 +442,11 @@ static u32 test_step(u32 init, unsigned char *buf, size_t len) /* Now swap it around for the other test */ bytereverse(buf, len + 4); - init = bitreverse(init); - crc2 = bitreverse(crc1); - if (crc1 != bitreverse(crc2)) + init = bitrev32(init); + crc2 = bitrev32(crc1); + if (crc1 != bitrev32(crc2)) printf("\nBit reversal fail: 0x%08x -> 0x%08x -> 0x%08x\n", - crc1, crc2, bitreverse(crc2)); + crc1, crc2, bitrev32(crc2)); crc1 = crc32_le(init, buf, len); if (crc1 != crc2) printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1, -- cgit v1.2.3 From 42cf11939becc717bd125d121a1a23415106a099 Mon Sep 17 00:00:00 2001 From: "Josef \"Jeff\" Sipek" Date: Fri, 8 Dec 2006 02:36:31 -0800 Subject: [PATCH] fsstack: Introduce fsstack_copy_{attr,inode}_* Introduce several fsstack_copy_* functions which allow stackable filesystems (such as eCryptfs and Unionfs) to easily copy over (currently only) inode attributes. This prevents code duplication and allows for code reuse. [akpm@osdl.org: Remove unneeded wrapper] [bunk@stusta.de: fs/stack.c should #include ] Signed-off-by: Josef "Jeff" Sipek Cc: Michael Halcrow Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/Makefile | 3 ++- fs/stack.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/linux/fs_stack.h | 31 +++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 fs/stack.c create mode 100644 include/linux/fs_stack.h (limited to 'include/linux') diff --git a/fs/Makefile b/fs/Makefile index 9a5ce9323bfd..b9ffa63f77fc 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -10,7 +10,8 @@ obj-y := open.o read_write.o file_table.o super.o \ ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \ attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ - pnode.o drop_caches.o splice.o sync.o utimes.o + pnode.o drop_caches.o splice.o sync.o utimes.o \ + stack.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o diff --git a/fs/stack.c b/fs/stack.c new file mode 100644 index 000000000000..5ddbc34535f9 --- /dev/null +++ b/fs/stack.c @@ -0,0 +1,40 @@ +#include +#include +#include + +/* does _NOT_ require i_mutex to be held. + * + * This function cannot be inlined since i_size_{read,write} is rather + * heavy-weight on 32-bit systems + */ +void fsstack_copy_inode_size(struct inode *dst, const struct inode *src) +{ + i_size_write(dst, i_size_read((struct inode *)src)); + dst->i_blocks = src->i_blocks; +} +EXPORT_SYMBOL_GPL(fsstack_copy_inode_size); + +/* copy all attributes; get_nlinks is optional way to override the i_nlink + * copying + */ +void fsstack_copy_attr_all(struct inode *dest, const struct inode *src, + int (*get_nlinks)(struct inode *)) +{ + if (!get_nlinks) + dest->i_nlink = src->i_nlink; + else + dest->i_nlink = (*get_nlinks)(dest); + + dest->i_mode = src->i_mode; + dest->i_uid = src->i_uid; + dest->i_gid = src->i_gid; + dest->i_rdev = src->i_rdev; + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + dest->i_blkbits = src->i_blkbits; + dest->i_flags = src->i_flags; + + fsstack_copy_inode_size(dest, src); +} +EXPORT_SYMBOL_GPL(fsstack_copy_attr_all); diff --git a/include/linux/fs_stack.h b/include/linux/fs_stack.h new file mode 100644 index 000000000000..bb516ceeefc9 --- /dev/null +++ b/include/linux/fs_stack.h @@ -0,0 +1,31 @@ +#ifndef _LINUX_FS_STACK_H +#define _LINUX_FS_STACK_H + +/* This file defines generic functions used primarily by stackable + * filesystems; none of these functions require i_mutex to be held. + */ + +#include + +/* externs for fs/stack.c */ +extern void fsstack_copy_attr_all(struct inode *dest, const struct inode *src, + int (*get_nlinks)(struct inode *)); + +extern void fsstack_copy_inode_size(struct inode *dst, const struct inode *src); + +/* inlines */ +static inline void fsstack_copy_attr_atime(struct inode *dest, + const struct inode *src) +{ + dest->i_atime = src->i_atime; +} + +static inline void fsstack_copy_attr_times(struct inode *dest, + const struct inode *src) +{ + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; +} + +#endif /* _LINUX_FS_STACK_H */ -- cgit v1.2.3 From fec6d055da71fb02a76f9c2c12427fa79974018b Mon Sep 17 00:00:00 2001 From: "Josef \"Jeff\" Sipek" Date: Fri, 8 Dec 2006 02:36:32 -0800 Subject: [PATCH] struct path: rename Reiserfs's struct path Rename Reiserfs's struct path to struct treepath to prevent name collision between it and struct path from fs/namei.c. Signed-off-by: Josef "Jeff" Sipek Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/bitmap.c | 2 +- fs/reiserfs/fix_node.c | 6 +++--- fs/reiserfs/inode.c | 12 ++++++------ fs/reiserfs/namei.c | 6 +++--- fs/reiserfs/stree.c | 42 ++++++++++++++++++++--------------------- fs/reiserfs/tail_conversion.c | 4 ++-- include/linux/reiserfs_fs.h | 44 +++++++++++++++++++++---------------------- 7 files changed, 58 insertions(+), 58 deletions(-) (limited to 'include/linux') diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index e3d466a228d4..b286ccb08587 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -708,7 +708,7 @@ static void oid_groups(reiserfs_blocknr_hint_t * hint) */ static int get_left_neighbor(reiserfs_blocknr_hint_t * hint) { - struct path *path; + struct treepath *path; struct buffer_head *bh; struct item_head *ih; int pos_in_item; diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c index 6d0e554daa9d..0ee35c6c9b72 100644 --- a/fs/reiserfs/fix_node.c +++ b/fs/reiserfs/fix_node.c @@ -957,7 +957,7 @@ static int get_far_parent(struct tree_balance *p_s_tb, { struct buffer_head *p_s_parent; INITIALIZE_PATH(s_path_to_neighbor_father); - struct path *p_s_path = p_s_tb->tb_path; + struct treepath *p_s_path = p_s_tb->tb_path; struct cpu_key s_lr_father_key; int n_counter, n_position = INT_MAX, @@ -1074,7 +1074,7 @@ static int get_far_parent(struct tree_balance *p_s_tb, */ static int get_parents(struct tree_balance *p_s_tb, int n_h) { - struct path *p_s_path = p_s_tb->tb_path; + struct treepath *p_s_path = p_s_tb->tb_path; int n_position, n_ret_value, n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h); @@ -1885,7 +1885,7 @@ static int check_balance(int mode, static int get_direct_parent(struct tree_balance *p_s_tb, int n_h) { struct buffer_head *p_s_bh; - struct path *p_s_path = p_s_tb->tb_path; + struct treepath *p_s_path = p_s_tb->tb_path; int n_position, n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 254239e6f9e3..f3d1c4a77979 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -207,7 +207,7 @@ static int file_capable(struct inode *inode, long block) } /*static*/ int restart_transaction(struct reiserfs_transaction_handle *th, - struct inode *inode, struct path *path) + struct inode *inode, struct treepath *path) { struct super_block *s = th->t_super; int len = th->t_blocks_allocated; @@ -570,7 +570,7 @@ static inline int _allocate_block(struct reiserfs_transaction_handle *th, long block, struct inode *inode, b_blocknr_t * allocated_block_nr, - struct path *path, int flags) + struct treepath *path, int flags) { BUG_ON(!th->t_trans_id); @@ -1107,7 +1107,7 @@ static inline ulong to_fake_used_blocks(struct inode *inode, int sd_size) // // called by read_locked_inode -static void init_inode(struct inode *inode, struct path *path) +static void init_inode(struct inode *inode, struct treepath *path) { struct buffer_head *bh; struct item_head *ih; @@ -1284,7 +1284,7 @@ static void inode2sd_v1(void *sd, struct inode *inode, loff_t size) /* NOTE, you must prepare the buffer head before sending it here, ** and then log it after the call */ -static void update_stat_data(struct path *path, struct inode *inode, +static void update_stat_data(struct treepath *path, struct inode *inode, loff_t size) { struct buffer_head *bh; @@ -1653,7 +1653,7 @@ int reiserfs_write_inode(struct inode *inode, int do_sync) containing "." and ".." entries */ static int reiserfs_new_directory(struct reiserfs_transaction_handle *th, struct inode *inode, - struct item_head *ih, struct path *path, + struct item_head *ih, struct treepath *path, struct inode *dir) { struct super_block *sb = th->t_super; @@ -1712,7 +1712,7 @@ static int reiserfs_new_directory(struct reiserfs_transaction_handle *th, containing the body of symlink */ static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct inode *inode, /* Inode of symlink */ struct item_head *ih, - struct path *path, const char *symname, + struct treepath *path, const char *symname, int item_len) { struct super_block *sb = th->t_super; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index abde1edc2235..23f5cd5bbf56 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -54,7 +54,7 @@ static int bin_search_in_dir_item(struct reiserfs_dir_entry *de, loff_t off) // comment? maybe something like set de to point to what the path points to? static inline void set_de_item_location(struct reiserfs_dir_entry *de, - struct path *path) + struct treepath *path) { de->de_bh = get_last_bh(path); de->de_ih = get_ih(path); @@ -113,7 +113,7 @@ entry position in the item /* The function is NOT SCHEDULE-SAFE! */ int search_by_entry_key(struct super_block *sb, const struct cpu_key *key, - struct path *path, struct reiserfs_dir_entry *de) + struct treepath *path, struct reiserfs_dir_entry *de) { int retval; @@ -282,7 +282,7 @@ static int linear_search_in_dir_item(struct cpu_key *key, // may return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND // FIXME: should add something like IOERROR static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen, - struct path *path_to_entry, + struct treepath *path_to_entry, struct reiserfs_dir_entry *de) { struct cpu_key key_to_search; diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 5240abe1a709..47e7027ea39f 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -244,7 +244,7 @@ static const struct reiserfs_key MAX_KEY = { of the path, and going upwards. We must check the path's validity at each step. If the key is not in the path, there is no delimiting key in the tree (buffer is first or last buffer in tree), and in this case we return a special key, either MIN_KEY or MAX_KEY. */ -static inline const struct reiserfs_key *get_lkey(const struct path +static inline const struct reiserfs_key *get_lkey(const struct treepath *p_s_chk_path, const struct super_block *p_s_sb) @@ -290,7 +290,7 @@ static inline const struct reiserfs_key *get_lkey(const struct path } /* Get delimiting key of the buffer at the path and its right neighbor. */ -inline const struct reiserfs_key *get_rkey(const struct path *p_s_chk_path, +inline const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path, const struct super_block *p_s_sb) { int n_position, n_path_offset = p_s_chk_path->path_length; @@ -337,7 +337,7 @@ inline const struct reiserfs_key *get_rkey(const struct path *p_s_chk_path, the path. These delimiting keys are stored at least one level above that buffer in the tree. If the buffer is the first or last node in the tree order then one of the delimiting keys may be absent, and in this case get_lkey and get_rkey return a special key which is MIN_KEY or MAX_KEY. */ -static inline int key_in_buffer(struct path *p_s_chk_path, /* Path which should be checked. */ +static inline int key_in_buffer(struct treepath *p_s_chk_path, /* Path which should be checked. */ const struct cpu_key *p_s_key, /* Key which should be checked. */ struct super_block *p_s_sb /* Super block pointer. */ ) @@ -374,7 +374,7 @@ inline void decrement_bcount(struct buffer_head *p_s_bh) } /* Decrement b_count field of the all buffers in the path. */ -void decrement_counters_in_path(struct path *p_s_search_path) +void decrement_counters_in_path(struct treepath *p_s_search_path) { int n_path_offset = p_s_search_path->path_length; @@ -391,7 +391,7 @@ void decrement_counters_in_path(struct path *p_s_search_path) p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; } -int reiserfs_check_path(struct path *p) +int reiserfs_check_path(struct treepath *p) { RFALSE(p->path_length != ILLEGAL_PATH_ELEMENT_OFFSET, "path not properly relsed"); @@ -403,7 +403,7 @@ int reiserfs_check_path(struct path *p) ** ** only called from fix_nodes() */ -void pathrelse_and_restore(struct super_block *s, struct path *p_s_search_path) +void pathrelse_and_restore(struct super_block *s, struct treepath *p_s_search_path) { int n_path_offset = p_s_search_path->path_length; @@ -421,7 +421,7 @@ void pathrelse_and_restore(struct super_block *s, struct path *p_s_search_path) } /* Release all buffers in the path. */ -void pathrelse(struct path *p_s_search_path) +void pathrelse(struct treepath *p_s_search_path) { int n_path_offset = p_s_search_path->path_length; @@ -602,7 +602,7 @@ static void search_by_key_reada(struct super_block *s, correctness of the bottom of the path */ /* The function is NOT SCHEDULE-SAFE! */ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* Key to search. */ - struct path *p_s_search_path, /* This structure was + struct treepath *p_s_search_path,/* This structure was allocated and initialized by the calling function. It is filled up @@ -813,7 +813,7 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* /* The function is NOT SCHEDULE-SAFE! */ int search_for_position_by_key(struct super_block *p_s_sb, /* Pointer to the super block. */ const struct cpu_key *p_cpu_key, /* Key to search (cpu variable) */ - struct path *p_s_search_path /* Filled up by this function. */ + struct treepath *p_s_search_path /* Filled up by this function. */ ) { struct item_head *p_le_ih; /* pointer to on-disk structure */ @@ -884,7 +884,7 @@ int search_for_position_by_key(struct super_block *p_s_sb, /* Pointer to the sup } /* Compare given item and item pointed to by the path. */ -int comp_items(const struct item_head *stored_ih, const struct path *p_s_path) +int comp_items(const struct item_head *stored_ih, const struct treepath *p_s_path) { struct buffer_head *p_s_bh; struct item_head *ih; @@ -911,7 +911,7 @@ int comp_items(const struct item_head *stored_ih, const struct path *p_s_path) #define block_in_use(bh) (buffer_locked(bh) || (held_by_others(bh))) // prepare for delete or cut of direct item -static inline int prepare_for_direct_item(struct path *path, +static inline int prepare_for_direct_item(struct treepath *path, struct item_head *le_ih, struct inode *inode, loff_t new_file_length, int *cut_size) @@ -952,7 +952,7 @@ static inline int prepare_for_direct_item(struct path *path, return M_CUT; /* Cut from this item. */ } -static inline int prepare_for_direntry_item(struct path *path, +static inline int prepare_for_direntry_item(struct treepath *path, struct item_head *le_ih, struct inode *inode, loff_t new_file_length, @@ -987,7 +987,7 @@ static inline int prepare_for_direntry_item(struct path *path, In case of file truncate calculate whether this item must be deleted/truncated or last unformatted node of this item will be converted to a direct item. This function returns a determination of what balance mode the calling function should employ. */ -static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *p_s_path, const struct cpu_key *p_s_item_key, int *p_n_removed, /* Number of unformatted nodes which were removed +static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct treepath *p_s_path, const struct cpu_key *p_s_item_key, int *p_n_removed, /* Number of unformatted nodes which were removed from end of the file. */ int *p_n_cut_size, unsigned long long n_new_file_length /* MAX_KEY_OFFSET in case of delete. */ ) @@ -1125,7 +1125,7 @@ static int calc_deleted_bytes_number(struct tree_balance *p_s_tb, char c_mode) static void init_tb_struct(struct reiserfs_transaction_handle *th, struct tree_balance *p_s_tb, struct super_block *p_s_sb, - struct path *p_s_path, int n_size) + struct treepath *p_s_path, int n_size) { BUG_ON(!th->t_trans_id); @@ -1176,7 +1176,7 @@ char head2type(struct item_head *ih) #endif /* Delete object item. */ -int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct path *p_s_path, /* Path to the deleted item. */ +int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path, /* Path to the deleted item. */ const struct cpu_key *p_s_item_key, /* Key to search for the deleted item. */ struct inode *p_s_inode, /* inode is here just to update i_blocks and quotas */ struct buffer_head *p_s_un_bh) @@ -1468,7 +1468,7 @@ static void unmap_buffers(struct page *page, loff_t pos) static int maybe_indirect_to_direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, - struct path *p_s_path, + struct treepath *p_s_path, const struct cpu_key *p_s_item_key, loff_t n_new_file_size, char *p_c_mode) { @@ -1503,7 +1503,7 @@ static int maybe_indirect_to_direct(struct reiserfs_transaction_handle *th, pointer being converted. Therefore we have to delete inserted direct item(s) */ static void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th, - struct inode *inode, struct path *path) + struct inode *inode, struct treepath *path) { struct cpu_key tail_key; int tail_len; @@ -1545,7 +1545,7 @@ static void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th, /* (Truncate or cut entry) or delete object item. Returns < 0 on failure */ int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th, - struct path *p_s_path, + struct treepath *p_s_path, struct cpu_key *p_s_item_key, struct inode *p_s_inode, struct page *page, loff_t n_new_file_size) @@ -1920,7 +1920,7 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p #ifdef CONFIG_REISERFS_CHECK // this makes sure, that we __append__, not overwrite or add holes -static void check_research_for_paste(struct path *path, +static void check_research_for_paste(struct treepath *path, const struct cpu_key *p_s_key) { struct item_head *found_ih = get_ih(path); @@ -1954,7 +1954,7 @@ static void check_research_for_paste(struct path *path, #endif /* config reiserfs check */ /* Paste bytes to the existing item. Returns bytes number pasted into the item. */ -int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct path *p_s_search_path, /* Path to the pasted item. */ +int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_search_path, /* Path to the pasted item. */ const struct cpu_key *p_s_key, /* Key to search for the needed item. */ struct inode *inode, /* Inode item belongs to */ const char *p_c_body, /* Pointer to the bytes to paste. */ @@ -2036,7 +2036,7 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct path } /* Insert new item into the buffer at the path. */ -int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct path *p_s_path, /* Path to the inserteded item. */ +int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path, /* Path to the inserteded item. */ const struct cpu_key *key, struct item_head *p_s_ih, /* Pointer to the item header to insert. */ struct inode *inode, const char *p_c_body) { /* Pointer to the bytes to insert. */ diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c index 36f108fc1cf5..f8121a1147e8 100644 --- a/fs/reiserfs/tail_conversion.c +++ b/fs/reiserfs/tail_conversion.c @@ -15,7 +15,7 @@ /* path points to first direct item of the file regarless of how many of them are there */ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, - struct path *path, struct buffer_head *unbh, + struct treepath *path, struct buffer_head *unbh, loff_t tail_offset) { struct super_block *sb = inode->i_sb; @@ -171,7 +171,7 @@ void reiserfs_unmap_buffer(struct buffer_head *bh) what we expect from it (number of cut bytes). But when tail remains in the unformatted node, we set mode to SKIP_BALANCING and unlock inode */ -int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, struct path *p_s_path, /* path to the indirect item. */ +int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, struct treepath *p_s_path, /* path to the indirect item. */ const struct cpu_key *p_s_item_key, /* Key to look for unformatted node pointer to be cut. */ loff_t n_new_file_size, /* New file size. */ char *p_c_mode) diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index d0e4dce33ad5..c3fc6caaad3f 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -1159,7 +1159,7 @@ znodes are the way! */ #define PATH_READA 0x1 /* do read ahead */ #define PATH_READA_BACK 0x2 /* read backwards */ -struct path { +struct treepath { int path_length; /* Length of the array above. */ int reada; struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */ @@ -1169,7 +1169,7 @@ struct path { #define pos_in_item(path) ((path)->pos_in_item) #define INITIALIZE_PATH(var) \ -struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,} +struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,} /* Get path element by path and path position. */ #define PATH_OFFSET_PELEMENT(p_s_path,n_offset) ((p_s_path)->path_elements +(n_offset)) @@ -1327,7 +1327,7 @@ struct tree_balance { int need_balance_dirty; struct super_block *tb_sb; struct reiserfs_transaction_handle *transaction_handle; - struct path *tb_path; + struct treepath *tb_path; struct buffer_head *L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */ struct buffer_head *R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path */ struct buffer_head *FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */ @@ -1793,41 +1793,41 @@ static inline void copy_key(struct reiserfs_key *to, memcpy(to, from, KEY_SIZE); } -int comp_items(const struct item_head *stored_ih, const struct path *p_s_path); -const struct reiserfs_key *get_rkey(const struct path *p_s_chk_path, +int comp_items(const struct item_head *stored_ih, const struct treepath *p_s_path); +const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path, const struct super_block *p_s_sb); int search_by_key(struct super_block *, const struct cpu_key *, - struct path *, int); + struct treepath *, int); #define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL) int search_for_position_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_cpu_key, - struct path *p_s_search_path); + struct treepath *p_s_search_path); extern void decrement_bcount(struct buffer_head *p_s_bh); -void decrement_counters_in_path(struct path *p_s_search_path); -void pathrelse(struct path *p_s_search_path); -int reiserfs_check_path(struct path *p); -void pathrelse_and_restore(struct super_block *s, struct path *p_s_search_path); +void decrement_counters_in_path(struct treepath *p_s_search_path); +void pathrelse(struct treepath *p_s_search_path); +int reiserfs_check_path(struct treepath *p); +void pathrelse_and_restore(struct super_block *s, struct treepath *p_s_search_path); int reiserfs_insert_item(struct reiserfs_transaction_handle *th, - struct path *path, + struct treepath *path, const struct cpu_key *key, struct item_head *ih, struct inode *inode, const char *body); int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, - struct path *path, + struct treepath *path, const struct cpu_key *key, struct inode *inode, const char *body, int paste_size); int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th, - struct path *path, + struct treepath *path, struct cpu_key *key, struct inode *inode, struct page *page, loff_t new_file_size); int reiserfs_delete_item(struct reiserfs_transaction_handle *th, - struct path *path, + struct treepath *path, const struct cpu_key *key, struct inode *inode, struct buffer_head *p_s_un_bh); @@ -1858,7 +1858,7 @@ void padd_item(char *item, int total_length, int length); #define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */ int restart_transaction(struct reiserfs_transaction_handle *th, - struct inode *inode, struct path *path); + struct inode *inode, struct treepath *path); void reiserfs_read_locked_inode(struct inode *inode, struct reiserfs_iget_args *args); int reiserfs_find_actor(struct inode *inode, void *p); @@ -1905,7 +1905,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr); /* namei.c */ void set_de_name_and_namelen(struct reiserfs_dir_entry *de); int search_by_entry_key(struct super_block *sb, const struct cpu_key *key, - struct path *path, struct reiserfs_dir_entry *de); + struct treepath *path, struct reiserfs_dir_entry *de); struct dentry *reiserfs_get_parent(struct dentry *); /* procfs.c */ @@ -1956,9 +1956,9 @@ extern const struct file_operations reiserfs_dir_operations; /* tail_conversion.c */ int direct2indirect(struct reiserfs_transaction_handle *, struct inode *, - struct path *, struct buffer_head *, loff_t); + struct treepath *, struct buffer_head *, loff_t); int indirect2direct(struct reiserfs_transaction_handle *, struct inode *, - struct page *, struct path *, const struct cpu_key *, + struct page *, struct treepath *, const struct cpu_key *, loff_t, char *); void reiserfs_unmap_buffer(struct buffer_head *); @@ -2045,7 +2045,7 @@ struct __reiserfs_blocknr_hint { struct inode *inode; /* inode passed to allocator, if we allocate unf. nodes */ long block; /* file offset, in blocks */ struct in_core_key key; - struct path *path; /* search path, used by allocator to deternine search_start by + struct treepath *path; /* search path, used by allocator to deternine search_start by * various ways */ struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and * bitmap blocks changes */ @@ -2101,7 +2101,7 @@ static inline int reiserfs_new_form_blocknrs(struct tree_balance *tb, static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle *th, struct inode *inode, b_blocknr_t * new_blocknrs, - struct path *path, long block) + struct treepath *path, long block) { reiserfs_blocknr_hint_t hint = { .th = th, @@ -2118,7 +2118,7 @@ static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle static inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle *th, struct inode *inode, b_blocknr_t * new_blocknrs, - struct path *path, long block) + struct treepath *path, long block) { reiserfs_blocknr_hint_t hint = { .th = th, -- cgit v1.2.3 From 346f20ff6020ffa11d40b789069079c56a444ae6 Mon Sep 17 00:00:00 2001 From: "Josef \"Jeff\" Sipek" Date: Fri, 8 Dec 2006 02:36:34 -0800 Subject: [PATCH] struct path: move struct path from fs/namei.c into include/linux Moved struct path from fs/namei.c to include/linux/namei.h. This allows many places in the VFS, as well as any stackable filesystem to easily keep track of dentry-vfsmount pairs. Signed-off-by: Josef "Jeff" Sipek Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 5 ----- include/linux/namei.h | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/namei.c b/fs/namei.c index db1bca26d88c..8c2db88bb20d 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -572,11 +572,6 @@ fail: return PTR_ERR(link); } -struct path { - struct vfsmount *mnt; - struct dentry *dentry; -}; - static inline void dput_path(struct path *path, struct nameidata *nd) { dput(path->dentry); diff --git a/include/linux/namei.h b/include/linux/namei.h index f5f19606effb..d39a5a67e979 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -29,6 +29,11 @@ struct nameidata { } intent; }; +struct path { + struct vfsmount *mnt; + struct dentry *dentry; +}; + /* * Type of the last component on LOOKUP_PARENT */ -- cgit v1.2.3 From 0f7fc9e4d03987fe29f6dd4aa67e4c56eb7ecb05 Mon Sep 17 00:00:00 2001 From: "Josef \"Jeff\" Sipek" Date: Fri, 8 Dec 2006 02:36:35 -0800 Subject: [PATCH] VFS: change struct file to use struct path This patch changes struct file to use struct path instead of having independent pointers to struct dentry and struct vfsmount, and converts all users of f_{dentry,vfsmnt} in fs/ to use f_path.{dentry,mnt}. Additionally, it adds two #define's to make the transition easier for users of the f_dentry and f_vfsmnt. Signed-off-by: Josef "Jeff" Sipek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_aout.c | 8 ++++---- fs/binfmt_elf.c | 2 +- fs/binfmt_elf_fdpic.c | 4 ++-- fs/binfmt_flat.c | 2 +- fs/binfmt_misc.c | 10 +++++----- fs/block_dev.c | 4 ++-- fs/compat.c | 12 ++++++------ fs/compat_ioctl.c | 2 +- fs/dnotify.c | 4 ++-- fs/dquot.c | 4 ++-- fs/eventpoll.c | 4 ++-- fs/exec.c | 10 +++++----- fs/fcntl.c | 2 +- fs/file_table.c | 10 +++++----- fs/inode.c | 2 +- fs/inotify_user.c | 6 +++--- fs/ioctl.c | 14 +++++++------- fs/libfs.c | 14 +++++++------- fs/locks.c | 32 ++++++++++++++++---------------- fs/namei.c | 10 +++++----- fs/open.c | 26 +++++++++++++------------- fs/pipe.c | 28 ++++++++++++++-------------- fs/read_write.c | 20 ++++++++++---------- fs/readdir.c | 2 +- fs/seq_file.c | 2 +- fs/splice.c | 18 +++++++++--------- fs/stat.c | 2 +- fs/super.c | 2 +- fs/sync.c | 4 ++-- fs/xattr.c | 8 ++++---- include/linux/fs.h | 10 ++++++---- include/linux/fsnotify.h | 2 +- 32 files changed, 141 insertions(+), 139 deletions(-) (limited to 'include/linux') diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 517e111bb7ef..813a887cd2b3 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -274,7 +274,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || - i_size_read(bprm->file->f_dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { + i_size_read(bprm->file->f_path.dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { return -ENOEXEC; } @@ -389,7 +389,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) { printk(KERN_WARNING "fd_offset is not page aligned. Please convert program: %s\n", - bprm->file->f_dentry->d_name.name); + bprm->file->f_path.dentry->d_name.name); error_time = jiffies; } @@ -469,7 +469,7 @@ static int load_aout_library(struct file *file) int retval; struct exec ex; - inode = file->f_dentry->d_inode; + inode = file->f_path.dentry->d_inode; retval = -ENOEXEC; error = kernel_read(file, 0, (char *) &ex, sizeof(ex)); @@ -506,7 +506,7 @@ static int load_aout_library(struct file *file) { printk(KERN_WARNING "N_TXTOFF is not page aligned. Please convert library: %s\n", - file->f_dentry->d_name.name); + file->f_path.dentry->d_name.name); error_time = jiffies; } down_write(¤t->mm->mmap_sem); diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index be5869d34999..c6dbb4a7ec78 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1190,7 +1190,7 @@ static int maydump(struct vm_area_struct *vma) /* Dump shared memory only if mapped from an anonymous file. */ if (vma->vm_flags & VM_SHARED) - return vma->vm_file->f_dentry->d_inode->i_nlink == 0; + return vma->vm_file->f_path.dentry->d_inode->i_nlink == 0; /* If it hasn't been written to, don't write it out */ if (!vma->anon_vma) diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index ed9a61c6beb3..9f0b7efc3df5 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -855,7 +855,7 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, dynamic_error: printk("ELF FDPIC %s with invalid DYNAMIC section (inode=%lu)\n", - what, file->f_dentry->d_inode->i_ino); + what, file->f_path.dentry->d_inode->i_ino); return -ELIBBAD; } @@ -1186,7 +1186,7 @@ static int maydump(struct vm_area_struct *vma) /* Dump shared memory only if mapped from an anonymous file. */ if (vma->vm_flags & VM_SHARED) { - if (vma->vm_file->f_dentry->d_inode->i_nlink == 0) { + if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) { kdcore("%08lx: %08lx: no (share)", vma->vm_start, vma->vm_flags); return 1; } diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index a62fd4018a20..ae8595d49856 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -429,7 +429,7 @@ static int load_flat_file(struct linux_binprm * bprm, int ret; hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ - inode = bprm->file->f_dentry->d_inode; + inode = bprm->file->f_path.dentry->d_inode; text_len = ntohl(hdr->data_start); data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start); diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 1713c48fef54..00687ea62738 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -542,7 +542,7 @@ static void kill_node(Node *e) static ssize_t bm_entry_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) { - Node *e = file->f_dentry->d_inode->i_private; + Node *e = file->f_path.dentry->d_inode->i_private; loff_t pos = *ppos; ssize_t res; char *page; @@ -576,7 +576,7 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct dentry *root; - Node *e = file->f_dentry->d_inode->i_private; + Node *e = file->f_path.dentry->d_inode->i_private; int res = parse_command(buffer, count); switch (res) { @@ -584,7 +584,7 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer, break; case 2: set_bit(Enabled, &e->flags); break; - case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root); + case 3: root = dget(file->f_path.mnt->mnt_sb->s_root); mutex_lock(&root->d_inode->i_mutex); kill_node(e); @@ -610,7 +610,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer, Node *e; struct inode *inode; struct dentry *root, *dentry; - struct super_block *sb = file->f_vfsmnt->mnt_sb; + struct super_block *sb = file->f_path.mnt->mnt_sb; int err = 0; e = create_entry(buffer, count); @@ -699,7 +699,7 @@ static ssize_t bm_status_write(struct file * file, const char __user * buffer, switch (res) { case 1: enabled = 0; break; case 2: enabled = 1; break; - case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root); + case 3: root = dget(file->f_path.mnt->mnt_sb->s_root); mutex_lock(&root->d_inode->i_mutex); while (!list_empty(&entries)) diff --git a/fs/block_dev.c b/fs/block_dev.c index f3c3a44dd8b6..197f93921847 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -190,7 +190,7 @@ static int blkdev_commit_write(struct file *file, struct page *page, unsigned fr /* * private llseek: - * for a block special file file->f_dentry->d_inode->i_size is zero + * for a block special file file->f_path.dentry->d_inode->i_size is zero * so we compute the size by hand (just as in block_read/write above) */ static loff_t block_llseek(struct file *file, loff_t offset, int origin) @@ -1013,7 +1013,7 @@ static int __blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, struct dentry fake_dentry = {}; fake_file.f_mode = mode; fake_file.f_flags = flags; - fake_file.f_dentry = &fake_dentry; + fake_file.f_path.dentry = &fake_dentry; fake_dentry.d_inode = bdev->bd_inode; return do_open(bdev, &fake_file, for_part); diff --git a/fs/compat.c b/fs/compat.c index a7e3f162fb15..b766964a625c 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -232,7 +232,7 @@ asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user file = fget(fd); if (!file) goto out; - error = vfs_statfs(file->f_dentry, &tmp); + error = vfs_statfs(file->f_path.dentry, &tmp); if (!error) error = put_compat_statfs(buf, &tmp); fput(file); @@ -303,7 +303,7 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c file = fget(fd); if (!file) goto out; - error = vfs_statfs(file->f_dentry, &tmp); + error = vfs_statfs(file->f_path.dentry, &tmp); if (!error) error = put_compat_statfs64(buf, &tmp); fput(file); @@ -365,7 +365,7 @@ static void compat_ioctl_error(struct file *filp, unsigned int fd, /* find the name of the device. */ path = (char *)__get_free_page(GFP_KERNEL); if (path) { - fn = d_path(filp->f_dentry, filp->f_vfsmnt, path, PAGE_SIZE); + fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE); if (IS_ERR(fn)) fn = "?"; } @@ -416,7 +416,7 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, case FIBMAP: case FIGETBSZ: case FIONREAD: - if (S_ISREG(filp->f_dentry->d_inode->i_mode)) + if (S_ISREG(filp->f_path.dentry->d_inode->i_mode)) break; /*FALL THROUGH*/ @@ -438,7 +438,7 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, goto found_handler; } - if (S_ISSOCK(filp->f_dentry->d_inode->i_mode) && + if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) && cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { error = siocdevprivate_ioctl(fd, cmd, arg); } else { @@ -1259,7 +1259,7 @@ out: if (iov != iovstack) kfree(iov); if ((ret + (type == READ)) > 0) { - struct dentry *dentry = file->f_dentry; + struct dentry *dentry = file->f_path.dentry; if (type == READ) fsnotify_access(dentry); else diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index bcc3caf5d820..c81c958b3e1d 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -1177,7 +1177,7 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar static int vt_check(struct file *file) { struct tty_struct *tty; - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; if (file->f_op->ioctl != tty_ioctl) return -EINVAL; diff --git a/fs/dnotify.c b/fs/dnotify.c index 1f26a2b9eee1..936409fcd939 100644 --- a/fs/dnotify.c +++ b/fs/dnotify.c @@ -42,7 +42,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id) struct dnotify_struct **prev; struct inode *inode; - inode = filp->f_dentry->d_inode; + inode = filp->f_path.dentry->d_inode; if (!S_ISDIR(inode->i_mode)) return; spin_lock(&inode->i_lock); @@ -74,7 +74,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) } if (!dir_notify_enable) return -EINVAL; - inode = filp->f_dentry->d_inode; + inode = filp->f_path.dentry->d_inode; if (!S_ISDIR(inode->i_mode)) return -ENOTDIR; dn = kmem_cache_alloc(dn_cache, GFP_KERNEL); diff --git a/fs/dquot.c b/fs/dquot.c index 89066b19124d..0952cc474d9a 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -694,9 +694,9 @@ restart: file_list_lock(); list_for_each(p, &sb->s_files) { struct file *filp = list_entry(p, struct file, f_u.fu_list); - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) { - struct dentry *dentry = dget(filp->f_dentry); + struct dentry *dentry = dget(filp->f_path.dentry); file_list_unlock(); sb->dq_op->initialize(inode, type); dput(dentry); diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 88a6f8d0b88e..3ae644e7e860 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -795,8 +795,8 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile, goto eexit_4; dentry->d_op = &eventpollfs_dentry_operations; d_add(dentry, inode); - file->f_vfsmnt = mntget(eventpoll_mnt); - file->f_dentry = dentry; + file->f_path.mnt = mntget(eventpoll_mnt); + file->f_path.dentry = dentry; file->f_mapping = inode->i_mapping; file->f_pos = 0; diff --git a/fs/exec.c b/fs/exec.c index add0e03c3ea9..60433e2254a4 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -912,7 +912,7 @@ EXPORT_SYMBOL(flush_old_exec); int prepare_binprm(struct linux_binprm *bprm) { int mode; - struct inode * inode = bprm->file->f_dentry->d_inode; + struct inode * inode = bprm->file->f_path.dentry->d_inode; int retval; mode = inode->i_mode; @@ -922,7 +922,7 @@ int prepare_binprm(struct linux_binprm *bprm) bprm->e_uid = current->euid; bprm->e_gid = current->egid; - if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) { + if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { /* Set-uid? */ if (mode & S_ISUID) { current->personality &= ~PER_CLEAR_ON_SETID; @@ -1519,10 +1519,10 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) 0600); if (IS_ERR(file)) goto fail_unlock; - inode = file->f_dentry->d_inode; + inode = file->f_path.dentry->d_inode; if (inode->i_nlink > 1) goto close_fail; /* multiple links - don't dump */ - if (!ispipe && d_unhashed(file->f_dentry)) + if (!ispipe && d_unhashed(file->f_path.dentry)) goto close_fail; /* AK: actually i see no reason to not allow this for named pipes etc., @@ -1533,7 +1533,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) goto close_fail; if (!file->f_op->write) goto close_fail; - if (!ispipe && do_truncate(file->f_dentry, 0, 0, file) != 0) + if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0) goto close_fail; retval = binfmt->core_dump(signr, regs, file); diff --git a/fs/fcntl.c b/fs/fcntl.c index 4740d35e52cd..2bdaef35da54 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -204,7 +204,7 @@ asmlinkage long sys_dup(unsigned int fildes) static int setfl(int fd, struct file * filp, unsigned long arg) { - struct inode * inode = filp->f_dentry->d_inode; + struct inode * inode = filp->f_path.dentry->d_inode; int error = 0; /* diff --git a/fs/file_table.c b/fs/file_table.c index 24f25a057d9c..4c17a18d8c10 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -152,8 +152,8 @@ EXPORT_SYMBOL(fput); */ void fastcall __fput(struct file *file) { - struct dentry *dentry = file->f_dentry; - struct vfsmount *mnt = file->f_vfsmnt; + struct dentry *dentry = file->f_path.dentry; + struct vfsmount *mnt = file->f_path.mnt; struct inode *inode = dentry->d_inode; might_sleep(); @@ -176,8 +176,8 @@ void fastcall __fput(struct file *file) put_write_access(inode); put_pid(file->f_owner.pid); file_kill(file); - file->f_dentry = NULL; - file->f_vfsmnt = NULL; + file->f_path.dentry = NULL; + file->f_path.mnt = NULL; file_free(file); dput(dentry); mntput(mnt); @@ -271,7 +271,7 @@ int fs_may_remount_ro(struct super_block *sb) file_list_lock(); list_for_each(p, &sb->s_files) { struct file *file = list_entry(p, struct file, f_u.fu_list); - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; /* File with pending delete? */ if (inode->i_nlink == 0) diff --git a/fs/inode.c b/fs/inode.c index 9ecccab7326d..d00de182ecb9 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1200,7 +1200,7 @@ EXPORT_SYMBOL(touch_atime); void file_update_time(struct file *file) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct timespec now; int sync_it = 0; diff --git a/fs/inotify_user.c b/fs/inotify_user.c index e1956e6f116c..55f6da55b7c0 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -570,9 +570,9 @@ asmlinkage long sys_inotify_init(void) dev->ih = ih; filp->f_op = &inotify_fops; - filp->f_vfsmnt = mntget(inotify_mnt); - filp->f_dentry = dget(inotify_mnt->mnt_root); - filp->f_mapping = filp->f_dentry->d_inode->i_mapping; + filp->f_path.mnt = mntget(inotify_mnt); + filp->f_path.dentry = dget(inotify_mnt->mnt_root); + filp->f_mapping = filp->f_path.dentry->d_inode->i_mapping; filp->f_mode = FMODE_READ; filp->f_flags = O_RDONLY; filp->private_data = dev; diff --git a/fs/ioctl.c b/fs/ioctl.c index 4b7660b09ac0..ff61772ceedd 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -31,7 +31,7 @@ static long do_ioctl(struct file *filp, unsigned int cmd, goto out; } else if (filp->f_op->ioctl) { lock_kernel(); - error = filp->f_op->ioctl(filp->f_dentry->d_inode, + error = filp->f_op->ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg); unlock_kernel(); } @@ -45,7 +45,7 @@ static int file_ioctl(struct file *filp, unsigned int cmd, { int error; int block; - struct inode * inode = filp->f_dentry->d_inode; + struct inode * inode = filp->f_path.dentry->d_inode; int __user *p = (int __user *)arg; switch (cmd) { @@ -137,17 +137,17 @@ int vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, unsigned lon break; case FIOQSIZE: - if (S_ISDIR(filp->f_dentry->d_inode->i_mode) || - S_ISREG(filp->f_dentry->d_inode->i_mode) || - S_ISLNK(filp->f_dentry->d_inode->i_mode)) { - loff_t res = inode_get_bytes(filp->f_dentry->d_inode); + if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode) || + S_ISREG(filp->f_path.dentry->d_inode->i_mode) || + S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) { + loff_t res = inode_get_bytes(filp->f_path.dentry->d_inode); error = copy_to_user((loff_t __user *)arg, &res, sizeof(res)) ? -EFAULT : 0; } else error = -ENOTTY; break; default: - if (S_ISREG(filp->f_dentry->d_inode->i_mode)) + if (S_ISREG(filp->f_path.dentry->d_inode->i_mode)) error = file_ioctl(filp, cmd, arg); else error = do_ioctl(filp, cmd, arg); diff --git a/fs/libfs.c b/fs/libfs.c index bd08e0e64a8c..503898d5c4a7 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -63,7 +63,7 @@ int dcache_dir_open(struct inode *inode, struct file *file) { static struct qstr cursor_name = {.len = 1, .name = "."}; - file->private_data = d_alloc(file->f_dentry, &cursor_name); + file->private_data = d_alloc(file->f_path.dentry, &cursor_name); return file->private_data ? 0 : -ENOMEM; } @@ -76,7 +76,7 @@ int dcache_dir_close(struct inode *inode, struct file *file) loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) { - mutex_lock(&file->f_dentry->d_inode->i_mutex); + mutex_lock(&file->f_path.dentry->d_inode->i_mutex); switch (origin) { case 1: offset += file->f_pos; @@ -84,7 +84,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) if (offset >= 0) break; default: - mutex_unlock(&file->f_dentry->d_inode->i_mutex); + mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); return -EINVAL; } if (offset != file->f_pos) { @@ -96,8 +96,8 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) spin_lock(&dcache_lock); list_del(&cursor->d_u.d_child); - p = file->f_dentry->d_subdirs.next; - while (n && p != &file->f_dentry->d_subdirs) { + p = file->f_path.dentry->d_subdirs.next; + while (n && p != &file->f_path.dentry->d_subdirs) { struct dentry *next; next = list_entry(p, struct dentry, d_u.d_child); if (!d_unhashed(next) && next->d_inode) @@ -108,7 +108,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) spin_unlock(&dcache_lock); } } - mutex_unlock(&file->f_dentry->d_inode->i_mutex); + mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); return offset; } @@ -126,7 +126,7 @@ static inline unsigned char dt_type(struct inode *inode) int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) { - struct dentry *dentry = filp->f_dentry; + struct dentry *dentry = filp->f_path.dentry; struct dentry *cursor = filp->private_data; struct list_head *p, *q = &cursor->d_u.d_child; ino_t ino; diff --git a/fs/locks.c b/fs/locks.c index 1cb0c57fedbd..52a81005dab4 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -321,7 +321,7 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, start = filp->f_pos; break; case SEEK_END: - start = i_size_read(filp->f_dentry->d_inode); + start = i_size_read(filp->f_path.dentry->d_inode); break; default: return -EINVAL; @@ -371,7 +371,7 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, start = filp->f_pos; break; case SEEK_END: - start = i_size_read(filp->f_dentry->d_inode); + start = i_size_read(filp->f_path.dentry->d_inode); break; default: return -EINVAL; @@ -672,7 +672,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl, struct file_lock *cfl; lock_kernel(); - for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { + for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { if (!IS_POSIX(cfl)) continue; if (posix_locks_conflict(cfl, fl)) @@ -734,7 +734,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) { struct file_lock *new_fl = NULL; struct file_lock **before; - struct inode * inode = filp->f_dentry->d_inode; + struct inode * inode = filp->f_path.dentry->d_inode; int error = 0; int found = 0; @@ -1018,7 +1018,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request */ int posix_lock_file(struct file *filp, struct file_lock *fl) { - return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, NULL); + return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, NULL); } EXPORT_SYMBOL(posix_lock_file); @@ -1033,7 +1033,7 @@ EXPORT_SYMBOL(posix_lock_file); int posix_lock_file_conf(struct file *filp, struct file_lock *fl, struct file_lock *conflock) { - return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, conflock); + return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, conflock); } EXPORT_SYMBOL(posix_lock_file_conf); @@ -1333,8 +1333,8 @@ int fcntl_getlease(struct file *filp) int type = F_UNLCK; lock_kernel(); - time_out_leases(filp->f_dentry->d_inode); - for (fl = filp->f_dentry->d_inode->i_flock; fl && IS_LEASE(fl); + time_out_leases(filp->f_path.dentry->d_inode); + for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl); fl = fl->fl_next) { if (fl->fl_file == filp) { type = fl->fl_type & ~F_INPROGRESS; @@ -1359,7 +1359,7 @@ int fcntl_getlease(struct file *filp) static int __setlease(struct file *filp, long arg, struct file_lock **flp) { struct file_lock *fl, **before, **my_before = NULL, *lease; - struct dentry *dentry = filp->f_dentry; + struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; int error, rdlease_count = 0, wrlease_count = 0; @@ -1448,7 +1448,7 @@ out: int setlease(struct file *filp, long arg, struct file_lock **lease) { - struct dentry *dentry = filp->f_dentry; + struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; int error; @@ -1482,7 +1482,7 @@ EXPORT_SYMBOL(setlease); int fcntl_setlease(unsigned int fd, struct file *filp, long arg) { struct file_lock fl, *flp = &fl; - struct dentry *dentry = filp->f_dentry; + struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; int error; @@ -1692,7 +1692,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, if (copy_from_user(&flock, l, sizeof(flock))) goto out; - inode = filp->f_dentry->d_inode; + inode = filp->f_path.dentry->d_inode; /* Don't allow mandatory locks on files that may be memory mapped * and shared. @@ -1835,7 +1835,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, if (copy_from_user(&flock, l, sizeof(flock))) goto out; - inode = filp->f_dentry->d_inode; + inode = filp->f_path.dentry->d_inode; /* Don't allow mandatory locks on files that may be memory mapped * and shared. @@ -1922,7 +1922,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner) * posix_lock_file(). Another process could be setting a lock on this * file at the same time, but we wouldn't remove that lock anyway. */ - if (!filp->f_dentry->d_inode->i_flock) + if (!filp->f_path.dentry->d_inode->i_flock) return; lock.fl_type = F_UNLCK; @@ -1951,7 +1951,7 @@ EXPORT_SYMBOL(locks_remove_posix); */ void locks_remove_flock(struct file *filp) { - struct inode * inode = filp->f_dentry->d_inode; + struct inode * inode = filp->f_path.dentry->d_inode; struct file_lock *fl; struct file_lock **before; @@ -2020,7 +2020,7 @@ static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) struct inode *inode = NULL; if (fl->fl_file != NULL) - inode = fl->fl_file->f_dentry->d_inode; + inode = fl->fl_file->f_path.dentry->d_inode; out += sprintf(out, "%d:%s ", id, pfx); if (IS_POSIX(fl)) { diff --git a/fs/namei.c b/fs/namei.c index 8c2db88bb20d..e4f108f08230 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -297,7 +297,7 @@ int vfs_permission(struct nameidata *nd, int mask) */ int file_permission(struct file *file, int mask) { - return permission(file->f_dentry->d_inode, mask, NULL); + return permission(file->f_path.dentry->d_inode, mask, NULL); } /* @@ -333,7 +333,7 @@ int get_write_access(struct inode * inode) int deny_write_access(struct file * file) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; spin_lock(&inode->i_lock); if (atomic_read(&inode->i_writecount) > 0) { @@ -368,7 +368,7 @@ void path_release_on_umount(struct nameidata *nd) */ void release_open_intent(struct nameidata *nd) { - if (nd->intent.open.file->f_dentry == NULL) + if (nd->intent.open.file->f_path.dentry == NULL) put_filp(nd->intent.open.file); else fput(nd->intent.open.file); @@ -1138,7 +1138,7 @@ static int fastcall do_path_lookup(int dfd, const char *name, if (!file) goto out_fail; - dentry = file->f_dentry; + dentry = file->f_path.dentry; retval = -ENOTDIR; if (!S_ISDIR(dentry->d_inode->i_mode)) @@ -1148,7 +1148,7 @@ static int fastcall do_path_lookup(int dfd, const char *name, if (retval) goto fput_fail; - nd->mnt = mntget(file->f_vfsmnt); + nd->mnt = mntget(file->f_path.mnt); nd->dentry = dget(dentry); fput_light(file, fput_needed); diff --git a/fs/open.c b/fs/open.c index 3b56192816ca..0d94319e8681 100644 --- a/fs/open.c +++ b/fs/open.c @@ -165,7 +165,7 @@ asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf) file = fget(fd); if (!file) goto out; - error = vfs_statfs_native(file->f_dentry, &tmp); + error = vfs_statfs_native(file->f_path.dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); @@ -186,7 +186,7 @@ asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user file = fget(fd); if (!file) goto out; - error = vfs_statfs64(file->f_dentry, &tmp); + error = vfs_statfs64(file->f_path.dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); @@ -302,7 +302,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) if (file->f_flags & O_LARGEFILE) small = 0; - dentry = file->f_dentry; + dentry = file->f_path.dentry; inode = dentry->d_inode; error = -EINVAL; if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) @@ -448,8 +448,8 @@ asmlinkage long sys_fchdir(unsigned int fd) if (!file) goto out; - dentry = file->f_dentry; - mnt = file->f_vfsmnt; + dentry = file->f_path.dentry; + mnt = file->f_path.mnt; inode = dentry->d_inode; error = -ENOTDIR; @@ -503,7 +503,7 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) if (!file) goto out; - dentry = file->f_dentry; + dentry = file->f_path.dentry; inode = dentry->d_inode; audit_inode(NULL, inode); @@ -662,7 +662,7 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) if (!file) goto out; - dentry = file->f_dentry; + dentry = file->f_path.dentry; audit_inode(NULL, dentry->d_inode); error = chown_common(dentry, user, group); fput(file); @@ -688,8 +688,8 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, } f->f_mapping = inode->i_mapping; - f->f_dentry = dentry; - f->f_vfsmnt = mnt; + f->f_path.dentry = dentry; + f->f_path.mnt = mnt; f->f_pos = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); @@ -723,8 +723,8 @@ cleanup_all: if (f->f_mode & FMODE_WRITE) put_write_access(inode); file_kill(f); - f->f_dentry = NULL; - f->f_vfsmnt = NULL; + f->f_path.dentry = NULL; + f->f_path.mnt = NULL; cleanup_file: put_filp(f); dput(dentry); @@ -822,7 +822,7 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags) /* Pick up the filp from the open intent */ filp = nd->intent.open.file; /* Has the filesystem initialised the file for us? */ - if (filp->f_dentry == NULL) + if (filp->f_path.dentry == NULL) filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL); else path_release(nd); @@ -965,7 +965,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode) put_unused_fd(fd); fd = PTR_ERR(f); } else { - fsnotify_open(f->f_dentry); + fsnotify_open(f->f_path.dentry); fd_install(fd, f); } } diff --git a/fs/pipe.c b/fs/pipe.c index ae36b89b1a37..f8b6bdcb879a 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -222,7 +222,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, unsigned long nr_segs, loff_t pos) { struct file *filp = iocb->ki_filp; - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; struct pipe_inode_info *pipe; int do_wakeup; ssize_t ret; @@ -335,7 +335,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, unsigned long nr_segs, loff_t ppos) { struct file *filp = iocb->ki_filp; - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; struct pipe_inode_info *pipe; ssize_t ret; int do_wakeup; @@ -520,7 +520,7 @@ static int pipe_ioctl(struct inode *pino, struct file *filp, unsigned int cmd, unsigned long arg) { - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; struct pipe_inode_info *pipe; int count, buf, nrbufs; @@ -548,7 +548,7 @@ static unsigned int pipe_poll(struct file *filp, poll_table *wait) { unsigned int mask; - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; struct pipe_inode_info *pipe = inode->i_pipe; int nrbufs; @@ -601,7 +601,7 @@ pipe_release(struct inode *inode, int decr, int decw) static int pipe_read_fasync(int fd, struct file *filp, int on) { - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; int retval; mutex_lock(&inode->i_mutex); @@ -618,7 +618,7 @@ pipe_read_fasync(int fd, struct file *filp, int on) static int pipe_write_fasync(int fd, struct file *filp, int on) { - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; int retval; mutex_lock(&inode->i_mutex); @@ -635,7 +635,7 @@ pipe_write_fasync(int fd, struct file *filp, int on) static int pipe_rdwr_fasync(int fd, struct file *filp, int on) { - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; struct pipe_inode_info *pipe = inode->i_pipe; int retval; @@ -914,8 +914,8 @@ struct file *create_write_pipe(void) */ dentry->d_flags &= ~DCACHE_UNHASHED; d_instantiate(dentry, inode); - f->f_vfsmnt = mntget(pipe_mnt); - f->f_dentry = dentry; + f->f_path.mnt = mntget(pipe_mnt); + f->f_path.dentry = dentry; f->f_mapping = inode->i_mapping; f->f_flags = O_WRONLY; @@ -935,8 +935,8 @@ struct file *create_write_pipe(void) void free_write_pipe(struct file *f) { - mntput(f->f_vfsmnt); - dput(f->f_dentry); + mntput(f->f_path.mnt); + dput(f->f_path.dentry); put_filp(f); } @@ -947,9 +947,9 @@ struct file *create_read_pipe(struct file *wrf) return ERR_PTR(-ENFILE); /* Grab pipe from the writer */ - f->f_vfsmnt = mntget(wrf->f_vfsmnt); - f->f_dentry = dget(wrf->f_dentry); - f->f_mapping = wrf->f_dentry->d_inode->i_mapping; + f->f_path.mnt = mntget(wrf->f_path.mnt); + f->f_path.dentry = dget(wrf->f_path.dentry); + f->f_mapping = wrf->f_path.dentry->d_inode->i_mapping; f->f_pos = 0; f->f_flags = O_RDONLY; diff --git a/fs/read_write.c b/fs/read_write.c index f792000a28e6..1d3dda4fa70c 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -64,13 +64,13 @@ loff_t remote_llseek(struct file *file, loff_t offset, int origin) lock_kernel(); switch (origin) { case 2: - offset += i_size_read(file->f_dentry->d_inode); + offset += i_size_read(file->f_path.dentry->d_inode); break; case 1: offset += file->f_pos; } retval = -EINVAL; - if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) { + if (offset>=0 && offset<=file->f_path.dentry->d_inode->i_sb->s_maxbytes) { if (offset != file->f_pos) { file->f_pos = offset; file->f_version = 0; @@ -95,7 +95,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) lock_kernel(); switch (origin) { case 2: - offset += i_size_read(file->f_dentry->d_inode); + offset += i_size_read(file->f_path.dentry->d_inode); break; case 1: offset += file->f_pos; @@ -203,7 +203,7 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) goto Einval; - inode = file->f_dentry->d_inode; + inode = file->f_path.dentry->d_inode; if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) { int retval = locks_mandatory_area( read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, @@ -273,7 +273,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) else ret = do_sync_read(file, buf, count, pos); if (ret > 0) { - fsnotify_access(file->f_dentry); + fsnotify_access(file->f_path.dentry); current->rchar += ret; } current->syscr++; @@ -331,7 +331,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ else ret = do_sync_write(file, buf, count, pos); if (ret > 0) { - fsnotify_modify(file->f_dentry); + fsnotify_modify(file->f_path.dentry); current->wchar += ret; } current->syscw++; @@ -628,9 +628,9 @@ out: kfree(iov); if ((ret + (type == READ)) > 0) { if (type == READ) - fsnotify_access(file->f_dentry); + fsnotify_access(file->f_path.dentry); else - fsnotify_modify(file->f_dentry); + fsnotify_modify(file->f_path.dentry); } return ret; } @@ -722,7 +722,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, if (!(in_file->f_mode & FMODE_READ)) goto fput_in; retval = -EINVAL; - in_inode = in_file->f_dentry->d_inode; + in_inode = in_file->f_path.dentry->d_inode; if (!in_inode) goto fput_in; if (!in_file->f_op || !in_file->f_op->sendfile) @@ -754,7 +754,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, retval = -EINVAL; if (!out_file->f_op || !out_file->f_op->sendpage) goto fput_out; - out_inode = out_file->f_dentry->d_inode; + out_inode = out_file->f_path.dentry->d_inode; retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); if (retval < 0) goto fput_out; diff --git a/fs/readdir.c b/fs/readdir.c index bff3ee58e2f8..f39f5b313252 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -21,7 +21,7 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; int res = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; diff --git a/fs/seq_file.c b/fs/seq_file.c index 10690aa401c7..0ac22af7afe5 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -269,7 +269,7 @@ EXPORT_SYMBOL(seq_lseek); /** * seq_release - free the structures associated with sequential file. * @file: file in question - * @inode: file->f_dentry->d_inode + * @inode: file->f_path.dentry->d_inode * * Frees the structures associated with sequential file; can be used * as ->f_op->release() if you don't have private data to destroy. diff --git a/fs/splice.c b/fs/splice.c index da74583a00ee..bbd0aeb3f68e 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -844,7 +844,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, ssize_t ret; int err; - err = remove_suid(out->f_dentry); + err = remove_suid(out->f_path.dentry); if (unlikely(err)) return err; @@ -890,10 +890,10 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, ssize_t ret; int err; - err = should_remove_suid(out->f_dentry); + err = should_remove_suid(out->f_path.dentry); if (unlikely(err)) { mutex_lock(&inode->i_mutex); - err = __remove_suid(out->f_dentry, err); + err = __remove_suid(out->f_path.dentry, err); mutex_unlock(&inode->i_mutex); if (err) return err; @@ -1008,7 +1008,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, * randomly drop data for eg socket -> socket splicing. Use the * piped splicing for that! */ - i_mode = in->f_dentry->d_inode->i_mode; + i_mode = in->f_path.dentry->d_inode->i_mode; if (unlikely(!S_ISREG(i_mode) && !S_ISBLK(i_mode))) return -EINVAL; @@ -1132,7 +1132,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, loff_t offset, *off; long ret; - pipe = pipe_info(in->f_dentry->d_inode); + pipe = pipe_info(in->f_path.dentry->d_inode); if (pipe) { if (off_in) return -ESPIPE; @@ -1153,7 +1153,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, return ret; } - pipe = pipe_info(out->f_dentry->d_inode); + pipe = pipe_info(out->f_path.dentry->d_inode); if (pipe) { if (off_out) return -ESPIPE; @@ -1321,7 +1321,7 @@ static long do_vmsplice(struct file *file, const struct iovec __user *iov, .ops = &user_page_pipe_buf_ops, }; - pipe = pipe_info(file->f_dentry->d_inode); + pipe = pipe_info(file->f_path.dentry->d_inode); if (!pipe) return -EBADF; if (unlikely(nr_segs > UIO_MAXIOV)) @@ -1549,8 +1549,8 @@ static int link_pipe(struct pipe_inode_info *ipipe, static long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags) { - struct pipe_inode_info *ipipe = pipe_info(in->f_dentry->d_inode); - struct pipe_inode_info *opipe = pipe_info(out->f_dentry->d_inode); + struct pipe_inode_info *ipipe = pipe_info(in->f_path.dentry->d_inode); + struct pipe_inode_info *opipe = pipe_info(out->f_path.dentry->d_inode); int ret = -EINVAL; /* diff --git a/fs/stat.c b/fs/stat.c index a0ebfc7f8a64..38a8cb2a28de 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -102,7 +102,7 @@ int vfs_fstat(unsigned int fd, struct kstat *stat) int error = -EBADF; if (f) { - error = vfs_getattr(f->f_vfsmnt, f->f_dentry, stat); + error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat); fput(f); } return error; diff --git a/fs/super.c b/fs/super.c index 84c320f6ad7e..f961e0307997 100644 --- a/fs/super.c +++ b/fs/super.c @@ -570,7 +570,7 @@ static void mark_files_ro(struct super_block *sb) file_list_lock(); list_for_each_entry(f, &sb->s_files, f_u.fu_list) { - if (S_ISREG(f->f_dentry->d_inode->i_mode) && file_count(f)) + if (S_ISREG(f->f_path.dentry->d_inode->i_mode) && file_count(f)) f->f_mode &= ~FMODE_WRITE; } file_list_unlock(); diff --git a/fs/sync.c b/fs/sync.c index 865f32be386e..d0feff61e6aa 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -94,7 +94,7 @@ long do_fsync(struct file *file, int datasync) * livelocks in fsync_buffers_list(). */ mutex_lock(&mapping->host->i_mutex); - err = file->f_op->fsync(file, file->f_dentry, datasync); + err = file->f_op->fsync(file, file->f_path.dentry, datasync); if (!ret) ret = err; mutex_unlock(&mapping->host->i_mutex); @@ -223,7 +223,7 @@ asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, if (!file) goto out; - i_mode = file->f_dentry->d_inode->i_mode; + i_mode = file->f_path.dentry->d_inode->i_mode; ret = -ESPIPE; if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) && !S_ISLNK(i_mode)) diff --git a/fs/xattr.c b/fs/xattr.c index 0901bdc2ce24..38646132ab0e 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -268,7 +268,7 @@ sys_fsetxattr(int fd, char __user *name, void __user *value, f = fget(fd); if (!f) return error; - dentry = f->f_dentry; + dentry = f->f_path.dentry; audit_inode(NULL, dentry->d_inode); error = setxattr(dentry, name, value, size, flags); fput(f); @@ -351,7 +351,7 @@ sys_fgetxattr(int fd, char __user *name, void __user *value, size_t size) f = fget(fd); if (!f) return error; - error = getxattr(f->f_dentry, name, value, size); + error = getxattr(f->f_path.dentry, name, value, size); fput(f); return error; } @@ -423,7 +423,7 @@ sys_flistxattr(int fd, char __user *list, size_t size) f = fget(fd); if (!f) return error; - error = listxattr(f->f_dentry, list, size); + error = listxattr(f->f_path.dentry, list, size); fput(f); return error; } @@ -484,7 +484,7 @@ sys_fremovexattr(int fd, char __user *name) f = fget(fd); if (!f) return error; - dentry = f->f_dentry; + dentry = f->f_path.dentry; audit_inode(NULL, dentry->d_inode); error = removexattr(dentry, name); fput(f); diff --git a/include/linux/fs.h b/include/linux/fs.h index 45f2cabb8c75..adce6e1d70c2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -269,6 +269,7 @@ extern int dir_notify_enable; #include #include #include +#include #include #include #include @@ -711,8 +712,9 @@ struct file { struct list_head fu_list; struct rcu_head fu_rcuhead; } f_u; - struct dentry *f_dentry; - struct vfsmount *f_vfsmnt; + struct path f_path; +#define f_dentry f_path.dentry +#define f_vfsmnt f_path.mnt const struct file_operations *f_op; atomic_t f_count; unsigned int f_flags; @@ -1224,7 +1226,7 @@ extern void touch_atime(struct vfsmount *mnt, struct dentry *dentry); static inline void file_accessed(struct file *file) { if (!(file->f_flags & O_NOATIME)) - touch_atime(file->f_vfsmnt, file->f_dentry); + touch_atime(file->f_path.mnt, file->f_path.dentry); } int sync_inode(struct inode *inode, struct writeback_control *wbc); @@ -1615,7 +1617,7 @@ static inline void put_write_access(struct inode * inode) static inline void allow_write_access(struct file *file) { if (file) - atomic_inc(&file->f_dentry->d_inode->i_writecount); + atomic_inc(&file->f_path.dentry->d_inode->i_writecount); } extern int do_pipe(int *); extern struct file *create_read_pipe(struct file *f); diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index d4f219ffaa5d..dfc4e4f68da4 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -164,7 +164,7 @@ static inline void fsnotify_open(struct dentry *dentry) */ static inline void fsnotify_close(struct file *file) { - struct dentry *dentry = file->f_dentry; + struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; const char *name = dentry->d_name.name; mode_t mode = file->f_mode; -- cgit v1.2.3 From 225a719f79fbc4d0cd9d9ebc5b2e3ac0e95845aa Mon Sep 17 00:00:00 2001 From: Josef Sipek Date: Fri, 8 Dec 2006 02:37:18 -0800 Subject: [PATCH] struct path: convert lockd Signed-off-by: Josef Sipek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntlock.c | 2 +- fs/lockd/clntproc.c | 2 +- fs/lockd/svclock.c | 16 ++++++++-------- fs/lockd/svcsubs.c | 2 +- include/linux/lockd/lockd.h | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index b85a0ad2cfb6..92681c9e9b20 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -126,7 +126,7 @@ __be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock continue; if (!nlm_cmp_addr(&block->b_host->h_addr, addr)) continue; - if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_dentry->d_inode) ,fh) != 0) + if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0) continue; /* Alright, we found a lock. Set the return status * and wake up the caller diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 497c3cd59d52..80a1a6dccc8f 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -129,7 +129,7 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) nlmclnt_next_cookie(&argp->cookie); argp->state = nsm_local_state; - memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); + memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh)); lock->caller = utsname()->nodename; lock->oh.data = req->a_owner; lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 7e219b938552..5c054b20fd5e 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -343,8 +343,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, __be32 ret; dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", - file->f_file->f_dentry->d_inode->i_sb->s_id, - file->f_file->f_dentry->d_inode->i_ino, + file->f_file->f_path.dentry->d_inode->i_sb->s_id, + file->f_file->f_path.dentry->d_inode->i_ino, lock->fl.fl_type, lock->fl.fl_pid, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end, @@ -420,8 +420,8 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, struct nlm_lock *conflock) { dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", - file->f_file->f_dentry->d_inode->i_sb->s_id, - file->f_file->f_dentry->d_inode->i_ino, + file->f_file->f_path.dentry->d_inode->i_sb->s_id, + file->f_file->f_path.dentry->d_inode->i_ino, lock->fl.fl_type, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end); @@ -454,8 +454,8 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) int error; dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n", - file->f_file->f_dentry->d_inode->i_sb->s_id, - file->f_file->f_dentry->d_inode->i_ino, + file->f_file->f_path.dentry->d_inode->i_sb->s_id, + file->f_file->f_path.dentry->d_inode->i_ino, lock->fl.fl_pid, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end); @@ -483,8 +483,8 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) int status = 0; dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", - file->f_file->f_dentry->d_inode->i_sb->s_id, - file->f_file->f_dentry->d_inode->i_ino, + file->f_file->f_path.dentry->d_inode->i_sb->s_id, + file->f_file->f_path.dentry->d_inode->i_ino, lock->fl.fl_pid, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end); diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index e83024e16042..c0df00c74ce3 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -43,7 +43,7 @@ static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f) static inline void nlm_debug_print_file(char *msg, struct nlm_file *file) { - struct inode *inode = file->f_file->f_dentry->d_inode; + struct inode *inode = file->f_file->f_path.dentry->d_inode; dprintk("lockd: %s %s/%ld\n", msg, inode->i_sb->s_id, inode->i_ino); diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 8c39654549d8..0c962b82a9de 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -206,7 +206,7 @@ void nlmsvc_invalidate_all(void); static __inline__ struct inode * nlmsvc_file_inode(struct nlm_file *file) { - return file->f_file->f_dentry->d_inode; + return file->f_file->f_path.dentry->d_inode; } /* -- cgit v1.2.3 From f0d1b0b30d250a07627ad8b9fbbb5c7cc08422e8 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 8 Dec 2006 02:37:49 -0800 Subject: [PATCH] LOG2: Implement a general integer log2 facility in the kernel This facility provides three entry points: ilog2() Log base 2 of unsigned long ilog2_u32() Log base 2 of u32 ilog2_u64() Log base 2 of u64 These facilities can either be used inside functions on dynamic data: int do_something(long q) { ...; y = ilog2(x) ...; } Or can be used to statically initialise global variables with constant values: unsigned n = ilog2(27); When performing static initialisation, the compiler will report "error: initializer element is not constant" if asked to take a log of zero or of something not reducible to a constant. They treat negative numbers as unsigned. When not dealing with a constant, they fall back to using fls() which permits them to use arch-specific log calculation instructions - such as BSR on x86/x86_64 or SCAN on FRV - if available. [akpm@osdl.org: MMC fix] Signed-off-by: David Howells Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Herbert Xu Cc: David Howells Cc: Wojtek Kaniewski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/Kconfig | 8 ++ arch/arm/Kconfig | 8 ++ arch/arm26/Kconfig | 8 ++ arch/avr32/Kconfig | 8 ++ arch/cris/Kconfig | 8 ++ arch/frv/Kconfig | 8 ++ arch/h8300/Kconfig | 8 ++ arch/i386/Kconfig.cpu | 8 ++ arch/ia64/Kconfig | 8 ++ arch/m32r/Kconfig | 8 ++ arch/m68k/Kconfig | 8 ++ arch/m68knommu/Kconfig | 8 ++ arch/mips/Kconfig | 8 ++ arch/parisc/Kconfig | 8 ++ arch/powerpc/Kconfig | 8 ++ arch/ppc/Kconfig | 8 ++ arch/s390/Kconfig | 8 ++ arch/sh/Kconfig | 8 ++ arch/sh64/Kconfig | 8 ++ arch/sparc/Kconfig | 8 ++ arch/sparc64/Kconfig | 8 ++ arch/v850/Kconfig | 8 ++ arch/x86_64/Kconfig | 8 ++ arch/xtensa/Kconfig | 8 ++ drivers/infiniband/hw/mthca/mthca_provider.c | 4 +- drivers/infiniband/hw/mthca/mthca_qp.c | 4 +- drivers/infiniband/hw/mthca/mthca_srq.c | 4 +- drivers/infiniband/ulp/iser/iser_memory.c | 4 +- drivers/md/dm-crypt.c | 2 +- drivers/mmc/tifm_sd.c | 2 +- fs/ext2/super.c | 6 +- fs/ext3/super.c | 6 +- include/asm-frv/bitops.h | 44 +++++++++ include/linux/kernel.h | 9 +- include/linux/log2.h | 131 +++++++++++++++++++++++++++ mm/page_alloc.c | 4 +- 36 files changed, 384 insertions(+), 28 deletions(-) create mode 100644 include/linux/log2.h (limited to 'include/linux') diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 7e55ea66c6d4..84caf50725b5 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -25,6 +25,14 @@ config RWSEM_XCHGADD_ALGORITHM bool default y +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_FIND_NEXT_BIT bool default y diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 8c05d4321ae9..aa1d400d721a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -74,6 +74,14 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_HWEIGHT bool default y diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig index c14fe918bc4c..74eba8b5a8ca 100644 --- a/arch/arm26/Kconfig +++ b/arch/arm26/Kconfig @@ -41,6 +41,14 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_HWEIGHT bool default y diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index 5f1694eea842..bb059a4e1df9 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -45,6 +45,14 @@ config GENERIC_TIME config RWSEM_XCHGADD_ALGORITHM bool +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_BUST_SPINLOCK bool diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 6a1238a29d6c..3474309e049c 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -16,6 +16,14 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_FIND_NEXT_BIT bool default y diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index cf1c446e003a..7561d7b72e75 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig @@ -41,6 +41,14 @@ config TIME_LOW_RES bool default y +config ARCH_HAS_ILOG2_U32 + bool + default y + +config ARCH_HAS_ILOG2_U64 + bool + default y + mainmenu "Fujitsu FR-V Kernel Configuration" source "init/Kconfig" diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index cabf0bfffc53..34a84bc4baf5 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -29,6 +29,14 @@ config RWSEM_XCHGADD_ALGORITHM bool default n +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_FIND_NEXT_BIT bool default y diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu index 821fd269ca58..2aecfba4ac4f 100644 --- a/arch/i386/Kconfig.cpu +++ b/arch/i386/Kconfig.cpu @@ -248,6 +248,14 @@ config RWSEM_XCHGADD_ALGORITHM depends on !M386 default y +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_CALIBRATE_DELAY bool default y diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 75d839715b2f..fcacfe291b9b 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -34,6 +34,14 @@ config RWSEM_XCHGADD_ALGORITHM bool default y +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_FIND_NEXT_BIT bool default y diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 41fd490af3b4..f383dab973f5 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -214,6 +214,14 @@ config RWSEM_XCHGADD_ALGORITHM bool default n +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_FIND_NEXT_BIT bool default y diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 7bc14461a6ac..70a577c89c7c 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -17,6 +17,14 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_HWEIGHT bool default y diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index aa70dde54228..25993c2a8fbb 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -25,6 +25,14 @@ config RWSEM_XCHGADD_ALGORITHM bool default n +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_FIND_NEXT_BIT bool default y diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index d8af858fe3f5..57af8d8cf46f 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -819,6 +819,14 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_FIND_NEXT_BIT bool default y diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index d2101237442e..0f9ff618c6d7 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -25,6 +25,14 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_FIND_NEXT_BIT bool default y diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 291c95ac4b31..97c7a212cdda 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -41,6 +41,14 @@ config RWSEM_XCHGADD_ALGORITHM bool default y +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_HWEIGHT bool default y diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index f76a146cff13..692b5ba53209 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -19,6 +19,14 @@ config RWSEM_XCHGADD_ALGORITHM bool default y +config ARCH_HAS_ILOG2_U32 + bool + default y + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_HWEIGHT bool default y diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 583d9ff0a571..45e47bfb68a9 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -22,6 +22,14 @@ config RWSEM_XCHGADD_ALGORITHM bool default y +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config GENERIC_HWEIGHT bool default y diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index d83d64af31f2..8e24c40662e3 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -59,6 +59,14 @@ config LOCKDEP_SUPPORT bool default y +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + source "init/Kconfig" menu "System type" diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig index 58c678e06667..7bc0744b7ab6 100644 --- a/arch/sh64/Kconfig +++ b/arch/sh64/Kconfig @@ -39,6 +39,14 @@ config RWSEM_XCHGADD_ALGORITHM config GENERIC_ISA_DMA bool +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + source init/Kconfig menu "System type" diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 92a7c8a636d3..d0dec1ea2eed 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -166,6 +166,14 @@ config ARCH_MAY_HAVE_PC_FDC bool default y +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config SUN_PM bool default y diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index b627f8dbcaad..d391d11f245a 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -34,6 +34,14 @@ config ARCH_MAY_HAVE_PC_FDC bool default y +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + config AUDIT_ARCH bool default y diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig index 37ec644603ab..bcf825875d17 100644 --- a/arch/v850/Kconfig +++ b/arch/v850/Kconfig @@ -38,6 +38,14 @@ config TIME_LOW_RES bool default y +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + # Turn off some random 386 crap that can affect device config config ISA bool diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 3254a616c69e..3ac581d17202 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -101,6 +101,14 @@ config GENERIC_BUG default y depends on BUG +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + source "init/Kconfig" diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index c1e69a1f92a4..9eccfbd1b536 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -34,6 +34,14 @@ config GENERIC_HARDIRQS bool default y +config ARCH_HAS_ILOG2_U32 + bool + default n + +config ARCH_HAS_ILOG2_U64 + bool + default n + source "init/Kconfig" menu "Processor type and features" diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 21422a3336ad..7ec7c4b937f9 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -124,7 +124,7 @@ static int mthca_query_device(struct ib_device *ibdev, props->max_map_per_fmr = 255; else props->max_map_per_fmr = - (1 << (32 - long_log2(mdev->limits.num_mpts))) - 1; + (1 << (32 - ilog2(mdev->limits.num_mpts))) - 1; err = 0; out: @@ -816,7 +816,7 @@ static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *uda lkey = ucmd.lkey; } - ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, long_log2(entries), &status); + ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, ilog2(entries), &status); if (status) ret = -EINVAL; diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 33e3ba7937f1..d844a2569b47 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -636,11 +636,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, if (mthca_is_memfree(dev)) { if (qp->rq.max) - qp_context->rq_size_stride = long_log2(qp->rq.max) << 3; + qp_context->rq_size_stride = ilog2(qp->rq.max) << 3; qp_context->rq_size_stride |= qp->rq.wqe_shift - 4; if (qp->sq.max) - qp_context->sq_size_stride = long_log2(qp->sq.max) << 3; + qp_context->sq_size_stride = ilog2(qp->sq.max) << 3; qp_context->sq_size_stride |= qp->sq.wqe_shift - 4; } diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 34d2c4768962..10684da33d58 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -120,7 +120,7 @@ static void mthca_arbel_init_srq_context(struct mthca_dev *dev, memset(context, 0, sizeof *context); - logsize = long_log2(srq->max); + logsize = ilog2(srq->max); context->state_logsize_srqn = cpu_to_be32(logsize << 24 | srq->srqn); context->lkey = cpu_to_be32(srq->mr.ibmr.lkey); context->db_index = cpu_to_be32(srq->db_index); @@ -213,7 +213,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz)) return -EINVAL; - srq->wqe_shift = long_log2(ds); + srq->wqe_shift = ilog2(ds); srq->srqn = mthca_alloc(&dev->srq_table.alloc); if (srq->srqn == -1) diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 5e122501fd80..3aedd59b8a84 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -114,7 +114,7 @@ int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, if (cmd_data_len > ISER_KMALLOC_THRESHOLD) mem = (void *)__get_free_pages(GFP_NOIO, - long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT); + ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT); else mem = kmalloc(cmd_data_len, GFP_NOIO); @@ -211,7 +211,7 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, if (cmd_data_len > ISER_KMALLOC_THRESHOLD) free_pages((unsigned long)mem_copy->copy_buf, - long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT); + ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT); else kfree(mem_copy->copy_buf); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index a1086ee8cccd..96152868525b 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -220,7 +220,7 @@ static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti, const char *opts) { unsigned int bs = crypto_blkcipher_blocksize(cc->tfm); - int log = long_log2(bs); + int log = ilog2(bs); /* we need to calculate how far we must shift the sector count * to get the cipher block count, we use this shift in _gen */ diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index e846499a004c..f18ad998b3cb 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -387,7 +387,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) writel(TIFM_FIFO_INT_SETALL, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(long_log2(cmd->data->blksz) - 2, + writel(ilog2(cmd->data->blksz) - 2, sock->addr + SOCK_FIFO_PAGE_SIZE); writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL); writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 255cef5f7420..6347c2dbdd81 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -597,8 +597,6 @@ static int ext2_check_descriptors (struct super_block * sb) return 1; } -#define log2(n) ffz(~(n)) - /* * Maximal file size. There is a direct, and {,double-,triple-}indirect * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. @@ -834,9 +832,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) sbi->s_sbh = bh; sbi->s_mount_state = le16_to_cpu(es->s_state); sbi->s_addr_per_block_bits = - log2 (EXT2_ADDR_PER_BLOCK(sb)); + ilog2 (EXT2_ADDR_PER_BLOCK(sb)); sbi->s_desc_per_block_bits = - log2 (EXT2_DESC_PER_BLOCK(sb)); + ilog2 (EXT2_DESC_PER_BLOCK(sb)); if (sb->s_magic != EXT2_SUPER_MAGIC) goto cantfind_ext2; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 580b8a6ca979..b34886734a44 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1347,8 +1347,6 @@ static void ext3_orphan_cleanup (struct super_block * sb, sb->s_flags = s_flags; /* Restore MS_RDONLY status */ } -#define log2(n) ffz(~(n)) - /* * Maximal file size. There is a direct, and {,double-,triple-}indirect * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. @@ -1597,8 +1595,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc); sbi->s_sbh = bh; sbi->s_mount_state = le16_to_cpu(es->s_state); - sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb)); - sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb)); + sbi->s_addr_per_block_bits = ilog2(EXT3_ADDR_PER_BLOCK(sb)); + sbi->s_desc_per_block_bits = ilog2(EXT3_DESC_PER_BLOCK(sb)); for (i=0; i < 4; i++) sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); sbi->s_def_hash_version = es->s_def_hash_version; diff --git a/include/asm-frv/bitops.h b/include/asm-frv/bitops.h index 1f70d47148bd..f8560edf59ff 100644 --- a/include/asm-frv/bitops.h +++ b/include/asm-frv/bitops.h @@ -256,6 +256,50 @@ int __ffs(unsigned long x) return 31 - bit; } +/* + * special slimline version of fls() for calculating ilog2_u32() + * - note: no protection against n == 0 + */ +#define ARCH_HAS_ILOG2_U32 +static inline __attribute__((const)) +int __ilog2_u32(u32 n) +{ + int bit; + asm("scan %1,gr0,%0" : "=r"(bit) : "r"(n)); + return 31 - bit; +} + +/* + * special slimline version of fls64() for calculating ilog2_u64() + * - note: no protection against n == 0 + */ +#define ARCH_HAS_ILOG2_U64 +static inline __attribute__((const)) +int __ilog2_u64(u64 n) +{ + union { + u64 ll; + struct { u32 h, l; }; + } _; + int bit, x, y; + + _.ll = n; + + asm(" subcc %3,gr0,gr0,icc0 \n" + " ckeq icc0,cc4 \n" + " cscan.p %3,gr0,%0 ,cc4,0 \n" + " setlos #63,%1 \n" + " cscan.p %4,gr0,%0 ,cc4,1 \n" + " setlos #31,%2 \n" + " csub.p %1,%0,%0 ,cc4,0 \n" + " csub %2,%0,%0 ,cc4,1 \n" + : "=&r"(bit), "=r"(x), "=r"(y) + : "0r"(_.h), "r"(_.l) + : "icc0", "cc4" + ); + return bit; +} + #include #include diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 6738283ac385..3710cce16642 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -157,14 +158,6 @@ static inline int printk(const char *s, ...) { return 0; } unsigned long int_sqrt(unsigned long); -static inline int __attribute_pure__ long_log2(unsigned long x) -{ - int r = 0; - for (x >>= 1; x > 0; x >>= 1) - r++; - return r; -} - static inline unsigned long __attribute_const__ roundup_pow_of_two(unsigned long x) { diff --git a/include/linux/log2.h b/include/linux/log2.h new file mode 100644 index 000000000000..3979c60325ff --- /dev/null +++ b/include/linux/log2.h @@ -0,0 +1,131 @@ +/* Integer base 2 logarithm calculation + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _LINUX_LOG2_H +#define _LINUX_LOG2_H + +#include +#include + +/* + * deal with unrepresentable constant logarithms + */ +extern __attribute__((const, noreturn)) +int ____ilog2_NaN(void); + +/* + * non-constant log of base 2 calculators + * - the arch may override these in asm/bitops.h if they can be implemented + * more efficiently than using fls() and fls64() + * - the arch is not required to handle n==0 if implementing the fallback + */ +#ifndef CONFIG_ARCH_HAS_ILOG2_U32 +static inline __attribute__((const)) +int __ilog2_u32(u32 n) +{ + return fls(n) - 1; +} +#endif + +#ifndef CONFIG_ARCH_HAS_ILOG2_U64 +static inline __attribute__((const)) +int __ilog2_u64(u64 n) +{ + return fls64(n) - 1; +} +#endif + +/** + * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value + * @n - parameter + * + * constant-capable log of base 2 calculation + * - this can be used to initialise global variables from constant data, hence + * the massive ternary operator construction + * + * selects the appropriately-sized optimised version depending on sizeof(n) + */ +#define ilog2(n) \ +( \ + __builtin_constant_p(n) ? ( \ + (n) < 1 ? ____ilog2_NaN() : \ + (n) & (1ULL << 63) ? 63 : \ + (n) & (1ULL << 62) ? 62 : \ + (n) & (1ULL << 61) ? 61 : \ + (n) & (1ULL << 60) ? 60 : \ + (n) & (1ULL << 59) ? 59 : \ + (n) & (1ULL << 58) ? 58 : \ + (n) & (1ULL << 57) ? 57 : \ + (n) & (1ULL << 56) ? 56 : \ + (n) & (1ULL << 55) ? 55 : \ + (n) & (1ULL << 54) ? 54 : \ + (n) & (1ULL << 53) ? 53 : \ + (n) & (1ULL << 52) ? 52 : \ + (n) & (1ULL << 51) ? 51 : \ + (n) & (1ULL << 50) ? 50 : \ + (n) & (1ULL << 49) ? 49 : \ + (n) & (1ULL << 48) ? 48 : \ + (n) & (1ULL << 47) ? 47 : \ + (n) & (1ULL << 46) ? 46 : \ + (n) & (1ULL << 45) ? 45 : \ + (n) & (1ULL << 44) ? 44 : \ + (n) & (1ULL << 43) ? 43 : \ + (n) & (1ULL << 42) ? 42 : \ + (n) & (1ULL << 41) ? 41 : \ + (n) & (1ULL << 40) ? 40 : \ + (n) & (1ULL << 39) ? 39 : \ + (n) & (1ULL << 38) ? 38 : \ + (n) & (1ULL << 37) ? 37 : \ + (n) & (1ULL << 36) ? 36 : \ + (n) & (1ULL << 35) ? 35 : \ + (n) & (1ULL << 34) ? 34 : \ + (n) & (1ULL << 33) ? 33 : \ + (n) & (1ULL << 32) ? 32 : \ + (n) & (1ULL << 31) ? 31 : \ + (n) & (1ULL << 30) ? 30 : \ + (n) & (1ULL << 29) ? 29 : \ + (n) & (1ULL << 28) ? 28 : \ + (n) & (1ULL << 27) ? 27 : \ + (n) & (1ULL << 26) ? 26 : \ + (n) & (1ULL << 25) ? 25 : \ + (n) & (1ULL << 24) ? 24 : \ + (n) & (1ULL << 23) ? 23 : \ + (n) & (1ULL << 22) ? 22 : \ + (n) & (1ULL << 21) ? 21 : \ + (n) & (1ULL << 20) ? 20 : \ + (n) & (1ULL << 19) ? 19 : \ + (n) & (1ULL << 18) ? 18 : \ + (n) & (1ULL << 17) ? 17 : \ + (n) & (1ULL << 16) ? 16 : \ + (n) & (1ULL << 15) ? 15 : \ + (n) & (1ULL << 14) ? 14 : \ + (n) & (1ULL << 13) ? 13 : \ + (n) & (1ULL << 12) ? 12 : \ + (n) & (1ULL << 11) ? 11 : \ + (n) & (1ULL << 10) ? 10 : \ + (n) & (1ULL << 9) ? 9 : \ + (n) & (1ULL << 8) ? 8 : \ + (n) & (1ULL << 7) ? 7 : \ + (n) & (1ULL << 6) ? 6 : \ + (n) & (1ULL << 5) ? 5 : \ + (n) & (1ULL << 4) ? 4 : \ + (n) & (1ULL << 3) ? 3 : \ + (n) & (1ULL << 2) ? 2 : \ + (n) & (1ULL << 1) ? 1 : \ + (n) & (1ULL << 0) ? 0 : \ + ____ilog2_NaN() \ + ) : \ + (sizeof(n) <= 4) ? \ + __ilog2_u32(n) : \ + __ilog2_u64(n) \ + ) + +#endif /* _LINUX_LOG2_H */ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index cace22b3ac25..18f0e044c43d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3244,7 +3244,7 @@ void *__init alloc_large_system_hash(const char *tablename, if (numentries > max) numentries = max; - log2qty = long_log2(numentries); + log2qty = ilog2(numentries); do { size = bucketsize << log2qty; @@ -3266,7 +3266,7 @@ void *__init alloc_large_system_hash(const char *tablename, printk("%s hash table entries: %d (order: %d, %lu bytes)\n", tablename, (1U << log2qty), - long_log2(size) - PAGE_SHIFT, + ilog2(size) - PAGE_SHIFT, size); if (_hash_shift) -- cgit v1.2.3 From 312a0c170945b49f319960afd2e492c05f9dd551 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 8 Dec 2006 02:37:51 -0800 Subject: [PATCH] LOG2: Alter roundup_pow_of_two() so that it can use a ilog2() on a constant Alter roundup_pow_of_two() so that it can make use of ilog2() on a constant to produce a constant value, retaining the ability for an arch to override it in the non-const case. This permits the function to be used to initialise variables. Signed-off-by: David Howells Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 6 ------ include/linux/log2.h | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3710cce16642..e8bfac34d2ba 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -158,12 +158,6 @@ static inline int printk(const char *s, ...) { return 0; } unsigned long int_sqrt(unsigned long); -static inline unsigned long -__attribute_const__ roundup_pow_of_two(unsigned long x) -{ - return 1UL << fls_long(x - 1); -} - extern int printk_ratelimit(void); extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst); extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, diff --git a/include/linux/log2.h b/include/linux/log2.h index 3979c60325ff..d02e1a547a7e 100644 --- a/include/linux/log2.h +++ b/include/linux/log2.h @@ -43,6 +43,15 @@ int __ilog2_u64(u64 n) } #endif +/* + * round up to nearest power of two + */ +static inline __attribute__((const)) +unsigned long __roundup_pow_of_two(unsigned long n) +{ + return 1UL << fls_long(n - 1); +} + /** * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value * @n - parameter @@ -128,4 +137,21 @@ int __ilog2_u64(u64 n) __ilog2_u64(n) \ ) +/** + * roundup_pow_of_two - round the given value up to nearest power of two + * @n - parameter + * + * round the given balue up to the nearest power of two + * - the result is undefined when n == 0 + * - this can be used to initialise global variables from constant data + */ +#define roundup_pow_of_two(n) \ +( \ + __builtin_constant_p(n) ? ( \ + (n == 1) ? 0 : \ + (1UL << (ilog2((n) - 1) + 1)) \ + ) : \ + __roundup_pow_of_two(n) \ + ) + #endif /* _LINUX_LOG2_H */ -- cgit v1.2.3 From 937949d9edbf4049bd41af6c9f92c26280584564 Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Fri, 8 Dec 2006 02:37:54 -0800 Subject: [PATCH] add process_session() helper routine Replace occurences of task->signal->session by a new process_session() helper routine. It will be useful for pid namespaces to abstract the session pid number. Signed-off-by: Cedric Le Goater Cc: Kirill Korotaev Cc: Eric W. Biederman Cc: Herbert Poetzl Cc: Sukadev Bhattiprolu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/mips/kernel/irixelf.c | 2 +- drivers/char/mxser.c | 2 +- drivers/char/rocket.c | 2 +- drivers/char/tty_io.c | 12 ++++++------ fs/binfmt_elf.c | 4 ++-- fs/binfmt_elf_fdpic.c | 4 ++-- include/linux/sched.h | 5 +++++ kernel/exit.c | 19 ++++++++++--------- kernel/fork.c | 4 ++-- kernel/signal.c | 2 +- kernel/sys.c | 8 ++++---- 11 files changed, 35 insertions(+), 29 deletions(-) (limited to 'include/linux') diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 1bbefbf43373..37cad5de515c 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -1145,7 +1145,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) psinfo.pr_pid = prstatus.pr_pid = current->pid; psinfo.pr_ppid = prstatus.pr_ppid = current->parent->pid; psinfo.pr_pgrp = prstatus.pr_pgrp = process_group(current); - psinfo.pr_sid = prstatus.pr_sid = current->signal->session; + psinfo.pr_sid = prstatus.pr_sid = process_session(current); if (current->pid == current->tgid) { /* * This is the record for the group leader. Add in the diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 5ed2486b7581..b1cc89c89820 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -994,7 +994,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) mxser_change_speed(info, NULL); } - info->session = current->signal->session; + info->session = process_session(current); info->pgrp = process_group(current); /* diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index bac80056f7e0..4fdf52e9f3b1 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -1017,7 +1017,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) /* * Info->count is now 1; so it's safe to sleep now. */ - info->session = current->signal->session; + info->session = process_session(current); info->pgrp = process_group(current); if ((info->flags & ROCKET_INITIALIZED) == 0) { diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 8a2d26e98ac4..4ebba7ca1dc9 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1511,7 +1511,7 @@ void disassociate_ctty(int on_exit) spin_lock_irq(¤t->sighand->siglock); current->signal->tty_old_pgrp = 0; - session = current->signal->session; + session = process_session(current); spin_unlock_irq(¤t->sighand->siglock); mutex_lock(&tty_mutex); @@ -2897,7 +2897,7 @@ static int tiocsctty(struct tty_struct *tty, int arg) { int ret = 0; if (current->signal->leader && - (current->signal->session == tty->session)) + (process_session(current) == tty->session)) return ret; mutex_lock(&tty_mutex); @@ -2979,13 +2979,13 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t return retval; if (!current->signal->tty || (current->signal->tty != real_tty) || - (real_tty->session != current->signal->session)) + (real_tty->session != process_session(current))) return -ENOTTY; if (get_user(pgrp, p)) return -EFAULT; if (pgrp < 0) return -EINVAL; - if (session_of_pgrp(pgrp) != current->signal->session) + if (session_of_pgrp(pgrp) != process_session(current)) return -EPERM; real_tty->pgrp = pgrp; return 0; @@ -3338,7 +3338,7 @@ static void __do_SAK(struct work_struct *work) /* Kill the entire session */ do_each_task_pid(session, PIDTYPE_SID, p) { printk(KERN_NOTICE "SAK: killed process %d" - " (%s): p->signal->session==tty->session\n", + " (%s): process_session(p)==tty->session\n", p->pid, p->comm); send_sig(SIGKILL, p, 1); } while_each_task_pid(session, PIDTYPE_SID, p); @@ -3348,7 +3348,7 @@ static void __do_SAK(struct work_struct *work) do_each_thread(g, p) { if (p->signal->tty == tty) { printk(KERN_NOTICE "SAK: killed process %d" - " (%s): p->signal->session==tty->session\n", + " (%s): process_session(p)==tty->session\n", p->pid, p->comm); send_sig(SIGKILL, p, 1); continue; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index c6dbb4a7ec78..d3adfd353ff9 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1317,7 +1317,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus, prstatus->pr_pid = p->pid; prstatus->pr_ppid = p->parent->pid; prstatus->pr_pgrp = process_group(p); - prstatus->pr_sid = p->signal->session; + prstatus->pr_sid = process_session(p); if (thread_group_leader(p)) { /* * This is the record for the group leader. Add in the @@ -1363,7 +1363,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, psinfo->pr_pid = p->pid; psinfo->pr_ppid = p->parent->pid; psinfo->pr_pgrp = process_group(p); - psinfo->pr_sid = p->signal->session; + psinfo->pr_sid = process_session(p); i = p->state ? ffz(~p->state) + 1 : 0; psinfo->pr_state = i; diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 9f0b7efc3df5..76f06f6bc2f6 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1322,7 +1322,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus, prstatus->pr_pid = p->pid; prstatus->pr_ppid = p->parent->pid; prstatus->pr_pgrp = process_group(p); - prstatus->pr_sid = p->signal->session; + prstatus->pr_sid = process_session(p); if (thread_group_leader(p)) { /* * This is the record for the group leader. Add in the @@ -1371,7 +1371,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, psinfo->pr_pid = p->pid; psinfo->pr_ppid = p->parent->pid; psinfo->pr_pgrp = process_group(p); - psinfo->pr_sid = p->signal->session; + psinfo->pr_sid = process_session(p); i = p->state ? ffz(~p->state) + 1 : 0; psinfo->pr_state = i; diff --git a/include/linux/sched.h b/include/linux/sched.h index 5e8a0ba61749..270d864a8ff1 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1047,6 +1047,11 @@ static inline pid_t process_group(struct task_struct *tsk) return tsk->signal->pgrp; } +static inline pid_t process_session(struct task_struct *tsk) +{ + return tsk->signal->session; +} + static inline struct pid *task_pid(struct task_struct *task) { return task->pids[PIDTYPE_PID].pid; diff --git a/kernel/exit.c b/kernel/exit.c index fa0495e167e9..8d289bfc13d1 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -193,14 +193,14 @@ int session_of_pgrp(int pgrp) read_lock(&tasklist_lock); do_each_task_pid(pgrp, PIDTYPE_PGID, p) { - if (p->signal->session > 0) { - sid = p->signal->session; + if (process_session(p) > 0) { + sid = process_session(p); goto out; } } while_each_task_pid(pgrp, PIDTYPE_PGID, p); p = find_task_by_pid(pgrp); if (p) - sid = p->signal->session; + sid = process_session(p); out: read_unlock(&tasklist_lock); @@ -225,8 +225,8 @@ static int will_become_orphaned_pgrp(int pgrp, struct task_struct *ignored_task) || p->exit_state || is_init(p->real_parent)) continue; - if (process_group(p->real_parent) != pgrp - && p->real_parent->signal->session == p->signal->session) { + if (process_group(p->real_parent) != pgrp && + process_session(p->real_parent) == process_session(p)) { ret = 0; break; } @@ -302,7 +302,7 @@ void __set_special_pids(pid_t session, pid_t pgrp) { struct task_struct *curr = current->group_leader; - if (curr->signal->session != session) { + if (process_session(curr) != session) { detach_pid(curr, PIDTYPE_SID); curr->signal->session = session; attach_pid(curr, PIDTYPE_SID, session); @@ -647,10 +647,11 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced) * outside, so the child pgrp is now orphaned. */ if ((process_group(p) != process_group(father)) && - (p->signal->session == father->signal->session)) { + (process_session(p) == process_session(father))) { int pgrp = process_group(p); - if (will_become_orphaned_pgrp(pgrp, NULL) && has_stopped_jobs(pgrp)) { + if (will_become_orphaned_pgrp(pgrp, NULL) && + has_stopped_jobs(pgrp)) { __kill_pg_info(SIGHUP, SEND_SIG_PRIV, pgrp); __kill_pg_info(SIGCONT, SEND_SIG_PRIV, pgrp); } @@ -784,7 +785,7 @@ static void exit_notify(struct task_struct *tsk) t = tsk->real_parent; if ((process_group(t) != process_group(tsk)) && - (t->signal->session == tsk->signal->session) && + (process_session(t) == process_session(tsk)) && will_become_orphaned_pgrp(process_group(tsk), tsk) && has_stopped_jobs(process_group(tsk))) { __kill_pg_info(SIGHUP, SEND_SIG_PRIV, process_group(tsk)); diff --git a/kernel/fork.c b/kernel/fork.c index 597707819327..298c4d6ab512 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1259,9 +1259,9 @@ static struct task_struct *copy_process(unsigned long clone_flags, if (thread_group_leader(p)) { p->signal->tty = current->signal->tty; p->signal->pgrp = process_group(current); - p->signal->session = current->signal->session; + p->signal->session = process_session(current); attach_pid(p, PIDTYPE_PGID, process_group(p)); - attach_pid(p, PIDTYPE_SID, p->signal->session); + attach_pid(p, PIDTYPE_SID, process_session(p)); list_add_tail_rcu(&p->tasks, &init_task.tasks); __get_cpu_var(process_counts)++; diff --git a/kernel/signal.c b/kernel/signal.c index ec81defde339..9eac4db60eda 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -583,7 +583,7 @@ static int check_kill_permission(int sig, struct siginfo *info, error = -EPERM; if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info))) && ((sig != SIGCONT) || - (current->signal->session != t->signal->session)) + (process_session(current) != process_session(t))) && (current->euid ^ t->suid) && (current->euid ^ t->uid) && (current->uid ^ t->suid) && (current->uid ^ t->uid) && !capable(CAP_KILL)) diff --git a/kernel/sys.c b/kernel/sys.c index 1ac2d1c5d84e..4f9d23a3095f 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1381,7 +1381,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) if (p->real_parent == group_leader) { err = -EPERM; - if (p->signal->session != group_leader->signal->session) + if (process_session(p) != process_session(group_leader)) goto out; err = -EACCES; if (p->did_exec) @@ -1400,7 +1400,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) struct task_struct *p; do_each_task_pid(pgid, PIDTYPE_PGID, p) { - if (p->signal->session == group_leader->signal->session) + if (process_session(p) == process_session(group_leader)) goto ok_pgid; } while_each_task_pid(pgid, PIDTYPE_PGID, p); goto out; @@ -1459,7 +1459,7 @@ asmlinkage long sys_getpgrp(void) asmlinkage long sys_getsid(pid_t pid) { if (!pid) - return current->signal->session; + return process_session(current); else { int retval; struct task_struct *p; @@ -1471,7 +1471,7 @@ asmlinkage long sys_getsid(pid_t pid) if (p) { retval = security_task_getsid(p); if (!retval) - retval = p->signal->session; + retval = process_session(p); } read_unlock(&tasklist_lock); return retval; -- cgit v1.2.3 From 1ec320afdc9552c92191d5f89fcd1ebe588334ca Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Fri, 8 Dec 2006 02:37:55 -0800 Subject: [PATCH] add process_session() helper routine: deprecate old field Add an anonymous union and ((deprecated)) to catch direct usage of the session field. [akpm@osdl.org: fix various missed conversions] [jdike@addtoit.com: fix UML bug] Signed-off-by: Jeff Dike Cc: Cedric Le Goater Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 2 +- fs/proc/array.c | 2 +- include/linux/init_task.h | 11 ++++++----- include/linux/sched.h | 19 +++++++++++++++++-- kernel/exit.c | 2 +- kernel/fork.c | 2 +- 6 files changed, 27 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 4ebba7ca1dc9..48cee2004e97 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -3855,7 +3855,7 @@ EXPORT_SYMBOL(proc_clear_tty); void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) { if (tty) { - tty->session = tsk->signal->session; + tty->session = process_session(tsk); tty->pgrp = process_group(tsk); } tsk->signal->tty = tty; diff --git a/fs/proc/array.c b/fs/proc/array.c index b0cd014a39bd..70e4fab117b1 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -381,7 +381,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) stime = cputime_add(stime, sig->stime); } - sid = sig->session; + sid = signal_session(sig); pgid = process_group(task); ppid = rcu_dereference(task->real_parent)->tgid; diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 733790d4f7db..848a68af3d42 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -57,17 +57,18 @@ .cpu_vm_mask = CPU_MASK_ALL, \ } -#define INIT_SIGNALS(sig) { \ - .count = ATOMIC_INIT(1), \ +#define INIT_SIGNALS(sig) { \ + .count = ATOMIC_INIT(1), \ .wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\ - .shared_pending = { \ + .shared_pending = { \ .list = LIST_HEAD_INIT(sig.shared_pending.list), \ - .signal = {{0}}}, \ + .signal = {{0}}}, \ .posix_timers = LIST_HEAD_INIT(sig.posix_timers), \ .cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \ .rlim = INIT_RLIMITS, \ .pgrp = 1, \ - .session = 1, \ + .tty_old_pgrp = 0, \ + { .__session = 1}, \ } extern struct nsproxy init_nsproxy; diff --git a/include/linux/sched.h b/include/linux/sched.h index 270d864a8ff1..6fec1d419714 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -436,7 +436,12 @@ struct signal_struct { /* job control IDs */ pid_t pgrp; pid_t tty_old_pgrp; - pid_t session; + + union { + pid_t session __deprecated; + pid_t __session; + }; + /* boolean value for session group leader */ int leader; @@ -1047,9 +1052,19 @@ static inline pid_t process_group(struct task_struct *tsk) return tsk->signal->pgrp; } +static inline pid_t signal_session(struct signal_struct *sig) +{ + return sig->__session; +} + static inline pid_t process_session(struct task_struct *tsk) { - return tsk->signal->session; + return signal_session(tsk->signal); +} + +static inline void set_signal_session(struct signal_struct *sig, pid_t session) +{ + sig->__session = session; } static inline struct pid *task_pid(struct task_struct *task) diff --git a/kernel/exit.c b/kernel/exit.c index 8d289bfc13d1..6267a6cc6113 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -304,7 +304,7 @@ void __set_special_pids(pid_t session, pid_t pgrp) if (process_session(curr) != session) { detach_pid(curr, PIDTYPE_SID); - curr->signal->session = session; + set_signal_session(curr->signal, session); attach_pid(curr, PIDTYPE_SID, session); } if (process_group(curr) != pgrp) { diff --git a/kernel/fork.c b/kernel/fork.c index 298c4d6ab512..60d2644bfe85 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1259,7 +1259,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, if (thread_group_leader(p)) { p->signal->tty = current->signal->tty; p->signal->pgrp = process_group(current); - p->signal->session = process_session(current); + set_signal_session(p->signal, process_session(current)); attach_pid(p, PIDTYPE_PGID, process_group(p)); attach_pid(p, PIDTYPE_SID, process_session(p)); -- cgit v1.2.3 From 6b3286ed1169d74fea401367d6d4d6c6ec758a81 Mon Sep 17 00:00:00 2001 From: Kirill Korotaev Date: Fri, 8 Dec 2006 02:37:56 -0800 Subject: [PATCH] rename struct namespace to struct mnt_namespace Rename 'struct namespace' to 'struct mnt_namespace' to avoid confusion with other namespaces being developped for the containers : pid, uts, ipc, etc. 'namespace' variables and attributes are also renamed to 'mnt_ns' Signed-off-by: Kirill Korotaev Signed-off-by: Cedric Le Goater Cc: Eric W. Biederman Cc: Herbert Poetzl Cc: Sukadev Bhattiprolu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/afs/mntpt.c | 2 +- fs/namespace.c | 113 +++++++++++++++++++++--------------------- fs/nfs/getroot.c | 2 +- fs/pnode.c | 2 +- fs/pnode.h | 2 +- fs/proc/base.c | 36 +++++++------- fs/reiserfs/super.c | 2 +- include/linux/init_task.h | 2 +- include/linux/mnt_namespace.h | 42 ++++++++++++++++ include/linux/mount.h | 4 +- include/linux/namespace.h | 42 ---------------- include/linux/nsproxy.h | 4 +- kernel/exit.c | 2 +- kernel/fork.c | 21 ++++---- kernel/kmod.c | 2 +- kernel/nsproxy.c | 16 +++--- 16 files changed, 148 insertions(+), 146 deletions(-) create mode 100644 include/linux/mnt_namespace.h delete mode 100644 include/linux/namespace.h (limited to 'include/linux') diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index f33b1a81a761..8f74e8450826 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include "super.h" #include "cell.h" #include "volume.h" diff --git a/fs/namespace.c b/fs/namespace.c index b00ac84ebbdd..fde8553faa76 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -133,10 +133,10 @@ struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) static inline int check_mnt(struct vfsmount *mnt) { - return mnt->mnt_namespace == current->nsproxy->namespace; + return mnt->mnt_ns == current->nsproxy->mnt_ns; } -static void touch_namespace(struct namespace *ns) +static void touch_mnt_namespace(struct mnt_namespace *ns) { if (ns) { ns->event = ++event; @@ -144,7 +144,7 @@ static void touch_namespace(struct namespace *ns) } } -static void __touch_namespace(struct namespace *ns) +static void __touch_mnt_namespace(struct mnt_namespace *ns) { if (ns && ns->event != event) { ns->event = event; @@ -187,19 +187,19 @@ static void commit_tree(struct vfsmount *mnt) struct vfsmount *parent = mnt->mnt_parent; struct vfsmount *m; LIST_HEAD(head); - struct namespace *n = parent->mnt_namespace; + struct mnt_namespace *n = parent->mnt_ns; BUG_ON(parent == mnt); list_add_tail(&head, &mnt->mnt_list); list_for_each_entry(m, &head, mnt_list) - m->mnt_namespace = n; + m->mnt_ns = n; list_splice(&head, n->list.prev); list_add_tail(&mnt->mnt_hash, mount_hashtable + hash(parent, mnt->mnt_mountpoint)); list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); - touch_namespace(n); + touch_mnt_namespace(n); } static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root) @@ -320,7 +320,7 @@ EXPORT_SYMBOL(mnt_unpin); /* iterator */ static void *m_start(struct seq_file *m, loff_t *pos) { - struct namespace *n = m->private; + struct mnt_namespace *n = m->private; struct list_head *p; loff_t l = *pos; @@ -333,7 +333,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) static void *m_next(struct seq_file *m, void *v, loff_t *pos) { - struct namespace *n = m->private; + struct mnt_namespace *n = m->private; struct list_head *p = ((struct vfsmount *)v)->mnt_list.next; (*pos)++; return p == &n->list ? NULL : list_entry(p, struct vfsmount, mnt_list); @@ -526,8 +526,8 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) list_for_each_entry(p, kill, mnt_hash) { list_del_init(&p->mnt_expire); list_del_init(&p->mnt_list); - __touch_namespace(p->mnt_namespace); - p->mnt_namespace = NULL; + __touch_mnt_namespace(p->mnt_ns); + p->mnt_ns = NULL; list_del_init(&p->mnt_child); if (p->mnt_parent != p) p->mnt_mountpoint->d_mounted--; @@ -830,7 +830,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, if (parent_nd) { detach_mnt(source_mnt, parent_nd); attach_mnt(source_mnt, nd); - touch_namespace(current->nsproxy->namespace); + touch_mnt_namespace(current->nsproxy->mnt_ns); } else { mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); commit_tree(source_mnt); @@ -1145,9 +1145,9 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts, */ if (!propagate_mount_busy(mnt, 2)) { /* delete from the namespace */ - touch_namespace(mnt->mnt_namespace); + touch_mnt_namespace(mnt->mnt_ns); list_del_init(&mnt->mnt_list); - mnt->mnt_namespace = NULL; + mnt->mnt_ns = NULL; umount_tree(mnt, 1, umounts); spin_unlock(&vfsmount_lock); } else { @@ -1168,7 +1168,7 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts, */ static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts) { - struct namespace *namespace; + struct mnt_namespace *ns; struct vfsmount *mnt; while (!list_empty(graveyard)) { @@ -1178,10 +1178,10 @@ static void expire_mount_list(struct list_head *graveyard, struct list_head *mou /* don't do anything if the namespace is dead - all the * vfsmounts from it are going away anyway */ - namespace = mnt->mnt_namespace; - if (!namespace || !namespace->root) + ns = mnt->mnt_ns; + if (!ns || !ns->root) continue; - get_namespace(namespace); + get_mnt_ns(ns); spin_unlock(&vfsmount_lock); down_write(&namespace_sem); @@ -1189,7 +1189,7 @@ static void expire_mount_list(struct list_head *graveyard, struct list_head *mou up_write(&namespace_sem); release_mounts(&umounts); mntput(mnt); - put_namespace(namespace); + put_mnt_ns(ns); spin_lock(&vfsmount_lock); } } @@ -1439,14 +1439,15 @@ dput_out: * Allocate a new namespace structure and populate it with contents * copied from the namespace of the passed in task structure. */ -struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) +struct mnt_namespace *dup_mnt_ns(struct task_struct *tsk, + struct fs_struct *fs) { - struct namespace *namespace = tsk->nsproxy->namespace; - struct namespace *new_ns; + struct mnt_namespace *mnt_ns = tsk->nsproxy->mnt_ns; + struct mnt_namespace *new_ns; struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; struct vfsmount *p, *q; - new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL); + new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); if (!new_ns) return NULL; @@ -1457,7 +1458,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) down_write(&namespace_sem); /* First pass: copy the tree topology */ - new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root, + new_ns->root = copy_tree(mnt_ns->root, mnt_ns->root->mnt_root, CL_COPY_ALL | CL_EXPIRE); if (!new_ns->root) { up_write(&namespace_sem); @@ -1473,10 +1474,10 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) * as belonging to new namespace. We have already acquired a private * fs_struct, so tsk->fs->lock is not needed. */ - p = namespace->root; + p = mnt_ns->root; q = new_ns->root; while (p) { - q->mnt_namespace = new_ns; + q->mnt_ns = new_ns; if (fs) { if (p == fs->rootmnt) { rootmnt = p; @@ -1491,7 +1492,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) fs->altrootmnt = mntget(q); } } - p = next_mnt(p, namespace->root); + p = next_mnt(p, mnt_ns->root); q = next_mnt(q, new_ns->root); } up_write(&namespace_sem); @@ -1506,16 +1507,16 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) return new_ns; } -int copy_namespace(int flags, struct task_struct *tsk) +int copy_mnt_ns(int flags, struct task_struct *tsk) { - struct namespace *namespace = tsk->nsproxy->namespace; - struct namespace *new_ns; + struct mnt_namespace *ns = tsk->nsproxy->mnt_ns; + struct mnt_namespace *new_ns; int err = 0; - if (!namespace) + if (!ns) return 0; - get_namespace(namespace); + get_mnt_ns(ns); if (!(flags & CLONE_NEWNS)) return 0; @@ -1525,16 +1526,16 @@ int copy_namespace(int flags, struct task_struct *tsk) goto out; } - new_ns = dup_namespace(tsk, tsk->fs); + new_ns = dup_mnt_ns(tsk, tsk->fs); if (!new_ns) { err = -ENOMEM; goto out; } - tsk->nsproxy->namespace = new_ns; + tsk->nsproxy->mnt_ns = new_ns; out: - put_namespace(namespace); + put_mnt_ns(ns); return err; } @@ -1754,7 +1755,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root, detach_mnt(user_nd.mnt, &root_parent); attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ - touch_namespace(current->nsproxy->namespace); + touch_mnt_namespace(current->nsproxy->mnt_ns); spin_unlock(&vfsmount_lock); chroot_fs_refs(&user_nd, &new_nd); security_sb_post_pivotroot(&user_nd, &new_nd); @@ -1779,27 +1780,27 @@ out3: static void __init init_mount_tree(void) { struct vfsmount *mnt; - struct namespace *namespace; + struct mnt_namespace *ns; mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); if (IS_ERR(mnt)) panic("Can't create rootfs"); - namespace = kmalloc(sizeof(*namespace), GFP_KERNEL); - if (!namespace) + ns = kmalloc(sizeof(*ns), GFP_KERNEL); + if (!ns) panic("Can't allocate initial namespace"); - atomic_set(&namespace->count, 1); - INIT_LIST_HEAD(&namespace->list); - init_waitqueue_head(&namespace->poll); - namespace->event = 0; - list_add(&mnt->mnt_list, &namespace->list); - namespace->root = mnt; - mnt->mnt_namespace = namespace; - - init_task.nsproxy->namespace = namespace; - get_namespace(namespace); - - set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root); - set_fs_root(current->fs, namespace->root, namespace->root->mnt_root); + atomic_set(&ns->count, 1); + INIT_LIST_HEAD(&ns->list); + init_waitqueue_head(&ns->poll); + ns->event = 0; + list_add(&mnt->mnt_list, &ns->list); + ns->root = mnt; + mnt->mnt_ns = ns; + + init_task.nsproxy->mnt_ns = ns; + get_mnt_ns(ns); + + set_fs_pwd(current->fs, ns->root, ns->root->mnt_root); + set_fs_root(current->fs, ns->root, ns->root->mnt_root); } void __init mnt_init(unsigned long mempages) @@ -1860,11 +1861,11 @@ void __init mnt_init(unsigned long mempages) init_mount_tree(); } -void __put_namespace(struct namespace *namespace) +void __put_mnt_ns(struct mnt_namespace *ns) { - struct vfsmount *root = namespace->root; + struct vfsmount *root = ns->root; LIST_HEAD(umount_list); - namespace->root = NULL; + ns->root = NULL; spin_unlock(&vfsmount_lock); down_write(&namespace_sem); spin_lock(&vfsmount_lock); @@ -1872,5 +1873,5 @@ void __put_namespace(struct namespace *namespace) spin_unlock(&vfsmount_lock); up_write(&namespace_sem); release_mounts(&umount_list); - kfree(namespace); + kfree(ns); } diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 20c6f39ea38a..8391bd7a83ce 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/fs/pnode.c b/fs/pnode.c index da42ee61c1df..56aacead8362 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -6,7 +6,7 @@ * Author : Ram Pai (linuxram@us.ibm.com) * */ -#include +#include #include #include #include "pnode.h" diff --git a/fs/pnode.h b/fs/pnode.h index 020e1bb60fdb..d45bd8ec36bf 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -13,7 +13,7 @@ #define IS_MNT_SHARED(mnt) (mnt->mnt_flags & MNT_SHARED) #define IS_MNT_SLAVE(mnt) (mnt->mnt_master) -#define IS_MNT_NEW(mnt) (!mnt->mnt_namespace) +#define IS_MNT_NEW(mnt) (!mnt->mnt_ns) #define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED) #define IS_MNT_UNBINDABLE(mnt) (mnt->mnt_flags & MNT_UNBINDABLE) diff --git a/fs/proc/base.c b/fs/proc/base.c index a71f1755bb57..a3b5074118a7 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -59,7 +59,7 @@ #include #include #include -#include +#include #include #include #include @@ -365,33 +365,33 @@ struct proc_mounts { static int mounts_open(struct inode *inode, struct file *file) { struct task_struct *task = get_proc_task(inode); - struct namespace *namespace = NULL; + struct mnt_namespace *ns = NULL; struct proc_mounts *p; int ret = -EINVAL; if (task) { task_lock(task); - namespace = task->nsproxy->namespace; - if (namespace) - get_namespace(namespace); + ns = task->nsproxy->mnt_ns; + if (ns) + get_mnt_ns(ns); task_unlock(task); put_task_struct(task); } - if (namespace) { + if (ns) { ret = -ENOMEM; p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); if (p) { file->private_data = &p->m; ret = seq_open(file, &mounts_op); if (!ret) { - p->m.private = namespace; - p->event = namespace->event; + p->m.private = ns; + p->event = ns->event; return 0; } kfree(p); } - put_namespace(namespace); + put_mnt_ns(ns); } return ret; } @@ -399,15 +399,15 @@ static int mounts_open(struct inode *inode, struct file *file) static int mounts_release(struct inode *inode, struct file *file) { struct seq_file *m = file->private_data; - struct namespace *namespace = m->private; - put_namespace(namespace); + struct mnt_namespace *ns = m->private; + put_mnt_ns(ns); return seq_release(inode, file); } static unsigned mounts_poll(struct file *file, poll_table *wait) { struct proc_mounts *p = file->private_data; - struct namespace *ns = p->m.private; + struct mnt_namespace *ns = p->m.private; unsigned res = 0; poll_wait(file, &ns->poll, wait); @@ -437,21 +437,21 @@ static int mountstats_open(struct inode *inode, struct file *file) if (!ret) { struct seq_file *m = file->private_data; - struct namespace *namespace = NULL; + struct mnt_namespace *mnt_ns = NULL; struct task_struct *task = get_proc_task(inode); if (task) { task_lock(task); if (task->nsproxy) - namespace = task->nsproxy->namespace; - if (namespace) - get_namespace(namespace); + mnt_ns = task->nsproxy->mnt_ns; + if (mnt_ns) + get_mnt_ns(mnt_ns); task_unlock(task); put_task_struct(task); } - if (namespace) - m->private = namespace; + if (mnt_ns) + m->private = mnt_ns; else { seq_release(inode, file); ret = -EINVAL; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 7fb5fb036f90..58ad4551a7c1 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 848a68af3d42..5c4989172f7e 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -76,7 +76,7 @@ extern struct nsproxy init_nsproxy; .count = ATOMIC_INIT(1), \ .nslock = __SPIN_LOCK_UNLOCKED(nsproxy.nslock), \ .uts_ns = &init_uts_ns, \ - .namespace = NULL, \ + .mnt_ns = NULL, \ INIT_IPC_NS(ipc_ns) \ } diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h new file mode 100644 index 000000000000..4af0b1fc282a --- /dev/null +++ b/include/linux/mnt_namespace.h @@ -0,0 +1,42 @@ +#ifndef _NAMESPACE_H_ +#define _NAMESPACE_H_ +#ifdef __KERNEL__ + +#include +#include +#include + +struct mnt_namespace { + atomic_t count; + struct vfsmount * root; + struct list_head list; + wait_queue_head_t poll; + int event; +}; + +extern int copy_mnt_ns(int, struct task_struct *); +extern void __put_mnt_ns(struct mnt_namespace *ns); +extern struct mnt_namespace *dup_mnt_ns(struct task_struct *, + struct fs_struct *); + +static inline void put_mnt_ns(struct mnt_namespace *ns) +{ + if (atomic_dec_and_lock(&ns->count, &vfsmount_lock)) + /* releases vfsmount_lock */ + __put_mnt_ns(ns); +} + +static inline void exit_mnt_ns(struct task_struct *p) +{ + struct mnt_namespace *ns = p->nsproxy->mnt_ns; + if (ns) + put_mnt_ns(ns); +} + +static inline void get_mnt_ns(struct mnt_namespace *ns) +{ + atomic_inc(&ns->count); +} + +#endif +#endif diff --git a/include/linux/mount.h b/include/linux/mount.h index 403d1a97c512..e357dc86a4de 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -20,7 +20,7 @@ struct super_block; struct vfsmount; struct dentry; -struct namespace; +struct mnt_namespace; #define MNT_NOSUID 0x01 #define MNT_NODEV 0x02 @@ -52,7 +52,7 @@ struct vfsmount { struct list_head mnt_slave_list;/* list of slave mounts */ struct list_head mnt_slave; /* slave list entry */ struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ - struct namespace *mnt_namespace; /* containing namespace */ + struct mnt_namespace *mnt_ns; /* containing namespace */ int mnt_pinned; }; diff --git a/include/linux/namespace.h b/include/linux/namespace.h deleted file mode 100644 index d137009f0b2b..000000000000 --- a/include/linux/namespace.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _NAMESPACE_H_ -#define _NAMESPACE_H_ -#ifdef __KERNEL__ - -#include -#include -#include - -struct namespace { - atomic_t count; - struct vfsmount * root; - struct list_head list; - wait_queue_head_t poll; - int event; -}; - -extern int copy_namespace(int, struct task_struct *); -extern void __put_namespace(struct namespace *namespace); -extern struct namespace *dup_namespace(struct task_struct *, struct fs_struct *); - -static inline void put_namespace(struct namespace *namespace) -{ - if (atomic_dec_and_lock(&namespace->count, &vfsmount_lock)) - /* releases vfsmount_lock */ - __put_namespace(namespace); -} - -static inline void exit_namespace(struct task_struct *p) -{ - struct namespace *namespace = p->nsproxy->namespace; - if (namespace) { - put_namespace(namespace); - } -} - -static inline void get_namespace(struct namespace *namespace) -{ - atomic_inc(&namespace->count); -} - -#endif -#endif diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index 971d1c6dfc4b..0aba1b1a39c7 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h @@ -4,7 +4,7 @@ #include #include -struct namespace; +struct mnt_namespace; struct uts_namespace; struct ipc_namespace; @@ -25,7 +25,7 @@ struct nsproxy { spinlock_t nslock; struct uts_namespace *uts_ns; struct ipc_namespace *ipc_ns; - struct namespace *namespace; + struct mnt_namespace *mnt_ns; }; extern struct nsproxy init_nsproxy; diff --git a/kernel/exit.c b/kernel/exit.c index 6267a6cc6113..28d9feedfd27 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/kernel/fork.c b/kernel/fork.c index 60d2644bfe85..8c859eef8e6a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -1525,17 +1525,18 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) } /* - * Unshare the namespace structure if it is being shared + * Unshare the mnt_namespace structure if it is being shared */ -static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) +static int unshare_mnt_namespace(unsigned long unshare_flags, + struct mnt_namespace **new_nsp, struct fs_struct *new_fs) { - struct namespace *ns = current->nsproxy->namespace; + struct mnt_namespace *ns = current->nsproxy->mnt_ns; if ((unshare_flags & CLONE_NEWNS) && ns) { if (!capable(CAP_SYS_ADMIN)) return -EPERM; - *new_nsp = dup_namespace(current, new_fs ? new_fs : current->fs); + *new_nsp = dup_mnt_ns(current, new_fs ? new_fs : current->fs); if (!*new_nsp) return -ENOMEM; } @@ -1623,7 +1624,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) { int err = 0; struct fs_struct *fs, *new_fs = NULL; - struct namespace *ns, *new_ns = NULL; + struct mnt_namespace *ns, *new_ns = NULL; struct sighand_struct *new_sigh = NULL; struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL; struct files_struct *fd, *new_fd = NULL; @@ -1645,7 +1646,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) goto bad_unshare_out; if ((err = unshare_fs(unshare_flags, &new_fs))) goto bad_unshare_cleanup_thread; - if ((err = unshare_namespace(unshare_flags, &new_ns, new_fs))) + if ((err = unshare_mnt_namespace(unshare_flags, &new_ns, new_fs))) goto bad_unshare_cleanup_fs; if ((err = unshare_sighand(unshare_flags, &new_sigh))) goto bad_unshare_cleanup_ns; @@ -1686,8 +1687,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) } if (new_ns) { - ns = current->nsproxy->namespace; - current->nsproxy->namespace = new_ns; + ns = current->nsproxy->mnt_ns; + current->nsproxy->mnt_ns = new_ns; new_ns = ns; } @@ -1748,7 +1749,7 @@ bad_unshare_cleanup_sigh: bad_unshare_cleanup_ns: if (new_ns) - put_namespace(new_ns); + put_mnt_ns(new_ns); bad_unshare_cleanup_fs: if (new_fs) diff --git a/kernel/kmod.c b/kernel/kmod.c index 8d2bea09a4ec..3a7379aa31ca 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 674aceb7335a..bd9cb435dfe0 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); @@ -60,8 +60,8 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) struct nsproxy *ns = clone_namespaces(orig); if (ns) { - if (ns->namespace) - get_namespace(ns->namespace); + if (ns->mnt_ns) + get_mnt_ns(ns->mnt_ns); if (ns->uts_ns) get_uts_ns(ns->uts_ns); if (ns->ipc_ns) @@ -97,7 +97,7 @@ int copy_namespaces(int flags, struct task_struct *tsk) tsk->nsproxy = new_ns; - err = copy_namespace(flags, tsk); + err = copy_mnt_ns(flags, tsk); if (err) goto out_ns; @@ -117,8 +117,8 @@ out_ipc: if (new_ns->uts_ns) put_uts_ns(new_ns->uts_ns); out_uts: - if (new_ns->namespace) - put_namespace(new_ns->namespace); + if (new_ns->mnt_ns) + put_mnt_ns(new_ns->mnt_ns); out_ns: tsk->nsproxy = old_ns; kfree(new_ns); @@ -127,8 +127,8 @@ out_ns: void free_nsproxy(struct nsproxy *ns) { - if (ns->namespace) - put_namespace(ns->namespace); + if (ns->mnt_ns) + put_mnt_ns(ns->mnt_ns); if (ns->uts_ns) put_uts_ns(ns->uts_ns); if (ns->ipc_ns) -- cgit v1.2.3 From 373beb35cd6b625e0ba4ad98baace12310a26aa8 Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Fri, 8 Dec 2006 02:37:57 -0800 Subject: [PATCH] identifier to nsproxy Add an identifier to nsproxy. The default init_ns_proxy has identifier 0 and allocated nsproxies are given -1. This identifier will be used by a new syscall sys_bind_ns. Signed-off-by: Cedric Le Goater Cc: Kirill Korotaev Cc: Eric W. Biederman Cc: Herbert Poetzl Cc: Sukadev Bhattiprolu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/init_task.h | 1 + include/linux/nsproxy.h | 1 + kernel/nsproxy.c | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 5c4989172f7e..90c5f9a07730 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -75,6 +75,7 @@ extern struct nsproxy init_nsproxy; #define INIT_NSPROXY(nsproxy) { \ .count = ATOMIC_INIT(1), \ .nslock = __SPIN_LOCK_UNLOCKED(nsproxy.nslock), \ + .id = 0, \ .uts_ns = &init_uts_ns, \ .mnt_ns = NULL, \ INIT_IPC_NS(ipc_ns) \ diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index 0aba1b1a39c7..27f37c1ec1d9 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h @@ -23,6 +23,7 @@ struct ipc_namespace; struct nsproxy { atomic_t count; spinlock_t nslock; + unsigned long id; struct uts_namespace *uts_ns; struct ipc_namespace *ipc_ns; struct mnt_namespace *mnt_ns; diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index bd9cb435dfe0..f223c15c18e9 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -45,8 +45,10 @@ static inline struct nsproxy *clone_namespaces(struct nsproxy *orig) struct nsproxy *ns; ns = kmemdup(orig, sizeof(struct nsproxy), GFP_KERNEL); - if (ns) + if (ns) { atomic_set(&ns->count, 1); + ns->id = -1; + } return ns; } -- cgit v1.2.3 From 61a58c6c238cc81f7742b8cc84212cc55fb57747 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Fri, 8 Dec 2006 02:37:58 -0800 Subject: [PATCH] rename struct pspace to struct pid_namespace Rename struct pspace to struct pid_namespace for consistency with other namespaces (uts_namespace and ipc_namespace). Also rename include/linux/pspace.h to include/linux/pid_namespace.h and variables from pspace to pid_ns. Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Cedric Le Goater Cc: Kirill Korotaev Cc: Eric W. Biederman Cc: Herbert Poetzl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/proc_misc.c | 4 ++-- include/linux/pid_namespace.h | 23 ++++++++++++++++++++ include/linux/pspace.h | 23 -------------------- kernel/pid.c | 49 ++++++++++++++++++++++--------------------- 4 files changed, 50 insertions(+), 49 deletions(-) create mode 100644 include/linux/pid_namespace.h delete mode 100644 include/linux/pspace.h (limited to 'include/linux') diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 9397ff62553e..89ccfa16b000 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include #include @@ -92,7 +92,7 @@ static int loadavg_read_proc(char *page, char **start, off_t off, LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), - nr_running(), nr_threads, init_pspace.last_pid); + nr_running(), nr_threads, init_pid_ns.last_pid); return proc_calc_metrics(page, start, off, count, eof, len); } diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h new file mode 100644 index 000000000000..54d79095e295 --- /dev/null +++ b/include/linux/pid_namespace.h @@ -0,0 +1,23 @@ +#ifndef _LINUX_PID_NS_H +#define _LINUX_PID_NS_H + +#include +#include +#include +#include + +struct pidmap { + atomic_t nr_free; + void *page; +}; + +#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8) + +struct pid_namespace { + struct pidmap pidmap[PIDMAP_ENTRIES]; + int last_pid; +}; + +extern struct pid_namespace init_pid_ns; + +#endif /* _LINUX_PID_NS_H */ diff --git a/include/linux/pspace.h b/include/linux/pspace.h deleted file mode 100644 index 91d48b8b2d99..000000000000 --- a/include/linux/pspace.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _LINUX_PSPACE_H -#define _LINUX_PSPACE_H - -#include -#include -#include -#include - -struct pidmap { - atomic_t nr_free; - void *page; -}; - -#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8) - -struct pspace { - struct pidmap pidmap[PIDMAP_ENTRIES]; - int last_pid; -}; - -extern struct pspace init_pspace; - -#endif /* _LINUX_PSPACE_H */ diff --git a/kernel/pid.c b/kernel/pid.c index a48879b0b921..25807e1b98dd 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) static struct hlist_head *pid_hash; @@ -43,9 +43,10 @@ int pid_max_max = PID_MAX_LIMIT; #define BITS_PER_PAGE (PAGE_SIZE*8) #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) -static inline int mk_pid(struct pspace *pspace, struct pidmap *map, int off) +static inline int mk_pid(struct pid_namespace *pid_ns, + struct pidmap *map, int off) { - return (map - pspace->pidmap)*BITS_PER_PAGE + off; + return (map - pid_ns->pidmap)*BITS_PER_PAGE + off; } #define find_next_offset(map, off) \ @@ -57,7 +58,7 @@ static inline int mk_pid(struct pspace *pspace, struct pidmap *map, int off) * value does not cause lots of bitmaps to be allocated, but * the scheme scales to up to 4 million PIDs, runtime. */ -struct pspace init_pspace = { +struct pid_namespace init_pid_ns = { .pidmap = { [ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } }, @@ -80,25 +81,25 @@ struct pspace init_pspace = { static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock); -static fastcall void free_pidmap(struct pspace *pspace, int pid) +static fastcall void free_pidmap(struct pid_namespace *pid_ns, int pid) { - struct pidmap *map = pspace->pidmap + pid / BITS_PER_PAGE; + struct pidmap *map = pid_ns->pidmap + pid / BITS_PER_PAGE; int offset = pid & BITS_PER_PAGE_MASK; clear_bit(offset, map->page); atomic_inc(&map->nr_free); } -static int alloc_pidmap(struct pspace *pspace) +static int alloc_pidmap(struct pid_namespace *pid_ns) { - int i, offset, max_scan, pid, last = pspace->last_pid; + int i, offset, max_scan, pid, last = pid_ns->last_pid; struct pidmap *map; pid = last + 1; if (pid >= pid_max) pid = RESERVED_PIDS; offset = pid & BITS_PER_PAGE_MASK; - map = &pspace->pidmap[pid/BITS_PER_PAGE]; + map = &pid_ns->pidmap[pid/BITS_PER_PAGE]; max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset; for (i = 0; i <= max_scan; ++i) { if (unlikely(!map->page)) { @@ -120,11 +121,11 @@ static int alloc_pidmap(struct pspace *pspace) do { if (!test_and_set_bit(offset, map->page)) { atomic_dec(&map->nr_free); - pspace->last_pid = pid; + pid_ns->last_pid = pid; return pid; } offset = find_next_offset(map, offset); - pid = mk_pid(pspace, map, offset); + pid = mk_pid(pid_ns, map, offset); /* * find_next_offset() found a bit, the pid from it * is in-bounds, and if we fell back to the last @@ -135,34 +136,34 @@ static int alloc_pidmap(struct pspace *pspace) (i != max_scan || pid < last || !((last+1) & BITS_PER_PAGE_MASK))); } - if (map < &pspace->pidmap[(pid_max-1)/BITS_PER_PAGE]) { + if (map < &pid_ns->pidmap[(pid_max-1)/BITS_PER_PAGE]) { ++map; offset = 0; } else { - map = &pspace->pidmap[0]; + map = &pid_ns->pidmap[0]; offset = RESERVED_PIDS; if (unlikely(last == offset)) break; } - pid = mk_pid(pspace, map, offset); + pid = mk_pid(pid_ns, map, offset); } return -1; } -static int next_pidmap(struct pspace *pspace, int last) +static int next_pidmap(struct pid_namespace *pid_ns, int last) { int offset; struct pidmap *map, *end; offset = (last + 1) & BITS_PER_PAGE_MASK; - map = &pspace->pidmap[(last + 1)/BITS_PER_PAGE]; - end = &pspace->pidmap[PIDMAP_ENTRIES]; + map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE]; + end = &pid_ns->pidmap[PIDMAP_ENTRIES]; for (; map < end; map++, offset = 0) { if (unlikely(!map->page)) continue; offset = find_next_bit((map)->page, BITS_PER_PAGE, offset); if (offset < BITS_PER_PAGE) - return mk_pid(pspace, map, offset); + return mk_pid(pid_ns, map, offset); } return -1; } @@ -192,7 +193,7 @@ fastcall void free_pid(struct pid *pid) hlist_del_rcu(&pid->pid_chain); spin_unlock_irqrestore(&pidmap_lock, flags); - free_pidmap(&init_pspace, pid->nr); + free_pidmap(&init_pid_ns, pid->nr); call_rcu(&pid->rcu, delayed_put_pid); } @@ -206,7 +207,7 @@ struct pid *alloc_pid(void) if (!pid) goto out; - nr = alloc_pidmap(&init_pspace); + nr = alloc_pidmap(&init_pid_ns); if (nr < 0) goto out_free; @@ -348,7 +349,7 @@ struct pid *find_ge_pid(int nr) pid = find_pid(nr); if (pid) break; - nr = next_pidmap(&init_pspace, nr); + nr = next_pidmap(&init_pid_ns, nr); } while (nr > 0); return pid; @@ -382,10 +383,10 @@ void __init pidhash_init(void) void __init pidmap_init(void) { - init_pspace.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); + init_pid_ns.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); /* Reserve PID 0. We never call free_pidmap(0) */ - set_bit(0, init_pspace.pidmap[0].page); - atomic_dec(&init_pspace.pidmap[0].nr_free); + set_bit(0, init_pid_ns.pidmap[0].page); + atomic_dec(&init_pid_ns.pidmap[0].nr_free); pid_cachep = kmem_cache_create("pid", sizeof(struct pid), __alignof__(struct pid), -- cgit v1.2.3 From 9a575a92db3312a40cdf0b0406d88de88ad9741e Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Fri, 8 Dec 2006 02:37:59 -0800 Subject: [PATCH] to nsproxy Add the pid namespace framework to the nsproxy object. The copy of the pid namespace only increases the refcount on the global pid namespace, init_pid_ns, and unshare is not implemented. There is no configuration option to activate or deactivate this feature because this not relevant for the moment. Signed-off-by: Cedric Le Goater Cc: Kirill Korotaev Cc: Eric W. Biederman Cc: Herbert Poetzl Cc: Sukadev Bhattiprolu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/init_task.h | 2 ++ include/linux/nsproxy.h | 2 ++ include/linux/pid_namespace.h | 20 ++++++++++++++++++-- kernel/nsproxy.c | 26 +++++++++++++++++++------- kernel/pid.c | 23 +++++++++++++++++++++++ 5 files changed, 64 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 90c5f9a07730..7272ff9ee77c 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -7,6 +7,7 @@ #include #include #include +#include #define INIT_FDTABLE \ { \ @@ -73,6 +74,7 @@ extern struct nsproxy init_nsproxy; #define INIT_NSPROXY(nsproxy) { \ + .pid_ns = &init_pid_ns, \ .count = ATOMIC_INIT(1), \ .nslock = __SPIN_LOCK_UNLOCKED(nsproxy.nslock), \ .id = 0, \ diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index 27f37c1ec1d9..fdfb0e44912f 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h @@ -7,6 +7,7 @@ struct mnt_namespace; struct uts_namespace; struct ipc_namespace; +struct pid_namespace; /* * A structure to contain pointers to all per-process @@ -27,6 +28,7 @@ struct nsproxy { struct uts_namespace *uts_ns; struct ipc_namespace *ipc_ns; struct mnt_namespace *mnt_ns; + struct pid_namespace *pid_ns; }; extern struct nsproxy init_nsproxy; diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index 54d79095e295..76e7c6b2cf33 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include struct pidmap { atomic_t nr_free; @@ -14,10 +16,24 @@ struct pidmap { #define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8) struct pid_namespace { - struct pidmap pidmap[PIDMAP_ENTRIES]; - int last_pid; + struct kref kref; + struct pidmap pidmap[PIDMAP_ENTRIES]; + int last_pid; }; extern struct pid_namespace init_pid_ns; +static inline void get_pid_ns(struct pid_namespace *ns) +{ + kref_get(&ns->kref); +} + +extern int copy_pid_ns(int flags, struct task_struct *tsk); +extern void free_pid_ns(struct kref *kref); + +static inline void put_pid_ns(struct pid_namespace *ns) +{ + kref_put(&ns->kref, free_pid_ns); +} + #endif /* _LINUX_PID_NS_H */ diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index f223c15c18e9..e2ce748e96af 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -19,6 +19,7 @@ #include #include #include +#include struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); @@ -68,6 +69,8 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) get_uts_ns(ns->uts_ns); if (ns->ipc_ns) get_ipc_ns(ns->ipc_ns); + if (ns->pid_ns) + get_pid_ns(ns->pid_ns); } return ns; @@ -111,10 +114,17 @@ int copy_namespaces(int flags, struct task_struct *tsk) if (err) goto out_ipc; + err = copy_pid_ns(flags, tsk); + if (err) + goto out_pid; + out: put_nsproxy(old_ns); return err; +out_pid: + if (new_ns->ipc_ns) + put_ipc_ns(new_ns->ipc_ns); out_ipc: if (new_ns->uts_ns) put_uts_ns(new_ns->uts_ns); @@ -129,11 +139,13 @@ out_ns: void free_nsproxy(struct nsproxy *ns) { - if (ns->mnt_ns) - put_mnt_ns(ns->mnt_ns); - if (ns->uts_ns) - put_uts_ns(ns->uts_ns); - if (ns->ipc_ns) - put_ipc_ns(ns->ipc_ns); - kfree(ns); + if (ns->mnt_ns) + put_mnt_ns(ns->mnt_ns); + if (ns->uts_ns) + put_uts_ns(ns->uts_ns); + if (ns->ipc_ns) + put_ipc_ns(ns->ipc_ns); + if (ns->pid_ns) + put_pid_ns(ns->pid_ns); + kfree(ns); } diff --git a/kernel/pid.c b/kernel/pid.c index 25807e1b98dd..5319b9f2fc5e 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -59,6 +59,9 @@ static inline int mk_pid(struct pid_namespace *pid_ns, * the scheme scales to up to 4 million PIDs, runtime. */ struct pid_namespace init_pid_ns = { + .kref = { + .refcount = ATOMIC_INIT(2), + }, .pidmap = { [ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } }, @@ -356,6 +359,26 @@ struct pid *find_ge_pid(int nr) } EXPORT_SYMBOL_GPL(find_get_pid); +int copy_pid_ns(int flags, struct task_struct *tsk) +{ + struct pid_namespace *old_ns = tsk->nsproxy->pid_ns; + int err = 0; + + if (!old_ns) + return 0; + + get_pid_ns(old_ns); + return err; +} + +void free_pid_ns(struct kref *kref) +{ + struct pid_namespace *ns; + + ns = container_of(kref, struct pid_namespace, kref); + kfree(ns); +} + /* * The pid hash table is scaled according to the amount of memory in the * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or -- cgit v1.2.3 From 84d737866e2babdeab0c6b18ea155c6a649663b8 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Fri, 8 Dec 2006 02:38:01 -0800 Subject: [PATCH] add child reaper to pid_namespace Add a per pid_namespace child-reaper. This is needed so processes are reaped within the same pid space and do not spill over to the parent pid space. Its also needed so containers preserve existing semantic that pid == 1 would reap orphaned children. This is based on Eric Biederman's patch: http://lkml.org/lkml/2006/2/6/285 Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Cedric Le Goater Cc: Kirill Korotaev Cc: Eric W. Biederman Cc: Herbert Poetzl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/exec.c | 5 +++-- include/linux/pid.h | 5 +++-- include/linux/pid_namespace.h | 6 ++++++ include/linux/sched.h | 1 - init/main.c | 5 ++--- kernel/exit.c | 23 +++++++++++++++-------- kernel/pid.c | 3 ++- kernel/signal.c | 11 +++++++++-- 8 files changed, 40 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/fs/exec.c b/fs/exec.c index 60433e2254a4..12d8cd461b41 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -620,8 +621,8 @@ static int de_thread(struct task_struct *tsk) * Reparenting needs write_lock on tasklist_lock, * so it is safe to do it under read_lock. */ - if (unlikely(tsk->group_leader == child_reaper)) - child_reaper = tsk; + if (unlikely(tsk->group_leader == child_reaper(tsk))) + tsk->nsproxy->pid_ns->child_reaper = tsk; zap_other_threads(tsk); read_unlock(&tasklist_lock); diff --git a/include/linux/pid.h b/include/linux/pid.h index 2c0007d17218..4dec047b1837 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -35,8 +35,9 @@ enum pid_type * * Holding a reference to struct pid solves both of these problems. * It is small so holding a reference does not consume a lot of - * resources, and since a new struct pid is allocated when the numeric - * pid value is reused we don't mistakenly refer to new processes. + * resources, and since a new struct pid is allocated when the numeric pid + * value is reused (when pids wrap around) we don't mistakenly refer to new + * processes. */ struct pid diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index 76e7c6b2cf33..d2a9d419f01f 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -19,6 +19,7 @@ struct pid_namespace { struct kref kref; struct pidmap pidmap[PIDMAP_ENTRIES]; int last_pid; + struct task_struct *child_reaper; }; extern struct pid_namespace init_pid_ns; @@ -36,4 +37,9 @@ static inline void put_pid_ns(struct pid_namespace *ns) kref_put(&ns->kref, free_pid_ns); } +static inline struct task_struct *child_reaper(struct task_struct *tsk) +{ + return tsk->nsproxy->pid_ns->child_reaper; +} + #endif /* _LINUX_PID_NS_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 6fec1d419714..f0317edea141 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1400,7 +1400,6 @@ extern NORET_TYPE void do_group_exit(int); extern void daemonize(const char *, ...); extern int allow_signal(int); extern int disallow_signal(int); -extern struct task_struct *child_reaper; extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *); extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *); diff --git a/init/main.c b/init/main.c index 4cdcd06e6d78..036f97c0c34c 100644 --- a/init/main.c +++ b/init/main.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -626,8 +627,6 @@ static int __init initcall_debug_setup(char *str) } __setup("initcall_debug", initcall_debug_setup); -struct task_struct *child_reaper = &init_task; - extern initcall_t __initcall_start[], __initcall_end[]; static void __init do_initcalls(void) @@ -727,7 +726,7 @@ static int init(void * unused) * assumptions about where in the task array this * can be found. */ - child_reaper = current; + init_pid_ns.child_reaper = current; cad_pid = task_pid(current); diff --git a/kernel/exit.c b/kernel/exit.c index 28d9feedfd27..fd0e067952ab 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -48,7 +49,6 @@ #include extern void sem_exit (void); -extern struct task_struct *child_reaper; static void exit_mm(struct task_struct * tsk); @@ -260,7 +260,8 @@ static int has_stopped_jobs(int pgrp) } /** - * reparent_to_init - Reparent the calling kernel thread to the init task. + * reparent_to_init - Reparent the calling kernel thread to the init task + * of the pid space that the thread belongs to. * * If a kernel thread is launched as a result of a system call, or if * it ever exits, it should generally reparent itself to init so that @@ -278,8 +279,8 @@ static void reparent_to_init(void) ptrace_unlink(current); /* Reparent to init */ remove_parent(current); - current->parent = child_reaper; - current->real_parent = child_reaper; + current->parent = child_reaper(current); + current->real_parent = child_reaper(current); add_parent(current); /* Set the exit signal to SIGCHLD so we signal init on exit */ @@ -662,7 +663,8 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced) * When we die, we re-parent all our children. * Try to give them to another thread in our thread * group, and if no such member exists, give it to - * the global child reaper process (ie "init") + * the child reaper process (ie "init") in our pid + * space. */ static void forget_original_parent(struct task_struct *father, struct list_head *to_release) @@ -673,7 +675,7 @@ forget_original_parent(struct task_struct *father, struct list_head *to_release) do { reaper = next_thread(reaper); if (reaper == father) { - reaper = child_reaper; + reaper = child_reaper(father); break; } } while (reaper->exit_state); @@ -859,8 +861,13 @@ fastcall NORET_TYPE void do_exit(long code) panic("Aiee, killing interrupt handler!"); if (unlikely(!tsk->pid)) panic("Attempted to kill the idle task!"); - if (unlikely(tsk == child_reaper)) - panic("Attempted to kill init!"); + if (unlikely(tsk == child_reaper(tsk))) { + if (tsk->nsproxy->pid_ns != &init_pid_ns) + tsk->nsproxy->pid_ns->child_reaper = init_pid_ns.child_reaper; + else + panic("Attempted to kill init!"); + } + if (unlikely(current->ptrace & PT_TRACE_EXIT)) { current->ptrace_message = code; diff --git a/kernel/pid.c b/kernel/pid.c index 1d9cc268b499..2efe9d8d367b 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -65,7 +65,8 @@ struct pid_namespace init_pid_ns = { .pidmap = { [ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } }, - .last_pid = 0 + .last_pid = 0, + .child_reaper = &init_task }; /* diff --git a/kernel/signal.c b/kernel/signal.c index 9eac4db60eda..1921ffdc5e77 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -24,6 +24,9 @@ #include #include #include +#include +#include + #include #include #include @@ -1877,8 +1880,12 @@ relock: if (sig_kernel_ignore(signr)) /* Default is nothing. */ continue; - /* Init gets no signals it doesn't want. */ - if (current == child_reaper) + /* + * Init of a pid space gets no signals it doesn't want from + * within that pid space. It can of course get signals from + * its parent pid space. + */ + if (current == child_reaper(current)) continue; if (sig_kernel_stop(signr)) { -- cgit v1.2.3 From 3306ce3d0554e2e59cc429b7133e17e1513307cb Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 8 Dec 2006 02:38:13 -0800 Subject: [PATCH] Char: mxser_new, upgrade to 1.9.1 Change cloned experimental driver according to original 1.9.1 moxa driver. Some int->ulong conversions, outb ~UART_IER_THRI constant. Remove commented stuff. I also added printk line with info, if somebody wants to test it, he may contact me as I can potentially debug the driver with him or just to confirm it works properly. Signed-off-by: Jiri Slaby Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/mxser_new.c | 396 +++++++++++++++++++++++------------------------ include/linux/pci_ids.h | 3 + 2 files changed, 195 insertions(+), 204 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index 993e3a26c406..befff0548da3 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c @@ -1,7 +1,7 @@ /* * mxser.c -- MOXA Smartio/Industio family multiport serial driver. * - * Copyright (C) 1999-2001 Moxa Technologies (support@moxa.com.tw). + * Copyright (C) 1999-2006 Moxa Technologies (support@moxa.com.tw). * * This code is loosely based on the Linux serial driver, written by * Linus Torvalds, Theodore T'so and others. @@ -20,15 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Original release 10/26/00 - * - * 02/06/01 Support MOXA Industio family boards. - * 02/06/01 Support TIOCGICOUNT. - * 02/06/01 Fix the problem for connecting to serial mouse. - * 02/06/01 Fix the problem for H/W flow control. - * 02/06/01 Fix the compling warning when CONFIG_PCI - * don't be defined. - * * Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox * . The original 1.8 code is available on www.moxa.com. * - Fixed x86_64 cleanness @@ -66,7 +57,7 @@ #include "mxser_new.h" -#define MXSER_VERSION "1.8" +#define MXSER_VERSION "1.9.1" #define MXSERMAJOR 174 #define MXSERCUMAJOR 175 @@ -76,7 +67,7 @@ #define MXSER_BOARDS 4 /* Max. boards */ #define MXSER_PORTS 32 /* Max. ports */ #define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */ -#define MXSER_ISR_PASS_LIMIT 256 +#define MXSER_ISR_PASS_LIMIT 99999L #define MXSER_ERR_IOADDR -1 #define MXSER_ERR_IRQ -2 @@ -125,6 +116,9 @@ enum { MXSER_BOARD_CP118U, MXSER_BOARD_CP102UL, MXSER_BOARD_CP102U, + MXSER_BOARD_CP118EL, + MXSER_BOARD_CP168EL, + MXSER_BOARD_CP104EL }; static char *mxser_brdname[] = { @@ -149,6 +143,9 @@ static char *mxser_brdname[] = { "CP-118U series", "CP-102UL series", "CP-102U series", + "CP-118EL series", + "CP-168EL series", + "CP-104EL series" }; static int mxser_numports[] = { @@ -173,6 +170,9 @@ static int mxser_numports[] = { 8, /* CP118U */ 2, /* CP102UL */ 2, /* CP102U */ + 8, /* CP118EL */ + 8, /* CP168EL */ + 4 /* CP104EL */ }; #define UART_TYPE_NUM 2 @@ -205,22 +205,43 @@ static const struct mxpciuart_info Gpci_uart_info[UART_INFO_NUM] = { #ifdef CONFIG_PCI static struct pci_device_id mxser_pcibrds[] = { - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C168_PCI}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C104_PCI}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP132}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP114}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CT114}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP104U}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP168U}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP132U}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP134U}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP104JU}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_RC7000}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP118U}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102UL}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102U}, - {0} + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168), + .driver_data = MXSER_BOARD_C168_PCI }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104), + .driver_data = MXSER_BOARD_C104_PCI }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132), + .driver_data = MXSER_BOARD_CP132 }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114), + .driver_data = MXSER_BOARD_CP114 }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114), + .driver_data = MXSER_BOARD_CT114 }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102), + .driver_data = MXSER_BOARD_CP102 }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U), + .driver_data = MXSER_BOARD_CP104U }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U), + .driver_data = MXSER_BOARD_CP168U }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U), + .driver_data = MXSER_BOARD_CP132U }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U), + .driver_data = MXSER_BOARD_CP134U }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU), + .driver_data = MXSER_BOARD_CP104JU }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000), + .driver_data = MXSER_BOARD_RC7000 }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U), + .driver_data = MXSER_BOARD_CP118U }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL), + .driver_data = MXSER_BOARD_CP102UL }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U), + .driver_data = MXSER_BOARD_CP102U }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL), + .driver_data = MXSER_BOARD_CP118EL }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL), + .driver_data = MXSER_BOARD_CP168EL }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL), + .driver_data = MXSER_BOARD_CP104EL }, + { } }; MODULE_DEVICE_TABLE(pci, mxser_pcibrds); @@ -245,7 +266,6 @@ MODULE_AUTHOR("Casper Yang"); MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver"); module_param_array(ioaddr, int, NULL, 0); module_param(ttymajor, int, 0); -module_param(calloutmajor, int, 0); module_param(verbose, bool, 0); MODULE_LICENSE("GPL"); @@ -285,23 +305,23 @@ struct mxser_hwconf { int board_type; int ports; int irq; - int vector; - int vector_mask; + unsigned long vector; + unsigned long vector_mask; int uart_type; - int ioaddr[MXSER_PORTS_PER_BOARD]; + unsigned long ioaddr[MXSER_PORTS_PER_BOARD]; int baud_base[MXSER_PORTS_PER_BOARD]; moxa_pci_info pciInfo; int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */ int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 09-04-2002 */ - int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 01-05-2004 */ + unsigned long opmode_ioaddr[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 01-05-2004 */ }; struct mxser_struct { int port; - int base; /* port base address */ + unsigned long base; /* port base address */ int irq; /* port using irq no. */ - int vector; /* port irq vector */ - int vectormask; /* port vector mask */ + unsigned long vector; /* port irq vector */ + unsigned long vectormask; /* port vector mask */ int rx_high_water; int rx_trigger; /* Rx fifo trigger level */ int rx_low_water; @@ -337,7 +357,7 @@ struct mxser_struct { int timeout; int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */ int MaxCanSetBaudRate; /* add by Victor Yu. 09-04-2002 */ - int opmode_ioaddr; /* add by Victor Yu. 01-05-2004 */ + unsigned long opmode_ioaddr; /* add by Victor Yu. 01-05-2004 */ unsigned char stop_rx; unsigned char ldisc_stop_rx; long realbaud; @@ -485,6 +505,9 @@ static int __init mxser_module_init(void) if (verbose) printk(KERN_DEBUG "Loading module mxser ...\n"); + printk(KERN_INFO "This is mxser driver version 1.9.1 and needs TESTING." + "If your are willing to test this driver, please report to " + "jirislaby@gmail.com. Thanks.\n"); ret = mxser_init(); if (verbose) printk(KERN_DEBUG "Done.\n"); @@ -636,7 +659,7 @@ static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxs { int i, j; /* unsigned int val; */ - unsigned int ioaddress; + unsigned long ioaddress; struct pci_dev *pdev = hwconf->pciInfo.pdev; /* io address */ @@ -790,7 +813,7 @@ static int mxser_init(void) /* Start finding ISA boards from module arg */ for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { - int cap; + unsigned long cap; if (!(cap = ioaddr[b])) continue; @@ -928,12 +951,10 @@ static void mxser_do_softint(void *private_) tty = info->tty; - if (tty) { - if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) - tty_wakeup(tty); - if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) - tty_hangup(tty); - } + if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) + tty_wakeup(tty); + if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) + tty_hangup(tty); } static unsigned char mxser_get_msr(int baseaddr, int mode, int port, struct mxser_struct *info) @@ -979,6 +1000,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) /* * Start up serial port */ + info->count++; retval = mxser_startup(info); if (retval) return retval; @@ -987,8 +1009,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) if (retval) return retval; - info->count++; - if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver->subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; @@ -1150,11 +1170,13 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou total += c; } - if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) { + if (info->xmit_cnt && !tty->stopped + /*&& !(info->IER & UART_IER_THRI)*/) { if (!tty->hw_stopped || (info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) { spin_lock_irqsave(&info->slock, flags); + outb(info->IER & ~UART_IER_THRI, info->base + UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); spin_unlock_irqrestore(&info->slock, flags); @@ -1179,11 +1201,12 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch) info->xmit_head &= SERIAL_XMIT_SIZE - 1; info->xmit_cnt++; spin_unlock_irqrestore(&info->slock, flags); - if (!tty->stopped && !(info->IER & UART_IER_THRI)) { + if (!tty->stopped /*&& !(info->IER & UART_IER_THRI)*/) { if (!tty->hw_stopped || (info->type == PORT_16550A) || info->IsMoxaMustChipFlag) { spin_lock_irqsave(&info->slock, flags); + outb(info->IER & ~UART_IER_THRI, info->base + UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); spin_unlock_irqrestore(&info->slock, flags); @@ -1208,6 +1231,7 @@ static void mxser_flush_chars(struct tty_struct *tty) spin_lock_irqsave(&info->slock, flags); + outb(info->IER & ~UART_IER_THRI, info->base + UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); @@ -1228,7 +1252,12 @@ static int mxser_write_room(struct tty_struct *tty) static int mxser_chars_in_buffer(struct tty_struct *tty) { struct mxser_struct *info = tty->driver_data; - return info->xmit_cnt; + int len = info->xmit_cnt; + + if (!(inb(info->base + UART_LSR) & UART_LSR_THRE)) + len++; + + return len; } static void mxser_flush_buffer(struct tty_struct *tty) @@ -1270,7 +1299,8 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c /* following add by Victor Yu. 01-05-2004 */ if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) { - int opmode, p; + int p; + unsigned long opmode; static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f }; int shiftbit; unsigned char val, mask; @@ -1572,9 +1602,8 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) return -EFAULT; return 0; case MOXA_ASPP_MON_EXT: { - int status; - int opmode, p; - int shiftbit; + int status, p, shiftbit; + unsigned long opmode; unsigned cflag, iflag; for (i = 0; i < MXSER_PORTS; i++) { @@ -1654,73 +1683,52 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) static void mxser_stoprx(struct tty_struct *tty) { struct mxser_struct *info = tty->driver_data; - /* unsigned long flags; */ info->ldisc_stop_rx = 1; if (I_IXOFF(tty)) { - /* MX_LOCK(&info->slock); */ /* following add by Victor Yu. 09-02-2002 */ if (info->IsMoxaMustChipFlag) { info->IER &= ~MOXA_MUST_RECV_ISR; outb(info->IER, info->base + UART_IER); - } else { - /* above add by Victor Yu. 09-02-2002 */ + } else if (!(info->flags & ASYNC_CLOSING)) { info->x_char = STOP_CHAR(tty); - /* mask by Victor Yu. 09-02-2002 */ - /* outb(info->IER, 0); */ outb(0, info->base + UART_IER); info->IER |= UART_IER_THRI; - /* force Tx interrupt */ outb(info->IER, info->base + UART_IER); - } /* add by Victor Yu. 09-02-2002 */ - /* MX_UNLOCK(&info->slock); */ + } } if (info->tty->termios->c_cflag & CRTSCTS) { - /* MX_LOCK(&info->slock); */ info->MCR &= ~UART_MCR_RTS; outb(info->MCR, info->base + UART_MCR); - /* MX_UNLOCK(&info->slock); */ } } static void mxser_startrx(struct tty_struct *tty) { struct mxser_struct *info = tty->driver_data; - /* unsigned long flags; */ info->ldisc_stop_rx = 0; if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; else { - /* MX_LOCK(&info->slock); */ - /* following add by Victor Yu. 09-02-2002 */ if (info->IsMoxaMustChipFlag) { info->IER |= MOXA_MUST_RECV_ISR; outb(info->IER, info->base + UART_IER); - } else { - /* above add by Victor Yu. 09-02-2002 */ - + } else if (!(info->flags & ASYNC_CLOSING)) { info->x_char = START_CHAR(tty); - /* mask by Victor Yu. 09-02-2002 */ - /* outb(info->IER, 0); */ - /* add by Victor Yu. 09-02-2002 */ outb(0, info->base + UART_IER); - /* force Tx interrupt */ info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); - } /* add by Victor Yu. 09-02-2002 */ - /* MX_UNLOCK(&info->slock); */ + } } } if (info->tty->termios->c_cflag & CRTSCTS) { - /* MX_LOCK(&info->slock); */ info->MCR |= UART_MCR_RTS; outb(info->MCR, info->base + UART_MCR); - /* MX_UNLOCK(&info->slock); */ } } @@ -1730,22 +1738,22 @@ static void mxser_startrx(struct tty_struct *tty) */ static void mxser_throttle(struct tty_struct *tty) { - /* struct mxser_struct *info = tty->driver_data; */ - /* unsigned long flags; */ + struct mxser_struct *info = tty->driver_data; + unsigned long flags; - /* MX_LOCK(&info->slock); */ + spin_lock_irqsave(&info->slock, flags); mxser_stoprx(tty); - /* MX_UNLOCK(&info->slock); */ + spin_unlock_irqrestore(&info->slock, flags); } static void mxser_unthrottle(struct tty_struct *tty) { - /* struct mxser_struct *info = tty->driver_data; */ - /* unsigned long flags; */ + struct mxser_struct *info = tty->driver_data; + unsigned long flags; - /* MX_LOCK(&info->slock); */ + spin_lock_irqsave(&info->slock, flags); mxser_startrx(tty); - /* MX_UNLOCK(&info->slock); */ + spin_unlock_irqrestore(&info->slock, flags); } static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios) @@ -1807,7 +1815,9 @@ static void mxser_start(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->slock, flags); - if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { + if (info->xmit_cnt && info->xmit_buf + /* && !(info->IER & UART_IER_THRI) */) { + outb(info->IER & ~UART_IER_THRI, info->base + UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); } @@ -1927,6 +1937,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct mxser_struct *port; int max, irqbits, bits, msr; int pass_counter = 0; + unsigned int int_cnt; int handled = IRQ_NONE; port = NULL; @@ -1957,90 +1968,77 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) continue; info = port + i; - /* following add by Victor Yu. 09-13-2002 */ - iir = inb(info->base + UART_IIR); - if (iir & UART_IIR_NO_INT) - continue; - iir &= MOXA_MUST_IIR_MASK; - if (!info->tty) { - status = inb(info->base + UART_LSR); - outb(0x27, info->base + UART_FCR); - inb(info->base + UART_MSR); - continue; - } - /* above add by Victor Yu. 09-13-2002 */ - /* - if (info->tty->flip.count < TTY_FLIPBUF_SIZE / 4) { - info->IER |= MOXA_MUST_RECV_ISR; - outb(info->IER, info->base + UART_IER); - } - */ - - - /* mask by Victor Yu. 09-13-2002 - if ( !info->tty || - (inb(info->base + UART_IIR) & UART_IIR_NO_INT) ) - continue; - */ - /* mask by Victor Yu. 09-02-2002 - status = inb(info->base + UART_LSR) & info->read_status_mask; - */ - - /* following add by Victor Yu. 09-02-2002 */ - status = inb(info->base + UART_LSR); + int_cnt = 0; + do { + /* following add by Victor Yu. 09-13-2002 */ + iir = inb(info->base + UART_IIR); + if (iir & UART_IIR_NO_INT) + break; + iir &= MOXA_MUST_IIR_MASK; + if (!info->tty) { + status = inb(info->base + UART_LSR); + outb(0x27, info->base + UART_FCR); + inb(info->base + UART_MSR); + break; + } + /* above add by Victor Yu. 09-13-2002 */ - if (status & UART_LSR_PE) - info->err_shadow |= NPPI_NOTIFY_PARITY; - if (status & UART_LSR_FE) - info->err_shadow |= NPPI_NOTIFY_FRAMING; - if (status & UART_LSR_OE) - info->err_shadow |= NPPI_NOTIFY_HW_OVERRUN; - if (status & UART_LSR_BI) - info->err_shadow |= NPPI_NOTIFY_BREAK; + spin_lock(&info->slock); + /* following add by Victor Yu. 09-02-2002 */ + status = inb(info->base + UART_LSR); - if (info->IsMoxaMustChipFlag) { - /* - if ( (status & 0x02) && !(status & 0x01) ) { - outb(info->base+UART_FCR, 0x23); - continue; - } - */ - if (iir == MOXA_MUST_IIR_GDA || - iir == MOXA_MUST_IIR_RDA || - iir == MOXA_MUST_IIR_RTO || - iir == MOXA_MUST_IIR_LSR) - mxser_receive_chars(info, &status); + if (status & UART_LSR_PE) + info->err_shadow |= NPPI_NOTIFY_PARITY; + if (status & UART_LSR_FE) + info->err_shadow |= NPPI_NOTIFY_FRAMING; + if (status & UART_LSR_OE) + info->err_shadow |= + NPPI_NOTIFY_HW_OVERRUN; + if (status & UART_LSR_BI) + info->err_shadow |= NPPI_NOTIFY_BREAK; + + if (info->IsMoxaMustChipFlag) { + /* + if ( (status & 0x02) && !(status & 0x01) ) { + outb(info->base+UART_FCR, 0x23); + continue; + } + */ + if (iir == MOXA_MUST_IIR_GDA || + iir == MOXA_MUST_IIR_RDA || + iir == MOXA_MUST_IIR_RTO || + iir == MOXA_MUST_IIR_LSR) + mxser_receive_chars(info, + &status); - } else { - /* above add by Victor Yu. 09-02-2002 */ + } else { + /* above add by Victor Yu. 09-02-2002 */ - status &= info->read_status_mask; - if (status & UART_LSR_DR) - mxser_receive_chars(info, &status); - } - msr = inb(info->base + UART_MSR); - if (msr & UART_MSR_ANY_DELTA) { - mxser_check_modem_status(info, msr); - } - /* following add by Victor Yu. 09-13-2002 */ - if (info->IsMoxaMustChipFlag) { - if ((iir == 0x02) && (status & UART_LSR_THRE)) { - mxser_transmit_chars(info); + status &= info->read_status_mask; + if (status & UART_LSR_DR) + mxser_receive_chars(info, + &status); } - } else { - /* above add by Victor Yu. 09-13-2002 */ + msr = inb(info->base + UART_MSR); + if (msr & UART_MSR_ANY_DELTA) + mxser_check_modem_status(info, msr); + + /* following add by Victor Yu. 09-13-2002 */ + if (info->IsMoxaMustChipFlag) { + if (iir == 0x02 && (status & + UART_LSR_THRE)) + mxser_transmit_chars(info); + } else { + /* above add by Victor Yu. 09-13-2002 */ - if (status & UART_LSR_THRE) { -/* 8-2-99 by William - if ( info->x_char || (info->xmit_cnt > 0) ) -*/ - mxser_transmit_chars(info); + if (status & UART_LSR_THRE) + mxser_transmit_chars(info); } - } + spin_unlock(&info->slock); + } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); } - if (pass_counter++ > MXSER_ISR_PASS_LIMIT) { + if (pass_counter++ > MXSER_ISR_PASS_LIMIT) break; /* Prevent infinite loops */ - } } irq_stop: @@ -2070,9 +2068,8 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status) /* following add by Victor Yu. 09-02-2002 */ if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) { - if (*status & UART_LSR_SPECIAL) { + if (*status & UART_LSR_SPECIAL) goto intr_old; - } /* following add by Victor Yu. 02-11-2004 */ if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID && (*status & MOXA_MUST_LSR_RERR)) @@ -2097,12 +2094,6 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status) ch = inb(info->base + UART_RX); tty_insert_flip_char(tty, ch, 0); cnt++; - /* - if ((cnt >= HI_WATER) && (info->stop_rx == 0)) { - mxser_stoprx(tty); - info->stop_rx = 1; - break; - } */ } goto end_intr; } @@ -2112,17 +2103,11 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status) do { if (max-- < 0) break; - /* - if ((cnt >= HI_WATER) && (info->stop_rx == 0)) { - mxser_stoprx(tty); - info->stop_rx=1; - break; - } - */ ch = inb(info->base + UART_RX); /* following add by Victor Yu. 09-02-2002 */ - if (info->IsMoxaMustChipFlag && (*status & UART_LSR_OE) /*&& !(*status&UART_LSR_DR) */ ) + if (info->IsMoxaMustChipFlag && (*status & UART_LSR_OE) + /*&& !(*status&UART_LSR_DR) */) outb(0x23, info->base + UART_FCR); *status &= info->read_status_mask; /* above add by Victor Yu. 09-02-2002 */ @@ -2136,26 +2121,25 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status) flag = TTY_BREAK; /* added by casper 1/11/2000 */ info->icount.brk++; -/* */ + if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (*status & UART_LSR_PE) { flag = TTY_PARITY; /* added by casper 1/11/2000 */ info->icount.parity++; -/* */ } else if (*status & UART_LSR_FE) { flag = TTY_FRAME; /* added by casper 1/11/2000 */ info->icount.frame++; -/* */ } else if (*status & UART_LSR_OE) { flag = TTY_OVERRUN; /* added by casper 1/11/2000 */ info->icount.overrun++; -/* */ - } - } + } else + flags = TTY_BREAK; + } else + flags = 0; tty_insert_flip_char(tty, ch, flag); cnt++; if (cnt >= recv_room) { @@ -2171,7 +2155,6 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status) /* following add by Victor Yu. 09-02-2002 */ if (info->IsMoxaMustChipFlag) break; - /* above add by Victor Yu. 09-02-2002 */ /* mask by Victor Yu. 09-02-2002 *status = inb(info->base + UART_LSR) & info->read_status_mask; @@ -2206,24 +2189,25 @@ static void mxser_transmit_chars(struct mxser_struct *info) /* added by casper 1/11/2000 */ info->icount.tx++; -/* */ - spin_unlock_irqrestore(&info->slock, flags); - return; + goto unlock; } - if (info->xmit_buf == 0) { - spin_unlock_irqrestore(&info->slock, flags); - return; - } + if (info->xmit_buf == 0) + goto unlock; - if ((info->xmit_cnt <= 0) || info->tty->stopped || - (info->tty->hw_stopped && + if (info->xmit_cnt == 0) { + if (info->xmit_cnt < WAKEUP_CHARS) { /* XXX what's this for?? */ + set_bit(MXSER_EVENT_TXLOW, &info->event); + schedule_work(&info->tqueue); + } + goto unlock; + } + if (info->tty->stopped || (info->tty->hw_stopped && (info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag))) { info->IER &= ~UART_IER_THRI; outb(info->IER, info->base + UART_IER); - spin_unlock_irqrestore(&info->slock, flags); - return; + goto unlock; } cnt = info->xmit_cnt; @@ -2240,11 +2224,9 @@ static void mxser_transmit_chars(struct mxser_struct *info) /* added by James 03-12-2004. */ info->mon_data.txcnt += (cnt - info->xmit_cnt); info->mon_data.up_txcnt += (cnt - info->xmit_cnt); -/* (above) added by James. */ /* added by casper 1/11/2000 */ info->icount.tx += (cnt - info->xmit_cnt); -/* */ if (info->xmit_cnt < WAKEUP_CHARS) { set_bit(MXSER_EVENT_TXLOW, &info->event); @@ -2254,6 +2236,7 @@ static void mxser_transmit_chars(struct mxser_struct *info) info->IER &= ~UART_IER_THRI; outb(info->IER, info->base + UART_IER); } +unlock: spin_unlock_irqrestore(&info->slock, flags); } @@ -2284,16 +2267,19 @@ static void mxser_check_modem_status(struct mxser_struct *info, int status) if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) { + outb(info->IER & ~UART_IER_THRI, + info->base + UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); } set_bit(MXSER_EVENT_TXLOW, &info->event); - schedule_work(&info->tqueue); } + schedule_work(&info->tqueue); + } } else { if (!(status & UART_MSR_CTS)) { info->tty->hw_stopped = 1; - if ((info->type != PORT_16550A) && - (!info->IsMoxaMustChipFlag)) { + if (info->type != PORT_16550A && + !info->IsMoxaMustChipFlag) { info->IER &= ~UART_IER_THRI; outb(info->IER, info->base + UART_IER); } @@ -2645,8 +2631,10 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter if (info->tty->hw_stopped) { if (status & UART_MSR_CTS) { info->tty->hw_stopped = 0; - if ((info->type != PORT_16550A) && - (!info->IsMoxaMustChipFlag)) { + if (info->type != PORT_16550A && + !info->IsMoxaMustChipFlag) { + outb(info->IER & ~UART_IER_THRI, + info->base + UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); } diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 4d972bbef316..51180dba9a98 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1785,14 +1785,17 @@ #define PCI_DEVICE_ID_MOXA_C104 0x1040 #define PCI_DEVICE_ID_MOXA_CP104U 0x1041 #define PCI_DEVICE_ID_MOXA_CP104JU 0x1042 +#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043 #define PCI_DEVICE_ID_MOXA_CT114 0x1140 #define PCI_DEVICE_ID_MOXA_CP114 0x1141 #define PCI_DEVICE_ID_MOXA_CP118U 0x1180 +#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181 #define PCI_DEVICE_ID_MOXA_CP132 0x1320 #define PCI_DEVICE_ID_MOXA_CP132U 0x1321 #define PCI_DEVICE_ID_MOXA_CP134U 0x1340 #define PCI_DEVICE_ID_MOXA_C168 0x1680 #define PCI_DEVICE_ID_MOXA_CP168U 0x1681 +#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682 #define PCI_VENDOR_ID_CCD 0x1397 #define PCI_DEVICE_ID_CCD_2BD0 0x2bd0 -- cgit v1.2.3 From ca7ed0f22f4876986b2eb1fbd80ba78e07fd69d5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 8 Dec 2006 02:38:39 -0800 Subject: [PATCH] Char: stallion, kill typedefs Typedefs are considered ugly in the kernel. Eliminate them. Signed-off-by: Jiri Slaby Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/stallion.c | 458 +++++++++++++++++++++++------------------------ include/linux/stallion.h | 24 +-- 2 files changed, 239 insertions(+), 243 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 6a6e5124a5fa..b108ac6e3d83 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -88,16 +88,14 @@ * PCI BIOS32 support is compiled into the kernel. */ -typedef struct { +static struct stlconf { int brdtype; int ioaddr1; int ioaddr2; unsigned long memaddr; int irq; int irqtype; -} stlconf_t; - -static stlconf_t stl_brdconf[] = { +} stl_brdconf[] = { /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/ }; @@ -154,8 +152,8 @@ static struct termios stl_deftermios = { */ static comstats_t stl_comstats; static combrd_t stl_brdstats; -static stlbrd_t stl_dummybrd; -static stlport_t stl_dummyport; +static struct stlbrd stl_dummybrd; +static struct stlport stl_dummyport; /* * Define global place to put buffer overflow characters. @@ -164,7 +162,7 @@ static char stl_unwanted[SC26198_RXFIFOSIZE]; /*****************************************************************************/ -static stlbrd_t *stl_brds[STL_MAXBRDS]; +static struct stlbrd *stl_brds[STL_MAXBRDS]; /* * Per board state flags. Used with the state field of the board struct. @@ -243,12 +241,10 @@ static char **stl_brdsp[] = { * parse any module arguments. */ -typedef struct stlbrdtype { +static struct { char *name; int type; -} stlbrdtype_t; - -static stlbrdtype_t stl_brdstr[] = { +} stl_brdstr[] = { { "easyio", BRD_EASYIO }, { "eio", BRD_EASYIO }, { "20", BRD_EASYIO }, @@ -458,7 +454,7 @@ static unsigned int stl_baudrates[] = { */ static void stl_argbrds(void); -static int stl_parsebrd(stlconf_t *confp, char **argp); +static int stl_parsebrd(struct stlconf *confp, char **argp); static unsigned long stl_atol(char *str); @@ -482,31 +478,31 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout); static void stl_sendxchar(struct tty_struct *tty, char ch); static void stl_hangup(struct tty_struct *tty); static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); -static int stl_portinfo(stlport_t *portp, int portnr, char *pos); +static int stl_portinfo(struct stlport *portp, int portnr, char *pos); static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data); -static int stl_brdinit(stlbrd_t *brdp); -static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp); -static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp); -static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp); +static int stl_brdinit(struct stlbrd *brdp); +static int stl_initports(struct stlbrd *brdp, struct stlpanel *panelp); +static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp); +static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp); static int stl_getbrdstats(combrd_t __user *bp); -static int stl_getportstats(stlport_t *portp, comstats_t __user *cp); -static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp); -static int stl_getportstruct(stlport_t __user *arg); -static int stl_getbrdstruct(stlbrd_t __user *arg); -static int stl_waitcarrier(stlport_t *portp, struct file *filp); -static int stl_eiointr(stlbrd_t *brdp); -static int stl_echatintr(stlbrd_t *brdp); -static int stl_echmcaintr(stlbrd_t *brdp); -static int stl_echpciintr(stlbrd_t *brdp); -static int stl_echpci64intr(stlbrd_t *brdp); +static int stl_getportstats(struct stlport *portp, comstats_t __user *cp); +static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp); +static int stl_getportstruct(struct stlport __user *arg); +static int stl_getbrdstruct(struct stlbrd __user *arg); +static int stl_waitcarrier(struct stlport *portp, struct file *filp); +static int stl_eiointr(struct stlbrd *brdp); +static int stl_echatintr(struct stlbrd *brdp); +static int stl_echmcaintr(struct stlbrd *brdp); +static int stl_echpciintr(struct stlbrd *brdp); +static int stl_echpci64intr(struct stlbrd *brdp); static void stl_offintr(struct work_struct *); -static stlbrd_t *stl_allocbrd(void); -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); +static struct stlbrd *stl_allocbrd(void); +static struct stlport *stl_getport(int brdnr, int panelnr, int portnr); static inline int stl_initbrds(void); -static inline int stl_initeio(stlbrd_t *brdp); -static inline int stl_initech(stlbrd_t *brdp); +static inline int stl_initeio(struct stlbrd *brdp); +static inline int stl_initech(struct stlbrd *brdp); static inline int stl_getbrdnr(void); #ifdef CONFIG_PCI @@ -517,59 +513,59 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp); /* * CD1400 uart specific handling functions. */ -static void stl_cd1400setreg(stlport_t *portp, int regnr, int value); -static int stl_cd1400getreg(stlport_t *portp, int regnr); -static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value); -static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp); -static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); -static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp); -static int stl_cd1400getsignals(stlport_t *portp); -static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts); -static void stl_cd1400ccrwait(stlport_t *portp); -static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx); -static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx); -static void stl_cd1400disableintrs(stlport_t *portp); -static void stl_cd1400sendbreak(stlport_t *portp, int len); -static void stl_cd1400flowctrl(stlport_t *portp, int state); -static void stl_cd1400sendflow(stlport_t *portp, int state); -static void stl_cd1400flush(stlport_t *portp); -static int stl_cd1400datastate(stlport_t *portp); -static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase); -static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase); -static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr); -static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr); -static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr); - -static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr); +static void stl_cd1400setreg(struct stlport *portp, int regnr, int value); +static int stl_cd1400getreg(struct stlport *portp, int regnr); +static int stl_cd1400updatereg(struct stlport *portp, int regnr, int value); +static int stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp); +static void stl_cd1400portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp); +static void stl_cd1400setport(struct stlport *portp, struct termios *tiosp); +static int stl_cd1400getsignals(struct stlport *portp); +static void stl_cd1400setsignals(struct stlport *portp, int dtr, int rts); +static void stl_cd1400ccrwait(struct stlport *portp); +static void stl_cd1400enablerxtx(struct stlport *portp, int rx, int tx); +static void stl_cd1400startrxtx(struct stlport *portp, int rx, int tx); +static void stl_cd1400disableintrs(struct stlport *portp); +static void stl_cd1400sendbreak(struct stlport *portp, int len); +static void stl_cd1400flowctrl(struct stlport *portp, int state); +static void stl_cd1400sendflow(struct stlport *portp, int state); +static void stl_cd1400flush(struct stlport *portp); +static int stl_cd1400datastate(struct stlport *portp); +static void stl_cd1400eiointr(struct stlpanel *panelp, unsigned int iobase); +static void stl_cd1400echintr(struct stlpanel *panelp, unsigned int iobase); +static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr); +static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr); +static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr); + +static inline int stl_cd1400breakisr(struct stlport *portp, int ioaddr); /* * SC26198 uart specific handling functions. */ -static void stl_sc26198setreg(stlport_t *portp, int regnr, int value); -static int stl_sc26198getreg(stlport_t *portp, int regnr); -static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value); -static int stl_sc26198getglobreg(stlport_t *portp, int regnr); -static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp); -static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); -static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp); -static int stl_sc26198getsignals(stlport_t *portp); -static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts); -static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx); -static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx); -static void stl_sc26198disableintrs(stlport_t *portp); -static void stl_sc26198sendbreak(stlport_t *portp, int len); -static void stl_sc26198flowctrl(stlport_t *portp, int state); -static void stl_sc26198sendflow(stlport_t *portp, int state); -static void stl_sc26198flush(stlport_t *portp); -static int stl_sc26198datastate(stlport_t *portp); -static void stl_sc26198wait(stlport_t *portp); -static void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty); -static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase); -static void stl_sc26198txisr(stlport_t *port); -static void stl_sc26198rxisr(stlport_t *port, unsigned int iack); -static void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch); -static void stl_sc26198rxbadchars(stlport_t *portp); -static void stl_sc26198otherisr(stlport_t *port, unsigned int iack); +static void stl_sc26198setreg(struct stlport *portp, int regnr, int value); +static int stl_sc26198getreg(struct stlport *portp, int regnr); +static int stl_sc26198updatereg(struct stlport *portp, int regnr, int value); +static int stl_sc26198getglobreg(struct stlport *portp, int regnr); +static int stl_sc26198panelinit(struct stlbrd *brdp, struct stlpanel *panelp); +static void stl_sc26198portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp); +static void stl_sc26198setport(struct stlport *portp, struct termios *tiosp); +static int stl_sc26198getsignals(struct stlport *portp); +static void stl_sc26198setsignals(struct stlport *portp, int dtr, int rts); +static void stl_sc26198enablerxtx(struct stlport *portp, int rx, int tx); +static void stl_sc26198startrxtx(struct stlport *portp, int rx, int tx); +static void stl_sc26198disableintrs(struct stlport *portp); +static void stl_sc26198sendbreak(struct stlport *portp, int len); +static void stl_sc26198flowctrl(struct stlport *portp, int state); +static void stl_sc26198sendflow(struct stlport *portp, int state); +static void stl_sc26198flush(struct stlport *portp); +static int stl_sc26198datastate(struct stlport *portp); +static void stl_sc26198wait(struct stlport *portp); +static void stl_sc26198txunflow(struct stlport *portp, struct tty_struct *tty); +static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase); +static void stl_sc26198txisr(struct stlport *port); +static void stl_sc26198rxisr(struct stlport *port, unsigned int iack); +static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char ch); +static void stl_sc26198rxbadchars(struct stlport *portp); +static void stl_sc26198otherisr(struct stlport *port, unsigned int iack); /*****************************************************************************/ @@ -577,20 +573,20 @@ static void stl_sc26198otherisr(stlport_t *port, unsigned int iack); * Generic UART support structure. */ typedef struct uart { - int (*panelinit)(stlbrd_t *brdp, stlpanel_t *panelp); - void (*portinit)(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); - void (*setport)(stlport_t *portp, struct termios *tiosp); - int (*getsignals)(stlport_t *portp); - void (*setsignals)(stlport_t *portp, int dtr, int rts); - void (*enablerxtx)(stlport_t *portp, int rx, int tx); - void (*startrxtx)(stlport_t *portp, int rx, int tx); - void (*disableintrs)(stlport_t *portp); - void (*sendbreak)(stlport_t *portp, int len); - void (*flowctrl)(stlport_t *portp, int state); - void (*sendflow)(stlport_t *portp, int state); - void (*flush)(stlport_t *portp); - int (*datastate)(stlport_t *portp); - void (*intr)(stlpanel_t *panelp, unsigned int iobase); + int (*panelinit)(struct stlbrd *brdp, struct stlpanel *panelp); + void (*portinit)(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp); + void (*setport)(struct stlport *portp, struct termios *tiosp); + int (*getsignals)(struct stlport *portp); + void (*setsignals)(struct stlport *portp, int dtr, int rts); + void (*enablerxtx)(struct stlport *portp, int rx, int tx); + void (*startrxtx)(struct stlport *portp, int rx, int tx); + void (*disableintrs)(struct stlport *portp); + void (*sendbreak)(struct stlport *portp, int len); + void (*flowctrl)(struct stlport *portp, int state); + void (*sendflow)(struct stlport *portp, int state); + void (*flush)(struct stlport *portp); + int (*datastate)(struct stlport *portp); + void (*intr)(struct stlpanel *panelp, unsigned int iobase); } uart_t; /* @@ -730,9 +726,9 @@ static int __init stallion_module_init(void) static void __exit stallion_module_exit(void) { - stlbrd_t *brdp; - stlpanel_t *panelp; - stlport_t *portp; + struct stlbrd *brdp; + struct stlpanel *panelp; + struct stlport *portp; int i, j, k; pr_debug("cleanup_module()\n"); @@ -802,8 +798,8 @@ module_exit(stallion_module_exit); static void stl_argbrds(void) { - stlconf_t conf; - stlbrd_t *brdp; + struct stlconf conf; + struct stlbrd *brdp; int i; pr_debug("stl_argbrds()\n"); @@ -867,7 +863,7 @@ static unsigned long stl_atol(char *str) * Parse the supplied argument string, into the board conf struct. */ -static int stl_parsebrd(stlconf_t *confp, char **argp) +static int stl_parsebrd(struct stlconf *confp, char **argp) { char *sp; int i; @@ -911,14 +907,14 @@ static int stl_parsebrd(stlconf_t *confp, char **argp) * Allocate a new board structure. Fill out the basic info in it. */ -static stlbrd_t *stl_allocbrd(void) +static struct stlbrd *stl_allocbrd(void) { - stlbrd_t *brdp; + struct stlbrd *brdp; - brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL); + brdp = kzalloc(sizeof(struct stlbrd), GFP_KERNEL); if (!brdp) { printk("STALLION: failed to allocate memory (size=%Zd)\n", - sizeof(stlbrd_t)); + sizeof(struct stlbrd)); return NULL; } @@ -930,8 +926,8 @@ static stlbrd_t *stl_allocbrd(void) static int stl_open(struct tty_struct *tty, struct file *filp) { - stlport_t *portp; - stlbrd_t *brdp; + struct stlport *portp; + struct stlbrd *brdp; unsigned int minordev; int brdnr, panelnr, portnr, rc; @@ -1020,7 +1016,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * maybe because if we are clocal then we don't need to wait... */ -static int stl_waitcarrier(stlport_t *portp, struct file *filp) +static int stl_waitcarrier(struct stlport *portp, struct file *filp) { unsigned long flags; int rc, doclocal; @@ -1074,7 +1070,7 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp) static void stl_close(struct tty_struct *tty, struct file *filp) { - stlport_t *portp; + struct stlport *portp; unsigned long flags; pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp); @@ -1154,7 +1150,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp) static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count) { - stlport_t *portp; + struct stlport *portp; unsigned int len, stlen; unsigned char *chbuf; char *head, *tail; @@ -1211,7 +1207,7 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count static void stl_putchar(struct tty_struct *tty, unsigned char ch) { - stlport_t *portp; + struct stlport *portp; unsigned int len; char *head, *tail; @@ -1249,7 +1245,7 @@ static void stl_putchar(struct tty_struct *tty, unsigned char ch) static void stl_flushchars(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; pr_debug("stl_flushchars(tty=%p)\n", tty); @@ -1268,7 +1264,7 @@ static void stl_flushchars(struct tty_struct *tty) static int stl_writeroom(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; char *head, *tail; pr_debug("stl_writeroom(tty=%p)\n", tty); @@ -1299,7 +1295,7 @@ static int stl_writeroom(struct tty_struct *tty) static int stl_charsinbuffer(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; unsigned int size; char *head, *tail; @@ -1327,10 +1323,10 @@ static int stl_charsinbuffer(struct tty_struct *tty) * Generate the serial struct info. */ -static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp) +static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp) { struct serial_struct sio; - stlbrd_t *brdp; + struct stlbrd *brdp; pr_debug("stl_getserial(portp=%p,sp=%p)\n", portp, sp); @@ -1366,7 +1362,7 @@ static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp) * just quietly ignore any requests to change irq, etc. */ -static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp) +static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp) { struct serial_struct sio; @@ -1396,7 +1392,7 @@ static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp) static int stl_tiocmget(struct tty_struct *tty, struct file *file) { - stlport_t *portp; + struct stlport *portp; if (tty == NULL) return -ENODEV; @@ -1412,7 +1408,7 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file) static int stl_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - stlport_t *portp; + struct stlport *portp; int rts = -1, dtr = -1; if (tty == NULL) @@ -1438,7 +1434,7 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file, static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - stlport_t *portp; + struct stlport *portp; unsigned int ival; int rc; void __user *argp = (void __user *)arg; @@ -1503,7 +1499,7 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd static void stl_settermios(struct tty_struct *tty, struct termios *old) { - stlport_t *portp; + struct stlport *portp; struct termios *tiosp; pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old); @@ -1539,7 +1535,7 @@ static void stl_settermios(struct tty_struct *tty, struct termios *old) static void stl_throttle(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; pr_debug("stl_throttle(tty=%p)\n", tty); @@ -1559,7 +1555,7 @@ static void stl_throttle(struct tty_struct *tty) static void stl_unthrottle(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; pr_debug("stl_unthrottle(tty=%p)\n", tty); @@ -1580,7 +1576,7 @@ static void stl_unthrottle(struct tty_struct *tty) static void stl_stop(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; pr_debug("stl_stop(tty=%p)\n", tty); @@ -1600,7 +1596,7 @@ static void stl_stop(struct tty_struct *tty) static void stl_start(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; pr_debug("stl_start(tty=%p)\n", tty); @@ -1622,7 +1618,7 @@ static void stl_start(struct tty_struct *tty) static void stl_hangup(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; pr_debug("stl_hangup(tty=%p)\n", tty); @@ -1656,7 +1652,7 @@ static void stl_hangup(struct tty_struct *tty) static void stl_flushbuffer(struct tty_struct *tty) { - stlport_t *portp; + struct stlport *portp; pr_debug("stl_flushbuffer(tty=%p)\n", tty); @@ -1674,7 +1670,7 @@ static void stl_flushbuffer(struct tty_struct *tty) static void stl_breakctl(struct tty_struct *tty, int state) { - stlport_t *portp; + struct stlport *portp; pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state); @@ -1691,7 +1687,7 @@ static void stl_breakctl(struct tty_struct *tty, int state) static void stl_waituntilsent(struct tty_struct *tty, int timeout) { - stlport_t *portp; + struct stlport *portp; unsigned long tend; pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout); @@ -1719,7 +1715,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) static void stl_sendxchar(struct tty_struct *tty, char ch) { - stlport_t *portp; + struct stlport *portp; pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch); @@ -1747,7 +1743,7 @@ static void stl_sendxchar(struct tty_struct *tty, char ch) * short then padded with spaces). */ -static int stl_portinfo(stlport_t *portp, int portnr, char *pos) +static int stl_portinfo(struct stlport *portp, int portnr, char *pos) { char *sp; int sigs, cnt; @@ -1793,9 +1789,9 @@ static int stl_portinfo(stlport_t *portp, int portnr, char *pos) static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data) { - stlbrd_t *brdp; - stlpanel_t *panelp; - stlport_t *portp; + struct stlbrd *brdp; + struct stlpanel *panelp; + struct stlport *portp; int brdnr, panelnr, portnr, totalport; int curoff, maxoff; char *pos; @@ -1876,7 +1872,7 @@ stl_readdone: static irqreturn_t stl_intr(int irq, void *dev_id) { - stlbrd_t *brdp = dev_id; + struct stlbrd *brdp = dev_id; pr_debug("stl_intr(brdp=%p,irq=%d)\n", brdp, irq); @@ -1889,9 +1885,9 @@ static irqreturn_t stl_intr(int irq, void *dev_id) * Interrupt service routine for EasyIO board types. */ -static int stl_eiointr(stlbrd_t *brdp) +static int stl_eiointr(struct stlbrd *brdp) { - stlpanel_t *panelp; + struct stlpanel *panelp; unsigned int iobase; int handled = 0; @@ -1912,9 +1908,9 @@ static int stl_eiointr(stlbrd_t *brdp) * Interrupt service routine for ECH-AT board types. */ -static int stl_echatintr(stlbrd_t *brdp) +static int stl_echatintr(struct stlbrd *brdp) { - stlpanel_t *panelp; + struct stlpanel *panelp; unsigned int ioaddr; int bnknr; int handled = 0; @@ -1943,9 +1939,9 @@ static int stl_echatintr(stlbrd_t *brdp) * Interrupt service routine for ECH-MCA board types. */ -static int stl_echmcaintr(stlbrd_t *brdp) +static int stl_echmcaintr(struct stlbrd *brdp) { - stlpanel_t *panelp; + struct stlpanel *panelp; unsigned int ioaddr; int bnknr; int handled = 0; @@ -1969,9 +1965,9 @@ static int stl_echmcaintr(stlbrd_t *brdp) * Interrupt service routine for ECH-PCI board types. */ -static int stl_echpciintr(stlbrd_t *brdp) +static int stl_echpciintr(struct stlbrd *brdp) { - stlpanel_t *panelp; + struct stlpanel *panelp; unsigned int ioaddr; int bnknr, recheck; int handled = 0; @@ -2000,9 +1996,9 @@ static int stl_echpciintr(stlbrd_t *brdp) * Interrupt service routine for ECH-8/64-PCI board types. */ -static int stl_echpci64intr(stlbrd_t *brdp) +static int stl_echpci64intr(struct stlbrd *brdp) { - stlpanel_t *panelp; + struct stlpanel *panelp; unsigned int ioaddr; int bnknr; int handled = 0; @@ -2028,7 +2024,7 @@ static int stl_echpci64intr(stlbrd_t *brdp) */ static void stl_offintr(struct work_struct *work) { - stlport_t *portp = container_of(work, stlport_t, tqueue); + struct stlport *portp = container_of(work, struct stlport, tqueue); struct tty_struct *tty; unsigned int oldsigs; @@ -2065,9 +2061,9 @@ static void stl_offintr(struct work_struct *work) * Initialize all the ports on a panel. */ -static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) +static int __init stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) { - stlport_t *portp; + struct stlport *portp; int chipmask, i; pr_debug("stl_initports(brdp=%p,panelp=%p)\n", brdp, panelp); @@ -2079,10 +2075,10 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) * each ports data structures. */ for (i = 0; (i < panelp->nrports); i++) { - portp = kzalloc(sizeof(stlport_t), GFP_KERNEL); + portp = kzalloc(sizeof(struct stlport), GFP_KERNEL); if (!portp) { printk("STALLION: failed to allocate memory " - "(size=%Zd)\n", sizeof(stlport_t)); + "(size=%Zd)\n", sizeof(struct stlport)); break; } @@ -2114,9 +2110,9 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) * Try to find and initialize an EasyIO board. */ -static inline int stl_initeio(stlbrd_t *brdp) +static inline int stl_initeio(struct stlbrd *brdp) { - stlpanel_t *panelp; + struct stlpanel *panelp; unsigned int status; char *name; int rc; @@ -2213,10 +2209,10 @@ static inline int stl_initeio(stlbrd_t *brdp) * can complete the setup. */ - panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL); + panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL); if (!panelp) { printk(KERN_WARNING "STALLION: failed to allocate memory " - "(size=%Zd)\n", sizeof(stlpanel_t)); + "(size=%Zd)\n", sizeof(struct stlpanel)); return -ENOMEM; } @@ -2255,9 +2251,9 @@ static inline int stl_initeio(stlbrd_t *brdp) * dealing with all types of ECH board. */ -static inline int stl_initech(stlbrd_t *brdp) +static inline int stl_initech(struct stlbrd *brdp) { - stlpanel_t *panelp; + struct stlpanel *panelp; unsigned int status, nxtid, ioaddr, conflict; int panelnr, banknr, i; char *name; @@ -2385,10 +2381,10 @@ static inline int stl_initech(stlbrd_t *brdp) status = inb(ioaddr + ECH_PNLSTATUS); if ((status & ECH_PNLIDMASK) != nxtid) break; - panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL); + panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL); if (!panelp) { printk("STALLION: failed to allocate memory " - "(size=%Zd)\n", sizeof(stlpanel_t)); + "(size=%Zd)\n", sizeof(struct stlpanel)); break; } panelp->magic = STL_PANELMAGIC; @@ -2466,7 +2462,7 @@ static inline int stl_initech(stlbrd_t *brdp) * since the initial search and setup is very different. */ -static int __init stl_brdinit(stlbrd_t *brdp) +static int __init stl_brdinit(struct stlbrd *brdp) { int i; @@ -2540,7 +2536,7 @@ static inline int stl_getbrdnr(void) static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp) { - stlbrd_t *brdp; + struct stlbrd *brdp; pr_debug("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype, devp->bus->number, devp->devfn); @@ -2638,8 +2634,8 @@ static inline int stl_findpcibrds(void) static inline int stl_initbrds(void) { - stlbrd_t *brdp; - stlconf_t *confp; + struct stlbrd *brdp; + struct stlconf *confp; int i; pr_debug("stl_initbrds()\n"); @@ -2688,8 +2684,8 @@ static inline int stl_initbrds(void) static int stl_getbrdstats(combrd_t __user *bp) { - stlbrd_t *brdp; - stlpanel_t *panelp; + struct stlbrd *brdp; + struct stlpanel *panelp; int i; if (copy_from_user(&stl_brdstats, bp, sizeof(combrd_t))) @@ -2726,10 +2722,10 @@ static int stl_getbrdstats(combrd_t __user *bp) * Resolve the referenced port number into a port struct pointer. */ -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) +static struct stlport *stl_getport(int brdnr, int panelnr, int portnr) { - stlbrd_t *brdp; - stlpanel_t *panelp; + struct stlbrd *brdp; + struct stlpanel *panelp; if ((brdnr < 0) || (brdnr >= STL_MAXBRDS)) return(NULL); @@ -2754,7 +2750,7 @@ static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) * what port to get stats for (used through board control device). */ -static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) +static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) { unsigned char *head, *tail; unsigned long flags; @@ -2812,7 +2808,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) * Clear the port stats structure. We also return it zeroed out... */ -static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp) +static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp) { if (!portp) { if (copy_from_user(&stl_comstats, cp, sizeof(comstats_t))) @@ -2837,17 +2833,17 @@ static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp) * Return the entire driver ports structure to a user app. */ -static int stl_getportstruct(stlport_t __user *arg) +static int stl_getportstruct(struct stlport __user *arg) { - stlport_t *portp; + struct stlport *portp; - if (copy_from_user(&stl_dummyport, arg, sizeof(stlport_t))) + if (copy_from_user(&stl_dummyport, arg, sizeof(struct stlport))) return -EFAULT; portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr, stl_dummyport.portnr); if (!portp) return -ENODEV; - return copy_to_user(arg, portp, sizeof(stlport_t)) ? -EFAULT : 0; + return copy_to_user(arg, portp, sizeof(struct stlport)) ? -EFAULT : 0; } /*****************************************************************************/ @@ -2856,18 +2852,18 @@ static int stl_getportstruct(stlport_t __user *arg) * Return the entire driver board structure to a user app. */ -static int stl_getbrdstruct(stlbrd_t __user *arg) +static int stl_getbrdstruct(struct stlbrd __user *arg) { - stlbrd_t *brdp; + struct stlbrd *brdp; - if (copy_from_user(&stl_dummybrd, arg, sizeof(stlbrd_t))) + if (copy_from_user(&stl_dummybrd, arg, sizeof(struct stlbrd))) return -EFAULT; if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS)) return -ENODEV; brdp = stl_brds[stl_dummybrd.brdnr]; if (!brdp) return(-ENODEV); - return copy_to_user(arg, brdp, sizeof(stlbrd_t)) ? -EFAULT : 0; + return copy_to_user(arg, brdp, sizeof(struct stlbrd)) ? -EFAULT : 0; } /*****************************************************************************/ @@ -2997,19 +2993,19 @@ static int __init stl_init(void) * (Maybe should make this inline...) */ -static int stl_cd1400getreg(stlport_t *portp, int regnr) +static int stl_cd1400getreg(struct stlport *portp, int regnr) { outb((regnr + portp->uartaddr), portp->ioaddr); return inb(portp->ioaddr + EREG_DATA); } -static void stl_cd1400setreg(stlport_t *portp, int regnr, int value) +static void stl_cd1400setreg(struct stlport *portp, int regnr, int value) { outb((regnr + portp->uartaddr), portp->ioaddr); outb(value, portp->ioaddr + EREG_DATA); } -static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value) +static int stl_cd1400updatereg(struct stlport *portp, int regnr, int value) { outb((regnr + portp->uartaddr), portp->ioaddr); if (inb(portp->ioaddr + EREG_DATA) != value) { @@ -3027,7 +3023,7 @@ static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value) * identical when dealing with ports. */ -static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) +static int stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp) { unsigned int gfrcr; int chipmask, i, j; @@ -3084,7 +3080,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) * Initialize hardware specific port registers. */ -static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) +static void stl_cd1400portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp) { unsigned long flags; pr_debug("stl_cd1400portinit(brdp=%p,panelp=%p,portp=%p)\n", brdp, @@ -3115,7 +3111,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po * since it won't usually take too long to be ready. */ -static void stl_cd1400ccrwait(stlport_t *portp) +static void stl_cd1400ccrwait(struct stlport *portp) { int i; @@ -3136,9 +3132,9 @@ static void stl_cd1400ccrwait(stlport_t *portp) * settings. */ -static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) +static void stl_cd1400setport(struct stlport *portp, struct termios *tiosp) { - stlbrd_t *brdp; + struct stlbrd *brdp; unsigned long flags; unsigned int clkdiv, baudrate; unsigned char cor1, cor2, cor3; @@ -3359,7 +3355,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) * Set the state of the DTR and RTS signals. */ -static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) +static void stl_cd1400setsignals(struct stlport *portp, int dtr, int rts) { unsigned char msvr1, msvr2; unsigned long flags; @@ -3391,7 +3387,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) * Return the state of the signals. */ -static int stl_cd1400getsignals(stlport_t *portp) +static int stl_cd1400getsignals(struct stlport *portp) { unsigned char msvr1, msvr2; unsigned long flags; @@ -3427,7 +3423,7 @@ static int stl_cd1400getsignals(stlport_t *portp) * Enable/Disable the Transmitter and/or Receiver. */ -static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) +static void stl_cd1400enablerxtx(struct stlport *portp, int rx, int tx) { unsigned char ccr; unsigned long flags; @@ -3461,7 +3457,7 @@ static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) * Start/stop the Transmitter and/or Receiver. */ -static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) +static void stl_cd1400startrxtx(struct stlport *portp, int rx, int tx) { unsigned char sreron, sreroff; unsigned long flags; @@ -3498,7 +3494,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) * Disable all interrupts from this port. */ -static void stl_cd1400disableintrs(stlport_t *portp) +static void stl_cd1400disableintrs(struct stlport *portp) { unsigned long flags; @@ -3514,7 +3510,7 @@ static void stl_cd1400disableintrs(stlport_t *portp) /*****************************************************************************/ -static void stl_cd1400sendbreak(stlport_t *portp, int len) +static void stl_cd1400sendbreak(struct stlport *portp, int len) { unsigned long flags; @@ -3539,7 +3535,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len) * Take flow control actions... */ -static void stl_cd1400flowctrl(stlport_t *portp, int state) +static void stl_cd1400flowctrl(struct stlport *portp, int state) { struct tty_struct *tty; unsigned long flags; @@ -3601,7 +3597,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state) * Send a flow control character... */ -static void stl_cd1400sendflow(stlport_t *portp, int state) +static void stl_cd1400sendflow(struct stlport *portp, int state) { struct tty_struct *tty; unsigned long flags; @@ -3634,7 +3630,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state) /*****************************************************************************/ -static void stl_cd1400flush(stlport_t *portp) +static void stl_cd1400flush(struct stlport *portp) { unsigned long flags; @@ -3663,7 +3659,7 @@ static void stl_cd1400flush(stlport_t *portp) * maintains the busy port flag. */ -static int stl_cd1400datastate(stlport_t *portp) +static int stl_cd1400datastate(struct stlport *portp) { pr_debug("stl_cd1400datastate(portp=%p)\n", portp); @@ -3679,7 +3675,7 @@ static int stl_cd1400datastate(stlport_t *portp) * Interrupt service routine for cd1400 EasyIO boards. */ -static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) +static void stl_cd1400eiointr(struct stlpanel *panelp, unsigned int iobase) { unsigned char svrtype; @@ -3709,7 +3705,7 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) * Interrupt service routine for cd1400 panels. */ -static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase) +static void stl_cd1400echintr(struct stlpanel *panelp, unsigned int iobase) { unsigned char svrtype; @@ -3735,7 +3731,7 @@ static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase) * this is the only way to generate them on the cd1400. */ -static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr) +static inline int stl_cd1400breakisr(struct stlport *portp, int ioaddr) { if (portp->brklen == 1) { outb((COR2 + portp->uartaddr), ioaddr); @@ -3777,9 +3773,9 @@ static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr) * be NULL if the buffer has been freed. */ -static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr) +static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) { - stlport_t *portp; + struct stlport *portp; int len, stlen; char *head, *tail; unsigned char ioack, srer; @@ -3856,9 +3852,9 @@ stl_txalldone: * shutdown a port not in user context. Need to handle this case. */ -static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) +static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) { - stlport_t *portp; + struct stlport *portp; struct tty_struct *tty; unsigned int ioack, len, buflen; unsigned char status; @@ -3954,9 +3950,9 @@ stl_rxalldone: * processing routine. */ -static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr) +static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr) { - stlport_t *portp; + struct stlport *portp; unsigned int ioack; unsigned char misr; @@ -3992,19 +3988,19 @@ static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr) * (Maybe should make this inline...) */ -static int stl_sc26198getreg(stlport_t *portp, int regnr) +static int stl_sc26198getreg(struct stlport *portp, int regnr) { outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); return inb(portp->ioaddr + XP_DATA); } -static void stl_sc26198setreg(stlport_t *portp, int regnr, int value) +static void stl_sc26198setreg(struct stlport *portp, int regnr, int value) { outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); outb(value, (portp->ioaddr + XP_DATA)); } -static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value) +static int stl_sc26198updatereg(struct stlport *portp, int regnr, int value) { outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); if (inb(portp->ioaddr + XP_DATA) != value) { @@ -4020,14 +4016,14 @@ static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value) * Functions to get and set the sc26198 global registers. */ -static int stl_sc26198getglobreg(stlport_t *portp, int regnr) +static int stl_sc26198getglobreg(struct stlport *portp, int regnr) { outb(regnr, (portp->ioaddr + XP_ADDR)); return inb(portp->ioaddr + XP_DATA); } #if 0 -static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value) +static void stl_sc26198setglobreg(struct stlport *portp, int regnr, int value) { outb(regnr, (portp->ioaddr + XP_ADDR)); outb(value, (portp->ioaddr + XP_DATA)); @@ -4042,7 +4038,7 @@ static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value) * identical when dealing with ports. */ -static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) +static int stl_sc26198panelinit(struct stlbrd *brdp, struct stlpanel *panelp) { int chipmask, i; int nrchips, ioaddr; @@ -4087,7 +4083,7 @@ static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) * Initialize hardware specific port registers. */ -static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) +static void stl_sc26198portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp) { pr_debug("stl_sc26198portinit(brdp=%p,panelp=%p,portp=%p)\n", brdp, panelp, portp); @@ -4113,9 +4109,9 @@ static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *p * settings. */ -static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) +static void stl_sc26198setport(struct stlport *portp, struct termios *tiosp) { - stlbrd_t *brdp; + struct stlbrd *brdp; unsigned long flags; unsigned int baudrate; unsigned char mr0, mr1, mr2, clk; @@ -4308,7 +4304,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) * Set the state of the DTR and RTS signals. */ -static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) +static void stl_sc26198setsignals(struct stlport *portp, int dtr, int rts) { unsigned char iopioron, iopioroff; unsigned long flags; @@ -4341,7 +4337,7 @@ static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) * Return the state of the signals. */ -static int stl_sc26198getsignals(stlport_t *portp) +static int stl_sc26198getsignals(struct stlport *portp) { unsigned char ipr; unsigned long flags; @@ -4370,7 +4366,7 @@ static int stl_sc26198getsignals(stlport_t *portp) * Enable/Disable the Transmitter and/or Receiver. */ -static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) +static void stl_sc26198enablerxtx(struct stlport *portp, int rx, int tx) { unsigned char ccr; unsigned long flags; @@ -4401,7 +4397,7 @@ static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) * Start/stop the Transmitter and/or Receiver. */ -static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) +static void stl_sc26198startrxtx(struct stlport *portp, int rx, int tx) { unsigned char imr; unsigned long flags; @@ -4434,7 +4430,7 @@ static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) * Disable all interrupts from this port. */ -static void stl_sc26198disableintrs(stlport_t *portp) +static void stl_sc26198disableintrs(struct stlport *portp) { unsigned long flags; @@ -4450,7 +4446,7 @@ static void stl_sc26198disableintrs(stlport_t *portp) /*****************************************************************************/ -static void stl_sc26198sendbreak(stlport_t *portp, int len) +static void stl_sc26198sendbreak(struct stlport *portp, int len) { unsigned long flags; @@ -4474,7 +4470,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len) * Take flow control actions... */ -static void stl_sc26198flowctrl(stlport_t *portp, int state) +static void stl_sc26198flowctrl(struct stlport *portp, int state) { struct tty_struct *tty; unsigned long flags; @@ -4543,7 +4539,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state) * Send a flow control character. */ -static void stl_sc26198sendflow(stlport_t *portp, int state) +static void stl_sc26198sendflow(struct stlport *portp, int state) { struct tty_struct *tty; unsigned long flags; @@ -4582,7 +4578,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state) /*****************************************************************************/ -static void stl_sc26198flush(stlport_t *portp) +static void stl_sc26198flush(struct stlport *portp) { unsigned long flags; @@ -4610,7 +4606,7 @@ static void stl_sc26198flush(stlport_t *portp) * check the port statusy register to be sure. */ -static int stl_sc26198datastate(stlport_t *portp) +static int stl_sc26198datastate(struct stlport *portp) { unsigned long flags; unsigned char sr; @@ -4638,7 +4634,7 @@ static int stl_sc26198datastate(stlport_t *portp) * to process a command... */ -static void stl_sc26198wait(stlport_t *portp) +static void stl_sc26198wait(struct stlport *portp) { int i; @@ -4659,7 +4655,7 @@ static void stl_sc26198wait(stlport_t *portp) * automatic flow control modes of the sc26198. */ -static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty) +static inline void stl_sc26198txunflow(struct stlport *portp, struct tty_struct *tty) { unsigned char mr0; @@ -4677,9 +4673,9 @@ static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty) * Interrupt service routine for sc26198 panels. */ -static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) +static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase) { - stlport_t *portp; + struct stlport *portp; unsigned int iack; spin_lock(&brd_lock); @@ -4715,7 +4711,7 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) * be NULL if the buffer has been freed. */ -static void stl_sc26198txisr(stlport_t *portp) +static void stl_sc26198txisr(struct stlport *portp) { unsigned int ioaddr; unsigned char mr0; @@ -4776,7 +4772,7 @@ static void stl_sc26198txisr(stlport_t *portp) * shutdown a port not in user context. Need to handle this case. */ -static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) +static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) { struct tty_struct *tty; unsigned int len, buflen, ioaddr; @@ -4830,7 +4826,7 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) * Process an RX bad character. */ -static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch) +static inline void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char ch) { struct tty_struct *tty; unsigned int ioaddr; @@ -4888,7 +4884,7 @@ static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, ch * the FIFO). */ -static void stl_sc26198rxbadchars(stlport_t *portp) +static void stl_sc26198rxbadchars(struct stlport *portp) { unsigned char status, mr1; char ch; @@ -4921,7 +4917,7 @@ static void stl_sc26198rxbadchars(stlport_t *portp) * processing time. */ -static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack) +static void stl_sc26198otherisr(struct stlport *portp, unsigned int iack) { unsigned char cir, ipr, xisr; diff --git a/include/linux/stallion.h b/include/linux/stallion.h index 13a37f137ea2..ef5270b83d02 100644 --- a/include/linux/stallion.h +++ b/include/linux/stallion.h @@ -52,11 +52,11 @@ * protection - since "write" code only needs to change the head, and * interrupt code only needs to change the tail. */ -typedef struct { +struct stlrq { char *buf; char *head; char *tail; -} stlrq_t; +}; /* * Port, panel and board structures to hold status info about each. @@ -67,7 +67,7 @@ typedef struct { * is associated with, this makes it (fairly) easy to get back to the * board/panel info for a port. */ -typedef struct stlport { +struct stlport { unsigned long magic; int portnr; int panelnr; @@ -97,10 +97,10 @@ typedef struct stlport { wait_queue_head_t close_wait; struct work_struct tqueue; comstats_t stats; - stlrq_t tx; -} stlport_t; + struct stlrq tx; +}; -typedef struct stlpanel { +struct stlpanel { unsigned long magic; int panelnr; int brdnr; @@ -111,10 +111,10 @@ typedef struct stlpanel { void (*isr)(struct stlpanel *panelp, unsigned int iobase); unsigned int hwid; unsigned int ackmask; - stlport_t *ports[STL_PORTSPERPANEL]; -} stlpanel_t; + struct stlport *ports[STL_PORTSPERPANEL]; +}; -typedef struct stlbrd { +struct stlbrd { unsigned long magic; int brdnr; int brdtype; @@ -136,9 +136,9 @@ typedef struct stlbrd { unsigned long clk; unsigned int bnkpageaddr[STL_MAXBANKS]; unsigned int bnkstataddr[STL_MAXBANKS]; - stlpanel_t *bnk2panel[STL_MAXBANKS]; - stlpanel_t *panels[STL_MAXPANELS]; -} stlbrd_t; + struct stlpanel *bnk2panel[STL_MAXBANKS]; + struct stlpanel *panels[STL_MAXPANELS]; +}; /* -- cgit v1.2.3 From edc6afc5496875a640bef0913604be7550c1795d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 8 Dec 2006 02:38:44 -0800 Subject: [PATCH] tty: switch to ktermios and new framework This is the core of the switch to the new framework. I've split it from the driver patches which are mostly search/replace and would encourage people to give this one a good hard stare. The references to BOTHER and ISHIFT are the termios values that must be defined by a platform once it wants to turn on "new style" ioctl support. The code patches here ensure that providing 1. The termios overlays the ktermios in memory 2. The only new kernel only fields are c_ispeed/c_ospeed (or none) the existing behaviour is retained. This is true for the patches at this point in time. Future patches will define BOTHER, ISHIFT and enable newer termios structures for each architecture, and once they are all done some of the ifdefs also vanish. [akpm@osdl.org: warning fix] [akpm@osdl.org: IRDA fix] Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 137 ++++++-------------- drivers/char/tty_ioctl.c | 258 +++++++++++++++++++++++++++++++++++-- include/linux/tty.h | 9 +- include/linux/tty_driver.h | 12 +- include/linux/tty_ldisc.h | 4 +- include/net/irda/ircomm_tty.h | 2 +- net/irda/ircomm/ircomm_tty_ioctl.c | 2 +- 7 files changed, 297 insertions(+), 127 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 48cee2004e97..4044c864fdd4 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -109,13 +109,15 @@ #define TTY_PARANOIA_CHECK 1 #define CHECK_TTY_COUNT 1 -struct termios tty_std_termios = { /* for the benefit of tty drivers */ +struct ktermios tty_std_termios = { /* for the benefit of tty drivers */ .c_iflag = ICRNL | IXON, .c_oflag = OPOST | ONLCR, .c_cflag = B38400 | CS8 | CREAD | HUPCL, .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN, - .c_cc = INIT_C_CC + .c_cc = INIT_C_CC, + .c_ispeed = 38400, + .c_ospeed = 38400 }; EXPORT_SYMBOL(tty_std_termios); @@ -1239,6 +1241,22 @@ void tty_ldisc_flush(struct tty_struct *tty) } EXPORT_SYMBOL_GPL(tty_ldisc_flush); + +/** + * tty_reset_termios - reset terminal state + * @tty: tty to reset + * + * Restore a terminal to the driver default state + */ + +static void tty_reset_termios(struct tty_struct *tty) +{ + mutex_lock(&tty->termios_mutex); + *tty->termios = tty->driver->init_termios; + tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); + tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); + mutex_unlock(&tty->termios_mutex); +} /** * do_tty_hangup - actual handler for hangup events @@ -1327,11 +1345,7 @@ static void do_tty_hangup(struct work_struct *work) * N_TTY. */ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) - { - mutex_lock(&tty->termios_mutex); - *tty->termios = tty->driver->init_termios; - mutex_unlock(&tty->termios_mutex); - } + tty_reset_termios(tty); /* Defer ldisc switch */ /* tty_deferred_ldisc_switch(N_TTY); @@ -1870,8 +1884,8 @@ static int init_dev(struct tty_driver *driver, int idx, struct tty_struct **ret_tty) { struct tty_struct *tty, *o_tty; - struct termios *tp, **tp_loc, *o_tp, **o_tp_loc; - struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; + struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc; + struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; int retval = 0; /* check whether we're reopening an existing tty */ @@ -1918,7 +1932,7 @@ static int init_dev(struct tty_driver *driver, int idx, } if (!*tp_loc) { - tp = (struct termios *) kmalloc(sizeof(struct termios), + tp = (struct ktermios *) kmalloc(sizeof(struct ktermios), GFP_KERNEL); if (!tp) goto free_mem_out; @@ -1926,11 +1940,11 @@ static int init_dev(struct tty_driver *driver, int idx, } if (!*ltp_loc) { - ltp = (struct termios *) kmalloc(sizeof(struct termios), + ltp = (struct ktermios *) kmalloc(sizeof(struct ktermios), GFP_KERNEL); if (!ltp) goto free_mem_out; - memset(ltp, 0, sizeof(struct termios)); + memset(ltp, 0, sizeof(struct ktermios)); } if (driver->type == TTY_DRIVER_TYPE_PTY) { @@ -1951,19 +1965,19 @@ static int init_dev(struct tty_driver *driver, int idx, } if (!*o_tp_loc) { - o_tp = (struct termios *) - kmalloc(sizeof(struct termios), GFP_KERNEL); + o_tp = (struct ktermios *) + kmalloc(sizeof(struct ktermios), GFP_KERNEL); if (!o_tp) goto free_mem_out; *o_tp = driver->other->init_termios; } if (!*o_ltp_loc) { - o_ltp = (struct termios *) - kmalloc(sizeof(struct termios), GFP_KERNEL); + o_ltp = (struct ktermios *) + kmalloc(sizeof(struct ktermios), GFP_KERNEL); if (!o_ltp) goto free_mem_out; - memset(o_ltp, 0, sizeof(struct termios)); + memset(o_ltp, 0, sizeof(struct ktermios)); } /* @@ -2002,6 +2016,9 @@ static int init_dev(struct tty_driver *driver, int idx, *ltp_loc = ltp; tty->termios = *tp_loc; tty->termios_locked = *ltp_loc; + /* Compatibility until drivers always set this */ + tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); + tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); driver->refcount++; tty->count++; @@ -2104,7 +2121,7 @@ release_mem_out: static void release_mem(struct tty_struct *tty, int idx) { struct tty_struct *o_tty; - struct termios *tp; + struct ktermios *tp; int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM; if ((o_tty = tty->link) != NULL) { @@ -3458,84 +3475,6 @@ static void flush_to_ldisc(struct work_struct *work) tty_ldisc_deref(disc); } -/* - * Routine which returns the baud rate of the tty - * - * Note that the baud_table needs to be kept in sync with the - * include/asm/termbits.h file. - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, -#ifdef __sparc__ - 76800, 153600, 307200, 614400, 921600 -#else - 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, - 2500000, 3000000, 3500000, 4000000 -#endif -}; - -static int n_baud_table = ARRAY_SIZE(baud_table); - -/** - * tty_termios_baud_rate - * @termios: termios structure - * - * Convert termios baud rate data into a speed. This should be called - * with the termios lock held if this termios is a terminal termios - * structure. May change the termios data. - * - * Locking: none - */ - -int tty_termios_baud_rate(struct termios *termios) -{ - unsigned int cbaud; - - cbaud = termios->c_cflag & CBAUD; - - if (cbaud & CBAUDEX) { - cbaud &= ~CBAUDEX; - - if (cbaud < 1 || cbaud + 15 > n_baud_table) - termios->c_cflag &= ~CBAUDEX; - else - cbaud += 15; - } - return baud_table[cbaud]; -} - -EXPORT_SYMBOL(tty_termios_baud_rate); - -/** - * tty_get_baud_rate - get tty bit rates - * @tty: tty to query - * - * Returns the baud rate as an integer for this terminal. The - * termios lock must be held by the caller and the terminal bit - * flags may be updated. - * - * Locking: none - */ - -int tty_get_baud_rate(struct tty_struct *tty) -{ - int baud = tty_termios_baud_rate(tty->termios); - - if (baud == 38400 && tty->alt_speed) { - if (!tty->warned) { - printk(KERN_WARNING "Use of setserial/setrocket to " - "set SPD_* flags is deprecated\n"); - tty->warned = 1; - } - baud = tty->alt_speed; - } - - return baud; -} - -EXPORT_SYMBOL(tty_get_baud_rate); - /** * tty_flip_buffer_push - terminal * @tty: tty to push @@ -3758,8 +3697,8 @@ int tty_register_driver(struct tty_driver *driver) if (p) { driver->ttys = (struct tty_struct **)p; - driver->termios = (struct termios **)(p + driver->num); - driver->termios_locked = (struct termios **)(p + driver->num * 2); + driver->termios = (struct ktermios **)(p + driver->num); + driver->termios_locked = (struct ktermios **)(p + driver->num * 2); } else { driver->ttys = NULL; driver->termios = NULL; @@ -3798,7 +3737,7 @@ EXPORT_SYMBOL(tty_register_driver); int tty_unregister_driver(struct tty_driver *driver) { int i; - struct termios *tp; + struct ktermios *tp; void *p; if (driver->refcount) diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 3b6fa7b0be8b..0ffba4e911ca 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -36,6 +36,7 @@ #define TERMIOS_FLUSH 1 #define TERMIOS_WAIT 2 #define TERMIOS_TERMIO 4 +#define TERMIOS_OLD 8 /** @@ -84,9 +85,9 @@ stop_waiting: EXPORT_SYMBOL(tty_wait_until_sent); -static void unset_locked_termios(struct termios *termios, - struct termios *old, - struct termios *locked) +static void unset_locked_termios(struct ktermios *termios, + struct ktermios *old, + struct ktermios *locked) { int i; @@ -105,8 +106,204 @@ static void unset_locked_termios(struct termios *termios, for (i=0; i < NCCS; i++) termios->c_cc[i] = locked->c_cc[i] ? old->c_cc[i] : termios->c_cc[i]; + /* FIXME: What should we do for i/ospeed */ } +/* + * Routine which returns the baud rate of the tty + * + * Note that the baud_table needs to be kept in sync with the + * include/asm/termbits.h file. + */ +static const speed_t baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, +#ifdef __sparc__ + 76800, 153600, 307200, 614400, 921600 +#else + 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, + 2500000, 3000000, 3500000, 4000000 +#endif +}; + +#ifndef __sparc__ +static const tcflag_t baud_bits[] = { + B0, B50, B75, B110, B134, B150, B200, B300, B600, + B1200, B1800, B2400, B4800, B9600, B19200, B38400, + B57600, B115200, B230400, B460800, B500000, B576000, + B921600, B1000000, B1152000, B1500000, B2000000, B2500000, + B3000000, B3500000, B4000000 +}; +#else +static const tcflag_t baud_bits[] = { + B0, B50, B75, B110, B134, B150, B200, B300, B600, + B1200, B1800, B2400, B4800, B9600, B19200, B38400, + B57600, B115200, B230400, B460800, B76800, B153600, + B307200, B614400, B921600 +}; +#endif + +static int n_baud_table = ARRAY_SIZE(baud_table); + +/** + * tty_termios_baud_rate + * @termios: termios structure + * + * Convert termios baud rate data into a speed. This should be called + * with the termios lock held if this termios is a terminal termios + * structure. May change the termios data. Device drivers can call this + * function but should use ->c_[io]speed directly as they are updated. + * + * Locking: none + */ + +speed_t tty_termios_baud_rate(struct ktermios *termios) +{ + unsigned int cbaud; + + cbaud = termios->c_cflag & CBAUD; + +#ifdef BOTHER + /* Magic token for arbitary speed via c_ispeed/c_ospeed */ + if (cbaud == BOTHER) + return termios->c_ospeed; +#endif + if (cbaud & CBAUDEX) { + cbaud &= ~CBAUDEX; + + if (cbaud < 1 || cbaud + 15 > n_baud_table) + termios->c_cflag &= ~CBAUDEX; + else + cbaud += 15; + } + return baud_table[cbaud]; +} + +EXPORT_SYMBOL(tty_termios_baud_rate); + +/** + * tty_termios_input_baud_rate + * @termios: termios structure + * + * Convert termios baud rate data into a speed. This should be called + * with the termios lock held if this termios is a terminal termios + * structure. May change the termios data. Device drivers can call this + * function but should use ->c_[io]speed directly as they are updated. + * + * Locking: none + */ + +speed_t tty_termios_input_baud_rate(struct ktermios *termios) +{ +#ifdef IBSHIFT + unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD; + + if (cbaud == B0) + return tty_termios_baud_rate(termios); + + /* Magic token for arbitary speed via c_ispeed*/ + if (cbaud == BOTHER) + return termios->c_ispeed; + + if (cbaud & CBAUDEX) { + cbaud &= ~CBAUDEX; + + if (cbaud < 1 || cbaud + 15 > n_baud_table) + termios->c_cflag &= ~(CBAUDEX << IBSHIFT); + else + cbaud += 15; + } + return baud_table[cbaud]; +#else + return tty_termios_baud_rate(termios); +#endif +} + +EXPORT_SYMBOL(tty_termios_input_baud_rate); + +#ifdef BOTHER + +/** + * tty_termios_encode_baud_rate + * @termios: termios structure + * @ispeed: input speed + * @ospeed: output speed + * + * Encode the speeds set into the passed termios structure. This is + * used as a library helper for drivers os that they can report back + * the actual speed selected when it differs from the speed requested + * + * For now input and output speed must agree. + * + * Locking: Caller should hold termios lock. This is already held + * when calling this function from the driver termios handler. + */ + +void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud) +{ + int i = 0; + int ifound = 0, ofound = 0; + + termios->c_ispeed = ibaud; + termios->c_ospeed = obaud; + + termios->c_cflag &= ~CBAUD; + /* Identical speed means no input encoding (ie B0 << IBSHIFT)*/ + if (termios->c_ispeed == termios->c_ospeed) + ifound = 1; + + do { + if (obaud == baud_table[i]) { + termios->c_cflag |= baud_bits[i]; + ofound = 1; + /* So that if ibaud == obaud we don't set it */ + continue; + } + if (ibaud == baud_table[i]) { + termios->c_cflag |= (baud_bits[i] << IBSHIFT); + ifound = 1; + } + } + while(++i < n_baud_table); + if (!ofound) + termios->c_cflag |= BOTHER; + if (!ifound) + termios->c_cflag |= (BOTHER << IBSHIFT); +} + +EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); + +#endif + +/** + * tty_get_baud_rate - get tty bit rates + * @tty: tty to query + * + * Returns the baud rate as an integer for this terminal. The + * termios lock must be held by the caller and the terminal bit + * flags may be updated. + * + * Locking: none + */ + +speed_t tty_get_baud_rate(struct tty_struct *tty) +{ + speed_t baud = tty_termios_baud_rate(tty->termios); + + if (baud == 38400 && tty->alt_speed) { + if (!tty->warned) { + printk(KERN_WARNING "Use of setserial/setrocket to " + "set SPD_* flags is deprecated\n"); + tty->warned = 1; + } + baud = tty->alt_speed; + } + + return baud; +} + +EXPORT_SYMBOL(tty_get_baud_rate); + /** * change_termios - update termios values * @tty: tty to update @@ -119,10 +316,10 @@ static void unset_locked_termios(struct termios *termios, * Locking: termios_sem */ -static void change_termios(struct tty_struct * tty, struct termios * new_termios) +static void change_termios(struct tty_struct * tty, struct ktermios * new_termios) { int canon_change; - struct termios old_termios = *tty->termios; + struct ktermios old_termios = *tty->termios; struct tty_ldisc *ld; /* @@ -195,7 +392,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios static int set_termios(struct tty_struct * tty, void __user *arg, int opt) { - struct termios tmp_termios; + struct ktermios tmp_termios; struct tty_ldisc *ld; int retval = tty_check_change(tty); @@ -203,16 +400,28 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt) return retval; if (opt & TERMIOS_TERMIO) { - memcpy(&tmp_termios, tty->termios, sizeof(struct termios)); + memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios)); if (user_termio_to_kernel_termios(&tmp_termios, (struct termio __user *)arg)) return -EFAULT; +#ifdef TCGETS2 + } else if (opt & TERMIOS_OLD) { + memcpy(&tmp_termios, tty->termios, sizeof(struct termios)); + if (user_termios_to_kernel_termios_1(&tmp_termios, + (struct termios_v1 __user *)arg)) + return -EFAULT; +#endif } else { if (user_termios_to_kernel_termios(&tmp_termios, (struct termios __user *)arg)) return -EFAULT; } + /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed + so its unconditionally usable */ + tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); + tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); + ld = tty_ldisc_ref(tty); if (ld != NULL) { @@ -286,8 +495,8 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) struct sgttyb tmp; mutex_lock(&tty->termios_mutex); - tmp.sg_ispeed = 0; - tmp.sg_ospeed = 0; + tmp.sg_ispeed = tty->c_ispeed; + tmp.sg_ospeed = tty->c_ospeed; tmp.sg_erase = tty->termios->c_cc[VERASE]; tmp.sg_kill = tty->termios->c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); @@ -296,7 +505,7 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; } -static void set_sgflags(struct termios * termios, int flags) +static void set_sgflags(struct ktermios * termios, int flags) { termios->c_iflag = ICRNL | IXON; termios->c_oflag = 0; @@ -337,7 +546,7 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) { int retval; struct sgttyb tmp; - struct termios termios; + struct ktermios termios; retval = tty_check_change(tty); if (retval) @@ -351,6 +560,10 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) termios.c_cc[VERASE] = tmp.sg_erase; termios.c_cc[VKILL] = tmp.sg_kill; set_sgflags(&termios, tmp.sg_flags); + /* Try and encode into Bfoo format */ +#ifdef BOTHER + tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed); +#endif mutex_unlock(&tty->termios_mutex); change_termios(tty, &termios); return 0; @@ -481,16 +694,33 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, case TIOCSLTC: return set_ltchars(real_tty, p); #endif + case TCSETSF: + return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD); + case TCSETSW: + return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD); + case TCSETS: + return set_termios(real_tty, p, TERMIOS_OLD); +#ifndef TCGETS2 case TCGETS: if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) return -EFAULT; return 0; - case TCSETSF: +#else + case TCGETS: + if (kernel_termios_to_user_termios_1((struct termios_v1 __user *)arg, real_tty->termios)) + return -EFAULT; + return 0; + case TCGETS2: + if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) + return -EFAULT; + return 0; + case TCSETSF2: return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); - case TCSETSW: + case TCSETSW2: return set_termios(real_tty, p, TERMIOS_WAIT); - case TCSETS: + case TCSETS2: return set_termios(real_tty, p, 0); +#endif case TCGETA: return get_termio(real_tty, p); case TCSETAF: diff --git a/include/linux/tty.h b/include/linux/tty.h index 1d29999a3439..65cbcf22c31e 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -175,7 +175,7 @@ struct tty_struct { int index; struct tty_ldisc ldisc; struct mutex termios_mutex; - struct termios *termios, *termios_locked; + struct ktermios *termios, *termios_locked; char name[64]; int pgrp; int session; @@ -258,7 +258,7 @@ struct tty_struct { extern void tty_write_flush(struct tty_struct *); -extern struct termios tty_std_termios; +extern struct ktermios tty_std_termios; extern int kmsg_redirect; @@ -293,8 +293,9 @@ extern int tty_hung_up_p(struct file * filp); extern void do_SAK(struct tty_struct *tty); extern void disassociate_ctty(int priv); extern void tty_flip_buffer_push(struct tty_struct *tty); -extern int tty_get_baud_rate(struct tty_struct *tty); -extern int tty_termios_baud_rate(struct termios *termios); +extern speed_t tty_get_baud_rate(struct tty_struct *tty); +extern speed_t tty_termios_baud_rate(struct ktermios *termios); +extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *); extern void tty_ldisc_deref(struct tty_ldisc *); diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 5c8473bb6882..659487e3ebeb 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -53,7 +53,7 @@ * device-specific ioctl's. If the ioctl number passed in cmd * is not recognized by the driver, it should return ENOIOCTLCMD. * - * void (*set_termios)(struct tty_struct *tty, struct termios * old); + * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); * * This routine allows the tty driver to be notified when * device's termios settings have changed. Note that a @@ -132,7 +132,7 @@ struct tty_operations { int (*chars_in_buffer)(struct tty_struct *tty); int (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); - void (*set_termios)(struct tty_struct *tty, struct termios * old); + void (*set_termios)(struct tty_struct *tty, struct ktermios * old); void (*throttle)(struct tty_struct * tty); void (*unthrottle)(struct tty_struct * tty); void (*stop)(struct tty_struct *tty); @@ -165,7 +165,7 @@ struct tty_driver { int num; /* number of devices allocated */ short type; /* type of tty driver */ short subtype; /* subtype of tty driver */ - struct termios init_termios; /* Initial termios */ + struct ktermios init_termios; /* Initial termios */ int flags; /* tty driver flags */ int refcount; /* for loadable tty drivers */ struct proc_dir_entry *proc_entry; /* /proc fs entry */ @@ -175,8 +175,8 @@ struct tty_driver { * Pointer to the tty data structures */ struct tty_struct **ttys; - struct termios **termios; - struct termios **termios_locked; + struct ktermios **termios; + struct ktermios **termios_locked; void *driver_state; /* only used for the PTY driver */ /* @@ -193,7 +193,7 @@ struct tty_driver { int (*chars_in_buffer)(struct tty_struct *tty); int (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); - void (*set_termios)(struct tty_struct *tty, struct termios * old); + void (*set_termios)(struct tty_struct *tty, struct ktermios * old); void (*throttle)(struct tty_struct * tty); void (*unthrottle)(struct tty_struct * tty); void (*stop)(struct tty_struct *tty); diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 83c6e6c10ebb..d75932e27710 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -59,7 +59,7 @@ * low-level driver can "grab" an ioctl request before the line * discpline has a chance to see it. * - * void (*set_termios)(struct tty_struct *tty, struct termios * old); + * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); * * This function notifies the line discpline that a change has * been made to the termios structure. @@ -118,7 +118,7 @@ struct tty_ldisc { const unsigned char * buf, size_t nr); int (*ioctl)(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg); - void (*set_termios)(struct tty_struct *tty, struct termios * old); + void (*set_termios)(struct tty_struct *tty, struct ktermios * old); unsigned int (*poll)(struct tty_struct *, struct file *, struct poll_table_struct *); int (*hangup)(struct tty_struct *tty); diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h index 87699cb4ef8c..8dabdd603fe1 100644 --- a/include/net/irda/ircomm_tty.h +++ b/include/net/irda/ircomm_tty.h @@ -126,7 +126,7 @@ extern int ircomm_tty_tiocmset(struct tty_struct *tty, struct file *file, extern int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); extern void ircomm_tty_set_termios(struct tty_struct *tty, - struct termios *old_termios); + struct ktermios *old_termios); extern hashbin_t *ircomm_tty; #endif diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index 197e3e7ed7e2..75e39ea599d8 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -146,7 +146,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self) * do something rational. */ void ircomm_tty_set_termios(struct tty_struct *tty, - struct termios *old_termios) + struct ktermios *old_termios) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned int cflag = tty->termios->c_cflag; -- cgit v1.2.3 From 606d099cdd1080bbb50ea50dc52d98252f8f10a1 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 8 Dec 2006 02:38:45 -0800 Subject: [PATCH] tty: switch to ktermios This is the grungy swap all the occurrences in the right places patch that goes with the updates. At this point we have the same functionality as before (except that sgttyb() returns speeds not zero) and are ready to begin turning new stuff on providing nobody reports lots of bugs If you are a tty driver author converting an out of tree driver the only impact should be termios->ktermios name changes for the speed/property setting functions from your upper layers. If you are implementing your own TCGETS function before then your driver was broken already and its about to get a whole lot more painful for you so please fix it 8) Also fill in c_ispeed/ospeed on init for most devices, although the current code will do this for you anyway but I'd like eventually to lose that extra paranoia [akpm@osdl.org: bluetooth fix] [mp3@de.ibm.com: sclp fix] [mp3@de.ibm.com: warning fix for tty3270] [hugh@veritas.com: fix tty_ioctl powerpc build] [jdike@addtoit.com: uml: fix ->set_termios declaration] Signed-off-by: Alan Cox Signed-off-by: Martin Peschke Acked-by: Peter Oberparleiter Cc: Cornelia Huck Signed-off-by: Hugh Dickins Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/line.c | 2 +- arch/um/include/line.h | 2 +- drivers/char/amiserial.c | 6 +++--- drivers/char/cyclades.c | 2 +- drivers/char/epca.c | 16 +++++++++++----- drivers/char/esp.c | 2 +- drivers/char/generic_serial.c | 4 ++-- drivers/char/hvcs.c | 6 ++++-- drivers/char/hvsi.c | 2 ++ drivers/char/ip2/ip2main.c | 10 +++++----- drivers/char/isicom.c | 2 +- drivers/char/istallion.c | 14 ++++++++------ drivers/char/moxa.c | 18 ++++++++++-------- drivers/char/mxser.c | 18 ++++++++++-------- drivers/char/mxser_new.c | 8 ++++---- drivers/char/n_r3964.c | 4 ++-- drivers/char/n_tty.c | 2 +- drivers/char/pcmcia/synclink_cs.c | 2 +- drivers/char/pty.c | 10 +++++++++- drivers/char/riscom8.c | 4 +++- drivers/char/rocket.c | 8 +++++--- drivers/char/ser_a2232.c | 2 ++ drivers/char/serial167.c | 2 +- drivers/char/specialix.c | 9 +++++++-- drivers/char/stallion.c | 20 +++++++++++--------- drivers/char/sx.c | 2 ++ drivers/char/synclink.c | 4 +++- drivers/char/synclink_gt.c | 6 ++++-- drivers/char/synclinkmp.c | 6 ++++-- drivers/char/tty_ioctl.c | 4 ++-- drivers/char/vme_scc.c | 2 ++ drivers/isdn/capi/capi.c | 2 +- drivers/isdn/gigaset/interface.c | 4 ++-- drivers/isdn/i4l/isdn_tty.c | 2 +- drivers/net/irda/irtty-sir.c | 4 ++-- drivers/s390/char/sclp_tty.c | 2 -- drivers/s390/char/tty3270.c | 2 +- drivers/serial/21285.c | 4 ++-- drivers/serial/68328serial.c | 2 +- drivers/serial/68360serial.c | 2 +- drivers/serial/8250.c | 4 ++-- drivers/serial/amba-pl010.c | 4 ++-- drivers/serial/amba-pl011.c | 4 ++-- drivers/serial/atmel_serial.c | 2 +- drivers/serial/clps711x.c | 4 ++-- drivers/serial/crisv10.c | 8 +++++--- drivers/serial/crisv10.h | 4 ++-- drivers/serial/dz.c | 4 ++-- drivers/serial/icom.c | 4 ++-- drivers/serial/imx.c | 4 ++-- drivers/serial/ioc3_serial.c | 4 ++-- drivers/serial/ioc4_serial.c | 6 +++--- drivers/serial/ip22zilog.c | 4 ++-- drivers/serial/jsm/jsm_tty.c | 10 +++++----- drivers/serial/m32r_sio.c | 2 +- drivers/serial/mcfserial.c | 2 +- drivers/serial/mpc52xx_uart.c | 4 ++-- drivers/serial/mpsc.c | 4 ++-- drivers/serial/mux.c | 4 ++-- drivers/serial/netx-serial.c | 4 ++-- drivers/serial/pmac_zilog.c | 10 +++++----- drivers/serial/pmac_zilog.h | 2 +- drivers/serial/pxa.c | 4 ++-- drivers/serial/s3c2410.c | 4 ++-- drivers/serial/sa1100.c | 4 ++-- drivers/serial/serial_core.c | 21 +++++++++++---------- drivers/serial/serial_lh7a40x.c | 4 ++-- drivers/serial/serial_txx9.c | 4 ++-- drivers/serial/sh-sci.c | 4 ++-- drivers/serial/sn_console.c | 4 ++-- drivers/serial/sunhv.c | 4 ++-- drivers/serial/sunsab.c | 4 ++-- drivers/serial/sunsu.c | 4 ++-- drivers/serial/sunzilog.c | 4 ++-- drivers/serial/uartlite.c | 4 ++-- drivers/serial/v850e_uart.c | 4 ++-- drivers/serial/vr41xx_siu.c | 4 ++-- drivers/tc/zs.c | 2 +- drivers/usb/class/cdc-acm.c | 4 ++-- drivers/usb/gadget/serial.c | 4 ++-- drivers/usb/serial/ark3116.c | 4 ++-- drivers/usb/serial/belkin_sa.c | 4 ++-- drivers/usb/serial/console.c | 2 +- drivers/usb/serial/cp2101.c | 4 ++-- drivers/usb/serial/cypress_m8.c | 10 +++++----- drivers/usb/serial/digi_acceleport.c | 6 +++--- drivers/usb/serial/empeg.c | 4 ++-- drivers/usb/serial/ftdi_sio.c | 4 ++-- drivers/usb/serial/io_edgeport.c | 8 ++++---- drivers/usb/serial/io_ti.c | 6 +++--- drivers/usb/serial/ir-usb.c | 4 ++-- drivers/usb/serial/keyspan.c | 2 +- drivers/usb/serial/keyspan.h | 2 +- drivers/usb/serial/keyspan_pda.c | 2 +- drivers/usb/serial/kl5kusb105.c | 6 +++--- drivers/usb/serial/kobil_sct.c | 10 +++++----- drivers/usb/serial/mct_u232.c | 4 ++-- drivers/usb/serial/mos7720.c | 4 ++-- drivers/usb/serial/mos7840.c | 4 ++-- drivers/usb/serial/option.c | 4 ++-- drivers/usb/serial/pl2303.c | 4 ++-- drivers/usb/serial/sierra.c | 2 +- drivers/usb/serial/ti_usb_3410_5052.c | 4 ++-- drivers/usb/serial/usb-serial.c | 2 +- drivers/usb/serial/visor.c | 4 ++-- drivers/usb/serial/whiteheat.c | 6 +++--- include/asm-generic/termios.h | 4 ++-- include/asm-powerpc/termbits.h | 2 +- include/linux/generic_serial.h | 2 +- include/linux/isdn.h | 8 ++++---- include/linux/serial_core.h | 8 ++++---- include/linux/usb/serial.h | 2 +- net/bluetooth/rfcomm/tty.c | 4 ++-- 113 files changed, 301 insertions(+), 253 deletions(-) (limited to 'include/linux') diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index aa3090d05a8f..83301e1ef67c 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -246,7 +246,7 @@ out_up: return ret; } -void line_set_termios(struct tty_struct *tty, struct termios * old) +void line_set_termios(struct tty_struct *tty, struct ktermios * old) { /* nothing */ } diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 214ee76c40df..5f232ae89fbb 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -76,7 +76,7 @@ extern int line_setup(struct line *lines, unsigned int sizeof_lines, extern int line_write(struct tty_struct *tty, const unsigned char *buf, int len); extern void line_put_char(struct tty_struct *tty, unsigned char ch); -extern void line_set_termios(struct tty_struct *tty, struct termios * old); +extern void line_set_termios(struct tty_struct *tty, struct ktermios * old); extern int line_chars_in_buffer(struct tty_struct *tty); extern void line_flush_buffer(struct tty_struct *tty); extern void line_flush_chars(struct tty_struct *tty); diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 66086fa2d59a..feb4ac802a0d 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -104,7 +104,7 @@ static struct async_struct *IRQ_ports; static unsigned char current_ctl_bits; -static void change_speed(struct async_struct *info, struct termios *old); +static void change_speed(struct async_struct *info, struct ktermios *old); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); @@ -694,7 +694,7 @@ static void shutdown(struct async_struct * info) * the specified baud rate for a serial port. */ static void change_speed(struct async_struct *info, - struct termios *old_termios) + struct ktermios *old_termios) { int quot = 0, baud_base, baud; unsigned cflag, cval = 0; @@ -1365,7 +1365,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, return 0; } -static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index acb2de5e3a98..3bb4e534c14e 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -4101,7 +4101,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file, * where old == NULL, and try to do something rational. */ static void -cy_set_termios(struct tty_struct *tty, struct termios * old_termios) +cy_set_termios(struct tty_struct *tty, struct ktermios * old_termios) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 7c71eb779802..a0f822c9d74d 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -199,7 +199,7 @@ static int pc_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); static int info_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); -static void pc_set_termios(struct tty_struct *, struct termios *); +static void pc_set_termios(struct tty_struct *, struct ktermios *); static void do_softint(struct work_struct *work); static void pc_stop(struct tty_struct *); static void pc_start(struct tty_struct *); @@ -1236,6 +1236,8 @@ static int __init pc_init(void) pc_driver->init_termios.c_oflag = 0; pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; pc_driver->init_termios.c_lflag = 0; + pc_driver->init_termios.c_ispeed = 9600; + pc_driver->init_termios.c_ospeed = 9600; pc_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(pc_driver, &pc_ops); @@ -1250,6 +1252,8 @@ static int __init pc_init(void) pc_info->init_termios.c_oflag = 0; pc_info->init_termios.c_lflag = 0; pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; + pc_info->init_termios.c_ispeed = 9600; + pc_info->init_termios.c_ospeed = 9600; pc_info->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(pc_info, &info_ops); @@ -1999,7 +2003,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) { /* Begin epcaparam */ unsigned int cmdHead; - struct termios *ts; + struct ktermios *ts; struct board_chan __iomem *bc; unsigned mval, hflow, cflag, iflag; @@ -2114,7 +2118,7 @@ static void receive_data(struct channel *ch) { /* Begin receive_data */ unchar *rptr; - struct termios *ts = NULL; + struct ktermios *ts = NULL; struct tty_struct *tty; struct board_chan __iomem *bc; int dataToRead, wrapgap, bytesAvailable; @@ -2362,12 +2366,14 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, switch (cmd) { /* Begin switch cmd */ +#if 0 /* Handled by calling layer properly */ case TCGETS: - if (copy_to_user(argp, tty->termios, sizeof(struct termios))) + if (copy_to_user(argp, tty->termios, sizeof(struct ktermios))) return -EFAULT; return 0; case TCGETA: return get_termio(tty, argp); +#endif case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) @@ -2536,7 +2542,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, /* --------------------- Begin pc_set_termios ----------------------- */ -static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { /* Begin pc_set_termios */ struct channel *ch; diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 93b551962513..d1bfbaa2aa02 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -1915,7 +1915,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, return 0; } -static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct esp_struct *info = (struct esp_struct *)tty->driver_data; unsigned long flags; diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 87127e49c0db..e769811e7417 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -718,11 +718,11 @@ static unsigned int gs_baudrates[] = { void gs_set_termios (struct tty_struct * tty, - struct termios * old_termios) + struct ktermios * old_termios) { struct gs_port *port; int baudrate, tmp, rv; - struct termios *tiosp; + struct ktermios *tiosp; func_enter(); diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index d090622f1dea..207f7343ba60 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -192,11 +192,13 @@ MODULE_VERSION(HVCS_DRIVER_VERSION); * that will cause echoing or we'll go into recursive loop echoing chars back * and forth with the console drivers. */ -static struct termios hvcs_tty_termios = { +static struct ktermios hvcs_tty_termios = { .c_iflag = IGNBRK | IGNPAR, .c_oflag = OPOST, .c_cflag = B38400 | CS8 | CREAD | HUPCL, - .c_cc = INIT_C_CC + .c_cc = INIT_C_CC, + .c_ispeed = 38400, + .c_ospeed = 38400 }; /* diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 82a41d5b4ed0..d7806834fc17 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -1161,6 +1161,8 @@ static int __init hvsi_init(void) hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM; hvsi_driver->init_termios = tty_std_termios; hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; + hvsi_driver->init_termios.c_ispeed = 9600; + hvsi_driver->init_termios.c_ospeed = 9600; hvsi_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(hvsi_driver, &hvsi_ops); diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 6810b7bbcbb7..7c70310a49b5 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -177,7 +177,7 @@ static int ip2_write_room(PTTY); static int ip2_chars_in_buf(PTTY); static void ip2_flush_buffer(PTTY); static int ip2_ioctl(PTTY, struct file *, UINT, ULONG); -static void ip2_set_termios(PTTY, struct termios *); +static void ip2_set_termios(PTTY, struct ktermios *); static void ip2_set_line_discipline(PTTY); static void ip2_throttle(PTTY); static void ip2_unthrottle(PTTY); @@ -198,7 +198,7 @@ static void do_status(struct work_struct *); static void ip2_wait_until_sent(PTTY,int); -static void set_params (i2ChanStrPtr, struct termios *); +static void set_params (i2ChanStrPtr, struct ktermios *); static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *); static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *); @@ -2398,7 +2398,7 @@ set_serial_info( i2ChanStrPtr pCh, struct serial_struct __user *new_info ) /* */ /******************************************************************************/ static void -ip2_set_termios( PTTY tty, struct termios *old_termios ) +ip2_set_termios( PTTY tty, struct ktermios *old_termios ) { i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data; @@ -2440,11 +2440,11 @@ ip2_set_line_discipline ( PTTY tty ) /* change. */ /******************************************************************************/ static void -set_params( i2ChanStrPtr pCh, struct termios *o_tios ) +set_params( i2ChanStrPtr pCh, struct ktermios *o_tios ) { tcflag_t cflag, iflag, lflag; char stop_char, start_char; - struct termios dummy; + struct ktermios dummy; lflag = pCh->pTTY->termios->c_lflag; cflag = pCh->pTTY->termios->c_cflag; diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 1637c1d9a4ba..29e28b756336 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -1399,7 +1399,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp, /* set_termios et all */ static void isicom_set_termios(struct tty_struct *tty, - struct termios *old_termios) + struct ktermios *old_termios) { struct isi_port *port = tty->driver_data; diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index b6f0d036a760..0ef2523733ee 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -194,9 +194,11 @@ static struct tty_struct *stli_txcooktty; * with this termios initially. Basically all it defines is a raw port * at 9600 baud, 8 data bits, no parity, 1 stop bit. */ -static struct termios stli_deftermios = { +static struct ktermios stli_deftermios = { .c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL), .c_cc = INIT_C_CC, + .c_ispeed = 9600, + .c_ospeed = 9600, }; /* @@ -639,7 +641,7 @@ static void stli_flushchars(struct tty_struct *tty); static int stli_writeroom(struct tty_struct *tty); static int stli_charsinbuffer(struct tty_struct *tty); static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static void stli_settermios(struct tty_struct *tty, struct termios *old); +static void stli_settermios(struct tty_struct *tty, struct ktermios *old); static void stli_throttle(struct tty_struct *tty); static void stli_unthrottle(struct tty_struct *tty); static void stli_stop(struct tty_struct *tty); @@ -669,7 +671,7 @@ static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, v static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp); -static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp); +static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct ktermios *tiosp); static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts); static long stli_mktiocm(unsigned long sigvalue); static void stli_read(stlibrd_t *brdp, stliport_t *portp); @@ -1889,11 +1891,11 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm * Looks like it is true for the current ttys implementation..!! */ -static void stli_settermios(struct tty_struct *tty, struct termios *old) +static void stli_settermios(struct tty_struct *tty, struct ktermios *old) { stliport_t *portp; stlibrd_t *brdp; - struct termios *tiosp; + struct ktermios *tiosp; asyport_t aport; if (tty == NULL) @@ -2730,7 +2732,7 @@ static void stli_poll(unsigned long arg) * the slave. */ -static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp) +static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct ktermios *tiosp) { memset(pp, 0, sizeof(asyport_t)); diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 8b316953173d..f391a24a1b44 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -234,7 +234,7 @@ static void moxa_put_char(struct tty_struct *, unsigned char); static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); static void moxa_throttle(struct tty_struct *); static void moxa_unthrottle(struct tty_struct *); -static void moxa_set_termios(struct tty_struct *, struct termios *); +static void moxa_set_termios(struct tty_struct *, struct ktermios *); static void moxa_stop(struct tty_struct *); static void moxa_start(struct tty_struct *); static void moxa_hangup(struct tty_struct *); @@ -261,7 +261,7 @@ static void MoxaPortEnable(int); static void MoxaPortDisable(int); static long MoxaPortGetMaxBaud(int); static long MoxaPortSetBaud(int, long); -static int MoxaPortSetTermio(int, struct termios *, speed_t); +static int MoxaPortSetTermio(int, struct ktermios *, speed_t); static int MoxaPortGetLineOut(int, int *, int *); static void MoxaPortLineCtrl(int, int, int); static void MoxaPortFlowCtrl(int, int, int, int, int, int); @@ -355,6 +355,8 @@ static int __init moxa_init(void) moxaDriver->init_termios.c_oflag = 0; moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; moxaDriver->init_termios.c_lflag = 0; + moxaDriver->init_termios.c_ispeed = 9600; + moxaDriver->init_termios.c_ospeed = 9600; moxaDriver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(moxaDriver, &moxa_ops); @@ -864,7 +866,7 @@ static void moxa_unthrottle(struct tty_struct *tty) } static void moxa_set_termios(struct tty_struct *tty, - struct termios *old_termios) + struct ktermios *old_termios) { struct moxa_str *ch = (struct moxa_str *) tty->driver_data; @@ -978,7 +980,7 @@ static void moxa_poll(unsigned long ignored) static void set_tty_param(struct tty_struct *tty) { - register struct termios *ts; + register struct ktermios *ts; struct moxa_str *ch; int rts, cts, txflow, rxflow, xany; @@ -1149,7 +1151,7 @@ static void shut_down(struct moxa_str *ch) static void receive_data(struct moxa_str *ch) { struct tty_struct *tp; - struct termios *ts; + struct ktermios *ts; unsigned long flags; ts = NULL; @@ -1912,9 +1914,9 @@ int MoxaPortsOfCard(int cardno) * * Function 12: Configure the port. * Syntax: - * int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud); + * int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud); * int port : port number (0 - 127) - * struct termios * termio : termio structure pointer + * struct ktermios * termio : termio structure pointer * speed_t baud : baud rate * * return: -1 : this port is invalid or termio == NULL @@ -2195,7 +2197,7 @@ long MoxaPortSetBaud(int port, long baud) return (baud); } -int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud) +int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud) { void __iomem *ofsAddr; tcflag_t cflag; diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 2dc49be144e6..c063359baf78 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -328,8 +328,8 @@ struct mxser_struct { int xmit_tail; int xmit_cnt; struct work_struct tqueue; - struct termios normal_termios; - struct termios callout_termios; + struct ktermios normal_termios; + struct ktermios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; wait_queue_head_t delta_msr_wait; @@ -364,8 +364,8 @@ static int mxserBoardCAP[MXSER_BOARDS] = { static struct tty_driver *mxvar_sdriver; static struct mxser_struct mxvar_table[MXSER_PORTS]; static struct tty_struct *mxvar_tty[MXSER_PORTS + 1]; -static struct termios *mxvar_termios[MXSER_PORTS + 1]; -static struct termios *mxvar_termios_locked[MXSER_PORTS + 1]; +static struct ktermios *mxvar_termios[MXSER_PORTS + 1]; +static struct ktermios *mxvar_termios_locked[MXSER_PORTS + 1]; static struct mxser_log mxvar_log; static int mxvar_diagflag; static unsigned char mxser_msr[MXSER_PORTS + 1]; @@ -402,7 +402,7 @@ static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong); static int mxser_ioctl_special(unsigned int, void __user *); static void mxser_throttle(struct tty_struct *); static void mxser_unthrottle(struct tty_struct *); -static void mxser_set_termios(struct tty_struct *, struct termios *); +static void mxser_set_termios(struct tty_struct *, struct ktermios *); static void mxser_stop(struct tty_struct *); static void mxser_start(struct tty_struct *); static void mxser_hangup(struct tty_struct *); @@ -414,7 +414,7 @@ static void mxser_check_modem_status(struct mxser_struct *, int); static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *); static int mxser_startup(struct mxser_struct *); static void mxser_shutdown(struct mxser_struct *); -static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios); +static int mxser_change_speed(struct mxser_struct *, struct ktermios *old_termios); static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *); static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *); static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *); @@ -726,6 +726,8 @@ static int mxser_init(void) mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL; mxvar_sdriver->init_termios = tty_std_termios; mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; + mxvar_sdriver->init_termios.c_ispeed = 9600; + mxvar_sdriver->init_termios.c_ospeed = 9600; mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(mxvar_sdriver, &mxser_ops); mxvar_sdriver->ttys = mxvar_tty; @@ -1749,7 +1751,7 @@ static void mxser_unthrottle(struct tty_struct *tty) /* MX_UNLOCK(&info->slock); */ } -static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct mxser_struct *info = tty->driver_data; unsigned long flags; @@ -2541,7 +2543,7 @@ static void mxser_shutdown(struct mxser_struct *info) * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static int mxser_change_speed(struct mxser_struct *info, struct termios *old_termios) +static int mxser_change_speed(struct mxser_struct *info, struct ktermios *old_termios) { unsigned cflag, cval, fcr; int ret = 0; diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index 369d2742d6be..efa8076c33e0 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c @@ -266,8 +266,8 @@ struct mxser_port { int xmit_tail; int xmit_cnt; - struct termios normal_termios; - struct termios callout_termios; + struct ktermios normal_termios; + struct ktermios callout_termios; struct mxser_mon mon_data; @@ -512,7 +512,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) * the specified baud rate for a serial port. */ static int mxser_change_speed(struct mxser_port *info, - struct termios *old_termios) + struct ktermios *old_termios) { unsigned cflag, cval, fcr; int ret = 0; @@ -1966,7 +1966,7 @@ static void mxser_start(struct tty_struct *tty) spin_unlock_irqrestore(&info->slock, flags); } -static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct mxser_port *info = tty->driver_data; unsigned long flags; diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 203dc2b661d5..103d338f21e2 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -142,7 +142,7 @@ static ssize_t r3964_write(struct tty_struct * tty, struct file * file, const unsigned char * buf, size_t nr); static int r3964_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg); -static void r3964_set_termios(struct tty_struct *tty, struct termios * old); +static void r3964_set_termios(struct tty_struct *tty, struct ktermios * old); static unsigned int r3964_poll(struct tty_struct * tty, struct file * file, struct poll_table_struct *wait); static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, @@ -1347,7 +1347,7 @@ static int r3964_ioctl(struct tty_struct * tty, struct file * file, } } -static void r3964_set_termios(struct tty_struct *tty, struct termios * old) +static void r3964_set_termios(struct tty_struct *tty, struct ktermios * old) { TRACE_L("set_termios"); } diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 603b9ade5eb0..e96a00fe1389 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -994,7 +994,7 @@ int is_ignored(int sig) * when the ldisc is closed. */ -static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) +static void n_tty_set_termios(struct tty_struct *tty, struct ktermios * old) { if (!tty) return; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 74d21c1c104f..5152cedd8878 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2375,7 +2375,7 @@ static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg) * tty pointer to tty structure * termios pointer to buffer to hold returned old termios */ -static void mgslpc_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; unsigned long flags; diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 80d3eedd7f96..c07a1b5cd05d 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -218,7 +218,7 @@ out: return retval; } -static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { tty->termios->c_cflag &= ~(CSIZE | PARENB); tty->termios->c_cflag |= (CS8 | CREAD); @@ -272,6 +272,8 @@ static void __init legacy_pty_init(void) pty_driver->init_termios.c_oflag = 0; pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; pty_driver->init_termios.c_lflag = 0; + pty_driver->init_termios.c_ispeed = 38400; + pty_driver->init_termios.c_ospeed = 38400; pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW; pty_driver->other = pty_slave_driver; tty_set_operations(pty_driver, &pty_ops); @@ -286,6 +288,8 @@ static void __init legacy_pty_init(void) pty_slave_driver->subtype = PTY_TYPE_SLAVE; pty_slave_driver->init_termios = tty_std_termios; pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; + pty_slave_driver->init_termios.c_ispeed = 38400; + pty_slave_driver->init_termios.c_ospeed = 38400; pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW; pty_slave_driver->other = pty_driver; @@ -366,6 +370,8 @@ static void __init unix98_pty_init(void) ptm_driver->init_termios.c_oflag = 0; ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; ptm_driver->init_termios.c_lflag = 0; + ptm_driver->init_termios.c_ispeed = 38400; + ptm_driver->init_termios.c_ospeed = 38400; ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; ptm_driver->other = pts_driver; @@ -381,6 +387,8 @@ static void __init unix98_pty_init(void) pts_driver->subtype = PTY_TYPE_SLAVE; pts_driver->init_termios = tty_std_termios; pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; + pts_driver->init_termios.c_ispeed = 38400; + pts_driver->init_termios.c_ospeed = 38400; pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; pts_driver->other = ptm_driver; diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 0a77bfcd5b5e..e2a94bfb2a43 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -1539,7 +1539,7 @@ static void rc_hangup(struct tty_struct * tty) wake_up_interruptible(&port->open_wait); } -static void rc_set_termios(struct tty_struct * tty, struct termios * old_termios) +static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termios) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; unsigned long flags; @@ -1614,6 +1614,8 @@ static inline int rc_init_drivers(void) riscom_driver->init_termios = tty_std_termios; riscom_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + riscom_driver->init_termios.c_ispeed = 9600; + riscom_driver->init_termios.c_ospeed = 9600; riscom_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(riscom_driver, &riscom_ops); if ((error = tty_register_driver(riscom_driver))) { diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 4fdf52e9f3b1..e94a62e30fc4 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -712,7 +712,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) * user mode into the driver (exception handler). *info CD manipulation is spinlock protected. */ static void configure_r_port(struct r_port *info, - struct termios *old_termios) + struct ktermios *old_termios) { unsigned cflag; unsigned long flags; @@ -1194,7 +1194,7 @@ static void rp_close(struct tty_struct *tty, struct file *filp) } static void rp_set_termios(struct tty_struct *tty, - struct termios *old_termios) + struct ktermios *old_termios) { struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; @@ -2214,7 +2214,7 @@ static int __init init_PCI(int boards_found) int count = 0; /* Work through the PCI device list, pulling out ours */ - while ((dev = pci_find_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) { + while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) { if (register_PCI(count + boards_found, dev)) count++; } @@ -2436,6 +2436,8 @@ static int __init rp_init(void) rocket_driver->init_termios = tty_std_termios; rocket_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + rocket_driver->init_termios.c_ispeed = 9600; + rocket_driver->init_termios.c_ospeed = 9600; #ifdef ROCKET_SOFT_FLOW rocket_driver->flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; #endif diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 4217d38caef9..75de5f66517a 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -695,6 +695,8 @@ static int a2232_init_drivers(void) a2232_driver->init_termios = tty_std_termios; a2232_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + a2232_driver->init_termios.c_ispeed = 9600; + a2232_driver->init_termios.c_ospeed = 9600; a2232_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(a2232_driver, &a2232_ops); if ((error = tty_register_driver(a2232_driver))) { diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 9ba13af234be..af50d32ae2c7 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -1695,7 +1695,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file, static void -cy_set_termios(struct tty_struct *tty, struct termios * old_termios) +cy_set_termios(struct tty_struct *tty, struct ktermios * old_termios) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 99137ab66b62..20946f5127e0 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -2311,7 +2311,7 @@ static void sx_hangup(struct tty_struct * tty) } -static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios) +static void sx_set_termios(struct tty_struct * tty, struct ktermios * old_termios) { struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; @@ -2400,6 +2400,8 @@ static int sx_init_drivers(void) specialix_driver->init_termios = tty_std_termios; specialix_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + specialix_driver->init_termios.c_ispeed = 9600; + specialix_driver->init_termios.c_ospeed = 9600; specialix_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(specialix_driver, &sx_ops); @@ -2475,7 +2477,7 @@ static int __init specialix_init(void) i++; continue; } - pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, + pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_IO8, pdev); if (!pdev) break; @@ -2491,6 +2493,9 @@ static int __init specialix_init(void) if (!sx_probe(&sx_board[i])) found ++; } + /* May exit pci_get sequence early with lots of boards */ + if (pdev != NULL) + pci_dev_put(pdev); } #endif diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index a547c0c8fb2a..71bfdccfb42e 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -141,9 +141,11 @@ static struct tty_driver *stl_serial; * with this termios initially. Basically all it defines is a raw port * at 9600, 8 data bits, 1 stop bit. */ -static struct termios stl_deftermios = { +static struct ktermios stl_deftermios = { .c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL), .c_cc = INIT_C_CC, + .c_ispeed = 9600, + .c_ospeed = 9600, }; /* @@ -464,7 +466,7 @@ static int stl_cd1400getreg(struct stlport *portp, int regnr); static int stl_cd1400updatereg(struct stlport *portp, int regnr, int value); static int stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp); static void stl_cd1400portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp); -static void stl_cd1400setport(struct stlport *portp, struct termios *tiosp); +static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp); static int stl_cd1400getsignals(struct stlport *portp); static void stl_cd1400setsignals(struct stlport *portp, int dtr, int rts); static void stl_cd1400ccrwait(struct stlport *portp); @@ -493,7 +495,7 @@ static int stl_sc26198updatereg(struct stlport *portp, int regnr, int value); static int stl_sc26198getglobreg(struct stlport *portp, int regnr); static int stl_sc26198panelinit(struct stlbrd *brdp, struct stlpanel *panelp); static void stl_sc26198portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp); -static void stl_sc26198setport(struct stlport *portp, struct termios *tiosp); +static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp); static int stl_sc26198getsignals(struct stlport *portp); static void stl_sc26198setsignals(struct stlport *portp, int dtr, int rts); static void stl_sc26198enablerxtx(struct stlport *portp, int rx, int tx); @@ -521,7 +523,7 @@ static void stl_sc26198otherisr(struct stlport *port, unsigned int iack); typedef struct uart { int (*panelinit)(struct stlbrd *brdp, struct stlpanel *panelp); void (*portinit)(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp); - void (*setport)(struct stlport *portp, struct termios *tiosp); + void (*setport)(struct stlport *portp, struct ktermios *tiosp); int (*getsignals)(struct stlport *portp); void (*setsignals)(struct stlport *portp, int dtr, int rts); void (*enablerxtx)(struct stlport *portp, int rx, int tx); @@ -1427,10 +1429,10 @@ static void stl_start(struct tty_struct *tty) /*****************************************************************************/ -static void stl_settermios(struct tty_struct *tty, struct termios *old) +static void stl_settermios(struct tty_struct *tty, struct ktermios *old) { struct stlport *portp; - struct termios *tiosp; + struct ktermios *tiosp; pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old); @@ -2468,7 +2470,7 @@ static int __init stl_findpcibrds(void) pr_debug("stl_findpcibrds()\n"); for (i = 0; (i < stl_nrpcibrds); i++) - while ((dev = pci_find_device(stl_pcibrds[i].vendid, + while ((dev = pci_get_device(stl_pcibrds[i].vendid, stl_pcibrds[i].devid, dev))) { /* @@ -2947,7 +2949,7 @@ static void stl_cd1400ccrwait(struct stlport *portp) * settings. */ -static void stl_cd1400setport(struct stlport *portp, struct termios *tiosp) +static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp) { struct stlbrd *brdp; unsigned long flags; @@ -3924,7 +3926,7 @@ static void stl_sc26198portinit(struct stlbrd *brdp, struct stlpanel *panelp, st * settings. */ -static void stl_sc26198setport(struct stlport *portp, struct termios *tiosp) +static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp) { struct stlbrd *brdp; unsigned long flags; diff --git a/drivers/char/sx.c b/drivers/char/sx.c index cc10af08cb05..e9bc147c32fe 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -2263,6 +2263,8 @@ static int sx_init_drivers(void) sx_driver->init_termios = tty_std_termios; sx_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + sx_driver->init_termios.c_ispeed = 9600; + sx_driver->init_termios.c_ospeed = 9600; sx_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(sx_driver, &sx_ops); diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 645187b9141e..acc6fab601cc 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -3060,7 +3060,7 @@ static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigne * * Return Value: None */ -static void mgsl_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; @@ -4405,6 +4405,8 @@ static int mgsl_init_tty(void) serial_driver->init_termios = tty_std_termios; serial_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->init_termios.c_ispeed = 9600; + serial_driver->init_termios.c_ospeed = 9600; serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &mgsl_ops); if ((rc = tty_register_driver(serial_driver)) < 0) { diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index e4730a7312b5..792c79c315e0 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -151,7 +151,7 @@ static struct tty_driver *serial_driver; static int open(struct tty_struct *tty, struct file * filp); static void close(struct tty_struct *tty, struct file * filp); static void hangup(struct tty_struct *tty); -static void set_termios(struct tty_struct *tty, struct termios *old_termios); +static void set_termios(struct tty_struct *tty, struct ktermios *old_termios); static int write(struct tty_struct *tty, const unsigned char *buf, int count); static void put_char(struct tty_struct *tty, unsigned char ch); @@ -816,7 +816,7 @@ static void hangup(struct tty_struct *tty) wake_up_interruptible(&info->open_wait); } -static void set_termios(struct tty_struct *tty, struct termios *old_termios) +static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct slgt_info *info = tty->driver_data; unsigned long flags; @@ -3546,6 +3546,8 @@ static int __init slgt_init(void) serial_driver->init_termios = tty_std_termios; serial_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->init_termios.c_ispeed = 9600; + serial_driver->init_termios.c_ospeed = 9600; serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &ops); if ((rc = tty_register_driver(serial_driver)) < 0) { diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 20a96ef250be..53e8ccf94fe3 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -519,7 +519,7 @@ static struct tty_driver *serial_driver; static int open(struct tty_struct *tty, struct file * filp); static void close(struct tty_struct *tty, struct file * filp); static void hangup(struct tty_struct *tty); -static void set_termios(struct tty_struct *tty, struct termios *old_termios); +static void set_termios(struct tty_struct *tty, struct ktermios *old_termios); static int write(struct tty_struct *tty, const unsigned char *buf, int count); static void put_char(struct tty_struct *tty, unsigned char ch); @@ -918,7 +918,7 @@ static void hangup(struct tty_struct *tty) /* Set new termios settings */ -static void set_termios(struct tty_struct *tty, struct termios *old_termios) +static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) { SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; @@ -4034,6 +4034,8 @@ static int __init synclinkmp_init(void) serial_driver->init_termios = tty_std_termios; serial_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->init_termios.c_ispeed = 9600; + serial_driver->init_termios.c_ospeed = 9600; serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &ops); if ((rc = tty_register_driver(serial_driver)) < 0) { diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 0ffba4e911ca..30486df9fd3f 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -495,8 +495,8 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) struct sgttyb tmp; mutex_lock(&tty->termios_mutex); - tmp.sg_ispeed = tty->c_ispeed; - tmp.sg_ospeed = tty->c_ospeed; + tmp.sg_ispeed = tty->termios->c_ispeed; + tmp.sg_ospeed = tty->termios->c_ospeed; tmp.sg_erase = tty->termios->c_cc[VERASE]; tmp.sg_kill = tty->termios->c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index d0b94dd1af6d..e01317cb1a0e 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -153,6 +153,8 @@ static int scc_init_drivers(void) scc_driver->init_termios = tty_std_termios; scc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + scc_driver->init_termios.c_ispeed = 9600; + scc_driver->init_termios.c_ospeed = 9600; scc_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(scc_driver, &scc_ops); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 787a630a8e56..0475a54df83a 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1203,7 +1203,7 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file, return error; } -static void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old) +static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old) { #ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_set_termios\n"); diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 7edea015867e..458b6462f937 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -127,7 +127,7 @@ static int if_write_room(struct tty_struct *tty); static int if_chars_in_buffer(struct tty_struct *tty); static void if_throttle(struct tty_struct *tty); static void if_unthrottle(struct tty_struct *tty); -static void if_set_termios(struct tty_struct *tty, struct termios *old); +static void if_set_termios(struct tty_struct *tty, struct ktermios *old); static int if_tiocmget(struct tty_struct *tty, struct file *file); static int if_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); @@ -490,7 +490,7 @@ static void if_unthrottle(struct tty_struct *tty) mutex_unlock(&cs->mutex); } -static void if_set_termios(struct tty_struct *tty, struct termios *old) +static void if_set_termios(struct tty_struct *tty, struct ktermios *old) { struct cardstate *cs; unsigned int iflag; diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 2b91bb07fc7f..fc80afe555b9 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1464,7 +1464,7 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file, } static void -isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) +isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { modem_info *info = (modem_info *) tty->driver_data; diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 6a98b7ae4975..ad1857364d51 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -117,7 +117,7 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed) { struct sirtty_cb *priv = dev->priv; struct tty_struct *tty; - struct termios old_termios; + struct ktermios old_termios; int cflag; IRDA_ASSERT(priv != NULL, return -1;); @@ -318,7 +318,7 @@ static void irtty_write_wakeup(struct tty_struct *tty) static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) { - struct termios old_termios; + struct ktermios old_termios; int cflag; lock_kernel(); diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 6f43e04dbefd..2d173e5c8a09 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -60,8 +60,6 @@ static unsigned short int sclp_tty_chars_count; struct tty_driver *sclp_tty_driver; -extern struct termios tty_std_termios; - static struct sclp_ioctls sclp_ioctls; static struct sclp_ioctls sclp_ioctls_init = { diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 4717c3611601..09844621edc0 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -1659,7 +1659,7 @@ tty3270_flush_buffer(struct tty_struct *tty) * Check for visible/invisible input switches */ static void -tty3270_set_termios(struct tty_struct *tty, struct termios *old) +tty3270_set_termios(struct tty_struct *tty, struct ktermios *old) { struct tty3270 *tp; int new; diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index 6a1a568ca649..facb67855619 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -214,8 +214,8 @@ static void serial21285_shutdown(struct uart_port *port) } static void -serial21285_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +serial21285_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned long flags; unsigned int baud, quot, h_lcr; diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index 9b8b585513ec..cad426c9711e 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -1061,7 +1061,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, return 0; } -static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index 634ecca36a77..68817a7d8c0d 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -1523,7 +1523,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file, /* FIX UP modem control here someday...... */ -static void rs_360_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { ser_info_t *info = (ser_info_t *)tty->driver_data; diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index e34bd03cfce7..51f3c739f7e1 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1763,8 +1763,8 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int } static void -serial8250_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +serial8250_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned char cval, fcr = 0; diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 4d3626ef4643..61db6973755a 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -345,8 +345,8 @@ static void pl010_shutdown(struct uart_port *port) } static void -pl010_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +pl010_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned int lcr_h, old_cr; unsigned long flags; diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index d503625730df..9a3b374b2a08 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -412,8 +412,8 @@ static void pl011_shutdown(struct uart_port *port) } static void -pl011_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +pl011_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned int lcr_h, old_cr; unsigned long flags; diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 9217ee6c7865..ed7f7209ea59 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -478,7 +478,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned /* * Change the port parameters */ -static void atmel_set_termios(struct uart_port *port, struct termios * termios, struct termios * old) +static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, struct ktermios * old) { unsigned long flags; unsigned int mode, imr, quot, baud; diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index 598012714882..23827189ec0e 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -286,8 +286,8 @@ static void clps711xuart_shutdown(struct uart_port *port) } static void -clps711xuart_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned int ubrlcr, baud, quot; unsigned long flags; diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 7a24e53546c7..42b050c46abe 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -804,8 +804,8 @@ static struct e100_serial rs_table[] = { #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) -static struct termios *serial_termios[NR_PORTS]; -static struct termios *serial_termios_locked[NR_PORTS]; +static struct ktermios *serial_termios[NR_PORTS]; +static struct ktermios *serial_termios_locked[NR_PORTS]; #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER static struct fast_timer fast_timers[NR_PORTS]; #endif @@ -4223,7 +4223,7 @@ rs_ioctl(struct tty_struct *tty, struct file * file, } static void -rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; @@ -4877,6 +4877,8 @@ rs_init(void) driver->init_termios = tty_std_termios; driver->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ + driver->init_termios.c_ispeed = 115200; + driver->init_termios.c_ospeed = 115200; driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; driver->termios = serial_termios; driver->termios_locked = serial_termios_locked; diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h index f30b93d6ef79..4a23340663aa 100644 --- a/drivers/serial/crisv10.h +++ b/drivers/serial/crisv10.h @@ -93,8 +93,8 @@ struct e100_serial { struct work_struct work; struct async_icount icount; /* error-statistics etc.*/ - struct termios normal_termios; - struct termios callout_termios; + struct ktermios normal_termios; + struct ktermios callout_termios; #ifdef DECLARE_WAITQUEUE wait_queue_head_t open_wait; wait_queue_head_t close_wait; diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index af1544f3356f..587d87b9eb3c 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -461,8 +461,8 @@ static void dz_break_ctl(struct uart_port *uport, int break_state) spin_unlock_irqrestore(&uport->lock, flags); } -static void dz_set_termios(struct uart_port *uport, struct termios *termios, - struct termios *old_termios) +static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, + struct ktermios *old_termios) { struct dz_port *dport = (struct dz_port *)uport; unsigned long flags; diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 8aa0f641866b..7d623003e65e 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -1087,8 +1087,8 @@ static void icom_close(struct uart_port *port) } static void icom_set_termios(struct uart_port *port, - struct termios *termios, - struct termios *old_termios) + struct ktermios *termios, + struct ktermios *old_termios) { int baud; unsigned cflag, iflag; diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index ee5c782597dd..e216dcf29376 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -459,8 +459,8 @@ static void imx_shutdown(struct uart_port *port) } static void -imx_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +imx_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c index 2308d26c8629..9cc0be932316 100644 --- a/drivers/serial/ioc3_serial.c +++ b/drivers/serial/ioc3_serial.c @@ -950,7 +950,7 @@ static void transmit_chars(struct uart_port *the_port) */ static void ioc3_change_speed(struct uart_port *the_port, - struct termios *new_termios, struct termios *old_termios) + struct ktermios *new_termios, struct ktermios *old_termios) { struct ioc3_port *port = get_ioc3_port(the_port); unsigned int cflag; @@ -1853,7 +1853,7 @@ static int ic3_startup(struct uart_port *the_port) */ static void ic3_set_termios(struct uart_port *the_port, - struct termios *termios, struct termios *old_termios) + struct ktermios *termios, struct ktermios *old_termios) { unsigned long port_flags; diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index 711bd1511439..c862f67c985a 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -1681,7 +1681,7 @@ static void transmit_chars(struct uart_port *the_port) */ static void ioc4_change_speed(struct uart_port *the_port, - struct termios *new_termios, struct termios *old_termios) + struct ktermios *new_termios, struct ktermios *old_termios) { struct ioc4_port *port = get_ioc4_port(the_port, 0); int baud, bits; @@ -1802,7 +1802,7 @@ static inline int ic4_startup_local(struct uart_port *the_port) ioc4_set_proto(port, the_port->mapbase); /* set the speed of the serial port */ - ioc4_change_speed(the_port, info->tty->termios, (struct termios *)0); + ioc4_change_speed(the_port, info->tty->termios, (struct ktermios *)0); return 0; } @@ -2570,7 +2570,7 @@ static int ic4_startup(struct uart_port *the_port) */ static void ic4_set_termios(struct uart_port *the_port, - struct termios *termios, struct termios *old_termios) + struct ktermios *termios, struct ktermios *old_termios) { unsigned long port_flags; diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index dca6c1bde8f9..0746c9446ae0 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c @@ -840,8 +840,8 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag, /* The port lock is not held. */ static void -ip22zilog_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; unsigned long flags; diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index f8262e6ad8d3..7cf1c60027f8 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c @@ -142,7 +142,7 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch) { unsigned long lock_flags; struct jsm_channel *channel = (struct jsm_channel *)port; - struct termios *termios; + struct ktermios *termios; spin_lock_irqsave(&port->lock, lock_flags); termios = port->info->tty->termios; @@ -180,7 +180,7 @@ static int jsm_tty_open(struct uart_port *port) struct jsm_board *brd; int rc = 0; struct jsm_channel *channel = (struct jsm_channel *)port; - struct termios *termios; + struct ktermios *termios; /* Get board pointer from our array of majors we have allocated */ brd = channel->ch_bd; @@ -269,7 +269,7 @@ static int jsm_tty_open(struct uart_port *port) static void jsm_tty_close(struct uart_port *port) { struct jsm_board *bd; - struct termios *ts; + struct ktermios *ts; struct jsm_channel *channel = (struct jsm_channel *)port; jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); @@ -302,8 +302,8 @@ static void jsm_tty_close(struct uart_port *port) } static void jsm_tty_set_termios(struct uart_port *port, - struct termios *termios, - struct termios *old_termios) + struct ktermios *termios, + struct ktermios *old_termios) { unsigned long lock_flags; struct jsm_channel *channel = (struct jsm_channel *)port; diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c index 7656a35f5e2f..6e09c8b395e8 100644 --- a/drivers/serial/m32r_sio.c +++ b/drivers/serial/m32r_sio.c @@ -699,7 +699,7 @@ static unsigned int m32r_sio_get_divisor(struct uart_port *port, } static void m32r_sio_set_termios(struct uart_port *port, - struct termios *termios, struct termios *old) + struct ktermios *termios, struct ktermios *old) { struct uart_sio_port *up = (struct uart_sio_port *)port; unsigned char cval = 0; diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 3db206d29b33..08430961a895 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -1132,7 +1132,7 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, return 0; } -static void mcfrs_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 6dd579ed9777..9d11a75663e6 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -270,8 +270,8 @@ mpc52xx_uart_shutdown(struct uart_port *port) } static void -mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new, - struct termios *old) +mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, + struct ktermios *old) { struct mpc52xx_psc __iomem *psc = PSC(port); unsigned long flags; diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index 29823bd60fb0..3d2fcc57b1ce 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -1440,8 +1440,8 @@ mpsc_shutdown(struct uart_port *port) } static void -mpsc_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +mpsc_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct mpsc_port_info *pi = (struct mpsc_port_info *)port; u32 baud; diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c index 8ad1b8c5ec5d..ccb8fa1800a5 100644 --- a/drivers/serial/mux.c +++ b/drivers/serial/mux.c @@ -273,8 +273,8 @@ static void mux_shutdown(struct uart_port *port) * The Serial Mux does not support this function. */ static void -mux_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +mux_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { } diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c index 062bad457b1a..b56f7db45031 100644 --- a/drivers/serial/netx-serial.c +++ b/drivers/serial/netx-serial.c @@ -337,8 +337,8 @@ static void netx_shutdown(struct uart_port *port) } static void -netx_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +netx_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned int baud, quot; unsigned char old_cr; diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index bf9809ed9c0b..752ef07516b9 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -1262,8 +1262,8 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) } -static void __pmz_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct uart_pmac_port *uap = to_pmz(port); unsigned long baud; @@ -1273,7 +1273,7 @@ static void __pmz_set_termios(struct uart_port *port, struct termios *termios, if (ZS_IS_ASLEEP(uap)) return; - memcpy(&uap->termios_cache, termios, sizeof(struct termios)); + memcpy(&uap->termios_cache, termios, sizeof(struct ktermios)); /* XXX Check which revs of machines actually allow 1 and 4Mb speeds * on the IR dongle. Note that the IRTTY driver currently doesn't know @@ -1313,8 +1313,8 @@ static void __pmz_set_termios(struct uart_port *port, struct termios *termios, } /* The port lock is not held. */ -static void pmz_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct uart_pmac_port *uap = to_pmz(port); unsigned long flags; diff --git a/drivers/serial/pmac_zilog.h b/drivers/serial/pmac_zilog.h index c03f9bfacdd8..570b0d925e83 100644 --- a/drivers/serial/pmac_zilog.h +++ b/drivers/serial/pmac_zilog.h @@ -60,7 +60,7 @@ struct uart_pmac_port { volatile struct dbdma_regs __iomem *tx_dma_regs; volatile struct dbdma_regs __iomem *rx_dma_regs; - struct termios termios_cache; + struct ktermios termios_cache; }; #define to_pmz(p) ((struct uart_pmac_port *)(p)) diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 415fe9633a9b..d403aaa55092 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -433,8 +433,8 @@ static void serial_pxa_shutdown(struct uart_port *port) } static void -serial_pxa_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct uart_pxa_port *up = (struct uart_pxa_port *)port; unsigned char cval, fcr = 0; diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 8dfc2dd058ca..3ba9208ebd0c 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -738,8 +738,8 @@ static unsigned int s3c24xx_serial_getclk(struct uart_port *port, } static void s3c24xx_serial_set_termios(struct uart_port *port, - struct termios *termios, - struct termios *old) + struct ktermios *termios, + struct ktermios *old) { struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); struct s3c24xx_uart_port *ourport = to_ourport(port); diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index d4065266b6fc..58a83c27e14b 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -408,8 +408,8 @@ static void sa1100_shutdown(struct uart_port *port) } static void -sa1100_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +sa1100_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct sa1100_port *sport = (struct sa1100_port *)port; unsigned long flags; diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index c67b05e9a451..f84982e508c7 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -65,7 +65,7 @@ static struct lock_class_key port_lock_key; #define uart_console(port) (0) #endif -static void uart_change_speed(struct uart_state *state, struct termios *old_termios); +static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, int pm_state); @@ -338,8 +338,8 @@ EXPORT_SYMBOL(uart_update_timeout); * we're actually going to be using. */ unsigned int -uart_get_baud_rate(struct uart_port *port, struct termios *termios, - struct termios *old, unsigned int min, unsigned int max) +uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, + struct ktermios *old, unsigned int min, unsigned int max) { unsigned int try, baud, altbaud = 38400; upf_t flags = port->flags & UPF_SPD_MASK; @@ -421,11 +421,11 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) EXPORT_SYMBOL(uart_get_divisor); static void -uart_change_speed(struct uart_state *state, struct termios *old_termios) +uart_change_speed(struct uart_state *state, struct ktermios *old_termios) { struct tty_struct *tty = state->info->tty; struct uart_port *port = state->port; - struct termios *termios; + struct ktermios *termios; /* * If we have no tty, termios, or the port does not exist, @@ -1139,7 +1139,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, return ret; } -static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct uart_state *state = tty->driver_data; unsigned long flags; @@ -1866,7 +1866,7 @@ int __init uart_set_options(struct uart_port *port, struct console *co, int baud, int parity, int bits, int flow) { - struct termios termios; + struct ktermios termios; int i; /* @@ -1876,7 +1876,7 @@ uart_set_options(struct uart_port *port, struct console *co, spin_lock_init(&port->lock); lockdep_set_class(&port->lock, &port_lock_key); - memset(&termios, 0, sizeof(struct termios)); + memset(&termios, 0, sizeof(struct ktermios)); termios.c_cflag = CREAD | HUPCL | CLOCAL; @@ -1991,12 +1991,12 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) * Re-enable the console device after suspending. */ if (uart_console(port)) { - struct termios termios; + struct ktermios termios; /* * First try to use the console cflag setting. */ - memset(&termios, 0, sizeof(struct termios)); + memset(&termios, 0, sizeof(struct ktermios)); termios.c_cflag = port->cons->cflag; /* @@ -2189,6 +2189,7 @@ int uart_register_driver(struct uart_driver *drv) normal->subtype = SERIAL_TYPE_NORMAL; normal->init_termios = tty_std_termios; normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600; normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; normal->driver_state = drv; tty_set_operations(normal, &uart_ops); diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index 5e1ac356bbb0..eb18d429752d 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c @@ -348,8 +348,8 @@ static void lh7a40xuart_shutdown (struct uart_port* port) } static void lh7a40xuart_set_termios (struct uart_port* port, - struct termios* termios, - struct termios* old) + struct ktermios* termios, + struct ktermios* old) { unsigned int con; unsigned int inten; diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 2a48289ac722..7186a82c4759 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -556,8 +556,8 @@ static void serial_txx9_shutdown(struct uart_port *port) } static void -serial_txx9_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct uart_txx9_port *up = (struct uart_txx9_port *)port; unsigned int cval, fcr = 0; diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 3b5f19ec2126..9031b57f12dd 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -943,8 +943,8 @@ static void sci_shutdown(struct uart_port *port) s->disable(port); } -static void sci_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +static void sci_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct sci_port *s = &sci_ports[port->line]; unsigned int status, baud, smr_val; diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index 956b2cf08e1e..253ceb895ca7 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -361,8 +361,8 @@ static int snp_startup(struct uart_port *port) * */ static void -snp_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +snp_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { } diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index 03941d27d15d..40d48566215c 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -281,8 +281,8 @@ static void sunhv_shutdown(struct uart_port *port) } /* port->lock is not held. */ -static void sunhv_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); unsigned int quot = uart_get_divisor(port, baud); diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 08a7cd6a3a0c..493d5bbb661b 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -786,8 +786,8 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla } /* port->lock is not held. */ -static void sunsab_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; unsigned long flags; diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index c577faea60e8..564592b2b2ba 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -893,8 +893,8 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, } static void -sunsu_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +sunsu_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned int baud, quot; diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index b2cc703b2b9e..75de919a9471 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -922,8 +922,8 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, /* The port lock is not held. */ static void -sunzilog_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; unsigned long flags; diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 83690653b78b..92eba893559d 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -214,8 +214,8 @@ static void ulite_shutdown(struct uart_port *port) free_irq(port->irq, port); } -static void ulite_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned long flags; unsigned int baud; diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c index 28f3bbff87bf..dd98aca6ed08 100644 --- a/drivers/serial/v850e_uart.c +++ b/drivers/serial/v850e_uart.c @@ -404,8 +404,8 @@ static void v850e_uart_shutdown (struct uart_port *port) } static void -v850e_uart_set_termios (struct uart_port *port, struct termios *termios, - struct termios *old) +v850e_uart_set_termios (struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned cflags = termios->c_cflag; diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index fd51f8182dec..cf0e663b42ed 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -562,8 +562,8 @@ static void siu_shutdown(struct uart_port *port) free_irq(port->irq, port); } -static void siu_set_termios(struct uart_port *port, struct termios *new, - struct termios *old) +static void siu_set_termios(struct uart_port *port, struct ktermios *new, + struct ktermios *old) { tcflag_t c_cflag, c_iflag; uint8_t lcr, fcr, ier; diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 792becdfe6f8..fc3197273663 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -1238,7 +1238,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, return 0; } -static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct dec_serial *info = (struct dec_serial *)tty->driver_data; int was_stopped; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7f1fa956dcdb..98199628e394 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -677,10 +677,10 @@ static const __u8 acm_tty_size[] = { 5, 6, 7, 8 }; -static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old) +static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) { struct acm *acm = tty->driver_data; - struct termios *termios = tty->termios; + struct ktermios *termios = tty->termios; struct usb_cdc_line_coding newline; int newctrl = acm->ctrlout; diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 208e55a667ac..5516c59ed5ec 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -200,7 +200,7 @@ static void gs_unthrottle(struct tty_struct * tty); static void gs_break(struct tty_struct *tty, int break_state); static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static void gs_set_termios(struct tty_struct *tty, struct termios *old); +static void gs_set_termios(struct tty_struct *tty, struct ktermios *old); static int gs_send(struct gs_dev *dev); static int gs_send_packet(struct gs_dev *dev, char *packet, @@ -1077,7 +1077,7 @@ static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, /* * gs_set_termios */ -static void gs_set_termios(struct tty_struct *tty, struct termios *old) +static void gs_set_termios(struct tty_struct *tty, struct ktermios *old) { } diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 863966c1c5ac..5261cd22ee6b 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -156,7 +156,7 @@ cleanup: } static void ark3116_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct ark3116_private *priv = usb_get_serial_port_data(port); @@ -326,7 +326,7 @@ static void ark3116_set_termios(struct usb_serial_port *port, static int ark3116_open(struct usb_serial_port *port, struct file *filp) { - struct termios tmp_termios; + struct ktermios tmp_termios; struct usb_serial *serial = port->serial; char *buf; int result = 0; diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 8835bb58ca9b..38b4dae319ee 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -92,7 +92,7 @@ static void belkin_sa_shutdown (struct usb_serial *serial); static int belkin_sa_open (struct usb_serial_port *port, struct file *filp); static void belkin_sa_close (struct usb_serial_port *port, struct file *filp); static void belkin_sa_read_int_callback (struct urb *urb); -static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old); +static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios * old); static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state ); static int belkin_sa_tiocmget (struct usb_serial_port *port, struct file *file); @@ -333,7 +333,7 @@ exit: __FUNCTION__, retval); } -static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct belkin_sa_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 7167728d764c..9386e216d681 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -65,7 +65,7 @@ static int usb_console_setup(struct console *co, char *options) struct usb_serial_port *port; int retval = 0; struct tty_struct *tty; - struct termios *termios; + struct ktermios *termios; dbg ("%s", __FUNCTION__); diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index f95d42c0d16a..2f9b7ac32663 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -41,7 +41,7 @@ static int cp2101_open(struct usb_serial_port*, struct file*); static void cp2101_cleanup(struct usb_serial_port*); static void cp2101_close(struct usb_serial_port*, struct file*); static void cp2101_get_termios(struct usb_serial_port*); -static void cp2101_set_termios(struct usb_serial_port*, struct termios*); +static void cp2101_set_termios(struct usb_serial_port*, struct ktermios*); static int cp2101_tiocmget (struct usb_serial_port *, struct file *); static int cp2101_tiocmset (struct usb_serial_port *, struct file *, unsigned int, unsigned int); @@ -506,7 +506,7 @@ static void cp2101_get_termios (struct usb_serial_port *port) } static void cp2101_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { unsigned int cflag, old_cflag=0; int baud=0, bits; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 093f303b3189..a1fdb85b8c0a 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -143,7 +143,7 @@ struct cypress_private { wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */ char prev_status, diff_status; /* used for TIOCMIWAIT */ /* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */ - struct termios tmp_termios; /* stores the old termios settings */ + struct ktermios tmp_termios; /* stores the old termios settings */ }; /* write buffer structure */ @@ -165,7 +165,7 @@ static int cypress_write (struct usb_serial_port *port, const unsigned char *b static void cypress_send (struct usb_serial_port *port); static int cypress_write_room (struct usb_serial_port *port); static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void cypress_set_termios (struct usb_serial_port *port, struct termios * old); +static void cypress_set_termios (struct usb_serial_port *port, struct ktermios * old); static int cypress_tiocmget (struct usb_serial_port *port, struct file *file); static int cypress_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static int cypress_chars_in_buffer (struct usb_serial_port *port); @@ -949,13 +949,13 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi switch (cmd) { case TIOCGSERIAL: - if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) { + if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct ktermios))) { return -EFAULT; } return (0); break; case TIOCSSERIAL: - if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) { + if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct ktermios))) { return -EFAULT; } /* here we need to call cypress_set_termios to invoke the new settings */ @@ -1019,7 +1019,7 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi static void cypress_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct cypress_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 83d0e21145b0..9d9ea874639c 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -449,7 +449,7 @@ static int digi_transmit_idle( struct usb_serial_port *port, static void digi_rx_throttle (struct usb_serial_port *port); static void digi_rx_unthrottle (struct usb_serial_port *port); static void digi_set_termios( struct usb_serial_port *port, - struct termios *old_termios ); + struct ktermios *old_termios ); static void digi_break_ctl( struct usb_serial_port *port, int break_state ); static int digi_ioctl( struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg ); @@ -976,7 +976,7 @@ dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num ); static void digi_set_termios( struct usb_serial_port *port, - struct termios *old_termios ) + struct ktermios *old_termios ) { struct digi_port *priv = usb_get_serial_port_data(port); @@ -1463,7 +1463,7 @@ static int digi_open( struct usb_serial_port *port, struct file *filp ) int ret; unsigned char buf[32]; struct digi_port *priv = usb_get_serial_port_data(port); - struct termios not_termios; + struct ktermios not_termios; unsigned long flags = 0; diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 4ce10a831953..92beeb19795f 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -92,7 +92,7 @@ static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void empeg_write_bulk_callback (struct urb *urb); static void empeg_read_bulk_callback (struct urb *urb); @@ -442,7 +442,7 @@ static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsign } -static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { dbg("%s - port %d", __FUNCTION__, port->number); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 72e4d48f51e9..41b0ad2d56ac 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -595,7 +595,7 @@ static int ftdi_chars_in_buffer (struct usb_serial_port *port); static void ftdi_write_bulk_callback (struct urb *urb); static void ftdi_read_bulk_callback (struct urb *urb); static void ftdi_process_read (struct work_struct *work); -static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old); +static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios * old); static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file); static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear); static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); @@ -1880,7 +1880,7 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) * WARNING: set_termios calls this with old_termios in kernel space */ -static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { /* ftdi_termios */ struct usb_device *dev = port->serial->dev; unsigned int cflag = port->tty->termios->c_cflag; diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index d06547a13f28..f623d58370a4 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -229,7 +229,7 @@ static int edge_write_room (struct usb_serial_port *port); static int edge_chars_in_buffer (struct usb_serial_port *port); static void edge_throttle (struct usb_serial_port *port); static void edge_unthrottle (struct usb_serial_port *port); -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); static void edge_break (struct usb_serial_port *port, int break_state); static int edge_tiocmget (struct usb_serial_port *port, struct file *file); @@ -257,7 +257,7 @@ static void handle_new_lsr (struct edgeport_port *edge_port, __u8 lsrData, __u8 static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u8 param); static int calc_baud_rate_divisor (int baud_rate, int *divisor); static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate); -static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios); +static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios); static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue); static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer, int writeLength); static void send_more_port_data (struct edgeport_serial *edge_serial, struct edgeport_port *edge_port); @@ -1431,7 +1431,7 @@ static void edge_unthrottle (struct usb_serial_port *port) * SerialSetTermios * this function is called by the tty driver when it wants to change the termios structure *****************************************************************************/ -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; @@ -2412,7 +2412,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r #ifndef CMSPAR #define CMSPAR 0 #endif -static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios) +static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios) { struct tty_struct *tty; int baud; diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index ee0c921e1520..2da2684e0809 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -238,7 +238,7 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned c static void stop_read(struct edgeport_port *edge_port); static int restart_read(struct edgeport_port *edge_port); -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void edge_send(struct usb_serial_port *port); /* circular buffer */ @@ -2361,7 +2361,7 @@ static int restart_read(struct edgeport_port *edge_port) return status; } -static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios) +static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios) { struct ump_uart_config *config; struct tty_struct *tty; @@ -2512,7 +2512,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio return; } -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 331bf81556fc..8fdf486e3465 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -107,7 +107,7 @@ static void ir_close (struct usb_serial_port *port, struct file *filep); static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int count); static void ir_write_bulk_callback (struct urb *urb); static void ir_read_bulk_callback (struct urb *urb); -static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static u8 ir_baud = 0; static u8 ir_xbof = 0; @@ -497,7 +497,7 @@ static void ir_read_bulk_callback (struct urb *urb) return; } -static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { unsigned char *transfer_buffer; unsigned int cflag; diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 7639652cec42..9d2fdfd6865f 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -264,7 +264,7 @@ static void keyspan_break_ctl (struct usb_serial_port *port, int break_state) static void keyspan_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { int baud_rate, device_port; struct keyspan_port_private *p_priv; diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 7472ed6bf626..6413d73c139c 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -59,7 +59,7 @@ static int keyspan_ioctl (struct usb_serial_port *port, unsigned int cmd, unsigned long arg); static void keyspan_set_termios (struct usb_serial_port *port, - struct termios *old); + struct ktermios *old); static void keyspan_break_ctl (struct usb_serial_port *port, int break_state); static int keyspan_tiocmget (struct usb_serial_port *port, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index e09a0bfe6231..126b9703bbaf 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -365,7 +365,7 @@ static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state static void keyspan_pda_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; unsigned int cflag = port->tty->termios->c_cflag; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 17e205699c2b..73d755df4840 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -86,7 +86,7 @@ static int klsi_105_write_room (struct usb_serial_port *port); static void klsi_105_read_bulk_callback (struct urb *urb); static void klsi_105_set_termios (struct usb_serial_port *port, - struct termios * old); + struct ktermios *old); static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, @@ -164,7 +164,7 @@ struct klsi_105_port_settings { #define URB_TRANSFER_BUFFER_SIZE 64 struct klsi_105_private { struct klsi_105_port_settings cfg; - struct termios termios; + struct ktermios termios; unsigned long line_state; /* modem line settings */ /* write pool */ struct urb * write_urb_pool[NUM_URBS]; @@ -688,7 +688,7 @@ static void klsi_105_read_bulk_callback (struct urb *urb) static void klsi_105_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct klsi_105_private *priv = usb_get_serial_port_data(port); unsigned int iflag = port->tty->termios->c_iflag; diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 237289920f03..e284d6c0fd35 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -136,7 +136,7 @@ struct kobil_private { int cur_pos; // index of the next char to send in buf __u16 device_type; int line_state; - struct termios internal_termios; + struct ktermios internal_termios; }; @@ -624,11 +624,11 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, switch (cmd) { case TCGETS: // 0x5401 - if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) { + if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) { dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); return -EFAULT; } - if (kernel_termios_to_user_termios((struct termios __user *)arg, + if (kernel_termios_to_user_termios((struct ktermios __user *)arg, &priv->internal_termios)) return -EFAULT; return 0; @@ -638,12 +638,12 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number); return -ENOTTY; } - if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) { + if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) { dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); return -EFAULT; } if (user_termios_to_kernel_termios(&priv->internal_termios, - (struct termios __user *)arg)) + (struct ktermios __user *)arg)) return -EFAULT; settings = kzalloc(50, GFP_KERNEL); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index a906e500a02b..38b1d17e06ef 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -98,7 +98,7 @@ static void mct_u232_close (struct usb_serial_port *port, struct file *filp); static void mct_u232_read_int_callback (struct urb *urb); static void mct_u232_set_termios (struct usb_serial_port *port, - struct termios * old); + struct ktermios * old); static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, @@ -556,7 +556,7 @@ exit: } /* mct_u232_read_int_callback */ static void mct_u232_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 70f93b18292f..e55f4ed81d7b 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1014,7 +1014,7 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, * the specified new settings. */ static void change_port_settings(struct moschip_port *mos7720_port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial_port *port; struct usb_serial *serial; @@ -1203,7 +1203,7 @@ static void change_port_settings(struct moschip_port *mos7720_port, * termios structure. */ static void mos7720_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { int status; unsigned int cflag; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 5432c6340086..8cc728a49e41 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1931,7 +1931,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, *****************************************************************************/ static void mos7840_change_port_settings(struct moschip_port *mos7840_port, - struct termios *old_termios) + struct ktermios *old_termios) { struct tty_struct *tty; int baud; @@ -2118,7 +2118,7 @@ static void mos7840_change_port_settings(struct moschip_port *mos7840_port, *****************************************************************************/ static void mos7840_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { int status; unsigned int cflag; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 130afbbd3fca..0ae4098718c3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -59,7 +59,7 @@ static int option_chars_in_buffer(struct usb_serial_port *port); static int option_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); static void option_set_termios(struct usb_serial_port *port, - struct termios *old); + struct ktermios *old); static void option_break_ctl(struct usb_serial_port *port, int break_state); static int option_tiocmget(struct usb_serial_port *port, struct file *file); static int option_tiocmset(struct usb_serial_port *port, struct file *file, @@ -230,7 +230,7 @@ static void option_break_ctl(struct usb_serial_port *port, int break_state) } static void option_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { dbg("%s", __FUNCTION__); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index bc800c8787a8..d124d780e42e 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -455,7 +455,7 @@ static int pl2303_chars_in_buffer(struct usb_serial_port *port) } static void pl2303_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); @@ -687,7 +687,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp) static int pl2303_open(struct usb_serial_port *port, struct file *filp) { - struct termios tmp_termios; + struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned char *buf; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 4b5097fa48d7..6d8e91e00ecf 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -145,7 +145,7 @@ static void sierra_break_ctl(struct usb_serial_port *port, int break_state) } static void sierra_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { dbg("%s", __FUNCTION__); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index ae98d8cbdbb8..f42eb9ea6405 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -161,7 +161,7 @@ static void ti_throttle(struct usb_serial_port *port); static void ti_unthrottle(struct usb_serial_port *port); static int ti_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); static void ti_set_termios(struct usb_serial_port *port, - struct termios *old_termios); + struct ktermios *old_termios); static int ti_tiocmget(struct usb_serial_port *port, struct file *file); static int ti_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); @@ -881,7 +881,7 @@ static int ti_ioctl(struct usb_serial_port *port, struct file *file, static void ti_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct ti_port *tport = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 3d5072f14b8d..716f6806cc89 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -397,7 +397,7 @@ exit: return retval; } -static void serial_set_termios (struct tty_struct *tty, struct termios * old) +static void serial_set_termios (struct tty_struct *tty, struct ktermios * old) { struct usb_serial_port *port = tty->driver_data; diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index eef5eaa5fa0b..b09f06096056 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -46,7 +46,7 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id static int visor_calc_num_ports(struct usb_serial *serial); static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); static void visor_read_int_callback (struct urb *urb); @@ -916,7 +916,7 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign /* This function is all nice and good, but we don't change anything based on it :) */ -static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { unsigned int cflag; diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 154c7d290597..dc45e58e2b8c 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -145,7 +145,7 @@ static void whiteheat_close (struct usb_serial_port *port, struct file *filp); static int whiteheat_write (struct usb_serial_port *port, const unsigned char *buf, int count); static int whiteheat_write_room (struct usb_serial_port *port); static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old); +static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios * old); static int whiteheat_tiocmget (struct usb_serial_port *port, struct file *file); static int whiteheat_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static void whiteheat_break_ctl (struct usb_serial_port *port, int break_state); @@ -597,7 +597,7 @@ static void whiteheat_shutdown (struct usb_serial *serial) static int whiteheat_open (struct usb_serial_port *port, struct file *filp) { int retval = 0; - struct termios old_term; + struct ktermios old_term; dbg("%s - port %d", __FUNCTION__, port->number); @@ -870,7 +870,7 @@ static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, un } -static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { dbg("%s -port %d", __FUNCTION__, port->number); diff --git a/include/asm-generic/termios.h b/include/asm-generic/termios.h index 1e58ca39592c..3769e6bd63b1 100644 --- a/include/asm-generic/termios.h +++ b/include/asm-generic/termios.h @@ -11,7 +11,7 @@ /* * Translate a "termio" structure into a "termios". Ugh. */ -static inline int user_termio_to_kernel_termios(struct termios *termios, +static inline int user_termio_to_kernel_termios(struct ktermios *termios, struct termio __user *termio) { unsigned short tmp; @@ -48,7 +48,7 @@ static inline int user_termio_to_kernel_termios(struct termios *termios, * Translate a "termios" structure into a "termio". Ugh. */ static inline int kernel_termios_to_user_termio(struct termio __user *termio, - struct termios *termios) + struct ktermios *termios) { if (put_user(termios->c_iflag, &termio->c_iflag) < 0 || put_user(termios->c_oflag, &termio->c_oflag) < 0 || diff --git a/include/asm-powerpc/termbits.h b/include/asm-powerpc/termbits.h index b572f21b32c4..5e79198f7d18 100644 --- a/include/asm-powerpc/termbits.h +++ b/include/asm-powerpc/termbits.h @@ -37,8 +37,8 @@ struct ktermios { tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ cc_t c_cc[NCCS]; /* control characters */ + cc_t c_line; /* line discipline (== c_cc[19]) */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h index e25384561955..5412da28fa47 100644 --- a/include/linux/generic_serial.h +++ b/include/linux/generic_serial.h @@ -91,7 +91,7 @@ void gs_hangup(struct tty_struct *tty); int gs_block_til_ready(void *port, struct file *filp); void gs_close(struct tty_struct *tty, struct file *filp); void gs_set_termios (struct tty_struct * tty, - struct termios * old_termios); + struct ktermios * old_termios); int gs_init_port(struct gs_port *port); int gs_setserial(struct gs_port *port, struct serial_struct __user *sp); int gs_getserial(struct gs_port *port, struct serial_struct __user *sp); diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 62991148d5a5..3c7875b7ab5b 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -511,8 +511,8 @@ typedef struct modem_info { #endif struct tty_struct *tty; /* Pointer to corresponding tty */ atemu emu; /* AT-emulator data */ - struct termios normal_termios; /* For saving termios structs */ - struct termios callout_termios; + struct ktermios normal_termios; /* For saving termios structs */ + struct ktermios callout_termios; wait_queue_head_t open_wait, close_wait; struct semaphore write_sem; spinlock_t readlock; @@ -525,8 +525,8 @@ typedef struct _isdn_modem { int refcount; /* Number of opens */ struct tty_driver *tty_modem; /* tty-device */ struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */ - struct termios *modem_termios[ISDN_MAX_CHANNELS]; - struct termios *modem_termios_locked[ISDN_MAX_CHANNELS]; + struct ktermios *modem_termios[ISDN_MAX_CHANNELS]; + struct ktermios *modem_termios_locked[ISDN_MAX_CHANNELS]; modem_info info[ISDN_MAX_CHANNELS]; /* Private data */ } isdn_modem_t; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 827672136646..cf23813cbec2 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -166,8 +166,8 @@ struct uart_ops { void (*break_ctl)(struct uart_port *, int ctl); int (*startup)(struct uart_port *); void (*shutdown)(struct uart_port *); - void (*set_termios)(struct uart_port *, struct termios *new, - struct termios *old); + void (*set_termios)(struct uart_port *, struct ktermios *new, + struct ktermios *old); void (*pm)(struct uart_port *, unsigned int state, unsigned int oldstate); int (*set_wake)(struct uart_port *, unsigned int state); @@ -361,8 +361,8 @@ void uart_write_wakeup(struct uart_port *port); */ void uart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int baud); -unsigned int uart_get_baud_rate(struct uart_port *port, struct termios *termios, - struct termios *old, unsigned int min, +unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, + struct ktermios *old, unsigned int min, unsigned int max); unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud); diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 91b3ea2bbb14..10f99e5f1a97 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -218,7 +218,7 @@ struct usb_serial_driver { int (*write) (struct usb_serial_port *port, const unsigned char *buf, int count); int (*write_room) (struct usb_serial_port *port); int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); - void (*set_termios) (struct usb_serial_port *port, struct termios * old); + void (*set_termios) (struct usb_serial_port *port, struct ktermios * old); void (*break_ctl) (struct usb_serial_port *port, int break_state); int (*chars_in_buffer) (struct usb_serial_port *port); void (*throttle) (struct usb_serial_port *port); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 1fb5d42f37ae..e0e0d09023b2 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -752,9 +752,9 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned return -ENOIOCTLCMD; } -static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old) +static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { - struct termios *new = (struct termios *) tty->termios; + struct ktermios *new = tty->termios; int old_baud_rate = tty_termios_baud_rate(old); int new_baud_rate = tty_termios_baud_rate(new); -- cgit v1.2.3 From 6b2c9457bb377bf843f0a3ca2f4eb2ef69c67985 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 8 Dec 2006 02:39:15 -0800 Subject: [PATCH] Char: stallion, variables cleanup - fix `gcc -W' un/signed warnings by converting some ints -> uints. - move 3 global variables into functions, where are they used. Signed-off-by: Jiri Slaby Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/stallion.c | 67 ++++++++++++++++++++++-------------------------- include/linux/stallion.h | 28 ++++++++++---------- 2 files changed, 45 insertions(+), 50 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 2db2e9fbb5c6..97c7dc9c0cf0 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -63,7 +63,7 @@ #define BRD_EASYIOPCI 28 struct stlconf { - int brdtype; + unsigned int brdtype; int ioaddr1; int ioaddr2; unsigned long memaddr; @@ -120,15 +120,6 @@ static struct ktermios stl_deftermios = { .c_ospeed = 9600, }; -/* - * Define global stats structures. Not used often, and can be - * re-used for each stats call. - */ -static comstats_t stl_comstats; -static combrd_t stl_brdstats; -static struct stlbrd stl_dummybrd; -static struct stlport stl_dummyport; - /* * Define global place to put buffer overflow characters. */ @@ -200,7 +191,7 @@ static char *stl_brdnames[] = { * load line. These allow for easy board definitions, and easy * modification of the io, memory and irq resoucres. */ -static int stl_nargs = 0; +static unsigned int stl_nargs; static char *board0[4]; static char *board1[4]; static char *board2[4]; @@ -632,7 +623,7 @@ static struct class *stallion_class; static int __init stl_parsebrd(struct stlconf *confp, char **argp) { char *sp; - int i; + unsigned int i; pr_debug("stl_parsebrd(confp=%p,argp=%p)\n", confp, argp); @@ -694,8 +685,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp) { struct stlport *portp; struct stlbrd *brdp; - unsigned int minordev; - int brdnr, panelnr, portnr, rc; + unsigned int minordev, brdnr, panelnr; + int portnr, rc; pr_debug("stl_open(tty=%p,filp=%p): device=%s\n", tty, filp, tty->name); @@ -1556,8 +1547,8 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof struct stlbrd *brdp; struct stlpanel *panelp; struct stlport *portp; - int brdnr, panelnr, portnr, totalport; - int curoff, maxoff; + unsigned int brdnr, panelnr, portnr; + int totalport, curoff, maxoff; char *pos; pr_debug("stl_readproc(page=%p,start=%p,off=%lx,count=%d,eof=%p," @@ -1675,8 +1666,7 @@ static int stl_eiointr(struct stlbrd *brdp) static int stl_echatintr(struct stlbrd *brdp) { struct stlpanel *panelp; - unsigned int ioaddr; - int bnknr; + unsigned int ioaddr, bnknr; int handled = 0; outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); @@ -1706,8 +1696,7 @@ static int stl_echatintr(struct stlbrd *brdp) static int stl_echmcaintr(struct stlbrd *brdp) { struct stlpanel *panelp; - unsigned int ioaddr; - int bnknr; + unsigned int ioaddr, bnknr; int handled = 0; while (inb(brdp->iostatus) & ECH_INTRPEND) { @@ -1732,8 +1721,7 @@ static int stl_echmcaintr(struct stlbrd *brdp) static int stl_echpciintr(struct stlbrd *brdp) { struct stlpanel *panelp; - unsigned int ioaddr; - int bnknr, recheck; + unsigned int ioaddr, bnknr, recheck; int handled = 0; while (1) { @@ -1763,8 +1751,7 @@ static int stl_echpciintr(struct stlbrd *brdp) static int stl_echpci64intr(struct stlbrd *brdp) { struct stlpanel *panelp; - unsigned int ioaddr; - int bnknr; + unsigned int ioaddr, bnknr; int handled = 0; while (inb(brdp->ioctrl) & 0x1) { @@ -1826,8 +1813,9 @@ static void stl_offintr(struct work_struct *work) static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) { - struct stlport *portp; - int chipmask, i; + struct stlport *portp; + unsigned int i; + int chipmask; pr_debug("stl_initports(brdp=%p,panelp=%p)\n", brdp, panelp); @@ -2052,8 +2040,8 @@ err: static int __devinit stl_initech(struct stlbrd *brdp) { struct stlpanel *panelp; - unsigned int status, nxtid, ioaddr, conflict; - int panelnr, banknr, i, retval; + unsigned int status, nxtid, ioaddr, conflict, panelnr, banknr, i; + int retval; char *name; pr_debug("stl_initech(brdp=%p)\n", brdp); @@ -2337,7 +2325,7 @@ err: static int __devinit stl_getbrdnr(void) { - int i; + unsigned int i; for (i = 0; i < STL_MAXBRDS; i++) if (stl_brds[i] == NULL) { @@ -2361,7 +2349,7 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev, { struct stlbrd *brdp; unsigned int brdtype = ent->driver_data; - int retval = -ENODEV; + int brdnr, retval = -ENODEV; if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) goto err; @@ -2378,13 +2366,14 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev, goto err; } mutex_lock(&stl_brdslock); - brdp->brdnr = stl_getbrdnr(); - if (brdp->brdnr < 0) { + brdnr = stl_getbrdnr(); + if (brdnr < 0) { dev_err(&pdev->dev, "too many boards found, " "maximum supported %d\n", STL_MAXBRDS); mutex_unlock(&stl_brdslock); goto err_fr; } + brdp->brdnr = (unsigned int)brdnr; stl_brds[brdp->brdnr] = brdp; mutex_unlock(&stl_brdslock); @@ -2460,9 +2449,10 @@ static struct pci_driver stl_pcidriver = { static int stl_getbrdstats(combrd_t __user *bp) { + combrd_t stl_brdstats; struct stlbrd *brdp; struct stlpanel *panelp; - int i; + unsigned int i; if (copy_from_user(&stl_brdstats, bp, sizeof(combrd_t))) return -EFAULT; @@ -2508,12 +2498,12 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr) brdp = stl_brds[brdnr]; if (brdp == NULL) return NULL; - if (panelnr < 0 || panelnr >= brdp->nrpanels) + if (panelnr < 0 || (unsigned int)panelnr >= brdp->nrpanels) return NULL; panelp = brdp->panels[panelnr]; if (panelp == NULL) return NULL; - if (portnr < 0 || portnr >= panelp->nrports) + if (portnr < 0 || (unsigned int)portnr >= panelp->nrports) return NULL; return panelp->ports[portnr]; } @@ -2528,6 +2518,7 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr) static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) { + comstats_t stl_comstats; unsigned char *head, *tail; unsigned long flags; @@ -2585,6 +2576,8 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp) { + comstats_t stl_comstats; + if (!portp) { if (copy_from_user(&stl_comstats, cp, sizeof(comstats_t))) return -EFAULT; @@ -2610,6 +2603,7 @@ static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp) static int stl_getportstruct(struct stlport __user *arg) { + struct stlport stl_dummyport; struct stlport *portp; if (copy_from_user(&stl_dummyport, arg, sizeof(struct stlport))) @@ -2629,11 +2623,12 @@ static int stl_getportstruct(struct stlport __user *arg) static int stl_getbrdstruct(struct stlbrd __user *arg) { + struct stlbrd stl_dummybrd; struct stlbrd *brdp; if (copy_from_user(&stl_dummybrd, arg, sizeof(struct stlbrd))) return -EFAULT; - if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS)) + if (stl_dummybrd.brdnr >= STL_MAXBRDS) return -ENODEV; brdp = stl_brds[stl_dummybrd.brdnr]; if (!brdp) diff --git a/include/linux/stallion.h b/include/linux/stallion.h index ef5270b83d02..4a0a329beafb 100644 --- a/include/linux/stallion.h +++ b/include/linux/stallion.h @@ -69,12 +69,12 @@ struct stlrq { */ struct stlport { unsigned long magic; - int portnr; - int panelnr; - int brdnr; + unsigned int portnr; + unsigned int panelnr; + unsigned int brdnr; int ioaddr; int uartaddr; - int pagenr; + unsigned int pagenr; long istate; int flags; int baud_base; @@ -102,10 +102,10 @@ struct stlport { struct stlpanel { unsigned long magic; - int panelnr; - int brdnr; - int pagenr; - int nrports; + unsigned int panelnr; + unsigned int brdnr; + unsigned int pagenr; + unsigned int nrports; int iobase; void *uartp; void (*isr)(struct stlpanel *panelp, unsigned int iobase); @@ -116,12 +116,12 @@ struct stlpanel { struct stlbrd { unsigned long magic; - int brdnr; - int brdtype; - int state; - int nrpanels; - int nrports; - int nrbnks; + unsigned int brdnr; + unsigned int brdtype; + unsigned int state; + unsigned int nrpanels; + unsigned int nrports; + unsigned int nrbnks; int irq; int irqtype; int (*isr)(struct stlbrd *brdp); -- cgit v1.2.3 From 1f8ec435e3516eb831bb98110cc2b2b28057154b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 8 Dec 2006 02:39:18 -0800 Subject: [PATCH] Char: istallion, eliminate typedefs Use only struct instead of defining a new type . Signed-off-by: Jiri Slaby Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/istallion.c | 414 +++++++++++++++++++++++----------------------- include/linux/istallion.h | 12 +- 2 files changed, 212 insertions(+), 214 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 2f56bc7d147b..75b1e0cbf586 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -101,14 +101,14 @@ * interrupt is required. */ -typedef struct { +struct stlconf { int brdtype; int ioaddr1; int ioaddr2; unsigned long memaddr; int irq; int irqtype; -} stlconf_t; +}; static int stli_nrbrds; @@ -185,13 +185,13 @@ static struct ktermios stli_deftermios = { */ static comstats_t stli_comstats; static combrd_t stli_brdstats; -static asystats_t stli_cdkstats; -static stlibrd_t stli_dummybrd; -static stliport_t stli_dummyport; +static struct asystats stli_cdkstats; +static struct stlibrd stli_dummybrd; +static struct stliport stli_dummyport; /*****************************************************************************/ -static stlibrd_t *stli_brds[STL_MAXBRDS]; +static struct stlibrd *stli_brds[STL_MAXBRDS]; static int stli_shared; @@ -284,12 +284,10 @@ static char **stli_brdsp[] = { * parse any module arguments. */ -typedef struct stlibrdtype { +static struct stlibrdtype { char *name; int type; -} stlibrdtype_t; - -static stlibrdtype_t stli_brdstr[] = { +} stli_brdstr[] = { { "stallion", BRD_STALLION }, { "1", BRD_STALLION }, { "brumby", BRD_BRUMBY }, @@ -594,7 +592,7 @@ static struct pci_driver stli_pcidriver; * Prototype all functions in this driver! */ -static int stli_parsebrd(stlconf_t *confp, char **argp); +static int stli_parsebrd(struct stlconf *confp, char **argp); static int stli_init(void); static int stli_open(struct tty_struct *tty, struct file *filp); static void stli_close(struct tty_struct *tty, struct file *filp); @@ -614,82 +612,82 @@ static void stli_breakctl(struct tty_struct *tty, int state); static void stli_waituntilsent(struct tty_struct *tty, int timeout); static void stli_sendxchar(struct tty_struct *tty, char ch); static void stli_hangup(struct tty_struct *tty); -static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *pos); +static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos); -static int stli_brdinit(stlibrd_t *brdp); -static int stli_startbrd(stlibrd_t *brdp); +static int stli_brdinit(struct stlibrd *brdp); +static int stli_startbrd(struct stlibrd *brdp); static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp); static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp); static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); -static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp); +static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp); static void stli_poll(unsigned long arg); -static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp); -static int stli_initopen(stlibrd_t *brdp, stliport_t *portp); -static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); -static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); -static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp); +static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp); +static int stli_initopen(struct stlibrd *brdp, struct stliport *portp); +static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); +static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); +static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp); static void stli_dohangup(struct work_struct *); -static int stli_setport(stliport_t *portp); -static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); -static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); -static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); -static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp); -static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct ktermios *tiosp); +static int stli_setport(struct stliport *portp); +static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); +static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); +static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); +static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp); +static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp); static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts); static long stli_mktiocm(unsigned long sigvalue); -static void stli_read(stlibrd_t *brdp, stliport_t *portp); -static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp); -static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp); +static void stli_read(struct stlibrd *brdp, struct stliport *portp); +static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp); +static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp); static int stli_getbrdstats(combrd_t __user *bp); -static int stli_getportstats(stliport_t *portp, comstats_t __user *cp); -static int stli_portcmdstats(stliport_t *portp); -static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp); -static int stli_getportstruct(stliport_t __user *arg); -static int stli_getbrdstruct(stlibrd_t __user *arg); -static stlibrd_t *stli_allocbrd(void); - -static void stli_ecpinit(stlibrd_t *brdp); -static void stli_ecpenable(stlibrd_t *brdp); -static void stli_ecpdisable(stlibrd_t *brdp); -static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); -static void stli_ecpreset(stlibrd_t *brdp); -static void stli_ecpintr(stlibrd_t *brdp); -static void stli_ecpeiinit(stlibrd_t *brdp); -static void stli_ecpeienable(stlibrd_t *brdp); -static void stli_ecpeidisable(stlibrd_t *brdp); -static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line); -static void stli_ecpeireset(stlibrd_t *brdp); -static void stli_ecpmcenable(stlibrd_t *brdp); -static void stli_ecpmcdisable(stlibrd_t *brdp); -static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); -static void stli_ecpmcreset(stlibrd_t *brdp); -static void stli_ecppciinit(stlibrd_t *brdp); -static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line); -static void stli_ecppcireset(stlibrd_t *brdp); - -static void stli_onbinit(stlibrd_t *brdp); -static void stli_onbenable(stlibrd_t *brdp); -static void stli_onbdisable(stlibrd_t *brdp); -static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); -static void stli_onbreset(stlibrd_t *brdp); -static void stli_onbeinit(stlibrd_t *brdp); -static void stli_onbeenable(stlibrd_t *brdp); -static void stli_onbedisable(stlibrd_t *brdp); -static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line); -static void stli_onbereset(stlibrd_t *brdp); -static void stli_bbyinit(stlibrd_t *brdp); -static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line); -static void stli_bbyreset(stlibrd_t *brdp); -static void stli_stalinit(stlibrd_t *brdp); -static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); -static void stli_stalreset(stlibrd_t *brdp); - -static stliport_t *stli_getport(int brdnr, int panelnr, int portnr); - -static int stli_initecp(stlibrd_t *brdp); -static int stli_initonb(stlibrd_t *brdp); -static int stli_eisamemprobe(stlibrd_t *brdp); -static int stli_initports(stlibrd_t *brdp); +static int stli_getportstats(struct stliport *portp, comstats_t __user *cp); +static int stli_portcmdstats(struct stliport *portp); +static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp); +static int stli_getportstruct(struct stliport __user *arg); +static int stli_getbrdstruct(struct stlibrd __user *arg); +static struct stlibrd *stli_allocbrd(void); + +static void stli_ecpinit(struct stlibrd *brdp); +static void stli_ecpenable(struct stlibrd *brdp); +static void stli_ecpdisable(struct stlibrd *brdp); +static void __iomem *stli_ecpgetmemptr(struct stlibrd *brdp, unsigned long offset, int line); +static void stli_ecpreset(struct stlibrd *brdp); +static void stli_ecpintr(struct stlibrd *brdp); +static void stli_ecpeiinit(struct stlibrd *brdp); +static void stli_ecpeienable(struct stlibrd *brdp); +static void stli_ecpeidisable(struct stlibrd *brdp); +static void __iomem *stli_ecpeigetmemptr(struct stlibrd *brdp, unsigned long offset, int line); +static void stli_ecpeireset(struct stlibrd *brdp); +static void stli_ecpmcenable(struct stlibrd *brdp); +static void stli_ecpmcdisable(struct stlibrd *brdp); +static void __iomem *stli_ecpmcgetmemptr(struct stlibrd *brdp, unsigned long offset, int line); +static void stli_ecpmcreset(struct stlibrd *brdp); +static void stli_ecppciinit(struct stlibrd *brdp); +static void __iomem *stli_ecppcigetmemptr(struct stlibrd *brdp, unsigned long offset, int line); +static void stli_ecppcireset(struct stlibrd *brdp); + +static void stli_onbinit(struct stlibrd *brdp); +static void stli_onbenable(struct stlibrd *brdp); +static void stli_onbdisable(struct stlibrd *brdp); +static void __iomem *stli_onbgetmemptr(struct stlibrd *brdp, unsigned long offset, int line); +static void stli_onbreset(struct stlibrd *brdp); +static void stli_onbeinit(struct stlibrd *brdp); +static void stli_onbeenable(struct stlibrd *brdp); +static void stli_onbedisable(struct stlibrd *brdp); +static void __iomem *stli_onbegetmemptr(struct stlibrd *brdp, unsigned long offset, int line); +static void stli_onbereset(struct stlibrd *brdp); +static void stli_bbyinit(struct stlibrd *brdp); +static void __iomem *stli_bbygetmemptr(struct stlibrd *brdp, unsigned long offset, int line); +static void stli_bbyreset(struct stlibrd *brdp); +static void stli_stalinit(struct stlibrd *brdp); +static void __iomem *stli_stalgetmemptr(struct stlibrd *brdp, unsigned long offset, int line); +static void stli_stalreset(struct stlibrd *brdp); + +static struct stliport *stli_getport(int brdnr, int panelnr, int portnr); + +static int stli_initecp(struct stlibrd *brdp); +static int stli_initonb(struct stlibrd *brdp); +static int stli_eisamemprobe(struct stlibrd *brdp); +static int stli_initports(struct stlibrd *brdp); /*****************************************************************************/ @@ -727,9 +725,9 @@ static int stli_timeron; static struct class *istallion_class; -static void stli_cleanup_ports(stlibrd_t *brdp) +static void stli_cleanup_ports(struct stlibrd *brdp) { - stliport_t *portp; + struct stliport *portp; unsigned int j; for (j = 0; j < STL_MAXPORTS; j++) { @@ -756,7 +754,7 @@ static int __init istallion_module_init(void) static void __exit istallion_module_exit(void) { - stlibrd_t *brdp; + struct stlibrd *brdp; int i; printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle, @@ -811,7 +809,7 @@ module_exit(istallion_module_exit); * Parse the supplied argument string, into the board conf struct. */ -static int stli_parsebrd(stlconf_t *confp, char **argp) +static int stli_parsebrd(struct stlconf *confp, char **argp) { char *sp; int i; @@ -843,8 +841,8 @@ static int stli_parsebrd(stlconf_t *confp, char **argp) static int stli_open(struct tty_struct *tty, struct file *filp) { - stlibrd_t *brdp; - stliport_t *portp; + struct stlibrd *brdp; + struct stliport *portp; unsigned int minordev; int brdnr, portnr, rc; @@ -938,8 +936,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp) static void stli_close(struct tty_struct *tty, struct file *filp) { - stlibrd_t *brdp; - stliport_t *portp; + struct stlibrd *brdp; + struct stliport *portp; unsigned long flags; portp = tty->driver_data; @@ -1016,7 +1014,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp) * this still all happens pretty quickly. */ -static int stli_initopen(stlibrd_t *brdp, stliport_t *portp) +static int stli_initopen(struct stlibrd *brdp, struct stliport *portp) { struct tty_struct *tty; asynotify_t nt; @@ -1064,7 +1062,7 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp) * to overlap. */ -static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait) +static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait) { cdkhdr_t __iomem *hdrp; cdkctrl_t __iomem *cp; @@ -1135,7 +1133,7 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i * wait is true then must have user context (to sleep). */ -static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait) +static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait) { cdkhdr_t __iomem *hdrp; cdkctrl_t __iomem *cp; @@ -1199,7 +1197,7 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, * to complete (as opposed to initiating the command then returning). */ -static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback) +static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback) { wait_event_interruptible(portp->raw_wait, !test_bit(ST_CMDING, &portp->state)); @@ -1225,9 +1223,9 @@ static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, v * waiting for the command to complete - so must have user context. */ -static int stli_setport(stliport_t *portp) +static int stli_setport(struct stliport *portp) { - stlibrd_t *brdp; + struct stlibrd *brdp; asyport_t aport; if (portp == NULL) @@ -1251,7 +1249,7 @@ static int stli_setport(stliport_t *portp) * maybe because if we are clocal then we don't need to wait... */ -static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp) +static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp) { unsigned long flags; int rc, doclocal; @@ -1316,8 +1314,8 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun unsigned char __iomem *bits; unsigned char __iomem *shbuf; unsigned char *chbuf; - stliport_t *portp; - stlibrd_t *brdp; + struct stliport *portp; + struct stlibrd *brdp; unsigned int len, stlen, head, tail, size; unsigned long flags; @@ -1423,8 +1421,8 @@ static void stli_flushchars(struct tty_struct *tty) unsigned char __iomem *bits; cdkasy_t __iomem *ap; struct tty_struct *cooktty; - stliport_t *portp; - stlibrd_t *brdp; + struct stliport *portp; + struct stlibrd *brdp; unsigned int len, stlen, head, tail, size, count, cooksize; unsigned char *buf; unsigned char __iomem *shbuf; @@ -1511,8 +1509,8 @@ static void stli_flushchars(struct tty_struct *tty) static int stli_writeroom(struct tty_struct *tty) { cdkasyrq_t __iomem *rp; - stliport_t *portp; - stlibrd_t *brdp; + struct stliport *portp; + struct stlibrd *brdp; unsigned int head, tail, len; unsigned long flags; @@ -1564,8 +1562,8 @@ static int stli_writeroom(struct tty_struct *tty) static int stli_charsinbuffer(struct tty_struct *tty) { cdkasyrq_t __iomem *rp; - stliport_t *portp; - stlibrd_t *brdp; + struct stliport *portp; + struct stlibrd *brdp; unsigned int head, tail, len; unsigned long flags; @@ -1602,10 +1600,10 @@ static int stli_charsinbuffer(struct tty_struct *tty) * Generate the serial struct info. */ -static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp) +static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp) { struct serial_struct sio; - stlibrd_t *brdp; + struct stlibrd *brdp; memset(&sio, 0, sizeof(struct serial_struct)); sio.type = PORT_UNKNOWN; @@ -1635,7 +1633,7 @@ static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp) * just quietly ignore any requests to change irq, etc. */ -static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp) +static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp) { struct serial_struct sio; int rc; @@ -1666,8 +1664,8 @@ static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp) static int stli_tiocmget(struct tty_struct *tty, struct file *file) { - stliport_t *portp = tty->driver_data; - stlibrd_t *brdp; + struct stliport *portp = tty->driver_data; + struct stlibrd *brdp; int rc; if (portp == NULL) @@ -1690,8 +1688,8 @@ static int stli_tiocmget(struct tty_struct *tty, struct file *file) static int stli_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - stliport_t *portp = tty->driver_data; - stlibrd_t *brdp; + struct stliport *portp = tty->driver_data; + struct stlibrd *brdp; int rts = -1, dtr = -1; if (portp == NULL) @@ -1721,8 +1719,8 @@ static int stli_tiocmset(struct tty_struct *tty, struct file *file, static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - stliport_t *portp; - stlibrd_t *brdp; + struct stliport *portp; + struct stlibrd *brdp; unsigned int ival; int rc; void __user *argp = (void __user *)arg; @@ -1798,8 +1796,8 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm static void stli_settermios(struct tty_struct *tty, struct ktermios *old) { - stliport_t *portp; - stlibrd_t *brdp; + struct stliport *portp; + struct stlibrd *brdp; struct ktermios *tiosp; asyport_t aport; @@ -1844,7 +1842,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) static void stli_throttle(struct tty_struct *tty) { - stliport_t *portp = tty->driver_data; + struct stliport *portp = tty->driver_data; if (portp == NULL) return; set_bit(ST_RXSTOP, &portp->state); @@ -1860,7 +1858,7 @@ static void stli_throttle(struct tty_struct *tty) static void stli_unthrottle(struct tty_struct *tty) { - stliport_t *portp = tty->driver_data; + struct stliport *portp = tty->driver_data; if (portp == NULL) return; clear_bit(ST_RXSTOP, &portp->state); @@ -1899,7 +1897,7 @@ static void stli_start(struct tty_struct *tty) static void stli_dohangup(struct work_struct *ugly_api) { - stliport_t *portp = container_of(ugly_api, stliport_t, tqhangup); + struct stliport *portp = container_of(ugly_api, struct stliport, tqhangup); if (portp->tty != NULL) { tty_hangup(portp->tty); } @@ -1916,8 +1914,8 @@ static void stli_dohangup(struct work_struct *ugly_api) static void stli_hangup(struct tty_struct *tty) { - stliport_t *portp; - stlibrd_t *brdp; + struct stliport *portp; + struct stlibrd *brdp; unsigned long flags; portp = tty->driver_data; @@ -1969,8 +1967,8 @@ static void stli_hangup(struct tty_struct *tty) static void stli_flushbuffer(struct tty_struct *tty) { - stliport_t *portp; - stlibrd_t *brdp; + struct stliport *portp; + struct stlibrd *brdp; unsigned long ftype, flags; portp = tty->driver_data; @@ -2006,8 +2004,8 @@ static void stli_flushbuffer(struct tty_struct *tty) static void stli_breakctl(struct tty_struct *tty, int state) { - stlibrd_t *brdp; - stliport_t *portp; + struct stlibrd *brdp; + struct stliport *portp; long arg; portp = tty->driver_data; @@ -2027,7 +2025,7 @@ static void stli_breakctl(struct tty_struct *tty, int state) static void stli_waituntilsent(struct tty_struct *tty, int timeout) { - stliport_t *portp; + struct stliport *portp; unsigned long tend; if (tty == NULL) @@ -2053,8 +2051,8 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout) static void stli_sendxchar(struct tty_struct *tty, char ch) { - stlibrd_t *brdp; - stliport_t *portp; + struct stlibrd *brdp; + struct stliport *portp; asyctrl_t actrl; portp = tty->driver_data; @@ -2088,7 +2086,7 @@ static void stli_sendxchar(struct tty_struct *tty, char ch) * short then padded with spaces). */ -static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *pos) +static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos) { char *sp, *uart; int rc, cnt; @@ -2151,8 +2149,8 @@ static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *p static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data) { - stlibrd_t *brdp; - stliport_t *portp; + struct stlibrd *brdp; + struct stliport *portp; int brdnr, portnr, totalport; int curoff, maxoff; char *pos; @@ -2223,7 +2221,7 @@ stli_readdone: * entry point) */ -static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback) +static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback) { cdkhdr_t __iomem *hdrp; cdkctrl_t __iomem *cp; @@ -2259,7 +2257,7 @@ static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd spin_unlock_irqrestore(&brd_lock, flags); } -static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback) +static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback) { unsigned long flags; @@ -2278,7 +2276,7 @@ static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, * more chars to unload. */ -static void stli_read(stlibrd_t *brdp, stliport_t *portp) +static void stli_read(struct stlibrd *brdp, struct stliport *portp) { cdkasyrq_t __iomem *rp; char __iomem *shbuf; @@ -2340,7 +2338,7 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp) * difficult to deal with them here. */ -static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp) +static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp) { int cmd; @@ -2388,7 +2386,7 @@ static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp) * then port is still busy, otherwise no longer busy. */ -static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp) +static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) { cdkasy_t __iomem *ap; cdkctrl_t __iomem *cp; @@ -2535,9 +2533,9 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp) * at the cdk header structure. */ -static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp) +static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp) { - stliport_t *portp; + struct stliport *portp; unsigned char hostbits[(STL_MAXCHANS / 8) + 1]; unsigned char slavebits[(STL_MAXCHANS / 8) + 1]; unsigned char __iomem *slavep; @@ -2604,7 +2602,7 @@ static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp) static void stli_poll(unsigned long arg) { cdkhdr_t __iomem *hdrp; - stlibrd_t *brdp; + struct stlibrd *brdp; int brdnr; stli_timerlist.expires = STLI_TIMEOUT; @@ -2637,7 +2635,7 @@ static void stli_poll(unsigned long arg) * the slave. */ -static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct ktermios *tiosp) +static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp) { memset(pp, 0, sizeof(asyport_t)); @@ -2786,13 +2784,13 @@ static long stli_mktiocm(unsigned long sigvalue) * we need to do here is set up the appropriate per port data structures. */ -static int stli_initports(stlibrd_t *brdp) +static int stli_initports(struct stlibrd *brdp) { - stliport_t *portp; + struct stliport *portp; int i, panelnr, panelport; for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) { - portp = kzalloc(sizeof(stliport_t), GFP_KERNEL); + portp = kzalloc(sizeof(struct stliport), GFP_KERNEL); if (!portp) { printk("STALLION: failed to allocate port structure\n"); continue; @@ -2826,7 +2824,7 @@ static int stli_initports(stlibrd_t *brdp) * All the following routines are board specific hardware operations. */ -static void stli_ecpinit(stlibrd_t *brdp) +static void stli_ecpinit(struct stlibrd *brdp) { unsigned long memconf; @@ -2841,21 +2839,21 @@ static void stli_ecpinit(stlibrd_t *brdp) /*****************************************************************************/ -static void stli_ecpenable(stlibrd_t *brdp) +static void stli_ecpenable(struct stlibrd *brdp) { outb(ECP_ATENABLE, (brdp->iobase + ECP_ATCONFR)); } /*****************************************************************************/ -static void stli_ecpdisable(stlibrd_t *brdp) +static void stli_ecpdisable(struct stlibrd *brdp) { outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR)); } /*****************************************************************************/ -static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_ecpgetmemptr(struct stlibrd *brdp, unsigned long offset, int line) { void __iomem *ptr; unsigned char val; @@ -2876,7 +2874,7 @@ static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, in /*****************************************************************************/ -static void stli_ecpreset(stlibrd_t *brdp) +static void stli_ecpreset(struct stlibrd *brdp) { outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR)); udelay(10); @@ -2886,7 +2884,7 @@ static void stli_ecpreset(stlibrd_t *brdp) /*****************************************************************************/ -static void stli_ecpintr(stlibrd_t *brdp) +static void stli_ecpintr(struct stlibrd *brdp) { outb(0x1, brdp->iobase); } @@ -2897,7 +2895,7 @@ static void stli_ecpintr(stlibrd_t *brdp) * The following set of functions act on ECP EISA boards. */ -static void stli_ecpeiinit(stlibrd_t *brdp) +static void stli_ecpeiinit(struct stlibrd *brdp) { unsigned long memconf; @@ -2915,21 +2913,21 @@ static void stli_ecpeiinit(stlibrd_t *brdp) /*****************************************************************************/ -static void stli_ecpeienable(stlibrd_t *brdp) +static void stli_ecpeienable(struct stlibrd *brdp) { outb(ECP_EIENABLE, (brdp->iobase + ECP_EICONFR)); } /*****************************************************************************/ -static void stli_ecpeidisable(stlibrd_t *brdp) +static void stli_ecpeidisable(struct stlibrd *brdp) { outb(ECP_EIDISABLE, (brdp->iobase + ECP_EICONFR)); } /*****************************************************************************/ -static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_ecpeigetmemptr(struct stlibrd *brdp, unsigned long offset, int line) { void __iomem *ptr; unsigned char val; @@ -2953,7 +2951,7 @@ static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, /*****************************************************************************/ -static void stli_ecpeireset(stlibrd_t *brdp) +static void stli_ecpeireset(struct stlibrd *brdp) { outb(ECP_EISTOP, (brdp->iobase + ECP_EICONFR)); udelay(10); @@ -2967,21 +2965,21 @@ static void stli_ecpeireset(stlibrd_t *brdp) * The following set of functions act on ECP MCA boards. */ -static void stli_ecpmcenable(stlibrd_t *brdp) +static void stli_ecpmcenable(struct stlibrd *brdp) { outb(ECP_MCENABLE, (brdp->iobase + ECP_MCCONFR)); } /*****************************************************************************/ -static void stli_ecpmcdisable(stlibrd_t *brdp) +static void stli_ecpmcdisable(struct stlibrd *brdp) { outb(ECP_MCDISABLE, (brdp->iobase + ECP_MCCONFR)); } /*****************************************************************************/ -static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_ecpmcgetmemptr(struct stlibrd *brdp, unsigned long offset, int line) { void __iomem *ptr; unsigned char val; @@ -3002,7 +3000,7 @@ static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, /*****************************************************************************/ -static void stli_ecpmcreset(stlibrd_t *brdp) +static void stli_ecpmcreset(struct stlibrd *brdp) { outb(ECP_MCSTOP, (brdp->iobase + ECP_MCCONFR)); udelay(10); @@ -3016,7 +3014,7 @@ static void stli_ecpmcreset(stlibrd_t *brdp) * The following set of functions act on ECP PCI boards. */ -static void stli_ecppciinit(stlibrd_t *brdp) +static void stli_ecppciinit(struct stlibrd *brdp) { outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR)); udelay(10); @@ -3026,7 +3024,7 @@ static void stli_ecppciinit(stlibrd_t *brdp) /*****************************************************************************/ -static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_ecppcigetmemptr(struct stlibrd *brdp, unsigned long offset, int line) { void __iomem *ptr; unsigned char val; @@ -3047,7 +3045,7 @@ static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, /*****************************************************************************/ -static void stli_ecppcireset(stlibrd_t *brdp) +static void stli_ecppcireset(struct stlibrd *brdp) { outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR)); udelay(10); @@ -3061,7 +3059,7 @@ static void stli_ecppcireset(stlibrd_t *brdp) * The following routines act on ONboards. */ -static void stli_onbinit(stlibrd_t *brdp) +static void stli_onbinit(struct stlibrd *brdp) { unsigned long memconf; @@ -3078,21 +3076,21 @@ static void stli_onbinit(stlibrd_t *brdp) /*****************************************************************************/ -static void stli_onbenable(stlibrd_t *brdp) +static void stli_onbenable(struct stlibrd *brdp) { outb((brdp->enabval | ONB_ATENABLE), (brdp->iobase + ONB_ATCONFR)); } /*****************************************************************************/ -static void stli_onbdisable(stlibrd_t *brdp) +static void stli_onbdisable(struct stlibrd *brdp) { outb((brdp->enabval | ONB_ATDISABLE), (brdp->iobase + ONB_ATCONFR)); } /*****************************************************************************/ -static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_onbgetmemptr(struct stlibrd *brdp, unsigned long offset, int line) { void __iomem *ptr; @@ -3109,7 +3107,7 @@ static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, in /*****************************************************************************/ -static void stli_onbreset(stlibrd_t *brdp) +static void stli_onbreset(struct stlibrd *brdp) { outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR)); udelay(10); @@ -3123,7 +3121,7 @@ static void stli_onbreset(stlibrd_t *brdp) * The following routines act on ONboard EISA. */ -static void stli_onbeinit(stlibrd_t *brdp) +static void stli_onbeinit(struct stlibrd *brdp) { unsigned long memconf; @@ -3143,21 +3141,21 @@ static void stli_onbeinit(stlibrd_t *brdp) /*****************************************************************************/ -static void stli_onbeenable(stlibrd_t *brdp) +static void stli_onbeenable(struct stlibrd *brdp) { outb(ONB_EIENABLE, (brdp->iobase + ONB_EICONFR)); } /*****************************************************************************/ -static void stli_onbedisable(stlibrd_t *brdp) +static void stli_onbedisable(struct stlibrd *brdp) { outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR)); } /*****************************************************************************/ -static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_onbegetmemptr(struct stlibrd *brdp, unsigned long offset, int line) { void __iomem *ptr; unsigned char val; @@ -3181,7 +3179,7 @@ static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, i /*****************************************************************************/ -static void stli_onbereset(stlibrd_t *brdp) +static void stli_onbereset(struct stlibrd *brdp) { outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR)); udelay(10); @@ -3195,7 +3193,7 @@ static void stli_onbereset(stlibrd_t *brdp) * The following routines act on Brumby boards. */ -static void stli_bbyinit(stlibrd_t *brdp) +static void stli_bbyinit(struct stlibrd *brdp) { outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR)); udelay(10); @@ -3207,7 +3205,7 @@ static void stli_bbyinit(stlibrd_t *brdp) /*****************************************************************************/ -static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_bbygetmemptr(struct stlibrd *brdp, unsigned long offset, int line) { void __iomem *ptr; unsigned char val; @@ -3222,7 +3220,7 @@ static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, in /*****************************************************************************/ -static void stli_bbyreset(stlibrd_t *brdp) +static void stli_bbyreset(struct stlibrd *brdp) { outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR)); udelay(10); @@ -3236,7 +3234,7 @@ static void stli_bbyreset(stlibrd_t *brdp) * The following routines act on original old Stallion boards. */ -static void stli_stalinit(stlibrd_t *brdp) +static void stli_stalinit(struct stlibrd *brdp) { outb(0x1, brdp->iobase); mdelay(1000); @@ -3244,7 +3242,7 @@ static void stli_stalinit(stlibrd_t *brdp) /*****************************************************************************/ -static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +static void __iomem *stli_stalgetmemptr(struct stlibrd *brdp, unsigned long offset, int line) { BUG_ON(offset > brdp->memsize); return brdp->membase + (offset % STAL_PAGESIZE); @@ -3252,7 +3250,7 @@ static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, i /*****************************************************************************/ -static void stli_stalreset(stlibrd_t *brdp) +static void stli_stalreset(struct stlibrd *brdp) { u32 __iomem *vecp; @@ -3269,7 +3267,7 @@ static void stli_stalreset(stlibrd_t *brdp) * board types. */ -static int stli_initecp(stlibrd_t *brdp) +static int stli_initecp(struct stlibrd *brdp) { cdkecpsig_t sig; cdkecpsig_t __iomem *sigsp; @@ -3415,7 +3413,7 @@ static int stli_initecp(stlibrd_t *brdp) * This handles only these board types. */ -static int stli_initonb(stlibrd_t *brdp) +static int stli_initonb(struct stlibrd *brdp) { cdkonbsig_t sig; cdkonbsig_t __iomem *sigsp; @@ -3566,13 +3564,13 @@ static int stli_initonb(stlibrd_t *brdp) * read in the memory map, and get the show on the road... */ -static int stli_startbrd(stlibrd_t *brdp) +static int stli_startbrd(struct stlibrd *brdp) { cdkhdr_t __iomem *hdrp; cdkmem_t __iomem *memp; cdkasy_t __iomem *ap; unsigned long flags; - stliport_t *portp; + struct stliport *portp; int portnr, nrdevs, i, rc = 0; u32 memoff; @@ -3673,7 +3671,7 @@ stli_donestartup: * Probe and initialize the specified board. */ -static int __devinit stli_brdinit(stlibrd_t *brdp) +static int __devinit stli_brdinit(struct stlibrd *brdp) { stli_brds[brdp->brdnr] = brdp; @@ -3720,7 +3718,7 @@ static int __devinit stli_brdinit(stlibrd_t *brdp) * might be. This is a bit if hack, but it is the best we can do. */ -static int stli_eisamemprobe(stlibrd_t *brdp) +static int stli_eisamemprobe(struct stlibrd *brdp) { cdkecpsig_t ecpsig, __iomem *ecpsigp; cdkonbsig_t onbsig, __iomem *onbsigp; @@ -3835,7 +3833,7 @@ static int stli_getbrdnr(void) static int stli_findeisabrds(void) { - stlibrd_t *brdp; + struct stlibrd *brdp; unsigned int iobase, eid; int i; @@ -3912,7 +3910,7 @@ static int stli_findeisabrds(void) static int __devinit stli_pciprobe(struct pci_dev *pdev, const struct pci_device_id *ent) { - stlibrd_t *brdp; + struct stlibrd *brdp; int retval = -EIO; retval = pci_enable_device(pdev); @@ -3951,7 +3949,7 @@ err: static void stli_pciremove(struct pci_dev *pdev) { - stlibrd_t *brdp = pci_get_drvdata(pdev); + struct stlibrd *brdp = pci_get_drvdata(pdev); stli_cleanup_ports(brdp); @@ -3975,14 +3973,14 @@ static struct pci_driver stli_pcidriver = { * Allocate a new board structure. Fill out the basic info in it. */ -static stlibrd_t *stli_allocbrd(void) +static struct stlibrd *stli_allocbrd(void) { - stlibrd_t *brdp; + struct stlibrd *brdp; - brdp = kzalloc(sizeof(stlibrd_t), GFP_KERNEL); + brdp = kzalloc(sizeof(struct stlibrd), GFP_KERNEL); if (!brdp) { printk(KERN_ERR "STALLION: failed to allocate memory " - "(size=%Zd)\n", sizeof(stlibrd_t)); + "(size=%Zd)\n", sizeof(struct stlibrd)); return NULL; } brdp->magic = STLI_BOARDMAGIC; @@ -3998,8 +3996,8 @@ static stlibrd_t *stli_allocbrd(void) static int stli_initbrds(void) { - stlibrd_t *brdp, *nxtbrdp; - stlconf_t conf; + struct stlibrd *brdp, *nxtbrdp; + struct stlconf conf; int i, j, retval; for (stli_nrbrds = 0; stli_nrbrds < ARRAY_SIZE(stli_brdsp); @@ -4075,7 +4073,7 @@ static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, lof { unsigned long flags; void __iomem *memptr; - stlibrd_t *brdp; + struct stlibrd *brdp; int brdnr, size, n; void *p; loff_t off = *offp; @@ -4138,7 +4136,7 @@ static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t cou { unsigned long flags; void __iomem *memptr; - stlibrd_t *brdp; + struct stlibrd *brdp; char __user *chbuf; int brdnr, size, n; void *p; @@ -4199,7 +4197,7 @@ out: static int stli_getbrdstats(combrd_t __user *bp) { - stlibrd_t *brdp; + struct stlibrd *brdp; int i; if (copy_from_user(&stli_brdstats, bp, sizeof(combrd_t))) @@ -4236,9 +4234,9 @@ static int stli_getbrdstats(combrd_t __user *bp) * Resolve the referenced port number into a port struct pointer. */ -static stliport_t *stli_getport(int brdnr, int panelnr, int portnr) +static struct stliport *stli_getport(int brdnr, int panelnr, int portnr) { - stlibrd_t *brdp; + struct stlibrd *brdp; int i; if (brdnr < 0 || brdnr >= STL_MAXBRDS) @@ -4261,10 +4259,10 @@ static stliport_t *stli_getport(int brdnr, int panelnr, int portnr) * what port to get stats for (used through board control device). */ -static int stli_portcmdstats(stliport_t *portp) +static int stli_portcmdstats(struct stliport *portp) { unsigned long flags; - stlibrd_t *brdp; + struct stlibrd *brdp; int rc; memset(&stli_comstats, 0, sizeof(comstats_t)); @@ -4335,9 +4333,9 @@ static int stli_portcmdstats(stliport_t *portp) * what port to get stats for (used through board control device). */ -static int stli_getportstats(stliport_t *portp, comstats_t __user *cp) +static int stli_getportstats(struct stliport *portp, comstats_t __user *cp) { - stlibrd_t *brdp; + struct stlibrd *brdp; int rc; if (!portp) { @@ -4366,9 +4364,9 @@ static int stli_getportstats(stliport_t *portp, comstats_t __user *cp) * Clear the port stats structure. We also return it zeroed out... */ -static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp) +static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp) { - stlibrd_t *brdp; + struct stlibrd *brdp; int rc; if (!portp) { @@ -4405,17 +4403,17 @@ static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp) * Return the entire driver ports structure to a user app. */ -static int stli_getportstruct(stliport_t __user *arg) +static int stli_getportstruct(struct stliport __user *arg) { - stliport_t *portp; + struct stliport *portp; - if (copy_from_user(&stli_dummyport, arg, sizeof(stliport_t))) + if (copy_from_user(&stli_dummyport, arg, sizeof(struct stliport))) return -EFAULT; portp = stli_getport(stli_dummyport.brdnr, stli_dummyport.panelnr, stli_dummyport.portnr); if (!portp) return -ENODEV; - if (copy_to_user(arg, portp, sizeof(stliport_t))) + if (copy_to_user(arg, portp, sizeof(struct stliport))) return -EFAULT; return 0; } @@ -4426,18 +4424,18 @@ static int stli_getportstruct(stliport_t __user *arg) * Return the entire driver board structure to a user app. */ -static int stli_getbrdstruct(stlibrd_t __user *arg) +static int stli_getbrdstruct(struct stlibrd __user *arg) { - stlibrd_t *brdp; + struct stlibrd *brdp; - if (copy_from_user(&stli_dummybrd, arg, sizeof(stlibrd_t))) + if (copy_from_user(&stli_dummybrd, arg, sizeof(struct stlibrd))) return -EFAULT; if ((stli_dummybrd.brdnr < 0) || (stli_dummybrd.brdnr >= STL_MAXBRDS)) return -ENODEV; brdp = stli_brds[stli_dummybrd.brdnr]; if (!brdp) return -ENODEV; - if (copy_to_user(arg, brdp, sizeof(stlibrd_t))) + if (copy_to_user(arg, brdp, sizeof(struct stlibrd))) return -EFAULT; return 0; } @@ -4452,7 +4450,7 @@ static int stli_getbrdstruct(stlibrd_t __user *arg) static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { - stlibrd_t *brdp; + struct stlibrd *brdp; int brdnr, rc, done; void __user *argp = (void __user *)arg; diff --git a/include/linux/istallion.h b/include/linux/istallion.h index b55e2a035605..af2c32d16d45 100644 --- a/include/linux/istallion.h +++ b/include/linux/istallion.h @@ -49,7 +49,7 @@ * communication with the slave board will always be on a per port * basis. */ -typedef struct { +struct stliport { unsigned long magic; int portnr; int panelnr; @@ -72,7 +72,7 @@ typedef struct { wait_queue_head_t close_wait; wait_queue_head_t raw_wait; struct work_struct tqhangup; - asysigs_t asig; + struct asysigs asig; unsigned long addr; unsigned long rxoffset; unsigned long txoffset; @@ -83,13 +83,13 @@ typedef struct { unsigned char reqbit; unsigned char portidx; unsigned char portbit; -} stliport_t; +}; /* * Use a structure of function pointers to do board level operations. * These include, enable/disable, paging shared memory, interrupting, etc. */ -typedef struct stlibrd { +struct stlibrd { unsigned long magic; int brdnr; int brdtype; @@ -116,8 +116,8 @@ typedef struct stlibrd { void __iomem *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line); void (*intr)(struct stlibrd *brdp); void (*reset)(struct stlibrd *brdp); - stliport_t *ports[STL_MAXPORTS]; -} stlibrd_t; + struct stliport *ports[STL_MAXPORTS]; +}; /* -- cgit v1.2.3 From 1328d737f510e9933a621f66aa8de81c02b647a7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 8 Dec 2006 02:39:19 -0800 Subject: [PATCH] Char: istallion, variables cleanup - wipe gcc -W warnings by int -> uint conversion - move 2 global variables into their local place Signed-off-by: Jiri Slaby Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/istallion.c | 100 +++++++++++++++++++++++++--------------------- include/linux/istallion.h | 24 +++++------ 2 files changed, 67 insertions(+), 57 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 75b1e0cbf586..28e9230e887a 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -110,7 +110,7 @@ struct stlconf { int irqtype; }; -static int stli_nrbrds; +static unsigned int stli_nrbrds; /* stli_lock must NOT be taken holding brd_lock */ static spinlock_t stli_lock; /* TTY logic lock */ @@ -186,8 +186,6 @@ static struct ktermios stli_deftermios = { static comstats_t stli_comstats; static combrd_t stli_brdstats; static struct asystats stli_cdkstats; -static struct stlibrd stli_dummybrd; -static struct stliport stli_dummyport; /*****************************************************************************/ @@ -682,7 +680,7 @@ static void stli_stalinit(struct stlibrd *brdp); static void __iomem *stli_stalgetmemptr(struct stlibrd *brdp, unsigned long offset, int line); static void stli_stalreset(struct stlibrd *brdp); -static struct stliport *stli_getport(int brdnr, int panelnr, int portnr); +static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr, unsigned int portnr); static int stli_initecp(struct stlibrd *brdp); static int stli_initonb(struct stlibrd *brdp); @@ -755,6 +753,7 @@ static int __init istallion_module_init(void) static void __exit istallion_module_exit(void) { struct stlibrd *brdp; + unsigned int j; int i; printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle, @@ -777,8 +776,8 @@ static void __exit istallion_module_exit(void) return; } put_tty_driver(stli_serial); - for (i = 0; i < 4; i++) - class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i)); + for (j = 0; j < 4; j++) + class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j)); class_destroy(istallion_class); if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) printk("STALLION: failed to un-register serial memory device, " @@ -786,8 +785,8 @@ static void __exit istallion_module_exit(void) kfree(stli_txcookbuf); - for (i = 0; (i < stli_nrbrds); i++) { - if ((brdp = stli_brds[i]) == NULL) + for (j = 0; (j < stli_nrbrds); j++) { + if ((brdp = stli_brds[j]) == NULL) continue; stli_cleanup_ports(brdp); @@ -796,7 +795,7 @@ static void __exit istallion_module_exit(void) if (brdp->iosize > 0) release_region(brdp->iobase, brdp->iosize); kfree(brdp); - stli_brds[i] = NULL; + stli_brds[j] = NULL; } } @@ -811,8 +810,8 @@ module_exit(istallion_module_exit); static int stli_parsebrd(struct stlconf *confp, char **argp) { + unsigned int i; char *sp; - int i; if (argp[0] == NULL || *argp[0] == 0) return 0; @@ -843,8 +842,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp) { struct stlibrd *brdp; struct stliport *portp; - unsigned int minordev; - int brdnr, portnr, rc; + unsigned int minordev, brdnr, portnr; + int rc; minordev = tty->index; brdnr = MINOR2BRD(minordev); @@ -856,7 +855,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) if ((brdp->state & BST_STARTED) == 0) return -ENODEV; portnr = MINOR2PORT(minordev); - if ((portnr < 0) || (portnr > brdp->nrports)) + if (portnr > brdp->nrports) return -ENODEV; portp = brdp->ports[portnr]; @@ -1232,7 +1231,7 @@ static int stli_setport(struct stliport *portp) return -ENODEV; if (portp->tty == NULL) return -ENODEV; - if (portp->brdnr < 0 && portp->brdnr >= stli_nrbrds) + if (portp->brdnr >= stli_nrbrds) return -ENODEV; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -1324,7 +1323,7 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun portp = tty->driver_data; if (portp == NULL) return 0; - if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds)) + if (portp->brdnr >= stli_nrbrds) return 0; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -1446,7 +1445,7 @@ static void stli_flushchars(struct tty_struct *tty) portp = tty->driver_data; if (portp == NULL) return; - if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds)) + if (portp->brdnr >= stli_nrbrds) return; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -1524,7 +1523,7 @@ static int stli_writeroom(struct tty_struct *tty) portp = tty->driver_data; if (portp == NULL) return 0; - if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds)) + if (portp->brdnr >= stli_nrbrds) return 0; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -1572,7 +1571,7 @@ static int stli_charsinbuffer(struct tty_struct *tty) portp = tty->driver_data; if (portp == NULL) return 0; - if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds)) + if (portp->brdnr >= stli_nrbrds) return 0; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -1670,7 +1669,7 @@ static int stli_tiocmget(struct tty_struct *tty, struct file *file) if (portp == NULL) return -ENODEV; - if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds) + if (portp->brdnr >= stli_nrbrds) return 0; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -1694,7 +1693,7 @@ static int stli_tiocmset(struct tty_struct *tty, struct file *file, if (portp == NULL) return -ENODEV; - if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds) + if (portp->brdnr >= stli_nrbrds) return 0; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -1728,7 +1727,7 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm portp = tty->driver_data; if (portp == NULL) return -ENODEV; - if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds) + if (portp->brdnr >= stli_nrbrds) return 0; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -1806,7 +1805,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) portp = tty->driver_data; if (portp == NULL) return; - if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds) + if (portp->brdnr >= stli_nrbrds) return; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -1921,7 +1920,7 @@ static void stli_hangup(struct tty_struct *tty) portp = tty->driver_data; if (portp == NULL) return; - if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds) + if (portp->brdnr >= stli_nrbrds) return; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -1974,7 +1973,7 @@ static void stli_flushbuffer(struct tty_struct *tty) portp = tty->driver_data; if (portp == NULL) return; - if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds) + if (portp->brdnr >= stli_nrbrds) return; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -2011,7 +2010,7 @@ static void stli_breakctl(struct tty_struct *tty, int state) portp = tty->driver_data; if (portp == NULL) return; - if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds) + if (portp->brdnr >= stli_nrbrds) return; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -2058,7 +2057,7 @@ static void stli_sendxchar(struct tty_struct *tty, char ch) portp = tty->driver_data; if (portp == NULL) return; - if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds) + if (portp->brdnr >= stli_nrbrds) return; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) @@ -2151,7 +2150,7 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo { struct stlibrd *brdp; struct stliport *portp; - int brdnr, portnr, totalport; + unsigned int brdnr, portnr, totalport; int curoff, maxoff; char *pos; @@ -2603,7 +2602,7 @@ static void stli_poll(unsigned long arg) { cdkhdr_t __iomem *hdrp; struct stlibrd *brdp; - int brdnr; + unsigned int brdnr; stli_timerlist.expires = STLI_TIMEOUT; add_timer(&stli_timerlist); @@ -2787,7 +2786,7 @@ static long stli_mktiocm(unsigned long sigvalue) static int stli_initports(struct stlibrd *brdp) { struct stliport *portp; - int i, panelnr, panelport; + unsigned int i, panelnr, panelport; for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) { portp = kzalloc(sizeof(struct stliport), GFP_KERNEL); @@ -3570,8 +3569,9 @@ static int stli_startbrd(struct stlibrd *brdp) cdkmem_t __iomem *memp; cdkasy_t __iomem *ap; unsigned long flags; + unsigned int portnr, nrdevs, i; struct stliport *portp; - int portnr, nrdevs, i, rc = 0; + int rc = 0; u32 memoff; spin_lock_irqsave(&brd_lock, flags); @@ -3807,7 +3807,7 @@ static int stli_eisamemprobe(struct stlibrd *brdp) static int stli_getbrdnr(void) { - int i; + unsigned int i; for (i = 0; i < STL_MAXBRDS; i++) { if (!stli_brds[i]) { @@ -3834,8 +3834,8 @@ static int stli_getbrdnr(void) static int stli_findeisabrds(void) { struct stlibrd *brdp; - unsigned int iobase, eid; - int i; + unsigned int iobase, eid, i; + int brdnr; /* * Firstly check if this is an EISA system. If this is not an EISA system then @@ -3874,8 +3874,10 @@ static int stli_findeisabrds(void) */ if ((brdp = stli_allocbrd()) == NULL) return -ENOMEM; - if ((brdp->brdnr = stli_getbrdnr()) < 0) + brdnr = stli_getbrdnr(); + if (brdnr < 0) return -ENOMEM; + brdp->brdnr = (unsigned int)brdnr; eid = inb(iobase + 0xc82); if (eid == ECP_EISAID) brdp->brdtype = BRD_ECPE; @@ -3911,7 +3913,7 @@ static int __devinit stli_pciprobe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct stlibrd *brdp; - int retval = -EIO; + int brdnr, retval = -EIO; retval = pci_enable_device(pdev); if (retval) @@ -3921,12 +3923,14 @@ static int __devinit stli_pciprobe(struct pci_dev *pdev, retval = -ENOMEM; goto err; } - if ((brdp->brdnr = stli_getbrdnr()) < 0) { /* TODO: locking */ + brdnr = stli_getbrdnr(); + if (brdnr < 0) { /* TODO: locking */ printk(KERN_INFO "STALLION: too many boards found, " "maximum supported %d\n", STL_MAXBRDS); retval = -EIO; goto err_fr; } + brdp->brdnr = (unsigned int)brdnr; brdp->brdtype = BRD_ECPPCI; /* * We have all resources from the board, so lets setup the actual @@ -3998,7 +4002,8 @@ static int stli_initbrds(void) { struct stlibrd *brdp, *nxtbrdp; struct stlconf conf; - int i, j, retval; + unsigned int i, j; + int retval; for (stli_nrbrds = 0; stli_nrbrds < ARRAY_SIZE(stli_brdsp); stli_nrbrds++) { @@ -4074,7 +4079,8 @@ static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, lof unsigned long flags; void __iomem *memptr; struct stlibrd *brdp; - int brdnr, size, n; + unsigned int brdnr; + int size, n; void *p; loff_t off = *offp; @@ -4138,7 +4144,8 @@ static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t cou void __iomem *memptr; struct stlibrd *brdp; char __user *chbuf; - int brdnr, size, n; + unsigned int brdnr; + int size, n; void *p; loff_t off = *offp; @@ -4198,7 +4205,7 @@ out: static int stli_getbrdstats(combrd_t __user *bp) { struct stlibrd *brdp; - int i; + unsigned int i; if (copy_from_user(&stli_brdstats, bp, sizeof(combrd_t))) return -EFAULT; @@ -4234,19 +4241,20 @@ static int stli_getbrdstats(combrd_t __user *bp) * Resolve the referenced port number into a port struct pointer. */ -static struct stliport *stli_getport(int brdnr, int panelnr, int portnr) +static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr, + unsigned int portnr) { struct stlibrd *brdp; - int i; + unsigned int i; - if (brdnr < 0 || brdnr >= STL_MAXBRDS) + if (brdnr >= STL_MAXBRDS) return NULL; brdp = stli_brds[brdnr]; if (brdp == NULL) return NULL; for (i = 0; (i < panelnr); i++) portnr += brdp->panels[i]; - if ((portnr < 0) || (portnr >= brdp->nrports)) + if (portnr >= brdp->nrports) return NULL; return brdp->ports[portnr]; } @@ -4405,6 +4413,7 @@ static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp) static int stli_getportstruct(struct stliport __user *arg) { + struct stliport stli_dummyport; struct stliport *portp; if (copy_from_user(&stli_dummyport, arg, sizeof(struct stliport))) @@ -4426,11 +4435,12 @@ static int stli_getportstruct(struct stliport __user *arg) static int stli_getbrdstruct(struct stlibrd __user *arg) { + struct stlibrd stli_dummybrd; struct stlibrd *brdp; if (copy_from_user(&stli_dummybrd, arg, sizeof(struct stlibrd))) return -EFAULT; - if ((stli_dummybrd.brdnr < 0) || (stli_dummybrd.brdnr >= STL_MAXBRDS)) + if (stli_dummybrd.brdnr >= STL_MAXBRDS) return -ENODEV; brdp = stli_brds[stli_dummybrd.brdnr]; if (!brdp) diff --git a/include/linux/istallion.h b/include/linux/istallion.h index af2c32d16d45..106a5e85e5c4 100644 --- a/include/linux/istallion.h +++ b/include/linux/istallion.h @@ -51,11 +51,11 @@ */ struct stliport { unsigned long magic; - int portnr; - int panelnr; - int brdnr; + unsigned int portnr; + unsigned int panelnr; + unsigned int brdnr; unsigned long state; - int devnr; + unsigned int devnr; int flags; int baud_base; int custom_divisor; @@ -91,23 +91,23 @@ struct stliport { */ struct stlibrd { unsigned long magic; - int brdnr; - int brdtype; - int state; - int nrpanels; - int nrports; - int nrdevs; + unsigned int brdnr; + unsigned int brdtype; + unsigned int state; + unsigned int nrpanels; + unsigned int nrports; + unsigned int nrdevs; unsigned int iobase; int iosize; unsigned long memaddr; void __iomem *membase; - int memsize; + unsigned long memsize; int pagesize; int hostoffset; int slaveoffset; int bitsize; int enabval; - int panels[STL_MAXPANELS]; + unsigned int panels[STL_MAXPANELS]; int panelids[STL_MAXPANELS]; void (*init)(struct stlibrd *brdp); void (*enable)(struct stlibrd *brdp); -- cgit v1.2.3 From 6ff1cb355e628f8fc55fa2d01e269e5e1bbc2fe9 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 8 Dec 2006 02:39:43 -0800 Subject: [PATCH] fault-injection capabilities infrastructure This patch provides base functions implement to fault-injection capabilities. - The function should_fail() is taken from failmalloc-1.0 (http://www.nongnu.org/failmalloc/) [akpm@osdl.org: cleanups, comments, add __init] Cc: Signed-off-by: Akinobu Mita Signed-off-by: Don Mullis Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fault-inject.h | 69 ++++++++++++++++ lib/Kconfig.debug | 12 +++ lib/Makefile | 1 + lib/fault-inject.c | 183 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 265 insertions(+) create mode 100644 include/linux/fault-inject.h create mode 100644 lib/fault-inject.c (limited to 'include/linux') diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h new file mode 100644 index 000000000000..4df4902bc8d8 --- /dev/null +++ b/include/linux/fault-inject.h @@ -0,0 +1,69 @@ +#ifndef _LINUX_FAULT_INJECT_H +#define _LINUX_FAULT_INJECT_H + +#ifdef CONFIG_FAULT_INJECTION + +#include +#include +#include + +/* + * For explanation of the elements of this struct, see + * Documentation/fault-injection/fault-injection.txt + */ +struct fault_attr { + unsigned long probability; + unsigned long interval; + atomic_t times; + atomic_t space; + unsigned long verbose; + + unsigned long count; + +#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS + + struct { + struct dentry *dir; + + struct dentry *probability_file; + struct dentry *interval_file; + struct dentry *times_file; + struct dentry *space_file; + struct dentry *verbose_file; + } dentries; + +#endif +}; + +#define FAULT_ATTR_INITIALIZER { \ + .interval = 1, \ + .times = ATOMIC_INIT(1), \ + } + +#define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER +int setup_fault_attr(struct fault_attr *attr, char *str); +void should_fail_srandom(unsigned long entropy); +int should_fail(struct fault_attr *attr, ssize_t size); + +#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS + +int init_fault_attr_dentries(struct fault_attr *attr, const char *name); +void cleanup_fault_attr_dentries(struct fault_attr *attr); + +#else /* CONFIG_FAULT_INJECTION_DEBUG_FS */ + +static inline int init_fault_attr_dentries(struct fault_attr *attr, + const char *name) +{ + return -ENODEV; +} + +static inline void cleanup_fault_attr_dentries(struct fault_attr *attr) +{ +} + +#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ + +#endif /* CONFIG_FAULT_INJECTION */ + +#endif /* _LINUX_FAULT_INJECT_H */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2c133c098607..35228b3e7e92 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -413,3 +413,15 @@ config LKDTM Documentation on how to use the module can be found in drivers/misc/lkdtm.c + +config FAULT_INJECTION + bool + +config FAULT_INJECTION_DEBUG_FS + bool "Debugfs entries for fault-injection capabilities" + depends on FAULT_INJECTION && SYSFS + select DEBUG_FS + help + This option enable configuration of fault-injection capabilities via + debugfs. + diff --git a/lib/Makefile b/lib/Makefile index 6f675c6149a7..2d6106af53cd 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_SMP) += percpu_counter.o obj-$(CONFIG_AUDIT_GENERIC) += audit.o obj-$(CONFIG_SWIOTLB) += swiotlb.o +obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o lib-$(CONFIG_GENERIC_BUG) += bug.o diff --git a/lib/fault-inject.c b/lib/fault-inject.c new file mode 100644 index 000000000000..a7cb3afd132a --- /dev/null +++ b/lib/fault-inject.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * setup_fault_attr() is a helper function for various __setup handlers, so it + * returns 0 on error, because that is what __setup handlers do. + */ +int __init setup_fault_attr(struct fault_attr *attr, char *str) +{ + unsigned long probability; + unsigned long interval; + int times; + int space; + + /* ",,," */ + if (sscanf(str, "%lu,%lu,%d,%d", + &interval, &probability, &space, ×) < 4) { + printk(KERN_WARNING + "FAULT_INJECTION: failed to parse arguments\n"); + return 0; + } + + attr->probability = probability; + attr->interval = interval; + atomic_set(&attr->times, times); + atomic_set(&attr->space, space); + + return 1; +} + +static void fail_dump(struct fault_attr *attr) +{ + if (attr->verbose > 0) + printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure\n"); + if (attr->verbose > 1) + dump_stack(); +} + +#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) + +/* + * This code is stolen from failmalloc-1.0 + * http://www.nongnu.org/failmalloc/ + */ + +int should_fail(struct fault_attr *attr, ssize_t size) +{ + if (atomic_read(&attr->times) == 0) + return 0; + + if (atomic_read(&attr->space) > size) { + atomic_sub(size, &attr->space); + return 0; + } + + if (attr->interval > 1) { + attr->count++; + if (attr->count % attr->interval) + return 0; + } + + if (attr->probability > random32() % 100) + goto fail; + + return 0; + +fail: + fail_dump(attr); + + if (atomic_read(&attr->times) != -1) + atomic_dec_not_zero(&attr->times); + + return 1; +} + +#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS + +static void debugfs_ul_set(void *data, u64 val) +{ + *(unsigned long *)data = val; +} + +static u64 debugfs_ul_get(void *data) +{ + return *(unsigned long *)data; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_ul, debugfs_ul_get, debugfs_ul_set, "%llu\n"); + +static struct dentry *debugfs_create_ul(const char *name, mode_t mode, + struct dentry *parent, unsigned long *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_ul); +} + +static void debugfs_atomic_t_set(void *data, u64 val) +{ + atomic_set((atomic_t *)data, val); +} + +static u64 debugfs_atomic_t_get(void *data) +{ + return atomic_read((atomic_t *)data); +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, + debugfs_atomic_t_set, "%lld\n"); + +static struct dentry *debugfs_create_atomic_t(const char *name, mode_t mode, + struct dentry *parent, atomic_t *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_atomic_t); +} + +void cleanup_fault_attr_dentries(struct fault_attr *attr) +{ + debugfs_remove(attr->dentries.probability_file); + attr->dentries.probability_file = NULL; + + debugfs_remove(attr->dentries.interval_file); + attr->dentries.interval_file = NULL; + + debugfs_remove(attr->dentries.times_file); + attr->dentries.times_file = NULL; + + debugfs_remove(attr->dentries.space_file); + attr->dentries.space_file = NULL; + + debugfs_remove(attr->dentries.verbose_file); + attr->dentries.verbose_file = NULL; + + if (attr->dentries.dir) + WARN_ON(!simple_empty(attr->dentries.dir)); + + debugfs_remove(attr->dentries.dir); + attr->dentries.dir = NULL; +} + +int init_fault_attr_dentries(struct fault_attr *attr, const char *name) +{ + mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; + struct dentry *dir; + + memset(&attr->dentries, 0, sizeof(attr->dentries)); + + dir = debugfs_create_dir(name, NULL); + if (!dir) + goto fail; + attr->dentries.dir = dir; + + attr->dentries.probability_file = + debugfs_create_ul("probability", mode, dir, &attr->probability); + + attr->dentries.interval_file = + debugfs_create_ul("interval", mode, dir, &attr->interval); + + attr->dentries.times_file = + debugfs_create_atomic_t("times", mode, dir, &attr->times); + + attr->dentries.space_file = + debugfs_create_atomic_t("space", mode, dir, &attr->space); + + attr->dentries.verbose_file = + debugfs_create_ul("verbose", mode, dir, &attr->verbose); + + if (!attr->dentries.probability_file || !attr->dentries.interval_file + || !attr->dentries.times_file || !attr->dentries.space_file + || !attr->dentries.verbose_file) + goto fail; + + return 0; +fail: + cleanup_fault_attr_dentries(attr); + return -ENOMEM; +} + +#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ -- cgit v1.2.3 From c17bb4951752d3e0f49cd1ea9d2e868422f9e0d6 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 8 Dec 2006 02:39:46 -0800 Subject: [PATCH] fault-injection capability for disk IO This patch provides fault-injection capability for disk IO. Boot option: fail_make_request=,,, -- specifies the interval of failures. -- specifies how often it should fail in percent. -- specifies the size of free space where disk IO can be issued safely in bytes. -- specifies how many times failures may happen at most. Debugfs: /debug/fail_make_request/interval /debug/fail_make_request/probability /debug/fail_make_request/specifies /debug/fail_make_request/times Example: fail_make_request=10,100,0,-1 echo 1 > /sys/blocks/hda/hda1/make-it-fail generic_make_request() on /dev/hda1 fails once per 10 times. Cc: Jens Axboe Signed-off-by: Akinobu Mita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- block/genhd.c | 31 +++++++++++++++++++++++++++++++ block/ll_rw_blk.c | 40 ++++++++++++++++++++++++++++++++++++++++ fs/partitions/check.c | 27 +++++++++++++++++++++++++++ include/linux/genhd.h | 4 ++++ lib/Kconfig.debug | 7 +++++++ 5 files changed, 109 insertions(+) (limited to 'include/linux') diff --git a/block/genhd.c b/block/genhd.c index 653919d50cd4..457fdac4c17d 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -417,6 +417,34 @@ static struct disk_attribute disk_attr_stat = { .show = disk_stats_read }; +#ifdef CONFIG_FAIL_MAKE_REQUEST + +static ssize_t disk_fail_store(struct gendisk * disk, + const char *buf, size_t count) +{ + int i; + + if (count > 0 && sscanf(buf, "%d", &i) > 0) { + if (i == 0) + disk->flags &= ~GENHD_FL_FAIL; + else + disk->flags |= GENHD_FL_FAIL; + } + + return count; +} +static ssize_t disk_fail_read(struct gendisk * disk, char *page) +{ + return sprintf(page, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0); +} +static struct disk_attribute disk_attr_fail = { + .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR }, + .store = disk_fail_store, + .show = disk_fail_read +}; + +#endif + static struct attribute * default_attrs[] = { &disk_attr_uevent.attr, &disk_attr_dev.attr, @@ -424,6 +452,9 @@ static struct attribute * default_attrs[] = { &disk_attr_removable.attr, &disk_attr_size.attr, &disk_attr_stat.attr, +#ifdef CONFIG_FAIL_MAKE_REQUEST + &disk_attr_fail.attr, +#endif NULL, }; diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 31512cd9f3ad..4f83fd922377 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -28,6 +28,7 @@ #include #include #include +#include /* * for max sense size @@ -3056,6 +3057,42 @@ static void handle_bad_sector(struct bio *bio) set_bit(BIO_EOF, &bio->bi_flags); } +#ifdef CONFIG_FAIL_MAKE_REQUEST + +static DECLARE_FAULT_ATTR(fail_make_request); + +static int __init setup_fail_make_request(char *str) +{ + return setup_fault_attr(&fail_make_request, str); +} +__setup("fail_make_request=", setup_fail_make_request); + +static int should_fail_request(struct bio *bio) +{ + if ((bio->bi_bdev->bd_disk->flags & GENHD_FL_FAIL) || + (bio->bi_bdev->bd_part && bio->bi_bdev->bd_part->make_it_fail)) + return should_fail(&fail_make_request, bio->bi_size); + + return 0; +} + +static int __init fail_make_request_debugfs(void) +{ + return init_fault_attr_dentries(&fail_make_request, + "fail_make_request"); +} + +late_initcall(fail_make_request_debugfs); + +#else /* CONFIG_FAIL_MAKE_REQUEST */ + +static inline int should_fail_request(struct bio *bio) +{ + return 0; +} + +#endif /* CONFIG_FAIL_MAKE_REQUEST */ + /** * generic_make_request: hand a buffer to its device driver for I/O * @bio: The bio describing the location in memory and on the device. @@ -3141,6 +3178,9 @@ end_io: if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) goto end_io; + if (should_fail_request(bio)) + goto end_io; + /* * If this device has partitions, remap block n * of partition p to block n+start(p) of the disk. diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 1901137f4eca..3d73d94d93a7 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -276,12 +276,39 @@ static struct part_attribute part_attr_stat = { .show = part_stat_read }; +#ifdef CONFIG_FAIL_MAKE_REQUEST + +static ssize_t part_fail_store(struct hd_struct * p, + const char *buf, size_t count) +{ + int i; + + if (count > 0 && sscanf(buf, "%d", &i) > 0) + p->make_it_fail = (i == 0) ? 0 : 1; + + return count; +} +static ssize_t part_fail_read(struct hd_struct * p, char *page) +{ + return sprintf(page, "%d\n", p->make_it_fail); +} +static struct part_attribute part_attr_fail = { + .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR }, + .store = part_fail_store, + .show = part_fail_read +}; + +#endif + static struct attribute * default_attrs[] = { &part_attr_uevent.attr, &part_attr_dev.attr, &part_attr_start.attr, &part_attr_size.attr, &part_attr_stat.attr, +#ifdef CONFIG_FAIL_MAKE_REQUEST + &part_attr_fail.attr, +#endif NULL, }; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 41f276fdd185..0a022b2f63fc 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -83,6 +83,9 @@ struct hd_struct { struct kobject *holder_dir; unsigned ios[2], sectors[2]; /* READs and WRITEs */ int policy, partno; +#ifdef CONFIG_FAIL_MAKE_REQUEST + int make_it_fail; +#endif }; #define GENHD_FL_REMOVABLE 1 @@ -90,6 +93,7 @@ struct hd_struct { #define GENHD_FL_CD 8 #define GENHD_FL_UP 16 #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 +#define GENHD_FL_FAIL 64 struct disk_stats { unsigned long sectors[2]; /* READs and WRITEs */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c66b7b400c9f..336241bf0ced 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -431,6 +431,13 @@ config FAIL_PAGE_ALLOC help This option provides fault-injection capabilitiy for alloc_pages(). +config FAIL_MAKE_REQUEST + bool "Fault-injection capabilitiy for disk IO" + depends on DEBUG_KERNEL + select FAULT_INJECTION + help + This option provides fault-injection capabilitiy to disk IO. + config FAULT_INJECTION_DEBUG_FS bool "Debugfs entries for fault-injection capabilities" depends on FAULT_INJECTION && SYSFS -- cgit v1.2.3 From f4f154fd920b2178382a6a24a236348e4429ebc1 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 8 Dec 2006 02:39:47 -0800 Subject: [PATCH] fault injection: process filtering for fault-injection capabilities This patch provides process filtering feature. The process filter allows failing only permitted processes by /proc//make-it-fail Please see the example that demostrates how to inject slab allocation failures into module init/cleanup code in Documentation/fault-injection/fault-injection.txt Signed-off-by: Akinobu Mita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 65 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/fault-inject.h | 2 ++ include/linux/sched.h | 3 ++ lib/fault-inject.c | 17 +++++++++++- 4 files changed, 86 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/fs/proc/base.c b/fs/proc/base.c index a3b5074118a7..fd959d5b5a80 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -853,6 +853,65 @@ static struct file_operations proc_seccomp_operations = { }; #endif /* CONFIG_SECCOMP */ +#ifdef CONFIG_FAULT_INJECTION +static ssize_t proc_fault_inject_read(struct file * file, char __user * buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task = get_proc_task(file->f_dentry->d_inode); + char buffer[PROC_NUMBUF]; + size_t len; + int make_it_fail; + loff_t __ppos = *ppos; + + if (!task) + return -ESRCH; + make_it_fail = task->make_it_fail; + put_task_struct(task); + + len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail); + if (__ppos >= len) + return 0; + if (count > len-__ppos) + count = len-__ppos; + if (copy_to_user(buf, buffer + __ppos, count)) + return -EFAULT; + *ppos = __ppos + count; + return count; +} + +static ssize_t proc_fault_inject_write(struct file * file, + const char __user * buf, size_t count, loff_t *ppos) +{ + struct task_struct *task; + char buffer[PROC_NUMBUF], *end; + int make_it_fail; + + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) + return -EFAULT; + make_it_fail = simple_strtol(buffer, &end, 0); + if (*end == '\n') + end++; + task = get_proc_task(file->f_dentry->d_inode); + if (!task) + return -ESRCH; + task->make_it_fail = make_it_fail; + put_task_struct(task); + if (end - buffer == 0) + return -EIO; + return end - buffer; +} + +static struct file_operations proc_fault_inject_operations = { + .read = proc_fault_inject_read, + .write = proc_fault_inject_write, +}; +#endif + static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; @@ -1793,6 +1852,9 @@ static struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_AUDITSYSCALL REG("loginuid", S_IWUSR|S_IRUGO, loginuid), #endif +#ifdef CONFIG_FAULT_INJECTION + REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject), +#endif }; static int proc_tgid_base_readdir(struct file * filp, @@ -2068,6 +2130,9 @@ static struct pid_entry tid_base_stuff[] = { #ifdef CONFIG_AUDITSYSCALL REG("loginuid", S_IWUSR|S_IRUGO, loginuid), #endif +#ifdef CONFIG_FAULT_INJECTION + REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject), +#endif }; static int proc_tid_base_readdir(struct file * filp, diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h index 4df4902bc8d8..a525f9b9f015 100644 --- a/include/linux/fault-inject.h +++ b/include/linux/fault-inject.h @@ -17,6 +17,7 @@ struct fault_attr { atomic_t times; atomic_t space; unsigned long verbose; + u32 task_filter; unsigned long count; @@ -30,6 +31,7 @@ struct fault_attr { struct dentry *times_file; struct dentry *space_file; struct dentry *verbose_file; + struct dentry *task_filter_file; } dentries; #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index f0317edea141..ad9c46071ff8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1045,6 +1045,9 @@ struct task_struct { #ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info *delays; #endif +#ifdef CONFIG_FAULT_INJECTION + int make_it_fail; +#endif }; static inline pid_t process_group(struct task_struct *tsk) diff --git a/lib/fault-inject.c b/lib/fault-inject.c index a7cb3afd132a..03468609d701 100644 --- a/lib/fault-inject.c +++ b/lib/fault-inject.c @@ -5,6 +5,7 @@ #include #include #include +#include #include /* @@ -44,6 +45,11 @@ static void fail_dump(struct fault_attr *attr) #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) +static int fail_task(struct fault_attr *attr, struct task_struct *task) +{ + return !in_interrupt() && task->make_it_fail; +} + /* * This code is stolen from failmalloc-1.0 * http://www.nongnu.org/failmalloc/ @@ -51,6 +57,9 @@ static void fail_dump(struct fault_attr *attr) int should_fail(struct fault_attr *attr, ssize_t size) { + if (attr->task_filter && !fail_task(attr, current)) + return 0; + if (atomic_read(&attr->times) == 0) return 0; @@ -135,6 +144,9 @@ void cleanup_fault_attr_dentries(struct fault_attr *attr) debugfs_remove(attr->dentries.verbose_file); attr->dentries.verbose_file = NULL; + debugfs_remove(attr->dentries.task_filter_file); + attr->dentries.task_filter_file = NULL; + if (attr->dentries.dir) WARN_ON(!simple_empty(attr->dentries.dir)); @@ -169,9 +181,12 @@ int init_fault_attr_dentries(struct fault_attr *attr, const char *name) attr->dentries.verbose_file = debugfs_create_ul("verbose", mode, dir, &attr->verbose); + attr->dentries.task_filter_file = debugfs_create_bool("task-filter", + mode, dir, &attr->task_filter); + if (!attr->dentries.probability_file || !attr->dentries.interval_file || !attr->dentries.times_file || !attr->dentries.space_file - || !attr->dentries.verbose_file) + || !attr->dentries.verbose_file || !attr->dentries.task_filter_file) goto fail; return 0; -- cgit v1.2.3 From 329409aeda064c4aff00c51f837fcd3bbdaeeba6 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 8 Dec 2006 02:39:48 -0800 Subject: [PATCH] fault injection: stacktrace filtering This patch provides stacktrace filtering feature. The stacktrace filter allows failing only for the caller you are interested in. For example someone may want to inject kmalloc() failures into only e100 module. they want to inject not only direct kmalloc() call, but also indirect allocation, too. - e100_poll --> netif_receive_skb --> packet_rcv_spkt --> skb_clone --> kmem_cache_alloc This patch enables to detect function calls like this by stacktrace and inject failures. The script Documentaion/fault-injection/failmodule.sh helps it. The range of text section of loaded e100 is expected to be [/sys/module/e100/sections/.text, /sys/module/e100/sections/.exit.text) So failmodule.sh stores these values into /debug/failslab/address-start and /debug/failslab/address-end. The maximum stacktrace depth is specified by /debug/failslab/stacktrace-depth. Please see the example that demonstrates how to inject slab allocation failures only for a specific module in Documentation/fault-injection/fault-injection.txt [dwm@meer.net: reject failure if any caller lies within specified range] Signed-off-by: Akinobu Mita Signed-off-by: Don Mullis Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/fault-injection/fault-injection.txt | 12 ++- include/linux/fault-inject.h | 12 +++ lib/Kconfig.debug | 5 + lib/fault-inject.c | 126 +++++++++++++++++++++- 4 files changed, 150 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/Documentation/fault-injection/fault-injection.txt b/Documentation/fault-injection/fault-injection.txt index cf075c20eda0..6d6e5ac5ea92 100644 --- a/Documentation/fault-injection/fault-injection.txt +++ b/Documentation/fault-injection/fault-injection.txt @@ -73,13 +73,17 @@ configuration of fault-injection capabilities. Any positive value limits failures to only processes indicated by /proc//make-it-fail==1. -- /debug/*/address-start: -- /debug/*/address-end: +- /debug/*/require-start: +- /debug/*/require-end: +- /debug/*/reject-start: +- /debug/*/reject-end: specifies the range of virtual addresses tested during stacktrace walking. Failure is injected only if some caller - in the walked stacktrace lies within this range. - Default is [0,ULONG_MAX) (whole of virtual address space). + in the walked stacktrace lies within the required range, and + none lies within the rejected range. + Default required range is [0,ULONG_MAX) (whole of virtual address space). + Default rejected range is [0,0). - /debug/*/stacktrace-depth: diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h index a525f9b9f015..9bb584e89399 100644 --- a/include/linux/fault-inject.h +++ b/include/linux/fault-inject.h @@ -18,6 +18,11 @@ struct fault_attr { atomic_t space; unsigned long verbose; u32 task_filter; + unsigned long stacktrace_depth; + unsigned long require_start; + unsigned long require_end; + unsigned long reject_start; + unsigned long reject_end; unsigned long count; @@ -32,6 +37,11 @@ struct fault_attr { struct dentry *space_file; struct dentry *verbose_file; struct dentry *task_filter_file; + struct dentry *stacktrace_depth_file; + struct dentry *require_start_file; + struct dentry *require_end_file; + struct dentry *reject_start_file; + struct dentry *reject_end_file; } dentries; #endif @@ -40,6 +50,8 @@ struct fault_attr { #define FAULT_ATTR_INITIALIZER { \ .interval = 1, \ .times = ATOMIC_INIT(1), \ + .require_end = ULONG_MAX, \ + .stacktrace_depth = 32, \ } #define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 336241bf0ced..1449ca1bf572 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -416,6 +416,11 @@ config LKDTM config FAULT_INJECTION bool + select STACKTRACE + select FRAME_POINTER + help + Provide fault-injection framework. + For more details, see Documentation/fault-injection/. config FAILSLAB bool "Fault-injection capabilitiy for kmalloc" diff --git a/lib/fault-inject.c b/lib/fault-inject.c index 03468609d701..361c6e9cd77f 100644 --- a/lib/fault-inject.c +++ b/lib/fault-inject.c @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include /* @@ -50,6 +53,86 @@ static int fail_task(struct fault_attr *attr, struct task_struct *task) return !in_interrupt() && task->make_it_fail; } +#ifdef CONFIG_STACK_UNWIND + +static asmlinkage int fail_stacktrace_callback(struct unwind_frame_info *info, + void *arg) +{ + int depth; + struct fault_attr *attr = arg; + bool found = (attr->require_start == 0 && attr->require_end == ULONG_MAX); + + for (depth = 0; depth < attr->stacktrace_depth + && unwind(info) == 0 && UNW_PC(info); depth++) { + if (arch_unw_user_mode(info)) + break; + if (attr->reject_start <= UNW_PC(info) && + UNW_PC(info) < attr->reject_end) + return 0; + if (attr->require_start <= UNW_PC(info) && + UNW_PC(info) < attr->require_end) + found = 1; + } + return found; +} + +static int fail_stacktrace(struct fault_attr *attr) +{ + struct unwind_frame_info info; + + return unwind_init_running(&info, fail_stacktrace_callback, attr); +} + +#elif defined(CONFIG_STACKTRACE) + +#define MAX_STACK_TRACE_DEPTH 32 + +static int fail_stacktrace(struct fault_attr *attr) +{ + struct stack_trace trace; + int depth = attr->stacktrace_depth; + unsigned long entries[MAX_STACK_TRACE_DEPTH]; + int n; + bool found = (attr->require_start == 0 && attr->require_end == ULONG_MAX); + + if (depth == 0) + return found; + + trace.nr_entries = 0; + trace.entries = entries; + trace.max_entries = (depth < MAX_STACK_TRACE_DEPTH) ? + depth : MAX_STACK_TRACE_DEPTH; + trace.skip = 1; + trace.all_contexts = 0; + + save_stack_trace(&trace, NULL); + for (n = 0; n < trace.nr_entries; n++) { + if (attr->reject_start <= entries[n] && + entries[n] < attr->reject_end) + return 0; + if (attr->require_start <= entries[n] && + entries[n] < attr->require_end) + found = 1; + } + return found; +} + +#else + +static inline int fail_stacktrace(struct fault_attr *attr) +{ + static int firsttime = 1; + + if (firsttime) { + printk(KERN_WARNING + "This architecture does not implement save_stack_trace()\n"); + firsttime = 0; + } + return 0; +} + +#endif + /* * This code is stolen from failmalloc-1.0 * http://www.nongnu.org/failmalloc/ @@ -60,6 +143,9 @@ int should_fail(struct fault_attr *attr, ssize_t size) if (attr->task_filter && !fail_task(attr, current)) return 0; + if (!fail_stacktrace(attr)) + return 0; + if (atomic_read(&attr->times) == 0) return 0; @@ -147,6 +233,21 @@ void cleanup_fault_attr_dentries(struct fault_attr *attr) debugfs_remove(attr->dentries.task_filter_file); attr->dentries.task_filter_file = NULL; + debugfs_remove(attr->dentries.stacktrace_depth_file); + attr->dentries.stacktrace_depth_file = NULL; + + debugfs_remove(attr->dentries.require_start_file); + attr->dentries.require_start_file = NULL; + + debugfs_remove(attr->dentries.require_end_file); + attr->dentries.require_end_file = NULL; + + debugfs_remove(attr->dentries.reject_start_file); + attr->dentries.reject_start_file = NULL; + + debugfs_remove(attr->dentries.reject_end_file); + attr->dentries.reject_end_file = NULL; + if (attr->dentries.dir) WARN_ON(!simple_empty(attr->dentries.dir)); @@ -184,9 +285,32 @@ int init_fault_attr_dentries(struct fault_attr *attr, const char *name) attr->dentries.task_filter_file = debugfs_create_bool("task-filter", mode, dir, &attr->task_filter); + attr->dentries.stacktrace_depth_file = + debugfs_create_ul("stacktrace-depth", mode, dir, + &attr->stacktrace_depth); + + attr->dentries.require_start_file = + debugfs_create_ul("require-start", mode, dir, &attr->require_start); + + attr->dentries.require_end_file = + debugfs_create_ul("require-end", mode, dir, &attr->require_end); + + attr->dentries.reject_start_file = + debugfs_create_ul("reject-start", mode, dir, &attr->reject_start); + + attr->dentries.reject_end_file = + debugfs_create_ul("reject-end", mode, dir, &attr->reject_end); + + if (!attr->dentries.probability_file || !attr->dentries.interval_file || !attr->dentries.times_file || !attr->dentries.space_file - || !attr->dentries.verbose_file || !attr->dentries.task_filter_file) + || !attr->dentries.verbose_file || !attr->dentries.task_filter_file + || !attr->dentries.stacktrace_depth_file + || !attr->dentries.require_start_file + || !attr->dentries.require_end_file + || !attr->dentries.reject_start_file + || !attr->dentries.reject_end_file + ) goto fail; return 0; -- cgit v1.2.3 From 08b3df2d16cbebf7d72c09dcbc071696c14d07e3 Mon Sep 17 00:00:00 2001 From: Don Mullis Date: Fri, 8 Dec 2006 02:39:51 -0800 Subject: [PATCH] fault-injection: Use bool-true-false throughout Use bool-true-false throughout. Signed-off-by: Don Mullis Cc: Akinobu Mita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fault-inject.h | 2 +- lib/fault-inject.c | 40 +++++++++++++++++++--------------------- 2 files changed, 20 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h index 9bb584e89399..c77067916b7e 100644 --- a/include/linux/fault-inject.h +++ b/include/linux/fault-inject.h @@ -57,7 +57,7 @@ struct fault_attr { #define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER int setup_fault_attr(struct fault_attr *attr, char *str); void should_fail_srandom(unsigned long entropy); -int should_fail(struct fault_attr *attr, ssize_t size); +bool should_fail(struct fault_attr *attr, ssize_t size); #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS diff --git a/lib/fault-inject.c b/lib/fault-inject.c index 361c6e9cd77f..244782940349 100644 --- a/lib/fault-inject.c +++ b/lib/fault-inject.c @@ -48,7 +48,7 @@ static void fail_dump(struct fault_attr *attr) #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) -static int fail_task(struct fault_attr *attr, struct task_struct *task) +static bool fail_task(struct fault_attr *attr, struct task_struct *task) { return !in_interrupt() && task->make_it_fail; } @@ -68,15 +68,15 @@ static asmlinkage int fail_stacktrace_callback(struct unwind_frame_info *info, break; if (attr->reject_start <= UNW_PC(info) && UNW_PC(info) < attr->reject_end) - return 0; + return false; if (attr->require_start <= UNW_PC(info) && UNW_PC(info) < attr->require_end) - found = 1; + found = true; } return found; } -static int fail_stacktrace(struct fault_attr *attr) +static bool fail_stacktrace(struct fault_attr *attr) { struct unwind_frame_info info; @@ -85,9 +85,7 @@ static int fail_stacktrace(struct fault_attr *attr) #elif defined(CONFIG_STACKTRACE) -#define MAX_STACK_TRACE_DEPTH 32 - -static int fail_stacktrace(struct fault_attr *attr) +static bool fail_stacktrace(struct fault_attr *attr) { struct stack_trace trace; int depth = attr->stacktrace_depth; @@ -109,26 +107,26 @@ static int fail_stacktrace(struct fault_attr *attr) for (n = 0; n < trace.nr_entries; n++) { if (attr->reject_start <= entries[n] && entries[n] < attr->reject_end) - return 0; + return false; if (attr->require_start <= entries[n] && entries[n] < attr->require_end) - found = 1; + found = true; } return found; } #else -static inline int fail_stacktrace(struct fault_attr *attr) +static inline bool fail_stacktrace(struct fault_attr *attr) { - static int firsttime = 1; + static bool firsttime = true; if (firsttime) { printk(KERN_WARNING "This architecture does not implement save_stack_trace()\n"); - firsttime = 0; + firsttime = false; } - return 0; + return false; } #endif @@ -138,32 +136,32 @@ static inline int fail_stacktrace(struct fault_attr *attr) * http://www.nongnu.org/failmalloc/ */ -int should_fail(struct fault_attr *attr, ssize_t size) +bool should_fail(struct fault_attr *attr, ssize_t size) { if (attr->task_filter && !fail_task(attr, current)) - return 0; + return false; if (!fail_stacktrace(attr)) - return 0; + return false; if (atomic_read(&attr->times) == 0) - return 0; + return false; if (atomic_read(&attr->space) > size) { atomic_sub(size, &attr->space); - return 0; + return false; } if (attr->interval > 1) { attr->count++; if (attr->count % attr->interval) - return 0; + return false; } if (attr->probability > random32() % 100) goto fail; - return 0; + return false; fail: fail_dump(attr); @@ -171,7 +169,7 @@ fail: if (atomic_read(&attr->times) != -1) atomic_dec_not_zero(&attr->times); - return 1; + return true; } #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS -- cgit v1.2.3 From 6b1b60f41eef3ba7b188fd72f1d6de478aafd93c Mon Sep 17 00:00:00 2001 From: Don Mullis Date: Fri, 8 Dec 2006 02:39:53 -0800 Subject: [PATCH] fault-injection: defaults likely to please a new user Assign defaults most likely to please a new user: 1) generate some logging output (verbose=2) 2) avoid injecting failures likely to lock up UI (ignore_gfp_wait=1, ignore_gfp_highmem=1) Signed-off-by: Don Mullis Cc: Akinobu Mita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fault-inject.h | 1 + mm/page_alloc.c | 2 ++ mm/slab.c | 1 + 3 files changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h index c77067916b7e..32368c4f0326 100644 --- a/include/linux/fault-inject.h +++ b/include/linux/fault-inject.h @@ -52,6 +52,7 @@ struct fault_attr { .times = ATOMIC_INIT(1), \ .require_end = ULONG_MAX, \ .stacktrace_depth = 32, \ + .verbose = 2, \ } #define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0cc8b4376e91..e6b17b2989e0 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -910,6 +910,8 @@ static struct fail_page_alloc_attr { } fail_page_alloc = { .attr = FAULT_ATTR_INITIALIZER, + .ignore_gfp_wait = 1, + .ignore_gfp_highmem = 1, }; static int __init setup_fail_page_alloc(char *str) diff --git a/mm/slab.c b/mm/slab.c index 47011e2ef3c9..56af694c9e6a 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3102,6 +3102,7 @@ static struct failslab_attr { } failslab = { .attr = FAULT_ATTR_INITIALIZER, + .ignore_gfp_wait = 1, }; static int __init setup_failslab(char *str) -- cgit v1.2.3 From adf6b206546414fd006098d027e81f2b576ea2aa Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 8 Dec 2006 02:40:27 -0800 Subject: [PATCH] fbcmap.c: mark structs const or __read_mostly - Mark the default colormaps read-only, as nobody should be allowed to modify them - Additionally mark color values as __read_mostly since they will only be modified (very seldom) by fb_invert_cmaps() - Add named C99-initializers in fb_cmap structs and use the ARRAY_SIZE() macro Signed-off-by: Helge Deller Acked-by: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/fbcmap.c | 55 +++++++++++++++++++++++++------------------------- include/linux/fb.h | 6 +++--- 2 files changed, 31 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index e8b135f3d80d..148108afdd51 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c @@ -18,63 +18,64 @@ #include -static u16 red2[] = { +static u16 red2[] __read_mostly = { 0x0000, 0xaaaa }; -static u16 green2[] = { +static u16 green2[] __read_mostly = { 0x0000, 0xaaaa }; -static u16 blue2[] = { +static u16 blue2[] __read_mostly = { 0x0000, 0xaaaa }; -static u16 red4[] = { +static u16 red4[] __read_mostly = { 0x0000, 0xaaaa, 0x5555, 0xffff }; -static u16 green4[] = { +static u16 green4[] __read_mostly = { 0x0000, 0xaaaa, 0x5555, 0xffff }; -static u16 blue4[] = { +static u16 blue4[] __read_mostly = { 0x0000, 0xaaaa, 0x5555, 0xffff }; -static u16 red8[] = { +static u16 red8[] __read_mostly = { 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa }; -static u16 green8[] = { +static u16 green8[] __read_mostly = { 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa }; -static u16 blue8[] = { +static u16 blue8[] __read_mostly = { 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa }; -static u16 red16[] = { +static u16 red16[] __read_mostly = { 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff }; -static u16 green16[] = { +static u16 green16[] __read_mostly = { 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa, 0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff }; -static u16 blue16[] = { +static u16 blue16[] __read_mostly = { 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff }; -static struct fb_cmap default_2_colors = { - 0, 2, red2, green2, blue2, NULL +static const struct fb_cmap default_2_colors = { + .len=2, .red=red2, .green=green2, .blue=blue2 }; -static struct fb_cmap default_8_colors = { - 0, 8, red8, green8, blue8, NULL +static const struct fb_cmap default_8_colors = { + .len=8, .red=red8, .green=green8, .blue=blue8 }; -static struct fb_cmap default_4_colors = { - 0, 4, red4, green4, blue4, NULL +static const struct fb_cmap default_4_colors = { + .len=4, .red=red4, .green=green4, .blue=blue4 }; -static struct fb_cmap default_16_colors = { - 0, 16, red16, green16, blue16, NULL +static const struct fb_cmap default_16_colors = { + .len=16, .red=red16, .green=green16, .blue=blue16 }; + /** * fb_alloc_cmap - allocate a colormap * @cmap: frame buffer colormap structure @@ -146,7 +147,7 @@ void fb_dealloc_cmap(struct fb_cmap *cmap) * Copy contents of colormap from @from to @to. */ -int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to) +int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to) { int tooff = 0, fromoff = 0; int size; @@ -170,7 +171,7 @@ int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to) return 0; } -int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to) +int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to) { int tooff = 0, fromoff = 0; int size; @@ -282,7 +283,7 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info) * */ -struct fb_cmap *fb_default_cmap(int len) +const struct fb_cmap *fb_default_cmap(int len) { if (len <= 2) return &default_2_colors; @@ -305,22 +306,22 @@ void fb_invert_cmaps(void) { u_int i; - for (i = 0; i < 2; i++) { + for (i = 0; i < ARRAY_SIZE(red2); i++) { red2[i] = ~red2[i]; green2[i] = ~green2[i]; blue2[i] = ~blue2[i]; } - for (i = 0; i < 4; i++) { + for (i = 0; i < ARRAY_SIZE(red4); i++) { red4[i] = ~red4[i]; green4[i] = ~green4[i]; blue4[i] = ~blue4[i]; } - for (i = 0; i < 8; i++) { + for (i = 0; i < ARRAY_SIZE(red8); i++) { red8[i] = ~red8[i]; green8[i] = ~green8[i]; blue8[i] = ~blue8[i]; } - for (i = 0; i < 16; i++) { + for (i = 0; i < ARRAY_SIZE(red16); i++) { red16[i] = ~red16[i]; green16[i] = ~green16[i]; blue16[i] = ~blue16[i]; diff --git a/include/linux/fb.h b/include/linux/fb.h index fa23e0671bb3..6fe56aaa6685 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -970,11 +970,11 @@ extern struct fb_videomode *fb_find_best_display(struct fb_monspecs *specs, /* drivers/video/fbcmap.c */ extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp); extern void fb_dealloc_cmap(struct fb_cmap *cmap); -extern int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to); -extern int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to); +extern int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to); +extern int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to); extern int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *fb_info); extern int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *fb_info); -extern struct fb_cmap *fb_default_cmap(int len); +extern const struct fb_cmap *fb_default_cmap(int len); extern void fb_invert_cmaps(void); struct fb_videomode { -- cgit v1.2.3 From a3d77d35be6f416a250c528c3ed5c70013a915e8 Mon Sep 17 00:00:00 2001 From: Kiyoshi Ueda Date: Fri, 8 Dec 2006 02:41:04 -0800 Subject: [PATCH] dm: suspend: parameter change Change the interface of dm_suspend() so that we can pass several options without increasing the number of parameters. The existing 'do_lockfs' integer parameter is replaced by a flag DM_SUSPEND_LOCKFS_FLAG. There is no functional change to the code. Test results: I have tested 'dmsetup suspend' command with/without the '--nolockfs' option and confirmed the do_lockfs value is correctly set. Signed-off-by: Kiyoshi Ueda Signed-off-by: Jun'ichi Nomura Signed-off-by: Alasdair G Kergon Cc: dm-devel@redhat.com Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-ioctl.c | 12 ++++++------ drivers/md/dm.c | 3 ++- drivers/md/dm.h | 5 +++++ include/linux/device-mapper.h | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 4510ad8f971c..6d7a3d0c8f88 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -765,7 +765,7 @@ out: static int do_suspend(struct dm_ioctl *param) { int r = 0; - int do_lockfs = 1; + unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG; struct mapped_device *md; md = find_device(param); @@ -773,10 +773,10 @@ static int do_suspend(struct dm_ioctl *param) return -ENXIO; if (param->flags & DM_SKIP_LOCKFS_FLAG) - do_lockfs = 0; + suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; if (!dm_suspended(md)) - r = dm_suspend(md, do_lockfs); + r = dm_suspend(md, suspend_flags); if (!r) r = __dev_status(md, param); @@ -788,7 +788,7 @@ static int do_suspend(struct dm_ioctl *param) static int do_resume(struct dm_ioctl *param) { int r = 0; - int do_lockfs = 1; + unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG; struct hash_cell *hc; struct mapped_device *md; struct dm_table *new_map; @@ -814,9 +814,9 @@ static int do_resume(struct dm_ioctl *param) if (new_map) { /* Suspend if it isn't already suspended */ if (param->flags & DM_SKIP_LOCKFS_FLAG) - do_lockfs = 0; + suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; if (!dm_suspended(md)) - dm_suspend(md, do_lockfs); + dm_suspend(md, suspend_flags); r = dm_swap_table(md, new_map); if (r) { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index dd50e30b6dcf..b42e71bb9e67 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1272,12 +1272,13 @@ static void unlock_fs(struct mapped_device *md) * dm_bind_table, dm_suspend must be called to flush any in * flight bios and ensure that any further io gets deferred. */ -int dm_suspend(struct mapped_device *md, int do_lockfs) +int dm_suspend(struct mapped_device *md, unsigned suspend_flags) { struct dm_table *map = NULL; DECLARE_WAITQUEUE(wait, current); struct bio *def; int r = -EINVAL; + int do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG ? 1 : 0; down(&md->suspend_lock); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index a48ec5e3c1f4..81c98d6e35e9 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -32,6 +32,11 @@ #define SECTOR_SHIFT 9 +/* + * Suspend feature flags + */ +#define DM_SUSPEND_LOCKFS_FLAG (1 << 0) + /* * List of devices that a metadevice uses and should open/close. */ diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 03ef41c1eaac..9194ff2d08c0 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -173,7 +173,7 @@ void *dm_get_mdptr(struct mapped_device *md); /* * A device can still be used while suspended, but I/O is deferred. */ -int dm_suspend(struct mapped_device *md, int with_lockfs); +int dm_suspend(struct mapped_device *md, unsigned suspend_flags); int dm_resume(struct mapped_device *md); /* -- cgit v1.2.3 From 45cbcd798354251b99694086af9d57c99e89bb43 Mon Sep 17 00:00:00 2001 From: Kiyoshi Ueda Date: Fri, 8 Dec 2006 02:41:05 -0800 Subject: [PATCH] dm: map and endio return code clarification Tighten the use of return values from the target map and end_io functions. Values of 2 and above are now explictly reserved for future use. There are no existing targets using such values. The patch has no effect on existing behaviour. o Reserve return values of 2 and above from target map functions. Any positive value currently indicates "mapping complete", but all existing drivers use the value 1. We now make that a requirement so we can assign new meaning to higher values in future. The new definition of return values from target map functions is: < 0 : error = 0 : The target will handle the io (DM_MAPIO_SUBMITTED). = 1 : Mapping completed (DM_MAPIO_REMAPPED). > 1 : Reserved (undefined). Previously this was the same as '= 1'. o Reserve return values of 2 and above from target end_io functions for similar reasons. DM_ENDIO_INCOMPLETE is introduced for a return value of 1. Test results: I have tested by using the multipath target. I/Os succeed when valid paths exist. I/Os are queued in the multipath target when there are no valid paths and queue_if_no_path is set. I/Os fail when there are no valid paths and queue_if_no_path is not set. Signed-off-by: Kiyoshi Ueda Signed-off-by: Jun'ichi Nomura Signed-off-by: Alasdair G Kergon Cc: dm-devel@redhat.com Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm.c | 13 ++++++++++--- drivers/md/dm.h | 11 +++++++++++ include/linux/device-mapper.h | 2 +- 3 files changed, 22 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index b42e71bb9e67..d8544e1a4c1f 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -482,9 +482,13 @@ static int clone_endio(struct bio *bio, unsigned int done, int error) r = endio(tio->ti, bio, error, &tio->info); if (r < 0) error = r; - else if (r > 0) - /* the target wants another shot at the io */ + else if (r == DM_ENDIO_INCOMPLETE) + /* The target will handle the io */ return 1; + else if (r) { + DMWARN("unimplemented target endio return value: %d", r); + BUG(); + } } dec_pending(tio->io, error); @@ -542,7 +546,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, atomic_inc(&tio->io->io_count); sector = clone->bi_sector; r = ti->type->map(ti, clone, &tio->info); - if (r > 0) { + if (r == DM_MAPIO_REMAPPED) { /* the bio has been remapped so dispatch it */ blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone, @@ -560,6 +564,9 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, clone->bi_private = md->bs; bio_put(clone); free_tio(md, tio); + } else if (r) { + DMWARN("unimplemented target map return value: %d", r); + BUG(); } } diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 81c98d6e35e9..293d5ce62a21 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -32,6 +32,17 @@ #define SECTOR_SHIFT 9 +/* + * Definitions of return values from target end_io function. + */ +#define DM_ENDIO_INCOMPLETE 1 + +/* + * Definitions of return values from target map function. + */ +#define DM_MAPIO_SUBMITTED 0 +#define DM_MAPIO_REMAPPED 1 + /* * Suspend feature flags */ diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 9194ff2d08c0..2e5c42346c38 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -39,7 +39,7 @@ typedef void (*dm_dtr_fn) (struct dm_target *ti); * The map function must return: * < 0: error * = 0: The target will handle the io by resubmitting it later - * > 0: simple remap complete + * = 1: simple remap complete */ typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio, union map_info *map_context); -- cgit v1.2.3 From 81fdb096dbcedcc3b94c7e47b59362b5214891e2 Mon Sep 17 00:00:00 2001 From: Kiyoshi Ueda Date: Fri, 8 Dec 2006 02:41:07 -0800 Subject: [PATCH] dm: ioctl: add noflush suspend Provide a dm ioctl option to request noflush suspending. (See next patch for what this is for.) As the interface is extended, the version number is incremented. Other than accepting the new option through the interface, There is no change to existing behaviour. Test results: Confirmed the option is given from user-space correctly. Signed-off-by: Kiyoshi Ueda Signed-off-by: Jun'ichi Nomura Signed-off-by: Alasdair G Kergon Cc: dm-devel@redhat.com Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-ioctl.c | 4 ++++ drivers/md/dm.h | 1 + include/linux/dm-ioctl.h | 9 +++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 6d7a3d0c8f88..cd6a184536a1 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -774,6 +774,8 @@ static int do_suspend(struct dm_ioctl *param) if (param->flags & DM_SKIP_LOCKFS_FLAG) suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; + if (param->flags & DM_NOFLUSH_FLAG) + suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG; if (!dm_suspended(md)) r = dm_suspend(md, suspend_flags); @@ -815,6 +817,8 @@ static int do_resume(struct dm_ioctl *param) /* Suspend if it isn't already suspended */ if (param->flags & DM_SKIP_LOCKFS_FLAG) suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; + if (param->flags & DM_NOFLUSH_FLAG) + suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG; if (!dm_suspended(md)) dm_suspend(md, suspend_flags); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 293d5ce62a21..c307ca9a4c33 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -47,6 +47,7 @@ * Suspend feature flags */ #define DM_SUSPEND_LOCKFS_FLAG (1 << 0) +#define DM_SUSPEND_NOFLUSH_FLAG (1 << 1) /* * List of devices that a metadevice uses and should open/close. diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index 8853fc4d1c5e..b93486107821 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h @@ -285,9 +285,9 @@ typedef char ioctl_struct[308]; #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 10 +#define DM_VERSION_MINOR 11 #define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2006-09-14)" +#define DM_VERSION_EXTRA "-ioctl (2006-10-12)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ @@ -323,4 +323,9 @@ typedef char ioctl_struct[308]; */ #define DM_SKIP_LOCKFS_FLAG (1 << 10) /* In */ +/* + * Set this to suspend without flushing queued ios. + */ +#define DM_NOFLUSH_FLAG (1 << 11) /* In */ + #endif /* _LINUX_DM_IOCTL_H */ -- cgit v1.2.3 From 2e93ccc1933d08d32d9bde3784c3823e67b9b030 Mon Sep 17 00:00:00 2001 From: Kiyoshi Ueda Date: Fri, 8 Dec 2006 02:41:09 -0800 Subject: [PATCH] dm: suspend: add noflush pushback In device-mapper I/O is sometimes queued within targets for later processing. For example the multipath target can be configured to store I/O when no paths are available instead of returning it -EIO. This patch allows the device-mapper core to instruct a target to transfer the contents of any such in-target queue back into the core. This frees up the resources used by the target so the core can replace that target with an alternative one and then resend the I/O to it. Without this patch the only way to change the target in such circumstances involves returning the I/O with an error back to the filesystem/application. In the multipath case, this patch will let us add new paths for existing I/O to try after all the existing paths have failed. DMF_NOFLUSH_SUSPENDING ---------------------- If the DM_NOFLUSH_FLAG ioctl option is specified at suspend time, the DMF_NOFLUSH_SUSPENDING flag is set in md->flags during dm_suspend(). It is always cleared before dm_suspend() returns. The flag must be visible while the target is flushing pending I/Os so it is set before presuspend where the flush starts and unset after the wait for md->pending where the flush ends. Target drivers can check this flag by calling dm_noflush_suspending(). DM_MAPIO_REQUEUE / DM_ENDIO_REQUEUE ----------------------------------- A target's map() function can now return DM_MAPIO_REQUEUE to request the device mapper core queue the bio. Similarly, a target's end_io() function can return DM_ENDIO_REQUEUE to request the same. This has been labelled 'pushback'. The __map_bio() and clone_endio() functions in the core treat these return values as errors and call dec_pending() to end the I/O. dec_pending ----------- dec_pending() saves the pushback request in struct dm_io->error. Once all the split clones have ended, dec_pending() will put the original bio on the md->pushback list. Note that this supercedes any I/O errors. It is possible for the suspend with DM_NOFLUSH_FLAG to be aborted while in progress (e.g. by user interrupt). dec_pending() checks for this and returns -EIO if it happened. pushdback list and pushback_lock -------------------------------- The bio is queued on md->pushback temporarily in dec_pending(), and after all pending I/Os return, md->pushback is merged into md->deferred in dm_suspend() for re-issuing at resume time. md->pushback_lock protects md->pushback. The lock should be held with irq disabled because dec_pending() can be called from interrupt context. Queueing bios to md->pushback in dec_pending() must be done atomically with the check for DMF_NOFLUSH_SUSPENDING flag. So md->pushback_lock is held when checking the flag. Otherwise dec_pending() may queue a bio to md->pushback after the interrupted dm_suspend() flushes md->pushback. Then the bio would be left in md->pushback. Flag setting in dm_suspend() can be done without md->pushback_lock because the flag is checked only after presuspend and the set value is already made visible via the target's presuspend function. The flag can be checked without md->pushback_lock (e.g. the first part of the dec_pending() or target drivers), because the flag is checked again with md->pushback_lock held when the bio is really queued to md->pushback as described above. So even if the flag is cleared after the lockless checkings, the bio isn't left in md->pushback but returned to applications with -EIO. Other notes on the current patch -------------------------------- - md->pushback is added to the struct mapped_device instead of using md->deferred directly because md->io_lock which protects md->deferred is rw_semaphore and can't be used in interrupt context like dec_pending(), and md->io_lock protects the DMF_BLOCK_IO flag of md->flags too. - Don't issue lock_fs() in dm_suspend() if the DM_NOFLUSH_FLAG ioctl option is specified, because I/Os generated by lock_fs() would be pushed back and never return if there were no valid devices. - If an error occurs in dm_suspend() after the DMF_NOFLUSH_SUSPENDING flag is set, md->pushback must be flushed because I/Os may be queued to the list already. (flush_and_out label in dm_suspend()) Test results ------------ I have tested using multipath target with the next patch. The following tests are for regression/compatibility: - I/Os succeed when valid paths exist; - I/Os fail when there are no valid paths and queue_if_no_path is not set; - I/Os are queued in the multipath target when there are no valid paths and queue_if_no_path is set; - The queued I/Os above fail when suspend is issued without the DM_NOFLUSH_FLAG ioctl option. I/Os spanning 2 multipath targets also fail. The following tests are for the normal code path of new pushback feature: - Queued I/Os in the multipath target are flushed from the target but don't return when suspend is issued with the DM_NOFLUSH_FLAG ioctl option; - The I/Os above are queued in the multipath target again when resume is issued without path recovery; - The I/Os above succeed when resume is issued after path recovery or table load; - Queued I/Os in the multipath target succeed when resume is issued with the DM_NOFLUSH_FLAG ioctl option after table load. I/Os spanning 2 multipath targets also succeed. The following tests are for the error paths of the new pushback feature: - When the bdget_disk() fails in dm_suspend(), the DMF_NOFLUSH_SUSPENDING flag is cleared and I/Os already queued to the pushback list are flushed properly. - When suspend with the DM_NOFLUSH_FLAG ioctl option is interrupted, o I/Os which had already been queued to the pushback list at the time don't return, and are re-issued at resume time; o I/Os which hadn't been returned at the time return with EIO. Signed-off-by: Kiyoshi Ueda Signed-off-by: Jun'ichi Nomura Signed-off-by: Alasdair G Kergon Cc: dm-devel@redhat.com Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-bio-list.h | 14 ++++++ drivers/md/dm.c | 105 ++++++++++++++++++++++++++++++++++++++---- drivers/md/dm.h | 2 + include/linux/device-mapper.h | 3 ++ 4 files changed, 114 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h index bbf4615f0e30..da4349649f7f 100644 --- a/drivers/md/dm-bio-list.h +++ b/drivers/md/dm-bio-list.h @@ -44,6 +44,20 @@ static inline void bio_list_merge(struct bio_list *bl, struct bio_list *bl2) bl->tail = bl2->tail; } +static inline void bio_list_merge_head(struct bio_list *bl, + struct bio_list *bl2) +{ + if (!bl2->head) + return; + + if (bl->head) + bl2->tail->bi_next = bl->head; + else + bl->tail = bl2->tail; + + bl->head = bl2->head; +} + static inline struct bio *bio_list_pop(struct bio_list *bl) { struct bio *bio = bl->head; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index d8544e1a4c1f..fe7c56e10435 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -68,10 +68,12 @@ union map_info *dm_get_mapinfo(struct bio *bio) #define DMF_FROZEN 2 #define DMF_FREEING 3 #define DMF_DELETING 4 +#define DMF_NOFLUSH_SUSPENDING 5 struct mapped_device { struct rw_semaphore io_lock; struct semaphore suspend_lock; + spinlock_t pushback_lock; rwlock_t map_lock; atomic_t holders; atomic_t open_count; @@ -90,6 +92,7 @@ struct mapped_device { atomic_t pending; wait_queue_head_t wait; struct bio_list deferred; + struct bio_list pushback; /* * The current mapping. @@ -444,23 +447,50 @@ int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo) * you this clearly demarcated crap. *---------------------------------------------------------------*/ +static int __noflush_suspending(struct mapped_device *md) +{ + return test_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); +} + /* * Decrements the number of outstanding ios that a bio has been * cloned into, completing the original io if necc. */ static void dec_pending(struct dm_io *io, int error) { - if (error) + unsigned long flags; + + /* Push-back supersedes any I/O errors */ + if (error && !(io->error > 0 && __noflush_suspending(io->md))) io->error = error; if (atomic_dec_and_test(&io->io_count)) { + if (io->error == DM_ENDIO_REQUEUE) { + /* + * Target requested pushing back the I/O. + * This must be handled before the sleeper on + * suspend queue merges the pushback list. + */ + spin_lock_irqsave(&io->md->pushback_lock, flags); + if (__noflush_suspending(io->md)) + bio_list_add(&io->md->pushback, io->bio); + else + /* noflush suspend was interrupted. */ + io->error = -EIO; + spin_unlock_irqrestore(&io->md->pushback_lock, flags); + } + if (end_io_acct(io)) /* nudge anyone waiting on suspend queue */ wake_up(&io->md->wait); - blk_add_trace_bio(io->md->queue, io->bio, BLK_TA_COMPLETE); + if (io->error != DM_ENDIO_REQUEUE) { + blk_add_trace_bio(io->md->queue, io->bio, + BLK_TA_COMPLETE); + + bio_endio(io->bio, io->bio->bi_size, io->error); + } - bio_endio(io->bio, io->bio->bi_size, io->error); free_io(io->md, io); } } @@ -480,7 +510,11 @@ static int clone_endio(struct bio *bio, unsigned int done, int error) if (endio) { r = endio(tio->ti, bio, error, &tio->info); - if (r < 0) + if (r < 0 || r == DM_ENDIO_REQUEUE) + /* + * error and requeue request are handled + * in dec_pending(). + */ error = r; else if (r == DM_ENDIO_INCOMPLETE) /* The target will handle the io */ @@ -554,8 +588,8 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, clone->bi_sector); generic_make_request(clone); - } else if (r < 0) { - /* error the io and bail out */ + } else if (r < 0 || r == DM_MAPIO_REQUEUE) { + /* error the io and bail out, or requeue it if needed */ md = tio->io->md; dec_pending(tio->io, r); /* @@ -952,6 +986,7 @@ static struct mapped_device *alloc_dev(int minor) memset(md, 0, sizeof(*md)); init_rwsem(&md->io_lock); init_MUTEX(&md->suspend_lock); + spin_lock_init(&md->pushback_lock); rwlock_init(&md->map_lock); atomic_set(&md->holders, 1); atomic_set(&md->open_count, 0); @@ -1282,10 +1317,12 @@ static void unlock_fs(struct mapped_device *md) int dm_suspend(struct mapped_device *md, unsigned suspend_flags) { struct dm_table *map = NULL; + unsigned long flags; DECLARE_WAITQUEUE(wait, current); struct bio *def; int r = -EINVAL; int do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG ? 1 : 0; + int noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG ? 1 : 0; down(&md->suspend_lock); @@ -1294,6 +1331,13 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) map = dm_get_table(md); + /* + * DMF_NOFLUSH_SUSPENDING must be set before presuspend. + * This flag is cleared before dm_suspend returns. + */ + if (noflush) + set_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); + /* This does not get reverted if there's an error later. */ dm_table_presuspend_targets(map); @@ -1301,11 +1345,14 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) if (!md->suspended_bdev) { DMWARN("bdget failed in dm_suspend"); r = -ENOMEM; - goto out; + goto flush_and_out; } - /* Flush I/O to the device. */ - if (do_lockfs) { + /* + * Flush I/O to the device. + * noflush supersedes do_lockfs, because lock_fs() needs to flush I/Os. + */ + if (do_lockfs && !noflush) { r = lock_fs(md); if (r) goto out; @@ -1341,6 +1388,14 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) down_write(&md->io_lock); remove_wait_queue(&md->wait, &wait); + if (noflush) { + spin_lock_irqsave(&md->pushback_lock, flags); + clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); + bio_list_merge_head(&md->deferred, &md->pushback); + bio_list_init(&md->pushback); + spin_unlock_irqrestore(&md->pushback_lock, flags); + } + /* were we interrupted ? */ r = -EINTR; if (atomic_read(&md->pending)) { @@ -1349,7 +1404,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) __flush_deferred_io(md, def); up_write(&md->io_lock); unlock_fs(md); - goto out; + goto out; /* pushback list is already flushed, so skip flush */ } up_write(&md->io_lock); @@ -1359,6 +1414,25 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) r = 0; +flush_and_out: + if (r && noflush) { + /* + * Because there may be already I/Os in the pushback list, + * flush them before return. + */ + down_write(&md->io_lock); + + spin_lock_irqsave(&md->pushback_lock, flags); + clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); + bio_list_merge_head(&md->deferred, &md->pushback); + bio_list_init(&md->pushback); + spin_unlock_irqrestore(&md->pushback_lock, flags); + + def = bio_list_get(&md->deferred); + __flush_deferred_io(md, def); + up_write(&md->io_lock); + } + out: if (r && md->suspended_bdev) { bdput(md->suspended_bdev); @@ -1445,6 +1519,17 @@ int dm_suspended(struct mapped_device *md) return test_bit(DMF_SUSPENDED, &md->flags); } +int dm_noflush_suspending(struct dm_target *ti) +{ + struct mapped_device *md = dm_table_get_md(ti->table); + int r = __noflush_suspending(md); + + dm_put(md); + + return r; +} +EXPORT_SYMBOL_GPL(dm_noflush_suspending); + static struct block_device_operations dm_blk_dops = { .open = dm_blk_open, .release = dm_blk_close, diff --git a/drivers/md/dm.h b/drivers/md/dm.h index c307ca9a4c33..2f796b1436b2 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -36,12 +36,14 @@ * Definitions of return values from target end_io function. */ #define DM_ENDIO_INCOMPLETE 1 +#define DM_ENDIO_REQUEUE 2 /* * Definitions of return values from target map function. */ #define DM_MAPIO_SUBMITTED 0 #define DM_MAPIO_REMAPPED 1 +#define DM_MAPIO_REQUEUE DM_ENDIO_REQUEUE /* * Suspend feature flags diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 2e5c42346c38..499f5373e213 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -40,6 +40,7 @@ typedef void (*dm_dtr_fn) (struct dm_target *ti); * < 0: error * = 0: The target will handle the io by resubmitting it later * = 1: simple remap complete + * = 2: The target wants to push back the io */ typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio, union map_info *map_context); @@ -50,6 +51,7 @@ typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio, * 0 : ended successfully * 1 : for some reason the io has still not completed (eg, * multipath target might want to requeue a failed io). + * 2 : The target wants to push back the io */ typedef int (*dm_endio_fn) (struct dm_target *ti, struct bio *bio, int error, @@ -188,6 +190,7 @@ int dm_wait_event(struct mapped_device *md, int event_nr); const char *dm_device_name(struct mapped_device *md); struct gendisk *dm_disk(struct mapped_device *md); int dm_suspended(struct mapped_device *md); +int dm_noflush_suspending(struct dm_target *ti); /* * Geometry functions. -- cgit v1.2.3 From dde5845a529ff753364a6d1aea61180946270bfa Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:40:44 +0100 Subject: [PATCH] Generic HID layer - code split The "big main" split of USB HID code into generic HID code and USB-transport specific HID handling. Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 940 +++++++++++++++++++++++++++++++++++++ drivers/hid/hid-input.c | 840 +++++++++++++++++++++++++++++++++ drivers/usb/input/hid-core.c | 1039 ++++------------------------------------- drivers/usb/input/hid-debug.h | 757 ------------------------------ drivers/usb/input/hid-ff.c | 2 +- drivers/usb/input/hid-input.c | 844 +-------------------------------- drivers/usb/input/hid-lgff.c | 2 +- drivers/usb/input/hid-pidff.c | 4 +- drivers/usb/input/hid-tmff.c | 2 +- drivers/usb/input/hid-zpff.c | 2 +- drivers/usb/input/hid.h | 540 --------------------- drivers/usb/input/hiddev.c | 3 +- include/linux/hid-debug.h | 757 ++++++++++++++++++++++++++++++ include/linux/hid.h | 540 +++++++++++++++++++++ 14 files changed, 3183 insertions(+), 3089 deletions(-) create mode 100644 drivers/hid/hid-core.c create mode 100644 drivers/hid/hid-input.c delete mode 100644 drivers/usb/input/hid-debug.h delete mode 100644 drivers/usb/input/hid.h create mode 100644 include/linux/hid-debug.h create mode 100644 include/linux/hid.h (limited to 'include/linux') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c new file mode 100644 index 000000000000..689ae16adf33 --- /dev/null +++ b/drivers/hid/hid-core.c @@ -0,0 +1,940 @@ +/* + * USB HID support for Linux + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006 Jiri Kosina + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#undef DEBUG_DATA + +#include + +#include +#include + +/* + * Version Information + */ + +#define DRIVER_VERSION "v2.6" +#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik" +#define DRIVER_DESC "USB HID core driver" +#define DRIVER_LICENSE "GPL" + +/* + * Module parameters. + */ + +static unsigned int hid_mousepoll_interval; +module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); +MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); + +/* + * Register a new report for a device. + */ + +static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) +{ + struct hid_report_enum *report_enum = device->report_enum + type; + struct hid_report *report; + + if (report_enum->report_id_hash[id]) + return report_enum->report_id_hash[id]; + + if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL))) + return NULL; + + if (id != 0) + report_enum->numbered = 1; + + report->id = id; + report->type = type; + report->size = 0; + report->device = device; + report_enum->report_id_hash[id] = report; + + list_add_tail(&report->list, &report_enum->report_list); + + return report; +} + +/* + * Register a new field for this report. + */ + +static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) +{ + struct hid_field *field; + + if (report->maxfield == HID_MAX_FIELDS) { + dbg("too many fields in report"); + return NULL; + } + + if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + + values * sizeof(unsigned), GFP_KERNEL))) return NULL; + + field->index = report->maxfield++; + report->field[field->index] = field; + field->usage = (struct hid_usage *)(field + 1); + field->value = (unsigned *)(field->usage + usages); + field->report = report; + + return field; +} + +/* + * Open a collection. The type/usage is pushed on the stack. + */ + +static int open_collection(struct hid_parser *parser, unsigned type) +{ + struct hid_collection *collection; + unsigned usage; + + usage = parser->local.usage[0]; + + if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { + dbg("collection stack overflow"); + return -1; + } + + if (parser->device->maxcollection == parser->device->collection_size) { + collection = kmalloc(sizeof(struct hid_collection) * + parser->device->collection_size * 2, GFP_KERNEL); + if (collection == NULL) { + dbg("failed to reallocate collection array"); + return -1; + } + memcpy(collection, parser->device->collection, + sizeof(struct hid_collection) * + parser->device->collection_size); + memset(collection + parser->device->collection_size, 0, + sizeof(struct hid_collection) * + parser->device->collection_size); + kfree(parser->device->collection); + parser->device->collection = collection; + parser->device->collection_size *= 2; + } + + parser->collection_stack[parser->collection_stack_ptr++] = + parser->device->maxcollection; + + collection = parser->device->collection + + parser->device->maxcollection++; + collection->type = type; + collection->usage = usage; + collection->level = parser->collection_stack_ptr - 1; + + if (type == HID_COLLECTION_APPLICATION) + parser->device->maxapplication++; + + return 0; +} + +/* + * Close a collection. + */ + +static int close_collection(struct hid_parser *parser) +{ + if (!parser->collection_stack_ptr) { + dbg("collection stack underflow"); + return -1; + } + parser->collection_stack_ptr--; + return 0; +} + +/* + * Climb up the stack, search for the specified collection type + * and return the usage. + */ + +static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) +{ + int n; + for (n = parser->collection_stack_ptr - 1; n >= 0; n--) + if (parser->device->collection[parser->collection_stack[n]].type == type) + return parser->device->collection[parser->collection_stack[n]].usage; + return 0; /* we know nothing about this usage type */ +} + +/* + * Add a usage to the temporary parser table. + */ + +static int hid_add_usage(struct hid_parser *parser, unsigned usage) +{ + if (parser->local.usage_index >= HID_MAX_USAGES) { + dbg("usage index exceeded"); + return -1; + } + parser->local.usage[parser->local.usage_index] = usage; + parser->local.collection_index[parser->local.usage_index] = + parser->collection_stack_ptr ? + parser->collection_stack[parser->collection_stack_ptr - 1] : 0; + parser->local.usage_index++; + return 0; +} + +/* + * Register a new field for this report. + */ + +static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags) +{ + struct hid_report *report; + struct hid_field *field; + int usages; + unsigned offset; + int i; + + if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) { + dbg("hid_register_report failed"); + return -1; + } + + if (parser->global.logical_maximum < parser->global.logical_minimum) { + dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); + return -1; + } + + offset = report->size; + report->size += parser->global.report_size * parser->global.report_count; + + if (!parser->local.usage_index) /* Ignore padding fields */ + return 0; + + usages = max_t(int, parser->local.usage_index, parser->global.report_count); + + if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) + return 0; + + field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); + field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); + field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); + + for (i = 0; i < usages; i++) { + int j = i; + /* Duplicate the last usage we parsed if we have excess values */ + if (i >= parser->local.usage_index) + j = parser->local.usage_index - 1; + field->usage[i].hid = parser->local.usage[j]; + field->usage[i].collection_index = + parser->local.collection_index[j]; + } + + field->maxusage = usages; + field->flags = flags; + field->report_offset = offset; + field->report_type = report_type; + field->report_size = parser->global.report_size; + field->report_count = parser->global.report_count; + field->logical_minimum = parser->global.logical_minimum; + field->logical_maximum = parser->global.logical_maximum; + field->physical_minimum = parser->global.physical_minimum; + field->physical_maximum = parser->global.physical_maximum; + field->unit_exponent = parser->global.unit_exponent; + field->unit = parser->global.unit; + + return 0; +} + +/* + * Read data value from item. + */ + +static u32 item_udata(struct hid_item *item) +{ + switch (item->size) { + case 1: return item->data.u8; + case 2: return item->data.u16; + case 4: return item->data.u32; + } + return 0; +} + +static s32 item_sdata(struct hid_item *item) +{ + switch (item->size) { + case 1: return item->data.s8; + case 2: return item->data.s16; + case 4: return item->data.s32; + } + return 0; +} + +/* + * Process a global item. + */ + +static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) +{ + switch (item->tag) { + + case HID_GLOBAL_ITEM_TAG_PUSH: + + if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) { + dbg("global enviroment stack overflow"); + return -1; + } + + memcpy(parser->global_stack + parser->global_stack_ptr++, + &parser->global, sizeof(struct hid_global)); + return 0; + + case HID_GLOBAL_ITEM_TAG_POP: + + if (!parser->global_stack_ptr) { + dbg("global enviroment stack underflow"); + return -1; + } + + memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr, + sizeof(struct hid_global)); + return 0; + + case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: + parser->global.usage_page = item_udata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: + parser->global.logical_minimum = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: + if (parser->global.logical_minimum < 0) + parser->global.logical_maximum = item_sdata(item); + else + parser->global.logical_maximum = item_udata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: + parser->global.physical_minimum = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: + if (parser->global.physical_minimum < 0) + parser->global.physical_maximum = item_sdata(item); + else + parser->global.physical_maximum = item_udata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: + parser->global.unit_exponent = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_UNIT: + parser->global.unit = item_udata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: + if ((parser->global.report_size = item_udata(item)) > 32) { + dbg("invalid report_size %d", parser->global.report_size); + return -1; + } + return 0; + + case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: + if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) { + dbg("invalid report_count %d", parser->global.report_count); + return -1; + } + return 0; + + case HID_GLOBAL_ITEM_TAG_REPORT_ID: + if ((parser->global.report_id = item_udata(item)) == 0) { + dbg("report_id 0 is invalid"); + return -1; + } + return 0; + + default: + dbg("unknown global tag 0x%x", item->tag); + return -1; + } +} + +/* + * Process a local item. + */ + +static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) +{ + __u32 data; + unsigned n; + + if (item->size == 0) { + dbg("item data expected for local item"); + return -1; + } + + data = item_udata(item); + + switch (item->tag) { + + case HID_LOCAL_ITEM_TAG_DELIMITER: + + if (data) { + /* + * We treat items before the first delimiter + * as global to all usage sets (branch 0). + * In the moment we process only these global + * items and the first delimiter set. + */ + if (parser->local.delimiter_depth != 0) { + dbg("nested delimiters"); + return -1; + } + parser->local.delimiter_depth++; + parser->local.delimiter_branch++; + } else { + if (parser->local.delimiter_depth < 1) { + dbg("bogus close delimiter"); + return -1; + } + parser->local.delimiter_depth--; + } + return 1; + + case HID_LOCAL_ITEM_TAG_USAGE: + + if (parser->local.delimiter_branch > 1) { + dbg("alternative usage ignored"); + return 0; + } + + if (item->size <= 2) + data = (parser->global.usage_page << 16) + data; + + return hid_add_usage(parser, data); + + case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: + + if (parser->local.delimiter_branch > 1) { + dbg("alternative usage ignored"); + return 0; + } + + if (item->size <= 2) + data = (parser->global.usage_page << 16) + data; + + parser->local.usage_minimum = data; + return 0; + + case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: + + if (parser->local.delimiter_branch > 1) { + dbg("alternative usage ignored"); + return 0; + } + + if (item->size <= 2) + data = (parser->global.usage_page << 16) + data; + + for (n = parser->local.usage_minimum; n <= data; n++) + if (hid_add_usage(parser, n)) { + dbg("hid_add_usage failed\n"); + return -1; + } + return 0; + + default: + + dbg("unknown local item tag 0x%x", item->tag); + return 0; + } + return 0; +} + +/* + * Process a main item. + */ + +static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) +{ + __u32 data; + int ret; + + data = item_udata(item); + + switch (item->tag) { + case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: + ret = open_collection(parser, data & 0xff); + break; + case HID_MAIN_ITEM_TAG_END_COLLECTION: + ret = close_collection(parser); + break; + case HID_MAIN_ITEM_TAG_INPUT: + ret = hid_add_field(parser, HID_INPUT_REPORT, data); + break; + case HID_MAIN_ITEM_TAG_OUTPUT: + ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); + break; + case HID_MAIN_ITEM_TAG_FEATURE: + ret = hid_add_field(parser, HID_FEATURE_REPORT, data); + break; + default: + dbg("unknown main item tag 0x%x", item->tag); + ret = 0; + } + + memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ + + return ret; +} + +/* + * Process a reserved item. + */ + +static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) +{ + dbg("reserved item type, tag 0x%x", item->tag); + return 0; +} + +/* + * Free a report and all registered fields. The field->usage and + * field->value table's are allocated behind the field, so we need + * only to free(field) itself. + */ + +static void hid_free_report(struct hid_report *report) +{ + unsigned n; + + for (n = 0; n < report->maxfield; n++) + kfree(report->field[n]); + kfree(report); +} + +/* + * Free a device structure, all reports, and all fields. + */ + +static void hid_free_device(struct hid_device *device) +{ + unsigned i,j; + + for (i = 0; i < HID_REPORT_TYPES; i++) { + struct hid_report_enum *report_enum = device->report_enum + i; + + for (j = 0; j < 256; j++) { + struct hid_report *report = report_enum->report_id_hash[j]; + if (report) + hid_free_report(report); + } + } + + kfree(device->rdesc); + kfree(device); +} + +/* + * Fetch a report description item from the data stream. We support long + * items, though they are not used yet. + */ + +static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) +{ + u8 b; + + if ((end - start) <= 0) + return NULL; + + b = *start++; + + item->type = (b >> 2) & 3; + item->tag = (b >> 4) & 15; + + if (item->tag == HID_ITEM_TAG_LONG) { + + item->format = HID_ITEM_FORMAT_LONG; + + if ((end - start) < 2) + return NULL; + + item->size = *start++; + item->tag = *start++; + + if ((end - start) < item->size) + return NULL; + + item->data.longdata = start; + start += item->size; + return start; + } + + item->format = HID_ITEM_FORMAT_SHORT; + item->size = b & 3; + + switch (item->size) { + + case 0: + return start; + + case 1: + if ((end - start) < 1) + return NULL; + item->data.u8 = *start++; + return start; + + case 2: + if ((end - start) < 2) + return NULL; + item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start)); + start = (__u8 *)((__le16 *)start + 1); + return start; + + case 3: + item->size++; + if ((end - start) < 4) + return NULL; + item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start)); + start = (__u8 *)((__le32 *)start + 1); + return start; + } + + return NULL; +} + +/* + * Parse a report description into a hid_device structure. Reports are + * enumerated, fields are attached to these reports. + */ + +static struct hid_device *hid_parse_report(__u8 *start, unsigned size) +{ + struct hid_device *device; + struct hid_parser *parser; + struct hid_item item; + __u8 *end; + unsigned i; + static int (*dispatch_type[])(struct hid_parser *parser, + struct hid_item *item) = { + hid_parser_main, + hid_parser_global, + hid_parser_local, + hid_parser_reserved + }; + + if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL))) + return NULL; + + if (!(device->collection = kzalloc(sizeof(struct hid_collection) * + HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) { + kfree(device); + return NULL; + } + device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; + + for (i = 0; i < HID_REPORT_TYPES; i++) + INIT_LIST_HEAD(&device->report_enum[i].report_list); + + if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { + kfree(device->collection); + kfree(device); + return NULL; + } + memcpy(device->rdesc, start, size); + device->rsize = size; + + if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) { + kfree(device->rdesc); + kfree(device->collection); + kfree(device); + return NULL; + } + parser->device = device; + + end = start + size; + while ((start = fetch_item(start, end, &item)) != NULL) { + + if (item.format != HID_ITEM_FORMAT_SHORT) { + dbg("unexpected long global item"); + kfree(device->collection); + hid_free_device(device); + kfree(parser); + return NULL; + } + + if (dispatch_type[item.type](parser, &item)) { + dbg("item %u %u %u %u parsing failed\n", + item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); + kfree(device->collection); + hid_free_device(device); + kfree(parser); + return NULL; + } + + if (start == end) { + if (parser->collection_stack_ptr) { + dbg("unbalanced collection at end of report description"); + kfree(device->collection); + hid_free_device(device); + kfree(parser); + return NULL; + } + if (parser->local.delimiter_depth) { + dbg("unbalanced delimiter at end of report description"); + kfree(device->collection); + hid_free_device(device); + kfree(parser); + return NULL; + } + kfree(parser); + return device; + } + } + + dbg("item fetching failed at offset %d\n", (int)(end - start)); + kfree(device->collection); + hid_free_device(device); + kfree(parser); + return NULL; +} + +/* + * Convert a signed n-bit integer to signed 32-bit integer. Common + * cases are done through the compiler, the screwed things has to be + * done by hand. + */ + +static s32 snto32(__u32 value, unsigned n) +{ + switch (n) { + case 8: return ((__s8)value); + case 16: return ((__s16)value); + case 32: return ((__s32)value); + } + return value & (1 << (n - 1)) ? value | (-1 << n) : value; +} + +/* + * Convert a signed 32-bit integer to a signed n-bit integer. + */ + +static u32 s32ton(__s32 value, unsigned n) +{ + s32 a = value >> (n - 1); + if (a && a != -1) + return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; + return value & ((1 << n) - 1); +} + +/* + * Extract/implement a data field from/to a little endian report (bit array). + * + * Code sort-of follows HID spec: + * http://www.usb.org/developers/devclass_docs/HID1_11.pdf + * + * While the USB HID spec allows unlimited length bit fields in "report + * descriptors", most devices never use more than 16 bits. + * One model of UPS is claimed to report "LINEV" as a 32-bit field. + * Search linux-kernel and linux-usb-devel archives for "hid-core extract". + */ + +static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) +{ + u64 x; + + WARN_ON(n > 32); + + report += offset >> 3; /* adjust byte index */ + offset &= 7; /* now only need bit offset into one byte */ + x = get_unaligned((u64 *) report); + x = le64_to_cpu(x); + x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ + return (u32) x; +} + +/* + * "implement" : set bits in a little endian bit stream. + * Same concepts as "extract" (see comments above). + * The data mangled in the bit stream remains in little endian + * order the whole time. It make more sense to talk about + * endianness of register values by considering a register + * a "cached" copy of the little endiad bit stream. + */ +static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) +{ + u64 x; + u64 m = (1ULL << n) - 1; + + WARN_ON(n > 32); + + WARN_ON(value > m); + value &= m; + + report += offset >> 3; + offset &= 7; + + x = get_unaligned((u64 *)report); + x &= cpu_to_le64(~(m << offset)); + x |= cpu_to_le64(((u64) value) << offset); + put_unaligned(x, (u64 *) report); +} + +/* + * Search an array for a value. + */ + +static __inline__ int search(__s32 *array, __s32 value, unsigned n) +{ + while (n--) { + if (*array++ == value) + return 0; + } + return -1; +} + +static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt) +{ + hid_dump_input(usage, value); + if (hid->claimed & HID_CLAIMED_INPUT) + hidinput_hid_event(hid, field, usage, value); + if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt) + hiddev_hid_event(hid, field, usage, value); +} + +/* + * Analyse a received field, and fetch the data from it. The field + * content is stored for next report processing (we do differential + * reporting to the layer). + */ + +static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt) +{ + unsigned n; + unsigned count = field->report_count; + unsigned offset = field->report_offset; + unsigned size = field->report_size; + __s32 min = field->logical_minimum; + __s32 max = field->logical_maximum; + __s32 *value; + + if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC))) + return; + + for (n = 0; n < count; n++) { + + value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : + extract(data, offset + n * size, size); + + if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */ + && value[n] >= min && value[n] <= max + && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) + goto exit; + } + + for (n = 0; n < count; n++) { + + if (HID_MAIN_ITEM_VARIABLE & field->flags) { + hid_process_event(hid, field, &field->usage[n], value[n], interrupt); + continue; + } + + if (field->value[n] >= min && field->value[n] <= max + && field->usage[field->value[n] - min].hid + && search(value, field->value[n], count)) + hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); + + if (value[n] >= min && value[n] <= max + && field->usage[value[n] - min].hid + && search(field->value, value[n], count)) + hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); + } + + memcpy(field->value, value, count * sizeof(__s32)); +exit: + kfree(value); +} + + +/* + * Output the field into the report. + */ + +static void hid_output_field(struct hid_field *field, __u8 *data) +{ + unsigned count = field->report_count; + unsigned offset = field->report_offset; + unsigned size = field->report_size; + unsigned n; + + for (n = 0; n < count; n++) { + if (field->logical_minimum < 0) /* signed values */ + implement(data, offset + n * size, size, s32ton(field->value[n], size)); + else /* unsigned values */ + implement(data, offset + n * size, size, field->value[n]); + } +} + +/* + * Create a report. + */ + +static void hid_output_report(struct hid_report *report, __u8 *data) +{ + unsigned n; + + if (report->id > 0) + *data++ = report->id; + + for (n = 0; n < report->maxfield; n++) + hid_output_field(report->field[n], data); +} + +/* + * Set a field value. The report this field belongs to has to be + * created and transferred to the device, to set this value in the + * device. + */ + +int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) +{ + unsigned size = field->report_size; + + hid_dump_input(field->usage + offset, value); + + if (offset >= field->report_count) { + dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count); + hid_dump_field(field, 8); + return -1; + } + if (field->logical_minimum < 0) { + if (value != snto32(s32ton(value, size), size)) { + dbg("value %d is out of range", value); + return -1; + } + } + field->value[offset] = value; + return 0; +} + diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c new file mode 100644 index 000000000000..d459005062e0 --- /dev/null +++ b/drivers/hid/hid-input.c @@ -0,0 +1,840 @@ +/* + * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2006 Jiri Kosina + * + * HID to Linux Input mapping + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include + +#undef DEBUG + +#include + +#define unk KEY_UNKNOWN + +static const unsigned char hid_keyboard[256] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, + 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, + 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, + 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, + 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk +}; + +static const struct { + __s32 x; + __s32 y; +} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + +#define map_abs(c) do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0) +#define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0) +#define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0) +#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0) + +#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) +#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) + +#ifdef CONFIG_USB_HIDINPUT_POWERBOOK + +struct hidinput_key_translation { + u16 from; + u16 to; + u8 flags; +}; + +#define POWERBOOK_FLAG_FKEY 0x01 + +static struct hidinput_key_translation powerbook_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY }, + { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY }, + { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY }, + { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY }, + { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY }, + { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY }, + { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY }, + { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY }, + { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + +static struct hidinput_key_translation powerbook_numlock_keys[] = { + { KEY_J, KEY_KP1 }, + { KEY_K, KEY_KP2 }, + { KEY_L, KEY_KP3 }, + { KEY_U, KEY_KP4 }, + { KEY_I, KEY_KP5 }, + { KEY_O, KEY_KP6 }, + { KEY_7, KEY_KP7 }, + { KEY_8, KEY_KP8 }, + { KEY_9, KEY_KP9 }, + { KEY_M, KEY_KP0 }, + { KEY_DOT, KEY_KPDOT }, + { KEY_SLASH, KEY_KPPLUS }, + { KEY_SEMICOLON, KEY_KPMINUS }, + { KEY_P, KEY_KPASTERISK }, + { KEY_MINUS, KEY_KPEQUAL }, + { KEY_0, KEY_KPSLASH }, + { KEY_F6, KEY_NUMLOCK }, + { KEY_KPENTER, KEY_KPENTER }, + { KEY_BACKSPACE, KEY_BACKSPACE }, + { } +}; + +static struct hidinput_key_translation powerbook_iso_keyboard[] = { + { KEY_GRAVE, KEY_102ND }, + { KEY_102ND, KEY_GRAVE }, + { } +}; + + +static int usbhid_pb_fnmode = 1; +module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); +MODULE_PARM_DESC(pb_fnmode, + "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); + +static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from) +{ + struct hidinput_key_translation *trans; + + /* Look for the translation */ + for (trans = table; trans->from; trans++) + if (trans->from == from) + return trans; + + return NULL; +} + +static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, + struct hid_usage *usage, __s32 value) +{ + struct hidinput_key_translation *trans; + + if (usage->code == KEY_FN) { + if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON; + else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON; + + input_event(input, usage->type, usage->code, value); + + return 1; + } + + if (usbhid_pb_fnmode) { + int do_translate; + + trans = find_translation(powerbook_fn_keys, usage->code); + if (trans) { + if (test_bit(usage->code, hid->pb_pressed_fn)) + do_translate = 1; + else if (trans->flags & POWERBOOK_FLAG_FKEY) + do_translate = + (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) || + (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)); + else + do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON); + + if (do_translate) { + if (value) + set_bit(usage->code, hid->pb_pressed_fn); + else + clear_bit(usage->code, hid->pb_pressed_fn); + + input_event(input, usage->type, trans->to, value); + + return 1; + } + } + + if (test_bit(usage->code, hid->pb_pressed_numlock) || + test_bit(LED_NUML, input->led)) { + trans = find_translation(powerbook_numlock_keys, usage->code); + + if (trans) { + if (value) + set_bit(usage->code, hid->pb_pressed_numlock); + else + clear_bit(usage->code, hid->pb_pressed_numlock); + + input_event(input, usage->type, trans->to, value); + } + + return 1; + } + } + + if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) { + trans = find_translation(powerbook_iso_keyboard, usage->code); + if (trans) { + input_event(input, usage->type, trans->to, value); + return 1; + } + } + + return 0; +} + +static void hidinput_pb_setup(struct input_dev *input) +{ + struct hidinput_key_translation *trans; + + set_bit(KEY_NUMLOCK, input->keybit); + + /* Enable all needed keys */ + for (trans = powerbook_fn_keys; trans->from; trans++) + set_bit(trans->to, input->keybit); + + for (trans = powerbook_numlock_keys; trans->from; trans++) + set_bit(trans->to, input->keybit); + + for (trans = powerbook_iso_keyboard; trans->from; trans++) + set_bit(trans->to, input->keybit); + +} +#else +static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, + struct hid_usage *usage, __s32 value) +{ + return 0; +} + +static inline void hidinput_pb_setup(struct input_dev *input) +{ +} +#endif + +static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, + struct hid_usage *usage) +{ + struct input_dev *input = hidinput->input; + struct hid_device *device = input->private; + int max = 0, code; + unsigned long *bit = NULL; + + field->hidinput = hidinput; + +#ifdef DEBUG + printk(KERN_DEBUG "Mapping: "); + resolv_usage(usage->hid); + printk(" ---> "); +#endif + + if (field->flags & HID_MAIN_ITEM_CONSTANT) + goto ignore; + + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_UNDEFINED: + goto ignore; + + case HID_UP_KEYBOARD: + + set_bit(EV_REP, input->evbit); + + if ((usage->hid & HID_USAGE) < 256) { + if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore; + map_key_clear(hid_keyboard[usage->hid & HID_USAGE]); + } else + map_key(KEY_UNKNOWN); + + break; + + case HID_UP_BUTTON: + + code = ((usage->hid - 1) & 0xf); + + switch (field->application) { + case HID_GD_MOUSE: + case HID_GD_POINTER: code += 0x110; break; + case HID_GD_JOYSTICK: code += 0x120; break; + case HID_GD_GAMEPAD: code += 0x130; break; + default: + switch (field->physical) { + case HID_GD_MOUSE: + case HID_GD_POINTER: code += 0x110; break; + case HID_GD_JOYSTICK: code += 0x120; break; + case HID_GD_GAMEPAD: code += 0x130; break; + default: code += 0x100; + } + } + + map_key(code); + break; + + + case HID_UP_SIMULATION: + + switch (usage->hid & 0xffff) { + case 0xba: map_abs(ABS_RUDDER); break; + case 0xbb: map_abs(ABS_THROTTLE); break; + case 0xc4: map_abs(ABS_GAS); break; + case 0xc5: map_abs(ABS_BRAKE); break; + case 0xc8: map_abs(ABS_WHEEL); break; + default: goto ignore; + } + break; + + case HID_UP_GENDESK: + + if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */ + switch (usage->hid & 0xf) { + case 0x1: map_key_clear(KEY_POWER); break; + case 0x2: map_key_clear(KEY_SLEEP); break; + case 0x3: map_key_clear(KEY_WAKEUP); break; + default: goto unknown; + } + break; + } + + if ((usage->hid & 0xf0) == 0x90) { /* D-pad */ + switch (usage->hid) { + case HID_GD_UP: usage->hat_dir = 1; break; + case HID_GD_DOWN: usage->hat_dir = 5; break; + case HID_GD_RIGHT: usage->hat_dir = 3; break; + case HID_GD_LEFT: usage->hat_dir = 7; break; + default: goto unknown; + } + if (field->dpad) { + map_abs(field->dpad); + goto ignore; + } + map_abs(ABS_HAT0X); + break; + } + + switch (usage->hid) { + + /* These usage IDs map directly to the usage codes. */ + case HID_GD_X: case HID_GD_Y: case HID_GD_Z: + case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: + case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: + if (field->flags & HID_MAIN_ITEM_RELATIVE) + map_rel(usage->hid & 0xf); + else + map_abs(usage->hid & 0xf); + break; + + case HID_GD_HATSWITCH: + usage->hat_min = field->logical_minimum; + usage->hat_max = field->logical_maximum; + map_abs(ABS_HAT0X); + break; + + case HID_GD_START: map_key_clear(BTN_START); break; + case HID_GD_SELECT: map_key_clear(BTN_SELECT); break; + + default: goto unknown; + } + + break; + + case HID_UP_LED: + if (((usage->hid - 1) & 0xffff) >= LED_MAX) + goto ignore; + map_led((usage->hid - 1) & 0xffff); + break; + + case HID_UP_DIGITIZER: + + switch (usage->hid & 0xff) { + + case 0x30: /* TipPressure */ + if (!test_bit(BTN_TOUCH, input->keybit)) { + device->quirks |= HID_QUIRK_NOTOUCH; + set_bit(EV_KEY, input->evbit); + set_bit(BTN_TOUCH, input->keybit); + } + + map_abs_clear(ABS_PRESSURE); + break; + + case 0x32: /* InRange */ + switch (field->physical & 0xff) { + case 0x21: map_key(BTN_TOOL_MOUSE); break; + case 0x22: map_key(BTN_TOOL_FINGER); break; + default: map_key(BTN_TOOL_PEN); break; + } + break; + + case 0x3c: /* Invert */ + map_key_clear(BTN_TOOL_RUBBER); + break; + + case 0x33: /* Touch */ + case 0x42: /* TipSwitch */ + case 0x43: /* TipSwitch2 */ + device->quirks &= ~HID_QUIRK_NOTOUCH; + map_key_clear(BTN_TOUCH); + break; + + case 0x44: /* BarrelSwitch */ + map_key_clear(BTN_STYLUS); + break; + + default: goto unknown; + } + break; + + case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ + + switch (usage->hid & HID_USAGE) { + case 0x000: goto ignore; + case 0x034: map_key_clear(KEY_SLEEP); break; + case 0x036: map_key_clear(BTN_MISC); break; + case 0x045: map_key_clear(KEY_RADIO); break; + case 0x08a: map_key_clear(KEY_WWW); break; + case 0x08d: map_key_clear(KEY_PROGRAM); break; + case 0x095: map_key_clear(KEY_HELP); break; + case 0x09c: map_key_clear(KEY_CHANNELUP); break; + case 0x09d: map_key_clear(KEY_CHANNELDOWN); break; + case 0x0b0: map_key_clear(KEY_PLAY); break; + case 0x0b1: map_key_clear(KEY_PAUSE); break; + case 0x0b2: map_key_clear(KEY_RECORD); break; + case 0x0b3: map_key_clear(KEY_FASTFORWARD); break; + case 0x0b4: map_key_clear(KEY_REWIND); break; + case 0x0b5: map_key_clear(KEY_NEXTSONG); break; + case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break; + case 0x0b7: map_key_clear(KEY_STOPCD); break; + case 0x0b8: map_key_clear(KEY_EJECTCD); break; + case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; + case 0x0e0: map_abs_clear(ABS_VOLUME); break; + case 0x0e2: map_key_clear(KEY_MUTE); break; + case 0x0e5: map_key_clear(KEY_BASSBOOST); break; + case 0x0e9: map_key_clear(KEY_VOLUMEUP); break; + case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; + case 0x183: map_key_clear(KEY_CONFIG); break; + case 0x18a: map_key_clear(KEY_MAIL); break; + case 0x192: map_key_clear(KEY_CALC); break; + case 0x194: map_key_clear(KEY_FILE); break; + case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; + case 0x201: map_key_clear(KEY_NEW); break; + case 0x207: map_key_clear(KEY_SAVE); break; + case 0x208: map_key_clear(KEY_PRINT); break; + case 0x209: map_key_clear(KEY_PROPS); break; + case 0x21a: map_key_clear(KEY_UNDO); break; + case 0x21b: map_key_clear(KEY_COPY); break; + case 0x21c: map_key_clear(KEY_CUT); break; + case 0x21d: map_key_clear(KEY_PASTE); break; + case 0x221: map_key_clear(KEY_FIND); break; + case 0x223: map_key_clear(KEY_HOMEPAGE); break; + case 0x224: map_key_clear(KEY_BACK); break; + case 0x225: map_key_clear(KEY_FORWARD); break; + case 0x226: map_key_clear(KEY_STOP); break; + case 0x227: map_key_clear(KEY_REFRESH); break; + case 0x22a: map_key_clear(KEY_BOOKMARKS); break; + case 0x233: map_key_clear(KEY_SCROLLUP); break; + case 0x234: map_key_clear(KEY_SCROLLDOWN); break; + case 0x238: map_rel(REL_HWHEEL); break; + case 0x279: map_key_clear(KEY_REDO); break; + case 0x289: map_key_clear(KEY_REPLY); break; + case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; + case 0x28c: map_key_clear(KEY_SEND); break; + + /* Reported on a Cherry Cymotion keyboard */ + case 0x301: map_key_clear(KEY_PROG1); break; + case 0x302: map_key_clear(KEY_PROG2); break; + case 0x303: map_key_clear(KEY_PROG3); break; + + default: goto ignore; + } + break; + + case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ + + set_bit(EV_REP, input->evbit); + switch (usage->hid & HID_USAGE) { + case 0x021: map_key_clear(KEY_PRINT); break; + case 0x070: map_key_clear(KEY_HP); break; + case 0x071: map_key_clear(KEY_CAMERA); break; + case 0x072: map_key_clear(KEY_SOUND); break; + case 0x073: map_key_clear(KEY_QUESTION); break; + case 0x080: map_key_clear(KEY_EMAIL); break; + case 0x081: map_key_clear(KEY_CHAT); break; + case 0x082: map_key_clear(KEY_SEARCH); break; + case 0x083: map_key_clear(KEY_CONNECT); break; + case 0x084: map_key_clear(KEY_FINANCE); break; + case 0x085: map_key_clear(KEY_SPORT); break; + case 0x086: map_key_clear(KEY_SHOP); break; + default: goto ignore; + } + break; + + case HID_UP_MSVENDOR: + goto ignore; + + case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */ + + set_bit(EV_REP, input->evbit); + switch(usage->hid & HID_USAGE) { + case 0x003: + /* The fn key on Apple PowerBooks */ + map_key_clear(KEY_FN); + hidinput_pb_setup(input); + break; + + default: goto ignore; + } + break; + + case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */ + + set_bit(EV_REP, input->evbit); + switch(usage->hid & HID_USAGE) { + case 0x004: map_key_clear(KEY_AGAIN); break; + case 0x00d: map_key_clear(KEY_HOME); break; + case 0x024: map_key_clear(KEY_SHUFFLE); break; + case 0x025: map_key_clear(KEY_TV); break; + case 0x026: map_key_clear(KEY_MENU); break; + case 0x031: map_key_clear(KEY_AUDIO); break; + case 0x032: map_key_clear(KEY_TEXT); break; + case 0x033: map_key_clear(KEY_LAST); break; + case 0x047: map_key_clear(KEY_MP3); break; + case 0x048: map_key_clear(KEY_DVD); break; + case 0x049: map_key_clear(KEY_MEDIA); break; + case 0x04a: map_key_clear(KEY_VIDEO); break; + case 0x04b: map_key_clear(KEY_ANGLE); break; + case 0x04c: map_key_clear(KEY_LANGUAGE); break; + case 0x04d: map_key_clear(KEY_SUBTITLE); break; + case 0x051: map_key_clear(KEY_RED); break; + case 0x052: map_key_clear(KEY_CLOSE); break; + default: goto ignore; + } + break; + + case HID_UP_PID: + + switch(usage->hid & HID_USAGE) { + case 0xa4: map_key_clear(BTN_DEAD); break; + default: goto ignore; + } + break; + + default: + unknown: + if (field->report_size == 1) { + if (field->report->type == HID_OUTPUT_REPORT) { + map_led(LED_MISC); + break; + } + map_key(BTN_MISC); + break; + } + if (field->flags & HID_MAIN_ITEM_RELATIVE) { + map_rel(REL_MISC); + break; + } + map_abs(ABS_MISC); + break; + } + + if (device->quirks & HID_QUIRK_MIGHTYMOUSE) { + if (usage->hid == HID_GD_Z) + map_rel(REL_HWHEEL); + else if (usage->code == BTN_1) + map_key(BTN_2); + else if (usage->code == BTN_2) + map_key(BTN_1); + } + + if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && + (usage->type == EV_REL) && (usage->code == REL_WHEEL)) + set_bit(REL_HWHEEL, bit); + + if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) + || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) + goto ignore; + + if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) && + usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE)) + field->flags &= ~HID_MAIN_ITEM_RELATIVE; + + set_bit(usage->type, input->evbit); + + while (usage->code <= max && test_and_set_bit(usage->code, bit)) + usage->code = find_next_zero_bit(bit, max + 1, usage->code); + + if (usage->code > max) + goto ignore; + + + if (usage->type == EV_ABS) { + + int a = field->logical_minimum; + int b = field->logical_maximum; + + if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) { + a = field->logical_minimum = 0; + b = field->logical_maximum = 255; + } + + if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK) + input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4); + else input_set_abs_params(input, usage->code, a, b, 0, 0); + + } + + if (usage->type == EV_ABS && + (usage->hat_min < usage->hat_max || usage->hat_dir)) { + int i; + for (i = usage->code; i < usage->code + 2 && i <= max; i++) { + input_set_abs_params(input, i, -1, 1, 0, 0); + set_bit(i, input->absbit); + } + if (usage->hat_dir && !field->dpad) + field->dpad = usage->code; + } + +#ifdef DEBUG + resolv_event(usage->type, usage->code); + printk("\n"); +#endif + return; + +ignore: +#ifdef DEBUG + printk("IGNORED\n"); +#endif + return; +} + +void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) +{ + struct input_dev *input; + int *quirks = &hid->quirks; + + if (!field->hidinput) + return; + + input = field->hidinput->input; + + if (!usage->type) + return; + + if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) + || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) { + if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; + else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; + return; + } + + if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) { + input_event(input, usage->type, usage->code, -value); + return; + } + + if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { + input_event(input, usage->type, REL_HWHEEL, value); + return; + } + + if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value)) + return; + + if (usage->hat_min < usage->hat_max || usage->hat_dir) { + int hat_dir = usage->hat_dir; + if (!hat_dir) + hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; + if (hat_dir < 0 || hat_dir > 8) hat_dir = 0; + input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x); + input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y); + return; + } + + if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */ + *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); + return; + } + + if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */ + if (value) { + input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); + return; + } + input_event(input, usage->type, usage->code, 0); + input_event(input, usage->type, BTN_TOOL_RUBBER, 0); + return; + } + + if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */ + int a = field->logical_minimum; + int b = field->logical_maximum; + input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); + } + + if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ + dbg("Maximum Effects - %d",value); + return; + } + + if (usage->hid == (HID_UP_PID | 0x7fUL)) { + dbg("PID Pool Report\n"); + return; + } + + if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ + return; + + input_event(input, usage->type, usage->code, value); + + if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) + input_event(input, usage->type, usage->code, 0); +} + +void hidinput_report_event(struct hid_device *hid, struct hid_report *report) +{ + struct hid_input *hidinput; + + list_for_each_entry(hidinput, &hid->inputs, list) + input_sync(hidinput->input); +} + +static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) +{ + struct hid_report *report; + int i, j; + + list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) { + for (i = 0; i < report->maxfield; i++) { + *field = report->field[i]; + for (j = 0; j < (*field)->maxusage; j++) + if ((*field)->usage[j].type == type && (*field)->usage[j].code == code) + return j; + } + } + return -1; +} + +/* + * Register the input device; print a message. + * Configure the input layer interface + * Read all reports and initialize the absolute field values. + */ + +int hidinput_connect(struct hid_device *hid) +{ + struct usb_device *dev = hid->dev; + struct hid_report *report; + struct hid_input *hidinput = NULL; + struct input_dev *input_dev; + int i, j, k; + + INIT_LIST_HEAD(&hid->inputs); + + for (i = 0; i < hid->maxcollection; i++) + if (hid->collection[i].type == HID_COLLECTION_APPLICATION || + hid->collection[i].type == HID_COLLECTION_PHYSICAL) + if (IS_INPUT_APPLICATION(hid->collection[i].usage)) + break; + + if (i == hid->maxcollection) + return -1; + + for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) + list_for_each_entry(report, &hid->report_enum[k].report_list, list) { + + if (!report->maxfield) + continue; + + if (!hidinput) { + hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!hidinput || !input_dev) { + kfree(hidinput); + input_free_device(input_dev); + err("Out of memory during hid input probe"); + return -1; + } + + input_dev->private = hid; + input_dev->event = hidinput_input_event; + input_dev->open = hidinput_open; + input_dev->close = hidinput_close; + + input_dev->name = hid->name; + input_dev->phys = hid->phys; + input_dev->uniq = hid->uniq; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &hid->intf->dev; + + hidinput->input = input_dev; + list_add_tail(&hidinput->list, &hid->inputs); + } + + for (i = 0; i < report->maxfield; i++) + for (j = 0; j < report->field[i]->maxusage; j++) + hidinput_configure_usage(hidinput, report->field[i], + report->field[i]->usage + j); + + if (hid->quirks & HID_QUIRK_MULTI_INPUT) { + /* This will leave hidinput NULL, so that it + * allocates another one if we have more inputs on + * the same interface. Some devices (e.g. Happ's + * UGCI) cram a lot of unrelated inputs into the + * same interface. */ + hidinput->report = report; + input_register_device(hidinput->input); + hidinput = NULL; + } + } + + /* This only gets called when we are a single-input (most of the + * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is + * only useful in this case, and not for multi-input quirks. */ + if (hidinput) { + hid_ff_init(hid); + input_register_device(hidinput->input); + } + + return 0; +} + +void hidinput_disconnect(struct hid_device *hid) +{ + struct hid_input *hidinput, *next; + + list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { + list_del(&hidinput->list); + input_unregister_device(hidinput->input); + kfree(hidinput); + } +} diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 0811c39bd14f..06e169b6a17e 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -4,6 +4,7 @@ * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2005 Vojtech Pavlik * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006 Jiri Kosina */ /* @@ -32,7 +33,7 @@ #include -#include "hid.h" +#include #include /* @@ -54,887 +55,6 @@ static unsigned int hid_mousepoll_interval; module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); -/* - * Register a new report for a device. - */ - -static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) -{ - struct hid_report_enum *report_enum = device->report_enum + type; - struct hid_report *report; - - if (report_enum->report_id_hash[id]) - return report_enum->report_id_hash[id]; - - if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL))) - return NULL; - - if (id != 0) - report_enum->numbered = 1; - - report->id = id; - report->type = type; - report->size = 0; - report->device = device; - report_enum->report_id_hash[id] = report; - - list_add_tail(&report->list, &report_enum->report_list); - - return report; -} - -/* - * Register a new field for this report. - */ - -static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) -{ - struct hid_field *field; - - if (report->maxfield == HID_MAX_FIELDS) { - dbg("too many fields in report"); - return NULL; - } - - if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) - + values * sizeof(unsigned), GFP_KERNEL))) return NULL; - - field->index = report->maxfield++; - report->field[field->index] = field; - field->usage = (struct hid_usage *)(field + 1); - field->value = (unsigned *)(field->usage + usages); - field->report = report; - - return field; -} - -/* - * Open a collection. The type/usage is pushed on the stack. - */ - -static int open_collection(struct hid_parser *parser, unsigned type) -{ - struct hid_collection *collection; - unsigned usage; - - usage = parser->local.usage[0]; - - if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { - dbg("collection stack overflow"); - return -1; - } - - if (parser->device->maxcollection == parser->device->collection_size) { - collection = kmalloc(sizeof(struct hid_collection) * - parser->device->collection_size * 2, GFP_KERNEL); - if (collection == NULL) { - dbg("failed to reallocate collection array"); - return -1; - } - memcpy(collection, parser->device->collection, - sizeof(struct hid_collection) * - parser->device->collection_size); - memset(collection + parser->device->collection_size, 0, - sizeof(struct hid_collection) * - parser->device->collection_size); - kfree(parser->device->collection); - parser->device->collection = collection; - parser->device->collection_size *= 2; - } - - parser->collection_stack[parser->collection_stack_ptr++] = - parser->device->maxcollection; - - collection = parser->device->collection + - parser->device->maxcollection++; - collection->type = type; - collection->usage = usage; - collection->level = parser->collection_stack_ptr - 1; - - if (type == HID_COLLECTION_APPLICATION) - parser->device->maxapplication++; - - return 0; -} - -/* - * Close a collection. - */ - -static int close_collection(struct hid_parser *parser) -{ - if (!parser->collection_stack_ptr) { - dbg("collection stack underflow"); - return -1; - } - parser->collection_stack_ptr--; - return 0; -} - -/* - * Climb up the stack, search for the specified collection type - * and return the usage. - */ - -static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) -{ - int n; - for (n = parser->collection_stack_ptr - 1; n >= 0; n--) - if (parser->device->collection[parser->collection_stack[n]].type == type) - return parser->device->collection[parser->collection_stack[n]].usage; - return 0; /* we know nothing about this usage type */ -} - -/* - * Add a usage to the temporary parser table. - */ - -static int hid_add_usage(struct hid_parser *parser, unsigned usage) -{ - if (parser->local.usage_index >= HID_MAX_USAGES) { - dbg("usage index exceeded"); - return -1; - } - parser->local.usage[parser->local.usage_index] = usage; - parser->local.collection_index[parser->local.usage_index] = - parser->collection_stack_ptr ? - parser->collection_stack[parser->collection_stack_ptr - 1] : 0; - parser->local.usage_index++; - return 0; -} - -/* - * Register a new field for this report. - */ - -static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags) -{ - struct hid_report *report; - struct hid_field *field; - int usages; - unsigned offset; - int i; - - if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) { - dbg("hid_register_report failed"); - return -1; - } - - if (parser->global.logical_maximum < parser->global.logical_minimum) { - dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); - return -1; - } - - offset = report->size; - report->size += parser->global.report_size * parser->global.report_count; - - if (!parser->local.usage_index) /* Ignore padding fields */ - return 0; - - usages = max_t(int, parser->local.usage_index, parser->global.report_count); - - if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) - return 0; - - field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); - field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); - field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); - - for (i = 0; i < usages; i++) { - int j = i; - /* Duplicate the last usage we parsed if we have excess values */ - if (i >= parser->local.usage_index) - j = parser->local.usage_index - 1; - field->usage[i].hid = parser->local.usage[j]; - field->usage[i].collection_index = - parser->local.collection_index[j]; - } - - field->maxusage = usages; - field->flags = flags; - field->report_offset = offset; - field->report_type = report_type; - field->report_size = parser->global.report_size; - field->report_count = parser->global.report_count; - field->logical_minimum = parser->global.logical_minimum; - field->logical_maximum = parser->global.logical_maximum; - field->physical_minimum = parser->global.physical_minimum; - field->physical_maximum = parser->global.physical_maximum; - field->unit_exponent = parser->global.unit_exponent; - field->unit = parser->global.unit; - - return 0; -} - -/* - * Read data value from item. - */ - -static u32 item_udata(struct hid_item *item) -{ - switch (item->size) { - case 1: return item->data.u8; - case 2: return item->data.u16; - case 4: return item->data.u32; - } - return 0; -} - -static s32 item_sdata(struct hid_item *item) -{ - switch (item->size) { - case 1: return item->data.s8; - case 2: return item->data.s16; - case 4: return item->data.s32; - } - return 0; -} - -/* - * Process a global item. - */ - -static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) -{ - switch (item->tag) { - - case HID_GLOBAL_ITEM_TAG_PUSH: - - if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) { - dbg("global enviroment stack overflow"); - return -1; - } - - memcpy(parser->global_stack + parser->global_stack_ptr++, - &parser->global, sizeof(struct hid_global)); - return 0; - - case HID_GLOBAL_ITEM_TAG_POP: - - if (!parser->global_stack_ptr) { - dbg("global enviroment stack underflow"); - return -1; - } - - memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr, - sizeof(struct hid_global)); - return 0; - - case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: - parser->global.usage_page = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: - parser->global.logical_minimum = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: - if (parser->global.logical_minimum < 0) - parser->global.logical_maximum = item_sdata(item); - else - parser->global.logical_maximum = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: - parser->global.physical_minimum = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: - if (parser->global.physical_minimum < 0) - parser->global.physical_maximum = item_sdata(item); - else - parser->global.physical_maximum = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: - parser->global.unit_exponent = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_UNIT: - parser->global.unit = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: - if ((parser->global.report_size = item_udata(item)) > 32) { - dbg("invalid report_size %d", parser->global.report_size); - return -1; - } - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: - if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) { - dbg("invalid report_count %d", parser->global.report_count); - return -1; - } - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_ID: - if ((parser->global.report_id = item_udata(item)) == 0) { - dbg("report_id 0 is invalid"); - return -1; - } - return 0; - - default: - dbg("unknown global tag 0x%x", item->tag); - return -1; - } -} - -/* - * Process a local item. - */ - -static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - unsigned n; - - if (item->size == 0) { - dbg("item data expected for local item"); - return -1; - } - - data = item_udata(item); - - switch (item->tag) { - - case HID_LOCAL_ITEM_TAG_DELIMITER: - - if (data) { - /* - * We treat items before the first delimiter - * as global to all usage sets (branch 0). - * In the moment we process only these global - * items and the first delimiter set. - */ - if (parser->local.delimiter_depth != 0) { - dbg("nested delimiters"); - return -1; - } - parser->local.delimiter_depth++; - parser->local.delimiter_branch++; - } else { - if (parser->local.delimiter_depth < 1) { - dbg("bogus close delimiter"); - return -1; - } - parser->local.delimiter_depth--; - } - return 1; - - case HID_LOCAL_ITEM_TAG_USAGE: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - return hid_add_usage(parser, data); - - case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - parser->local.usage_minimum = data; - return 0; - - case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - for (n = parser->local.usage_minimum; n <= data; n++) - if (hid_add_usage(parser, n)) { - dbg("hid_add_usage failed\n"); - return -1; - } - return 0; - - default: - - dbg("unknown local item tag 0x%x", item->tag); - return 0; - } - return 0; -} - -/* - * Process a main item. - */ - -static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - int ret; - - data = item_udata(item); - - switch (item->tag) { - case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: - ret = open_collection(parser, data & 0xff); - break; - case HID_MAIN_ITEM_TAG_END_COLLECTION: - ret = close_collection(parser); - break; - case HID_MAIN_ITEM_TAG_INPUT: - ret = hid_add_field(parser, HID_INPUT_REPORT, data); - break; - case HID_MAIN_ITEM_TAG_OUTPUT: - ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); - break; - case HID_MAIN_ITEM_TAG_FEATURE: - ret = hid_add_field(parser, HID_FEATURE_REPORT, data); - break; - default: - dbg("unknown main item tag 0x%x", item->tag); - ret = 0; - } - - memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ - - return ret; -} - -/* - * Process a reserved item. - */ - -static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) -{ - dbg("reserved item type, tag 0x%x", item->tag); - return 0; -} - -/* - * Free a report and all registered fields. The field->usage and - * field->value table's are allocated behind the field, so we need - * only to free(field) itself. - */ - -static void hid_free_report(struct hid_report *report) -{ - unsigned n; - - for (n = 0; n < report->maxfield; n++) - kfree(report->field[n]); - kfree(report); -} - -/* - * Free a device structure, all reports, and all fields. - */ - -static void hid_free_device(struct hid_device *device) -{ - unsigned i,j; - - for (i = 0; i < HID_REPORT_TYPES; i++) { - struct hid_report_enum *report_enum = device->report_enum + i; - - for (j = 0; j < 256; j++) { - struct hid_report *report = report_enum->report_id_hash[j]; - if (report) - hid_free_report(report); - } - } - - kfree(device->rdesc); - kfree(device); -} - -/* - * Fetch a report description item from the data stream. We support long - * items, though they are not used yet. - */ - -static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) -{ - u8 b; - - if ((end - start) <= 0) - return NULL; - - b = *start++; - - item->type = (b >> 2) & 3; - item->tag = (b >> 4) & 15; - - if (item->tag == HID_ITEM_TAG_LONG) { - - item->format = HID_ITEM_FORMAT_LONG; - - if ((end - start) < 2) - return NULL; - - item->size = *start++; - item->tag = *start++; - - if ((end - start) < item->size) - return NULL; - - item->data.longdata = start; - start += item->size; - return start; - } - - item->format = HID_ITEM_FORMAT_SHORT; - item->size = b & 3; - - switch (item->size) { - - case 0: - return start; - - case 1: - if ((end - start) < 1) - return NULL; - item->data.u8 = *start++; - return start; - - case 2: - if ((end - start) < 2) - return NULL; - item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start)); - start = (__u8 *)((__le16 *)start + 1); - return start; - - case 3: - item->size++; - if ((end - start) < 4) - return NULL; - item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start)); - start = (__u8 *)((__le32 *)start + 1); - return start; - } - - return NULL; -} - -/* - * Parse a report description into a hid_device structure. Reports are - * enumerated, fields are attached to these reports. - */ - -static struct hid_device *hid_parse_report(__u8 *start, unsigned size) -{ - struct hid_device *device; - struct hid_parser *parser; - struct hid_item item; - __u8 *end; - unsigned i; - static int (*dispatch_type[])(struct hid_parser *parser, - struct hid_item *item) = { - hid_parser_main, - hid_parser_global, - hid_parser_local, - hid_parser_reserved - }; - - if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL))) - return NULL; - - if (!(device->collection = kzalloc(sizeof(struct hid_collection) * - HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) { - kfree(device); - return NULL; - } - device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; - - for (i = 0; i < HID_REPORT_TYPES; i++) - INIT_LIST_HEAD(&device->report_enum[i].report_list); - - if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { - kfree(device->collection); - kfree(device); - return NULL; - } - memcpy(device->rdesc, start, size); - device->rsize = size; - - if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) { - kfree(device->rdesc); - kfree(device->collection); - kfree(device); - return NULL; - } - parser->device = device; - - end = start + size; - while ((start = fetch_item(start, end, &item)) != NULL) { - - if (item.format != HID_ITEM_FORMAT_SHORT) { - dbg("unexpected long global item"); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - - if (dispatch_type[item.type](parser, &item)) { - dbg("item %u %u %u %u parsing failed\n", - item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - - if (start == end) { - if (parser->collection_stack_ptr) { - dbg("unbalanced collection at end of report description"); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - if (parser->local.delimiter_depth) { - dbg("unbalanced delimiter at end of report description"); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - kfree(parser); - return device; - } - } - - dbg("item fetching failed at offset %d\n", (int)(end - start)); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; -} - -/* - * Convert a signed n-bit integer to signed 32-bit integer. Common - * cases are done through the compiler, the screwed things has to be - * done by hand. - */ - -static s32 snto32(__u32 value, unsigned n) -{ - switch (n) { - case 8: return ((__s8)value); - case 16: return ((__s16)value); - case 32: return ((__s32)value); - } - return value & (1 << (n - 1)) ? value | (-1 << n) : value; -} - -/* - * Convert a signed 32-bit integer to a signed n-bit integer. - */ - -static u32 s32ton(__s32 value, unsigned n) -{ - s32 a = value >> (n - 1); - if (a && a != -1) - return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; - return value & ((1 << n) - 1); -} - -/* - * Extract/implement a data field from/to a little endian report (bit array). - * - * Code sort-of follows HID spec: - * http://www.usb.org/developers/devclass_docs/HID1_11.pdf - * - * While the USB HID spec allows unlimited length bit fields in "report - * descriptors", most devices never use more than 16 bits. - * One model of UPS is claimed to report "LINEV" as a 32-bit field. - * Search linux-kernel and linux-usb-devel archives for "hid-core extract". - */ - -static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) -{ - u64 x; - - WARN_ON(n > 32); - - report += offset >> 3; /* adjust byte index */ - offset &= 7; /* now only need bit offset into one byte */ - x = get_unaligned((u64 *) report); - x = le64_to_cpu(x); - x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ - return (u32) x; -} - -/* - * "implement" : set bits in a little endian bit stream. - * Same concepts as "extract" (see comments above). - * The data mangled in the bit stream remains in little endian - * order the whole time. It make more sense to talk about - * endianness of register values by considering a register - * a "cached" copy of the little endiad bit stream. - */ -static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) -{ - u64 x; - u64 m = (1ULL << n) - 1; - - WARN_ON(n > 32); - - WARN_ON(value > m); - value &= m; - - report += offset >> 3; - offset &= 7; - - x = get_unaligned((u64 *)report); - x &= cpu_to_le64(~(m << offset)); - x |= cpu_to_le64(((u64) value) << offset); - put_unaligned(x, (u64 *) report); -} - -/* - * Search an array for a value. - */ - -static __inline__ int search(__s32 *array, __s32 value, unsigned n) -{ - while (n--) { - if (*array++ == value) - return 0; - } - return -1; -} - -static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt) -{ - hid_dump_input(usage, value); - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_hid_event(hid, field, usage, value); - if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt) - hiddev_hid_event(hid, field, usage, value); -} - -/* - * Analyse a received field, and fetch the data from it. The field - * content is stored for next report processing (we do differential - * reporting to the layer). - */ - -static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt) -{ - unsigned n; - unsigned count = field->report_count; - unsigned offset = field->report_offset; - unsigned size = field->report_size; - __s32 min = field->logical_minimum; - __s32 max = field->logical_maximum; - __s32 *value; - - if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC))) - return; - - for (n = 0; n < count; n++) { - - value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : - extract(data, offset + n * size, size); - - if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */ - && value[n] >= min && value[n] <= max - && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) - goto exit; - } - - for (n = 0; n < count; n++) { - - if (HID_MAIN_ITEM_VARIABLE & field->flags) { - hid_process_event(hid, field, &field->usage[n], value[n], interrupt); - continue; - } - - if (field->value[n] >= min && field->value[n] <= max - && field->usage[field->value[n] - min].hid - && search(value, field->value[n], count)) - hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); - - if (value[n] >= min && value[n] <= max - && field->usage[value[n] - min].hid - && search(field->value, value[n], count)) - hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); - } - - memcpy(field->value, value, count * sizeof(__s32)); -exit: - kfree(value); -} - -static int hid_input_report(int type, struct urb *urb, int interrupt) -{ - struct hid_device *hid = urb->context; - struct hid_report_enum *report_enum = hid->report_enum + type; - u8 *data = urb->transfer_buffer; - int len = urb->actual_length; - struct hid_report *report; - int n, size; - - if (!len) { - dbg("empty report"); - return -1; - } - -#ifdef DEBUG_DATA - printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un"); -#endif - - n = 0; /* Normally report number is 0 */ - if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ - n = *data++; - len--; - } - -#ifdef DEBUG_DATA - { - int i; - printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len); - for (i = 0; i < len; i++) - printk(" %02x", data[i]); - printk("\n"); - } -#endif - - if (!(report = report_enum->report_id_hash[n])) { - dbg("undefined report_id %d received", n); - return -1; - } - - size = ((report->size - 1) >> 3) + 1; - - if (len < size) { - dbg("report %d is too short, (%d < %d)", report->id, len, size); - memset(data + len, 0, size - len); - } - - if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_report_event(hid, report); - - for (n = 0; n < report->maxfield; n++) - hid_input_field(hid, report->field[n], data, interrupt); - - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_report_event(hid, report); - - return 0; -} - /* * Input submission and I/O error handler. */ @@ -1044,6 +164,65 @@ done: spin_unlock_irqrestore(&hid->inlock, flags); } + +static int hid_input_report(int type, struct urb *urb, int interrupt) +{ + struct hid_device *hid = urb->context; + struct hid_report_enum *report_enum = hid->report_enum + type; + u8 *data = urb->transfer_buffer; + int len = urb->actual_length; + struct hid_report *report; + int n, size; + + if (!len) { + dbg("empty report"); + return -1; + } + +#ifdef DEBUG_DATA + printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un"); +#endif + + n = 0; /* Normally report number is 0 */ + if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ + n = *data++; + len--; + } + +#ifdef DEBUG_DATA + { + int i; + printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len); + for (i = 0; i < len; i++) + printk(" %02x", data[i]); + printk("\n"); + } +#endif + + if (!(report = report_enum->report_id_hash[n])) { + dbg("undefined report_id %d received", n); + return -1; + } + + size = ((report->size - 1) >> 3) + 1; + + if (len < size) { + dbg("report %d is too short, (%d < %d)", report->id, len, size); + memset(data + len, 0, size - len); + } + + if (hid->claimed & HID_CLAIMED_HIDDEV) + hiddev_report_event(hid, report); + + for (n = 0; n < report->maxfield; n++) + hid_input_field(hid, report->field[n], data, interrupt); + + if (hid->claimed & HID_CLAIMED_INPUT) + hidinput_report_event(hid, report); + + return 0; +} + /* * Input interrupt completion handler. */ @@ -1092,67 +271,6 @@ static void hid_irq_in(struct urb *urb) } } -/* - * Output the field into the report. - */ - -static void hid_output_field(struct hid_field *field, __u8 *data) -{ - unsigned count = field->report_count; - unsigned offset = field->report_offset; - unsigned size = field->report_size; - unsigned n; - - for (n = 0; n < count; n++) { - if (field->logical_minimum < 0) /* signed values */ - implement(data, offset + n * size, size, s32ton(field->value[n], size)); - else /* unsigned values */ - implement(data, offset + n * size, size, field->value[n]); - } -} - -/* - * Create a report. - */ - -static void hid_output_report(struct hid_report *report, __u8 *data) -{ - unsigned n; - - if (report->id > 0) - *data++ = report->id; - - for (n = 0; n < report->maxfield; n++) - hid_output_field(report->field[n], data); -} - -/* - * Set a field value. The report this field belongs to has to be - * created and transferred to the device, to set this value in the - * device. - */ - -int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) -{ - unsigned size = field->report_size; - - hid_dump_input(field->usage + offset, value); - - if (offset >= field->report_count) { - dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count); - hid_dump_field(field, 8); - return -1; - } - if (field->logical_minimum < 0) { - if (value != snto32(s32ton(value, size), size)) { - dbg("value %d is out of range", value); - return -1; - } - } - field->value[offset] = value; - return 0; -} - /* * Find a report field with a specified HID usage. */ @@ -1379,6 +497,29 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign spin_unlock_irqrestore(&hid->ctrllock, flags); } +static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct hid_device *hid = dev->private; + struct hid_field *field; + int offset; + + if (type == EV_FF) + return input_ff_event(dev, type, code, value); + + if (type != EV_LED) + return -1; + + if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { + warn("event field not found"); + return -1; + } + + hid_set_field(field, offset, value); + hid_submit_report(hid, field->report, USB_DIR_OUT); + + return 0; +} + int hid_wait_io(struct hid_device *hid) { if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &hid->iofl) && @@ -1428,6 +569,18 @@ void hid_close(struct hid_device *hid) usb_kill_urb(hid->urbin); } +static int hidinput_open(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + return hid_open(hid); +} + +static void hidinput_close(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + hid_close(hid); +} + #define USB_VENDOR_ID_PANJIT 0x134c #define USB_VENDOR_ID_TURBOX 0x062a diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h deleted file mode 100644 index f04d6d75c098..000000000000 --- a/drivers/usb/input/hid-debug.h +++ /dev/null @@ -1,757 +0,0 @@ -/* - * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $ - * - * (c) 1999 Andreas Gal - * (c) 2000-2001 Vojtech Pavlik - * - * Some debug stuff for the HID parser. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include - -struct hid_usage_entry { - unsigned page; - unsigned usage; - char *description; -}; - -static const struct hid_usage_entry hid_usage_table[] = { - { 0, 0, "Undefined" }, - { 1, 0, "GenericDesktop" }, - {0, 0x01, "Pointer"}, - {0, 0x02, "Mouse"}, - {0, 0x04, "Joystick"}, - {0, 0x05, "GamePad"}, - {0, 0x06, "Keyboard"}, - {0, 0x07, "Keypad"}, - {0, 0x08, "MultiAxis"}, - {0, 0x30, "X"}, - {0, 0x31, "Y"}, - {0, 0x32, "Z"}, - {0, 0x33, "Rx"}, - {0, 0x34, "Ry"}, - {0, 0x35, "Rz"}, - {0, 0x36, "Slider"}, - {0, 0x37, "Dial"}, - {0, 0x38, "Wheel"}, - {0, 0x39, "HatSwitch"}, - {0, 0x3a, "CountedBuffer"}, - {0, 0x3b, "ByteCount"}, - {0, 0x3c, "MotionWakeup"}, - {0, 0x3d, "Start"}, - {0, 0x3e, "Select"}, - {0, 0x40, "Vx"}, - {0, 0x41, "Vy"}, - {0, 0x42, "Vz"}, - {0, 0x43, "Vbrx"}, - {0, 0x44, "Vbry"}, - {0, 0x45, "Vbrz"}, - {0, 0x46, "Vno"}, - {0, 0x80, "SystemControl"}, - {0, 0x81, "SystemPowerDown"}, - {0, 0x82, "SystemSleep"}, - {0, 0x83, "SystemWakeUp"}, - {0, 0x84, "SystemContextMenu"}, - {0, 0x85, "SystemMainMenu"}, - {0, 0x86, "SystemAppMenu"}, - {0, 0x87, "SystemMenuHelp"}, - {0, 0x88, "SystemMenuExit"}, - {0, 0x89, "SystemMenuSelect"}, - {0, 0x8a, "SystemMenuRight"}, - {0, 0x8b, "SystemMenuLeft"}, - {0, 0x8c, "SystemMenuUp"}, - {0, 0x8d, "SystemMenuDown"}, - {0, 0x90, "D-PadUp"}, - {0, 0x91, "D-PadDown"}, - {0, 0x92, "D-PadRight"}, - {0, 0x93, "D-PadLeft"}, - { 2, 0, "Simulation" }, - {0, 0xb0, "Aileron"}, - {0, 0xb1, "AileronTrim"}, - {0, 0xb2, "Anti-Torque"}, - {0, 0xb3, "Autopilot"}, - {0, 0xb4, "Chaff"}, - {0, 0xb5, "Collective"}, - {0, 0xb6, "DiveBrake"}, - {0, 0xb7, "ElectronicCountermeasures"}, - {0, 0xb8, "Elevator"}, - {0, 0xb9, "ElevatorTrim"}, - {0, 0xba, "Rudder"}, - {0, 0xbb, "Throttle"}, - {0, 0xbc, "FlightCommunications"}, - {0, 0xbd, "FlareRelease"}, - {0, 0xbe, "LandingGear"}, - {0, 0xbf, "ToeBrake"}, - { 7, 0, "Keyboard" }, - { 8, 0, "LED" }, - {0, 0x01, "NumLock"}, - {0, 0x02, "CapsLock"}, - {0, 0x03, "ScrollLock"}, - {0, 0x04, "Compose"}, - {0, 0x05, "Kana"}, - {0, 0x4b, "GenericIndicator"}, - { 9, 0, "Button" }, - { 10, 0, "Ordinal" }, - { 12, 0, "Consumer" }, - {0, 0x238, "HorizontalWheel"}, - { 13, 0, "Digitizers" }, - {0, 0x01, "Digitizer"}, - {0, 0x02, "Pen"}, - {0, 0x03, "LightPen"}, - {0, 0x04, "TouchScreen"}, - {0, 0x05, "TouchPad"}, - {0, 0x20, "Stylus"}, - {0, 0x21, "Puck"}, - {0, 0x22, "Finger"}, - {0, 0x30, "TipPressure"}, - {0, 0x31, "BarrelPressure"}, - {0, 0x32, "InRange"}, - {0, 0x33, "Touch"}, - {0, 0x34, "UnTouch"}, - {0, 0x35, "Tap"}, - {0, 0x39, "TabletFunctionKey"}, - {0, 0x3a, "ProgramChangeKey"}, - {0, 0x3c, "Invert"}, - {0, 0x42, "TipSwitch"}, - {0, 0x43, "SecondaryTipSwitch"}, - {0, 0x44, "BarrelSwitch"}, - {0, 0x45, "Eraser"}, - {0, 0x46, "TabletPick"}, - { 15, 0, "PhysicalInterfaceDevice" }, - {0, 0x00, "Undefined"}, - {0, 0x01, "Physical_Interface_Device"}, - {0, 0x20, "Normal"}, - {0, 0x21, "Set_Effect_Report"}, - {0, 0x22, "Effect_Block_Index"}, - {0, 0x23, "Parameter_Block_Offset"}, - {0, 0x24, "ROM_Flag"}, - {0, 0x25, "Effect_Type"}, - {0, 0x26, "ET_Constant_Force"}, - {0, 0x27, "ET_Ramp"}, - {0, 0x28, "ET_Custom_Force_Data"}, - {0, 0x30, "ET_Square"}, - {0, 0x31, "ET_Sine"}, - {0, 0x32, "ET_Triangle"}, - {0, 0x33, "ET_Sawtooth_Up"}, - {0, 0x34, "ET_Sawtooth_Down"}, - {0, 0x40, "ET_Spring"}, - {0, 0x41, "ET_Damper"}, - {0, 0x42, "ET_Inertia"}, - {0, 0x43, "ET_Friction"}, - {0, 0x50, "Duration"}, - {0, 0x51, "Sample_Period"}, - {0, 0x52, "Gain"}, - {0, 0x53, "Trigger_Button"}, - {0, 0x54, "Trigger_Repeat_Interval"}, - {0, 0x55, "Axes_Enable"}, - {0, 0x56, "Direction_Enable"}, - {0, 0x57, "Direction"}, - {0, 0x58, "Type_Specific_Block_Offset"}, - {0, 0x59, "Block_Type"}, - {0, 0x5A, "Set_Envelope_Report"}, - {0, 0x5B, "Attack_Level"}, - {0, 0x5C, "Attack_Time"}, - {0, 0x5D, "Fade_Level"}, - {0, 0x5E, "Fade_Time"}, - {0, 0x5F, "Set_Condition_Report"}, - {0, 0x60, "CP_Offset"}, - {0, 0x61, "Positive_Coefficient"}, - {0, 0x62, "Negative_Coefficient"}, - {0, 0x63, "Positive_Saturation"}, - {0, 0x64, "Negative_Saturation"}, - {0, 0x65, "Dead_Band"}, - {0, 0x66, "Download_Force_Sample"}, - {0, 0x67, "Isoch_Custom_Force_Enable"}, - {0, 0x68, "Custom_Force_Data_Report"}, - {0, 0x69, "Custom_Force_Data"}, - {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, - {0, 0x6B, "Set_Custom_Force_Report"}, - {0, 0x6C, "Custom_Force_Data_Offset"}, - {0, 0x6D, "Sample_Count"}, - {0, 0x6E, "Set_Periodic_Report"}, - {0, 0x6F, "Offset"}, - {0, 0x70, "Magnitude"}, - {0, 0x71, "Phase"}, - {0, 0x72, "Period"}, - {0, 0x73, "Set_Constant_Force_Report"}, - {0, 0x74, "Set_Ramp_Force_Report"}, - {0, 0x75, "Ramp_Start"}, - {0, 0x76, "Ramp_End"}, - {0, 0x77, "Effect_Operation_Report"}, - {0, 0x78, "Effect_Operation"}, - {0, 0x79, "Op_Effect_Start"}, - {0, 0x7A, "Op_Effect_Start_Solo"}, - {0, 0x7B, "Op_Effect_Stop"}, - {0, 0x7C, "Loop_Count"}, - {0, 0x7D, "Device_Gain_Report"}, - {0, 0x7E, "Device_Gain"}, - {0, 0x7F, "PID_Pool_Report"}, - {0, 0x80, "RAM_Pool_Size"}, - {0, 0x81, "ROM_Pool_Size"}, - {0, 0x82, "ROM_Effect_Block_Count"}, - {0, 0x83, "Simultaneous_Effects_Max"}, - {0, 0x84, "Pool_Alignment"}, - {0, 0x85, "PID_Pool_Move_Report"}, - {0, 0x86, "Move_Source"}, - {0, 0x87, "Move_Destination"}, - {0, 0x88, "Move_Length"}, - {0, 0x89, "PID_Block_Load_Report"}, - {0, 0x8B, "Block_Load_Status"}, - {0, 0x8C, "Block_Load_Success"}, - {0, 0x8D, "Block_Load_Full"}, - {0, 0x8E, "Block_Load_Error"}, - {0, 0x8F, "Block_Handle"}, - {0, 0x90, "PID_Block_Free_Report"}, - {0, 0x91, "Type_Specific_Block_Handle"}, - {0, 0x92, "PID_State_Report"}, - {0, 0x94, "Effect_Playing"}, - {0, 0x95, "PID_Device_Control_Report"}, - {0, 0x96, "PID_Device_Control"}, - {0, 0x97, "DC_Enable_Actuators"}, - {0, 0x98, "DC_Disable_Actuators"}, - {0, 0x99, "DC_Stop_All_Effects"}, - {0, 0x9A, "DC_Device_Reset"}, - {0, 0x9B, "DC_Device_Pause"}, - {0, 0x9C, "DC_Device_Continue"}, - {0, 0x9F, "Device_Paused"}, - {0, 0xA0, "Actuators_Enabled"}, - {0, 0xA4, "Safety_Switch"}, - {0, 0xA5, "Actuator_Override_Switch"}, - {0, 0xA6, "Actuator_Power"}, - {0, 0xA7, "Start_Delay"}, - {0, 0xA8, "Parameter_Block_Size"}, - {0, 0xA9, "Device_Managed_Pool"}, - {0, 0xAA, "Shared_Parameter_Blocks"}, - {0, 0xAB, "Create_New_Effect_Report"}, - {0, 0xAC, "RAM_Pool_Available"}, - { 0x84, 0, "Power Device" }, - { 0x84, 0x02, "PresentStatus" }, - { 0x84, 0x03, "ChangeStatus" }, - { 0x84, 0x04, "UPS" }, - { 0x84, 0x05, "PowerSupply" }, - { 0x84, 0x10, "BatterySystem" }, - { 0x84, 0x11, "BatterySystemID" }, - { 0x84, 0x12, "Battery" }, - { 0x84, 0x13, "BatteryID" }, - { 0x84, 0x14, "Charger" }, - { 0x84, 0x15, "ChargerID" }, - { 0x84, 0x16, "PowerConverter" }, - { 0x84, 0x17, "PowerConverterID" }, - { 0x84, 0x18, "OutletSystem" }, - { 0x84, 0x19, "OutletSystemID" }, - { 0x84, 0x1a, "Input" }, - { 0x84, 0x1b, "InputID" }, - { 0x84, 0x1c, "Output" }, - { 0x84, 0x1d, "OutputID" }, - { 0x84, 0x1e, "Flow" }, - { 0x84, 0x1f, "FlowID" }, - { 0x84, 0x20, "Outlet" }, - { 0x84, 0x21, "OutletID" }, - { 0x84, 0x22, "Gang" }, - { 0x84, 0x24, "PowerSummary" }, - { 0x84, 0x25, "PowerSummaryID" }, - { 0x84, 0x30, "Voltage" }, - { 0x84, 0x31, "Current" }, - { 0x84, 0x32, "Frequency" }, - { 0x84, 0x33, "ApparentPower" }, - { 0x84, 0x35, "PercentLoad" }, - { 0x84, 0x40, "ConfigVoltage" }, - { 0x84, 0x41, "ConfigCurrent" }, - { 0x84, 0x43, "ConfigApparentPower" }, - { 0x84, 0x53, "LowVoltageTransfer" }, - { 0x84, 0x54, "HighVoltageTransfer" }, - { 0x84, 0x56, "DelayBeforeStartup" }, - { 0x84, 0x57, "DelayBeforeShutdown" }, - { 0x84, 0x58, "Test" }, - { 0x84, 0x5a, "AudibleAlarmControl" }, - { 0x84, 0x60, "Present" }, - { 0x84, 0x61, "Good" }, - { 0x84, 0x62, "InternalFailure" }, - { 0x84, 0x65, "Overload" }, - { 0x84, 0x66, "OverCharged" }, - { 0x84, 0x67, "OverTemperature" }, - { 0x84, 0x68, "ShutdownRequested" }, - { 0x84, 0x69, "ShutdownImminent" }, - { 0x84, 0x6b, "SwitchOn/Off" }, - { 0x84, 0x6c, "Switchable" }, - { 0x84, 0x6d, "Used" }, - { 0x84, 0x6e, "Boost" }, - { 0x84, 0x73, "CommunicationLost" }, - { 0x84, 0xfd, "iManufacturer" }, - { 0x84, 0xfe, "iProduct" }, - { 0x84, 0xff, "iSerialNumber" }, - { 0x85, 0, "Battery System" }, - { 0x85, 0x01, "SMBBatteryMode" }, - { 0x85, 0x02, "SMBBatteryStatus" }, - { 0x85, 0x03, "SMBAlarmWarning" }, - { 0x85, 0x04, "SMBChargerMode" }, - { 0x85, 0x05, "SMBChargerStatus" }, - { 0x85, 0x06, "SMBChargerSpecInfo" }, - { 0x85, 0x07, "SMBSelectorState" }, - { 0x85, 0x08, "SMBSelectorPresets" }, - { 0x85, 0x09, "SMBSelectorInfo" }, - { 0x85, 0x29, "RemainingCapacityLimit" }, - { 0x85, 0x2c, "CapacityMode" }, - { 0x85, 0x42, "BelowRemainingCapacityLimit" }, - { 0x85, 0x44, "Charging" }, - { 0x85, 0x45, "Discharging" }, - { 0x85, 0x4b, "NeedReplacement" }, - { 0x85, 0x66, "RemainingCapacity" }, - { 0x85, 0x68, "RunTimeToEmpty" }, - { 0x85, 0x6a, "AverageTimeToFull" }, - { 0x85, 0x83, "DesignCapacity" }, - { 0x85, 0x85, "ManufacturerDate" }, - { 0x85, 0x89, "iDeviceChemistry" }, - { 0x85, 0x8b, "Rechargable" }, - { 0x85, 0x8f, "iOEMInformation" }, - { 0x85, 0x8d, "CapacityGranularity1" }, - { 0x85, 0xd0, "ACPresent" }, - /* pages 0xff00 to 0xffff are vendor-specific */ - { 0xffff, 0, "Vendor-specific-FF" }, - { 0, 0, NULL } -}; - -static void resolv_usage_page(unsigned page) { - const struct hid_usage_entry *p; - - for (p = hid_usage_table; p->description; p++) - if (p->page == page) { - printk("%s", p->description); - return; - } - printk("%04x", page); -} - -static void resolv_usage(unsigned usage) { - const struct hid_usage_entry *p; - - resolv_usage_page(usage >> 16); - printk("."); - for (p = hid_usage_table; p->description; p++) - if (p->page == (usage >> 16)) { - for(++p; p->description && p->usage != 0; p++) - if (p->usage == (usage & 0xffff)) { - printk("%s", p->description); - return; - } - break; - } - printk("%04x", usage & 0xffff); -} - -__inline__ static void tab(int n) { - while (n--) printk(" "); -} - -static void hid_dump_field(struct hid_field *field, int n) { - int j; - - if (field->physical) { - tab(n); - printk("Physical("); - resolv_usage(field->physical); printk(")\n"); - } - if (field->logical) { - tab(n); - printk("Logical("); - resolv_usage(field->logical); printk(")\n"); - } - tab(n); printk("Usage(%d)\n", field->maxusage); - for (j = 0; j < field->maxusage; j++) { - tab(n+2);resolv_usage(field->usage[j].hid); printk("\n"); - } - if (field->logical_minimum != field->logical_maximum) { - tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); - tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); - } - if (field->physical_minimum != field->physical_maximum) { - tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); - tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); - } - if (field->unit_exponent) { - tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); - } - if (field->unit) { - char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; - char *units[5][8] = { - { "None", "None", "None", "None", "None", "None", "None", "None" }, - { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, - { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, - { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }, - { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" } - }; - - int i; - int sys; - __u32 data = field->unit; - - /* First nibble tells us which system we're in. */ - sys = data & 0xf; - data >>= 4; - - if(sys > 4) { - tab(n); printk("Unit(Invalid)\n"); - } - else { - int earlier_unit = 0; - - tab(n); printk("Unit(%s : ", systems[sys]); - - for (i=1 ; i>= 4; - if (nibble != 0) { - if(earlier_unit++ > 0) - printk("*"); - printk("%s", units[sys][i]); - if(nibble != 1) { - /* This is a _signed_ nibble(!) */ - - int val = nibble & 0x7; - if(nibble & 0x08) - val = -((0x7 & ~val) +1); - printk("^%d", val); - } - } - } - printk(")\n"); - } - } - tab(n); printk("Report Size(%u)\n", field->report_size); - tab(n); printk("Report Count(%u)\n", field->report_count); - tab(n); printk("Report Offset(%u)\n", field->report_offset); - - tab(n); printk("Flags( "); - j = field->flags; - printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); - printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); - printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); - printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); - printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); - printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); - printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); - printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); - printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); - printk(")\n"); -} - -static void __attribute__((unused)) hid_dump_device(struct hid_device *device) { - struct hid_report_enum *report_enum; - struct hid_report *report; - struct list_head *list; - unsigned i,k; - static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; - - for (i = 0; i < HID_REPORT_TYPES; i++) { - report_enum = device->report_enum + i; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - tab(2); - printk("%s", table[i]); - if (report->id) - printk("(%d)", report->id); - printk("[%s]", table[report->type]); - printk("\n"); - for (k = 0; k < report->maxfield; k++) { - tab(4); - printk("Field(%d)\n", k); - hid_dump_field(report->field[k], 6); - } - list = list->next; - } - } -} - -static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) { - printk("hid-debug: input "); - resolv_usage(usage->hid); - printk(" = %d\n", value); -} - - -static char *events[EV_MAX + 1] = { - [EV_SYN] = "Sync", [EV_KEY] = "Key", - [EV_REL] = "Relative", [EV_ABS] = "Absolute", - [EV_MSC] = "Misc", [EV_LED] = "LED", - [EV_SND] = "Sound", [EV_REP] = "Repeat", - [EV_FF] = "ForceFeedback", [EV_PWR] = "Power", - [EV_FF_STATUS] = "ForceFeedbackStatus", -}; - -static char *syncs[2] = { - [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", -}; -static char *keys[KEY_MAX + 1] = { - [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", - [KEY_1] = "1", [KEY_2] = "2", - [KEY_3] = "3", [KEY_4] = "4", - [KEY_5] = "5", [KEY_6] = "6", - [KEY_7] = "7", [KEY_8] = "8", - [KEY_9] = "9", [KEY_0] = "0", - [KEY_MINUS] = "Minus", [KEY_EQUAL] = "Equal", - [KEY_BACKSPACE] = "Backspace", [KEY_TAB] = "Tab", - [KEY_Q] = "Q", [KEY_W] = "W", - [KEY_E] = "E", [KEY_R] = "R", - [KEY_T] = "T", [KEY_Y] = "Y", - [KEY_U] = "U", [KEY_I] = "I", - [KEY_O] = "O", [KEY_P] = "P", - [KEY_LEFTBRACE] = "LeftBrace", [KEY_RIGHTBRACE] = "RightBrace", - [KEY_ENTER] = "Enter", [KEY_LEFTCTRL] = "LeftControl", - [KEY_A] = "A", [KEY_S] = "S", - [KEY_D] = "D", [KEY_F] = "F", - [KEY_G] = "G", [KEY_H] = "H", - [KEY_J] = "J", [KEY_K] = "K", - [KEY_L] = "L", [KEY_SEMICOLON] = "Semicolon", - [KEY_APOSTROPHE] = "Apostrophe", [KEY_GRAVE] = "Grave", - [KEY_LEFTSHIFT] = "LeftShift", [KEY_BACKSLASH] = "BackSlash", - [KEY_Z] = "Z", [KEY_X] = "X", - [KEY_C] = "C", [KEY_V] = "V", - [KEY_B] = "B", [KEY_N] = "N", - [KEY_M] = "M", [KEY_COMMA] = "Comma", - [KEY_DOT] = "Dot", [KEY_SLASH] = "Slash", - [KEY_RIGHTSHIFT] = "RightShift", [KEY_KPASTERISK] = "KPAsterisk", - [KEY_LEFTALT] = "LeftAlt", [KEY_SPACE] = "Space", - [KEY_CAPSLOCK] = "CapsLock", [KEY_F1] = "F1", - [KEY_F2] = "F2", [KEY_F3] = "F3", - [KEY_F4] = "F4", [KEY_F5] = "F5", - [KEY_F6] = "F6", [KEY_F7] = "F7", - [KEY_F8] = "F8", [KEY_F9] = "F9", - [KEY_F10] = "F10", [KEY_NUMLOCK] = "NumLock", - [KEY_SCROLLLOCK] = "ScrollLock", [KEY_KP7] = "KP7", - [KEY_KP8] = "KP8", [KEY_KP9] = "KP9", - [KEY_KPMINUS] = "KPMinus", [KEY_KP4] = "KP4", - [KEY_KP5] = "KP5", [KEY_KP6] = "KP6", - [KEY_KPPLUS] = "KPPlus", [KEY_KP1] = "KP1", - [KEY_KP2] = "KP2", [KEY_KP3] = "KP3", - [KEY_KP0] = "KP0", [KEY_KPDOT] = "KPDot", - [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd", - [KEY_F11] = "F11", [KEY_F12] = "F12", - [KEY_RO] = "RO", [KEY_KATAKANA] = "Katakana", - [KEY_HIRAGANA] = "HIRAGANA", [KEY_HENKAN] = "Henkan", - [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan", - [KEY_KPJPCOMMA] = "KPJpComma", [KEY_KPENTER] = "KPEnter", - [KEY_RIGHTCTRL] = "RightCtrl", [KEY_KPSLASH] = "KPSlash", - [KEY_SYSRQ] = "SysRq", [KEY_RIGHTALT] = "RightAlt", - [KEY_LINEFEED] = "LineFeed", [KEY_HOME] = "Home", - [KEY_UP] = "Up", [KEY_PAGEUP] = "PageUp", - [KEY_LEFT] = "Left", [KEY_RIGHT] = "Right", - [KEY_END] = "End", [KEY_DOWN] = "Down", - [KEY_PAGEDOWN] = "PageDown", [KEY_INSERT] = "Insert", - [KEY_DELETE] = "Delete", [KEY_MACRO] = "Macro", - [KEY_MUTE] = "Mute", [KEY_VOLUMEDOWN] = "VolumeDown", - [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power", - [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus", - [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma", - [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja", - [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta", - [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose", - [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again", - [KEY_PROPS] = "Props", [KEY_UNDO] = "Undo", - [KEY_FRONT] = "Front", [KEY_COPY] = "Copy", - [KEY_OPEN] = "Open", [KEY_PASTE] = "Paste", - [KEY_FIND] = "Find", [KEY_CUT] = "Cut", - [KEY_HELP] = "Help", [KEY_MENU] = "Menu", - [KEY_CALC] = "Calc", [KEY_SETUP] = "Setup", - [KEY_SLEEP] = "Sleep", [KEY_WAKEUP] = "WakeUp", - [KEY_FILE] = "File", [KEY_SENDFILE] = "SendFile", - [KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer", - [KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2", - [KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS", - [KEY_COFFEE] = "Coffee", [KEY_DIRECTION] = "Direction", - [KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail", - [KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer", - [KEY_BACK] = "Back", [KEY_FORWARD] = "Forward", - [KEY_CLOSECD] = "CloseCD", [KEY_EJECTCD] = "EjectCD", - [KEY_EJECTCLOSECD] = "EjectCloseCD", [KEY_NEXTSONG] = "NextSong", - [KEY_PLAYPAUSE] = "PlayPause", [KEY_PREVIOUSSONG] = "PreviousSong", - [KEY_STOPCD] = "StopCD", [KEY_RECORD] = "Record", - [KEY_REWIND] = "Rewind", [KEY_PHONE] = "Phone", - [KEY_ISO] = "ISOKey", [KEY_CONFIG] = "Config", - [KEY_HOMEPAGE] = "HomePage", [KEY_REFRESH] = "Refresh", - [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move", - [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp", - [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis", - [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New", - [KEY_REDO] = "Redo", [KEY_F13] = "F13", - [KEY_F14] = "F14", [KEY_F15] = "F15", - [KEY_F16] = "F16", [KEY_F17] = "F17", - [KEY_F18] = "F18", [KEY_F19] = "F19", - [KEY_F20] = "F20", [KEY_F21] = "F21", - [KEY_F22] = "F22", [KEY_F23] = "F23", - [KEY_F24] = "F24", [KEY_PLAYCD] = "PlayCD", - [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3", - [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend", - [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play", - [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost", - [KEY_PRINT] = "Print", [KEY_HP] = "HP", - [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound", - [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email", - [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search", - [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance", - [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop", - [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel", - [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp", - [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", - [BTN_0] = "Btn0", [BTN_1] = "Btn1", - [BTN_2] = "Btn2", [BTN_3] = "Btn3", - [BTN_4] = "Btn4", [BTN_5] = "Btn5", - [BTN_6] = "Btn6", [BTN_7] = "Btn7", - [BTN_8] = "Btn8", [BTN_9] = "Btn9", - [BTN_LEFT] = "LeftBtn", [BTN_RIGHT] = "RightBtn", - [BTN_MIDDLE] = "MiddleBtn", [BTN_SIDE] = "SideBtn", - [BTN_EXTRA] = "ExtraBtn", [BTN_FORWARD] = "ForwardBtn", - [BTN_BACK] = "BackBtn", [BTN_TASK] = "TaskBtn", - [BTN_TRIGGER] = "Trigger", [BTN_THUMB] = "ThumbBtn", - [BTN_THUMB2] = "ThumbBtn2", [BTN_TOP] = "TopBtn", - [BTN_TOP2] = "TopBtn2", [BTN_PINKIE] = "PinkieBtn", - [BTN_BASE] = "BaseBtn", [BTN_BASE2] = "BaseBtn2", - [BTN_BASE3] = "BaseBtn3", [BTN_BASE4] = "BaseBtn4", - [BTN_BASE5] = "BaseBtn5", [BTN_BASE6] = "BaseBtn6", - [BTN_DEAD] = "BtnDead", [BTN_A] = "BtnA", - [BTN_B] = "BtnB", [BTN_C] = "BtnC", - [BTN_X] = "BtnX", [BTN_Y] = "BtnY", - [BTN_Z] = "BtnZ", [BTN_TL] = "BtnTL", - [BTN_TR] = "BtnTR", [BTN_TL2] = "BtnTL2", - [BTN_TR2] = "BtnTR2", [BTN_SELECT] = "BtnSelect", - [BTN_START] = "BtnStart", [BTN_MODE] = "BtnMode", - [BTN_THUMBL] = "BtnThumbL", [BTN_THUMBR] = "BtnThumbR", - [BTN_TOOL_PEN] = "ToolPen", [BTN_TOOL_RUBBER] = "ToolRubber", - [BTN_TOOL_BRUSH] = "ToolBrush", [BTN_TOOL_PENCIL] = "ToolPencil", - [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger", - [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", - [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", - [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", - [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn", - [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", - [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", - [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", - [KEY_OPTION] = "Option", [KEY_INFO] = "Info", - [KEY_TIME] = "Time", [KEY_VENDOR] = "Vendor", - [KEY_ARCHIVE] = "Archive", [KEY_PROGRAM] = "Program", - [KEY_CHANNEL] = "Channel", [KEY_FAVORITES] = "Favorites", - [KEY_EPG] = "EPG", [KEY_PVR] = "PVR", - [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language", - [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle", - [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom", - [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard", - [KEY_SCREEN] = "Screen", [KEY_PC] = "PC", - [KEY_TV] = "TV", [KEY_TV2] = "TV2", - [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2", - [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2", - [KEY_CD] = "CD", [KEY_TAPE] = "Tape", - [KEY_RADIO] = "Radio", [KEY_TUNER] = "Tuner", - [KEY_PLAYER] = "Player", [KEY_TEXT] = "Text", - [KEY_DVD] = "DVD", [KEY_AUX] = "Aux", - [KEY_MP3] = "MP3", [KEY_AUDIO] = "Audio", - [KEY_VIDEO] = "Video", [KEY_DIRECTORY] = "Directory", - [KEY_LIST] = "List", [KEY_MEMO] = "Memo", - [KEY_CALENDAR] = "Calendar", [KEY_RED] = "Red", - [KEY_GREEN] = "Green", [KEY_YELLOW] = "Yellow", - [KEY_BLUE] = "Blue", [KEY_CHANNELUP] = "ChannelUp", - [KEY_CHANNELDOWN] = "ChannelDown", [KEY_FIRST] = "First", - [KEY_LAST] = "Last", [KEY_AB] = "AB", - [KEY_NEXT] = "Next", [KEY_RESTART] = "Restart", - [KEY_SLOW] = "Slow", [KEY_SHUFFLE] = "Shuffle", - [KEY_BREAK] = "Break", [KEY_PREVIOUS] = "Previous", - [KEY_DIGITS] = "Digits", [KEY_TEEN] = "TEEN", - [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL", - [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine", - [KEY_DEL_LINE] = "DeleteLine", - [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", - [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", - [KEY_DOCUMENTS] = "Documents", - [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", - [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", - [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", - [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F", - [KEY_FN_S] = "Fn+S", - [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2", - [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4", - [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6", - [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8", - [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10", - [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12", - [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle", - [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", - [KEY_KBDILLUMUP] = "KbdIlluminationUp", - [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", -}; - -static char *relatives[REL_MAX + 1] = { - [REL_X] = "X", [REL_Y] = "Y", - [REL_Z] = "Z", [REL_HWHEEL] = "HWheel", - [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel", - [REL_MISC] = "Misc", -}; - -static char *absolutes[ABS_MAX + 1] = { - [ABS_X] = "X", [ABS_Y] = "Y", - [ABS_Z] = "Z", [ABS_RX] = "Rx", - [ABS_RY] = "Ry", [ABS_RZ] = "Rz", - [ABS_THROTTLE] = "Throttle", [ABS_RUDDER] = "Rudder", - [ABS_WHEEL] = "Wheel", [ABS_GAS] = "Gas", - [ABS_BRAKE] = "Brake", [ABS_HAT0X] = "Hat0X", - [ABS_HAT0Y] = "Hat0Y", [ABS_HAT1X] = "Hat1X", - [ABS_HAT1Y] = "Hat1Y", [ABS_HAT2X] = "Hat2X", - [ABS_HAT2Y] = "Hat2Y", [ABS_HAT3X] = "Hat3X", - [ABS_HAT3Y] = "Hat 3Y", [ABS_PRESSURE] = "Pressure", - [ABS_DISTANCE] = "Distance", [ABS_TILT_X] = "XTilt", - [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "Tool Width", - [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", -}; - -static char *misc[MSC_MAX + 1] = { - [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", - [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" -}; - -static char *leds[LED_MAX + 1] = { - [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", - [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", - [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", - [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute", - [LED_MISC] = "Misc", -}; - -static char *repeats[REP_MAX + 1] = { - [REP_DELAY] = "Delay", [REP_PERIOD] = "Period" -}; - -static char *sounds[SND_MAX + 1] = { - [SND_CLICK] = "Click", [SND_BELL] = "Bell", - [SND_TONE] = "Tone" -}; - -static char **names[EV_MAX + 1] = { - [EV_SYN] = syncs, [EV_KEY] = keys, - [EV_REL] = relatives, [EV_ABS] = absolutes, - [EV_MSC] = misc, [EV_LED] = leds, - [EV_SND] = sounds, [EV_REP] = repeats, -}; - -static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) { - - printk("%s.%s", events[type] ? events[type] : "?", - names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); -} diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index a8fc46c721c5..4187f4ee9a9c 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -32,7 +32,7 @@ #undef DEBUG #include -#include "hid.h" +#include /* * This table contains pointers to initializers. To add support for new diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 3a7e5fbff025..8756eb3263de 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -4,6 +4,7 @@ * Copyright (c) 2000-2001 Vojtech Pavlik * * USB HID to Linux Input mapping + * */ /* @@ -26,847 +27,4 @@ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ -#include -#include -#include -#include - -#undef DEBUG - -#include "hid.h" - -#define unk KEY_UNKNOWN - -static const unsigned char hid_keyboard[256] = { - 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, - 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, - 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, - 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, - 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, - 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, - 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, - 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk -}; - -static const struct { - __s32 x; - __s32 y; -} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; - -#define map_abs(c) do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0) -#define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0) -#define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0) -#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0) - -#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) -#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) - -#ifdef CONFIG_USB_HIDINPUT_POWERBOOK - -struct hidinput_key_translation { - u16 from; - u16 to; - u8 flags; -}; - -#define POWERBOOK_FLAG_FKEY 0x01 - -static struct hidinput_key_translation powerbook_fn_keys[] = { - { KEY_BACKSPACE, KEY_DELETE }, - { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY }, - { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY }, - { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY }, - { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY }, - { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY }, - { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY }, - { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY }, - { KEY_UP, KEY_PAGEUP }, - { KEY_DOWN, KEY_PAGEDOWN }, - { KEY_LEFT, KEY_HOME }, - { KEY_RIGHT, KEY_END }, - { } -}; - -static struct hidinput_key_translation powerbook_numlock_keys[] = { - { KEY_J, KEY_KP1 }, - { KEY_K, KEY_KP2 }, - { KEY_L, KEY_KP3 }, - { KEY_U, KEY_KP4 }, - { KEY_I, KEY_KP5 }, - { KEY_O, KEY_KP6 }, - { KEY_7, KEY_KP7 }, - { KEY_8, KEY_KP8 }, - { KEY_9, KEY_KP9 }, - { KEY_M, KEY_KP0 }, - { KEY_DOT, KEY_KPDOT }, - { KEY_SLASH, KEY_KPPLUS }, - { KEY_SEMICOLON, KEY_KPMINUS }, - { KEY_P, KEY_KPASTERISK }, - { KEY_MINUS, KEY_KPEQUAL }, - { KEY_0, KEY_KPSLASH }, - { KEY_F6, KEY_NUMLOCK }, - { KEY_KPENTER, KEY_KPENTER }, - { KEY_BACKSPACE, KEY_BACKSPACE }, - { } -}; - -static struct hidinput_key_translation powerbook_iso_keyboard[] = { - { KEY_GRAVE, KEY_102ND }, - { KEY_102ND, KEY_GRAVE }, - { } -}; - -static int usbhid_pb_fnmode = 1; -module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); -MODULE_PARM_DESC(pb_fnmode, - "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); - -static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from) -{ - struct hidinput_key_translation *trans; - - /* Look for the translation */ - for (trans = table; trans->from; trans++) - if (trans->from == from) - return trans; - - return NULL; -} - -static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, - struct hid_usage *usage, __s32 value) -{ - struct hidinput_key_translation *trans; - - if (usage->code == KEY_FN) { - if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON; - else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON; - - input_event(input, usage->type, usage->code, value); - - return 1; - } - - if (usbhid_pb_fnmode) { - int do_translate; - - trans = find_translation(powerbook_fn_keys, usage->code); - if (trans) { - if (test_bit(usage->code, hid->pb_pressed_fn)) - do_translate = 1; - else if (trans->flags & POWERBOOK_FLAG_FKEY) - do_translate = - (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) || - (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)); - else - do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON); - - if (do_translate) { - if (value) - set_bit(usage->code, hid->pb_pressed_fn); - else - clear_bit(usage->code, hid->pb_pressed_fn); - - input_event(input, usage->type, trans->to, value); - - return 1; - } - } - - if (test_bit(usage->code, hid->pb_pressed_numlock) || - test_bit(LED_NUML, input->led)) { - trans = find_translation(powerbook_numlock_keys, usage->code); - - if (trans) { - if (value) - set_bit(usage->code, hid->pb_pressed_numlock); - else - clear_bit(usage->code, hid->pb_pressed_numlock); - - input_event(input, usage->type, trans->to, value); - } - - return 1; - } - } - - if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) { - trans = find_translation(powerbook_iso_keyboard, usage->code); - if (trans) { - input_event(input, usage->type, trans->to, value); - return 1; - } - } - - return 0; -} - -static void hidinput_pb_setup(struct input_dev *input) -{ - struct hidinput_key_translation *trans; - - set_bit(KEY_NUMLOCK, input->keybit); - - /* Enable all needed keys */ - for (trans = powerbook_fn_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = powerbook_numlock_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = powerbook_iso_keyboard; trans->from; trans++) - set_bit(trans->to, input->keybit); -} -#else -static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, - struct hid_usage *usage, __s32 value) -{ - return 0; -} - -static inline void hidinput_pb_setup(struct input_dev *input) -{ -} -#endif - -static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, - struct hid_usage *usage) -{ - struct input_dev *input = hidinput->input; - struct hid_device *device = input->private; - int max = 0, code; - unsigned long *bit = NULL; - - field->hidinput = hidinput; - -#ifdef DEBUG - printk(KERN_DEBUG "Mapping: "); - resolv_usage(usage->hid); - printk(" ---> "); -#endif - - if (field->flags & HID_MAIN_ITEM_CONSTANT) - goto ignore; - - switch (usage->hid & HID_USAGE_PAGE) { - - case HID_UP_UNDEFINED: - goto ignore; - - case HID_UP_KEYBOARD: - - set_bit(EV_REP, input->evbit); - - if ((usage->hid & HID_USAGE) < 256) { - if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore; - map_key_clear(hid_keyboard[usage->hid & HID_USAGE]); - } else - map_key(KEY_UNKNOWN); - - break; - - case HID_UP_BUTTON: - - code = ((usage->hid - 1) & 0xf); - - switch (field->application) { - case HID_GD_MOUSE: - case HID_GD_POINTER: code += 0x110; break; - case HID_GD_JOYSTICK: code += 0x120; break; - case HID_GD_GAMEPAD: code += 0x130; break; - default: - switch (field->physical) { - case HID_GD_MOUSE: - case HID_GD_POINTER: code += 0x110; break; - case HID_GD_JOYSTICK: code += 0x120; break; - case HID_GD_GAMEPAD: code += 0x130; break; - default: code += 0x100; - } - } - - map_key(code); - break; - - - case HID_UP_SIMULATION: - - switch (usage->hid & 0xffff) { - case 0xba: map_abs(ABS_RUDDER); break; - case 0xbb: map_abs(ABS_THROTTLE); break; - case 0xc4: map_abs(ABS_GAS); break; - case 0xc5: map_abs(ABS_BRAKE); break; - case 0xc8: map_abs(ABS_WHEEL); break; - default: goto ignore; - } - break; - - case HID_UP_GENDESK: - - if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */ - switch (usage->hid & 0xf) { - case 0x1: map_key_clear(KEY_POWER); break; - case 0x2: map_key_clear(KEY_SLEEP); break; - case 0x3: map_key_clear(KEY_WAKEUP); break; - default: goto unknown; - } - break; - } - - if ((usage->hid & 0xf0) == 0x90) { /* D-pad */ - switch (usage->hid) { - case HID_GD_UP: usage->hat_dir = 1; break; - case HID_GD_DOWN: usage->hat_dir = 5; break; - case HID_GD_RIGHT: usage->hat_dir = 3; break; - case HID_GD_LEFT: usage->hat_dir = 7; break; - default: goto unknown; - } - if (field->dpad) { - map_abs(field->dpad); - goto ignore; - } - map_abs(ABS_HAT0X); - break; - } - - switch (usage->hid) { - - /* These usage IDs map directly to the usage codes. */ - case HID_GD_X: case HID_GD_Y: case HID_GD_Z: - case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: - case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: - if (field->flags & HID_MAIN_ITEM_RELATIVE) - map_rel(usage->hid & 0xf); - else - map_abs(usage->hid & 0xf); - break; - - case HID_GD_HATSWITCH: - usage->hat_min = field->logical_minimum; - usage->hat_max = field->logical_maximum; - map_abs(ABS_HAT0X); - break; - - case HID_GD_START: map_key_clear(BTN_START); break; - case HID_GD_SELECT: map_key_clear(BTN_SELECT); break; - - default: goto unknown; - } - - break; - - case HID_UP_LED: - if (((usage->hid - 1) & 0xffff) >= LED_MAX) - goto ignore; - map_led((usage->hid - 1) & 0xffff); - break; - - case HID_UP_DIGITIZER: - - switch (usage->hid & 0xff) { - - case 0x30: /* TipPressure */ - if (!test_bit(BTN_TOUCH, input->keybit)) { - device->quirks |= HID_QUIRK_NOTOUCH; - set_bit(EV_KEY, input->evbit); - set_bit(BTN_TOUCH, input->keybit); - } - - map_abs_clear(ABS_PRESSURE); - break; - - case 0x32: /* InRange */ - switch (field->physical & 0xff) { - case 0x21: map_key(BTN_TOOL_MOUSE); break; - case 0x22: map_key(BTN_TOOL_FINGER); break; - default: map_key(BTN_TOOL_PEN); break; - } - break; - - case 0x3c: /* Invert */ - map_key_clear(BTN_TOOL_RUBBER); - break; - - case 0x33: /* Touch */ - case 0x42: /* TipSwitch */ - case 0x43: /* TipSwitch2 */ - device->quirks &= ~HID_QUIRK_NOTOUCH; - map_key_clear(BTN_TOUCH); - break; - - case 0x44: /* BarrelSwitch */ - map_key_clear(BTN_STYLUS); - break; - - default: goto unknown; - } - break; - - case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ - - switch (usage->hid & HID_USAGE) { - case 0x000: goto ignore; - case 0x034: map_key_clear(KEY_SLEEP); break; - case 0x036: map_key_clear(BTN_MISC); break; - case 0x045: map_key_clear(KEY_RADIO); break; - case 0x08a: map_key_clear(KEY_WWW); break; - case 0x08d: map_key_clear(KEY_PROGRAM); break; - case 0x095: map_key_clear(KEY_HELP); break; - case 0x09c: map_key_clear(KEY_CHANNELUP); break; - case 0x09d: map_key_clear(KEY_CHANNELDOWN); break; - case 0x0b0: map_key_clear(KEY_PLAY); break; - case 0x0b1: map_key_clear(KEY_PAUSE); break; - case 0x0b2: map_key_clear(KEY_RECORD); break; - case 0x0b3: map_key_clear(KEY_FASTFORWARD); break; - case 0x0b4: map_key_clear(KEY_REWIND); break; - case 0x0b5: map_key_clear(KEY_NEXTSONG); break; - case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break; - case 0x0b7: map_key_clear(KEY_STOPCD); break; - case 0x0b8: map_key_clear(KEY_EJECTCD); break; - case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; - case 0x0e0: map_abs_clear(ABS_VOLUME); break; - case 0x0e2: map_key_clear(KEY_MUTE); break; - case 0x0e5: map_key_clear(KEY_BASSBOOST); break; - case 0x0e9: map_key_clear(KEY_VOLUMEUP); break; - case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; - case 0x183: map_key_clear(KEY_CONFIG); break; - case 0x18a: map_key_clear(KEY_MAIL); break; - case 0x192: map_key_clear(KEY_CALC); break; - case 0x194: map_key_clear(KEY_FILE); break; - case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; - case 0x201: map_key_clear(KEY_NEW); break; - case 0x207: map_key_clear(KEY_SAVE); break; - case 0x208: map_key_clear(KEY_PRINT); break; - case 0x209: map_key_clear(KEY_PROPS); break; - case 0x21a: map_key_clear(KEY_UNDO); break; - case 0x21b: map_key_clear(KEY_COPY); break; - case 0x21c: map_key_clear(KEY_CUT); break; - case 0x21d: map_key_clear(KEY_PASTE); break; - case 0x221: map_key_clear(KEY_FIND); break; - case 0x223: map_key_clear(KEY_HOMEPAGE); break; - case 0x224: map_key_clear(KEY_BACK); break; - case 0x225: map_key_clear(KEY_FORWARD); break; - case 0x226: map_key_clear(KEY_STOP); break; - case 0x227: map_key_clear(KEY_REFRESH); break; - case 0x22a: map_key_clear(KEY_BOOKMARKS); break; - case 0x233: map_key_clear(KEY_SCROLLUP); break; - case 0x234: map_key_clear(KEY_SCROLLDOWN); break; - case 0x238: map_rel(REL_HWHEEL); break; - case 0x279: map_key_clear(KEY_REDO); break; - case 0x289: map_key_clear(KEY_REPLY); break; - case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; - case 0x28c: map_key_clear(KEY_SEND); break; - - /* Reported on a Cherry Cymotion keyboard */ - case 0x301: map_key_clear(KEY_PROG1); break; - case 0x302: map_key_clear(KEY_PROG2); break; - case 0x303: map_key_clear(KEY_PROG3); break; - - default: goto ignore; - } - break; - - case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ - - set_bit(EV_REP, input->evbit); - switch (usage->hid & HID_USAGE) { - case 0x021: map_key_clear(KEY_PRINT); break; - case 0x070: map_key_clear(KEY_HP); break; - case 0x071: map_key_clear(KEY_CAMERA); break; - case 0x072: map_key_clear(KEY_SOUND); break; - case 0x073: map_key_clear(KEY_QUESTION); break; - case 0x080: map_key_clear(KEY_EMAIL); break; - case 0x081: map_key_clear(KEY_CHAT); break; - case 0x082: map_key_clear(KEY_SEARCH); break; - case 0x083: map_key_clear(KEY_CONNECT); break; - case 0x084: map_key_clear(KEY_FINANCE); break; - case 0x085: map_key_clear(KEY_SPORT); break; - case 0x086: map_key_clear(KEY_SHOP); break; - default: goto ignore; - } - break; - - case HID_UP_MSVENDOR: - goto ignore; - - case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */ - - set_bit(EV_REP, input->evbit); - switch(usage->hid & HID_USAGE) { - case 0x003: - /* The fn key on Apple PowerBooks */ - map_key_clear(KEY_FN); - hidinput_pb_setup(input); - break; - - default: goto ignore; - } - break; - - case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */ - - set_bit(EV_REP, input->evbit); - switch(usage->hid & HID_USAGE) { - case 0x004: map_key_clear(KEY_AGAIN); break; - case 0x00d: map_key_clear(KEY_HOME); break; - case 0x024: map_key_clear(KEY_SHUFFLE); break; - case 0x025: map_key_clear(KEY_TV); break; - case 0x026: map_key_clear(KEY_MENU); break; - case 0x031: map_key_clear(KEY_AUDIO); break; - case 0x032: map_key_clear(KEY_TEXT); break; - case 0x033: map_key_clear(KEY_LAST); break; - case 0x047: map_key_clear(KEY_MP3); break; - case 0x048: map_key_clear(KEY_DVD); break; - case 0x049: map_key_clear(KEY_MEDIA); break; - case 0x04a: map_key_clear(KEY_VIDEO); break; - case 0x04b: map_key_clear(KEY_ANGLE); break; - case 0x04c: map_key_clear(KEY_LANGUAGE); break; - case 0x04d: map_key_clear(KEY_SUBTITLE); break; - case 0x051: map_key_clear(KEY_RED); break; - case 0x052: map_key_clear(KEY_CLOSE); break; - default: goto ignore; - } - break; - - case HID_UP_PID: - - switch(usage->hid & HID_USAGE) { - case 0xa4: map_key_clear(BTN_DEAD); break; - default: goto ignore; - } - break; - - default: - unknown: - if (field->report_size == 1) { - if (field->report->type == HID_OUTPUT_REPORT) { - map_led(LED_MISC); - break; - } - map_key(BTN_MISC); - break; - } - if (field->flags & HID_MAIN_ITEM_RELATIVE) { - map_rel(REL_MISC); - break; - } - map_abs(ABS_MISC); - break; - } - - if (device->quirks & HID_QUIRK_MIGHTYMOUSE) { - if (usage->hid == HID_GD_Z) - map_rel(REL_HWHEEL); - else if (usage->code == BTN_1) - map_key(BTN_2); - else if (usage->code == BTN_2) - map_key(BTN_1); - } - - if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && - (usage->type == EV_REL) && (usage->code == REL_WHEEL)) - set_bit(REL_HWHEEL, bit); - - if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) - || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) - goto ignore; - - if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) && - usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE)) - field->flags &= ~HID_MAIN_ITEM_RELATIVE; - - set_bit(usage->type, input->evbit); - - while (usage->code <= max && test_and_set_bit(usage->code, bit)) - usage->code = find_next_zero_bit(bit, max + 1, usage->code); - - if (usage->code > max) - goto ignore; - - - if (usage->type == EV_ABS) { - - int a = field->logical_minimum; - int b = field->logical_maximum; - - if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) { - a = field->logical_minimum = 0; - b = field->logical_maximum = 255; - } - - if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK) - input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4); - else input_set_abs_params(input, usage->code, a, b, 0, 0); - - } - - if (usage->type == EV_ABS && - (usage->hat_min < usage->hat_max || usage->hat_dir)) { - int i; - for (i = usage->code; i < usage->code + 2 && i <= max; i++) { - input_set_abs_params(input, i, -1, 1, 0, 0); - set_bit(i, input->absbit); - } - if (usage->hat_dir && !field->dpad) - field->dpad = usage->code; - } - -#ifdef DEBUG - resolv_event(usage->type, usage->code); - printk("\n"); -#endif - return; - -ignore: -#ifdef DEBUG - printk("IGNORED\n"); -#endif - return; -} - -void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) -{ - struct input_dev *input; - int *quirks = &hid->quirks; - - if (!field->hidinput) - return; - - input = field->hidinput->input; - - if (!usage->type) - return; - - if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) - || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) { - if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - return; - } - - if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) { - input_event(input, usage->type, usage->code, -value); - return; - } - - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { - input_event(input, usage->type, REL_HWHEEL, value); - return; - } - - if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value)) - return; - - if (usage->hat_min < usage->hat_max || usage->hat_dir) { - int hat_dir = usage->hat_dir; - if (!hat_dir) - hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; - if (hat_dir < 0 || hat_dir > 8) hat_dir = 0; - input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x); - input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */ - *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */ - if (value) { - input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); - return; - } - input_event(input, usage->type, usage->code, 0); - input_event(input, usage->type, BTN_TOOL_RUBBER, 0); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */ - int a = field->logical_minimum; - int b = field->logical_maximum; - input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); - } - - if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ - dbg("Maximum Effects - %d",value); - return; - } - - if (usage->hid == (HID_UP_PID | 0x7fUL)) { - dbg("PID Pool Report\n"); - return; - } - - if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ - return; - - input_event(input, usage->type, usage->code, value); - - if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) - input_event(input, usage->type, usage->code, 0); -} - -void hidinput_report_event(struct hid_device *hid, struct hid_report *report) -{ - struct hid_input *hidinput; - - list_for_each_entry(hidinput, &hid->inputs, list) - input_sync(hidinput->input); -} - -static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) -{ - struct hid_report *report; - int i, j; - - list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) { - for (i = 0; i < report->maxfield; i++) { - *field = report->field[i]; - for (j = 0; j < (*field)->maxusage; j++) - if ((*field)->usage[j].type == type && (*field)->usage[j].code == code) - return j; - } - } - return -1; -} - -static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - struct hid_device *hid = dev->private; - struct hid_field *field; - int offset; - - if (type == EV_FF) - return input_ff_event(dev, type, code, value); - - if (type != EV_LED) - return -1; - - if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { - warn("event field not found"); - return -1; - } - - hid_set_field(field, offset, value); - hid_submit_report(hid, field->report, USB_DIR_OUT); - - return 0; -} - -static int hidinput_open(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - return hid_open(hid); -} - -static void hidinput_close(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - hid_close(hid); -} - -/* - * Register the input device; print a message. - * Configure the input layer interface - * Read all reports and initialize the absolute field values. - */ - -int hidinput_connect(struct hid_device *hid) -{ - struct usb_device *dev = hid->dev; - struct hid_report *report; - struct hid_input *hidinput = NULL; - struct input_dev *input_dev; - int i, j, k; - - INIT_LIST_HEAD(&hid->inputs); - - for (i = 0; i < hid->maxcollection; i++) - if (hid->collection[i].type == HID_COLLECTION_APPLICATION || - hid->collection[i].type == HID_COLLECTION_PHYSICAL) - if (IS_INPUT_APPLICATION(hid->collection[i].usage)) - break; - - if (i == hid->maxcollection) - return -1; - - for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) - list_for_each_entry(report, &hid->report_enum[k].report_list, list) { - - if (!report->maxfield) - continue; - - if (!hidinput) { - hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!hidinput || !input_dev) { - kfree(hidinput); - input_free_device(input_dev); - err("Out of memory during hid input probe"); - return -1; - } - - input_dev->private = hid; - input_dev->event = hidinput_input_event; - input_dev->open = hidinput_open; - input_dev->close = hidinput_close; - - input_dev->name = hid->name; - input_dev->phys = hid->phys; - input_dev->uniq = hid->uniq; - usb_to_input_id(dev, &input_dev->id); - input_dev->cdev.dev = &hid->intf->dev; - - hidinput->input = input_dev; - list_add_tail(&hidinput->list, &hid->inputs); - } - - for (i = 0; i < report->maxfield; i++) - for (j = 0; j < report->field[i]->maxusage; j++) - hidinput_configure_usage(hidinput, report->field[i], - report->field[i]->usage + j); - - if (hid->quirks & HID_QUIRK_MULTI_INPUT) { - /* This will leave hidinput NULL, so that it - * allocates another one if we have more inputs on - * the same interface. Some devices (e.g. Happ's - * UGCI) cram a lot of unrelated inputs into the - * same interface. */ - hidinput->report = report; - input_register_device(hidinput->input); - hidinput = NULL; - } - } - - /* This only gets called when we are a single-input (most of the - * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is - * only useful in this case, and not for multi-input quirks. */ - if (hidinput) { - hid_ff_init(hid); - input_register_device(hidinput->input); - } - - return 0; -} - -void hidinput_disconnect(struct hid_device *hid) -{ - struct hid_input *hidinput, *next; - list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { - list_del(&hidinput->list); - input_unregister_device(hidinput->input); - kfree(hidinput); - } -} diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index 93da222b6da8..e977ba3d17e0 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -29,7 +29,7 @@ #include #include -#include "hid.h" +#include struct device_type { u16 idVendor; diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c index 5420c13eb8eb..b4caea3864e3 100644 --- a/drivers/usb/input/hid-pidff.c +++ b/drivers/usb/input/hid-pidff.c @@ -28,7 +28,9 @@ #include #include -#include "hid.h" +#include + +#include "usbhid.h" #define PID_EFFECTS_MAX 64 diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c index 2d5be4c318ac..1cd1418ad6ac 100644 --- a/drivers/usb/input/hid-tmff.c +++ b/drivers/usb/input/hid-tmff.c @@ -32,7 +32,7 @@ #undef DEBUG #include -#include "hid.h" +#include /* Usages for thrustmaster devices I know about */ #define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c index d2ce3214572c..af1bfae39dce 100644 --- a/drivers/usb/input/hid-zpff.c +++ b/drivers/usb/input/hid-zpff.c @@ -27,7 +27,7 @@ #include #include -#include "hid.h" +#include struct zpff_device { struct hid_report *report; diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h deleted file mode 100644 index 76ad68d9edfd..000000000000 --- a/drivers/usb/input/hid.h +++ /dev/null @@ -1,540 +0,0 @@ -#ifndef __HID_H -#define __HID_H - -/* - * $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $ - * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2001 Vojtech Pavlik - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include - -/* - * USB HID (Human Interface Device) interface class code - */ - -#define USB_INTERFACE_CLASS_HID 3 - -/* - * USB HID interface subclass and protocol codes - */ - -#define USB_INTERFACE_SUBCLASS_BOOT 1 -#define USB_INTERFACE_PROTOCOL_KEYBOARD 1 -#define USB_INTERFACE_PROTOCOL_MOUSE 2 - -/* - * HID class requests - */ - -#define HID_REQ_GET_REPORT 0x01 -#define HID_REQ_GET_IDLE 0x02 -#define HID_REQ_GET_PROTOCOL 0x03 -#define HID_REQ_SET_REPORT 0x09 -#define HID_REQ_SET_IDLE 0x0A -#define HID_REQ_SET_PROTOCOL 0x0B - -/* - * HID class descriptor types - */ - -#define HID_DT_HID (USB_TYPE_CLASS | 0x01) -#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02) -#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) - -/* - * We parse each description item into this structure. Short items data - * values are expanded to 32-bit signed int, long items contain a pointer - * into the data area. - */ - -struct hid_item { - unsigned format; - __u8 size; - __u8 type; - __u8 tag; - union { - __u8 u8; - __s8 s8; - __u16 u16; - __s16 s16; - __u32 u32; - __s32 s32; - __u8 *longdata; - } data; -}; - -/* - * HID report item format - */ - -#define HID_ITEM_FORMAT_SHORT 0 -#define HID_ITEM_FORMAT_LONG 1 - -/* - * Special tag indicating long items - */ - -#define HID_ITEM_TAG_LONG 15 - -/* - * HID report descriptor item type (prefix bit 2,3) - */ - -#define HID_ITEM_TYPE_MAIN 0 -#define HID_ITEM_TYPE_GLOBAL 1 -#define HID_ITEM_TYPE_LOCAL 2 -#define HID_ITEM_TYPE_RESERVED 3 - -/* - * HID report descriptor main item tags - */ - -#define HID_MAIN_ITEM_TAG_INPUT 8 -#define HID_MAIN_ITEM_TAG_OUTPUT 9 -#define HID_MAIN_ITEM_TAG_FEATURE 11 -#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 -#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 - -/* - * HID report descriptor main item contents - */ - -#define HID_MAIN_ITEM_CONSTANT 0x001 -#define HID_MAIN_ITEM_VARIABLE 0x002 -#define HID_MAIN_ITEM_RELATIVE 0x004 -#define HID_MAIN_ITEM_WRAP 0x008 -#define HID_MAIN_ITEM_NONLINEAR 0x010 -#define HID_MAIN_ITEM_NO_PREFERRED 0x020 -#define HID_MAIN_ITEM_NULL_STATE 0x040 -#define HID_MAIN_ITEM_VOLATILE 0x080 -#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 - -/* - * HID report descriptor collection item types - */ - -#define HID_COLLECTION_PHYSICAL 0 -#define HID_COLLECTION_APPLICATION 1 -#define HID_COLLECTION_LOGICAL 2 - -/* - * HID report descriptor global item tags - */ - -#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 -#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 -#define HID_GLOBAL_ITEM_TAG_UNIT 6 -#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 -#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 -#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 -#define HID_GLOBAL_ITEM_TAG_PUSH 10 -#define HID_GLOBAL_ITEM_TAG_POP 11 - -/* - * HID report descriptor local item tags - */ - -#define HID_LOCAL_ITEM_TAG_USAGE 0 -#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 -#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 -#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 -#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 -#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 -#define HID_LOCAL_ITEM_TAG_DELIMITER 10 - -/* - * HID usage tables - */ - -#define HID_USAGE_PAGE 0xffff0000 - -#define HID_UP_UNDEFINED 0x00000000 -#define HID_UP_GENDESK 0x00010000 -#define HID_UP_SIMULATION 0x00020000 -#define HID_UP_KEYBOARD 0x00070000 -#define HID_UP_LED 0x00080000 -#define HID_UP_BUTTON 0x00090000 -#define HID_UP_ORDINAL 0x000a0000 -#define HID_UP_CONSUMER 0x000c0000 -#define HID_UP_DIGITIZER 0x000d0000 -#define HID_UP_PID 0x000f0000 -#define HID_UP_HPVENDOR 0xff7f0000 -#define HID_UP_MSVENDOR 0xff000000 -#define HID_UP_CUSTOM 0x00ff0000 -#define HID_UP_LOGIVENDOR 0xffbc0000 - -#define HID_USAGE 0x0000ffff - -#define HID_GD_POINTER 0x00010001 -#define HID_GD_MOUSE 0x00010002 -#define HID_GD_JOYSTICK 0x00010004 -#define HID_GD_GAMEPAD 0x00010005 -#define HID_GD_KEYBOARD 0x00010006 -#define HID_GD_KEYPAD 0x00010007 -#define HID_GD_MULTIAXIS 0x00010008 -#define HID_GD_X 0x00010030 -#define HID_GD_Y 0x00010031 -#define HID_GD_Z 0x00010032 -#define HID_GD_RX 0x00010033 -#define HID_GD_RY 0x00010034 -#define HID_GD_RZ 0x00010035 -#define HID_GD_SLIDER 0x00010036 -#define HID_GD_DIAL 0x00010037 -#define HID_GD_WHEEL 0x00010038 -#define HID_GD_HATSWITCH 0x00010039 -#define HID_GD_BUFFER 0x0001003a -#define HID_GD_BYTECOUNT 0x0001003b -#define HID_GD_MOTION 0x0001003c -#define HID_GD_START 0x0001003d -#define HID_GD_SELECT 0x0001003e -#define HID_GD_VX 0x00010040 -#define HID_GD_VY 0x00010041 -#define HID_GD_VZ 0x00010042 -#define HID_GD_VBRX 0x00010043 -#define HID_GD_VBRY 0x00010044 -#define HID_GD_VBRZ 0x00010045 -#define HID_GD_VNO 0x00010046 -#define HID_GD_FEATURE 0x00010047 -#define HID_GD_UP 0x00010090 -#define HID_GD_DOWN 0x00010091 -#define HID_GD_RIGHT 0x00010092 -#define HID_GD_LEFT 0x00010093 - -/* - * HID report types --- Ouch! HID spec says 1 2 3! - */ - -#define HID_INPUT_REPORT 0 -#define HID_OUTPUT_REPORT 1 -#define HID_FEATURE_REPORT 2 - -/* - * HID device quirks. - */ - -#define HID_QUIRK_INVERT 0x00000001 -#define HID_QUIRK_NOTOUCH 0x00000002 -#define HID_QUIRK_IGNORE 0x00000004 -#define HID_QUIRK_NOGET 0x00000008 -#define HID_QUIRK_HIDDEV 0x00000010 -#define HID_QUIRK_BADPAD 0x00000020 -#define HID_QUIRK_MULTI_INPUT 0x00000040 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 -#define HID_QUIRK_MIGHTYMOUSE 0x00000400 -#define HID_QUIRK_CYMOTION 0x00000800 -#define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000 -#define HID_QUIRK_POWERBOOK_FN_ON 0x00002000 -#define HID_QUIRK_INVERT_HWHEEL 0x00004000 -#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000 -#define HID_QUIRK_BAD_RELATIVE_KEYS 0x00010000 - -/* - * This is the global environment of the parser. This information is - * persistent for main-items. The global environment can be saved and - * restored with PUSH/POP statements. - */ - -struct hid_global { - unsigned usage_page; - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned unit; - unsigned report_id; - unsigned report_size; - unsigned report_count; -}; - -/* - * This is the local environment. It is persistent up the next main-item. - */ - -#define HID_MAX_DESCRIPTOR_SIZE 4096 -#define HID_MAX_USAGES 1024 -#define HID_DEFAULT_NUM_COLLECTIONS 16 - -struct hid_local { - unsigned usage[HID_MAX_USAGES]; /* usage array */ - unsigned collection_index[HID_MAX_USAGES]; /* collection index array */ - unsigned usage_index; - unsigned usage_minimum; - unsigned delimiter_depth; - unsigned delimiter_branch; -}; - -/* - * This is the collection stack. We climb up the stack to determine - * application and function of each field. - */ - -struct hid_collection { - unsigned type; - unsigned usage; - unsigned level; -}; - -struct hid_usage { - unsigned hid; /* hid usage code */ - unsigned collection_index; /* index into collection array */ - /* hidinput data */ - __u16 code; /* input driver code */ - __u8 type; /* input driver type */ - __s8 hat_min; /* hat switch fun */ - __s8 hat_max; /* ditto */ - __s8 hat_dir; /* ditto */ -}; - -struct hid_input; - -struct hid_field { - unsigned physical; /* physical usage for this field */ - unsigned logical; /* logical usage for this field */ - unsigned application; /* application usage for this field */ - struct hid_usage *usage; /* usage table for this function */ - unsigned maxusage; /* maximum usage index */ - unsigned flags; /* main-item flags (i.e. volatile,array,constant) */ - unsigned report_offset; /* bit offset in the report */ - unsigned report_size; /* size of this field in the report */ - unsigned report_count; /* number of this field in the report */ - unsigned report_type; /* (input,output,feature) */ - __s32 *value; /* last known value(s) */ - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned unit; - struct hid_report *report; /* associated report */ - unsigned index; /* index into report->field[] */ - /* hidinput data */ - struct hid_input *hidinput; /* associated input structure */ - __u16 dpad; /* dpad input code */ -}; - -#define HID_MAX_FIELDS 64 - -struct hid_report { - struct list_head list; - unsigned id; /* id of this report */ - unsigned type; /* report type */ - struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ - unsigned maxfield; /* maximum valid field index */ - unsigned size; /* size of the report (bits) */ - struct hid_device *device; /* associated device */ -}; - -struct hid_report_enum { - unsigned numbered; - struct list_head report_list; - struct hid_report *report_id_hash[256]; -}; - -#define HID_REPORT_TYPES 3 - -#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ -#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */ -#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ -#define HID_OUTPUT_FIFO_SIZE 64 - -struct hid_control_fifo { - unsigned char dir; - struct hid_report *report; -}; - -#define HID_CLAIMED_INPUT 1 -#define HID_CLAIMED_HIDDEV 2 - -#define HID_CTRL_RUNNING 1 -#define HID_OUT_RUNNING 2 -#define HID_IN_RUNNING 3 -#define HID_RESET_PENDING 4 -#define HID_SUSPENDED 5 -#define HID_CLEAR_HALT 6 - -struct hid_input { - struct list_head list; - struct hid_report *report; - struct input_dev *input; -}; - -struct hid_device { /* device report descriptor */ - __u8 *rdesc; - unsigned rsize; - struct hid_collection *collection; /* List of HID collections */ - unsigned collection_size; /* Number of allocated hid_collections */ - unsigned maxcollection; /* Number of parsed collections */ - unsigned maxapplication; /* Number of applications */ - unsigned version; /* HID version */ - unsigned country; /* HID country */ - struct hid_report_enum report_enum[HID_REPORT_TYPES]; - - struct usb_device *dev; /* USB device */ - struct usb_interface *intf; /* USB interface */ - int ifnum; /* USB interface number */ - - unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ - struct timer_list io_retry; /* Retry timer */ - unsigned long stop_retry; /* Time to give up, in jiffies */ - unsigned int retry_delay; /* Delay length in ms */ - struct work_struct reset_work; /* Task context for resets */ - - unsigned int bufsize; /* URB buffer size */ - - struct urb *urbin; /* Input URB */ - char *inbuf; /* Input buffer */ - dma_addr_t inbuf_dma; /* Input buffer dma */ - spinlock_t inlock; /* Input fifo spinlock */ - - struct urb *urbctrl; /* Control URB */ - struct usb_ctrlrequest *cr; /* Control request struct */ - dma_addr_t cr_dma; /* Control request struct dma */ - struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ - unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ - char *ctrlbuf; /* Control buffer */ - dma_addr_t ctrlbuf_dma; /* Control buffer dma */ - spinlock_t ctrllock; /* Control fifo spinlock */ - - struct urb *urbout; /* Output URB */ - struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ - unsigned char outhead, outtail; /* Output pipe fifo head & tail */ - char *outbuf; /* Output buffer */ - dma_addr_t outbuf_dma; /* Output buffer dma */ - spinlock_t outlock; /* Output fifo spinlock */ - - unsigned claimed; /* Claimed by hidinput, hiddev? */ - unsigned quirks; /* Various quirks the device can pull on us */ - - struct list_head inputs; /* The list of inputs */ - void *hiddev; /* The hiddev structure */ - int minor; /* Hiddev minor number */ - - wait_queue_head_t wait; /* For sleeping */ - - int open; /* is the device open by anyone? */ - char name[128]; /* Device name */ - char phys[64]; /* Device physical location */ - char uniq[64]; /* Device unique identifier (serial #) */ - -#ifdef CONFIG_USB_HIDINPUT_POWERBOOK - unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; - unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; -#endif -}; - -#define HID_GLOBAL_STACK_SIZE 4 -#define HID_COLLECTION_STACK_SIZE 4 - -struct hid_parser { - struct hid_global global; - struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; - unsigned global_stack_ptr; - struct hid_local local; - unsigned collection_stack[HID_COLLECTION_STACK_SIZE]; - unsigned collection_stack_ptr; - struct hid_device *device; -}; - -struct hid_class_descriptor { - __u8 bDescriptorType; - __u16 wDescriptorLength; -} __attribute__ ((packed)); - -struct hid_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u16 bcdHID; - __u8 bCountryCode; - __u8 bNumDescriptors; - - struct hid_class_descriptor desc[1]; -} __attribute__ ((packed)); - -#ifdef DEBUG -#include "hid-debug.h" -#else -#define hid_dump_input(a,b) do { } while (0) -#define hid_dump_device(c) do { } while (0) -#define hid_dump_field(a,b) do { } while (0) -#define resolv_usage(a) do { } while (0) -#define resolv_event(a,b) do { } while (0) -#endif - -#endif - -#ifdef CONFIG_USB_HIDINPUT -/* Applications from HID Usage Tables 4/8/99 Version 1.1 */ -/* We ignore a few input applications that are not widely used */ -#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001)) -extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); -extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); -extern int hidinput_connect(struct hid_device *); -extern void hidinput_disconnect(struct hid_device *); -#else -#define IS_INPUT_APPLICATION(a) (0) -static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { } -static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { } -static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; } -static inline void hidinput_disconnect(struct hid_device *hid) { } -#endif - -int hid_open(struct hid_device *); -void hid_close(struct hid_device *); -int hid_set_field(struct hid_field *, unsigned, __s32); -void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir); -void hid_init_reports(struct hid_device *hid); -int hid_wait_io(struct hid_device* hid); - - -#ifdef CONFIG_HID_FF -int hid_ff_init(struct hid_device *hid); - -int hid_lgff_init(struct hid_device *hid); -int hid_tmff_init(struct hid_device *hid); -int hid_zpff_init(struct hid_device *hid); -#ifdef CONFIG_HID_PID -int hid_pidff_init(struct hid_device *hid); -#else -static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; } -#endif - -#else -static inline int hid_ff_init(struct hid_device *hid) { return -1; } -#endif - diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 7dc14d0cacc1..cbd3b60d93bb 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -32,8 +32,9 @@ #include #include #include -#include "hid.h" +#include #include +#include "usbhid.h" #ifdef CONFIG_USB_DYNAMIC_MINORS #define HIDDEV_MINOR_BASE 0 diff --git a/include/linux/hid-debug.h b/include/linux/hid-debug.h new file mode 100644 index 000000000000..f04d6d75c098 --- /dev/null +++ b/include/linux/hid-debug.h @@ -0,0 +1,757 @@ +/* + * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $ + * + * (c) 1999 Andreas Gal + * (c) 2000-2001 Vojtech Pavlik + * + * Some debug stuff for the HID parser. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include + +struct hid_usage_entry { + unsigned page; + unsigned usage; + char *description; +}; + +static const struct hid_usage_entry hid_usage_table[] = { + { 0, 0, "Undefined" }, + { 1, 0, "GenericDesktop" }, + {0, 0x01, "Pointer"}, + {0, 0x02, "Mouse"}, + {0, 0x04, "Joystick"}, + {0, 0x05, "GamePad"}, + {0, 0x06, "Keyboard"}, + {0, 0x07, "Keypad"}, + {0, 0x08, "MultiAxis"}, + {0, 0x30, "X"}, + {0, 0x31, "Y"}, + {0, 0x32, "Z"}, + {0, 0x33, "Rx"}, + {0, 0x34, "Ry"}, + {0, 0x35, "Rz"}, + {0, 0x36, "Slider"}, + {0, 0x37, "Dial"}, + {0, 0x38, "Wheel"}, + {0, 0x39, "HatSwitch"}, + {0, 0x3a, "CountedBuffer"}, + {0, 0x3b, "ByteCount"}, + {0, 0x3c, "MotionWakeup"}, + {0, 0x3d, "Start"}, + {0, 0x3e, "Select"}, + {0, 0x40, "Vx"}, + {0, 0x41, "Vy"}, + {0, 0x42, "Vz"}, + {0, 0x43, "Vbrx"}, + {0, 0x44, "Vbry"}, + {0, 0x45, "Vbrz"}, + {0, 0x46, "Vno"}, + {0, 0x80, "SystemControl"}, + {0, 0x81, "SystemPowerDown"}, + {0, 0x82, "SystemSleep"}, + {0, 0x83, "SystemWakeUp"}, + {0, 0x84, "SystemContextMenu"}, + {0, 0x85, "SystemMainMenu"}, + {0, 0x86, "SystemAppMenu"}, + {0, 0x87, "SystemMenuHelp"}, + {0, 0x88, "SystemMenuExit"}, + {0, 0x89, "SystemMenuSelect"}, + {0, 0x8a, "SystemMenuRight"}, + {0, 0x8b, "SystemMenuLeft"}, + {0, 0x8c, "SystemMenuUp"}, + {0, 0x8d, "SystemMenuDown"}, + {0, 0x90, "D-PadUp"}, + {0, 0x91, "D-PadDown"}, + {0, 0x92, "D-PadRight"}, + {0, 0x93, "D-PadLeft"}, + { 2, 0, "Simulation" }, + {0, 0xb0, "Aileron"}, + {0, 0xb1, "AileronTrim"}, + {0, 0xb2, "Anti-Torque"}, + {0, 0xb3, "Autopilot"}, + {0, 0xb4, "Chaff"}, + {0, 0xb5, "Collective"}, + {0, 0xb6, "DiveBrake"}, + {0, 0xb7, "ElectronicCountermeasures"}, + {0, 0xb8, "Elevator"}, + {0, 0xb9, "ElevatorTrim"}, + {0, 0xba, "Rudder"}, + {0, 0xbb, "Throttle"}, + {0, 0xbc, "FlightCommunications"}, + {0, 0xbd, "FlareRelease"}, + {0, 0xbe, "LandingGear"}, + {0, 0xbf, "ToeBrake"}, + { 7, 0, "Keyboard" }, + { 8, 0, "LED" }, + {0, 0x01, "NumLock"}, + {0, 0x02, "CapsLock"}, + {0, 0x03, "ScrollLock"}, + {0, 0x04, "Compose"}, + {0, 0x05, "Kana"}, + {0, 0x4b, "GenericIndicator"}, + { 9, 0, "Button" }, + { 10, 0, "Ordinal" }, + { 12, 0, "Consumer" }, + {0, 0x238, "HorizontalWheel"}, + { 13, 0, "Digitizers" }, + {0, 0x01, "Digitizer"}, + {0, 0x02, "Pen"}, + {0, 0x03, "LightPen"}, + {0, 0x04, "TouchScreen"}, + {0, 0x05, "TouchPad"}, + {0, 0x20, "Stylus"}, + {0, 0x21, "Puck"}, + {0, 0x22, "Finger"}, + {0, 0x30, "TipPressure"}, + {0, 0x31, "BarrelPressure"}, + {0, 0x32, "InRange"}, + {0, 0x33, "Touch"}, + {0, 0x34, "UnTouch"}, + {0, 0x35, "Tap"}, + {0, 0x39, "TabletFunctionKey"}, + {0, 0x3a, "ProgramChangeKey"}, + {0, 0x3c, "Invert"}, + {0, 0x42, "TipSwitch"}, + {0, 0x43, "SecondaryTipSwitch"}, + {0, 0x44, "BarrelSwitch"}, + {0, 0x45, "Eraser"}, + {0, 0x46, "TabletPick"}, + { 15, 0, "PhysicalInterfaceDevice" }, + {0, 0x00, "Undefined"}, + {0, 0x01, "Physical_Interface_Device"}, + {0, 0x20, "Normal"}, + {0, 0x21, "Set_Effect_Report"}, + {0, 0x22, "Effect_Block_Index"}, + {0, 0x23, "Parameter_Block_Offset"}, + {0, 0x24, "ROM_Flag"}, + {0, 0x25, "Effect_Type"}, + {0, 0x26, "ET_Constant_Force"}, + {0, 0x27, "ET_Ramp"}, + {0, 0x28, "ET_Custom_Force_Data"}, + {0, 0x30, "ET_Square"}, + {0, 0x31, "ET_Sine"}, + {0, 0x32, "ET_Triangle"}, + {0, 0x33, "ET_Sawtooth_Up"}, + {0, 0x34, "ET_Sawtooth_Down"}, + {0, 0x40, "ET_Spring"}, + {0, 0x41, "ET_Damper"}, + {0, 0x42, "ET_Inertia"}, + {0, 0x43, "ET_Friction"}, + {0, 0x50, "Duration"}, + {0, 0x51, "Sample_Period"}, + {0, 0x52, "Gain"}, + {0, 0x53, "Trigger_Button"}, + {0, 0x54, "Trigger_Repeat_Interval"}, + {0, 0x55, "Axes_Enable"}, + {0, 0x56, "Direction_Enable"}, + {0, 0x57, "Direction"}, + {0, 0x58, "Type_Specific_Block_Offset"}, + {0, 0x59, "Block_Type"}, + {0, 0x5A, "Set_Envelope_Report"}, + {0, 0x5B, "Attack_Level"}, + {0, 0x5C, "Attack_Time"}, + {0, 0x5D, "Fade_Level"}, + {0, 0x5E, "Fade_Time"}, + {0, 0x5F, "Set_Condition_Report"}, + {0, 0x60, "CP_Offset"}, + {0, 0x61, "Positive_Coefficient"}, + {0, 0x62, "Negative_Coefficient"}, + {0, 0x63, "Positive_Saturation"}, + {0, 0x64, "Negative_Saturation"}, + {0, 0x65, "Dead_Band"}, + {0, 0x66, "Download_Force_Sample"}, + {0, 0x67, "Isoch_Custom_Force_Enable"}, + {0, 0x68, "Custom_Force_Data_Report"}, + {0, 0x69, "Custom_Force_Data"}, + {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, + {0, 0x6B, "Set_Custom_Force_Report"}, + {0, 0x6C, "Custom_Force_Data_Offset"}, + {0, 0x6D, "Sample_Count"}, + {0, 0x6E, "Set_Periodic_Report"}, + {0, 0x6F, "Offset"}, + {0, 0x70, "Magnitude"}, + {0, 0x71, "Phase"}, + {0, 0x72, "Period"}, + {0, 0x73, "Set_Constant_Force_Report"}, + {0, 0x74, "Set_Ramp_Force_Report"}, + {0, 0x75, "Ramp_Start"}, + {0, 0x76, "Ramp_End"}, + {0, 0x77, "Effect_Operation_Report"}, + {0, 0x78, "Effect_Operation"}, + {0, 0x79, "Op_Effect_Start"}, + {0, 0x7A, "Op_Effect_Start_Solo"}, + {0, 0x7B, "Op_Effect_Stop"}, + {0, 0x7C, "Loop_Count"}, + {0, 0x7D, "Device_Gain_Report"}, + {0, 0x7E, "Device_Gain"}, + {0, 0x7F, "PID_Pool_Report"}, + {0, 0x80, "RAM_Pool_Size"}, + {0, 0x81, "ROM_Pool_Size"}, + {0, 0x82, "ROM_Effect_Block_Count"}, + {0, 0x83, "Simultaneous_Effects_Max"}, + {0, 0x84, "Pool_Alignment"}, + {0, 0x85, "PID_Pool_Move_Report"}, + {0, 0x86, "Move_Source"}, + {0, 0x87, "Move_Destination"}, + {0, 0x88, "Move_Length"}, + {0, 0x89, "PID_Block_Load_Report"}, + {0, 0x8B, "Block_Load_Status"}, + {0, 0x8C, "Block_Load_Success"}, + {0, 0x8D, "Block_Load_Full"}, + {0, 0x8E, "Block_Load_Error"}, + {0, 0x8F, "Block_Handle"}, + {0, 0x90, "PID_Block_Free_Report"}, + {0, 0x91, "Type_Specific_Block_Handle"}, + {0, 0x92, "PID_State_Report"}, + {0, 0x94, "Effect_Playing"}, + {0, 0x95, "PID_Device_Control_Report"}, + {0, 0x96, "PID_Device_Control"}, + {0, 0x97, "DC_Enable_Actuators"}, + {0, 0x98, "DC_Disable_Actuators"}, + {0, 0x99, "DC_Stop_All_Effects"}, + {0, 0x9A, "DC_Device_Reset"}, + {0, 0x9B, "DC_Device_Pause"}, + {0, 0x9C, "DC_Device_Continue"}, + {0, 0x9F, "Device_Paused"}, + {0, 0xA0, "Actuators_Enabled"}, + {0, 0xA4, "Safety_Switch"}, + {0, 0xA5, "Actuator_Override_Switch"}, + {0, 0xA6, "Actuator_Power"}, + {0, 0xA7, "Start_Delay"}, + {0, 0xA8, "Parameter_Block_Size"}, + {0, 0xA9, "Device_Managed_Pool"}, + {0, 0xAA, "Shared_Parameter_Blocks"}, + {0, 0xAB, "Create_New_Effect_Report"}, + {0, 0xAC, "RAM_Pool_Available"}, + { 0x84, 0, "Power Device" }, + { 0x84, 0x02, "PresentStatus" }, + { 0x84, 0x03, "ChangeStatus" }, + { 0x84, 0x04, "UPS" }, + { 0x84, 0x05, "PowerSupply" }, + { 0x84, 0x10, "BatterySystem" }, + { 0x84, 0x11, "BatterySystemID" }, + { 0x84, 0x12, "Battery" }, + { 0x84, 0x13, "BatteryID" }, + { 0x84, 0x14, "Charger" }, + { 0x84, 0x15, "ChargerID" }, + { 0x84, 0x16, "PowerConverter" }, + { 0x84, 0x17, "PowerConverterID" }, + { 0x84, 0x18, "OutletSystem" }, + { 0x84, 0x19, "OutletSystemID" }, + { 0x84, 0x1a, "Input" }, + { 0x84, 0x1b, "InputID" }, + { 0x84, 0x1c, "Output" }, + { 0x84, 0x1d, "OutputID" }, + { 0x84, 0x1e, "Flow" }, + { 0x84, 0x1f, "FlowID" }, + { 0x84, 0x20, "Outlet" }, + { 0x84, 0x21, "OutletID" }, + { 0x84, 0x22, "Gang" }, + { 0x84, 0x24, "PowerSummary" }, + { 0x84, 0x25, "PowerSummaryID" }, + { 0x84, 0x30, "Voltage" }, + { 0x84, 0x31, "Current" }, + { 0x84, 0x32, "Frequency" }, + { 0x84, 0x33, "ApparentPower" }, + { 0x84, 0x35, "PercentLoad" }, + { 0x84, 0x40, "ConfigVoltage" }, + { 0x84, 0x41, "ConfigCurrent" }, + { 0x84, 0x43, "ConfigApparentPower" }, + { 0x84, 0x53, "LowVoltageTransfer" }, + { 0x84, 0x54, "HighVoltageTransfer" }, + { 0x84, 0x56, "DelayBeforeStartup" }, + { 0x84, 0x57, "DelayBeforeShutdown" }, + { 0x84, 0x58, "Test" }, + { 0x84, 0x5a, "AudibleAlarmControl" }, + { 0x84, 0x60, "Present" }, + { 0x84, 0x61, "Good" }, + { 0x84, 0x62, "InternalFailure" }, + { 0x84, 0x65, "Overload" }, + { 0x84, 0x66, "OverCharged" }, + { 0x84, 0x67, "OverTemperature" }, + { 0x84, 0x68, "ShutdownRequested" }, + { 0x84, 0x69, "ShutdownImminent" }, + { 0x84, 0x6b, "SwitchOn/Off" }, + { 0x84, 0x6c, "Switchable" }, + { 0x84, 0x6d, "Used" }, + { 0x84, 0x6e, "Boost" }, + { 0x84, 0x73, "CommunicationLost" }, + { 0x84, 0xfd, "iManufacturer" }, + { 0x84, 0xfe, "iProduct" }, + { 0x84, 0xff, "iSerialNumber" }, + { 0x85, 0, "Battery System" }, + { 0x85, 0x01, "SMBBatteryMode" }, + { 0x85, 0x02, "SMBBatteryStatus" }, + { 0x85, 0x03, "SMBAlarmWarning" }, + { 0x85, 0x04, "SMBChargerMode" }, + { 0x85, 0x05, "SMBChargerStatus" }, + { 0x85, 0x06, "SMBChargerSpecInfo" }, + { 0x85, 0x07, "SMBSelectorState" }, + { 0x85, 0x08, "SMBSelectorPresets" }, + { 0x85, 0x09, "SMBSelectorInfo" }, + { 0x85, 0x29, "RemainingCapacityLimit" }, + { 0x85, 0x2c, "CapacityMode" }, + { 0x85, 0x42, "BelowRemainingCapacityLimit" }, + { 0x85, 0x44, "Charging" }, + { 0x85, 0x45, "Discharging" }, + { 0x85, 0x4b, "NeedReplacement" }, + { 0x85, 0x66, "RemainingCapacity" }, + { 0x85, 0x68, "RunTimeToEmpty" }, + { 0x85, 0x6a, "AverageTimeToFull" }, + { 0x85, 0x83, "DesignCapacity" }, + { 0x85, 0x85, "ManufacturerDate" }, + { 0x85, 0x89, "iDeviceChemistry" }, + { 0x85, 0x8b, "Rechargable" }, + { 0x85, 0x8f, "iOEMInformation" }, + { 0x85, 0x8d, "CapacityGranularity1" }, + { 0x85, 0xd0, "ACPresent" }, + /* pages 0xff00 to 0xffff are vendor-specific */ + { 0xffff, 0, "Vendor-specific-FF" }, + { 0, 0, NULL } +}; + +static void resolv_usage_page(unsigned page) { + const struct hid_usage_entry *p; + + for (p = hid_usage_table; p->description; p++) + if (p->page == page) { + printk("%s", p->description); + return; + } + printk("%04x", page); +} + +static void resolv_usage(unsigned usage) { + const struct hid_usage_entry *p; + + resolv_usage_page(usage >> 16); + printk("."); + for (p = hid_usage_table; p->description; p++) + if (p->page == (usage >> 16)) { + for(++p; p->description && p->usage != 0; p++) + if (p->usage == (usage & 0xffff)) { + printk("%s", p->description); + return; + } + break; + } + printk("%04x", usage & 0xffff); +} + +__inline__ static void tab(int n) { + while (n--) printk(" "); +} + +static void hid_dump_field(struct hid_field *field, int n) { + int j; + + if (field->physical) { + tab(n); + printk("Physical("); + resolv_usage(field->physical); printk(")\n"); + } + if (field->logical) { + tab(n); + printk("Logical("); + resolv_usage(field->logical); printk(")\n"); + } + tab(n); printk("Usage(%d)\n", field->maxusage); + for (j = 0; j < field->maxusage; j++) { + tab(n+2);resolv_usage(field->usage[j].hid); printk("\n"); + } + if (field->logical_minimum != field->logical_maximum) { + tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); + tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); + } + if (field->physical_minimum != field->physical_maximum) { + tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); + tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); + } + if (field->unit_exponent) { + tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); + } + if (field->unit) { + char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; + char *units[5][8] = { + { "None", "None", "None", "None", "None", "None", "None", "None" }, + { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, + { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, + { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }, + { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" } + }; + + int i; + int sys; + __u32 data = field->unit; + + /* First nibble tells us which system we're in. */ + sys = data & 0xf; + data >>= 4; + + if(sys > 4) { + tab(n); printk("Unit(Invalid)\n"); + } + else { + int earlier_unit = 0; + + tab(n); printk("Unit(%s : ", systems[sys]); + + for (i=1 ; i>= 4; + if (nibble != 0) { + if(earlier_unit++ > 0) + printk("*"); + printk("%s", units[sys][i]); + if(nibble != 1) { + /* This is a _signed_ nibble(!) */ + + int val = nibble & 0x7; + if(nibble & 0x08) + val = -((0x7 & ~val) +1); + printk("^%d", val); + } + } + } + printk(")\n"); + } + } + tab(n); printk("Report Size(%u)\n", field->report_size); + tab(n); printk("Report Count(%u)\n", field->report_count); + tab(n); printk("Report Offset(%u)\n", field->report_offset); + + tab(n); printk("Flags( "); + j = field->flags; + printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); + printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); + printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); + printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); + printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); + printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); + printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); + printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); + printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); + printk(")\n"); +} + +static void __attribute__((unused)) hid_dump_device(struct hid_device *device) { + struct hid_report_enum *report_enum; + struct hid_report *report; + struct list_head *list; + unsigned i,k; + static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; + + for (i = 0; i < HID_REPORT_TYPES; i++) { + report_enum = device->report_enum + i; + list = report_enum->report_list.next; + while (list != &report_enum->report_list) { + report = (struct hid_report *) list; + tab(2); + printk("%s", table[i]); + if (report->id) + printk("(%d)", report->id); + printk("[%s]", table[report->type]); + printk("\n"); + for (k = 0; k < report->maxfield; k++) { + tab(4); + printk("Field(%d)\n", k); + hid_dump_field(report->field[k], 6); + } + list = list->next; + } + } +} + +static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) { + printk("hid-debug: input "); + resolv_usage(usage->hid); + printk(" = %d\n", value); +} + + +static char *events[EV_MAX + 1] = { + [EV_SYN] = "Sync", [EV_KEY] = "Key", + [EV_REL] = "Relative", [EV_ABS] = "Absolute", + [EV_MSC] = "Misc", [EV_LED] = "LED", + [EV_SND] = "Sound", [EV_REP] = "Repeat", + [EV_FF] = "ForceFeedback", [EV_PWR] = "Power", + [EV_FF_STATUS] = "ForceFeedbackStatus", +}; + +static char *syncs[2] = { + [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", +}; +static char *keys[KEY_MAX + 1] = { + [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", + [KEY_1] = "1", [KEY_2] = "2", + [KEY_3] = "3", [KEY_4] = "4", + [KEY_5] = "5", [KEY_6] = "6", + [KEY_7] = "7", [KEY_8] = "8", + [KEY_9] = "9", [KEY_0] = "0", + [KEY_MINUS] = "Minus", [KEY_EQUAL] = "Equal", + [KEY_BACKSPACE] = "Backspace", [KEY_TAB] = "Tab", + [KEY_Q] = "Q", [KEY_W] = "W", + [KEY_E] = "E", [KEY_R] = "R", + [KEY_T] = "T", [KEY_Y] = "Y", + [KEY_U] = "U", [KEY_I] = "I", + [KEY_O] = "O", [KEY_P] = "P", + [KEY_LEFTBRACE] = "LeftBrace", [KEY_RIGHTBRACE] = "RightBrace", + [KEY_ENTER] = "Enter", [KEY_LEFTCTRL] = "LeftControl", + [KEY_A] = "A", [KEY_S] = "S", + [KEY_D] = "D", [KEY_F] = "F", + [KEY_G] = "G", [KEY_H] = "H", + [KEY_J] = "J", [KEY_K] = "K", + [KEY_L] = "L", [KEY_SEMICOLON] = "Semicolon", + [KEY_APOSTROPHE] = "Apostrophe", [KEY_GRAVE] = "Grave", + [KEY_LEFTSHIFT] = "LeftShift", [KEY_BACKSLASH] = "BackSlash", + [KEY_Z] = "Z", [KEY_X] = "X", + [KEY_C] = "C", [KEY_V] = "V", + [KEY_B] = "B", [KEY_N] = "N", + [KEY_M] = "M", [KEY_COMMA] = "Comma", + [KEY_DOT] = "Dot", [KEY_SLASH] = "Slash", + [KEY_RIGHTSHIFT] = "RightShift", [KEY_KPASTERISK] = "KPAsterisk", + [KEY_LEFTALT] = "LeftAlt", [KEY_SPACE] = "Space", + [KEY_CAPSLOCK] = "CapsLock", [KEY_F1] = "F1", + [KEY_F2] = "F2", [KEY_F3] = "F3", + [KEY_F4] = "F4", [KEY_F5] = "F5", + [KEY_F6] = "F6", [KEY_F7] = "F7", + [KEY_F8] = "F8", [KEY_F9] = "F9", + [KEY_F10] = "F10", [KEY_NUMLOCK] = "NumLock", + [KEY_SCROLLLOCK] = "ScrollLock", [KEY_KP7] = "KP7", + [KEY_KP8] = "KP8", [KEY_KP9] = "KP9", + [KEY_KPMINUS] = "KPMinus", [KEY_KP4] = "KP4", + [KEY_KP5] = "KP5", [KEY_KP6] = "KP6", + [KEY_KPPLUS] = "KPPlus", [KEY_KP1] = "KP1", + [KEY_KP2] = "KP2", [KEY_KP3] = "KP3", + [KEY_KP0] = "KP0", [KEY_KPDOT] = "KPDot", + [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd", + [KEY_F11] = "F11", [KEY_F12] = "F12", + [KEY_RO] = "RO", [KEY_KATAKANA] = "Katakana", + [KEY_HIRAGANA] = "HIRAGANA", [KEY_HENKAN] = "Henkan", + [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan", + [KEY_KPJPCOMMA] = "KPJpComma", [KEY_KPENTER] = "KPEnter", + [KEY_RIGHTCTRL] = "RightCtrl", [KEY_KPSLASH] = "KPSlash", + [KEY_SYSRQ] = "SysRq", [KEY_RIGHTALT] = "RightAlt", + [KEY_LINEFEED] = "LineFeed", [KEY_HOME] = "Home", + [KEY_UP] = "Up", [KEY_PAGEUP] = "PageUp", + [KEY_LEFT] = "Left", [KEY_RIGHT] = "Right", + [KEY_END] = "End", [KEY_DOWN] = "Down", + [KEY_PAGEDOWN] = "PageDown", [KEY_INSERT] = "Insert", + [KEY_DELETE] = "Delete", [KEY_MACRO] = "Macro", + [KEY_MUTE] = "Mute", [KEY_VOLUMEDOWN] = "VolumeDown", + [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power", + [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus", + [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma", + [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja", + [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta", + [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose", + [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again", + [KEY_PROPS] = "Props", [KEY_UNDO] = "Undo", + [KEY_FRONT] = "Front", [KEY_COPY] = "Copy", + [KEY_OPEN] = "Open", [KEY_PASTE] = "Paste", + [KEY_FIND] = "Find", [KEY_CUT] = "Cut", + [KEY_HELP] = "Help", [KEY_MENU] = "Menu", + [KEY_CALC] = "Calc", [KEY_SETUP] = "Setup", + [KEY_SLEEP] = "Sleep", [KEY_WAKEUP] = "WakeUp", + [KEY_FILE] = "File", [KEY_SENDFILE] = "SendFile", + [KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer", + [KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2", + [KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS", + [KEY_COFFEE] = "Coffee", [KEY_DIRECTION] = "Direction", + [KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail", + [KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer", + [KEY_BACK] = "Back", [KEY_FORWARD] = "Forward", + [KEY_CLOSECD] = "CloseCD", [KEY_EJECTCD] = "EjectCD", + [KEY_EJECTCLOSECD] = "EjectCloseCD", [KEY_NEXTSONG] = "NextSong", + [KEY_PLAYPAUSE] = "PlayPause", [KEY_PREVIOUSSONG] = "PreviousSong", + [KEY_STOPCD] = "StopCD", [KEY_RECORD] = "Record", + [KEY_REWIND] = "Rewind", [KEY_PHONE] = "Phone", + [KEY_ISO] = "ISOKey", [KEY_CONFIG] = "Config", + [KEY_HOMEPAGE] = "HomePage", [KEY_REFRESH] = "Refresh", + [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move", + [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp", + [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis", + [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New", + [KEY_REDO] = "Redo", [KEY_F13] = "F13", + [KEY_F14] = "F14", [KEY_F15] = "F15", + [KEY_F16] = "F16", [KEY_F17] = "F17", + [KEY_F18] = "F18", [KEY_F19] = "F19", + [KEY_F20] = "F20", [KEY_F21] = "F21", + [KEY_F22] = "F22", [KEY_F23] = "F23", + [KEY_F24] = "F24", [KEY_PLAYCD] = "PlayCD", + [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3", + [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend", + [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play", + [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost", + [KEY_PRINT] = "Print", [KEY_HP] = "HP", + [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound", + [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email", + [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search", + [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance", + [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop", + [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel", + [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp", + [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", + [BTN_0] = "Btn0", [BTN_1] = "Btn1", + [BTN_2] = "Btn2", [BTN_3] = "Btn3", + [BTN_4] = "Btn4", [BTN_5] = "Btn5", + [BTN_6] = "Btn6", [BTN_7] = "Btn7", + [BTN_8] = "Btn8", [BTN_9] = "Btn9", + [BTN_LEFT] = "LeftBtn", [BTN_RIGHT] = "RightBtn", + [BTN_MIDDLE] = "MiddleBtn", [BTN_SIDE] = "SideBtn", + [BTN_EXTRA] = "ExtraBtn", [BTN_FORWARD] = "ForwardBtn", + [BTN_BACK] = "BackBtn", [BTN_TASK] = "TaskBtn", + [BTN_TRIGGER] = "Trigger", [BTN_THUMB] = "ThumbBtn", + [BTN_THUMB2] = "ThumbBtn2", [BTN_TOP] = "TopBtn", + [BTN_TOP2] = "TopBtn2", [BTN_PINKIE] = "PinkieBtn", + [BTN_BASE] = "BaseBtn", [BTN_BASE2] = "BaseBtn2", + [BTN_BASE3] = "BaseBtn3", [BTN_BASE4] = "BaseBtn4", + [BTN_BASE5] = "BaseBtn5", [BTN_BASE6] = "BaseBtn6", + [BTN_DEAD] = "BtnDead", [BTN_A] = "BtnA", + [BTN_B] = "BtnB", [BTN_C] = "BtnC", + [BTN_X] = "BtnX", [BTN_Y] = "BtnY", + [BTN_Z] = "BtnZ", [BTN_TL] = "BtnTL", + [BTN_TR] = "BtnTR", [BTN_TL2] = "BtnTL2", + [BTN_TR2] = "BtnTR2", [BTN_SELECT] = "BtnSelect", + [BTN_START] = "BtnStart", [BTN_MODE] = "BtnMode", + [BTN_THUMBL] = "BtnThumbL", [BTN_THUMBR] = "BtnThumbR", + [BTN_TOOL_PEN] = "ToolPen", [BTN_TOOL_RUBBER] = "ToolRubber", + [BTN_TOOL_BRUSH] = "ToolBrush", [BTN_TOOL_PENCIL] = "ToolPencil", + [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger", + [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", + [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", + [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", + [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn", + [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", + [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", + [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", + [KEY_OPTION] = "Option", [KEY_INFO] = "Info", + [KEY_TIME] = "Time", [KEY_VENDOR] = "Vendor", + [KEY_ARCHIVE] = "Archive", [KEY_PROGRAM] = "Program", + [KEY_CHANNEL] = "Channel", [KEY_FAVORITES] = "Favorites", + [KEY_EPG] = "EPG", [KEY_PVR] = "PVR", + [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language", + [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle", + [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom", + [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard", + [KEY_SCREEN] = "Screen", [KEY_PC] = "PC", + [KEY_TV] = "TV", [KEY_TV2] = "TV2", + [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2", + [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2", + [KEY_CD] = "CD", [KEY_TAPE] = "Tape", + [KEY_RADIO] = "Radio", [KEY_TUNER] = "Tuner", + [KEY_PLAYER] = "Player", [KEY_TEXT] = "Text", + [KEY_DVD] = "DVD", [KEY_AUX] = "Aux", + [KEY_MP3] = "MP3", [KEY_AUDIO] = "Audio", + [KEY_VIDEO] = "Video", [KEY_DIRECTORY] = "Directory", + [KEY_LIST] = "List", [KEY_MEMO] = "Memo", + [KEY_CALENDAR] = "Calendar", [KEY_RED] = "Red", + [KEY_GREEN] = "Green", [KEY_YELLOW] = "Yellow", + [KEY_BLUE] = "Blue", [KEY_CHANNELUP] = "ChannelUp", + [KEY_CHANNELDOWN] = "ChannelDown", [KEY_FIRST] = "First", + [KEY_LAST] = "Last", [KEY_AB] = "AB", + [KEY_NEXT] = "Next", [KEY_RESTART] = "Restart", + [KEY_SLOW] = "Slow", [KEY_SHUFFLE] = "Shuffle", + [KEY_BREAK] = "Break", [KEY_PREVIOUS] = "Previous", + [KEY_DIGITS] = "Digits", [KEY_TEEN] = "TEEN", + [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL", + [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine", + [KEY_DEL_LINE] = "DeleteLine", + [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", + [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", + [KEY_DOCUMENTS] = "Documents", + [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", + [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", + [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", + [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F", + [KEY_FN_S] = "Fn+S", + [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2", + [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4", + [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6", + [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8", + [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10", + [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12", + [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle", + [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", + [KEY_KBDILLUMUP] = "KbdIlluminationUp", + [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", +}; + +static char *relatives[REL_MAX + 1] = { + [REL_X] = "X", [REL_Y] = "Y", + [REL_Z] = "Z", [REL_HWHEEL] = "HWheel", + [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel", + [REL_MISC] = "Misc", +}; + +static char *absolutes[ABS_MAX + 1] = { + [ABS_X] = "X", [ABS_Y] = "Y", + [ABS_Z] = "Z", [ABS_RX] = "Rx", + [ABS_RY] = "Ry", [ABS_RZ] = "Rz", + [ABS_THROTTLE] = "Throttle", [ABS_RUDDER] = "Rudder", + [ABS_WHEEL] = "Wheel", [ABS_GAS] = "Gas", + [ABS_BRAKE] = "Brake", [ABS_HAT0X] = "Hat0X", + [ABS_HAT0Y] = "Hat0Y", [ABS_HAT1X] = "Hat1X", + [ABS_HAT1Y] = "Hat1Y", [ABS_HAT2X] = "Hat2X", + [ABS_HAT2Y] = "Hat2Y", [ABS_HAT3X] = "Hat3X", + [ABS_HAT3Y] = "Hat 3Y", [ABS_PRESSURE] = "Pressure", + [ABS_DISTANCE] = "Distance", [ABS_TILT_X] = "XTilt", + [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "Tool Width", + [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", +}; + +static char *misc[MSC_MAX + 1] = { + [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", + [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" +}; + +static char *leds[LED_MAX + 1] = { + [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", + [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", + [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", + [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute", + [LED_MISC] = "Misc", +}; + +static char *repeats[REP_MAX + 1] = { + [REP_DELAY] = "Delay", [REP_PERIOD] = "Period" +}; + +static char *sounds[SND_MAX + 1] = { + [SND_CLICK] = "Click", [SND_BELL] = "Bell", + [SND_TONE] = "Tone" +}; + +static char **names[EV_MAX + 1] = { + [EV_SYN] = syncs, [EV_KEY] = keys, + [EV_REL] = relatives, [EV_ABS] = absolutes, + [EV_MSC] = misc, [EV_LED] = leds, + [EV_SND] = sounds, [EV_REP] = repeats, +}; + +static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) { + + printk("%s.%s", events[type] ? events[type] : "?", + names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); +} diff --git a/include/linux/hid.h b/include/linux/hid.h new file mode 100644 index 000000000000..ee567ae6fec1 --- /dev/null +++ b/include/linux/hid.h @@ -0,0 +1,540 @@ +#ifndef __HID_H +#define __HID_H + +/* + * $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $ + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2006 Jiri Kosina + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +/* + * USB HID (Human Interface Device) interface class code + */ + +#define USB_INTERFACE_CLASS_HID 3 + +/* + * USB HID interface subclass and protocol codes + */ + +#define USB_INTERFACE_SUBCLASS_BOOT 1 +#define USB_INTERFACE_PROTOCOL_KEYBOARD 1 +#define USB_INTERFACE_PROTOCOL_MOUSE 2 + +/* + * HID class requests + */ + +#define HID_REQ_GET_REPORT 0x01 +#define HID_REQ_GET_IDLE 0x02 +#define HID_REQ_GET_PROTOCOL 0x03 +#define HID_REQ_SET_REPORT 0x09 +#define HID_REQ_SET_IDLE 0x0A +#define HID_REQ_SET_PROTOCOL 0x0B + +/* + * HID class descriptor types + */ + +#define HID_DT_HID (USB_TYPE_CLASS | 0x01) +#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02) +#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) + +/* + * We parse each description item into this structure. Short items data + * values are expanded to 32-bit signed int, long items contain a pointer + * into the data area. + */ + +struct hid_item { + unsigned format; + __u8 size; + __u8 type; + __u8 tag; + union { + __u8 u8; + __s8 s8; + __u16 u16; + __s16 s16; + __u32 u32; + __s32 s32; + __u8 *longdata; + } data; +}; + +/* + * HID report item format + */ + +#define HID_ITEM_FORMAT_SHORT 0 +#define HID_ITEM_FORMAT_LONG 1 + +/* + * Special tag indicating long items + */ + +#define HID_ITEM_TAG_LONG 15 + +/* + * HID report descriptor item type (prefix bit 2,3) + */ + +#define HID_ITEM_TYPE_MAIN 0 +#define HID_ITEM_TYPE_GLOBAL 1 +#define HID_ITEM_TYPE_LOCAL 2 +#define HID_ITEM_TYPE_RESERVED 3 + +/* + * HID report descriptor main item tags + */ + +#define HID_MAIN_ITEM_TAG_INPUT 8 +#define HID_MAIN_ITEM_TAG_OUTPUT 9 +#define HID_MAIN_ITEM_TAG_FEATURE 11 +#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 +#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 + +/* + * HID report descriptor main item contents + */ + +#define HID_MAIN_ITEM_CONSTANT 0x001 +#define HID_MAIN_ITEM_VARIABLE 0x002 +#define HID_MAIN_ITEM_RELATIVE 0x004 +#define HID_MAIN_ITEM_WRAP 0x008 +#define HID_MAIN_ITEM_NONLINEAR 0x010 +#define HID_MAIN_ITEM_NO_PREFERRED 0x020 +#define HID_MAIN_ITEM_NULL_STATE 0x040 +#define HID_MAIN_ITEM_VOLATILE 0x080 +#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 + +/* + * HID report descriptor collection item types + */ + +#define HID_COLLECTION_PHYSICAL 0 +#define HID_COLLECTION_APPLICATION 1 +#define HID_COLLECTION_LOGICAL 2 + +/* + * HID report descriptor global item tags + */ + +#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 +#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 +#define HID_GLOBAL_ITEM_TAG_UNIT 6 +#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 +#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 +#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 +#define HID_GLOBAL_ITEM_TAG_PUSH 10 +#define HID_GLOBAL_ITEM_TAG_POP 11 + +/* + * HID report descriptor local item tags + */ + +#define HID_LOCAL_ITEM_TAG_USAGE 0 +#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 +#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 +#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 +#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 +#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 +#define HID_LOCAL_ITEM_TAG_DELIMITER 10 + +/* + * HID usage tables + */ + +#define HID_USAGE_PAGE 0xffff0000 + +#define HID_UP_UNDEFINED 0x00000000 +#define HID_UP_GENDESK 0x00010000 +#define HID_UP_SIMULATION 0x00020000 +#define HID_UP_KEYBOARD 0x00070000 +#define HID_UP_LED 0x00080000 +#define HID_UP_BUTTON 0x00090000 +#define HID_UP_ORDINAL 0x000a0000 +#define HID_UP_CONSUMER 0x000c0000 +#define HID_UP_DIGITIZER 0x000d0000 +#define HID_UP_PID 0x000f0000 +#define HID_UP_HPVENDOR 0xff7f0000 +#define HID_UP_MSVENDOR 0xff000000 +#define HID_UP_CUSTOM 0x00ff0000 +#define HID_UP_LOGIVENDOR 0xffbc0000 + +#define HID_USAGE 0x0000ffff + +#define HID_GD_POINTER 0x00010001 +#define HID_GD_MOUSE 0x00010002 +#define HID_GD_JOYSTICK 0x00010004 +#define HID_GD_GAMEPAD 0x00010005 +#define HID_GD_KEYBOARD 0x00010006 +#define HID_GD_KEYPAD 0x00010007 +#define HID_GD_MULTIAXIS 0x00010008 +#define HID_GD_X 0x00010030 +#define HID_GD_Y 0x00010031 +#define HID_GD_Z 0x00010032 +#define HID_GD_RX 0x00010033 +#define HID_GD_RY 0x00010034 +#define HID_GD_RZ 0x00010035 +#define HID_GD_SLIDER 0x00010036 +#define HID_GD_DIAL 0x00010037 +#define HID_GD_WHEEL 0x00010038 +#define HID_GD_HATSWITCH 0x00010039 +#define HID_GD_BUFFER 0x0001003a +#define HID_GD_BYTECOUNT 0x0001003b +#define HID_GD_MOTION 0x0001003c +#define HID_GD_START 0x0001003d +#define HID_GD_SELECT 0x0001003e +#define HID_GD_VX 0x00010040 +#define HID_GD_VY 0x00010041 +#define HID_GD_VZ 0x00010042 +#define HID_GD_VBRX 0x00010043 +#define HID_GD_VBRY 0x00010044 +#define HID_GD_VBRZ 0x00010045 +#define HID_GD_VNO 0x00010046 +#define HID_GD_FEATURE 0x00010047 +#define HID_GD_UP 0x00010090 +#define HID_GD_DOWN 0x00010091 +#define HID_GD_RIGHT 0x00010092 +#define HID_GD_LEFT 0x00010093 + +/* + * HID report types --- Ouch! HID spec says 1 2 3! + */ + +#define HID_INPUT_REPORT 0 +#define HID_OUTPUT_REPORT 1 +#define HID_FEATURE_REPORT 2 + +/* + * HID device quirks. + */ + +#define HID_QUIRK_INVERT 0x00000001 +#define HID_QUIRK_NOTOUCH 0x00000002 +#define HID_QUIRK_IGNORE 0x00000004 +#define HID_QUIRK_NOGET 0x00000008 +#define HID_QUIRK_HIDDEV 0x00000010 +#define HID_QUIRK_BADPAD 0x00000020 +#define HID_QUIRK_MULTI_INPUT 0x00000040 +#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080 +#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 +#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 +#define HID_QUIRK_MIGHTYMOUSE 0x00000400 +#define HID_QUIRK_CYMOTION 0x00000800 +#define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000 +#define HID_QUIRK_POWERBOOK_FN_ON 0x00002000 +#define HID_QUIRK_INVERT_HWHEEL 0x00004000 +#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000 +#define HID_QUIRK_BAD_RELATIVE_KEYS 0x00010000 + +/* + * This is the global environment of the parser. This information is + * persistent for main-items. The global environment can be saved and + * restored with PUSH/POP statements. + */ + +struct hid_global { + unsigned usage_page; + __s32 logical_minimum; + __s32 logical_maximum; + __s32 physical_minimum; + __s32 physical_maximum; + __s32 unit_exponent; + unsigned unit; + unsigned report_id; + unsigned report_size; + unsigned report_count; +}; + +/* + * This is the local environment. It is persistent up the next main-item. + */ + +#define HID_MAX_DESCRIPTOR_SIZE 4096 +#define HID_MAX_USAGES 1024 +#define HID_DEFAULT_NUM_COLLECTIONS 16 + +struct hid_local { + unsigned usage[HID_MAX_USAGES]; /* usage array */ + unsigned collection_index[HID_MAX_USAGES]; /* collection index array */ + unsigned usage_index; + unsigned usage_minimum; + unsigned delimiter_depth; + unsigned delimiter_branch; +}; + +/* + * This is the collection stack. We climb up the stack to determine + * application and function of each field. + */ + +struct hid_collection { + unsigned type; + unsigned usage; + unsigned level; +}; + +struct hid_usage { + unsigned hid; /* hid usage code */ + unsigned collection_index; /* index into collection array */ + /* hidinput data */ + __u16 code; /* input driver code */ + __u8 type; /* input driver type */ + __s8 hat_min; /* hat switch fun */ + __s8 hat_max; /* ditto */ + __s8 hat_dir; /* ditto */ +}; + +struct hid_input; + +struct hid_field { + unsigned physical; /* physical usage for this field */ + unsigned logical; /* logical usage for this field */ + unsigned application; /* application usage for this field */ + struct hid_usage *usage; /* usage table for this function */ + unsigned maxusage; /* maximum usage index */ + unsigned flags; /* main-item flags (i.e. volatile,array,constant) */ + unsigned report_offset; /* bit offset in the report */ + unsigned report_size; /* size of this field in the report */ + unsigned report_count; /* number of this field in the report */ + unsigned report_type; /* (input,output,feature) */ + __s32 *value; /* last known value(s) */ + __s32 logical_minimum; + __s32 logical_maximum; + __s32 physical_minimum; + __s32 physical_maximum; + __s32 unit_exponent; + unsigned unit; + struct hid_report *report; /* associated report */ + unsigned index; /* index into report->field[] */ + /* hidinput data */ + struct hid_input *hidinput; /* associated input structure */ + __u16 dpad; /* dpad input code */ +}; + +#define HID_MAX_FIELDS 64 + +struct hid_report { + struct list_head list; + unsigned id; /* id of this report */ + unsigned type; /* report type */ + struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ + unsigned maxfield; /* maximum valid field index */ + unsigned size; /* size of the report (bits) */ + struct hid_device *device; /* associated device */ +}; + +struct hid_report_enum { + unsigned numbered; + struct list_head report_list; + struct hid_report *report_id_hash[256]; +}; + +#define HID_REPORT_TYPES 3 + +#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ +#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */ +#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ +#define HID_OUTPUT_FIFO_SIZE 64 + +struct hid_control_fifo { + unsigned char dir; + struct hid_report *report; +}; + +#define HID_CLAIMED_INPUT 1 +#define HID_CLAIMED_HIDDEV 2 + +#define HID_CTRL_RUNNING 1 +#define HID_OUT_RUNNING 2 +#define HID_IN_RUNNING 3 +#define HID_RESET_PENDING 4 +#define HID_SUSPENDED 5 +#define HID_CLEAR_HALT 6 + +struct hid_input { + struct list_head list; + struct hid_report *report; + struct input_dev *input; +}; + +struct hid_device { /* device report descriptor */ + __u8 *rdesc; + unsigned rsize; + struct hid_collection *collection; /* List of HID collections */ + unsigned collection_size; /* Number of allocated hid_collections */ + unsigned maxcollection; /* Number of parsed collections */ + unsigned maxapplication; /* Number of applications */ + unsigned version; /* HID version */ + unsigned country; /* HID country */ + struct hid_report_enum report_enum[HID_REPORT_TYPES]; + + struct usb_device *dev; /* USB device */ + struct usb_interface *intf; /* USB interface */ + int ifnum; /* USB interface number */ + + unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ + struct timer_list io_retry; /* Retry timer */ + unsigned long stop_retry; /* Time to give up, in jiffies */ + unsigned int retry_delay; /* Delay length in ms */ + struct work_struct reset_work; /* Task context for resets */ + + unsigned int bufsize; /* URB buffer size */ + + struct urb *urbin; /* Input URB */ + char *inbuf; /* Input buffer */ + dma_addr_t inbuf_dma; /* Input buffer dma */ + spinlock_t inlock; /* Input fifo spinlock */ + + struct urb *urbctrl; /* Control URB */ + struct usb_ctrlrequest *cr; /* Control request struct */ + dma_addr_t cr_dma; /* Control request struct dma */ + struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ + unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ + char *ctrlbuf; /* Control buffer */ + dma_addr_t ctrlbuf_dma; /* Control buffer dma */ + spinlock_t ctrllock; /* Control fifo spinlock */ + + struct urb *urbout; /* Output URB */ + struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ + unsigned char outhead, outtail; /* Output pipe fifo head & tail */ + char *outbuf; /* Output buffer */ + dma_addr_t outbuf_dma; /* Output buffer dma */ + spinlock_t outlock; /* Output fifo spinlock */ + + unsigned claimed; /* Claimed by hidinput, hiddev? */ + unsigned quirks; /* Various quirks the device can pull on us */ + + struct list_head inputs; /* The list of inputs */ + void *hiddev; /* The hiddev structure */ + int minor; /* Hiddev minor number */ + + wait_queue_head_t wait; /* For sleeping */ + + int open; /* is the device open by anyone? */ + char name[128]; /* Device name */ + char phys[64]; /* Device physical location */ + char uniq[64]; /* Device unique identifier (serial #) */ + +#ifdef CONFIG_USB_HIDINPUT_POWERBOOK + unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; + unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; +#endif +}; + +#define HID_GLOBAL_STACK_SIZE 4 +#define HID_COLLECTION_STACK_SIZE 4 + +struct hid_parser { + struct hid_global global; + struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; + unsigned global_stack_ptr; + struct hid_local local; + unsigned collection_stack[HID_COLLECTION_STACK_SIZE]; + unsigned collection_stack_ptr; + struct hid_device *device; +}; + +struct hid_class_descriptor { + __u8 bDescriptorType; + __u16 wDescriptorLength; +} __attribute__ ((packed)); + +struct hid_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u16 bcdHID; + __u8 bCountryCode; + __u8 bNumDescriptors; + + struct hid_class_descriptor desc[1]; +} __attribute__ ((packed)); + +#ifdef DEBUG +#include "hid-debug.h" +#else +#define hid_dump_input(a,b) do { } while (0) +#define hid_dump_device(c) do { } while (0) +#define hid_dump_field(a,b) do { } while (0) +#define resolv_usage(a) do { } while (0) +#define resolv_event(a,b) do { } while (0) +#endif + +#ifdef CONFIG_HID +/* Applications from HID Usage Tables 4/8/99 Version 1.1 */ +/* We ignore a few input applications that are not widely used */ +#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001)) +extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); +extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); +extern int hidinput_connect(struct hid_device *); +extern void hidinput_disconnect(struct hid_device *); +#else +#define IS_INPUT_APPLICATION(a) (0) +static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { } +static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { } +static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; } +static inline void hidinput_disconnect(struct hid_device *hid) { } +#endif + +int hid_set_field(struct hid_field *, unsigned, __s32); +int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); +void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt); +void hid_output_report(struct hid_report *report, __u8 *data); +void hid_free_device(struct hid_device *device); +struct hid_device *hid_parse_report(__u8 *start, unsigned size); + +#ifdef CONFIG_HID_FF +int hid_ff_init(struct hid_device *hid); + +int hid_lgff_init(struct hid_device *hid); +int hid_tmff_init(struct hid_device *hid); +int hid_zpff_init(struct hid_device *hid); +#ifdef CONFIG_HID_PID +int hid_pidff_init(struct hid_device *hid); +#else +static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; } +#endif + +#else +static inline int hid_ff_init(struct hid_device *hid) { return -1; } +#endif +#endif + -- cgit v1.2.3 From 229695e51efc4ed5e04ab471c82591d0f432909d Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:40:53 +0100 Subject: [PATCH] Generic HID layer - API - fixed generic API (added neccessary EXPORT_SYMBOL, fixed hid.h to provide correct prototypes) - extended hid_device with open/close/event function pointers to driver-specific functions - added driver specific driver_data to hid_device Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 22 ++++++++++++---------- drivers/hid/hid-input.c | 19 +++++++++++++------ drivers/usb/input/hid-core.c | 9 ++++++++- drivers/usb/input/hid-ff.c | 2 ++ drivers/usb/input/hiddev.c | 2 +- include/linux/hid.h | 36 ++++++++++++++++++++++++++++-------- 6 files changed, 64 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 689ae16adf33..8474a7923322 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1,5 +1,5 @@ /* - * USB HID support for Linux + * HID support for Linux * * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2005 Vojtech Pavlik @@ -31,8 +31,6 @@ #undef DEBUG #undef DEBUG_DATA -#include - #include #include @@ -538,7 +536,7 @@ static void hid_free_report(struct hid_report *report) * Free a device structure, all reports, and all fields. */ -static void hid_free_device(struct hid_device *device) +void hid_free_device(struct hid_device *device) { unsigned i,j; @@ -555,6 +553,7 @@ static void hid_free_device(struct hid_device *device) kfree(device->rdesc); kfree(device); } +EXPORT_SYMBOL_GPL(hid_free_device); /* * Fetch a report description item from the data stream. We support long @@ -629,7 +628,7 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) * enumerated, fields are attached to these reports. */ -static struct hid_device *hid_parse_report(__u8 *start, unsigned size) +struct hid_device *hid_parse_report(__u8 *start, unsigned size) { struct hid_device *device; struct hid_parser *parser; @@ -719,6 +718,7 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) kfree(parser); return NULL; } +EXPORT_SYMBOL_GPL(hid_parse_report); /* * Convert a signed n-bit integer to signed 32-bit integer. Common @@ -767,10 +767,10 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) WARN_ON(n > 32); report += offset >> 3; /* adjust byte index */ - offset &= 7; /* now only need bit offset into one byte */ + offset &= 7; /* now only need bit offset into one byte */ x = get_unaligned((u64 *) report); x = le64_to_cpu(x); - x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ + x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ return (u32) x; } @@ -829,7 +829,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s * reporting to the layer). */ -static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt) +void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt) { unsigned n; unsigned count = field->report_count; @@ -875,7 +875,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u exit: kfree(value); } - +EXPORT_SYMBOL_GPL(hid_input_field); /* * Output the field into the report. @@ -900,7 +900,7 @@ static void hid_output_field(struct hid_field *field, __u8 *data) * Create a report. */ -static void hid_output_report(struct hid_report *report, __u8 *data) +void hid_output_report(struct hid_report *report, __u8 *data) { unsigned n; @@ -910,6 +910,7 @@ static void hid_output_report(struct hid_report *report, __u8 *data) for (n = 0; n < report->maxfield; n++) hid_output_field(report->field[n], data); } +EXPORT_SYMBOL_GPL(hid_output_report); /* * Set a field value. The report this field belongs to has to be @@ -937,4 +938,5 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) field->value[offset] = value; return 0; } +EXPORT_SYMBOL_GPL(hid_set_field); diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d459005062e0..6d3d80ba9582 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -727,8 +727,9 @@ void hidinput_report_event(struct hid_device *hid, struct hid_report *report) list_for_each_entry(hidinput, &hid->inputs, list) input_sync(hidinput->input); } +EXPORT_SYMBOL_GPL(hidinput_report_event); -static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) +int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) { struct hid_report *report; int i, j; @@ -743,6 +744,7 @@ static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsign } return -1; } +EXPORT_SYMBOL_GPL(hidinput_find_field); /* * Register the input device; print a message. @@ -752,7 +754,6 @@ static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsign int hidinput_connect(struct hid_device *hid) { - struct usb_device *dev = hid->dev; struct hid_report *report; struct hid_input *hidinput = NULL; struct input_dev *input_dev; @@ -786,14 +787,17 @@ int hidinput_connect(struct hid_device *hid) } input_dev->private = hid; - input_dev->event = hidinput_input_event; - input_dev->open = hidinput_open; - input_dev->close = hidinput_close; + input_dev->event = hid->hidinput_input_event; + input_dev->open = hid->hidinput_open; + input_dev->close = hid->hidinput_close; input_dev->name = hid->name; input_dev->phys = hid->phys; input_dev->uniq = hid->uniq; - usb_to_input_id(dev, &input_dev->id); + input_dev->id.bustype = hid->bus; + input_dev->id.vendor = hid->vendor; + input_dev->id.product = hid->product; + input_dev->id.version = hid->version; input_dev->cdev.dev = &hid->intf->dev; hidinput->input = input_dev; @@ -827,6 +831,7 @@ int hidinput_connect(struct hid_device *hid) return 0; } +EXPORT_SYMBOL_GPL(hidinput_connect); void hidinput_disconnect(struct hid_device *hid) { @@ -838,3 +843,5 @@ void hidinput_disconnect(struct hid_device *hid) kfree(hidinput); } } +EXPORT_SYMBOL_GPL(hidinput_disconnect); + diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 06e169b6a17e..462947f74135 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -497,7 +497,7 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign spin_unlock_irqrestore(&hid->ctrllock, flags); } -static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct hid_device *hid = dev->private; struct hid_field *field; @@ -1231,6 +1231,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); + hid->bus = BUS_USB; + hid->vendor = dev->descriptor.idVendor; + hid->product = dev->descriptor.idProduct; + usb_make_path(dev, hid->phys, sizeof(hid->phys)); strlcat(hid->phys, "/input", sizeof(hid->phys)); len = strlen(hid->phys); @@ -1250,6 +1254,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->urbctrl->setup_dma = hid->cr_dma; hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); + hid->hidinput_input_event = usb_hidinput_input_event; + hid->hidinput_open = hidinput_open; + hid->hidinput_close = hidinput_close; return hid; diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 4187f4ee9a9c..7ecdafa8eb7b 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -79,3 +79,5 @@ int hid_ff_init(struct hid_device* hid) return init->init(hid); } +EXPORT_SYMBOL_GPL(hid_ff_init); + diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index cbd3b60d93bb..07d7996575cd 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -197,7 +197,7 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, hiddev_send_event(hid, &uref); } - +EXPORT_SYMBOL_GPL(hiddev_hid_event); void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { diff --git a/include/linux/hid.h b/include/linux/hid.h index ee567ae6fec1..0473b45b73b8 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -403,11 +403,17 @@ struct hid_device { /* device report descriptor */ unsigned collection_size; /* Number of allocated hid_collections */ unsigned maxcollection; /* Number of parsed collections */ unsigned maxapplication; /* Number of applications */ + unsigned short bus; /* BUS ID */ + unsigned short vendor; /* Vendor ID */ + unsigned short product; /* Product ID */ unsigned version; /* HID version */ unsigned country; /* HID country */ struct hid_report_enum report_enum[HID_REPORT_TYPES]; - struct usb_device *dev; /* USB device */ + struct usb_device *dev; /* device */ + + /* USB specific fields */ + struct usb_interface *intf; /* USB interface */ int ifnum; /* USB interface number */ @@ -454,6 +460,13 @@ struct hid_device { /* device report descriptor */ char phys[64]; /* Device physical location */ char uniq[64]; /* Device unique identifier (serial #) */ + void *driver_data; + + /* device-specific function pointers */ + int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int); + int (*hidinput_open) (struct input_dev *); + void (*hidinput_close) (struct input_dev *); + #ifdef CONFIG_USB_HIDINPUT_POWERBOOK unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; @@ -502,17 +515,15 @@ struct hid_descriptor { /* Applications from HID Usage Tables 4/8/99 Version 1.1 */ /* We ignore a few input applications that are not widely used */ #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001)) +#else +#define IS_INPUT_APPLICATION(a) (0) +#endif + +/* HID core API */ extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); extern int hidinput_connect(struct hid_device *); extern void hidinput_disconnect(struct hid_device *); -#else -#define IS_INPUT_APPLICATION(a) (0) -static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { } -static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { } -static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; } -static inline void hidinput_disconnect(struct hid_device *hid) { } -#endif int hid_set_field(struct hid_field *, unsigned, __s32); int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); @@ -536,5 +547,14 @@ static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; } #else static inline int hid_ff_init(struct hid_device *hid) { return -1; } #endif +#ifdef DEBUG +#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \ + __FILE__ , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif + +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , \ + __FILE__ , ## arg) #endif -- cgit v1.2.3 From 4916b3a57fc94664677d439b911b8aaf86c7ec23 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:41:03 +0100 Subject: [PATCH] Generic HID layer - USB API - 'dev' in struct hid_device changed from struct usb_device to struct device and fixed all the users - renamed functions which are part of USB HID API from 'hid_*' to 'usbhid_*' - force feedback initialization moved from common part into USB-specific driver - added usbhid.h header for USB HID API users - removed USB-specific fields from struct hid_device and moved them to new usbhid_device, which is pointed to by hid_device->driver_data - fixed all USB users to use this new structure Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-input.c | 10 +- drivers/usb/input/hid-core.c | 419 +++++++++++++++++++++++------------------- drivers/usb/input/hid-ff.c | 4 +- drivers/usb/input/hid-lgff.c | 5 +- drivers/usb/input/hid-pidff.c | 54 +++--- drivers/usb/input/hid-tmff.c | 3 +- drivers/usb/input/hid-zpff.c | 5 +- drivers/usb/input/hiddev.c | 31 ++-- drivers/usb/input/usbhid.h | 84 +++++++++ include/linux/hid.h | 36 +--- 10 files changed, 370 insertions(+), 281 deletions(-) create mode 100644 drivers/usb/input/usbhid.h (limited to 'include/linux') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 6d3d80ba9582..e542ef971c46 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -798,8 +798,7 @@ int hidinput_connect(struct hid_device *hid) input_dev->id.vendor = hid->vendor; input_dev->id.product = hid->product; input_dev->id.version = hid->version; - input_dev->cdev.dev = &hid->intf->dev; - + input_dev->cdev.dev = hid->dev; hidinput->input = input_dev; list_add_tail(&hidinput->list, &hid->inputs); } @@ -821,13 +820,8 @@ int hidinput_connect(struct hid_device *hid) } } - /* This only gets called when we are a single-input (most of the - * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is - * only useful in this case, and not for multi-input quirks. */ - if (hidinput) { - hid_ff_init(hid); + if (hidinput) input_register_device(hidinput->input); - } return 0; } diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 462947f74135..0991c4b751a6 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -35,6 +35,7 @@ #include #include +#include "usbhid.h" /* * Version Information @@ -66,15 +67,16 @@ static int hid_start_in(struct hid_device *hid) { unsigned long flags; int rc = 0; + struct usbhid_device *usbhid = hid->driver_data; - spin_lock_irqsave(&hid->inlock, flags); - if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) && - !test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) { - rc = usb_submit_urb(hid->urbin, GFP_ATOMIC); + spin_lock_irqsave(&usbhid->inlock, flags); + if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) && + !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { + rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); if (rc != 0) - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); } - spin_unlock_irqrestore(&hid->inlock, flags); + spin_unlock_irqrestore(&usbhid->inlock, flags); return rc; } @@ -82,8 +84,9 @@ static int hid_start_in(struct hid_device *hid) static void hid_retry_timeout(unsigned long _hid) { struct hid_device *hid = (struct hid_device *) _hid; + struct usbhid_device *usbhid = hid->driver_data; - dev_dbg(&hid->intf->dev, "retrying intr urb\n"); + dev_dbg(&usbhid->intf->dev, "retrying intr urb\n"); if (hid_start_in(hid)) hid_io_error(hid); } @@ -91,38 +94,39 @@ static void hid_retry_timeout(unsigned long _hid) /* Workqueue routine to reset the device or clear a halt */ static void hid_reset(struct work_struct *work) { - struct hid_device *hid = - container_of(work, struct hid_device, reset_work); + struct usbhid_device *usbhid = + container_of(work, struct usbhid_device, reset_work); + struct hid_device *hid = usbhid->hid; int rc_lock, rc = 0; - if (test_bit(HID_CLEAR_HALT, &hid->iofl)) { - dev_dbg(&hid->intf->dev, "clear halt\n"); - rc = usb_clear_halt(hid->dev, hid->urbin->pipe); - clear_bit(HID_CLEAR_HALT, &hid->iofl); + if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) { + dev_dbg(&usbhid->intf->dev, "clear halt\n"); + rc = usb_clear_halt(to_usb_device(hid->dev), usbhid->urbin->pipe); + clear_bit(HID_CLEAR_HALT, &usbhid->iofl); hid_start_in(hid); } - else if (test_bit(HID_RESET_PENDING, &hid->iofl)) { - dev_dbg(&hid->intf->dev, "resetting device\n"); - rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); + else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) { + dev_dbg(&usbhid->intf->dev, "resetting device\n"); + rc = rc_lock = usb_lock_device_for_reset(to_usb_device(hid->dev), usbhid->intf); if (rc_lock >= 0) { - rc = usb_reset_composite_device(hid->dev, hid->intf); + rc = usb_reset_composite_device(to_usb_device(hid->dev), usbhid->intf); if (rc_lock) - usb_unlock_device(hid->dev); + usb_unlock_device(to_usb_device(hid->dev)); } - clear_bit(HID_RESET_PENDING, &hid->iofl); + clear_bit(HID_RESET_PENDING, &usbhid->iofl); } switch (rc) { case 0: - if (!test_bit(HID_IN_RUNNING, &hid->iofl)) + if (!test_bit(HID_IN_RUNNING, &usbhid->iofl)) hid_io_error(hid); break; default: err("can't reset device, %s-%s/input%d, status %d", - hid->dev->bus->bus_name, - hid->dev->devpath, - hid->ifnum, rc); + to_usb_device(hid->dev)->bus->bus_name, + to_usb_device(hid->dev)->devpath, + usbhid->ifnum, rc); /* FALLTHROUGH */ case -EHOSTUNREACH: case -ENODEV: @@ -135,33 +139,34 @@ static void hid_reset(struct work_struct *work) static void hid_io_error(struct hid_device *hid) { unsigned long flags; + struct usbhid_device *usbhid = hid->driver_data; - spin_lock_irqsave(&hid->inlock, flags); + spin_lock_irqsave(&usbhid->inlock, flags); /* Stop when disconnected */ - if (usb_get_intfdata(hid->intf) == NULL) + if (usb_get_intfdata(usbhid->intf) == NULL) goto done; /* When an error occurs, retry at increasing intervals */ - if (hid->retry_delay == 0) { - hid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */ - hid->stop_retry = jiffies + msecs_to_jiffies(1000); - } else if (hid->retry_delay < 100) - hid->retry_delay *= 2; + if (usbhid->retry_delay == 0) { + usbhid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */ + usbhid->stop_retry = jiffies + msecs_to_jiffies(1000); + } else if (usbhid->retry_delay < 100) + usbhid->retry_delay *= 2; - if (time_after(jiffies, hid->stop_retry)) { + if (time_after(jiffies, usbhid->stop_retry)) { /* Retries failed, so do a port reset */ - if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) { - schedule_work(&hid->reset_work); + if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { + schedule_work(&usbhid->reset_work); goto done; } } - mod_timer(&hid->io_retry, - jiffies + msecs_to_jiffies(hid->retry_delay)); + mod_timer(&usbhid->io_retry, + jiffies + msecs_to_jiffies(usbhid->retry_delay)); done: - spin_unlock_irqrestore(&hid->inlock, flags); + spin_unlock_irqrestore(&usbhid->inlock, flags); } @@ -230,28 +235,29 @@ static int hid_input_report(int type, struct urb *urb, int interrupt) static void hid_irq_in(struct urb *urb) { struct hid_device *hid = urb->context; + struct usbhid_device *usbhid = hid->driver_data; int status; switch (urb->status) { case 0: /* success */ - hid->retry_delay = 0; + usbhid->retry_delay = 0; hid_input_report(HID_INPUT_REPORT, urb, 1); break; case -EPIPE: /* stall */ - clear_bit(HID_IN_RUNNING, &hid->iofl); - set_bit(HID_CLEAR_HALT, &hid->iofl); - schedule_work(&hid->reset_work); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); + set_bit(HID_CLEAR_HALT, &usbhid->iofl); + schedule_work(&usbhid->reset_work); return; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: /* unplug */ - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); return; case -EILSEQ: /* protocol error or unplug */ case -EPROTO: /* protocol error or unplug */ case -ETIME: /* protocol error or unplug */ case -ETIMEDOUT: /* Should never happen, but... */ - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); hid_io_error(hid); return; default: /* error */ @@ -260,12 +266,12 @@ static void hid_irq_in(struct urb *urb) status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); if (status != -EPERM) { err("can't resubmit intr, %s-%s/input%d, status %d", - hid->dev->bus->bus_name, - hid->dev->devpath, - hid->ifnum, status); + to_usb_device(hid->dev)->bus->bus_name, + to_usb_device(hid->dev)->devpath, + usbhid->ifnum, status); hid_io_error(hid); } } @@ -291,16 +297,17 @@ struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_u static int hid_submit_out(struct hid_device *hid) { struct hid_report *report; + struct usbhid_device *usbhid = hid->driver_data; - report = hid->out[hid->outtail]; + report = usbhid->out[usbhid->outtail]; - hid_output_report(report, hid->outbuf); - hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); - hid->urbout->dev = hid->dev; + hid_output_report(report, usbhid->outbuf); + usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); + usbhid->urbout->dev = to_usb_device(hid->dev); dbg("submitting out urb"); - if (usb_submit_urb(hid->urbout, GFP_ATOMIC)) { + if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) { err("usb_submit_urb(out) failed"); return -1; } @@ -313,42 +320,43 @@ static int hid_submit_ctrl(struct hid_device *hid) struct hid_report *report; unsigned char dir; int len; + struct usbhid_device *usbhid = hid->driver_data; - report = hid->ctrl[hid->ctrltail].report; - dir = hid->ctrl[hid->ctrltail].dir; + report = usbhid->ctrl[usbhid->ctrltail].report; + dir = usbhid->ctrl[usbhid->ctrltail].dir; len = ((report->size - 1) >> 3) + 1 + (report->id > 0); if (dir == USB_DIR_OUT) { - hid_output_report(report, hid->ctrlbuf); - hid->urbctrl->pipe = usb_sndctrlpipe(hid->dev, 0); - hid->urbctrl->transfer_buffer_length = len; + hid_output_report(report, usbhid->ctrlbuf); + usbhid->urbctrl->pipe = usb_sndctrlpipe(to_usb_device(hid->dev), 0); + usbhid->urbctrl->transfer_buffer_length = len; } else { int maxpacket, padlen; - hid->urbctrl->pipe = usb_rcvctrlpipe(hid->dev, 0); - maxpacket = usb_maxpacket(hid->dev, hid->urbctrl->pipe, 0); + usbhid->urbctrl->pipe = usb_rcvctrlpipe(to_usb_device(hid->dev), 0); + maxpacket = usb_maxpacket(to_usb_device(hid->dev), usbhid->urbctrl->pipe, 0); if (maxpacket > 0) { padlen = (len + maxpacket - 1) / maxpacket; padlen *= maxpacket; - if (padlen > hid->bufsize) - padlen = hid->bufsize; + if (padlen > usbhid->bufsize) + padlen = usbhid->bufsize; } else padlen = 0; - hid->urbctrl->transfer_buffer_length = padlen; + usbhid->urbctrl->transfer_buffer_length = padlen; } - hid->urbctrl->dev = hid->dev; + usbhid->urbctrl->dev = to_usb_device(hid->dev); - hid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; - hid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; - hid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); - hid->cr->wIndex = cpu_to_le16(hid->ifnum); - hid->cr->wLength = cpu_to_le16(len); + usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; + usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; + usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); + usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum); + usbhid->cr->wLength = cpu_to_le16(len); dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u", - hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", - hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength); + usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", + usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength); - if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) { + if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) { err("usb_submit_urb(ctrl) failed"); return -1; } @@ -363,6 +371,7 @@ static int hid_submit_ctrl(struct hid_device *hid) static void hid_irq_out(struct urb *urb) { struct hid_device *hid = urb->context; + struct usbhid_device *usbhid = hid->driver_data; unsigned long flags; int unplug = 0; @@ -380,24 +389,24 @@ static void hid_irq_out(struct urb *urb) warn("output irq status %d received", urb->status); } - spin_lock_irqsave(&hid->outlock, flags); + spin_lock_irqsave(&usbhid->outlock, flags); if (unplug) - hid->outtail = hid->outhead; + usbhid->outtail = usbhid->outhead; else - hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); + usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); - if (hid->outhead != hid->outtail) { + if (usbhid->outhead != usbhid->outtail) { if (hid_submit_out(hid)) { - clear_bit(HID_OUT_RUNNING, &hid->iofl); + clear_bit(HID_OUT_RUNNING, &usbhid->iofl); wake_up(&hid->wait); } - spin_unlock_irqrestore(&hid->outlock, flags); + spin_unlock_irqrestore(&usbhid->outlock, flags); return; } - clear_bit(HID_OUT_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->outlock, flags); + clear_bit(HID_OUT_RUNNING, &usbhid->iofl); + spin_unlock_irqrestore(&usbhid->outlock, flags); wake_up(&hid->wait); } @@ -408,15 +417,16 @@ static void hid_irq_out(struct urb *urb) static void hid_ctrl(struct urb *urb) { struct hid_device *hid = urb->context; + struct usbhid_device *usbhid = hid->driver_data; unsigned long flags; int unplug = 0; - spin_lock_irqsave(&hid->ctrllock, flags); + spin_lock_irqsave(&usbhid->ctrllock, flags); switch (urb->status) { case 0: /* success */ - if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) - hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0); + if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) + hid_input_report(usbhid->ctrl[usbhid->ctrltail].report->type, urb, 0); break; case -ESHUTDOWN: /* unplug */ unplug = 1; @@ -431,70 +441,71 @@ static void hid_ctrl(struct urb *urb) } if (unplug) - hid->ctrltail = hid->ctrlhead; + usbhid->ctrltail = usbhid->ctrlhead; else - hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); + usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); - if (hid->ctrlhead != hid->ctrltail) { + if (usbhid->ctrlhead != usbhid->ctrltail) { if (hid_submit_ctrl(hid)) { - clear_bit(HID_CTRL_RUNNING, &hid->iofl); + clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); wake_up(&hid->wait); } - spin_unlock_irqrestore(&hid->ctrllock, flags); + spin_unlock_irqrestore(&usbhid->ctrllock, flags); return; } - clear_bit(HID_CTRL_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->ctrllock, flags); + clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); + spin_unlock_irqrestore(&usbhid->ctrllock, flags); wake_up(&hid->wait); } -void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) +void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) { int head; unsigned long flags; + struct usbhid_device *usbhid = hid->driver_data; if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) return; - if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { + if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { - spin_lock_irqsave(&hid->outlock, flags); + spin_lock_irqsave(&usbhid->outlock, flags); - if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) { - spin_unlock_irqrestore(&hid->outlock, flags); + if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) { + spin_unlock_irqrestore(&usbhid->outlock, flags); warn("output queue full"); return; } - hid->out[hid->outhead] = report; - hid->outhead = head; + usbhid->out[usbhid->outhead] = report; + usbhid->outhead = head; - if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) + if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) if (hid_submit_out(hid)) - clear_bit(HID_OUT_RUNNING, &hid->iofl); + clear_bit(HID_OUT_RUNNING, &usbhid->iofl); - spin_unlock_irqrestore(&hid->outlock, flags); + spin_unlock_irqrestore(&usbhid->outlock, flags); return; } - spin_lock_irqsave(&hid->ctrllock, flags); + spin_lock_irqsave(&usbhid->ctrllock, flags); - if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) { - spin_unlock_irqrestore(&hid->ctrllock, flags); + if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) { + spin_unlock_irqrestore(&usbhid->ctrllock, flags); warn("control queue full"); return; } - hid->ctrl[hid->ctrlhead].report = report; - hid->ctrl[hid->ctrlhead].dir = dir; - hid->ctrlhead = head; + usbhid->ctrl[usbhid->ctrlhead].report = report; + usbhid->ctrl[usbhid->ctrlhead].dir = dir; + usbhid->ctrlhead = head; - if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl)) + if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) if (hid_submit_ctrl(hid)) - clear_bit(HID_CTRL_RUNNING, &hid->iofl); + clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); - spin_unlock_irqrestore(&hid->ctrllock, flags); + spin_unlock_irqrestore(&usbhid->ctrllock, flags); } static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) @@ -515,15 +526,17 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un } hid_set_field(field, offset, value); - hid_submit_report(hid, field->report, USB_DIR_OUT); + usbhid_submit_report(hid, field->report, USB_DIR_OUT); return 0; } -int hid_wait_io(struct hid_device *hid) +int usbhid_wait_io(struct hid_device *hid) { - if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &hid->iofl) && - !test_bit(HID_OUT_RUNNING, &hid->iofl)), + struct usbhid_device *usbhid = hid->driver_data; + + if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && + !test_bit(HID_OUT_RUNNING, &usbhid->iofl)), 10*HZ)) { dbg("timeout waiting for ctrl or out queue to clear"); return -1; @@ -555,7 +568,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, return result; } -int hid_open(struct hid_device *hid) +int usbhid_open(struct hid_device *hid) { ++hid->open; if (hid_start_in(hid)) @@ -563,22 +576,24 @@ int hid_open(struct hid_device *hid) return 0; } -void hid_close(struct hid_device *hid) +void usbhid_close(struct hid_device *hid) { + struct usbhid_device *usbhid = hid->driver_data; + if (!--hid->open) - usb_kill_urb(hid->urbin); + usb_kill_urb(usbhid->urbin); } static int hidinput_open(struct input_dev *dev) { struct hid_device *hid = dev->private; - return hid_open(hid); + return usbhid_open(hid); } static void hidinput_close(struct input_dev *dev) { struct hid_device *hid = dev->private; - hid_close(hid); + usbhid_close(hid); } #define USB_VENDOR_ID_PANJIT 0x134c @@ -590,26 +605,27 @@ static void hidinput_close(struct input_dev *dev) * Initialize all reports */ -void hid_init_reports(struct hid_device *hid) +void usbhid_init_reports(struct hid_device *hid) { struct hid_report *report; + struct usbhid_device *usbhid = hid->driver_data; int err, ret; list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) - hid_submit_report(hid, report, USB_DIR_IN); + usbhid_submit_report(hid, report, USB_DIR_IN); list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) - hid_submit_report(hid, report, USB_DIR_IN); + usbhid_submit_report(hid, report, USB_DIR_IN); err = 0; - ret = hid_wait_io(hid); + ret = usbhid_wait_io(hid); while (ret) { err |= ret; - if (test_bit(HID_CTRL_RUNNING, &hid->iofl)) - usb_kill_urb(hid->urbctrl); - if (test_bit(HID_OUT_RUNNING, &hid->iofl)) - usb_kill_urb(hid->urbout); - ret = hid_wait_io(hid); + if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) + usb_kill_urb(usbhid->urbctrl); + if (test_bit(HID_OUT_RUNNING, &usbhid->iofl)) + usb_kill_urb(usbhid->urbout); + ret = usbhid_wait_io(hid); } if (err) @@ -1022,13 +1038,15 @@ static void hid_find_max_report(struct hid_device *hid, unsigned int type, int * static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) { - if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->inbuf_dma))) + struct usbhid_device *usbhid = hid->driver_data; + + if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma))) return -1; - if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->outbuf_dma))) + if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma))) return -1; - if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), GFP_ATOMIC, &hid->cr_dma))) + if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma))) return -1; - if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->ctrlbuf_dma))) + if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma))) return -1; return 0; @@ -1036,14 +1054,16 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) { - if (hid->inbuf) - usb_buffer_free(dev, hid->bufsize, hid->inbuf, hid->inbuf_dma); - if (hid->outbuf) - usb_buffer_free(dev, hid->bufsize, hid->outbuf, hid->outbuf_dma); - if (hid->cr) - usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma); - if (hid->ctrlbuf) - usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma); + struct usbhid_device *usbhid = hid->driver_data; + + if (usbhid->inbuf) + usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma); + if (usbhid->outbuf) + usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma); + if (usbhid->cr) + usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma); + if (usbhid->ctrlbuf) + usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma); } /* @@ -1069,6 +1089,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) unsigned quirks = 0, rsize = 0; char *rdesc; int n, len, insize = 0; + struct usbhid_device *usbhid; /* Ignore all Wacom devices */ if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM) @@ -1138,13 +1159,19 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) kfree(rdesc); hid->quirks = quirks; - hid->bufsize = HID_MIN_BUFFER_SIZE; - hid_find_max_report(hid, HID_INPUT_REPORT, &hid->bufsize); - hid_find_max_report(hid, HID_OUTPUT_REPORT, &hid->bufsize); - hid_find_max_report(hid, HID_FEATURE_REPORT, &hid->bufsize); + if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL))) + goto fail; + + hid->driver_data = usbhid; + usbhid->hid = hid; + + usbhid->bufsize = HID_MIN_BUFFER_SIZE; + hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize); + hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize); + hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize); - if (hid->bufsize > HID_MAX_BUFFER_SIZE) - hid->bufsize = HID_MAX_BUFFER_SIZE; + if (usbhid->bufsize > HID_MAX_BUFFER_SIZE) + usbhid->bufsize = HID_MAX_BUFFER_SIZE; hid_find_max_report(hid, HID_INPUT_REPORT, &insize); @@ -1173,47 +1200,47 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) interval = hid_mousepoll_interval; if (usb_endpoint_dir_in(endpoint)) { - if (hid->urbin) + if (usbhid->urbin) continue; - if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) + if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, insize, + usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize, hid_irq_in, hid, interval); - hid->urbin->transfer_dma = hid->inbuf_dma; - hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usbhid->urbin->transfer_dma = usbhid->inbuf_dma; + usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } else { - if (hid->urbout) + if (usbhid->urbout) continue; - if (!(hid->urbout = usb_alloc_urb(0, GFP_KERNEL))) + if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress); - usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0, + usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0, hid_irq_out, hid, interval); - hid->urbout->transfer_dma = hid->outbuf_dma; - hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usbhid->urbout->transfer_dma = usbhid->outbuf_dma; + usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } } - if (!hid->urbin) { + if (!usbhid->urbin) { err("couldn't find an input interrupt endpoint"); goto fail; } init_waitqueue_head(&hid->wait); - INIT_WORK(&hid->reset_work, hid_reset); - setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid); + INIT_WORK(&usbhid->reset_work, hid_reset); + setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); - spin_lock_init(&hid->inlock); - spin_lock_init(&hid->outlock); - spin_lock_init(&hid->ctrllock); + spin_lock_init(&usbhid->inlock); + spin_lock_init(&usbhid->outlock); + spin_lock_init(&usbhid->ctrllock); hid->version = le16_to_cpu(hdesc->bcdHID); hid->country = hdesc->bCountryCode; - hid->dev = dev; - hid->intf = intf; - hid->ifnum = interface->desc.bInterfaceNumber; + hid->dev = &dev->dev; + usbhid->intf = intf; + usbhid->ifnum = interface->desc.bInterfaceNumber; hid->name[0] = 0; @@ -1245,15 +1272,15 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) hid->uniq[0] = 0; - hid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); - if (!hid->urbctrl) + usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); + if (!usbhid->urbctrl) goto fail; - usb_fill_control_urb(hid->urbctrl, dev, 0, (void *) hid->cr, - hid->ctrlbuf, 1, hid_ctrl, hid); - hid->urbctrl->setup_dma = hid->cr_dma; - hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; - hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); + usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr, + usbhid->ctrlbuf, 1, hid_ctrl, hid); + usbhid->urbctrl->setup_dma = usbhid->cr_dma; + usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; + usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); hid->hidinput_input_event = usb_hidinput_input_event; hid->hidinput_open = hidinput_open; hid->hidinput_close = hidinput_close; @@ -1261,9 +1288,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) return hid; fail: - usb_free_urb(hid->urbin); - usb_free_urb(hid->urbout); - usb_free_urb(hid->urbctrl); + usb_free_urb(usbhid->urbin); + usb_free_urb(usbhid->urbout); + usb_free_urb(usbhid->urbctrl); hid_free_buffers(dev, hid); hid_free_device(hid); @@ -1273,18 +1300,21 @@ fail: static void hid_disconnect(struct usb_interface *intf) { struct hid_device *hid = usb_get_intfdata (intf); + struct usbhid_device *usbhid; if (!hid) return; - spin_lock_irq(&hid->inlock); /* Sync with error handler */ + usbhid = hid->driver_data; + + spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ usb_set_intfdata(intf, NULL); - spin_unlock_irq(&hid->inlock); - usb_kill_urb(hid->urbin); - usb_kill_urb(hid->urbout); - usb_kill_urb(hid->urbctrl); + spin_unlock_irq(&usbhid->inlock); + usb_kill_urb(usbhid->urbin); + usb_kill_urb(usbhid->urbout); + usb_kill_urb(usbhid->urbctrl); - del_timer_sync(&hid->io_retry); + del_timer_sync(&usbhid->io_retry); flush_scheduled_work(); if (hid->claimed & HID_CLAIMED_INPUT) @@ -1292,11 +1322,11 @@ static void hid_disconnect(struct usb_interface *intf) if (hid->claimed & HID_CLAIMED_HIDDEV) hiddev_disconnect(hid); - usb_free_urb(hid->urbin); - usb_free_urb(hid->urbctrl); - usb_free_urb(hid->urbout); + usb_free_urb(usbhid->urbin); + usb_free_urb(usbhid->urbctrl); + usb_free_urb(usbhid->urbout); - hid_free_buffers(hid->dev, hid); + hid_free_buffers(to_usb_device(hid->dev), hid); hid_free_device(hid); } @@ -1313,7 +1343,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) if (!(hid = usb_hid_configure(intf))) return -ENODEV; - hid_init_reports(hid); + usbhid_init_reports(hid); hid_dump_device(hid); if (!hidinput_connect(hid)) @@ -1329,6 +1359,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) return -ENODEV; } + /* This only gets called when we are a single-input (most of the + * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is + * only useful in this case, and not for multi-input quirks. */ + if ((hid->claimed & HID_CLAIMED_INPUT) && + !(hid->quirks & HID_QUIRK_MULTI_INPUT)) + hid_ff_init(hid); + printk(KERN_INFO); if (hid->claimed & HID_CLAIMED_INPUT) @@ -1359,12 +1396,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) static int hid_suspend(struct usb_interface *intf, pm_message_t message) { struct hid_device *hid = usb_get_intfdata (intf); + struct usbhid_device *usbhid = hid->driver_data; - spin_lock_irq(&hid->inlock); /* Sync with error handler */ - set_bit(HID_SUSPENDED, &hid->iofl); - spin_unlock_irq(&hid->inlock); - del_timer(&hid->io_retry); - usb_kill_urb(hid->urbin); + spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ + set_bit(HID_SUSPENDED, &usbhid->iofl); + spin_unlock_irq(&usbhid->inlock); + del_timer(&usbhid->io_retry); + usb_kill_urb(usbhid->urbin); dev_dbg(&intf->dev, "suspend\n"); return 0; } @@ -1372,10 +1410,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) static int hid_resume(struct usb_interface *intf) { struct hid_device *hid = usb_get_intfdata (intf); + struct usbhid_device *usbhid = hid->driver_data; int status; - clear_bit(HID_SUSPENDED, &hid->iofl); - hid->retry_delay = 0; + clear_bit(HID_SUSPENDED, &usbhid->iofl); + usbhid->retry_delay = 0; status = hid_start_in(hid); dev_dbg(&intf->dev, "resume status %d\n", status); return status; diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 7ecdafa8eb7b..f8f660ee3fac 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -70,8 +70,8 @@ static struct hid_ff_initializer inits[] = { int hid_ff_init(struct hid_device* hid) { struct hid_ff_initializer *init; - int vendor = le16_to_cpu(hid->dev->descriptor.idVendor); - int product = le16_to_cpu(hid->dev->descriptor.idProduct); + int vendor = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idVendor); + int product = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idProduct); for (init = inits; init->idVendor; init++) if (init->idVendor == vendor && init->idProduct == product) diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index e977ba3d17e0..e47466268565 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -30,6 +30,7 @@ #include #include #include +#include "usbhid.h" struct device_type { u16 idVendor; @@ -75,7 +76,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef report->field[0]->value[2] = x; report->field[0]->value[3] = y; dbg("(x, y)=(%04x, %04x)", x, y); - hid_submit_report(hid, report, USB_DIR_OUT); + usbhid_submit_report(hid, report, USB_DIR_OUT); break; case FF_RUMBLE: @@ -90,7 +91,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef report->field[0]->value[2] = left; report->field[0]->value[3] = right; dbg("(left, right)=(%04x, %04x)", left, right); - hid_submit_report(hid, report, USB_DIR_OUT); + usbhid_submit_report(hid, report, USB_DIR_OUT); break; } return 0; diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c index b4caea3864e3..cbd2d53fefff 100644 --- a/drivers/usb/input/hid-pidff.c +++ b/drivers/usb/input/hid-pidff.c @@ -262,7 +262,7 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, debug("attack %u => %d", envelope->attack_level, pidff->set_envelope[PID_ATTACK_LEVEL].value[0]); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE], USB_DIR_OUT); } @@ -289,7 +289,7 @@ static void pidff_set_constant_force_report(struct pidff_device *pidff, pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE], effect->u.constant.level); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT], USB_DIR_OUT); } @@ -324,7 +324,7 @@ static void pidff_set_effect_report(struct pidff_device *pidff, pidff->effect_direction); pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; - hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], USB_DIR_OUT); } @@ -356,7 +356,7 @@ static void pidff_set_periodic_report(struct pidff_device *pidff, pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase); pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period; - hid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC], USB_DIR_OUT); } @@ -398,8 +398,8 @@ static void pidff_set_condition_report(struct pidff_device *pidff, effect->u.condition[i].left_saturation); pidff_set(&pidff->set_condition[PID_DEAD_BAND], effect->u.condition[i].deadband); - hid_wait_io(pidff->hid); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], + usbhid_wait_io(pidff->hid); + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], USB_DIR_OUT); } } @@ -440,7 +440,7 @@ static void pidff_set_ramp_force_report(struct pidff_device *pidff, effect->u.ramp.start_level); pidff_set_signed(&pidff->set_ramp[PID_RAMP_END], effect->u.ramp.end_level); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP], USB_DIR_OUT); } @@ -465,19 +465,19 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) int j; pidff->create_new_effect_type->value[0] = efnum; - hid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], USB_DIR_OUT); debug("create_new_effect sent, type: %d", efnum); pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0; pidff->block_load_status->value[0] = 0; - hid_wait_io(pidff->hid); + usbhid_wait_io(pidff->hid); for (j = 0; j < 60; j++) { debug("pid_block_load requested"); - hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD], + usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD], USB_DIR_IN); - hid_wait_io(pidff->hid); + usbhid_wait_io(pidff->hid); if (pidff->block_load_status->value[0] == pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) { debug("device reported free memory: %d bytes", @@ -513,8 +513,8 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; } - hid_wait_io(pidff->hid); - hid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], + usbhid_wait_io(pidff->hid); + usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], USB_DIR_OUT); } @@ -536,7 +536,7 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value) static void pidff_erase_pid(struct pidff_device *pidff, int pid_id) { pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; - hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE], + usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE], USB_DIR_OUT); } @@ -716,7 +716,7 @@ static void pidff_set_gain(struct input_dev *dev, u16 gain) struct pidff_device *pidff = dev->ff->private; pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); - hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], + usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], USB_DIR_OUT); } @@ -741,7 +741,7 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) pidff_set(&pidff->set_effect[PID_GAIN], magnitude); pidff->set_effect[PID_START_DELAY].value[0] = 0; - hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], USB_DIR_OUT); } @@ -1165,19 +1165,19 @@ static void pidff_reset(struct pidff_device *pidff) pidff->device_control->value[0] = pidff->control_id[PID_RESET]; /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ - hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); - hid_wait_io(hid); - hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); - hid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); + usbhid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); + usbhid_wait_io(hid); pidff->device_control->value[0] = pidff->control_id[PID_ENABLE_ACTUATORS]; - hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); - hid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); + usbhid_wait_io(hid); /* pool report is sometimes messed up, refetch it */ - hid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); - hid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); + usbhid_wait_io(hid); if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0]; @@ -1189,9 +1189,9 @@ static void pidff_reset(struct pidff_device *pidff) break; } debug("pid_pool requested again"); - hid_submit_report(hid, pidff->reports[PID_POOL], + usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); - hid_wait_io(hid); + usbhid_wait_io(hid); } } } @@ -1277,7 +1277,7 @@ int hid_pidff_init(struct hid_device *hid) if (test_bit(FF_GAIN, dev->ffbit)) { pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff); - hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], + usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], USB_DIR_OUT); } diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c index 1cd1418ad6ac..ab67331620d0 100644 --- a/drivers/usb/input/hid-tmff.c +++ b/drivers/usb/input/hid-tmff.c @@ -33,6 +33,7 @@ #include #include +#include "usbhid.h" /* Usages for thrustmaster devices I know about */ #define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) @@ -70,7 +71,7 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef tmff->rumble->value[0] = left; tmff->rumble->value[1] = right; dbg("(left,right)=(%08x, %08x)", left, right); - hid_submit_report(hid, tmff->report, USB_DIR_OUT); + usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); return 0; } diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c index af1bfae39dce..7bd8238ca212 100644 --- a/drivers/usb/input/hid-zpff.c +++ b/drivers/usb/input/hid-zpff.c @@ -28,6 +28,7 @@ #include #include #include +#include "usbhid.h" struct zpff_device { struct hid_report *report; @@ -56,7 +57,7 @@ static int hid_zpff_play(struct input_dev *dev, void *data, zpff->report->field[2]->value[0] = left; zpff->report->field[3]->value[0] = right; debug("running with 0x%02x 0x%02x", left, right); - hid_submit_report(hid, zpff->report, USB_DIR_OUT); + usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); return 0; } @@ -101,7 +102,7 @@ int hid_zpff_init(struct hid_device *hid) zpff->report->field[1]->value[0] = 0x02; zpff->report->field[2]->value[0] = 0x00; zpff->report->field[3]->value[0] = 0x00; - hid_submit_report(hid, zpff->report, USB_DIR_OUT); + usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); printk(KERN_INFO "Force feedback for Zeroplus based devices by " "Anssi Hannula \n"); diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 07d7996575cd..0c2647eb9eec 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -240,7 +240,7 @@ static int hiddev_release(struct inode * inode, struct file * file) if (!--list->hiddev->open) { if (list->hiddev->exist) - hid_close(list->hiddev->hid); + usbhid_close(list->hiddev->hid); else kfree(list->hiddev); } @@ -271,7 +271,7 @@ static int hiddev_open(struct inode *inode, struct file *file) if (!list->hiddev->open++) if (list->hiddev->exist) - hid_open(hiddev_table[i]->hid); + usbhid_open(hiddev_table[i]->hid); return 0; } @@ -383,7 +383,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; struct hid_device *hid = hiddev->hid; - struct usb_device *dev = hid->dev; + struct usb_device *dev = to_usb_device(hid->dev); struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; @@ -392,6 +392,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; + struct usbhid_device *usbhid = hid->driver_data; void __user *user_arg = (void __user *)arg; int i; @@ -421,7 +422,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd dinfo.bustype = BUS_USB; dinfo.busnum = dev->bus->busnum; dinfo.devnum = dev->devnum; - dinfo.ifnum = hid->ifnum; + dinfo.ifnum = usbhid->ifnum; dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor); dinfo.product = le16_to_cpu(dev->descriptor.idProduct); dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice); @@ -480,7 +481,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd } case HIDIOCINITREPORT: - hid_init_reports(hid); + usbhid_init_reports(hid); return 0; @@ -494,8 +495,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - hid_submit_report(hid, report, USB_DIR_IN); - hid_wait_io(hid); + usbhid_submit_report(hid, report, USB_DIR_IN); + usbhid_wait_io(hid); return 0; @@ -509,8 +510,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - hid_submit_report(hid, report, USB_DIR_OUT); - hid_wait_io(hid); + usbhid_submit_report(hid, report, USB_DIR_OUT); + usbhid_wait_io(hid); return 0; @@ -746,6 +747,7 @@ static struct usb_class_driver hiddev_class = { int hiddev_connect(struct hid_device *hid) { struct hiddev *hiddev; + struct usbhid_device *usbhid = hid->driver_data; int i; int retval; @@ -761,7 +763,7 @@ int hiddev_connect(struct hid_device *hid) if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL))) return -1; - retval = usb_register_dev(hid->intf, &hiddev_class); + retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { err("Not able to get a minor for this device."); kfree(hiddev); @@ -773,10 +775,10 @@ int hiddev_connect(struct hid_device *hid) hiddev->hid = hid; hiddev->exist = 1; - hid->minor = hid->intf->minor; + hid->minor = usbhid->intf->minor; hid->hiddev = hiddev; - hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; + hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; return 0; } @@ -789,14 +791,15 @@ static struct usb_class_driver hiddev_class; void hiddev_disconnect(struct hid_device *hid) { struct hiddev *hiddev = hid->hiddev; + struct usbhid_device *usbhid = hid->driver_data; hiddev->exist = 0; hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; - usb_deregister_dev(hiddev->hid->intf, &hiddev_class); + usb_deregister_dev(usbhid->intf, &hiddev_class); if (hiddev->open) { - hid_close(hiddev->hid); + usbhid_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { kfree(hiddev); diff --git a/drivers/usb/input/usbhid.h b/drivers/usb/input/usbhid.h new file mode 100644 index 000000000000..830107e5251f --- /dev/null +++ b/drivers/usb/input/usbhid.h @@ -0,0 +1,84 @@ +#ifndef __USBHID_H +#define __USBHID_H + +/* + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2006 Jiri Kosina + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +/* API provided by hid-core.c for USB HID drivers */ +int usbhid_wait_io(struct hid_device* hid); +void usbhid_close(struct hid_device *hid); +int usbhid_open(struct hid_device *hid); +void usbhid_init_reports(struct hid_device *hid); +void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir); + +/* + * USB-specific HID struct, to be pointed to + * from struct hid_device->driver_data + */ + +struct usbhid_device { + struct hid_device *hid; /* pointer to corresponding HID dev */ + + struct usb_interface *intf; /* USB interface */ + int ifnum; /* USB interface number */ + + unsigned int bufsize; /* URB buffer size */ + + struct urb *urbin; /* Input URB */ + char *inbuf; /* Input buffer */ + dma_addr_t inbuf_dma; /* Input buffer dma */ + spinlock_t inlock; /* Input fifo spinlock */ + + struct urb *urbctrl; /* Control URB */ + struct usb_ctrlrequest *cr; /* Control request struct */ + dma_addr_t cr_dma; /* Control request struct dma */ + struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ + unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ + char *ctrlbuf; /* Control buffer */ + dma_addr_t ctrlbuf_dma; /* Control buffer dma */ + spinlock_t ctrllock; /* Control fifo spinlock */ + + struct urb *urbout; /* Output URB */ + struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ + unsigned char outhead, outtail; /* Output pipe fifo head & tail */ + char *outbuf; /* Output buffer */ + dma_addr_t outbuf_dma; /* Output buffer dma */ + spinlock_t outlock; /* Output fifo spinlock */ + + unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ + struct timer_list io_retry; /* Retry timer */ + unsigned long stop_retry; /* Time to give up, in jiffies */ + unsigned int retry_delay; /* Delay length in ms */ + struct work_struct reset_work; /* Task context for resets */ + +}; + +#endif + diff --git a/include/linux/hid.h b/include/linux/hid.h index 0473b45b73b8..fc6f74228da3 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -410,41 +410,7 @@ struct hid_device { /* device report descriptor */ unsigned country; /* HID country */ struct hid_report_enum report_enum[HID_REPORT_TYPES]; - struct usb_device *dev; /* device */ - - /* USB specific fields */ - - struct usb_interface *intf; /* USB interface */ - int ifnum; /* USB interface number */ - - unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ - struct timer_list io_retry; /* Retry timer */ - unsigned long stop_retry; /* Time to give up, in jiffies */ - unsigned int retry_delay; /* Delay length in ms */ - struct work_struct reset_work; /* Task context for resets */ - - unsigned int bufsize; /* URB buffer size */ - - struct urb *urbin; /* Input URB */ - char *inbuf; /* Input buffer */ - dma_addr_t inbuf_dma; /* Input buffer dma */ - spinlock_t inlock; /* Input fifo spinlock */ - - struct urb *urbctrl; /* Control URB */ - struct usb_ctrlrequest *cr; /* Control request struct */ - dma_addr_t cr_dma; /* Control request struct dma */ - struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ - unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ - char *ctrlbuf; /* Control buffer */ - dma_addr_t ctrlbuf_dma; /* Control buffer dma */ - spinlock_t ctrllock; /* Control fifo spinlock */ - - struct urb *urbout; /* Output URB */ - struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ - unsigned char outhead, outtail; /* Output pipe fifo head & tail */ - char *outbuf; /* Output buffer */ - dma_addr_t outbuf_dma; /* Output buffer dma */ - spinlock_t outlock; /* Output fifo spinlock */ + struct device *dev; /* device */ unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned quirks; /* Various quirks the device can pull on us */ -- cgit v1.2.3 From aa938f7974b82cfd9ee955031987344f332b7c77 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:41:10 +0100 Subject: [PATCH] Generic HID layer - hiddev - hiddev is USB-only (agreed with Marcel Holtmann that Bluetooth currently doesn't need it, and future planned interface (rawhid) will be more flexible and usable) - both HID and USB-hid can be now compiled as modules (wasn't possible before hiddev was fully separated from generic HID layer) Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 6 ++++-- drivers/usb/input/hid-core.c | 3 +++ include/linux/hid.h | 8 ++++---- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8474a7923322..1dd9e4f0df1e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -819,8 +819,8 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s hid_dump_input(usage, value); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_hid_event(hid, field, usage, value); - if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt) - hiddev_hid_event(hid, field, usage, value); + if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); } /* @@ -940,3 +940,5 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) } EXPORT_SYMBOL_GPL(hid_set_field); +MODULE_LICENSE(DRIVER_LICENSE); + diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 0991c4b751a6..4fc828041d0f 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1284,6 +1284,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->hidinput_input_event = usb_hidinput_input_event; hid->hidinput_open = hidinput_open; hid->hidinput_close = hidinput_close; +#ifdef CONFIG_USB_HIDDEV + hid->hiddev_hid_event = hiddev_hid_event; +#endif return hid; diff --git a/include/linux/hid.h b/include/linux/hid.h index fc6f74228da3..5a969a137b85 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -433,6 +433,10 @@ struct hid_device { /* device report descriptor */ int (*hidinput_open) (struct input_dev *); void (*hidinput_close) (struct input_dev *); + /* hiddev event handler */ + void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field, + struct hid_usage *, __s32); + #ifdef CONFIG_USB_HIDINPUT_POWERBOOK unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; @@ -477,13 +481,9 @@ struct hid_descriptor { #define resolv_event(a,b) do { } while (0) #endif -#ifdef CONFIG_HID /* Applications from HID Usage Tables 4/8/99 Version 1.1 */ /* We ignore a few input applications that are not widely used */ #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001)) -#else -#define IS_INPUT_APPLICATION(a) (0) -#endif /* HID core API */ extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); -- cgit v1.2.3 From aa8de2f038baec993f07ef66fb3e94481d1ec22b Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:41:17 +0100 Subject: [PATCH] Generic HID layer - input and event reporting hid_input_report() was needlessly USB-specific in USB HID. This patch makes the function independent of HID implementation and fixes all the current users. Bluetooth patches comply with this prototype. Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 59 ++++++++++++++++++++++++++++++++++++++ drivers/usb/input/hid-core.c | 67 ++++---------------------------------------- drivers/usb/input/hiddev.c | 1 + include/linux/hid.h | 3 +- 4 files changed, 68 insertions(+), 62 deletions(-) (limited to 'include/linux') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 1dd9e4f0df1e..18c2b3cf6bcc 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -940,5 +940,64 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) } EXPORT_SYMBOL_GPL(hid_set_field); +int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt) +{ + struct hid_report_enum *report_enum = hid->report_enum + type; + struct hid_report *report; + int n, rsize; + + if (!hid) + return -ENODEV; + + if (!size) { + dbg("empty report"); + return -1; + } + +#ifdef DEBUG_DATA + printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un"); +#endif + + n = 0; /* Normally report number is 0 */ + if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ + n = *data++; + size--; + } + +#ifdef DEBUG_DATA + { + int i; + printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size); + for (i = 0; i < size; i++) + printk(" %02x", data[i]); + printk("\n"); + } +#endif + + if (!(report = report_enum->report_id_hash[n])) { + dbg("undefined report_id %d received", n); + return -1; + } + + rsize = ((report->size - 1) >> 3) + 1; + + if (size < rsize) { + dbg("report %d is too short, (%d < %d)", report->id, size, rsize); + return -1; + } + + if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) + hid->hiddev_report_event(hid, report); + + for (n = 0; n < report->maxfield; n++) + hid_input_field(hid, report->field[n], data, interrupt); + + if (hid->claimed & HID_CLAIMED_INPUT) + hidinput_report_event(hid, report); + + return 0; +} +EXPORT_SYMBOL_GPL(hid_input_report); + MODULE_LICENSE(DRIVER_LICENSE); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 4fc828041d0f..a20ff61624b1 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -169,65 +169,6 @@ done: spin_unlock_irqrestore(&usbhid->inlock, flags); } - -static int hid_input_report(int type, struct urb *urb, int interrupt) -{ - struct hid_device *hid = urb->context; - struct hid_report_enum *report_enum = hid->report_enum + type; - u8 *data = urb->transfer_buffer; - int len = urb->actual_length; - struct hid_report *report; - int n, size; - - if (!len) { - dbg("empty report"); - return -1; - } - -#ifdef DEBUG_DATA - printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un"); -#endif - - n = 0; /* Normally report number is 0 */ - if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ - n = *data++; - len--; - } - -#ifdef DEBUG_DATA - { - int i; - printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len); - for (i = 0; i < len; i++) - printk(" %02x", data[i]); - printk("\n"); - } -#endif - - if (!(report = report_enum->report_id_hash[n])) { - dbg("undefined report_id %d received", n); - return -1; - } - - size = ((report->size - 1) >> 3) + 1; - - if (len < size) { - dbg("report %d is too short, (%d < %d)", report->id, len, size); - memset(data + len, 0, size - len); - } - - if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_report_event(hid, report); - - for (n = 0; n < report->maxfield; n++) - hid_input_field(hid, report->field[n], data, interrupt); - - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_report_event(hid, report); - - return 0; -} - /* * Input interrupt completion handler. */ @@ -241,7 +182,9 @@ static void hid_irq_in(struct urb *urb) switch (urb->status) { case 0: /* success */ usbhid->retry_delay = 0; - hid_input_report(HID_INPUT_REPORT, urb, 1); + hid_input_report(urb->context, HID_INPUT_REPORT, + urb->transfer_buffer, + urb->actual_length, 1); break; case -EPIPE: /* stall */ clear_bit(HID_IN_RUNNING, &usbhid->iofl); @@ -426,7 +369,8 @@ static void hid_ctrl(struct urb *urb) switch (urb->status) { case 0: /* success */ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) - hid_input_report(usbhid->ctrl[usbhid->ctrltail].report->type, urb, 0); + hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type, + urb->transfer_buffer, urb->actual_length, 0); break; case -ESHUTDOWN: /* unplug */ unplug = 1; @@ -1286,6 +1230,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->hidinput_close = hidinput_close; #ifdef CONFIG_USB_HIDDEV hid->hiddev_hid_event = hiddev_hid_event; + hid->hiddev_report_event = hiddev_report_event; #endif return hid; diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 0c2647eb9eec..114d6c9f64b1 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -214,6 +214,7 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report) hiddev_send_event(hid, &uref); } + /* * fasync file op */ diff --git a/include/linux/hid.h b/include/linux/hid.h index 5a969a137b85..342b4e639acb 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -436,7 +436,7 @@ struct hid_device { /* device report descriptor */ /* hiddev event handler */ void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field, struct hid_usage *, __s32); - + void (*hiddev_report_event) (struct hid_device *, struct hid_report *); #ifdef CONFIG_USB_HIDINPUT_POWERBOOK unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; @@ -492,6 +492,7 @@ extern int hidinput_connect(struct hid_device *); extern void hidinput_disconnect(struct hid_device *); int hid_set_field(struct hid_field *, unsigned, __s32); +int hid_input_report(struct hid_device *, int type, u8 *, int, int); int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt); void hid_output_report(struct hid_report *report, __u8 *data); -- cgit v1.2.3 From 4c2ae844b5ef85fd4b571c9c91ac48afa6ef2dfc Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:41:22 +0100 Subject: [PATCH] Generic HID layer - pb_fnmode pb_fnmode parameter has to be passed to usbhid, both for compatibility reasons and also because it logically belongs there. Also removes empty hid-input.c file in drivers/usb/input. Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-input.c | 12 +++--------- drivers/usb/input/hid-core.c | 8 ++++++++ drivers/usb/input/hid-input.c | 30 ------------------------------ include/linux/hid.h | 1 + 4 files changed, 12 insertions(+), 39 deletions(-) delete mode 100644 drivers/usb/input/hid-input.c (limited to 'include/linux') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index e542ef971c46..14cdf09316ce 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -128,12 +128,6 @@ static struct hidinput_key_translation powerbook_iso_keyboard[] = { { } }; - -static int usbhid_pb_fnmode = 1; -module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); -MODULE_PARM_DESC(pb_fnmode, - "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); - static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from) { struct hidinput_key_translation *trans; @@ -160,7 +154,7 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, return 1; } - if (usbhid_pb_fnmode) { + if (hid->pb_fnmode) { int do_translate; trans = find_translation(powerbook_fn_keys, usage->code); @@ -169,8 +163,8 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, do_translate = 1; else if (trans->flags & POWERBOOK_FLAG_FKEY) do_translate = - (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) || - (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)); + (hid->pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) || + (hid->pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)); else do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index a20ff61624b1..89fa6885709b 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -56,6 +56,11 @@ static unsigned int hid_mousepoll_interval; module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); +static int usbhid_pb_fnmode = 1; +module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); +MODULE_PARM_DESC(pb_fnmode, + "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); + /* * Input submission and I/O error handler. */ @@ -1232,6 +1237,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->hiddev_hid_event = hiddev_hid_event; hid->hiddev_report_event = hiddev_report_event; #endif +#ifdef CONFIG_USB_HIDINPUT_POWERBOOK + hid->pb_fnmode = usbhid_pb_fnmode; +#endif return hid; diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c deleted file mode 100644 index 8756eb3263de..000000000000 --- a/drivers/usb/input/hid-input.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ - * - * Copyright (c) 2000-2001 Vojtech Pavlik - * - * USB HID to Linux Input mapping - * - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - - diff --git a/include/linux/hid.h b/include/linux/hid.h index 342b4e639acb..770120add15a 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -438,6 +438,7 @@ struct hid_device { /* device report descriptor */ struct hid_usage *, __s32); void (*hiddev_report_event) (struct hid_device *, struct hid_report *); #ifdef CONFIG_USB_HIDINPUT_POWERBOOK + unsigned int pb_fnmode; unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; #endif -- cgit v1.2.3 From 3644f0cee77494190452de132e82245107939284 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 7 Dec 2006 15:08:17 -0800 Subject: [NET]: Convert hh_lock to seqlock. The hard header cache is in the main output path, so using seqlock instead of reader/writer lock should reduce overhead. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- include/net/neighbour.h | 18 ++++++++++++++++++ net/core/neighbour.c | 11 ++++++----- net/ipv4/ip_output.c | 14 +++----------- net/ipv6/ip6_output.c | 17 ++++------------- 5 files changed, 32 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c57088f575a3..631cec4ff5e1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -199,7 +199,7 @@ struct hh_cache */ u16 hh_len; /* length of header */ int (*hh_output)(struct sk_buff *skb); - rwlock_t hh_lock; + seqlock_t hh_lock; /* cached hardware header; allow for machine alignment needs. */ #define HH_DATA_MOD 16 diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 23967031ddb7..3725b93c52f3 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -309,6 +309,24 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) return 0; } +static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb) +{ + unsigned seq; + int hh_len; + + do { + int hh_alen; + + seq = read_seqbegin(&hh->hh_lock); + hh_len = hh->hh_len; + hh_alen = HH_DATA_ALIGN(hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); + } while (read_seqretry(&hh->hh_lock, seq)); + + skb_push(skb, hh_len); + return hh->hh_output(skb); +} + static inline struct neighbour * __neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat) { diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0ab1987b9348..e7300b6b4079 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -577,9 +577,10 @@ void neigh_destroy(struct neighbour *neigh) while ((hh = neigh->hh) != NULL) { neigh->hh = hh->hh_next; hh->hh_next = NULL; - write_lock_bh(&hh->hh_lock); + + write_seqlock_bh(&hh->hh_lock); hh->hh_output = neigh_blackhole; - write_unlock_bh(&hh->hh_lock); + write_sequnlock_bh(&hh->hh_lock); if (atomic_dec_and_test(&hh->hh_refcnt)) kfree(hh); } @@ -897,9 +898,9 @@ static void neigh_update_hhs(struct neighbour *neigh) if (update) { for (hh = neigh->hh; hh; hh = hh->hh_next) { - write_lock_bh(&hh->hh_lock); + write_seqlock_bh(&hh->hh_lock); update(hh, neigh->dev, neigh->ha); - write_unlock_bh(&hh->hh_lock); + write_sequnlock_bh(&hh->hh_lock); } } } @@ -1089,7 +1090,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, break; if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { - rwlock_init(&hh->hh_lock); + seqlock_init(&hh->hh_lock); hh->hh_type = protocol; atomic_set(&hh->hh_refcnt, 0); hh->hh_next = NULL; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index a35209d517ad..f071f84808fa 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -164,7 +164,6 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt); static inline int ip_finish_output2(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; - struct hh_cache *hh = dst->hh; struct net_device *dev = dst->dev; int hh_len = LL_RESERVED_SPACE(dev); @@ -183,16 +182,9 @@ static inline int ip_finish_output2(struct sk_buff *skb) skb = skb2; } - if (hh) { - int hh_alen; - - read_lock_bh(&hh->hh_lock); - hh_alen = HH_DATA_ALIGN(hh->hh_len); - memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); - read_unlock_bh(&hh->hh_lock); - skb_push(skb, hh->hh_len); - return hh->hh_output(skb); - } else if (dst->neighbour) + if (dst->hh) + return neigh_hh_output(dst->hh, skb); + else if (dst->neighbour) return dst->neighbour->output(skb); if (net_ratelimit()) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e9212c7ff5cf..7b7bd44fbf47 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -72,20 +72,11 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f static inline int ip6_output_finish(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; - struct hh_cache *hh = dst->hh; - - if (hh) { - int hh_alen; - - read_lock_bh(&hh->hh_lock); - hh_alen = HH_DATA_ALIGN(hh->hh_len); - memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); - read_unlock_bh(&hh->hh_lock); - skb_push(skb, hh->hh_len); - return hh->hh_output(skb); - } else if (dst->neighbour) + + if (dst->hh) + return neigh_hh_output(dst->hh, skb); + else if (dst->neighbour) return dst->neighbour->output(skb); IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); -- cgit v1.2.3 From e07bca84cd9d31f76ed655d51e68b6a0ca15f162 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 7 Dec 2006 23:49:45 -0800 Subject: [NETLINK]: Restore API compatibility of address and neighbour bits Restore API compatibility due to bits moved from rtnetlink.h to separate headers. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 493297acdae8..4a629ea70cc4 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -3,6 +3,8 @@ #include #include +#include +#include /**** * Routing/neighbour discovery messages. -- cgit v1.2.3 From f0490980a152958d25ce9762bfb296d8fd4c5512 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 8 Dec 2006 00:08:43 -0800 Subject: [NET]: Force a cache line split in hh_cache in SMP. hh_lock was converted from rwlock to seqlock by Stephen. To have a 100% benefit of this change, I suggest to place read mostly fields of hh_cache in a separate cache line, because hh_refcnt may be changed quite frequently on some busy machines. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 631cec4ff5e1..6be767c76b37 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -193,7 +193,14 @@ struct hh_cache { struct hh_cache *hh_next; /* Next entry */ atomic_t hh_refcnt; /* number of users */ - __be16 hh_type; /* protocol identifier, f.e ETH_P_IP +/* + * We want hh_output, hh_len, hh_lock and hh_data be a in a separate + * cache line on SMP. + * They are mostly read, but hh_refcnt may be changed quite frequently, + * incurring cache line ping pongs. + */ + __be16 hh_type ____cacheline_aligned_in_smp; + /* protocol identifier, f.e ETH_P_IP * NOTE: For VLANs, this will be the * encapuslated type. --BLG */ -- cgit v1.2.3 From 93366c537b3426261cac4db27acc10a99cd91b06 Mon Sep 17 00:00:00 2001 From: J Hadi Salim Date: Fri, 8 Dec 2006 00:12:15 -0800 Subject: [XFRM]: Fix XFRMGRP_REPORT to use correct multicast group. XFRMGRP_REPORT uses 0x10 which is a group that belongs to events. The correct value is 0x20. We should really be using xfrm_nlgroups going forward; it was tempting to delete the definition of XFRMGRP_REPORT but it would break at least iproute2. Signed-off-by: J Hadi Salim Signed-off-by: David S. Miller --- include/linux/xfrm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 088ba8113f7e..9529ea1ae392 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -357,7 +357,7 @@ struct xfrm_user_report { #define XFRMGRP_EXPIRE 2 #define XFRMGRP_SA 4 #define XFRMGRP_POLICY 8 -#define XFRMGRP_REPORT 0x10 +#define XFRMGRP_REPORT 0x20 #endif enum xfrm_nlgroups { -- cgit v1.2.3 From d3dcc077bf88806201093f86325ec656e4dbfbce Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 8 Dec 2006 17:05:13 -0800 Subject: [NETLINK]: Put {IFA,IFLA}_{RTA,PAYLOAD} macros back for userspace. GLIBC uses them etc. They are guarded by ifndef __KERNEL__ so nobody will start accidently using them in the kernel again, it's just for userspace. Signed-off-by: David S. Miller --- include/linux/if_addr.h | 6 ++++++ include/linux/if_link.h | 6 ++++++ 2 files changed, 12 insertions(+) (limited to 'include/linux') diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h index dbe8f6120a40..d557e4ce9b6b 100644 --- a/include/linux/if_addr.h +++ b/include/linux/if_addr.h @@ -52,4 +52,10 @@ struct ifa_cacheinfo __u32 tstamp; /* updated timestamp, hundredths of seconds */ }; +/* backwards compatibility for userspace */ +#ifndef __KERNEL__ +#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) +#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) +#endif + #endif diff --git a/include/linux/if_link.h b/include/linux/if_link.h index e963a077e6f5..35ed3b5467f3 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -82,6 +82,12 @@ enum #define IFLA_MAX (__IFLA_MAX - 1) +/* backwards compatibility for userspace */ +#ifndef __KERNEL__ +#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) +#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +#endif + /* ifi_flags. IFF_* flags. -- cgit v1.2.3 From 9c4dfadbde3cfa78b92c28597125b8c41d36ffd0 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sat, 4 Nov 2006 09:22:27 -0300 Subject: V4L/DVB (4796): A couple of V4L2 defines needed by Cafe Camara driver Two defines for V4L2, needed by the Cafe camera driver: 1) Add the RGB444 image format 2) Add the "init" internal command which is separate from "reset". Signed-off-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 1 + include/media/v4l2-common.h | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index df5c4654360d..5cb380a559fd 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -244,6 +244,7 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:2:0 16x16 macroblocks */ +#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R','4','4','4') /* 16 xxxxrrrr ggggbbbb */ /* see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */ diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index aecc946980a3..8263ea00ca6f 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -251,4 +251,8 @@ struct v4l2_crystal_freq { If the frequency is not supported, then -EINVAL is returned. */ #define VIDIOC_INT_S_CRYSTAL_FREQ _IOW ('d', 113, struct v4l2_crystal_freq) +/* Initialize the sensor registors to some sort of reasonable + default values. */ +#define VIDIOC_INT_INIT _IOW ('d', 114, u32) + #endif /* V4L2_COMMON_H_ */ -- cgit v1.2.3 From d905b382d797a213e15868cbf3204f50ed52e30b Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sat, 4 Nov 2006 09:25:53 -0300 Subject: V4L/DVB (4797): Marvell 88ALP01 "cafe" driver A driver for the Marvell M88ALP01 "CAFE" CMOS integrated camera controller. This driver has been renamed "cafe_ccic" since my previous patch set. Signed-off-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/cafe_ccic | 54 + drivers/media/video/Kconfig | 9 + drivers/media/video/Makefile | 2 + drivers/media/video/cafe_ccic-regs.h | 160 +++ drivers/media/video/cafe_ccic.c | 2237 ++++++++++++++++++++++++++++++++++ include/linux/i2c-id.h | 1 + 6 files changed, 2463 insertions(+) create mode 100644 Documentation/video4linux/cafe_ccic create mode 100644 drivers/media/video/cafe_ccic-regs.h create mode 100644 drivers/media/video/cafe_ccic.c (limited to 'include/linux') diff --git a/Documentation/video4linux/cafe_ccic b/Documentation/video4linux/cafe_ccic new file mode 100644 index 000000000000..88821022a5de --- /dev/null +++ b/Documentation/video4linux/cafe_ccic @@ -0,0 +1,54 @@ +"cafe_ccic" is a driver for the Marvell 88ALP01 "cafe" CMOS camera +controller. This is the controller found in first-generation OLPC systems, +and this driver was written with support from the OLPC project. + +Current status: the core driver works. It can generate data in YUV422, +RGB565, and RGB444 formats. (Anybody looking at the code will see RGB32 as +well, but that is a debugging aid which will be removed shortly). VGA and +QVGA modes work; CIF is there but the colors remain funky. Only the OV7670 +sensor is known to work with this controller at this time. + +To try it out: either of these commands will work: + + mplayer tv:// -tv driver=v4l2:width=640:height=480 -nosound + mplayer tv:// -tv driver=v4l2:width=640:height=480:outfmt=bgr16 -nosound + +The "xawtv" utility also works; gqcam does not, for unknown reasons. + +There are a few load-time options, most of which can be changed after +loading via sysfs as well: + + - alloc_bufs_at_load: Normally, the driver will not allocate any DMA + buffers until the time comes to transfer data. If this option is set, + then worst-case-sized buffers will be allocated at module load time. + This option nails down the memory for the life of the module, but + perhaps decreases the chances of an allocation failure later on. + + - dma_buf_size: The size of DMA buffers to allocate. Note that this + option is only consulted for load-time allocation; when buffers are + allocated at run time, they will be sized appropriately for the current + camera settings. + + - n_dma_bufs: The controller can cycle through either two or three DMA + buffers. Normally, the driver tries to use three buffers; on faster + systems, however, it will work well with only two. + + - min_buffers: The minimum number of streaming I/O buffers that the driver + will consent to work with. Default is one, but, on slower systems, + better behavior with mplayer can be achieved by setting to a higher + value (like six). + + - max_buffers: The maximum number of streaming I/O buffers; default is + ten. That number was carefully picked out of a hat and should not be + assumed to actually mean much of anything. + + - flip: If this boolean parameter is set, the sensor will be instructed to + invert the video image. Whether it makes sense is determined by how + your particular camera is mounted. + +Work is ongoing with this driver, stay tuned. + +jon + +Jonathan Corbet +corbet@lwn.net diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index b8fde5cf4735..4ea1d0ebf5fd 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -670,6 +670,15 @@ config VIDEO_M32R_AR_M64278 To compile this driver as a module, choose M here: the module will be called arv. +config VIDEO_CAFE_CCIC + tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" + depends on I2C && VIDEO_V4L2 + select VIDEO_OV7670 + ---help--- + This is a video4linux2 driver for the Marvell 88ALP01 integrated + CMOS camera controller. This is the controller found on first- + generation OLPC systems. + # # USB Multimedia device configuration # diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index af57abce8a6e..8ff787a4cf6a 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -92,6 +92,8 @@ obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o +obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o + obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_SE401) += se401.o diff --git a/drivers/media/video/cafe_ccic-regs.h b/drivers/media/video/cafe_ccic-regs.h new file mode 100644 index 000000000000..b2c22a0d6643 --- /dev/null +++ b/drivers/media/video/cafe_ccic-regs.h @@ -0,0 +1,160 @@ +/* + * Register definitions for the m88alp01 camera interface. Offsets in bytes + * as given in the spec. + * + * Copyright 2006 One Laptop Per Child Association, Inc. + * + * Written by Jonathan Corbet, corbet@lwn.net. + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ +#define REG_Y0BAR 0x00 +#define REG_Y1BAR 0x04 +#define REG_Y2BAR 0x08 +/* ... */ + +#define REG_IMGPITCH 0x24 /* Image pitch register */ +#define IMGP_YP_SHFT 2 /* Y pitch params */ +#define IMGP_YP_MASK 0x00003ffc /* Y pitch field */ +#define IMGP_UVP_SHFT 18 /* UV pitch (planar) */ +#define IMGP_UVP_MASK 0x3ffc0000 +#define REG_IRQSTATRAW 0x28 /* RAW IRQ Status */ +#define IRQ_EOF0 0x00000001 /* End of frame 0 */ +#define IRQ_EOF1 0x00000002 /* End of frame 1 */ +#define IRQ_EOF2 0x00000004 /* End of frame 2 */ +#define IRQ_SOF0 0x00000008 /* Start of frame 0 */ +#define IRQ_SOF1 0x00000010 /* Start of frame 1 */ +#define IRQ_SOF2 0x00000020 /* Start of frame 2 */ +#define IRQ_OVERFLOW 0x00000040 /* FIFO overflow */ +#define IRQ_TWSIW 0x00010000 /* TWSI (smbus) write */ +#define IRQ_TWSIR 0x00020000 /* TWSI read */ +#define IRQ_TWSIE 0x00040000 /* TWSI error */ +#define TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE) +#define FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2) +#define ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW) +#define REG_IRQMASK 0x2c /* IRQ mask - same bits as IRQSTAT */ +#define REG_IRQSTAT 0x30 /* IRQ status / clear */ + +#define REG_IMGSIZE 0x34 /* Image size */ +#define IMGSZ_V_MASK 0x1fff0000 +#define IMGSZ_V_SHIFT 16 +#define IMGSZ_H_MASK 0x00003fff +#define REG_IMGOFFSET 0x38 /* IMage offset */ + +#define REG_CTRL0 0x3c /* Control 0 */ +#define C0_ENABLE 0x00000001 /* Makes the whole thing go */ + +/* Mask for all the format bits */ +#define C0_DF_MASK 0x00fffffc /* Bits 2-23 */ + +/* RGB ordering */ +#define C0_RGB4_RGBX 0x00000000 +#define C0_RGB4_XRGB 0x00000004 +#define C0_RGB4_BGRX 0x00000008 +#define C0_RGB4_XBGR 0x0000000c +#define C0_RGB5_RGGB 0x00000000 +#define C0_RGB5_GRBG 0x00000004 +#define C0_RGB5_GBRG 0x00000008 +#define C0_RGB5_BGGR 0x0000000c + +/* Spec has two fields for DIN and DOUT, but they must match, so + combine them here. */ +#define C0_DF_YUV 0x00000000 /* Data is YUV */ +#define C0_DF_RGB 0x000000a0 /* ... RGB */ +#define C0_DF_BAYER 0x00000140 /* ... Bayer */ +/* 8-8-8 must be missing from the below - ask */ +#define C0_RGBF_565 0x00000000 +#define C0_RGBF_444 0x00000800 +#define C0_RGB_BGR 0x00001000 /* Blue comes first */ +#define C0_YUV_PLANAR 0x00000000 /* YUV 422 planar format */ +#define C0_YUV_PACKED 0x00008000 /* YUV 422 packed */ +#define C0_YUV_420PL 0x0000a000 /* YUV 420 planar */ +/* Think that 420 packed must be 111 - ask */ +#define C0_YUVE_YUYV 0x00000000 /* Y1CbY0Cr */ +#define C0_YUVE_YVYU 0x00010000 /* Y1CrY0Cb */ +#define C0_YUVE_VYUY 0x00020000 /* CrY1CbY0 */ +#define C0_YUVE_UYVY 0x00030000 /* CbY1CrY0 */ +#define C0_YUVE_XYUV 0x00000000 /* 420: .YUV */ +#define C0_YUVE_XYVU 0x00010000 /* 420: .YVU */ +#define C0_YUVE_XUVY 0x00020000 /* 420: .UVY */ +#define C0_YUVE_XVUY 0x00030000 /* 420: .VUY */ +/* Bayer bits 18,19 if needed */ +#define C0_HPOL_LOW 0x01000000 /* HSYNC polarity active low */ +#define C0_VPOL_LOW 0x02000000 /* VSYNC polarity active low */ +#define C0_VCLK_LOW 0x04000000 /* VCLK on falling edge */ +#define C0_DOWNSCALE 0x08000000 /* Enable downscaler */ +#define C0_SIFM_MASK 0xc0000000 /* SIF mode bits */ +#define C0_SIF_HVSYNC 0x00000000 /* Use H/VSYNC */ +#define CO_SOF_NOSYNC 0x40000000 /* Use inband active signaling */ + + +#define REG_CTRL1 0x40 /* Control 1 */ +#define C1_444ALPHA 0x00f00000 /* Alpha field in RGB444 */ +#define C1_ALPHA_SHFT 20 +#define C1_DMAB32 0x00000000 /* 32-byte DMA burst */ +#define C1_DMAB16 0x02000000 /* 16-byte DMA burst */ +#define C1_DMAB64 0x04000000 /* 64-byte DMA burst */ +#define C1_DMAB_MASK 0x06000000 +#define C1_TWOBUFS 0x08000000 /* Use only two DMA buffers */ +#define C1_PWRDWN 0x10000000 /* Power down */ + +#define REG_CLKCTRL 0x88 /* Clock control */ +#define CLK_DIV_MASK 0x0000ffff /* Upper bits RW "reserved" */ + +#define REG_GPR 0xb4 /* General purpose register. This + controls inputs to the power and reset + pins on the OV7670 used with OLPC; + other deployments could differ. */ +#define GPR_C1EN 0x00000020 /* Pad 1 (power down) enable */ +#define GPR_C0EN 0x00000010 /* Pad 0 (reset) enable */ +#define GPR_C1 0x00000002 /* Control 1 value */ +/* + * Control 0 is wired to reset on OLPC machines. For ov7x sensors, + * it is active low, for 0v6x, instead, it's active high. What + * fun. + */ +#define GPR_C0 0x00000001 /* Control 0 value */ + +#define REG_TWSIC0 0xb8 /* TWSI (smbus) control 0 */ +#define TWSIC0_EN 0x00000001 /* TWSI enable */ +#define TWSIC0_MODE 0x00000002 /* 1 = 16-bit, 0 = 8-bit */ +#define TWSIC0_SID 0x000003fc /* Slave ID */ +#define TWSIC0_SID_SHIFT 2 +#define TWSIC0_CLKDIV 0x0007fc00 /* Clock divider */ +#define TWSIC0_MASKACK 0x00400000 /* Mask ack from sensor */ +#define TWSIC0_OVMAGIC 0x00800000 /* Make it work on OV sensors */ + +#define REG_TWSIC1 0xbc /* TWSI control 1 */ +#define TWSIC1_DATA 0x0000ffff /* Data to/from camchip */ +#define TWSIC1_ADDR 0x00ff0000 /* Address (register) */ +#define TWSIC1_ADDR_SHIFT 16 +#define TWSIC1_READ 0x01000000 /* Set for read op */ +#define TWSIC1_WSTAT 0x02000000 /* Write status */ +#define TWSIC1_RVALID 0x04000000 /* Read data valid */ +#define TWSIC1_ERROR 0x08000000 /* Something screwed up */ + + +#define REG_UBAR 0xc4 /* Upper base address register */ + +/* + * Here's the weird global control registers which are said to live + * way up here. + */ +#define REG_GL_CSR 0x3004 /* Control/status register */ +#define GCSR_SRS 0x00000001 /* SW Reset set */ +#define GCSR_SRC 0x00000002 /* SW Reset clear */ +#define GCSR_MRS 0x00000004 /* Master reset set */ +#define GCSR_MRC 0x00000008 /* HW Reset clear */ +#define GCSR_CCIC_EN 0x00004000 /* CCIC Clock enable */ +#define REG_GL_IMASK 0x300c /* Interrupt mask register */ +#define GIMSK_CCIC_EN 0x00000004 /* CCIC Interrupt enable */ + +#define REG_LEN REG_GL_IMASK + 4 + + +/* + * Useful stuff that probably belongs somewhere global. + */ +#define VGA_WIDTH 640 +#define VGA_HEIGHT 480 diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c new file mode 100644 index 000000000000..2026c4983b26 --- /dev/null +++ b/drivers/media/video/cafe_ccic.c @@ -0,0 +1,2237 @@ +/* + * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe" + * multifunction chip. Currently works with the Omnivision OV7670 + * sensor. + * + * Copyright 2006 One Laptop Per Child Association, Inc. + * + * Written by Jonathan Corbet, corbet@lwn.net. + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "cafe_ccic-regs.h" + +#define CAFE_VERSION 0x000001 + + +/* + * Parameters. + */ +MODULE_AUTHOR("Jonathan Corbet "); +MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("Video"); + +/* + * Internal DMA buffer management. Since the controller cannot do S/G I/O, + * we must have physically contiguous buffers to bring frames into. + * These parameters control how many buffers we use, whether we + * allocate them at load time (better chance of success, but nails down + * memory) or when somebody tries to use the camera (riskier), and, + * for load-time allocation, how big they should be. + * + * The controller can cycle through three buffers. We could use + * more by flipping pointers around, but it probably makes little + * sense. + */ + +#define MAX_DMA_BUFS 3 +static int alloc_bufs_at_load = 0; +module_param(alloc_bufs_at_load, bool, 0444); +MODULE_PARM_DESC(alloc_bufs_at_load, + "Non-zero value causes DMA buffers to be allocated at module " + "load time. This increases the chances of successfully getting " + "those buffers, but at the cost of nailing down the memory from " + "the outset."); + +static int n_dma_bufs = 3; +module_param(n_dma_bufs, uint, 0644); +MODULE_PARM_DESC(n_dma_bufs, + "The number of DMA buffers to allocate. Can be either two " + "(saves memory, makes timing tighter) or three."); + +static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2; /* Worst case */ +module_param(dma_buf_size, uint, 0444); +MODULE_PARM_DESC(dma_buf_size, + "The size of the allocated DMA buffers. If actual operating " + "parameters require larger buffers, an attempt to reallocate " + "will be made."); + +static int min_buffers = 1; +module_param(min_buffers, uint, 0644); +MODULE_PARM_DESC(min_buffers, + "The minimum number of streaming I/O buffers we are willing " + "to work with."); + +static int max_buffers = 10; +module_param(max_buffers, uint, 0644); +MODULE_PARM_DESC(max_buffers, + "The maximum number of streaming I/O buffers an application " + "will be allowed to allocate. These buffers are big and live " + "in vmalloc space."); + +static int flip = 0; +module_param(flip, bool, 0444); +MODULE_PARM_DESC(flip, + "If set, the sensor will be instructed to flip the image " + "vertically."); + + +enum cafe_state { + S_NOTREADY, /* Not yet initialized */ + S_IDLE, /* Just hanging around */ + S_FLAKED, /* Some sort of problem */ + S_SINGLEREAD, /* In read() */ + S_SPECREAD, /* Speculative read (for future read()) */ + S_STREAMING /* Streaming data */ +}; + +/* + * Tracking of streaming I/O buffers. + */ +struct cafe_sio_buffer { + struct list_head list; + struct v4l2_buffer v4lbuf; + char *buffer; /* Where it lives in kernel space */ + int mapcount; + struct cafe_camera *cam; +}; + +/* + * A description of one of our devices. + * Locking: controlled by s_mutex. Certain fields, however, require + * the dev_lock spinlock; they are marked as such by comments. + * dev_lock is also required for access to device registers. + */ +struct cafe_camera +{ + enum cafe_state state; + unsigned long flags; /* Buffer status, mainly (dev_lock) */ + int users; /* How many open FDs */ + struct file *owner; /* Who has data access (v4l2) */ + + /* + * Subsystem structures. + */ + struct pci_dev *pdev; + struct video_device v4ldev; + struct i2c_adapter i2c_adapter; + struct i2c_client *sensor; + + unsigned char __iomem *regs; + struct list_head dev_list; /* link to other devices */ + + /* DMA buffers */ + unsigned int nbufs; /* How many are alloc'd */ + int next_buf; /* Next to consume (dev_lock) */ + unsigned int dma_buf_size; /* allocated size */ + void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */ + dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */ + unsigned int specframes; /* Unconsumed spec frames (dev_lock) */ + unsigned int sequence; /* Frame sequence number */ + unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */ + + /* Streaming buffers */ + unsigned int n_sbufs; /* How many we have */ + struct cafe_sio_buffer *sb_bufs; /* The array of housekeeping structs */ + struct list_head sb_avail; /* Available for data (we own) (dev_lock) */ + struct list_head sb_full; /* With data (user space owns) (dev_lock) */ + struct tasklet_struct s_tasklet; + + /* Current operating parameters */ + enum v4l2_chip_ident sensor_type; /* Currently ov7670 only */ + struct v4l2_pix_format pix_format; + + /* Locks */ + struct mutex s_mutex; /* Access to this structure */ + spinlock_t dev_lock; /* Access to device */ + + /* Misc */ + wait_queue_head_t smbus_wait; /* Waiting on i2c events */ + wait_queue_head_t iowait; /* Waiting on frame data */ +#ifdef CONFIG_VIDEO_ADV_DEBUG + struct dentry *dfs_regs; + struct dentry *dfs_cam_regs; +#endif +}; + +/* + * Status flags. Always manipulated with bit operations. + */ +#define CF_BUF0_VALID 0 /* Buffers valid - first three */ +#define CF_BUF1_VALID 1 +#define CF_BUF2_VALID 2 +#define CF_DMA_ACTIVE 3 /* A frame is incoming */ +#define CF_CONFIG_NEEDED 4 /* Must configure hardware */ + + + +/* + * Start over with DMA buffers - dev_lock needed. + */ +static void cafe_reset_buffers(struct cafe_camera *cam) +{ + int i; + + cam->next_buf = -1; + for (i = 0; i < cam->nbufs; i++) + clear_bit(i, &cam->flags); + cam->specframes = 0; +} + +static inline int cafe_needs_config(struct cafe_camera *cam) +{ + return test_bit(CF_CONFIG_NEEDED, &cam->flags); +} + +static void cafe_set_config_needed(struct cafe_camera *cam, int needed) +{ + if (needed) + set_bit(CF_CONFIG_NEEDED, &cam->flags); + else + clear_bit(CF_CONFIG_NEEDED, &cam->flags); +} + + + + +/* + * Debugging and related. + */ +#define cam_err(cam, fmt, arg...) \ + dev_err(&(cam)->pdev->dev, fmt, ##arg); +#define cam_warn(cam, fmt, arg...) \ + dev_warn(&(cam)->pdev->dev, fmt, ##arg); +#define cam_dbg(cam, fmt, arg...) \ + dev_dbg(&(cam)->pdev->dev, fmt, ##arg); + + +/* ---------------------------------------------------------------------*/ +/* + * We keep a simple list of known devices to search at open time. + */ +static LIST_HEAD(cafe_dev_list); +static DEFINE_MUTEX(cafe_dev_list_lock); + +static void cafe_add_dev(struct cafe_camera *cam) +{ + mutex_lock(&cafe_dev_list_lock); + list_add_tail(&cam->dev_list, &cafe_dev_list); + mutex_unlock(&cafe_dev_list_lock); +} + +static void cafe_remove_dev(struct cafe_camera *cam) +{ + mutex_lock(&cafe_dev_list_lock); + list_del(&cam->dev_list); + mutex_unlock(&cafe_dev_list_lock); +} + +static struct cafe_camera *cafe_find_dev(int minor) +{ + struct cafe_camera *cam; + + mutex_lock(&cafe_dev_list_lock); + list_for_each_entry(cam, &cafe_dev_list, dev_list) { + if (cam->v4ldev.minor == minor) + goto done; + } + cam = NULL; + done: + mutex_unlock(&cafe_dev_list_lock); + return cam; +} + + +static struct cafe_camera *cafe_find_by_pdev(struct pci_dev *pdev) +{ + struct cafe_camera *cam; + + mutex_lock(&cafe_dev_list_lock); + list_for_each_entry(cam, &cafe_dev_list, dev_list) { + if (cam->pdev == pdev) + goto done; + } + cam = NULL; + done: + mutex_unlock(&cafe_dev_list_lock); + return cam; +} + + +/* ------------------------------------------------------------------------ */ +/* + * Device register I/O + */ +static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg, + unsigned int val) +{ + iowrite32(val, cam->regs + reg); +} + +static inline unsigned int cafe_reg_read(struct cafe_camera *cam, + unsigned int reg) +{ + return ioread32(cam->regs + reg); +} + + +static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg, + unsigned int val, unsigned int mask) +{ + unsigned int v = cafe_reg_read(cam, reg); + + v = (v & ~mask) | (val & mask); + cafe_reg_write(cam, reg, v); +} + +static inline void cafe_reg_clear_bit(struct cafe_camera *cam, + unsigned int reg, unsigned int val) +{ + cafe_reg_write_mask(cam, reg, 0, val); +} + +static inline void cafe_reg_set_bit(struct cafe_camera *cam, + unsigned int reg, unsigned int val) +{ + cafe_reg_write_mask(cam, reg, val, val); +} + + + +/* -------------------------------------------------------------------- */ +/* + * The I2C/SMBUS interface to the camera itself starts here. The + * controller handles SMBUS itself, presenting a relatively simple register + * interface; all we have to do is to tell it where to route the data. + */ +#define CAFE_SMBUS_TIMEOUT (HZ) /* generous */ + +static int cafe_smbus_write_done(struct cafe_camera *cam) +{ + unsigned long flags; + int c1; + + /* + * We must delay after the interrupt, or the controller gets confused + * and never does give us good status. Fortunately, we don't do this + * often. + */ + udelay(20); + spin_lock_irqsave(&cam->dev_lock, flags); + c1 = cafe_reg_read(cam, REG_TWSIC1); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT; +} + +static int cafe_smbus_write_data(struct cafe_camera *cam, + u16 addr, u8 command, u8 value) +{ + unsigned int rval; + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); + rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ + /* + * Marvell sez set clkdiv to all 1's for now. + */ + rval |= TWSIC0_CLKDIV; + cafe_reg_write(cam, REG_TWSIC0, rval); + (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */ + rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); + cafe_reg_write(cam, REG_TWSIC1, rval); + spin_unlock_irqrestore(&cam->dev_lock, flags); + msleep(2); /* Required or things flake */ + + wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam), + CAFE_SMBUS_TIMEOUT); + spin_lock_irqsave(&cam->dev_lock, flags); + rval = cafe_reg_read(cam, REG_TWSIC1); + spin_unlock_irqrestore(&cam->dev_lock, flags); + + if (rval & TWSIC1_WSTAT) { + cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr, + command, value); + return -EIO; + } + if (rval & TWSIC1_ERROR) { + cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr, + command, value); + return -EIO; + } + return 0; +} + + + +static int cafe_smbus_read_done(struct cafe_camera *cam) +{ + unsigned long flags; + int c1; + + /* + * We must delay after the interrupt, or the controller gets confused + * and never does give us good status. Fortunately, we don't do this + * often. + */ + udelay(20); + spin_lock_irqsave(&cam->dev_lock, flags); + c1 = cafe_reg_read(cam, REG_TWSIC1); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return c1 & (TWSIC1_RVALID|TWSIC1_ERROR); +} + + + +static int cafe_smbus_read_data(struct cafe_camera *cam, + u16 addr, u8 command, u8 *value) +{ + unsigned int rval; + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); + rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ + /* + * Marvel sez set clkdiv to all 1's for now. + */ + rval |= TWSIC0_CLKDIV; + cafe_reg_write(cam, REG_TWSIC0, rval); + (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */ + rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); + cafe_reg_write(cam, REG_TWSIC1, rval); + spin_unlock_irqrestore(&cam->dev_lock, flags); + + wait_event_timeout(cam->smbus_wait, + cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT); + spin_lock_irqsave(&cam->dev_lock, flags); + rval = cafe_reg_read(cam, REG_TWSIC1); + spin_unlock_irqrestore(&cam->dev_lock, flags); + + if (rval & TWSIC1_ERROR) { + cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command); + return -EIO; + } + if (! (rval & TWSIC1_RVALID)) { + cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr, + command); + return -EIO; + } + *value = rval & 0xff; + return 0; +} + +/* + * Perform a transfer over SMBUS. This thing is called under + * the i2c bus lock, so we shouldn't race with ourselves... + */ +static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char rw, u8 command, + int size, union i2c_smbus_data *data) +{ + struct cafe_camera *cam = i2c_get_adapdata(adapter); + int ret = -EINVAL; + + /* + * Refuse to talk to anything but OV cam chips. We should + * never even see an attempt to do so, but one never knows. + */ + if (cam->sensor && addr != cam->sensor->addr) { + cam_err(cam, "funky smbus addr %d\n", addr); + return -EINVAL; + } + /* + * This interface would appear to only do byte data ops. OK + * it can do word too, but the cam chip has no use for that. + */ + if (size != I2C_SMBUS_BYTE_DATA) { + cam_err(cam, "funky xfer size %d\n", size); + return -EINVAL; + } + + if (rw == I2C_SMBUS_WRITE) + ret = cafe_smbus_write_data(cam, addr, command, data->byte); + else if (rw == I2C_SMBUS_READ) + ret = cafe_smbus_read_data(cam, addr, command, &data->byte); + return ret; +} + + +static void cafe_smbus_enable_irq(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +static u32 cafe_smbus_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA; +} + +static struct i2c_algorithm cafe_smbus_algo = { + .smbus_xfer = cafe_smbus_xfer, + .functionality = cafe_smbus_func +}; + +/* Somebody is on the bus */ +static int cafe_cam_init(struct cafe_camera *cam); + +static int cafe_smbus_attach(struct i2c_client *client) +{ + struct cafe_camera *cam = i2c_get_adapdata(client->adapter); + + /* + * Don't talk to chips we don't recognize. + */ + cam_err(cam, "smbus_attach id = %d\n", client->driver->id); + if (client->driver->id == I2C_DRIVERID_OV7670) { + cam->sensor = client; + return cafe_cam_init(cam); + } + return -EINVAL; +} + +static int cafe_smbus_detach(struct i2c_client *client) +{ + struct cafe_camera *cam = i2c_get_adapdata(client->adapter); + + if (cam->sensor == client) + cam->sensor = NULL; /* Bummer, no camera */ + return 0; +} + +static int cafe_smbus_setup(struct cafe_camera *cam) +{ + struct i2c_adapter *adap = &cam->i2c_adapter; + int ret; + + cafe_smbus_enable_irq(cam); + adap->id = I2C_HW_SMBUS_CAFE; + adap->class = I2C_CLASS_CAM_DIGITAL; + adap->owner = THIS_MODULE; + adap->client_register = cafe_smbus_attach; + adap->client_unregister = cafe_smbus_detach; + adap->algo = &cafe_smbus_algo; + strcpy(adap->name, "cafe_ccic"); + i2c_set_adapdata(adap, cam); + ret = i2c_add_adapter(adap); + if (ret) + printk(KERN_ERR "Unable to register cafe i2c adapter\n"); + return ret; +} + +static void cafe_smbus_shutdown(struct cafe_camera *cam) +{ + i2c_del_adapter(&cam->i2c_adapter); +} + + +/* ------------------------------------------------------------------- */ +/* + * Deal with the controller. + */ + +/* + * Do everything we think we need to have the interface operating + * according to the desired format. + */ +static void cafe_ctlr_dma(struct cafe_camera *cam) +{ + /* + * Store the first two Y buffers (we aren't supporting + * planar formats for now, so no UV bufs). Then either + * set the third if it exists, or tell the controller + * to just use two. + */ + cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]); + cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]); + if (cam->nbufs > 2) { + cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]); + cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS); + } + else + cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); + cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */ +} + +static void cafe_ctlr_image(struct cafe_camera *cam) +{ + int imgsz; + struct v4l2_pix_format *fmt = &cam->pix_format; + + imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | + (fmt->bytesperline & IMGSZ_H_MASK); + cafe_reg_write(cam, REG_IMGSIZE, imgsz); + cafe_reg_write(cam, REG_IMGOFFSET, 0); + /* YPITCH just drops the last two bits */ + cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline, + IMGP_YP_MASK); + /* + * Tell the controller about the image format we are using. + */ + switch (cam->pix_format.pixelformat) { + case V4L2_PIX_FMT_YUYV: + cafe_reg_write_mask(cam, REG_CTRL0, + C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV, + C0_DF_MASK); + break; + + /* + * For "fake rgb32" get the image pitch right. + */ + case V4L2_PIX_FMT_RGB32: + cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline/2, + IMGP_YP_MASK); + imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | + ((fmt->bytesperline/2) & IMGSZ_H_MASK); + cafe_reg_write(cam, REG_IMGSIZE, imgsz); + /* fall into ... */ + case V4L2_PIX_FMT_RGB444: + cafe_reg_write_mask(cam, REG_CTRL0, + C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB, + C0_DF_MASK); + /* Alpha value? */ + break; + + case V4L2_PIX_FMT_RGB565: + cafe_reg_write_mask(cam, REG_CTRL0, + C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR, + C0_DF_MASK); + break; + + default: + cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat); + break; + } + /* + * Make sure it knows we want to use hsync/vsync. + */ + cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, + C0_SIFM_MASK); +} + + +/* + * Configure the controller for operation; caller holds the + * device mutex. + */ +static int cafe_ctlr_configure(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_ctlr_dma(cam); + cafe_ctlr_image(cam); + cafe_set_config_needed(cam, 0); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return 0; +} + +static void cafe_ctlr_irq_enable(struct cafe_camera *cam) +{ + /* + * Clear any pending interrupts, since we do not + * expect to have I/O active prior to enabling. + */ + cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); + cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS); +} + +static void cafe_ctlr_irq_disable(struct cafe_camera *cam) +{ + cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); +} + +/* + * Make the controller start grabbing images. Everything must + * be set up before doing this. + */ +static void cafe_ctlr_start(struct cafe_camera *cam) +{ + /* set_bit performs a read, so no other barrier should be + needed here */ + cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE); +} + +static void cafe_ctlr_stop(struct cafe_camera *cam) +{ + cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); +} + +static void cafe_ctlr_init(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + /* + * Added magic to bring up the hardware on the B-Test board + */ + cafe_reg_write(cam, 0x3038, 0x8); + cafe_reg_write(cam, 0x315c, 0x80008); + /* + * Go through the dance needed to wake the device up. + * Note that these registers are global and shared + * with the NAND and SD devices. Interaction between the + * three still needs to be examined. + */ + cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ + cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); + cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); + mdelay(5); /* FIXME revisit this */ + cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); + cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); + /* + * Make sure it's not powered down. + */ + cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); + /* + * Turn off the enable bit. It sure should be off anyway, + * but it's good to be sure. + */ + cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); + /* + * Mask all interrupts. + */ + cafe_reg_write(cam, REG_IRQMASK, 0); + /* + * Clock the sensor appropriately. Controller clock should + * be 48MHz, sensor "typical" value is half that. + */ + cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + + +/* + * Stop the controller, and don't return until we're really sure that no + * further DMA is going on. + */ +static void cafe_ctlr_stop_dma(struct cafe_camera *cam) +{ + unsigned long flags; + + /* + * Theory: stop the camera controller (whether it is operating + * or not). Delay briefly just in case we race with the SOF + * interrupt, then wait until no DMA is active. + */ + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_ctlr_stop(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); + mdelay(1); + wait_event_timeout(cam->iowait, + !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ); + if (test_bit(CF_DMA_ACTIVE, &cam->flags)) + cam_err(cam, "Timeout waiting for DMA to end\n"); + /* This would be bad news - what now? */ + spin_lock_irqsave(&cam->dev_lock, flags); + cam->state = S_IDLE; + cafe_ctlr_irq_disable(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +/* + * Power up and down. + */ +static void cafe_ctlr_power_up(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); + /* + * Put the sensor into operational mode (assumes OLPC-style + * wiring). Control 0 is reset - set to 1 to operate. + * Control 1 is power down, set to 0 to operate. + */ + cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); + mdelay(1); /* Marvell says 1ms will do it */ + cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); + mdelay(1); /* Enough? */ + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +static void cafe_ctlr_power_down(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); + cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +/* -------------------------------------------------------------------- */ +/* + * Communications with the sensor. + */ + +static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg) +{ + struct i2c_client *sc = cam->sensor; + int ret; + + if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL) + return -EINVAL; + ret = sc->driver->command(sc, cmd, arg); + if (ret == -EPERM) /* Unsupported command */ + return 0; + return ret; +} + +static int __cafe_cam_reset(struct cafe_camera *cam) +{ + int zero = 0; + return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero); +} + +/* + * We have found the sensor on the i2c. Let's try to have a + * conversation. + */ +static int cafe_cam_init(struct cafe_camera *cam) +{ + int ret; + + mutex_lock(&cam->s_mutex); + if (cam->state != S_NOTREADY) + cam_warn(cam, "Cam init with device in funky state %d", + cam->state); + ret = __cafe_cam_reset(cam); + if (ret) + goto out; + ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type); + if (ret) + goto out; +// if (cam->sensor->addr != OV7xx0_SID) { + if (cam->sensor_type != V4L2_IDENT_OV7670) { + cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr); + ret = -EINVAL; + goto out; + } +/* Get/set parameters? */ + ret = 0; + cam->state = S_IDLE; + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +/* + * Configure the sensor to match the parameters we have. Caller should + * hold s_mutex + */ +static int cafe_cam_set_flip(struct cafe_camera *cam) +{ + struct v4l2_control ctrl; + + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.id = V4L2_CID_VFLIP; + ctrl.value = flip; + return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl); +} + + +static int cafe_cam_configure(struct cafe_camera *cam) +{ + struct v4l2_format fmt; + int ret, zero = 0; + + if (cam->state != S_IDLE) + return -EINVAL; + fmt.fmt.pix = cam->pix_format; + ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero); + if (ret == 0) + ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt); + /* + * OV7670 does weird things if flip is set *before* format... + */ + ret += cafe_cam_set_flip(cam); + return ret; +} + +/* -------------------------------------------------------------------- */ +/* + * DMA buffer management. These functions need s_mutex held. + */ + +/* FIXME: this is inefficient as hell, since dma_alloc_coherent just + * does a get_free_pages() call, and we waste a good chunk of an orderN + * allocation. Should try to allocate the whole set in one chunk. + */ +static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime) +{ + int i; + + cafe_set_config_needed(cam, 1); + if (loadtime) + cam->dma_buf_size = dma_buf_size; + else { + cam->dma_buf_size = cam->pix_format.sizeimage; + if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32) + cam->dma_buf_size /= 2; + } + if (n_dma_bufs > 3) + n_dma_bufs = 3; + + cam->nbufs = 0; + for (i = 0; i < n_dma_bufs; i++) { + cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev, + cam->dma_buf_size, cam->dma_handles + i, + GFP_KERNEL); + if (cam->dma_bufs[i] == NULL) { + cam_warn(cam, "Failed to allocate DMA buffer\n"); + break; + } + /* For debug, remove eventually */ + memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size); + (cam->nbufs)++; + } + + switch (cam->nbufs) { + case 1: + dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size, + cam->dma_bufs[0], cam->dma_handles[0]); + cam->nbufs = 0; + case 0: + cam_err(cam, "Insufficient DMA buffers, cannot operate\n"); + return -ENOMEM; + + case 2: + if (n_dma_bufs > 2) + cam_warn(cam, "Will limp along with only 2 buffers\n"); + break; + } + return 0; +} + +static void cafe_free_dma_bufs(struct cafe_camera *cam) +{ + int i; + + for (i = 0; i < cam->nbufs; i++) { + dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size, + cam->dma_bufs[i], cam->dma_handles[i]); + cam->dma_bufs[i] = NULL; + } + cam->nbufs = 0; +} + + + + + +/* ----------------------------------------------------------------------- */ +/* + * Here starts the V4L2 interface code. + */ + +/* + * Read an image from the device. + */ +static ssize_t cafe_deliver_buffer(struct cafe_camera *cam, + char __user *buffer, size_t len, loff_t *pos) +{ + int bufno; + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + if (cam->next_buf < 0) { + cam_err(cam, "deliver_buffer: No next buffer\n"); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return -EIO; + } + bufno = cam->next_buf; + clear_bit(bufno, &cam->flags); + if (++(cam->next_buf) >= cam->nbufs) + cam->next_buf = 0; + if (! test_bit(cam->next_buf, &cam->flags)) + cam->next_buf = -1; + cam->specframes = 0; + spin_unlock_irqrestore(&cam->dev_lock, flags); + + if (len > cam->pix_format.sizeimage) + len = cam->pix_format.sizeimage; + if (copy_to_user(buffer, cam->dma_bufs[bufno], len)) + return -EFAULT; + (*pos) += len; + return len; +} + +/* + * Get everything ready, and start grabbing frames. + */ +static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state) +{ + int ret; + unsigned long flags; + + /* + * Configuration. If we still don't have DMA buffers, + * make one last, desperate attempt. + */ + if (cam->nbufs == 0) + if (cafe_alloc_dma_bufs(cam, 0)) + return -ENOMEM; + + if (cafe_needs_config(cam)) { + cafe_cam_configure(cam); + ret = cafe_ctlr_configure(cam); + if (ret) + return ret; + } + + /* + * Turn it loose. + */ + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_reset_buffers(cam); + cafe_ctlr_irq_enable(cam); + cam->state = state; + cafe_ctlr_start(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return 0; +} + + +static ssize_t cafe_v4l_read(struct file *filp, + char __user *buffer, size_t len, loff_t *pos) +{ + struct cafe_camera *cam = filp->private_data; + int ret; + + /* + * Perhaps we're in speculative read mode and already + * have data? + */ + mutex_lock(&cam->s_mutex); + if (cam->state == S_SPECREAD) { + if (cam->next_buf >= 0) { + ret = cafe_deliver_buffer(cam, buffer, len, pos); + if (ret != 0) + goto out_unlock; + } + } else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) { + ret = -EIO; + goto out_unlock; + } else if (cam->state != S_IDLE) { + ret = -EBUSY; + goto out_unlock; + } + + /* + * v4l2: multiple processes can open the device, but only + * one gets to grab data from it. + */ + if (cam->owner && cam->owner != filp) { + ret = -EBUSY; + goto out_unlock; + } + cam->owner = filp; + + /* + * Do setup if need be. + */ + if (cam->state != S_SPECREAD) { + ret = cafe_read_setup(cam, S_SINGLEREAD); + if (ret) + goto out_unlock; + } + /* + * Wait for something to happen. This should probably + * be interruptible (FIXME). + */ + wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ); + if (cam->next_buf < 0) { + cam_err(cam, "read() operation timed out\n"); + cafe_ctlr_stop_dma(cam); + ret = -EIO; + goto out_unlock; + } + /* + * Give them their data and we should be done. + */ + ret = cafe_deliver_buffer(cam, buffer, len, pos); + + out_unlock: + mutex_unlock(&cam->s_mutex); + return ret; +} + + + + + + + + +/* + * Streaming I/O support. + */ + + + +static int cafe_vidioc_streamon(struct file *filp, void *priv, + enum v4l2_buf_type type) +{ + struct cafe_camera *cam = filp->private_data; + int ret = -EINVAL; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out; + mutex_lock(&cam->s_mutex); + if (cam->state != S_IDLE || cam->n_sbufs == 0) + goto out_unlock; + + cam->sequence = 0; + ret = cafe_read_setup(cam, S_STREAMING); + + out_unlock: + mutex_unlock(&cam->s_mutex); + out: + return ret; +} + + +static int cafe_vidioc_streamoff(struct file *filp, void *priv, + enum v4l2_buf_type type) +{ + struct cafe_camera *cam = filp->private_data; + int ret = -EINVAL; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out; + mutex_lock(&cam->s_mutex); + if (cam->state != S_STREAMING) + goto out_unlock; + + cafe_ctlr_stop_dma(cam); + ret = 0; + + out_unlock: + mutex_unlock(&cam->s_mutex); + out: + return ret; +} + + + +static int cafe_setup_siobuf(struct cafe_camera *cam, int index) +{ + struct cafe_sio_buffer *buf = cam->sb_bufs + index; + + INIT_LIST_HEAD(&buf->list); + buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage); + buf->buffer = vmalloc_user(buf->v4lbuf.length); + if (buf->buffer == NULL) + return -ENOMEM; + buf->mapcount = 0; + buf->cam = cam; + + buf->v4lbuf.index = index; + buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf->v4lbuf.field = V4L2_FIELD_NONE; + buf->v4lbuf.memory = V4L2_MEMORY_MMAP; + /* + * Offset: must be 32-bit even on a 64-bit system. video-buf + * just uses the length times the index, but the spec warns + * against doing just that - vma merging problems. So we + * leave a gap between each pair of buffers. + */ + buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; + return 0; +} + +static int cafe_free_sio_buffers(struct cafe_camera *cam) +{ + int i; + + /* + * If any buffers are mapped, we cannot free them at all. + */ + for (i = 0; i < cam->n_sbufs; i++) + if (cam->sb_bufs[i].mapcount > 0) + return -EBUSY; + /* + * OK, let's do it. + */ + for (i = 0; i < cam->n_sbufs; i++) + vfree(cam->sb_bufs[i].buffer); + cam->n_sbufs = 0; + kfree(cam->sb_bufs); + cam->sb_bufs = NULL; + INIT_LIST_HEAD(&cam->sb_avail); + INIT_LIST_HEAD(&cam->sb_full); + return 0; +} + + + +static int cafe_vidioc_reqbufs(struct file *filp, void *priv, + struct v4l2_requestbuffers *req) +{ + struct cafe_camera *cam = filp->private_data; + int ret; + + /* + * Make sure it's something we can do. User pointers could be + * implemented without great pain, but that's not been done yet. + */ + if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (req->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + /* + * If they ask for zero buffers, they really want us to stop streaming + * (if it's happening) and free everything. Should we check owner? + */ + mutex_lock(&cam->s_mutex); + if (req->count == 0) { + if (cam->state == S_STREAMING) + cafe_ctlr_stop_dma(cam); + ret = cafe_free_sio_buffers (cam); + goto out; + } + /* + * Device needs to be idle and working. We *could* try to do the + * right thing in S_SPECREAD by shutting things down, but it + * probably doesn't matter. + */ + if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) { + ret = -EBUSY; + goto out; + } + cam->owner = filp; + + if (req->count < min_buffers) + req->count = min_buffers; + else if (req->count > max_buffers) + req->count = max_buffers; + if (cam->n_sbufs > 0) { + ret = cafe_free_sio_buffers(cam); + if (ret) + goto out; + } + + cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer), + GFP_KERNEL); + if (cam->sb_bufs == NULL) { + ret = -ENOMEM; + goto out; + } + for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) { + ret = cafe_setup_siobuf(cam, cam->n_sbufs); + if (ret) + break; + } + + if (cam->n_sbufs == 0) /* no luck at all - ret already set */ + kfree(cam->sb_bufs); + else + ret = 0; + req->count = cam->n_sbufs; /* In case of partial success */ + + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int cafe_vidioc_querybuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct cafe_camera *cam = filp->private_data; + int ret = -EINVAL; + + mutex_lock(&cam->s_mutex); + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out; + if (buf->index < 0 || buf->index >= cam->n_sbufs) + goto out; + *buf = cam->sb_bufs[buf->index].v4lbuf; + ret = 0; + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int cafe_vidioc_qbuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct cafe_camera *cam = filp->private_data; + struct cafe_sio_buffer *sbuf; + int ret = -EINVAL; + unsigned long flags; + + mutex_lock(&cam->s_mutex); + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out; + if (buf->index < 0 || buf->index >= cam->n_sbufs) + goto out; + sbuf = cam->sb_bufs + buf->index; + if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) { + ret = 0; /* Already queued?? */ + goto out; + } + if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) { + /* Spec doesn't say anything, seems appropriate tho */ + ret = -EBUSY; + goto out; + } + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; + spin_lock_irqsave(&cam->dev_lock, flags); + list_add(&sbuf->list, &cam->sb_avail); + spin_unlock_irqrestore(&cam->dev_lock, flags); + ret = 0; + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int cafe_vidioc_dqbuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct cafe_camera *cam = filp->private_data; + struct cafe_sio_buffer *sbuf; + int ret = -EINVAL; + unsigned long flags; + + mutex_lock(&cam->s_mutex); + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out_unlock; + if (cam->state != S_STREAMING) + goto out_unlock; + if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto out_unlock; + } + + while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) { + mutex_unlock(&cam->s_mutex); + if (wait_event_interruptible(cam->iowait, + !list_empty(&cam->sb_full))) { + ret = -ERESTARTSYS; + goto out; + } + mutex_lock(&cam->s_mutex); + } + + if (cam->state != S_STREAMING) + ret = -EINTR; + else { + spin_lock_irqsave(&cam->dev_lock, flags); + /* Should probably recheck !list_empty() here */ + sbuf = list_entry(cam->sb_full.next, + struct cafe_sio_buffer, list); + list_del_init(&sbuf->list); + spin_unlock_irqrestore(&cam->dev_lock, flags); + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; + *buf = sbuf->v4lbuf; + ret = 0; + } + + out_unlock: + mutex_unlock(&cam->s_mutex); + out: + return ret; +} + + + +static void cafe_v4l_vm_open(struct vm_area_struct *vma) +{ + struct cafe_sio_buffer *sbuf = vma->vm_private_data; + /* + * Locking: done under mmap_sem, so we don't need to + * go back to the camera lock here. + */ + sbuf->mapcount++; +} + + +static void cafe_v4l_vm_close(struct vm_area_struct *vma) +{ + struct cafe_sio_buffer *sbuf = vma->vm_private_data; + + mutex_lock(&sbuf->cam->s_mutex); + sbuf->mapcount--; + /* Docs say we should stop I/O too... */ + if (sbuf->mapcount == 0) + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; + mutex_unlock(&sbuf->cam->s_mutex); +} + +static struct vm_operations_struct cafe_v4l_vm_ops = { + .open = cafe_v4l_vm_open, + .close = cafe_v4l_vm_close +}; + + +static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct cafe_camera *cam = filp->private_data; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + int ret = -EINVAL; + int i; + struct cafe_sio_buffer *sbuf = NULL; + + if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) + return -EINVAL; + /* + * Find the buffer they are looking for. + */ + mutex_lock(&cam->s_mutex); + for (i = 0; i < cam->n_sbufs; i++) + if (cam->sb_bufs[i].v4lbuf.m.offset == offset) { + sbuf = cam->sb_bufs + i; + break; + } + if (sbuf == NULL) + goto out; + + ret = remap_vmalloc_range(vma, sbuf->buffer, 0); + if (ret) + goto out; + vma->vm_flags |= VM_DONTEXPAND; + vma->vm_private_data = sbuf; + vma->vm_ops = &cafe_v4l_vm_ops; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; + cafe_v4l_vm_open(vma); + ret = 0; + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + + + +static int cafe_v4l_open(struct inode *inode, struct file *filp) +{ + struct cafe_camera *cam; + + cam = cafe_find_dev(iminor(inode)); + if (cam == NULL) + return -ENODEV; + filp->private_data = cam; + + mutex_lock(&cam->s_mutex); + if (cam->users == 0) { + cafe_ctlr_power_up(cam); + __cafe_cam_reset(cam); + cafe_set_config_needed(cam, 1); + /* FIXME make sure this is complete */ + } + (cam->users)++; + mutex_unlock(&cam->s_mutex); + return 0; +} + + +static int cafe_v4l_release(struct inode *inode, struct file *filp) +{ + struct cafe_camera *cam = filp->private_data; + + mutex_lock(&cam->s_mutex); + (cam->users)--; + if (filp == cam->owner) { + cafe_ctlr_stop_dma(cam); + cafe_free_sio_buffers(cam); + cam->owner = NULL; + } + if (cam->users == 0) + cafe_ctlr_power_down(cam); + mutex_unlock(&cam->s_mutex); + return 0; +} + + + +static unsigned int cafe_v4l_poll(struct file *filp, + struct poll_table_struct *pt) +{ + struct cafe_camera *cam = filp->private_data; + + poll_wait(filp, &cam->iowait, pt); + if (cam->next_buf >= 0) + return POLLIN | POLLRDNORM; + return 0; +} + + + +static int cafe_vidioc_queryctrl(struct file *filp, void *priv, + struct v4l2_queryctrl *qc) +{ + struct cafe_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int cafe_vidioc_g_ctrl(struct file *filp, void *priv, + struct v4l2_control *ctrl) +{ + struct cafe_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int cafe_vidioc_s_ctrl(struct file *filp, void *priv, + struct v4l2_control *ctrl) +{ + struct cafe_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl); + mutex_unlock(&cam->s_mutex); + return ret; +} + + + + + +static int cafe_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strcpy(cap->driver, "cafe_ccic"); + strcpy(cap->card, "cafe_ccic"); + cap->version = CAFE_VERSION; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + return 0; +} + + +/* + * The default format we use until somebody says otherwise. + */ +static struct v4l2_pix_format cafe_def_pix_format = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .pixelformat = V4L2_PIX_FMT_YUYV, + .field = V4L2_FIELD_NONE, + .bytesperline = VGA_WIDTH*2, + .sizeimage = VGA_WIDTH*VGA_HEIGHT*2, +}; + +static int cafe_vidioc_enum_fmt_cap(struct file *filp, + void *priv, struct v4l2_fmtdesc *fmt) +{ + struct cafe_camera *cam = priv; + int ret; + + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + struct cafe_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt); + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + struct cafe_camera *cam = priv; + int ret; + + /* + * Can't do anything if the device is not idle + * Also can't if there are streaming buffers in place. + */ + if (cam->state != S_IDLE || cam->n_sbufs > 0) + return -EBUSY; + /* + * See if the formatting works in principle. + */ + ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt); + if (ret) + return ret; + /* + * Now we start to change things for real, so let's do it + * under lock. + */ + mutex_lock(&cam->s_mutex); + cam->pix_format = fmt->fmt.pix; + /* + * Make sure we have appropriate DMA buffers. + */ + ret = -ENOMEM; + if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage) + cafe_free_dma_bufs(cam); + if (cam->nbufs == 0) { + if (cafe_alloc_dma_bufs(cam, 0)) + goto out; + } + /* + * It looks like this might work, so let's program the sensor. + */ + ret = cafe_cam_configure(cam); + if (! ret) + ret = cafe_ctlr_configure(cam); + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +/* + * Return our stored notion of how the camera is/should be configured. + * The V4l2 spec wants us to be smarter, and actually get this from + * the camera (and not mess with it at open time). Someday. + */ +static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv, + struct v4l2_format *f) +{ + struct cafe_camera *cam = priv; + + f->fmt.pix = cam->pix_format; + return 0; +} + +/* + * We only have one input - the sensor - so minimize the nonsense here. + */ +static int cafe_vidioc_enum_input(struct file *filp, void *priv, + struct v4l2_input *input) +{ + if (input->index != 0) + return -EINVAL; + + input->type = V4L2_INPUT_TYPE_CAMERA; + input->std = V4L2_STD_ALL; /* Not sure what should go here */ + strcpy(input->name, "Camera"); + return 0; +} + +static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + return 0; +} + +/* from vivi.c */ +static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a) +{ + return 0; +} + + +/* + * The TV Norm stuff is weird - we're a camera with little to do with TV, + * really. The following is what vivi does. + */ +static struct v4l2_tvnorm cafe_tvnorm[] = { + { + .name = "NTSC-M", + .id = V4L2_STD_NTSC_M, + } +}; + + +void cafe_v4l_dev_release(struct video_device *vd) +{ + struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev); + + kfree(cam); +} + + +/* + * This template device holds all of those v4l2 methods; we + * clone it for specific real devices. + */ + +static struct file_operations cafe_v4l_fops = { + .owner = THIS_MODULE, + .open = cafe_v4l_open, + .release = cafe_v4l_release, + .read = cafe_v4l_read, + .poll = cafe_v4l_poll, + .mmap = cafe_v4l_mmap, + .ioctl = video_ioctl2, + .llseek = no_llseek, +}; + +static struct video_device cafe_v4l_template = { + .name = "cafe", + .type = VFL_TYPE_GRABBER, + .type2 = VID_TYPE_CAPTURE, + .minor = -1, /* Get one dynamically */ + .tvnorms = cafe_tvnorm, + .tvnormsize = 1, + .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ + + .fops = &cafe_v4l_fops, + .release = cafe_v4l_dev_release, + + .vidioc_querycap = cafe_vidioc_querycap, + .vidioc_enum_fmt_cap = cafe_vidioc_enum_fmt_cap, + .vidioc_try_fmt_cap = cafe_vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = cafe_vidioc_s_fmt_cap, + .vidioc_g_fmt_cap = cafe_vidioc_g_fmt_cap, + .vidioc_enum_input = cafe_vidioc_enum_input, + .vidioc_g_input = cafe_vidioc_g_input, + .vidioc_s_input = cafe_vidioc_s_input, + .vidioc_s_std = cafe_vidioc_s_std, + .vidioc_reqbufs = cafe_vidioc_reqbufs, + .vidioc_querybuf = cafe_vidioc_querybuf, + .vidioc_qbuf = cafe_vidioc_qbuf, + .vidioc_dqbuf = cafe_vidioc_dqbuf, + .vidioc_streamon = cafe_vidioc_streamon, + .vidioc_streamoff = cafe_vidioc_streamoff, + .vidioc_queryctrl = cafe_vidioc_queryctrl, + .vidioc_g_ctrl = cafe_vidioc_g_ctrl, + .vidioc_s_ctrl = cafe_vidioc_s_ctrl, + /* Do cropping someday */ +}; + + + + + + + +/* ---------------------------------------------------------------------- */ +/* + * Interrupt handler stuff + */ + +/* + * Create RGB32 from RGB444 so it can be displayed before the applications + * know about the latter format. + */ +static void cafe_fake_rgb32(struct cafe_camera *cam, char *dest, char *src) +{ + int i; + u16 *ssrc = (u16 *) src; + + /* RGB444 version */ + for (i = 0; i < cam->pix_format.sizeimage; i += 4) { + // dest[0] = (*ssrc & 0xf000) >> 8; + dest[0] = (*ssrc & 0x000f) << 4; + dest[1] = (*ssrc & 0x00f0); + dest[2] = (*ssrc & 0x0f00) >> 4; + dest[3] = (*ssrc & 0xf000); /* Alpha */ + dest += 4; + ssrc++; + } +} + + +static void cafe_frame_tasklet(unsigned long data) +{ + struct cafe_camera *cam = (struct cafe_camera *) data; + int i; + unsigned long flags; + struct cafe_sio_buffer *sbuf; + + spin_lock_irqsave(&cam->dev_lock, flags); + for (i = 0; i < cam->nbufs; i++) { + int bufno = cam->next_buf; + if (bufno < 0) { /* "will never happen" */ + cam_err(cam, "No valid bufs in tasklet!\n"); + break; + } + if (++(cam->next_buf) >= cam->nbufs) + cam->next_buf = 0; + if (! test_bit(bufno, &cam->flags)) + continue; + if (list_empty(&cam->sb_avail)) + break; /* Leave it valid, hope for better later */ + clear_bit(bufno, &cam->flags); + /* + * We could perhaps drop the spinlock during this + * big copy. Something to consider. + */ + sbuf = list_entry(cam->sb_avail.next, + struct cafe_sio_buffer, list); + if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32) + cafe_fake_rgb32(cam, sbuf->buffer, cam->dma_bufs[bufno]); + else + memcpy(sbuf->buffer, cam->dma_bufs[bufno], + cam->pix_format.sizeimage); + sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; + sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; + list_move_tail(&sbuf->list, &cam->sb_full); + } + if (! list_empty(&cam->sb_full)) + wake_up(&cam->iowait); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + + + +static void cafe_frame_complete(struct cafe_camera *cam, int frame) +{ + /* + * Basic frame housekeeping. + */ + if (test_bit(frame, &cam->flags) && printk_ratelimit()) + cam_err(cam, "Frame overrun on %d, frames lost\n", frame); + set_bit(frame, &cam->flags); + clear_bit(CF_DMA_ACTIVE, &cam->flags); + if (cam->next_buf < 0) + cam->next_buf = frame; + cam->buf_seq[frame] = ++(cam->sequence); + + switch (cam->state) { + /* + * If in single read mode, try going speculative. + */ + case S_SINGLEREAD: + cam->state = S_SPECREAD; + cam->specframes = 0; + wake_up(&cam->iowait); + break; + + /* + * If we are already doing speculative reads, and nobody is + * reading them, just stop. + */ + case S_SPECREAD: + if (++(cam->specframes) >= cam->nbufs) { + cafe_ctlr_stop(cam); + cafe_ctlr_irq_disable(cam); + cam->state = S_IDLE; + } + wake_up(&cam->iowait); + break; + /* + * For the streaming case, we defer the real work to the + * camera tasklet. + * + * FIXME: if the application is not consuming the buffers, + * we should eventually put things on hold and restart in + * vidioc_dqbuf(). + */ + case S_STREAMING: + tasklet_schedule(&cam->s_tasklet); + break; + + default: + cam_err(cam, "Frame interrupt in non-operational state\n"); + break; + } +} + + + + +static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs) +{ + unsigned int frame; + + cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */ + /* + * Handle any frame completions. There really should + * not be more than one of these, or we have fallen + * far behind. + */ + for (frame = 0; frame < cam->nbufs; frame++) + if (irqs & (IRQ_EOF0 << frame)) + cafe_frame_complete(cam, frame); + /* + * If a frame starts, note that we have DMA active. This + * code assumes that we won't get multiple frame interrupts + * at once; may want to rethink that. + */ + if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) + set_bit(CF_DMA_ACTIVE, &cam->flags); +} + + + +static irqreturn_t cafe_irq(int irq, void *data) +{ + struct cafe_camera *cam = data; + unsigned int irqs; + + spin_lock(&cam->dev_lock); + irqs = cafe_reg_read(cam, REG_IRQSTAT); + if ((irqs & ALLIRQS) == 0) { + spin_unlock(&cam->dev_lock); + return IRQ_NONE; + } + if (irqs & FRAMEIRQS) + cafe_frame_irq(cam, irqs); + if (irqs & TWSIIRQS) { + cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS); + wake_up(&cam->smbus_wait); + } + spin_unlock(&cam->dev_lock); + return IRQ_HANDLED; +} + + +/* -------------------------------------------------------------------------- */ +#ifdef CONFIG_VIDEO_ADV_DEBUG +/* + * Debugfs stuff. + */ + +static char cafe_debug_buf[1024]; +static struct dentry *cafe_dfs_root; + +static void cafe_dfs_setup(void) +{ + cafe_dfs_root = debugfs_create_dir("cafe_ccic", NULL); + if (IS_ERR(cafe_dfs_root)) { + cafe_dfs_root = NULL; /* Never mind */ + printk(KERN_NOTICE "cafe_ccic unable to set up debugfs\n"); + } +} + +static void cafe_dfs_shutdown(void) +{ + if (cafe_dfs_root) + debugfs_remove(cafe_dfs_root); +} + +static int cafe_dfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t cafe_dfs_read_regs(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct cafe_camera *cam = file->private_data; + char *s = cafe_debug_buf; + int offset; + + for (offset = 0; offset < 0x44; offset += 4) + s += sprintf(s, "%02x: %08x\n", offset, + cafe_reg_read(cam, offset)); + for (offset = 0x88; offset <= 0x90; offset += 4) + s += sprintf(s, "%02x: %08x\n", offset, + cafe_reg_read(cam, offset)); + for (offset = 0xb4; offset <= 0xbc; offset += 4) + s += sprintf(s, "%02x: %08x\n", offset, + cafe_reg_read(cam, offset)); + for (offset = 0x3000; offset <= 0x300c; offset += 4) + s += sprintf(s, "%04x: %08x\n", offset, + cafe_reg_read(cam, offset)); + return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf, + s - cafe_debug_buf); +} + +static struct file_operations cafe_dfs_reg_ops = { + .owner = THIS_MODULE, + .read = cafe_dfs_read_regs, + .open = cafe_dfs_open +}; + +static ssize_t cafe_dfs_read_cam(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct cafe_camera *cam = file->private_data; + char *s = cafe_debug_buf; + int offset; + + if (! cam->sensor) + return -EINVAL; + for (offset = 0x0; offset < 0x8a; offset++) + { + u8 v; + + cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v); + s += sprintf(s, "%02x: %02x\n", offset, v); + } + return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf, + s - cafe_debug_buf); +} + +static struct file_operations cafe_dfs_cam_ops = { + .owner = THIS_MODULE, + .read = cafe_dfs_read_cam, + .open = cafe_dfs_open +}; + + + +static void cafe_dfs_cam_setup(struct cafe_camera *cam) +{ + char fname[40]; + + if (!cafe_dfs_root) + return; + sprintf(fname, "regs-%d", cam->v4ldev.minor); + cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root, + cam, &cafe_dfs_reg_ops); + sprintf(fname, "cam-%d", cam->v4ldev.minor); + cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root, + cam, &cafe_dfs_cam_ops); +} + + +static void cafe_dfs_cam_shutdown(struct cafe_camera *cam) +{ + if (! IS_ERR(cam->dfs_regs)) + debugfs_remove(cam->dfs_regs); + if (! IS_ERR(cam->dfs_cam_regs)) + debugfs_remove(cam->dfs_cam_regs); +} + +#else + +#define cafe_dfs_setup() +#define cafe_dfs_shutdown() +#define cafe_dfs_cam_setup(cam) +#define cafe_dfs_cam_shutdown(cam) +#endif /* CONFIG_VIDEO_ADV_DEBUG */ + + + + +/* ------------------------------------------------------------------------*/ +/* + * PCI interface stuff. + */ + +static int cafe_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret; + u16 classword; + struct cafe_camera *cam; + /* + * Make sure we have a camera here - we'll get calls for + * the other cafe devices as well. + */ + pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword); + if (classword != PCI_CLASS_MULTIMEDIA_VIDEO) + return -ENODEV; + /* + * Start putting together one of our big camera structures. + */ + ret = -ENOMEM; + cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL); + if (cam == NULL) + goto out; + mutex_init(&cam->s_mutex); + mutex_lock(&cam->s_mutex); + spin_lock_init(&cam->dev_lock); + cam->state = S_NOTREADY; + cafe_set_config_needed(cam, 1); + init_waitqueue_head(&cam->smbus_wait); + init_waitqueue_head(&cam->iowait); + cam->pdev = pdev; + cam->pix_format = cafe_def_pix_format; + INIT_LIST_HEAD(&cam->dev_list); + INIT_LIST_HEAD(&cam->sb_avail); + INIT_LIST_HEAD(&cam->sb_full); + tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam); + /* + * Get set up on the PCI bus. + */ + ret = pci_enable_device(pdev); + if (ret) + goto out_free; + pci_set_master(pdev); + + ret = -EIO; + cam->regs = pci_iomap(pdev, 0, 0); + if (! cam->regs) { + printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n"); + goto out_free; + } + ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam); + if (ret) + goto out_iounmap; + cafe_ctlr_init(cam); + cafe_ctlr_power_up(cam); + /* + * Set up I2C/SMBUS communications + */ + mutex_unlock(&cam->s_mutex); /* attach can deadlock */ + ret = cafe_smbus_setup(cam); + if (ret) + goto out_freeirq; + /* + * Get the v4l2 setup done. + */ + mutex_lock(&cam->s_mutex); + cam->v4ldev = cafe_v4l_template; + cam->v4ldev.debug = 0; +// cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG; + ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1); + if (ret) + goto out_smbus; + /* + * If so requested, try to get our DMA buffers now. + */ + if (alloc_bufs_at_load) { + if (cafe_alloc_dma_bufs(cam, 1)) + cam_warn(cam, "Unable to alloc DMA buffers at load" + " will try again later."); + } + + cafe_dfs_cam_setup(cam); + mutex_unlock(&cam->s_mutex); + cafe_add_dev(cam); + return 0; + + out_smbus: + cafe_smbus_shutdown(cam); + out_freeirq: + cafe_ctlr_power_down(cam); + free_irq(pdev->irq, cam); + out_iounmap: + pci_iounmap(pdev, cam->regs); + out_free: + kfree(cam); + out: + return ret; +} + + +/* + * Shut down an initialized device + */ +static void cafe_shutdown(struct cafe_camera *cam) +{ +/* FIXME: Make sure we take care of everything here */ + cafe_dfs_cam_shutdown(cam); + if (cam->n_sbufs > 0) + /* What if they are still mapped? Shouldn't be, but... */ + cafe_free_sio_buffers(cam); + cafe_remove_dev(cam); + cafe_ctlr_stop_dma(cam); + cafe_ctlr_power_down(cam); + cafe_smbus_shutdown(cam); + cafe_free_dma_bufs(cam); + free_irq(cam->pdev->irq, cam); + pci_iounmap(cam->pdev, cam->regs); + video_unregister_device(&cam->v4ldev); + /* kfree(cam); done in v4l_release () */ +} + + +static void cafe_pci_remove(struct pci_dev *pdev) +{ + struct cafe_camera *cam = cafe_find_by_pdev(pdev); + + if (cam == NULL) { + cam_warn(cam, "pci_remove on unknown pdev %p\n", pdev); + return; + } + mutex_lock(&cam->s_mutex); + if (cam->users > 0) + cam_warn(cam, "Removing a device with users!\n"); + cafe_shutdown(cam); +/* No unlock - it no longer exists */ +} + + + + +static struct pci_device_id cafe_ids[] = { + { PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */ + { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ + { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, cafe_ids); + +static struct pci_driver cafe_pci_driver = { + .name = "cafe1000-ccic", + .id_table = cafe_ids, + .probe = cafe_pci_probe, + .remove = cafe_pci_remove, +}; + + + + +static int __init cafe_init(void) +{ + int ret; + + printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n", + CAFE_VERSION); + cafe_dfs_setup(); + ret = pci_register_driver(&cafe_pci_driver); + if (ret) { + printk(KERN_ERR "Unable to register cafe_ccic driver\n"); + goto out; + } + request_module("ov7670"); /* FIXME want something more general */ + ret = 0; + + out: + return ret; +} + + +static void __exit cafe_exit(void) +{ + pci_unregister_driver(&cafe_pci_driver); + cafe_dfs_shutdown(); +} + +module_init(cafe_init); +module_exit(cafe_exit); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 0a8f750cbede..a32db163cbc0 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -250,6 +250,7 @@ #define I2C_HW_SMBUS_OV518 0x04000f /* OV518(+) USB 1.1 webcam ICs */ #define I2C_HW_SMBUS_OV519 0x040010 /* OV519 USB 1.1 webcam IC */ #define I2C_HW_SMBUS_OVFX2 0x040011 /* Cypress/OmniVision FX2 webcam */ +#define I2C_HW_SMBUS_CAFE 0x040012 /* Marvell 88ALP01 "CAFE" cam */ /* --- ISA pseudo-adapter */ #define I2C_HW_ISA 0x050000 -- cgit v1.2.3 From 111f33564e19b2b5f70e3df9a8f92c08c1c91fd9 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sat, 4 Nov 2006 09:26:00 -0300 Subject: V4L/DVB (4798): OmniVision OV7670 driver This patch adds a V4L2 driver for the OmniVision OV7670 camera. Signed-off-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 8 + drivers/media/video/Makefile | 1 + drivers/media/video/ov7670.c | 1002 ++++++++++++++++++++++++++++++++++++++++++ include/linux/i2c-id.h | 1 + include/media/v4l2-common.h | 3 + 5 files changed, 1015 insertions(+) create mode 100644 drivers/media/video/ov7670.c (limited to 'include/linux') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 4ea1d0ebf5fd..c95735cd688c 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -184,6 +184,14 @@ config VIDEO_KS0127 To compile this driver as a module, choose M here: the module will be called ks0127. +config VIDEO_OV7670 + tristate "OmniVision OV7670 sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV7670 VGA camera. It currently only works with the M88ALP01 + controller. + config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L1 && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 8ff787a4cf6a..2adb56d01ef6 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o +obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.o diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c new file mode 100644 index 000000000000..382aa83b73c5 --- /dev/null +++ b/drivers/media/video/ov7670.c @@ -0,0 +1,1002 @@ +/* + * A V4L2 driver for OmniVision OV7670 cameras. + * + * Copyright 2006 One Laptop Per Child Association, Inc. Written + * by Jonathan Corbet with substantial inspiration from Mark + * McClelland's ovcamchip code. + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +MODULE_AUTHOR("Jonathan Corbet 0) + *value = (unsigned char) ret; + return ret; +} + + +static int ov7670_write(struct i2c_client *c, unsigned char reg, + unsigned char value) +{ + return i2c_smbus_write_byte_data(c, reg, value); +} + + +/* + * Write a list of register settings; ff/ff stops the process. + */ +static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals) +{ + while (vals->reg_num != 0xff || vals->value != 0xff) { + int ret = ov7670_write(c, vals->reg_num, vals->value); + if (ret < 0) + return ret; + vals++; + } + return 0; +} + + +/* + * Stuff that knows about the sensor. + */ +static void ov7670_reset(struct i2c_client *client) +{ + ov7670_write(client, REG_COM7, COM7_RESET); + msleep(1); +} + + +static int ov7670_init(struct i2c_client *client) +{ + return ov7670_write_array(client, ov7670_default_regs); +} + + + +static int ov7670_detect(struct i2c_client *client) +{ + unsigned char v; + int ret; + + ret = ov7670_init(client); + if (ret < 0) + return ret; + ret = ov7670_read(client, REG_MIDH, &v); + if (ret < 0) + return ret; + if (v != 0x7f) /* OV manuf. id. */ + return -ENODEV; + ret = ov7670_read(client, REG_MIDL, &v); + if (ret < 0) + return ret; + if (v != 0xa2) + return -ENODEV; + /* + * OK, we know we have an OmniVision chip...but which one? + */ + ret = ov7670_read(client, REG_PID, &v); + if (ret < 0) + return ret; + if (v != 0x76) /* PID + VER = 0x76 / 0x73 */ + return -ENODEV; + ret = ov7670_read(client, REG_VER, &v); + if (ret < 0) + return ret; + if (v != 0x73) /* PID + VER = 0x76 / 0x73 */ + return -ENODEV; + return 0; +} + + + + + +static struct ov7670_format_struct { + __u8 *desc; + __u32 pixelformat; + struct regval_list *regs; +} ov7670_formats[] = { + { + .desc = "YUYV 4:2:2", + .pixelformat = V4L2_PIX_FMT_YUYV, + .regs = ov7670_fmt_yuv422, + }, + { + .desc = "RGB 444", + .pixelformat = V4L2_PIX_FMT_RGB444, + .regs = ov7670_fmt_rgb444, + }, + { + .desc = "RGB 565", + .pixelformat = V4L2_PIX_FMT_RGB565, + .regs = ov7670_fmt_rgb565, + }, + /* + * Pretend we do RGB32. This is here on the assumption that the + * upper layer will reformat RGB444 appropriately. + * + * The entire purpose for this thing's existence is to enable easy + * display of RGB444 for debugging purposes. It will come out soon. + */ + { + .desc = "RGB32 (faked)", + .pixelformat = V4L2_PIX_FMT_RGB32, + .regs = ov7670_fmt_rgb444, + }, +}; +#define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0])) + +/* + * All formats we support are 2 bytes/pixel. + */ +#define BYTES_PER_PIXEL 2 + +/* + * Then there is the issue of window sizes. Try to capture the info here. + */ +static struct ov7670_win_size { + int width; + int height; + unsigned char com7_bit; + int hstart; /* Start/stop values for the camera. Note */ + int hstop; /* that they do not always make complete */ + int vstart; /* sense to humans, but evidently the sensor */ + int vstop; /* will do the right thing... */ +/* h/vref stuff */ +} ov7670_win_sizes[] = { + /* VGA */ + { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .com7_bit = COM7_FMT_VGA, + .hstart = 158, /* These values from */ + .hstop = 14, /* Omnivision */ + .vstart = 10, + .vstop = 490, + }, + /* CIF */ + { + .width = CIF_WIDTH, + .height = CIF_HEIGHT, + .com7_bit = COM7_FMT_CIF, + .hstart = 170, /* Empirically determined */ + .hstop = 90, + .vstart = 14, + .vstop = 494, + }, + /* QVGA */ + { + .width = QVGA_WIDTH, + .height = QVGA_HEIGHT, + .com7_bit = COM7_FMT_QVGA, + .hstart = 164, /* Empirically determined */ + .hstop = 20, + .vstart = 14, + .vstop = 494, + }, +}; + +#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0])) + + +/* + * Store a set of start/stop values into the camera. + */ +static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop, + int vstart, int vstop) +{ + int ret; + unsigned char v; +/* + * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of + * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is + * a mystery "edge offset" value in the top two bits of href. + */ + ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff); + ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff); + ret += ov7670_read(client, REG_HREF, &v); + v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); + msleep(10); + ret += ov7670_write(client, REG_HREF, v); +/* + * Vertical: similar arrangement, but only 10 bits. + */ + ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff); + ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff); + ret += ov7670_read(client, REG_VREF, &v); + v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3); + msleep(10); + ret += ov7670_write(client, REG_VREF, v); + return ret; +} + + +static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt) +{ + struct ov7670_format_struct *ofmt; + + if (fmt->index >= N_OV7670_FMTS) + return -EINVAL; + + ofmt = ov7670_formats + fmt->index; + fmt->flags = 0; + strcpy(fmt->description, ofmt->desc); + fmt->pixelformat = ofmt->pixelformat; + return 0; +} + + +static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, + struct ov7670_format_struct **ret_fmt, + struct ov7670_win_size **ret_wsize) +{ + int index; + struct ov7670_win_size *wsize; + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + for (index = 0; index < N_OV7670_FMTS; index++) + if (ov7670_formats[index].pixelformat == pix->pixelformat) + break; + if (index >= N_OV7670_FMTS) + return -EINVAL; + if (ret_fmt != NULL) + *ret_fmt = ov7670_formats + index; + /* + * Fields: the OV devices claim to be progressive. + */ + if (pix->field == V4L2_FIELD_ANY) + pix->field = V4L2_FIELD_NONE; + else if (pix->field != V4L2_FIELD_NONE) + return -EINVAL; + /* + * Round requested image size down to the nearest + * we support, but not below the smallest. + */ + for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES; + wsize++) + if (pix->width >= wsize->width && pix->height >= wsize->height) + break; + if (wsize > ov7670_win_sizes + N_WIN_SIZES) + wsize--; /* Take the smallest one */ + if (ret_wsize != NULL) + *ret_wsize = wsize; + /* + * Note the size we'll actually handle. + */ + pix->width = wsize->width; + pix->height = wsize->height; + pix->bytesperline = pix->width*BYTES_PER_PIXEL; + if (pix->pixelformat == V4L2_PIX_FMT_RGB32) + pix->bytesperline *= 2; + pix->sizeimage = pix->height*pix->bytesperline; + return 0; + +} + +/* + * Set a format. + */ +static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) +{ + int ret; + struct ov7670_format_struct *ovfmt; + struct ov7670_win_size *wsize; + unsigned char com7; + + ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize); + if (ret) + return ret; + /* + * COM7 is a pain in the ass, it doesn't like to be read then + * quickly written afterward. But we have everything we need + * to set it absolutely here, as long as the format-specific + * register sets list it first. + */ + com7 = ovfmt->regs[0].value; + com7 |= wsize->com7_bit; + ov7670_write(c, REG_COM7, com7); + /* + * Now write the rest of the array. Also store start/stops + */ + ov7670_write_array(c, ovfmt->regs + 1); + ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart, + wsize->vstop); + return 0; +} + +/* + * Code for dealing with controls. + */ + +/* + * Some weird registers seem to store values in a sign/magnitude format! + */ +static unsigned char ov7670_sm_to_abs(unsigned char v) +{ + if ((v & 0x80) == 0) + return v + 128; + else + return 128 - (v & 0x7f); +} + + +static unsigned char ov7670_abs_to_sm(unsigned char v) +{ + if (v > 127) + return v & 0x7f; + else + return (128 - v) | 0x80; +} + +static int ov7670_t_brightness(struct i2c_client *client, unsigned char value) +{ + unsigned char com8; + int ret; + + ov7670_read(client, REG_COM8, &com8); + com8 &= ~COM8_AEC; + ov7670_write(client, REG_COM8, com8); + value = ov7670_abs_to_sm(value); + ret = ov7670_write(client, REG_BRIGHT, value); + return ret; +} + +static int ov7670_q_brightness(struct i2c_client *client, unsigned char *value) +{ + int ret; + ret = ov7670_read(client, REG_BRIGHT, value); + *value = ov7670_sm_to_abs(*value); + return ret; +} + +static int ov7670_t_contrast(struct i2c_client *client, unsigned char value) +{ + return ov7670_write(client, REG_CONTRAS, value); +} + +static int ov7670_q_contrast(struct i2c_client *client, unsigned char *value) +{ + return ov7670_read(client, REG_CONTRAS, value); +} + +static int ov7670_q_hflip(struct i2c_client *client, unsigned char *value) +{ + int ret; + unsigned char v; + + ret = ov7670_read(client, REG_MVFP, &v); + *value = (v & MVFP_MIRROR) == MVFP_MIRROR; + return ret; +} + + +static int ov7670_t_hflip(struct i2c_client *client, unsigned char value) +{ + unsigned char v; + int ret; + + ret = ov7670_read(client, REG_MVFP, &v); + if (value) + v |= MVFP_MIRROR; + else + v &= ~MVFP_MIRROR; + msleep(10); /* FIXME */ + ret += ov7670_write(client, REG_MVFP, v); + return ret; +} + + + +static int ov7670_q_vflip(struct i2c_client *client, unsigned char *value) +{ + int ret; + unsigned char v; + + ret = ov7670_read(client, REG_MVFP, &v); + *value = (v & MVFP_FLIP) == MVFP_FLIP; + return ret; +} + + +static int ov7670_t_vflip(struct i2c_client *client, unsigned char value) +{ + unsigned char v; + int ret; + + ret = ov7670_read(client, REG_MVFP, &v); + if (value) + v |= MVFP_FLIP; + else + v &= ~MVFP_FLIP; + msleep(10); /* FIXME */ + ret += ov7670_write(client, REG_MVFP, v); + return ret; +} + + +static struct ov7670_control { + struct v4l2_queryctrl qc; + int (*query)(struct i2c_client *c, unsigned char *value); + int (*tweak)(struct i2c_client *c, unsigned char value); +} ov7670_controls[] = +{ + { + .qc = { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0x80, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .tweak = ov7670_t_brightness, + .query = ov7670_q_brightness, + }, + { + .qc = { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0x40, /* XXX ov7670 spec */ + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .tweak = ov7670_t_contrast, + .query = ov7670_q_contrast, + }, + { + .qc = { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .tweak = ov7670_t_vflip, + .query = ov7670_q_vflip, + }, + { + .qc = { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Horizontal mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .tweak = ov7670_t_hflip, + .query = ov7670_q_hflip, + }, +}; +#define N_CONTROLS (sizeof(ov7670_controls)/sizeof(ov7670_controls[0])) + +static struct ov7670_control *ov7670_find_control(__u32 id) +{ + int i; + + for (i = 0; i < N_CONTROLS; i++) + if (ov7670_controls[i].qc.id == id) + return ov7670_controls + i; + return NULL; +} + + +static int ov7670_queryctrl(struct i2c_client *client, + struct v4l2_queryctrl *qc) +{ + struct ov7670_control *ctrl = ov7670_find_control(qc->id); + + if (ctrl == NULL) + return -EINVAL; + *qc = ctrl->qc; + return 0; +} + +static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +{ + struct ov7670_control *octrl = ov7670_find_control(ctrl->id); + int ret; + unsigned char v; + + if (octrl == NULL) + return -EINVAL; + ret = octrl->query(client, &v); + if (ret >= 0) { + ctrl->value = v; + return 0; + } + return ret; +} + +static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +{ + struct ov7670_control *octrl = ov7670_find_control(ctrl->id); + + if (octrl == NULL) + return -EINVAL; + return octrl->tweak(client, ctrl->value); +} + + + + + + + +/* + * Basic i2c stuff. + */ +static struct i2c_driver ov7670_driver; + +static int ov7670_attach(struct i2c_adapter *adapter) +{ + int ret; + struct i2c_client *client; + + printk(KERN_ERR "ov7670 attach, id = %d\n", adapter->id); + /* + * For now: only deal with adapters we recognize. + */ + if (adapter->id != I2C_HW_SMBUS_CAFE) + return -ENODEV; + + printk(KERN_ERR "ov7670 accepting\n"); + client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL); + if (! client) + return -ENOMEM; + client->adapter = adapter; + client->addr = OV7670_I2C_ADDR; + client->driver = &ov7670_driver, + strcpy(client->name, "OV7670"); + /* Do we need clientdata? */ + + /* + * Make sure it's an ov7670 + */ + ret = ov7670_detect(client); + printk(KERN_ERR "detect result is %d\n", ret); + if (ret) + goto out_free; + i2c_attach_client(client); + return 0; + + out_free: + kfree(client); + return ret; +} + + +static int ov7670_detach(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(client); + return 0; +} + + +static int ov7670_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + switch (cmd) { + case VIDIOC_INT_G_CHIP_IDENT: + * (enum v4l2_chip_ident *) arg = V4L2_IDENT_OV7670; + return 0; + + case VIDIOC_INT_RESET: + ov7670_reset(client); + return 0; + + case VIDIOC_INT_INIT: + return ov7670_init(client); + + case VIDIOC_ENUM_FMT: + return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg); + case VIDIOC_TRY_FMT: + return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL); + case VIDIOC_S_FMT: + return ov7670_s_fmt(client, (struct v4l2_format *) arg); + case VIDIOC_QUERYCTRL: + return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg); + case VIDIOC_S_CTRL: + return ov7670_s_ctrl(client, (struct v4l2_control *) arg); + case VIDIOC_G_CTRL: + return ov7670_g_ctrl(client, (struct v4l2_control *) arg); + /* Todo: + g/s_parm + initialization + */ + } + return -EINVAL; +} + + + +static struct i2c_driver ov7670_driver = { + .driver = { + .name = "ov7670", + }, + .id = I2C_DRIVERID_OV7670, + .class = I2C_CLASS_CAM_DIGITAL, + .attach_adapter = ov7670_attach, + .detach_client = ov7670_detach, + .command = ov7670_command, +}; + + +/* + * Module initialization + */ +static int __init ov7670_mod_init(void) +{ + printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n"); + return i2c_add_driver(&ov7670_driver); +} + +static void __exit ov7670_mod_exit(void) +{ + i2c_del_driver(&ov7670_driver); +} + +module_init(ov7670_mod_init); +module_exit(ov7670_mod_exit); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index a32db163cbc0..0f4cf34b6fa2 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -159,6 +159,7 @@ #define I2C_DRIVERID_ASB100 1043 #define I2C_DRIVERID_FSCHER 1046 #define I2C_DRIVERID_W83L785TS 1047 +#define I2C_DRIVERID_OV7670 1048 /* Omnivision 7670 camera */ /* * ---- Adapter types ---------------------------------------------------- diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 8263ea00ca6f..91b19921f958 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -144,6 +144,9 @@ enum v4l2_chip_ident { V4L2_IDENT_CX25841 = 241, V4L2_IDENT_CX25842 = 242, V4L2_IDENT_CX25843 = 243, + + /* OmniVision sensors - range 250-299 */ + V4L2_IDENT_OV7670 = 250, }; /* audio ioctls */ -- cgit v1.2.3 From 5c543eff6cc658f46241f1ccb77436d65abbf445 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 10 Dec 2006 02:18:58 -0800 Subject: [PATCH] freezer.h uses task_struct fields freezer.h uses task_struct fields so it should include sched.h. CC [M] fs/jfs/jfs_txnmgr.o In file included from fs/jfs/jfs_txnmgr.c:49: include/linux/freezer.h: In function 'frozen': include/linux/freezer.h:9: error: dereferencing pointer to incomplete type include/linux/freezer.h:9: error: 'PF_FROZEN' undeclared (first use in this function) include/linux/freezer.h:9: error: (Each undeclared identifier is reported only once include/linux/freezer.h:9: error: for each function it appears in.) include/linux/freezer.h: In function 'freezing': include/linux/freezer.h:17: error: dereferencing pointer to incomplete type include/linux/freezer.h:17: error: 'PF_FREEZE' undeclared (first use in this function) include/linux/freezer.h: In function 'freeze': include/linux/freezer.h:26: error: dereferencing pointer to incomplete type include/linux/freezer.h:26: error: 'PF_FREEZE' undeclared (first use in this function) include/linux/freezer.h: In function 'do_not_freeze': include/linux/freezer.h:34: error: dereferencing pointer to incomplete type include/linux/freezer.h:34: error: 'PF_FREEZE' undeclared (first use in this function) include/linux/freezer.h: In function 'thaw_process': include/linux/freezer.h:43: error: dereferencing pointer to incomplete type include/linux/freezer.h:43: error: 'PF_FROZEN' undeclared (first use in this function) include/linux/freezer.h:44: warning: implicit declaration of function 'wake_up_process' include/linux/freezer.h: In function 'frozen_process': include/linux/freezer.h:55: error: dereferencing pointer to incomplete type include/linux/freezer.h:55: error: dereferencing pointer to incomplete type include/linux/freezer.h:55: error: 'PF_FREEZE' undeclared (first use in this function) include/linux/freezer.h:55: error: 'PF_FROZEN' undeclared (first use in this function) fs/jfs/jfs_txnmgr.c: In function 'freezing': include/linux/freezer.h:18: warning: control reaches end of non-void function make[2]: *** [fs/jfs/jfs_txnmgr.o] Error 1 Signed-off-by: Randy Dunlap Acked-by: Dave Kleikamp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/freezer.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 6e05e3e7ce39..393063096134 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -1,5 +1,7 @@ /* Freezer declarations */ +#include + #ifdef CONFIG_PM /* * Check if a process has been frozen -- cgit v1.2.3 From 884b4aaaa242a2db8c8252796f0118164a680ab5 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Sun, 10 Dec 2006 02:19:00 -0800 Subject: [PATCH] rtc: Add rtc_merge_alarm() Add rtc_merge_alarm(), which can be used by rtc drivers to turn a partially specified alarm expiry (i.e. most significant fields set to -1, as with the RTC_ALM_SET ioctl()) into a fully specified expiry. If the most significant specified field is earlier than the current time, the least significant unspecified field is incremented. Signed-off-by: Scott Wood Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-lib.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/rtc.h | 1 + 2 files changed, 82 insertions(+) (limited to 'include/linux') diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index ba795a4db1e9..7bbc26a34bd2 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -117,4 +117,85 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) } EXPORT_SYMBOL(rtc_tm_to_time); + +/* Merge the valid (i.e. non-negative) fields of alarm into the current + * time. If the valid alarm fields are earlier than the equivalent + * fields in the time, carry one into the least significant invalid + * field, so that the alarm expiry is in the future. It assumes that the + * least significant invalid field is more significant than the most + * significant valid field, and that the seconds field is valid. + * + * This is used by alarms that take relative (rather than absolute) + * times, and/or have a simple binary second counter instead of + * day/hour/minute/sec registers. + */ +void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm) +{ + int *alarmp = &alarm->tm_sec; + int *timep = &now->tm_sec; + int carry_into, i; + + /* Ignore everything past the 6th element (tm_year). */ + for (i = 5; i > 0; i--) { + if (alarmp[i] < 0) + alarmp[i] = timep[i]; + else + break; + } + + /* No carry needed if all fields are valid. */ + if (i == 5) + return; + + for (carry_into = i + 1; i >= 0; i--) { + if (alarmp[i] < timep[i]) + break; + + if (alarmp[i] > timep[i]) + return; + } + + switch (carry_into) { + case 1: + alarm->tm_min++; + + if (alarm->tm_min < 60) + return; + + alarm->tm_min = 0; + /* fall-through */ + + case 2: + alarm->tm_hour++; + + if (alarm->tm_hour < 60) + return; + + alarm->tm_hour = 0; + /* fall-through */ + + case 3: + alarm->tm_mday++; + + if (alarm->tm_mday <= rtc_days_in_month[alarm->tm_mon]) + return; + + alarm->tm_mday = 1; + /* fall-through */ + + case 4: + alarm->tm_mon++; + + if (alarm->tm_mon <= 12) + return; + + alarm->tm_mon = 1; + /* fall-through */ + + case 5: + alarm->tm_year++; + } +} +EXPORT_SYMBOL(rtc_merge_alarm); + MODULE_LICENSE("GPL"); diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 09ff4c3e2713..5e22d4510d11 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -106,6 +106,7 @@ extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year extern int rtc_valid_tm(struct rtc_time *tm); extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time); extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm); +extern void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm); #include #include -- cgit v1.2.3 From 1f29bcd739972f71f2fd5d5d265daf3e1208fa5e Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 10 Dec 2006 02:19:10 -0800 Subject: [PATCH] sysctl: remove unused "context" param Signed-off-by: Alexey Dobriyan Cc: Andi Kleen Cc: "David S. Miller" Cc: David Howells Cc: Ralf Baechle Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/kernel/pm.c | 6 +++--- arch/mips/lasat/sysctl.c | 17 +++++++-------- arch/x86_64/kernel/vsyscall.c | 3 +-- drivers/char/random.c | 2 +- include/linux/sysctl.h | 5 ++--- include/net/ip.h | 3 +-- include/net/sctp/sctp.h | 2 +- kernel/sysctl.c | 47 ++++++++++++++++++++---------------------- net/decnet/dn_dev.c | 6 ++---- net/decnet/sysctl_net_decnet.c | 6 ++---- net/ipv4/devinet.c | 3 +-- net/ipv4/route.c | 3 +-- net/ipv4/sysctl_net_ipv4.c | 16 ++++++-------- net/ipv6/addrconf.c | 3 +-- net/ipv6/ndisc.c | 9 +++----- 15 files changed, 55 insertions(+), 76 deletions(-) (limited to 'include/linux') diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c index c1d9fc8f1a85..ee677ced7b68 100644 --- a/arch/frv/kernel/pm.c +++ b/arch/frv/kernel/pm.c @@ -223,7 +223,7 @@ static int cmode_procctl(ctl_table *ctl, int write, struct file *filp, static int cmode_sysctl(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { if (oldval && oldlenp) { size_t oldlen; @@ -326,7 +326,7 @@ static int p0_procctl(ctl_table *ctl, int write, struct file *filp, static int p0_sysctl(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { if (oldval && oldlenp) { size_t oldlen; @@ -370,7 +370,7 @@ static int cm_procctl(ctl_table *ctl, int write, struct file *filp, static int cm_sysctl(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { if (oldval && oldlenp) { size_t oldlen; diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c index da35d4555491..12878359f2c8 100644 --- a/arch/mips/lasat/sysctl.c +++ b/arch/mips/lasat/sysctl.c @@ -40,12 +40,12 @@ static DEFINE_MUTEX(lasat_info_mutex); /* Strategy function to write EEPROM after changing string entry */ int sysctl_lasatstring(ctl_table *table, int *name, int nlen, void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) + void *newval, size_t newlen) { int r; mutex_lock(&lasat_info_mutex); r = sysctl_string(table, name, - nlen, oldval, oldlenp, newval, newlen, context); + nlen, oldval, oldlenp, newval, newlen); if (r < 0) { mutex_unlock(&lasat_info_mutex); return r; @@ -119,11 +119,11 @@ int proc_dolasatrtc(ctl_table *table, int write, struct file *filp, /* Sysctl for setting the IP addresses */ int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen, void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) + void *newval, size_t newlen) { int r; mutex_lock(&lasat_info_mutex); - r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context); + r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); if (r < 0) { mutex_unlock(&lasat_info_mutex); return r; @@ -139,14 +139,14 @@ int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen, /* Same for RTC */ int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen, void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) + void *newval, size_t newlen) { int r; mutex_lock(&lasat_info_mutex); rtctmp = ds1603_read(); if (rtctmp < 0) rtctmp = 0; - r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context); + r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); if (r < 0) { mutex_unlock(&lasat_info_mutex); return r; @@ -251,13 +251,12 @@ int proc_lasat_ip(ctl_table *table, int write, struct file *filp, static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen, void *oldval, size_t *oldlenp, - void *newval, size_t newlen, - void **context) + void *newval, size_t newlen) { int r; mutex_lock(&lasat_info_mutex); - r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context); + r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); if (r < 0) { mutex_unlock(&lasat_info_mutex); return r; diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index 4a673f5397a0..2433d6fc68b1 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -225,8 +225,7 @@ out: static int vsyscall_sysctl_nostrat(ctl_table *t, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context) + void __user *newval, size_t newlen) { return -ENOSYS; } diff --git a/drivers/char/random.c b/drivers/char/random.c index 092a01cc02da..13d0b1350a62 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1203,7 +1203,7 @@ static int proc_do_uuid(ctl_table *table, int write, struct file *filp, static int uuid_strategy(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { unsigned char tmp_uuid[16], *uuid; unsigned int len; diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 94316a98e0d0..6d8846e7be6d 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -918,8 +918,7 @@ typedef struct ctl_table ctl_table; typedef int ctl_handler (ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context); + void __user *newval, size_t newlen); typedef int proc_handler (ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos); @@ -950,7 +949,7 @@ extern int do_sysctl (int __user *name, int nlen, extern int do_sysctl_strategy (ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void ** context); + void __user *newval, size_t newlen); extern ctl_handler sysctl_string; extern ctl_handler sysctl_intvec; diff --git a/include/net/ip.h b/include/net/ip.h index 83cb9ac5554e..053f02b5cb89 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -376,8 +376,7 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write, size_t *lenp, loff_t *ppos); int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context); + void __user *newval, size_t newlen); #ifdef CONFIG_PROC_FS extern int ip_misc_proc_init(void); #endif diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 215461f18db1..c818f87122af 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -368,7 +368,7 @@ static inline void sctp_sysctl_register(void) { return; } static inline void sctp_sysctl_unregister(void) { return; } static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) { + void __user *newval, size_t newlen) { return -ENOSYS; } #endif diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c86445a62af2..130c5ec9ee0b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -133,7 +133,7 @@ extern int max_lock_depth; #ifdef CONFIG_SYSCTL_SYSCALL static int parse_table(int __user *, int, void __user *, size_t __user *, - void __user *, size_t, ctl_table *, void **); + void __user *, size_t, ctl_table *); #endif static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, @@ -141,12 +141,12 @@ static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context); + void __user *newval, size_t newlen); #ifdef CONFIG_SYSVIPC static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context); + void __user *newval, size_t newlen); #endif #ifdef CONFIG_PROC_SYSCTL @@ -1243,7 +1243,6 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol do { struct ctl_table_header *head = list_entry(tmp, struct ctl_table_header, ctl_entry); - void *context = NULL; if (!use_table(head)) continue; @@ -1251,9 +1250,7 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol spin_unlock(&sysctl_lock); error = parse_table(name, nlen, oldval, oldlenp, - newval, newlen, head->ctl_table, - &context); - kfree(context); + newval, newlen, head->ctl_table); spin_lock(&sysctl_lock); unuse_table(head); @@ -1309,7 +1306,7 @@ static inline int ctl_perm(ctl_table *table, int op) static int parse_table(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, - ctl_table *table, void **context) + ctl_table *table) { int n; repeat: @@ -1329,7 +1326,7 @@ repeat: error = table->strategy( table, name, nlen, oldval, oldlenp, - newval, newlen, context); + newval, newlen); if (error) return error; } @@ -1340,7 +1337,7 @@ repeat: } error = do_sysctl_strategy(table, name, nlen, oldval, oldlenp, - newval, newlen, context); + newval, newlen); return error; } } @@ -1351,7 +1348,7 @@ repeat: int do_sysctl_strategy (ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { int op = 0, rc; size_t len; @@ -1365,7 +1362,7 @@ int do_sysctl_strategy (ctl_table *table, if (table->strategy) { rc = table->strategy(table, name, nlen, oldval, oldlenp, - newval, newlen, context); + newval, newlen); if (rc < 0) return rc; if (rc > 0) @@ -2473,7 +2470,7 @@ int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, /* The generic string strategy routine: */ int sysctl_string(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { if (!table->data || !table->maxlen) return -ENOTDIR; @@ -2519,7 +2516,7 @@ int sysctl_string(ctl_table *table, int __user *name, int nlen, */ int sysctl_intvec(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { if (newval && newlen) { @@ -2555,7 +2552,7 @@ int sysctl_intvec(ctl_table *table, int __user *name, int nlen, /* Strategy function to convert jiffies to seconds */ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { if (oldval) { size_t olen; @@ -2583,7 +2580,7 @@ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, /* Strategy function to convert jiffies to seconds */ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { if (oldval) { size_t olen; @@ -2612,7 +2609,7 @@ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, /* The generic string strategy routine: */ static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { struct ctl_table uts_table; int r, write; @@ -2620,7 +2617,7 @@ static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, memcpy(&uts_table, table, sizeof(uts_table)); uts_table.data = get_uts(table, write); r = sysctl_string(&uts_table, name, nlen, - oldval, oldlenp, newval, newlen, context); + oldval, oldlenp, newval, newlen); put_uts(table, write, uts_table.data); return r; } @@ -2629,7 +2626,7 @@ static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, /* The generic sysctl ipc data routine. */ static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { size_t len; void *data; @@ -2704,41 +2701,41 @@ out: int sysctl_string(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { return -ENOSYS; } int sysctl_intvec(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { return -ENOSYS; } int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { return -ENOSYS; } int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { return -ENOSYS; } static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { return -ENOSYS; } static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, void **context) + void __user *newval, size_t newlen) { return -ENOSYS; } diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 0b9d4c955154..fc6f3c023a54 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -167,8 +167,7 @@ static int dn_forwarding_proc(ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context); + void __user *newval, size_t newlen); static struct dn_dev_sysctl_table { struct ctl_table_header *sysctl_header; @@ -347,8 +346,7 @@ static int dn_forwarding_proc(ctl_table *table, int write, static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context) + void __user *newval, size_t newlen) { #ifdef CONFIG_DECNET_ROUTER struct net_device *dev = table->extra1; diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index e246f054f368..a4065eb1341e 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c @@ -134,8 +134,7 @@ static int parse_addr(__le16 *addr, char *str) static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context) + void __user *newval, size_t newlen) { size_t len; __le16 addr; @@ -220,8 +219,7 @@ static int dn_node_address_handler(ctl_table *table, int write, static int dn_def_dev_strategy(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context) + void __user *newval, size_t newlen) { size_t len; struct net_device *dev; diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 2fd899160f85..84bed40273ad 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1303,8 +1303,7 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write, int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context) + void __user *newval, size_t newlen) { int *valp = table->data; int new; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 11c167118e87..1aaff0a2e098 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2872,8 +2872,7 @@ static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, void __user *oldval, size_t __user *oldlenp, void __user *newval, - size_t newlen, - void **context) + size_t newlen) { int delay; if (newlen != sizeof(int)) diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index dfcf47f10f88..fabf69a9108c 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -51,8 +51,7 @@ int ipv4_sysctl_forward(ctl_table *ctl, int write, struct file * filp, static int ipv4_sysctl_forward_strategy(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context) + void __user *newval, size_t newlen) { int *valp = table->data; int new; @@ -111,8 +110,7 @@ static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context) + void __user *newval, size_t newlen) { char val[TCP_CA_NAME_MAX]; ctl_table tbl = { @@ -122,8 +120,7 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name, int ret; tcp_get_default_congestion_control(val); - ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen, - context); + ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen); if (ret == 0 && newval && newlen) ret = tcp_set_default_congestion_control(val); return ret; @@ -169,8 +166,8 @@ static int proc_allowed_congestion_control(ctl_table *ctl, static int strategy_allowed_congestion_control(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context) + void __user *newval, + size_t newlen) { ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX }; int ret; @@ -180,8 +177,7 @@ static int strategy_allowed_congestion_control(ctl_table *table, int __user *nam return -ENOMEM; tcp_get_available_congestion_control(tbl.data, tbl.maxlen); - ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen, - context); + ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen); if (ret == 0 && newval && newlen) ret = tcp_set_allowed_congestion_control(tbl.data); kfree(tbl.data); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a5e8d207a51b..9b0a90643151 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3656,8 +3656,7 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context) + void __user *newval, size_t newlen) { int *valp = table->data; int new; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 56ea92837307..6a9f616de37d 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1667,8 +1667,7 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * f static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, - void **context) + void __user *newval, size_t newlen) { struct net_device *dev = ctl->extra1; struct inet6_dev *idev; @@ -1681,14 +1680,12 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name, switch (ctl->ctl_name) { case NET_NEIGH_REACHABLE_TIME: ret = sysctl_jiffies(ctl, name, nlen, - oldval, oldlenp, newval, newlen, - context); + oldval, oldlenp, newval, newlen); break; case NET_NEIGH_RETRANS_TIME_MS: case NET_NEIGH_REACHABLE_TIME_MS: ret = sysctl_ms_jiffies(ctl, name, nlen, - oldval, oldlenp, newval, newlen, - context); + oldval, oldlenp, newval, newlen); break; default: ret = 0; -- cgit v1.2.3 From 58f64d83c37f5073a01573d27043c9c0ccc764f1 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 10 Dec 2006 02:19:11 -0800 Subject: [PATCH] Fix noise in futex.h There are some kernel-only bits in the middle of which should be removed in what we export to userspace. Signed-off-by: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/Kbuild | 2 +- include/linux/futex.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index e618b25b5add..a1b04d8a1d01 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -61,7 +61,6 @@ header-y += fd.h header-y += fdreg.h header-y += fib_rules.h header-y += fuse.h -header-y += futex.h header-y += genetlink.h header-y += gen_stats.h header-y += gigaset_dev.h @@ -203,6 +202,7 @@ unifdef-y += fb.h unifdef-y += fcntl.h unifdef-y += filter.h unifdef-y += flat.h +unifdef-y += futex.h unifdef-y += fs.h unifdef-y += gameport.h unifdef-y += generic_serial.h diff --git a/include/linux/futex.h b/include/linux/futex.h index d097b5b72bc6..3f153b4e156c 100644 --- a/include/linux/futex.h +++ b/include/linux/futex.h @@ -93,6 +93,7 @@ struct robust_list_head { */ #define ROBUST_LIST_LIMIT 2048 +#ifdef __KERNEL__ long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout, u32 __user *uaddr2, u32 val2, u32 val3); @@ -110,6 +111,7 @@ static inline void exit_pi_state_list(struct task_struct *curr) { } #endif +#endif /* __KERNEL__ */ #define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */ #define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */ -- cgit v1.2.3 From 7c3ab7381e79dfc7db14a67c6f4f3285664e1ec2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 10 Dec 2006 02:19:19 -0800 Subject: [PATCH] io-accounting: core statistics The present per-task IO accounting isn't very useful. It simply counts the number of bytes passed into read() and write(). So if a process reads 1MB from an already-cached file, it is accused of having performed 1MB of I/O, which is wrong. (David Wright had some comments on the applicability of the present logical IO accounting: For billing purposes it is useless but for workload analysis it is very useful read_bytes/read_calls average read request size write_bytes/write_calls average write request size read_bytes/read_blocks ie logical/physical can indicate hit rate or thrashing write_bytes/write_blocks ie logical/physical guess since pdflush writes can be missed I often look for logical larger than physical to see filesystem cache problems. And the bytes/cpusec can help find applications that are dominating the cache and causing slow interactive response from page cache contention. I want to find the IO intensive applications and make sure they are doing efficient IO. Thus the acctcms(sysV) or csacms command would give the high IO commands). This patchset adds new accounting which tries to be more accurate. We account for three things: reads: attempt to count the number of bytes which this process really did cause to be fetched from the storage layer. Done at the submit_bio() level, so it is accurate for block-backed filesystems. I also attempt to wire up NFS and CIFS. writes: attempt to count the number of bytes which this process caused to be sent to the storage layer. This is done at page-dirtying time. The big inaccuracy here is truncate. If a process writes 1MB to a file and then deletes the file, it will in fact perform no writeout. But it will have been accounted as having caused 1MB of write. So... cancelled_writes: account the number of bytes which this process caused to not happen, by truncating pagecache. We _could_ just subtract this from the process's `write' accounting. But that means that some processes would be reported to have done negative amounts of write IO, which is silly. So we just report the raw number and punt this decision up to userspace. Now, we _could_ account for writes at the physical I/O level. But - This would require that we track memory-dirtying tasks at the per-page level (would require a new pointer in struct page). - It would mean that IO statistics for a process are usually only available long after that process has exitted. Which means that we probably cannot communicate this info via taskstats. This patch: Wire up the kernel-private data structures and the accessor functions to manipulate them. Cc: Jay Lan Cc: Shailabh Nagar Cc: Balbir Singh Cc: Chris Sturtivant Cc: Tony Ernst Cc: Guillaume Thouvenin Cc: David Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 2 ++ include/linux/task_io_accounting.h | 37 ++++++++++++++++++++++++++ include/linux/task_io_accounting_ops.h | 47 ++++++++++++++++++++++++++++++++++ init/Kconfig | 9 +++++++ kernel/fork.c | 2 ++ 5 files changed, 97 insertions(+) create mode 100644 include/linux/task_io_accounting.h create mode 100644 include/linux/task_io_accounting_ops.h (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index ad9c46071ff8..1208feab46e0 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -82,6 +82,7 @@ struct sched_param { #include #include #include +#include #include @@ -1013,6 +1014,7 @@ struct task_struct { wait_queue_t *io_wait; /* i/o counters(bytes read/written, #syscalls */ u64 rchar, wchar, syscr, syscw; + struct task_io_accounting ioac; #if defined(CONFIG_TASK_XACCT) u64 acct_rss_mem1; /* accumulated rss usage */ u64 acct_vm_mem1; /* accumulated virtual memory usage */ diff --git a/include/linux/task_io_accounting.h b/include/linux/task_io_accounting.h new file mode 100644 index 000000000000..44d00e9cceea --- /dev/null +++ b/include/linux/task_io_accounting.h @@ -0,0 +1,37 @@ +/* + * task_io_accounting: a structure which is used for recording a single task's + * IO statistics. + * + * Don't include this header file directly - it is designed to be dragged in via + * sched.h. + * + * Blame akpm@osdl.org for all this. + */ + +#ifdef CONFIG_TASK_IO_ACCOUNTING +struct task_io_accounting { + /* + * The number of bytes which this task has caused to be read from + * storage. + */ + u64 read_bytes; + + /* + * The number of bytes which this task has caused, or shall cause to be + * written to disk. + */ + u64 write_bytes; + + /* + * A task can cause "negative" IO too. If this task truncates some + * dirty pagecache, some IO which another task has been accounted for + * (in its write_bytes) will not be happening. We _could_ just + * subtract that from the truncating task's write_bytes, but there is + * information loss in doing that. + */ + u64 cancelled_write_bytes; +}; +#else +struct task_io_accounting { +}; +#endif diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h new file mode 100644 index 000000000000..df2a319106b2 --- /dev/null +++ b/include/linux/task_io_accounting_ops.h @@ -0,0 +1,47 @@ +/* + * Task I/O accounting operations + */ +#ifndef __TASK_IO_ACCOUNTING_OPS_INCLUDED +#define __TASK_IO_ACCOUNTING_OPS_INCLUDED + +#ifdef CONFIG_TASK_IO_ACCOUNTING +static inline void task_io_account_read(size_t bytes) +{ + current->ioac.read_bytes += bytes; +} + +static inline void task_io_account_write(size_t bytes) +{ + current->ioac.write_bytes += bytes; +} + +static inline void task_io_account_cancelled_write(size_t bytes) +{ + current->ioac.cancelled_write_bytes += bytes; +} + +static inline void task_io_accounting_init(struct task_struct *tsk) +{ + memset(&tsk->ioac, 0, sizeof(tsk->ioac)); +} + +#else + +static inline void task_io_account_read(size_t bytes) +{ +} + +static inline void task_io_account_write(size_t bytes) +{ +} + +static inline void task_io_account_cancelled_write(size_t bytes) +{ +} + +static inline void task_io_accounting_init(struct task_struct *tsk) +{ +} + +#endif /* CONFIG_TASK_IO_ACCOUNTING */ +#endif /* __TASK_IO_ACCOUNTING_OPS_INCLUDED */ diff --git a/init/Kconfig b/init/Kconfig index 14d484606fab..9edf103b3ec3 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -304,6 +304,15 @@ config TASK_XACCT Say N if unsure. +config TASK_IO_ACCOUNTING + bool "Enable per-task storage I/O accounting (EXPERIMENTAL)" + depends on TASK_XACCT + help + Collect information on the number of bytes of storage I/O which this + task has caused. + + Say N if unsure. + config SYSCTL bool diff --git a/kernel/fork.c b/kernel/fork.c index 8c859eef8e6a..086e172d0d3d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1055,6 +1056,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->wchar = 0; /* I/O counter: bytes written */ p->syscr = 0; /* I/O counter: read syscalls */ p->syscw = 0; /* I/O counter: write syscalls */ + task_io_accounting_init(p); acct_clear_integrals(p); p->it_virt_expires = cputime_zero; -- cgit v1.2.3 From f2f1f8a3b86ccc5e998dc70a3ba35af199fdbc58 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 10 Dec 2006 02:19:50 -0800 Subject: [PATCH] cleanup taskstats.h Fix weird whitespace mangling in taskstats.h Cc: Jay Lan Cc: Shailabh Nagar Cc: Balbir Singh Cc: Chris Sturtivant Cc: Tony Ernst Cc: Guillaume Thouvenin Cc: David Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/taskstats.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h index 45248806ae9c..15c64037be1b 100644 --- a/include/linux/taskstats.h +++ b/include/linux/taskstats.h @@ -115,31 +115,31 @@ struct taskstats { __u64 ac_majflt; /* Major Page Fault Count */ /* Basic Accounting Fields end */ - /* Extended accounting fields start */ + /* Extended accounting fields start */ /* Accumulated RSS usage in duration of a task, in MBytes-usecs. * The current rss usage is added to this counter every time * a tick is charged to a task's system time. So, at the end we * will have memory usage multiplied by system time. Thus an * average usage per system time unit can be calculated. */ - __u64 coremem; /* accumulated RSS usage in MB-usec */ + __u64 coremem; /* accumulated RSS usage in MB-usec */ /* Accumulated virtual memory usage in duration of a task. * Same as acct_rss_mem1 above except that we keep track of VM usage. */ - __u64 virtmem; /* accumulated VM usage in MB-usec */ + __u64 virtmem; /* accumulated VM usage in MB-usec */ /* High watermark of RSS and virtual memory usage in duration of * a task, in KBytes. */ - __u64 hiwater_rss; /* High-watermark of RSS usage, in KB */ - __u64 hiwater_vm; /* High-water VM usage, in KB */ + __u64 hiwater_rss; /* High-watermark of RSS usage, in KB */ + __u64 hiwater_vm; /* High-water VM usage, in KB */ /* The following four fields are I/O statistics of a task. */ - __u64 read_char; /* bytes read */ - __u64 write_char; /* bytes written */ - __u64 read_syscalls; /* read syscalls */ - __u64 write_syscalls; /* write syscalls */ - /* Extended accounting fields end */ + __u64 read_char; /* bytes read */ + __u64 write_char; /* bytes written */ + __u64 read_syscalls; /* read syscalls */ + __u64 write_syscalls; /* write syscalls */ + /* Extended accounting fields end */ }; -- cgit v1.2.3 From 4a7864ca638e0a38307962ee8ef122822a351b65 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 10 Dec 2006 02:19:53 -0800 Subject: [PATCH] io-accounting: via taskstats Deliver IO accounting via taskstats. Cc: Jay Lan Cc: Shailabh Nagar Cc: Balbir Singh Cc: Chris Sturtivant Cc: Tony Ernst Cc: Guillaume Thouvenin Cc: David Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/taskstats.h | 8 +++++++- kernel/tsacct.c | 9 +++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h index 15c64037be1b..3fced4798255 100644 --- a/include/linux/taskstats.h +++ b/include/linux/taskstats.h @@ -31,7 +31,7 @@ */ -#define TASKSTATS_VERSION 2 +#define TASKSTATS_VERSION 3 #define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN * in linux/sched.h */ @@ -140,6 +140,12 @@ struct taskstats { __u64 read_syscalls; /* read syscalls */ __u64 write_syscalls; /* write syscalls */ /* Extended accounting fields end */ + +#define TASKSTATS_HAS_IO_ACCOUNTING + /* Per-task storage I/O accounting starts */ + __u64 read_bytes; /* bytes of read I/O */ + __u64 write_bytes; /* bytes of write I/O */ + __u64 cancelled_write_bytes; /* bytes of cancelled write I/O */ }; diff --git a/kernel/tsacct.c b/kernel/tsacct.c index 96f77013d3f0..baacc3691415 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c @@ -96,6 +96,15 @@ void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) stats->write_char = p->wchar; stats->read_syscalls = p->syscr; stats->write_syscalls = p->syscw; +#ifdef CONFIG_TASK_IO_ACCOUNTING + stats->read_bytes = p->ioac.read_bytes; + stats->write_bytes = p->ioac.write_bytes; + stats->cancelled_write_bytes = p->ioac.cancelled_write_bytes; +#else + stats->read_bytes = 0; + stats->write_bytes = 0; + stats->cancelled_write_bytes = 0; +#endif } #undef KB #undef MB -- cgit v1.2.3 From ac7d550499e225efb51a53d0b00667f26b93bdff Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" Date: Sun, 10 Dec 2006 02:20:12 -0800 Subject: [PATCH] sched domain: increase the SMT busy rebalance interval With SMT, if the logical processor is busy, load balance happens for every 8msec(min)-16msec(max). There is no need to do this often, as this is just for fairness(to maintain uniform runqueue lengths) and default time slice anyhow is 100msec. Appended patch increases this interval to 64msec(min)-128msec(max) when the logical processor is busy. Signed-off-by: Suresh Siddha Cc: Nick Piggin Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/topology.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/topology.h b/include/linux/topology.h index da508d1998e4..b93bb6cc6cc2 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -93,7 +93,7 @@ .groups = NULL, \ .min_interval = 1, \ .max_interval = 2, \ - .busy_factor = 8, \ + .busy_factor = 64, \ .imbalance_pct = 110, \ .cache_nice_tries = 0, \ .per_cpu_gain = 25, \ -- cgit v1.2.3 From c9819f4593e8d052b41a89f47140f5c5e7e30582 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 10 Dec 2006 02:20:25 -0800 Subject: [PATCH] sched: use softirq for load balancing Call rebalance_tick (renamed to run_rebalance_domains) from a newly introduced softirq. We calculate the earliest time for each layer of sched domains to be rescanned (this is the rescan time for idle) and use the earliest of those to schedule the softirq via a new field "next_balance" added to struct rq. Signed-off-by: Christoph Lameter Cc: Peter Williams Cc: Nick Piggin Cc: Christoph Lameter Cc: "Siddha, Suresh B" Cc: "Chen, Kenneth W" Acked-by: Ingo Molnar Cc: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/interrupt.h | 3 ++- kernel/sched.c | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index de7593f4e895..e36e86c869fb 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -231,7 +231,8 @@ enum NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, BLOCK_SOFTIRQ, - TASKLET_SOFTIRQ + TASKLET_SOFTIRQ, + SCHED_SOFTIRQ, }; /* softirq mask and active fields moved to irq_cpustat_t in diff --git a/kernel/sched.c b/kernel/sched.c index 14a8d9050cd4..0a3e748d737d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -227,6 +227,7 @@ struct rq { unsigned long expired_timestamp; unsigned long long timestamp_last_tick; struct task_struct *curr, *idle; + unsigned long next_balance; struct mm_struct *prev_mm; struct prio_array *active, *expired, arrays[2]; int best_expired_prio; @@ -2858,7 +2859,7 @@ static void update_load(struct rq *this_rq) } /* - * rebalance_tick will get called every timer tick, on every CPU. + * run_rebalance_domains is triggered when needed from the scheduler tick. * * It checks each scheduling domain to see if it is due to be balanced, * and initiates a balancing operation if so. @@ -2866,9 +2867,10 @@ static void update_load(struct rq *this_rq) * Balancing parameters are set up in arch_init_sched_domains. */ -static void -rebalance_tick(int this_cpu, struct rq *this_rq) +static void run_rebalance_domains(struct softirq_action *h) { + int this_cpu = smp_processor_id(); + struct rq *this_rq = cpu_rq(this_cpu); unsigned long interval; struct sched_domain *sd; /* @@ -2877,6 +2879,8 @@ rebalance_tick(int this_cpu, struct rq *this_rq) */ enum idle_type idle = !this_rq->nr_running ? SCHED_IDLE : NOT_IDLE; + /* Earliest time when we have to call run_rebalance_domains again */ + unsigned long next_balance = jiffies + 60*HZ; for_each_domain(this_cpu, sd) { if (!(sd->flags & SD_LOAD_BALANCE)) @@ -2891,7 +2895,7 @@ rebalance_tick(int this_cpu, struct rq *this_rq) if (unlikely(!interval)) interval = 1; - if (jiffies - sd->last_balance >= interval) { + if (time_after_eq(jiffies, sd->last_balance + interval)) { if (load_balance(this_cpu, this_rq, sd, idle)) { /* * We've pulled tasks over so either we're no @@ -2902,7 +2906,10 @@ rebalance_tick(int this_cpu, struct rq *this_rq) } sd->last_balance += interval; } + if (time_after(next_balance, sd->last_balance + interval)) + next_balance = sd->last_balance + interval; } + this_rq->next_balance = next_balance; } #else /* @@ -3155,7 +3162,8 @@ void scheduler_tick(void) task_running_tick(rq, p); #ifdef CONFIG_SMP update_load(rq); - rebalance_tick(cpu, rq); + if (time_after_eq(jiffies, rq->next_balance)) + raise_softirq(SCHED_SOFTIRQ); #endif } @@ -6859,6 +6867,10 @@ void __init sched_init(void) set_load_weight(&init_task); +#ifdef CONFIG_SMP + open_softirq(SCHED_SOFTIRQ, run_rebalance_domains, NULL); +#endif + #ifdef CONFIG_RT_MUTEXES plist_head_init(&init_task.pi_waiters, &init_task.pi_lock); #endif -- cgit v1.2.3 From 08c183f31bdbb709f177f6d3110d5f288ea33933 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 10 Dec 2006 02:20:29 -0800 Subject: [PATCH] sched: add option to serialize load balancing Large sched domains can be very expensive to scan. Add an option SD_SERIALIZE to the sched domain flags. If that flag is set then we make sure that no other such domain is being balanced. [akpm@osdl.org: build fix] Signed-off-by: Christoph Lameter Cc: Peter Williams Cc: Nick Piggin Cc: Christoph Lameter Cc: "Siddha, Suresh B" Cc: "Chen, Kenneth W" Acked-by: Ingo Molnar Cc: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-i386/topology.h | 1 + include/asm-ia64/topology.h | 1 + include/asm-powerpc/topology.h | 1 + include/asm-x86_64/topology.h | 1 + include/linux/sched.h | 1 + include/linux/topology.h | 3 ++- kernel/sched.c | 9 +++++++++ 7 files changed, 16 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h index 978d09596130..ac58580ad664 100644 --- a/include/asm-i386/topology.h +++ b/include/asm-i386/topology.h @@ -89,6 +89,7 @@ static inline int node_to_first_cpu(int node) .flags = SD_LOAD_BALANCE \ | SD_BALANCE_EXEC \ | SD_BALANCE_FORK \ + | SD_SERIALIZE \ | SD_WAKE_BALANCE, \ .last_balance = jiffies, \ .balance_interval = 1, \ diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h index a6e38565ab4c..22ed6749557e 100644 --- a/include/asm-ia64/topology.h +++ b/include/asm-ia64/topology.h @@ -101,6 +101,7 @@ void build_cpu_to_node_map(void); .flags = SD_LOAD_BALANCE \ | SD_BALANCE_EXEC \ | SD_BALANCE_FORK \ + | SD_SERIALIZE \ | SD_WAKE_BALANCE, \ .last_balance = jiffies, \ .balance_interval = 64, \ diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h index 50c014007de7..6610495f5f16 100644 --- a/include/asm-powerpc/topology.h +++ b/include/asm-powerpc/topology.h @@ -66,6 +66,7 @@ static inline int pcibus_to_node(struct pci_bus *bus) | SD_BALANCE_EXEC \ | SD_BALANCE_NEWIDLE \ | SD_WAKE_IDLE \ + | SD_SERIALIZE \ | SD_WAKE_BALANCE, \ .last_balance = jiffies, \ .balance_interval = 1, \ diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h index 5c8f49280dbc..2facec5914d2 100644 --- a/include/asm-x86_64/topology.h +++ b/include/asm-x86_64/topology.h @@ -47,6 +47,7 @@ extern int __node_distance(int, int); .flags = SD_LOAD_BALANCE \ | SD_BALANCE_FORK \ | SD_BALANCE_EXEC \ + | SD_SERIALIZE \ | SD_WAKE_BALANCE, \ .last_balance = jiffies, \ .balance_interval = 1, \ diff --git a/include/linux/sched.h b/include/linux/sched.h index 1208feab46e0..ea92e5c89089 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -648,6 +648,7 @@ enum idle_type #define SD_SHARE_CPUPOWER 128 /* Domain members share cpu power */ #define SD_POWERSAVINGS_BALANCE 256 /* Balance for power savings */ #define SD_SHARE_PKG_RESOURCES 512 /* Domain members share cpu pkg resources */ +#define SD_SERIALIZE 1024 /* Only a single load balancing instance */ #define BALANCE_FOR_MC_POWER \ (sched_smt_power_savings ? SD_POWERSAVINGS_BALANCE : 0) diff --git a/include/linux/topology.h b/include/linux/topology.h index b93bb6cc6cc2..6c5a6e6e813b 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -194,7 +194,8 @@ .wake_idx = 0, /* unused */ \ .forkexec_idx = 0, /* unused */ \ .per_cpu_gain = 100, \ - .flags = SD_LOAD_BALANCE, \ + .flags = SD_LOAD_BALANCE \ + | SD_SERIALIZE, \ .last_balance = jiffies, \ .balance_interval = 64, \ .nr_balance_failed = 0, \ diff --git a/kernel/sched.c b/kernel/sched.c index 0a4a26b21f69..2b2b780939c9 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2880,6 +2880,7 @@ static void update_load(struct rq *this_rq) * * Balancing parameters are set up in arch_init_sched_domains. */ +static DEFINE_SPINLOCK(balancing); static void run_rebalance_domains(struct softirq_action *h) { @@ -2909,6 +2910,11 @@ static void run_rebalance_domains(struct softirq_action *h) if (unlikely(!interval)) interval = 1; + if (sd->flags & SD_SERIALIZE) { + if (!spin_trylock(&balancing)) + goto out; + } + if (time_after_eq(jiffies, sd->last_balance + interval)) { if (load_balance(this_cpu, this_rq, sd, idle)) { /* @@ -2920,6 +2926,9 @@ static void run_rebalance_domains(struct softirq_action *h) } sd->last_balance = jiffies; } + if (sd->flags & SD_SERIALIZE) + spin_unlock(&balancing); +out: if (time_after(next_balance, sd->last_balance + interval)) next_balance = sd->last_balance + interval; } -- cgit v1.2.3 From 783609c6cb4eaa23f2ac5c968a44483584ec133f Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" Date: Sun, 10 Dec 2006 02:20:33 -0800 Subject: [PATCH] sched: decrease number of load balances Currently at a particular domain, each cpu in the sched group will do a load balance at the frequency of balance_interval. More the cores and threads, more the cpus will be in each sched group at SMP and NUMA domain. And we endup spending quite a bit of time doing load balancing in those domains. Fix this by making only one cpu(first idle cpu or first cpu in the group if all the cpus are busy) in the sched group do the load balance at that particular sched domain and this load will slowly percolate down to the other cpus with in that group(when they do load balancing at lower domains). Signed-off-by: Suresh Siddha Cc: Christoph Lameter Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 + kernel/sched.c | 59 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index ea92e5c89089..72d6927d29ed 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -707,6 +707,7 @@ struct sched_domain { unsigned long lb_hot_gained[MAX_IDLE_TYPES]; unsigned long lb_nobusyg[MAX_IDLE_TYPES]; unsigned long lb_nobusyq[MAX_IDLE_TYPES]; + unsigned long lb_stopbalance[MAX_IDLE_TYPES]; /* Active load balancing */ unsigned long alb_cnt; diff --git a/kernel/sched.c b/kernel/sched.c index 15ce772a471a..4e453431c61a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -428,7 +428,7 @@ static inline void task_rq_unlock(struct rq *rq, unsigned long *flags) * bump this up when changing the output format or the meaning of an existing * format, so that tools can adapt (or abort) */ -#define SCHEDSTAT_VERSION 12 +#define SCHEDSTAT_VERSION 13 static int show_schedstat(struct seq_file *seq, void *v) { @@ -466,7 +466,7 @@ static int show_schedstat(struct seq_file *seq, void *v) seq_printf(seq, "domain%d %s", dcnt++, mask_str); for (itype = SCHED_IDLE; itype < MAX_IDLE_TYPES; itype++) { - seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu", + seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu", sd->lb_cnt[itype], sd->lb_balanced[itype], sd->lb_failed[itype], @@ -474,7 +474,8 @@ static int show_schedstat(struct seq_file *seq, void *v) sd->lb_gained[itype], sd->lb_hot_gained[itype], sd->lb_nobusyq[itype], - sd->lb_nobusyg[itype]); + sd->lb_nobusyg[itype], + sd->lb_stopbalance[itype]); } seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", sd->alb_cnt, sd->alb_failed, sd->alb_pushed, @@ -2249,7 +2250,7 @@ out: static struct sched_group * find_busiest_group(struct sched_domain *sd, int this_cpu, unsigned long *imbalance, enum idle_type idle, int *sd_idle, - cpumask_t *cpus) + cpumask_t *cpus, int *balance) { struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups; unsigned long max_load, avg_load, total_load, this_load, total_pwr; @@ -2278,10 +2279,14 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, unsigned long load, group_capacity; int local_group; int i; + unsigned int balance_cpu = -1, first_idle_cpu = 0; unsigned long sum_nr_running, sum_weighted_load; local_group = cpu_isset(this_cpu, group->cpumask); + if (local_group) + balance_cpu = first_cpu(group->cpumask); + /* Tally up the load of all CPUs in the group */ sum_weighted_load = sum_nr_running = avg_load = 0; @@ -2297,9 +2302,14 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, *sd_idle = 0; /* Bias balancing toward cpus of our domain */ - if (local_group) + if (local_group) { + if (idle_cpu(i) && !first_idle_cpu) { + first_idle_cpu = 1; + balance_cpu = i; + } + load = target_load(i, load_idx); - else + } else load = source_load(i, load_idx); avg_load += load; @@ -2307,6 +2317,16 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, sum_weighted_load += rq->raw_weighted_load; } + /* + * First idle cpu or the first cpu(busiest) in this sched group + * is eligible for doing load balancing at this and above + * domains. + */ + if (local_group && balance_cpu != this_cpu && balance) { + *balance = 0; + goto ret; + } + total_load += avg_load; total_pwr += group->cpu_power; @@ -2498,8 +2518,8 @@ out_balanced: *imbalance = min_load_per_task; return group_min; } -ret: #endif +ret: *imbalance = 0; return NULL; } @@ -2550,7 +2570,8 @@ static inline unsigned long minus_1_or_zero(unsigned long n) * tasks if there is an imbalance. */ static int load_balance(int this_cpu, struct rq *this_rq, - struct sched_domain *sd, enum idle_type idle) + struct sched_domain *sd, enum idle_type idle, + int *balance) { int nr_moved, all_pinned = 0, active_balance = 0, sd_idle = 0; struct sched_group *group; @@ -2573,7 +2594,13 @@ static int load_balance(int this_cpu, struct rq *this_rq, redo: group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle, - &cpus); + &cpus, balance); + + if (*balance == 0) { + schedstat_inc(sd, lb_stopbalance[idle]); + goto out_balanced; + } + if (!group) { schedstat_inc(sd, lb_nobusyg[idle]); goto out_balanced; @@ -2715,7 +2742,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd) schedstat_inc(sd, lb_cnt[NEWLY_IDLE]); redo: group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE, - &sd_idle, &cpus); + &sd_idle, &cpus, NULL); if (!group) { schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]); goto out_balanced; @@ -2885,7 +2912,7 @@ static DEFINE_SPINLOCK(balancing); static void run_rebalance_domains(struct softirq_action *h) { - int this_cpu = smp_processor_id(); + int this_cpu = smp_processor_id(), balance = 1; struct rq *this_rq = cpu_rq(this_cpu); unsigned long interval; struct sched_domain *sd; @@ -2917,7 +2944,7 @@ static void run_rebalance_domains(struct softirq_action *h) } if (time_after_eq(jiffies, sd->last_balance + interval)) { - if (load_balance(this_cpu, this_rq, sd, idle)) { + if (load_balance(this_cpu, this_rq, sd, idle, &balance)) { /* * We've pulled tasks over so either we're no * longer idle, or one of our SMT siblings is @@ -2932,6 +2959,14 @@ static void run_rebalance_domains(struct softirq_action *h) out: if (time_after(next_balance, sd->last_balance + interval)) next_balance = sd->last_balance + interval; + + /* + * Stop the load balance at this level. There is another + * CPU in our sched group which is doing load balancing more + * actively. + */ + if (!balance) + break; } this_rq->next_balance = next_balance; } -- cgit v1.2.3 From 06066714f6016cffcb249f6ab21b7919de1bc859 Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" Date: Sun, 10 Dec 2006 02:20:35 -0800 Subject: [PATCH] sched: remove lb_stopbalance counter Remove scheduler stats lb_stopbalance counter. This counter can be calculated by: lb_balanced - lb_nobusyg - lb_nobusyq. There is no need to create gazillion counters while we can derive the value. Signed-off-by: Ken Chen Signed-off-by: Suresh Siddha Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 - kernel/sched.c | 11 ++++------- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 72d6927d29ed..ea92e5c89089 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -707,7 +707,6 @@ struct sched_domain { unsigned long lb_hot_gained[MAX_IDLE_TYPES]; unsigned long lb_nobusyg[MAX_IDLE_TYPES]; unsigned long lb_nobusyq[MAX_IDLE_TYPES]; - unsigned long lb_stopbalance[MAX_IDLE_TYPES]; /* Active load balancing */ unsigned long alb_cnt; diff --git a/kernel/sched.c b/kernel/sched.c index 4e453431c61a..66e44b5b53d2 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -428,7 +428,7 @@ static inline void task_rq_unlock(struct rq *rq, unsigned long *flags) * bump this up when changing the output format or the meaning of an existing * format, so that tools can adapt (or abort) */ -#define SCHEDSTAT_VERSION 13 +#define SCHEDSTAT_VERSION 14 static int show_schedstat(struct seq_file *seq, void *v) { @@ -466,7 +466,7 @@ static int show_schedstat(struct seq_file *seq, void *v) seq_printf(seq, "domain%d %s", dcnt++, mask_str); for (itype = SCHED_IDLE; itype < MAX_IDLE_TYPES; itype++) { - seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu", + seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu", sd->lb_cnt[itype], sd->lb_balanced[itype], sd->lb_failed[itype], @@ -474,8 +474,7 @@ static int show_schedstat(struct seq_file *seq, void *v) sd->lb_gained[itype], sd->lb_hot_gained[itype], sd->lb_nobusyq[itype], - sd->lb_nobusyg[itype], - sd->lb_stopbalance[itype]); + sd->lb_nobusyg[itype]); } seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", sd->alb_cnt, sd->alb_failed, sd->alb_pushed, @@ -2596,10 +2595,8 @@ redo: group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle, &cpus, balance); - if (*balance == 0) { - schedstat_inc(sd, lb_stopbalance[idle]); + if (*balance == 0) goto out_balanced; - } if (!group) { schedstat_inc(sd, lb_nobusyg[idle]); -- cgit v1.2.3 From ee2f344b33b507af23610c8fdfdde38d7c10fb33 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 10 Dec 2006 02:20:39 -0800 Subject: [PATCH] ide-cd: Handle strange interrupt on the Intel ESB2 The ESB2 appears to emit spurious DMA interrupts when configured for native mode and handling ATAPI devices. Stratus were able to pin this bug down and produce a patch. This is a rework which applies the fixup only to the ESB2 (for now). We can apply it to other chips later if the same problem is found. This code has been tested and confirmed to fix the problem on the tested systems. Signed-off-by: Alan Cox (Most of the hard work done by Stratus however) Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/ide-cd.c | 7 +++++++ drivers/ide/pci/piix.c | 4 ++++ include/linux/ide.h | 1 + 3 files changed, 12 insertions(+) (limited to 'include/linux') diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 88214943d00a..5969cec58dc1 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -687,8 +687,15 @@ static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 sta static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) { struct request *rq = HWGROUP(drive)->rq; + ide_hwif_t *hwif = HWIF(drive); int stat, err, sense_key; + /* We may have bogus DMA interrupts in PIO state here */ + if (HWIF(drive)->dma_status && hwif->atapi_irq_bogon) { + stat = hwif->INB(hwif->dma_status); + /* Should we force the bit as well ? */ + hwif->OUTB(stat, hwif->dma_status); + } /* Check for errors. */ stat = HWIF(drive)->INB(IDE_STATUS_REG); if (stat_ret) diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index cdc3aab9ebcb..b1e9a8eba6b6 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -505,6 +505,10 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) /* This is a painful system best to let it self tune for now */ return; } + /* ESB2 appears to generate spurious DMA interrupts in PIO mode + when in native mode */ + if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_ESB2_18) + hwif->atapi_irq_bogon = 1; hwif->autodma = 0; hwif->tuneproc = &piix_tune_drive; diff --git a/include/linux/ide.h b/include/linux/ide.h index 9c2050293f17..64e070f62a87 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -796,6 +796,7 @@ typedef struct hwif_s { unsigned sg_mapped : 1; /* sg_table and sg_nents are ready */ unsigned no_io_32bit : 1; /* 1 = can not do 32-bit IO ops */ unsigned err_stops_fifo : 1; /* 1=data FIFO is cleared by an error */ + unsigned atapi_irq_bogon : 1; /* Generates spurious DMA interrupts in PIO mode */ struct device gendev; struct completion gendev_rel_comp; /* To deal with device release() */ -- cgit v1.2.3 From 46031f9a38a9773021f1872abc713d62467ac22e Mon Sep 17 00:00:00 2001 From: "Raz Ben-Jehuda(caro)" Date: Sun, 10 Dec 2006 02:20:47 -0800 Subject: [PATCH] md: allow reads that have bypassed the cache to be retried on failure If a bypass-the-cache read fails, we simply try again through the cache. If it fails again it will trigger normal recovery precedures. update 1: From: NeilBrown 1/ chunk_aligned_read and retry_aligned_read assume that data_disks == raid_disks - 1 which is not true for raid6. So when an aligned read request bypasses the cache, we can get the wrong data. 2/ The cloned bio is being used-after-free in raid5_align_endio (to test BIO_UPTODATE). 3/ We forgot to add rdev->data_offset when submitting a bio for aligned-read 4/ clone_bio calls blk_recount_segments and then we change bi_bdev, so we need to invalidate the segment counts. 5/ We don't de-reference the rdev when the read completes. This means we need to record the rdev to so it is still available in the end_io routine. Fortunately bi_next in the original bio is unused at this point so we can stuff it in there. 6/ We leak a cloned bio if the target rdev is not usable. From: NeilBrown update 2: 1/ When aligned requests fail (read error) they need to be retried via the normal method (stripe cache). As we cannot be sure that we can process a single read in one go (we may not be able to allocate all the stripes needed) we store a bio-being-retried and a list of bioes-that-still-need-to-be-retried. When find a bio that needs to be retried, we should add it to the list, not to single-bio... 2/ We were never incrementing 'scnt' when resubmitting failed aligned requests. [akpm@osdl.org: build fix] Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/raid5.c | 165 +++++++++++++++++++++++++++++++++++++++++++-- include/linux/raid/raid5.h | 3 + 2 files changed, 163 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 269b7771a30b..2ac2e56a1a40 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -134,6 +134,8 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) if (!test_bit(STRIPE_EXPANDING, &sh->state)) { list_add_tail(&sh->lru, &conf->inactive_list); wake_up(&conf->wait_for_stripe); + if (conf->retry_read_aligned) + md_wakeup_thread(conf->mddev->thread); } } } @@ -2644,19 +2646,81 @@ static int in_chunk_boundary(mddev_t *mddev, struct bio *bio) ((sector & (chunk_sectors - 1)) + bio_sectors); } +/* + * add bio to the retry LIFO ( in O(1) ... we are in interrupt ) + * later sampled by raid5d. + */ +static void add_bio_to_retry(struct bio *bi,raid5_conf_t *conf) +{ + unsigned long flags; + + spin_lock_irqsave(&conf->device_lock, flags); + + bi->bi_next = conf->retry_read_aligned_list; + conf->retry_read_aligned_list = bi; + + spin_unlock_irqrestore(&conf->device_lock, flags); + md_wakeup_thread(conf->mddev->thread); +} + + +static struct bio *remove_bio_from_retry(raid5_conf_t *conf) +{ + struct bio *bi; + + bi = conf->retry_read_aligned; + if (bi) { + conf->retry_read_aligned = NULL; + return bi; + } + bi = conf->retry_read_aligned_list; + if(bi) { + conf->retry_read_aligned = bi->bi_next; + bi->bi_next = NULL; + bi->bi_phys_segments = 1; /* biased count of active stripes */ + bi->bi_hw_segments = 0; /* count of processed stripes */ + } + + return bi; +} + + /* * The "raid5_align_endio" should check if the read succeeded and if it * did, call bio_endio on the original bio (having bio_put the new bio * first). * If the read failed.. */ -int raid5_align_endio(struct bio *bi, unsigned int bytes , int error) +static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error) { struct bio* raid_bi = bi->bi_private; + mddev_t *mddev; + raid5_conf_t *conf; + int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); + mdk_rdev_t *rdev; + if (bi->bi_size) return 1; bio_put(bi); - bio_endio(raid_bi, bytes, error); + + mddev = raid_bi->bi_bdev->bd_disk->queue->queuedata; + conf = mddev_to_conf(mddev); + rdev = (void*)raid_bi->bi_next; + raid_bi->bi_next = NULL; + + rdev_dec_pending(rdev, conf->mddev); + + if (!error && uptodate) { + bio_endio(raid_bi, bytes, 0); + if (atomic_dec_and_test(&conf->active_aligned_reads)) + wake_up(&conf->wait_for_stripe); + return 0; + } + + + PRINTK("raid5_align_endio : io error...handing IO for a retry\n"); + + add_bio_to_retry(raid_bi, conf); return 0; } @@ -2665,7 +2729,7 @@ static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio) mddev_t *mddev = q->queuedata; raid5_conf_t *conf = mddev_to_conf(mddev); const unsigned int raid_disks = conf->raid_disks; - const unsigned int data_disks = raid_disks - 1; + const unsigned int data_disks = raid_disks - conf->max_degraded; unsigned int dd_idx, pd_idx; struct bio* align_bi; mdk_rdev_t *rdev; @@ -2699,13 +2763,25 @@ static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio) rcu_read_lock(); rdev = rcu_dereference(conf->disks[dd_idx].rdev); if (rdev && test_bit(In_sync, &rdev->flags)) { - align_bi->bi_bdev = rdev->bdev; atomic_inc(&rdev->nr_pending); rcu_read_unlock(); + raid_bio->bi_next = (void*)rdev; + align_bi->bi_bdev = rdev->bdev; + align_bi->bi_flags &= ~(1 << BIO_SEG_VALID); + align_bi->bi_sector += rdev->data_offset; + + spin_lock_irq(&conf->device_lock); + wait_event_lock_irq(conf->wait_for_stripe, + conf->quiesce == 0, + conf->device_lock, /* nothing */); + atomic_inc(&conf->active_aligned_reads); + spin_unlock_irq(&conf->device_lock); + generic_make_request(align_bi); return 1; } else { rcu_read_unlock(); + bio_put(align_bi); return 0; } } @@ -3050,6 +3126,72 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski return STRIPE_SECTORS; } +static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio) +{ + /* We may not be able to submit a whole bio at once as there + * may not be enough stripe_heads available. + * We cannot pre-allocate enough stripe_heads as we may need + * more than exist in the cache (if we allow ever large chunks). + * So we do one stripe head at a time and record in + * ->bi_hw_segments how many have been done. + * + * We *know* that this entire raid_bio is in one chunk, so + * it will be only one 'dd_idx' and only need one call to raid5_compute_sector. + */ + struct stripe_head *sh; + int dd_idx, pd_idx; + sector_t sector, logical_sector, last_sector; + int scnt = 0; + int remaining; + int handled = 0; + + logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1); + sector = raid5_compute_sector( logical_sector, + conf->raid_disks, + conf->raid_disks - conf->max_degraded, + &dd_idx, + &pd_idx, + conf); + last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9); + + for (; logical_sector < last_sector; + logical_sector += STRIPE_SECTORS, scnt++) { + + if (scnt < raid_bio->bi_hw_segments) + /* already done this stripe */ + continue; + + sh = get_active_stripe(conf, sector, conf->raid_disks, pd_idx, 1); + + if (!sh) { + /* failed to get a stripe - must wait */ + raid_bio->bi_hw_segments = scnt; + conf->retry_read_aligned = raid_bio; + return handled; + } + + set_bit(R5_ReadError, &sh->dev[dd_idx].flags); + add_stripe_bio(sh, raid_bio, dd_idx, 0); + handle_stripe(sh, NULL); + release_stripe(sh); + handled++; + } + spin_lock_irq(&conf->device_lock); + remaining = --raid_bio->bi_phys_segments; + spin_unlock_irq(&conf->device_lock); + if (remaining == 0) { + int bytes = raid_bio->bi_size; + + raid_bio->bi_size = 0; + raid_bio->bi_end_io(raid_bio, bytes, 0); + } + if (atomic_dec_and_test(&conf->active_aligned_reads)) + wake_up(&conf->wait_for_stripe); + return handled; +} + + + /* * This is our raid5 kernel thread. * @@ -3071,6 +3213,7 @@ static void raid5d (mddev_t *mddev) spin_lock_irq(&conf->device_lock); while (1) { struct list_head *first; + struct bio *bio; if (conf->seq_flush != conf->seq_write) { int seq = conf->seq_flush; @@ -3087,6 +3230,16 @@ static void raid5d (mddev_t *mddev) !list_empty(&conf->delayed_list)) raid5_activate_delayed(conf); + while ((bio = remove_bio_from_retry(conf))) { + int ok; + spin_unlock_irq(&conf->device_lock); + ok = retry_aligned_read(conf, bio); + spin_lock_irq(&conf->device_lock); + if (!ok) + break; + handled++; + } + if (list_empty(&conf->handle_list)) break; @@ -3274,6 +3427,7 @@ static int run(mddev_t *mddev) INIT_LIST_HEAD(&conf->inactive_list); atomic_set(&conf->active_stripes, 0); atomic_set(&conf->preread_active_stripes, 0); + atomic_set(&conf->active_aligned_reads, 0); PRINTK("raid5: run(%s) called.\n", mdname(mddev)); @@ -3796,7 +3950,8 @@ static void raid5_quiesce(mddev_t *mddev, int state) spin_lock_irq(&conf->device_lock); conf->quiesce = 1; wait_event_lock_irq(conf->wait_for_stripe, - atomic_read(&conf->active_stripes) == 0, + atomic_read(&conf->active_stripes) == 0 && + atomic_read(&conf->active_aligned_reads) == 0, conf->device_lock, /* nothing */); spin_unlock_irq(&conf->device_lock); break; diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h index 03636d7918fe..d8286db60b96 100644 --- a/include/linux/raid/raid5.h +++ b/include/linux/raid/raid5.h @@ -227,7 +227,10 @@ struct raid5_private_data { struct list_head handle_list; /* stripes needing handling */ struct list_head delayed_list; /* stripes that have plugged requests */ struct list_head bitmap_list; /* stripes delaying awaiting bitmap update */ + struct bio *retry_read_aligned; /* currently retrying aligned bios */ + struct bio *retry_read_aligned_list; /* aligned bios retry list */ atomic_t preread_active_stripes; /* stripes with scheduled io */ + atomic_t active_aligned_reads; atomic_t reshape_stripes; /* stripes with pending writes for reshape */ /* unfortunately we need two cache names as we temporarily have -- cgit v1.2.3 From bbea9f69668a3d0cf9feba15a724cd02896f8675 Mon Sep 17 00:00:00 2001 From: Vadim Lobanov Date: Sun, 10 Dec 2006 02:21:12 -0800 Subject: [PATCH] fdtable: Make fdarray and fdsets equal in size Currently, each fdtable supports three dynamically-sized arrays of data: the fdarray and two fdsets. The code allows the number of fds supported by the fdarray (fdtable->max_fds) to differ from the number of fds supported by each of the fdsets (fdtable->max_fdset). In practice, it is wasteful for these two sizes to differ: whenever we hit a limit on the smaller-capacity structure, we will reallocate the entire fdtable and all the dynamic arrays within it, so any delta in the memory used by the larger-capacity structure will never be touched at all. Rather than hogging this excess, we shouldn't even allocate it in the first place, and keep the capacities of the fdarray and the fdsets equal. This patch removes fdtable->max_fdset. As an added bonus, most of the supporting code becomes simpler. Signed-off-by: Vadim Lobanov Cc: Christoph Hellwig Cc: Al Viro Cc: Dipankar Sarma Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/osf_sys.c | 6 ++--- arch/mips/kernel/kspd.c | 2 +- fs/compat.c | 10 ++++---- fs/exec.c | 2 +- fs/fcntl.c | 5 ++-- fs/file.c | 56 ++++++++++++++++++--------------------------- fs/open.c | 3 +-- fs/select.c | 10 ++++---- include/linux/file.h | 6 ----- include/linux/init_task.h | 1 - kernel/exit.c | 2 +- kernel/fork.c | 24 +++++-------------- security/selinux/hooks.c | 2 +- 13 files changed, 48 insertions(+), 81 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index fb804043b320..be133f1f75a4 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -979,7 +979,7 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, long timeout; int ret = -EINVAL; struct fdtable *fdt; - int max_fdset; + int max_fds; timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { @@ -1003,9 +1003,9 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, rcu_read_lock(); fdt = files_fdtable(current->files); - max_fdset = fdt->max_fdset; + max_fds = fdt->max_fds; rcu_read_unlock(); - if (n < 0 || n > max_fdset) + if (n < 0 || n > max_fds) goto out_nofds; /* diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c index 2c82412b9efe..5929f883e46b 100644 --- a/arch/mips/kernel/kspd.c +++ b/arch/mips/kernel/kspd.c @@ -301,7 +301,7 @@ static void sp_cleanup(void) for (;;) { unsigned long set; i = j * __NFDBITS; - if (i >= fdt->max_fdset || i >= fdt->max_fds) + if (i >= fdt->max_fds) break; set = fdt->open_fds->fds_bits[j++]; while (set) { diff --git a/fs/compat.c b/fs/compat.c index b766964a625c..0ec70e3cee0a 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1679,19 +1679,19 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp, { fd_set_bits fds; char *bits; - int size, max_fdset, ret = -EINVAL; + int size, max_fds, ret = -EINVAL; struct fdtable *fdt; if (n < 0) goto out_nofds; - /* max_fdset can increase, so grab it once to avoid race */ + /* max_fds can increase, so grab it once to avoid race */ rcu_read_lock(); fdt = files_fdtable(current->files); - max_fdset = fdt->max_fdset; + max_fds = fdt->max_fds; rcu_read_unlock(); - if (n > max_fdset) - n = max_fdset; + if (n > max_fds) + n = max_fds; /* * We need 6 bitmaps (in/out/ex for both incoming and outgoing), diff --git a/fs/exec.c b/fs/exec.c index 12d8cd461b41..11fe93f7363c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -783,7 +783,7 @@ static void flush_old_files(struct files_struct * files) j++; i = j * __NFDBITS; fdt = files_fdtable(files); - if (i >= fdt->max_fds || i >= fdt->max_fdset) + if (i >= fdt->max_fds) break; set = fdt->close_on_exec->fds_bits[j]; if (!set) diff --git a/fs/fcntl.c b/fs/fcntl.c index 2bdaef35da54..8e382a5d51bd 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -77,10 +77,9 @@ repeat: start = files->next_fd; newfd = start; - if (start < fdt->max_fdset) { + if (start < fdt->max_fds) newfd = find_next_zero_bit(fdt->open_fds->fds_bits, - fdt->max_fdset, start); - } + fdt->max_fds, start); error = -EMFILE; if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) diff --git a/fs/file.c b/fs/file.c index 51aef675470f..fb3d2038dc21 100644 --- a/fs/file.c +++ b/fs/file.c @@ -68,8 +68,8 @@ void free_fd_array(struct file **array, int num) static void __free_fdtable(struct fdtable *fdt) { - free_fdset(fdt->open_fds, fdt->max_fdset); - free_fdset(fdt->close_on_exec, fdt->max_fdset); + free_fdset(fdt->open_fds, fdt->max_fds); + free_fdset(fdt->close_on_exec, fdt->max_fds); free_fd_array(fdt->fd, fdt->max_fds); kfree(fdt); } @@ -98,7 +98,7 @@ static void free_fdtable_rcu(struct rcu_head *rcu) struct fdtable_defer *fddef; BUG_ON(!fdt); - fdset_size = fdt->max_fdset / 8; + fdset_size = fdt->max_fds / 8; fdarray_size = fdt->max_fds * sizeof(struct file *); if (fdt->free_files) { @@ -110,13 +110,11 @@ static void free_fdtable_rcu(struct rcu_head *rcu) kmem_cache_free(files_cachep, fdt->free_files); return; } - if (fdt->max_fdset <= EMBEDDED_FD_SET_SIZE && - fdt->max_fds <= NR_OPEN_DEFAULT) { + if (fdt->max_fds <= NR_OPEN_DEFAULT) /* * The fdtable was embedded */ return; - } if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) { kfree(fdt->open_fds); kfree(fdt->close_on_exec); @@ -136,9 +134,7 @@ static void free_fdtable_rcu(struct rcu_head *rcu) void free_fdtable(struct fdtable *fdt) { - if (fdt->free_files || - fdt->max_fdset > EMBEDDED_FD_SET_SIZE || - fdt->max_fds > NR_OPEN_DEFAULT) + if (fdt->free_files || fdt->max_fds > NR_OPEN_DEFAULT) call_rcu(&fdt->rcu, free_fdtable_rcu); } @@ -151,12 +147,11 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt) int i; int count; - BUG_ON(nfdt->max_fdset < fdt->max_fdset); BUG_ON(nfdt->max_fds < fdt->max_fds); /* Copy the existing tables and install the new pointers */ - i = fdt->max_fdset / (sizeof(unsigned long) * 8); - count = (nfdt->max_fdset - fdt->max_fdset) / 8; + i = fdt->max_fds / (sizeof(unsigned long) * 8); + count = (nfdt->max_fds - fdt->max_fds) / 8; /* * Don't copy the entire array if the current fdset is @@ -164,9 +159,9 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt) */ if (i) { memcpy (nfdt->open_fds, fdt->open_fds, - fdt->max_fdset/8); + fdt->max_fds/8); memcpy (nfdt->close_on_exec, fdt->close_on_exec, - fdt->max_fdset/8); + fdt->max_fds/8); memset (&nfdt->open_fds->fds_bits[i], 0, count); memset (&nfdt->close_on_exec->fds_bits[i], 0, count); } @@ -201,7 +196,7 @@ fd_set * alloc_fdset(int num) void free_fdset(fd_set *array, int num) { - if (num <= EMBEDDED_FD_SET_SIZE) /* Don't free an embedded fdset */ + if (num <= NR_OPEN_DEFAULT) /* Don't free an embedded fdset */ return; else if (num <= 8 * PAGE_SIZE) kfree(array); @@ -220,18 +215,6 @@ static struct fdtable *alloc_fdtable(int nr) if (!fdt) goto out; - nfds = max_t(int, 8 * L1_CACHE_BYTES, roundup_pow_of_two(nr + 1)); - if (nfds > NR_OPEN) - nfds = NR_OPEN; - - new_openset = alloc_fdset(nfds); - new_execset = alloc_fdset(nfds); - if (!new_openset || !new_execset) - goto out; - fdt->open_fds = new_openset; - fdt->close_on_exec = new_execset; - fdt->max_fdset = nfds; - nfds = NR_OPEN_DEFAULT; /* * Expand to the max in easy steps, and keep expanding it until @@ -251,15 +234,21 @@ static struct fdtable *alloc_fdtable(int nr) nfds = NR_OPEN; } } while (nfds <= nr); + + new_openset = alloc_fdset(nfds); + new_execset = alloc_fdset(nfds); + if (!new_openset || !new_execset) + goto out; + fdt->open_fds = new_openset; + fdt->close_on_exec = new_execset; + new_fds = alloc_fd_array(nfds); if (!new_fds) - goto out2; + goto out; fdt->fd = new_fds; fdt->max_fds = nfds; fdt->free_files = NULL; return fdt; -out2: - nfds = fdt->max_fdset; out: free_fdset(new_openset, nfds); free_fdset(new_execset, nfds); @@ -290,7 +279,7 @@ static int expand_fdtable(struct files_struct *files, int nr) * we dropped the lock */ cur_fdt = files_fdtable(files); - if (nr >= cur_fdt->max_fds || nr >= cur_fdt->max_fdset) { + if (nr >= cur_fdt->max_fds) { /* Continue as planned */ copy_fdtable(new_fdt, cur_fdt); rcu_assign_pointer(files->fdt, new_fdt); @@ -316,11 +305,10 @@ int expand_files(struct files_struct *files, int nr) fdt = files_fdtable(files); /* Do we need to expand? */ - if (nr < fdt->max_fdset && nr < fdt->max_fds) + if (nr < fdt->max_fds) return 0; /* Can we expand? */ - if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN || - nr >= NR_OPEN) + if (nr >= NR_OPEN) return -EMFILE; /* All good, so we try */ diff --git a/fs/open.c b/fs/open.c index 0d94319e8681..c989fb4cf7b9 100644 --- a/fs/open.c +++ b/fs/open.c @@ -864,8 +864,7 @@ int get_unused_fd(void) repeat: fdt = files_fdtable(files); - fd = find_next_zero_bit(fdt->open_fds->fds_bits, - fdt->max_fdset, + fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds, files->next_fd); /* diff --git a/fs/select.c b/fs/select.c index dcbc1112b7ec..fe0893afd931 100644 --- a/fs/select.c +++ b/fs/select.c @@ -311,7 +311,7 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, { fd_set_bits fds; void *bits; - int ret, max_fdset; + int ret, max_fds; unsigned int size; struct fdtable *fdt; /* Allocate small arguments on the stack to save memory and be faster */ @@ -321,13 +321,13 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, if (n < 0) goto out_nofds; - /* max_fdset can increase, so grab it once to avoid race */ + /* max_fds can increase, so grab it once to avoid race */ rcu_read_lock(); fdt = files_fdtable(current->files); - max_fdset = fdt->max_fdset; + max_fds = fdt->max_fds; rcu_read_unlock(); - if (n > max_fdset) - n = max_fdset; + if (n > max_fds) + n = max_fds; /* * We need 6 bitmaps (in/out/ex for both incoming and outgoing), diff --git a/include/linux/file.h b/include/linux/file.h index 6e77b9177f9e..02be4012225b 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -26,14 +26,8 @@ struct embedded_fd_set { unsigned long fds_bits[1]; }; -/* - * More than this number of fds: we use a separately allocated fd_set - */ -#define EMBEDDED_FD_SET_SIZE (BITS_PER_BYTE * sizeof(struct embedded_fd_set)) - struct fdtable { unsigned int max_fds; - int max_fdset; struct file ** fd; /* current fd array */ fd_set *close_on_exec; fd_set *open_fds; diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 7272ff9ee77c..58c18daab65d 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -12,7 +12,6 @@ #define INIT_FDTABLE \ { \ .max_fds = NR_OPEN_DEFAULT, \ - .max_fdset = EMBEDDED_FD_SET_SIZE, \ .fd = &init_files.fd_array[0], \ .close_on_exec = (fd_set *)&init_files.close_on_exec_init, \ .open_fds = (fd_set *)&init_files.open_fds_init, \ diff --git a/kernel/exit.c b/kernel/exit.c index 03e64fe4a14a..5f77e76b4f97 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -425,7 +425,7 @@ static void close_files(struct files_struct * files) for (;;) { unsigned long set; i = j * __NFDBITS; - if (i >= fdt->max_fdset || i >= fdt->max_fds) + if (i >= fdt->max_fds) break; set = fdt->open_fds->fds_bits[j++]; while (set) { diff --git a/kernel/fork.c b/kernel/fork.c index 30eab4f063cd..aba595424f78 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -614,7 +614,7 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk) static int count_open_files(struct fdtable *fdt) { - int size = fdt->max_fdset; + int size = fdt->max_fds; int i; /* Find the last open fd */ @@ -641,7 +641,6 @@ static struct files_struct *alloc_files(void) newf->next_fd = 0; fdt = &newf->fdtab; fdt->max_fds = NR_OPEN_DEFAULT; - fdt->max_fdset = EMBEDDED_FD_SET_SIZE; fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init; fdt->open_fds = (fd_set *)&newf->open_fds_init; fdt->fd = &newf->fd_array[0]; @@ -662,7 +661,7 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) { struct files_struct *newf; struct file **old_fds, **new_fds; - int open_files, size, i, expand; + int open_files, size, i; struct fdtable *old_fdt, *new_fdt; *errorp = -ENOMEM; @@ -673,25 +672,14 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) spin_lock(&oldf->file_lock); old_fdt = files_fdtable(oldf); new_fdt = files_fdtable(newf); - size = old_fdt->max_fdset; open_files = count_open_files(old_fdt); - expand = 0; /* - * Check whether we need to allocate a larger fd array or fd set. - * Note: we're not a clone task, so the open count won't change. + * Check whether we need to allocate a larger fd array and fd set. + * Note: we're not a clone task, so the open count won't change. */ - if (open_files > new_fdt->max_fdset) { - new_fdt->max_fdset = 0; - expand = 1; - } if (open_files > new_fdt->max_fds) { new_fdt->max_fds = 0; - expand = 1; - } - - /* if the old fdset gets grown now, we'll only copy up to "size" fds */ - if (expand) { spin_unlock(&oldf->file_lock); spin_lock(&newf->file_lock); *errorp = expand_files(newf, open_files-1); @@ -739,8 +727,8 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) /* This is long word aligned thus could use a optimized version */ memset(new_fds, 0, size); - if (new_fdt->max_fdset > open_files) { - int left = (new_fdt->max_fdset-open_files)/8; + if (new_fdt->max_fds > open_files) { + int left = (new_fdt->max_fds-open_files)/8; int start = open_files / (8 * sizeof(unsigned long)); memset(&new_fdt->open_fds->fds_bits[start], 0, left); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3753416eb9b9..65fb5e8ea941 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1734,7 +1734,7 @@ static inline void flush_unauthorized_files(struct files_struct * files) j++; i = j * __NFDBITS; fdt = files_fdtable(files); - if (i >= fdt->max_fds || i >= fdt->max_fdset) + if (i >= fdt->max_fds) break; set = fdt->open_fds->fds_bits[j]; if (!set) -- cgit v1.2.3 From 4fd45812cbe875a620c86a096a5d46c742694b7e Mon Sep 17 00:00:00 2001 From: Vadim Lobanov Date: Sun, 10 Dec 2006 02:21:17 -0800 Subject: [PATCH] fdtable: Remove the free_files field An fdtable can either be embedded inside a files_struct or standalone (after being expanded). When an fdtable is being discarded after all RCU references to it have expired, we must either free it directly, in the standalone case, or free the files_struct it is contained within, in the embedded case. Currently the free_files field controls this behavior, but we can get rid of it entirely, as all the necessary information is already recorded. We can distinguish embedded and standalone fdtables using max_fds, and if it is embedded we can divine the relevant files_struct using container_of(). Signed-off-by: Vadim Lobanov Cc: Christoph Hellwig Cc: Al Viro Cc: Dipankar Sarma Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/file.c | 27 ++++++++------------------- include/linux/file.h | 3 +-- include/linux/init_task.h | 1 - kernel/exit.c | 6 ++---- kernel/fork.c | 1 - 5 files changed, 11 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/fs/file.c b/fs/file.c index fb3d2038dc21..17e6a55521e2 100644 --- a/fs/file.c +++ b/fs/file.c @@ -91,7 +91,7 @@ static void free_fdtable_work(struct work_struct *work) } } -static void free_fdtable_rcu(struct rcu_head *rcu) +void free_fdtable_rcu(struct rcu_head *rcu) { struct fdtable *fdt = container_of(rcu, struct fdtable, rcu); int fdset_size, fdarray_size; @@ -101,20 +101,15 @@ static void free_fdtable_rcu(struct rcu_head *rcu) fdset_size = fdt->max_fds / 8; fdarray_size = fdt->max_fds * sizeof(struct file *); - if (fdt->free_files) { + if (fdt->max_fds <= NR_OPEN_DEFAULT) { /* - * The this fdtable was embedded in the files structure - * and the files structure itself was getting destroyed. - * It is now safe to free the files structure. + * This fdtable is embedded in the files structure and that + * structure itself is getting destroyed. */ - kmem_cache_free(files_cachep, fdt->free_files); + kmem_cache_free(files_cachep, + container_of(fdt, struct files_struct, fdtab)); return; } - if (fdt->max_fds <= NR_OPEN_DEFAULT) - /* - * The fdtable was embedded - */ - return; if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) { kfree(fdt->open_fds); kfree(fdt->close_on_exec); @@ -132,12 +127,6 @@ static void free_fdtable_rcu(struct rcu_head *rcu) } } -void free_fdtable(struct fdtable *fdt) -{ - if (fdt->free_files || fdt->max_fds > NR_OPEN_DEFAULT) - call_rcu(&fdt->rcu, free_fdtable_rcu); -} - /* * Expand the fdset in the files_struct. Called with the files spinlock * held for write. @@ -247,7 +236,6 @@ static struct fdtable *alloc_fdtable(int nr) goto out; fdt->fd = new_fds; fdt->max_fds = nfds; - fdt->free_files = NULL; return fdt; out: free_fdset(new_openset, nfds); @@ -283,7 +271,8 @@ static int expand_fdtable(struct files_struct *files, int nr) /* Continue as planned */ copy_fdtable(new_fdt, cur_fdt); rcu_assign_pointer(files->fdt, new_fdt); - free_fdtable(cur_fdt); + if (cur_fdt->max_fds > NR_OPEN_DEFAULT) + call_rcu(&cur_fdt->rcu, free_fdtable_rcu); } else { /* Somebody else expanded, so undo our attempt */ __free_fdtable(new_fdt); diff --git a/include/linux/file.h b/include/linux/file.h index 02be4012225b..319118f275b0 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -32,7 +32,6 @@ struct fdtable { fd_set *close_on_exec; fd_set *open_fds; struct rcu_head rcu; - struct files_struct *free_files; struct fdtable *next; }; @@ -84,7 +83,7 @@ extern fd_set *alloc_fdset(int); extern void free_fdset(fd_set *, int); extern int expand_files(struct files_struct *, int nr); -extern void free_fdtable(struct fdtable *fdt); +extern void free_fdtable_rcu(struct rcu_head *rcu); extern void __init files_defer_init(void); static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 58c18daab65d..b5315150199e 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -16,7 +16,6 @@ .close_on_exec = (fd_set *)&init_files.close_on_exec_init, \ .open_fds = (fd_set *)&init_files.open_fds_init, \ .rcu = RCU_HEAD_INIT, \ - .free_files = NULL, \ .next = NULL, \ } diff --git a/kernel/exit.c b/kernel/exit.c index 5f77e76b4f97..122fadb972fc 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -466,11 +466,9 @@ void fastcall put_files_struct(struct files_struct *files) * you can free files immediately. */ fdt = files_fdtable(files); - if (fdt == &files->fdtab) - fdt->free_files = files; - else + if (fdt != &files->fdtab) kmem_cache_free(files_cachep, files); - free_fdtable(fdt); + call_rcu(&fdt->rcu, free_fdtable_rcu); } } diff --git a/kernel/fork.c b/kernel/fork.c index aba595424f78..d16c566eb645 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -645,7 +645,6 @@ static struct files_struct *alloc_files(void) fdt->open_fds = (fd_set *)&newf->open_fds_init; fdt->fd = &newf->fd_array[0]; INIT_RCU_HEAD(&fdt->rcu); - fdt->free_files = NULL; fdt->next = NULL; rcu_assign_pointer(newf->fdt, fdt); out: -- cgit v1.2.3 From 5466b456ed6748e0bfe02831e570004d4c04c1d7 Mon Sep 17 00:00:00 2001 From: Vadim Lobanov Date: Sun, 10 Dec 2006 02:21:22 -0800 Subject: [PATCH] fdtable: Implement new pagesize-based fdtable allocator This patch provides an improved fdtable allocation scheme, useful for expanding fdtable file descriptor entries. The main focus is on the fdarray, as its memory usage grows 128 times faster than that of an fdset. The allocation algorithm sizes the fdarray in such a way that its memory usage increases in easy page-sized chunks. The overall algorithm expands the allowed size in powers of two, in order to amortize the cost of invoking vmalloc() for larger allocation sizes. Namely, the following sizes for the fdarray are considered, and the smallest that accommodates the requested fd count is chosen: pagesize / 4 pagesize / 2 pagesize <- memory allocator switch point pagesize * 2 pagesize * 4 ...etc... Unlike the current implementation, this allocation scheme does not require a loop to compute the optimal fdarray size, and can be done in efficient straightline code. Furthermore, since the fdarray overflows the pagesize boundary long before any of the fdsets do, it makes sense to optimize run-time by allocating both fdsets in a single swoop. Even together, they will still be, by far, smaller than the fdarray. The fdtable->open_fds is now used as the anchor for the fdset memory allocation. Signed-off-by: Vadim Lobanov Cc: Christoph Hellwig Cc: Al Viro Cc: Dipankar Sarma Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/file.c | 208 ++++++++++++++++++--------------------------------- include/linux/file.h | 6 -- 2 files changed, 72 insertions(+), 142 deletions(-) (limited to 'include/linux') diff --git a/fs/file.c b/fs/file.c index 17e6a55521e2..857fa49e984c 100644 --- a/fs/file.c +++ b/fs/file.c @@ -32,46 +32,28 @@ struct fdtable_defer { */ static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list); - -/* - * Allocate an fd array, using kmalloc or vmalloc. - * Note: the array isn't cleared at allocation time. - */ -struct file ** alloc_fd_array(int num) +static inline void * alloc_fdmem(unsigned int size) { - struct file **new_fds; - int size = num * sizeof(struct file *); - if (size <= PAGE_SIZE) - new_fds = (struct file **) kmalloc(size, GFP_KERNEL); - else - new_fds = (struct file **) vmalloc(size); - return new_fds; + return kmalloc(size, GFP_KERNEL); + else + return vmalloc(size); } -void free_fd_array(struct file **array, int num) +static inline void free_fdarr(struct fdtable *fdt) { - int size = num * sizeof(struct file *); - - if (!array) { - printk (KERN_ERR "free_fd_array: array = 0 (num = %d)\n", num); - return; - } - - if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */ - return; - else if (size <= PAGE_SIZE) - kfree(array); + if (fdt->max_fds <= (PAGE_SIZE / sizeof(struct file *))) + kfree(fdt->fd); else - vfree(array); + vfree(fdt->fd); } -static void __free_fdtable(struct fdtable *fdt) +static inline void free_fdset(struct fdtable *fdt) { - free_fdset(fdt->open_fds, fdt->max_fds); - free_fdset(fdt->close_on_exec, fdt->max_fds); - free_fd_array(fdt->fd, fdt->max_fds); - kfree(fdt); + if (fdt->max_fds <= (PAGE_SIZE * BITS_PER_BYTE / 2)) + kfree(fdt->open_fds); + else + vfree(fdt->open_fds); } static void free_fdtable_work(struct work_struct *work) @@ -86,7 +68,9 @@ static void free_fdtable_work(struct work_struct *work) spin_unlock_bh(&f->lock); while(fdt) { struct fdtable *next = fdt->next; - __free_fdtable(fdt); + vfree(fdt->fd); + free_fdset(fdt); + kfree(fdt); fdt = next; } } @@ -94,12 +78,9 @@ static void free_fdtable_work(struct work_struct *work) void free_fdtable_rcu(struct rcu_head *rcu) { struct fdtable *fdt = container_of(rcu, struct fdtable, rcu); - int fdset_size, fdarray_size; struct fdtable_defer *fddef; BUG_ON(!fdt); - fdset_size = fdt->max_fds / 8; - fdarray_size = fdt->max_fds * sizeof(struct file *); if (fdt->max_fds <= NR_OPEN_DEFAULT) { /* @@ -110,10 +91,9 @@ void free_fdtable_rcu(struct rcu_head *rcu) container_of(fdt, struct files_struct, fdtab)); return; } - if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) { - kfree(fdt->open_fds); - kfree(fdt->close_on_exec); + if (fdt->max_fds <= (PAGE_SIZE / sizeof(struct file *))) { kfree(fdt->fd); + kfree(fdt->open_fds); kfree(fdt); } else { fddef = &get_cpu_var(fdtable_defer_list); @@ -131,116 +111,70 @@ void free_fdtable_rcu(struct rcu_head *rcu) * Expand the fdset in the files_struct. Called with the files spinlock * held for write. */ -static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt) +static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt) { - int i; - int count; - - BUG_ON(nfdt->max_fds < fdt->max_fds); - /* Copy the existing tables and install the new pointers */ - - i = fdt->max_fds / (sizeof(unsigned long) * 8); - count = (nfdt->max_fds - fdt->max_fds) / 8; - - /* - * Don't copy the entire array if the current fdset is - * not yet initialised. - */ - if (i) { - memcpy (nfdt->open_fds, fdt->open_fds, - fdt->max_fds/8); - memcpy (nfdt->close_on_exec, fdt->close_on_exec, - fdt->max_fds/8); - memset (&nfdt->open_fds->fds_bits[i], 0, count); - memset (&nfdt->close_on_exec->fds_bits[i], 0, count); - } + unsigned int cpy, set; - /* Don't copy/clear the array if we are creating a new - fd array for fork() */ - if (fdt->max_fds) { - memcpy(nfdt->fd, fdt->fd, - fdt->max_fds * sizeof(struct file *)); - /* clear the remainder of the array */ - memset(&nfdt->fd[fdt->max_fds], 0, - (nfdt->max_fds - fdt->max_fds) * - sizeof(struct file *)); - } -} - -/* - * Allocate an fdset array, using kmalloc or vmalloc. - * Note: the array isn't cleared at allocation time. - */ -fd_set * alloc_fdset(int num) -{ - fd_set *new_fdset; - int size = num / 8; - - if (size <= PAGE_SIZE) - new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL); - else - new_fdset = (fd_set *) vmalloc(size); - return new_fdset; -} - -void free_fdset(fd_set *array, int num) -{ - if (num <= NR_OPEN_DEFAULT) /* Don't free an embedded fdset */ + BUG_ON(nfdt->max_fds < ofdt->max_fds); + if (ofdt->max_fds == 0) return; - else if (num <= 8 * PAGE_SIZE) - kfree(array); - else - vfree(array); + + cpy = ofdt->max_fds * sizeof(struct file *); + set = (nfdt->max_fds - ofdt->max_fds) * sizeof(struct file *); + memcpy(nfdt->fd, ofdt->fd, cpy); + memset((char *)(nfdt->fd) + cpy, 0, set); + + cpy = ofdt->max_fds / BITS_PER_BYTE; + set = (nfdt->max_fds - ofdt->max_fds) / BITS_PER_BYTE; + memcpy(nfdt->open_fds, ofdt->open_fds, cpy); + memset((char *)(nfdt->open_fds) + cpy, 0, set); + memcpy(nfdt->close_on_exec, ofdt->close_on_exec, cpy); + memset((char *)(nfdt->close_on_exec) + cpy, 0, set); } -static struct fdtable *alloc_fdtable(int nr) +static struct fdtable * alloc_fdtable(unsigned int nr) { - struct fdtable *fdt = NULL; - int nfds = 0; - fd_set *new_openset = NULL, *new_execset = NULL; - struct file **new_fds; - - fdt = kzalloc(sizeof(*fdt), GFP_KERNEL); - if (!fdt) - goto out; + struct fdtable *fdt; + char *data; - nfds = NR_OPEN_DEFAULT; /* - * Expand to the max in easy steps, and keep expanding it until - * we have enough for the requested fd array size. + * Figure out how many fds we actually want to support in this fdtable. + * Allocation steps are keyed to the size of the fdarray, since it + * grows far faster than any of the other dynamic data. We try to fit + * the fdarray into comfortable page-tuned chunks: starting at 1024B + * and growing in powers of two from there on. */ - do { -#if NR_OPEN_DEFAULT < 256 - if (nfds < 256) - nfds = 256; - else -#endif - if (nfds < (PAGE_SIZE / sizeof(struct file *))) - nfds = PAGE_SIZE / sizeof(struct file *); - else { - nfds = nfds * 2; - if (nfds > NR_OPEN) - nfds = NR_OPEN; - } - } while (nfds <= nr); - - new_openset = alloc_fdset(nfds); - new_execset = alloc_fdset(nfds); - if (!new_openset || !new_execset) - goto out; - fdt->open_fds = new_openset; - fdt->close_on_exec = new_execset; + nr /= (1024 / sizeof(struct file *)); + nr = roundup_pow_of_two(nr + 1); + nr *= (1024 / sizeof(struct file *)); + if (nr > NR_OPEN) + nr = NR_OPEN; - new_fds = alloc_fd_array(nfds); - if (!new_fds) + fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL); + if (!fdt) goto out; - fdt->fd = new_fds; - fdt->max_fds = nfds; + fdt->max_fds = nr; + data = alloc_fdmem(nr * sizeof(struct file *)); + if (!data) + goto out_fdt; + fdt->fd = (struct file **)data; + data = alloc_fdmem(max_t(unsigned int, + 2 * nr / BITS_PER_BYTE, L1_CACHE_BYTES)); + if (!data) + goto out_arr; + fdt->open_fds = (fd_set *)data; + data += nr / BITS_PER_BYTE; + fdt->close_on_exec = (fd_set *)data; + INIT_RCU_HEAD(&fdt->rcu); + fdt->next = NULL; + return fdt; -out: - free_fdset(new_openset, nfds); - free_fdset(new_execset, nfds); + +out_arr: + free_fdarr(fdt); +out_fdt: kfree(fdt); +out: return NULL; } @@ -275,7 +209,9 @@ static int expand_fdtable(struct files_struct *files, int nr) call_rcu(&cur_fdt->rcu, free_fdtable_rcu); } else { /* Somebody else expanded, so undo our attempt */ - __free_fdtable(new_fdt); + free_fdarr(new_fdt); + free_fdset(new_fdt); + kfree(new_fdt); } return 1; } diff --git a/include/linux/file.h b/include/linux/file.h index 319118f275b0..edca361f2ab4 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -76,12 +76,6 @@ extern int get_unused_fd(void); extern void FASTCALL(put_unused_fd(unsigned int fd)); struct kmem_cache; -extern struct file ** alloc_fd_array(int); -extern void free_fd_array(struct file **, int); - -extern fd_set *alloc_fdset(int); -extern void free_fdset(fd_set *, int); - extern int expand_files(struct files_struct *, int nr); extern void free_fdtable_rcu(struct rcu_head *rcu); extern void __init files_defer_init(void); -- cgit v1.2.3 From 4c36a5dec25fb344ad76b11860da3a8b50bd1248 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sun, 10 Dec 2006 02:21:24 -0800 Subject: [PATCH] round_jiffies infrastructure Introduce a round_jiffies() function as well as a round_jiffies_relative() function. These functions round a jiffies value to the next whole second. The primary purpose of this rounding is to cause all "we don't care exactly when" timers to happen at the same jiffy. This avoids multiple timers firing within the second for no real reason; with dynamic ticks these extra timers cause wakeups from deep sleep CPU sleep states and thus waste power. The exact wakeup moment is skewed by the cpu number, to avoid all cpus from waking up at the exact same time (and hitting the same lock/cachelines there) [akpm@osdl.org: fix variable type] Signed-off-by: Arjan van de Ven Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/timer.h | 6 +++ kernel/timer.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) (limited to 'include/linux') diff --git a/include/linux/timer.h b/include/linux/timer.h index c982304dbafd..eeef6643d4c6 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -98,4 +98,10 @@ extern void run_local_timers(void); struct hrtimer; extern int it_real_fn(struct hrtimer *); +unsigned long __round_jiffies(unsigned long j, int cpu); +unsigned long __round_jiffies_relative(unsigned long j, int cpu); +unsigned long round_jiffies(unsigned long j); +unsigned long round_jiffies_relative(unsigned long j); + + #endif diff --git a/kernel/timer.c b/kernel/timer.c index c1c7fbcffec1..b1f40f256eb0 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -80,6 +80,138 @@ tvec_base_t boot_tvec_bases; EXPORT_SYMBOL(boot_tvec_bases); static DEFINE_PER_CPU(tvec_base_t *, tvec_bases) = &boot_tvec_bases; +/** + * __round_jiffies - function to round jiffies to a full second + * @j: the time in (absolute) jiffies that should be rounded + * @cpu: the processor number on which the timeout will happen + * + * __round_jiffies rounds an absolute time in the future (in jiffies) + * up or down to (approximately) full seconds. This is useful for timers + * for which the exact time they fire does not matter too much, as long as + * they fire approximately every X seconds. + * + * By rounding these timers to whole seconds, all such timers will fire + * at the same time, rather than at various times spread out. The goal + * of this is to have the CPU wake up less, which saves power. + * + * The exact rounding is skewed for each processor to avoid all + * processors firing at the exact same time, which could lead + * to lock contention or spurious cache line bouncing. + * + * The return value is the rounded version of the "j" parameter. + */ +unsigned long __round_jiffies(unsigned long j, int cpu) +{ + int rem; + unsigned long original = j; + + /* + * We don't want all cpus firing their timers at once hitting the + * same lock or cachelines, so we skew each extra cpu with an extra + * 3 jiffies. This 3 jiffies came originally from the mm/ code which + * already did this. + * The skew is done by adding 3*cpunr, then round, then subtract this + * extra offset again. + */ + j += cpu * 3; + + rem = j % HZ; + + /* + * If the target jiffie is just after a whole second (which can happen + * due to delays of the timer irq, long irq off times etc etc) then + * we should round down to the whole second, not up. Use 1/4th second + * as cutoff for this rounding as an extreme upper bound for this. + */ + if (rem < HZ/4) /* round down */ + j = j - rem; + else /* round up */ + j = j - rem + HZ; + + /* now that we have rounded, subtract the extra skew again */ + j -= cpu * 3; + + if (j <= jiffies) /* rounding ate our timeout entirely; */ + return original; + return j; +} +EXPORT_SYMBOL_GPL(__round_jiffies); + +/** + * __round_jiffies_relative - function to round jiffies to a full second + * @j: the time in (relative) jiffies that should be rounded + * @cpu: the processor number on which the timeout will happen + * + * __round_jiffies_relative rounds a time delta in the future (in jiffies) + * up or down to (approximately) full seconds. This is useful for timers + * for which the exact time they fire does not matter too much, as long as + * they fire approximately every X seconds. + * + * By rounding these timers to whole seconds, all such timers will fire + * at the same time, rather than at various times spread out. The goal + * of this is to have the CPU wake up less, which saves power. + * + * The exact rounding is skewed for each processor to avoid all + * processors firing at the exact same time, which could lead + * to lock contention or spurious cache line bouncing. + * + * The return value is the rounded version of the "j" parameter. + */ +unsigned long __round_jiffies_relative(unsigned long j, int cpu) +{ + /* + * In theory the following code can skip a jiffy in case jiffies + * increments right between the addition and the later subtraction. + * However since the entire point of this function is to use approximate + * timeouts, it's entirely ok to not handle that. + */ + return __round_jiffies(j + jiffies, cpu) - jiffies; +} +EXPORT_SYMBOL_GPL(__round_jiffies_relative); + +/** + * round_jiffies - function to round jiffies to a full second + * @j: the time in (absolute) jiffies that should be rounded + * + * round_jiffies rounds an absolute time in the future (in jiffies) + * up or down to (approximately) full seconds. This is useful for timers + * for which the exact time they fire does not matter too much, as long as + * they fire approximately every X seconds. + * + * By rounding these timers to whole seconds, all such timers will fire + * at the same time, rather than at various times spread out. The goal + * of this is to have the CPU wake up less, which saves power. + * + * The return value is the rounded version of the "j" parameter. + */ +unsigned long round_jiffies(unsigned long j) +{ + return __round_jiffies(j, raw_smp_processor_id()); +} +EXPORT_SYMBOL_GPL(round_jiffies); + +/** + * round_jiffies_relative - function to round jiffies to a full second + * @j: the time in (relative) jiffies that should be rounded + * + * round_jiffies_relative rounds a time delta in the future (in jiffies) + * up or down to (approximately) full seconds. This is useful for timers + * for which the exact time they fire does not matter too much, as long as + * they fire approximately every X seconds. + * + * By rounding these timers to whole seconds, all such timers will fire + * at the same time, rather than at various times spread out. The goal + * of this is to have the CPU wake up less, which saves power. + * + * The return value is the rounded version of the "j" parameter. + */ +unsigned long round_jiffies_relative(unsigned long j) +{ + return __round_jiffies_relative(j, raw_smp_processor_id()); +} +EXPORT_SYMBOL_GPL(round_jiffies_relative); + + static inline void set_running_timer(tvec_base_t *base, struct timer_list *timer) { -- cgit v1.2.3 From f5f1a24a2caa299bb7d294aee92d7dd3410d9ed7 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Sun, 10 Dec 2006 02:21:33 -0800 Subject: [PATCH] clocksource: small cleanup Mostly changing alignment. Just some general cleanup. [akpm@osdl.org: build fix] Signed-off-by: Daniel Walker Acked-by: John Stultz Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/clocksource/acpi_pm.c | 6 +++--- include/linux/clocksource.h | 2 +- kernel/time/clocksource.c | 6 +++--- kernel/timer.c | 16 +++++++++++----- 4 files changed, 18 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 8ab61ef97b4c..b6bcdbbf57b3 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -77,11 +77,11 @@ static struct clocksource clocksource_acpi_pm = { #ifdef CONFIG_PCI -static int acpi_pm_good; +static int __devinitdata acpi_pm_good; static int __init acpi_pm_good_setup(char *__str) { - acpi_pm_good = 1; - return 1; + acpi_pm_good = 1; + return 1; } __setup("acpi_pm_good", acpi_pm_good_setup); diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index d852024ed095..1622d23a8dc3 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -159,7 +159,7 @@ static inline s64 cyc2ns(struct clocksource *cs, cycle_t cycles) * Unless you're the timekeeping code, you should not be using this! */ static inline void clocksource_calculate_interval(struct clocksource *c, - unsigned long length_nsec) + unsigned long length_nsec) { u64 tmp; diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 3651b34cc355..22504afc0d34 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -156,7 +156,7 @@ int clocksource_register(struct clocksource *c) /* check if clocksource is already registered */ if (is_registered_source(c)) { printk("register_clocksource: Cannot register %s. " - "Already registered!", c->name); + "Already registered!", c->name); ret = -EBUSY; } else { /* register it */ @@ -276,10 +276,10 @@ sysfs_show_available_clocksources(struct sys_device *dev, char *buf) * Sysfs setup bits: */ static SYSDEV_ATTR(current_clocksource, 0600, sysfs_show_current_clocksources, - sysfs_override_clocksource); + sysfs_override_clocksource); static SYSDEV_ATTR(available_clocksource, 0600, - sysfs_show_available_clocksources, NULL); + sysfs_show_available_clocksources, NULL); static struct sysdev_class clocksource_sysclass = { set_kset_name("clocksource"), diff --git a/kernel/timer.c b/kernel/timer.c index b1f40f256eb0..0256ab443d8a 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -846,7 +846,7 @@ static int change_clocksource(void) clock = new; clock->cycle_last = now; printk(KERN_INFO "Time: %s clocksource has been installed.\n", - clock->name); + clock->name); return 1; } else if (clock->update_callback) { return clock->update_callback(); @@ -854,7 +854,10 @@ static int change_clocksource(void) return 0; } #else -#define change_clocksource() (0) +static inline int change_clocksource(void) +{ + return 0; +} #endif /** @@ -952,7 +955,8 @@ device_initcall(timekeeping_init_device); * If the error is already larger, we look ahead even further * to compensate for late or lost adjustments. */ -static __always_inline int clocksource_bigadjust(s64 error, s64 *interval, s64 *offset) +static __always_inline int clocksource_bigadjust(s64 error, s64 *interval, + s64 *offset) { s64 tick_error, i; u32 look_ahead, adj; @@ -976,7 +980,8 @@ static __always_inline int clocksource_bigadjust(s64 error, s64 *interval, s64 * * Now calculate the error in (1 << look_ahead) ticks, but first * remove the single look ahead already included in the error. */ - tick_error = current_tick_length() >> (TICK_LENGTH_SHIFT - clock->shift + 1); + tick_error = current_tick_length() >> + (TICK_LENGTH_SHIFT - clock->shift + 1); tick_error -= clock->xtime_interval >> 1; error = ((error - tick_error) >> look_ahead) + tick_error; @@ -1028,7 +1033,8 @@ static void clocksource_adjust(struct clocksource *clock, s64 offset) clock->mult += adj; clock->xtime_interval += interval; clock->xtime_nsec -= offset; - clock->error -= (interval - offset) << (TICK_LENGTH_SHIFT - clock->shift); + clock->error -= (interval - offset) << + (TICK_LENGTH_SHIFT - clock->shift); } /** -- cgit v1.2.3 From 6aa8b732ca01c3d7a54e93f4d701b8aabbe60fb7 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 10 Dec 2006 02:21:36 -0800 Subject: [PATCH] kvm: userspace interface web site: http://kvm.sourceforge.net mailing list: kvm-devel@lists.sourceforge.net (http://lists.sourceforge.net/lists/listinfo/kvm-devel) The following patchset adds a driver for Intel's hardware virtualization extensions to the x86 architecture. The driver adds a character device (/dev/kvm) that exposes the virtualization capabilities to userspace. Using this driver, a process can run a virtual machine (a "guest") in a fully virtualized PC containing its own virtual hard disks, network adapters, and display. Using this driver, one can start multiple virtual machines on a host. Each virtual machine is a process on the host; a virtual cpu is a thread in that process. kill(1), nice(1), top(1) work as expected. In effect, the driver adds a third execution mode to the existing two: we now have kernel mode, user mode, and guest mode. Guest mode has its own address space mapping guest physical memory (which is accessible to user mode by mmap()ing /dev/kvm). Guest mode has no access to any I/O devices; any such access is intercepted and directed to user mode for emulation. The driver supports i386 and x86_64 hosts and guests. All combinations are allowed except x86_64 guest on i386 host. For i386 guests and hosts, both pae and non-pae paging modes are supported. SMP hosts and UP guests are supported. At the moment only Intel hardware is supported, but AMD virtualization support is being worked on. Performance currently is non-stellar due to the naive implementation of the mmu virtualization, which throws away most of the shadow page table entries every context switch. We plan to address this in two ways: - cache shadow page tables across tlb flushes - wait until AMD and Intel release processors with nested page tables Currently a virtual desktop is responsive but consumes a lot of CPU. Under Windows I tried playing pinball and watching a few flash movies; with a recent CPU one can hardly feel the virtualization. Linux/X is slower, probably due to X being in a separate process. In addition to the driver, you need a slightly modified qemu to provide I/O device emulation and the BIOS. Caveats (akpm: might no longer be true): - The Windows install currently bluescreens due to a problem with the virtual APIC. We are working on a fix. A temporary workaround is to use an existing image or install through qemu - Windows 64-bit does not work. That's also true for qemu, so it's probably a problem with the device model. [bero@arklinux.org: build fix] [simon.kagstrom@bth.se: build fix, other fixes] [uril@qumranet.com: KVM: Expose interrupt bitmap] [akpm@osdl.org: i386 build fix] [mingo@elte.hu: i386 fixes] [rdreier@cisco.com: add log levels to all printks] [randy.dunlap@oracle.com: Fix sparse NULL and C99 struct init warnings] [anthony@codemonkey.ws: KVM: AMD SVM: 32-bit host support] Signed-off-by: Yaniv Kamay Signed-off-by: Avi Kivity Cc: Simon Kagstrom Cc: Bernhard Rosenkraenzer Signed-off-by: Uri Lublin Cc: Ingo Molnar Cc: Roland Dreier Signed-off-by: Randy Dunlap Signed-off-by: Anthony Liguori Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/kvm/Kconfig | 33 + drivers/kvm/Makefile | 10 + drivers/kvm/kvm.h | 551 +++++++++++ drivers/kvm/kvm_main.c | 1935 ++++++++++++++++++++++++++++++++++++ drivers/kvm/kvm_svm.h | 44 + drivers/kvm/kvm_vmx.h | 14 + drivers/kvm/mmu.c | 699 +++++++++++++ drivers/kvm/paging_tmpl.h | 397 ++++++++ drivers/kvm/segment_descriptor.h | 17 + drivers/kvm/svm.c | 1677 +++++++++++++++++++++++++++++++ drivers/kvm/svm.h | 315 ++++++ drivers/kvm/vmx.c | 2002 ++++++++++++++++++++++++++++++++++++++ drivers/kvm/vmx.h | 296 ++++++ drivers/kvm/x86_emulate.c | 1409 +++++++++++++++++++++++++++ drivers/kvm/x86_emulate.h | 185 ++++ include/linux/kvm.h | 227 +++++ 18 files changed, 9814 insertions(+) create mode 100644 drivers/kvm/Kconfig create mode 100644 drivers/kvm/Makefile create mode 100644 drivers/kvm/kvm.h create mode 100644 drivers/kvm/kvm_main.c create mode 100644 drivers/kvm/kvm_svm.h create mode 100644 drivers/kvm/kvm_vmx.h create mode 100644 drivers/kvm/mmu.c create mode 100644 drivers/kvm/paging_tmpl.h create mode 100644 drivers/kvm/segment_descriptor.h create mode 100644 drivers/kvm/svm.c create mode 100644 drivers/kvm/svm.h create mode 100644 drivers/kvm/vmx.c create mode 100644 drivers/kvm/vmx.h create mode 100644 drivers/kvm/x86_emulate.c create mode 100644 drivers/kvm/x86_emulate.h create mode 100644 include/linux/kvm.h (limited to 'include/linux') diff --git a/drivers/Kconfig b/drivers/Kconfig index 4929e923b5c6..e7da9fa724ec 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -80,4 +80,6 @@ source "drivers/rtc/Kconfig" source "drivers/dma/Kconfig" +source "drivers/kvm/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 50f76da598c9..0dd96d1afd39 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_SPI) += spi/ obj-$(CONFIG_PCCARD) += pcmcia/ obj-$(CONFIG_DIO) += dio/ obj-$(CONFIG_SBUS) += sbus/ +obj-$(CONFIG_KVM) += kvm/ obj-$(CONFIG_ZORRO) += zorro/ obj-$(CONFIG_MAC) += macintosh/ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/ diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig new file mode 100644 index 000000000000..36412e90f09b --- /dev/null +++ b/drivers/kvm/Kconfig @@ -0,0 +1,33 @@ +# +# KVM configuration +# +config KVM + tristate "Kernel-based Virtual Machine (KVM) support" + depends on X86 && EXPERIMENTAL + ---help--- + Support hosting fully virtualized guest machines using hardware + virtualization extensions. You will need a fairly recent + processor equipped with virtualization extensions. You will also + need to select one or more of the processor modules below. + + This module provides access to the hardware capabilities through + a character device node named /dev/kvm. + + To compile this as a module, choose M here: the module + will be called kvm. + + If unsure, say N. + +config KVM_INTEL + tristate "KVM for Intel processors support" + depends on KVM + ---help--- + Provides support for KVM on Intel processors equipped with the VT + extensions. + +config KVM_AMD + tristate "KVM for AMD processors support" + depends on KVM + ---help--- + Provides support for KVM on AMD processors equipped with the AMD-V + (SVM) extensions. diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile new file mode 100644 index 000000000000..c0a789fa9d65 --- /dev/null +++ b/drivers/kvm/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for Kernel-based Virtual Machine module +# + +kvm-objs := kvm_main.o mmu.o x86_emulate.o +obj-$(CONFIG_KVM) += kvm.o +kvm-intel-objs = vmx.o +obj-$(CONFIG_KVM_INTEL) += kvm-intel.o +kvm-amd-objs = svm.o +obj-$(CONFIG_KVM_AMD) += kvm-amd.o diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h new file mode 100644 index 000000000000..5785d0870ab6 --- /dev/null +++ b/drivers/kvm/kvm.h @@ -0,0 +1,551 @@ +#ifndef __KVM_H +#define __KVM_H + +/* + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +#include "vmx.h" +#include + +#define CR0_PE_MASK (1ULL << 0) +#define CR0_TS_MASK (1ULL << 3) +#define CR0_NE_MASK (1ULL << 5) +#define CR0_WP_MASK (1ULL << 16) +#define CR0_NW_MASK (1ULL << 29) +#define CR0_CD_MASK (1ULL << 30) +#define CR0_PG_MASK (1ULL << 31) + +#define CR3_WPT_MASK (1ULL << 3) +#define CR3_PCD_MASK (1ULL << 4) + +#define CR3_RESEVED_BITS 0x07ULL +#define CR3_L_MODE_RESEVED_BITS (~((1ULL << 40) - 1) | 0x0fe7ULL) +#define CR3_FLAGS_MASK ((1ULL << 5) - 1) + +#define CR4_VME_MASK (1ULL << 0) +#define CR4_PSE_MASK (1ULL << 4) +#define CR4_PAE_MASK (1ULL << 5) +#define CR4_PGE_MASK (1ULL << 7) +#define CR4_VMXE_MASK (1ULL << 13) + +#define KVM_GUEST_CR0_MASK \ + (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \ + | CR0_NW_MASK | CR0_CD_MASK) +#define KVM_VM_CR0_ALWAYS_ON \ + (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK) +#define KVM_GUEST_CR4_MASK \ + (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK) +#define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK) +#define KVM_RMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK | CR4_VME_MASK) + +#define INVALID_PAGE (~(hpa_t)0) +#define UNMAPPED_GVA (~(gpa_t)0) + +#define KVM_MAX_VCPUS 1 +#define KVM_MEMORY_SLOTS 4 +#define KVM_NUM_MMU_PAGES 256 + +#define FX_IMAGE_SIZE 512 +#define FX_IMAGE_ALIGN 16 +#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN) + +#define DE_VECTOR 0 +#define DF_VECTOR 8 +#define TS_VECTOR 10 +#define NP_VECTOR 11 +#define SS_VECTOR 12 +#define GP_VECTOR 13 +#define PF_VECTOR 14 + +#define SELECTOR_TI_MASK (1 << 2) +#define SELECTOR_RPL_MASK 0x03 + +#define IOPL_SHIFT 12 + +/* + * Address types: + * + * gva - guest virtual address + * gpa - guest physical address + * gfn - guest frame number + * hva - host virtual address + * hpa - host physical address + * hfn - host frame number + */ + +typedef unsigned long gva_t; +typedef u64 gpa_t; +typedef unsigned long gfn_t; + +typedef unsigned long hva_t; +typedef u64 hpa_t; +typedef unsigned long hfn_t; + +struct kvm_mmu_page { + struct list_head link; + hpa_t page_hpa; + unsigned long slot_bitmap; /* One bit set per slot which has memory + * in this shadow page. + */ + int global; /* Set if all ptes in this page are global */ + u64 *parent_pte; +}; + +struct vmcs { + u32 revision_id; + u32 abort; + char data[0]; +}; + +#define vmx_msr_entry kvm_msr_entry + +struct kvm_vcpu; + +/* + * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level + * 32-bit). The kvm_mmu structure abstracts the details of the current mmu + * mode. + */ +struct kvm_mmu { + void (*new_cr3)(struct kvm_vcpu *vcpu); + int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err); + void (*inval_page)(struct kvm_vcpu *vcpu, gva_t gva); + void (*free)(struct kvm_vcpu *vcpu); + gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva); + hpa_t root_hpa; + int root_level; + int shadow_root_level; +}; + +struct kvm_guest_debug { + int enabled; + unsigned long bp[4]; + int singlestep; +}; + +enum { + VCPU_REGS_RAX = 0, + VCPU_REGS_RCX = 1, + VCPU_REGS_RDX = 2, + VCPU_REGS_RBX = 3, + VCPU_REGS_RSP = 4, + VCPU_REGS_RBP = 5, + VCPU_REGS_RSI = 6, + VCPU_REGS_RDI = 7, +#ifdef __x86_64__ + VCPU_REGS_R8 = 8, + VCPU_REGS_R9 = 9, + VCPU_REGS_R10 = 10, + VCPU_REGS_R11 = 11, + VCPU_REGS_R12 = 12, + VCPU_REGS_R13 = 13, + VCPU_REGS_R14 = 14, + VCPU_REGS_R15 = 15, +#endif + NR_VCPU_REGS +}; + +enum { + VCPU_SREG_CS, + VCPU_SREG_DS, + VCPU_SREG_ES, + VCPU_SREG_FS, + VCPU_SREG_GS, + VCPU_SREG_SS, + VCPU_SREG_TR, + VCPU_SREG_LDTR, +}; + +struct kvm_vcpu { + struct kvm *kvm; + union { + struct vmcs *vmcs; + struct vcpu_svm *svm; + }; + struct mutex mutex; + int cpu; + int launched; + unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ +#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long) + unsigned long irq_pending[NR_IRQ_WORDS]; + unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */ + unsigned long rip; /* needs vcpu_load_rsp_rip() */ + + unsigned long cr0; + unsigned long cr2; + unsigned long cr3; + unsigned long cr4; + unsigned long cr8; + u64 shadow_efer; + u64 apic_base; + int nmsrs; + struct vmx_msr_entry *guest_msrs; + struct vmx_msr_entry *host_msrs; + + struct list_head free_pages; + struct kvm_mmu_page page_header_buf[KVM_NUM_MMU_PAGES]; + struct kvm_mmu mmu; + + struct kvm_guest_debug guest_debug; + + char fx_buf[FX_BUF_SIZE]; + char *host_fx_image; + char *guest_fx_image; + + int mmio_needed; + int mmio_read_completed; + int mmio_is_write; + int mmio_size; + unsigned char mmio_data[8]; + gpa_t mmio_phys_addr; + + struct { + int active; + u8 save_iopl; + struct kvm_save_segment { + u16 selector; + unsigned long base; + u32 limit; + u32 ar; + } tr, es, ds, fs, gs; + } rmode; +}; + +struct kvm_memory_slot { + gfn_t base_gfn; + unsigned long npages; + unsigned long flags; + struct page **phys_mem; + unsigned long *dirty_bitmap; +}; + +struct kvm { + spinlock_t lock; /* protects everything except vcpus */ + int nmemslots; + struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS]; + struct list_head active_mmu_pages; + struct kvm_vcpu vcpus[KVM_MAX_VCPUS]; + int memory_config_version; + int busy; +}; + +struct kvm_stat { + u32 pf_fixed; + u32 pf_guest; + u32 tlb_flush; + u32 invlpg; + + u32 exits; + u32 io_exits; + u32 mmio_exits; + u32 signal_exits; + u32 irq_exits; +}; + +struct descriptor_table { + u16 limit; + unsigned long base; +} __attribute__((packed)); + +struct kvm_arch_ops { + int (*cpu_has_kvm_support)(void); /* __init */ + int (*disabled_by_bios)(void); /* __init */ + void (*hardware_enable)(void *dummy); /* __init */ + void (*hardware_disable)(void *dummy); + int (*hardware_setup)(void); /* __init */ + void (*hardware_unsetup)(void); /* __exit */ + + int (*vcpu_create)(struct kvm_vcpu *vcpu); + void (*vcpu_free)(struct kvm_vcpu *vcpu); + + struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu); + void (*vcpu_put)(struct kvm_vcpu *vcpu); + + int (*set_guest_debug)(struct kvm_vcpu *vcpu, + struct kvm_debug_guest *dbg); + int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata); + int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); + u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg); + void (*get_segment)(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg); + void (*set_segment)(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg); + int (*is_long_mode)(struct kvm_vcpu *vcpu); + void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l); + void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0); + void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu, + unsigned long cr0); + void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3); + void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4); + void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer); + void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); + void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); + void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); + void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); + unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr); + void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value, + int *exception); + void (*cache_regs)(struct kvm_vcpu *vcpu); + void (*decache_regs)(struct kvm_vcpu *vcpu); + unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); + void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags); + + void (*invlpg)(struct kvm_vcpu *vcpu, gva_t addr); + void (*tlb_flush)(struct kvm_vcpu *vcpu); + void (*inject_page_fault)(struct kvm_vcpu *vcpu, + unsigned long addr, u32 err_code); + + void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code); + + int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); + int (*vcpu_setup)(struct kvm_vcpu *vcpu); + void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); +}; + +extern struct kvm_stat kvm_stat; +extern struct kvm_arch_ops *kvm_arch_ops; + +#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt) +#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt) + +int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module); +void kvm_exit_arch(void); + +void kvm_mmu_destroy(struct kvm_vcpu *vcpu); +int kvm_mmu_init(struct kvm_vcpu *vcpu); + +int kvm_mmu_reset_context(struct kvm_vcpu *vcpu); +void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot); + +hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa); +#define HPA_MSB ((sizeof(hpa_t) * 8) - 1) +#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB) +static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } +hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva); + +void kvm_emulator_want_group7_invlpg(void); + +extern hpa_t bad_page_address; + +static inline struct page *gfn_to_page(struct kvm_memory_slot *slot, gfn_t gfn) +{ + return slot->phys_mem[gfn - slot->base_gfn]; +} + +struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn); +void mark_page_dirty(struct kvm *kvm, gfn_t gfn); + +enum emulation_result { + EMULATE_DONE, /* no further processing */ + EMULATE_DO_MMIO, /* kvm_run filled with mmio request */ + EMULATE_FAIL, /* can't emulate this instruction */ +}; + +int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run, + unsigned long cr2, u16 error_code); +void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); +void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); +void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, + unsigned long *rflags); + +unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr); +void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value, + unsigned long *rflags); + +struct x86_emulate_ctxt; + +int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); +int emulate_clts(struct kvm_vcpu *vcpu); +int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, + unsigned long *dest); +int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, + unsigned long value); + +void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); +void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0); +void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0); +void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0); +void lmsw(struct kvm_vcpu *vcpu, unsigned long msw); + +#ifdef __x86_64__ +void set_efer(struct kvm_vcpu *vcpu, u64 efer); +#endif + +void fx_init(struct kvm_vcpu *vcpu); + +void load_msrs(struct vmx_msr_entry *e, int n); +void save_msrs(struct vmx_msr_entry *e, int n); +void kvm_resched(struct kvm_vcpu *vcpu); + +int kvm_read_guest(struct kvm_vcpu *vcpu, + gva_t addr, + unsigned long size, + void *dest); + +int kvm_write_guest(struct kvm_vcpu *vcpu, + gva_t addr, + unsigned long size, + void *data); + +unsigned long segment_base(u16 selector); + +static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn) +{ + struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn); + return (slot) ? slot->phys_mem[gfn - slot->base_gfn] : NULL; +} + +static inline int is_pae(struct kvm_vcpu *vcpu) +{ + return vcpu->cr4 & CR4_PAE_MASK; +} + +static inline int is_pse(struct kvm_vcpu *vcpu) +{ + return vcpu->cr4 & CR4_PSE_MASK; +} + +static inline int is_paging(struct kvm_vcpu *vcpu) +{ + return vcpu->cr0 & CR0_PG_MASK; +} + +static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot) +{ + return slot - kvm->memslots; +} + +static inline struct kvm_mmu_page *page_header(hpa_t shadow_page) +{ + struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT); + + return (struct kvm_mmu_page *)page->private; +} + +static inline u16 read_fs(void) +{ + u16 seg; + asm ("mov %%fs, %0" : "=g"(seg)); + return seg; +} + +static inline u16 read_gs(void) +{ + u16 seg; + asm ("mov %%gs, %0" : "=g"(seg)); + return seg; +} + +static inline u16 read_ldt(void) +{ + u16 ldt; + asm ("sldt %0" : "=g"(ldt)); + return ldt; +} + +static inline void load_fs(u16 sel) +{ + asm ("mov %0, %%fs" : : "rm"(sel)); +} + +static inline void load_gs(u16 sel) +{ + asm ("mov %0, %%gs" : : "rm"(sel)); +} + +#ifndef load_ldt +static inline void load_ldt(u16 sel) +{ + asm ("lldt %0" : : "g"(sel)); +} +#endif + +static inline void get_idt(struct descriptor_table *table) +{ + asm ("sidt %0" : "=m"(*table)); +} + +static inline void get_gdt(struct descriptor_table *table) +{ + asm ("sgdt %0" : "=m"(*table)); +} + +static inline unsigned long read_tr_base(void) +{ + u16 tr; + asm ("str %0" : "=g"(tr)); + return segment_base(tr); +} + +#ifdef __x86_64__ +static inline unsigned long read_msr(unsigned long msr) +{ + u64 value; + + rdmsrl(msr, value); + return value; +} +#endif + +static inline void fx_save(void *image) +{ + asm ("fxsave (%0)":: "r" (image)); +} + +static inline void fx_restore(void *image) +{ + asm ("fxrstor (%0)":: "r" (image)); +} + +static inline void fpu_init(void) +{ + asm ("finit"); +} + +static inline u32 get_rdx_init_val(void) +{ + return 0x600; /* P6 family */ +} + +#define ASM_VMX_VMCLEAR_RAX ".byte 0x66, 0x0f, 0xc7, 0x30" +#define ASM_VMX_VMLAUNCH ".byte 0x0f, 0x01, 0xc2" +#define ASM_VMX_VMRESUME ".byte 0x0f, 0x01, 0xc3" +#define ASM_VMX_VMPTRLD_RAX ".byte 0x0f, 0xc7, 0x30" +#define ASM_VMX_VMREAD_RDX_RAX ".byte 0x0f, 0x78, 0xd0" +#define ASM_VMX_VMWRITE_RAX_RDX ".byte 0x0f, 0x79, 0xd0" +#define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4" +#define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4" +#define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30" + +#define MSR_IA32_TIME_STAMP_COUNTER 0x010 + +#define TSS_IOPB_BASE_OFFSET 0x66 +#define TSS_BASE_SIZE 0x68 +#define TSS_IOPB_SIZE (65536 / 8) +#define TSS_REDIRECTION_SIZE (256 / 8) +#define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) + +#ifdef __x86_64__ + +/* + * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64. Therefore + * we need to allocate shadow page tables in the first 4GB of memory, which + * happens to fit the DMA32 zone. + */ +#define GFP_KVM_MMU (GFP_KERNEL | __GFP_DMA32) + +#else + +#define GFP_KVM_MMU GFP_KERNEL + +#endif + +#endif diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c new file mode 100644 index 000000000000..b6b8a41b5ec8 --- /dev/null +++ b/drivers/kvm/kvm_main.c @@ -0,0 +1,1935 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * This module enables machines with Intel VT-x extensions to run virtual + * machines without emulation or binary translation. + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Avi Kivity + * Yaniv Kamay + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "kvm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "x86_emulate.h" +#include "segment_descriptor.h" + +MODULE_AUTHOR("Qumranet"); +MODULE_LICENSE("GPL"); + +struct kvm_arch_ops *kvm_arch_ops; +struct kvm_stat kvm_stat; +EXPORT_SYMBOL_GPL(kvm_stat); + +static struct kvm_stats_debugfs_item { + const char *name; + u32 *data; + struct dentry *dentry; +} debugfs_entries[] = { + { "pf_fixed", &kvm_stat.pf_fixed }, + { "pf_guest", &kvm_stat.pf_guest }, + { "tlb_flush", &kvm_stat.tlb_flush }, + { "invlpg", &kvm_stat.invlpg }, + { "exits", &kvm_stat.exits }, + { "io_exits", &kvm_stat.io_exits }, + { "mmio_exits", &kvm_stat.mmio_exits }, + { "signal_exits", &kvm_stat.signal_exits }, + { "irq_exits", &kvm_stat.irq_exits }, + { 0, 0 } +}; + +static struct dentry *debugfs_dir; + +#define MAX_IO_MSRS 256 + +#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL +#define LMSW_GUEST_MASK 0x0eULL +#define CR4_RESEVED_BITS (~((1ULL << 11) - 1)) +#define CR8_RESEVED_BITS (~0x0fULL) +#define EFER_RESERVED_BITS 0xfffffffffffff2fe + +struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr) +{ + int i; + + for (i = 0; i < vcpu->nmsrs; ++i) + if (vcpu->guest_msrs[i].index == msr) + return &vcpu->guest_msrs[i]; + return 0; +} +EXPORT_SYMBOL_GPL(find_msr_entry); + +#ifdef __x86_64__ +// LDT or TSS descriptor in the GDT. 16 bytes. +struct segment_descriptor_64 { + struct segment_descriptor s; + u32 base_higher; + u32 pad_zero; +}; + +#endif + +unsigned long segment_base(u16 selector) +{ + struct descriptor_table gdt; + struct segment_descriptor *d; + unsigned long table_base; + typedef unsigned long ul; + unsigned long v; + + if (selector == 0) + return 0; + + asm ("sgdt %0" : "=m"(gdt)); + table_base = gdt.base; + + if (selector & 4) { /* from ldt */ + u16 ldt_selector; + + asm ("sldt %0" : "=g"(ldt_selector)); + table_base = segment_base(ldt_selector); + } + d = (struct segment_descriptor *)(table_base + (selector & ~7)); + v = d->base_low | ((ul)d->base_mid << 16) | ((ul)d->base_high << 24); +#ifdef __x86_64__ + if (d->system == 0 + && (d->type == 2 || d->type == 9 || d->type == 11)) + v |= ((ul)((struct segment_descriptor_64 *)d)->base_higher) << 32; +#endif + return v; +} +EXPORT_SYMBOL_GPL(segment_base); + +int kvm_read_guest(struct kvm_vcpu *vcpu, + gva_t addr, + unsigned long size, + void *dest) +{ + unsigned char *host_buf = dest; + unsigned long req_size = size; + + while (size) { + hpa_t paddr; + unsigned now; + unsigned offset; + hva_t guest_buf; + + paddr = gva_to_hpa(vcpu, addr); + + if (is_error_hpa(paddr)) + break; + + guest_buf = (hva_t)kmap_atomic( + pfn_to_page(paddr >> PAGE_SHIFT), + KM_USER0); + offset = addr & ~PAGE_MASK; + guest_buf |= offset; + now = min(size, PAGE_SIZE - offset); + memcpy(host_buf, (void*)guest_buf, now); + host_buf += now; + addr += now; + size -= now; + kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0); + } + return req_size - size; +} +EXPORT_SYMBOL_GPL(kvm_read_guest); + +int kvm_write_guest(struct kvm_vcpu *vcpu, + gva_t addr, + unsigned long size, + void *data) +{ + unsigned char *host_buf = data; + unsigned long req_size = size; + + while (size) { + hpa_t paddr; + unsigned now; + unsigned offset; + hva_t guest_buf; + + paddr = gva_to_hpa(vcpu, addr); + + if (is_error_hpa(paddr)) + break; + + guest_buf = (hva_t)kmap_atomic( + pfn_to_page(paddr >> PAGE_SHIFT), KM_USER0); + offset = addr & ~PAGE_MASK; + guest_buf |= offset; + now = min(size, PAGE_SIZE - offset); + memcpy((void*)guest_buf, host_buf, now); + host_buf += now; + addr += now; + size -= now; + kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0); + } + return req_size - size; +} +EXPORT_SYMBOL_GPL(kvm_write_guest); + +static int vcpu_slot(struct kvm_vcpu *vcpu) +{ + return vcpu - vcpu->kvm->vcpus; +} + +/* + * Switches to specified vcpu, until a matching vcpu_put() + */ +static struct kvm_vcpu *vcpu_load(struct kvm *kvm, int vcpu_slot) +{ + struct kvm_vcpu *vcpu = &kvm->vcpus[vcpu_slot]; + + mutex_lock(&vcpu->mutex); + if (unlikely(!vcpu->vmcs)) { + mutex_unlock(&vcpu->mutex); + return 0; + } + return kvm_arch_ops->vcpu_load(vcpu); +} + +static void vcpu_put(struct kvm_vcpu *vcpu) +{ + kvm_arch_ops->vcpu_put(vcpu); + put_cpu(); + mutex_unlock(&vcpu->mutex); +} + +static int kvm_dev_open(struct inode *inode, struct file *filp) +{ + struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); + int i; + + if (!kvm) + return -ENOMEM; + + spin_lock_init(&kvm->lock); + INIT_LIST_HEAD(&kvm->active_mmu_pages); + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + struct kvm_vcpu *vcpu = &kvm->vcpus[i]; + + mutex_init(&vcpu->mutex); + vcpu->mmu.root_hpa = INVALID_PAGE; + INIT_LIST_HEAD(&vcpu->free_pages); + } + filp->private_data = kvm; + return 0; +} + +/* + * Free any memory in @free but not in @dont. + */ +static void kvm_free_physmem_slot(struct kvm_memory_slot *free, + struct kvm_memory_slot *dont) +{ + int i; + + if (!dont || free->phys_mem != dont->phys_mem) + if (free->phys_mem) { + for (i = 0; i < free->npages; ++i) + __free_page(free->phys_mem[i]); + vfree(free->phys_mem); + } + + if (!dont || free->dirty_bitmap != dont->dirty_bitmap) + vfree(free->dirty_bitmap); + + free->phys_mem = 0; + free->npages = 0; + free->dirty_bitmap = 0; +} + +static void kvm_free_physmem(struct kvm *kvm) +{ + int i; + + for (i = 0; i < kvm->nmemslots; ++i) + kvm_free_physmem_slot(&kvm->memslots[i], 0); +} + +static void kvm_free_vcpu(struct kvm_vcpu *vcpu) +{ + kvm_arch_ops->vcpu_free(vcpu); + kvm_mmu_destroy(vcpu); +} + +static void kvm_free_vcpus(struct kvm *kvm) +{ + unsigned int i; + + for (i = 0; i < KVM_MAX_VCPUS; ++i) + kvm_free_vcpu(&kvm->vcpus[i]); +} + +static int kvm_dev_release(struct inode *inode, struct file *filp) +{ + struct kvm *kvm = filp->private_data; + + kvm_free_vcpus(kvm); + kvm_free_physmem(kvm); + kfree(kvm); + return 0; +} + +static void inject_gp(struct kvm_vcpu *vcpu) +{ + kvm_arch_ops->inject_gp(vcpu, 0); +} + +static int pdptrs_have_reserved_bits_set(struct kvm_vcpu *vcpu, + unsigned long cr3) +{ + gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT; + unsigned offset = (cr3 & (PAGE_SIZE-1)) >> 5; + int i; + u64 pdpte; + u64 *pdpt; + struct kvm_memory_slot *memslot; + + spin_lock(&vcpu->kvm->lock); + memslot = gfn_to_memslot(vcpu->kvm, pdpt_gfn); + /* FIXME: !memslot - emulate? 0xff? */ + pdpt = kmap_atomic(gfn_to_page(memslot, pdpt_gfn), KM_USER0); + + for (i = 0; i < 4; ++i) { + pdpte = pdpt[offset + i]; + if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) + break; + } + + kunmap_atomic(pdpt, KM_USER0); + spin_unlock(&vcpu->kvm->lock); + + return i != 4; +} + +void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) +{ + if (cr0 & CR0_RESEVED_BITS) { + printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n", + cr0, vcpu->cr0); + inject_gp(vcpu); + return; + } + + if ((cr0 & CR0_NW_MASK) && !(cr0 & CR0_CD_MASK)) { + printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n"); + inject_gp(vcpu); + return; + } + + if ((cr0 & CR0_PG_MASK) && !(cr0 & CR0_PE_MASK)) { + printk(KERN_DEBUG "set_cr0: #GP, set PG flag " + "and a clear PE flag\n"); + inject_gp(vcpu); + return; + } + + if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) { +#ifdef __x86_64__ + if ((vcpu->shadow_efer & EFER_LME)) { + int cs_db, cs_l; + + if (!is_pae(vcpu)) { + printk(KERN_DEBUG "set_cr0: #GP, start paging " + "in long mode while PAE is disabled\n"); + inject_gp(vcpu); + return; + } + kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); + if (cs_l) { + printk(KERN_DEBUG "set_cr0: #GP, start paging " + "in long mode while CS.L == 1\n"); + inject_gp(vcpu); + return; + + } + } else +#endif + if (is_pae(vcpu) && + pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) { + printk(KERN_DEBUG "set_cr0: #GP, pdptrs " + "reserved bits\n"); + inject_gp(vcpu); + return; + } + + } + + kvm_arch_ops->set_cr0(vcpu, cr0); + vcpu->cr0 = cr0; + + spin_lock(&vcpu->kvm->lock); + kvm_mmu_reset_context(vcpu); + spin_unlock(&vcpu->kvm->lock); + return; +} +EXPORT_SYMBOL_GPL(set_cr0); + +void lmsw(struct kvm_vcpu *vcpu, unsigned long msw) +{ + set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f)); +} +EXPORT_SYMBOL_GPL(lmsw); + +void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) +{ + if (cr4 & CR4_RESEVED_BITS) { + printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n"); + inject_gp(vcpu); + return; + } + + if (kvm_arch_ops->is_long_mode(vcpu)) { + if (!(cr4 & CR4_PAE_MASK)) { + printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while " + "in long mode\n"); + inject_gp(vcpu); + return; + } + } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK) + && pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) { + printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n"); + inject_gp(vcpu); + } + + if (cr4 & CR4_VMXE_MASK) { + printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n"); + inject_gp(vcpu); + return; + } + kvm_arch_ops->set_cr4(vcpu, cr4); + spin_lock(&vcpu->kvm->lock); + kvm_mmu_reset_context(vcpu); + spin_unlock(&vcpu->kvm->lock); +} +EXPORT_SYMBOL_GPL(set_cr4); + +void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) +{ + if (kvm_arch_ops->is_long_mode(vcpu)) { + if ( cr3 & CR3_L_MODE_RESEVED_BITS) { + printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); + inject_gp(vcpu); + return; + } + } else { + if (cr3 & CR3_RESEVED_BITS) { + printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); + inject_gp(vcpu); + return; + } + if (is_paging(vcpu) && is_pae(vcpu) && + pdptrs_have_reserved_bits_set(vcpu, cr3)) { + printk(KERN_DEBUG "set_cr3: #GP, pdptrs " + "reserved bits\n"); + inject_gp(vcpu); + return; + } + } + + vcpu->cr3 = cr3; + spin_lock(&vcpu->kvm->lock); + vcpu->mmu.new_cr3(vcpu); + spin_unlock(&vcpu->kvm->lock); +} +EXPORT_SYMBOL_GPL(set_cr3); + +void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) +{ + if ( cr8 & CR8_RESEVED_BITS) { + printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8); + inject_gp(vcpu); + return; + } + vcpu->cr8 = cr8; +} +EXPORT_SYMBOL_GPL(set_cr8); + +void fx_init(struct kvm_vcpu *vcpu) +{ + struct __attribute__ ((__packed__)) fx_image_s { + u16 control; //fcw + u16 status; //fsw + u16 tag; // ftw + u16 opcode; //fop + u64 ip; // fpu ip + u64 operand;// fpu dp + u32 mxcsr; + u32 mxcsr_mask; + + } *fx_image; + + fx_save(vcpu->host_fx_image); + fpu_init(); + fx_save(vcpu->guest_fx_image); + fx_restore(vcpu->host_fx_image); + + fx_image = (struct fx_image_s *)vcpu->guest_fx_image; + fx_image->mxcsr = 0x1f80; + memset(vcpu->guest_fx_image + sizeof(struct fx_image_s), + 0, FX_IMAGE_SIZE - sizeof(struct fx_image_s)); +} +EXPORT_SYMBOL_GPL(fx_init); + +/* + * Creates some virtual cpus. Good luck creating more than one. + */ +static int kvm_dev_ioctl_create_vcpu(struct kvm *kvm, int n) +{ + int r; + struct kvm_vcpu *vcpu; + + r = -EINVAL; + if (n < 0 || n >= KVM_MAX_VCPUS) + goto out; + + vcpu = &kvm->vcpus[n]; + + mutex_lock(&vcpu->mutex); + + if (vcpu->vmcs) { + mutex_unlock(&vcpu->mutex); + return -EEXIST; + } + + vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf, + FX_IMAGE_ALIGN); + vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE; + + vcpu->cpu = -1; /* First load will set up TR */ + vcpu->kvm = kvm; + r = kvm_arch_ops->vcpu_create(vcpu); + if (r < 0) + goto out_free_vcpus; + + kvm_arch_ops->vcpu_load(vcpu); + + r = kvm_arch_ops->vcpu_setup(vcpu); + if (r >= 0) + r = kvm_mmu_init(vcpu); + + vcpu_put(vcpu); + + if (r < 0) + goto out_free_vcpus; + + return 0; + +out_free_vcpus: + kvm_free_vcpu(vcpu); + mutex_unlock(&vcpu->mutex); +out: + return r; +} + +/* + * Allocate some memory and give it an address in the guest physical address + * space. + * + * Discontiguous memory is allowed, mostly for framebuffers. + */ +static int kvm_dev_ioctl_set_memory_region(struct kvm *kvm, + struct kvm_memory_region *mem) +{ + int r; + gfn_t base_gfn; + unsigned long npages; + unsigned long i; + struct kvm_memory_slot *memslot; + struct kvm_memory_slot old, new; + int memory_config_version; + + r = -EINVAL; + /* General sanity checks */ + if (mem->memory_size & (PAGE_SIZE - 1)) + goto out; + if (mem->guest_phys_addr & (PAGE_SIZE - 1)) + goto out; + if (mem->slot >= KVM_MEMORY_SLOTS) + goto out; + if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr) + goto out; + + memslot = &kvm->memslots[mem->slot]; + base_gfn = mem->guest_phys_addr >> PAGE_SHIFT; + npages = mem->memory_size >> PAGE_SHIFT; + + if (!npages) + mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES; + +raced: + spin_lock(&kvm->lock); + + memory_config_version = kvm->memory_config_version; + new = old = *memslot; + + new.base_gfn = base_gfn; + new.npages = npages; + new.flags = mem->flags; + + /* Disallow changing a memory slot's size. */ + r = -EINVAL; + if (npages && old.npages && npages != old.npages) + goto out_unlock; + + /* Check for overlaps */ + r = -EEXIST; + for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { + struct kvm_memory_slot *s = &kvm->memslots[i]; + + if (s == memslot) + continue; + if (!((base_gfn + npages <= s->base_gfn) || + (base_gfn >= s->base_gfn + s->npages))) + goto out_unlock; + } + /* + * Do memory allocations outside lock. memory_config_version will + * detect any races. + */ + spin_unlock(&kvm->lock); + + /* Deallocate if slot is being removed */ + if (!npages) + new.phys_mem = 0; + + /* Free page dirty bitmap if unneeded */ + if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES)) + new.dirty_bitmap = 0; + + r = -ENOMEM; + + /* Allocate if a slot is being created */ + if (npages && !new.phys_mem) { + new.phys_mem = vmalloc(npages * sizeof(struct page *)); + + if (!new.phys_mem) + goto out_free; + + memset(new.phys_mem, 0, npages * sizeof(struct page *)); + for (i = 0; i < npages; ++i) { + new.phys_mem[i] = alloc_page(GFP_HIGHUSER + | __GFP_ZERO); + if (!new.phys_mem[i]) + goto out_free; + } + } + + /* Allocate page dirty bitmap if needed */ + if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) { + unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8; + + new.dirty_bitmap = vmalloc(dirty_bytes); + if (!new.dirty_bitmap) + goto out_free; + memset(new.dirty_bitmap, 0, dirty_bytes); + } + + spin_lock(&kvm->lock); + + if (memory_config_version != kvm->memory_config_version) { + spin_unlock(&kvm->lock); + kvm_free_physmem_slot(&new, &old); + goto raced; + } + + r = -EAGAIN; + if (kvm->busy) + goto out_unlock; + + if (mem->slot >= kvm->nmemslots) + kvm->nmemslots = mem->slot + 1; + + *memslot = new; + ++kvm->memory_config_version; + + spin_unlock(&kvm->lock); + + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + struct kvm_vcpu *vcpu; + + vcpu = vcpu_load(kvm, i); + if (!vcpu) + continue; + kvm_mmu_reset_context(vcpu); + vcpu_put(vcpu); + } + + kvm_free_physmem_slot(&old, &new); + return 0; + +out_unlock: + spin_unlock(&kvm->lock); +out_free: + kvm_free_physmem_slot(&new, &old); +out: + return r; +} + +/* + * Get (and clear) the dirty memory log for a memory slot. + */ +static int kvm_dev_ioctl_get_dirty_log(struct kvm *kvm, + struct kvm_dirty_log *log) +{ + struct kvm_memory_slot *memslot; + int r, i; + int n; + unsigned long any = 0; + + spin_lock(&kvm->lock); + + /* + * Prevent changes to guest memory configuration even while the lock + * is not taken. + */ + ++kvm->busy; + spin_unlock(&kvm->lock); + r = -EINVAL; + if (log->slot >= KVM_MEMORY_SLOTS) + goto out; + + memslot = &kvm->memslots[log->slot]; + r = -ENOENT; + if (!memslot->dirty_bitmap) + goto out; + + n = ALIGN(memslot->npages, 8) / 8; + + for (i = 0; !any && i < n; ++i) + any = memslot->dirty_bitmap[i]; + + r = -EFAULT; + if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n)) + goto out; + + + if (any) { + spin_lock(&kvm->lock); + kvm_mmu_slot_remove_write_access(kvm, log->slot); + spin_unlock(&kvm->lock); + memset(memslot->dirty_bitmap, 0, n); + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + struct kvm_vcpu *vcpu = vcpu_load(kvm, i); + + if (!vcpu) + continue; + kvm_arch_ops->tlb_flush(vcpu); + vcpu_put(vcpu); + } + } + + r = 0; + +out: + spin_lock(&kvm->lock); + --kvm->busy; + spin_unlock(&kvm->lock); + return r; +} + +struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) +{ + int i; + + for (i = 0; i < kvm->nmemslots; ++i) { + struct kvm_memory_slot *memslot = &kvm->memslots[i]; + + if (gfn >= memslot->base_gfn + && gfn < memslot->base_gfn + memslot->npages) + return memslot; + } + return 0; +} +EXPORT_SYMBOL_GPL(gfn_to_memslot); + +void mark_page_dirty(struct kvm *kvm, gfn_t gfn) +{ + int i; + struct kvm_memory_slot *memslot = 0; + unsigned long rel_gfn; + + for (i = 0; i < kvm->nmemslots; ++i) { + memslot = &kvm->memslots[i]; + + if (gfn >= memslot->base_gfn + && gfn < memslot->base_gfn + memslot->npages) { + + if (!memslot || !memslot->dirty_bitmap) + return; + + rel_gfn = gfn - memslot->base_gfn; + + /* avoid RMW */ + if (!test_bit(rel_gfn, memslot->dirty_bitmap)) + set_bit(rel_gfn, memslot->dirty_bitmap); + return; + } + } +} + +static int emulator_read_std(unsigned long addr, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + struct kvm_vcpu *vcpu = ctxt->vcpu; + void *data = val; + + while (bytes) { + gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); + unsigned offset = addr & (PAGE_SIZE-1); + unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset); + unsigned long pfn; + struct kvm_memory_slot *memslot; + void *page; + + if (gpa == UNMAPPED_GVA) + return X86EMUL_PROPAGATE_FAULT; + pfn = gpa >> PAGE_SHIFT; + memslot = gfn_to_memslot(vcpu->kvm, pfn); + if (!memslot) + return X86EMUL_UNHANDLEABLE; + page = kmap_atomic(gfn_to_page(memslot, pfn), KM_USER0); + + memcpy(data, page + offset, tocopy); + + kunmap_atomic(page, KM_USER0); + + bytes -= tocopy; + data += tocopy; + addr += tocopy; + } + + return X86EMUL_CONTINUE; +} + +static int emulator_write_std(unsigned long addr, + unsigned long val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + printk(KERN_ERR "emulator_write_std: addr %lx n %d\n", + addr, bytes); + return X86EMUL_UNHANDLEABLE; +} + +static int emulator_read_emulated(unsigned long addr, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + struct kvm_vcpu *vcpu = ctxt->vcpu; + + if (vcpu->mmio_read_completed) { + memcpy(val, vcpu->mmio_data, bytes); + vcpu->mmio_read_completed = 0; + return X86EMUL_CONTINUE; + } else if (emulator_read_std(addr, val, bytes, ctxt) + == X86EMUL_CONTINUE) + return X86EMUL_CONTINUE; + else { + gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); + if (gpa == UNMAPPED_GVA) + return vcpu_printf(vcpu, "not present\n"), X86EMUL_PROPAGATE_FAULT; + vcpu->mmio_needed = 1; + vcpu->mmio_phys_addr = gpa; + vcpu->mmio_size = bytes; + vcpu->mmio_is_write = 0; + + return X86EMUL_UNHANDLEABLE; + } +} + +static int emulator_write_emulated(unsigned long addr, + unsigned long val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + struct kvm_vcpu *vcpu = ctxt->vcpu; + gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); + + if (gpa == UNMAPPED_GVA) + return X86EMUL_PROPAGATE_FAULT; + + vcpu->mmio_needed = 1; + vcpu->mmio_phys_addr = gpa; + vcpu->mmio_size = bytes; + vcpu->mmio_is_write = 1; + memcpy(vcpu->mmio_data, &val, bytes); + + return X86EMUL_CONTINUE; +} + +static int emulator_cmpxchg_emulated(unsigned long addr, + unsigned long old, + unsigned long new, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + static int reported; + + if (!reported) { + reported = 1; + printk(KERN_WARNING "kvm: emulating exchange as write\n"); + } + return emulator_write_emulated(addr, new, bytes, ctxt); +} + +static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) +{ + return kvm_arch_ops->get_segment_base(vcpu, seg); +} + +int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) +{ + spin_lock(&vcpu->kvm->lock); + vcpu->mmu.inval_page(vcpu, address); + spin_unlock(&vcpu->kvm->lock); + kvm_arch_ops->invlpg(vcpu, address); + return X86EMUL_CONTINUE; +} + +int emulate_clts(struct kvm_vcpu *vcpu) +{ + unsigned long cr0 = vcpu->cr0; + + cr0 &= ~CR0_TS_MASK; + kvm_arch_ops->set_cr0(vcpu, cr0); + return X86EMUL_CONTINUE; +} + +int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, unsigned long *dest) +{ + struct kvm_vcpu *vcpu = ctxt->vcpu; + + switch (dr) { + case 0 ... 3: + *dest = kvm_arch_ops->get_dr(vcpu, dr); + return X86EMUL_CONTINUE; + default: + printk(KERN_DEBUG "%s: unexpected dr %u\n", + __FUNCTION__, dr); + return X86EMUL_UNHANDLEABLE; + } +} + +int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) +{ + unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U; + int exception; + + kvm_arch_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception); + if (exception) { + /* FIXME: better handling */ + return X86EMUL_UNHANDLEABLE; + } + return X86EMUL_CONTINUE; +} + +static void report_emulation_failure(struct x86_emulate_ctxt *ctxt) +{ + static int reported; + u8 opcodes[4]; + unsigned long rip = ctxt->vcpu->rip; + unsigned long rip_linear; + + rip_linear = rip + get_segment_base(ctxt->vcpu, VCPU_SREG_CS); + + if (reported) + return; + + emulator_read_std(rip_linear, (void *)opcodes, 4, ctxt); + + printk(KERN_ERR "emulation failed but !mmio_needed?" + " rip %lx %02x %02x %02x %02x\n", + rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]); + reported = 1; +} + +struct x86_emulate_ops emulate_ops = { + .read_std = emulator_read_std, + .write_std = emulator_write_std, + .read_emulated = emulator_read_emulated, + .write_emulated = emulator_write_emulated, + .cmpxchg_emulated = emulator_cmpxchg_emulated, +}; + +int emulate_instruction(struct kvm_vcpu *vcpu, + struct kvm_run *run, + unsigned long cr2, + u16 error_code) +{ + struct x86_emulate_ctxt emulate_ctxt; + int r; + int cs_db, cs_l; + + kvm_arch_ops->cache_regs(vcpu); + + kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); + + emulate_ctxt.vcpu = vcpu; + emulate_ctxt.eflags = kvm_arch_ops->get_rflags(vcpu); + emulate_ctxt.cr2 = cr2; + emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM) + ? X86EMUL_MODE_REAL : cs_l + ? X86EMUL_MODE_PROT64 : cs_db + ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; + + if (emulate_ctxt.mode == X86EMUL_MODE_PROT64) { + emulate_ctxt.cs_base = 0; + emulate_ctxt.ds_base = 0; + emulate_ctxt.es_base = 0; + emulate_ctxt.ss_base = 0; + } else { + emulate_ctxt.cs_base = get_segment_base(vcpu, VCPU_SREG_CS); + emulate_ctxt.ds_base = get_segment_base(vcpu, VCPU_SREG_DS); + emulate_ctxt.es_base = get_segment_base(vcpu, VCPU_SREG_ES); + emulate_ctxt.ss_base = get_segment_base(vcpu, VCPU_SREG_SS); + } + + emulate_ctxt.gs_base = get_segment_base(vcpu, VCPU_SREG_GS); + emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS); + + vcpu->mmio_is_write = 0; + r = x86_emulate_memop(&emulate_ctxt, &emulate_ops); + + if ((r || vcpu->mmio_is_write) && run) { + run->mmio.phys_addr = vcpu->mmio_phys_addr; + memcpy(run->mmio.data, vcpu->mmio_data, 8); + run->mmio.len = vcpu->mmio_size; + run->mmio.is_write = vcpu->mmio_is_write; + } + + if (r) { + if (!vcpu->mmio_needed) { + report_emulation_failure(&emulate_ctxt); + return EMULATE_FAIL; + } + return EMULATE_DO_MMIO; + } + + kvm_arch_ops->decache_regs(vcpu); + kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags); + + if (vcpu->mmio_is_write) + return EMULATE_DO_MMIO; + + return EMULATE_DONE; +} +EXPORT_SYMBOL_GPL(emulate_instruction); + +static u64 mk_cr_64(u64 curr_cr, u32 new_val) +{ + return (curr_cr & ~((1ULL << 32) - 1)) | new_val; +} + +void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) +{ + struct descriptor_table dt = { limit, base }; + + kvm_arch_ops->set_gdt(vcpu, &dt); +} + +void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) +{ + struct descriptor_table dt = { limit, base }; + + kvm_arch_ops->set_idt(vcpu, &dt); +} + +void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, + unsigned long *rflags) +{ + lmsw(vcpu, msw); + *rflags = kvm_arch_ops->get_rflags(vcpu); +} + +unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) +{ + switch (cr) { + case 0: + return vcpu->cr0; + case 2: + return vcpu->cr2; + case 3: + return vcpu->cr3; + case 4: + return vcpu->cr4; + default: + vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr); + return 0; + } +} + +void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val, + unsigned long *rflags) +{ + switch (cr) { + case 0: + set_cr0(vcpu, mk_cr_64(vcpu->cr0, val)); + *rflags = kvm_arch_ops->get_rflags(vcpu); + break; + case 2: + vcpu->cr2 = val; + break; + case 3: + set_cr3(vcpu, val); + break; + case 4: + set_cr4(vcpu, mk_cr_64(vcpu->cr4, val)); + break; + default: + vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr); + } +} + +/* + * Reads an msr value (of 'msr_index') into 'pdata'. + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) +{ + return kvm_arch_ops->get_msr(vcpu, msr_index, pdata); +} + +#ifdef __x86_64__ + +void set_efer(struct kvm_vcpu *vcpu, u64 efer) +{ + struct vmx_msr_entry *msr; + + if (efer & EFER_RESERVED_BITS) { + printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n", + efer); + inject_gp(vcpu); + return; + } + + if (is_paging(vcpu) + && (vcpu->shadow_efer & EFER_LME) != (efer & EFER_LME)) { + printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n"); + inject_gp(vcpu); + return; + } + + efer &= ~EFER_LMA; + efer |= vcpu->shadow_efer & EFER_LMA; + + vcpu->shadow_efer = efer; + + msr = find_msr_entry(vcpu, MSR_EFER); + + if (!(efer & EFER_LMA)) + efer &= ~EFER_LME; + msr->data = efer; +} +EXPORT_SYMBOL_GPL(set_efer); + +#endif + +/* + * Writes msr value into into the appropriate "register". + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) +{ + return kvm_arch_ops->set_msr(vcpu, msr_index, data); +} + +void kvm_resched(struct kvm_vcpu *vcpu) +{ + vcpu_put(vcpu); + cond_resched(); + /* Cannot fail - no vcpu unplug yet. */ + vcpu_load(vcpu->kvm, vcpu_slot(vcpu)); +} +EXPORT_SYMBOL_GPL(kvm_resched); + +void load_msrs(struct vmx_msr_entry *e, int n) +{ + int i; + + for (i = 0; i < n; ++i) + wrmsrl(e[i].index, e[i].data); +} +EXPORT_SYMBOL_GPL(load_msrs); + +void save_msrs(struct vmx_msr_entry *e, int n) +{ + int i; + + for (i = 0; i < n; ++i) + rdmsrl(e[i].index, e[i].data); +} +EXPORT_SYMBOL_GPL(save_msrs); + +static int kvm_dev_ioctl_run(struct kvm *kvm, struct kvm_run *kvm_run) +{ + struct kvm_vcpu *vcpu; + int r; + + if (kvm_run->vcpu < 0 || kvm_run->vcpu >= KVM_MAX_VCPUS) + return -EINVAL; + + vcpu = vcpu_load(kvm, kvm_run->vcpu); + if (!vcpu) + return -ENOENT; + + if (kvm_run->emulated) { + kvm_arch_ops->skip_emulated_instruction(vcpu); + kvm_run->emulated = 0; + } + + if (kvm_run->mmio_completed) { + memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); + vcpu->mmio_read_completed = 1; + } + + vcpu->mmio_needed = 0; + + r = kvm_arch_ops->run(vcpu, kvm_run); + + vcpu_put(vcpu); + return r; +} + +static int kvm_dev_ioctl_get_regs(struct kvm *kvm, struct kvm_regs *regs) +{ + struct kvm_vcpu *vcpu; + + if (regs->vcpu < 0 || regs->vcpu >= KVM_MAX_VCPUS) + return -EINVAL; + + vcpu = vcpu_load(kvm, regs->vcpu); + if (!vcpu) + return -ENOENT; + + kvm_arch_ops->cache_regs(vcpu); + + regs->rax = vcpu->regs[VCPU_REGS_RAX]; + regs->rbx = vcpu->regs[VCPU_REGS_RBX]; + regs->rcx = vcpu->regs[VCPU_REGS_RCX]; + regs->rdx = vcpu->regs[VCPU_REGS_RDX]; + regs->rsi = vcpu->regs[VCPU_REGS_RSI]; + regs->rdi = vcpu->regs[VCPU_REGS_RDI]; + regs->rsp = vcpu->regs[VCPU_REGS_RSP]; + regs->rbp = vcpu->regs[VCPU_REGS_RBP]; +#ifdef __x86_64__ + regs->r8 = vcpu->regs[VCPU_REGS_R8]; + regs->r9 = vcpu->regs[VCPU_REGS_R9]; + regs->r10 = vcpu->regs[VCPU_REGS_R10]; + regs->r11 = vcpu->regs[VCPU_REGS_R11]; + regs->r12 = vcpu->regs[VCPU_REGS_R12]; + regs->r13 = vcpu->regs[VCPU_REGS_R13]; + regs->r14 = vcpu->regs[VCPU_REGS_R14]; + regs->r15 = vcpu->regs[VCPU_REGS_R15]; +#endif + + regs->rip = vcpu->rip; + regs->rflags = kvm_arch_ops->get_rflags(vcpu); + + /* + * Don't leak debug flags in case they were set for guest debugging + */ + if (vcpu->guest_debug.enabled && vcpu->guest_debug.singlestep) + regs->rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF); + + vcpu_put(vcpu); + + return 0; +} + +static int kvm_dev_ioctl_set_regs(struct kvm *kvm, struct kvm_regs *regs) +{ + struct kvm_vcpu *vcpu; + + if (regs->vcpu < 0 || regs->vcpu >= KVM_MAX_VCPUS) + return -EINVAL; + + vcpu = vcpu_load(kvm, regs->vcpu); + if (!vcpu) + return -ENOENT; + + vcpu->regs[VCPU_REGS_RAX] = regs->rax; + vcpu->regs[VCPU_REGS_RBX] = regs->rbx; + vcpu->regs[VCPU_REGS_RCX] = regs->rcx; + vcpu->regs[VCPU_REGS_RDX] = regs->rdx; + vcpu->regs[VCPU_REGS_RSI] = regs->rsi; + vcpu->regs[VCPU_REGS_RDI] = regs->rdi; + vcpu->regs[VCPU_REGS_RSP] = regs->rsp; + vcpu->regs[VCPU_REGS_RBP] = regs->rbp; +#ifdef __x86_64__ + vcpu->regs[VCPU_REGS_R8] = regs->r8; + vcpu->regs[VCPU_REGS_R9] = regs->r9; + vcpu->regs[VCPU_REGS_R10] = regs->r10; + vcpu->regs[VCPU_REGS_R11] = regs->r11; + vcpu->regs[VCPU_REGS_R12] = regs->r12; + vcpu->regs[VCPU_REGS_R13] = regs->r13; + vcpu->regs[VCPU_REGS_R14] = regs->r14; + vcpu->regs[VCPU_REGS_R15] = regs->r15; +#endif + + vcpu->rip = regs->rip; + kvm_arch_ops->set_rflags(vcpu, regs->rflags); + + kvm_arch_ops->decache_regs(vcpu); + + vcpu_put(vcpu); + + return 0; +} + +static void get_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + return kvm_arch_ops->get_segment(vcpu, var, seg); +} + +static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs) +{ + struct kvm_vcpu *vcpu; + struct descriptor_table dt; + + if (sregs->vcpu < 0 || sregs->vcpu >= KVM_MAX_VCPUS) + return -EINVAL; + vcpu = vcpu_load(kvm, sregs->vcpu); + if (!vcpu) + return -ENOENT; + + get_segment(vcpu, &sregs->cs, VCPU_SREG_CS); + get_segment(vcpu, &sregs->ds, VCPU_SREG_DS); + get_segment(vcpu, &sregs->es, VCPU_SREG_ES); + get_segment(vcpu, &sregs->fs, VCPU_SREG_FS); + get_segment(vcpu, &sregs->gs, VCPU_SREG_GS); + get_segment(vcpu, &sregs->ss, VCPU_SREG_SS); + + get_segment(vcpu, &sregs->tr, VCPU_SREG_TR); + get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); + + kvm_arch_ops->get_idt(vcpu, &dt); + sregs->idt.limit = dt.limit; + sregs->idt.base = dt.base; + kvm_arch_ops->get_gdt(vcpu, &dt); + sregs->gdt.limit = dt.limit; + sregs->gdt.base = dt.base; + + sregs->cr0 = vcpu->cr0; + sregs->cr2 = vcpu->cr2; + sregs->cr3 = vcpu->cr3; + sregs->cr4 = vcpu->cr4; + sregs->cr8 = vcpu->cr8; + sregs->efer = vcpu->shadow_efer; + sregs->apic_base = vcpu->apic_base; + + memcpy(sregs->interrupt_bitmap, vcpu->irq_pending, + sizeof sregs->interrupt_bitmap); + + vcpu_put(vcpu); + + return 0; +} + +static void set_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + return kvm_arch_ops->set_segment(vcpu, var, seg); +} + +static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs) +{ + struct kvm_vcpu *vcpu; + int mmu_reset_needed = 0; + int i; + struct descriptor_table dt; + + if (sregs->vcpu < 0 || sregs->vcpu >= KVM_MAX_VCPUS) + return -EINVAL; + vcpu = vcpu_load(kvm, sregs->vcpu); + if (!vcpu) + return -ENOENT; + + set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); + set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); + set_segment(vcpu, &sregs->es, VCPU_SREG_ES); + set_segment(vcpu, &sregs->fs, VCPU_SREG_FS); + set_segment(vcpu, &sregs->gs, VCPU_SREG_GS); + set_segment(vcpu, &sregs->ss, VCPU_SREG_SS); + + set_segment(vcpu, &sregs->tr, VCPU_SREG_TR); + set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); + + dt.limit = sregs->idt.limit; + dt.base = sregs->idt.base; + kvm_arch_ops->set_idt(vcpu, &dt); + dt.limit = sregs->gdt.limit; + dt.base = sregs->gdt.base; + kvm_arch_ops->set_gdt(vcpu, &dt); + + vcpu->cr2 = sregs->cr2; + mmu_reset_needed |= vcpu->cr3 != sregs->cr3; + vcpu->cr3 = sregs->cr3; + + vcpu->cr8 = sregs->cr8; + + mmu_reset_needed |= vcpu->shadow_efer != sregs->efer; +#ifdef __x86_64__ + kvm_arch_ops->set_efer(vcpu, sregs->efer); +#endif + vcpu->apic_base = sregs->apic_base; + + mmu_reset_needed |= vcpu->cr0 != sregs->cr0; + kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0); + + mmu_reset_needed |= vcpu->cr4 != sregs->cr4; + kvm_arch_ops->set_cr4(vcpu, sregs->cr4); + + if (mmu_reset_needed) + kvm_mmu_reset_context(vcpu); + + memcpy(vcpu->irq_pending, sregs->interrupt_bitmap, + sizeof vcpu->irq_pending); + vcpu->irq_summary = 0; + for (i = 0; i < NR_IRQ_WORDS; ++i) + if (vcpu->irq_pending[i]) + __set_bit(i, &vcpu->irq_summary); + + vcpu_put(vcpu); + + return 0; +} + +/* + * List of msr numbers which we expose to userspace through KVM_GET_MSRS + * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST. + */ +static u32 msrs_to_save[] = { + MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, + MSR_K6_STAR, +#ifdef __x86_64__ + MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, +#endif + MSR_IA32_TIME_STAMP_COUNTER, +}; + + +/* + * Adapt set_msr() to msr_io()'s calling convention + */ +static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) +{ + return set_msr(vcpu, index, *data); +} + +/* + * Read or write a bunch of msrs. All parameters are kernel addresses. + * + * @return number of msrs set successfully. + */ +static int __msr_io(struct kvm *kvm, struct kvm_msrs *msrs, + struct kvm_msr_entry *entries, + int (*do_msr)(struct kvm_vcpu *vcpu, + unsigned index, u64 *data)) +{ + struct kvm_vcpu *vcpu; + int i; + + if (msrs->vcpu < 0 || msrs->vcpu >= KVM_MAX_VCPUS) + return -EINVAL; + + vcpu = vcpu_load(kvm, msrs->vcpu); + if (!vcpu) + return -ENOENT; + + for (i = 0; i < msrs->nmsrs; ++i) + if (do_msr(vcpu, entries[i].index, &entries[i].data)) + break; + + vcpu_put(vcpu); + + return i; +} + +/* + * Read or write a bunch of msrs. Parameters are user addresses. + * + * @return number of msrs set successfully. + */ +static int msr_io(struct kvm *kvm, struct kvm_msrs __user *user_msrs, + int (*do_msr)(struct kvm_vcpu *vcpu, + unsigned index, u64 *data), + int writeback) +{ + struct kvm_msrs msrs; + struct kvm_msr_entry *entries; + int r, n; + unsigned size; + + r = -EFAULT; + if (copy_from_user(&msrs, user_msrs, sizeof msrs)) + goto out; + + r = -E2BIG; + if (msrs.nmsrs >= MAX_IO_MSRS) + goto out; + + r = -ENOMEM; + size = sizeof(struct kvm_msr_entry) * msrs.nmsrs; + entries = vmalloc(size); + if (!entries) + goto out; + + r = -EFAULT; + if (copy_from_user(entries, user_msrs->entries, size)) + goto out_free; + + r = n = __msr_io(kvm, &msrs, entries, do_msr); + if (r < 0) + goto out_free; + + r = -EFAULT; + if (writeback && copy_to_user(user_msrs->entries, entries, size)) + goto out_free; + + r = n; + +out_free: + vfree(entries); +out: + return r; +} + +/* + * Translate a guest virtual address to a guest physical address. + */ +static int kvm_dev_ioctl_translate(struct kvm *kvm, struct kvm_translation *tr) +{ + unsigned long vaddr = tr->linear_address; + struct kvm_vcpu *vcpu; + gpa_t gpa; + + vcpu = vcpu_load(kvm, tr->vcpu); + if (!vcpu) + return -ENOENT; + spin_lock(&kvm->lock); + gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr); + tr->physical_address = gpa; + tr->valid = gpa != UNMAPPED_GVA; + tr->writeable = 1; + tr->usermode = 0; + spin_unlock(&kvm->lock); + vcpu_put(vcpu); + + return 0; +} + +static int kvm_dev_ioctl_interrupt(struct kvm *kvm, struct kvm_interrupt *irq) +{ + struct kvm_vcpu *vcpu; + + if (irq->vcpu < 0 || irq->vcpu >= KVM_MAX_VCPUS) + return -EINVAL; + if (irq->irq < 0 || irq->irq >= 256) + return -EINVAL; + vcpu = vcpu_load(kvm, irq->vcpu); + if (!vcpu) + return -ENOENT; + + set_bit(irq->irq, vcpu->irq_pending); + set_bit(irq->irq / BITS_PER_LONG, &vcpu->irq_summary); + + vcpu_put(vcpu); + + return 0; +} + +static int kvm_dev_ioctl_debug_guest(struct kvm *kvm, + struct kvm_debug_guest *dbg) +{ + struct kvm_vcpu *vcpu; + int r; + + if (dbg->vcpu < 0 || dbg->vcpu >= KVM_MAX_VCPUS) + return -EINVAL; + vcpu = vcpu_load(kvm, dbg->vcpu); + if (!vcpu) + return -ENOENT; + + r = kvm_arch_ops->set_guest_debug(vcpu, dbg); + + vcpu_put(vcpu); + + return r; +} + +static long kvm_dev_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + struct kvm *kvm = filp->private_data; + int r = -EINVAL; + + switch (ioctl) { + case KVM_CREATE_VCPU: { + r = kvm_dev_ioctl_create_vcpu(kvm, arg); + if (r) + goto out; + break; + } + case KVM_RUN: { + struct kvm_run kvm_run; + + r = -EFAULT; + if (copy_from_user(&kvm_run, (void *)arg, sizeof kvm_run)) + goto out; + r = kvm_dev_ioctl_run(kvm, &kvm_run); + if (r < 0) + goto out; + r = -EFAULT; + if (copy_to_user((void *)arg, &kvm_run, sizeof kvm_run)) + goto out; + r = 0; + break; + } + case KVM_GET_REGS: { + struct kvm_regs kvm_regs; + + r = -EFAULT; + if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs)) + goto out; + r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user((void *)arg, &kvm_regs, sizeof kvm_regs)) + goto out; + r = 0; + break; + } + case KVM_SET_REGS: { + struct kvm_regs kvm_regs; + + r = -EFAULT; + if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs)) + goto out; + r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs); + if (r) + goto out; + r = 0; + break; + } + case KVM_GET_SREGS: { + struct kvm_sregs kvm_sregs; + + r = -EFAULT; + if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs)) + goto out; + r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user((void *)arg, &kvm_sregs, sizeof kvm_sregs)) + goto out; + r = 0; + break; + } + case KVM_SET_SREGS: { + struct kvm_sregs kvm_sregs; + + r = -EFAULT; + if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs)) + goto out; + r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs); + if (r) + goto out; + r = 0; + break; + } + case KVM_TRANSLATE: { + struct kvm_translation tr; + + r = -EFAULT; + if (copy_from_user(&tr, (void *)arg, sizeof tr)) + goto out; + r = kvm_dev_ioctl_translate(kvm, &tr); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user((void *)arg, &tr, sizeof tr)) + goto out; + r = 0; + break; + } + case KVM_INTERRUPT: { + struct kvm_interrupt irq; + + r = -EFAULT; + if (copy_from_user(&irq, (void *)arg, sizeof irq)) + goto out; + r = kvm_dev_ioctl_interrupt(kvm, &irq); + if (r) + goto out; + r = 0; + break; + } + case KVM_DEBUG_GUEST: { + struct kvm_debug_guest dbg; + + r = -EFAULT; + if (copy_from_user(&dbg, (void *)arg, sizeof dbg)) + goto out; + r = kvm_dev_ioctl_debug_guest(kvm, &dbg); + if (r) + goto out; + r = 0; + break; + } + case KVM_SET_MEMORY_REGION: { + struct kvm_memory_region kvm_mem; + + r = -EFAULT; + if (copy_from_user(&kvm_mem, (void *)arg, sizeof kvm_mem)) + goto out; + r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem); + if (r) + goto out; + break; + } + case KVM_GET_DIRTY_LOG: { + struct kvm_dirty_log log; + + r = -EFAULT; + if (copy_from_user(&log, (void *)arg, sizeof log)) + goto out; + r = kvm_dev_ioctl_get_dirty_log(kvm, &log); + if (r) + goto out; + break; + } + case KVM_GET_MSRS: + r = msr_io(kvm, (void __user *)arg, get_msr, 1); + break; + case KVM_SET_MSRS: + r = msr_io(kvm, (void __user *)arg, do_set_msr, 0); + break; + case KVM_GET_MSR_INDEX_LIST: { + struct kvm_msr_list __user *user_msr_list = (void __user *)arg; + struct kvm_msr_list msr_list; + unsigned n; + + r = -EFAULT; + if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list)) + goto out; + n = msr_list.nmsrs; + msr_list.nmsrs = ARRAY_SIZE(msrs_to_save); + if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list)) + goto out; + r = -E2BIG; + if (n < ARRAY_SIZE(msrs_to_save)) + goto out; + r = -EFAULT; + if (copy_to_user(user_msr_list->indices, &msrs_to_save, + sizeof msrs_to_save)) + goto out; + r = 0; + } + default: + ; + } +out: + return r; +} + +static struct page *kvm_dev_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type) +{ + struct kvm *kvm = vma->vm_file->private_data; + unsigned long pgoff; + struct kvm_memory_slot *slot; + struct page *page; + + *type = VM_FAULT_MINOR; + pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + slot = gfn_to_memslot(kvm, pgoff); + if (!slot) + return NOPAGE_SIGBUS; + page = gfn_to_page(slot, pgoff); + if (!page) + return NOPAGE_SIGBUS; + get_page(page); + return page; +} + +static struct vm_operations_struct kvm_dev_vm_ops = { + .nopage = kvm_dev_nopage, +}; + +static int kvm_dev_mmap(struct file *file, struct vm_area_struct *vma) +{ + vma->vm_ops = &kvm_dev_vm_ops; + return 0; +} + +static struct file_operations kvm_chardev_ops = { + .open = kvm_dev_open, + .release = kvm_dev_release, + .unlocked_ioctl = kvm_dev_ioctl, + .compat_ioctl = kvm_dev_ioctl, + .mmap = kvm_dev_mmap, +}; + +static struct miscdevice kvm_dev = { + MISC_DYNAMIC_MINOR, + "kvm", + &kvm_chardev_ops, +}; + +static int kvm_reboot(struct notifier_block *notifier, unsigned long val, + void *v) +{ + if (val == SYS_RESTART) { + /* + * Some (well, at least mine) BIOSes hang on reboot if + * in vmx root mode. + */ + printk(KERN_INFO "kvm: exiting hardware virtualization\n"); + on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + } + return NOTIFY_OK; +} + +static struct notifier_block kvm_reboot_notifier = { + .notifier_call = kvm_reboot, + .priority = 0, +}; + +static __init void kvm_init_debug(void) +{ + struct kvm_stats_debugfs_item *p; + + debugfs_dir = debugfs_create_dir("kvm", 0); + for (p = debugfs_entries; p->name; ++p) + p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir, + p->data); +} + +static void kvm_exit_debug(void) +{ + struct kvm_stats_debugfs_item *p; + + for (p = debugfs_entries; p->name; ++p) + debugfs_remove(p->dentry); + debugfs_remove(debugfs_dir); +} + +hpa_t bad_page_address; + +int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) +{ + int r; + + kvm_arch_ops = ops; + + if (!kvm_arch_ops->cpu_has_kvm_support()) { + printk(KERN_ERR "kvm: no hardware support\n"); + return -EOPNOTSUPP; + } + if (kvm_arch_ops->disabled_by_bios()) { + printk(KERN_ERR "kvm: disabled by bios\n"); + return -EOPNOTSUPP; + } + + r = kvm_arch_ops->hardware_setup(); + if (r < 0) + return r; + + on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1); + register_reboot_notifier(&kvm_reboot_notifier); + + kvm_chardev_ops.owner = module; + + r = misc_register(&kvm_dev); + if (r) { + printk (KERN_ERR "kvm: misc device register failed\n"); + goto out_free; + } + + return r; + +out_free: + unregister_reboot_notifier(&kvm_reboot_notifier); + on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + kvm_arch_ops->hardware_unsetup(); + return r; +} + +void kvm_exit_arch(void) +{ + misc_deregister(&kvm_dev); + + unregister_reboot_notifier(&kvm_reboot_notifier); + on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + kvm_arch_ops->hardware_unsetup(); +} + +static __init int kvm_init(void) +{ + static struct page *bad_page; + int r = 0; + + kvm_init_debug(); + + if ((bad_page = alloc_page(GFP_KERNEL)) == NULL) { + r = -ENOMEM; + goto out; + } + + bad_page_address = page_to_pfn(bad_page) << PAGE_SHIFT; + memset(__va(bad_page_address), 0, PAGE_SIZE); + + return r; + +out: + kvm_exit_debug(); + return r; +} + +static __exit void kvm_exit(void) +{ + kvm_exit_debug(); + __free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT)); +} + +module_init(kvm_init) +module_exit(kvm_exit) + +EXPORT_SYMBOL_GPL(kvm_init_arch); +EXPORT_SYMBOL_GPL(kvm_exit_arch); diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h new file mode 100644 index 000000000000..7d7f2aa10960 --- /dev/null +++ b/drivers/kvm/kvm_svm.h @@ -0,0 +1,44 @@ +#ifndef __KVM_SVM_H +#define __KVM_SVM_H + +#include +#include +#include + +#include "svm.h" +#include "kvm.h" + +static const u32 host_save_msrs[] = { +#ifdef __x86_64__ + MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE, + MSR_FS_BASE, MSR_GS_BASE, +#endif + MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, + MSR_IA32_DEBUGCTLMSR, /*MSR_IA32_LASTBRANCHFROMIP, + MSR_IA32_LASTBRANCHTOIP, MSR_IA32_LASTINTFROMIP,MSR_IA32_LASTINTTOIP,*/ +}; + +#define NR_HOST_SAVE_MSRS (sizeof(host_save_msrs) / sizeof(*host_save_msrs)) +#define NUM_DB_REGS 4 + +struct vcpu_svm { + struct vmcb *vmcb; + unsigned long vmcb_pa; + struct svm_cpu_data *svm_data; + uint64_t asid_generation; + + unsigned long cr0; + unsigned long cr4; + unsigned long db_regs[NUM_DB_REGS]; + + u64 next_rip; + + u64 host_msrs[NR_HOST_SAVE_MSRS]; + unsigned long host_cr2; + unsigned long host_db_regs[NUM_DB_REGS]; + unsigned long host_dr6; + unsigned long host_dr7; +}; + +#endif + diff --git a/drivers/kvm/kvm_vmx.h b/drivers/kvm/kvm_vmx.h new file mode 100644 index 000000000000..87e12d2bfa16 --- /dev/null +++ b/drivers/kvm/kvm_vmx.h @@ -0,0 +1,14 @@ +#ifndef __KVM_VMX_H +#define __KVM_VMX_H + +#ifdef __x86_64__ +/* + * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt + * mechanism (cpu bug AA24) + */ +#define NR_BAD_MSRS 2 +#else +#define NR_BAD_MSRS 0 +#endif + +#endif diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c new file mode 100644 index 000000000000..4e29d9b7211c --- /dev/null +++ b/drivers/kvm/mmu.c @@ -0,0 +1,699 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * This module enables machines with Intel VT-x extensions to run virtual + * machines without emulation or binary translation. + * + * MMU support + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Yaniv Kamay + * Avi Kivity + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ +#include +#include +#include +#include +#include +#include + +#include "vmx.h" +#include "kvm.h" + +#define pgprintk(x...) do { } while (0) + +#define ASSERT(x) \ + if (!(x)) { \ + printk(KERN_WARNING "assertion failed %s:%d: %s\n", \ + __FILE__, __LINE__, #x); \ + } + +#define PT64_ENT_PER_PAGE 512 +#define PT32_ENT_PER_PAGE 1024 + +#define PT_WRITABLE_SHIFT 1 + +#define PT_PRESENT_MASK (1ULL << 0) +#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT) +#define PT_USER_MASK (1ULL << 2) +#define PT_PWT_MASK (1ULL << 3) +#define PT_PCD_MASK (1ULL << 4) +#define PT_ACCESSED_MASK (1ULL << 5) +#define PT_DIRTY_MASK (1ULL << 6) +#define PT_PAGE_SIZE_MASK (1ULL << 7) +#define PT_PAT_MASK (1ULL << 7) +#define PT_GLOBAL_MASK (1ULL << 8) +#define PT64_NX_MASK (1ULL << 63) + +#define PT_PAT_SHIFT 7 +#define PT_DIR_PAT_SHIFT 12 +#define PT_DIR_PAT_MASK (1ULL << PT_DIR_PAT_SHIFT) + +#define PT32_DIR_PSE36_SIZE 4 +#define PT32_DIR_PSE36_SHIFT 13 +#define PT32_DIR_PSE36_MASK (((1ULL << PT32_DIR_PSE36_SIZE) - 1) << PT32_DIR_PSE36_SHIFT) + + +#define PT32_PTE_COPY_MASK \ + (PT_PRESENT_MASK | PT_PWT_MASK | PT_PCD_MASK | \ + PT_ACCESSED_MASK | PT_DIRTY_MASK | PT_PAT_MASK | \ + PT_GLOBAL_MASK ) + +#define PT32_NON_PTE_COPY_MASK \ + (PT_PRESENT_MASK | PT_PWT_MASK | PT_PCD_MASK | \ + PT_ACCESSED_MASK | PT_DIRTY_MASK) + + +#define PT64_PTE_COPY_MASK \ + (PT64_NX_MASK | PT32_PTE_COPY_MASK) + +#define PT64_NON_PTE_COPY_MASK \ + (PT64_NX_MASK | PT32_NON_PTE_COPY_MASK) + + + +#define PT_FIRST_AVAIL_BITS_SHIFT 9 +#define PT64_SECOND_AVAIL_BITS_SHIFT 52 + +#define PT_SHADOW_PS_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT) +#define PT_SHADOW_IO_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT) + +#define PT_SHADOW_WRITABLE_SHIFT (PT_FIRST_AVAIL_BITS_SHIFT + 1) +#define PT_SHADOW_WRITABLE_MASK (1ULL << PT_SHADOW_WRITABLE_SHIFT) + +#define PT_SHADOW_USER_SHIFT (PT_SHADOW_WRITABLE_SHIFT + 1) +#define PT_SHADOW_USER_MASK (1ULL << (PT_SHADOW_USER_SHIFT)) + +#define PT_SHADOW_BITS_OFFSET (PT_SHADOW_WRITABLE_SHIFT - PT_WRITABLE_SHIFT) + +#define VALID_PAGE(x) ((x) != INVALID_PAGE) + +#define PT64_LEVEL_BITS 9 + +#define PT64_LEVEL_SHIFT(level) \ + ( PAGE_SHIFT + (level - 1) * PT64_LEVEL_BITS ) + +#define PT64_LEVEL_MASK(level) \ + (((1ULL << PT64_LEVEL_BITS) - 1) << PT64_LEVEL_SHIFT(level)) + +#define PT64_INDEX(address, level)\ + (((address) >> PT64_LEVEL_SHIFT(level)) & ((1 << PT64_LEVEL_BITS) - 1)) + + +#define PT32_LEVEL_BITS 10 + +#define PT32_LEVEL_SHIFT(level) \ + ( PAGE_SHIFT + (level - 1) * PT32_LEVEL_BITS ) + +#define PT32_LEVEL_MASK(level) \ + (((1ULL << PT32_LEVEL_BITS) - 1) << PT32_LEVEL_SHIFT(level)) + +#define PT32_INDEX(address, level)\ + (((address) >> PT32_LEVEL_SHIFT(level)) & ((1 << PT32_LEVEL_BITS) - 1)) + + +#define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & PAGE_MASK) +#define PT64_DIR_BASE_ADDR_MASK \ + (PT64_BASE_ADDR_MASK & ~((1ULL << (PAGE_SHIFT + PT64_LEVEL_BITS)) - 1)) + +#define PT32_BASE_ADDR_MASK PAGE_MASK +#define PT32_DIR_BASE_ADDR_MASK \ + (PAGE_MASK & ~((1ULL << (PAGE_SHIFT + PT32_LEVEL_BITS)) - 1)) + + +#define PFERR_PRESENT_MASK (1U << 0) +#define PFERR_WRITE_MASK (1U << 1) +#define PFERR_USER_MASK (1U << 2) + +#define PT64_ROOT_LEVEL 4 +#define PT32_ROOT_LEVEL 2 +#define PT32E_ROOT_LEVEL 3 + +#define PT_DIRECTORY_LEVEL 2 +#define PT_PAGE_TABLE_LEVEL 1 + +static int is_write_protection(struct kvm_vcpu *vcpu) +{ + return vcpu->cr0 & CR0_WP_MASK; +} + +static int is_cpuid_PSE36(void) +{ + return 1; +} + +static int is_present_pte(unsigned long pte) +{ + return pte & PT_PRESENT_MASK; +} + +static int is_writeble_pte(unsigned long pte) +{ + return pte & PT_WRITABLE_MASK; +} + +static int is_io_pte(unsigned long pte) +{ + return pte & PT_SHADOW_IO_MARK; +} + +static void kvm_mmu_free_page(struct kvm_vcpu *vcpu, hpa_t page_hpa) +{ + struct kvm_mmu_page *page_head = page_header(page_hpa); + + list_del(&page_head->link); + page_head->page_hpa = page_hpa; + list_add(&page_head->link, &vcpu->free_pages); +} + +static int is_empty_shadow_page(hpa_t page_hpa) +{ + u32 *pos; + u32 *end; + for (pos = __va(page_hpa), end = pos + PAGE_SIZE / sizeof(u32); + pos != end; pos++) + if (*pos != 0) + return 0; + return 1; +} + +static hpa_t kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, u64 *parent_pte) +{ + struct kvm_mmu_page *page; + + if (list_empty(&vcpu->free_pages)) + return INVALID_PAGE; + + page = list_entry(vcpu->free_pages.next, struct kvm_mmu_page, link); + list_del(&page->link); + list_add(&page->link, &vcpu->kvm->active_mmu_pages); + ASSERT(is_empty_shadow_page(page->page_hpa)); + page->slot_bitmap = 0; + page->global = 1; + page->parent_pte = parent_pte; + return page->page_hpa; +} + +static void page_header_update_slot(struct kvm *kvm, void *pte, gpa_t gpa) +{ + int slot = memslot_id(kvm, gfn_to_memslot(kvm, gpa >> PAGE_SHIFT)); + struct kvm_mmu_page *page_head = page_header(__pa(pte)); + + __set_bit(slot, &page_head->slot_bitmap); +} + +hpa_t safe_gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa) +{ + hpa_t hpa = gpa_to_hpa(vcpu, gpa); + + return is_error_hpa(hpa) ? bad_page_address | (gpa & ~PAGE_MASK): hpa; +} + +hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa) +{ + struct kvm_memory_slot *slot; + struct page *page; + + ASSERT((gpa & HPA_ERR_MASK) == 0); + slot = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT); + if (!slot) + return gpa | HPA_ERR_MASK; + page = gfn_to_page(slot, gpa >> PAGE_SHIFT); + return ((hpa_t)page_to_pfn(page) << PAGE_SHIFT) + | (gpa & (PAGE_SIZE-1)); +} + +hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva) +{ + gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva); + + if (gpa == UNMAPPED_GVA) + return UNMAPPED_GVA; + return gpa_to_hpa(vcpu, gpa); +} + + +static void release_pt_page_64(struct kvm_vcpu *vcpu, hpa_t page_hpa, + int level) +{ + ASSERT(vcpu); + ASSERT(VALID_PAGE(page_hpa)); + ASSERT(level <= PT64_ROOT_LEVEL && level > 0); + + if (level == 1) + memset(__va(page_hpa), 0, PAGE_SIZE); + else { + u64 *pos; + u64 *end; + + for (pos = __va(page_hpa), end = pos + PT64_ENT_PER_PAGE; + pos != end; pos++) { + u64 current_ent = *pos; + + *pos = 0; + if (is_present_pte(current_ent)) + release_pt_page_64(vcpu, + current_ent & + PT64_BASE_ADDR_MASK, + level - 1); + } + } + kvm_mmu_free_page(vcpu, page_hpa); +} + +static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) +{ +} + +static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p) +{ + int level = PT32E_ROOT_LEVEL; + hpa_t table_addr = vcpu->mmu.root_hpa; + + for (; ; level--) { + u32 index = PT64_INDEX(v, level); + u64 *table; + + ASSERT(VALID_PAGE(table_addr)); + table = __va(table_addr); + + if (level == 1) { + mark_page_dirty(vcpu->kvm, v >> PAGE_SHIFT); + page_header_update_slot(vcpu->kvm, table, v); + table[index] = p | PT_PRESENT_MASK | PT_WRITABLE_MASK | + PT_USER_MASK; + return 0; + } + + if (table[index] == 0) { + hpa_t new_table = kvm_mmu_alloc_page(vcpu, + &table[index]); + + if (!VALID_PAGE(new_table)) { + pgprintk("nonpaging_map: ENOMEM\n"); + return -ENOMEM; + } + + if (level == PT32E_ROOT_LEVEL) + table[index] = new_table | PT_PRESENT_MASK; + else + table[index] = new_table | PT_PRESENT_MASK | + PT_WRITABLE_MASK | PT_USER_MASK; + } + table_addr = table[index] & PT64_BASE_ADDR_MASK; + } +} + +static void nonpaging_flush(struct kvm_vcpu *vcpu) +{ + hpa_t root = vcpu->mmu.root_hpa; + + ++kvm_stat.tlb_flush; + pgprintk("nonpaging_flush\n"); + ASSERT(VALID_PAGE(root)); + release_pt_page_64(vcpu, root, vcpu->mmu.shadow_root_level); + root = kvm_mmu_alloc_page(vcpu, NULL); + ASSERT(VALID_PAGE(root)); + vcpu->mmu.root_hpa = root; + if (is_paging(vcpu)) + root |= (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)); + kvm_arch_ops->set_cr3(vcpu, root); + kvm_arch_ops->tlb_flush(vcpu); +} + +static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr) +{ + return vaddr; +} + +static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, + u32 error_code) +{ + int ret; + gpa_t addr = gva; + + ASSERT(vcpu); + ASSERT(VALID_PAGE(vcpu->mmu.root_hpa)); + + for (;;) { + hpa_t paddr; + + paddr = gpa_to_hpa(vcpu , addr & PT64_BASE_ADDR_MASK); + + if (is_error_hpa(paddr)) + return 1; + + ret = nonpaging_map(vcpu, addr & PAGE_MASK, paddr); + if (ret) { + nonpaging_flush(vcpu); + continue; + } + break; + } + return ret; +} + +static void nonpaging_inval_page(struct kvm_vcpu *vcpu, gva_t addr) +{ +} + +static void nonpaging_free(struct kvm_vcpu *vcpu) +{ + hpa_t root; + + ASSERT(vcpu); + root = vcpu->mmu.root_hpa; + if (VALID_PAGE(root)) + release_pt_page_64(vcpu, root, vcpu->mmu.shadow_root_level); + vcpu->mmu.root_hpa = INVALID_PAGE; +} + +static int nonpaging_init_context(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu *context = &vcpu->mmu; + + context->new_cr3 = nonpaging_new_cr3; + context->page_fault = nonpaging_page_fault; + context->inval_page = nonpaging_inval_page; + context->gva_to_gpa = nonpaging_gva_to_gpa; + context->free = nonpaging_free; + context->root_level = PT32E_ROOT_LEVEL; + context->shadow_root_level = PT32E_ROOT_LEVEL; + context->root_hpa = kvm_mmu_alloc_page(vcpu, NULL); + ASSERT(VALID_PAGE(context->root_hpa)); + kvm_arch_ops->set_cr3(vcpu, context->root_hpa); + return 0; +} + + +static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu_page *page, *npage; + + list_for_each_entry_safe(page, npage, &vcpu->kvm->active_mmu_pages, + link) { + if (page->global) + continue; + + if (!page->parent_pte) + continue; + + *page->parent_pte = 0; + release_pt_page_64(vcpu, page->page_hpa, 1); + } + ++kvm_stat.tlb_flush; + kvm_arch_ops->tlb_flush(vcpu); +} + +static void paging_new_cr3(struct kvm_vcpu *vcpu) +{ + kvm_mmu_flush_tlb(vcpu); +} + +static void mark_pagetable_nonglobal(void *shadow_pte) +{ + page_header(__pa(shadow_pte))->global = 0; +} + +static inline void set_pte_common(struct kvm_vcpu *vcpu, + u64 *shadow_pte, + gpa_t gaddr, + int dirty, + u64 access_bits) +{ + hpa_t paddr; + + *shadow_pte |= access_bits << PT_SHADOW_BITS_OFFSET; + if (!dirty) + access_bits &= ~PT_WRITABLE_MASK; + + if (access_bits & PT_WRITABLE_MASK) + mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT); + + *shadow_pte |= access_bits; + + paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK); + + if (!(*shadow_pte & PT_GLOBAL_MASK)) + mark_pagetable_nonglobal(shadow_pte); + + if (is_error_hpa(paddr)) { + *shadow_pte |= gaddr; + *shadow_pte |= PT_SHADOW_IO_MARK; + *shadow_pte &= ~PT_PRESENT_MASK; + } else { + *shadow_pte |= paddr; + page_header_update_slot(vcpu->kvm, shadow_pte, gaddr); + } +} + +static void inject_page_fault(struct kvm_vcpu *vcpu, + u64 addr, + u32 err_code) +{ + kvm_arch_ops->inject_page_fault(vcpu, addr, err_code); +} + +static inline int fix_read_pf(u64 *shadow_ent) +{ + if ((*shadow_ent & PT_SHADOW_USER_MASK) && + !(*shadow_ent & PT_USER_MASK)) { + /* + * If supervisor write protect is disabled, we shadow kernel + * pages as user pages so we can trap the write access. + */ + *shadow_ent |= PT_USER_MASK; + *shadow_ent &= ~PT_WRITABLE_MASK; + + return 1; + + } + return 0; +} + +static int may_access(u64 pte, int write, int user) +{ + + if (user && !(pte & PT_USER_MASK)) + return 0; + if (write && !(pte & PT_WRITABLE_MASK)) + return 0; + return 1; +} + +/* + * Remove a shadow pte. + */ +static void paging_inval_page(struct kvm_vcpu *vcpu, gva_t addr) +{ + hpa_t page_addr = vcpu->mmu.root_hpa; + int level = vcpu->mmu.shadow_root_level; + + ++kvm_stat.invlpg; + + for (; ; level--) { + u32 index = PT64_INDEX(addr, level); + u64 *table = __va(page_addr); + + if (level == PT_PAGE_TABLE_LEVEL ) { + table[index] = 0; + return; + } + + if (!is_present_pte(table[index])) + return; + + page_addr = table[index] & PT64_BASE_ADDR_MASK; + + if (level == PT_DIRECTORY_LEVEL && + (table[index] & PT_SHADOW_PS_MARK)) { + table[index] = 0; + release_pt_page_64(vcpu, page_addr, PT_PAGE_TABLE_LEVEL); + + kvm_arch_ops->tlb_flush(vcpu); + return; + } + } +} + +static void paging_free(struct kvm_vcpu *vcpu) +{ + nonpaging_free(vcpu); +} + +#define PTTYPE 64 +#include "paging_tmpl.h" +#undef PTTYPE + +#define PTTYPE 32 +#include "paging_tmpl.h" +#undef PTTYPE + +static int paging64_init_context(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu *context = &vcpu->mmu; + + ASSERT(is_pae(vcpu)); + context->new_cr3 = paging_new_cr3; + context->page_fault = paging64_page_fault; + context->inval_page = paging_inval_page; + context->gva_to_gpa = paging64_gva_to_gpa; + context->free = paging_free; + context->root_level = PT64_ROOT_LEVEL; + context->shadow_root_level = PT64_ROOT_LEVEL; + context->root_hpa = kvm_mmu_alloc_page(vcpu, NULL); + ASSERT(VALID_PAGE(context->root_hpa)); + kvm_arch_ops->set_cr3(vcpu, context->root_hpa | + (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK))); + return 0; +} + +static int paging32_init_context(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu *context = &vcpu->mmu; + + context->new_cr3 = paging_new_cr3; + context->page_fault = paging32_page_fault; + context->inval_page = paging_inval_page; + context->gva_to_gpa = paging32_gva_to_gpa; + context->free = paging_free; + context->root_level = PT32_ROOT_LEVEL; + context->shadow_root_level = PT32E_ROOT_LEVEL; + context->root_hpa = kvm_mmu_alloc_page(vcpu, NULL); + ASSERT(VALID_PAGE(context->root_hpa)); + kvm_arch_ops->set_cr3(vcpu, context->root_hpa | + (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK))); + return 0; +} + +static int paging32E_init_context(struct kvm_vcpu *vcpu) +{ + int ret; + + if ((ret = paging64_init_context(vcpu))) + return ret; + + vcpu->mmu.root_level = PT32E_ROOT_LEVEL; + vcpu->mmu.shadow_root_level = PT32E_ROOT_LEVEL; + return 0; +} + +static int init_kvm_mmu(struct kvm_vcpu *vcpu) +{ + ASSERT(vcpu); + ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa)); + + if (!is_paging(vcpu)) + return nonpaging_init_context(vcpu); + else if (kvm_arch_ops->is_long_mode(vcpu)) + return paging64_init_context(vcpu); + else if (is_pae(vcpu)) + return paging32E_init_context(vcpu); + else + return paging32_init_context(vcpu); +} + +static void destroy_kvm_mmu(struct kvm_vcpu *vcpu) +{ + ASSERT(vcpu); + if (VALID_PAGE(vcpu->mmu.root_hpa)) { + vcpu->mmu.free(vcpu); + vcpu->mmu.root_hpa = INVALID_PAGE; + } +} + +int kvm_mmu_reset_context(struct kvm_vcpu *vcpu) +{ + destroy_kvm_mmu(vcpu); + return init_kvm_mmu(vcpu); +} + +static void free_mmu_pages(struct kvm_vcpu *vcpu) +{ + while (!list_empty(&vcpu->free_pages)) { + struct kvm_mmu_page *page; + + page = list_entry(vcpu->free_pages.next, + struct kvm_mmu_page, link); + list_del(&page->link); + __free_page(pfn_to_page(page->page_hpa >> PAGE_SHIFT)); + page->page_hpa = INVALID_PAGE; + } +} + +static int alloc_mmu_pages(struct kvm_vcpu *vcpu) +{ + int i; + + ASSERT(vcpu); + + for (i = 0; i < KVM_NUM_MMU_PAGES; i++) { + struct page *page; + struct kvm_mmu_page *page_header = &vcpu->page_header_buf[i]; + + INIT_LIST_HEAD(&page_header->link); + if ((page = alloc_page(GFP_KVM_MMU)) == NULL) + goto error_1; + page->private = (unsigned long)page_header; + page_header->page_hpa = (hpa_t)page_to_pfn(page) << PAGE_SHIFT; + memset(__va(page_header->page_hpa), 0, PAGE_SIZE); + list_add(&page_header->link, &vcpu->free_pages); + } + return 0; + +error_1: + free_mmu_pages(vcpu); + return -ENOMEM; +} + +int kvm_mmu_init(struct kvm_vcpu *vcpu) +{ + int r; + + ASSERT(vcpu); + ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa)); + ASSERT(list_empty(&vcpu->free_pages)); + + if ((r = alloc_mmu_pages(vcpu))) + return r; + + if ((r = init_kvm_mmu(vcpu))) { + free_mmu_pages(vcpu); + return r; + } + return 0; +} + +void kvm_mmu_destroy(struct kvm_vcpu *vcpu) +{ + ASSERT(vcpu); + + destroy_kvm_mmu(vcpu); + free_mmu_pages(vcpu); +} + +void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) +{ + struct kvm_mmu_page *page; + + list_for_each_entry(page, &kvm->active_mmu_pages, link) { + int i; + u64 *pt; + + if (!test_bit(slot, &page->slot_bitmap)) + continue; + + pt = __va(page->page_hpa); + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) + /* avoid RMW */ + if (pt[i] & PT_WRITABLE_MASK) + pt[i] &= ~PT_WRITABLE_MASK; + + } +} diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h new file mode 100644 index 000000000000..765c2e1a048e --- /dev/null +++ b/drivers/kvm/paging_tmpl.h @@ -0,0 +1,397 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * This module enables machines with Intel VT-x extensions to run virtual + * machines without emulation or binary translation. + * + * MMU support + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Yaniv Kamay + * Avi Kivity + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +/* + * We need the mmu code to access both 32-bit and 64-bit guest ptes, + * so the code in this file is compiled twice, once per pte size. + */ + +#if PTTYPE == 64 + #define pt_element_t u64 + #define guest_walker guest_walker64 + #define FNAME(name) paging##64_##name + #define PT_BASE_ADDR_MASK PT64_BASE_ADDR_MASK + #define PT_DIR_BASE_ADDR_MASK PT64_DIR_BASE_ADDR_MASK + #define PT_INDEX(addr, level) PT64_INDEX(addr, level) + #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) + #define PT_LEVEL_MASK(level) PT64_LEVEL_MASK(level) + #define PT_PTE_COPY_MASK PT64_PTE_COPY_MASK + #define PT_NON_PTE_COPY_MASK PT64_NON_PTE_COPY_MASK +#elif PTTYPE == 32 + #define pt_element_t u32 + #define guest_walker guest_walker32 + #define FNAME(name) paging##32_##name + #define PT_BASE_ADDR_MASK PT32_BASE_ADDR_MASK + #define PT_DIR_BASE_ADDR_MASK PT32_DIR_BASE_ADDR_MASK + #define PT_INDEX(addr, level) PT32_INDEX(addr, level) + #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) + #define PT_LEVEL_MASK(level) PT32_LEVEL_MASK(level) + #define PT_PTE_COPY_MASK PT32_PTE_COPY_MASK + #define PT_NON_PTE_COPY_MASK PT32_NON_PTE_COPY_MASK +#else + #error Invalid PTTYPE value +#endif + +/* + * The guest_walker structure emulates the behavior of the hardware page + * table walker. + */ +struct guest_walker { + int level; + pt_element_t *table; + pt_element_t inherited_ar; +}; + +static void FNAME(init_walker)(struct guest_walker *walker, + struct kvm_vcpu *vcpu) +{ + hpa_t hpa; + struct kvm_memory_slot *slot; + + walker->level = vcpu->mmu.root_level; + slot = gfn_to_memslot(vcpu->kvm, + (vcpu->cr3 & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT); + hpa = safe_gpa_to_hpa(vcpu, vcpu->cr3 & PT64_BASE_ADDR_MASK); + walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0); + + ASSERT((!kvm_arch_ops->is_long_mode(vcpu) && is_pae(vcpu)) || + (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0); + + walker->table = (pt_element_t *)( (unsigned long)walker->table | + (unsigned long)(vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) ); + walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK; +} + +static void FNAME(release_walker)(struct guest_walker *walker) +{ + kunmap_atomic(walker->table, KM_USER0); +} + +static void FNAME(set_pte)(struct kvm_vcpu *vcpu, u64 guest_pte, + u64 *shadow_pte, u64 access_bits) +{ + ASSERT(*shadow_pte == 0); + access_bits &= guest_pte; + *shadow_pte = (guest_pte & PT_PTE_COPY_MASK); + set_pte_common(vcpu, shadow_pte, guest_pte & PT_BASE_ADDR_MASK, + guest_pte & PT_DIRTY_MASK, access_bits); +} + +static void FNAME(set_pde)(struct kvm_vcpu *vcpu, u64 guest_pde, + u64 *shadow_pte, u64 access_bits, + int index) +{ + gpa_t gaddr; + + ASSERT(*shadow_pte == 0); + access_bits &= guest_pde; + gaddr = (guest_pde & PT_DIR_BASE_ADDR_MASK) + PAGE_SIZE * index; + if (PTTYPE == 32 && is_cpuid_PSE36()) + gaddr |= (guest_pde & PT32_DIR_PSE36_MASK) << + (32 - PT32_DIR_PSE36_SHIFT); + *shadow_pte = (guest_pde & (PT_NON_PTE_COPY_MASK | PT_GLOBAL_MASK)) | + ((guest_pde & PT_DIR_PAT_MASK) >> + (PT_DIR_PAT_SHIFT - PT_PAT_SHIFT)); + set_pte_common(vcpu, shadow_pte, gaddr, + guest_pde & PT_DIRTY_MASK, access_bits); +} + +/* + * Fetch a guest pte from a specific level in the paging hierarchy. + */ +static pt_element_t *FNAME(fetch_guest)(struct kvm_vcpu *vcpu, + struct guest_walker *walker, + int level, + gva_t addr) +{ + + ASSERT(level > 0 && level <= walker->level); + + for (;;) { + int index = PT_INDEX(addr, walker->level); + hpa_t paddr; + + ASSERT(((unsigned long)walker->table & PAGE_MASK) == + ((unsigned long)&walker->table[index] & PAGE_MASK)); + if (level == walker->level || + !is_present_pte(walker->table[index]) || + (walker->level == PT_DIRECTORY_LEVEL && + (walker->table[index] & PT_PAGE_SIZE_MASK) && + (PTTYPE == 64 || is_pse(vcpu)))) + return &walker->table[index]; + if (walker->level != 3 || kvm_arch_ops->is_long_mode(vcpu)) + walker->inherited_ar &= walker->table[index]; + paddr = safe_gpa_to_hpa(vcpu, walker->table[index] & PT_BASE_ADDR_MASK); + kunmap_atomic(walker->table, KM_USER0); + walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT), + KM_USER0); + --walker->level; + } +} + +/* + * Fetch a shadow pte for a specific level in the paging hierarchy. + */ +static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, + struct guest_walker *walker) +{ + hpa_t shadow_addr; + int level; + u64 *prev_shadow_ent = NULL; + + shadow_addr = vcpu->mmu.root_hpa; + level = vcpu->mmu.shadow_root_level; + + for (; ; level--) { + u32 index = SHADOW_PT_INDEX(addr, level); + u64 *shadow_ent = ((u64 *)__va(shadow_addr)) + index; + pt_element_t *guest_ent; + + if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) { + if (level == PT_PAGE_TABLE_LEVEL) + return shadow_ent; + shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK; + prev_shadow_ent = shadow_ent; + continue; + } + + if (PTTYPE == 32 && level > PT32_ROOT_LEVEL) { + ASSERT(level == PT32E_ROOT_LEVEL); + guest_ent = FNAME(fetch_guest)(vcpu, walker, + PT32_ROOT_LEVEL, addr); + } else + guest_ent = FNAME(fetch_guest)(vcpu, walker, + level, addr); + + if (!is_present_pte(*guest_ent)) + return NULL; + + /* Don't set accessed bit on PAE PDPTRs */ + if (vcpu->mmu.root_level != 3 || walker->level != 3) + *guest_ent |= PT_ACCESSED_MASK; + + if (level == PT_PAGE_TABLE_LEVEL) { + + if (walker->level == PT_DIRECTORY_LEVEL) { + if (prev_shadow_ent) + *prev_shadow_ent |= PT_SHADOW_PS_MARK; + FNAME(set_pde)(vcpu, *guest_ent, shadow_ent, + walker->inherited_ar, + PT_INDEX(addr, PT_PAGE_TABLE_LEVEL)); + } else { + ASSERT(walker->level == PT_PAGE_TABLE_LEVEL); + FNAME(set_pte)(vcpu, *guest_ent, shadow_ent, walker->inherited_ar); + } + return shadow_ent; + } + + shadow_addr = kvm_mmu_alloc_page(vcpu, shadow_ent); + if (!VALID_PAGE(shadow_addr)) + return ERR_PTR(-ENOMEM); + if (!kvm_arch_ops->is_long_mode(vcpu) && level == 3) + *shadow_ent = shadow_addr | + (*guest_ent & (PT_PRESENT_MASK | PT_PWT_MASK | PT_PCD_MASK)); + else { + *shadow_ent = shadow_addr | + (*guest_ent & PT_NON_PTE_COPY_MASK); + *shadow_ent |= (PT_WRITABLE_MASK | PT_USER_MASK); + } + prev_shadow_ent = shadow_ent; + } +} + +/* + * The guest faulted for write. We need to + * + * - check write permissions + * - update the guest pte dirty bit + * - update our own dirty page tracking structures + */ +static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu, + u64 *shadow_ent, + struct guest_walker *walker, + gva_t addr, + int user) +{ + pt_element_t *guest_ent; + int writable_shadow; + gfn_t gfn; + + if (is_writeble_pte(*shadow_ent)) + return 0; + + writable_shadow = *shadow_ent & PT_SHADOW_WRITABLE_MASK; + if (user) { + /* + * User mode access. Fail if it's a kernel page or a read-only + * page. + */ + if (!(*shadow_ent & PT_SHADOW_USER_MASK) || !writable_shadow) + return 0; + ASSERT(*shadow_ent & PT_USER_MASK); + } else + /* + * Kernel mode access. Fail if it's a read-only page and + * supervisor write protection is enabled. + */ + if (!writable_shadow) { + if (is_write_protection(vcpu)) + return 0; + *shadow_ent &= ~PT_USER_MASK; + } + + guest_ent = FNAME(fetch_guest)(vcpu, walker, PT_PAGE_TABLE_LEVEL, addr); + + if (!is_present_pte(*guest_ent)) { + *shadow_ent = 0; + return 0; + } + + gfn = (*guest_ent & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; + mark_page_dirty(vcpu->kvm, gfn); + *shadow_ent |= PT_WRITABLE_MASK; + *guest_ent |= PT_DIRTY_MASK; + + return 1; +} + +/* + * Page fault handler. There are several causes for a page fault: + * - there is no shadow pte for the guest pte + * - write access through a shadow pte marked read only so that we can set + * the dirty bit + * - write access to a shadow pte marked read only so we can update the page + * dirty bitmap, when userspace requests it + * - mmio access; in this case we will never install a present shadow pte + * - normal guest page fault due to the guest pte marked not present, not + * writable, or not executable + * + * Returns: 1 if we need to emulate the instruction, 0 otherwise + */ +static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, + u32 error_code) +{ + int write_fault = error_code & PFERR_WRITE_MASK; + int pte_present = error_code & PFERR_PRESENT_MASK; + int user_fault = error_code & PFERR_USER_MASK; + struct guest_walker walker; + u64 *shadow_pte; + int fixed; + + /* + * Look up the shadow pte for the faulting address. + */ + for (;;) { + FNAME(init_walker)(&walker, vcpu); + shadow_pte = FNAME(fetch)(vcpu, addr, &walker); + if (IS_ERR(shadow_pte)) { /* must be -ENOMEM */ + nonpaging_flush(vcpu); + FNAME(release_walker)(&walker); + continue; + } + break; + } + + /* + * The page is not mapped by the guest. Let the guest handle it. + */ + if (!shadow_pte) { + inject_page_fault(vcpu, addr, error_code); + FNAME(release_walker)(&walker); + return 0; + } + + /* + * Update the shadow pte. + */ + if (write_fault) + fixed = FNAME(fix_write_pf)(vcpu, shadow_pte, &walker, addr, + user_fault); + else + fixed = fix_read_pf(shadow_pte); + + FNAME(release_walker)(&walker); + + /* + * mmio: emulate if accessible, otherwise its a guest fault. + */ + if (is_io_pte(*shadow_pte)) { + if (may_access(*shadow_pte, write_fault, user_fault)) + return 1; + pgprintk("%s: io work, no access\n", __FUNCTION__); + inject_page_fault(vcpu, addr, + error_code | PFERR_PRESENT_MASK); + return 0; + } + + /* + * pte not present, guest page fault. + */ + if (pte_present && !fixed) { + inject_page_fault(vcpu, addr, error_code); + return 0; + } + + ++kvm_stat.pf_fixed; + + return 0; +} + +static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) +{ + struct guest_walker walker; + pt_element_t guest_pte; + gpa_t gpa; + + FNAME(init_walker)(&walker, vcpu); + guest_pte = *FNAME(fetch_guest)(vcpu, &walker, PT_PAGE_TABLE_LEVEL, + vaddr); + FNAME(release_walker)(&walker); + + if (!is_present_pte(guest_pte)) + return UNMAPPED_GVA; + + if (walker.level == PT_DIRECTORY_LEVEL) { + ASSERT((guest_pte & PT_PAGE_SIZE_MASK)); + ASSERT(PTTYPE == 64 || is_pse(vcpu)); + + gpa = (guest_pte & PT_DIR_BASE_ADDR_MASK) | (vaddr & + (PT_LEVEL_MASK(PT_PAGE_TABLE_LEVEL) | ~PAGE_MASK)); + + if (PTTYPE == 32 && is_cpuid_PSE36()) + gpa |= (guest_pte & PT32_DIR_PSE36_MASK) << + (32 - PT32_DIR_PSE36_SHIFT); + } else { + gpa = (guest_pte & PT_BASE_ADDR_MASK); + gpa |= (vaddr & ~PAGE_MASK); + } + + return gpa; +} + +#undef pt_element_t +#undef guest_walker +#undef FNAME +#undef PT_BASE_ADDR_MASK +#undef PT_INDEX +#undef SHADOW_PT_INDEX +#undef PT_LEVEL_MASK +#undef PT_PTE_COPY_MASK +#undef PT_NON_PTE_COPY_MASK +#undef PT_DIR_BASE_ADDR_MASK diff --git a/drivers/kvm/segment_descriptor.h b/drivers/kvm/segment_descriptor.h new file mode 100644 index 000000000000..71fdf458619a --- /dev/null +++ b/drivers/kvm/segment_descriptor.h @@ -0,0 +1,17 @@ +struct segment_descriptor { + u16 limit_low; + u16 base_low; + u8 base_mid; + u8 type : 4; + u8 system : 1; + u8 dpl : 2; + u8 present : 1; + u8 limit_high : 4; + u8 avl : 1; + u8 long_mode : 1; + u8 default_op : 1; + u8 granularity : 1; + u8 base_high; +} __attribute__((packed)); + + diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c new file mode 100644 index 000000000000..a33a89c68138 --- /dev/null +++ b/drivers/kvm/svm.c @@ -0,0 +1,1677 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * AMD SVM support + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Yaniv Kamay + * Avi Kivity + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include +#include +#include +#include + +#include "kvm_svm.h" +#include "x86_emulate.h" + +MODULE_AUTHOR("Qumranet"); +MODULE_LICENSE("GPL"); + +#define IOPM_ALLOC_ORDER 2 +#define MSRPM_ALLOC_ORDER 1 + +#define DB_VECTOR 1 +#define UD_VECTOR 6 +#define GP_VECTOR 13 + +#define DR7_GD_MASK (1 << 13) +#define DR6_BD_MASK (1 << 13) +#define CR4_DE_MASK (1UL << 3) + +#define SEG_TYPE_LDT 2 +#define SEG_TYPE_BUSY_TSS16 3 + +#define KVM_EFER_LMA (1 << 10) +#define KVM_EFER_LME (1 << 8) + +unsigned long iopm_base; +unsigned long msrpm_base; + +struct kvm_ldttss_desc { + u16 limit0; + u16 base0; + unsigned base1 : 8, type : 5, dpl : 2, p : 1; + unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8; + u32 base3; + u32 zero1; +} __attribute__((packed)); + +struct svm_cpu_data { + int cpu; + + uint64_t asid_generation; + uint32_t max_asid; + uint32_t next_asid; + struct kvm_ldttss_desc *tss_desc; + + struct page *save_area; +}; + +static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data); + +struct svm_init_data { + int cpu; + int r; +}; + +static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000}; + +#define NUM_MSR_MAPS (sizeof(msrpm_ranges) / sizeof(*msrpm_ranges)) +#define MSRS_RANGE_SIZE 2048 +#define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2) + +#define MAX_INST_SIZE 15 + +static unsigned get_addr_size(struct kvm_vcpu *vcpu) +{ + struct vmcb_save_area *sa = &vcpu->svm->vmcb->save; + u16 cs_attrib; + + if (!(sa->cr0 & CR0_PE_MASK) || (sa->rflags & X86_EFLAGS_VM)) + return 2; + + cs_attrib = sa->cs.attrib; + + return (cs_attrib & SVM_SELECTOR_L_MASK) ? 8 : + (cs_attrib & SVM_SELECTOR_DB_MASK) ? 4 : 2; +} + +static inline u8 pop_irq(struct kvm_vcpu *vcpu) +{ + int word_index = __ffs(vcpu->irq_summary); + int bit_index = __ffs(vcpu->irq_pending[word_index]); + int irq = word_index * BITS_PER_LONG + bit_index; + + clear_bit(bit_index, &vcpu->irq_pending[word_index]); + if (!vcpu->irq_pending[word_index]) + clear_bit(word_index, &vcpu->irq_summary); + return irq; +} + +static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq) +{ + set_bit(irq, vcpu->irq_pending); + set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary); +} + +static inline void clgi(void) +{ + asm volatile (SVM_CLGI); +} + +static inline void stgi(void) +{ + asm volatile (SVM_STGI); +} + +static inline void invlpga(unsigned long addr, u32 asid) +{ + asm volatile (SVM_INVLPGA :: "a"(addr), "c"(asid)); +} + +static inline unsigned long kvm_read_cr2(void) +{ + unsigned long cr2; + + asm volatile ("mov %%cr2, %0" : "=r" (cr2)); + return cr2; +} + +static inline void kvm_write_cr2(unsigned long val) +{ + asm volatile ("mov %0, %%cr2" :: "r" (val)); +} + +static inline unsigned long read_dr6(void) +{ + unsigned long dr6; + + asm volatile ("mov %%dr6, %0" : "=r" (dr6)); + return dr6; +} + +static inline void write_dr6(unsigned long val) +{ + asm volatile ("mov %0, %%dr6" :: "r" (val)); +} + +static inline unsigned long read_dr7(void) +{ + unsigned long dr7; + + asm volatile ("mov %%dr7, %0" : "=r" (dr7)); + return dr7; +} + +static inline void write_dr7(unsigned long val) +{ + asm volatile ("mov %0, %%dr7" :: "r" (val)); +} + +static inline int svm_is_long_mode(struct kvm_vcpu *vcpu) +{ + return vcpu->svm->vmcb->save.efer & KVM_EFER_LMA; +} + +static inline void force_new_asid(struct kvm_vcpu *vcpu) +{ + vcpu->svm->asid_generation--; +} + +static inline void flush_guest_tlb(struct kvm_vcpu *vcpu) +{ + force_new_asid(vcpu); +} + +static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) +{ + if (!(efer & KVM_EFER_LMA)) + efer &= ~KVM_EFER_LME; + + vcpu->svm->vmcb->save.efer = efer | MSR_EFER_SVME_MASK; + vcpu->shadow_efer = efer; +} + +static void svm_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) +{ + vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + SVM_EVTINJ_VALID_ERR | + SVM_EVTINJ_TYPE_EXEPT | + GP_VECTOR; + vcpu->svm->vmcb->control.event_inj_err = error_code; +} + +static void inject_ud(struct kvm_vcpu *vcpu) +{ + vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + SVM_EVTINJ_TYPE_EXEPT | + UD_VECTOR; +} + +static void inject_db(struct kvm_vcpu *vcpu) +{ + vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + SVM_EVTINJ_TYPE_EXEPT | + DB_VECTOR; +} + +static int is_page_fault(uint32_t info) +{ + info &= SVM_EVTINJ_VEC_MASK | SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID; + return info == (PF_VECTOR | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_EXEPT); +} + +static int is_external_interrupt(u32 info) +{ + info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID; + return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR); +} + +static void skip_emulated_instruction(struct kvm_vcpu *vcpu) +{ + if (!vcpu->svm->next_rip) { + printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__); + return; + } + if (vcpu->svm->next_rip - vcpu->svm->vmcb->save.rip > 15) { + printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n", + __FUNCTION__, + vcpu->svm->vmcb->save.rip, + vcpu->svm->next_rip); + } + + vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip; + vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; +} + +static int has_svm(void) +{ + uint32_t eax, ebx, ecx, edx; + + if (current_cpu_data.x86_vendor != X86_VENDOR_AMD) { + printk(KERN_INFO "has_svm: not amd\n"); + return 0; + } + + cpuid(0x80000000, &eax, &ebx, &ecx, &edx); + if (eax < SVM_CPUID_FUNC) { + printk(KERN_INFO "has_svm: can't execute cpuid_8000000a\n"); + return 0; + } + + cpuid(0x80000001, &eax, &ebx, &ecx, &edx); + if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) { + printk(KERN_DEBUG "has_svm: svm not available\n"); + return 0; + } + return 1; +} + +static void svm_hardware_disable(void *garbage) +{ + struct svm_cpu_data *svm_data + = per_cpu(svm_data, raw_smp_processor_id()); + + if (svm_data) { + uint64_t efer; + + wrmsrl(MSR_VM_HSAVE_PA, 0); + rdmsrl(MSR_EFER, efer); + wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); + per_cpu(svm_data, raw_smp_processor_id()) = 0; + __free_page(svm_data->save_area); + kfree(svm_data); + } +} + +static void svm_hardware_enable(void *garbage) +{ + + struct svm_cpu_data *svm_data; + uint64_t efer; +#ifdef __x86_64__ + struct desc_ptr gdt_descr; +#else + struct Xgt_desc_struct gdt_descr; +#endif + struct desc_struct *gdt; + int me = raw_smp_processor_id(); + + if (!has_svm()) { + printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me); + return; + } + svm_data = per_cpu(svm_data, me); + + if (!svm_data) { + printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n", + me); + return; + } + + svm_data->asid_generation = 1; + svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1; + svm_data->next_asid = svm_data->max_asid + 1; + + asm volatile ( "sgdt %0" : "=m"(gdt_descr) ); + gdt = (struct desc_struct *)gdt_descr.address; + svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS); + + rdmsrl(MSR_EFER, efer); + wrmsrl(MSR_EFER, efer | MSR_EFER_SVME_MASK); + + wrmsrl(MSR_VM_HSAVE_PA, + page_to_pfn(svm_data->save_area) << PAGE_SHIFT); +} + +static int svm_cpu_init(int cpu) +{ + struct svm_cpu_data *svm_data; + int r; + + svm_data = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL); + if (!svm_data) + return -ENOMEM; + svm_data->cpu = cpu; + svm_data->save_area = alloc_page(GFP_KERNEL); + r = -ENOMEM; + if (!svm_data->save_area) + goto err_1; + + per_cpu(svm_data, cpu) = svm_data; + + return 0; + +err_1: + kfree(svm_data); + return r; + +} + +static int set_msr_interception(u32 *msrpm, unsigned msr, + int read, int write) +{ + int i; + + for (i = 0; i < NUM_MSR_MAPS; i++) { + if (msr >= msrpm_ranges[i] && + msr < msrpm_ranges[i] + MSRS_IN_RANGE) { + u32 msr_offset = (i * MSRS_IN_RANGE + msr - + msrpm_ranges[i]) * 2; + + u32 *base = msrpm + (msr_offset / 32); + u32 msr_shift = msr_offset % 32; + u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1); + *base = (*base & ~(0x3 << msr_shift)) | + (mask << msr_shift); + return 1; + } + } + printk(KERN_DEBUG "%s: not found 0x%x\n", __FUNCTION__, msr); + return 0; +} + +static __init int svm_hardware_setup(void) +{ + int cpu; + struct page *iopm_pages; + struct page *msrpm_pages; + void *msrpm_va; + int r; + + + iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER); + + if (!iopm_pages) + return -ENOMEM; + memset(page_address(iopm_pages), 0xff, + PAGE_SIZE * (1 << IOPM_ALLOC_ORDER)); + iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT; + + + msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER); + + r = -ENOMEM; + if (!msrpm_pages) + goto err_1; + + msrpm_va = page_address(msrpm_pages); + memset(msrpm_va, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER)); + msrpm_base = page_to_pfn(msrpm_pages) << PAGE_SHIFT; + +#ifdef __x86_64__ + set_msr_interception(msrpm_va, MSR_GS_BASE, 1, 1); + set_msr_interception(msrpm_va, MSR_FS_BASE, 1, 1); + set_msr_interception(msrpm_va, MSR_KERNEL_GS_BASE, 1, 1); + set_msr_interception(msrpm_va, MSR_STAR, 1, 1); + set_msr_interception(msrpm_va, MSR_LSTAR, 1, 1); + set_msr_interception(msrpm_va, MSR_CSTAR, 1, 1); + set_msr_interception(msrpm_va, MSR_SYSCALL_MASK, 1, 1); +#endif + set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_CS, 1, 1); + set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_ESP, 1, 1); + set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_EIP, 1, 1); + + for_each_online_cpu(cpu) { + r = svm_cpu_init(cpu); + if (r) + goto err_2; + } + return 0; + +err_2: + __free_pages(msrpm_pages, MSRPM_ALLOC_ORDER); + msrpm_base = 0; +err_1: + __free_pages(iopm_pages, IOPM_ALLOC_ORDER); + iopm_base = 0; + return r; +} + +static __exit void svm_hardware_unsetup(void) +{ + __free_pages(pfn_to_page(msrpm_base >> PAGE_SHIFT), MSRPM_ALLOC_ORDER); + __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER); + iopm_base = msrpm_base = 0; +} + +static void init_seg(struct vmcb_seg *seg) +{ + seg->selector = 0; + seg->attrib = SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK | + SVM_SELECTOR_WRITE_MASK; /* Read/Write Data Segment */ + seg->limit = 0xffff; + seg->base = 0; +} + +static void init_sys_seg(struct vmcb_seg *seg, uint32_t type) +{ + seg->selector = 0; + seg->attrib = SVM_SELECTOR_P_MASK | type; + seg->limit = 0xffff; + seg->base = 0; +} + +static int svm_vcpu_setup(struct kvm_vcpu *vcpu) +{ + return 0; +} + +static void init_vmcb(struct vmcb *vmcb) +{ + struct vmcb_control_area *control = &vmcb->control; + struct vmcb_save_area *save = &vmcb->save; + u64 tsc; + + control->intercept_cr_read = INTERCEPT_CR0_MASK | + INTERCEPT_CR3_MASK | + INTERCEPT_CR4_MASK; + + control->intercept_cr_write = INTERCEPT_CR0_MASK | + INTERCEPT_CR3_MASK | + INTERCEPT_CR4_MASK; + + control->intercept_dr_read = INTERCEPT_DR0_MASK | + INTERCEPT_DR1_MASK | + INTERCEPT_DR2_MASK | + INTERCEPT_DR3_MASK; + + control->intercept_dr_write = INTERCEPT_DR0_MASK | + INTERCEPT_DR1_MASK | + INTERCEPT_DR2_MASK | + INTERCEPT_DR3_MASK | + INTERCEPT_DR5_MASK | + INTERCEPT_DR7_MASK; + + control->intercept_exceptions = 1 << PF_VECTOR; + + + control->intercept = (1ULL << INTERCEPT_INTR) | + (1ULL << INTERCEPT_NMI) | + /* + * selective cr0 intercept bug? + * 0: 0f 22 d8 mov %eax,%cr3 + * 3: 0f 20 c0 mov %cr0,%eax + * 6: 0d 00 00 00 80 or $0x80000000,%eax + * b: 0f 22 c0 mov %eax,%cr0 + * set cr3 ->interception + * get cr0 ->interception + * set cr0 -> no interception + */ + /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */ + (1ULL << INTERCEPT_CPUID) | + (1ULL << INTERCEPT_HLT) | + (1ULL << INTERCEPT_INVLPG) | + (1ULL << INTERCEPT_INVLPGA) | + (1ULL << INTERCEPT_IOIO_PROT) | + (1ULL << INTERCEPT_MSR_PROT) | + (1ULL << INTERCEPT_TASK_SWITCH) | + (1ULL << INTERCEPT_VMRUN) | + (1ULL << INTERCEPT_VMMCALL) | + (1ULL << INTERCEPT_VMLOAD) | + (1ULL << INTERCEPT_VMSAVE) | + (1ULL << INTERCEPT_STGI) | + (1ULL << INTERCEPT_CLGI) | + (1ULL << INTERCEPT_SKINIT); + + control->iopm_base_pa = iopm_base; + control->msrpm_base_pa = msrpm_base; + rdtscll(tsc); + control->tsc_offset = -tsc; + control->int_ctl = V_INTR_MASKING_MASK; + + init_seg(&save->es); + init_seg(&save->ss); + init_seg(&save->ds); + init_seg(&save->fs); + init_seg(&save->gs); + + save->cs.selector = 0xf000; + /* Executable/Readable Code Segment */ + save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK | + SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK; + save->cs.limit = 0xffff; + save->cs.base = 0xffff0000; + + save->gdtr.limit = 0xffff; + save->idtr.limit = 0xffff; + + init_sys_seg(&save->ldtr, SEG_TYPE_LDT); + init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16); + + save->efer = MSR_EFER_SVME_MASK; + + save->dr6 = 0xffff0ff0; + save->dr7 = 0x400; + save->rflags = 2; + save->rip = 0x0000fff0; + + /* + * cr0 val on cpu init should be 0x60000010, we enable cpu + * cache by default. the orderly way is to enable cache in bios. + */ + save->cr0 = 0x00000010 | CR0_PG_MASK; + save->cr4 = CR4_PAE_MASK; + /* rdx = ?? */ +} + +static int svm_create_vcpu(struct kvm_vcpu *vcpu) +{ + struct page *page; + int r; + + r = -ENOMEM; + vcpu->svm = kzalloc(sizeof *vcpu->svm, GFP_KERNEL); + if (!vcpu->svm) + goto out1; + page = alloc_page(GFP_KERNEL); + if (!page) + goto out2; + + vcpu->svm->vmcb = page_address(page); + memset(vcpu->svm->vmcb, 0, PAGE_SIZE); + vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; + vcpu->svm->cr0 = 0x00000010; + vcpu->svm->asid_generation = 0; + memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs)); + init_vmcb(vcpu->svm->vmcb); + + return 0; + +out2: + kfree(vcpu->svm); +out1: + return r; +} + +static void svm_free_vcpu(struct kvm_vcpu *vcpu) +{ + if (!vcpu->svm) + return; + if (vcpu->svm->vmcb) + __free_page(pfn_to_page(vcpu->svm->vmcb_pa >> PAGE_SHIFT)); + kfree(vcpu->svm); +} + +static struct kvm_vcpu *svm_vcpu_load(struct kvm_vcpu *vcpu) +{ + get_cpu(); + return vcpu; +} + +static void svm_vcpu_put(struct kvm_vcpu *vcpu) +{ + put_cpu(); +} + +static void svm_cache_regs(struct kvm_vcpu *vcpu) +{ + vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax; + vcpu->regs[VCPU_REGS_RSP] = vcpu->svm->vmcb->save.rsp; + vcpu->rip = vcpu->svm->vmcb->save.rip; +} + +static void svm_decache_regs(struct kvm_vcpu *vcpu) +{ + vcpu->svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX]; + vcpu->svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP]; + vcpu->svm->vmcb->save.rip = vcpu->rip; +} + +static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu) +{ + return vcpu->svm->vmcb->save.rflags; +} + +static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) +{ + vcpu->svm->vmcb->save.rflags = rflags; +} + +static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg) +{ + struct vmcb_save_area *save = &vcpu->svm->vmcb->save; + + switch (seg) { + case VCPU_SREG_CS: return &save->cs; + case VCPU_SREG_DS: return &save->ds; + case VCPU_SREG_ES: return &save->es; + case VCPU_SREG_FS: return &save->fs; + case VCPU_SREG_GS: return &save->gs; + case VCPU_SREG_SS: return &save->ss; + case VCPU_SREG_TR: return &save->tr; + case VCPU_SREG_LDTR: return &save->ldtr; + } + BUG(); + return 0; +} + +static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg) +{ + struct vmcb_seg *s = svm_seg(vcpu, seg); + + return s->base; +} + +static void svm_get_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + struct vmcb_seg *s = svm_seg(vcpu, seg); + + var->base = s->base; + var->limit = s->limit; + var->selector = s->selector; + var->type = s->attrib & SVM_SELECTOR_TYPE_MASK; + var->s = (s->attrib >> SVM_SELECTOR_S_SHIFT) & 1; + var->dpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3; + var->present = (s->attrib >> SVM_SELECTOR_P_SHIFT) & 1; + var->avl = (s->attrib >> SVM_SELECTOR_AVL_SHIFT) & 1; + var->l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1; + var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1; + var->g = (s->attrib >> SVM_SELECTOR_G_SHIFT) & 1; + var->unusable = !var->present; +} + +static void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) +{ + struct vmcb_seg *s = svm_seg(vcpu, VCPU_SREG_CS); + + *db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1; + *l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1; +} + +static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + dt->limit = vcpu->svm->vmcb->save.ldtr.limit; + dt->base = vcpu->svm->vmcb->save.ldtr.base; +} + +static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + vcpu->svm->vmcb->save.ldtr.limit = dt->limit; + vcpu->svm->vmcb->save.ldtr.base = dt->base ; +} + +static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + dt->limit = vcpu->svm->vmcb->save.gdtr.limit; + dt->base = vcpu->svm->vmcb->save.gdtr.base; +} + +static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + vcpu->svm->vmcb->save.gdtr.limit = dt->limit; + vcpu->svm->vmcb->save.gdtr.base = dt->base ; +} + +static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) +{ +#ifdef __x86_64__ + if (vcpu->shadow_efer & KVM_EFER_LME) { + if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) { + vcpu->shadow_efer |= KVM_EFER_LMA; + vcpu->svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME; + } + + if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK) ) { + vcpu->shadow_efer &= ~KVM_EFER_LMA; + vcpu->svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME); + } + } +#endif + vcpu->svm->cr0 = cr0; + vcpu->svm->vmcb->save.cr0 = cr0 | CR0_PG_MASK; + vcpu->cr0 = cr0; +} + +static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) +{ + vcpu->cr4 = cr4; + vcpu->svm->vmcb->save.cr4 = cr4 | CR4_PAE_MASK; +} + +static void svm_set_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + struct vmcb_seg *s = svm_seg(vcpu, seg); + + s->base = var->base; + s->limit = var->limit; + s->selector = var->selector; + if (var->unusable) + s->attrib = 0; + else { + s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); + s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; + s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; + s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT; + s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; + s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; + s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; + s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; + } + if (seg == VCPU_SREG_CS) + vcpu->svm->vmcb->save.cpl + = (vcpu->svm->vmcb->save.cs.attrib + >> SVM_SELECTOR_DPL_SHIFT) & 3; + +} + +/* FIXME: + + vcpu->svm->vmcb->control.int_ctl &= ~V_TPR_MASK; + vcpu->svm->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK); + +*/ + +static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) +{ + return -EOPNOTSUPP; +} + +static void load_host_msrs(struct kvm_vcpu *vcpu) +{ + int i; + + for ( i = 0; i < NR_HOST_SAVE_MSRS; i++) + wrmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]); +} + +static void save_host_msrs(struct kvm_vcpu *vcpu) +{ + int i; + + for ( i = 0; i < NR_HOST_SAVE_MSRS; i++) + rdmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]); +} + +static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data) +{ + if (svm_data->next_asid > svm_data->max_asid) { + ++svm_data->asid_generation; + svm_data->next_asid = 1; + vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; + } + + vcpu->cpu = svm_data->cpu; + vcpu->svm->asid_generation = svm_data->asid_generation; + vcpu->svm->vmcb->control.asid = svm_data->next_asid++; +} + +static void svm_invlpg(struct kvm_vcpu *vcpu, gva_t address) +{ + invlpga(address, vcpu->svm->vmcb->control.asid); // is needed? +} + +static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) +{ + return vcpu->svm->db_regs[dr]; +} + +static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, + int *exception) +{ + *exception = 0; + + if (vcpu->svm->vmcb->save.dr7 & DR7_GD_MASK) { + vcpu->svm->vmcb->save.dr7 &= ~DR7_GD_MASK; + vcpu->svm->vmcb->save.dr6 |= DR6_BD_MASK; + *exception = DB_VECTOR; + return; + } + + switch (dr) { + case 0 ... 3: + vcpu->svm->db_regs[dr] = value; + return; + case 4 ... 5: + if (vcpu->cr4 & CR4_DE_MASK) { + *exception = UD_VECTOR; + return; + } + case 7: { + if (value & ~((1ULL << 32) - 1)) { + *exception = GP_VECTOR; + return; + } + vcpu->svm->vmcb->save.dr7 = value; + return; + } + default: + printk(KERN_DEBUG "%s: unexpected dr %u\n", + __FUNCTION__, dr); + *exception = UD_VECTOR; + return; + } +} + +static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 exit_int_info = vcpu->svm->vmcb->control.exit_int_info; + u64 fault_address; + u32 error_code; + enum emulation_result er; + + if (is_external_interrupt(exit_int_info)) + push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); + + spin_lock(&vcpu->kvm->lock); + + fault_address = vcpu->svm->vmcb->control.exit_info_2; + error_code = vcpu->svm->vmcb->control.exit_info_1; + if (!vcpu->mmu.page_fault(vcpu, fault_address, error_code)) { + spin_unlock(&vcpu->kvm->lock); + return 1; + } + er = emulate_instruction(vcpu, kvm_run, fault_address, error_code); + spin_unlock(&vcpu->kvm->lock); + + switch (er) { + case EMULATE_DONE: + return 1; + case EMULATE_DO_MMIO: + ++kvm_stat.mmio_exits; + kvm_run->exit_reason = KVM_EXIT_MMIO; + return 0; + case EMULATE_FAIL: + vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__); + break; + default: + BUG(); + } + + kvm_run->exit_reason = KVM_EXIT_UNKNOWN; + return 0; +} + +static int io_get_override(struct kvm_vcpu *vcpu, + struct vmcb_seg **seg, + int *addr_override) +{ + u8 inst[MAX_INST_SIZE]; + unsigned ins_length; + gva_t rip; + int i; + + rip = vcpu->svm->vmcb->save.rip; + ins_length = vcpu->svm->next_rip - rip; + rip += vcpu->svm->vmcb->save.cs.base; + + if (ins_length > MAX_INST_SIZE) + printk(KERN_DEBUG + "%s: inst length err, cs base 0x%llx rip 0x%llx " + "next rip 0x%llx ins_length %u\n", + __FUNCTION__, + vcpu->svm->vmcb->save.cs.base, + vcpu->svm->vmcb->save.rip, + vcpu->svm->vmcb->control.exit_info_2, + ins_length); + + if (kvm_read_guest(vcpu, rip, ins_length, inst) != ins_length) + /* #PF */ + return 0; + + *addr_override = 0; + *seg = 0; + for (i = 0; i < ins_length; i++) + switch (inst[i]) { + case 0xf0: + case 0xf2: + case 0xf3: + case 0x66: + continue; + case 0x67: + *addr_override = 1; + continue; + case 0x2e: + *seg = &vcpu->svm->vmcb->save.cs; + continue; + case 0x36: + *seg = &vcpu->svm->vmcb->save.ss; + continue; + case 0x3e: + *seg = &vcpu->svm->vmcb->save.ds; + continue; + case 0x26: + *seg = &vcpu->svm->vmcb->save.es; + continue; + case 0x64: + *seg = &vcpu->svm->vmcb->save.fs; + continue; + case 0x65: + *seg = &vcpu->svm->vmcb->save.gs; + continue; + default: + return 1; + } + printk(KERN_DEBUG "%s: unexpected\n", __FUNCTION__); + return 0; +} + +static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, u64 *address) +{ + unsigned long addr_mask; + unsigned long *reg; + struct vmcb_seg *seg; + int addr_override; + struct vmcb_save_area *save_area = &vcpu->svm->vmcb->save; + u16 cs_attrib = save_area->cs.attrib; + unsigned addr_size = get_addr_size(vcpu); + + if (!io_get_override(vcpu, &seg, &addr_override)) + return 0; + + if (addr_override) + addr_size = (addr_size == 2) ? 4: (addr_size >> 1); + + if (ins) { + reg = &vcpu->regs[VCPU_REGS_RDI]; + seg = &vcpu->svm->vmcb->save.es; + } else { + reg = &vcpu->regs[VCPU_REGS_RSI]; + seg = (seg) ? seg : &vcpu->svm->vmcb->save.ds; + } + + addr_mask = ~0ULL >> (64 - (addr_size * 8)); + + if ((cs_attrib & SVM_SELECTOR_L_MASK) && + !(vcpu->svm->vmcb->save.rflags & X86_EFLAGS_VM)) { + *address = (*reg & addr_mask); + return addr_mask; + } + + if (!(seg->attrib & SVM_SELECTOR_P_SHIFT)) { + svm_inject_gp(vcpu, 0); + return 0; + } + + *address = (*reg & addr_mask) + seg->base; + return addr_mask; +} + +static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug? + int _in = io_info & SVM_IOIO_TYPE_MASK; + + ++kvm_stat.io_exits; + + vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2; + + kvm_run->exit_reason = KVM_EXIT_IO; + kvm_run->io.port = io_info >> 16; + kvm_run->io.direction = (_in) ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; + kvm_run->io.size = ((io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT); + kvm_run->io.string = (io_info & SVM_IOIO_STR_MASK) != 0; + kvm_run->io.rep = (io_info & SVM_IOIO_REP_MASK) != 0; + + if (kvm_run->io.string) { + unsigned addr_mask; + + addr_mask = io_adress(vcpu, _in, &kvm_run->io.address); + if (!addr_mask) { + printk(KERN_DEBUG "%s: get io address failed\n", __FUNCTION__); + return 1; + } + + if (kvm_run->io.rep) { + kvm_run->io.count = vcpu->regs[VCPU_REGS_RCX] & addr_mask; + kvm_run->io.string_down = (vcpu->svm->vmcb->save.rflags + & X86_EFLAGS_DF) != 0; + } + } else { + kvm_run->io.value = vcpu->svm->vmcb->save.rax; + } + return 0; +} + + +static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + return 1; +} + +static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1; + skip_emulated_instruction(vcpu); + if (vcpu->irq_summary && (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF)) + return 1; + + kvm_run->exit_reason = KVM_EXIT_HLT; + return 0; +} + +static int invalid_op_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + inject_ud(vcpu); + return 1; +} + +static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + printk(KERN_DEBUG "%s: task swiche is unsupported\n", __FUNCTION__); + kvm_run->exit_reason = KVM_EXIT_UNKNOWN; + return 0; +} + +static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; + kvm_run->exit_reason = KVM_EXIT_CPUID; + return 0; +} + +static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + if (emulate_instruction(vcpu, 0, 0, 0) != EMULATE_DONE) + printk(KERN_ERR "%s: failed\n", __FUNCTION__); + return 1; +} + +static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) +{ + switch (ecx) { + case MSR_IA32_MC0_CTL: + case MSR_IA32_MCG_STATUS: + case MSR_IA32_MCG_CAP: + case MSR_IA32_MC0_MISC: + case MSR_IA32_MC0_MISC+4: + case MSR_IA32_MC0_MISC+8: + case MSR_IA32_MC0_MISC+12: + case MSR_IA32_MC0_MISC+16: + case MSR_IA32_UCODE_REV: + /* MTRR registers */ + case 0xfe: + case 0x200 ... 0x2ff: + *data = 0; + break; + case MSR_IA32_TIME_STAMP_COUNTER: { + u64 tsc; + + rdtscll(tsc); + *data = vcpu->svm->vmcb->control.tsc_offset + tsc; + break; + } + case MSR_EFER: + *data = vcpu->shadow_efer; + break; + case MSR_IA32_APICBASE: + *data = vcpu->apic_base; + break; +#ifdef __x86_64__ + case MSR_STAR: + *data = vcpu->svm->vmcb->save.star; + break; + case MSR_LSTAR: + *data = vcpu->svm->vmcb->save.lstar; + break; + case MSR_CSTAR: + *data = vcpu->svm->vmcb->save.cstar; + break; + case MSR_KERNEL_GS_BASE: + *data = vcpu->svm->vmcb->save.kernel_gs_base; + break; + case MSR_SYSCALL_MASK: + *data = vcpu->svm->vmcb->save.sfmask; + break; +#endif + case MSR_IA32_SYSENTER_CS: + *data = vcpu->svm->vmcb->save.sysenter_cs; + break; + case MSR_IA32_SYSENTER_EIP: + *data = vcpu->svm->vmcb->save.sysenter_eip; + break; + case MSR_IA32_SYSENTER_ESP: + *data = vcpu->svm->vmcb->save.sysenter_esp; + break; + default: + printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", ecx); + return 1; + } + return 0; +} + +static int rdmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 ecx = vcpu->regs[VCPU_REGS_RCX]; + u64 data; + + if (svm_get_msr(vcpu, ecx, &data)) + svm_inject_gp(vcpu, 0); + else { + vcpu->svm->vmcb->save.rax = data & 0xffffffff; + vcpu->regs[VCPU_REGS_RDX] = data >> 32; + vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; + skip_emulated_instruction(vcpu); + } + return 1; +} + +static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) +{ + switch (ecx) { +#ifdef __x86_64__ + case MSR_EFER: + set_efer(vcpu, data); + break; +#endif + case MSR_IA32_MC0_STATUS: + printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n" + , __FUNCTION__, data); + break; + case MSR_IA32_TIME_STAMP_COUNTER: { + u64 tsc; + + rdtscll(tsc); + vcpu->svm->vmcb->control.tsc_offset = data - tsc; + break; + } + case MSR_IA32_UCODE_REV: + case MSR_IA32_UCODE_WRITE: + case 0x200 ... 0x2ff: /* MTRRs */ + break; + case MSR_IA32_APICBASE: + vcpu->apic_base = data; + break; +#ifdef __x86_64___ + case MSR_STAR: + vcpu->svm->vmcb->save.star = data; + break; + case MSR_LSTAR: + vcpu->svm->vmcb->save.lstar = data; + break; + case MSR_CSTAR: + vcpu->svm->vmcb->save.cstar = data; + break; + case MSR_KERNEL_GS_BASE: + vcpu->svm->vmcb->save.kernel_gs_base = data; + break; + case MSR_SYSCALL_MASK: + vcpu->svm->vmcb->save.sfmask = data; + break; +#endif + case MSR_IA32_SYSENTER_CS: + vcpu->svm->vmcb->save.sysenter_cs = data; + break; + case MSR_IA32_SYSENTER_EIP: + vcpu->svm->vmcb->save.sysenter_eip = data; + break; + case MSR_IA32_SYSENTER_ESP: + vcpu->svm->vmcb->save.sysenter_esp = data; + break; + default: + printk(KERN_ERR "kvm: unhandled wrmsr: %x\n", ecx); + return 1; + } + return 0; +} + +static int wrmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 ecx = vcpu->regs[VCPU_REGS_RCX]; + u64 data = (vcpu->svm->vmcb->save.rax & -1u) + | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32); + vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; + if (svm_set_msr(vcpu, ecx, data)) + svm_inject_gp(vcpu, 0); + else + skip_emulated_instruction(vcpu); + return 1; +} + +static int msr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + if (vcpu->svm->vmcb->control.exit_info_1) + return wrmsr_interception(vcpu, kvm_run); + else + return rdmsr_interception(vcpu, kvm_run); +} + +static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) = { + [SVM_EXIT_READ_CR0] = emulate_on_interception, + [SVM_EXIT_READ_CR3] = emulate_on_interception, + [SVM_EXIT_READ_CR4] = emulate_on_interception, + /* for now: */ + [SVM_EXIT_WRITE_CR0] = emulate_on_interception, + [SVM_EXIT_WRITE_CR3] = emulate_on_interception, + [SVM_EXIT_WRITE_CR4] = emulate_on_interception, + [SVM_EXIT_READ_DR0] = emulate_on_interception, + [SVM_EXIT_READ_DR1] = emulate_on_interception, + [SVM_EXIT_READ_DR2] = emulate_on_interception, + [SVM_EXIT_READ_DR3] = emulate_on_interception, + [SVM_EXIT_WRITE_DR0] = emulate_on_interception, + [SVM_EXIT_WRITE_DR1] = emulate_on_interception, + [SVM_EXIT_WRITE_DR2] = emulate_on_interception, + [SVM_EXIT_WRITE_DR3] = emulate_on_interception, + [SVM_EXIT_WRITE_DR5] = emulate_on_interception, + [SVM_EXIT_WRITE_DR7] = emulate_on_interception, + [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, + [SVM_EXIT_INTR] = nop_on_interception, + [SVM_EXIT_NMI] = nop_on_interception, + [SVM_EXIT_SMI] = nop_on_interception, + [SVM_EXIT_INIT] = nop_on_interception, + /* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */ + [SVM_EXIT_CPUID] = cpuid_interception, + [SVM_EXIT_HLT] = halt_interception, + [SVM_EXIT_INVLPG] = emulate_on_interception, + [SVM_EXIT_INVLPGA] = invalid_op_interception, + [SVM_EXIT_IOIO] = io_interception, + [SVM_EXIT_MSR] = msr_interception, + [SVM_EXIT_TASK_SWITCH] = task_switch_interception, + [SVM_EXIT_VMRUN] = invalid_op_interception, + [SVM_EXIT_VMMCALL] = invalid_op_interception, + [SVM_EXIT_VMLOAD] = invalid_op_interception, + [SVM_EXIT_VMSAVE] = invalid_op_interception, + [SVM_EXIT_STGI] = invalid_op_interception, + [SVM_EXIT_CLGI] = invalid_op_interception, + [SVM_EXIT_SKINIT] = invalid_op_interception, +}; + + +static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 exit_code = vcpu->svm->vmcb->control.exit_code; + + kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT; + + if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) && + exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR) + printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " + "exit_code 0x%x\n", + __FUNCTION__, vcpu->svm->vmcb->control.exit_int_info, + exit_code); + + if (exit_code >= sizeof(svm_exit_handlers) / sizeof(*svm_exit_handlers) + || svm_exit_handlers[exit_code] == 0) { + kvm_run->exit_reason = KVM_EXIT_UNKNOWN; + printk(KERN_ERR "%s: 0x%x @ 0x%llx cr0 0x%lx rflags 0x%llx\n", + __FUNCTION__, + exit_code, + vcpu->svm->vmcb->save.rip, + vcpu->cr0, + vcpu->svm->vmcb->save.rflags); + return 0; + } + + return svm_exit_handlers[exit_code](vcpu, kvm_run); +} + +static void reload_tss(struct kvm_vcpu *vcpu) +{ + int cpu = raw_smp_processor_id(); + + struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu); + svm_data->tss_desc->type = 9; //available 32/64-bit TSS + load_TR_desc(); +} + +static void pre_svm_run(struct kvm_vcpu *vcpu) +{ + int cpu = raw_smp_processor_id(); + + struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu); + + vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; + if (vcpu->cpu != cpu || + vcpu->svm->asid_generation != svm_data->asid_generation) + new_asid(vcpu, svm_data); +} + + +static inline void kvm_try_inject_irq(struct kvm_vcpu *vcpu) +{ + struct vmcb_control_area *control; + + if (!vcpu->irq_summary) + return; + + control = &vcpu->svm->vmcb->control; + + control->int_vector = pop_irq(vcpu); + control->int_ctl &= ~V_INTR_PRIO_MASK; + control->int_ctl |= V_IRQ_MASK | + ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); +} + +static void kvm_reput_irq(struct kvm_vcpu *vcpu) +{ + struct vmcb_control_area *control = &vcpu->svm->vmcb->control; + + if (control->int_ctl & V_IRQ_MASK) { + control->int_ctl &= ~V_IRQ_MASK; + push_irq(vcpu, control->int_vector); + } +} + +static void save_db_regs(unsigned long *db_regs) +{ +#ifdef __x86_64__ + asm ("mov %%dr0, %%rax \n\t" + "mov %%rax, %[dr0] \n\t" + "mov %%dr1, %%rax \n\t" + "mov %%rax, %[dr1] \n\t" + "mov %%dr2, %%rax \n\t" + "mov %%rax, %[dr2] \n\t" + "mov %%dr3, %%rax \n\t" + "mov %%rax, %[dr3] \n\t" + : [dr0] "=m"(db_regs[0]), + [dr1] "=m"(db_regs[1]), + [dr2] "=m"(db_regs[2]), + [dr3] "=m"(db_regs[3]) + : : "rax"); +#else + asm ("mov %%dr0, %%eax \n\t" + "mov %%eax, %[dr0] \n\t" + "mov %%dr1, %%eax \n\t" + "mov %%eax, %[dr1] \n\t" + "mov %%dr2, %%eax \n\t" + "mov %%eax, %[dr2] \n\t" + "mov %%dr3, %%eax \n\t" + "mov %%eax, %[dr3] \n\t" + : [dr0] "=m"(db_regs[0]), + [dr1] "=m"(db_regs[1]), + [dr2] "=m"(db_regs[2]), + [dr3] "=m"(db_regs[3]) + : : "eax"); +#endif +} + +static void load_db_regs(unsigned long *db_regs) +{ + asm volatile ("mov %[dr0], %%dr0 \n\t" + "mov %[dr1], %%dr1 \n\t" + "mov %[dr2], %%dr2 \n\t" + "mov %[dr3], %%dr3 \n\t" + : + : [dr0] "r"(db_regs[0]), + [dr1] "r"(db_regs[1]), + [dr2] "r"(db_regs[2]), + [dr3] "r"(db_regs[3]) +#ifdef __x86_64__ + : "rax"); +#else + : "eax"); +#endif +} + +static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u16 fs_selector; + u16 gs_selector; + u16 ldt_selector; + +again: + kvm_try_inject_irq(vcpu); + + clgi(); + + pre_svm_run(vcpu); + + save_host_msrs(vcpu); + fs_selector = read_fs(); + gs_selector = read_gs(); + ldt_selector = read_ldt(); + vcpu->svm->host_cr2 = kvm_read_cr2(); + vcpu->svm->host_dr6 = read_dr6(); + vcpu->svm->host_dr7 = read_dr7(); + vcpu->svm->vmcb->save.cr2 = vcpu->cr2; + + if (vcpu->svm->vmcb->save.dr7 & 0xff) { + write_dr7(0); + save_db_regs(vcpu->svm->host_db_regs); + load_db_regs(vcpu->svm->db_regs); + } + asm volatile ( +#ifdef __x86_64__ + "push %%rbx; push %%rcx; push %%rdx;" + "push %%rsi; push %%rdi; push %%rbp;" + "push %%r8; push %%r9; push %%r10; push %%r11;" + "push %%r12; push %%r13; push %%r14; push %%r15;" +#else + "push %%ebx; push %%ecx; push %%edx;" + "push %%esi; push %%edi; push %%ebp;" +#endif + +#ifdef __x86_64__ + "mov %c[rbx](%[vcpu]), %%rbx \n\t" + "mov %c[rcx](%[vcpu]), %%rcx \n\t" + "mov %c[rdx](%[vcpu]), %%rdx \n\t" + "mov %c[rsi](%[vcpu]), %%rsi \n\t" + "mov %c[rdi](%[vcpu]), %%rdi \n\t" + "mov %c[rbp](%[vcpu]), %%rbp \n\t" + "mov %c[r8](%[vcpu]), %%r8 \n\t" + "mov %c[r9](%[vcpu]), %%r9 \n\t" + "mov %c[r10](%[vcpu]), %%r10 \n\t" + "mov %c[r11](%[vcpu]), %%r11 \n\t" + "mov %c[r12](%[vcpu]), %%r12 \n\t" + "mov %c[r13](%[vcpu]), %%r13 \n\t" + "mov %c[r14](%[vcpu]), %%r14 \n\t" + "mov %c[r15](%[vcpu]), %%r15 \n\t" +#else + "mov %c[rbx](%[vcpu]), %%ebx \n\t" + "mov %c[rcx](%[vcpu]), %%ecx \n\t" + "mov %c[rdx](%[vcpu]), %%edx \n\t" + "mov %c[rsi](%[vcpu]), %%esi \n\t" + "mov %c[rdi](%[vcpu]), %%edi \n\t" + "mov %c[rbp](%[vcpu]), %%ebp \n\t" +#endif + +#ifdef __x86_64__ + /* Enter guest mode */ + "push %%rax \n\t" + "mov %c[svm](%[vcpu]), %%rax \n\t" + "mov %c[vmcb](%%rax), %%rax \n\t" + SVM_VMLOAD "\n\t" + SVM_VMRUN "\n\t" + SVM_VMSAVE "\n\t" + "pop %%rax \n\t" +#else + /* Enter guest mode */ + "push %%eax \n\t" + "mov %c[svm](%[vcpu]), %%eax \n\t" + "mov %c[vmcb](%%eax), %%eax \n\t" + SVM_VMLOAD "\n\t" + SVM_VMRUN "\n\t" + SVM_VMSAVE "\n\t" + "pop %%eax \n\t" +#endif + + /* Save guest registers, load host registers */ +#ifdef __x86_64__ + "mov %%rbx, %c[rbx](%[vcpu]) \n\t" + "mov %%rcx, %c[rcx](%[vcpu]) \n\t" + "mov %%rdx, %c[rdx](%[vcpu]) \n\t" + "mov %%rsi, %c[rsi](%[vcpu]) \n\t" + "mov %%rdi, %c[rdi](%[vcpu]) \n\t" + "mov %%rbp, %c[rbp](%[vcpu]) \n\t" + "mov %%r8, %c[r8](%[vcpu]) \n\t" + "mov %%r9, %c[r9](%[vcpu]) \n\t" + "mov %%r10, %c[r10](%[vcpu]) \n\t" + "mov %%r11, %c[r11](%[vcpu]) \n\t" + "mov %%r12, %c[r12](%[vcpu]) \n\t" + "mov %%r13, %c[r13](%[vcpu]) \n\t" + "mov %%r14, %c[r14](%[vcpu]) \n\t" + "mov %%r15, %c[r15](%[vcpu]) \n\t" + + "pop %%r15; pop %%r14; pop %%r13; pop %%r12;" + "pop %%r11; pop %%r10; pop %%r9; pop %%r8;" + "pop %%rbp; pop %%rdi; pop %%rsi;" + "pop %%rdx; pop %%rcx; pop %%rbx; \n\t" +#else + "mov %%ebx, %c[rbx](%[vcpu]) \n\t" + "mov %%ecx, %c[rcx](%[vcpu]) \n\t" + "mov %%edx, %c[rdx](%[vcpu]) \n\t" + "mov %%esi, %c[rsi](%[vcpu]) \n\t" + "mov %%edi, %c[rdi](%[vcpu]) \n\t" + "mov %%ebp, %c[rbp](%[vcpu]) \n\t" + + "pop %%ebp; pop %%edi; pop %%esi;" + "pop %%edx; pop %%ecx; pop %%ebx; \n\t" +#endif + : + : [vcpu]"a"(vcpu), + [svm]"i"(offsetof(struct kvm_vcpu, svm)), + [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)), + [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])), + [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])), + [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])), + [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])), + [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])), + [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP])) +#ifdef __x86_64__ + ,[r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])), + [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])), + [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])), + [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])), + [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])), + [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])), + [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])), + [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15])) +#endif + : "cc", "memory" ); + + if ((vcpu->svm->vmcb->save.dr7 & 0xff)) + load_db_regs(vcpu->svm->host_db_regs); + + vcpu->cr2 = vcpu->svm->vmcb->save.cr2; + + write_dr6(vcpu->svm->host_dr6); + write_dr7(vcpu->svm->host_dr7); + kvm_write_cr2(vcpu->svm->host_cr2); + + load_fs(fs_selector); + load_gs(gs_selector); + load_ldt(ldt_selector); + load_host_msrs(vcpu); + + reload_tss(vcpu); + + stgi(); + + kvm_reput_irq(vcpu); + + vcpu->svm->next_rip = 0; + + if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) { + kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; + kvm_run->exit_reason = vcpu->svm->vmcb->control.exit_code; + return 0; + } + + if (handle_exit(vcpu, kvm_run)) { + if (signal_pending(current)) { + ++kvm_stat.signal_exits; + return -EINTR; + } + kvm_resched(vcpu); + goto again; + } + return 0; +} + +static void svm_flush_tlb(struct kvm_vcpu *vcpu) +{ + force_new_asid(vcpu); +} + +static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) +{ + vcpu->svm->vmcb->save.cr3 = root; + force_new_asid(vcpu); +} + +static void svm_inject_page_fault(struct kvm_vcpu *vcpu, + unsigned long addr, + uint32_t err_code) +{ + uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info; + + ++kvm_stat.pf_guest; + + if (is_page_fault(exit_int_info)) { + + vcpu->svm->vmcb->control.event_inj_err = 0; + vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + SVM_EVTINJ_VALID_ERR | + SVM_EVTINJ_TYPE_EXEPT | + DF_VECTOR; + return; + } + vcpu->cr2 = addr; + vcpu->svm->vmcb->save.cr2 = addr; + vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + SVM_EVTINJ_VALID_ERR | + SVM_EVTINJ_TYPE_EXEPT | + PF_VECTOR; + vcpu->svm->vmcb->control.event_inj_err = err_code; +} + + +static int is_disabled(void) +{ + return 0; +} + +static struct kvm_arch_ops svm_arch_ops = { + .cpu_has_kvm_support = has_svm, + .disabled_by_bios = is_disabled, + .hardware_setup = svm_hardware_setup, + .hardware_unsetup = svm_hardware_unsetup, + .hardware_enable = svm_hardware_enable, + .hardware_disable = svm_hardware_disable, + + .vcpu_create = svm_create_vcpu, + .vcpu_free = svm_free_vcpu, + + .vcpu_load = svm_vcpu_load, + .vcpu_put = svm_vcpu_put, + + .set_guest_debug = svm_guest_debug, + .get_msr = svm_get_msr, + .set_msr = svm_set_msr, + .get_segment_base = svm_get_segment_base, + .get_segment = svm_get_segment, + .set_segment = svm_set_segment, + .is_long_mode = svm_is_long_mode, + .get_cs_db_l_bits = svm_get_cs_db_l_bits, + .set_cr0 = svm_set_cr0, + .set_cr0_no_modeswitch = svm_set_cr0, + .set_cr3 = svm_set_cr3, + .set_cr4 = svm_set_cr4, + .set_efer = svm_set_efer, + .get_idt = svm_get_idt, + .set_idt = svm_set_idt, + .get_gdt = svm_get_gdt, + .set_gdt = svm_set_gdt, + .get_dr = svm_get_dr, + .set_dr = svm_set_dr, + .cache_regs = svm_cache_regs, + .decache_regs = svm_decache_regs, + .get_rflags = svm_get_rflags, + .set_rflags = svm_set_rflags, + + .invlpg = svm_invlpg, + .tlb_flush = svm_flush_tlb, + .inject_page_fault = svm_inject_page_fault, + + .inject_gp = svm_inject_gp, + + .run = svm_vcpu_run, + .skip_emulated_instruction = skip_emulated_instruction, + .vcpu_setup = svm_vcpu_setup, +}; + +static int __init svm_init(void) +{ + kvm_emulator_want_group7_invlpg(); + kvm_init_arch(&svm_arch_ops, THIS_MODULE); + return 0; +} + +static void __exit svm_exit(void) +{ + kvm_exit_arch(); +} + +module_init(svm_init) +module_exit(svm_exit) diff --git a/drivers/kvm/svm.h b/drivers/kvm/svm.h new file mode 100644 index 000000000000..df731c3fb588 --- /dev/null +++ b/drivers/kvm/svm.h @@ -0,0 +1,315 @@ +#ifndef __SVM_H +#define __SVM_H + +enum { + INTERCEPT_INTR, + INTERCEPT_NMI, + INTERCEPT_SMI, + INTERCEPT_INIT, + INTERCEPT_VINTR, + INTERCEPT_SELECTIVE_CR0, + INTERCEPT_STORE_IDTR, + INTERCEPT_STORE_GDTR, + INTERCEPT_STORE_LDTR, + INTERCEPT_STORE_TR, + INTERCEPT_LOAD_IDTR, + INTERCEPT_LOAD_GDTR, + INTERCEPT_LOAD_LDTR, + INTERCEPT_LOAD_TR, + INTERCEPT_RDTSC, + INTERCEPT_RDPMC, + INTERCEPT_PUSHF, + INTERCEPT_POPF, + INTERCEPT_CPUID, + INTERCEPT_RSM, + INTERCEPT_IRET, + INTERCEPT_INTn, + INTERCEPT_INVD, + INTERCEPT_PAUSE, + INTERCEPT_HLT, + INTERCEPT_INVLPG, + INTERCEPT_INVLPGA, + INTERCEPT_IOIO_PROT, + INTERCEPT_MSR_PROT, + INTERCEPT_TASK_SWITCH, + INTERCEPT_FERR_FREEZE, + INTERCEPT_SHUTDOWN, + INTERCEPT_VMRUN, + INTERCEPT_VMMCALL, + INTERCEPT_VMLOAD, + INTERCEPT_VMSAVE, + INTERCEPT_STGI, + INTERCEPT_CLGI, + INTERCEPT_SKINIT, + INTERCEPT_RDTSCP, + INTERCEPT_ICEBP, + INTERCEPT_WBINVD, +}; + + +struct __attribute__ ((__packed__)) vmcb_control_area { + u16 intercept_cr_read; + u16 intercept_cr_write; + u16 intercept_dr_read; + u16 intercept_dr_write; + u32 intercept_exceptions; + u64 intercept; + u8 reserved_1[44]; + u64 iopm_base_pa; + u64 msrpm_base_pa; + u64 tsc_offset; + u32 asid; + u8 tlb_ctl; + u8 reserved_2[3]; + u32 int_ctl; + u32 int_vector; + u32 int_state; + u8 reserved_3[4]; + u32 exit_code; + u32 exit_code_hi; + u64 exit_info_1; + u64 exit_info_2; + u32 exit_int_info; + u32 exit_int_info_err; + u64 nested_ctl; + u8 reserved_4[16]; + u32 event_inj; + u32 event_inj_err; + u64 nested_cr3; + u64 lbr_ctl; + u8 reserved_5[832]; +}; + + +#define TLB_CONTROL_DO_NOTHING 0 +#define TLB_CONTROL_FLUSH_ALL_ASID 1 + +#define V_TPR_MASK 0x0f + +#define V_IRQ_SHIFT 8 +#define V_IRQ_MASK (1 << V_IRQ_SHIFT) + +#define V_INTR_PRIO_SHIFT 16 +#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT) + +#define V_IGN_TPR_SHIFT 20 +#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT) + +#define V_INTR_MASKING_SHIFT 24 +#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT) + +#define SVM_INTERRUPT_SHADOW_MASK 1 + +#define SVM_IOIO_STR_SHIFT 2 +#define SVM_IOIO_REP_SHIFT 3 +#define SVM_IOIO_SIZE_SHIFT 4 +#define SVM_IOIO_ASIZE_SHIFT 7 + +#define SVM_IOIO_TYPE_MASK 1 +#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT) +#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT) +#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT) +#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT) + +struct __attribute__ ((__packed__)) vmcb_seg { + u16 selector; + u16 attrib; + u32 limit; + u64 base; +}; + +struct __attribute__ ((__packed__)) vmcb_save_area { + struct vmcb_seg es; + struct vmcb_seg cs; + struct vmcb_seg ss; + struct vmcb_seg ds; + struct vmcb_seg fs; + struct vmcb_seg gs; + struct vmcb_seg gdtr; + struct vmcb_seg ldtr; + struct vmcb_seg idtr; + struct vmcb_seg tr; + u8 reserved_1[43]; + u8 cpl; + u8 reserved_2[4]; + u64 efer; + u8 reserved_3[112]; + u64 cr4; + u64 cr3; + u64 cr0; + u64 dr7; + u64 dr6; + u64 rflags; + u64 rip; + u8 reserved_4[88]; + u64 rsp; + u8 reserved_5[24]; + u64 rax; + u64 star; + u64 lstar; + u64 cstar; + u64 sfmask; + u64 kernel_gs_base; + u64 sysenter_cs; + u64 sysenter_esp; + u64 sysenter_eip; + u64 cr2; + u8 reserved_6[32]; + u64 g_pat; + u64 dbgctl; + u64 br_from; + u64 br_to; + u64 last_excp_from; + u64 last_excp_to; +}; + +struct __attribute__ ((__packed__)) vmcb { + struct vmcb_control_area control; + struct vmcb_save_area save; +}; + +#define SVM_CPUID_FEATURE_SHIFT 2 +#define SVM_CPUID_FUNC 0x8000000a + +#define MSR_EFER_SVME_MASK (1ULL << 12) +#define MSR_VM_HSAVE_PA 0xc0010117ULL + +#define SVM_SELECTOR_S_SHIFT 4 +#define SVM_SELECTOR_DPL_SHIFT 5 +#define SVM_SELECTOR_P_SHIFT 7 +#define SVM_SELECTOR_AVL_SHIFT 8 +#define SVM_SELECTOR_L_SHIFT 9 +#define SVM_SELECTOR_DB_SHIFT 10 +#define SVM_SELECTOR_G_SHIFT 11 + +#define SVM_SELECTOR_TYPE_MASK (0xf) +#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT) +#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT) +#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT) +#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT) +#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT) +#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT) +#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT) + +#define SVM_SELECTOR_WRITE_MASK (1 << 1) +#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK +#define SVM_SELECTOR_CODE_MASK (1 << 3) + +#define INTERCEPT_CR0_MASK 1 +#define INTERCEPT_CR3_MASK (1 << 3) +#define INTERCEPT_CR4_MASK (1 << 4) + +#define INTERCEPT_DR0_MASK 1 +#define INTERCEPT_DR1_MASK (1 << 1) +#define INTERCEPT_DR2_MASK (1 << 2) +#define INTERCEPT_DR3_MASK (1 << 3) +#define INTERCEPT_DR4_MASK (1 << 4) +#define INTERCEPT_DR5_MASK (1 << 5) +#define INTERCEPT_DR6_MASK (1 << 6) +#define INTERCEPT_DR7_MASK (1 << 7) + +#define SVM_EVTINJ_VEC_MASK 0xff + +#define SVM_EVTINJ_TYPE_SHIFT 8 +#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT) + +#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT) +#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT) +#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT) +#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT) + +#define SVM_EVTINJ_VALID (1 << 31) +#define SVM_EVTINJ_VALID_ERR (1 << 11) + +#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK + +#define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR +#define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI +#define SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT +#define SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT + +#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID +#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR + +#define SVM_EXIT_READ_CR0 0x000 +#define SVM_EXIT_READ_CR3 0x003 +#define SVM_EXIT_READ_CR4 0x004 +#define SVM_EXIT_READ_CR8 0x008 +#define SVM_EXIT_WRITE_CR0 0x010 +#define SVM_EXIT_WRITE_CR3 0x013 +#define SVM_EXIT_WRITE_CR4 0x014 +#define SVM_EXIT_WRITE_CR8 0x018 +#define SVM_EXIT_READ_DR0 0x020 +#define SVM_EXIT_READ_DR1 0x021 +#define SVM_EXIT_READ_DR2 0x022 +#define SVM_EXIT_READ_DR3 0x023 +#define SVM_EXIT_READ_DR4 0x024 +#define SVM_EXIT_READ_DR5 0x025 +#define SVM_EXIT_READ_DR6 0x026 +#define SVM_EXIT_READ_DR7 0x027 +#define SVM_EXIT_WRITE_DR0 0x030 +#define SVM_EXIT_WRITE_DR1 0x031 +#define SVM_EXIT_WRITE_DR2 0x032 +#define SVM_EXIT_WRITE_DR3 0x033 +#define SVM_EXIT_WRITE_DR4 0x034 +#define SVM_EXIT_WRITE_DR5 0x035 +#define SVM_EXIT_WRITE_DR6 0x036 +#define SVM_EXIT_WRITE_DR7 0x037 +#define SVM_EXIT_EXCP_BASE 0x040 +#define SVM_EXIT_INTR 0x060 +#define SVM_EXIT_NMI 0x061 +#define SVM_EXIT_SMI 0x062 +#define SVM_EXIT_INIT 0x063 +#define SVM_EXIT_VINTR 0x064 +#define SVM_EXIT_CR0_SEL_WRITE 0x065 +#define SVM_EXIT_IDTR_READ 0x066 +#define SVM_EXIT_GDTR_READ 0x067 +#define SVM_EXIT_LDTR_READ 0x068 +#define SVM_EXIT_TR_READ 0x069 +#define SVM_EXIT_IDTR_WRITE 0x06a +#define SVM_EXIT_GDTR_WRITE 0x06b +#define SVM_EXIT_LDTR_WRITE 0x06c +#define SVM_EXIT_TR_WRITE 0x06d +#define SVM_EXIT_RDTSC 0x06e +#define SVM_EXIT_RDPMC 0x06f +#define SVM_EXIT_PUSHF 0x070 +#define SVM_EXIT_POPF 0x071 +#define SVM_EXIT_CPUID 0x072 +#define SVM_EXIT_RSM 0x073 +#define SVM_EXIT_IRET 0x074 +#define SVM_EXIT_SWINT 0x075 +#define SVM_EXIT_INVD 0x076 +#define SVM_EXIT_PAUSE 0x077 +#define SVM_EXIT_HLT 0x078 +#define SVM_EXIT_INVLPG 0x079 +#define SVM_EXIT_INVLPGA 0x07a +#define SVM_EXIT_IOIO 0x07b +#define SVM_EXIT_MSR 0x07c +#define SVM_EXIT_TASK_SWITCH 0x07d +#define SVM_EXIT_FERR_FREEZE 0x07e +#define SVM_EXIT_SHUTDOWN 0x07f +#define SVM_EXIT_VMRUN 0x080 +#define SVM_EXIT_VMMCALL 0x081 +#define SVM_EXIT_VMLOAD 0x082 +#define SVM_EXIT_VMSAVE 0x083 +#define SVM_EXIT_STGI 0x084 +#define SVM_EXIT_CLGI 0x085 +#define SVM_EXIT_SKINIT 0x086 +#define SVM_EXIT_RDTSCP 0x087 +#define SVM_EXIT_ICEBP 0x088 +#define SVM_EXIT_WBINVD 0x089 +#define SVM_EXIT_NPF 0x400 + +#define SVM_EXIT_ERR -1 + +#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) // TS and MP + +#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda" +#define SVM_VMRUN ".byte 0x0f, 0x01, 0xd8" +#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb" +#define SVM_CLGI ".byte 0x0f, 0x01, 0xdd" +#define SVM_STGI ".byte 0x0f, 0x01, 0xdc" +#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf" + +#endif + diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c new file mode 100644 index 000000000000..bda7a7ae2167 --- /dev/null +++ b/drivers/kvm/vmx.c @@ -0,0 +1,2002 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * This module enables machines with Intel VT-x extensions to run virtual + * machines without emulation or binary translation. + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Avi Kivity + * Yaniv Kamay + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "kvm.h" +#include "vmx.h" +#include "kvm_vmx.h" +#include +#include +#include +#include + +#include "segment_descriptor.h" + +#define MSR_IA32_FEATURE_CONTROL 0x03a + +MODULE_AUTHOR("Qumranet"); +MODULE_LICENSE("GPL"); + +static DEFINE_PER_CPU(struct vmcs *, vmxarea); +static DEFINE_PER_CPU(struct vmcs *, current_vmcs); + +#ifdef __x86_64__ +#define HOST_IS_64 1 +#else +#define HOST_IS_64 0 +#endif + +static struct vmcs_descriptor { + int size; + int order; + u32 revision_id; +} vmcs_descriptor; + +#define VMX_SEGMENT_FIELD(seg) \ + [VCPU_SREG_##seg] = { \ + .selector = GUEST_##seg##_SELECTOR, \ + .base = GUEST_##seg##_BASE, \ + .limit = GUEST_##seg##_LIMIT, \ + .ar_bytes = GUEST_##seg##_AR_BYTES, \ + } + +static struct kvm_vmx_segment_field { + unsigned selector; + unsigned base; + unsigned limit; + unsigned ar_bytes; +} kvm_vmx_segment_fields[] = { + VMX_SEGMENT_FIELD(CS), + VMX_SEGMENT_FIELD(DS), + VMX_SEGMENT_FIELD(ES), + VMX_SEGMENT_FIELD(FS), + VMX_SEGMENT_FIELD(GS), + VMX_SEGMENT_FIELD(SS), + VMX_SEGMENT_FIELD(TR), + VMX_SEGMENT_FIELD(LDTR), +}; + +static const u32 vmx_msr_index[] = { +#ifdef __x86_64__ + MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, MSR_KERNEL_GS_BASE, +#endif + MSR_EFER, MSR_K6_STAR, +}; +#define NR_VMX_MSR (sizeof(vmx_msr_index) / sizeof(*vmx_msr_index)) + +struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr); + +static inline int is_page_fault(u32 intr_info) +{ + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | + INTR_INFO_VALID_MASK)) == + (INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK); +} + +static inline int is_external_interrupt(u32 intr_info) +{ + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) + == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); +} + +static void vmcs_clear(struct vmcs *vmcs) +{ + u64 phys_addr = __pa(vmcs); + u8 error; + + asm volatile (ASM_VMX_VMCLEAR_RAX "; setna %0" + : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) + : "cc", "memory"); + if (error) + printk(KERN_ERR "kvm: vmclear fail: %p/%llx\n", + vmcs, phys_addr); +} + +static void __vcpu_clear(void *arg) +{ + struct kvm_vcpu *vcpu = arg; + int cpu = smp_processor_id(); + + if (vcpu->cpu == cpu) + vmcs_clear(vcpu->vmcs); + if (per_cpu(current_vmcs, cpu) == vcpu->vmcs) + per_cpu(current_vmcs, cpu) = NULL; +} + +static unsigned long vmcs_readl(unsigned long field) +{ + unsigned long value; + + asm volatile (ASM_VMX_VMREAD_RDX_RAX + : "=a"(value) : "d"(field) : "cc"); + return value; +} + +static u16 vmcs_read16(unsigned long field) +{ + return vmcs_readl(field); +} + +static u32 vmcs_read32(unsigned long field) +{ + return vmcs_readl(field); +} + +static u64 vmcs_read64(unsigned long field) +{ +#ifdef __x86_64__ + return vmcs_readl(field); +#else + return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32); +#endif +} + +static void vmcs_writel(unsigned long field, unsigned long value) +{ + u8 error; + + asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0" + : "=q"(error) : "a"(value), "d"(field) : "cc" ); + if (error) + printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n", + field, value, vmcs_read32(VM_INSTRUCTION_ERROR)); +} + +static void vmcs_write16(unsigned long field, u16 value) +{ + vmcs_writel(field, value); +} + +static void vmcs_write32(unsigned long field, u32 value) +{ + vmcs_writel(field, value); +} + +static void vmcs_write64(unsigned long field, u64 value) +{ +#ifdef __x86_64__ + vmcs_writel(field, value); +#else + vmcs_writel(field, value); + asm volatile (""); + vmcs_writel(field+1, value >> 32); +#endif +} + +/* + * Switches to specified vcpu, until a matching vcpu_put(), but assumes + * vcpu mutex is already taken. + */ +static struct kvm_vcpu *vmx_vcpu_load(struct kvm_vcpu *vcpu) +{ + u64 phys_addr = __pa(vcpu->vmcs); + int cpu; + + cpu = get_cpu(); + + if (vcpu->cpu != cpu) { + smp_call_function(__vcpu_clear, vcpu, 0, 1); + vcpu->launched = 0; + } + + if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) { + u8 error; + + per_cpu(current_vmcs, cpu) = vcpu->vmcs; + asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0" + : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) + : "cc"); + if (error) + printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n", + vcpu->vmcs, phys_addr); + } + + if (vcpu->cpu != cpu) { + struct descriptor_table dt; + unsigned long sysenter_esp; + + vcpu->cpu = cpu; + /* + * Linux uses per-cpu TSS and GDT, so set these when switching + * processors. + */ + vmcs_writel(HOST_TR_BASE, read_tr_base()); /* 22.2.4 */ + get_gdt(&dt); + vmcs_writel(HOST_GDTR_BASE, dt.base); /* 22.2.4 */ + + rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); + vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ + } + return vcpu; +} + +static void vmx_vcpu_put(struct kvm_vcpu *vcpu) +{ + put_cpu(); +} + +static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) +{ + return vmcs_readl(GUEST_RFLAGS); +} + +static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) +{ + vmcs_writel(GUEST_RFLAGS, rflags); +} + +static void skip_emulated_instruction(struct kvm_vcpu *vcpu) +{ + unsigned long rip; + u32 interruptibility; + + rip = vmcs_readl(GUEST_RIP); + rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN); + vmcs_writel(GUEST_RIP, rip); + + /* + * We emulated an instruction, so temporary interrupt blocking + * should be removed, if set. + */ + interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + if (interruptibility & 3) + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, + interruptibility & ~3); +} + +static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) +{ + printk(KERN_DEBUG "inject_general_protection: rip 0x%lx\n", + vmcs_readl(GUEST_RIP)); + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + GP_VECTOR | + INTR_TYPE_EXCEPTION | + INTR_INFO_DELIEVER_CODE_MASK | + INTR_INFO_VALID_MASK); +} + +/* + * reads and returns guest's timestamp counter "register" + * guest_tsc = host_tsc + tsc_offset -- 21.3 + */ +static u64 guest_read_tsc(void) +{ + u64 host_tsc, tsc_offset; + + rdtscll(host_tsc); + tsc_offset = vmcs_read64(TSC_OFFSET); + return host_tsc + tsc_offset; +} + +/* + * writes 'guest_tsc' into guest's timestamp counter "register" + * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc + */ +static void guest_write_tsc(u64 guest_tsc) +{ + u64 host_tsc; + + rdtscll(host_tsc); + vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc); +} + +static void reload_tss(void) +{ +#ifndef __x86_64__ + + /* + * VT restores TR but not its size. Useless. + */ + struct descriptor_table gdt; + struct segment_descriptor *descs; + + get_gdt(&gdt); + descs = (void *)gdt.base; + descs[GDT_ENTRY_TSS].type = 9; /* available TSS */ + load_TR_desc(); +#endif +} + +/* + * Reads an msr value (of 'msr_index') into 'pdata'. + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) +{ + u64 data; + struct vmx_msr_entry *msr; + + if (!pdata) { + printk(KERN_ERR "BUG: get_msr called with NULL pdata\n"); + return -EINVAL; + } + + switch (msr_index) { +#ifdef __x86_64__ + case MSR_FS_BASE: + data = vmcs_readl(GUEST_FS_BASE); + break; + case MSR_GS_BASE: + data = vmcs_readl(GUEST_GS_BASE); + break; + case MSR_EFER: + data = vcpu->shadow_efer; + break; +#endif + case MSR_IA32_TIME_STAMP_COUNTER: + data = guest_read_tsc(); + break; + case MSR_IA32_SYSENTER_CS: + data = vmcs_read32(GUEST_SYSENTER_CS); + break; + case MSR_IA32_SYSENTER_EIP: + data = vmcs_read32(GUEST_SYSENTER_EIP); + break; + case MSR_IA32_SYSENTER_ESP: + data = vmcs_read32(GUEST_SYSENTER_ESP); + break; + case MSR_IA32_MC0_CTL: + case MSR_IA32_MCG_STATUS: + case MSR_IA32_MCG_CAP: + case MSR_IA32_MC0_MISC: + case MSR_IA32_MC0_MISC+4: + case MSR_IA32_MC0_MISC+8: + case MSR_IA32_MC0_MISC+12: + case MSR_IA32_MC0_MISC+16: + case MSR_IA32_UCODE_REV: + /* MTRR registers */ + case 0xfe: + case 0x200 ... 0x2ff: + data = 0; + break; + case MSR_IA32_APICBASE: + data = vcpu->apic_base; + break; + default: + msr = find_msr_entry(vcpu, msr_index); + if (!msr) { + printk(KERN_ERR "kvm: unhandled rdmsr: %x\n", msr_index); + return 1; + } + data = msr->data; + break; + } + + *pdata = data; + return 0; +} + +/* + * Writes msr value into into the appropriate "register". + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) +{ + struct vmx_msr_entry *msr; + switch (msr_index) { +#ifdef __x86_64__ + case MSR_FS_BASE: + vmcs_writel(GUEST_FS_BASE, data); + break; + case MSR_GS_BASE: + vmcs_writel(GUEST_GS_BASE, data); + break; +#endif + case MSR_IA32_SYSENTER_CS: + vmcs_write32(GUEST_SYSENTER_CS, data); + break; + case MSR_IA32_SYSENTER_EIP: + vmcs_write32(GUEST_SYSENTER_EIP, data); + break; + case MSR_IA32_SYSENTER_ESP: + vmcs_write32(GUEST_SYSENTER_ESP, data); + break; +#ifdef __x86_64 + case MSR_EFER: + set_efer(vcpu, data); + break; + case MSR_IA32_MC0_STATUS: + printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n" + , __FUNCTION__, data); + break; +#endif + case MSR_IA32_TIME_STAMP_COUNTER: { + guest_write_tsc(data); + break; + } + case MSR_IA32_UCODE_REV: + case MSR_IA32_UCODE_WRITE: + case 0x200 ... 0x2ff: /* MTRRs */ + break; + case MSR_IA32_APICBASE: + vcpu->apic_base = data; + break; + default: + msr = find_msr_entry(vcpu, msr_index); + if (!msr) { + printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr_index); + return 1; + } + msr->data = data; + break; + } + + return 0; +} + +/* + * Sync the rsp and rip registers into the vcpu structure. This allows + * registers to be accessed by indexing vcpu->regs. + */ +static void vcpu_load_rsp_rip(struct kvm_vcpu *vcpu) +{ + vcpu->regs[VCPU_REGS_RSP] = vmcs_readl(GUEST_RSP); + vcpu->rip = vmcs_readl(GUEST_RIP); +} + +/* + * Syncs rsp and rip back into the vmcs. Should be called after possible + * modification. + */ +static void vcpu_put_rsp_rip(struct kvm_vcpu *vcpu) +{ + vmcs_writel(GUEST_RSP, vcpu->regs[VCPU_REGS_RSP]); + vmcs_writel(GUEST_RIP, vcpu->rip); +} + +static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) +{ + unsigned long dr7 = 0x400; + u32 exception_bitmap; + int old_singlestep; + + exception_bitmap = vmcs_read32(EXCEPTION_BITMAP); + old_singlestep = vcpu->guest_debug.singlestep; + + vcpu->guest_debug.enabled = dbg->enabled; + if (vcpu->guest_debug.enabled) { + int i; + + dr7 |= 0x200; /* exact */ + for (i = 0; i < 4; ++i) { + if (!dbg->breakpoints[i].enabled) + continue; + vcpu->guest_debug.bp[i] = dbg->breakpoints[i].address; + dr7 |= 2 << (i*2); /* global enable */ + dr7 |= 0 << (i*4+16); /* execution breakpoint */ + } + + exception_bitmap |= (1u << 1); /* Trap debug exceptions */ + + vcpu->guest_debug.singlestep = dbg->singlestep; + } else { + exception_bitmap &= ~(1u << 1); /* Ignore debug exceptions */ + vcpu->guest_debug.singlestep = 0; + } + + if (old_singlestep && !vcpu->guest_debug.singlestep) { + unsigned long flags; + + flags = vmcs_readl(GUEST_RFLAGS); + flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF); + vmcs_writel(GUEST_RFLAGS, flags); + } + + vmcs_write32(EXCEPTION_BITMAP, exception_bitmap); + vmcs_writel(GUEST_DR7, dr7); + + return 0; +} + +static __init int cpu_has_kvm_support(void) +{ + unsigned long ecx = cpuid_ecx(1); + return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */ +} + +static __init int vmx_disabled_by_bios(void) +{ + u64 msr; + + rdmsrl(MSR_IA32_FEATURE_CONTROL, msr); + return (msr & 5) == 1; /* locked but not enabled */ +} + +static __init void hardware_enable(void *garbage) +{ + int cpu = raw_smp_processor_id(); + u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); + u64 old; + + rdmsrl(MSR_IA32_FEATURE_CONTROL, old); + if ((old & 5) == 0) + /* enable and lock */ + wrmsrl(MSR_IA32_FEATURE_CONTROL, old | 5); + write_cr4(read_cr4() | CR4_VMXE); /* FIXME: not cpu hotplug safe */ + asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr) + : "memory", "cc"); +} + +static void hardware_disable(void *garbage) +{ + asm volatile (ASM_VMX_VMXOFF : : : "cc"); +} + +static __init void setup_vmcs_descriptor(void) +{ + u32 vmx_msr_low, vmx_msr_high; + + rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high); + vmcs_descriptor.size = vmx_msr_high & 0x1fff; + vmcs_descriptor.order = get_order(vmcs_descriptor.size); + vmcs_descriptor.revision_id = vmx_msr_low; +}; + +static struct vmcs *alloc_vmcs_cpu(int cpu) +{ + int node = cpu_to_node(cpu); + struct page *pages; + struct vmcs *vmcs; + + pages = alloc_pages_node(node, GFP_KERNEL, vmcs_descriptor.order); + if (!pages) + return NULL; + vmcs = page_address(pages); + memset(vmcs, 0, vmcs_descriptor.size); + vmcs->revision_id = vmcs_descriptor.revision_id; /* vmcs revision id */ + return vmcs; +} + +static struct vmcs *alloc_vmcs(void) +{ + return alloc_vmcs_cpu(smp_processor_id()); +} + +static void free_vmcs(struct vmcs *vmcs) +{ + free_pages((unsigned long)vmcs, vmcs_descriptor.order); +} + +static __exit void free_kvm_area(void) +{ + int cpu; + + for_each_online_cpu(cpu) + free_vmcs(per_cpu(vmxarea, cpu)); +} + +extern struct vmcs *alloc_vmcs_cpu(int cpu); + +static __init int alloc_kvm_area(void) +{ + int cpu; + + for_each_online_cpu(cpu) { + struct vmcs *vmcs; + + vmcs = alloc_vmcs_cpu(cpu); + if (!vmcs) { + free_kvm_area(); + return -ENOMEM; + } + + per_cpu(vmxarea, cpu) = vmcs; + } + return 0; +} + +static __init int hardware_setup(void) +{ + setup_vmcs_descriptor(); + return alloc_kvm_area(); +} + +static __exit void hardware_unsetup(void) +{ + free_kvm_area(); +} + +static void update_exception_bitmap(struct kvm_vcpu *vcpu) +{ + if (vcpu->rmode.active) + vmcs_write32(EXCEPTION_BITMAP, ~0); + else + vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR); +} + +static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + + if (vmcs_readl(sf->base) == save->base) { + vmcs_write16(sf->selector, save->selector); + vmcs_writel(sf->base, save->base); + vmcs_write32(sf->limit, save->limit); + vmcs_write32(sf->ar_bytes, save->ar); + } else { + u32 dpl = (vmcs_read16(sf->selector) & SELECTOR_RPL_MASK) + << AR_DPL_SHIFT; + vmcs_write32(sf->ar_bytes, 0x93 | dpl); + } +} + +static void enter_pmode(struct kvm_vcpu *vcpu) +{ + unsigned long flags; + + vcpu->rmode.active = 0; + + vmcs_writel(GUEST_TR_BASE, vcpu->rmode.tr.base); + vmcs_write32(GUEST_TR_LIMIT, vcpu->rmode.tr.limit); + vmcs_write32(GUEST_TR_AR_BYTES, vcpu->rmode.tr.ar); + + flags = vmcs_readl(GUEST_RFLAGS); + flags &= ~(IOPL_MASK | X86_EFLAGS_VM); + flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT); + vmcs_writel(GUEST_RFLAGS, flags); + + vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~CR4_VME_MASK) | + (vmcs_readl(CR4_READ_SHADOW) & CR4_VME_MASK)); + + update_exception_bitmap(vcpu); + + fix_pmode_dataseg(VCPU_SREG_ES, &vcpu->rmode.es); + fix_pmode_dataseg(VCPU_SREG_DS, &vcpu->rmode.ds); + fix_pmode_dataseg(VCPU_SREG_GS, &vcpu->rmode.gs); + fix_pmode_dataseg(VCPU_SREG_FS, &vcpu->rmode.fs); + + vmcs_write16(GUEST_SS_SELECTOR, 0); + vmcs_write32(GUEST_SS_AR_BYTES, 0x93); + + vmcs_write16(GUEST_CS_SELECTOR, + vmcs_read16(GUEST_CS_SELECTOR) & ~SELECTOR_RPL_MASK); + vmcs_write32(GUEST_CS_AR_BYTES, 0x9b); +} + +static int rmode_tss_base(struct kvm* kvm) +{ + gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3; + return base_gfn << PAGE_SHIFT; +} + +static void fix_rmode_seg(int seg, struct kvm_save_segment *save) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + + save->selector = vmcs_read16(sf->selector); + save->base = vmcs_readl(sf->base); + save->limit = vmcs_read32(sf->limit); + save->ar = vmcs_read32(sf->ar_bytes); + vmcs_write16(sf->selector, vmcs_readl(sf->base) >> 4); + vmcs_write32(sf->limit, 0xffff); + vmcs_write32(sf->ar_bytes, 0xf3); +} + +static void enter_rmode(struct kvm_vcpu *vcpu) +{ + unsigned long flags; + + vcpu->rmode.active = 1; + + vcpu->rmode.tr.base = vmcs_readl(GUEST_TR_BASE); + vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm)); + + vcpu->rmode.tr.limit = vmcs_read32(GUEST_TR_LIMIT); + vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1); + + vcpu->rmode.tr.ar = vmcs_read32(GUEST_TR_AR_BYTES); + vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); + + flags = vmcs_readl(GUEST_RFLAGS); + vcpu->rmode.save_iopl = (flags & IOPL_MASK) >> IOPL_SHIFT; + + flags |= IOPL_MASK | X86_EFLAGS_VM; + + vmcs_writel(GUEST_RFLAGS, flags); + vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | CR4_VME_MASK); + update_exception_bitmap(vcpu); + + vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4); + vmcs_write32(GUEST_SS_LIMIT, 0xffff); + vmcs_write32(GUEST_SS_AR_BYTES, 0xf3); + + vmcs_write32(GUEST_CS_AR_BYTES, 0xf3); + vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4); + + fix_rmode_seg(VCPU_SREG_ES, &vcpu->rmode.es); + fix_rmode_seg(VCPU_SREG_DS, &vcpu->rmode.ds); + fix_rmode_seg(VCPU_SREG_GS, &vcpu->rmode.gs); + fix_rmode_seg(VCPU_SREG_FS, &vcpu->rmode.fs); +} + +#ifdef __x86_64__ + +static void enter_lmode(struct kvm_vcpu *vcpu) +{ + u32 guest_tr_ar; + + guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES); + if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) { + printk(KERN_DEBUG "%s: tss fixup for long mode. \n", + __FUNCTION__); + vmcs_write32(GUEST_TR_AR_BYTES, + (guest_tr_ar & ~AR_TYPE_MASK) + | AR_TYPE_BUSY_64_TSS); + } + + vcpu->shadow_efer |= EFER_LMA; + + find_msr_entry(vcpu, MSR_EFER)->data |= EFER_LMA | EFER_LME; + vmcs_write32(VM_ENTRY_CONTROLS, + vmcs_read32(VM_ENTRY_CONTROLS) + | VM_ENTRY_CONTROLS_IA32E_MASK); +} + +static void exit_lmode(struct kvm_vcpu *vcpu) +{ + vcpu->shadow_efer &= ~EFER_LMA; + + vmcs_write32(VM_ENTRY_CONTROLS, + vmcs_read32(VM_ENTRY_CONTROLS) + & ~VM_ENTRY_CONTROLS_IA32E_MASK); +} + +#endif + +static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) +{ + if (vcpu->rmode.active && (cr0 & CR0_PE_MASK)) + enter_pmode(vcpu); + + if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK)) + enter_rmode(vcpu); + +#ifdef __x86_64__ + if (vcpu->shadow_efer & EFER_LME) { + if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) + enter_lmode(vcpu); + if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK)) + exit_lmode(vcpu); + } +#endif + + vmcs_writel(CR0_READ_SHADOW, cr0); + vmcs_writel(GUEST_CR0, + (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON); + vcpu->cr0 = cr0; +} + +/* + * Used when restoring the VM to avoid corrupting segment registers + */ +static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0) +{ + vcpu->rmode.active = ((cr0 & CR0_PE_MASK) == 0); + update_exception_bitmap(vcpu); + vmcs_writel(CR0_READ_SHADOW, cr0); + vmcs_writel(GUEST_CR0, + (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON); + vcpu->cr0 = cr0; +} + +static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) +{ + vmcs_writel(GUEST_CR3, cr3); +} + +static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) +{ + vmcs_writel(CR4_READ_SHADOW, cr4); + vmcs_writel(GUEST_CR4, cr4 | (vcpu->rmode.active ? + KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON)); + vcpu->cr4 = cr4; +} + +#ifdef __x86_64__ + +static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) +{ + struct vmx_msr_entry *msr = find_msr_entry(vcpu, MSR_EFER); + + vcpu->shadow_efer = efer; + if (efer & EFER_LMA) { + vmcs_write32(VM_ENTRY_CONTROLS, + vmcs_read32(VM_ENTRY_CONTROLS) | + VM_ENTRY_CONTROLS_IA32E_MASK); + msr->data = efer; + + } else { + vmcs_write32(VM_ENTRY_CONTROLS, + vmcs_read32(VM_ENTRY_CONTROLS) & + ~VM_ENTRY_CONTROLS_IA32E_MASK); + + msr->data = efer & ~EFER_LME; + } +} + +#endif + +static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + + return vmcs_readl(sf->base); +} + +static void vmx_get_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + u32 ar; + + var->base = vmcs_readl(sf->base); + var->limit = vmcs_read32(sf->limit); + var->selector = vmcs_read16(sf->selector); + ar = vmcs_read32(sf->ar_bytes); + if (ar & AR_UNUSABLE_MASK) + ar = 0; + var->type = ar & 15; + var->s = (ar >> 4) & 1; + var->dpl = (ar >> 5) & 3; + var->present = (ar >> 7) & 1; + var->avl = (ar >> 12) & 1; + var->l = (ar >> 13) & 1; + var->db = (ar >> 14) & 1; + var->g = (ar >> 15) & 1; + var->unusable = (ar >> 16) & 1; +} + +static void vmx_set_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + u32 ar; + + vmcs_writel(sf->base, var->base); + vmcs_write32(sf->limit, var->limit); + vmcs_write16(sf->selector, var->selector); + if (var->unusable) + ar = 1 << 16; + else { + ar = var->type & 15; + ar |= (var->s & 1) << 4; + ar |= (var->dpl & 3) << 5; + ar |= (var->present & 1) << 7; + ar |= (var->avl & 1) << 12; + ar |= (var->l & 1) << 13; + ar |= (var->db & 1) << 14; + ar |= (var->g & 1) << 15; + } + vmcs_write32(sf->ar_bytes, ar); +} + +static int vmx_is_long_mode(struct kvm_vcpu *vcpu) +{ + return vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_CONTROLS_IA32E_MASK; +} + +static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) +{ + u32 ar = vmcs_read32(GUEST_CS_AR_BYTES); + + *db = (ar >> 14) & 1; + *l = (ar >> 13) & 1; +} + +static void vmx_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + dt->limit = vmcs_read32(GUEST_IDTR_LIMIT); + dt->base = vmcs_readl(GUEST_IDTR_BASE); +} + +static void vmx_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + vmcs_write32(GUEST_IDTR_LIMIT, dt->limit); + vmcs_writel(GUEST_IDTR_BASE, dt->base); +} + +static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + dt->limit = vmcs_read32(GUEST_GDTR_LIMIT); + dt->base = vmcs_readl(GUEST_GDTR_BASE); +} + +static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + vmcs_write32(GUEST_GDTR_LIMIT, dt->limit); + vmcs_writel(GUEST_GDTR_BASE, dt->base); +} + +static int init_rmode_tss(struct kvm* kvm) +{ + struct page *p1, *p2, *p3; + gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT; + char *page; + + p1 = _gfn_to_page(kvm, fn++); + p2 = _gfn_to_page(kvm, fn++); + p3 = _gfn_to_page(kvm, fn); + + if (!p1 || !p2 || !p3) { + kvm_printf(kvm,"%s: gfn_to_page failed\n", __FUNCTION__); + return 0; + } + + page = kmap_atomic(p1, KM_USER0); + memset(page, 0, PAGE_SIZE); + *(u16*)(page + 0x66) = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE; + kunmap_atomic(page, KM_USER0); + + page = kmap_atomic(p2, KM_USER0); + memset(page, 0, PAGE_SIZE); + kunmap_atomic(page, KM_USER0); + + page = kmap_atomic(p3, KM_USER0); + memset(page, 0, PAGE_SIZE); + *(page + RMODE_TSS_SIZE - 2 * PAGE_SIZE - 1) = ~0; + kunmap_atomic(page, KM_USER0); + + return 1; +} + +static void vmcs_write32_fixedbits(u32 msr, u32 vmcs_field, u32 val) +{ + u32 msr_high, msr_low; + + rdmsr(msr, msr_low, msr_high); + + val &= msr_high; + val |= msr_low; + vmcs_write32(vmcs_field, val); +} + +static void seg_setup(int seg) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + + vmcs_write16(sf->selector, 0); + vmcs_writel(sf->base, 0); + vmcs_write32(sf->limit, 0xffff); + vmcs_write32(sf->ar_bytes, 0x93); +} + +/* + * Sets up the vmcs for emulated real mode. + */ +static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) +{ + u32 host_sysenter_cs; + u32 junk; + unsigned long a; + struct descriptor_table dt; + int i; + int ret = 0; + int nr_good_msrs; + extern asmlinkage void kvm_vmx_return(void); + + if (!init_rmode_tss(vcpu->kvm)) { + ret = -ENOMEM; + goto out; + } + + memset(vcpu->regs, 0, sizeof(vcpu->regs)); + vcpu->regs[VCPU_REGS_RDX] = get_rdx_init_val(); + vcpu->cr8 = 0; + vcpu->apic_base = 0xfee00000 | + /*for vcpu 0*/ MSR_IA32_APICBASE_BSP | + MSR_IA32_APICBASE_ENABLE; + + fx_init(vcpu); + + /* + * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode + * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4. Sigh. + */ + vmcs_write16(GUEST_CS_SELECTOR, 0xf000); + vmcs_writel(GUEST_CS_BASE, 0x000f0000); + vmcs_write32(GUEST_CS_LIMIT, 0xffff); + vmcs_write32(GUEST_CS_AR_BYTES, 0x9b); + + seg_setup(VCPU_SREG_DS); + seg_setup(VCPU_SREG_ES); + seg_setup(VCPU_SREG_FS); + seg_setup(VCPU_SREG_GS); + seg_setup(VCPU_SREG_SS); + + vmcs_write16(GUEST_TR_SELECTOR, 0); + vmcs_writel(GUEST_TR_BASE, 0); + vmcs_write32(GUEST_TR_LIMIT, 0xffff); + vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); + + vmcs_write16(GUEST_LDTR_SELECTOR, 0); + vmcs_writel(GUEST_LDTR_BASE, 0); + vmcs_write32(GUEST_LDTR_LIMIT, 0xffff); + vmcs_write32(GUEST_LDTR_AR_BYTES, 0x00082); + + vmcs_write32(GUEST_SYSENTER_CS, 0); + vmcs_writel(GUEST_SYSENTER_ESP, 0); + vmcs_writel(GUEST_SYSENTER_EIP, 0); + + vmcs_writel(GUEST_RFLAGS, 0x02); + vmcs_writel(GUEST_RIP, 0xfff0); + vmcs_writel(GUEST_RSP, 0); + + vmcs_writel(GUEST_CR3, 0); + + //todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0 + vmcs_writel(GUEST_DR7, 0x400); + + vmcs_writel(GUEST_GDTR_BASE, 0); + vmcs_write32(GUEST_GDTR_LIMIT, 0xffff); + + vmcs_writel(GUEST_IDTR_BASE, 0); + vmcs_write32(GUEST_IDTR_LIMIT, 0xffff); + + vmcs_write32(GUEST_ACTIVITY_STATE, 0); + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0); + vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0); + + /* I/O */ + vmcs_write64(IO_BITMAP_A, 0); + vmcs_write64(IO_BITMAP_B, 0); + + guest_write_tsc(0); + + vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ + + /* Special registers */ + vmcs_write64(GUEST_IA32_DEBUGCTL, 0); + + /* Control */ + vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS_MSR, + PIN_BASED_VM_EXEC_CONTROL, + PIN_BASED_EXT_INTR_MASK /* 20.6.1 */ + | PIN_BASED_NMI_EXITING /* 20.6.1 */ + ); + vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS_MSR, + CPU_BASED_VM_EXEC_CONTROL, + CPU_BASED_HLT_EXITING /* 20.6.2 */ + | CPU_BASED_CR8_LOAD_EXITING /* 20.6.2 */ + | CPU_BASED_CR8_STORE_EXITING /* 20.6.2 */ + | CPU_BASED_UNCOND_IO_EXITING /* 20.6.2 */ + | CPU_BASED_INVDPG_EXITING + | CPU_BASED_MOV_DR_EXITING + | CPU_BASED_USE_TSC_OFFSETING /* 21.3 */ + ); + + vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR); + vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); + vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); + vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */ + + vmcs_writel(HOST_CR0, read_cr0()); /* 22.2.3 */ + vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */ + vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ + + vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ + vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ + vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */ + vmcs_write16(HOST_FS_SELECTOR, read_fs()); /* 22.2.4 */ + vmcs_write16(HOST_GS_SELECTOR, read_gs()); /* 22.2.4 */ + vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ +#ifdef __x86_64__ + rdmsrl(MSR_FS_BASE, a); + vmcs_writel(HOST_FS_BASE, a); /* 22.2.4 */ + rdmsrl(MSR_GS_BASE, a); + vmcs_writel(HOST_GS_BASE, a); /* 22.2.4 */ +#else + vmcs_writel(HOST_FS_BASE, 0); /* 22.2.4 */ + vmcs_writel(HOST_GS_BASE, 0); /* 22.2.4 */ +#endif + + vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8); /* 22.2.4 */ + + get_idt(&dt); + vmcs_writel(HOST_IDTR_BASE, dt.base); /* 22.2.4 */ + + + vmcs_writel(HOST_RIP, (unsigned long)kvm_vmx_return); /* 22.2.5 */ + + rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk); + vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs); + rdmsrl(MSR_IA32_SYSENTER_ESP, a); + vmcs_writel(HOST_IA32_SYSENTER_ESP, a); /* 22.2.3 */ + rdmsrl(MSR_IA32_SYSENTER_EIP, a); + vmcs_writel(HOST_IA32_SYSENTER_EIP, a); /* 22.2.3 */ + + ret = -ENOMEM; + vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!vcpu->guest_msrs) + goto out; + vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!vcpu->host_msrs) + goto out_free_guest_msrs; + + for (i = 0; i < NR_VMX_MSR; ++i) { + u32 index = vmx_msr_index[i]; + u32 data_low, data_high; + u64 data; + int j = vcpu->nmsrs; + + if (rdmsr_safe(index, &data_low, &data_high) < 0) + continue; + data = data_low | ((u64)data_high << 32); + vcpu->host_msrs[j].index = index; + vcpu->host_msrs[j].reserved = 0; + vcpu->host_msrs[j].data = data; + vcpu->guest_msrs[j] = vcpu->host_msrs[j]; + ++vcpu->nmsrs; + } + printk(KERN_DEBUG "kvm: msrs: %d\n", vcpu->nmsrs); + + nr_good_msrs = vcpu->nmsrs - NR_BAD_MSRS; + vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR, + virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS)); + vmcs_writel(VM_EXIT_MSR_STORE_ADDR, + virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS)); + vmcs_writel(VM_EXIT_MSR_LOAD_ADDR, + virt_to_phys(vcpu->host_msrs + NR_BAD_MSRS)); + vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS_MSR, VM_EXIT_CONTROLS, + (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */ + vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */ + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ + + + /* 22.2.1, 20.8.1 */ + vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS_MSR, + VM_ENTRY_CONTROLS, 0); + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ + + vmcs_writel(VIRTUAL_APIC_PAGE_ADDR, 0); + vmcs_writel(TPR_THRESHOLD, 0); + + vmcs_writel(CR0_GUEST_HOST_MASK, KVM_GUEST_CR0_MASK); + vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK); + + vcpu->cr0 = 0x60000010; + vmx_set_cr0(vcpu, vcpu->cr0); // enter rmode + vmx_set_cr4(vcpu, 0); +#ifdef __x86_64__ + vmx_set_efer(vcpu, 0); +#endif + + return 0; + +out_free_guest_msrs: + kfree(vcpu->guest_msrs); +out: + return ret; +} + +static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) +{ + u16 ent[2]; + u16 cs; + u16 ip; + unsigned long flags; + unsigned long ss_base = vmcs_readl(GUEST_SS_BASE); + u16 sp = vmcs_readl(GUEST_RSP); + u32 ss_limit = vmcs_read32(GUEST_SS_LIMIT); + + if (sp > ss_limit || sp - 6 > sp) { + vcpu_printf(vcpu, "%s: #SS, rsp 0x%lx ss 0x%lx limit 0x%x\n", + __FUNCTION__, + vmcs_readl(GUEST_RSP), + vmcs_readl(GUEST_SS_BASE), + vmcs_read32(GUEST_SS_LIMIT)); + return; + } + + if (kvm_read_guest(vcpu, irq * sizeof(ent), sizeof(ent), &ent) != + sizeof(ent)) { + vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__); + return; + } + + flags = vmcs_readl(GUEST_RFLAGS); + cs = vmcs_readl(GUEST_CS_BASE) >> 4; + ip = vmcs_readl(GUEST_RIP); + + + if (kvm_write_guest(vcpu, ss_base + sp - 2, 2, &flags) != 2 || + kvm_write_guest(vcpu, ss_base + sp - 4, 2, &cs) != 2 || + kvm_write_guest(vcpu, ss_base + sp - 6, 2, &ip) != 2) { + vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__); + return; + } + + vmcs_writel(GUEST_RFLAGS, flags & + ~( X86_EFLAGS_IF | X86_EFLAGS_AC | X86_EFLAGS_TF)); + vmcs_write16(GUEST_CS_SELECTOR, ent[1]) ; + vmcs_writel(GUEST_CS_BASE, ent[1] << 4); + vmcs_writel(GUEST_RIP, ent[0]); + vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6)); +} + +static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) +{ + int word_index = __ffs(vcpu->irq_summary); + int bit_index = __ffs(vcpu->irq_pending[word_index]); + int irq = word_index * BITS_PER_LONG + bit_index; + + clear_bit(bit_index, &vcpu->irq_pending[word_index]); + if (!vcpu->irq_pending[word_index]) + clear_bit(word_index, &vcpu->irq_summary); + + if (vcpu->rmode.active) { + inject_rmode_irq(vcpu, irq); + return; + } + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); +} + +static void kvm_try_inject_irq(struct kvm_vcpu *vcpu) +{ + if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) + && (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0) + /* + * Interrupts enabled, and not blocked by sti or mov ss. Good. + */ + kvm_do_inject_irq(vcpu); + else + /* + * Interrupts blocked. Wait for unblock. + */ + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, + vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) + | CPU_BASED_VIRTUAL_INTR_PENDING); +} + +static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu) +{ + struct kvm_guest_debug *dbg = &vcpu->guest_debug; + + set_debugreg(dbg->bp[0], 0); + set_debugreg(dbg->bp[1], 1); + set_debugreg(dbg->bp[2], 2); + set_debugreg(dbg->bp[3], 3); + + if (dbg->singlestep) { + unsigned long flags; + + flags = vmcs_readl(GUEST_RFLAGS); + flags |= X86_EFLAGS_TF | X86_EFLAGS_RF; + vmcs_writel(GUEST_RFLAGS, flags); + } +} + +static int handle_rmode_exception(struct kvm_vcpu *vcpu, + int vec, u32 err_code) +{ + if (!vcpu->rmode.active) + return 0; + + if (vec == GP_VECTOR && err_code == 0) + if (emulate_instruction(vcpu, NULL, 0, 0) == EMULATE_DONE) + return 1; + return 0; +} + +static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 intr_info, error_code; + unsigned long cr2, rip; + u32 vect_info; + enum emulation_result er; + + vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); + intr_info = vmcs_read32(VM_EXIT_INTR_INFO); + + if ((vect_info & VECTORING_INFO_VALID_MASK) && + !is_page_fault(intr_info)) { + printk(KERN_ERR "%s: unexpected, vectoring info 0x%x " + "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info); + } + + if (is_external_interrupt(vect_info)) { + int irq = vect_info & VECTORING_INFO_VECTOR_MASK; + set_bit(irq, vcpu->irq_pending); + set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary); + } + + if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */ + asm ("int $2"); + return 1; + } + error_code = 0; + rip = vmcs_readl(GUEST_RIP); + if (intr_info & INTR_INFO_DELIEVER_CODE_MASK) + error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE); + if (is_page_fault(intr_info)) { + cr2 = vmcs_readl(EXIT_QUALIFICATION); + + spin_lock(&vcpu->kvm->lock); + if (!vcpu->mmu.page_fault(vcpu, cr2, error_code)) { + spin_unlock(&vcpu->kvm->lock); + return 1; + } + + er = emulate_instruction(vcpu, kvm_run, cr2, error_code); + spin_unlock(&vcpu->kvm->lock); + + switch (er) { + case EMULATE_DONE: + return 1; + case EMULATE_DO_MMIO: + ++kvm_stat.mmio_exits; + kvm_run->exit_reason = KVM_EXIT_MMIO; + return 0; + case EMULATE_FAIL: + vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__); + break; + default: + BUG(); + } + } + + if (vcpu->rmode.active && + handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK, + error_code)) + return 1; + + if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) == (INTR_TYPE_EXCEPTION | 1)) { + kvm_run->exit_reason = KVM_EXIT_DEBUG; + return 0; + } + kvm_run->exit_reason = KVM_EXIT_EXCEPTION; + kvm_run->ex.exception = intr_info & INTR_INFO_VECTOR_MASK; + kvm_run->ex.error_code = error_code; + return 0; +} + +static int handle_external_interrupt(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + ++kvm_stat.irq_exits; + return 1; +} + + +static int get_io_count(struct kvm_vcpu *vcpu, u64 *count) +{ + u64 inst; + gva_t rip; + int countr_size; + int i, n; + + if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_VM)) { + countr_size = 2; + } else { + u32 cs_ar = vmcs_read32(GUEST_CS_AR_BYTES); + + countr_size = (cs_ar & AR_L_MASK) ? 8: + (cs_ar & AR_DB_MASK) ? 4: 2; + } + + rip = vmcs_readl(GUEST_RIP); + if (countr_size != 8) + rip += vmcs_readl(GUEST_CS_BASE); + + n = kvm_read_guest(vcpu, rip, sizeof(inst), &inst); + + for (i = 0; i < n; i++) { + switch (((u8*)&inst)[i]) { + case 0xf0: + case 0xf2: + case 0xf3: + case 0x2e: + case 0x36: + case 0x3e: + case 0x26: + case 0x64: + case 0x65: + case 0x66: + break; + case 0x67: + countr_size = (countr_size == 2) ? 4: (countr_size >> 1); + default: + goto done; + } + } + return 0; +done: + countr_size *= 8; + *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size)); + return 1; +} + +static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u64 exit_qualification; + + ++kvm_stat.io_exits; + exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + kvm_run->exit_reason = KVM_EXIT_IO; + if (exit_qualification & 8) + kvm_run->io.direction = KVM_EXIT_IO_IN; + else + kvm_run->io.direction = KVM_EXIT_IO_OUT; + kvm_run->io.size = (exit_qualification & 7) + 1; + kvm_run->io.string = (exit_qualification & 16) != 0; + kvm_run->io.string_down + = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; + kvm_run->io.rep = (exit_qualification & 32) != 0; + kvm_run->io.port = exit_qualification >> 16; + if (kvm_run->io.string) { + if (!get_io_count(vcpu, &kvm_run->io.count)) + return 1; + kvm_run->io.address = vmcs_readl(GUEST_LINEAR_ADDRESS); + } else + kvm_run->io.value = vcpu->regs[VCPU_REGS_RAX]; /* rax */ + return 0; +} + +static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u64 address = vmcs_read64(EXIT_QUALIFICATION); + int instruction_length = vmcs_read32(VM_EXIT_INSTRUCTION_LEN); + spin_lock(&vcpu->kvm->lock); + vcpu->mmu.inval_page(vcpu, address); + spin_unlock(&vcpu->kvm->lock); + vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP) + instruction_length); + return 1; +} + +static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u64 exit_qualification; + int cr; + int reg; + + exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + cr = exit_qualification & 15; + reg = (exit_qualification >> 8) & 15; + switch ((exit_qualification >> 4) & 3) { + case 0: /* mov to cr */ + switch (cr) { + case 0: + vcpu_load_rsp_rip(vcpu); + set_cr0(vcpu, vcpu->regs[reg]); + skip_emulated_instruction(vcpu); + return 1; + case 3: + vcpu_load_rsp_rip(vcpu); + set_cr3(vcpu, vcpu->regs[reg]); + skip_emulated_instruction(vcpu); + return 1; + case 4: + vcpu_load_rsp_rip(vcpu); + set_cr4(vcpu, vcpu->regs[reg]); + skip_emulated_instruction(vcpu); + return 1; + case 8: + vcpu_load_rsp_rip(vcpu); + set_cr8(vcpu, vcpu->regs[reg]); + skip_emulated_instruction(vcpu); + return 1; + }; + break; + case 1: /*mov from cr*/ + switch (cr) { + case 3: + vcpu_load_rsp_rip(vcpu); + vcpu->regs[reg] = vcpu->cr3; + vcpu_put_rsp_rip(vcpu); + skip_emulated_instruction(vcpu); + return 1; + case 8: + printk(KERN_DEBUG "handle_cr: read CR8 " + "cpu erratum AA15\n"); + vcpu_load_rsp_rip(vcpu); + vcpu->regs[reg] = vcpu->cr8; + vcpu_put_rsp_rip(vcpu); + skip_emulated_instruction(vcpu); + return 1; + } + break; + case 3: /* lmsw */ + lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f); + + skip_emulated_instruction(vcpu); + return 1; + default: + break; + } + kvm_run->exit_reason = 0; + printk(KERN_ERR "kvm: unhandled control register: op %d cr %d\n", + (int)(exit_qualification >> 4) & 3, cr); + return 0; +} + +static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u64 exit_qualification; + unsigned long val; + int dr, reg; + + /* + * FIXME: this code assumes the host is debugging the guest. + * need to deal with guest debugging itself too. + */ + exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + dr = exit_qualification & 7; + reg = (exit_qualification >> 8) & 15; + vcpu_load_rsp_rip(vcpu); + if (exit_qualification & 16) { + /* mov from dr */ + switch (dr) { + case 6: + val = 0xffff0ff0; + break; + case 7: + val = 0x400; + break; + default: + val = 0; + } + vcpu->regs[reg] = val; + } else { + /* mov to dr */ + } + vcpu_put_rsp_rip(vcpu); + skip_emulated_instruction(vcpu); + return 1; +} + +static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + kvm_run->exit_reason = KVM_EXIT_CPUID; + return 0; +} + +static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 ecx = vcpu->regs[VCPU_REGS_RCX]; + u64 data; + + if (vmx_get_msr(vcpu, ecx, &data)) { + vmx_inject_gp(vcpu, 0); + return 1; + } + + /* FIXME: handling of bits 32:63 of rax, rdx */ + vcpu->regs[VCPU_REGS_RAX] = data & -1u; + vcpu->regs[VCPU_REGS_RDX] = (data >> 32) & -1u; + skip_emulated_instruction(vcpu); + return 1; +} + +static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 ecx = vcpu->regs[VCPU_REGS_RCX]; + u64 data = (vcpu->regs[VCPU_REGS_RAX] & -1u) + | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32); + + if (vmx_set_msr(vcpu, ecx, data) != 0) { + vmx_inject_gp(vcpu, 0); + return 1; + } + + skip_emulated_instruction(vcpu); + return 1; +} + +static int handle_interrupt_window(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + /* Turn off interrupt window reporting. */ + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, + vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) + & ~CPU_BASED_VIRTUAL_INTR_PENDING); + return 1; +} + +static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + skip_emulated_instruction(vcpu); + if (vcpu->irq_summary && (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)) + return 1; + + kvm_run->exit_reason = KVM_EXIT_HLT; + return 0; +} + +/* + * The exit handlers return 1 if the exit was handled fully and guest execution + * may resume. Otherwise they set the kvm_run parameter to indicate what needs + * to be done to userspace and return 0. + */ +static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) = { + [EXIT_REASON_EXCEPTION_NMI] = handle_exception, + [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, + [EXIT_REASON_IO_INSTRUCTION] = handle_io, + [EXIT_REASON_INVLPG] = handle_invlpg, + [EXIT_REASON_CR_ACCESS] = handle_cr, + [EXIT_REASON_DR_ACCESS] = handle_dr, + [EXIT_REASON_CPUID] = handle_cpuid, + [EXIT_REASON_MSR_READ] = handle_rdmsr, + [EXIT_REASON_MSR_WRITE] = handle_wrmsr, + [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, + [EXIT_REASON_HLT] = handle_halt, +}; + +static const int kvm_vmx_max_exit_handlers = + sizeof(kvm_vmx_exit_handlers) / sizeof(*kvm_vmx_exit_handlers); + +/* + * The guest has exited. See if we can fix it or if we need userspace + * assistance. + */ +static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) +{ + u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); + u32 exit_reason = vmcs_read32(VM_EXIT_REASON); + + if ( (vectoring_info & VECTORING_INFO_VALID_MASK) && + exit_reason != EXIT_REASON_EXCEPTION_NMI ) + printk(KERN_WARNING "%s: unexpected, valid vectoring info and " + "exit reason is 0x%x\n", __FUNCTION__, exit_reason); + kvm_run->instruction_length = vmcs_read32(VM_EXIT_INSTRUCTION_LEN); + if (exit_reason < kvm_vmx_max_exit_handlers + && kvm_vmx_exit_handlers[exit_reason]) + return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run); + else { + kvm_run->exit_reason = KVM_EXIT_UNKNOWN; + kvm_run->hw.hardware_exit_reason = exit_reason; + } + return 0; +} + +static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u8 fail; + u16 fs_sel, gs_sel, ldt_sel; + int fs_gs_ldt_reload_needed; + +again: + /* + * Set host fs and gs selectors. Unfortunately, 22.2.3 does not + * allow segment selectors with cpl > 0 or ti == 1. + */ + fs_sel = read_fs(); + gs_sel = read_gs(); + ldt_sel = read_ldt(); + fs_gs_ldt_reload_needed = (fs_sel & 7) | (gs_sel & 7) | ldt_sel; + if (!fs_gs_ldt_reload_needed) { + vmcs_write16(HOST_FS_SELECTOR, fs_sel); + vmcs_write16(HOST_GS_SELECTOR, gs_sel); + } else { + vmcs_write16(HOST_FS_SELECTOR, 0); + vmcs_write16(HOST_GS_SELECTOR, 0); + } + +#ifdef __x86_64__ + vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE)); + vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE)); +#else + vmcs_writel(HOST_FS_BASE, segment_base(fs_sel)); + vmcs_writel(HOST_GS_BASE, segment_base(gs_sel)); +#endif + + if (vcpu->irq_summary && + !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK)) + kvm_try_inject_irq(vcpu); + + if (vcpu->guest_debug.enabled) + kvm_guest_debug_pre(vcpu); + + fx_save(vcpu->host_fx_image); + fx_restore(vcpu->guest_fx_image); + + save_msrs(vcpu->host_msrs, vcpu->nmsrs); + load_msrs(vcpu->guest_msrs, NR_BAD_MSRS); + + asm ( + /* Store host registers */ + "pushf \n\t" +#ifdef __x86_64__ + "push %%rax; push %%rbx; push %%rdx;" + "push %%rsi; push %%rdi; push %%rbp;" + "push %%r8; push %%r9; push %%r10; push %%r11;" + "push %%r12; push %%r13; push %%r14; push %%r15;" + "push %%rcx \n\t" + ASM_VMX_VMWRITE_RSP_RDX "\n\t" +#else + "pusha; push %%ecx \n\t" + ASM_VMX_VMWRITE_RSP_RDX "\n\t" +#endif + /* Check if vmlaunch of vmresume is needed */ + "cmp $0, %1 \n\t" + /* Load guest registers. Don't clobber flags. */ +#ifdef __x86_64__ + "mov %c[cr2](%3), %%rax \n\t" + "mov %%rax, %%cr2 \n\t" + "mov %c[rax](%3), %%rax \n\t" + "mov %c[rbx](%3), %%rbx \n\t" + "mov %c[rdx](%3), %%rdx \n\t" + "mov %c[rsi](%3), %%rsi \n\t" + "mov %c[rdi](%3), %%rdi \n\t" + "mov %c[rbp](%3), %%rbp \n\t" + "mov %c[r8](%3), %%r8 \n\t" + "mov %c[r9](%3), %%r9 \n\t" + "mov %c[r10](%3), %%r10 \n\t" + "mov %c[r11](%3), %%r11 \n\t" + "mov %c[r12](%3), %%r12 \n\t" + "mov %c[r13](%3), %%r13 \n\t" + "mov %c[r14](%3), %%r14 \n\t" + "mov %c[r15](%3), %%r15 \n\t" + "mov %c[rcx](%3), %%rcx \n\t" /* kills %3 (rcx) */ +#else + "mov %c[cr2](%3), %%eax \n\t" + "mov %%eax, %%cr2 \n\t" + "mov %c[rax](%3), %%eax \n\t" + "mov %c[rbx](%3), %%ebx \n\t" + "mov %c[rdx](%3), %%edx \n\t" + "mov %c[rsi](%3), %%esi \n\t" + "mov %c[rdi](%3), %%edi \n\t" + "mov %c[rbp](%3), %%ebp \n\t" + "mov %c[rcx](%3), %%ecx \n\t" /* kills %3 (ecx) */ +#endif + /* Enter guest mode */ + "jne launched \n\t" + ASM_VMX_VMLAUNCH "\n\t" + "jmp kvm_vmx_return \n\t" + "launched: " ASM_VMX_VMRESUME "\n\t" + ".globl kvm_vmx_return \n\t" + "kvm_vmx_return: " + /* Save guest registers, load host registers, keep flags */ +#ifdef __x86_64__ + "xchg %3, 0(%%rsp) \n\t" + "mov %%rax, %c[rax](%3) \n\t" + "mov %%rbx, %c[rbx](%3) \n\t" + "pushq 0(%%rsp); popq %c[rcx](%3) \n\t" + "mov %%rdx, %c[rdx](%3) \n\t" + "mov %%rsi, %c[rsi](%3) \n\t" + "mov %%rdi, %c[rdi](%3) \n\t" + "mov %%rbp, %c[rbp](%3) \n\t" + "mov %%r8, %c[r8](%3) \n\t" + "mov %%r9, %c[r9](%3) \n\t" + "mov %%r10, %c[r10](%3) \n\t" + "mov %%r11, %c[r11](%3) \n\t" + "mov %%r12, %c[r12](%3) \n\t" + "mov %%r13, %c[r13](%3) \n\t" + "mov %%r14, %c[r14](%3) \n\t" + "mov %%r15, %c[r15](%3) \n\t" + "mov %%cr2, %%rax \n\t" + "mov %%rax, %c[cr2](%3) \n\t" + "mov 0(%%rsp), %3 \n\t" + + "pop %%rcx; pop %%r15; pop %%r14; pop %%r13; pop %%r12;" + "pop %%r11; pop %%r10; pop %%r9; pop %%r8;" + "pop %%rbp; pop %%rdi; pop %%rsi;" + "pop %%rdx; pop %%rbx; pop %%rax \n\t" +#else + "xchg %3, 0(%%esp) \n\t" + "mov %%eax, %c[rax](%3) \n\t" + "mov %%ebx, %c[rbx](%3) \n\t" + "pushl 0(%%esp); popl %c[rcx](%3) \n\t" + "mov %%edx, %c[rdx](%3) \n\t" + "mov %%esi, %c[rsi](%3) \n\t" + "mov %%edi, %c[rdi](%3) \n\t" + "mov %%ebp, %c[rbp](%3) \n\t" + "mov %%cr2, %%eax \n\t" + "mov %%eax, %c[cr2](%3) \n\t" + "mov 0(%%esp), %3 \n\t" + + "pop %%ecx; popa \n\t" +#endif + "setbe %0 \n\t" + "popf \n\t" + : "=g" (fail) + : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP), + "c"(vcpu), + [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])), + [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])), + [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])), + [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])), + [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])), + [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])), + [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP])), +#ifdef __x86_64__ + [r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])), + [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])), + [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])), + [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])), + [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])), + [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])), + [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])), + [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15])), +#endif + [cr2]"i"(offsetof(struct kvm_vcpu, cr2)) + : "cc", "memory" ); + + ++kvm_stat.exits; + + save_msrs(vcpu->guest_msrs, NR_BAD_MSRS); + load_msrs(vcpu->host_msrs, NR_BAD_MSRS); + + fx_save(vcpu->guest_fx_image); + fx_restore(vcpu->host_fx_image); + +#ifndef __x86_64__ + asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); +#endif + + kvm_run->exit_type = 0; + if (fail) { + kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; + kvm_run->exit_reason = vmcs_read32(VM_INSTRUCTION_ERROR); + } else { + if (fs_gs_ldt_reload_needed) { + load_ldt(ldt_sel); + load_fs(fs_sel); + /* + * If we have to reload gs, we must take care to + * preserve our gs base. + */ + local_irq_disable(); + load_gs(gs_sel); +#ifdef __x86_64__ + wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE)); +#endif + local_irq_enable(); + + reload_tss(); + } + vcpu->launched = 1; + kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT; + if (kvm_handle_exit(kvm_run, vcpu)) { + /* Give scheduler a change to reschedule. */ + if (signal_pending(current)) { + ++kvm_stat.signal_exits; + return -EINTR; + } + kvm_resched(vcpu); + goto again; + } + } + return 0; +} + +static void vmx_flush_tlb(struct kvm_vcpu *vcpu) +{ + vmcs_writel(GUEST_CR3, vmcs_readl(GUEST_CR3)); +} + +static void vmx_inject_page_fault(struct kvm_vcpu *vcpu, + unsigned long addr, + u32 err_code) +{ + u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); + + ++kvm_stat.pf_guest; + + if (is_page_fault(vect_info)) { + printk(KERN_DEBUG "inject_page_fault: " + "double fault 0x%lx @ 0x%lx\n", + addr, vmcs_readl(GUEST_RIP)); + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, 0); + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + DF_VECTOR | + INTR_TYPE_EXCEPTION | + INTR_INFO_DELIEVER_CODE_MASK | + INTR_INFO_VALID_MASK); + return; + } + vcpu->cr2 = addr; + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, err_code); + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + PF_VECTOR | + INTR_TYPE_EXCEPTION | + INTR_INFO_DELIEVER_CODE_MASK | + INTR_INFO_VALID_MASK); + +} + +static void vmx_free_vmcs(struct kvm_vcpu *vcpu) +{ + if (vcpu->vmcs) { + on_each_cpu(__vcpu_clear, vcpu, 0, 1); + free_vmcs(vcpu->vmcs); + vcpu->vmcs = NULL; + } +} + +static void vmx_free_vcpu(struct kvm_vcpu *vcpu) +{ + vmx_free_vmcs(vcpu); +} + +static int vmx_create_vcpu(struct kvm_vcpu *vcpu) +{ + struct vmcs *vmcs; + + vmcs = alloc_vmcs(); + if (!vmcs) + return -ENOMEM; + vmcs_clear(vmcs); + vcpu->vmcs = vmcs; + vcpu->launched = 0; + return 0; +} + +static struct kvm_arch_ops vmx_arch_ops = { + .cpu_has_kvm_support = cpu_has_kvm_support, + .disabled_by_bios = vmx_disabled_by_bios, + .hardware_setup = hardware_setup, + .hardware_unsetup = hardware_unsetup, + .hardware_enable = hardware_enable, + .hardware_disable = hardware_disable, + + .vcpu_create = vmx_create_vcpu, + .vcpu_free = vmx_free_vcpu, + + .vcpu_load = vmx_vcpu_load, + .vcpu_put = vmx_vcpu_put, + + .set_guest_debug = set_guest_debug, + .get_msr = vmx_get_msr, + .set_msr = vmx_set_msr, + .get_segment_base = vmx_get_segment_base, + .get_segment = vmx_get_segment, + .set_segment = vmx_set_segment, + .is_long_mode = vmx_is_long_mode, + .get_cs_db_l_bits = vmx_get_cs_db_l_bits, + .set_cr0 = vmx_set_cr0, + .set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch, + .set_cr3 = vmx_set_cr3, + .set_cr4 = vmx_set_cr4, +#ifdef __x86_64__ + .set_efer = vmx_set_efer, +#endif + .get_idt = vmx_get_idt, + .set_idt = vmx_set_idt, + .get_gdt = vmx_get_gdt, + .set_gdt = vmx_set_gdt, + .cache_regs = vcpu_load_rsp_rip, + .decache_regs = vcpu_put_rsp_rip, + .get_rflags = vmx_get_rflags, + .set_rflags = vmx_set_rflags, + + .tlb_flush = vmx_flush_tlb, + .inject_page_fault = vmx_inject_page_fault, + + .inject_gp = vmx_inject_gp, + + .run = vmx_vcpu_run, + .skip_emulated_instruction = skip_emulated_instruction, + .vcpu_setup = vmx_vcpu_setup, +}; + +static int __init vmx_init(void) +{ + kvm_init_arch(&vmx_arch_ops, THIS_MODULE); + return 0; +} + +static void __exit vmx_exit(void) +{ + kvm_exit_arch(); +} + +module_init(vmx_init) +module_exit(vmx_exit) diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h new file mode 100644 index 000000000000..797278341581 --- /dev/null +++ b/drivers/kvm/vmx.h @@ -0,0 +1,296 @@ +#ifndef VMX_H +#define VMX_H + +/* + * vmx.h: VMX Architecture related definitions + * Copyright (c) 2004, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * A few random additions are: + * Copyright (C) 2006 Qumranet + * Avi Kivity + * Yaniv Kamay + * + */ + +#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 +#define CPU_BASED_USE_TSC_OFFSETING 0x00000008 +#define CPU_BASED_HLT_EXITING 0x00000080 +#define CPU_BASED_INVDPG_EXITING 0x00000200 +#define CPU_BASED_MWAIT_EXITING 0x00000400 +#define CPU_BASED_RDPMC_EXITING 0x00000800 +#define CPU_BASED_RDTSC_EXITING 0x00001000 +#define CPU_BASED_CR8_LOAD_EXITING 0x00080000 +#define CPU_BASED_CR8_STORE_EXITING 0x00100000 +#define CPU_BASED_TPR_SHADOW 0x00200000 +#define CPU_BASED_MOV_DR_EXITING 0x00800000 +#define CPU_BASED_UNCOND_IO_EXITING 0x01000000 +#define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000 +#define CPU_BASED_MSR_BITMAPS 0x10000000 +#define CPU_BASED_MONITOR_EXITING 0x20000000 +#define CPU_BASED_PAUSE_EXITING 0x40000000 + +#define PIN_BASED_EXT_INTR_MASK 0x1 +#define PIN_BASED_NMI_EXITING 0x8 + +#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 +#define VM_EXIT_HOST_ADD_SPACE_SIZE 0x00000200 + + +/* VMCS Encodings */ +enum vmcs_field { + GUEST_ES_SELECTOR = 0x00000800, + GUEST_CS_SELECTOR = 0x00000802, + GUEST_SS_SELECTOR = 0x00000804, + GUEST_DS_SELECTOR = 0x00000806, + GUEST_FS_SELECTOR = 0x00000808, + GUEST_GS_SELECTOR = 0x0000080a, + GUEST_LDTR_SELECTOR = 0x0000080c, + GUEST_TR_SELECTOR = 0x0000080e, + HOST_ES_SELECTOR = 0x00000c00, + HOST_CS_SELECTOR = 0x00000c02, + HOST_SS_SELECTOR = 0x00000c04, + HOST_DS_SELECTOR = 0x00000c06, + HOST_FS_SELECTOR = 0x00000c08, + HOST_GS_SELECTOR = 0x00000c0a, + HOST_TR_SELECTOR = 0x00000c0c, + IO_BITMAP_A = 0x00002000, + IO_BITMAP_A_HIGH = 0x00002001, + IO_BITMAP_B = 0x00002002, + IO_BITMAP_B_HIGH = 0x00002003, + MSR_BITMAP = 0x00002004, + MSR_BITMAP_HIGH = 0x00002005, + VM_EXIT_MSR_STORE_ADDR = 0x00002006, + VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007, + VM_EXIT_MSR_LOAD_ADDR = 0x00002008, + VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009, + VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a, + VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b, + TSC_OFFSET = 0x00002010, + TSC_OFFSET_HIGH = 0x00002011, + VIRTUAL_APIC_PAGE_ADDR = 0x00002012, + VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013, + VMCS_LINK_POINTER = 0x00002800, + VMCS_LINK_POINTER_HIGH = 0x00002801, + GUEST_IA32_DEBUGCTL = 0x00002802, + GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, + PIN_BASED_VM_EXEC_CONTROL = 0x00004000, + CPU_BASED_VM_EXEC_CONTROL = 0x00004002, + EXCEPTION_BITMAP = 0x00004004, + PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, + PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, + CR3_TARGET_COUNT = 0x0000400a, + VM_EXIT_CONTROLS = 0x0000400c, + VM_EXIT_MSR_STORE_COUNT = 0x0000400e, + VM_EXIT_MSR_LOAD_COUNT = 0x00004010, + VM_ENTRY_CONTROLS = 0x00004012, + VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, + VM_ENTRY_INTR_INFO_FIELD = 0x00004016, + VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, + VM_ENTRY_INSTRUCTION_LEN = 0x0000401a, + TPR_THRESHOLD = 0x0000401c, + SECONDARY_VM_EXEC_CONTROL = 0x0000401e, + VM_INSTRUCTION_ERROR = 0x00004400, + VM_EXIT_REASON = 0x00004402, + VM_EXIT_INTR_INFO = 0x00004404, + VM_EXIT_INTR_ERROR_CODE = 0x00004406, + IDT_VECTORING_INFO_FIELD = 0x00004408, + IDT_VECTORING_ERROR_CODE = 0x0000440a, + VM_EXIT_INSTRUCTION_LEN = 0x0000440c, + VMX_INSTRUCTION_INFO = 0x0000440e, + GUEST_ES_LIMIT = 0x00004800, + GUEST_CS_LIMIT = 0x00004802, + GUEST_SS_LIMIT = 0x00004804, + GUEST_DS_LIMIT = 0x00004806, + GUEST_FS_LIMIT = 0x00004808, + GUEST_GS_LIMIT = 0x0000480a, + GUEST_LDTR_LIMIT = 0x0000480c, + GUEST_TR_LIMIT = 0x0000480e, + GUEST_GDTR_LIMIT = 0x00004810, + GUEST_IDTR_LIMIT = 0x00004812, + GUEST_ES_AR_BYTES = 0x00004814, + GUEST_CS_AR_BYTES = 0x00004816, + GUEST_SS_AR_BYTES = 0x00004818, + GUEST_DS_AR_BYTES = 0x0000481a, + GUEST_FS_AR_BYTES = 0x0000481c, + GUEST_GS_AR_BYTES = 0x0000481e, + GUEST_LDTR_AR_BYTES = 0x00004820, + GUEST_TR_AR_BYTES = 0x00004822, + GUEST_INTERRUPTIBILITY_INFO = 0x00004824, + GUEST_ACTIVITY_STATE = 0X00004826, + GUEST_SYSENTER_CS = 0x0000482A, + HOST_IA32_SYSENTER_CS = 0x00004c00, + CR0_GUEST_HOST_MASK = 0x00006000, + CR4_GUEST_HOST_MASK = 0x00006002, + CR0_READ_SHADOW = 0x00006004, + CR4_READ_SHADOW = 0x00006006, + CR3_TARGET_VALUE0 = 0x00006008, + CR3_TARGET_VALUE1 = 0x0000600a, + CR3_TARGET_VALUE2 = 0x0000600c, + CR3_TARGET_VALUE3 = 0x0000600e, + EXIT_QUALIFICATION = 0x00006400, + GUEST_LINEAR_ADDRESS = 0x0000640a, + GUEST_CR0 = 0x00006800, + GUEST_CR3 = 0x00006802, + GUEST_CR4 = 0x00006804, + GUEST_ES_BASE = 0x00006806, + GUEST_CS_BASE = 0x00006808, + GUEST_SS_BASE = 0x0000680a, + GUEST_DS_BASE = 0x0000680c, + GUEST_FS_BASE = 0x0000680e, + GUEST_GS_BASE = 0x00006810, + GUEST_LDTR_BASE = 0x00006812, + GUEST_TR_BASE = 0x00006814, + GUEST_GDTR_BASE = 0x00006816, + GUEST_IDTR_BASE = 0x00006818, + GUEST_DR7 = 0x0000681a, + GUEST_RSP = 0x0000681c, + GUEST_RIP = 0x0000681e, + GUEST_RFLAGS = 0x00006820, + GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, + GUEST_SYSENTER_ESP = 0x00006824, + GUEST_SYSENTER_EIP = 0x00006826, + HOST_CR0 = 0x00006c00, + HOST_CR3 = 0x00006c02, + HOST_CR4 = 0x00006c04, + HOST_FS_BASE = 0x00006c06, + HOST_GS_BASE = 0x00006c08, + HOST_TR_BASE = 0x00006c0a, + HOST_GDTR_BASE = 0x00006c0c, + HOST_IDTR_BASE = 0x00006c0e, + HOST_IA32_SYSENTER_ESP = 0x00006c10, + HOST_IA32_SYSENTER_EIP = 0x00006c12, + HOST_RSP = 0x00006c14, + HOST_RIP = 0x00006c16, +}; + +#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 + +#define EXIT_REASON_EXCEPTION_NMI 0 +#define EXIT_REASON_EXTERNAL_INTERRUPT 1 + +#define EXIT_REASON_PENDING_INTERRUPT 7 + +#define EXIT_REASON_TASK_SWITCH 9 +#define EXIT_REASON_CPUID 10 +#define EXIT_REASON_HLT 12 +#define EXIT_REASON_INVLPG 14 +#define EXIT_REASON_RDPMC 15 +#define EXIT_REASON_RDTSC 16 +#define EXIT_REASON_VMCALL 18 +#define EXIT_REASON_VMCLEAR 19 +#define EXIT_REASON_VMLAUNCH 20 +#define EXIT_REASON_VMPTRLD 21 +#define EXIT_REASON_VMPTRST 22 +#define EXIT_REASON_VMREAD 23 +#define EXIT_REASON_VMRESUME 24 +#define EXIT_REASON_VMWRITE 25 +#define EXIT_REASON_VMOFF 26 +#define EXIT_REASON_VMON 27 +#define EXIT_REASON_CR_ACCESS 28 +#define EXIT_REASON_DR_ACCESS 29 +#define EXIT_REASON_IO_INSTRUCTION 30 +#define EXIT_REASON_MSR_READ 31 +#define EXIT_REASON_MSR_WRITE 32 +#define EXIT_REASON_MWAIT_INSTRUCTION 36 + +/* + * Interruption-information format + */ +#define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ +#define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ +#define INTR_INFO_DELIEVER_CODE_MASK 0x800 /* 11 */ +#define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ + +#define VECTORING_INFO_VECTOR_MASK INTR_INFO_VECTOR_MASK +#define VECTORING_INFO_TYPE_MASK INTR_INFO_INTR_TYPE_MASK +#define VECTORING_INFO_DELIEVER_CODE_MASK INTR_INFO_DELIEVER_CODE_MASK +#define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK + +#define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */ +#define INTR_TYPE_EXCEPTION (3 << 8) /* processor exception */ + +/* + * Exit Qualifications for MOV for Control Register Access + */ +#define CONTROL_REG_ACCESS_NUM 0x7 /* 2:0, number of control register */ +#define CONTROL_REG_ACCESS_TYPE 0x30 /* 5:4, access type */ +#define CONTROL_REG_ACCESS_REG 0xf00 /* 10:8, general purpose register */ +#define LMSW_SOURCE_DATA_SHIFT 16 +#define LMSW_SOURCE_DATA (0xFFFF << LMSW_SOURCE_DATA_SHIFT) /* 16:31 lmsw source */ +#define REG_EAX (0 << 8) +#define REG_ECX (1 << 8) +#define REG_EDX (2 << 8) +#define REG_EBX (3 << 8) +#define REG_ESP (4 << 8) +#define REG_EBP (5 << 8) +#define REG_ESI (6 << 8) +#define REG_EDI (7 << 8) +#define REG_R8 (8 << 8) +#define REG_R9 (9 << 8) +#define REG_R10 (10 << 8) +#define REG_R11 (11 << 8) +#define REG_R12 (12 << 8) +#define REG_R13 (13 << 8) +#define REG_R14 (14 << 8) +#define REG_R15 (15 << 8) + +/* + * Exit Qualifications for MOV for Debug Register Access + */ +#define DEBUG_REG_ACCESS_NUM 0x7 /* 2:0, number of debug register */ +#define DEBUG_REG_ACCESS_TYPE 0x10 /* 4, direction of access */ +#define TYPE_MOV_TO_DR (0 << 4) +#define TYPE_MOV_FROM_DR (1 << 4) +#define DEBUG_REG_ACCESS_REG 0xf00 /* 11:8, general purpose register */ + + +/* segment AR */ +#define SEGMENT_AR_L_MASK (1 << 13) + +/* entry controls */ +#define VM_ENTRY_CONTROLS_IA32E_MASK (1 << 9) + +#define AR_TYPE_ACCESSES_MASK 1 +#define AR_TYPE_READABLE_MASK (1 << 1) +#define AR_TYPE_WRITEABLE_MASK (1 << 2) +#define AR_TYPE_CODE_MASK (1 << 3) +#define AR_TYPE_MASK 0x0f +#define AR_TYPE_BUSY_64_TSS 11 +#define AR_TYPE_BUSY_32_TSS 11 +#define AR_TYPE_BUSY_16_TSS 3 +#define AR_TYPE_LDT 2 + +#define AR_UNUSABLE_MASK (1 << 16) +#define AR_S_MASK (1 << 4) +#define AR_P_MASK (1 << 7) +#define AR_L_MASK (1 << 13) +#define AR_DB_MASK (1 << 14) +#define AR_G_MASK (1 << 15) +#define AR_DPL_SHIFT 5 +#define AR_DPL(ar) (((ar) >> AR_DPL_SHIFT) & 3) + +#define AR_RESERVD_MASK 0xfffe0f00 + +#define CR4_VMXE 0x2000 + +#define MSR_IA32_VMX_BASIC_MSR 0x480 +#define MSR_IA32_FEATURE_CONTROL 0x03a +#define MSR_IA32_VMX_PINBASED_CTLS_MSR 0x481 +#define MSR_IA32_VMX_PROCBASED_CTLS_MSR 0x482 +#define MSR_IA32_VMX_EXIT_CTLS_MSR 0x483 +#define MSR_IA32_VMX_ENTRY_CTLS_MSR 0x484 + +#endif diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c new file mode 100644 index 000000000000..7e838bf0592d --- /dev/null +++ b/drivers/kvm/x86_emulate.c @@ -0,0 +1,1409 @@ +/****************************************************************************** + * x86_emulate.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * Copyright (c) 2005 Keir Fraser + * + * Linux coding style, mod r/m decoder, segment base fixes, real-mode + * privieged instructions: + * + * Copyright (C) 2006 Qumranet + * + * Avi Kivity + * Yaniv Kamay + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4 + */ + +#ifndef __KERNEL__ +#include +#include +#include +#define DPRINTF(_f, _a ...) printf( _f , ## _a ) +#else +#include "kvm.h" +#define DPRINTF(x...) do {} while (0) +#endif +#include "x86_emulate.h" +#include + +/* + * Opcode effective-address decode tables. + * Note that we only emulate instructions that have at least one memory + * operand (excluding implicit stack references). We assume that stack + * references and instruction fetches will never occur in special memory + * areas that require emulation. So, for example, 'mov ,' need + * not be handled. + */ + +/* Operand sizes: 8-bit operands or specified/overridden size. */ +#define ByteOp (1<<0) /* 8-bit operands. */ +/* Destination operand type. */ +#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */ +#define DstReg (2<<1) /* Register operand. */ +#define DstMem (3<<1) /* Memory operand. */ +#define DstMask (3<<1) +/* Source operand type. */ +#define SrcNone (0<<3) /* No source operand. */ +#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */ +#define SrcReg (1<<3) /* Register operand. */ +#define SrcMem (2<<3) /* Memory operand. */ +#define SrcMem16 (3<<3) /* Memory operand (16-bit). */ +#define SrcMem32 (4<<3) /* Memory operand (32-bit). */ +#define SrcImm (5<<3) /* Immediate operand. */ +#define SrcImmByte (6<<3) /* 8-bit sign-extended immediate operand. */ +#define SrcMask (7<<3) +/* Generic ModRM decode. */ +#define ModRM (1<<6) +/* Destination is only written; never read. */ +#define Mov (1<<7) + +static u8 opcode_table[256] = { + /* 0x00 - 0x07 */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x08 - 0x0F */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x10 - 0x17 */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x18 - 0x1F */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x20 - 0x27 */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x28 - 0x2F */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x30 - 0x37 */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x38 - 0x3F */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x40 - 0x4F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x50 - 0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 - 0x6F */ + 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 - 0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 - 0x87 */ + ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, + ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + /* 0x88 - 0x8F */ + ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov, + ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + 0, 0, 0, DstMem | SrcNone | ModRM | Mov, + /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xA0 - 0xA7 */ + ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov, + ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov, + ByteOp | ImplicitOps | Mov, ImplicitOps | Mov, + ByteOp | ImplicitOps, ImplicitOps, + /* 0xA8 - 0xAF */ + 0, 0, ByteOp | ImplicitOps | Mov, ImplicitOps | Mov, + ByteOp | ImplicitOps | Mov, ImplicitOps | Mov, + ByteOp | ImplicitOps, ImplicitOps, + /* 0xB0 - 0xBF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xC0 - 0xC7 */ + ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, 0, 0, + 0, 0, ByteOp | DstMem | SrcImm | ModRM | Mov, + DstMem | SrcImm | ModRM | Mov, + /* 0xC8 - 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xD0 - 0xD7 */ + ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, + ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, + 0, 0, 0, 0, + /* 0xD8 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xF0 - 0xF7 */ + 0, 0, 0, 0, + 0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM, + /* 0xF8 - 0xFF */ + 0, 0, 0, 0, + 0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM +}; + +static u8 twobyte_table[256] = { + /* 0x00 - 0x0F */ + 0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0, + 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, + /* 0x10 - 0x1F */ + 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, + /* 0x20 - 0x2F */ + ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x30 - 0x3F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x40 - 0x47 */ + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + /* 0x48 - 0x4F */ + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + /* 0x50 - 0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 - 0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 - 0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 - 0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xA0 - 0xA7 */ + 0, 0, 0, DstMem | SrcReg | ModRM, 0, 0, 0, 0, + /* 0xA8 - 0xAF */ + 0, 0, 0, DstMem | SrcReg | ModRM, 0, 0, 0, 0, + /* 0xB0 - 0xB7 */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0, + DstMem | SrcReg | ModRM, + 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem16 | ModRM | Mov, + /* 0xB8 - 0xBF */ + 0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM, + 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem16 | ModRM | Mov, + /* 0xC0 - 0xCF */ + 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xD0 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xF0 - 0xFF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * Tell the emulator that of the Group 7 instructions (sgdt, lidt, etc.) we + * are interested only in invlpg and not in any of the rest. + * + * invlpg is a special instruction in that the data it references may not + * be mapped. + */ +void kvm_emulator_want_group7_invlpg(void) +{ + twobyte_table[1] &= ~SrcMem; +} +EXPORT_SYMBOL_GPL(kvm_emulator_want_group7_invlpg); + +/* Type, address-of, and value of an instruction's operand. */ +struct operand { + enum { OP_REG, OP_MEM, OP_IMM } type; + unsigned int bytes; + unsigned long val, orig_val, *ptr; +}; + +/* EFLAGS bit definitions. */ +#define EFLG_OF (1<<11) +#define EFLG_DF (1<<10) +#define EFLG_SF (1<<7) +#define EFLG_ZF (1<<6) +#define EFLG_AF (1<<4) +#define EFLG_PF (1<<2) +#define EFLG_CF (1<<0) + +/* + * Instruction emulation: + * Most instructions are emulated directly via a fragment of inline assembly + * code. This allows us to save/restore EFLAGS and thus very easily pick up + * any modified flags. + */ + +#if defined(__x86_64__) +#define _LO32 "k" /* force 32-bit operand */ +#define _STK "%%rsp" /* stack pointer */ +#elif defined(__i386__) +#define _LO32 "" /* force 32-bit operand */ +#define _STK "%%esp" /* stack pointer */ +#endif + +/* + * These EFLAGS bits are restored from saved value during emulation, and + * any changes are written back to the saved value after emulation. + */ +#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF) + +/* Before executing instruction: restore necessary bits in EFLAGS. */ +#define _PRE_EFLAGS(_sav, _msk, _tmp) \ + /* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); */ \ + "push %"_sav"; " \ + "movl %"_msk",%"_LO32 _tmp"; " \ + "andl %"_LO32 _tmp",("_STK"); " \ + "pushf; " \ + "notl %"_LO32 _tmp"; " \ + "andl %"_LO32 _tmp",("_STK"); " \ + "pop %"_tmp"; " \ + "orl %"_LO32 _tmp",("_STK"); " \ + "popf; " \ + /* _sav &= ~msk; */ \ + "movl %"_msk",%"_LO32 _tmp"; " \ + "notl %"_LO32 _tmp"; " \ + "andl %"_LO32 _tmp",%"_sav"; " + +/* After executing instruction: write-back necessary bits in EFLAGS. */ +#define _POST_EFLAGS(_sav, _msk, _tmp) \ + /* _sav |= EFLAGS & _msk; */ \ + "pushf; " \ + "pop %"_tmp"; " \ + "andl %"_msk",%"_LO32 _tmp"; " \ + "orl %"_LO32 _tmp",%"_sav"; " + +/* Raw emulation: instruction has two explicit operands. */ +#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy) \ + do { \ + unsigned long _tmp; \ + \ + switch ((_dst).bytes) { \ + case 2: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","4","2") \ + _op"w %"_wx"3,%1; " \ + _POST_EFLAGS("0","4","2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : _wy ((_src).val), "i" (EFLAGS_MASK) ); \ + break; \ + case 4: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","4","2") \ + _op"l %"_lx"3,%1; " \ + _POST_EFLAGS("0","4","2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : _ly ((_src).val), "i" (EFLAGS_MASK) ); \ + break; \ + case 8: \ + __emulate_2op_8byte(_op, _src, _dst, \ + _eflags, _qx, _qy); \ + break; \ + } \ + } while (0) + +#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \ + do { \ + unsigned long _tmp; \ + switch ( (_dst).bytes ) \ + { \ + case 1: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","4","2") \ + _op"b %"_bx"3,%1; " \ + _POST_EFLAGS("0","4","2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : _by ((_src).val), "i" (EFLAGS_MASK) ); \ + break; \ + default: \ + __emulate_2op_nobyte(_op, _src, _dst, _eflags, \ + _wx, _wy, _lx, _ly, _qx, _qy); \ + break; \ + } \ + } while (0) + +/* Source operand is byte-sized and may be restricted to just %cl. */ +#define emulate_2op_SrcB(_op, _src, _dst, _eflags) \ + __emulate_2op(_op, _src, _dst, _eflags, \ + "b", "c", "b", "c", "b", "c", "b", "c") + +/* Source operand is byte, word, long or quad sized. */ +#define emulate_2op_SrcV(_op, _src, _dst, _eflags) \ + __emulate_2op(_op, _src, _dst, _eflags, \ + "b", "q", "w", "r", _LO32, "r", "", "r") + +/* Source operand is word, long or quad sized. */ +#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags) \ + __emulate_2op_nobyte(_op, _src, _dst, _eflags, \ + "w", "r", _LO32, "r", "", "r") + +/* Instruction has only one explicit operand (no source operand). */ +#define emulate_1op(_op, _dst, _eflags) \ + do { \ + unsigned long _tmp; \ + \ + switch ( (_dst).bytes ) \ + { \ + case 1: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","3","2") \ + _op"b %1; " \ + _POST_EFLAGS("0","3","2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : "i" (EFLAGS_MASK) ); \ + break; \ + case 2: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","3","2") \ + _op"w %1; " \ + _POST_EFLAGS("0","3","2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : "i" (EFLAGS_MASK) ); \ + break; \ + case 4: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","3","2") \ + _op"l %1; " \ + _POST_EFLAGS("0","3","2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : "i" (EFLAGS_MASK) ); \ + break; \ + case 8: \ + __emulate_1op_8byte(_op, _dst, _eflags); \ + break; \ + } \ + } while (0) + +/* Emulate an instruction with quadword operands (x86/64 only). */ +#if defined(__x86_64__) +#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) \ + do { \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","4","2") \ + _op"q %"_qx"3,%1; " \ + _POST_EFLAGS("0","4","2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : _qy ((_src).val), "i" (EFLAGS_MASK) ); \ + } while (0) + +#define __emulate_1op_8byte(_op, _dst, _eflags) \ + do { \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","3","2") \ + _op"q %1; " \ + _POST_EFLAGS("0","3","2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : "i" (EFLAGS_MASK) ); \ + } while (0) + +#elif defined(__i386__) +#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) +#define __emulate_1op_8byte(_op, _dst, _eflags) +#endif /* __i386__ */ + +/* Fetch next part of the instruction being emulated. */ +#define insn_fetch(_type, _size, _eip) \ +({ unsigned long _x; \ + rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x, \ + (_size), ctxt); \ + if ( rc != 0 ) \ + goto done; \ + (_eip) += (_size); \ + (_type)_x; \ +}) + +/* Access/update address held in a register, based on addressing mode. */ +#define register_address(base, reg) \ + ((base) + ((ad_bytes == sizeof(unsigned long)) ? (reg) : \ + ((reg) & ((1UL << (ad_bytes << 3)) - 1)))) + +#define register_address_increment(reg, inc) \ + do { \ + /* signed type ensures sign extension to long */ \ + int _inc = (inc); \ + if ( ad_bytes == sizeof(unsigned long) ) \ + (reg) += _inc; \ + else \ + (reg) = ((reg) & ~((1UL << (ad_bytes << 3)) - 1)) | \ + (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \ + } while (0) + +void *decode_register(u8 modrm_reg, unsigned long *regs, + int highbyte_regs) +{ + void *p; + + p = ®s[modrm_reg]; + if (highbyte_regs && modrm_reg >= 4 && modrm_reg < 8) + p = (unsigned char *)®s[modrm_reg & 3] + 1; + return p; +} + +static int read_descriptor(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + void *ptr, + u16 *size, unsigned long *address, int op_bytes) +{ + int rc; + + if (op_bytes == 2) + op_bytes = 3; + *address = 0; + rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, ctxt); + if (rc) + return rc; + rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, ctxt); + return rc; +} + +int +x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) +{ + u8 b, d, sib, twobyte = 0, rex_prefix = 0; + u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0; + unsigned long *override_base = NULL; + unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i; + int rc = 0; + struct operand src, dst; + unsigned long cr2 = ctxt->cr2; + int mode = ctxt->mode; + unsigned long modrm_ea; + int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0; + + /* Shadow copy of register state. Committed on successful emulation. */ + unsigned long _regs[NR_VCPU_REGS]; + unsigned long _eip = ctxt->vcpu->rip, _eflags = ctxt->eflags; + unsigned long modrm_val = 0; + + memcpy(_regs, ctxt->vcpu->regs, sizeof _regs); + + switch (mode) { + case X86EMUL_MODE_REAL: + case X86EMUL_MODE_PROT16: + op_bytes = ad_bytes = 2; + break; + case X86EMUL_MODE_PROT32: + op_bytes = ad_bytes = 4; + break; +#ifdef __x86_64__ + case X86EMUL_MODE_PROT64: + op_bytes = 4; + ad_bytes = 8; + break; +#endif + default: + return -1; + } + + /* Legacy prefixes. */ + for (i = 0; i < 8; i++) { + switch (b = insn_fetch(u8, 1, _eip)) { + case 0x66: /* operand-size override */ + op_bytes ^= 6; /* switch between 2/4 bytes */ + break; + case 0x67: /* address-size override */ + if (mode == X86EMUL_MODE_PROT64) + ad_bytes ^= 12; /* switch between 4/8 bytes */ + else + ad_bytes ^= 6; /* switch between 2/4 bytes */ + break; + case 0x2e: /* CS override */ + override_base = &ctxt->cs_base; + break; + case 0x3e: /* DS override */ + override_base = &ctxt->ds_base; + break; + case 0x26: /* ES override */ + override_base = &ctxt->es_base; + break; + case 0x64: /* FS override */ + override_base = &ctxt->fs_base; + break; + case 0x65: /* GS override */ + override_base = &ctxt->gs_base; + break; + case 0x36: /* SS override */ + override_base = &ctxt->ss_base; + break; + case 0xf0: /* LOCK */ + lock_prefix = 1; + break; + case 0xf3: /* REP/REPE/REPZ */ + rep_prefix = 1; + break; + case 0xf2: /* REPNE/REPNZ */ + break; + default: + goto done_prefixes; + } + } + +done_prefixes: + + /* REX prefix. */ + if ((mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40)) { + rex_prefix = b; + if (b & 8) + op_bytes = 8; /* REX.W */ + modrm_reg = (b & 4) << 1; /* REX.R */ + index_reg = (b & 2) << 2; /* REX.X */ + modrm_rm = base_reg = (b & 1) << 3; /* REG.B */ + b = insn_fetch(u8, 1, _eip); + } + + /* Opcode byte(s). */ + d = opcode_table[b]; + if (d == 0) { + /* Two-byte opcode? */ + if (b == 0x0f) { + twobyte = 1; + b = insn_fetch(u8, 1, _eip); + d = twobyte_table[b]; + } + + /* Unrecognised? */ + if (d == 0) + goto cannot_emulate; + } + + /* ModRM and SIB bytes. */ + if (d & ModRM) { + modrm = insn_fetch(u8, 1, _eip); + modrm_mod |= (modrm & 0xc0) >> 6; + modrm_reg |= (modrm & 0x38) >> 3; + modrm_rm |= (modrm & 0x07); + modrm_ea = 0; + use_modrm_ea = 1; + + if (modrm_mod == 3) { + modrm_val = *(unsigned long *) + decode_register(modrm_rm, _regs, d & ByteOp); + goto modrm_done; + } + + if (ad_bytes == 2) { + unsigned bx = _regs[VCPU_REGS_RBX]; + unsigned bp = _regs[VCPU_REGS_RBP]; + unsigned si = _regs[VCPU_REGS_RSI]; + unsigned di = _regs[VCPU_REGS_RDI]; + + /* 16-bit ModR/M decode. */ + switch (modrm_mod) { + case 0: + if (modrm_rm == 6) + modrm_ea += insn_fetch(u16, 2, _eip); + break; + case 1: + modrm_ea += insn_fetch(s8, 1, _eip); + break; + case 2: + modrm_ea += insn_fetch(u16, 2, _eip); + break; + } + switch (modrm_rm) { + case 0: + modrm_ea += bx + si; + break; + case 1: + modrm_ea += bx + di; + break; + case 2: + modrm_ea += bp + si; + break; + case 3: + modrm_ea += bp + di; + break; + case 4: + modrm_ea += si; + break; + case 5: + modrm_ea += di; + break; + case 6: + if (modrm_mod != 0) + modrm_ea += bp; + break; + case 7: + modrm_ea += bx; + break; + } + if (modrm_rm == 2 || modrm_rm == 3 || + (modrm_rm == 6 && modrm_mod != 0)) + if (!override_base) + override_base = &ctxt->ss_base; + modrm_ea = (u16)modrm_ea; + } else { + /* 32/64-bit ModR/M decode. */ + switch (modrm_rm) { + case 4: + case 12: + sib = insn_fetch(u8, 1, _eip); + index_reg |= (sib >> 3) & 7; + base_reg |= sib & 7; + scale = sib >> 6; + + switch (base_reg) { + case 5: + if (modrm_mod != 0) + modrm_ea += _regs[base_reg]; + else + modrm_ea += insn_fetch(s32, 4, _eip); + break; + default: + modrm_ea += _regs[base_reg]; + } + switch (index_reg) { + case 4: + break; + default: + modrm_ea += _regs[index_reg] << scale; + + } + break; + case 5: + if (modrm_mod != 0) + modrm_ea += _regs[modrm_rm]; + else if (mode == X86EMUL_MODE_PROT64) + rip_relative = 1; + break; + default: + modrm_ea += _regs[modrm_rm]; + break; + } + switch (modrm_mod) { + case 0: + if (modrm_rm == 5) + modrm_ea += insn_fetch(s32, 4, _eip); + break; + case 1: + modrm_ea += insn_fetch(s8, 1, _eip); + break; + case 2: + modrm_ea += insn_fetch(s32, 4, _eip); + break; + } + } + if (!override_base) + override_base = &ctxt->ds_base; + if (mode == X86EMUL_MODE_PROT64 && + override_base != &ctxt->fs_base && + override_base != &ctxt->gs_base) + override_base = NULL; + + if (override_base) + modrm_ea += *override_base; + + if (rip_relative) { + modrm_ea += _eip; + switch (d & SrcMask) { + case SrcImmByte: + modrm_ea += 1; + break; + case SrcImm: + if (d & ByteOp) + modrm_ea += 1; + else + if (op_bytes == 8) + modrm_ea += 4; + else + modrm_ea += op_bytes; + } + } + if (ad_bytes != 8) + modrm_ea = (u32)modrm_ea; + cr2 = modrm_ea; + modrm_done: + ; + } + + /* Decode and fetch the destination operand: register or memory. */ + switch (d & DstMask) { + case ImplicitOps: + /* Special instructions do their own operand decoding. */ + goto special_insn; + case DstReg: + dst.type = OP_REG; + if ((d & ByteOp) + && !(twobyte_table && (b == 0xb6 || b == 0xb7))) { + dst.ptr = decode_register(modrm_reg, _regs, + (rex_prefix == 0)); + dst.val = *(u8 *) dst.ptr; + dst.bytes = 1; + } else { + dst.ptr = decode_register(modrm_reg, _regs, 0); + switch ((dst.bytes = op_bytes)) { + case 2: + dst.val = *(u16 *)dst.ptr; + break; + case 4: + dst.val = *(u32 *)dst.ptr; + break; + case 8: + dst.val = *(u64 *)dst.ptr; + break; + } + } + break; + case DstMem: + dst.type = OP_MEM; + dst.ptr = (unsigned long *)cr2; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + if (!(d & Mov) && /* optimisation - avoid slow emulated read */ + ((rc = ops->read_emulated((unsigned long)dst.ptr, + &dst.val, dst.bytes, ctxt)) != 0)) + goto done; + break; + } + dst.orig_val = dst.val; + + /* + * Decode and fetch the source operand: register, memory + * or immediate. + */ + switch (d & SrcMask) { + case SrcNone: + break; + case SrcReg: + src.type = OP_REG; + if (d & ByteOp) { + src.ptr = decode_register(modrm_reg, _regs, + (rex_prefix == 0)); + src.val = src.orig_val = *(u8 *) src.ptr; + src.bytes = 1; + } else { + src.ptr = decode_register(modrm_reg, _regs, 0); + switch ((src.bytes = op_bytes)) { + case 2: + src.val = src.orig_val = *(u16 *) src.ptr; + break; + case 4: + src.val = src.orig_val = *(u32 *) src.ptr; + break; + case 8: + src.val = src.orig_val = *(u64 *) src.ptr; + break; + } + } + break; + case SrcMem16: + src.bytes = 2; + goto srcmem_common; + case SrcMem32: + src.bytes = 4; + goto srcmem_common; + case SrcMem: + src.bytes = (d & ByteOp) ? 1 : op_bytes; + srcmem_common: + src.type = OP_MEM; + src.ptr = (unsigned long *)cr2; + if ((rc = ops->read_emulated((unsigned long)src.ptr, + &src.val, src.bytes, ctxt)) != 0) + goto done; + src.orig_val = src.val; + break; + case SrcImm: + src.type = OP_IMM; + src.ptr = (unsigned long *)_eip; + src.bytes = (d & ByteOp) ? 1 : op_bytes; + if (src.bytes == 8) + src.bytes = 4; + /* NB. Immediates are sign-extended as necessary. */ + switch (src.bytes) { + case 1: + src.val = insn_fetch(s8, 1, _eip); + break; + case 2: + src.val = insn_fetch(s16, 2, _eip); + break; + case 4: + src.val = insn_fetch(s32, 4, _eip); + break; + } + break; + case SrcImmByte: + src.type = OP_IMM; + src.ptr = (unsigned long *)_eip; + src.bytes = 1; + src.val = insn_fetch(s8, 1, _eip); + break; + } + + if (twobyte) + goto twobyte_insn; + + switch (b) { + case 0x00 ... 0x05: + add: /* add */ + emulate_2op_SrcV("add", src, dst, _eflags); + break; + case 0x08 ... 0x0d: + or: /* or */ + emulate_2op_SrcV("or", src, dst, _eflags); + break; + case 0x10 ... 0x15: + adc: /* adc */ + emulate_2op_SrcV("adc", src, dst, _eflags); + break; + case 0x18 ... 0x1d: + sbb: /* sbb */ + emulate_2op_SrcV("sbb", src, dst, _eflags); + break; + case 0x20 ... 0x25: + and: /* and */ + emulate_2op_SrcV("and", src, dst, _eflags); + break; + case 0x28 ... 0x2d: + sub: /* sub */ + emulate_2op_SrcV("sub", src, dst, _eflags); + break; + case 0x30 ... 0x35: + xor: /* xor */ + emulate_2op_SrcV("xor", src, dst, _eflags); + break; + case 0x38 ... 0x3d: + cmp: /* cmp */ + emulate_2op_SrcV("cmp", src, dst, _eflags); + break; + case 0x63: /* movsxd */ + if (mode != X86EMUL_MODE_PROT64) + goto cannot_emulate; + dst.val = (s32) src.val; + break; + case 0x80 ... 0x83: /* Grp1 */ + switch (modrm_reg) { + case 0: + goto add; + case 1: + goto or; + case 2: + goto adc; + case 3: + goto sbb; + case 4: + goto and; + case 5: + goto sub; + case 6: + goto xor; + case 7: + goto cmp; + } + break; + case 0x84 ... 0x85: + test: /* test */ + emulate_2op_SrcV("test", src, dst, _eflags); + break; + case 0x86 ... 0x87: /* xchg */ + /* Write back the register source. */ + switch (dst.bytes) { + case 1: + *(u8 *) src.ptr = (u8) dst.val; + break; + case 2: + *(u16 *) src.ptr = (u16) dst.val; + break; + case 4: + *src.ptr = (u32) dst.val; + break; /* 64b reg: zero-extend */ + case 8: + *src.ptr = dst.val; + break; + } + /* + * Write back the memory destination with implicit LOCK + * prefix. + */ + dst.val = src.val; + lock_prefix = 1; + break; + case 0xa0 ... 0xa1: /* mov */ + dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; + dst.val = src.val; + _eip += ad_bytes; /* skip src displacement */ + break; + case 0xa2 ... 0xa3: /* mov */ + dst.val = (unsigned long)_regs[VCPU_REGS_RAX]; + _eip += ad_bytes; /* skip dst displacement */ + break; + case 0x88 ... 0x8b: /* mov */ + case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ + dst.val = src.val; + break; + case 0x8f: /* pop (sole member of Grp1a) */ + /* 64-bit mode: POP always pops a 64-bit operand. */ + if (mode == X86EMUL_MODE_PROT64) + dst.bytes = 8; + if ((rc = ops->read_std(register_address(ctxt->ss_base, + _regs[VCPU_REGS_RSP]), + &dst.val, dst.bytes, ctxt)) != 0) + goto done; + register_address_increment(_regs[VCPU_REGS_RSP], dst.bytes); + break; + case 0xc0 ... 0xc1: + grp2: /* Grp2 */ + switch (modrm_reg) { + case 0: /* rol */ + emulate_2op_SrcB("rol", src, dst, _eflags); + break; + case 1: /* ror */ + emulate_2op_SrcB("ror", src, dst, _eflags); + break; + case 2: /* rcl */ + emulate_2op_SrcB("rcl", src, dst, _eflags); + break; + case 3: /* rcr */ + emulate_2op_SrcB("rcr", src, dst, _eflags); + break; + case 4: /* sal/shl */ + case 6: /* sal/shl */ + emulate_2op_SrcB("sal", src, dst, _eflags); + break; + case 5: /* shr */ + emulate_2op_SrcB("shr", src, dst, _eflags); + break; + case 7: /* sar */ + emulate_2op_SrcB("sar", src, dst, _eflags); + break; + } + break; + case 0xd0 ... 0xd1: /* Grp2 */ + src.val = 1; + goto grp2; + case 0xd2 ... 0xd3: /* Grp2 */ + src.val = _regs[VCPU_REGS_RCX]; + goto grp2; + case 0xf6 ... 0xf7: /* Grp3 */ + switch (modrm_reg) { + case 0 ... 1: /* test */ + /* + * Special case in Grp3: test has an immediate + * source operand. + */ + src.type = OP_IMM; + src.ptr = (unsigned long *)_eip; + src.bytes = (d & ByteOp) ? 1 : op_bytes; + if (src.bytes == 8) + src.bytes = 4; + switch (src.bytes) { + case 1: + src.val = insn_fetch(s8, 1, _eip); + break; + case 2: + src.val = insn_fetch(s16, 2, _eip); + break; + case 4: + src.val = insn_fetch(s32, 4, _eip); + break; + } + goto test; + case 2: /* not */ + dst.val = ~dst.val; + break; + case 3: /* neg */ + emulate_1op("neg", dst, _eflags); + break; + default: + goto cannot_emulate; + } + break; + case 0xfe ... 0xff: /* Grp4/Grp5 */ + switch (modrm_reg) { + case 0: /* inc */ + emulate_1op("inc", dst, _eflags); + break; + case 1: /* dec */ + emulate_1op("dec", dst, _eflags); + break; + case 6: /* push */ + /* 64-bit mode: PUSH always pushes a 64-bit operand. */ + if (mode == X86EMUL_MODE_PROT64) { + dst.bytes = 8; + if ((rc = ops->read_std((unsigned long)dst.ptr, + &dst.val, 8, + ctxt)) != 0) + goto done; + } + register_address_increment(_regs[VCPU_REGS_RSP], + -dst.bytes); + if ((rc = ops->write_std( + register_address(ctxt->ss_base, + _regs[VCPU_REGS_RSP]), + dst.val, dst.bytes, ctxt)) != 0) + goto done; + dst.val = dst.orig_val; /* skanky: disable writeback */ + break; + default: + goto cannot_emulate; + } + break; + } + +writeback: + if ((d & Mov) || (dst.orig_val != dst.val)) { + switch (dst.type) { + case OP_REG: + /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */ + switch (dst.bytes) { + case 1: + *(u8 *)dst.ptr = (u8)dst.val; + break; + case 2: + *(u16 *)dst.ptr = (u16)dst.val; + break; + case 4: + *dst.ptr = (u32)dst.val; + break; /* 64b: zero-ext */ + case 8: + *dst.ptr = dst.val; + break; + } + break; + case OP_MEM: + if (lock_prefix) + rc = ops->cmpxchg_emulated((unsigned long)dst. + ptr, dst.orig_val, + dst.val, dst.bytes, + ctxt); + else + rc = ops->write_emulated((unsigned long)dst.ptr, + dst.val, dst.bytes, + ctxt); + if (rc != 0) + goto done; + default: + break; + } + } + + /* Commit shadow register state. */ + memcpy(ctxt->vcpu->regs, _regs, sizeof _regs); + ctxt->eflags = _eflags; + ctxt->vcpu->rip = _eip; + +done: + return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; + +special_insn: + if (twobyte) + goto twobyte_special_insn; + if (rep_prefix) { + if (_regs[VCPU_REGS_RCX] == 0) { + ctxt->vcpu->rip = _eip; + goto done; + } + _regs[VCPU_REGS_RCX]--; + _eip = ctxt->vcpu->rip; + } + switch (b) { + case 0xa4 ... 0xa5: /* movs */ + dst.type = OP_MEM; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + dst.ptr = (unsigned long *)register_address(ctxt->es_base, + _regs[VCPU_REGS_RDI]); + if ((rc = ops->read_emulated(register_address( + override_base ? *override_base : ctxt->ds_base, + _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt)) != 0) + goto done; + register_address_increment(_regs[VCPU_REGS_RSI], + (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); + register_address_increment(_regs[VCPU_REGS_RDI], + (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); + break; + case 0xa6 ... 0xa7: /* cmps */ + DPRINTF("Urk! I don't handle CMPS.\n"); + goto cannot_emulate; + case 0xaa ... 0xab: /* stos */ + dst.type = OP_MEM; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + dst.ptr = (unsigned long *)cr2; + dst.val = _regs[VCPU_REGS_RAX]; + register_address_increment(_regs[VCPU_REGS_RDI], + (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); + break; + case 0xac ... 0xad: /* lods */ + dst.type = OP_REG; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; + if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0) + goto done; + register_address_increment(_regs[VCPU_REGS_RSI], + (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); + break; + case 0xae ... 0xaf: /* scas */ + DPRINTF("Urk! I don't handle SCAS.\n"); + goto cannot_emulate; + } + goto writeback; + +twobyte_insn: + switch (b) { + case 0x01: /* lgdt, lidt, lmsw */ + switch (modrm_reg) { + u16 size; + unsigned long address; + + case 2: /* lgdt */ + rc = read_descriptor(ctxt, ops, src.ptr, + &size, &address, op_bytes); + if (rc) + goto done; + realmode_lgdt(ctxt->vcpu, size, address); + break; + case 3: /* lidt */ + rc = read_descriptor(ctxt, ops, src.ptr, + &size, &address, op_bytes); + if (rc) + goto done; + realmode_lidt(ctxt->vcpu, size, address); + break; + case 4: /* smsw */ + if (modrm_mod != 3) + goto cannot_emulate; + *(u16 *)&_regs[modrm_rm] + = realmode_get_cr(ctxt->vcpu, 0); + break; + case 6: /* lmsw */ + if (modrm_mod != 3) + goto cannot_emulate; + realmode_lmsw(ctxt->vcpu, (u16)modrm_val, &_eflags); + break; + case 7: /* invlpg*/ + emulate_invlpg(ctxt->vcpu, cr2); + break; + default: + goto cannot_emulate; + } + break; + case 0x21: /* mov from dr to reg */ + if (modrm_mod != 3) + goto cannot_emulate; + rc = emulator_get_dr(ctxt, modrm_reg, &_regs[modrm_rm]); + break; + case 0x23: /* mov from reg to dr */ + if (modrm_mod != 3) + goto cannot_emulate; + rc = emulator_set_dr(ctxt, modrm_reg, _regs[modrm_rm]); + break; + case 0x40 ... 0x4f: /* cmov */ + dst.val = dst.orig_val = src.val; + d &= ~Mov; /* default to no move */ + /* + * First, assume we're decoding an even cmov opcode + * (lsb == 0). + */ + switch ((b & 15) >> 1) { + case 0: /* cmovo */ + d |= (_eflags & EFLG_OF) ? Mov : 0; + break; + case 1: /* cmovb/cmovc/cmovnae */ + d |= (_eflags & EFLG_CF) ? Mov : 0; + break; + case 2: /* cmovz/cmove */ + d |= (_eflags & EFLG_ZF) ? Mov : 0; + break; + case 3: /* cmovbe/cmovna */ + d |= (_eflags & (EFLG_CF | EFLG_ZF)) ? Mov : 0; + break; + case 4: /* cmovs */ + d |= (_eflags & EFLG_SF) ? Mov : 0; + break; + case 5: /* cmovp/cmovpe */ + d |= (_eflags & EFLG_PF) ? Mov : 0; + break; + case 7: /* cmovle/cmovng */ + d |= (_eflags & EFLG_ZF) ? Mov : 0; + /* fall through */ + case 6: /* cmovl/cmovnge */ + d |= (!(_eflags & EFLG_SF) != + !(_eflags & EFLG_OF)) ? Mov : 0; + break; + } + /* Odd cmov opcodes (lsb == 1) have inverted sense. */ + d ^= (b & 1) ? Mov : 0; + break; + case 0xb0 ... 0xb1: /* cmpxchg */ + /* + * Save real source value, then compare EAX against + * destination. + */ + src.orig_val = src.val; + src.val = _regs[VCPU_REGS_RAX]; + emulate_2op_SrcV("cmp", src, dst, _eflags); + /* Always write back. The question is: where to? */ + d |= Mov; + if (_eflags & EFLG_ZF) { + /* Success: write back to memory. */ + dst.val = src.orig_val; + } else { + /* Failure: write the value we saw to EAX. */ + dst.type = OP_REG; + dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; + } + break; + case 0xa3: + bt: /* bt */ + src.val &= (dst.bytes << 3) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("bt", src, dst, _eflags); + break; + case 0xb3: + btr: /* btr */ + src.val &= (dst.bytes << 3) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("btr", src, dst, _eflags); + break; + case 0xab: + bts: /* bts */ + src.val &= (dst.bytes << 3) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("bts", src, dst, _eflags); + break; + case 0xb6 ... 0xb7: /* movzx */ + dst.bytes = op_bytes; + dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val; + break; + case 0xbb: + btc: /* btc */ + src.val &= (dst.bytes << 3) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("btc", src, dst, _eflags); + break; + case 0xba: /* Grp8 */ + switch (modrm_reg & 3) { + case 0: + goto bt; + case 1: + goto bts; + case 2: + goto btr; + case 3: + goto btc; + } + break; + case 0xbe ... 0xbf: /* movsx */ + dst.bytes = op_bytes; + dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val; + break; + } + goto writeback; + +twobyte_special_insn: + /* Disable writeback. */ + dst.orig_val = dst.val; + switch (b) { + case 0x0d: /* GrpP (prefetch) */ + case 0x18: /* Grp16 (prefetch/nop) */ + break; + case 0x06: + emulate_clts(ctxt->vcpu); + break; + case 0x20: /* mov cr, reg */ + if (modrm_mod != 3) + goto cannot_emulate; + _regs[modrm_rm] = realmode_get_cr(ctxt->vcpu, modrm_reg); + break; + case 0x22: /* mov reg, cr */ + if (modrm_mod != 3) + goto cannot_emulate; + realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags); + break; + case 0xc7: /* Grp9 (cmpxchg8b) */ +#if defined(__i386__) + { + unsigned long old_lo, old_hi; + if (((rc = ops->read_emulated(cr2 + 0, &old_lo, 4, + ctxt)) != 0) + || ((rc = ops->read_emulated(cr2 + 4, &old_hi, 4, + ctxt)) != 0)) + goto done; + if ((old_lo != _regs[VCPU_REGS_RAX]) + || (old_hi != _regs[VCPU_REGS_RDI])) { + _regs[VCPU_REGS_RAX] = old_lo; + _regs[VCPU_REGS_RDX] = old_hi; + _eflags &= ~EFLG_ZF; + } else if (ops->cmpxchg8b_emulated == NULL) { + rc = X86EMUL_UNHANDLEABLE; + goto done; + } else { + if ((rc = ops->cmpxchg8b_emulated(cr2, old_lo, + old_hi, + _regs[VCPU_REGS_RBX], + _regs[VCPU_REGS_RCX], + ctxt)) != 0) + goto done; + _eflags |= EFLG_ZF; + } + break; + } +#elif defined(__x86_64__) + { + unsigned long old, new; + if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0) + goto done; + if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || + ((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) { + _regs[VCPU_REGS_RAX] = (u32) (old >> 0); + _regs[VCPU_REGS_RDX] = (u32) (old >> 32); + _eflags &= ~EFLG_ZF; + } else { + new = (_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX]; + if ((rc = ops->cmpxchg_emulated(cr2, old, + new, 8, ctxt)) != 0) + goto done; + _eflags |= EFLG_ZF; + } + break; + } +#endif + } + goto writeback; + +cannot_emulate: + DPRINTF("Cannot emulate %02x\n", b); + return -1; +} + +#ifdef __XEN__ + +#include +#include + +int +x86_emulate_read_std(unsigned long addr, + unsigned long *val, + unsigned int bytes, struct x86_emulate_ctxt *ctxt) +{ + unsigned int rc; + + *val = 0; + + if ((rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0) { + propagate_page_fault(addr + bytes - rc, 0); /* read fault */ + return X86EMUL_PROPAGATE_FAULT; + } + + return X86EMUL_CONTINUE; +} + +int +x86_emulate_write_std(unsigned long addr, + unsigned long val, + unsigned int bytes, struct x86_emulate_ctxt *ctxt) +{ + unsigned int rc; + + if ((rc = copy_to_user((void *)addr, (void *)&val, bytes)) != 0) { + propagate_page_fault(addr + bytes - rc, PGERR_write_access); + return X86EMUL_PROPAGATE_FAULT; + } + + return X86EMUL_CONTINUE; +} + +#endif diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h new file mode 100644 index 000000000000..658b58de30fc --- /dev/null +++ b/drivers/kvm/x86_emulate.h @@ -0,0 +1,185 @@ +/****************************************************************************** + * x86_emulate.h + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * Copyright (c) 2005 Keir Fraser + * + * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4 + */ + +#ifndef __X86_EMULATE_H__ +#define __X86_EMULATE_H__ + +struct x86_emulate_ctxt; + +/* + * x86_emulate_ops: + * + * These operations represent the instruction emulator's interface to memory. + * There are two categories of operation: those that act on ordinary memory + * regions (*_std), and those that act on memory regions known to require + * special treatment or emulation (*_emulated). + * + * The emulator assumes that an instruction accesses only one 'emulated memory' + * location, that this location is the given linear faulting address (cr2), and + * that this is one of the instruction's data operands. Instruction fetches and + * stack operations are assumed never to access emulated memory. The emulator + * automatically deduces which operand of a string-move operation is accessing + * emulated memory, and assumes that the other operand accesses normal memory. + * + * NOTES: + * 1. The emulator isn't very smart about emulated vs. standard memory. + * 'Emulated memory' access addresses should be checked for sanity. + * 'Normal memory' accesses may fault, and the caller must arrange to + * detect and handle reentrancy into the emulator via recursive faults. + * Accesses may be unaligned and may cross page boundaries. + * 2. If the access fails (cannot emulate, or a standard access faults) then + * it is up to the memop to propagate the fault to the guest VM via + * some out-of-band mechanism, unknown to the emulator. The memop signals + * failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will + * then immediately bail. + * 3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only + * cmpxchg8b_emulated need support 8-byte accesses. + * 4. The emulator cannot handle 64-bit mode emulation on an x86/32 system. + */ +/* Access completed successfully: continue emulation as normal. */ +#define X86EMUL_CONTINUE 0 +/* Access is unhandleable: bail from emulation and return error to caller. */ +#define X86EMUL_UNHANDLEABLE 1 +/* Terminate emulation but return success to the caller. */ +#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */ +#define X86EMUL_RETRY_INSTR 2 /* retry the instruction for some reason */ +#define X86EMUL_CMPXCHG_FAILED 2 /* cmpxchg did not see expected value */ +struct x86_emulate_ops { + /* + * read_std: Read bytes of standard (non-emulated/special) memory. + * Used for instruction fetch, stack operations, and others. + * @addr: [IN ] Linear address from which to read. + * @val: [OUT] Value read from memory, zero-extended to 'u_long'. + * @bytes: [IN ] Number of bytes to read from memory. + */ + int (*read_std)(unsigned long addr, + unsigned long *val, + unsigned int bytes, struct x86_emulate_ctxt * ctxt); + + /* + * write_std: Write bytes of standard (non-emulated/special) memory. + * Used for stack operations, and others. + * @addr: [IN ] Linear address to which to write. + * @val: [IN ] Value to write to memory (low-order bytes used as + * required). + * @bytes: [IN ] Number of bytes to write to memory. + */ + int (*write_std)(unsigned long addr, + unsigned long val, + unsigned int bytes, struct x86_emulate_ctxt * ctxt); + + /* + * read_emulated: Read bytes from emulated/special memory area. + * @addr: [IN ] Linear address from which to read. + * @val: [OUT] Value read from memory, zero-extended to 'u_long'. + * @bytes: [IN ] Number of bytes to read from memory. + */ + int (*read_emulated) (unsigned long addr, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt * ctxt); + + /* + * write_emulated: Read bytes from emulated/special memory area. + * @addr: [IN ] Linear address to which to write. + * @val: [IN ] Value to write to memory (low-order bytes used as + * required). + * @bytes: [IN ] Number of bytes to write to memory. + */ + int (*write_emulated) (unsigned long addr, + unsigned long val, + unsigned int bytes, + struct x86_emulate_ctxt * ctxt); + + /* + * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an + * emulated/special memory area. + * @addr: [IN ] Linear address to access. + * @old: [IN ] Value expected to be current at @addr. + * @new: [IN ] Value to write to @addr. + * @bytes: [IN ] Number of bytes to access using CMPXCHG. + */ + int (*cmpxchg_emulated) (unsigned long addr, + unsigned long old, + unsigned long new, + unsigned int bytes, + struct x86_emulate_ctxt * ctxt); + + /* + * cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an + * emulated/special memory area. + * @addr: [IN ] Linear address to access. + * @old: [IN ] Value expected to be current at @addr. + * @new: [IN ] Value to write to @addr. + * NOTES: + * 1. This function is only ever called when emulating a real CMPXCHG8B. + * 2. This function is *never* called on x86/64 systems. + * 2. Not defining this function (i.e., specifying NULL) is equivalent + * to defining a function that always returns X86EMUL_UNHANDLEABLE. + */ + int (*cmpxchg8b_emulated) (unsigned long addr, + unsigned long old_lo, + unsigned long old_hi, + unsigned long new_lo, + unsigned long new_hi, + struct x86_emulate_ctxt * ctxt); +}; + +struct cpu_user_regs; + +struct x86_emulate_ctxt { + /* Register state before/after emulation. */ + struct kvm_vcpu *vcpu; + + /* Linear faulting address (if emulating a page-faulting instruction). */ + unsigned long eflags; + unsigned long cr2; + + /* Emulated execution mode, represented by an X86EMUL_MODE value. */ + int mode; + + unsigned long cs_base; + unsigned long ds_base; + unsigned long es_base; + unsigned long ss_base; + unsigned long gs_base; + unsigned long fs_base; +}; + +/* Execution mode, passed to the emulator. */ +#define X86EMUL_MODE_REAL 0 /* Real mode. */ +#define X86EMUL_MODE_PROT16 2 /* 16-bit protected mode. */ +#define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */ +#define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */ + +/* Host execution mode. */ +#if defined(__i386__) +#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32 +#elif defined(__x86_64__) +#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64 +#endif + +/* + * x86_emulate_memop: Emulate an instruction that faulted attempting to + * read/write a 'special' memory area. + * Returns -1 on failure, 0 on success. + */ +int x86_emulate_memop(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops); + +/* + * Given the 'reg' portion of a ModRM byte, and a register block, return a + * pointer into the block that addresses the relevant register. + * @highbyte_regs specifies whether to decode AH,CH,DH,BH. + */ +void *decode_register(u8 modrm_reg, unsigned long *regs, + int highbyte_regs); + +#endif /* __X86_EMULATE_H__ */ diff --git a/include/linux/kvm.h b/include/linux/kvm.h new file mode 100644 index 000000000000..5bb2c3c585c1 --- /dev/null +++ b/include/linux/kvm.h @@ -0,0 +1,227 @@ +#ifndef __LINUX_KVM_H +#define __LINUX_KVM_H + +/* + * Userspace interface for /dev/kvm - kernel based virtual machine + * + * Note: this interface is considered experimental and may change without + * notice. + */ + +#include +#include + +/* + * Architectural interrupt line count, and the size of the bitmap needed + * to hold them. + */ +#define KVM_NR_INTERRUPTS 256 +#define KVM_IRQ_BITMAP_SIZE_BYTES ((KVM_NR_INTERRUPTS + 7) / 8) +#define KVM_IRQ_BITMAP_SIZE(type) (KVM_IRQ_BITMAP_SIZE_BYTES / sizeof(type)) + + +/* for KVM_CREATE_MEMORY_REGION */ +struct kvm_memory_region { + __u32 slot; + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; /* bytes */ +}; + +/* for kvm_memory_region::flags */ +#define KVM_MEM_LOG_DIRTY_PAGES 1UL + + +#define KVM_EXIT_TYPE_FAIL_ENTRY 1 +#define KVM_EXIT_TYPE_VM_EXIT 2 + +enum kvm_exit_reason { + KVM_EXIT_UNKNOWN = 0, + KVM_EXIT_EXCEPTION = 1, + KVM_EXIT_IO = 2, + KVM_EXIT_CPUID = 3, + KVM_EXIT_DEBUG = 4, + KVM_EXIT_HLT = 5, + KVM_EXIT_MMIO = 6, +}; + +/* for KVM_RUN */ +struct kvm_run { + /* in */ + __u32 vcpu; + __u32 emulated; /* skip current instruction */ + __u32 mmio_completed; /* mmio request completed */ + + /* out */ + __u32 exit_type; + __u32 exit_reason; + __u32 instruction_length; + union { + /* KVM_EXIT_UNKNOWN */ + struct { + __u32 hardware_exit_reason; + } hw; + /* KVM_EXIT_EXCEPTION */ + struct { + __u32 exception; + __u32 error_code; + } ex; + /* KVM_EXIT_IO */ + struct { +#define KVM_EXIT_IO_IN 0 +#define KVM_EXIT_IO_OUT 1 + __u8 direction; + __u8 size; /* bytes */ + __u8 string; + __u8 string_down; + __u8 rep; + __u8 pad; + __u16 port; + __u64 count; + union { + __u64 address; + __u32 value; + }; + } io; + struct { + } debug; + /* KVM_EXIT_MMIO */ + struct { + __u64 phys_addr; + __u8 data[8]; + __u32 len; + __u8 is_write; + } mmio; + }; +}; + +/* for KVM_GET_REGS and KVM_SET_REGS */ +struct kvm_regs { + /* in */ + __u32 vcpu; + __u32 padding; + + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ + __u64 rax, rbx, rcx, rdx; + __u64 rsi, rdi, rsp, rbp; + __u64 r8, r9, r10, r11; + __u64 r12, r13, r14, r15; + __u64 rip, rflags; +}; + +struct kvm_segment { + __u64 base; + __u32 limit; + __u16 selector; + __u8 type; + __u8 present, dpl, db, s, l, g, avl; + __u8 unusable; + __u8 padding; +}; + +struct kvm_dtable { + __u64 base; + __u16 limit; + __u16 padding[3]; +}; + +/* for KVM_GET_SREGS and KVM_SET_SREGS */ +struct kvm_sregs { + /* in */ + __u32 vcpu; + __u32 padding; + + /* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */ + struct kvm_segment cs, ds, es, fs, gs, ss; + struct kvm_segment tr, ldt; + struct kvm_dtable gdt, idt; + __u64 cr0, cr2, cr3, cr4, cr8; + __u64 efer; + __u64 apic_base; + __u64 interrupt_bitmap[KVM_IRQ_BITMAP_SIZE(__u64)]; +}; + +struct kvm_msr_entry { + __u32 index; + __u32 reserved; + __u64 data; +}; + +/* for KVM_GET_MSRS and KVM_SET_MSRS */ +struct kvm_msrs { + __u32 vcpu; + __u32 nmsrs; /* number of msrs in entries */ + + struct kvm_msr_entry entries[0]; +}; + +/* for KVM_GET_MSR_INDEX_LIST */ +struct kvm_msr_list { + __u32 nmsrs; /* number of msrs in entries */ + __u32 indices[0]; +}; + +/* for KVM_TRANSLATE */ +struct kvm_translation { + /* in */ + __u64 linear_address; + __u32 vcpu; + __u32 padding; + + /* out */ + __u64 physical_address; + __u8 valid; + __u8 writeable; + __u8 usermode; +}; + +/* for KVM_INTERRUPT */ +struct kvm_interrupt { + /* in */ + __u32 vcpu; + __u32 irq; +}; + +struct kvm_breakpoint { + __u32 enabled; + __u32 padding; + __u64 address; +}; + +/* for KVM_DEBUG_GUEST */ +struct kvm_debug_guest { + /* int */ + __u32 vcpu; + __u32 enabled; + struct kvm_breakpoint breakpoints[4]; + __u32 singlestep; +}; + +/* for KVM_GET_DIRTY_LOG */ +struct kvm_dirty_log { + __u32 slot; + __u32 padding; + union { + void __user *dirty_bitmap; /* one bit per page */ + __u64 padding; + }; +}; + +#define KVMIO 0xAE + +#define KVM_RUN _IOWR(KVMIO, 2, struct kvm_run) +#define KVM_GET_REGS _IOWR(KVMIO, 3, struct kvm_regs) +#define KVM_SET_REGS _IOW(KVMIO, 4, struct kvm_regs) +#define KVM_GET_SREGS _IOWR(KVMIO, 5, struct kvm_sregs) +#define KVM_SET_SREGS _IOW(KVMIO, 6, struct kvm_sregs) +#define KVM_TRANSLATE _IOWR(KVMIO, 7, struct kvm_translation) +#define KVM_INTERRUPT _IOW(KVMIO, 8, struct kvm_interrupt) +#define KVM_DEBUG_GUEST _IOW(KVMIO, 9, struct kvm_debug_guest) +#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 10, struct kvm_memory_region) +#define KVM_CREATE_VCPU _IOW(KVMIO, 11, int /* vcpu_slot */) +#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 12, struct kvm_dirty_log) +#define KVM_GET_MSRS _IOWR(KVMIO, 13, struct kvm_msrs) +#define KVM_SET_MSRS _IOWR(KVMIO, 14, struct kvm_msrs) +#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 15, struct kvm_msr_list) + +#endif -- cgit v1.2.3 From 36cfb5ccfa39ddd030926d08fcf80ba553c88737 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 10 Dec 2006 21:21:28 +0100 Subject: i2c: Update the list of driver IDs * A chip driver ID was assigned to the Radeon, while it is an adapter so it needs an i2c adapter ID. * The SAA7191 is a video decoder, not encoder. * The icspll driver is dead, and will never be ported to Linux 2.6. Signed-off-by: Jean Delvare --- include/linux/i2c-id.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 0a8f750cbede..36f0c5b0cbf7 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -82,9 +82,8 @@ #define I2C_DRIVERID_STM41T00 52 /* real time clock */ #define I2C_DRIVERID_UDA1342 53 /* UDA1342 audio codec */ #define I2C_DRIVERID_ADV7170 54 /* video encoder */ -#define I2C_DRIVERID_RADEON 55 /* I2C bus on Radeon boards */ #define I2C_DRIVERID_MAX1617 56 /* temp sensor */ -#define I2C_DRIVERID_SAA7191 57 /* video encoder */ +#define I2C_DRIVERID_SAA7191 57 /* video decoder */ #define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */ #define I2C_DRIVERID_BT832 59 /* CMOS camera video processor */ #define I2C_DRIVERID_TDA9887 60 /* TDA988x IF-PLL demodulator */ @@ -132,7 +131,6 @@ #define I2C_DRIVERID_ADM1021 1008 #define I2C_DRIVERID_ADM9240 1009 #define I2C_DRIVERID_LTC1710 1010 -#define I2C_DRIVERID_ICSPLL 1012 #define I2C_DRIVERID_BT869 1013 #define I2C_DRIVERID_MAXILIFE 1014 #define I2C_DRIVERID_MATORB 1015 -- cgit v1.2.3 From 51fd554b6547b74c7e6d1f52885ba8532b531023 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 10 Dec 2006 21:21:29 +0100 Subject: i2c: Delete the broken i2c-ite bus driver The rest of the ITE8172 support was already removed from MIPS tree. Signed-off-by: Jean Delvare Signed-off-by: Yoichi Yuasa Acked-by: Ralf Baechle --- Documentation/feature-removal-schedule.txt | 11 - drivers/i2c/algos/Kconfig | 11 - drivers/i2c/algos/Makefile | 1 - drivers/i2c/algos/i2c-algo-ite.c | 806 ----------------------------- drivers/i2c/algos/i2c-algo-ite.h | 117 ----- drivers/i2c/busses/Kconfig | 12 - drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-ite.c | 278 ---------- include/linux/i2c-algo-ite.h | 72 --- include/linux/i2c-id.h | 3 - 10 files changed, 1312 deletions(-) delete mode 100644 drivers/i2c/algos/i2c-algo-ite.c delete mode 100644 drivers/i2c/algos/i2c-algo-ite.h delete mode 100644 drivers/i2c/busses/i2c-ite.c delete mode 100644 include/linux/i2c-algo-ite.h (limited to 'include/linux') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 46f2a559b27c..031029e89fd9 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -216,17 +216,6 @@ Who: Thomas Gleixner --------------------------- -What: i2c-ite and i2c-algo-ite drivers -When: September 2006 -Why: These drivers never compiled since they were added to the kernel - tree 5 years ago. This feature removal can be reevaluated if - someone shows interest in the drivers, fixes them and takes over - maintenance. - http://marc.theaimsgroup.com/?l=linux-mips&m=115040510817448 -Who: Jean Delvare - ---------------------------- - What: Bridge netfilter deferred IPv4/IPv6 output hook calling When: January 2007 Why: The deferred output hooks are a layering violation causing unusual diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig index c034820615bb..af0203409dd1 100644 --- a/drivers/i2c/algos/Kconfig +++ b/drivers/i2c/algos/Kconfig @@ -38,17 +38,6 @@ config I2C_ALGOPCA This support is also available as a module. If so, the module will be called i2c-algo-pca. -config I2C_ALGOITE - tristate "ITE I2C Algorithm" - depends on MIPS_ITE8172 && I2C - help - This supports the use of the ITE8172 I2C interface found on some MIPS - systems. Say Y if you have one of these. You should also say Y for - the ITE I2C peripheral driver support below. - - This support is also available as a module. If so, the module - will be called i2c-algo-ite. - config I2C_ALGO8XX tristate "MPC8xx CPM I2C interface" depends on 8xx && I2C diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile index 208be04a3dbd..cac1051bd4f1 100644 --- a/drivers/i2c/algos/Makefile +++ b/drivers/i2c/algos/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o -obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o ifeq ($(CONFIG_I2C_DEBUG_ALGO),y) diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c deleted file mode 100644 index 70d8eefb5efc..000000000000 --- a/drivers/i2c/algos/i2c-algo-ite.c +++ /dev/null @@ -1,806 +0,0 @@ -/* - ------------------------------------------------------------------------- - i2c-algo-ite.c i2c driver algorithms for ITE adapters - - Hai-Pao Fan, MontaVista Software, Inc. - hpfan@mvista.com or source@mvista.com - - Copyright 2000 MontaVista Software Inc. - - --------------------------------------------------------------------------- - This file was highly leveraged from i2c-algo-pcf.c, which was created - by Simon G. Vogl and Hans Berglund: - - - Copyright (C) 1995-1997 Simon G. Vogl - 1998-2000 Hans Berglund - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* ------------------------------------------------------------------------- */ - -/* With some changes from Kyösti Mälkki and - Frodo Looijaard ,and also from Martin Bailey - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "i2c-algo-ite.h" - -#define PM_DSR IT8172_PCI_IO_BASE + IT_PM_DSR -#define PM_IBSR IT8172_PCI_IO_BASE + IT_PM_DSR + 0x04 -#define GPIO_CCR IT8172_PCI_IO_BASE + IT_GPCCR - -#define DEB2(x) if (i2c_debug>=2) x -#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/ -#define DEF_TIMEOUT 16 - - -/* module parameters: - */ -static int i2c_debug; -static int iic_test; /* see if the line-setting functions work */ - -/* --- setting states on the bus with the right timing: --------------- */ - -#define get_clock(adap) adap->getclock(adap->data) -#define iic_outw(adap, reg, val) adap->setiic(adap->data, reg, val) -#define iic_inw(adap, reg) adap->getiic(adap->data, reg) - - -/* --- other auxiliary functions -------------------------------------- */ - -static void iic_start(struct i2c_algo_iic_data *adap) -{ - iic_outw(adap,ITE_I2CHCR,ITE_CMD); -} - -static void iic_stop(struct i2c_algo_iic_data *adap) -{ - iic_outw(adap,ITE_I2CHCR,0); - iic_outw(adap,ITE_I2CHSR,ITE_I2CHSR_TDI); -} - -static void iic_reset(struct i2c_algo_iic_data *adap) -{ - iic_outw(adap, PM_IBSR, iic_inw(adap, PM_IBSR) | 0x80); -} - - -static int wait_for_bb(struct i2c_algo_iic_data *adap) -{ - int timeout = DEF_TIMEOUT; - short status; - - status = iic_inw(adap, ITE_I2CHSR); -#ifndef STUB_I2C - while (timeout-- && (status & ITE_I2CHSR_HB)) { - udelay(1000); /* How much is this? */ - status = iic_inw(adap, ITE_I2CHSR); - } -#endif - if (timeout<=0) { - printk(KERN_ERR "Timeout, host is busy\n"); - iic_reset(adap); - } - return(timeout<=0); -} - -/* After we issue a transaction on the IIC bus, this function - * is called. It puts this process to sleep until we get an interrupt from - * from the controller telling us that the transaction we requested in complete. - */ -static int wait_for_pin(struct i2c_algo_iic_data *adap, short *status) { - - int timeout = DEF_TIMEOUT; - - timeout = wait_for_bb(adap); - if (timeout) { - DEB2(printk("Timeout waiting for host not busy\n");) - return -EIO; - } - timeout = DEF_TIMEOUT; - - *status = iic_inw(adap, ITE_I2CHSR); -#ifndef STUB_I2C - while (timeout-- && !(*status & ITE_I2CHSR_TDI)) { - adap->waitforpin(); - *status = iic_inw(adap, ITE_I2CHSR); - } -#endif - if (timeout <= 0) - return(-1); - else - return(0); -} - -static int wait_for_fe(struct i2c_algo_iic_data *adap, short *status) -{ - int timeout = DEF_TIMEOUT; - - *status = iic_inw(adap, ITE_I2CFSR); -#ifndef STUB_I2C - while (timeout-- && (*status & ITE_I2CFSR_FE)) { - udelay(1000); - iic_inw(adap, ITE_I2CFSR); - } -#endif - if (timeout <= 0) - return(-1); - else - return(0); -} - -static int iic_init (struct i2c_algo_iic_data *adap) -{ - short i; - - /* Clear bit 7 to set I2C to normal operation mode */ - i=iic_inw(adap, PM_DSR)& 0xff7f; - iic_outw(adap, PM_DSR, i); - - /* set IT_GPCCR port C bit 2&3 as function 2 */ - i = iic_inw(adap, GPIO_CCR) & 0xfc0f; - iic_outw(adap,GPIO_CCR,i); - - /* Clear slave address/sub-address */ - iic_outw(adap,ITE_I2CSAR, 0); - iic_outw(adap,ITE_I2CSSAR, 0); - - /* Set clock counter register */ - iic_outw(adap,ITE_I2CCKCNT, get_clock(adap)); - - /* Set START/reSTART/STOP time registers */ - iic_outw(adap,ITE_I2CSHDR, 0x0a); - iic_outw(adap,ITE_I2CRSUR, 0x0a); - iic_outw(adap,ITE_I2CPSUR, 0x0a); - - /* Enable interrupts on completing the current transaction */ - iic_outw(adap,ITE_I2CHCR, ITE_I2CHCR_IE | ITE_I2CHCR_HCE); - - /* Clear transfer count */ - iic_outw(adap,ITE_I2CFBCR, 0x0); - - DEB2(printk("iic_init: Initialized IIC on ITE 0x%x\n", - iic_inw(adap, ITE_I2CHSR))); - return 0; -} - - -/* - * Sanity check for the adapter hardware - check the reaction of - * the bus lines only if it seems to be idle. - */ -static int test_bus(struct i2c_algo_iic_data *adap, char *name) { -#if 0 - int scl,sda; - sda=getsda(adap); - if (adap->getscl==NULL) { - printk("test_bus: Warning: Adapter can't read from clock line - skipping test.\n"); - return 0; - } - scl=getscl(adap); - printk("test_bus: Adapter: %s scl: %d sda: %d -- testing...\n", - name,getscl(adap),getsda(adap)); - if (!scl || !sda ) { - printk("test_bus: %s seems to be busy.\n",adap->name); - goto bailout; - } - sdalo(adap); - printk("test_bus:1 scl: %d sda: %d\n", getscl(adap), - getsda(adap)); - if ( 0 != getsda(adap) ) { - printk("test_bus: %s SDA stuck high!\n",name); - sdahi(adap); - goto bailout; - } - if ( 0 == getscl(adap) ) { - printk("test_bus: %s SCL unexpected low while pulling SDA low!\n", - name); - goto bailout; - } - sdahi(adap); - printk("test_bus:2 scl: %d sda: %d\n", getscl(adap), - getsda(adap)); - if ( 0 == getsda(adap) ) { - printk("test_bus: %s SDA stuck low!\n",name); - sdahi(adap); - goto bailout; - } - if ( 0 == getscl(adap) ) { - printk("test_bus: %s SCL unexpected low while SDA high!\n", - adap->name); - goto bailout; - } - scllo(adap); - printk("test_bus:3 scl: %d sda: %d\n", getscl(adap), - getsda(adap)); - if ( 0 != getscl(adap) ) { - - sclhi(adap); - goto bailout; - } - if ( 0 == getsda(adap) ) { - printk("test_bus: %s SDA unexpected low while pulling SCL low!\n", - name); - goto bailout; - } - sclhi(adap); - printk("test_bus:4 scl: %d sda: %d\n", getscl(adap), - getsda(adap)); - if ( 0 == getscl(adap) ) { - printk("test_bus: %s SCL stuck low!\n",name); - sclhi(adap); - goto bailout; - } - if ( 0 == getsda(adap) ) { - printk("test_bus: %s SDA unexpected low while SCL high!\n", - name); - goto bailout; - } - printk("test_bus: %s passed test.\n",name); - return 0; -bailout: - sdahi(adap); - sclhi(adap); - return -ENODEV; -#endif - return (0); -} - -/* ----- Utility functions - */ - - -/* Verify the device we want to talk to on the IIC bus really exists. */ -static inline int try_address(struct i2c_algo_iic_data *adap, - unsigned int addr, int retries) -{ - int i, ret = -1; - short status; - - for (i=0;iudelay); - } - DEB2(if (i) printk("try_address: needed %d retries for 0x%x\n",i, - addr)); - return ret; -} - - -static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf, - int count) -{ - struct i2c_algo_iic_data *adap = i2c_adap->algo_data; - int wrcount=0, timeout; - short status; - int loops, remainder, i, j; - union { - char byte[2]; - unsigned short word; - } tmp; - - iic_outw(adap, ITE_I2CSSAR, (unsigned short)buf[wrcount++]); - count--; - if (count == 0) - return -EIO; - - loops = count / 32; /* 32-byte FIFO */ - remainder = count % 32; - - if(loops) { - for(i=0; iname); - return -EREMOTEIO; /* got a better one ?? */ - } - if (status & ITE_I2CHSR_DB) { - iic_stop(adap); - printk("iic_sendbytes: %s write error - no ack.\n", i2c_adap->name); - return -EREMOTEIO; /* got a better one ?? */ - } - } - } - if(remainder) { - iic_outw(adap, ITE_I2CFBCR, remainder); - for(i=0; iname); - return -EREMOTEIO; /* got a better one ?? */ - } -#ifndef STUB_I2C - if (status & ITE_I2CHSR_DB) { - iic_stop(adap); - printk("iic_sendbytes: %s write error - no ack.\n", i2c_adap->name); - return -EREMOTEIO; /* got a better one ?? */ - } -#endif - } - iic_stop(adap); - return wrcount; -} - - -static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, - int sread) -{ - int rdcount=0, i, timeout; - short status; - struct i2c_algo_iic_data *adap = i2c_adap->algo_data; - int loops, remainder, j; - union { - char byte[2]; - unsigned short word; - } tmp; - - loops = count / 32; /* 32-byte FIFO */ - remainder = count % 32; - - if(loops) { - for(i=0; iname); - return (-1); - } -#ifndef STUB_I2C - if (status & ITE_I2CHSR_DB) { - iic_stop(adap); - printk("iic_readbytes: %s read error - no ack.\n", i2c_adap->name); - return (-1); - } -#endif - - timeout = wait_for_fe(adap, &status); - if(timeout) { - iic_stop(adap); - printk("iic_readbytes: %s FIFO is empty\n", i2c_adap->name); - return (-1); - } - - for(j=0; j<32/2; j++) { - tmp.word = iic_inw(adap, ITE_I2CFDR); - buf[rdcount++] = tmp.byte[1]; - buf[rdcount++] = tmp.byte[0]; - } - - /* status FIFO underrun */ - iic_inw(adap, ITE_I2CFSR); - - } - } - - - if(remainder) { - remainder=(remainder+1)/2 * 2; - iic_outw(adap, ITE_I2CFBCR, remainder); - if (sread) - iic_outw(adap, ITE_I2CHCR, ITE_SREAD); - else - iic_outw(adap, ITE_I2CHCR, ITE_READ); /* Issue READ command */ - - timeout = wait_for_pin(adap, &status); - if(timeout) { - iic_stop(adap); - printk("iic_readbytes: %s read timeout.\n", i2c_adap->name); - return (-1); - } -#ifndef STUB_I2C - if (status & ITE_I2CHSR_DB) { - iic_stop(adap); - printk("iic_readbytes: %s read error - no ack.\n", i2c_adap->name); - return (-1); - } -#endif - timeout = wait_for_fe(adap, &status); - if(timeout) { - iic_stop(adap); - printk("iic_readbytes: %s FIFO is empty\n", i2c_adap->name); - return (-1); - } - - for(i=0; i<(remainder+1)/2; i++) { - tmp.word = iic_inw(adap, ITE_I2CFDR); - buf[rdcount++] = tmp.byte[1]; - buf[rdcount++] = tmp.byte[0]; - } - - /* status FIFO underrun */ - iic_inw(adap, ITE_I2CFSR); - - } - - iic_stop(adap); - return rdcount; -} - - -/* This function implements combined transactions. Combined - * transactions consist of combinations of reading and writing blocks of data. - * Each transfer (i.e. a read or a write) is separated by a repeated start - * condition. - */ -#if 0 -static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) -{ - int i; - struct i2c_msg *pmsg; - int ret; - - DEB2(printk("Beginning combined transaction\n")); - - for(i=0; i<(num-1); i++) { - pmsg = &msgs[i]; - if(pmsg->flags & I2C_M_RD) { - DEB2(printk(" This one is a read\n")); - ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_COMBINED_XFER); - } - else if(!(pmsg->flags & I2C_M_RD)) { - DEB2(printk("This one is a write\n")); - ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_COMBINED_XFER); - } - } - /* Last read or write segment needs to be terminated with a stop */ - pmsg = &msgs[i]; - - if(pmsg->flags & I2C_M_RD) { - DEB2(printk("Doing the last read\n")); - ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER); - } - else if(!(pmsg->flags & I2C_M_RD)) { - DEB2(printk("Doing the last write\n")); - ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER); - } - - return ret; -} -#endif - - -/* Whenever we initiate a transaction, the first byte clocked - * onto the bus after the start condition is the address (7 bit) of the - * device we want to talk to. This function manipulates the address specified - * so that it makes sense to the hardware when written to the IIC peripheral. - * - * Note: 10 bit addresses are not supported in this driver, although they are - * supported by the hardware. This functionality needs to be implemented. - */ -static inline int iic_doAddress(struct i2c_algo_iic_data *adap, - struct i2c_msg *msg, int retries) -{ - unsigned short flags = msg->flags; - unsigned int addr; - int ret; - -/* Ten bit addresses not supported right now */ - if ( (flags & I2C_M_TEN) ) { -#if 0 - addr = 0xf0 | (( msg->addr >> 7) & 0x03); - DEB2(printk("addr0: %d\n",addr)); - ret = try_address(adap, addr, retries); - if (ret!=1) { - printk("iic_doAddress: died at extended address code.\n"); - return -EREMOTEIO; - } - iic_outw(adap,msg->addr & 0x7f); - if (ret != 1) { - printk("iic_doAddress: died at 2nd address code.\n"); - return -EREMOTEIO; - } - if ( flags & I2C_M_RD ) { - i2c_repstart(adap); - addr |= 0x01; - ret = try_address(adap, addr, retries); - if (ret!=1) { - printk("iic_doAddress: died at extended address code.\n"); - return -EREMOTEIO; - } - } -#endif - } else { - - addr = ( msg->addr << 1 ); - -#if 0 - if (flags & I2C_M_RD ) - addr |= 1; - if (flags & I2C_M_REV_DIR_ADDR ) - addr ^= 1; -#endif - - if (iic_inw(adap, ITE_I2CSAR) != addr) { - iic_outw(adap, ITE_I2CSAR, addr); - ret = try_address(adap, addr, retries); - if (ret!=1) { - printk("iic_doAddress: died at address code.\n"); - return -EREMOTEIO; - } - } - - } - - return 0; -} - - -/* Description: Prepares the controller for a transaction (clearing status - * registers, data buffers, etc), and then calls either iic_readbytes or - * iic_sendbytes to do the actual transaction. - * - * still to be done: Before we issue a transaction, we should - * verify that the bus is not busy or in some unknown state. - */ -static int iic_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg *msgs, - int num) -{ - struct i2c_algo_iic_data *adap = i2c_adap->algo_data; - struct i2c_msg *pmsg; - int i = 0; - int ret, timeout; - - pmsg = &msgs[i]; - - if(!pmsg->len) { - DEB2(printk("iic_xfer: read/write length is 0\n");) - return -EIO; - } - if(!(pmsg->flags & I2C_M_RD) && (!(pmsg->len)%2) ) { - DEB2(printk("iic_xfer: write buffer length is not odd\n");) - return -EIO; - } - - /* Wait for any pending transfers to complete */ - timeout = wait_for_bb(adap); - if (timeout) { - DEB2(printk("iic_xfer: Timeout waiting for host not busy\n");) - return -EIO; - } - - /* Flush FIFO */ - iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH); - - /* Load address */ - ret = iic_doAddress(adap, pmsg, i2c_adap->retries); - if (ret) - return -EIO; - -#if 0 - /* Combined transaction (read and write) */ - if(num > 1) { - DEB2(printk("iic_xfer: Call combined transaction\n")); - ret = iic_combined_transaction(i2c_adap, msgs, num); - } -#endif - - DEB3(printk("iic_xfer: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", - i, msgs[i].addr, msgs[i].flags, msgs[i].len);) - - if(pmsg->flags & I2C_M_RD) /* Read */ - ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, 0); - else { /* Write */ - udelay(1000); - ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len); - } - - if (ret != pmsg->len) - DEB3(printk("iic_xfer: error or fail on read/write %d bytes.\n",ret)); - else - DEB3(printk("iic_xfer: read/write %d bytes.\n",ret)); - - return ret; -} - - -/* Implements device specific ioctls. Higher level ioctls can - * be found in i2c-core.c and are typical of any i2c controller (specifying - * slave address, timeouts, etc). These ioctls take advantage of any hardware - * features built into the controller for which this algorithm-adapter set - * was written. These ioctls allow you to take control of the data and clock - * lines and set the either high or low, - * similar to a GPIO pin. - */ -static int algo_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - - struct i2c_algo_iic_data *adap = adapter->algo_data; - struct i2c_iic_msg s_msg; - char *buf; - int ret; - - if (cmd == I2C_SREAD) { - if(copy_from_user(&s_msg, (struct i2c_iic_msg *)arg, - sizeof(struct i2c_iic_msg))) - return -EFAULT; - buf = kmalloc(s_msg.len, GFP_KERNEL); - if (buf== NULL) - return -ENOMEM; - - /* Flush FIFO */ - iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH); - - /* Load address */ - iic_outw(adap, ITE_I2CSAR,s_msg.addr<<1); - iic_outw(adap, ITE_I2CSSAR,s_msg.waddr & 0xff); - - ret = iic_readbytes(adapter, buf, s_msg.len, 1); - if (ret>=0) { - if(copy_to_user( s_msg.buf, buf, s_msg.len) ) - ret = -EFAULT; - } - kfree(buf); - } - return 0; -} - - -static u32 iic_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | - I2C_FUNC_PROTOCOL_MANGLING; -} - -/* -----exported algorithm data: ------------------------------------- */ - -static struct i2c_algorithm iic_algo = { - .master_xfer = iic_xfer, - .algo_control = algo_control, /* ioctl */ - .functionality = iic_func, -}; - - -/* - * registering functions to load algorithms at runtime - */ -int i2c_iic_add_bus(struct i2c_adapter *adap) -{ - struct i2c_algo_iic_data *iic_adap = adap->algo_data; - - if (iic_test) { - int ret = test_bus(iic_adap, adap->name); - if (ret<0) - return -ENODEV; - } - - DEB2(printk("i2c-algo-ite: hw routines for %s registered.\n", - adap->name)); - - /* register new adapter to i2c module... */ - adap->algo = &iic_algo; - - adap->timeout = 100; /* default values, should */ - adap->retries = 3; /* be replaced by defines */ - adap->flags = 0; - - iic_init(iic_adap); - return i2c_add_adapter(adap); -} - - -int i2c_iic_del_bus(struct i2c_adapter *adap) -{ - int res; - if ((res = i2c_del_adapter(adap)) < 0) - return res; - DEB2(printk("i2c-algo-ite: adapter unregistered: %s\n",adap->name)); - - return 0; -} - - -int __init i2c_algo_iic_init (void) -{ - printk(KERN_INFO "ITE iic (i2c) algorithm module\n"); - return 0; -} - - -void i2c_algo_iic_exit(void) -{ - return; -} - - -EXPORT_SYMBOL(i2c_iic_add_bus); -EXPORT_SYMBOL(i2c_iic_del_bus); - -/* The MODULE_* macros resolve to nothing if MODULES is not defined - * when this file is compiled. - */ -MODULE_AUTHOR("MontaVista Software "); -MODULE_DESCRIPTION("ITE iic algorithm"); -MODULE_LICENSE("GPL"); - -module_param(iic_test, bool, 0); -module_param(i2c_debug, int, S_IRUGO | S_IWUSR); - -MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available"); -MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol"); - - -/* This function resolves to init_module (the function invoked when a module - * is loaded via insmod) when this file is compiled with MODULES defined. - * Otherwise (i.e. if you want this driver statically linked to the kernel), - * a pointer to this function is stored in a table and called - * during the initialization of the kernel (in do_basic_setup in /init/main.c) - * - * All this functionality is complements of the macros defined in linux/init.h - */ -module_init(i2c_algo_iic_init); - - -/* If MODULES is defined when this file is compiled, then this function will - * resolved to cleanup_module. - */ -module_exit(i2c_algo_iic_exit); diff --git a/drivers/i2c/algos/i2c-algo-ite.h b/drivers/i2c/algos/i2c-algo-ite.h deleted file mode 100644 index a8ca3c9b546a..000000000000 --- a/drivers/i2c/algos/i2c-algo-ite.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - -------------------------------------------------------------------- - i2c-ite.h: Global defines for the I2C controller on board the - ITE MIPS processor. - -------------------------------------------------------------------- - Hai-Pao Fan, MontaVista Software, Inc. - hpfan@mvista.com or source@mvista.com - - Copyright 2001 MontaVista Software Inc. - - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#ifndef I2C_ITE_H -#define I2C_ITE_H 1 - -#include - -/* I2C Registers */ -#define ITE_I2CHCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x30 -#define ITE_I2CHSR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x34 -#define ITE_I2CSAR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x38 -#define ITE_I2CSSAR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x3c -#define ITE_I2CCKCNT IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x48 -#define ITE_I2CSHDR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x4c -#define ITE_I2CRSUR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x50 -#define ITE_I2CPSUR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x54 - -#define ITE_I2CFDR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x70 -#define ITE_I2CFBCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x74 -#define ITE_I2CFCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x78 -#define ITE_I2CFSR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x7c - - -/* Host Control Register ITE_I2CHCR */ -#define ITE_I2CHCR_HCE 0x01 /* Enable I2C Host Controller */ -#define ITE_I2CHCR_IE 0x02 /* Enable the interrupt after completing - the current transaction */ -#define ITE_I2CHCR_CP_W 0x00 /* bit2-4 000 - Write */ -#define ITE_I2CHCR_CP_R 0x08 /* 010 - Current address read */ -#define ITE_I2CHCR_CP_S 0x10 /* 100 - Sequential read */ -#define ITE_I2CHCR_ST 0x20 /* Initiates the I2C host controller to execute - the command and send the data programmed in - all required registers to I2C bus */ -#define ITE_CMD ITE_I2CHCR_HCE | ITE_I2CHCR_IE | ITE_I2CHCR_ST -#define ITE_WRITE ITE_CMD | ITE_I2CHCR_CP_W -#define ITE_READ ITE_CMD | ITE_I2CHCR_CP_R -#define ITE_SREAD ITE_CMD | ITE_I2CHCR_CP_S - -/* Host Status Register ITE_I2CHSR */ -#define ITE_I2CHSR_DB 0x01 /* Device is busy, receives NACK response except - in the first and last bytes */ -#define ITE_I2CHSR_DNE 0x02 /* Target address on I2C bus does not exist */ -#define ITE_I2CHSR_TDI 0x04 /* R/W Transaction on I2C bus was completed */ -#define ITE_I2CHSR_HB 0x08 /* Host controller is processing transactions */ -#define ITE_I2CHSR_FER 0x10 /* Error occurs in the FIFO */ - -/* Slave Address Register ITE_I2CSAR */ -#define ITE_I2CSAR_SA_MASK 0xfe /* Target I2C device address */ -#define ITE_I2CSAR_ASO 0x0100 /* Output 1/0 to I2CAS port when the - next slave address is addressed */ - -/* Slave Sub-address Register ITE_I2CSSAR */ -#define ITE_I2CSSAR_SUBA_MASK 0xff /* Target I2C device sub-address */ - -/* Clock Counter Register ITE_I2CCKCNT */ -#define ITE_I2CCKCNT_STOP 0x00 /* stop I2C clock */ -#define ITE_I2CCKCNT_HPCC_MASK 0x7f /* SCL high period counter */ -#define ITE_I2CCKCNT_LPCC_MASK 0x7f00 /* SCL low period counter */ - -/* START Hold Time Register ITE_I2CSHDR */ -/* value is counted based on 16 MHz internal clock */ -#define ITE_I2CSHDR_FM 0x0a /* START condition at fast mode */ -#define ITE_I2CSHDR_SM 0x47 /* START contition at standard mode */ - -/* (Repeated) START Setup Time Register ITE_I2CRSUR */ -/* value is counted based on 16 MHz internal clock */ -#define ITE_I2CRSUR_FM 0x0a /* repeated START condition at fast mode */ -#define ITE_I2CRSUR_SM 0x50 /* repeated START condition at standard mode */ - -/* STOP setup Time Register ITE_I2CPSUR */ - -/* FIFO Data Register ITE_I2CFDR */ -#define ITE_I2CFDR_MASK 0xff - -/* FIFO Byte Count Register ITE_I2CFBCR */ -#define ITE_I2CFBCR_MASK 0x3f - -/* FIFO Control Register ITE_I2CFCR */ -#define ITE_I2CFCR_FLUSH 0x01 /* Flush FIFO and reset the FIFO point - and I2CFSR */ -/* FIFO Status Register ITE_I2CFSR */ -#define ITE_I2CFSR_FO 0x01 /* FIFO is overrun when write */ -#define ITE_I2CFSR_FU 0x02 /* FIFO is underrun when read */ -#define ITE_I2CFSR_FF 0x04 /* FIFO is full when write */ -#define ITE_I2CFSR_FE 0x08 /* FIFO is empty when read */ - -#endif /* I2C_ITE_H */ diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 90f91d039ee2..7c9ab337d180 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -209,18 +209,6 @@ config I2C_ISA tristate depends on I2C -config I2C_ITE - tristate "ITE I2C Adapter" - depends on I2C && MIPS_ITE8172 - select I2C_ALGOITE - help - This supports the ITE8172 I2C peripheral found on some MIPS - systems. Say Y if you have one of these. You should also say Y for - the ITE I2C driver algorithm support above. - - This support is also available as a module. If so, the module - will be called i2c-ite. - config I2C_IXP4XX tristate "IXP4xx GPIO-Based I2C Interface" depends on I2C && ARCH_IXP4XX diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 493c87289b62..bf5fd078b292 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_I2C_I810) += i2c-i810.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_ISA) += i2c-isa.o -obj-$(CONFIG_I2C_ITE) += i2c-ite.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c deleted file mode 100644 index f7d71869b3b9..000000000000 --- a/drivers/i2c/busses/i2c-ite.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - ------------------------------------------------------------------------- - i2c-adap-ite.c i2c-hw access for the IIC peripheral on the ITE MIPS system - ------------------------------------------------------------------------- - Hai-Pao Fan, MontaVista Software, Inc. - hpfan@mvista.com or source@mvista.com - - Copyright 2001 MontaVista Software Inc. - - ---------------------------------------------------------------------------- - This file was highly leveraged from i2c-elektor.c, which was created - by Simon G. Vogl and Hans Berglund: - - - Copyright (C) 1995-97 Simon G. Vogl - 1998-99 Hans Berglund - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* ------------------------------------------------------------------------- */ - -/* With some changes from Kyösti Mälkki and even - Frodo Looijaard */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "../i2c-ite.h" - -#define DEFAULT_BASE 0x14014030 -#define ITE_IIC_IO_SIZE 0x40 -#define DEFAULT_IRQ 0 -#define DEFAULT_CLOCK 0x1b0e /* default 16MHz/(27+14) = 400KHz */ -#define DEFAULT_OWN 0x55 - -static int base; -static int irq; -static int clock; -static int own; - -static struct iic_ite gpi; -static wait_queue_head_t iic_wait; -static int iic_pending; -static spinlock_t lock; - -/* ----- local functions ---------------------------------------------- */ - -static void iic_ite_setiic(void *data, int ctl, short val) -{ - unsigned long j = jiffies + 10; - - pr_debug(" Write 0x%02x to 0x%x\n",(unsigned short)val, ctl&0xff); -#ifdef DEBUG - while (time_before(jiffies, j)) - schedule(); -#endif - outw(val,ctl); -} - -static short iic_ite_getiic(void *data, int ctl) -{ - short val; - - val = inw(ctl); - pr_debug("Read 0x%02x from 0x%x\n",(unsigned short)val, ctl&0xff); - return (val); -} - -/* Return our slave address. This is the address - * put on the I2C bus when another master on the bus wants to address us - * as a slave - */ -static int iic_ite_getown(void *data) -{ - return (gpi.iic_own); -} - - -static int iic_ite_getclock(void *data) -{ - return (gpi.iic_clock); -} - - -/* Put this process to sleep. We will wake up when the - * IIC controller interrupts. - */ -static void iic_ite_waitforpin(void) { - DEFINE_WAIT(wait); - int timeout = 2; - unsigned long flags; - - /* If interrupts are enabled (which they are), then put the process to - * sleep. This process will be awakened by two events -- either the - * the IIC peripheral interrupts or the timeout expires. - * If interrupts are not enabled then delay for a reasonable amount - * of time and return. - */ - if (gpi.iic_irq > 0) { - spin_lock_irqsave(&lock, flags); - if (iic_pending == 0) { - spin_unlock_irqrestore(&lock, flags); - prepare_to_wait(&iic_wait, &wait, TASK_INTERRUPTIBLE); - if (schedule_timeout(timeout*HZ)) { - spin_lock_irqsave(&lock, flags); - if (iic_pending == 1) { - iic_pending = 0; - } - spin_unlock_irqrestore(&lock, flags); - } - finish_wait(&iic_wait, &wait); - } else { - iic_pending = 0; - spin_unlock_irqrestore(&lock, flags); - } - } else { - udelay(100); - } -} - - -static irqreturn_t iic_ite_handler(int this_irq, void *dev_id) -{ - spin_lock(&lock); - iic_pending = 1; - spin_unlock(&lock); - - wake_up_interruptible(&iic_wait); - - return IRQ_HANDLED; -} - - -/* Lock the region of memory where I/O registers exist. Request our - * interrupt line and register its associated handler. - */ -static int iic_hw_resrc_init(void) -{ - if (!request_region(gpi.iic_base, ITE_IIC_IO_SIZE, "i2c")) - return -ENODEV; - - if (gpi.iic_irq <= 0) - return 0; - - if (request_irq(gpi.iic_irq, iic_ite_handler, 0, "ITE IIC", 0) < 0) - gpi.iic_irq = 0; - else - enable_irq(gpi.iic_irq); - - return 0; -} - - -static void iic_ite_release(void) -{ - if (gpi.iic_irq > 0) { - disable_irq(gpi.iic_irq); - free_irq(gpi.iic_irq, 0); - } - release_region(gpi.iic_base , 2); -} - -/* ------------------------------------------------------------------------ - * Encapsulate the above functions in the correct operations structure. - * This is only done when more than one hardware adapter is supported. - */ -static struct i2c_algo_iic_data iic_ite_data = { - NULL, - iic_ite_setiic, - iic_ite_getiic, - iic_ite_getown, - iic_ite_getclock, - iic_ite_waitforpin, - 80, 80, 100, /* waits, timeout */ -}; - -static struct i2c_adapter iic_ite_ops = { - .owner = THIS_MODULE, - .id = I2C_HW_I_IIC, - .algo_data = &iic_ite_data, - .name = "ITE IIC adapter", -}; - -/* Called when the module is loaded. This function starts the - * cascade of calls up through the hierarchy of i2c modules (i.e. up to the - * algorithm layer and into to the core layer) - */ -static int __init iic_ite_init(void) -{ - - struct iic_ite *piic = &gpi; - - printk(KERN_INFO "Initialize ITE IIC adapter module\n"); - if (base == 0) - piic->iic_base = DEFAULT_BASE; - else - piic->iic_base = base; - - if (irq == 0) - piic->iic_irq = DEFAULT_IRQ; - else - piic->iic_irq = irq; - - if (clock == 0) - piic->iic_clock = DEFAULT_CLOCK; - else - piic->iic_clock = clock; - - if (own == 0) - piic->iic_own = DEFAULT_OWN; - else - piic->iic_own = own; - - iic_ite_data.data = (void *)piic; - init_waitqueue_head(&iic_wait); - spin_lock_init(&lock); - if (iic_hw_resrc_init() == 0) { - if (i2c_iic_add_bus(&iic_ite_ops) < 0) - return -ENODEV; - } else { - return -ENODEV; - } - printk(KERN_INFO " found device at %#x irq %d.\n", - piic->iic_base, piic->iic_irq); - return 0; -} - - -static void iic_ite_exit(void) -{ - i2c_iic_del_bus(&iic_ite_ops); - iic_ite_release(); -} - -/* If modules is NOT defined when this file is compiled, then the MODULE_* - * macros will resolve to nothing - */ -MODULE_AUTHOR("MontaVista Software "); -MODULE_DESCRIPTION("I2C-Bus adapter routines for ITE IIC bus adapter"); -MODULE_LICENSE("GPL"); - -module_param(base, int, 0); -module_param(irq, int, 0); -module_param(clock, int, 0); -module_param(own, int, 0); - - -/* Called when module is loaded or when kernel is initialized. - * If MODULES is defined when this file is compiled, then this function will - * resolve to init_module (the function called when insmod is invoked for a - * module). Otherwise, this function is called early in the boot, when the - * kernel is intialized. Check out /include/init.h to see how this works. - */ -module_init(iic_ite_init); - -/* Resolves to module_cleanup when MODULES is defined. */ -module_exit(iic_ite_exit); diff --git a/include/linux/i2c-algo-ite.h b/include/linux/i2c-algo-ite.h deleted file mode 100644 index 0073fe96c76e..000000000000 --- a/include/linux/i2c-algo-ite.h +++ /dev/null @@ -1,72 +0,0 @@ -/* ------------------------------------------------------------------------- */ -/* i2c-algo-ite.h i2c driver algorithms for ITE IIC adapters */ -/* ------------------------------------------------------------------------- */ -/* Copyright (C) 1995-97 Simon G. Vogl - 1998-99 Hans Berglund - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* ------------------------------------------------------------------------- */ - -/* With some changes from Kyösti Mälkki and even - Frodo Looijaard */ - -/* Modifications by MontaVista Software, 2001 - Changes made to support the ITE IIC peripheral */ - - -#ifndef I2C_ALGO_ITE_H -#define I2C_ALGO_ITE_H 1 - -#include - -/* Example of a sequential read request: - struct i2c_iic_msg s_msg; - - s_msg.addr=device_address; - s_msg.len=length; - s_msg.buf=buffer; - s_msg.waddr=word_address; - ioctl(file,I2C_SREAD, &s_msg); - */ -#define I2C_SREAD 0x780 /* SREAD ioctl command */ - -struct i2c_iic_msg { - __u16 addr; /* device address */ - __u16 waddr; /* word address */ - short len; /* msg length */ - char *buf; /* pointer to msg data */ -}; - -#ifdef __KERNEL__ -struct i2c_adapter; - -struct i2c_algo_iic_data { - void *data; /* private data for lolevel routines */ - void (*setiic) (void *data, int ctl, int val); - int (*getiic) (void *data, int ctl); - int (*getown) (void *data); - int (*getclock) (void *data); - void (*waitforpin) (void); - - /* local settings */ - int udelay; - int mdelay; - int timeout; -}; - -int i2c_iic_add_bus(struct i2c_adapter *); -int i2c_iic_del_bus(struct i2c_adapter *); -#endif /* __KERNEL__ */ -#endif /* I2C_ALGO_ITE_H */ diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 36f0c5b0cbf7..00da370bbcd6 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -210,9 +210,6 @@ /* --- MPC8xx PowerPC adapters */ #define I2C_HW_MPC8XX_EPON 0x110000 /* Eponymous MPC8xx I2C adapter */ -/* --- ITE based algorithms */ -#define I2C_HW_I_IIC 0x080000 /* controller on the ITE */ - /* --- PowerPC on-chip adapters */ #define I2C_HW_OCP 0x120000 /* IBM on-chip I2C adapter */ -- cgit v1.2.3 From 41561f28e76a47dc6de0a954da85d0b5c42874eb Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Sun, 10 Dec 2006 21:21:29 +0100 Subject: i2c: New Philips PNX bus driver New I2C bus driver for Philips ARM boards (Philips IP3204 I2C IP block). This I2C controller can be found on (at least) PNX010x, PNX52xx and PNX4008 Philips boards. Signed-off-by: Vitaly Wool Signed-off-by: Jean Delvare --- arch/arm/mach-pnx4008/Makefile | 2 +- arch/arm/mach-pnx4008/i2c.c | 167 +++++++++ drivers/i2c/busses/Kconfig | 19 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-pnx.c | 708 +++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-pnx4008/i2c.h | 67 ++++ include/linux/i2c-pnx.h | 43 +++ 7 files changed, 1006 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-pnx4008/i2c.c create mode 100644 drivers/i2c/busses/i2c-pnx.c create mode 100644 include/asm-arm/arch-pnx4008/i2c.h create mode 100644 include/linux/i2c-pnx.h (limited to 'include/linux') diff --git a/arch/arm/mach-pnx4008/Makefile b/arch/arm/mach-pnx4008/Makefile index b457ca0a431a..777564c90a12 100644 --- a/arch/arm/mach-pnx4008/Makefile +++ b/arch/arm/mach-pnx4008/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y := core.o irq.o time.o clock.o gpio.o serial.o dma.o +obj-y := core.o irq.o time.o clock.o gpio.o serial.o dma.o i2c.o obj-m := obj-n := obj- := diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c new file mode 100644 index 000000000000..6f308827c4fe --- /dev/null +++ b/arch/arm/mach-pnx4008/i2c.c @@ -0,0 +1,167 @@ +/* + * I2C initialization for PNX4008. + * + * Author: Vitaly Wool + * + * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +static int set_clock_run(struct platform_device *pdev) +{ + struct clk *clk; + char name[10]; + int retval = 0; + + snprintf(name, 10, "i2c%d_ck", pdev->id); + clk = clk_get(&pdev->dev, name); + if (!IS_ERR(clk)) { + clk_set_rate(clk, 1); + clk_put(clk); + } else + retval = -ENOENT; + + return retval; +} + +static int set_clock_stop(struct platform_device *pdev) +{ + struct clk *clk; + char name[10]; + int retval = 0; + + snprintf(name, 10, "i2c%d_ck", pdev->id); + clk = clk_get(&pdev->dev, name); + if (!IS_ERR(clk)) { + clk_set_rate(clk, 0); + clk_put(clk); + } else + retval = -ENOENT; + + return retval; +} + +static int i2c_pnx_suspend(struct platform_device *pdev, pm_message_t state) +{ + int retval = 0; +#ifdef CONFIG_PM + retval = set_clock_run(pdev); +#endif + return retval; +} + +static int i2c_pnx_resume(struct platform_device *pdev) +{ + int retval = 0; +#ifdef CONFIG_PM + retval = set_clock_run(pdev); +#endif + return retval; +} + +static u32 calculate_input_freq(struct platform_device *pdev) +{ + return HCLK_MHZ; +} + + +static struct i2c_pnx_algo_data pnx_algo_data0 = { + .base = PNX4008_I2C1_BASE, + .irq = I2C_1_INT, +}; + +static struct i2c_pnx_algo_data pnx_algo_data1 = { + .base = PNX4008_I2C2_BASE, + .irq = I2C_2_INT, +}; + +static struct i2c_pnx_algo_data pnx_algo_data2 = { + .base = (PNX4008_USB_CONFIG_BASE + 0x300), + .irq = USB_I2C_INT, +}; + +static struct i2c_adapter pnx_adapter0 = { + .name = I2C_CHIP_NAME "0", + .algo_data = &pnx_algo_data0, +}; +static struct i2c_adapter pnx_adapter1 = { + .name = I2C_CHIP_NAME "1", + .algo_data = &pnx_algo_data1, +}; + +static struct i2c_adapter pnx_adapter2 = { + .name = "USB-I2C", + .algo_data = &pnx_algo_data2, +}; + +static struct i2c_pnx_data i2c0_data = { + .suspend = i2c_pnx_suspend, + .resume = i2c_pnx_resume, + .calculate_input_freq = calculate_input_freq, + .set_clock_run = set_clock_run, + .set_clock_stop = set_clock_stop, + .adapter = &pnx_adapter0, +}; + +static struct i2c_pnx_data i2c1_data = { + .suspend = i2c_pnx_suspend, + .resume = i2c_pnx_resume, + .calculate_input_freq = calculate_input_freq, + .set_clock_run = set_clock_run, + .set_clock_stop = set_clock_stop, + .adapter = &pnx_adapter1, +}; + +static struct i2c_pnx_data i2c2_data = { + .suspend = i2c_pnx_suspend, + .resume = i2c_pnx_resume, + .calculate_input_freq = calculate_input_freq, + .set_clock_run = set_clock_run, + .set_clock_stop = set_clock_stop, + .adapter = &pnx_adapter2, +}; + +static struct platform_device i2c0_device = { + .name = "pnx-i2c", + .id = 0, + .dev = { + .platform_data = &i2c0_data, + }, +}; + +static struct platform_device i2c1_device = { + .name = "pnx-i2c", + .id = 1, + .dev = { + .platform_data = &i2c1_data, + }, +}; + +static struct platform_device i2c2_device = { + .name = "pnx-i2c", + .id = 2, + .dev = { + .platform_data = &i2c2_data, + }, +}; + +static struct platform_device *devices[] __initdata = { + &i2c0_device, + &i2c1_device, + &i2c2_device, +}; + +void __init pnx4008_register_i2c_devices(void) +{ + platform_add_devices(devices, ARRAY_SIZE(devices)); +} diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7c9ab337d180..291da25e84d1 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -536,4 +536,23 @@ config I2C_MV64XXX This driver can also be built as a module. If so, the module will be called i2c-mv64xxx. +config I2C_PNX + tristate "I2C bus support for Philips PNX targets" + depends on ARCH_PNX4008 && I2C + help + This driver supports the Philips IP3204 I2C IP block master and/or + slave controller + + This driver can also be built as a module. If so, the module + will be called i2c-pnx. + +config I2C_PNX_EARLY + bool "Early initialization for I2C on PNXxxxx" + depends on I2C_PNX=y + help + Under certain circumstances one may need to make sure I2C on PNXxxxx + is initialized earlier than some other driver that depends on it + (for instance, that might be USB in case of PNX4008). With this + option turned on you can guarantee that. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index bf5fd078b292..626ac71af959 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o +obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c new file mode 100644 index 000000000000..de0bca77e926 --- /dev/null +++ b/drivers/i2c/busses/i2c-pnx.c @@ -0,0 +1,708 @@ +/* + * Provides I2C support for Philips PNX010x/PNX4008 boards. + * + * Authors: Dennis Kovalev + * Vitaly Wool + * + * 2004-2006 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_PNX_TIMEOUT 10 /* msec */ +#define I2C_PNX_SPEED_KHZ 100 +#define I2C_PNX_REGION_SIZE 0x100 +#define PNX_DEFAULT_FREQ 13 /* MHz */ + +static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data) +{ + while (timeout > 0 && + (ioread32(I2C_REG_STS(data)) & mstatus_active)) { + mdelay(1); + timeout--; + } + return (timeout <= 0); +} + +static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data) +{ + while (timeout > 0 && + (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) { + mdelay(1); + timeout--; + } + return (timeout <= 0); +} + +static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *data = adap->algo_data; + struct timer_list *timer = &data->mif.timer; + int expires = I2C_PNX_TIMEOUT / (1000 / HZ); + + del_timer_sync(timer); + + dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n", + jiffies, expires); + + timer->expires = jiffies + expires; + timer->data = (unsigned long)adap; + + add_timer(timer); +} + +/** + * i2c_pnx_start - start a device + * @slave_addr: slave address + * @adap: pointer to adapter structure + * + * Generate a START signal in the desired mode. + */ +static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + + dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __FUNCTION__, + slave_addr, alg_data->mif.mode); + + /* Check for 7 bit slave addresses only */ + if (slave_addr & ~0x7f) { + dev_err(&adap->dev, "%s: Invalid slave address %x. " + "Only 7-bit addresses are supported\n", + adap->name, slave_addr); + return -EINVAL; + } + + /* First, make sure bus is idle */ + if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) { + /* Somebody else is monopolizing the bus */ + dev_err(&adap->dev, "%s: Bus busy. Slave addr = %02x, " + "cntrl = %x, stat = %x\n", + adap->name, slave_addr, + ioread32(I2C_REG_CTL(alg_data)), + ioread32(I2C_REG_STS(alg_data))); + return -EBUSY; + } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) { + /* Sorry, we lost the bus */ + dev_err(&adap->dev, "%s: Arbitration failure. " + "Slave addr = %02x\n", adap->name, slave_addr); + return -EIO; + } + + /* + * OK, I2C is enabled and we have the bus. + * Clear the current TDI and AFI status flags. + */ + iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi, + I2C_REG_STS(alg_data)); + + dev_dbg(&adap->dev, "%s(): sending %#x\n", __FUNCTION__, + (slave_addr << 1) | start_bit | alg_data->mif.mode); + + /* Write the slave address, START bit and R/W bit */ + iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode, + I2C_REG_TX(alg_data)); + + dev_dbg(&adap->dev, "%s(): exit\n", __FUNCTION__); + + return 0; +} + +/** + * i2c_pnx_stop - stop a device + * @adap: pointer to I2C adapter structure + * + * Generate a STOP signal to terminate the master transaction. + */ +static void i2c_pnx_stop(struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + /* Only 1 msec max timeout due to interrupt context */ + long timeout = 1000; + + dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + /* Write a STOP bit to TX FIFO */ + iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data)); + + /* Wait until the STOP is seen. */ + while (timeout > 0 && + (ioread32(I2C_REG_STS(alg_data)) & mstatus_active)) { + /* may be called from interrupt context */ + udelay(1); + timeout--; + } + + dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); +} + +/** + * i2c_pnx_master_xmit - transmit data to slave + * @adap: pointer to I2C adapter structure + * + * Sends one byte of data to the slave + */ +static int i2c_pnx_master_xmit(struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + u32 val; + + dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + if (alg_data->mif.len > 0) { + /* We still have something to talk about... */ + val = *alg_data->mif.buf++; + + if (alg_data->mif.len == 1) { + val |= stop_bit; + if (!alg_data->last) + val |= start_bit; + } + + alg_data->mif.len--; + iowrite32(val, I2C_REG_TX(alg_data)); + + dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __FUNCTION__, + val, alg_data->mif.len + 1); + + if (alg_data->mif.len == 0) { + if (alg_data->last) { + /* Wait until the STOP is seen. */ + if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) + dev_err(&adap->dev, "The bus is still " + "active after timeout\n"); + } + /* Disable master interrupts */ + iowrite32(ioread32(I2C_REG_CTL(alg_data)) & + ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), + I2C_REG_CTL(alg_data)); + + del_timer_sync(&alg_data->mif.timer); + + dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n", + __FUNCTION__); + + complete(&alg_data->mif.complete); + } + } else if (alg_data->mif.len == 0) { + /* zero-sized transfer */ + i2c_pnx_stop(adap); + + /* Disable master interrupts. */ + iowrite32(ioread32(I2C_REG_CTL(alg_data)) & + ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), + I2C_REG_CTL(alg_data)); + + /* Stop timer. */ + del_timer_sync(&alg_data->mif.timer); + dev_dbg(&adap->dev, "%s(): Waking up xfer routine after " + "zero-xfer.\n", __FUNCTION__); + + complete(&alg_data->mif.complete); + } + + dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + return 0; +} + +/** + * i2c_pnx_master_rcv - receive data from slave + * @adap: pointer to I2C adapter structure + * + * Reads one byte data from the slave + */ +static int i2c_pnx_master_rcv(struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + unsigned int val = 0; + u32 ctl = 0; + + dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + /* Check, whether there is already data, + * or we didn't 'ask' for it yet. + */ + if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { + dev_dbg(&adap->dev, "%s(): Write dummy data to fill " + "Rx-fifo...\n", __FUNCTION__); + + if (alg_data->mif.len == 1) { + /* Last byte, do not acknowledge next rcv. */ + val |= stop_bit; + if (!alg_data->last) + val |= start_bit; + + /* + * Enable interrupt RFDAIE (data in Rx fifo), + * and disable DRMIE (need data for Tx) + */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl |= mcntrl_rffie | mcntrl_daie; + ctl &= ~mcntrl_drmie; + iowrite32(ctl, I2C_REG_CTL(alg_data)); + } + + /* + * Now we'll 'ask' for data: + * For each byte we want to receive, we must + * write a (dummy) byte to the Tx-FIFO. + */ + iowrite32(val, I2C_REG_TX(alg_data)); + + return 0; + } + + /* Handle data. */ + if (alg_data->mif.len > 0) { + val = ioread32(I2C_REG_RX(alg_data)); + *alg_data->mif.buf++ = (u8) (val & 0xff); + dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __FUNCTION__, val, + alg_data->mif.len); + + alg_data->mif.len--; + if (alg_data->mif.len == 0) { + if (alg_data->last) + /* Wait until the STOP is seen. */ + if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) + dev_err(&adap->dev, "The bus is still " + "active after timeout\n"); + + /* Disable master interrupts */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | + mcntrl_drmie | mcntrl_daie); + iowrite32(ctl, I2C_REG_CTL(alg_data)); + + /* Kill timer. */ + del_timer_sync(&alg_data->mif.timer); + complete(&alg_data->mif.complete); + } + } + + dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + return 0; +} + +static irqreturn_t +i2c_pnx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 stat, ctl; + struct i2c_adapter *adap = dev_id; + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + + dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n", + __FUNCTION__, + ioread32(I2C_REG_STS(alg_data)), + ioread32(I2C_REG_CTL(alg_data)), + alg_data->mif.mode); + stat = ioread32(I2C_REG_STS(alg_data)); + + /* let's see what kind of event this is */ + if (stat & mstatus_afi) { + /* We lost arbitration in the midst of a transfer */ + alg_data->mif.ret = -EIO; + + /* Disable master interrupts. */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | + mcntrl_drmie); + iowrite32(ctl, I2C_REG_CTL(alg_data)); + + /* Stop timer, to prevent timeout. */ + del_timer_sync(&alg_data->mif.timer); + complete(&alg_data->mif.complete); + } else if (stat & mstatus_nai) { + /* Slave did not acknowledge, generate a STOP */ + dev_dbg(&adap->dev, "%s(): " + "Slave did not acknowledge, generating a STOP.\n", + __FUNCTION__); + i2c_pnx_stop(adap); + + /* Disable master interrupts. */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | + mcntrl_drmie); + iowrite32(ctl, I2C_REG_CTL(alg_data)); + + /* Our return value. */ + alg_data->mif.ret = -EIO; + + /* Stop timer, to prevent timeout. */ + del_timer_sync(&alg_data->mif.timer); + complete(&alg_data->mif.complete); + } else { + /* + * Two options: + * - Master Tx needs data. + * - There is data in the Rx-fifo + * The latter is only the case if we have requested for data, + * via a dummy write. (See 'i2c_pnx_master_rcv'.) + * We therefore check, as a sanity check, whether that interrupt + * has been enabled. + */ + if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) { + if (alg_data->mif.mode == I2C_SMBUS_WRITE) { + i2c_pnx_master_xmit(adap); + } else if (alg_data->mif.mode == I2C_SMBUS_READ) { + i2c_pnx_master_rcv(adap); + } + } + } + + /* Clear TDI and AFI bits */ + stat = ioread32(I2C_REG_STS(alg_data)); + iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data)); + + dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data)), + ioread32(I2C_REG_CTL(alg_data))); + + return IRQ_HANDLED; +} + +static void i2c_pnx_timeout(unsigned long data) +{ + struct i2c_adapter *adap = (struct i2c_adapter *)data; + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + u32 ctl; + + dev_err(&adap->dev, "Master timed out. stat = %04x, cntrl = %04x. " + "Resetting master...\n", + ioread32(I2C_REG_STS(alg_data)), + ioread32(I2C_REG_CTL(alg_data))); + + /* Reset master and disable interrupts */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | mcntrl_drmie); + iowrite32(ctl, I2C_REG_CTL(alg_data)); + + ctl |= mcntrl_reset; + iowrite32(ctl, I2C_REG_CTL(alg_data)); + wait_reset(I2C_PNX_TIMEOUT, alg_data); + alg_data->mif.ret = -EIO; + complete(&alg_data->mif.complete); +} + +static inline void bus_reset_if_active(struct i2c_adapter *adap) +{ + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + u32 stat; + + if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) { + dev_err(&adap->dev, + "%s: Bus is still active after xfer. Reset it...\n", + adap->name); + iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, + I2C_REG_CTL(alg_data)); + wait_reset(I2C_PNX_TIMEOUT, alg_data); + } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) { + /* If there is data in the fifo's after transfer, + * flush fifo's by reset. + */ + iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, + I2C_REG_CTL(alg_data)); + wait_reset(I2C_PNX_TIMEOUT, alg_data); + } else if (stat & mstatus_nai) { + iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, + I2C_REG_CTL(alg_data)); + wait_reset(I2C_PNX_TIMEOUT, alg_data); + } +} + +/** + * i2c_pnx_xfer - generic transfer entry point + * @adap: pointer to I2C adapter structure + * @msgs: array of messages + * @num: number of messages + * + * Initiates the transfer + */ +static int +i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct i2c_msg *pmsg; + int rc = 0, completed = 0, i; + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + u32 stat = ioread32(I2C_REG_STS(alg_data)); + + dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n", + __FUNCTION__, num, ioread32(I2C_REG_STS(alg_data))); + + bus_reset_if_active(adap); + + /* Process transactions in a loop. */ + for (i = 0; rc >= 0 && i < num; i++) { + u8 addr; + + pmsg = &msgs[i]; + addr = pmsg->addr; + + if (pmsg->flags & I2C_M_TEN) { + dev_err(&adap->dev, + "%s: 10 bits addr not supported!\n", + adap->name); + rc = -EINVAL; + break; + } + + alg_data->mif.buf = pmsg->buf; + alg_data->mif.len = pmsg->len; + alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? + I2C_SMBUS_READ : I2C_SMBUS_WRITE; + alg_data->mif.ret = 0; + alg_data->last = (i == num - 1); + + dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __FUNCTION__, + alg_data->mif.mode, + alg_data->mif.len); + + i2c_pnx_arm_timer(adap); + + /* initialize the completion var */ + init_completion(&alg_data->mif.complete); + + /* Enable master interrupt */ + iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie | + mcntrl_naie | mcntrl_drmie, + I2C_REG_CTL(alg_data)); + + /* Put start-code and slave-address on the bus. */ + rc = i2c_pnx_start(addr, adap); + if (rc < 0) + break; + + /* Wait for completion */ + wait_for_completion(&alg_data->mif.complete); + + if (!(rc = alg_data->mif.ret)) + completed++; + dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n", + __FUNCTION__, rc); + + /* Clear TDI and AFI bits in case they are set. */ + if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) { + dev_dbg(&adap->dev, + "%s: TDI still set... clearing now.\n", + adap->name); + iowrite32(stat, I2C_REG_STS(alg_data)); + } + if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) { + dev_dbg(&adap->dev, + "%s: AFI still set... clearing now.\n", + adap->name); + iowrite32(stat, I2C_REG_STS(alg_data)); + } + } + + bus_reset_if_active(adap); + + /* Cleanup to be sure... */ + alg_data->mif.buf = NULL; + alg_data->mif.len = 0; + + dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n", + __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); + + if (completed != num) + return ((rc < 0) ? rc : -EREMOTEIO); + + return num; +} + +static u32 i2c_pnx_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm pnx_algorithm = { + .master_xfer = i2c_pnx_xfer, + .functionality = i2c_pnx_func, +}; + +static int i2c_pnx_controller_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); + return i2c_pnx->suspend(pdev, state); +} + +static int i2c_pnx_controller_resume(struct platform_device *pdev) +{ + struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); + return i2c_pnx->resume(pdev); +} + +static int __devinit i2c_pnx_probe(struct platform_device *pdev) +{ + unsigned long tmp; + int ret = 0; + struct i2c_pnx_algo_data *alg_data; + int freq_mhz; + struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data; + + if (!i2c_pnx || !i2c_pnx->adapter) { + dev_err(&pdev->dev, "%s: no platform data supplied\n", + __FUNCTION__); + ret = -EINVAL; + goto out; + } + + platform_set_drvdata(pdev, i2c_pnx); + + if (i2c_pnx->calculate_input_freq) + freq_mhz = i2c_pnx->calculate_input_freq(pdev); + else { + freq_mhz = PNX_DEFAULT_FREQ; + dev_info(&pdev->dev, "Setting bus frequency to default value: " + "%d MHz", freq_mhz); + } + + i2c_pnx->adapter->algo = &pnx_algorithm; + + alg_data = i2c_pnx->adapter->algo_data; + init_timer(&alg_data->mif.timer); + alg_data->mif.timer.function = i2c_pnx_timeout; + alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter; + + /* Register I/O resource */ + if (!request_region(alg_data->base, I2C_PNX_REGION_SIZE, pdev->name)) { + dev_err(&pdev->dev, + "I/O region 0x%08x for I2C already in use.\n", + alg_data->base); + ret = -ENODEV; + goto out_drvdata; + } + + if (!(alg_data->ioaddr = + (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) { + dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n"); + ret = -ENOMEM; + goto out_release; + } + + i2c_pnx->set_clock_run(pdev); + + /* + * Clock Divisor High This value is the number of system clocks + * the serial clock (SCL) will be high. + * For example, if the system clock period is 50 ns and the maximum + * desired serial period is 10000 ns (100 kHz), then CLKHI would be + * set to 0.5*(f_sys/f_i2c)-2=0.5*(20e6/100e3)-2=98. The actual value + * programmed into CLKHI will vary from this slightly due to + * variations in the output pad's rise and fall times as well as + * the deglitching filter length. + */ + + tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; + iowrite32(tmp, I2C_REG_CKH(alg_data)); + iowrite32(tmp, I2C_REG_CKL(alg_data)); + + iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data)); + if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) { + ret = -ENODEV; + goto out_unmap; + } + init_completion(&alg_data->mif.complete); + + ret = request_irq(alg_data->irq, i2c_pnx_interrupt, + 0, pdev->name, i2c_pnx->adapter); + if (ret) + goto out_clock; + + /* Register this adapter with the I2C subsystem */ + i2c_pnx->adapter->dev.parent = &pdev->dev; + ret = i2c_add_adapter(i2c_pnx->adapter); + if (ret < 0) { + dev_err(&pdev->dev, "I2C: Failed to add bus\n"); + goto out_irq; + } + + dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", + i2c_pnx->adapter->name, alg_data->base, alg_data->irq); + + return 0; + +out_irq: + free_irq(alg_data->irq, alg_data); +out_clock: + i2c_pnx->set_clock_stop(pdev); +out_unmap: + iounmap((void *)alg_data->ioaddr); +out_release: + release_region(alg_data->base, I2C_PNX_REGION_SIZE); +out_drvdata: + platform_set_drvdata(pdev, NULL); +out: + return ret; +} + +static int __devexit i2c_pnx_remove(struct platform_device *pdev) +{ + struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); + struct i2c_adapter *adap = i2c_pnx->adapter; + struct i2c_pnx_algo_data *alg_data = adap->algo_data; + + free_irq(alg_data->irq, alg_data); + i2c_del_adapter(adap); + i2c_pnx->set_clock_stop(pdev); + iounmap((void *)alg_data->ioaddr); + release_region(alg_data->base, I2C_PNX_REGION_SIZE); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver i2c_pnx_driver = { + .driver = { + .name = "pnx-i2c", + .owner = THIS_MODULE, + }, + .probe = i2c_pnx_probe, + .remove = __devexit_p(i2c_pnx_remove), + .suspend = i2c_pnx_controller_suspend, + .resume = i2c_pnx_controller_resume, +}; + +static int __init i2c_adap_pnx_init(void) +{ + return platform_driver_register(&i2c_pnx_driver); +} + +static void __exit i2c_adap_pnx_exit(void) +{ + platform_driver_unregister(&i2c_pnx_driver); +} + +MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev "); +MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_I2C_PNX_EARLY +/* We need to make sure I2C is initialized before USB */ +subsys_initcall(i2c_adap_pnx_init); +#else +mudule_init(i2c_adap_pnx_init); +#endif +module_exit(i2c_adap_pnx_exit); diff --git a/include/asm-arm/arch-pnx4008/i2c.h b/include/asm-arm/arch-pnx4008/i2c.h new file mode 100644 index 000000000000..92e8d65006f7 --- /dev/null +++ b/include/asm-arm/arch-pnx4008/i2c.h @@ -0,0 +1,67 @@ +/* + * PNX4008-specific tweaks for I2C IP3204 block + * + * Author: Vitaly Wool + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifndef __ASM_ARCH_I2C_H__ +#define __ASM_ARCH_I2C_H__ + +#include +#include + +enum { + mstatus_tdi = 0x00000001, + mstatus_afi = 0x00000002, + mstatus_nai = 0x00000004, + mstatus_drmi = 0x00000008, + mstatus_active = 0x00000020, + mstatus_scl = 0x00000040, + mstatus_sda = 0x00000080, + mstatus_rff = 0x00000100, + mstatus_rfe = 0x00000200, + mstatus_tff = 0x00000400, + mstatus_tfe = 0x00000800, +}; + +enum { + mcntrl_tdie = 0x00000001, + mcntrl_afie = 0x00000002, + mcntrl_naie = 0x00000004, + mcntrl_drmie = 0x00000008, + mcntrl_daie = 0x00000020, + mcntrl_rffie = 0x00000040, + mcntrl_tffie = 0x00000080, + mcntrl_reset = 0x00000100, + mcntrl_cdbmode = 0x00000400, +}; + +enum { + rw_bit = 1 << 0, + start_bit = 1 << 8, + stop_bit = 1 << 9, +}; + +#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */ +#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */ +#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */ +#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */ +#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */ +#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */ +#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */ +#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */ +#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */ +#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */ +#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */ +#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */ +#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */ + +#define HCLK_MHZ 13 +#define I2C_CHIP_NAME "PNX4008-I2C" + +#endif /* __ASM_ARCH_I2C_H___ */ diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h new file mode 100644 index 000000000000..e6e9c814da61 --- /dev/null +++ b/include/linux/i2c-pnx.h @@ -0,0 +1,43 @@ +/* + * Header file for I2C support on PNX010x/4008. + * + * Author: Dennis Kovalev + * + * 2004-2006 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifndef __I2C_PNX_H__ +#define __I2C_PNX_H__ + +#include + +struct i2c_pnx_mif { + int ret; /* Return value */ + int mode; /* Interface mode */ + struct completion complete; /* I/O completion */ + struct timer_list timer; /* Timeout */ + char * buf; /* Data buffer */ + int len; /* Length of data buffer */ +}; + +struct i2c_pnx_algo_data { + u32 base; + u32 ioaddr; + int irq; + struct i2c_pnx_mif mif; + int last; +}; + +struct i2c_pnx_data { + int (*suspend) (struct platform_device *pdev, pm_message_t state); + int (*resume) (struct platform_device *pdev); + u32 (*calculate_input_freq) (struct platform_device *pdev); + int (*set_clock_run) (struct platform_device *pdev); + int (*set_clock_stop) (struct platform_device *pdev); + struct i2c_adapter *adapter; +}; + +#endif /* __I2C_PNX_H__ */ -- cgit v1.2.3 From 6ea23039cb1cc7c379eb5fba0ed2c53291e9bea7 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Sun, 10 Dec 2006 21:21:30 +0100 Subject: i2c: Add support for nested i2c bus locking This patch adds the 'level' field into the i2c_adapter structure, which is used to represent the 'logical' level of nesting for the purposes of lockdep. This field is then used in the i2c_transfer() function, to acquire the per-adapter bus_lock with correct nesting level. Signed-off-by: Jiri Kosina Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 2 +- include/linux/i2c.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 7ca81f42d14b..79eaa12474dd 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -603,7 +603,7 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) } #endif - mutex_lock(&adap->bus_lock); + mutex_lock_nested(&adap->bus_lock, adap->level); ret = adap->algo->master_xfer(adap,msgs,num); mutex_unlock(&adap->bus_lock); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 9b5d04768c2c..08df4169b411 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -216,6 +216,7 @@ struct i2c_adapter { int (*client_unregister)(struct i2c_client *); /* data fields that are valid for all devices */ + u8 level; /* nesting level for lockdep */ struct mutex bus_lock; struct mutex clist_lock; -- cgit v1.2.3 From 438d6c2c015cf63bf7e9bdc2033d435433ac8455 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 10 Dec 2006 21:21:31 +0100 Subject: i2c: Whitespace cleanups Remove extraneous whitespace from various i2c headers and core files, like space-before-tab and whitespace at end of line. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 54 ++++++++++++++++---------------- drivers/i2c/i2c-dev.c | 34 ++++++++++---------- include/linux/i2c-algo-bit.h | 4 +-- include/linux/i2c-algo-pcf.h | 2 +- include/linux/i2c-id.h | 10 +++--- include/linux/i2c.h | 74 ++++++++++++++++++++++---------------------- 6 files changed, 89 insertions(+), 89 deletions(-) (limited to 'include/linux') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 79eaa12474dd..64f11e00651c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -127,7 +127,7 @@ static ssize_t show_client_name(struct device *dev, struct device_attribute *att return sprintf(buf, "%s\n", client->name); } -/* +/* * We can't use the DEVICE_ATTR() macro here as we want the same filename for a * different type of a device. So beware if the DEVICE_ATTR() macro ever * changes, this definition will also have to change. @@ -139,8 +139,8 @@ static struct device_attribute dev_attr_client_name = { /* --------------------------------------------------- - * registering functions - * --------------------------------------------------- + * registering functions + * --------------------------------------------------- */ /* ----- @@ -314,7 +314,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) res = driver_register(&driver->driver); if (res) return res; - + mutex_lock(&core_lists); list_add_tail(&driver->list,&drivers); @@ -338,13 +338,13 @@ int i2c_del_driver(struct i2c_driver *driver) struct list_head *item1, *item2, *_n; struct i2c_client *client; struct i2c_adapter *adap; - + int res = 0; mutex_lock(&core_lists); /* Have a look at each adapter, if clients of this driver are still - * attached. If so, detach them to be able to kill the driver + * attached. If so, detach them to be able to kill the driver * afterwards. */ list_for_each(item1,&adapters) { @@ -419,14 +419,14 @@ int i2c_attach_client(struct i2c_client *client) goto out_unlock; } list_add_tail(&client->list,&adapter->clients); - + client->usage_count = 0; client->dev.parent = &client->adapter->dev; client->dev.driver = &client->driver->driver; client->dev.bus = &i2c_bus_type; client->dev.release = &i2c_client_release; - + snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", @@ -467,7 +467,7 @@ int i2c_detach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; int res = 0; - + if (client->usage_count > 0) { dev_warn(&client->dev, "Client [%s] still busy, " "can't detach\n", client->name); @@ -535,10 +535,10 @@ int i2c_release_client(struct i2c_client *client) __FUNCTION__); return -EPERM; } - + client->usage_count--; i2c_dec_use_client(client); - + return 0; } @@ -624,7 +624,7 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count) msg.flags = client->flags & I2C_M_TEN; msg.len = count; msg.buf = (char *)buf; - + ret = i2c_transfer(adap, &msg, 1); /* If everything went ok (i.e. 1 msg transmitted), return #bytes @@ -757,7 +757,7 @@ int i2c_probe(struct i2c_adapter *adapter, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { if (address_data->probe[0] == I2C_CLIENT_END && address_data->normal_i2c[0] == I2C_CLIENT_END) - return 0; + return 0; dev_warn(&adapter->dev, "SMBus Quick command not supported, " "can't probe for chips\n"); @@ -817,7 +817,7 @@ int i2c_probe(struct i2c_adapter *adapter, struct i2c_adapter* i2c_get_adapter(int id) { struct i2c_adapter *adapter; - + mutex_lock(&core_lists); adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) @@ -834,14 +834,14 @@ void i2c_put_adapter(struct i2c_adapter *adap) /* The SMBus parts */ -#define POLY (0x1070U << 3) +#define POLY (0x1070U << 3) static u8 crc8(u16 data) { int i; - + for(i = 0; i < 8; i++) { - if (data & 0x8000) + if (data & 0x8000) data = data ^ POLY; data = data << 1; } @@ -891,13 +891,13 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) rpec, cpec); return -1; } - return 0; + return 0; } s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value) { return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - value,0,I2C_SMBUS_QUICK,NULL); + value,0,I2C_SMBUS_QUICK,NULL); } s32 i2c_smbus_read_byte(struct i2c_client *client) @@ -996,11 +996,11 @@ s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, I2C_SMBUS_I2C_BLOCK_DATA, &data); } -/* Simulate a SMBus command using the i2c protocol +/* Simulate a SMBus command using the i2c protocol No checking of parameters is done! */ -static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, +static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, unsigned short flags, - char read_write, u8 command, int size, + char read_write, u8 command, int size, union i2c_smbus_data * data) { /* So we need to generate a series of msgs. In the case of writing, we @@ -1010,7 +1010,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; int num = read_write == I2C_SMBUS_READ?2:1; - struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, + struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, { addr, flags | I2C_M_RD, 0, msgbuf1 } }; int i; @@ -1103,14 +1103,14 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, if (i) { /* Compute PEC if first message is a write */ if (!(msg[0].flags & I2C_M_RD)) { - if (num == 1) /* Write only */ + if (num == 1) /* Write only */ i2c_smbus_add_pec(&msg[0]); else /* Write followed by read */ partial_pec = i2c_smbus_msg_pec(0, &msg[0]); } /* Ask for PEC if last message is a read */ if (msg[num-1].flags & I2C_M_RD) - msg[num-1].len++; + msg[num-1].len++; } if (i2c_transfer(adapter, msg, num) < 0) @@ -1130,7 +1130,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, case I2C_SMBUS_BYTE_DATA: data->byte = msgbuf1[0]; break; - case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_WORD_DATA: case I2C_SMBUS_PROC_CALL: data->word = msgbuf1[0] | (msgbuf1[1] << 8); break; @@ -1146,7 +1146,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, - char read_write, u8 command, int size, + char read_write, u8 command, int size, union i2c_smbus_data * data) { s32 res; diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index d66cefc63df7..cf9381eae8da 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -1,5 +1,5 @@ /* - i2c-dev.c - i2c-bus driver, char device interface + i2c-dev.c - i2c-bus driver, char device interface Copyright (C) 1995-97 Simon G. Vogl Copyright (C) 1998-99 Frodo Looijaard @@ -172,7 +172,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, switch ( cmd ) { case I2C_SLAVE: case I2C_SLAVE_FORCE: - if ((arg > 0x3ff) || + if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f)) return -EINVAL; if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg)) @@ -196,8 +196,8 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, return put_user(funcs, (unsigned long __user *)arg); case I2C_RDWR: - if (copy_from_user(&rdwr_arg, - (struct i2c_rdwr_ioctl_data __user *)arg, + if (copy_from_user(&rdwr_arg, + (struct i2c_rdwr_ioctl_data __user *)arg, sizeof(rdwr_arg))) return -EFAULT; @@ -205,9 +205,9 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, * be sent at once */ if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) return -EINVAL; - + rdwr_pa = (struct i2c_msg *) - kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), + kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); if (rdwr_pa == NULL) return -ENOMEM; @@ -277,9 +277,9 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, (struct i2c_smbus_ioctl_data __user *) arg, sizeof(struct i2c_smbus_ioctl_data))) return -EFAULT; - if ((data_arg.size != I2C_SMBUS_BYTE) && + if ((data_arg.size != I2C_SMBUS_BYTE) && (data_arg.size != I2C_SMBUS_QUICK) && - (data_arg.size != I2C_SMBUS_BYTE_DATA) && + (data_arg.size != I2C_SMBUS_BYTE_DATA) && (data_arg.size != I2C_SMBUS_WORD_DATA) && (data_arg.size != I2C_SMBUS_PROC_CALL) && (data_arg.size != I2C_SMBUS_BLOCK_DATA) && @@ -290,11 +290,11 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, data_arg.size); return -EINVAL; } - /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, + /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, so the check is valid if size==I2C_SMBUS_QUICK too. */ - if ((data_arg.read_write != I2C_SMBUS_READ) && + if ((data_arg.read_write != I2C_SMBUS_READ) && (data_arg.read_write != I2C_SMBUS_WRITE)) { - dev_dbg(&client->adapter->dev, + dev_dbg(&client->adapter->dev, "read_write out of range (%x) in ioctl I2C_SMBUS.\n", data_arg.read_write); return -EINVAL; @@ -303,7 +303,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, /* Note that command values are always valid! */ if ((data_arg.size == I2C_SMBUS_QUICK) || - ((data_arg.size == I2C_SMBUS_BYTE) && + ((data_arg.size == I2C_SMBUS_BYTE) && (data_arg.read_write == I2C_SMBUS_WRITE))) /* These are special: we do not use data */ return i2c_smbus_xfer(client->adapter, client->addr, @@ -321,14 +321,14 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || (data_arg.size == I2C_SMBUS_BYTE)) datasize = sizeof(data_arg.data->byte); - else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || + else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || (data_arg.size == I2C_SMBUS_PROC_CALL)) datasize = sizeof(data_arg.data->word); else /* size == smbus block, i2c block, or block proc. call */ datasize = sizeof(data_arg.data->block); - if ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || + if ((data_arg.size == I2C_SMBUS_PROC_CALL) || + (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || (data_arg.read_write == I2C_SMBUS_WRITE)) { if (copy_from_user(&temp, data_arg.data, datasize)) return -EFAULT; @@ -336,8 +336,8 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, res = i2c_smbus_xfer(client->adapter,client->addr,client->flags, data_arg.read_write, data_arg.command,data_arg.size,&temp); - if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || + if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || + (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || (data_arg.read_write == I2C_SMBUS_READ))) { if (copy_to_user(data_arg.data, &temp, datasize)) return -EFAULT; diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h index c8f8df25c7e0..a99e28a86c3b 100644 --- a/include/linux/i2c-algo-bit.h +++ b/include/linux/i2c-algo-bit.h @@ -26,9 +26,9 @@ /* --- Defines for bit-adapters --------------------------------------- */ /* - * This struct contains the hw-dependent functions of bit-style adapters to + * This struct contains the hw-dependent functions of bit-style adapters to * manipulate the line states, and to init any hw-specific features. This is - * only used if you have more than one hw-type of adapter running. + * only used if you have more than one hw-type of adapter running. */ struct i2c_algo_bit_data { void *data; /* private data for lowlevel routines */ diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h index 9908f3fc4839..7d7045cbb344 100644 --- a/include/linux/i2c-algo-pcf.h +++ b/include/linux/i2c-algo-pcf.h @@ -31,7 +31,7 @@ struct i2c_algo_pcf_data { int (*getpcf) (void *data, int ctl); int (*getown) (void *data); int (*getclock) (void *data); - void (*waitforpin) (void); + void (*waitforpin) (void); /* local settings */ int udelay; diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 00da370bbcd6..5b97f1cce7a5 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------- */ -/* */ +/* */ /* i2c-id.h - identifier values for i2c drivers and adapters */ -/* */ +/* */ /* ------------------------------------------------------------------------- */ /* Copyright (C) 1995-1999 Simon G. Vogl @@ -40,10 +40,10 @@ #define I2C_DRIVERID_SAA7120 11 /* video encoder */ #define I2C_DRIVERID_SAA7121 12 /* video encoder */ #define I2C_DRIVERID_SAA7185B 13 /* video encoder */ -#define I2C_DRIVERID_CH7003 14 /* digital pc to tv encoder */ +#define I2C_DRIVERID_CH7003 14 /* digital pc to tv encoder */ #define I2C_DRIVERID_PCF8574A 15 /* i2c expander - 8 bit in/out */ #define I2C_DRIVERID_PCF8582C 16 /* eeprom */ -#define I2C_DRIVERID_AT24Cxx 17 /* eeprom 1/2/4/8/16 K */ +#define I2C_DRIVERID_AT24Cxx 17 /* eeprom 1/2/4/8/16 K */ #define I2C_DRIVERID_TEA6300 18 /* audio mixer */ #define I2C_DRIVERID_BT829 19 /* pc to tv encoder */ #define I2C_DRIVERID_TDA9850 20 /* audio mixer */ @@ -162,7 +162,7 @@ * ---- Adapter types ---------------------------------------------------- */ -/* --- Bit algorithm adapters */ +/* --- Bit algorithm adapters */ #define I2C_HW_B_LP 0x010000 /* Parallel port Philips style */ #define I2C_HW_B_SER 0x010002 /* Serial line interface */ #define I2C_HW_B_BT848 0x010005 /* BT848 video boards */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 08df4169b411..71e50d3e492f 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------- */ -/* */ +/* */ /* i2c.h - definitions for the i2c-bus interface */ -/* */ +/* */ /* ------------------------------------------------------------------------- */ /* Copyright (C) 1995-2000 Simon G. Vogl @@ -27,7 +27,7 @@ #define _LINUX_I2C_H #include -#ifdef __KERNEL__ +#ifdef __KERNEL__ #include #include #include @@ -53,8 +53,8 @@ union i2c_smbus_data; /* * The master routines are the ones normally used to transmit data to devices - * on a bus (or read from them). Apart from two basic transfer functions to - * transmit one message at a time, a more complex version can be used to + * on a bus (or read from them). Apart from two basic transfer functions to + * transmit one message at a time, a more complex version can be used to * transmit an arbitrary number of messages without interruption. */ extern int i2c_master_send(struct i2c_client *,const char* ,int); @@ -67,10 +67,10 @@ extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) /* This is the very generalized SMBus access routine. You probably do not want to use this, though; one of the functions below may be much easier, - and probably just as fast. + and probably just as fast. Note that we use i2c_adapter here, because you do not need a specific smbus adapter to call this function. */ -extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr, +extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data); @@ -112,14 +112,14 @@ struct i2c_driver { /* Notifies the driver that a new bus has appeared. This routine * can be used by the driver to test if the bus meets its conditions - * & seek for the presence of the chip(s) it supports. If found, it + * & seek for the presence of the chip(s) it supports. If found, it * registers the client(s) that are on the bus to the i2c admin. via * i2c_attach_client. */ int (*attach_adapter)(struct i2c_adapter *); int (*detach_adapter)(struct i2c_adapter *); - /* tells the driver that a client is about to be deleted & gives it + /* tells the driver that a client is about to be deleted & gives it * the chance to remove its private data. Also, if the client struct * has been dynamically allocated by the driver in the function above, * it must be freed here. @@ -139,13 +139,13 @@ struct i2c_driver { #define I2C_NAME_SIZE 50 /* - * i2c_client identifies a single device (i.e. chip) that is connected to an + * i2c_client identifies a single device (i.e. chip) that is connected to an * i2c bus. The behaviour is defined by the routines of the driver. This * function is mainly used for lookup & other admin. functions. */ struct i2c_client { unsigned int flags; /* div., see below */ - unsigned short addr; /* chip address - NOTE: 7bit */ + unsigned short addr; /* chip address - NOTE: 7bit */ /* addresses are stored in the */ /* _LOWER_ 7 bits */ struct i2c_adapter *adapter; /* the adapter we sit on */ @@ -182,14 +182,14 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data) */ struct i2c_algorithm { /* If an adapter algorithm can't do I2C-level access, set master_xfer - to NULL. If an adapter algorithm can do SMBus access, set + to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated using common I2C messages */ /* master_xfer should return the number of messages successfully processed, or a negative value on error */ - int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs, + int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs, int num); - int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, + int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data); @@ -317,7 +317,7 @@ extern int i2c_check_addr (struct i2c_adapter *adapter, int addr); * It will only call found_proc if some client is connected at the * specific address (unless a 'force' matched); */ -extern int i2c_probe(struct i2c_adapter *adapter, +extern int i2c_probe(struct i2c_adapter *adapter, struct i2c_client_address_data *address_data, int (*found_proc) (struct i2c_adapter *, int, int)); @@ -353,15 +353,15 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap) */ struct i2c_msg { __u16 addr; /* slave address */ - __u16 flags; + __u16 flags; #define I2C_M_TEN 0x10 /* we have a ten bit chip address */ #define I2C_M_RD 0x01 #define I2C_M_NOSTART 0x4000 #define I2C_M_REV_DIR_ADDR 0x2000 #define I2C_M_IGNORE_NAK 0x1000 #define I2C_M_NO_RD_ACK 0x0800 - __u16 len; /* msg length */ - __u8 *buf; /* pointer to msg data */ + __u16 len; /* msg length */ + __u8 *buf; /* pointer to msg data */ }; /* To determine what functionality is present */ @@ -371,16 +371,16 @@ struct i2c_msg { #define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ #define I2C_FUNC_SMBUS_HWPEC_CALC 0x00000008 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ -#define I2C_FUNC_SMBUS_QUICK 0x00010000 -#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 -#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 -#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 -#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 -#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 -#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 -#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 -#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 -#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 +#define I2C_FUNC_SMBUS_QUICK 0x00010000 +#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 +#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 +#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 +#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 +#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 +#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 #define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ #define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */ @@ -407,10 +407,10 @@ struct i2c_msg { I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ I2C_FUNC_SMBUS_I2C_BLOCK) -/* - * Data for SMBus Messages +/* + * Data for SMBus Messages */ -#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ union i2c_smbus_data { __u8 byte; __u16 word; @@ -422,11 +422,11 @@ union i2c_smbus_data { #define I2C_SMBUS_READ 1 #define I2C_SMBUS_WRITE 0 -/* SMBus transaction types (size parameter in the above functions) +/* SMBus transaction types (size parameter in the above functions) Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ #define I2C_SMBUS_QUICK 0 #define I2C_SMBUS_BYTE 1 -#define I2C_SMBUS_BYTE_DATA 2 +#define I2C_SMBUS_BYTE_DATA 2 #define I2C_SMBUS_WORD_DATA 3 #define I2C_SMBUS_PROC_CALL 4 #define I2C_SMBUS_BLOCK_DATA 5 @@ -435,15 +435,15 @@ union i2c_smbus_data { /* ----- commands for the ioctl like i2c_command call: - * note that additional calls are defined in the algorithm and hw - * dependent layers - these can be listed here, or see the + * note that additional calls are defined in the algorithm and hw + * dependent layers - these can be listed here, or see the * corresponding header files. */ /* -> bit-adapter specific ioctls */ #define I2C_RETRIES 0x0701 /* number of times a device address */ /* should be polled when not */ - /* acknowledging */ -#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */ + /* acknowledging */ +#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */ /* this is for i2c-dev.c */ -- cgit v1.2.3 From 3269711b76ba27b78862c48398b0d313ccaa99c2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 10 Dec 2006 21:21:33 +0100 Subject: i2c: Discard the i2c algo del_bus wrappers They are all only calling i2c_del_adapter, so we may as well do it directly. Signed-off-by: Jean Delvare --- drivers/acorn/char/i2c.c | 2 +- drivers/i2c/algos/i2c-algo-bit.c | 8 -------- drivers/i2c/algos/i2c-algo-pca.c | 7 ------- drivers/i2c/algos/i2c-algo-pcf.c | 8 -------- drivers/i2c/algos/i2c-algo-sgi.c | 8 -------- drivers/i2c/busses/i2c-elektor.c | 2 +- drivers/i2c/busses/i2c-hydra.c | 2 +- drivers/i2c/busses/i2c-i810.c | 6 +++--- drivers/i2c/busses/i2c-ixp2000.c | 2 +- drivers/i2c/busses/i2c-ixp4xx.c | 2 +- drivers/i2c/busses/i2c-parport-light.c | 2 +- drivers/i2c/busses/i2c-parport.c | 2 +- drivers/i2c/busses/i2c-pca-isa.c | 2 +- drivers/i2c/busses/i2c-prosavage.c | 2 +- drivers/i2c/busses/i2c-savage4.c | 2 +- drivers/i2c/busses/i2c-via.c | 2 +- drivers/i2c/busses/i2c-voodoo3.c | 6 +++--- drivers/i2c/busses/scx200_i2c.c | 2 +- drivers/ieee1394/pcilynx.c | 2 +- drivers/media/dvb/pluto2/pluto2.c | 8 ++++---- drivers/media/video/bt8xx/bttv-i2c.c | 6 +----- drivers/media/video/cx88/cx88-core.c | 2 +- drivers/media/video/cx88/cx88-vp3054-i2c.c | 2 +- drivers/media/video/vino.c | 2 +- drivers/media/video/zoran_card.c | 2 +- drivers/video/aty/radeon_i2c.c | 8 ++++---- drivers/video/i810/i810-i2c.c | 6 +++--- drivers/video/intelfb/intelfb_i2c.c | 4 ++-- drivers/video/matrox/i2c-matroxfb.c | 2 +- drivers/video/nvidia/nv_i2c.c | 6 +++--- drivers/video/riva/rivafb-i2c.c | 6 +++--- drivers/video/savage/savagefb-i2c.c | 2 +- include/linux/i2c-algo-bit.h | 1 - include/linux/i2c-algo-pca.h | 1 - include/linux/i2c-algo-pcf.h | 1 - include/linux/i2c-algo-sgi.h | 1 - 36 files changed, 45 insertions(+), 84 deletions(-) (limited to 'include/linux') diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c index bdb9c8b78ed8..9e584a7af434 100644 --- a/drivers/acorn/char/i2c.c +++ b/drivers/acorn/char/i2c.c @@ -360,7 +360,7 @@ static int __init i2c_ioc_init(void) if (ret >= 0){ ret = misc_register(&rtc_dev); if(ret < 0) - i2c_bit_del_bus(&ioc_ops); + i2c_del_adapter(&ioc_ops); } return ret; diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 21c36bfb5e6b..95aa5395a5be 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -540,15 +540,7 @@ int i2c_bit_add_bus(struct i2c_adapter *adap) return i2c_add_adapter(adap); } - - -int i2c_bit_del_bus(struct i2c_adapter *adap) -{ - return i2c_del_adapter(adap); -} - EXPORT_SYMBOL(i2c_bit_add_bus); -EXPORT_SYMBOL(i2c_bit_del_bus); MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 9081c9fbcd29..36fdf971f080 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -381,14 +381,7 @@ int i2c_pca_add_bus(struct i2c_adapter *adap) return rval; } - -int i2c_pca_del_bus(struct i2c_adapter *adap) -{ - return i2c_del_adapter(adap); -} - EXPORT_SYMBOL(i2c_pca_add_bus); -EXPORT_SYMBOL(i2c_pca_del_bus); MODULE_AUTHOR("Ian Campbell "); MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm"); diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index 3b2003398966..ecb2c2d7d540 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -486,15 +486,7 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap) return rval; } - - -int i2c_pcf_del_bus(struct i2c_adapter *adap) -{ - return i2c_del_adapter(adap); -} - EXPORT_SYMBOL(i2c_pcf_add_bus); -EXPORT_SYMBOL(i2c_pcf_del_bus); MODULE_AUTHOR("Hans Berglund "); MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c index 490d99997fd0..ac2d5053078a 100644 --- a/drivers/i2c/algos/i2c-algo-sgi.c +++ b/drivers/i2c/algos/i2c-algo-sgi.c @@ -171,15 +171,7 @@ int i2c_sgi_add_bus(struct i2c_adapter *adap) return i2c_add_adapter(adap); } - - -int i2c_sgi_del_bus(struct i2c_adapter *adap) -{ - return i2c_del_adapter(adap); -} - EXPORT_SYMBOL(i2c_sgi_add_bus); -EXPORT_SYMBOL(i2c_sgi_del_bus); MODULE_AUTHOR("Ladislav Michl "); MODULE_DESCRIPTION("I2C-Bus SGI algorithm"); diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index a591fe685f06..834967464814 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -293,7 +293,7 @@ static int __init i2c_pcfisa_init(void) static void i2c_pcfisa_exit(void) { - i2c_pcf_del_bus(&pcf_isa_ops); + i2c_del_adapter(&pcf_isa_ops); if (irq > 0) { disable_irq(irq); diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index 457d48a0ab9d..9832f773651d 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -146,7 +146,7 @@ static int __devinit hydra_probe(struct pci_dev *dev, static void __devexit hydra_remove(struct pci_dev *dev) { pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */ - i2c_bit_del_bus(&hydra_adap); + i2c_del_adapter(&hydra_adap); iounmap(hydra_bit_data.data); release_mem_region(pci_resource_start(dev, 0)+ offsetof(struct Hydra, CachePD), 4); diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index b66fb6bb1870..10c98bc88aa6 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -219,14 +219,14 @@ static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id return retval; retval = i2c_bit_add_bus(&i810_ddc_adapter); if (retval) - i2c_bit_del_bus(&i810_i2c_adapter); + i2c_del_adapter(&i810_i2c_adapter); return retval; } static void __devexit i810_remove(struct pci_dev *dev) { - i2c_bit_del_bus(&i810_ddc_adapter); - i2c_bit_del_bus(&i810_i2c_adapter); + i2c_del_adapter(&i810_ddc_adapter); + i2c_del_adapter(&i810_i2c_adapter); iounmap(ioaddr); } diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index dd3f4cd3aa68..efa3ecc5522a 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -90,7 +90,7 @@ static int ixp2000_i2c_remove(struct platform_device *plat_dev) platform_set_drvdata(plat_dev, NULL); - i2c_bit_del_bus(&drv_data->adapter); + i2c_del_adapter(&drv_data->adapter); kfree(drv_data); diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 68fe863f9d54..08e89b83984a 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -91,7 +91,7 @@ static int ixp4xx_i2c_remove(struct platform_device *plat_dev) platform_set_drvdata(plat_dev, NULL); - i2c_bit_del_bus(&drv_data->adapter); + i2c_del_adapter(&drv_data->adapter); kfree(drv_data); diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index 5eb2bd294fd9..4bc42810b9aa 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -163,7 +163,7 @@ static void __exit i2c_parport_exit(void) if (adapter_parm[type].init.val) line_set(0, &adapter_parm[type].init); - i2c_bit_del_bus(&parport_adapter); + i2c_del_adapter(&parport_adapter); release_region(base, 3); } diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 48a829431c7b..66696a40c7b5 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -218,7 +218,7 @@ static void i2c_parport_detach (struct parport *port) if (adapter_parm[type].init.val) line_set(port, 0, &adapter_parm[type].init); - i2c_bit_del_bus(&adapter->adapter); + i2c_del_adapter(&adapter->adapter); parport_unregister_device(adapter->pdev); if (prev) prev->next = adapter->next; diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index 407840b6a260..cc6536a19eca 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -156,7 +156,7 @@ static int __init pca_isa_init(void) static void pca_isa_exit(void) { - i2c_pca_del_bus(&pca_isa_ops); + i2c_del_adapter(&pca_isa_ops); if (irq > 0) { disable_irq(irq); diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 7745e21874a8..07c1f1e27df1 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c @@ -212,7 +212,7 @@ static void prosavage_remove(struct pci_dev *dev) if (chip->i2c_bus[i].adap_ok == 0) continue; - ret = i2c_bit_del_bus(&chip->i2c_bus[i].adap); + ret = i2c_del_adapter(&chip->i2c_bus[i].adap); if (ret) { dev_err(&dev->dev, "%s not removed\n", chip->i2c_bus[i].adap.name); diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 209f47ea1750..844b4ff90893 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c @@ -173,7 +173,7 @@ static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_ static void __devexit savage4_remove(struct pci_dev *dev) { - i2c_bit_del_bus(&savage4_i2c_adapter); + i2c_del_adapter(&savage4_i2c_adapter); iounmap(ioaddr); } diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 910e200ad500..15d7e00e47e6 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -151,7 +151,7 @@ static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_i static void __devexit vt586b_remove(struct pci_dev *dev) { - i2c_bit_del_bus(&vt586b_adapter); + i2c_del_adapter(&vt586b_adapter); release_region(I2C_DIR, IOSPACE); pm_io_base = 0; } diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 6c8d25183382..b0377b81744b 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -211,14 +211,14 @@ static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_ return retval; retval = i2c_bit_add_bus(&voodoo3_ddc_adapter); if (retval) - i2c_bit_del_bus(&voodoo3_i2c_adapter); + i2c_del_adapter(&voodoo3_i2c_adapter); return retval; } static void __devexit voodoo3_remove(struct pci_dev *dev) { - i2c_bit_del_bus(&voodoo3_i2c_adapter); - i2c_bit_del_bus(&voodoo3_ddc_adapter); + i2c_del_adapter(&voodoo3_i2c_adapter); + i2c_del_adapter(&voodoo3_ddc_adapter); iounmap(ioaddr); } diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c index 8ddbae4fafe6..6cd96e43aa72 100644 --- a/drivers/i2c/busses/scx200_i2c.c +++ b/drivers/i2c/busses/scx200_i2c.c @@ -116,7 +116,7 @@ static int scx200_i2c_init(void) static void scx200_i2c_cleanup(void) { - i2c_bit_del_bus(&scx200_i2c_ops); + i2c_del_adapter(&scx200_i2c_ops); } module_init(scx200_i2c_init); diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index 13a617917bf2..fbb7f14ec509 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -1485,7 +1485,7 @@ static int __devinit add_card(struct pci_dev *dev, } - i2c_bit_del_bus(i2c_ad); + i2c_del_adapter(i2c_ad); kfree(i2c_ad); } } diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index 8e4ce101eb22..ffda71dfdd65 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -650,7 +650,7 @@ static int __devinit pluto2_probe(struct pci_dev *pdev, /* dvb */ ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE, &pdev->dev); if (ret < 0) - goto err_i2c_bit_del_bus; + goto err_i2c_del_adapter; dvb_adapter = &pluto->dvb_adapter; @@ -712,8 +712,8 @@ err_dvb_dmx_release: dvb_dmx_release(dvbdemux); err_dvb_unregister_adapter: dvb_unregister_adapter(dvb_adapter); -err_i2c_bit_del_bus: - i2c_bit_del_bus(&pluto->i2c_adap); +err_i2c_del_adapter: + i2c_del_adapter(&pluto->i2c_adap); err_pluto_hw_exit: pluto_hw_exit(pluto); err_free_irq: @@ -748,7 +748,7 @@ static void __devexit pluto2_remove(struct pci_dev *pdev) dvb_dmxdev_release(&pluto->dmxdev); dvb_dmx_release(dvbdemux); dvb_unregister_adapter(dvb_adapter); - i2c_bit_del_bus(&pluto->i2c_adap); + i2c_del_adapter(&pluto->i2c_adap); pluto_hw_exit(pluto); free_irq(pdev->irq, pluto); pci_iounmap(pdev, pluto->io_mem); diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index 70de6c96e201..62b873076e09 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -479,11 +479,7 @@ int __devexit fini_bttv_i2c(struct bttv *btv) if (0 != btv->i2c_rc) return 0; - if (btv->use_i2c_hw) { - return i2c_del_adapter(&btv->c.i2c_adap); - } else { - return i2c_bit_del_bus(&btv->c.i2c_adap); - } + return i2c_del_adapter(&btv->c.i2c_adap); } /* diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 4b655f2ef278..453af5e943ff 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1153,7 +1153,7 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) mutex_lock(&devlist); cx88_ir_fini(core); if (0 == core->i2c_rc) - i2c_bit_del_bus(&core->i2c_adap); + i2c_del_adapter(&core->i2c_adap); list_del(&core->devlist); iounmap(core->lmmio); cx88_devcount--; diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index 2b4f1970c7df..6068c9bf82cd 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -168,7 +168,7 @@ void vp3054_i2c_remove(struct cx8802_dev *dev) dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) return; - i2c_bit_del_bus(&vp3054_i2c->adap); + i2c_del_adapter(&vp3054_i2c->adap); kfree(vp3054_i2c); } diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index 6b6dff4d236a..a373c142e742 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -782,7 +782,7 @@ static int vino_i2c_add_bus(void) static int vino_i2c_del_bus(void) { - return i2c_sgi_del_bus(&vino_i2c_adapter); + return i2c_del_adapter(&vino_i2c_adapter); } static int i2c_camera_command(unsigned int cmd, void *arg) diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 653822ce391c..4d1eb2fba34a 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -849,7 +849,7 @@ zoran_register_i2c (struct zoran *zr) static void zoran_unregister_i2c (struct zoran *zr) { - i2c_bit_del_bus((&zr->i2c_adapter)); + i2c_del_adapter(&zr->i2c_adapter); } /* Check a zoran_params struct for correctness, insert default params */ diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c index 869725a13c21..e7c5b219ad1b 100644 --- a/drivers/video/aty/radeon_i2c.c +++ b/drivers/video/aty/radeon_i2c.c @@ -120,19 +120,19 @@ void radeon_create_i2c_busses(struct radeonfb_info *rinfo) void radeon_delete_i2c_busses(struct radeonfb_info *rinfo) { if (rinfo->i2c[0].rinfo) - i2c_bit_del_bus(&rinfo->i2c[0].adapter); + i2c_del_adapter(&rinfo->i2c[0].adapter); rinfo->i2c[0].rinfo = NULL; if (rinfo->i2c[1].rinfo) - i2c_bit_del_bus(&rinfo->i2c[1].adapter); + i2c_del_adapter(&rinfo->i2c[1].adapter); rinfo->i2c[1].rinfo = NULL; if (rinfo->i2c[2].rinfo) - i2c_bit_del_bus(&rinfo->i2c[2].adapter); + i2c_del_adapter(&rinfo->i2c[2].adapter); rinfo->i2c[2].rinfo = NULL; if (rinfo->i2c[3].rinfo) - i2c_bit_del_bus(&rinfo->i2c[3].adapter); + i2c_del_adapter(&rinfo->i2c[3].adapter); rinfo->i2c[3].rinfo = NULL; } diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c index b952e4504abe..961f4d404467 100644 --- a/drivers/video/i810/i810-i2c.c +++ b/drivers/video/i810/i810-i2c.c @@ -137,15 +137,15 @@ void i810_create_i2c_busses(struct i810fb_par *par) void i810_delete_i2c_busses(struct i810fb_par *par) { if (par->chan[0].par) - i2c_bit_del_bus(&par->chan[0].adapter); + i2c_del_adapter(&par->chan[0].adapter); par->chan[0].par = NULL; if (par->chan[1].par) - i2c_bit_del_bus(&par->chan[1].adapter); + i2c_del_adapter(&par->chan[1].adapter); par->chan[1].par = NULL; if (par->chan[2].par) - i2c_bit_del_bus(&par->chan[2].adapter); + i2c_del_adapter(&par->chan[2].adapter); par->chan[2].par = NULL; } diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index 5686e2164e39..33bc41f50540 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -188,11 +188,11 @@ void intelfb_delete_i2c_busses(struct intelfb_info *dinfo) for (i = 0; i < MAX_OUTPUTS; i++) { if (dinfo->output[i].i2c_bus.dinfo) { - i2c_bit_del_bus(&dinfo->output[i].i2c_bus.adapter); + i2c_del_adapter(&dinfo->output[i].i2c_bus.adapter); dinfo->output[i].i2c_bus.dinfo = NULL; } if (dinfo->output[i].ddc_bus.dinfo) { - i2c_bit_del_bus(&dinfo->output[i].ddc_bus.adapter); + i2c_del_adapter(&dinfo->output[i].ddc_bus.adapter); dinfo->output[i].ddc_bus.dinfo = NULL; } } diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c index 795c1a99a680..797b42305b0f 100644 --- a/drivers/video/matrox/i2c-matroxfb.c +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -124,7 +124,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, static void i2c_bit_bus_del(struct i2c_bit_adapter* b) { if (b->initialized) { - i2c_bit_del_bus(&b->adapter); + i2c_del_adapter(&b->adapter); b->initialized = 0; } } diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c index 442e85328341..8454adf2d178 100644 --- a/drivers/video/nvidia/nv_i2c.c +++ b/drivers/video/nvidia/nv_i2c.c @@ -147,15 +147,15 @@ void nvidia_create_i2c_busses(struct nvidia_par *par) void nvidia_delete_i2c_busses(struct nvidia_par *par) { if (par->chan[0].par) - i2c_bit_del_bus(&par->chan[0].adapter); + i2c_del_adapter(&par->chan[0].adapter); par->chan[0].par = NULL; if (par->chan[1].par) - i2c_bit_del_bus(&par->chan[1].adapter); + i2c_del_adapter(&par->chan[1].adapter); par->chan[1].par = NULL; if (par->chan[2].par) - i2c_bit_del_bus(&par->chan[2].adapter); + i2c_del_adapter(&par->chan[2].adapter); par->chan[2].par = NULL; } diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c index c15b259af644..01b85e3b0ae1 100644 --- a/drivers/video/riva/rivafb-i2c.c +++ b/drivers/video/riva/rivafb-i2c.c @@ -144,15 +144,15 @@ void riva_create_i2c_busses(struct riva_par *par) void riva_delete_i2c_busses(struct riva_par *par) { if (par->chan[0].par) - i2c_bit_del_bus(&par->chan[0].adapter); + i2c_del_adapter(&par->chan[0].adapter); par->chan[0].par = NULL; if (par->chan[1].par) - i2c_bit_del_bus(&par->chan[1].adapter); + i2c_del_adapter(&par->chan[1].adapter); par->chan[1].par = NULL; if (par->chan[2].par) - i2c_bit_del_bus(&par->chan[2].adapter); + i2c_del_adapter(&par->chan[2].adapter); par->chan[2].par = NULL; } diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index cef5bf591cdf..1411f3b6a009 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -208,7 +208,7 @@ void savagefb_delete_i2c_busses(struct fb_info *info) struct savagefb_par *par = info->par; if (par->chan.par) - i2c_bit_del_bus(&par->chan.adapter); + i2c_del_adapter(&par->chan.adapter); par->chan.par = NULL; } diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h index a99e28a86c3b..937da70cb4c4 100644 --- a/include/linux/i2c-algo-bit.h +++ b/include/linux/i2c-algo-bit.h @@ -44,6 +44,5 @@ struct i2c_algo_bit_data { }; int i2c_bit_add_bus(struct i2c_adapter *); -int i2c_bit_del_bus(struct i2c_adapter *); #endif /* _LINUX_I2C_ALGO_BIT_H */ diff --git a/include/linux/i2c-algo-pca.h b/include/linux/i2c-algo-pca.h index 226693e0d88b..fce47c051bb1 100644 --- a/include/linux/i2c-algo-pca.h +++ b/include/linux/i2c-algo-pca.h @@ -10,6 +10,5 @@ struct i2c_algo_pca_data { }; int i2c_pca_add_bus(struct i2c_adapter *); -int i2c_pca_del_bus(struct i2c_adapter *); #endif /* _LINUX_I2C_ALGO_PCA_H */ diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h index 7d7045cbb344..994eb86f882c 100644 --- a/include/linux/i2c-algo-pcf.h +++ b/include/linux/i2c-algo-pcf.h @@ -39,6 +39,5 @@ struct i2c_algo_pcf_data { }; int i2c_pcf_add_bus(struct i2c_adapter *); -int i2c_pcf_del_bus(struct i2c_adapter *); #endif /* _LINUX_I2C_ALGO_PCF_H */ diff --git a/include/linux/i2c-algo-sgi.h b/include/linux/i2c-algo-sgi.h index 4a0113d64064..3b7715024e69 100644 --- a/include/linux/i2c-algo-sgi.h +++ b/include/linux/i2c-algo-sgi.h @@ -22,6 +22,5 @@ struct i2c_algo_sgi_data { }; int i2c_sgi_add_bus(struct i2c_adapter *); -int i2c_sgi_del_bus(struct i2c_adapter *); #endif /* I2C_ALGO_SGI_H */ -- cgit v1.2.3 From d10f73480b991da2aa1c000ed38eda3e4a987292 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sun, 10 Dec 2006 23:26:16 -0600 Subject: [PPC] Fix compile failure do to introduction of PHY_POLL PHY_POLL is defined in include it in so board code will have it defined. Signed-off-by: Kumar Gala --- include/linux/fsl_devices.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 3da29e2d524a..abb64c437f6f 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -19,6 +19,7 @@ #define _FSL_DEVICE_H_ #include +#include /* * Some conventions on how we handle peripherals on Freescale chips -- cgit v1.2.3 From 8993780a6e44fb4e7ed34e33458506a775356c6e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 11 Dec 2006 09:28:46 -0800 Subject: Make SLES9 "get_kernel_version" work on the kernel binary again As reported by Andy Whitcroft, at least the SLES9 initrd build process depends on getting the kernel version from the kernel binary. It does that by simply trawling the binary and looking for the signature of the "linux_banner" string (the string "Linux version " to be exact. Which is really broken in itself, but whatever..) That got broken when the string was changed to allow /proc/version to change the UTS release information dynamically, and "get_kernel_version" thus returned "%s" (see commit a2ee8649ba6d71416712e798276bf7c40b64e6e5: "[PATCH] Fix linux banner utsname information"). This just restores "linux_banner" as a static string, which should fix the version finding. And /proc/version simply uses a different string. To avoid wasting even that miniscule amount of memory, the early boot string should really be marked __initdata, but that just causes the same bug in SLES9 to re-appear, since it will then find other occurrences of "Linux version " first. Cc: Andy Whitcroft Acked-by: Herbert Poetzl Cc: Andi Kleen Cc: Andrew Morton Cc: Steve Fox Acked-by: Olaf Hering Signed-off-by: Linus Torvalds --- fs/proc/proc_misc.c | 12 ++++++++++-- include/linux/kernel.h | 2 -- init/main.c | 8 +++++++- init/version.c | 5 ----- 4 files changed, 17 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index dc3e580d1dca..92ea7743fe8f 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -253,8 +254,15 @@ static int version_read_proc(char *page, char **start, off_t off, { int len; - len = sprintf(page, linux_banner, - utsname()->release, utsname()->version); + /* FIXED STRING! Don't touch! */ + len = snprintf(page, PAGE_SIZE, + "%s version %s" + " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")" + " (" LINUX_COMPILER ")" + " %s\n", + utsname()->sysname, + utsname()->release, + utsname()->version); return proc_calc_metrics(page, start, off, count, eof, len); } diff --git a/include/linux/kernel.h b/include/linux/kernel.h index e8bfac34d2ba..b0c4a05a4b0c 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -17,8 +17,6 @@ #include #include -extern const char linux_banner[]; - #define INT_MAX ((int)(~0U>>1)) #define INT_MIN (-INT_MAX - 1) #define UINT_MAX (~0U) diff --git a/init/main.c b/init/main.c index 036f97c0c34c..fcd9ddc3ccf5 100644 --- a/init/main.c +++ b/init/main.c @@ -483,6 +483,12 @@ void __init __attribute__((weak)) smp_setup_processor_id(void) { } +static const char linux_banner[] = + "Linux version " UTS_RELEASE + " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")" + " (" LINUX_COMPILER ")" + " " UTS_VERSION "\n"; + asmlinkage void __init start_kernel(void) { char * command_line; @@ -509,7 +515,7 @@ asmlinkage void __init start_kernel(void) boot_cpu_init(); page_address_init(); printk(KERN_NOTICE); - printk(linux_banner, UTS_RELEASE, UTS_VERSION); + printk(linux_banner); setup_arch(&command_line); unwind_setup(); setup_per_cpu_areas(); diff --git a/init/version.c b/init/version.c index 2a5dfcd1c2e6..9d96d36501ca 100644 --- a/init/version.c +++ b/init/version.c @@ -33,8 +33,3 @@ struct uts_namespace init_uts_ns = { }, }; EXPORT_SYMBOL_GPL(init_uts_ns); - -const char linux_banner[] = - "Linux version %s (" LINUX_COMPILE_BY "@" - LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") %s\n"; - -- cgit v1.2.3 From 8d610dd52dd1da696e199e4b4545f33a2a5de5c6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 11 Dec 2006 12:12:04 -0800 Subject: Make sure we populate the initroot filesystem late enough We should not initialize rootfs before all the core initializers have run. So do it as a separate stage just before starting the regular driver initializers. Signed-off-by: Linus Torvalds --- include/asm-generic/vmlinux.lds.h | 1 + include/linux/init.h | 1 + init/initramfs.c | 6 ++++-- init/main.c | 7 ------- 4 files changed, 6 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 6e9fcebbf89f..7437ccaada77 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -242,6 +242,7 @@ *(.initcall4s.init) \ *(.initcall5.init) \ *(.initcall5s.init) \ + *(.initcallrootfs.init) \ *(.initcall6.init) \ *(.initcall6s.init) \ *(.initcall7.init) \ diff --git a/include/linux/init.h b/include/linux/init.h index 5eb5d24b7680..5a593a1dec1e 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -111,6 +111,7 @@ extern void setup_arch(char **); #define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s) #define fs_initcall(fn) __define_initcall("5",fn,5) #define fs_initcall_sync(fn) __define_initcall("5s",fn,5s) +#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs) #define device_initcall(fn) __define_initcall("6",fn,6) #define device_initcall_sync(fn) __define_initcall("6s",fn,6s) #define late_initcall(fn) __define_initcall("7",fn,7) diff --git a/init/initramfs.c b/init/initramfs.c index 85f04037ade1..4fa0f7977de1 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -526,7 +526,7 @@ static void __init free_initrd(void) #endif -void __init populate_rootfs(void) +static int __init populate_rootfs(void) { char *err = unpack_to_rootfs(__initramfs_start, __initramfs_end - __initramfs_start, 0); @@ -544,7 +544,7 @@ void __init populate_rootfs(void) unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start, 0); free_initrd(); - return; + return 0; } printk("it isn't (%s); looks like an initrd\n", err); fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700); @@ -565,4 +565,6 @@ void __init populate_rootfs(void) #endif } #endif + return 0; } +rootfs_initcall(populate_rootfs); diff --git a/init/main.c b/init/main.c index fcd9ddc3ccf5..e3f0bb20b4dd 100644 --- a/init/main.c +++ b/init/main.c @@ -94,7 +94,6 @@ extern void pidmap_init(void); extern void prio_tree_init(void); extern void radix_tree_init(void); extern void free_initmem(void); -extern void populate_rootfs(void); extern void driver_init(void); extern void prepare_namespace(void); #ifdef CONFIG_ACPI @@ -745,12 +744,6 @@ static int init(void * unused) cpuset_init_smp(); - /* - * Do this before initcalls, because some drivers want to access - * firmware files. - */ - populate_rootfs(); - do_basic_setup(); /* -- cgit v1.2.3 From 1a21e49a8d60f588c1276f765198b14d5688a778 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sun, 10 Dec 2006 00:02:12 -0200 Subject: [DCCP] ccid3: Finer-grained resolution of sending rates This patch * resolves a bug where packets smaller than 32/64 bytes resulted in sending rates of 0 * supports all sending rates from 1/64 bytes/second up to 4Gbyte/second * simplifies the present overflow problems in calculations Current sending rate X and the cached value X_recv of the receiver-estimated sending rate are both scaled by 64 (2^6) in order to * cope with low sending rates (minimally 1 byte/second) * allow upgrading to use a packets-per-second implementation of CCID 3 * avoid calculation errors due to integer arithmetic cut-off The patch implements a revised strategy from http://www.mail-archive.com/dccp@vger.kernel.org/msg01040.html The only difference with regard to that strategy is that t_ipi is already used in the calculation of the nofeedback timeout, which saves one division. Signed-off-by: Gerrit Renker Acked-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/tfrc.h | 8 ++++-- net/dccp/ccids/ccid3.c | 76 ++++++++++++++++++++++++++++++-------------------- net/dccp/ccids/ccid3.h | 33 +++++++++++++++++----- 3 files changed, 78 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tfrc.h b/include/linux/tfrc.h index 31a9b25276fe..8a8462b4a4dd 100644 --- a/include/linux/tfrc.h +++ b/include/linux/tfrc.h @@ -37,10 +37,14 @@ struct tfrc_rx_info { * @tfrctx_p: current loss event rate (5.4) * @tfrctx_rto: estimate of RTO, equals 4*RTT (4.3) * @tfrctx_ipi: inter-packet interval (4.6) + * + * Note: X and X_recv are both maintained in units of 64 * bytes/second. This + * enables a finer resolution of sending rates and avoids problems with + * integer arithmetic; u32 is not sufficient as scaling consumes 6 bits. */ struct tfrc_tx_info { - __u32 tfrctx_x; - __u32 tfrctx_x_recv; + __u64 tfrctx_x; + __u64 tfrctx_x_recv; __u32 tfrctx_x_calc; __u32 tfrctx_rtt; __u32 tfrctx_p; diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index c54663f21fdd..aa355d4cfc8a 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -108,8 +108,9 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx) { timeval_sub_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi); - /* Calculate new t_ipi (inter packet interval) by t_ipi = s / X_inst */ - hctx->ccid3hctx_t_ipi = usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_x); + /* Calculate new t_ipi = s / X_inst (X_inst is in 64 * bytes/second) */ + hctx->ccid3hctx_t_ipi = scaled_div(hctx->ccid3hctx_s, + hctx->ccid3hctx_x >> 6); /* Update nominal send time with regard to the new t_ipi */ timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi); @@ -128,26 +129,33 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx) * X = max(min(2 * X, 2 * X_recv), s / R); * tld = now; * + * Note: X and X_recv are both stored in units of 64 * bytes/second, to support + * fine-grained resolution of sending rates. This requires scaling by 2^6 + * throughout the code. Only X_calc is unscaled (in bytes/second). + * * If X has changed, we also update the scheduled send time t_now, * the inter-packet interval t_ipi, and the delta value. - */ + */ static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) { struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); - const __u32 old_x = hctx->ccid3hctx_x; + const __u64 old_x = hctx->ccid3hctx_x; if (hctx->ccid3hctx_p > 0) { - hctx->ccid3hctx_x = max_t(u32, min(hctx->ccid3hctx_x_calc, - hctx->ccid3hctx_x_recv * 2), - hctx->ccid3hctx_s / TFRC_T_MBI); + + hctx->ccid3hctx_x = min_t(u64, hctx->ccid3hctx_x_calc << 6, + hctx->ccid3hctx_x_recv * 2 ); + hctx->ccid3hctx_x = max_t(u64, hctx->ccid3hctx_x, + (hctx->ccid3hctx_s << 6)/TFRC_T_MBI); } else if (timeval_delta(now, &hctx->ccid3hctx_t_ld) >= hctx->ccid3hctx_rtt) { - hctx->ccid3hctx_x = max(min(hctx->ccid3hctx_x_recv, - hctx->ccid3hctx_x ) * 2, - usecs_div(hctx->ccid3hctx_s, - hctx->ccid3hctx_rtt) ); + + hctx->ccid3hctx_x = max(2 * min(hctx->ccid3hctx_x, + hctx->ccid3hctx_x_recv), + scaled_div(hctx->ccid3hctx_s << 6, + hctx->ccid3hctx_rtt )); hctx->ccid3hctx_t_ld = *now; } @@ -194,13 +202,13 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) case TFRC_SSTATE_NO_FBACK: /* RFC 3448, 4.4: Halve send rate directly */ hctx->ccid3hctx_x = max_t(u32, hctx->ccid3hctx_x / 2, - hctx->ccid3hctx_s / TFRC_T_MBI); + (hctx->ccid3hctx_s << 6)/TFRC_T_MBI); - ccid3_pr_debug("%s, sk=%p, state=%s, updated tx rate to %d " + ccid3_pr_debug("%s, sk=%p, state=%s, updated tx rate to %u " "bytes/s\n", dccp_role(sk), sk, ccid3_tx_state_name(hctx->ccid3hctx_state), - hctx->ccid3hctx_x); + (unsigned)(hctx->ccid3hctx_x >> 6)); /* The value of R is still undefined and so we can not recompute * the timout value. Keep initial value as per [RFC 4342, 5]. */ t_nfb = TFRC_INITIAL_TIMEOUT; @@ -209,11 +217,11 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) case TFRC_SSTATE_FBACK: /* * Check if IDLE since last timeout and recv rate is less than - * 4 packets per RTT + * 4 packets (in units of 64*bytes/sec) per RTT */ if (!hctx->ccid3hctx_idle || - (hctx->ccid3hctx_x_recv >= - 4 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt))) { + (hctx->ccid3hctx_x_recv >= 4 * + scaled_div(hctx->ccid3hctx_s << 6, hctx->ccid3hctx_rtt))) { struct timeval now; ccid3_pr_debug("%s, sk=%p, state=%s, not idle\n", @@ -227,17 +235,23 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) * X_recv = max(X_recv / 2, s / (2 * t_mbi)); * Else * X_recv = X_calc / 4; + * + * Note that X_recv is scaled by 2^6 while X_calc is not */ BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc); if (hctx->ccid3hctx_p == 0 || - hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv) { - hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2, - hctx->ccid3hctx_s / (2 * TFRC_T_MBI)); + hctx->ccid3hctx_x_calc > (hctx->ccid3hctx_x_recv >> 5)) { + + hctx->ccid3hctx_x_recv = + max_t(u64, hctx->ccid3hctx_x_recv / 2, + (hctx->ccid3hctx_s << 6) / + (2*TFRC_T_MBI)); + if (hctx->ccid3hctx_p == 0) dccp_timestamp(sk, &now); } else - hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc / 4; + hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc << 4; /* Now recalculate X [RFC 3448, 4.3, step (4)] */ ccid3_hc_tx_update_x(sk, &now); @@ -315,9 +329,9 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) hctx->ccid3hctx_t_last_win_count = now; ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK); - /* Set initial sending rate to 1 packet per second */ + /* Set initial sending rate X/s to 1pps (X is scaled by 2^6) */ ccid3_hc_tx_update_s(hctx, skb->len); - hctx->ccid3hctx_x = hctx->ccid3hctx_s; + hctx->ccid3hctx_x = hctx->ccid3hctx_s << 6; /* First timeout, according to [RFC 3448, 4.2], is 1 second */ hctx->ccid3hctx_t_ipi = USEC_PER_SEC; @@ -438,8 +452,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) return; } - /* Update receive rate */ - hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate; + /* Update receive rate in units of 64 * bytes/second */ + hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate << 6; /* Update loss event rate */ pinv = opt_recv->ccid3or_loss_event_rate; @@ -475,12 +489,14 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) * q is a constant, RFC 3448 recomments 0.9 */ if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) { - /* Use Larger Initial Windows [RFC 4342, sec. 5] - * We deviate in that we use `s' instead of `MSS'. */ + /* + * Larger Initial Windows [RFC 4342, sec. 5] + * We deviate in that we use `s' instead of `MSS'. + */ u16 w_init = min( 4 * hctx->ccid3hctx_s, max(2 * hctx->ccid3hctx_s, 4380)); hctx->ccid3hctx_rtt = r_sample; - hctx->ccid3hctx_x = usecs_div(w_init, r_sample); + hctx->ccid3hctx_x = scaled_div(w_init<< 6, r_sample); hctx->ccid3hctx_t_ld = now; ccid3_update_send_time(hctx); @@ -488,7 +504,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ccid3_pr_debug("%s(%p), s=%u, w_init=%u, " "R_sample=%ldus, X=%u\n", dccp_role(sk), sk, hctx->ccid3hctx_s, w_init, r_sample, - hctx->ccid3hctx_x); + (unsigned)(hctx->ccid3hctx_x >> 6)); ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK); } else { @@ -508,7 +524,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) sk, hctx->ccid3hctx_rtt, r_sample, hctx->ccid3hctx_s, hctx->ccid3hctx_p, hctx->ccid3hctx_x_calc, - hctx->ccid3hctx_x); + (unsigned)(hctx->ccid3hctx_x >> 6)); } /* unschedule no feedback timer */ diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 07596d704ef9..cd4fc542f73e 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -75,14 +75,14 @@ enum ccid3_hc_tx_states { /** struct ccid3_hc_tx_sock - CCID3 sender half-connection socket * - * @ccid3hctx_x - Current sending rate - * @ccid3hctx_x_recv - Receive rate - * @ccid3hctx_x_calc - Calculated send rate (RFC 3448, 3.1) + * @ccid3hctx_x - Current sending rate in 64 * bytes per second + * @ccid3hctx_x_recv - Receive rate in 64 * bytes per second + * @ccid3hctx_x_calc - Calculated rate in bytes per second * @ccid3hctx_rtt - Estimate of current round trip time in usecs * @ccid3hctx_p - Current loss event rate (0-1) scaled by 1000000 - * @ccid3hctx_s - Packet size - * @ccid3hctx_t_rto - Retransmission Timeout (RFC 3448, 3.1) - * @ccid3hctx_t_ipi - Interpacket (send) interval (RFC 3448, 4.6) + * @ccid3hctx_s - Packet size in bytes + * @ccid3hctx_t_rto - Nofeedback Timer setting in usecs + * @ccid3hctx_t_ipi - Interpacket (send) interval (RFC 3448, 4.6) in usecs * @ccid3hctx_state - Sender state, one of %ccid3_hc_tx_states * @ccid3hctx_last_win_count - Last window counter sent * @ccid3hctx_t_last_win_count - Timestamp of earliest packet @@ -91,7 +91,7 @@ enum ccid3_hc_tx_states { * @ccid3hctx_idle - Flag indicating that sender is idling * @ccid3hctx_t_ld - Time last doubled during slow start * @ccid3hctx_t_nom - Nominal send time of next packet - * @ccid3hctx_delta - Send timer delta + * @ccid3hctx_delta - Send timer delta (RFC 3448, 4.6) in usecs * @ccid3hctx_hist - Packet history * @ccid3hctx_options_received - Parsed set of retrieved options */ @@ -171,4 +171,23 @@ static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk) return ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid); } +static inline u64 scaled_div(u64 a, u32 b) +{ + BUG_ON(b==0); + a *= 1000000; + do_div(a, b); + return a; +} + +static inline u32 scaled_div32(u64 a, u32 b) +{ + u64 result = scaled_div(a, b); + + if (result > UINT_MAX) { + DCCP_CRIT("Overflow: a(%llu)/b(%u) > ~0U", + (unsigned long long)a, b); + return UINT_MAX; + } + return result; +} #endif /* _DCCP_CCID3_H_ */ -- cgit v1.2.3 From 8109b02b5397ed52a32c116163a62a34f4768b26 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 10 Dec 2006 16:01:18 -0200 Subject: [DCCP]: Whitespace cleanups That accumulated over the last months hackaton, shame on me for not using git-apply whitespace helping hand, will do that from now on. Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/dccp.h | 26 ++++++------ net/dccp/ackvec.c | 4 +- net/dccp/ccids/ccid2.c | 12 +++--- net/dccp/ccids/ccid3.c | 111 +++++++++++++++++++++++++++---------------------- net/dccp/ccids/ccid3.h | 22 +++++----- net/dccp/feat.c | 6 +-- net/dccp/input.c | 26 ++++++------ net/dccp/ipv4.c | 26 ++++++------ net/dccp/ipv6.c | 24 +++++------ net/dccp/minisocks.c | 2 +- net/dccp/output.c | 7 ++-- net/dccp/proto.c | 6 +-- net/dccp/timer.c | 14 +++---- 13 files changed, 149 insertions(+), 137 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index ed6cc8962d87..1cb054bd93f2 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -176,20 +176,20 @@ enum { }; /* DCCP features (RFC 4340 section 6.4) */ - enum { - DCCPF_RESERVED = 0, - DCCPF_CCID = 1, +enum { + DCCPF_RESERVED = 0, + DCCPF_CCID = 1, DCCPF_SHORT_SEQNOS = 2, /* XXX: not yet implemented */ - DCCPF_SEQUENCE_WINDOW = 3, + DCCPF_SEQUENCE_WINDOW = 3, DCCPF_ECN_INCAPABLE = 4, /* XXX: not yet implemented */ - DCCPF_ACK_RATIO = 5, - DCCPF_SEND_ACK_VECTOR = 6, - DCCPF_SEND_NDP_COUNT = 7, + DCCPF_ACK_RATIO = 5, + DCCPF_SEND_ACK_VECTOR = 6, + DCCPF_SEND_NDP_COUNT = 7, DCCPF_MIN_CSUM_COVER = 8, DCCPF_DATA_CHECKSUM = 9, /* XXX: not yet implemented */ - /* 10-127 reserved */ - DCCPF_MIN_CCID_SPECIFIC = 128, - DCCPF_MAX_CCID_SPECIFIC = 255, + /* 10-127 reserved */ + DCCPF_MIN_CCID_SPECIFIC = 128, + DCCPF_MAX_CCID_SPECIFIC = 255, }; /* this structure is argument to DCCP_SOCKOPT_CHANGE_X */ @@ -427,7 +427,7 @@ struct dccp_service_list { }; #define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1) -#define DCCP_SERVICE_CODE_IS_ABSENT 0 +#define DCCP_SERVICE_CODE_IS_ABSENT 0 static inline int dccp_list_has_service(const struct dccp_service_list *sl, const __be32 service) @@ -436,7 +436,7 @@ static inline int dccp_list_has_service(const struct dccp_service_list *sl, u32 i = sl->dccpsl_nr; while (i--) if (sl->dccpsl_list[i] == service) - return 1; + return 1; } return 0; } @@ -511,7 +511,7 @@ struct dccp_sock { __u8 dccps_hc_tx_insert_options:1; struct timer_list dccps_xmit_timer; }; - + static inline struct dccp_sock *dccp_sk(const struct sock *sk) { return (struct dccp_sock *)sk; diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 1f4727ddbdbf..a086c6312d3b 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -223,7 +223,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av, gap = -new_head; } new_head += DCCP_MAX_ACKVEC_LEN; - } + } av->dccpav_buf_head = new_head; @@ -336,7 +336,7 @@ out_duplicate: void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, int len) { dccp_pr_debug_cat("ACK vector len=%d, ackno=%llu |", len, - (unsigned long long)ackno); + (unsigned long long)ackno); while (len--) { const u8 state = (*vector & DCCP_ACKVEC_STATE_MASK) >> 6; diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 2555be8f4790..fd38b05d6f79 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -351,7 +351,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len) while (seqp != hctx->ccid2hctx_seqh) { ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n", - (unsigned long long)seqp->ccid2s_seq, + (unsigned long long)seqp->ccid2s_seq, seqp->ccid2s_acked, seqp->ccid2s_sent); seqp = seqp->ccid2s_next; } @@ -473,7 +473,7 @@ static inline void ccid2_new_ack(struct sock *sk, /* first measurement */ if (hctx->ccid2hctx_srtt == -1) { ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", - r, jiffies, + r, jiffies, (unsigned long long)seqp->ccid2s_seq); ccid2_change_srtt(hctx, r); hctx->ccid2hctx_rttvar = r >> 1; @@ -518,8 +518,8 @@ static inline void ccid2_new_ack(struct sock *sk, hctx->ccid2hctx_lastrtt = jiffies; ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n", - hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar, - hctx->ccid2hctx_rto, HZ, r); + hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar, + hctx->ccid2hctx_rto, HZ, r); hctx->ccid2hctx_sent = 0; } @@ -667,9 +667,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) /* new packet received or marked */ if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED && !seqp->ccid2s_acked) { - if (state == + if (state == DCCP_ACKVEC_STATE_ECN_MARKED) { - ccid2_congestion_event(hctx, + ccid2_congestion_event(hctx, seqp); } else ccid2_new_ack(sk, seqp, diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 5e817e2f1ebc..fa6b75372ed7 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -124,18 +124,18 @@ static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) if (hctx->ccid3hctx_p > 0) { hctx->ccid3hctx_x = min(((__u64)hctx->ccid3hctx_x_calc) << 6, - hctx->ccid3hctx_x_recv * 2 ); + hctx->ccid3hctx_x_recv * 2); hctx->ccid3hctx_x = max(hctx->ccid3hctx_x, (((__u64)hctx->ccid3hctx_s) << 6) / - TFRC_T_MBI); + TFRC_T_MBI); } else if (timeval_delta(now, &hctx->ccid3hctx_t_ld) - - (suseconds_t)hctx->ccid3hctx_rtt >= 0 ) { + (suseconds_t)hctx->ccid3hctx_rtt >= 0) { hctx->ccid3hctx_x = max(2 * min(hctx->ccid3hctx_x, hctx->ccid3hctx_x_recv), scaled_div(((__u64)hctx->ccid3hctx_s) << 6, - hctx->ccid3hctx_rtt ) ); + hctx->ccid3hctx_rtt)); hctx->ccid3hctx_t_ld = *now; } @@ -144,8 +144,8 @@ static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) } /* - * Track the mean packet size `s' (cf. RFC 4342, 5.3 and RFC 3448, 4.1) - * @len: DCCP packet payload size in bytes + * Track the mean packet size `s' (cf. RFC 4342, 5.3 and RFC 3448, 4.1) + * @len: DCCP packet payload size in bytes */ static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len) { @@ -163,8 +163,8 @@ static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len) } /* - * Update Window Counter using the algorithm from [RFC 4342, 8.1]. - * The algorithm is not applicable if RTT < 4 microseconds. + * Update Window Counter using the algorithm from [RFC 4342, 8.1]. + * The algorithm is not applicable if RTT < 4 microseconds. */ static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx, struct timeval *now) @@ -228,12 +228,13 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) */ if (!hctx->ccid3hctx_idle || (hctx->ccid3hctx_x_recv >= 4 * - scaled_div(((__u64)hctx->ccid3hctx_s) << 6, hctx->ccid3hctx_rtt))) { + scaled_div(((__u64)hctx->ccid3hctx_s) << 6, + hctx->ccid3hctx_rtt))) { struct timeval now; ccid3_pr_debug("%s(%p, state=%s), not idle\n", dccp_role(sk), sk, - ccid3_tx_state_name(hctx->ccid3hctx_state)); + ccid3_tx_state_name(hctx->ccid3hctx_state)); /* * Modify the cached value of X_recv [RFC 3448, 4.4] @@ -248,12 +249,13 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc); if (hctx->ccid3hctx_p == 0 || - hctx->ccid3hctx_x_calc > (hctx->ccid3hctx_x_recv >> 5)) { + (hctx->ccid3hctx_x_calc > + (hctx->ccid3hctx_x_recv >> 5))) { hctx->ccid3hctx_x_recv = max(hctx->ccid3hctx_x_recv / 2, (((__u64)hctx->ccid3hctx_s) << 6) / - (2*TFRC_T_MBI)); + (2 * TFRC_T_MBI)); if (hctx->ccid3hctx_p == 0) dccp_timestamp(sk, &now); @@ -316,7 +318,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) switch (hctx->ccid3hctx_state) { case TFRC_SSTATE_NO_SENT: sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, - jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)); + (jiffies + + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT))); hctx->ccid3hctx_last_win_count = 0; hctx->ccid3hctx_t_last_win_count = now; ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK); @@ -338,7 +341,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) case TFRC_SSTATE_FBACK: delay = timeval_delta(&hctx->ccid3hctx_t_nom, &now); /* - * Scheduling of packet transmissions [RFC 3448, 4.6] + * Scheduling of packet transmissions [RFC 3448, 4.6] * * if (t_now > t_nom - delta) * // send the packet now @@ -365,7 +368,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) return 0; } -static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len) +static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, + unsigned int len) { struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct timeval now; @@ -415,12 +419,12 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) case TFRC_SSTATE_FBACK: /* get packet from history to look up t_recvdata */ packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist, - DCCP_SKB_CB(skb)->dccpd_ack_seq); + DCCP_SKB_CB(skb)->dccpd_ack_seq); if (unlikely(packet == NULL)) { DCCP_WARN("%s(%p), seqno %llu(%s) doesn't exist " "in history!\n", dccp_role(sk), sk, (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq, - dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type)); + dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type)); return; } @@ -433,13 +437,13 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) if (pinv == ~0U || pinv == 0) /* see RFC 4342, 8.5 */ hctx->ccid3hctx_p = 0; else /* can not exceed 100% */ - hctx->ccid3hctx_p = 1000000 / pinv; + hctx->ccid3hctx_p = 1000000 / pinv; dccp_timestamp(sk, &now); /* * Calculate new round trip sample as per [RFC 3448, 4.3] by - * R_sample = (now - t_recvdata) - t_elapsed + * R_sample = (now - t_recvdata) - t_elapsed */ r_sample = timeval_delta(&now, &packet->dccphtx_tstamp); t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10; @@ -465,7 +469,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) * Larger Initial Windows [RFC 4342, sec. 5] * We deviate in that we use `s' instead of `MSS'. */ - __u64 w_init = min( 4 * hctx->ccid3hctx_s, + __u64 w_init = min(4 * hctx->ccid3hctx_s, max(2 * hctx->ccid3hctx_s, 4380)); hctx->ccid3hctx_rtt = r_sample; hctx->ccid3hctx_x = scaled_div(w_init << 6, r_sample); @@ -475,13 +479,14 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ccid3_pr_debug("%s(%p), s=%u, w_init=%llu, " "R_sample=%dus, X=%u\n", dccp_role(sk), - sk, hctx->ccid3hctx_s, w_init, (int)r_sample, + sk, hctx->ccid3hctx_s, w_init, + (int)r_sample, (unsigned)(hctx->ccid3hctx_x >> 6)); ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK); } else { hctx->ccid3hctx_rtt = (9 * hctx->ccid3hctx_rtt + - (u32)r_sample ) / 10; + (u32)r_sample) / 10; /* Update sending rate (step 4 of [RFC 3448, 4.3]) */ if (hctx->ccid3hctx_p > 0) @@ -492,12 +497,13 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ccid3_hc_tx_update_x(sk, &now); ccid3_pr_debug("%s(%p), RTT=%uus (sample=%dus), s=%u, " - "p=%u, X_calc=%u, X_recv=%u, X=%u\n", dccp_role(sk), + "p=%u, X_calc=%u, X_recv=%u, X=%u\n", + dccp_role(sk), sk, hctx->ccid3hctx_rtt, (int)r_sample, hctx->ccid3hctx_s, hctx->ccid3hctx_p, hctx->ccid3hctx_x_calc, (unsigned)(hctx->ccid3hctx_x_recv >> 6), - (unsigned)(hctx->ccid3hctx_x >> 6) ); + (unsigned)(hctx->ccid3hctx_x >> 6)); } /* unschedule no feedback timer */ @@ -507,20 +513,20 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) dccp_tx_hist_purge_older(ccid3_tx_hist, &hctx->ccid3hctx_hist, packet); /* - * As we have calculated new ipi, delta, t_nom it is possible that - * we now can send a packet, so wake up dccp_wait_for_ccid + * As we have calculated new ipi, delta, t_nom it is possible + * that we now can send a packet, so wake up dccp_wait_for_ccid */ sk->sk_write_space(sk); /* * Update timeout interval for the nofeedback timer. * We use a configuration option to increase the lower bound. - * This can help avoid triggering the nofeedback timer too often - * ('spinning') on LANs with small RTTs. + * This can help avoid triggering the nofeedback timer too + * often ('spinning') on LANs with small RTTs. */ hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt, CONFIG_IP_DCCP_CCID3_RTO * - (USEC_PER_SEC/1000) ); + (USEC_PER_SEC/1000)); /* * Schedule no feedback timer to expire in * max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi) @@ -528,7 +534,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi); ccid3_pr_debug("%s(%p), Scheduled no feedback timer to " - "expire in %lu jiffies (%luus)\n", dccp_role(sk), + "expire in %lu jiffies (%luus)\n", + dccp_role(sk), sk, usecs_to_jiffies(t_nfb), t_nfb); sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, @@ -538,7 +545,9 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) hctx->ccid3hctx_idle = 1; break; case TFRC_SSTATE_NO_SENT: - /* XXX when implementing bidirectional rx/tx check this again */ + /* + * XXX when implementing bidirectional rx/tx check this again + */ DCCP_WARN("Illegal ACK received - no packet sent\n"); /* fall through */ case TFRC_SSTATE_TERM: /* ignore feedback when closing */ @@ -575,7 +584,8 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, dccp_role(sk), sk, len); rc = -EINVAL; } else { - opt_recv->ccid3or_loss_event_rate = ntohl(*(__be32 *)value); + opt_recv->ccid3or_loss_event_rate = + ntohl(*(__be32 *)value); ccid3_pr_debug("%s(%p), LOSS_EVENT_RATE=%u\n", dccp_role(sk), sk, opt_recv->ccid3or_loss_event_rate); @@ -596,7 +606,8 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, dccp_role(sk), sk, len); rc = -EINVAL; } else { - opt_recv->ccid3or_receive_rate = ntohl(*(__be32 *)value); + opt_recv->ccid3or_receive_rate = + ntohl(*(__be32 *)value); ccid3_pr_debug("%s(%p), RECEIVE_RATE=%u\n", dccp_role(sk), sk, opt_recv->ccid3or_receive_rate); @@ -616,7 +627,8 @@ static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk) hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT; INIT_LIST_HEAD(&hctx->ccid3hctx_hist); - hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer; + hctx->ccid3hctx_no_feedback_timer.function = + ccid3_hc_tx_no_feedback_timer; hctx->ccid3hctx_no_feedback_timer.data = (unsigned long)sk; init_timer(&hctx->ccid3hctx_no_feedback_timer); @@ -754,9 +766,9 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) hcrx->ccid3hcrx_elapsed_time)) || dccp_insert_option_timestamp(sk, skb) || dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE, - &pinv, sizeof(pinv)) || + &pinv, sizeof(pinv)) || dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE, - &x_recv, sizeof(x_recv))) + &x_recv, sizeof(x_recv))) return -1; return 0; @@ -827,9 +839,9 @@ found: /* * Determine the length of the first loss interval via inverse lookup. * Assume that X_recv can be computed by the throughput equation - * s - * X_recv = -------- - * R * fval + * s + * X_recv = -------- + * R * fval * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1]. */ if (rtt == 0) { /* would result in divide-by-zero */ @@ -860,7 +872,7 @@ found: if (p == 0) return ~0; else - return 1000000 / p; + return 1000000 / p; } static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss) @@ -914,7 +926,8 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk, struct dccp_rx_hist_entry *packet) { struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); - struct dccp_rx_hist_entry *rx_hist = dccp_rx_hist_head(&hcrx->ccid3hcrx_hist); + struct dccp_rx_hist_entry *rx_hist = + dccp_rx_hist_head(&hcrx->ccid3hcrx_hist); u64 seqno = packet->dccphrx_seqno; u64 tmp_seqno; int loss = 0; @@ -942,7 +955,7 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk, dccp_inc_seqno(&tmp_seqno); while (dccp_rx_hist_find_entry(&hcrx->ccid3hcrx_hist, tmp_seqno, &ccval)) { - hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno; + hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno; hcrx->ccid3hcrx_ccval_nonloss = ccval; dccp_inc_seqno(&tmp_seqno); } @@ -1044,8 +1057,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) break; dccp_timestamp(sk, &now); - if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) - - (suseconds_t)hcrx->ccid3hcrx_rtt >= 0) { + if ((timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) - + (suseconds_t)hcrx->ccid3hcrx_rtt) >= 0) { hcrx->ccid3hcrx_tstamp_last_ack = now; ccid3_hc_rx_send_feedback(sk); } @@ -1118,9 +1131,9 @@ static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) BUG_ON(hcrx == NULL); - info->tcpi_ca_state = hcrx->ccid3hcrx_state; - info->tcpi_options |= TCPI_OPT_TIMESTAMPS; - info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt; + info->tcpi_ca_state = hcrx->ccid3hcrx_state; + info->tcpi_options |= TCPI_OPT_TIMESTAMPS; + info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt; } static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) @@ -1212,7 +1225,7 @@ static struct ccid_operations ccid3 = { .ccid_hc_rx_getsockopt = ccid3_hc_rx_getsockopt, .ccid_hc_tx_getsockopt = ccid3_hc_tx_getsockopt, }; - + #ifdef CONFIG_IP_DCCP_CCID3_DEBUG module_param(ccid3_debug, int, 0444); MODULE_PARM_DESC(ccid3_debug, "Enable debug messages"); @@ -1235,7 +1248,7 @@ static __init int ccid3_module_init(void) goto out_free_tx; rc = ccid_register(&ccid3); - if (rc != 0) + if (rc != 0) goto out_free_loss_interval_history; out: return rc; diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 3e3a9cc69b10..15776a88c090 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -77,7 +77,7 @@ struct ccid3_options_received { /* TFRC sender states */ enum ccid3_hc_tx_states { - TFRC_SSTATE_NO_SENT = 1, + TFRC_SSTATE_NO_SENT = 1, TFRC_SSTATE_NO_FBACK, TFRC_SSTATE_FBACK, TFRC_SSTATE_TERM, @@ -96,7 +96,7 @@ enum ccid3_hc_tx_states { * @ccid3hctx_state - Sender state, one of %ccid3_hc_tx_states * @ccid3hctx_last_win_count - Last window counter sent * @ccid3hctx_t_last_win_count - Timestamp of earliest packet - * with last_win_count value sent + * with last_win_count value sent * @ccid3hctx_no_feedback_timer - Handle to no feedback timer * @ccid3hctx_idle - Flag indicating that sender is idling * @ccid3hctx_t_ld - Time last doubled during slow start @@ -115,7 +115,7 @@ struct ccid3_hc_tx_sock { #define ccid3hctx_t_rto ccid3hctx_tfrc.tfrctx_rto #define ccid3hctx_t_ipi ccid3hctx_tfrc.tfrctx_ipi u16 ccid3hctx_s; - enum ccid3_hc_tx_states ccid3hctx_state:8; + enum ccid3_hc_tx_states ccid3hctx_state:8; u8 ccid3hctx_last_win_count; u8 ccid3hctx_idle; struct timeval ccid3hctx_t_last_win_count; @@ -129,7 +129,7 @@ struct ccid3_hc_tx_sock { /* TFRC receiver states */ enum ccid3_hc_rx_states { - TFRC_RSTATE_NO_DATA = 1, + TFRC_RSTATE_NO_DATA = 1, TFRC_RSTATE_DATA, TFRC_RSTATE_TERM = 127, }; @@ -157,18 +157,18 @@ struct ccid3_hc_rx_sock { #define ccid3hcrx_x_recv ccid3hcrx_tfrc.tfrcrx_x_recv #define ccid3hcrx_rtt ccid3hcrx_tfrc.tfrcrx_rtt #define ccid3hcrx_p ccid3hcrx_tfrc.tfrcrx_p - u64 ccid3hcrx_seqno_nonloss:48, + u64 ccid3hcrx_seqno_nonloss:48, ccid3hcrx_ccval_nonloss:4, ccid3hcrx_ccval_last_counter:4; enum ccid3_hc_rx_states ccid3hcrx_state:8; - u32 ccid3hcrx_bytes_recv; - struct timeval ccid3hcrx_tstamp_last_feedback; - struct timeval ccid3hcrx_tstamp_last_ack; + u32 ccid3hcrx_bytes_recv; + struct timeval ccid3hcrx_tstamp_last_feedback; + struct timeval ccid3hcrx_tstamp_last_ack; struct list_head ccid3hcrx_hist; struct list_head ccid3hcrx_li_hist; - u16 ccid3hcrx_s; - u32 ccid3hcrx_pinv; - u32 ccid3hcrx_elapsed_time; + u16 ccid3hcrx_s; + u32 ccid3hcrx_pinv; + u32 ccid3hcrx_elapsed_time; }; static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk) diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 4dc487f27a1f..95b6927ec653 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -329,7 +329,7 @@ static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, switch (type) { case DCCPO_CHANGE_L: opt->dccpop_type = DCCPO_CONFIRM_R; break; case DCCPO_CHANGE_R: opt->dccpop_type = DCCPO_CONFIRM_L; break; - default: DCCP_WARN("invalid type %d\n", type); return; + default: DCCP_WARN("invalid type %d\n", type); return; } opt->dccpop_feat = feature; @@ -427,7 +427,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, switch (type) { case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break; case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break; - default: DCCP_WARN("invalid type %d\n", type); + default: DCCP_WARN("invalid type %d\n", type); return 1; } @@ -610,7 +610,7 @@ const char *dccp_feat_typename(const u8 type) case DCCPO_CHANGE_R: return("ChangeR"); case DCCPO_CONFIRM_R: return("ConfirmR"); /* the following case must not appear in feature negotation */ - default: dccp_pr_debug("unknown type %d [BUG!]\n", type); + default: dccp_pr_debug("unknown type %d [BUG!]\n", type); } return NULL; } diff --git a/net/dccp/input.c b/net/dccp/input.c index 4a3279cd684c..565bc80557ce 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -1,6 +1,6 @@ /* * net/dccp/input.c - * + * * An implementation of the DCCP protocol * Arnaldo Carvalho de Melo * @@ -82,7 +82,7 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) * Otherwise, * Drop packet and return */ - if (dh->dccph_type == DCCP_PKT_SYNC || + if (dh->dccph_type == DCCP_PKT_SYNC || dh->dccph_type == DCCP_PKT_SYNCACK) { if (between48(DCCP_SKB_CB(skb)->dccpd_ack_seq, dp->dccps_awl, dp->dccps_awh) && @@ -185,8 +185,8 @@ static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb, dccp_rcv_close(sk, skb); return 0; case DCCP_PKT_REQUEST: - /* Step 7 - * or (S.is_server and P.type == Response) + /* Step 7 + * or (S.is_server and P.type == Response) * or (S.is_client and P.type == Request) * or (S.state >= OPEN and P.type == Request * and P.seqno >= S.OSR) @@ -274,7 +274,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, const struct dccp_hdr *dh, const unsigned len) { - /* + /* * Step 4: Prepare sequence numbers in REQUEST * If S.state == REQUEST, * If (P.type == Response or P.type == Reset) @@ -342,7 +342,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, * from the Response * / * S.state := PARTOPEN * Set PARTOPEN timer - * Continue with S.state == PARTOPEN + * Continue with S.state == PARTOPEN * / * Step 12 will send the Ack completing the * three-way handshake * / */ @@ -373,7 +373,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, */ __kfree_skb(skb); return 0; - } + } dccp_send_ack(sk); return -1; } @@ -381,7 +381,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, out_invalid_packet: /* dccp_v4_do_rcv will send a reset */ DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR; - return 1; + return 1; } static int dccp_rcv_respond_partopen_state_process(struct sock *sk, @@ -488,11 +488,11 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_event_ack_recv(sk, skb); - if (dccp_msk(sk)->dccpms_send_ack_vector && + if (dccp_msk(sk)->dccpms_send_ack_vector && dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, - DCCP_SKB_CB(skb)->dccpd_seq, - DCCP_ACKVEC_STATE_RECEIVED)) - goto discard; + DCCP_SKB_CB(skb)->dccpd_seq, + DCCP_ACKVEC_STATE_RECEIVED)) + goto discard; /* XXX see the comments in dccp_rcv_established about this */ if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER) @@ -580,7 +580,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, } } - if (!queued) { + if (!queued) { discard: __kfree_skb(skb); } diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index ff81679c9f17..90c74b4adb73 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -157,7 +157,7 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk, /* We don't check in the destentry if pmtu discovery is forbidden * on this route. We just assume that no packet_to_big packets * are send back when pmtu discovery is not active. - * There is a small race when the user changes this flag in the + * There is a small race when the user changes this flag in the * route, but I think that's acceptable. */ if ((dst = __sk_dst_check(sk, 0)) == NULL) @@ -467,7 +467,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, .uli_u = { .ports = { .sport = dccp_hdr(skb)->dccph_dport, .dport = dccp_hdr(skb)->dccph_sport } - } + } }; security_skb_classify_flow(skb, &fl); @@ -595,7 +595,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) struct inet_request_sock *ireq; struct request_sock *req; struct dccp_request_sock *dreq; - const __be32 service = dccp_hdr_request(skb)->dccph_req_service; + const __be32 service = dccp_hdr_request(skb)->dccph_req_service; struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; @@ -609,7 +609,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (dccp_bad_service_code(sk, service)) { reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; goto drop; - } + } /* * TW buckets are converted to open requests without * limitations, they conserve resources and peer is @@ -644,7 +644,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ireq->rmt_addr = skb->nh.iph->saddr; ireq->opt = NULL; - /* + /* * Step 3: Process LISTEN state * * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie @@ -846,15 +846,15 @@ static int dccp_v4_rcv(struct sk_buff *skb) } /* Step 2: - * Look up flow ID in table and get corresponding socket */ + * Look up flow ID in table and get corresponding socket */ sk = __inet_lookup(&dccp_hashinfo, skb->nh.iph->saddr, dh->dccph_sport, skb->nh.iph->daddr, dh->dccph_dport, inet_iif(skb)); - /* + /* * Step 2: - * If no socket ... + * If no socket ... */ if (sk == NULL) { dccp_pr_debug("failed to look up flow ID in table and " @@ -862,9 +862,9 @@ static int dccp_v4_rcv(struct sk_buff *skb) goto no_dccp_socket; } - /* + /* * Step 2: - * ... or S.state == TIMEWAIT, + * ... or S.state == TIMEWAIT, * Generate Reset(No Connection) unless P.type == Reset * Drop packet and return */ @@ -876,8 +876,8 @@ static int dccp_v4_rcv(struct sk_buff *skb) /* * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage - * o if MinCsCov = 0, only packets with CsCov = 0 are accepted - * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov + * o if MinCsCov = 0, only packets with CsCov = 0 are accepted + * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov */ min_cov = dccp_sk(sk)->dccps_pcrlen; if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) { @@ -900,7 +900,7 @@ no_dccp_socket: goto discard_it; /* * Step 2: - * If no socket ... + * If no socket ... * Generate Reset(No Connection) unless P.type == Reset * Drop packet and return */ diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index c7aaa2574f52..6b91a9dd0411 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -77,7 +77,7 @@ static inline void dccp_v6_send_check(struct sock *sk, int unused_value, } static inline __u32 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, - __be16 sport, __be16 dport ) + __be16 sport, __be16 dport ) { return secure_tcpv6_sequence_number(saddr, daddr, sport, dport); } @@ -329,7 +329,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header, GFP_ATOMIC); if (skb == NULL) - return; + return; skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); @@ -353,7 +353,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) dccp_csum_outgoing(skb); dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr, - &rxskb->nh.ipv6h->daddr); + &rxskb->nh.ipv6h->daddr); memset(&fl, 0, sizeof(fl)); ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr); @@ -424,7 +424,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) struct dccp_request_sock *dreq; struct inet6_request_sock *ireq6; struct ipv6_pinfo *np = inet6_sk(sk); - const __be32 service = dccp_hdr_request(skb)->dccph_req_service; + const __be32 service = dccp_hdr_request(skb)->dccph_req_service; struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; @@ -437,7 +437,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (dccp_bad_service_code(sk, service)) { reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; goto drop; - } + } /* * There are no SYN attacks on IPv6, yet... */ @@ -787,7 +787,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) * otherwise we just shortcircuit this and continue with * the new socket.. */ - if (nsk != sk) { + if (nsk != sk) { if (dccp_child_process(sk, nsk, skb)) goto reset; if (opt_skb != NULL) @@ -843,14 +843,14 @@ static int dccp_v6_rcv(struct sk_buff **pskb) DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb); /* Step 2: - * Look up flow ID in table and get corresponding socket */ + * Look up flow ID in table and get corresponding socket */ sk = __inet6_lookup(&dccp_hashinfo, &skb->nh.ipv6h->saddr, dh->dccph_sport, &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport), inet6_iif(skb)); /* * Step 2: - * If no socket ... + * If no socket ... */ if (sk == NULL) { dccp_pr_debug("failed to look up flow ID in table and " @@ -860,7 +860,7 @@ static int dccp_v6_rcv(struct sk_buff **pskb) /* * Step 2: - * ... or S.state == TIMEWAIT, + * ... or S.state == TIMEWAIT, * Generate Reset(No Connection) unless P.type == Reset * Drop packet and return */ @@ -872,8 +872,8 @@ static int dccp_v6_rcv(struct sk_buff **pskb) /* * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage - * o if MinCsCov = 0, only packets with CsCov = 0 are accepted - * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov + * o if MinCsCov = 0, only packets with CsCov = 0 are accepted + * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov */ min_cov = dccp_sk(sk)->dccps_pcrlen; if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) { @@ -893,7 +893,7 @@ no_dccp_socket: goto discard_it; /* * Step 2: - * If no socket ... + * If no socket ... * Generate Reset(No Connection) unless P.type == Reset * Drop packet and return */ diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 4c9e26775f72..6656bb497c7b 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -182,7 +182,7 @@ out_free: EXPORT_SYMBOL_GPL(dccp_create_openreq_child); -/* +/* * Process an incoming packet for RESPOND sockets represented * as an request_sock. */ diff --git a/net/dccp/output.c b/net/dccp/output.c index b4df12b24161..824569659083 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -1,6 +1,6 @@ /* * net/dccp/output.c - * + * * An implementation of the DCCP protocol * Arnaldo Carvalho de Melo * @@ -338,7 +338,6 @@ EXPORT_SYMBOL_GPL(dccp_make_response); static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, const enum dccp_reset_codes code) - { struct dccp_hdr *dh; struct dccp_sock *dp = dccp_sk(sk); @@ -419,14 +418,14 @@ static inline void dccp_connect_init(struct sock *sk) dccp_sync_mss(sk, dst_mtu(dst)); - /* + /* * SWL and AWL are initially adjusted so that they are not less than * the initial Sequence Numbers received and sent, respectively: * SWL := max(GSR + 1 - floor(W/4), ISR), * AWL := max(GSS - W' + 1, ISS). * These adjustments MUST be applied only at the beginning of the * connection. - */ + */ dccp_update_gss(sk, dp->dccps_iss); dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss)); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 5ec47d9ee447..63b3fa20e14b 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -196,7 +196,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) sk, GFP_KERNEL); dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid, sk, GFP_KERNEL); - if (unlikely(dp->dccps_hc_rx_ccid == NULL || + if (unlikely(dp->dccps_hc_rx_ccid == NULL || dp->dccps_hc_tx_ccid == NULL)) { ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); @@ -390,7 +390,7 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service, struct dccp_sock *dp = dccp_sk(sk); struct dccp_service_list *sl = NULL; - if (service == DCCP_SERVICE_INVALID_VALUE || + if (service == DCCP_SERVICE_INVALID_VALUE || optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32)) return -EINVAL; @@ -830,7 +830,7 @@ EXPORT_SYMBOL_GPL(inet_dccp_listen); static const unsigned char dccp_new_state[] = { /* current state: new state: action: */ [0] = DCCP_CLOSED, - [DCCP_OPEN] = DCCP_CLOSING | DCCP_ACTION_FIN, + [DCCP_OPEN] = DCCP_CLOSING | DCCP_ACTION_FIN, [DCCP_REQUESTING] = DCCP_CLOSED, [DCCP_PARTOPEN] = DCCP_CLOSING | DCCP_ACTION_FIN, [DCCP_LISTEN] = DCCP_CLOSED, diff --git a/net/dccp/timer.c b/net/dccp/timer.c index e8f519e7f481..e5348f369c60 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -1,6 +1,6 @@ /* * net/dccp/timer.c - * + * * An implementation of the DCCP protocol * Arnaldo Carvalho de Melo * @@ -102,13 +102,13 @@ static void dccp_retransmit_timer(struct sock *sk) * sk->sk_send_head has to have one skb with * DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP * packet types. The only packets eligible for retransmission are: - * -- Requests in client-REQUEST state (sec. 8.1.1) - * -- Acks in client-PARTOPEN state (sec. 8.1.5) - * -- CloseReq in server-CLOSEREQ state (sec. 8.3) - * -- Close in node-CLOSING state (sec. 8.3) */ + * -- Requests in client-REQUEST state (sec. 8.1.1) + * -- Acks in client-PARTOPEN state (sec. 8.1.5) + * -- CloseReq in server-CLOSEREQ state (sec. 8.3) + * -- Close in node-CLOSING state (sec. 8.3) */ BUG_TRAP(sk->sk_send_head != NULL); - /* + /* * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was * sent, no need to retransmit, this sock is dead. */ @@ -200,7 +200,7 @@ static void dccp_keepalive_timer(unsigned long data) /* Only process if socket is not in use. */ bh_lock_sock(sk); if (sock_owned_by_user(sk)) { - /* Try again later. */ + /* Try again later. */ inet_csk_reset_keepalive_timer(sk, HZ / 20); goto out; } -- cgit v1.2.3 From 2b02a1792000900ead4638f4d42fcdd742062cfa Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Tue, 5 Dec 2006 10:19:14 +0100 Subject: [PATCH] remove blk_queue_activity_fn While working on bidi support at struct request level I have found that blk_queue_activity_fn is actually never used. The only user is in ide-probe.c with this code: /* enable led activity for disk drives only */ if (drive->media == ide_disk && hwif->led_act) blk_queue_activity_fn(q, hwif->led_act, drive); And led_act is never initialized anywhere. (Looking back at older kernels it was used in the PPC arch, but was removed around 2.6.18) Unless it is all for future use off course. (this patch is against linux-2.6-block.git as off 2006/12/4) Signed-off-by: Boaz Harrosh Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 12 ------------ drivers/ide/ide-probe.c | 4 ---- include/linux/blkdev.h | 5 ----- include/linux/ide.h | 2 -- 4 files changed, 23 deletions(-) (limited to 'include/linux') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 785e61c9a810..a541b42c08e3 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -129,13 +129,6 @@ struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev) } EXPORT_SYMBOL(blk_get_backing_dev_info); -void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data) -{ - q->activity_fn = fn; - q->activity_data = data; -} -EXPORT_SYMBOL(blk_queue_activity_fn); - /** * blk_queue_prep_rq - set a prepare_request function for queue * @q: queue @@ -238,8 +231,6 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) * by default assume old behaviour and bounce for any highmem page */ blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); - - blk_queue_activity_fn(q, NULL, NULL); } EXPORT_SYMBOL(blk_queue_make_request); @@ -2696,9 +2687,6 @@ static inline void add_request(request_queue_t * q, struct request * req) { drive_stat_acct(req, req->nr_sectors, 1); - if (q->activity_fn) - q->activity_fn(q->activity_data, rq_data_dir(req)); - /* * elevator indicated where it wants this request to be * inserted at elevator_merge time diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index dad9c47ebb69..5a5c565a32a8 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1000,10 +1000,6 @@ static int ide_init_queue(ide_drive_t *drive) /* needs drive->queue to be set */ ide_toggle_bounce(drive, 1); - /* enable led activity for disk drives only */ - if (drive->media == ide_disk && hwif->led_act) - blk_queue_activity_fn(q, hwif->led_act, drive); - return 0; } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index e1c7286165ff..ea330d7b46c0 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -342,7 +342,6 @@ typedef void (unplug_fn) (request_queue_t *); struct bio_vec; typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *); -typedef void (activity_fn) (void *data, int rw); typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *); typedef void (prepare_flush_fn) (request_queue_t *, struct request *); typedef void (softirq_done_fn)(struct request *); @@ -384,7 +383,6 @@ struct request_queue prep_rq_fn *prep_rq_fn; unplug_fn *unplug_fn; merge_bvec_fn *merge_bvec_fn; - activity_fn *activity_fn; issue_flush_fn *issue_flush_fn; prepare_flush_fn *prepare_flush_fn; softirq_done_fn *softirq_done_fn; @@ -411,8 +409,6 @@ struct request_queue */ void *queuedata; - void *activity_data; - /* * queue needs bounce pages for pages above this limit */ @@ -677,7 +673,6 @@ extern void blk_sync_queue(struct request_queue *q); extern void __blk_stop_queue(request_queue_t *q); extern void blk_run_queue(request_queue_t *); extern void blk_start_queueing(request_queue_t *); -extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned long); extern int blk_rq_unmap_user(struct request *); extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t); diff --git a/include/linux/ide.h b/include/linux/ide.h index 64e070f62a87..e26a03981a94 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -804,8 +804,6 @@ typedef struct hwif_s { void *hwif_data; /* extra hwif data */ unsigned dma; - - void (*led_act)(void *data, int rw); } ____cacheline_internodealigned_in_smp ide_hwif_t; /* -- cgit v1.2.3 From 99a3eb3845f034eb55640a3da73e5e28349678c6 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 12 Dec 2006 12:10:28 +0100 Subject: [PATCH] lockdep: fix seqlock_init() seqlock_init() needs to use spin_lock_init() for dynamic locks, so that lockdep is notified about the presence of a new lock. (this is a fallout of the recent networking merge, which started using the so-far unused seqlock_init() API.) This fix solves the following lockdep-internal warning on current -git: INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. __lock_acquire+0x10c/0x9f9 lock_acquire+0x56/0x72 _spin_lock+0x35/0x42 neigh_destroy+0x9d/0x12e neigh_periodic_timer+0x10a/0x15c run_timer_softirq+0x126/0x18e __do_softirq+0x6b/0xe6 do_softirq+0x64/0xd2 ksoftirqd+0x82/0x138 Signed-off-by: Ingo Molnar Signed-off-by: Linus Torvalds --- include/linux/seqlock.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h index 46000936f8f1..6b0648cfdffc 100644 --- a/include/linux/seqlock.h +++ b/include/linux/seqlock.h @@ -44,8 +44,11 @@ typedef struct { #define SEQLOCK_UNLOCKED \ __SEQLOCK_UNLOCKED(old_style_seqlock_init) -#define seqlock_init(x) \ - do { *(x) = (seqlock_t) __SEQLOCK_UNLOCKED(x); } while (0) +#define seqlock_init(x) \ + do { \ + (x)->sequence = 0; \ + spin_lock_init(&(x)->lock); \ + } while (0) #define DEFINE_SEQLOCK(x) \ seqlock_t x = __SEQLOCK_UNLOCKED(x) -- cgit v1.2.3